Try to always keep the server window Z-order in sync with the X11 one
authorAlexandre Julliard <julliard@winehq.org>
Mon, 21 Mar 2005 12:37:00 +0000 (12:37 +0000)
committerAlexandre Julliard <julliard@winehq.org>
Mon, 21 Mar 2005 12:37:00 +0000 (12:37 +0000)
using a heuristic based on mouse and expose events.

dlls/x11drv/mouse.c
dlls/x11drv/winpos.c
dlls/x11drv/x11ddraw.c
dlls/x11drv/x11drv.h
dlls/x11drv/x11drv_main.c
include/wine/server_protocol.h
server/protocol.def
server/request.h
server/trace.c
server/window.c

index 4da199fa34ae354546b99bae9e8cca5dae35e4d3..8137f09158e0da6506d94f0f0fdc1f12bbc22573 100644 (file)
@@ -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 );
 }
index c0059effcb490985945933061391eb66d26c491b..d5469702f94077af31ec43b57a7d51e3e753b1d8 100644 (file)
@@ -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;
index 2fdb8bffb2846735b88f61701561a529bfe7f04a..f12cdb24fcdcd891149f54b8a26759cd3fc240c0 100644 (file)
@@ -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)
index 9750c3be8fec902e6d357146e0491a5bdb7726ff..e6b4c6a9f71637232a3bbf863d78e0fb72812657 100644 (file)
@@ -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 */
index c3d8de3cfbce42788bdc1301751e42fbd6357e2f..d94f62dc757652d25890cc9d1cf240cbf7d91ae0 100644 (file)
@@ -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;
index 39787923f26aa424ddd576810e4754054f97b4a5..b2ce8239321d5cb00c5ab2d926ab978aa31de8b7 100644 (file)
@@ -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 */
index 9602819ab61b41b19d0cecd705c4313d4ef71e10..c899ce9c1a0a3a6db654ff8b13428a46b05cd07b 100644 (file)
@@ -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 */
index 3902c7b2555403e5b515c9b656933ec356d47268..dc57117d31bb4d0c8301d90a027aa87d001800e4 100644 (file)
@@ -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,
index 266673f52f23b7cb126e09b3eddd51bb455eecd7..a07a54c953da2855df7294ed097afd6b86acf613 100644 (file)
@@ -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",
index 219a244a44c351d33e8f815cf4c3d241081b9ac3..ae46dc9876d61ad3058ccb83f78c50f655e9b07e 100644 (file)
@@ -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)
 {