Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

916 lines
29 KiB

  1. /*++
  2. Copyright (c) 2000 Microsoft Corporation
  3. Module Name:
  4. supertip.cpp
  5. Abstract:
  6. This module contains the code to invoke SuperTIP.
  7. Author:
  8. Michael Tsang (MikeTs) 11-Jul-2000
  9. Environment:
  10. User mode
  11. Revision History:
  12. --*/
  13. #include "pch.h"
  14. #include <cpl.h>
  15. #include <shellapi.h>
  16. static const TCHAR tstrClassName[] = TEXT("SuperTIPWndClass");
  17. UINT guimsgTaskbarCreated = 0;
  18. UINT guimsgTrayCallback = 0;
  19. HICON ghSuperTIPIcon = NULL;
  20. HMENU ghmenuTray = NULL;
  21. HMENU ghmenuTrayPopup = NULL;
  22. TCHAR gtszSuperTIPTitle[64] = {0};
  23. TCHAR gtszBalloonTip[256] = {0};
  24. /*++
  25. @doc INTERNAL
  26. @func unsigned | SuperTIPThread | SuperTIP thread.
  27. @parm IN PVOID | param | Points to the thread structure.
  28. @rvalue Always returns 0.
  29. --*/
  30. unsigned __stdcall
  31. SuperTIPThread(
  32. IN PVOID param
  33. )
  34. {
  35. TRACEPROC("SuperTIPThread", 2)
  36. WNDCLASSEX wc;
  37. BOOL fSuccess = TRUE;
  38. HRESULT hr;
  39. TRACEENTER(("(pThread=%p)\n", param));
  40. TRACEASSERT(ghwndSuperTIP == NULL);
  41. guimsgTaskbarCreated = RegisterWindowMessage(TEXT("TaskbarCreated"));
  42. guimsgTrayCallback = RegisterWindowMessage(
  43. TEXT("{D0061156-D460-4230-AF87-9E7658AB987D}"));
  44. TRACEINFO(1, ("TaskbarCreateMsg=%x, TrayCallbackMsg=%x\n",
  45. guimsgTaskbarCreated, guimsgTrayCallback));
  46. LoadString(ghMod,
  47. IDS_SUPERTIP_TITLE,
  48. gtszSuperTIPTitle,
  49. ARRAYSIZE(gtszSuperTIPTitle));
  50. LoadString(ghMod,
  51. IDS_BALLOON_TEXT,
  52. gtszBalloonTip,
  53. ARRAYSIZE(gtszBalloonTip));
  54. ghSuperTIPIcon = (HICON)LoadImage(ghMod,
  55. MAKEINTRESOURCE(IDI_SUPERTIP),
  56. IMAGE_ICON,
  57. 16,
  58. 16,
  59. 0);
  60. TRACEASSERT(ghSuperTIPIcon != NULL);
  61. memset(&wc, 0, sizeof(wc));
  62. wc.cbSize = sizeof(wc);
  63. wc.lpfnWndProc = SuperTIPWndProc;
  64. wc.hInstance = ghMod;
  65. wc.lpszClassName = tstrClassName;
  66. RegisterClassEx(&wc);
  67. //
  68. // Protect the majority of this thread in a try/except block to catch any
  69. // faults in the SuperTip object. If there is a fault, this thread will
  70. // be destroyed and then recreated.
  71. //
  72. __try
  73. {
  74. while (fSuccess && !(gdwfTabSrv & TSF_TERMINATE))
  75. {
  76. if (SwitchThreadToInputDesktop((PTSTHREAD)param))
  77. {
  78. BOOL fImpersonate;
  79. fImpersonate = ImpersonateCurrentUser();
  80. CoInitialize(NULL);
  81. hr = CoCreateInstance(CLSID_SuperTip,
  82. NULL,
  83. CLSCTX_INPROC_SERVER,
  84. IID_ISuperTip,
  85. (LPVOID *)&gpISuperTip);
  86. if (SUCCEEDED(hr))
  87. {
  88. hr = CoCreateInstance(CLSID_TellMe,
  89. NULL,
  90. CLSCTX_INPROC_SERVER,
  91. IID_TellMe,
  92. (LPVOID *)&gpITellMe);
  93. if (FAILED(hr))
  94. {
  95. TABSRVERR(("CoCreateInstance on ITellMe failed (hr=%x)\n", hr));
  96. }
  97. ghwndSuperTIP = CreateWindow(tstrClassName,
  98. tstrClassName,
  99. WS_POPUP,
  100. CW_USEDEFAULT,
  101. 0,
  102. CW_USEDEFAULT,
  103. 0,
  104. NULL,
  105. NULL,
  106. ghMod,
  107. 0);
  108. if (ghwndSuperTIP != NULL)
  109. {
  110. BOOL rc;
  111. MSG msg;
  112. PostMessage(ghwndSuperTIP, WM_SUPERTIP_INIT, 0, 0);
  113. //
  114. // Pump messages for our window until it is destroyed.
  115. //
  116. ((PTSTHREAD)param)->pvSDTParam = ghwndSuperTIP;
  117. while (GetMessage(&msg, NULL, 0, 0))
  118. {
  119. TranslateMessage(&msg);
  120. DispatchMessage(&msg);
  121. }
  122. ((PTSTHREAD)param)->pvSDTParam = ghwndSuperTIP = NULL;
  123. gdwfTabSrv &= ~TSF_TRAYICON_CREATED;
  124. }
  125. else
  126. {
  127. TABSRVERR(("Failed to create SuperTIP window.\n"));
  128. fSuccess = FALSE;
  129. }
  130. if (SUCCEEDED(hr))
  131. {
  132. gpITellMe->Release();
  133. gpITellMe = NULL;
  134. }
  135. gpISuperTip->Release();
  136. gpISuperTip = NULL;
  137. }
  138. else
  139. {
  140. TABSRVERR(("Failed to create SuperTIP COM instance (hr=%x).\n",
  141. hr));
  142. fSuccess = FALSE;
  143. }
  144. CoUninitialize();
  145. if (fImpersonate)
  146. {
  147. RevertToSelf();
  148. }
  149. }
  150. else
  151. {
  152. TABSRVERR(("Failed to set current desktop.\n"));
  153. fSuccess = FALSE;
  154. }
  155. }
  156. }
  157. __except(EXCEPTION_EXECUTE_HANDLER)
  158. {
  159. TABSRVERR(("Exception in SuperTIP thread (%X).\n", _exception_code()));
  160. }
  161. DestroyIcon(ghSuperTIPIcon);
  162. ghSuperTIPIcon = NULL;
  163. TRACEEXIT(("=0\n"));
  164. return 0;
  165. } //SuperTIPThread
  166. /*++
  167. @doc EXTERNAL
  168. @func LRESULT | SuperTIPWndProc | SuperTIP window proc.
  169. @parm IN HWND | hwnd | Window handle.
  170. @parm IN UINT | uiMsg | Window message.
  171. @parm IN WPARAM | wParam | Param 1.
  172. @parm IN LPARAM | lParam | Param 2.
  173. @rvalue Return code is message specific.
  174. --*/
  175. LRESULT CALLBACK
  176. SuperTIPWndProc(
  177. IN HWND hwnd,
  178. IN UINT uiMsg,
  179. IN WPARAM wParam,
  180. IN LPARAM lParam
  181. )
  182. {
  183. TRACEPROC("SuperTIPWndProc", 5)
  184. LRESULT rc = 0;
  185. TRACEENTER(("(hwnd=%x,Msg=%s,wParam=%x,lParam=%x)\n",
  186. hwnd, LookupName(uiMsg, WMMsgNames), wParam, lParam));
  187. if ((guimsgTaskbarCreated != 0) && (uiMsg == guimsgTaskbarCreated))
  188. {
  189. TRACEINFO(1, ("Taskbar created...\n"));
  190. //
  191. // If whistler fixes the shell bug, we can restore this code.
  192. //
  193. gdwfTabSrv |= TSF_TASKBAR_CREATED;
  194. if (!CreateTrayIcon(hwnd,
  195. guimsgTrayCallback,
  196. ghSuperTIPIcon,
  197. gtszSuperTIPTitle))
  198. {
  199. TABSRVERR(("OnTaskbarCreated: failed to create tray icon.\n"));
  200. }
  201. }
  202. else if ((guimsgTrayCallback != 0) && (uiMsg == guimsgTrayCallback))
  203. {
  204. switch (lParam)
  205. {
  206. case WM_LBUTTONUP:
  207. {
  208. int iDefaultCmd = GetMenuDefaultItem(ghmenuTrayPopup,
  209. FALSE,
  210. 0);
  211. //
  212. // Perform default action.
  213. //
  214. if (iDefaultCmd != -1)
  215. {
  216. PostMessage(hwnd, WM_COMMAND, iDefaultCmd, 0);
  217. }
  218. break;
  219. }
  220. case WM_RBUTTONUP:
  221. {
  222. TCHAR tszMenuText[128];
  223. POINT pt;
  224. //
  225. // Do popup menu.
  226. //
  227. TRACEASSERT(ghmenuTrayPopup != NULL);
  228. LoadString(ghMod,
  229. gdwfTabSrv & TSF_SUPERTIP_OPENED?
  230. IDS_HIDE_SUPERTIP: IDS_SHOW_SUPERTIP,
  231. tszMenuText,
  232. ARRAYSIZE(tszMenuText));
  233. ModifyMenu(ghmenuTrayPopup,
  234. IDM_OPEN,
  235. MF_BYCOMMAND | MF_STRING,
  236. IDM_OPEN,
  237. tszMenuText);
  238. LoadString(ghMod,
  239. gdwfTabSrv & TSF_PORTRAIT_MODE?
  240. IDS_SCREEN_LANDSCAPE: IDS_SCREEN_PORTRAIT,
  241. tszMenuText,
  242. ARRAYSIZE(tszMenuText));
  243. ModifyMenu(ghmenuTrayPopup,
  244. IDM_TOGGLE_ROTATION,
  245. MF_BYCOMMAND | MF_STRING,
  246. IDM_TOGGLE_ROTATION,
  247. tszMenuText);
  248. GetCursorPos(&pt);
  249. //
  250. // It is necessary to set focus on this window in order to
  251. // popup the menu.
  252. //
  253. SetForegroundWindow(hwnd);
  254. TrackPopupMenu(ghmenuTrayPopup,
  255. TPM_NONOTIFY | TPM_RIGHTBUTTON,
  256. pt.x,
  257. pt.y,
  258. 0,
  259. hwnd,
  260. NULL);
  261. break;
  262. }
  263. }
  264. }
  265. else
  266. {
  267. HRESULT hr;
  268. switch (uiMsg)
  269. {
  270. case WM_SUPERTIP_INIT:
  271. hr = gpISuperTip->Activate();
  272. if (SUCCEEDED(hr))
  273. {
  274. hr = gpISuperTip->SetNotifyHWND(hwnd,
  275. WM_SUPERTIP_NOTIFY,
  276. 0);
  277. if (FAILED(hr))
  278. {
  279. TABSRVERR(("Failed to set notify hwnd (hr=%x)\n", hr));
  280. }
  281. //
  282. // If we are not on the Winlogon desktop, wait for the
  283. // shell's tray notification window to be created so
  284. // our tray icon can be added. Keep checking the
  285. // Winlogon desktop flag in case the user switches
  286. // desktops while this loop is still waiting for the
  287. // tray window.
  288. //
  289. int i;
  290. PTSTHREAD SuperTIPThread = FindThread(TSF_SUPERTIPTHREAD);
  291. for (i = 0;
  292. (i < 30) &&
  293. !(SuperTIPThread->dwfThread & THREADF_DESKTOP_WINLOGON);
  294. i++)
  295. {
  296. if (FindWindow(TEXT("Shell_TrayWnd"), NULL))
  297. {
  298. break;
  299. }
  300. Sleep(500);
  301. }
  302. //
  303. // At this point we're either on the Winlogon desktop or
  304. // we're ready to create our tray icon.
  305. //
  306. if (SuperTIPThread->dwfThread & THREADF_DESKTOP_WINLOGON)
  307. {
  308. POINT pt;
  309. pt.x = gcxPrimary;
  310. pt.y = gcyPrimary;
  311. gpISuperTip->Show(TIP_SHOW_KBDONLY, pt);
  312. gdwfTabSrv |= TSF_SUPERTIP_OPENED;
  313. }
  314. else
  315. {
  316. if (i > 1)
  317. {
  318. TRACEINFO(1, ("Shell_TrayWnd loop count: %d\n", i));
  319. }
  320. ghmenuTray = LoadMenu(ghMod,
  321. MAKEINTRESOURCE(IDR_TRAYMENU));
  322. TRACEASSERT(ghmenuTray != NULL);
  323. ghmenuTrayPopup = GetSubMenu(ghmenuTray, 0);
  324. TRACEASSERT(ghmenuTrayPopup != NULL);
  325. SetMenuDefaultItem(ghmenuTrayPopup, IDM_OPEN, FALSE);
  326. if (!CreateTrayIcon(hwnd,
  327. guimsgTrayCallback,
  328. ghSuperTIPIcon,
  329. gtszSuperTIPTitle))
  330. {
  331. TABSRVERR(("OnCreate: failed to create tray icon.\n"));
  332. }
  333. }
  334. }
  335. else
  336. {
  337. TABSRVERR(("Failed to activate SuperTIP (hr=%d)\n", hr));
  338. rc = -1;
  339. }
  340. break;
  341. case WM_CLOSE:
  342. ghwndSuperTIPInk = NULL;
  343. guimsgSuperTIPInk = 0;
  344. gdwfTabSrv &= ~(TSF_SUPERTIP_OPENED | TSF_SUPERTIP_SENDINK);
  345. if (gdwfTabSrv & TSF_TRAYICON_CREATED)
  346. {
  347. if (!DestroyTrayIcon(hwnd,
  348. guimsgTrayCallback,
  349. ghSuperTIPIcon))
  350. {
  351. TABSRVERR(("failed to destroy tray icon.\n"));
  352. }
  353. }
  354. if (ghmenuTray != NULL)
  355. {
  356. DestroyMenu(ghmenuTray);
  357. ghmenuTray = ghmenuTrayPopup = NULL;
  358. }
  359. gpISuperTip->Deactivate();
  360. DestroyWindow(hwnd);
  361. PostQuitMessage(0);
  362. break;
  363. case WM_DISPLAYCHANGE:
  364. UpdateRotation();
  365. break;
  366. case WM_SETTINGCHANGE:
  367. if ((wParam == SPI_SETKEYBOARDDELAY) ||
  368. (wParam == SPI_SETKEYBOARDSPEED))
  369. {
  370. UpdateButtonRepeatRate();
  371. }
  372. break;
  373. case WM_SUPERTIP_NOTIFY:
  374. if (wParam == 0)
  375. {
  376. gdwfTabSrv &= ~TSF_SUPERTIP_OPENED;
  377. if (!(gdwfTabSrv & TSF_SUPERTIP_MINIMIZED_BEFORE))
  378. {
  379. gdwfTabSrv |= TSF_SUPERTIP_MINIMIZED_BEFORE;
  380. if (gdwfTabSrv & TSF_TRAYICON_CREATED)
  381. {
  382. if (!SetBalloonToolTip(hwnd,
  383. guimsgTrayCallback,
  384. gtszSuperTIPTitle,
  385. gtszBalloonTip,
  386. TIMEOUT_BALLOON_TIP,
  387. NIIF_INFO))
  388. {
  389. TABSRVERR(("failed to popup balloon tip.\n"));
  390. }
  391. }
  392. }
  393. }
  394. else if (wParam >= WM_USER)
  395. {
  396. ghwndSuperTIPInk = (HWND)lParam;
  397. guimsgSuperTIPInk = (UINT)wParam;
  398. }
  399. break;
  400. case WM_COMMAND:
  401. switch (LOWORD(wParam))
  402. {
  403. case IDM_OPEN:
  404. {
  405. if (gpITellMe != NULL)
  406. {
  407. HWND hwndTarget;
  408. __try
  409. {
  410. if (SUCCEEDED(
  411. gpITellMe->GetLastValidFocusHWnd(&hwndTarget)))
  412. {
  413. SetForegroundWindow(hwndTarget);
  414. }
  415. }
  416. __except(EXCEPTION_EXECUTE_HANDLER)
  417. {
  418. TABSRVERR(("Exception in TellMe::GetLastValidFocusHWnd (%X).\n",
  419. _exception_code()));
  420. }
  421. }
  422. POINT pt = {0, 0};
  423. HRESULT hr = gpISuperTip->Show(TIP_SHOW_TOGGLE, pt);
  424. gdwfTabSrv ^= TSF_SUPERTIP_OPENED;
  425. break;
  426. }
  427. #ifdef DEBUG
  428. case IDM_PROPERTIES:
  429. {
  430. HMODULE hmod;
  431. APPLET_PROC pfnCplApplet;
  432. LRESULT lrc;
  433. hmod = LoadLibrary(TEXT("tabletpc.cpl"));
  434. if (hmod != NULL)
  435. {
  436. pfnCplApplet = (APPLET_PROC)GetProcAddress(
  437. hmod,
  438. TEXT("CPlApplet"));
  439. if (pfnCplApplet != NULL)
  440. {
  441. pfnCplApplet(hwnd, CPL_DBLCLK, 0, 0);
  442. }
  443. else
  444. {
  445. TABSRVERR(("Failed to get entry point of control panel (err=%d)\n",
  446. GetLastError()));
  447. }
  448. FreeLibrary(hmod);
  449. hmod = NULL;
  450. }
  451. else
  452. {
  453. TABSRVERR(("Failed to load control panel (err=%d)\n",
  454. GetLastError()));
  455. }
  456. break;
  457. }
  458. #endif
  459. case IDM_TOGGLE_ROTATION:
  460. {
  461. #if 0
  462. DEVMODE DevMode;
  463. LONG rcDisplay;
  464. //
  465. // To circumvent the dynamic mode tablet problem,
  466. // we need to enumerate the display modes table to
  467. // force the SMI driver to load a mode table that
  468. // supports portrait modes.
  469. //
  470. EnumDisplayModes();
  471. memset(&DevMode, 0, sizeof(DevMode));
  472. DevMode.dmSize = sizeof(DevMode);
  473. DevMode.dmPelsWidth = gcyPrimary;
  474. DevMode.dmPelsHeight = gcxPrimary;
  475. DevMode.dmFields = DM_PELSWIDTH | DM_PELSHEIGHT;
  476. if (DevMode.dmPelsWidth < DevMode.dmPelsHeight)
  477. {
  478. //
  479. // We are switching to Portrait mode,
  480. // make sure our color depth is 16-bit.
  481. //
  482. DevMode.dmBitsPerPel = 16;
  483. DevMode.dmFields |= DM_BITSPERPEL;
  484. }
  485. rcDisplay = ChangeDisplaySettings(&DevMode,
  486. CDS_UPDATEREGISTRY);
  487. if (rcDisplay < 0)
  488. {
  489. TABSRVERR(("Failed to toggle rotation (rc=%d)\n",
  490. rcDisplay));
  491. //BUGBUG: make this LoadString
  492. MessageBox(NULL,
  493. TEXT("Failed to toggle rotation"),
  494. TEXT(MODNAME),
  495. MB_OK);
  496. }
  497. #endif
  498. //#if 0
  499. typedef BOOL (__stdcall *PFNSETROTATION)(DWORD);
  500. HMODULE hmod = LoadLibrary(TEXT("tabletpc.cpl"));
  501. PFNSETROTATION pfnSetRotation;
  502. LRESULT lrc;
  503. if (hmod != NULL)
  504. {
  505. pfnSetRotation = (PFNSETROTATION)GetProcAddress(
  506. hmod,
  507. TEXT("SetRotation"));
  508. if (pfnSetRotation != NULL)
  509. {
  510. if (pfnSetRotation(
  511. (gdwfTabSrv & TSF_PORTRAIT_MODE)?
  512. 0: RT_CLOCKWISE))
  513. {
  514. //
  515. // Sometimes the system miss sending
  516. // WM_DISPLAYCHANGE, so we will do it
  517. // here just in case.
  518. //
  519. UpdateRotation();
  520. }
  521. }
  522. else
  523. {
  524. TABSRVERR(("Failed to get entry point of SetRotation (err=%d)\n",
  525. GetLastError()));
  526. }
  527. FreeLibrary(hmod);
  528. }
  529. else
  530. {
  531. TABSRVERR(("Failed to load control panel (err=%d)\n",
  532. GetLastError()));
  533. }
  534. //#endif
  535. break;
  536. }
  537. default:
  538. rc = DefWindowProc(hwnd, uiMsg, wParam, lParam);
  539. }
  540. break;
  541. case WM_GESTURE:
  542. {
  543. POINT pt;
  544. //
  545. // Unpack x and y. Sign extend if necessary.
  546. //
  547. pt.x = (LONG)((SHORT)(lParam & 0xffff));
  548. pt.y = (LONG)((SHORT)(lParam >> 16));
  549. switch (wParam)
  550. {
  551. case PopupSuperTIP:
  552. TRACEINFO(1, ("Popup SuperTIP\n"));
  553. gpISuperTip->Show(TIP_SHOW_GESTURE, pt);
  554. gdwfTabSrv |= TSF_SUPERTIP_OPENED;
  555. break;
  556. case PopupMIP:
  557. TRACEINFO(1, ("Popup MIP\n"));
  558. gpISuperTip->ShowMIP(TIP_SHOW_GESTURE, pt);
  559. break;
  560. }
  561. break;
  562. }
  563. default:
  564. rc = DefWindowProc(hwnd, uiMsg, wParam, lParam);
  565. }
  566. }
  567. TRACEEXIT(("=%x\n", rc));
  568. return rc;
  569. } //SuperTIPWndProc
  570. #if 0
  571. /*++
  572. @doc INTERNAL
  573. @func VOID | EnumDisplayModes | Enumerate display modes to force
  574. SMI driver to dynamically load a mode table that supports
  575. Portrait modes.
  576. @parm None.
  577. @rvalue None.
  578. --*/
  579. VOID
  580. EnumDisplayModes(
  581. VOID
  582. )
  583. {
  584. TRACEPROC("EnumDisplayModes", 3)
  585. DWORD i;
  586. DEVMODE DevMode;
  587. TRACEENTER(("()\n"));
  588. for (i = 0; EnumDisplaySettings(NULL, i, &DevMode); ++i)
  589. {
  590. //
  591. // Don't have to do anything.
  592. //
  593. }
  594. TRACEEXIT(("!\n"));
  595. return;
  596. } //EnumDisplayModes
  597. #endif
  598. /*++
  599. @doc INTERNAL
  600. @func VOID | UpdateRotation | Update the rotation info.
  601. @parm None.
  602. @rvalue None.
  603. --*/
  604. VOID
  605. UpdateRotation(
  606. VOID
  607. )
  608. {
  609. TRACEPROC("UpdateRotation", 3)
  610. TRACEENTER(("()\n"));
  611. //
  612. // Display mode has changed, better recompute everything related
  613. // to screen.
  614. //
  615. glVirtualDesktopLeft =
  616. glVirtualDesktopRight =
  617. glVirtualDesktopTop =
  618. glVirtualDesktopBottom = 0;
  619. EnumDisplayMonitors(NULL, NULL, MonitorEnumProc, 0);
  620. gcxPrimary = GetSystemMetrics(SM_CXSCREEN);
  621. gcyPrimary = GetSystemMetrics(SM_CYSCREEN);
  622. gcxScreen = GetSystemMetrics(SM_CXVIRTUALSCREEN);
  623. gcyScreen = GetSystemMetrics(SM_CYVIRTUALSCREEN);
  624. if (gcxPrimary > gcyPrimary)
  625. {
  626. gdwfTabSrv &= ~TSF_PORTRAIT_MODE;
  627. }
  628. else
  629. {
  630. gdwfTabSrv |= TSF_PORTRAIT_MODE;
  631. }
  632. glLongOffset = ((NUM_PIXELS_LONG -
  633. max(gcxPrimary, gcyPrimary))*(MAX_NORMALIZED_X + 1))/
  634. (2*NUM_PIXELS_LONG);
  635. glShortOffset = ((NUM_PIXELS_SHORT -
  636. min(gcxPrimary, gcyPrimary))*(MAX_NORMALIZED_Y + 1))/
  637. (2*NUM_PIXELS_SHORT);
  638. TRACEEXIT(("!\n"));
  639. return;
  640. } //UpdateRotation
  641. /*++
  642. @doc EXTERNAL
  643. @func BOOL | MonitorEnumProc | The callback function for
  644. EnumDisplayMonitors.
  645. @parm IN HMONITOR | hMon | Handle to display monitor.
  646. @parm IN HDC | hdcMon | Handle to monitor DC.
  647. @parm IN LPRECT | lprcMon | Monitor intersection rectangle.
  648. @parm IN LPARAM | dwData | Unused.
  649. @rvalue Always return TRUE to continue enumeration.
  650. --*/
  651. BOOL CALLBACK
  652. MonitorEnumProc(
  653. IN HMONITOR hMon,
  654. IN HDC hdcMon,
  655. IN LPRECT lprcMon,
  656. IN LPARAM dwData
  657. )
  658. {
  659. TRACEPROC("MonitorEnumProc", 3)
  660. TRACEENTER(("(hMon=%x,hdcMon=%x,MonLeft=%d,MonRight=%d,MonTop=%d,MonBottom=%d,dwData=%x)\n",
  661. hMon, hdcMon, lprcMon->left, lprcMon->right, lprcMon->top,
  662. lprcMon->bottom, dwData));
  663. if (lprcMon->left < glVirtualDesktopLeft)
  664. {
  665. glVirtualDesktopLeft = lprcMon->left;
  666. }
  667. if (lprcMon->right - 1 > glVirtualDesktopRight)
  668. {
  669. glVirtualDesktopRight = lprcMon->right - 1;
  670. }
  671. if (lprcMon->top < glVirtualDesktopTop)
  672. {
  673. glVirtualDesktopTop = lprcMon->top;
  674. }
  675. if (lprcMon->bottom - 1> glVirtualDesktopBottom)
  676. {
  677. glVirtualDesktopBottom = lprcMon->bottom - 1;
  678. }
  679. TRACEEXIT(("=1\n"));
  680. return TRUE;
  681. } //MonitorEnumProc
  682. /*++
  683. @doc INTERNAL
  684. @func BOOL | CreateTrayIcon | Create the tray icon.
  685. @parm IN HWND | hwnd | Window handle that the tray can send message to.
  686. @parm IN UINT | umsgTray | Message ID that the tray used to send messages.
  687. @parm IN HICON | hIcon | Icon handle.
  688. @parm IN LPCTSTR | ptszTip | Points to the Tip string.
  689. @rvalue SUCCESS | Returns TRUE.
  690. @rvalue FAILURE | Returns FALSE.
  691. --*/
  692. BOOL
  693. CreateTrayIcon(
  694. IN HWND hwnd,
  695. IN UINT umsgTray,
  696. IN HICON hIcon,
  697. IN LPCTSTR ptszTip
  698. )
  699. {
  700. TRACEPROC("CreateTrayIcon", 2)
  701. BOOL rc;
  702. NOTIFYICONDATA nid;
  703. TRACEENTER(("(hwnd=%x,msgTray=%x,hIcon=%x,Tip=%s)\n",
  704. hwnd, umsgTray, hIcon, ptszTip));
  705. TRACEASSERT(hIcon != NULL);
  706. TRACEASSERT(ptszTip != NULL);
  707. memset(&nid, 0, sizeof(nid));
  708. nid.cbSize = sizeof(nid);
  709. nid.hWnd = hwnd;
  710. nid.uCallbackMessage = umsgTray;
  711. nid.hIcon = hIcon;
  712. lstrcpyn(nid.szTip, ptszTip, ARRAYSIZE(nid.szTip));
  713. nid.uFlags = NIF_ICON | NIF_MESSAGE | NIF_TIP;
  714. rc = Shell_NotifyIcon(NIM_ADD, &nid);
  715. if (rc == TRUE)
  716. {
  717. gdwfTabSrv |= TSF_TRAYICON_CREATED;
  718. }
  719. TRACEEXIT(("=%x\n", rc));
  720. return rc;
  721. } //CreateTrayIcon
  722. /*++
  723. @doc INTERNAL
  724. @func BOOL | DestroyTrayIcon | Destroy the tray icon.
  725. @parm IN HWND | hwnd | Window handle that the tray can send message to.
  726. @parm IN UINT | umsgTray | Message ID that the tray used to send messages.
  727. @parm IN HICON | hIcon | Icon handle.
  728. @parm IN LPCTSTR | ptszTip | Points to the Tip string.
  729. @rvalue SUCCESS | Returns TRUE.
  730. @rvalue FAILURE | Returns FALSE.
  731. --*/
  732. BOOL
  733. DestroyTrayIcon(
  734. IN HWND hwnd,
  735. IN UINT umsgTray,
  736. IN HICON hIcon
  737. )
  738. {
  739. TRACEPROC("DestroyTrayIcon", 2)
  740. BOOL rc;
  741. NOTIFYICONDATA nid;
  742. TRACEENTER(("(hwnd=%x,msgTray=%x,hIcon=%x)\n", hwnd, umsgTray, hIcon));
  743. TRACEASSERT(hIcon != NULL);
  744. TRACEASSERT(gdwfTabSrv & TSF_TRAYICON_CREATED);
  745. memset(&nid, 0, sizeof(nid));
  746. nid.cbSize = sizeof(nid);
  747. nid.hWnd = hwnd;
  748. nid.uCallbackMessage = umsgTray;
  749. nid.hIcon = hIcon;
  750. nid.uFlags = NIF_ICON | NIF_MESSAGE;
  751. rc = Shell_NotifyIcon(NIM_DELETE, &nid);
  752. if (rc == TRUE)
  753. {
  754. gdwfTabSrv &= ~TSF_TRAYICON_CREATED;
  755. }
  756. TRACEEXIT(("=%x\n", rc));
  757. return rc;
  758. } //DestroyTrayIcon
  759. /*++
  760. @doc INTERNAL
  761. @func BOOL | SetBalloonToolTip | Set Balloon Tool Tip on tray icon
  762. @parm IN HWND | hwnd | Window handle that the tray can send message to.
  763. @parm IN UINT | umsgTray | Message ID that the tray used to send messages.
  764. @parm IN LPCTSTR | ptszTitle | Points to the Tip title string.
  765. @parm IN LPCTSTR | ptszTip | Points to the Tip text string.
  766. @parm IN UINT | uTimeout | Specify how long the balloon tip stays up.
  767. @rvalue SUCCESS | Returns TRUE.
  768. @rvalue FAILURE | Returns FALSE.
  769. --*/
  770. BOOL SetBalloonToolTip(
  771. IN HWND hwnd,
  772. IN UINT umsgTray,
  773. IN LPCTSTR ptszTitle,
  774. IN LPCTSTR ptszTip,
  775. IN UINT uTimeout,
  776. IN DWORD dwInfoFlags
  777. )
  778. {
  779. TRACEPROC("SetBalloonToolTip", 2)
  780. BOOL rc;
  781. NOTIFYICONDATA nid;
  782. TRACEENTER(("(hwnd=%x,TrayMsg=%x,Title=%s,Tip=%s,Timeout=%d,InfoFlags=%x)\n",
  783. hwnd, umsgTray, ptszTitle, ptszTip, uTimeout, dwInfoFlags));
  784. TRACEASSERT(gdwfTabSrv & TSF_TRAYICON_CREATED);
  785. memset(&nid, 0, sizeof(nid));
  786. nid.cbSize = sizeof(nid);
  787. nid.hWnd = hwnd;
  788. nid.uFlags = NIF_INFO;
  789. nid.uCallbackMessage = umsgTray;
  790. nid.uTimeout = uTimeout;
  791. lstrcpyn(nid.szInfo, ptszTip, ARRAYSIZE(nid.szInfo));
  792. lstrcpyn(nid.szInfoTitle, ptszTitle, ARRAYSIZE(nid.szInfoTitle));
  793. nid.dwInfoFlags = dwInfoFlags;
  794. rc = Shell_NotifyIcon(NIM_MODIFY, &nid);
  795. TRACEEXIT(("=%x\n", rc));
  796. return rc;
  797. } //SetBalloonToolTip