This version is resynced against CVS HEAD, and now does a ShowWindow in
the right place (just after the embed notification not in some random WM
message).
This won't be merged so I'm sending it to wine-devel not wine-patches.
Getting it merged is blocking on either somebody giving me example code
for [un]marshaling an HICON into a block of memory or (best fix) images
being moved into the wineserver. This is on Ulrichs todo list but if
anybody wants to beat him to it, go ahead, it's still some time off yet.
thanks -mike
Index: dlls/x11drv/event.c
===================================================================
RCS file: /home/wine/wine/dlls/x11drv/event.c,v
retrieving revision 1.34
diff -u -p -r1.34 event.c
--- dlls/x11drv/event.c 19 Mar 2004 01:17:32 -0000 1.34
+++ dlls/x11drv/event.c 15 Jun 2004 16:12:08 -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
@@ -50,12 +51,17 @@
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 BOOL ximInComposeMode;
+extern Atom systray_selection;
+extern Window systray_window;
+
#define DndNotDnd -1 /* OffiX drag&drop */
#define DndUnknown 0
#define DndRawData 1
@@ -275,7 +281,7 @@ static void EVENT_ProcessEvent( XEvent *
if (!hWnd && event->type != PropertyNotify &&
event->type != MappingNotify && event->type != KeymapNotify)
- WARN( "Got event %s for unknown Window %08lx\n",
+ WARN( "Got event %s for unknown Window %08lx\n",
event_names[event->type], event->xany.window );
else if (event->type <= MappingNotify)
TRACE("Got event %s for hwnd/window %p/%lx, GetFocus()=%p\n",
@@ -1234,7 +1240,35 @@ static void EVENT_DropURLs( HWND hWnd, X
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]);
+ /* for now, do nothing. doing something useful here is blocked on XFIXES */
+ }
+ } 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]);
+
+ /* ensure the window is shown when docked. in future we may wish to dispatch these messages */
+ if (event->data.l[1] == 0) ShowWindow(hWnd, SW_SHOW);
+
+ } 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.77
diff -u -p -r1.77 window.c
--- dlls/x11drv/window.c 7 May 2004 00:41:32 -0000 1.77
+++ dlls/x11drv/window.c 15 Jun 2004 16:12:09 -0000
@@ -4,6 +4,7 @@
* Copyright 1993, 1994, 1995, 1996, 2001 Alexandre Julliard
* Copyright 1993 David Metcalfe
* Copyright 1995, 1996 Alex Korobka
+ * Copyright 2004 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 );
@@ -69,6 +72,7 @@ static const char * const atom_names[NB_
"WM_PROTOCOLS",
"WM_DELETE_WINDOW",
"WM_TAKE_FOCUS",
+ "MANAGER",
"KWM_DOCKWINDOW",
"DndProtocol",
"DndSelection",
@@ -77,6 +81,9 @@ static const char * const atom_names[NB_
"_NET_WM_PID",
"_NET_WM_PING",
"_NET_WM_NAME",
+ "_XEMBED_INFO",
+ "_XEMBED",
+ "_NET_SYSTEM_TRAY_OPCODE",
"_NET_WM_WINDOW_TYPE",
"_NET_WM_WINDOW_TYPE_UTILITY",
"XdndAware",
@@ -102,6 +109,14 @@ static const char * const atom_names[NB_
"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;
@@ -380,11 +395,59 @@ static void set_size_hints( Display *dis
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] = 1; /* embedder should map */
+ 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
@@ -434,7 +497,7 @@ void X11DRV_set_wm_hints( Display *displ
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),
@@ -744,10 +807,19 @@ void X11DRV_register_window( Display *di
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" ));
@@ -1134,6 +1206,13 @@ BOOL X11DRV_CreateWindow( HWND hwnd, CRE
newPos.right, newPos.bottom, swFlag );
}
+ /* 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/winpos.c
===================================================================
RCS file: /home/wine/wine/dlls/x11drv/winpos.c,v
retrieving revision 1.85
diff -u -p -r1.85 winpos.c
--- dlls/x11drv/winpos.c 14 Jun 2004 19:32:21 -0000 1.85
+++ dlls/x11drv/winpos.c 15 Jun 2004 16:12:09 -0000
@@ -1410,6 +1410,8 @@ void X11DRV_MapNotify( HWND hwnd, XMapEv
if (!(win = WIN_GetPtr( hwnd ))) return;
+ TRACE("hwnd=%p\n", hwnd);
+
if ((win->dwStyle & WS_VISIBLE) &&
(win->dwStyle & WS_MINIMIZE) &&
(win->dwExStyle & WS_EX_MANAGED))
Index: dlls/x11drv/x11drv.h
===================================================================
RCS file: /home/wine/wine/dlls/x11drv/x11drv.h,v
retrieving revision 1.29
diff -u -p -r1.29 x11drv.h
--- dlls/x11drv/x11drv.h 6 May 2004 23:40:30 -0000 1.29
+++ dlls/x11drv/x11drv.h 15 Jun 2004 16:12:09 -0000
@@ -408,6 +408,7 @@ enum x11drv_atoms
XATOM_WM_PROTOCOLS,
XATOM_WM_DELETE_WINDOW,
XATOM_WM_TAKE_FOCUS,
+ XATOM_MANAGER,
XATOM_KWM_DOCKWINDOW,
XATOM_DndProtocol,
XATOM_DndSelection,
@@ -416,6 +417,9 @@ enum x11drv_atoms
XATOM__NET_WM_PID,
XATOM__NET_WM_PING,
XATOM__NET_WM_NAME,
+ XATOM__XEMBED_INFO,
+ XATOM__XEMBED,
+ XATOM__NET_SYSTEM_TRAY_OPCODE,
XATOM__NET_WM_WINDOW_TYPE,
XATOM__NET_WM_WINDOW_TYPE_UTILITY,
XATOM_XdndAware,
Index: dlls/shell32/systray.c
===================================================================
RCS file: /home/wine/wine/dlls/shell32/systray.c,v
retrieving revision 1.26
diff -u -p -r1.26 systray.c
--- dlls/shell32/systray.c 27 Feb 2004 21:30:16 -0000 1.26
+++ dlls/shell32/systray.c 15 Jun 2004 16:12:09 -0000
@@ -1,11 +1,11 @@
/*
- * Systray
+ * System tray handling code (client side)
*
- * Copyright 1999 Kai Morich <[EMAIL PROTECTED]>
+ * Copyright 1999 Kai Morich <[EMAIL PROTECTED]>
+ * Copyright 2003 Mike Hearn <[EMAIL PROTECTED]>
*
- * Manage the systray window. That it actually appears in the docking
- * area of KDE is handled in dlls/x11drv/window.c,
- * X11DRV_set_wm_hints using KWM_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 @@ typedef struct SystrayItem {
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,27 @@ static LRESULT CALLBACK SYSTRAY_WndProc(
{
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);
+ TRACE("WM_PAINT for %p\n", hWnd);
+
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 +112,10 @@ static LRESULT CALLBACK SYSTRAY_WndProc(
ptrayItem = ptrayItem->nextTrayItem;
}
EndPaint(hWnd, &ps);
+ LeaveCriticalSection(&systray_lock);
}
break;
- case WM_MOUSEMOVE:
case WM_LBUTTONDOWN:
case WM_LBUTTONUP:
case WM_RBUTTONDOWN:
@@ -110,7 +125,8 @@ static LRESULT CALLBACK SYSTRAY_WndProc(
{
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 +141,17 @@ static LRESULT CALLBACK SYSTRAY_WndProc(
}
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 +165,10 @@ static LRESULT CALLBACK SYSTRAY_WndProc(
}
ptrayItem = ptrayItem->nextTrayItem;
}
+ LeaveCriticalSection(&systray_lock);
}
break;
-
+
default:
return (DefWindowProcA(hWnd, message, wParam, lParam));
}
@@ -169,7 +188,7 @@ BOOL SYSTRAY_RegisterClass(void)
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,32 +200,23 @@ BOOL SYSTRAY_RegisterClass(void)
}
-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,
+ rect.right, rect.bottom,
0, 0, 0, 0 );
if ( !ptrayItem->hWnd ) {
ERR( "CreateWindow(WineSystray) failed\n" );
@@ -222,34 +232,74 @@ BOOL SYSTRAY_ItemInit(SystrayItem *ptray
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);
+ 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)
{
- if(ptrayItem->notifyIcon.hIcon)
- DestroyIcon(ptrayItem->notifyIcon.hIcon);
+ EnterCriticalSection(&systray_lock);
+ if (ptrayItem->notifyIcon.hIcon) DestroyIcon(ptrayItem->notifyIcon.hIcon);
ptrayItem->notifyIcon.hIcon = CopyIcon(hIcon);
InvalidateRect(ptrayItem->hWnd, NULL, TRUE);
+ LeaveCriticalSection(&systray_lock);
}
@@ -257,9 +307,11 @@ void SYSTRAY_ItemSetTip(SystrayItem *ptr
{
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;
@@ -282,10 +334,15 @@ static BOOL SYSTRAY_Add(PNOTIFYICONDATAA
{
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. */
@@ -299,6 +356,7 @@ static BOOL SYSTRAY_Add(PNOTIFYICONDATAA
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;
@@ -309,8 +367,12 @@ static BOOL SYSTRAY_Modify(PNOTIFYICONDA
{
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)
@@ -323,6 +385,7 @@ static BOOL SYSTRAY_Modify(PNOTIFYICONDA
}
ptrayItem = ptrayItem->nextTrayItem;
}
+ LeaveCriticalSection(&systray_lock);
return FALSE; /* not found */
}
@@ -331,6 +394,9 @@ static BOOL SYSTRAY_Delete(PNOTIFYICONDA
{
SystrayItem **ptrayItem = &systray;
+ TRACE("%p\n", pnid);
+
+ EnterCriticalSection(&systray_lock);
while (*ptrayItem) {
if (SYSTRAY_ItemIsEqual(pnid, &(*ptrayItem)->notifyIcon)) {
SystrayItem *next = (*ptrayItem)->nextTrayItem;
@@ -340,10 +406,12 @@ static BOOL SYSTRAY_Delete(PNOTIFYICONDA
free(*ptrayItem);
*ptrayItem = next;
+ LeaveCriticalSection(&systray_lock);
return TRUE;
}
ptrayItem = &((*ptrayItem)->nextTrayItem);
}
+ LeaveCriticalSection(&systray_lock);
return FALSE; /* not found */
}