diff --git a/dlls/x11drv/mouse.c b/dlls/x11drv/mouse.c index 4da199fa34a..8137f09158e 100644 --- a/dlls/x11drv/mouse.c +++ b/dlls/x11drv/mouse.c @@ -68,7 +68,7 @@ POINT cursor_pos; * * get the coordinates of a mouse event */ -static inline void get_coords( HWND hwnd, Window window, int x, int y, POINT *pt ) +static inline void get_coords( HWND hwnd, int x, int y, POINT *pt ) { struct x11drv_win_data *data = X11DRV_get_win_data( hwnd ); @@ -84,7 +84,7 @@ static inline void get_coords( HWND hwnd, Window window, int x, int y, POINT *pt * * Update the button state with what X provides us */ -static void update_button_state( unsigned int state ) +static inline void update_button_state( unsigned int state ) { key_state_table[VK_LBUTTON] = (state & Button1Mask ? 0x80 : 0); key_state_table[VK_MBUTTON] = (state & Button2Mask ? 0x80 : 0); @@ -97,13 +97,55 @@ static void update_button_state( unsigned int state ) * * Update the key state with what X provides us */ -static void update_key_state( unsigned int state ) +static inline void update_key_state( unsigned int state ) { key_state_table[VK_SHIFT] = (state & ShiftMask ? 0x80 : 0); key_state_table[VK_CONTROL] = (state & ControlMask ? 0x80 : 0); } +/*********************************************************************** + * update_mouse_state + * + * Update the various window states on a mouse event. + */ +static void update_mouse_state( HWND hwnd, Window window, int x, int y, unsigned int state, POINT *pt ) +{ + struct x11drv_thread_data *data = x11drv_thread_data(); + + get_coords( hwnd, x, y, pt ); + update_key_state( state ); + + /* update the cursor */ + + if (data->cursor_window != window) + { + data->cursor_window = window; + wine_tsx11_lock(); + if (data->cursor) XDefineCursor( data->display, window, data->cursor ); + wine_tsx11_unlock(); + } + + /* update the wine server Z-order */ + + if (window != data->grab_window && + /* ignore event if a button is pressed, since the mouse is then grabbed too */ + !(state & (Button1Mask|Button2Mask|Button3Mask|Button4Mask|Button5Mask))) + { + SERVER_START_REQ( update_window_zorder ) + { + req->window = hwnd; + req->rect.left = pt->x; + req->rect.top = pt->y; + req->rect.right = pt->x + 1; + req->rect.bottom = pt->y + 1; + wine_server_call( req ); + } + SERVER_END_REQ; + } +} + + /*********************************************************************** * get_key_state */ @@ -286,25 +328,6 @@ void X11DRV_send_mouse_input( HWND hwnd, DWORD flags, DWORD x, DWORD y, } -/*********************************************************************** - * update_cursor - * - * Update the cursor of a window on a mouse event. - */ -static void update_cursor( HWND hwnd, Window win ) -{ - struct x11drv_thread_data *data = x11drv_thread_data(); - - if (data->cursor_window != win) - { - data->cursor_window = win; - wine_tsx11_lock(); - if (data->cursor) XDefineCursor( data->display, win, data->cursor ); - wine_tsx11_unlock(); - } -} - - /*********************************************************************** * create_cursor * @@ -693,9 +716,6 @@ void X11DRV_ButtonPress( HWND hwnd, XEvent *xev ) if (buttonNum >= NB_BUTTONS) return; if (!hwnd) return; - update_cursor( hwnd, event->window ); - get_coords( hwnd, event->window, event->x, event->y, &pt ); - switch (buttonNum) { case 3: @@ -705,7 +725,9 @@ void X11DRV_ButtonPress( HWND hwnd, XEvent *xev ) wData = -WHEEL_DELTA; break; } - update_key_state( event->state ); + + update_mouse_state( hwnd, event->window, event->x, event->y, event->state, &pt ); + X11DRV_send_mouse_input( hwnd, button_down_flags[buttonNum] | MOUSEEVENTF_ABSOLUTE, pt.x, pt.y, wData, EVENT_x11_time_to_win32_time(event->time), 0, 0 ); } @@ -723,9 +745,8 @@ void X11DRV_ButtonRelease( HWND hwnd, XEvent *xev ) if (buttonNum >= NB_BUTTONS || !button_up_flags[buttonNum]) return; if (!hwnd) return; - update_cursor( hwnd, event->window ); - get_coords( hwnd, event->window, event->x, event->y, &pt ); - update_key_state( event->state ); + update_mouse_state( hwnd, event->window, event->x, event->y, event->state, &pt ); + X11DRV_send_mouse_input( hwnd, button_up_flags[buttonNum] | MOUSEEVENTF_ABSOLUTE, pt.x, pt.y, 0, EVENT_x11_time_to_win32_time(event->time), 0, 0 ); } @@ -743,9 +764,8 @@ void X11DRV_MotionNotify( HWND hwnd, XEvent *xev ) if (!hwnd) return; - update_cursor( hwnd, event->window ); - get_coords( hwnd, event->window, event->x, event->y, &pt ); - update_key_state( event->state ); + update_mouse_state( hwnd, event->window, event->x, event->y, event->state, &pt ); + X11DRV_send_mouse_input( hwnd, MOUSEEVENTF_MOVE | MOUSEEVENTF_ABSOLUTE, pt.x, pt.y, 0, EVENT_x11_time_to_win32_time(event->time), 0, 0 ); } @@ -765,9 +785,8 @@ void X11DRV_EnterNotify( HWND hwnd, XEvent *xev ) if (event->detail == NotifyVirtual || event->detail == NotifyNonlinearVirtual) return; /* simulate a mouse motion event */ - update_cursor( hwnd, event->window ); - get_coords( hwnd, event->window, event->x, event->y, &pt ); - update_key_state( event->state ); + update_mouse_state( hwnd, event->window, event->x, event->y, event->state, &pt ); + X11DRV_send_mouse_input( hwnd, MOUSEEVENTF_MOVE | MOUSEEVENTF_ABSOLUTE, pt.x, pt.y, 0, EVENT_x11_time_to_win32_time(event->time), 0, 0 ); } diff --git a/dlls/x11drv/winpos.c b/dlls/x11drv/winpos.c index c0059effcb4..d5469702f94 100644 --- a/dlls/x11drv/winpos.c +++ b/dlls/x11drv/winpos.c @@ -159,9 +159,19 @@ void X11DRV_Expose( HWND hwnd, XEvent *xev ) rect.right > data->client_rect.right || rect.bottom > data->client_rect.bottom) flags |= RDW_FRAME; + SERVER_START_REQ( update_window_zorder ) + { + req->window = hwnd; + req->rect.left = rect.left + data->whole_rect.left; + req->rect.top = rect.top + data->whole_rect.top; + req->rect.right = rect.right + data->whole_rect.left; + req->rect.bottom = rect.bottom + data->whole_rect.top; + wine_server_call( req ); + } + SERVER_END_REQ; + /* make position relative to client area instead of window */ OffsetRect( &rect, -data->client_rect.left, -data->client_rect.top ); - RedrawWindow( hwnd, &rect, 0, flags ); } @@ -1606,7 +1616,7 @@ void X11DRV_SysCommandSizeMove( HWND hwnd, WPARAM wParam ) BOOL grab; Window parent_win, whole_win; Display *old_gdi_display = NULL; - Display *display = thread_display(); + struct x11drv_thread_data *thread_data = x11drv_thread_data(); struct x11drv_win_data *data; pt.x = (short)LOWORD(dwPoint); @@ -1732,21 +1742,22 @@ void X11DRV_SysCommandSizeMove( HWND hwnd, WPARAM wParam ) { wine_tsx11_lock(); XSync( gdi_display, False ); - XGrabServer( display ); - XSync( display, False ); + XGrabServer( thread_data->display ); + XSync( thread_data->display, False ); /* switch gdi display to the thread display, since the server is grabbed */ old_gdi_display = gdi_display; - gdi_display = display; + gdi_display = thread_data->display; wine_tsx11_unlock(); } whole_win = X11DRV_get_whole_window( GetAncestor(hwnd,GA_ROOT) ); parent_win = parent ? X11DRV_get_whole_window( GetAncestor(parent,GA_ROOT) ) : root_window; wine_tsx11_lock(); - XGrabPointer( display, whole_win, False, + XGrabPointer( thread_data->display, whole_win, False, PointerMotionMask | ButtonPressMask | ButtonReleaseMask, GrabModeAsync, GrabModeAsync, parent_win, None, CurrentTime ); wine_tsx11_unlock(); + thread_data->grab_window = whole_win; while(1) { @@ -1846,15 +1857,16 @@ void X11DRV_SysCommandSizeMove( HWND hwnd, WPARAM wParam ) ReleaseDC( parent, hdc ); wine_tsx11_lock(); - XUngrabPointer( display, CurrentTime ); + XUngrabPointer( thread_data->display, CurrentTime ); if (grab) { - XSync( display, False ); - XUngrabServer( display ); - XSync( display, False ); + XSync( thread_data->display, False ); + XUngrabServer( thread_data->display ); + XSync( thread_data->display, False ); gdi_display = old_gdi_display; } wine_tsx11_unlock(); + thread_data->grab_window = None; if (HOOK_CallHooks( WH_CBT, HCBT_MOVESIZE, (WPARAM)hwnd, (LPARAM)&sizingRect, TRUE )) moved = FALSE; diff --git a/dlls/x11drv/x11ddraw.c b/dlls/x11drv/x11ddraw.c index 2fdb8bffb28..f12cdb24fcd 100644 --- a/dlls/x11drv/x11ddraw.c +++ b/dlls/x11drv/x11ddraw.c @@ -62,7 +62,7 @@ static void SetPrimaryDIB(HBITMAP hBmp) static LRESULT WINAPI GrabWndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) { - Display *display = thread_display(); + struct x11drv_thread_data *data = x11drv_thread_data(); if(message != X11DRV_DD_GrabMessage) return CallWindowProcA(X11DRV_DD_GrabOldProcedure, hWnd, message, wParam, lParam); @@ -80,14 +80,16 @@ static LRESULT WINAPI GrabWndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM } wine_tsx11_lock(); - XGrabPointer(display, win, True, 0, GrabModeAsync, GrabModeAsync, win, None, CurrentTime); + XGrabPointer(data->display, win, True, 0, GrabModeAsync, GrabModeAsync, win, None, CurrentTime); wine_tsx11_unlock(); + data->grab_window = win; } else { wine_tsx11_lock(); - XUngrabPointer(display, CurrentTime); + XUngrabPointer(data->display, CurrentTime); wine_tsx11_unlock(); + data->grab_window = None; } return 0; @@ -98,7 +100,11 @@ static void GrabPointer(BOOL grab) if(grab) { Window window = X11DRV_get_whole_window(GetFocus()); if(window) + { + wine_tsx11_lock(); XSetInputFocus(thread_display(), window, RevertToParent, CurrentTime); + wine_tsx11_unlock(); + } } if(!X11DRV_DD_GrabMessage) @@ -107,7 +113,7 @@ static void GrabPointer(BOOL grab) X11DRV_DD_GrabOldProcedure = (WNDPROC)SetWindowLongPtrA(X11DRV_DD_PrimaryWnd, GWLP_WNDPROC, (LONG_PTR)GrabWndProc); - SendMessageA(X11DRV_DD_PrimaryWnd, X11DRV_DD_GrabMessage, grab ? 1 : 0, 0); + SendMessageW(X11DRV_DD_PrimaryWnd, X11DRV_DD_GrabMessage, grab, 0); if(SetWindowLongPtrA(X11DRV_DD_PrimaryWnd, GWLP_WNDPROC, (LONG_PTR)X11DRV_DD_GrabOldProcedure) != (LONG_PTR)GrabWndProc) diff --git a/dlls/x11drv/x11drv.h b/dlls/x11drv/x11drv.h index 9750c3be8fe..e6b4c6a9f71 100644 --- a/dlls/x11drv/x11drv.h +++ b/dlls/x11drv/x11drv.h @@ -504,6 +504,7 @@ struct x11drv_thread_data int process_event_count; /* recursion count for event processing */ Cursor cursor; /* current cursor */ Window cursor_window; /* current window that contains the cursor */ + Window grab_window; /* window that currentl grabs the mouse */ HWND last_focus; /* last window that had focus */ XIM xim; /* input method */ Window selection_wnd; /* window used for selection interactions */ diff --git a/dlls/x11drv/x11drv_main.c b/dlls/x11drv/x11drv_main.c index c3d8de3cfbc..d94f62dc757 100644 --- a/dlls/x11drv/x11drv_main.c +++ b/dlls/x11drv/x11drv_main.c @@ -488,6 +488,7 @@ struct x11drv_thread_data *x11drv_init_thread_data(void) data->process_event_count = 0; data->cursor = None; data->cursor_window = None; + data->grab_window = None; data->last_focus = 0; data->selection_wnd = 0; NtCurrentTeb()->driver_data = data; diff --git a/include/wine/server_protocol.h b/include/wine/server_protocol.h index 39787923f26..b2ce8239321 100644 --- a/include/wine/server_protocol.h +++ b/include/wine/server_protocol.h @@ -2720,6 +2720,19 @@ struct get_update_region_reply +struct update_window_zorder_request +{ + struct request_header __header; + user_handle_t window; + rectangle_t rect; +}; +struct update_window_zorder_reply +{ + struct reply_header __header; +}; + + + struct redraw_window_request { struct request_header __header; @@ -3372,6 +3385,7 @@ enum request REQ_get_window_region, REQ_set_window_region, REQ_get_update_region, + REQ_update_window_zorder, REQ_redraw_window, REQ_set_window_property, REQ_remove_window_property, @@ -3562,6 +3576,7 @@ union generic_request struct get_window_region_request get_window_region_request; struct set_window_region_request set_window_region_request; struct get_update_region_request get_update_region_request; + struct update_window_zorder_request update_window_zorder_request; struct redraw_window_request redraw_window_request; struct set_window_property_request set_window_property_request; struct remove_window_property_request remove_window_property_request; @@ -3750,6 +3765,7 @@ union generic_reply struct get_window_region_reply get_window_region_reply; struct set_window_region_reply set_window_region_reply; struct get_update_region_reply get_update_region_reply; + struct update_window_zorder_reply update_window_zorder_reply; struct redraw_window_reply redraw_window_reply; struct set_window_property_reply set_window_property_reply; struct remove_window_property_reply remove_window_property_reply; @@ -3781,6 +3797,6 @@ union generic_reply struct duplicate_token_reply duplicate_token_reply; }; -#define SERVER_PROTOCOL_VERSION 161 +#define SERVER_PROTOCOL_VERSION 162 #endif /* __WINE_WINE_SERVER_PROTOCOL_H */ diff --git a/server/protocol.def b/server/protocol.def index 9602819ab61..c899ce9c1a0 100644 --- a/server/protocol.def +++ b/server/protocol.def @@ -1916,6 +1916,13 @@ enum message_type #define UPDATE_NOREGION 0x40 /* don't return a region, only the flags */ +/* Update the z order of a window so that a given rectangle is fully visible */ +@REQ(update_window_zorder) + user_handle_t window; /* handle to the window */ + rectangle_t rect; /* rectangle that must be visible */ +@END + + /* Mark parts of a window as needing a redraw */ @REQ(redraw_window) user_handle_t window; /* handle to the window */ diff --git a/server/request.h b/server/request.h index 3902c7b2555..dc57117d31b 100644 --- a/server/request.h +++ b/server/request.h @@ -257,6 +257,7 @@ DECL_HANDLER(get_visible_region); DECL_HANDLER(get_window_region); DECL_HANDLER(set_window_region); DECL_HANDLER(get_update_region); +DECL_HANDLER(update_window_zorder); DECL_HANDLER(redraw_window); DECL_HANDLER(set_window_property); DECL_HANDLER(remove_window_property); @@ -446,6 +447,7 @@ static const req_handler req_handlers[REQ_NB_REQUESTS] = (req_handler)req_get_window_region, (req_handler)req_set_window_region, (req_handler)req_get_update_region, + (req_handler)req_update_window_zorder, (req_handler)req_redraw_window, (req_handler)req_set_window_property, (req_handler)req_remove_window_property, diff --git a/server/trace.c b/server/trace.c index 266673f52f2..a07a54c953d 100644 --- a/server/trace.c +++ b/server/trace.c @@ -2302,6 +2302,13 @@ static void dump_get_update_region_reply( const struct get_update_region_reply * dump_varargs_rectangles( cur_size ); } +static void dump_update_window_zorder_request( const struct update_window_zorder_request *req ) +{ + fprintf( stderr, " window=%p,", req->window ); + fprintf( stderr, " rect=" ); + dump_rectangle( &req->rect ); +} + static void dump_redraw_window_request( const struct redraw_window_request *req ) { fprintf( stderr, " window=%p,", req->window ); @@ -2839,6 +2846,7 @@ static const dump_func req_dumpers[REQ_NB_REQUESTS] = { (dump_func)dump_get_window_region_request, (dump_func)dump_set_window_region_request, (dump_func)dump_get_update_region_request, + (dump_func)dump_update_window_zorder_request, (dump_func)dump_redraw_window_request, (dump_func)dump_set_window_property_request, (dump_func)dump_remove_window_property_request, @@ -3027,6 +3035,7 @@ static const dump_func reply_dumpers[REQ_NB_REQUESTS] = { (dump_func)dump_get_update_region_reply, (dump_func)0, (dump_func)0, + (dump_func)0, (dump_func)dump_remove_window_property_reply, (dump_func)dump_get_window_property_reply, (dump_func)dump_get_window_properties_reply, @@ -3211,6 +3220,7 @@ static const char * const req_names[REQ_NB_REQUESTS] = { "get_window_region", "set_window_region", "get_update_region", + "update_window_zorder", "redraw_window", "set_window_property", "remove_window_property", diff --git a/server/window.c b/server/window.c index 219a244a44c..ae46dc9876d 100644 --- a/server/window.c +++ b/server/window.c @@ -645,15 +645,23 @@ static struct region *clip_children( struct window *parent, struct window *last, } +/* compute the intersection of two rectangles; return 0 if the result is empty */ +static inline int intersect_rect( rectangle_t *dst, const rectangle_t *src1, const rectangle_t *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 (dst->left < dst->right && dst->top < dst->bottom); +} + + /* set the region to the client rect clipped by the window rect, in parent-relative coordinates */ static void set_region_client_rect( struct region *region, struct window *win ) { rectangle_t rect; - rect.left = max( win->window_rect.left, win->client_rect.left ); - rect.top = max( win->window_rect.top, win->client_rect.top ); - rect.right = min( win->window_rect.right, win->client_rect.right ); - rect.bottom = min( win->window_rect.bottom, win->client_rect.bottom ); + intersect_rect( &rect, &win->window_rect, &win->client_rect ); set_region_rect( region, &rect ); } @@ -1667,6 +1675,29 @@ DECL_HANDLER(get_update_region) } +/* update the z order of a window so that a given rectangle is fully visible */ +DECL_HANDLER(update_window_zorder) +{ + rectangle_t tmp; + struct window *ptr, *win = get_window( req->window ); + + if (!win || !win->parent || !is_visible( win )) return; /* nothing to do */ + + LIST_FOR_EACH_ENTRY( ptr, &win->parent->children, struct window, entry ) + { + if (ptr == win) break; + if (!(ptr->style & WS_VISIBLE)) continue; + if (ptr->ex_style & WS_EX_TRANSPARENT) continue; + if (!intersect_rect( &tmp, &ptr->visible_rect, &req->rect )) continue; + if (ptr->win_region && !rect_in_region( ptr->win_region, &req->rect )) continue; + /* found a window obscuring the rectangle, now move win above this one */ + list_remove( &win->entry ); + list_add_before( &ptr->entry, &win->entry ); + break; + } +} + + /* mark parts of a window as needing a redraw */ DECL_HANDLER(redraw_window) {