[PATCH 4/9] winex11: Use unixlib interface for systray docking.

Jacek Caban wine at gitlab.winehq.org
Thu May 5 08:40:41 CDT 2022


From: Jacek Caban <jacek at codeweavers.com>

Signed-off-by: Jacek Caban <jacek at codeweavers.com>
---
 dlls/winex11.drv/dllmain.c     |   1 +
 dlls/winex11.drv/event.c       |  10 ++-
 dlls/winex11.drv/systray.c     | 117 ++++++---------------------------
 dlls/winex11.drv/unixlib.h     |  16 +++++
 dlls/winex11.drv/window.c      | 114 ++++++++++++++++++++++++++++++++
 dlls/winex11.drv/x11drv.h      |   2 +
 dlls/winex11.drv/x11drv_main.c |   2 +
 7 files changed, 165 insertions(+), 97 deletions(-)

diff --git a/dlls/winex11.drv/dllmain.c b/dlls/winex11.drv/dllmain.c
index bbfcefe05e3..7ea07647dc9 100644
--- a/dlls/winex11.drv/dllmain.c
+++ b/dlls/winex11.drv/dllmain.c
@@ -157,6 +157,7 @@ static const kernel_callback kernel_callbacks[] =
     x11drv_dnd_post_drop,
     x11drv_ime_set_composition_string,
     x11drv_ime_set_result,
+    x11drv_systray_change_owner,
 };
 
 C_ASSERT( NtUserDriverCallbackFirst + ARRAYSIZE(kernel_callbacks) == client_func_last );
diff --git a/dlls/winex11.drv/event.c b/dlls/winex11.drv/event.c
index cefc86d0902..12b0884a250 100644
--- a/dlls/winex11.drv/event.c
+++ b/dlls/winex11.drv/event.c
@@ -621,8 +621,16 @@ static void set_focus( Display *display, HWND hwnd, Time time )
 static void handle_manager_message( HWND hwnd, XClientMessageEvent *event )
 {
     if (hwnd != NtUserGetDesktopWindow()) return;
+
     if (systray_atom && event->data.l[1] == systray_atom)
-        change_systray_owner( event->display, event->data.l[2] );
+    {
+        struct systray_change_owner_params params;
+
+        TRACE( "new owner %lx\n", event->data.l[2] );
+
+        params.event_handle = (UINT_PTR)event;
+        x11drv_client_func( client_func_systray_change_owner, &params, sizeof(params) );
+    }
 }
 
 
diff --git a/dlls/winex11.drv/systray.c b/dlls/winex11.drv/systray.c
index bb2e5d563dd..ae1c5738f8e 100644
--- a/dlls/winex11.drv/systray.c
+++ b/dlls/winex11.drv/systray.c
@@ -75,12 +75,6 @@ static BOOL show_icon( struct tray_icon *icon );
 static BOOL hide_icon( struct tray_icon *icon );
 static BOOL delete_icon( struct tray_icon *icon );
 
-#define SYSTEM_TRAY_REQUEST_DOCK  0
-#define SYSTEM_TRAY_BEGIN_MESSAGE   1
-#define SYSTEM_TRAY_CANCEL_MESSAGE  2
-
-Atom systray_atom = 0;
-
 #define MIN_DISPLAYED 8
 #define ICON_BORDER 2
 
@@ -550,39 +544,6 @@ static LRESULT WINAPI tray_icon_wndproc(HWND hwnd, UINT msg, WPARAM wparam, LPAR
     return DefWindowProcW( hwnd, msg, wparam, lparam );
 }
 
-/* find the X11 window owner the system tray selection */
-static Window get_systray_selection_owner( Display *display )
-{
-    return XGetSelectionOwner( display, systray_atom );
-}
-
-static void get_systray_visual_info( Display *display, Window systray_window, XVisualInfo *info )
-{
-    XVisualInfo *list, template;
-    VisualID *visual_id;
-    Atom type;
-    int format, num;
-    unsigned long count, remaining;
-
-    *info = default_visual;
-    if (XGetWindowProperty( display, systray_window, x11drv_atom(_NET_SYSTEM_TRAY_VISUAL), 0,
-                            65536/sizeof(CARD32), False, XA_VISUALID, &type, &format, &count,
-                            &remaining, (unsigned char **)&visual_id ))
-        return;
-
-    if (type == XA_VISUALID && format == 32)
-    {
-        template.visualid = visual_id[0];
-        if ((list = XGetVisualInfo( display, VisualIDMask, &template, &num )))
-        {
-            *info = list[0];
-            TRACE( "systray window %lx got visual %lx\n", systray_window, info->visualid );
-            XFree( list );
-        }
-    }
-    XFree( visual_id );
-}
-
 static BOOL init_systray(void)
 {
     static BOOL init_done;
@@ -627,66 +588,27 @@ static BOOL init_systray(void)
     return TRUE;
 }
 
-/* dock the given icon with the NETWM system tray */
-static void dock_systray_icon( Display *display, struct tray_icon *icon, Window systray_window )
-{
-    Window window;
-    XEvent ev;
-    XSetWindowAttributes attr;
-    XVisualInfo visual;
-    struct x11drv_win_data *data;
-
-    get_systray_visual_info( display, systray_window, &visual );
-
-    icon->layered = (visual.depth == 32);
-    CreateWindowExW( icon->layered ? WS_EX_LAYERED : 0,
-                     icon_classname, NULL, WS_CLIPSIBLINGS | WS_POPUP,
-                     CW_USEDEFAULT, CW_USEDEFAULT, icon_cx, icon_cy,
-                     NULL, NULL, NULL, icon );
-
-    if (!(data = get_win_data( icon->window ))) return;
-    if (icon->layered) set_window_visual( data, &visual, TRUE );
-    make_window_embedded( data );
-    window = data->whole_window;
-    release_win_data( data );
-
-    ShowWindow( icon->window, SW_SHOWNA );
-
-    TRACE( "icon window %p/%lx\n", icon->window, window );
-
-    /* send the docking request message */
-    ev.xclient.type = ClientMessage;
-    ev.xclient.window = systray_window;
-    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] = window;
-    ev.xclient.data.l[3] = 0;
-    ev.xclient.data.l[4] = 0;
-    XSendEvent( display, systray_window, False, NoEventMask, &ev );
-
-    if (!icon->layered)
-    {
-        attr.background_pixmap = ParentRelative;
-        attr.bit_gravity = ForgetGravity;
-        XChangeWindowAttributes( display, window, CWBackPixmap | CWBitGravity, &attr );
-    }
-    else repaint_tray_icon( icon );
-}
-
 /* dock systray windows again with the new owner */
-void change_systray_owner( Display *display, Window systray_window )
+NTSTATUS WINAPI x11drv_systray_change_owner( void *arg, ULONG size )
 {
+    struct systray_change_owner_params *params = arg;
+    struct systray_dock_params dock_params;
     struct tray_icon *icon;
 
-    TRACE( "new owner %lx\n", systray_window );
     LIST_FOR_EACH_ENTRY( icon, &icon_list, struct tray_icon, entry )
     {
         if (icon->display == -1) continue;
         hide_icon( icon );
-        dock_systray_icon( display, icon, systray_window );
+
+        dock_params.event_handle = params->event_handle;
+        dock_params.icon = icon;
+        dock_params.cx = icon_cx;
+        dock_params.cy = icon_cy;
+        dock_params.layered = &icon->layered;
+        X11DRV_CALL( systray_dock, &dock_params );
     }
+
+    return 0;
 }
 
 /* hide a tray icon */
@@ -710,16 +632,19 @@ static BOOL hide_icon( struct tray_icon *icon )
 /* make the icon visible */
 static BOOL show_icon( struct tray_icon *icon )
 {
-    Window systray_window;
-    Display *display = thread_init_display();
+    struct systray_dock_params params;
+
+    if (icon->window) return TRUE;  /* already shown */
 
     TRACE( "id=0x%x, hwnd=%p\n", icon->id, icon->owner );
 
-    if (icon->window) return TRUE;  /* already shown */
+    params.event_handle = 0;
+    params.icon = icon;
+    params.cx = icon_cx;
+    params.cy = icon_cy;
+    params.layered = &icon->layered;
 
-    if ((systray_window = get_systray_selection_owner( display )))
-        dock_systray_icon( display, icon, systray_window );
-    else
+    if (X11DRV_CALL( systray_dock, &params ))
         add_to_standalone_tray( icon );
 
     update_balloon( icon );
diff --git a/dlls/winex11.drv/unixlib.h b/dlls/winex11.drv/unixlib.h
index ce89f7d4d39..dc3c74979ca 100644
--- a/dlls/winex11.drv/unixlib.h
+++ b/dlls/winex11.drv/unixlib.h
@@ -25,6 +25,7 @@ enum x11drv_funcs
     unix_create_desktop,
     unix_init,
     unix_systray_clear,
+    unix_systray_dock,
     unix_systray_hide,
     unix_systray_init,
     unix_tablet_attach_queue,
@@ -56,6 +57,15 @@ struct create_desktop_params
     UINT height;
 };
 
+struct systray_dock_params
+{
+    UINT64 event_handle;
+    void *icon;
+    int cx;
+    int cy;
+    BOOL *layered;
+};
+
 /* x11drv_tablet_info params */
 struct tablet_info_params
 {
@@ -80,6 +90,7 @@ enum x11drv_client_funcs
     client_func_dnd_post_drop,
     client_func_ime_set_composition_string,
     client_func_ime_set_result,
+    client_func_systray_change_owner,
     client_func_last
 };
 
@@ -121,3 +132,8 @@ struct dnd_position_event_params
     POINT point;
     DWORD effect;
 };
+
+struct systray_change_owner_params
+{
+    UINT64 event_handle;
+};
diff --git a/dlls/winex11.drv/window.c b/dlls/winex11.drv/window.c
index 4ae1d3f11a3..f006150fb7c 100644
--- a/dlls/winex11.drv/window.c
+++ b/dlls/winex11.drv/window.c
@@ -53,6 +53,7 @@
 #include "mwm.h"
 
 WINE_DEFAULT_DEBUG_CHANNEL(x11drv);
+WINE_DECLARE_DEBUG_CHANNEL(systray);
 
 #define _NET_WM_MOVERESIZE_SIZE_TOPLEFT      0
 #define _NET_WM_MOVERESIZE_SIZE_TOP          1
@@ -70,6 +71,10 @@ WINE_DEFAULT_DEBUG_CHANNEL(x11drv);
 #define _NET_WM_STATE_ADD     1
 #define _NET_WM_STATE_TOGGLE  2
 
+#define SYSTEM_TRAY_REQUEST_DOCK    0
+#define SYSTEM_TRAY_BEGIN_MESSAGE   1
+#define SYSTEM_TRAY_CANCEL_MESSAGE  2
+
 static const unsigned int net_wm_state_atoms[NB_NET_WM_STATES] =
 {
     XATOM__NET_WM_STATE_FULLSCREEN,
@@ -2138,6 +2143,115 @@ NTSTATUS x11drv_systray_hide( void *arg )
 }
 
 
+/* find the X11 window owner the system tray selection */
+static Window get_systray_selection_owner( Display *display )
+{
+    return XGetSelectionOwner( display, systray_atom );
+}
+
+
+static void get_systray_visual_info( Display *display, Window systray_window, XVisualInfo *info )
+{
+    XVisualInfo *list, template;
+    VisualID *visual_id;
+    Atom type;
+    int format, num;
+    unsigned long count, remaining;
+
+    *info = default_visual;
+    if (XGetWindowProperty( display, systray_window, x11drv_atom(_NET_SYSTEM_TRAY_VISUAL), 0,
+                            65536/sizeof(CARD32), False, XA_VISUALID, &type, &format, &count,
+                            &remaining, (unsigned char **)&visual_id ))
+        return;
+
+    if (type == XA_VISUALID && format == 32)
+    {
+        template.visualid = visual_id[0];
+        if ((list = XGetVisualInfo( display, VisualIDMask, &template, &num )))
+        {
+            *info = list[0];
+            TRACE_(systray)( "systray window %lx got visual %lx\n", systray_window, info->visualid );
+            XFree( list );
+        }
+    }
+    XFree( visual_id );
+}
+
+
+NTSTATUS x11drv_systray_dock( void *arg )
+{
+    struct systray_dock_params *params = arg;
+    Window systray_window, window;
+    Display *display;
+    XEvent ev;
+    XSetWindowAttributes attr;
+    XVisualInfo visual;
+    struct x11drv_win_data *data;
+    BOOL layered;
+    HWND hwnd;
+
+    static const WCHAR icon_classname[] =
+        {'_','_','w','i','n','e','x','1','1','_','t','r','a','y','_','i','c','o','n',0};
+
+    if (params->event_handle)
+    {
+        XClientMessageEvent *event = (XClientMessageEvent *)(UINT_PTR)params->event_handle;
+        display = event->display;
+        systray_window = event->data.l[2];
+    }
+    else
+    {
+        display = thread_init_display();
+        if (!(systray_window = get_systray_selection_owner( display ))) return STATUS_UNSUCCESSFUL;
+    }
+
+    get_systray_visual_info( display, systray_window, &visual );
+
+    *params->layered = layered = (visual.depth == 32);
+
+    hwnd = CreateWindowExW( layered ? WS_EX_LAYERED : 0,
+                            icon_classname, NULL, WS_CLIPSIBLINGS | WS_POPUP,
+                            CW_USEDEFAULT, CW_USEDEFAULT, params->cx, params->cy,
+                            NULL, NULL, NULL, params->icon );
+
+    if (!(data = get_win_data( hwnd ))) return STATUS_UNSUCCESSFUL;
+    if (layered) set_window_visual( data, &visual, TRUE );
+    make_window_embedded( data );
+    window = data->whole_window;
+    release_win_data( data );
+
+    NtUserShowWindow( hwnd, SW_SHOWNA );
+
+    TRACE_(systray)( "icon window %p/%lx\n", hwnd, window );
+
+    /* send the docking request message */
+    ev.xclient.type = ClientMessage;
+    ev.xclient.window = systray_window;
+    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] = window;
+    ev.xclient.data.l[3] = 0;
+    ev.xclient.data.l[4] = 0;
+    XSendEvent( display, systray_window, False, NoEventMask, &ev );
+
+    if (!layered)
+    {
+        attr.background_pixmap = ParentRelative;
+        attr.bit_gravity = ForgetGravity;
+        XChangeWindowAttributes( display, window, CWBackPixmap | CWBitGravity, &attr );
+    }
+    else
+    {
+        /* force repainig */
+        send_message( hwnd, WM_SIZE, SIZE_RESTORED, MAKELONG( params->cx, params->cy ));
+    }
+
+    return STATUS_SUCCESS;
+}
+
+
 /***********************************************************************
  *		X11DRV_get_whole_window
  *
diff --git a/dlls/winex11.drv/x11drv.h b/dlls/winex11.drv/x11drv.h
index ec72d8a550e..d3db49b86b6 100644
--- a/dlls/winex11.drv/x11drv.h
+++ b/dlls/winex11.drv/x11drv.h
@@ -828,6 +828,7 @@ static inline BOOL is_window_rect_mapped( const RECT *rect )
 extern NTSTATUS x11drv_clipboard_message( void *arg ) DECLSPEC_HIDDEN;
 extern NTSTATUS x11drv_create_desktop( void *arg ) DECLSPEC_HIDDEN;
 extern NTSTATUS x11drv_systray_clear( void *arg ) DECLSPEC_HIDDEN;
+extern NTSTATUS x11drv_systray_dock( void *arg ) DECLSPEC_HIDDEN;
 extern NTSTATUS x11drv_systray_hide( void *arg ) DECLSPEC_HIDDEN;
 extern NTSTATUS x11drv_systray_init( void *arg ) DECLSPEC_HIDDEN;
 extern NTSTATUS x11drv_tablet_attach_queue( void *arg ) DECLSPEC_HIDDEN;
@@ -842,6 +843,7 @@ extern NTSTATUS WINAPI x11drv_dnd_position_event( void *params, ULONG size ) DEC
 extern NTSTATUS WINAPI x11drv_dnd_post_drop( void *data, ULONG size ) DECLSPEC_HIDDEN;
 extern NTSTATUS WINAPI x11drv_ime_set_composition_string( void *params, ULONG size ) DECLSPEC_HIDDEN;
 extern NTSTATUS WINAPI x11drv_ime_set_result( void *params, ULONG size ) DECLSPEC_HIDDEN;
+extern NTSTATUS WINAPI x11drv_systray_change_owner( void *params, ULONG size ) DECLSPEC_HIDDEN;
 
 extern NTSTATUS x11drv_dnd_drop_event( UINT arg ) DECLSPEC_HIDDEN;
 extern NTSTATUS x11drv_dnd_leave_event( UINT arg ) DECLSPEC_HIDDEN;
diff --git a/dlls/winex11.drv/x11drv_main.c b/dlls/winex11.drv/x11drv_main.c
index 2d65f2a03d6..cbcfc659a67 100644
--- a/dlls/winex11.drv/x11drv_main.c
+++ b/dlls/winex11.drv/x11drv_main.c
@@ -60,6 +60,7 @@ XVisualInfo default_visual = { 0 };
 XVisualInfo argb_visual = { 0 };
 Colormap default_colormap = None;
 XPixmapFormatValues **pixmap_formats;
+Atom systray_atom = 0;
 unsigned int screen_bpp;
 Window root_window;
 BOOL usexvidmode = TRUE;
@@ -978,6 +979,7 @@ const unixlib_entry_t __wine_unix_call_funcs[] =
     x11drv_create_desktop,
     x11drv_init,
     x11drv_systray_clear,
+    x11drv_systray_dock,
     x11drv_systray_hide,
     x11drv_systray_init,
     x11drv_tablet_attach_queue,
-- 
GitLab


https://gitlab.winehq.org/wine/wine/-/merge_requests/39



More information about the wine-devel mailing list