Commit e03b8e1a authored by Alexandre Julliard's avatar Alexandre Julliard

winex11: Use ARGB layered windows for system tray icons when supported.

parent d8247efd
......@@ -53,6 +53,7 @@ struct tray_icon
HICON image; /* the image to render */
HWND owner; /* the HWND passed in to the Shell_NotifyIcon call */
HWND window; /* the adaptor window */
BOOL layered; /* whether we are using a layered window */
HWND tooltip; /* Icon tooltip */
UINT state; /* state flags */
UINT id; /* the unique id given by the app */
......@@ -361,6 +362,80 @@ static void remove_from_standalone_tray( struct tray_icon *icon )
TRACE( "removed %u now %d icons\n", icon->id, nb_displayed );
}
static void repaint_tray_icon( struct tray_icon *icon )
{
BLENDFUNCTION blend = { AC_SRC_OVER, 0, 255, AC_SRC_ALPHA };
int width = GetSystemMetrics( SM_CXSMICON );
int height = GetSystemMetrics( SM_CYSMICON );
BITMAPINFO *info;
HBITMAP dib, mask;
HDC hdc;
RECT rc;
SIZE size;
POINT pos;
int i, x, y;
void *color_bits, *mask_bits;
DWORD *ptr;
BOOL has_alpha = FALSE;
GetWindowRect( icon->window, &rc );
size.cx = rc.right - rc.left;
size.cy = rc.bottom - rc.top;
pos.x = (size.cx - width) / 2;
pos.y = (size.cy - height) / 2;
info = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, FIELD_OFFSET( BITMAPINFO, bmiColors[2] ));
if (!info) return;
info->bmiHeader.biSize = sizeof(info->bmiHeader);
info->bmiHeader.biWidth = size.cx;
info->bmiHeader.biHeight = size.cy;
info->bmiHeader.biBitCount = 32;
info->bmiHeader.biPlanes = 1;
info->bmiHeader.biCompression = BI_RGB;
hdc = CreateCompatibleDC( 0 );
if (!(dib = CreateDIBSection( 0, info, DIB_RGB_COLORS, &color_bits, NULL, 0 ))) goto done;
SelectObject( hdc, dib );
DrawIconEx( hdc, pos.x, pos.y, icon->image, width, height, 0, 0, DI_DEFAULTSIZE | DI_NORMAL );
/* check if the icon was drawn with an alpha channel */
for (i = 0, ptr = color_bits; i < size.cx * size.cy; i++)
if ((has_alpha = (ptr[i] & 0xff000000) != 0)) break;
if (!has_alpha)
{
unsigned int width_bytes = (size.cx + 31) / 32 * 4;
info->bmiHeader.biBitCount = 1;
info->bmiColors[0].rgbRed = 0;
info->bmiColors[0].rgbGreen = 0;
info->bmiColors[0].rgbBlue = 0;
info->bmiColors[0].rgbReserved = 0;
info->bmiColors[1].rgbRed = 0xff;
info->bmiColors[1].rgbGreen = 0xff;
info->bmiColors[1].rgbBlue = 0xff;
info->bmiColors[1].rgbReserved = 0;
if (!(mask = CreateDIBSection( 0, info, DIB_RGB_COLORS, &mask_bits, NULL, 0 ))) goto done;
memset( mask_bits, 0xff, width_bytes * size.cy );
SelectObject( hdc, mask );
DrawIconEx( hdc, pos.x, pos.y, icon->image, width, height, 0, 0, DI_DEFAULTSIZE | DI_MASK );
for (y = 0, ptr = color_bits; y < size.cy; y++)
for (x = 0; x < size.cx; x++, ptr++)
if (!((((BYTE *)mask_bits)[y * width_bytes + x / 8] << (x % 8)) & 0x80))
*ptr |= 0xff000000;
SelectObject( hdc, dib );
DeleteObject( mask );
}
UpdateLayeredWindow( icon->window, 0, NULL, NULL, hdc, NULL, 0, &blend, ULW_ALPHA );
done:
if (hdc) DeleteDC( hdc );
if (dib) DeleteObject( dib );
}
/* window procedure for the individual tray icon window */
static LRESULT WINAPI tray_icon_wndproc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam)
{
......@@ -381,6 +456,10 @@ static LRESULT WINAPI tray_icon_wndproc(HWND hwnd, UINT msg, WPARAM wparam, LPAR
SetTimer( hwnd, VALID_WIN_TIMER, VALID_WIN_TIMEOUT, NULL );
break;
case WM_SIZE:
if (icon->window && icon->layered) repaint_tray_icon( icon );
break;
case WM_PAINT:
{
PAINTSTRUCT ps;
......@@ -455,6 +534,33 @@ 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;
......@@ -513,15 +619,26 @@ static void dock_systray_icon( Display *display, struct tray_icon *icon, 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.visualid != default_visual.visualid);
icon->window = 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 );
make_window_embedded( data );
window = data->whole_window;
release_win_data( data );
icon->window = CreateWindowW( icon_classname, NULL, WS_CLIPSIBLINGS | WS_POPUP,
CW_USEDEFAULT, CW_USEDEFAULT, icon_cx, icon_cy,
NULL, NULL, NULL, icon );
make_window_embedded( icon->window );
create_tooltip( icon );
ShowWindow( icon->window, SW_SHOWNA );
if (!(window = X11DRV_get_whole_window( icon->window ))) return;
TRACE( "icon window %p/%lx\n", icon->window, window );
/* send the docking request message */
......@@ -535,9 +652,14 @@ static void dock_systray_icon( Display *display, struct tray_icon *icon, Window
ev.xclient.data.l[3] = 0;
ev.xclient.data.l[4] = 0;
XSendEvent( display, systray_window, False, NoEventMask, &ev );
attr.background_pixmap = ParentRelative;
attr.bit_gravity = ForgetGravity;
XChangeWindowAttributes( display, window, CWBackPixmap | CWBitGravity, &attr );
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 */
......@@ -572,6 +694,7 @@ static BOOL hide_icon( struct tray_icon *icon )
DestroyWindow(icon->window);
DestroyWindow(icon->tooltip);
icon->window = 0;
icon->layered = FALSE;
icon->tooltip = 0;
remove_from_standalone_tray( icon );
update_balloon( icon );
......@@ -614,6 +737,7 @@ static BOOL modify_icon( struct tray_icon *icon, NOTIFYICONDATAW *nid )
if (icon->window)
{
if (icon->display != -1) InvalidateRect( icon->window, NULL, TRUE );
else if (icon->layered) repaint_tray_icon( icon );
else
{
Window win = X11DRV_get_whole_window( icon->window );
......
......@@ -1124,12 +1124,8 @@ static void unmap_window( HWND hwnd )
/***********************************************************************
* make_window_embedded
*/
void make_window_embedded( HWND hwnd )
void make_window_embedded( struct x11drv_win_data *data )
{
struct x11drv_win_data *data = get_win_data( hwnd );
if (!data) return;
/* the window cannot be mapped before being embedded */
if (data->mapped)
{
......@@ -1139,10 +1135,9 @@ void make_window_embedded( HWND hwnd )
}
data->embedded = TRUE;
data->managed = TRUE;
SetPropA( hwnd, managed_prop, (HANDLE)1 );
SetPropA( data->hwnd, managed_prop, (HANDLE)1 );
sync_window_style( data );
set_xembed_flags( data, data->mapped ? XEMBED_MAPPED : 0 );
release_win_data( data );
}
......@@ -2376,7 +2371,7 @@ BOOL CDECL X11DRV_UpdateLayeredWindow( HWND hwnd, const UPDATELAYEREDWINDOWINFO
if (!(data = get_win_data( hwnd ))) return FALSE;
set_window_visual( data, &argb_visual );
if (!data->embedded) set_window_visual( data, &argb_visual );
rect = *window_rect;
OffsetRect( &rect, -window_rect->left, -window_rect->top );
......
......@@ -407,6 +407,7 @@ enum x11drv_atoms
XATOM__NET_SUPPORTED,
XATOM__NET_SYSTEM_TRAY_OPCODE,
XATOM__NET_SYSTEM_TRAY_S0,
XATOM__NET_SYSTEM_TRAY_VISUAL,
XATOM__NET_WM_ICON,
XATOM__NET_WM_MOVERESIZE,
XATOM__NET_WM_NAME,
......@@ -570,7 +571,7 @@ extern void wait_for_withdrawn_state( HWND hwnd, BOOL set ) DECLSPEC_HIDDEN;
extern Window init_clip_window(void) DECLSPEC_HIDDEN;
extern void update_user_time( Time time ) DECLSPEC_HIDDEN;
extern void update_net_wm_states( struct x11drv_win_data *data ) DECLSPEC_HIDDEN;
extern void make_window_embedded( HWND hwnd ) DECLSPEC_HIDDEN;
extern void make_window_embedded( struct x11drv_win_data *data ) DECLSPEC_HIDDEN;
extern void set_window_visual( struct x11drv_win_data *data, const XVisualInfo *vis ) DECLSPEC_HIDDEN;
extern void change_systray_owner( Display *display, Window systray_window ) DECLSPEC_HIDDEN;
extern void update_systray_balloon_position(void) DECLSPEC_HIDDEN;
......
......@@ -134,6 +134,7 @@ static const char * const atom_names[NB_XATOMS - FIRST_XATOM] =
"_NET_SUPPORTED",
"_NET_SYSTEM_TRAY_OPCODE",
"_NET_SYSTEM_TRAY_S0",
"_NET_SYSTEM_TRAY_VISUAL",
"_NET_WM_ICON",
"_NET_WM_MOVERESIZE",
"_NET_WM_NAME",
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment