2016-05-09 02:08:26 +03:00
|
|
|
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
|
|
|
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
|
|
|
|
/* This Source Code Form is subject to the terms of the Mozilla Public
|
|
|
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
|
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
|
|
|
|
|
|
|
#include <dlfcn.h>
|
|
|
|
#include <gtk/gtk.h>
|
|
|
|
#include "WidgetStyleCache.h"
|
|
|
|
#include "gtkdrawing.h"
|
|
|
|
|
2016-09-08 01:12:55 +03:00
|
|
|
#define STATE_FLAG_DIR_LTR (1U << 7)
|
|
|
|
#define STATE_FLAG_DIR_RTL (1U << 8)
|
|
|
|
#if GTK_CHECK_VERSION(3,8,0)
|
|
|
|
static_assert(GTK_STATE_FLAG_DIR_LTR == STATE_FLAG_DIR_LTR &&
|
|
|
|
GTK_STATE_FLAG_DIR_RTL == STATE_FLAG_DIR_RTL,
|
|
|
|
"incorrect direction state flags");
|
|
|
|
#endif
|
|
|
|
|
2016-05-09 02:08:26 +03:00
|
|
|
static GtkWidget* sWidgetStorage[MOZ_GTK_WIDGET_NODE_COUNT];
|
|
|
|
static GtkStyleContext* sStyleStorage[MOZ_GTK_WIDGET_NODE_COUNT];
|
|
|
|
|
|
|
|
static GtkStyleContext*
|
2016-11-15 07:11:14 +03:00
|
|
|
GetWidgetRootStyle(WidgetNodeType aNodeType);
|
|
|
|
static GtkStyleContext*
|
2016-06-07 03:49:00 +03:00
|
|
|
GetCssNodeStyleInternal(WidgetNodeType aNodeType);
|
2016-05-09 02:08:26 +03:00
|
|
|
|
|
|
|
static GtkWidget*
|
|
|
|
CreateWindowWidget()
|
|
|
|
{
|
|
|
|
GtkWidget *widget = gtk_window_new(GTK_WINDOW_POPUP);
|
|
|
|
gtk_widget_set_name(widget, "MozillaGtkWidget");
|
|
|
|
return widget;
|
|
|
|
}
|
|
|
|
|
|
|
|
static GtkWidget*
|
|
|
|
CreateWindowContainerWidget()
|
|
|
|
{
|
|
|
|
GtkWidget *widget = gtk_fixed_new();
|
|
|
|
gtk_container_add(GTK_CONTAINER(GetWidget(MOZ_GTK_WINDOW)), widget);
|
|
|
|
return widget;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
AddToWindowContainer(GtkWidget* widget)
|
|
|
|
{
|
|
|
|
gtk_container_add(GTK_CONTAINER(GetWidget(MOZ_GTK_WINDOW_CONTAINER)), widget);
|
|
|
|
}
|
|
|
|
|
|
|
|
static GtkWidget*
|
|
|
|
CreateScrollbarWidget(WidgetNodeType aWidgetType, GtkOrientation aOrientation)
|
|
|
|
{
|
|
|
|
GtkWidget* widget = gtk_scrollbar_new(aOrientation, nullptr);
|
|
|
|
AddToWindowContainer(widget);
|
|
|
|
return widget;
|
|
|
|
}
|
|
|
|
|
2016-05-13 02:59:17 +03:00
|
|
|
static GtkWidget*
|
|
|
|
CreateCheckboxWidget()
|
|
|
|
{
|
|
|
|
GtkWidget* widget = gtk_check_button_new_with_label("M");
|
|
|
|
AddToWindowContainer(widget);
|
|
|
|
return widget;
|
|
|
|
}
|
|
|
|
|
|
|
|
static GtkWidget*
|
|
|
|
CreateRadiobuttonWidget()
|
|
|
|
{
|
2016-07-20 02:57:00 +03:00
|
|
|
GtkWidget* widget = gtk_radio_button_new_with_label(nullptr, "M");
|
2016-05-13 02:59:17 +03:00
|
|
|
AddToWindowContainer(widget);
|
|
|
|
return widget;
|
|
|
|
}
|
|
|
|
|
2016-05-17 09:24:55 +03:00
|
|
|
static GtkWidget*
|
|
|
|
CreateMenuBarWidget()
|
|
|
|
{
|
|
|
|
GtkWidget* widget = gtk_menu_bar_new();
|
|
|
|
AddToWindowContainer(widget);
|
|
|
|
return widget;
|
|
|
|
}
|
|
|
|
|
|
|
|
static GtkWidget*
|
|
|
|
CreateMenuPopupWidget()
|
|
|
|
{
|
|
|
|
GtkWidget* widget = gtk_menu_new();
|
|
|
|
gtk_menu_attach_to_widget(GTK_MENU(widget), GetWidget(MOZ_GTK_WINDOW),
|
|
|
|
nullptr);
|
|
|
|
return widget;
|
|
|
|
}
|
|
|
|
|
2016-05-24 14:43:00 +03:00
|
|
|
static GtkWidget*
|
|
|
|
CreateProgressWidget()
|
|
|
|
{
|
|
|
|
GtkWidget* widget = gtk_progress_bar_new();
|
|
|
|
AddToWindowContainer(widget);
|
|
|
|
return widget;
|
|
|
|
}
|
|
|
|
|
2016-06-07 07:22:00 +03:00
|
|
|
static GtkWidget*
|
|
|
|
CreateTooltipWidget()
|
|
|
|
{
|
|
|
|
MOZ_ASSERT(gtk_check_version(3, 20, 0) != nullptr,
|
|
|
|
"CreateTooltipWidget should be used for Gtk < 3.20 only.");
|
|
|
|
GtkWidget* widget = CreateWindowWidget();
|
|
|
|
GtkStyleContext* style = gtk_widget_get_style_context(widget);
|
|
|
|
gtk_style_context_add_class(style, GTK_STYLE_CLASS_TOOLTIP);
|
|
|
|
return widget;
|
|
|
|
}
|
|
|
|
|
2016-07-18 05:27:00 +03:00
|
|
|
static GtkWidget*
|
|
|
|
CreateExpanderWidget()
|
|
|
|
{
|
|
|
|
GtkWidget* widget = gtk_expander_new("M");
|
|
|
|
AddToWindowContainer(widget);
|
|
|
|
return widget;
|
|
|
|
}
|
|
|
|
|
2016-07-18 06:29:00 +03:00
|
|
|
static GtkWidget*
|
|
|
|
CreateFrameWidget()
|
|
|
|
{
|
|
|
|
GtkWidget* widget = gtk_frame_new(nullptr);
|
|
|
|
AddToWindowContainer(widget);
|
|
|
|
return widget;
|
|
|
|
}
|
|
|
|
|
|
|
|
static GtkWidget*
|
|
|
|
CreateGripperWidget()
|
|
|
|
{
|
|
|
|
GtkWidget* widget = gtk_handle_box_new();
|
|
|
|
AddToWindowContainer(widget);
|
|
|
|
return widget;
|
|
|
|
}
|
|
|
|
|
|
|
|
static GtkWidget*
|
|
|
|
CreateToolbarWidget()
|
|
|
|
{
|
|
|
|
GtkWidget* widget = gtk_toolbar_new();
|
|
|
|
gtk_container_add(GTK_CONTAINER(GetWidget(MOZ_GTK_GRIPPER)), widget);
|
|
|
|
return widget;
|
|
|
|
}
|
|
|
|
|
|
|
|
static GtkWidget*
|
|
|
|
CreateToolbarSeparatorWidget()
|
|
|
|
{
|
|
|
|
GtkWidget* widget = GTK_WIDGET(gtk_separator_tool_item_new());
|
|
|
|
AddToWindowContainer(widget);
|
|
|
|
return widget;
|
|
|
|
}
|
|
|
|
|
2016-07-19 07:03:00 +03:00
|
|
|
static GtkWidget*
|
|
|
|
CreateInfoBarWidget()
|
|
|
|
{
|
|
|
|
GtkWidget* widget = gtk_info_bar_new();
|
|
|
|
AddToWindowContainer(widget);
|
|
|
|
return widget;
|
|
|
|
}
|
|
|
|
|
2016-07-20 02:57:00 +03:00
|
|
|
static GtkWidget*
|
|
|
|
CreateButtonWidget()
|
|
|
|
{
|
|
|
|
GtkWidget* widget = gtk_button_new_with_label("M");
|
|
|
|
AddToWindowContainer(widget);
|
|
|
|
return widget;
|
|
|
|
}
|
|
|
|
|
|
|
|
static GtkWidget*
|
|
|
|
CreateToggleButtonWidget()
|
|
|
|
{
|
|
|
|
GtkWidget* widget = gtk_toggle_button_new();
|
|
|
|
AddToWindowContainer(widget);
|
|
|
|
return widget;
|
|
|
|
}
|
|
|
|
|
|
|
|
static GtkWidget*
|
|
|
|
CreateButtonArrowWidget()
|
|
|
|
{
|
|
|
|
GtkWidget* widget = gtk_arrow_new(GTK_ARROW_DOWN, GTK_SHADOW_OUT);
|
|
|
|
gtk_container_add(GTK_CONTAINER(GetWidget(MOZ_GTK_TOGGLE_BUTTON)), widget);
|
|
|
|
gtk_widget_show(widget);
|
|
|
|
return widget;
|
|
|
|
}
|
|
|
|
|
|
|
|
static GtkWidget*
|
|
|
|
CreateSpinWidget()
|
|
|
|
{
|
|
|
|
GtkWidget* widget = gtk_spin_button_new(nullptr, 1, 0);
|
|
|
|
AddToWindowContainer(widget);
|
|
|
|
return widget;
|
|
|
|
}
|
|
|
|
|
|
|
|
static GtkWidget*
|
|
|
|
CreateEntryWidget()
|
|
|
|
{
|
|
|
|
GtkWidget* widget = gtk_entry_new();
|
|
|
|
AddToWindowContainer(widget);
|
|
|
|
return widget;
|
|
|
|
}
|
|
|
|
|
2016-10-19 05:13:25 +03:00
|
|
|
static GtkWidget*
|
|
|
|
CreateComboBoxWidget()
|
|
|
|
{
|
|
|
|
GtkWidget* widget = gtk_combo_box_new();
|
|
|
|
AddToWindowContainer(widget);
|
|
|
|
return widget;
|
|
|
|
}
|
|
|
|
|
|
|
|
typedef struct
|
|
|
|
{
|
|
|
|
GType type;
|
|
|
|
GtkWidget** widget;
|
|
|
|
} GtkInnerWidgetInfo;
|
|
|
|
|
|
|
|
static void
|
|
|
|
GetInnerWidget(GtkWidget* widget, gpointer client_data)
|
|
|
|
{
|
|
|
|
auto info = static_cast<GtkInnerWidgetInfo*>(client_data);
|
|
|
|
|
|
|
|
if (G_TYPE_CHECK_INSTANCE_TYPE(widget, info->type)) {
|
|
|
|
*info->widget = widget;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static GtkWidget*
|
|
|
|
CreateComboBoxButtonWidget()
|
|
|
|
{
|
|
|
|
GtkWidget* comboBox = GetWidget(MOZ_GTK_COMBOBOX);
|
|
|
|
GtkWidget* comboBoxButton = nullptr;
|
|
|
|
|
|
|
|
/* Get its inner Button */
|
|
|
|
GtkInnerWidgetInfo info = { GTK_TYPE_TOGGLE_BUTTON,
|
|
|
|
&comboBoxButton };
|
|
|
|
gtk_container_forall(GTK_CONTAINER(comboBox),
|
|
|
|
GetInnerWidget, &info);
|
|
|
|
|
|
|
|
if (!comboBoxButton) {
|
|
|
|
/* Shouldn't be reached with current internal gtk implementation; we
|
|
|
|
* use a generic toggle button as last resort fallback to avoid
|
|
|
|
* crashing. */
|
|
|
|
comboBoxButton = GetWidget(MOZ_GTK_TOGGLE_BUTTON);
|
|
|
|
} else {
|
|
|
|
/* We need to have pointers to the inner widgets (button, separator, arrow)
|
|
|
|
* of the ComboBox to get the correct rendering from theme engines which
|
|
|
|
* special cases their look. Since the inner layout can change, we ask GTK
|
|
|
|
* to NULL our pointers when they are about to become invalid because the
|
|
|
|
* corresponding widgets don't exist anymore. It's the role of
|
|
|
|
* g_object_add_weak_pointer().
|
|
|
|
* Note that if we don't find the inner widgets (which shouldn't happen), we
|
|
|
|
* fallback to use generic "non-inner" widgets, and they don't need that kind
|
|
|
|
* of weak pointer since they are explicit children of gProtoLayout and as
|
|
|
|
* such GTK holds a strong reference to them. */
|
|
|
|
g_object_add_weak_pointer(G_OBJECT(comboBoxButton),
|
|
|
|
reinterpret_cast<gpointer *>(sWidgetStorage) +
|
|
|
|
MOZ_GTK_COMBOBOX_BUTTON);
|
|
|
|
}
|
|
|
|
|
|
|
|
return comboBoxButton;
|
|
|
|
}
|
|
|
|
|
|
|
|
static GtkWidget*
|
|
|
|
CreateComboBoxArrowWidget()
|
|
|
|
{
|
|
|
|
GtkWidget* comboBoxButton = GetWidget(MOZ_GTK_COMBOBOX_BUTTON);
|
|
|
|
GtkWidget* comboBoxArrow = nullptr;
|
|
|
|
|
|
|
|
/* Get the widgets inside the Button */
|
|
|
|
GtkWidget* buttonChild = gtk_bin_get_child(GTK_BIN(comboBoxButton));
|
|
|
|
if (GTK_IS_BOX(buttonChild)) {
|
|
|
|
/* appears-as-list = FALSE, cell-view = TRUE; the button
|
|
|
|
* contains an hbox. This hbox is there because the ComboBox
|
|
|
|
* needs to place a cell renderer, a separator, and an arrow in
|
|
|
|
* the button when appears-as-list is FALSE. */
|
|
|
|
GtkInnerWidgetInfo info = { GTK_TYPE_ARROW,
|
|
|
|
&comboBoxArrow };
|
|
|
|
gtk_container_forall(GTK_CONTAINER(buttonChild),
|
|
|
|
GetInnerWidget, &info);
|
|
|
|
} else if (GTK_IS_ARROW(buttonChild)) {
|
|
|
|
/* appears-as-list = TRUE, or cell-view = FALSE;
|
|
|
|
* the button only contains an arrow */
|
|
|
|
comboBoxArrow = buttonChild;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!comboBoxArrow) {
|
|
|
|
/* Shouldn't be reached with current internal gtk implementation;
|
|
|
|
* we gButtonArrowWidget as last resort fallback to avoid
|
|
|
|
* crashing. */
|
|
|
|
comboBoxArrow = GetWidget(MOZ_GTK_BUTTON_ARROW);
|
|
|
|
} else {
|
|
|
|
g_object_add_weak_pointer(G_OBJECT(comboBoxArrow),
|
|
|
|
reinterpret_cast<gpointer *>(sWidgetStorage) +
|
|
|
|
MOZ_GTK_COMBOBOX_ARROW);
|
|
|
|
}
|
|
|
|
|
|
|
|
return comboBoxArrow;
|
|
|
|
}
|
|
|
|
|
|
|
|
static GtkWidget*
|
|
|
|
CreateComboBoxSeparatorWidget()
|
|
|
|
{
|
|
|
|
// Ensure to search for separator only once as it can fail
|
|
|
|
// TODO - it won't initialize after ResetWidgetCache() call
|
|
|
|
static bool isMissingSeparator = false;
|
|
|
|
if (isMissingSeparator)
|
|
|
|
return nullptr;
|
|
|
|
|
|
|
|
/* Get the widgets inside the Button */
|
|
|
|
GtkWidget* comboBoxSeparator = nullptr;
|
|
|
|
GtkWidget* buttonChild =
|
|
|
|
gtk_bin_get_child(GTK_BIN(GetWidget(MOZ_GTK_COMBOBOX_BUTTON)));
|
|
|
|
if (GTK_IS_BOX(buttonChild)) {
|
|
|
|
/* appears-as-list = FALSE, cell-view = TRUE; the button
|
|
|
|
* contains an hbox. This hbox is there because the ComboBox
|
|
|
|
* needs to place a cell renderer, a separator, and an arrow in
|
|
|
|
* the button when appears-as-list is FALSE. */
|
|
|
|
GtkInnerWidgetInfo info = { GTK_TYPE_SEPARATOR,
|
|
|
|
&comboBoxSeparator };
|
|
|
|
gtk_container_forall(GTK_CONTAINER(buttonChild),
|
|
|
|
GetInnerWidget, &info);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (comboBoxSeparator) {
|
|
|
|
g_object_add_weak_pointer(G_OBJECT(comboBoxSeparator),
|
|
|
|
reinterpret_cast<gpointer *>(sWidgetStorage) +
|
|
|
|
MOZ_GTK_COMBOBOX_SEPARATOR);
|
|
|
|
} else {
|
|
|
|
/* comboBoxSeparator may be NULL
|
|
|
|
* when "appears-as-list" = TRUE or "cell-view" = FALSE;
|
|
|
|
* if there is no separator, then we just won't paint it. */
|
|
|
|
isMissingSeparator = true;
|
|
|
|
}
|
|
|
|
|
|
|
|
return comboBoxSeparator;
|
|
|
|
}
|
|
|
|
|
|
|
|
static GtkWidget*
|
|
|
|
CreateComboBoxEntryWidget()
|
|
|
|
{
|
|
|
|
GtkWidget* widget = gtk_combo_box_new_with_entry();
|
|
|
|
AddToWindowContainer(widget);
|
|
|
|
return widget;
|
|
|
|
}
|
|
|
|
|
|
|
|
static GtkWidget*
|
|
|
|
CreateComboBoxEntryTextareaWidget()
|
|
|
|
{
|
|
|
|
GtkWidget* comboBoxTextarea = nullptr;
|
|
|
|
|
|
|
|
/* Get its inner Entry and Button */
|
|
|
|
GtkInnerWidgetInfo info = { GTK_TYPE_ENTRY,
|
|
|
|
&comboBoxTextarea };
|
|
|
|
gtk_container_forall(GTK_CONTAINER(GetWidget(MOZ_GTK_COMBOBOX_ENTRY)),
|
|
|
|
GetInnerWidget, &info);
|
|
|
|
|
|
|
|
if (!comboBoxTextarea) {
|
|
|
|
comboBoxTextarea = GetWidget(MOZ_GTK_ENTRY);
|
|
|
|
} else {
|
|
|
|
g_object_add_weak_pointer(G_OBJECT(comboBoxTextarea),
|
|
|
|
reinterpret_cast<gpointer *>(sWidgetStorage) +
|
|
|
|
MOZ_GTK_COMBOBOX_ENTRY);
|
|
|
|
}
|
|
|
|
|
|
|
|
return comboBoxTextarea;
|
|
|
|
}
|
|
|
|
|
|
|
|
static GtkWidget*
|
|
|
|
CreateComboBoxEntryButtonWidget()
|
|
|
|
{
|
|
|
|
GtkWidget* comboBoxButton = nullptr;
|
|
|
|
|
|
|
|
/* Get its inner Entry and Button */
|
|
|
|
GtkInnerWidgetInfo info = { GTK_TYPE_TOGGLE_BUTTON,
|
|
|
|
&comboBoxButton };
|
|
|
|
gtk_container_forall(GTK_CONTAINER(GetWidget(MOZ_GTK_COMBOBOX_ENTRY)),
|
|
|
|
GetInnerWidget, &info);
|
|
|
|
|
|
|
|
if (!comboBoxButton) {
|
|
|
|
comboBoxButton = GetWidget(MOZ_GTK_TOGGLE_BUTTON);
|
|
|
|
} else {
|
|
|
|
g_object_add_weak_pointer(G_OBJECT(comboBoxButton),
|
|
|
|
reinterpret_cast<gpointer *>(sWidgetStorage) +
|
|
|
|
MOZ_GTK_COMBOBOX_ENTRY_BUTTON);
|
|
|
|
}
|
|
|
|
|
|
|
|
return comboBoxButton;
|
|
|
|
}
|
|
|
|
|
|
|
|
static GtkWidget*
|
|
|
|
CreateComboBoxEntryArrowWidget()
|
|
|
|
{
|
|
|
|
GtkWidget* comboBoxArrow = nullptr;
|
|
|
|
|
|
|
|
/* Get the Arrow inside the Button */
|
|
|
|
GtkWidget* buttonChild =
|
|
|
|
gtk_bin_get_child(GTK_BIN(GetWidget(MOZ_GTK_COMBOBOX_ENTRY_BUTTON)));
|
|
|
|
|
|
|
|
if (GTK_IS_BOX(buttonChild)) {
|
|
|
|
/* appears-as-list = FALSE, cell-view = TRUE; the button
|
|
|
|
* contains an hbox. This hbox is there because the ComboBox
|
|
|
|
* needs to place a cell renderer, a separator, and an arrow in
|
|
|
|
* the button when appears-as-list is FALSE. */
|
|
|
|
GtkInnerWidgetInfo info = { GTK_TYPE_ARROW,
|
|
|
|
&comboBoxArrow };
|
|
|
|
gtk_container_forall(GTK_CONTAINER(buttonChild),
|
|
|
|
GetInnerWidget, &info);
|
|
|
|
} else if (GTK_IS_ARROW(buttonChild)) {
|
|
|
|
/* appears-as-list = TRUE, or cell-view = FALSE;
|
|
|
|
* the button only contains an arrow */
|
|
|
|
comboBoxArrow = buttonChild;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!comboBoxArrow) {
|
|
|
|
/* Shouldn't be reached with current internal gtk implementation;
|
|
|
|
* we gButtonArrowWidget as last resort fallback to avoid
|
|
|
|
* crashing. */
|
|
|
|
comboBoxArrow = GetWidget(MOZ_GTK_BUTTON_ARROW);
|
|
|
|
} else {
|
|
|
|
g_object_add_weak_pointer(G_OBJECT(comboBoxArrow),
|
|
|
|
reinterpret_cast<gpointer *>(sWidgetStorage) +
|
|
|
|
MOZ_GTK_COMBOBOX_ENTRY_ARROW);
|
|
|
|
}
|
|
|
|
|
|
|
|
return comboBoxArrow;
|
|
|
|
}
|
|
|
|
|
2016-07-25 07:46:00 +03:00
|
|
|
static GtkWidget*
|
|
|
|
CreateScrolledWindowWidget()
|
|
|
|
{
|
|
|
|
GtkWidget* widget = gtk_scrolled_window_new(nullptr, nullptr);
|
|
|
|
AddToWindowContainer(widget);
|
|
|
|
return widget;
|
|
|
|
}
|
|
|
|
|
2016-07-25 06:40:00 +03:00
|
|
|
static GtkWidget*
|
|
|
|
CreateMenuSeparatorWidget()
|
|
|
|
{
|
|
|
|
GtkWidget* widget = gtk_separator_menu_item_new();
|
|
|
|
gtk_menu_shell_append(GTK_MENU_SHELL(GetWidget(MOZ_GTK_MENUPOPUP)),
|
|
|
|
widget);
|
|
|
|
return widget;
|
|
|
|
}
|
|
|
|
|
2016-07-29 06:15:00 +03:00
|
|
|
static GtkWidget*
|
|
|
|
CreateTreeViewWidget()
|
|
|
|
{
|
|
|
|
GtkWidget* widget = gtk_tree_view_new();
|
|
|
|
AddToWindowContainer(widget);
|
|
|
|
return widget;
|
|
|
|
}
|
|
|
|
|
|
|
|
static GtkWidget*
|
|
|
|
CreateTreeHeaderCellWidget()
|
|
|
|
{
|
|
|
|
/*
|
|
|
|
* Some GTK engines paint the first and last cell
|
|
|
|
* of a TreeView header with a highlight.
|
|
|
|
* Since we do not know where our widget will be relative
|
|
|
|
* to the other buttons in the TreeView header, we must
|
|
|
|
* paint it as a button that is between two others,
|
|
|
|
* thus ensuring it is neither the first or last button
|
|
|
|
* in the header.
|
|
|
|
* GTK doesn't give us a way to do this explicitly,
|
|
|
|
* so we must paint with a button that is between two
|
|
|
|
* others.
|
|
|
|
*/
|
|
|
|
GtkTreeViewColumn* firstTreeViewColumn;
|
|
|
|
GtkTreeViewColumn* middleTreeViewColumn;
|
|
|
|
GtkTreeViewColumn* lastTreeViewColumn;
|
|
|
|
|
|
|
|
GtkWidget *treeView = GetWidget(MOZ_GTK_TREEVIEW);
|
|
|
|
|
|
|
|
/* Create and append our three columns */
|
|
|
|
firstTreeViewColumn = gtk_tree_view_column_new();
|
|
|
|
gtk_tree_view_column_set_title(firstTreeViewColumn, "M");
|
|
|
|
gtk_tree_view_append_column(GTK_TREE_VIEW(treeView),
|
|
|
|
firstTreeViewColumn);
|
|
|
|
|
|
|
|
middleTreeViewColumn = gtk_tree_view_column_new();
|
|
|
|
gtk_tree_view_column_set_title(middleTreeViewColumn, "M");
|
|
|
|
gtk_tree_view_append_column(GTK_TREE_VIEW(treeView),
|
|
|
|
middleTreeViewColumn);
|
|
|
|
|
|
|
|
lastTreeViewColumn = gtk_tree_view_column_new();
|
|
|
|
gtk_tree_view_column_set_title(lastTreeViewColumn, "M");
|
|
|
|
gtk_tree_view_append_column(GTK_TREE_VIEW(treeView),
|
|
|
|
lastTreeViewColumn);
|
|
|
|
|
|
|
|
/* Use the middle column's header for our button */
|
|
|
|
return gtk_tree_view_column_get_button(middleTreeViewColumn);
|
|
|
|
}
|
|
|
|
|
|
|
|
static GtkWidget*
|
|
|
|
CreateTreeHeaderSortArrowWidget()
|
|
|
|
{
|
|
|
|
/* TODO, but it can't be NULL */
|
|
|
|
GtkWidget* widget = gtk_button_new();
|
|
|
|
AddToWindowContainer(widget);
|
|
|
|
return widget;
|
|
|
|
}
|
2016-07-25 06:40:00 +03:00
|
|
|
|
2016-07-29 06:30:00 +03:00
|
|
|
static GtkWidget*
|
|
|
|
CreateHPanedWidget()
|
|
|
|
{
|
|
|
|
GtkWidget* widget = gtk_paned_new(GTK_ORIENTATION_HORIZONTAL);
|
|
|
|
AddToWindowContainer(widget);
|
|
|
|
return widget;
|
|
|
|
}
|
|
|
|
|
|
|
|
static GtkWidget*
|
|
|
|
CreateVPanedWidget()
|
|
|
|
{
|
|
|
|
GtkWidget* widget = gtk_paned_new(GTK_ORIENTATION_VERTICAL);
|
|
|
|
AddToWindowContainer(widget);
|
|
|
|
return widget;
|
|
|
|
}
|
|
|
|
|
2016-08-19 12:20:00 +03:00
|
|
|
static GtkWidget*
|
|
|
|
CreateScaleWidget(GtkOrientation aOrientation)
|
|
|
|
{
|
|
|
|
GtkWidget* widget = gtk_scale_new(aOrientation, nullptr);
|
|
|
|
AddToWindowContainer(widget);
|
|
|
|
return widget;
|
|
|
|
}
|
|
|
|
|
2016-08-22 06:13:00 +03:00
|
|
|
static GtkWidget*
|
|
|
|
CreateNotebookWidget()
|
|
|
|
{
|
|
|
|
GtkWidget* widget = gtk_notebook_new();
|
|
|
|
AddToWindowContainer(widget);
|
|
|
|
return widget;
|
|
|
|
}
|
|
|
|
|
2017-09-19 19:20:48 +03:00
|
|
|
static GtkWidget*
|
|
|
|
CreateHeaderBar(WidgetNodeType aWidgetType)
|
|
|
|
{
|
|
|
|
MOZ_ASSERT(gtk_check_version(3, 10, 0) == nullptr,
|
|
|
|
"GtkHeaderBar is only available on GTK 3.10+.");
|
|
|
|
|
|
|
|
static auto sGtkHeaderBarNewPtr = (GtkWidget* (*)())
|
|
|
|
dlsym(RTLD_DEFAULT, "gtk_header_bar_new");
|
|
|
|
|
|
|
|
GtkWidget* headerbar = sGtkHeaderBarNewPtr();
|
|
|
|
if (aWidgetType == MOZ_GTK_HEADER_BAR_MAXIMIZED) {
|
|
|
|
GtkWidget *window = gtk_window_new(GTK_WINDOW_POPUP);
|
|
|
|
gtk_widget_set_name(window, "MozillaMaximizedGtkWidget");
|
|
|
|
GtkStyleContext* style = gtk_widget_get_style_context(window);
|
|
|
|
gtk_style_context_add_class(style, "maximized");
|
|
|
|
GtkWidget *fixed = gtk_fixed_new();
|
|
|
|
gtk_container_add(GTK_CONTAINER(window), fixed);
|
|
|
|
gtk_container_add(GTK_CONTAINER(fixed), headerbar);
|
|
|
|
// Save the window container so we don't leak it.
|
|
|
|
sWidgetStorage[MOZ_GTK_WINDOW_MAXIMIZED] = window;
|
|
|
|
} else {
|
|
|
|
AddToWindowContainer(headerbar);
|
|
|
|
}
|
|
|
|
|
|
|
|
// Emulate what create_titlebar() at gtkwindow.c does.
|
|
|
|
GtkStyleContext* style = gtk_widget_get_style_context(headerbar);
|
|
|
|
gtk_style_context_add_class(style, "titlebar");
|
2018-01-22 14:09:09 +03:00
|
|
|
|
|
|
|
// TODO: Define default-decoration titlebar style as workaround
|
|
|
|
// to ensure the titlebar buttons does not overflow outside.
|
|
|
|
// Recently the titlebar size is calculated as
|
|
|
|
// tab size + titlebar border/padding (default-decoration has 6px padding
|
|
|
|
// at default Adwaita theme).
|
|
|
|
// We need to fix titlebar size calculation to also include
|
|
|
|
// titlebar button sizes. (Bug 1419442)
|
2017-09-19 19:20:48 +03:00
|
|
|
gtk_style_context_add_class(style, "default-decoration");
|
|
|
|
|
|
|
|
return headerbar;
|
|
|
|
}
|
|
|
|
|
|
|
|
// TODO - Also return style for buttons located at Maximized toolbar.
|
|
|
|
static GtkWidget*
|
|
|
|
CreateHeaderBarButton(WidgetNodeType aWidgetType)
|
|
|
|
{
|
|
|
|
MOZ_ASSERT(gtk_check_version(3, 10, 0) == nullptr,
|
|
|
|
"GtkHeaderBar is only available on GTK 3.10+.");
|
|
|
|
|
|
|
|
GtkWidget* widget = gtk_button_new();
|
|
|
|
gtk_container_add(GTK_CONTAINER(GetWidget(MOZ_GTK_HEADER_BAR)), widget);
|
|
|
|
|
|
|
|
GtkStyleContext* style = gtk_widget_get_style_context(widget);
|
|
|
|
gtk_style_context_add_class(style, "titlebutton");
|
|
|
|
|
|
|
|
switch (aWidgetType) {
|
|
|
|
case MOZ_GTK_HEADER_BAR_BUTTON_CLOSE:
|
|
|
|
gtk_style_context_add_class(style, "close");
|
|
|
|
break;
|
|
|
|
case MOZ_GTK_HEADER_BAR_BUTTON_MINIMIZE:
|
|
|
|
gtk_style_context_add_class(style, "minimize");
|
|
|
|
break;
|
|
|
|
case MOZ_GTK_HEADER_BAR_BUTTON_MAXIMIZE:
|
|
|
|
gtk_style_context_add_class(style, "maximize");
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
return widget;
|
|
|
|
}
|
|
|
|
|
2016-05-09 02:08:26 +03:00
|
|
|
static GtkWidget*
|
|
|
|
CreateWidget(WidgetNodeType aWidgetType)
|
|
|
|
{
|
|
|
|
switch (aWidgetType) {
|
|
|
|
case MOZ_GTK_WINDOW:
|
|
|
|
return CreateWindowWidget();
|
|
|
|
case MOZ_GTK_WINDOW_CONTAINER:
|
|
|
|
return CreateWindowContainerWidget();
|
2016-05-24 14:43:00 +03:00
|
|
|
case MOZ_GTK_CHECKBUTTON_CONTAINER:
|
|
|
|
return CreateCheckboxWidget();
|
|
|
|
case MOZ_GTK_PROGRESSBAR:
|
|
|
|
return CreateProgressWidget();
|
|
|
|
case MOZ_GTK_RADIOBUTTON_CONTAINER:
|
|
|
|
return CreateRadiobuttonWidget();
|
2016-05-09 02:08:26 +03:00
|
|
|
case MOZ_GTK_SCROLLBAR_HORIZONTAL:
|
|
|
|
return CreateScrollbarWidget(aWidgetType,
|
|
|
|
GTK_ORIENTATION_HORIZONTAL);
|
|
|
|
case MOZ_GTK_SCROLLBAR_VERTICAL:
|
|
|
|
return CreateScrollbarWidget(aWidgetType,
|
|
|
|
GTK_ORIENTATION_VERTICAL);
|
2016-05-17 09:24:55 +03:00
|
|
|
case MOZ_GTK_MENUBAR:
|
|
|
|
return CreateMenuBarWidget();
|
|
|
|
case MOZ_GTK_MENUPOPUP:
|
|
|
|
return CreateMenuPopupWidget();
|
2016-07-25 06:40:00 +03:00
|
|
|
case MOZ_GTK_MENUSEPARATOR:
|
|
|
|
return CreateMenuSeparatorWidget();
|
2016-07-18 05:27:00 +03:00
|
|
|
case MOZ_GTK_EXPANDER:
|
|
|
|
return CreateExpanderWidget();
|
2016-07-18 06:29:00 +03:00
|
|
|
case MOZ_GTK_FRAME:
|
|
|
|
return CreateFrameWidget();
|
|
|
|
case MOZ_GTK_GRIPPER:
|
|
|
|
return CreateGripperWidget();
|
|
|
|
case MOZ_GTK_TOOLBAR:
|
|
|
|
return CreateToolbarWidget();
|
|
|
|
case MOZ_GTK_TOOLBAR_SEPARATOR:
|
|
|
|
return CreateToolbarSeparatorWidget();
|
2016-07-19 07:03:00 +03:00
|
|
|
case MOZ_GTK_INFO_BAR:
|
|
|
|
return CreateInfoBarWidget();
|
2016-07-20 02:57:00 +03:00
|
|
|
case MOZ_GTK_SPINBUTTON:
|
|
|
|
return CreateSpinWidget();
|
|
|
|
case MOZ_GTK_BUTTON:
|
|
|
|
return CreateButtonWidget();
|
|
|
|
case MOZ_GTK_TOGGLE_BUTTON:
|
|
|
|
return CreateToggleButtonWidget();
|
|
|
|
case MOZ_GTK_BUTTON_ARROW:
|
|
|
|
return CreateButtonArrowWidget();
|
|
|
|
case MOZ_GTK_ENTRY:
|
|
|
|
return CreateEntryWidget();
|
2017-12-19 13:38:59 +03:00
|
|
|
case MOZ_GTK_SCROLLED_WINDOW:
|
2016-07-25 07:46:00 +03:00
|
|
|
return CreateScrolledWindowWidget();
|
2016-07-29 06:15:00 +03:00
|
|
|
case MOZ_GTK_TREEVIEW:
|
|
|
|
return CreateTreeViewWidget();
|
|
|
|
case MOZ_GTK_TREE_HEADER_CELL:
|
|
|
|
return CreateTreeHeaderCellWidget();
|
|
|
|
case MOZ_GTK_TREE_HEADER_SORTARROW:
|
|
|
|
return CreateTreeHeaderSortArrowWidget();
|
2016-07-29 06:30:00 +03:00
|
|
|
case MOZ_GTK_SPLITTER_HORIZONTAL:
|
|
|
|
return CreateHPanedWidget();
|
|
|
|
case MOZ_GTK_SPLITTER_VERTICAL:
|
|
|
|
return CreateVPanedWidget();
|
2016-08-19 12:20:00 +03:00
|
|
|
case MOZ_GTK_SCALE_HORIZONTAL:
|
|
|
|
return CreateScaleWidget(GTK_ORIENTATION_HORIZONTAL);
|
|
|
|
case MOZ_GTK_SCALE_VERTICAL:
|
|
|
|
return CreateScaleWidget(GTK_ORIENTATION_VERTICAL);
|
2016-08-22 06:13:00 +03:00
|
|
|
case MOZ_GTK_NOTEBOOK:
|
|
|
|
return CreateNotebookWidget();
|
2016-10-19 05:13:25 +03:00
|
|
|
case MOZ_GTK_COMBOBOX:
|
|
|
|
return CreateComboBoxWidget();
|
|
|
|
case MOZ_GTK_COMBOBOX_BUTTON:
|
|
|
|
return CreateComboBoxButtonWidget();
|
|
|
|
case MOZ_GTK_COMBOBOX_ARROW:
|
|
|
|
return CreateComboBoxArrowWidget();
|
|
|
|
case MOZ_GTK_COMBOBOX_SEPARATOR:
|
|
|
|
return CreateComboBoxSeparatorWidget();
|
|
|
|
case MOZ_GTK_COMBOBOX_ENTRY:
|
|
|
|
return CreateComboBoxEntryWidget();
|
|
|
|
case MOZ_GTK_COMBOBOX_ENTRY_TEXTAREA:
|
|
|
|
return CreateComboBoxEntryTextareaWidget();
|
|
|
|
case MOZ_GTK_COMBOBOX_ENTRY_BUTTON:
|
|
|
|
return CreateComboBoxEntryButtonWidget();
|
|
|
|
case MOZ_GTK_COMBOBOX_ENTRY_ARROW:
|
|
|
|
return CreateComboBoxEntryArrowWidget();
|
2017-09-19 21:34:31 +03:00
|
|
|
case MOZ_GTK_HEADER_BAR:
|
|
|
|
case MOZ_GTK_HEADER_BAR_MAXIMIZED:
|
|
|
|
return CreateHeaderBar(aWidgetType);
|
|
|
|
case MOZ_GTK_HEADER_BAR_BUTTON_CLOSE:
|
|
|
|
case MOZ_GTK_HEADER_BAR_BUTTON_MINIMIZE:
|
|
|
|
case MOZ_GTK_HEADER_BAR_BUTTON_MAXIMIZE:
|
|
|
|
return CreateHeaderBarButton(aWidgetType);
|
2016-05-09 02:08:26 +03:00
|
|
|
default:
|
|
|
|
/* Not implemented */
|
|
|
|
return nullptr;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
GtkWidget*
|
|
|
|
GetWidget(WidgetNodeType aWidgetType)
|
|
|
|
{
|
|
|
|
GtkWidget* widget = sWidgetStorage[aWidgetType];
|
|
|
|
if (!widget) {
|
|
|
|
widget = CreateWidget(aWidgetType);
|
2017-08-10 19:07:41 +03:00
|
|
|
// Some widgets (MOZ_GTK_COMBOBOX_SEPARATOR for instance) may not be
|
|
|
|
// available or implemented.
|
|
|
|
if (!widget)
|
|
|
|
return nullptr;
|
2017-08-01 00:17:46 +03:00
|
|
|
// In GTK versions prior to 3.18, automatic invalidation of style contexts
|
|
|
|
// for widgets was delayed until the next resize event. Gecko however,
|
|
|
|
// typically uses the style context before the resize event runs and so an
|
|
|
|
// explicit invalidation may be required. This is necessary if a style
|
|
|
|
// property was retrieved before all changes were made to the style
|
|
|
|
// context. One such situation is where gtk_button_construct_child()
|
|
|
|
// retrieves the style property "image-spacing" during construction of the
|
|
|
|
// GtkButton, before its parent is set to provide inheritance of ancestor
|
|
|
|
// properties. More recent GTK versions do not need this, but do not
|
|
|
|
// re-resolve until required and so invalidation does not trigger
|
|
|
|
// unnecessary resolution in general.
|
|
|
|
GtkStyleContext* style = gtk_widget_get_style_context(widget);
|
|
|
|
gtk_style_context_invalidate(style);
|
|
|
|
|
2016-05-09 02:08:26 +03:00
|
|
|
sWidgetStorage[aWidgetType] = widget;
|
|
|
|
}
|
|
|
|
return widget;
|
|
|
|
}
|
|
|
|
|
2016-12-02 02:39:23 +03:00
|
|
|
static void
|
|
|
|
AddStyleClassesFromStyle(GtkStyleContext* aDest, GtkStyleContext* aSrc)
|
|
|
|
{
|
|
|
|
GList* classes = gtk_style_context_list_classes(aSrc);
|
|
|
|
for (GList* link = classes; link; link = link->next) {
|
|
|
|
gtk_style_context_add_class(aDest, static_cast<gchar*>(link->data));
|
|
|
|
}
|
|
|
|
g_list_free(classes);
|
|
|
|
}
|
|
|
|
|
2016-06-07 09:06:04 +03:00
|
|
|
GtkStyleContext*
|
|
|
|
CreateStyleForWidget(GtkWidget* aWidget, GtkStyleContext* aParentStyle)
|
|
|
|
{
|
2016-11-15 05:29:06 +03:00
|
|
|
static auto sGtkWidgetClassGetCSSName =
|
|
|
|
reinterpret_cast<const char* (*)(GtkWidgetClass*)>
|
|
|
|
(dlsym(RTLD_DEFAULT, "gtk_widget_class_get_css_name"));
|
|
|
|
|
|
|
|
GtkWidgetClass *widgetClass = GTK_WIDGET_GET_CLASS(aWidget);
|
|
|
|
const gchar* name = sGtkWidgetClassGetCSSName ?
|
|
|
|
sGtkWidgetClassGetCSSName(widgetClass) : nullptr;
|
|
|
|
|
|
|
|
GtkStyleContext *context =
|
|
|
|
CreateCSSNode(name, aParentStyle, G_TYPE_FROM_CLASS(widgetClass));
|
|
|
|
|
|
|
|
// Classes are stored on the style context instead of the path so that any
|
|
|
|
// future gtk_style_context_save() will inherit classes on the head CSS
|
|
|
|
// node, in the same way as happens when called on a style context owned by
|
|
|
|
// a widget.
|
|
|
|
//
|
|
|
|
// Classes can be stored on a GtkCssNodeDeclaration and/or the path.
|
|
|
|
// gtk_style_context_save() reuses the GtkCssNodeDeclaration, and appends a
|
|
|
|
// new object to the path, without copying the classes from the old path
|
|
|
|
// head. The new head picks up classes from the GtkCssNodeDeclaration, but
|
|
|
|
// not the path. GtkWidgets store their classes on the
|
|
|
|
// GtkCssNodeDeclaration, so make sure to add classes there.
|
|
|
|
//
|
|
|
|
// Picking up classes from the style context also means that
|
|
|
|
// https://bugzilla.gnome.org/show_bug.cgi?id=767312, which can stop
|
|
|
|
// gtk_widget_path_append_for_widget() from finding classes in GTK 3.20,
|
|
|
|
// is not a problem.
|
|
|
|
GtkStyleContext* widgetStyle = gtk_widget_get_style_context(aWidget);
|
2016-12-02 02:39:23 +03:00
|
|
|
AddStyleClassesFromStyle(context, widgetStyle);
|
2016-06-07 09:06:04 +03:00
|
|
|
|
|
|
|
// Release any floating reference on aWidget.
|
|
|
|
g_object_ref_sink(aWidget);
|
|
|
|
g_object_unref(aWidget);
|
|
|
|
|
|
|
|
return context;
|
|
|
|
}
|
|
|
|
|
2016-11-15 07:11:14 +03:00
|
|
|
static GtkStyleContext*
|
|
|
|
CreateStyleForWidget(GtkWidget* aWidget, WidgetNodeType aParentType)
|
|
|
|
{
|
|
|
|
return CreateStyleForWidget(aWidget, GetWidgetRootStyle(aParentType));
|
|
|
|
}
|
|
|
|
|
2016-06-07 03:49:00 +03:00
|
|
|
GtkStyleContext*
|
|
|
|
CreateCSSNode(const char* aName, GtkStyleContext* aParentStyle, GType aType)
|
2016-05-09 02:08:26 +03:00
|
|
|
{
|
|
|
|
static auto sGtkWidgetPathIterSetObjectName =
|
|
|
|
reinterpret_cast<void (*)(GtkWidgetPath *, gint, const char *)>
|
|
|
|
(dlsym(RTLD_DEFAULT, "gtk_widget_path_iter_set_object_name"));
|
|
|
|
|
2016-11-16 06:55:13 +03:00
|
|
|
GtkWidgetPath* path;
|
|
|
|
if (aParentStyle) {
|
|
|
|
path = gtk_widget_path_copy(gtk_style_context_get_path(aParentStyle));
|
|
|
|
// Copy classes from the parent style context to its corresponding node in
|
|
|
|
// the path, because GTK will only match against ancestor classes if they
|
|
|
|
// are on the path.
|
|
|
|
GList* classes = gtk_style_context_list_classes(aParentStyle);
|
|
|
|
for (GList* link = classes; link; link = link->next) {
|
|
|
|
gtk_widget_path_iter_add_class(path, -1, static_cast<gchar*>(link->data));
|
|
|
|
}
|
|
|
|
g_list_free(classes);
|
|
|
|
} else {
|
|
|
|
path = gtk_widget_path_new();
|
|
|
|
}
|
2016-05-09 02:08:26 +03:00
|
|
|
|
2016-06-07 03:49:00 +03:00
|
|
|
gtk_widget_path_append_type(path, aType);
|
2016-05-09 02:08:26 +03:00
|
|
|
|
2016-11-15 05:29:06 +03:00
|
|
|
if (sGtkWidgetPathIterSetObjectName) {
|
|
|
|
(*sGtkWidgetPathIterSetObjectName)(path, -1, aName);
|
|
|
|
}
|
2016-05-09 02:08:26 +03:00
|
|
|
|
|
|
|
GtkStyleContext *context = gtk_style_context_new();
|
|
|
|
gtk_style_context_set_path(context, path);
|
|
|
|
gtk_style_context_set_parent(context, aParentStyle);
|
|
|
|
gtk_widget_path_unref(path);
|
|
|
|
|
2016-12-14 09:22:28 +03:00
|
|
|
// In GTK 3.4, gtk_render_* functions use |theming_engine| on the style
|
|
|
|
// context without ensuring any style resolution sets it appropriately
|
|
|
|
// in style_data_lookup(). e.g.
|
|
|
|
// https://git.gnome.org/browse/gtk+/tree/gtk/gtkstylecontext.c?h=3.4.4#n3847
|
|
|
|
//
|
|
|
|
// That can result in incorrect drawing on first draw. To work around this,
|
|
|
|
// force a style look-up to set |theming_engine|. It is sufficient to do
|
|
|
|
// this only on context creation, instead of after every modification to the
|
|
|
|
// context, because themes typically (Ambiance and oxygen-gtk, at least) set
|
|
|
|
// the "engine" property with the '*' selector.
|
|
|
|
if (GTK_MAJOR_VERSION == 3 && gtk_get_minor_version() < 6) {
|
|
|
|
GdkRGBA unused;
|
|
|
|
gtk_style_context_get_color(context, GTK_STATE_FLAG_NORMAL, &unused);
|
|
|
|
}
|
|
|
|
|
2016-05-09 02:08:26 +03:00
|
|
|
return context;
|
|
|
|
}
|
|
|
|
|
2016-11-15 07:11:14 +03:00
|
|
|
// Return a style context matching that of the root CSS node of a widget.
|
|
|
|
// This is used by all GTK versions.
|
|
|
|
static GtkStyleContext*
|
|
|
|
GetWidgetRootStyle(WidgetNodeType aNodeType)
|
|
|
|
{
|
|
|
|
GtkStyleContext* style = sStyleStorage[aNodeType];
|
|
|
|
if (style)
|
|
|
|
return style;
|
|
|
|
|
|
|
|
switch (aNodeType) {
|
|
|
|
case MOZ_GTK_MENUBARITEM:
|
|
|
|
style = CreateStyleForWidget(gtk_menu_item_new(), MOZ_GTK_MENUBAR);
|
|
|
|
break;
|
|
|
|
case MOZ_GTK_MENUITEM:
|
|
|
|
style = CreateStyleForWidget(gtk_menu_item_new(), MOZ_GTK_MENUPOPUP);
|
|
|
|
break;
|
2016-11-18 03:01:27 +03:00
|
|
|
case MOZ_GTK_CHECKMENUITEM:
|
2016-11-15 07:11:14 +03:00
|
|
|
style = CreateStyleForWidget(gtk_check_menu_item_new(), MOZ_GTK_MENUPOPUP);
|
|
|
|
break;
|
2016-11-18 03:01:27 +03:00
|
|
|
case MOZ_GTK_RADIOMENUITEM:
|
2016-11-15 07:11:14 +03:00
|
|
|
style = CreateStyleForWidget(gtk_radio_menu_item_new(nullptr),
|
|
|
|
MOZ_GTK_MENUPOPUP);
|
|
|
|
break;
|
2016-12-30 03:37:51 +03:00
|
|
|
case MOZ_GTK_TEXT_VIEW:
|
|
|
|
style = CreateStyleForWidget(gtk_text_view_new(),
|
|
|
|
MOZ_GTK_SCROLLED_WINDOW);
|
|
|
|
break;
|
2016-11-24 05:14:58 +03:00
|
|
|
case MOZ_GTK_TOOLTIP:
|
|
|
|
if (gtk_check_version(3, 20, 0) != nullptr) {
|
|
|
|
// The tooltip style class is added first in CreateTooltipWidget()
|
|
|
|
// and transfered to style in CreateStyleForWidget().
|
|
|
|
GtkWidget* tooltipWindow = CreateTooltipWidget();
|
|
|
|
style = CreateStyleForWidget(tooltipWindow, nullptr);
|
|
|
|
gtk_widget_destroy(tooltipWindow); // Release GtkWindow self-reference.
|
|
|
|
} else {
|
|
|
|
// We create this from the path because GtkTooltipWindow is not public.
|
|
|
|
style = CreateCSSNode("tooltip", nullptr, GTK_TYPE_TOOLTIP);
|
|
|
|
gtk_style_context_add_class(style, GTK_STYLE_CLASS_BACKGROUND);
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case MOZ_GTK_TOOLTIP_BOX:
|
|
|
|
style = CreateStyleForWidget(gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 0),
|
|
|
|
MOZ_GTK_TOOLTIP);
|
|
|
|
break;
|
|
|
|
case MOZ_GTK_TOOLTIP_BOX_LABEL:
|
|
|
|
style = CreateStyleForWidget(gtk_label_new(nullptr),
|
|
|
|
MOZ_GTK_TOOLTIP_BOX);
|
|
|
|
break;
|
2016-11-15 07:11:14 +03:00
|
|
|
default:
|
|
|
|
GtkWidget* widget = GetWidget(aNodeType);
|
|
|
|
MOZ_ASSERT(widget);
|
|
|
|
return gtk_widget_get_style_context(widget);
|
|
|
|
}
|
|
|
|
|
|
|
|
MOZ_ASSERT(style);
|
|
|
|
sStyleStorage[aNodeType] = style;
|
|
|
|
return style;
|
|
|
|
}
|
|
|
|
|
2016-05-09 02:08:26 +03:00
|
|
|
static GtkStyleContext*
|
2016-06-07 03:49:00 +03:00
|
|
|
CreateChildCSSNode(const char* aName, WidgetNodeType aParentNodeType)
|
2016-05-09 02:08:26 +03:00
|
|
|
{
|
2016-06-07 03:49:00 +03:00
|
|
|
return CreateCSSNode(aName, GetCssNodeStyleInternal(aParentNodeType));
|
2016-05-09 02:08:26 +03:00
|
|
|
}
|
|
|
|
|
2016-12-02 02:39:23 +03:00
|
|
|
// Create a style context equivalent to a saved root style context of
|
|
|
|
// |aWidgetType| with |aStyleClass| as an additional class. This is used to
|
|
|
|
// produce a context equivalent to what GTK versions < 3.20 use for many
|
|
|
|
// internal parts of widgets.
|
2016-07-18 06:29:00 +03:00
|
|
|
static GtkStyleContext*
|
2016-12-02 02:39:23 +03:00
|
|
|
CreateSubStyleWithClass(WidgetNodeType aWidgetType, const gchar* aStyleClass)
|
2016-07-18 06:29:00 +03:00
|
|
|
{
|
2016-12-02 02:39:23 +03:00
|
|
|
static auto sGtkWidgetPathIterGetObjectName =
|
|
|
|
reinterpret_cast<const char* (*)(const GtkWidgetPath*, gint)>
|
|
|
|
(dlsym(RTLD_DEFAULT, "gtk_widget_path_iter_get_object_name"));
|
|
|
|
|
|
|
|
GtkStyleContext* parentStyle = GetWidgetRootStyle(aWidgetType);
|
|
|
|
|
|
|
|
// Create a new context that behaves like |parentStyle| would after
|
|
|
|
// gtk_style_context_save(parentStyle).
|
|
|
|
//
|
|
|
|
// Avoiding gtk_style_context_save() avoids the need to manage the
|
|
|
|
// restore, and a new context permits caching style resolution.
|
|
|
|
//
|
|
|
|
// gtk_style_context_save(context) changes the node hierarchy of |context|
|
|
|
|
// to add a new GtkCssNodeDeclaration that is a copy of its original node.
|
|
|
|
// The new node is a child of the original node, and so the new heirarchy is
|
|
|
|
// one level deeper. The new node receives the same classes as the
|
|
|
|
// original, but any changes to the classes on |context| will change only
|
|
|
|
// the new node. The new node inherits properties from the original node
|
|
|
|
// (which retains the original heirarchy and classes) and matches CSS rules
|
|
|
|
// with the new heirarchy and any changes to the classes.
|
|
|
|
//
|
|
|
|
// The change in hierarchy can produce some surprises in matching theme CSS
|
|
|
|
// rules (e.g. https://bugzilla.gnome.org/show_bug.cgi?id=761870#c2), but it
|
|
|
|
// is important here to produce the same behavior so that rules match the
|
|
|
|
// same widget parts in Gecko as they do in GTK.
|
|
|
|
//
|
|
|
|
// When using public GTK API to construct style contexts, a widget path is
|
|
|
|
// required. CSS rules are not matched against the style context heirarchy
|
|
|
|
// but according to the heirarchy in the widget path. The path that matches
|
|
|
|
// the same CSS rules as a saved context is like the path of |parentStyle|
|
|
|
|
// but with an extra copy of the head (last) object appended. Setting
|
|
|
|
// |parentStyle| as the parent context provides the same inheritance of
|
|
|
|
// properties from the widget root node.
|
|
|
|
const GtkWidgetPath* parentPath = gtk_style_context_get_path(parentStyle);
|
|
|
|
const gchar* name = sGtkWidgetPathIterGetObjectName ?
|
|
|
|
sGtkWidgetPathIterGetObjectName(parentPath, -1) : nullptr;
|
|
|
|
GType objectType = gtk_widget_path_get_object_type(parentPath);
|
|
|
|
|
|
|
|
GtkStyleContext* style = CreateCSSNode(name, parentStyle, objectType);
|
|
|
|
|
|
|
|
// Start with the same classes on the new node as were on |parentStyle|.
|
|
|
|
// GTK puts no regions or junction_sides on widget root nodes, and so there
|
|
|
|
// is no need to copy these.
|
|
|
|
AddStyleClassesFromStyle(style, parentStyle);
|
|
|
|
|
2016-07-18 06:29:00 +03:00
|
|
|
gtk_style_context_add_class(style, aStyleClass);
|
|
|
|
return style;
|
|
|
|
}
|
|
|
|
|
2016-06-07 03:49:00 +03:00
|
|
|
/* GetCssNodeStyleInternal is used by Gtk >= 3.20 */
|
2016-05-09 02:08:26 +03:00
|
|
|
static GtkStyleContext*
|
2016-06-07 03:49:00 +03:00
|
|
|
GetCssNodeStyleInternal(WidgetNodeType aNodeType)
|
2016-05-09 02:08:26 +03:00
|
|
|
{
|
2016-06-07 03:49:00 +03:00
|
|
|
GtkStyleContext* style = sStyleStorage[aNodeType];
|
|
|
|
if (style)
|
|
|
|
return style;
|
|
|
|
|
2016-05-09 02:08:26 +03:00
|
|
|
switch (aNodeType) {
|
2016-06-13 05:35:00 +03:00
|
|
|
case MOZ_GTK_SCROLLBAR_CONTENTS_HORIZONTAL:
|
|
|
|
style = CreateChildCSSNode("contents",
|
|
|
|
MOZ_GTK_SCROLLBAR_HORIZONTAL);
|
|
|
|
break;
|
2016-05-09 02:08:26 +03:00
|
|
|
case MOZ_GTK_SCROLLBAR_TROUGH_HORIZONTAL:
|
2016-06-07 03:49:00 +03:00
|
|
|
style = CreateChildCSSNode(GTK_STYLE_CLASS_TROUGH,
|
2016-06-13 05:35:00 +03:00
|
|
|
MOZ_GTK_SCROLLBAR_CONTENTS_HORIZONTAL);
|
2016-06-07 03:49:00 +03:00
|
|
|
break;
|
2016-05-09 02:08:26 +03:00
|
|
|
case MOZ_GTK_SCROLLBAR_THUMB_HORIZONTAL:
|
2016-06-07 03:49:00 +03:00
|
|
|
style = CreateChildCSSNode(GTK_STYLE_CLASS_SLIDER,
|
|
|
|
MOZ_GTK_SCROLLBAR_TROUGH_HORIZONTAL);
|
2016-05-13 02:59:17 +03:00
|
|
|
break;
|
2016-06-13 05:35:00 +03:00
|
|
|
case MOZ_GTK_SCROLLBAR_CONTENTS_VERTICAL:
|
|
|
|
style = CreateChildCSSNode("contents",
|
|
|
|
MOZ_GTK_SCROLLBAR_VERTICAL);
|
|
|
|
break;
|
2016-05-09 02:08:26 +03:00
|
|
|
case MOZ_GTK_SCROLLBAR_TROUGH_VERTICAL:
|
2016-06-07 03:49:00 +03:00
|
|
|
style = CreateChildCSSNode(GTK_STYLE_CLASS_TROUGH,
|
2016-06-13 05:35:00 +03:00
|
|
|
MOZ_GTK_SCROLLBAR_CONTENTS_VERTICAL);
|
2016-06-07 03:49:00 +03:00
|
|
|
break;
|
2016-05-09 02:08:26 +03:00
|
|
|
case MOZ_GTK_SCROLLBAR_THUMB_VERTICAL:
|
2016-06-07 03:49:00 +03:00
|
|
|
style = CreateChildCSSNode(GTK_STYLE_CLASS_SLIDER,
|
|
|
|
MOZ_GTK_SCROLLBAR_TROUGH_VERTICAL);
|
2016-05-13 02:59:17 +03:00
|
|
|
break;
|
Bug 1289148 - Fixing scrollbar metrics for GTK >= 3.20 r=karlt
The Gtk 3.20 scrollbars has moved towards usual box model. The scrollbar,
trough,thumb and scrollbar button can now have margin, padding and border set,
different for each direction (ie. left, right, bottom, top). The scrollbar
metrics become ignored in Gtk 3.20 and later.
* Draw scrollbar element [for GTK 3.20+]
* The border for scrollbar, trough, thumb and scrollbar buttons is newly
calculated as margin+padding+border [for GTK 3.20+].
* The margin is subtracted for scrollbar, trough and sb buttons during paint
function [for GTK 3.6+]
* All scrollbar widget's borders transfered from
nsNativeThemeGTK::GetWidgetBorder to the moz_gtk_get_widget_border.
* Added helper function NativeThemeToGtkTheme for mapping mozilla's widget type
to the gtk widget type.
* Scrollbar troughs are now drawn even when there is not enough room for
the thumb [GTK 3.20+]
MozReview-Commit-ID: jd2q67gKM1
--HG--
extra : rebase_source : ecc8b85401845113d84c6c5a48219a0c3d4f8de3
2016-10-17 01:37:13 +03:00
|
|
|
case MOZ_GTK_SCROLLBAR_BUTTON:
|
|
|
|
style = CreateChildCSSNode(GTK_STYLE_CLASS_BUTTON,
|
|
|
|
MOZ_GTK_SCROLLBAR_CONTENTS_VERTICAL);
|
|
|
|
break;
|
2016-05-13 02:59:17 +03:00
|
|
|
case MOZ_GTK_RADIOBUTTON:
|
2016-06-07 03:49:00 +03:00
|
|
|
style = CreateChildCSSNode(GTK_STYLE_CLASS_RADIO,
|
|
|
|
MOZ_GTK_RADIOBUTTON_CONTAINER);
|
2016-05-13 02:59:17 +03:00
|
|
|
break;
|
|
|
|
case MOZ_GTK_CHECKBUTTON:
|
2016-06-07 03:49:00 +03:00
|
|
|
style = CreateChildCSSNode(GTK_STYLE_CLASS_CHECK,
|
|
|
|
MOZ_GTK_CHECKBUTTON_CONTAINER);
|
2016-05-24 14:43:00 +03:00
|
|
|
break;
|
2016-11-18 03:01:27 +03:00
|
|
|
case MOZ_GTK_RADIOMENUITEM_INDICATOR:
|
2016-07-28 04:54:00 +03:00
|
|
|
style = CreateChildCSSNode(GTK_STYLE_CLASS_RADIO,
|
2016-11-18 03:01:27 +03:00
|
|
|
MOZ_GTK_RADIOMENUITEM);
|
2016-07-28 04:54:00 +03:00
|
|
|
break;
|
2016-11-18 03:01:27 +03:00
|
|
|
case MOZ_GTK_CHECKMENUITEM_INDICATOR:
|
2016-07-28 04:54:00 +03:00
|
|
|
style = CreateChildCSSNode(GTK_STYLE_CLASS_CHECK,
|
2016-11-18 03:01:27 +03:00
|
|
|
MOZ_GTK_CHECKMENUITEM);
|
2016-07-28 04:54:00 +03:00
|
|
|
break;
|
2016-05-24 14:43:00 +03:00
|
|
|
case MOZ_GTK_PROGRESS_TROUGH:
|
|
|
|
/* Progress bar background (trough) */
|
2016-06-07 03:49:00 +03:00
|
|
|
style = CreateChildCSSNode(GTK_STYLE_CLASS_TROUGH,
|
|
|
|
MOZ_GTK_PROGRESSBAR);
|
|
|
|
break;
|
2016-05-24 14:43:00 +03:00
|
|
|
case MOZ_GTK_PROGRESS_CHUNK:
|
2016-06-07 03:49:00 +03:00
|
|
|
style = CreateChildCSSNode("progress",
|
|
|
|
MOZ_GTK_PROGRESS_TROUGH);
|
2016-05-13 02:59:17 +03:00
|
|
|
break;
|
2016-07-18 06:29:00 +03:00
|
|
|
case MOZ_GTK_GRIPPER:
|
|
|
|
// TODO - create from CSS node
|
2016-12-02 02:39:23 +03:00
|
|
|
style = CreateSubStyleWithClass(MOZ_GTK_GRIPPER,
|
|
|
|
GTK_STYLE_CLASS_GRIP);
|
|
|
|
break;
|
2016-07-19 07:03:00 +03:00
|
|
|
case MOZ_GTK_INFO_BAR:
|
|
|
|
// TODO - create from CSS node
|
2016-12-02 02:39:23 +03:00
|
|
|
style = CreateSubStyleWithClass(MOZ_GTK_INFO_BAR,
|
|
|
|
GTK_STYLE_CLASS_INFO);
|
|
|
|
break;
|
2016-07-20 02:57:00 +03:00
|
|
|
case MOZ_GTK_SPINBUTTON_ENTRY:
|
|
|
|
// TODO - create from CSS node
|
2016-12-02 02:39:23 +03:00
|
|
|
style = CreateSubStyleWithClass(MOZ_GTK_SPINBUTTON,
|
|
|
|
GTK_STYLE_CLASS_ENTRY);
|
|
|
|
break;
|
2016-07-25 07:46:00 +03:00
|
|
|
case MOZ_GTK_SCROLLED_WINDOW:
|
|
|
|
// TODO - create from CSS node
|
2016-12-02 02:39:23 +03:00
|
|
|
style = CreateSubStyleWithClass(MOZ_GTK_SCROLLED_WINDOW,
|
|
|
|
GTK_STYLE_CLASS_FRAME);
|
|
|
|
break;
|
2016-12-30 03:37:51 +03:00
|
|
|
case MOZ_GTK_TEXT_VIEW_TEXT:
|
|
|
|
case MOZ_GTK_RESIZER:
|
2016-12-30 03:44:55 +03:00
|
|
|
style = CreateChildCSSNode("text", MOZ_GTK_TEXT_VIEW);
|
2016-12-30 03:37:51 +03:00
|
|
|
if (aNodeType == MOZ_GTK_RESIZER) {
|
|
|
|
// The "grip" class provides the correct builtin icon from
|
|
|
|
// gtk_render_handle(). The icon is drawn with shaded variants of
|
|
|
|
// the background color, and so a transparent background would lead to
|
|
|
|
// a transparent resizer. gtk_render_handle() also uses the
|
|
|
|
// background color to draw a background, and so this style otherwise
|
2016-12-30 03:44:55 +03:00
|
|
|
// matches what is used in GtkTextView to match the background with
|
2016-12-30 03:37:51 +03:00
|
|
|
// textarea elements.
|
2016-12-30 03:44:55 +03:00
|
|
|
GdkRGBA color;
|
|
|
|
gtk_style_context_get_background_color(style, GTK_STATE_FLAG_NORMAL,
|
|
|
|
&color);
|
|
|
|
if (color.alpha == 0.0) {
|
|
|
|
g_object_unref(style);
|
|
|
|
style = CreateStyleForWidget(gtk_text_view_new(),
|
|
|
|
MOZ_GTK_SCROLLED_WINDOW);
|
|
|
|
}
|
2016-12-30 03:37:51 +03:00
|
|
|
gtk_style_context_add_class(style, GTK_STYLE_CLASS_GRIP);
|
|
|
|
}
|
2016-12-30 03:44:55 +03:00
|
|
|
break;
|
2016-07-25 17:32:12 +03:00
|
|
|
case MOZ_GTK_FRAME_BORDER:
|
2016-08-08 04:10:00 +03:00
|
|
|
style = CreateChildCSSNode("border", MOZ_GTK_FRAME);
|
|
|
|
break;
|
2016-07-29 06:15:00 +03:00
|
|
|
case MOZ_GTK_TREEVIEW_VIEW:
|
|
|
|
// TODO - create from CSS node
|
2016-12-02 02:39:23 +03:00
|
|
|
style = CreateSubStyleWithClass(MOZ_GTK_TREEVIEW,
|
|
|
|
GTK_STYLE_CLASS_VIEW);
|
|
|
|
break;
|
2016-07-29 06:15:00 +03:00
|
|
|
case MOZ_GTK_TREEVIEW_EXPANDER:
|
|
|
|
// TODO - create from CSS node
|
2016-12-02 02:39:23 +03:00
|
|
|
style = CreateSubStyleWithClass(MOZ_GTK_TREEVIEW,
|
|
|
|
GTK_STYLE_CLASS_EXPANDER);
|
|
|
|
break;
|
2016-07-29 06:30:00 +03:00
|
|
|
case MOZ_GTK_SPLITTER_SEPARATOR_HORIZONTAL:
|
|
|
|
style = CreateChildCSSNode("separator",
|
|
|
|
MOZ_GTK_SPLITTER_HORIZONTAL);
|
|
|
|
break;
|
|
|
|
case MOZ_GTK_SPLITTER_SEPARATOR_VERTICAL:
|
|
|
|
style = CreateChildCSSNode("separator",
|
|
|
|
MOZ_GTK_SPLITTER_VERTICAL);
|
|
|
|
break;
|
2016-08-19 12:20:00 +03:00
|
|
|
case MOZ_GTK_SCALE_CONTENTS_HORIZONTAL:
|
|
|
|
style = CreateChildCSSNode("contents",
|
|
|
|
MOZ_GTK_SCALE_HORIZONTAL);
|
|
|
|
break;
|
|
|
|
case MOZ_GTK_SCALE_CONTENTS_VERTICAL:
|
|
|
|
style = CreateChildCSSNode("contents",
|
|
|
|
MOZ_GTK_SCALE_VERTICAL);
|
2017-12-19 13:38:59 +03:00
|
|
|
break;
|
2016-08-19 12:20:00 +03:00
|
|
|
case MOZ_GTK_SCALE_TROUGH_HORIZONTAL:
|
|
|
|
style = CreateChildCSSNode(GTK_STYLE_CLASS_TROUGH,
|
|
|
|
MOZ_GTK_SCALE_CONTENTS_HORIZONTAL);
|
2017-12-19 13:38:59 +03:00
|
|
|
break;
|
2016-08-19 12:20:00 +03:00
|
|
|
case MOZ_GTK_SCALE_TROUGH_VERTICAL:
|
|
|
|
style = CreateChildCSSNode(GTK_STYLE_CLASS_TROUGH,
|
|
|
|
MOZ_GTK_SCALE_CONTENTS_VERTICAL);
|
|
|
|
break;
|
|
|
|
case MOZ_GTK_SCALE_THUMB_HORIZONTAL:
|
|
|
|
style = CreateChildCSSNode(GTK_STYLE_CLASS_SLIDER,
|
|
|
|
MOZ_GTK_SCALE_TROUGH_HORIZONTAL);
|
|
|
|
break;
|
|
|
|
case MOZ_GTK_SCALE_THUMB_VERTICAL:
|
|
|
|
style = CreateChildCSSNode(GTK_STYLE_CLASS_SLIDER,
|
|
|
|
MOZ_GTK_SCALE_TROUGH_VERTICAL);
|
|
|
|
break;
|
2016-08-22 06:13:00 +03:00
|
|
|
case MOZ_GTK_TAB_TOP:
|
|
|
|
{
|
|
|
|
// TODO - create from CSS node
|
2016-12-02 02:39:23 +03:00
|
|
|
style = CreateSubStyleWithClass(MOZ_GTK_NOTEBOOK,
|
2016-08-22 06:13:00 +03:00
|
|
|
GTK_STYLE_CLASS_TOP);
|
|
|
|
gtk_style_context_add_region(style, GTK_STYLE_REGION_TAB,
|
|
|
|
static_cast<GtkRegionFlags>(0));
|
2016-12-02 02:39:23 +03:00
|
|
|
break;
|
2016-08-22 06:13:00 +03:00
|
|
|
}
|
|
|
|
case MOZ_GTK_TAB_BOTTOM:
|
|
|
|
{
|
|
|
|
// TODO - create from CSS node
|
2016-12-02 02:39:23 +03:00
|
|
|
style = CreateSubStyleWithClass(MOZ_GTK_NOTEBOOK,
|
2016-08-22 06:13:00 +03:00
|
|
|
GTK_STYLE_CLASS_BOTTOM);
|
|
|
|
gtk_style_context_add_region(style, GTK_STYLE_REGION_TAB,
|
|
|
|
static_cast<GtkRegionFlags>(0));
|
2016-12-02 02:39:23 +03:00
|
|
|
break;
|
2016-08-22 06:13:00 +03:00
|
|
|
}
|
|
|
|
case MOZ_GTK_NOTEBOOK:
|
|
|
|
case MOZ_GTK_NOTEBOOK_HEADER:
|
|
|
|
case MOZ_GTK_TABPANELS:
|
|
|
|
case MOZ_GTK_TAB_SCROLLARROW:
|
2017-12-19 13:38:59 +03:00
|
|
|
{
|
2016-08-22 06:13:00 +03:00
|
|
|
// TODO - create from CSS node
|
|
|
|
GtkWidget* widget = GetWidget(MOZ_GTK_NOTEBOOK);
|
|
|
|
return gtk_widget_get_style_context(widget);
|
|
|
|
}
|
2016-06-07 03:49:00 +03:00
|
|
|
default:
|
2016-11-15 07:11:14 +03:00
|
|
|
return GetWidgetRootStyle(aNodeType);
|
2016-05-09 02:08:26 +03:00
|
|
|
}
|
2016-05-13 02:59:17 +03:00
|
|
|
|
2016-06-22 07:46:24 +03:00
|
|
|
MOZ_ASSERT(style, "missing style context for node type");
|
|
|
|
sStyleStorage[aNodeType] = style;
|
|
|
|
return style;
|
2016-05-09 02:08:26 +03:00
|
|
|
}
|
|
|
|
|
2016-06-07 03:49:00 +03:00
|
|
|
/* GetWidgetStyleInternal is used by Gtk < 3.20 */
|
|
|
|
static GtkStyleContext*
|
|
|
|
GetWidgetStyleInternal(WidgetNodeType aNodeType)
|
|
|
|
{
|
2016-12-02 02:39:23 +03:00
|
|
|
GtkStyleContext* style = sStyleStorage[aNodeType];
|
|
|
|
if (style)
|
|
|
|
return style;
|
|
|
|
|
2016-06-07 03:49:00 +03:00
|
|
|
switch (aNodeType) {
|
|
|
|
case MOZ_GTK_SCROLLBAR_TROUGH_HORIZONTAL:
|
2016-12-02 02:39:23 +03:00
|
|
|
style = CreateSubStyleWithClass(MOZ_GTK_SCROLLBAR_HORIZONTAL,
|
|
|
|
GTK_STYLE_CLASS_TROUGH);
|
|
|
|
break;
|
2016-06-07 03:49:00 +03:00
|
|
|
case MOZ_GTK_SCROLLBAR_THUMB_HORIZONTAL:
|
2016-12-02 02:39:23 +03:00
|
|
|
style = CreateSubStyleWithClass(MOZ_GTK_SCROLLBAR_HORIZONTAL,
|
|
|
|
GTK_STYLE_CLASS_SLIDER);
|
|
|
|
break;
|
2016-06-07 03:49:00 +03:00
|
|
|
case MOZ_GTK_SCROLLBAR_TROUGH_VERTICAL:
|
2016-12-02 02:39:23 +03:00
|
|
|
style = CreateSubStyleWithClass(MOZ_GTK_SCROLLBAR_VERTICAL,
|
|
|
|
GTK_STYLE_CLASS_TROUGH);
|
|
|
|
break;
|
2016-06-07 03:49:00 +03:00
|
|
|
case MOZ_GTK_SCROLLBAR_THUMB_VERTICAL:
|
2016-12-02 02:39:23 +03:00
|
|
|
style = CreateSubStyleWithClass(MOZ_GTK_SCROLLBAR_VERTICAL,
|
|
|
|
GTK_STYLE_CLASS_SLIDER);
|
|
|
|
break;
|
2016-06-07 03:49:00 +03:00
|
|
|
case MOZ_GTK_RADIOBUTTON:
|
2016-12-02 02:39:23 +03:00
|
|
|
style = CreateSubStyleWithClass(MOZ_GTK_RADIOBUTTON_CONTAINER,
|
|
|
|
GTK_STYLE_CLASS_RADIO);
|
|
|
|
break;
|
2016-06-07 03:49:00 +03:00
|
|
|
case MOZ_GTK_CHECKBUTTON:
|
2016-12-02 02:39:23 +03:00
|
|
|
style = CreateSubStyleWithClass(MOZ_GTK_CHECKBUTTON_CONTAINER,
|
|
|
|
GTK_STYLE_CLASS_CHECK);
|
|
|
|
break;
|
2016-11-18 03:01:27 +03:00
|
|
|
case MOZ_GTK_RADIOMENUITEM_INDICATOR:
|
2016-12-02 02:39:23 +03:00
|
|
|
style = CreateSubStyleWithClass(MOZ_GTK_RADIOMENUITEM,
|
|
|
|
GTK_STYLE_CLASS_RADIO);
|
|
|
|
break;
|
2016-11-18 03:01:27 +03:00
|
|
|
case MOZ_GTK_CHECKMENUITEM_INDICATOR:
|
2016-12-02 02:39:23 +03:00
|
|
|
style = CreateSubStyleWithClass(MOZ_GTK_CHECKMENUITEM,
|
|
|
|
GTK_STYLE_CLASS_CHECK);
|
|
|
|
break;
|
2016-06-07 03:49:00 +03:00
|
|
|
case MOZ_GTK_PROGRESS_TROUGH:
|
2016-12-02 02:39:23 +03:00
|
|
|
style = CreateSubStyleWithClass(MOZ_GTK_PROGRESSBAR,
|
|
|
|
GTK_STYLE_CLASS_TROUGH);
|
|
|
|
break;
|
|
|
|
case MOZ_GTK_PROGRESS_CHUNK:
|
|
|
|
style = CreateSubStyleWithClass(MOZ_GTK_PROGRESSBAR,
|
|
|
|
GTK_STYLE_CLASS_PROGRESSBAR);
|
2016-11-25 07:51:13 +03:00
|
|
|
gtk_style_context_remove_class(style, GTK_STYLE_CLASS_TROUGH);
|
2016-12-02 02:39:23 +03:00
|
|
|
break;
|
2016-07-18 06:29:00 +03:00
|
|
|
case MOZ_GTK_GRIPPER:
|
2016-12-02 02:39:23 +03:00
|
|
|
style = CreateSubStyleWithClass(MOZ_GTK_GRIPPER,
|
|
|
|
GTK_STYLE_CLASS_GRIP);
|
|
|
|
break;
|
2016-07-19 07:03:00 +03:00
|
|
|
case MOZ_GTK_INFO_BAR:
|
2016-12-02 02:39:23 +03:00
|
|
|
style = CreateSubStyleWithClass(MOZ_GTK_INFO_BAR,
|
|
|
|
GTK_STYLE_CLASS_INFO);
|
|
|
|
break;
|
2016-07-20 02:57:00 +03:00
|
|
|
case MOZ_GTK_SPINBUTTON_ENTRY:
|
2016-12-02 02:39:23 +03:00
|
|
|
style = CreateSubStyleWithClass(MOZ_GTK_SPINBUTTON,
|
|
|
|
GTK_STYLE_CLASS_ENTRY);
|
|
|
|
break;
|
2016-07-25 07:46:00 +03:00
|
|
|
case MOZ_GTK_SCROLLED_WINDOW:
|
2016-12-02 02:39:23 +03:00
|
|
|
style = CreateSubStyleWithClass(MOZ_GTK_SCROLLED_WINDOW,
|
|
|
|
GTK_STYLE_CLASS_FRAME);
|
|
|
|
break;
|
2016-12-30 03:37:51 +03:00
|
|
|
case MOZ_GTK_TEXT_VIEW_TEXT:
|
2016-12-02 02:39:23 +03:00
|
|
|
case MOZ_GTK_RESIZER:
|
2016-12-30 03:37:51 +03:00
|
|
|
// GTK versions prior to 3.20 do not have the view class on the root
|
|
|
|
// node, but add this to determine the background for the text window.
|
2016-12-02 02:39:23 +03:00
|
|
|
style = CreateSubStyleWithClass(MOZ_GTK_TEXT_VIEW, GTK_STYLE_CLASS_VIEW);
|
2016-12-30 03:37:51 +03:00
|
|
|
if (aNodeType == MOZ_GTK_RESIZER) {
|
|
|
|
// The "grip" class provides the correct builtin icon from
|
|
|
|
// gtk_render_handle(). The icon is drawn with shaded variants of
|
|
|
|
// the background color, and so a transparent background would lead to
|
|
|
|
// a transparent resizer. gtk_render_handle() also uses the
|
|
|
|
// background color to draw a background, and so this style otherwise
|
|
|
|
// matches MOZ_GTK_TEXT_VIEW_TEXT to match the background with
|
|
|
|
// textarea elements. GtkTextView creates a separate text window and
|
|
|
|
// so the background should not be transparent.
|
|
|
|
gtk_style_context_add_class(style, GTK_STYLE_CLASS_GRIP);
|
|
|
|
}
|
2016-12-02 02:39:23 +03:00
|
|
|
break;
|
2016-07-25 17:32:12 +03:00
|
|
|
case MOZ_GTK_FRAME_BORDER:
|
2016-11-15 07:11:14 +03:00
|
|
|
return GetWidgetRootStyle(MOZ_GTK_FRAME);
|
2016-07-29 06:15:00 +03:00
|
|
|
case MOZ_GTK_TREEVIEW_VIEW:
|
2016-12-02 02:39:23 +03:00
|
|
|
style = CreateSubStyleWithClass(MOZ_GTK_TREEVIEW,
|
|
|
|
GTK_STYLE_CLASS_VIEW);
|
|
|
|
break;
|
2016-07-29 06:15:00 +03:00
|
|
|
case MOZ_GTK_TREEVIEW_EXPANDER:
|
2016-12-02 02:39:23 +03:00
|
|
|
style = CreateSubStyleWithClass(MOZ_GTK_TREEVIEW,
|
|
|
|
GTK_STYLE_CLASS_EXPANDER);
|
|
|
|
break;
|
2016-07-29 06:30:00 +03:00
|
|
|
case MOZ_GTK_SPLITTER_SEPARATOR_HORIZONTAL:
|
2016-12-02 02:39:23 +03:00
|
|
|
style = CreateSubStyleWithClass(MOZ_GTK_SPLITTER_HORIZONTAL,
|
|
|
|
GTK_STYLE_CLASS_PANE_SEPARATOR);
|
|
|
|
break;
|
2016-07-29 06:30:00 +03:00
|
|
|
case MOZ_GTK_SPLITTER_SEPARATOR_VERTICAL:
|
2016-12-02 02:39:23 +03:00
|
|
|
style = CreateSubStyleWithClass(MOZ_GTK_SPLITTER_VERTICAL,
|
|
|
|
GTK_STYLE_CLASS_PANE_SEPARATOR);
|
|
|
|
break;
|
2016-08-19 12:20:00 +03:00
|
|
|
case MOZ_GTK_SCALE_TROUGH_HORIZONTAL:
|
2016-12-02 02:39:23 +03:00
|
|
|
style = CreateSubStyleWithClass(MOZ_GTK_SCALE_HORIZONTAL,
|
|
|
|
GTK_STYLE_CLASS_TROUGH);
|
|
|
|
break;
|
2016-08-19 12:20:00 +03:00
|
|
|
case MOZ_GTK_SCALE_TROUGH_VERTICAL:
|
2016-12-02 02:39:23 +03:00
|
|
|
style = CreateSubStyleWithClass(MOZ_GTK_SCALE_VERTICAL,
|
|
|
|
GTK_STYLE_CLASS_TROUGH);
|
|
|
|
break;
|
2016-08-19 12:20:00 +03:00
|
|
|
case MOZ_GTK_SCALE_THUMB_HORIZONTAL:
|
2016-12-02 02:39:23 +03:00
|
|
|
style = CreateSubStyleWithClass(MOZ_GTK_SCALE_HORIZONTAL,
|
|
|
|
GTK_STYLE_CLASS_SLIDER);
|
|
|
|
break;
|
2016-08-19 12:20:00 +03:00
|
|
|
case MOZ_GTK_SCALE_THUMB_VERTICAL:
|
2016-12-02 02:39:23 +03:00
|
|
|
style = CreateSubStyleWithClass(MOZ_GTK_SCALE_VERTICAL,
|
|
|
|
GTK_STYLE_CLASS_SLIDER);
|
|
|
|
break;
|
2016-08-22 06:13:00 +03:00
|
|
|
case MOZ_GTK_TAB_TOP:
|
2016-12-02 02:39:23 +03:00
|
|
|
style = CreateSubStyleWithClass(MOZ_GTK_NOTEBOOK, GTK_STYLE_CLASS_TOP);
|
2016-08-22 06:13:00 +03:00
|
|
|
gtk_style_context_add_region(style, GTK_STYLE_REGION_TAB,
|
|
|
|
static_cast<GtkRegionFlags>(0));
|
2016-12-02 02:39:23 +03:00
|
|
|
break;
|
2016-08-22 06:13:00 +03:00
|
|
|
case MOZ_GTK_TAB_BOTTOM:
|
2016-12-02 02:39:23 +03:00
|
|
|
style = CreateSubStyleWithClass(MOZ_GTK_NOTEBOOK, GTK_STYLE_CLASS_BOTTOM);
|
2016-08-22 06:13:00 +03:00
|
|
|
gtk_style_context_add_region(style, GTK_STYLE_REGION_TAB,
|
|
|
|
static_cast<GtkRegionFlags>(0));
|
2016-12-02 02:39:23 +03:00
|
|
|
break;
|
2016-08-22 06:13:00 +03:00
|
|
|
case MOZ_GTK_NOTEBOOK:
|
|
|
|
case MOZ_GTK_NOTEBOOK_HEADER:
|
|
|
|
case MOZ_GTK_TABPANELS:
|
|
|
|
case MOZ_GTK_TAB_SCROLLARROW:
|
2017-12-19 13:38:59 +03:00
|
|
|
{
|
2016-08-22 06:13:00 +03:00
|
|
|
GtkWidget* widget = GetWidget(MOZ_GTK_NOTEBOOK);
|
|
|
|
return gtk_widget_get_style_context(widget);
|
|
|
|
}
|
2016-06-07 03:49:00 +03:00
|
|
|
default:
|
2016-11-15 07:11:14 +03:00
|
|
|
return GetWidgetRootStyle(aNodeType);
|
2016-06-07 03:49:00 +03:00
|
|
|
}
|
2016-12-02 02:39:23 +03:00
|
|
|
|
|
|
|
MOZ_ASSERT(style);
|
|
|
|
sStyleStorage[aNodeType] = style;
|
|
|
|
return style;
|
2016-06-07 03:49:00 +03:00
|
|
|
}
|
|
|
|
|
2016-05-09 02:08:26 +03:00
|
|
|
void
|
|
|
|
ResetWidgetCache(void)
|
|
|
|
{
|
|
|
|
for (int i = 0; i < MOZ_GTK_WIDGET_NODE_COUNT; i++) {
|
|
|
|
if (sStyleStorage[i])
|
|
|
|
g_object_unref(sStyleStorage[i]);
|
|
|
|
}
|
2016-05-09 19:50:00 +03:00
|
|
|
mozilla::PodArrayZero(sStyleStorage);
|
2016-05-09 02:08:26 +03:00
|
|
|
|
|
|
|
/* This will destroy all of our widgets */
|
|
|
|
if (sWidgetStorage[MOZ_GTK_WINDOW])
|
|
|
|
gtk_widget_destroy(sWidgetStorage[MOZ_GTK_WINDOW]);
|
2017-09-19 19:20:48 +03:00
|
|
|
if (sWidgetStorage[MOZ_GTK_WINDOW_MAXIMIZED])
|
|
|
|
gtk_widget_destroy(sWidgetStorage[MOZ_GTK_WINDOW_MAXIMIZED]);
|
2016-05-09 02:08:26 +03:00
|
|
|
|
|
|
|
/* Clear already freed arrays */
|
2016-05-09 19:50:00 +03:00
|
|
|
mozilla::PodArrayZero(sWidgetStorage);
|
2016-05-09 02:08:26 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
GtkStyleContext*
|
2017-09-05 00:16:01 +03:00
|
|
|
GetStyleContext(WidgetNodeType aNodeType, GtkTextDirection aDirection,
|
|
|
|
GtkStateFlags aStateFlags, StyleFlags aFlags)
|
2016-05-09 02:08:26 +03:00
|
|
|
{
|
2016-06-07 03:49:00 +03:00
|
|
|
GtkStyleContext* style;
|
|
|
|
if (gtk_check_version(3, 20, 0) != nullptr) {
|
|
|
|
style = GetWidgetStyleInternal(aNodeType);
|
|
|
|
} else {
|
|
|
|
style = GetCssNodeStyleInternal(aNodeType);
|
|
|
|
}
|
2016-09-08 01:12:55 +03:00
|
|
|
bool stateChanged = false;
|
|
|
|
bool stateHasDirection = gtk_get_minor_version() >= 8;
|
2016-05-17 09:15:12 +03:00
|
|
|
GtkStateFlags oldState = gtk_style_context_get_state(style);
|
2016-09-08 01:12:55 +03:00
|
|
|
MOZ_ASSERT(!(aStateFlags & (STATE_FLAG_DIR_LTR|STATE_FLAG_DIR_RTL)));
|
|
|
|
unsigned newState = aStateFlags;
|
|
|
|
if (stateHasDirection) {
|
|
|
|
switch (aDirection) {
|
|
|
|
case GTK_TEXT_DIR_LTR:
|
|
|
|
newState |= STATE_FLAG_DIR_LTR;
|
|
|
|
break;
|
|
|
|
case GTK_TEXT_DIR_RTL:
|
|
|
|
newState |= STATE_FLAG_DIR_RTL;
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
MOZ_FALLTHROUGH_ASSERT("Bad GtkTextDirection");
|
|
|
|
case GTK_TEXT_DIR_NONE:
|
|
|
|
// GtkWidget uses a default direction if neither is explicitly
|
|
|
|
// specified, but here DIR_NONE is interpreted as meaning the
|
|
|
|
// direction is not important, so don't change the direction
|
|
|
|
// unnecessarily.
|
|
|
|
newState |= oldState & (STATE_FLAG_DIR_LTR|STATE_FLAG_DIR_RTL);
|
|
|
|
}
|
|
|
|
} else if (aDirection != GTK_TEXT_DIR_NONE) {
|
|
|
|
GtkTextDirection oldDirection = gtk_style_context_get_direction(style);
|
|
|
|
if (aDirection != oldDirection) {
|
|
|
|
gtk_style_context_set_direction(style, aDirection);
|
|
|
|
stateChanged = true;
|
2016-05-17 09:15:12 +03:00
|
|
|
}
|
|
|
|
}
|
2016-09-08 01:12:55 +03:00
|
|
|
if (oldState != newState) {
|
|
|
|
gtk_style_context_set_state(style, static_cast<GtkStateFlags>(newState));
|
|
|
|
stateChanged = true;
|
|
|
|
}
|
|
|
|
// This invalidate is necessary for unsaved style contexts from GtkWidgets
|
|
|
|
// in pre-3.18 GTK, because automatic invalidation of such contexts
|
|
|
|
// was delayed until a resize event runs.
|
|
|
|
//
|
|
|
|
// https://bugzilla.mozilla.org/show_bug.cgi?id=1272194#c7
|
|
|
|
//
|
2016-12-02 02:39:23 +03:00
|
|
|
// Avoid calling invalidate on contexts that are not owned and constructed
|
|
|
|
// by widgets to avoid performing build_properties() (in 3.16 stylecontext.c)
|
|
|
|
// unnecessarily early.
|
|
|
|
if (stateChanged && sWidgetStorage[aNodeType]) {
|
2016-09-08 01:12:55 +03:00
|
|
|
gtk_style_context_invalidate(style);
|
|
|
|
}
|
2016-05-09 02:08:26 +03:00
|
|
|
return style;
|
|
|
|
}
|