--- a/widget/gtk/gtk3drawing.cpp
+++ b/widget/gtk/gtk3drawing.cpp
@@ -43,26 +43,29 @@ moz_gtk_get_tab_thickness(GtkStyleContex
static gint
moz_gtk_menu_item_paint(WidgetNodeType widget, cairo_t *cr, GdkRectangle* rect,
GtkWidgetState* state, GtkTextDirection direction);
static GtkBorder
GetMarginBorderPadding(GtkStyleContext* aStyle);
static void
+Inset(GdkRectangle* rect, const GtkBorder& aBorder);
+
+static void
InsetByMargin(GdkRectangle* rect, GtkStyleContext* style);
static void
moz_gtk_add_style_margin(GtkStyleContext* style,
gint* left, gint* top, gint* right, gint* bottom)
{
GtkBorder margin;
- gtk_style_context_get_margin(style, GTK_STATE_FLAG_NORMAL, &margin);
-
+ gtk_style_context_get_margin(style, gtk_style_context_get_state(style),
+ &margin);
*left += margin.left;
*right += margin.right;
*top += margin.top;
*bottom += margin.bottom;
}
static void
moz_gtk_add_style_border(GtkStyleContext* style,
@@ -304,76 +307,202 @@ moz_gtk_splitter_get_metrics(gint orient
} else {
style = GetStyleContext(MOZ_GTK_SPLITTER_VERTICAL);
}
gtk_style_context_get_style(style, "handle_size", size, NULL);
return MOZ_GTK_SUCCESS;
}
static void
-InitToolbarButtonMetrics(ToolbarButtonGTKMetrics *aButtonMetrics,
- WidgetNodeType aWidgetType)
+CalculateToolbarButtonMetrics(WidgetNodeType aWidgetType,
+ ToolbarButtonGTKMetrics* aMetrics)
{
- GtkStyleContext* style = GetStyleContext(aWidgetType);
-
gint iconWidth, iconHeight;
if (!gtk_icon_size_lookup(GTK_ICON_SIZE_MENU, &iconWidth, &iconHeight)) {
NS_WARNING("Failed to get Gtk+ icon size for titlebar button!");
// Use some reasonable fallback size
iconWidth = 16;
iconHeight = 16;
}
+ GtkStyleContext* style = GetStyleContext(aWidgetType);
gint width = 0, height = 0;
if (gtk_check_version(3, 20, 0) == nullptr) {
gtk_style_context_get(style, gtk_style_context_get_state(style),
"min-width", &width,
"min-height", &height, NULL);
}
// Cover cases when min-width/min-height is not set, it's invalid
// or we're running on Gtk+ < 3.20.
if (width < iconWidth)
width = iconWidth;
if (height < iconHeight)
height = iconHeight;
gint left = 0, top = 0, right = 0, bottom = 0;
- moz_gtk_add_margin_border_padding(style, &left, &top, &right, &bottom);
-
+ moz_gtk_add_border_padding(style, &left, &top, &right, &bottom);
+
+ // Button size is calculated as min-width/height + border/padding.
width += left + right;
height += top + bottom;
- aButtonMetrics->minSizeWithBorderMargin.width = width;
- aButtonMetrics->minSizeWithBorderMargin.height = height;
-
- // Get border size from gap between icon and button sizes.
- // Buton size is calculated as min-width/height + border/padding.
- aButtonMetrics->iconXPosition = (width - iconWidth) / 2;
- aButtonMetrics->iconYPosition = (height - iconHeight) / 2;
+
+ // Place icon at button center.
+ aMetrics->iconXPosition = (width - iconWidth) / 2;
+ aMetrics->iconYPosition = (height - iconHeight) / 2;
+
+ aMetrics->minSizeWithBorderMargin.width = width;
+ aMetrics->minSizeWithBorderMargin.height = height;
+}
+
+// We support LTR layout only here for now.
+static void
+CalculateToolbarButtonSpacing(WidgetNodeType aWidgetType,
+ ToolbarButtonGTKMetrics* aMetrics)
+{
+ GtkStyleContext* style = GetStyleContext(aWidgetType);
+ gtk_style_context_get_margin(style, gtk_style_context_get_state(style),
+ &aMetrics->buttonMargin);
+
+ // Get titlebar spacing, a default one is 6 pixels (gtk/gtkheaderbar.c)
+ gint buttonSpacing = 6;
+ g_object_get(GetWidget(MOZ_GTK_HEADER_BAR),
+ "spacing", &buttonSpacing, nullptr);
+
+ // We apply spacing as a margin equaly to both adjacent buttons.
+ buttonSpacing /= 2;
+
+ if (!aMetrics->firstButton) {
+ aMetrics->buttonMargin.left += buttonSpacing;
+ }
+ if (!aMetrics->lastButton) {
+ aMetrics->buttonMargin.right += buttonSpacing;
+ }
+
+ aMetrics->iconXPosition += aMetrics->buttonMargin.left;
+ aMetrics->iconYPosition += aMetrics->buttonMargin.top;
+
+ aMetrics->minSizeWithBorderMargin.width +=
+ aMetrics->buttonMargin.right + aMetrics->buttonMargin.left;
+ aMetrics->minSizeWithBorderMargin.height +=
+ aMetrics->buttonMargin.top + aMetrics->buttonMargin.bottom;
+}
+
+static int
+GetGtkHeaderBarButtonLayout(WidgetNodeType* aButtonLayout, int aMaxButtonNums)
+{
+ NS_ASSERTION(aMaxButtonNums >= TOOLBAR_BUTTONS,
+ "Requested number of buttons is higher than storage capacity!");
+
+ static auto sGtkHeaderBarGetDecorationLayoutPtr =
+ (const gchar* (*)(GtkWidget*))
+ dlsym(RTLD_DEFAULT, "gtk_header_bar_get_decoration_layout");
+
+ const gchar* decorationLayout = nullptr;
+ if (sGtkHeaderBarGetDecorationLayoutPtr) {
+ GtkWidget* headerBar = GetWidget(MOZ_GTK_HEADER_BAR);
+ decorationLayout = sGtkHeaderBarGetDecorationLayoutPtr(headerBar);
+ if (!decorationLayout) {
+ GtkSettings *settings = gtk_settings_get_for_screen(
+ gdk_screen_get_default());
+ g_object_get(settings, "gtk-decoration-layout",
+ &decorationLayout,
+ nullptr);
+ }
+ }
+
+ // Use a default layout
+ if (!decorationLayout) {
+ decorationLayout = "minimize,maximize,close";
+ }
+
+ // We support only default button order now:
+ // minimize/maximize/close
+ int activeButtonNums = 0;
+ if (strstr(decorationLayout, "minimize") != nullptr) {
+ aButtonLayout[activeButtonNums++] = MOZ_GTK_HEADER_BAR_BUTTON_MINIMIZE;
+ }
+ if (strstr(decorationLayout, "maximize") != nullptr) {
+ aButtonLayout[activeButtonNums++] = MOZ_GTK_HEADER_BAR_BUTTON_MAXIMIZE;
+ }
+ if (strstr(decorationLayout, "close") != nullptr) {
+ aButtonLayout[activeButtonNums++] = MOZ_GTK_HEADER_BAR_BUTTON_CLOSE;
+ }
+
+ return activeButtonNums;
+}
+
+static void
+EnsureToolbarMetrics(void)
+{
+ if (!sToolbarMetrics.initialized) {
+ // Make sure we have clean cache after theme reset, etc.
+ memset(&sToolbarMetrics, 0, sizeof(sToolbarMetrics));
+
+ // We're running on old Gtk+ version. Leave the cache empty
+ // which means all buttons are disabled.
+ if (gtk_check_version(3, 10, 0) != nullptr) {
+ sToolbarMetrics.initialized = true;
+ return;
+ }
+
+ // Calculate titlebar button visibility and positions.
+ WidgetNodeType aButtonLayout[TOOLBAR_BUTTONS];
+ int activeButtonNums =
+ GetGtkHeaderBarButtonLayout(aButtonLayout, TOOLBAR_BUTTONS);
+
+ for (int i = 0; i < activeButtonNums; i++) {
+ int buttonIndex = (aButtonLayout[i] - MOZ_GTK_HEADER_BAR_BUTTON_CLOSE);
+ ToolbarButtonGTKMetrics* metrics = sToolbarMetrics.button + buttonIndex;
+ metrics->visible = true;
+ // Mark first button
+ if (!i) {
+ metrics->firstButton = true;
+ }
+ // Mark last button.
+ if (i == (activeButtonNums-1)) {
+ metrics->lastButton = true;
+ }
+
+ CalculateToolbarButtonMetrics(aButtonLayout[i], metrics);
+ CalculateToolbarButtonSpacing(aButtonLayout[i], metrics);
+ }
+
+ sToolbarMetrics.initialized = true;
+ }
}
const ToolbarButtonGTKMetrics*
GetToolbarButtonMetrics(WidgetNodeType aWidgetType)
{
- if (!sToolbarMetrics.initialized) {
- for (int i = 0; i < TOOLBAR_BUTTONS; i++) {
- InitToolbarButtonMetrics(sToolbarMetrics.button + i,
- WidgetNodeType(int(MOZ_GTK_HEADER_BAR_BUTTON_CLOSE) + i));
- }
- sToolbarMetrics.initialized = true;
- }
+ EnsureToolbarMetrics();
int buttonIndex = (aWidgetType - MOZ_GTK_HEADER_BAR_BUTTON_CLOSE);
NS_ASSERTION(buttonIndex >= 0 &&
buttonIndex <= TOOLBAR_BUTTONS,
"GetToolbarButtonMetrics(): Wrong titlebar button!");
return sToolbarMetrics.button + buttonIndex;
}
+bool
+IsToolbarButtonEnabled(WidgetNodeType aWidgetType)
+{
+ WidgetNodeType aButtonLayout[TOOLBAR_BUTTONS];
+ int activeButtonNums =
+ GetGtkHeaderBarButtonLayout(aButtonLayout, TOOLBAR_BUTTONS);
+
+ for (int i = 0; i < activeButtonNums; i++) {
+ if (aButtonLayout[i] == aWidgetType) {
+ return true;
+ }
+ }
+ return false;
+}
+
static gint
moz_gtk_window_paint(cairo_t *cr, GdkRectangle* rect,
GtkTextDirection direction)
{
GtkStyleContext* style = GetStyleContext(MOZ_GTK_WINDOW, direction);
gtk_style_context_save(style);
gtk_style_context_add_class(style, GTK_STYLE_CLASS_BACKGROUND);
@@ -439,18 +568,23 @@ moz_gtk_button_paint(cairo_t *cr, GdkRec
static gint
moz_gtk_header_bar_button_paint(cairo_t *cr, GdkRectangle* rect,
GtkWidgetState* state,
GtkReliefStyle relief,
WidgetNodeType aWidgetType,
GtkTextDirection direction)
{
+ // We need to inset our calculated margin because it also
+ // contains titlebar button spacing.
+ const ToolbarButtonGTKMetrics* metrics =
+ GetToolbarButtonMetrics(aWidgetType);
+ Inset(rect, metrics->buttonMargin);
+
GtkWidget *widget = GetWidget(aWidgetType);
- InsetByMargin(rect, gtk_widget_get_style_context(widget));
moz_gtk_button_paint(cr, rect, state, relief, widget, direction);
GtkWidget* iconWidget = gtk_bin_get_child(GTK_BIN(widget));
cairo_surface_t *surface = GetWidgetIconSurface(iconWidget, state->scale);
if (surface) {
GtkStyleContext* style = gtk_widget_get_style_context(iconWidget);
GtkStateFlags state_flags = GetStateFlagsFromGtkWidgetState(state);
@@ -641,17 +775,17 @@ static MozGtkSize
GetMinMarginBox(WidgetNodeType aNodeType)
{
gint width, height;
moz_gtk_get_widget_min_size(aNodeType, &width, &height);
return {width, height};
}
static void
-Inset(GdkRectangle* rect, GtkBorder& aBorder)
+Inset(GdkRectangle* rect, const GtkBorder& aBorder)
{
MOZ_ASSERT(rect);
rect->x += aBorder.left;
rect->y += aBorder.top;
rect->width -= aBorder.left + aBorder.right;
rect->height -= aBorder.top + aBorder.bottom;
}
--- a/widget/gtk/nsLookAndFeel.cpp
+++ b/widget/gtk/nsLookAndFeel.cpp
@@ -21,18 +21,16 @@
#include "ScreenHelperGTK.h"
#include "gtkdrawing.h"
#include "nsStyleConsts.h"
#include "gfxFontConstants.h"
#include "WidgetUtils.h"
#include "nsWindow.h"
-#include <dlfcn.h>
-
#include "mozilla/gfx/2D.h"
#include <cairo-gobject.h>
#include "WidgetStyleCache.h"
#include "prenv.h"
using mozilla::LookAndFeel;
@@ -1084,45 +1082,22 @@ nsLookAndFeel::EnsureInit()
g_object_unref(labelWidget);
// Require GTK 3.10 for GtkHeaderBar support and compatible window manager.
mCSDAvailable = (gtk_check_version(3, 10, 0) == nullptr &&
nsWindow::GetCSDSupportLevel() != nsWindow::CSD_SUPPORT_NONE);
// We need to initialize whole CSD config explicitly because it's queried
// as -moz-gtk* media features.
- mCSDCloseButton = true;
- mCSDMaximizeButton = false;
- mCSDMinimizeButton = false;
-
- if (mCSDAvailable) {
- static auto sGtkHeaderBarGetDecorationLayoutPtr =
- (const gchar* (*)(GtkWidget*))
- dlsym(RTLD_DEFAULT, "gtk_header_bar_get_decoration_layout");
-
- if (sGtkHeaderBarGetDecorationLayoutPtr) {
- GtkWidget* headerBar = GetWidget(MOZ_GTK_HEADER_BAR);
- const gchar* decorationLayout =
- sGtkHeaderBarGetDecorationLayoutPtr(headerBar);
- if (!decorationLayout) {
- g_object_get(settings, "gtk-decoration-layout",
- &decorationLayout,
- nullptr);
- }
-
- if (decorationLayout) {
- mCSDCloseButton =
- (strstr(decorationLayout, "close") != nullptr);
- mCSDMaximizeButton =
- (strstr(decorationLayout, "maximize") != nullptr);
- mCSDMinimizeButton =
- (strstr(decorationLayout, "minimize") != nullptr);
- }
- }
- }
+ mCSDCloseButton =
+ IsToolbarButtonEnabled(MOZ_GTK_HEADER_BAR_BUTTON_CLOSE);
+ mCSDMinimizeButton =
+ IsToolbarButtonEnabled(MOZ_GTK_HEADER_BAR_BUTTON_MINIMIZE);
+ mCSDMaximizeButton =
+ IsToolbarButtonEnabled(MOZ_GTK_HEADER_BAR_BUTTON_MAXIMIZE);
}
// virtual
char16_t
nsLookAndFeel::GetPasswordCharacterImpl()
{
EnsureInit();
return mInvisibleCharacter;