Bug 574454 - Theme code for caption button box, content padding. r=vlad.
authorJim Mathies <jmathies@mozilla.com>
Mon, 09 Aug 2010 20:49:35 -0500
changeset 49250 5715673e78c2deaa95f443e7ca791929d194c175
parent 49249 ff19c2e8669545c99eefd70d4315c2f36928cd7e
child 49251 34b248dfbf59fbf7a2a6731ad5c2266d175359d1
push id1
push userroot
push dateTue, 26 Apr 2011 22:38:44 +0000
treeherdermozilla-beta@bfdb6e623a36 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersvlad
bugs574454
milestone2.0b4pre
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 574454 - Theme code for caption button box, content padding. r=vlad.
widget/src/windows/nsNativeThemeWin.cpp
widget/src/windows/nsUXThemeData.cpp
widget/src/windows/nsUXThemeData.h
widget/src/windows/nsWindow.cpp
--- a/widget/src/windows/nsNativeThemeWin.cpp
+++ b/widget/src/windows/nsNativeThemeWin.cpp
@@ -134,18 +134,21 @@ static PRInt32 GetTopLevelWindowActiveSt
   if (window->GetWindowHandle() == ::GetActiveWindow())
     return mozilla::widget::themeconst::FS_ACTIVE;
   return mozilla::widget::themeconst::FS_INACTIVE;
 }
 
 static PRInt32 GetWindowFrameButtonState(nsIFrame *aFrame, PRInt32 eventState)
 {
   if (GetTopLevelWindowActiveState(aFrame) ==
-      mozilla::widget::themeconst::FS_INACTIVE)
+      mozilla::widget::themeconst::FS_INACTIVE) {
+    if (eventState & NS_EVENT_STATE_HOVER)
+      return mozilla::widget::themeconst::BS_HOT;
     return mozilla::widget::themeconst::BS_INACTIVE;
+  }
 
   if (eventState & NS_EVENT_STATE_ACTIVE)
     return mozilla::widget::themeconst::BS_PUSHED;
   else if (eventState & NS_EVENT_STATE_HOVER)
     return mozilla::widget::themeconst::BS_HOT;
   else
     return mozilla::widget::themeconst::BS_NORMAL;
 }
@@ -155,16 +158,32 @@ static PRInt32 GetClassicWindowFrameButt
   if (eventState & NS_EVENT_STATE_ACTIVE)
     return DFCS_BUTTONPUSH|DFCS_PUSHED;
   else if (eventState & NS_EVENT_STATE_HOVER)
     return DFCS_BUTTONPUSH|DFCS_HOT;
   else
     return DFCS_BUTTONPUSH;
 }
 
+static void QueryForButtonData(nsIFrame *aFrame)
+{
+  if (nsUXThemeData::sTitlebarInfoPopulated)
+    return;
+
+  nsIWidget* widget = aFrame->GetNearestWidget();
+  nsWindow * window = static_cast<nsWindow*>(widget);
+  if (!window)
+    return;
+  if (!window->IsTopLevelWidget() &&
+      !(window = window->GetParentWindow(PR_FALSE)))
+    return;
+
+  nsUXThemeData::UpdateTitlebarInfo(window->GetWindowHandle());
+}
+
 nsNativeThemeWin::nsNativeThemeWin() {
   // If there is a relevant change in forms.css for windows platform,
   // static widget style variables (e.g. sButtonBorderSize) should be 
   // reinitialized here.
 }
 
 nsNativeThemeWin::~nsNativeThemeWin() {
   nsUXThemeData::Invalidate();
@@ -410,16 +429,18 @@ nsNativeThemeWin::GetTheme(PRUint8 aWidg
     case NS_THEME_WINDOW_TITLEBAR_MAXIMIZED:
     case NS_THEME_WINDOW_FRAME_LEFT:
     case NS_THEME_WINDOW_FRAME_RIGHT:
     case NS_THEME_WINDOW_FRAME_BOTTOM:
     case NS_THEME_WINDOW_BUTTON_CLOSE:
     case NS_THEME_WINDOW_BUTTON_MINIMIZE:
     case NS_THEME_WINDOW_BUTTON_MAXIMIZE:
     case NS_THEME_WINDOW_BUTTON_RESTORE:
+    case NS_THEME_WINDOW_BUTTON_BOX:
+    case NS_THEME_WINDOW_BUTTON_BOX_MAXIMIZED:
       return nsUXThemeData::GetTheme(eUXWindowFrame);
   }
   return NULL;
 }
 
 PRInt32
 nsNativeThemeWin::StandardGetState(nsIFrame* aFrame, PRUint8 aWidgetType,
                                    PRBool wantFocused)
@@ -1057,16 +1078,21 @@ nsNativeThemeWin::GetThemePartAndState(n
     case NS_THEME_WINDOW_BUTTON_MAXIMIZE:
       aPart = mozilla::widget::themeconst::WP_MAXBUTTON;
       aState = GetWindowFrameButtonState(aFrame, GetContentState(aFrame, aWidgetType));
       return NS_OK;
     case NS_THEME_WINDOW_BUTTON_RESTORE:
       aPart = mozilla::widget::themeconst::WP_RESTOREBUTTON;
       aState = GetWindowFrameButtonState(aFrame, GetContentState(aFrame, aWidgetType));
       return NS_OK;
+    case NS_THEME_WINDOW_BUTTON_BOX:
+    case NS_THEME_WINDOW_BUTTON_BOX_MAXIMIZED:
+      aPart = -1;
+      aState = 0;
+      return NS_OK;
   }
 
   aPart = 0;
   aState = 0;
   return NS_ERROR_FAILURE;
 }
 
 NS_IMETHODIMP
@@ -1494,16 +1520,63 @@ nsNativeThemeWin::GetWidgetPadding(nsIDe
     // author-specified padding.
     case NS_THEME_CHECKBOX:
     case NS_THEME_RADIO:
       aResult->SizeTo(0, 0, 0, 0);
       return PR_TRUE;
   }
 
   HANDLE theme = GetTheme(aWidgetType);
+
+  if (aWidgetType == NS_THEME_WINDOW_BUTTON_BOX ||
+      aWidgetType == NS_THEME_WINDOW_BUTTON_BOX_MAXIMIZED) {
+    aResult->SizeTo(0, 0, 0, 0);
+
+#if MOZ_WINSDK_TARGETVER >= MOZ_NTDDI_LONGHORN
+    // aero glass doesn't display custom buttons
+    if (nsUXThemeData::CheckForCompositor())
+      return PR_TRUE;
+#endif
+
+    // button padding for standard windows
+    if (aWidgetType == NS_THEME_WINDOW_BUTTON_BOX) {
+      aResult->top = GetSystemMetrics(SM_CXFRAME);
+      if (nsUXThemeData::sIsVistaOrLater) {
+        aResult->right += 2;
+      } else {
+        aResult->right += 1;
+      }
+    }
+
+    // Adjust horizontal button padding for maximized windows on XP
+    if (aWidgetType == NS_THEME_WINDOW_BUTTON_BOX_MAXIMIZED &&
+        !nsUXThemeData::sIsVistaOrLater) {
+      aResult->right += 1;
+    }
+
+    // Push buttons down
+    if (theme) {
+      aResult->top += 1;
+    } else {
+      aResult->top += 2;
+    }
+    return PR_TRUE;
+  }
+
+  // Content padding
+  if (aWidgetType == NS_THEME_WINDOW_TITLEBAR ||
+      aWidgetType == NS_THEME_WINDOW_TITLEBAR_MAXIMIZED) {
+    aResult->SizeTo(0, 0, 0, 0);
+    // Maximized windows have an offscreen offset equal to
+    // the border padding. (windows quirk)
+    if (aWidgetType == NS_THEME_WINDOW_TITLEBAR_MAXIMIZED)
+      aResult->top = GetSystemMetrics(SM_CXFRAME);
+    return PR_TRUE;
+  }
+
   if (!theme)
     return PR_FALSE;
 
   if (aWidgetType == NS_THEME_MENUPOPUP)
   {
     SIZE popupSize;
     nsUXThemeData::getThemePartSize(theme, NULL, MENU_POPUPBORDERS, /* state */ 0, NULL, TS_TRUE, &popupSize);
     aResult->top = aResult->bottom = popupSize.cy;
@@ -1755,40 +1828,49 @@ nsNativeThemeWin::GetMinimumWidgetSize(n
       // use the one they want.
       if (aFrame->GetContent()->IsHTML()) {
         sizeReq = TS_MIN;
       }
       break;
 
     case NS_THEME_WINDOW_BUTTON_MAXIMIZE:
     case NS_THEME_WINDOW_BUTTON_RESTORE:
-      // For XP, use the theme library dimensions, which seem to be accurate.
-      if (nsWindow::GetWindowsVersion() < VISTA_VERSION)
-        break;
       // The only way to get accurate titlebar button info is to query a
       // window w/buttons when it's visible. nsWindow takes care of this and
       // stores that info in nsUXThemeData.
+      QueryForButtonData(aFrame);
       aResult->width = nsUXThemeData::sCommandButtons[CMDBUTTONIDX_RESTORE].cx;
       aResult->height = nsUXThemeData::sCommandButtons[CMDBUTTONIDX_RESTORE].cy;
+      // For XP, subtract 4 from system metrics dimensions.
+      if (nsWindow::GetWindowsVersion() == WINXP_VERSION) {
+        aResult->width -= 4;
+        aResult->height -= 4;
+      }
       *aIsOverridable = PR_FALSE;
       return NS_OK;
 
     case NS_THEME_WINDOW_BUTTON_MINIMIZE:
-      if (nsWindow::GetWindowsVersion() < VISTA_VERSION)
-        break;
+      QueryForButtonData(aFrame);
       aResult->width = nsUXThemeData::sCommandButtons[CMDBUTTONIDX_MINIMIZE].cx;
       aResult->height = nsUXThemeData::sCommandButtons[CMDBUTTONIDX_MINIMIZE].cy;
+      if (nsWindow::GetWindowsVersion() == WINXP_VERSION) {
+        aResult->width -= 4;
+        aResult->height -= 4;
+      }
       *aIsOverridable = PR_FALSE;
       return NS_OK;
 
     case NS_THEME_WINDOW_BUTTON_CLOSE:
-      if (nsWindow::GetWindowsVersion() < VISTA_VERSION)
-        break;
+      QueryForButtonData(aFrame);
       aResult->width = nsUXThemeData::sCommandButtons[CMDBUTTONIDX_CLOSE].cx;
       aResult->height = nsUXThemeData::sCommandButtons[CMDBUTTONIDX_CLOSE].cy;
+      if (nsWindow::GetWindowsVersion() == WINXP_VERSION) {
+        aResult->width -= 4;
+        aResult->height -= 4;
+      }
       *aIsOverridable = PR_FALSE;
       return NS_OK;
 
     case NS_THEME_WINDOW_TITLEBAR:
     case NS_THEME_WINDOW_TITLEBAR_MAXIMIZED:
       aResult->height = GetSystemMetrics(SM_CYCAPTION);
       aResult->height += GetSystemMetrics(SM_CYFRAME);
       *aIsOverridable = PR_FALSE;
@@ -2063,16 +2145,18 @@ nsNativeThemeWin::ClassicThemeSupportsWi
     case NS_THEME_WINDOW_TITLEBAR_MAXIMIZED:
     case NS_THEME_WINDOW_FRAME_LEFT:
     case NS_THEME_WINDOW_FRAME_RIGHT:
     case NS_THEME_WINDOW_FRAME_BOTTOM:
     case NS_THEME_WINDOW_BUTTON_CLOSE:
     case NS_THEME_WINDOW_BUTTON_MINIMIZE:
     case NS_THEME_WINDOW_BUTTON_MAXIMIZE:
     case NS_THEME_WINDOW_BUTTON_RESTORE:
+    case NS_THEME_WINDOW_BUTTON_BOX:
+    case NS_THEME_WINDOW_BUTTON_BOX_MAXIMIZED:
       return PR_TRUE;
   }
   return PR_FALSE;
 }
 
 nsresult
 nsNativeThemeWin::ClassicGetWidgetBorder(nsIDeviceContext* aContext, 
                                   nsIFrame* aFrame,
--- a/widget/src/windows/nsUXThemeData.cpp
+++ b/widget/src/windows/nsUXThemeData.cpp
@@ -165,16 +165,18 @@ nsUXThemeData::Invalidate() {
                      useFlat : PR_FALSE;
   } else {
     // Contrary to Microsoft's documentation, SPI_GETFLATMENU will not fail
     // on Windows 2000, and it is also possible (though unlikely) for WIN2K
     // to be misconfigured in such a way that it would return true, so we
     // shall give WIN2K special treatment
     sFlatMenus = PR_FALSE;
   }
+  // Refresh titlebar button info
+  sTitlebarInfoPopulated = PR_FALSE;
 }
 
 HANDLE
 nsUXThemeData::GetTheme(nsUXThemeClass cls) {
   NS_ASSERTION(cls < eUXNumClasses, "Invalid theme class!");
   if(!sThemeDLL)
     return NULL;
   if(!sThemes[cls])
@@ -239,25 +241,33 @@ void
 nsUXThemeData::InitTitlebarInfo()
 {
   // Pre-populate with generic metrics. These likley will not match
   // the current theme, but they insure the buttons at least show up.
   sCommandButtons[0].cx = GetSystemMetrics(SM_CXSIZE);
   sCommandButtons[0].cy = GetSystemMetrics(SM_CYSIZE);
   sCommandButtons[1].cx = sCommandButtons[2].cx = sCommandButtons[0].cx;
   sCommandButtons[1].cy = sCommandButtons[2].cy = sCommandButtons[0].cy;
+
+  // Use system metrics for pre-vista
+  if (nsWindow::GetWindowsVersion() < VISTA_VERSION)
+    sTitlebarInfoPopulated = PR_TRUE;
 }
 
 // static
 void
-nsUXThemeData::UpdateTitlebarInfo(TITLEBARINFOEX& info)
+nsUXThemeData::UpdateTitlebarInfo(HWND aWnd)
 {
-  if (sTitlebarInfoPopulated)
+  if (sTitlebarInfoPopulated || !aWnd)
     return;
 
+  TITLEBARINFOEX info = {0};
+  info.cbSize = sizeof(TITLEBARINFOEX);
+  SendMessage(aWnd, WM_GETTITLEBARINFOEX, 0, (LPARAM)&info); 
+
   // Only set if we have valid data for all three buttons we use.
   if ((info.rgrect[2].right - info.rgrect[2].left) == 0 ||
       (info.rgrect[3].right - info.rgrect[3].left) == 0 ||
       (info.rgrect[5].right - info.rgrect[5].left) == 0)
     return;
 
   // minimize
   sCommandButtons[0].cx = info.rgrect[2].right - info.rgrect[2].left;
--- a/widget/src/windows/nsUXThemeData.h
+++ b/widget/src/windows/nsUXThemeData.h
@@ -118,17 +118,17 @@ public:
 
   static void Initialize();
   static void Teardown();
   static void Invalidate();
   static HANDLE GetTheme(nsUXThemeClass cls);
 
   // nsWindow calls this to update desktop settings info
   static void InitTitlebarInfo();
-  static void UpdateTitlebarInfo(TITLEBARINFOEX& info);
+  static void UpdateTitlebarInfo(HWND aWnd);
 
   static inline BOOL IsAppThemed() {
     return isAppThemed && isAppThemed();
   }
 
   static inline HRESULT GetThemeColor(nsUXThemeClass cls, int iPartId, int iStateId,
                                                    int iPropId, OUT COLORREF* pFont) {
     if(!getThemeColor)
--- a/widget/src/windows/nsWindow.cpp
+++ b/widget/src/windows/nsWindow.cpp
@@ -435,19 +435,17 @@ nsWindow::nsWindow() : nsBaseWidget()
     InitHeapDump();
 #endif
 
 #if !defined(WINCE)
     InitTrackPointHack();
 #endif
 
     // Init titlebar button info for custom frames.
-    if (GetWindowsVersion() >= VISTA_VERSION) {
-      nsUXThemeData::InitTitlebarInfo();
-    }
+    nsUXThemeData::InitTitlebarInfo();
   } // !sInstanceCount
 
   mIdleService = nsnull;
 
   sInstanceCount++;
 }
 
 nsWindow::~nsWindow()
@@ -1229,26 +1227,16 @@ NS_METHOD nsWindow::Show(PRBool bState)
     }
   }
   
 #ifdef MOZ_XUL
   if (!wasVisible && bState)
     Invalidate(PR_FALSE);
 #endif
 
-  // Update titlebar metric info when the window is shown.
-  if (!nsUXThemeData::sTitlebarInfoPopulated && bState &&
-      GetWindowsVersion() >= VISTA_VERSION &&
-      (mWindowType == eWindowType_toplevel || mWindowType == eWindowType_dialog) &&
-      (mBorderStyle == eBorderStyle_default || mBorderStyle == eBorderStyle_all)) {
-    TITLEBARINFOEX info = {0};
-    info.cbSize = sizeof(TITLEBARINFOEX);
-    SendMessage(mWnd, WM_GETTITLEBARINFOEX, 0, (LPARAM)&info); 
-    nsUXThemeData::UpdateTitlebarInfo(info);
-  }
   return NS_OK;
 }
 
 /**************************************************************
  *
  * SECTION: nsIWidget::IsVisible
  *
  * Returns the visibility state.