System tray integration

Mike Hearn mike at theoretic.com
Thu Dec 4 06:16:20 CST 2003


Hi Alexandre,

This has missed the last two commits. Is this codes presence in shell32
really a blocking issue? If so then I'd note that quite a lot of people
have problems caused by the lack of this patch (can't quit apps etc).

thanks -mike

On Sun, 2003-11-30 at 16:16, Mike Hearn wrote:
> 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-devel mailing list