On Wed Feb 14 16:42:28 2024 +0000, Gabriel Ivăncescu wrote:
BTW I think I found the reason it fails. It's not the `make_window_embedded` or `set_window_visual` calls. Neither is the `NtUserShowWindow`. For example the following works:
diff --git a/dlls/winex11.drv/window.c b/dlls/winex11.drv/window.c index 8ab6944..1ce0165 100644 --- a/dlls/winex11.drv/window.c +++ b/dlls/winex11.drv/window.c @@ -2337,6 +2337,11 @@ BOOL X11DRV_SystrayDockInsert( HWND hwnd, UINT cx, UINT cy, void *icon ) release_win_data( data ); NtUserShowWindow( hwnd, SW_SHOWNA ); + NtUserSetWindowLong( hwnd, GWL_EXSTYLE, NtUserGetWindowLongW( hwnd, GWL_EXSTYLE ) | WS_EX_LAYERED, FALSE ); + + if (!(data = get_win_data( hwnd ))) return FALSE; + window = data->whole_window; + release_win_data( data ); TRACE_(systray)( "icon window %p/%lx\n", hwnd, window );
One important thing to notice is that the whole `window = data->whole_window` **after** setting it to layered is important, so the correct window is sent to `XSendEvent` for the docking message. Without that, it will still fail. So why does this happen? Because setting it to WS_EX_LAYERED makes it eventually end up in `set_window_visual` (from `X11DRV_SetWindowStyle`), which **destroys and recreates the X window**. As in, the old X window no longer exists, so there's nothing to dock! Sure enough the following hack also fixes it:
diff --git a/dlls/winex11.drv/window.c b/dlls/winex11.drv/window.c index 8ab6944..0e2ef96 100644 --- a/dlls/winex11.drv/window.c +++ b/dlls/winex11.drv/window.c @@ -1812,6 +1812,7 @@ void set_window_visual( struct x11drv_win_data *data, const XVisualInfo *vis, BO Window client_window = data->client_window; Window whole_window = data->whole_window; + return; if (!data->use_alpha == !use_alpha) return; if (data->surface) window_surface_release( data->surface ); data->surface = NULL;
Why does it even need to destroy and recreate the window? I'm going to experiment a bit but otherwise I'll go with just setting it earlier.
How about something like this?
```diff diff --git a/dlls/winex11.drv/window.c b/dlls/winex11.drv/window.c index 8ab6944..7bda648 100644 --- a/dlls/winex11.drv/window.c +++ b/dlls/winex11.drv/window.c @@ -1822,14 +1822,32 @@ void set_window_visual( struct x11drv_win_data *data, const XVisualInfo *vis, BO destroy_whole_window( data, client_window != 0 /* don't destroy whole_window until reparented */ ); data->vis = *vis; create_whole_window( data ); - if (!client_window) return; - /* move the client to the new parent */ - XReparentWindow( gdi_display, client_window, data->whole_window, - data->client_rect.left - data->whole_rect.left, - data->client_rect.top - data->whole_rect.top ); - data->client_window = client_window; - XSync( gdi_display, False ); /* make sure XReparentWindow requests have completed before destroying whole_window */ - XDestroyWindow( data->display, whole_window ); + if (client_window) + { + /* move the client to the new parent */ + XReparentWindow( gdi_display, client_window, data->whole_window, + data->client_rect.left - data->whole_rect.left, + data->client_rect.top - data->whole_rect.top ); + data->client_window = client_window; + XSync( gdi_display, False ); /* make sure XReparentWindow requests have completed before destroying whole_window */ + XDestroyWindow( data->display, whole_window ); + } + + /* if we were docked, re-send the docking request message */ + if (data->docked_to) + { + XEvent ev; + ev.xclient.type = ClientMessage; + ev.xclient.window = data->docked_to; + ev.xclient.message_type = x11drv_atom( _NET_SYSTEM_TRAY_OPCODE ); + ev.xclient.format = 32; + ev.xclient.data.l[0] = CurrentTime; + ev.xclient.data.l[1] = SYSTEM_TRAY_REQUEST_DOCK; + ev.xclient.data.l[2] = data->whole_window; + ev.xclient.data.l[3] = 0; + ev.xclient.data.l[4] = 0; + XSendEvent( data->display, data->docked_to, False, NoEventMask, &ev ); + } }
@@ -2272,6 +2290,7 @@ BOOL X11DRV_SystrayDockRemove( HWND hwnd ) if ((data = get_win_data( hwnd ))) { if ((ret = data->embedded)) data->mapped = FALSE; + data->docked_to = 0; release_win_data( data ); return ret; } @@ -2334,6 +2353,7 @@ BOOL X11DRV_SystrayDockInsert( HWND hwnd, UINT cx, UINT cy, void *icon ) set_window_visual( data, &visual, TRUE ); make_window_embedded( data ); window = data->whole_window; + data->docked_to = systray_window; release_win_data( data );
NtUserShowWindow( hwnd, SW_SHOWNA ); diff --git a/dlls/winex11.drv/x11drv.h b/dlls/winex11.drv/x11drv.h index 71a3582..b1ea370 100644 --- a/dlls/winex11.drv/x11drv.h +++ b/dlls/winex11.drv/x11drv.h @@ -628,6 +628,7 @@ struct x11drv_win_data int wm_state; /* current value of the WM_STATE property */ DWORD net_wm_state; /* bit mask of active x11drv_net_wm_state values */ Window embedder; /* window id of embedder */ + Window docked_to; /* window id of systray if we are docked to it */ unsigned long configure_serial; /* serial number of last configure request */ struct window_surface *surface; Pixmap icon_pixmap; ```
It also fixes it without any change to explorer, since it seems to be a winex11.drv quirk we have (destroying and re-creating the window…).
Is this acceptable?