Bug 406474 - "Native GTK look for toolbar arrows" [p=twanno@lycos.nl (Teune van Steeg) r+sr=roc a1.9=beltzner]
authorreed@reedloden.com
Thu, 14 Feb 2008 21:28:44 -0800
changeset 11754 bb236428a18c749c531680dbda38be3691f22eed
parent 11753 3fb0510430959b9d39810a469ed41672ccc1a5d9
child 11755 8bb7540dd186fd9c3f58451d67a1f3a57b8d83f1
push idunknown
push userunknown
push dateunknown
bugs406474
milestone1.9b4pre
Bug 406474 - "Native GTK look for toolbar arrows" [p=twanno@lycos.nl (Teune van Steeg) r+sr=roc a1.9=beltzner]
browser/themes/gnomestripe/browser/browser.css
gfx/public/nsThemeConstants.h
layout/style/nsCSSKeywordList.h
layout/style/nsCSSProps.cpp
widget/src/gtk2/gtk2drawing.c
widget/src/gtk2/gtkdrawing.h
widget/src/gtk2/nsNativeThemeGTK.cpp
--- a/browser/themes/gnomestripe/browser/browser.css
+++ b/browser/themes/gnomestripe/browser/browser.css
@@ -1243,16 +1243,27 @@ tabpanels {
   list-style-image: url("moz-icon://stock/gtk-close?size=menu");
   border: none;
 }
 
 .tabs-closebutton > .toolbarbutton-icon {
   margin: -3px !important;
 }
 
+/* Tabbrowser arrowscrollbox arrows */
+.tabbrowser-arrowscrollbox > .scrollbutton-up {
+  -moz-appearance: tab-scroll-arrow-back;
+  margin: 0px;
+}
+
+.tabbrowser-arrowscrollbox > .scrollbutton-down {
+  -moz-appearance: tab-scroll-arrow-forward;
+  margin: 0px;
+}
+
 /* All tabs menupopup */
 .alltabs-item > .menu-iconic-left > .menu-iconic-icon {
   list-style-image: url("chrome://global/skin/icons/folder-item.png");
   -moz-image-region: rect(0px, 16px, 16px, 0px);
 }
 
 .alltabs-item[selected="true"] {
   font-weight: bold;
--- a/gfx/public/nsThemeConstants.h
+++ b/gfx/public/nsThemeConstants.h
@@ -109,16 +109,20 @@
 #define NS_THEME_TAB_LEFT_EDGE                             63
 
 // The tab just after the selection
 #define NS_THEME_TAB_RIGHT_EDGE                            64
 
 // The tab panels container.
 #define NS_THEME_TAB_PANELS                                65
 
+// The tabs scroll arrows (left/right)
+#define NS_THEME_TAB_SCROLLARROW_BACK                      66
+#define NS_THEME_TAB_SCROLLARROW_FORWARD                   67
+
 // A tooltip
 #define NS_THEME_TOOLTIP                                   71
 
 // A spin control (up/down control for time/date pickers)
 #define NS_THEME_SPINNER                                   72
 
 // The up button of a spin control
 #define NS_THEME_SPINNER_UP_BUTTON                         73
--- a/layout/style/nsCSSKeywordList.h
+++ b/layout/style/nsCSSKeywordList.h
@@ -500,16 +500,18 @@ CSS_KEY(progressbar, progressbar)
 CSS_KEY(progressbar-vertical, progressbar_vertical)
 CSS_KEY(progresschunk, progresschunk)
 CSS_KEY(progresschunk-vertical, progresschunk_vertical)
 CSS_KEY(tab, tab)
 CSS_KEY(tab-left-edge, tab_left_edge)
 CSS_KEY(tab-right-edge, tab_right_edge)
 CSS_KEY(tabpanels, tabpanels)
 CSS_KEY(tabpanel, tabpanel)
+CSS_KEY(tab-scroll-arrow-back, tabscrollarrow_back)
+CSS_KEY(tab-scroll-arrow-forward, tabscrollarrow_forward)
 CSS_KEY(tooltip, tooltip)
 CSS_KEY(spinner, spinner)
 CSS_KEY(spinner-upbutton, spinner_upbutton)
 CSS_KEY(spinner-downbutton, spinner_downbutton)
 CSS_KEY(spinner-textfield, spinner_textfield)
 CSS_KEY(scrollbarbutton-up, scrollbarbutton_up)
 CSS_KEY(scrollbarbutton-down, scrollbarbutton_down)
 CSS_KEY(scrollbarbutton-left, scrollbarbutton_left)
--- a/layout/style/nsCSSProps.cpp
+++ b/layout/style/nsCSSProps.cpp
@@ -209,16 +209,18 @@ const PRInt32 nsCSSProps::kAppearanceKTa
   eCSSKeyword_progresschunk,          NS_THEME_PROGRESSBAR_CHUNK,
   eCSSKeyword_progressbar_vertical,   NS_THEME_PROGRESSBAR_VERTICAL,
   eCSSKeyword_progresschunk_vertical, NS_THEME_PROGRESSBAR_CHUNK_VERTICAL,
   eCSSKeyword_tab,                    NS_THEME_TAB,
   eCSSKeyword_tab_left_edge,          NS_THEME_TAB_LEFT_EDGE,
   eCSSKeyword_tab_right_edge,         NS_THEME_TAB_RIGHT_EDGE,
   eCSSKeyword_tabpanels,              NS_THEME_TAB_PANELS,
   eCSSKeyword_tabpanel,               NS_THEME_TAB_PANEL,
+  eCSSKeyword_tabscrollarrow_back,    NS_THEME_TAB_SCROLLARROW_BACK,
+  eCSSKeyword_tabscrollarrow_forward, NS_THEME_TAB_SCROLLARROW_FORWARD,
   eCSSKeyword_tooltip,                NS_THEME_TOOLTIP,
   eCSSKeyword_spinner,                NS_THEME_SPINNER,
   eCSSKeyword_spinner_upbutton,       NS_THEME_SPINNER_UP_BUTTON,
   eCSSKeyword_spinner_downbutton,     NS_THEME_SPINNER_DOWN_BUTTON,
   eCSSKeyword_spinner_textfield,      NS_THEME_SPINNER_TEXTFIELD,
   eCSSKeyword_scrollbar,              NS_THEME_SCROLLBAR,
   eCSSKeyword_scrollbar_small,        NS_THEME_SCROLLBAR_SMALL,
   eCSSKeyword_scrollbarbutton_up,     NS_THEME_SCROLLBAR_BUTTON_UP,
--- a/widget/src/gtk2/gtk2drawing.c
+++ b/widget/src/gtk2/gtk2drawing.c
@@ -2024,16 +2024,46 @@ moz_gtk_tabpanels_paint(GdkDrawable* dra
                       cliprect, gTabWidget, "notebook", rect->x, rect->y,
                       rect->width, rect->height,
                       GTK_POS_TOP, -10, 0);
 
     return MOZ_GTK_SUCCESS;
 }
 
 static gint
+moz_gtk_tab_scroll_arrow_paint(GdkDrawable* drawable, GdkRectangle* rect,
+                               GdkRectangle* cliprect, GtkWidgetState* state,
+                               GtkArrowType arrow_type,
+                               GtkTextDirection direction)
+{
+    GtkStateType state_type = ConvertGtkState(state);
+    GtkShadowType shadow_type = state->active ? GTK_SHADOW_IN : GTK_SHADOW_OUT;
+    GtkStyle* style;
+    gint arrow_size = MIN(rect->width, rect->height);
+    gint x = rect->x + (rect->width - arrow_size) / 2;
+    gint y = rect->y + (rect->height - arrow_size) / 2;
+
+    ensure_tab_widget();
+
+    style = gTabWidget->style;
+    TSOffsetStyleGCs(style, rect->x, rect->y);
+
+    if (direction == GTK_TEXT_DIR_RTL) {
+        arrow_type = (arrow_type == GTK_ARROW_LEFT) ?
+                         GTK_ARROW_RIGHT : GTK_ARROW_LEFT;
+    }
+
+    gtk_paint_arrow(style, drawable, state_type, shadow_type, NULL,
+                    gTabWidget, "notebook", arrow_type, TRUE,
+                    x, y, arrow_size, arrow_size);
+
+    return MOZ_GTK_SUCCESS;
+}
+
+static gint
 moz_gtk_menu_bar_paint(GdkDrawable* drawable, GdkRectangle* rect,
                        GdkRectangle* cliprect, GtkTextDirection direction)
 {
     GtkStyle* style;
     GtkShadowType shadow_type;
     ensure_menu_bar_widget();
     gtk_widget_set_direction(gMenuBarWidget, direction);
 
@@ -2477,16 +2507,17 @@ moz_gtk_get_widget_border(GtkThemeWidget
     case MOZ_GTK_SPINBUTTON:
     case MOZ_GTK_TOOLTIP:
     case MOZ_GTK_WINDOW:
     case MOZ_GTK_RESIZER:
     case MOZ_GTK_MENUARROW:
     case MOZ_GTK_TOOLBARBUTTON_ARROW:
     case MOZ_GTK_TOOLBAR:
     case MOZ_GTK_MENUBAR:
+    case MOZ_GTK_TAB_SCROLLARROW:
         *left = *top = *right = *bottom = 0;
         return MOZ_GTK_SUCCESS;
     default:
         g_warning("Unsupported widget type: %d", widget);
         return MOZ_GTK_UNKNOWN_WIDGET;
     }
 
     *right = *left = XTHICKNESS(w->style);
@@ -2512,16 +2543,31 @@ moz_gtk_get_dropdown_arrow_size(gint* wi
 
     *height = 2 * (1 + YTHICKNESS(gDropdownButtonWidget->style));
     *height += min_arrow_size + GTK_MISC(gArrowWidget)->ypad * 2;
 
     return MOZ_GTK_SUCCESS;
 }
 
 gint
+moz_gtk_get_tab_scroll_arrow_size(gint* width, gint* height)
+{
+    gint arrow_size;
+
+    ensure_tab_widget();
+    gtk_widget_style_get(gTabWidget,
+                         "scroll-arrow-hlength", &arrow_size,
+                         NULL);
+
+    *height = *width = arrow_size;
+
+    return MOZ_GTK_SUCCESS;
+}
+
+gint
 moz_gtk_get_toolbar_separator_width(gint* size)
 {
     gboolean wide_separators;
     gint separator_width;
     GtkStyle* style;
 
     ensure_toolbar_widget();
 
@@ -2763,16 +2809,20 @@ moz_gtk_widget_paint(GtkThemeWidgetType 
         break;
     case MOZ_GTK_TAB:
         return moz_gtk_tab_paint(drawable, rect, cliprect,
                                  (GtkTabFlags) flags, direction);
         break;
     case MOZ_GTK_TABPANELS:
         return moz_gtk_tabpanels_paint(drawable, rect, cliprect, direction);
         break;
+    case MOZ_GTK_TAB_SCROLLARROW:
+        return moz_gtk_tab_scroll_arrow_paint(drawable, rect, cliprect, state,
+                                              (GtkArrowType) flags, direction);
+        break;
     case MOZ_GTK_MENUBAR:
         return moz_gtk_menu_bar_paint(drawable, rect, cliprect, direction);
         break;
     case MOZ_GTK_MENUPOPUP:
         return moz_gtk_menu_popup_paint(drawable, rect, cliprect, direction);
         break;
     case MOZ_GTK_MENUSEPARATOR:
         return moz_gtk_menu_separator_paint(drawable, rect, cliprect,
--- a/widget/src/gtk2/gtkdrawing.h
+++ b/widget/src/gtk2/gtkdrawing.h
@@ -171,16 +171,18 @@ typedef enum {
   /* Paints a GtkProgressBar. */
   MOZ_GTK_PROGRESSBAR,
   /* Paints a progress chunk of a GtkProgressBar. */
   MOZ_GTK_PROGRESS_CHUNK,
   /* Paints a tab of a GtkNotebook. flags is a GtkTabFlags, defined above. */
   MOZ_GTK_TAB,
   /* Paints the background and border of a GtkNotebook. */
   MOZ_GTK_TABPANELS,
+  /* Paints a GtkArrow for a GtkNotebook. flags is a GtkArrowType. */
+  MOZ_GTK_TAB_SCROLLARROW,
   /* Paints the background and border of a GtkTreeView */
   MOZ_GTK_TREEVIEW,
   /* Paints treeheader cells */
   MOZ_GTK_TREE_HEADER_CELL,
   /* Paints sort arrows in treeheader cells */
   MOZ_GTK_TREE_HEADER_SORTARROW,
   /* Paints an expander for a GtkTreeView */
   MOZ_GTK_TREEVIEW_EXPANDER,
@@ -337,16 +339,25 @@ moz_gtk_get_scrollbar_metrics(MozGtkScro
  * width:   [OUT] the desired width
  * height:  [OUT] the desired height
  *
  * returns:    MOZ_GTK_SUCCESS if there was no error, an error code otherwise
  */
 gint moz_gtk_get_dropdown_arrow_size(gint* width, gint* height);
 
 /**
+ * Get the desired size of a scroll arrow widget
+ * width:   [OUT] the desired width
+ * height:  [OUT] the desired height
+ *
+ * returns:    MOZ_GTK_SUCCESS if there was no error, an error code otherwise
+ */
+gint moz_gtk_get_tab_scroll_arrow_size(gint* width, gint* height);
+
+/**
  * Get the desired size of a toolbar separator
  * size:    [OUT] the desired width
  *
  * returns: MOZ_GTK_SUCCESS if there was no error, an error code otherwise
  */
 gint moz_gtk_get_toolbar_separator_width(gint* size);
 
 /**
--- a/widget/src/gtk2/nsNativeThemeGTK.cpp
+++ b/widget/src/gtk2/nsNativeThemeGTK.cpp
@@ -520,16 +520,23 @@ nsNativeThemeGTK::GetGtkWidgetAndState(P
   case NS_THEME_PROGRESSBAR:
   case NS_THEME_PROGRESSBAR_VERTICAL:
     aGtkWidgetType = MOZ_GTK_PROGRESSBAR;
     break;
   case NS_THEME_PROGRESSBAR_CHUNK:
   case NS_THEME_PROGRESSBAR_CHUNK_VERTICAL:
     aGtkWidgetType = MOZ_GTK_PROGRESS_CHUNK;
     break;
+  case NS_THEME_TAB_SCROLLARROW_BACK:
+  case NS_THEME_TAB_SCROLLARROW_FORWARD:
+    if (aWidgetFlags)
+      *aWidgetFlags = aWidgetType == NS_THEME_TAB_SCROLLARROW_BACK ?
+                        GTK_ARROW_LEFT : GTK_ARROW_RIGHT;
+    aGtkWidgetType = MOZ_GTK_TAB_SCROLLARROW;
+    break;
   case NS_THEME_TAB_PANELS:
     aGtkWidgetType = MOZ_GTK_TABPANELS;
     break;
   case NS_THEME_TAB:
     {
       if (aWidgetFlags) {
         /* First bits will be used to store max(0,-bmargin) where bmargin
          * is the bottom margin of the tab in pixels  (resp. top margin,
@@ -885,17 +892,19 @@ nsNativeThemeGTK::GetWidgetBorder(nsIDev
 
 PRBool
 nsNativeThemeGTK::GetWidgetPadding(nsIDeviceContext* aContext,
                                    nsIFrame* aFrame, PRUint8 aWidgetType,
                                    nsMargin* aResult)
 {
   if (aWidgetType == NS_THEME_BUTTON_FOCUS ||
       aWidgetType == NS_THEME_TOOLBAR_BUTTON ||
-      aWidgetType == NS_THEME_TOOLBAR_DUAL_BUTTON) {
+      aWidgetType == NS_THEME_TOOLBAR_DUAL_BUTTON ||
+      aWidgetType == NS_THEME_TAB_SCROLLARROW_BACK ||
+      aWidgetType == NS_THEME_TAB_SCROLLARROW_FORWARD) {
     aResult->SizeTo(0, 0, 0, 0);
     return PR_TRUE;
   }
 
   return PR_FALSE;
 }
 
 PRBool
@@ -1029,16 +1038,23 @@ nsNativeThemeGTK::GetMinimumWidgetSize(n
           moz_gtk_get_scalethumb_metrics(GTK_ORIENTATION_HORIZONTAL, &thumb_length, &thumb_height);
           aResult->width = thumb_length;
           aResult->height = thumb_height;
         }
 
         *aIsOverridable = PR_FALSE;
       }
       break;
+    case NS_THEME_TAB_SCROLLARROW_BACK:
+    case NS_THEME_TAB_SCROLLARROW_FORWARD:
+      {
+        moz_gtk_get_tab_scroll_arrow_size(&aResult->width, &aResult->height);
+        *aIsOverridable = PR_FALSE;
+      }
+      break;
   case NS_THEME_DROPDOWN_BUTTON:
     {
       moz_gtk_get_dropdown_arrow_size(&aResult->width, &aResult->height);
       *aIsOverridable = PR_FALSE;
     }
     break;
   case NS_THEME_MENUSEPARATOR:
     {
@@ -1239,16 +1255,18 @@ nsNativeThemeGTK::ThemeSupportsWidget(ns
   case NS_THEME_TREEVIEW_TWISTY_OPEN:
     case NS_THEME_PROGRESSBAR:
     case NS_THEME_PROGRESSBAR_CHUNK:
     case NS_THEME_PROGRESSBAR_VERTICAL:
     case NS_THEME_PROGRESSBAR_CHUNK_VERTICAL:
     case NS_THEME_TAB:
     // case NS_THEME_TAB_PANEL:
     case NS_THEME_TAB_PANELS:
+    case NS_THEME_TAB_SCROLLARROW_BACK:
+    case NS_THEME_TAB_SCROLLARROW_FORWARD:
   case NS_THEME_TOOLTIP:
   case NS_THEME_SPINNER:
   case NS_THEME_SPINNER_UP_BUTTON:
   case NS_THEME_SPINNER_DOWN_BUTTON:
   case NS_THEME_SPINNER_TEXTFIELD:
     // case NS_THEME_SCROLLBAR:  (n/a for gtk)
     // case NS_THEME_SCROLLBAR_SMALL: (n/a for gtk)
   case NS_THEME_SCROLLBAR_BUTTON_UP:
@@ -1300,19 +1318,21 @@ nsNativeThemeGTK::ThemeSupportsWidget(ns
 
   return PR_FALSE;
 }
 
 NS_IMETHODIMP_(PRBool)
 nsNativeThemeGTK::WidgetIsContainer(PRUint8 aWidgetType)
 {
   // XXXdwh At some point flesh all of this out.
-  if (aWidgetType == NS_THEME_DROPDOWN_BUTTON || 
+  if (aWidgetType == NS_THEME_DROPDOWN_BUTTON ||
       IsRadioWidgetType(aWidgetType) ||
-      IsCheckboxWidgetType(aWidgetType))
+      IsCheckboxWidgetType(aWidgetType) ||
+      aWidgetType == NS_THEME_TAB_SCROLLARROW_BACK ||
+      aWidgetType == NS_THEME_TAB_SCROLLARROW_FORWARD)
     return PR_FALSE;
   return PR_TRUE;
 }
 
 PRBool
 nsNativeThemeGTK::ThemeDrawsFocusForWidget(nsPresContext* aPresContext, nsIFrame* aFrame, PRUint8 aWidgetType)
 {
    if (aWidgetType == NS_THEME_DROPDOWN ||