user32: Cache monitor information.
Multiple applications call EnumDisplayMonitors very frequently. Reduce most of the overhead by caching. Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=47431 Signed-off-by: Zhiyi Zhang <zzhang@codeweavers.com> Signed-off-by: Alexandre Julliard <julliard@winehq.org>
This commit is contained in:
parent
d4115033ef
commit
95be042be3
dlls/user32
|
@ -305,6 +305,19 @@ static const WCHAR MONITOR_INTERFACE_PREFIX[] = {'\\','\\','\?','\\',0};
|
||||||
static const WCHAR GUID_DEVINTERFACE_MONITOR[] = {'#','{','e','6','f','0','7','b','5','f','-','e','e','9','7','-',
|
static const WCHAR GUID_DEVINTERFACE_MONITOR[] = {'#','{','e','6','f','0','7','b','5','f','-','e','e','9','7','-',
|
||||||
'4','a','9','0','-','b','0','7','6','-','3','3','f','5','7','b','f','4','e','a','a','7','}',0};
|
'4','a','9','0','-','b','0','7','6','-','3','3','f','5','7','b','f','4','e','a','a','7','}',0};
|
||||||
|
|
||||||
|
/* Cached monitor information */
|
||||||
|
static MONITORINFOEXW *monitors;
|
||||||
|
static UINT monitor_count;
|
||||||
|
static FILETIME last_query_monitors_time;
|
||||||
|
static CRITICAL_SECTION monitors_section;
|
||||||
|
static CRITICAL_SECTION_DEBUG monitors_critsect_debug =
|
||||||
|
{
|
||||||
|
0, 0, &monitors_section,
|
||||||
|
{ &monitors_critsect_debug.ProcessLocksList, &monitors_critsect_debug.ProcessLocksList },
|
||||||
|
0, 0, { (DWORD_PTR)(__FILE__ ": monitors_section") }
|
||||||
|
};
|
||||||
|
static CRITICAL_SECTION monitors_section = { &monitors_critsect_debug, -1 , 0, 0, 0, 0 };
|
||||||
|
|
||||||
static HDC display_dc;
|
static HDC display_dc;
|
||||||
static CRITICAL_SECTION display_dc_section;
|
static CRITICAL_SECTION display_dc_section;
|
||||||
static CRITICAL_SECTION_DEBUG critsect_debug =
|
static CRITICAL_SECTION_DEBUG critsect_debug =
|
||||||
|
@ -328,6 +341,7 @@ static DPI_AWARENESS dpi_awareness;
|
||||||
static DPI_AWARENESS default_awareness = DPI_AWARENESS_UNAWARE;
|
static DPI_AWARENESS default_awareness = DPI_AWARENESS_UNAWARE;
|
||||||
|
|
||||||
static HKEY volatile_base_key;
|
static HKEY volatile_base_key;
|
||||||
|
static HKEY video_key;
|
||||||
|
|
||||||
union sysparam_all_entry;
|
union sysparam_all_entry;
|
||||||
|
|
||||||
|
@ -3723,15 +3737,85 @@ HMONITOR WINAPI MonitorFromWindow(HWND hWnd, DWORD dwFlags)
|
||||||
return MonitorFromRect( &rect, dwFlags );
|
return MonitorFromRect( &rect, dwFlags );
|
||||||
}
|
}
|
||||||
|
|
||||||
BOOL CDECL nulldrv_GetMonitorInfo( HMONITOR handle, MONITORINFO *info )
|
/* Return FALSE on failure and TRUE on success */
|
||||||
|
static BOOL update_monitor_cache(void)
|
||||||
{
|
{
|
||||||
SP_DEVINFO_DATA device_data = {sizeof(device_data)};
|
SP_DEVINFO_DATA device_data = {sizeof(device_data)};
|
||||||
WCHAR adapter_name[CCHDEVICENAME];
|
HDEVINFO devinfo = INVALID_HANDLE_VALUE;
|
||||||
HDEVINFO devinfo;
|
MONITORINFOEXW *monitor_array;
|
||||||
DWORD error = 0;
|
FILETIME filetime = {0};
|
||||||
HANDLE mutex;
|
DWORD device_count = 0;
|
||||||
|
HANDLE mutex = NULL;
|
||||||
|
DWORD state_flags;
|
||||||
|
BOOL ret = FALSE;
|
||||||
|
DWORD i = 0;
|
||||||
DWORD type;
|
DWORD type;
|
||||||
BOOL ret;
|
|
||||||
|
/* Update monitor cache from SetupAPI if it's outdated */
|
||||||
|
if (!video_key && RegOpenKeyW( HKEY_LOCAL_MACHINE, VIDEO_KEY, &video_key ))
|
||||||
|
return FALSE;
|
||||||
|
if (RegQueryInfoKeyW( video_key, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, &filetime ))
|
||||||
|
return FALSE;
|
||||||
|
if (CompareFileTime( &filetime, &last_query_monitors_time ) < 1)
|
||||||
|
return TRUE;
|
||||||
|
|
||||||
|
mutex = get_display_device_init_mutex();
|
||||||
|
EnterCriticalSection( &monitors_section );
|
||||||
|
devinfo = SetupDiGetClassDevsW( &GUID_DEVCLASS_MONITOR, DISPLAY, NULL, DIGCF_PRESENT );
|
||||||
|
|
||||||
|
while (SetupDiEnumDeviceInfo( devinfo, i++, &device_data ))
|
||||||
|
{
|
||||||
|
/* Inactive monitors don't get enumerated */
|
||||||
|
if (!SetupDiGetDevicePropertyW( devinfo, &device_data, &WINE_DEVPROPKEY_MONITOR_STATEFLAGS, &type,
|
||||||
|
(BYTE *)&state_flags, sizeof(DWORD), NULL, 0 ))
|
||||||
|
goto fail;
|
||||||
|
if (state_flags & DISPLAY_DEVICE_ACTIVE)
|
||||||
|
device_count++;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (device_count && monitor_count < device_count)
|
||||||
|
{
|
||||||
|
monitor_array = heap_alloc( device_count * sizeof(*monitor_array) );
|
||||||
|
if (!monitor_array)
|
||||||
|
goto fail;
|
||||||
|
heap_free( monitors );
|
||||||
|
monitors = monitor_array;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (i = 0, monitor_count = 0; SetupDiEnumDeviceInfo( devinfo, i, &device_data ); i++)
|
||||||
|
{
|
||||||
|
if (!SetupDiGetDevicePropertyW( devinfo, &device_data, &WINE_DEVPROPKEY_MONITOR_STATEFLAGS, &type,
|
||||||
|
(BYTE *)&state_flags, sizeof(DWORD), NULL, 0 ))
|
||||||
|
goto fail;
|
||||||
|
if (!(state_flags & DISPLAY_DEVICE_ACTIVE))
|
||||||
|
continue;
|
||||||
|
if (!SetupDiGetDevicePropertyW( devinfo, &device_data, &WINE_DEVPROPKEY_MONITOR_RCMONITOR, &type,
|
||||||
|
(BYTE *)&monitors[monitor_count].rcMonitor, sizeof(RECT), NULL, 0 ))
|
||||||
|
goto fail;
|
||||||
|
if (!SetupDiGetDevicePropertyW( devinfo, &device_data, &WINE_DEVPROPKEY_MONITOR_RCWORK, &type,
|
||||||
|
(BYTE *)&monitors[monitor_count].rcWork, sizeof(RECT), NULL, 0 ))
|
||||||
|
goto fail;
|
||||||
|
if (!SetupDiGetDevicePropertyW( devinfo, &device_data, &WINE_DEVPROPKEY_MONITOR_ADAPTERNAME, &type,
|
||||||
|
(BYTE *)monitors[monitor_count].szDevice, CCHDEVICENAME * sizeof(WCHAR), NULL, 0))
|
||||||
|
goto fail;
|
||||||
|
monitors[monitor_count].dwFlags =
|
||||||
|
!lstrcmpW( DEFAULT_ADAPTER_NAME, monitors[monitor_count].szDevice ) ? MONITORINFOF_PRIMARY : 0;
|
||||||
|
|
||||||
|
monitor_count++;
|
||||||
|
}
|
||||||
|
|
||||||
|
last_query_monitors_time = filetime;
|
||||||
|
ret = TRUE;
|
||||||
|
fail:
|
||||||
|
SetupDiDestroyDeviceInfoList( devinfo );
|
||||||
|
LeaveCriticalSection( &monitors_section );
|
||||||
|
release_display_device_init_mutex( mutex );
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
BOOL CDECL nulldrv_GetMonitorInfo( HMONITOR handle, MONITORINFO *info )
|
||||||
|
{
|
||||||
|
UINT index = (UINT_PTR)handle - 1;
|
||||||
|
|
||||||
TRACE("(%p, %p)\n", handle, info);
|
TRACE("(%p, %p)\n", handle, info);
|
||||||
|
|
||||||
|
@ -3747,32 +3831,26 @@ BOOL CDECL nulldrv_GetMonitorInfo( HMONITOR handle, MONITORINFO *info )
|
||||||
return TRUE;
|
return TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Use SetupAPI to get monitors */
|
if (!update_monitor_cache())
|
||||||
mutex = get_display_device_init_mutex();
|
return FALSE;
|
||||||
devinfo = SetupDiGetClassDevsW( &GUID_DEVCLASS_MONITOR, DISPLAY, NULL, DIGCF_PRESENT );
|
|
||||||
if (SetupDiEnumDeviceInfo(devinfo, (DWORD)(UINT_PTR)handle - 1, &device_data))
|
EnterCriticalSection( &monitors_section );
|
||||||
|
if (index < monitor_count)
|
||||||
{
|
{
|
||||||
SetupDiGetDevicePropertyW( devinfo, &device_data, &WINE_DEVPROPKEY_MONITOR_RCMONITOR, &type,
|
info->rcMonitor = monitors[index].rcMonitor;
|
||||||
(BYTE *)&info->rcMonitor, sizeof(info->rcMonitor), NULL, 0 );
|
info->rcWork = monitors[index].rcWork;
|
||||||
SetupDiGetDevicePropertyW( devinfo, &device_data, &WINE_DEVPROPKEY_MONITOR_RCWORK, &type,
|
info->dwFlags = monitors[index].dwFlags;
|
||||||
(BYTE *)&info->rcWork, sizeof(info->rcWork), NULL, 0 );
|
|
||||||
SetupDiGetDevicePropertyW( devinfo, &device_data, &WINE_DEVPROPKEY_MONITOR_ADAPTERNAME, &type,
|
|
||||||
(BYTE *)adapter_name, sizeof(adapter_name), NULL, 0 );
|
|
||||||
info->dwFlags = !lstrcmpW( DEFAULT_ADAPTER_NAME, adapter_name ) ? MONITORINFOF_PRIMARY : 0;
|
|
||||||
if (info->cbSize >= sizeof(MONITORINFOEXW))
|
if (info->cbSize >= sizeof(MONITORINFOEXW))
|
||||||
lstrcpyW( ((MONITORINFOEXW *)info)->szDevice, adapter_name );
|
lstrcpyW( ((MONITORINFOEXW *)info)->szDevice, monitors[index].szDevice );
|
||||||
ret = TRUE;
|
LeaveCriticalSection( &monitors_section );
|
||||||
|
return TRUE;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
error = ERROR_INVALID_MONITOR_HANDLE;
|
LeaveCriticalSection( &monitors_section );
|
||||||
ret = FALSE;
|
|
||||||
}
|
|
||||||
SetupDiDestroyDeviceInfoList( devinfo );
|
|
||||||
release_display_device_init_mutex( mutex );
|
|
||||||
if (error)
|
|
||||||
SetLastError( ERROR_INVALID_MONITOR_HANDLE );
|
SetLastError( ERROR_INVALID_MONITOR_HANDLE );
|
||||||
return ret;
|
return FALSE;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/***********************************************************************
|
/***********************************************************************
|
||||||
|
@ -3875,56 +3953,29 @@ static BOOL CALLBACK enum_mon_callback( HMONITOR monitor, HDC hdc, LPRECT rect,
|
||||||
|
|
||||||
BOOL CDECL nulldrv_EnumDisplayMonitors( HDC hdc, RECT *rect, MONITORENUMPROC proc, LPARAM lp )
|
BOOL CDECL nulldrv_EnumDisplayMonitors( HDC hdc, RECT *rect, MONITORENUMPROC proc, LPARAM lp )
|
||||||
{
|
{
|
||||||
SP_DEVINFO_DATA device_data = {sizeof(device_data)};
|
RECT default_rect = {0, 0, 640, 480};
|
||||||
USEROBJECTFLAGS flags;
|
DWORD i;
|
||||||
HWINSTA winstation;
|
|
||||||
BOOL success = FALSE;
|
|
||||||
HDEVINFO devinfo;
|
|
||||||
RECT monitor_rect;
|
|
||||||
DWORD state_flags;
|
|
||||||
HANDLE mutex;
|
|
||||||
DWORD type;
|
|
||||||
DWORD i = 0;
|
|
||||||
|
|
||||||
TRACE("(%p, %p, %p, 0x%lx)\n", hdc, rect, proc, lp);
|
TRACE("(%p, %p, %p, 0x%lx)\n", hdc, rect, proc, lp);
|
||||||
|
|
||||||
/* Use SetupAPI to get monitors only if window station has visible display surfaces */
|
if (update_monitor_cache())
|
||||||
winstation = GetProcessWindowStation();
|
|
||||||
if (GetUserObjectInformationA( winstation, UOI_FLAGS, &flags, sizeof(flags), NULL ) && (flags.dwFlags & WSF_VISIBLE))
|
|
||||||
{
|
{
|
||||||
mutex = get_display_device_init_mutex();
|
EnterCriticalSection( &monitors_section );
|
||||||
devinfo = SetupDiGetClassDevsW( &GUID_DEVCLASS_MONITOR, DISPLAY, NULL, DIGCF_PRESENT );
|
for (i = 0; i < monitor_count; i++)
|
||||||
while (SetupDiEnumDeviceInfo( devinfo, i++, &device_data ))
|
|
||||||
{
|
{
|
||||||
/* Inactive monitors don't get enumerated */
|
if (!proc( (HMONITOR)(UINT_PTR)(i + 1), hdc, &monitors[i].rcMonitor, lp ))
|
||||||
if (!SetupDiGetDevicePropertyW( devinfo, &device_data, &WINE_DEVPROPKEY_MONITOR_STATEFLAGS, &type,
|
|
||||||
(BYTE *)&state_flags, sizeof(state_flags), NULL, 0 )
|
|
||||||
|| !(state_flags & DISPLAY_DEVICE_ACTIVE))
|
|
||||||
continue;
|
|
||||||
|
|
||||||
if (SetupDiGetDevicePropertyW( devinfo, &device_data, &WINE_DEVPROPKEY_MONITOR_RCMONITOR, &type,
|
|
||||||
(BYTE *)&monitor_rect, sizeof(monitor_rect), NULL, 0 ))
|
|
||||||
{
|
{
|
||||||
if (!proc( (HMONITOR)(UINT_PTR)i, hdc, &monitor_rect, lp ))
|
LeaveCriticalSection( &monitors_section );
|
||||||
{
|
return FALSE;
|
||||||
SetupDiDestroyDeviceInfoList( devinfo );
|
|
||||||
release_display_device_init_mutex( mutex );
|
|
||||||
return FALSE;
|
|
||||||
}
|
|
||||||
success = TRUE;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
SetupDiDestroyDeviceInfoList( devinfo );
|
LeaveCriticalSection( &monitors_section );
|
||||||
release_display_device_init_mutex( mutex );
|
return TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Fallback to report one monitor if using SetupAPI failed */
|
/* Fallback to report one monitor if using SetupAPI failed */
|
||||||
if (!success)
|
if (!proc( NULLDRV_DEFAULT_HMONITOR, hdc, &default_rect, lp ))
|
||||||
{
|
return FALSE;
|
||||||
RECT default_rect = {0, 0, 640, 480};
|
|
||||||
if (!proc( NULLDRV_DEFAULT_HMONITOR, hdc, &default_rect, lp ))
|
|
||||||
return FALSE;
|
|
||||||
}
|
|
||||||
return TRUE;
|
return TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue