diff --git a/patches/patchinstall.sh b/patches/patchinstall.sh index e738e55d..c284b08f 100755 --- a/patches/patchinstall.sh +++ b/patches/patchinstall.sh @@ -8000,12 +8000,18 @@ fi # | * [#9512] Make sure popups don't block access to objects underneath in DVDPro # | # | Modified files: -# | * dlls/user32/message.c, dlls/user32/tests/input.c +# | * dlls/user32/message.c, dlls/user32/tests/input.c, dlls/winex11.drv/bitblt.c, server/protocol.def, server/window.c # | if test "$enable_user32_Mouse_Message_Hwnd" -eq 1; then patch_apply user32-Mouse_Message_Hwnd/0001-user32-Try-harder-to-find-a-target-for-mouse-message.patch + patch_apply user32-Mouse_Message_Hwnd/0002-user32-tests-Add-tests-for-clicking-through-layered-.patch + patch_apply user32-Mouse_Message_Hwnd/0003-user32-tests-Add-tests-for-window-region-of-layered-.patch + patch_apply user32-Mouse_Message_Hwnd/0004-server-Add-support-for-a-layered-window-region.-v2.patch ( printf '%s\n' '+ { "Dmitry Timoshkov", "user32: Try harder to find a target for mouse messages.", 1 },'; + printf '%s\n' '+ { "Sebastian Lackner", "user32/tests: Add tests for clicking through layered window.", 1 },'; + printf '%s\n' '+ { "Sebastian Lackner", "user32/tests: Add tests for window region of layered windows.", 1 },'; + printf '%s\n' '+ { "Dmitry Timoshkov", "server: Add support for a layered window region.", 2 },'; ) >> "$patchlist" fi diff --git a/patches/user32-Mouse_Message_Hwnd/0002-user32-tests-Add-tests-for-clicking-through-layered-.patch b/patches/user32-Mouse_Message_Hwnd/0002-user32-tests-Add-tests-for-clicking-through-layered-.patch new file mode 100644 index 00000000..9af523aa --- /dev/null +++ b/patches/user32-Mouse_Message_Hwnd/0002-user32-tests-Add-tests-for-clicking-through-layered-.patch @@ -0,0 +1,202 @@ +From 9728ac1dc57f11b11d4467de7f1c58c59218978d Mon Sep 17 00:00:00 2001 +From: Sebastian Lackner +Date: Mon, 29 May 2017 05:30:44 +0200 +Subject: user32/tests: Add tests for clicking through layered window. + +FIXME: + +* It seems like the color key channels are swapped between Windows and Wine. + This can be tested by replacing the (128, 128, 128) with something else. + +* Add tests with WS_CHILD layered Windows. On Windows this is supported for + >= Win8, but only when a manifest is present. +--- + dlls/user32/tests/input.c | 157 ++++++++++++++++++++++++++++++++++++++++++++++ + 1 file changed, 157 insertions(+) + +diff --git a/dlls/user32/tests/input.c b/dlls/user32/tests/input.c +index 62cd5b38055..47c5fa8c932 100644 +--- a/dlls/user32/tests/input.c ++++ b/dlls/user32/tests/input.c +@@ -53,6 +53,7 @@ + #include "windef.h" + #include "winbase.h" + #include "winuser.h" ++#include "wingdi.h" + #include "winnls.h" + + #include "wine/test.h" +@@ -1927,7 +1928,9 @@ static void test_Input_mouse(void) + struct thread_data thread_data; + HANDLE thread; + DWORD thread_id; ++ WNDCLASSA wclass; + POINT pt, pt_org; ++ BOOL ret; + MSG msg; + + GetCursorPos(&pt_org); +@@ -2131,6 +2134,160 @@ static void test_Input_mouse(void) + ok(got_button_up, "expected WM_LBUTTONUP message\n"); + DestroyWindow(hwnd); + ok(ReleaseCapture(), "ReleaseCapture failed\n"); ++ ++ wclass.style = 0; ++ wclass.lpfnWndProc = WndProc; ++ wclass.cbClsExtra = 0; ++ wclass.cbWndExtra = 0; ++ wclass.hInstance = GetModuleHandleA(NULL); ++ wclass.hIcon = LoadIconA(0, (LPCSTR)IDI_APPLICATION); ++ wclass.hCursor = LoadCursorA(NULL, (LPCSTR)IDC_ARROW); ++ wclass.hbrBackground = CreateSolidBrush(RGB(128, 128, 128)); ++ wclass.lpszMenuName = NULL; ++ wclass.lpszClassName = "InputLayeredTestClass"; ++ RegisterClassA( &wclass ); ++ ++ /* click through layered window with alpha channel / color key */ ++ hwnd = CreateWindowA(wclass.lpszClassName, "InputLayeredTest", ++ WS_VISIBLE | WS_POPUP, 100, 100, 100, 100, button_win, NULL, NULL, NULL); ++ ok(hwnd != NULL, "CreateWindowEx failed\n"); ++ ++ SetWindowPos(hwnd, HWND_TOPMOST, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE); ++ SetWindowLongA(hwnd, GWL_EXSTYLE, GetWindowLongA(hwnd, GWL_EXSTYLE) | WS_EX_LAYERED); ++ ret = SetLayeredWindowAttributes(hwnd, 0, 255, LWA_ALPHA); ++ ok(ret, "SetLayeredWindowAttributes failed\n"); ++ while (wait_for_message(&msg)) DispatchMessageA(&msg); ++ Sleep(100); ++ ++ got_button_down = got_button_up = FALSE; ++ simulate_click(TRUE, 150, 150); ++ while (wait_for_message(&msg)) ++ { ++ DispatchMessageA(&msg); ++ ++ if (msg.message == WM_LBUTTONDOWN) ++ { ++ ok(msg.hwnd == hwnd, "msg.hwnd = %p\n", msg.hwnd); ++ got_button_down = TRUE; ++ } ++ else if (msg.message == WM_LBUTTONUP) ++ { ++ ok(msg.hwnd == hwnd, "msg.hwnd = %p\n", msg.hwnd); ++ got_button_up = TRUE; ++ break; ++ } ++ } ++ ok(got_button_down, "expected WM_LBUTTONDOWN message\n"); ++ ok(got_button_up, "expected WM_LBUTTONUP message\n"); ++ ++ ret = SetLayeredWindowAttributes(hwnd, 0, 0, LWA_ALPHA); ++ ok(ret, "SetLayeredWindowAttributes failed\n"); ++ while (wait_for_message(&msg)) DispatchMessageA(&msg); ++ Sleep(100); ++ ++ got_button_down = got_button_up = FALSE; ++ simulate_click(TRUE, 150, 150); ++ while (wait_for_message(&msg)) ++ { ++ DispatchMessageA(&msg); ++ ++ 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; ++ } ++ } ++ ok(got_button_down || broken(!got_button_down), "expected WM_LBUTTONDOWN message\n"); ++ ok(got_button_up, "expected WM_LBUTTONUP message\n"); ++ ++ ret = SetLayeredWindowAttributes(hwnd, RGB(0, 255, 0), 255, LWA_ALPHA | LWA_COLORKEY); ++ ok(ret, "SetLayeredWindowAttributes failed\n"); ++ while (wait_for_message(&msg)) DispatchMessageA(&msg); ++ Sleep(100); ++ ++ got_button_down = got_button_up = FALSE; ++ simulate_click(TRUE, 150, 150); ++ while (wait_for_message(&msg)) ++ { ++ DispatchMessageA(&msg); ++ ++ if (msg.message == WM_LBUTTONDOWN) ++ { ++ ok(msg.hwnd == hwnd, "msg.hwnd = %p\n", msg.hwnd); ++ got_button_down = TRUE; ++ } ++ else if (msg.message == WM_LBUTTONUP) ++ { ++ ok(msg.hwnd == hwnd, "msg.hwnd = %p\n", msg.hwnd); ++ got_button_up = TRUE; ++ break; ++ } ++ } ++ ok(got_button_down, "expected WM_LBUTTONDOWN message\n"); ++ ok(got_button_up, "expected WM_LBUTTONUP message\n"); ++ ++ ret = SetLayeredWindowAttributes(hwnd, RGB(128, 128, 128), 0, LWA_COLORKEY); ++ ok(ret, "SetLayeredWindowAttributes failed\n"); ++ while (wait_for_message(&msg)) DispatchMessageA(&msg); ++ Sleep(100); ++ ++ got_button_down = got_button_up = FALSE; ++ simulate_click(TRUE, 150, 150); ++ while (wait_for_message(&msg)) ++ { ++ DispatchMessageA(&msg); ++ ++ 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; ++ } ++ } ++ ok(got_button_down, "expected WM_LBUTTONDOWN message\n"); ++ ok(got_button_up, "expected WM_LBUTTONUP message\n"); ++ ++ SetWindowLongA(hwnd, GWL_EXSTYLE, GetWindowLongA(hwnd, GWL_EXSTYLE) & ~WS_EX_LAYERED); ++ while (wait_for_message(&msg)) DispatchMessageA(&msg); ++ Sleep(100); ++ ++ got_button_down = got_button_up = FALSE; ++ simulate_click(TRUE, 150, 150); ++ while (wait_for_message(&msg)) ++ { ++ DispatchMessageA(&msg); ++ ++ if (msg.message == WM_LBUTTONDOWN) ++ { ++ ok(msg.hwnd == hwnd, "msg.hwnd = %p\n", msg.hwnd); ++ got_button_down = TRUE; ++ } ++ else if (msg.message == WM_LBUTTONUP) ++ { ++ ok(msg.hwnd == hwnd, "msg.hwnd = %p\n", msg.hwnd); ++ got_button_up = TRUE; ++ break; ++ } ++ } ++ ok(got_button_down, "expected WM_LBUTTONDOWN message\n"); ++ ok(got_button_up, "expected WM_LBUTTONUP message\n"); ++ ++ DestroyWindow(hwnd); + SetCursorPos(pt_org.x, pt_org.y); + + CloseHandle(thread_data.start_event); +-- +2.12.2 + diff --git a/patches/user32-Mouse_Message_Hwnd/0003-user32-tests-Add-tests-for-window-region-of-layered-.patch b/patches/user32-Mouse_Message_Hwnd/0003-user32-tests-Add-tests-for-window-region-of-layered-.patch new file mode 100644 index 00000000..ad420cbe --- /dev/null +++ b/patches/user32-Mouse_Message_Hwnd/0003-user32-tests-Add-tests-for-window-region-of-layered-.patch @@ -0,0 +1,149 @@ +From c5c370cded7281e5b24545123e2ce5f310f651e5 Mon Sep 17 00:00:00 2001 +From: Sebastian Lackner +Date: Mon, 29 May 2017 06:04:18 +0200 +Subject: user32/tests: Add tests for window region of layered windows. + +--- + dlls/user32/tests/input.c | 70 +++++++++++++++++++++++++++++++++++++++++++++++ + 1 file changed, 70 insertions(+) + +diff --git a/dlls/user32/tests/input.c b/dlls/user32/tests/input.c +index 47c5fa8c932..08c4c5435c6 100644 +--- a/dlls/user32/tests/input.c ++++ b/dlls/user32/tests/input.c +@@ -80,6 +80,7 @@ static struct { + static UINT (WINAPI *pSendInput) (UINT, INPUT*, size_t); + static int (WINAPI *pGetMouseMovePointsEx) (UINT, LPMOUSEMOVEPOINT, LPMOUSEMOVEPOINT, int, DWORD); + static UINT (WINAPI *pGetRawInputDeviceList) (PRAWINPUTDEVICELIST, PUINT, UINT); ++static int (WINAPI *pGetWindowRgnBox)(HWND, LPRECT); + + #define MAXKEYEVENTS 12 + #define MAXKEYMESSAGES MAXKEYEVENTS /* assuming a key event generates one +@@ -164,6 +165,7 @@ static void init_function_pointers(void) + GET_PROC(SendInput) + GET_PROC(GetMouseMovePointsEx) + GET_PROC(GetRawInputDeviceList) ++ GET_PROC(GetWindowRgnBox) + + #undef GET_PROC + } +@@ -1930,6 +1932,9 @@ static void test_Input_mouse(void) + DWORD thread_id; + WNDCLASSA wclass; + POINT pt, pt_org; ++ int region_type; ++ HRGN hregion; ++ RECT region; + BOOL ret; + MSG msg; + +@@ -2159,6 +2164,12 @@ static void test_Input_mouse(void) + while (wait_for_message(&msg)) DispatchMessageA(&msg); + Sleep(100); + ++ if (pGetWindowRgnBox) ++ { ++ region_type = pGetWindowRgnBox(hwnd, ®ion); ++ ok(region_type == ERROR, "expected ERROR, got %d\n", region_type); ++ } ++ + got_button_down = got_button_up = FALSE; + simulate_click(TRUE, 150, 150); + while (wait_for_message(&msg)) +@@ -2185,6 +2196,12 @@ static void test_Input_mouse(void) + while (wait_for_message(&msg)) DispatchMessageA(&msg); + Sleep(100); + ++ if (pGetWindowRgnBox) ++ { ++ region_type = pGetWindowRgnBox(hwnd, ®ion); ++ ok(region_type == ERROR, "expected ERROR, got %d\n", region_type); ++ } ++ + got_button_down = got_button_up = FALSE; + simulate_click(TRUE, 150, 150); + while (wait_for_message(&msg)) +@@ -2213,6 +2230,12 @@ static void test_Input_mouse(void) + while (wait_for_message(&msg)) DispatchMessageA(&msg); + Sleep(100); + ++ if (pGetWindowRgnBox) ++ { ++ region_type = pGetWindowRgnBox(hwnd, ®ion); ++ ok(region_type == ERROR, "expected ERROR, got %d\n", region_type); ++ } ++ + got_button_down = got_button_up = FALSE; + simulate_click(TRUE, 150, 150); + while (wait_for_message(&msg)) +@@ -2239,6 +2262,12 @@ static void test_Input_mouse(void) + while (wait_for_message(&msg)) DispatchMessageA(&msg); + Sleep(100); + ++ if (pGetWindowRgnBox) ++ { ++ region_type = pGetWindowRgnBox(hwnd, ®ion); ++ ok(region_type == ERROR, "expected ERROR, got %d\n", region_type); ++ } ++ + got_button_down = got_button_up = FALSE; + simulate_click(TRUE, 150, 150); + while (wait_for_message(&msg)) +@@ -2266,6 +2295,12 @@ static void test_Input_mouse(void) + while (wait_for_message(&msg)) DispatchMessageA(&msg); + Sleep(100); + ++ if (pGetWindowRgnBox) ++ { ++ region_type = pGetWindowRgnBox(hwnd, ®ion); ++ ok(region_type == ERROR, "expected ERROR, got %d\n", region_type); ++ } ++ + got_button_down = got_button_up = FALSE; + simulate_click(TRUE, 150, 150); + while (wait_for_message(&msg)) +@@ -2287,6 +2322,41 @@ static void test_Input_mouse(void) + ok(got_button_down, "expected WM_LBUTTONDOWN message\n"); + ok(got_button_up, "expected WM_LBUTTONUP message\n"); + ++ hregion = CreateRectRgn(0, 0, 10, 10); ++ ok(hregion != NULL, "CreateRectRgn failed\n"); ++ ret = SetWindowRgn(hwnd, hregion, TRUE); ++ ok(ret, "SetWindowRgn failed\n"); ++ DeleteObject(hregion); ++ while (wait_for_message(&msg)) DispatchMessageA(&msg); ++ Sleep(1000); ++ ++ if (pGetWindowRgnBox) ++ { ++ region_type = pGetWindowRgnBox(hwnd, ®ion); ++ ok(region_type == SIMPLEREGION, "expected SIMPLEREGION, got %d\n", region_type); ++ } ++ ++ got_button_down = got_button_up = FALSE; ++ simulate_click(TRUE, 150, 150); ++ while (wait_for_message(&msg)) ++ { ++ DispatchMessageA(&msg); ++ ++ if (msg.message == WM_LBUTTONDOWN) ++ { ++ ok(msg.hwnd == button_win, "msg.hwnd = %p\n", msg.hwnd); ++ got_button_down = TRUE; ++ } ++ else if (msg.message == WM_LBUTTONUP) ++ { ++ ok(msg.hwnd == button_win, "msg.hwnd = %p\n", msg.hwnd); ++ got_button_up = TRUE; ++ break; ++ } ++ } ++ ok(got_button_down, "expected WM_LBUTTONDOWN message\n"); ++ ok(got_button_up, "expected WM_LBUTTONUP message\n"); ++ + DestroyWindow(hwnd); + SetCursorPos(pt_org.x, pt_org.y); + +-- +2.12.2 + diff --git a/patches/user32-Mouse_Message_Hwnd/0004-server-Add-support-for-a-layered-window-region.-v2.patch b/patches/user32-Mouse_Message_Hwnd/0004-server-Add-support-for-a-layered-window-region.-v2.patch new file mode 100644 index 00000000..cb43e4ec --- /dev/null +++ b/patches/user32-Mouse_Message_Hwnd/0004-server-Add-support-for-a-layered-window-region.-v2.patch @@ -0,0 +1,300 @@ +From ac68b0ca43fd70c641d4b84477858db8c38af20a Mon Sep 17 00:00:00 2001 +From: Dmitry Timoshkov +Date: Wed, 17 May 2017 23:55:55 +0800 +Subject: server: Add support for a layered window region. (v2) + +--- + dlls/user32/tests/input.c | 2 -- + dlls/winex11.drv/bitblt.c | 46 ++++++++++++++++++++++++++++++++++- + server/protocol.def | 7 ++++++ + server/window.c | 62 +++++++++++++++++++++++++++++++++++++++++++++++ + 4 files changed, 114 insertions(+), 3 deletions(-) + +diff --git a/dlls/user32/tests/input.c b/dlls/user32/tests/input.c +index 08c4c5435c6..87c491657a9 100644 +--- a/dlls/user32/tests/input.c ++++ b/dlls/user32/tests/input.c +@@ -2276,13 +2276,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 80256dce569..474131da741 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); +@@ -1609,6 +1610,48 @@ static inline void add_row( HRGN rgn, RGNDATA *data, int x, int y, int len ) + flush_rgn_data( rgn, data ); + } + ++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 + */ +@@ -1627,7 +1670,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 ); +- return; ++ set_layer_region( surface, NULL ); + } + + data->rdh.dwSize = sizeof(data->rdh); +@@ -1737,6 +1780,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 7eaaec2b823..f2526c4836c 100644 +--- a/server/protocol.def ++++ b/server/protocol.def +@@ -2682,6 +2682,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 f35d6f60a42..672512b3a43 100644 +--- a/server/window.c ++++ b/server/window.c +@@ -72,6 +72,7 @@ struct window + rectangle_t visible_rect; /* visible part of window rect (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 */ +@@ -477,6 +478,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; +@@ -653,6 +655,9 @@ static inline int is_point_in_window( struct window *win, int x, int y ) + 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; + } + +@@ -875,6 +880,18 @@ static struct region *intersect_window_region( struct region *region, struct win + } + + ++/* intersect the layer region with the specified region, relative to the window parent */ ++static struct region *intersect_layer_region( struct region *region, struct window *win ) ++{ ++ /* make region relative to window rect */ ++ offset_region( region, -win->window_rect.left, -win->window_rect.top ); ++ if (!intersect_region( region, region, win->layer_region )) return NULL; ++ /* make region relative to parent again */ ++ offset_region( region, win->window_rect.left, win->window_rect.top ); ++ return region; ++} ++ ++ + /* convert coordinates from client to screen coords */ + static inline void client_to_screen( struct window *win, int *x, int *y ) + { +@@ -929,6 +946,11 @@ static struct region *clip_children( struct window *parent, struct window *last, + free_region( tmp ); + return NULL; + } ++ if (ptr->layer_region && !intersect_layer_region( tmp, ptr )) ++ { ++ free_region( tmp ); ++ return NULL; ++ } + offset_region( tmp, offset_x, offset_y ); + if (!(region = subtract_region( region, region, tmp ))) break; + if (is_region_empty( region )) break; +@@ -990,11 +1012,13 @@ static struct region *get_visible_region( struct window *win, unsigned int flags + { + set_region_rect( region, &win->visible_rect ); + if (win->win_region && !intersect_window_region( region, win )) goto error; ++ if (win->layer_region && !intersect_layer_region( region, win )) goto error; + } + else + { + set_region_client_rect( region, win ); + if (win->win_region && !intersect_window_region( region, win )) goto error; ++ if (win->layer_region && !intersect_layer_region( region, win )) goto error; + } + + /* clip children */ +@@ -1039,6 +1063,7 @@ static struct region *get_visible_region( struct window *win, unsigned int flags + } + set_region_client_rect( tmp, win ); + if (win->win_region && !intersect_window_region( tmp, win )) goto error; ++ if (win->layer_region && !intersect_layer_region( tmp, win )) goto error; + if (!intersect_region( region, region, tmp )) goto error; + if (is_region_empty( region )) break; + } +@@ -1071,6 +1096,7 @@ static struct region *clip_pixel_format_children( struct window *parent, struct + /* add the visible rect */ + set_region_rect( clip, &ptr->visible_rect ); + if (ptr->win_region && !intersect_window_region( clip, ptr )) break; ++ if (ptr->layer_region && !intersect_layer_region( clip, ptr )) break; + offset_region( clip, offset_x, offset_y ); + if (!intersect_region( clip, clip, parent_clip )) break; + if (!union_region( region, region, clip )) break; +@@ -1079,6 +1105,7 @@ static struct region *clip_pixel_format_children( struct window *parent, struct + /* subtract the client rect if it uses a custom pixel format */ + set_region_rect( clip, &ptr->client_rect ); + if (ptr->win_region && !intersect_window_region( clip, ptr )) break; ++ if (ptr->layer_region && !intersect_layer_region( clip, ptr )) break; + offset_region( clip, offset_x, offset_y ); + if (!intersect_region( clip, clip, parent_clip )) break; + if ((ptr->paint_flags & PAINT_HAS_PIXEL_FORMAT) && !subtract_region( region, region, clip )) +@@ -1105,8 +1132,10 @@ static struct region *get_surface_region( struct window *win ) + if (!(clip = create_empty_region())) goto error; + set_region_rect( region, &win->visible_rect ); + if (win->win_region && !intersect_window_region( region, win )) goto error; ++ if (win->layer_region && !intersect_layer_region( region, win )) goto error; + set_region_rect( clip, &win->client_rect ); + if (win->win_region && !intersect_window_region( clip, win )) goto error; ++ if (win->layer_region && !intersect_layer_region( clip, win )) goto error; + + if ((win->paint_flags & PAINT_HAS_PIXEL_FORMAT) && !subtract_region( region, region, clip )) + goto error; +@@ -1825,6 +1854,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 ) + { +@@ -1873,6 +1910,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 ); +@@ -2537,6 +2575,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) + { +@@ -2633,6 +2689,12 @@ DECL_HANDLER(update_window_zorder) + offset_rect( &tmp, -ptr->window_rect.left, -ptr->window_rect.top ); + if (!rect_in_region( ptr->win_region, &tmp )) continue; + } ++ if (ptr->layer_region) ++ { ++ tmp = rect; ++ offset_rect( &tmp, -ptr->window_rect.left, -ptr->window_rect.top ); ++ if (!rect_in_region( ptr->layer_region, &tmp )) continue; ++ } + /* found a window obscuring the rectangle, now move win above this one */ + /* making sure to not violate the topmost rule */ + if (!(ptr->ex_style & WS_EX_TOPMOST) || (win->ex_style & WS_EX_TOPMOST)) +-- +2.12.2 +