Quellcode-Bibliothek WidgetStyleCache.cpp
Sprache: C
/* -*- 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/. */
/* 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);
}
/* 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);
} elseif (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 staticbool 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;
}
/* Get its inner Entry and Button */
GtkInnerWidgetInfo info = {GTK_TYPE_ENTRY, &comboBoxTextarea};
gtk_container_forall(GTK_CONTAINER(GetWidget(MOZ_GTK_COMBOBOX_ENTRY)),
GetInnerWidget, &info);
/* 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);
/* 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);
} elseif (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);
}
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;
// Headerbar has to be placed to window with csd or solid-csd style // to properly draw the decorated.
gtk_style_context_add_class(windowStyle,
IsSolidCSDStyleUsed() ? "solid-csd" : "csd");
// Emulate what create_titlebar() at gtkwindow.c does.
GtkStyleContext* headerBarStyle = gtk_widget_get_style_context(headerBar);
gtk_style_context_add_class(headerBarStyle, "titlebar");
// 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)
gtk_style_context_add_class(headerBarStyle, "default-decoration");
sWidgetStorage[aAppearance] = headerBar; if (aAppearance == MOZ_GTK_HEADER_BAR_MAXIMIZED) {
MOZ_ASSERT(!sWidgetStorage[MOZ_GTK_HEADERBAR_WINDOW_MAXIMIZED], "Window widget is already created!");
MOZ_ASSERT(!sWidgetStorage[MOZ_GTK_HEADERBAR_FIXED_MAXIMIZED], "Fixed widget is already created!");
// Some themes like Elementary's style the container of the headerbar rather // than the header bar itself. bool& shouldDrawContainer = aAppearance == MOZ_GTK_HEADER_BAR
? gHeaderBarShouldDrawContainer
: gMaximizedHeaderBarShouldDrawContainer;
shouldDrawContainer = [&] { constbool headerBarHasBackground = HasBackground(headerBarStyle); if (headerBarHasBackground && GetBorderRadius(headerBarStyle)) { returnfalse;
} if (HasBackground(fixedStyle) &&
(GetBorderRadius(fixedStyle) || !headerBarHasBackground)) { returntrue;
} returnfalse;
}();
}
/* Those are available since Gtk+ 3.10 as well as GtkHeaderBar */ for (int scale = 1; scale < ICON_SCALE_VARIANTS + 1; scale++) {
GtkIconInfo* gtkIconInfo = gtk_icon_theme_lookup_icon_for_scale(
gtk_icon_theme_get_default(), iconName, iconWidth, scale,
(GtkIconLookupFlags)0);
if (!gtkIconInfo) { // We miss the icon, nothing to do here. return;
}
// We have to add button to widget hierarchy now to pick // right icon style at LoadWidgetIconPixbuf(). if (GTK_IS_BOX(aParentWidget)) {
gtk_box_pack_start(GTK_BOX(aParentWidget), widget, FALSE, FALSE, 0);
} else {
gtk_container_add(GTK_CONTAINER(aParentWidget), widget);
}
// We bypass GetWidget() here because we create all titlebar // buttons at once when a first one is requested.
NS_ASSERTION(!sWidgetStorage[aAppearance], "Titlebar button is already created!");
sWidgetStorage[aAppearance] = widget;
// We need to show the button widget now as GtkBox does not // place invisible widgets and we'll miss first-child/last-child // css selectors at the buttons otherwise.
gtk_widget_show(widget);
// We bypass GetWidget() here by explicit sWidgetStorage[] update so // invalidate the style as well as GetWidget() does.
style = gtk_widget_get_style_context(image);
gtk_style_context_invalidate(style);
LoadWidgetIconPixbuf(image);
}
staticbool IsToolbarButtonEnabled(ButtonLayout* aButtonLayout,
size_t aButtonNums,
WidgetNodeType aAppearance) { for (size_t i = 0; i < aButtonNums; i++) { if (aButtonLayout[i].mType == aAppearance) { returntrue;
}
} returnfalse;
}
GtkWidget* buttonBox = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 0);
gtk_container_add(GTK_CONTAINER(headerBar), buttonBox); // We support only LTR headerbar layout for now.
gtk_style_context_add_class(gtk_widget_get_style_context(buttonBox),
GTK_STYLE_CLASS_LEFT);
if (IsToolbarButtonEnabled(buttonLayout, activeButtons,
MOZ_GTK_HEADER_BAR_BUTTON_MINIMIZE)) {
CreateHeaderBarButton(buttonBox, MOZ_GTK_HEADER_BAR_BUTTON_MINIMIZE);
} if (IsToolbarButtonEnabled(buttonLayout, activeButtons,
MOZ_GTK_HEADER_BAR_BUTTON_MAXIMIZE)) {
CreateHeaderBarButton(buttonBox, MOZ_GTK_HEADER_BAR_BUTTON_MAXIMIZE); // We don't pack "restore" headerbar button to box as it's an icon // placeholder. Pack it only to header bar to get correct style.
CreateHeaderBarButton(GetWidget(MOZ_GTK_HEADER_BAR_MAXIMIZED),
MOZ_GTK_HEADER_BAR_BUTTON_MAXIMIZE_RESTORE);
} if (IsToolbarButtonEnabled(buttonLayout, activeButtons,
MOZ_GTK_HEADER_BAR_BUTTON_CLOSE)) {
CreateHeaderBarButton(buttonBox, MOZ_GTK_HEADER_BAR_BUTTON_CLOSE);
}
}
static GtkWidget* CreateWidget(WidgetNodeType aAppearance) { switch (aAppearance) { case MOZ_GTK_WINDOW: return CreateWindowWidget(); case MOZ_GTK_WINDOW_CONTAINER: return CreateWindowContainerWidget(); case MOZ_GTK_CHECKBUTTON_CONTAINER: return CreateCheckboxWidget(); case MOZ_GTK_PROGRESSBAR: return CreateProgressWidget(); case MOZ_GTK_RADIOBUTTON_CONTAINER: return CreateRadiobuttonWidget(); case MOZ_GTK_SCROLLBAR_VERTICAL: return CreateScrollbarWidget(aAppearance, GTK_ORIENTATION_VERTICAL); case MOZ_GTK_MENUPOPUP: return CreateMenuPopupWidget(); case MOZ_GTK_MENUBAR: return CreateMenuBarWidget(); case MOZ_GTK_EXPANDER: return CreateExpanderWidget(); case MOZ_GTK_FRAME: return CreateFrameWidget(); 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: case MOZ_GTK_DROPDOWN_ENTRY: return CreateEntryWidget(); case MOZ_GTK_SCROLLED_WINDOW: return CreateScrolledWindowWidget(); case MOZ_GTK_TREEVIEW: return CreateTreeViewWidget(); case MOZ_GTK_TREE_HEADER_CELL: return CreateTreeHeaderCellWidget(); case MOZ_GTK_SPLITTER_HORIZONTAL: return CreateHPanedWidget(); case MOZ_GTK_SPLITTER_VERTICAL: return CreateVPanedWidget(); case MOZ_GTK_SCALE_HORIZONTAL: return CreateScaleWidget(GTK_ORIENTATION_HORIZONTAL); case MOZ_GTK_SCALE_VERTICAL: return CreateScaleWidget(GTK_ORIENTATION_VERTICAL); case MOZ_GTK_NOTEBOOK: return CreateNotebookWidget(); 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(); case MOZ_GTK_HEADERBAR_WINDOW: case MOZ_GTK_HEADERBAR_WINDOW_MAXIMIZED: case MOZ_GTK_HEADERBAR_FIXED: case MOZ_GTK_HEADERBAR_FIXED_MAXIMIZED: case MOZ_GTK_HEADER_BAR: case MOZ_GTK_HEADER_BAR_MAXIMIZED: case MOZ_GTK_HEADER_BAR_BUTTON_CLOSE: case MOZ_GTK_HEADER_BAR_BUTTON_MINIMIZE: case MOZ_GTK_HEADER_BAR_BUTTON_MAXIMIZE: case MOZ_GTK_HEADER_BAR_BUTTON_MAXIMIZE_RESTORE: /* Create header bar widgets once and fill with child elements as we need
the header bar fully configured to get a correct style */
CreateHeaderBar(); return sWidgetStorage[aAppearance]; default: /* Not implemented */ return nullptr;
}
}
GtkWidget* GetWidget(WidgetNodeType aAppearance) {
GtkWidget* widget = sWidgetStorage[aAppearance]; if (!widget) {
widget = CreateWidget(aAppearance); // Some widgets (MOZ_GTK_COMBOBOX_SEPARATOR for instance) may not be // available or implemented. if (!widget) { return nullptr;
} // 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);
// 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);
AddStyleClassesFromStyle(context, widgetStyle);
// Release any floating reference on aWidget.
g_object_ref_sink(aWidget);
g_object_unref(aWidget);
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();
}
gtk_widget_path_append_type(path, aType);
if (sGtkWidgetPathIterSetObjectName) {
(*sGtkWidgetPathIterSetObjectName)(path, -1, aName);
}
// 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);
}
return context;
}
// 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_MENUITEM:
style = CreateStyleForWidget(gtk_menu_item_new(), MOZ_GTK_MENUPOPUP); break; case MOZ_GTK_MENUBARITEM:
style = CreateStyleForWidget(gtk_menu_item_new(), MOZ_GTK_MENUBAR); break; case MOZ_GTK_TEXT_VIEW:
style =
CreateStyleForWidget(gtk_text_view_new(), MOZ_GTK_SCROLLED_WINDOW); break; 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; default:
GtkWidget* widget = GetWidget(aNodeType);
MOZ_ASSERT(widget); return gtk_widget_get_style_context(widget);
}
// Create a style context equivalent to a saved root style context of // |aAppearance| 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. static GtkStyleContext* CreateSubStyleWithClass(WidgetNodeType aAppearance, const gchar* aStyleClass) { staticauto sGtkWidgetPathIterGetObjectName = reinterpret_cast<constchar* (*)(const GtkWidgetPath*, gint)>(
dlsym(RTLD_DEFAULT, "gtk_widget_path_iter_get_object_name"));
// 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);
// 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);
/* GetCssNodeStyleInternal is used by Gtk >= 3.20 */ static GtkStyleContext* GetCssNodeStyleInternal(WidgetNodeType aNodeType) {
GtkStyleContext* style = sStyleStorage[aNodeType]; if (style) return style;
switch (aNodeType) { case MOZ_GTK_SCROLLBAR_CONTENTS_VERTICAL:
style = CreateChildCSSNode("contents", MOZ_GTK_SCROLLBAR_VERTICAL); break; case MOZ_GTK_SCROLLBAR_TROUGH_VERTICAL:
style = CreateChildCSSNode(GTK_STYLE_CLASS_TROUGH,
MOZ_GTK_SCROLLBAR_CONTENTS_VERTICAL); break; case MOZ_GTK_SCROLLBAR_THUMB_VERTICAL:
style = CreateChildCSSNode(GTK_STYLE_CLASS_SLIDER,
MOZ_GTK_SCROLLBAR_TROUGH_VERTICAL); break; case MOZ_GTK_RADIOBUTTON:
style = CreateChildCSSNode(GTK_STYLE_CLASS_RADIO,
MOZ_GTK_RADIOBUTTON_CONTAINER); break; case MOZ_GTK_CHECKBUTTON:
style = CreateChildCSSNode(GTK_STYLE_CLASS_CHECK,
MOZ_GTK_CHECKBUTTON_CONTAINER); break; case MOZ_GTK_PROGRESS_TROUGH: /* Progress bar background (trough) */
style = CreateChildCSSNode(GTK_STYLE_CLASS_TROUGH, MOZ_GTK_PROGRESSBAR); break; case MOZ_GTK_PROGRESS_CHUNK:
style = CreateChildCSSNode("progress", MOZ_GTK_PROGRESS_TROUGH); break; case MOZ_GTK_SPINBUTTON_ENTRY: // TODO - create from CSS node
style =
CreateSubStyleWithClass(MOZ_GTK_SPINBUTTON, GTK_STYLE_CLASS_ENTRY); break; case MOZ_GTK_SCROLLED_WINDOW: // TODO - create from CSS node
style = CreateSubStyleWithClass(MOZ_GTK_SCROLLED_WINDOW,
GTK_STYLE_CLASS_FRAME); break; case MOZ_GTK_TEXT_VIEW_TEXT_SELECTION:
style = CreateChildCSSNode("selection", MOZ_GTK_TEXT_VIEW_TEXT); break; case MOZ_GTK_TEXT_VIEW_TEXT: case MOZ_GTK_RESIZER:
style = CreateChildCSSNode("text", MOZ_GTK_TEXT_VIEW); 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 what is used in GtkTextView to match the background with // textarea elements.
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);
}
gtk_style_context_add_class(style, GTK_STYLE_CLASS_GRIP);
} break; case MOZ_GTK_FRAME_BORDER:
style = CreateChildCSSNode("border", MOZ_GTK_FRAME); break; case MOZ_GTK_TREEVIEW_VIEW: // TODO - create from CSS node
style = CreateSubStyleWithClass(MOZ_GTK_TREEVIEW, GTK_STYLE_CLASS_VIEW); break; 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; 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); break; case MOZ_GTK_SCALE_TROUGH_HORIZONTAL:
style = CreateChildCSSNode(GTK_STYLE_CLASS_TROUGH,
MOZ_GTK_SCALE_CONTENTS_HORIZONTAL); break; 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; case MOZ_GTK_TAB_TOP: { // TODO - create from CSS node
style = CreateSubStyleWithClass(MOZ_GTK_NOTEBOOK, GTK_STYLE_CLASS_TOP);
gtk_style_context_add_region(style, GTK_STYLE_REGION_TAB, static_cast<GtkRegionFlags>(0)); break;
} case MOZ_GTK_TAB_BOTTOM: { // TODO - create from CSS node
style = CreateSubStyleWithClass(MOZ_GTK_NOTEBOOK, GTK_STYLE_CLASS_BOTTOM);
gtk_style_context_add_region(style, GTK_STYLE_REGION_TAB, static_cast<GtkRegionFlags>(0)); break;
} case MOZ_GTK_NOTEBOOK: case MOZ_GTK_NOTEBOOK_HEADER: case MOZ_GTK_TABPANELS: case MOZ_GTK_TAB_SCROLLARROW: { // TODO - create from CSS node
GtkWidget* widget = GetWidget(MOZ_GTK_NOTEBOOK); return gtk_widget_get_style_context(widget);
} case MOZ_GTK_WINDOW_DECORATION: {
GtkStyleContext* parentStyle =
CreateSubStyleWithClass(MOZ_GTK_WINDOW, "csd");
style = CreateCSSNode("decoration", parentStyle);
g_object_unref(parentStyle); break;
} case MOZ_GTK_WINDOW_DECORATION_SOLID: {
GtkStyleContext* parentStyle =
CreateSubStyleWithClass(MOZ_GTK_WINDOW, "solid-csd");
style = CreateCSSNode("decoration", parentStyle);
g_object_unref(parentStyle); break;
} default: return GetWidgetRootStyle(aNodeType);
}
/* GetWidgetStyleInternal is used by Gtk < 3.20 */ static GtkStyleContext* GetWidgetStyleInternal(WidgetNodeType aNodeType) {
GtkStyleContext* style = sStyleStorage[aNodeType]; if (style) return style;
switch (aNodeType) { case MOZ_GTK_SCROLLBAR_TROUGH_VERTICAL:
style = CreateSubStyleWithClass(MOZ_GTK_SCROLLBAR_VERTICAL,
GTK_STYLE_CLASS_TROUGH); break; case MOZ_GTK_SCROLLBAR_THUMB_VERTICAL:
style = CreateSubStyleWithClass(MOZ_GTK_SCROLLBAR_VERTICAL,
GTK_STYLE_CLASS_SLIDER); break; case MOZ_GTK_RADIOBUTTON:
style = CreateSubStyleWithClass(MOZ_GTK_RADIOBUTTON_CONTAINER,
GTK_STYLE_CLASS_RADIO); break; case MOZ_GTK_CHECKBUTTON:
style = CreateSubStyleWithClass(MOZ_GTK_CHECKBUTTON_CONTAINER,
GTK_STYLE_CLASS_CHECK); break; case MOZ_GTK_PROGRESS_TROUGH:
style =
CreateSubStyleWithClass(MOZ_GTK_PROGRESSBAR, GTK_STYLE_CLASS_TROUGH); break; case MOZ_GTK_PROGRESS_CHUNK:
style = CreateSubStyleWithClass(MOZ_GTK_PROGRESSBAR,
GTK_STYLE_CLASS_PROGRESSBAR);
gtk_style_context_remove_class(style, GTK_STYLE_CLASS_TROUGH); break; case MOZ_GTK_SPINBUTTON_ENTRY:
style =
CreateSubStyleWithClass(MOZ_GTK_SPINBUTTON, GTK_STYLE_CLASS_ENTRY); break; case MOZ_GTK_SCROLLED_WINDOW:
style = CreateSubStyleWithClass(MOZ_GTK_SCROLLED_WINDOW,
GTK_STYLE_CLASS_FRAME); break; case MOZ_GTK_TEXT_VIEW_TEXT: case MOZ_GTK_RESIZER: // 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.
style = CreateSubStyleWithClass(MOZ_GTK_TEXT_VIEW, GTK_STYLE_CLASS_VIEW); 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);
} break; case MOZ_GTK_FRAME_BORDER: return GetWidgetRootStyle(MOZ_GTK_FRAME); case MOZ_GTK_TREEVIEW_VIEW:
style = CreateSubStyleWithClass(MOZ_GTK_TREEVIEW, GTK_STYLE_CLASS_VIEW); break; case MOZ_GTK_SPLITTER_SEPARATOR_HORIZONTAL:
style = CreateSubStyleWithClass(MOZ_GTK_SPLITTER_HORIZONTAL,
GTK_STYLE_CLASS_PANE_SEPARATOR); break; case MOZ_GTK_SPLITTER_SEPARATOR_VERTICAL:
style = CreateSubStyleWithClass(MOZ_GTK_SPLITTER_VERTICAL,
GTK_STYLE_CLASS_PANE_SEPARATOR); break; case MOZ_GTK_SCALE_TROUGH_HORIZONTAL:
style = CreateSubStyleWithClass(MOZ_GTK_SCALE_HORIZONTAL,
GTK_STYLE_CLASS_TROUGH); break; case MOZ_GTK_SCALE_TROUGH_VERTICAL:
style = CreateSubStyleWithClass(MOZ_GTK_SCALE_VERTICAL,
GTK_STYLE_CLASS_TROUGH); break; case MOZ_GTK_SCALE_THUMB_HORIZONTAL:
style = CreateSubStyleWithClass(MOZ_GTK_SCALE_HORIZONTAL,
GTK_STYLE_CLASS_SLIDER); break; case MOZ_GTK_SCALE_THUMB_VERTICAL:
style = CreateSubStyleWithClass(MOZ_GTK_SCALE_VERTICAL,
GTK_STYLE_CLASS_SLIDER); break; case MOZ_GTK_TAB_TOP:
style = CreateSubStyleWithClass(MOZ_GTK_NOTEBOOK, GTK_STYLE_CLASS_TOP);
gtk_style_context_add_region(style, GTK_STYLE_REGION_TAB, static_cast<GtkRegionFlags>(0)); break; case MOZ_GTK_TAB_BOTTOM:
style = CreateSubStyleWithClass(MOZ_GTK_NOTEBOOK, GTK_STYLE_CLASS_BOTTOM);
gtk_style_context_add_region(style, GTK_STYLE_REGION_TAB, static_cast<GtkRegionFlags>(0)); break; case MOZ_GTK_NOTEBOOK: case MOZ_GTK_NOTEBOOK_HEADER: case MOZ_GTK_TABPANELS: case MOZ_GTK_TAB_SCROLLARROW: {
GtkWidget* widget = GetWidget(MOZ_GTK_NOTEBOOK); return gtk_widget_get_style_context(widget);
} default: return GetWidgetRootStyle(aNodeType);
}
void ResetWidgetCache() { for (int i = 0; i < MOZ_GTK_WIDGET_NODE_COUNT; i++) { if (sStyleStorage[i]) g_object_unref(sStyleStorage[i]);
}
mozilla::PodArrayZero(sStyleStorage);
gCSDStyle = CSDStyle::Unknown;
/* This will destroy all of our widgets */ if (sWidgetStorage[MOZ_GTK_WINDOW]) {
gtk_widget_destroy(sWidgetStorage[MOZ_GTK_WINDOW]);
} if (sWidgetStorage[MOZ_GTK_HEADERBAR_WINDOW]) {
gtk_widget_destroy(sWidgetStorage[MOZ_GTK_HEADERBAR_WINDOW]);
} if (sWidgetStorage[MOZ_GTK_HEADERBAR_WINDOW_MAXIMIZED]) {
gtk_widget_destroy(sWidgetStorage[MOZ_GTK_HEADERBAR_WINDOW_MAXIMIZED]);
}
GtkStyleContext* GetStyleContext(WidgetNodeType aNodeType, int aScale,
GtkTextDirection aDirection,
GtkStateFlags aStateFlags) {
GtkStyleContext* style; if (gtk_check_version(3, 20, 0) != nullptr) {
style = GetWidgetStyleInternal(aNodeType);
} else {
style = GetCssNodeStyleInternal(aNodeType);
StyleContextSetScale(style, aScale);
} bool stateChanged = false; bool stateHasDirection = gtk_get_minor_version() >= 8;
GtkStateFlags oldState = gtk_style_context_get_state(style);
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);
}
} elseif (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;
}
} 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 // // 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]) {
gtk_style_context_invalidate(style);
} return style;
}
int pathLength = gtk_widget_path_length(path); for (int i = 0; i < pathLength; i++) { unsigned state = aStateFlags | sGtkWidgetPathIterGetState(path, i);
sGtkWidgetPathIterSetState(path, i, GtkStateFlags(state));
}
gint GetBorderRadius(GtkStyleContext* aStyle) {
GValue value = G_VALUE_INIT; // NOTE(emilio): In an ideal world, we'd query the two longhands // (border-top-left-radius and border-top-right-radius) separately. However, // that doesn't work (GTK rejects the query with: // // Style property "border-top-left-radius" is not gettable // // However! Getting border-radius does work, and it does return the // border-top-left-radius as a gint: // // https://docs.gtk.org/gtk3/const.STYLE_PROPERTY_BORDER_RADIUS.html // https://gitlab.gnome.org/GNOME/gtk/-/blob/gtk-3-20/gtk/gtkcssshorthandpropertyimpl.c#L961-977 // // So we abuse this fact, and make the assumption here that the // border-top-{left,right}-radius are the same, and roll with it.
gtk_style_context_get_property(aStyle, "border-radius", GTK_STATE_FLAG_NORMAL,
&value);
gint result = 0; auto type = G_VALUE_TYPE(&value); if (type == G_TYPE_INT) {
result = g_value_get_int(&value);
} else {
NS_WARNING(nsPrintfCString("Unknown value type %lu for border-radius", type)
.get());
}
g_value_unset(&value); return result;
}
¤ Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.0.52Bemerkung:
(vorverarbeitet)
¤
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung ist noch experimentell.