Fix fullscreen resolution for specific monitor selection
Problem: Previous fix removed /f but didn't provide proper resolution, causing RDP to open in very low resolution window instead of fullscreen. Solution: Calculate combined resolution of selected monitors - 2 monitors (1,2): /size:3840x1080 /monitors:1,2 - 3 monitors (1,2,0): /size:5760x1080 /monitors:1,2,0 Changes: - Add _get_monitors_combined_resolution() method - Calculate total width from leftmost to rightmost selected monitor - Use calculated resolution with /size: parameter - Eliminate duplicate monitor selection calls - Enhanced logging for resolution calculation Expected result: - '2 Monitors' opens fullscreen across 2 monitors at proper resolution - '3 Monitors' opens fullscreen across 3 monitors at proper resolution - Maintains /monitors: parameter for correct monitor targeting
This commit is contained in:
@@ -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")
|
||||
|
||||
104
test_combined_resolution.py
Normal file
104
test_combined_resolution.py
Normal file
@@ -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)
|
||||
Reference in New Issue
Block a user