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 id1
push usershaver@mozilla.com
push dateTue, 04 Jan 2011 17:58:04 +0000
reviewersneil, final
bugs606160
milestone2.0b8pre
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;