2 * System parameters functions
4 * Copyright 1994 Alexandre Julliard
5 * Copyright 2019 Zhiyi Zhang for CodeWeavers
6 * Copyright 2021 Jacek Caban for CodeWeavers
8 * This library is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU Lesser General Public
10 * License as published by the Free Software Foundation; either
11 * version 2.1 of the License, or (at your option) any later version.
13 * This library is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * Lesser General Public License for more details.
18 * You should have received a copy of the GNU Lesser General Public
19 * License along with this library; if not, write to the Free Software
20 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
31 #define WIN32_NO_STATUS
32 #include "ntgdi_private.h"
33 #include "ntuser_private.h"
34 #include "devpropdef.h"
35 #include "wine/wingdi16.h"
36 #include "wine/server.h"
38 WINE_DEFAULT_DEBUG_CHANNEL(system
);
41 static HKEY video_key
, enum_key
, control_key
, config_key
, volatile_base_key
;
43 static const WCHAR devicemap_video_keyW
[] =
45 '\\','R','e','g','i','s','t','r','y',
46 '\\','M','a','c','h','i','n','e',
47 '\\','H','A','R','D','W','A','R','E',
48 '\\','D','E','V','I','C','E','M','A','P',
49 '\\','V','I','D','E','O'
52 static const WCHAR enum_keyW
[] =
54 '\\','R','e','g','i','s','t','r','y',
55 '\\','M','a','c','h','i','n','e',
56 '\\','S','y','s','t','e','m',
57 '\\','C','u','r','r','e','n','t','C','o','n','t','r','o','l','S','e','t',
61 static const WCHAR control_keyW
[] =
63 '\\','R','e','g','i','s','t','r','y',
64 '\\','M','a','c','h','i','n','e',
65 '\\','S','y','s','t','e','m',
66 '\\','C','u','r','r','e','n','t','C','o','n','t','r','o','l','S','e','t',
67 '\\','C','o','n','t','r','o','l'
70 static const WCHAR config_keyW
[] =
72 '\\','R','e','g','i','s','t','r','y',
73 '\\','M','a','c','h','i','n','e',
74 '\\','S','y','s','t','e','m',
75 '\\','C','u','r','r','e','n','t','C','o','n','t','r','o','l','S','e','t',
76 '\\','H','a','r','d','w','a','r','e',' ','P','r','o','f','i','l','e','s',
77 '\\','C','u','r','r','e','n','t'
80 static const WCHAR devpropkey_gpu_vulkan_uuidW
[] =
82 'P','r','o','p','e','r','t','i','e','s',
83 '\\','{','2','3','3','A','9','E','F','3','-','A','F','C','4','-','4','A','B','D',
84 '-','B','5','6','4','-','C','3','2','F','2','1','F','1','5','3','5','C','}',
88 static const WCHAR devpropkey_gpu_luidW
[] =
90 'P','r','o','p','e','r','t','i','e','s',
91 '\\','{','6','0','B','1','9','3','C','B','-','5','2','7','6','-','4','D','0','F',
92 '-','9','6','F','C','-','F','1','7','3','A','B','A','D','3','E','C','6','}',
96 static const WCHAR devpkey_device_matching_device_id
[] =
98 'P','r','o','p','e','r','t','i','e','s',
99 '\\','{','A','8','B','8','6','5','D','D','-','2','E','3','D','-','4','0','9','4',
100 '-','A','D','9','7','-','E','5','9','3','A','7','0','C','7','5','D','6','}',
104 static const WCHAR devpropkey_device_ispresentW
[] =
106 'P','r','o','p','e','r','t','i','e','s',
107 '\\','{','5','4','0','B','9','4','7','E','-','8','B','4','0','-','4','5','B','C',
108 '-','A','8','A','2','-','6','A','0','B','8','9','4','C','B','D','A','2','}',
112 static const WCHAR devpropkey_monitor_gpu_luidW
[] =
114 'P','r','o','p','e','r','t','i','e','s',
115 '\\','{','C','A','0','8','5','8','5','3','-','1','6','C','E','-','4','8','A','A',
116 '-','B','1','1','4','-','D','E','9','C','7','2','3','3','4','2','2','3','}',
120 static const WCHAR devpropkey_monitor_output_idW
[] =
122 'P','r','o','p','e','r','t','i','e','s',
123 '\\','{','C','A','0','8','5','8','5','3','-','1','6','C','E','-','4','8','A','A',
124 '-','B','1','1','4','-','D','E','9','C','7','2','3','3','4','2','2','3','}',
128 static const WCHAR wine_devpropkey_monitor_stateflagsW
[] =
130 'P','r','o','p','e','r','t','i','e','s','\\',
131 '{','2','3','3','a','9','e','f','3','-','a','f','c','4','-','4','a','b','d',
132 '-','b','5','6','4','-','c','3','2','f','2','1','f','1','5','3','5','b','}',
136 static const WCHAR wine_devpropkey_monitor_rcmonitorW
[] =
138 'P','r','o','p','e','r','t','i','e','s','\\',
139 '{','2','3','3','a','9','e','f','3','-','a','f','c','4','-','4','a','b','d',
140 '-','b','5','6','4','-','c','3','2','f','2','1','f','1','5','3','5','b','}',
144 static const WCHAR wine_devpropkey_monitor_rcworkW
[] =
146 'P','r','o','p','e','r','t','i','e','s','\\',
147 '{','2','3','3','a','9','e','f','3','-','a','f','c','4','-','4','a','b','d',
148 '-','b','5','6','4','-','c','3','2','f','2','1','f','1','5','3','5','b','}',
152 static const WCHAR wine_devpropkey_monitor_adapternameW
[] =
154 'P','r','o','p','e','r','t','i','e','s','\\',
155 '{','2','3','3','a','9','e','f','3','-','a','f','c','4','-','4','a','b','d',
156 '-','b','5','6','4','-','c','3','2','f','2','1','f','1','5','3','5','b','}',
160 static const WCHAR device_instanceW
[] = {'D','e','v','i','c','e','I','n','s','t','a','n','c','e',0};
161 static const WCHAR controlW
[] = {'C','o','n','t','r','o','l'};
162 static const WCHAR device_parametersW
[] =
163 {'D','e','v','i','c','e',' ','P','a','r','a','m','e','t','e','r','s'};
164 static const WCHAR linkedW
[] = {'L','i','n','k','e','d',0};
165 static const WCHAR symbolic_link_valueW
[] =
166 {'S','y','m','b','o','l','i','c','L','i','n','k','V','a','l','u','e',0};
167 static const WCHAR state_flagsW
[] = {'S','t','a','t','e','F','l','a','g','s',0};
168 static const WCHAR gpu_idW
[] = {'G','P','U','I','D',0};
169 static const WCHAR hardware_idW
[] = {'H','a','r','d','w','a','r','e','I','D',0};
170 static const WCHAR device_descW
[] = {'D','e','v','i','c','e','D','e','s','c',0};
171 static const WCHAR driver_descW
[] = {'D','r','i','v','e','r','D','e','s','c',0};
172 static const WCHAR driverW
[] = {'D','r','i','v','e','r',0};
173 static const WCHAR class_guidW
[] = {'C','l','a','s','s','G','U','I','D',0};
174 static const WCHAR pciW
[] = {'P','C','I'};
175 static const WCHAR classW
[] = {'C','l','a','s','s',0};
176 static const WCHAR displayW
[] = {'D','i','s','p','l','a','y',0};
177 static const WCHAR monitorW
[] = {'M','o','n','i','t','o','r',0};
178 static const WCHAR yesW
[] = {'Y','e','s',0};
179 static const WCHAR noW
[] = {'N','o',0};
180 static const WCHAR mode_countW
[] = {'M','o','d','e','C','o','u','n','t',0};
181 static const WCHAR edidW
[] = {'E','D','I','D',0};
183 static const char guid_devclass_displayA
[] = "{4D36E968-E325-11CE-BFC1-08002BE10318}";
184 static const WCHAR guid_devclass_displayW
[] =
185 {'{','4','D','3','6','E','9','6','8','-','E','3','2','5','-','1','1','C','E','-',
186 'B','F','C','1','-','0','8','0','0','2','B','E','1','0','3','1','8','}',0};
188 static const char guid_devclass_monitorA
[] = "{4D36E96E-E325-11CE-BFC1-08002BE10318}";
189 static const WCHAR guid_devclass_monitorW
[] =
190 {'{','4','D','3','6','E','9','6','E','-','E','3','2','5','-','1','1','C','E','-',
191 'B','F','C','1','-','0','8','0','0','2','B','E','1','0','3','1','8','}',0};
193 static const WCHAR guid_devinterface_display_adapterW
[] =
194 {'{','5','B','4','5','2','0','1','D','-','F','2','F','2','-','4','F','3','B','-',
195 '8','5','B','B','-','3','0','F','F','1','F','9','5','3','5','9','9','}',0};
197 static const WCHAR guid_display_device_arrivalW
[] =
198 {'{','1','C','A','0','5','1','8','0','-','A','6','9','9','-','4','5','0','A','-',
199 '9','A','0','C','-','D','E','4','F','B','E','3','D','D','D','8','9','}',0};
201 static const WCHAR guid_devinterface_monitorW
[] =
202 {'{','E','6','F','0','7','B','5','F','-','E','E','9','7','-','4','A','9','0','-',
203 'B','0','7','6','-','3','3','F','5','7','B','F','4','E','A','A','7','}',0};
205 #define NEXT_DEVMODEW(mode) ((DEVMODEW *)((char *)((mode) + 1) + (mode)->dmDriverExtra))
207 /* Cached display device information */
208 struct display_device
210 WCHAR device_name
[32]; /* DeviceName in DISPLAY_DEVICEW */
211 WCHAR device_string
[128]; /* DeviceString in DISPLAY_DEVICEW */
212 DWORD state_flags
; /* StateFlags in DISPLAY_DEVICEW */
213 WCHAR device_id
[128]; /* DeviceID in DISPLAY_DEVICEW */
214 WCHAR interface_name
[128]; /* DeviceID in DISPLAY_DEVICEW when EDD_GET_DEVICE_INTERFACE_NAME is set */
215 WCHAR device_key
[128]; /* DeviceKey in DISPLAY_DEVICEW */
222 struct display_device dev
;
225 const WCHAR
*config_key
;
226 unsigned int mode_count
;
230 #define MONITOR_INFO_HAS_MONITOR_ID 0x00000001
231 #define MONITOR_INFO_HAS_MONITOR_NAME 0x00000002
232 struct edid_monitor_info
235 /* MONITOR_INFO_HAS_MONITOR_ID */
236 unsigned short manufacturer
, product_code
;
237 char monitor_id_string
[8];
238 /* MONITOR_INFO_HAS_MONITOR_NAME */
239 WCHAR monitor_name
[14];
245 struct display_device dev
;
246 struct adapter
*adapter
;
250 unsigned int output_id
;
254 struct edid_monitor_info edid_info
;
257 static struct list adapters
= LIST_INIT(adapters
);
258 static struct list monitors
= LIST_INIT(monitors
);
259 static INT64 last_query_display_time
;
260 static pthread_mutex_t display_lock
= PTHREAD_MUTEX_INITIALIZER
;
262 BOOL enable_thunk_lock
= FALSE
;
264 #define VIRTUAL_HMONITOR ((HMONITOR)(UINT_PTR)(0x10000 + 1))
265 static struct monitor virtual_monitor
=
267 .handle
= VIRTUAL_HMONITOR
,
268 .flags
= MONITORINFOF_PRIMARY
,
269 .rc_monitor
.right
= 1024,
270 .rc_monitor
.bottom
= 768,
271 .rc_work
.right
= 1024,
272 .rc_work
.bottom
= 768,
273 .dev
.state_flags
= DISPLAY_DEVICE_ACTIVE
| DISPLAY_DEVICE_ATTACHED
,
276 /* the various registry keys that are used to store parameters */
293 static const char *parameter_key_names
[NB_PARAM_KEYS
] =
295 "Control Panel\\Colors",
296 "Control Panel\\Desktop",
297 "Control Panel\\Keyboard",
298 "Control Panel\\Mouse",
299 "Control Panel\\Desktop\\WindowMetrics",
300 "Control Panel\\Sound",
301 "Software\\Microsoft\\Windows NT\\CurrentVersion\\Windows",
302 "Control Panel\\Accessibility\\ShowSounds",
303 "Control Panel\\Accessibility\\Keyboard Preference",
304 "Control Panel\\Accessibility\\Blind Access",
305 "Control Panel\\Accessibility\\AudioDescription",
308 /* System parameters storage */
309 union sysparam_all_entry
;
311 struct sysparam_entry
313 BOOL (*get
)( union sysparam_all_entry
*entry
, UINT int_param
, void *ptr_param
, UINT dpi
);
314 BOOL (*set
)( union sysparam_all_entry
*entry
, UINT int_param
, void *ptr_param
, UINT flags
);
315 BOOL (*init
)( union sysparam_all_entry
*entry
);
316 enum parameter_key base_key
;
318 enum parameter_key mirror_key
;
323 struct sysparam_uint_entry
325 struct sysparam_entry hdr
;
329 struct sysparam_bool_entry
331 struct sysparam_entry hdr
;
335 struct sysparam_dword_entry
337 struct sysparam_entry hdr
;
341 struct sysparam_rgb_entry
343 struct sysparam_entry hdr
;
349 struct sysparam_binary_entry
351 struct sysparam_entry hdr
;
356 struct sysparam_path_entry
358 struct sysparam_entry hdr
;
362 struct sysparam_font_entry
364 struct sysparam_entry hdr
;
367 WCHAR fullname
[LF_FACESIZE
];
370 struct sysparam_pref_entry
372 struct sysparam_entry hdr
;
373 union sysparam_all_entry
*parent
;
378 union sysparam_all_entry
380 struct sysparam_entry hdr
;
381 struct sysparam_uint_entry uint
;
382 struct sysparam_bool_entry
bool;
383 struct sysparam_dword_entry dword
;
384 struct sysparam_rgb_entry rgb
;
385 struct sysparam_binary_entry bin
;
386 struct sysparam_path_entry path
;
387 struct sysparam_font_entry font
;
388 struct sysparam_pref_entry pref
;
391 static UINT system_dpi
;
392 static RECT work_area
;
393 static DWORD process_layout
= ~0u;
395 static HDC display_dc
;
396 static pthread_mutex_t display_dc_lock
= PTHREAD_MUTEX_INITIALIZER
;
398 static pthread_mutex_t user_mutex
;
399 static unsigned int user_lock_thread
, user_lock_rec
;
403 pthread_mutex_lock( &user_mutex
);
404 if (!user_lock_rec
++) user_lock_thread
= GetCurrentThreadId();
407 void user_unlock(void)
409 if (!--user_lock_rec
) user_lock_thread
= 0;
410 pthread_mutex_unlock( &user_mutex
);
413 void user_check_not_lock(void)
415 if (user_lock_thread
== GetCurrentThreadId())
417 ERR( "BUG: holding USER lock\n" );
422 static HANDLE
get_display_device_init_mutex( void )
425 UNICODE_STRING name
= {.Buffer
= bufferW
};
426 OBJECT_ATTRIBUTES attr
;
430 snprintf( buffer
, ARRAY_SIZE(buffer
), "\\Sessions\\%u\\BaseNamedObjects\\display_device_init",
431 (int)NtCurrentTeb()->Peb
->SessionId
);
432 name
.Length
= name
.MaximumLength
= asciiz_to_unicode( bufferW
, buffer
);
434 InitializeObjectAttributes( &attr
, &name
, OBJ_OPENIF
, NULL
, NULL
);
435 if (NtCreateMutant( &mutex
, MUTEX_ALL_ACCESS
, &attr
, FALSE
) < 0) return 0;
436 NtWaitForSingleObject( mutex
, FALSE
, NULL
);
440 static void release_display_device_init_mutex( HANDLE mutex
)
442 NtReleaseMutant( mutex
, NULL
);
446 static struct adapter
*adapter_acquire( struct adapter
*adapter
)
448 InterlockedIncrement( &adapter
->refcount
);
452 static void adapter_release( struct adapter
*adapter
)
454 if (!InterlockedDecrement( &adapter
->refcount
))
456 free( adapter
->modes
);
461 C_ASSERT(sizeof(DEVMODEW
) - offsetof(DEVMODEW
, dmFields
) == 0x94);
463 static void get_monitor_info_from_edid( struct edid_monitor_info
*info
, const unsigned char *edid
, unsigned int edid_len
)
471 if (!edid
|| edid_len
< 128) return;
473 w
= (edid
[8] << 8) | edid
[9]; /* Manufacturer ID, big endian. */
474 for (i
= 0; i
< 3; ++i
)
477 if (!d
|| d
- 1 > 'Z' - 'A') return;
478 info
->monitor_id_string
[2 - i
] = 'A' + d
- 1;
482 w
= edid
[10] | (edid
[11] << 8); /* Product code, little endian. */
483 info
->manufacturer
= *(unsigned short *)(edid
+ 8);
484 info
->product_code
= w
;
485 sprintf( info
->monitor_id_string
+ 3, "%04X", w
);
486 info
->flags
= MONITOR_INFO_HAS_MONITOR_ID
;
487 TRACE( "Monitor id %s.\n", info
->monitor_id_string
);
489 for (i
= 0; i
< 4; ++i
)
491 if (edid
[54 + i
* 18 + 3] != 0xfc) continue;
492 /* "Display name" ASCII descriptor. */
493 s
= (const char *)&edid
[54 + i
* 18 + 5];
494 for (j
= 0; s
[j
] && j
< 13; ++j
)
495 info
->monitor_name
[j
] = s
[j
];
496 while (j
&& isspace(s
[j
- 1])) --j
;
497 info
->monitor_name
[j
] = 0;
498 info
->flags
|= MONITOR_INFO_HAS_MONITOR_NAME
;
503 static BOOL
write_adapter_mode( HKEY adapter_key
, UINT index
, const DEVMODEW
*mode
)
505 WCHAR bufferW
[MAX_PATH
] = {0};
506 char buffer
[MAX_PATH
];
508 sprintf( buffer
, "Modes\\%08X", index
);
509 asciiz_to_unicode( bufferW
, buffer
);
510 return set_reg_value( adapter_key
, bufferW
, REG_BINARY
, &mode
->dmFields
, sizeof(*mode
) - offsetof(DEVMODEW
, dmFields
) );
513 static BOOL
read_adapter_mode( HKEY adapter_key
, UINT index
, DEVMODEW
*mode
)
515 char value_buf
[offsetof(KEY_VALUE_PARTIAL_INFORMATION
, Data
[sizeof(*mode
)])];
516 KEY_VALUE_PARTIAL_INFORMATION
*value
= (void *)value_buf
;
517 WCHAR bufferW
[MAX_PATH
] = {0};
518 char buffer
[MAX_PATH
];
520 sprintf( buffer
, "Modes\\%08X", index
);
521 asciiz_to_unicode( bufferW
, buffer
);
522 if (!query_reg_value( adapter_key
, bufferW
, value
, sizeof(value_buf
) )) return FALSE
;
524 memcpy( &mode
->dmFields
, value
->Data
, sizeof(*mode
) - offsetof(DEVMODEW
, dmFields
) );
528 static BOOL
adapter_get_registry_settings( const struct adapter
*adapter
, DEVMODEW
*mode
)
534 mutex
= get_display_device_init_mutex();
536 if (!config_key
&& !(config_key
= reg_open_key( NULL
, config_keyW
, sizeof(config_keyW
) ))) ret
= FALSE
;
537 else if (!(hkey
= reg_open_key( config_key
, adapter
->config_key
, lstrlenW( adapter
->config_key
) * sizeof(WCHAR
) ))) ret
= FALSE
;
540 ret
= read_adapter_mode( hkey
, ENUM_REGISTRY_SETTINGS
, mode
);
544 release_display_device_init_mutex( mutex
);
548 static BOOL
adapter_set_registry_settings( const struct adapter
*adapter
, const DEVMODEW
*mode
)
554 mutex
= get_display_device_init_mutex();
556 if (!config_key
&& !(config_key
= reg_open_key( NULL
, config_keyW
, sizeof(config_keyW
) ))) ret
= FALSE
;
557 if (!(hkey
= reg_open_key( config_key
, adapter
->config_key
, lstrlenW( adapter
->config_key
) * sizeof(WCHAR
) ))) ret
= FALSE
;
560 ret
= write_adapter_mode( hkey
, ENUM_REGISTRY_SETTINGS
, mode
);
564 release_display_device_init_mutex( mutex
);
568 static BOOL
adapter_get_current_settings( const struct adapter
*adapter
, DEVMODEW
*mode
)
570 BOOL is_primary
= !!(adapter
->dev
.state_flags
& DISPLAY_DEVICE_PRIMARY_DEVICE
);
575 if ((ret
= user_driver
->pGetCurrentDisplaySettings( adapter
->dev
.device_name
, is_primary
, mode
))) return TRUE
;
577 /* default implementation: read current display settings from the registry. */
579 mutex
= get_display_device_init_mutex();
581 if (!config_key
&& !(config_key
= reg_open_key( NULL
, config_keyW
, sizeof(config_keyW
) ))) ret
= FALSE
;
582 else if (!(hkey
= reg_open_key( config_key
, adapter
->config_key
, lstrlenW( adapter
->config_key
) * sizeof(WCHAR
) ))) ret
= FALSE
;
585 ret
= read_adapter_mode( hkey
, ENUM_CURRENT_SETTINGS
, mode
);
589 release_display_device_init_mutex( mutex
);
593 static BOOL
adapter_set_current_settings( const struct adapter
*adapter
, const DEVMODEW
*mode
)
599 mutex
= get_display_device_init_mutex();
601 if (!config_key
&& !(config_key
= reg_open_key( NULL
, config_keyW
, sizeof(config_keyW
) ))) ret
= FALSE
;
602 if (!(hkey
= reg_open_key( config_key
, adapter
->config_key
, lstrlenW( adapter
->config_key
) * sizeof(WCHAR
) ))) ret
= FALSE
;
605 ret
= write_adapter_mode( hkey
, ENUM_CURRENT_SETTINGS
, mode
);
609 release_display_device_init_mutex( mutex
);
613 static int mode_compare(const void *p1
, const void *p2
)
615 BOOL a_interlaced
, b_interlaced
, a_stretched
, b_stretched
;
616 DWORD a_width
, a_height
, b_width
, b_height
;
617 const DEVMODEW
*a
= p1
, *b
= p2
;
620 /* Depth in descending order */
621 if ((ret
= b
->dmBitsPerPel
- a
->dmBitsPerPel
)) return ret
;
623 /* Use the width and height in landscape mode for comparison */
624 if (a
->dmDisplayOrientation
== DMDO_DEFAULT
|| a
->dmDisplayOrientation
== DMDO_180
)
626 a_width
= a
->dmPelsWidth
;
627 a_height
= a
->dmPelsHeight
;
631 a_width
= a
->dmPelsHeight
;
632 a_height
= a
->dmPelsWidth
;
635 if (b
->dmDisplayOrientation
== DMDO_DEFAULT
|| b
->dmDisplayOrientation
== DMDO_180
)
637 b_width
= b
->dmPelsWidth
;
638 b_height
= b
->dmPelsHeight
;
642 b_width
= b
->dmPelsHeight
;
643 b_height
= b
->dmPelsWidth
;
646 /* Width in ascending order */
647 if ((ret
= a_width
- b_width
)) return ret
;
649 /* Height in ascending order */
650 if ((ret
= a_height
- b_height
)) return ret
;
652 /* Frequency in descending order */
653 if ((ret
= b
->dmDisplayFrequency
- a
->dmDisplayFrequency
)) return ret
;
655 /* Orientation in ascending order */
656 if ((ret
= a
->dmDisplayOrientation
- b
->dmDisplayOrientation
)) return ret
;
658 if (!(a
->dmFields
& DM_DISPLAYFLAGS
)) a_interlaced
= FALSE
;
659 else a_interlaced
= !!(a
->dmDisplayFlags
& DM_INTERLACED
);
660 if (!(b
->dmFields
& DM_DISPLAYFLAGS
)) b_interlaced
= FALSE
;
661 else b_interlaced
= !!(b
->dmDisplayFlags
& DM_INTERLACED
);
663 /* Interlaced in ascending order */
664 if ((ret
= a_interlaced
- b_interlaced
)) return ret
;
666 if (!(a
->dmFields
& DM_DISPLAYFIXEDOUTPUT
)) a_stretched
= FALSE
;
667 else a_stretched
= a
->dmDisplayFixedOutput
== DMDFO_STRETCH
;
668 if (!(b
->dmFields
& DM_DISPLAYFIXEDOUTPUT
)) b_stretched
= FALSE
;
669 else b_stretched
= b
->dmDisplayFixedOutput
== DMDFO_STRETCH
;
671 /* Stretched in ascending order */
672 if ((ret
= a_stretched
- b_stretched
)) return ret
;
677 static unsigned int query_reg_subkey_value( HKEY hkey
, const WCHAR
*name
, unsigned int name_size
,
678 KEY_VALUE_PARTIAL_INFORMATION
*value
, unsigned int size
)
682 if (!(subkey
= reg_open_key( hkey
, name
, name_size
))) return 0;
683 size
= query_reg_value( subkey
, NULL
, value
, size
);
688 static BOOL
read_display_adapter_settings( unsigned int index
, struct adapter
*info
)
691 KEY_VALUE_PARTIAL_INFORMATION
*value
= (void *)buffer
;
692 WCHAR
*value_str
= (WCHAR
*)value
->Data
;
697 if (!enum_key
&& !(enum_key
= reg_open_key( NULL
, enum_keyW
, sizeof(enum_keyW
) )))
701 sprintf( buffer
, "\\Device\\Video%d", index
);
702 size
= query_reg_ascii_value( video_key
, buffer
, value
, sizeof(buffer
) );
703 if (!size
|| value
->Type
!= REG_SZ
||
704 value
->DataLength
<= sizeof("\\Registry\\Machine\\") * sizeof(WCHAR
))
708 memcpy( info
->dev
.device_key
, value_str
, value
->DataLength
);
709 info
->config_key
= info
->dev
.device_key
+ sizeof("\\Registry\\Machine\\") - 1;
711 if (!(hkey
= reg_open_key( NULL
, value_str
, value
->DataLength
- sizeof(WCHAR
) )))
715 if (query_reg_value( hkey
, driver_descW
, value
, sizeof(buffer
) ) && value
->Type
== REG_SZ
)
716 memcpy( info
->dev
.device_string
, value_str
, value
->DataLength
);
720 sprintf( buffer
, "\\\\.\\DISPLAY%d", index
+ 1 );
721 asciiz_to_unicode( info
->dev
.device_name
, buffer
);
723 if (!(hkey
= reg_open_key( config_key
, info
->config_key
,
724 lstrlenW( info
->config_key
) * sizeof(WCHAR
) )))
728 if (query_reg_value( hkey
, state_flagsW
, value
, sizeof(buffer
) ) && value
->Type
== REG_DWORD
)
729 info
->dev
.state_flags
= *(const DWORD
*)value
->Data
;
732 info
->dev
.interface_name
[0] = 0;
735 if (query_reg_value( hkey
, mode_countW
, value
, sizeof(buffer
) ) && value
->Type
== REG_DWORD
)
736 info
->mode_count
= *(const DWORD
*)value
->Data
;
738 /* Modes, allocate an extra mode for easier iteration */
739 if ((info
->modes
= calloc( info
->mode_count
+ 1, sizeof(DEVMODEW
) )))
741 for (i
= 0, mode
= info
->modes
; i
< info
->mode_count
; i
++)
743 mode
->dmSize
= offsetof(DEVMODEW
, dmICMMethod
);
744 if (!read_adapter_mode( hkey
, i
, mode
)) break;
745 mode
= NEXT_DEVMODEW(mode
);
747 info
->mode_count
= i
;
749 qsort(info
->modes
, info
->mode_count
, sizeof(*info
->modes
) + info
->modes
->dmDriverExtra
, mode_compare
);
753 size
= query_reg_value( hkey
, gpu_idW
, value
, sizeof(buffer
) );
755 if (!size
|| value
->Type
!= REG_SZ
|| !info
->mode_count
|| !info
->modes
) return FALSE
;
757 if (!(hkey
= reg_open_key( enum_key
, value_str
, value
->DataLength
- sizeof(WCHAR
) )))
760 size
= query_reg_subkey_value( hkey
, devpropkey_gpu_luidW
, sizeof(devpropkey_gpu_luidW
), value
, sizeof(buffer
) );
761 if (size
!= sizeof(info
->gpu_luid
))
766 memcpy( &info
->gpu_luid
, value
->Data
, sizeof(info
->gpu_luid
) );
768 size
= query_reg_value( hkey
, hardware_idW
, value
, sizeof(buffer
) );
770 if (!size
|| (value
->Type
!= REG_SZ
&& value
->Type
!= REG_MULTI_SZ
))
773 lstrcpyW( info
->dev
.device_id
, value_str
);
777 static BOOL
read_monitor_settings( struct adapter
*adapter
, UINT index
, struct monitor
*monitor
)
780 KEY_VALUE_PARTIAL_INFORMATION
*value
= (void *)buffer
;
781 WCHAR
*device_name
, *value_str
= (WCHAR
*)value
->Data
, *ptr
;
785 monitor
->flags
= adapter
->id
? 0 : MONITORINFOF_PRIMARY
;
788 sprintf( buffer
, "\\\\.\\DISPLAY%d\\Monitor%d", adapter
->id
+ 1, index
);
789 asciiz_to_unicode( monitor
->dev
.device_name
, buffer
);
791 if (!(hkey
= reg_open_key( config_key
, adapter
->config_key
,
792 lstrlenW( adapter
->config_key
) * sizeof(WCHAR
) )))
796 sprintf( buffer
, "MonitorID%u", index
);
797 size
= query_reg_ascii_value( hkey
, buffer
, value
, sizeof(buffer
) );
799 if (!size
|| value
->Type
!= REG_SZ
) return FALSE
;
800 len
= asciiz_to_unicode( monitor
->dev
.interface_name
, "\\\\\?\\" ) / sizeof(WCHAR
) - 1;
801 memcpy( monitor
->dev
.interface_name
+ len
, value_str
, value
->DataLength
- sizeof(WCHAR
) );
802 len
+= value
->DataLength
/ sizeof(WCHAR
) - 1;
803 monitor
->dev
.interface_name
[len
++] = '#';
804 memcpy( monitor
->dev
.interface_name
+ len
, guid_devinterface_monitorW
,
805 sizeof(guid_devinterface_monitorW
) );
807 /* Replace '\\' with '#' after prefix */
808 for (ptr
= monitor
->dev
.interface_name
+ ARRAYSIZE("\\\\\?\\") - 1; *ptr
; ptr
++)
809 if (*ptr
== '\\') *ptr
= '#';
811 if (!(hkey
= reg_open_key( enum_key
, value_str
, value
->DataLength
- sizeof(WCHAR
) )))
814 /* StateFlags, WINE_DEVPROPKEY_MONITOR_STATEFLAGS */
815 size
= query_reg_subkey_value( hkey
, wine_devpropkey_monitor_stateflagsW
,
816 sizeof(wine_devpropkey_monitor_stateflagsW
),
817 value
, sizeof(buffer
) );
818 if (size
!= sizeof(monitor
->dev
.state_flags
))
823 monitor
->dev
.state_flags
= *(const DWORD
*)value
->Data
;
826 size
= query_reg_subkey_value( hkey
, devpropkey_monitor_output_idW
,
827 sizeof(devpropkey_monitor_output_idW
),
828 value
, sizeof(buffer
) );
829 if (size
!= sizeof(monitor
->output_id
))
834 monitor
->output_id
= *(const unsigned int *)value
->Data
;
836 /* rc_monitor, WINE_DEVPROPKEY_MONITOR_RCMONITOR */
837 size
= query_reg_subkey_value( hkey
, wine_devpropkey_monitor_rcmonitorW
,
838 sizeof(wine_devpropkey_monitor_rcmonitorW
),
839 value
, sizeof(buffer
) );
840 if (size
!= sizeof(monitor
->rc_monitor
))
845 monitor
->rc_monitor
= *(const RECT
*)value
->Data
;
847 /* rc_work, WINE_DEVPROPKEY_MONITOR_RCWORK */
848 size
= query_reg_subkey_value( hkey
, wine_devpropkey_monitor_rcworkW
,
849 sizeof(wine_devpropkey_monitor_rcworkW
),
850 value
, sizeof(buffer
) );
851 if (size
!= sizeof(monitor
->rc_work
))
856 monitor
->rc_work
= *(const RECT
*)value
->Data
;
859 if (!query_reg_value( hkey
, device_descW
, value
, sizeof(buffer
) ) || value
->Type
!= REG_SZ
)
864 memcpy( monitor
->dev
.device_string
, value
->Data
, value
->DataLength
);
867 if (!query_reg_value( hkey
, driverW
, value
, sizeof(buffer
) ) || value
->Type
!= REG_SZ
)
872 size
= asciiz_to_unicode( monitor
->dev
.device_key
,
873 "\\Registry\\Machine\\System\\CurrentControlSet\\Control\\Class\\" );
874 device_name
= &monitor
->dev
.device_key
[size
/ sizeof(WCHAR
) - 1];
875 memcpy( device_name
, value_str
, value
->DataLength
);
878 if (!query_reg_value( hkey
, hardware_idW
, value
, sizeof(buffer
) ) ||
879 (value
->Type
!= REG_SZ
&& value
->Type
!= REG_MULTI_SZ
))
884 size
= lstrlenW( value_str
);
885 memcpy( monitor
->dev
.device_id
, value_str
, size
* sizeof(WCHAR
) );
886 monitor
->dev
.device_id
[size
++] = '\\';
887 lstrcpyW( monitor
->dev
.device_id
+ size
, device_name
);
890 if ((subkey
= reg_open_key( hkey
, device_parametersW
, sizeof(device_parametersW
) )))
892 if (query_reg_value( subkey
, edidW
, value
, sizeof(buffer
) ))
893 get_monitor_info_from_edid( &monitor
->edid_info
, value
->Data
, value
->DataLength
);
901 static void reg_empty_key( HKEY root
, const char *key_name
)
904 KEY_NODE_INFORMATION
*key
= (KEY_NODE_INFORMATION
*)buffer
;
905 KEY_VALUE_FULL_INFORMATION
*value
= (KEY_VALUE_FULL_INFORMATION
*)buffer
;
911 hkey
= reg_open_key( root
, bufferW
, asciiz_to_unicode( bufferW
, key_name
) - sizeof(WCHAR
) );
915 while (!NtEnumerateKey( hkey
, 0, KeyNodeInformation
, key
, sizeof(buffer
), &size
))
916 reg_delete_tree( hkey
, key
->Name
, key
->NameLength
);
918 while (!NtEnumerateValueKey( hkey
, 0, KeyValueFullInformation
, value
, sizeof(buffer
), &size
))
920 UNICODE_STRING name
= { value
->NameLength
, value
->NameLength
, value
->Name
};
921 NtDeleteValueKey( hkey
, &name
);
924 if (hkey
!= root
) NtClose( hkey
);
927 static void prepare_devices(void)
930 KEY_NODE_INFORMATION
*key
= (void *)buffer
;
931 KEY_VALUE_PARTIAL_INFORMATION
*value
= (void *)buffer
;
932 WCHAR
*value_str
= (WCHAR
*)value
->Data
;
936 HKEY hkey
, subkey
, device_key
, prop_key
;
938 if (!enum_key
) enum_key
= reg_create_key( NULL
, enum_keyW
, sizeof(enum_keyW
), 0, NULL
);
939 if (!control_key
) control_key
= reg_create_key( NULL
, control_keyW
, sizeof(control_keyW
), 0, NULL
);
940 if (!video_key
) video_key
= reg_create_key( NULL
, devicemap_video_keyW
, sizeof(devicemap_video_keyW
),
941 REG_OPTION_VOLATILE
, NULL
);
943 /* delete monitors */
944 reg_empty_key( enum_key
, "DISPLAY" );
945 sprintf( buffer
, "Class\\%s", guid_devclass_monitorA
);
946 hkey
= reg_create_key( control_key
, bufferW
, asciiz_to_unicode( bufferW
, buffer
) - sizeof(WCHAR
),
948 reg_empty_key( hkey
, NULL
);
949 set_reg_value( hkey
, classW
, REG_SZ
, monitorW
, sizeof(monitorW
) );
952 /* delete adapters */
953 reg_empty_key( video_key
, NULL
);
956 sprintf( buffer
, "Class\\%s", guid_devclass_displayA
);
957 hkey
= reg_create_key( control_key
, bufferW
, asciiz_to_unicode( bufferW
, buffer
) - sizeof(WCHAR
),
959 reg_empty_key( hkey
, NULL
);
960 set_reg_value( hkey
, classW
, REG_SZ
, displayW
, sizeof(displayW
) );
963 hkey
= reg_open_key( enum_key
, pciW
, sizeof(pciW
) );
965 /* To preserve GPU GUIDs, mark them as not present and delete them in cleanup_devices if needed. */
966 while (!NtEnumerateKey( hkey
, i
++, KeyNodeInformation
, key
, sizeof(buffer
), &size
))
970 if (!(subkey
= reg_open_key( hkey
, key
->Name
, key
->NameLength
))) continue;
972 while (!NtEnumerateKey( subkey
, j
++, KeyNodeInformation
, key
, sizeof(buffer
), &size
))
974 if (!(device_key
= reg_open_key( subkey
, key
->Name
, key
->NameLength
))) continue;
975 size
= query_reg_value( device_key
, class_guidW
, value
, sizeof(buffer
) );
976 if (size
!= sizeof(guid_devclass_displayW
) || wcscmp( value_str
, guid_devclass_displayW
))
978 NtClose( device_key
);
982 size
= query_reg_value( device_key
, class_guidW
, value
, sizeof(buffer
) );
983 if (size
== sizeof(guid_devclass_displayW
) &&
984 !wcscmp( (const WCHAR
*)value
->Data
, guid_devclass_displayW
) &&
985 (prop_key
= reg_create_key( device_key
, devpropkey_device_ispresentW
,
986 sizeof(devpropkey_device_ispresentW
), 0, NULL
)))
988 BOOL present
= FALSE
;
989 set_reg_value( prop_key
, NULL
, 0xffff0000 | DEVPROP_TYPE_BOOLEAN
,
990 &present
, sizeof(present
) );
994 NtClose( device_key
);
1003 static void cleanup_devices(void)
1006 KEY_NODE_INFORMATION
*key
= (void *)buffer
;
1007 KEY_VALUE_PARTIAL_INFORMATION
*value
= (void *)buffer
;
1008 WCHAR bufferW
[512], *value_str
= (WCHAR
*)value
->Data
;
1011 HKEY hkey
, subkey
, device_key
, prop_key
;
1013 hkey
= reg_open_key( enum_key
, pciW
, sizeof(pciW
) );
1015 while (!NtEnumerateKey( hkey
, i
++, KeyNodeInformation
, key
, sizeof(buffer
), &size
))
1019 if (!(subkey
= reg_open_key( hkey
, key
->Name
, key
->NameLength
))) continue;
1021 while (!NtEnumerateKey( subkey
, j
++, KeyNodeInformation
, key
, sizeof(buffer
), &size
))
1023 BOOL present
= FALSE
;
1025 if (!(device_key
= reg_open_key( subkey
, key
->Name
, key
->NameLength
))) continue;
1026 memcpy( bufferW
, key
->Name
, key
->NameLength
);
1027 bufferW
[key
->NameLength
/ sizeof(WCHAR
)] = 0;
1029 size
= query_reg_value( device_key
, class_guidW
, value
, sizeof(buffer
) );
1030 if (size
!= sizeof(guid_devclass_displayW
) || wcscmp( value_str
, guid_devclass_displayW
))
1032 NtClose( device_key
);
1036 if ((prop_key
= reg_open_key( device_key
, devpropkey_device_ispresentW
,
1037 sizeof(devpropkey_device_ispresentW
) )))
1039 if (query_reg_value( prop_key
, NULL
, value
, sizeof(buffer
) ) == sizeof(BOOL
))
1040 present
= *(const BOOL
*)value
->Data
;
1041 NtClose( prop_key
);
1044 NtClose( device_key
);
1046 if (!present
&& reg_delete_tree( subkey
, bufferW
, lstrlenW( bufferW
) * sizeof(WCHAR
) ))
1056 /* see UuidCreate */
1057 static void uuid_create( GUID
*uuid
)
1060 NtQuerySystemInformation( SystemInterruptInformation
, buf
, sizeof(buf
), NULL
);
1061 memcpy( uuid
, buf
, sizeof(*uuid
) );
1062 uuid
->Data3
&= 0x0fff;
1063 uuid
->Data3
|= (4 << 12);
1064 uuid
->Data4
[0] &= 0x3f;
1065 uuid
->Data4
[0] |= 0x80;
1068 #define TICKSPERSEC 10000000
1069 #define SECSPERDAY 86400
1070 #define DAYSPERQUADRICENTENNIUM (365 * 400 + 97)
1071 #define DAYSPERNORMALQUADRENNIUM (365 * 4 + 1)
1073 static unsigned int format_date( WCHAR
*bufferW
, LONGLONG time
)
1075 int cleaps
, years
, yearday
, months
, days
;
1076 unsigned int day
, month
, year
;
1079 days
= time
/ TICKSPERSEC
/ SECSPERDAY
;
1081 /* compute year, month and day of month, see RtlTimeToTimeFields */
1082 cleaps
= (3 * ((4 * days
+ 1227) / DAYSPERQUADRICENTENNIUM
) + 3) / 4;
1083 days
+= 28188 + cleaps
;
1084 years
= (20 * days
- 2442) / (5 * DAYSPERNORMALQUADRENNIUM
);
1085 yearday
= days
- (years
* DAYSPERNORMALQUADRENNIUM
) / 4;
1086 months
= (64 * yearday
) / 1959;
1090 year
= years
+ 1524;
1094 month
= months
- 13;
1095 year
= years
+ 1525;
1097 day
= yearday
- (1959 * months
) / 64 ;
1099 sprintf( buffer
, "%u-%u-%u", month
, day
, year
);
1100 return asciiz_to_unicode( bufferW
, buffer
);
1103 struct device_manager_ctx
1105 unsigned int gpu_count
;
1106 unsigned int adapter_count
;
1107 unsigned int video_count
;
1108 unsigned int monitor_count
;
1109 unsigned int output_count
;
1110 unsigned int mode_count
;
1118 static void link_device( const WCHAR
*instance
, const WCHAR
*class )
1120 unsigned int instance_len
= lstrlenW( instance
), len
;
1121 unsigned int class_len
= lstrlenW( class );
1122 WCHAR buffer
[MAX_PATH
], *ptr
;
1125 static const WCHAR symbolic_linkW
[] = {'S','y','m','b','o','l','i','c','L','i','n','k',0};
1126 static const WCHAR hashW
[] = {'#'};
1128 len
= asciiz_to_unicode( buffer
, "DeviceClasses\\" ) / sizeof(WCHAR
) - 1;
1129 memcpy( buffer
+ len
, class, class_len
* sizeof(WCHAR
) );
1131 len
+= asciiz_to_unicode( buffer
+ len
, "\\##?#" ) / sizeof(WCHAR
) - 1;
1132 memcpy( buffer
+ len
, instance
, instance_len
* sizeof(WCHAR
) );
1133 for (ptr
= buffer
+ len
; *ptr
; ptr
++) if (*ptr
== '\\') *ptr
= '#';
1134 len
+= instance_len
;
1135 buffer
[len
++] = '#';
1136 memcpy( buffer
+ len
, class, class_len
* sizeof(WCHAR
) );
1138 hkey
= reg_create_key( control_key
, buffer
, len
* sizeof(WCHAR
), 0, NULL
);
1140 set_reg_value( hkey
, device_instanceW
, REG_SZ
, instance
, (instance_len
+ 1) * sizeof(WCHAR
) );
1142 subkey
= reg_create_key( hkey
, hashW
, sizeof(hashW
), REG_OPTION_VOLATILE
, NULL
);
1146 len
= asciiz_to_unicode( buffer
, "\\\\?\\" ) / sizeof(WCHAR
) - 1;
1147 memcpy( buffer
+ len
, instance
, (instance_len
+ 1) * sizeof(WCHAR
) );
1148 len
+= instance_len
;
1149 memcpy( buffer
+ len
, class, (class_len
+ 1) * sizeof(WCHAR
) );
1150 len
+= class_len
+ 1;
1151 for (ptr
= buffer
+ 4; *ptr
; ptr
++) if (*ptr
== '\\') *ptr
= '#';
1152 set_reg_value( hkey
, symbolic_linkW
, REG_SZ
, buffer
, len
* sizeof(WCHAR
) );
1154 if ((subkey
= reg_create_key( hkey
, controlW
, sizeof(controlW
), REG_OPTION_VOLATILE
, NULL
)))
1156 const DWORD linked
= 1;
1157 set_reg_value( subkey
, linkedW
, REG_DWORD
, &linked
, sizeof(linked
) );
1162 static void add_gpu( const struct gdi_gpu
*gpu
, void *param
)
1164 struct device_manager_ctx
*ctx
= param
;
1168 KEY_VALUE_PARTIAL_INFORMATION
*value
= (void *)buffer
;
1169 unsigned int gpu_index
, size
;
1173 static const BOOL present
= TRUE
;
1174 static const WCHAR wine_adapterW
[] = {'W','i','n','e',' ','A','d','a','p','t','e','r',0};
1175 static const WCHAR video_idW
[] = {'V','i','d','e','o','I','D',0};
1176 static const WCHAR driver_date_dataW
[] =
1177 {'D','r','i','v','e','r','D','a','t','e','D','a','t','a',0};
1178 static const WCHAR adapter_stringW
[] =
1179 {'H','a','r','d','w','a','r','e','I','n','f','o','r','m','a','t','i','o','n',
1180 '.','A','d','a','p','t','e','r','S','t','r','i','n','g',0};
1181 static const WCHAR bios_stringW
[] =
1182 {'H','a','r','d','w','a','r','e','I','n','f','o','r','m','a','t','i','o','n','.',
1183 'B','i','o','s','S','t','r','i','n','g',0};
1184 static const WCHAR chip_typeW
[] =
1185 {'H','a','r','d','w','a','r','e','I','n','f','o','r','m','a','t','i','o','n','.',
1186 'C','h','i','p','T','y','p','e',0};
1187 static const WCHAR dac_typeW
[] =
1188 {'H','a','r','d','w','a','r','e','I','n','f','o','r','m','a','t','i','o','n','.',
1189 'D','a','c','T','y','p','e',0};
1190 static const WCHAR ramdacW
[] =
1191 {'I','n','t','e','r','g','r','a','t','e','d',' ','R','A','M','D','A','C',0};
1192 static const WCHAR driver_dateW
[] = {'D','r','i','v','e','r','D','a','t','e',0};
1194 TRACE( "%s %04X %04X %08X %02X\n", debugstr_w(gpu
->name
),
1195 gpu
->vendor_id
, gpu
->device_id
, gpu
->subsys_id
, gpu
->revision_id
);
1197 gpu_index
= ctx
->gpu_count
++;
1198 ctx
->adapter_count
= 0;
1199 ctx
->monitor_count
= 0;
1200 ctx
->mode_count
= 0;
1202 if (!enum_key
&& !(enum_key
= reg_create_key( NULL
, enum_keyW
, sizeof(enum_keyW
), 0, NULL
)))
1207 ctx
->mutex
= get_display_device_init_mutex();
1208 pthread_mutex_lock( &display_lock
);
1212 sprintf( buffer
, "PCI\\VEN_%04X&DEV_%04X&SUBSYS_%08X&REV_%02X\\%08X",
1213 gpu
->vendor_id
, gpu
->device_id
, gpu
->subsys_id
, gpu
->revision_id
, gpu_index
);
1214 size
= asciiz_to_unicode( ctx
->gpuid
, buffer
);
1215 if (!(hkey
= reg_create_key( enum_key
, ctx
->gpuid
, size
- sizeof(WCHAR
), 0, NULL
))) return;
1217 set_reg_value( hkey
, classW
, REG_SZ
, displayW
, sizeof(displayW
) );
1218 set_reg_value( hkey
, class_guidW
, REG_SZ
, guid_devclass_displayW
,
1219 sizeof(guid_devclass_displayW
) );
1220 sprintf( buffer
, "%s\\%04X", guid_devclass_displayA
, gpu_index
);
1221 set_reg_value( hkey
, driverW
, REG_SZ
, bufferW
, asciiz_to_unicode( bufferW
, buffer
));
1223 sprintf( buffer
, "PCI\\VEN_%04X&DEV_%04X&SUBSYS_%08X&REV_%02X",
1224 gpu
->vendor_id
, gpu
->device_id
, gpu
->subsys_id
, gpu
->revision_id
);
1225 size
= asciiz_to_unicode( bufferW
, buffer
);
1226 bufferW
[size
/ sizeof(WCHAR
)] = 0; /* for REG_MULTI_SZ */
1227 set_reg_value( hkey
, hardware_idW
, REG_MULTI_SZ
, bufferW
, size
+ sizeof(WCHAR
) );
1229 if ((subkey
= reg_create_key( hkey
, devpkey_device_matching_device_id
,
1230 sizeof(devpkey_device_matching_device_id
), 0, NULL
)))
1232 if (gpu
->vendor_id
&& gpu
->device_id
)
1233 set_reg_value( subkey
, NULL
, 0xffff0000 | DEVPROP_TYPE_STRING
, bufferW
, size
);
1235 set_reg_value( subkey
, NULL
, 0xffff0000 | DEVPROP_TYPE_STRING
, bufferW
,
1236 asciiz_to_unicode( bufferW
, "ROOT\\BasicRender" ));
1241 if (!desc
[0]) desc
= wine_adapterW
;
1242 set_reg_value( hkey
, device_descW
, REG_SZ
, desc
, (lstrlenW( desc
) + 1) * sizeof(WCHAR
) );
1244 if ((subkey
= reg_create_key( hkey
, device_parametersW
, sizeof(device_parametersW
), 0, NULL
)))
1246 if (!query_reg_value( subkey
, video_idW
, value
, sizeof(buffer
) ))
1249 uuid_create( &guid
);
1250 sprintf( buffer
, "{%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x}",
1251 (unsigned int)guid
.Data1
, guid
.Data2
, guid
.Data3
, guid
.Data4
[0], guid
.Data4
[1], guid
.Data4
[2],
1252 guid
.Data4
[3], guid
.Data4
[4], guid
.Data4
[5], guid
.Data4
[6], guid
.Data4
[7] );
1253 size
= asciiz_to_unicode( ctx
->gpu_guid
, buffer
);
1254 TRACE( "created guid %s\n", debugstr_w(ctx
->gpu_guid
) );
1255 set_reg_value( subkey
, video_idW
, REG_SZ
, ctx
->gpu_guid
, size
);
1259 memcpy( ctx
->gpu_guid
, value
->Data
, value
->DataLength
);
1260 TRACE( "got guid %s\n", debugstr_w(ctx
->gpu_guid
) );
1265 if ((subkey
= reg_create_key( hkey
, devpropkey_gpu_vulkan_uuidW
,
1266 sizeof(devpropkey_gpu_vulkan_uuidW
), 0, NULL
)))
1268 set_reg_value( subkey
, NULL
, 0xffff0000 | DEVPROP_TYPE_GUID
,
1269 &gpu
->vulkan_uuid
, sizeof(gpu
->vulkan_uuid
) );
1273 if ((subkey
= reg_create_key( hkey
, devpropkey_device_ispresentW
,
1274 sizeof(devpropkey_device_ispresentW
), 0, NULL
)))
1276 set_reg_value( subkey
, NULL
, 0xffff0000 | DEVPROP_TYPE_BOOLEAN
,
1277 &present
, sizeof(present
) );
1281 if ((subkey
= reg_create_key( hkey
, devpropkey_gpu_luidW
, sizeof(devpropkey_gpu_luidW
), 0, NULL
)))
1283 if (query_reg_value( subkey
, NULL
, value
, sizeof(buffer
) ) != sizeof(LUID
))
1285 NtAllocateLocallyUniqueId( &ctx
->gpu_luid
);
1286 TRACE("allocated luid %08x%08x\n", (int)ctx
->gpu_luid
.HighPart
, (int)ctx
->gpu_luid
.LowPart
);
1287 set_reg_value( subkey
, NULL
, 0xffff0000 | DEVPROP_TYPE_UINT64
,
1288 &ctx
->gpu_luid
, sizeof(ctx
->gpu_luid
) );
1292 memcpy( &ctx
->gpu_luid
, value
->Data
, sizeof(ctx
->gpu_luid
) );
1293 TRACE("got luid %08x%08x\n", (int)ctx
->gpu_luid
.HighPart
, (int)ctx
->gpu_luid
.LowPart
);
1300 sprintf( buffer
, "Class\\%s\\%04X", guid_devclass_displayA
, gpu_index
);
1301 hkey
= reg_create_key( control_key
, bufferW
,
1302 asciiz_to_unicode( bufferW
, buffer
) - sizeof(WCHAR
), 0, NULL
);
1304 NtQuerySystemTime( &ft
);
1305 set_reg_value( hkey
, driver_dateW
, REG_SZ
, bufferW
, format_date( bufferW
, ft
.QuadPart
));
1307 set_reg_value( hkey
, driver_date_dataW
, REG_BINARY
, &ft
, sizeof(ft
) );
1309 size
= (lstrlenW( desc
) + 1) * sizeof(WCHAR
);
1310 set_reg_value( hkey
, driver_descW
, REG_SZ
, desc
, size
);
1311 set_reg_value( hkey
, adapter_stringW
, REG_BINARY
, desc
, size
);
1312 set_reg_value( hkey
, bios_stringW
, REG_BINARY
, desc
, size
);
1313 set_reg_value( hkey
, chip_typeW
, REG_BINARY
, desc
, size
);
1314 set_reg_value( hkey
, dac_typeW
, REG_BINARY
, ramdacW
, sizeof(ramdacW
) );
1318 link_device( ctx
->gpuid
, guid_devinterface_display_adapterW
);
1319 link_device( ctx
->gpuid
, guid_display_device_arrivalW
);
1322 static void add_adapter( const struct gdi_adapter
*adapter
, void *param
)
1324 struct device_manager_ctx
*ctx
= param
;
1325 unsigned int adapter_index
, video_index
, len
;
1326 char name
[64], buffer
[MAX_PATH
];
1327 WCHAR nameW
[64], bufferW
[MAX_PATH
];
1332 if (ctx
->adapter_key
)
1334 NtClose( ctx
->adapter_key
);
1335 ctx
->adapter_key
= NULL
;
1338 adapter_index
= ctx
->adapter_count
++;
1339 video_index
= ctx
->video_count
++;
1340 ctx
->monitor_count
= 0;
1341 ctx
->mode_count
= 0;
1343 len
= asciiz_to_unicode( bufferW
, "\\Registry\\Machine\\System\\CurrentControlSet\\"
1344 "Control\\Video\\" ) / sizeof(WCHAR
) - 1;
1345 lstrcpyW( bufferW
+ len
, ctx
->gpu_guid
);
1346 len
+= lstrlenW( bufferW
+ len
);
1347 sprintf( buffer
, "\\%04x", adapter_index
);
1348 len
+= asciiz_to_unicode( bufferW
+ len
, buffer
) / sizeof(WCHAR
) - 1;
1349 hkey
= reg_create_key( NULL
, bufferW
, len
* sizeof(WCHAR
),
1350 REG_OPTION_VOLATILE
| REG_OPTION_CREATE_LINK
, NULL
);
1351 if (!hkey
) hkey
= reg_create_key( NULL
, bufferW
, len
* sizeof(WCHAR
),
1352 REG_OPTION_VOLATILE
| REG_OPTION_OPEN_LINK
, NULL
);
1354 sprintf( name
, "\\Device\\Video%u", video_index
);
1355 asciiz_to_unicode( nameW
, name
);
1356 set_reg_value( video_key
, nameW
, REG_SZ
, bufferW
, (lstrlenW( bufferW
) + 1) * sizeof(WCHAR
) );
1360 sprintf( buffer
, "\\Registry\\Machine\\System\\CurrentControlSet\\Control\\Class\\"
1361 "%s\\%04X", guid_devclass_displayA
, ctx
->gpu_count
- 1 );
1362 len
= asciiz_to_unicode( bufferW
, buffer
) - sizeof(WCHAR
);
1363 set_reg_value( hkey
, symbolic_link_valueW
, REG_LINK
, bufferW
, len
);
1366 else ERR( "failed to create link key\n" );
1368 /* Following information is Wine specific, it doesn't really exist on Windows. */
1369 len
= asciiz_to_unicode( bufferW
, "System\\CurrentControlSet\\Control\\Video\\" )
1370 / sizeof(WCHAR
) - 1;
1371 lstrcpyW( bufferW
+ len
, ctx
->gpu_guid
);
1372 len
+= lstrlenW( bufferW
+ len
);
1373 sprintf( buffer
, "\\%04x", adapter_index
);
1374 len
+= asciiz_to_unicode( bufferW
+ len
, buffer
) / sizeof(WCHAR
) - 1;
1375 ctx
->adapter_key
= reg_create_key( config_key
, bufferW
, len
* sizeof(WCHAR
),
1376 REG_OPTION_VOLATILE
, NULL
);
1378 set_reg_value( ctx
->adapter_key
, gpu_idW
, REG_SZ
, ctx
->gpuid
,
1379 (lstrlenW( ctx
->gpuid
) + 1) * sizeof(WCHAR
) );
1380 set_reg_value( ctx
->adapter_key
, state_flagsW
, REG_DWORD
, &adapter
->state_flags
,
1381 sizeof(adapter
->state_flags
) );
1384 static void add_monitor( const struct gdi_monitor
*monitor
, void *param
)
1386 struct device_manager_ctx
*ctx
= param
;
1387 char buffer
[MAX_PATH
], instance
[64];
1388 unsigned int monitor_index
, output_index
;
1389 struct edid_monitor_info monitor_info
;
1390 char monitor_id_string
[16];
1391 WCHAR bufferW
[MAX_PATH
];
1395 monitor_index
= ctx
->monitor_count
++;
1396 output_index
= ctx
->output_count
++;
1398 TRACE( "%u %s %s\n", monitor_index
, wine_dbgstr_rect(&monitor
->rc_monitor
), wine_dbgstr_rect(&monitor
->rc_work
) );
1400 get_monitor_info_from_edid( &monitor_info
, monitor
->edid
, monitor
->edid_len
);
1401 if (monitor_info
.flags
& MONITOR_INFO_HAS_MONITOR_ID
)
1402 strcpy( monitor_id_string
, monitor_info
.monitor_id_string
);
1404 strcpy( monitor_id_string
, "Default_Monitor" );
1406 sprintf( buffer
, "MonitorID%u", monitor_index
);
1407 sprintf( instance
, "DISPLAY\\%s\\%04X&%04X", monitor_id_string
, ctx
->video_count
- 1, monitor_index
);
1408 set_reg_ascii_value( ctx
->adapter_key
, buffer
, instance
);
1410 hkey
= reg_create_key( enum_key
, bufferW
, asciiz_to_unicode( bufferW
, instance
) - sizeof(WCHAR
),
1414 link_device( bufferW
, guid_devinterface_monitorW
);
1416 asciiz_to_unicode( bufferW
, "Generic Non-PnP Monitor" );
1417 set_reg_value( hkey
, device_descW
, REG_SZ
, bufferW
, (lstrlenW( bufferW
) + 1) * sizeof(WCHAR
) );
1419 set_reg_value( hkey
, classW
, REG_SZ
, monitorW
, sizeof(monitorW
) );
1420 sprintf( buffer
, "%s\\%04X", guid_devclass_monitorA
, output_index
);
1421 set_reg_ascii_value( hkey
, "Driver", buffer
);
1422 set_reg_value( hkey
, class_guidW
, REG_SZ
, guid_devclass_monitorW
, sizeof(guid_devclass_monitorW
) );
1424 sprintf( buffer
, "MONITOR\\%s", monitor_id_string
);
1425 len
= asciiz_to_unicode( bufferW
, buffer
);
1426 bufferW
[len
/ sizeof(WCHAR
)] = 0;
1427 set_reg_value( hkey
, hardware_idW
, REG_MULTI_SZ
, bufferW
, len
+ sizeof(WCHAR
) );
1429 if ((subkey
= reg_create_key( hkey
, device_parametersW
, sizeof(device_parametersW
), 0, NULL
)))
1431 static const WCHAR bad_edidW
[] = {'B','A','D','_','E','D','I','D',0};
1433 if (monitor
->edid_len
)
1434 set_reg_value( subkey
, edidW
, REG_BINARY
, monitor
->edid
, monitor
->edid_len
);
1436 set_reg_value( subkey
, bad_edidW
, REG_BINARY
, NULL
, 0 );
1441 if ((subkey
= reg_create_key( hkey
, wine_devpropkey_monitor_stateflagsW
,
1442 sizeof(wine_devpropkey_monitor_stateflagsW
), 0, NULL
)))
1444 set_reg_value( subkey
, NULL
, 0xffff0000 | DEVPROP_TYPE_UINT32
, &monitor
->state_flags
,
1445 sizeof(monitor
->state_flags
) );
1449 /* WINE_DEVPROPKEY_MONITOR_RCMONITOR */
1450 if ((subkey
= reg_create_key( hkey
, wine_devpropkey_monitor_rcmonitorW
,
1451 sizeof(wine_devpropkey_monitor_rcmonitorW
), 0, NULL
)))
1453 set_reg_value( subkey
, NULL
, 0xffff0000 | DEVPROP_TYPE_BINARY
, &monitor
->rc_monitor
,
1454 sizeof(monitor
->rc_monitor
) );
1458 /* WINE_DEVPROPKEY_MONITOR_RCWORK */
1459 if ((subkey
= reg_create_key( hkey
, wine_devpropkey_monitor_rcworkW
,
1460 sizeof(wine_devpropkey_monitor_rcworkW
), 0, NULL
)))
1462 TRACE( "rc_work %s\n", wine_dbgstr_rect(&monitor
->rc_work
) );
1463 set_reg_value( subkey
, NULL
, 0xffff0000 | DEVPROP_TYPE_BINARY
, &monitor
->rc_work
,
1464 sizeof(monitor
->rc_work
) );
1468 /* WINE_DEVPROPKEY_MONITOR_ADAPTERNAME */
1469 if ((subkey
= reg_create_key( hkey
, wine_devpropkey_monitor_adapternameW
,
1470 sizeof(wine_devpropkey_monitor_adapternameW
), 0, NULL
)))
1472 sprintf( buffer
, "\\\\.\\DISPLAY%u", ctx
->video_count
);
1473 set_reg_value( subkey
, NULL
, 0xffff0000 | DEVPROP_TYPE_STRING
, bufferW
,
1474 asciiz_to_unicode( bufferW
, buffer
));
1478 /* DEVPROPKEY_MONITOR_GPU_LUID */
1479 if ((subkey
= reg_create_key( hkey
, devpropkey_monitor_gpu_luidW
,
1480 sizeof(devpropkey_monitor_gpu_luidW
), 0, NULL
)))
1482 set_reg_value( subkey
, NULL
, 0xffff0000 | DEVPROP_TYPE_INT64
,
1483 &ctx
->gpu_luid
, sizeof(ctx
->gpu_luid
) );
1487 /* DEVPROPKEY_MONITOR_OUTPUT_ID */
1488 if ((subkey
= reg_create_key( hkey
, devpropkey_monitor_output_idW
,
1489 sizeof(devpropkey_monitor_output_idW
), 0, NULL
)))
1491 set_reg_value( subkey
, NULL
, 0xffff0000 | DEVPROP_TYPE_UINT32
,
1492 &output_index
, sizeof(output_index
) );
1498 sprintf( buffer
, "Class\\%s\\%04X", guid_devclass_monitorA
, output_index
);
1499 hkey
= reg_create_key( control_key
, bufferW
,
1500 asciiz_to_unicode( bufferW
, buffer
) - sizeof(WCHAR
), 0, NULL
);
1501 if (hkey
) NtClose( hkey
);
1504 static void add_mode( const DEVMODEW
*mode
, BOOL current
, void *param
)
1506 struct device_manager_ctx
*ctx
= param
;
1507 DEVMODEW nopos_mode
;
1509 if (!ctx
->adapter_count
)
1511 static const struct gdi_adapter default_adapter
=
1513 .state_flags
= DISPLAY_DEVICE_ATTACHED_TO_DESKTOP
| DISPLAY_DEVICE_PRIMARY_DEVICE
| DISPLAY_DEVICE_VGA_COMPATIBLE
,
1515 TRACE( "adding default fake adapter\n" );
1516 add_adapter( &default_adapter
, ctx
);
1520 nopos_mode
.dmPosition
.x
= 0;
1521 nopos_mode
.dmPosition
.y
= 0;
1522 nopos_mode
.dmFields
&= ~DM_POSITION
;
1524 if (write_adapter_mode( ctx
->adapter_key
, ctx
->mode_count
, &nopos_mode
))
1527 set_reg_value( ctx
->adapter_key
, mode_countW
, REG_DWORD
, &ctx
->mode_count
, sizeof(ctx
->mode_count
) );
1530 if (!read_adapter_mode( ctx
->adapter_key
, ENUM_REGISTRY_SETTINGS
, &nopos_mode
))
1531 write_adapter_mode( ctx
->adapter_key
, ENUM_REGISTRY_SETTINGS
, mode
);
1532 write_adapter_mode( ctx
->adapter_key
, ENUM_CURRENT_SETTINGS
, mode
);
1537 static const struct gdi_device_manager device_manager
=
1545 static void release_display_manager_ctx( struct device_manager_ctx
*ctx
)
1549 pthread_mutex_unlock( &display_lock
);
1550 release_display_device_init_mutex( ctx
->mutex
);
1552 if (ctx
->adapter_key
)
1554 NtClose( ctx
->adapter_key
);
1555 last_query_display_time
= 0;
1557 if (ctx
->gpu_count
) cleanup_devices();
1560 static void clear_display_devices(void)
1562 struct adapter
*adapter
;
1563 struct monitor
*monitor
;
1565 if (list_head( &monitors
) == &virtual_monitor
.entry
)
1567 list_init( &monitors
);
1571 while (!list_empty( &monitors
))
1573 monitor
= LIST_ENTRY( list_head( &monitors
), struct monitor
, entry
);
1574 adapter_release( monitor
->adapter
);
1575 list_remove( &monitor
->entry
);
1579 while (!list_empty( &adapters
))
1581 adapter
= LIST_ENTRY( list_head( &adapters
), struct adapter
, entry
);
1582 list_remove( &adapter
->entry
);
1583 adapter_release( adapter
);
1587 static BOOL
update_display_cache_from_registry(void)
1589 DWORD adapter_id
, monitor_id
, monitor_count
= 0, size
;
1590 KEY_BASIC_INFORMATION key
;
1591 struct adapter
*adapter
;
1592 struct monitor
*monitor
, *monitor2
;
1593 HANDLE mutex
= NULL
;
1597 /* If user driver did initialize the registry, then exit */
1598 if (!video_key
&& !(video_key
= reg_open_key( NULL
, devicemap_video_keyW
,
1599 sizeof(devicemap_video_keyW
) )))
1602 status
= NtQueryKey( video_key
, KeyBasicInformation
, &key
,
1603 offsetof(KEY_BASIC_INFORMATION
, Name
), &size
);
1604 if (status
&& status
!= STATUS_BUFFER_OVERFLOW
)
1607 if (key
.LastWriteTime
.QuadPart
<= last_query_display_time
) return TRUE
;
1609 mutex
= get_display_device_init_mutex();
1610 pthread_mutex_lock( &display_lock
);
1612 clear_display_devices();
1614 for (adapter_id
= 0;; adapter_id
++)
1616 if (!(adapter
= calloc( 1, sizeof(*adapter
) ))) break;
1617 adapter
->refcount
= 1;
1618 adapter
->id
= adapter_id
;
1620 if (!read_display_adapter_settings( adapter_id
, adapter
))
1622 adapter_release( adapter
);
1626 list_add_tail( &adapters
, &adapter
->entry
);
1627 for (monitor_id
= 0;; monitor_id
++)
1629 if (!(monitor
= calloc( 1, sizeof(*monitor
) ))) break;
1630 if (!read_monitor_settings( adapter
, monitor_id
, monitor
))
1636 monitor
->id
= monitor_id
;
1637 monitor
->adapter
= adapter_acquire( adapter
);
1639 LIST_FOR_EACH_ENTRY(monitor2
, &monitors
, struct monitor
, entry
)
1641 if (EqualRect(&monitor2
->rc_monitor
, &monitor
->rc_monitor
))
1643 monitor
->is_clone
= TRUE
;
1648 monitor
->handle
= UlongToHandle( ++monitor_count
);
1649 list_add_tail( &monitors
, &monitor
->entry
);
1653 if ((ret
= !list_empty( &adapters
) && !list_empty( &monitors
)))
1654 last_query_display_time
= key
.LastWriteTime
.QuadPart
;
1655 pthread_mutex_unlock( &display_lock
);
1656 release_display_device_init_mutex( mutex
);
1660 static BOOL
is_same_devmode( const DEVMODEW
*a
, const DEVMODEW
*b
)
1662 return a
->dmDisplayOrientation
== b
->dmDisplayOrientation
&&
1663 a
->dmBitsPerPel
== b
->dmBitsPerPel
&&
1664 a
->dmPelsWidth
== b
->dmPelsWidth
&&
1665 a
->dmPelsHeight
== b
->dmPelsHeight
&&
1666 a
->dmDisplayFrequency
== b
->dmDisplayFrequency
;
1669 static BOOL
update_display_cache( BOOL force
)
1671 HWINSTA winstation
= NtUserGetProcessWindowStation();
1672 struct device_manager_ctx ctx
= {0};
1673 USEROBJECTFLAGS flags
;
1675 /* services do not have any adapters, only a virtual monitor */
1676 if (NtUserGetObjectInformation( winstation
, UOI_FLAGS
, &flags
, sizeof(flags
), NULL
)
1677 && !(flags
.dwFlags
& WSF_VISIBLE
))
1679 pthread_mutex_lock( &display_lock
);
1680 clear_display_devices();
1681 list_add_tail( &monitors
, &virtual_monitor
.entry
);
1682 pthread_mutex_unlock( &display_lock
);
1686 if (!user_driver
->pUpdateDisplayDevices( &device_manager
, force
, &ctx
) && force
)
1688 /* default implementation: expose an adapter and a monitor with a few standard modes,
1689 * and read / write current display settings from / to the registry.
1691 static const DEVMODEW modes
[] =
1693 { .dmFields
= DM_DISPLAYORIENTATION
| DM_BITSPERPEL
| DM_PELSWIDTH
| DM_PELSHEIGHT
| DM_DISPLAYFLAGS
| DM_DISPLAYFREQUENCY
,
1694 .dmBitsPerPel
= 32, .dmPelsWidth
= 640, .dmPelsHeight
= 480, .dmDisplayFrequency
= 60, },
1695 { .dmFields
= DM_DISPLAYORIENTATION
| DM_BITSPERPEL
| DM_PELSWIDTH
| DM_PELSHEIGHT
| DM_DISPLAYFLAGS
| DM_DISPLAYFREQUENCY
,
1696 .dmBitsPerPel
= 32, .dmPelsWidth
= 800, .dmPelsHeight
= 600, .dmDisplayFrequency
= 60, },
1697 { .dmFields
= DM_DISPLAYORIENTATION
| DM_BITSPERPEL
| DM_PELSWIDTH
| DM_PELSHEIGHT
| DM_DISPLAYFLAGS
| DM_DISPLAYFREQUENCY
,
1698 .dmBitsPerPel
= 32, .dmPelsWidth
= 1024, .dmPelsHeight
= 768, .dmDisplayFrequency
= 60, },
1699 { .dmFields
= DM_DISPLAYORIENTATION
| DM_BITSPERPEL
| DM_PELSWIDTH
| DM_PELSHEIGHT
| DM_DISPLAYFLAGS
| DM_DISPLAYFREQUENCY
,
1700 .dmBitsPerPel
= 16, .dmPelsWidth
= 640, .dmPelsHeight
= 480, .dmDisplayFrequency
= 60, },
1701 { .dmFields
= DM_DISPLAYORIENTATION
| DM_BITSPERPEL
| DM_PELSWIDTH
| DM_PELSHEIGHT
| DM_DISPLAYFLAGS
| DM_DISPLAYFREQUENCY
,
1702 .dmBitsPerPel
= 16, .dmPelsWidth
= 800, .dmPelsHeight
= 600, .dmDisplayFrequency
= 60, },
1703 { .dmFields
= DM_DISPLAYORIENTATION
| DM_BITSPERPEL
| DM_PELSWIDTH
| DM_PELSHEIGHT
| DM_DISPLAYFLAGS
| DM_DISPLAYFREQUENCY
,
1704 .dmBitsPerPel
= 16, .dmPelsWidth
= 1024, .dmPelsHeight
= 768, .dmDisplayFrequency
= 60, },
1706 static const struct gdi_gpu gpu
;
1707 static const struct gdi_adapter adapter
=
1709 .state_flags
= DISPLAY_DEVICE_ATTACHED_TO_DESKTOP
| DISPLAY_DEVICE_PRIMARY_DEVICE
| DISPLAY_DEVICE_VGA_COMPATIBLE
,
1711 struct gdi_monitor monitor
=
1713 .state_flags
= DISPLAY_DEVICE_ACTIVE
| DISPLAY_DEVICE_ATTACHED
,
1715 DEVMODEW mode
= {{0}};
1718 add_gpu( &gpu
, &ctx
);
1719 add_adapter( &adapter
, &ctx
);
1721 if (!read_adapter_mode( ctx
.adapter_key
, ENUM_CURRENT_SETTINGS
, &mode
))
1724 mode
.dmFields
|= DM_POSITION
;
1726 monitor
.rc_monitor
.right
= mode
.dmPelsWidth
;
1727 monitor
.rc_monitor
.bottom
= mode
.dmPelsHeight
;
1728 monitor
.rc_work
.right
= mode
.dmPelsWidth
;
1729 monitor
.rc_work
.bottom
= mode
.dmPelsHeight
;
1731 add_monitor( &monitor
, &ctx
);
1732 for (i
= 0; i
< ARRAY_SIZE(modes
); ++i
)
1734 if (is_same_devmode( modes
+ i
, &mode
)) add_mode( &mode
, TRUE
, &ctx
);
1735 else add_mode( modes
+ i
, FALSE
, &ctx
);
1738 release_display_manager_ctx( &ctx
);
1740 if (!update_display_cache_from_registry())
1744 ERR( "Failed to read display config.\n" );
1750 ERR( "Driver reported devices, but we failed to read them.\n" );
1754 return update_display_cache( TRUE
);
1760 static BOOL
lock_display_devices(void)
1762 if (!update_display_cache( FALSE
)) return FALSE
;
1763 pthread_mutex_lock( &display_lock
);
1767 static void unlock_display_devices(void)
1769 pthread_mutex_unlock( &display_lock
);
1772 static HDC
get_display_dc(void)
1774 pthread_mutex_lock( &display_dc_lock
);
1779 pthread_mutex_unlock( &display_dc_lock
);
1780 dc
= NtGdiOpenDCW( NULL
, NULL
, NULL
, 0, TRUE
, NULL
, NULL
, NULL
);
1781 pthread_mutex_lock( &display_dc_lock
);
1783 NtGdiDeleteObjectApp( dc
);
1790 static void release_display_dc( HDC hdc
)
1792 pthread_mutex_unlock( &display_dc_lock
);
1795 /**********************************************************************
1798 UINT
get_monitor_dpi( HMONITOR monitor
)
1800 /* FIXME: use the monitor DPI instead */
1804 /**********************************************************************
1805 * get_win_monitor_dpi
1807 UINT
get_win_monitor_dpi( HWND hwnd
)
1809 /* FIXME: use the monitor DPI instead */
1813 /**********************************************************************
1814 * get_thread_dpi_awareness
1816 DPI_AWARENESS
get_thread_dpi_awareness(void)
1818 struct ntuser_thread_info
*info
= NtUserGetThreadInfo();
1819 ULONG_PTR context
= info
->dpi_awareness
;
1821 if (!context
) context
= NtUserGetProcessDpiAwarenessContext( NULL
);
1832 case (ULONG_PTR
)DPI_AWARENESS_CONTEXT_UNAWARE
:
1833 case (ULONG_PTR
)DPI_AWARENESS_CONTEXT_SYSTEM_AWARE
:
1834 case (ULONG_PTR
)DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE
:
1837 return DPI_AWARENESS_INVALID
;
1841 DWORD
get_process_layout(void)
1843 return process_layout
== ~0u ? 0 : process_layout
;
1846 /**********************************************************************
1849 UINT
get_thread_dpi(void)
1851 switch (get_thread_dpi_awareness())
1853 case DPI_AWARENESS_UNAWARE
: return USER_DEFAULT_SCREEN_DPI
;
1854 case DPI_AWARENESS_SYSTEM_AWARE
: return system_dpi
;
1855 default: return 0; /* no scaling */
1859 /* see GetDpiForSystem */
1860 UINT
get_system_dpi(void)
1862 if (get_thread_dpi_awareness() == DPI_AWARENESS_UNAWARE
) return USER_DEFAULT_SCREEN_DPI
;
1866 /* see GetAwarenessFromDpiAwarenessContext */
1867 static DPI_AWARENESS
get_awareness_from_dpi_awareness_context( DPI_AWARENESS_CONTEXT context
)
1869 switch ((ULONG_PTR
)context
)
1877 return (ULONG_PTR
)context
& 3;
1878 case (ULONG_PTR
)DPI_AWARENESS_CONTEXT_UNAWARE
:
1879 case (ULONG_PTR
)DPI_AWARENESS_CONTEXT_SYSTEM_AWARE
:
1880 case (ULONG_PTR
)DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE
:
1881 return ~(ULONG_PTR
)context
;
1883 return DPI_AWARENESS_INVALID
;
1887 /**********************************************************************
1888 * SetThreadDpiAwarenessContext (win32u.so)
1890 DPI_AWARENESS_CONTEXT WINAPI
SetThreadDpiAwarenessContext( DPI_AWARENESS_CONTEXT context
)
1892 struct ntuser_thread_info
*info
= NtUserGetThreadInfo();
1893 DPI_AWARENESS prev
, val
= get_awareness_from_dpi_awareness_context( context
);
1895 if (val
== DPI_AWARENESS_INVALID
)
1897 RtlSetLastWin32Error( ERROR_INVALID_PARAMETER
);
1900 if (!(prev
= info
->dpi_awareness
))
1902 prev
= NtUserGetProcessDpiAwarenessContext( GetCurrentProcess() ) & 3;
1903 prev
|= 0x80000010; /* restore to process default */
1905 if (((ULONG_PTR
)context
& ~(ULONG_PTR
)0x13) == 0x80000000) info
->dpi_awareness
= 0;
1906 else info
->dpi_awareness
= val
| 0x10;
1907 return ULongToHandle( prev
);
1910 /**********************************************************************
1913 RECT
map_dpi_rect( RECT rect
, UINT dpi_from
, UINT dpi_to
)
1915 if (dpi_from
&& dpi_to
&& dpi_from
!= dpi_to
)
1917 rect
.left
= muldiv( rect
.left
, dpi_to
, dpi_from
);
1918 rect
.top
= muldiv( rect
.top
, dpi_to
, dpi_from
);
1919 rect
.right
= muldiv( rect
.right
, dpi_to
, dpi_from
);
1920 rect
.bottom
= muldiv( rect
.bottom
, dpi_to
, dpi_from
);
1925 /**********************************************************************
1928 POINT
map_dpi_point( POINT pt
, UINT dpi_from
, UINT dpi_to
)
1930 if (dpi_from
&& dpi_to
&& dpi_from
!= dpi_to
)
1932 pt
.x
= muldiv( pt
.x
, dpi_to
, dpi_from
);
1933 pt
.y
= muldiv( pt
.y
, dpi_to
, dpi_from
);
1938 /**********************************************************************
1939 * point_win_to_phys_dpi
1941 static POINT
point_win_to_phys_dpi( HWND hwnd
, POINT pt
)
1943 return map_dpi_point( pt
, get_dpi_for_window( hwnd
), get_win_monitor_dpi( hwnd
) );
1946 /**********************************************************************
1947 * point_phys_to_win_dpi
1949 POINT
point_phys_to_win_dpi( HWND hwnd
, POINT pt
)
1951 return map_dpi_point( pt
, get_win_monitor_dpi( hwnd
), get_dpi_for_window( hwnd
));
1954 /**********************************************************************
1955 * point_thread_to_win_dpi
1957 POINT
point_thread_to_win_dpi( HWND hwnd
, POINT pt
)
1959 UINT dpi
= get_thread_dpi();
1960 if (!dpi
) dpi
= get_win_monitor_dpi( hwnd
);
1961 return map_dpi_point( pt
, dpi
, get_dpi_for_window( hwnd
));
1964 /**********************************************************************
1965 * rect_thread_to_win_dpi
1967 RECT
rect_thread_to_win_dpi( HWND hwnd
, RECT rect
)
1969 UINT dpi
= get_thread_dpi();
1970 if (!dpi
) dpi
= get_win_monitor_dpi( hwnd
);
1971 return map_dpi_rect( rect
, dpi
, get_dpi_for_window( hwnd
) );
1974 /* map value from system dpi to standard 96 dpi for storing in the registry */
1975 static int map_from_system_dpi( int val
)
1977 return muldiv( val
, USER_DEFAULT_SCREEN_DPI
, get_system_dpi() );
1980 /* map value from 96 dpi to system or custom dpi */
1981 static int map_to_dpi( int val
, UINT dpi
)
1983 if (!dpi
) dpi
= get_system_dpi();
1984 return muldiv( val
, dpi
, USER_DEFAULT_SCREEN_DPI
);
1987 RECT
get_virtual_screen_rect( UINT dpi
)
1989 struct monitor
*monitor
;
1992 if (!lock_display_devices()) return rect
;
1994 LIST_FOR_EACH_ENTRY( monitor
, &monitors
, struct monitor
, entry
)
1996 union_rect( &rect
, &rect
, &monitor
->rc_monitor
);
1999 unlock_display_devices();
2001 if (dpi
) rect
= map_dpi_rect( rect
, system_dpi
, dpi
);
2005 static BOOL
is_window_rect_full_screen( const RECT
*rect
)
2007 struct monitor
*monitor
;
2010 if (!lock_display_devices()) return FALSE
;
2012 LIST_FOR_EACH_ENTRY( monitor
, &monitors
, struct monitor
, entry
)
2014 if (!(monitor
->dev
.state_flags
& DISPLAY_DEVICE_ACTIVE
))
2017 if (rect
->left
<= monitor
->rc_monitor
.left
&& rect
->right
>= monitor
->rc_monitor
.right
&&
2018 rect
->top
<= monitor
->rc_monitor
.top
&& rect
->bottom
>= monitor
->rc_monitor
.bottom
)
2025 unlock_display_devices();
2029 RECT
get_display_rect( const WCHAR
*display
)
2031 struct monitor
*monitor
;
2034 if (!lock_display_devices()) return rect
;
2036 LIST_FOR_EACH_ENTRY( monitor
, &monitors
, struct monitor
, entry
)
2038 if (!monitor
->adapter
|| wcsicmp( monitor
->adapter
->dev
.device_name
, display
)) continue;
2039 rect
= monitor
->rc_monitor
;
2043 unlock_display_devices();
2044 return map_dpi_rect( rect
, system_dpi
, get_thread_dpi() );
2047 RECT
get_primary_monitor_rect( UINT dpi
)
2049 struct monitor
*monitor
;
2052 if (!lock_display_devices()) return rect
;
2054 LIST_FOR_EACH_ENTRY( monitor
, &monitors
, struct monitor
, entry
)
2056 if (!(monitor
->flags
& MONITORINFOF_PRIMARY
)) continue;
2057 rect
= monitor
->rc_monitor
;
2061 unlock_display_devices();
2062 return map_dpi_rect( rect
, system_dpi
, dpi
);
2065 /**********************************************************************
2066 * NtUserGetDisplayConfigBufferSizes (win32u.@)
2068 LONG WINAPI
NtUserGetDisplayConfigBufferSizes( UINT32 flags
, UINT32
*num_path_info
,
2069 UINT32
*num_mode_info
)
2071 struct monitor
*monitor
;
2074 TRACE( "(0x%x %p %p)\n", flags
, num_path_info
, num_mode_info
);
2076 if (!num_path_info
|| !num_mode_info
)
2077 return ERROR_INVALID_PARAMETER
;
2084 case QDC_ONLY_ACTIVE_PATHS
:
2085 case QDC_DATABASE_CURRENT
:
2088 return ERROR_INVALID_PARAMETER
;
2091 /* FIXME: semi-stub */
2092 if (flags
!= QDC_ONLY_ACTIVE_PATHS
)
2093 FIXME( "only returning active paths\n" );
2095 if (lock_display_devices())
2097 LIST_FOR_EACH_ENTRY( monitor
, &monitors
, struct monitor
, entry
)
2099 if (!(monitor
->dev
.state_flags
& DISPLAY_DEVICE_ACTIVE
))
2103 unlock_display_devices();
2106 *num_path_info
= count
;
2107 *num_mode_info
= count
* 2;
2108 TRACE( "returning %u paths %u modes\n", *num_path_info
, *num_mode_info
);
2109 return ERROR_SUCCESS
;
2112 /* display_lock mutex must be held */
2113 static struct display_device
*find_monitor_device( struct display_device
*adapter
, UINT index
)
2115 struct monitor
*monitor
;
2117 LIST_FOR_EACH_ENTRY(monitor
, &monitors
, struct monitor
, entry
)
2118 if (&monitor
->adapter
->dev
== adapter
&& index
== monitor
->id
)
2119 return &monitor
->dev
;
2121 WARN( "Failed to find adapter %s monitor with id %u.\n", debugstr_w(adapter
->device_name
), index
);
2125 /* display_lock mutex must be held */
2126 static struct display_device
*find_adapter_device_by_id( UINT index
)
2128 struct adapter
*adapter
;
2130 LIST_FOR_EACH_ENTRY(adapter
, &adapters
, struct adapter
, entry
)
2131 if (index
== adapter
->id
) return &adapter
->dev
;
2133 WARN( "Failed to find adapter with id %u.\n", index
);
2137 /* display_lock mutex must be held */
2138 static struct display_device
*find_adapter_device_by_name( UNICODE_STRING
*name
)
2140 SIZE_T len
= name
->Length
/ sizeof(WCHAR
);
2141 struct adapter
*adapter
;
2143 LIST_FOR_EACH_ENTRY(adapter
, &adapters
, struct adapter
, entry
)
2144 if (!wcsnicmp( name
->Buffer
, adapter
->dev
.device_name
, len
) && !adapter
->dev
.device_name
[len
])
2145 return &adapter
->dev
;
2147 WARN( "Failed to find adapter with name %s.\n", debugstr_us(name
) );
2151 /* Find and acquire the adapter matching name, or primary adapter if name is NULL.
2152 * If not NULL, the returned adapter needs to be released with adapter_release.
2154 static struct adapter
*find_adapter( UNICODE_STRING
*name
)
2156 struct display_device
*device
;
2157 struct adapter
*adapter
;
2159 if (!lock_display_devices()) return NULL
;
2161 if (name
&& name
->Length
) device
= find_adapter_device_by_name( name
);
2162 else device
= find_adapter_device_by_id( 0 ); /* use primary adapter */
2164 if (!device
) adapter
= NULL
;
2165 else adapter
= adapter_acquire( CONTAINING_RECORD( device
, struct adapter
, dev
) );
2167 unlock_display_devices();
2171 /***********************************************************************
2172 * NtUserEnumDisplayDevices (win32u.@)
2174 NTSTATUS WINAPI
NtUserEnumDisplayDevices( UNICODE_STRING
*device
, DWORD index
,
2175 DISPLAY_DEVICEW
*info
, DWORD flags
)
2177 struct display_device
*found
= NULL
;
2179 TRACE( "%s %u %p %#x\n", debugstr_us( device
), (int)index
, info
, (int)flags
);
2181 if (!info
|| !info
->cb
) return STATUS_UNSUCCESSFUL
;
2183 if (!lock_display_devices()) return STATUS_UNSUCCESSFUL
;
2185 if (!device
|| !device
->Length
) found
= find_adapter_device_by_id( index
);
2186 else if ((found
= find_adapter_device_by_name( device
))) found
= find_monitor_device( found
, index
);
2190 if (info
->cb
>= offsetof(DISPLAY_DEVICEW
, DeviceName
) + sizeof(info
->DeviceName
))
2191 lstrcpyW( info
->DeviceName
, found
->device_name
);
2192 if (info
->cb
>= offsetof(DISPLAY_DEVICEW
, DeviceString
) + sizeof(info
->DeviceString
))
2193 lstrcpyW( info
->DeviceString
, found
->device_string
);
2194 if (info
->cb
>= offsetof(DISPLAY_DEVICEW
, StateFlags
) + sizeof(info
->StateFlags
))
2195 info
->StateFlags
= found
->state_flags
;
2196 if (info
->cb
>= offsetof(DISPLAY_DEVICEW
, DeviceID
) + sizeof(info
->DeviceID
))
2197 lstrcpyW( info
->DeviceID
, (flags
& EDD_GET_DEVICE_INTERFACE_NAME
)
2198 ? found
->interface_name
: found
->device_id
);
2199 if (info
->cb
>= offsetof(DISPLAY_DEVICEW
, DeviceKey
) + sizeof(info
->DeviceKey
))
2200 lstrcpyW( info
->DeviceKey
, found
->device_key
);
2202 unlock_display_devices();
2203 return found
? STATUS_SUCCESS
: STATUS_UNSUCCESSFUL
;
2206 #define _X_FIELD(prefix, bits) \
2207 if ((fields) & prefix##_##bits) \
2209 p += sprintf( p, "%s%s", first ? "" : ",", #bits ); \
2213 static const char *_CDS_flags( DWORD fields
)
2219 _X_FIELD(CDS
, UPDATEREGISTRY
)
2221 _X_FIELD(CDS
, FULLSCREEN
)
2222 _X_FIELD(CDS
, GLOBAL
)
2223 _X_FIELD(CDS
, SET_PRIMARY
)
2224 _X_FIELD(CDS
, VIDEOPARAMETERS
)
2225 _X_FIELD(CDS
, ENABLE_UNSAFE_MODES
)
2226 _X_FIELD(CDS
, DISABLE_UNSAFE_MODES
)
2227 _X_FIELD(CDS
, RESET
)
2228 _X_FIELD(CDS
, RESET_EX
)
2229 _X_FIELD(CDS
, NORESET
)
2232 return wine_dbg_sprintf( "%s", buf
);
2235 static const char *_DM_fields( DWORD fields
)
2241 _X_FIELD(DM
, BITSPERPEL
)
2242 _X_FIELD(DM
, PELSWIDTH
)
2243 _X_FIELD(DM
, PELSHEIGHT
)
2244 _X_FIELD(DM
, DISPLAYFLAGS
)
2245 _X_FIELD(DM
, DISPLAYFREQUENCY
)
2246 _X_FIELD(DM
, POSITION
)
2247 _X_FIELD(DM
, DISPLAYORIENTATION
)
2250 return wine_dbg_sprintf( "%s", buf
);
2255 static void trace_devmode( const DEVMODEW
*devmode
)
2257 TRACE( "dmFields=%s ", _DM_fields(devmode
->dmFields
) );
2258 if (devmode
->dmFields
& DM_BITSPERPEL
)
2259 TRACE( "dmBitsPerPel=%u ", (int)devmode
->dmBitsPerPel
);
2260 if (devmode
->dmFields
& DM_PELSWIDTH
)
2261 TRACE( "dmPelsWidth=%u ", (int)devmode
->dmPelsWidth
);
2262 if (devmode
->dmFields
& DM_PELSHEIGHT
)
2263 TRACE( "dmPelsHeight=%u ", (int)devmode
->dmPelsHeight
);
2264 if (devmode
->dmFields
& DM_DISPLAYFREQUENCY
)
2265 TRACE( "dmDisplayFrequency=%u ", (int)devmode
->dmDisplayFrequency
);
2266 if (devmode
->dmFields
& DM_POSITION
)
2267 TRACE( "dmPosition=(%d,%d) ", (int)devmode
->dmPosition
.x
, (int)devmode
->dmPosition
.y
);
2268 if (devmode
->dmFields
& DM_DISPLAYFLAGS
)
2269 TRACE( "dmDisplayFlags=%#x ", (int)devmode
->dmDisplayFlags
);
2270 if (devmode
->dmFields
& DM_DISPLAYORIENTATION
)
2271 TRACE( "dmDisplayOrientation=%u ", (int)devmode
->dmDisplayOrientation
);
2275 static BOOL
is_detached_mode( const DEVMODEW
*mode
)
2277 return mode
->dmFields
& DM_POSITION
&&
2278 mode
->dmFields
& DM_PELSWIDTH
&&
2279 mode
->dmFields
& DM_PELSHEIGHT
&&
2280 mode
->dmPelsWidth
== 0 &&
2281 mode
->dmPelsHeight
== 0;
2284 static const DEVMODEW
*find_display_mode( const DEVMODEW
*modes
, DEVMODEW
*devmode
)
2286 const DEVMODEW
*mode
;
2288 if (is_detached_mode( devmode
)) return devmode
;
2290 for (mode
= modes
; mode
&& mode
->dmSize
; mode
= NEXT_DEVMODEW(mode
))
2292 if ((mode
->dmFields
& DM_DISPLAYFLAGS
) && (mode
->dmDisplayFlags
& WINE_DM_UNSUPPORTED
))
2294 if ((devmode
->dmFields
& DM_BITSPERPEL
) && devmode
->dmBitsPerPel
&& devmode
->dmBitsPerPel
!= mode
->dmBitsPerPel
)
2296 if ((devmode
->dmFields
& DM_PELSWIDTH
) && devmode
->dmPelsWidth
!= mode
->dmPelsWidth
)
2298 if ((devmode
->dmFields
& DM_PELSHEIGHT
) && devmode
->dmPelsHeight
!= mode
->dmPelsHeight
)
2300 if ((devmode
->dmFields
& DM_DISPLAYFREQUENCY
) && devmode
->dmDisplayFrequency
!= mode
->dmDisplayFrequency
2301 && devmode
->dmDisplayFrequency
> 1 && mode
->dmDisplayFrequency
)
2303 if ((devmode
->dmFields
& DM_DISPLAYORIENTATION
) && devmode
->dmDisplayOrientation
!= mode
->dmDisplayOrientation
)
2305 if ((devmode
->dmFields
& DM_DISPLAYFLAGS
) && (mode
->dmFields
& DM_DISPLAYFLAGS
) &&
2306 (devmode
->dmDisplayFlags
& DM_INTERLACED
) != (mode
->dmDisplayFlags
& DM_INTERLACED
))
2308 if ((devmode
->dmFields
& DM_DISPLAYFIXEDOUTPUT
) && (mode
->dmFields
& DM_DISPLAYFIXEDOUTPUT
) &&
2309 devmode
->dmDisplayFixedOutput
!= mode
->dmDisplayFixedOutput
)
2318 static BOOL
adapter_get_full_mode( const struct adapter
*adapter
, const DEVMODEW
*devmode
, DEVMODEW
*full_mode
)
2320 const DEVMODEW
*adapter_mode
;
2324 trace_devmode( devmode
);
2326 if (devmode
->dmSize
< offsetof(DEVMODEW
, dmICMMethod
)) return FALSE
;
2327 if (!is_detached_mode( devmode
) &&
2328 (!(devmode
->dmFields
& DM_BITSPERPEL
) || !devmode
->dmBitsPerPel
) &&
2329 (!(devmode
->dmFields
& DM_PELSWIDTH
) || !devmode
->dmPelsWidth
) &&
2330 (!(devmode
->dmFields
& DM_PELSHEIGHT
) || !devmode
->dmPelsHeight
) &&
2331 (!(devmode
->dmFields
& DM_DISPLAYFREQUENCY
) || !devmode
->dmDisplayFrequency
))
2335 if (devmode
) memcpy( full_mode
, devmode
, devmode
->dmSize
);
2338 if (!adapter_get_registry_settings( adapter
, full_mode
)) return FALSE
;
2339 TRACE( "Return to original display mode\n" );
2342 if ((full_mode
->dmFields
& (DM_PELSWIDTH
| DM_PELSHEIGHT
)) != (DM_PELSWIDTH
| DM_PELSHEIGHT
))
2344 WARN( "devmode doesn't specify the resolution: %#x\n", (int)full_mode
->dmFields
);
2348 if (!is_detached_mode( full_mode
) && (!full_mode
->dmPelsWidth
|| !full_mode
->dmPelsHeight
|| !(full_mode
->dmFields
& DM_POSITION
)))
2350 DEVMODEW current_mode
= {.dmSize
= sizeof(DEVMODEW
)};
2352 if (!adapter_get_current_settings( adapter
, ¤t_mode
)) return FALSE
;
2353 if (!full_mode
->dmPelsWidth
) full_mode
->dmPelsWidth
= current_mode
.dmPelsWidth
;
2354 if (!full_mode
->dmPelsHeight
) full_mode
->dmPelsHeight
= current_mode
.dmPelsHeight
;
2355 if (!(full_mode
->dmFields
& DM_POSITION
))
2357 full_mode
->dmPosition
= current_mode
.dmPosition
;
2358 full_mode
->dmFields
|= DM_POSITION
;
2362 if ((adapter_mode
= find_display_mode( adapter
->modes
, full_mode
)) && adapter_mode
!= full_mode
)
2364 POINTL position
= full_mode
->dmPosition
;
2365 *full_mode
= *adapter_mode
;
2366 full_mode
->dmFields
|= DM_POSITION
;
2367 full_mode
->dmPosition
= position
;
2370 return adapter_mode
!= NULL
;
2373 static DEVMODEW
*get_display_settings( const WCHAR
*devname
, const DEVMODEW
*devmode
)
2375 DEVMODEW
*mode
, *displays
;
2376 struct adapter
*adapter
;
2379 /* allocate an extra mode for easier iteration */
2380 if (!(displays
= calloc( list_count( &adapters
) + 1, sizeof(DEVMODEW
) ))) return NULL
;
2383 LIST_FOR_EACH_ENTRY( adapter
, &adapters
, struct adapter
, entry
)
2385 mode
->dmSize
= sizeof(DEVMODEW
);
2386 if (devmode
&& !wcsicmp( devname
, adapter
->dev
.device_name
))
2387 memcpy( &mode
->dmFields
, &devmode
->dmFields
, devmode
->dmSize
- offsetof(DEVMODEW
, dmFields
) );
2390 if (!devname
) ret
= adapter_get_registry_settings( adapter
, mode
);
2391 else ret
= adapter_get_current_settings( adapter
, mode
);
2399 lstrcpyW( mode
->dmDeviceName
, adapter
->dev
.device_name
);
2400 mode
= NEXT_DEVMODEW(mode
);
2406 static INT
offset_length( POINT offset
)
2408 return offset
.x
* offset
.x
+ offset
.y
* offset
.y
;
2411 static void set_rect_from_devmode( RECT
*rect
, const DEVMODEW
*mode
)
2413 SetRect( rect
, mode
->dmPosition
.x
, mode
->dmPosition
.y
, mode
->dmPosition
.x
+ mode
->dmPelsWidth
,
2414 mode
->dmPosition
.y
+ mode
->dmPelsHeight
);
2417 /* Check if a rect overlaps with placed display rects */
2418 static BOOL
overlap_placed_displays( const RECT
*rect
, const DEVMODEW
*displays
)
2420 const DEVMODEW
*mode
;
2423 for (mode
= displays
; mode
->dmSize
; mode
= NEXT_DEVMODEW(mode
))
2425 set_rect_from_devmode( &intersect
, mode
);
2426 if ((mode
->dmFields
& DM_POSITION
) && intersect_rect( &intersect
, &intersect
, rect
)) return TRUE
;
2432 /* Get the offset with minimum length to place a display next to the placed displays with no spacing and overlaps */
2433 static POINT
get_placement_offset( const DEVMODEW
*displays
, const DEVMODEW
*placing
)
2435 POINT points
[8], left_top
, offset
, min_offset
= {0, 0};
2436 INT point_idx
, point_count
, vertex_idx
;
2437 BOOL has_placed
= FALSE
, first
= TRUE
;
2438 RECT desired_rect
, rect
;
2439 const DEVMODEW
*mode
;
2442 set_rect_from_devmode( &desired_rect
, placing
);
2444 /* If the display to be placed is detached, no offset is needed to place it */
2445 if (IsRectEmpty( &desired_rect
)) return min_offset
;
2447 /* If there is no placed and attached display, place this display as it is */
2448 for (mode
= displays
; mode
->dmSize
; mode
= NEXT_DEVMODEW(mode
))
2450 set_rect_from_devmode( &rect
, mode
);
2451 if ((mode
->dmFields
& DM_POSITION
) && !IsRectEmpty( &rect
))
2458 if (!has_placed
) return min_offset
;
2460 /* Try to place this display with each of its four vertices at every vertex of the placed
2461 * displays and see which combination has the minimum offset length */
2462 width
= desired_rect
.right
- desired_rect
.left
;
2463 height
= desired_rect
.bottom
- desired_rect
.top
;
2465 for (mode
= displays
; mode
->dmSize
; mode
= NEXT_DEVMODEW(mode
))
2467 set_rect_from_devmode( &rect
, mode
);
2468 if (!(mode
->dmFields
& DM_POSITION
) || IsRectEmpty( &rect
)) continue;
2470 /* Get four vertices of the placed display rectangle */
2471 points
[0].x
= rect
.left
;
2472 points
[0].y
= rect
.top
;
2473 points
[1].x
= rect
.left
;
2474 points
[1].y
= rect
.bottom
;
2475 points
[2].x
= rect
.right
;
2476 points
[2].y
= rect
.top
;
2477 points
[3].x
= rect
.right
;
2478 points
[3].y
= rect
.bottom
;
2481 /* Intersected points when moving the display to be placed horizontally */
2482 if (desired_rect
.bottom
>= rect
.top
&& desired_rect
.top
<= rect
.bottom
)
2484 points
[point_count
].x
= rect
.left
;
2485 points
[point_count
++].y
= desired_rect
.top
;
2486 points
[point_count
].x
= rect
.right
;
2487 points
[point_count
++].y
= desired_rect
.top
;
2489 /* Intersected points when moving the display to be placed vertically */
2490 if (desired_rect
.left
<= rect
.right
&& desired_rect
.right
>= rect
.left
)
2492 points
[point_count
].x
= desired_rect
.left
;
2493 points
[point_count
++].y
= rect
.top
;
2494 points
[point_count
].x
= desired_rect
.left
;
2495 points
[point_count
++].y
= rect
.bottom
;
2498 /* Try moving each vertex of the display rectangle to each points */
2499 for (point_idx
= 0; point_idx
< point_count
; ++point_idx
)
2501 for (vertex_idx
= 0; vertex_idx
< 4; ++vertex_idx
)
2505 /* Move the bottom right vertex to the point */
2507 left_top
.x
= points
[point_idx
].x
- width
;
2508 left_top
.y
= points
[point_idx
].y
- height
;
2510 /* Move the bottom left vertex to the point */
2512 left_top
.x
= points
[point_idx
].x
;
2513 left_top
.y
= points
[point_idx
].y
- height
;
2515 /* Move the top right vertex to the point */
2517 left_top
.x
= points
[point_idx
].x
- width
;
2518 left_top
.y
= points
[point_idx
].y
;
2520 /* Move the top left vertex to the point */
2522 left_top
.x
= points
[point_idx
].x
;
2523 left_top
.y
= points
[point_idx
].y
;
2527 offset
.x
= left_top
.x
- desired_rect
.left
;
2528 offset
.y
= left_top
.y
- desired_rect
.top
;
2529 rect
= desired_rect
;
2530 OffsetRect( &rect
, offset
.x
, offset
.y
);
2531 if (!overlap_placed_displays( &rect
, displays
))
2535 min_offset
= offset
;
2540 if (offset_length( offset
) < offset_length( min_offset
)) min_offset
= offset
;
2549 static void place_all_displays( DEVMODEW
*displays
)
2551 POINT min_offset
, offset
;
2552 DEVMODEW
*mode
, *placing
;
2554 for (mode
= displays
; mode
->dmSize
; mode
= NEXT_DEVMODEW(mode
))
2555 mode
->dmFields
&= ~DM_POSITION
;
2557 /* Place all displays with no extra space between them and no overlapping */
2560 /* Place the unplaced display with the minimum offset length first */
2562 for (mode
= displays
; mode
->dmSize
; mode
= NEXT_DEVMODEW(mode
))
2564 if (mode
->dmFields
& DM_POSITION
) continue;
2566 offset
= get_placement_offset( displays
, mode
);
2567 if (!placing
|| offset_length( offset
) < offset_length( min_offset
))
2569 min_offset
= offset
;
2574 /* If all displays are placed */
2575 if (!placing
) break;
2577 placing
->dmPosition
.x
+= min_offset
.x
;
2578 placing
->dmPosition
.y
+= min_offset
.y
;
2579 placing
->dmFields
|= DM_POSITION
;
2583 static BOOL
all_detached_settings( const DEVMODEW
*displays
)
2585 const DEVMODEW
*mode
;
2587 for (mode
= displays
; mode
->dmSize
; mode
= NEXT_DEVMODEW(mode
))
2588 if (!is_detached_mode( mode
)) return FALSE
;
2593 static LONG
apply_display_settings( const WCHAR
*devname
, const DEVMODEW
*devmode
,
2594 HWND hwnd
, DWORD flags
, void *lparam
)
2596 WCHAR primary_name
[CCHDEVICENAME
];
2597 struct display_device
*primary
;
2598 DEVMODEW
*mode
, *displays
;
2599 struct adapter
*adapter
;
2602 if (!lock_display_devices()) return DISP_CHANGE_FAILED
;
2603 if (!(displays
= get_display_settings( devname
, devmode
)))
2605 unlock_display_devices();
2606 return DISP_CHANGE_FAILED
;
2609 if (all_detached_settings( displays
))
2611 unlock_display_devices();
2612 WARN( "Detaching all modes is not permitted.\n" );
2614 return DISP_CHANGE_SUCCESSFUL
;
2617 place_all_displays( displays
);
2619 if (!(primary
= find_adapter_device_by_id( 0 ))) primary_name
[0] = 0;
2620 else wcscpy( primary_name
, primary
->device_name
);
2622 if ((ret
= user_driver
->pChangeDisplaySettings( displays
, primary_name
, hwnd
, flags
, lparam
)) == E_NOTIMPL
)
2624 /* default implementation: write current display settings to the registry. */
2626 LIST_FOR_EACH_ENTRY( adapter
, &adapters
, struct adapter
, entry
)
2628 if (!adapter_set_current_settings( adapter
, mode
))
2629 WARN( "Failed to write adapter %s current mode.\n", debugstr_w(adapter
->dev
.device_name
) );
2630 mode
= NEXT_DEVMODEW(mode
);
2632 ret
= DISP_CHANGE_SUCCESSFUL
;
2634 unlock_display_devices();
2637 if (ret
) return ret
;
2639 if (!update_display_cache( TRUE
))
2640 WARN( "Failed to update display cache after mode change.\n" );
2642 if ((adapter
= find_adapter( NULL
)))
2644 DEVMODEW current_mode
= {.dmSize
= sizeof(DEVMODEW
)};
2646 if (!adapter_get_current_settings( adapter
, ¤t_mode
)) WARN( "Failed to get primary adapter current display settings.\n" );
2647 adapter_release( adapter
);
2649 send_notify_message( NtUserGetDesktopWindow(), WM_DISPLAYCHANGE
, current_mode
.dmBitsPerPel
,
2650 MAKELPARAM( current_mode
.dmPelsWidth
, current_mode
.dmPelsHeight
), FALSE
);
2651 send_message_timeout( HWND_BROADCAST
, WM_DISPLAYCHANGE
, current_mode
.dmBitsPerPel
,
2652 MAKELPARAM( current_mode
.dmPelsWidth
, current_mode
.dmPelsHeight
),
2653 SMTO_ABORTIFHUNG
, 2000, FALSE
);
2659 /***********************************************************************
2660 * NtUserChangeDisplaySettings (win32u.@)
2662 LONG WINAPI
NtUserChangeDisplaySettings( UNICODE_STRING
*devname
, DEVMODEW
*devmode
, HWND hwnd
,
2663 DWORD flags
, void *lparam
)
2665 DEVMODEW full_mode
= {.dmSize
= sizeof(DEVMODEW
)};
2666 int ret
= DISP_CHANGE_SUCCESSFUL
;
2667 struct adapter
*adapter
;
2669 TRACE( "%s %p %p %#x %p\n", debugstr_us(devname
), devmode
, hwnd
, (int)flags
, lparam
);
2670 TRACE( "flags=%s\n", _CDS_flags(flags
) );
2672 if ((!devname
|| !devname
->Length
) && !devmode
) return apply_display_settings( NULL
, NULL
, hwnd
, flags
, lparam
);
2674 if (!(adapter
= find_adapter( devname
))) return DISP_CHANGE_BADPARAM
;
2676 if (!adapter_get_full_mode( adapter
, devmode
, &full_mode
)) ret
= DISP_CHANGE_BADMODE
;
2677 else if ((flags
& CDS_UPDATEREGISTRY
) && !adapter_set_registry_settings( adapter
, &full_mode
)) ret
= DISP_CHANGE_NOTUPDATED
;
2678 else if (flags
& (CDS_TEST
| CDS_NORESET
)) ret
= DISP_CHANGE_SUCCESSFUL
;
2679 else ret
= apply_display_settings( adapter
->dev
.device_name
, &full_mode
, hwnd
, flags
, lparam
);
2680 adapter_release( adapter
);
2682 if (ret
) ERR( "Changing %s display settings returned %d.\n", debugstr_us(devname
), ret
);
2686 static BOOL
adapter_enum_display_settings( const struct adapter
*adapter
, UINT index
, DEVMODEW
*devmode
, UINT flags
)
2688 DEVMODEW current_mode
= {.dmSize
= sizeof(DEVMODEW
)};
2689 const DEVMODEW
*adapter_mode
;
2691 if (!(flags
& EDS_ROTATEDMODE
) && !adapter_get_current_settings( adapter
, ¤t_mode
))
2693 WARN( "Failed to query current display mode for EDS_ROTATEDMODE flag.\n" );
2697 for (adapter_mode
= adapter
->modes
; adapter_mode
->dmSize
; adapter_mode
= NEXT_DEVMODEW(adapter_mode
))
2699 if (!(flags
& EDS_ROTATEDMODE
) && (adapter_mode
->dmFields
& DM_DISPLAYORIENTATION
) &&
2700 adapter_mode
->dmDisplayOrientation
!= current_mode
.dmDisplayOrientation
)
2702 if (!(flags
& EDS_RAWMODE
) && (adapter_mode
->dmFields
& DM_DISPLAYFLAGS
) &&
2703 (adapter_mode
->dmDisplayFlags
& WINE_DM_UNSUPPORTED
))
2707 memcpy( &devmode
->dmFields
, &adapter_mode
->dmFields
, devmode
->dmSize
- FIELD_OFFSET(DEVMODEW
, dmFields
) );
2708 devmode
->dmDisplayFlags
&= ~WINE_DM_UNSUPPORTED
;
2713 WARN( "device %s, index %#x, flags %#x display mode not found.\n",
2714 debugstr_w( adapter
->dev
.device_name
), index
, flags
);
2715 RtlSetLastWin32Error( ERROR_NO_MORE_FILES
);
2719 /***********************************************************************
2720 * NtUserEnumDisplaySettings (win32u.@)
2722 BOOL WINAPI
NtUserEnumDisplaySettings( UNICODE_STRING
*device
, DWORD index
, DEVMODEW
*devmode
, DWORD flags
)
2724 static const WCHAR wine_display_driverW
[] = {'W','i','n','e',' ','D','i','s','p','l','a','y',' ','D','r','i','v','e','r',0};
2725 struct adapter
*adapter
;
2728 TRACE( "device %s, index %#x, devmode %p, flags %#x\n",
2729 debugstr_us(device
), (int)index
, devmode
, (int)flags
);
2731 if (!(adapter
= find_adapter( device
))) return FALSE
;
2733 lstrcpynW( devmode
->dmDeviceName
, wine_display_driverW
, ARRAY_SIZE(devmode
->dmDeviceName
) );
2734 devmode
->dmSpecVersion
= DM_SPECVERSION
;
2735 devmode
->dmDriverVersion
= DM_SPECVERSION
;
2736 devmode
->dmSize
= offsetof(DEVMODEW
, dmICMMethod
);
2737 devmode
->dmDriverExtra
= 0;
2739 if (index
== ENUM_REGISTRY_SETTINGS
) ret
= adapter_get_registry_settings( adapter
, devmode
);
2740 else if (index
== ENUM_CURRENT_SETTINGS
) ret
= adapter_get_current_settings( adapter
, devmode
);
2741 else ret
= adapter_enum_display_settings( adapter
, index
, devmode
, flags
);
2742 adapter_release( adapter
);
2744 if (!ret
) WARN( "Failed to query %s display settings.\n", debugstr_us(device
) );
2745 else TRACE( "position %dx%d, resolution %ux%u, frequency %u, depth %u, orientation %#x.\n",
2746 (int)devmode
->dmPosition
.x
, (int)devmode
->dmPosition
.y
, (int)devmode
->dmPelsWidth
,
2747 (int)devmode
->dmPelsHeight
, (int)devmode
->dmDisplayFrequency
,
2748 (int)devmode
->dmBitsPerPel
, (int)devmode
->dmDisplayOrientation
);
2752 struct monitor_enum_info
2758 static unsigned int active_monitor_count(void)
2760 struct monitor
*monitor
;
2761 unsigned int count
= 0;
2763 LIST_FOR_EACH_ENTRY(monitor
, &monitors
, struct monitor
, entry
)
2765 if ((monitor
->dev
.state_flags
& DISPLAY_DEVICE_ACTIVE
)) count
++;
2770 INT
get_display_depth( UNICODE_STRING
*name
)
2772 struct display_device
*device
;
2776 if (!lock_display_devices())
2779 if (name
&& name
->Length
)
2780 device
= find_adapter_device_by_name( name
);
2782 device
= find_adapter_device_by_id( 0 ); /* use primary adapter */
2786 unlock_display_devices();
2790 is_primary
= !!(device
->state_flags
& DISPLAY_DEVICE_PRIMARY_DEVICE
);
2791 if ((depth
= user_driver
->pGetDisplayDepth( device
->device_name
, is_primary
)) < 0)
2793 struct adapter
*adapter
= CONTAINING_RECORD( device
, struct adapter
, dev
);
2794 DEVMODEW current_mode
= {.dmSize
= sizeof(DEVMODEW
)};
2796 if (!adapter_get_current_settings( adapter
, ¤t_mode
)) depth
= 32;
2797 else depth
= current_mode
.dmBitsPerPel
;
2800 unlock_display_devices();
2804 /***********************************************************************
2805 * NtUserEnumDisplayMonitors (win32u.@)
2807 BOOL WINAPI
NtUserEnumDisplayMonitors( HDC hdc
, RECT
*rect
, MONITORENUMPROC proc
, LPARAM lparam
)
2809 struct monitor_enum_info enum_buf
[8], *enum_info
= enum_buf
;
2810 struct enum_display_monitor_params params
;
2811 struct monitor
*monitor
;
2812 unsigned int count
= 0, i
;
2820 if (!(dc
= get_dc_ptr( hdc
))) return FALSE
;
2821 origin
.x
= dc
->attr
->vis_rect
.left
;
2822 origin
.y
= dc
->attr
->vis_rect
.top
;
2823 release_dc_ptr( dc
);
2824 if (NtGdiGetAppClipBox( hdc
, &limit
) == ERROR
) return FALSE
;
2828 origin
.x
= origin
.y
= 0;
2829 limit
.left
= limit
.top
= INT_MIN
;
2830 limit
.right
= limit
.bottom
= INT_MAX
;
2832 if (rect
&& !intersect_rect( &limit
, &limit
, rect
)) return TRUE
;
2834 if (!lock_display_devices()) return FALSE
;
2836 count
= list_count( &monitors
);
2837 if (!count
|| (count
> ARRAYSIZE(enum_buf
) &&
2838 !(enum_info
= malloc( count
* sizeof(*enum_info
) ))))
2840 unlock_display_devices();
2845 LIST_FOR_EACH_ENTRY(monitor
, &monitors
, struct monitor
, entry
)
2849 if (!(monitor
->dev
.state_flags
& DISPLAY_DEVICE_ACTIVE
)) continue;
2851 monrect
= map_dpi_rect( monitor
->rc_monitor
, get_monitor_dpi( monitor
->handle
),
2853 OffsetRect( &monrect
, -origin
.x
, -origin
.y
);
2854 if (!intersect_rect( &monrect
, &monrect
, &limit
)) continue;
2855 if (monitor
->is_clone
) continue;
2857 enum_info
[count
].handle
= monitor
->handle
;
2858 enum_info
[count
].rect
= monrect
;
2862 unlock_display_devices();
2866 params
.lparam
= lparam
;
2867 for (i
= 0; i
< count
; i
++)
2871 params
.monitor
= enum_info
[i
].handle
;
2872 params
.rect
= enum_info
[i
].rect
;
2873 if (!KeUserModeCallback( NtUserCallEnumDisplayMonitor
, ¶ms
, sizeof(params
),
2874 &ret_ptr
, &ret_len
))
2880 if (enum_info
!= enum_buf
) free( enum_info
);
2884 BOOL
get_monitor_info( HMONITOR handle
, MONITORINFO
*info
)
2886 struct monitor
*monitor
;
2887 UINT dpi_from
, dpi_to
;
2889 if (info
->cbSize
!= sizeof(MONITORINFOEXW
) && info
->cbSize
!= sizeof(MONITORINFO
)) return FALSE
;
2891 if (!lock_display_devices()) return FALSE
;
2893 LIST_FOR_EACH_ENTRY( monitor
, &monitors
, struct monitor
, entry
)
2895 if (monitor
->handle
!= handle
) continue;
2896 if (!(monitor
->dev
.state_flags
& DISPLAY_DEVICE_ACTIVE
)) break;
2898 /* FIXME: map dpi */
2899 info
->rcMonitor
= monitor
->rc_monitor
;
2900 info
->rcWork
= monitor
->rc_work
;
2901 info
->dwFlags
= monitor
->flags
;
2902 if (info
->cbSize
>= sizeof(MONITORINFOEXW
))
2904 if (monitor
->adapter
)
2905 lstrcpyW( ((MONITORINFOEXW
*)info
)->szDevice
, monitor
->adapter
->dev
.device_name
);
2907 asciiz_to_unicode( ((MONITORINFOEXW
*)info
)->szDevice
, "WinDisc" );
2909 unlock_display_devices();
2911 if ((dpi_to
= get_thread_dpi()))
2913 dpi_from
= get_monitor_dpi( handle
);
2914 info
->rcMonitor
= map_dpi_rect( info
->rcMonitor
, dpi_from
, dpi_to
);
2915 info
->rcWork
= map_dpi_rect( info
->rcWork
, dpi_from
, dpi_to
);
2917 TRACE( "flags %04x, monitor %s, work %s\n", (int)info
->dwFlags
,
2918 wine_dbgstr_rect(&info
->rcMonitor
), wine_dbgstr_rect(&info
->rcWork
));
2922 unlock_display_devices();
2923 WARN( "invalid handle %p\n", handle
);
2924 RtlSetLastWin32Error( ERROR_INVALID_MONITOR_HANDLE
);
2928 HMONITOR
monitor_from_rect( const RECT
*rect
, UINT flags
, UINT dpi
)
2930 HMONITOR primary
= 0, nearest
= 0, ret
= 0;
2931 UINT max_area
= 0, min_distance
= ~0u;
2932 struct monitor
*monitor
;
2935 r
= map_dpi_rect( *rect
, dpi
, system_dpi
);
2936 if (IsRectEmpty( &r
))
2938 r
.right
= r
.left
+ 1;
2939 r
.bottom
= r
.top
+ 1;
2942 if (!lock_display_devices()) return 0;
2944 LIST_FOR_EACH_ENTRY(monitor
, &monitors
, struct monitor
, entry
)
2947 RECT monitor_rect
= map_dpi_rect( monitor
->rc_monitor
, get_monitor_dpi( monitor
->handle
),
2950 if (intersect_rect( &intersect
, &monitor_rect
, &r
))
2952 /* check for larger intersecting area */
2953 UINT area
= (intersect
.right
- intersect
.left
) * (intersect
.bottom
- intersect
.top
);
2954 if (area
> max_area
)
2957 ret
= monitor
->handle
;
2960 else if (!max_area
) /* if not intersecting, check for min distance */
2965 if (r
.right
<= monitor_rect
.left
) x
= monitor_rect
.left
- r
.right
;
2966 else if (monitor_rect
.right
<= r
.left
) x
= r
.left
- monitor_rect
.right
;
2968 if (r
.bottom
<= monitor_rect
.top
) y
= monitor_rect
.top
- r
.bottom
;
2969 else if (monitor_rect
.bottom
<= r
.top
) y
= r
.top
- monitor_rect
.bottom
;
2971 distance
= x
* x
+ y
* y
;
2972 if (distance
< min_distance
)
2974 min_distance
= distance
;
2975 nearest
= monitor
->handle
;
2979 if (monitor
->flags
& MONITORINFOF_PRIMARY
) primary
= monitor
->handle
;
2982 unlock_display_devices();
2986 if (flags
& MONITOR_DEFAULTTOPRIMARY
) ret
= primary
;
2987 else if (flags
& MONITOR_DEFAULTTONEAREST
) ret
= nearest
;
2990 TRACE( "%s flags %x returning %p\n", wine_dbgstr_rect(rect
), flags
, ret
);
2994 HMONITOR
monitor_from_point( POINT pt
, UINT flags
, UINT dpi
)
2997 SetRect( &rect
, pt
.x
, pt
.y
, pt
.x
+ 1, pt
.y
+ 1 );
2998 return monitor_from_rect( &rect
, flags
, dpi
);
3001 /* see MonitorFromWindow */
3002 HMONITOR
monitor_from_window( HWND hwnd
, UINT flags
, UINT dpi
)
3007 TRACE( "(%p, 0x%08x)\n", hwnd
, flags
);
3009 wp
.length
= sizeof(wp
);
3010 if (is_iconic( hwnd
) && NtUserGetWindowPlacement( hwnd
, &wp
))
3011 return monitor_from_rect( &wp
.rcNormalPosition
, flags
, dpi
);
3013 if (get_window_rect( hwnd
, &rect
, dpi
))
3014 return monitor_from_rect( &rect
, flags
, dpi
);
3016 if (!(flags
& (MONITOR_DEFAULTTOPRIMARY
|MONITOR_DEFAULTTONEAREST
))) return 0;
3017 /* retrieve the primary */
3018 SetRect( &rect
, 0, 0, 1, 1 );
3019 return monitor_from_rect( &rect
, flags
, dpi
);
3022 /***********************************************************************
3023 * NtUserGetSystemDpiForProcess (win32u.@)
3025 ULONG WINAPI
NtUserGetSystemDpiForProcess( HANDLE process
)
3027 if (process
&& process
!= GetCurrentProcess())
3029 FIXME( "not supported on other process %p\n", process
);
3036 /***********************************************************************
3037 * NtUserGetDpiForMonitor (win32u.@)
3039 BOOL WINAPI
NtUserGetDpiForMonitor( HMONITOR monitor
, UINT type
, UINT
*x
, UINT
*y
)
3043 RtlSetLastWin32Error( ERROR_BAD_ARGUMENTS
);
3048 RtlSetLastWin32Error( ERROR_INVALID_ADDRESS
);
3051 switch (get_thread_dpi_awareness())
3053 case DPI_AWARENESS_UNAWARE
: *x
= *y
= USER_DEFAULT_SCREEN_DPI
; break;
3054 case DPI_AWARENESS_SYSTEM_AWARE
: *x
= *y
= system_dpi
; break;
3055 default: *x
= *y
= get_monitor_dpi( monitor
); break;
3060 /**********************************************************************
3061 * LogicalToPhysicalPointForPerMonitorDPI (win32u.@)
3063 BOOL WINAPI
NtUserLogicalToPerMonitorDPIPhysicalPoint( HWND hwnd
, POINT
*pt
)
3067 if (!get_window_rect( hwnd
, &rect
, get_thread_dpi() )) return FALSE
;
3068 if (pt
->x
< rect
.left
|| pt
->y
< rect
.top
|| pt
->x
> rect
.right
|| pt
->y
> rect
.bottom
) return FALSE
;
3069 *pt
= point_win_to_phys_dpi( hwnd
, *pt
);
3073 /**********************************************************************
3074 * NtUserPerMonitorDPIPhysicalToLogicalPoint (win32u.@)
3076 BOOL WINAPI
NtUserPerMonitorDPIPhysicalToLogicalPoint( HWND hwnd
, POINT
*pt
)
3081 if (get_window_rect( hwnd
, &rect
, 0 ) &&
3082 pt
->x
>= rect
.left
&& pt
->y
>= rect
.top
&& pt
->x
<= rect
.right
&& pt
->y
<= rect
.bottom
)
3084 *pt
= point_phys_to_win_dpi( hwnd
, *pt
);
3090 /* retrieve the cached base keys for a given entry */
3091 static BOOL
get_base_keys( enum parameter_key index
, HKEY
*base_key
, HKEY
*volatile_key
)
3093 static HKEY base_keys
[NB_PARAM_KEYS
];
3094 static HKEY volatile_keys
[NB_PARAM_KEYS
];
3098 if (!base_keys
[index
] && base_key
)
3100 if (!(key
= reg_create_key( hkcu_key
, bufferW
,
3101 asciiz_to_unicode( bufferW
, parameter_key_names
[index
] ) - sizeof(WCHAR
),
3104 if (InterlockedCompareExchangePointer( (void **)&base_keys
[index
], key
, 0 ))
3107 if (!volatile_keys
[index
] && volatile_key
)
3109 if (!(key
= reg_create_key( volatile_base_key
, bufferW
,
3110 asciiz_to_unicode( bufferW
, parameter_key_names
[index
] ) - sizeof(WCHAR
),
3111 REG_OPTION_VOLATILE
, NULL
)))
3113 if (InterlockedCompareExchangePointer( (void **)&volatile_keys
[index
], key
, 0 ))
3116 if (base_key
) *base_key
= base_keys
[index
];
3117 if (volatile_key
) *volatile_key
= volatile_keys
[index
];
3121 /* load a value to a registry entry */
3122 static DWORD
load_entry( struct sysparam_entry
*entry
, void *data
, DWORD size
)
3125 KEY_VALUE_PARTIAL_INFORMATION
*value
= (void *)buffer
;
3127 HKEY base_key
, volatile_key
;
3129 if (!get_base_keys( entry
->base_key
, &base_key
, &volatile_key
)) return FALSE
;
3131 if (!(count
= query_reg_ascii_value( volatile_key
, entry
->regval
, value
, sizeof(buffer
) )))
3132 count
= query_reg_ascii_value( base_key
, entry
->regval
, value
, sizeof(buffer
) );
3136 /* make sure strings are null-terminated */
3137 if (value
->Type
== REG_SZ
) ((WCHAR
*)value
->Data
)[count
/ sizeof(WCHAR
) - 1] = 0;
3139 if (count
) memcpy( data
, value
->Data
, count
);
3140 entry
->loaded
= TRUE
;
3144 /* save a value to a registry entry */
3145 static BOOL
save_entry( const struct sysparam_entry
*entry
, const void *data
, DWORD size
,
3146 DWORD type
, UINT flags
)
3148 HKEY base_key
, volatile_key
;
3151 asciiz_to_unicode( nameW
, entry
->regval
);
3152 if (flags
& SPIF_UPDATEINIFILE
)
3154 if (!get_base_keys( entry
->base_key
, &base_key
, &volatile_key
)) return FALSE
;
3155 if (!set_reg_value( base_key
, nameW
, type
, data
, size
)) return FALSE
;
3156 reg_delete_value( volatile_key
, nameW
);
3158 if (entry
->mirror
&& get_base_keys( entry
->mirror_key
, &base_key
, NULL
))
3160 asciiz_to_unicode( nameW
, entry
->mirror
);
3161 set_reg_value( base_key
, nameW
, type
, data
, size
);
3166 if (!get_base_keys( entry
->base_key
, NULL
, &volatile_key
)) return FALSE
;
3167 if (!set_reg_value( volatile_key
, nameW
, type
, data
, size
)) return FALSE
;
3172 /* save a string value to a registry entry */
3173 static BOOL
save_entry_string( const struct sysparam_entry
*entry
, const WCHAR
*str
, UINT flags
)
3175 return save_entry( entry
, str
, (lstrlenW(str
) + 1) * sizeof(WCHAR
), REG_SZ
, flags
);
3178 /* initialize an entry in the registry if missing */
3179 static BOOL
init_entry( struct sysparam_entry
*entry
, const void *data
, DWORD size
, DWORD type
)
3181 KEY_VALUE_PARTIAL_INFORMATION value
;
3182 UNICODE_STRING name
;
3188 if (!get_base_keys( entry
->base_key
, &base_key
, NULL
)) return FALSE
;
3190 name
.Buffer
= nameW
;
3191 name
.MaximumLength
= asciiz_to_unicode( nameW
, entry
->regval
);
3192 name
.Length
= name
.MaximumLength
- sizeof(WCHAR
);
3193 status
= NtQueryValueKey( base_key
, &name
, KeyValuePartialInformation
,
3194 &value
, sizeof(value
), &count
);
3195 if (!status
|| status
== STATUS_BUFFER_OVERFLOW
) return TRUE
;
3197 if (!set_reg_value( base_key
, nameW
, type
, data
, size
)) return FALSE
;
3198 if (entry
->mirror
&& get_base_keys( entry
->mirror_key
, &base_key
, NULL
))
3200 asciiz_to_unicode( nameW
, entry
->mirror
);
3201 set_reg_value( base_key
, nameW
, type
, data
, size
);
3203 entry
->loaded
= TRUE
;
3207 /* initialize a string value in the registry if missing */
3208 static BOOL
init_entry_string( struct sysparam_entry
*entry
, const WCHAR
*str
)
3210 return init_entry( entry
, str
, (lstrlenW(str
) + 1) * sizeof(WCHAR
), REG_SZ
);
3213 /* set an int parameter in the registry */
3214 static BOOL
set_int_entry( union sysparam_all_entry
*entry
, UINT int_param
, void *ptr_param
, UINT flags
)
3219 sprintf( buf
, "%d", int_param
);
3220 asciiz_to_unicode( bufW
, buf
);
3221 if (!save_entry_string( &entry
->hdr
, bufW
, flags
)) return FALSE
;
3222 entry
->uint
.val
= int_param
;
3223 entry
->hdr
.loaded
= TRUE
;
3227 /* initialize an int parameter */
3228 static BOOL
init_int_entry( union sysparam_all_entry
*entry
)
3233 sprintf( buf
, "%d", entry
->uint
.val
);
3234 asciiz_to_unicode( bufW
, buf
);
3235 return init_entry_string( &entry
->hdr
, bufW
);
3238 /* load a uint parameter from the registry */
3239 static BOOL
get_uint_entry( union sysparam_all_entry
*entry
, UINT int_param
, void *ptr_param
, UINT dpi
)
3241 if (!ptr_param
) return FALSE
;
3243 if (!entry
->hdr
.loaded
)
3246 if (load_entry( &entry
->hdr
, buf
, sizeof(buf
) )) entry
->uint
.val
= wcstol( buf
, NULL
, 10 );
3248 *(UINT
*)ptr_param
= entry
->uint
.val
;
3252 /* set a uint parameter in the registry */
3253 static BOOL
set_uint_entry( union sysparam_all_entry
*entry
, UINT int_param
, void *ptr_param
, UINT flags
)
3258 sprintf( buf
, "%u", int_param
);
3259 asciiz_to_unicode( bufW
, buf
);
3260 if (!save_entry_string( &entry
->hdr
, bufW
, flags
)) return FALSE
;
3261 entry
->uint
.val
= int_param
;
3262 entry
->hdr
.loaded
= TRUE
;
3266 /* initialize a uint parameter */
3267 static BOOL
init_uint_entry( union sysparam_all_entry
*entry
)
3272 sprintf( buf
, "%u", entry
->uint
.val
);
3273 asciiz_to_unicode( bufW
, buf
);
3274 return init_entry_string( &entry
->hdr
, bufW
);
3277 /* load a twips parameter from the registry */
3278 static BOOL
get_twips_entry( union sysparam_all_entry
*entry
, UINT int_param
, void *ptr_param
, UINT dpi
)
3282 if (!ptr_param
) return FALSE
;
3284 if (!entry
->hdr
.loaded
)
3287 if (load_entry( &entry
->hdr
, buf
, sizeof(buf
) )) entry
->uint
.val
= wcstol( buf
, NULL
, 10 );
3290 /* Dimensions are quoted as being "twips" values if negative and pixels if positive.
3291 * One inch is 1440 twips.
3293 * Technical Reference to the Windows 2000 Registry ->
3294 * HKEY_CURRENT_USER -> Control Panel -> Desktop -> WindowMetrics
3296 val
= entry
->uint
.val
;
3298 val
= muldiv( -val
, dpi
, 1440 );
3300 val
= map_to_dpi( val
, dpi
);
3302 *(int *)ptr_param
= val
;
3306 /* set a twips parameter in the registry */
3307 static BOOL
set_twips_entry( union sysparam_all_entry
*entry
, UINT int_param
, void *ptr_param
, UINT flags
)
3309 int val
= int_param
;
3310 if (val
> 0) val
= map_from_system_dpi( val
);
3311 return set_int_entry( entry
, val
, ptr_param
, flags
);
3314 /* load a bool parameter from the registry */
3315 static BOOL
get_bool_entry( union sysparam_all_entry
*entry
, UINT int_param
, void *ptr_param
, UINT dpi
)
3317 if (!ptr_param
) return FALSE
;
3319 if (!entry
->hdr
.loaded
)
3322 if (load_entry( &entry
->hdr
, buf
, sizeof(buf
) )) entry
->bool.val
= wcstol( buf
, NULL
, 10 ) != 0;
3324 *(UINT
*)ptr_param
= entry
->bool.val
;
3328 /* set a bool parameter in the registry */
3329 static BOOL
set_bool_entry( union sysparam_all_entry
*entry
, UINT int_param
, void *ptr_param
, UINT flags
)
3331 WCHAR buf
[] = { int_param
? '1' : '0', 0 };
3333 if (!save_entry_string( &entry
->hdr
, buf
, flags
)) return FALSE
;
3334 entry
->bool.val
= int_param
!= 0;
3335 entry
->hdr
.loaded
= TRUE
;
3339 /* initialize a bool parameter */
3340 static BOOL
init_bool_entry( union sysparam_all_entry
*entry
)
3342 WCHAR buf
[] = { entry
->bool.val
? '1' : '0', 0 };
3344 return init_entry_string( &entry
->hdr
, buf
);
3347 /* load a bool parameter using Yes/No strings from the registry */
3348 static BOOL
get_yesno_entry( union sysparam_all_entry
*entry
, UINT int_param
, void *ptr_param
, UINT dpi
)
3350 if (!ptr_param
) return FALSE
;
3352 if (!entry
->hdr
.loaded
)
3355 if (load_entry( &entry
->hdr
, buf
, sizeof(buf
) )) entry
->bool.val
= !wcsicmp( yesW
, buf
);
3357 *(UINT
*)ptr_param
= entry
->bool.val
;
3361 /* set a bool parameter using Yes/No strings from the registry */
3362 static BOOL
set_yesno_entry( union sysparam_all_entry
*entry
, UINT int_param
, void *ptr_param
, UINT flags
)
3364 const WCHAR
*str
= int_param
? yesW
: noW
;
3366 if (!save_entry_string( &entry
->hdr
, str
, flags
)) return FALSE
;
3367 entry
->bool.val
= int_param
!= 0;
3368 entry
->hdr
.loaded
= TRUE
;
3372 /* initialize a bool parameter using Yes/No strings */
3373 static BOOL
init_yesno_entry( union sysparam_all_entry
*entry
)
3375 return init_entry_string( &entry
->hdr
, entry
->bool.val
? yesW
: noW
);
3378 /* load a dword (binary) parameter from the registry */
3379 static BOOL
get_dword_entry( union sysparam_all_entry
*entry
, UINT int_param
, void *ptr_param
, UINT dpi
)
3381 if (!ptr_param
) return FALSE
;
3383 if (!entry
->hdr
.loaded
)
3386 if (load_entry( &entry
->hdr
, &val
, sizeof(val
) ) == sizeof(DWORD
)) entry
->dword
.val
= val
;
3388 *(DWORD
*)ptr_param
= entry
->dword
.val
;
3392 /* set a dword (binary) parameter in the registry */
3393 static BOOL
set_dword_entry( union sysparam_all_entry
*entry
, UINT int_param
, void *ptr_param
, UINT flags
)
3395 DWORD val
= PtrToUlong( ptr_param
);
3397 if (!save_entry( &entry
->hdr
, &val
, sizeof(val
), REG_DWORD
, flags
)) return FALSE
;
3398 entry
->dword
.val
= val
;
3399 entry
->hdr
.loaded
= TRUE
;
3403 /* initialize a dword parameter */
3404 static BOOL
init_dword_entry( union sysparam_all_entry
*entry
)
3406 return init_entry( &entry
->hdr
, &entry
->dword
.val
, sizeof(entry
->dword
.val
), REG_DWORD
);
3409 /* load an RGB parameter from the registry */
3410 static BOOL
get_rgb_entry( union sysparam_all_entry
*entry
, UINT int_param
, void *ptr_param
, UINT dpi
)
3412 if (!ptr_param
) return FALSE
;
3414 if (!entry
->hdr
.loaded
)
3418 if (load_entry( &entry
->hdr
, buf
, sizeof(buf
) ))
3421 WCHAR
*end
, *str
= buf
;
3423 r
= wcstoul( str
, &end
, 10 );
3424 if (end
== str
|| !*end
) goto done
;
3426 g
= wcstoul( str
, &end
, 10 );
3427 if (end
== str
|| !*end
) goto done
;
3429 b
= wcstoul( str
, &end
, 10 );
3430 if (end
== str
) goto done
;
3431 if (r
> 255 || g
> 255 || b
> 255) goto done
;
3432 entry
->rgb
.val
= RGB( r
, g
, b
);
3436 *(COLORREF
*)ptr_param
= entry
->rgb
.val
;
3440 /* set an RGB parameter in the registry */
3441 static BOOL
set_rgb_entry( union sysparam_all_entry
*entry
, UINT int_param
, void *ptr_param
, UINT flags
)
3448 sprintf( buf
, "%u %u %u", GetRValue(int_param
), GetGValue(int_param
), GetBValue(int_param
) );
3449 asciiz_to_unicode( bufW
, buf
);
3450 if (!save_entry_string( &entry
->hdr
, bufW
, flags
)) return FALSE
;
3451 entry
->rgb
.val
= int_param
;
3452 entry
->hdr
.loaded
= TRUE
;
3453 if ((brush
= InterlockedExchangePointer( (void **)&entry
->rgb
.brush
, 0 )))
3455 make_gdi_object_system( brush
, FALSE
);
3456 NtGdiDeleteObjectApp( brush
);
3458 if ((pen
= InterlockedExchangePointer( (void **)&entry
->rgb
.pen
, 0 )))
3460 make_gdi_object_system( pen
, FALSE
);
3461 NtGdiDeleteObjectApp( pen
);
3466 /* initialize an RGB parameter */
3467 static BOOL
init_rgb_entry( union sysparam_all_entry
*entry
)
3472 sprintf( buf
, "%u %u %u", GetRValue(entry
->rgb
.val
), GetGValue(entry
->rgb
.val
),
3473 GetBValue(entry
->rgb
.val
) );
3474 asciiz_to_unicode( bufW
, buf
);
3475 return init_entry_string( &entry
->hdr
, bufW
);
3478 /* get a path parameter in the registry */
3479 static BOOL
get_path_entry( union sysparam_all_entry
*entry
, UINT int_param
, void *ptr_param
, UINT dpi
)
3481 if (!ptr_param
) return FALSE
;
3483 if (!entry
->hdr
.loaded
)
3485 WCHAR buffer
[MAX_PATH
];
3487 if (load_entry( &entry
->hdr
, buffer
, sizeof(buffer
) ))
3488 lstrcpynW( entry
->path
.path
, buffer
, MAX_PATH
);
3490 lstrcpynW( ptr_param
, entry
->path
.path
, int_param
);
3494 /* set a path parameter in the registry */
3495 static BOOL
set_path_entry( union sysparam_all_entry
*entry
, UINT int_param
, void *ptr_param
, UINT flags
)
3497 WCHAR buffer
[MAX_PATH
];
3500 lstrcpynW( buffer
, ptr_param
, MAX_PATH
);
3501 ret
= save_entry_string( &entry
->hdr
, buffer
, flags
);
3504 lstrcpyW( entry
->path
.path
, buffer
);
3505 entry
->hdr
.loaded
= TRUE
;
3510 /* initialize a path parameter */
3511 static BOOL
init_path_entry( union sysparam_all_entry
*entry
)
3513 return init_entry_string( &entry
->hdr
, entry
->path
.path
);
3516 /* get a binary parameter in the registry */
3517 static BOOL
get_binary_entry( union sysparam_all_entry
*entry
, UINT int_param
, void *ptr_param
, UINT dpi
)
3519 if (!ptr_param
) return FALSE
;
3521 if (!entry
->hdr
.loaded
)
3523 void *buffer
= malloc( entry
->bin
.size
);
3524 DWORD len
= load_entry( &entry
->hdr
, buffer
, entry
->bin
.size
);
3528 memcpy( entry
->bin
.ptr
, buffer
, entry
->bin
.size
);
3529 memset( (char *)entry
->bin
.ptr
+ len
, 0, entry
->bin
.size
- len
);
3533 memcpy( ptr_param
, entry
->bin
.ptr
, min( int_param
, entry
->bin
.size
) );
3537 /* set a binary parameter in the registry */
3538 static BOOL
set_binary_entry( union sysparam_all_entry
*entry
, UINT int_param
, void *ptr_param
, UINT flags
)
3541 void *buffer
= malloc( entry
->bin
.size
);
3543 memcpy( buffer
, entry
->bin
.ptr
, entry
->bin
.size
);
3544 memcpy( buffer
, ptr_param
, min( int_param
, entry
->bin
.size
));
3545 ret
= save_entry( &entry
->hdr
, buffer
, entry
->bin
.size
, REG_BINARY
, flags
);
3548 memcpy( entry
->bin
.ptr
, buffer
, entry
->bin
.size
);
3549 entry
->hdr
.loaded
= TRUE
;
3555 /* initialize a binary parameter */
3556 static BOOL
init_binary_entry( union sysparam_all_entry
*entry
)
3558 return init_entry( &entry
->hdr
, entry
->bin
.ptr
, entry
->bin
.size
, REG_BINARY
);
3561 static void logfont16to32( const LOGFONT16
*font16
, LPLOGFONTW font32
)
3563 font32
->lfHeight
= font16
->lfHeight
;
3564 font32
->lfWidth
= font16
->lfWidth
;
3565 font32
->lfEscapement
= font16
->lfEscapement
;
3566 font32
->lfOrientation
= font16
->lfOrientation
;
3567 font32
->lfWeight
= font16
->lfWeight
;
3568 font32
->lfItalic
= font16
->lfItalic
;
3569 font32
->lfUnderline
= font16
->lfUnderline
;
3570 font32
->lfStrikeOut
= font16
->lfStrikeOut
;
3571 font32
->lfCharSet
= font16
->lfCharSet
;
3572 font32
->lfOutPrecision
= font16
->lfOutPrecision
;
3573 font32
->lfClipPrecision
= font16
->lfClipPrecision
;
3574 font32
->lfQuality
= font16
->lfQuality
;
3575 font32
->lfPitchAndFamily
= font16
->lfPitchAndFamily
;
3576 win32u_mbtowc( &ansi_cp
, font32
->lfFaceName
, LF_FACESIZE
, font16
->lfFaceName
,
3577 strlen( font16
->lfFaceName
));
3578 font32
->lfFaceName
[LF_FACESIZE
-1] = 0;
3581 static void get_real_fontname( LOGFONTW
*lf
, WCHAR fullname
[LF_FACESIZE
] )
3583 struct font_enum_entry enum_entry
;
3584 ULONG count
= sizeof(enum_entry
);
3587 hdc
= get_display_dc();
3588 NtGdiEnumFonts( hdc
, 0, 0, lstrlenW( lf
->lfFaceName
), lf
->lfFaceName
, lf
->lfCharSet
,
3589 &count
, &enum_entry
);
3590 release_display_dc( hdc
);
3593 lstrcpyW( fullname
, enum_entry
.lf
.elfFullName
);
3595 lstrcpyW( fullname
, lf
->lfFaceName
);
3598 LONG
get_char_dimensions( HDC hdc
, TEXTMETRICW
*metric
, int *height
)
3601 static const WCHAR abcdW
[] =
3602 {'a','b','c','d','e','f','g','h','i','j','k','l','m','n','o','p','q',
3603 'r','s','t','u','v','w','x','y','z','A','B','C','D','E','F','G','H',
3604 'I','J','K','L','M','N','O','P','Q','R','S','T','U','V','W','X','Y','Z'};
3606 if (metric
&& !NtGdiGetTextMetricsW( hdc
, metric
, 0 )) return 0;
3608 if (!NtGdiGetTextExtentExW( hdc
, abcdW
, ARRAYSIZE(abcdW
), 0, NULL
, NULL
, &sz
, 0 ))
3611 if (height
) *height
= sz
.cy
;
3612 return (sz
.cx
/ 26 + 1) / 2;
3615 /* get text metrics and/or "average" char width of the specified logfont
3616 * for the specified dc */
3617 static void get_text_metr_size( HDC hdc
, LOGFONTW
*lf
, TEXTMETRICW
*metric
, UINT
*psz
)
3619 HFONT hfont
, hfontsav
;
3622 if (!metric
) metric
= &tm
;
3623 hfont
= NtGdiHfontCreate( lf
, sizeof(*lf
), 0, 0, NULL
);
3624 if (!hfont
|| !(hfontsav
= NtGdiSelectFont( hdc
, hfont
)))
3626 metric
->tmHeight
= -1;
3628 if (hfont
) NtGdiDeleteObjectApp( hfont
);
3631 ret
= get_char_dimensions( hdc
, metric
, NULL
);
3632 if (psz
) *psz
= ret
? ret
: 10;
3633 NtGdiSelectFont( hdc
, hfontsav
);
3634 NtGdiDeleteObjectApp( hfont
);
3637 DWORD
get_dialog_base_units(void)
3645 if ((hdc
= NtUserGetDC( 0 )))
3647 cx
= get_char_dimensions( hdc
, NULL
, &cy
);
3648 NtUserReleaseDC( 0, hdc
);
3650 TRACE( "base units = %d,%d\n", cx
, cy
);
3653 return MAKELONG( muldiv( cx
, get_system_dpi(), USER_DEFAULT_SCREEN_DPI
),
3654 muldiv( cy
, get_system_dpi(), USER_DEFAULT_SCREEN_DPI
));
3657 /* adjust some of the raw values found in the registry */
3658 static void normalize_nonclientmetrics( NONCLIENTMETRICSW
*pncm
)
3661 HDC hdc
= get_display_dc();
3663 if( pncm
->iBorderWidth
< 1) pncm
->iBorderWidth
= 1;
3664 if( pncm
->iCaptionWidth
< 8) pncm
->iCaptionWidth
= 8;
3665 if( pncm
->iScrollWidth
< 8) pncm
->iScrollWidth
= 8;
3666 if( pncm
->iScrollHeight
< 8) pncm
->iScrollHeight
= 8;
3668 /* adjust some heights to the corresponding font */
3669 get_text_metr_size( hdc
, &pncm
->lfMenuFont
, &tm
, NULL
);
3670 pncm
->iMenuHeight
= max( pncm
->iMenuHeight
, 2 + tm
.tmHeight
+ tm
.tmExternalLeading
);
3671 get_text_metr_size( hdc
, &pncm
->lfCaptionFont
, &tm
, NULL
);
3672 pncm
->iCaptionHeight
= max( pncm
->iCaptionHeight
, 2 + tm
.tmHeight
);
3673 get_text_metr_size( hdc
, &pncm
->lfSmCaptionFont
, &tm
, NULL
);
3674 pncm
->iSmCaptionHeight
= max( pncm
->iSmCaptionHeight
, 2 + tm
.tmHeight
);
3675 release_display_dc( hdc
);
3678 /* load a font (binary) parameter from the registry */
3679 static BOOL
get_font_entry( union sysparam_all_entry
*entry
, UINT int_param
, void *ptr_param
, UINT dpi
)
3683 if (!ptr_param
) return FALSE
;
3685 if (!entry
->hdr
.loaded
)
3687 switch (load_entry( &entry
->hdr
, &font
, sizeof(font
) ))
3690 if (font
.lfHeight
> 0) /* positive height value means points ( inch/72 ) */
3691 font
.lfHeight
= -muldiv( font
.lfHeight
, USER_DEFAULT_SCREEN_DPI
, 72 );
3692 entry
->font
.val
= font
;
3694 case sizeof(LOGFONT16
): /* win9x-winME format */
3695 logfont16to32( (LOGFONT16
*)&font
, &entry
->font
.val
);
3696 if (entry
->font
.val
.lfHeight
> 0)
3697 entry
->font
.val
.lfHeight
= -muldiv( entry
->font
.val
.lfHeight
, USER_DEFAULT_SCREEN_DPI
, 72 );
3700 WARN( "Unknown format in key %s value %s\n",
3701 debugstr_a( parameter_key_names
[entry
->hdr
.base_key
] ),
3702 debugstr_a( entry
->hdr
.regval
));
3704 case 0: /* use the default GUI font */
3705 NtGdiExtGetObjectW( GetStockObject( DEFAULT_GUI_FONT
), sizeof(font
), &font
);
3706 font
.lfHeight
= map_from_system_dpi( font
.lfHeight
);
3707 font
.lfWeight
= entry
->font
.weight
;
3708 entry
->font
.val
= font
;
3711 get_real_fontname( &entry
->font
.val
, entry
->font
.fullname
);
3712 entry
->hdr
.loaded
= TRUE
;
3714 font
= entry
->font
.val
;
3715 font
.lfHeight
= map_to_dpi( font
.lfHeight
, dpi
);
3716 lstrcpyW( font
.lfFaceName
, entry
->font
.fullname
);
3717 *(LOGFONTW
*)ptr_param
= font
;
3721 /* set a font (binary) parameter in the registry */
3722 static BOOL
set_font_entry( union sysparam_all_entry
*entry
, UINT int_param
, void *ptr_param
, UINT flags
)
3727 memcpy( &font
, ptr_param
, sizeof(font
) );
3728 /* zero pad the end of lfFaceName so we don't save uninitialised data */
3729 for (ptr
= font
.lfFaceName
; ptr
< font
.lfFaceName
+ LF_FACESIZE
&& *ptr
; ptr
++);
3730 if (ptr
< font
.lfFaceName
+ LF_FACESIZE
)
3731 memset( ptr
, 0, (font
.lfFaceName
+ LF_FACESIZE
- ptr
) * sizeof(WCHAR
) );
3732 if (font
.lfHeight
< 0) font
.lfHeight
= map_from_system_dpi( font
.lfHeight
);
3734 if (!save_entry( &entry
->hdr
, &font
, sizeof(font
), REG_BINARY
, flags
)) return FALSE
;
3735 entry
->font
.val
= font
;
3736 get_real_fontname( &entry
->font
.val
, entry
->font
.fullname
);
3737 entry
->hdr
.loaded
= TRUE
;
3741 /* initialize a font (binary) parameter */
3742 static BOOL
init_font_entry( union sysparam_all_entry
*entry
)
3744 NtGdiExtGetObjectW( GetStockObject( DEFAULT_GUI_FONT
), sizeof(entry
->font
.val
), &entry
->font
.val
);
3745 entry
->font
.val
.lfHeight
= map_from_system_dpi( entry
->font
.val
.lfHeight
);
3746 entry
->font
.val
.lfWeight
= entry
->font
.weight
;
3747 get_real_fontname( &entry
->font
.val
, entry
->font
.fullname
);
3748 return init_entry( &entry
->hdr
, &entry
->font
.val
, sizeof(entry
->font
.val
), REG_BINARY
);
3751 /* get a user pref parameter in the registry */
3752 static BOOL
get_userpref_entry( union sysparam_all_entry
*entry
, UINT int_param
, void *ptr_param
, UINT dpi
)
3754 union sysparam_all_entry
*parent_entry
= entry
->pref
.parent
;
3757 if (!ptr_param
) return FALSE
;
3759 if (!parent_entry
->hdr
.get( parent_entry
, sizeof(prefs
), prefs
, dpi
)) return FALSE
;
3760 *(BOOL
*)ptr_param
= (prefs
[entry
->pref
.offset
] & entry
->pref
.mask
) != 0;
3764 /* set a user pref parameter in the registry */
3765 static BOOL
set_userpref_entry( union sysparam_all_entry
*entry
, UINT int_param
, void *ptr_param
, UINT flags
)
3767 union sysparam_all_entry
*parent_entry
= entry
->pref
.parent
;
3770 parent_entry
->hdr
.loaded
= FALSE
; /* force loading it again */
3771 if (!parent_entry
->hdr
.get( parent_entry
, sizeof(prefs
), prefs
, get_system_dpi() )) return FALSE
;
3773 if (PtrToUlong( ptr_param
)) prefs
[entry
->pref
.offset
] |= entry
->pref
.mask
;
3774 else prefs
[entry
->pref
.offset
] &= ~entry
->pref
.mask
;
3776 return parent_entry
->hdr
.set( parent_entry
, sizeof(prefs
), prefs
, flags
);
3779 static BOOL
get_entry_dpi( void *ptr
, UINT int_param
, void *ptr_param
, UINT dpi
)
3781 union sysparam_all_entry
*entry
= ptr
;
3782 return entry
->hdr
.get( entry
, int_param
, ptr_param
, dpi
);
3785 static BOOL
get_entry( void *ptr
, UINT int_param
, void *ptr_param
)
3787 return get_entry_dpi( ptr
, int_param
, ptr_param
, get_system_dpi() );
3790 static BOOL
set_entry( void *ptr
, UINT int_param
, void *ptr_param
, UINT flags
)
3792 union sysparam_all_entry
*entry
= ptr
;
3793 return entry
->hdr
.set( entry
, int_param
, ptr_param
, flags
);
3796 #define UINT_ENTRY(name,val,base,reg) union sysparam_all_entry entry_##name = \
3797 { .uint = { { get_uint_entry, set_uint_entry, init_uint_entry, base, reg }, (val) } }
3799 #define UINT_ENTRY_MIRROR(name,val,base,reg,mirror_base) union sysparam_all_entry entry_##name = \
3800 { .uint = { { get_uint_entry, set_uint_entry, init_uint_entry, base, reg, mirror_base, reg }, (val) } }
3802 #define INT_ENTRY(name,val,base,reg) union sysparam_all_entry entry_##name = \
3803 { .uint = { { get_uint_entry, set_int_entry, init_int_entry, base, reg }, (val) } }
3805 #define BOOL_ENTRY(name,val,base,reg) union sysparam_all_entry entry_##name = \
3806 { .bool = { { get_bool_entry, set_bool_entry, init_bool_entry, base, reg }, (val) } }
3808 #define BOOL_ENTRY_MIRROR(name,val,base,reg,mirror_base) union sysparam_all_entry entry_##name = \
3809 { .bool = { { get_bool_entry, set_bool_entry, init_bool_entry, base, reg, mirror_base, reg }, (val) } }
3811 #define TWIPS_ENTRY(name,val,base,reg) union sysparam_all_entry entry_##name = \
3812 { .uint = { { get_twips_entry, set_twips_entry, init_int_entry, base, reg }, (val) } }
3814 #define YESNO_ENTRY(name,val,base,reg) union sysparam_all_entry entry_##name = \
3815 { .bool = { { get_yesno_entry, set_yesno_entry, init_yesno_entry, base, reg }, (val) } }
3817 #define DWORD_ENTRY(name,val,base,reg) union sysparam_all_entry entry_##name = \
3818 { .dword = { { get_dword_entry, set_dword_entry, init_dword_entry, base, reg }, (val) } }
3820 #define BINARY_ENTRY(name,data,base,reg) union sysparam_all_entry entry_##name = \
3821 { .bin = { { get_binary_entry, set_binary_entry, init_binary_entry, base, reg }, data, sizeof(data) } }
3823 #define PATH_ENTRY(name,base,reg,buffer) union sysparam_all_entry entry_##name = \
3824 { .path = { { get_path_entry, set_path_entry, init_path_entry, base, reg }, buffer } }
3826 #define FONT_ENTRY(name,weight,base,reg) union sysparam_all_entry entry_##name = \
3827 { .font = { { get_font_entry, set_font_entry, init_font_entry, base, reg }, (weight) } }
3829 #define USERPREF_ENTRY(name,offset,mask) union sysparam_all_entry entry_##name = \
3830 { .pref = { { get_userpref_entry, set_userpref_entry }, &entry_USERPREFERENCESMASK, (offset), (mask) } }
3832 static UINT_ENTRY( DRAGWIDTH
, 4, DESKTOP_KEY
, "DragWidth" );
3833 static UINT_ENTRY( DRAGHEIGHT
, 4, DESKTOP_KEY
, "DragHeight" );
3834 static UINT_ENTRY( DOUBLECLICKTIME
, 500, MOUSE_KEY
, "DoubleClickSpeed" );
3835 static UINT_ENTRY( FONTSMOOTHING
, 2, DESKTOP_KEY
, "FontSmoothing" );
3836 static UINT_ENTRY( GRIDGRANULARITY
, 0, DESKTOP_KEY
, "GridGranularity" );
3837 static UINT_ENTRY( KEYBOARDDELAY
, 1, KEYBOARD_KEY
, "KeyboardDelay" );
3838 static UINT_ENTRY( KEYBOARDSPEED
, 31, KEYBOARD_KEY
, "KeyboardSpeed" );
3839 static UINT_ENTRY( MENUSHOWDELAY
, 400, DESKTOP_KEY
, "MenuShowDelay" );
3840 static UINT_ENTRY( MINARRANGE
, ARW_HIDE
, METRICS_KEY
, "MinArrange" );
3841 static UINT_ENTRY( MINHORZGAP
, 0, METRICS_KEY
, "MinHorzGap" );
3842 static UINT_ENTRY( MINVERTGAP
, 0, METRICS_KEY
, "MinVertGap" );
3843 static UINT_ENTRY( MINWIDTH
, 154, METRICS_KEY
, "MinWidth" );
3844 static UINT_ENTRY( MOUSEHOVERHEIGHT
, 4, MOUSE_KEY
, "MouseHoverHeight" );
3845 static UINT_ENTRY( MOUSEHOVERTIME
, 400, MOUSE_KEY
, "MouseHoverTime" );
3846 static UINT_ENTRY( MOUSEHOVERWIDTH
, 4, MOUSE_KEY
, "MouseHoverWidth" );
3847 static UINT_ENTRY( MOUSESPEED
, 10, MOUSE_KEY
, "MouseSensitivity" );
3848 static UINT_ENTRY( MOUSETRAILS
, 0, MOUSE_KEY
, "MouseTrails" );
3849 static UINT_ENTRY( SCREENSAVETIMEOUT
, 300, DESKTOP_KEY
, "ScreenSaveTimeOut" );
3850 static UINT_ENTRY( WHEELSCROLLCHARS
, 3, DESKTOP_KEY
, "WheelScrollChars" );
3851 static UINT_ENTRY( WHEELSCROLLLINES
, 3, DESKTOP_KEY
, "WheelScrollLines" );
3852 static UINT_ENTRY_MIRROR( DOUBLECLKHEIGHT
, 4, MOUSE_KEY
, "DoubleClickHeight", DESKTOP_KEY
);
3853 static UINT_ENTRY_MIRROR( DOUBLECLKWIDTH
, 4, MOUSE_KEY
, "DoubleClickWidth", DESKTOP_KEY
);
3854 static UINT_ENTRY_MIRROR( MENUDROPALIGNMENT
, 0, DESKTOP_KEY
, "MenuDropAlignment", VERSION_KEY
);
3856 static INT_ENTRY( MOUSETHRESHOLD1
, 6, MOUSE_KEY
, "MouseThreshold1" );
3857 static INT_ENTRY( MOUSETHRESHOLD2
, 10, MOUSE_KEY
, "MouseThreshold2" );
3858 static INT_ENTRY( MOUSEACCELERATION
, 1, MOUSE_KEY
, "MouseSpeed" );
3860 static BOOL_ENTRY( BLOCKSENDINPUTRESETS
, FALSE
, DESKTOP_KEY
, "BlockSendInputResets" );
3861 static BOOL_ENTRY( DRAGFULLWINDOWS
, FALSE
, DESKTOP_KEY
, "DragFullWindows" );
3862 static BOOL_ENTRY( KEYBOARDPREF
, TRUE
, KEYBOARDPREF_KEY
, "On" );
3863 static BOOL_ENTRY( LOWPOWERACTIVE
, FALSE
, DESKTOP_KEY
, "LowPowerActive" );
3864 static BOOL_ENTRY( MOUSEBUTTONSWAP
, FALSE
, MOUSE_KEY
, "SwapMouseButtons" );
3865 static BOOL_ENTRY( POWEROFFACTIVE
, FALSE
, DESKTOP_KEY
, "PowerOffActive" );
3866 static BOOL_ENTRY( SCREENREADER
, FALSE
, SCREENREADER_KEY
, "On" );
3867 static BOOL_ENTRY( SCREENSAVEACTIVE
, TRUE
, DESKTOP_KEY
, "ScreenSaveActive" );
3868 static BOOL_ENTRY( SCREENSAVERRUNNING
, FALSE
, DESKTOP_KEY
, "WINE_ScreenSaverRunning" ); /* FIXME - real value */
3869 static BOOL_ENTRY( SHOWSOUNDS
, FALSE
, SHOWSOUNDS_KEY
, "On" );
3870 static BOOL_ENTRY( SNAPTODEFBUTTON
, FALSE
, MOUSE_KEY
, "SnapToDefaultButton" );
3871 static BOOL_ENTRY_MIRROR( ICONTITLEWRAP
, TRUE
, DESKTOP_KEY
, "IconTitleWrap", METRICS_KEY
);
3872 static BOOL_ENTRY( AUDIODESC_ON
, FALSE
, AUDIODESC_KEY
, "On" );
3874 static TWIPS_ENTRY( BORDER
, -15, METRICS_KEY
, "BorderWidth" );
3875 static TWIPS_ENTRY( CAPTIONHEIGHT
, -270, METRICS_KEY
, "CaptionHeight" );
3876 static TWIPS_ENTRY( CAPTIONWIDTH
, -270, METRICS_KEY
, "CaptionWidth" );
3877 static TWIPS_ENTRY( ICONHORIZONTALSPACING
, -1125, METRICS_KEY
, "IconSpacing" );
3878 static TWIPS_ENTRY( ICONVERTICALSPACING
, -1125, METRICS_KEY
, "IconVerticalSpacing" );
3879 static TWIPS_ENTRY( MENUHEIGHT
, -270, METRICS_KEY
, "MenuHeight" );
3880 static TWIPS_ENTRY( MENUWIDTH
, -270, METRICS_KEY
, "MenuWidth" );
3881 static TWIPS_ENTRY( PADDEDBORDERWIDTH
, 0, METRICS_KEY
, "PaddedBorderWidth" );
3882 static TWIPS_ENTRY( SCROLLHEIGHT
, -240, METRICS_KEY
, "ScrollHeight" );
3883 static TWIPS_ENTRY( SCROLLWIDTH
, -240, METRICS_KEY
, "ScrollWidth" );
3884 static TWIPS_ENTRY( SMCAPTIONHEIGHT
, -225, METRICS_KEY
, "SmCaptionHeight" );
3885 static TWIPS_ENTRY( SMCAPTIONWIDTH
, -225, METRICS_KEY
, "SmCaptionWidth" );
3887 static YESNO_ENTRY( BEEP
, TRUE
, SOUND_KEY
, "Beep" );
3889 static DWORD_ENTRY( ACTIVEWINDOWTRACKING
, 0, MOUSE_KEY
, "ActiveWindowTracking" );
3890 static DWORD_ENTRY( ACTIVEWNDTRKTIMEOUT
, 0, DESKTOP_KEY
, "ActiveWndTrackTimeout" );
3891 static DWORD_ENTRY( CARETWIDTH
, 1, DESKTOP_KEY
, "CaretWidth" );
3892 static DWORD_ENTRY( DPISCALINGVER
, 0, DESKTOP_KEY
, "DpiScalingVer" );
3893 static DWORD_ENTRY( FOCUSBORDERHEIGHT
, 1, DESKTOP_KEY
, "FocusBorderHeight" );
3894 static DWORD_ENTRY( FOCUSBORDERWIDTH
, 1, DESKTOP_KEY
, "FocusBorderWidth" );
3895 static DWORD_ENTRY( FONTSMOOTHINGCONTRAST
, 0, DESKTOP_KEY
, "FontSmoothingGamma" );
3896 static DWORD_ENTRY( FONTSMOOTHINGORIENTATION
, FE_FONTSMOOTHINGORIENTATIONRGB
, DESKTOP_KEY
, "FontSmoothingOrientation" );
3897 static DWORD_ENTRY( FONTSMOOTHINGTYPE
, FE_FONTSMOOTHINGSTANDARD
, DESKTOP_KEY
, "FontSmoothingType" );
3898 static DWORD_ENTRY( FOREGROUNDFLASHCOUNT
, 3, DESKTOP_KEY
, "ForegroundFlashCount" );
3899 static DWORD_ENTRY( FOREGROUNDLOCKTIMEOUT
, 0, DESKTOP_KEY
, "ForegroundLockTimeout" );
3900 static DWORD_ENTRY( LOGPIXELS
, 0, DESKTOP_KEY
, "LogPixels" );
3901 static DWORD_ENTRY( MOUSECLICKLOCKTIME
, 1200, DESKTOP_KEY
, "ClickLockTime" );
3902 static DWORD_ENTRY( AUDIODESC_LOCALE
, 0, AUDIODESC_KEY
, "Locale" );
3904 static WCHAR desk_pattern_path
[MAX_PATH
];
3905 static WCHAR desk_wallpaper_path
[MAX_PATH
];
3906 static PATH_ENTRY( DESKPATTERN
, DESKTOP_KEY
, "Pattern", desk_pattern_path
);
3907 static PATH_ENTRY( DESKWALLPAPER
, DESKTOP_KEY
, "Wallpaper", desk_wallpaper_path
);
3909 static BYTE user_prefs
[8] = { 0x30, 0x00, 0x00, 0x80, 0x12, 0x00, 0x00, 0x00 };
3910 static BINARY_ENTRY( USERPREFERENCESMASK
, user_prefs
, DESKTOP_KEY
, "UserPreferencesMask" );
3912 static FONT_ENTRY( CAPTIONLOGFONT
, FW_BOLD
, METRICS_KEY
, "CaptionFont" );
3913 static FONT_ENTRY( ICONTITLELOGFONT
, FW_NORMAL
, METRICS_KEY
, "IconFont" );
3914 static FONT_ENTRY( MENULOGFONT
, FW_NORMAL
, METRICS_KEY
, "MenuFont" );
3915 static FONT_ENTRY( MESSAGELOGFONT
, FW_NORMAL
, METRICS_KEY
, "MessageFont" );
3916 static FONT_ENTRY( SMCAPTIONLOGFONT
, FW_NORMAL
, METRICS_KEY
, "SmCaptionFont" );
3917 static FONT_ENTRY( STATUSLOGFONT
, FW_NORMAL
, METRICS_KEY
, "StatusFont" );
3919 static USERPREF_ENTRY( MENUANIMATION
, 0, 0x02 );
3920 static USERPREF_ENTRY( COMBOBOXANIMATION
, 0, 0x04 );
3921 static USERPREF_ENTRY( LISTBOXSMOOTHSCROLLING
, 0, 0x08 );
3922 static USERPREF_ENTRY( GRADIENTCAPTIONS
, 0, 0x10 );
3923 static USERPREF_ENTRY( KEYBOARDCUES
, 0, 0x20 );
3924 static USERPREF_ENTRY( ACTIVEWNDTRKZORDER
, 0, 0x40 );
3925 static USERPREF_ENTRY( HOTTRACKING
, 0, 0x80 );
3926 static USERPREF_ENTRY( MENUFADE
, 1, 0x02 );
3927 static USERPREF_ENTRY( SELECTIONFADE
, 1, 0x04 );
3928 static USERPREF_ENTRY( TOOLTIPANIMATION
, 1, 0x08 );
3929 static USERPREF_ENTRY( TOOLTIPFADE
, 1, 0x10 );
3930 static USERPREF_ENTRY( CURSORSHADOW
, 1, 0x20 );
3931 static USERPREF_ENTRY( MOUSESONAR
, 1, 0x40 );
3932 static USERPREF_ENTRY( MOUSECLICKLOCK
, 1, 0x80 );
3933 static USERPREF_ENTRY( MOUSEVANISH
, 2, 0x01 );
3934 static USERPREF_ENTRY( FLATMENU
, 2, 0x02 );
3935 static USERPREF_ENTRY( DROPSHADOW
, 2, 0x04 );
3936 static USERPREF_ENTRY( UIEFFECTS
, 3, 0x80 );
3937 static USERPREF_ENTRY( DISABLEOVERLAPPEDCONTENT
, 4, 0x01 );
3938 static USERPREF_ENTRY( CLIENTAREAANIMATION
, 4, 0x02 );
3939 static USERPREF_ENTRY( CLEARTYPE
, 4, 0x10 );
3940 static USERPREF_ENTRY( SPEECHRECOGNITION
, 4, 0x20 );
3942 /* System parameter indexes */
3945 SPI_SETWORKAREA_IDX
,
3949 /* indicators whether system parameter value is loaded */
3950 static char spi_loaded
[SPI_INDEX_COUNT
];
3952 static struct sysparam_rgb_entry system_colors
[] =
3954 #define RGB_ENTRY(name,val,reg) { { get_rgb_entry, set_rgb_entry, init_rgb_entry, COLORS_KEY, reg }, (val) }
3955 RGB_ENTRY( COLOR_SCROLLBAR
, RGB(212, 208, 200), "Scrollbar" ),
3956 RGB_ENTRY( COLOR_BACKGROUND
, RGB(58, 110, 165), "Background" ),
3957 RGB_ENTRY( COLOR_ACTIVECAPTION
, RGB(10, 36, 106), "ActiveTitle" ),
3958 RGB_ENTRY( COLOR_INACTIVECAPTION
, RGB(128, 128, 128), "InactiveTitle" ),
3959 RGB_ENTRY( COLOR_MENU
, RGB(212, 208, 200), "Menu" ),
3960 RGB_ENTRY( COLOR_WINDOW
, RGB(255, 255, 255), "Window" ),
3961 RGB_ENTRY( COLOR_WINDOWFRAME
, RGB(0, 0, 0), "WindowFrame" ),
3962 RGB_ENTRY( COLOR_MENUTEXT
, RGB(0, 0, 0), "MenuText" ),
3963 RGB_ENTRY( COLOR_WINDOWTEXT
, RGB(0, 0, 0), "WindowText" ),
3964 RGB_ENTRY( COLOR_CAPTIONTEXT
, RGB(255, 255, 255), "TitleText" ),
3965 RGB_ENTRY( COLOR_ACTIVEBORDER
, RGB(212, 208, 200), "ActiveBorder" ),
3966 RGB_ENTRY( COLOR_INACTIVEBORDER
, RGB(212, 208, 200), "InactiveBorder" ),
3967 RGB_ENTRY( COLOR_APPWORKSPACE
, RGB(128, 128, 128), "AppWorkSpace" ),
3968 RGB_ENTRY( COLOR_HIGHLIGHT
, RGB(10, 36, 106), "Hilight" ),
3969 RGB_ENTRY( COLOR_HIGHLIGHTTEXT
, RGB(255, 255, 255), "HilightText" ),
3970 RGB_ENTRY( COLOR_BTNFACE
, RGB(212, 208, 200), "ButtonFace" ),
3971 RGB_ENTRY( COLOR_BTNSHADOW
, RGB(128, 128, 128), "ButtonShadow" ),
3972 RGB_ENTRY( COLOR_GRAYTEXT
, RGB(128, 128, 128), "GrayText" ),
3973 RGB_ENTRY( COLOR_BTNTEXT
, RGB(0, 0, 0), "ButtonText" ),
3974 RGB_ENTRY( COLOR_INACTIVECAPTIONTEXT
, RGB(212, 208, 200), "InactiveTitleText" ),
3975 RGB_ENTRY( COLOR_BTNHIGHLIGHT
, RGB(255, 255, 255), "ButtonHilight" ),
3976 RGB_ENTRY( COLOR_3DDKSHADOW
, RGB(64, 64, 64), "ButtonDkShadow" ),
3977 RGB_ENTRY( COLOR_3DLIGHT
, RGB(212, 208, 200), "ButtonLight" ),
3978 RGB_ENTRY( COLOR_INFOTEXT
, RGB(0, 0, 0), "InfoText" ),
3979 RGB_ENTRY( COLOR_INFOBK
, RGB(255, 255, 225), "InfoWindow" ),
3980 RGB_ENTRY( COLOR_ALTERNATEBTNFACE
, RGB(181, 181, 181), "ButtonAlternateFace" ),
3981 RGB_ENTRY( COLOR_HOTLIGHT
, RGB(0, 0, 200), "HotTrackingColor" ),
3982 RGB_ENTRY( COLOR_GRADIENTACTIVECAPTION
, RGB(166, 202, 240), "GradientActiveTitle" ),
3983 RGB_ENTRY( COLOR_GRADIENTINACTIVECAPTION
, RGB(192, 192, 192), "GradientInactiveTitle" ),
3984 RGB_ENTRY( COLOR_MENUHILIGHT
, RGB(10, 36, 106), "MenuHilight" ),
3985 RGB_ENTRY( COLOR_MENUBAR
, RGB(212, 208, 200), "MenuBar" )
3989 /* entries that are initialized by default in the registry */
3990 static union sysparam_all_entry
* const default_entries
[] =
3992 (union sysparam_all_entry
*)&entry_ACTIVEWINDOWTRACKING
,
3993 (union sysparam_all_entry
*)&entry_ACTIVEWNDTRKTIMEOUT
,
3994 (union sysparam_all_entry
*)&entry_BEEP
,
3995 (union sysparam_all_entry
*)&entry_BLOCKSENDINPUTRESETS
,
3996 (union sysparam_all_entry
*)&entry_BORDER
,
3997 (union sysparam_all_entry
*)&entry_CAPTIONHEIGHT
,
3998 (union sysparam_all_entry
*)&entry_CAPTIONWIDTH
,
3999 (union sysparam_all_entry
*)&entry_CARETWIDTH
,
4000 (union sysparam_all_entry
*)&entry_DESKWALLPAPER
,
4001 (union sysparam_all_entry
*)&entry_DOUBLECLICKTIME
,
4002 (union sysparam_all_entry
*)&entry_DOUBLECLKHEIGHT
,
4003 (union sysparam_all_entry
*)&entry_DOUBLECLKWIDTH
,
4004 (union sysparam_all_entry
*)&entry_DRAGFULLWINDOWS
,
4005 (union sysparam_all_entry
*)&entry_DRAGHEIGHT
,
4006 (union sysparam_all_entry
*)&entry_DRAGWIDTH
,
4007 (union sysparam_all_entry
*)&entry_FOCUSBORDERHEIGHT
,
4008 (union sysparam_all_entry
*)&entry_FOCUSBORDERWIDTH
,
4009 (union sysparam_all_entry
*)&entry_FONTSMOOTHING
,
4010 (union sysparam_all_entry
*)&entry_FONTSMOOTHINGCONTRAST
,
4011 (union sysparam_all_entry
*)&entry_FONTSMOOTHINGORIENTATION
,
4012 (union sysparam_all_entry
*)&entry_FONTSMOOTHINGTYPE
,
4013 (union sysparam_all_entry
*)&entry_FOREGROUNDFLASHCOUNT
,
4014 (union sysparam_all_entry
*)&entry_FOREGROUNDLOCKTIMEOUT
,
4015 (union sysparam_all_entry
*)&entry_ICONHORIZONTALSPACING
,
4016 (union sysparam_all_entry
*)&entry_ICONTITLEWRAP
,
4017 (union sysparam_all_entry
*)&entry_ICONVERTICALSPACING
,
4018 (union sysparam_all_entry
*)&entry_KEYBOARDDELAY
,
4019 (union sysparam_all_entry
*)&entry_KEYBOARDPREF
,
4020 (union sysparam_all_entry
*)&entry_KEYBOARDSPEED
,
4021 (union sysparam_all_entry
*)&entry_LOWPOWERACTIVE
,
4022 (union sysparam_all_entry
*)&entry_MENUHEIGHT
,
4023 (union sysparam_all_entry
*)&entry_MENUSHOWDELAY
,
4024 (union sysparam_all_entry
*)&entry_MENUWIDTH
,
4025 (union sysparam_all_entry
*)&entry_MOUSEACCELERATION
,
4026 (union sysparam_all_entry
*)&entry_MOUSEBUTTONSWAP
,
4027 (union sysparam_all_entry
*)&entry_MOUSECLICKLOCKTIME
,
4028 (union sysparam_all_entry
*)&entry_MOUSEHOVERHEIGHT
,
4029 (union sysparam_all_entry
*)&entry_MOUSEHOVERTIME
,
4030 (union sysparam_all_entry
*)&entry_MOUSEHOVERWIDTH
,
4031 (union sysparam_all_entry
*)&entry_MOUSESPEED
,
4032 (union sysparam_all_entry
*)&entry_MOUSETHRESHOLD1
,
4033 (union sysparam_all_entry
*)&entry_MOUSETHRESHOLD2
,
4034 (union sysparam_all_entry
*)&entry_PADDEDBORDERWIDTH
,
4035 (union sysparam_all_entry
*)&entry_SCREENREADER
,
4036 (union sysparam_all_entry
*)&entry_SCROLLHEIGHT
,
4037 (union sysparam_all_entry
*)&entry_SCROLLWIDTH
,
4038 (union sysparam_all_entry
*)&entry_SHOWSOUNDS
,
4039 (union sysparam_all_entry
*)&entry_SMCAPTIONHEIGHT
,
4040 (union sysparam_all_entry
*)&entry_SMCAPTIONWIDTH
,
4041 (union sysparam_all_entry
*)&entry_SNAPTODEFBUTTON
,
4042 (union sysparam_all_entry
*)&entry_USERPREFERENCESMASK
,
4043 (union sysparam_all_entry
*)&entry_WHEELSCROLLCHARS
,
4044 (union sysparam_all_entry
*)&entry_WHEELSCROLLLINES
,
4045 (union sysparam_all_entry
*)&entry_AUDIODESC_LOCALE
,
4046 (union sysparam_all_entry
*)&entry_AUDIODESC_ON
,
4049 void sysparams_init(void)
4052 DWORD i
, dispos
, dpi_scaling
;
4053 WCHAR layout
[KL_NAMELENGTH
];
4054 pthread_mutexattr_t attr
;
4057 static const WCHAR software_wineW
[] = {'S','o','f','t','w','a','r','e','\\','W','i','n','e'};
4058 static const WCHAR temporary_system_parametersW
[] =
4059 {'T','e','m','p','o','r','a','r','y',' ','S','y','s','t','e','m',' ',
4060 'P','a','r','a','m','e','t','e','r','s'};
4061 static const WCHAR oneW
[] = {'1',0};
4062 static const WCHAR kl_preloadW
[] =
4063 {'K','e','y','b','o','a','r','d',' ','L','a','y','o','u','t','\\','P','r','e','l','o','a','d'};
4065 pthread_mutexattr_init( &attr
);
4066 pthread_mutexattr_settype( &attr
, PTHREAD_MUTEX_RECURSIVE
);
4067 pthread_mutex_init( &user_mutex
, &attr
);
4068 pthread_mutexattr_destroy( &attr
);
4070 if ((hkey
= reg_create_key( hkcu_key
, kl_preloadW
, sizeof(kl_preloadW
), 0, NULL
)))
4072 if (NtUserGetKeyboardLayoutName( layout
))
4073 set_reg_value( hkey
, oneW
, REG_SZ
, (const BYTE
*)layout
,
4074 (lstrlenW(layout
) + 1) * sizeof(WCHAR
) );
4078 /* this one must be non-volatile */
4079 if (!(hkey
= reg_create_key( hkcu_key
, software_wineW
, sizeof(software_wineW
), 0, NULL
)))
4081 ERR("Can't create wine registry branch\n");
4085 /* @@ Wine registry key: HKCU\Software\Wine\Temporary System Parameters */
4086 if (!(volatile_base_key
= reg_create_key( hkey
, temporary_system_parametersW
,
4087 sizeof(temporary_system_parametersW
),
4088 REG_OPTION_VOLATILE
, &dispos
)))
4089 ERR("Can't create non-permanent wine registry branch\n");
4093 config_key
= reg_create_key( NULL
, config_keyW
, sizeof(config_keyW
), 0, NULL
);
4095 get_dword_entry( (union sysparam_all_entry
*)&entry_LOGPIXELS
, 0, &system_dpi
, 0 );
4096 if (!system_dpi
) /* check fallback key */
4098 static const WCHAR log_pixelsW
[] = {'L','o','g','P','i','x','e','l','s',0};
4099 static const WCHAR software_fontsW
[] =
4100 {'S','o','f','t','w','a','r','e','\\','F','o','n','t','s'};
4102 if ((hkey
= reg_open_key( config_key
, software_fontsW
, sizeof(software_fontsW
) )))
4104 char buffer
[offsetof(KEY_VALUE_PARTIAL_INFORMATION
, Data
[sizeof(DWORD
)])];
4105 KEY_VALUE_PARTIAL_INFORMATION
*value
= (void *)buffer
;
4107 if (query_reg_value( hkey
, log_pixelsW
, value
, sizeof(buffer
) ) && value
->Type
== REG_DWORD
)
4108 system_dpi
= *(const DWORD
*)value
->Data
;
4112 if (!system_dpi
) system_dpi
= USER_DEFAULT_SCREEN_DPI
;
4114 /* FIXME: what do the DpiScalingVer flags mean? */
4115 get_dword_entry( (union sysparam_all_entry
*)&entry_DPISCALINGVER
, 0, &dpi_scaling
, 0 );
4116 if (!dpi_scaling
) NtUserSetProcessDpiAwarenessContext( NTUSER_DPI_PER_MONITOR_AWARE
, 0 );
4118 if (volatile_base_key
&& dispos
== REG_CREATED_NEW_KEY
) /* first process, initialize entries */
4120 for (i
= 0; i
< ARRAY_SIZE( default_entries
); i
++)
4121 default_entries
[i
]->hdr
.init( default_entries
[i
] );
4125 static BOOL
update_desktop_wallpaper(void)
4127 /* FIXME: move implementation from user32 */
4128 entry_DESKWALLPAPER
.hdr
.loaded
= entry_DESKPATTERN
.hdr
.loaded
= FALSE
;
4132 /***********************************************************************
4133 * NtUserSystemParametersInfoForDpi (win32u.@)
4135 BOOL WINAPI
NtUserSystemParametersInfoForDpi( UINT action
, UINT val
, PVOID ptr
, UINT winini
, UINT dpi
)
4141 case SPI_GETICONTITLELOGFONT
:
4142 ret
= get_entry_dpi( &entry_ICONTITLELOGFONT
, val
, ptr
, dpi
);
4144 case SPI_GETNONCLIENTMETRICS
:
4146 NONCLIENTMETRICSW
*ncm
= ptr
;
4149 ret
= get_entry_dpi( &entry_BORDER
, 0, &ncm
->iBorderWidth
, dpi
) &&
4150 get_entry_dpi( &entry_SCROLLWIDTH
, 0, &ncm
->iScrollWidth
, dpi
) &&
4151 get_entry_dpi( &entry_SCROLLHEIGHT
, 0, &ncm
->iScrollHeight
, dpi
) &&
4152 get_entry_dpi( &entry_CAPTIONWIDTH
, 0, &ncm
->iCaptionWidth
, dpi
) &&
4153 get_entry_dpi( &entry_CAPTIONHEIGHT
, 0, &ncm
->iCaptionHeight
, dpi
) &&
4154 get_entry_dpi( &entry_CAPTIONLOGFONT
, 0, &ncm
->lfCaptionFont
, dpi
) &&
4155 get_entry_dpi( &entry_SMCAPTIONWIDTH
, 0, &ncm
->iSmCaptionWidth
, dpi
) &&
4156 get_entry_dpi( &entry_SMCAPTIONHEIGHT
, 0, &ncm
->iSmCaptionHeight
, dpi
) &&
4157 get_entry_dpi( &entry_SMCAPTIONLOGFONT
, 0, &ncm
->lfSmCaptionFont
, dpi
) &&
4158 get_entry_dpi( &entry_MENUWIDTH
, 0, &ncm
->iMenuWidth
, dpi
) &&
4159 get_entry_dpi( &entry_MENUHEIGHT
, 0, &ncm
->iMenuHeight
, dpi
) &&
4160 get_entry_dpi( &entry_MENULOGFONT
, 0, &ncm
->lfMenuFont
, dpi
) &&
4161 get_entry_dpi( &entry_STATUSLOGFONT
, 0, &ncm
->lfStatusFont
, dpi
) &&
4162 get_entry_dpi( &entry_MESSAGELOGFONT
, 0, &ncm
->lfMessageFont
, dpi
);
4163 if (ret
&& ncm
->cbSize
== sizeof(NONCLIENTMETRICSW
))
4164 ret
= get_entry_dpi( &entry_PADDEDBORDERWIDTH
, 0, &ncm
->iPaddedBorderWidth
, dpi
);
4165 normalize_nonclientmetrics( ncm
);
4168 case SPI_GETICONMETRICS
:
4170 ICONMETRICSW
*im
= ptr
;
4171 if (im
&& im
->cbSize
== sizeof(*im
))
4172 ret
= get_entry_dpi( &entry_ICONHORIZONTALSPACING
, 0, &im
->iHorzSpacing
, dpi
) &&
4173 get_entry_dpi( &entry_ICONVERTICALSPACING
, 0, &im
->iVertSpacing
, dpi
) &&
4174 get_entry_dpi( &entry_ICONTITLEWRAP
, 0, &im
->iTitleWrap
, dpi
) &&
4175 get_entry_dpi( &entry_ICONTITLELOGFONT
, 0, &im
->lfFont
, dpi
);
4179 RtlSetLastWin32Error( ERROR_INVALID_PARAMETER
);
4185 /***********************************************************************
4186 * NtUserSystemParametersInfo (win32u.@)
4188 * Each system parameter has flag which shows whether the parameter
4189 * is loaded or not. Parameters, stored directly in SysParametersInfo are
4190 * loaded from registry only when they are requested and the flag is
4191 * "false", after the loading the flag is set to "true". On interprocess
4192 * notification of the parameter change the corresponding parameter flag is
4193 * set to "false". The parameter value will be reloaded when it is requested
4195 * Parameters, backed by or depend on GetSystemMetrics are processed
4196 * differently. These parameters are always loaded. They are reloaded right
4197 * away on interprocess change notification. We can't do lazy loading because
4198 * we don't want to complicate GetSystemMetrics.
4199 * Parameters backed by driver settings are read from corresponding setting.
4200 * On the parameter change request the setting is changed. Interprocess change
4201 * notifications are ignored.
4202 * When parameter value is updated the changed value is stored in permanent
4203 * registry branch if saving is requested. Otherwise it is stored
4204 * in temporary branch
4206 * Some SPI values can also be stored as Twips values in the registry,
4207 * don't forget the conversion!
4209 BOOL WINAPI
NtUserSystemParametersInfo( UINT action
, UINT val
, void *ptr
, UINT winini
)
4211 #define WINE_SPI_FIXME(x) \
4214 static BOOL warn = TRUE; \
4218 FIXME( "Unimplemented action: %u (%s)\n", x, #x ); \
4221 RtlSetLastWin32Error( ERROR_INVALID_SPI_VALUE ); \
4224 #define WINE_SPI_WARN(x) \
4226 WARN( "Ignored action: %u (%s)\n", x, #x ); \
4230 BOOL ret
= user_driver
->pSystemParametersInfo( action
, val
, ptr
, winini
);
4231 unsigned spi_idx
= 0;
4233 if (!ret
) switch (action
)
4236 ret
= get_entry( &entry_BEEP
, val
, ptr
);
4239 ret
= set_entry( &entry_BEEP
, val
, ptr
, winini
);
4242 ret
= get_entry( &entry_MOUSETHRESHOLD1
, val
, (INT
*)ptr
) &&
4243 get_entry( &entry_MOUSETHRESHOLD2
, val
, (INT
*)ptr
+ 1 ) &&
4244 get_entry( &entry_MOUSEACCELERATION
, val
, (INT
*)ptr
+ 2 );
4247 ret
= set_entry( &entry_MOUSETHRESHOLD1
, ((INT
*)ptr
)[0], ptr
, winini
) &&
4248 set_entry( &entry_MOUSETHRESHOLD2
, ((INT
*)ptr
)[1], ptr
, winini
) &&
4249 set_entry( &entry_MOUSEACCELERATION
, ((INT
*)ptr
)[2], ptr
, winini
);
4252 ret
= get_entry( &entry_BORDER
, val
, ptr
);
4253 if (*(INT
*)ptr
< 1) *(INT
*)ptr
= 1;
4256 ret
= set_entry( &entry_BORDER
, val
, ptr
, winini
);
4258 case SPI_GETKEYBOARDSPEED
:
4259 ret
= get_entry( &entry_KEYBOARDSPEED
, val
, ptr
);
4261 case SPI_SETKEYBOARDSPEED
:
4262 if (val
> 31) val
= 31;
4263 ret
= set_entry( &entry_KEYBOARDSPEED
, val
, ptr
, winini
);
4266 WINE_SPI_WARN(SPI_LANGDRIVER
); /* not implemented in Windows */
4268 case SPI_ICONHORIZONTALSPACING
:
4270 ret
= get_entry( &entry_ICONHORIZONTALSPACING
, val
, ptr
);
4273 int min_val
= map_to_dpi( 32, get_system_dpi() );
4274 ret
= set_entry( &entry_ICONHORIZONTALSPACING
, max( min_val
, val
), ptr
, winini
);
4277 case SPI_GETSCREENSAVETIMEOUT
:
4278 ret
= get_entry( &entry_SCREENSAVETIMEOUT
, val
, ptr
);
4280 case SPI_SETSCREENSAVETIMEOUT
:
4281 ret
= set_entry( &entry_SCREENSAVETIMEOUT
, val
, ptr
, winini
);
4283 case SPI_GETSCREENSAVEACTIVE
:
4284 ret
= get_entry( &entry_SCREENSAVEACTIVE
, val
, ptr
);
4286 case SPI_SETSCREENSAVEACTIVE
:
4287 ret
= set_entry( &entry_SCREENSAVEACTIVE
, val
, ptr
, winini
);
4289 case SPI_GETGRIDGRANULARITY
:
4290 ret
= get_entry( &entry_GRIDGRANULARITY
, val
, ptr
);
4292 case SPI_SETGRIDGRANULARITY
:
4293 ret
= set_entry( &entry_GRIDGRANULARITY
, val
, ptr
, winini
);
4295 case SPI_SETDESKWALLPAPER
:
4296 if (!ptr
|| set_entry( &entry_DESKWALLPAPER
, val
, ptr
, winini
))
4297 ret
= update_desktop_wallpaper();
4299 case SPI_SETDESKPATTERN
:
4300 if (!ptr
|| set_entry( &entry_DESKPATTERN
, val
, ptr
, winini
))
4301 ret
= update_desktop_wallpaper();
4303 case SPI_GETKEYBOARDDELAY
:
4304 ret
= get_entry( &entry_KEYBOARDDELAY
, val
, ptr
);
4306 case SPI_SETKEYBOARDDELAY
:
4307 ret
= set_entry( &entry_KEYBOARDDELAY
, val
, ptr
, winini
);
4309 case SPI_ICONVERTICALSPACING
:
4311 ret
= get_entry( &entry_ICONVERTICALSPACING
, val
, ptr
);
4314 int min_val
= map_to_dpi( 32, get_system_dpi() );
4315 ret
= set_entry( &entry_ICONVERTICALSPACING
, max( min_val
, val
), ptr
, winini
);
4318 case SPI_GETICONTITLEWRAP
:
4319 ret
= get_entry( &entry_ICONTITLEWRAP
, val
, ptr
);
4321 case SPI_SETICONTITLEWRAP
:
4322 ret
= set_entry( &entry_ICONTITLEWRAP
, val
, ptr
, winini
);
4324 case SPI_GETMENUDROPALIGNMENT
:
4325 ret
= get_entry( &entry_MENUDROPALIGNMENT
, val
, ptr
);
4327 case SPI_SETMENUDROPALIGNMENT
:
4328 ret
= set_entry( &entry_MENUDROPALIGNMENT
, val
, ptr
, winini
);
4330 case SPI_SETDOUBLECLKWIDTH
:
4331 ret
= set_entry( &entry_DOUBLECLKWIDTH
, val
, ptr
, winini
);
4333 case SPI_SETDOUBLECLKHEIGHT
:
4334 ret
= set_entry( &entry_DOUBLECLKHEIGHT
, val
, ptr
, winini
);
4336 case SPI_GETICONTITLELOGFONT
:
4337 ret
= get_entry( &entry_ICONTITLELOGFONT
, val
, ptr
);
4339 case SPI_SETDOUBLECLICKTIME
:
4340 ret
= set_entry( &entry_DOUBLECLICKTIME
, val
, ptr
, winini
);
4342 case SPI_SETMOUSEBUTTONSWAP
:
4343 ret
= set_entry( &entry_MOUSEBUTTONSWAP
, val
, ptr
, winini
);
4345 case SPI_SETICONTITLELOGFONT
:
4346 ret
= set_entry( &entry_ICONTITLELOGFONT
, val
, ptr
, winini
);
4348 case SPI_GETFASTTASKSWITCH
:
4349 if (!ptr
) return FALSE
;
4350 *(BOOL
*)ptr
= TRUE
;
4353 case SPI_SETFASTTASKSWITCH
:
4354 /* the action is disabled */
4357 case SPI_SETDRAGFULLWINDOWS
:
4358 ret
= set_entry( &entry_DRAGFULLWINDOWS
, val
, ptr
, winini
);
4360 case SPI_GETDRAGFULLWINDOWS
:
4361 ret
= get_entry( &entry_DRAGFULLWINDOWS
, val
, ptr
);
4363 case SPI_GETNONCLIENTMETRICS
:
4365 NONCLIENTMETRICSW
*nm
= ptr
;
4368 if (!ptr
) return FALSE
;
4370 ret
= get_entry( &entry_BORDER
, 0, &nm
->iBorderWidth
) &&
4371 get_entry( &entry_PADDEDBORDERWIDTH
, 0, &padded_border
) &&
4372 get_entry( &entry_SCROLLWIDTH
, 0, &nm
->iScrollWidth
) &&
4373 get_entry( &entry_SCROLLHEIGHT
, 0, &nm
->iScrollHeight
) &&
4374 get_entry( &entry_CAPTIONWIDTH
, 0, &nm
->iCaptionWidth
) &&
4375 get_entry( &entry_CAPTIONHEIGHT
, 0, &nm
->iCaptionHeight
) &&
4376 get_entry( &entry_CAPTIONLOGFONT
, 0, &nm
->lfCaptionFont
) &&
4377 get_entry( &entry_SMCAPTIONWIDTH
, 0, &nm
->iSmCaptionWidth
) &&
4378 get_entry( &entry_SMCAPTIONHEIGHT
, 0, &nm
->iSmCaptionHeight
) &&
4379 get_entry( &entry_SMCAPTIONLOGFONT
, 0, &nm
->lfSmCaptionFont
) &&
4380 get_entry( &entry_MENUWIDTH
, 0, &nm
->iMenuWidth
) &&
4381 get_entry( &entry_MENUHEIGHT
, 0, &nm
->iMenuHeight
) &&
4382 get_entry( &entry_MENULOGFONT
, 0, &nm
->lfMenuFont
) &&
4383 get_entry( &entry_STATUSLOGFONT
, 0, &nm
->lfStatusFont
) &&
4384 get_entry( &entry_MESSAGELOGFONT
, 0, &nm
->lfMessageFont
);
4387 nm
->iBorderWidth
+= padded_border
;
4388 if (nm
->cbSize
== sizeof(NONCLIENTMETRICSW
)) nm
->iPaddedBorderWidth
= 0;
4390 normalize_nonclientmetrics( nm
);
4393 case SPI_SETNONCLIENTMETRICS
:
4395 LPNONCLIENTMETRICSW nm
= ptr
;
4398 if (nm
&& (nm
->cbSize
== sizeof(NONCLIENTMETRICSW
) ||
4399 nm
->cbSize
== FIELD_OFFSET(NONCLIENTMETRICSW
, iPaddedBorderWidth
)))
4401 get_entry( &entry_PADDEDBORDERWIDTH
, 0, &padded_border
);
4403 ret
= set_entry( &entry_BORDER
, nm
->iBorderWidth
- padded_border
, NULL
, winini
) &&
4404 set_entry( &entry_SCROLLWIDTH
, nm
->iScrollWidth
, NULL
, winini
) &&
4405 set_entry( &entry_SCROLLHEIGHT
, nm
->iScrollHeight
, NULL
, winini
) &&
4406 set_entry( &entry_CAPTIONWIDTH
, nm
->iCaptionWidth
, NULL
, winini
) &&
4407 set_entry( &entry_CAPTIONHEIGHT
, nm
->iCaptionHeight
, NULL
, winini
) &&
4408 set_entry( &entry_SMCAPTIONWIDTH
, nm
->iSmCaptionWidth
, NULL
, winini
) &&
4409 set_entry( &entry_SMCAPTIONHEIGHT
, nm
->iSmCaptionHeight
, NULL
, winini
) &&
4410 set_entry( &entry_MENUWIDTH
, nm
->iMenuWidth
, NULL
, winini
) &&
4411 set_entry( &entry_MENUHEIGHT
, nm
->iMenuHeight
, NULL
, winini
) &&
4412 set_entry( &entry_MENULOGFONT
, 0, &nm
->lfMenuFont
, winini
) &&
4413 set_entry( &entry_CAPTIONLOGFONT
, 0, &nm
->lfCaptionFont
, winini
) &&
4414 set_entry( &entry_SMCAPTIONLOGFONT
, 0, &nm
->lfSmCaptionFont
, winini
) &&
4415 set_entry( &entry_STATUSLOGFONT
, 0, &nm
->lfStatusFont
, winini
) &&
4416 set_entry( &entry_MESSAGELOGFONT
, 0, &nm
->lfMessageFont
, winini
);
4420 case SPI_GETMINIMIZEDMETRICS
:
4422 MINIMIZEDMETRICS
*mm
= ptr
;
4423 if (mm
&& mm
->cbSize
== sizeof(*mm
)) {
4424 ret
= get_entry( &entry_MINWIDTH
, 0, &mm
->iWidth
) &&
4425 get_entry( &entry_MINHORZGAP
, 0, &mm
->iHorzGap
) &&
4426 get_entry( &entry_MINVERTGAP
, 0, &mm
->iVertGap
) &&
4427 get_entry( &entry_MINARRANGE
, 0, &mm
->iArrange
);
4428 mm
->iWidth
= max( 0, mm
->iWidth
);
4429 mm
->iHorzGap
= max( 0, mm
->iHorzGap
);
4430 mm
->iVertGap
= max( 0, mm
->iVertGap
);
4431 mm
->iArrange
&= 0x0f;
4435 case SPI_SETMINIMIZEDMETRICS
:
4437 MINIMIZEDMETRICS
*mm
= ptr
;
4438 if (mm
&& mm
->cbSize
== sizeof(*mm
))
4439 ret
= set_entry( &entry_MINWIDTH
, max( 0, mm
->iWidth
), NULL
, winini
) &&
4440 set_entry( &entry_MINHORZGAP
, max( 0, mm
->iHorzGap
), NULL
, winini
) &&
4441 set_entry( &entry_MINVERTGAP
, max( 0, mm
->iVertGap
), NULL
, winini
) &&
4442 set_entry( &entry_MINARRANGE
, mm
->iArrange
& 0x0f, NULL
, winini
);
4445 case SPI_GETICONMETRICS
:
4447 ICONMETRICSW
*icon
= ptr
;
4448 if(icon
&& icon
->cbSize
== sizeof(*icon
))
4450 ret
= get_entry( &entry_ICONHORIZONTALSPACING
, 0, &icon
->iHorzSpacing
) &&
4451 get_entry( &entry_ICONVERTICALSPACING
, 0, &icon
->iVertSpacing
) &&
4452 get_entry( &entry_ICONTITLEWRAP
, 0, &icon
->iTitleWrap
) &&
4453 get_entry( &entry_ICONTITLELOGFONT
, 0, &icon
->lfFont
);
4457 case SPI_SETICONMETRICS
:
4459 ICONMETRICSW
*icon
= ptr
;
4460 if (icon
&& icon
->cbSize
== sizeof(*icon
))
4461 ret
= set_entry( &entry_ICONVERTICALSPACING
, max(32,icon
->iVertSpacing
), NULL
, winini
) &&
4462 set_entry( &entry_ICONHORIZONTALSPACING
, max(32,icon
->iHorzSpacing
), NULL
, winini
) &&
4463 set_entry( &entry_ICONTITLEWRAP
, icon
->iTitleWrap
, NULL
, winini
) &&
4464 set_entry( &entry_ICONTITLELOGFONT
, 0, &icon
->lfFont
, winini
);
4467 case SPI_SETWORKAREA
:
4469 if (!ptr
) return FALSE
;
4470 spi_idx
= SPI_SETWORKAREA_IDX
;
4471 work_area
= *(RECT
*)ptr
;
4472 spi_loaded
[spi_idx
] = TRUE
;
4476 case SPI_GETWORKAREA
:
4478 if (!ptr
) return FALSE
;
4480 spi_idx
= SPI_SETWORKAREA_IDX
;
4481 if (!spi_loaded
[spi_idx
])
4483 struct monitor
*monitor
;
4485 if (!lock_display_devices()) return FALSE
;
4487 LIST_FOR_EACH_ENTRY( monitor
, &monitors
, struct monitor
, entry
)
4489 if (!(monitor
->flags
& MONITORINFOF_PRIMARY
)) continue;
4490 work_area
= monitor
->rc_work
;
4494 unlock_display_devices();
4495 spi_loaded
[spi_idx
] = TRUE
;
4497 *(RECT
*)ptr
= map_dpi_rect( work_area
, system_dpi
, get_thread_dpi() );
4499 TRACE("work area %s\n", wine_dbgstr_rect( &work_area
));
4503 WINE_SPI_FIXME(SPI_SETPENWINDOWS
);
4505 case SPI_GETFILTERKEYS
:
4507 LPFILTERKEYS filter_keys
= ptr
;
4508 WARN("SPI_GETFILTERKEYS not fully implemented\n");
4509 if (filter_keys
&& filter_keys
->cbSize
== sizeof(FILTERKEYS
))
4511 /* Indicate that no FilterKeys feature available */
4512 filter_keys
->dwFlags
= 0;
4513 filter_keys
->iWaitMSec
= 0;
4514 filter_keys
->iDelayMSec
= 0;
4515 filter_keys
->iRepeatMSec
= 0;
4516 filter_keys
->iBounceMSec
= 0;
4521 WINE_SPI_FIXME(SPI_SETFILTERKEYS
);
4523 case SPI_GETTOGGLEKEYS
:
4525 LPTOGGLEKEYS toggle_keys
= ptr
;
4526 WARN("SPI_GETTOGGLEKEYS not fully implemented\n");
4527 if (toggle_keys
&& toggle_keys
->cbSize
== sizeof(TOGGLEKEYS
))
4529 /* Indicate that no ToggleKeys feature available */
4530 toggle_keys
->dwFlags
= 0;
4536 WINE_SPI_FIXME(SPI_SETTOGGLEKEYS
);
4538 case SPI_GETMOUSEKEYS
:
4540 MOUSEKEYS
*mouse_keys
= ptr
;
4541 WARN("SPI_GETMOUSEKEYS not fully implemented\n");
4542 if (mouse_keys
&& mouse_keys
->cbSize
== sizeof(MOUSEKEYS
))
4544 /* Indicate that no MouseKeys feature available */
4545 mouse_keys
->dwFlags
= 0;
4546 mouse_keys
->iMaxSpeed
= 360;
4547 mouse_keys
->iTimeToMaxSpeed
= 1000;
4548 mouse_keys
->iCtrlSpeed
= 0;
4549 mouse_keys
->dwReserved1
= 0;
4550 mouse_keys
->dwReserved2
= 0;
4556 WINE_SPI_FIXME(SPI_SETMOUSEKEYS
);
4558 case SPI_GETSHOWSOUNDS
:
4559 ret
= get_entry( &entry_SHOWSOUNDS
, val
, ptr
);
4561 case SPI_SETSHOWSOUNDS
:
4562 ret
= set_entry( &entry_SHOWSOUNDS
, val
, ptr
, winini
);
4564 case SPI_GETSTICKYKEYS
:
4566 STICKYKEYS
*sticky_keys
= ptr
;
4567 WARN("SPI_GETSTICKYKEYS not fully implemented\n");
4568 if (sticky_keys
&& sticky_keys
->cbSize
== sizeof(STICKYKEYS
))
4570 /* Indicate that no StickyKeys feature available */
4571 sticky_keys
->dwFlags
= 0;
4577 WINE_SPI_FIXME(SPI_SETSTICKYKEYS
);
4579 case SPI_GETACCESSTIMEOUT
:
4581 ACCESSTIMEOUT
*access_timeout
= ptr
;
4582 WARN("SPI_GETACCESSTIMEOUT not fully implemented\n");
4583 if (access_timeout
&& access_timeout
->cbSize
== sizeof(ACCESSTIMEOUT
))
4585 /* Indicate that no accessibility features timeout is available */
4586 access_timeout
->dwFlags
= 0;
4587 access_timeout
->iTimeOutMSec
= 0;
4593 WINE_SPI_FIXME(SPI_SETACCESSTIMEOUT
);
4595 case SPI_GETSERIALKEYS
:
4597 LPSERIALKEYSW serial_keys
= ptr
;
4598 WARN("SPI_GETSERIALKEYS not fully implemented\n");
4599 if (serial_keys
&& serial_keys
->cbSize
== sizeof(SERIALKEYSW
))
4601 /* Indicate that no SerialKeys feature available */
4602 serial_keys
->dwFlags
= 0;
4603 serial_keys
->lpszActivePort
= NULL
;
4604 serial_keys
->lpszPort
= NULL
;
4605 serial_keys
->iBaudRate
= 0;
4606 serial_keys
->iPortState
= 0;
4612 WINE_SPI_FIXME(SPI_SETSERIALKEYS
);
4614 case SPI_GETSOUNDSENTRY
:
4616 SOUNDSENTRYW
*sound_sentry
= ptr
;
4617 WARN("SPI_GETSOUNDSENTRY not fully implemented\n");
4618 if (sound_sentry
&& sound_sentry
->cbSize
== sizeof(SOUNDSENTRYW
))
4620 /* Indicate that no SoundSentry feature available */
4621 sound_sentry
->dwFlags
= 0;
4622 sound_sentry
->iFSTextEffect
= 0;
4623 sound_sentry
->iFSTextEffectMSec
= 0;
4624 sound_sentry
->iFSTextEffectColorBits
= 0;
4625 sound_sentry
->iFSGrafEffect
= 0;
4626 sound_sentry
->iFSGrafEffectMSec
= 0;
4627 sound_sentry
->iFSGrafEffectColor
= 0;
4628 sound_sentry
->iWindowsEffect
= 0;
4629 sound_sentry
->iWindowsEffectMSec
= 0;
4630 sound_sentry
->lpszWindowsEffectDLL
= 0;
4631 sound_sentry
->iWindowsEffectOrdinal
= 0;
4637 WINE_SPI_FIXME(SPI_SETSOUNDSENTRY
);
4639 case SPI_GETHIGHCONTRAST
:
4641 HIGHCONTRASTW
*high_contrast
= ptr
;
4642 WARN("SPI_GETHIGHCONTRAST not fully implemented\n");
4643 if (high_contrast
&& high_contrast
->cbSize
== sizeof(HIGHCONTRASTW
))
4645 /* Indicate that no high contrast feature available */
4646 high_contrast
->dwFlags
= 0;
4647 high_contrast
->lpszDefaultScheme
= NULL
;
4653 WINE_SPI_FIXME(SPI_SETHIGHCONTRAST
);
4655 case SPI_GETKEYBOARDPREF
:
4656 ret
= get_entry( &entry_KEYBOARDPREF
, val
, ptr
);
4658 case SPI_SETKEYBOARDPREF
:
4659 ret
= set_entry( &entry_KEYBOARDPREF
, val
, ptr
, winini
);
4661 case SPI_GETSCREENREADER
:
4662 ret
= get_entry( &entry_SCREENREADER
, val
, ptr
);
4664 case SPI_SETSCREENREADER
:
4665 ret
= set_entry( &entry_SCREENREADER
, val
, ptr
, winini
);
4668 case SPI_GETANIMATION
:
4670 ANIMATIONINFO
*anim_info
= ptr
;
4672 /* Tell it "disabled" */
4673 if (anim_info
&& anim_info
->cbSize
== sizeof(ANIMATIONINFO
))
4675 /* Minimize and restore animation is disabled (nonzero == enabled) */
4676 anim_info
->iMinAnimate
= 0;
4682 WINE_SPI_WARN(SPI_SETANIMATION
);
4684 case SPI_GETFONTSMOOTHING
:
4685 ret
= get_entry( &entry_FONTSMOOTHING
, val
, ptr
);
4686 if (ret
) *(UINT
*)ptr
= (*(UINT
*)ptr
!= 0);
4688 case SPI_SETFONTSMOOTHING
:
4689 val
= val
? 2 : 0; /* Win NT4/2k/XP behavior */
4690 ret
= set_entry( &entry_FONTSMOOTHING
, val
, ptr
, winini
);
4692 case SPI_SETDRAGWIDTH
:
4693 ret
= set_entry( &entry_DRAGWIDTH
, val
, ptr
, winini
);
4695 case SPI_SETDRAGHEIGHT
:
4696 ret
= set_entry( &entry_DRAGHEIGHT
, val
, ptr
, winini
);
4699 WINE_SPI_FIXME(SPI_SETHANDHELD
);
4700 WINE_SPI_FIXME(SPI_GETLOWPOWERTIMEOUT
);
4701 WINE_SPI_FIXME(SPI_GETPOWEROFFTIMEOUT
);
4702 WINE_SPI_FIXME(SPI_SETLOWPOWERTIMEOUT
);
4703 WINE_SPI_FIXME(SPI_SETPOWEROFFTIMEOUT
);
4705 case SPI_GETLOWPOWERACTIVE
:
4706 ret
= get_entry( &entry_LOWPOWERACTIVE
, val
, ptr
);
4708 case SPI_SETLOWPOWERACTIVE
:
4709 ret
= set_entry( &entry_LOWPOWERACTIVE
, val
, ptr
, winini
);
4711 case SPI_GETPOWEROFFACTIVE
:
4712 ret
= get_entry( &entry_POWEROFFACTIVE
, val
, ptr
);
4714 case SPI_SETPOWEROFFACTIVE
:
4715 ret
= set_entry( &entry_POWEROFFACTIVE
, val
, ptr
, winini
);
4718 WINE_SPI_FIXME(SPI_SETCURSORS
);
4719 WINE_SPI_FIXME(SPI_SETICONS
);
4721 case SPI_GETDEFAULTINPUTLANG
:
4722 ret
= NtUserGetKeyboardLayout(0) != 0;
4725 WINE_SPI_FIXME(SPI_SETDEFAULTINPUTLANG
);
4726 WINE_SPI_FIXME(SPI_SETLANGTOGGLE
);
4728 case SPI_GETWINDOWSEXTENSION
:
4729 WARN( "pretend no support for Win9x Plus! for now.\n" );
4730 ret
= FALSE
; /* yes, this is the result value */
4732 case SPI_SETMOUSETRAILS
:
4733 ret
= set_entry( &entry_MOUSETRAILS
, val
, ptr
, winini
);
4735 case SPI_GETMOUSETRAILS
:
4736 ret
= get_entry( &entry_MOUSETRAILS
, val
, ptr
);
4738 case SPI_GETSNAPTODEFBUTTON
:
4739 ret
= get_entry( &entry_SNAPTODEFBUTTON
, val
, ptr
);
4741 case SPI_SETSNAPTODEFBUTTON
:
4742 ret
= set_entry( &entry_SNAPTODEFBUTTON
, val
, ptr
, winini
);
4744 case SPI_SETSCREENSAVERRUNNING
:
4745 ret
= set_entry( &entry_SCREENSAVERRUNNING
, val
, ptr
, winini
);
4747 case SPI_GETMOUSEHOVERWIDTH
:
4748 ret
= get_entry( &entry_MOUSEHOVERWIDTH
, val
, ptr
);
4750 case SPI_SETMOUSEHOVERWIDTH
:
4751 ret
= set_entry( &entry_MOUSEHOVERWIDTH
, val
, ptr
, winini
);
4753 case SPI_GETMOUSEHOVERHEIGHT
:
4754 ret
= get_entry( &entry_MOUSEHOVERHEIGHT
, val
, ptr
);
4756 case SPI_SETMOUSEHOVERHEIGHT
:
4757 ret
= set_entry( &entry_MOUSEHOVERHEIGHT
, val
, ptr
, winini
);
4759 case SPI_GETMOUSEHOVERTIME
:
4760 ret
= get_entry( &entry_MOUSEHOVERTIME
, val
, ptr
);
4762 case SPI_SETMOUSEHOVERTIME
:
4763 ret
= set_entry( &entry_MOUSEHOVERTIME
, val
, ptr
, winini
);
4765 case SPI_GETWHEELSCROLLLINES
:
4766 ret
= get_entry( &entry_WHEELSCROLLLINES
, val
, ptr
);
4768 case SPI_SETWHEELSCROLLLINES
:
4769 ret
= set_entry( &entry_WHEELSCROLLLINES
, val
, ptr
, winini
);
4771 case SPI_GETMENUSHOWDELAY
:
4772 ret
= get_entry( &entry_MENUSHOWDELAY
, val
, ptr
);
4774 case SPI_SETMENUSHOWDELAY
:
4775 ret
= set_entry( &entry_MENUSHOWDELAY
, val
, ptr
, winini
);
4777 case SPI_GETWHEELSCROLLCHARS
:
4778 ret
= get_entry( &entry_WHEELSCROLLCHARS
, val
, ptr
);
4780 case SPI_SETWHEELSCROLLCHARS
:
4781 ret
= set_entry( &entry_WHEELSCROLLCHARS
, val
, ptr
, winini
);
4784 WINE_SPI_FIXME(SPI_GETSHOWIMEUI
);
4785 WINE_SPI_FIXME(SPI_SETSHOWIMEUI
);
4787 case SPI_GETMOUSESPEED
:
4788 ret
= get_entry( &entry_MOUSESPEED
, val
, ptr
);
4790 case SPI_SETMOUSESPEED
:
4791 ret
= set_entry( &entry_MOUSESPEED
, val
, ptr
, winini
);
4793 case SPI_GETSCREENSAVERRUNNING
:
4794 ret
= get_entry( &entry_SCREENSAVERRUNNING
, val
, ptr
);
4796 case SPI_GETDESKWALLPAPER
:
4797 ret
= get_entry( &entry_DESKWALLPAPER
, val
, ptr
);
4799 case SPI_GETACTIVEWINDOWTRACKING
:
4800 ret
= get_entry( &entry_ACTIVEWINDOWTRACKING
, val
, ptr
);
4802 case SPI_SETACTIVEWINDOWTRACKING
:
4803 ret
= set_entry( &entry_ACTIVEWINDOWTRACKING
, val
, ptr
, winini
);
4805 case SPI_GETMENUANIMATION
:
4806 ret
= get_entry( &entry_MENUANIMATION
, val
, ptr
);
4808 case SPI_SETMENUANIMATION
:
4809 ret
= set_entry( &entry_MENUANIMATION
, val
, ptr
, winini
);
4811 case SPI_GETCOMBOBOXANIMATION
:
4812 ret
= get_entry( &entry_COMBOBOXANIMATION
, val
, ptr
);
4814 case SPI_SETCOMBOBOXANIMATION
:
4815 ret
= set_entry( &entry_COMBOBOXANIMATION
, val
, ptr
, winini
);
4817 case SPI_GETLISTBOXSMOOTHSCROLLING
:
4818 ret
= get_entry( &entry_LISTBOXSMOOTHSCROLLING
, val
, ptr
);
4820 case SPI_SETLISTBOXSMOOTHSCROLLING
:
4821 ret
= set_entry( &entry_LISTBOXSMOOTHSCROLLING
, val
, ptr
, winini
);
4823 case SPI_GETGRADIENTCAPTIONS
:
4824 ret
= get_entry( &entry_GRADIENTCAPTIONS
, val
, ptr
);
4826 case SPI_SETGRADIENTCAPTIONS
:
4827 ret
= set_entry( &entry_GRADIENTCAPTIONS
, val
, ptr
, winini
);
4829 case SPI_GETKEYBOARDCUES
:
4830 ret
= get_entry( &entry_KEYBOARDCUES
, val
, ptr
);
4832 case SPI_SETKEYBOARDCUES
:
4833 ret
= set_entry( &entry_KEYBOARDCUES
, val
, ptr
, winini
);
4835 case SPI_GETACTIVEWNDTRKZORDER
:
4836 ret
= get_entry( &entry_ACTIVEWNDTRKZORDER
, val
, ptr
);
4838 case SPI_SETACTIVEWNDTRKZORDER
:
4839 ret
= set_entry( &entry_ACTIVEWNDTRKZORDER
, val
, ptr
, winini
);
4841 case SPI_GETHOTTRACKING
:
4842 ret
= get_entry( &entry_HOTTRACKING
, val
, ptr
);
4844 case SPI_SETHOTTRACKING
:
4845 ret
= set_entry( &entry_HOTTRACKING
, val
, ptr
, winini
);
4847 case SPI_GETMENUFADE
:
4848 ret
= get_entry( &entry_MENUFADE
, val
, ptr
);
4850 case SPI_SETMENUFADE
:
4851 ret
= set_entry( &entry_MENUFADE
, val
, ptr
, winini
);
4853 case SPI_GETSELECTIONFADE
:
4854 ret
= get_entry( &entry_SELECTIONFADE
, val
, ptr
);
4856 case SPI_SETSELECTIONFADE
:
4857 ret
= set_entry( &entry_SELECTIONFADE
, val
, ptr
, winini
);
4859 case SPI_GETTOOLTIPANIMATION
:
4860 ret
= get_entry( &entry_TOOLTIPANIMATION
, val
, ptr
);
4862 case SPI_SETTOOLTIPANIMATION
:
4863 ret
= set_entry( &entry_TOOLTIPANIMATION
, val
, ptr
, winini
);
4865 case SPI_GETTOOLTIPFADE
:
4866 ret
= get_entry( &entry_TOOLTIPFADE
, val
, ptr
);
4868 case SPI_SETTOOLTIPFADE
:
4869 ret
= set_entry( &entry_TOOLTIPFADE
, val
, ptr
, winini
);
4871 case SPI_GETCURSORSHADOW
:
4872 ret
= get_entry( &entry_CURSORSHADOW
, val
, ptr
);
4874 case SPI_SETCURSORSHADOW
:
4875 ret
= set_entry( &entry_CURSORSHADOW
, val
, ptr
, winini
);
4877 case SPI_GETMOUSESONAR
:
4878 ret
= get_entry( &entry_MOUSESONAR
, val
, ptr
);
4880 case SPI_SETMOUSESONAR
:
4881 ret
= set_entry( &entry_MOUSESONAR
, val
, ptr
, winini
);
4883 case SPI_GETMOUSECLICKLOCK
:
4884 ret
= get_entry( &entry_MOUSECLICKLOCK
, val
, ptr
);
4886 case SPI_SETMOUSECLICKLOCK
:
4887 ret
= set_entry( &entry_MOUSECLICKLOCK
, val
, ptr
, winini
);
4889 case SPI_GETMOUSEVANISH
:
4890 ret
= get_entry( &entry_MOUSEVANISH
, val
, ptr
);
4892 case SPI_SETMOUSEVANISH
:
4893 ret
= set_entry( &entry_MOUSEVANISH
, val
, ptr
, winini
);
4895 case SPI_GETFLATMENU
:
4896 ret
= get_entry( &entry_FLATMENU
, val
, ptr
);
4898 case SPI_SETFLATMENU
:
4899 ret
= set_entry( &entry_FLATMENU
, val
, ptr
, winini
);
4901 case SPI_GETDROPSHADOW
:
4902 ret
= get_entry( &entry_DROPSHADOW
, val
, ptr
);
4904 case SPI_SETDROPSHADOW
:
4905 ret
= set_entry( &entry_DROPSHADOW
, val
, ptr
, winini
);
4907 case SPI_GETBLOCKSENDINPUTRESETS
:
4908 ret
= get_entry( &entry_BLOCKSENDINPUTRESETS
, val
, ptr
);
4910 case SPI_SETBLOCKSENDINPUTRESETS
:
4911 ret
= set_entry( &entry_BLOCKSENDINPUTRESETS
, val
, ptr
, winini
);
4913 case SPI_GETUIEFFECTS
:
4914 ret
= get_entry( &entry_UIEFFECTS
, val
, ptr
);
4916 case SPI_SETUIEFFECTS
:
4917 /* FIXME: this probably should mask other UI effect values when unset */
4918 ret
= set_entry( &entry_UIEFFECTS
, val
, ptr
, winini
);
4920 case SPI_GETDISABLEOVERLAPPEDCONTENT
:
4921 ret
= get_entry( &entry_DISABLEOVERLAPPEDCONTENT
, val
, ptr
);
4923 case SPI_SETDISABLEOVERLAPPEDCONTENT
:
4924 ret
= set_entry( &entry_DISABLEOVERLAPPEDCONTENT
, val
, ptr
, winini
);
4926 case SPI_GETCLIENTAREAANIMATION
:
4927 ret
= get_entry( &entry_CLIENTAREAANIMATION
, val
, ptr
);
4929 case SPI_SETCLIENTAREAANIMATION
:
4930 ret
= set_entry( &entry_CLIENTAREAANIMATION
, val
, ptr
, winini
);
4932 case SPI_GETCLEARTYPE
:
4933 ret
= get_entry( &entry_CLEARTYPE
, val
, ptr
);
4935 case SPI_SETCLEARTYPE
:
4936 ret
= set_entry( &entry_CLEARTYPE
, val
, ptr
, winini
);
4938 case SPI_GETSPEECHRECOGNITION
:
4939 ret
= get_entry( &entry_SPEECHRECOGNITION
, val
, ptr
);
4941 case SPI_SETSPEECHRECOGNITION
:
4942 ret
= set_entry( &entry_SPEECHRECOGNITION
, val
, ptr
, winini
);
4944 case SPI_GETFOREGROUNDLOCKTIMEOUT
:
4945 ret
= get_entry( &entry_FOREGROUNDLOCKTIMEOUT
, val
, ptr
);
4947 case SPI_SETFOREGROUNDLOCKTIMEOUT
:
4948 /* FIXME: this should check that the calling thread
4949 * is able to change the foreground window */
4950 ret
= set_entry( &entry_FOREGROUNDLOCKTIMEOUT
, val
, ptr
, winini
);
4952 case SPI_GETACTIVEWNDTRKTIMEOUT
:
4953 ret
= get_entry( &entry_ACTIVEWNDTRKTIMEOUT
, val
, ptr
);
4955 case SPI_SETACTIVEWNDTRKTIMEOUT
:
4956 ret
= get_entry( &entry_ACTIVEWNDTRKTIMEOUT
, val
, ptr
);
4958 case SPI_GETFOREGROUNDFLASHCOUNT
:
4959 ret
= get_entry( &entry_FOREGROUNDFLASHCOUNT
, val
, ptr
);
4961 case SPI_SETFOREGROUNDFLASHCOUNT
:
4962 ret
= set_entry( &entry_FOREGROUNDFLASHCOUNT
, val
, ptr
, winini
);
4964 case SPI_GETCARETWIDTH
:
4965 ret
= get_entry( &entry_CARETWIDTH
, val
, ptr
);
4967 case SPI_SETCARETWIDTH
:
4968 ret
= set_entry( &entry_CARETWIDTH
, val
, ptr
, winini
);
4970 case SPI_GETMOUSECLICKLOCKTIME
:
4971 ret
= get_entry( &entry_MOUSECLICKLOCKTIME
, val
, ptr
);
4973 case SPI_SETMOUSECLICKLOCKTIME
:
4974 ret
= set_entry( &entry_MOUSECLICKLOCKTIME
, val
, ptr
, winini
);
4976 case SPI_GETFONTSMOOTHINGTYPE
:
4977 ret
= get_entry( &entry_FONTSMOOTHINGTYPE
, val
, ptr
);
4979 case SPI_SETFONTSMOOTHINGTYPE
:
4980 ret
= set_entry( &entry_FONTSMOOTHINGTYPE
, val
, ptr
, winini
);
4982 case SPI_GETFONTSMOOTHINGCONTRAST
:
4983 ret
= get_entry( &entry_FONTSMOOTHINGCONTRAST
, val
, ptr
);
4985 case SPI_SETFONTSMOOTHINGCONTRAST
:
4986 ret
= set_entry( &entry_FONTSMOOTHINGCONTRAST
, val
, ptr
, winini
);
4988 case SPI_GETFOCUSBORDERWIDTH
:
4989 ret
= get_entry( &entry_FOCUSBORDERWIDTH
, val
, ptr
);
4991 case SPI_GETFOCUSBORDERHEIGHT
:
4992 ret
= get_entry( &entry_FOCUSBORDERHEIGHT
, val
, ptr
);
4994 case SPI_SETFOCUSBORDERWIDTH
:
4995 ret
= set_entry( &entry_FOCUSBORDERWIDTH
, val
, ptr
, winini
);
4997 case SPI_SETFOCUSBORDERHEIGHT
:
4998 ret
= set_entry( &entry_FOCUSBORDERHEIGHT
, val
, ptr
, winini
);
5000 case SPI_GETFONTSMOOTHINGORIENTATION
:
5001 ret
= get_entry( &entry_FONTSMOOTHINGORIENTATION
, val
, ptr
);
5003 case SPI_SETFONTSMOOTHINGORIENTATION
:
5004 ret
= set_entry( &entry_FONTSMOOTHINGORIENTATION
, val
, ptr
, winini
);
5006 case SPI_GETAUDIODESCRIPTION
:
5008 AUDIODESCRIPTION
*audio
= ptr
;
5009 if (audio
&& audio
->cbSize
== sizeof(AUDIODESCRIPTION
) && val
== sizeof(AUDIODESCRIPTION
) )
5011 ret
= get_entry( &entry_AUDIODESC_ON
, 0, &audio
->Enabled
) &&
5012 get_entry( &entry_AUDIODESC_LOCALE
, 0, &audio
->Locale
);
5016 case SPI_SETAUDIODESCRIPTION
:
5018 AUDIODESCRIPTION
*audio
= ptr
;
5019 if (audio
&& audio
->cbSize
== sizeof(AUDIODESCRIPTION
) && val
== sizeof(AUDIODESCRIPTION
) )
5021 ret
= set_entry( &entry_AUDIODESC_ON
, 0, &audio
->Enabled
, winini
) &&
5022 set_entry( &entry_AUDIODESC_LOCALE
, 0, &audio
->Locale
, winini
);
5027 FIXME( "Unknown action: %u\n", action
);
5028 RtlSetLastWin32Error( ERROR_INVALID_SPI_VALUE
);
5033 if (ret
&& (winini
& SPIF_UPDATEINIFILE
))
5035 static const WCHAR emptyW
[1];
5036 if (winini
& (SPIF_SENDWININICHANGE
| SPIF_SENDCHANGE
))
5037 send_message_timeout( HWND_BROADCAST
, WM_SETTINGCHANGE
, action
, (LPARAM
) emptyW
,
5038 SMTO_ABORTIFHUNG
, 2000, FALSE
);
5040 TRACE( "(%u, %u, %p, %u) ret %d\n", action
, val
, ptr
, winini
, ret
);
5043 #undef WINE_SPI_FIXME
5044 #undef WINE_SPI_WARN
5047 int get_system_metrics( int index
)
5049 NONCLIENTMETRICSW ncm
;
5050 MINIMIZEDMETRICS mm
;
5056 /* some metrics are dynamic */
5061 get_entry( &entry_SCROLLWIDTH
, 0, &ret
);
5062 return max( ret
, 8 );
5064 ncm
.cbSize
= sizeof(ncm
);
5065 NtUserSystemParametersInfo( SPI_GETNONCLIENTMETRICS
, 0, &ncm
, 0 );
5066 return ncm
.iCaptionHeight
+ 1;
5069 /* SM_C{X,Y}BORDER always returns 1 regardless of 'BorderWidth' value in registry */
5078 get_entry( &entry_SCROLLHEIGHT
, 0, &ret
);
5079 return max( ret
, 8 );
5082 return map_to_dpi( 32, get_system_dpi() );
5085 ret
= map_to_dpi( 32, get_system_dpi() );
5086 if (ret
>= 64) return 64;
5087 if (ret
>= 48) return 48;
5090 ncm
.cbSize
= sizeof(ncm
);
5091 NtUserSystemParametersInfo( SPI_GETNONCLIENTMETRICS
, 0, &ncm
, 0 );
5092 return ncm
.iMenuHeight
+ 1;
5093 case SM_CXFULLSCREEN
:
5094 /* see the remark for SM_CXMAXIMIZED, at least this formulation is correct */
5095 return get_system_metrics( SM_CXMAXIMIZED
) - 2 * get_system_metrics( SM_CXFRAME
);
5096 case SM_CYFULLSCREEN
:
5097 /* see the remark for SM_CYMAXIMIZED, at least this formulation is
5099 return get_system_metrics( SM_CYMAXIMIZED
) - get_system_metrics( SM_CYMIN
);
5100 case SM_CYKANJIWINDOW
:
5102 case SM_MOUSEPRESENT
:
5107 get_entry( &entry_MOUSEBUTTONSWAP
, 0, &ret
);
5115 ncm
.cbSize
= sizeof(ncm
);
5116 NtUserSystemParametersInfo( SPI_GETNONCLIENTMETRICS
, 0, &ncm
, 0 );
5117 hdc
= get_display_dc();
5118 get_text_metr_size( hdc
, &ncm
.lfCaptionFont
, NULL
, &ret
);
5119 release_display_dc( hdc
);
5120 return 3 * ncm
.iCaptionWidth
+ ncm
.iCaptionHeight
+ 4 * ret
+
5121 2 * get_system_metrics( SM_CXFRAME
) + 4;
5123 return get_system_metrics( SM_CYCAPTION
) + 2 * get_system_metrics( SM_CYFRAME
);
5125 get_entry( &entry_CAPTIONWIDTH
, 0, &ret
);
5126 return max( ret
, 8 );
5128 ncm
.cbSize
= sizeof(ncm
);
5129 NtUserSystemParametersInfo( SPI_GETNONCLIENTMETRICS
, 0, &ncm
, 0 );
5130 return ncm
.iCaptionHeight
;
5132 get_entry( &entry_BORDER
, 0, &ret
);
5133 ret
= max( ret
, 1 );
5134 return get_system_metrics( SM_CXDLGFRAME
) + ret
;
5136 get_entry( &entry_BORDER
, 0, &ret
);
5137 ret
= max( ret
, 1 );
5138 return get_system_metrics( SM_CYDLGFRAME
) + ret
;
5140 return get_system_metrics( SM_CXMIN
);
5142 return get_system_metrics( SM_CYMIN
);
5143 case SM_CXDOUBLECLK
:
5144 get_entry( &entry_DOUBLECLKWIDTH
, 0, &ret
);
5146 case SM_CYDOUBLECLK
:
5147 get_entry( &entry_DOUBLECLKHEIGHT
, 0, &ret
);
5149 case SM_CXICONSPACING
:
5150 im
.cbSize
= sizeof(im
);
5151 NtUserSystemParametersInfo( SPI_GETICONMETRICS
, sizeof(im
), &im
, 0 );
5152 return im
.iHorzSpacing
;
5153 case SM_CYICONSPACING
:
5154 im
.cbSize
= sizeof(im
);
5155 NtUserSystemParametersInfo( SPI_GETICONMETRICS
, sizeof(im
), &im
, 0 );
5156 return im
.iVertSpacing
;
5157 case SM_MENUDROPALIGNMENT
:
5158 NtUserSystemParametersInfo( SPI_GETMENUDROPALIGNMENT
, 0, &ret
, 0 );
5162 case SM_DBCSENABLED
:
5163 return ansi_cp
.MaximumCharacterSize
> 1;
5164 case SM_CMOUSEBUTTONS
:
5169 return get_system_metrics( SM_CXBORDER
) + 1;
5171 return get_system_metrics( SM_CYBORDER
) + 1;
5172 case SM_CXMINSPACING
:
5173 mm
.cbSize
= sizeof(mm
);
5174 NtUserSystemParametersInfo( SPI_GETMINIMIZEDMETRICS
, sizeof(mm
), &mm
, 0 );
5175 return get_system_metrics( SM_CXMINIMIZED
) + mm
.iHorzGap
;
5176 case SM_CYMINSPACING
:
5177 mm
.cbSize
= sizeof(mm
);
5178 NtUserSystemParametersInfo( SPI_GETMINIMIZEDMETRICS
, sizeof(mm
), &mm
, 0 );
5179 return get_system_metrics( SM_CYMINIMIZED
) + mm
.iVertGap
;
5182 return map_to_dpi( 16, get_system_dpi() ) & ~1;
5183 case SM_CYSMCAPTION
:
5184 ncm
.cbSize
= sizeof(ncm
);
5185 NtUserSystemParametersInfo( SPI_GETNONCLIENTMETRICS
, 0, &ncm
, 0 );
5186 return ncm
.iSmCaptionHeight
+ 1;
5188 get_entry( &entry_SMCAPTIONWIDTH
, 0, &ret
);
5191 ncm
.cbSize
= sizeof(ncm
);
5192 NtUserSystemParametersInfo( SPI_GETNONCLIENTMETRICS
, 0, &ncm
, 0 );
5193 return ncm
.iSmCaptionHeight
;
5195 get_entry( &entry_MENUWIDTH
, 0, &ret
);
5198 ncm
.cbSize
= sizeof(ncm
);
5199 NtUserSystemParametersInfo( SPI_GETNONCLIENTMETRICS
, 0, &ncm
, 0 );
5200 return ncm
.iMenuHeight
;
5202 mm
.cbSize
= sizeof(mm
);
5203 NtUserSystemParametersInfo( SPI_GETMINIMIZEDMETRICS
, sizeof(mm
), &mm
, 0 );
5205 case SM_CXMINIMIZED
:
5206 mm
.cbSize
= sizeof(mm
);
5207 NtUserSystemParametersInfo( SPI_GETMINIMIZEDMETRICS
, sizeof(mm
), &mm
, 0 );
5208 return mm
.iWidth
+ 6;
5209 case SM_CYMINIMIZED
:
5210 ncm
.cbSize
= sizeof(ncm
);
5211 NtUserSystemParametersInfo( SPI_GETNONCLIENTMETRICS
, 0, &ncm
, 0 );
5212 return ncm
.iCaptionHeight
+ 6;
5214 return get_system_metrics( SM_CXVIRTUALSCREEN
) + 4 + 2 * get_system_metrics( SM_CXFRAME
);
5216 return get_system_metrics( SM_CYVIRTUALSCREEN
) + 4 + 2 * get_system_metrics( SM_CYFRAME
);
5217 case SM_CXMAXIMIZED
:
5218 /* FIXME: subtract the width of any vertical application toolbars*/
5219 return get_system_metrics( SM_CXSCREEN
) + 2 * get_system_metrics( SM_CXFRAME
);
5220 case SM_CYMAXIMIZED
:
5221 /* FIXME: subtract the width of any horizontal application toolbars*/
5222 return get_system_metrics( SM_CYSCREEN
) + 2 * get_system_metrics( SM_CYCAPTION
);
5224 return 3; /* FIXME */
5226 return 0; /* 0 = ok, 1 = failsafe, 2 = failsafe + network */
5228 get_entry( &entry_DRAGWIDTH
, 0, &ret
);
5231 get_entry( &entry_DRAGHEIGHT
, 0, &ret
);
5234 get_entry( &entry_SHOWSOUNDS
, 0, &ret
);
5236 case SM_CXMENUCHECK
:
5237 case SM_CYMENUCHECK
:
5240 ncm
.cbSize
= sizeof(ncm
);
5241 NtUserSystemParametersInfo( SPI_GETNONCLIENTMETRICS
, 0, &ncm
, 0 );
5242 hdc
= get_display_dc();
5243 get_text_metr_size( hdc
, &ncm
.lfMenuFont
, &tm
, NULL
);
5244 release_display_dc( hdc
);
5245 return tm
.tmHeight
<= 0 ? 13 : ((tm
.tmHeight
+ tm
.tmExternalLeading
+ 1) / 2) * 2 - 1;
5247 case SM_SLOWMACHINE
:
5248 return 0; /* Never true */
5249 case SM_MIDEASTENABLED
:
5250 return 0; /* FIXME */
5251 case SM_MOUSEWHEELPRESENT
:
5254 rect
= get_primary_monitor_rect( get_thread_dpi() );
5255 return rect
.right
- rect
.left
;
5257 rect
= get_primary_monitor_rect( get_thread_dpi() );
5258 return rect
.bottom
- rect
.top
;
5259 case SM_XVIRTUALSCREEN
:
5260 rect
= get_virtual_screen_rect( get_thread_dpi() );
5262 case SM_YVIRTUALSCREEN
:
5263 rect
= get_virtual_screen_rect( get_thread_dpi() );
5265 case SM_CXVIRTUALSCREEN
:
5266 rect
= get_virtual_screen_rect( get_thread_dpi() );
5267 return rect
.right
- rect
.left
;
5268 case SM_CYVIRTUALSCREEN
:
5269 rect
= get_virtual_screen_rect( get_thread_dpi() );
5270 return rect
.bottom
- rect
.top
;
5272 if (!lock_display_devices()) return FALSE
;
5273 ret
= active_monitor_count();
5274 unlock_display_devices();
5276 case SM_SAMEDISPLAYFORMAT
:
5279 return 0; /* FIXME */
5280 case SM_CXFOCUSBORDER
:
5281 case SM_CYFOCUSBORDER
:
5284 case SM_MEDIACENTER
:
5293 static int get_system_metrics_for_dpi( int index
, unsigned int dpi
)
5295 NONCLIENTMETRICSW ncm
;
5300 /* some metrics are dynamic */
5305 get_entry_dpi( &entry_SCROLLWIDTH
, 0, &ret
, dpi
);
5306 return max( ret
, 8 );
5308 ncm
.cbSize
= sizeof(ncm
);
5309 NtUserSystemParametersInfoForDpi( SPI_GETNONCLIENTMETRICS
, 0, &ncm
, 0, dpi
);
5310 return ncm
.iCaptionHeight
+ 1;
5315 get_entry_dpi( &entry_SCROLLHEIGHT
, 0, &ret
, dpi
);
5316 return max( ret
, 8 );
5319 return map_to_dpi( 32, dpi
);
5322 ret
= map_to_dpi( 32, dpi
);
5323 if (ret
>= 64) return 64;
5324 if (ret
>= 48) return 48;
5327 ncm
.cbSize
= sizeof(ncm
);
5328 NtUserSystemParametersInfoForDpi( SPI_GETNONCLIENTMETRICS
, 0, &ncm
, 0, dpi
);
5329 return ncm
.iMenuHeight
+ 1;
5331 get_entry_dpi( &entry_CAPTIONWIDTH
, 0, &ret
, dpi
);
5332 return max( ret
, 8 );
5334 ncm
.cbSize
= sizeof(ncm
);
5335 NtUserSystemParametersInfoForDpi( SPI_GETNONCLIENTMETRICS
, 0, &ncm
, 0, dpi
);
5336 return ncm
.iCaptionHeight
;
5338 get_entry_dpi( &entry_BORDER
, 0, &ret
, dpi
);
5339 ret
= max( ret
, 1 );
5340 return get_system_metrics_for_dpi( SM_CXDLGFRAME
, dpi
) + ret
;
5342 get_entry_dpi( &entry_BORDER
, 0, &ret
, dpi
);
5343 ret
= max( ret
, 1 );
5344 return get_system_metrics_for_dpi( SM_CYDLGFRAME
, dpi
) + ret
;
5345 case SM_CXICONSPACING
:
5346 im
.cbSize
= sizeof(im
);
5347 NtUserSystemParametersInfoForDpi( SPI_GETICONMETRICS
, sizeof(im
), &im
, 0, dpi
);
5348 return im
.iHorzSpacing
;
5349 case SM_CYICONSPACING
:
5350 im
.cbSize
= sizeof(im
);
5351 NtUserSystemParametersInfoForDpi( SPI_GETICONMETRICS
, sizeof(im
), &im
, 0, dpi
);
5352 return im
.iVertSpacing
;
5355 return map_to_dpi( 16, dpi
) & ~1;
5356 case SM_CYSMCAPTION
:
5357 ncm
.cbSize
= sizeof(ncm
);
5358 NtUserSystemParametersInfoForDpi( SPI_GETNONCLIENTMETRICS
, 0, &ncm
, 0, dpi
);
5359 return ncm
.iSmCaptionHeight
+ 1;
5361 get_entry_dpi( &entry_SMCAPTIONWIDTH
, 0, &ret
, dpi
);
5364 ncm
.cbSize
= sizeof(ncm
);
5365 NtUserSystemParametersInfoForDpi( SPI_GETNONCLIENTMETRICS
, 0, &ncm
, 0, dpi
);
5366 return ncm
.iSmCaptionHeight
;
5368 get_entry_dpi( &entry_MENUWIDTH
, 0, &ret
, dpi
);
5371 ncm
.cbSize
= sizeof(ncm
);
5372 NtUserSystemParametersInfoForDpi( SPI_GETNONCLIENTMETRICS
, 0, &ncm
, 0, dpi
);
5373 return ncm
.iMenuHeight
;
5374 case SM_CXMENUCHECK
:
5375 case SM_CYMENUCHECK
:
5378 ncm
.cbSize
= sizeof(ncm
);
5379 NtUserSystemParametersInfoForDpi( SPI_GETNONCLIENTMETRICS
, 0, &ncm
, 0, dpi
);
5380 hdc
= get_display_dc();
5381 get_text_metr_size( hdc
, &ncm
.lfMenuFont
, &tm
, NULL
);
5382 release_display_dc( hdc
);
5383 return tm
.tmHeight
<= 0 ? 13 : ((tm
.tmHeight
+ tm
.tmExternalLeading
- 1) | 1);
5386 return get_system_metrics( index
);
5390 COLORREF
get_sys_color( int index
)
5394 if (index
>= 0 && index
< ARRAY_SIZE( system_colors
))
5395 get_entry( &system_colors
[index
], 0, &ret
);
5399 HBRUSH
get_55aa_brush(void)
5401 static const WORD pattern
[] = { 0x5555, 0xaaaa, 0x5555, 0xaaaa, 0x5555, 0xaaaa, 0x5555, 0xaaaa };
5402 static HBRUSH brush_55aa
;
5406 HBITMAP bitmap
= NtGdiCreateBitmap( 8, 8, 1, 1, pattern
);
5407 HBRUSH brush
= NtGdiCreatePatternBrushInternal( bitmap
, FALSE
, FALSE
);
5408 NtGdiDeleteObjectApp( bitmap
);
5409 make_gdi_object_system( brush
, TRUE
);
5410 if (InterlockedCompareExchangePointer( (void **)&brush_55aa
, brush
, 0 ))
5412 make_gdi_object_system( brush
, FALSE
);
5413 NtGdiDeleteObjectApp( brush
);
5419 HBRUSH
get_sys_color_brush( unsigned int index
)
5421 if (index
== COLOR_55AA_BRUSH
) return get_55aa_brush();
5422 if (index
>= ARRAY_SIZE( system_colors
)) return 0;
5424 if (!system_colors
[index
].brush
)
5426 HBRUSH brush
= NtGdiCreateSolidBrush( get_sys_color( index
), NULL
);
5427 make_gdi_object_system( brush
, TRUE
);
5428 if (InterlockedCompareExchangePointer( (void **)&system_colors
[index
].brush
, brush
, 0 ))
5430 make_gdi_object_system( brush
, FALSE
);
5431 NtGdiDeleteObjectApp( brush
);
5434 return system_colors
[index
].brush
;
5437 HPEN
get_sys_color_pen( unsigned int index
)
5439 if (index
>= ARRAY_SIZE( system_colors
)) return 0;
5441 if (!system_colors
[index
].pen
)
5443 HPEN pen
= NtGdiCreatePen( PS_SOLID
, 1, get_sys_color( index
), NULL
);
5444 make_gdi_object_system( pen
, TRUE
);
5445 if (InterlockedCompareExchangePointer( (void **)&system_colors
[index
].pen
, pen
, 0 ))
5447 make_gdi_object_system( pen
, FALSE
);
5448 NtGdiDeleteObjectApp( pen
);
5451 return system_colors
[index
].pen
;
5454 /**********************************************************************
5455 * NtUserGetDoubleClickTime (win32u.@)
5457 UINT WINAPI
NtUserGetDoubleClickTime(void)
5461 get_entry( &entry_DOUBLECLICKTIME
, 0, &time
);
5462 if (!time
) time
= 500;
5466 /*************************************************************************
5467 * NtUserSetSysColors (win32u.@)
5469 BOOL WINAPI
NtUserSetSysColors( INT count
, const INT
*colors
, const COLORREF
*values
)
5473 if (IS_INTRESOURCE(colors
)) return FALSE
; /* stupid app passes a color instead of an array */
5475 for (i
= 0; i
< count
; i
++)
5476 if (colors
[i
] >= 0 && colors
[i
] <= ARRAY_SIZE( system_colors
))
5477 set_entry( &system_colors
[colors
[i
]], values
[i
], 0, 0 );
5479 /* Send WM_SYSCOLORCHANGE message to all windows */
5480 send_message_timeout( HWND_BROADCAST
, WM_SYSCOLORCHANGE
, 0, 0,
5481 SMTO_ABORTIFHUNG
, 2000, FALSE
);
5482 /* Repaint affected portions of all visible windows */
5483 NtUserRedrawWindow( 0, NULL
, 0, RDW_INVALIDATE
| RDW_ERASE
| RDW_UPDATENOW
| RDW_ALLCHILDREN
);
5488 static LONG dpi_awareness
;
5490 /***********************************************************************
5491 * NtUserSetProcessDpiAwarenessContext (win32u.@)
5493 BOOL WINAPI
NtUserSetProcessDpiAwarenessContext( ULONG awareness
, ULONG unknown
)
5497 case NTUSER_DPI_UNAWARE
:
5498 case NTUSER_DPI_SYSTEM_AWARE
:
5499 case NTUSER_DPI_PER_MONITOR_AWARE
:
5500 case NTUSER_DPI_PER_MONITOR_AWARE_V2
:
5501 case NTUSER_DPI_PER_UNAWARE_GDISCALED
:
5504 RtlSetLastWin32Error( ERROR_INVALID_PARAMETER
);
5508 return !InterlockedCompareExchange( &dpi_awareness
, awareness
, 0 );
5511 /***********************************************************************
5512 * NtUserGetProcessDpiAwarenessContext (win32u.@)
5514 ULONG WINAPI
NtUserGetProcessDpiAwarenessContext( HANDLE process
)
5518 if (process
&& process
!= GetCurrentProcess())
5520 WARN( "not supported on other process %p\n", process
);
5521 return NTUSER_DPI_UNAWARE
;
5524 val
= ReadNoFence( &dpi_awareness
);
5525 if (!val
) return NTUSER_DPI_UNAWARE
;
5529 BOOL
message_beep( UINT i
)
5532 NtUserSystemParametersInfo( SPI_GETBEEP
, 0, &active
, FALSE
);
5533 if (active
) user_driver
->pBeep();
5537 static DWORD exiting_thread_id
;
5539 /**********************************************************************
5542 BOOL
is_exiting_thread( DWORD tid
)
5544 return tid
== exiting_thread_id
;
5547 static void thread_detach(void)
5549 struct user_thread_info
*thread_info
= get_user_thread_info();
5551 user_driver
->pThreadDetach();
5553 free( thread_info
->key_state
);
5554 thread_info
->key_state
= 0;
5555 free( thread_info
->rawinput
);
5557 destroy_thread_windows();
5558 cleanup_imm_thread();
5559 NtClose( thread_info
->server_queue
);
5561 exiting_thread_id
= 0;
5564 /***********************************************************************
5565 * NtUserCallNoParam (win32u.@)
5567 ULONG_PTR WINAPI
NtUserCallNoParam( ULONG code
)
5571 case NtUserCallNoParam_DestroyCaret
:
5572 return destroy_caret();
5574 case NtUserCallNoParam_GetDesktopWindow
:
5575 return HandleToUlong( get_desktop_window() );
5577 case NtUserCallNoParam_GetDialogBaseUnits
:
5578 return get_dialog_base_units();
5580 case NtUserCallNoParam_GetInputState
:
5581 return get_input_state();
5583 case NtUserCallNoParam_GetProcessDefaultLayout
:
5584 return process_layout
;
5586 case NtUserCallNoParam_GetProgmanWindow
:
5587 return HandleToUlong( get_progman_window() );
5589 case NtUserCallNoParam_GetShellWindow
:
5590 return HandleToUlong( get_shell_window() );
5592 case NtUserCallNoParam_GetTaskmanWindow
:
5593 return HandleToUlong( get_taskman_window() );
5595 case NtUserCallNoParam_ReleaseCapture
:
5596 return release_capture();
5598 /* temporary exports */
5599 case NtUserExitingThread
:
5600 exiting_thread_id
= GetCurrentThreadId();
5603 case NtUserThreadDetach
:
5608 FIXME( "invalid code %u\n", (int)code
);
5613 /***********************************************************************
5614 * NtUserCallOneParam (win32u.@)
5616 ULONG_PTR WINAPI
NtUserCallOneParam( ULONG_PTR arg
, ULONG code
)
5620 case NtUserCallOneParam_BeginDeferWindowPos
:
5621 return HandleToUlong( begin_defer_window_pos( arg
));
5623 case NtUserCallOneParam_CreateCursorIcon
:
5624 return HandleToUlong( alloc_cursoricon_handle( arg
));
5626 case NtUserCallOneParam_CreateMenu
:
5627 return HandleToUlong( create_menu( arg
) );
5629 case NtUserCallOneParam_EnableDC
:
5630 return set_dce_flags( UlongToHandle(arg
), DCHF_ENABLEDC
);
5632 case NtUserCallOneParam_EnableThunkLock
:
5633 enable_thunk_lock
= arg
;
5636 case NtUserCallOneParam_EnumClipboardFormats
:
5637 return enum_clipboard_formats( arg
);
5639 case NtUserCallOneParam_GetClipCursor
:
5640 return get_clip_cursor( (RECT
*)arg
);
5642 case NtUserCallOneParam_GetCursorPos
:
5643 return get_cursor_pos( (POINT
*)arg
);
5645 case NtUserCallOneParam_GetIconParam
:
5646 return get_icon_param( UlongToHandle(arg
) );
5648 case NtUserCallOneParam_GetMenuItemCount
:
5649 return get_menu_item_count( UlongToHandle(arg
) );
5651 case NtUserCallOneParam_GetSysColor
:
5652 return get_sys_color( arg
);
5654 case NtUserCallOneParam_IsWindowRectFullScreen
:
5655 return is_window_rect_full_screen( (const RECT
*)arg
);
5657 case NtUserCallOneParam_RealizePalette
:
5658 return realize_palette( UlongToHandle(arg
) );
5660 case NtUserCallOneParam_GetPrimaryMonitorRect
:
5661 *(RECT
*)arg
= get_primary_monitor_rect( 0 );
5664 case NtUserCallOneParam_GetSysColorBrush
:
5665 return HandleToUlong( get_sys_color_brush(arg
) );
5667 case NtUserCallOneParam_GetSysColorPen
:
5668 return HandleToUlong( get_sys_color_pen(arg
) );
5670 case NtUserCallOneParam_GetSystemMetrics
:
5671 return get_system_metrics( arg
);
5673 case NtUserCallOneParam_GetVirtualScreenRect
:
5674 *(RECT
*)arg
= get_virtual_screen_rect( 0 );
5677 case NtUserCallOneParam_MessageBeep
:
5678 return message_beep( arg
);
5680 case NtUserCallOneParam_ReplyMessage
:
5681 return reply_message_result( arg
);
5683 case NtUserCallOneParam_SetCaretBlinkTime
:
5684 return set_caret_blink_time( arg
);
5686 case NtUserCallOneParam_SetProcessDefaultLayout
:
5687 process_layout
= arg
;
5690 /* temporary exports */
5691 case NtUserGetDeskPattern
:
5692 return get_entry( &entry_DESKPATTERN
, 256, (WCHAR
*)arg
);
5695 FIXME( "invalid code %u\n", (int)code
);
5700 /***********************************************************************
5701 * NtUserCallTwoParam (win32u.@)
5703 ULONG_PTR WINAPI
NtUserCallTwoParam( ULONG_PTR arg1
, ULONG_PTR arg2
, ULONG code
)
5707 case NtUserCallTwoParam_GetDialogProc
:
5708 return (ULONG_PTR
)get_dialog_proc( (DLGPROC
)arg1
, arg2
);
5710 case NtUserCallTwoParam_GetMenuInfo
:
5711 return get_menu_info( UlongToHandle(arg1
), (MENUINFO
*)arg2
);
5713 case NtUserCallTwoParam_GetMonitorInfo
:
5714 return get_monitor_info( UlongToHandle(arg1
), (MONITORINFO
*)arg2
);
5716 case NtUserCallTwoParam_GetSystemMetricsForDpi
:
5717 return get_system_metrics_for_dpi( arg1
, arg2
);
5719 case NtUserCallTwoParam_MonitorFromRect
:
5720 return HandleToUlong( monitor_from_rect( (const RECT
*)arg1
, arg2
, get_thread_dpi() ));
5722 case NtUserCallTwoParam_SetCaretPos
:
5723 return set_caret_pos( arg1
, arg2
);
5725 case NtUserCallTwoParam_SetIconParam
:
5726 return set_icon_param( UlongToHandle(arg1
), arg2
);
5728 case NtUserCallTwoParam_UnhookWindowsHook
:
5729 return unhook_windows_hook( arg1
, (HOOKPROC
)arg2
);
5731 /* temporary exports */
5732 case NtUserAllocWinProc
:
5733 return (UINT_PTR
)alloc_winproc( (WNDPROC
)arg1
, arg2
);
5736 FIXME( "invalid code %u\n", (int)code
);
5741 /***********************************************************************
5742 * NtUserDisplayConfigGetDeviceInfo (win32u.@)
5744 NTSTATUS WINAPI
NtUserDisplayConfigGetDeviceInfo( DISPLAYCONFIG_DEVICE_INFO_HEADER
*packet
)
5746 NTSTATUS ret
= STATUS_UNSUCCESSFUL
;
5748 TRACE( "packet %p.\n", packet
);
5750 if (!packet
|| packet
->size
< sizeof(*packet
))
5751 return STATUS_UNSUCCESSFUL
;
5753 switch (packet
->type
)
5755 case DISPLAYCONFIG_DEVICE_INFO_GET_SOURCE_NAME
:
5757 DISPLAYCONFIG_SOURCE_DEVICE_NAME
*source_name
= (DISPLAYCONFIG_SOURCE_DEVICE_NAME
*)packet
;
5758 struct adapter
*adapter
;
5760 TRACE( "DISPLAYCONFIG_DEVICE_INFO_GET_SOURCE_NAME.\n" );
5762 if (packet
->size
< sizeof(*source_name
))
5763 return STATUS_INVALID_PARAMETER
;
5765 if (!lock_display_devices()) return STATUS_UNSUCCESSFUL
;
5767 LIST_FOR_EACH_ENTRY(adapter
, &adapters
, struct adapter
, entry
)
5769 if (source_name
->header
.id
!= adapter
->id
) continue;
5770 if (memcmp( &source_name
->header
.adapterId
, &adapter
->gpu_luid
, sizeof(adapter
->gpu_luid
) )) continue;
5772 lstrcpyW( source_name
->viewGdiDeviceName
, adapter
->dev
.device_name
);
5773 ret
= STATUS_SUCCESS
;
5777 unlock_display_devices();
5780 case DISPLAYCONFIG_DEVICE_INFO_GET_TARGET_NAME
:
5782 DISPLAYCONFIG_TARGET_DEVICE_NAME
*target_name
= (DISPLAYCONFIG_TARGET_DEVICE_NAME
*)packet
;
5783 char buffer
[ARRAY_SIZE(target_name
->monitorFriendlyDeviceName
)];
5784 struct monitor
*monitor
;
5786 TRACE( "DISPLAYCONFIG_DEVICE_INFO_GET_TARGET_NAME.\n" );
5788 if (packet
->size
< sizeof(*target_name
))
5789 return STATUS_INVALID_PARAMETER
;
5791 if (!lock_display_devices()) return STATUS_UNSUCCESSFUL
;
5793 memset( &target_name
->flags
, 0, sizeof(*target_name
) - offsetof(DISPLAYCONFIG_TARGET_DEVICE_NAME
, flags
) );
5795 LIST_FOR_EACH_ENTRY(monitor
, &monitors
, struct monitor
, entry
)
5797 if (target_name
->header
.id
!= monitor
->output_id
) continue;
5798 if (memcmp( &target_name
->header
.adapterId
, &monitor
->adapter
->gpu_luid
,
5799 sizeof(monitor
->adapter
->gpu_luid
) ))
5802 target_name
->outputTechnology
= DISPLAYCONFIG_OUTPUT_TECHNOLOGY_INTERNAL
;
5803 snprintf( buffer
, ARRAY_SIZE(buffer
), "Display%u", monitor
->output_id
+ 1 );
5804 asciiz_to_unicode( target_name
->monitorFriendlyDeviceName
, buffer
);
5805 lstrcpyW( target_name
->monitorDevicePath
, monitor
->dev
.interface_name
);
5806 if (monitor
->edid_info
.flags
& MONITOR_INFO_HAS_MONITOR_ID
)
5808 target_name
->edidManufactureId
= monitor
->edid_info
.manufacturer
;
5809 target_name
->edidProductCodeId
= monitor
->edid_info
.product_code
;
5810 target_name
->flags
.edidIdsValid
= 1;
5812 if (monitor
->edid_info
.flags
& MONITOR_INFO_HAS_MONITOR_NAME
)
5814 wcscpy( target_name
->monitorFriendlyDeviceName
, monitor
->edid_info
.monitor_name
);
5815 target_name
->flags
.friendlyNameFromEdid
= 1;
5817 ret
= STATUS_SUCCESS
;
5821 unlock_display_devices();
5824 case DISPLAYCONFIG_DEVICE_INFO_GET_TARGET_PREFERRED_MODE
:
5826 DISPLAYCONFIG_TARGET_PREFERRED_MODE
*preferred_mode
= (DISPLAYCONFIG_TARGET_PREFERRED_MODE
*)packet
;
5828 FIXME( "DISPLAYCONFIG_DEVICE_INFO_GET_TARGET_PREFERRED_MODE stub.\n" );
5830 if (packet
->size
< sizeof(*preferred_mode
))
5831 return STATUS_INVALID_PARAMETER
;
5833 return STATUS_NOT_SUPPORTED
;
5835 case DISPLAYCONFIG_DEVICE_INFO_GET_ADAPTER_NAME
:
5837 DISPLAYCONFIG_ADAPTER_NAME
*adapter_name
= (DISPLAYCONFIG_ADAPTER_NAME
*)packet
;
5839 FIXME( "DISPLAYCONFIG_DEVICE_INFO_GET_ADAPTER_NAME stub.\n" );
5841 if (packet
->size
< sizeof(*adapter_name
))
5842 return STATUS_INVALID_PARAMETER
;
5844 return STATUS_NOT_SUPPORTED
;
5846 case DISPLAYCONFIG_DEVICE_INFO_SET_TARGET_PERSISTENCE
:
5847 case DISPLAYCONFIG_DEVICE_INFO_GET_TARGET_BASE_TYPE
:
5848 case DISPLAYCONFIG_DEVICE_INFO_GET_SUPPORT_VIRTUAL_RESOLUTION
:
5849 case DISPLAYCONFIG_DEVICE_INFO_SET_SUPPORT_VIRTUAL_RESOLUTION
:
5850 case DISPLAYCONFIG_DEVICE_INFO_GET_ADVANCED_COLOR_INFO
:
5851 case DISPLAYCONFIG_DEVICE_INFO_SET_ADVANCED_COLOR_STATE
:
5852 case DISPLAYCONFIG_DEVICE_INFO_GET_SDR_WHITE_LEVEL
:
5854 FIXME( "Unimplemented packet type %u.\n", packet
->type
);
5855 return STATUS_INVALID_PARAMETER
;