[PATCH 4/5] winex11.drv: Merge settings.c into display.c.
Rémi Bernon
wine at gitlab.winehq.org
Mon Jun 27 07:50:23 CDT 2022
From: Rémi Bernon <rbernon at codeweavers.com>
Signed-off-by: Rémi Bernon <rbernon at codeweavers.com>
---
dlls/winex11.drv/Makefile.in | 1 -
dlls/winex11.drv/display.c | 962 +++++++++++++++++++++++++++++++++
dlls/winex11.drv/settings.c | 999 -----------------------------------
3 files changed, 962 insertions(+), 1000 deletions(-)
delete mode 100644 dlls/winex11.drv/settings.c
diff --git a/dlls/winex11.drv/Makefile.in b/dlls/winex11.drv/Makefile.in
index 3c653902ef2..e79c691b4d5 100644
--- a/dlls/winex11.drv/Makefile.in
+++ b/dlls/winex11.drv/Makefile.in
@@ -22,7 +22,6 @@ C_SRCS = \
opengl.c \
palette.c \
pen.c \
- settings.c \
systray.c \
vulkan.c \
window.c \
diff --git a/dlls/winex11.drv/display.c b/dlls/winex11.drv/display.c
index 510cb9dcee6..dec9d0afba8 100644
--- a/dlls/winex11.drv/display.c
+++ b/dlls/winex11.drv/display.c
@@ -30,6 +30,968 @@ WINE_DEFAULT_DEBUG_CHANNEL(x11drv);
static struct x11drv_display_device_handler host_handler;
struct x11drv_display_device_handler desktop_handler;
+static struct x11drv_settings_handler settings_handler;
+
+struct x11drv_display_setting
+{
+ ULONG_PTR id;
+ BOOL placed;
+ RECT new_rect;
+ RECT desired_rect;
+ DEVMODEW desired_mode;
+};
+
+struct x11drv_display_depth
+{
+ struct list entry;
+ ULONG_PTR display_id;
+ DWORD depth;
+};
+
+/* Display device emulated depth list, protected by modes_section */
+static struct list x11drv_display_depth_list = LIST_INIT(x11drv_display_depth_list);
+
+/* All Windows drivers seen so far either support 32 bit depths, or 24 bit depths, but never both. So if we have
+ * a 32 bit framebuffer, report 32 bit bpps, otherwise 24 bit ones.
+ */
+static const unsigned int depths_24[] = {8, 16, 24};
+static const unsigned int depths_32[] = {8, 16, 32};
+const unsigned int *depths;
+
+/* Cached display modes for a device, protected by modes_section */
+static WCHAR cached_device_name[CCHDEVICENAME];
+static DWORD cached_flags;
+static DEVMODEW *cached_modes;
+static UINT cached_mode_count;
+
+static pthread_mutex_t settings_mutex = PTHREAD_MUTEX_INITIALIZER;
+
+void X11DRV_Settings_SetHandler(const struct x11drv_settings_handler *new_handler)
+{
+ if (new_handler->priority > settings_handler.priority)
+ {
+ settings_handler = *new_handler;
+ TRACE("Display settings are now handled by: %s.\n", settings_handler.name);
+ }
+}
+
+/***********************************************************************
+ * Default handlers if resolution switching is not enabled
+ *
+ */
+static BOOL nores_get_id(const WCHAR *device_name, ULONG_PTR *id)
+{
+ WCHAR primary_adapter[CCHDEVICENAME];
+
+ if (!get_primary_adapter( primary_adapter ))
+ return FALSE;
+
+ *id = !wcsicmp( device_name, primary_adapter ) ? 1 : 0;
+ return TRUE;
+}
+
+static BOOL nores_get_modes(ULONG_PTR id, DWORD flags, DEVMODEW **new_modes, UINT *mode_count)
+{
+ RECT primary = get_host_primary_monitor_rect();
+ DEVMODEW *modes;
+
+ modes = calloc(1, sizeof(*modes));
+ if (!modes)
+ {
+ SetLastError(ERROR_NOT_ENOUGH_MEMORY);
+ return FALSE;
+ }
+
+ modes[0].dmSize = sizeof(*modes);
+ modes[0].dmDriverExtra = 0;
+ modes[0].dmFields = DM_DISPLAYORIENTATION | DM_BITSPERPEL | DM_PELSWIDTH | DM_PELSHEIGHT |
+ DM_DISPLAYFLAGS | DM_DISPLAYFREQUENCY;
+ modes[0].dmDisplayOrientation = DMDO_DEFAULT;
+ modes[0].dmBitsPerPel = screen_bpp;
+ modes[0].dmPelsWidth = primary.right;
+ modes[0].dmPelsHeight = primary.bottom;
+ modes[0].dmDisplayFlags = 0;
+ modes[0].dmDisplayFrequency = 60;
+
+ *new_modes = modes;
+ *mode_count = 1;
+ return TRUE;
+}
+
+static void nores_free_modes(DEVMODEW *modes)
+{
+ free(modes);
+}
+
+static BOOL nores_get_current_mode(ULONG_PTR id, DEVMODEW *mode)
+{
+ RECT primary = get_host_primary_monitor_rect();
+
+ mode->dmFields = DM_DISPLAYORIENTATION | DM_BITSPERPEL | DM_PELSWIDTH | DM_PELSHEIGHT |
+ DM_DISPLAYFLAGS | DM_DISPLAYFREQUENCY | DM_POSITION;
+ mode->dmDisplayOrientation = DMDO_DEFAULT;
+ mode->dmDisplayFlags = 0;
+ mode->dmPosition.x = 0;
+ mode->dmPosition.y = 0;
+
+ if (id != 1)
+ {
+ FIXME("Non-primary adapters are unsupported.\n");
+ mode->dmBitsPerPel = 0;
+ mode->dmPelsWidth = 0;
+ mode->dmPelsHeight = 0;
+ mode->dmDisplayFrequency = 0;
+ return TRUE;
+ }
+
+ mode->dmBitsPerPel = screen_bpp;
+ mode->dmPelsWidth = primary.right;
+ mode->dmPelsHeight = primary.bottom;
+ mode->dmDisplayFrequency = 60;
+ return TRUE;
+}
+
+static LONG nores_set_current_mode(ULONG_PTR id, DEVMODEW *mode)
+{
+ WARN("NoRes settings handler, ignoring mode change request.\n");
+ return DISP_CHANGE_SUCCESSFUL;
+}
+
+/* default handler only gets the current X desktop resolution */
+void X11DRV_Settings_Init(void)
+{
+ struct x11drv_settings_handler nores_handler;
+
+ depths = screen_bpp == 32 ? depths_32 : depths_24;
+
+ nores_handler.name = "NoRes";
+ nores_handler.priority = 1;
+ nores_handler.get_id = nores_get_id;
+ nores_handler.get_modes = nores_get_modes;
+ nores_handler.free_modes = nores_free_modes;
+ nores_handler.get_current_mode = nores_get_current_mode;
+ nores_handler.set_current_mode = nores_set_current_mode;
+ X11DRV_Settings_SetHandler(&nores_handler);
+}
+
+/* Initialize registry display settings when new display devices are added */
+void init_registry_display_settings(void)
+{
+ DEVMODEW dm = {.dmSize = sizeof(dm)};
+ DISPLAY_DEVICEW dd = {sizeof(dd)};
+ UNICODE_STRING device_name;
+ DWORD i = 0;
+ LONG ret;
+
+ while (!NtUserEnumDisplayDevices( NULL, i++, &dd, 0 ))
+ {
+ RtlInitUnicodeString( &device_name, dd.DeviceName );
+
+ /* Skip if the device already has registry display settings */
+ if (NtUserEnumDisplaySettings( &device_name, ENUM_REGISTRY_SETTINGS, &dm, 0 ))
+ continue;
+
+ if (!NtUserEnumDisplaySettings( &device_name, ENUM_CURRENT_SETTINGS, &dm, 0 ))
+ {
+ ERR("Failed to query current display settings for %s.\n", wine_dbgstr_w(dd.DeviceName));
+ continue;
+ }
+
+ TRACE("Device %s current display mode %ux%u %ubits %uHz at %d,%d.\n",
+ wine_dbgstr_w(dd.DeviceName), dm.dmPelsWidth, dm.dmPelsHeight, dm.dmBitsPerPel,
+ dm.dmDisplayFrequency, dm.dmPosition.x, dm.dmPosition.y);
+
+ ret = NtUserChangeDisplaySettings( &device_name, &dm, NULL,
+ CDS_GLOBAL | CDS_NORESET | CDS_UPDATEREGISTRY, NULL );
+ if (ret != DISP_CHANGE_SUCCESSFUL)
+ ERR("Failed to save registry display settings for %s, returned %d.\n",
+ wine_dbgstr_w(dd.DeviceName), ret);
+ }
+}
+
+static HKEY get_display_device_reg_key( const WCHAR *device_name )
+{
+ static const WCHAR display[] = {'\\','\\','.','\\','D','I','S','P','L','A','Y'};
+ static const WCHAR video_key[] = {
+ '\\','R','e','g','i','s','t','r','y',
+ '\\','M','a','c','h','i','n','e',
+ '\\','H','A','R','D','W','A','R','E',
+ '\\','D','E','V','I','C','E','M','A','P',
+ '\\','V','I','D','E','O'};
+ static const WCHAR current_config_key[] = {
+ '\\','R','e','g','i','s','t','r','y',
+ '\\','M','a','c','h','i','n','e',
+ '\\','S','y','s','t','e','m',
+ '\\','C','u','r','r','e','n','t','C','o','n','t','r','o','l','S','e','t',
+ '\\','H','a','r','d','w','a','r','e',' ','P','r','o','f','i','l','e','s',
+ '\\','C','u','r','r','e','n','t'};
+ WCHAR value_name[MAX_PATH], buffer[4096], *end_ptr;
+ KEY_VALUE_PARTIAL_INFORMATION *value = (void *)buffer;
+ DWORD adapter_index, size;
+ char adapter_name[100];
+ HKEY hkey;
+
+ /* Device name has to be \\.\DISPLAY%d */
+ if (wcsnicmp( device_name, display, ARRAY_SIZE(display) ))
+ return FALSE;
+
+ /* Parse \\.\DISPLAY* */
+ adapter_index = wcstol( device_name + ARRAY_SIZE(display), &end_ptr, 10 ) - 1;
+ if (*end_ptr)
+ return FALSE;
+
+ /* Open \Device\Video* in HKLM\HARDWARE\DEVICEMAP\VIDEO\ */
+ if (!(hkey = reg_open_key( NULL, video_key, sizeof(video_key) ))) return FALSE;
+ sprintf( adapter_name, "\\Device\\Video%d", adapter_index );
+ asciiz_to_unicode( value_name, adapter_name );
+ size = query_reg_value( hkey, value_name, value, sizeof(buffer) );
+ NtClose( hkey );
+ if (!size || value->Type != REG_SZ) return FALSE;
+
+ /* Replace \Registry\Machine\ prefix with HKEY_CURRENT_CONFIG */
+ memmove( buffer + ARRAYSIZE(current_config_key), (const WCHAR *)value->Data + 17,
+ size - 17 * sizeof(WCHAR) );
+ memcpy( buffer, current_config_key, sizeof(current_config_key) );
+ TRACE( "display device %s registry settings key %s.\n", wine_dbgstr_w(device_name),
+ wine_dbgstr_w(buffer) );
+ return reg_open_key( NULL, buffer, lstrlenW(buffer) * sizeof(WCHAR) );
+}
+
+static BOOL query_display_setting( HKEY hkey, const char *name, DWORD *ret )
+{
+ char buffer[1024];
+ WCHAR nameW[128];
+ KEY_VALUE_PARTIAL_INFORMATION *value = (void *)buffer;
+
+ asciiz_to_unicode( nameW, name );
+ if (query_reg_value( hkey, nameW, value, sizeof(buffer) ) != sizeof(DWORD) ||
+ value->Type != REG_DWORD)
+ return FALSE;
+
+ *ret = *(DWORD *)value->Data;
+ return TRUE;
+}
+
+static BOOL read_registry_settings(const WCHAR *device_name, DEVMODEW *dm)
+{
+ HANDLE mutex;
+ HKEY hkey;
+ BOOL ret = TRUE;
+
+ dm->dmFields = 0;
+
+ mutex = get_display_device_init_mutex();
+ if (!(hkey = get_display_device_reg_key( device_name )))
+ {
+ release_display_device_init_mutex(mutex);
+ return FALSE;
+ }
+
+ ret &= query_display_setting( hkey, "DefaultSettings.BitsPerPel", &dm->dmBitsPerPel );
+ dm->dmFields |= DM_BITSPERPEL;
+ ret &= query_display_setting( hkey, "DefaultSettings.XResolution", &dm->dmPelsWidth );
+ dm->dmFields |= DM_PELSWIDTH;
+ ret &= query_display_setting( hkey, "DefaultSettings.YResolution", &dm->dmPelsHeight );
+ dm->dmFields |= DM_PELSHEIGHT;
+ ret &= query_display_setting( hkey, "DefaultSettings.VRefresh", &dm->dmDisplayFrequency );
+ dm->dmFields |= DM_DISPLAYFREQUENCY;
+ ret &= query_display_setting( hkey, "DefaultSettings.Flags", &dm->dmDisplayFlags );
+ dm->dmFields |= DM_DISPLAYFLAGS;
+ ret &= query_display_setting( hkey, "DefaultSettings.XPanning", (DWORD *)&dm->dmPosition.x );
+ ret &= query_display_setting( hkey, "DefaultSettings.YPanning", (DWORD *)&dm->dmPosition.y );
+ dm->dmFields |= DM_POSITION;
+ ret &= query_display_setting( hkey, "DefaultSettings.Orientation", &dm->dmDisplayOrientation );
+ dm->dmFields |= DM_DISPLAYORIENTATION;
+ ret &= query_display_setting( hkey, "DefaultSettings.FixedOutput", &dm->dmDisplayFixedOutput );
+
+ NtClose( hkey );
+ release_display_device_init_mutex(mutex);
+ return ret;
+}
+
+static BOOL set_setting_value( HKEY hkey, const char *name, DWORD val )
+{
+ WCHAR nameW[128];
+ UNICODE_STRING str = { asciiz_to_unicode( nameW, name ) - sizeof(WCHAR), sizeof(nameW), nameW };
+ return !NtSetValueKey( hkey, &str, 0, REG_DWORD, &val, sizeof(val) );
+}
+
+static BOOL write_registry_settings(const WCHAR *device_name, const DEVMODEW *dm)
+{
+ HANDLE mutex;
+ HKEY hkey;
+ BOOL ret = TRUE;
+
+ mutex = get_display_device_init_mutex();
+ if (!(hkey = get_display_device_reg_key( device_name )))
+ {
+ release_display_device_init_mutex(mutex);
+ return FALSE;
+ }
+
+ ret &= set_setting_value( hkey, "DefaultSettings.BitsPerPel", dm->dmBitsPerPel );
+ ret &= set_setting_value( hkey, "DefaultSettings.XResolution", dm->dmPelsWidth );
+ ret &= set_setting_value( hkey, "DefaultSettings.YResolution", dm->dmPelsHeight );
+ ret &= set_setting_value( hkey, "DefaultSettings.VRefresh", dm->dmDisplayFrequency );
+ ret &= set_setting_value( hkey, "DefaultSettings.Flags", dm->dmDisplayFlags );
+ ret &= set_setting_value( hkey, "DefaultSettings.XPanning", dm->dmPosition.x );
+ ret &= set_setting_value( hkey, "DefaultSettings.YPanning", dm->dmPosition.y );
+ ret &= set_setting_value( hkey, "DefaultSettings.Orientation", dm->dmDisplayOrientation );
+ ret &= set_setting_value( hkey, "DefaultSettings.FixedOutput", dm->dmDisplayFixedOutput );
+
+ NtClose( hkey );
+ release_display_device_init_mutex(mutex);
+ return ret;
+}
+
+BOOL get_primary_adapter(WCHAR *name)
+{
+ DISPLAY_DEVICEW dd;
+ DWORD i;
+
+ dd.cb = sizeof(dd);
+ for (i = 0; !NtUserEnumDisplayDevices( NULL, i, &dd, 0 ); ++i)
+ {
+ if (dd.StateFlags & DISPLAY_DEVICE_PRIMARY_DEVICE)
+ {
+ lstrcpyW(name, dd.DeviceName);
+ return TRUE;
+ }
+ }
+
+ return FALSE;
+}
+
+static int mode_compare(const void *p1, const void *p2)
+{
+ DWORD a_width, a_height, b_width, b_height;
+ const DEVMODEW *a = p1, *b = p2;
+
+ /* Use the width and height in landscape mode for comparison */
+ if (a->dmDisplayOrientation == DMDO_DEFAULT || a->dmDisplayOrientation == DMDO_180)
+ {
+ a_width = a->dmPelsWidth;
+ a_height = a->dmPelsHeight;
+ }
+ else
+ {
+ a_width = a->dmPelsHeight;
+ a_height = a->dmPelsWidth;
+ }
+
+ if (b->dmDisplayOrientation == DMDO_DEFAULT || b->dmDisplayOrientation == DMDO_180)
+ {
+ b_width = b->dmPelsWidth;
+ b_height = b->dmPelsHeight;
+ }
+ else
+ {
+ b_width = b->dmPelsHeight;
+ b_height = b->dmPelsWidth;
+ }
+
+ /* Depth in descending order */
+ if (a->dmBitsPerPel != b->dmBitsPerPel)
+ return b->dmBitsPerPel - a->dmBitsPerPel;
+
+ /* Width in ascending order */
+ if (a_width != b_width)
+ return a_width - b_width;
+
+ /* Height in ascending order */
+ if (a_height != b_height)
+ return a_height - b_height;
+
+ /* Frequency in descending order */
+ if (a->dmDisplayFrequency != b->dmDisplayFrequency)
+ return b->dmDisplayFrequency - a->dmDisplayFrequency;
+
+ /* Orientation in ascending order */
+ return a->dmDisplayOrientation - b->dmDisplayOrientation;
+}
+
+static void set_display_depth(ULONG_PTR display_id, DWORD depth)
+{
+ struct x11drv_display_depth *display_depth;
+
+ pthread_mutex_lock( &settings_mutex );
+ LIST_FOR_EACH_ENTRY(display_depth, &x11drv_display_depth_list, struct x11drv_display_depth, entry)
+ {
+ if (display_depth->display_id == display_id)
+ {
+ display_depth->depth = depth;
+ pthread_mutex_unlock( &settings_mutex );
+ return;
+ }
+ }
+
+ display_depth = malloc(sizeof(*display_depth));
+ if (!display_depth)
+ {
+ ERR("Failed to allocate memory.\n");
+ pthread_mutex_unlock( &settings_mutex );
+ return;
+ }
+
+ display_depth->display_id = display_id;
+ display_depth->depth = depth;
+ list_add_head(&x11drv_display_depth_list, &display_depth->entry);
+ pthread_mutex_unlock( &settings_mutex );
+}
+
+static DWORD get_display_depth(ULONG_PTR display_id)
+{
+ struct x11drv_display_depth *display_depth;
+ DWORD depth;
+
+ pthread_mutex_lock( &settings_mutex );
+ LIST_FOR_EACH_ENTRY(display_depth, &x11drv_display_depth_list, struct x11drv_display_depth, entry)
+ {
+ if (display_depth->display_id == display_id)
+ {
+ depth = display_depth->depth;
+ pthread_mutex_unlock( &settings_mutex );
+ return depth;
+ }
+ }
+ pthread_mutex_unlock( &settings_mutex );
+ return screen_bpp;
+}
+
+/***********************************************************************
+ * EnumDisplaySettingsEx (X11DRV.@)
+ *
+ */
+BOOL X11DRV_EnumDisplaySettingsEx( LPCWSTR name, DWORD n, LPDEVMODEW devmode, DWORD flags)
+{
+ static const WCHAR dev_name[CCHDEVICENAME] =
+ { 'W','i','n','e',' ','X','1','1',' ','d','r','i','v','e','r',0 };
+ DEVMODEW *modes;
+ UINT mode_count;
+ ULONG_PTR id;
+
+ if (n == ENUM_REGISTRY_SETTINGS)
+ {
+ if (!read_registry_settings(name, devmode))
+ {
+ ERR("Failed to get %s registry display settings.\n", wine_dbgstr_w(name));
+ return FALSE;
+ }
+ goto done;
+ }
+
+ if (n == ENUM_CURRENT_SETTINGS)
+ {
+ if (!settings_handler.get_id(name, &id) || !settings_handler.get_current_mode(id, devmode))
+ {
+ ERR("Failed to get %s current display settings.\n", wine_dbgstr_w(name));
+ return FALSE;
+ }
+
+ if (!is_detached_mode(devmode))
+ devmode->dmBitsPerPel = get_display_depth(id);
+
+ goto done;
+ }
+
+ pthread_mutex_lock( &settings_mutex );
+ if (n == 0 || wcsicmp(cached_device_name, name) || cached_flags != flags)
+ {
+ if (!settings_handler.get_id(name, &id) || !settings_handler.get_modes(id, flags, &modes, &mode_count))
+ {
+ ERR("Failed to get %s supported display modes.\n", wine_dbgstr_w(name));
+ pthread_mutex_unlock( &settings_mutex );
+ return FALSE;
+ }
+
+ qsort(modes, mode_count, sizeof(*modes) + modes[0].dmDriverExtra, mode_compare);
+
+ if (cached_modes)
+ settings_handler.free_modes(cached_modes);
+ lstrcpyW(cached_device_name, name);
+ cached_flags = flags;
+ cached_modes = modes;
+ cached_mode_count = mode_count;
+ }
+
+ if (n >= cached_mode_count)
+ {
+ pthread_mutex_unlock( &settings_mutex );
+ WARN("handler:%s device:%s mode index:%#x not found.\n", settings_handler.name, wine_dbgstr_w(name), n);
+ SetLastError(ERROR_NO_MORE_FILES);
+ return FALSE;
+ }
+
+ memcpy(devmode, (BYTE *)cached_modes + (sizeof(*cached_modes) + cached_modes[0].dmDriverExtra) * n, sizeof(*devmode));
+ pthread_mutex_unlock( &settings_mutex );
+
+done:
+ /* Set generic fields */
+ devmode->dmSize = FIELD_OFFSET(DEVMODEW, dmICMMethod);
+ devmode->dmDriverExtra = 0;
+ devmode->dmSpecVersion = DM_SPECVERSION;
+ devmode->dmDriverVersion = DM_SPECVERSION;
+ lstrcpyW(devmode->dmDeviceName, dev_name);
+ return TRUE;
+}
+
+BOOL is_detached_mode(const DEVMODEW *mode)
+{
+ return mode->dmFields & DM_POSITION &&
+ mode->dmFields & DM_PELSWIDTH &&
+ mode->dmFields & DM_PELSHEIGHT &&
+ mode->dmPelsWidth == 0 &&
+ mode->dmPelsHeight == 0;
+}
+
+/* Get the full display mode with all the necessary fields set.
+ * Return NULL on failure. Caller should call free_full_mode() to free the returned mode. */
+static DEVMODEW *get_full_mode(ULONG_PTR id, DEVMODEW *dev_mode)
+{
+ DEVMODEW *modes, *full_mode, *found_mode = NULL;
+ UINT mode_count, mode_idx;
+
+ if (is_detached_mode(dev_mode))
+ return dev_mode;
+
+ if (!settings_handler.get_modes(id, EDS_ROTATEDMODE, &modes, &mode_count))
+ return NULL;
+
+ qsort(modes, mode_count, sizeof(*modes) + modes[0].dmDriverExtra, mode_compare);
+ for (mode_idx = 0; mode_idx < mode_count; ++mode_idx)
+ {
+ 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)
+ continue;
+ if (dev_mode->dmFields & DM_PELSWIDTH && found_mode->dmPelsWidth != dev_mode->dmPelsWidth)
+ continue;
+ if (dev_mode->dmFields & DM_PELSHEIGHT && 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)
+ continue;
+ if (dev_mode->dmFields & DM_DISPLAYORIENTATION &&
+ found_mode->dmDisplayOrientation != dev_mode->dmDisplayOrientation)
+ continue;
+
+ break;
+ }
+
+ if (!found_mode || mode_idx == mode_count)
+ {
+ settings_handler.free_modes(modes);
+ return NULL;
+ }
+
+ if (!(full_mode = malloc(sizeof(*found_mode) + found_mode->dmDriverExtra)))
+ {
+ settings_handler.free_modes(modes);
+ return NULL;
+ }
+
+ memcpy(full_mode, found_mode, sizeof(*found_mode) + found_mode->dmDriverExtra);
+ settings_handler.free_modes(modes);
+
+ full_mode->dmFields |= DM_POSITION;
+ full_mode->dmPosition = dev_mode->dmPosition;
+ return full_mode;
+}
+
+static void free_full_mode(DEVMODEW *mode)
+{
+ if (!is_detached_mode(mode))
+ free(mode);
+}
+
+static LONG get_display_settings(struct x11drv_display_setting **new_displays,
+ INT *new_display_count, const WCHAR *dev_name, DEVMODEW *dev_mode)
+{
+ struct x11drv_display_setting *displays;
+ DEVMODEW registry_mode, current_mode;
+ 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;
+
+ displays = calloc(display_count, sizeof(*displays));
+ if (!displays)
+ goto done;
+
+ for (display_idx = 0; display_idx < display_count; ++display_idx)
+ {
+ if (NtUserEnumDisplayDevices( NULL, display_idx, &display_device, 0 ))
+ goto done;
+
+ if (!settings_handler.get_id(display_device.DeviceName, &displays[display_idx].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;
+
+ displays[display_idx].desired_mode = registry_mode;
+ }
+ else if (!wcsicmp(dev_name, display_device.DeviceName))
+ {
+ displays[display_idx].desired_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;
+
+ displays[display_idx].desired_mode.dmFields |= DM_POSITION;
+ displays[display_idx].desired_mode.dmPosition = current_mode.dmPosition;
+ }
+ }
+ 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;
+
+ displays[display_idx].desired_mode = current_mode;
+ }
+
+ SetRect(&displays[display_idx].desired_rect,
+ displays[display_idx].desired_mode.dmPosition.x,
+ displays[display_idx].desired_mode.dmPosition.y,
+ displays[display_idx].desired_mode.dmPosition.x + displays[display_idx].desired_mode.dmPelsWidth,
+ displays[display_idx].desired_mode.dmPosition.y + displays[display_idx].desired_mode.dmPelsHeight);
+ lstrcpyW(displays[display_idx].desired_mode.dmDeviceName, display_device.DeviceName);
+ }
+
+ *new_displays = displays;
+ *new_display_count = display_count;
+ return DISP_CHANGE_SUCCESSFUL;
+
+done:
+ free(displays);
+ return ret;
+}
+
+static INT offset_length(POINT offset)
+{
+ return offset.x * offset.x + offset.y * offset.y;
+}
+
+/* Check if a rect overlaps with placed display rects */
+static BOOL overlap_placed_displays(const RECT *rect, const struct x11drv_display_setting *displays, INT display_count)
+{
+ INT display_idx;
+ RECT intersect;
+
+ for (display_idx = 0; display_idx < display_count; ++display_idx)
+ {
+ if (displays[display_idx].placed &&
+ intersect_rect(&intersect, &displays[display_idx].new_rect, 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 struct x11drv_display_setting *displays, INT display_count, INT placing_idx)
+{
+ POINT points[8], left_top, offset, min_offset = {0, 0};
+ INT display_idx, point_idx, point_count, vertex_idx;
+ BOOL has_placed = FALSE, first = TRUE;
+ INT width, height;
+ RECT rect;
+
+ /* If the display to be placed is detached, no offset is needed to place it */
+ if (IsRectEmpty(&displays[placing_idx].desired_rect))
+ return min_offset;
+
+ /* If there is no placed and attached display, place this display as it is */
+ for (display_idx = 0; display_idx < display_count; ++display_idx)
+ {
+ if (displays[display_idx].placed && !IsRectEmpty(&displays[display_idx].new_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 = displays[placing_idx].desired_rect.right - displays[placing_idx].desired_rect.left;
+ height = displays[placing_idx].desired_rect.bottom - displays[placing_idx].desired_rect.top;
+
+ for (display_idx = 0; display_idx < display_count; ++display_idx)
+ {
+ if (!displays[display_idx].placed || IsRectEmpty(&displays[display_idx].new_rect))
+ continue;
+
+ /* Get four vertices of the placed display rectangle */
+ points[0].x = displays[display_idx].new_rect.left;
+ points[0].y = displays[display_idx].new_rect.top;
+ points[1].x = displays[display_idx].new_rect.left;
+ points[1].y = displays[display_idx].new_rect.bottom;
+ points[2].x = displays[display_idx].new_rect.right;
+ points[2].y = displays[display_idx].new_rect.top;
+ points[3].x = displays[display_idx].new_rect.right;
+ points[3].y = displays[display_idx].new_rect.bottom;
+ point_count = 4;
+
+ /* Intersected points when moving the display to be placed horizontally */
+ if (displays[placing_idx].desired_rect.bottom >= displays[display_idx].new_rect.top &&
+ displays[placing_idx].desired_rect.top <= displays[display_idx].new_rect.bottom)
+ {
+ points[point_count].x = displays[display_idx].new_rect.left;
+ points[point_count++].y = displays[placing_idx].desired_rect.top;
+ points[point_count].x = displays[display_idx].new_rect.right;
+ points[point_count++].y = displays[placing_idx].desired_rect.top;
+ }
+ /* Intersected points when moving the display to be placed vertically */
+ if (displays[placing_idx].desired_rect.left <= displays[display_idx].new_rect.right &&
+ displays[placing_idx].desired_rect.right >= displays[display_idx].new_rect.left)
+ {
+ points[point_count].x = displays[placing_idx].desired_rect.left;
+ points[point_count++].y = displays[display_idx].new_rect.top;
+ points[point_count].x = displays[placing_idx].desired_rect.left;
+ points[point_count++].y = displays[display_idx].new_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 - displays[placing_idx].desired_rect.left;
+ offset.y = left_top.y - displays[placing_idx].desired_rect.top;
+ rect = displays[placing_idx].desired_rect;
+ OffsetRect(&rect, offset.x, offset.y);
+ if (!overlap_placed_displays(&rect, displays, display_count))
+ {
+ 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(struct x11drv_display_setting *displays, INT display_count)
+{
+ INT left_most = INT_MAX, top_most = INT_MAX;
+ INT placing_idx, display_idx;
+ POINT min_offset, offset;
+
+ /* 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_idx = -1;
+ for (display_idx = 0; display_idx < display_count; ++display_idx)
+ {
+ if (displays[display_idx].placed)
+ continue;
+
+ offset = get_placement_offset(displays, display_count, display_idx);
+ if (placing_idx == -1 || offset_length(offset) < offset_length(min_offset))
+ {
+ min_offset = offset;
+ placing_idx = display_idx;
+ }
+ }
+
+ /* If all displays are placed */
+ if (placing_idx == -1)
+ break;
+
+ displays[placing_idx].new_rect = displays[placing_idx].desired_rect;
+ OffsetRect(&displays[placing_idx].new_rect, min_offset.x, min_offset.y);
+ displays[placing_idx].placed = TRUE;
+ }
+
+ for (display_idx = 0; display_idx < display_count; ++display_idx)
+ {
+ displays[display_idx].desired_mode.dmPosition.x = displays[display_idx].new_rect.left;
+ displays[display_idx].desired_mode.dmPosition.y = displays[display_idx].new_rect.top;
+ left_most = min(left_most, displays[display_idx].new_rect.left);
+ top_most = min(top_most, displays[display_idx].new_rect.top);
+ }
+
+ /* Convert virtual screen coordinates to root coordinates */
+ for (display_idx = 0; display_idx < display_count; ++display_idx)
+ {
+ displays[display_idx].desired_mode.dmPosition.x -= left_most;
+ displays[display_idx].desired_mode.dmPosition.y -= top_most;
+ }
+}
+
+static LONG apply_display_settings(struct x11drv_display_setting *displays, INT display_count, BOOL do_attach)
+{
+ DEVMODEW *full_mode;
+ BOOL attached_mode;
+ INT display_idx;
+ LONG ret;
+
+ for (display_idx = 0; display_idx < display_count; ++display_idx)
+ {
+ attached_mode = !is_detached_mode(&displays[display_idx].desired_mode);
+ if ((attached_mode && !do_attach) || (!attached_mode && do_attach))
+ continue;
+
+ full_mode = get_full_mode(displays[display_idx].id, &displays[display_idx].desired_mode);
+ if (!full_mode)
+ return DISP_CHANGE_BADMODE;
+
+ TRACE("handler:%s changing %s to position:(%d,%d) resolution:%ux%u frequency:%uHz "
+ "depth:%ubits orientation:%#x.\n", settings_handler.name,
+ wine_dbgstr_w(displays[display_idx].desired_mode.dmDeviceName),
+ full_mode->dmPosition.x, full_mode->dmPosition.y, full_mode->dmPelsWidth,
+ full_mode->dmPelsHeight, full_mode->dmDisplayFrequency, full_mode->dmBitsPerPel,
+ full_mode->dmDisplayOrientation);
+
+ ret = settings_handler.set_current_mode(displays[display_idx].id, full_mode);
+ if (attached_mode && ret == DISP_CHANGE_SUCCESSFUL)
+ set_display_depth(displays[display_idx].id, full_mode->dmBitsPerPel);
+ free_full_mode(full_mode);
+ if (ret != DISP_CHANGE_SUCCESSFUL)
+ return ret;
+ }
+
+ return DISP_CHANGE_SUCCESSFUL;
+}
+
+static BOOL all_detached_settings(const struct x11drv_display_setting *displays, INT display_count)
+{
+ INT display_idx;
+
+ for (display_idx = 0; display_idx < display_count; ++display_idx)
+ {
+ if (!is_detached_mode(&displays[display_idx].desired_mode))
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+/***********************************************************************
+ * ChangeDisplaySettingsEx (X11DRV.@)
+ *
+ */
+LONG X11DRV_ChangeDisplaySettingsEx( LPCWSTR devname, LPDEVMODEW devmode,
+ HWND hwnd, DWORD flags, LPVOID lpvoid )
+{
+ struct x11drv_display_setting *displays;
+ INT display_idx, display_count;
+ DEVMODEW *full_mode;
+ LONG ret;
+
+ ret = get_display_settings(&displays, &display_count, devname, devmode);
+ if (ret != DISP_CHANGE_SUCCESSFUL)
+ return ret;
+
+ if (flags & CDS_UPDATEREGISTRY && devname && devmode)
+ {
+ for (display_idx = 0; display_idx < display_count; ++display_idx)
+ {
+ if (!wcsicmp(displays[display_idx].desired_mode.dmDeviceName, devname))
+ {
+ full_mode = get_full_mode(displays[display_idx].id, &displays[display_idx].desired_mode);
+ if (!full_mode)
+ {
+ free(displays);
+ return DISP_CHANGE_BADMODE;
+ }
+
+ if (!write_registry_settings(devname, full_mode))
+ {
+ ERR("Failed to write %s display settings to registry.\n", wine_dbgstr_w(devname));
+ free_full_mode(full_mode);
+ free(displays);
+ return DISP_CHANGE_NOTUPDATED;
+ }
+
+ free_full_mode(full_mode);
+ break;
+ }
+ }
+ }
+
+ if (flags & (CDS_TEST | CDS_NORESET))
+ {
+ free(displays);
+ return DISP_CHANGE_SUCCESSFUL;
+ }
+
+ if (all_detached_settings(displays, display_count))
+ {
+ WARN("Detaching all displays is not permitted.\n");
+ free(displays);
+ return DISP_CHANGE_SUCCESSFUL;
+ }
+
+ place_all_displays(displays, display_count);
+
+ /* Detach displays first to free up CRTCs */
+ ret = apply_display_settings(displays, display_count, FALSE);
+ if (ret == DISP_CHANGE_SUCCESSFUL)
+ ret = apply_display_settings(displays, display_count, TRUE);
+ if (ret == DISP_CHANGE_SUCCESSFUL)
+ X11DRV_DisplayDevices_Update(TRUE);
+ free(displays);
+ return ret;
+}
HANDLE get_display_device_init_mutex(void)
{
diff --git a/dlls/winex11.drv/settings.c b/dlls/winex11.drv/settings.c
deleted file mode 100644
index 06cf0df4482..00000000000
--- a/dlls/winex11.drv/settings.c
+++ /dev/null
@@ -1,999 +0,0 @@
-/*
- * Wine X11drv display settings functions
- *
- * Copyright 2003 Alexander James Pasadyn
- * Copyright 2020 Zhiyi Zhang for CodeWeavers
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
- */
-
-#if 0
-#pragma makedep unix
-#endif
-
-#include "config.h"
-#include <stdlib.h>
-
-#include "x11drv.h"
-
-#include "windef.h"
-#include "winreg.h"
-#include "wingdi.h"
-#include "wine/debug.h"
-
-WINE_DEFAULT_DEBUG_CHANNEL(x11settings);
-
-static struct x11drv_settings_handler settings_handler;
-
-struct x11drv_display_setting
-{
- ULONG_PTR id;
- BOOL placed;
- RECT new_rect;
- RECT desired_rect;
- DEVMODEW desired_mode;
-};
-
-struct x11drv_display_depth
-{
- struct list entry;
- ULONG_PTR display_id;
- DWORD depth;
-};
-
-/* Display device emulated depth list, protected by modes_section */
-static struct list x11drv_display_depth_list = LIST_INIT(x11drv_display_depth_list);
-
-/* All Windows drivers seen so far either support 32 bit depths, or 24 bit depths, but never both. So if we have
- * a 32 bit framebuffer, report 32 bit bpps, otherwise 24 bit ones.
- */
-static const unsigned int depths_24[] = {8, 16, 24};
-static const unsigned int depths_32[] = {8, 16, 32};
-const unsigned int *depths;
-
-/* Cached display modes for a device, protected by modes_section */
-static WCHAR cached_device_name[CCHDEVICENAME];
-static DWORD cached_flags;
-static DEVMODEW *cached_modes;
-static UINT cached_mode_count;
-
-static pthread_mutex_t settings_mutex = PTHREAD_MUTEX_INITIALIZER;
-
-void X11DRV_Settings_SetHandler(const struct x11drv_settings_handler *new_handler)
-{
- if (new_handler->priority > settings_handler.priority)
- {
- settings_handler = *new_handler;
- TRACE("Display settings are now handled by: %s.\n", settings_handler.name);
- }
-}
-
-/***********************************************************************
- * Default handlers if resolution switching is not enabled
- *
- */
-static BOOL nores_get_id(const WCHAR *device_name, ULONG_PTR *id)
-{
- WCHAR primary_adapter[CCHDEVICENAME];
-
- if (!get_primary_adapter( primary_adapter ))
- return FALSE;
-
- *id = !wcsicmp( device_name, primary_adapter ) ? 1 : 0;
- return TRUE;
-}
-
-static BOOL nores_get_modes(ULONG_PTR id, DWORD flags, DEVMODEW **new_modes, UINT *mode_count)
-{
- RECT primary = get_host_primary_monitor_rect();
- DEVMODEW *modes;
-
- modes = calloc(1, sizeof(*modes));
- if (!modes)
- {
- SetLastError(ERROR_NOT_ENOUGH_MEMORY);
- return FALSE;
- }
-
- modes[0].dmSize = sizeof(*modes);
- modes[0].dmDriverExtra = 0;
- modes[0].dmFields = DM_DISPLAYORIENTATION | DM_BITSPERPEL | DM_PELSWIDTH | DM_PELSHEIGHT |
- DM_DISPLAYFLAGS | DM_DISPLAYFREQUENCY;
- modes[0].dmDisplayOrientation = DMDO_DEFAULT;
- modes[0].dmBitsPerPel = screen_bpp;
- modes[0].dmPelsWidth = primary.right;
- modes[0].dmPelsHeight = primary.bottom;
- modes[0].dmDisplayFlags = 0;
- modes[0].dmDisplayFrequency = 60;
-
- *new_modes = modes;
- *mode_count = 1;
- return TRUE;
-}
-
-static void nores_free_modes(DEVMODEW *modes)
-{
- free(modes);
-}
-
-static BOOL nores_get_current_mode(ULONG_PTR id, DEVMODEW *mode)
-{
- RECT primary = get_host_primary_monitor_rect();
-
- mode->dmFields = DM_DISPLAYORIENTATION | DM_BITSPERPEL | DM_PELSWIDTH | DM_PELSHEIGHT |
- DM_DISPLAYFLAGS | DM_DISPLAYFREQUENCY | DM_POSITION;
- mode->dmDisplayOrientation = DMDO_DEFAULT;
- mode->dmDisplayFlags = 0;
- mode->dmPosition.x = 0;
- mode->dmPosition.y = 0;
-
- if (id != 1)
- {
- FIXME("Non-primary adapters are unsupported.\n");
- mode->dmBitsPerPel = 0;
- mode->dmPelsWidth = 0;
- mode->dmPelsHeight = 0;
- mode->dmDisplayFrequency = 0;
- return TRUE;
- }
-
- mode->dmBitsPerPel = screen_bpp;
- mode->dmPelsWidth = primary.right;
- mode->dmPelsHeight = primary.bottom;
- mode->dmDisplayFrequency = 60;
- return TRUE;
-}
-
-static LONG nores_set_current_mode(ULONG_PTR id, DEVMODEW *mode)
-{
- WARN("NoRes settings handler, ignoring mode change request.\n");
- return DISP_CHANGE_SUCCESSFUL;
-}
-
-/* default handler only gets the current X desktop resolution */
-void X11DRV_Settings_Init(void)
-{
- struct x11drv_settings_handler nores_handler;
-
- depths = screen_bpp == 32 ? depths_32 : depths_24;
-
- nores_handler.name = "NoRes";
- nores_handler.priority = 1;
- nores_handler.get_id = nores_get_id;
- nores_handler.get_modes = nores_get_modes;
- nores_handler.free_modes = nores_free_modes;
- nores_handler.get_current_mode = nores_get_current_mode;
- nores_handler.set_current_mode = nores_set_current_mode;
- X11DRV_Settings_SetHandler(&nores_handler);
-}
-
-/* Initialize registry display settings when new display devices are added */
-void init_registry_display_settings(void)
-{
- DEVMODEW dm = {.dmSize = sizeof(dm)};
- DISPLAY_DEVICEW dd = {sizeof(dd)};
- UNICODE_STRING device_name;
- DWORD i = 0;
- LONG ret;
-
- while (!NtUserEnumDisplayDevices( NULL, i++, &dd, 0 ))
- {
- RtlInitUnicodeString( &device_name, dd.DeviceName );
-
- /* Skip if the device already has registry display settings */
- if (NtUserEnumDisplaySettings( &device_name, ENUM_REGISTRY_SETTINGS, &dm, 0 ))
- continue;
-
- if (!NtUserEnumDisplaySettings( &device_name, ENUM_CURRENT_SETTINGS, &dm, 0 ))
- {
- ERR("Failed to query current display settings for %s.\n", wine_dbgstr_w(dd.DeviceName));
- continue;
- }
-
- TRACE("Device %s current display mode %ux%u %ubits %uHz at %d,%d.\n",
- wine_dbgstr_w(dd.DeviceName), dm.dmPelsWidth, dm.dmPelsHeight, dm.dmBitsPerPel,
- dm.dmDisplayFrequency, dm.dmPosition.x, dm.dmPosition.y);
-
- ret = NtUserChangeDisplaySettings( &device_name, &dm, NULL,
- CDS_GLOBAL | CDS_NORESET | CDS_UPDATEREGISTRY, NULL );
- if (ret != DISP_CHANGE_SUCCESSFUL)
- ERR("Failed to save registry display settings for %s, returned %d.\n",
- wine_dbgstr_w(dd.DeviceName), ret);
- }
-}
-
-static HKEY get_display_device_reg_key( const WCHAR *device_name )
-{
- static const WCHAR display[] = {'\\','\\','.','\\','D','I','S','P','L','A','Y'};
- static const WCHAR video_key[] = {
- '\\','R','e','g','i','s','t','r','y',
- '\\','M','a','c','h','i','n','e',
- '\\','H','A','R','D','W','A','R','E',
- '\\','D','E','V','I','C','E','M','A','P',
- '\\','V','I','D','E','O'};
- static const WCHAR current_config_key[] = {
- '\\','R','e','g','i','s','t','r','y',
- '\\','M','a','c','h','i','n','e',
- '\\','S','y','s','t','e','m',
- '\\','C','u','r','r','e','n','t','C','o','n','t','r','o','l','S','e','t',
- '\\','H','a','r','d','w','a','r','e',' ','P','r','o','f','i','l','e','s',
- '\\','C','u','r','r','e','n','t'};
- WCHAR value_name[MAX_PATH], buffer[4096], *end_ptr;
- KEY_VALUE_PARTIAL_INFORMATION *value = (void *)buffer;
- DWORD adapter_index, size;
- char adapter_name[100];
- HKEY hkey;
-
- /* Device name has to be \\.\DISPLAY%d */
- if (wcsnicmp( device_name, display, ARRAY_SIZE(display) ))
- return FALSE;
-
- /* Parse \\.\DISPLAY* */
- adapter_index = wcstol( device_name + ARRAY_SIZE(display), &end_ptr, 10 ) - 1;
- if (*end_ptr)
- return FALSE;
-
- /* Open \Device\Video* in HKLM\HARDWARE\DEVICEMAP\VIDEO\ */
- if (!(hkey = reg_open_key( NULL, video_key, sizeof(video_key) ))) return FALSE;
- sprintf( adapter_name, "\\Device\\Video%d", adapter_index );
- asciiz_to_unicode( value_name, adapter_name );
- size = query_reg_value( hkey, value_name, value, sizeof(buffer) );
- NtClose( hkey );
- if (!size || value->Type != REG_SZ) return FALSE;
-
- /* Replace \Registry\Machine\ prefix with HKEY_CURRENT_CONFIG */
- memmove( buffer + ARRAYSIZE(current_config_key), (const WCHAR *)value->Data + 17,
- size - 17 * sizeof(WCHAR) );
- memcpy( buffer, current_config_key, sizeof(current_config_key) );
- TRACE( "display device %s registry settings key %s.\n", wine_dbgstr_w(device_name),
- wine_dbgstr_w(buffer) );
- return reg_open_key( NULL, buffer, lstrlenW(buffer) * sizeof(WCHAR) );
-}
-
-static BOOL query_display_setting( HKEY hkey, const char *name, DWORD *ret )
-{
- char buffer[1024];
- WCHAR nameW[128];
- KEY_VALUE_PARTIAL_INFORMATION *value = (void *)buffer;
-
- asciiz_to_unicode( nameW, name );
- if (query_reg_value( hkey, nameW, value, sizeof(buffer) ) != sizeof(DWORD) ||
- value->Type != REG_DWORD)
- return FALSE;
-
- *ret = *(DWORD *)value->Data;
- return TRUE;
-}
-
-static BOOL read_registry_settings(const WCHAR *device_name, DEVMODEW *dm)
-{
- HANDLE mutex;
- HKEY hkey;
- BOOL ret = TRUE;
-
- dm->dmFields = 0;
-
- mutex = get_display_device_init_mutex();
- if (!(hkey = get_display_device_reg_key( device_name )))
- {
- release_display_device_init_mutex(mutex);
- return FALSE;
- }
-
- ret &= query_display_setting( hkey, "DefaultSettings.BitsPerPel", &dm->dmBitsPerPel );
- dm->dmFields |= DM_BITSPERPEL;
- ret &= query_display_setting( hkey, "DefaultSettings.XResolution", &dm->dmPelsWidth );
- dm->dmFields |= DM_PELSWIDTH;
- ret &= query_display_setting( hkey, "DefaultSettings.YResolution", &dm->dmPelsHeight );
- dm->dmFields |= DM_PELSHEIGHT;
- ret &= query_display_setting( hkey, "DefaultSettings.VRefresh", &dm->dmDisplayFrequency );
- dm->dmFields |= DM_DISPLAYFREQUENCY;
- ret &= query_display_setting( hkey, "DefaultSettings.Flags", &dm->dmDisplayFlags );
- dm->dmFields |= DM_DISPLAYFLAGS;
- ret &= query_display_setting( hkey, "DefaultSettings.XPanning", (DWORD *)&dm->dmPosition.x );
- ret &= query_display_setting( hkey, "DefaultSettings.YPanning", (DWORD *)&dm->dmPosition.y );
- dm->dmFields |= DM_POSITION;
- ret &= query_display_setting( hkey, "DefaultSettings.Orientation", &dm->dmDisplayOrientation );
- dm->dmFields |= DM_DISPLAYORIENTATION;
- ret &= query_display_setting( hkey, "DefaultSettings.FixedOutput", &dm->dmDisplayFixedOutput );
-
- NtClose( hkey );
- release_display_device_init_mutex(mutex);
- return ret;
-}
-
-static BOOL set_setting_value( HKEY hkey, const char *name, DWORD val )
-{
- WCHAR nameW[128];
- UNICODE_STRING str = { asciiz_to_unicode( nameW, name ) - sizeof(WCHAR), sizeof(nameW), nameW };
- return !NtSetValueKey( hkey, &str, 0, REG_DWORD, &val, sizeof(val) );
-}
-
-static BOOL write_registry_settings(const WCHAR *device_name, const DEVMODEW *dm)
-{
- HANDLE mutex;
- HKEY hkey;
- BOOL ret = TRUE;
-
- mutex = get_display_device_init_mutex();
- if (!(hkey = get_display_device_reg_key( device_name )))
- {
- release_display_device_init_mutex(mutex);
- return FALSE;
- }
-
- ret &= set_setting_value( hkey, "DefaultSettings.BitsPerPel", dm->dmBitsPerPel );
- ret &= set_setting_value( hkey, "DefaultSettings.XResolution", dm->dmPelsWidth );
- ret &= set_setting_value( hkey, "DefaultSettings.YResolution", dm->dmPelsHeight );
- ret &= set_setting_value( hkey, "DefaultSettings.VRefresh", dm->dmDisplayFrequency );
- ret &= set_setting_value( hkey, "DefaultSettings.Flags", dm->dmDisplayFlags );
- ret &= set_setting_value( hkey, "DefaultSettings.XPanning", dm->dmPosition.x );
- ret &= set_setting_value( hkey, "DefaultSettings.YPanning", dm->dmPosition.y );
- ret &= set_setting_value( hkey, "DefaultSettings.Orientation", dm->dmDisplayOrientation );
- ret &= set_setting_value( hkey, "DefaultSettings.FixedOutput", dm->dmDisplayFixedOutput );
-
- NtClose( hkey );
- release_display_device_init_mutex(mutex);
- return ret;
-}
-
-BOOL get_primary_adapter(WCHAR *name)
-{
- DISPLAY_DEVICEW dd;
- DWORD i;
-
- dd.cb = sizeof(dd);
- for (i = 0; !NtUserEnumDisplayDevices( NULL, i, &dd, 0 ); ++i)
- {
- if (dd.StateFlags & DISPLAY_DEVICE_PRIMARY_DEVICE)
- {
- lstrcpyW(name, dd.DeviceName);
- return TRUE;
- }
- }
-
- return FALSE;
-}
-
-static int mode_compare(const void *p1, const void *p2)
-{
- DWORD a_width, a_height, b_width, b_height;
- const DEVMODEW *a = p1, *b = p2;
-
- /* Use the width and height in landscape mode for comparison */
- if (a->dmDisplayOrientation == DMDO_DEFAULT || a->dmDisplayOrientation == DMDO_180)
- {
- a_width = a->dmPelsWidth;
- a_height = a->dmPelsHeight;
- }
- else
- {
- a_width = a->dmPelsHeight;
- a_height = a->dmPelsWidth;
- }
-
- if (b->dmDisplayOrientation == DMDO_DEFAULT || b->dmDisplayOrientation == DMDO_180)
- {
- b_width = b->dmPelsWidth;
- b_height = b->dmPelsHeight;
- }
- else
- {
- b_width = b->dmPelsHeight;
- b_height = b->dmPelsWidth;
- }
-
- /* Depth in descending order */
- if (a->dmBitsPerPel != b->dmBitsPerPel)
- return b->dmBitsPerPel - a->dmBitsPerPel;
-
- /* Width in ascending order */
- if (a_width != b_width)
- return a_width - b_width;
-
- /* Height in ascending order */
- if (a_height != b_height)
- return a_height - b_height;
-
- /* Frequency in descending order */
- if (a->dmDisplayFrequency != b->dmDisplayFrequency)
- return b->dmDisplayFrequency - a->dmDisplayFrequency;
-
- /* Orientation in ascending order */
- return a->dmDisplayOrientation - b->dmDisplayOrientation;
-}
-
-static void set_display_depth(ULONG_PTR display_id, DWORD depth)
-{
- struct x11drv_display_depth *display_depth;
-
- pthread_mutex_lock( &settings_mutex );
- LIST_FOR_EACH_ENTRY(display_depth, &x11drv_display_depth_list, struct x11drv_display_depth, entry)
- {
- if (display_depth->display_id == display_id)
- {
- display_depth->depth = depth;
- pthread_mutex_unlock( &settings_mutex );
- return;
- }
- }
-
- display_depth = malloc(sizeof(*display_depth));
- if (!display_depth)
- {
- ERR("Failed to allocate memory.\n");
- pthread_mutex_unlock( &settings_mutex );
- return;
- }
-
- display_depth->display_id = display_id;
- display_depth->depth = depth;
- list_add_head(&x11drv_display_depth_list, &display_depth->entry);
- pthread_mutex_unlock( &settings_mutex );
-}
-
-static DWORD get_display_depth(ULONG_PTR display_id)
-{
- struct x11drv_display_depth *display_depth;
- DWORD depth;
-
- pthread_mutex_lock( &settings_mutex );
- LIST_FOR_EACH_ENTRY(display_depth, &x11drv_display_depth_list, struct x11drv_display_depth, entry)
- {
- if (display_depth->display_id == display_id)
- {
- depth = display_depth->depth;
- pthread_mutex_unlock( &settings_mutex );
- return depth;
- }
- }
- pthread_mutex_unlock( &settings_mutex );
- return screen_bpp;
-}
-
-/***********************************************************************
- * EnumDisplaySettingsEx (X11DRV.@)
- *
- */
-BOOL X11DRV_EnumDisplaySettingsEx( LPCWSTR name, DWORD n, LPDEVMODEW devmode, DWORD flags)
-{
- static const WCHAR dev_name[CCHDEVICENAME] =
- { 'W','i','n','e',' ','X','1','1',' ','d','r','i','v','e','r',0 };
- DEVMODEW *modes;
- UINT mode_count;
- ULONG_PTR id;
-
- if (n == ENUM_REGISTRY_SETTINGS)
- {
- if (!read_registry_settings(name, devmode))
- {
- ERR("Failed to get %s registry display settings.\n", wine_dbgstr_w(name));
- return FALSE;
- }
- goto done;
- }
-
- if (n == ENUM_CURRENT_SETTINGS)
- {
- if (!settings_handler.get_id(name, &id) || !settings_handler.get_current_mode(id, devmode))
- {
- ERR("Failed to get %s current display settings.\n", wine_dbgstr_w(name));
- return FALSE;
- }
-
- if (!is_detached_mode(devmode))
- devmode->dmBitsPerPel = get_display_depth(id);
-
- goto done;
- }
-
- pthread_mutex_lock( &settings_mutex );
- if (n == 0 || wcsicmp(cached_device_name, name) || cached_flags != flags)
- {
- if (!settings_handler.get_id(name, &id) || !settings_handler.get_modes(id, flags, &modes, &mode_count))
- {
- ERR("Failed to get %s supported display modes.\n", wine_dbgstr_w(name));
- pthread_mutex_unlock( &settings_mutex );
- return FALSE;
- }
-
- qsort(modes, mode_count, sizeof(*modes) + modes[0].dmDriverExtra, mode_compare);
-
- if (cached_modes)
- settings_handler.free_modes(cached_modes);
- lstrcpyW(cached_device_name, name);
- cached_flags = flags;
- cached_modes = modes;
- cached_mode_count = mode_count;
- }
-
- if (n >= cached_mode_count)
- {
- pthread_mutex_unlock( &settings_mutex );
- WARN("handler:%s device:%s mode index:%#x not found.\n", settings_handler.name, wine_dbgstr_w(name), n);
- SetLastError(ERROR_NO_MORE_FILES);
- return FALSE;
- }
-
- memcpy(devmode, (BYTE *)cached_modes + (sizeof(*cached_modes) + cached_modes[0].dmDriverExtra) * n, sizeof(*devmode));
- pthread_mutex_unlock( &settings_mutex );
-
-done:
- /* Set generic fields */
- devmode->dmSize = FIELD_OFFSET(DEVMODEW, dmICMMethod);
- devmode->dmDriverExtra = 0;
- devmode->dmSpecVersion = DM_SPECVERSION;
- devmode->dmDriverVersion = DM_SPECVERSION;
- lstrcpyW(devmode->dmDeviceName, dev_name);
- return TRUE;
-}
-
-BOOL is_detached_mode(const DEVMODEW *mode)
-{
- return mode->dmFields & DM_POSITION &&
- mode->dmFields & DM_PELSWIDTH &&
- mode->dmFields & DM_PELSHEIGHT &&
- mode->dmPelsWidth == 0 &&
- mode->dmPelsHeight == 0;
-}
-
-/* Get the full display mode with all the necessary fields set.
- * Return NULL on failure. Caller should call free_full_mode() to free the returned mode. */
-static DEVMODEW *get_full_mode(ULONG_PTR id, DEVMODEW *dev_mode)
-{
- DEVMODEW *modes, *full_mode, *found_mode = NULL;
- UINT mode_count, mode_idx;
-
- if (is_detached_mode(dev_mode))
- return dev_mode;
-
- if (!settings_handler.get_modes(id, EDS_ROTATEDMODE, &modes, &mode_count))
- return NULL;
-
- qsort(modes, mode_count, sizeof(*modes) + modes[0].dmDriverExtra, mode_compare);
- for (mode_idx = 0; mode_idx < mode_count; ++mode_idx)
- {
- 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)
- continue;
- if (dev_mode->dmFields & DM_PELSWIDTH && found_mode->dmPelsWidth != dev_mode->dmPelsWidth)
- continue;
- if (dev_mode->dmFields & DM_PELSHEIGHT && 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)
- continue;
- if (dev_mode->dmFields & DM_DISPLAYORIENTATION &&
- found_mode->dmDisplayOrientation != dev_mode->dmDisplayOrientation)
- continue;
-
- break;
- }
-
- if (!found_mode || mode_idx == mode_count)
- {
- settings_handler.free_modes(modes);
- return NULL;
- }
-
- if (!(full_mode = malloc(sizeof(*found_mode) + found_mode->dmDriverExtra)))
- {
- settings_handler.free_modes(modes);
- return NULL;
- }
-
- memcpy(full_mode, found_mode, sizeof(*found_mode) + found_mode->dmDriverExtra);
- settings_handler.free_modes(modes);
-
- full_mode->dmFields |= DM_POSITION;
- full_mode->dmPosition = dev_mode->dmPosition;
- return full_mode;
-}
-
-static void free_full_mode(DEVMODEW *mode)
-{
- if (!is_detached_mode(mode))
- free(mode);
-}
-
-static LONG get_display_settings(struct x11drv_display_setting **new_displays,
- INT *new_display_count, const WCHAR *dev_name, DEVMODEW *dev_mode)
-{
- struct x11drv_display_setting *displays;
- DEVMODEW registry_mode, current_mode;
- 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;
-
- displays = calloc(display_count, sizeof(*displays));
- if (!displays)
- goto done;
-
- for (display_idx = 0; display_idx < display_count; ++display_idx)
- {
- if (NtUserEnumDisplayDevices( NULL, display_idx, &display_device, 0 ))
- goto done;
-
- if (!settings_handler.get_id(display_device.DeviceName, &displays[display_idx].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;
-
- displays[display_idx].desired_mode = registry_mode;
- }
- else if (!wcsicmp(dev_name, display_device.DeviceName))
- {
- displays[display_idx].desired_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;
-
- displays[display_idx].desired_mode.dmFields |= DM_POSITION;
- displays[display_idx].desired_mode.dmPosition = current_mode.dmPosition;
- }
- }
- 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;
-
- displays[display_idx].desired_mode = current_mode;
- }
-
- SetRect(&displays[display_idx].desired_rect,
- displays[display_idx].desired_mode.dmPosition.x,
- displays[display_idx].desired_mode.dmPosition.y,
- displays[display_idx].desired_mode.dmPosition.x + displays[display_idx].desired_mode.dmPelsWidth,
- displays[display_idx].desired_mode.dmPosition.y + displays[display_idx].desired_mode.dmPelsHeight);
- lstrcpyW(displays[display_idx].desired_mode.dmDeviceName, display_device.DeviceName);
- }
-
- *new_displays = displays;
- *new_display_count = display_count;
- return DISP_CHANGE_SUCCESSFUL;
-
-done:
- free(displays);
- return ret;
-}
-
-static INT offset_length(POINT offset)
-{
- return offset.x * offset.x + offset.y * offset.y;
-}
-
-/* Check if a rect overlaps with placed display rects */
-static BOOL overlap_placed_displays(const RECT *rect, const struct x11drv_display_setting *displays, INT display_count)
-{
- INT display_idx;
- RECT intersect;
-
- for (display_idx = 0; display_idx < display_count; ++display_idx)
- {
- if (displays[display_idx].placed &&
- intersect_rect(&intersect, &displays[display_idx].new_rect, 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 struct x11drv_display_setting *displays, INT display_count, INT placing_idx)
-{
- POINT points[8], left_top, offset, min_offset = {0, 0};
- INT display_idx, point_idx, point_count, vertex_idx;
- BOOL has_placed = FALSE, first = TRUE;
- INT width, height;
- RECT rect;
-
- /* If the display to be placed is detached, no offset is needed to place it */
- if (IsRectEmpty(&displays[placing_idx].desired_rect))
- return min_offset;
-
- /* If there is no placed and attached display, place this display as it is */
- for (display_idx = 0; display_idx < display_count; ++display_idx)
- {
- if (displays[display_idx].placed && !IsRectEmpty(&displays[display_idx].new_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 = displays[placing_idx].desired_rect.right - displays[placing_idx].desired_rect.left;
- height = displays[placing_idx].desired_rect.bottom - displays[placing_idx].desired_rect.top;
-
- for (display_idx = 0; display_idx < display_count; ++display_idx)
- {
- if (!displays[display_idx].placed || IsRectEmpty(&displays[display_idx].new_rect))
- continue;
-
- /* Get four vertices of the placed display rectangle */
- points[0].x = displays[display_idx].new_rect.left;
- points[0].y = displays[display_idx].new_rect.top;
- points[1].x = displays[display_idx].new_rect.left;
- points[1].y = displays[display_idx].new_rect.bottom;
- points[2].x = displays[display_idx].new_rect.right;
- points[2].y = displays[display_idx].new_rect.top;
- points[3].x = displays[display_idx].new_rect.right;
- points[3].y = displays[display_idx].new_rect.bottom;
- point_count = 4;
-
- /* Intersected points when moving the display to be placed horizontally */
- if (displays[placing_idx].desired_rect.bottom >= displays[display_idx].new_rect.top &&
- displays[placing_idx].desired_rect.top <= displays[display_idx].new_rect.bottom)
- {
- points[point_count].x = displays[display_idx].new_rect.left;
- points[point_count++].y = displays[placing_idx].desired_rect.top;
- points[point_count].x = displays[display_idx].new_rect.right;
- points[point_count++].y = displays[placing_idx].desired_rect.top;
- }
- /* Intersected points when moving the display to be placed vertically */
- if (displays[placing_idx].desired_rect.left <= displays[display_idx].new_rect.right &&
- displays[placing_idx].desired_rect.right >= displays[display_idx].new_rect.left)
- {
- points[point_count].x = displays[placing_idx].desired_rect.left;
- points[point_count++].y = displays[display_idx].new_rect.top;
- points[point_count].x = displays[placing_idx].desired_rect.left;
- points[point_count++].y = displays[display_idx].new_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 - displays[placing_idx].desired_rect.left;
- offset.y = left_top.y - displays[placing_idx].desired_rect.top;
- rect = displays[placing_idx].desired_rect;
- OffsetRect(&rect, offset.x, offset.y);
- if (!overlap_placed_displays(&rect, displays, display_count))
- {
- 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(struct x11drv_display_setting *displays, INT display_count)
-{
- INT left_most = INT_MAX, top_most = INT_MAX;
- INT placing_idx, display_idx;
- POINT min_offset, offset;
-
- /* 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_idx = -1;
- for (display_idx = 0; display_idx < display_count; ++display_idx)
- {
- if (displays[display_idx].placed)
- continue;
-
- offset = get_placement_offset(displays, display_count, display_idx);
- if (placing_idx == -1 || offset_length(offset) < offset_length(min_offset))
- {
- min_offset = offset;
- placing_idx = display_idx;
- }
- }
-
- /* If all displays are placed */
- if (placing_idx == -1)
- break;
-
- displays[placing_idx].new_rect = displays[placing_idx].desired_rect;
- OffsetRect(&displays[placing_idx].new_rect, min_offset.x, min_offset.y);
- displays[placing_idx].placed = TRUE;
- }
-
- for (display_idx = 0; display_idx < display_count; ++display_idx)
- {
- displays[display_idx].desired_mode.dmPosition.x = displays[display_idx].new_rect.left;
- displays[display_idx].desired_mode.dmPosition.y = displays[display_idx].new_rect.top;
- left_most = min(left_most, displays[display_idx].new_rect.left);
- top_most = min(top_most, displays[display_idx].new_rect.top);
- }
-
- /* Convert virtual screen coordinates to root coordinates */
- for (display_idx = 0; display_idx < display_count; ++display_idx)
- {
- displays[display_idx].desired_mode.dmPosition.x -= left_most;
- displays[display_idx].desired_mode.dmPosition.y -= top_most;
- }
-}
-
-static LONG apply_display_settings(struct x11drv_display_setting *displays, INT display_count, BOOL do_attach)
-{
- DEVMODEW *full_mode;
- BOOL attached_mode;
- INT display_idx;
- LONG ret;
-
- for (display_idx = 0; display_idx < display_count; ++display_idx)
- {
- attached_mode = !is_detached_mode(&displays[display_idx].desired_mode);
- if ((attached_mode && !do_attach) || (!attached_mode && do_attach))
- continue;
-
- full_mode = get_full_mode(displays[display_idx].id, &displays[display_idx].desired_mode);
- if (!full_mode)
- return DISP_CHANGE_BADMODE;
-
- TRACE("handler:%s changing %s to position:(%d,%d) resolution:%ux%u frequency:%uHz "
- "depth:%ubits orientation:%#x.\n", settings_handler.name,
- wine_dbgstr_w(displays[display_idx].desired_mode.dmDeviceName),
- full_mode->dmPosition.x, full_mode->dmPosition.y, full_mode->dmPelsWidth,
- full_mode->dmPelsHeight, full_mode->dmDisplayFrequency, full_mode->dmBitsPerPel,
- full_mode->dmDisplayOrientation);
-
- ret = settings_handler.set_current_mode(displays[display_idx].id, full_mode);
- if (attached_mode && ret == DISP_CHANGE_SUCCESSFUL)
- set_display_depth(displays[display_idx].id, full_mode->dmBitsPerPel);
- free_full_mode(full_mode);
- if (ret != DISP_CHANGE_SUCCESSFUL)
- return ret;
- }
-
- return DISP_CHANGE_SUCCESSFUL;
-}
-
-static BOOL all_detached_settings(const struct x11drv_display_setting *displays, INT display_count)
-{
- INT display_idx;
-
- for (display_idx = 0; display_idx < display_count; ++display_idx)
- {
- if (!is_detached_mode(&displays[display_idx].desired_mode))
- return FALSE;
- }
-
- return TRUE;
-}
-
-/***********************************************************************
- * ChangeDisplaySettingsEx (X11DRV.@)
- *
- */
-LONG X11DRV_ChangeDisplaySettingsEx( LPCWSTR devname, LPDEVMODEW devmode,
- HWND hwnd, DWORD flags, LPVOID lpvoid )
-{
- struct x11drv_display_setting *displays;
- INT display_idx, display_count;
- DEVMODEW *full_mode;
- LONG ret;
-
- ret = get_display_settings(&displays, &display_count, devname, devmode);
- if (ret != DISP_CHANGE_SUCCESSFUL)
- return ret;
-
- if (flags & CDS_UPDATEREGISTRY && devname && devmode)
- {
- for (display_idx = 0; display_idx < display_count; ++display_idx)
- {
- if (!wcsicmp(displays[display_idx].desired_mode.dmDeviceName, devname))
- {
- full_mode = get_full_mode(displays[display_idx].id, &displays[display_idx].desired_mode);
- if (!full_mode)
- {
- free(displays);
- return DISP_CHANGE_BADMODE;
- }
-
- if (!write_registry_settings(devname, full_mode))
- {
- ERR("Failed to write %s display settings to registry.\n", wine_dbgstr_w(devname));
- free_full_mode(full_mode);
- free(displays);
- return DISP_CHANGE_NOTUPDATED;
- }
-
- free_full_mode(full_mode);
- break;
- }
- }
- }
-
- if (flags & (CDS_TEST | CDS_NORESET))
- {
- free(displays);
- return DISP_CHANGE_SUCCESSFUL;
- }
-
- if (all_detached_settings(displays, display_count))
- {
- WARN("Detaching all displays is not permitted.\n");
- free(displays);
- return DISP_CHANGE_SUCCESSFUL;
- }
-
- place_all_displays(displays, display_count);
-
- /* Detach displays first to free up CRTCs */
- ret = apply_display_settings(displays, display_count, FALSE);
- if (ret == DISP_CHANGE_SUCCESSFUL)
- ret = apply_display_settings(displays, display_count, TRUE);
- if (ret == DISP_CHANGE_SUCCESSFUL)
- X11DRV_DisplayDevices_Update(TRUE);
- free(displays);
- return ret;
-}
--
GitLab
https://gitlab.winehq.org/wine/wine/-/merge_requests/322
More information about the wine-devel
mailing list