From bd18d7e21494557615c398244a4e180e44a11e25 Mon Sep 17 00:00:00 2001
From: Dmitry Timoshkov <dmitry@baikal.ru>
Date: Wed, 17 May 2017 23:55:55 +0800
Subject: [PATCH] server: Add support for a layered window region. (v3)

---
 dlls/user32/tests/input.c |  2 --
 dlls/winex11.drv/bitblt.c | 45 +++++++++++++++++++++++++++++++++++++++++++++
 server/protocol.def       |  7 +++++++
 server/window.c           | 32 ++++++++++++++++++++++++++++++++
 4 files changed, 84 insertions(+), 2 deletions(-)

diff --git a/dlls/user32/tests/input.c b/dlls/user32/tests/input.c
index 858e7d6..5fa15af 100644
--- a/dlls/user32/tests/input.c
+++ b/dlls/user32/tests/input.c
@@ -2388,13 +2388,11 @@ static void test_Input_mouse(void)
 
         if (msg.message == WM_LBUTTONDOWN)
         {
-            todo_wine
             ok(msg.hwnd == button_win, "msg.hwnd = %p\n", msg.hwnd);
             got_button_down = TRUE;
         }
         else if (msg.message == WM_LBUTTONUP)
         {
-            todo_wine
             ok(msg.hwnd == button_win, "msg.hwnd = %p\n", msg.hwnd);
             got_button_up = TRUE;
             break;
diff --git a/dlls/winex11.drv/bitblt.c b/dlls/winex11.drv/bitblt.c
index 0343d96..b07c9be 100644
--- a/dlls/winex11.drv/bitblt.c
+++ b/dlls/winex11.drv/bitblt.c
@@ -48,6 +48,7 @@
 #include "winuser.h"
 #include "x11drv.h"
 #include "winternl.h"
+#include "wine/server.h"
 #include "wine/debug.h"
 
 WINE_DEFAULT_DEBUG_CHANNEL(bitblt);
@@ -1612,6 +1613,48 @@ static inline void add_row( HRGN rgn, RGNDATA *data, int x, int y, int len )
 }
 #endif
 
+static void set_layer_region( struct x11drv_window_surface *surface, HRGN hrgn )
+{
+    static const RECT empty_rect;
+    RGNDATA *data;
+    DWORD size;
+    HWND hwnd;
+
+    if (XFindContext( thread_init_display(), surface->window, winContext, (char **)&hwnd ))
+        return;
+
+    if (hrgn)
+    {
+        if (!(size = GetRegionData( hrgn, 0, NULL ))) return;
+        if (!(data = HeapAlloc( GetProcessHeap(), 0, size ))) return;
+        if (!GetRegionData( hrgn, size, data ))
+        {
+            HeapFree( GetProcessHeap(), 0, data );
+            return;
+        }
+        SERVER_START_REQ( set_layer_region )
+        {
+            req->window = wine_server_user_handle( hwnd );
+            if (data->rdh.nCount)
+                wine_server_add_data( req, data->Buffer, data->rdh.nCount * sizeof(RECT) );
+            else
+                wine_server_add_data( req, &empty_rect, sizeof(empty_rect) );
+            wine_server_call( req );
+        }
+        SERVER_END_REQ;
+        HeapFree( GetProcessHeap(), 0, data );
+    }
+    else  /* clear existing region */
+    {
+        SERVER_START_REQ( set_layer_region )
+        {
+            req->window = wine_server_user_handle( hwnd );
+            wine_server_call( req );
+        }
+        SERVER_END_REQ;
+    }
+}
+
 /***********************************************************************
  *           update_surface_region
  */
@@ -1630,6 +1673,7 @@ static void update_surface_region( struct x11drv_window_surface *surface )
     if (!surface->is_argb && surface->color_key == CLR_INVALID)
     {
         XShapeCombineMask( gdi_display, surface->window, ShapeBounding, 0, 0, None, ShapeSet );
+        set_layer_region( surface, NULL );
         return;
     }
 
@@ -1740,6 +1784,7 @@ static void update_surface_region( struct x11drv_window_surface *surface )
         HeapFree( GetProcessHeap(), 0, data );
     }
 
+    set_layer_region( surface, rgn );
     DeleteObject( rgn );
 #endif
 }
diff --git a/server/protocol.def b/server/protocol.def
index f48fd00..f3aa6f1 100644
--- a/server/protocol.def
+++ b/server/protocol.def
@@ -2775,6 +2775,13 @@ enum coords_relative
 @END
 
 
+/* Set the layer region */
+@REQ(set_layer_region)
+    user_handle_t  window;        /* handle to the window */
+    VARARG(region,rectangles);    /* list of rectangles for the region (in window coords) */
+@END
+
+
 /* Get the window update region */
 @REQ(get_update_region)
     user_handle_t  window;        /* handle to the window */
diff --git a/server/window.c b/server/window.c
index c9b131c..766bf51 100644
--- a/server/window.c
+++ b/server/window.c
@@ -73,6 +73,7 @@ struct window
     rectangle_t      surface_rect;    /* window surface rectangle (relative to parent client area) */
     rectangle_t      client_rect;     /* client rectangle (relative to parent client area) */
     struct region   *win_region;      /* region for shaped windows (relative to window rect) */
+    struct region   *layer_region;    /* region for layered windows (relative to window rect) */
     struct region   *update_region;   /* update region (relative to window rect) */
     unsigned int     style;           /* window style */
     unsigned int     ex_style;        /* window extended style */
@@ -494,6 +495,7 @@ static struct window *create_window( struct window *parent, struct window *owner
     win->atom           = atom;
     win->last_active    = win->handle;
     win->win_region     = NULL;
+    win->layer_region   = NULL;
     win->update_region  = NULL;
     win->style          = 0;
     win->ex_style       = 0;
@@ -723,6 +725,9 @@ static int is_point_in_window( struct window *win, int *x, int *y, unsigned int
     if (win->win_region &&
         !point_in_region( win->win_region, *x - win->window_rect.left, *y - win->window_rect.top ))
         return 0;  /* not in window region */
+    if (win->layer_region &&
+        !point_in_region( win->layer_region, *x - win->window_rect.left, *y - win->window_rect.top ))
+        return 0;  /* not in layer mask region */
     return 1;
 }
 
@@ -1868,6 +1873,14 @@ static void set_window_region( struct window *win, struct region *region, int re
 }
 
 
+/* set the layer region */
+static void set_layer_region( struct window *win, struct region *region )
+{
+    if (win->layer_region) free_region( win->layer_region );
+    win->layer_region = region;
+}
+
+
 /* destroy a window */
 void destroy_window( struct window *win )
 {
@@ -1916,6 +1929,7 @@ void destroy_window( struct window *win )
 
     detach_window_thread( win );
     if (win->win_region) free_region( win->win_region );
+    if (win->layer_region) free_region( win->layer_region );
     if (win->update_region) free_region( win->update_region );
     if (win->class) release_class( win->class );
     free( win->text );
@@ -2569,6 +2583,24 @@ DECL_HANDLER(set_window_region)
 }
 
 
+/* set the layer region */
+DECL_HANDLER(set_layer_region)
+{
+    struct region *region = NULL;
+    struct window *win = get_window( req->window );
+
+    if (!win) return;
+
+    if (get_req_data_size())  /* no data means remove the region completely */
+    {
+        if (!(region = create_region_from_req_data( get_req_data(), get_req_data_size() )))
+            return;
+        if (win->ex_style & WS_EX_LAYOUTRTL) mirror_region( &win->window_rect, region );
+    }
+    set_layer_region( win, region );
+}
+
+
 /* get a window update region */
 DECL_HANDLER(get_update_region)
 {
-- 
1.9.1

