| 31 | | static int G_itlsSysTrayCtlData = -1; |
| 32 | | |
| 33 | | static HWND FindSysTrayWindow() |
| | 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 |
| | 43 | |
| | 44 | // @todo to be on the safe side with casting in __atomic_cmpxchg32() we need |
| | 45 | // compile-time assertions like this: |
| | 46 | // AssertCompile(sizeof(uint32_t) == sizeof(HWND)); |
| | 47 | // AssertCompile(sizeof(uint32_t) == sizeof(PVOID)); |
| | 48 | |
| | 49 | static HWND FindSysTrayServerWindow() |
| 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). |
| 106 | | static PSYSTRAYCTLDATA GetSysTrayCtlDataPtr() |
| | 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 | static PSYSTRAYCTLDATA AllocSysTrayCtlDataPtr() |
| 109 | | |
| 110 | | // allocate a thread local storage entry if not done so |
| 111 | | if (G_itlsSysTrayCtlData == -1) |
| 112 | | { |
| 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) |
| 116 | | int itls = __libc_TLSAlloc(); |
| 117 | | if (!__atomic_cmpxchg32(&G_itlsSysTrayCtlData, itls, -1)) |
| | 124 | PVOID pvPool; |
| | 125 | PSYSTRAYCTLDATA pData; |
| | 126 | |
| | 127 | if (!G_pvMemoryPool) |
| | 128 | { |
| | 129 | // Note: we don't PAG_COMMIT, DosSubAllocMem will do so when needed |
| | 130 | arc = DosAllocSharedMem((PVOID)&pvPool, NULL, MEMORYPOOL_SIZE, |
| | 131 | PAG_READ | PAG_WRITE | OBJ_GIVEABLE); |
| | 132 | if (arc == NO_ERROR) |
| | 133 | arc = DosSubSetMem(pvPool, |
| | 134 | DOSSUB_INIT | DOSSUB_SPARSE_OBJ, |
| | 135 | MEMORYPOOL_SIZE); |
| | 136 | if (!__atomic_cmpxchg32((uint32_t *)&G_pvMemoryPool, |
| | 137 | (uint32_t)pvPool, (uint32_t)NULL)) |
| 123 | | |
| 124 | | if (G_itlsSysTrayCtlData == -1) |
| 125 | | return NULL; |
| 126 | | } |
| 127 | | |
| 128 | | // allocate a SYSTRAYCTLDATA struct for this thread if not done so |
| 129 | | PSYSTRAYCTLDATA pData = __libc_TLSGet(G_itlsSysTrayCtlData); |
| 130 | | if (!pData) |
| 131 | | { |
| 132 | | arc = DosAllocSharedMem((PVOID)&pData, NULL, sizeof(SYSTRAYCTLDATA), |
| 133 | | PAG_COMMIT | PAG_READ | PAG_WRITE | OBJ_GIVEABLE); |
| 134 | | if (arc != NO_ERROR) |
| 135 | | return NULL; |
| 136 | | |
| 137 | | __libc_TLSSet(G_itlsSysTrayCtlData, pData); |
| 138 | | |
| 139 | | // note that we don't ever free the allocated block since our API doesn't |
| 140 | | // have a concept of initialization/termination and therefore it's fine |
| 141 | | // if the memory stays allocated until application termination |
| 142 | | } |
| | 143 | else |
| | 144 | { |
| | 145 | // we could fail to allocate while being the first... give up |
| | 146 | if (arc != NO_ERROR) |
| | 147 | return NULL; |
| | 148 | } |
| | 149 | } |
| | 150 | |
| | 151 | arc = DosSubAllocMem(G_pvMemoryPool, (PVOID)&pData, sizeof(SYSTRAYCTLDATA)); |
| | 152 | if (arc != NO_ERROR) |
| | 153 | return NULL; |
| 232 | | if (!brc) |
| 233 | | return FALSE; |
| 234 | | |
| 235 | | pData->ulCommand = SYSTRAYCMD_ADDICON; |
| 236 | | pData->hwndSender = hwnd; |
| 237 | | pData->u.icon.ulId = ulId; |
| 238 | | pData->u.icon.hIcon = hIcon; |
| 239 | | pData->u.icon.ulMsgId = ulMsgId; |
| 240 | | |
| 241 | | brc = SendSysTrayCtlMsg(pData); |
| 242 | | |
| 243 | | // revoke temporary access to hIcon |
| 244 | | DosGetInfoBlocks(NULL, &ppib); |
| 245 | | WinSetPointerOwner(hIcon, ppib->pib_ulpid, TRUE); |
| | 250 | if (brc) |
| | 251 | { |
| | 252 | pData->ulCommand = SYSTRAYCMD_ADDICON; |
| | 253 | pData->hwndSender = hwnd; |
| | 254 | pData->u.icon.ulId = ulId; |
| | 255 | pData->u.icon.hIcon = hIcon; |
| | 256 | pData->u.icon.ulMsgId = ulMsgId; |
| | 257 | |
| | 258 | brc = SendSysTrayCtlMsg(pData); |
| | 259 | |
| | 260 |