winex11: Use unixlib interface for systray docking.

Signed-off-by: Jacek Caban <jacek@codeweavers.com>
Signed-off-by: Alexandre Julliard <julliard@winehq.org>
This commit is contained in:
Jacek Caban 2022-05-04 00:10:36 +02:00 committed by Alexandre Julliard
parent e41630612b
commit 21d269f2fc
7 changed files with 166 additions and 98 deletions

View File

@ -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 );

View File

@ -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) );
}
}

View File

@ -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();
TRACE( "id=0x%x, hwnd=%p\n", icon->id, icon->owner );
struct systray_dock_params params;
if (icon->window) return TRUE; /* already shown */
if ((systray_window = get_systray_selection_owner( display )))
dock_systray_icon( display, icon, systray_window );
else
TRACE( "id=0x%x, hwnd=%p\n", icon->id, icon->owner );
params.event_handle = 0;
params.icon = icon;
params.cx = icon_cx;
params.cy = icon_cy;
params.layered = &icon->layered;
if (X11DRV_CALL( systray_dock, &params ))
add_to_standalone_tray( icon );
update_balloon( icon );

View File

@ -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;
};

View File

@ -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
*

View File

@ -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;

View File

@ -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,