In preparation for nulldrv display modes support.
-- v7: win32u: Move display placement logic out of graphics drivers. win32u: Move full display mode lookup out of graphics drivers. win32u: Use current mode position if desired mode doesn't specify it. win32u: Always copy devmode in validate_display_settings. win32u: Read registry or current mode when validation needs it. win32u: Do not keep display modes driver extra in the registry.
From: R��mi Bernon rbernon@codeweavers.com
It's not always serializable and cannot be shared across processes. --- dlls/win32u/sysparams.c | 17 +++-------------- 1 file changed, 3 insertions(+), 14 deletions(-)
diff --git a/dlls/win32u/sysparams.c b/dlls/win32u/sysparams.c index ef2462e6540..01f0151fff7 100644 --- a/dlls/win32u/sysparams.c +++ b/dlls/win32u/sysparams.c @@ -178,7 +178,6 @@ static const WCHAR x_panningW[] = {'X','P','a','n','n','i','n','g',0}; static const WCHAR y_panningW[] = {'Y','P','a','n','n','i','n','g',0}; static const WCHAR orientationW[] = {'O','r','i','e','n','t','a','t','i','o','n',0}; static const WCHAR fixed_outputW[] = {'F','i','x','e','d','O','u','t','p','u','t',0}; -static const WCHAR driver_extraW[] = {'D','r','i','v','e','r','E','x','t','r','a',0}; static const WCHAR mode_countW[] = {'M','o','d','e','C','o','u','n','t',0};
static const char guid_devclass_displayA[] = "{4D36E968-E325-11CE-BFC1-08002BE10318}"; @@ -453,7 +452,6 @@ static BOOL write_adapter_mode( HKEY adapter_key, DWORD index, const DEVMODEW *m set_mode_field( x_panningW, dmPosition.x, DM_POSITION ); set_mode_field( y_panningW, dmPosition.y, DM_POSITION ); } - ret = set_reg_value( hkey, driver_extraW, REG_BINARY, mode + 1, mode->dmDriverExtra );
#undef set_mode_field
@@ -500,11 +498,6 @@ static BOOL read_adapter_mode( HKEY adapter_key, DWORD index, DEVMODEW *mode )
#undef query_mode_field
- ret = query_reg_value( hkey, driver_extraW, value, sizeof(value_buf) ) && - value->Type == REG_BINARY; - if (ret && value->DataLength <= mode->dmDriverExtra) - memcpy( mode + 1, value->Data, mode->dmDriverExtra ); - done: NtClose( hkey ); return TRUE; @@ -555,8 +548,8 @@ static BOOL read_display_adapter_settings( unsigned int index, struct adapter *i char buffer[4096]; KEY_VALUE_PARTIAL_INFORMATION *value = (void *)buffer; WCHAR *value_str = (WCHAR *)value->Data; - DWORD i, driver_extra = 0, size; DEVMODEW *mode; + DWORD i, size; HKEY hkey;
if (!enum_key && !(enum_key = reg_open_key( NULL, enum_keyW, sizeof(enum_keyW) ))) @@ -599,16 +592,13 @@ static BOOL read_display_adapter_settings( unsigned int index, struct adapter *i /* ModeCount / DriverExtra */ if (query_reg_value( hkey, mode_countW, value, sizeof(buffer) ) && value->Type == REG_DWORD) info->mode_count = *(const DWORD *)value->Data; - if (query_reg_value( hkey, driver_extraW, value, sizeof(buffer) ) && value->Type == REG_DWORD) - driver_extra = *(const DWORD *)value->Data;
/* Modes */ - if ((info->modes = calloc( info->mode_count, sizeof(DEVMODEW) + driver_extra ))) + if ((info->modes = calloc( info->mode_count, sizeof(DEVMODEW) ))) { for (i = 0, mode = info->modes; i < info->mode_count; i++) { mode->dmSize = offsetof(DEVMODEW, dmICMMethod); - mode->dmDriverExtra = driver_extra; if (!read_adapter_mode( hkey, i, mode )) break; mode = NEXT_DEVMODEW(mode); } @@ -1349,8 +1339,7 @@ static void add_mode( const DEVMODEW *mode, void *param )
if (write_adapter_mode( ctx->adapter_key, ctx->mode_count, mode )) { - if (!ctx->mode_count++) set_reg_value( ctx->adapter_key, driver_extraW, REG_DWORD, - &mode->dmDriverExtra, sizeof(mode->dmDriverExtra) ); + ctx->mode_count++; set_reg_value( ctx->adapter_key, mode_countW, REG_DWORD, &ctx->mode_count, sizeof(ctx->mode_count) ); } }
From: R��mi Bernon rbernon@codeweavers.com
--- dlls/win32u/sysparams.c | 20 +++++++++----------- 1 file changed, 9 insertions(+), 11 deletions(-)
diff --git a/dlls/win32u/sysparams.c b/dlls/win32u/sysparams.c index 01f0151fff7..c5605ffdb10 100644 --- a/dlls/win32u/sysparams.c +++ b/dlls/win32u/sysparams.c @@ -2026,7 +2026,7 @@ static BOOL is_detached_mode( const DEVMODEW *mode ) mode->dmPelsHeight == 0; }
-static DEVMODEW *validate_display_settings( DEVMODEW *default_mode, DEVMODEW *current_mode, DEVMODEW *devmode ) +static DEVMODEW *validate_display_settings( const WCHAR *adapter_path, const WCHAR *device_name, DEVMODEW *devmode, DEVMODEW *temp_mode ) { if (devmode) { @@ -2043,9 +2043,9 @@ static DEVMODEW *validate_display_settings( DEVMODEW *default_mode, DEVMODEW *cu
if (!devmode) { - if (!default_mode->dmSize) return NULL; + if (!read_registry_settings( adapter_path, temp_mode )) return NULL; TRACE( "Return to original display mode\n" ); - devmode = default_mode; + devmode = temp_mode; }
if ((devmode->dmFields & (DM_PELSWIDTH | DM_PELSHEIGHT)) != (DM_PELSWIDTH | DM_PELSHEIGHT)) @@ -2056,9 +2056,10 @@ static DEVMODEW *validate_display_settings( DEVMODEW *default_mode, DEVMODEW *cu
if (!is_detached_mode( devmode ) && (!devmode->dmPelsWidth || !devmode->dmPelsHeight)) { - if (!current_mode->dmSize) return NULL; - if (!devmode->dmPelsWidth) devmode->dmPelsWidth = current_mode->dmPelsWidth; - if (!devmode->dmPelsHeight) devmode->dmPelsHeight = current_mode->dmPelsHeight; + DEVMODEW current_mode = {.dmSize = sizeof(DEVMODEW)}; + if (!user_driver->pGetCurrentDisplaySettings( device_name, ¤t_mode )) return NULL; + if (!devmode->dmPelsWidth) devmode->dmPelsWidth = current_mode.dmPelsWidth; + if (!devmode->dmPelsHeight) devmode->dmPelsHeight = current_mode.dmPelsHeight; }
return devmode; @@ -2070,8 +2071,8 @@ static DEVMODEW *validate_display_settings( DEVMODEW *default_mode, DEVMODEW *cu LONG WINAPI NtUserChangeDisplaySettings( UNICODE_STRING *devname, DEVMODEW *devmode, HWND hwnd, DWORD flags, void *lparam ) { - DEVMODEW default_mode = {.dmSize = sizeof(DEVMODEW)}, current_mode = {.dmSize = sizeof(DEVMODEW)}; WCHAR device_name[CCHDEVICENAME], adapter_path[MAX_PATH]; + DEVMODEW temp_mode = {.dmSize = sizeof(DEVMODEW)}; LONG ret = DISP_CHANGE_SUCCESSFUL; struct adapter *adapter;
@@ -2099,10 +2100,7 @@ LONG WINAPI NtUserChangeDisplaySettings( UNICODE_STRING *devname, DEVMODEW *devm return DISP_CHANGE_BADPARAM; }
- if (!read_registry_settings( adapter_path, &default_mode )) default_mode.dmSize = 0; - if (!NtUserEnumDisplaySettings( devname, ENUM_CURRENT_SETTINGS, ¤t_mode, 0 )) current_mode.dmSize = 0; - - if (!(devmode = validate_display_settings( &default_mode, ¤t_mode, devmode ))) ret = DISP_CHANGE_BADMODE; + if (!(devmode = validate_display_settings( adapter_path, device_name, devmode, &temp_mode ))) ret = DISP_CHANGE_BADMODE; else if (user_driver->pChangeDisplaySettingsEx( device_name, devmode, hwnd, flags | CDS_TEST, lparam )) ret = DISP_CHANGE_BADMODE; else if ((flags & CDS_UPDATEREGISTRY) && !write_registry_settings( adapter_path, devmode )) ret = DISP_CHANGE_NOTUPDATED; else if (flags & (CDS_TEST | CDS_NORESET)) ret = DISP_CHANGE_SUCCESSFUL;
From: R��mi Bernon rbernon@codeweavers.com
So that updating dmPelsWidth / dmPelsHeight doesn't modify user devmode. --- dlls/win32u/sysparams.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-)
diff --git a/dlls/win32u/sysparams.c b/dlls/win32u/sysparams.c index c5605ffdb10..c6c4551c478 100644 --- a/dlls/win32u/sysparams.c +++ b/dlls/win32u/sysparams.c @@ -2041,12 +2041,13 @@ static DEVMODEW *validate_display_settings( const WCHAR *adapter_path, const WCH devmode = NULL; }
- if (!devmode) + if (devmode) memcpy( temp_mode, devmode, devmode->dmSize ); + else { if (!read_registry_settings( adapter_path, temp_mode )) return NULL; TRACE( "Return to original display mode\n" ); - devmode = temp_mode; } + devmode = temp_mode;
if ((devmode->dmFields & (DM_PELSWIDTH | DM_PELSHEIGHT)) != (DM_PELSWIDTH | DM_PELSHEIGHT)) {
From: R��mi Bernon rbernon@codeweavers.com
--- dlls/win32u/sysparams.c | 7 ++++++- dlls/winex11.drv/display.c | 10 ---------- 2 files changed, 6 insertions(+), 11 deletions(-)
diff --git a/dlls/win32u/sysparams.c b/dlls/win32u/sysparams.c index c6c4551c478..36434877c93 100644 --- a/dlls/win32u/sysparams.c +++ b/dlls/win32u/sysparams.c @@ -2055,12 +2055,17 @@ static DEVMODEW *validate_display_settings( const WCHAR *adapter_path, const WCH return NULL; }
- if (!is_detached_mode( devmode ) && (!devmode->dmPelsWidth || !devmode->dmPelsHeight)) + if (!is_detached_mode( devmode ) && (!devmode->dmPelsWidth || !devmode->dmPelsHeight || !(devmode->dmFields & DM_POSITION))) { DEVMODEW current_mode = {.dmSize = sizeof(DEVMODEW)}; if (!user_driver->pGetCurrentDisplaySettings( device_name, ¤t_mode )) return NULL; if (!devmode->dmPelsWidth) devmode->dmPelsWidth = current_mode.dmPelsWidth; if (!devmode->dmPelsHeight) devmode->dmPelsHeight = current_mode.dmPelsHeight; + if (!(devmode->dmFields & DM_POSITION)) + { + devmode->dmPosition = current_mode.dmPosition; + devmode->dmFields |= DM_POSITION; + } }
return devmode; diff --git a/dlls/winex11.drv/display.c b/dlls/winex11.drv/display.c index 77f71b73b77..34fd0136fc3 100644 --- a/dlls/winex11.drv/display.c +++ b/dlls/winex11.drv/display.c @@ -498,16 +498,6 @@ static LONG get_display_settings(DEVMODEW **new_displays, const WCHAR *dev_name, else if (!wcsicmp(dev_name, display_device.DeviceName)) { *mode = *dev_mode; - if (!(dev_mode->dmFields & DM_POSITION)) - { - memset(¤t_mode, 0, sizeof(current_mode)); - current_mode.dmSize = sizeof(current_mode); - if (!NtUserEnumDisplaySettings( &device_name, ENUM_CURRENT_SETTINGS, ¤t_mode, 0 )) - goto done; - - mode->dmFields |= DM_POSITION; - mode->dmPosition = current_mode.dmPosition; - } } else {
From: R��mi Bernon rbernon@codeweavers.com
--- dlls/win32u/sysparams.c | 46 +++++++++++++++++++++++++++++++++----- dlls/winemac.drv/display.c | 3 +-- dlls/winex11.drv/display.c | 30 +------------------------ 3 files changed, 43 insertions(+), 36 deletions(-)
diff --git a/dlls/win32u/sysparams.c b/dlls/win32u/sysparams.c index 36434877c93..ec7ca4734d1 100644 --- a/dlls/win32u/sysparams.c +++ b/dlls/win32u/sysparams.c @@ -2026,7 +2026,34 @@ static BOOL is_detached_mode( const DEVMODEW *mode ) mode->dmPelsHeight == 0; }
-static DEVMODEW *validate_display_settings( const WCHAR *adapter_path, const WCHAR *device_name, DEVMODEW *devmode, DEVMODEW *temp_mode ) +static DEVMODEW *find_display_mode( DEVMODEW *modes, DEVMODEW *devmode ) +{ + DEVMODEW *mode; + + if (is_detached_mode( devmode )) return devmode; + + for (mode = modes; mode && mode->dmSize; mode = NEXT_DEVMODEW(mode)) + { + if ((devmode->dmFields & DM_BITSPERPEL) && devmode->dmBitsPerPel && devmode->dmBitsPerPel != mode->dmBitsPerPel) + continue; + if ((devmode->dmFields & DM_PELSWIDTH) && devmode->dmPelsWidth != mode->dmPelsWidth) + continue; + if ((devmode->dmFields & DM_PELSHEIGHT) && devmode->dmPelsHeight != mode->dmPelsHeight) + continue; + if ((devmode->dmFields & DM_DISPLAYFREQUENCY) && devmode->dmDisplayFrequency && mode->dmDisplayFrequency && + devmode->dmDisplayFrequency != 1 && devmode->dmDisplayFrequency != mode->dmDisplayFrequency) + continue; + if ((devmode->dmFields & DM_DISPLAYORIENTATION) && devmode->dmDisplayOrientation != mode->dmDisplayOrientation) + continue; + + return mode; + } + + return NULL; +} + +static DEVMODEW *get_full_mode( const WCHAR *adapter_path, const WCHAR *device_name, DEVMODEW *modes, + DEVMODEW *devmode, DEVMODEW *temp_mode ) { if (devmode) { @@ -2068,6 +2095,12 @@ static DEVMODEW *validate_display_settings( const WCHAR *adapter_path, const WCH } }
+ if ((devmode = find_display_mode( modes, devmode )) && devmode != temp_mode) + { + devmode->dmFields |= DM_POSITION; + devmode->dmPosition = temp_mode->dmPosition; + } + return devmode; }
@@ -2077,8 +2110,8 @@ static DEVMODEW *validate_display_settings( const WCHAR *adapter_path, const WCH LONG WINAPI NtUserChangeDisplaySettings( UNICODE_STRING *devname, DEVMODEW *devmode, HWND hwnd, DWORD flags, void *lparam ) { + DEVMODEW *modes, temp_mode = {.dmSize = sizeof(DEVMODEW)}; WCHAR device_name[CCHDEVICENAME], adapter_path[MAX_PATH]; - DEVMODEW temp_mode = {.dmSize = sizeof(DEVMODEW)}; LONG ret = DISP_CHANGE_SUCCESSFUL; struct adapter *adapter;
@@ -2098,19 +2131,22 @@ LONG WINAPI NtUserChangeDisplaySettings( UNICODE_STRING *devname, DEVMODEW *devm { lstrcpyW( device_name, adapter->dev.device_name ); lstrcpyW( adapter_path, adapter->config_key ); + /* allocate an extra mode to make iteration easier */ + modes = calloc( adapter->mode_count + 1, sizeof(DEVMODEW) ); + if (modes) memcpy( modes, adapter->modes, adapter->mode_count * sizeof(DEVMODEW) ); } unlock_display_devices(); - if (!adapter) + if (!adapter || !modes) { WARN( "Invalid device name %s.\n", debugstr_us(devname) ); return DISP_CHANGE_BADPARAM; }
- if (!(devmode = validate_display_settings( adapter_path, device_name, devmode, &temp_mode ))) ret = DISP_CHANGE_BADMODE; - else if (user_driver->pChangeDisplaySettingsEx( device_name, devmode, hwnd, flags | CDS_TEST, lparam )) ret = DISP_CHANGE_BADMODE; + if (!(devmode = get_full_mode( adapter_path, device_name, modes, devmode, &temp_mode ))) ret = DISP_CHANGE_BADMODE; else if ((flags & CDS_UPDATEREGISTRY) && !write_registry_settings( adapter_path, devmode )) ret = DISP_CHANGE_NOTUPDATED; else if (flags & (CDS_TEST | CDS_NORESET)) ret = DISP_CHANGE_SUCCESSFUL; else ret = user_driver->pChangeDisplaySettingsEx( device_name, devmode, hwnd, flags, lparam ); + free( modes );
if (ret) ERR( "Changing %s display settings returned %d.\n", debugstr_us(devname), ret ); return ret; diff --git a/dlls/winemac.drv/display.c b/dlls/winemac.drv/display.c index 8baa4b6df83..52c4b8846f1 100644 --- a/dlls/winemac.drv/display.c +++ b/dlls/winemac.drv/display.c @@ -881,8 +881,7 @@ LONG macdrv_ChangeDisplaySettingsEx(LPCWSTR devname, LPDEVMODEW devmode,
if (best_display_mode) { - if (flags & (CDS_TEST | CDS_NORESET)) ret = DISP_CHANGE_SUCCESSFUL; - else if (wcsicmp(primary_adapter, devname)) + if (wcsicmp(primary_adapter, devname)) { FIXME("Changing non-primary adapter settings is currently unsupported.\n"); ret = DISP_CHANGE_SUCCESSFUL; diff --git a/dlls/winex11.drv/display.c b/dlls/winex11.drv/display.c index 34fd0136fc3..5304a2c0ecb 100644 --- a/dlls/winex11.drv/display.c +++ b/dlls/winex11.drv/display.c @@ -774,41 +774,13 @@ static BOOL all_detached_settings(const DEVMODEW *displays) LONG X11DRV_ChangeDisplaySettingsEx( LPCWSTR devname, LPDEVMODEW devmode, HWND hwnd, DWORD flags, LPVOID lpvoid ) { - DEVMODEW *displays, *mode, *full_mode; + DEVMODEW *displays; LONG ret;
ret = get_display_settings( &displays, devname, devmode ); if (ret != DISP_CHANGE_SUCCESSFUL) return ret;
- if (flags & CDS_UPDATEREGISTRY && devname && devmode) - { - for (mode = displays; mode->dmSize; mode = NEXT_DEVMODEW(mode)) - { - ULONG_PTR *id = (ULONG_PTR *)(mode + 1); - - if (!wcsicmp(mode->dmDeviceName, devname)) - { - full_mode = get_full_mode(*id, mode); - if (!full_mode) - { - free(displays); - return DISP_CHANGE_BADMODE; - } - - memcpy( &devmode->dmFields, &full_mode->dmFields, devmode->dmSize - offsetof(DEVMODEW, dmFields) ); - free_full_mode(full_mode); - break; - } - } - } - - if (flags & (CDS_TEST | CDS_NORESET)) - { - free(displays); - return DISP_CHANGE_SUCCESSFUL; - } - if (all_detached_settings( displays )) { WARN("Detaching all displays is not permitted.\n");
From: R��mi Bernon rbernon@codeweavers.com
--- dlls/win32u/driver.c | 14 +- dlls/win32u/sysparams.c | 264 ++++++++++++++++++++++++++-- dlls/wineandroid.drv/init.c | 9 +- dlls/winemac.drv/display.c | 101 +++++------ dlls/winemac.drv/gdi.c | 2 +- dlls/winemac.drv/macdrv.h | 3 +- dlls/winex11.drv/display.c | 342 ++++-------------------------------- dlls/winex11.drv/init.c | 2 +- dlls/winex11.drv/x11drv.h | 3 +- include/wine/gdi_driver.h | 2 +- 10 files changed, 346 insertions(+), 396 deletions(-)
diff --git a/dlls/win32u/driver.c b/dlls/win32u/driver.c index e8f410b7f4c..32c7ed0a591 100644 --- a/dlls/win32u/driver.c +++ b/dlls/win32u/driver.c @@ -753,8 +753,8 @@ static void nulldrv_UpdateClipboard(void) { }
-static LONG nulldrv_ChangeDisplaySettingsEx( LPCWSTR name, LPDEVMODEW mode, HWND hwnd, - DWORD flags, LPVOID lparam ) +static LONG nulldrv_ChangeDisplaySettings( LPDEVMODEW displays, HWND hwnd, + DWORD flags, LPVOID lparam ) { return DISP_CHANGE_FAILED; } @@ -1071,10 +1071,10 @@ static SHORT loaderdrv_VkKeyScanEx( WCHAR ch, HKL layout ) return load_driver()->pVkKeyScanEx( ch, layout ); }
-static LONG loaderdrv_ChangeDisplaySettingsEx( LPCWSTR name, LPDEVMODEW mode, HWND hwnd, - DWORD flags, LPVOID lparam ) +static LONG loaderdrv_ChangeDisplaySettings( LPDEVMODEW displays, HWND hwnd, + DWORD flags, LPVOID lparam ) { - return load_driver()->pChangeDisplaySettingsEx( name, mode, hwnd, flags, lparam ); + return load_driver()->pChangeDisplaySettings( displays, hwnd, flags, lparam ); }
static BOOL loaderdrv_EnumDisplaySettingsEx( LPCWSTR name, DWORD num, LPDEVMODEW mode, DWORD flags ) @@ -1187,7 +1187,7 @@ static const struct user_driver_funcs lazy_load_driver = nulldrv_ClipboardWindowProc, loaderdrv_UpdateClipboard, /* display modes */ - loaderdrv_ChangeDisplaySettingsEx, + loaderdrv_ChangeDisplaySettings, loaderdrv_EnumDisplaySettingsEx, loaderdrv_GetCurrentDisplaySettings, loaderdrv_UpdateDisplayDevices, @@ -1263,7 +1263,7 @@ void __wine_set_user_driver( const struct user_driver_funcs *funcs, UINT version SET_USER_FUNC(ClipCursor); SET_USER_FUNC(ClipboardWindowProc); SET_USER_FUNC(UpdateClipboard); - SET_USER_FUNC(ChangeDisplaySettingsEx); + SET_USER_FUNC(ChangeDisplaySettings); SET_USER_FUNC(EnumDisplaySettingsEx); SET_USER_FUNC(GetCurrentDisplaySettings); SET_USER_FUNC(UpdateDisplayDevices); diff --git a/dlls/win32u/sysparams.c b/dlls/win32u/sysparams.c index ec7ca4734d1..e901d0ec8a7 100644 --- a/dlls/win32u/sysparams.c +++ b/dlls/win32u/sysparams.c @@ -593,8 +593,8 @@ static BOOL read_display_adapter_settings( unsigned int index, struct adapter *i if (query_reg_value( hkey, mode_countW, value, sizeof(buffer) ) && value->Type == REG_DWORD) info->mode_count = *(const DWORD *)value->Data;
- /* Modes */ - if ((info->modes = calloc( info->mode_count, sizeof(DEVMODEW) ))) + /* Modes, allocate an extra mode for easier iteration */ + if ((info->modes = calloc( info->mode_count + 1, sizeof(DEVMODEW) ))) { for (i = 0, mode = info->modes; i < info->mode_count; i++) { @@ -2104,6 +2104,256 @@ static DEVMODEW *get_full_mode( const WCHAR *adapter_path, const WCHAR *device_n return devmode; }
+static DEVMODEW *get_display_settings( const WCHAR *devname, const DEVMODEW *devmode ) +{ + DEVMODEW *mode, *displays; + struct adapter *adapter; + BOOL ret; + + if (!lock_display_devices()) return NULL; + + /* allocate an extra mode for easier iteration */ + if (!(displays = calloc( list_count( &adapters ) + 1, sizeof(DEVMODEW) ))) goto done; + mode = displays; + + LIST_FOR_EACH_ENTRY( adapter, &adapters, struct adapter, entry ) + { + if (!adapter->mode_count) continue; + + mode->dmSize = sizeof(DEVMODEW); + if (devmode && !wcsicmp( devname, adapter->dev.device_name )) + memcpy( &mode->dmFields, &devmode->dmFields, devmode->dmSize - offsetof(DEVMODEW, dmFields) ); + else + { + if (!devname) ret = read_registry_settings( adapter->config_key, mode ); + else ret = user_driver->pGetCurrentDisplaySettings( adapter->dev.device_name, mode ); + if (!ret) goto done; + } + + lstrcpyW( mode->dmDeviceName, adapter->dev.device_name ); + mode = NEXT_DEVMODEW(mode); + } + + unlock_display_devices(); + return displays; + +done: + unlock_display_devices(); + free( displays ); + return NULL; +} + +static INT offset_length( POINT offset ) +{ + return offset.x * offset.x + offset.y * offset.y; +} + +static void set_rect_from_devmode( RECT *rect, const DEVMODEW *mode ) +{ + SetRect( rect, mode->dmPosition.x, mode->dmPosition.y, mode->dmPosition.x + mode->dmPelsWidth, + mode->dmPosition.y + mode->dmPelsHeight ); +} + +/* Check if a rect overlaps with placed display rects */ +static BOOL overlap_placed_displays( const RECT *rect, const DEVMODEW *displays ) +{ + const DEVMODEW *mode; + RECT intersect; + + for (mode = displays; mode->dmSize; mode = NEXT_DEVMODEW(mode)) + { + set_rect_from_devmode( &intersect, mode ); + if ((mode->dmFields & DM_POSITION) && intersect_rect( &intersect, &intersect, rect )) return TRUE; + } + + return FALSE; +} + +/* Get the offset with minimum length to place a display next to the placed displays with no spacing and overlaps */ +static POINT get_placement_offset( const DEVMODEW *displays, const DEVMODEW *placing ) +{ + POINT points[8], left_top, offset, min_offset = {0, 0}; + INT point_idx, point_count, vertex_idx; + BOOL has_placed = FALSE, first = TRUE; + RECT desired_rect, rect; + const DEVMODEW *mode; + INT width, height; + + set_rect_from_devmode( &desired_rect, placing ); + + /* If the display to be placed is detached, no offset is needed to place it */ + if (IsRectEmpty( &desired_rect )) return min_offset; + + /* If there is no placed and attached display, place this display as it is */ + for (mode = displays; mode->dmSize; mode = NEXT_DEVMODEW(mode)) + { + set_rect_from_devmode( &rect, mode ); + if ((mode->dmFields & DM_POSITION) && !IsRectEmpty( &rect )) + { + has_placed = TRUE; + break; + } + } + + if (!has_placed) return min_offset; + + /* Try to place this display with each of its four vertices at every vertex of the placed + * displays and see which combination has the minimum offset length */ + width = desired_rect.right - desired_rect.left; + height = desired_rect.bottom - desired_rect.top; + + for (mode = displays; mode->dmSize; mode = NEXT_DEVMODEW(mode)) + { + set_rect_from_devmode( &rect, mode ); + if (!(mode->dmFields & DM_POSITION) || IsRectEmpty( &rect )) continue; + + /* Get four vertices of the placed display rectangle */ + points[0].x = rect.left; + points[0].y = rect.top; + points[1].x = rect.left; + points[1].y = rect.bottom; + points[2].x = rect.right; + points[2].y = rect.top; + points[3].x = rect.right; + points[3].y = rect.bottom; + point_count = 4; + + /* Intersected points when moving the display to be placed horizontally */ + if (desired_rect.bottom >= rect.top && desired_rect.top <= rect.bottom) + { + points[point_count].x = rect.left; + points[point_count++].y = desired_rect.top; + points[point_count].x = rect.right; + points[point_count++].y = desired_rect.top; + } + /* Intersected points when moving the display to be placed vertically */ + if (desired_rect.left <= rect.right && desired_rect.right >= rect.left) + { + points[point_count].x = desired_rect.left; + points[point_count++].y = rect.top; + points[point_count].x = desired_rect.left; + points[point_count++].y = rect.bottom; + } + + /* Try moving each vertex of the display rectangle to each points */ + for (point_idx = 0; point_idx < point_count; ++point_idx) + { + for (vertex_idx = 0; vertex_idx < 4; ++vertex_idx) + { + switch (vertex_idx) + { + /* Move the bottom right vertex to the point */ + case 0: + left_top.x = points[point_idx].x - width; + left_top.y = points[point_idx].y - height; + break; + /* Move the bottom left vertex to the point */ + case 1: + left_top.x = points[point_idx].x; + left_top.y = points[point_idx].y - height; + break; + /* Move the top right vertex to the point */ + case 2: + left_top.x = points[point_idx].x - width; + left_top.y = points[point_idx].y; + break; + /* Move the top left vertex to the point */ + case 3: + left_top.x = points[point_idx].x; + left_top.y = points[point_idx].y; + break; + } + + offset.x = left_top.x - desired_rect.left; + offset.y = left_top.y - desired_rect.top; + rect = desired_rect; + OffsetRect( &rect, offset.x, offset.y ); + if (!overlap_placed_displays( &rect, displays )) + { + if (first) + { + min_offset = offset; + first = FALSE; + continue; + } + + if (offset_length( offset ) < offset_length( min_offset )) min_offset = offset; + } + } + } + } + + return min_offset; +} + +static void place_all_displays( DEVMODEW *displays ) +{ + POINT min_offset, offset; + DEVMODEW *mode, *placing; + + for (mode = displays; mode->dmSize; mode = NEXT_DEVMODEW(mode)) + mode->dmFields &= ~DM_POSITION; + + /* Place all displays with no extra space between them and no overlapping */ + while (1) + { + /* Place the unplaced display with the minimum offset length first */ + placing = NULL; + for (mode = displays; mode->dmSize; mode = NEXT_DEVMODEW(mode)) + { + if (mode->dmFields & DM_POSITION) continue; + + offset = get_placement_offset( displays, mode ); + if (!placing || offset_length( offset ) < offset_length( min_offset )) + { + min_offset = offset; + placing = mode; + } + } + + /* If all displays are placed */ + if (!placing) break; + + placing->dmPosition.x += min_offset.x; + placing->dmPosition.y += min_offset.y; + placing->dmFields |= DM_POSITION; + } +} + +static BOOL all_detached_settings( const DEVMODEW *displays ) +{ + const DEVMODEW *mode; + + for (mode = displays; mode->dmSize; mode = NEXT_DEVMODEW(mode)) + if (!is_detached_mode( mode )) return FALSE; + + return TRUE; +} + +static LONG apply_display_settings( const WCHAR *devname, const DEVMODEW *devmode, + HWND hwnd, DWORD flags, void *lparam ) +{ + DEVMODEW *displays; + LONG ret; + + displays = get_display_settings( devname, devmode ); + if (!displays) return DISP_CHANGE_FAILED; + + if (all_detached_settings( displays )) + { + WARN( "Detaching all modes is not permitted.\n" ); + free( displays ); + return DISP_CHANGE_SUCCESSFUL; + } + + place_all_displays( displays ); + + ret = user_driver->pChangeDisplaySettings( displays, hwnd, flags, lparam ); + + free( displays ); + return ret; +} + /*********************************************************************** * NtUserChangeDisplaySettings (win32u.@) */ @@ -2118,13 +2368,7 @@ LONG WINAPI NtUserChangeDisplaySettings( UNICODE_STRING *devname, DEVMODEW *devm TRACE( "%s %p %p %#x %p\n", debugstr_us(devname), devmode, hwnd, flags, lparam ); TRACE( "flags=%s\n", _CDS_flags(flags) );
- if ((!devname || !devname->Length) && !devmode) - { - ret = user_driver->pChangeDisplaySettingsEx( NULL, NULL, hwnd, flags, lparam ); - if (ret != DISP_CHANGE_SUCCESSFUL) - ERR( "Restoring all displays to their registry settings returned %d.\n", ret ); - return ret; - } + if ((!devname || !devname->Length) && !devmode) return apply_display_settings( NULL, NULL, hwnd, flags, lparam );
if (!lock_display_devices()) return DISP_CHANGE_FAILED; if ((adapter = find_adapter( devname ))) @@ -2145,7 +2389,7 @@ LONG WINAPI NtUserChangeDisplaySettings( UNICODE_STRING *devname, DEVMODEW *devm if (!(devmode = get_full_mode( adapter_path, device_name, modes, devmode, &temp_mode ))) ret = DISP_CHANGE_BADMODE; else if ((flags & CDS_UPDATEREGISTRY) && !write_registry_settings( adapter_path, devmode )) ret = DISP_CHANGE_NOTUPDATED; else if (flags & (CDS_TEST | CDS_NORESET)) ret = DISP_CHANGE_SUCCESSFUL; - else ret = user_driver->pChangeDisplaySettingsEx( device_name, devmode, hwnd, flags, lparam ); + else ret = apply_display_settings( device_name, devmode, hwnd, flags, lparam ); free( modes );
if (ret) ERR( "Changing %s display settings returned %d.\n", debugstr_us(devname), ret ); diff --git a/dlls/wineandroid.drv/init.c b/dlls/wineandroid.drv/init.c index 4ddc66e73e8..7d05475dd27 100644 --- a/dlls/wineandroid.drv/init.c +++ b/dlls/wineandroid.drv/init.c @@ -260,12 +260,11 @@ static BOOL CDECL ANDROID_DeleteDC( PHYSDEV dev )
/*********************************************************************** - * ANDROID_ChangeDisplaySettingsEx + * ANDROID_ChangeDisplaySettings */ -LONG ANDROID_ChangeDisplaySettingsEx( LPCWSTR devname, LPDEVMODEW devmode, - HWND hwnd, DWORD flags, LPVOID lpvoid ) +LONG ANDROID_ChangeDisplaySettings( LPDEVMODEW displays, HWND hwnd, DWORD flags, LPVOID lpvoid ) { - FIXME( "(%s,%p,%p,0x%08x,%p)\n", debugstr_w( devname ), devmode, hwnd, flags, lpvoid ); + FIXME( "(%p,%p,0x%08x,%p)\n", displays, hwnd, flags, lpvoid ); return DISP_CHANGE_SUCCESSFUL; }
@@ -377,7 +376,7 @@ static const struct user_driver_funcs android_drv_funcs = .pMapVirtualKeyEx = ANDROID_MapVirtualKeyEx, .pVkKeyScanEx = ANDROID_VkKeyScanEx, .pSetCursor = ANDROID_SetCursor, - .pChangeDisplaySettingsEx = ANDROID_ChangeDisplaySettingsEx, + .pChangeDisplaySettings = ANDROID_ChangeDisplaySettings, .pEnumDisplaySettingsEx = ANDROID_EnumDisplaySettingsEx, .pGetCurrentDisplaySettings = ANDROID_GetCurrentDisplaySettings, .pUpdateDisplayDevices = ANDROID_UpdateDisplayDevices, diff --git a/dlls/winemac.drv/display.c b/dlls/winemac.drv/display.c index 52c4b8846f1..3e2788f8803 100644 --- a/dlls/winemac.drv/display.c +++ b/dlls/winemac.drv/display.c @@ -34,6 +34,7 @@
WINE_DEFAULT_DEBUG_CHANNEL(display);
+#define NEXT_DEVMODEW(mode) ((DEVMODEW *)((char *)((mode) + 1) + (mode)->dmDriverExtra))
struct display_mode_descriptor { @@ -804,89 +805,78 @@ better: }
/*********************************************************************** - * ChangeDisplaySettingsEx (MACDRV.@) + * ChangeDisplaySettings (MACDRV.@) * */ -LONG macdrv_ChangeDisplaySettingsEx(LPCWSTR devname, LPDEVMODEW devmode, - HWND hwnd, DWORD flags, LPVOID lpvoid) +LONG macdrv_ChangeDisplaySettings(LPDEVMODEW displays, HWND hwnd, DWORD flags, LPVOID lpvoid) { WCHAR primary_adapter[CCHDEVICENAME]; - LONG ret = DISP_CHANGE_BADMODE; - DEVMODEW default_mode; + LONG ret = DISP_CHANGE_SUCCESSFUL; + DEVMODEW *mode; int bpp; - struct macdrv_display *displays; + struct macdrv_display *macdrv_displays; int num_displays; CFArrayRef display_modes; struct display_mode_descriptor *desc; CGDisplayModeRef best_display_mode;
- TRACE("%s %p %p 0x%08x %p\n", debugstr_w(devname), devmode, hwnd, flags, lpvoid); + TRACE("%p %p 0x%08x %p\n", displays, hwnd, flags, lpvoid);
init_original_display_mode();
if (!get_primary_adapter(primary_adapter)) return DISP_CHANGE_FAILED;
- if (!devname && !devmode) - { - UNICODE_STRING str; - memset(&default_mode, 0, sizeof(default_mode)); - default_mode.dmSize = sizeof(default_mode); - RtlInitUnicodeString(&str, primary_adapter); - if (!NtUserEnumDisplaySettings(&str, ENUM_REGISTRY_SETTINGS, &default_mode, 0)) - { - ERR("Default mode not found for %s!\n", wine_dbgstr_w(primary_adapter)); - return DISP_CHANGE_BADMODE; - } - - devname = primary_adapter; - devmode = &default_mode; - } - - if (is_detached_mode(devmode)) - { - FIXME("Detaching adapters is currently unsupported.\n"); - return DISP_CHANGE_SUCCESSFUL; - } - - if (macdrv_get_displays(&displays, &num_displays)) + if (macdrv_get_displays(&macdrv_displays, &num_displays)) return DISP_CHANGE_FAILED;
- display_modes = copy_display_modes(displays[0].displayID, FALSE); + display_modes = copy_display_modes(macdrv_displays[0].displayID, FALSE); if (!display_modes) { - macdrv_free_displays(displays); + macdrv_free_displays(macdrv_displays); return DISP_CHANGE_FAILED; }
pthread_mutex_lock(&modes_mutex); bpp = get_default_bpp(); pthread_mutex_unlock(&modes_mutex); - if ((devmode->dmFields & DM_BITSPERPEL) && devmode->dmBitsPerPel != bpp) - TRACE("using default %d bpp instead of caller's request %d bpp\n", bpp, devmode->dmBitsPerPel); - - TRACE("looking for %dx%dx%dbpp @%d Hz", - (devmode->dmFields & DM_PELSWIDTH ? devmode->dmPelsWidth : 0), - (devmode->dmFields & DM_PELSHEIGHT ? devmode->dmPelsHeight : 0), - bpp, - (devmode->dmFields & DM_DISPLAYFREQUENCY ? devmode->dmDisplayFrequency : 0)); - if (devmode->dmFields & DM_DISPLAYFIXEDOUTPUT) - TRACE(" %sstretched", devmode->dmDisplayFixedOutput == DMDFO_STRETCH ? "" : "un"); - if (devmode->dmFields & DM_DISPLAYFLAGS) - TRACE(" %sinterlaced", devmode->dmDisplayFlags & DM_INTERLACED ? "" : "non-"); - TRACE("\n");
- desc = create_original_display_mode_descriptor(displays[0].displayID); - best_display_mode = find_best_display_mode(devmode, display_modes, bpp, desc); + desc = create_original_display_mode_descriptor(macdrv_displays[0].displayID);
- if (best_display_mode) + for (mode = displays; mode->dmSize && !ret; mode = NEXT_DEVMODEW(mode)) { - if (wcsicmp(primary_adapter, devname)) + if (wcsicmp(primary_adapter, mode->dmDeviceName)) { FIXME("Changing non-primary adapter settings is currently unsupported.\n"); - ret = DISP_CHANGE_SUCCESSFUL; + continue; + } + if (is_detached_mode(mode)) + { + FIXME("Detaching adapters is currently unsupported.\n"); + continue; + } + + if ((mode->dmFields & DM_BITSPERPEL) && mode->dmBitsPerPel != bpp) + TRACE("using default %d bpp instead of caller's request %d bpp\n", bpp, mode->dmBitsPerPel); + + TRACE("looking for %dx%dx%dbpp @%d Hz", + (mode->dmFields & DM_PELSWIDTH ? mode->dmPelsWidth : 0), + (mode->dmFields & DM_PELSHEIGHT ? mode->dmPelsHeight : 0), + bpp, + (mode->dmFields & DM_DISPLAYFREQUENCY ? mode->dmDisplayFrequency : 0)); + if (mode->dmFields & DM_DISPLAYFIXEDOUTPUT) + TRACE(" %sstretched", mode->dmDisplayFixedOutput == DMDFO_STRETCH ? "" : "un"); + if (mode->dmFields & DM_DISPLAYFLAGS) + TRACE(" %sinterlaced", mode->dmDisplayFlags & DM_INTERLACED ? "" : "non-"); + TRACE("\n"); + + if (!(best_display_mode = find_best_display_mode(mode, display_modes, bpp, desc))) + { + ERR("No matching mode found %ux%ux%d @%u!\n", mode->dmPelsWidth, mode->dmPelsHeight, + bpp, mode->dmDisplayFrequency); + ret = DISP_CHANGE_BADMODE; } - else if (macdrv_set_display_mode(&displays[0], best_display_mode)) + else if (macdrv_set_display_mode(&macdrv_displays[0], best_display_mode)) { int mode_bpp = display_mode_bits_per_pixel(best_display_mode); size_t width = CGDisplayModeGetWidth(best_display_mode); @@ -902,7 +892,6 @@ LONG macdrv_ChangeDisplaySettingsEx(LPCWSTR devname, LPDEVMODEW devmode,
send_message(NtUserGetDesktopWindow(), WM_MACDRV_UPDATE_DESKTOP_RECT, mode_bpp, MAKELPARAM(width, height)); - ret = DISP_CHANGE_SUCCESSFUL; } else { @@ -910,16 +899,10 @@ LONG macdrv_ChangeDisplaySettingsEx(LPCWSTR devname, LPDEVMODEW devmode, ret = DISP_CHANGE_FAILED; } } - else - { - /* no valid modes found */ - ERR("No matching mode found %ux%ux%d @%u!\n", devmode->dmPelsWidth, devmode->dmPelsHeight, - bpp, devmode->dmDisplayFrequency); - }
free_display_mode_descriptor(desc); CFRelease(display_modes); - macdrv_free_displays(displays); + macdrv_free_displays(macdrv_displays);
return ret; } diff --git a/dlls/winemac.drv/gdi.c b/dlls/winemac.drv/gdi.c index 2057891faa7..c3e3fa6cdb7 100644 --- a/dlls/winemac.drv/gdi.c +++ b/dlls/winemac.drv/gdi.c @@ -268,7 +268,7 @@ static const struct user_driver_funcs macdrv_funcs =
.pActivateKeyboardLayout = macdrv_ActivateKeyboardLayout, .pBeep = macdrv_Beep, - .pChangeDisplaySettingsEx = macdrv_ChangeDisplaySettingsEx, + .pChangeDisplaySettings = macdrv_ChangeDisplaySettings, .pClipCursor = macdrv_ClipCursor, .pClipboardWindowProc = macdrv_ClipboardWindowProc, .pCreateDesktopWindow = macdrv_CreateDesktopWindow, diff --git a/dlls/winemac.drv/macdrv.h b/dlls/winemac.drv/macdrv.h index 2e44206dc92..e0492046ccd 100644 --- a/dlls/winemac.drv/macdrv.h +++ b/dlls/winemac.drv/macdrv.h @@ -123,8 +123,7 @@ static inline struct macdrv_thread_data *macdrv_thread_data(void)
extern BOOL macdrv_ActivateKeyboardLayout(HKL hkl, UINT flags) DECLSPEC_HIDDEN; extern void macdrv_Beep(void) DECLSPEC_HIDDEN; -extern LONG macdrv_ChangeDisplaySettingsEx(LPCWSTR devname, LPDEVMODEW devmode, - HWND hwnd, DWORD flags, LPVOID lpvoid) DECLSPEC_HIDDEN; +extern LONG macdrv_ChangeDisplaySettings(LPDEVMODEW displays, HWND hwnd, DWORD flags, LPVOID lpvoid) DECLSPEC_HIDDEN; extern BOOL macdrv_EnumDisplaySettingsEx(LPCWSTR devname, DWORD mode, LPDEVMODEW devmode, DWORD flags) DECLSPEC_HIDDEN; extern BOOL macdrv_GetCurrentDisplaySettings(LPCWSTR name, LPDEVMODEW devmode) DECLSPEC_HIDDEN; diff --git a/dlls/winex11.drv/display.c b/dlls/winex11.drv/display.c index 5304a2c0ecb..2556ac15b4e 100644 --- a/dlls/winex11.drv/display.c +++ b/dlls/winex11.drv/display.c @@ -408,22 +408,15 @@ static DEVMODEW *get_full_mode(ULONG_PTR id, DEVMODEW *dev_mode) { found_mode = (DEVMODEW *)((BYTE *)modes + (sizeof(*modes) + modes[0].dmDriverExtra) * mode_idx);
- if (dev_mode->dmFields & DM_BITSPERPEL && - dev_mode->dmBitsPerPel && - found_mode->dmBitsPerPel != dev_mode->dmBitsPerPel) + if (found_mode->dmBitsPerPel != dev_mode->dmBitsPerPel) continue; - if (dev_mode->dmFields & DM_PELSWIDTH && found_mode->dmPelsWidth != dev_mode->dmPelsWidth) + if (found_mode->dmPelsWidth != dev_mode->dmPelsWidth) continue; - if (dev_mode->dmFields & DM_PELSHEIGHT && found_mode->dmPelsHeight != dev_mode->dmPelsHeight) + if (found_mode->dmPelsHeight != dev_mode->dmPelsHeight) continue; - if (dev_mode->dmFields & DM_DISPLAYFREQUENCY && - dev_mode->dmDisplayFrequency && - found_mode->dmDisplayFrequency && - dev_mode->dmDisplayFrequency != 1 && - dev_mode->dmDisplayFrequency != found_mode->dmDisplayFrequency) + if (found_mode->dmDisplayFrequency != dev_mode->dmDisplayFrequency) continue; - if (dev_mode->dmFields & DM_DISPLAYORIENTATION && - found_mode->dmDisplayOrientation != dev_mode->dmDisplayOrientation) + if (found_mode->dmDisplayOrientation != dev_mode->dmDisplayOrientation) continue;
break; @@ -455,283 +448,22 @@ static void free_full_mode(DEVMODEW *mode) free(mode); }
-static LONG get_display_settings(DEVMODEW **new_displays, const WCHAR *dev_name, DEVMODEW *dev_mode) -{ - DEVMODEW registry_mode, current_mode, *mode, *displays; - INT display_idx, display_count = 0; - DISPLAY_DEVICEW display_device; - LONG ret = DISP_CHANGE_FAILED; - UNICODE_STRING device_name; - - display_device.cb = sizeof(display_device); - for (display_idx = 0; !NtUserEnumDisplayDevices( NULL, display_idx, &display_device, 0 ); ++display_idx) - ++display_count; - - /* use driver extra data to store an ULONG_PTR adapter id after each mode, - * and allocate an extra mode to make iteration easier */ - if (!(displays = calloc(display_count + 1, sizeof(DEVMODEW) + sizeof(ULONG_PTR)))) goto done; - mode = displays; - - for (display_idx = 0; display_idx < display_count; ++display_idx) - { - ULONG_PTR *id = (ULONG_PTR *)(mode + 1); - - if (NtUserEnumDisplayDevices( NULL, display_idx, &display_device, 0 )) - goto done; - - if (!settings_handler.get_id(display_device.DeviceName, id)) - { - ret = DISP_CHANGE_BADPARAM; - goto done; - } - - RtlInitUnicodeString( &device_name, display_device.DeviceName ); - - if (!dev_mode) - { - memset(®istry_mode, 0, sizeof(registry_mode)); - registry_mode.dmSize = sizeof(registry_mode); - if (!NtUserEnumDisplaySettings( &device_name, ENUM_REGISTRY_SETTINGS, ®istry_mode, 0 )) - goto done; - *mode = registry_mode; - } - else if (!wcsicmp(dev_name, display_device.DeviceName)) - { - *mode = *dev_mode; - } - else - { - memset(¤t_mode, 0, sizeof(current_mode)); - current_mode.dmSize = sizeof(current_mode); - if (!NtUserEnumDisplaySettings( &device_name, ENUM_CURRENT_SETTINGS, ¤t_mode, 0 )) - goto done; - *mode = current_mode; - } - - mode->dmSize = sizeof(DEVMODEW); - lstrcpyW(mode->dmDeviceName, display_device.DeviceName); - mode->dmDriverExtra = sizeof(ULONG_PTR); - mode = NEXT_DEVMODEW(mode); - } - - *new_displays = displays; - return DISP_CHANGE_SUCCESSFUL; - -done: - free(displays); - return ret; -} - -static INT offset_length(POINT offset) -{ - return offset.x * offset.x + offset.y * offset.y; -} - -static void set_rect_from_devmode(RECT *rect, const DEVMODEW *mode) -{ - SetRect(rect, mode->dmPosition.x, mode->dmPosition.y, mode->dmPosition.x + mode->dmPelsWidth, mode->dmPosition.y + mode->dmPelsHeight); -} - -/* Check if a rect overlaps with placed display rects */ -static BOOL overlap_placed_displays(const RECT *rect, const DEVMODEW *displays) -{ - const DEVMODEW *mode; - RECT intersect; - - for (mode = displays; mode->dmSize; mode = NEXT_DEVMODEW(mode)) - { - set_rect_from_devmode(&intersect, mode); - if ((mode->dmFields & DM_POSITION) && intersect_rect(&intersect, &intersect, rect)) - return TRUE; - } - return FALSE; -} - -/* Get the offset with minimum length to place a display next to the placed displays with no spacing and overlaps */ -static POINT get_placement_offset(const DEVMODEW *displays, const DEVMODEW *placing) -{ - POINT points[8], left_top, offset, min_offset = {0, 0}; - INT point_idx, point_count, vertex_idx; - BOOL has_placed = FALSE, first = TRUE; - RECT desired_rect, rect; - const DEVMODEW *mode; - INT width, height; - - set_rect_from_devmode(&desired_rect, placing); - - /* If the display to be placed is detached, no offset is needed to place it */ - if (IsRectEmpty(&desired_rect)) - return min_offset; - - /* If there is no placed and attached display, place this display as it is */ - for (mode = displays; mode->dmSize; mode = NEXT_DEVMODEW(mode)) - { - set_rect_from_devmode(&rect, mode); - if ((mode->dmFields & DM_POSITION) && !IsRectEmpty(&rect)) - { - has_placed = TRUE; - break; - } - } - - if (!has_placed) - return min_offset; - - /* Try to place this display with each of its four vertices at every vertex of the placed - * displays and see which combination has the minimum offset length */ - width = desired_rect.right - desired_rect.left; - height = desired_rect.bottom - desired_rect.top; - - for (mode = displays; mode->dmSize; mode = NEXT_DEVMODEW(mode)) - { - set_rect_from_devmode(&rect, mode); - if (!(mode->dmFields & DM_POSITION) || IsRectEmpty(&rect)) - continue; - - /* Get four vertices of the placed display rectangle */ - points[0].x = rect.left; - points[0].y = rect.top; - points[1].x = rect.left; - points[1].y = rect.bottom; - points[2].x = rect.right; - points[2].y = rect.top; - points[3].x = rect.right; - points[3].y = rect.bottom; - point_count = 4; - - /* Intersected points when moving the display to be placed horizontally */ - if (desired_rect.bottom >= rect.top && - desired_rect.top <= rect.bottom) - { - points[point_count].x = rect.left; - points[point_count++].y = desired_rect.top; - points[point_count].x = rect.right; - points[point_count++].y = desired_rect.top; - } - /* Intersected points when moving the display to be placed vertically */ - if (desired_rect.left <= rect.right && - desired_rect.right >= rect.left) - { - points[point_count].x = desired_rect.left; - points[point_count++].y = rect.top; - points[point_count].x = desired_rect.left; - points[point_count++].y = rect.bottom; - } - - /* Try moving each vertex of the display rectangle to each points */ - for (point_idx = 0; point_idx < point_count; ++point_idx) - { - for (vertex_idx = 0; vertex_idx < 4; ++vertex_idx) - { - switch (vertex_idx) - { - /* Move the bottom right vertex to the point */ - case 0: - left_top.x = points[point_idx].x - width; - left_top.y = points[point_idx].y - height; - break; - /* Move the bottom left vertex to the point */ - case 1: - left_top.x = points[point_idx].x; - left_top.y = points[point_idx].y - height; - break; - /* Move the top right vertex to the point */ - case 2: - left_top.x = points[point_idx].x - width; - left_top.y = points[point_idx].y; - break; - /* Move the top left vertex to the point */ - case 3: - left_top.x = points[point_idx].x; - left_top.y = points[point_idx].y; - break; - } - - offset.x = left_top.x - desired_rect.left; - offset.y = left_top.y - desired_rect.top; - rect = desired_rect; - OffsetRect(&rect, offset.x, offset.y); - if (!overlap_placed_displays(&rect, displays)) - { - if (first) - { - min_offset = offset; - first = FALSE; - continue; - } - - if (offset_length(offset) < offset_length(min_offset)) - min_offset = offset; - } - } - } - } - - return min_offset; -} - -static void place_all_displays(DEVMODEW *displays) -{ - INT left_most = INT_MAX, top_most = INT_MAX; - POINT min_offset, offset; - DEVMODEW *mode, *placing; - - for (mode = displays; mode->dmSize; mode = NEXT_DEVMODEW(mode)) - mode->dmFields &= ~DM_POSITION; - - /* Place all displays with no extra space between them and no overlapping */ - while (1) - { - /* Place the unplaced display with the minimum offset length first */ - placing = NULL; - for (mode = displays; mode->dmSize; mode = NEXT_DEVMODEW(mode)) - { - if (mode->dmFields & DM_POSITION) - continue; - - offset = get_placement_offset(displays, mode); - if (!placing || offset_length(offset) < offset_length(min_offset)) - { - min_offset = offset; - placing = mode; - } - } - - /* If all displays are placed */ - if (!placing) - break; - - placing->dmPosition.x += min_offset.x; - placing->dmPosition.y += min_offset.y; - placing->dmFields |= DM_POSITION; - - left_most = min(left_most, placing->dmPosition.x); - top_most = min(top_most, placing->dmPosition.y); - } - - /* Convert virtual screen coordinates to root coordinates */ - for (mode = displays; mode->dmSize; mode = NEXT_DEVMODEW(mode)) - { - mode->dmPosition.x -= left_most; - mode->dmPosition.y -= top_most; - } -} - -static LONG apply_display_settings(DEVMODEW *displays, BOOL do_attach) +static LONG apply_display_settings( DEVMODEW *displays, ULONG_PTR *ids, BOOL do_attach ) { DEVMODEW *full_mode; BOOL attached_mode; + LONG count, ret; DEVMODEW *mode; - LONG ret;
- for (mode = displays; mode->dmSize; mode = NEXT_DEVMODEW(mode)) + for (count = 0, mode = displays; mode->dmSize; mode = NEXT_DEVMODEW(mode), count++) { - ULONG_PTR *id = (ULONG_PTR *)(mode + 1); + ULONG_PTR *id = ids + count;
attached_mode = !is_detached_mode(mode); if ((attached_mode && !do_attach) || (!attached_mode && do_attach)) continue;
+ /* FIXME: get a full mode again because X11 driver extra data isn't portable */ full_mode = get_full_mode(*id, mode); if (!full_mode) return DISP_CHANGE_BADMODE; @@ -754,49 +486,43 @@ static LONG apply_display_settings(DEVMODEW *displays, BOOL do_attach) return DISP_CHANGE_SUCCESSFUL; }
-static BOOL all_detached_settings(const DEVMODEW *displays) -{ - const DEVMODEW *mode; - - for (mode = displays; mode->dmSize; mode = NEXT_DEVMODEW(mode)) - { - if (!is_detached_mode(mode)) - return FALSE; - } - - return TRUE; -} - /*********************************************************************** - * ChangeDisplaySettingsEx (X11DRV.@) + * ChangeDisplaySettings (X11DRV.@) * */ -LONG X11DRV_ChangeDisplaySettingsEx( LPCWSTR devname, LPDEVMODEW devmode, - HWND hwnd, DWORD flags, LPVOID lpvoid ) +LONG X11DRV_ChangeDisplaySettings( LPDEVMODEW displays, HWND hwnd, DWORD flags, LPVOID lpvoid ) { - DEVMODEW *displays; - LONG ret; - - ret = get_display_settings( &displays, devname, devmode ); - if (ret != DISP_CHANGE_SUCCESSFUL) - return ret; + INT left_most = INT_MAX, top_most = INT_MAX; + LONG count, ret = DISP_CHANGE_BADPARAM; + ULONG_PTR *ids; + DEVMODEW *mode;
- if (all_detached_settings( displays )) + /* Convert virtual screen coordinates to root coordinates, and find display ids. + * We cannot safely get the ids while changing modes, as the backend state may be invalidated. + */ + for (count = 0, mode = displays; mode->dmSize; mode = NEXT_DEVMODEW(mode), count++) { - WARN("Detaching all displays is not permitted.\n"); - free(displays); - return DISP_CHANGE_SUCCESSFUL; + left_most = min( left_most, mode->dmPosition.x ); + top_most = min( top_most, mode->dmPosition.y ); }
- place_all_displays( displays ); + if (!(ids = calloc( count, sizeof(*ids) ))) return DISP_CHANGE_FAILED; + for (count = 0, mode = displays; mode->dmSize; mode = NEXT_DEVMODEW(mode), count++) + { + if (!settings_handler.get_id( mode->dmDeviceName, ids + count )) goto done; + mode->dmPosition.x -= left_most; + mode->dmPosition.y -= top_most; + }
/* Detach displays first to free up CRTCs */ - ret = apply_display_settings( displays, FALSE ); + ret = apply_display_settings( displays, ids, FALSE ); if (ret == DISP_CHANGE_SUCCESSFUL) - ret = apply_display_settings( displays, TRUE ); + ret = apply_display_settings( displays, ids, TRUE ); if (ret == DISP_CHANGE_SUCCESSFUL) X11DRV_DisplayDevices_Update(TRUE); - free(displays); + +done: + free( ids ); return ret; }
diff --git a/dlls/winex11.drv/init.c b/dlls/winex11.drv/init.c index 82ba7ea24ea..5d688c27114 100644 --- a/dlls/winex11.drv/init.c +++ b/dlls/winex11.drv/init.c @@ -403,7 +403,7 @@ static const struct user_driver_funcs x11drv_funcs = .pGetCursorPos = X11DRV_GetCursorPos, .pSetCursorPos = X11DRV_SetCursorPos, .pClipCursor = X11DRV_ClipCursor, - .pChangeDisplaySettingsEx = X11DRV_ChangeDisplaySettingsEx, + .pChangeDisplaySettings = X11DRV_ChangeDisplaySettings, .pEnumDisplaySettingsEx = X11DRV_EnumDisplaySettingsEx, .pGetCurrentDisplaySettings = X11DRV_GetCurrentDisplaySettings, .pUpdateDisplayDevices = X11DRV_UpdateDisplayDevices, diff --git a/dlls/winex11.drv/x11drv.h b/dlls/winex11.drv/x11drv.h index 31a94d1632a..7300bd91aec 100644 --- a/dlls/winex11.drv/x11drv.h +++ b/dlls/winex11.drv/x11drv.h @@ -213,8 +213,7 @@ extern void X11DRV_SetCursor( HCURSOR handle ) DECLSPEC_HIDDEN; extern BOOL X11DRV_SetCursorPos( INT x, INT y ) DECLSPEC_HIDDEN; extern BOOL X11DRV_GetCursorPos( LPPOINT pos ) DECLSPEC_HIDDEN; extern BOOL X11DRV_ClipCursor( LPCRECT clip ) DECLSPEC_HIDDEN; -extern LONG X11DRV_ChangeDisplaySettingsEx( LPCWSTR devname, LPDEVMODEW devmode, - HWND hwnd, DWORD flags, LPVOID lpvoid ) DECLSPEC_HIDDEN; +extern LONG X11DRV_ChangeDisplaySettings( LPDEVMODEW displays, HWND hwnd, DWORD flags, LPVOID lpvoid ) DECLSPEC_HIDDEN; extern BOOL X11DRV_EnumDisplaySettingsEx( LPCWSTR name, DWORD n, LPDEVMODEW devmode, DWORD flags ) DECLSPEC_HIDDEN; extern BOOL X11DRV_GetCurrentDisplaySettings( LPCWSTR name, LPDEVMODEW devmode ) DECLSPEC_HIDDEN; diff --git a/include/wine/gdi_driver.h b/include/wine/gdi_driver.h index 0ba4851a2c3..e1d8998d812 100644 --- a/include/wine/gdi_driver.h +++ b/include/wine/gdi_driver.h @@ -295,7 +295,7 @@ struct user_driver_funcs LRESULT (*pClipboardWindowProc)(HWND,UINT,WPARAM,LPARAM); void (*pUpdateClipboard)(void); /* display modes */ - LONG (*pChangeDisplaySettingsEx)(LPCWSTR,LPDEVMODEW,HWND,DWORD,LPVOID); + LONG (*pChangeDisplaySettings)(LPDEVMODEW,HWND,DWORD,LPVOID); BOOL (*pEnumDisplaySettingsEx)(LPCWSTR,DWORD,LPDEVMODEW,DWORD); BOOL (*pGetCurrentDisplaySettings)(LPCWSTR,LPDEVMODEW); BOOL (*pUpdateDisplayDevices)(const struct gdi_device_manager *,BOOL,void*);
Zhiyi Zhang (@zhiyi) commented about dlls/win32u/sysparams.c:
/* ModeCount / DriverExtra */
Comments
Zhiyi Zhang (@zhiyi) commented about dlls/win32u/sysparams.c:
+static DEVMODEW *get_display_settings( const WCHAR *devname, const DEVMODEW *devmode ) +{
- DEVMODEW *mode, *displays;
- struct adapter *adapter;
- BOOL ret;
- if (!lock_display_devices()) return NULL;
- /* allocate an extra mode for easier iteration */
- if (!(displays = calloc( list_count( &adapters ) + 1, sizeof(DEVMODEW) ))) goto done;
- mode = displays;
- LIST_FOR_EACH_ENTRY( adapter, &adapters, struct adapter, entry )
- {
if (!adapter->mode_count) continue;
There should be at least one available mode so this condition seems unnecessary.
Zhiyi Zhang (@zhiyi) commented about dlls/winemac.drv/display.c:
- for (mode = displays; mode->dmSize && !ret; mode = NEXT_DEVMODEW(mode)) {
if (wcsicmp(primary_adapter, devname))
if (wcsicmp(primary_adapter, mode->dmDeviceName)) { FIXME("Changing non-primary adapter settings is currently unsupported.\n");
ret = DISP_CHANGE_SUCCESSFUL;
continue;
}
if (is_detached_mode(mode))
{
FIXME("Detaching adapters is currently unsupported.\n");
continue;
}
if ((mode->dmFields & DM_BITSPERPEL) && mode->dmBitsPerPel != bpp)
You can remove the DM_BITSPERPEL, DM_PELSWIDTH, DM_PELSHEIGHT, and DM_DISPLAYFREQUENCY checks here since you already got a full mode in win32u.