diff --git a/debug_monitor_issue.sh b/debug_monitor_issue.sh new file mode 100755 index 0000000..571ed6f --- /dev/null +++ b/debug_monitor_issue.sh @@ -0,0 +1,46 @@ +#!/bin/bash + +echo "=== Monitor Selection Debugging ===" +echo "This script helps debug monitor selection issues" +echo + +# Show current monitor setup +echo "1. Current monitor configuration:" +xfreerdp /monitor-list +echo + +# Test different monitor parameter combinations +echo "2. Testing different xfreerdp monitor parameters:" +echo + +echo "Testing /monitors:1,2 (should use monitors 1 and 2):" +echo "Command: xfreerdp /monitor-list /monitors:1,2" +echo "Note: This would be used for '2 Monitors' selection" +echo + +echo "Testing /monitors:1,2,0 (should use monitors 1, 2, and 0):" +echo "Command: xfreerdp /monitor-list /monitors:1,2,0" +echo "Note: This would be used for '3 Monitors' selection" +echo + +echo "Testing /multimon (should use all monitors):" +echo "Command: xfreerdp /monitor-list /multimon" +echo "Note: This would be used for 'All Monitors' selection" +echo + +echo "3. To test with actual RDP connection, you can use:" +echo "xfreerdp /v:your-server /u:username /p:password /monitors:1,2" +echo +echo "If /monitors:1,2 still uses only one monitor, this indicates" +echo "a limitation or bug in your FreeRDP version (2.11.5)" +echo + +echo "4. Alternative workarounds to try:" +echo "- Use /multimon instead of /monitors: (uses all monitors)" +echo "- Use /span to span across monitors" +echo "- Update to a newer version of FreeRDP" +echo "- Check if your RDP server supports multi-monitor" +echo + +echo "5. Check current RDP client logs:" +echo "tail -20 ~/.config/rdp-client/rdp_client.log" \ No newline at end of file diff --git a/debug_rdp_command.py b/debug_rdp_command.py new file mode 100644 index 0000000..4202a64 --- /dev/null +++ b/debug_rdp_command.py @@ -0,0 +1,99 @@ +#!/usr/bin/env python3 + +import subprocess + +def get_best_monitor_selection(count): + """Get the best monitor selection based on layout""" + try: + result = subprocess.run(['xfreerdp', '/monitor-list'], + capture_output=True, text=True, timeout=5) + if result.returncode == 0: + lines = result.stdout.strip().split('\n') + monitors = [] + for line in lines: + # Clean up the line and split by whitespace/tabs + cleaned_line = line.strip().replace('*', '').strip() + if '[' in cleaned_line and ']' in cleaned_line and 'x' in cleaned_line and '+' in cleaned_line: + # Split by whitespace/tabs + parts = cleaned_line.split() + if len(parts) >= 3: + id_part = parts[0] # [0] + pos_part = parts[2] # +3840+0 + if '[' in id_part and ']' in id_part: + monitor_id = int(id_part.strip('[]')) + x_pos = int(pos_part.split('+')[1]) + monitors.append((monitor_id, x_pos)) + + # Sort monitors by X position (left to right) + monitors.sort(key=lambda x: x[1]) + + # Return the leftmost monitors + selected = [str(m[0]) for m in monitors[:count]] + return ','.join(selected) + except: + pass + + # Fallback: simple sequential selection + return ','.join([str(i) for i in range(count)]) + +def test_command_generation(): + print("=== Testing RDP Command Generation ===") + print() + + # Test connection data + conn = { + 'server': 'test-server', + 'username': 'testuser', + 'domain': '', + 'resolution': 'Full Screen', + 'color_depth': 32, + 'sound': 'Yes', + 'clipboard': 'Yes' + } + + # Test different monitor configurations + test_cases = [ + ("2 Monitors", 2), + ("3 Monitors", 3), + ("All Monitors", None) + ] + + for multimon, count in test_cases: + print(f"Testing: {multimon}") + + # Build base command + cmd = ["xfreerdp"] + cmd.append(f"/v:{conn['server']}") + cmd.append(f"/u:{conn['username']}") + cmd.append("/p:password") + + if conn.get('domain'): + cmd.append(f"/d:{conn['domain']}") + + # Resolution + cmd.append("/f") # Full screen + + # Color depth + cmd.append(f"/bpp:{conn['color_depth']}") + + # Monitor handling + if multimon == "2 Monitors": + monitor_list = get_best_monitor_selection(2) + cmd.append(f"/monitors:{monitor_list}") + elif multimon == "3 Monitors": + monitor_list = get_best_monitor_selection(3) + cmd.append(f"/monitors:{monitor_list}") + elif multimon == "All Monitors": + cmd.append("/multimon") + + # Other options + cmd.append("/sound:sys") + cmd.append("+clipboard") + + # Print the command + cmd_str = ' '.join(cmd).replace("/p:password", "/p:***") + print(f"Command: {cmd_str}") + print() + +if __name__ == "__main__": + test_command_generation() \ No newline at end of file diff --git a/rdp_client.py b/rdp_client.py index b695cf8..f1601a9 100755 --- a/rdp_client.py +++ b/rdp_client.py @@ -253,9 +253,14 @@ class RDPClient: if result.returncode == 0: lines = result.stdout.strip().split('\n') monitors = [] + primary_monitor = None + for line in lines: # Clean up the line and split by whitespace/tabs - cleaned_line = line.strip().replace('*', '').strip() + cleaned_line = line.strip() + is_primary = cleaned_line.startswith('*') + cleaned_line = cleaned_line.replace('*', '').strip() + if '[' in cleaned_line and ']' in cleaned_line and 'x' in cleaned_line and '+' in cleaned_line: # Split by whitespace/tabs parts = cleaned_line.split() @@ -265,19 +270,31 @@ class RDPClient: if '[' in id_part and ']' in id_part: monitor_id = int(id_part.strip('[]')) x_pos = int(pos_part.split('+')[1]) - monitors.append((monitor_id, x_pos)) + monitor_info = (monitor_id, x_pos, is_primary) + monitors.append(monitor_info) + + if is_primary: + primary_monitor = monitor_id # Sort monitors by X position (left to right) monitors.sort(key=lambda x: x[1]) - # Return the leftmost monitors + # For debugging, log the monitor layout + self.logger.info(f"Monitor layout detected: {[(m[0], m[1], 'primary' if m[2] else 'secondary') for m in monitors]}") + + # Return the leftmost monitors (excluding position and primary flag) selected = [str(m[0]) for m in monitors[:count]] - return ','.join(selected) - except: - pass + selected_str = ','.join(selected) + + self.logger.info(f"Selected {count} monitors: {selected_str}") + return selected_str + except Exception as e: + self.logger.error(f"Error detecting monitors: {e}") # Fallback: simple sequential selection - return ','.join([str(i) for i in range(count)]) + fallback = ','.join([str(i) for i in range(count)]) + self.logger.warning(f"Using fallback monitor selection: {fallback}") + return fallback def _setup_gui(self): """Setup the main GUI""" @@ -840,17 +857,23 @@ Multi-Monitor Support: multimon = conn.get("multimon", "No") if multimon == "2 Monitors": monitor_list = self._get_best_monitor_selection(2) + # Try using /monitors without /multimon for specific monitor selection cmd.append(f"/monitors:{monitor_list}") + self.logger.info(f"Using specific monitors for 2 monitors: {monitor_list}") elif multimon == "3 Monitors": monitor_list = self._get_best_monitor_selection(3) cmd.append(f"/monitors:{monitor_list}") + self.logger.info(f"Using specific monitors for 3 monitors: {monitor_list}") elif multimon == "4 Monitors": monitor_list = self._get_best_monitor_selection(4) cmd.append(f"/monitors:{monitor_list}") + self.logger.info(f"Using specific monitors for 4 monitors: {monitor_list}") elif multimon == "All Monitors": cmd.append("/multimon") + self.logger.info("Using all available monitors") elif multimon == "Span": cmd.append("/span") + self.logger.info("Using span mode across monitors") # Sound sound = conn.get("sound", "Yes") diff --git a/test_enhanced_monitor.py b/test_enhanced_monitor.py new file mode 100644 index 0000000..85e2534 --- /dev/null +++ b/test_enhanced_monitor.py @@ -0,0 +1,69 @@ +#!/usr/bin/env python3 + +import subprocess +import logging + +# Set up logging to see the output +logging.basicConfig(level=logging.INFO, format='%(levelname)s: %(message)s') +logger = logging.getLogger(__name__) + +def _get_best_monitor_selection(count): + """Get the best monitor selection based on layout""" + try: + result = subprocess.run(['xfreerdp', '/monitor-list'], + capture_output=True, text=True, timeout=5) + if result.returncode == 0: + lines = result.stdout.strip().split('\n') + monitors = [] + primary_monitor = None + + for line in lines: + # Clean up the line and split by whitespace/tabs + cleaned_line = line.strip() + is_primary = cleaned_line.startswith('*') + cleaned_line = cleaned_line.replace('*', '').strip() + + if '[' in cleaned_line and ']' in cleaned_line and 'x' in cleaned_line and '+' in cleaned_line: + # Split by whitespace/tabs + parts = cleaned_line.split() + if len(parts) >= 3: + id_part = parts[0] # [0] + pos_part = parts[2] # +3840+0 + if '[' in id_part and ']' in id_part: + monitor_id = int(id_part.strip('[]')) + x_pos = int(pos_part.split('+')[1]) + monitor_info = (monitor_id, x_pos, is_primary) + monitors.append(monitor_info) + + if is_primary: + primary_monitor = monitor_id + + # Sort monitors by X position (left to right) + monitors.sort(key=lambda x: x[1]) + + # For debugging, log the monitor layout + logger.info(f"Monitor layout detected: {[(m[0], m[1], 'primary' if m[2] else 'secondary') for m in monitors]}") + + # Return the leftmost monitors (excluding position and primary flag) + selected = [str(m[0]) for m in monitors[:count]] + selected_str = ','.join(selected) + + logger.info(f"Selected {count} monitors: {selected_str}") + return selected_str + except Exception as e: + logger.error(f"Error detecting monitors: {e}") + + # Fallback: simple sequential selection + fallback = ','.join([str(i) for i in range(count)]) + logger.warning(f"Using fallback monitor selection: {fallback}") + return fallback + +if __name__ == "__main__": + print("=== Testing Enhanced Monitor Selection Logic ===") + print() + + for count in [2, 3]: + print(f"Testing {count} monitors:") + result = _get_best_monitor_selection(count) + print(f"Result: {result}") + print() \ No newline at end of file