Ignore:
Timestamp:
Nov 2, 2009, 3:10:29 AM (16 years ago)
Author:
Dmitry A. Kuminov
Message:

3rdparty: os2/xsystray: Use custom shared memory pool for structures posted by the server to the client windows. Process mouse/wheel and context menu messages in the icon area and post them to the respective client windows. Use smaller spacing between icons (one pad unit instead of two).

Location:
trunk/src/3rdparty/os2/xsystray
Files:
4 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/3rdparty/os2/xsystray/xsystray.c

    r270 r273  
    111111 */
    112112
    113 typedef struct _ICONDATA
     113typedef struct
    114114{
    115115    HWND        hwnd;
    116116                // associated window
    117     ULONG       ulId;
     117    USHORT      usId;
    118118                // icon ID
    119119    HPOINTER    hIcon;
     
    123123    PSZ         pszToolTip;
    124124                // icon tooltip (NULL if none)
     125    BOOL        bMemoryPoolGiven;
     126                // TRUE if SYSTRAYDATA::pvMemoryPool is already given to
     127                // the process hwnd belongs to
    125128
    126129} ICONDATA, *PICONDATA;
     
    147150    size_t      cIconsMax;
    148151                // maximum number of icons pIcons can fit
     152    PVOID       pvMemoryPool;
     153                // memory pool for NOTIFYDATA structures
    149154
    150155} SYSTRAYDATA, *PSYSTRAYDATA;
     
    154159        // space for the newly added icon
    155160
    156 static ULONG QWL_USER_SERVER_DATA = 0;
    157              // offset to the PXCENTERWIDGET pointer in the widget data array
     161#define SERVER_MEMORYPOOL_SIZE 65536
     162        // taking NOTIFYDATA size into account (<=32 B), this is enough for at
     163        // least 2048 simultaneous notification messages, which (even taking
     164        // slowly responsing clients into account) sounds sane since in most
     165        // cases the structure is freed once it reaches the target event queue
     166        // and before a message created as a copy of it is sent to the target
     167        // window procedure
    158168
    159169#define TID_CHECKALIVE          1
     
    161171#define TID_CHECKALIVE_TIMEOUT  2000 // ms
    162172         // how often to perform alive checks
     173
     174static ULONG WM_XST_CREATED = 0;
     175             // identity of the WM_XST_CREATED message taken from the atom table
     176static ULONG WM_XST_NOTIFY = 0;
     177             // identity of the WM_XST_NOTIFY message taken from the atom table
     178
     179static ULONG QWL_USER_SERVER_DATA = 0;
     180             // offset to the PXCENTERWIDGET pointer in the widget data array
    163181
    164182static
     
    299317{
    300318    pData->hwnd = NULLHANDLE;
    301     pData->ulId = 0;
     319    pData->usId = 0;
    302320    if (pData->hIcon != NULLHANDLE)
    303321    {
     
    323341PICONDATA FindIconData(PSYSTRAYDATA pSysTrayData,
    324342                       HWND hwnd,       // in: associated window handle
    325                        ULONG ulId,      // in: icon ID
     343                       USHORT usId,     // in: icon ID
    326344                       size_t *pIdx)    // out: index of the icon in the icon array
    327345                                        // (optional, may be NULL)
     
    331349    {
    332350        if (pSysTrayData->pIcons[i].hwnd == hwnd &&
    333             pSysTrayData->pIcons[i].ulId == ulId)
     351            pSysTrayData->pIcons[i].usId == usId)
    334352        {
    335353            if (pIdx)
     
    342360        *pIdx = i;
    343361    return NULL;
     362}
     363
     364/*
     365 *@@ AllocNotifyDataPtr:
     366 *      Allocates a SYSTRAYCTLDATA struct in the pool of shared memory on belalf
     367 *      of the client window identified by pIconData->hwnd.
     368 *
     369 *      If there is no free space in the pool, it returns NULL. On success,
     370 *      fills in msg and mp1 fields of the returned structure using the
     371 *      information provided in pIconData.
     372 *
     373 *      Note that the allocated structure is supposed to be freed using
     374 *      FreeNotifyDataPtr by the client-side API implementation in another
     375 *      process.
     376 */
     377static
     378PNOTIFYDATA AllocNotifyDataPtr(PVOID pvMemoryPool,  // in: memory pool base address
     379                               PICONDATA pIconData) // in: icon data
     380{
     381    // NOTE: we cannot use DosSubAllocMem() and friends since we want to be able
     382    // to free blocks allocated to clients which death we detect but we cannot
     383    // be sure about the layout of memory DosSub API uses. Therefore, we provide
     384    // our own sub-allocation scheme which is rather simple because we need to
     385    // allocate equally sized blocks (each is NOTIFYDATA struct). The memory
     386    // pool is laid out as follows: MEMPOOLHDR followed by a number of
     387    // MEMPOOLBLK.
     388
     389    APIRET arc;
     390    PID pid;
     391    TID tid;
     392    PMEMPOOLHDR pHdr;
     393    ULONG ulMax, ulNeedsCommit, ulNext, ulCurr;
     394    PNOTIFYDATA pData;
     395
     396    LOGF(("pvMemoryPool %p\n", pvMemoryPool));
     397    LOGF(("hwnd         %p\n", pIconData->hwnd));
     398
     399    if (!pIconData->bMemoryPoolGiven)
     400    {
     401        LOGF(("Giving memory pool to %lx\n", pIconData->hwnd));
     402
     403        arc = ERROR_INVALID_HANDLE;
     404        if (WinQueryWindowProcess(pIconData->hwnd, &pid, &tid))
     405            arc = DosGiveSharedMem(pvMemoryPool, pid, PAG_READ | PAG_WRITE);
     406        if (arc != NO_ERROR)
     407            return NULL;
     408
     409        pIconData->bMemoryPoolGiven = TRUE;
     410    }
     411
     412    pHdr = (PMEMPOOLHDR)pvMemoryPool;
     413
     414    // maximum address that is still enough for a block
     415    ulMax = pHdr->ulBeyond - sizeof(MEMPOOLBLK);
     416
     417    ulNeedsCommit = pHdr->ulNeedsCommit;
     418    ulNext = pHdr->ulNext;
     419    ulCurr = ulNext;
     420
     421    LOGF(("ulNeedsCommit %p\n", ulNeedsCommit));
     422    LOGF(("ulNext        %p\n", ulNext));
     423
     424    do
     425    {
     426        if (ulCurr >= ulNeedsCommit)
     427        {
     428            // commit more memory; it's OK two or more threads will do the same
     429            DosSetMem((PVOID)ulNeedsCommit, 4096,
     430                      PAG_COMMIT | PAG_READ | PAG_WRITE);
     431            // advance the address (only if nobody has already done so -- they
     432            // could already commit more than we did)
     433            __atomic_cmpxchg32((uint32_t *)&pHdr->ulNeedsCommit,
     434                               ulNeedsCommit + 4096, ulNeedsCommit);
     435        }
     436
     437        if (__atomic_cmpxchg32((uint32_t *)ulCurr, pIconData->hwnd, NULLHANDLE))
     438            break;
     439
     440        ulCurr += sizeof(MEMPOOLBLK);
     441        if (ulCurr > ulMax)
     442            // start over
     443            ulCurr = ((ULONG)pvMemoryPool) + sizeof(MEMPOOLHDR);
     444
     445        if (ulCurr == ulNext)
     446            return NULL; // no free blocks!
     447    }
     448    while (1);
     449
     450    LOGF(("ulCurr        %p\n", ulCurr));
     451
     452    // advance to the next possibly free block
     453    ulCurr += sizeof(MEMPOOLBLK);
     454    if (ulCurr > ulMax)
     455        // start over
     456        ulCurr = ((ULONG)pvMemoryPool) + sizeof(MEMPOOLHDR);
     457
     458    // store the new next address until someone else has already done that
     459    __atomic_cmpxchg32((uint32_t *)&pHdr->ulNext, ulCurr, ulNext);
     460
     461    pData = &((PMEMPOOLBLK)ulCurr)->NotifyData;
     462    memset(pData, sizeof(*pData), 0);
     463
     464    pData->msg = pIconData->ulMsgId;
     465    pData->mp1 = MPFROMSHORT(pIconData->usId);
     466
     467    return pData;
     468}
     469
     470/*
     471 *@@ PostNotifyMsg:
     472 *      Posts WM_XST_NOTIFY to the given client window. Frees pNotifyData if
     473 *      posting fails.
     474 */
     475
     476VOID PostNotifyMsg(PSYSTRAYDATA pSysTrayData, HWND hwnd,
     477                   PNOTIFYDATA *pNotifyData)
     478{
     479    if (!WinPostMsg(hwnd, WM_XST_NOTIFY, pNotifyData, pSysTrayData->pvMemoryPool))
     480        FreeNotifyDataPtr(pSysTrayData->pvMemoryPool, hwnd, pNotifyData);
    344481}
    345482
     
    404541            {
    405542                PSIZEL pszl = (PSIZEL)mp2;
    406                 LONG pad2 = pSysTrayData->lIconPad * 2;
    407                 pszl->cx = (pSysTrayData->lIconWidth + pad2) * pSysTrayData->cIcons; // desired width
    408                 pszl->cy = pSysTrayData->lIconHeight + pad2; // desired minimum height
     543                LONG pad = pSysTrayData->lIconPad;
     544                size_t cnt = pSysTrayData->cIcons;
     545                // desired width
     546                if (cnt)
     547                    pszl->cx = pad + (pSysTrayData->lIconWidth + pad) * cnt;
     548                else
     549                    pszl->cx = 0;
     550                // desired minimum height
     551                pszl->cy = pSysTrayData->lIconHeight + pad * 2;
    409552                brc = TRUE;
    410553            }
     
    421564 *      implementation for WM_PAINT in fnwpXSysTray.
    422565 *
    423  *      This really does nothing, except painting a
    424  *      3D rectangle and printing a question mark.
     566 *      Draws all the icons. If the widget's center is located to the left from
     567 *      the XCenter's center, icons go left to right. Otherwise, they go right
     568 *      to left.
     569 */
     570/*
     571        +---------------------------+  p = lIconPad
     572        |     p                     |  w = lIconWidth
     573        |   +-------+   +-------+   |  h = lIconHeight
     574        | p |   w   | p |   w   | p |
     575        |   |      h|   |      h|   |
     576        |   |       |   |       |   |  If "Frame around statics" is on in XCenter
     577        |   +-------+   +-------+   |  properties, then a 1 px 3D frame is drawn
     578        |     p                     |  within the pad area. So, lIconPad must
     579        +---------------------------+  be at least 2 px.
    425580 */
    426581
     
    438593        RECTL   rcl;
    439594        BOOL    bLeftToRight;
    440         LONG    x, y, lTotalWidth;
     595        LONG    x, y, lIconStep;
    441596        size_t  i;
    442597
     
    481636        // always center the icon vertically (we may be given more height than
    482637        // we requested)
    483         y = (swp.cy - pSysTrayData->lIconWidth) / 2;
     638        y = (swp.cy - pSysTrayData->lIconHeight) / 2;
    484639
    485640        if (bLeftToRight)
     
    488643            x = swp.cx - pSysTrayData->lIconPad - pSysTrayData->lIconWidth;
    489644
    490         lTotalWidth = pSysTrayData->lIconWidth + pSysTrayData->lIconPad * 2;
     645        lIconStep = pSysTrayData->lIconWidth + pSysTrayData->lIconPad;
    491646
    492647        // where to start from?
    493648        if (bLeftToRight)
    494649        {
    495             i = rclPaint.xLeft / lTotalWidth;
    496             x = pSysTrayData->lIconPad + i * lTotalWidth;
     650            i = rclPaint.xLeft / lIconStep;
     651            x = pSysTrayData->lIconPad + i * lIconStep;
    497652        }
    498653        else
    499654        {
    500             i = (swp.cx - rclPaint.xRight) / lTotalWidth;
    501             x = swp.cx - (i + 1) * lTotalWidth + pSysTrayData->lIconPad;
     655            i = (swp.cx - rclPaint.xRight) / lIconStep;
     656            x = swp.cx - (i + 1) * lIconStep;
     657            // negate the step, for convenience
     658            lIconStep = -lIconStep;
    502659        }
    503660
    504661        // draw as many icons as we can / need
    505         for (i = 0; i < pSysTrayData->cIcons; ++i)
     662        for (; i < pSysTrayData->cIcons; ++i)
    506663        {
    507664            if (x >= rclPaint.xRight)
     
    509666
    510667            DrawPointer(hps, x, y, pSysTrayData->pIcons[i].hIcon, DP_MINI);
    511             if (bLeftToRight)
    512                 x += lTotalWidth;
    513             else
    514                 x -= lTotalWidth;
     668            x += lIconStep;
    515669        }
    516670
    517671        WinEndPaint(hps);
    518672    }
     673}
     674
     675/*
     676 *@@ WgtMouse:
     677 *      implementation for WM_BUTTONxyyy in fnwpXSysTray.
     678 *
     679 *      Posts a notification to the window associated with the icon and returns
     680 *      TRUE if this mouse message is within the icon bounds. Otherwise returns
     681 *      FALSE.
     682 *
     683 *      Refer to WgtPaint for more details about the widget geometry.
     684 */
     685
     686static
     687BOOL WgtMouse(HWND hwnd, ULONG msg, MRESULT mp1, MRESULT mp2,
     688              PXCENTERWIDGET pWidget)
     689{
     690    PSYSTRAYDATA pSysTrayData = (PSYSTRAYDATA)pWidget->pUser;
     691
     692    POINTL  ptl;
     693    SWP     swp;
     694    RECTL   rcl;
     695    BOOL    bLeftToRight;
     696    LONG    y, lIconStep;
     697    size_t  i;
     698
     699    PICONDATA   pIconData;
     700    PNOTIFYDATA pNotifyData;
     701
     702    ptl.x = ((PPOINTS)&mp1)->x;
     703    ptl.y = ((PPOINTS)&mp1)->y;
     704
     705    LOGF(("msg %x ptl %ld,%ld\n", msg, ptl.x, ptl.y));
     706
     707    WinQueryWindowPos(hwnd, &swp);
     708    WinQueryWindowRect(pWidget->pGlobals->hwndClient, &rcl);
     709
     710    y = (swp.cy - pSysTrayData->lIconHeight) / 2;
     711    if (ptl.y < y || ptl.y >= y + pSysTrayData->lIconHeight)
     712        return FALSE; // hit pad space
     713
     714    // detect the direction
     715    bLeftToRight = swp.x + swp.cx / 2 < (rcl.xRight / 2);
     716
     717    lIconStep = pSysTrayData->lIconWidth + pSysTrayData->lIconPad;
     718
     719    // which icon is that?
     720    if (bLeftToRight)
     721    {
     722        i = ptl.x / lIconStep;
     723        if (ptl.x % lIconStep < pSysTrayData->lIconPad)
     724            return FALSE; // hit pad space
     725    }
     726    else
     727    {
     728        i = (swp.cx - ptl.x - 1) / lIconStep;
     729        if ((swp.cx - ptl.x - 1) % lIconStep < pSysTrayData->lIconPad)
     730            return FALSE; // hit pad space
     731    }
     732    if (i >= pSysTrayData->cIcons)
     733        return FALSE; // hit pad space
     734
     735    pIconData = &pSysTrayData->pIcons[i];
     736
     737    LOGF(("hwnd  %x\n", pIconData->hwnd));
     738    LOGF(("usId  %d\n", pIconData->usId));
     739    LOGF(("hIcon %x\n", pIconData->hIcon));
     740
     741    // make the coordinates global
     742    WinMapWindowPoints(hwnd, HWND_DESKTOP, &ptl, 1);
     743
     744    // allocate a NOTIFYDATA struct
     745    pNotifyData = AllocNotifyDataPtr(pSysTrayData->pvMemoryPool, pIconData);
     746    if (!pNotifyData)
     747        return FALSE;
     748
     749    switch (msg)
     750    {
     751        case WM_HSCROLL:
     752        case WM_VSCROLL:
     753            pNotifyData->mp1 += XST_IN_WHEEL << 16;
     754            pNotifyData->u.WheelMsg.ulWheelMsg = msg;
     755            pNotifyData->u.WheelMsg.ptsPointerPos.x = ptl.x;
     756            pNotifyData->u.WheelMsg.ptsPointerPos.y = ptl.y;
     757            pNotifyData->u.WheelMsg.usCmd = SHORT2FROMMP(mp2);
     758            pNotifyData->mp2 = &pNotifyData->u.WheelMsg;
     759        break;
     760
     761        case WM_CONTEXTMENU:
     762            pNotifyData->mp1 += XST_IN_CONTEXT << 16;
     763            pNotifyData->u.ContextMsg.ptsPointerPos.x = ptl.x;
     764            pNotifyData->u.ContextMsg.ptsPointerPos.y = ptl.y;
     765            pNotifyData->u.ContextMsg.fPointer = TRUE;
     766            pNotifyData->mp2 = &pNotifyData->u.ContextMsg;
     767        break;
     768
     769        default:
     770            pNotifyData->mp1 += XST_IN_MOUSE << 16;
     771            pNotifyData->u.MouseMsg.ulMouseMsg = msg;
     772            pNotifyData->u.MouseMsg.ptsPointerPos.x = ptl.x;
     773            pNotifyData->u.MouseMsg.ptsPointerPos.y = ptl.y;
     774            pNotifyData->u.MouseMsg.fsHitTestRes = SHORT1FROMMP(mp2);
     775            pNotifyData->u.MouseMsg.fsFlags = SHORT2FROMMP(mp2);
     776            pNotifyData->mp2 = &pNotifyData->u.MouseMsg;
     777        break;
     778    }
     779
     780    PostNotifyMsg(pSysTrayData, hwnd, pNotifyData);
     781
     782    return TRUE;
     783}
     784
     785static
     786VOID FreeSysTrayData(PSYSTRAYDATA pSysTrayData)
     787{
     788    // destroy the server
     789    if (pSysTrayData->hwndServer != NULLHANDLE)
     790    {
     791        WinDestroyWindow(pSysTrayData->hwndServer);
     792        pSysTrayData->hwndServer = NULLHANDLE;
     793    }
     794
     795    // free all system tray data
     796    if (pSysTrayData->pvMemoryPool)
     797    {
     798        DosFreeMem(pSysTrayData->pvMemoryPool);
     799    }
     800    if (pSysTrayData->pIcons)
     801    {
     802        size_t i;
     803        for (i = 0; i < pSysTrayData->cIcons; ++i)
     804            FreeIconData(&pSysTrayData->pIcons[i]);
     805        pSysTrayData->cIcons = 0;
     806        free(pSysTrayData->pIcons);
     807        pSysTrayData->pIcons = NULL;
     808    }
     809
     810    free(pSysTrayData);
    519811}
    520812
     
    562854
    563855            PSYSTRAYDATA pSysTrayData = NULL;
     856            APIRET arc;
    564857
    565858            WinSetWindowPtr(hwnd, QWL_USER, mp1);
     
    575868
    576869            // initialize the SYSTRAYDATA structure
     870            memset(pSysTrayData, sizeof(*pSysTrayData), 0);
    577871            pSysTrayData->lIconWidth = WinQuerySysValue(HWND_DESKTOP, SV_CXICON) / 2;
    578872            pSysTrayData->lIconHeight = WinQuerySysValue(HWND_DESKTOP, SV_CYICON) / 2;
     
    583877            if (pSysTrayData->pIcons == NULL)
    584878            {
    585                 free(pSysTrayData);
     879                FreeSysTrayData(pSysTrayData);
    586880                return (MRESULT)TRUE;
    587881            }
    588882            pSysTrayData->cIcons = 0;
     883
     884            // Allocate the memory pool for NOTIFYDATA structs (we don't
     885            // PAG_COMMIT all memory, AllocNotifyDataPtr() will do so as needed)
     886            arc = DosAllocSharedMem((PVOID)&pSysTrayData->pvMemoryPool, NULL,
     887                                    SERVER_MEMORYPOOL_SIZE,
     888                                    PAG_READ | PAG_WRITE | OBJ_GIVEABLE);
     889            if (arc == NO_ERROR)
     890            {
     891                PMEMPOOLHDR pHdr = (PMEMPOOLHDR)pSysTrayData->pvMemoryPool;
     892                arc = DosSetMem(pSysTrayData->pvMemoryPool, 4096,
     893                                PAG_COMMIT | PAG_READ | PAG_WRITE);
     894                if (arc == NO_ERROR)
     895                {
     896                    pHdr->ulBeyond = (ULONG)pSysTrayData->pvMemoryPool +
     897                                     SERVER_MEMORYPOOL_SIZE;
     898                    pHdr->ulNeedsCommit = (ULONG)pSysTrayData->pvMemoryPool +
     899                                           4096;
     900                    pHdr->ulNext = (ULONG)pSysTrayData->pvMemoryPool +
     901                                   sizeof(MEMPOOLHDR);
     902                }
     903            }
     904            if (arc != NO_ERROR)
     905            {
     906                FreeSysTrayData(pSysTrayData);
     907                return (MRESULT)TRUE;
     908            }
    589909
    590910            // create the "server" window (note that we pass the XCENTERWIDGET
     
    598918            if (pSysTrayData->hwndServer == NULLHANDLE)
    599919            {
    600                 free(pSysTrayData->pIcons);
    601                 free(pSysTrayData);
     920                FreeSysTrayData(pSysTrayData);
    602921                return (MRESULT)TRUE;
    603922            }
     
    606925
    607926            // inform all interested parties that we are fired up
    608             // (NOTE: keep in sync with xstGetSysTrayCreatedMsgId())
    609             WinBroadcastMsg(HWND_DESKTOP,
    610                             WinAddAtom(WinQuerySystemAtomTable(),
    611                                        "ExtendedSysTray.WM_XST_CREATED"),
    612                             NULL, NULL,
    613                             BMSG_POST);
     927            WinBroadcastMsg(HWND_DESKTOP, WM_XST_CREATED,
     928                            NULL, NULL, BMSG_POST);
    614929
    615930            return FALSE; // confirm success
     
    628943
    629944            PSYSTRAYDATA pSysTrayData = (PSYSTRAYDATA)pWidget->pUser;
    630             size_t i;
    631 
    632             // destroy the server
    633             WinDestroyWindow(pSysTrayData->hwndServer);
    634             pSysTrayData->hwndServer = NULLHANDLE;
    635 
    636             // free all system tray data
    637             for (i = 0; i < pSysTrayData->cIcons; ++i)
    638                 FreeIconData(&pSysTrayData->pIcons[i]);
    639             pSysTrayData->cIcons = 0;
    640             free(pSysTrayData->pIcons);
    641             pSysTrayData->pIcons = NULL;
    642 
    643             // make sure we remove the check alive timer
    644             WgtXSysTrayUpdateAfterIconAddRemove(pWidget);
    645 
    646             free(pSysTrayData);
     945
     946            // stop the check alive timer
     947            WinStopTimer(pWidget->habWidget, pSysTrayData->hwndServer,
     948                         TID_CHECKALIVE);
     949
     950            FreeSysTrayData(pSysTrayData);
    647951            pWidget->pUser = NULL;
    648952
     
    680984        break; */
    681985
     986        /*
     987         * All mouse click and wheel events:
     988         *      Note that we hide WM_CONTEXTMENU from XCenter when it is within
     989         *      the icon bounds as it's a responsibility of the application
     990         *      owning the icon to show it.
     991         */
     992
     993        case WM_BUTTON1UP:
     994        case WM_BUTTON1DOWN:
     995        case WM_BUTTON1CLICK:
     996        case WM_BUTTON1DBLCLK:
     997        case WM_BUTTON2UP:
     998        case WM_BUTTON2DOWN:
     999        case WM_BUTTON2CLICK:
     1000        case WM_BUTTON2DBLCLK:
     1001        case WM_BUTTON3UP:
     1002        case WM_BUTTON3DOWN:
     1003        case WM_BUTTON3CLICK:
     1004        case WM_BUTTON3DBLCLK:
     1005        case WM_CONTEXTMENU:
     1006        case WM_VSCROLL:
     1007        case WM_HSCROLL:
     1008        {
     1009            if (WgtMouse(hwnd, msg, mp1, mp2, pWidget))
     1010                return (MRESULT)TRUE;
     1011            // we didn't hit the icon, pass it on to XCenter
     1012        }
     1013        break;
     1014
    6821015        default:
    6831016            break;
     
    7131046    }
    7141047
    715     if (pSysTrayData->pIcons != NULL)
    716     {
    717         // ask XCenter to take our new size into account (this will also
    718         // invalidate us). If pIcons is NULL it means that we are in WM_DESTROY,
    719         // in which case XCenter will do everything for us
    720         WinPostMsg(pWidget->pGlobals->hwndClient,
    721                    XCM_REFORMAT,
    722                    (MPARAM)XFMF_GETWIDGETSIZES,
    723                    0);
    724     }
     1048    // ask XCenter to take our new size into account (this will also
     1049    // invalidate us)
     1050    WinPostMsg(pWidget->pGlobals->hwndClient,
     1051               XCM_REFORMAT,
     1052               (MPARAM)XFMF_GETWIDGETSIZES,
     1053               0);
    7251054}
    7261055
     
    7671096            LOGF(("SYSTRAYCMD_ADDICON\n"));
    7681097            LOGF((" hwnd  %x\n", pCtlData->hwndSender));
    769             LOGF((" ulId  %ld\n", pCtlData->u.icon.ulId));
     1098            LOGF((" usId  %d\n", pCtlData->u.icon.usId));
    7701099            LOGF((" hIcon %x\n", pCtlData->u.icon.hIcon));
    7711100
     
    7851114
    7861115            pData = FindIconData(pSysTrayData, pCtlData->hwndSender,
    787                                  pCtlData->u.icon.ulId, &i);
     1116                                 pCtlData->u.icon.usId, &i);
    7881117            if (pData)
    7891118            {
     
    8251154
    8261155                pData = &pSysTrayData->pIcons[i];
     1156                memset(pData, sizeof(*pData), 0);
     1157
    8271158                pData->hwnd = pCtlData->hwndSender;
    828                 pData->ulId = pCtlData->u.icon.ulId;
     1159                pData->usId = pCtlData->u.icon.usId;
    8291160                pData->hIcon = hIcon;
    8301161                pData->ulMsgId = pCtlData->u.icon.ulMsgId;
     
    8441175            LOGF(("SYSTRAYCMD_REMOVEICON\n"));
    8451176            LOGF((" hwnd  %x\n", pCtlData->hwndSender));
    846             LOGF((" ulId  %ld\n", pCtlData->u.icon.ulId));
     1177            LOGF((" usId  %d\n", pCtlData->u.icon.usId));
    8471178
    8481179            pCtlData->bAcknowledged = TRUE;
    8491180
    8501181            pData = FindIconData(pSysTrayData, pCtlData->hwndSender,
    851                                  pCtlData->u.icon.ulId, &i);
     1182                                 pCtlData->u.icon.usId, &i);
    8521183            if (pData)
    8531184            {
     
    8931224{
    8941225    PSYSTRAYDATA pSysTrayData = (PSYSTRAYDATA)pWidget->pUser;
     1226    PMEMPOOLHDR pMemPoolHdr = (PMEMPOOLHDR)pSysTrayData->pvMemoryPool;
     1227    PMEMPOOLBLK pMemPoolBlk;
     1228    ULONG ulMemPoolMax;
    8951229
    8961230    if (usTimerId == TID_CHECKALIVE)
     
    9041238            if (!WinIsWindow(pWidget->habWidget, pSysTrayData->pIcons[i].hwnd))
    9051239            {
     1240                PICONDATA pData = &pSysTrayData->pIcons[i];
     1241
    9061242                LOGF(("Removing icon of dead window!\n"));
    907                 LOGF((" hwnd  %x\n", pSysTrayData->pIcons[i].hwnd));
    908                 LOGF((" ulId  %ld\n", pSysTrayData->pIcons[i].ulId));
    909                 LOGF((" hIcon %x\n", pSysTrayData->pIcons[i].hIcon));
     1243                LOGF((" hwnd  %x\n", pData->hwnd));
     1244                LOGF((" usId  %ld\n", pData->usId));
     1245                LOGF((" hIcon %x\n", pData->hIcon));
     1246
     1247                // free memory blocks from the pool allocated for this client
     1248                ulMemPoolMax = pMemPoolHdr->ulBeyond;
     1249                if (ulMemPoolMax > pMemPoolHdr->ulNeedsCommit)
     1250                    ulMemPoolMax = pMemPoolHdr->ulNeedsCommit;
     1251                ulMemPoolMax -= sizeof(MEMPOOLBLK);
     1252
     1253                pMemPoolBlk = pMemPoolHdr->aBlocks;
     1254                while ((ULONG)pMemPoolBlk <= ulMemPoolMax)
     1255                {
     1256                    if (pMemPoolBlk->hwnd == pData->hwnd)
     1257                    {
     1258                        LOGF((" freeing memory block %p\n", pMemPoolBlk));
     1259                        __atomic_cmpxchg32((uint32_t *)&pMemPoolBlk->hwnd,
     1260                                           NULLHANDLE, hwnd);
     1261                    }
     1262                    ++pMemPoolBlk;
     1263                }
    9101264
    9111265                bAnyDead = TRUE;
    912                 FreeIconData(&pSysTrayData->pIcons[i]);
    913                 // hwnd is NULLHANDLE here
     1266                FreeIconData(pData);
     1267                // pData->hwnd is NULLHANDLE here
    9141268            }
    9151269        }
     
    11281482        }
    11291483
     1484        if (WM_XST_CREATED == 0)
     1485            WM_XST_CREATED = WinAddAtom(WinQuerySystemAtomTable(),
     1486                                        WM_XST_CREATED_ATOM);
     1487        if (WM_XST_NOTIFY == 0)
     1488            WM_XST_NOTIFY = WinAddAtom(WinQuerySystemAtomTable(),
     1489                                       WM_XST_NOTIFY_ATOM);
     1490
    11301491        // no error:
    11311492        // return widget classes array
  • trunk/src/3rdparty/os2/xsystray/xsystray.h

    r272 r273  
    1717#define XSYSTRAY_HEADER_INCLUDED
    1818
     19#include "xsystray_api.h"
     20
     21#include <sys/builtin.h>        // atomics
     22
    1923#define XSYSTRAY_VERSION_MAJOR 0
    2024#define XSYSTRAY_VERSION_MINOR 1
     
    2630#define INTCLASS_WIDGET_XSYSTRAY        "ExtendedSysTray"
    2731#define HUMANSTR_WIDGET_XSYSTRAY        "Extended system tray"
     32
     33#define WM_XST_CREATED_ATOM             "ExtendedSysTray.WM_XST_CREATED"
     34#define WM_XST_NOTIFY_ATOM              "ExtendedSysTray.WM_XST_NOTIFY"
    2835
    2936#define WM_XST_CONTROL  (WM_USER + 0)
     
    3845    SYSTRAYCMD_HIDEBALLOON,
    3946} SYSTRAYCMD;
     47
     48/*
     49 *@@ SYSTRAYCTLDATA:
     50 *      Structure holding information accompanying WM_XST_CONTROL messages sent
     51 *      to the system tray server by clients (windows associated with system
     52 *      tray icons).
     53 *
     54 *      NOTE: When you change the size of this structure, you may also need to
     55 *      change CLIENT_MEMORYPOOL_SIZE value (see the comments there for
     56 *      details).
     57 */
    4058
    4159typedef struct
     
    5876        struct
    5977        {
    60             ULONG       ulId;
     78            USHORT      usId;
    6179            HPOINTER    hIcon;
    6280            ULONG       ulMsgId;
     
    6684        struct
    6785        {
    68             ULONG   ulId;
     86            USHORT  usId;
    6987            CHAR    szText[512];
    7088        } tooltip;
     
    7795} SYSTRAYCTLDATA, *PSYSTRAYCTLDATA;
    7896
     97/*
     98 *@@ NOTIFYDATA:
     99 *      Structure holding information acompanying notification messages
     100 *      posted to clients (windows associated with system tray icons) about
     101 *      icon events. This structure unions all public notification code
     102 *      dependent structures defined in xsystray_api.h (starting with XST*).
     103 *
     104 *      All messages posted to the client have an ID corresponding to the
     105 *      WM_XST_NOTIFY_ATOM in the system atom table. The client-side API
     106 *      implementation intercepts these messages (using HK_INPUT), composes a
     107 *      new message given the information in NOTIFYDATA, frees the NOTIFYDATA
     108 *      pointer using FreeNotifyDataPtr() and then sends the composed message to
     109 *      the appropriate window.
     110 *
     111 *      The layout of the XST_NOTIFY message is as follows:
     112 *
     113 *          param1
     114 *              PNOTIFYDATA pNotifyData     pointer to the NOTIFYDATA structure
     115 *
     116 *          param2
     117 *              PVOID       pvMemoryPool    server memory pool (for the
     118 *                                          FreeNotifyDataPtr() call)
     119 *
     120 *      NOTE: When you change the size of this structure, you may also need to
     121 *      change SERVER_MEMORYPOOL_SIZE value in xsystray.c (see the comments
     122 *      there for details).
     123 */
     124
     125typedef struct
     126{
     127    ULONG   msg;
     128            // ID of the message that is to be sent to the target window
     129    MPARAM  mp1;
     130            // message parameter (usually: USHORT usIconId, USHORT usNotifyCode)
     131    MPARAM  mp2;
     132            // message parameter (usually, a pointer to a struct from the union)
     133    union
     134    {
     135        XSTMOUSEMSG     MouseMsg;
     136        XSTCONTEXTMSG   ContextMsg;
     137        XSTWHEELMSG     WheelMsg;
     138    } u;
     139
     140} NOTIFYDATA, *PNOTIFYDATA;
     141
     142// Header of the server-side memory pool
     143typedef struct
     144{
     145    volatile HWND   hwnd;        // owner of the block or NULLHANDLE if free
     146    NOTIFYDATA      NotifyData;  // data
     147
     148} MEMPOOLBLK, *PMEMPOOLBLK;
     149
     150// allocation unit in the server-side memory pool
     151typedef struct
     152{
     153    ULONG ulBeyond;         // address of the first byte beyond the memory pool
     154
     155    volatile ULONG ulNeedsCommit;   // address of the first decommitted byte
     156    volatile ULONG ulNext;          // address of next possibly free block
     157
     158    MEMPOOLBLK aBlocks[0];          // fake array for easier addressing
     159
     160} MEMPOOLHDR, *PMEMPOOLHDR;
     161
     162/*
     163 *@@ FreeNotifyDataPtr:
     164 *      Frees the NOTIFYDATA structure allocated by AllocNotifyDataPtr().
     165 *
     166 *      See AllocNotifyDataPtr() for more details about allocating these
     167 *      structures.dd
     168 */
     169
     170inline
     171VOID FreeNotifyDataPtr(PVOID pvMemoryPool,  // in: memory pool base address
     172                       HWND hwndOwner,      // in: owner of the struct to free
     173                       PNOTIFYDATA pData)   // in: address of the struct to free
     174{
     175    PMEMPOOLHDR pHdr = (PMEMPOOLHDR)pvMemoryPool;
     176    PMEMPOOLBLK pBlk = (PMEMPOOLBLK)((ULONG)pData - sizeof(HWND));
     177
     178    ULONG ulNext = pHdr->ulNext;
     179
     180    __atomic_cmpxchg32((uint32_t *)&pBlk->hwnd, NULLHANDLE, hwndOwner);
     181
     182    // if the next possible free block is greater than we just freed,
     183    // set it to us (to minimize the amount of committed pages)
     184    if (ulNext > (ULONG)pBlk)
     185        __atomic_cmpxchg32((uint32_t *)&pHdr->ulNext, (ULONG)pBlk, ulNext);
     186}
     187
    79188#endif // XSYSTRAY_HEADER_INCLUDED
    80189
  • trunk/src/3rdparty/os2/xsystray/xsystray_api.c

    r272 r273  
    2828#include <sys/builtin.h>        // atomics
    2929
    30 static HWND G_hwndSysTray = NULLHANDLE;
    31             // window handle of the system tray server
    32 
    33 static PVOID G_pvMemoryPool = NULL;
    34              // memory pool for SYSTRAYCTLDATA structs used by WM_XST_CONTROL
    35              // messages. Note that once allocated, this memory is never freed:
    36              // it is intentional since the memory is assumed to be always in
    37              // need and that the system will free it when the application
    38              // terminates
    39 
    40 #define MEMORYPOOL_SIZE 65536
    41         // taking SYSTRAYCTLDATA size into account, this is enough for at least
    42         // 64 threads sending WM_XST_CONTROL simultaneously, which sounds sane
     30static
     31volatile HWND G_hwndSysTray = NULLHANDLE;
     32              // window handle of the system tray server
     33
     34static
     35volatile PVOID G_pvMemoryPool = NULL;
     36               // shared memory pool for SYSTRAYCTLDATA structs used by
     37               // WM_XST_CONTROL messages. Note that once allocated, this memory
     38               // is never freed: it is intentional since the memory is assumed
     39               // to be always in need and that the system will free it when the
     40               // application terminates
     41
     42#define CLIENT_MEMORYPOOL_SIZE 65536
     43        // taking SYSTRAYCTLDATA size into account (<=1024 B), this is enough
     44        // for at least 64 threads sending WM_XST_CONTROL simultaneously, which
     45        // sounds sane
    4346
    4447// @todo to be on the safe side with casting in __atomic_cmpxchg32() we need
     
    116119}
    117120
    118 // This function allocates a SYSTRAYCTLDATA struct in the pool of shared memory.
    119 // If there is no free space in the pool, it returns NULL. The allocated memory
    120 // must be freed by FreeSysTrayCtlDataPtr() when not needed.
     121/*
     122 *@@ AllocSysTrayCtlDataPtr:
     123 *      Allocates a SYSTRAYCTLDATA struct in the pool of shared memory.
     124 *
     125 *      If there is no free space in the pool, it returns NULL. The allocated
     126 *      memory must be freed by FreeSysTrayCtlDataPtr() when not needed.
     127 */
     128
    121129static PSYSTRAYCTLDATA AllocSysTrayCtlDataPtr()
    122130{
     
    128136    {
    129137        // Note: we don't PAG_COMMIT, DosSubAllocMem will do so when needed
    130         arc = DosAllocSharedMem((PVOID)&pvPool, NULL, MEMORYPOOL_SIZE,
     138        arc = DosAllocSharedMem((PVOID)&pvPool, NULL, CLIENT_MEMORYPOOL_SIZE,
    131139                                PAG_READ | PAG_WRITE | OBJ_GIVEABLE);
    132140        if (arc == NO_ERROR)
    133141            arc = DosSubSetMem(pvPool,
    134142                               DOSSUB_INIT | DOSSUB_SPARSE_OBJ,
    135                                MEMORYPOOL_SIZE);
     143                               CLIENT_MEMORYPOOL_SIZE);
    136144        if (!__atomic_cmpxchg32((uint32_t *)&G_pvMemoryPool,
    137145                                (uint32_t)pvPool, (uint32_t)NULL))
     
    149157    }
    150158
    151     arc = DosSubAllocMem(G_pvMemoryPool, (PVOID)&pData, sizeof(SYSTRAYCTLDATA));
     159    arc = DosSubAllocMem(G_pvMemoryPool, (PVOID)&pData, sizeof(*pData));
    152160    if (arc != NO_ERROR)
    153161        return NULL;
     
    158166static VOID FreeSysTrayCtlDataPtr(PSYSTRAYCTLDATA pData)
    159167{
    160     DosSubFreeMem(G_pvMemoryPool, pData, sizeof(SYSTRAYCTLDATA));
     168    DosSubFreeMem(G_pvMemoryPool, pData, sizeof(*pData));
    161169}
    162170
     
    220228 *
    221229 *          param1
    222  *              USHORT  usID        icon ID
    223  *              USHORT  usCode      notify code, one of XST_IN_ constants
     230 *              USHORT  usIconID        icon ID
     231 *              USHORT  usNotifyCode    notify code, one of XST_IN_ constants
    224232 *
    225233 *          param2
    226  *              PVOID   pData       notify code specific data (see below)
     234 *              PVOID   pData           notify code specific data (see below)
    227235 *
    228236 *      The following notify codes are currently recognized:
     
    232240 *              messages are recognized. param2 is a pointer to the XSTMOUSEMSG
    233241 *              structure containing full mouse message details.
     242 *
     243 *          XST_IN_CONTEXT:
     244 *              Context menu event in the icon area. param2 is a pointer to the
     245 *              XSTCONTEXTMSG structure containing full message details.
     246 *
     247 *          XST_IN_WHEEL:
     248 *              Mouse wheel event in the icon area. param2 is a pointer to the
     249 *              XSTWHEELTMSG structure containing full message details.
    234250 */
    235251
    236252BOOL xstAddSysTrayIcon(HWND hwnd,       // in: window handle associated with the icon
    237                        ULONG ulId,      // in: icon ID to add
     253                       USHORT usId,     // in: icon ID to add
    238254                       HPOINTER hIcon,  // in: icon handle
    239255                       ULONG ulMsgId,   // in: message ID for notifications
     
    252268        pData->ulCommand = SYSTRAYCMD_ADDICON;
    253269        pData->hwndSender = hwnd;
    254         pData->u.icon.ulId = ulId;
     270        pData->u.icon.usId = usId;
    255271        pData->u.icon.hIcon = hIcon;
    256272        pData->u.icon.ulMsgId = ulMsgId;
     
    278294
    279295BOOL xstRemoveSysTrayIcon(HWND hwnd,    // in: window handle associated with the icon
    280                           ULONG ulId)   // in: icon ID to remove
     296                          USHORT usId)  // in: icon ID to remove
    281297{
    282298    BOOL brc;
     
    287303    pData->ulCommand = SYSTRAYCMD_REMOVEICON;
    288304    pData->hwndSender = hwnd;
    289     pData->u.icon.ulId = ulId;
     305    pData->u.icon.usId = usId;
    290306
    291307    brc = SendSysTrayCtlMsg(pData);
     
    314330
    315331BOOL xstSetSysTrayIconToolTip(HWND hwnd,    // in: window handle associated with the icon
    316                               ULONG ulId,   // in: icon ID to set the tooltip for
     332                              USHORT usId,  // in: icon ID to set the tooltip for
    317333                              PSZ pszText)  // in: tooltip text
    318334{
     
    324340    pData->ulCommand = SYSTRAYCMD_SETTOOLTIP;
    325341    pData->hwndSender = hwnd;
    326     pData->u.tooltip.ulId = ulId;
     342    pData->u.tooltip.usId = usId;
    327343
    328344    if (pszText == NULL)
     
    343359}
    344360
    345 BOOL xstShowSysTrayIconBalloon(HWND hwnd, ULONG ulId, PSZ pszTitle, PSZ pszText,
     361BOOL xstShowSysTrayIconBalloon(HWND hwnd, USHORT usId, PSZ pszTitle, PSZ pszText,
    346362                               ULONG ulFlags, ULONG ulTimeout)
    347363{
     
    350366}
    351367
    352 BOOL xstHideSysTrayIconBalloon(HWND hwnd, ULONG ulId)
     368BOOL xstHideSysTrayIconBalloon(HWND hwnd, USHORT usId)
    353369{
    354370    // @todo implement
     
    364380 *      Returns TRUE on success and FALSE otherwise.
    365381 */
    366 BOOL xstQuerySysTrayIconRect(HWND hwnd, ULONG ulId, PRECTL prclRect)
     382BOOL xstQuerySysTrayIconRect(HWND hwnd, USHORT usId, PRECTL prclRect)
    367383{
    368384    // @todo implement
     
    384400ULONG xstGetSysTrayCreatedMsgId()
    385401{
    386     // NOTE: keep in sync with fnwpXSysTray()::WM_CREATED
    387 
    388402    static ULONG WM_XST_CREATED = 0;
    389403    if (WM_XST_CREATED == 0)
    390404        WM_XST_CREATED = WinAddAtom(WinQuerySystemAtomTable(),
    391                                     "ExtendedSysTray.WM_XST_CREATED");
     405                                    WM_XST_CREATED_ATOM);
    392406    return WM_XST_CREATED;
    393407}
  • trunk/src/3rdparty/os2/xsystray/xsystray_api.h

    r256 r273  
    2424// tray (refer to xstAddSysTrayIcon() for details)
    2525#define XST_IN_MOUSE    0x0001
     26#define XST_IN_CONTEXT  0x0002
     27#define XST_IN_WHEEL    0x0003
    2628
    2729// structure for XST_IN_MOUSE
     
    2931{
    3032    ULONG  ulMouseMsg;
     33           // mouse message (one of WM_BUTTONxyyy)
    3134    POINTS ptsPointerPos;
     35           // global pointer position at the time of the mouse event
    3236    USHORT fsHitTestRes;
     37           // hit-test result (see WM_BUTTONxyyy description in PM)
    3338    USHORT fsFlags;
     39           // keyboard control codes (see WM_BUTTONxyyy description in PM)
    3440
    3541} XSTMOUSEMSG, *PXSTMOUSEMSG;
    3642
     43// structure for XST_IN_CONTEXT
     44typedef struct
     45{
     46    POINTS ptsPointerPos;
     47           // global pointer position at the time of the mouse event
     48    USHORT fPointer;
     49           // input device flag (see WM_CONTEXTMENU description in PM)
     50
     51} XSTCONTEXTMSG, *PXSTCONTEXTMSG;
     52
     53// structure for XST_IN_WHEEL
     54typedef struct
     55{
     56    ULONG  ulWheelMsg;
     57           // mouse message (one of WM_HSCROLL or WM_VSCROLL)
     58    POINTS ptsPointerPos;
     59           // global pointer position at the time of the mouse event
     60    USHORT usCmd;
     61           // command (see WM_HSCROLL/WM_VSCROLL description in PM)
     62
     63} XSTWHEELMSG, *PXSTWHEELMSG;
     64
    3765BOOL xstQuerySysTrayVersion(PULONG pulMajor, PULONG pulMinor, PULONG pulRevision);
    38 BOOL xstAddSysTrayIcon(HWND hwnd, ULONG ulId, HPOINTER hIcon, ULONG ulMsgId,
     66BOOL xstAddSysTrayIcon(HWND hwnd, USHORT usId, HPOINTER hIcon, ULONG ulMsgId,
    3967                       ULONG ulFlags);
    40 BOOL xstRemoveSysTrayIcon(HWND hwnd, ULONG ulId);
    41 BOOL xstSetSysTrayIconToolTip(HWND hwnd, ULONG ulId, PSZ pszText);
    42 BOOL xstShowSysTrayIconBalloon(HWND hwnd, ULONG ulId, PSZ pszTitle, PSZ pszText,
     68BOOL xstRemoveSysTrayIcon(HWND hwnd, USHORT usId);
     69BOOL xstSetSysTrayIconToolTip(HWND hwnd, USHORT usId, PSZ pszText);
     70BOOL xstShowSysTrayIconBalloon(HWND hwnd, USHORT usId, PSZ pszTitle, PSZ pszText,
    4371                               ULONG ulFlags, ULONG ulTimeout);
    44 BOOL xstHideSysTrayIconBalloon(HWND hwnd, ULONG ulId);
     72BOOL xstHideSysTrayIconBalloon(HWND hwnd, USHORT usId);
    4573
    46 BOOL xstQuerySysTrayIconRect(HWND hwnd, ULONG ulId, PRECTL prclRect);
     74BOOL xstQuerySysTrayIconRect(HWND hwnd, USHORT usId, PRECTL prclRect);
    4775
    4876ULONG xstGetSysTrayCreatedMsgId();
Note: See TracChangeset for help on using the changeset viewer.