Index: /trunk/src/3rdparty/os2/xsystray/xsystray.c
===================================================================
--- /trunk/src/3rdparty/os2/xsystray/xsystray.c	(revision 255)
+++ /trunk/src/3rdparty/os2/xsystray/xsystray.c	(revision 256)
@@ -40,4 +40,6 @@
 #include <stdio.h>
 #include <string.h>
+#include <stdlib.h>
+#include <stdarg.h>
 
 // generic headers
@@ -73,4 +75,29 @@
 #pragma hdrstop                     // VAC++ keeps crashing otherwise
 
+// primitive debug logging to a file
+#if 1
+static void __LOG_WORKER(const char *fmt, ...)
+{
+    static FILE *f = NULL;
+    if (f == NULL)
+    {
+        f = fopen("c:\\xsystray.dbg", "a");
+        setbuf(f, NULL);
+    }
+    if (f != NULL)
+    {
+        va_list vl;
+        va_start(vl, fmt);
+        vfprintf(f, fmt, vl);
+        va_end(vl);
+    }
+}
+#define LOG(m)  do { __LOG_WORKER m; } while(0)
+#define LOGF(m) do { __LOG_WORKER("%s: ", __FUNCTION__); __LOG_WORKER m; } while(0)
+#else
+#define LOG(m)  do {} while (0)
+#define LOGF(m) do {} while (0)
+#endif
+
 /* ******************************************************************
  *
@@ -79,5 +106,42 @@
  ********************************************************************/
 
-// None currently.
+/*
+ *@@ ICONDATA:
+ *      Per-icon data.
+ */
+
+typedef struct _ICONDATA
+{
+    HWND        hwnd;
+                // associated window
+    ULONG       ulId;
+                // icon ID
+    HPOINTER    hIcon;
+                // icon handle
+    ULONG       ulMsgId;
+                // message ID for notifications
+    PSZ         pszToolTip;
+                // icon tooltip (NULL if none)
+
+} ICONDATA, *PICONDATA;
+
+/*
+ *@@ SYSTRAYDATA:
+ *      Global system tray data.
+ */
+
+typedef struct
+{
+    PICONDATA   pIcons;
+                // array of icons currently shown in the system tray
+                // (left to right)
+    size_t      cIcons;
+                // number of icons in the pIcons array
+    size_t      cIconsMax;
+                // maximum number of icons pIcons can fit
+
+} SYSTRAYDATA, *PSYSTRAYDATA;
+
+ULONG QWL_USER_SERVER_DATA = 0;
 
 /* ******************************************************************
@@ -196,4 +260,5 @@
  */
 
+static
 BOOL WgtControl(PXCENTERWIDGET pWidget,
                 MPARAM mp1,
@@ -240,4 +305,5 @@
  */
 
+static
 VOID WgtPaint(HWND hwnd,
               PXCENTERWIDGET pWidget)
@@ -274,5 +340,5 @@
 /*
  *@@ fnwpXSysTray:
- *      window procedure for the winlist widget class.
+ *      window procedure for the Extended system tray widget class.
  *
  *      There are a few rules which widget window procs
@@ -311,4 +377,9 @@
 
         case WM_CREATE:
+        {
+            PSYSTRAYDATA pSysTrayData = NULL;
+
+            mrc = (MPARAM)TRUE; // being pessimistic gives more compact code
+
             WinSetWindowPtr(hwnd, QWL_USER, mp1);
             if (    (!(pWidget = (PXCENTERWIDGET)mp1))
@@ -316,5 +387,35 @@
                )
                 // shouldn't happen... stop window creation!!
-                mrc = (MPARAM)TRUE;
+                break;
+
+            pSysTrayData = malloc(sizeof(*pSysTrayData));
+            if (pSysTrayData == NULL)
+                break;
+
+            // initialize the SYSTRAYDATA structure
+            pSysTrayData->cIconsMax = 4;
+            pSysTrayData->pIcons = malloc(sizeof(*pSysTrayData->pIcons) *
+                                          pSysTrayData->cIconsMax);
+            if (pSysTrayData->pIcons == NULL)
+            {
+                free(pSysTrayData);
+                break;
+            }
+            pSysTrayData->cIcons = 0;
+            pWidget->pUser = pSysTrayData;
+
+            // create the "server" window (note that we pass the XCENTERWIDGET
+            // pointer on to it)
+            HWND hwndServer =
+                WinCreateWindow(HWND_DESKTOP, WNDCLASS_WIDGET_XSYSTRAY_SERVER,
+                                NULL, WS_MINIMIZED,
+                                0, 0, 0, 0,
+                                HWND_DESKTOP, HWND_BOTTOM,
+                                0, mp1, NULL);
+            if (hwndServer == NULLHANDLE)
+                break;
+
+            mrc = FALSE; // confirm success
+        }
         break;
 
@@ -353,9 +454,20 @@
 
         case WM_DESTROY:
-            // If we had any user data allocated in WM_CREATE
-            // or elsewhere, we'd clean this up here.
+        {
+            // free all system tray data
+            PSYSTRAYDATA pSysTrayData = (PSYSTRAYDATA)pWidget->pUser;
+            size_t i;
+            for (i = 0; i < pSysTrayData->cIcons; ++i)
+            {
+                if (pSysTrayData->pIcons[i].pszToolTip)
+                    free(pSysTrayData->pIcons[i].pszToolTip);
+            }
+            free(pSysTrayData->pIcons);
+            free(pSysTrayData);
+            pWidget->pUser = NULL;
             // We _MUST_ pass this on, or the default widget proc
             // cannot clean up.
             mrc = pWidget->pfnwpDefWidgetProc(hwnd, msg, mp1, mp2);
+        }
         break;
 
@@ -363,4 +475,89 @@
             mrc = pWidget->pfnwpDefWidgetProc(hwnd, msg, mp1, mp2);
 
+    } // end switch(msg)
+
+    return mrc;
+}
+
+/*
+ *@@ WgtXSysTrayControl:
+ *      implementation for WM_XST_CONTROL in fnwpXSysTrayServer.
+ *
+ *      Serves as an entry point for all client-side requests to the Extended
+ *      system tray.
+ *
+ *      Note that this message is being sent from another process which is
+ *      awaiting for an answer, so it must return as far as possible (by
+ *      rescheduling any potentially long term operation for another cycle).
+ */
+
+static
+BOOL WgtXSysTrayControl(HWND hwnd, PXCENTERWIDGET pWidget,
+                        PSYSTRAYCTLDATA pCtlData)
+{
+    BOOL brc = FALSE;
+
+    switch (pCtlData->ulCommand)
+    {
+        case SYSTRAYCMD_GETVERSION:
+        {
+            LOGF(("SYSTRAYCMD_GETVERSION\n"));
+
+            pCtlData->bAcknowledged = TRUE;
+            pCtlData->u.version.ulMajor = XSYSTRAY_VERSION_MAJOR;
+            pCtlData->u.version.ulMajor = XSYSTRAY_VERSION_MINOR;
+            pCtlData->u.version.ulRevision = XSYSTRAY_VERSION_REVISION;
+            brc = TRUE;
+        }
+        break;
+
+        default:
+            break;
+    }
+
+    return brc;
+}
+
+/*
+ *@@ fnwpXSysTrayServer:
+ *      window procedure for the Extended system tray server window class.
+ *
+ *      A separate "server" class is necessary because we need a CS_FRAME
+ *      top-level window for DDE (which we need to support to be backward
+ *      compatible with the System tray wdget from the SysTray/WPS package) and
+ *      also to make ourselves discoverable for the client-side implementation
+ *      of our new extended API (which queries the class of each top-level
+ *      window to find the system tray server).
+ */
+
+static
+MRESULT EXPENTRY fnwpXSysTrayServer(HWND hwnd, ULONG msg, MPARAM mp1, MPARAM mp2)
+{
+    MRESULT mrc = 0;
+    // get widget data from QWL_USER_SERVER_DATA (stored there by WM_CREATE)
+    PXCENTERWIDGET pWidget =
+        (PXCENTERWIDGET)WinQueryWindowPtr(hwnd, QWL_USER_SERVER_DATA);
+                    // this ptr is valid after WM_CREATE
+
+    switch (msg)
+    {
+        case WM_CREATE:
+            WinSetWindowPtr(hwnd, QWL_USER_SERVER_DATA, mp1);
+        break;
+
+        /*
+         * WM_XST_CONTROL:
+         *      This is the message sent to us by the clinet-side implementation
+         *      of the API to request some function. mp1 points to a
+         *      SYSTRAYCTLDATA structure.
+         */
+
+        case WM_XST_CONTROL:
+            mrc = (MRESULT)WgtXSysTrayControl(hwnd, pWidget,
+                                              (PSYSTRAYCTLDATA)mp1);
+        break;
+
+        default:
+            mrc = WinDefWindowProc(hwnd, msg, mp1, mp2);
     } // end switch(msg)
 
@@ -428,18 +625,46 @@
                              PSZ pszErrorMsg)       // if 0 is returned, 500 bytes of error msg
 {
-    ULONG   ulrc = 0;
-
-    // register our PM window class
-    if (!WinRegisterClass(hab,
-                          WNDCLASS_WIDGET_XSYSTRAY,
-                          fnwpXSysTray,
-                          CS_PARENTCLIP | CS_SIZEREDRAW | CS_SYNCPAINT,
-                          sizeof(PVOID))
+    ULONG       ulrc = 0;
+    CLASSINFO   ClassInfo;
+
+    LOGF(("hmodPlugin %x\n", hmodPlugin));
+
+    do
+    {
+        // register our PM window class
+        if (!WinRegisterClass(hab,
+                             WNDCLASS_WIDGET_XSYSTRAY,
+                             fnwpXSysTray,
+                             CS_PARENTCLIP | CS_SIZEREDRAW | CS_SYNCPAINT,
+                             sizeof(PVOID))
                                 // extra memory to reserve for QWL_USER
-                         )
-        // error registering class: report error then
-        strcpy(pszErrorMsg, "WinRegisterClass failed.");
-    else
-    {
+            )
+        {
+            LOG(("WinRegisterClass(%s) failed with %lX",
+                 WNDCLASS_WIDGET_XSYSTRAY, WinGetLastError(hab)));
+            break;
+        }
+
+        // get the window data size for the WC_FRAME class (any window class
+        // that specifies CS_FRAME must have at least this number, otherise
+        // WinRegisterClass returns 0x1003
+        if (!WinQueryClassInfo(hab, (PSZ)WC_FRAME, &ClassInfo))
+            break;
+        QWL_USER_SERVER_DATA = ClassInfo.cbWindowData;
+
+        if (!WinRegisterClass(hab,
+                              WNDCLASS_WIDGET_XSYSTRAY_SERVER,
+                              fnwpXSysTrayServer,
+                              CS_FRAME,
+                              QWL_USER_SERVER_DATA + sizeof(PVOID))
+                                // extra memory to reserve for QWL_USER
+            )
+        {
+            // error registering class: report error then
+            snprintf(pszErrorMsg, 500, "WinRegisterClass(%s) failed with %lX",
+                     WNDCLASS_WIDGET_XSYSTRAY_SERVER, WinGetLastError(hab));
+            break;
+        }
+
         // no error:
         // return widget classes array
@@ -449,4 +674,8 @@
         ulrc = sizeof(G_WidgetClasses) / sizeof(G_WidgetClasses[0]);
     }
+    while (0);
+
+    LOGF(("pszErrorMsg %s\n", pszErrorMsg));
+    LOGF(("ulrc %d\n", ulrc));
 
     return ulrc;
@@ -489,6 +718,6 @@
 {
     *pulMajor = 0;
-    *pulMinor = 1;
-    *pulRevision = 0;
-}
-
+    *pulMinor = 9;
+    *pulRevision = 9;
+}
+
Index: /trunk/src/3rdparty/os2/xsystray/xsystray.h
===================================================================
--- /trunk/src/3rdparty/os2/xsystray/xsystray.h	(revision 255)
+++ /trunk/src/3rdparty/os2/xsystray/xsystray.h	(revision 256)
@@ -16,4 +16,8 @@
 #ifndef XSYSTRAY_HEADER_INCLUDED
 #define XSYSTRAY_HEADER_INCLUDED
+
+#define XSYSTRAY_VERSION_MAJOR 0
+#define XSYSTRAY_VERSION_MINOR 1
+#define XSYSTRAY_VERSION_REVISION 0
 
 #define WNDCLASS_WIDGET_XSYSTRAY_SERVER "XWPCenterExtendedSysTrayServer"
@@ -35,5 +39,5 @@
 } SYSTRAYCMD;
 
-// NOTE: the idea is to fit SYSTRAYMSGDATA into a page (4K) since this is the
+// NOTE: the idea is to fit SYSTRAYCTLDATA into a page (4K) since this is the
 // smallest piece DosAllocSharedMem() allocates anyway.
 typedef struct
@@ -73,5 +77,5 @@
             // set to true by the recipient if it processes the message
 
-} SYSTRAYMSGDATA, *PSYSTRAYMSGDATA;
+} SYSTRAYCTLDATA, *PSYSTRAYCTLDATA;
 
 #endif // XSYSTRAY_HEADER_INCLUDED
Index: /trunk/src/3rdparty/os2/xsystray/xsystray_api.c
===================================================================
--- /trunk/src/3rdparty/os2/xsystray/xsystray_api.c	(revision 255)
+++ /trunk/src/3rdparty/os2/xsystray/xsystray_api.c	(revision 256)
@@ -27,5 +27,5 @@
 
 static HWND G_hwndSysTray = NULLHANDLE;
-static int G_itlsSysTrayMsgData = -1;
+static int G_itlsSysTrayCtlData = -1;
 
 static HWND FindSysTrayWindow()
@@ -46,5 +46,5 @@
 }
 
-static BOOL SendSysTrayCtlMsg(PSYSTRAYMSGDATA pData)
+static BOOL SendSysTrayCtlMsg(PSYSTRAYCTLDATA pData)
 {
     APIRET arc;
@@ -70,5 +70,5 @@
             arc = ERROR_INVALID_HANDLE;
             if (WinQueryWindowProcess(G_hwndSysTray, &pid, &tid))
-                arc = DosGiveSharedMem(__libc_TLSGet(G_itlsSysTrayMsgData),
+                arc = DosGiveSharedMem(__libc_TLSGet(G_itlsSysTrayCtlData),
                                        pid, PAG_READ | PAG_WRITE);
             if (arc != NO_ERROR)
@@ -80,5 +80,5 @@
         mrc = WinSendMsg(G_hwndSysTray, WM_XST_CONTROL, pData, NULL);
         if (mrc == (MRESULT)TRUE && pData->bAcknowledged)
-            break;
+            return TRUE;
 
         // if we failed to send the message, it may mean that XCenter was restarted
@@ -98,10 +98,10 @@
 }
 
-static PSYSTRAYMSGDATA GetSysTrayMsgDataPtr()
+static PSYSTRAYCTLDATA GetSysTrayCtlDataPtr()
 {
     APIRET arc;
 
     // allocate a thread local storage entry if not done so
-    if (G_itlsSysTrayMsgData == -1)
+    if (G_itlsSysTrayCtlData == -1)
     {
         // @todo does XWorkplace have its own TLS? Not? Use
@@ -109,5 +109,5 @@
         // to the lack of space in that area)
         int itls = __libc_TLSAlloc();
-        if (!__atomic_cmpxchg32(&G_itlsSysTrayMsgData, itls, -1))
+        if (!__atomic_cmpxchg32(&G_itlsSysTrayCtlData, itls, -1))
         {
             // another thread has already got an entry, discard our try
@@ -116,18 +116,18 @@
         }
 
-        if (G_itlsSysTrayMsgData == -1)
+        if (G_itlsSysTrayCtlData == -1)
             return NULL;
     }
 
-    // allocate a SYSTRAYMSGDATA struct for this thread if not done so
-    PSYSTRAYMSGDATA pData = __libc_TLSGet(G_itlsSysTrayMsgData);
-    if (!pData)
-    {
-        arc = DosAllocSharedMem((PVOID)&pData, NULL, sizeof(SYSTRAYMSGDATA),
+    // allocate a SYSTRAYCTLDATA struct for this thread if not done so
+    PSYSTRAYCTLDATA pData = __libc_TLSGet(G_itlsSysTrayCtlData);
+    if (!pData)
+    {
+        arc = DosAllocSharedMem((PVOID)&pData, NULL, sizeof(SYSTRAYCTLDATA),
                                 PAG_COMMIT | PAG_READ | PAG_WRITE | OBJ_GIVEABLE);
         if (arc != NO_ERROR)
             return NULL;
 
-        __libc_TLSSet(G_itlsSysTrayMsgData, pData);
+        __libc_TLSSet(G_itlsSysTrayCtlData, pData);
 
         // note that we don't ever free the allocated block since our API doesn't
@@ -159,5 +159,5 @@
                             PULONG pulRevision) // out: revision number
 {
-    PSYSTRAYMSGDATA pData = GetSysTrayMsgDataPtr();
+    PSYSTRAYCTLDATA pData = GetSysTrayCtlDataPtr();
     if (!pData)
         return FALSE;
@@ -166,6 +166,6 @@
     pData->hwndSender = NULLHANDLE;
 
-    BOOL rc = SendSysTrayCtlMsg(pData);
-    if (rc)
+    BOOL brc = SendSysTrayCtlMsg(pData);
+    if (brc)
     {
         if (pulMajor)
@@ -177,5 +177,5 @@
     }
 
-    return rc;
+    return brc;
 }
 
@@ -215,5 +215,5 @@
                        ULONG ulFlags)   // in: flags (not currently used, must be 0)
 {
-    PSYSTRAYMSGDATA pData = GetSysTrayMsgDataPtr();
+    PSYSTRAYCTLDATA pData = GetSysTrayCtlDataPtr();
     if (!pData)
         return FALSE;
@@ -240,5 +240,5 @@
                           ULONG ulId)   // in: icon ID to remove
 {
-    PSYSTRAYMSGDATA pData = GetSysTrayMsgDataPtr();
+    PSYSTRAYCTLDATA pData = GetSysTrayCtlDataPtr();
     if (!pData)
         return FALSE;
@@ -272,5 +272,5 @@
                               PSZ pszText)  // in: tooltip text
 {
-    PSYSTRAYMSGDATA pData = GetSysTrayMsgDataPtr();
+    PSYSTRAYCTLDATA pData = GetSysTrayCtlDataPtr();
     if (!pData)
         return FALSE;
@@ -361,5 +361,5 @@
 ULONG xstGetSysTrayMaxTextLen()
 {
-    return sizeof(((PSYSTRAYMSGDATA)0)->u.tooltip.szText);
-}
-
+    return sizeof(((PSYSTRAYCTLDATA)0)->u.tooltip.szText);
+}
+
Index: /trunk/src/3rdparty/os2/xsystray/xsystray_api.h
===================================================================
--- /trunk/src/3rdparty/os2/xsystray/xsystray_api.h	(revision 255)
+++ /trunk/src/3rdparty/os2/xsystray/xsystray_api.h	(revision 256)
@@ -21,5 +21,6 @@
 #endif
 
-// notification code constants for WM_XST_NOTIFY, refer to xstAddSysTrayIcon()
+// notification code constants for the notification messages sent by the system
+// tray (refer to xstAddSysTrayIcon() for details)
 #define XST_IN_MOUSE    0x0001
 
