mirror of
git://source.winehq.org/git/wine.git
synced 2024-10-31 14:24:45 +00:00
win32u: Move display placement logic out of graphics drivers.
This commit is contained in:
parent
8b737af658
commit
12d0792f74
10 changed files with 337 additions and 382 deletions
|
@ -753,8 +753,8 @@ static void nulldrv_UpdateClipboard(void)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
static LONG nulldrv_ChangeDisplaySettingsEx( LPCWSTR name, LPDEVMODEW mode, HWND hwnd,
|
static LONG nulldrv_ChangeDisplaySettings( LPDEVMODEW displays, HWND hwnd,
|
||||||
DWORD flags, LPVOID lparam )
|
DWORD flags, LPVOID lparam )
|
||||||
{
|
{
|
||||||
return DISP_CHANGE_FAILED;
|
return DISP_CHANGE_FAILED;
|
||||||
}
|
}
|
||||||
|
@ -1071,10 +1071,10 @@ static SHORT loaderdrv_VkKeyScanEx( WCHAR ch, HKL layout )
|
||||||
return load_driver()->pVkKeyScanEx( ch, layout );
|
return load_driver()->pVkKeyScanEx( ch, layout );
|
||||||
}
|
}
|
||||||
|
|
||||||
static LONG loaderdrv_ChangeDisplaySettingsEx( LPCWSTR name, LPDEVMODEW mode, HWND hwnd,
|
static LONG loaderdrv_ChangeDisplaySettings( LPDEVMODEW displays, HWND hwnd,
|
||||||
DWORD flags, LPVOID lparam )
|
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 )
|
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,
|
nulldrv_ClipboardWindowProc,
|
||||||
loaderdrv_UpdateClipboard,
|
loaderdrv_UpdateClipboard,
|
||||||
/* display modes */
|
/* display modes */
|
||||||
loaderdrv_ChangeDisplaySettingsEx,
|
loaderdrv_ChangeDisplaySettings,
|
||||||
loaderdrv_EnumDisplaySettingsEx,
|
loaderdrv_EnumDisplaySettingsEx,
|
||||||
loaderdrv_GetCurrentDisplaySettings,
|
loaderdrv_GetCurrentDisplaySettings,
|
||||||
loaderdrv_UpdateDisplayDevices,
|
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(ClipCursor);
|
||||||
SET_USER_FUNC(ClipboardWindowProc);
|
SET_USER_FUNC(ClipboardWindowProc);
|
||||||
SET_USER_FUNC(UpdateClipboard);
|
SET_USER_FUNC(UpdateClipboard);
|
||||||
SET_USER_FUNC(ChangeDisplaySettingsEx);
|
SET_USER_FUNC(ChangeDisplaySettings);
|
||||||
SET_USER_FUNC(EnumDisplaySettingsEx);
|
SET_USER_FUNC(EnumDisplaySettingsEx);
|
||||||
SET_USER_FUNC(GetCurrentDisplaySettings);
|
SET_USER_FUNC(GetCurrentDisplaySettings);
|
||||||
SET_USER_FUNC(UpdateDisplayDevices);
|
SET_USER_FUNC(UpdateDisplayDevices);
|
||||||
|
|
|
@ -660,8 +660,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)
|
if (query_reg_value( hkey, mode_countW, value, sizeof(buffer) ) && value->Type == REG_DWORD)
|
||||||
info->mode_count = *(const DWORD *)value->Data;
|
info->mode_count = *(const DWORD *)value->Data;
|
||||||
|
|
||||||
/* Modes */
|
/* Modes, allocate an extra mode for easier iteration */
|
||||||
if ((info->modes = calloc( info->mode_count, sizeof(DEVMODEW) )))
|
if ((info->modes = calloc( info->mode_count + 1, sizeof(DEVMODEW) )))
|
||||||
{
|
{
|
||||||
for (i = 0, mode = info->modes; i < info->mode_count; i++)
|
for (i = 0, mode = info->modes; i < info->mode_count; i++)
|
||||||
{
|
{
|
||||||
|
@ -2192,6 +2192,254 @@ static DEVMODEW *get_full_mode( const WCHAR *adapter_path, const WCHAR *device_n
|
||||||
return devmode;
|
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 )
|
||||||
|
{
|
||||||
|
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.@)
|
* NtUserChangeDisplaySettings (win32u.@)
|
||||||
*/
|
*/
|
||||||
|
@ -2206,13 +2454,7 @@ LONG WINAPI NtUserChangeDisplaySettings( UNICODE_STRING *devname, DEVMODEW *devm
|
||||||
TRACE( "%s %p %p %#x %p\n", debugstr_us(devname), devmode, hwnd, flags, lparam );
|
TRACE( "%s %p %p %#x %p\n", debugstr_us(devname), devmode, hwnd, flags, lparam );
|
||||||
TRACE( "flags=%s\n", _CDS_flags(flags) );
|
TRACE( "flags=%s\n", _CDS_flags(flags) );
|
||||||
|
|
||||||
if ((!devname || !devname->Length) && !devmode)
|
if ((!devname || !devname->Length) && !devmode) return apply_display_settings( NULL, NULL, hwnd, flags, lparam );
|
||||||
{
|
|
||||||
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 (!lock_display_devices()) return DISP_CHANGE_FAILED;
|
if (!lock_display_devices()) return DISP_CHANGE_FAILED;
|
||||||
if ((adapter = find_adapter( devname )))
|
if ((adapter = find_adapter( devname )))
|
||||||
|
@ -2233,7 +2475,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;
|
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_UPDATEREGISTRY) && !write_registry_settings( adapter_path, devmode )) ret = DISP_CHANGE_NOTUPDATED;
|
||||||
else if (flags & (CDS_TEST | CDS_NORESET)) ret = DISP_CHANGE_SUCCESSFUL;
|
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 );
|
free( modes );
|
||||||
|
|
||||||
if (ret) ERR( "Changing %s display settings returned %d.\n", debugstr_us(devname), ret );
|
if (ret) ERR( "Changing %s display settings returned %d.\n", debugstr_us(devname), ret );
|
||||||
|
|
|
@ -260,12 +260,11 @@ static BOOL CDECL ANDROID_DeleteDC( PHYSDEV dev )
|
||||||
|
|
||||||
|
|
||||||
/***********************************************************************
|
/***********************************************************************
|
||||||
* ANDROID_ChangeDisplaySettingsEx
|
* ANDROID_ChangeDisplaySettings
|
||||||
*/
|
*/
|
||||||
LONG ANDROID_ChangeDisplaySettingsEx( LPCWSTR devname, LPDEVMODEW devmode,
|
LONG ANDROID_ChangeDisplaySettings( LPDEVMODEW displays, HWND hwnd, DWORD flags, LPVOID lpvoid )
|
||||||
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;
|
return DISP_CHANGE_SUCCESSFUL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -377,7 +376,7 @@ static const struct user_driver_funcs android_drv_funcs =
|
||||||
.pMapVirtualKeyEx = ANDROID_MapVirtualKeyEx,
|
.pMapVirtualKeyEx = ANDROID_MapVirtualKeyEx,
|
||||||
.pVkKeyScanEx = ANDROID_VkKeyScanEx,
|
.pVkKeyScanEx = ANDROID_VkKeyScanEx,
|
||||||
.pSetCursor = ANDROID_SetCursor,
|
.pSetCursor = ANDROID_SetCursor,
|
||||||
.pChangeDisplaySettingsEx = ANDROID_ChangeDisplaySettingsEx,
|
.pChangeDisplaySettings = ANDROID_ChangeDisplaySettings,
|
||||||
.pEnumDisplaySettingsEx = ANDROID_EnumDisplaySettingsEx,
|
.pEnumDisplaySettingsEx = ANDROID_EnumDisplaySettingsEx,
|
||||||
.pGetCurrentDisplaySettings = ANDROID_GetCurrentDisplaySettings,
|
.pGetCurrentDisplaySettings = ANDROID_GetCurrentDisplaySettings,
|
||||||
.pUpdateDisplayDevices = ANDROID_UpdateDisplayDevices,
|
.pUpdateDisplayDevices = ANDROID_UpdateDisplayDevices,
|
||||||
|
|
|
@ -34,6 +34,7 @@
|
||||||
|
|
||||||
WINE_DEFAULT_DEBUG_CHANNEL(display);
|
WINE_DEFAULT_DEBUG_CHANNEL(display);
|
||||||
|
|
||||||
|
#define NEXT_DEVMODEW(mode) ((DEVMODEW *)((char *)((mode) + 1) + (mode)->dmDriverExtra))
|
||||||
|
|
||||||
struct display_mode_descriptor
|
struct display_mode_descriptor
|
||||||
{
|
{
|
||||||
|
@ -769,84 +770,73 @@ static CGDisplayModeRef find_best_display_mode(DEVMODEW *devmode, CFArrayRef dis
|
||||||
}
|
}
|
||||||
|
|
||||||
/***********************************************************************
|
/***********************************************************************
|
||||||
* ChangeDisplaySettingsEx (MACDRV.@)
|
* ChangeDisplaySettings (MACDRV.@)
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
LONG macdrv_ChangeDisplaySettingsEx(LPCWSTR devname, LPDEVMODEW devmode,
|
LONG macdrv_ChangeDisplaySettings(LPDEVMODEW displays, HWND hwnd, DWORD flags, LPVOID lpvoid)
|
||||||
HWND hwnd, DWORD flags, LPVOID lpvoid)
|
|
||||||
{
|
{
|
||||||
WCHAR primary_adapter[CCHDEVICENAME];
|
WCHAR primary_adapter[CCHDEVICENAME];
|
||||||
LONG ret = DISP_CHANGE_BADMODE;
|
LONG ret = DISP_CHANGE_SUCCESSFUL;
|
||||||
DEVMODEW default_mode;
|
DEVMODEW *mode;
|
||||||
int bpp;
|
int bpp;
|
||||||
struct macdrv_display *displays;
|
struct macdrv_display *macdrv_displays;
|
||||||
int num_displays;
|
int num_displays;
|
||||||
CFArrayRef display_modes;
|
CFArrayRef display_modes;
|
||||||
struct display_mode_descriptor *desc;
|
struct display_mode_descriptor *desc;
|
||||||
CGDisplayModeRef best_display_mode;
|
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();
|
init_original_display_mode();
|
||||||
|
|
||||||
if (!get_primary_adapter(primary_adapter))
|
if (!get_primary_adapter(primary_adapter))
|
||||||
return DISP_CHANGE_FAILED;
|
return DISP_CHANGE_FAILED;
|
||||||
|
|
||||||
if (!devname && !devmode)
|
if (macdrv_get_displays(&macdrv_displays, &num_displays))
|
||||||
{
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
else if (wcsicmp(primary_adapter, devname))
|
|
||||||
{
|
|
||||||
FIXME("Changing non-primary adapter settings is currently unsupported.\n");
|
|
||||||
return DISP_CHANGE_SUCCESSFUL;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (is_detached_mode(devmode))
|
|
||||||
{
|
|
||||||
FIXME("Detaching adapters is currently unsupported.\n");
|
|
||||||
return DISP_CHANGE_SUCCESSFUL;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (macdrv_get_displays(&displays, &num_displays))
|
|
||||||
return DISP_CHANGE_FAILED;
|
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)
|
if (!display_modes)
|
||||||
{
|
{
|
||||||
macdrv_free_displays(displays);
|
macdrv_free_displays(macdrv_displays);
|
||||||
return DISP_CHANGE_FAILED;
|
return DISP_CHANGE_FAILED;
|
||||||
}
|
}
|
||||||
|
|
||||||
pthread_mutex_lock(&cached_modes_mutex);
|
pthread_mutex_lock(&cached_modes_mutex);
|
||||||
bpp = get_default_bpp();
|
bpp = get_default_bpp();
|
||||||
pthread_mutex_unlock(&cached_modes_mutex);
|
pthread_mutex_unlock(&cached_modes_mutex);
|
||||||
if (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->dmPelsWidth, devmode->dmPelsHeight,
|
desc = create_original_display_mode_descriptor(macdrv_displays[0].displayID);
|
||||||
bpp, devmode->dmDisplayFrequency);
|
|
||||||
TRACE(" %sstretched", devmode->dmDisplayFixedOutput == DMDFO_STRETCH ? "" : "un");
|
|
||||||
TRACE(" %sinterlaced", devmode->dmDisplayFlags & DM_INTERLACED ? "" : "non-");
|
|
||||||
TRACE("\n");
|
|
||||||
|
|
||||||
desc = create_original_display_mode_descriptor(displays[0].displayID);
|
for (mode = displays; mode->dmSize && !ret; mode = NEXT_DEVMODEW(mode))
|
||||||
best_display_mode = find_best_display_mode(devmode, display_modes, bpp, desc);
|
|
||||||
|
|
||||||
if (best_display_mode)
|
|
||||||
{
|
{
|
||||||
if (macdrv_set_display_mode(&displays[0], best_display_mode))
|
if (wcsicmp(primary_adapter, mode->dmDeviceName))
|
||||||
|
{
|
||||||
|
FIXME("Changing non-primary adapter settings is currently unsupported.\n");
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (is_detached_mode(mode))
|
||||||
|
{
|
||||||
|
FIXME("Detaching adapters is currently unsupported.\n");
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (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->dmPelsWidth, mode->dmPelsHeight,
|
||||||
|
bpp, mode->dmDisplayFrequency);
|
||||||
|
TRACE(" %sstretched", mode->dmDisplayFixedOutput == DMDFO_STRETCH ? "" : "un");
|
||||||
|
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(&macdrv_displays[0], best_display_mode))
|
||||||
{
|
{
|
||||||
int mode_bpp = display_mode_bits_per_pixel(best_display_mode);
|
int mode_bpp = display_mode_bits_per_pixel(best_display_mode);
|
||||||
size_t width = CGDisplayModeGetWidth(best_display_mode);
|
size_t width = CGDisplayModeGetWidth(best_display_mode);
|
||||||
|
@ -862,7 +852,6 @@ LONG macdrv_ChangeDisplaySettingsEx(LPCWSTR devname, LPDEVMODEW devmode,
|
||||||
|
|
||||||
send_message(NtUserGetDesktopWindow(), WM_MACDRV_UPDATE_DESKTOP_RECT, mode_bpp,
|
send_message(NtUserGetDesktopWindow(), WM_MACDRV_UPDATE_DESKTOP_RECT, mode_bpp,
|
||||||
MAKELPARAM(width, height));
|
MAKELPARAM(width, height));
|
||||||
ret = DISP_CHANGE_SUCCESSFUL;
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
@ -870,16 +859,10 @@ LONG macdrv_ChangeDisplaySettingsEx(LPCWSTR devname, LPDEVMODEW devmode,
|
||||||
ret = DISP_CHANGE_FAILED;
|
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);
|
free_display_mode_descriptor(desc);
|
||||||
CFRelease(display_modes);
|
CFRelease(display_modes);
|
||||||
macdrv_free_displays(displays);
|
macdrv_free_displays(macdrv_displays);
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
|
@ -268,7 +268,7 @@ static const struct user_driver_funcs macdrv_funcs =
|
||||||
|
|
||||||
.pActivateKeyboardLayout = macdrv_ActivateKeyboardLayout,
|
.pActivateKeyboardLayout = macdrv_ActivateKeyboardLayout,
|
||||||
.pBeep = macdrv_Beep,
|
.pBeep = macdrv_Beep,
|
||||||
.pChangeDisplaySettingsEx = macdrv_ChangeDisplaySettingsEx,
|
.pChangeDisplaySettings = macdrv_ChangeDisplaySettings,
|
||||||
.pClipCursor = macdrv_ClipCursor,
|
.pClipCursor = macdrv_ClipCursor,
|
||||||
.pClipboardWindowProc = macdrv_ClipboardWindowProc,
|
.pClipboardWindowProc = macdrv_ClipboardWindowProc,
|
||||||
.pCreateDesktopWindow = macdrv_CreateDesktopWindow,
|
.pCreateDesktopWindow = macdrv_CreateDesktopWindow,
|
||||||
|
|
|
@ -123,8 +123,7 @@ static inline RECT rect_from_cgrect(CGRect cgrect)
|
||||||
|
|
||||||
extern BOOL macdrv_ActivateKeyboardLayout(HKL hkl, UINT flags) DECLSPEC_HIDDEN;
|
extern BOOL macdrv_ActivateKeyboardLayout(HKL hkl, UINT flags) DECLSPEC_HIDDEN;
|
||||||
extern void macdrv_Beep(void) DECLSPEC_HIDDEN;
|
extern void macdrv_Beep(void) DECLSPEC_HIDDEN;
|
||||||
extern LONG macdrv_ChangeDisplaySettingsEx(LPCWSTR devname, LPDEVMODEW devmode,
|
extern LONG macdrv_ChangeDisplaySettings(LPDEVMODEW displays, HWND hwnd, DWORD flags, LPVOID lpvoid) DECLSPEC_HIDDEN;
|
||||||
HWND hwnd, DWORD flags, LPVOID lpvoid) DECLSPEC_HIDDEN;
|
|
||||||
extern BOOL macdrv_EnumDisplaySettingsEx(LPCWSTR devname, DWORD mode,
|
extern BOOL macdrv_EnumDisplaySettingsEx(LPCWSTR devname, DWORD mode,
|
||||||
LPDEVMODEW devmode, DWORD flags) DECLSPEC_HIDDEN;
|
LPDEVMODEW devmode, DWORD flags) DECLSPEC_HIDDEN;
|
||||||
extern BOOL macdrv_GetCurrentDisplaySettings(LPCWSTR name, LPDEVMODEW devmode) DECLSPEC_HIDDEN;
|
extern BOOL macdrv_GetCurrentDisplaySettings(LPCWSTR name, LPDEVMODEW devmode) DECLSPEC_HIDDEN;
|
||||||
|
|
|
@ -447,283 +447,22 @@ static void free_full_mode(DEVMODEW *mode)
|
||||||
free(mode);
|
free(mode);
|
||||||
}
|
}
|
||||||
|
|
||||||
static LONG get_display_settings(DEVMODEW **new_displays, const WCHAR *dev_name, DEVMODEW *dev_mode)
|
static LONG apply_display_settings( DEVMODEW *displays, ULONG_PTR *ids, BOOL do_attach )
|
||||||
{
|
|
||||||
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)
|
|
||||||
{
|
{
|
||||||
DEVMODEW *full_mode;
|
DEVMODEW *full_mode;
|
||||||
BOOL attached_mode;
|
BOOL attached_mode;
|
||||||
|
LONG count, ret;
|
||||||
DEVMODEW *mode;
|
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);
|
attached_mode = !is_detached_mode(mode);
|
||||||
if ((attached_mode && !do_attach) || (!attached_mode && do_attach))
|
if ((attached_mode && !do_attach) || (!attached_mode && do_attach))
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
|
/* FIXME: get a full mode again because X11 driver extra data isn't portable */
|
||||||
full_mode = get_full_mode(*id, mode);
|
full_mode = get_full_mode(*id, mode);
|
||||||
if (!full_mode)
|
if (!full_mode)
|
||||||
return DISP_CHANGE_BADMODE;
|
return DISP_CHANGE_BADMODE;
|
||||||
|
@ -746,49 +485,43 @@ static LONG apply_display_settings(DEVMODEW *displays, BOOL do_attach)
|
||||||
return DISP_CHANGE_SUCCESSFUL;
|
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,
|
LONG X11DRV_ChangeDisplaySettings( LPDEVMODEW displays, HWND hwnd, DWORD flags, LPVOID lpvoid )
|
||||||
HWND hwnd, DWORD flags, LPVOID lpvoid )
|
|
||||||
{
|
{
|
||||||
DEVMODEW *displays;
|
INT left_most = INT_MAX, top_most = INT_MAX;
|
||||||
LONG ret;
|
LONG count, ret = DISP_CHANGE_BADPARAM;
|
||||||
|
ULONG_PTR *ids;
|
||||||
|
DEVMODEW *mode;
|
||||||
|
|
||||||
ret = get_display_settings( &displays, devname, devmode );
|
/* Convert virtual screen coordinates to root coordinates, and find display ids.
|
||||||
if (ret != DISP_CHANGE_SUCCESSFUL)
|
* We cannot safely get the ids while changing modes, as the backend state may be invalidated.
|
||||||
return ret;
|
*/
|
||||||
|
for (count = 0, mode = displays; mode->dmSize; mode = NEXT_DEVMODEW(mode), count++)
|
||||||
if (all_detached_settings( displays ))
|
|
||||||
{
|
{
|
||||||
WARN("Detaching all displays is not permitted.\n");
|
left_most = min( left_most, mode->dmPosition.x );
|
||||||
free(displays);
|
top_most = min( top_most, mode->dmPosition.y );
|
||||||
return DISP_CHANGE_SUCCESSFUL;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
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 */
|
/* 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)
|
if (ret == DISP_CHANGE_SUCCESSFUL)
|
||||||
ret = apply_display_settings( displays, TRUE );
|
ret = apply_display_settings( displays, ids, TRUE );
|
||||||
if (ret == DISP_CHANGE_SUCCESSFUL)
|
if (ret == DISP_CHANGE_SUCCESSFUL)
|
||||||
X11DRV_DisplayDevices_Update(TRUE);
|
X11DRV_DisplayDevices_Update(TRUE);
|
||||||
free(displays);
|
|
||||||
|
done:
|
||||||
|
free( ids );
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -403,7 +403,7 @@ static const struct user_driver_funcs x11drv_funcs =
|
||||||
.pGetCursorPos = X11DRV_GetCursorPos,
|
.pGetCursorPos = X11DRV_GetCursorPos,
|
||||||
.pSetCursorPos = X11DRV_SetCursorPos,
|
.pSetCursorPos = X11DRV_SetCursorPos,
|
||||||
.pClipCursor = X11DRV_ClipCursor,
|
.pClipCursor = X11DRV_ClipCursor,
|
||||||
.pChangeDisplaySettingsEx = X11DRV_ChangeDisplaySettingsEx,
|
.pChangeDisplaySettings = X11DRV_ChangeDisplaySettings,
|
||||||
.pEnumDisplaySettingsEx = X11DRV_EnumDisplaySettingsEx,
|
.pEnumDisplaySettingsEx = X11DRV_EnumDisplaySettingsEx,
|
||||||
.pGetCurrentDisplaySettings = X11DRV_GetCurrentDisplaySettings,
|
.pGetCurrentDisplaySettings = X11DRV_GetCurrentDisplaySettings,
|
||||||
.pUpdateDisplayDevices = X11DRV_UpdateDisplayDevices,
|
.pUpdateDisplayDevices = X11DRV_UpdateDisplayDevices,
|
||||||
|
|
|
@ -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_SetCursorPos( INT x, INT y ) DECLSPEC_HIDDEN;
|
||||||
extern BOOL X11DRV_GetCursorPos( LPPOINT pos ) DECLSPEC_HIDDEN;
|
extern BOOL X11DRV_GetCursorPos( LPPOINT pos ) DECLSPEC_HIDDEN;
|
||||||
extern BOOL X11DRV_ClipCursor( LPCRECT clip ) DECLSPEC_HIDDEN;
|
extern BOOL X11DRV_ClipCursor( LPCRECT clip ) DECLSPEC_HIDDEN;
|
||||||
extern LONG X11DRV_ChangeDisplaySettingsEx( LPCWSTR devname, LPDEVMODEW devmode,
|
extern LONG X11DRV_ChangeDisplaySettings( LPDEVMODEW displays, HWND hwnd, DWORD flags, LPVOID lpvoid ) DECLSPEC_HIDDEN;
|
||||||
HWND hwnd, DWORD flags, LPVOID lpvoid ) DECLSPEC_HIDDEN;
|
|
||||||
extern BOOL X11DRV_EnumDisplaySettingsEx( LPCWSTR name, DWORD n, LPDEVMODEW devmode,
|
extern BOOL X11DRV_EnumDisplaySettingsEx( LPCWSTR name, DWORD n, LPDEVMODEW devmode,
|
||||||
DWORD flags ) DECLSPEC_HIDDEN;
|
DWORD flags ) DECLSPEC_HIDDEN;
|
||||||
extern BOOL X11DRV_GetCurrentDisplaySettings( LPCWSTR name, LPDEVMODEW devmode ) DECLSPEC_HIDDEN;
|
extern BOOL X11DRV_GetCurrentDisplaySettings( LPCWSTR name, LPDEVMODEW devmode ) DECLSPEC_HIDDEN;
|
||||||
|
|
|
@ -295,7 +295,7 @@ struct user_driver_funcs
|
||||||
LRESULT (*pClipboardWindowProc)(HWND,UINT,WPARAM,LPARAM);
|
LRESULT (*pClipboardWindowProc)(HWND,UINT,WPARAM,LPARAM);
|
||||||
void (*pUpdateClipboard)(void);
|
void (*pUpdateClipboard)(void);
|
||||||
/* display modes */
|
/* display modes */
|
||||||
LONG (*pChangeDisplaySettingsEx)(LPCWSTR,LPDEVMODEW,HWND,DWORD,LPVOID);
|
LONG (*pChangeDisplaySettings)(LPDEVMODEW,HWND,DWORD,LPVOID);
|
||||||
BOOL (*pEnumDisplaySettingsEx)(LPCWSTR,DWORD,LPDEVMODEW,DWORD);
|
BOOL (*pEnumDisplaySettingsEx)(LPCWSTR,DWORD,LPDEVMODEW,DWORD);
|
||||||
BOOL (*pGetCurrentDisplaySettings)(LPCWSTR,LPDEVMODEW);
|
BOOL (*pGetCurrentDisplaySettings)(LPCWSTR,LPDEVMODEW);
|
||||||
BOOL (*pUpdateDisplayDevices)(const struct gdi_device_manager *,BOOL,void*);
|
BOOL (*pUpdateDisplayDevices)(const struct gdi_device_manager *,BOOL,void*);
|
||||||
|
|
Loading…
Reference in a new issue