diff --git a/rdp_client.py b/rdp_client.py index 14b8810..380ca25 100755 --- a/rdp_client.py +++ b/rdp_client.py @@ -245,7 +245,50 @@ class RDPClient: return options - def _get_best_monitor_selection(self, count): + def _get_monitors_combined_resolution(self, monitor_list): + """Get the combined resolution for selected monitors""" + try: + result = subprocess.run(['xfreerdp', '/monitor-list'], + capture_output=True, text=True, timeout=5) + if result.returncode == 0: + lines = result.stdout.strip().split('\n') + selected_monitors = [int(x.strip()) for x in monitor_list.split(',')] + + min_x = float('inf') + max_x = 0 + max_y = 0 + + for line in lines: + cleaned_line = line.strip().replace('*', '').strip() + if '[' in cleaned_line and ']' in cleaned_line: + parts = cleaned_line.split() + if len(parts) >= 3: + id_part = parts[0] + res_part = parts[1] # 1920x1080 + pos_part = parts[2] # +3840+0 + + if '[' in id_part and ']' in id_part: + monitor_id = int(id_part.strip('[]')) + if monitor_id in selected_monitors: + # Parse resolution + width, height = map(int, res_part.split('x')) + # Parse position + pos_coords = pos_part.split('+')[1:] # ['3840', '0'] + x_pos = int(pos_coords[0]) + + min_x = min(min_x, x_pos) + max_x = max(max_x, x_pos + width) + max_y = max(max_y, height) + + if min_x != float('inf'): + total_width = max_x - min_x + total_height = max_y + return f"{total_width}x{total_height}" + except Exception as e: + self.logger.error(f"Error calculating combined resolution: {e}") + + # Fallback to a reasonable default + return "3840x1080" # Assume dual 1920x1080 monitors """Get the best monitor selection based on layout""" try: result = subprocess.run(['xfreerdp', '/monitor-list'], @@ -846,13 +889,25 @@ Multi-Monitor Support: multimon = conn.get("multimon", "No") use_specific_monitors = multimon in ["2 Monitors", "3 Monitors", "4 Monitors"] - # Resolution - avoid /f with specific monitor selection due to conflicts + # Get monitor list once if needed + monitor_list = None + if use_specific_monitors: + if multimon == "2 Monitors": + monitor_list = self._get_best_monitor_selection(2) + elif multimon == "3 Monitors": + monitor_list = self._get_best_monitor_selection(3) + elif multimon == "4 Monitors": + monitor_list = self._get_best_monitor_selection(4) + + # Resolution - calculate proper size for specific monitor selection resolution = conn.get("resolution", "1920x1080") if resolution == "Full Screen" and not use_specific_monitors: cmd.append("/f") elif resolution == "Full Screen" and use_specific_monitors: - # Don't use /f with specific monitors - let /monitors: determine the layout - self.logger.info("Skipping /f (fullscreen) due to specific monitor selection") + # Calculate combined resolution for selected monitors + combined_res = self._get_monitors_combined_resolution(monitor_list) + cmd.append(f"/size:{combined_res}") + self.logger.info(f"Using calculated resolution {combined_res} for {multimon}: {monitor_list}") else: cmd.append(f"/size:{resolution}") @@ -860,19 +915,10 @@ Multi-Monitor Support: color_depth = conn.get("color_depth", 32) cmd.append(f"/bpp:{color_depth}") - # Multiple monitors - use /monitors: without /multimon for specific selection - if multimon == "2 Monitors": - monitor_list = self._get_best_monitor_selection(2) + # Multiple monitors - use /monitors: for specific selection + if use_specific_monitors: 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}") + self.logger.info(f"Using specific monitors for {multimon}: {monitor_list}") elif multimon == "All Monitors": cmd.append("/multimon") self.logger.info("Using all available monitors") diff --git a/test_combined_resolution.py b/test_combined_resolution.py new file mode 100644 index 0000000..f2c5e9c --- /dev/null +++ b/test_combined_resolution.py @@ -0,0 +1,104 @@ +#!/usr/bin/env python3 + +import subprocess + +def get_monitors_combined_resolution(monitor_list): + """Get the combined resolution for selected monitors""" + try: + result = subprocess.run(['xfreerdp', '/monitor-list'], + capture_output=True, text=True, timeout=5) + if result.returncode == 0: + lines = result.stdout.strip().split('\n') + selected_monitors = [int(x.strip()) for x in monitor_list.split(',')] + + min_x = float('inf') + max_x = 0 + max_y = 0 + + print(f"Looking for monitors: {selected_monitors}") + + for line in lines: + cleaned_line = line.strip().replace('*', '').strip() + if '[' in cleaned_line and ']' in cleaned_line: + parts = cleaned_line.split() + if len(parts) >= 3: + id_part = parts[0] + res_part = parts[1] # 1920x1080 + pos_part = parts[2] # +3840+0 + + if '[' in id_part and ']' in id_part: + monitor_id = int(id_part.strip('[]')) + if monitor_id in selected_monitors: + # Parse resolution + width, height = map(int, res_part.split('x')) + # Parse position + pos_coords = pos_part.split('+')[1:] # ['3840', '0'] + x_pos = int(pos_coords[0]) + + print(f" Monitor {monitor_id}: {width}x{height} at +{x_pos}+0") + + min_x = min(min_x, x_pos) + max_x = max(max_x, x_pos + width) + max_y = max(max_y, height) + + if min_x != float('inf'): + total_width = max_x - min_x + total_height = max_y + print(f" Combined: {total_width}x{total_height} (from x={min_x} to x={max_x})") + return f"{total_width}x{total_height}" + except Exception as e: + print(f"Error: {e}") + + # Fallback to a reasonable default + return "3840x1080" # Assume dual 1920x1080 monitors + +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: + 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: + parts = cleaned_line.split() + if len(parts) >= 3: + id_part = parts[0] + pos_part = parts[2] + 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) + + monitors.sort(key=lambda x: x[1]) + selected = [str(m[0]) for m in monitors[:count]] + return ','.join(selected) + except: + pass + + return ','.join([str(i) for i in range(count)]) + +if __name__ == "__main__": + print("=== Testing Combined Resolution Calculation ===") + print() + print("Current monitor layout:") + subprocess.run(['xfreerdp', '/monitor-list']) + print() + + for count in [2, 3]: + monitor_list = get_best_monitor_selection(count) + print(f"Testing {count} monitors (selection: {monitor_list}):") + combined_res = get_monitors_combined_resolution(monitor_list) + print(f"Result: {combined_res}") + print() + + # Show what the command would be + print(f"Command would be: xfreerdp /size:{combined_res} /monitors:{monitor_list}") + print("-" * 50) \ No newline at end of file