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

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