From: Rémi Bernon rbernon@codeweavers.com
--- dlls/win32u/input.c | 70 +++++++++++++++++++++++++--- dlls/win32u/message.c | 8 +++- dlls/win32u/ntgdi_private.h | 9 ---- dlls/win32u/sysparams.c | 4 ++ dlls/win32u/win32u_private.h | 16 ++++++- dlls/win32u/winstation.c | 13 ++++++ dlls/winex11.drv/desktop.c | 3 -- dlls/winex11.drv/event.c | 6 +-- dlls/winex11.drv/mouse.c | 89 +----------------------------------- dlls/winex11.drv/window.c | 2 - dlls/winex11.drv/x11drv.h | 4 -- 11 files changed, 103 insertions(+), 121 deletions(-)
diff --git a/dlls/win32u/input.c b/dlls/win32u/input.c index 0dc166986f3..205b792d784 100644 --- a/dlls/win32u/input.c +++ b/dlls/win32u/input.c @@ -408,6 +408,7 @@ static LONG clipping_cursor; /* clipping thread counter */
LONG global_key_state_counter = 0; BOOL grab_pointer = TRUE; +BOOL grab_fullscreen = FALSE;
static void kbd_tables_init_vsc2vk( const KBDTABLES *tables, BYTE vsc2vk[0x300] ) { @@ -1845,7 +1846,7 @@ static BOOL set_active_window( HWND hwnd, HWND *prev, BOOL mouse, BOOL focus ) if (previous == hwnd) { if (prev) *prev = hwnd; - return TRUE; + goto done; }
/* call CBT hook chain */ @@ -1869,7 +1870,7 @@ static BOOL set_active_window( HWND hwnd, HWND *prev, BOOL mouse, BOOL focus ) SERVER_END_REQ; if (!ret) return FALSE; if (prev) *prev = previous; - if (previous == hwnd) return TRUE; + if (previous == hwnd) goto done;
if (hwnd) { @@ -1934,6 +1935,8 @@ static BOOL set_active_window( HWND hwnd, HWND *prev, BOOL mouse, BOOL focus ) } }
+done: + if (hwnd) clip_fullscreen_window( hwnd, FALSE ); return TRUE; }
@@ -2458,6 +2461,49 @@ BOOL WINAPI NtUserIsMouseInPointerEnabled(void) return FALSE; }
+/*********************************************************************** + * clip_fullscreen_window + * + * Turn on clipping if the active window is fullscreen. + */ +BOOL clip_fullscreen_window( HWND hwnd, BOOL reset ) +{ + struct user_thread_info *thread_info = get_user_thread_info(); + MONITORINFO monitor_info = {.cbSize = sizeof(MONITORINFO)}; + RECT rect, virtual_rect = NtUserGetVirtualScreenRect(); + HMONITOR monitor; + DWORD style; + + if (hwnd == NtUserGetDesktopWindow()) return FALSE; + if (hwnd != NtUserGetForegroundWindow()) return FALSE; + + style = NtUserGetWindowLongW( hwnd, GWL_STYLE ); + if (!(style & WS_VISIBLE)) return FALSE; + if ((style & (WS_POPUP | WS_CHILD)) == WS_CHILD) return FALSE; + /* maximized windows don't count as full screen */ + if ((style & WS_MAXIMIZE) && (style & WS_CAPTION) == WS_CAPTION) return FALSE; + + if (!NtUserGetWindowRect( hwnd, &rect )) return FALSE; + if (!NtUserIsWindowRectFullScreen( &rect )) return FALSE; + if (NtGetTickCount() - thread_info->clipping_reset < 1000) return FALSE; + if (!reset && clipping_cursor && thread_info->clipping_cursor) return FALSE; /* already clipping */ + + if (!(monitor = NtUserMonitorFromWindow( hwnd, MONITOR_DEFAULTTONEAREST ))) return FALSE; + if (!NtUserGetMonitorInfo( monitor, &monitor_info )) return FALSE; + if (!grab_fullscreen) + { + RECT virtual_rect = NtUserGetVirtualScreenRect(); + if (!EqualRect( &monitor_info.rcMonitor, &virtual_rect )) return FALSE; + if (is_virtual_desktop()) return FALSE; + } + + /* shrink the clipping rect to make sure it is not ignored for being fullscreen */ + if (EqualRect( &monitor_info.rcMonitor, &virtual_rect )) InflateRect( &monitor_info.rcMonitor, -1, -1 ); + + TRACE( "win %p clipping fullscreen\n", hwnd ); + return NtUserClipCursor( &monitor_info.rcMonitor ); +} + /********************************************************************** * NtUserGetPointerInfoList (win32u.@) */ @@ -2498,14 +2544,15 @@ BOOL get_clip_cursor( RECT *rect ) return ret; }
-BOOL process_wine_clipcursor( BOOL empty, BOOL reset ) +BOOL process_wine_clipcursor( HWND hwnd, BOOL empty, BOOL reset ) { struct user_thread_info *thread_info = get_user_thread_info(); - RECT rect; + RECT rect, virtual_rect = NtUserGetVirtualScreenRect(); + BOOL was_clipping;
- TRACE( "empty %u, reset %u\n", empty, reset ); + TRACE( "hwnd %p, empty %u, reset %u\n", hwnd, empty, reset );
- if (thread_info->clipping_cursor) InterlockedDecrement( &clipping_cursor ); + if ((was_clipping = thread_info->clipping_cursor)) InterlockedDecrement( &clipping_cursor ); thread_info->clipping_cursor = FALSE;
if (reset) @@ -2515,9 +2562,18 @@ BOOL process_wine_clipcursor( BOOL empty, BOOL reset ) }
if (!grab_pointer) return TRUE; - if (empty) return user_driver->pClipCursor( NULL, reset );
+ /* we are clipping if the clip rectangle is smaller than the screen */ get_clip_cursor( &rect ); + intersect_rect( &rect, &rect, &virtual_rect ); + if (EqualRect( &rect, &virtual_rect )) empty = TRUE; + if (empty) + { + /* if currently clipping, check if we should switch to fullscreen clipping */ + if (was_clipping && clip_fullscreen_window( hwnd, TRUE )) return TRUE; + return user_driver->pClipCursor( NULL, FALSE ); + } + if (!user_driver->pClipCursor( &rect, FALSE )) return FALSE; InterlockedIncrement( &clipping_cursor ); thread_info->clipping_cursor = TRUE; diff --git a/dlls/win32u/message.c b/dlls/win32u/message.c index 7238dd1bd46..e10350fcd3b 100644 --- a/dlls/win32u/message.c +++ b/dlls/win32u/message.c @@ -1272,7 +1272,8 @@ static LRESULT handle_internal_message( HWND hwnd, UINT msg, WPARAM wparam, LPAR return call_current_hook( h_extra->handle, HC_ACTION, wparam, h_extra->lparam ); } case WM_WINE_CLIPCURSOR: - return process_wine_clipcursor( wparam, lparam ); + if (wparam && lparam) return clip_fullscreen_window( hwnd, FALSE ); + return process_wine_clipcursor( hwnd, wparam, lparam ); case WM_WINE_UPDATEWINDOWSTATE: update_window_state( hwnd ); return 0; @@ -1767,7 +1768,7 @@ static BOOL process_hardware_message( MSG *msg, UINT hw_id, const struct hardwar else if (is_mouse_message( msg->message )) ret = process_mouse_message( msg, hw_id, msg_data->info, hwnd_filter, first, last, remove ); else if (msg->message == WM_WINE_CLIPCURSOR) - process_wine_clipcursor( msg->wParam, msg->lParam ); + process_wine_clipcursor( msg->hwnd, msg->wParam, msg->lParam ); else ERR( "unknown message type %x\n", msg->message ); SetThreadDpiAwarenessContext( context ); @@ -2594,6 +2595,9 @@ NTSTATUS send_hardware_message( HWND hwnd, const INPUT *input, const RAWINPUT *r info.timeout = 0; info.params = NULL;
+ if (input->type == INPUT_MOUSE && (input->mi.dwFlags & (MOUSEEVENTF_LEFTDOWN | MOUSEEVENTF_RIGHTDOWN))) + clip_fullscreen_window( hwnd, FALSE ); + if (input->type == INPUT_HARDWARE && rawinput->header.dwType == RIM_TYPEHID) { if (input->hi.uMsg == WM_INPUT_DEVICE_CHANGE) diff --git a/dlls/win32u/ntgdi_private.h b/dlls/win32u/ntgdi_private.h index 87b7d943295..ad4c709b865 100644 --- a/dlls/win32u/ntgdi_private.h +++ b/dlls/win32u/ntgdi_private.h @@ -531,15 +531,6 @@ static inline DC *get_physdev_dc( PHYSDEV dev ) return get_nulldrv_dc( dev ); }
-static inline BOOL intersect_rect( RECT *dst, const RECT *src1, const RECT *src2 ) -{ - dst->left = max( src1->left, src2->left ); - dst->top = max( src1->top, src2->top ); - dst->right = min( src1->right, src2->right ); - dst->bottom = min( src1->bottom, src2->bottom ); - return !IsRectEmpty( dst ); -} - static inline void order_rect( RECT *rect ) { if (rect->left > rect->right) diff --git a/dlls/win32u/sysparams.c b/dlls/win32u/sysparams.c index 1ffb040ae75..2424777970d 100644 --- a/dlls/win32u/sysparams.c +++ b/dlls/win32u/sysparams.c @@ -2704,6 +2704,8 @@ static LONG apply_display_settings( const WCHAR *devname, const DEVMODEW *devmod send_message_timeout( HWND_BROADCAST, WM_DISPLAYCHANGE, current_mode.dmBitsPerPel, MAKELPARAM( current_mode.dmPelsWidth, current_mode.dmPelsHeight ), SMTO_ABORTIFHUNG, 2000, FALSE ); + /* post clip_fullscreen_window request to the foreground window */ + NtUserPostMessage( NtUserGetForegroundWindow(), WM_WINE_CLIPCURSOR, TRUE, TRUE ); }
return ret; @@ -4242,6 +4244,8 @@ void sysparams_init(void)
if (!get_config_key( hkey, appkey, "GrabPointer", buffer, sizeof(buffer) )) grab_pointer = IS_OPTION_TRUE( buffer[0] ); + if (!get_config_key( hkey, appkey, "GrabFullscreen", buffer, sizeof(buffer) )) + grab_fullscreen = IS_OPTION_TRUE( buffer[0] );
#undef IS_OPTION_TRUE } diff --git a/dlls/win32u/win32u_private.h b/dlls/win32u/win32u_private.h index 3cb5eef6fb1..44baf546182 100644 --- a/dlls/win32u/win32u_private.h +++ b/dlls/win32u/win32u_private.h @@ -87,6 +87,7 @@ extern void unregister_imm_window( HWND hwnd ) DECLSPEC_HIDDEN;
/* input.c */ extern BOOL grab_pointer DECLSPEC_HIDDEN; +extern BOOL grab_fullscreen DECLSPEC_HIDDEN; extern BOOL destroy_caret(void) DECLSPEC_HIDDEN; extern LONG global_key_state_counter DECLSPEC_HIDDEN; extern HWND get_active_window(void) DECLSPEC_HIDDEN; @@ -102,7 +103,8 @@ extern BOOL set_foreground_window( HWND hwnd, BOOL mouse ) DECLSPEC_HIDDEN; extern void toggle_caret( HWND hwnd ) DECLSPEC_HIDDEN; extern void update_mouse_tracking_info( HWND hwnd ) DECLSPEC_HIDDEN; extern BOOL get_clip_cursor( RECT *rect ) DECLSPEC_HIDDEN; -extern BOOL process_wine_clipcursor( BOOL empty, BOOL reset ) DECLSPEC_HIDDEN; +extern BOOL process_wine_clipcursor( HWND hwnd, BOOL empty, BOOL reset ) DECLSPEC_HIDDEN; +extern BOOL clip_fullscreen_window( HWND hwnd, BOOL reset ) DECLSPEC_HIDDEN;
/* menu.c */ extern HMENU create_menu( BOOL is_popup ) DECLSPEC_HIDDEN; @@ -183,6 +185,9 @@ extern void user_lock(void) DECLSPEC_HIDDEN; extern void user_unlock(void) DECLSPEC_HIDDEN; extern void user_check_not_lock(void) DECLSPEC_HIDDEN;
+/* winstation.c */ +extern BOOL is_virtual_desktop(void) DECLSPEC_HIDDEN; + /* window.c */ struct tagWND; extern HDWP begin_defer_window_pos( INT count ) DECLSPEC_HIDDEN; @@ -347,4 +352,13 @@ static inline const char *debugstr_color( COLORREF color ) return wine_dbg_sprintf( "RGB(%02x,%02x,%02x)", GetRValue(color), GetGValue(color), GetBValue(color) ); }
+static inline BOOL intersect_rect( RECT *dst, const RECT *src1, const RECT *src2 ) +{ + dst->left = max( src1->left, src2->left ); + dst->top = max( src1->top, src2->top ); + dst->right = min( src1->right, src2->right ); + dst->bottom = min( src1->bottom, src2->bottom ); + return !IsRectEmpty( dst ); +} + #endif /* __WINE_WIN32U_PRIVATE */ diff --git a/dlls/win32u/winstation.c b/dlls/win32u/winstation.c index 466b2e6262c..049ed111954 100644 --- a/dlls/win32u/winstation.c +++ b/dlls/win32u/winstation.c @@ -40,6 +40,19 @@ WINE_DECLARE_DEBUG_CHANNEL(win);
#define DESKTOP_ALL_ACCESS 0x01ff
+BOOL is_virtual_desktop(void) +{ + HANDLE desktop = NtUserGetThreadDesktop( GetCurrentThreadId() ); + USEROBJECTFLAGS flags = {0}; + NTSTATUS status; + DWORD len; + + status = NtUserGetObjectInformation( desktop, UOI_FLAGS, &flags, sizeof(flags), &len ); + if (status) return FALSE; + + return !!(flags.dwFlags & DF_WINE_CREATE_DESKTOP); +} + /*********************************************************************** * NtUserCreateWindowStation (win32u.@) */ diff --git a/dlls/winex11.drv/desktop.c b/dlls/winex11.drv/desktop.c index b58dc050bd3..8a5682c1acb 100644 --- a/dlls/winex11.drv/desktop.c +++ b/dlls/winex11.drv/desktop.c @@ -451,8 +451,5 @@ void X11DRV_resize_desktop(void) send_message_timeout( HWND_BROADCAST, WM_X11DRV_DESKTOP_RESIZED, old_virtual_rect.left, old_virtual_rect.top, SMTO_ABORTIFHUNG, 2000, FALSE );
- /* forward clip_fullscreen_window request to the foreground window */ - send_notify_message( NtUserGetForegroundWindow(), WM_X11DRV_CLIP_CURSOR_REQUEST, TRUE, TRUE ); - old_virtual_rect = virtual_rect; } diff --git a/dlls/winex11.drv/event.c b/dlls/winex11.drv/event.c index 0e059a94f30..55709a0bc5f 100644 --- a/dlls/winex11.drv/event.c +++ b/dlls/winex11.drv/event.c @@ -780,11 +780,7 @@ static BOOL X11DRV_FocusIn( HWND hwnd, XEvent *xev )
xim_set_focus( hwnd, TRUE );
- if (use_take_focus) - { - clip_fullscreen_window( hwnd, FALSE ); - return TRUE; - } + if (use_take_focus) return TRUE;
if (!can_activate_window(hwnd)) { diff --git a/dlls/winex11.drv/mouse.c b/dlls/winex11.drv/mouse.c index 00e537cecde..33256e5880c 100644 --- a/dlls/winex11.drv/mouse.c +++ b/dlls/winex11.drv/mouse.c @@ -467,7 +467,6 @@ static void ungrab_clipping_window(void) clipping_cursor = FALSE; NtUserDestroyWindow( data->clip_hwnd ); data->clip_hwnd = 0; - data->clip_reset = NtGetTickCount(); disable_xinput2(); }
@@ -485,50 +484,6 @@ void retry_grab_clipping_window(void) NtUserClipCursor( &last_clip_rect ); }
-/*********************************************************************** - * clip_fullscreen_window - * - * Turn on clipping if the active window is fullscreen. - */ -BOOL clip_fullscreen_window( HWND hwnd, BOOL reset ) -{ - struct x11drv_win_data *data; - struct x11drv_thread_data *thread_data; - MONITORINFO monitor_info; - HMONITOR monitor; - DWORD style; - BOOL fullscreen; - - if (hwnd == NtUserGetDesktopWindow()) return FALSE; - if (hwnd != NtUserGetForegroundWindow()) return FALSE; - - style = NtUserGetWindowLongW( hwnd, GWL_STYLE ); - if (!(style & WS_VISIBLE)) return FALSE; - if ((style & (WS_POPUP | WS_CHILD)) == WS_CHILD) return FALSE; - /* maximized windows don't count as full screen */ - if ((style & WS_MAXIMIZE) && (style & WS_CAPTION) == WS_CAPTION) return FALSE; - if (!(data = get_win_data( hwnd ))) return FALSE; - fullscreen = NtUserIsWindowRectFullScreen( &data->whole_rect ); - release_win_data( data ); - if (!fullscreen) return FALSE; - if (!(thread_data = x11drv_thread_data())) return FALSE; - if (NtGetTickCount() - thread_data->clip_reset < 1000) return FALSE; - if (!reset && clipping_cursor && thread_data->clip_hwnd) return FALSE; /* already clipping */ - - monitor = NtUserMonitorFromWindow( hwnd, MONITOR_DEFAULTTONEAREST ); - if (!monitor) return FALSE; - monitor_info.cbSize = sizeof(monitor_info); - if (!NtUserGetMonitorInfo( monitor, &monitor_info )) return FALSE; - if (!grab_fullscreen) - { - RECT virtual_rect = NtUserGetVirtualScreenRect(); - if (!EqualRect( &monitor_info.rcMonitor, &virtual_rect )) return FALSE; - if (is_virtual_desktop()) return FALSE; - } - TRACE( "win %p clipping fullscreen\n", hwnd ); - return grab_clipping_window( &monitor_info.rcMonitor ); -} -
/*********************************************************************** * is_old_motion_event @@ -630,9 +585,6 @@ static void send_mouse_input( HWND hwnd, Window window, unsigned int state, INPU last_cursor_change = input->u.mi.time; }
- if (input->u.mi.dwFlags & (MOUSEEVENTF_LEFTDOWN|MOUSEEVENTF_RIGHTDOWN)) - clip_fullscreen_window( hwnd, FALSE ); - /* update the wine server Z-order */
if (hwnd != x11drv_thread_data()->grab_hwnd && @@ -1522,50 +1474,11 @@ BOOL X11DRV_GetCursorPos(LPPOINT pos) */ BOOL X11DRV_ClipCursor( const RECT *clip, BOOL reset ) { - TRACE( "clip %p, reset %u\n", clip, reset ); - - if (!reset) - { - RECT virtual_rect = NtUserGetVirtualScreenRect(); - - if (!clip) clip = &virtual_rect; - - /* we are clipping if the clip rectangle is smaller than the screen */ - if (clip->left > virtual_rect.left || clip->right < virtual_rect.right || - clip->top > virtual_rect.top || clip->bottom < virtual_rect.bottom) - { - if (grab_clipping_window( clip )) return TRUE; - } - else /* if currently clipping, check if we should switch to fullscreen clipping */ - { - struct x11drv_thread_data *data = x11drv_thread_data(); - if (data && data->clip_hwnd) - { - if (EqualRect( clip, &clip_rect )) return TRUE; - if (clip_fullscreen_window( NtUserGetForegroundWindow(), TRUE )) return TRUE; - } - } - } + if (!reset && clip && grab_clipping_window( clip )) return TRUE; ungrab_clipping_window(); return TRUE; }
-/*********************************************************************** - * clip_cursor_request - * - * Function called upon receiving a WM_X11DRV_CLIP_CURSOR_REQUEST. - */ -LRESULT clip_cursor_request( HWND hwnd, BOOL fullscreen, BOOL reset ) -{ - if (hwnd == NtUserGetDesktopWindow()) - WARN( "ignoring clip cursor request on desktop window.\n" ); - else if (hwnd != NtUserGetForegroundWindow()) - WARN( "ignoring clip cursor request on non-foreground window.\n" ); - else if (fullscreen) - clip_fullscreen_window( hwnd, reset ); - return 0; -} - /*********************************************************************** * move_resize_window */ diff --git a/dlls/winex11.drv/window.c b/dlls/winex11.drv/window.c index 3705d337101..e139b06d634 100644 --- a/dlls/winex11.drv/window.c +++ b/dlls/winex11.drv/window.c @@ -3085,8 +3085,6 @@ LRESULT X11DRV_WindowMessage( HWND hwnd, UINT msg, WPARAM wp, LPARAM lp ) } return 0; } - case WM_X11DRV_CLIP_CURSOR_REQUEST: - return clip_cursor_request( hwnd, (BOOL)wp, (BOOL)lp ); case WM_X11DRV_DELETE_TAB: taskbar_delete_tab( hwnd ); return 0; diff --git a/dlls/winex11.drv/x11drv.h b/dlls/winex11.drv/x11drv.h index 7cbf40079d2..1055bcc7117 100644 --- a/dlls/winex11.drv/x11drv.h +++ b/dlls/winex11.drv/x11drv.h @@ -389,7 +389,6 @@ struct x11drv_thread_data unsigned long warp_serial; /* serial number of last pointer warp request */ Window clip_window; /* window used for cursor clipping */ HWND clip_hwnd; /* message window stored in desktop while clipping is active */ - DWORD clip_reset; /* time when clipping was last reset */ #ifdef HAVE_X11_EXTENSIONS_XINPUT2_H enum { xi_unavailable = -1, xi_unknown, xi_disabled, xi_enabled } xi2_state; /* XInput2 state */ void *xi2_devices; /* list of XInput2 devices (valid when state is enabled) */ @@ -588,7 +587,6 @@ enum x11drv_window_messages WM_X11DRV_SET_WIN_REGION, WM_X11DRV_DESKTOP_RESIZED, WM_X11DRV_SET_CURSOR, - WM_X11DRV_CLIP_CURSOR_REQUEST, WM_X11DRV_DELETE_TAB, WM_X11DRV_ADD_TAB }; @@ -682,9 +680,7 @@ extern XContext cursor_context DECLSPEC_HIDDEN; extern void X11DRV_SetFocus( HWND hwnd ) DECLSPEC_HIDDEN; extern void set_window_cursor( Window window, HCURSOR handle ) DECLSPEC_HIDDEN; extern void sync_window_cursor( Window window ) DECLSPEC_HIDDEN; -extern LRESULT clip_cursor_request( HWND hwnd, BOOL fullscreen, BOOL reset ) DECLSPEC_HIDDEN; extern void retry_grab_clipping_window(void) DECLSPEC_HIDDEN; -extern BOOL clip_fullscreen_window( HWND hwnd, BOOL reset ) DECLSPEC_HIDDEN; extern void move_resize_window( HWND hwnd, int dir ) DECLSPEC_HIDDEN; extern void X11DRV_InitKeyboard( Display *display ) DECLSPEC_HIDDEN; extern BOOL X11DRV_ProcessEvents( DWORD mask ) DECLSPEC_HIDDEN;