--- a/widget/gtk/gtk3drawing.cpp
+++ b/widget/gtk/gtk3drawing.cpp
@@ -19,16 +19,17 @@
#include <math.h>
#include <dlfcn.h>
static gboolean checkbox_check_state;
static gboolean notebook_has_tab_gap;
static ScrollbarGTKMetrics sScrollbarMetrics[2];
+static ScrollbarGTKMetrics sScrollbarMetricsActive[2];
static ToggleGTKMetrics sCheckboxMetrics;
static ToggleGTKMetrics sRadioMetrics;
static ToolbarGTKMetrics sToolbarMetrics;
#define ARROW_UP 0
#define ARROW_DOWN G_PI
#define ARROW_RIGHT G_PI_2
#define ARROW_LEFT (G_PI+G_PI_2)
@@ -177,16 +178,18 @@ moz_gtk_refresh()
"has-tab-gap", ¬ebook_has_tab_gap, NULL);
}
else {
notebook_has_tab_gap = true;
}
sScrollbarMetrics[GTK_ORIENTATION_HORIZONTAL].initialized = false;
sScrollbarMetrics[GTK_ORIENTATION_VERTICAL].initialized = false;
+ sScrollbarMetricsActive[GTK_ORIENTATION_HORIZONTAL].initialized = false;
+ sScrollbarMetricsActive[GTK_ORIENTATION_VERTICAL].initialized = false;
sCheckboxMetrics.initialized = false;
sRadioMetrics.initialized = false;
sToolbarMetrics.initialized = false;
/* This will destroy all of our widgets */
ResetWidgetCache();
}
@@ -735,20 +738,19 @@ GetMinContentBox(GtkStyleContext* style)
return {width, height};
}
/**
* Get minimum widget size as sum of margin, padding, border and
* min-width/min-height.
*/
static void
-moz_gtk_get_widget_min_size(WidgetNodeType aGtkWidgetType, int* width,
+moz_gtk_get_widget_min_size(GtkStyleContext* style, int* width,
int* height)
{
- GtkStyleContext* style = GetStyleContext(aGtkWidgetType);
GtkStateFlags state_flags = gtk_style_context_get_state(style);
gtk_style_context_get(style, state_flags,
"min-height", height,
"min-width", width,
nullptr);
GtkBorder border, padding, margin;
gtk_style_context_get_border(style, state_flags, &border);
@@ -757,20 +759,20 @@ moz_gtk_get_widget_min_size(WidgetNodeTy
*width += border.left + border.right + margin.left + margin.right +
padding.left + padding.right;
*height += border.top + border.bottom + margin.top + margin.bottom +
padding.top + padding.bottom;
}
static MozGtkSize
-GetMinMarginBox(WidgetNodeType aNodeType)
+GetMinMarginBox(GtkStyleContext* style)
{
gint width, height;
- moz_gtk_get_widget_min_size(aNodeType, &width, &height);
+ moz_gtk_get_widget_min_size(style, &width, &height);
return {width, height};
}
static void
Inset(GdkRectangle* rect, const GtkBorder& aBorder)
{
MOZ_ASSERT(rect);
rect->x += aBorder.left;
@@ -942,17 +944,17 @@ moz_gtk_scrollbar_trough_paint(WidgetNod
{
GdkRectangle rect = *aRect;
GtkStyleContext* style;
if (gtk_get_minor_version() >= 20) {
WidgetNodeType thumb = widget == MOZ_GTK_SCROLLBAR_TROUGH_VERTICAL ?
MOZ_GTK_SCROLLBAR_THUMB_VERTICAL :
MOZ_GTK_SCROLLBAR_THUMB_HORIZONTAL;
- MozGtkSize thumbSize = GetMinMarginBox(thumb);
+ MozGtkSize thumbSize = GetMinMarginBox(GetStyleContext(thumb));
style = GetStyleContext(widget, direction);
MozGtkSize trackSize = GetMinContentBox(style);
trackSize.Include(thumbSize);
trackSize += GetMarginBorderPadding(style);
// Gecko's trough |aRect| fills available breadth, but GTK's trough is
// centered in the contents_gadget. The centering here round left
// and up, like gtk_box_gadget_allocate_child().
if (widget == MOZ_GTK_SCROLLBAR_TROUGH_VERTICAL) {
@@ -2760,17 +2762,18 @@ moz_gtk_get_scale_metrics(GtkOrientation
} else {
*scale_width = thumb_height + trough_border * 2;
*scale_height = thumb_length + trough_border * 2;
}
} else {
WidgetNodeType widget = (orient == GTK_ORIENTATION_HORIZONTAL) ?
MOZ_GTK_SCALE_TROUGH_HORIZONTAL :
MOZ_GTK_SCALE_TROUGH_VERTICAL;
- moz_gtk_get_widget_min_size(widget, scale_width, scale_height);
+ moz_gtk_get_widget_min_size(GetStyleContext(widget),
+ scale_width, scale_height);
}
}
gint
moz_gtk_get_scalethumb_metrics(GtkOrientation orient, gint* thumb_length, gint* thumb_height)
{
if (gtk_check_version(3, 20, 0) != nullptr) {
@@ -2879,29 +2882,32 @@ GetToggleMetrics(bool isRadio)
nullptr);
metrics->minSizeWithBorder.width =
metrics->minSizeWithBorder.height = indicator_size;
}
return metrics;
}
const ScrollbarGTKMetrics*
-GetScrollbarMetrics(GtkOrientation aOrientation)
+GetScrollbarMetrics(GtkOrientation aOrientation, bool aActive)
{
- auto metrics = &sScrollbarMetrics[aOrientation];
+ auto metrics = aActive ? &sScrollbarMetricsActive[aOrientation] :
+ &sScrollbarMetrics[aOrientation];
if (metrics->initialized)
return metrics;
metrics->initialized = true;
WidgetNodeType scrollbar = aOrientation == GTK_ORIENTATION_HORIZONTAL ?
MOZ_GTK_SCROLLBAR_HORIZONTAL : MOZ_GTK_SCROLLBAR_VERTICAL;
gboolean backward, forward, secondary_backward, secondary_forward;
- GtkStyleContext* style = GetStyleContext(scrollbar);
+ GtkStyleContext* style = GetStyleContext(scrollbar, GTK_TEXT_DIR_NONE,
+ aActive ? GTK_STATE_FLAG_PRELIGHT :
+ GTK_STATE_FLAG_NORMAL);
gtk_style_context_get_style(style,
"has-backward-stepper", &backward,
"has-forward-stepper", &forward,
"has-secondary-backward-stepper",
&secondary_backward,
"has-secondary-forward-stepper",
&secondary_forward, nullptr);
bool hasButtons =
@@ -2958,26 +2964,58 @@ GetScrollbarMetrics(GtkOrientation aOrie
contents = MOZ_GTK_SCROLLBAR_CONTENTS_HORIZONTAL;
track = MOZ_GTK_SCROLLBAR_TROUGH_HORIZONTAL;
thumb = MOZ_GTK_SCROLLBAR_THUMB_HORIZONTAL;
} else {
contents = MOZ_GTK_SCROLLBAR_CONTENTS_VERTICAL;
track = MOZ_GTK_SCROLLBAR_TROUGH_VERTICAL;
thumb = MOZ_GTK_SCROLLBAR_THUMB_VERTICAL;
}
+
+ /* GetStyleContext() sets GtkStateFlags to the latest widget name
+ * in css selector string. When we call:
+ *
+ * GetStyleContext(thumb, GTK_STATE_FLAG_PRELIGHT)
+ *
+ * we get:
+ *
+ * "scrollbar contents trough slider:hover"
+ *
+ * Some themes (Ubuntu Ambiance) styles trough/thumb by scrollbar,
+ * the Gtk+ css rule looks like:
+ *
+ * "scrollbar:hover contents trough slider"
+ *
+ * So we need to apply GtkStateFlags to each widgets in style path.
+ */
+
// thumb
- metrics->size.thumb = GetMinMarginBox(thumb);
+ style = CreateStyleContextWithStates(thumb, GTK_TEXT_DIR_NONE,
+ aActive ? GTK_STATE_FLAG_PRELIGHT :
+ GTK_STATE_FLAG_NORMAL);
+ metrics->size.thumb = GetMinMarginBox(style);
+ g_object_unref(style);
+
// track
- style = GetStyleContext(track);
+ style = CreateStyleContextWithStates(track, GTK_TEXT_DIR_NONE,
+ aActive ? GTK_STATE_FLAG_PRELIGHT :
+ GTK_STATE_FLAG_NORMAL);
metrics->border.track = GetMarginBorderPadding(style);
MozGtkSize trackMinSize = GetMinContentBox(style) + metrics->border.track;
MozGtkSize trackSizeForThumb = metrics->size.thumb + metrics->border.track;
+ g_object_unref(style);
+
// button
if (hasButtons) {
- metrics->size.button = GetMinMarginBox(MOZ_GTK_SCROLLBAR_BUTTON);
+ style = CreateStyleContextWithStates(MOZ_GTK_SCROLLBAR_BUTTON,
+ GTK_TEXT_DIR_NONE,
+ aActive ? GTK_STATE_FLAG_PRELIGHT :
+ GTK_STATE_FLAG_NORMAL);
+ metrics->size.button = GetMinMarginBox(style);
+ g_object_unref(style);
} else {
metrics->size.button = {0, 0};
}
if (aOrientation == GTK_ORIENTATION_HORIZONTAL) {
metrics->size.button.Rotate();
// If the track is wider than necessary for the thumb, including when
// the buttons will cause Gecko to expand the track to fill
// available breadth, then add to the track border to prevent Gecko
@@ -3001,18 +3039,21 @@ GetScrollbarMetrics(GtkOrientation aOrie
// If extra is odd, then the thumb is 0.5 pixels to the left
// of center as in gtk_range_compute_slider_position().
metrics->border.track.left += extra / 2;
metrics->border.track.right += extra - extra / 2;
trackSizeForThumb.width += extra;
}
}
- style = GetStyleContext(contents);
+ style = CreateStyleContextWithStates(contents, GTK_TEXT_DIR_NONE,
+ aActive ? GTK_STATE_FLAG_PRELIGHT :
+ GTK_STATE_FLAG_NORMAL);
GtkBorder contentsBorder = GetMarginBorderPadding(style);
+ g_object_unref(style);
metrics->size.scrollbar =
trackSizeForThumb + contentsBorder + metrics->border.scrollbar;
return metrics;
}
/* cairo_t *cr argument has to be a system-cairo. */
--- a/widget/gtk/gtkdrawing.h
+++ b/widget/gtk/gtkdrawing.h
@@ -48,16 +48,21 @@ struct MozGtkSize {
height += aBorder.top + aBorder.bottom;
return *this;
}
MozGtkSize operator+(const GtkBorder& aBorder) const
{
MozGtkSize result = *this;
return result += aBorder;
}
+ bool operator<(const MozGtkSize &aOther) const
+ {
+ return (width < aOther.width && height <= aOther.height) ||
+ (width <= aOther.width && height < aOther.height);
+ }
void Include(MozGtkSize aOther)
{
width = std::max(width, aOther.width);
height = std::max(height, aOther.height);
}
void Rotate()
{
gint tmp = width;
@@ -486,19 +491,22 @@ moz_gtk_get_scale_metrics(GtkOrientation
*
* returns: MOZ_GTK_SUCCESS if there was no error, an error code otherwise
*/
gint
moz_gtk_get_scalethumb_metrics(GtkOrientation orient, gint* thumb_length, gint* thumb_height);
/**
* Get the metrics in GTK pixels for a scrollbar.
+ * aOrientation: [IN] the scrollbar orientation
+ * aActive: [IN] Metricts for scrollbar with mouse pointer over it.
+ *
*/
const ScrollbarGTKMetrics*
-GetScrollbarMetrics(GtkOrientation aOrientation);
+GetScrollbarMetrics(GtkOrientation aOrientation, bool aActive = false);
/**
* Get the desired size of a dropdown arrow button
* width: [OUT] the desired width
* height: [OUT] the desired height
*
* returns: MOZ_GTK_SUCCESS if there was no error, an error code otherwise
*/