win32u: Enumerate monitors from their device keys.
This commit is contained in:
parent
b4e4921cb6
commit
b59619d2e4
1 changed files with 85 additions and 50 deletions
|
@ -74,6 +74,9 @@ static const WCHAR guid_devclass_displayW[] =
|
|||
{'{','4','D','3','6','E','9','6','8','-','E','3','2','5','-','1','1','C','E','-',
|
||||
'B','F','C','1','-','0','8','0','0','2','B','E','1','0','3','1','8','}',0};
|
||||
static const char guid_devclass_monitorA[] = "{4D36E96E-E325-11CE-BFC1-08002BE10318}";
|
||||
static const WCHAR guid_devclass_monitorW[] =
|
||||
{'{','4','D','3','6','E','9','6','E','-','E','3','2','5','-','1','1','C','E','-',
|
||||
'B','F','C','1','-','0','8','0','0','2','B','E','1','0','3','1','8','}',0};
|
||||
|
||||
static const char guid_devinterface_display_adapterA[] = "{5B45201D-F2F2-4F3B-85BB-30FF1F953599}";
|
||||
static const char guid_display_device_arrivalA[] = "{1CA05180-A699-450A-9A0C-DE4FBE3DDD89}";
|
||||
|
@ -658,28 +661,14 @@ static BOOL read_display_adapter_settings( unsigned int index, struct adapter *i
|
|||
return TRUE;
|
||||
}
|
||||
|
||||
static BOOL read_monitor_settings( struct adapter *adapter, UINT index, struct monitor *monitor )
|
||||
static BOOL read_monitor_from_registry( struct monitor *monitor )
|
||||
{
|
||||
char buffer[4096];
|
||||
KEY_VALUE_PARTIAL_INFORMATION *value = (void *)buffer;
|
||||
WCHAR *value_str = (WCHAR *)value->Data;
|
||||
HKEY hkey, subkey;
|
||||
DWORD size;
|
||||
UINT i;
|
||||
|
||||
if (!(hkey = reg_open_key( config_key, adapter->config_key,
|
||||
lstrlenW( adapter->config_key ) * sizeof(WCHAR) )))
|
||||
return FALSE;
|
||||
|
||||
/* Interface name */
|
||||
sprintf( buffer, "MonitorID%u", index );
|
||||
size = query_reg_ascii_value( hkey, buffer, value, sizeof(buffer) );
|
||||
NtClose( hkey );
|
||||
if (!size || value->Type != REG_SZ) return FALSE;
|
||||
|
||||
for (i = 0; i < value->DataLength / sizeof(WCHAR); i++) monitor->path[i] = value_str[i];
|
||||
if (!(hkey = reg_open_key( enum_key, value_str, value->DataLength - sizeof(WCHAR) )))
|
||||
return FALSE;
|
||||
if (!(hkey = reg_open_ascii_key( enum_key, monitor->path ))) return FALSE;
|
||||
|
||||
/* Output ID */
|
||||
size = query_reg_subkey_value( hkey, devpropkey_monitor_output_idA,
|
||||
|
@ -723,6 +712,22 @@ static BOOL read_monitor_settings( struct adapter *adapter, UINT index, struct m
|
|||
return TRUE;
|
||||
}
|
||||
|
||||
static BOOL read_adapter_monitor_path( HKEY hkey, UINT index, char *path )
|
||||
{
|
||||
char buffer[4096];
|
||||
KEY_VALUE_PARTIAL_INFORMATION *value = (void *)buffer;
|
||||
WCHAR *value_str = (WCHAR *)value->Data;
|
||||
DWORD size;
|
||||
UINT i;
|
||||
|
||||
sprintf( buffer, "MonitorID%u", index );
|
||||
size = query_reg_ascii_value( hkey, buffer, value, sizeof(buffer) );
|
||||
if (!size || value->Type != REG_SZ) return FALSE;
|
||||
|
||||
for (i = 0; i < value->DataLength / sizeof(WCHAR); i++) path[i] = value_str[i];
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static void reg_empty_key( HKEY root, const char *key_name )
|
||||
{
|
||||
char buffer[4096];
|
||||
|
@ -1598,16 +1603,36 @@ static struct gpu *find_gpu_from_path( const char *path )
|
|||
return NULL;
|
||||
}
|
||||
|
||||
static void enum_monitors( const char *path )
|
||||
{
|
||||
struct monitor *monitor;
|
||||
if (!(monitor = calloc( 1, sizeof(*monitor) ))) return;
|
||||
strcpy( monitor->path, path );
|
||||
list_add_tail( &monitors, &monitor->entry );
|
||||
}
|
||||
|
||||
static struct monitor *find_monitor_from_path( const char *path )
|
||||
{
|
||||
struct monitor *monitor;
|
||||
|
||||
LIST_FOR_EACH_ENTRY( monitor, &monitors, struct monitor, entry )
|
||||
if (!strcmp( monitor->path, path )) return monitor;
|
||||
|
||||
ERR( "Failed to find monitor with path %s\n", debugstr_a(path) );
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static BOOL update_display_cache_from_registry(void)
|
||||
{
|
||||
char path[MAX_PATH];
|
||||
DWORD adapter_id, monitor_id, monitor_count = 0, size;
|
||||
KEY_BASIC_INFORMATION key;
|
||||
struct adapter *adapter;
|
||||
struct monitor *monitor, *monitor2;
|
||||
struct monitor *monitor;
|
||||
HANDLE mutex = NULL;
|
||||
NTSTATUS status;
|
||||
struct gpu *gpu;
|
||||
HKEY hkey;
|
||||
BOOL ret;
|
||||
|
||||
/* If user driver did initialize the registry, then exit */
|
||||
|
@ -1629,6 +1654,7 @@ static BOOL update_display_cache_from_registry(void)
|
|||
clear_display_devices();
|
||||
|
||||
enum_device_keys( "PCI", guid_devclass_displayW, sizeof(guid_devclass_displayW), enum_gpus );
|
||||
enum_device_keys( "DISPLAY", guid_devclass_monitorW, sizeof(guid_devclass_monitorW), enum_monitors );
|
||||
|
||||
LIST_FOR_EACH_ENTRY( gpu, &gpus, struct gpu, entry )
|
||||
{
|
||||
|
@ -1636,6 +1662,12 @@ static BOOL update_display_cache_from_registry(void)
|
|||
WARN( "Failed to read gpu from registry\n" );
|
||||
}
|
||||
|
||||
LIST_FOR_EACH_ENTRY( monitor, &monitors, struct monitor, entry )
|
||||
{
|
||||
if (!read_monitor_from_registry( monitor ))
|
||||
WARN( "Failed to read monitor from registry\n" );
|
||||
}
|
||||
|
||||
for (adapter_id = 0;; adapter_id++)
|
||||
{
|
||||
if (!(adapter = calloc( 1, sizeof(*adapter) ))) break;
|
||||
|
@ -1651,34 +1683,24 @@ static BOOL update_display_cache_from_registry(void)
|
|||
}
|
||||
|
||||
list_add_tail( &adapters, &adapter->entry );
|
||||
|
||||
size = lstrlenW( adapter->config_key ) * sizeof(WCHAR);
|
||||
if (!(hkey = reg_open_key( config_key, adapter->config_key, size ))) continue;
|
||||
|
||||
for (monitor_id = 0;; monitor_id++)
|
||||
{
|
||||
if (!(monitor = calloc( 1, sizeof(*monitor) ))) break;
|
||||
if (!read_monitor_settings( adapter, monitor_id, monitor ))
|
||||
{
|
||||
free( monitor );
|
||||
break;
|
||||
}
|
||||
struct monitor *monitor;
|
||||
|
||||
if (!read_adapter_monitor_path( hkey, monitor_id, path )) break;
|
||||
if (!(monitor = find_monitor_from_path( path ))) continue;
|
||||
|
||||
monitor->id = monitor_id;
|
||||
monitor->adapter = adapter_acquire( adapter );
|
||||
|
||||
if (adapter->state_flags & DISPLAY_DEVICE_ATTACHED_TO_DESKTOP)
|
||||
{
|
||||
LIST_FOR_EACH_ENTRY( monitor2, &monitors, struct monitor, entry )
|
||||
{
|
||||
if (!is_monitor_active( monitor2 )) continue;
|
||||
if (EqualRect( &monitor2->rc_monitor, &monitor->rc_monitor ))
|
||||
{
|
||||
monitor->is_clone = TRUE;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
monitor->handle = UlongToHandle( ++monitor_count );
|
||||
list_add_tail( &monitors, &monitor->entry );
|
||||
if (adapter->monitor_count++) monitor->is_clone = TRUE;
|
||||
}
|
||||
|
||||
NtClose( hkey );
|
||||
}
|
||||
|
||||
if ((ret = !list_empty( &adapters ) && !list_empty( &monitors )))
|
||||
|
@ -3378,6 +3400,18 @@ INT get_display_depth( UNICODE_STRING *name )
|
|||
return depth;
|
||||
}
|
||||
|
||||
static BOOL should_enumerate_monitor( struct monitor *monitor, const POINT *origin,
|
||||
const RECT *limit, RECT *rect )
|
||||
{
|
||||
if (!is_monitor_active( monitor )) return FALSE;
|
||||
if (monitor->is_clone) return FALSE;
|
||||
|
||||
*rect = map_dpi_rect( monitor->rc_monitor, get_monitor_dpi( monitor->handle ),
|
||||
get_thread_dpi() );
|
||||
OffsetRect( rect, -origin->x, -origin->y );
|
||||
return intersect_rect( rect, rect, limit );
|
||||
}
|
||||
|
||||
/***********************************************************************
|
||||
* NtUserEnumDisplayMonitors (win32u.@)
|
||||
*/
|
||||
|
@ -3419,21 +3453,22 @@ BOOL WINAPI NtUserEnumDisplayMonitors( HDC hdc, RECT *rect, MONITORENUMPROC proc
|
|||
}
|
||||
|
||||
count = 0;
|
||||
|
||||
/* enumerate primary monitors first */
|
||||
LIST_FOR_EACH_ENTRY(monitor, &monitors, struct monitor, entry)
|
||||
{
|
||||
RECT monrect;
|
||||
if (!is_monitor_primary( monitor )) continue;
|
||||
if (should_enumerate_monitor( monitor, &origin, &limit, &enum_info[count].rect ))
|
||||
enum_info[count++].handle = monitor->handle;
|
||||
break;
|
||||
}
|
||||
|
||||
if (!is_monitor_active( monitor )) continue;
|
||||
|
||||
monrect = map_dpi_rect( monitor->rc_monitor, get_monitor_dpi( monitor->handle ),
|
||||
get_thread_dpi() );
|
||||
OffsetRect( &monrect, -origin.x, -origin.y );
|
||||
if (!intersect_rect( &monrect, &monrect, &limit )) continue;
|
||||
if (monitor->is_clone) continue;
|
||||
|
||||
enum_info[count].handle = monitor->handle;
|
||||
enum_info[count].rect = monrect;
|
||||
count++;
|
||||
/* then non-primary monitors */
|
||||
LIST_FOR_EACH_ENTRY(monitor, &monitors, struct monitor, entry)
|
||||
{
|
||||
if (is_monitor_primary( monitor )) continue;
|
||||
if (should_enumerate_monitor( monitor, &origin, &limit, &enum_info[count].rect ))
|
||||
enum_info[count++].handle = monitor->handle;
|
||||
}
|
||||
|
||||
unlock_display_devices();
|
||||
|
|
Loading…
Add table
Reference in a new issue