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
-- v3: server: inherit wine internal desktop flags when creating desktops. include: Rename DF_WINE_CREATE_DESKTOP to DF_WINE_VIRTUAL_DESKTOP.
From: Zhiyi Zhang zzhang@codeweavers.com
--- dlls/user32/winstation.c | 2 +- dlls/win32u/winstation.c | 6 +++--- include/ntuser.h | 2 +- programs/explorer/desktop.c | 2 +- server/winstation.c | 2 +- 5 files changed, 7 insertions(+), 7 deletions(-)
diff --git a/dlls/user32/winstation.c b/dlls/user32/winstation.c index 62593ca046f..c433ea6ec88 100644 --- a/dlls/user32/winstation.c +++ b/dlls/user32/winstation.c @@ -256,7 +256,7 @@ HDESK WINAPI CreateDesktopW( LPCWSTR name, LPCWSTR device, LPDEVMODEW devmode, OBJECT_ATTRIBUTES attr; UNICODE_STRING str;
- if (device || (devmode && !(flags & DF_WINE_CREATE_DESKTOP))) + if (device || (devmode && !(flags & DF_WINE_VIRTUAL_DESKTOP))) { SetLastError( ERROR_INVALID_PARAMETER ); return 0; diff --git a/dlls/win32u/winstation.c b/dlls/win32u/winstation.c index b187b246941..9df27517a43 100644 --- a/dlls/win32u/winstation.c +++ b/dlls/win32u/winstation.c @@ -47,7 +47,7 @@ BOOL is_virtual_desktop(void) DWORD len;
if (!NtUserGetObjectInformation( desktop, UOI_FLAGS, &flags, sizeof(flags), &len )) return FALSE; - return !!(flags.dwFlags & DF_WINE_CREATE_DESKTOP); + return !!(flags.dwFlags & DF_WINE_VIRTUAL_DESKTOP); }
/*********************************************************************** @@ -154,7 +154,7 @@ HDESK WINAPI NtUserCreateDesktopEx( OBJECT_ATTRIBUTES *attr, UNICODE_STRING *dev WCHAR buffer[MAX_PATH]; HANDLE ret;
- if ((device && device->Length) || (devmode && !(flags & DF_WINE_CREATE_DESKTOP))) + if ((device && device->Length) || (devmode && !(flags & DF_WINE_VIRTUAL_DESKTOP))) { RtlSetLastWin32Error( ERROR_INVALID_PARAMETER ); return 0; @@ -184,7 +184,7 @@ HDESK WINAPI NtUserCreateDesktopEx( OBJECT_ATTRIBUTES *attr, UNICODE_STRING *dev }
/* force update display cache to use virtual desktop display settings */ - if (flags & DF_WINE_CREATE_DESKTOP) update_display_cache( TRUE ); + if (flags & DF_WINE_VIRTUAL_DESKTOP) update_display_cache( TRUE ); return ret; }
diff --git a/include/ntuser.h b/include/ntuser.h index f23249ace5a..a694fddf9d3 100644 --- a/include/ntuser.h +++ b/include/ntuser.h @@ -294,7 +294,7 @@ struct unpack_dde_message_params #define SPY_RESULT_DEFWND 0x0002
/* CreateDesktop wine specific flag */ -#define DF_WINE_CREATE_DESKTOP 0x80000000 +#define DF_WINE_VIRTUAL_DESKTOP 0x80000000
/* NtUserMessageCall codes */ enum diff --git a/programs/explorer/desktop.c b/programs/explorer/desktop.c index 9a58f13d887..e89addf5727 100644 --- a/programs/explorer/desktop.c +++ b/programs/explorer/desktop.c @@ -1066,7 +1066,7 @@ 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 ); - else desktop = CreateDesktopW( name, NULL, &devmode, DF_WINE_CREATE_DESKTOP, DESKTOP_ALL_ACCESS, NULL ); + else desktop = CreateDesktopW( name, NULL, &devmode, DF_WINE_VIRTUAL_DESKTOP, DESKTOP_ALL_ACCESS, NULL ); if (!desktop) { ERR( "failed to create desktop %s error %ld\n", debugstr_w(name), GetLastError() ); diff --git a/server/winstation.c b/server/winstation.c index 5903497d61e..5c59fbffae1 100644 --- a/server/winstation.c +++ b/server/winstation.c @@ -243,7 +243,7 @@ static struct desktop *create_desktop( const struct unicode_str *name, unsigned } else { - desktop->flags |= (flags & DF_WINE_CREATE_DESKTOP); + desktop->flags |= (flags & DF_WINE_VIRTUAL_DESKTOP); clear_error(); } }
From: Zhiyi Zhang zzhang@codeweavers.com
Based on Rémi's idea.
CEF applications create their own desktops and so is_virtual_desktop() could incorrectly report that virtual desktop is off if DF_WINE_VIRTUAL_DESKTOP is not inherited.
Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=55810 --- dlls/user32/winstation.c | 3 ++- include/ntuser.h | 1 + programs/explorer/desktop.c | 2 +- server/winstation.c | 23 +++++++++++++++++++++-- 4 files changed, 25 insertions(+), 4 deletions(-)
diff --git a/dlls/user32/winstation.c b/dlls/user32/winstation.c index c433ea6ec88..ec8be243b32 100644 --- a/dlls/user32/winstation.c +++ b/dlls/user32/winstation.c @@ -256,7 +256,8 @@ HDESK WINAPI CreateDesktopW( LPCWSTR name, LPCWSTR device, LPDEVMODEW devmode, OBJECT_ATTRIBUTES attr; UNICODE_STRING str;
- if (device || (devmode && !(flags & DF_WINE_VIRTUAL_DESKTOP))) + if (device || (devmode && !(flags & DF_WINE_VIRTUAL_DESKTOP)) + || (flags & DF_WINE_ROOT_DESKTOP && flags & DF_WINE_VIRTUAL_DESKTOP)) { SetLastError( ERROR_INVALID_PARAMETER ); return 0; diff --git a/include/ntuser.h b/include/ntuser.h index a694fddf9d3..9043772dcd3 100644 --- a/include/ntuser.h +++ b/include/ntuser.h @@ -294,6 +294,7 @@ struct unpack_dde_message_params #define SPY_RESULT_DEFWND 0x0002
/* CreateDesktop wine specific flag */ +#define DF_WINE_ROOT_DESKTOP 0x40000000 #define DF_WINE_VIRTUAL_DESKTOP 0x80000000
/* NtUserMessageCall codes */ diff --git a/programs/explorer/desktop.c b/programs/explorer/desktop.c index e89addf5727..ae017533fc9 100644 --- a/programs/explorer/desktop.c +++ b/programs/explorer/desktop.c @@ -1065,7 +1065,7 @@ 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 ); + if ((using_root = !wcsicmp( name, L"root" ))) desktop = CreateDesktopW( name, NULL, NULL, DF_WINE_ROOT_DESKTOP, DESKTOP_ALL_ACCESS, NULL ); else desktop = CreateDesktopW( name, NULL, &devmode, DF_WINE_VIRTUAL_DESKTOP, DESKTOP_ALL_ACCESS, NULL ); if (!desktop) { diff --git a/server/winstation.c b/server/winstation.c index 5c59fbffae1..d7ae0c1db72 100644 --- a/server/winstation.c +++ b/server/winstation.c @@ -221,14 +221,30 @@ struct desktop *get_desktop_obj( struct process *process, obj_handle_t handle, u static struct desktop *create_desktop( const struct unicode_str *name, unsigned int attr, unsigned int flags, struct winstation *winstation ) { - struct desktop *desktop; + struct desktop *desktop, *current_desktop; + + if (flags & DF_WINE_ROOT_DESKTOP && flags & DF_WINE_VIRTUAL_DESKTOP) + { + set_error( STATUS_INVALID_PARAMETER ); + return NULL; + }
if ((desktop = create_named_object( &winstation->obj, &desktop_ops, name, attr, NULL ))) { if (get_error() != STATUS_OBJECT_NAME_EXISTS) { /* initialize it if it didn't already exist */ + desktop->flags = flags; + + /* inherit DF_WINE_*_DESKTOP flags if none of them are specified */ + if (!(flags & (DF_WINE_ROOT_DESKTOP | DF_WINE_VIRTUAL_DESKTOP)) + && (current_desktop = get_thread_desktop( current, 0 ))) + { + desktop->flags |= current_desktop->flags & (DF_WINE_VIRTUAL_DESKTOP | DF_WINE_ROOT_DESKTOP); + release_object( current_desktop ); + } + desktop->winstation = (struct winstation *)grab_object( winstation ); desktop->top_window = NULL; desktop->msg_window = NULL; @@ -243,7 +259,10 @@ static struct desktop *create_desktop( const struct unicode_str *name, unsigned } else { - desktop->flags |= (flags & DF_WINE_VIRTUAL_DESKTOP); + if (!(desktop->flags & DF_WINE_VIRTUAL_DESKTOP)) + desktop->flags |= flags & DF_WINE_ROOT_DESKTOP; + if (!(desktop->flags & DF_WINE_ROOT_DESKTOP)) + desktop->flags |= flags & DF_WINE_VIRTUAL_DESKTOP; clear_error(); } }
v3: Add an internal flag for the root desktop.
Rémi Bernon (@rbernon) commented about server/winstation.c:
static struct desktop *create_desktop( const struct unicode_str *name, unsigned int attr, unsigned int flags, struct winstation *winstation ) {
- struct desktop *desktop;
- struct desktop *desktop, *current_desktop;
- if (flags & DF_WINE_ROOT_DESKTOP && flags & DF_WINE_VIRTUAL_DESKTOP)
- {
set_error( STATUS_INVALID_PARAMETER );
return NULL;
- }
I'm not sure we should bother about misusing the internal flags, they are only used in a single place.
Rémi Bernon (@rbernon) commented about server/winstation.c:
} else {
desktop->flags |= (flags & DF_WINE_VIRTUAL_DESKTOP);
if (!(desktop->flags & DF_WINE_VIRTUAL_DESKTOP))
desktop->flags |= flags & DF_WINE_ROOT_DESKTOP;
if (!(desktop->flags & DF_WINE_ROOT_DESKTOP))
desktop->flags |= flags & DF_WINE_VIRTUAL_DESKTOP;
Same here, IMO `desktop->flags |= (flags & (DF_WINE_VIRTUAL_DESKTOP | DF_WINE_ROOT_DESKTOP));` is enough and makes the code simpler to read.