Wine applications crash in VNC/headless environments due to invalid all-zero monitor coordinates.
The root cause is: - Environment Issue: VNC systems report all displays as RR_Disconnected - Faulty Fallback: Wine incorrectly reverts to legacy XRandR 1.0 API when no "connected" displays are detected - API Incompatibility: Modern XRandR 1.6 doesn't support Wine's XRandR 1.0 implementation, causing XRRSizes() to return empty display modes - Uninitialized Data: This leaves critical display fields (dmPelsWidth/Height) at initialization value 0
-- v2: winex11: handle fallback display modes when XRandR fails server: prevent division by zero in coordinate mapping
From: Wei Xie xiewei@uniontech.com
Wine applications crash in VNC/headless environments due to invalid all-zero monitor coordinates.
The root cause is: Environment Issue: VNC systems report all displays as RR_Disconnected Faulty Fallback: Wine incorrectly reverts to legacy XRandR 1.0 API when no "connected" displays are detected API Incompatibility: Modern XRandR 1.6 doesn't support Wine's XRandR 1.0 implementation, causing XRRSizes() to return empty display modes Uninitialized Data: This leaves critical display fields (dmPelsWidth/Height) at initialization value 0 --- server/window.c | 2 ++ 1 file changed, 2 insertions(+)
diff --git a/server/window.c b/server/window.c index c59b8646118..8d75482940d 100644 --- a/server/window.c +++ b/server/window.c @@ -315,6 +315,8 @@ static void map_point_raw_to_virt( struct desktop *desktop, int *x, int *y ) width_from = monitor->raw.right - monitor->raw.left; height_from = monitor->raw.bottom - monitor->raw.top;
+ if (width_from == 0 || height_from == 0) return; + *x = *x * 2 - (monitor->raw.left * 2 + width_from); *x = (*x * width_to * 2 + width_from) / (width_from * 2); *x = (*x + monitor->virt.left * 2 + width_to) / 2;
From: Wei Xie xiewei@uniontech.com
1. Added fallback logic to use default display dimensions when XRandR fails to provide screen sizes 2. Implemented default mode creation with standard 60Hz refresh rate 3. Added proper error handling for memory allocation failures 4. Maintains compatibility with systems where XRandR extension is not available
The reason for the problem is that in scenes where the monitor is not connected, xrandr does not get connected display --- dlls/winex11.drv/xrandr.c | 35 ++++++++++++++++++++++++++++++++++- 1 file changed, 34 insertions(+), 1 deletion(-)
diff --git a/dlls/winex11.drv/xrandr.c b/dlls/winex11.drv/xrandr.c index 979cbc8645f..a794d1be0f9 100644 --- a/dlls/winex11.drv/xrandr.c +++ b/dlls/winex11.drv/xrandr.c @@ -267,8 +267,35 @@ static BOOL xrandr10_get_modes( x11drv_settings_id id, DWORD flags, DEVMODEW **n short *rates;
sizes = pXRRSizes( gdi_display, DefaultScreen( gdi_display ), &size_count ); + /* 如果没有获取到屏幕大小,尝试使用默认屏幕大小 */ if (size_count <= 0) + { + INT width = DisplayWidth(gdi_display, DefaultScreen(gdi_display)); + INT height = DisplayHeight(gdi_display, DefaultScreen(gdi_display)); + + if (width > 0 && height > 0) + { + /* 使用默认屏幕大小创建一个模式 */ + mode_count = 1; + modes = calloc(mode_count * DEPTH_COUNT, sizeof(*modes) + sizeof(SizeID)); + if (!modes) + { + RtlSetLastWin32Error(ERROR_NOT_ENOUGH_MEMORY); + return FALSE; + } + + for (depth_idx = 0, mode = modes; depth_idx < DEPTH_COUNT; ++depth_idx) + { + add_xrandr10_mode(mode, depths[depth_idx], width, height, 0, 0, full); + mode = NEXT_DEVMODEW(mode); + } + + *new_modes = modes; + *new_mode_count = mode_count * DEPTH_COUNT; + return TRUE; + } return FALSE; + }
for (size_idx = 0; size_idx < size_count; ++size_idx) { @@ -350,7 +377,13 @@ static BOOL xrandr10_get_current_mode( x11drv_settings_id id, DEVMODEW *mode )
sizes = pXRRSizes( gdi_display, DefaultScreen( gdi_display ), &size_count ); if (size_count <= 0) - return FALSE; + { + mode->dmBitsPerPel = screen_bpp; + mode->dmPelsWidth = DisplayWidth(gdi_display, DefaultScreen(gdi_display)); + mode->dmPelsHeight = DisplayHeight(gdi_display, DefaultScreen(gdi_display)); + mode->dmDisplayFrequency = 60; + return TRUE; + }
screen_config = pXRRGetScreenInfo( gdi_display, DefaultRootWindow( gdi_display ) ); size_id = pXRRConfigCurrentConfiguration( screen_config, &rotation );