Of course, the fact that it doesn't seem to build anymore might have something to do with that. Not sure what happened there..... This one hopefully works.... On Thu, 2003-08-21 at 15:20, Mike Hearn wrote: > [ this version of the patch was dropped, so bumping it to the top of the queue again ] > > Last time I submitted this, it was dropped because of the non-thread > safe global array. Doing some more work on this last night, I realised > it was pointless anyway, as the tray applet will destroy any windows > when it's deleted (ie if you remove it then readd it, we'd have to > reconstruct any tray windows). I talked to andersca - he said that the > EggTrayIcon code doesn't deal with this situation either, and that the > upcoming XFIXES extension would let us deal with that scenario more > intelligently. > > Therefore, I removed the relevant code, as it was unlikely to work > properly without a lot more work. > > ChangeLog: > Implement support for XEMBED system tray areas
Index: dlls/shell32/systray.c =================================================================== RCS file: /home/wine/wine/dlls/shell32/systray.c,v retrieving revision 1.20 diff -u -r1.20 systray.c --- dlls/shell32/systray.c 24 Nov 2002 22:16:29 -0000 1.20 +++ dlls/shell32/systray.c 21 Aug 2003 16:39:29 -0000 @@ -1,11 +1,11 @@ /* - * Systray + * System tray handling code (client side) * - * Copyright 1999 Kai Morich <kai.morich@bigfoot.de> + * Copyright 1999 Kai Morich <kai.morich@bigfoot.de> + * Copyright 2003 Mike Hearn <mike@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 @@ -37,21 +37,21 @@ #include "commctrl.h" #include "wine/debug.h" -WINE_DEFAULT_DEBUG_CHANNEL(shell); +WINE_DEFAULT_DEBUG_CHANNEL(systray); typedef struct SystrayItem { HWND hWnd; HWND hWndToolTip; NOTIFYICONDATAA notifyIcon; + CRITICAL_SECTION lock; 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 @@ -69,21 +69,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(&ptrayItem->lock); + while (ptrayItem) { 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(&ptrayItem->lock); SYSTRAY_Delete(&ptrayItem->notifyIcon); } } @@ -92,10 +97,10 @@ ptrayItem = ptrayItem->nextTrayItem; } EndPaint(hWnd, &ps); + LeaveCriticalSection(&ptrayItem->lock); } break; - case WM_MOUSEMOVE: case WM_LBUTTONDOWN: case WM_LBUTTONUP: case WM_RBUTTONDOWN: @@ -105,7 +110,7 @@ { MSG msg; SystrayItem *ptrayItem = systray; - + /* relay the event to the tooltip */ while ( ptrayItem ) { if (ptrayItem->hWnd == hWnd) { msg.hwnd=hWnd; @@ -121,14 +126,14 @@ ptrayItem = ptrayItem->nextTrayItem; } } - /* 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 */ while (ptrayItem) { if (ptrayItem->hWnd == hWnd) { if (ptrayItem->notifyIcon.hWnd && ptrayItem->notifyIcon.uCallbackMessage) { @@ -145,6 +150,14 @@ } 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)); } @@ -176,30 +189,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, + 0, CW_USEDEFAULT, CW_USEDEFAULT, rect.right-rect.left, rect.bottom-rect.top, 0, 0, 0, 0 ); @@ -217,31 +221,72 @@ 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. */ + if ( firstSystray ) { + firstSystray = FALSE; + if ( !SYSTRAY_RegisterClass() ) { + ERR( "RegisterClass(WineSystray) failed\n" ); + return FALSE; + } + } + + 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. */ + InitializeCriticalSection(&ptrayItem->lock); + 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); + DeleteCriticalSection(&ptrayItem->lock); return; } void SYSTRAY_ItemSetMessage(SystrayItem *ptrayItem, UINT uCallbackMessage) { + EnterCriticalSection(&ptrayItem->lock); ptrayItem->notifyIcon.uCallbackMessage = uCallbackMessage; + LeaveCriticalSection(&ptrayItem->lock); } void SYSTRAY_ItemSetIcon(SystrayItem *ptrayItem, HICON hIcon) { + EnterCriticalSection(&ptrayItem->lock); ptrayItem->notifyIcon.hIcon = CopyIcon(hIcon); + LeaveCriticalSection(&ptrayItem->lock); + InvalidateRect(ptrayItem->hWnd, NULL, TRUE); } @@ -250,9 +295,11 @@ { TTTOOLINFOA ti; - strncpy(ptrayItem->notifyIcon.szTip, szTip, sizeof(ptrayItem->notifyIcon.szTip)); + EnterCriticalSection(&ptrayItem->lock); + strncpy(ptrayItem->notifyIcon.szTip, szTip, sizeof(ptrayItem->notifyIcon.szTip)); ptrayItem->notifyIcon.szTip[sizeof(ptrayItem->notifyIcon.szTip)-1]=0; - + LeaveCriticalSection(&ptrayItem->lock); + ti.cbSize = sizeof(TTTOOLINFOA); ti.uFlags = 0; ti.hwnd = ptrayItem->hWnd; Index: dlls/x11drv/window.c =================================================================== RCS file: /home/wine/wine/dlls/x11drv/window.c,v retrieving revision 1.55 diff -u -r1.55 window.c --- dlls/x11drv/window.c 9 Jul 2003 04:22:57 -0000 1.55 +++ dlls/x11drv/window.c 21 Aug 2003 16:39:36 -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 <stdlib.h> #include <unistd.h> +#include <stdio.h> #include "ts_xlib.h" #include <X11/Xresource.h> @@ -42,6 +44,7 @@ #include "mwm.h" WINE_DEFAULT_DEBUG_CHANNEL(x11drv); +WINE_DECLARE_DEBUG_CHANNEL(systray); extern Pixmap X11DRV_BITMAP_Pixmap( HBITMAP ); @@ -55,6 +58,7 @@ Atom wmProtocols = None; Atom wmDeleteWindow = None; Atom wmTakeFocus = None; +Atom wmManager = None; Atom dndProtocol = None; Atom dndSelection = None; Atom wmChangeState = None; @@ -62,12 +66,23 @@ Atom kwmDockWindow = None; Atom netwmPid = None; Atom netwmPing = None; +Atom netSysTraySelection = None; +Atom netSysTrayOpcode = None; +Atom xembedInfo = None; +Atom xembed = None; Atom _kde_net_wm_system_tray_window_for = None; /* KDE 2 Final */ +Window systrayWindow; + static LPCSTR whole_window_atom; static LPCSTR client_window_atom; static LPCSTR icon_window_atom; +#define SYSTEM_TRAY_REQUEST_DOCK 0 +#define SYSTEM_TRAY_BEGIN_MESSAGE 1 +#define SYSTEM_TRAY_CANCEL_MESSAGE 2 + + /*********************************************************************** * is_window_managed * @@ -315,11 +330,59 @@ 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); + wine_tsx11_lock(); + + /* set XEMBED protocol data on the window */ + info[0] = 0; /* protocol version */ + info[1] = 0; /* mapped = true */ + XChangeProperty(display, data->whole_window, xembedInfo, xembedInfo, 32, PropModeReplace, (unsigned char*)info, 2); + + /* send the docking request message */ + memset(&ev, 0, sizeof(ev)); + ev.xclient.type = ClientMessage; + ev.xclient.window = systrayWindow; + ev.xclient.message_type = netSysTrayOpcode; + 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, systrayWindow, False, NoEventMask, &ev); + XSync(display, False); + wine_tsx11_unlock(); + + WIN_ReleasePtr(win); + return TRUE; +} + /*********************************************************************** * X11DRV_set_wm_hints @@ -365,16 +428,19 @@ /* size hints */ set_size_hints( display, win ); - /* systray properties (KDE only for now) */ + /* systray properties */ if (win->dwExStyle & WS_EX_TRAYWINDOW) { int val = 1; - if (kwmDockWindow != None) + + if (systrayWindow == None) { + if (kwmDockWindow != None) XChangeProperty( display, data->whole_window, kwmDockWindow, kwmDockWindow, 32, PropModeReplace, (char*)&val, 1 ); - if (_kde_net_wm_system_tray_window_for != None) + if (_kde_net_wm_system_tray_window_for != None) XChangeProperty( display, data->whole_window, _kde_net_wm_system_tray_window_for, XA_WINDOW, 32, PropModeReplace, (char*)&data->whole_window, 1 ); + } } /* set the WM_CLIENT_MACHINE and WM_LOCALE_NAME properties */ @@ -403,7 +469,7 @@ if (win->dwStyle & WS_SYSMENU) mwm_hints.decorations |= MWM_DECOR_MENU; if (win->dwStyle & WS_MINIMIZEBOX) mwm_hints.decorations |= MWM_DECOR_MINIMIZE; if (win->dwStyle & WS_MAXIMIZEBOX) mwm_hints.decorations |= MWM_DECOR_MAXIMIZE; - + XChangeProperty( display, data->whole_window, mwmHints, mwmHints, 32, PropModeReplace, (char*)&mwm_hints, sizeof(mwm_hints)/sizeof(long) ); } @@ -542,6 +608,7 @@ /* should use stack_mode Below but most window managers don't get it right */ /* so move it above the next one in Z order */ HWND next = GetWindow( win->hwndSelf, GW_HWNDNEXT ); + while (next && !(GetWindowLongW( next, GWL_STYLE ) & WS_VISIBLE)) next = GetWindow( next, GW_HWNDNEXT ); if (next) @@ -651,7 +718,8 @@ static void create_desktop( Display *display, WND *wndPtr ) { X11DRV_WND_DATA *data = wndPtr->pDriverData; - + char *buffer; + wine_tsx11_lock(); winContext = XUniqueContext(); wmProtocols = XInternAtom( display, "WM_PROTOCOLS", False ); @@ -665,6 +733,18 @@ _kde_net_wm_system_tray_window_for = XInternAtom( display, "_KDE_NET_WM_SYSTEM_TRAY_WINDOW_FOR", False ); netwmPid = XInternAtom( display, "_NET_WM_PID", False ); netwmPing = XInternAtom( display, "_NET_WM_PING", False ); + xembedInfo = XInternAtom( display, "_XEMBED_INFO", False ); + xembed = XInternAtom( display, "_XEMBED", False ); + systrayWindow = None; + + /* get system tray atoms */ + buffer = malloc(sizeof(char)*20); + sprintf(buffer, "_NET_SYSTEM_TRAY_S%d", DefaultScreen(display)); + netSysTraySelection = XInternAtom(display, buffer, False); + free(buffer); + netSysTrayOpcode = XInternAtom(display, "_NET_SYSTEM_TRAY_OPCODE", False); + wmManager = XInternAtom(display, "MANAGER", False); + wine_tsx11_unlock(); whole_window_atom = MAKEINTATOMA( GlobalAddAtomA( "__wine_x11_whole_window" )); @@ -679,6 +759,8 @@ SetPropA( wndPtr->hwndSelf, "__wine_x11_visual_id", (HANDLE)XVisualIDFromVisual(visual) ); if (root_window != DefaultRootWindow(display)) X11DRV_create_desktop_thread(); + /* notify us of manager events, so we can monitor for system tray managers */ + if (root_window == DefaultRootWindow(display)) XSelectInput(display, root_window, StructureNotifyMask); } @@ -949,7 +1031,7 @@ } /* Send the WM_GETMINMAXINFO message and fix the size if needed */ - if ((cs->style & WS_THICKFRAME) || !(cs->style & (WS_POPUP | WS_CHILD))) + if (((cs->style & WS_THICKFRAME) || !(cs->style & (WS_POPUP | WS_CHILD))) && !(cs->dwExStyle & WS_EX_TRAYWINDOW)) { POINT maxSize, maxPos, minTrack, maxTrack; @@ -1044,7 +1126,7 @@ } /* Show the window, maximizing or minimizing if needed */ - + if (wndPtr->dwStyle & (WS_MINIMIZE | WS_MAXIMIZE)) { extern UINT WINPOS_MinMaximize( HWND hwnd, UINT cmd, LPRECT rect ); /*FIXME*/ @@ -1064,6 +1146,13 @@ * 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 */ + systrayWindow = XGetSelectionOwner(display, netSysTraySelection); + if (systrayWindow != None) + X11DRV_systray_dock_window(hwnd, display); + } WIN_ReleaseWndPtr( wndPtr ); return TRUE; @@ -1231,8 +1320,9 @@ /* we must not use CurrentTime (ICCCM), so try to use last message time instead */ /* FIXME: this is not entirely correct */ + /* NOTE - not using CurrentTime here causes focus problems with some fullscreen apps */ XSetInputFocus( display, win, RevertToParent, - /*CurrentTime*/ GetMessageTime() + X11DRV_server_startticks ); + CurrentTime /* GetMessageTime() + X11DRV_server_startticks */ ); if (X11DRV_PALETTE_PaletteFlags & X11DRV_PALETTE_PRIVATE) XInstallColormap( display, X11DRV_PALETTE_PaletteXColormap ); } Index: dlls/x11drv/event.c =================================================================== RCS file: /home/wine/wine/dlls/x11drv/event.c,v retrieving revision 1.22 diff -u -r1.22 event.c --- dlls/x11drv/event.c 8 Jul 2003 21:02:51 -0000 1.22 +++ dlls/x11drv/event.c 21 Aug 2003 16:39:41 -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 @@ -34,6 +35,7 @@ #include <assert.h> #include <string.h> +#include <stdio.h> #include "wine/winuser16.h" #include "shlobj.h" /* DROPFILES */ @@ -47,6 +49,7 @@ #include "wine/debug.h" WINE_DEFAULT_DEBUG_CHANNEL(event); +WINE_DECLARE_DEBUG_CHANNEL(systray); WINE_DECLARE_DEBUG_CHANNEL(clipboard); /* X context to associate a hwnd to an X window */ @@ -54,9 +57,14 @@ extern Atom wmProtocols; extern Atom wmDeleteWindow; +extern Atom wmManager; extern Atom dndProtocol; extern Atom dndSelection; extern Atom netwmPing; +extern Atom netSysTraySelection; +extern Atom xembed; + +extern Window systrayWindow; #define DndNotDnd -1 /* OffiX drag&drop */ #define DndUnknown 0 @@ -106,6 +114,7 @@ extern void X11DRV_UnmapNotify( HWND hwnd, XUnmapEvent *event ); extern void X11DRV_ConfigureNotify( HWND hwnd, XConfigureEvent *event ); extern void X11DRV_MappingNotify( XMappingEvent *event ); +extern void X11DRV_systray_dock_all( Display* display ); #ifdef HAVE_LIBXXF86DGA2 static int DGAMotionEventType; @@ -275,7 +284,10 @@ wine_tsx11_unlock(); if (!hWnd && event->xany.window == root_window) hWnd = GetDesktopWindow(); - if (!hWnd && event->type != PropertyNotify && event->type != MappingNotify) + if ( !hWnd && event->xany.window != root_window + && event->type != PropertyNotify + && event->type != MappingNotify + && event->type != ClientMessage) WARN( "Got event %s for unknown Window %08lx\n", event_names[event->type], event->xany.window ); else @@ -338,7 +350,6 @@ break; case ClientMessage: - if (!hWnd) return; EVENT_ClientMessage( hWnd, (XClientMessageEvent *) event ); break; @@ -1202,8 +1213,49 @@ */ static void EVENT_ClientMessage( HWND hWnd, XClientMessageEvent *event ) { + TRACE("called\n"); if (event->message_type != None && event->format == 32) { - if (event->message_type == wmProtocols) + if (event->message_type == wmManager) { + if (event->data.l[1] == netSysTraySelection) { + 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 == 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 == wmProtocols) handle_wm_protocols_message( hWnd, event ); else if (event->message_type == dndProtocol) {