| 1 |
|
|---|
| 2 | /*
|
|---|
| 3 | *@@sourcefile xsystray.c:
|
|---|
| 4 | * Extended system tray widget for XCenter/eCenter.
|
|---|
| 5 | *
|
|---|
| 6 | * Implementation.
|
|---|
| 7 | *
|
|---|
| 8 | * Copyright (C) 2009 Dmitry A. Kuminov
|
|---|
| 9 | *
|
|---|
| 10 | * This file is part of the Extended system tray widget source package.
|
|---|
| 11 | * Extended system tray widget is free software; you can redistribute it
|
|---|
| 12 | * and/or modify it under the terms of the GNU General Public License as
|
|---|
| 13 | * published by the Free Software Foundation, in version 2 as it comes in
|
|---|
| 14 | * the "COPYING" file of the Extended system tray widget distribution. This
|
|---|
| 15 | * program is distributed in the hope that it will be useful, but WITHOUT
|
|---|
| 16 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
|---|
| 17 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
|---|
| 18 | * more details.
|
|---|
| 19 | */
|
|---|
| 20 |
|
|---|
| 21 | #pragma strings(readonly)
|
|---|
| 22 |
|
|---|
| 23 | /*
|
|---|
| 24 | * Suggested #include order:
|
|---|
| 25 | * 1) os2.h
|
|---|
| 26 | * 2) C library headers
|
|---|
| 27 | * 3) setup.h (code generation and debugging options)
|
|---|
| 28 | * 4) headers in helpers\
|
|---|
| 29 | * 5) at least one SOM implementation header (*.ih)
|
|---|
| 30 | * 6) dlgids.h, headers in shared\ (as needed)
|
|---|
| 31 | * 7) headers in implementation dirs (e.g. filesys\, as needed)
|
|---|
| 32 | * 8) #pragma hdrstop and then more SOM headers which crash with precompiled headers
|
|---|
| 33 | */
|
|---|
| 34 |
|
|---|
| 35 | #define INCL_BASE
|
|---|
| 36 | #define INCL_PM
|
|---|
| 37 | #include <os2.h>
|
|---|
| 38 |
|
|---|
| 39 | // C library headers
|
|---|
| 40 | #include <stdio.h>
|
|---|
| 41 | #include <string.h>
|
|---|
| 42 | #include <stdlib.h>
|
|---|
| 43 | #include <stdarg.h>
|
|---|
| 44 |
|
|---|
| 45 | // generic headers
|
|---|
| 46 | // If this file were part of the XWorkplace sources, we'd now include
|
|---|
| 47 | // the generic "setup.h" file, which has common set up code for every
|
|---|
| 48 | // single XWorkplace code file. But it's not, so we won't include that.
|
|---|
| 49 | // #include "setup.h" // code generation and debugging options
|
|---|
| 50 |
|
|---|
| 51 | // headers in /helpers
|
|---|
| 52 | // This would be the place to include headers from the "XWorkplace helpers".
|
|---|
| 53 | // But since we do a minimal sample here, we can't include those helpful
|
|---|
| 54 | // routines... again, see the src\widgets in the XWorkplace source code
|
|---|
| 55 | // for how these functions can be imported from XFLDR.DLL to avoid duplicate
|
|---|
| 56 | // code.
|
|---|
| 57 | // #include "helpers\dosh.h" // Control Program helper routines
|
|---|
| 58 | // #include "helpers\gpih.h" // GPI helper routines
|
|---|
| 59 | // #include "helpers\prfh.h" // INI file helper routines;
|
|---|
| 60 | // this include is required for some
|
|---|
| 61 | // of the structures in shared\center.h
|
|---|
| 62 | // #include "helpers\winh.h" // PM helper routines
|
|---|
| 63 | // #include "helpers\xstring.h" // extended string helpers
|
|---|
| 64 |
|
|---|
| 65 | // XWorkplace implementation headers
|
|---|
| 66 | // If this file were part of the XCenter sources, we'd now include
|
|---|
| 67 | // "center.h" from the "include\shared" directory. Since we're not
|
|---|
| 68 | // part of the XCenter sources here, we include that file from the
|
|---|
| 69 | // "toolkit" directory in the binary release. That file is identical
|
|---|
| 70 | // to "include\shared\center.h" in the XWorkplace sources.
|
|---|
| 71 | #include "shared\center.h" // public XCenter interfaces
|
|---|
| 72 |
|
|---|
| 73 | #include "xsystray.h"
|
|---|
| 74 |
|
|---|
| 75 | #pragma hdrstop // VAC++ keeps crashing otherwise
|
|---|
| 76 |
|
|---|
| 77 | // copy paste from helpers\comctl.h
|
|---|
| 78 | // @todo not necessary when we become part of XWorkplace
|
|---|
| 79 |
|
|---|
| 80 | #define TTN_NEEDTEXT 1000
|
|---|
| 81 | #define TTN_SHOW 1001
|
|---|
| 82 | #define TTN_POP 1002
|
|---|
| 83 |
|
|---|
| 84 | #define TTFMT_PSZ 0x01
|
|---|
| 85 | #define TTFMT_STRINGRES 0x02
|
|---|
| 86 |
|
|---|
| 87 | typedef struct _TOOLTIPTEXT
|
|---|
| 88 | {
|
|---|
| 89 | HWND hwndTooltip;
|
|---|
| 90 | HWND hwndTool;
|
|---|
| 91 | ULONG ulFormat;
|
|---|
| 92 | PSZ pszText;
|
|---|
| 93 | HMODULE hmod;
|
|---|
| 94 | ULONG idResource;
|
|---|
| 95 | } TOOLTIPTEXT, *PTOOLTIPTEXT;
|
|---|
| 96 |
|
|---|
| 97 | #define TTM_FIRST (WM_USER + 1000)
|
|---|
| 98 | #define TTM_UPDATETIPTEXT (TTM_FIRST + 9)
|
|---|
| 99 | #define TTM_SHOWTOOLTIPNOW (TTM_FIRST + 17)
|
|---|
| 100 |
|
|---|
| 101 | // primitive debug logging to a file
|
|---|
| 102 | #if 0
|
|---|
| 103 | static void __LOG_WORKER(const char *fmt, ...)
|
|---|
| 104 | {
|
|---|
| 105 | static FILE *f = NULL;
|
|---|
| 106 | if (f == NULL)
|
|---|
| 107 | {
|
|---|
| 108 | f = fopen("c:\\xsystray.dbg", "a");
|
|---|
| 109 | setbuf(f, NULL);
|
|---|
| 110 | }
|
|---|
| 111 | if (f != NULL)
|
|---|
| 112 | {
|
|---|
| 113 | va_list vl;
|
|---|
| 114 | va_start(vl, fmt);
|
|---|
| 115 | vfprintf(f, fmt, vl);
|
|---|
| 116 | va_end(vl);
|
|---|
| 117 | }
|
|---|
| 118 | }
|
|---|
| 119 | #define LOG(m) do { __LOG_WORKER m; } while(0)
|
|---|
| 120 | #define LOGF(m) do { __LOG_WORKER("%s: ", __FUNCTION__); __LOG_WORKER m; } while(0)
|
|---|
| 121 | #else
|
|---|
| 122 | #define LOG(m) do {} while (0)
|
|---|
| 123 | #define LOGF(m) do {} while (0)
|
|---|
| 124 | #endif
|
|---|
| 125 |
|
|---|
| 126 | /* ******************************************************************
|
|---|
| 127 | *
|
|---|
| 128 | * Private definitions
|
|---|
| 129 | *
|
|---|
| 130 | ********************************************************************/
|
|---|
| 131 |
|
|---|
| 132 | /*
|
|---|
| 133 | *@@ ICONDATA:
|
|---|
| 134 | * Per-icon data.
|
|---|
| 135 | */
|
|---|
| 136 |
|
|---|
| 137 | typedef struct
|
|---|
| 138 | {
|
|---|
| 139 | HWND hwnd;
|
|---|
| 140 | // associated window
|
|---|
| 141 | USHORT usId;
|
|---|
| 142 | // icon ID
|
|---|
| 143 | HPOINTER hIcon;
|
|---|
| 144 | // icon handle
|
|---|
| 145 | ULONG ulMsgId;
|
|---|
| 146 | // message ID for notifications
|
|---|
| 147 | PSZ pszToolTip;
|
|---|
| 148 | // icon tooltip (NULL if none)
|
|---|
| 149 | BOOL bIsToolTipShowing;
|
|---|
| 150 | // whether the tooltip is currently shown
|
|---|
| 151 | BOOL bMemoryPoolGiven;
|
|---|
| 152 | // TRUE if SYSTRAYDATA::pvMemoryPool is already given to
|
|---|
| 153 | // the process hwnd belongs to
|
|---|
| 154 |
|
|---|
| 155 | } ICONDATA, *PICONDATA;
|
|---|
| 156 |
|
|---|
| 157 | /*
|
|---|
| 158 | *@@ SYSTRAYDATA:
|
|---|
| 159 | * Global system tray data.
|
|---|
| 160 | */
|
|---|
| 161 |
|
|---|
| 162 | typedef struct
|
|---|
| 163 | {
|
|---|
| 164 | HWND hwndServer;
|
|---|
| 165 | // systtem tray server window handle
|
|---|
| 166 | LONG lIconWidth;
|
|---|
| 167 | // system icon width in px
|
|---|
| 168 | LONG lIconHeight;
|
|---|
| 169 | // system icon height in px
|
|---|
| 170 | LONG lIconPad;
|
|---|
| 171 | // padding around each icon in px
|
|---|
| 172 | PICONDATA pIcons;
|
|---|
| 173 | // array of icons currently shown in the system tray
|
|---|
| 174 | size_t cIcons;
|
|---|
| 175 | // number of icons in the pIcons array
|
|---|
| 176 | size_t cIconsMax;
|
|---|
| 177 | // maximum number of icons pIcons can fit
|
|---|
| 178 | CHAR szToolTip[sizeof(((PSYSTRAYCTLDATA)0)->u.icon.szToolTip)];
|
|---|
| 179 | // "static" buffer for the tooltip (XCenter requirement)
|
|---|
| 180 | PVOID pvMemoryPool;
|
|---|
| 181 | // memory pool for NOTIFYDATA structures
|
|---|
| 182 |
|
|---|
| 183 | } SYSTRAYDATA, *PSYSTRAYDATA;
|
|---|
| 184 |
|
|---|
| 185 | #define ICONARRAY_GROW 4
|
|---|
| 186 | // number of element the icon array is increased by when there is no
|
|---|
| 187 | // space for the newly added icon
|
|---|
| 188 |
|
|---|
| 189 | #define SERVER_MEMORYPOOL_SIZE 65536
|
|---|
| 190 | // taking NOTIFYDATA size into account (<=32 B), this is enough for at
|
|---|
| 191 | // least 2048 simultaneous notification messages, which (even taking
|
|---|
| 192 | // slowly responsing clients into account) sounds sane since in most
|
|---|
| 193 | // cases the structure is freed once it reaches the target event queue
|
|---|
| 194 | // and before a message created as a copy of it is sent to the target
|
|---|
| 195 | // window procedure
|
|---|
| 196 |
|
|---|
| 197 | #define TID_CHECKALIVE 1
|
|---|
| 198 | // timer that checks if windows associated with icons are still alive
|
|---|
| 199 | #define TID_CHECKALIVE_TIMEOUT 2000 // ms
|
|---|
| 200 | // how often to perform alive checks
|
|---|
| 201 |
|
|---|
| 202 | static ULONG WM_XST_CREATED = 0;
|
|---|
| 203 | // identity of the WM_XST_CREATED message taken from the atom table
|
|---|
| 204 | static ULONG WM_XST_NOTIFY = 0;
|
|---|
| 205 | // identity of the WM_XST_NOTIFY message taken from the atom table
|
|---|
| 206 |
|
|---|
| 207 | static ULONG QWL_USER_SERVER_DATA = 0;
|
|---|
| 208 | // offset to the PXCENTERWIDGET pointer in the widget data array
|
|---|
| 209 |
|
|---|
| 210 | static
|
|---|
| 211 | VOID WgtXSysTrayUpdateAfterIconAddRemove(PXCENTERWIDGET pWidget);
|
|---|
| 212 |
|
|---|
| 213 | /* ******************************************************************
|
|---|
| 214 | *
|
|---|
| 215 | * XCenter widget class definition
|
|---|
| 216 | *
|
|---|
| 217 | ********************************************************************/
|
|---|
| 218 |
|
|---|
| 219 | /*
|
|---|
| 220 | * This contains the name of the PM window class and
|
|---|
| 221 | * the XCENTERWIDGETCLASS definition(s) for the widget
|
|---|
| 222 | * class(es) in this DLL.
|
|---|
| 223 | *
|
|---|
| 224 | * The address of this structure (or an array of these
|
|---|
| 225 | * structures, if there were several widget classes in
|
|---|
| 226 | * this plugin) is returned by the "init" export
|
|---|
| 227 | * (WgtInitModule).
|
|---|
| 228 | */
|
|---|
| 229 |
|
|---|
| 230 | static const XCENTERWIDGETCLASS G_WidgetClasses[] =
|
|---|
| 231 | {
|
|---|
| 232 | {
|
|---|
| 233 | WNDCLASS_WIDGET_XSYSTRAY, // PM window class name
|
|---|
| 234 | 0, // additional flag, not used here
|
|---|
| 235 | INTCLASS_WIDGET_XSYSTRAY, // internal widget class name
|
|---|
| 236 | HUMANSTR_WIDGET_XSYSTRAY, // widget class name displayed to user
|
|---|
| 237 | WGTF_UNIQUEGLOBAL | // widget class flags
|
|---|
| 238 | WGTF_TOOLTIP,
|
|---|
| 239 | NULL // no settings dialog
|
|---|
| 240 | }
|
|---|
| 241 | };
|
|---|
| 242 |
|
|---|
| 243 | /* ******************************************************************
|
|---|
| 244 | *
|
|---|
| 245 | * Function imports from XFLDR.DLL
|
|---|
| 246 | *
|
|---|
| 247 | ********************************************************************/
|
|---|
| 248 |
|
|---|
| 249 | /*
|
|---|
| 250 | * To reduce the size of the widget DLL, it can
|
|---|
| 251 | * be compiled with the VAC subsystem libraries.
|
|---|
| 252 | * In addition, instead of linking frequently
|
|---|
| 253 | * used helpers against the DLL again, you can
|
|---|
| 254 | * import them from XFLDR.DLL, whose module handle
|
|---|
| 255 | * is given to you in the INITMODULE export.
|
|---|
| 256 | *
|
|---|
| 257 | * Note that importing functions from XFLDR.DLL
|
|---|
| 258 | * is _not_ a requirement. We can't do this in
|
|---|
| 259 | * this minimal sample anyway without having access
|
|---|
| 260 | * to the full XWorkplace source code.
|
|---|
| 261 | *
|
|---|
| 262 | * If you want to know how you can import the useful
|
|---|
| 263 | * functions from XFLDR.DLL to use them in your widget
|
|---|
| 264 | * plugin, again, see src\widgets in the XWorkplace sources.
|
|---|
| 265 | * The actual imports would then be made by WgtInitModule.
|
|---|
| 266 | */
|
|---|
| 267 |
|
|---|
| 268 | // @todo the function declarations should become not necessary when we move into
|
|---|
| 269 | // XWorkplace. Let's hope the prototypes will not change until then. Let's also
|
|---|
| 270 | // pray that XFLDRxxx.DLL has the _Optlink calling convention for exports and
|
|---|
| 271 | // not the default __cdecl (which happens if it builds with GCC according to the
|
|---|
| 272 | // XWPENTRY definition in the current xwphelpers sources)
|
|---|
| 273 |
|
|---|
| 274 | #define XWPENTRY _Optlink
|
|---|
| 275 |
|
|---|
| 276 | typedef VOID XWPENTRY GPIHDRAW3DFRAME(HPS hps,
|
|---|
| 277 | PRECTL prcl,
|
|---|
| 278 | USHORT usWidth,
|
|---|
| 279 | LONG lColorLeft,
|
|---|
| 280 | LONG lColorRight);
|
|---|
| 281 | typedef GPIHDRAW3DFRAME *PGPIHDRAW3DFRAME;
|
|---|
| 282 | PGPIHDRAW3DFRAME pgpihDraw3DFrame = NULL;
|
|---|
| 283 |
|
|---|
| 284 | typedef struct _RESOLVEFUNCTION
|
|---|
| 285 | {
|
|---|
| 286 | const char *pcszFunctionName;
|
|---|
| 287 | PFN *ppFuncAddress;
|
|---|
| 288 | } RESOLVEFUNCTION, *PRESOLVEFUNCTION;
|
|---|
| 289 | RESOLVEFUNCTION G_aImports[] =
|
|---|
| 290 | {
|
|---|
| 291 | { "gpihDraw3DFrame", (PFN*)&pgpihDraw3DFrame },
|
|---|
| 292 | };
|
|---|
| 293 |
|
|---|
| 294 | /* ******************************************************************
|
|---|
| 295 | *
|
|---|
| 296 | * Private widget instance data
|
|---|
| 297 | *
|
|---|
| 298 | ********************************************************************/
|
|---|
| 299 |
|
|---|
| 300 | // None presently. The samples in src\widgets in the XWorkplace
|
|---|
| 301 | // sources cleanly separate setup string data from other widget
|
|---|
| 302 | // instance data to allow for easier manipulation with settings
|
|---|
| 303 | // dialogs. We have skipped this for the minimal sample.
|
|---|
| 304 |
|
|---|
| 305 | /* ******************************************************************
|
|---|
| 306 | *
|
|---|
| 307 | * Widget setup management
|
|---|
| 308 | *
|
|---|
| 309 | ********************************************************************/
|
|---|
| 310 |
|
|---|
| 311 | // None presently. See above.
|
|---|
| 312 |
|
|---|
| 313 | /* ******************************************************************
|
|---|
| 314 | *
|
|---|
| 315 | * Widget settings dialog
|
|---|
| 316 | *
|
|---|
| 317 | ********************************************************************/
|
|---|
| 318 |
|
|---|
| 319 | // None currently. To see how a setup dialog can be done,
|
|---|
| 320 | // see the "window list" widget in the XWorkplace sources
|
|---|
| 321 | // (src\widgets\w_winlist.c).
|
|---|
| 322 |
|
|---|
| 323 | /* ******************************************************************
|
|---|
| 324 | *
|
|---|
| 325 | * Callbacks stored in XCENTERWIDGETCLASS
|
|---|
| 326 | *
|
|---|
| 327 | ********************************************************************/
|
|---|
| 328 |
|
|---|
| 329 | // If you implement a settings dialog, you must write a
|
|---|
| 330 | // "show settings dlg" function and store its function pointer
|
|---|
| 331 | // in XCENTERWIDGETCLASS.
|
|---|
| 332 |
|
|---|
| 333 | /* ******************************************************************
|
|---|
| 334 | *
|
|---|
| 335 | * Helper methods
|
|---|
| 336 | *
|
|---|
| 337 | ********************************************************************/
|
|---|
| 338 |
|
|---|
| 339 | /*
|
|---|
| 340 | *@@ FreeIconData:
|
|---|
| 341 | * Frees all members of the ICONDATA structure and resets them to 0.
|
|---|
| 342 | */
|
|---|
| 343 |
|
|---|
| 344 | static
|
|---|
| 345 | VOID FreeIconData(PICONDATA pData)
|
|---|
| 346 | {
|
|---|
| 347 | pData->hwnd = NULLHANDLE;
|
|---|
| 348 | pData->usId = 0;
|
|---|
| 349 | if (pData->hIcon != NULLHANDLE)
|
|---|
| 350 | {
|
|---|
| 351 | WinDestroyPointer(pData->hIcon);
|
|---|
| 352 | pData->hIcon = NULLHANDLE;
|
|---|
| 353 |
|
|---|
| 354 | }
|
|---|
| 355 | pData->ulMsgId = 0;
|
|---|
| 356 | if (pData->pszToolTip)
|
|---|
| 357 | {
|
|---|
| 358 | free(pData->pszToolTip);
|
|---|
| 359 | pData->pszToolTip = NULL;
|
|---|
| 360 | }
|
|---|
| 361 | }
|
|---|
| 362 |
|
|---|
| 363 | /*
|
|---|
| 364 | *@@ FindIconData:
|
|---|
| 365 | * Searches for the icon with the given identity. Returns NULL if not
|
|---|
| 366 | * found.
|
|---|
| 367 | */
|
|---|
| 368 |
|
|---|
| 369 | static
|
|---|
| 370 | PICONDATA FindIconData(PSYSTRAYDATA pSysTrayData,
|
|---|
| 371 | HWND hwnd, // in: associated window handle
|
|---|
| 372 | USHORT usId, // in: icon ID
|
|---|
| 373 | size_t *pIdx) // out: index of the icon in the icon array
|
|---|
| 374 | // (optional, may be NULL)
|
|---|
| 375 | {
|
|---|
| 376 | size_t i;
|
|---|
| 377 | for (i = 0; i < pSysTrayData->cIcons; ++i)
|
|---|
| 378 | {
|
|---|
| 379 | if (pSysTrayData->pIcons[i].hwnd == hwnd &&
|
|---|
| 380 | pSysTrayData->pIcons[i].usId == usId)
|
|---|
| 381 | {
|
|---|
| 382 | if (pIdx)
|
|---|
| 383 | *pIdx = i;
|
|---|
| 384 | return &pSysTrayData->pIcons[i];
|
|---|
| 385 | }
|
|---|
| 386 | }
|
|---|
| 387 |
|
|---|
| 388 | if (pIdx)
|
|---|
| 389 | *pIdx = i;
|
|---|
| 390 | return NULL;
|
|---|
| 391 | }
|
|---|
| 392 |
|
|---|
| 393 | /*
|
|---|
| 394 | *@@ FindIconDataAtPt:
|
|---|
| 395 | * Searches for the icon under the given point.
|
|---|
| 396 | * Returns NULL if no icon found (e.g. the pad space).
|
|---|
| 397 | *
|
|---|
| 398 | * Refer to WgtPaint() for system tray geometry description.
|
|---|
| 399 | */
|
|---|
| 400 |
|
|---|
| 401 | static
|
|---|
| 402 | PICONDATA FindIconDataAtPt(PXCENTERWIDGET pWidget,
|
|---|
| 403 | PPOINTL pptl, // point coordinates (relative to systray)
|
|---|
| 404 | size_t *pIdx) // out: index of the icon in the icon array
|
|---|
| 405 | // (optional, may be NULL)
|
|---|
| 406 | {
|
|---|
| 407 | PSYSTRAYDATA pSysTrayData = (PSYSTRAYDATA)pWidget->pUser;
|
|---|
| 408 |
|
|---|
| 409 | SWP swp;
|
|---|
| 410 | RECTL rcl;
|
|---|
| 411 | BOOL bLeftToRight;
|
|---|
| 412 | LONG y, lIconStep;
|
|---|
| 413 | size_t i;
|
|---|
| 414 |
|
|---|
| 415 | // start with invalid index index
|
|---|
| 416 | if (pIdx)
|
|---|
| 417 | *pIdx = pSysTrayData->cIcons;
|
|---|
| 418 |
|
|---|
| 419 | WinQueryWindowPos(pWidget->hwndWidget, &swp);
|
|---|
| 420 | WinQueryWindowRect(pWidget->pGlobals->hwndClient, &rcl);
|
|---|
| 421 |
|
|---|
| 422 | y = (swp.cy - pSysTrayData->lIconHeight) / 2;
|
|---|
| 423 | if (pptl->y < y || pptl->y >= y + pSysTrayData->lIconHeight)
|
|---|
| 424 | return NULL; // hit pad space
|
|---|
| 425 |
|
|---|
| 426 | // detect the direction
|
|---|
| 427 | bLeftToRight = swp.x + swp.cx / 2 < (rcl.xRight / 2);
|
|---|
| 428 |
|
|---|
| 429 | lIconStep = pSysTrayData->lIconWidth + pSysTrayData->lIconPad;
|
|---|
| 430 |
|
|---|
| 431 | // which icon is that?
|
|---|
| 432 | if (bLeftToRight)
|
|---|
| 433 | {
|
|---|
| 434 | i = pptl->x / lIconStep;
|
|---|
| 435 | if (pptl->x % lIconStep < pSysTrayData->lIconPad)
|
|---|
| 436 | return NULL; // hit pad space
|
|---|
| 437 | }
|
|---|
| 438 | else
|
|---|
| 439 | {
|
|---|
| 440 | i = (swp.cx - pptl->x - 1) / lIconStep;
|
|---|
| 441 | if ((swp.cx - pptl->x - 1) % lIconStep < pSysTrayData->lIconPad)
|
|---|
| 442 | return NULL; // hit pad space
|
|---|
| 443 | }
|
|---|
| 444 | if (i >= pSysTrayData->cIcons)
|
|---|
| 445 | return NULL; // hit pad space
|
|---|
| 446 |
|
|---|
| 447 | if (pIdx)
|
|---|
| 448 | *pIdx = i;
|
|---|
| 449 | return &pSysTrayData->pIcons[i];
|
|---|
| 450 | }
|
|---|
| 451 |
|
|---|
| 452 | static
|
|---|
| 453 | VOID FreeSysTrayData(PSYSTRAYDATA pSysTrayData)
|
|---|
| 454 | {
|
|---|
| 455 | // destroy the server
|
|---|
| 456 | if (pSysTrayData->hwndServer != NULLHANDLE)
|
|---|
| 457 | {
|
|---|
| 458 | WinDestroyWindow(pSysTrayData->hwndServer);
|
|---|
| 459 | pSysTrayData->hwndServer = NULLHANDLE;
|
|---|
| 460 | }
|
|---|
| 461 |
|
|---|
| 462 | // free all system tray data
|
|---|
| 463 | if (pSysTrayData->pvMemoryPool)
|
|---|
| 464 | {
|
|---|
| 465 | DosFreeMem(pSysTrayData->pvMemoryPool);
|
|---|
| 466 | }
|
|---|
| 467 | if (pSysTrayData->pIcons)
|
|---|
| 468 | {
|
|---|
| 469 | size_t i;
|
|---|
| 470 | for (i = 0; i < pSysTrayData->cIcons; ++i)
|
|---|
| 471 | FreeIconData(&pSysTrayData->pIcons[i]);
|
|---|
| 472 | pSysTrayData->cIcons = 0;
|
|---|
| 473 | free(pSysTrayData->pIcons);
|
|---|
| 474 | pSysTrayData->pIcons = NULL;
|
|---|
| 475 | }
|
|---|
| 476 |
|
|---|
| 477 | free(pSysTrayData);
|
|---|
| 478 | }
|
|---|
| 479 |
|
|---|
| 480 | /*
|
|---|
| 481 | *@@ AllocNotifyDataPtr:
|
|---|
| 482 | * Allocates a SYSTRAYCTLDATA struct in the pool of shared memory on belalf
|
|---|
| 483 | * of the client window identified by pIconData->hwnd.
|
|---|
| 484 | *
|
|---|
| 485 | * If there is no free space in the pool, it returns NULL. On success,
|
|---|
| 486 | * fills in msg and mp1 fields of the returned structure using the
|
|---|
| 487 | * information provided in pIconData.
|
|---|
| 488 | *
|
|---|
| 489 | * Note that the allocated structure is supposed to be freed using
|
|---|
| 490 | * FreeNotifyDataPtr by the client-side API implementation in another
|
|---|
| 491 | * process.
|
|---|
| 492 | */
|
|---|
| 493 | static
|
|---|
| 494 | PNOTIFYDATA AllocNotifyDataPtr(PVOID pvMemoryPool, // in: memory pool base address
|
|---|
| 495 | PICONDATA pIconData) // in: icon data
|
|---|
| 496 | {
|
|---|
| 497 | // NOTE: we cannot use DosSubAllocMem() and friends since we want to be able
|
|---|
| 498 | // to free blocks allocated to clients which death we detect but we cannot
|
|---|
| 499 | // be sure about the layout of memory DosSub API uses. Therefore, we provide
|
|---|
| 500 | // our own sub-allocation scheme which is rather simple because we need to
|
|---|
| 501 | // allocate equally sized blocks (each is NOTIFYDATA struct). The memory
|
|---|
| 502 | // pool is laid out as follows: MEMPOOLHDR followed by a number of
|
|---|
| 503 | // MEMPOOLBLK.
|
|---|
| 504 |
|
|---|
| 505 | APIRET arc;
|
|---|
| 506 | PID pid;
|
|---|
| 507 | TID tid;
|
|---|
| 508 | PMEMPOOLHDR pHdr;
|
|---|
| 509 | ULONG ulMax, ulNeedsCommit, ulNext, ulCurr;
|
|---|
| 510 | PNOTIFYDATA pData;
|
|---|
| 511 |
|
|---|
| 512 | LOGF(("pvMemoryPool %p\n", pvMemoryPool));
|
|---|
| 513 | LOGF(("hwnd %lx\n", pIconData->hwnd));
|
|---|
| 514 |
|
|---|
| 515 | if (!pIconData->bMemoryPoolGiven)
|
|---|
| 516 | {
|
|---|
| 517 | LOGF(("Giving memory pool to %lx\n", pIconData->hwnd));
|
|---|
| 518 |
|
|---|
| 519 | arc = ERROR_INVALID_HANDLE;
|
|---|
| 520 | if (WinQueryWindowProcess(pIconData->hwnd, &pid, &tid))
|
|---|
| 521 | arc = DosGiveSharedMem(pvMemoryPool, pid, PAG_READ | PAG_WRITE);
|
|---|
| 522 | if (arc != NO_ERROR)
|
|---|
| 523 | return NULL;
|
|---|
| 524 |
|
|---|
| 525 | pIconData->bMemoryPoolGiven = TRUE;
|
|---|
| 526 | }
|
|---|
| 527 |
|
|---|
| 528 | pHdr = (PMEMPOOLHDR)pvMemoryPool;
|
|---|
| 529 |
|
|---|
| 530 | // maximum address that is still enough for a block
|
|---|
| 531 | ulMax = pHdr->ulBeyond - sizeof(MEMPOOLBLK);
|
|---|
| 532 |
|
|---|
| 533 | ulNeedsCommit = pHdr->ulNeedsCommit;
|
|---|
| 534 | ulNext = pHdr->ulNext;
|
|---|
| 535 | ulCurr = ulNext;
|
|---|
| 536 |
|
|---|
| 537 | LOGF(("ulNeedsCommit %p\n", ulNeedsCommit));
|
|---|
| 538 | LOGF(("ulNext %p\n", ulNext));
|
|---|
| 539 |
|
|---|
| 540 | do
|
|---|
| 541 | {
|
|---|
| 542 | if (ulCurr >= ulNeedsCommit)
|
|---|
| 543 | {
|
|---|
| 544 | // commit more memory; it's OK two or more threads will do the same
|
|---|
| 545 | DosSetMem((PVOID)ulNeedsCommit, 4096,
|
|---|
| 546 | PAG_COMMIT | PAG_READ | PAG_WRITE);
|
|---|
| 547 | // advance the address (only if nobody has already done so -- they
|
|---|
| 548 | // could already commit more than we did)
|
|---|
| 549 | __atomic_cmpxchg32((volatile uint32_t *)&pHdr->ulNeedsCommit,
|
|---|
| 550 | ulNeedsCommit + 4096, ulNeedsCommit);
|
|---|
| 551 | }
|
|---|
| 552 |
|
|---|
| 553 | if (__atomic_cmpxchg32((volatile uint32_t *)ulCurr,
|
|---|
| 554 | pIconData->hwnd, NULLHANDLE))
|
|---|
| 555 | break;
|
|---|
| 556 |
|
|---|
| 557 | ulCurr += sizeof(MEMPOOLBLK);
|
|---|
| 558 | if (ulCurr > ulMax)
|
|---|
| 559 | // start over
|
|---|
| 560 | ulCurr = ((ULONG)pvMemoryPool) + sizeof(MEMPOOLHDR);
|
|---|
| 561 |
|
|---|
| 562 | if (ulCurr == ulNext)
|
|---|
| 563 | return NULL; // no free blocks!
|
|---|
| 564 | }
|
|---|
| 565 | while (1);
|
|---|
| 566 |
|
|---|
| 567 | LOGF(("ulCurr %p\n", ulCurr));
|
|---|
| 568 |
|
|---|
| 569 | // memorize a pointer to the new struct
|
|---|
| 570 | pData = &((PMEMPOOLBLK)ulCurr)->NotifyData;
|
|---|
| 571 |
|
|---|
| 572 | // advance to the next possibly free block
|
|---|
| 573 | ulCurr += sizeof(MEMPOOLBLK);
|
|---|
| 574 | if (ulCurr > ulMax)
|
|---|
| 575 | // start over
|
|---|
| 576 | ulCurr = ((ULONG)pvMemoryPool) + sizeof(MEMPOOLHDR);
|
|---|
| 577 |
|
|---|
| 578 | // store the new next address until someone else has already done that
|
|---|
| 579 | __atomic_cmpxchg32((volatile uint32_t *)&pHdr->ulNext, ulCurr, ulNext);
|
|---|
| 580 |
|
|---|
| 581 | // fill in parts of the allocated NOTIFYDATA
|
|---|
| 582 | memset(pData, 0, sizeof(*pData));
|
|---|
| 583 |
|
|---|
| 584 | pData->msg = pIconData->ulMsgId;
|
|---|
| 585 | pData->mp1 = MPFROMSHORT(pIconData->usId);
|
|---|
| 586 |
|
|---|
| 587 | return pData;
|
|---|
| 588 | }
|
|---|
| 589 |
|
|---|
| 590 | /*
|
|---|
| 591 | *@@ PostNotifyMsg:
|
|---|
| 592 | * Posts WM_XST_NOTIFY to the given client window. Frees pNotifyData if
|
|---|
| 593 | * posting fails.
|
|---|
| 594 | */
|
|---|
| 595 |
|
|---|
| 596 | VOID PostNotifyMsg(PSYSTRAYDATA pSysTrayData, HWND hwnd,
|
|---|
| 597 | PNOTIFYDATA pNotifyData)
|
|---|
| 598 | {
|
|---|
| 599 | if (!WinPostMsg(hwnd, WM_XST_NOTIFY, pNotifyData, pSysTrayData->pvMemoryPool))
|
|---|
| 600 | FreeNotifyDataPtr(pSysTrayData->pvMemoryPool, hwnd, pNotifyData);
|
|---|
| 601 | }
|
|---|
| 602 |
|
|---|
| 603 | /*
|
|---|
| 604 | *@@ DrawPointer:
|
|---|
| 605 | * Draws a pointer in a presentation space.
|
|---|
| 606 | */
|
|---|
| 607 |
|
|---|
| 608 | static
|
|---|
| 609 | BOOL DrawPointer(HPS hps, LONG lx, LONG ly, HPOINTER hptrPointer, BOOL bMini)
|
|---|
| 610 | {
|
|---|
| 611 | return WinDrawPointer(hps, lx, ly, hptrPointer, bMini ? DP_MINI : DP_NORMAL);
|
|---|
| 612 | // @todo: for icons with real alpha, do manual alpha blending
|
|---|
| 613 | }
|
|---|
| 614 |
|
|---|
| 615 | /* ******************************************************************
|
|---|
| 616 | *
|
|---|
| 617 | * PM window class implementation
|
|---|
| 618 | *
|
|---|
| 619 | ********************************************************************/
|
|---|
| 620 |
|
|---|
| 621 | /*
|
|---|
| 622 | * This code has the actual PM window class.
|
|---|
| 623 | *
|
|---|
| 624 | */
|
|---|
| 625 |
|
|---|
| 626 | /*
|
|---|
| 627 | *@@ MwgtControl:
|
|---|
| 628 | * implementation for WM_CONTROL in fnwpXSysTray.
|
|---|
| 629 | *
|
|---|
| 630 | * The XCenter communicates with widgets thru
|
|---|
| 631 | * WM_CONTROL messages. At the very least, the
|
|---|
| 632 | * widget should respond to XN_QUERYSIZE because
|
|---|
| 633 | * otherwise it will be given some dumb default
|
|---|
| 634 | * size.
|
|---|
| 635 | */
|
|---|
| 636 |
|
|---|
| 637 | static
|
|---|
| 638 | BOOL WgtControl(PXCENTERWIDGET pWidget,
|
|---|
| 639 | MPARAM mp1,
|
|---|
| 640 | MPARAM mp2)
|
|---|
| 641 | {
|
|---|
| 642 | PSYSTRAYDATA pSysTrayData = (PSYSTRAYDATA)pWidget->pUser;
|
|---|
| 643 | BOOL brc = FALSE;
|
|---|
| 644 |
|
|---|
| 645 | USHORT usID = SHORT1FROMMP(mp1),
|
|---|
| 646 | usNotifyCode = SHORT2FROMMP(mp1);
|
|---|
| 647 |
|
|---|
| 648 | // is this from the XCenter client?
|
|---|
| 649 | if (usID == ID_XCENTER_CLIENT)
|
|---|
| 650 | {
|
|---|
| 651 | // yes:
|
|---|
| 652 |
|
|---|
| 653 | switch (usNotifyCode)
|
|---|
| 654 | {
|
|---|
| 655 | /*
|
|---|
| 656 | * XN_QUERYSIZE:
|
|---|
| 657 | * XCenter wants to know our size.
|
|---|
| 658 | */
|
|---|
| 659 |
|
|---|
| 660 | case XN_QUERYSIZE:
|
|---|
| 661 | {
|
|---|
| 662 | PSIZEL pszl = (PSIZEL)mp2;
|
|---|
| 663 | LONG pad = pSysTrayData->lIconPad;
|
|---|
| 664 | size_t cnt = pSysTrayData->cIcons;
|
|---|
| 665 | // desired width
|
|---|
| 666 | if (cnt)
|
|---|
| 667 | pszl->cx = pad + (pSysTrayData->lIconWidth + pad) * cnt;
|
|---|
| 668 | else
|
|---|
| 669 | pszl->cx = 0;
|
|---|
| 670 | // desired minimum height
|
|---|
| 671 | pszl->cy = pSysTrayData->lIconHeight + pad * 2;
|
|---|
| 672 | brc = TRUE;
|
|---|
| 673 | }
|
|---|
| 674 | break;
|
|---|
| 675 |
|
|---|
| 676 | }
|
|---|
| 677 | }
|
|---|
| 678 | else if (usID == ID_XCENTER_TOOLTIP)
|
|---|
| 679 | {
|
|---|
| 680 | PICONDATA pIconData;
|
|---|
| 681 | POINTL ptl;
|
|---|
| 682 |
|
|---|
| 683 | WinQueryMsgPos(pWidget->habWidget, &ptl);
|
|---|
| 684 | // make the coordinates systray-relative
|
|---|
| 685 | WinMapWindowPoints(HWND_DESKTOP, pWidget->hwndWidget, &ptl, 1);
|
|---|
| 686 |
|
|---|
| 687 | pIconData = FindIconDataAtPt(pWidget, &ptl, NULL);
|
|---|
| 688 |
|
|---|
| 689 | switch (usNotifyCode)
|
|---|
| 690 | {
|
|---|
| 691 | case TTN_NEEDTEXT:
|
|---|
| 692 | {
|
|---|
| 693 | LOGF(("TTN_NEEDTEXT\n"));
|
|---|
| 694 |
|
|---|
| 695 | PTOOLTIPTEXT pttt = (PTOOLTIPTEXT)mp2;
|
|---|
| 696 | pttt->ulFormat = TTFMT_PSZ;
|
|---|
| 697 |
|
|---|
| 698 | if (!pIconData || !pIconData->pszToolTip)
|
|---|
| 699 | pttt->pszText = NULL;
|
|---|
| 700 | else
|
|---|
| 701 | {
|
|---|
| 702 | strncpy(pSysTrayData->szToolTip, pIconData->pszToolTip,
|
|---|
| 703 | sizeof(pSysTrayData->szToolTip) - 1);
|
|---|
| 704 | // be on the safe side
|
|---|
| 705 | pSysTrayData->szToolTip[sizeof(pSysTrayData->szToolTip) - 1] = '\0';
|
|---|
| 706 |
|
|---|
| 707 | pttt->pszText = pSysTrayData->szToolTip;
|
|---|
| 708 | }
|
|---|
| 709 |
|
|---|
| 710 | LOGF((" pszText '%s'\n", pttt->pszText));
|
|---|
| 711 | }
|
|---|
| 712 | break;
|
|---|
| 713 |
|
|---|
| 714 | case TTN_SHOW:
|
|---|
| 715 | if (pIconData)
|
|---|
| 716 | pIconData->bIsToolTipShowing = TRUE;
|
|---|
| 717 | break;
|
|---|
| 718 |
|
|---|
| 719 | case TTN_POP:
|
|---|
| 720 | if (pIconData)
|
|---|
| 721 | pIconData->bIsToolTipShowing = FALSE;
|
|---|
| 722 | break;
|
|---|
| 723 | }
|
|---|
| 724 | }
|
|---|
| 725 |
|
|---|
| 726 | return brc;
|
|---|
| 727 | }
|
|---|
| 728 |
|
|---|
| 729 | /*
|
|---|
| 730 | *@@ WgtPaint:
|
|---|
| 731 | * implementation for WM_PAINT in fnwpXSysTray.
|
|---|
| 732 | *
|
|---|
| 733 | * Draws all the icons. If the widget's center is located to the left from
|
|---|
| 734 | * the XCenter's center, icons go left to right. Otherwise, they go right
|
|---|
| 735 | * to left.
|
|---|
| 736 | *
|
|---|
| 737 | * NOTE: This function must be keept in sync with FindIconDataAtPt() and
|
|---|
| 738 | * SYSTRAYCMD_QUERYRECT in terms of system tray geometry.
|
|---|
| 739 | */
|
|---|
| 740 | /*
|
|---|
| 741 | +---------------------------+ p = lIconPad
|
|---|
| 742 | | p | w = lIconWidth
|
|---|
| 743 | | +-------+ +-------+ | h = lIconHeight
|
|---|
| 744 | | p | w | p | w | p |
|
|---|
| 745 | | | h| | h| |
|
|---|
| 746 | | | | | | | If "Frame around statics" is on in XCenter
|
|---|
| 747 | | +-------+ +-------+ | properties, then a 1 px 3D frame is drawn
|
|---|
| 748 | | p | within the pad area. So, lIconPad must
|
|---|
| 749 | +---------------------------+ be at least 2 px.
|
|---|
| 750 | */
|
|---|
| 751 |
|
|---|
| 752 | static
|
|---|
| 753 | VOID WgtPaint(HWND hwnd,
|
|---|
| 754 | PXCENTERWIDGET pWidget)
|
|---|
| 755 | {
|
|---|
| 756 | PSYSTRAYDATA pSysTrayData = (PSYSTRAYDATA)pWidget->pUser;
|
|---|
| 757 | HPS hps;
|
|---|
| 758 | RECTL rclPaint;
|
|---|
| 759 |
|
|---|
| 760 | if ((hps = WinBeginPaint(hwnd, NULLHANDLE, &rclPaint)))
|
|---|
| 761 | {
|
|---|
| 762 | SWP swp;
|
|---|
| 763 | RECTL rcl;
|
|---|
| 764 | BOOL bLeftToRight;
|
|---|
| 765 | LONG x, y, lIconStep;
|
|---|
| 766 | size_t i;
|
|---|
| 767 |
|
|---|
| 768 | WinQueryWindowPos(hwnd, &swp);
|
|---|
| 769 | WinQueryWindowRect(pWidget->pGlobals->hwndClient, &rcl);
|
|---|
| 770 |
|
|---|
| 771 | // correct the paint area
|
|---|
| 772 | // @todo find out why it exceeds the window bounds
|
|---|
| 773 | if (rclPaint.xLeft < 0)
|
|---|
| 774 | rclPaint.xLeft = 0;
|
|---|
| 775 | if (rclPaint.xRight > swp.cx)
|
|---|
| 776 | rclPaint.xRight = swp.cx;
|
|---|
| 777 | if (rclPaint.yBottom < 0)
|
|---|
| 778 | rclPaint.yBottom = 0;
|
|---|
| 779 | if (rclPaint.yTop > swp.cy)
|
|---|
| 780 | rclPaint.yTop = swp.cy;
|
|---|
| 781 |
|
|---|
| 782 | LOGF(("rclPaint %d,%d-%d,%d\n",
|
|---|
| 783 | rclPaint.xLeft, rclPaint.yBottom, rclPaint.xRight, rclPaint.yTop));
|
|---|
| 784 |
|
|---|
| 785 | // switch HPS to RGB mode
|
|---|
| 786 | GpiCreateLogColorTable(hps, 0, LCOLF_RGB, 0, 0, NULL);
|
|---|
| 787 |
|
|---|
| 788 | // draw icons left to right if our center is closer to the left edge
|
|---|
| 789 | // of XCenter and right to left otherwise
|
|---|
| 790 | bLeftToRight = swp.x + swp.cx / 2 < (rcl.xRight / 2);
|
|---|
| 791 |
|
|---|
| 792 | WinFillRect(hps, &rclPaint,
|
|---|
| 793 | WinQuerySysColor(HWND_DESKTOP, SYSCLR_DIALOGBACKGROUND, 0));
|
|---|
| 794 |
|
|---|
| 795 | if ((pWidget->pGlobals->flDisplayStyle & XCS_SUNKBORDERS))
|
|---|
| 796 | {
|
|---|
| 797 | rcl.xLeft = 0;
|
|---|
| 798 | rcl.yBottom = 0;
|
|---|
| 799 | rcl.xRight = swp.cx - 1;
|
|---|
| 800 | rcl.yTop = swp.cy - 1;
|
|---|
| 801 | pgpihDraw3DFrame(hps, &rcl, 1,
|
|---|
| 802 | pWidget->pGlobals->lcol3DDark,
|
|---|
| 803 | pWidget->pGlobals->lcol3DLight);
|
|---|
| 804 | }
|
|---|
| 805 |
|
|---|
| 806 | // always center the icon vertically (we may be given more height than
|
|---|
| 807 | // we requested)
|
|---|
| 808 | y = (swp.cy - pSysTrayData->lIconHeight) / 2;
|
|---|
| 809 |
|
|---|
| 810 | if (bLeftToRight)
|
|---|
| 811 | x = pSysTrayData->lIconPad;
|
|---|
| 812 | else
|
|---|
| 813 | x = swp.cx - pSysTrayData->lIconPad - pSysTrayData->lIconWidth;
|
|---|
| 814 |
|
|---|
| 815 | lIconStep = pSysTrayData->lIconWidth + pSysTrayData->lIconPad;
|
|---|
| 816 |
|
|---|
| 817 | // where to start from?
|
|---|
| 818 | if (bLeftToRight)
|
|---|
| 819 | {
|
|---|
| 820 | i = rclPaint.xLeft / lIconStep;
|
|---|
| 821 | x = pSysTrayData->lIconPad + i * lIconStep;
|
|---|
| 822 | }
|
|---|
| 823 | else
|
|---|
| 824 | {
|
|---|
| 825 | i = (swp.cx - rclPaint.xRight) / lIconStep;
|
|---|
| 826 | x = swp.cx - (i + 1) * lIconStep;
|
|---|
| 827 | // negate the step, for convenience
|
|---|
| 828 | lIconStep = -lIconStep;
|
|---|
| 829 | }
|
|---|
| 830 |
|
|---|
| 831 | // draw as many icons as we can / need
|
|---|
| 832 | for (; i < pSysTrayData->cIcons; ++i)
|
|---|
| 833 | {
|
|---|
| 834 | if (x >= rclPaint.xRight)
|
|---|
| 835 | break;
|
|---|
| 836 |
|
|---|
| 837 | DrawPointer(hps, x, y, pSysTrayData->pIcons[i].hIcon, DP_MINI);
|
|---|
| 838 | x += lIconStep;
|
|---|
| 839 | }
|
|---|
| 840 |
|
|---|
| 841 | WinEndPaint(hps);
|
|---|
| 842 | }
|
|---|
| 843 | }
|
|---|
| 844 |
|
|---|
| 845 | /*
|
|---|
| 846 | *@@ WgtMouse:
|
|---|
| 847 | * implementation for WM_BUTTONxyyy in fnwpXSysTray.
|
|---|
| 848 | *
|
|---|
| 849 | * Posts a notification to the window associated with the icon and returns
|
|---|
| 850 | * TRUE if this mouse message is within the icon bounds. Otherwise returns
|
|---|
| 851 | * FALSE.
|
|---|
| 852 | *
|
|---|
| 853 | * Refer to WgtPaint for more details about the widget geometry.
|
|---|
| 854 | */
|
|---|
| 855 |
|
|---|
| 856 | static
|
|---|
| 857 | BOOL WgtMouse(HWND hwnd, ULONG msg, MRESULT mp1, MRESULT mp2,
|
|---|
| 858 | PXCENTERWIDGET pWidget)
|
|---|
| 859 | {
|
|---|
| 860 | PSYSTRAYDATA pSysTrayData = (PSYSTRAYDATA)pWidget->pUser;
|
|---|
| 861 |
|
|---|
| 862 | POINTL ptl;
|
|---|
| 863 |
|
|---|
| 864 | PICONDATA pIconData;
|
|---|
| 865 | PNOTIFYDATA pNotifyData;
|
|---|
| 866 |
|
|---|
| 867 | ptl.x = ((PPOINTS)&mp1)->x;
|
|---|
| 868 | ptl.y = ((PPOINTS)&mp1)->y;
|
|---|
| 869 |
|
|---|
| 870 | LOGF(("msg %x ptl %ld,%ld\n", msg, ptl.x, ptl.y));
|
|---|
| 871 |
|
|---|
| 872 | pIconData = FindIconDataAtPt(pWidget, &ptl, NULL);
|
|---|
| 873 | if (!pIconData)
|
|---|
| 874 | return FALSE; // hit pad space
|
|---|
| 875 |
|
|---|
| 876 | LOGF(("hwnd %x\n", pIconData->hwnd));
|
|---|
| 877 | LOGF(("usId %d\n", pIconData->usId));
|
|---|
| 878 | LOGF(("hIcon %x\n", pIconData->hIcon));
|
|---|
| 879 |
|
|---|
| 880 | // make the coordinates global
|
|---|
| 881 | WinMapWindowPoints(hwnd, HWND_DESKTOP, &ptl, 1);
|
|---|
| 882 |
|
|---|
| 883 | // allocate a NOTIFYDATA struct
|
|---|
| 884 | pNotifyData = AllocNotifyDataPtr(pSysTrayData->pvMemoryPool, pIconData);
|
|---|
| 885 | if (!pNotifyData)
|
|---|
| 886 | return FALSE;
|
|---|
| 887 |
|
|---|
| 888 | switch (msg)
|
|---|
| 889 | {
|
|---|
| 890 | case WM_HSCROLL:
|
|---|
| 891 | case WM_VSCROLL:
|
|---|
| 892 | pNotifyData->mp1 += XST_IN_WHEEL << 16;
|
|---|
| 893 | pNotifyData->u.WheelMsg.ulWheelMsg = msg;
|
|---|
| 894 | pNotifyData->u.WheelMsg.ptsPointerPos.x = ptl.x;
|
|---|
| 895 | pNotifyData->u.WheelMsg.ptsPointerPos.y = ptl.y;
|
|---|
| 896 | pNotifyData->u.WheelMsg.usCmd = SHORT2FROMMP(mp2);
|
|---|
| 897 | pNotifyData->mp2 = &pNotifyData->u.WheelMsg;
|
|---|
| 898 | break;
|
|---|
| 899 |
|
|---|
| 900 | case WM_CONTEXTMENU:
|
|---|
| 901 | pNotifyData->mp1 += XST_IN_CONTEXT << 16;
|
|---|
| 902 | pNotifyData->u.ContextMsg.ptsPointerPos.x = ptl.x;
|
|---|
| 903 | pNotifyData->u.ContextMsg.ptsPointerPos.y = ptl.y;
|
|---|
| 904 | pNotifyData->u.ContextMsg.fPointer = TRUE;
|
|---|
| 905 | pNotifyData->mp2 = &pNotifyData->u.ContextMsg;
|
|---|
| 906 | break;
|
|---|
| 907 |
|
|---|
| 908 | default:
|
|---|
| 909 | pNotifyData->mp1 += XST_IN_MOUSE << 16;
|
|---|
| 910 | pNotifyData->u.MouseMsg.ulMouseMsg = msg;
|
|---|
| 911 | pNotifyData->u.MouseMsg.ptsPointerPos.x = ptl.x;
|
|---|
| 912 | pNotifyData->u.MouseMsg.ptsPointerPos.y = ptl.y;
|
|---|
| 913 | pNotifyData->u.MouseMsg.fsHitTestRes = SHORT1FROMMP(mp2);
|
|---|
| 914 | pNotifyData->u.MouseMsg.fsFlags = SHORT2FROMMP(mp2);
|
|---|
| 915 | pNotifyData->mp2 = &pNotifyData->u.MouseMsg;
|
|---|
| 916 | break;
|
|---|
| 917 | }
|
|---|
| 918 |
|
|---|
| 919 | PostNotifyMsg(pSysTrayData, pIconData->hwnd, pNotifyData);
|
|---|
| 920 |
|
|---|
| 921 | return TRUE;
|
|---|
| 922 | }
|
|---|
| 923 |
|
|---|
| 924 | /*
|
|---|
| 925 | *@@ fnwpXSysTray:
|
|---|
| 926 | * window procedure for the Extended system tray widget class.
|
|---|
| 927 | *
|
|---|
| 928 | * There are a few rules which widget window procs
|
|---|
| 929 | * must follow. See XCENTERWIDGETCLASS in center.h
|
|---|
| 930 | * for details.
|
|---|
| 931 | *
|
|---|
| 932 | * Other than that, this is a regular window procedure
|
|---|
| 933 | * which follows the basic rules for a PM window class.
|
|---|
| 934 | */
|
|---|
| 935 |
|
|---|
| 936 | static
|
|---|
| 937 | MRESULT EXPENTRY fnwpXSysTray(HWND hwnd, ULONG msg, MPARAM mp1, MPARAM mp2)
|
|---|
| 938 | {
|
|---|
| 939 | // get widget data from QWL_USER (stored there by WM_CREATE)
|
|---|
| 940 | PXCENTERWIDGET pWidget = (PXCENTERWIDGET)WinQueryWindowPtr(hwnd, QWL_USER);
|
|---|
| 941 | // this ptr is valid after WM_CREATE
|
|---|
| 942 |
|
|---|
| 943 | switch (msg)
|
|---|
| 944 | {
|
|---|
| 945 | /*
|
|---|
| 946 | * WM_CREATE:
|
|---|
| 947 | * as with all widgets, we receive a pointer to the
|
|---|
| 948 | * XCENTERWIDGET in mp1, which was created for us.
|
|---|
| 949 | *
|
|---|
| 950 | * The first thing the widget MUST do on WM_CREATE
|
|---|
| 951 | * is to store the XCENTERWIDGET pointer (from mp1)
|
|---|
| 952 | * in the QWL_USER window word by calling:
|
|---|
| 953 | *
|
|---|
| 954 | * WinSetWindowPtr(hwnd, QWL_USER, mp1);
|
|---|
| 955 | *
|
|---|
| 956 | * We could use XCENTERWIDGET.pUser for allocating
|
|---|
| 957 | * another private memory block for our own stuff,
|
|---|
| 958 | * for example to be able to store fonts and colors.
|
|---|
| 959 | * We ain't doing this in the minimal sample.
|
|---|
| 960 | */
|
|---|
| 961 |
|
|---|
| 962 | case WM_CREATE:
|
|---|
| 963 | {
|
|---|
| 964 | LOGF(("WM_CREATE\n"));
|
|---|
| 965 |
|
|---|
| 966 | PSYSTRAYDATA pSysTrayData = NULL;
|
|---|
| 967 | APIRET arc;
|
|---|
| 968 |
|
|---|
| 969 | WinSetWindowPtr(hwnd, QWL_USER, mp1);
|
|---|
| 970 | if ( (!(pWidget = (PXCENTERWIDGET)mp1))
|
|---|
| 971 | || (!pWidget->pfnwpDefWidgetProc)
|
|---|
| 972 | )
|
|---|
| 973 | // shouldn't happen... stop window creation!!
|
|---|
| 974 | return (MRESULT)TRUE;
|
|---|
| 975 |
|
|---|
| 976 | pSysTrayData = malloc(sizeof(*pSysTrayData));
|
|---|
| 977 | if (pSysTrayData == NULL)
|
|---|
| 978 | return (MRESULT)TRUE;
|
|---|
| 979 |
|
|---|
| 980 | // initialize the SYSTRAYDATA structure
|
|---|
| 981 | memset(pSysTrayData, 0, sizeof(*pSysTrayData));
|
|---|
| 982 | pSysTrayData->lIconWidth = WinQuerySysValue(HWND_DESKTOP, SV_CXICON) / 2;
|
|---|
| 983 | pSysTrayData->lIconHeight = WinQuerySysValue(HWND_DESKTOP, SV_CYICON) / 2;
|
|---|
| 984 | pSysTrayData->lIconPad = pSysTrayData->lIconHeight / 8;
|
|---|
| 985 | pSysTrayData->cIconsMax = ICONARRAY_GROW;
|
|---|
| 986 | pSysTrayData->pIcons = malloc(sizeof(*pSysTrayData->pIcons) *
|
|---|
| 987 | pSysTrayData->cIconsMax);
|
|---|
| 988 | if (pSysTrayData->pIcons == NULL)
|
|---|
| 989 | {
|
|---|
| 990 | FreeSysTrayData(pSysTrayData);
|
|---|
| 991 | return (MRESULT)TRUE;
|
|---|
| 992 | }
|
|---|
| 993 | pSysTrayData->cIcons = 0;
|
|---|
| 994 |
|
|---|
| 995 | // Allocate the memory pool for NOTIFYDATA structs (we don't
|
|---|
| 996 | // PAG_COMMIT all memory, AllocNotifyDataPtr() will do so as needed)
|
|---|
| 997 | arc = DosAllocSharedMem((PVOID)&pSysTrayData->pvMemoryPool, NULL,
|
|---|
| 998 | SERVER_MEMORYPOOL_SIZE,
|
|---|
| 999 | PAG_READ | PAG_WRITE | OBJ_GIVEABLE);
|
|---|
| 1000 | if (arc == NO_ERROR)
|
|---|
| 1001 | {
|
|---|
| 1002 | PMEMPOOLHDR pHdr = (PMEMPOOLHDR)pSysTrayData->pvMemoryPool;
|
|---|
| 1003 | arc = DosSetMem(pSysTrayData->pvMemoryPool, 4096,
|
|---|
| 1004 | PAG_COMMIT | PAG_READ | PAG_WRITE);
|
|---|
| 1005 | if (arc == NO_ERROR)
|
|---|
| 1006 | {
|
|---|
| 1007 | pHdr->ulBeyond = (ULONG)pSysTrayData->pvMemoryPool +
|
|---|
| 1008 | SERVER_MEMORYPOOL_SIZE;
|
|---|
| 1009 | pHdr->ulNeedsCommit = (ULONG)pSysTrayData->pvMemoryPool +
|
|---|
| 1010 | 4096;
|
|---|
| 1011 | pHdr->ulNext = (ULONG)pSysTrayData->pvMemoryPool +
|
|---|
| 1012 | sizeof(MEMPOOLHDR);
|
|---|
| 1013 | }
|
|---|
| 1014 | }
|
|---|
| 1015 | if (arc != NO_ERROR)
|
|---|
| 1016 | {
|
|---|
| 1017 | FreeSysTrayData(pSysTrayData);
|
|---|
| 1018 | return (MRESULT)TRUE;
|
|---|
| 1019 | }
|
|---|
| 1020 |
|
|---|
| 1021 | // create the "server" window (note that we pass the XCENTERWIDGET
|
|---|
| 1022 | // pointer on to it)
|
|---|
| 1023 | pSysTrayData->hwndServer =
|
|---|
| 1024 | WinCreateWindow(HWND_DESKTOP, WNDCLASS_WIDGET_XSYSTRAY_SERVER,
|
|---|
| 1025 | NULL, WS_MINIMIZED,
|
|---|
| 1026 | 0, 0, 0, 0,
|
|---|
| 1027 | HWND_DESKTOP, HWND_BOTTOM,
|
|---|
| 1028 | 0, mp1, NULL);
|
|---|
| 1029 | if (pSysTrayData->hwndServer == NULLHANDLE)
|
|---|
| 1030 | {
|
|---|
| 1031 | FreeSysTrayData(pSysTrayData);
|
|---|
| 1032 | return (MRESULT)TRUE;
|
|---|
| 1033 | }
|
|---|
| 1034 |
|
|---|
| 1035 | pWidget->pUser = pSysTrayData;
|
|---|
| 1036 |
|
|---|
| 1037 | // inform all interested parties that we are fired up
|
|---|
| 1038 | WinBroadcastMsg(HWND_DESKTOP, WM_XST_CREATED,
|
|---|
| 1039 | NULL, NULL, BMSG_POST);
|
|---|
| 1040 |
|
|---|
| 1041 | return FALSE; // confirm success
|
|---|
| 1042 | }
|
|---|
| 1043 | break;
|
|---|
| 1044 |
|
|---|
| 1045 | /*
|
|---|
| 1046 | * WM_DESTROY:
|
|---|
| 1047 | * clean up. This _must_ be passed on to
|
|---|
| 1048 | * ctrDefWidgetProc.
|
|---|
| 1049 | */
|
|---|
| 1050 |
|
|---|
| 1051 | case WM_DESTROY:
|
|---|
| 1052 | {
|
|---|
| 1053 | LOGF(("WM_DESTROY\n"));
|
|---|
| 1054 |
|
|---|
| 1055 | PSYSTRAYDATA pSysTrayData = (PSYSTRAYDATA)pWidget->pUser;
|
|---|
| 1056 |
|
|---|
| 1057 | // stop the check alive timer
|
|---|
| 1058 | WinStopTimer(pWidget->habWidget, pSysTrayData->hwndServer,
|
|---|
| 1059 | TID_CHECKALIVE);
|
|---|
| 1060 |
|
|---|
| 1061 | FreeSysTrayData(pSysTrayData);
|
|---|
| 1062 | pWidget->pUser = NULL;
|
|---|
| 1063 |
|
|---|
| 1064 | // We _MUST_ pass this on, or the default widget proc
|
|---|
| 1065 | // cannot clean up, so break
|
|---|
| 1066 | }
|
|---|
| 1067 | break;
|
|---|
| 1068 |
|
|---|
| 1069 | /*
|
|---|
| 1070 | * WM_CONTROL:
|
|---|
| 1071 | * process notifications/queries from the XCenter.
|
|---|
| 1072 | */
|
|---|
| 1073 |
|
|---|
| 1074 | case WM_CONTROL:
|
|---|
| 1075 | return (MPARAM)WgtControl(pWidget, mp1, mp2);
|
|---|
| 1076 | break;
|
|---|
| 1077 |
|
|---|
| 1078 | /*
|
|---|
| 1079 | * WM_PAINT:
|
|---|
| 1080 | * well, paint the widget.
|
|---|
| 1081 | */
|
|---|
| 1082 |
|
|---|
| 1083 | case WM_PAINT:
|
|---|
| 1084 | WgtPaint(hwnd, pWidget);
|
|---|
| 1085 | return (MRESULT)TRUE;
|
|---|
| 1086 | break;
|
|---|
| 1087 |
|
|---|
| 1088 | /*
|
|---|
| 1089 | * WM_PRESPARAMCHANGED:
|
|---|
| 1090 | * A well-behaved widget would intercept
|
|---|
| 1091 | * this and store fonts and colors.
|
|---|
| 1092 | */
|
|---|
| 1093 |
|
|---|
| 1094 | /* case WM_PRESPARAMCHANGED:
|
|---|
| 1095 | break; */
|
|---|
| 1096 |
|
|---|
| 1097 | /*
|
|---|
| 1098 | * All mouse click and wheel events:
|
|---|
| 1099 | * Note that we hide WM_CONTEXTMENU from XCenter when it is within
|
|---|
| 1100 | * the icon bounds as it's a responsibility of the application
|
|---|
| 1101 | * owning the icon to show it.
|
|---|
| 1102 | */
|
|---|
| 1103 |
|
|---|
| 1104 | case WM_BUTTON1UP:
|
|---|
| 1105 | case WM_BUTTON1DOWN:
|
|---|
| 1106 | case WM_BUTTON1CLICK:
|
|---|
| 1107 | case WM_BUTTON1DBLCLK:
|
|---|
| 1108 | case WM_BUTTON2UP:
|
|---|
| 1109 | case WM_BUTTON2DOWN:
|
|---|
| 1110 | case WM_BUTTON2CLICK:
|
|---|
| 1111 | case WM_BUTTON2DBLCLK:
|
|---|
| 1112 | case WM_BUTTON3UP:
|
|---|
| 1113 | case WM_BUTTON3DOWN:
|
|---|
| 1114 | case WM_BUTTON3CLICK:
|
|---|
| 1115 | case WM_BUTTON3DBLCLK:
|
|---|
| 1116 | case WM_CONTEXTMENU:
|
|---|
| 1117 | case WM_VSCROLL:
|
|---|
| 1118 | case WM_HSCROLL:
|
|---|
| 1119 | {
|
|---|
| 1120 | if (WgtMouse(hwnd, msg, mp1, mp2, pWidget))
|
|---|
| 1121 | return (MRESULT)TRUE;
|
|---|
| 1122 | // we didn't hit the icon, pass it on to XCenter
|
|---|
| 1123 | }
|
|---|
| 1124 | break;
|
|---|
| 1125 |
|
|---|
| 1126 | default:
|
|---|
| 1127 | break;
|
|---|
| 1128 |
|
|---|
| 1129 | } // end switch(msg)
|
|---|
| 1130 |
|
|---|
| 1131 | return pWidget->pfnwpDefWidgetProc(hwnd, msg, mp1, mp2);
|
|---|
| 1132 | }
|
|---|
| 1133 |
|
|---|
| 1134 | /*
|
|---|
| 1135 | *@@ WgtXSysTrayUpdateAfterIconAddRemove:
|
|---|
| 1136 | * Name says it all.
|
|---|
| 1137 | */
|
|---|
| 1138 |
|
|---|
| 1139 | static
|
|---|
| 1140 | VOID WgtXSysTrayUpdateAfterIconAddRemove(PXCENTERWIDGET pWidget)
|
|---|
| 1141 | {
|
|---|
| 1142 | PSYSTRAYDATA pSysTrayData = (PSYSTRAYDATA)pWidget->pUser;
|
|---|
| 1143 |
|
|---|
| 1144 | if (pSysTrayData->cIcons == 1)
|
|---|
| 1145 | {
|
|---|
| 1146 | // start a timer to perform "is window alive" checks
|
|---|
| 1147 | WinStartTimer(pWidget->habWidget, pSysTrayData->hwndServer,
|
|---|
| 1148 | TID_CHECKALIVE,
|
|---|
| 1149 | TID_CHECKALIVE_TIMEOUT);
|
|---|
| 1150 | }
|
|---|
| 1151 | else
|
|---|
| 1152 | if (pSysTrayData->cIcons == 0)
|
|---|
| 1153 | {
|
|---|
| 1154 | // stop the check alive timer
|
|---|
| 1155 | WinStopTimer(pWidget->habWidget, pSysTrayData->hwndServer,
|
|---|
| 1156 | TID_CHECKALIVE);
|
|---|
| 1157 | }
|
|---|
| 1158 |
|
|---|
| 1159 | // ask XCenter to take our new size into account (this will also
|
|---|
| 1160 | // invalidate us)
|
|---|
| 1161 | WinPostMsg(pWidget->pGlobals->hwndClient,
|
|---|
| 1162 | XCM_REFORMAT,
|
|---|
| 1163 | (MPARAM)XFMF_GETWIDGETSIZES,
|
|---|
| 1164 | 0);
|
|---|
| 1165 | }
|
|---|
| 1166 |
|
|---|
| 1167 | /*
|
|---|
| 1168 | *@@ WgtXSysTrayControl:
|
|---|
| 1169 | * implementation for WM_XST_CONTROL in fnwpXSysTrayServer.
|
|---|
| 1170 | *
|
|---|
| 1171 | * Serves as an entry point for all client-side API requests to the
|
|---|
| 1172 | * Extended system tray.
|
|---|
| 1173 | *
|
|---|
| 1174 | * Note that this message is being sent from another process which is
|
|---|
| 1175 | * awaiting for an answer, so it must return as far as possible (by
|
|---|
| 1176 | * rescheduling any potentially long term operation for another cycle).
|
|---|
| 1177 | */
|
|---|
| 1178 |
|
|---|
| 1179 | static
|
|---|
| 1180 | ULONG WgtXSysTrayControl(HWND hwnd, PXCENTERWIDGET pWidget,
|
|---|
| 1181 | PSYSTRAYCTLDATA pCtlData)
|
|---|
| 1182 | {
|
|---|
| 1183 | BOOL brc = FALSE;
|
|---|
| 1184 | ULONG xrc = XST_FAIL;
|
|---|
| 1185 |
|
|---|
| 1186 | PSYSTRAYDATA pSysTrayData = (PSYSTRAYDATA)pWidget->pUser;
|
|---|
| 1187 |
|
|---|
| 1188 | switch (pCtlData->ulCommand)
|
|---|
| 1189 | {
|
|---|
| 1190 | case SYSTRAYCMD_GETVERSION:
|
|---|
| 1191 | {
|
|---|
| 1192 | LOGF(("SYSTRAYCMD_GETVERSION\n"));
|
|---|
| 1193 |
|
|---|
| 1194 | pCtlData->bAcknowledged = TRUE;
|
|---|
| 1195 | pCtlData->u.version.ulMajor = XSYSTRAY_VERSION_MAJOR;
|
|---|
| 1196 | pCtlData->u.version.ulMajor = XSYSTRAY_VERSION_MINOR;
|
|---|
| 1197 | pCtlData->u.version.ulRevision = XSYSTRAY_VERSION_REVISION;
|
|---|
| 1198 | xrc = XST_OK;
|
|---|
| 1199 | }
|
|---|
| 1200 | break;
|
|---|
| 1201 |
|
|---|
| 1202 | case SYSTRAYCMD_ADDICON:
|
|---|
| 1203 | {
|
|---|
| 1204 | POINTERINFO Info;
|
|---|
| 1205 | HPOINTER hIcon = NULLHANDLE;
|
|---|
| 1206 | size_t i;
|
|---|
| 1207 | PICONDATA pData;
|
|---|
| 1208 |
|
|---|
| 1209 | LOGF(("SYSTRAYCMD_ADDICON\n"));
|
|---|
| 1210 | LOGF((" hwnd %x\n", pCtlData->hwndSender));
|
|---|
| 1211 | LOGF((" usId %d\n", pCtlData->u.icon.usId));
|
|---|
| 1212 | LOGF((" hIcon %x\n", pCtlData->u.icon.hIcon));
|
|---|
| 1213 | LOGF((" szToolTip '%s'\n", pCtlData->u.icon.szToolTip));
|
|---|
| 1214 |
|
|---|
| 1215 | pCtlData->bAcknowledged = TRUE;
|
|---|
| 1216 |
|
|---|
| 1217 | // make a private copy of the provided icon (it will get lost after
|
|---|
| 1218 | // we return from this message)
|
|---|
| 1219 | brc = WinQueryPointerInfo(pCtlData->u.icon.hIcon, &Info);
|
|---|
| 1220 | if (!brc)
|
|---|
| 1221 | break;
|
|---|
| 1222 | hIcon = WinCreatePointerIndirect(HWND_DESKTOP, &Info);
|
|---|
| 1223 | if (hIcon == NULLHANDLE)
|
|---|
| 1224 | break;
|
|---|
| 1225 |
|
|---|
| 1226 | pData = FindIconData(pSysTrayData, pCtlData->hwndSender,
|
|---|
| 1227 | pCtlData->u.icon.usId, &i);
|
|---|
| 1228 | if (pData)
|
|---|
| 1229 | {
|
|---|
| 1230 | LOGF((" Replacing with hIcon %x\n", hIcon));
|
|---|
| 1231 |
|
|---|
| 1232 | // try update the tooltip first
|
|---|
| 1233 | free(pData->pszToolTip);
|
|---|
| 1234 | pData->pszToolTip = NULL;
|
|---|
| 1235 | if (pCtlData->u.icon.szToolTip[0] != '\0')
|
|---|
| 1236 | {
|
|---|
| 1237 | pData->pszToolTip = strdup(pCtlData->u.icon.szToolTip);
|
|---|
| 1238 | if (!pData->pszToolTip)
|
|---|
| 1239 | {
|
|---|
| 1240 | WinDestroyPointer(hIcon);
|
|---|
| 1241 | break;
|
|---|
| 1242 | }
|
|---|
| 1243 | }
|
|---|
| 1244 |
|
|---|
| 1245 | if (pData->bIsToolTipShowing)
|
|---|
| 1246 | {
|
|---|
| 1247 | if (pData->pszToolTip)
|
|---|
| 1248 | // update the tooltip on screen
|
|---|
| 1249 | WinSendMsg(pWidget->pGlobals->hwndTooltip,
|
|---|
| 1250 | TTM_UPDATETIPTEXT,
|
|---|
| 1251 | (MPARAM)pData->pszToolTip, 0);
|
|---|
| 1252 | else
|
|---|
| 1253 | // hide the tooltip
|
|---|
| 1254 | WinSendMsg(pWidget->pGlobals->hwndTooltip,
|
|---|
| 1255 | TTM_SHOWTOOLTIPNOW,
|
|---|
| 1256 | (MPARAM)FALSE, 0);
|
|---|
| 1257 | }
|
|---|
| 1258 |
|
|---|
| 1259 | // now update the icon
|
|---|
| 1260 | WinDestroyPointer(pData->hIcon);
|
|---|
| 1261 | pData->hIcon = hIcon;
|
|---|
| 1262 | pData->ulMsgId = pCtlData->u.icon.ulMsgId;
|
|---|
| 1263 |
|
|---|
| 1264 | // we didn't change the number of icons so simply invalidate
|
|---|
| 1265 | WinInvalidateRect(pWidget->hwndWidget, NULL, FALSE);
|
|---|
| 1266 |
|
|---|
| 1267 | xrc = XST_REPLACED;
|
|---|
| 1268 | }
|
|---|
| 1269 | else
|
|---|
| 1270 | {
|
|---|
| 1271 | LOGF((" Adding new hIcon %x\n", hIcon));
|
|---|
| 1272 |
|
|---|
| 1273 | if (pSysTrayData->cIcons == pSysTrayData->cIconsMax)
|
|---|
| 1274 | {
|
|---|
| 1275 | PICONDATA pNewIcons;
|
|---|
| 1276 |
|
|---|
| 1277 | LOGF((" Allocating more memory (new icon count is %u)!\n",
|
|---|
| 1278 | pSysTrayData->cIcons + 1));
|
|---|
| 1279 |
|
|---|
| 1280 | pNewIcons = realloc(pSysTrayData->pIcons,
|
|---|
| 1281 | sizeof(*pSysTrayData->pIcons) *
|
|---|
| 1282 | pSysTrayData->cIconsMax + ICONARRAY_GROW);
|
|---|
| 1283 | if (pNewIcons == NULL)
|
|---|
| 1284 | {
|
|---|
| 1285 | WinDestroyPointer(hIcon);
|
|---|
| 1286 | break;
|
|---|
| 1287 | }
|
|---|
| 1288 |
|
|---|
| 1289 | pSysTrayData->pIcons = pNewIcons;
|
|---|
| 1290 | pSysTrayData->cIconsMax += ICONARRAY_GROW;
|
|---|
| 1291 | }
|
|---|
| 1292 |
|
|---|
| 1293 | i = pSysTrayData->cIcons;
|
|---|
| 1294 |
|
|---|
| 1295 | pData = &pSysTrayData->pIcons[i];
|
|---|
| 1296 | memset(pData, 0, sizeof(*pData));
|
|---|
| 1297 |
|
|---|
| 1298 | pData->hwnd = pCtlData->hwndSender;
|
|---|
| 1299 | pData->usId = pCtlData->u.icon.usId;
|
|---|
| 1300 | pData->hIcon = hIcon;
|
|---|
| 1301 | pData->ulMsgId = pCtlData->u.icon.ulMsgId;
|
|---|
| 1302 |
|
|---|
| 1303 | if (pCtlData->u.icon.szToolTip[0] != '\0')
|
|---|
| 1304 | {
|
|---|
| 1305 | pData->pszToolTip = strdup(pCtlData->u.icon.szToolTip);
|
|---|
| 1306 | if (!pData->pszToolTip)
|
|---|
| 1307 | {
|
|---|
| 1308 | WinDestroyPointer(hIcon);
|
|---|
| 1309 | break;
|
|---|
| 1310 | }
|
|---|
| 1311 | }
|
|---|
| 1312 |
|
|---|
| 1313 | ++pSysTrayData->cIcons;
|
|---|
| 1314 |
|
|---|
| 1315 | WgtXSysTrayUpdateAfterIconAddRemove(pWidget);
|
|---|
| 1316 |
|
|---|
| 1317 | xrc = XST_OK;
|
|---|
| 1318 | }
|
|---|
| 1319 | }
|
|---|
| 1320 | break;
|
|---|
| 1321 |
|
|---|
| 1322 | case SYSTRAYCMD_REPLACEICON:
|
|---|
| 1323 | {
|
|---|
| 1324 | POINTERINFO Info;
|
|---|
| 1325 | HPOINTER hIcon = NULLHANDLE;
|
|---|
| 1326 | size_t i;
|
|---|
| 1327 | PICONDATA pData;
|
|---|
| 1328 |
|
|---|
| 1329 | LOGF(("SYSTRAYCMD_REPLACEICON\n"));
|
|---|
| 1330 | LOGF((" hwnd %x\n", pCtlData->hwndSender));
|
|---|
| 1331 | LOGF((" usId %d\n", pCtlData->u.icon.usId));
|
|---|
| 1332 |
|
|---|
| 1333 | pCtlData->bAcknowledged = TRUE;
|
|---|
| 1334 |
|
|---|
| 1335 | // make a private copy of the provided icon (it will get lost after
|
|---|
| 1336 | // we return from this message)
|
|---|
| 1337 | brc = WinQueryPointerInfo(pCtlData->u.icon.hIcon, &Info);
|
|---|
| 1338 | if (!brc)
|
|---|
| 1339 | break;
|
|---|
| 1340 | hIcon = WinCreatePointerIndirect(HWND_DESKTOP, &Info);
|
|---|
| 1341 | if (hIcon == NULLHANDLE)
|
|---|
| 1342 | break;
|
|---|
| 1343 |
|
|---|
| 1344 | pData = FindIconData(pSysTrayData, pCtlData->hwndSender,
|
|---|
| 1345 | pCtlData->u.icon.usId, &i);
|
|---|
| 1346 | if (pData)
|
|---|
| 1347 | {
|
|---|
| 1348 | LOGF((" Replacing with hIcon %x\n", hIcon));
|
|---|
| 1349 |
|
|---|
| 1350 | WinDestroyPointer(pData->hIcon);
|
|---|
| 1351 | pData->hIcon = hIcon;
|
|---|
| 1352 | pData->ulMsgId = pCtlData->u.icon.ulMsgId;
|
|---|
| 1353 |
|
|---|
| 1354 | // we didn't change the number of icons so simply invalidate
|
|---|
| 1355 | WinInvalidateRect(pWidget->hwndWidget, NULL, FALSE);
|
|---|
| 1356 |
|
|---|
| 1357 | xrc = XST_OK;
|
|---|
| 1358 | }
|
|---|
| 1359 | else
|
|---|
| 1360 | LOGF((" Icon not found!\n"));
|
|---|
| 1361 | }
|
|---|
| 1362 | break;
|
|---|
| 1363 |
|
|---|
| 1364 | case SYSTRAYCMD_REMOVEICON:
|
|---|
| 1365 | {
|
|---|
| 1366 | size_t i;
|
|---|
| 1367 | PICONDATA pData;
|
|---|
| 1368 |
|
|---|
| 1369 | LOGF(("SYSTRAYCMD_REMOVEICON\n"));
|
|---|
| 1370 | LOGF((" hwnd %x\n", pCtlData->hwndSender));
|
|---|
| 1371 | LOGF((" usId %d\n", pCtlData->u.icon.usId));
|
|---|
| 1372 |
|
|---|
| 1373 | pCtlData->bAcknowledged = TRUE;
|
|---|
| 1374 |
|
|---|
| 1375 | pData = FindIconData(pSysTrayData, pCtlData->hwndSender,
|
|---|
| 1376 | pCtlData->u.icon.usId, &i);
|
|---|
| 1377 | if (pData)
|
|---|
| 1378 | {
|
|---|
| 1379 | LOGF((" Removing hIcon %x\n", pData->hIcon));
|
|---|
| 1380 |
|
|---|
| 1381 | FreeIconData(pData);
|
|---|
| 1382 |
|
|---|
| 1383 | --pSysTrayData->cIcons;
|
|---|
| 1384 | if (pSysTrayData->cIcons > 0)
|
|---|
| 1385 | {
|
|---|
| 1386 | memcpy(&pSysTrayData->pIcons[i],
|
|---|
| 1387 | &pSysTrayData->pIcons[i + 1],
|
|---|
| 1388 | sizeof(*pSysTrayData->pIcons) * (pSysTrayData->cIcons - i));
|
|---|
| 1389 | }
|
|---|
| 1390 |
|
|---|
| 1391 | WgtXSysTrayUpdateAfterIconAddRemove(pWidget);
|
|---|
| 1392 |
|
|---|
| 1393 | xrc = XST_OK;
|
|---|
| 1394 | }
|
|---|
| 1395 | else
|
|---|
| 1396 | LOGF((" Icon not found!\n"));
|
|---|
| 1397 | }
|
|---|
| 1398 | break;
|
|---|
| 1399 |
|
|---|
| 1400 | case SYSTRAYCMD_SETTOOLTIP:
|
|---|
| 1401 | {
|
|---|
| 1402 | size_t i;
|
|---|
| 1403 | PICONDATA pData;
|
|---|
| 1404 |
|
|---|
| 1405 | LOGF(("SYSTRAYCMD_SETTOOLTIP\n"));
|
|---|
| 1406 | LOGF((" hwnd %x\n", pCtlData->hwndSender));
|
|---|
| 1407 | LOGF((" usId %d\n", pCtlData->u.icon.usId));
|
|---|
| 1408 |
|
|---|
| 1409 | pCtlData->bAcknowledged = TRUE;
|
|---|
| 1410 |
|
|---|
| 1411 | pData = FindIconData(pSysTrayData, pCtlData->hwndSender,
|
|---|
| 1412 | pCtlData->u.icon.usId, &i);
|
|---|
| 1413 | if (pData)
|
|---|
| 1414 | {
|
|---|
| 1415 | LOGF((" Replacing with szToolTip '%s'\n",
|
|---|
| 1416 | pCtlData->u.icon.szToolTip));
|
|---|
| 1417 |
|
|---|
| 1418 | free(pData->pszToolTip);
|
|---|
| 1419 | pData->pszToolTip = NULL;
|
|---|
| 1420 | if (pCtlData->u.icon.szToolTip[0] != '\0')
|
|---|
| 1421 | {
|
|---|
| 1422 | pData->pszToolTip = strdup(pCtlData->u.icon.szToolTip);
|
|---|
| 1423 | if (!pData->pszToolTip)
|
|---|
| 1424 | break;
|
|---|
| 1425 | }
|
|---|
| 1426 |
|
|---|
| 1427 | if (pData->bIsToolTipShowing)
|
|---|
| 1428 | {
|
|---|
| 1429 | if (pData->pszToolTip)
|
|---|
| 1430 | // update the tooltip on screen
|
|---|
| 1431 | WinSendMsg(pWidget->pGlobals->hwndTooltip,
|
|---|
| 1432 | TTM_UPDATETIPTEXT,
|
|---|
| 1433 | (MPARAM)pData->pszToolTip, 0);
|
|---|
| 1434 | else
|
|---|
| 1435 | // hide the tooltip
|
|---|
| 1436 | WinSendMsg(pWidget->pGlobals->hwndTooltip,
|
|---|
| 1437 | TTM_SHOWTOOLTIPNOW,
|
|---|
| 1438 | (MPARAM)FALSE, 0);
|
|---|
| 1439 | }
|
|---|
| 1440 |
|
|---|
| 1441 | xrc = XST_OK;
|
|---|
| 1442 | }
|
|---|
| 1443 | else
|
|---|
| 1444 | LOGF((" Icon not found!\n"));
|
|---|
| 1445 | }
|
|---|
| 1446 | break;
|
|---|
| 1447 |
|
|---|
| 1448 | case SYSTRAYCMD_QUERYRECT:
|
|---|
| 1449 | {
|
|---|
| 1450 | size_t i;
|
|---|
| 1451 | PICONDATA pData;
|
|---|
| 1452 |
|
|---|
| 1453 | LOGF(("SYSTRAYCMD_QUERYRECT\n"));
|
|---|
| 1454 | LOGF((" hwnd %x\n", pCtlData->hwndSender));
|
|---|
| 1455 | LOGF((" usId %d\n", pCtlData->u.icon.usId));
|
|---|
| 1456 |
|
|---|
| 1457 | pCtlData->bAcknowledged = TRUE;
|
|---|
| 1458 |
|
|---|
| 1459 | pData = FindIconData(pSysTrayData, pCtlData->hwndSender,
|
|---|
| 1460 | pCtlData->u.icon.usId, &i);
|
|---|
| 1461 | if (pData)
|
|---|
| 1462 | {
|
|---|
| 1463 | // Refer to FindIconDataAtPt() for details
|
|---|
| 1464 |
|
|---|
| 1465 | SWP swp;
|
|---|
| 1466 | RECTL rcl;
|
|---|
| 1467 | BOOL bLeftToRight;
|
|---|
| 1468 | LONG y, lIconStep;
|
|---|
| 1469 |
|
|---|
| 1470 | WinQueryWindowPos(pWidget->hwndWidget, &swp);
|
|---|
| 1471 | WinQueryWindowRect(pWidget->pGlobals->hwndClient, &rcl);
|
|---|
| 1472 |
|
|---|
| 1473 | y = (swp.cy - pSysTrayData->lIconHeight) / 2;
|
|---|
| 1474 |
|
|---|
| 1475 | // detect the direction
|
|---|
| 1476 | bLeftToRight = swp.x + swp.cx / 2 < (rcl.xRight / 2);
|
|---|
| 1477 |
|
|---|
| 1478 | lIconStep = pSysTrayData->lIconWidth + pSysTrayData->lIconPad;
|
|---|
| 1479 |
|
|---|
| 1480 | pCtlData->u.rect.rclIcon.yBottom = y;
|
|---|
| 1481 | pCtlData->u.rect.rclIcon.yTop = y + pSysTrayData->lIconHeight;
|
|---|
| 1482 |
|
|---|
| 1483 | if (bLeftToRight)
|
|---|
| 1484 | {
|
|---|
| 1485 | pCtlData->u.rect.rclIcon.xLeft =
|
|---|
| 1486 | pSysTrayData->lIconPad + (lIconStep) * i;
|
|---|
| 1487 | pCtlData->u.rect.rclIcon.xRight =
|
|---|
| 1488 | pCtlData->u.rect.rclIcon.xLeft +
|
|---|
| 1489 | pSysTrayData->lIconWidth;
|
|---|
| 1490 | }
|
|---|
| 1491 | else
|
|---|
| 1492 | {
|
|---|
| 1493 | pCtlData->u.rect.rclIcon.xLeft =
|
|---|
| 1494 | swp.cx - (lIconStep) * (i + 1);
|
|---|
| 1495 | pCtlData->u.rect.rclIcon.xRight =
|
|---|
| 1496 | pCtlData->u.rect.rclIcon.xLeft +
|
|---|
| 1497 | pSysTrayData->lIconWidth;
|
|---|
| 1498 | }
|
|---|
| 1499 |
|
|---|
| 1500 | // convert to screen coordinates
|
|---|
| 1501 | WinMapWindowPoints(pWidget->hwndWidget, HWND_DESKTOP,
|
|---|
| 1502 | (PPOINTL)&pCtlData->u.rect.rclIcon, 2);
|
|---|
| 1503 | xrc = XST_OK;
|
|---|
| 1504 | }
|
|---|
| 1505 | else
|
|---|
| 1506 | LOGF((" Icon not found!\n"));
|
|---|
| 1507 | }
|
|---|
| 1508 | break;
|
|---|
| 1509 |
|
|---|
| 1510 | default:
|
|---|
| 1511 | break;
|
|---|
| 1512 | }
|
|---|
| 1513 |
|
|---|
| 1514 | LOGF(("return %d (WinGetLastError is %x)\n",
|
|---|
| 1515 | xrc, WinGetLastError(pWidget->habWidget)));
|
|---|
| 1516 |
|
|---|
| 1517 | return xrc;
|
|---|
| 1518 | }
|
|---|
| 1519 |
|
|---|
| 1520 | /*
|
|---|
| 1521 | *@@ WgtXSysTrayTimer:
|
|---|
| 1522 | * implementation for WM_TIMER in fnwpXSysTrayServer.
|
|---|
| 1523 | */
|
|---|
| 1524 |
|
|---|
| 1525 | static
|
|---|
| 1526 | VOID WgtXSysTrayTimer(HWND hwnd, PXCENTERWIDGET pWidget,
|
|---|
| 1527 | USHORT usTimerId)
|
|---|
| 1528 | {
|
|---|
| 1529 | PSYSTRAYDATA pSysTrayData = (PSYSTRAYDATA)pWidget->pUser;
|
|---|
| 1530 | PMEMPOOLHDR pMemPoolHdr = (PMEMPOOLHDR)pSysTrayData->pvMemoryPool;
|
|---|
| 1531 | PMEMPOOLBLK pMemPoolBlk;
|
|---|
| 1532 | ULONG ulMemPoolMax;
|
|---|
| 1533 |
|
|---|
| 1534 | if (usTimerId == TID_CHECKALIVE)
|
|---|
| 1535 | {
|
|---|
| 1536 | // check if windows associated with the icons are still alive
|
|---|
| 1537 | // and remove those icons whose windows are invalid
|
|---|
| 1538 | BOOL bAnyDead = FALSE;
|
|---|
| 1539 | size_t i;
|
|---|
| 1540 | for (i = 0; i < pSysTrayData->cIcons; ++i)
|
|---|
| 1541 | {
|
|---|
| 1542 | if (!WinIsWindow(pWidget->habWidget, pSysTrayData->pIcons[i].hwnd))
|
|---|
| 1543 | {
|
|---|
| 1544 | PICONDATA pData = &pSysTrayData->pIcons[i];
|
|---|
| 1545 |
|
|---|
| 1546 | LOGF(("Removing icon of dead window!\n"));
|
|---|
| 1547 | LOGF((" hwnd %x\n", pData->hwnd));
|
|---|
| 1548 | LOGF((" usId %ld\n", pData->usId));
|
|---|
| 1549 | LOGF((" hIcon %x\n", pData->hIcon));
|
|---|
| 1550 |
|
|---|
| 1551 | // free memory blocks from the pool allocated for this client
|
|---|
| 1552 | ulMemPoolMax = pMemPoolHdr->ulBeyond;
|
|---|
| 1553 | if (ulMemPoolMax > pMemPoolHdr->ulNeedsCommit)
|
|---|
| 1554 | ulMemPoolMax = pMemPoolHdr->ulNeedsCommit;
|
|---|
| 1555 | ulMemPoolMax -= sizeof(MEMPOOLBLK);
|
|---|
| 1556 |
|
|---|
| 1557 | pMemPoolBlk = pMemPoolHdr->aBlocks;
|
|---|
| 1558 | while ((ULONG)pMemPoolBlk <= ulMemPoolMax)
|
|---|
| 1559 | {
|
|---|
| 1560 | if (pMemPoolBlk->hwnd == pData->hwnd)
|
|---|
| 1561 | {
|
|---|
| 1562 | LOGF((" freeing memory block %p\n", pMemPoolBlk));
|
|---|
| 1563 | FreeNotifyDataPtr(pSysTrayData->pvMemoryPool,
|
|---|
| 1564 | pData->hwnd,
|
|---|
| 1565 | &pMemPoolBlk->NotifyData);
|
|---|
| 1566 | }
|
|---|
| 1567 | ++pMemPoolBlk;
|
|---|
| 1568 | }
|
|---|
| 1569 |
|
|---|
| 1570 | bAnyDead = TRUE;
|
|---|
| 1571 | FreeIconData(pData);
|
|---|
| 1572 | // pData->hwnd is NULLHANDLE here
|
|---|
| 1573 | }
|
|---|
| 1574 | }
|
|---|
| 1575 |
|
|---|
| 1576 | if (bAnyDead)
|
|---|
| 1577 | {
|
|---|
| 1578 | // compact the icon array
|
|---|
| 1579 | i = 0;
|
|---|
| 1580 | while (i < pSysTrayData->cIcons)
|
|---|
| 1581 | {
|
|---|
| 1582 | if (pSysTrayData->pIcons[i].hwnd == NULLHANDLE)
|
|---|
| 1583 | {
|
|---|
| 1584 | --pSysTrayData->cIcons;
|
|---|
| 1585 | if (pSysTrayData->cIcons > 0)
|
|---|
| 1586 | {
|
|---|
| 1587 | memcpy(&pSysTrayData->pIcons[i],
|
|---|
| 1588 | &pSysTrayData->pIcons[i + 1],
|
|---|
| 1589 | sizeof(*pSysTrayData->pIcons) * (pSysTrayData->cIcons - i));
|
|---|
| 1590 | }
|
|---|
| 1591 | }
|
|---|
| 1592 | else
|
|---|
| 1593 | ++i;
|
|---|
| 1594 | }
|
|---|
| 1595 |
|
|---|
| 1596 | WgtXSysTrayUpdateAfterIconAddRemove(pWidget);
|
|---|
| 1597 | }
|
|---|
| 1598 | }
|
|---|
| 1599 | }
|
|---|
| 1600 |
|
|---|
| 1601 | /*
|
|---|
| 1602 | *@@ fnwpXSysTrayServer:
|
|---|
| 1603 | * window procedure for the Extended system tray server window class.
|
|---|
| 1604 | *
|
|---|
| 1605 | * A separate "server" class is necessary because we need a CS_FRAME
|
|---|
| 1606 | * top-level window for DDE (which we need to support to be backward
|
|---|
| 1607 | * compatible with the System tray wdget from the SysTray/WPS package) and
|
|---|
| 1608 | * also to make ourselves discoverable for the client-side implementation
|
|---|
| 1609 | * of our new extended API (which queries the class of each top-level
|
|---|
| 1610 | * window to find the system tray server).
|
|---|
| 1611 | */
|
|---|
| 1612 |
|
|---|
| 1613 | static
|
|---|
| 1614 | MRESULT EXPENTRY fnwpXSysTrayServer(HWND hwnd, ULONG msg, MPARAM mp1, MPARAM mp2)
|
|---|
| 1615 | {
|
|---|
| 1616 | // get widget data from QWL_USER_SERVER_DATA (stored there by WM_CREATE)
|
|---|
| 1617 | PXCENTERWIDGET pWidget =
|
|---|
| 1618 | (PXCENTERWIDGET)WinQueryWindowPtr(hwnd, QWL_USER_SERVER_DATA);
|
|---|
| 1619 | // this ptr is valid after WM_CREATE
|
|---|
| 1620 |
|
|---|
| 1621 | switch (msg)
|
|---|
| 1622 | {
|
|---|
| 1623 | case WM_CREATE:
|
|---|
| 1624 | LOGF(("WM_CREATE\n"));
|
|---|
| 1625 | WinSetWindowPtr(hwnd, QWL_USER_SERVER_DATA, mp1);
|
|---|
| 1626 | return FALSE; // confirm success
|
|---|
| 1627 | break;
|
|---|
| 1628 |
|
|---|
| 1629 | case WM_DESTROY:
|
|---|
| 1630 | LOGF(("WM_DESTROY\n"));
|
|---|
| 1631 | break;
|
|---|
| 1632 |
|
|---|
| 1633 | /*
|
|---|
| 1634 | * WM_XST_CONTROL:
|
|---|
| 1635 | * This is the message sent to us by the clinet-side implementation
|
|---|
| 1636 | * of the API to request some function. mp1 points to a
|
|---|
| 1637 | * SYSTRAYCTLDATA structure.
|
|---|
| 1638 | */
|
|---|
| 1639 |
|
|---|
| 1640 | case WM_XST_CONTROL:
|
|---|
| 1641 | return (MRESULT)WgtXSysTrayControl(hwnd, pWidget,
|
|---|
| 1642 | (PSYSTRAYCTLDATA)mp1);
|
|---|
| 1643 | break;
|
|---|
| 1644 |
|
|---|
| 1645 | /*
|
|---|
| 1646 | * WM_TIMER:
|
|---|
| 1647 | * timer event.
|
|---|
| 1648 | */
|
|---|
| 1649 |
|
|---|
| 1650 | case WM_TIMER:
|
|---|
| 1651 | WgtXSysTrayTimer(hwnd, pWidget, SHORT1FROMMP(mp1));
|
|---|
| 1652 | return (MRESULT)TRUE;
|
|---|
| 1653 | break;
|
|---|
| 1654 |
|
|---|
| 1655 | default:
|
|---|
| 1656 | break;
|
|---|
| 1657 | } // end switch(msg)
|
|---|
| 1658 |
|
|---|
| 1659 | return WinDefWindowProc(hwnd, msg, mp1, mp2);
|
|---|
| 1660 | }
|
|---|
| 1661 |
|
|---|
| 1662 | /* ******************************************************************
|
|---|
| 1663 | *
|
|---|
| 1664 | * Exported procedures
|
|---|
| 1665 | *
|
|---|
| 1666 | ********************************************************************/
|
|---|
| 1667 |
|
|---|
| 1668 | /*
|
|---|
| 1669 | *@@ WgtInitModule:
|
|---|
| 1670 | * required export with ordinal 1, which must tell
|
|---|
| 1671 | * the XCenter how many widgets this DLL provides,
|
|---|
| 1672 | * and give the XCenter an array of XCENTERWIDGETCLASS
|
|---|
| 1673 | * structures describing the widgets.
|
|---|
| 1674 | *
|
|---|
| 1675 | * With this call, you are given the module handle of
|
|---|
| 1676 | * XFLDR.DLL. For convenience, and if you have the full
|
|---|
| 1677 | * XWorkplace source code, you could resolve imports
|
|---|
| 1678 | * for some useful functions which are exported thru
|
|---|
| 1679 | * src\shared\xwp.def. We don't do this here.
|
|---|
| 1680 | *
|
|---|
| 1681 | * This function must also register the PM window classes
|
|---|
| 1682 | * which are specified in the XCENTERWIDGETCLASS array
|
|---|
| 1683 | * entries. For this, you are given a HAB which you
|
|---|
| 1684 | * should pass to WinRegisterClass. For the window
|
|---|
| 1685 | * class style (4th param to WinRegisterClass),
|
|---|
| 1686 | * you should specify
|
|---|
| 1687 | *
|
|---|
| 1688 | + CS_PARENTCLIP | CS_SIZEREDRAW | CS_SYNCPAINT
|
|---|
| 1689 | *
|
|---|
| 1690 | * Your widget window _will_ be resized by the XCenter,
|
|---|
| 1691 | * even if you're not planning it to be.
|
|---|
| 1692 | *
|
|---|
| 1693 | * This function only gets called _once_ when the widget
|
|---|
| 1694 | * DLL has been successfully loaded by the XCenter. If
|
|---|
| 1695 | * there are several instances of a widget running (in
|
|---|
| 1696 | * the same or in several XCenters), this function does
|
|---|
| 1697 | * not get called again. However, since the XCenter unloads
|
|---|
| 1698 | * the widget DLLs again if they are no longer referenced
|
|---|
| 1699 | * by any XCenter, this might get called again when the
|
|---|
| 1700 | * DLL is re-loaded.
|
|---|
| 1701 | *
|
|---|
| 1702 | * There will ever be only one load occurence of the DLL.
|
|---|
| 1703 | * The XCenter manages sharing the DLL between several
|
|---|
| 1704 | * XCenters. As a result, it doesn't matter if the DLL
|
|---|
| 1705 | * has INITINSTANCE etc. set or not.
|
|---|
| 1706 | *
|
|---|
| 1707 | * If this returns 0, this is considered an error, and the
|
|---|
| 1708 | * DLL will be unloaded again immediately.
|
|---|
| 1709 | *
|
|---|
| 1710 | * If this returns any value > 0, *ppaClasses must be
|
|---|
| 1711 | * set to a static array (best placed in the DLL's
|
|---|
| 1712 | * global data) of XCENTERWIDGETCLASS structures,
|
|---|
| 1713 | * which must have as many entries as the return value.
|
|---|
| 1714 | */
|
|---|
| 1715 |
|
|---|
| 1716 | ULONG EXPENTRY WgtInitModule(HAB hab, // XCenter's anchor block
|
|---|
| 1717 | HMODULE hmodPlugin, // module handle of the widget DLL
|
|---|
| 1718 | HMODULE hmodXFLDR, // XFLDR.DLL module handle
|
|---|
| 1719 | PCXCENTERWIDGETCLASS *ppaClasses,
|
|---|
| 1720 | PSZ pszErrorMsg) // if 0 is returned, 500 bytes of error msg
|
|---|
| 1721 | {
|
|---|
| 1722 | ULONG ulrc = 0, ul = 0;
|
|---|
| 1723 | CLASSINFO ClassInfo;
|
|---|
| 1724 |
|
|---|
| 1725 | LOGF(("hmodPlugin %x\n", hmodPlugin));
|
|---|
| 1726 |
|
|---|
| 1727 | do
|
|---|
| 1728 | {
|
|---|
| 1729 | // resolve imports from XFLDR.DLL (this is basically
|
|---|
| 1730 | // a copy of the doshResolveImports code, but we can't
|
|---|
| 1731 | // use that before resolving...)
|
|---|
| 1732 | for (ul = 0;
|
|---|
| 1733 | ul < sizeof(G_aImports) / sizeof(G_aImports[0]);
|
|---|
| 1734 | ul++)
|
|---|
| 1735 | {
|
|---|
| 1736 | APIRET arc;
|
|---|
| 1737 | if ((arc = DosQueryProcAddr(hmodXFLDR,
|
|---|
| 1738 | 0, // ordinal, ignored
|
|---|
| 1739 | (PSZ)G_aImports[ul].pcszFunctionName,
|
|---|
| 1740 | G_aImports[ul].ppFuncAddress))
|
|---|
| 1741 | != NO_ERROR)
|
|---|
| 1742 | {
|
|---|
| 1743 | snprintf(pszErrorMsg, 500,
|
|---|
| 1744 | "Import %s failed with %ld.",
|
|---|
| 1745 | G_aImports[ul].pcszFunctionName, arc);
|
|---|
| 1746 | break;
|
|---|
| 1747 | }
|
|---|
| 1748 | }
|
|---|
| 1749 | if (ul < sizeof(G_aImports) / sizeof(G_aImports[0]))
|
|---|
| 1750 | break;
|
|---|
| 1751 |
|
|---|
| 1752 | // register our PM window class
|
|---|
| 1753 | if (!WinRegisterClass(hab,
|
|---|
| 1754 | WNDCLASS_WIDGET_XSYSTRAY,
|
|---|
| 1755 | fnwpXSysTray,
|
|---|
| 1756 | CS_PARENTCLIP | CS_SIZEREDRAW | CS_SYNCPAINT,
|
|---|
| 1757 | sizeof(PVOID))
|
|---|
| 1758 | // extra memory to reserve for QWL_USER
|
|---|
| 1759 | )
|
|---|
| 1760 | {
|
|---|
| 1761 | snprintf(pszErrorMsg, 500,
|
|---|
| 1762 | "WinRegisterClass(%s) failed with %lX.",
|
|---|
| 1763 | WNDCLASS_WIDGET_XSYSTRAY, WinGetLastError(hab));
|
|---|
| 1764 | break;
|
|---|
| 1765 | }
|
|---|
| 1766 |
|
|---|
| 1767 | // get the window data size for the WC_FRAME class (any window class
|
|---|
| 1768 | // that specifies CS_FRAME must have at least this number, otherise
|
|---|
| 1769 | // WinRegisterClass returns 0x1003
|
|---|
| 1770 | if (!WinQueryClassInfo(hab, (PSZ)WC_FRAME, &ClassInfo))
|
|---|
| 1771 | break;
|
|---|
| 1772 | QWL_USER_SERVER_DATA = ClassInfo.cbWindowData;
|
|---|
| 1773 |
|
|---|
| 1774 | if (!WinRegisterClass(hab,
|
|---|
| 1775 | WNDCLASS_WIDGET_XSYSTRAY_SERVER,
|
|---|
| 1776 | fnwpXSysTrayServer,
|
|---|
| 1777 | CS_FRAME,
|
|---|
| 1778 | QWL_USER_SERVER_DATA + sizeof(PVOID))
|
|---|
| 1779 | // extra memory to reserve for QWL_USER
|
|---|
| 1780 | )
|
|---|
| 1781 | {
|
|---|
| 1782 | // error registering class: report error then
|
|---|
| 1783 | snprintf(pszErrorMsg, 500,
|
|---|
| 1784 | "WinRegisterClass(%s) failed with %lX",
|
|---|
| 1785 | WNDCLASS_WIDGET_XSYSTRAY_SERVER, WinGetLastError(hab));
|
|---|
| 1786 | break;
|
|---|
| 1787 | }
|
|---|
| 1788 |
|
|---|
| 1789 | if (WM_XST_CREATED == 0)
|
|---|
| 1790 | WM_XST_CREATED = WinAddAtom(WinQuerySystemAtomTable(),
|
|---|
| 1791 | WM_XST_CREATED_ATOM);
|
|---|
| 1792 | if (WM_XST_NOTIFY == 0)
|
|---|
| 1793 | WM_XST_NOTIFY = WinAddAtom(WinQuerySystemAtomTable(),
|
|---|
| 1794 | WM_XST_NOTIFY_ATOM);
|
|---|
| 1795 |
|
|---|
| 1796 | // no error:
|
|---|
| 1797 | // return widget classes array
|
|---|
| 1798 | *ppaClasses = G_WidgetClasses;
|
|---|
| 1799 |
|
|---|
| 1800 | // return no. of classes in this DLL (one here):
|
|---|
| 1801 | ulrc = sizeof(G_WidgetClasses) / sizeof(G_WidgetClasses[0]);
|
|---|
| 1802 | }
|
|---|
| 1803 | while (0);
|
|---|
| 1804 |
|
|---|
| 1805 | LOGF(("pszErrorMsg '%s'\n", pszErrorMsg));
|
|---|
| 1806 | LOGF(("ulrc %d\n", ulrc));
|
|---|
| 1807 |
|
|---|
| 1808 | return ulrc;
|
|---|
| 1809 | }
|
|---|
| 1810 |
|
|---|
| 1811 | /*
|
|---|
| 1812 | *@@ WgtUnInitModule:
|
|---|
| 1813 | * optional export with ordinal 2, which can clean
|
|---|
| 1814 | * up global widget class data.
|
|---|
| 1815 | *
|
|---|
| 1816 | * This gets called by the XCenter right before
|
|---|
| 1817 | * a widget DLL gets unloaded. Note that this
|
|---|
| 1818 | * gets called even if the "init module" export
|
|---|
| 1819 | * returned 0 (meaning an error) and the DLL
|
|---|
| 1820 | * gets unloaded right away.
|
|---|
| 1821 | */
|
|---|
| 1822 |
|
|---|
| 1823 | VOID EXPENTRY WgtUnInitModule(VOID)
|
|---|
| 1824 | {
|
|---|
| 1825 | LOGF(("\n"));
|
|---|
| 1826 | }
|
|---|
| 1827 |
|
|---|
| 1828 | /*
|
|---|
| 1829 | *@@ WgtQueryVersion:
|
|---|
| 1830 | * this new export with ordinal 3 can return the
|
|---|
| 1831 | * XWorkplace version number which is required
|
|---|
| 1832 | * for this widget to run. For example, if this
|
|---|
| 1833 | * returns 0.9.10, this widget will not run on
|
|---|
| 1834 | * earlier XWorkplace versions.
|
|---|
| 1835 | *
|
|---|
| 1836 | * NOTE: This export was mainly added because the
|
|---|
| 1837 | * prototype for the "Init" export was changed
|
|---|
| 1838 | * with V0.9.9. If this returns 0.9.9, it is
|
|---|
| 1839 | * assumed that the INIT export understands
|
|---|
| 1840 | * the new FNWGTINITMODULE_099 format (see center.h).
|
|---|
| 1841 | */
|
|---|
| 1842 |
|
|---|
| 1843 | VOID EXPENTRY WgtQueryVersion(PULONG pulMajor,
|
|---|
| 1844 | PULONG pulMinor,
|
|---|
| 1845 | PULONG pulRevision)
|
|---|
| 1846 | {
|
|---|
| 1847 | *pulMajor = 0;
|
|---|
| 1848 | *pulMinor = 9;
|
|---|
| 1849 | *pulRevision = 9;
|
|---|
| 1850 | }
|
|---|
| 1851 |
|
|---|