Leaked source code of windows server 2003
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.

900 lines
26 KiB

  1. #include "stdafx.h"
  2. #include "sfthost.h"
  3. #include "hostutil.h"
  4. #include "moreprog.h"
  5. #include <desktray.h>
  6. #include "tray.h" // To get access to c_tray
  7. #include "rcids.h" // for IDM_PROGRAMS etc.
  8. #include <strsafe.h>
  9. //
  10. // Unfortunately, WTL #undef's SelectFont, so we have to define it again.
  11. //
  12. inline HFONT SelectFont(HDC hdc, HFONT hf)
  13. {
  14. return (HFONT)SelectObject(hdc, hf);
  15. }
  16. CMorePrograms::CMorePrograms(HWND hwnd) :
  17. _lRef(1),
  18. _hwnd(hwnd),
  19. _clrText(CLR_INVALID),
  20. _clrBk(CLR_INVALID)
  21. {
  22. }
  23. CMorePrograms::~CMorePrograms()
  24. {
  25. if (_hf)
  26. DeleteObject(_hf);
  27. if (_hfTTBold)
  28. DeleteObject(_hfTTBold);
  29. if (_hfMarlett)
  30. DeleteObject(_hfMarlett);
  31. ATOMICRELEASE(_pdth);
  32. ATOMICRELEASE(_psmPrograms);
  33. // Note that we do not need to clean up our HWNDs.
  34. // USER does that for us automatically.
  35. }
  36. //
  37. // Metrics changed -- update.
  38. //
  39. void CMorePrograms::_InitMetrics()
  40. {
  41. if (_hwndTT)
  42. {
  43. MakeMultilineTT(_hwndTT);
  44. // Disable/enable infotips based on user preference
  45. SendMessage(_hwndTT, TTM_ACTIVATE, ShowInfoTip(), 0);
  46. }
  47. }
  48. LRESULT CMorePrograms::_OnNCCreate(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
  49. {
  50. CMorePrograms *self = new CMorePrograms(hwnd);
  51. if (self)
  52. {
  53. SetWindowLongPtr(hwnd, GWLP_USERDATA, (LPARAM)self);
  54. return ::DefWindowProc(hwnd, uMsg, wParam, lParam);
  55. }
  56. return FALSE;
  57. }
  58. //
  59. // Create an inner button that is exactly the right size.
  60. //
  61. // Height of inner button = height of text.
  62. // Width of inner button = full width.
  63. //
  64. // This allows us to let USER do most of the work of hit-testing and
  65. // focus rectangling.
  66. //
  67. LRESULT CMorePrograms::_OnCreate(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
  68. {
  69. _hTheme = (PaneDataFromCreateStruct(lParam))->hTheme;
  70. if (!_hTheme)
  71. {
  72. _clrText = GetSysColor(COLOR_MENUTEXT);
  73. _clrBk = GetSysColor(COLOR_MENU);
  74. _hbrBk = GetSysColorBrush(COLOR_MENU);
  75. _colorHighlight = COLOR_HIGHLIGHT;
  76. _colorHighlightText = COLOR_HIGHLIGHTTEXT;
  77. // should match proglist values, in sfthost.cpp
  78. _margins.cxLeftWidth = 2*GetSystemMetrics(SM_CXEDGE);
  79. _margins.cxRightWidth = 2*GetSystemMetrics(SM_CXEDGE);
  80. }
  81. else
  82. {
  83. GetThemeColor(_hTheme, SPP_MOREPROGRAMS, 0, TMT_TEXTCOLOR, &_clrText );
  84. _hbrBk = (HBRUSH) GetStockObject(HOLLOW_BRUSH);
  85. _colorHighlight = COLOR_MENUHILIGHT;
  86. _colorHighlightText = COLOR_HIGHLIGHTTEXT;
  87. // theme designer should make it so these margins match proglist's
  88. GetThemeMargins(_hTheme, NULL, SPP_MOREPROGRAMS, 0, TMT_CONTENTMARGINS, NULL, &_margins);
  89. // get the width of the arrow
  90. SIZE siz = { 0, 0 };
  91. GetThemePartSize(_hTheme, NULL, SPP_MOREPROGRAMSARROW, 0, NULL, TS_TRUE, &siz);
  92. _cxArrow = siz.cx;
  93. }
  94. // If we're restricted, just create the window without doing any work
  95. // We still need to paint our background, so we can't just fail the create
  96. if(SHRestricted(REST_NOSMMOREPROGRAMS))
  97. return TRUE;
  98. if (!LoadString(_Module.GetResourceInstance(),
  99. IDS_STARTPANE_MOREPROGRAMS, _szMessage, ARRAYSIZE(_szMessage)))
  100. {
  101. return FALSE;
  102. }
  103. // Find the accelerator
  104. _chMnem = CharUpperChar(SHFindMnemonic(_szMessage));
  105. _hf = LoadControlFont(_hTheme, SPP_MOREPROGRAMS, FALSE, 0);
  106. // Get some information about the font the user has selected
  107. // and create a Marlett font at a matching size.
  108. TEXTMETRIC tm;
  109. HDC hdc = GetDC(hwnd);
  110. if (hdc)
  111. {
  112. HFONT hfPrev = SelectFont(hdc, _hf);
  113. if (hfPrev)
  114. {
  115. SIZE sizText;
  116. GetTextExtentPoint32(hdc, _szMessage, lstrlen(_szMessage), &sizText);
  117. _cxText = sizText.cx + GetSystemMetrics(SM_CXEDGE); // chevron should be a little right of the text
  118. if (GetTextMetrics(hdc, &tm))
  119. {
  120. _tmAscent = tm.tmAscent;
  121. LOGFONT lf;
  122. ZeroMemory(&lf, sizeof(lf));
  123. lf.lfHeight = _tmAscent;
  124. lf.lfWeight = FW_NORMAL;
  125. lf.lfCharSet = SYMBOL_CHARSET;
  126. StringCchCopy(lf.lfFaceName, ARRAYSIZE(lf.lfFaceName), TEXT("Marlett"));
  127. _hfMarlett = CreateFontIndirect(&lf);
  128. if (_hfMarlett)
  129. {
  130. SelectFont(hdc, _hfMarlett);
  131. if (GetTextMetrics(hdc, &tm))
  132. {
  133. _tmAscentMarlett = tm.tmAscent;
  134. }
  135. if (0 == _cxArrow) // if we're not themed, or the GetThemePartSize failed,
  136. {
  137. // set the width of the Marlett arrow into _cxArrow
  138. GetTextExtentPoint32(hdc, GetLayout(hdc) & LAYOUT_RTL ? TEXT("w") : TEXT("8"), 1, &sizText);
  139. _cxArrow = sizText.cx;
  140. }
  141. }
  142. }
  143. SelectFont(hdc, hfPrev);
  144. }
  145. ReleaseDC(hwnd, hdc);
  146. }
  147. if (!_tmAscentMarlett)
  148. {
  149. return FALSE;
  150. }
  151. // This is the same large icon setting from proglist
  152. BOOL bLargeIcons = SHRegGetBoolUSValue(REGSTR_EXPLORER_ADVANCED, REGSTR_VAL_DV2_LARGEICONS, FALSE, TRUE /* default to large*/);
  153. RECT rc;
  154. GetClientRect(_hwnd, &rc);
  155. rc.left += _margins.cxLeftWidth;
  156. rc.right -= _margins.cxRightWidth;
  157. rc.top += _margins.cyTopHeight;
  158. rc.bottom -= _margins.cyBottomHeight;
  159. // Compute the text indent value, so more programs lines up with text on icons in programs list
  160. _cxTextIndent = (3 * GetSystemMetrics(SM_CXEDGE)) + // 2 between icon&text + 1 before icon
  161. GetSystemMetrics(bLargeIcons ? SM_CXICON : SM_CXSMICON);
  162. // truncate the indent, if the text won't fit in the given area
  163. if (_cxTextIndent > RECTWIDTH(rc) - (_cxText + _cxArrow))
  164. {
  165. TraceMsg(TF_WARNING, "StartMenu: '%s' is %dpx, only room for %d- notify localizers!",_szMessage, _cxText, RECTWIDTH(rc)-(_cxArrow+_cxTextIndent));
  166. _cxTextIndent = max(0, RECTWIDTH(rc) - (_cxText + _cxArrow));
  167. }
  168. ASSERT(RECTHEIGHT(rc) > _tmAscent);
  169. _iTextCenterVal = (RECTHEIGHT(rc) - _tmAscent) / 2;
  170. // Do not set WS_TABSTOP or WS_GROUP; CMorePrograms handles that
  171. // BS_NOTIFY ensures that we get BN_SETFOCUS and BN_KILLFOCUS
  172. DWORD dwStyle = WS_CHILD | WS_CLIPCHILDREN | WS_CLIPSIBLINGS | WS_VISIBLE |
  173. BS_OWNERDRAW;
  174. _hwndButton = CreateWindowEx(0, TEXT("button"), _szMessage, dwStyle,
  175. rc.left, rc.top, RECTWIDTH(rc), RECTHEIGHT(rc),
  176. _hwnd, (HMENU)IntToPtr(IDC_BUTTON),
  177. _Module.GetModuleInstance(), NULL);
  178. if (!_hwndButton)
  179. {
  180. return FALSE;
  181. }
  182. //
  183. // Don't freak out if this fails. It just means that the accessibility
  184. // stuff won't be perfect.
  185. //
  186. SetAccessibleSubclassWindow(_hwndButton);
  187. if (_hf)
  188. SetWindowFont(_hwndButton, _hf, FALSE);
  189. // Unlike the button itself, failure to create the tooltip is nonfatal.
  190. // only create the tooltip if auto-cascade is off
  191. if (!SHRegGetBoolUSValue(REGSTR_EXPLORER_ADVANCED, REGSTR_VAL_DV2_AUTOCASCADE, FALSE, TRUE))
  192. _hwndTT = _CreateTooltip();
  193. _InitMetrics();
  194. // We can survive if this fails to be created
  195. CoCreateInstance(CLSID_DragDropHelper, NULL, CLSCTX_INPROC_SERVER,
  196. IID_PPV_ARG(IDropTargetHelper, &_pdth));
  197. //
  198. // If this fails, no big whoop - you just don't get
  199. // drag/drop, boo hoo.
  200. //
  201. RegisterDragDrop(_hwndButton, this);
  202. return TRUE;
  203. }
  204. HWND CMorePrograms::_CreateTooltip()
  205. {
  206. DWORD dwStyle = WS_BORDER | TTS_NOPREFIX;
  207. HWND hwnd = CreateWindowEx(0, TOOLTIPS_CLASS, NULL, dwStyle,
  208. 0, 0, 0, 0,
  209. _hwndButton, NULL,
  210. _Module.GetModuleInstance(), NULL);
  211. if (hwnd)
  212. {
  213. TCHAR szBuf[MAX_PATH];
  214. TOOLINFO ti;
  215. ti.cbSize = sizeof(ti);
  216. ti.hwnd = _hwnd;
  217. ti.uId = reinterpret_cast<UINT_PTR>(_hwndButton);
  218. ti.uFlags = TTF_IDISHWND | TTF_SUBCLASS;
  219. ti.hinst = _Module.GetResourceInstance();
  220. // We can't use MAKEINTRESOURCE because that allows only up to 80
  221. // characters for text, and our text can be longer than that.
  222. UINT ids = IDS_STARTPANE_MOREPROGRAMS_TIP;
  223. ti.lpszText = szBuf;
  224. if (LoadString(_Module.GetResourceInstance(), ids, szBuf, ARRAYSIZE(szBuf)))
  225. {
  226. SendMessage(hwnd, TTM_ADDTOOL, 0, reinterpret_cast<LPARAM>(&ti));
  227. }
  228. }
  229. return hwnd;
  230. }
  231. LRESULT CMorePrograms::_OnDestroy(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
  232. {
  233. RevokeDragDrop(_hwndButton);
  234. return DefWindowProc(hwnd, uMsg, wParam, lParam);
  235. }
  236. LRESULT CMorePrograms::_OnNCDestroy(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
  237. {
  238. // WARNING! "this" might be invalid (if WM_NCCREATE failed), so
  239. // do not use any member variables!
  240. LRESULT lres = DefWindowProc(hwnd, uMsg, wParam, lParam);
  241. SetWindowPtr0(hwnd, 0);
  242. if (this)
  243. {
  244. this->Release();
  245. }
  246. return lres;
  247. }
  248. LRESULT CMorePrograms::_OnCtlColorBtn(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
  249. {
  250. HDC hdc = reinterpret_cast<HDC>(wParam);
  251. if (_clrText != CLR_INVALID)
  252. {
  253. SetTextColor(hdc, _clrText);
  254. }
  255. if (_clrBk != CLR_INVALID)
  256. {
  257. SetBkColor(hdc, _clrBk);
  258. }
  259. return reinterpret_cast<LRESULT>(_hbrBk);
  260. }
  261. LRESULT CMorePrograms::_OnDrawItem(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
  262. {
  263. LPDRAWITEMSTRUCT pdis = reinterpret_cast<LPDRAWITEMSTRUCT>(lParam);
  264. ASSERT(pdis->CtlType == ODT_BUTTON);
  265. ASSERT(pdis->CtlID == IDC_BUTTON);
  266. if (pdis->itemAction & (ODA_DRAWENTIRE | ODA_FOCUS))
  267. {
  268. BOOL fRTLReading = GetLayout(pdis->hDC) & LAYOUT_RTL;
  269. UINT fuOptions = 0;
  270. if (fRTLReading)
  271. {
  272. fuOptions |= ETO_RTLREADING;
  273. }
  274. HFONT hfPrev = SelectFont(pdis->hDC, _hf);
  275. if (hfPrev)
  276. {
  277. BOOL fHot = (pdis->itemState & ODS_FOCUS) || _tmHoverStart;
  278. if (fHot)
  279. {
  280. // hot background
  281. FillRect(pdis->hDC, &pdis->rcItem, GetSysColorBrush(_colorHighlight));
  282. SetTextColor(pdis->hDC, GetSysColor(_colorHighlightText));
  283. }
  284. else if (_hTheme)
  285. {
  286. // Themed non-hot background = custom
  287. RECT rc;
  288. GetClientRect(hwnd, &rc);
  289. MapWindowRect(hwnd, pdis->hwndItem, &rc);
  290. DrawThemeBackground(_hTheme, pdis->hDC, SPP_MOREPROGRAMS, 0, &rc, 0);
  291. }
  292. else
  293. {
  294. // non-themed non-hot background
  295. FillRect(pdis->hDC, &pdis->rcItem, _hbrBk);
  296. }
  297. int iOldMode = SetBkMode(pdis->hDC, TRANSPARENT);
  298. // _cxTextIndent will move it in the current width of an icon (small or large), plus the space we add between an icon and the text
  299. pdis->rcItem.left += _cxTextIndent;
  300. UINT dtFlags = DT_VCENTER | DT_SINGLELINE | DT_EDITCONTROL;
  301. if (fRTLReading)
  302. {
  303. dtFlags |= DT_RTLREADING;
  304. }
  305. if (pdis->itemState & ODS_NOACCEL)
  306. {
  307. dtFlags |= DT_HIDEPREFIX;
  308. }
  309. DrawText(pdis->hDC, _szMessage, -1, &pdis->rcItem, dtFlags);
  310. RECT rc = pdis->rcItem;
  311. rc.left += _cxText;
  312. if (_hTheme)
  313. {
  314. if (_iTextCenterVal < 0) // text is taller than the bitmap
  315. rc.top += (-_iTextCenterVal);
  316. rc.right = rc.left + _cxArrow; // clip rectangle down to the minumum size...
  317. DrawThemeBackground(_hTheme, pdis->hDC, SPP_MOREPROGRAMSARROW,
  318. fHot ? SPS_HOT : 0, &rc, 0);
  319. }
  320. else
  321. {
  322. if (SelectFont(pdis->hDC, _hfMarlett))
  323. {
  324. rc.top = rc.top + _tmAscent - _tmAscentMarlett + (_iTextCenterVal > 0 ? _iTextCenterVal : 0);
  325. TCHAR chOut = fRTLReading ? TEXT('w') : TEXT('8');
  326. if (EVAL(!IsRectEmpty(&rc)))
  327. {
  328. ExtTextOut(pdis->hDC, rc.left, rc.top, fuOptions, &rc, &chOut, 1, NULL);
  329. rc.right = rc.left + _cxArrow;
  330. }
  331. }
  332. }
  333. _rcExclude = rc;
  334. _rcExclude.left -= _cxText; // includes the text in the exclusion rectangle.
  335. MapWindowRect(pdis->hwndItem, NULL, &_rcExclude);
  336. SetBkMode(pdis->hDC, iOldMode);
  337. SelectFont(pdis->hDC, hfPrev);
  338. }
  339. }
  340. //
  341. // Since we are emulating a menu item, we don't need to draw a
  342. // focus rectangle.
  343. //
  344. return TRUE;
  345. }
  346. void CMorePrograms::_TrackShellMenu(DWORD dwFlags)
  347. {
  348. // Pop the balloon tip and tell the Start Menu not to offer it any more
  349. _PopBalloon();
  350. _SendNotify(_hwnd, SMN_SEENNEWITEMS);
  351. SMNTRACKSHELLMENU tsm;
  352. tsm.itemID = 0;
  353. tsm.dwFlags = dwFlags;
  354. if (!_psmPrograms)
  355. {
  356. CoCreateInstance(CLSID_PersonalStartMenu, NULL, CLSCTX_INPROC,
  357. IID_PPV_ARG(IShellMenu, &_psmPrograms));
  358. }
  359. if (_psmPrograms)
  360. {
  361. tsm.psm = _psmPrograms;
  362. tsm.rcExclude = _rcExclude;
  363. HWND hwnd = _hwnd;
  364. _fMenuOpen = TRUE;
  365. _SendNotify(_hwnd, SMN_TRACKSHELLMENU, &tsm.hdr);
  366. }
  367. }
  368. LRESULT CMorePrograms::_OnCommand(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
  369. {
  370. switch (GET_WM_COMMAND_ID(wParam, lParam))
  371. {
  372. case IDC_BUTTON:
  373. switch (GET_WM_COMMAND_CMD(wParam, lParam))
  374. {
  375. case BN_CLICKED:
  376. _TrackShellMenu(0);
  377. break;
  378. }
  379. break;
  380. case IDC_KEYPRESS:
  381. _TrackShellMenu(MPPF_KEYBOARD | MPPF_INITIALSELECT);
  382. break;
  383. }
  384. return 0;
  385. }
  386. LRESULT CMorePrograms::_OnEraseBkgnd(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
  387. {
  388. RECT rc;
  389. GetClientRect(hwnd, &rc);
  390. if (_hTheme)
  391. {
  392. DrawThemeBackground(_hTheme, (HDC)wParam, SPP_MOREPROGRAMS, 0, &rc, 0);
  393. }
  394. else
  395. SHFillRectClr((HDC)wParam, &rc, _clrBk);
  396. return 0;
  397. }
  398. LRESULT CMorePrograms::_OnNotify(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
  399. {
  400. LPNMHDR pnm = reinterpret_cast<LPNMHDR>(lParam);
  401. switch (pnm->code)
  402. {
  403. case SMN_FINDITEM:
  404. return _OnSMNFindItem(CONTAINING_RECORD(pnm, SMNDIALOGMESSAGE, hdr));
  405. case SMN_SHOWNEWAPPSTIP:
  406. return _OnSMNShowNewAppsTip(CONTAINING_RECORD(pnm, SMNMBOOL, hdr));
  407. case SMN_DISMISS:
  408. return _OnSMNDismiss();
  409. case SMN_APPLYREGION:
  410. return HandleApplyRegion(_hwnd, _hTheme, (SMNMAPPLYREGION *)lParam, SPP_MOREPROGRAMS, 0);
  411. case SMN_SHELLMENUDISMISSED:
  412. _fMenuOpen = FALSE;
  413. return 0;
  414. }
  415. return 0;
  416. }
  417. LRESULT CMorePrograms::_OnSMNFindItem(PSMNDIALOGMESSAGE pdm)
  418. {
  419. if(SHRestricted(REST_NOSMMOREPROGRAMS))
  420. return 0;
  421. switch (pdm->flags & SMNDM_FINDMASK)
  422. {
  423. // Life is simple if you have only one item -- all searches succeed!
  424. case SMNDM_FINDFIRST:
  425. case SMNDM_FINDLAST:
  426. case SMNDM_FINDNEAREST:
  427. case SMNDM_HITTEST:
  428. pdm->itemID = 0;
  429. return TRUE;
  430. case SMNDM_FINDFIRSTMATCH:
  431. {
  432. TCHAR tch = CharUpperChar((TCHAR)pdm->pmsg->wParam);
  433. if (tch == _chMnem)
  434. {
  435. pdm->itemID = 0;
  436. return TRUE;
  437. }
  438. }
  439. break; // not found
  440. case SMNDM_FINDNEXTMATCH:
  441. break; // there is only one item so there can't be a "next"
  442. case SMNDM_FINDNEXTARROW:
  443. if (pdm->flags & SMNDM_TRYCASCADE)
  444. {
  445. FORWARD_WM_COMMAND(_hwnd, IDC_KEYPRESS, NULL, 0, PostMessage);
  446. return TRUE;
  447. }
  448. break; // not found
  449. case SMNDM_INVOKECURRENTITEM:
  450. case SMNDM_OPENCASCADE:
  451. if (pdm->flags & SMNDM_KEYBOARD)
  452. {
  453. FORWARD_WM_COMMAND(_hwnd, IDC_KEYPRESS, NULL, 0, PostMessage);
  454. }
  455. else
  456. {
  457. FORWARD_WM_COMMAND(_hwnd, IDC_BUTTON, NULL, 0, PostMessage);
  458. }
  459. return TRUE;
  460. case SMNDM_FINDITEMID:
  461. return TRUE;
  462. default:
  463. ASSERT(!"Unknown SMNDM command");
  464. break;
  465. }
  466. //
  467. // If not found, then tell caller what our orientation is (vertical)
  468. // and where the currently-selected item is.
  469. //
  470. pdm->flags |= SMNDM_VERTICAL;
  471. pdm->pt.x = 0;
  472. pdm->pt.y = 0;
  473. return FALSE;
  474. }
  475. //
  476. // The boolean parameter in the SMNMBOOL tells us whether to display or
  477. // hide the balloon tip.
  478. //
  479. LRESULT CMorePrograms::_OnSMNShowNewAppsTip(PSMNMBOOL psmb)
  480. {
  481. if(SHRestricted(REST_NOSMMOREPROGRAMS))
  482. return 0;
  483. if (psmb->f)
  484. {
  485. if (_hwndTT)
  486. {
  487. SendMessage(_hwndTT, TTM_ACTIVATE, FALSE, 0);
  488. }
  489. if (!_hwndBalloon)
  490. {
  491. RECT rc;
  492. GetWindowRect(_hwndButton, &rc);
  493. if (!_hfTTBold)
  494. {
  495. NONCLIENTMETRICS ncm;
  496. ncm.cbSize = sizeof(ncm);
  497. if (SystemParametersInfo(SPI_GETNONCLIENTMETRICS, sizeof(ncm), &ncm, 0))
  498. {
  499. ncm.lfStatusFont.lfWeight = FW_BOLD;
  500. SHAdjustLOGFONT(&ncm.lfStatusFont);
  501. _hfTTBold = CreateFontIndirect(&ncm.lfStatusFont);
  502. }
  503. }
  504. _hwndBalloon = CreateBalloonTip(_hwnd,
  505. rc.left + _cxTextIndent + _cxText,
  506. (rc.top + rc.bottom)/2,
  507. _hfTTBold, 0,
  508. IDS_STARTPANE_MOREPROGRAMS_BALLOONTITLE);
  509. if (_hwndBalloon)
  510. {
  511. SetProp(_hwndBalloon, PROP_DV2_BALLOONTIP, DV2_BALLOONTIP_MOREPROG);
  512. }
  513. }
  514. }
  515. else
  516. {
  517. _PopBalloon();
  518. }
  519. return 0;
  520. }
  521. void CMorePrograms::_PopBalloon()
  522. {
  523. if (_hwndBalloon)
  524. {
  525. DestroyWindow(_hwndBalloon);
  526. _hwndBalloon = NULL;
  527. }
  528. if (_hwndTT)
  529. {
  530. SendMessage(_hwndTT, TTM_ACTIVATE, TRUE, 0);
  531. }
  532. }
  533. LRESULT CMorePrograms::_OnSMNDismiss()
  534. {
  535. _PopBalloon();
  536. return 0;
  537. }
  538. LRESULT CMorePrograms::_OnSysColorChange(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
  539. {
  540. // update colors in classic mode
  541. if (!_hTheme)
  542. {
  543. _clrText = GetSysColor(COLOR_MENUTEXT);
  544. _clrBk = GetSysColor(COLOR_MENU);
  545. _hbrBk = GetSysColorBrush(COLOR_MENU);
  546. }
  547. SHPropagateMessage(hwnd, uMsg, wParam, lParam, SPM_SEND | SPM_ONELEVEL);
  548. return 0;
  549. }
  550. LRESULT CMorePrograms::_OnDisplayChange(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
  551. {
  552. _InitMetrics();
  553. SHPropagateMessage(hwnd, uMsg, wParam, lParam, SPM_SEND | SPM_ONELEVEL);
  554. return 0;
  555. }
  556. LRESULT CMorePrograms::_OnSettingChange(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
  557. {
  558. // _InitMetrics() is so cheap it's not worth getting too upset about
  559. // calling it too many times.
  560. _InitMetrics();
  561. SHPropagateMessage(hwnd, uMsg, wParam, lParam, SPM_SEND | SPM_ONELEVEL);
  562. return 0;
  563. }
  564. LRESULT CMorePrograms::_OnContextMenu(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
  565. {
  566. if(SHRestricted(REST_NOSMMOREPROGRAMS))
  567. return 0;
  568. if (IS_WM_CONTEXTMENU_KEYBOARD(lParam))
  569. {
  570. RECT rc;
  571. GetWindowRect(_hwnd, &rc);
  572. lParam = MAKELPARAM(rc.left, rc.top);
  573. }
  574. c_tray.StartMenuContextMenu(_hwnd, (DWORD)lParam);
  575. return 0;
  576. }
  577. LRESULT CALLBACK CMorePrograms::s_WndProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
  578. {
  579. CMorePrograms *self = reinterpret_cast<CMorePrograms *>(GetWindowPtr(hwnd, GWLP_USERDATA));
  580. switch (uMsg)
  581. {
  582. case WM_NCCREATE:
  583. return self->_OnNCCreate(hwnd, uMsg, wParam, lParam);
  584. case WM_CREATE:
  585. return self->_OnCreate(hwnd, uMsg, wParam, lParam);
  586. case WM_DESTROY:
  587. return self->_OnDestroy(hwnd, uMsg, wParam, lParam);
  588. case WM_NCDESTROY:
  589. return self->_OnNCDestroy(hwnd, uMsg, wParam, lParam);
  590. case WM_CTLCOLORBTN:
  591. return self->_OnCtlColorBtn(hwnd, uMsg, wParam, lParam);
  592. case WM_DRAWITEM:
  593. return self->_OnDrawItem(hwnd, uMsg, wParam, lParam);
  594. case WM_ERASEBKGND:
  595. return self->_OnEraseBkgnd(hwnd, uMsg, wParam, lParam);
  596. case WM_COMMAND:
  597. return self->_OnCommand(hwnd, uMsg, wParam, lParam);
  598. case WM_SYSCOLORCHANGE:
  599. return self->_OnSysColorChange(hwnd, uMsg, wParam, lParam);
  600. case WM_DISPLAYCHANGE:
  601. return self->_OnDisplayChange(hwnd, uMsg, wParam, lParam);
  602. case WM_SETTINGCHANGE:
  603. return self->_OnSettingChange(hwnd, uMsg, wParam, lParam);
  604. case WM_NOTIFY:
  605. return self->_OnNotify(hwnd, uMsg, wParam, lParam);
  606. case WM_CONTEXTMENU:
  607. return self->_OnContextMenu(hwnd, uMsg, wParam, lParam);
  608. }
  609. return ::DefWindowProc(hwnd, uMsg, wParam, lParam);
  610. }
  611. BOOL WINAPI MorePrograms_RegisterClass()
  612. {
  613. WNDCLASSEX wc;
  614. ZeroMemory(&wc, sizeof(wc));
  615. wc.cbSize = sizeof(wc);
  616. wc.style = CS_GLOBALCLASS;
  617. wc.lpfnWndProc = CMorePrograms::s_WndProc;
  618. wc.hInstance = _Module.GetModuleInstance();
  619. wc.hCursor = LoadCursor(NULL, IDC_ARROW);
  620. wc.hbrBackground = NULL;
  621. wc.lpszClassName = WC_MOREPROGRAMS;
  622. return RegisterClassEx(&wc);
  623. }
  624. // We implement a minimal drop target so we can auto-open the More Programs
  625. // list when the user hovers over the More Programs button.
  626. // *** IUnknown ***
  627. HRESULT CMorePrograms::QueryInterface(REFIID riid, void * *ppvOut)
  628. {
  629. static const QITAB qit[] = {
  630. QITABENT(CMorePrograms, IDropTarget),
  631. QITABENT(CMorePrograms, IAccessible),
  632. QITABENT(CMorePrograms, IDispatch), // IAccessible derives from IDispatch
  633. { 0 },
  634. };
  635. return QISearch(this, qit, riid, ppvOut);
  636. }
  637. ULONG CMorePrograms::AddRef()
  638. {
  639. return InterlockedIncrement(&_lRef);
  640. }
  641. ULONG CMorePrograms::Release()
  642. {
  643. ASSERT( 0 != _lRef );
  644. ULONG cRef = InterlockedDecrement(&_lRef);
  645. if ( 0 == cRef)
  646. {
  647. delete this;
  648. }
  649. return cRef;
  650. }
  651. // *** IDropTarget::DragEnter ***
  652. HRESULT CMorePrograms::DragEnter(IDataObject *pdto, DWORD grfKeyState, POINTL ptl, DWORD *pdwEffect)
  653. {
  654. POINT pt = { ptl.x, ptl.y };
  655. if (_pdth) {
  656. _pdth->DragEnter(_hwnd, pdto, &pt, *pdwEffect);
  657. }
  658. // Remember when the hover started.
  659. _tmHoverStart = NonzeroGetTickCount();
  660. InvalidateRect(_hwndButton, NULL, TRUE); // draw with drop highlight
  661. return DragOver(grfKeyState, ptl, pdwEffect);
  662. }
  663. // *** IDropTarget::DragOver ***
  664. HRESULT CMorePrograms::DragOver(DWORD grfKeyState, POINTL ptl, DWORD *pdwEffect)
  665. {
  666. POINT pt = { ptl.x, ptl.y };
  667. if (_pdth) {
  668. _pdth->DragOver(&pt, *pdwEffect);
  669. }
  670. // Hover time is 1 second, the same as the hard-coded value for the
  671. // Start Button.
  672. if (_tmHoverStart && GetTickCount() - _tmHoverStart > 1000)
  673. {
  674. _tmHoverStart = 0;
  675. FORWARD_WM_COMMAND(_hwnd, IDC_BUTTON, _hwndButton, BN_CLICKED, PostMessage);
  676. }
  677. *pdwEffect = DROPEFFECT_NONE;
  678. return S_OK;
  679. }
  680. // *** IDropTarget::DragLeave ***
  681. HRESULT CMorePrograms::DragLeave()
  682. {
  683. if (_pdth) {
  684. _pdth->DragLeave();
  685. }
  686. _tmHoverStart = 0;
  687. InvalidateRect(_hwndButton, NULL, TRUE); // draw without drop highlight
  688. return S_OK;
  689. }
  690. // *** IDropTarget::Drop ***
  691. HRESULT CMorePrograms::Drop(IDataObject *pdto, DWORD grfKeyState, POINTL ptl, DWORD *pdwEffect)
  692. {
  693. POINT pt = { ptl.x, ptl.y };
  694. if (_pdth) {
  695. _pdth->Drop(pdto, &pt, *pdwEffect);
  696. }
  697. _tmHoverStart = 0;
  698. InvalidateRect(_hwndButton, NULL, TRUE); // draw without drop highlight
  699. return S_OK;
  700. }
  701. //****************************************************************************
  702. //
  703. // Accessibility
  704. //
  705. //
  706. // The default accessibility object reports buttons as
  707. // ROLE_SYSTEM_PUSHBUTTON, but we know that we are really a menu.
  708. //
  709. HRESULT CMorePrograms::get_accRole(VARIANT varChild, VARIANT *pvarRole)
  710. {
  711. HRESULT hr = CAccessible::get_accRole(varChild, pvarRole);
  712. if (SUCCEEDED(hr) && V_VT(pvarRole) == VT_I4)
  713. {
  714. switch (V_I4(pvarRole))
  715. {
  716. case ROLE_SYSTEM_PUSHBUTTON:
  717. V_I4(pvarRole) = ROLE_SYSTEM_MENUITEM;
  718. break;
  719. }
  720. }
  721. return hr;
  722. }
  723. HRESULT CMorePrograms::get_accState(VARIANT varChild, VARIANT *pvarState)
  724. {
  725. HRESULT hr = CAccessible::get_accState(varChild, pvarState);
  726. if (SUCCEEDED(hr) && V_VT(pvarState) == VT_I4)
  727. {
  728. V_I4(pvarState) |= STATE_SYSTEM_HASPOPUP;
  729. }
  730. return hr;
  731. }
  732. HRESULT CMorePrograms::get_accKeyboardShortcut(VARIANT varChild, BSTR *pszKeyboardShortcut)
  733. {
  734. return CreateAcceleratorBSTR(_chMnem, pszKeyboardShortcut);
  735. }
  736. HRESULT CMorePrograms::get_accDefaultAction(VARIANT varChild, BSTR *pszDefAction)
  737. {
  738. DWORD dwRole = _fMenuOpen ? ACCSTR_CLOSE : ACCSTR_OPEN;
  739. return GetRoleString(dwRole, pszDefAction);
  740. }
  741. HRESULT CMorePrograms::accDoDefaultAction(VARIANT varChild)
  742. {
  743. if (_fMenuOpen)
  744. {
  745. _SendNotify(_hwnd, SMN_CANCELSHELLMENU);
  746. return S_OK;
  747. }
  748. else
  749. {
  750. return CAccessible::accDoDefaultAction(varChild);
  751. }
  752. }