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.

6478 lines
226 KiB

  1. //-------------------------------------------------------------------------//
  2. // NCTheme.cpp
  3. //-------------------------------------------------------------------------//
  4. // bug: resizable dialog (themesel) doesn't repaint client when needed
  5. // (for test case, resize "themesel" using "bussolid" theme.
  6. //-------------------------------------------------------------------------//
  7. #include "stdafx.h"
  8. #include "nctheme.h"
  9. #include "sethook.h"
  10. #include "info.h"
  11. #include "rgn.h" // AddToCompositeRgn()
  12. #include "scroll.h" // DrawSizeBox, DrawScrollBar, HandleScrollCmd
  13. #include "resource.h"
  14. #include "tmreg.h"
  15. #include "wrapper.h"
  16. #include "appinfo.h"
  17. //-------------------------------------------------------------------------//
  18. /// local macros, consts, vars
  19. //-------------------------------------------------------------------------//
  20. const RECT rcNil = {-1,-1,-1,-1};
  21. const WINDOWPARTS BOGUS_WINDOWPART = (WINDOWPARTS)0;
  22. #define VALID_WINDOWPART(part) ((part)!=BOGUS_WINDOWPART)
  23. #define WS_MINMAX (WS_MINIMIZEBOX | WS_MAXIMIZEBOX)
  24. #define HAS_CAPTIONBAR( dwStyle ) (WS_CAPTION == ((dwStyle) & WS_CAPTION))
  25. #define DLGWNDCLASSNAME TEXT("#32770")
  26. #define DLGWNDCLASSNAMEW L"#32770"
  27. #define NUMBTNSTATES 4 /*number of defined states*/
  28. #define MAKE_BTNSTATE(framestate, state) ((((framestate)-1) * NUMBTNSTATES) + (state))
  29. #define MDIBTNINDEX(ncrc) ((ncrc)-NCMDIBTNFIRST)
  30. #ifdef MAKEPOINT
  31. #undef MAKEPOINT
  32. #endif MAKEPOINT
  33. #define MAKEPOINT(pt,lParam) POINTSTOPOINT(pt, MAKEPOINTS(lParam))
  34. #define IsHTFrameButton(htCode) \
  35. (((htCode) == HTMINBUTTON) || \
  36. ((htCode) == HTMAXBUTTON) || \
  37. ((htCode) == HTCLOSE) || \
  38. ((htCode) == HTHELP))
  39. #define IsTopLevelWindow(hwnd) (IsWindow(hwnd) && NULL==GetParent(hwnd))
  40. #define IsHTScrollBar(htCode) (((htCode) == HTVSCROLL) || ((htCode) == HTHSCROLL))
  41. #define SIG_CTHEMEWND_HEAD "themewnd"
  42. #define SIG_CTHEMEWND_TAIL "end"
  43. //-------------------------------------------------------------------------//
  44. HWND _hwndFirstTop = NULL; // first themed window in process
  45. TCHAR _szWindowMetrics[128] = {0}; // WM_SETTINGCHANGE string param.
  46. //-------------------------------------------------------------------------//
  47. // debug painting switch.
  48. #define DEBUG_NCPAINT
  49. //-------------------------------------------------------------------------//
  50. // internal helper forwards
  51. //-------------------------------------------------------------------------//
  52. HDC _GetNonclientDC( IN HWND hwnd, IN OPTIONAL HRGN hrgnUpdate );
  53. void _ScreenToParent( HWND, LPRECT prcWnd );
  54. BOOL _GetWindowMonitorRect( HWND hwnd, LPRECT prcMonitor );
  55. BOOL _GetMaximizedContainer( IN HWND hwnd, OUT LPRECT prcContainer );
  56. BOOL _IsFullMaximized( IN OPTIONAL HWND hwnd, IN LPCRECT prcWnd );
  57. BOOL _IsMessageWindow( HWND );
  58. void _MDIUpdate( HWND hwndMDIChildOrClient, UINT uSwpFlags );
  59. BOOL _MDIClientUpdateChildren( HWND hwndMDIClient );
  60. void _MDIChildUpdateParent( HWND hwndMDIChild, BOOL fSetMenu = FALSE );
  61. HWND _MDIGetActive( HWND, OUT OPTIONAL BOOL* pfMaximized = NULL );
  62. HWND _MDIGetParent( HWND hwnd, OUT OPTIONAL CThemeWnd** ppMdiFrame = NULL, OUT OPTIONAL HWND *phwndMDIClient = NULL );
  63. int _GetRawClassicCaptionHeight( DWORD dwStyle, DWORD dwExStyle );
  64. int _GetSumClassicCaptionHeight( DWORD dwStyle, DWORD dwExStyle );
  65. void _ComputeNcWindowStatus( IN HWND, IN DWORD dwStatus, IN OUT NCWNDMET* pncwm );
  66. BOOL _MNCanClose(HWND);
  67. int _GetWindowBorders(LONG lStyle, DWORD dwExStyle );
  68. BOOL _GetWindowMetrics( HWND, IN OPTIONAL HWND hwndMDIActive, OUT NCWNDMET* pncwm );
  69. BOOL _IsNcPartTransparent( WINDOWPARTS part, const NCTHEMEMET& nctm );
  70. BOOL _GetNcFrameMetrics( HWND, HTHEME hTheme, const NCTHEMEMET&, IN OUT NCWNDMET& );
  71. BOOL _GetNcCaptionMargins( HTHEME hTheme, IN const NCTHEMEMET& nctm, IN OUT NCWNDMET& ncwm );
  72. LPWSTR _AllocWindowText( IN HWND hwnd );
  73. BOOL _GetNcCaptionTextSize( IN HTHEME hTheme, IN HWND hwnd, IN HFONT hf, OUT SIZE* psizeCaption );
  74. BOOL _GetNcCaptionTextRect( IN OUT NCWNDMET* pncwm );
  75. COLORREF _GetNcCaptionTextColor( FRAMESTATES iStateId );
  76. void _GetNcBtnHitTestRect( IN const NCWNDMET* pncwm, IN UINT uHitcode, BOOL fWindowRelative, OUT LPRECT prcHit );
  77. void _GetBrushesForPart(HTHEME hTheme, int iPart, HBITMAP* phbm, HBRUSH* phbr);
  78. BOOL _ShouldAssignFrameRgn( IN const NCWNDMET* pncwm, IN const NCTHEMEMET& nctm );
  79. BOOL _IsNcPartTransparent( WINDOWPARTS part, const NCTHEMEMET& nctm );
  80. BOOL _ComputeNcPartTransparency( HTHEME, IN OUT NCTHEMEMET* pnctm );
  81. HRESULT _LoadNcThemeMetrics( HWND, IN OUT OPTIONAL NCTHEMEMET* pnctm );
  82. HRESULT _LoadNcThemeSysMetrics( HWND hwnd, IN OUT OPTIONAL NCTHEMEMET* pnctm );
  83. void _NcSetPreviewMetrics( BOOL fPreview );
  84. BOOL _NcUsingPreviewMetrics();
  85. BOOL _GetNcBtnMetrics( IN OUT NCWNDMET*, IN const NCTHEMEMET*, IN HICON, IN OPTIONAL BOOL );
  86. //-------------------------------------------------------------------------//
  87. // Debug painting.
  88. #if defined(DEBUG)
  89. ULONG _NcTraceFlags = 0;
  90. # if defined(DEBUG_NCPAINT)
  91. # define BEGIN_DEBUG_NCPAINT() int cgbl = 0; if(TESTFLAG(_NcTraceFlags, NCTF_NCPAINT)) {GdiSetBatchLimit(1);}
  92. # define END_DEBUG_NCPAINT() if(TESTFLAG(_NcTraceFlags, NCTF_NCPAINT)) {GdiSetBatchLimit(cgbl);}
  93. HRESULT _DebugDrawThemeBackground(HTHEME, HDC, int, int, const RECT*, OPTIONAL const RECT*);
  94. HRESULT _DebugDrawThemeBackgroundEx(HTHEME, HDC, int, int, const RECT *prc, OPTIONAL const DTBGOPTS*);
  95. void NcDebugClipRgn( HDC hdc, COLORREF rgbPaint );
  96. # define NcDrawThemeBackground _DebugDrawThemeBackground
  97. # define NcDrawThemeBackgroundEx _DebugDrawThemeBackgroundEx
  98. # else //defined(DEBUG_NCPAINT)
  99. # define BEGIN_DEBUG_NCPAINT()
  100. # define END_DEBUG_NCPAINT()
  101. # define NcDrawThemeBackground DrawThemeBackground
  102. # define NcDrawThemeBackgroundEx DrawThemeBackgroundEx
  103. # define NcDebugClipRgn(hdc,rgbPaint)
  104. # endif //defined(DEBUG_NCPAINT)
  105. #else
  106. # define BEGIN_DEBUG_NCPAINT()
  107. # define END_DEBUG_NCPAINT()
  108. # define NcDrawThemeBackground DrawThemeBackground
  109. # define NcDrawThemeBackgroundEx DrawThemeBackgroundEx
  110. # define NcDebugClipRgn(hdc,rgbPaint)
  111. #endif //defined(DEBUG)
  112. #define RGBDEBUGBKGND RGB(0xFF,0x00,0xFF) // debug background indicator fill color
  113. //-------------------------------------------------------------------------//
  114. // process-global metrics
  115. static NCTHEMEMET _nctmCurrent = {0};
  116. CRITICAL_SECTION _csNcSysMet = {0}; // protects access to _incmCurrent
  117. CRITICAL_SECTION _csThemeMet = {0}; // protects access to _nctmCurrent
  118. //-------------------------------------------------------------------------//
  119. // process NONCLIENTMETRICS cache.
  120. struct CInternalNonclientMetrics
  121. //-------------------------------------------------------------------------//
  122. {
  123. const NONCLIENTMETRICS& GetNcm()
  124. {
  125. Acquire(FALSE);
  126. return _ncm;
  127. }
  128. HFONT GetFont( BOOL fSmallCaption )
  129. {
  130. if( _fSet)
  131. {
  132. return fSmallCaption ? _hfSmCaption : _hfCaption;
  133. }
  134. return NULL;
  135. }
  136. void operator =( const NONCLIENTMETRICS& ncmSrc )
  137. {
  138. _ncm = ncmSrc;
  139. SAFE_DELETE_GDIOBJ(_hfCaption);
  140. _hfCaption = CreateFontIndirect( &_ncm.lfCaptionFont );
  141. SAFE_DELETE_GDIOBJ(_hfSmCaption);
  142. _hfSmCaption = CreateFontIndirect( &_ncm.lfSmCaptionFont );
  143. _fSet = TRUE;
  144. }
  145. BOOL Acquire( BOOL fRefresh )
  146. {
  147. //---- quick check for outdated metrics ----
  148. if (!_fPreview)
  149. {
  150. int iNewHeight = GetSystemMetrics(SM_CYSIZE);
  151. if (iNewHeight != _iCaptionButtonHeight) // out of date
  152. {
  153. fRefresh = TRUE; // force the issue
  154. _iCaptionButtonHeight = iNewHeight;
  155. }
  156. }
  157. // normal metrics
  158. if( !_fSet || fRefresh )
  159. {
  160. // save logfont checksum
  161. LOGFONT lfCaption = _ncm.lfCaptionFont;
  162. LOGFONT lfSmCaption = _ncm.lfSmCaptionFont;
  163. Log(LOG_TMLOAD, L"Acquire: calling ClassicSystemParmetersInfo");
  164. _ncm.cbSize = sizeof(_ncm);
  165. _fSet = ClassicSystemParametersInfo( SPI_GETNONCLIENTMETRICS, 0, &_ncm, FALSE );
  166. if( _fSet )
  167. {
  168. // if old, new logfont checksums don't match, recycle our fonts
  169. if( CompareLogfont( &lfCaption, &_ncm.lfCaptionFont) )
  170. {
  171. SAFE_DELETE_GDIOBJ(_hfCaption);
  172. _hfCaption = CreateFontIndirect(&_ncm.lfCaptionFont);
  173. }
  174. if( CompareLogfont( &lfSmCaption, &_ncm.lfSmCaptionFont) )
  175. {
  176. SAFE_DELETE_GDIOBJ(_hfSmCaption);
  177. _hfSmCaption = CreateFontIndirect(&_ncm.lfSmCaptionFont);
  178. }
  179. }
  180. }
  181. return _fSet;
  182. }
  183. void Clear()
  184. {
  185. SAFE_DELETE_GDIOBJ(_hfCaption);
  186. SAFE_DELETE_GDIOBJ(_hfSmCaption);
  187. ZeroMemory( &_ncm, sizeof(_ncm) );
  188. _fSet = FALSE;
  189. }
  190. static int CompareLogfont( const LOGFONT* plf1, const LOGFONT* plf2 )
  191. {
  192. int n = memcmp( plf1, plf2, sizeof(LOGFONT) - sizeof(plf1->lfFaceName) );
  193. if( !n )
  194. {
  195. n = lstrcmp( plf1->lfFaceName, plf2->lfFaceName );
  196. }
  197. return n;
  198. }
  199. NONCLIENTMETRICS _ncm;
  200. int _iCaptionButtonHeight;
  201. BOOL _fSet;
  202. HFONT _hfCaption;
  203. HFONT _hfSmCaption;
  204. BOOL _fPreview;
  205. } _incmCurrent = {0}, _incmPreview = {0};
  206. //-------------------------------------------------------------------------//
  207. // MDI sys button group abstraction
  208. class CMdiBtns
  209. //-------------------------------------------------------------------------//
  210. {
  211. public:
  212. CMdiBtns();
  213. ~CMdiBtns() { Unload(); }
  214. BOOL Load( IN HTHEME hTheme, IN OPTIONAL HDC hdc = NULL, IN OPTIONAL UINT uSysCmd = 0 );
  215. BOOL ThemeItem( HMENU hMenu, int iPos, MENUITEMINFO* pmii, BOOL fTheme );
  216. void Unload( IN OPTIONAL UINT uSysCmd = 0 );
  217. BOOL Measure( IN HTHEME hTheme, IN OUT MEASUREITEMSTRUCT* pmis );
  218. BOOL Draw( IN HTHEME hTheme, IN DRAWITEMSTRUCT* pdis );
  219. private:
  220. #define MDIBTNCOUNT 3 // 1=min, 2=restore, 3=close
  221. //------------------------------------//
  222. // MDI sys button descriptor element
  223. struct MDIBTN
  224. {
  225. UINT wID;
  226. WINDOWPARTS iPartId;
  227. SIZINGTYPE sizingType;
  228. SIZE size;
  229. UINT fTypePrev;
  230. HBITMAP hbmPrev;
  231. HBITMAP hbmTheme;
  232. } _rgBtns[MDIBTNCOUNT];
  233. private:
  234. MDIBTN* _FindBtn( IN UINT wID );
  235. static CLOSEBUTTONSTATES _CalcState( IN ULONG ulodAction, IN ULONG ulodState );
  236. };
  237. //-------------------------------------------------------------------------//
  238. //-------------------------------------------------------------------------//
  239. // utility impl
  240. //-------------------------------------------------------------------------//
  241. //-------------------------------------------------------------------------//
  242. void _ScreenToParent( HWND hwnd, LPRECT prcWnd )
  243. {
  244. //if we have a parent, we need to convert to those coords
  245. HWND hwndParent = GetAncestor(hwnd, GA_PARENT);
  246. POINT* pp = (POINT*)prcWnd;
  247. //---- use MapWindowPoints() to account for mirrored windows ----
  248. MapWindowPoints(HWND_DESKTOP, hwndParent, pp, 2);
  249. }
  250. //-------------------------------------------------------------------------//
  251. inline BOOL _StrictPtInRect( LPCRECT prc, const POINT& pt )
  252. {
  253. // Win32 PtInRect will test positive for an empty rectangle...
  254. return !IsRectEmpty(prc) &&
  255. PtInRect( prc, pt );
  256. }
  257. //-------------------------------------------------------------------------//
  258. inline BOOL _RectInRect( LPCRECT prcTest, LPCRECT prc )
  259. {
  260. if ( prc->left < prcTest->left &&
  261. prc->right > prcTest->right &&
  262. prc->top < prcTest->top &&
  263. prc->bottom > prcTest->bottom )
  264. {
  265. return TRUE;
  266. }
  267. else
  268. {
  269. return FALSE;
  270. }
  271. }
  272. //-------------------------------------------------------------------------//
  273. inline HDC _GetNonclientDC( IN HWND hwnd, IN OPTIONAL HRGN hrgnUpdate )
  274. {
  275. // private GetDCEx #defines from user
  276. #define DCX_USESTYLE 0x00010000L
  277. #define DCX_NODELETERGN 0x00040000L
  278. DWORD dwDCX = DCX_USESTYLE|DCX_WINDOW|DCX_LOCKWINDOWUPDATE;
  279. if( hrgnUpdate != NULL )
  280. dwDCX |= (DCX_INTERSECTRGN|DCX_NODELETERGN);
  281. return GetDCEx( hwnd, hrgnUpdate, dwDCX );
  282. }
  283. //-------------------------------------------------------------------------//
  284. HWND _MDIGetActive( HWND hwndMDIClient, OUT OPTIONAL BOOL* pfMaximized )
  285. {
  286. BOOL fMaximized = FALSE;
  287. HWND hwndActive = NULL;
  288. if( IsWindow( hwndMDIClient ) )
  289. hwndActive = (HWND)SendMessage( hwndMDIClient, WM_MDIGETACTIVE, 0, (LPARAM)&fMaximized );
  290. if( pfMaximized ) *pfMaximized = fMaximized;
  291. return hwndActive;
  292. }
  293. //-------------------------------------------------------------------------////
  294. // computes rectangle of window's default monitor
  295. BOOL _GetWindowMonitorRect( HWND hwnd, LPRECT prcMonitor )
  296. {
  297. if( IsWindow(hwnd) )
  298. {
  299. // default to primary monitor
  300. SetRect( prcMonitor, 0, 0,
  301. NcGetSystemMetrics(SM_CXSCREEN),
  302. NcGetSystemMetrics(SM_CYSCREEN));
  303. // try determining window's real monitor
  304. HMONITOR hMon = MonitorFromWindow( hwnd, MONITOR_DEFAULTTONULL );
  305. if( hMon )
  306. {
  307. MONITORINFO mi;
  308. mi.cbSize = sizeof(mi);
  309. if( GetMonitorInfo( hMon, &mi ) )
  310. {
  311. *prcMonitor = mi.rcWork;
  312. }
  313. }
  314. return TRUE;
  315. }
  316. return FALSE;
  317. }
  318. //-------------------------------------------------------------------------////
  319. // determines whether the indicate window is as large or larger than
  320. // the target monitor
  321. BOOL _GetMaximizedContainer(
  322. IN HWND hwnd,
  323. OUT LPRECT prcContainer )
  324. {
  325. ASSERT(IsWindow(hwnd));
  326. HWND hwndParent = GetParent(hwnd);
  327. if( hwndParent )
  328. {
  329. return GetWindowRect( hwndParent, prcContainer );
  330. }
  331. // top-level window: container is primary monitor
  332. return _GetWindowMonitorRect( hwnd, prcContainer );
  333. }
  334. //-------------------------------------------------------------------------////
  335. // determines whether the indicate window is as large or larger than
  336. // the target monitor
  337. BOOL _IsFullMaximized( IN OPTIONAL HWND hwnd, IN LPCRECT prcWnd )
  338. {
  339. if( !IsWindow(hwnd) )
  340. return TRUE; // assume full-screen maximized window
  341. if( IsZoomed(hwnd) )
  342. {
  343. RECT rcContainer = {0};
  344. if( !_GetMaximizedContainer( hwnd, &rcContainer ) )
  345. return TRUE;
  346. // determine whether the rect is contained in the screen rect
  347. return _RectInRect( &rcContainer, prcWnd );
  348. }
  349. return FALSE;
  350. }
  351. //-------------------------------------------------------------------------//
  352. //
  353. // _GetRawClassicCaptionHeight() -
  354. //
  355. // Using system metrics, computes the total height of the caption bar
  356. // including edge and borders
  357. //
  358. inline int _GetRawClassicCaptionHeight( DWORD dwStyle, DWORD dwExStyle )
  359. {
  360. ASSERT(HAS_CAPTIONBAR(dwStyle)); // shouldn't be here without WS_CAPTION
  361. return NcGetSystemMetrics(
  362. TESTFLAG(dwExStyle, WS_EX_TOOLWINDOW ) ? SM_CYSMCAPTION : SM_CYCAPTION );
  363. }
  364. //-------------------------------------------------------------------------//
  365. //
  366. // _GetSumClassicCaptionHeight() -
  367. //
  368. // Using system metrics, computes the total height of the caption bar
  369. // including edge and borders
  370. //
  371. inline int _GetSumClassicCaptionHeight( DWORD dwStyle, DWORD dwExStyle )
  372. {
  373. ASSERT(HAS_CAPTIONBAR(dwStyle)); // shouldn't be here without WS_CAPTION
  374. // Factor in window border width.
  375. return _GetWindowBorders( dwStyle, dwExStyle) +
  376. _GetRawClassicCaptionHeight( dwStyle, dwExStyle );
  377. }
  378. //-------------------------------------------------------------------------//
  379. //
  380. // GetWindowBorders() - port from win32k, rtl\winmgr.c
  381. //
  382. // Computes window border dimensions based on style bits.
  383. //
  384. int _GetWindowBorders(LONG lStyle, DWORD dwExStyle )
  385. {
  386. int cBorders = 0;
  387. //
  388. // Is there a 3D border around the window?
  389. //
  390. if( TESTFLAG(dwExStyle, WS_EX_WINDOWEDGE) )
  391. cBorders += 2;
  392. else if ( TESTFLAG(dwExStyle, WS_EX_STATICEDGE) )
  393. ++cBorders;
  394. //
  395. // Is there a single flat border around the window? This is true for
  396. // WS_BORDER, WS_DLGFRAME, and WS_EX_DLGMODALFRAME windows.
  397. //
  398. if( TESTFLAG(lStyle, WS_CAPTION) || TESTFLAG(dwExStyle, WS_EX_DLGMODALFRAME) )
  399. ++cBorders;
  400. //
  401. // Is there a sizing flat border around the window?
  402. //
  403. if( TESTFLAG(lStyle, WS_THICKFRAME) && !TESTFLAG(lStyle, WS_MINIMIZE) )
  404. {
  405. NONCLIENTMETRICS ncm;
  406. cBorders += (NcGetNonclientMetrics( &ncm, FALSE ) ?
  407. ncm.iBorderWidth : NcGetSystemMetrics( SM_CXBORDER ));
  408. }
  409. return(cBorders);
  410. }
  411. //-------------------------------------------------------------------------//
  412. // _MNCanClose
  413. //
  414. // returns TRUE only if USER32 determines that the window can be closed
  415. // (by checking its system menu items and their disabled state)
  416. //
  417. BOOL _MNCanClose(HWND hwnd)
  418. {
  419. LogEntryNC(L"_MNCanClose");
  420. BOOL fRetVal = FALSE;
  421. TITLEBARINFO tbi = {sizeof(tbi)};
  422. //---- don't use GetSystemMenu() - has user handle leak issues ----
  423. if (GetTitleBarInfo(hwnd, &tbi))
  424. {
  425. //---- mask out the good bits ----
  426. DWORD dwVal = (tbi.rgstate[5] & (~(STATE_SYSTEM_PRESSED | STATE_SYSTEM_FOCUSABLE)));
  427. fRetVal = (dwVal == 0); // only if no bad bits are left
  428. }
  429. if ( !fRetVal && TESTFLAG(GetWindowLong(hwnd, GWL_EXSTYLE), WS_EX_MDICHILD) )
  430. {
  431. HMENU hMenu = GetSystemMenu(hwnd, FALSE);
  432. MENUITEMINFO menuInfo;
  433. menuInfo.cbSize = sizeof(MENUITEMINFO);
  434. menuInfo.fMask = MIIM_STATE;
  435. if ( GetMenuItemInfo(hMenu, SC_CLOSE, FALSE, &menuInfo) )
  436. {
  437. fRetVal = !(menuInfo.fState & MFS_GRAYED) ? TRUE : FALSE;
  438. }
  439. }
  440. LogExitNC(L"_MNCanClose");
  441. return fRetVal;
  442. }
  443. //-------------------------------------------------------------------------//
  444. void CThemeWnd::UpdateMDIFrameStuff( HWND hwndMDIClient, BOOL fSetMenu )
  445. {
  446. HWND hwndMDIActive = _MDIGetActive( hwndMDIClient, NULL );
  447. // cache MDIClient, maximized M window handle
  448. _hwndMDIClient = IsWindow(hwndMDIActive) ? hwndMDIClient : NULL;
  449. }
  450. //-------------------------------------------------------------------------//
  451. BOOL CALLBACK _FreshenThemeMetricsCB( HWND hwnd, LPARAM lParam )
  452. {
  453. CThemeWnd* pwnd = CThemeWnd::FromHwnd( hwnd );
  454. if( VALID_THEMEWND(pwnd) )
  455. {
  456. pwnd->AddRef();
  457. pwnd->GetNcWindowMetrics( NULL, NULL, NULL, NCWMF_RECOMPUTE );
  458. pwnd->Release();
  459. }
  460. return TRUE;
  461. }
  462. //-------------------------------------------------------------------------//
  463. BOOL _IsMessageWindow( HWND hwnd )
  464. {
  465. // A window parented by HWND_MESSAGE has no UI and should not be themed.
  466. static ATOM _atomMsgWnd = 0;
  467. HWND hwndParent = (HWND)GetWindowLongPtr( hwnd, GWLP_HWNDPARENT );
  468. if( hwndParent )
  469. {
  470. ATOM atomParent = (ATOM)GetClassLong( hwndParent, GCW_ATOM );
  471. // have we seen the message window wndclass before?
  472. if( _atomMsgWnd )
  473. return (atomParent == _atomMsgWnd); // compare class atoms
  474. // haven't seen a message window come through in this process,
  475. // so compare class names.
  476. WCHAR szClass[128];
  477. if( GetClassNameW( hwndParent, szClass, ARRAYSIZE(szClass) ) )
  478. {
  479. if( 0 == AsciiStrCmpI( szClass, L"Message" ) )
  480. {
  481. _atomMsgWnd = atomParent;
  482. return TRUE;
  483. }
  484. }
  485. }
  486. return FALSE;
  487. }
  488. //-------------------------------------------------------------------------//
  489. // Retrieves MDI frame and/or MDICLIENT window for an MDI child window
  490. HWND _MDIGetParent(
  491. HWND hwnd, OUT OPTIONAL CThemeWnd** ppMdiFrame, OUT OPTIONAL HWND* phwndMDIClient )
  492. {
  493. if( ppMdiFrame ) *ppMdiFrame = NULL;
  494. if( phwndMDIClient ) *phwndMDIClient = NULL;
  495. if( TESTFLAG(GetWindowLong( hwnd, GWL_EXSTYLE ), WS_EX_MDICHILD) )
  496. {
  497. HWND hwndMDIClient = GetParent(hwnd);
  498. if( IsWindow(hwndMDIClient) )
  499. {
  500. HWND hwndFrame = GetParent(hwndMDIClient);
  501. if( IsWindow(hwndFrame) )
  502. {
  503. if( phwndMDIClient ) *phwndMDIClient = hwndMDIClient;
  504. if( ppMdiFrame )
  505. *ppMdiFrame = CThemeWnd::FromHwnd(hwndFrame);
  506. return hwndFrame;
  507. }
  508. }
  509. }
  510. return NULL;
  511. }
  512. //-------------------------------------------------------------------------//
  513. HWND _FindMDIClient( HWND hwndFrame )
  514. {
  515. for( HWND hwndChild = GetWindow(hwndFrame, GW_CHILD); hwndChild != NULL;
  516. hwndChild = GetNextWindow(hwndChild, GW_HWNDNEXT))
  517. {
  518. TCHAR szClass[48];
  519. if( GetClassName(hwndChild, szClass, ARRAYSIZE(szClass)) )
  520. {
  521. if( 0 == lstrcmpi(szClass, TEXT("MDIClient")) )
  522. {
  523. return hwndChild;
  524. }
  525. }
  526. }
  527. return NULL;
  528. }
  529. //-------------------------------------------------------------------------//
  530. // Handle MDI relative updating on WM_WINDOWPOSCHANGED
  531. void _MDIUpdate( HWND hwnd, UINT uSwpFlags)
  532. {
  533. // Notify MDI frame if we became maximized, etc.
  534. BOOL bIsClient = FALSE;
  535. // Could be the MDI client, could be a MDI child
  536. if (!(TESTFLAG(uSwpFlags, SWP_NOMOVE) && TESTFLAG(uSwpFlags, SWP_NOSIZE)))
  537. {
  538. bIsClient = _MDIClientUpdateChildren( hwnd );
  539. }
  540. if (!bIsClient)
  541. {
  542. _MDIChildUpdateParent( hwnd, FALSE );
  543. }
  544. }
  545. //-------------------------------------------------------------------------//
  546. // Post-WM_WINDOWPOSCHANGED processing for MDI client or children.
  547. // We need to recompute each child when the MDI client moves.
  548. BOOL _MDIClientUpdateChildren( HWND hwndMDIChildOrClient )
  549. {
  550. // Find if it's the MDI client window
  551. HWND hWndChild = GetWindow(hwndMDIChildOrClient, GW_CHILD);
  552. if (IsWindow(hWndChild) && TESTFLAG(GetWindowLong(hWndChild, GWL_EXSTYLE), WS_EX_MDICHILD))
  553. {
  554. // Yes it's the MDI client, refresh each MDI child's metrics
  555. do
  556. {
  557. _FreshenThemeMetricsCB(hWndChild, NULL);
  558. } while (NULL != (hWndChild = GetWindow(hWndChild, GW_HWNDNEXT)));
  559. return TRUE;
  560. }
  561. return FALSE;
  562. }
  563. //-------------------------------------------------------------------------//
  564. // Informs MDI frame that a child window may
  565. void _MDIChildUpdateParent( HWND hwndMDIChild, BOOL fSetMenu )
  566. {
  567. CThemeWnd* pwndParent;
  568. HWND hwndMDIClient;
  569. if( _MDIGetParent( hwndMDIChild, &pwndParent, &hwndMDIClient ) &&
  570. VALID_THEMEWND(pwndParent) )
  571. {
  572. pwndParent->UpdateMDIFrameStuff( hwndMDIClient, fSetMenu );
  573. }
  574. }
  575. //-------------------------------------------------------------------------//
  576. // _ComputeNcWindowStatus
  577. //
  578. // Assigns and translates window status bits to/in NCWNDMET block.
  579. //
  580. void _ComputeNcWindowStatus( IN HWND hwnd, IN DWORD dwStatus, IN OUT NCWNDMET* pncwm )
  581. {
  582. BOOL fActive = TESTFLAG( dwStatus, WS_ACTIVECAPTION );
  583. if (fActive || !HAS_CAPTIONBAR(pncwm->dwStyle) )
  584. {
  585. pncwm->framestate = FS_ACTIVE;
  586. }
  587. else
  588. {
  589. pncwm->framestate = FS_INACTIVE;
  590. }
  591. if( HAS_CAPTIONBAR(pncwm->dwStyle) )
  592. {
  593. pncwm->rgbCaption = _GetNcCaptionTextColor( pncwm->framestate );
  594. }
  595. }
  596. //-------------------------------------------------------------------------////
  597. BOOL _GetWindowMetrics( HWND hwnd, IN OPTIONAL HWND hwndMDIActive, OUT NCWNDMET* pncwm )
  598. {
  599. WINDOWINFO wi;
  600. wi.cbSize = sizeof(wi);
  601. if( GetWindowInfo( hwnd, &wi ) )
  602. {
  603. pncwm->dwStyle = wi.dwStyle;
  604. pncwm->dwExStyle = wi.dwExStyle;
  605. pncwm->rcS0[NCRC_WINDOW] = wi.rcWindow;
  606. pncwm->rcS0[NCRC_CLIENT] = wi.rcClient;
  607. pncwm->fMin = IsIconic(hwnd);
  608. pncwm->fMaxed = IsZoomed(hwnd);
  609. pncwm->fFullMaxed = pncwm->fMaxed ? _IsFullMaximized(hwnd, &wi.rcWindow) : FALSE;
  610. pncwm->dwWindowStatus = wi.dwWindowStatus;
  611. // if this window is the active MDI child and is owned by the foreground window
  612. // (which may not be the case if a popup, for example, is foremost), then
  613. // fix up the status bit.
  614. if( hwnd == hwndMDIActive )
  615. {
  616. HWND hwndFore = GetForegroundWindow();
  617. if( IsChild(hwndFore, hwndMDIActive) )
  618. {
  619. pncwm->dwWindowStatus = WS_ACTIVECAPTION;
  620. }
  621. }
  622. return TRUE;
  623. }
  624. return FALSE;
  625. }
  626. //-------------------------------------------------------------------------//
  627. BOOL _ShouldAssignFrameRgn(
  628. IN const NCWNDMET* pncwm,
  629. IN const NCTHEMEMET& nctm )
  630. {
  631. if( TESTFLAG( CThemeWnd::EvaluateStyle(pncwm->dwStyle, pncwm->dwExStyle), TWCF_FRAME|TWCF_TOOLFRAME) )
  632. {
  633. // always need window region for maximized windows.
  634. if( pncwm->fFullMaxed )
  635. return TRUE;
  636. // otherwise, need region only if the background is transparent
  637. for( int i = 0; i < ARRAYSIZE( pncwm->rgframeparts ); i++ )
  638. {
  639. if( _IsNcPartTransparent( pncwm->rgframeparts[i], nctm ) )
  640. return TRUE;
  641. }
  642. }
  643. return FALSE;
  644. }
  645. //-------------------------------------------------------------------------//
  646. BOOL _IsNcPartTransparent( WINDOWPARTS part, const NCTHEMEMET& nctm )
  647. {
  648. #define GET_NCTRANSPARENCY(part,field) \
  649. case part: return nctm.nct.##field
  650. switch(part)
  651. {
  652. GET_NCTRANSPARENCY(WP_CAPTION, fCaption);
  653. GET_NCTRANSPARENCY(WP_SMALLCAPTION, fCaption);
  654. GET_NCTRANSPARENCY(WP_MINCAPTION, fMinCaption);
  655. GET_NCTRANSPARENCY(WP_SMALLMINCAPTION, fSmallMinCaption);
  656. GET_NCTRANSPARENCY(WP_MAXCAPTION, fMaxCaption);
  657. GET_NCTRANSPARENCY(WP_SMALLMAXCAPTION, fSmallMaxCaption);
  658. GET_NCTRANSPARENCY(WP_FRAMELEFT, fFrameLeft);
  659. GET_NCTRANSPARENCY(WP_FRAMERIGHT, fFrameRight);
  660. GET_NCTRANSPARENCY(WP_FRAMEBOTTOM, fFrameBottom);
  661. GET_NCTRANSPARENCY(WP_SMALLFRAMELEFT, fSmFrameLeft);
  662. GET_NCTRANSPARENCY(WP_SMALLFRAMERIGHT, fSmFrameRight);
  663. GET_NCTRANSPARENCY(WP_SMALLFRAMEBOTTOM, fSmFrameBottom);
  664. }
  665. return FALSE;
  666. }
  667. //-------------------------------------------------------------------------//
  668. BOOL _ComputeNcPartTransparency( HTHEME hTheme, IN OUT NCTHEMEMET* pnctm )
  669. {
  670. #define TEST_NCTRANSPARENCY(part) IsThemePartDefined(hTheme,part,0) ? \
  671. IsThemeBackgroundPartiallyTransparent(hTheme,part,FS_ACTIVE) : FALSE;
  672. pnctm->nct.fCaption = TEST_NCTRANSPARENCY(WP_CAPTION);
  673. pnctm->nct.fSmallCaption = TEST_NCTRANSPARENCY(WP_SMALLCAPTION);
  674. pnctm->nct.fMinCaption = TEST_NCTRANSPARENCY(WP_MINCAPTION);
  675. pnctm->nct.fSmallMinCaption = TEST_NCTRANSPARENCY(WP_SMALLMINCAPTION);
  676. pnctm->nct.fMaxCaption = TEST_NCTRANSPARENCY(WP_MAXCAPTION);
  677. pnctm->nct.fSmallMaxCaption = TEST_NCTRANSPARENCY(WP_SMALLMAXCAPTION);
  678. pnctm->nct.fFrameLeft = TEST_NCTRANSPARENCY(WP_FRAMELEFT);
  679. pnctm->nct.fFrameRight = TEST_NCTRANSPARENCY(WP_FRAMERIGHT);
  680. pnctm->nct.fFrameBottom = TEST_NCTRANSPARENCY(WP_FRAMEBOTTOM);
  681. pnctm->nct.fSmFrameLeft = TEST_NCTRANSPARENCY(WP_SMALLFRAMELEFT);
  682. pnctm->nct.fSmFrameRight = TEST_NCTRANSPARENCY(WP_SMALLFRAMERIGHT);
  683. pnctm->nct.fSmFrameBottom = TEST_NCTRANSPARENCY(WP_SMALLFRAMEBOTTOM);
  684. return TRUE;
  685. }
  686. //-------------------------------------------------------------------------//
  687. // NCTHEMEMET implementation
  688. //-------------------------------------------------------------------------//
  689. //-------------------------------------------------------------------------//
  690. BOOL GetCurrentNcThemeMetrics( OUT NCTHEMEMET* pnctm )
  691. {
  692. *pnctm = _nctmCurrent;
  693. return IsValidNcThemeMetrics( pnctm );
  694. }
  695. //-------------------------------------------------------------------------//
  696. void InitNcThemeMetrics( NCTHEMEMET* pnctm )
  697. {
  698. if( !pnctm )
  699. pnctm = &_nctmCurrent;
  700. ZeroMemory( pnctm, sizeof(*pnctm) );
  701. }
  702. //---------------------------------------------------------------------------
  703. void ClearNcThemeMetrics( NCTHEMEMET* pnctm )
  704. {
  705. if( !pnctm )
  706. pnctm = &_nctmCurrent;
  707. //---- minimize THREAD-UNSAFE access to _nctmCurrent by ----
  708. //---- NULL-ing out the hTheme type members as soon as ----
  709. //---- they are closed ----
  710. if( pnctm->hTheme )
  711. {
  712. CloseThemeData( pnctm->hTheme );
  713. pnctm->hTheme = NULL;
  714. }
  715. if( pnctm->hThemeTab )
  716. {
  717. CloseThemeData( pnctm->hThemeTab );
  718. pnctm->hThemeTab = NULL;
  719. }
  720. SAFE_DELETE_GDIOBJ( pnctm->hbmTabDialog );
  721. SAFE_DELETE_GDIOBJ( pnctm->hbrTabDialog );
  722. InitNcThemeMetrics( pnctm );
  723. }
  724. //-------------------------------------------------------------------------//
  725. // Computes process-global, per-theme metrics for the nonclient area theme.
  726. HRESULT AcquireNcThemeMetrics()
  727. {
  728. HRESULT hr = E_FAIL;
  729. if( VALID_CRITICALSECTION(&_csThemeMet) )
  730. {
  731. hr = S_OK;
  732. EnterCriticalSection( &_csThemeMet );
  733. ClearNcThemeMetrics( &_nctmCurrent );
  734. NcGetNonclientMetrics( NULL, FALSE );
  735. hr = _LoadNcThemeMetrics(NULL, &_nctmCurrent);
  736. LeaveCriticalSection( &_csThemeMet );
  737. Log(LOG_TMCHANGE, L"AcquireNcThemeMetrics: got hTheme=0x%x", _nctmCurrent.hTheme);
  738. }
  739. return hr;
  740. }
  741. //-------------------------------------------------------------------------//
  742. // Computes and/or loads per-theme (as opposed to per-window)
  743. // system metrics and resources not managed by the theme manager.
  744. //
  745. // Called by _LoadNcThemeMetrics
  746. HRESULT _LoadNcThemeSysMetrics( HWND hwnd, IN OUT NCTHEMEMET* pnctm )
  747. {
  748. HRESULT hr = E_FAIL;
  749. ASSERT(pnctm);
  750. // grab system metrics for nonclient area.
  751. NONCLIENTMETRICS ncm = {0};
  752. ncm.cbSize = sizeof(ncm);
  753. if( NcGetNonclientMetrics( &ncm, FALSE ) )
  754. {
  755. hr = S_OK;
  756. // Establish minimized window size
  757. if( 0 >= pnctm->sizeMinimized.cx )
  758. pnctm->sizeMinimized.cx = NcGetSystemMetrics( SM_CXMINIMIZED );
  759. if( 0 >= pnctm->sizeMinimized.cy )
  760. pnctm->sizeMinimized.cy = NcGetSystemMetrics( SM_CYMINIMIZED );
  761. }
  762. else
  763. {
  764. hr = HRESULT_FROM_WIN32(GetLastError());
  765. if( SUCCEEDED(hr) )
  766. hr = E_FAIL;
  767. }
  768. // Maximized caption height or width
  769. pnctm->cyMaxCaption = _GetRawClassicCaptionHeight( WS_CAPTION|WS_OVERLAPPED, 0 );
  770. return hr;
  771. }
  772. //-------------------------------------------------------------------------//
  773. // Computes and/or loads per-theme (as opposed to per-window)
  774. // metrics and resources not managed by the theme manager
  775. HRESULT _LoadNcThemeMetrics( HWND hwnd, NCTHEMEMET* pnctm )
  776. {
  777. HRESULT hr = E_FAIL;
  778. // Initialize incoming NCTHEMEMET:
  779. if( pnctm )
  780. {
  781. InitNcThemeMetrics( pnctm );
  782. HTHEME hTheme = ::OpenNcThemeData( hwnd, L"Window" );
  783. if( hTheme )
  784. {
  785. pnctm->hTheme = hTheme;
  786. // determine transparency for each frame part.
  787. _ComputeNcPartTransparency(hTheme, pnctm);
  788. // menubar pixels not accounted for by CalcMenuBar or PaintMenuBar
  789. pnctm->dyMenuBar = NcGetSystemMetrics(SM_CYMENU) - NcGetSystemMetrics(SM_CYMENUSIZE);
  790. // normal caption margins
  791. if( FAILED( GetThemeMargins( hTheme, NULL, WP_CAPTION, CS_ACTIVE, TMT_CAPTIONMARGINS,
  792. NULL, &pnctm->marCaptionText )) )
  793. {
  794. FillMemory( &pnctm->marCaptionText, sizeof(pnctm->marCaptionText), 0 );
  795. }
  796. // maximized caption margins
  797. if( FAILED( GetThemeMargins( hTheme, NULL, WP_MAXCAPTION, CS_ACTIVE, TMT_CAPTIONMARGINS,
  798. NULL, &pnctm->marMaxCaptionText )) )
  799. {
  800. FillMemory( &pnctm->marMaxCaptionText, sizeof(pnctm->marMaxCaptionText), 0 );
  801. }
  802. // minimized caption margins
  803. if( FAILED( GetThemeMargins( hTheme, NULL, WP_MINCAPTION, CS_ACTIVE, TMT_CAPTIONMARGINS,
  804. NULL, &pnctm->marMinCaptionText )) )
  805. {
  806. FillMemory( &pnctm->marMinCaptionText, sizeof(pnctm->marMinCaptionText), 0 );
  807. }
  808. // dynamically resizing small (toolframe) caption margins
  809. if( FAILED( GetThemeMargins( hTheme, NULL, WP_SMALLCAPTION, CS_ACTIVE, TMT_CAPTIONMARGINS,
  810. NULL, &pnctm->marSmCaptionText )) )
  811. {
  812. FillMemory( &pnctm->marSmCaptionText, sizeof(pnctm->marSmCaptionText), 0 );
  813. }
  814. // caption and frame resizing border hittest template parts
  815. pnctm->fCapSizingTemplate = IsThemePartDefined( hTheme, WP_CAPTIONSIZINGTEMPLATE, 0);
  816. pnctm->fLeftSizingTemplate = IsThemePartDefined( hTheme, WP_FRAMELEFTSIZINGTEMPLATE, 0);
  817. pnctm->fRightSizingTemplate = IsThemePartDefined( hTheme, WP_FRAMERIGHTSIZINGTEMPLATE, 0);
  818. pnctm->fBottomSizingTemplate = IsThemePartDefined( hTheme, WP_FRAMEBOTTOMSIZINGTEMPLATE, 0);
  819. // toolwindow caption and frame resizing border hittest template parts
  820. pnctm->fSmCapSizingTemplate = IsThemePartDefined( hTheme, WP_SMALLCAPTIONSIZINGTEMPLATE, 0);
  821. pnctm->fSmLeftSizingTemplate = IsThemePartDefined( hTheme, WP_SMALLFRAMELEFTSIZINGTEMPLATE, 0);
  822. pnctm->fSmRightSizingTemplate = IsThemePartDefined( hTheme, WP_SMALLFRAMERIGHTSIZINGTEMPLATE, 0);
  823. pnctm->fSmBottomSizingTemplate = IsThemePartDefined( hTheme, WP_SMALLFRAMEBOTTOMSIZINGTEMPLATE, 0);
  824. // Minimized window size.
  825. // If this is a truesize image, honor its dimensions; otherwise use
  826. // width, height properties. Fall back on system metrics.
  827. SIZINGTYPE st = ST_TRUESIZE;
  828. hr = GetThemeInt( hTheme, WP_MINCAPTION, FS_ACTIVE, TMT_SIZINGTYPE, (int*)&st );
  829. if( ST_TRUESIZE == st )
  830. {
  831. hr = GetThemePartSize( hTheme, NULL, WP_MINCAPTION, FS_ACTIVE, NULL,
  832. TS_TRUE, &pnctm->sizeMinimized );
  833. if( FAILED(hr) )
  834. {
  835. GetThemeMetric( hTheme, NULL, WP_MINCAPTION, FS_ACTIVE, TMT_WIDTH,
  836. (int*)&pnctm->sizeMinimized.cx );
  837. GetThemeMetric( hTheme, NULL, WP_MINCAPTION, FS_ACTIVE, TMT_HEIGHT,
  838. (int*)&pnctm->sizeMinimized.cy );
  839. }
  840. }
  841. // -- normal nonclient button size.
  842. int cy = NcGetSystemMetrics( SM_CYSIZE );
  843. hr = GetThemePartSize( pnctm->hTheme, NULL, WP_CLOSEBUTTON, 0, NULL, TS_TRUE, &pnctm->sizeBtn );
  844. if( SUCCEEDED(hr) )
  845. {
  846. pnctm->theme_sysmets.cxBtn = MulDiv( cy, pnctm->sizeBtn.cx, pnctm->sizeBtn.cy );
  847. }
  848. else
  849. {
  850. pnctm->theme_sysmets.cxBtn =
  851. pnctm->sizeBtn.cx = NcGetSystemMetrics( SM_CXSIZE );
  852. pnctm->sizeBtn.cy = cy;
  853. }
  854. // -- toolframe nonclient button size.
  855. cy = NcGetSystemMetrics( SM_CYSMSIZE );
  856. hr = GetThemePartSize( pnctm->hTheme, NULL, WP_SMALLCLOSEBUTTON, 0, NULL, TS_TRUE, &pnctm->sizeSmBtn );
  857. if( SUCCEEDED(hr) )
  858. {
  859. pnctm->theme_sysmets.cxSmBtn = MulDiv( cy, pnctm->sizeSmBtn.cx, pnctm->sizeSmBtn.cy );
  860. }
  861. else
  862. {
  863. pnctm->theme_sysmets.cxSmBtn =
  864. pnctm->sizeSmBtn.cx = NcGetSystemMetrics( SM_CXSMSIZE );
  865. pnctm->sizeSmBtn.cy = cy;
  866. }
  867. // -- validate sysmet hook values
  868. pnctm->theme_sysmets.fValid = TRUE;
  869. // dialog background for dialogs parented by PROPSHEETs or
  870. // specifically stamped via EnableThemeDialogTexture to match the tab control background.
  871. //
  872. // We need to open the tab control's theme so that we can get the background of tab dialogs
  873. // We can't dynamically load this because of how this cache is set up: It's all or nothing.
  874. pnctm->hThemeTab = ::OpenThemeData(hwnd, L"Tab");
  875. _GetBrushesForPart(pnctm->hThemeTab, TABP_BODY, &pnctm->hbmTabDialog, &pnctm->hbrTabDialog);
  876. hr = _LoadNcThemeSysMetrics( hwnd, pnctm );
  877. }
  878. }
  879. return hr;
  880. }
  881. //-------------------------------------------------------------------------//
  882. BOOL IsValidNcThemeMetrics( NCTHEMEMET* pnctm )
  883. {
  884. return pnctm->hTheme != NULL;
  885. }
  886. //-------------------------------------------------------------------------//
  887. // THREADWINDOW implementation
  888. //-------------------------------------------------------------------------//
  889. //
  890. // Note: this is a fixed length array of threads-window mappings.
  891. // We'll use this to keep track of the threads processing a certain message
  892. //
  893. // Thread local storage would be better suited to the task, but we
  894. // learned early on that the unique load/unload situation of uxtheme
  895. // causes us to miss DLL_THREAD_DETACH in some scenarios, which would mean
  896. // leaking the TLS.
  897. //
  898. typedef struct _THREADWINDOW
  899. {
  900. DWORD dwThread;
  901. HWND hwnd;
  902. } THREADWINDOW;
  903. //-------------------------------------------------------------------------//
  904. // WM_NCPAINT tracking:
  905. THREADWINDOW _rgtwNcPaint[16] = {0}; // threads processing NCPAINT in this process
  906. int _cNcPaintWnd = 0; // count of threads processing NCPAINT in this process
  907. CRITICAL_SECTION _csNcPaint = {0}; // serializes access to _rgtwNcPaint
  908. //-------------------------------------------------------------------------//
  909. void NcPaintWindow_Add( HWND hwnd )
  910. {
  911. // add entry to our list of threads handling WM_NCPAINT.
  912. if( VALID_CRITICALSECTION(&_csNcPaint) )
  913. {
  914. EnterCriticalSection( &_csNcPaint );
  915. for( int i = 0; i < ARRAYSIZE(_rgtwNcPaint); i++ )
  916. {
  917. if( 0 == _rgtwNcPaint[i].dwThread )
  918. {
  919. _rgtwNcPaint[i].dwThread = GetCurrentThreadId();
  920. _rgtwNcPaint[i].hwnd = hwnd;
  921. _cNcPaintWnd++;
  922. }
  923. }
  924. LeaveCriticalSection( &_csNcPaint );
  925. }
  926. }
  927. //-------------------------------------------------------------------------//
  928. void NcPaintWindow_Remove()
  929. {
  930. // remove entry from our list of threads handling WM_NCPAINT.
  931. if( _cNcPaintWnd )
  932. {
  933. DWORD dwThread = GetCurrentThreadId();
  934. if( VALID_CRITICALSECTION(&_csNcPaint) )
  935. {
  936. EnterCriticalSection( &_csNcPaint );
  937. for( int i = 0; i < ARRAYSIZE(_rgtwNcPaint); i++ )
  938. {
  939. if( dwThread == _rgtwNcPaint[i].dwThread )
  940. {
  941. _rgtwNcPaint[i].dwThread = 0;
  942. _rgtwNcPaint[i].hwnd = 0;
  943. _cNcPaintWnd--;
  944. break;
  945. }
  946. }
  947. LeaveCriticalSection( &_csNcPaint );
  948. }
  949. }
  950. }
  951. //-------------------------------------------------------------------------//
  952. HWND NcPaintWindow_Find()
  953. {
  954. HWND hwnd = NULL;
  955. // Search entries in our list of threads handling WM_NCPAINT.
  956. if( _cNcPaintWnd )
  957. {
  958. DWORD dwThread = GetCurrentThreadId();
  959. if( VALID_CRITICALSECTION(&_csNcPaint) )
  960. {
  961. EnterCriticalSection( &_csNcPaint );
  962. for( int i = 0; i < ARRAYSIZE(_rgtwNcPaint); i++ )
  963. {
  964. if( dwThread == _rgtwNcPaint[i].dwThread )
  965. {
  966. hwnd = _rgtwNcPaint[i].hwnd;
  967. break;
  968. }
  969. }
  970. LeaveCriticalSection( &_csNcPaint );
  971. }
  972. }
  973. return hwnd;
  974. }
  975. //-------------------------------------------------------------------------//
  976. // CThemeWnd implementation
  977. //-------------------------------------------------------------------------//
  978. //-------------------------------------------------------------------------//
  979. LONG CThemeWnd::_cObj = 0;
  980. //-------------------------------------------------------------------------//
  981. CThemeWnd::CThemeWnd()
  982. : _hwnd(NULL),
  983. _hTheme(NULL),
  984. _dwRenderedNcParts(0),
  985. _hwndMDIClient(NULL),
  986. _hAppIcon(NULL),
  987. _hrgnWnd(NULL),
  988. _fClassFlags(0),
  989. _fDirtyFrameRgn(0),
  990. _fFrameThemed(FALSE),
  991. _fThemedMDIBtns(FALSE),
  992. _pMdiBtns(NULL),
  993. _fAssigningFrameRgn(FALSE),
  994. _fAssignedFrameRgn(FALSE),
  995. _fSuppressStyleMsgs(FALSE),
  996. _fInThemeSettingChange(FALSE),
  997. _fDetached(FALSE),
  998. _dwRevokeFlags(0),
  999. _cLockRedraw(0),
  1000. _cNcPaint(0),
  1001. _cNcThemePaint(0),
  1002. _htHot(HTERROR),
  1003. _fProcessedEraseBk(0),
  1004. #ifdef LAME_BUTTON
  1005. _hFontLame(NULL),
  1006. #endif // LAME_BUTTON
  1007. _cRef(1)
  1008. {
  1009. InterlockedIncrement( &_cObj );
  1010. // set object validation signature tags
  1011. StringCchCopyA(_szHead, ARRAYSIZE(_szHead), SIG_CTHEMEWND_HEAD);
  1012. StringCchCopyA(_szTail, ARRAYSIZE(_szTail), SIG_CTHEMEWND_TAIL);
  1013. // cached subregion arrays
  1014. ZeroMemory( _rghrgnParts, sizeof(_rghrgnParts) );
  1015. ZeroMemory( _rghrgnSizingTemplates, sizeof(_rghrgnSizingTemplates) );
  1016. // initialize add'l structures.
  1017. InitWindowMetrics();
  1018. ZeroMemory(&_cswm, sizeof(_cswm));
  1019. FillMemory(&_sizeRgn, sizeof(_sizeRgn), 0xFF);
  1020. #ifdef DEBUG
  1021. *_szCaption = *_szWndClass = 0;
  1022. #endif DEBUG
  1023. }
  1024. //-------------------------------------------------------------------------//
  1025. CThemeWnd::~CThemeWnd()
  1026. {
  1027. _CloseTheme();
  1028. _FreeRegionHandles();
  1029. UnloadMdiBtns();
  1030. ClearLameResources();
  1031. SAFE_DELETECRITICALSECTION(&_cswm);
  1032. ASSERT( 0 != _cObj );
  1033. InterlockedDecrement( &_cObj );
  1034. }
  1035. //-------------------------------------------------------------------------//
  1036. void CThemeWnd::_CloseTheme()
  1037. {
  1038. if( _hTheme )
  1039. {
  1040. CloseThemeData(_hTheme);
  1041. _hTheme = NULL;
  1042. }
  1043. }
  1044. //-------------------------------------------------------------------------//
  1045. LONG CThemeWnd::AddRef()
  1046. {
  1047. return InterlockedIncrement( &_cRef );
  1048. }
  1049. //-------------------------------------------------------------------------//
  1050. LONG CThemeWnd::Release()
  1051. {
  1052. ASSERT( 0 != _cRef );
  1053. LONG cRef = InterlockedDecrement( &_cRef );
  1054. if( 0 == cRef )
  1055. {
  1056. if (_hwnd)
  1057. {
  1058. //---- check if last window of app ----
  1059. ShutDownCheck(_hwnd);
  1060. }
  1061. //Log(LOG_RFBUG, L"DELETING CThemeWnd=0x%08x", this);
  1062. delete this;
  1063. }
  1064. return cRef;
  1065. }
  1066. //-------------------------------------------------------------------------//
  1067. ULONG CThemeWnd::EvaluateWindowStyle( HWND hwnd )
  1068. {
  1069. ULONG dwStyle = GetWindowLong( hwnd, GWL_STYLE );
  1070. ULONG dwExStyle = GetWindowLong( hwnd, GWL_EXSTYLE );
  1071. return EvaluateStyle( dwStyle, dwExStyle );
  1072. }
  1073. //-------------------------------------------------------------------------//
  1074. // CThemeWnd::EvaluateStyle() - determines appropriate theming flags for the
  1075. // specified window style bits.
  1076. ULONG CThemeWnd::EvaluateStyle( DWORD dwStyle, DWORD dwExStyle )
  1077. {
  1078. ULONG fClassFlags = 0;
  1079. //--- frame check ---
  1080. if( HAS_CAPTIONBAR(dwStyle) )
  1081. {
  1082. fClassFlags |=
  1083. (TESTFLAG(dwExStyle, WS_EX_TOOLWINDOW) ? TWCF_TOOLFRAME : TWCF_FRAME );
  1084. }
  1085. //--- client edge check ---
  1086. if( TESTFLAG(dwExStyle, WS_EX_CLIENTEDGE) )
  1087. fClassFlags |= TWCF_CLIENTEDGE;
  1088. //--- scrollbar check ---
  1089. if( TESTFLAG(dwStyle, WS_HSCROLL|WS_VSCROLL) )
  1090. fClassFlags |= TWCF_SCROLLBARS;
  1091. return fClassFlags;
  1092. }
  1093. //-------------------------------------------------------------------------//
  1094. // CThemeWnd::_EvaluateExclusions() - determines special-case per-window exclusions
  1095. ULONG CThemeWnd::_EvaluateExclusions( HWND hwnd, NCEVALUATE* pnce )
  1096. {
  1097. // Windows parented by HWND_MESSAGE should not be themed..
  1098. if( _IsMessageWindow(hwnd) )
  1099. {
  1100. pnce->fExile = TRUE;
  1101. return 0L;
  1102. }
  1103. TCHAR szWndClass[128];
  1104. *szWndClass = 0;
  1105. if( TESTFLAG(pnce->fClassFlags, (TWCF_FRAME|TWCF_TOOLFRAME)) )
  1106. {
  1107. do
  1108. {
  1109. if( !pnce->fIgnoreWndRgn )
  1110. {
  1111. //--- Complex region check on frame
  1112. RECT rcRgn = {0};
  1113. int nRgn = GetWindowRgnBox( hwnd, &rcRgn );
  1114. if( COMPLEXREGION == nRgn || SIMPLEREGION == nRgn )
  1115. {
  1116. pnce->fClassFlags &= ~TWCF_FRAME;
  1117. break;
  1118. }
  1119. }
  1120. // SHIMSHIM [scotthan]:
  1121. #ifndef __NO_APPHACKS__
  1122. // Check for excluded window classes.
  1123. static LPCWSTR _rgExcludedClassesW[] =
  1124. {
  1125. L"MsoCommandBar", // Outlook's custom combobox control.
  1126. // (122225) In OnOwpPostCreate we call SetWindowPos which causes
  1127. // a WM_WINDOWPOSCHANGING to be sent to the control. However
  1128. // the controls isn't ready to begin accepting messages and
  1129. // the following error message is display:
  1130. //
  1131. // Runtime Error!
  1132. // Program: Outlook.exe
  1133. // R6025 - pure virtual function call
  1134. L"Exceed", // 150248: Hummingbird Exceed 6.xx
  1135. // The application's main window class name, a hidden window
  1136. // whose only purpose is to appear in the task bar in order to handle
  1137. // his context menu. The ExceedWndProc AVs when themed due to the
  1138. // additional messages generated in OnOwpPostCreate.
  1139. //---- winlogoon hidden windows ----
  1140. L"NDDEAgnt", // on private desktop
  1141. L"MM Notify Callback", // on private desktop
  1142. L"SAS window class", // on private desktop
  1143. };
  1144. if( GetClassNameW( hwnd, szWndClass, ARRAYSIZE(szWndClass) ) &&
  1145. AsciiScanStringList( szWndClass, _rgExcludedClassesW,
  1146. ARRAYSIZE(_rgExcludedClassesW), TRUE ) )
  1147. {
  1148. pnce->fClassFlags &= ~TWCF_FRAME;
  1149. pnce->fExile = TRUE;
  1150. break;
  1151. }
  1152. #endif __NO_APPHACKS__
  1153. } while(0);
  1154. }
  1155. // Some applications (MsDev) create scrollbar controls and incorrectly include
  1156. // WS_[V|H]SCROLL style bits causing us to think they are non-client scrolls.
  1157. // See #204191.
  1158. if( TESTFLAG(pnce->fClassFlags, TWCF_SCROLLBARS) )
  1159. {
  1160. if( !*szWndClass && GetClassName( hwnd, szWndClass, ARRAYSIZE(szWndClass) ) )
  1161. {
  1162. if( 0 == AsciiStrCmpI(szWndClass, L"scrollbar") )
  1163. pnce->fClassFlags &= ~TWCF_SCROLLBARS;
  1164. }
  1165. }
  1166. // Fixed in longhorn [phellyar]:
  1167. #ifndef __NO_APPHACKS__
  1168. if( *szWndClass || GetClassName( hwnd, szWndClass, ARRAYSIZE(szWndClass) ) )
  1169. {
  1170. // 453888: VB Grid control - setting the redraw property on this control
  1171. // causes it to zero and reset the scrollbar range for every scroll event.
  1172. // This causes the scrollbar to function incorrecly when themed.
  1173. if( 0 == AsciiStrCmpI(szWndClass, L"MSFlexGridWndClass") )
  1174. {
  1175. pnce->fClassFlags &= ~TWCF_SCROLLBARS;
  1176. pnce->fExile = TRUE;
  1177. }
  1178. }
  1179. #endif __NO_APPHACKS__
  1180. return pnce->fClassFlags;
  1181. }
  1182. //-------------------------------------------------------------------------//
  1183. // CThemeWnd::_Evaluate() - determines appropriate theming flags for the
  1184. // specified window.
  1185. ULONG CThemeWnd::_Evaluate( HWND hwnd, NCEVALUATE* pnce )
  1186. {
  1187. pnce->fClassFlags = 0;
  1188. pnce->dwStyle = GetWindowLong( hwnd, GWL_STYLE );
  1189. pnce->dwExStyle = GetWindowLong( hwnd, GWL_EXSTYLE );
  1190. if( GetClassLong( hwnd, GCW_ATOM ) == (DWORD)(DWORD_PTR)WC_DIALOG )
  1191. {
  1192. pnce->fClassFlags |= TWCF_DIALOG;
  1193. }
  1194. #ifdef DEBUG
  1195. //--- dialog check ---
  1196. if( TESTFLAG( pnce->fClassFlags, TWCF_DIALOG ) )
  1197. {
  1198. TCHAR szWndClass[96];
  1199. if( !GetClassNameW( hwnd, szWndClass, ARRAYSIZE(szWndClass) ) )
  1200. return 0;
  1201. ASSERT(0 == lstrcmpW(szWndClass, DLGWNDCLASSNAMEW));
  1202. }
  1203. #endif DEBUG
  1204. pnce->fClassFlags |= EvaluateStyle( pnce->dwStyle, pnce->dwExStyle );
  1205. if( pnce->fClassFlags )
  1206. {
  1207. pnce->fClassFlags = _EvaluateExclusions( hwnd, pnce );
  1208. }
  1209. return pnce->fClassFlags;
  1210. }
  1211. //-------------------------------------------------------------------------//
  1212. // Retrieves the address of the CThemeWnd object instance from the
  1213. // indicated window.
  1214. CThemeWnd* CThemeWnd::FromHwnd( HWND hwnd )
  1215. {
  1216. CThemeWnd *pwnd = NULL;
  1217. if( IsWindow(hwnd) )
  1218. {
  1219. if( g_dwProcessId )
  1220. {
  1221. DWORD dwPid = 0;
  1222. GetWindowThreadProcessId( hwnd, &dwPid );
  1223. if( dwPid == g_dwProcessId )
  1224. {
  1225. pwnd = (CThemeWnd*)GetProp( hwnd, MAKEINTATOM(GetThemeAtom(THEMEATOM_NONCLIENT)) );
  1226. if ( VALID_THEMEWND(pwnd) )
  1227. {
  1228. // verify this is a valid CThemeWnd object pointer
  1229. if ( IsBadReadPtr(pwnd, sizeof(CThemeWnd)) ||
  1230. (memcmp(pwnd->_szHead, SIG_CTHEMEWND_HEAD, ARRAYSIZE(pwnd->_szHead)) != 0) ||
  1231. (memcmp(pwnd->_szTail, SIG_CTHEMEWND_TAIL, ARRAYSIZE(pwnd->_szTail)) != 0) )
  1232. {
  1233. pwnd = THEMEWND_REJECT;
  1234. }
  1235. }
  1236. }
  1237. }
  1238. }
  1239. return pwnd;
  1240. }
  1241. //-------------------------------------------------------------------------//
  1242. // retrieves CThemeWnd instance from window or ancestors.
  1243. CThemeWnd* CThemeWnd::FromHdc( HDC hdc, int cAncestors )
  1244. {
  1245. HWND hwnd = NULL;
  1246. for( hwnd = WindowFromDC(hdc);
  1247. cAncestors >=0 && IsWindow(hwnd);
  1248. cAncestors--, hwnd = GetParent(hwnd) )
  1249. {
  1250. CThemeWnd* pwnd = FromHwnd(hwnd);
  1251. if( VALID_THEMEWND(pwnd) )
  1252. {
  1253. return pwnd;
  1254. }
  1255. }
  1256. return NULL;
  1257. }
  1258. //-------------------------------------------------------------------------//
  1259. // Static wrapper: attaches a CThemeWnd instance to the specified window.
  1260. CThemeWnd* CThemeWnd::Attach( HWND hwnd, IN OUT OPTIONAL NCEVALUATE* pnce )
  1261. {
  1262. LogEntryNC(L"Attach");
  1263. #ifdef LOGGING
  1264. //---- remember first window (app window) hooked for ShutDownCheck() ----
  1265. //---- this is only for BoundsChecker (tm) runs for finding leaks ----
  1266. if (! g_hwndFirstHooked)
  1267. {
  1268. if ((GetMenu(hwnd)) && (! GetParent(hwnd)))
  1269. g_hwndFirstHooked = hwnd;
  1270. }
  1271. #endif
  1272. CThemeWnd* pwnd = NULL;
  1273. // Note: Important not to do anything here that causes
  1274. // a window message to be posted or sent to the window: could
  1275. // mean tying ourselves up in a recursive knot (see _ThemeDefWindowProc).
  1276. pwnd = FromHwnd( hwnd );
  1277. if( NULL == pwnd )
  1278. {
  1279. HTHEME hTheme = NULL;
  1280. NCEVALUATE nce;
  1281. // copy any IN params from NCEVALUATE struct
  1282. if( !pnce )
  1283. {
  1284. ZeroMemory(&nce, sizeof(nce));
  1285. pnce = &nce;
  1286. }
  1287. ULONG ulTargetFlags = _Evaluate( hwnd, pnce );
  1288. // Anything worth theming?
  1289. if( TESTFLAG(ulTargetFlags, TWCF_NCTHEMETARGETMASK) )
  1290. {
  1291. hTheme = _AcquireThemeHandle( hwnd, &ulTargetFlags );
  1292. if( NULL == hTheme )
  1293. {
  1294. Fail(hwnd);
  1295. }
  1296. }
  1297. else
  1298. {
  1299. // reject windows with untargeted a
  1300. Reject(hwnd, pnce->fExile);
  1301. }
  1302. if( NULL != hTheme )
  1303. {
  1304. // Yes, create a real nctheme object for the window
  1305. if( (pwnd = new CThemeWnd) != NULL )
  1306. {
  1307. if( !pwnd->_AttachInstance( hwnd, hTheme, ulTargetFlags, pnce->pvWndCompat ) )
  1308. {
  1309. pwnd->Release();
  1310. pwnd = NULL;
  1311. }
  1312. }
  1313. else // cleanup hTheme if CThemeWnd creation failed
  1314. {
  1315. CloseThemeData(hTheme);
  1316. }
  1317. }
  1318. }
  1319. LogExitNC(L"Attach");
  1320. return pwnd;
  1321. }
  1322. //-------------------------------------------------------------------------//
  1323. // Instance method: attaches the CThemeWnd object to the specified window.
  1324. BOOL CThemeWnd::_AttachInstance( HWND hwnd, HTHEME hTheme, ULONG ulTargetFlags, PVOID pvWndCompat )
  1325. {
  1326. if( VALID_CRITICALSECTION(&_cswm) || NT_SUCCESS(RtlInitializeCriticalSection( &_cswm )) )
  1327. {
  1328. Log(LOG_NCATTACH, L"_AttachInstance: Nonclient attached to hwnd=0x%x", hwnd);
  1329. _hwnd = hwnd;
  1330. _hTheme = hTheme;
  1331. _fClassFlags = ulTargetFlags;
  1332. _fFrameThemed = TESTFLAG( ulTargetFlags, TWCF_FRAME|TWCF_TOOLFRAME );
  1333. return SetProp( hwnd, MAKEINTATOM(GetThemeAtom(THEMEATOM_NONCLIENT)), this );
  1334. }
  1335. return FALSE;
  1336. }
  1337. //-------------------------------------------------------------------------//
  1338. void CThemeWnd::RemoveWindowProperties(HWND hwnd, BOOL fDestroying)
  1339. {
  1340. //---- remove properties that require theme or hooks ----
  1341. RemoveProp(hwnd, MAKEINTATOM(GetThemeAtom(THEMEATOM_HTHEME)));
  1342. if (fDestroying)
  1343. {
  1344. // Help apps by cleaning up the dialog texture.
  1345. RemoveProp(hwnd, MAKEINTATOM(GetThemeAtom(THEMEATOM_DLGTEXTURING)));
  1346. //---- remove all remaining theme properties ----
  1347. ApplyStringProp(hwnd, NULL, GetThemeAtom(THEMEATOM_SUBIDLIST));
  1348. ApplyStringProp(hwnd, NULL, GetThemeAtom(THEMEATOM_SUBAPPNAME));
  1349. //---- notify appinfo (foreign tracking, preview) ----
  1350. g_pAppInfo->OnWindowDestroyed(hwnd);
  1351. }
  1352. else
  1353. {
  1354. //---- only do this if hwnd is not being destroyed ----
  1355. ClearExStyleBits(hwnd);
  1356. }
  1357. }
  1358. //-------------------------------------------------------------------------//
  1359. // Static wrapper: detaches and destroys the CThemeWnd instance attached to the indicated
  1360. // window
  1361. void CThemeWnd::Detach( HWND hwnd, DWORD dwDisposition )
  1362. {
  1363. LogEntryNC(L"Detach");
  1364. // DO NOT GENERATE ANY WINDOW MESSAGES FROM THIS FUNCTION!!!
  1365. // (unless cleaning up frame).
  1366. // Prevent message threads from detaching when unhook thread (DetachAll) is executing...
  1367. if( !UNHOOKING() || TESTFLAG(dwDisposition, HMD_BULKDETACH) )
  1368. {
  1369. CThemeWnd* pwnd = FromHwnd( hwnd );
  1370. if( pwnd ) // nonclient tagged
  1371. {
  1372. if( VALID_THEMEWND(pwnd) )
  1373. {
  1374. // only one thread flips the _fDetached bit and proceeds through
  1375. // instance detatch and object free. Otherwise, object can be freed
  1376. // simultaneously on two different threads,
  1377. // e.g. (1) message thread and (2) UIAH_UNHOOK thread (ouch! scotthan).
  1378. if( !InterlockedCompareExchange( (LONG*)&pwnd->_fDetached, TRUE, FALSE ) )
  1379. {
  1380. pwnd->_DetachInstance( dwDisposition );
  1381. pwnd->Release();
  1382. }
  1383. }
  1384. else
  1385. {
  1386. RemoveProp( hwnd, MAKEINTATOM(GetThemeAtom(THEMEATOM_NONCLIENT)) );
  1387. }
  1388. }
  1389. if (hwnd)
  1390. {
  1391. RemoveWindowProperties( hwnd, ((dwDisposition & HMD_WINDOWDESTROY) != 0) );
  1392. }
  1393. }
  1394. LogExitNC(L"Detach");
  1395. }
  1396. //-------------------------------------------------------------------------//
  1397. // Instance method: detaches the CThemeWnd object from the specified window.
  1398. BOOL CThemeWnd::_DetachInstance( DWORD dwDisposition )
  1399. {
  1400. HWND hwnd = _hwnd;
  1401. // untheme maxed MDI child sysbuttons.
  1402. ThemeMDIMenuButtons(FALSE, FALSE);
  1403. // Here's our last chance to ensure frame theme is withdrawn cleanly.
  1404. if( (IsFrameThemed() || IsRevoked(RF_REGION)) && AssignedFrameRgn() &&
  1405. !TESTFLAG(dwDisposition, HMD_PROCESSDETACH|HMD_WINDOWDESTROY))
  1406. {
  1407. RemoveFrameTheme( FTF_REDRAW );
  1408. }
  1409. //SPEW_THEMEWND( pwnd, 0, TEXT("UxTheme - Detaching and deleting themewnd: %s\n") );
  1410. DetachScrollBars( hwnd );
  1411. _hwnd =
  1412. _hwndMDIClient = NULL;
  1413. UnloadMdiBtns();
  1414. _CloseTheme();
  1415. Log(LOG_NCATTACH, L"_DetachInstance: Nonclient detached to hwnd=0x%x", hwnd);
  1416. RemoveProp( hwnd, MAKEINTATOM(GetThemeAtom(THEMEATOM_NONCLIENT)) );
  1417. return TRUE;
  1418. }
  1419. //-------------------------------------------------------------------------//
  1420. // Ensures that the specified window will not be themed during its lifetime
  1421. BOOL CThemeWnd::Reject( HWND hwnd, BOOL fExile )
  1422. {
  1423. // set a 'nil' tag on the window
  1424. return hwnd ? SetProp( hwnd, MAKEINTATOM(GetThemeAtom(THEMEATOM_NONCLIENT)),
  1425. fExile ? THEMEWND_EXILE : THEMEWND_REJECT ) : FALSE;
  1426. }
  1427. //-------------------------------------------------------------------------//
  1428. // Ensures that the specified window will not be themed during its lifetime
  1429. BOOL CThemeWnd::Fail( HWND hwnd )
  1430. {
  1431. // set a failure tag on the window
  1432. return hwnd ? SetProp( hwnd, MAKEINTATOM(GetThemeAtom(THEMEATOM_NONCLIENT)),
  1433. THEMEWND_FAILURE ) : FALSE;
  1434. }
  1435. //-------------------------------------------------------------------------//
  1436. // Revokes theming on a themed window
  1437. BOOL CThemeWnd::Revoke()
  1438. {
  1439. // Warning Will Robinson: After we detach, the CThemeWnd::_hwnd
  1440. // and related members will be reset, so save this on the stack.
  1441. BOOL fRet = TRUE;
  1442. HWND hwnd = _hwnd;
  1443. if( !IsRevoked(RF_INREVOKE) )
  1444. {
  1445. EnterRevoke();
  1446. _dwRevokeFlags &= ~RF_DEFER;
  1447. Detach( hwnd, HMD_REVOKE );
  1448. fRet = Reject( hwnd, TRUE );
  1449. LeaveRevoke();
  1450. }
  1451. return fRet;
  1452. }
  1453. //-------------------------------------------------------------------------//
  1454. // cookie passed to EnumChildWindows callback for CThemeWnd::DetachAll
  1455. typedef struct
  1456. {
  1457. DWORD dwProcessId;
  1458. DWORD dwDisposition;
  1459. }DETACHALL;
  1460. //-------------------------------------------------------------------------//
  1461. // EnumChildWindows callback for CThemeWnd::DetachAll
  1462. BOOL CThemeWnd::_DetachDesktopWindowsCB( HWND hwnd, LPARAM lParam )
  1463. {
  1464. DETACHALL* pda = (DETACHALL*)lParam;
  1465. // detach this window
  1466. if( IsWindowProcess( hwnd, pda->dwProcessId ) )
  1467. {
  1468. //---- clear the nonclient theme ----
  1469. CThemeWnd::Detach(hwnd, HMD_THEMEDETACH|pda->dwDisposition);
  1470. if( !TESTFLAG(pda->dwDisposition, HMD_PROCESSDETACH) )
  1471. {
  1472. //---- clear the client theme now, so that we can invalidate ----
  1473. //---- all old theme handles after this. ----
  1474. SafeSendMessage(hwnd, WM_THEMECHANGED, (WPARAM)-1, 0);
  1475. Log(LOG_TMHANDLE, L"Did SEND of WM_THEMECHANGED to client hwnd=0x%x", hwnd);
  1476. }
  1477. }
  1478. return TRUE;
  1479. }
  1480. //-------------------------------------------------------------------------//
  1481. // Detaches all themed windows managed by this process.
  1482. void CThemeWnd::DetachAll( DWORD dwDisposition )
  1483. {
  1484. DETACHALL da;
  1485. da.dwProcessId = GetCurrentProcessId();
  1486. da.dwDisposition = dwDisposition;
  1487. da.dwDisposition |= HMD_BULKDETACH;
  1488. //---- this will enum all windows for this process (all desktops, all child levels) ----
  1489. EnumProcessWindows( _DetachDesktopWindowsCB, (LPARAM)&da );
  1490. }
  1491. //-------------------------------------------------------------------------//
  1492. HTHEME CThemeWnd::_AcquireThemeHandle( HWND hwnd, ULONG* pfClassFlags )
  1493. {
  1494. HTHEME hTheme = ::OpenNcThemeData( hwnd, L"Window" );
  1495. if( NULL == hTheme )
  1496. {
  1497. if( pfClassFlags )
  1498. {
  1499. if( TESTFLAG(*pfClassFlags, TWCF_ANY) )
  1500. (*pfClassFlags) &= ~TWCF_ALL;
  1501. else
  1502. *pfClassFlags = 0;
  1503. }
  1504. }
  1505. //---- Did OpenNcThemeData() discover a new theme ----
  1506. if (g_pAppInfo->HasThemeChanged())
  1507. {
  1508. //---- IMPORTANT: we must refresh our theme metrics now, ----
  1509. //---- BEFORE we do our nonclient layout calcs & build a region window ----
  1510. AcquireNcThemeMetrics();
  1511. }
  1512. return hTheme;
  1513. }
  1514. //-------------------------------------------------------------------------//
  1515. // CThemeWnd::SetFrameTheme
  1516. //
  1517. // Initiates theming of the frame.
  1518. void CThemeWnd::SetFrameTheme(
  1519. IN ULONG dwFlags,
  1520. IN OPTIONAL WINDOWINFO* pwi )
  1521. {
  1522. LogEntryNC(L"SetFrameTheme");
  1523. ASSERT(TestCF( TWCF_FRAME|TWCF_TOOLFRAME ));
  1524. InitLameResources();
  1525. DWORD fSwp = SWP_NOZORDER|SWP_NOACTIVATE;
  1526. RECT rcWnd = {0};
  1527. BOOL bSwp = FALSE;
  1528. if( !TESTFLAG( dwFlags, FTF_NOMODIFYPLACEMENT ) )
  1529. {
  1530. GetWindowRect( _hwnd, &rcWnd );
  1531. fSwp |= (SWP_NOSIZE|SWP_NOMOVE/*|SWP_FRAMECHANGED 341700: this flag causes some apps to crash on WINDOWPOSCHANGED*/);
  1532. bSwp = TRUE;
  1533. }
  1534. // Generate a WM_WINDOWPOSCHANGING message to
  1535. // force a SetWindowRgn + frame repaint.
  1536. if( TESTFLAG(dwFlags, FTF_REDRAW) )
  1537. {
  1538. fSwp |= SWP_DRAWFRAME;
  1539. }
  1540. else
  1541. {
  1542. fSwp |= SWP_NOSENDCHANGING;
  1543. }
  1544. // theme MDI menubar buttons
  1545. _hwndMDIClient = _FindMDIClient(_hwnd);
  1546. if( _hwndMDIClient )
  1547. {
  1548. ThemeMDIMenuButtons(TRUE, FALSE);
  1549. }
  1550. // Kick frame region update.
  1551. _fFrameThemed = TRUE; // we invoked SetFrameTheme. Must be set BEFORE SetWindowPos.so we handle NCCALCSIZE properly.
  1552. SetDirtyFrameRgn(TRUE, TRUE); // ensure region assembly on non-resizing windows and dlgs.
  1553. if( !TESTFLAG( dwFlags, FTF_NOMODIFYPLACEMENT ) && bSwp )
  1554. {
  1555. _ScreenToParent( _hwnd, &rcWnd );
  1556. SetWindowPos( _hwnd, NULL, rcWnd.left, rcWnd.top,
  1557. RECTWIDTH(&rcWnd), RECTHEIGHT(&rcWnd), fSwp );
  1558. }
  1559. LogExitNC(L"SetFrameTheme");
  1560. }
  1561. //-------------------------------------------------------------------------//
  1562. void CThemeWnd::_FreeRegionHandles()
  1563. {
  1564. #ifdef DEBUG
  1565. if( _hrgnWnd )
  1566. {
  1567. SPEW_RGNRECT(NCTF_RGNWND, TEXT("_FreeRegionHandles() - deleting window region"), _hrgnWnd, -1 );
  1568. }
  1569. #endif DEBUG
  1570. SAFE_DELETE_GDIOBJ(_hrgnWnd);
  1571. for( int i = 0; i < cFRAMEPARTS; i++ )
  1572. {
  1573. #ifdef DEBUG
  1574. if( _rghrgnParts[i] )
  1575. {
  1576. SPEW_RGNRECT(NCTF_RGNWND, TEXT("_FreeRegionHandles() - deleting component region"), _rghrgnParts[i], _ncwm.rgframeparts[i] );
  1577. }
  1578. if( _rghrgnSizingTemplates[i] )
  1579. {
  1580. SPEW_RGNRECT(NCTF_RGNWND, TEXT("_FreeRegionHandles() - deleting template region"), _rghrgnSizingTemplates[i], _ncwm.rgframeparts[i] );
  1581. }
  1582. #endif DEBUG
  1583. SAFE_DELETE_GDIOBJ(_rghrgnParts[i]);
  1584. SAFE_DELETE_GDIOBJ(_rghrgnSizingTemplates[i]);
  1585. }
  1586. }
  1587. //-------------------------------------------------------------------------//
  1588. // CThemeWnd::RemoveFrameTheme
  1589. //
  1590. // Initiates theming of the frame. This method will not free the
  1591. // theme handle nor update the theme index.
  1592. void CThemeWnd::RemoveFrameTheme( ULONG dwFlags )
  1593. {
  1594. LogEntryNC(L"RemoveFrameTheme");
  1595. ASSERT(TestCF( TWCF_FRAME|TWCF_TOOLFRAME ));
  1596. _fFrameThemed = FALSE; // we're reverting SetFrameTheme
  1597. ClearRenderedNcPart(RNCF_ALL);
  1598. // Remove region
  1599. if( AssignedFrameRgn() && !TESTFLAG(dwFlags, FTF_NOMODIFYRGN) )
  1600. {
  1601. _fAssignedFrameRgn = FALSE;
  1602. _AssignRgn( NULL, dwFlags );
  1603. _FreeRegionHandles();
  1604. }
  1605. // Force redraw
  1606. if( TESTFLAG(dwFlags, FTF_REDRAW) )
  1607. InvalidateRect( _hwnd, NULL, TRUE );
  1608. ClearLameResources();
  1609. LogExitNC(L"RemoveFrameTheme");
  1610. }
  1611. //-------------------------------------------------------------------------//
  1612. BOOL CThemeWnd::IsNcThemed()
  1613. {
  1614. if( _hTheme != NULL && (IsRevoked(RF_DEFER) || !IsRevoked(RF_INREVOKE|RF_TYPEMASK)) &&
  1615. TestCF(TWCF_ANY & TWCF_NCTHEMETARGETMASK) )
  1616. {
  1617. if( TestCF(TWCF_FRAME|TWCF_TOOLFRAME) )
  1618. {
  1619. // if we're a frame window, we should be properly initialized
  1620. // w/ SetFrameTheme()
  1621. return _fFrameThemed;
  1622. }
  1623. return TRUE;
  1624. }
  1625. return FALSE;
  1626. }
  1627. //-------------------------------------------------------------------------//
  1628. BOOL CThemeWnd::IsFrameThemed()
  1629. {
  1630. return IsNcThemed() && _fFrameThemed &&
  1631. (AssignedFrameRgn() ? TRUE : TestCF( TWCF_FRAME|TWCF_TOOLFRAME ));
  1632. }
  1633. //-------------------------------------------------------------------------//
  1634. void CThemeWnd::SetDirtyFrameRgn( BOOL fDirty, BOOL fFrameChanged )
  1635. {
  1636. _fDirtyFrameRgn = fDirty;
  1637. Log(LOG_NCATTACH, L"SetDirtyFrameRgn: fDirty=%d, fFrameChanged=%d",
  1638. fDirty, fFrameChanged);
  1639. if( fFrameChanged ) // assure a region update despite no size change.
  1640. {
  1641. _sizeRgn.cx = _sizeRgn.cy = -1;
  1642. }
  1643. }
  1644. //-------------------------------------------------------------------------//
  1645. // CThemeWnd::CreateCompositeRgn() - assembles a composite region from
  1646. // non-client segment regions sized to fill the specified window rectangle.
  1647. //
  1648. HRGN CThemeWnd::CreateCompositeRgn(
  1649. IN const NCWNDMET* pncwm,
  1650. OUT HRGN rghrgnParts[],
  1651. OUT HRGN rghrgnTemplates[] )
  1652. {
  1653. ASSERT( pncwm->fFrame == TRUE ); // shouldn't be here unless we're a frame window
  1654. HRGN hrgnWnd = NULL, hrgnContent = NULL;
  1655. HRGN rghrgn[cFRAMEPARTS] = {0};
  1656. int i;
  1657. if( pncwm->fFullMaxed )
  1658. {
  1659. // All full-screen maximized windows get a region, which is used to clip
  1660. // the window to the current monitor. The window region for a maximized
  1661. // window consists of the maxcaption region combined with a rect region
  1662. // corresponding to the content area.
  1663. RECT rcFullCaption = pncwm->rcW0[NCRC_CAPTION];
  1664. rcFullCaption.top += pncwm->cnBorders;
  1665. rcFullCaption.left += pncwm->cnBorders;
  1666. rcFullCaption.right -= pncwm->cnBorders;
  1667. if( SUCCEEDED(GetThemeBackgroundRegion(_hTheme, NULL, pncwm->rgframeparts[iCAPTION], pncwm->framestate,
  1668. &rcFullCaption, &rghrgn[iCAPTION])) )
  1669. {
  1670. SPEW_RGNRECT(NCTF_RGNWND, TEXT("CreateCompositeRgn() maximized caption rgn"), rghrgn[iCAPTION], pncwm->rgframeparts[iCAPTION] );
  1671. AddToCompositeRgn(&hrgnWnd, rghrgn[iCAPTION], 0, 0);
  1672. if( !IsRectEmpty( &pncwm->rcW0[NCRC_CONTENT] ) )
  1673. {
  1674. // remainder of full-maxed frame region is the content area (client+menubar+scrollbars),
  1675. // and is always rectangular
  1676. hrgnContent = CreateRectRgnIndirect( &pncwm->rcW0[NCRC_CONTENT] );
  1677. SPEW_RGNRECT(NCTF_RGNWND, TEXT("CreateCompositeRgn() maximized frame content rgn"), hrgnContent, 0 );
  1678. AddToCompositeRgn(&hrgnWnd, hrgnContent, 0, 0);
  1679. SAFE_DELETE_GDIOBJ(hrgnContent);
  1680. }
  1681. }
  1682. }
  1683. else
  1684. {
  1685. // Normal windows consist of either a stand-alone frame part, or a frame
  1686. // part plus a caption part. In the first case, the window region is
  1687. // the frame region. In the second case, the window region is a composite
  1688. // of the frame and caption rects.
  1689. for( i = 0; i < ARRAYSIZE(pncwm->rgframeparts); i++ )
  1690. {
  1691. if( (iCAPTION == i || !pncwm->fMin) && !IsRectEmpty( &pncwm->rcW0[NCRC_FRAMEFIRST + i] ) )
  1692. {
  1693. if( _IsNcPartTransparent(pncwm->rgframeparts[i], _nctmCurrent) )
  1694. {
  1695. if( FAILED(GetThemeBackgroundRegion( _hTheme, NULL, pncwm->rgframeparts[i], pncwm->framestate,
  1696. &pncwm->rcW0[NCRC_FRAMEFIRST+i], &rghrgn[i] )) )
  1697. {
  1698. rghrgn[i] = NULL;
  1699. }
  1700. }
  1701. else
  1702. {
  1703. rghrgn[i] = CreateRectRgnIndirect( &pncwm->rcW0[NCRC_FRAMEFIRST + i] );
  1704. }
  1705. }
  1706. if( rghrgn[i] != NULL )
  1707. {
  1708. SPEW_RGNRECT(NCTF_RGNWND, TEXT("CreateCompositeRgn() frame subrgn"), rghrgn[i], pncwm->rgframeparts[i] );
  1709. AddToCompositeRgn(&hrgnWnd, rghrgn[i], 0, 0);
  1710. }
  1711. }
  1712. // don't forget window content area (client+menubar+scrollbars), which is always rectangular
  1713. if( !pncwm->fMin && !IsRectEmpty( &pncwm->rcW0[NCRC_CONTENT] ) )
  1714. {
  1715. hrgnContent = CreateRectRgnIndirect( &pncwm->rcW0[NCRC_CONTENT] );
  1716. SPEW_RGNRECT(NCTF_RGNWND, TEXT("CreateCompositeRgn() normal frame content rgn"), hrgnContent, 0 );
  1717. AddToCompositeRgn(&hrgnWnd, hrgnContent, 0, 0);
  1718. SAFE_DELETE_GDIOBJ(hrgnContent);
  1719. }
  1720. }
  1721. // copy subregions back to caller
  1722. CopyMemory( rghrgnParts, rghrgn, sizeof(rghrgn) );
  1723. // extract frame resizing templates
  1724. ZeroMemory( rghrgn, sizeof(rghrgn) ); // reuse region array
  1725. for( i = 0; i < cFRAMEPARTS; i++ )
  1726. {
  1727. const RECT* prc = &pncwm->rcW0[NCRC_FRAMEFIRST + i];
  1728. if( VALID_WINDOWPART(pncwm->rgsizehitparts[i]) && !IsRectEmpty( prc ) )
  1729. {
  1730. if( SUCCEEDED(GetThemeBackgroundRegion( _hTheme, NULL, pncwm->rgsizehitparts[i], pncwm->framestate,
  1731. prc, &rghrgn[i])) )
  1732. {
  1733. SPEW_RGNRECT(NCTF_RGNWND, TEXT("CreateCompositeRgn() sizing template"), rghrgn[i], pncwm->rgframeparts[i] );
  1734. }
  1735. }
  1736. }
  1737. CopyMemory( rghrgnTemplates, rghrgn, sizeof(rghrgn) );
  1738. return hrgnWnd;
  1739. }
  1740. //-------------------------------------------------------------------------//
  1741. void CThemeWnd::AssignFrameRgn( BOOL fAssign, DWORD dwFlags )
  1742. {
  1743. if( fAssign )
  1744. {
  1745. NCWNDMET* pncwm = NULL;
  1746. NCTHEMEMET nctm = {0};
  1747. if( GetNcWindowMetrics( NULL, &pncwm, &nctm, 0 ) )
  1748. {
  1749. // should we set up a window region on this frame?
  1750. if( pncwm->fFrame )
  1751. {
  1752. if( _ShouldAssignFrameRgn( pncwm, nctm ) )
  1753. {
  1754. if( (_sizeRgn.cx != RECTWIDTH(&pncwm->rcW0[NCRC_WINDOW]) ||
  1755. _sizeRgn.cy != RECTHEIGHT(&pncwm->rcW0[NCRC_WINDOW])) )
  1756. {
  1757. HRGN hrgnWnd = NULL;
  1758. HRGN rghrgnParts[cFRAMEPARTS] = {0};
  1759. HRGN rghrgnTemplates[cFRAMEPARTS] = {0};
  1760. if( (hrgnWnd = CreateCompositeRgn( pncwm, rghrgnParts, rghrgnTemplates )) != NULL )
  1761. {
  1762. _sizeRgn.cx = RECTWIDTH(&pncwm->rcW0[NCRC_WINDOW]);
  1763. _sizeRgn.cy = RECTHEIGHT(&pncwm->rcW0[NCRC_WINDOW]);
  1764. // cache all of our regions for fast hit-testing.
  1765. _FreeRegionHandles();
  1766. _hrgnWnd = _DupRgn( hrgnWnd ); // dup this one cuz after _AssignRgn, we don't own it.
  1767. CopyMemory( _rghrgnParts, rghrgnParts, sizeof(_rghrgnParts) );
  1768. CopyMemory( _rghrgnSizingTemplates, rghrgnTemplates, sizeof(_rghrgnSizingTemplates) );
  1769. // assign the region
  1770. _AssignRgn( hrgnWnd, dwFlags );
  1771. }
  1772. }
  1773. }
  1774. // otherwise, if we've assigned a region, make sure we remove it.
  1775. else if( AssignedFrameRgn() )
  1776. {
  1777. fAssign = FALSE;
  1778. }
  1779. }
  1780. }
  1781. }
  1782. if( !fAssign )
  1783. {
  1784. _AssignRgn( NULL, dwFlags );
  1785. FillMemory(&_sizeRgn, sizeof(_sizeRgn), 0xFF);
  1786. _FreeRegionHandles();
  1787. }
  1788. SetDirtyFrameRgn(FALSE); // make sure we reset this in case we didn't hit _AssignRgn.
  1789. }
  1790. //-------------------------------------------------------------------------//
  1791. // CThemeWnd::_AssignRgn() - assigns the specified region
  1792. // to the window, prevents recursion (SetWindowRgn w/ bRedraw == TRUE
  1793. // generates WM_WINDOWPOSCHANGING, WM_NCCALCSIZE, && WM_NCPAINT).
  1794. //
  1795. void CThemeWnd::_AssignRgn( HRGN hrgn, DWORD dwFlags )
  1796. {
  1797. if( TESTFLAG(dwFlags, FTF_NOMODIFYRGN) )
  1798. {
  1799. _fAssignedFrameRgn = FALSE;
  1800. }
  1801. else if( !IsWindowInDestroy(_hwnd) )
  1802. {
  1803. // Assign the new region.
  1804. _fAssigningFrameRgn = TRUE;
  1805. SPEW_RGNRECT(NCTF_RGNWND, TEXT("_AssignRgn() rect"), hrgn, -1 );
  1806. _fAssignedFrameRgn = SetWindowRgn( _hwnd, hrgn, TESTFLAG(dwFlags, FTF_REDRAW) ) != 0;
  1807. _fAssigningFrameRgn = FALSE;
  1808. }
  1809. SetDirtyFrameRgn(FALSE);
  1810. }
  1811. //-------------------------------------------------------------------------//
  1812. // CThemeWnd::GetNcWindowMetrics
  1813. //
  1814. // Computes internal per-window theme metrics.
  1815. //
  1816. BOOL CThemeWnd::GetNcWindowMetrics(
  1817. IN OPTIONAL LPCRECT prcWnd,
  1818. OUT OPTIONAL NCWNDMET** ppncwm,
  1819. OUT OPTIONAL NCTHEMEMET* pnctm,
  1820. IN DWORD dwOptions )
  1821. {
  1822. LogEntryNC(L"GetNcWindowMetrics");
  1823. NCTHEMEMET nctm;
  1824. BOOL bRet = FALSE;
  1825. BOOL fMenuBar = _ncwm.cyMenu != 0;
  1826. WINDOWPARTS rgframeparts[cFRAMEPARTS];
  1827. CopyMemory( rgframeparts, _ncwm.rgframeparts, sizeof(rgframeparts) );
  1828. // fetch per-theme metrics; we're going to need theme throughout
  1829. if (TESTFLAG(dwOptions, NCWMF_PREVIEW))
  1830. {
  1831. _LoadNcThemeMetrics(_hwnd, &nctm);
  1832. }
  1833. else if( !GetCurrentNcThemeMetrics( &nctm ) )
  1834. {
  1835. goto exit;
  1836. }
  1837. if( pnctm ) *pnctm = nctm;
  1838. if( !_ncwm.fValid || prcWnd != NULL )
  1839. dwOptions |= NCWMF_RECOMPUTE;
  1840. if( TESTFLAG(dwOptions, NCWMF_RECOMPUTE) )
  1841. {
  1842. // get caption text size before entering critsec (sends WM_GETTEXTLENGTH, WM_GETTEXT).
  1843. SIZE sizeCaptionText = {0};
  1844. HFONT hfCaption = NULL;
  1845. HWND hwndMDIActive = NULL;
  1846. // Do rough determination of whether or not we're a frame window and need to compute text metrics.
  1847. // We'll finalize this later
  1848. BOOL fFrame, fSmallFrame;
  1849. if( _ncwm.fValid )
  1850. {
  1851. fFrame = TESTFLAG( CThemeWnd::EvaluateStyle(_ncwm.dwStyle, _ncwm.dwExStyle), TWCF_FRAME|TWCF_TOOLFRAME );
  1852. fSmallFrame = TESTFLAG( CThemeWnd::EvaluateStyle(_ncwm.dwStyle, _ncwm.dwExStyle), TWCF_TOOLFRAME );
  1853. }
  1854. else
  1855. {
  1856. fFrame = TestCF(TWCF_FRAME|TWCF_TOOLFRAME);
  1857. fSmallFrame = TestCF(TWCF_TOOLFRAME);
  1858. }
  1859. // Compute text metrics outside of critical section (sends WM_GETTEXT);
  1860. if( fFrame && _fFrameThemed )
  1861. {
  1862. hfCaption = NcGetCaptionFont( fSmallFrame );
  1863. _GetNcCaptionTextSize( _hTheme, _hwnd, hfCaption, &sizeCaptionText );
  1864. }
  1865. // Retrieve active MDI sibling outside of critical section (sends WM_MDIGETACTIVE);
  1866. if( TESTFLAG(GetWindowLong(_hwnd, GWL_EXSTYLE), WS_EX_MDICHILD) )
  1867. {
  1868. hwndMDIActive = _MDIGetActive( GetParent(_hwnd) );
  1869. }
  1870. ASSERT(VALID_CRITICALSECTION(&_cswm));
  1871. if( VALID_CRITICALSECTION(&_cswm) )
  1872. {
  1873. EnterCriticalSection( &_cswm );
  1874. ZeroMemory( &_ncwm, sizeof(_ncwm) );
  1875. if( (bRet = _GetWindowMetrics( _hwnd, hwndMDIActive, &_ncwm )) != FALSE )
  1876. {
  1877. _ComputeNcWindowStatus( _hwnd, _ncwm.dwWindowStatus, &_ncwm );
  1878. // if window RECT is provided by the caller, stuff it now.
  1879. if( prcWnd )
  1880. {
  1881. _ncwm.rcS0[NCRC_WINDOW] = *prcWnd;
  1882. SetRectEmpty( &_ncwm.rcS0[NCRC_CLIENT] );
  1883. }
  1884. // stuff caption text size
  1885. _ncwm.sizeCaptionText = sizeCaptionText;
  1886. _ncwm.hfCaption = hfCaption;
  1887. // retrieve frame metrics.
  1888. if( _GetNcFrameMetrics( _hwnd, _hTheme, nctm, _ncwm ) )
  1889. {
  1890. if( _ncwm.fFrame )
  1891. {
  1892. // user32!SetMenu has been called, or the caption or frame part has changed
  1893. // So ensure frame region update.
  1894. if( (_ncwm.cyMenu == 0 && fMenuBar) || (_ncwm.cyMenu > 0 && !fMenuBar) ||
  1895. memcmp( rgframeparts, _ncwm.rgframeparts, sizeof(rgframeparts) ) )
  1896. {
  1897. SetDirtyFrameRgn(TRUE, TRUE);
  1898. }
  1899. // Compute NC button placement
  1900. AcquireFrameIcon(_ncwm.dwStyle, _ncwm.dwExStyle, FALSE);
  1901. _GetNcBtnMetrics( &_ncwm, &nctm, _hAppIcon, _MNCanClose(_hwnd) );
  1902. // Determine the caption margin for lame button metrics.
  1903. _GetNcCaptionMargins( _hTheme, nctm, _ncwm );
  1904. _GetNcCaptionTextRect( &_ncwm );
  1905. if( _ncwm.fFrame )
  1906. {
  1907. GetLameButtonMetrics( &_ncwm, &sizeCaptionText );
  1908. }
  1909. }
  1910. // Compute window-relative metrics
  1911. //
  1912. // If passed a window rect, base offsets on current window rect.
  1913. // This is done to ensure preview window's (_hwnd) fake child windows are rendered correctly.
  1914. RECT rcWnd = _ncwm.rcS0[NCRC_WINDOW];
  1915. if( prcWnd )
  1916. {
  1917. if( _hwnd )
  1918. GetWindowRect( _hwnd, &rcWnd );
  1919. // for an incoming window rect, assign the computed client rect.
  1920. _ncwm.rcS0[NCRC_CLIENT] = _ncwm.rcS0[NCRC_UXCLIENT];
  1921. }
  1922. for( int i = NCRC_FIRST; i < NCRC_COUNT; i++ )
  1923. {
  1924. _ncwm.rcW0[i] = _ncwm.rcS0[i];
  1925. OffsetRect( &_ncwm.rcW0[i], -rcWnd.left, -rcWnd.top );
  1926. }
  1927. // All base computations are done; mark valid.
  1928. _ncwm.fValid = TRUE;
  1929. }
  1930. }
  1931. LeaveCriticalSection( &_cswm );
  1932. }
  1933. }
  1934. if( ppncwm )
  1935. {
  1936. *ppncwm = &_ncwm;
  1937. }
  1938. bRet = TRUE;
  1939. exit:
  1940. LogExitNC(L"GetNcWindowMetrics");
  1941. return bRet;
  1942. }
  1943. //-------------------------------------------------------------------------//
  1944. inline COLORREF _GetNcCaptionTextColor( FRAMESTATES iStateId )
  1945. {
  1946. return GetSysColor( FS_ACTIVE == iStateId ?
  1947. COLOR_CAPTIONTEXT : COLOR_INACTIVECAPTIONTEXT );
  1948. }
  1949. //-------------------------------------------------------------------------//
  1950. // Get CTLCOLOR brush for solid fills
  1951. void _GetBrushesForPart(HTHEME hTheme, int iPart, HBITMAP* phbm, HBRUSH* phbr)
  1952. {
  1953. int nBgType;
  1954. *phbm = NULL;
  1955. *phbr = NULL;
  1956. // Get CTLCOLOR brush for solid fills
  1957. HRESULT hr = GetThemeEnumValue( hTheme, iPart, 0, TMT_BGTYPE, &nBgType );
  1958. if( SUCCEEDED( hr ))
  1959. {
  1960. if (BT_BORDERFILL == nBgType)
  1961. {
  1962. int nFillType;
  1963. hr = GetThemeEnumValue( hTheme, iPart, 0, TMT_FILLTYPE, &nFillType );
  1964. if (SUCCEEDED( hr ) &&
  1965. FT_SOLID == nFillType)
  1966. {
  1967. COLORREF cr;
  1968. hr = GetThemeColor( hTheme, iPart, 0, TMT_FILLCOLOR, &cr);
  1969. *phbr = CreateSolidBrush(cr);
  1970. }
  1971. else
  1972. {
  1973. ASSERTMSG(FALSE, "Themes: The theme file specified an invalid fill type for dialog boxes");
  1974. }
  1975. }
  1976. else if (BT_IMAGEFILE == nBgType)
  1977. {
  1978. HDC hdc = GetWindowDC(NULL);
  1979. if ( hdc )
  1980. {
  1981. hr = GetThemeBitmap(hTheme, hdc, iPart, 0, NULL, phbm);
  1982. if (SUCCEEDED(hr))
  1983. {
  1984. *phbr = CreatePatternBrush(*phbm);
  1985. }
  1986. ReleaseDC(NULL, hdc);
  1987. }
  1988. }
  1989. }
  1990. }
  1991. //-------------------------------------------------------------------------//
  1992. //
  1993. // Chooses appropriate hit testing parts for the various Nc area
  1994. //
  1995. void _GetNcSizingTemplates(
  1996. IN const NCTHEMEMET& nctm,
  1997. IN OUT NCWNDMET& ncwm ) // window metric block. dwStyle, dwExStyle, rcS0[NCRC_WINDOW] members are required.
  1998. {
  1999. FillMemory( ncwm.rgsizehitparts, sizeof(ncwm.rgsizehitparts), BOGUS_WINDOWPART );
  2000. // No need on windows without frames
  2001. if( !ncwm.fFrame )
  2002. return;
  2003. // minimized or full-screen maximized window
  2004. if( ncwm.fMin || ncwm.fFullMaxed )
  2005. return;
  2006. // No need on windows that aren't sizable
  2007. if( !TESTFLAG(ncwm.dwStyle, WS_THICKFRAME) )
  2008. return;
  2009. if( ncwm.fSmallFrame)
  2010. {
  2011. if (nctm.fSmCapSizingTemplate)
  2012. ncwm.rgsizehitparts[iCAPTION] = WP_SMALLCAPTIONSIZINGTEMPLATE;
  2013. if (nctm.fSmLeftSizingTemplate)
  2014. ncwm.rgsizehitparts[iFRAMELEFT] = WP_SMALLFRAMELEFTSIZINGTEMPLATE;
  2015. if (nctm.fSmRightSizingTemplate)
  2016. ncwm.rgsizehitparts[iFRAMERIGHT] = WP_SMALLFRAMERIGHTSIZINGTEMPLATE;
  2017. if (nctm.fSmBottomSizingTemplate)
  2018. ncwm.rgsizehitparts[iFRAMEBOTTOM] = WP_SMALLFRAMEBOTTOMSIZINGTEMPLATE;
  2019. }
  2020. else
  2021. {
  2022. if (nctm.fCapSizingTemplate)
  2023. ncwm.rgsizehitparts[iCAPTION] = WP_CAPTIONSIZINGTEMPLATE;
  2024. if (nctm.fLeftSizingTemplate)
  2025. ncwm.rgsizehitparts[iFRAMELEFT] = WP_FRAMELEFTSIZINGTEMPLATE;
  2026. if (nctm.fRightSizingTemplate)
  2027. ncwm.rgsizehitparts[iFRAMERIGHT] = WP_FRAMERIGHTSIZINGTEMPLATE;
  2028. if (nctm.fBottomSizingTemplate)
  2029. ncwm.rgsizehitparts[iFRAMEBOTTOM] = WP_FRAMEBOTTOMSIZINGTEMPLATE;
  2030. }
  2031. }
  2032. //-------------------------------------------------------------------------//
  2033. //
  2034. // Computes theme metrics for frame window.
  2035. //
  2036. BOOL _GetNcFrameMetrics(
  2037. IN OPTIONAL HWND hwnd, // window handle (required for multiline menubar calcs).
  2038. IN HTHEME hTheme, // theme handle (required)
  2039. IN const NCTHEMEMET& nctm, // theme metric block
  2040. IN OUT NCWNDMET& ncwm ) // window metric block. dwStyle, dwExStyle, rcS0[NCRC_WINDOW] members are required.
  2041. {
  2042. LogEntryNC(L"_GetNcFrameMetrics");
  2043. ASSERT(hTheme);
  2044. // recompute style class
  2045. ncwm.dwStyleClass = CThemeWnd::EvaluateStyle( ncwm.dwStyle, ncwm.dwExStyle );
  2046. ncwm.cnBorders = _GetWindowBorders( ncwm.dwStyle, ncwm.dwExStyle );
  2047. // compute frame attributes, state
  2048. ncwm.fFrame = TESTFLAG( ncwm.dwStyleClass, (TWCF_FRAME|TWCF_TOOLFRAME) );
  2049. ncwm.fSmallFrame = TESTFLAG( ncwm.dwStyleClass, TWCF_TOOLFRAME );
  2050. // compute frame and caption parts
  2051. if( ncwm.fFrame )
  2052. {
  2053. ncwm.rgframeparts[iFRAMEBOTTOM] =
  2054. ncwm.rgframeparts[iFRAMELEFT] =
  2055. ncwm.rgframeparts[iFRAMERIGHT] =
  2056. ncwm.rgframeparts[iCAPTION] = BOGUS_WINDOWPART;
  2057. if( ncwm.fMin ) // minimized window
  2058. {
  2059. ncwm.rgframeparts[iCAPTION] = WP_MINCAPTION;
  2060. }
  2061. else if( ncwm.fFullMaxed ) // full-screen maximized window
  2062. {
  2063. ncwm.rgframeparts[iCAPTION] = WP_MAXCAPTION;
  2064. }
  2065. else // normal or partial-screen maximized window with thick border
  2066. {
  2067. if( ncwm.fSmallFrame )
  2068. {
  2069. ncwm.rgframeparts[iCAPTION] = WP_SMALLCAPTION;
  2070. ncwm.rgframeparts[iFRAMELEFT] = WP_SMALLFRAMELEFT;
  2071. ncwm.rgframeparts[iFRAMERIGHT] = WP_SMALLFRAMERIGHT;
  2072. ncwm.rgframeparts[iFRAMEBOTTOM] = WP_SMALLFRAMEBOTTOM;
  2073. }
  2074. else
  2075. {
  2076. ncwm.rgframeparts[iCAPTION] = ncwm.fMaxed ? WP_MAXCAPTION : WP_CAPTION;
  2077. ncwm.rgframeparts[iFRAMELEFT] = WP_FRAMELEFT;
  2078. ncwm.rgframeparts[iFRAMERIGHT] = WP_FRAMERIGHT;
  2079. ncwm.rgframeparts[iFRAMEBOTTOM] = WP_FRAMEBOTTOM;
  2080. }
  2081. }
  2082. // stash caption text color.
  2083. ncwm.rgbCaption = _GetNcCaptionTextColor( ncwm.framestate );
  2084. // retrieve sizing templates.
  2085. _GetNcSizingTemplates( nctm, ncwm );
  2086. }
  2087. //-----------------------------------------------------------//
  2088. // Frame metrics
  2089. //
  2090. // Frame area includes 'skin' boundaries,
  2091. // menu, integrated caption and client edge.
  2092. //
  2093. // Independent of the frame is the separate caption seg,
  2094. // scrollbars, and sizebox
  2095. //-----------------------------------------------------------//
  2096. if( ncwm.fFrame ) // frame windows only
  2097. {
  2098. // Initialize positions of main frame components...
  2099. // Content rect: area bounded by frame theme.
  2100. // Client rect: area contained in content rect that excludes all nonclient
  2101. // elements (viz, scrollbars, menubar, inside edges).
  2102. // Caption rect: pertains to minimized and maximized windows,
  2103. // and normal windows if the theme defines a caption part
  2104. ncwm.rcS0[NCRC_CAPTION] =
  2105. ncwm.rcS0[NCRC_CONTENT] = ncwm.rcS0[NCRC_WINDOW];
  2106. SetRectEmpty( &ncwm.rcS0[NCRC_UXCLIENT] );
  2107. if( ncwm.fMin ) /* minimized frame */
  2108. {
  2109. // zero out content, client rectangles.
  2110. ncwm.rcS0[NCRC_CONTENT].right = ncwm.rcS0[NCRC_CONTENT].left;
  2111. ncwm.rcS0[NCRC_CONTENT].bottom = ncwm.rcS0[NCRC_CONTENT].top;
  2112. ncwm.rcS0[NCRC_CLIENT] =
  2113. ncwm.rcS0[NCRC_UXCLIENT] = ncwm.rcS0[NCRC_CONTENT];
  2114. }
  2115. else
  2116. {
  2117. NONCLIENTMETRICS ncm;
  2118. if( NcGetNonclientMetrics( &ncm, FALSE ) )
  2119. {
  2120. ncwm.rcS0[NCRC_FRAMEBOTTOM] =
  2121. ncwm.rcS0[NCRC_FRAMELEFT] =
  2122. ncwm.rcS0[NCRC_FRAMERIGHT] = ncwm.rcS0[NCRC_WINDOW];
  2123. // themed caption rect spans left, top, right bordersS
  2124. // and 1 pixel edge below caption
  2125. ncwm.rcS0[NCRC_CAPTION].bottom =
  2126. ncwm.rcS0[NCRC_CAPTION].top + ncwm.cnBorders +
  2127. (ncwm.fSmallFrame ? ncm.iSmCaptionHeight : ncm.iCaptionHeight) +
  2128. 1 /* 1 pixel below caption */;
  2129. // update the content and rects while we're here:
  2130. InflateRect( &ncwm.rcS0[NCRC_CONTENT], -ncwm.cnBorders, -ncwm.cnBorders );
  2131. ncwm.rcS0[NCRC_CONTENT].top = ncwm.rcS0[NCRC_CAPTION].bottom;
  2132. if( ncwm.rcS0[NCRC_CONTENT].bottom < ncwm.rcS0[NCRC_CONTENT].top )
  2133. ncwm.rcS0[NCRC_CONTENT].bottom = ncwm.rcS0[NCRC_CONTENT].top;
  2134. // at this point the client rect is identical to the content rect (haven't computed menubar, scrollbars).
  2135. ncwm.rcS0[NCRC_UXCLIENT] = ncwm.rcS0[NCRC_CONTENT];
  2136. // bottom border segment.
  2137. ncwm.rcS0[NCRC_FRAMEBOTTOM].top = ncwm.rcS0[NCRC_FRAMEBOTTOM].bottom - ncwm.cnBorders;
  2138. // side border segments
  2139. ncwm.rcS0[NCRC_FRAMELEFT].top =
  2140. ncwm.rcS0[NCRC_FRAMERIGHT].top = ncwm.rcS0[NCRC_CAPTION].bottom;
  2141. ncwm.rcS0[NCRC_FRAMELEFT].bottom =
  2142. ncwm.rcS0[NCRC_FRAMERIGHT].bottom = ncwm.rcS0[NCRC_FRAMEBOTTOM].top;
  2143. ncwm.rcS0[NCRC_FRAMELEFT].right = ncwm.rcS0[NCRC_FRAMELEFT].left + ncwm.cnBorders;
  2144. ncwm.rcS0[NCRC_FRAMERIGHT].left = ncwm.rcS0[NCRC_FRAMERIGHT].right - ncwm.cnBorders;
  2145. }
  2146. }
  2147. }
  2148. else // frameless windows with scrollbars and/or client-edge:
  2149. {
  2150. // Non-frame windows
  2151. ncwm.rcS0[NCRC_UXCLIENT] = ncwm.rcS0[NCRC_WINDOW];
  2152. InflateRect( &ncwm.rcS0[NCRC_UXCLIENT], -ncwm.cnBorders, -ncwm.cnBorders );
  2153. ncwm.rcS0[NCRC_CONTENT] = ncwm.rcS0[NCRC_UXCLIENT];
  2154. }
  2155. // Menubar
  2156. if( !(ncwm.fMin || TESTFLAG( ncwm.dwStyle, WS_CHILD )) ) // child windows don't have menubars
  2157. {
  2158. // Menubar offsets (for painting)
  2159. ncwm.cnMenuOffsetTop = ncwm.rcS0[NCRC_CONTENT].top - ncwm.rcS0[NCRC_WINDOW].top;
  2160. ncwm.cnMenuOffsetLeft = ncwm.rcS0[NCRC_CONTENT].left - ncwm.rcS0[NCRC_WINDOW].left;
  2161. ncwm.cnMenuOffsetRight = ncwm.rcS0[NCRC_WINDOW].right - ncwm.rcS0[NCRC_CONTENT].right;
  2162. if( hwnd )
  2163. {
  2164. // calc menubar does the right thing for multiline menubars
  2165. ncwm.cyMenu = CalcMenuBar( hwnd, ncwm.cnMenuOffsetLeft,
  2166. ncwm.cnMenuOffsetRight,
  2167. ncwm.cnMenuOffsetTop,
  2168. &ncwm.rcS0[NCRC_WINDOW] );
  2169. }
  2170. else
  2171. {
  2172. // no window (e.g. preview) == no menu, meaning don't call CalcMenuBar.
  2173. // we emulate computations best we can:
  2174. ncwm.cyMenu = NcGetSystemMetrics( SM_CYMENUSIZE );
  2175. }
  2176. // CalcMenuBar and SM_CYMENUSIZE are 1 pixel short of reality.
  2177. if( ncwm.cyMenu )
  2178. ncwm.cyMenu += nctm.dyMenuBar;
  2179. // Menubar rect (for hit-testing and clipping)
  2180. SetRect( &ncwm.rcS0[NCRC_MENUBAR],
  2181. ncwm.rcS0[NCRC_CONTENT].left,
  2182. ncwm.rcS0[NCRC_CONTENT].top,
  2183. ncwm.rcS0[NCRC_CONTENT].right,
  2184. min(ncwm.rcS0[NCRC_CONTENT].bottom, ncwm.rcS0[NCRC_CONTENT].top + ncwm.cyMenu) );
  2185. ncwm.rcS0[NCRC_UXCLIENT].top = ncwm.rcS0[NCRC_MENUBAR].bottom;
  2186. }
  2187. // Client Edge.
  2188. if( !ncwm.fMin && TESTFLAG(ncwm.dwExStyle, WS_EX_CLIENTEDGE) )
  2189. {
  2190. CopyRect( &ncwm.rcS0[NCRC_CLIENTEDGE], &ncwm.rcS0[NCRC_UXCLIENT] );
  2191. InflateRect( &ncwm.rcS0[NCRC_UXCLIENT],
  2192. -NcGetSystemMetrics( SM_CXEDGE ),
  2193. -NcGetSystemMetrics( SM_CYEDGE ));
  2194. }
  2195. //-----------------------------------------------------------//
  2196. // Scrollbars and sizebox/gripper
  2197. //-----------------------------------------------------------//
  2198. if( !ncwm.fMin )
  2199. {
  2200. // horizontal scroll bar.
  2201. if( TESTFLAG(ncwm.dwStyle, WS_HSCROLL) )
  2202. {
  2203. ncwm.rcS0[NCRC_HSCROLL] = ncwm.rcS0[NCRC_UXCLIENT];
  2204. ncwm.rcS0[NCRC_HSCROLL].top = ncwm.rcS0[NCRC_UXCLIENT].bottom =
  2205. ncwm.rcS0[NCRC_HSCROLL].bottom - NcGetSystemMetrics( SM_CYHSCROLL );
  2206. if( IsRectEmpty( &ncwm.rcS0[NCRC_CLIENT] ) /* this happens in preview */ )
  2207. {
  2208. ncwm.rcS0[NCRC_HSCROLL].left = ncwm.rcS0[NCRC_UXCLIENT].left;
  2209. ncwm.rcS0[NCRC_HSCROLL].right = ncwm.rcS0[NCRC_UXCLIENT].right;
  2210. }
  2211. else
  2212. {
  2213. ncwm.rcS0[NCRC_HSCROLL].left = ncwm.rcS0[NCRC_CLIENT].left;
  2214. ncwm.rcS0[NCRC_HSCROLL].right = ncwm.rcS0[NCRC_CLIENT].right;
  2215. }
  2216. }
  2217. // vertical scroll bar
  2218. if( TESTFLAG(ncwm.dwStyle, WS_VSCROLL) )
  2219. {
  2220. ncwm.rcS0[NCRC_VSCROLL] = ncwm.rcS0[NCRC_UXCLIENT];
  2221. if( TESTFLAG(ncwm.dwExStyle, WS_EX_LAYOUTRTL) ^ TESTFLAG(ncwm.dwExStyle, WS_EX_LEFTSCROLLBAR) )
  2222. {
  2223. ncwm.rcS0[NCRC_VSCROLL].right = ncwm.rcS0[NCRC_UXCLIENT].left =
  2224. ncwm.rcS0[NCRC_VSCROLL].left + NcGetSystemMetrics( SM_CXVSCROLL );
  2225. // Adjust for horz scroll, gripper
  2226. if( TESTFLAG(ncwm.dwStyle, WS_HSCROLL) )
  2227. {
  2228. ncwm.rcS0[NCRC_SIZEBOX]= ncwm.rcS0[NCRC_HSCROLL];
  2229. ncwm.rcS0[NCRC_SIZEBOX].right = ncwm.rcS0[NCRC_HSCROLL].left =
  2230. ncwm.rcS0[NCRC_UXCLIENT].left;
  2231. }
  2232. }
  2233. else
  2234. {
  2235. ncwm.rcS0[NCRC_VSCROLL].left = ncwm.rcS0[NCRC_UXCLIENT].right =
  2236. ncwm.rcS0[NCRC_VSCROLL].right - NcGetSystemMetrics( SM_CXVSCROLL );
  2237. // Adjust for horz scroll, gripper
  2238. if( TESTFLAG(ncwm.dwStyle, WS_HSCROLL) )
  2239. {
  2240. ncwm.rcS0[NCRC_SIZEBOX]= ncwm.rcS0[NCRC_HSCROLL];
  2241. ncwm.rcS0[NCRC_SIZEBOX].left = ncwm.rcS0[NCRC_HSCROLL].right =
  2242. ncwm.rcS0[NCRC_UXCLIENT].right;
  2243. }
  2244. }
  2245. if( IsRectEmpty( &ncwm.rcS0[NCRC_CLIENT] ) /* this happens in preview */ )
  2246. {
  2247. ncwm.rcS0[NCRC_VSCROLL].top = ncwm.rcS0[NCRC_UXCLIENT].top;
  2248. ncwm.rcS0[NCRC_VSCROLL].bottom = ncwm.rcS0[NCRC_UXCLIENT].bottom;
  2249. }
  2250. else
  2251. {
  2252. ncwm.rcS0[NCRC_VSCROLL].top = ncwm.rcS0[NCRC_CLIENT].top;
  2253. ncwm.rcS0[NCRC_VSCROLL].bottom = ncwm.rcS0[NCRC_CLIENT].bottom;
  2254. }
  2255. }
  2256. }
  2257. LogExitNC(L"_GetNcFrameMetrics");
  2258. return TRUE;
  2259. }
  2260. #define EXT_TRACK_VERT 0x01
  2261. #define EXT_TRACK_HORZ 0x02
  2262. //-------------------------------------------------------------------------//
  2263. void _GetNcBtnHitTestRect(
  2264. IN const NCWNDMET* pncwm,
  2265. IN UINT uHitcode,
  2266. BOOL fWindowRelative,
  2267. OUT LPRECT prcHit )
  2268. {
  2269. const RECT* prcBtn = NULL;
  2270. int dxLeft = 0; // button's left side delta
  2271. int dxRight = 0; // button's right side delta
  2272. // adjust hitrect to classic-look caption bar strip:
  2273. RECT rcHit = fWindowRelative ? pncwm->rcW0[NCRC_CAPTION] : pncwm->rcS0[NCRC_CAPTION];
  2274. rcHit.top += pncwm->cnBorders;
  2275. rcHit.left += pncwm->cnBorders;
  2276. rcHit.right -= pncwm->cnBorders;
  2277. rcHit.bottom -= 1;
  2278. // determine which button we're working with, how to extend the left, right sides.
  2279. switch( uHitcode )
  2280. {
  2281. case HTMINBUTTON:
  2282. prcBtn = fWindowRelative ? &pncwm->rcW0[NCRC_MINBTN] : &pncwm->rcS0[NCRC_MINBTN];
  2283. dxLeft = -1;
  2284. break;
  2285. case HTMAXBUTTON:
  2286. prcBtn = fWindowRelative ? &pncwm->rcW0[NCRC_MAXBTN] : &pncwm->rcS0[NCRC_MAXBTN];
  2287. dxRight = 1;
  2288. break;
  2289. case HTHELP:
  2290. prcBtn = fWindowRelative ? &pncwm->rcW0[NCRC_HELPBTN] : &pncwm->rcS0[NCRC_HELPBTN];
  2291. dxLeft = -1;
  2292. dxRight = 1;
  2293. break;
  2294. case HTCLOSE:
  2295. prcBtn = fWindowRelative ? &pncwm->rcW0[NCRC_CLOSEBTN] : &pncwm->rcS0[NCRC_CLOSEBTN];
  2296. dxLeft = -1;
  2297. dxRight = rcHit.right - prcBtn->right;
  2298. break;
  2299. case HTSYSMENU:
  2300. prcBtn = fWindowRelative ? &pncwm->rcW0[NCRC_SYSBTN] : &pncwm->rcS0[NCRC_SYSBTN];
  2301. dxLeft = rcHit.left - prcBtn->left;
  2302. dxRight = 1;
  2303. break;
  2304. }
  2305. if( prcBtn )
  2306. {
  2307. *prcHit = *prcBtn;
  2308. if( !IsRectEmpty( prcBtn ) )
  2309. {
  2310. rcHit.left = prcBtn->left + dxLeft;
  2311. rcHit.right = prcBtn->right + dxRight;
  2312. *prcHit = rcHit;
  2313. }
  2314. }
  2315. else
  2316. {
  2317. SetRectEmpty( prcHit );
  2318. }
  2319. }
  2320. //-------------------------------------------------------------------------//
  2321. // wraps alloc, retrieval of window text
  2322. LPWSTR _AllocWindowText( IN HWND hwnd )
  2323. {
  2324. LPWSTR pszRet = NULL;
  2325. if (hwnd && IsWindow(hwnd))
  2326. {
  2327. if( (pszRet = new WCHAR[MAX_PATH]) != NULL )
  2328. {
  2329. int cch;
  2330. if( (cch = InternalGetWindowText(hwnd, pszRet, MAX_PATH)) <= 0 )
  2331. {
  2332. __try // some wndprocs can't handle an early WM_GETTEXT (eg.310700).
  2333. {
  2334. cch = GetWindowText(hwnd, pszRet, MAX_PATH);
  2335. }
  2336. __except(EXCEPTION_EXECUTE_HANDLER)
  2337. {
  2338. cch = 0;
  2339. }
  2340. }
  2341. if( !cch )
  2342. {
  2343. SAFE_DELETE_ARRAY(pszRet); // delete and zero pointer
  2344. }
  2345. }
  2346. }
  2347. return pszRet;
  2348. }
  2349. //-------------------------------------------------------------------------//
  2350. // _GetNcCaptionMargins() - computes a margin from the window ULC based on the
  2351. // offsets in the theme and the location of enabled caption buttons. The left
  2352. // margin is to the right of the last left-aligned button, and the right margin
  2353. // is to the left of the first right-aligned button.
  2354. //
  2355. BOOL _GetNcCaptionMargins( IN HTHEME hTheme, IN const NCTHEMEMET& nctm, IN OUT NCWNDMET& ncwm )
  2356. {
  2357. ZeroMemory( &ncwm.CaptionMargins, sizeof(ncwm.CaptionMargins) );
  2358. if( ncwm.fFrame )
  2359. {
  2360. // assign per-window CaptinMargins, hfCaption values
  2361. if( ncwm.fSmallFrame )
  2362. {
  2363. ncwm.CaptionMargins = nctm.marSmCaptionText;
  2364. }
  2365. else
  2366. {
  2367. if( ncwm.fMaxed )
  2368. {
  2369. ncwm.CaptionMargins = nctm.marMaxCaptionText;
  2370. }
  2371. else if( ncwm.fMin )
  2372. {
  2373. ncwm.CaptionMargins = nctm.marMinCaptionText;
  2374. }
  2375. else
  2376. {
  2377. ncwm.CaptionMargins = nctm.marCaptionText;
  2378. }
  2379. }
  2380. ncwm.hfCaption = NcGetCaptionFont(ncwm.fSmallFrame);
  2381. RECT rcContainer = ncwm.rcS0[NCRC_CAPTION];
  2382. RECT *prcBtn = &ncwm.rcS0[NCBTNFIRST];
  2383. rcContainer.left += ncwm.cnBorders;
  2384. rcContainer.right -= ncwm.cnBorders;
  2385. // sysmenu icon, if present, is the leftmost limit
  2386. if( !IsRectEmpty( &ncwm.rcS0[NCRC_SYSBTN] ) )
  2387. {
  2388. rcContainer.left = ncwm.rcS0[NCRC_SYSBTN].right;
  2389. }
  2390. // Compute our rightmost limit
  2391. for( UINT cRects = NCBTNRECTS; cRects; --cRects, ++prcBtn )
  2392. {
  2393. if (!IsRectEmpty(prcBtn))
  2394. {
  2395. if( prcBtn->left < rcContainer.right )
  2396. {
  2397. rcContainer.right = prcBtn->left;
  2398. }
  2399. }
  2400. }
  2401. if( rcContainer.right < rcContainer.left )
  2402. {
  2403. rcContainer.right = rcContainer.left;
  2404. }
  2405. // final captions margins are adjusted to accommodate buttons.
  2406. ncwm.CaptionMargins.cxLeftWidth += (rcContainer.left - ncwm.rcS0[NCRC_CAPTION].left);
  2407. ncwm.CaptionMargins.cxRightWidth += (ncwm.rcS0[NCRC_CAPTION].right - rcContainer.right);
  2408. return TRUE;
  2409. }
  2410. return FALSE;
  2411. }
  2412. //-------------------------------------------------------------------------//
  2413. BOOL _GetNcCaptionTextSize( HTHEME hTheme, HWND hwnd, HFONT hf, OUT SIZE* psizeCaption )
  2414. {
  2415. BOOL fRet = FALSE;
  2416. LPWSTR pszCaption = _AllocWindowText( hwnd );
  2417. psizeCaption->cx = psizeCaption->cy = 0;
  2418. if( pszCaption )
  2419. {
  2420. HDC hdc = GetWindowDC(hwnd);
  2421. if( hdc )
  2422. {
  2423. //---- select font ----
  2424. HFONT hf0 = (HFONT)SelectObject(hdc, hf);
  2425. //---- let theme mgr do the calculation ----
  2426. RECT rcExtent;
  2427. HRESULT hr = GetThemeTextExtent( hTheme, hdc, WP_CAPTION, 0,
  2428. pszCaption, lstrlen(pszCaption), 0, NULL, &rcExtent );
  2429. //---- store result in "psizeCaption ----
  2430. if (SUCCEEDED(hr))
  2431. {
  2432. psizeCaption->cx = WIDTH(rcExtent);
  2433. psizeCaption->cy = HEIGHT(rcExtent);
  2434. }
  2435. //---- clean up ----
  2436. SelectObject(hdc, hf0);
  2437. ReleaseDC(hwnd, hdc);
  2438. }
  2439. SAFE_DELETE_ARRAY(pszCaption);
  2440. }
  2441. return fRet;
  2442. }
  2443. //-------------------------------------------------------------------------//
  2444. // Retrieves position of available area for caption text, in window-relative
  2445. // coordinates
  2446. BOOL _GetNcCaptionTextRect( IN OUT NCWNDMET* pncwm )
  2447. {
  2448. pncwm->rcS0[NCRC_CAPTIONTEXT] = pncwm->rcS0[NCRC_CAPTION];
  2449. // accommodate classic top sizing border:
  2450. pncwm->rcS0[NCRC_CAPTIONTEXT].top += pncwm->cnBorders;
  2451. // Assign left, right based on resp. caption margins
  2452. pncwm->rcS0[NCRC_CAPTIONTEXT].left += pncwm->CaptionMargins.cxLeftWidth;
  2453. pncwm->rcS0[NCRC_CAPTIONTEXT].right -= pncwm->CaptionMargins.cxRightWidth;
  2454. // vertically center the text between margins
  2455. int cyPadding = (RECTHEIGHT(&pncwm->rcS0[NCRC_CAPTIONTEXT]) - pncwm->sizeCaptionText.cy)/2;
  2456. pncwm->rcS0[NCRC_CAPTIONTEXT].top += cyPadding;
  2457. pncwm->rcS0[NCRC_CAPTIONTEXT].bottom -= cyPadding;
  2458. return TRUE;
  2459. }
  2460. //-------------------------------------------------------------------------//
  2461. // retrieve the window icon
  2462. HICON CThemeWnd::AcquireFrameIcon(
  2463. DWORD dwStyle, DWORD dwExStyle, BOOL fWinIniChange )
  2464. {
  2465. if( _hAppIcon != NULL )
  2466. {
  2467. if( fWinIniChange )
  2468. {
  2469. _hAppIcon = NULL;
  2470. }
  2471. }
  2472. if( !TESTFLAG(dwStyle, WS_SYSMENU) || TESTFLAG(dwExStyle, WS_EX_TOOLWINDOW) )
  2473. {
  2474. // return nil value without throwing away cached icon handle;
  2475. // this may be a transient style change.
  2476. return NULL;
  2477. }
  2478. NONCLIENTMETRICS ncm = {0};
  2479. NcGetNonclientMetrics( &ncm, FALSE );
  2480. BOOL fPerferLargeIcon = ((30 < ncm.iCaptionHeight) ? TRUE : FALSE);
  2481. if( NULL == _hAppIcon && NULL == (_hAppIcon = _GetWindowIcon(_hwnd, fPerferLargeIcon)) )
  2482. {
  2483. if ( HAS_CAPTIONBAR(dwStyle) &&
  2484. ((dwStyle & (WS_BORDER|WS_DLGFRAME)) != WS_DLGFRAME) &&
  2485. !TESTFLAG(dwExStyle, WS_EX_DLGMODALFRAME) )
  2486. {
  2487. // If we still can't get an icon and the window has
  2488. // SYSMENU set, then they get the default winlogo icon
  2489. _hAppIcon = LoadIcon(NULL, IDI_WINLOGO);
  2490. }
  2491. }
  2492. return _hAppIcon;
  2493. }
  2494. //-------------------------------------------------------------------------//
  2495. // CThemeWnd::ScreenToWindow() - transforms points from screen coords to
  2496. // window coords.
  2497. //
  2498. void CThemeWnd::ScreenToWindow( LPPOINT prgPts, UINT cPts )
  2499. {
  2500. RECT rcWnd;
  2501. if( GetWindowRect( _hwnd, &rcWnd ) )
  2502. {
  2503. for( UINT i = 0; i < cPts; i++ )
  2504. {
  2505. prgPts[i].x -= rcWnd.left;
  2506. prgPts[i].y -= rcWnd.top;
  2507. }
  2508. }
  2509. }
  2510. //-------------------------------------------------------------------------//
  2511. // CThemeWnd::ScreenToWindow() - transforms non-empty rectangles from
  2512. // screen coords to window coords.
  2513. //
  2514. void CThemeWnd::ScreenToWindowRect( LPRECT prc )
  2515. {
  2516. if( !IsRectEmpty(prc) )
  2517. ScreenToWindow( (LPPOINT)prc, 2 );
  2518. }
  2519. //-------------------------------------------------------------------------//
  2520. // CThemeWnd::InitWindowMetrics()
  2521. //
  2522. // initializes theme resources
  2523. void CThemeWnd::InitWindowMetrics()
  2524. {
  2525. ZeroMemory( &_ncwm, sizeof(_ncwm) );
  2526. }
  2527. //-------------------------------------------------------------------------//
  2528. BOOL _fClassicNcBtnMetricsReset = TRUE;
  2529. //-------------------------------------------------------------------------//
  2530. // computes classic button position
  2531. BOOL _GetNcBtnMetrics(
  2532. IN OUT NCWNDMET* pncwm,
  2533. IN const NCTHEMEMET* pnctm,
  2534. IN HICON hAppIcon,
  2535. IN OPTIONAL BOOL fCanClose )
  2536. {
  2537. BOOL fRet = TRUE;
  2538. if( pncwm && pncwm->fFrame && TESTFLAG(pncwm->dwStyle, WS_SYSMENU) )
  2539. {
  2540. NONCLIENTMETRICS ncm;
  2541. fRet = NcGetNonclientMetrics( &ncm, FALSE );
  2542. if( fRet )
  2543. {
  2544. // (1) compute baseline rectangles
  2545. int cxEdge = NcGetSystemMetrics( SM_CXEDGE );
  2546. int cyEdge = NcGetSystemMetrics( SM_CYEDGE );
  2547. int cyBtn = NcGetSystemMetrics( SM_CYSIZE );
  2548. int cxBtn = MulDiv( cyBtn, pnctm->sizeBtn.cx, pnctm->sizeBtn.cy );
  2549. int cySmBtn = NcGetSystemMetrics( SM_CYSMSIZE );
  2550. int cxSmBtn = MulDiv( cySmBtn, pnctm->sizeSmBtn.cx, pnctm->sizeSmBtn.cy );
  2551. // remove padding from x,y
  2552. cyBtn -= (cyEdge * 2);
  2553. cxBtn -= (cyEdge * 2);
  2554. cySmBtn -= (cyEdge * 2);
  2555. cxSmBtn -= (cyEdge * 2);
  2556. RECT rcClose, rcMin, rcMax, rcHelp, rcSys, rcSmClose;
  2557. // common top, w/ zero v-offset
  2558. rcClose.top = rcMin.top = rcMax.top = rcHelp.top = rcSys.top = rcSmClose.top = 0;
  2559. // common bottom, w/ zero v-offset
  2560. rcClose.bottom = rcMin.bottom = rcMax.bottom = rcHelp.bottom =
  2561. max( rcClose.top, rcClose.top + cyBtn );
  2562. rcSmClose.bottom =
  2563. max( rcSmClose.top, cySmBtn );
  2564. // sysmenu icon bottom
  2565. rcSys.bottom = rcSys.top + NcGetSystemMetrics(SM_CYSMICON);
  2566. // close, min, max left, right (as offsets from container's right boundary)
  2567. rcClose.right = -cxEdge;
  2568. rcClose.left = rcClose.right - cxBtn;
  2569. rcMax.right = rcClose.left - cxEdge;
  2570. rcMax.left = rcMax.right - cxBtn;
  2571. rcHelp = rcMax;
  2572. rcMin.right = rcMax.left - cxEdge;
  2573. rcMin.left = rcMin.right - cxBtn;
  2574. // appicon left, right (as offsets from container's left boundary)
  2575. rcSys.left = cxEdge;
  2576. rcSys.right = rcSys.left + NcGetSystemMetrics(SM_CXSMICON);
  2577. // toolwindow close, left, right
  2578. rcSmClose.right = -cxEdge;
  2579. rcSmClose.left = rcSmClose.right - cxSmBtn;
  2580. const RECT* prcBox = &pncwm->rcS0[NCRC_CAPTION];
  2581. int cnLOffset = prcBox->left + pncwm->cnBorders;
  2582. int cnROffset = prcBox->right - pncwm->cnBorders;
  2583. int cnCtrOffset = pncwm->cnBorders + prcBox->top +
  2584. (pncwm->fSmallFrame ? (ncm.iCaptionHeight - RECTHEIGHT(&rcClose))/2 :
  2585. (ncm.iSmCaptionHeight - RECTHEIGHT(&rcSmClose))/2);
  2586. // (2) assign outbound rectangles.
  2587. // vertically center w/ respect to classic caption area,
  2588. // horizontally position w/ respect to respective container boundary.
  2589. // close button
  2590. pncwm->rcS0[NCRC_CLOSEBTN] = pncwm->fSmallFrame ? rcSmClose : rcClose;
  2591. OffsetRect( &pncwm->rcS0[NCRC_CLOSEBTN], cnROffset, cnCtrOffset );
  2592. pncwm->rawCloseBtnState = fCanClose ? CBS_NORMAL : CBS_DISABLED;
  2593. // (1) min/max/help/appicons not displayed for toolwindows
  2594. // (2) min/max btns mutually exclusive w/ context help btn
  2595. if( !TESTFLAG(pncwm->dwExStyle, WS_EX_TOOLWINDOW) )
  2596. {
  2597. // min, max
  2598. if( TESTFLAG(pncwm->dwStyle, WS_MINIMIZEBOX|WS_MAXIMIZEBOX) )
  2599. {
  2600. pncwm->rcS0[NCRC_MINBTN] = rcMin;
  2601. OffsetRect( &pncwm->rcS0[NCRC_MINBTN], cnROffset, cnCtrOffset );
  2602. pncwm->rcS0[NCRC_MAXBTN] = rcMax;
  2603. OffsetRect( &pncwm->rcS0[NCRC_MAXBTN], cnROffset, cnCtrOffset );
  2604. pncwm->iMaxButtonPart = pncwm->fMaxed ? WP_RESTOREBUTTON : WP_MAXBUTTON;
  2605. pncwm->iMinButtonPart = pncwm->fMin ? WP_RESTOREBUTTON : WP_MINBUTTON;
  2606. pncwm->rawMaxBtnState = TESTFLAG(pncwm->dwStyle, WS_MAXIMIZEBOX) ? CBS_NORMAL : CBS_DISABLED;
  2607. pncwm->rawMinBtnState = TESTFLAG(pncwm->dwStyle, WS_MINIMIZEBOX) ? CBS_NORMAL : CBS_DISABLED;
  2608. }
  2609. // help btn
  2610. else if( TESTFLAG(pncwm->dwExStyle, WS_EX_CONTEXTHELP) )
  2611. {
  2612. pncwm->rcS0[NCRC_HELPBTN] = rcHelp;
  2613. OffsetRect( &pncwm->rcS0[NCRC_HELPBTN], cnROffset, cnCtrOffset );
  2614. }
  2615. if( hAppIcon )
  2616. {
  2617. // sysmenu icon
  2618. pncwm->rcS0[NCRC_SYSBTN] = rcSys;
  2619. OffsetRect( &pncwm->rcS0[NCRC_SYSBTN], cnLOffset,
  2620. pncwm->cnBorders + prcBox->top + (ncm.iCaptionHeight - RECTHEIGHT(&rcSys))/2 );
  2621. }
  2622. }
  2623. }
  2624. }
  2625. return fRet;
  2626. }
  2627. //-------------------------------------------------------------------------//
  2628. // computes classic nonclient button position
  2629. #if 0 // (keeping around for documentation purposes - scotthan)
  2630. BOOL _GetClassicNcBtnMetrics(
  2631. IN OPTIONAL NCWNDMET* pncwm,
  2632. IN HICON hAppIcon,
  2633. IN OPTIONAL BOOL fCanClose,
  2634. BOOL fRefresh )
  2635. {
  2636. static int cxEdge, cyEdge;
  2637. static int cxBtn, cyBtn, cxSmBtn, cySmBtn;
  2638. static RECT rcClose, rcMin, rcMax, rcHelp, rcSys;
  2639. static RECT rcSmClose;
  2640. static BOOL fInit = FALSE;
  2641. if( _fClassicNcBtnMetricsReset || fRefresh )
  2642. {
  2643. cxBtn = NcGetSystemMetrics( SM_CXSIZE );
  2644. cyBtn = NcGetSystemMetrics( SM_CYSIZE );
  2645. cxSmBtn = NcGetSystemMetrics( SM_CXSMSIZE );
  2646. cySmBtn = NcGetSystemMetrics( SM_CYSMSIZE );
  2647. cxEdge = NcGetSystemMetrics( SM_CXEDGE );
  2648. cyEdge = NcGetSystemMetrics( SM_CYEDGE );
  2649. // common top, w/ zero v-offset
  2650. rcClose.top = rcMin.top = rcMax.top = rcHelp.top = rcSys.top = rcSmClose.top = 0;
  2651. // common bottom, w/ zero v-offset
  2652. rcClose.bottom = rcMin.bottom = rcMax.bottom = rcHelp.bottom = rcClose.top + (cyBtn - (cyEdge * 2));
  2653. rcSmClose.bottom= (cySmBtn - (cyEdge * 2));
  2654. // sysmenu icon bottom
  2655. rcSys.bottom = rcSys.top + NcGetSystemMetrics(SM_CYSMICON);
  2656. // close, min, max left, right (as offsets from container's right boundary)
  2657. rcClose.right = -cxEdge;
  2658. rcClose.left = rcClose.right - (cxBtn - cxEdge);
  2659. rcMax.right = rcClose.left - cxEdge;
  2660. rcMax.left = rcMax.right - (cxBtn - cxEdge);
  2661. rcHelp = rcMax;
  2662. rcMin.right = rcMax.left;
  2663. rcMin.left = rcMin.right - (cxBtn - cxEdge);
  2664. // appicon left, right (as offsets from container's left boundary)
  2665. rcSys.left = cxEdge;
  2666. rcSys.right = rcSys.left + NcGetSystemMetrics(SM_CXSMICON);
  2667. // toolwindow close, left, right
  2668. rcSmClose.right = -cxEdge;
  2669. rcSmClose.left = rcSmClose.right - (cxSmBtn - cxEdge);
  2670. _fClassicNcBtnMetricsReset = FALSE;
  2671. }
  2672. if( !_fClassicNcBtnMetricsReset &&
  2673. pncwm && pncwm->fFrame && TESTFLAG(pncwm->dwStyle, WS_SYSMENU) )
  2674. {
  2675. NONCLIENTMETRICS ncm;
  2676. if( NcGetNonclientMetrics( &ncm, FALSE ) )
  2677. {
  2678. const RECT* prcBox = &pncwm->rcS0[NCRC_CAPTION];
  2679. int cnLOffset = prcBox->left + pncwm->cnBorders;
  2680. int cnROffset = prcBox->right - pncwm->cnBorders;
  2681. int cnCtrOffset = pncwm->cnBorders + prcBox->top +
  2682. (pncwm->fSmallFrame ? (ncm.iCaptionHeight - RECTHEIGHT(&rcClose))/2 :
  2683. (ncm.iSmCaptionHeight - RECTHEIGHT(&rcSmClose))/2);
  2684. // assign outbound rectangles.
  2685. // vertically center w/ respect to classic caption area,
  2686. // horizontally position w/ respect to respective container boundary.
  2687. // close button
  2688. pncwm->rcS0[NCRC_CLOSEBTN] = pncwm->fSmallFrame ? rcSmClose : rcClose;
  2689. OffsetRect( &pncwm->rcS0[NCRC_CLOSEBTN], cnROffset, cnCtrOffset );
  2690. pncwm->rawCloseBtnState = fCanClose ? CBS_NORMAL : CBS_DISABLED;
  2691. // (1) min/max/help/appicons not displayed for toolwindows
  2692. // (2) min/max btns mutually exclusive w/ context help btn
  2693. if( !TESTFLAG(pncwm->dwExStyle, WS_EX_TOOLWINDOW) )
  2694. {
  2695. // min, max
  2696. if( TESTFLAG(pncwm->dwStyle, WS_MINIMIZEBOX|WS_MAXIMIZEBOX) )
  2697. {
  2698. pncwm->rcS0[NCRC_MINBTN] = rcMin;
  2699. OffsetRect( &pncwm->rcS0[NCRC_MINBTN], cnROffset, cnCtrOffset );
  2700. pncwm->rcS0[NCRC_MAXBTN] = rcMax;
  2701. OffsetRect( &pncwm->rcS0[NCRC_MAXBTN], cnROffset, cnCtrOffset );
  2702. pncwm->iMaxButtonPart = pncwm->fMaxed ? WP_RESTOREBUTTON : WP_MAXBUTTON;
  2703. pncwm->iMinButtonPart = pncwm->fMin ? WP_RESTOREBUTTON : WP_MINBUTTON;
  2704. pncwm->rawMaxBtnState = TESTFLAG(pncwm->dwStyle, WS_MAXIMIZEBOX) ? CBS_NORMAL : CBS_DISABLED;
  2705. pncwm->rawMinBtnState = TESTFLAG(pncwm->dwStyle, WS_MINIMIZEBOX) ? CBS_NORMAL : CBS_DISABLED;
  2706. }
  2707. // help btn
  2708. else if( TESTFLAG(pncwm->dwExStyle, WS_EX_CONTEXTHELP) )
  2709. {
  2710. pncwm->rcS0[NCRC_HELPBTN] = rcHelp;
  2711. OffsetRect( &pncwm->rcS0[NCRC_HELPBTN], cnROffset, cnCtrOffset );
  2712. }
  2713. if( hAppIcon )
  2714. {
  2715. // sysmenu icon
  2716. pncwm->rcS0[NCRC_SYSBTN] = rcSys;
  2717. OffsetRect( &pncwm->rcS0[NCRC_SYSBTN], cnLOffset,
  2718. pncwm->cnBorders + prcBox->top + (ncm.iCaptionHeight - RECTHEIGHT(&rcSys))/2 );
  2719. }
  2720. }
  2721. return TRUE;
  2722. }
  2723. return FALSE;
  2724. }
  2725. return fInit;
  2726. }
  2727. #endif 0 // (keeping around for documentation purposes - scotthan)
  2728. //-------------------------------------------------------------------------//
  2729. // CThemeWnd::NcBackgroundHitTest() - hit test the Caption or Frame part
  2730. //
  2731. WORD CThemeWnd::NcBackgroundHitTest(
  2732. POINT ptHit, LPCRECT prcWnd,
  2733. DWORD dwStyle, DWORD dwExStyle,
  2734. FRAMESTATES fs,
  2735. const WINDOWPARTS rgiParts[],
  2736. const WINDOWPARTS rgiTemplates[],
  2737. const RECT rgrcParts[] )
  2738. {
  2739. WORD hitcode = HTNOWHERE;
  2740. HRESULT hr = E_FAIL;
  2741. eFRAMEPARTS iPartHit = (eFRAMEPARTS)-1;
  2742. // do a standard rect hit test:
  2743. for( int i = 0; i < cFRAMEPARTS; i++ )
  2744. {
  2745. if( _StrictPtInRect(&rgrcParts[i], ptHit) )
  2746. {
  2747. iPartHit = (eFRAMEPARTS)i;
  2748. break;
  2749. }
  2750. }
  2751. if( iPartHit >= 0 )
  2752. {
  2753. BOOL fResizing = TESTFLAG(dwStyle, WS_THICKFRAME);
  2754. DWORD dwHTFlags = fResizing ? HTTB_RESIZINGBORDER : HTTB_FIXEDBORDER;
  2755. RECT rcHit = rgrcParts[iPartHit];
  2756. switch( iPartHit )
  2757. {
  2758. case iCAPTION:
  2759. // Ensure caption rect and test point are zero-relative to
  2760. // the correct origin (if we have a window region,
  2761. // this would be window origin, otherwise, it's the part origin.)
  2762. if( _hrgnWnd != NULL )
  2763. rcHit = *prcWnd;
  2764. if( fResizing )
  2765. dwHTFlags &= ~HTTB_RESIZINGBORDER_BOTTOM;
  2766. break;
  2767. case iFRAMEBOTTOM:
  2768. if( fResizing )
  2769. dwHTFlags &= ~HTTB_RESIZINGBORDER_TOP;
  2770. break;
  2771. case iFRAMELEFT:
  2772. if( fResizing )
  2773. dwHTFlags = HTTB_RESIZINGBORDER_LEFT;
  2774. break;
  2775. case iFRAMERIGHT:
  2776. if( fResizing )
  2777. dwHTFlags = HTTB_RESIZINGBORDER_RIGHT;
  2778. break;
  2779. }
  2780. ptHit.x -= prcWnd->left;
  2781. ptHit.y -= prcWnd->top;
  2782. OffsetRect( &rcHit, -prcWnd->left, -prcWnd->top );
  2783. // Here our assumption is that the hit testing for the template
  2784. // is "as good" or "better" than the rectangles checking applied
  2785. // to the caption part. So we do one or the other. There are
  2786. // situations where you would need to do both (if the template
  2787. // were outside the window region and you were able to get USER to
  2788. // send you NcHitTest messages for it). For those situations
  2789. // you would need to call both so that you can distinguish between
  2790. // a mouse hit over the caption "client" area vs. over the
  2791. // outside-transparent area.
  2792. if( VALID_WINDOWPART(rgiTemplates[iPartHit]) )
  2793. {
  2794. hr = HitTestThemeBackground( _hTheme, NULL, rgiTemplates[iPartHit], fs,
  2795. dwHTFlags | (fResizing ? HTTB_SIZINGTEMPLATE : 0),
  2796. &rcHit, _rghrgnSizingTemplates[iPartHit], ptHit, &hitcode );
  2797. }
  2798. else
  2799. {
  2800. hr = HitTestThemeBackground( _hTheme, NULL, rgiParts[iPartHit], fs,
  2801. dwHTFlags | (fResizing ? HTTB_SYSTEMSIZINGMARGINS : 0),
  2802. &rcHit, _hrgnWnd, ptHit, &hitcode );
  2803. }
  2804. if( SUCCEEDED(hr) )
  2805. {
  2806. if( iCAPTION == iPartHit && (HTCLIENT == hitcode || HTBORDER == hitcode) )
  2807. hitcode = HTCAPTION;
  2808. }
  2809. }
  2810. if ( FAILED(hr) )
  2811. {
  2812. hitcode = HTNOWHERE;
  2813. }
  2814. return hitcode;
  2815. }
  2816. //-------------------------------------------------------------------------//
  2817. // CThemeWnd::TrackFrameButton() - track the mouse over the caption buttons,
  2818. // pressing/releasing as appropriate. Return back SC_* command to report or 0
  2819. // if the mouse was released off of the button.
  2820. //
  2821. BOOL CThemeWnd::TrackFrameButton(
  2822. HWND hwnd,
  2823. INT iHitCode,
  2824. OUT OPTIONAL WPARAM* puSysCmd,
  2825. BOOL fHottrack )
  2826. {
  2827. int iStateId, iNewStateId;
  2828. int iPartId = -1;
  2829. UINT cmd = 0;
  2830. MSG msg = {0};
  2831. LPRECT prcBtnPaint = NULL;
  2832. RECT rcBtnTrack;
  2833. HDC hdc;
  2834. if (puSysCmd)
  2835. {
  2836. *puSysCmd = 0;
  2837. }
  2838. // map iHitCode to the correct part number
  2839. switch (iHitCode)
  2840. {
  2841. case HTHELP:
  2842. cmd = SC_CONTEXTHELP;
  2843. iPartId = WP_HELPBUTTON;
  2844. prcBtnPaint = &_ncwm.rcW0[NCRC_HELPBTN];
  2845. break;
  2846. case HTCLOSE:
  2847. cmd = SC_CLOSE;
  2848. iPartId = _ncwm.fSmallFrame ? WP_SMALLCLOSEBUTTON : WP_CLOSEBUTTON;
  2849. prcBtnPaint = &_ncwm.rcW0[NCRC_CLOSEBTN];
  2850. break;
  2851. case HTMINBUTTON:
  2852. cmd = _ncwm.fMin ? SC_RESTORE : SC_MINIMIZE;
  2853. iPartId = _ncwm.iMinButtonPart;
  2854. prcBtnPaint = &_ncwm.rcW0[NCRC_MINBTN];
  2855. break;
  2856. case HTMAXBUTTON:
  2857. cmd = _ncwm.fMaxed ? SC_RESTORE : SC_MAXIMIZE;
  2858. iPartId = _ncwm.iMaxButtonPart;
  2859. prcBtnPaint = &_ncwm.rcW0[NCRC_MAXBTN];
  2860. break;
  2861. case HTSYSMENU:
  2862. if (puSysCmd)
  2863. {
  2864. *puSysCmd = SC_MOUSEMENU | iHitCode;
  2865. }
  2866. return TRUE;
  2867. }
  2868. // If we didn't recognize the hit code there's nothing to track
  2869. if (iPartId >= 0 )
  2870. {
  2871. // Get the window DC, in window coords
  2872. hdc = _GetNonclientDC(_hwnd, NULL);
  2873. if ( hdc )
  2874. {
  2875. // Don't paint in the window's content area, clip to the content area
  2876. ExcludeClipRect( hdc, _ncwm.rcW0[NCRC_CONTENT].left,
  2877. _ncwm.rcW0[NCRC_CONTENT].top,
  2878. _ncwm.rcW0[NCRC_CONTENT].right,
  2879. _ncwm.rcW0[NCRC_CONTENT].bottom );
  2880. // Calculate the tracking rect. We track a larger button rect when maximized
  2881. // but paint into the normal sized rect.
  2882. rcBtnTrack = *prcBtnPaint;
  2883. _GetNcBtnHitTestRect( &_ncwm, iHitCode, TRUE, &rcBtnTrack );
  2884. // when tracking MDI child window frame buttons, clip to their
  2885. // parent rect.
  2886. if ( TESTFLAG(GetWindowLong(hwnd, GWL_EXSTYLE), WS_EX_MDICHILD) )
  2887. {
  2888. RECT rcMDIClient;
  2889. GetWindowRect(GetParent(hwnd), &rcMDIClient);
  2890. ScreenToWindowRect(&rcMDIClient);
  2891. InflateRect(&rcMDIClient, -NcGetSystemMetrics(SM_CXEDGE), -NcGetSystemMetrics(SM_CYEDGE));
  2892. IntersectClipRect(hdc, rcMDIClient.left, rcMDIClient.top, rcMDIClient.right, rcMDIClient.bottom);
  2893. }
  2894. if (fHottrack)
  2895. {
  2896. // draw the button hot if the mouse is over it
  2897. iStateId = (iHitCode == _htHot) ? SBS_HOT : CBS_NORMAL;
  2898. }
  2899. else
  2900. {
  2901. // draw the button depressed
  2902. iStateId = SBS_PUSHED;
  2903. }
  2904. iStateId = MAKE_BTNSTATE(_ncwm.framestate, iStateId);
  2905. NcDrawThemeBackground(_hTheme, hdc, iPartId, iStateId, prcBtnPaint, 0);
  2906. // TODO NotifyWinEvent(EVENT_OBJECT_STATECHANGE, pwnd, OBJID_TITLEBAR, iButton, 0);
  2907. if (!fHottrack)
  2908. {
  2909. BOOL fTrack, fMouseUp = FALSE;
  2910. SetCapture(hwnd); // take mouse capture
  2911. do // mouse button tracking loop
  2912. {
  2913. fTrack = FALSE;
  2914. // Let's go to sleep, to be awakened only on a mouse message placed in our
  2915. // thread's queue.
  2916. switch (MsgWaitForMultipleObjectsEx(0, NULL, INFINITE /*why consume CPU processing a timeout when we don't have to?*/,
  2917. QS_MOUSE, MWMO_INPUTAVAILABLE))
  2918. {
  2919. case WAIT_OBJECT_0: // a mouse message or important system event has been queued
  2920. if (PeekMessage(&msg, NULL, WM_MOUSEFIRST, WM_MOUSELAST, PM_REMOVE))
  2921. {
  2922. // PeekMessage returns a point in screen relative coords. Mirror the
  2923. // point it this is a RTL window. Translate the point to window coords.
  2924. if ( TESTFLAG(_ncwm.dwExStyle, WS_EX_LAYOUTRTL) )
  2925. {
  2926. // mirror the point to hittest correctly
  2927. MIRROR_POINT(_ncwm.rcS0[NCRC_WINDOW], msg.pt);
  2928. }
  2929. ScreenToWindow( &msg.pt, 1 );
  2930. if (msg.message == WM_LBUTTONUP)
  2931. {
  2932. ReleaseCapture();
  2933. fMouseUp = TRUE;
  2934. }
  2935. else if ((msg.message == WM_MOUSEMOVE) && cmd)
  2936. {
  2937. iNewStateId = MAKE_BTNSTATE(_ncwm.framestate, PtInRect(&rcBtnTrack, msg.pt) ? SBS_PUSHED : SBS_NORMAL);
  2938. if (iStateId != iNewStateId)
  2939. {
  2940. iStateId = iNewStateId;
  2941. NcDrawThemeBackground(_hTheme, hdc, iPartId, iStateId, prcBtnPaint, 0);
  2942. // TODO NotifyWinEvent(EVENT_OBJECT_STATECHANGE, pwnd, OBJID_TITLEBAR, iButton, 0);
  2943. }
  2944. fTrack = TRUE;
  2945. }
  2946. }
  2947. else
  2948. {
  2949. // Check loss of capture. This can happen if we loose activation
  2950. // via alt-tab and may not have received a WM_CAPTURECHANGED message
  2951. if (GetCapture() != hwnd)
  2952. {
  2953. break;
  2954. }
  2955. }
  2956. // Dequeue CAPTURECHANGED
  2957. if (PeekMessage(&msg, NULL, WM_CAPTURECHANGED, WM_CAPTURECHANGED, PM_REMOVE) ||
  2958. fMouseUp)
  2959. {
  2960. break;
  2961. }
  2962. fTrack = TRUE; // go back to sleep until the next mouse event
  2963. break;
  2964. default:
  2965. break;
  2966. }
  2967. } while (fTrack);
  2968. // draw button in normal state if it is not in that state already
  2969. iNewStateId = MAKE_BTNSTATE(_ncwm.framestate, CBS_NORMAL);
  2970. if (iStateId != iNewStateId)
  2971. {
  2972. NcDrawThemeBackground(_hTheme, hdc, iPartId, iNewStateId, prcBtnPaint, 0);
  2973. }
  2974. // if we did not end up on a button return 0
  2975. if( puSysCmd && (*puSysCmd = cmd) != 0 )
  2976. {
  2977. // TODO NotifyWinEvent(EVENT_OBJECT_STATECHANGE, pwnd, OBJID_TITLEBAR, iButton, 0);
  2978. // If mouse wasn't released over the button, cancel the command.
  2979. if( !(fMouseUp && PtInRect(&rcBtnTrack, msg.pt)) )
  2980. *puSysCmd = 0;
  2981. }
  2982. }
  2983. // Done with DC now
  2984. ReleaseDC(_hwnd, hdc);
  2985. }
  2986. }
  2987. return TRUE;
  2988. }
  2989. //-------------------------------------------------------------------------//
  2990. DWORD GetTextAlignFlags(HTHEME hTheme, IN NCWNDMET* pncwm, BOOL fReverse)
  2991. {
  2992. CONTENTALIGNMENT contentAlignment = CA_LEFT;
  2993. DWORD dwAlignFlags = 0;
  2994. //---- compute text alignment ----
  2995. GetThemeInt(hTheme, pncwm->rgframeparts[iCAPTION], pncwm->framestate, TMT_CONTENTALIGNMENT,
  2996. (int *)&contentAlignment);
  2997. if (fReverse)
  2998. {
  2999. //---- reverse alignment ----
  3000. switch(contentAlignment)
  3001. {
  3002. default:
  3003. case CA_LEFT: dwAlignFlags |= DT_RIGHT; break;
  3004. case CA_CENTER: dwAlignFlags |= DT_CENTER; break;
  3005. case CA_RIGHT: dwAlignFlags |= DT_LEFT; break;
  3006. }
  3007. }
  3008. else
  3009. {
  3010. //---- normal alignment ----
  3011. switch(contentAlignment)
  3012. {
  3013. default:
  3014. case CA_LEFT: dwAlignFlags |= DT_LEFT; break;
  3015. case CA_CENTER: dwAlignFlags |= DT_CENTER; break;
  3016. case CA_RIGHT: dwAlignFlags |= DT_RIGHT; break;
  3017. }
  3018. }
  3019. return dwAlignFlags;
  3020. }
  3021. //-------------------------------------------------------------------------//
  3022. void _BorderRect( HDC hdc, COLORREF rgb, LPCRECT prc, int cxBorder, int cyBorder )
  3023. {
  3024. COLORREF rgbSave = SetBkColor( hdc, rgb );
  3025. RECT rc = *prc;
  3026. // bottom border
  3027. rc = *prc; rc.top = prc->bottom - cyBorder;
  3028. ExtTextOut( hdc, rc.left, rc.top, ETO_OPAQUE, &rc, NULL, 0, NULL );
  3029. // right border
  3030. rc = *prc; rc.left = prc->right - cxBorder;
  3031. ExtTextOut( hdc, rc.left, rc.top, ETO_OPAQUE, &rc, NULL, 0, NULL );
  3032. // left border
  3033. rc = *prc; rc.right = prc->left + cxBorder;
  3034. ExtTextOut( hdc, rc.left, rc.top, ETO_OPAQUE, &rc, NULL, 0, NULL );
  3035. // top border
  3036. rc = *prc; rc.bottom = prc->top + cyBorder;
  3037. ExtTextOut( hdc, rc.left, rc.top, ETO_OPAQUE, &rc, NULL, 0, NULL );
  3038. SetBkColor( hdc, rgbSave );
  3039. }
  3040. //-------------------------------------------------------------------------//
  3041. void _DrawWindowEdges( HDC hdc, NCWNDMET* pncwm, BOOL fIsFrame )
  3042. {
  3043. // non-frame window edge & border
  3044. if( !fIsFrame )
  3045. {
  3046. RECT rcWnd = pncwm->rcW0[NCRC_WINDOW];
  3047. int cxBorder = NcGetSystemMetrics(SM_CXBORDER),
  3048. cyBorder = NcGetSystemMetrics(SM_CYBORDER);
  3049. // static, window edge
  3050. if( TESTFLAG(pncwm->dwExStyle, WS_EX_WINDOWEDGE) )
  3051. {
  3052. RECT rcClip = rcWnd;
  3053. InflateRect( &rcClip, -pncwm->cnBorders, -pncwm->cnBorders );
  3054. ExcludeClipRect( hdc, rcClip.left, rcClip.top, rcClip.right, rcClip.bottom );
  3055. DrawEdge( hdc, &rcWnd, EDGE_RAISED, BF_RECT | BF_ADJUST | BF_MIDDLE);
  3056. SelectClipRgn( hdc, NULL );
  3057. }
  3058. else if( TESTFLAG(pncwm->dwExStyle, WS_EX_STATICEDGE) )
  3059. {
  3060. DrawEdge( hdc, &rcWnd, BDR_SUNKENOUTER, BF_RECT | BF_ADJUST );
  3061. }
  3062. // Normal border
  3063. else if( TESTFLAG(pncwm->dwStyle, WS_BORDER) )
  3064. {
  3065. _BorderRect( hdc, GetSysColor( COLOR_WINDOWFRAME),
  3066. &rcWnd, cxBorder, cyBorder );
  3067. }
  3068. }
  3069. // client edge
  3070. if( TESTFLAG(pncwm->dwExStyle, WS_EX_CLIENTEDGE) )
  3071. {
  3072. #ifdef _TEST_CLIENTEDGE_
  3073. HBRUSH hbr = CreateSolidBrush( RGB(255,0,255) );
  3074. FillRect(hdc, &ncwm.rcW0[NCRC_CLIENTEDGE], hbr);
  3075. DeleteObject(hbr);
  3076. #else _TEST_CLIENTEDGE_
  3077. DrawEdge( hdc, &pncwm->rcW0[NCRC_CLIENTEDGE], EDGE_SUNKEN, BF_RECT | BF_ADJUST);
  3078. #endif _TEST_CLIENTEDGE_
  3079. }
  3080. }
  3081. //-------------------------------------------------------------------------//
  3082. void CThemeWnd::NcPaintCaption(
  3083. IN HDC hdcOut,
  3084. IN NCWNDMET* pncwm,
  3085. IN BOOL fBuffered,
  3086. IN DWORD dwCaptionFlags, // draw caption flags (DC_xxx, winuser.h)
  3087. IN DTBGOPTS* pdtbopts )
  3088. {
  3089. ASSERT(hdcOut);
  3090. ASSERT(pncwm);
  3091. ASSERT(pncwm->fFrame);
  3092. ASSERT(HAS_CAPTIONBAR(pncwm->dwStyle));
  3093. DWORD dwOldAlign = 0;
  3094. // caption text implies caption background
  3095. if( TESTFLAG( dwCaptionFlags, DC_TEXT|DC_ICON ) || 0 == dwCaptionFlags )
  3096. {
  3097. dwCaptionFlags = DC_ENTIRECAPTION;
  3098. }
  3099. if( dwCaptionFlags != DC_ENTIRECAPTION
  3100. #if defined(DEBUG) && defined(DEBUG_NCPAINT)
  3101. || TESTFLAG( _NcTraceFlags, NCTF_NCPAINT )
  3102. #endif DEBUG
  3103. )
  3104. {
  3105. fBuffered = FALSE;
  3106. }
  3107. // create caption double buffer
  3108. HBITMAP hbmBuf = fBuffered ? CreateCompatibleBitmap(hdcOut, RECTWIDTH(&pncwm->rcW0[NCRC_CAPTION]),
  3109. RECTHEIGHT(&pncwm->rcW0[NCRC_CAPTION])) :
  3110. NULL;
  3111. if( !fBuffered || hbmBuf )
  3112. {
  3113. HDC hdc = fBuffered ? CreateCompatibleDC(hdcOut) : hdcOut;
  3114. if( hdc )
  3115. {
  3116. //--- DO NOT EXIT FROM WITHIN THIS CONDITIONAL ---//
  3117. EnterNcThemePaint();
  3118. HBITMAP hbm0 = fBuffered ? (HBITMAP)SelectObject(hdc, hbmBuf) : NULL;
  3119. if( TESTFLAG( dwCaptionFlags, DC_BACKGROUND ) )
  3120. {
  3121. // Draw caption background
  3122. RECT rcBkgnd = pncwm->rcW0[NCRC_CAPTION];
  3123. if( pncwm->fFullMaxed )
  3124. {
  3125. rcBkgnd.top += pncwm->cnBorders;
  3126. rcBkgnd.left += pncwm->cnBorders;
  3127. rcBkgnd.right -= pncwm->cnBorders;
  3128. }
  3129. NcDrawThemeBackgroundEx( _hTheme, hdc, pncwm->rgframeparts[iCAPTION], pncwm->framestate,
  3130. &rcBkgnd, pdtbopts );
  3131. }
  3132. if( TESTFLAG( dwCaptionFlags, DC_BUTTONS ) )
  3133. {
  3134. // Draw standard caption buttons
  3135. if (!IsRectEmpty(&pncwm->rcW0[NCRC_CLOSEBTN]))
  3136. {
  3137. NcDrawThemeBackground( _hTheme, hdc, pncwm->fSmallFrame ? WP_SMALLCLOSEBUTTON : WP_CLOSEBUTTON,
  3138. MAKE_BTNSTATE(pncwm->framestate, pncwm->rawCloseBtnState),
  3139. &pncwm->rcW0[NCRC_CLOSEBTN], 0);
  3140. }
  3141. if (!IsRectEmpty(&pncwm->rcW0[NCRC_MAXBTN]))
  3142. {
  3143. NcDrawThemeBackground(_hTheme, hdc, pncwm->iMaxButtonPart,
  3144. MAKE_BTNSTATE(pncwm->framestate, pncwm->rawMaxBtnState),
  3145. &pncwm->rcW0[NCRC_MAXBTN], 0);
  3146. }
  3147. if (!IsRectEmpty(&pncwm->rcW0[NCRC_MINBTN]))
  3148. {
  3149. NcDrawThemeBackground( _hTheme, hdc, pncwm->iMinButtonPart,
  3150. MAKE_BTNSTATE(pncwm->framestate, pncwm->rawMinBtnState),
  3151. &pncwm->rcW0[NCRC_MINBTN], 0);
  3152. }
  3153. if (!IsRectEmpty(&pncwm->rcW0[NCRC_HELPBTN]))
  3154. NcDrawThemeBackground(_hTheme, hdc, WP_HELPBUTTON, MAKE_BTNSTATE(pncwm->framestate, CBS_NORMAL),
  3155. &pncwm->rcW0[NCRC_HELPBTN], 0);
  3156. }
  3157. // Draw sysmenu icon
  3158. if( TESTFLAG( dwCaptionFlags, DC_ICON ) )
  3159. {
  3160. if (!IsRectEmpty(&pncwm->rcW0[NCRC_SYSBTN]) && _hAppIcon)
  3161. {
  3162. #define MAX_APPICON_RETRIES 1
  3163. int cRetries = 0;
  3164. DWORD dwLayout = GetLayout(hdc);
  3165. if( GDI_ERROR != dwLayout && TESTFLAG(dwLayout, LAYOUT_RTL) )
  3166. {
  3167. SetLayout(hdc, dwLayout|LAYOUT_BITMAPORIENTATIONPRESERVED);
  3168. }
  3169. do
  3170. {
  3171. // note: we don't draw sysmenu icon mirrored
  3172. if( DrawIconEx(hdc, pncwm->rcW0[NCRC_SYSBTN].left, pncwm->rcW0[NCRC_SYSBTN].top, _hAppIcon,
  3173. RECTWIDTH(&pncwm->rcW0[NCRC_SYSBTN]), RECTHEIGHT(&pncwm->rcW0[NCRC_SYSBTN]),
  3174. 0, NULL, DI_NORMAL))
  3175. {
  3176. break; // success; done
  3177. }
  3178. // failure; try recycling the handle
  3179. if( _hAppIcon && GetLastError() == ERROR_INVALID_CURSOR_HANDLE )
  3180. {
  3181. _hAppIcon = NULL;
  3182. AcquireFrameIcon( pncwm->dwStyle, pncwm->dwExStyle, FALSE );
  3183. if( (++cRetries) > MAX_APPICON_RETRIES )
  3184. {
  3185. _hAppIcon = NULL; // failed to retrieve a new icon handle; bail for good.
  3186. }
  3187. }
  3188. } while( _hAppIcon && cRetries <= MAX_APPICON_RETRIES );
  3189. if( GDI_ERROR != dwLayout )
  3190. {
  3191. SetLayout(hdc, dwLayout);
  3192. }
  3193. }
  3194. }
  3195. if( TESTFLAG( dwCaptionFlags, DC_TEXT ) )
  3196. {
  3197. // Draw caption text
  3198. HFONT hf0 = NULL;
  3199. DWORD dwDTFlags = DT_SINGLELINE | DT_NOPREFIX | DT_END_ELLIPSIS;
  3200. BOOL fSelFont = FALSE;
  3201. LPWSTR pszText = _AllocWindowText(_hwnd);
  3202. if( pszText && *pszText )
  3203. {
  3204. // Compute frame text rect
  3205. if( pncwm->hfCaption )
  3206. {
  3207. hf0 = (HFONT)SelectObject( hdc, pncwm->hfCaption );
  3208. fSelFont = TRUE;
  3209. }
  3210. //---- compute text alignment ----
  3211. BOOL fReverse = TESTFLAG(_ncwm.dwExStyle, WS_EX_RIGHT);
  3212. dwDTFlags |= GetTextAlignFlags(_hTheme, pncwm, fReverse);
  3213. }
  3214. //---- adjust text align for WS_EX_RTLREADING ----
  3215. if (TESTFLAG(_ncwm.dwExStyle, WS_EX_RTLREADING))
  3216. dwOldAlign = SetTextAlign(hdc, TA_RTLREADING | GetTextAlign(hdc));
  3217. if( pszText && *pszText )
  3218. {
  3219. //---- set options for DrawThemeText() ----
  3220. DTTOPTS DttOpts = {sizeof(DttOpts)};
  3221. DttOpts.dwFlags = DTT_TEXTCOLOR;
  3222. DttOpts.crText = pncwm->rgbCaption;
  3223. Log(LOG_RFBUG, L"Drawing Caption Text: left=%d, state=%d, text=%s",
  3224. pncwm->rcW0[NCRC_CAPTIONTEXT].left, pncwm->framestate, pszText);
  3225. //---- draw the caption text ----
  3226. DrawThemeTextEx(_hTheme, hdc, pncwm->rgframeparts[iCAPTION], pncwm->framestate,
  3227. pszText, -1, dwDTFlags, &pncwm->rcW0[NCRC_CAPTIONTEXT], &DttOpts);
  3228. }
  3229. //---- free the text, if temp. allocated ----
  3230. SAFE_DELETE_ARRAY(pszText)
  3231. //---- draw the "Comments?" text ----
  3232. SetBkMode( hdc, TRANSPARENT );
  3233. SetTextColor( hdc, pncwm->rgbCaption );
  3234. DrawLameButton(hdc, pncwm);
  3235. //---- restore the text align ----
  3236. if (TESTFLAG(_ncwm.dwExStyle, WS_EX_RTLREADING))
  3237. SetTextAlign(hdc, dwOldAlign);
  3238. if( fSelFont )
  3239. {
  3240. SelectObject(hdc, hf0);
  3241. }
  3242. }
  3243. if( hdc != hdcOut )
  3244. {
  3245. // Slap the bits on the output DC.
  3246. BitBlt( hdcOut, pncwm->rcW0[NCRC_CAPTION].left, pncwm->rcW0[NCRC_CAPTION].top,
  3247. WIDTH(pncwm->rcW0[NCRC_CAPTION]), HEIGHT(pncwm->rcW0[NCRC_CAPTION]),
  3248. hdc, 0, 0, SRCCOPY );
  3249. SelectObject(hdc, hbm0);
  3250. DeleteDC(hdc);
  3251. }
  3252. LeaveNcThemePaint();
  3253. }
  3254. DeleteObject( hbmBuf );
  3255. }
  3256. if( IsWindowVisible(_hwnd) )
  3257. {
  3258. SetRenderedNcPart(RNCF_CAPTION);
  3259. }
  3260. }
  3261. //-------------------------------------------------------------------------//
  3262. // CThemeWnd::NcPaint() - NC painting worker
  3263. //
  3264. void CThemeWnd::NcPaint(
  3265. IN OPTIONAL HDC hdcIn,
  3266. IN ULONG dwFlags,
  3267. IN OPTIONAL HRGN hrgnUpdate,
  3268. IN OPTIONAL NCPAINTOVERIDE* pncpo)
  3269. {
  3270. NCTHEMEMET nctm;
  3271. NCWNDMET* pncwm = NULL;
  3272. HDC hdc = NULL;
  3273. if( _cLockRedraw > 0 )
  3274. return;
  3275. // Compute all metrics before painting:
  3276. if (pncpo) // preview override
  3277. {
  3278. ASSERT(hdcIn);
  3279. hdc = hdcIn;
  3280. pncwm = pncpo->pncwm;
  3281. nctm = pncpo->nctm;
  3282. }
  3283. else // live window
  3284. {
  3285. if( !GetNcWindowMetrics( NULL, &pncwm, &nctm, NCWMF_RECOMPUTE ) )
  3286. return;
  3287. // Ensure status bits reflect caller's intention for frame state
  3288. if( dwFlags != NCPF_DEFAULT )
  3289. {
  3290. _ComputeNcWindowStatus( _hwnd, TESTFLAG(dwFlags, NCPF_ACTIVEFRAME) ? WS_ACTIVECAPTION : 0, pncwm );
  3291. }
  3292. hdc = hdcIn ? hdcIn : _GetNonclientDC( _hwnd, hrgnUpdate );
  3293. if (! hdc)
  3294. {
  3295. //---- don't assert here since stress (out of memory) could cause a legit failure ----
  3296. Log(LOG_ALWAYS, L"call to GetDCEx() for nonclient painting failed");
  3297. }
  3298. }
  3299. if( hdc != NULL )
  3300. {
  3301. //--- DO NOT EXIT FROM WITHIN THIS CONDITIONAL ---//
  3302. BEGIN_DEBUG_NCPAINT();
  3303. EnterNcThemePaint();
  3304. // Clip to content rect (alleviates flicker in menubar and scrollbars as we paint background)
  3305. RECT rcClip;
  3306. rcClip = pncwm->rcW0[NCRC_CONTENT];
  3307. if( TESTFLAG(pncwm->dwExStyle, WS_EX_LAYOUTRTL) )
  3308. {
  3309. // mirror the clip rect relative to the window rect
  3310. // and apply that as the clipping region for the dc
  3311. MIRROR_RECT(pncwm->rcW0[NCRC_WINDOW], rcClip);
  3312. }
  3313. ExcludeClipRect( hdc, rcClip.left, rcClip.top, rcClip.right, rcClip.bottom );
  3314. if( pncwm->fFrame )
  3315. {
  3316. //---- DrawThemeBackgroundEx() options ----
  3317. DTBGOPTS dtbopts = {sizeof(dtbopts)};
  3318. DTBGOPTS *pdtbopts = NULL;
  3319. // if not drawing preview, set "draw solid" option
  3320. if(!pncpo)
  3321. {
  3322. // Because of the interleaving of NCPAINT and SetWindowRgn, drawing solid results
  3323. // in some flicker and transparency bleed. Commenting this out for now [scotthan]
  3324. //dtbopts.dwFlags |= DTBG_DRAWSOLID;
  3325. pdtbopts = &dtbopts;
  3326. }
  3327. // Frame Background
  3328. if( pncwm->fMin )
  3329. {
  3330. NcDrawThemeBackgroundEx( _hTheme, hdc, WP_MINCAPTION, pncwm->framestate,
  3331. &pncwm->rcW0[NCRC_CAPTION], pdtbopts ) ;
  3332. }
  3333. else if( !pncwm->fFullMaxed )
  3334. {
  3335. NcDrawThemeBackgroundEx( _hTheme, hdc, pncwm->rgframeparts[iFRAMELEFT], pncwm->framestate,
  3336. &pncwm->rcW0[NCRC_FRAMELEFT], pdtbopts );
  3337. NcDrawThemeBackgroundEx( _hTheme, hdc, pncwm->rgframeparts[iFRAMERIGHT], pncwm->framestate,
  3338. &pncwm->rcW0[NCRC_FRAMERIGHT], pdtbopts );
  3339. NcDrawThemeBackgroundEx( _hTheme, hdc, pncwm->rgframeparts[iFRAMEBOTTOM], pncwm->framestate,
  3340. &pncwm->rcW0[NCRC_FRAMEBOTTOM], pdtbopts );
  3341. }
  3342. SetRenderedNcPart(RNCF_FRAME);
  3343. // Caption
  3344. NcPaintCaption( hdc, pncwm, !(pncwm->fMin || pncwm->fFullMaxed || pncpo),
  3345. DC_ENTIRECAPTION, pdtbopts );
  3346. }
  3347. // Clip to client rect
  3348. SelectClipRgn( hdc, NULL );
  3349. // Menubar
  3350. if( !(pncwm->fMin || TESTFLAG(pncwm->dwStyle, WS_CHILD))
  3351. && !IsRectEmpty(&pncwm->rcW0[NCRC_MENUBAR]) )
  3352. {
  3353. RECT rcMenuBar = pncwm->rcW0[NCRC_MENUBAR];
  3354. BOOL fClip = RECTHEIGHT(&rcMenuBar) < pncwm->cyMenu;
  3355. if( fClip )
  3356. {
  3357. IntersectClipRect( hdc, rcMenuBar.left, rcMenuBar.top,
  3358. rcMenuBar.right, rcMenuBar.bottom );
  3359. }
  3360. PaintMenuBar( _hwnd, hdc, pncwm->cnMenuOffsetLeft,
  3361. pncwm->cnMenuOffsetRight, pncwm->cnMenuOffsetTop,
  3362. TESTFLAG(pncwm->framestate, FS_ACTIVE) ? PMB_ACTIVE : 0 );
  3363. // deal with unpainted menubar pixels:
  3364. if( nctm.dyMenuBar > 0 && RECTHEIGHT(&pncwm->rcW0[NCRC_MENUBAR]) >= pncwm->cyMenu )
  3365. {
  3366. rcMenuBar.top = rcMenuBar.bottom - nctm.dyMenuBar;
  3367. COLORREF rgbBk = SetBkColor( hdc, GetSysColor(COLOR_MENU) );
  3368. ExtTextOut(hdc, rcMenuBar.left, rcMenuBar.top, ETO_OPAQUE, &rcMenuBar, NULL, 0, NULL );
  3369. SetBkColor( hdc, rgbBk );
  3370. }
  3371. if( fClip )
  3372. SelectClipRgn( hdc, NULL );
  3373. }
  3374. // Scrollbars
  3375. if( !pncwm->fMin )
  3376. {
  3377. // Draw static, window, client edges.
  3378. _DrawWindowEdges( hdc, pncwm, pncwm->fFrame );
  3379. RECT rcVScroll = pncwm->rcW0[NCRC_VSCROLL];
  3380. if ( TESTFLAG(pncwm->dwExStyle, WS_EX_LAYOUTRTL) )
  3381. {
  3382. MIRROR_RECT(pncwm->rcW0[NCRC_WINDOW], rcVScroll);
  3383. }
  3384. if( TESTFLAG(pncwm->dwStyle, WS_VSCROLL) &&
  3385. ( HasRenderedNcPart(RNCF_SCROLLBAR) || RectVisible(hdc, &rcVScroll)) )
  3386. {
  3387. if( TESTFLAG(pncwm->dwStyle, WS_HSCROLL) )
  3388. {
  3389. // Draw sizebox.
  3390. RECT rcSizeBox = pncwm->rcW0[NCRC_SIZEBOX];
  3391. if ( TESTFLAG(pncwm->dwExStyle, WS_EX_LAYOUTRTL) )
  3392. {
  3393. MIRROR_RECT(pncwm->rcW0[NCRC_WINDOW], rcSizeBox);
  3394. }
  3395. DrawSizeBox( _hwnd, hdc, rcSizeBox.left, rcSizeBox.top );
  3396. }
  3397. DrawScrollBar( _hwnd, hdc, pncpo ? &pncwm->rcW0[NCRC_VSCROLL]: NULL, TRUE /*vertical*/ );
  3398. SetRenderedNcPart( RNCF_SCROLLBAR );
  3399. }
  3400. if( TESTFLAG(pncwm->dwStyle, WS_HSCROLL) &&
  3401. ( HasRenderedNcPart(RNCF_SCROLLBAR) || RectVisible(hdc, &pncwm->rcW0[NCRC_HSCROLL])) )
  3402. {
  3403. DrawScrollBar( _hwnd, hdc, pncpo ? &pncwm->rcW0[NCRC_HSCROLL] : NULL, FALSE /*vertical*/ );
  3404. SetRenderedNcPart( RNCF_SCROLLBAR );
  3405. }
  3406. }
  3407. if (pncpo || hdcIn)
  3408. {
  3409. SelectClipRgn( hdc, NULL );
  3410. }
  3411. else
  3412. {
  3413. ReleaseDC( _hwnd, hdc );
  3414. }
  3415. LeaveNcThemePaint();
  3416. END_DEBUG_NCPAINT();
  3417. }
  3418. }
  3419. //-------------------------------------------------------------------------//
  3420. // WM_STYLECHANGED themewnd instance handler
  3421. void CThemeWnd::StyleChanged( UINT iGWL, DWORD dwOld, DWORD dwNew )
  3422. {
  3423. DWORD dwStyleOld, dwStyleNew, dwExStyleOld, dwExStyleNew;
  3424. switch( iGWL )
  3425. {
  3426. case GWL_STYLE:
  3427. dwStyleOld = dwOld;
  3428. dwStyleNew = dwNew;
  3429. dwExStyleOld = dwExStyleNew = GetWindowLong(_hwnd, GWL_EXSTYLE);
  3430. break;
  3431. case GWL_EXSTYLE:
  3432. dwExStyleOld = dwOld;
  3433. dwExStyleNew = dwNew;
  3434. dwStyleOld = dwStyleNew = GetWindowLong(_hwnd, GWL_STYLE);
  3435. break;
  3436. default:
  3437. return;
  3438. }
  3439. DWORD fClassFlagsOld = CThemeWnd::EvaluateStyle( dwStyleOld, dwExStyleOld);
  3440. DWORD fClassFlagsNew = CThemeWnd::EvaluateStyle( dwStyleNew, dwExStyleNew);
  3441. // Update theme class flags.
  3442. // Always keep the scrollbar class flag if the window had it initially. User
  3443. // flips scroll styles on and off without corresponding style change notification.
  3444. _fClassFlags = fClassFlagsNew | (_fClassFlags & TWCF_SCROLLBARS);
  3445. _fFrameThemed = TESTFLAG( _fClassFlags, TWCF_FRAME|TWCF_TOOLFRAME );
  3446. // Are we losing the frame?
  3447. if( TESTFLAG( fClassFlagsOld, TWCF_FRAME|TWCF_TOOLFRAME ) &&
  3448. !TESTFLAG( fClassFlagsNew, TWCF_FRAME|TWCF_TOOLFRAME ) )
  3449. {
  3450. ThemeMDIMenuButtons(FALSE, FALSE);
  3451. if( AssignedFrameRgn() )
  3452. {
  3453. AssignFrameRgn(FALSE /*strip off frame rgn*/, FTF_REDRAW);
  3454. }
  3455. }
  3456. // Are we gaining a frame?
  3457. else if( TESTFLAG( fClassFlagsNew, TWCF_FRAME|TWCF_TOOLFRAME ) &&
  3458. !TESTFLAG( fClassFlagsOld, TWCF_FRAME|TWCF_TOOLFRAME ) )
  3459. {
  3460. SetFrameTheme(0, NULL);
  3461. }
  3462. // Freshen window metrics
  3463. GetNcWindowMetrics( NULL, NULL, NULL, NCWMF_RECOMPUTE );
  3464. }
  3465. //-------------------------------------------------------------------------//
  3466. // ThemeDefWindowProc message handlers
  3467. //-------------------------------------------------------------------------//
  3468. //-------------------------------------------------------------------------//
  3469. // WM_THEMECHANGED post-wndproc msg handler
  3470. LRESULT CALLBACK OnOwpPostThemeChanged( CThemeWnd* pwnd, THEME_MSG *ptm )
  3471. {
  3472. if (IS_THEME_CHANGE_TARGET(ptm->lParam))
  3473. {
  3474. //---- avoid redundant retheming (except for SetWindowTheme() calls)
  3475. if ((HTHEME(*pwnd) == _nctmCurrent.hTheme) && (! (ptm->lParam & WTC_CUSTOMTHEME)))
  3476. {
  3477. Log(LOG_NCATTACH, L"OnOwpPostThemeChanged, just kicking the frame");
  3478. //---- window got correct theme thru _XXXWindowProc() from sethook ----
  3479. //---- we just need to redraw the frame for all to be right ----
  3480. if (pwnd->IsFrameThemed())
  3481. {
  3482. //---- attach the region to the window now ----
  3483. pwnd->SetFrameTheme(FTF_REDRAW, NULL);
  3484. }
  3485. }
  3486. else
  3487. {
  3488. Log(LOG_NCATTACH, L"OnOwpPostThemeChanged, calling Full ::ChangeTheme()");
  3489. //---- its a real, app/system theme change ----
  3490. pwnd->ChangeTheme( ptm );
  3491. }
  3492. }
  3493. MsgHandled( ptm );
  3494. return 1L;
  3495. }
  3496. //-------------------------------------------------------------------------//
  3497. void CThemeWnd::ChangeTheme( THEME_MSG* ptm )
  3498. {
  3499. if( _hTheme ) // hwnd attached for previous theme
  3500. {
  3501. // do a lightweight detach from current theme
  3502. _DetachInstance( HMD_CHANGETHEME );
  3503. }
  3504. if( IsAppThemed() ) // new theme is active
  3505. {
  3506. // retrieve window client rect, style bits.
  3507. WINDOWINFO wi;
  3508. wi.cbSize = sizeof(wi);
  3509. GetWindowInfo( ptm->hwnd, &wi );
  3510. ULONG ulTargetFlags = EvaluateStyle( wi.dwStyle, wi.dwExStyle );
  3511. // If the window is themable
  3512. if( TESTFLAG(ulTargetFlags, TWCF_NCTHEMETARGETMASK) )
  3513. {
  3514. // Open the new theme
  3515. HTHEME hTheme = ::OpenNcThemeData( ptm->hwnd, L"Window" );
  3516. if( hTheme )
  3517. {
  3518. // do a lightweight attach
  3519. if( _AttachInstance( ptm->hwnd, hTheme, ulTargetFlags, NULL ) )
  3520. {
  3521. // reattach scrollbars
  3522. if( TESTFLAG( ulTargetFlags, TWCF_SCROLLBARS ) )
  3523. {
  3524. AttachScrollBars(ptm->hwnd);
  3525. }
  3526. if (IsFrameThemed())
  3527. {
  3528. //---- attach the region to the window now ----
  3529. SetFrameTheme(FTF_REDRAW, NULL);
  3530. }
  3531. }
  3532. else
  3533. {
  3534. CloseThemeData( hTheme );
  3535. }
  3536. }
  3537. }
  3538. }
  3539. if (! _hTheme) // if an hwnd is no longer attached
  3540. {
  3541. // Left without a theme handle: This means either we failed to open a new theme handle or
  3542. // failed to evaulate as a target, no new theme, etc.
  3543. RemoveWindowProperties(ptm->hwnd, FALSE);
  3544. //---- release our CThemeWnd obj so it doesn't leak (addref-protected by caller) ----
  3545. Release();
  3546. }
  3547. }
  3548. //-------------------------------------------------------------------------//
  3549. BOOL IsPropertySheetChild(HWND hDlg)
  3550. {
  3551. while(hDlg)
  3552. {
  3553. ULONG ulFlags = HandleToUlong(GetProp(hDlg, MAKEINTATOM(GetThemeAtom(THEMEATOM_DLGTEXTURING))));
  3554. if( ETDT_ENABLETAB == (ulFlags & ETDT_ENABLETAB) /* all bits in this mask are required */ )
  3555. {
  3556. return TRUE;
  3557. }
  3558. hDlg = GetAncestor(hDlg, GA_PARENT);
  3559. }
  3560. return FALSE;
  3561. }
  3562. //---------------------------------------------------------------------------
  3563. void PrintClientNotHandled(HWND hwnd)
  3564. {
  3565. ATOM aIsPrinting = GetThemeAtom(THEMEATOM_PRINTING);
  3566. DWORD dw = PtrToUlong(GetProp(hwnd, (PCTSTR)aIsPrinting));
  3567. if (dw == PRINTING_ASKING)
  3568. SetProp(hwnd, (PCTSTR)aIsPrinting, (HANDLE)PRINTING_WINDOWDIDNOTHANDLE);
  3569. }
  3570. //---------------------------------------------------------------------------
  3571. HBRUSH GetDialogColor(HWND hwnd, NCTHEMEMET &nctm)
  3572. {
  3573. HBRUSH hbr = NULL;
  3574. // if this is a PROPSHEET child or the app called
  3575. // EnableThemeDialogTexture() on this hwnd, we'll use the tab background.
  3576. if (IsPropertySheetChild(hwnd))
  3577. {
  3578. hbr = nctm.hbrTabDialog;
  3579. }
  3580. if( NULL == hbr )
  3581. {
  3582. hbr = GetSysColorBrush(COLOR_3DFACE);
  3583. }
  3584. return hbr;
  3585. }
  3586. //---------------------------------------------------------------------------
  3587. LRESULT CALLBACK OnDdpPrint(CThemeWnd* pwnd, THEME_MSG* ptm)
  3588. {
  3589. LRESULT lRet = 0L;
  3590. if (!ptm->lRet)
  3591. {
  3592. if (pwnd->HasProcessedEraseBk())
  3593. {
  3594. RECT rc;
  3595. HDC hdc = (HDC)ptm->wParam;
  3596. NCTHEMEMET nctm;
  3597. if( GetCurrentNcThemeMetrics( &nctm ))
  3598. {
  3599. HBRUSH hbr = GetDialogColor(*pwnd, nctm);
  3600. if (hbr)
  3601. {
  3602. POINT pt;
  3603. if (GetClipBox(hdc, &rc) == NULLREGION)
  3604. GetClientRect(*pwnd, &rc);
  3605. SetBrushOrgEx(hdc, -rc.left, -rc.top, &pt);
  3606. FillRect(hdc, &rc, hbr);
  3607. SetBrushOrgEx(hdc, pt.x, pt.y, NULL);
  3608. lRet = (LRESULT)1;
  3609. MsgHandled( ptm );
  3610. }
  3611. }
  3612. }
  3613. else
  3614. {
  3615. PrintClientNotHandled(*pwnd);
  3616. }
  3617. }
  3618. return lRet;
  3619. }
  3620. //---------------------------------------------------------------------------
  3621. LRESULT CALLBACK OnDdpCtlColor(CThemeWnd* pwnd, THEME_MSG *ptm )
  3622. {
  3623. LRESULT lRet = 0L;
  3624. if (!ptm->lRet && pwnd->HasProcessedEraseBk())
  3625. {
  3626. NCTHEMEMET nctm;
  3627. if( GetCurrentNcThemeMetrics( &nctm ))
  3628. {
  3629. HBRUSH hbr = GetDialogColor(*pwnd, nctm);
  3630. if (hbr)
  3631. {
  3632. RECT rc;
  3633. HDC hdc = (HDC)ptm->wParam;
  3634. GetWindowRect(((HWND)ptm->lParam), &rc);
  3635. MapWindowPoints(NULL, *pwnd, (POINT*)&rc, 2);
  3636. SetBkMode(hdc, TRANSPARENT);
  3637. SetBrushOrgEx(hdc, -rc.left, -rc.top, NULL);
  3638. // the hdc's default background color needs to be set
  3639. // for for those controls that insist on using OPAQUE
  3640. SetBkColor(hdc, GetSysColor(COLOR_BTNFACE));
  3641. lRet = (LRESULT)hbr;
  3642. MsgHandled( ptm );
  3643. }
  3644. }
  3645. }
  3646. return lRet;
  3647. }
  3648. //-------------------------------------------------------------------------//
  3649. // WM_CTLCOLORxxx defwindowproc override handler
  3650. LRESULT CALLBACK OnDdpPostCtlColor( CThemeWnd* pwnd, THEME_MSG *ptm )
  3651. {
  3652. LRESULT lRet = 0L;
  3653. if (!ptm->lRet)
  3654. {
  3655. // This is sent to the parent in the case of WM_CTLCOLORMSGBOX, but to the
  3656. // dialog itself in the case of a WM_CTLCOLORDLG. This gets both.
  3657. CThemeWnd* pwndDlg = CThemeWnd::FromHwnd((HWND)ptm->lParam);
  3658. // WM_CTLCOLORMSGBOX is sent for Both the dialog AND the static
  3659. // control inside. So we need to sniff: Are we talking to a dialog or a
  3660. // control. the pwnd is associated with the dialog, but not the control
  3661. if (pwndDlg && VALID_THEMEWND(pwndDlg))
  3662. {
  3663. if (IsPropertySheetChild(*pwnd))
  3664. {
  3665. NCTHEMEMET nctm;
  3666. if( GetCurrentNcThemeMetrics( &nctm ))
  3667. {
  3668. HBRUSH hbr = GetDialogColor(*pwndDlg, nctm);
  3669. if (hbr)
  3670. {
  3671. lRet = (LRESULT) hbr;
  3672. pwndDlg->ProcessedEraseBk(TRUE);
  3673. MsgHandled(ptm);
  3674. }
  3675. }
  3676. }
  3677. }
  3678. else
  3679. {
  3680. // If we're talking to a control, forward to the control handler
  3681. // because we have to offset the brush
  3682. lRet = OnDdpCtlColor(pwnd, ptm );
  3683. }
  3684. }
  3685. return lRet;
  3686. }
  3687. //-------------------------------------------------------------------------//
  3688. LRESULT CALLBACK OnDwpPrintClient( CThemeWnd* pwnd, THEME_MSG *ptm )
  3689. {
  3690. PrintClientNotHandled(*pwnd);
  3691. return 0;
  3692. }
  3693. //---- Non-Client ----
  3694. //-------------------------------------------------------------------------//
  3695. // WM_NCPAINT pre-wndmproc msg handler
  3696. LRESULT CALLBACK OnOwpPreNcPaint( CThemeWnd* pwnd, THEME_MSG *ptm )
  3697. {
  3698. NcPaintWindow_Add(*pwnd);
  3699. if( !pwnd->InNcPaint() )
  3700. {
  3701. pwnd->ClearRenderedNcPart(RNCF_ALL);
  3702. }
  3703. pwnd->EnterNcPaint();
  3704. return 0L;
  3705. }
  3706. //-------------------------------------------------------------------------//
  3707. // WM_NCPAINT DefWindowProc msg handler
  3708. LRESULT CALLBACK OnDwpNcPaint( CThemeWnd* pwnd, THEME_MSG *ptm )
  3709. {
  3710. LRESULT lRet = 0L;
  3711. if( !pwnd->IsNcThemed() )
  3712. return lRet;
  3713. if( IsWindowVisible(*pwnd) )
  3714. {
  3715. pwnd->NcPaint( NULL, NCPF_DEFAULT, 1 == ptm->wParam ? NULL : (HRGN)ptm->wParam, NULL );
  3716. }
  3717. MsgHandled( ptm );
  3718. return lRet;
  3719. }
  3720. //-------------------------------------------------------------------------//
  3721. // WM_NCPAINT post-wndmproc msg handler
  3722. LRESULT CALLBACK OnOwpPostNcPaint( CThemeWnd* pwnd, THEME_MSG *ptm )
  3723. {
  3724. pwnd->LeaveNcPaint();
  3725. NcPaintWindow_Remove();
  3726. return 0L;
  3727. }
  3728. //-------------------------------------------------------------------------//
  3729. // WM_PRINT DefWindowProc msg handler
  3730. LRESULT CALLBACK OnDwpPrint( CThemeWnd* pwnd, THEME_MSG *ptm )
  3731. {
  3732. LRESULT lRet = DoMsgDefault(ptm);
  3733. if( !pwnd->IsNcThemed() )
  3734. return lRet;
  3735. if( ptm->lParam & PRF_NONCLIENT )
  3736. {
  3737. int iLayoutSave = GDI_ERROR;
  3738. HDC hdc = (HDC)ptm->wParam;
  3739. if (TESTFLAG(GetWindowLong(*pwnd, GWL_EXSTYLE), WS_EX_LAYOUTRTL))
  3740. {
  3741. // AnimateWindow sends WM_PRINT with an unmirrored memory hdc
  3742. iLayoutSave = SetLayout(hdc, LAYOUT_RTL);
  3743. }
  3744. pwnd->NcPaint( (HDC)ptm->wParam, NCPF_DEFAULT, NULL, NULL );
  3745. if (iLayoutSave != GDI_ERROR)
  3746. {
  3747. SetLayout(hdc, iLayoutSave);
  3748. }
  3749. }
  3750. return lRet;
  3751. }
  3752. //-------------------------------------------------------------------------//
  3753. // WM_NCUAHDRAWCAPTION DefWindowProc msg handler
  3754. LRESULT CALLBACK OnDwpNcThemeDrawCaption( CThemeWnd* pwnd, THEME_MSG *ptm )
  3755. {
  3756. LRESULT lRet = 0L;
  3757. if( !pwnd->IsNcThemed() || !pwnd->HasRenderedNcPart(RNCF_CAPTION) )
  3758. return lRet;
  3759. NCWNDMET* pncwm;
  3760. if( pwnd->GetNcWindowMetrics( NULL, &pncwm, NULL, NCWMF_RECOMPUTE ) )
  3761. {
  3762. HDC hdc = _GetNonclientDC( *pwnd, NULL );
  3763. if( hdc )
  3764. {
  3765. DTBGOPTS dtbo;
  3766. dtbo.dwSize = sizeof(dtbo);
  3767. dtbo.dwFlags = DTBG_DRAWSOLID;
  3768. pwnd->NcPaintCaption( hdc, pncwm, TRUE, (DWORD)ptm->wParam, &dtbo );
  3769. ReleaseDC( *pwnd, hdc );
  3770. MsgHandled( ptm );
  3771. }
  3772. }
  3773. return lRet;
  3774. }
  3775. //-------------------------------------------------------------------------//
  3776. // WM_NCUAHDRAWFRAME DefWindowProc msg handler
  3777. LRESULT CALLBACK OnDwpNcThemeDrawFrame( CThemeWnd* pwnd, THEME_MSG *ptm )
  3778. {
  3779. LRESULT lRet = 0L;
  3780. if( !pwnd->IsNcThemed() || !pwnd->HasRenderedNcPart(RNCF_FRAME) )
  3781. return lRet;
  3782. pwnd->NcPaint( (HDC)ptm->wParam, ptm->lParam & DF_ACTIVE ? NCPF_ACTIVEFRAME : NCPF_INACTIVEFRAME, NULL, NULL );
  3783. MsgHandled( ptm );
  3784. return lRet;
  3785. }
  3786. //-------------------------------------------------------------------------//
  3787. CMdiBtns* CThemeWnd::LoadMdiBtns( IN OPTIONAL HDC hdc, IN OPTIONAL UINT uSysCmd )
  3788. {
  3789. if( NULL == _pMdiBtns && NULL == (_pMdiBtns = new CMdiBtns) )
  3790. {
  3791. return NULL;
  3792. }
  3793. return _pMdiBtns->Load( _hTheme, hdc, uSysCmd ) ? _pMdiBtns : NULL;
  3794. }
  3795. //-------------------------------------------------------------------------//
  3796. void CThemeWnd::UnloadMdiBtns( IN OPTIONAL UINT uSysCmd )
  3797. {
  3798. SAFE_DELETE(_pMdiBtns);
  3799. }
  3800. //-------------------------------------------------------------------------//
  3801. // WM_MEASUREITEM pre-wndproc msg handler
  3802. LRESULT CALLBACK OnOwpPreMeasureItem( CThemeWnd* pwnd, THEME_MSG *ptm )
  3803. {
  3804. if( pwnd->IsNcThemed() && IsWindow(pwnd->GetMDIClient()) )
  3805. {
  3806. MEASUREITEMSTRUCT* pmis = (MEASUREITEMSTRUCT*)ptm->lParam;
  3807. CMdiBtns* pBtns = pwnd->LoadMdiBtns( NULL, pmis->itemID );
  3808. if( pBtns )
  3809. {
  3810. if( pBtns->Measure( *pwnd, pmis ) )
  3811. {
  3812. MsgHandled(ptm);
  3813. return TRUE;
  3814. }
  3815. }
  3816. }
  3817. return FALSE;
  3818. }
  3819. //-------------------------------------------------------------------------//
  3820. // WM_DRAWITEM pre-wndproc msg handler
  3821. LRESULT CALLBACK OnOwpPreDrawItem( CThemeWnd* pwnd, THEME_MSG *ptm )
  3822. {
  3823. if( pwnd->IsNcThemed() && IsWindow(pwnd->GetMDIClient()) )
  3824. {
  3825. DRAWITEMSTRUCT* pdis = (DRAWITEMSTRUCT*)ptm->lParam;
  3826. CMdiBtns* pBtns = pwnd->LoadMdiBtns( NULL, pdis->itemID );
  3827. if( pBtns )
  3828. {
  3829. if( pBtns->Draw( *pwnd, pdis ) )
  3830. {
  3831. MsgHandled(ptm);
  3832. return TRUE;
  3833. }
  3834. }
  3835. }
  3836. return FALSE;
  3837. }
  3838. //-------------------------------------------------------------------------//
  3839. // WM_MENUCHAR pre-wndproc msg handler
  3840. LRESULT CALLBACK OnOwpPreMenuChar( CThemeWnd* pwnd, THEME_MSG *ptm )
  3841. {
  3842. // Route MENUCHAR messages relating to themed MDI buttons to
  3843. // DefWindowProc (some apps assume all owner-drawn menuitems
  3844. // belong to themselves).
  3845. HWND hwndMDIClient = pwnd->GetMDIClient();
  3846. if( pwnd->IsNcThemed() && IsWindow(hwndMDIClient))
  3847. {
  3848. if( LOWORD(ptm->wParam) == TEXT('-') )
  3849. {
  3850. BOOL fMaxedChild;
  3851. HWND hwndActive = _MDIGetActive(hwndMDIClient, &fMaxedChild );
  3852. if( hwndActive && fMaxedChild )
  3853. {
  3854. MsgHandled(ptm);
  3855. return DefFrameProc(ptm->hwnd, hwndMDIClient, ptm->uMsg,
  3856. ptm->wParam, ptm->lParam);
  3857. }
  3858. }
  3859. }
  3860. return 0L;
  3861. }
  3862. //-------------------------------------------------------------------------//
  3863. // WM_NCHITTEST DefWindowProc msg handler
  3864. LRESULT CALLBACK OnDwpNcHitTest( CThemeWnd* pwnd, THEME_MSG *ptm )
  3865. {
  3866. if( !pwnd->IsNcThemed() )
  3867. return DoMsgDefault( ptm );
  3868. NCTHEMEMET nctm;
  3869. NCWNDMET* pncwm;
  3870. POINT pt;
  3871. MAKEPOINT( pt, ptm->lParam );
  3872. MsgHandled( ptm );
  3873. if( pwnd->GetNcWindowMetrics( NULL, &pncwm, &nctm, 0 ) )
  3874. {
  3875. if( _StrictPtInRect( &pncwm->rcS0[NCRC_CLIENT], pt ) )
  3876. return HTCLIENT;
  3877. if( _StrictPtInRect( &pncwm->rcS0[NCRC_HSCROLL], pt ) )
  3878. return HTHSCROLL;
  3879. if( _StrictPtInRect( &pncwm->rcS0[NCRC_SIZEBOX], pt ) )
  3880. {
  3881. if (SizeBoxHwnd(*pwnd) && !TESTFLAG(pncwm->dwExStyle, WS_EX_LEFTSCROLLBAR))
  3882. {
  3883. return TESTFLAG(pncwm->dwExStyle, WS_EX_LAYOUTRTL) ? HTBOTTOMLEFT : HTBOTTOMRIGHT;
  3884. }
  3885. else
  3886. {
  3887. return HTGROWBOX;
  3888. }
  3889. }
  3890. if ( TESTFLAG(pncwm->dwExStyle, WS_EX_LAYOUTRTL) )
  3891. {
  3892. // mirror the point to hittest correctly
  3893. MIRROR_POINT(pncwm->rcS0[NCRC_WINDOW], pt);
  3894. }
  3895. if( _StrictPtInRect( &pncwm->rcS0[NCRC_VSCROLL], pt ) )
  3896. return HTVSCROLL;
  3897. if( _StrictPtInRect( &pncwm->rcS0[NCRC_MENUBAR], pt ) )
  3898. return HTMENU;
  3899. if( pncwm->fFrame )
  3900. {
  3901. RECT rcButton;
  3902. // ---- close button ----
  3903. _GetNcBtnHitTestRect( pncwm, HTCLOSE, FALSE, &rcButton );
  3904. if ( _StrictPtInRect( &rcButton, pt ) )
  3905. {
  3906. return HTCLOSE;
  3907. }
  3908. // ---- minimize button ----
  3909. _GetNcBtnHitTestRect( pncwm, HTMINBUTTON, FALSE, &rcButton );
  3910. if ( _StrictPtInRect( &rcButton, pt ) )
  3911. {
  3912. return HTMINBUTTON;
  3913. }
  3914. // ---- maximize button ----
  3915. _GetNcBtnHitTestRect( pncwm, HTMAXBUTTON, FALSE, &rcButton );
  3916. if ( _StrictPtInRect( &rcButton, pt ) )
  3917. {
  3918. return HTMAXBUTTON;
  3919. }
  3920. // ---- sys menu ----
  3921. _GetNcBtnHitTestRect( pncwm, HTSYSMENU, FALSE, &rcButton );
  3922. if ( _StrictPtInRect( &rcButton, pt ) )
  3923. {
  3924. return HTSYSMENU;
  3925. }
  3926. // ---- help button ----
  3927. _GetNcBtnHitTestRect( pncwm, HTHELP, FALSE, &rcButton );
  3928. if ( _StrictPtInRect( &rcButton, pt ) )
  3929. {
  3930. return HTHELP;
  3931. }
  3932. #ifdef LAME_BUTTON
  3933. if ( TESTFLAG(pncwm->dwExStyle, WS_EX_LAMEBUTTON) )
  3934. {
  3935. if ( _StrictPtInRect( &pncwm->rcS0[NCRC_LAMEBTN], pt ) )
  3936. return HTLAMEBUTTON;
  3937. }
  3938. #endif // LAME_BUTTON
  3939. // don't need a mirrored point for the remaining hittests
  3940. MAKEPOINT( pt, ptm->lParam );
  3941. if( !_StrictPtInRect( &pncwm->rcS0[NCRC_CONTENT], pt ) )
  3942. {
  3943. if( pncwm->fMin || pncwm->fMaxed )
  3944. {
  3945. if( _StrictPtInRect( &pncwm->rcS0[NCRC_CAPTION], pt ) )
  3946. return HTCAPTION;
  3947. }
  3948. //---- combined caption/frame case ----
  3949. return pwnd->NcBackgroundHitTest( pt, &pncwm->rcS0[NCRC_WINDOW], pncwm->dwStyle, pncwm->dwExStyle,
  3950. pncwm->framestate, pncwm->rgframeparts, pncwm->rgsizehitparts,
  3951. pncwm->rcS0 + NCRC_FRAMEFIRST );
  3952. }
  3953. }
  3954. }
  3955. return DoMsgDefault( ptm );
  3956. }
  3957. //-------------------------------------------------------------------------//
  3958. // WM_WINDOWPOSCHANGING pre-wndproc override handler
  3959. LRESULT CALLBACK OnOwpPreWindowPosChanging( CThemeWnd* pwnd, THEME_MSG *ptm )
  3960. {
  3961. if( pwnd->IsFrameThemed() )
  3962. {
  3963. // Suppress WM_WINDOWPOSCHANGING from being sent to wndproc if it
  3964. // was generated by us calling SetWindowRgn.
  3965. // Many apps (e.g. Adobe Acrobat Reader, Photoshop dialogs, etc) that handle
  3966. // WM_NCCALCSIZE, WM_WINDOWPOSCHANGING and/or WM_WINDOWPOSCHANGED are not
  3967. // reentrant on their handlers for these messages, and therefore botch the
  3968. // recursion induced by our SetWindowRgn call when we post-process
  3969. // WM_WINDOWPOSCHANGED.
  3970. // There is no reason that a theme-complient wndproc should ever know that
  3971. // it's window(s) host a region managed by the system.
  3972. if( pwnd->AssigningFrameRgn() )
  3973. {
  3974. MsgHandled(ptm);
  3975. return DefWindowProc(ptm->hwnd, ptm->uMsg, ptm->wParam, ptm->lParam);
  3976. }
  3977. }
  3978. return 0L;
  3979. }
  3980. //-------------------------------------------------------------------------//
  3981. // WM_WINDOWPOSCHANGED pre-wndproc override handler
  3982. LRESULT CALLBACK OnOwpPreWindowPosChanged( CThemeWnd* pwnd, THEME_MSG *ptm )
  3983. {
  3984. if( pwnd->IsFrameThemed() )
  3985. {
  3986. // Suppress WM_WINDOWPOSCHANGING from being sent to wndproc if it
  3987. // was generated by us calling SetWindowRgn.
  3988. // Many apps (e.g. Adobe Acrobat Reader, Photoshop dialogs, etc) that handle
  3989. // WM_NCCALCSIZE, WM_WINDOWPOSCHANGING and/or WM_WINDOWPOSCHANGED are not
  3990. // reentrant on their handlers for these messages, and therefore botch the
  3991. // recursion induced by our SetWindowRgn call when we post-process
  3992. // WM_WINDOWPOSCHANGED.
  3993. // There is no reason that a theme-complient wndproc should ever know that
  3994. // it's window(s) host a region managed by the system.
  3995. if( pwnd->AssigningFrameRgn() )
  3996. {
  3997. MsgHandled(ptm);
  3998. return DefWindowProc(ptm->hwnd, ptm->uMsg, ptm->wParam, ptm->lParam);
  3999. }
  4000. }
  4001. return 0L;
  4002. }
  4003. //-------------------------------------------------------------------------//
  4004. // WM_WINDOWPOSCHANGED message handler
  4005. inline LRESULT WindowPosChangedWorker( CThemeWnd* pwnd, THEME_MSG *ptm )
  4006. {
  4007. if( pwnd->IsRevoked(RF_DEFER) )
  4008. {
  4009. if( !pwnd->IsRevoked(RF_INREVOKE) )
  4010. {
  4011. pwnd->Revoke(); // don't touch PWND after this!
  4012. }
  4013. }
  4014. else if( pwnd->IsNcThemed() && !IsWindowInDestroy(*pwnd) )
  4015. {
  4016. // If were not resizing, update the window region.
  4017. if( pwnd->IsFrameThemed() )
  4018. {
  4019. NCWNDMET* pncwm = NULL;
  4020. NCTHEMEMET nctm = {0};
  4021. // Freshen per-window metrics
  4022. if( !pwnd->AssigningFrameRgn() )
  4023. {
  4024. WINDOWPOS *pWndPos = (WINDOWPOS*) ptm->lParam;
  4025. // Freshen this window's per-window metrics
  4026. pwnd->GetNcWindowMetrics( NULL, &pncwm, &nctm, NCWMF_RECOMPUTE );
  4027. // Freshen window metrics for nc-themed children (e.g., MDI child frames)
  4028. EnumChildWindows( *pwnd, _FreshenThemeMetricsCB, NULL );
  4029. if( !TESTFLAG(pWndPos->flags, SWP_NOSIZE) || pwnd->DirtyFrameRgn() ||
  4030. TESTFLAG(pWndPos->flags, SWP_FRAMECHANGED) )
  4031. {
  4032. if( pWndPos->cx > 0 && pWndPos->cy > 0 )
  4033. {
  4034. pwnd->AssignFrameRgn( TRUE, FTF_REDRAW );
  4035. }
  4036. }
  4037. }
  4038. }
  4039. _MDIUpdate( *pwnd, ((WINDOWPOS*) ptm->lParam)->flags);
  4040. }
  4041. return 0L;
  4042. }
  4043. //-------------------------------------------------------------------------//
  4044. // WM_WINDOWPOSCHANGED post-wndproc override handler
  4045. //
  4046. // Note: we'll handle this post-wndproc for normal, client-side wndprocs
  4047. LRESULT CALLBACK OnOwpPostWindowPosChanged( CThemeWnd* pwnd, THEME_MSG *ptm )
  4048. {
  4049. if( !IsServerSideWindow(ptm->hwnd) )
  4050. {
  4051. return WindowPosChangedWorker( pwnd, ptm );
  4052. }
  4053. return 0L;
  4054. }
  4055. //-------------------------------------------------------------------------//
  4056. // WM_WINDOWPOSCHANGED DefWindowProc override handler.
  4057. //
  4058. // Note: we'll handle this in DefWindowProc only for windows with win32k-based
  4059. // wndprocs, which are deprived of OWP callbacks.
  4060. LRESULT CALLBACK OnDwpWindowPosChanged( CThemeWnd* pwnd, THEME_MSG *ptm )
  4061. {
  4062. if( IsServerSideWindow(ptm->hwnd) )
  4063. {
  4064. WindowPosChangedWorker( pwnd, ptm );
  4065. }
  4066. return 0L;
  4067. }
  4068. //-------------------------------------------------------------------------//
  4069. // WM_NACTIVATE DefWindowProc msg handler
  4070. LRESULT CALLBACK OnDwpNcActivate( CThemeWnd* pwnd, THEME_MSG *ptm )
  4071. {
  4072. LRESULT lRet = 1L;
  4073. if( pwnd->IsNcThemed() )
  4074. {
  4075. // We need to forward on. The DWP remembers the state
  4076. // and MFC apps (for one) need this as well
  4077. // but we don't want to actually paint, so lock the window
  4078. ptm->lParam = (LPARAM)-1;
  4079. lRet = DoMsgDefault(ptm);
  4080. pwnd->NcPaint( NULL, ptm->wParam ? NCPF_ACTIVEFRAME : NCPF_INACTIVEFRAME, NULL, NULL );
  4081. MsgHandled(ptm);
  4082. }
  4083. return lRet;
  4084. }
  4085. //-------------------------------------------------------------------------//
  4086. BOOL CThemeWnd::ShouldTrackFrameButton( UINT uHitcode )
  4087. {
  4088. switch(uHitcode)
  4089. {
  4090. case HTHELP:
  4091. return TESTFLAG(_ncwm.dwExStyle, WS_EX_CONTEXTHELP);
  4092. case HTMAXBUTTON:
  4093. if( !TESTFLAG(_ncwm.dwStyle, WS_MAXIMIZEBOX) ||
  4094. (CBS_DISABLED == _ncwm.rawMaxBtnState && FS_ACTIVE == _ncwm.framestate) )
  4095. {
  4096. break;
  4097. }
  4098. return TRUE;
  4099. case HTMINBUTTON:
  4100. if( !TESTFLAG(_ncwm.dwStyle, WS_MINIMIZEBOX) ||
  4101. (CBS_DISABLED == _ncwm.rawMinBtnState && FS_ACTIVE == _ncwm.framestate) )
  4102. {
  4103. break;
  4104. }
  4105. return TRUE;
  4106. case HTCLOSE:
  4107. if( !_MNCanClose(_hwnd) ||
  4108. (CBS_DISABLED == _ncwm.rawCloseBtnState && FS_ACTIVE == _ncwm.framestate) )
  4109. {
  4110. break;
  4111. }
  4112. return TRUE;
  4113. case HTSYSMENU:
  4114. return TESTFLAG(_ncwm.dwStyle, WS_SYSMENU);
  4115. }
  4116. return FALSE;
  4117. }
  4118. //-------------------------------------------------------------------------//
  4119. // WM_NCLBUTTONDOWN DefWindowProc msg handler
  4120. LRESULT CALLBACK OnDwpNcLButtonDown( CThemeWnd* pwnd, THEME_MSG *ptm )
  4121. {
  4122. WPARAM uSysCmd = 0;
  4123. MsgHandled( ptm );
  4124. switch( ptm->wParam /* hittest code */ )
  4125. {
  4126. case HTHELP:
  4127. case HTMAXBUTTON:
  4128. case HTMINBUTTON:
  4129. case HTCLOSE:
  4130. case HTSYSMENU:
  4131. if( pwnd->ShouldTrackFrameButton(ptm->wParam) )
  4132. {
  4133. if( pwnd->HasRenderedNcPart(RNCF_CAPTION) )
  4134. {
  4135. POINT pt;
  4136. MAKEPOINT( pt, ptm->lParam );
  4137. if( !pwnd->TrackFrameButton( *pwnd, (int)ptm->wParam, &uSysCmd ) )
  4138. {
  4139. return DoMsgDefault( ptm );
  4140. }
  4141. }
  4142. else
  4143. {
  4144. return DoMsgDefault( ptm );
  4145. }
  4146. }
  4147. break;
  4148. case HTHSCROLL:
  4149. case HTVSCROLL:
  4150. if( pwnd->HasRenderedNcPart(RNCF_SCROLLBAR) )
  4151. {
  4152. uSysCmd = ptm->wParam | ((ptm->wParam == HTVSCROLL) ? SC_HSCROLL:SC_VSCROLL);
  4153. break;
  4154. }
  4155. // fall thru
  4156. default:
  4157. return DoMsgDefault( ptm );
  4158. }
  4159. // TODO USER will ignore system command if it is disabled on system menu here,
  4160. // don't know why. Imitating the code caused standard min/max/close buttons to
  4161. // render so be careful.
  4162. if( uSysCmd != 0 )
  4163. {
  4164. SendMessage( *pwnd, WM_SYSCOMMAND, uSysCmd, ptm->lParam );
  4165. }
  4166. return 0L;
  4167. }
  4168. //-------------------------------------------------------------------------//
  4169. // WM_NCMOUSEMOVE DefWindowProc msg handler
  4170. LRESULT CALLBACK OnDwpNcMouseMove(CThemeWnd* pwnd, THEME_MSG *ptm)
  4171. {
  4172. LRESULT lRet = DoMsgDefault(ptm);
  4173. int htHotLast = pwnd->GetNcHotItem();
  4174. int htHot;
  4175. //
  4176. // If the mouse has just entered the NC area, request
  4177. // that we be notified when it leaves.
  4178. //
  4179. if (htHotLast == HTERROR)
  4180. {
  4181. TRACKMOUSEEVENT tme;
  4182. tme.cbSize = sizeof(tme);
  4183. tme.dwFlags = TME_LEAVE | TME_NONCLIENT;
  4184. tme.hwndTrack = *pwnd;
  4185. tme.dwHoverTime = 0;
  4186. TrackMouseEvent(&tme);
  4187. }
  4188. //
  4189. // Filter out the NC elements we don't care about hottracking. And only
  4190. // track the element if we've previously rendered it. Some apps handle
  4191. // painting non-client elements by handling ncpaint. They may not expect
  4192. // that we now hottrack.
  4193. //
  4194. if ( (IsHTFrameButton(ptm->wParam) && pwnd->HasRenderedNcPart(RNCF_CAPTION) &&
  4195. pwnd->ShouldTrackFrameButton(ptm->wParam)) ||
  4196. (IsHTScrollBar(ptm->wParam) && pwnd->HasRenderedNcPart(RNCF_SCROLLBAR)) )
  4197. {
  4198. htHot = (int)ptm->wParam;
  4199. }
  4200. else
  4201. {
  4202. htHot = HTNOWHERE;
  4203. }
  4204. //
  4205. // anything to do?
  4206. //
  4207. if ((htHot != htHotLast) || IsHTScrollBar(htHot) || IsHTScrollBar(htHotLast))
  4208. {
  4209. POINT pt;
  4210. MAKEPOINT( pt, ptm->lParam );
  4211. //
  4212. // save the hittest code of the NC element the mouse is
  4213. // currently over
  4214. //
  4215. pwnd->SetNcHotItem(htHot);
  4216. //
  4217. // Determine what should be repainted because the mouse
  4218. // is no longer over it
  4219. //
  4220. if ( IsHTFrameButton(htHotLast) && pwnd->HasRenderedNcPart(RNCF_CAPTION) )
  4221. {
  4222. pwnd->TrackFrameButton(*pwnd, htHotLast, NULL, TRUE);
  4223. }
  4224. else if ( IsHTScrollBar(htHotLast) && pwnd->HasRenderedNcPart(RNCF_SCROLLBAR) )
  4225. {
  4226. ScrollBar_MouseMove(*pwnd, (htHot == htHotLast) ? &pt : NULL, (htHotLast == HTVSCROLL) ? TRUE : FALSE);
  4227. }
  4228. //
  4229. // Determine what should be repainted because the mouse
  4230. // is now over it
  4231. //
  4232. if ( IsHTFrameButton(htHot) && pwnd->HasRenderedNcPart(RNCF_CAPTION) )
  4233. {
  4234. pwnd->TrackFrameButton(*pwnd, htHot, NULL, TRUE);
  4235. }
  4236. else if ( IsHTScrollBar(htHot) && pwnd->HasRenderedNcPart(RNCF_SCROLLBAR) )
  4237. {
  4238. ScrollBar_MouseMove(*pwnd, &pt, (htHot == HTVSCROLL) ? TRUE : FALSE);
  4239. }
  4240. }
  4241. return lRet;
  4242. }
  4243. //-------------------------------------------------------------------------//
  4244. // WM_NCMOUSELEAVE DefWindowProc msg handler
  4245. LRESULT CALLBACK OnDwpNcMouseLeave(CThemeWnd* pwnd, THEME_MSG *ptm)
  4246. {
  4247. LRESULT lRet = DoMsgDefault(ptm);
  4248. int htHot = pwnd->GetNcHotItem();
  4249. //
  4250. // the mouse has left NC area, nothing should be drawn in the
  4251. // hot state anymore
  4252. //
  4253. pwnd->SetNcHotItem(HTERROR);
  4254. if ( IsHTFrameButton(htHot) && pwnd->ShouldTrackFrameButton(htHot) &&
  4255. pwnd->HasRenderedNcPart(RNCF_CAPTION) )
  4256. {
  4257. pwnd->TrackFrameButton(*pwnd, htHot, NULL, TRUE);
  4258. }
  4259. else if ( IsHTScrollBar(htHot) && pwnd->HasRenderedNcPart(RNCF_SCROLLBAR) )
  4260. {
  4261. ScrollBar_MouseMove(*pwnd, NULL, (htHot == HTVSCROLL) ? TRUE : FALSE);
  4262. }
  4263. return lRet;
  4264. }
  4265. //-------------------------------------------------------------------------//
  4266. // WM_CONTEXTMENU DefWindowProc msg handler
  4267. LRESULT CALLBACK OnDwpContextMenu(CThemeWnd* pwnd, THEME_MSG *ptm)
  4268. {
  4269. NCWNDMET* pncwm;
  4270. POINT pt;
  4271. MAKEPOINT( pt, ptm->lParam );
  4272. MsgHandled( ptm );
  4273. if( pwnd->GetNcWindowMetrics( NULL, &pncwm, NULL, 0 ) )
  4274. {
  4275. if ( TESTFLAG(pncwm->dwExStyle, WS_EX_LAYOUTRTL) )
  4276. {
  4277. // mirror the point to hittest correctly
  4278. MIRROR_POINT(pncwm->rcS0[NCRC_WINDOW], pt);
  4279. }
  4280. if( _StrictPtInRect( &pncwm->rcS0[NCRC_HSCROLL], pt ) )
  4281. {
  4282. ScrollBar_Menu(*pwnd, *pwnd, ptm->lParam, FALSE);
  4283. return 0;
  4284. }
  4285. if( _StrictPtInRect( &pncwm->rcS0[NCRC_VSCROLL], pt ) )
  4286. {
  4287. ScrollBar_Menu(*pwnd, *pwnd, ptm->lParam, TRUE);
  4288. return 0;
  4289. }
  4290. }
  4291. return DoMsgDefault( ptm );
  4292. }
  4293. //-------------------------------------------------------------------------//
  4294. // WM_SYSCOMMAND DefWindowProc msg handler
  4295. LRESULT CALLBACK OnDwpSysCommand( CThemeWnd* pwnd, THEME_MSG *ptm )
  4296. {
  4297. LRESULT lRet = 0L;
  4298. switch( ptm->wParam & ~0x0F )
  4299. {
  4300. // Handle scroll commands
  4301. case SC_VSCROLL:
  4302. case SC_HSCROLL:
  4303. HandleScrollCmd( *pwnd, ptm->wParam, ptm->lParam );
  4304. MsgHandled( ptm );
  4305. return lRet;
  4306. }
  4307. return DoMsgDefault( ptm );
  4308. }
  4309. //-------------------------------------------------------------------------//
  4310. // MDI menubar button theme/untheme wrapper
  4311. void CThemeWnd::ThemeMDIMenuButtons( BOOL fTheme, BOOL fRedraw )
  4312. {
  4313. // Verify we're an MDI frame with a maximized mdi child
  4314. if( _hwndMDIClient && !IsWindowInDestroy(_hwndMDIClient) )
  4315. {
  4316. BOOL fMaxed = FALSE;
  4317. HWND hwndActive = _MDIGetActive( _hwndMDIClient, &fMaxed );
  4318. if( hwndActive && fMaxed )
  4319. {
  4320. ModifyMDIMenubar(fTheme, fRedraw );
  4321. }
  4322. }
  4323. }
  4324. //-------------------------------------------------------------------------//
  4325. // MDI menubar button theme/untheme worker
  4326. void CThemeWnd::ModifyMDIMenubar( BOOL fTheme, BOOL fRedraw )
  4327. {
  4328. _fThemedMDIBtns = FALSE;
  4329. if( IsFrameThemed() || !fTheme )
  4330. {
  4331. MENUBARINFO mbi;
  4332. mbi.cbSize = sizeof(mbi);
  4333. if( GetMenuBarInfo( _hwnd, OBJID_MENU, 0, &mbi ) )
  4334. {
  4335. _NcTraceMsg( NCTF_MDIBUTTONS, TEXT("ModifyMDIMenubar: GetMenuBarInfo() returns hMenu: %08lX, hwndMenu: %08lX"), mbi.hMenu, mbi.hwndMenu );
  4336. int cItems = GetMenuItemCount( mbi.hMenu );
  4337. int cThemedItems = 0;
  4338. int cRedraw = 0;
  4339. _NcTraceMsg( NCTF_MDIBUTTONS, TEXT("ModifyMDIMenubar: on entry, GetMenuItemCount(hMenu = %08lX) returns %d"), mbi.hMenu, cItems );
  4340. if( cItems > 0 )
  4341. {
  4342. for( int i = cItems - 1; i >= 0 && cThemedItems < MDIBTNCOUNT; i-- )
  4343. {
  4344. MENUITEMINFO mii;
  4345. mii.cbSize = sizeof(mii);
  4346. mii.fMask = MIIM_ID|MIIM_STATE|MIIM_FTYPE|MIIM_BITMAP;
  4347. if( GetMenuItemInfo( mbi.hMenu, i, TRUE, &mii ) )
  4348. {
  4349. _NcTraceMsg( NCTF_MDIBUTTONS, TEXT("GetMenuItemInfo by pos (%d) returns ID %04lX"), i, mii.wID );
  4350. switch( mii.wID )
  4351. {
  4352. case SC_RESTORE:
  4353. case SC_MINIMIZE:
  4354. case SC_CLOSE:
  4355. {
  4356. BOOL fThemed = TESTFLAG(mii.fType, MFT_OWNERDRAW);
  4357. if( (fThemed && fTheme) || (fThemed == fTheme) )
  4358. {
  4359. cThemedItems = MDIBTNCOUNT; // one item is already done, assume all to be.
  4360. }
  4361. else
  4362. {
  4363. CMdiBtns* pBtns = LoadMdiBtns( NULL, mii.wID );
  4364. if( pBtns )
  4365. {
  4366. if( pBtns->ThemeItem( mbi.hMenu, i, &mii, fTheme ) )
  4367. {
  4368. cThemedItems++;
  4369. cRedraw++;
  4370. _NcTraceMsg( NCTF_MDIBUTTONS, TEXT("ModifyMDIMenubar: on entry, GetMenuItemCount(hMenu = %08lX) returns %d"), mbi.hMenu, GetMenuItemCount(mbi.hMenu) );
  4371. }
  4372. }
  4373. }
  4374. break;
  4375. }
  4376. }
  4377. }
  4378. }
  4379. }
  4380. if( cThemedItems )
  4381. {
  4382. _fThemedMDIBtns = fTheme;
  4383. if( fRedraw && cRedraw )
  4384. {
  4385. DrawMenuBar( _hwnd );
  4386. }
  4387. }
  4388. _NcTraceMsg( NCTF_MDIBUTTONS, TEXT("ModifyMDIMenubar: Modified %d menu items, exiting"), cThemedItems );
  4389. }
  4390. }
  4391. }
  4392. //-------------------------------------------------------------------------//
  4393. BOOL CThemeWnd::_PreDefWindowProc(
  4394. HWND hwnd,
  4395. UINT uMsg,
  4396. WPARAM wParam,
  4397. LPARAM lParam,
  4398. LRESULT *plRet )
  4399. {
  4400. if (uMsg == WM_PRINTCLIENT)
  4401. {
  4402. PrintClientNotHandled(hwnd);
  4403. }
  4404. return FALSE;
  4405. }
  4406. //-------------------------------------------------------------------------//
  4407. BOOL CThemeWnd::_PostDlgProc(
  4408. HWND hwnd,
  4409. UINT uMsg,
  4410. WPARAM wParam,
  4411. LPARAM lParam,
  4412. LRESULT *plRet )
  4413. {
  4414. switch( uMsg )
  4415. {
  4416. case WM_PRINTCLIENT:
  4417. {
  4418. PrintClientNotHandled(hwnd);
  4419. }
  4420. break;
  4421. }
  4422. return FALSE;
  4423. }
  4424. //-------------------------------------------------------------------------//
  4425. // Handles Defwindowproc post-processing for unthemed windows.
  4426. BOOL CThemeWnd::_PostWndProc(
  4427. HWND hwnd,
  4428. UINT uMsg,
  4429. WPARAM wParam,
  4430. LPARAM lParam,
  4431. LRESULT *plRet )
  4432. {
  4433. switch( uMsg )
  4434. {
  4435. // Special-case WM_SYSCOMMAND for MDI frame window updates
  4436. case WM_WINDOWPOSCHANGED:
  4437. if( lParam /* don't trust this */)
  4438. {
  4439. _MDIUpdate( hwnd, ((WINDOWPOS*) lParam)->flags);
  4440. }
  4441. break;
  4442. case WM_MDISETMENU:
  4443. {
  4444. HWND hwndActive = _MDIGetActive(hwnd);
  4445. if( hwndActive )
  4446. _MDIChildUpdateParent( hwndActive, TRUE );
  4447. break;
  4448. }
  4449. }
  4450. return FALSE;
  4451. }
  4452. //-------------------------------------------------------------------------//
  4453. // WM_CREATE post-wndproc msg handler
  4454. LRESULT CALLBACK OnOwpPostCreate( CThemeWnd* pwnd, THEME_MSG *ptm )
  4455. {
  4456. if( -1 != ptm->lRet )
  4457. {
  4458. if( pwnd->TestCF( TWCF_FRAME|TWCF_TOOLFRAME ))
  4459. {
  4460. DWORD dwFTFlags = FTF_CREATE;
  4461. CREATESTRUCT* pcs = (CREATESTRUCT*)ptm->lParam;
  4462. if( pcs )
  4463. {
  4464. // don't resize dialogs until post-WM_INITDIALOG
  4465. if( pwnd->TestCF(TWCF_DIALOG) )
  4466. {
  4467. dwFTFlags |= FTF_NOMODIFYPLACEMENT;
  4468. }
  4469. pwnd->SetFrameTheme( dwFTFlags, NULL );
  4470. MsgHandled(ptm);
  4471. }
  4472. }
  4473. }
  4474. return 0L;
  4475. }
  4476. //---------------------------------------------------------------------------
  4477. // WM_INITDIALOG post defdialogproc handler
  4478. LRESULT CALLBACK OnDdpPostInitDialog(CThemeWnd* pwnd, THEME_MSG* ptm)
  4479. {
  4480. LRESULT lRet = ptm->lRet;
  4481. // Do this sequence for dialogs only
  4482. if( pwnd->TestCF( TWCF_DIALOG ) && pwnd->TestCF( TWCF_FRAME|TWCF_TOOLFRAME ) )
  4483. {
  4484. DWORD dwFTFlags = FTF_CREATE;
  4485. pwnd->SetFrameTheme( dwFTFlags, NULL );
  4486. MsgHandled(ptm);
  4487. }
  4488. return lRet;
  4489. }
  4490. //-------------------------------------------------------------------------//
  4491. // WM_STYLECHANGING/WM_SYTLECHANGED Pre DefWindowProc msg handler
  4492. LRESULT CALLBACK OnOwpPreStyleChange( CThemeWnd* pwnd, THEME_MSG *ptm )
  4493. {
  4494. // Allow this message to arrive at detination WndProc?
  4495. if ( pwnd->SuppressingStyleMsgs() )
  4496. {
  4497. MsgHandled(ptm);
  4498. return DefWindowProc(ptm->hwnd, ptm->uMsg, ptm->wParam, ptm->lParam);
  4499. }
  4500. return 0L;
  4501. }
  4502. //-------------------------------------------------------------------------//
  4503. // WM_SYTLECHANGED DefWindowProc msg handler
  4504. LRESULT CALLBACK OnDwpStyleChanged( CThemeWnd* pwnd, THEME_MSG *ptm )
  4505. {
  4506. pwnd->StyleChanged((UINT)ptm->wParam, ((STYLESTRUCT*)ptm->lParam)->styleOld,
  4507. ((STYLESTRUCT*)ptm->lParam)->styleNew );
  4508. return 0L;
  4509. }
  4510. //-------------------------------------------------------------------------//
  4511. // WM_SETTINGCHANGE post-wndproc handler
  4512. LRESULT CALLBACK OnOwpPostSettingChange( CThemeWnd* pwnd, THEME_MSG *ptm )
  4513. {
  4514. /*ignore theme setting change process refresh*/
  4515. if( SPI_SETNONCLIENTMETRICS == ptm->wParam && !pwnd->InThemeSettingChange() )
  4516. {
  4517. // recompute per-theme metrics.
  4518. if( VALID_CRITICALSECTION(&_csThemeMet) )
  4519. {
  4520. EnterCriticalSection( &_csThemeMet );
  4521. // force refresh of NONCLIENTMETRICS cache.
  4522. NcGetNonclientMetrics( NULL, TRUE );
  4523. LeaveCriticalSection( &_csThemeMet );
  4524. }
  4525. pwnd->UnloadMdiBtns();
  4526. // recycle frame icon handle; current one is no longer valid.
  4527. pwnd->AcquireFrameIcon( GetWindowLong(*pwnd, GWL_STYLE),
  4528. GetWindowLong(*pwnd, GWL_EXSTYLE), TRUE );
  4529. // frame windows should be invalidated.
  4530. if( pwnd->IsFrameThemed() )
  4531. {
  4532. SetWindowPos( *pwnd, NULL, 0,0,0,0, SWP_DRAWFRAME|
  4533. SWP_NOSIZE|SWP_NOMOVE|SWP_NOZORDER|SWP_NOACTIVATE );
  4534. }
  4535. }
  4536. return 0L;
  4537. }
  4538. //-------------------------------------------------------------------------//
  4539. // WM_SETTEXT DefWindowProc msg handler
  4540. LRESULT CALLBACK OnDwpSetText( CThemeWnd* pwnd, THEME_MSG *ptm )
  4541. {
  4542. LRESULT lRet = 0L;
  4543. if( pwnd->IsFrameThemed() )
  4544. {
  4545. // prevent ourselves from painting as we call on RealDefWindowProc()
  4546. // to cache the new window text.
  4547. pwnd->LockRedraw( TRUE );
  4548. lRet = DoMsgDefault(ptm);
  4549. pwnd->LockRedraw( FALSE );
  4550. }
  4551. return lRet;
  4552. }
  4553. //-------------------------------------------------------------------------//
  4554. // WM_SETICON DefWindowProc msg handler
  4555. LRESULT CALLBACK OnDwpSetIcon( CThemeWnd* pwnd, THEME_MSG *ptm )
  4556. {
  4557. LRESULT lRet = 0L;
  4558. // invalidate our app icon handle, force re-acquire.
  4559. pwnd->SetFrameIcon(NULL);
  4560. // call on RealDefWindowProc to cache the icon
  4561. lRet = DoMsgDefault( ptm );
  4562. // RealDefWindowProc won't call send a WM_NCUAHDRAWCAPTION for large icons
  4563. if( ICON_BIG == ptm->wParam && pwnd->IsFrameThemed() )
  4564. {
  4565. NCWNDMET* pncwm;
  4566. if( pwnd->GetNcWindowMetrics( NULL, &pncwm, NULL, NCWMF_RECOMPUTE ) )
  4567. {
  4568. HDC hdc = _GetNonclientDC( *pwnd, NULL );
  4569. if( hdc )
  4570. {
  4571. DTBGOPTS dtbo;
  4572. dtbo.dwSize = sizeof(dtbo);
  4573. dtbo.dwFlags = DTBG_DRAWSOLID;
  4574. pwnd->NcPaintCaption( hdc, pncwm, TRUE, (DWORD)DC_ICON, &dtbo );
  4575. ReleaseDC( *pwnd, hdc );
  4576. }
  4577. }
  4578. }
  4579. return lRet;
  4580. }
  4581. //-------------------------------------------------------------------------//
  4582. #define NCPREV_CLASS TEXT("NCPreviewFakeWindow")
  4583. //-------------------------------------------------------------------------//
  4584. BOOL _fPreviewSysMetrics = FALSE;
  4585. //-------------------------------------------------------------------------//
  4586. void _NcSetPreviewMetrics( BOOL fPreview )
  4587. {
  4588. BOOL fPrev = _fPreviewSysMetrics;
  4589. _fPreviewSysMetrics = fPreview;
  4590. if( fPreview != fPrev )
  4591. {
  4592. // make sure we reset button metrics if something has changed
  4593. _fClassicNcBtnMetricsReset = TRUE;
  4594. }
  4595. }
  4596. //-------------------------------------------------------------------------//
  4597. inline BOOL _NcUsingPreviewMetrics()
  4598. {
  4599. return _fPreviewSysMetrics;
  4600. }
  4601. //-------------------------------------------------------------------------//
  4602. BOOL NcGetNonclientMetrics( OUT OPTIONAL NONCLIENTMETRICS* pncm, BOOL fRefresh )
  4603. {
  4604. BOOL fRet = FALSE;
  4605. CInternalNonclientMetrics *pincm = NULL;
  4606. if( VALID_CRITICALSECTION(&_csNcSysMet) )
  4607. {
  4608. EnterCriticalSection( &_csNcSysMet );
  4609. // Feed off a static instance of NONCLIENTMETRICS to reduce call overhead.
  4610. if( _NcUsingPreviewMetrics() )
  4611. {
  4612. // hand off preview metrics and get out.
  4613. pincm = &_incmPreview;
  4614. }
  4615. else
  4616. {
  4617. if( _incmCurrent.Acquire( fRefresh ) )
  4618. {
  4619. pincm = &_incmCurrent;
  4620. }
  4621. }
  4622. if( pincm )
  4623. {
  4624. if( pncm )
  4625. {
  4626. *pncm = pincm->GetNcm();
  4627. }
  4628. fRet = TRUE;
  4629. }
  4630. LeaveCriticalSection( &_csNcSysMet );
  4631. }
  4632. return fRet;
  4633. }
  4634. //-------------------------------------------------------------------------//
  4635. HFONT NcGetCaptionFont( BOOL fSmallCaption )
  4636. {
  4637. HFONT hf = NULL;
  4638. if( VALID_CRITICALSECTION(&_csNcSysMet) )
  4639. {
  4640. EnterCriticalSection( &_csNcSysMet );
  4641. hf = _NcUsingPreviewMetrics() ? _incmPreview.GetFont( fSmallCaption ) :
  4642. _incmCurrent.GetFont( fSmallCaption );
  4643. LeaveCriticalSection( &_csNcSysMet );
  4644. }
  4645. return hf;
  4646. }
  4647. //-------------------------------------------------------------------------//
  4648. void NcClearNonclientMetrics()
  4649. {
  4650. _incmCurrent.Clear();
  4651. }
  4652. //-------------------------------------------------------------------------//
  4653. int NcGetSystemMetrics(int nIndex)
  4654. {
  4655. if( _NcUsingPreviewMetrics() )
  4656. {
  4657. int iValue;
  4658. const NONCLIENTMETRICS& ncmPreview = _incmPreview.GetNcm();
  4659. switch (nIndex)
  4660. {
  4661. case SM_CXHSCROLL: // fall through
  4662. case SM_CXVSCROLL: iValue = ncmPreview.iScrollWidth; break;
  4663. case SM_CYHSCROLL: // fall through
  4664. case SM_CYVSCROLL: iValue = ncmPreview.iScrollHeight; break;
  4665. case SM_CXSIZE: iValue = ncmPreview.iCaptionWidth; break;
  4666. case SM_CYSIZE: iValue = ncmPreview.iCaptionHeight; break;
  4667. case SM_CYCAPTION: iValue = ncmPreview.iCaptionHeight + 1; break;
  4668. case SM_CXSMSIZE: iValue = ncmPreview.iSmCaptionWidth; break;
  4669. case SM_CYSMSIZE: iValue = ncmPreview.iSmCaptionHeight; break;
  4670. case SM_CXMENUSIZE: iValue = ncmPreview.iMenuWidth; break;
  4671. case SM_CYMENUSIZE: iValue = ncmPreview.iMenuHeight; break;
  4672. default: iValue = ClassicGetSystemMetrics(nIndex); break;
  4673. }
  4674. return iValue;
  4675. }
  4676. else
  4677. {
  4678. return ClassicGetSystemMetrics(nIndex);
  4679. }
  4680. }
  4681. //-------------------------------------------------------------------------//
  4682. // _InternalGetSystemMetrics() - Themed implementation of GetSystemMetrics().
  4683. //
  4684. int _InternalGetSystemMetrics( int iMetric, BOOL& fHandled )
  4685. {
  4686. int iRet = 0;
  4687. int* plSysMet = NULL;
  4688. NCTHEMEMET nctm;
  4689. switch( iMetric )
  4690. {
  4691. case SM_CXSIZE:
  4692. plSysMet = &nctm.theme_sysmets.cxBtn; break;
  4693. case SM_CXSMSIZE:
  4694. plSysMet = &nctm.theme_sysmets.cxSmBtn; break;
  4695. }
  4696. if( plSysMet &&
  4697. GetCurrentNcThemeMetrics( &nctm ) && nctm.hTheme != NULL &&
  4698. nctm.theme_sysmets.fValid )
  4699. {
  4700. iRet = *plSysMet;
  4701. fHandled = TRUE; /*was missing (doh! - 408190)*/
  4702. }
  4703. return iRet;
  4704. }
  4705. //-------------------------------------------------------------------------//
  4706. // _InternalSystemParametersInfo() - Themed implementation of SystemParametersInfo().
  4707. //
  4708. // return value of FALSE interpreted by caller as not handled.
  4709. BOOL _InternalSystemParametersInfo(
  4710. IN UINT uiAction,
  4711. IN UINT uiParam,
  4712. IN OUT PVOID pvParam,
  4713. IN UINT fWinIni,
  4714. IN BOOL fUnicode,
  4715. BOOL& fHandled )
  4716. {
  4717. SYSTEMPARAMETERSINFO pfnDefault =
  4718. fUnicode ? ClassicSystemParametersInfoW : ClassicSystemParametersInfoA;\
  4719. BOOL fRet = pfnDefault( uiAction, uiParam, pvParam, fWinIni );
  4720. fHandled = TRUE;
  4721. if( SPI_GETNONCLIENTMETRICS == uiAction && fRet )
  4722. {
  4723. NCTHEMEMET nctm;
  4724. if( GetCurrentNcThemeMetrics( &nctm ) && nctm.hTheme != NULL && nctm.theme_sysmets.fValid )
  4725. {
  4726. NONCLIENTMETRICS* pncm = (NONCLIENTMETRICS*)pvParam;
  4727. pncm->iCaptionWidth = nctm.theme_sysmets.cxBtn;
  4728. }
  4729. }
  4730. return fRet;
  4731. }
  4732. //-------------------------------------------------------------------------//
  4733. THEMEAPI DrawNCWindow(CThemeWnd* pThemeWnd, HWND hwndFake, HDC hdc, DWORD dwFlags, LPRECT prc, NONCLIENTMETRICS* pncm, COLORREF* prgb)
  4734. {
  4735. // Build up Overide structure
  4736. NCPAINTOVERIDE ncpo;
  4737. pThemeWnd->GetNcWindowMetrics( prc, &ncpo.pncwm, &ncpo.nctm, NCWMF_RECOMPUTE|NCWMF_PREVIEW );
  4738. // Force window to look active
  4739. if (dwFlags & NCPREV_ACTIVEWINDOW)
  4740. {
  4741. ncpo.pncwm->framestate = FS_ACTIVE;
  4742. ncpo.pncwm->rawCloseBtnState =
  4743. ncpo.pncwm->rawMaxBtnState =
  4744. ncpo.pncwm->rawMinBtnState = CBS_NORMAL;
  4745. }
  4746. ncpo.pncwm->rgbCaption = prgb[FS_ACTIVE == ncpo.pncwm->framestate ? COLOR_CAPTIONTEXT : COLOR_INACTIVECAPTIONTEXT];
  4747. ncpo.pncwm->dwStyle &= ~WS_SIZEBOX;
  4748. // Paint the beautiful visual styled window
  4749. pThemeWnd->NcPaint(hdc, NCPF_DEFAULT, NULL, &ncpo);
  4750. COLORREF rgbBk = prgb[(dwFlags & NCPREV_MESSAGEBOX) ? COLOR_3DFACE : COLOR_WINDOW];
  4751. HBRUSH hbrBack = CreateSolidBrush(rgbBk);
  4752. FillRect(hdc, &ncpo.pncwm->rcW0[NCRC_CLIENT], hbrBack);
  4753. DeleteObject(hbrBack);
  4754. WCHAR szText[MAX_PATH];
  4755. // Draw client area
  4756. HFONT hfont = CreateFont(-MulDiv(8, GetDeviceCaps(hdc, LOGPIXELSY), 72), 0, 0, 0, FW_NORMAL, FALSE, FALSE, FALSE, DEFAULT_CHARSET, OUT_CHARACTER_PRECIS, CLIP_DEFAULT_PRECIS, DEFAULT_QUALITY, DEFAULT_PITCH, L"MS Shell Dlg");
  4757. if (hfont)
  4758. {
  4759. if (dwFlags & NCPREV_MESSAGEBOX)
  4760. {
  4761. HTHEME htheme = OpenThemeData( hwndFake, L"Button" );
  4762. int offsetX = ((ncpo.pncwm->rcW0[NCRC_CLIENT].right + ncpo.pncwm->rcW0[NCRC_CLIENT].left) / 2) - 40;
  4763. int offsetY = ((ncpo.pncwm->rcW0[NCRC_CLIENT].bottom + ncpo.pncwm->rcW0[NCRC_CLIENT].top) / 2) - 15;
  4764. RECT rcButton = { offsetX, offsetY, offsetX + 80, offsetY + 30 };
  4765. NcDrawThemeBackground(htheme, hdc, BP_PUSHBUTTON, PBS_DEFAULTED, &rcButton, 0);
  4766. RECT rcContent;
  4767. GetThemeBackgroundContentRect(htheme, hdc, BP_PUSHBUTTON, PBS_DEFAULTED, &rcButton, &rcContent);
  4768. LoadString(g_hInst, IDS_OKBUTTON, szText, ARRAYSIZE(szText));
  4769. if (szText[0])
  4770. {
  4771. HFONT hfontOld = (HFONT)SelectObject(hdc, hfont);
  4772. DrawThemeText(htheme, hdc, BP_PUSHBUTTON, PBS_DEFAULTED, szText, lstrlen(szText), DT_CENTER | DT_VCENTER | DT_SINGLELINE, 0, &rcContent);
  4773. SelectObject(hdc, hfontOld);
  4774. }
  4775. CloseThemeData(htheme);
  4776. }
  4777. else if (dwFlags & NCPREV_ACTIVEWINDOW)
  4778. {
  4779. HTHEME htheme = OpenThemeData( hwndFake, L"Button" );
  4780. RECT rcButton = ncpo.pncwm->rcW0[NCRC_CLIENT];
  4781. LoadString(g_hInst, IDS_WINDOWTEXT, szText, ARRAYSIZE(szText));
  4782. if (szText[0])
  4783. {
  4784. HFONT hfontOld = (HFONT)SelectObject(hdc, hfont);
  4785. DTTOPTS DttOpts = {sizeof(DttOpts)};
  4786. DttOpts.dwFlags = DTT_TEXTCOLOR;
  4787. DttOpts.crText = prgb[COLOR_WINDOWTEXT];
  4788. DrawThemeTextEx(htheme, hdc, BP_PUSHBUTTON, PBS_DEFAULTED, szText, lstrlen(szText), DT_SINGLELINE, &rcButton, &DttOpts);
  4789. SelectObject(hdc, hfontOld);
  4790. }
  4791. CloseThemeData(htheme);
  4792. }
  4793. }
  4794. DeleteObject(hfont);
  4795. ClearNcThemeMetrics(&ncpo.nctm);
  4796. return S_OK;
  4797. }
  4798. //-------------------------------------------------------------------------//
  4799. THEMEAPI DrawNCPreview(HDC hdc, DWORD dwFlags, LPRECT prc, LPCWSTR pszVSPath, LPCWSTR pszVSColor, LPCWSTR pszVSSize, NONCLIENTMETRICS* pncm, COLORREF* prgb)
  4800. {
  4801. WNDCLASS wc;
  4802. // Create a fake Window and attach NC themeing to it
  4803. if (!GetClassInfo(g_hInst, NCPREV_CLASS, &wc)) {
  4804. wc.style = 0;
  4805. wc.lpfnWndProc = DefWindowProc;
  4806. wc.cbClsExtra = 0;
  4807. wc.cbWndExtra = 0;
  4808. wc.hInstance = g_hInst;
  4809. wc.hIcon = NULL;
  4810. wc.hCursor = LoadCursor(NULL, IDC_ARROW);
  4811. wc.hbrBackground = (HBRUSH)(COLOR_3DFACE+1);
  4812. wc.lpszMenuName = NULL;
  4813. wc.lpszClassName = NCPREV_CLASS;
  4814. if (!RegisterClass(&wc))
  4815. return FALSE;
  4816. }
  4817. _incmPreview = *pncm;
  4818. _incmPreview._fPreview = TRUE;
  4819. _NcSetPreviewMetrics( TRUE );
  4820. DWORD dwExStyle = WS_EX_DLGMODALFRAME | ((dwFlags & NCPREV_RTL) ? WS_EX_RTLREADING : 0);
  4821. HWND hwndFake = CreateWindowEx(dwExStyle, NCPREV_CLASS, L"", 0, 0, 0, RECTWIDTH(prc), RECTHEIGHT(prc), NULL, NULL, g_hInst, NULL);
  4822. if (hwndFake)
  4823. {
  4824. HTHEMEFILE htFile = NULL;
  4825. WCHAR szCurVSPath[MAX_PATH];
  4826. WCHAR szCurVSColor[MAX_PATH];
  4827. WCHAR szCurVSSize[MAX_PATH];
  4828. GetCurrentThemeName(szCurVSPath, ARRAYSIZE(szCurVSPath), szCurVSColor, ARRAYSIZE(szCurVSColor), szCurVSSize, ARRAYSIZE(szCurVSSize));
  4829. if ((lstrcmp(szCurVSPath, pszVSPath) != 0) ||
  4830. (lstrcmp(szCurVSColor, pszVSColor) != 0) ||
  4831. (lstrcmp(szCurVSSize, pszVSSize) != 0))
  4832. {
  4833. HRESULT hr = OpenThemeFile(pszVSPath, pszVSColor, pszVSSize, &htFile, FALSE);
  4834. if (SUCCEEDED(hr))
  4835. {
  4836. //---- first, detach from the normal theme ----
  4837. CThemeWnd::Detach(hwndFake, FALSE);
  4838. //---- apply the preview theme ----
  4839. hr = ApplyTheme(htFile, 0, hwndFake);
  4840. }
  4841. }
  4842. //---- attach to the preview theme ----
  4843. CThemeWnd* pThemeWnd = CThemeWnd::Attach(hwndFake);
  4844. if (VALID_THEMEWND(pThemeWnd))
  4845. {
  4846. struct {
  4847. DWORD dwNcPrev;
  4848. UINT uIDStr;
  4849. DWORD dwFlags;
  4850. RECT rc;
  4851. } fakeWindow[]= { {NCPREV_INACTIVEWINDOW, IDS_INACTIVEWINDOW, 0, { prc->left, prc->top, prc->right - 17, prc->bottom - 20 }},
  4852. {NCPREV_ACTIVEWINDOW, IDS_ACTIVEWINDOW, NCPREV_ACTIVEWINDOW, { prc->left + 10, prc->top + 22, prc->right, prc->bottom }},
  4853. {NCPREV_MESSAGEBOX, IDS_MESSAGEBOX, NCPREV_ACTIVEWINDOW | NCPREV_MESSAGEBOX, { prc->left + (RECTWIDTH(prc)/2) - 75, prc->top + (RECTHEIGHT(prc)/2) - 50 + 22,
  4854. prc->left + (RECTWIDTH(prc)/2) + 75, prc->top + (RECTHEIGHT(prc)/2) + 50 + 22}}};
  4855. WCHAR szWindowName[MAX_PATH];
  4856. for (int i = 0; i < ARRAYSIZE(fakeWindow); i++)
  4857. {
  4858. if (dwFlags & fakeWindow[i].dwNcPrev)
  4859. {
  4860. LoadString(g_hInst, fakeWindow[i].uIDStr, szWindowName, ARRAYSIZE(szWindowName));
  4861. SetWindowText(hwndFake, szWindowName);
  4862. if (fakeWindow[i].dwNcPrev & NCPREV_MESSAGEBOX)
  4863. {
  4864. SetWindowLongPtr(hwndFake, GWL_STYLE, WS_TILED | WS_CAPTION | WS_SYSMENU);
  4865. }
  4866. else
  4867. {
  4868. SetWindowLongPtr(hwndFake, GWL_STYLE, WS_TILEDWINDOW | WS_VSCROLL);
  4869. }
  4870. DrawNCWindow(pThemeWnd, hwndFake, hdc, fakeWindow[i].dwFlags, &fakeWindow[i].rc, pncm, prgb);
  4871. }
  4872. }
  4873. // Clean Up
  4874. CThemeWnd::Detach(hwndFake, 0);
  4875. }
  4876. if (htFile)
  4877. {
  4878. CloseThemeFile(htFile);
  4879. //---- clear the preview hold on the theme file ----
  4880. ApplyTheme(NULL, 0, hwndFake);
  4881. }
  4882. DestroyWindow(hwndFake);
  4883. }
  4884. _NcSetPreviewMetrics( FALSE );
  4885. _incmPreview.Clear();
  4886. return S_OK;
  4887. }
  4888. //-------------------------------------------------------------------------//
  4889. // CMdiBtns impl
  4890. //-------------------------------------------------------------------------//
  4891. //-------------------------------------------------------------------------//
  4892. // ctor
  4893. CMdiBtns::CMdiBtns()
  4894. {
  4895. ZeroMemory( _rgBtns, sizeof(_rgBtns) );
  4896. _rgBtns[0].wID = SC_CLOSE;
  4897. _rgBtns[1].wID = SC_RESTORE;
  4898. _rgBtns[2].wID = SC_MINIMIZE;
  4899. }
  4900. //-------------------------------------------------------------------------//
  4901. // Helper: button lookup based on syscmd ID.
  4902. CMdiBtns::MDIBTN* CMdiBtns::_FindBtn( UINT wID )
  4903. {
  4904. for( int i = 0; i < ARRAYSIZE(_rgBtns); i++ )
  4905. {
  4906. if( wID == _rgBtns[i].wID )
  4907. {
  4908. return (_rgBtns + i);
  4909. }
  4910. }
  4911. return NULL;
  4912. }
  4913. //-------------------------------------------------------------------------//
  4914. // Acquires MDI button resources,.computes metrics
  4915. BOOL CMdiBtns::Load( HTHEME hTheme, IN OPTIONAL HDC hdc, UINT uSysCmd )
  4916. {
  4917. // if caller wants all buttons loaded, call recursively.
  4918. if( 0 == uSysCmd )
  4919. {
  4920. return Load( hTheme, hdc, SC_CLOSE ) &&
  4921. Load( hTheme, hdc, SC_RESTORE ) &&
  4922. Load( hTheme, hdc, SC_MINIMIZE );
  4923. }
  4924. MDIBTN* pBtn = _FindBtn( uSysCmd );
  4925. if( pBtn && !VALID_WINDOWPART(pBtn->iPartId) /*only if necessary*/ )
  4926. {
  4927. // select appropriate window part
  4928. WINDOWPARTS iPartId = BOGUS_WINDOWPART;
  4929. switch( uSysCmd )
  4930. {
  4931. case SC_CLOSE: iPartId = WP_MDICLOSEBUTTON; break;
  4932. case SC_RESTORE: iPartId = WP_MDIRESTOREBUTTON; break;
  4933. case SC_MINIMIZE: iPartId = WP_MDIMINBUTTON; break;
  4934. }
  4935. if( VALID_WINDOWPART(iPartId) )
  4936. {
  4937. if( IsThemePartDefined( hTheme, iPartId, 0) )
  4938. {
  4939. // Retrieve sizing type, defaulting to 'stretch'.
  4940. if( FAILED( GetThemeInt( hTheme, iPartId, 0, TMT_SIZINGTYPE, (int*)&pBtn->sizingType ) ) )
  4941. {
  4942. pBtn->sizingType = ST_STRETCH;
  4943. }
  4944. // if 'truesize', retrieve the size.
  4945. if( ST_TRUESIZE == pBtn->sizingType )
  4946. {
  4947. // If no DC provided, base size on screen DC of default monitor.
  4948. HDC hdcSize = hdc;
  4949. if( NULL == hdcSize )
  4950. {
  4951. hdcSize = GetDC(NULL);
  4952. }
  4953. if( FAILED( GetThemePartSize( hTheme, hdc, iPartId, 0, NULL, TS_TRUE, &pBtn->size ) ) )
  4954. {
  4955. pBtn->sizingType = ST_STRETCH;
  4956. }
  4957. if( hdcSize != hdc )
  4958. {
  4959. ReleaseDC(NULL, hdcSize);
  4960. }
  4961. }
  4962. // not 'truesize'; use system metrics for MDI buttons
  4963. if( pBtn->sizingType != ST_TRUESIZE )
  4964. {
  4965. pBtn->size.cx = NcGetSystemMetrics( SM_CXMENUSIZE );
  4966. pBtn->size.cy = NcGetSystemMetrics( SM_CYMENUSIZE );
  4967. }
  4968. // assign button attributes
  4969. pBtn->iPartId = iPartId;
  4970. }
  4971. }
  4972. }
  4973. return pBtn != NULL && VALID_WINDOWPART(pBtn->iPartId);
  4974. }
  4975. //-------------------------------------------------------------------------//
  4976. // Releases MDI button resources,.resets metrics
  4977. void CMdiBtns::Unload( IN OPTIONAL UINT uSysCmd )
  4978. {
  4979. // if caller wants all buttons unloaded, call recursively.
  4980. if( 0 == uSysCmd )
  4981. {
  4982. Unload( SC_CLOSE );
  4983. Unload( SC_RESTORE );
  4984. Unload( SC_MINIMIZE );
  4985. return;
  4986. }
  4987. MDIBTN* pBtn = _FindBtn( uSysCmd );
  4988. if( pBtn )
  4989. {
  4990. SAFE_DELETE_GDIOBJ(pBtn->hbmTheme);
  4991. ZeroMemory(pBtn, sizeof(*pBtn));
  4992. // restore our zeroed syscommand value
  4993. pBtn->wID = uSysCmd;
  4994. }
  4995. }
  4996. //-------------------------------------------------------------------------//
  4997. // Theme/untheme MDI frame menubar's Minimize, Restore, Close menu items.
  4998. BOOL CMdiBtns::ThemeItem( HMENU hMenu, int iPos, MENUITEMINFO* pmii, BOOL fTheme )
  4999. {
  5000. // To theme, we simply make the item owner draw. To untheme,
  5001. // we restore it to system-drawn.
  5002. BOOL fRet = FALSE;
  5003. MDIBTN* pBtn = _FindBtn( pmii->wID );
  5004. if( pBtn && pmii && hMenu )
  5005. {
  5006. if( fTheme )
  5007. {
  5008. // save off previous menuitem type, bitmap
  5009. pBtn->fTypePrev = pmii->fType;
  5010. pBtn->hbmPrev = pmii->hbmpItem;
  5011. pmii->fType &= ~MFT_BITMAP;
  5012. pmii->fType |= MFT_OWNERDRAW|MFT_RIGHTJUSTIFY;
  5013. pmii->hbmpItem = NULL;
  5014. }
  5015. else
  5016. {
  5017. // restore menuitem type, bitmap
  5018. pmii->fType = pBtn->fTypePrev|MFT_RIGHTJUSTIFY /*409042 - force right-justify on the way out*/;
  5019. pmii->hbmpItem = pBtn->hbmPrev;
  5020. }
  5021. pmii->fMask = MIIM_FTYPE;
  5022. fRet = SetMenuItemInfo( hMenu, iPos, TRUE, pmii );
  5023. if( !fRet || !fTheme )
  5024. {
  5025. pBtn->fTypePrev = 0;
  5026. pBtn->hbmPrev = NULL;
  5027. }
  5028. }
  5029. return fRet;
  5030. }
  5031. //-------------------------------------------------------------------------//
  5032. // Computes button state identifier from Win32 owner draw state
  5033. CLOSEBUTTONSTATES CMdiBtns::_CalcState( ULONG ulOwnerDrawAction, ULONG ulOwnerDrawState )
  5034. {
  5035. CLOSEBUTTONSTATES iStateId = CBS_NORMAL;
  5036. if( TESTFLAG(ulOwnerDrawState, ODS_DISABLED|ODS_GRAYED|ODS_INACTIVE) )
  5037. {
  5038. iStateId = CBS_DISABLED;
  5039. }
  5040. else if( TESTFLAG(ulOwnerDrawState, ODS_SELECTED) )
  5041. {
  5042. iStateId = CBS_PUSHED;
  5043. }
  5044. else if( TESTFLAG(ulOwnerDrawState, ODS_HOTLIGHT) )
  5045. {
  5046. iStateId = CBS_HOT;
  5047. }
  5048. return iStateId;
  5049. }
  5050. //-------------------------------------------------------------------------//
  5051. // MDI sys button WM_DRAWITEM handler
  5052. BOOL CMdiBtns::Measure( HTHEME hTheme, MEASUREITEMSTRUCT* pmis )
  5053. {
  5054. MDIBTN* pBtn = _FindBtn( pmis->itemID );
  5055. if( pBtn && VALID_WINDOWPART(pBtn->iPartId) )
  5056. {
  5057. pmis->itemWidth = pBtn->size.cx;
  5058. pmis->itemHeight = pBtn->size.cy;
  5059. return TRUE;
  5060. }
  5061. return FALSE;
  5062. }
  5063. //-------------------------------------------------------------------------//
  5064. // MDI sys button WM_DRAWITEM handler
  5065. BOOL CMdiBtns::Draw( HTHEME hTheme, DRAWITEMSTRUCT* pdis )
  5066. {
  5067. MDIBTN* pBtn = _FindBtn( pdis->itemID );
  5068. if( pBtn && VALID_WINDOWPART(pBtn->iPartId) )
  5069. {
  5070. return SUCCEEDED(NcDrawThemeBackground(
  5071. hTheme, pdis->hDC, pBtn->iPartId, _CalcState( pdis->itemAction, pdis->itemState ), &pdis->rcItem, 0 ));
  5072. }
  5073. return FALSE;
  5074. }
  5075. //-------------------------------------------------------------------------////
  5076. // "Comments?" link in caption bar, known as the PHellyar (lame) button
  5077. //-------------------------------------------------------------------------//
  5078. #ifdef LAME_BUTTON
  5079. //-------------------------------------------------------------------------//
  5080. WCHAR g_szLameText[50] = {0};
  5081. //-------------------------------------------------------------------------//
  5082. #define SZ_LAMETEXT_SUBKEY TEXT("Control Panel\\Desktop")
  5083. #define SZ_LAMETEXT_VALUE TEXT("LameButtonText")
  5084. #define SZ_LAMETEXT_DEFAULT TEXT("Comments?")
  5085. #define CLR_LAMETEXT RGB(91, 171, 245)
  5086. //-------------------------------------------------------------------------//
  5087. void InitLameText()
  5088. {
  5089. CCurrentUser hkeyCurrentUser(KEY_READ);
  5090. HKEY hkLame;
  5091. HRESULT hr = E_FAIL;
  5092. if ( RegOpenKeyEx(hkeyCurrentUser, SZ_LAMETEXT_SUBKEY, 0, KEY_QUERY_VALUE, &hkLame) == ERROR_SUCCESS )
  5093. {
  5094. hr = RegistryStrRead(hkLame, SZ_LAMETEXT_VALUE, g_szLameText, ARRAYSIZE(g_szLameText));
  5095. RegCloseKey(hkLame);
  5096. }
  5097. if ( FAILED(hr) )
  5098. {
  5099. StringCchCopyW(g_szLameText, ARRAYSIZE(g_szLameText), SZ_LAMETEXT_DEFAULT);
  5100. }
  5101. }
  5102. //-------------------------------------------------------------------------//
  5103. VOID CThemeWnd::InitLameResources()
  5104. {
  5105. //
  5106. // Using GetWindowInfo here bc GetWindowLong masks
  5107. // out the WS_EX_LAMEBUTTON bit.
  5108. //
  5109. SAFE_DELETE_GDIOBJ(_hFontLame);
  5110. WINDOWINFO wi = {0};
  5111. wi.cbSize = sizeof(wi);
  5112. if ( GetWindowInfo(_hwnd, &wi) && TESTFLAG(wi.dwExStyle, WS_EX_LAMEBUTTON) )
  5113. {
  5114. SIZE sizeLame;
  5115. HFONT hfCaption = NcGetCaptionFont(TESTFLAG(wi.dwExStyle, WS_EX_TOOLWINDOW));
  5116. if( hfCaption != NULL )
  5117. {
  5118. LOGFONT lfLame;
  5119. if( GetObject( hfCaption, sizeof(lfLame), &lfLame ) )
  5120. {
  5121. lfLame.lfHeight -= (lfLame.lfHeight > 0) ? 2 : -2;
  5122. lfLame.lfUnderline = TRUE;
  5123. lfLame.lfWeight = FW_THIN;
  5124. HFONT hFontLame = CreateFontIndirect(&lfLame);
  5125. if ( hFontLame != NULL )
  5126. {
  5127. HDC hdc = GetWindowDC(_hwnd);
  5128. if ( hdc != NULL )
  5129. {
  5130. SelectObject(hdc, hFontLame);
  5131. if (GetTextExtentPoint32(hdc, g_szLameText, lstrlen(g_szLameText), &sizeLame))
  5132. {
  5133. _hFontLame = hFontLame;
  5134. hFontLame = NULL; // don't free at end of this function
  5135. _sizeLame = sizeLame;
  5136. }
  5137. ReleaseDC(_hwnd, hdc);
  5138. }
  5139. }
  5140. if (hFontLame) // didn't assign this font
  5141. DeleteObject(hFontLame);
  5142. }
  5143. }
  5144. }
  5145. }
  5146. //-------------------------------------------------------------------------//
  5147. VOID CThemeWnd::ClearLameResources()
  5148. {
  5149. SAFE_DELETE_GDIOBJ(_hFontLame);
  5150. ZeroMemory( &_sizeLame, sizeof(_sizeLame) );
  5151. }
  5152. //-------------------------------------------------------------------------//
  5153. inline VOID CThemeWnd::DrawLameButton(HDC hdc, IN const NCWNDMET* pncwm)
  5154. {
  5155. if ( TESTFLAG(pncwm->dwExStyle, WS_EX_LAMEBUTTON) && _hFontLame )
  5156. {
  5157. Log(LOG_RFBUG, L"DrawLameButton; _hFontLame=0x%x", _hFontLame);
  5158. HFONT hFontSave = (HFONT)SelectObject(hdc, _hFontLame);
  5159. COLORREF clrSave = SetTextColor(hdc, CLR_LAMETEXT);
  5160. DrawText(hdc, g_szLameText, lstrlen(g_szLameText), (LPRECT)&pncwm->rcW0[NCRC_LAMEBTN],
  5161. DT_LEFT | DT_SINGLELINE);
  5162. SetTextColor(hdc, clrSave);
  5163. SelectObject(hdc, hFontSave);
  5164. }
  5165. }
  5166. //-------------------------------------------------------------------------//
  5167. VOID CThemeWnd::GetLameButtonMetrics( NCWNDMET* pncwm, const SIZE* psizeCaption )
  5168. {
  5169. if( TESTFLAG(pncwm->dwExStyle, WS_EX_LAMEBUTTON) && _hFontLame )
  5170. {
  5171. BOOL fLameOn;
  5172. RECT rcCaptionText = pncwm->rcS0[NCRC_CAPTIONTEXT];
  5173. RECT* prcButton = &pncwm->rcS0[NCRC_LAMEBTN];
  5174. int cxPad = NcGetSystemMetrics(SM_CXEDGE) * 2;
  5175. // Enough room to draw the lame button link?
  5176. fLameOn = RECTWIDTH(&rcCaptionText) >
  5177. psizeCaption->cx +
  5178. cxPad + // between caption, lame text
  5179. _sizeLame.cx +
  5180. cxPad; // between lame text, nearest button;
  5181. //---- compute lame button alignment ----
  5182. BOOL fReverse = TRUE; // normally, lame goes on right side
  5183. //---- WS_EX_RIGHT wants the opposite ----
  5184. if (TESTFLAG(_ncwm.dwExStyle, WS_EX_RIGHT))
  5185. fReverse = FALSE;
  5186. DWORD dwFlags = GetTextAlignFlags(_hTheme, &_ncwm, fReverse);
  5187. //---- turn off lame button for center captions ----
  5188. if (dwFlags & DT_CENTER)
  5189. fLameOn = FALSE;
  5190. if ( fLameOn )
  5191. {
  5192. CopyRect(prcButton, &rcCaptionText);
  5193. //---- note: pMargins already includes the theme specified ----
  5194. //---- CaptionMargins (which scale with DPI) and the ----
  5195. //---- icon and buttons widths ----
  5196. if(dwFlags & DT_RIGHT) // put lame on right
  5197. {
  5198. prcButton->left = (prcButton->right - _sizeLame.cx) - cxPad ;
  5199. //---- adjust margins to remove lame area ----
  5200. pncwm->CaptionMargins.cxRightWidth -= _sizeLame.cx;
  5201. }
  5202. else // put lame on left
  5203. {
  5204. prcButton->right = (prcButton->left + _sizeLame.cx) + cxPad;
  5205. //---- adjust margins to remove lame area ----
  5206. pncwm->CaptionMargins.cxLeftWidth += _sizeLame.cx;
  5207. }
  5208. // vertically center the text between margins
  5209. prcButton->top += (RECTHEIGHT(&rcCaptionText) - _sizeLame.cy)/2;
  5210. prcButton->bottom = prcButton->top + _sizeLame.cy;
  5211. }
  5212. }
  5213. }
  5214. #endif // LAME_BUTTON
  5215. #ifdef DEBUG
  5216. //-------------------------------------------------------------------------//
  5217. void CDECL _NcTraceMsg( ULONG uFlags, LPCTSTR pszFmt, ...)
  5218. {
  5219. if( TESTFLAG(_NcTraceFlags, uFlags) || NCTF_ALWAYS == uFlags )
  5220. {
  5221. va_list args;
  5222. va_start(args, pszFmt);
  5223. TCHAR szSpew[2048];
  5224. StringCchPrintf(szSpew, ARRAYSIZE(szSpew), pszFmt, args);
  5225. OutputDebugString(szSpew);
  5226. OutputDebugString(TEXT("\n"));
  5227. va_end(args);
  5228. }
  5229. }
  5230. //-------------------------------------------------------------------------//
  5231. void INIT_THEMEWND_DBG( CThemeWnd* pwnd )
  5232. {
  5233. if( IsWindow( *pwnd ) )
  5234. {
  5235. GetWindowText( *pwnd, pwnd->_szCaption, ARRAYSIZE(pwnd->_szCaption) );
  5236. GetClassName( *pwnd, pwnd->_szWndClass, ARRAYSIZE(pwnd->_szWndClass) );
  5237. }
  5238. }
  5239. //-------------------------------------------------------------------------//
  5240. void CThemeWnd::Spew( DWORD dwSpewFlags, LPCTSTR pszFmt, LPCTSTR pszClassList )
  5241. {
  5242. if( pszClassList && *pszClassList )
  5243. {
  5244. if( !_tcsstr( pszClassList, _szWndClass ) )
  5245. return;
  5246. }
  5247. TCHAR szInfo[MAX_PATH*2];
  5248. TCHAR szMsg[MAX_PATH*2];
  5249. StringCchPrintf( szInfo, ARRAYSIZE(szInfo), TEXT("%08lX -'%s' ('%s') cf: %08lX"), _hwnd, _szCaption, _szWndClass, _fClassFlags );
  5250. StringCchPrintf( szMsg, ARRAYSIZE(szMsg), pszFmt, szInfo );
  5251. Log(LOG_NCATTACH, szMsg );
  5252. }
  5253. typedef struct
  5254. {
  5255. DWORD dwProcessId;
  5256. DWORD dwThreadId;
  5257. DWORD dwSpewFlags;
  5258. LPCTSTR pszFmt;
  5259. LPCTSTR pszClassList;
  5260. } SPEW_ALL;
  5261. //-------------------------------------------------------------------------//
  5262. BOOL _SpewAllEnumCB( HWND hwnd, LPARAM lParam )
  5263. {
  5264. SPEW_ALL* psa = (SPEW_ALL*)lParam;
  5265. if( IsWindowProcess( hwnd, psa->dwProcessId ) )
  5266. {
  5267. CThemeWnd* pwnd = CThemeWnd::FromHwnd( hwnd );
  5268. if( VALID_THEMEWND(pwnd) )
  5269. pwnd->Spew( psa->dwSpewFlags, psa->pszFmt );
  5270. }
  5271. return TRUE;
  5272. }
  5273. //-------------------------------------------------------------------------//
  5274. void CThemeWnd::SpewAll( DWORD dwSpewFlags, LPCTSTR pszFmt, LPCTSTR pszClassList )
  5275. {
  5276. SPEW_ALL sa;
  5277. sa.dwThreadId = GetCurrentThreadId();
  5278. sa.dwProcessId = GetCurrentProcessId();
  5279. sa.dwSpewFlags = dwSpewFlags;
  5280. sa.pszFmt = pszFmt;
  5281. sa.pszClassList = pszClassList;
  5282. //---- this will enum all windows for this process (all desktops, all child levels) ----
  5283. EnumProcessWindows( _SpewAllEnumCB, (LPARAM)&sa );
  5284. }
  5285. //-------------------------------------------------------------------------//
  5286. void CThemeWnd::SpewLeaks()
  5287. {
  5288. if( _cObj > 0 )
  5289. {
  5290. Log(LOG_NCATTACH, L"LEAK WARNING: %d CThemeWnd instances outstanding.", _cObj );
  5291. }
  5292. }
  5293. //-------------------------------------------------------------------------//
  5294. void SPEW_RECT( ULONG ulTrace, LPCTSTR pszMsg, LPCRECT prc )
  5295. {
  5296. LPCTSTR pszFmt = TEXT("%s: {L:%d,T:%d,R:%d,B:%d}, (%d x %d)");
  5297. WCHAR szMsg[1024];
  5298. StringCchPrintfW( szMsg, ARRAYSIZE(szMsg), pszFmt, pszMsg,
  5299. prc->left, prc->top, prc->right, prc->bottom,
  5300. RECTWIDTH(prc), RECTHEIGHT(prc) );
  5301. _NcTraceMsg(ulTrace, szMsg);
  5302. }
  5303. //-------------------------------------------------------------------------//
  5304. void SPEW_MARGINS( ULONG ulTrace, LPCTSTR pszMsg,
  5305. LPCRECT prcParent, LPCRECT prcChild )
  5306. {
  5307. LPCTSTR pszFmt = TEXT("%s: {L:%d,T:%d,R:%d,B:%d}");
  5308. WCHAR szMsg[1024];
  5309. StringCchPrintfW( szMsg, ARRAYSIZE(szMsg), pszFmt, pszMsg,
  5310. prcChild->left - prcParent->left,
  5311. prcChild->top - prcParent->top,
  5312. prcParent->right - prcChild->right,
  5313. prcParent->bottom - prcChild->bottom );
  5314. _NcTraceMsg(ulTrace, szMsg);
  5315. }
  5316. //-------------------------------------------------------------------------//
  5317. void SPEW_RGNRECT( ULONG ulTrace, LPCTSTR pszMsg, HRGN hrgn, int iPartID )
  5318. {
  5319. RECT rc;
  5320. if( NULLREGION == GetRgnBox( hrgn, &rc ) )
  5321. FillMemory( &rc, sizeof(rc), static_cast<UCHAR>(-1) );
  5322. _NcTraceMsg( ulTrace, TEXT("Region %08lX for partID[%d]:\n\t"), hrgn, iPartID );
  5323. SPEW_RECT( ulTrace, pszMsg, &rc );
  5324. }
  5325. //-------------------------------------------------------------------------//
  5326. void SPEW_WINDOWINFO( ULONG ulTrace, WINDOWINFO* pwi )
  5327. {
  5328. SPEW_RECT(ulTrace, TEXT("->wi.rcWindow"), &pwi->rcWindow );
  5329. SPEW_RECT(ulTrace, TEXT("->wi.rcClient"), &pwi->rcClient );
  5330. _NcTraceMsg(ulTrace, TEXT("->wi.dwStyle: %08lX"), pwi->dwStyle );
  5331. _NcTraceMsg(ulTrace, TEXT("->wi.dwExStyle: %08lX"), pwi->dwExStyle );
  5332. _NcTraceMsg(ulTrace, TEXT("->wi.dwWindowStatus: %08lX"), pwi->dwWindowStatus );
  5333. _NcTraceMsg(ulTrace, TEXT("->wi.cxWindowBorders: %d"), pwi->cxWindowBorders );
  5334. _NcTraceMsg(ulTrace, TEXT("->wi.cyWindowBorders: %d"), pwi->cyWindowBorders );
  5335. }
  5336. //-------------------------------------------------------------------------//
  5337. void SPEW_NCWNDMET( ULONG ulTrace, LPCTSTR pszMsg, NCWNDMET* pncwm )
  5338. {
  5339. _NcTraceMsg(ulTrace, TEXT("\n%s - Spewing NCWNDMET @ %08lx..."), pszMsg, pncwm );
  5340. _NcTraceMsg(ulTrace, TEXT("->fValid: %d"), pncwm->fValid );
  5341. _NcTraceMsg(ulTrace, TEXT("->dwStyle: %08lX"), pncwm->dwStyle );
  5342. _NcTraceMsg(ulTrace, TEXT("->dwExStyle: %08lX"), pncwm->dwExStyle );
  5343. _NcTraceMsg(ulTrace, TEXT("->dwWindowStatus: %08lX"), pncwm->dwWindowStatus );
  5344. _NcTraceMsg(ulTrace, TEXT("->fFrame: %d"), pncwm->fFrame );
  5345. _NcTraceMsg(ulTrace, TEXT("->fSmallFrame: %d"), pncwm->fSmallFrame );
  5346. _NcTraceMsg(ulTrace, TEXT("->iFRAMEBOTTOM %d"), pncwm->rgframeparts[iFRAMEBOTTOM] );
  5347. _NcTraceMsg(ulTrace, TEXT("->iFRAMELEFT: %d"), pncwm->rgframeparts[iFRAMELEFT] );
  5348. _NcTraceMsg(ulTrace, TEXT("->iFRAMERIGHT: %d"), pncwm->rgframeparts[iFRAMERIGHT] );
  5349. _NcTraceMsg(ulTrace, TEXT("->framestate: %d"), pncwm->framestate );
  5350. _NcTraceMsg(ulTrace, TEXT("->iMinButtonPart: %d"), pncwm->iMinButtonPart);
  5351. _NcTraceMsg(ulTrace, TEXT("->iMaxButtonPart: %d"), pncwm->iMaxButtonPart);
  5352. _NcTraceMsg(ulTrace, TEXT("->rawCloseBtnState: %d"), pncwm->rawCloseBtnState);
  5353. _NcTraceMsg(ulTrace, TEXT("->rawMinBtnState: %d"), pncwm->rawMinBtnState);
  5354. _NcTraceMsg(ulTrace, TEXT("->rawMaxBtnState: %d"), pncwm->rawMaxBtnState);
  5355. _NcTraceMsg(ulTrace, TEXT("->cyMenu: %d"), pncwm->cyMenu );
  5356. _NcTraceMsg(ulTrace, TEXT("->cnMenuOffsetLeft: %d"), pncwm->cnMenuOffsetLeft );
  5357. _NcTraceMsg(ulTrace, TEXT("->cnMenuOffsetRight: %d"), pncwm->cnMenuOffsetRight );
  5358. _NcTraceMsg(ulTrace, TEXT("->cnMenuOffsetTop: %d"), pncwm->cnMenuOffsetTop );
  5359. _NcTraceMsg(ulTrace, TEXT("->cnBorders: %d"), pncwm->cnBorders );
  5360. _NcTraceMsg(ulTrace, TEXT("->CaptionMargins: (%d,%d,%d,%d)"), pncwm->CaptionMargins );
  5361. SPEW_RECT(ulTrace, TEXT("->rcS0[NCRC_WINDOW] "), &pncwm->rcS0[NCRC_WINDOW] );
  5362. SPEW_RECT(ulTrace, TEXT("->rcS0[NCRC_CLIENT] "), &pncwm->rcS0[NCRC_CLIENT] );
  5363. SPEW_MARGINS(ulTrace, TEXT("Window-Client margins"), &pncwm->rcS0[NCRC_WINDOW], &pncwm->rcS0[NCRC_CLIENT] );
  5364. SPEW_RECT(ulTrace, TEXT("->rcS0[NCRC_CONTENT] "), &pncwm->rcS0[NCRC_CONTENT] );
  5365. SPEW_MARGINS(ulTrace, TEXT("Window-Content margins"), &pncwm->rcS0[NCRC_WINDOW], &pncwm->rcS0[NCRC_CONTENT]);
  5366. SPEW_RECT(ulTrace, TEXT("->rcS0[NCRC_MENUBAR] "), &pncwm->rcS0[NCRC_MENUBAR] );
  5367. SPEW_MARGINS(ulTrace, TEXT("Window-Menubar margins"), &pncwm->rcS0[NCRC_WINDOW], &pncwm->rcS0[NCRC_MENUBAR]);
  5368. SPEW_RECT(ulTrace, TEXT("->rcS0[NCRC_CAPTION] "), &pncwm->rcS0[NCRC_CAPTION] );
  5369. SPEW_MARGINS(ulTrace, TEXT("Window-Caption margins"), &pncwm->rcS0[NCRC_WINDOW], &pncwm->rcS0[NCRC_CAPTION]);
  5370. SPEW_RECT(ulTrace, TEXT("->rcS0[NCRC_FRAMELEFT] "), &pncwm->rcS0[NCRC_FRAMELEFT] );
  5371. SPEW_MARGINS(ulTrace, TEXT("Window-FrameLeft margins"), &pncwm->rcS0[NCRC_WINDOW], &pncwm->rcS0[NCRC_FRAMELEFT]);
  5372. SPEW_RECT(ulTrace, TEXT("->rcS0[NCRC_FRAMERIGHT]"), &pncwm->rcS0[NCRC_FRAMERIGHT] );
  5373. SPEW_MARGINS(ulTrace, TEXT("Window-FrameRight margins"), &pncwm->rcS0[NCRC_WINDOW], &pncwm->rcS0[NCRC_FRAMERIGHT]);
  5374. SPEW_RECT(ulTrace, TEXT("->rcS0[NCRC_FRAMEBOTTOM]"), &pncwm->rcS0[NCRC_FRAMEBOTTOM] );
  5375. SPEW_MARGINS(ulTrace, TEXT("Window-FrameBottom margins"), &pncwm->rcS0[NCRC_WINDOW], &pncwm->rcS0[NCRC_FRAMEBOTTOM]);
  5376. SPEW_RECT(ulTrace, TEXT("->rcS0[NCRC_CLIENTEDGE]"), &pncwm->rcS0[NCRC_CLIENTEDGE] );
  5377. SPEW_MARGINS(ulTrace, TEXT("Window-ClientEdge margins"), &pncwm->rcS0[NCRC_WINDOW], &pncwm->rcS0[NCRC_CLIENTEDGE]);
  5378. SPEW_RECT(ulTrace, TEXT("->rcS0[NCRC_HSCROLL] "), &pncwm->rcS0[NCRC_HSCROLL] );
  5379. SPEW_RECT(ulTrace, TEXT("->rcS0[NCRC_VSCROLL] "), &pncwm->rcS0[NCRC_VSCROLL] );
  5380. SPEW_RECT(ulTrace, TEXT("->rcS0[NCRC_SIZEBOX] "), &pncwm->rcS0[NCRC_SIZEBOX] );
  5381. SPEW_RECT(ulTrace, TEXT("->rcS0[NCRC_CLOSEBTN] "), &pncwm->rcS0[NCRC_CLOSEBTN] );
  5382. SPEW_RECT(ulTrace, TEXT("->rcS0[NCRC_MINBTN] "), &pncwm->rcS0[NCRC_MINBTN] );
  5383. SPEW_RECT(ulTrace, TEXT("->rcS0[NCRC_MAXBTN] "), &pncwm->rcS0[NCRC_MAXBTN] );
  5384. SPEW_RECT(ulTrace, TEXT("->rcS0[NCRC_SYSBTN] "), &pncwm->rcS0[NCRC_SYSBTN] );
  5385. SPEW_RECT(ulTrace, TEXT("->rcS0[NCRC_HELPBTN] "), &pncwm->rcS0[NCRC_HELPBTN] );
  5386. #ifdef LAME_BUTTON
  5387. SPEW_RECT(ulTrace, TEXT("rcLame"), &pncwm->rcS0[NCRC_LAMEBTN] );
  5388. #endif // LAME_BUTTON
  5389. }
  5390. //-------------------------------------------------------------------------//
  5391. void SPEW_THEMEMSG( ULONG ulTrace, LPCTSTR pszMsg, THEME_MSG* ptm )
  5392. {
  5393. _NcTraceMsg(ulTrace, TEXT("%s hwnd: %08lX, uMsg: %04lX, handled?: %d"),
  5394. pszMsg, (ptm)->hwnd, (ptm)->uMsg, (ptm)->fHandled );
  5395. }
  5396. //-------------------------------------------------------------------------//
  5397. void SPEW_SCROLLINFO( LPCTSTR pszMsg, HWND hwnd, LPCSCROLLINFO psi )
  5398. {
  5399. #ifdef _ENABLE_SCROLL_SPEW_
  5400. _NcTraceMsg(ulTrace, L"%s for HWND %08lX...\ncbSize: %d\nfMask: %08lX\nnMin: %d\nnMax: %d\nnPage: %d\nnPos: %d",
  5401. pszMsg, hwnd, psi->cbSize, psi->fMask, psi->nMin, psi->nMax, psi->nPage, psi->nPos );
  5402. #endif _ENABLE_SCROLL_SPEW_
  5403. }
  5404. #if defined(DEBUG_NCPAINT)
  5405. static int _cPaintSleep = 10;
  5406. void _DebugBackground(
  5407. HDC hdc,
  5408. COLORREF rgb,
  5409. const RECT *prc )
  5410. {
  5411. // paint some indicator stuff
  5412. COLORREF rgb0 = SetBkColor( hdc, rgb );
  5413. SPEW_RECT( NCTF_ALWAYS, TEXT("\tprc"), prc );
  5414. ExtTextOut( hdc, prc->left, prc->top, ETO_OPAQUE, prc, NULL, 0, NULL );
  5415. Sleep(_cPaintSleep);
  5416. SetBkColor( hdc, rgb0 );
  5417. }
  5418. //-------------------------------------------------------------------------//
  5419. HRESULT _DebugDrawThemeBackground(
  5420. HTHEME hTheme,
  5421. HDC hdc,
  5422. int iPartId,
  5423. int iStateId,
  5424. const RECT *prc,
  5425. OPTIONAL const RECT* prcClip )
  5426. {
  5427. if( TESTFLAG( _NcTraceFlags, NCTF_NCPAINT ) )
  5428. {
  5429. _NcTraceMsg( NCTF_ALWAYS, TEXT("DrawThemeBackground( hTheme = %08lX, hdc = %08lX, iPartId = %d, iStateId = %d"),
  5430. hTheme, hdc, iPartId, iStateId );
  5431. _DebugBackground( hdc, RGBDEBUGBKGND, prc );
  5432. }
  5433. // paint the real background.
  5434. HRESULT hr = DrawThemeBackground( hTheme, hdc, iPartId, iStateId, prc, prcClip );
  5435. if( TESTFLAG( _NcTraceFlags, NCTF_NCPAINT ) )
  5436. {
  5437. Sleep(_cPaintSleep);
  5438. }
  5439. return hr;
  5440. }
  5441. //-------------------------------------------------------------------------//
  5442. HRESULT _DebugDrawThemeBackgroundEx(
  5443. HTHEME hTheme,
  5444. HDC hdc,
  5445. int iPartId,
  5446. int iStateId,
  5447. const RECT *prc,
  5448. OPTIONAL const DTBGOPTS *pOptions )
  5449. {
  5450. if( TESTFLAG( _NcTraceFlags, NCTF_NCPAINT ) )
  5451. {
  5452. _NcTraceMsg( NCTF_ALWAYS, TEXT("DrawThemeBackground( hTheme = %08lX, hdc = %08lX, iPartId = %d, iStateId = %d"),
  5453. hTheme, hdc, iPartId, iStateId );
  5454. _DebugBackground( hdc, RGBDEBUGBKGND, prc );
  5455. }
  5456. // paint the real background.
  5457. HRESULT hr = DrawThemeBackgroundEx( hTheme, hdc, iPartId, iStateId, prc, pOptions );
  5458. if( TESTFLAG( _NcTraceFlags, NCTF_NCPAINT ) )
  5459. {
  5460. Sleep(_cPaintSleep);
  5461. }
  5462. return hr;
  5463. }
  5464. //-------------------------------------------------------------------------//
  5465. void NcDebugClipRgn( HDC hdc, COLORREF rgbPaint )
  5466. {
  5467. if( TESTFLAG( _NcTraceFlags, NCTF_NCPAINT ) )
  5468. {
  5469. HRGN hrgn = CreateRectRgn(0,0,1,1);
  5470. if( hrgn )
  5471. {
  5472. if( GetClipRgn( hdc, hrgn ) > 0 )
  5473. {
  5474. HBRUSH hbr = CreateSolidBrush(rgbPaint);
  5475. FillRgn( hdc, hrgn, hbr );
  5476. DeleteObject(hbr);
  5477. Sleep(_cPaintSleep);
  5478. }
  5479. DeleteObject(hrgn);
  5480. }
  5481. }
  5482. }
  5483. #endif //defined(DEBUG_NCPAINT)
  5484. #endif DEBUG