Bug 606160 - Apply padding to caption buttons so off button clicks work. r=neil, a=final.
authorJim Mathies <jmathies@mozilla.com>
Mon, 29 Nov 2010 10:19:17 -0600
changeset 58328 c0d1cdc4553a2dabcddcbf5b08611bb3f1673732
parent 58327 d9cf761c6af47fd7cccac6f2ce9a1fa875ed387b
child 58329 0a758eabb2bb46cc2d47b7e98d74630475fea842
push id17246
push userjmathies@mozilla.com
push dateMon, 29 Nov 2010 16:19:29 +0000
treeherdermozilla-central@42a1862dd862 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersneil, final
bugs606160
milestone2.0b8pre
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 606160 - Apply padding to caption buttons so off button clicks work. r=neil, a=final.
widget/src/windows/nsNativeThemeWin.cpp
--- a/widget/src/windows/nsNativeThemeWin.cpp
+++ b/widget/src/windows/nsNativeThemeWin.cpp
@@ -317,16 +317,111 @@ static HRESULT DrawThemeBGRTLAware(HANDL
         return hr;
     }
   }
 
   // Draw normally if LTR or if anything went wrong
   return nsUXThemeData::drawThemeBG(theme, hdc, part, state, widgetRect, clipRect);
 }
 
+/*
+  Caption button padding data - 'hot' button padding.
+  These areas are considered hot, in that they activate
+  a button when hovered or clicked. The button graphic
+  is drawn inside the padding border. Unrecognized themes
+  are treated as their recognized counterparts for now.
+                       left      top    right   bottom
+  classic min             1        2        0        1
+  classic max             0        2        1        1
+  classic close           1        2        2        1
+
+  aero basic min          1        2        0        2
+  aero basic max          0        2        1        2
+  aero basic close        1        2        1        2
+
+  xp theme min            0        2        0        2
+  xp theme max            0        2        1        2
+  xp theme close          1        2        2        2
+
+  'cold' button padding - generic button padding, should
+  be handled in css.
+                       left      top    right   bottom
+  classic min             0        0        0        0
+  classic max             0        0        0        0
+  classic close           0        0        0        0
+
+  aero basic min          0        0        1        0
+  aero basic max          1        0        0        0
+  aero basic close        0        0        0        0
+
+  xp theme min            0        0        1        0
+  xp theme max            1        0        0        0
+  xp theme close          0        0        0        0
+*/
+
+enum CaptionDesktopTheme {
+  CAPTION_CLASSIC = 0,
+  CAPTION_BASIC,
+  CAPTION_XPTHEME,
+};
+
+enum CaptionButton {
+  CAPTIONBUTTON_MINIMIZE = 0,
+  CAPTIONBUTTON_RESTORE,
+  CAPTIONBUTTON_CLOSE,
+};
+
+struct CaptionButtonPadding {
+  RECT hotPadding[3];
+};
+
+// RECT: left, top, right, bottom
+static CaptionButtonPadding buttonData[3] = {
+  { 
+    { { 1, 2, 0, 1 }, { 0, 2, 1, 1 }, { 1, 2, 2, 1 } }
+  },
+  { 
+    { { 1, 2, 0, 2 }, { 0, 2, 1, 2 }, { 1, 2, 2, 2 } }
+  },
+  { 
+    { { 0, 2, 0, 2 }, { 0, 2, 1, 2 }, { 1, 2, 2, 2 } }
+  }
+};
+
+// Adds "hot" caption button padding to minimum widget size.
+static void AddPaddingRect(nsIntSize* aSize, CaptionButton button) {
+  if (!aSize)
+    return;
+  RECT offset;
+  if (!nsUXThemeData::IsAppThemed())
+    offset = buttonData[CAPTION_CLASSIC].hotPadding[button];
+  else if (nsWindow::GetWindowsVersion() == WINXP_VERSION)
+    offset = buttonData[CAPTION_XPTHEME].hotPadding[button];
+  else
+    offset = buttonData[CAPTION_BASIC].hotPadding[button];
+  aSize->width += offset.left + offset.right;
+  aSize->height += offset.top + offset.bottom;
+}
+
+// If we've added padding to the minimum widget size, offset
+// the area we draw into to compensate.
+static void OffsetBackgroundRect(RECT& rect, CaptionButton button) {
+  RECT offset;
+  if (!nsUXThemeData::IsAppThemed())
+    offset = buttonData[CAPTION_CLASSIC].hotPadding[button];
+  else if (nsWindow::GetWindowsVersion() == WINXP_VERSION)
+    offset = buttonData[CAPTION_XPTHEME].hotPadding[button];
+  else
+    offset = buttonData[CAPTION_BASIC].hotPadding[button];
+  rect.left += offset.left;
+  rect.top += offset.top;
+  rect.right -= offset.right;
+  rect.bottom -= offset.bottom;
+}
+
 HANDLE
 nsNativeThemeWin::GetTheme(PRUint8 aWidgetType)
 { 
   if (!nsUXThemeData::sIsVistaOrLater) {
     // On XP or earlier, render dropdowns as textfields;
     // doing it the right way works fine with the MS themes,
     // but breaks on a lot of custom themes (presumably because MS
     // apps do the textfield border business as well).
@@ -1225,16 +1320,26 @@ RENDER_AGAIN:
       if (isLeft)
         // The right edge should not be drawn.  Extend our rect by the edge size.
         widgetRect.right += edgeSize;
       else
         // The left edge should not be drawn.  Move the widget rect's left coord back.
         widgetRect.left -= edgeSize;
     }
   }
+  else if (aWidgetType == NS_THEME_WINDOW_BUTTON_MINIMIZE) {
+    OffsetBackgroundRect(widgetRect, CAPTIONBUTTON_MINIMIZE);
+  }
+  else if (aWidgetType == NS_THEME_WINDOW_BUTTON_MAXIMIZE ||
+           aWidgetType == NS_THEME_WINDOW_BUTTON_RESTORE) {
+    OffsetBackgroundRect(widgetRect, CAPTIONBUTTON_RESTORE);
+  }
+  else if (aWidgetType == NS_THEME_WINDOW_BUTTON_CLOSE) {
+    OffsetBackgroundRect(widgetRect, CAPTIONBUTTON_CLOSE);
+  }
 
   // widgetRect is the bounding box for a widget, yet the scale track is only
   // a small portion of this size, so the edges of the scale need to be
   // adjusted to the real size of the track.
   if (aWidgetType == NS_THEME_SCALE_HORIZONTAL ||
       aWidgetType == NS_THEME_SCALE_VERTICAL) {
     RECT contentRect;
     nsUXThemeData::getThemeContentRect(theme, hdc, part, state, &widgetRect, &contentRect);
@@ -1501,16 +1606,18 @@ nsNativeThemeWin::GetWidgetBorder(nsIDev
       aWidgetType == NS_THEME_STATUSBAR || 
       aWidgetType == NS_THEME_RESIZER || aWidgetType == NS_THEME_TAB_PANEL ||
       aWidgetType == NS_THEME_SCROLLBAR_TRACK_HORIZONTAL ||
       aWidgetType == NS_THEME_SCROLLBAR_TRACK_VERTICAL ||
       aWidgetType == NS_THEME_MENUITEM || aWidgetType == NS_THEME_CHECKMENUITEM ||
       aWidgetType == NS_THEME_RADIOMENUITEM || aWidgetType == NS_THEME_MENUPOPUP ||
       aWidgetType == NS_THEME_MENUIMAGE || aWidgetType == NS_THEME_MENUITEMTEXT ||
       aWidgetType == NS_THEME_TOOLBAR_SEPARATOR ||
+      aWidgetType == NS_THEME_WINDOW_TITLEBAR ||
+      aWidgetType == NS_THEME_WINDOW_TITLEBAR_MAXIMIZED ||
       aWidgetType == NS_THEME_WIN_GLASS || aWidgetType == NS_THEME_WIN_BORDERLESS_GLASS)
     return NS_OK; // Don't worry about it.
 
   if (!nsUXThemeData::getThemeContentRect)
     return NS_ERROR_FAILURE;
 
   PRInt32 part, state;
   nsresult rv = GetThemePartAndState(aFrame, aWidgetType, part, state);
@@ -1592,34 +1699,16 @@ nsNativeThemeWin::GetWidgetPadding(nsIDe
     // 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);
@@ -1899,38 +1988,41 @@ nsNativeThemeWin::GetMinimumWidgetSize(n
       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;
       }
+      AddPaddingRect(aResult, CAPTIONBUTTON_RESTORE);
       *aIsOverridable = PR_FALSE;
       return NS_OK;
 
     case NS_THEME_WINDOW_BUTTON_MINIMIZE:
       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;
       }
+      AddPaddingRect(aResult, CAPTIONBUTTON_MINIMIZE);
       *aIsOverridable = PR_FALSE;
       return NS_OK;
 
     case NS_THEME_WINDOW_BUTTON_CLOSE:
       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;
       }
+      AddPaddingRect(aResult, CAPTIONBUTTON_CLOSE);
       *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;
@@ -2480,16 +2572,26 @@ nsNativeThemeWin::ClassicGetMinimumWidge
     case NS_THEME_WINDOW_BUTTON_MAXIMIZE:
     case NS_THEME_WINDOW_BUTTON_RESTORE:
       aResult->width = GetSystemMetrics(SM_CXSIZE);
       aResult->height = GetSystemMetrics(SM_CYSIZE);
       // XXX I have no idea why these caption metrics are always off,
       // but they are.
       aResult->width -= 2;
       aResult->height -= 4;
+      if (aWidgetType == NS_THEME_WINDOW_BUTTON_MINIMIZE) {
+        AddPaddingRect(aResult, CAPTIONBUTTON_MINIMIZE);
+      }
+      else if (aWidgetType == NS_THEME_WINDOW_BUTTON_MAXIMIZE ||
+               aWidgetType == NS_THEME_WINDOW_BUTTON_RESTORE) {
+        AddPaddingRect(aResult, CAPTIONBUTTON_RESTORE);
+      }
+      else if (aWidgetType == NS_THEME_WINDOW_BUTTON_CLOSE) {
+        AddPaddingRect(aResult, CAPTIONBUTTON_CLOSE);
+      }
     break;
 
     default:
       return NS_ERROR_FAILURE;
   }  
   return NS_OK;
 }
 
@@ -3364,16 +3466,26 @@ RENDER_AGAIN:
       DrawEdge(hdc, &widgetRect, EDGE_RAISED, BF_BOTTOM);
       break;
 
     case NS_THEME_WINDOW_BUTTON_CLOSE:
     case NS_THEME_WINDOW_BUTTON_MINIMIZE:
     case NS_THEME_WINDOW_BUTTON_MAXIMIZE:
     case NS_THEME_WINDOW_BUTTON_RESTORE:
     {
+      if (aWidgetType == NS_THEME_WINDOW_BUTTON_MINIMIZE) {
+        OffsetBackgroundRect(widgetRect, CAPTIONBUTTON_MINIMIZE);
+      }
+      else if (aWidgetType == NS_THEME_WINDOW_BUTTON_MAXIMIZE ||
+               aWidgetType == NS_THEME_WINDOW_BUTTON_RESTORE) {
+        OffsetBackgroundRect(widgetRect, CAPTIONBUTTON_RESTORE);
+      }
+      else if (aWidgetType == NS_THEME_WINDOW_BUTTON_CLOSE) {
+        OffsetBackgroundRect(widgetRect, CAPTIONBUTTON_CLOSE);
+      }
       PRInt32 oldTA = SetTextAlign(hdc, TA_TOP | TA_LEFT | TA_NOUPDATECP);
       DrawFrameControl(hdc, &widgetRect, part, state);
       SetTextAlign(hdc, oldTA);
       break;
     }
 
     default:
       rv = NS_ERROR_FAILURE;