System tray integration
Mike Hearn
mike at theoretic.com
Sun Nov 30 10:16:54 CST 2003
Hi,
This patch updates my system tray patch to work with the new atom
interning code, fixes a few bugs and replaces the per-icon mutex with a
global one. The critical section handling should therefore be much less
broken now.
Yes, I know it should be in wineshell.exe but for now this will do, and
the code can always be moved later.
thanks -mike
ChangeLog:
Implement support for XEMBED based system trays
Index: dlls/shell32/systray.c
===================================================================
RCS file: /home/wine/wine/dlls/shell32/systray.c,v
retrieving revision 1.24
diff -u -r1.24 systray.c
--- dlls/shell32/systray.c 24 Oct 2003 04:23:37 -0000 1.24
+++ dlls/shell32/systray.c 30 Nov 2003 16:08:37 -0000
@@ -1,11 +1,11 @@
/*
- * Systray
+ * System tray handling code (client side)
*
- * Copyright 1999 Kai Morich <kai.morich at bigfoot.de>
+ * Copyright 1999 Kai Morich <kai.morich at bigfoot.de>
+ * Copyright 2003 Mike Hearn <mike at theoretic.com>
*
- * Manage the systray window. That it actually appears in the docking
- * area of KDE or GNOME is delegated to windows/x11drv/wnd.c,
- * X11DRV_WND_DockWindow.
+ * This code creates a window with the WS_EX_TRAYWINDOW style. The actual
+ * environment integration code is handled inside the X11 driver.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
@@ -42,7 +42,17 @@
#include "commctrl.h"
#include "wine/debug.h"
-WINE_DEFAULT_DEBUG_CHANNEL(shell);
+WINE_DEFAULT_DEBUG_CHANNEL(systray);
+
+static CRITICAL_SECTION systray_lock;
+static CRITICAL_SECTION_DEBUG critsect_debug =
+{
+ 0, 0, &systray_lock,
+ { &critsect_debug.ProcessLocksList, &critsect_debug.ProcessLocksList },
+ 0, 0, { 0, (DWORD)(__FILE__ ": system tray") }
+};
+static CRITICAL_SECTION systray_lock = { &critsect_debug, -1, 0, 0, 0, 0 };
+
typedef struct SystrayItem {
HWND hWnd;
@@ -51,12 +61,11 @@
struct SystrayItem *nextTrayItem;
} SystrayItem;
-static SystrayItem *systray=NULL;
-static int firstSystray=TRUE; /* defer creation of window class until first systray item is created */
+static SystrayItem *systray = NULL;
+static int firstSystray = TRUE; /* defer creation of window class until first systray item is created */
static BOOL SYSTRAY_Delete(PNOTIFYICONDATAA pnid);
-
#define ICON_SIZE GetSystemMetrics(SM_CXSMICON)
/* space around icon (forces icon to center of KDE systray area) */
#define ICON_BORDER 4
@@ -74,21 +83,26 @@
{
HDC hdc;
PAINTSTRUCT ps;
-
+ TRACE("hwnd=%p, msg=0x%x\n", hWnd, message);
switch (message) {
case WM_PAINT:
{
RECT rc;
SystrayItem *ptrayItem = systray;
-
+ int top;
+ EnterCriticalSection(&systray_lock);
+
while (ptrayItem) {
- if (ptrayItem->hWnd==hWnd) {
+ if (ptrayItem->hWnd == hWnd) {
if (ptrayItem->notifyIcon.hIcon) {
hdc = BeginPaint(hWnd, &ps);
GetClientRect(hWnd, &rc);
- if (!DrawIconEx(hdc, rc.left+ICON_BORDER, rc.top+ICON_BORDER, ptrayItem->notifyIcon.hIcon,
+ /* calculate top so we can deal with arbitrary sized trays */
+ top = ((rc.bottom-rc.top)/2) - ((ICON_SIZE)/2);
+ if (!DrawIconEx(hdc, (ICON_BORDER/2), top, ptrayItem->notifyIcon.hIcon,
ICON_SIZE, ICON_SIZE, 0, 0, DI_DEFAULTSIZE|DI_NORMAL)) {
ERR("Paint(SystrayWindow %p) failed -> removing SystrayItem %p\n", hWnd, ptrayItem);
+ LeaveCriticalSection(&systray_lock);
SYSTRAY_Delete(&ptrayItem->notifyIcon);
}
}
@@ -97,10 +111,10 @@
ptrayItem = ptrayItem->nextTrayItem;
}
EndPaint(hWnd, &ps);
+ LeaveCriticalSection(&systray_lock);
}
break;
- case WM_MOUSEMOVE:
case WM_LBUTTONDOWN:
case WM_LBUTTONUP:
case WM_RBUTTONDOWN:
@@ -110,7 +124,8 @@
{
MSG msg;
SystrayItem *ptrayItem = systray;
-
+ /* relay the event to the tooltip */
+ EnterCriticalSection(&systray_lock);
while ( ptrayItem ) {
if (ptrayItem->hWnd == hWnd) {
msg.hwnd=hWnd;
@@ -125,15 +140,17 @@
}
ptrayItem = ptrayItem->nextTrayItem;
}
+ LeaveCriticalSection(&systray_lock);
}
- /* fall through */
+ /* fall through, so the message is sent to the callback as well */
case WM_LBUTTONDBLCLK:
case WM_RBUTTONDBLCLK:
case WM_MBUTTONDBLCLK:
{
SystrayItem *ptrayItem = systray;
-
+ /* iterate over the currently active tray items */
+ EnterCriticalSection(&systray_lock);
while (ptrayItem) {
if (ptrayItem->hWnd == hWnd) {
if (ptrayItem->notifyIcon.hWnd && ptrayItem->notifyIcon.uCallbackMessage) {
@@ -147,9 +164,18 @@
}
ptrayItem = ptrayItem->nextTrayItem;
}
+ LeaveCriticalSection(&systray_lock);
}
break;
+ case WM_NOTIFYFORMAT:
+ {
+ TRACE("Received WM_NOTIFYFORMAT, showing the tray window\n");
+ ShowWindow(hWnd, SW_SHOW);
+ return (DefWindowProcA(hWnd, message, wParam, lParam));
+ }
+
+
default:
return (DefWindowProcA(hWnd, message, wParam, lParam));
}
@@ -169,7 +195,7 @@
wc.hInstance = 0;
wc.hIcon = 0;
wc.hCursor = LoadCursorA(0, (LPSTR)IDC_ARROW);
- wc.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1);
+ wc.hbrBackground = (HBRUSH) COLOR_WINDOW;
wc.lpszMenuName = NULL;
wc.lpszClassName = "WineSystray";
@@ -181,30 +207,21 @@
}
-BOOL SYSTRAY_ItemInit(SystrayItem *ptrayItem)
-{
+DWORD WINAPI SYSTRAY_ThreadProc(LPVOID p1) {
+ SystrayItem *ptrayItem = (SystrayItem *)p1;
+ MSG msg;
RECT rect;
-
- /* Register the class if this is our first tray item. */
- if ( firstSystray ) {
- firstSystray = FALSE;
- if ( !SYSTRAY_RegisterClass() ) {
- ERR( "RegisterClass(WineSystray) failed\n" );
- return FALSE;
- }
- }
-
+
/* Initialize the window size. */
rect.left = 0;
rect.top = 0;
rect.right = ICON_SIZE+2*ICON_BORDER;
rect.bottom = ICON_SIZE+2*ICON_BORDER;
- ZeroMemory( ptrayItem, sizeof(SystrayItem) );
/* Create tray window for icon. */
ptrayItem->hWnd = CreateWindowExA( WS_EX_TRAYWINDOW,
- "WineSystray", "Wine-Systray",
- WS_VISIBLE,
+ "WineSystray", "Windows System Tray",
+ 0,
CW_USEDEFAULT, CW_USEDEFAULT,
rect.right-rect.left, rect.bottom-rect.top,
0, 0, 0, 0 );
@@ -222,31 +239,73 @@
ERR( "CreateWindow(TOOLTIP) failed\n" );
return FALSE;
}
+
+ /* Enter the message loop */
+ while (GetMessageA (&msg, 0, 0, 0) > 0) {
+ TranslateMessage (&msg);
+ DispatchMessageA (&msg);
+ }
+
+ TRACE("Shutting down system tray thread\n");
+ if(ptrayItem->notifyIcon.hIcon)
+ DestroyIcon(ptrayItem->notifyIcon.hIcon);
+ if(ptrayItem->hWndToolTip)
+ DestroyWindow(ptrayItem->hWndToolTip);
+
+ return 0;
+}
+
+BOOL SYSTRAY_ItemInit(SystrayItem *ptrayItem)
+{
+ DWORD threadID;
+
+ /* Register the class if this is our first tray item. */
+ EnterCriticalSection(&systray_lock);
+ if ( firstSystray ) {
+ firstSystray = FALSE;
+ if ( !SYSTRAY_RegisterClass() ) {
+ ERR( "RegisterClass(WineSystray) failed\n" );
+ LeaveCriticalSection(&systray_lock);
+ return FALSE;
+ }
+ }
+ LeaveCriticalSection(&systray_lock);
+
+ ZeroMemory( ptrayItem, sizeof(SystrayItem) );
+
+ /* We need to run the system tray window in a separate thread, as otherwise if the originating thread
+ stops processing messages, the tray window will hang. If another part of the application then does
+ for instance a FindWindow call, this can deadlock the application. */
+ if (!CreateThread(NULL, 0, SYSTRAY_ThreadProc, (LPVOID) ptrayItem, 0, &threadID)) {
+ ERR("Could not create system tray item thread\n");
+ return FALSE;
+ }
return TRUE;
}
static void SYSTRAY_ItemTerm(SystrayItem *ptrayItem)
{
- if(ptrayItem->notifyIcon.hIcon)
- DestroyIcon(ptrayItem->notifyIcon.hIcon);
- if(ptrayItem->hWndToolTip)
- DestroyWindow(ptrayItem->hWndToolTip);
- if(ptrayItem->hWnd)
- DestroyWindow(ptrayItem->hWnd);
+ /* MSDN says we shouldn't do this, but I can't see another way to make GetMessage() return zero */
+ PostMessageA(ptrayItem->hWnd, WM_QUIT, 0, 0);
return;
}
void SYSTRAY_ItemSetMessage(SystrayItem *ptrayItem, UINT uCallbackMessage)
{
+ EnterCriticalSection(&systray_lock);
ptrayItem->notifyIcon.uCallbackMessage = uCallbackMessage;
+ LeaveCriticalSection(&systray_lock);
}
void SYSTRAY_ItemSetIcon(SystrayItem *ptrayItem, HICON hIcon)
{
+ EnterCriticalSection(&systray_lock);
ptrayItem->notifyIcon.hIcon = CopyIcon(hIcon);
+ LeaveCriticalSection(&systray_lock);
+
InvalidateRect(ptrayItem->hWnd, NULL, TRUE);
}
@@ -255,9 +314,11 @@
{
TTTOOLINFOA ti;
- strncpy(ptrayItem->notifyIcon.szTip, szTip, sizeof(ptrayItem->notifyIcon.szTip));
+ EnterCriticalSection(&systray_lock);
+ strncpy(ptrayItem->notifyIcon.szTip, szTip, sizeof(ptrayItem->notifyIcon.szTip));
ptrayItem->notifyIcon.szTip[sizeof(ptrayItem->notifyIcon.szTip)-1]=0;
-
+ LeaveCriticalSection(&systray_lock);
+
ti.cbSize = sizeof(TTTOOLINFOA);
ti.uFlags = 0;
ti.hwnd = ptrayItem->hWnd;
@@ -280,10 +341,15 @@
{
SystrayItem **ptrayItem = &systray;
+ TRACE("%p\n", pnid);
+
+ EnterCriticalSection(&systray_lock);
/* Find last element. */
while( *ptrayItem ) {
- if ( SYSTRAY_ItemIsEqual(pnid, &(*ptrayItem)->notifyIcon) )
+ if ( SYSTRAY_ItemIsEqual(pnid, &(*ptrayItem)->notifyIcon) ) {
+ LeaveCriticalSection(&systray_lock);
return FALSE;
+ }
ptrayItem = &((*ptrayItem)->nextTrayItem);
}
/* Allocate SystrayItem for element and add to end of list. */
@@ -297,6 +363,7 @@
SYSTRAY_ItemSetMessage(*ptrayItem, (pnid->uFlags&NIF_MESSAGE)?pnid->uCallbackMessage:0);
SYSTRAY_ItemSetTip (*ptrayItem, (pnid->uFlags&NIF_TIP) ?pnid->szTip :"", FALSE);
+ LeaveCriticalSection(&systray_lock);
TRACE("%p: %p %s\n", (*ptrayItem), (*ptrayItem)->notifyIcon.hWnd,
(*ptrayItem)->notifyIcon.szTip);
return TRUE;
@@ -307,8 +374,12 @@
{
SystrayItem *ptrayItem = systray;
+ TRACE("%p\n", pnid);
+
+ EnterCriticalSection(&systray_lock);
while ( ptrayItem ) {
if ( SYSTRAY_ItemIsEqual(pnid, &ptrayItem->notifyIcon) ) {
+ LeaveCriticalSection(&systray_lock);
if (pnid->uFlags & NIF_ICON)
SYSTRAY_ItemSetIcon(ptrayItem, pnid->hIcon);
if (pnid->uFlags & NIF_MESSAGE)
@@ -321,6 +392,7 @@
}
ptrayItem = ptrayItem->nextTrayItem;
}
+ LeaveCriticalSection(&systray_lock);
return FALSE; /* not found */
}
@@ -329,6 +401,9 @@
{
SystrayItem **ptrayItem = &systray;
+ TRACE("%p\n", pnid);
+
+ EnterCriticalSection(&systray_lock);
while (*ptrayItem) {
if (SYSTRAY_ItemIsEqual(pnid, &(*ptrayItem)->notifyIcon)) {
SystrayItem *next = (*ptrayItem)->nextTrayItem;
@@ -338,10 +413,12 @@
free(*ptrayItem);
*ptrayItem = next;
+ LeaveCriticalSection(&systray_lock);
return TRUE;
}
ptrayItem = &((*ptrayItem)->nextTrayItem);
}
+ LeaveCriticalSection(&systray_lock);
return FALSE; /* not found */
}
Index: dlls/x11drv/event.c
===================================================================
RCS file: /home/wine/wine/dlls/x11drv/event.c,v
retrieving revision 1.29
diff -u -r1.29 event.c
--- dlls/x11drv/event.c 21 Nov 2003 21:48:36 -0000 1.29
+++ dlls/x11drv/event.c 30 Nov 2003 16:08:37 -0000
@@ -3,6 +3,7 @@
*
* Copyright 1993 Alexandre Julliard
* 1999 Noel Borthwick
+ * 2003 Mike Hearn
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
@@ -51,10 +52,15 @@
WINE_DEFAULT_DEBUG_CHANNEL(event);
WINE_DECLARE_DEBUG_CHANNEL(clipboard);
+WINE_DECLARE_DEBUG_CHANNEL(systray);
/* X context to associate a hwnd to an X window */
extern XContext winContext;
+extern Atom systray_selection;
+extern Window systray_window;
+
+
#define DndNotDnd -1 /* OffiX drag&drop */
#define DndUnknown 0
#define DndRawData 1
@@ -1213,7 +1219,47 @@
static void EVENT_ClientMessage( HWND hWnd, XClientMessageEvent *event )
{
if (event->message_type != None && event->format == 32) {
- if (event->message_type == x11drv_atom(WM_PROTOCOLS))
+ if (event->message_type == x11drv_atom(MANAGER)) {
+ if (event->data.l[1] == systray_selection) {
+ TRACE_(systray)("New NETWM systray manager detected, id=%ld\n", event->data.l[2]);
+ /* NOTE: It turns out that the ability to detect when a new tray applet joins the
+ * desktop is not as helpful as you might think. In order to do something useful with it,
+ * we would need to be able to "store" icons unmapped as children of the root window while
+ * no tray applet is available.
+ *
+ * The basic problem is that tray icons are always destroyed when the applet is removed.
+ * This is apparently an issue with X itself, which the upcoming XFIXES extension should hopefully
+ * address. The EggTrayIcon code which will be soon moving into GTK+ doesn't attempt to handle this
+ * situation, so for now neither do we.
+ *
+ * This is theoretically fixable in Wine with enough work, we just have to modify the code in
+ * shell32/systray.c to save the image and recreate the window on demand. Exactly how the
+ * communication between the x11drv and shell32 takes place is left as an excercise for the
+ * reader.
+ * -mike (3rd August 2003)
+ */
+ }
+ } else if (event->message_type == x11drv_atom(_XEMBED)) {
+ char* opcode;
+ switch (event->data.l[1]) {
+ case 0: opcode = "XEMBED_EMBEDDED_NOTIFY"; break;
+ case 1: opcode = "XEMBED_WINDOW_ACTIVATE"; break;
+ case 2: opcode = "XEMBED_WINDOW_DEACTIVATE"; break;
+ case 3: opcode = "XEMBED_REQUEST_FOCUS"; break;
+ case 4: opcode = "XEMBED_FOCUS_IN"; break;
+ case 5: opcode = "XEMBED_FOCUS_OUT"; break;
+ case 6: opcode = "XEMBED_FOCUS_NEXT"; break;
+ case 7: opcode = "XEMEBD_FOCUS_PREV"; break;
+ case 10: opcode = "XEMBED_MODALITY_ON"; break;
+ case 11: opcode = "XEMBED_MODALITY_OFF"; break;
+ case 12: opcode = "XEMBED_REGISTER_ACCELERATOR"; break;
+ case 13: opcode = "XEMBED_UNREGISTER_ACCELERATOR"; break;
+ case 14: opcode = "XEMBED_ACTIVATE_ACCELERATOR"; break;
+ default: opcode = "[Unknown opcode]"; break;
+ }
+ TRACE_(systray)("XEmbed message, opcode is %s : %ld\n", opcode, event->data.l[1]);
+ /* we currently don't handle these messages */
+ } else if (event->message_type == x11drv_atom(WM_PROTOCOLS))
handle_wm_protocols_message( hWnd, event );
else if (event->message_type == x11drv_atom(DndProtocol))
{
Index: dlls/x11drv/window.c
===================================================================
RCS file: /home/wine/wine/dlls/x11drv/window.c,v
retrieving revision 1.65
diff -u -r1.65 window.c
--- dlls/x11drv/window.c 21 Nov 2003 21:48:36 -0000 1.65
+++ dlls/x11drv/window.c 30 Nov 2003 16:08:37 -0000
@@ -4,6 +4,7 @@
* Copyright 1993, 1994, 1995, 1996, 2001 Alexandre Julliard
* Copyright 1993 David Metcalfe
* Copyright 1995, 1996 Alex Korobka
+ * Copyright 2003 Mike Hearn
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
@@ -24,6 +25,7 @@
#include <stdarg.h>
#include <stdlib.h>
+#include <stdio.h>
#ifdef HAVE_UNISTD_H
# include <unistd.h>
#endif
@@ -46,6 +48,7 @@
#include "mwm.h"
WINE_DEFAULT_DEBUG_CHANNEL(x11drv);
+WINE_DECLARE_DEBUG_CHANNEL(systray);
extern Pixmap X11DRV_BITMAP_Pixmap( HBITMAP );
@@ -73,6 +76,7 @@
"WM_PROTOCOLS",
"WM_DELETE_WINDOW",
"WM_TAKE_FOCUS",
+ "MANAGER",
"KWM_DOCKWINDOW",
"DndProtocol",
"DndSelection",
@@ -81,6 +85,9 @@
"_NET_WM_PID",
"_NET_WM_PING",
"_NET_WM_NAME",
+ "_XEMBED_INFO",
+ "_XEMBED",
+ "_NET_SYSTEM_TRAY_OPCODE",
"XdndAware",
"XdndEnter",
"XdndPosition",
@@ -103,6 +110,14 @@
"text/richtext"
};
+/* for XDG systray icons */
+Atom systray_selection;
+Window systray_window;
+#define SYSTEM_TRAY_REQUEST_DOCK 0
+#define SYSTEM_TRAY_BEGIN_MESSAGE 1
+#define SYSTEM_TRAY_CANCEL_MESSAGE 2
+
+
static LPCSTR whole_window_atom;
static LPCSTR client_window_atom;
static LPCSTR icon_window_atom;
@@ -354,11 +369,60 @@
size_hints->min_height = size_hints->max_height;
size_hints->flags |= PMinSize | PMaxSize;
}
+ if (win->dwExStyle & WS_EX_TRAYWINDOW) {
+ /* force the window to be the correct width */
+ size_hints->min_width = GetSystemMetrics(SM_CXSMICON) + 5; /* give some padding to make icons not bunched up */
+ }
+
XSetWMNormalHints( display, data->whole_window, size_hints );
XFree( size_hints );
}
}
+/***********************************************************************
+ * X11DRV_systray_dock_window
+ *
+ * Docks the given X window with the NETWM system tray.
+ */
+BOOL CALLBACK X11DRV_systray_dock_window( HWND hwnd, Display *display ) {
+ WND* win = WIN_GetPtr((HWND)hwnd);
+ struct x11drv_win_data *data = win->pDriverData;
+ XEvent ev;
+ unsigned long info[2];
+ LONG exstyle;
+
+ /* is the window a tray window? */
+ if (IsWindowUnicode(hwnd))
+ exstyle = GetWindowLongW(hwnd, GWL_EXSTYLE);
+ else
+ exstyle = GetWindowLongA(hwnd, GWL_EXSTYLE);
+ if ( !(exstyle & WS_EX_TRAYWINDOW) ) return TRUE;
+
+ TRACE_(systray)("Docking tray icon 0x%x\n", (int)hwnd);
+
+
+ /* set XEMBED protocol data on the window */
+ info[0] = 0; /* protocol version */
+ info[1] = 0; /* mapped = true */
+ XChangeProperty(display, data->whole_window, x11drv_atom(_XEMBED_INFO), x11drv_atom(_XEMBED_INFO), 32, PropModeReplace, (unsigned char*)info, 2);
+
+ /* send the docking request message */
+ memset(&ev, 0, sizeof(ev));
+ 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] = data->whole_window;
+ XSendEvent(display, systray_window, False, NoEventMask, &ev);
+ XSync(display, False);
+
+ WIN_ReleasePtr(win);
+ return TRUE;
+}
+
+
/***********************************************************************
* X11DRV_set_wm_hints
@@ -408,7 +472,7 @@
set_size_hints( display, win );
/* systray properties (KDE only for now) */
- if (win->dwExStyle & WS_EX_TRAYWINDOW)
+ if ((win->dwExStyle & WS_EX_TRAYWINDOW) && (systray_window == None))
{
int val = 1;
XChangeProperty( display, data->whole_window, x11drv_atom(KWM_DOCKWINDOW),
@@ -709,10 +773,19 @@
static void create_desktop( Display *display, WND *wndPtr )
{
X11DRV_WND_DATA *data = wndPtr->pDriverData;
-
+ char *systray_buffer;
+
wine_tsx11_lock();
winContext = XUniqueContext();
XInternAtoms( display, (char **)atom_names, NB_XATOMS - FIRST_XATOM, False, X11DRV_Atoms );
+
+ /* we can't intern this with the rest as it depends on the screen we are connecting to */
+ systray_buffer = HeapAlloc(GetProcessHeap(), 0, sizeof(char)*20);
+ sprintf(systray_buffer, "_NET_SYSTEM_TRAY_S%d", DefaultScreen(display));
+ systray_selection = XInternAtom(display, systray_buffer, False);
+ HeapFree(GetProcessHeap(), 0, systray_buffer);
+
+
wine_tsx11_unlock();
whole_window_atom = MAKEINTATOMA( GlobalAddAtomA( "__wine_x11_whole_window" ));
@@ -1109,6 +1182,14 @@
* we do a proper ShowWindow later on */
if (wndPtr->dwStyle & WS_VISIBLE) cs->style |= WS_VISIBLE;
+ /* if it's a tray window, dock it */
+ if (wndPtr->dwExStyle & WS_EX_TRAYWINDOW) {
+ /* get the tray window if present */
+ systray_window = XGetSelectionOwner(display, systray_selection);
+ if (systray_window != None)
+ X11DRV_systray_dock_window(hwnd, display);
+ }
+
WIN_ReleaseWndPtr( wndPtr );
return TRUE;
Index: dlls/x11drv/x11drv.h
===================================================================
RCS file: /home/wine/wine/dlls/x11drv/x11drv.h,v
retrieving revision 1.11
diff -u -r1.11 x11drv.h
--- dlls/x11drv/x11drv.h 25 Nov 2003 03:27:38 -0000 1.11
+++ dlls/x11drv/x11drv.h 30 Nov 2003 16:08:37 -0000
@@ -387,6 +387,7 @@
XATOM_WM_PROTOCOLS,
XATOM_WM_DELETE_WINDOW,
XATOM_WM_TAKE_FOCUS,
+ XATOM_MANAGER,
XATOM_KWM_DOCKWINDOW,
XATOM_DndProtocol,
XATOM_DndSelection,
@@ -395,6 +396,9 @@
XATOM__NET_WM_PID,
XATOM__NET_WM_PING,
XATOM__NET_WM_NAME,
+ XATOM__XEMBED_INFO,
+ XATOM__XEMBED,
+ XATOM__NET_SYSTEM_TRAY_OPCODE,
XATOM_XdndAware,
XATOM_XdndEnter,
XATOM_XdndPosition,
More information about the wine-patches
mailing list