Changeset 265


Ignore:
Timestamp:
Oct 29, 2009, 2:13:16 AM (16 years ago)
Author:
Dmitry A. Kuminov
Message:

3rdparty: os2/xsystray: Implemented adding an icon to the system tray (one icon so far) and automatically removing it if the associated window gets destroyed w/o doing so (for example, as a result of unexpected application termination).

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

Legend:

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

    r256 r265  
    7676
    7777// primitive debug logging to a file
    78 #if 1
     78#if 0
    7979static void __LOG_WORKER(const char *fmt, ...)
    8080{
     
    133133typedef struct
    134134{
     135    LONG        lIconWidth;
     136                // system icon width in px
     137    LONG        lIconHeight;
     138                // system icon height in px
     139    LONG        lIconPad;
     140                // padding around each icon in px
    135141    PICONDATA   pIcons;
    136142                // array of icons currently shown in the system tray
    137                 // (left to right)
    138143    size_t      cIcons;
    139144                // number of icons in the pIcons array
     
    143148} SYSTRAYDATA, *PSYSTRAYDATA;
    144149
    145 ULONG QWL_USER_SERVER_DATA = 0;
     150static ULONG QWL_USER_SERVER_DATA = 0;
     151             // offset to the PXCENTERWIDGET pointer in the widget data array
     152
     153#define TID_CHECKALIVE          1
     154         // check alive timer
     155#define TID_CHECKALIVE_TIMEOUT  1000 // ms
     156         // how often to check if windows associated with icons are still alive
    146157
    147158/* ******************************************************************
     
    240251/* ******************************************************************
    241252 *
     253 *   Helper methods
     254 *
     255 ********************************************************************/
     256
     257VOID FreeIconData(PICONDATA pData)
     258{
     259    pData->hwnd = NULLHANDLE;
     260    pData->ulId = 0;
     261    if (pData->hIcon != NULLHANDLE)
     262    {
     263        WinDestroyPointer(pData->hIcon);
     264        pData->hIcon = NULLHANDLE;
     265
     266    }
     267    pData->ulMsgId = 0;
     268    if (pData->pszToolTip)
     269    {
     270        free(pData->pszToolTip);
     271        pData->pszToolTip = NULL;
     272    }
     273}
     274
     275/* ******************************************************************
     276 *
    242277 *   PM window class implementation
    243278 *
     
    265300                MPARAM mp2)
    266301{
     302    PSYSTRAYDATA pSysTrayData = (PSYSTRAYDATA)pWidget->pUser;
    267303    BOOL brc = FALSE;
    268304
     
    285321            {
    286322                PSIZEL pszl = (PSIZEL)mp2;
    287                 pszl->cx = 30;      // desired width
    288                 pszl->cy = 20;      // desired minimum height
     323                LONG pad2 = pSysTrayData->lIconPad * 2;
     324                pszl->cx = (pSysTrayData->lIconWidth + pad2) * pSysTrayData->cIcons; // desired width
     325                pszl->cy = pSysTrayData->lIconHeight + pad2; // desired minimum height
    289326                brc = TRUE;
    290327            }
     
    297334}
    298335
     336static
     337BOOL DrawPointer(HPS hps, LONG lx, LONG ly, HPOINTER hptrPointer, BOOL bMini)
     338{
     339    return WinDrawPointer(hps, lx, ly, hptrPointer, bMini ? DP_MINI : DP_NORMAL);
     340    // @todo:
     341    // 1) for icons w/o real alpha, draw them manually by correctly selecting
     342    //    the normal or mini HBITMAP (WinDrawPointer fails to do so);
     343    // 2) for icons with real alpha, do manual alpha blending
     344}
     345
    299346/*
    300347 *@@ WgtPaint:
     
    309356              PXCENTERWIDGET pWidget)
    310357{
     358    PSYSTRAYDATA pSysTrayData = (PSYSTRAYDATA)pWidget->pUser;
    311359    HPS hps;
    312     if ((hps = WinBeginPaint(hwnd, NULLHANDLE, NULL)))
    313     {
    314         RECTL   rclWin;
     360    RECTL rclPaint;
     361
     362    if ((hps = WinBeginPaint(hwnd, NULLHANDLE, &rclPaint)))
     363    {
     364        SWP     swp;
     365        RECTL   rcl;
     366        BOOL    bLeftToRight;
     367        LONG    x, lTotalWidth;
     368        size_t  i;
     369
     370        WinQueryWindowPos(hwnd, &swp);
     371        WinQueryWindowRect(pWidget->pGlobals->hwndClient, &rcl);
     372
     373        // correct the paint area
     374        // @todo find out why it exceeds the window bounds
     375        if (rclPaint.xLeft < 0)
     376            rclPaint.xLeft = 0;
     377        if (rclPaint.xRight > swp.cx)
     378            rclPaint.xRight = swp.cx;
     379        if (rclPaint.yBottom < 0)
     380            rclPaint.yBottom = 0;
     381        if (rclPaint.yTop > swp.cy)
     382            rclPaint.yTop = swp.cy;
     383
     384        LOGF(("rclPaint %d,%d-%d,%d\n",
     385              rclPaint.xLeft, rclPaint.xRight, rclPaint.yBottom, rclPaint.yTop));
    315386
    316387        // switch HPS to RGB mode
    317388        GpiCreateLogColorTable(hps, 0, LCOLF_RGB, 0, 0, NULL);
    318389
    319         // now paint
    320         WinQueryWindowRect(hwnd,
    321                            &rclWin);        // exclusive
    322 
    323         WinFillRect(hps,
    324                     &rclWin,                // exclusive
     390        // draw icons left to right if our center is closer to the left edge
     391        // of XCenter and right to left otherwise
     392        bLeftToRight = swp.x + swp.cx / 2 < (rcl.xRight / 2);
     393
     394        WinFillRect(hps, &rclPaint,
    325395                    WinQuerySysColor(HWND_DESKTOP, SYSCLR_DIALOGBACKGROUND, 0));
    326396
    327         // print question mark
    328         WinDrawText(hps,
    329                     1,
    330                     "?",
    331                     &rclWin,                // exclusive
    332                     WinQuerySysColor(HWND_DESKTOP, SYSCLR_WINDOWSTATICTEXT, 0),
    333                     WinQuerySysColor(HWND_DESKTOP, SYSCLR_DIALOGBACKGROUND, 0),
    334                     DT_CENTER | DT_VCENTER);
     397        if (bLeftToRight)
     398            x = pSysTrayData->lIconPad;
     399        else
     400            x = swp.cx - pSysTrayData->lIconPad - pSysTrayData->lIconWidth;
     401
     402        lTotalWidth = pSysTrayData->lIconWidth + pSysTrayData->lIconPad * 2;
     403
     404        // where to start from?
     405        if (bLeftToRight)
     406        {
     407            i = rclPaint.xLeft / lTotalWidth;
     408            x = pSysTrayData->lIconPad + i * lTotalWidth;
     409        }
     410        else
     411        {
     412            i = (swp.cx - rclPaint.xRight) / lTotalWidth;
     413            x = swp.cx - (i + 1) * lTotalWidth + pSysTrayData->lIconPad;
     414        }
     415
     416        // draw as many icons as we can / need
     417        for (i = 0; i < pSysTrayData->cIcons; ++i)
     418        {
     419            if (x >= rclPaint.xRight)
     420                break;
     421
     422            DrawPointer(hps, x, pSysTrayData->lIconPad,
     423                        pSysTrayData->pIcons[i].hIcon, DP_MINI);
     424            if (bLeftToRight)
     425                x += lTotalWidth;
     426            else
     427                x -= lTotalWidth;
     428        }
    335429
    336430        WinEndPaint(hps);
     
    394488
    395489            // initialize the SYSTRAYDATA structure
     490            pSysTrayData->lIconWidth = WinQuerySysValue(HWND_DESKTOP, SV_CXICON) / 2;
     491            pSysTrayData->lIconHeight = WinQuerySysValue(HWND_DESKTOP, SV_CYICON) / 2;
     492            pSysTrayData->lIconPad = pSysTrayData->lIconHeight / 8;
    396493            pSysTrayData->cIconsMax = 4;
    397494            pSysTrayData->pIcons = malloc(sizeof(*pSysTrayData->pIcons) *
     
    459556            size_t i;
    460557            for (i = 0; i < pSysTrayData->cIcons; ++i)
    461             {
    462                 if (pSysTrayData->pIcons[i].pszToolTip)
    463                     free(pSysTrayData->pIcons[i].pszToolTip);
    464             }
     558                FreeIconData(&pSysTrayData->pIcons[i]);
    465559            free(pSysTrayData->pIcons);
    466560            free(pSysTrayData);
     
    484578 *      implementation for WM_XST_CONTROL in fnwpXSysTrayServer.
    485579 *
    486  *      Serves as an entry point for all client-side requests to the Extended
    487  *      system tray.
     580 *      Serves as an entry point for all client-side API requests to the
     581 *      Extended system tray.
    488582 *
    489583 *      Note that this message is being sent from another process which is
     
    497591{
    498592    BOOL brc = FALSE;
     593    PSYSTRAYDATA pSysTrayData = (PSYSTRAYDATA)pWidget->pUser;
    499594
    500595    switch (pCtlData->ulCommand)
     
    512607        break;
    513608
     609        case SYSTRAYCMD_ADDICON:
     610        {
     611            POINTERINFO Info;
     612            HPOINTER hIcon = NULLHANDLE;
     613
     614            LOGF(("SYSTRAYCMD_ADDICON\n"));
     615            LOGF(("hIcon %x\n", pCtlData->u.icon.hIcon));
     616
     617            pCtlData->bAcknowledged = TRUE;
     618
     619            // make a private copy of the provided icon (it will get lost after
     620            // we return from this message)
     621            brc = WinQueryPointerInfo(pCtlData->u.icon.hIcon, &Info);
     622            if (!brc)
     623                break;
     624            hIcon = WinCreatePointerIndirect(HWND_DESKTOP, &Info);
     625            if (hIcon == NULLHANDLE)
     626            {
     627                brc = FALSE;
     628                break;
     629            }
     630
     631            // @todo just testing....
     632            if (pSysTrayData->pIcons[0].hIcon != NULLHANDLE)
     633                WinDestroyPointer(pSysTrayData->pIcons[0].hIcon);
     634            pSysTrayData->cIcons = 1;
     635            pSysTrayData->pIcons[0].hwnd = pCtlData->hwndSender;
     636            pSysTrayData->pIcons[0].ulId = pCtlData->u.icon.ulId;
     637            pSysTrayData->pIcons[0].hIcon = hIcon;
     638            pSysTrayData->pIcons[0].ulMsgId = pCtlData->u.icon.ulMsgId;
     639
     640            // ask XCenter to take our new size into account
     641            // (this will also invalidate us)
     642            WinPostMsg(pWidget->pGlobals->hwndClient,
     643                       XCM_REFORMAT,
     644                       (MPARAM)XFMF_GETWIDGETSIZES,
     645                       0);
     646
     647            if (pSysTrayData->cIcons == 1)
     648            {
     649                // start a timer to perform "is window alive" checks
     650                WinStartTimer(pWidget->habWidget, hwnd,
     651                              TID_CHECKALIVE,
     652                              TID_CHECKALIVE_TIMEOUT);
     653            }
     654
     655            brc = TRUE;
     656        }
     657
    514658        default:
    515659            break;
    516660    }
    517661
     662    LOGF(("return %d (WinGetLastError is %x)\n",
     663          brc, WinGetLastError(pWidget->habWidget)));
     664
    518665    return brc;
     666}
     667
     668/*
     669 *@@ WgtXSysTrayTimer:
     670 *      implementation for WM_TIMER in fnwpXSysTrayServer.
     671 */
     672
     673static
     674VOID WgtXSysTrayTimer(HWND hwnd, PXCENTERWIDGET pWidget,
     675                      USHORT usTimerId)
     676{
     677    PSYSTRAYDATA pSysTrayData = (PSYSTRAYDATA)pWidget->pUser;
     678
     679    if (usTimerId == TID_CHECKALIVE)
     680    {
     681        // check if windows associated with the icons are still alive
     682        // and remove those icons whose windows are invalid
     683        BOOL bAnyDead = FALSE;
     684        size_t i;
     685        for (i = 0; i < pSysTrayData->cIcons; ++i)
     686        {
     687            if (!WinIsWindow(pWidget->habWidget, pSysTrayData->pIcons[i].hwnd))
     688            {
     689                bAnyDead = TRUE;
     690                FreeIconData(&pSysTrayData->pIcons[i]);
     691                // hwnd is NULLHANDLE here
     692            }
     693        }
     694
     695        if (bAnyDead)
     696        {
     697            // compact the icon array
     698            i = 0;
     699            while (i < pSysTrayData->cIcons)
     700            {
     701                if (pSysTrayData->pIcons[i].hwnd == NULLHANDLE)
     702                {
     703                    --pSysTrayData->cIcons;
     704                    if (pSysTrayData->cIcons > 0)
     705                    {
     706                        memcpy(&pSysTrayData->pIcons[i],
     707                               &pSysTrayData->pIcons[i + 1],
     708                               sizeof(*pSysTrayData->pIcons) * (pSysTrayData->cIcons - i));
     709                    }
     710                }
     711                else
     712                    ++i;
     713            }
     714
     715            if (pSysTrayData->cIcons == 0)
     716            {
     717                // stop the check alive timer
     718                WinStopTimer(pWidget->habWidget, hwnd,
     719                              TID_CHECKALIVE);
     720            }
     721
     722            // ask XCenter to take our new size into account
     723            // (this will also invalidate us)
     724            WinPostMsg(pWidget->pGlobals->hwndClient,
     725                       XCM_REFORMAT,
     726                       (MPARAM)XFMF_GETWIDGETSIZES,
     727                       0);
     728        }
     729    }
    519730}
    520731
     
    556767            mrc = (MRESULT)WgtXSysTrayControl(hwnd, pWidget,
    557768                                              (PSYSTRAYCTLDATA)mp1);
     769        break;
     770
     771        /*
     772         * WM_TIMER:
     773         *      timer event.
     774         */
     775
     776        case WM_TIMER:
     777            WgtXSysTrayTimer(hwnd, pWidget, SHORT1FROMMP(mp1));
    558778        break;
    559779
  • trunk/src/3rdparty/os2/xsystray/xsystray_api.c

    r256 r265  
    1515
    1616#define INCL_DOSERRORS
     17#define INCL_DOSPROCESS
    1718#define INCL_WINWINDOWMGR
    1819#define INCL_WINATOM
     20#define INCL_WINPOINTERS
    1921#include <os2.h>
    2022
     
    98100}
    99101
     102// This function returns a per-thread SYSTRAYCTLDATA pointer. We communicate
     103// to the server thread using WinSendMsg() which allows us to reuse a single
     104// memory block for all calls (WinSendMsg() doesn't return until the server is
     105// done with processing the message).
    100106static PSYSTRAYCTLDATA GetSysTrayCtlDataPtr()
    101107{
     
    105111    if (G_itlsSysTrayCtlData == -1)
    106112    {
    107         // @todo does XWorkplace have its own TLS? Not? Use
    108         // DosAllocThreadLocalMemory() directly then (though it's not nice due
    109         // to the lack of space in that area)
     113        // @todo does XWorkplace have its own TLS? Or is it built with GCC? Not?
     114        // Use DosAllocThreadLocalMemory() directly then (though it's not nice
     115        // due to the too limited amount of memory space in that area)
    110116        int itls = __libc_TLSAlloc();
    111117        if (!__atomic_cmpxchg32(&G_itlsSysTrayCtlData, itls, -1))
     
    159165                            PULONG pulRevision) // out: revision number
    160166{
     167    BOOL brc;
    161168    PSYSTRAYCTLDATA pData = GetSysTrayCtlDataPtr();
    162169    if (!pData)
     
    166173    pData->hwndSender = NULLHANDLE;
    167174
    168     BOOL brc = SendSysTrayCtlMsg(pData);
     175    brc = SendSysTrayCtlMsg(pData);
    169176    if (brc)
    170177    {
     
    215222                       ULONG ulFlags)   // in: flags (not currently used, must be 0)
    216223{
     224    BOOL brc;
     225    PPIB ppib;
    217226    PSYSTRAYCTLDATA pData = GetSysTrayCtlDataPtr();
    218227    if (!pData)
     228        return FALSE;
     229
     230    // give all processes temporary access to hIcon
     231    brc = WinSetPointerOwner(hIcon, 0, FALSE);
     232    if (!brc)
    219233        return FALSE;
    220234
     
    225239    pData->u.icon.ulMsgId = ulMsgId;
    226240
    227     return SendSysTrayCtlMsg(pData);
     241    brc = SendSysTrayCtlMsg(pData);
     242
     243    // revoke temporary access to hIcon
     244    DosGetInfoBlocks(NULL, &ppib);
     245    WinSetPointerOwner(hIcon, ppib->pib_ulpid, TRUE);
     246
     247    return brc;
    228248}
    229249
Note: See TracChangeset for help on using the changeset viewer.