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.

493 lines
15 KiB

  1. #include "stdafx.h"
  2. #include "sfthost.h"
  3. #include "userpane.h"
  4. CUserPane::CUserPane()
  5. {
  6. ASSERT(_hwnd == NULL);
  7. ASSERT(*_szUserName == 0);
  8. ASSERT(_crColor == 0);
  9. ASSERT(_hFont == NULL);
  10. ASSERT(_hbmUserPicture== NULL);
  11. //Initialize the _rcColor to an invalid color
  12. _crColor = CLR_INVALID;
  13. }
  14. CUserPane::~CUserPane()
  15. {
  16. if (_uidChangeRegister)
  17. SHChangeNotifyDeregister(_uidChangeRegister);
  18. if (_hFont)
  19. DeleteObject(_hFont);
  20. if (_hbmUserPicture)
  21. DeleteObject(_hbmUserPicture);
  22. }
  23. LRESULT CALLBACK CUserPane::s_WndProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
  24. {
  25. CUserPane *pThis = reinterpret_cast<CUserPane *>(GetWindowPtr(hwnd, GWLP_USERDATA));
  26. if (!pThis && (WM_NCDESTROY != uMsg))
  27. {
  28. pThis = new CUserPane;
  29. SetWindowLongPtr(hwnd, GWLP_USERDATA, (LONG_PTR)pThis);
  30. }
  31. if (pThis)
  32. return pThis->WndProc(hwnd, uMsg, wParam, lParam);
  33. return DefWindowProc(hwnd, uMsg, wParam, lParam);
  34. }
  35. BOOL CUserPane::_IsCursorInPicture()
  36. {
  37. if (!_hbmUserPicture)
  38. return FALSE;
  39. RECT rc;
  40. POINT p;
  41. GetCursorPos(&p);
  42. MapWindowPoints(NULL, _hwnd, &p, 1);
  43. GetClientRect(_hwnd, &rc);
  44. int iOffset = (RECTHEIGHT(rc) - _iFramedPicHeight) / 2;
  45. return ((p.x > iOffset && p.x < iOffset + _iFramedPicWidth) &&
  46. (p.y > iOffset && p.y < iOffset + _iFramedPicHeight));
  47. }
  48. void CUserPane::OnDrawItem(DRAWITEMSTRUCT *pdis)
  49. {
  50. HFONT hfPrev = SelectFont(pdis->hDC, _hFont);
  51. int cchName = lstrlen(_szUserName);
  52. int iOldMode = SetBkMode(pdis->hDC, TRANSPARENT);
  53. // display the text centered
  54. SIZE siz;
  55. RECT rc;
  56. int iOffset=0;
  57. int iOffsetX = 0;
  58. GetTextExtentPoint32(pdis->hDC, _szUserName, cchName, &siz);
  59. GetClientRect(_hwnd, &rc);
  60. iOffset = (RECTHEIGHT(rc) - siz.cy)/2;
  61. if (!_hbmUserPicture)
  62. iOffsetX = iOffset;
  63. if (iOffset < 0)
  64. iOffset = 0;
  65. // later - read more precise offsets from theme file
  66. if (_hTheme)
  67. {
  68. RECT rcUser;
  69. rcUser.left = pdis->rcItem.left+ iOffsetX;
  70. rcUser.top = pdis->rcItem.top+iOffset;
  71. rcUser.bottom = pdis->rcItem.bottom + iOffset;
  72. rcUser.right = pdis->rcItem.right + iOffsetX;
  73. // First calculate the bounding rectangle to reduce the cost of DrawShadowText
  74. DrawText(pdis->hDC, _szUserName, cchName, &rcUser, DT_SINGLELINE | DT_NOPREFIX | DT_END_ELLIPSIS | DT_CALCRECT);
  75. DrawThemeText(_hTheme, pdis->hDC, SPP_USERPANE, 0, _szUserName, cchName, DT_SINGLELINE | DT_NOPREFIX | DT_END_ELLIPSIS, 0, &rcUser);
  76. }
  77. else
  78. {
  79. ExtTextOut(pdis->hDC, pdis->rcItem.left+ iOffsetX, pdis->rcItem.top+iOffset, 0, NULL, _szUserName, cchName, NULL);
  80. }
  81. SetBkMode(pdis->hDC, iOldMode);
  82. SelectFont(pdis->hDC, hfPrev);
  83. }
  84. LRESULT CALLBACK CUserPane::WndProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
  85. {
  86. LRESULT lr = 0L;
  87. switch (uMsg)
  88. {
  89. case WM_NCCREATE:
  90. {
  91. _hwnd = hwnd;
  92. _hTheme = (PaneDataFromCreateStruct(lParam))->hTheme;
  93. //Check for policy restrictions.
  94. //If No Name policy is in place, the username will continue to be a NULL string!
  95. ASSERT(*_szUserName == 0);
  96. _UpdateUserInfo();
  97. if (_hTheme)
  98. {
  99. GetThemeColor(_hTheme, SPP_USERPANE, 0, TMT_TEXTCOLOR, &_crColor);
  100. _hFont = LoadControlFont(_hTheme, SPP_USERPANE, FALSE, 150);
  101. }
  102. else
  103. {
  104. HFONT hfTemp = (HFONT) GetStockObject(DEFAULT_GUI_FONT);
  105. LOGFONT lf = {0};
  106. GetObject(hfTemp, sizeof(lf), &lf);
  107. lf.lfItalic = TRUE;
  108. lf.lfHeight = (lf.lfHeight * 175) / 100;
  109. lf.lfWidth = 0; // get the closest based on aspect ratio
  110. lf.lfWeight = FW_BOLD;
  111. lf.lfQuality = DEFAULT_QUALITY;
  112. SHAdjustLOGFONT(&lf); // apply locale-specific adjustments
  113. _hFont = CreateFontIndirect(&lf);
  114. _crColor = GetSysColor(COLOR_CAPTIONTEXT);
  115. // no need to free hfTemp
  116. }
  117. return TRUE;
  118. }
  119. case WM_NCDESTROY:
  120. {
  121. lr = DefWindowProc(hwnd, uMsg, wParam, lParam);
  122. SetWindowLongPtr(hwnd, GWLP_USERDATA, 0);
  123. delete this;
  124. return lr;
  125. }
  126. case WM_CREATE:
  127. {
  128. // create the user name static control and set its font if specified
  129. DWORD dwStyle = WS_CHILD | WS_CLIPCHILDREN | WS_CLIPSIBLINGS | WS_VISIBLE |
  130. SS_OWNERDRAW | SS_NOTIFY;
  131. _hwndStatic = CreateWindowEx(0, TEXT("static"), NULL, dwStyle,
  132. 0, 0, 0, 0, // we'll be sized properly on WM_SIZE
  133. _hwnd, NULL, _Module.GetModuleInstance(), NULL);
  134. if (_hwndStatic)
  135. {
  136. if (_hFont)
  137. SetWindowFont(_hwndStatic, _hFont, FALSE);
  138. if (*_szUserName)
  139. SetWindowText(_hwndStatic, _szUserName);
  140. return TRUE;
  141. }
  142. return FALSE;
  143. }
  144. case WM_SIZE:
  145. {
  146. return OnSize();
  147. }
  148. case WM_PAINT:
  149. {
  150. PAINTSTRUCT ps;
  151. HDC hdc;
  152. hdc = BeginPaint(_hwnd, &ps);
  153. if (hdc)
  154. {
  155. Paint(hdc);
  156. EndPaint(_hwnd, &ps);
  157. }
  158. return lr;
  159. }
  160. case WM_ERASEBKGND:
  161. {
  162. RECT rc;
  163. GetClientRect(_hwnd, &rc);
  164. if (!_hTheme)
  165. {
  166. // DrawCaption will draw the caption in its gradient glory so we don't
  167. // have to! Since we don't want any text to be drawn (we'll draw it ourselves)
  168. // we pass the handle of a window which has blank text. And despite
  169. // the documentation, you have to pass DC_TEXT or nothing draws!
  170. UINT uFlags = DC_ACTIVE | DC_TEXT;
  171. if (SHGetCurColorRes() > 8)
  172. uFlags |= DC_GRADIENT;
  173. DrawCaption(hwnd, (HDC)wParam, &rc, uFlags);
  174. }
  175. else
  176. {
  177. DrawThemeBackground(_hTheme, (HDC)wParam, SPP_USERPANE, 0, &rc, 0);
  178. }
  179. return TRUE;
  180. }
  181. case WM_PRINTCLIENT:
  182. {
  183. // paint user picture
  184. Paint((HDC)wParam);
  185. // Then forward the message to the static child window.
  186. lParam = lParam & ~PRF_ERASEBKGND; //Strip out the erase bkgnd. We want transparency!
  187. // We need to pass this message to the children, or else, they do not paint!
  188. // This break will result in calling DefWindowProc below and that in turn passes
  189. // this message to the children of this window.
  190. break;
  191. }
  192. case WM_CTLCOLORSTATIC:
  193. SetTextColor((HDC)wParam, _crColor);
  194. return (LRESULT)(GetStockObject(HOLLOW_BRUSH));
  195. case WM_DRAWITEM:
  196. OnDrawItem((LPDRAWITEMSTRUCT)lParam);
  197. return 0;
  198. case WM_SETCURSOR:
  199. // Change the cursor to a hand when its over the user picture
  200. if (_IsCursorInPicture())
  201. {
  202. SetCursor(LoadCursor(NULL, IDC_HAND));
  203. return TRUE;
  204. }
  205. break;
  206. case WM_LBUTTONUP:
  207. // Launch the cpl to change the picture, if the user clicks on it.
  208. // note that this is not exposed to accessibility, as this is a secondary access point for changing the picture
  209. // and we don't want to clutter the start panel's keyboard navigation for a minor fluff helper like this...
  210. if (_IsCursorInPicture())
  211. {
  212. // wow this is slow, should we shellexec "mshta.exe res://nusrmgr.cpl/nusrmgr.hta" ourselves,
  213. // since this will only happen when we know we are not on a domain.
  214. SHRunControlPanel(TEXT("nusrmgr.cpl ,initialTask=ChangePicture"), _hwnd);
  215. return 0;
  216. }
  217. break;
  218. case WM_SYSCOLORCHANGE:
  219. case WM_DISPLAYCHANGE:
  220. case WM_SETTINGCHANGE:
  221. SHPropagateMessage(hwnd, uMsg, wParam, lParam, SPM_SEND | SPM_ONELEVEL);
  222. break;
  223. case WM_NOTIFY:
  224. {
  225. NMHDR *pnm = (NMHDR*)lParam;
  226. switch (pnm->code)
  227. {
  228. case SMN_APPLYREGION:
  229. return HandleApplyRegion(_hwnd, _hTheme, (SMNMAPPLYREGION *)lParam, SPP_USERPANE, 0);
  230. }
  231. }
  232. break;
  233. case UPM_CHANGENOTIFY:
  234. {
  235. LPITEMIDLIST *ppidl;
  236. LONG lEvent;
  237. LPSHChangeNotificationLock pshcnl;
  238. pshcnl = SHChangeNotification_Lock((HANDLE)wParam, (DWORD)lParam, &ppidl, &lEvent);
  239. if (pshcnl)
  240. {
  241. if (lEvent == SHCNE_EXTENDED_EVENT && ppidl[0])
  242. {
  243. SHChangeDWORDAsIDList *pdwidl = (SHChangeDWORDAsIDList *)ppidl[0];
  244. if (pdwidl->dwItem1 == SHCNEE_USERINFOCHANGED)
  245. {
  246. _UpdateUserInfo();
  247. }
  248. }
  249. SHChangeNotification_Unlock(pshcnl);
  250. }
  251. }
  252. break;
  253. }
  254. return ::DefWindowProc(hwnd, uMsg, wParam, lParam);
  255. }
  256. void CUserPane::Paint(HDC hdc)
  257. {
  258. // paint user picture if there is one
  259. if (_hbmUserPicture)
  260. {
  261. RECT rc;
  262. int iOffset;
  263. BITMAP bm;
  264. HDC hdcTmp;
  265. GetClientRect(_hwnd, &rc);
  266. iOffset = (RECTHEIGHT(rc) - _iFramedPicHeight) / 2;
  267. GetObject(_hbmUserPicture, sizeof(bm), &bm);
  268. hdcTmp = CreateCompatibleDC(hdc);
  269. if (hdcTmp)
  270. {
  271. // draw the frame behind the user picture
  272. if (_hTheme && (_iFramedPicWidth != USERPICWIDTH || _iFramedPicHeight != USERPICHEIGHT))
  273. {
  274. RECT rcFrame;
  275. rcFrame.left = iOffset;
  276. rcFrame.top = iOffset;
  277. rcFrame.right = rcFrame.left + _iFramedPicWidth;
  278. rcFrame.bottom = rcFrame.top + _iFramedPicHeight;
  279. DrawThemeBackground(_hTheme, hdc, SPP_USERPICTURE, 0, &rcFrame, 0);
  280. }
  281. // draw the user picture
  282. SelectObject(hdcTmp, _hbmUserPicture);
  283. int iStretchMode = SetStretchBltMode(hdc, COLORONCOLOR);
  284. StretchBlt(hdc, iOffset + _mrgnPictureFrame.cxLeftWidth + (USERPICWIDTH - _iUnframedPicWidth)/2, iOffset + _mrgnPictureFrame.cyTopHeight + (USERPICHEIGHT - _iUnframedPicHeight)/2, _iUnframedPicWidth, _iUnframedPicHeight,
  285. hdcTmp, 0, 0, bm.bmWidth, bm.bmHeight, SRCCOPY);
  286. SetStretchBltMode(hdc, iStretchMode);
  287. DeleteDC(hdcTmp);
  288. }
  289. }
  290. }
  291. LRESULT CUserPane::OnSize()
  292. {
  293. RECT rc;
  294. GetClientRect(_hwnd, &rc);
  295. if (_hbmUserPicture)
  296. {
  297. // if we've got a picture, start the text 2 edges over from the right edge of the user picture
  298. // note - temp code - we'll read margins from the theme file shortly
  299. int iPicOffset = (RECTHEIGHT(rc) - _iFramedPicHeight) / 2;
  300. if (iPicOffset < 0)
  301. iPicOffset = 0;
  302. rc.left += iPicOffset + _iFramedPicWidth + GetSystemMetrics(SM_CYEDGE) * 2;
  303. }
  304. if (_hwndStatic)
  305. MoveWindow(_hwndStatic, rc.left, rc.top, RECTWIDTH(rc), RECTHEIGHT(rc), FALSE);
  306. return 0;
  307. }
  308. HRESULT CUserPane::_UpdateUserInfo()
  309. {
  310. HRESULT hr = S_OK;
  311. if(!SHRestricted(REST_NOUSERNAMEINSTARTPANEL))
  312. {
  313. //No restrictions!
  314. //Try to get the fiendly name or if it fails get the login name.
  315. ULONG uLen = ARRAYSIZE(_szUserName);
  316. SHGetUserDisplayName(_szUserName, &uLen); // Ignore failure. The string will be empty by default
  317. }
  318. // see if we should load the picture
  319. BOOL bShowPicture = FALSE;
  320. if (_hTheme)
  321. GetThemeBool(_hTheme, SPP_USERPANE, 0, TMT_USERPICTURE, &bShowPicture);
  322. // add FriendlyLogonUI check here, since SHGetUserPicturePath
  323. if (bShowPicture && IsOS(OS_FRIENDLYLOGONUI))
  324. {
  325. TCHAR szUserPicturePath[MAX_PATH];
  326. szUserPicturePath[0] = _T('0');
  327. SHGetUserPicturePath(NULL, SHGUPP_FLAG_CREATE, szUserPicturePath);
  328. if (szUserPicturePath[0])
  329. {
  330. if (_hbmUserPicture)
  331. {
  332. DeleteObject(_hbmUserPicture);
  333. _hbmUserPicture = NULL;
  334. }
  335. _hbmUserPicture = (HBITMAP)LoadImage(NULL, szUserPicturePath, IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE | LR_CREATEDIBSECTION);
  336. if (_hbmUserPicture)
  337. {
  338. BITMAP bm;
  339. GetObject(_hbmUserPicture, sizeof(bm), &bm);
  340. // Preferred dimensions
  341. _iUnframedPicHeight = USERPICHEIGHT;
  342. _iUnframedPicWidth = USERPICWIDTH;
  343. // If it's not square, scale the smaller dimension
  344. // to maintain the aspect ratio.
  345. if (bm.bmWidth > bm.bmHeight)
  346. {
  347. _iUnframedPicHeight = MulDiv(_iUnframedPicWidth, bm.bmHeight, bm.bmWidth);
  348. }
  349. else if (bm.bmHeight > bm.bmWidth)
  350. {
  351. _iUnframedPicWidth = MulDiv(_iUnframedPicHeight, bm.bmWidth, bm.bmHeight);
  352. }
  353. _iFramedPicHeight = USERPICHEIGHT;
  354. _iFramedPicWidth = USERPICWIDTH;
  355. if (_hTheme)
  356. {
  357. if (SUCCEEDED(GetThemeMargins(_hTheme, NULL, SPP_USERPICTURE, 0, TMT_CONTENTMARGINS, NULL,
  358. &_mrgnPictureFrame)))
  359. {
  360. _iFramedPicHeight += _mrgnPictureFrame.cyTopHeight + _mrgnPictureFrame.cyBottomHeight;
  361. _iFramedPicWidth += _mrgnPictureFrame.cxLeftWidth + _mrgnPictureFrame.cxRightWidth;
  362. }
  363. else
  364. {
  365. // Sometimes GetThemeMargins gets confused and returns failure
  366. // *and* puts garbage data in _mrgnPictureFrame.
  367. ZeroMemory(&_mrgnPictureFrame, sizeof(_mrgnPictureFrame));
  368. }
  369. }
  370. }
  371. }
  372. if (!_uidChangeRegister)
  373. {
  374. SHChangeNotifyEntry fsne;
  375. fsne.fRecursive = FALSE;
  376. fsne.pidl = NULL;
  377. _uidChangeRegister = SHChangeNotifyRegister(_hwnd, SHCNRF_NewDelivery | SHCNRF_ShellLevel, SHCNE_EXTENDED_EVENT,
  378. UPM_CHANGENOTIFY, 1, &fsne);
  379. }
  380. }
  381. OnSize();
  382. NMHDR nm;
  383. nm.hwndFrom = _hwnd;
  384. nm.idFrom = 0;
  385. nm.code = SMN_NEEDREPAINT;
  386. SendMessage(GetParent(_hwnd), WM_NOTIFY, nm.idFrom, (LPARAM)&nm);
  387. return hr;
  388. }
  389. BOOL WINAPI UserPane_RegisterClass()
  390. {
  391. WNDCLASSEX wc;
  392. ZeroMemory(&wc, sizeof(wc));
  393. wc.cbSize = sizeof(wc);
  394. wc.style = CS_GLOBALCLASS;
  395. wc.lpfnWndProc = CUserPane::s_WndProc;
  396. wc.hInstance = _Module.GetModuleInstance();
  397. wc.hCursor = LoadCursor(NULL, IDC_ARROW);
  398. wc.hbrBackground = (HBRUSH)(NULL);
  399. wc.lpszClassName = WC_USERPANE;
  400. return RegisterClassEx(&wc);
  401. }