From: Jacek Caban jacek@codeweavers.com
Signed-off-by: Jacek Caban jacek@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, ¶ms, 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, ¶ms )) 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,