Checking flags of the thread desktop to determine whether virtual desktop is on is unreliable. For example, CEF applications create their own desktop and so is_virtual_desktop() could incorrectly report that virtual desktop is off.
From: Zhiyi Zhang zzhang@codeweavers.com
Checking flags of the thread desktop to determine whether virtual desktop is on is unreliable. For example, CEF applications create their own desktop and so is_virtual_desktop() could incorrectly report that virtual desktop is off.
Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=55810 --- dlls/win32u/winstation.c | 20 +++++++++++++++----- programs/explorer/desktop.c | 24 +++++++++++++++++++++++- 2 files changed, 38 insertions(+), 6 deletions(-)
diff --git a/dlls/win32u/winstation.c b/dlls/win32u/winstation.c index b187b246941..249ea922f28 100644 --- a/dlls/win32u/winstation.c +++ b/dlls/win32u/winstation.c @@ -42,12 +42,22 @@ WINE_DECLARE_DEBUG_CHANNEL(win);
BOOL is_virtual_desktop(void) { - HANDLE desktop = NtUserGetThreadDesktop( GetCurrentThreadId() ); - USEROBJECTFLAGS flags = {0}; - DWORD len; + static const WCHAR enabledW[] = {'E','n','a','b','l','e','d',0}; + static int enabled = -1; + char value_buffer[FIELD_OFFSET(KEY_VALUE_PARTIAL_INFORMATION, Data[40 * sizeof(WCHAR)])]; + KEY_VALUE_PARTIAL_INFORMATION *info = (void *)value_buffer; + DWORD size; + HKEY key; + + if (enabled == -1 && (key = reg_open_hkcu_key( "Software\Wine\Explorer\VirtualDesktop" ))) + { + size = query_reg_value( key, enabledW, info, sizeof(value_buffer) ); + if (size == sizeof(DWORD) && info->Type == REG_DWORD) + enabled = *(DWORD *)info->Data > 0; + NtClose( key ); + }
- if (!NtUserGetObjectInformation( desktop, UOI_FLAGS, &flags, sizeof(flags), &len )) return FALSE; - return !!(flags.dwFlags & DF_WINE_CREATE_DESKTOP); + return enabled > 0; }
/*********************************************************************** diff --git a/programs/explorer/desktop.c b/programs/explorer/desktop.c index 9a58f13d887..923e5c27bb0 100644 --- a/programs/explorer/desktop.c +++ b/programs/explorer/desktop.c @@ -973,6 +973,21 @@ static void initialize_display_settings( unsigned int width, unsigned int height } }
+static void save_virtual_desktop_settings( DWORD enabled ) +{ + LSTATUS ls; + HKEY hkey; + + /* Store virtual desktop status at HKCU\Software\Wine\Explorer\VirtualDesktop */ + ls = RegCreateKeyExW( HKEY_CURRENT_USER, L"Software\Wine\Explorer\VirtualDesktop", 0, NULL, + REG_OPTION_VOLATILE, KEY_ALL_ACCESS, NULL, &hkey, NULL ); + if (!ls) + { + RegSetValueExW( hkey, L"Enabled", 0, REG_DWORD, (BYTE *)&enabled, sizeof(enabled) ); + RegCloseKey( hkey ); + } +} + static void set_desktop_window_title( HWND hwnd, const WCHAR *name ) { static const WCHAR desktop_nameW[] = L"Wine desktop"; @@ -1065,7 +1080,10 @@ void manage_desktop( WCHAR *arg ) { DEVMODEW devmode = {.dmPelsWidth = width, .dmPelsHeight = height}; /* magic: desktop "root" means use the root window */ - if ((using_root = !wcsicmp( name, L"root" ))) desktop = CreateDesktopW( name, NULL, NULL, 0, DESKTOP_ALL_ACCESS, NULL ); + using_root = !wcsicmp( name, L"root" ); + /* save virtual desktop status to the registry before creating desktops */ + save_virtual_desktop_settings( !using_root ); + if (using_root) desktop = CreateDesktopW( name, NULL, NULL, 0, DESKTOP_ALL_ACCESS, NULL ); else desktop = CreateDesktopW( name, NULL, &devmode, DF_WINE_CREATE_DESKTOP, DESKTOP_ALL_ACCESS, NULL ); if (!desktop) { @@ -1074,6 +1092,10 @@ void manage_desktop( WCHAR *arg ) } SetThreadDesktop( desktop ); } + else + { + save_virtual_desktop_settings( FALSE ); + }
/* create the desktop window */ hwnd = CreateWindowExW( 0, DESKTOP_CLASS_ATOM, NULL,
Thanks for addressing this one for me. I was struggling to understand the explorer/desktop/winstation architecture well enough to figure out where was the right place to store this information.
I don't understand how this can be a prefix global setting. You can run `explorer /desktop=bla,800x600` and it will start a new virtual desktop within which applications can be run, while still allowing to run applications outside of virtual desktop when run with the default one.
On Fri Jan 5 09:56:29 2024 +0000, Rémi Bernon wrote:
I don't understand how this can be a prefix global setting. You can run `explorer /desktop=bla,800x600` and it will start a new virtual desktop within which applications can be run, while still allowing to run applications outside of virtual desktop when run with the default one.
I don't know if this behavior is officially supported on Wine. But yeah, maybe it's best to keep the old way. @julliard, do you have any opinions on this?
On Fri Jan 5 09:56:29 2024 +0000, Zhiyi Zhang wrote:
I don't know if this behavior is officially supported on Wine. But yeah, maybe it's best to keep the old way. @julliard, do you have any opinions on this?
Perhaps this could be solved by inheriting the DF_WINE_CREATE_DESKTOP flag between desktops. Though this might require another one to break the chain when explorer is started with "root".
On Fri Jan 5 10:07:31 2024 +0000, Rémi Bernon wrote:
Perhaps this could be solved by inheriting the DF_WINE_CREATE_DESKTOP flag between desktops. Though this might require another one to break the chain when explorer is started with "root".
(Or use the fact that name is "root" and devmode is NULL in that case)
On Fri Jan 5 10:09:03 2024 +0000, Rémi Bernon wrote:
(Or use the fact that name is "root" and devmode is NULL in that case)
There are a few things to consider as well when using the current desktop to determine virtual desktop status. We don't want to incorrectly report whether the virtual desktop is on or off. For example, when we use "root" and devmode is NULL and report that virtual desktop is off, we have to make sure that when using a non-"root" or valid devmode desktop can't be interpreted as the virtual desktop is on, because applications can create their own desktops for purposes like sandboxing.
We might also have to consider that when a thread doesn't have enough access to query desktops. I don't know if that's possible.
I don't know if this behavior is officially supported on Wine. But yeah, maybe it's best to keep the old way. @julliard, do you have any opinions on this?
The virtual desktop is tied to a specific desktop, there can be multiple ones, as well as apps using the root desktop, all at the same time. It can't possibly be a flag in the registry.