diff options
author | The Android Open Source Project <initial-contribution@android.com> | 2008-12-17 18:05:15 -0800 |
---|---|---|
committer | The Android Open Source Project <initial-contribution@android.com> | 2008-12-17 18:05:15 -0800 |
commit | 1cbdecfa9fc428ac2d8aca0fa91c9580b3d57353 (patch) | |
tree | 4457a7306ea5acb43fe05bfe0973b1f7faf97ba2 /WebCore/platform/gtk/gtk2drawing.c | |
parent | 9364f22aed35e1a1e9d07c121510f80be3ab0502 (diff) | |
download | external_webkit-1cbdecfa9fc428ac2d8aca0fa91c9580b3d57353.zip external_webkit-1cbdecfa9fc428ac2d8aca0fa91c9580b3d57353.tar.gz external_webkit-1cbdecfa9fc428ac2d8aca0fa91c9580b3d57353.tar.bz2 |
Code drop from //branches/cupcake/...@124589
Diffstat (limited to 'WebCore/platform/gtk/gtk2drawing.c')
-rw-r--r-- | WebCore/platform/gtk/gtk2drawing.c | 1176 |
1 files changed, 836 insertions, 340 deletions
diff --git a/WebCore/platform/gtk/gtk2drawing.c b/WebCore/platform/gtk/gtk2drawing.c index 475e9fd..83b4cb4 100644 --- a/WebCore/platform/gtk/gtk2drawing.c +++ b/WebCore/platform/gtk/gtk2drawing.c @@ -23,6 +23,7 @@ * Brian Ryner <bryner@brianryner.com> (Original Author) * Pierre Chanial <p_ch@verizon.net> * Michael Ventnor <m.ventnor@gmail.com> + * Alp Toker <alp@nuanti.com> * * Alternatively, the contents of this file may be used under the terms of * either the GNU General Public License Version 2 or later (the "GPL"), or @@ -57,6 +58,7 @@ static GtkWidget* gProtoWindow; static GtkWidget* gButtonWidget; static GtkWidget* gToggleButtonWidget; +static GtkWidget* gButtonArrowWidget; static GtkWidget* gCheckboxWidget; static GtkWidget* gRadiobuttonWidget; static GtkWidget* gHorizScrollbarWidget; @@ -65,11 +67,14 @@ static GtkWidget* gSpinWidget; static GtkWidget* gHScaleWidget; static GtkWidget* gVScaleWidget; static GtkWidget* gEntryWidget; -static GtkWidget* gArrowWidget; -static GtkWidget* gOptionMenuWidget; +static GtkWidget* gComboBoxWidget; +static GtkWidget* gComboBoxButtonWidget; +static GtkWidget* gComboBoxArrowWidget; +static GtkWidget* gComboBoxSeparatorWidget; static GtkWidget* gComboBoxEntryWidget; -static GtkWidget* gDropdownEntryWidget; -static GtkWidget* gDropdownButtonWidget; +static GtkWidget* gComboBoxEntryTextareaWidget; +static GtkWidget* gComboBoxEntryButtonWidget; +static GtkWidget* gComboBoxEntryArrowWidget; static GtkWidget* gHandleBoxWidget; static GtkWidget* gToolbarWidget; static GtkWidget* gFrameWidget; @@ -81,8 +86,10 @@ static GtkWidget* gMenuBarWidget; static GtkWidget* gMenuBarItemWidget; static GtkWidget* gMenuPopupWidget; static GtkWidget* gMenuItemWidget; +static GtkWidget* gImageMenuItemWidget; static GtkWidget* gCheckMenuItemWidget; static GtkWidget* gTreeViewWidget; +static GtkWidget* gMiddleTreeViewColumn; static GtkWidget* gTreeHeaderCellWidget; static GtkWidget* gTreeHeaderSortArrowWidget; static GtkWidget* gExpanderWidget; @@ -90,14 +97,22 @@ static GtkWidget* gToolbarSeparatorWidget; static GtkWidget* gMenuSeparatorWidget; static GtkWidget* gHPanedWidget; static GtkWidget* gVPanedWidget; - -static GtkShadowType gMenuBarShadowType; -static GtkShadowType gToolbarShadowType; +static GtkWidget* gScrolledWindowWidget; static style_prop_t style_prop_func; -static gboolean have_menu_shadow_type; +static gboolean have_arrow_scaling; +static gboolean have_2_10; static gboolean is_initialized; +/* Because we have such an unconventional way of drawing widgets, signal to the GTK theme engine + that they are drawing for Mozilla instead of a conventional GTK app so they can do any specific + things they may want to do. */ +static void +moz_gtk_set_widget_name(GtkWidget* widget) +{ + gtk_widget_set_name(widget, "MozillaGtkWidget"); +} + gint moz_gtk_enable_style_props(style_prop_t styleGetProp) { @@ -111,6 +126,7 @@ ensure_window_widget() if (!gProtoWindow) { gProtoWindow = gtk_window_new(GTK_WINDOW_POPUP); gtk_widget_realize(gProtoWindow); + moz_gtk_set_widget_name(gProtoWindow); } return MOZ_GTK_SUCCESS; } @@ -127,6 +143,7 @@ setup_widget_prototype(GtkWidget* widget) gtk_container_add(GTK_CONTAINER(protoLayout), widget); gtk_widget_realize(widget); + g_object_set_data(G_OBJECT(widget), "transparent-bg-hint", TRUE); return MOZ_GTK_SUCCESS; } @@ -173,6 +190,19 @@ ensure_toggle_button_widget() } static gint +ensure_button_arrow_widget() +{ + if (!gButtonArrowWidget) { + ensure_toggle_button_widget(); + + gButtonArrowWidget = gtk_arrow_new(GTK_ARROW_DOWN, GTK_SHADOW_OUT); + gtk_container_add(GTK_CONTAINER(gToggleButtonWidget), gButtonArrowWidget); + gtk_widget_realize(gButtonArrowWidget); + } + return MOZ_GTK_SUCCESS; +} + +static gint ensure_checkbox_widget() { if (!gCheckboxWidget) { @@ -240,64 +270,219 @@ ensure_entry_widget() return MOZ_GTK_SUCCESS; } -static gint -ensure_option_menu_widget() -{ - if (!gOptionMenuWidget) { - gOptionMenuWidget = gtk_option_menu_new(); - setup_widget_prototype(gOptionMenuWidget); +/* 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 gProtoWindow and as + * such GTK holds a strong reference to them. */ +static void +moz_gtk_get_combo_box_inner_button(GtkWidget *widget, gpointer client_data) +{ + if (GTK_IS_TOGGLE_BUTTON(widget)) { + gComboBoxButtonWidget = widget; + g_object_add_weak_pointer(G_OBJECT(widget), + (gpointer) &gComboBoxButtonWidget); + gtk_widget_realize(widget); + g_object_set_data(G_OBJECT(widget), "transparent-bg-hint", TRUE); } - return MOZ_GTK_SUCCESS; } -static gint -ensure_combo_box_entry_widget() -{ - if (!gComboBoxEntryWidget) { - gComboBoxEntryWidget = gtk_combo_box_entry_new(); - setup_widget_prototype(gComboBoxEntryWidget); - } - return MOZ_GTK_SUCCESS; +static void +moz_gtk_get_combo_box_button_inner_widgets(GtkWidget *widget, + gpointer client_data) +{ + if (GTK_IS_SEPARATOR(widget)) { + gComboBoxSeparatorWidget = widget; + g_object_add_weak_pointer(G_OBJECT(widget), + (gpointer) &gComboBoxSeparatorWidget); + } else if (GTK_IS_ARROW(widget)) { + gComboBoxArrowWidget = widget; + g_object_add_weak_pointer(G_OBJECT(widget), + (gpointer) &gComboBoxArrowWidget); + } else + return; + gtk_widget_realize(widget); + g_object_set_data(G_OBJECT(widget), "transparent-bg-hint", TRUE); } static gint -ensure_dropdown_entry_widget() +ensure_combo_box_widgets() { - if (!gDropdownEntryWidget) { - ensure_combo_box_entry_widget(); + GtkWidget* buttonChild; + + if (gComboBoxButtonWidget && gComboBoxArrowWidget) + return MOZ_GTK_SUCCESS; + + /* Create a ComboBox if needed */ + if (!gComboBoxWidget) { + gComboBoxWidget = gtk_combo_box_new(); + setup_widget_prototype(gComboBoxWidget); + } + + /* Get its inner Button */ + gtk_container_forall(GTK_CONTAINER(gComboBoxWidget), + moz_gtk_get_combo_box_inner_button, + NULL); + + if (gComboBoxButtonWidget) { + /* Get the widgets inside the Button */ + buttonChild = GTK_BIN(gComboBoxButtonWidget)->child; + if (GTK_IS_HBOX(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. */ + gtk_container_forall(GTK_CONTAINER(buttonChild), + moz_gtk_get_combo_box_button_inner_widgets, + NULL); + } else if(GTK_IS_ARROW(buttonChild)) { + /* appears-as-list = TRUE, or cell-view = FALSE; + * the button only contains an arrow */ + gComboBoxArrowWidget = buttonChild; + g_object_add_weak_pointer(G_OBJECT(buttonChild), (gpointer) + &gComboBoxArrowWidget); + gtk_widget_realize(gComboBoxArrowWidget); + g_object_set_data(G_OBJECT(gComboBoxArrowWidget), + "transparent-bg-hint", TRUE); + } + } else { + /* Shouldn't be reached with current internal gtk implementation; we + * use a generic toggle button as last resort fallback to avoid + * crashing. */ + ensure_toggle_button_widget(); + gComboBoxButtonWidget = gToggleButtonWidget; + } - gDropdownEntryWidget = GTK_BIN(gComboBoxEntryWidget)->child; - gtk_widget_realize(gDropdownEntryWidget); + if (!gComboBoxArrowWidget) { + /* Shouldn't be reached with current internal gtk implementation; + * we gButtonArrowWidget as last resort fallback to avoid + * crashing. */ + ensure_button_arrow_widget(); + gComboBoxArrowWidget = gButtonArrowWidget; } + + /* We don't test the validity of gComboBoxSeparatorWidget since there + * is none when "appears-as-list" = TRUE or "cell-view" = FALSE; if it + * is invalid we just won't paint it. */ + return MOZ_GTK_SUCCESS; } +/* We need to have pointers to the inner widgets (entry, button, arrow) of + * the ComboBoxEntry 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 gProtoWindow and as + * such GTK holds a strong reference to them. */ static void -moz_gtk_get_dropdown_button(GtkWidget *widget, - gpointer client_data) -{ - if (GTK_IS_TOGGLE_BUTTON(widget)) - gDropdownButtonWidget = widget; +moz_gtk_get_combo_box_entry_inner_widgets(GtkWidget *widget, + gpointer client_data) +{ + if (GTK_IS_TOGGLE_BUTTON(widget)) { + gComboBoxEntryButtonWidget = widget; + g_object_add_weak_pointer(G_OBJECT(widget), + (gpointer) &gComboBoxEntryButtonWidget); + } else if (GTK_IS_ENTRY(widget)) { + gComboBoxEntryTextareaWidget = widget; + g_object_add_weak_pointer(G_OBJECT(widget), + (gpointer) &gComboBoxEntryTextareaWidget); + } else + return; + gtk_widget_realize(widget); + g_object_set_data(G_OBJECT(widget), "transparent-bg-hint", TRUE); +} + +static void +moz_gtk_get_combo_box_entry_arrow(GtkWidget *widget, gpointer client_data) +{ + if (GTK_IS_ARROW(widget)) { + gComboBoxEntryArrowWidget = widget; + g_object_add_weak_pointer(G_OBJECT(widget), + (gpointer) &gComboBoxEntryArrowWidget); + gtk_widget_realize(widget); + g_object_set_data(G_OBJECT(widget), "transparent-bg-hint", TRUE); + } } static gint -ensure_arrow_widget() +ensure_combo_box_entry_widgets() { - if (!gArrowWidget) { - ensure_combo_box_entry_widget(); + GtkWidget* buttonChild; - gtk_container_forall(GTK_CONTAINER(gComboBoxEntryWidget), - moz_gtk_get_dropdown_button, - NULL); + if (gComboBoxEntryTextareaWidget && + gComboBoxEntryButtonWidget && + gComboBoxEntryArrowWidget) + return MOZ_GTK_SUCCESS; + + /* Create a ComboBoxEntry if needed */ + if (!gComboBoxEntryWidget) { + gComboBoxEntryWidget = gtk_combo_box_entry_new(); + setup_widget_prototype(gComboBoxEntryWidget); + } - gArrowWidget = gtk_arrow_new(GTK_ARROW_DOWN, GTK_SHADOW_OUT); - gtk_container_add(GTK_CONTAINER(GTK_BIN(gDropdownButtonWidget)->child), - gArrowWidget); - gtk_widget_realize(gArrowWidget); + /* Get its inner Entry and Button */ + gtk_container_forall(GTK_CONTAINER(gComboBoxEntryWidget), + moz_gtk_get_combo_box_entry_inner_widgets, + NULL); + + if (!gComboBoxEntryTextareaWidget) { + ensure_entry_widget(); + gComboBoxEntryTextareaWidget = gEntryWidget; + } + + if (gComboBoxEntryButtonWidget) { + /* Get the Arrow inside the Button */ + buttonChild = GTK_BIN(gComboBoxEntryButtonWidget)->child; + if (GTK_IS_HBOX(buttonChild)) { + /* appears-as-list = FALSE, cell-view = TRUE; the button + * contains an hbox. This hbox is there because ComboBoxEntry + * inherits from ComboBox which needs to place a cell renderer, + * a separator, and an arrow in the button when appears-as-list + * is FALSE. Here the hbox should only contain an arrow, since + * a ComboBoxEntry doesn't need all those widgets in the + * button. */ + gtk_container_forall(GTK_CONTAINER(buttonChild), + moz_gtk_get_combo_box_entry_arrow, + NULL); + } else if(GTK_IS_ARROW(buttonChild)) { + /* appears-as-list = TRUE, or cell-view = FALSE; + * the button only contains an arrow */ + gComboBoxEntryArrowWidget = buttonChild; + g_object_add_weak_pointer(G_OBJECT(buttonChild), (gpointer) + &gComboBoxEntryArrowWidget); + gtk_widget_realize(gComboBoxEntryArrowWidget); + g_object_set_data(G_OBJECT(gComboBoxEntryArrowWidget), + "transparent-bg-hint", TRUE); + } + } else { + /* Shouldn't be reached with current internal gtk implementation; + * we use a generic toggle button as last resort fallback to avoid + * crashing. */ + ensure_toggle_button_widget(); + gComboBoxEntryButtonWidget = gToggleButtonWidget; } + + if (!gComboBoxEntryArrowWidget) { + /* Shouldn't be reached with current internal gtk implementation; + * we gButtonArrowWidget as last resort fallback to avoid + * crashing. */ + ensure_button_arrow_widget(); + gComboBoxEntryArrowWidget = gButtonArrowWidget; + } + return MOZ_GTK_SUCCESS; } + static gint ensure_handlebox_widget() { @@ -316,8 +501,7 @@ ensure_toolbar_widget() gToolbarWidget = gtk_toolbar_new(); gtk_container_add(GTK_CONTAINER(gHandleBoxWidget), gToolbarWidget); gtk_widget_realize(gToolbarWidget); - gtk_widget_style_get(gToolbarWidget, "shadow_type", &gToolbarShadowType, - NULL); + g_object_set_data(G_OBJECT(gToolbarWidget), "transparent-bg-hint", TRUE); } return MOZ_GTK_SUCCESS; } @@ -339,6 +523,7 @@ ensure_tooltip_widget() if (!gTooltipWidget) { gTooltipWidget = gtk_window_new(GTK_WINDOW_POPUP); gtk_widget_realize(gTooltipWidget); + moz_gtk_set_widget_name(gTooltipWidget); } return MOZ_GTK_SUCCESS; } @@ -391,8 +576,6 @@ ensure_menu_bar_widget() if (!gMenuBarWidget) { gMenuBarWidget = gtk_menu_bar_new(); setup_widget_prototype(gMenuBarWidget); - gtk_widget_style_get(gMenuBarWidget, "shadow_type", &gMenuBarShadowType, - NULL); } return MOZ_GTK_SUCCESS; } @@ -406,6 +589,8 @@ ensure_menu_bar_item_widget() gtk_menu_shell_append(GTK_MENU_SHELL(gMenuBarWidget), gMenuBarItemWidget); gtk_widget_realize(gMenuBarItemWidget); + g_object_set_data(G_OBJECT(gMenuBarItemWidget), + "transparent-bg-hint", TRUE); } return MOZ_GTK_SUCCESS; } @@ -419,6 +604,8 @@ ensure_menu_popup_widget() gtk_menu_item_set_submenu(GTK_MENU_ITEM(gMenuBarItemWidget), gMenuPopupWidget); gtk_widget_realize(gMenuPopupWidget); + g_object_set_data(G_OBJECT(gMenuPopupWidget), + "transparent-bg-hint", TRUE); } return MOZ_GTK_SUCCESS; } @@ -432,6 +619,23 @@ ensure_menu_item_widget() gtk_menu_shell_append(GTK_MENU_SHELL(gMenuPopupWidget), gMenuItemWidget); gtk_widget_realize(gMenuItemWidget); + g_object_set_data(G_OBJECT(gMenuItemWidget), + "transparent-bg-hint", TRUE); + } + return MOZ_GTK_SUCCESS; +} + +static gint +ensure_image_menu_item_widget() +{ + if (!gImageMenuItemWidget) { + ensure_menu_popup_widget(); + gImageMenuItemWidget = gtk_image_menu_item_new(); + gtk_menu_shell_append(GTK_MENU_SHELL(gMenuPopupWidget), + gImageMenuItemWidget); + gtk_widget_realize(gImageMenuItemWidget); + g_object_set_data(G_OBJECT(gImageMenuItemWidget), + "transparent-bg-hint", TRUE); } return MOZ_GTK_SUCCESS; } @@ -445,6 +649,8 @@ ensure_menu_separator_widget() gtk_menu_shell_append(GTK_MENU_SHELL(gMenuPopupWidget), gMenuSeparatorWidget); gtk_widget_realize(gMenuSeparatorWidget); + g_object_set_data(G_OBJECT(gMenuSeparatorWidget), + "transparent-bg-hint", TRUE); } return MOZ_GTK_SUCCESS; } @@ -458,6 +664,8 @@ ensure_check_menu_item_widget() gtk_menu_shell_append(GTK_MENU_SHELL(gMenuPopupWidget), gCheckMenuItemWidget); gtk_widget_realize(gCheckMenuItemWidget); + g_object_set_data(G_OBJECT(gCheckMenuItemWidget), + "transparent-bg-hint", TRUE); } return MOZ_GTK_SUCCESS; } @@ -476,16 +684,45 @@ static gint ensure_tree_header_cell_widget() { if(!gTreeHeaderCellWidget) { - GtkTreeViewColumn* treeViewColumn; - ensure_tree_view_widget(); + /* + * 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* lastTreeViewColumn; - treeViewColumn = gtk_tree_view_column_new(); - gtk_tree_view_column_set_title(treeViewColumn, "M"); + ensure_tree_view_widget(); - gtk_tree_view_append_column(GTK_TREE_VIEW(gTreeViewWidget), treeViewColumn); - gTreeHeaderCellWidget = treeViewColumn->button; - gtk_tree_view_column_set_sort_indicator(treeViewColumn, TRUE); - gTreeHeaderSortArrowWidget = treeViewColumn->arrow; + /* 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(gTreeViewWidget), firstTreeViewColumn); + + gMiddleTreeViewColumn = gtk_tree_view_column_new(); + gtk_tree_view_column_set_title(GTK_TREE_VIEW_COLUMN(gMiddleTreeViewColumn), "M"); + gtk_tree_view_append_column(GTK_TREE_VIEW(gTreeViewWidget), + GTK_TREE_VIEW_COLUMN(gMiddleTreeViewColumn)); + + lastTreeViewColumn = gtk_tree_view_column_new(); + gtk_tree_view_column_set_title(lastTreeViewColumn, "M"); + gtk_tree_view_append_column(GTK_TREE_VIEW(gTreeViewWidget), lastTreeViewColumn); + + /* Use the middle column's header for our button */ + gTreeHeaderCellWidget = GTK_TREE_VIEW_COLUMN(gMiddleTreeViewColumn)->button; + gTreeHeaderSortArrowWidget = GTK_TREE_VIEW_COLUMN(gMiddleTreeViewColumn)->arrow; + g_object_set_data(G_OBJECT(gTreeHeaderCellWidget), + "transparent-bg-hint", TRUE); + g_object_set_data(G_OBJECT(gTreeHeaderSortArrowWidget), + "transparent-bg-hint", TRUE); } return MOZ_GTK_SUCCESS; } @@ -500,6 +737,16 @@ ensure_expander_widget() return MOZ_GTK_SUCCESS; } +static gint +ensure_scrolled_window_widget() +{ + if (!gScrolledWindowWidget) { + gScrolledWindowWidget = gtk_scrolled_window_new(NULL, NULL); + setup_widget_prototype(gScrolledWindowWidget); + } + return MOZ_GTK_SUCCESS; +} + static GtkStateType ConvertGtkState(GtkWidgetState* state) { @@ -566,6 +813,13 @@ moz_gtk_button_paint(GdkDrawable* drawable, GdkRectangle* rect, if (state->isDefault) GTK_WIDGET_SET_FLAGS(widget, GTK_HAS_DEFAULT); + GTK_BUTTON(widget)->relief = relief; + + /* Some theme engines love to cause us pain in that gtk_paint_focus is a + no-op on buttons and button-like widgets. They only listen to this flag. */ + if (state->focused && !state->disabled) + GTK_WIDGET_SET_FLAGS(widget, GTK_HAS_FOCUS); + if (!interior_focus && state->focused) { x += focus_width + focus_pad; y += focus_width + focus_pad; @@ -576,7 +830,7 @@ moz_gtk_button_paint(GdkDrawable* drawable, GdkRectangle* rect, shadow_type = button_state == GTK_STATE_ACTIVE || state->depressed ? GTK_SHADOW_IN : GTK_SHADOW_OUT; - if (state->isDefault && GTK_BUTTON(widget)->relief == GTK_RELIEF_NORMAL) { + if (state->isDefault && relief == GTK_RELIEF_NORMAL) { gtk_paint_box(style, drawable, button_state, shadow_type, cliprect, widget, "buttondefault", x, y, width, height); } @@ -611,16 +865,32 @@ moz_gtk_button_paint(GdkDrawable* drawable, GdkRectangle* rect, } GTK_WIDGET_UNSET_FLAGS(widget, GTK_HAS_DEFAULT); + GTK_WIDGET_UNSET_FLAGS(widget, GTK_HAS_FOCUS); return MOZ_GTK_SUCCESS; } gint moz_gtk_init() { + GtkWidgetClass *entry_class; + is_initialized = TRUE; - have_menu_shadow_type = - (gtk_major_version > 2 || - (gtk_major_version == 2 && gtk_minor_version >= 1)); + have_arrow_scaling = (gtk_major_version > 2 || + (gtk_major_version == 2 && gtk_minor_version >= 12)); + + have_2_10 = (gtk_major_version > 2 || + (gtk_major_version == 2 && gtk_minor_version >= 10)); + + /* Add style property to GtkEntry. + * Adding the style property to the normal GtkEntry class means that it + * will work without issues inside GtkComboBox and for Spinbuttons. */ + entry_class = g_type_class_ref(GTK_TYPE_ENTRY); + gtk_widget_class_install_style_property(entry_class, + g_param_spec_boolean("honors-transparent-bg-hint", + "Transparent BG enabling flag", + "If TRUE, the theme is able to draw the GtkEntry on non-prefilled background.", + FALSE, + G_PARAM_READWRITE)); return MOZ_GTK_SUCCESS; } @@ -664,45 +934,6 @@ moz_gtk_widget_get_focus(GtkWidget* widget, gboolean* interior_focus, return MOZ_GTK_SUCCESS; } -static gint -moz_gtk_option_menu_get_metrics(gboolean* interior_focus, - GtkRequisition* indicator_size, - GtkBorder* indicator_spacing, - gint* focus_width, - gint* focus_pad) -{ - static const GtkRequisition default_indicator_size = { 7, 13 }; - static const GtkBorder default_indicator_spacing = { 7, 5, 2, 2 }; - /* these default values are not used in gtkoptionmenu.c - static const gboolean default_interior_focus = TRUE; - static const gint default_focus_width = 1; - static const gint default_focus_pad = 0; */ - GtkRequisition *tmp_indicator_size; - GtkBorder *tmp_indicator_spacing; - - gtk_widget_style_get(gOptionMenuWidget, - "interior_focus", interior_focus, - "indicator_size", &tmp_indicator_size, - "indicator_spacing", &tmp_indicator_spacing, - "focus_line_width", focus_width, - "focus_padding", focus_pad, - NULL); - - if (tmp_indicator_size) - *indicator_size = *tmp_indicator_size; - else - *indicator_size = default_indicator_size; - if (tmp_indicator_spacing) - *indicator_spacing = *tmp_indicator_spacing; - else - *indicator_spacing = default_indicator_spacing; - - gtk_requisition_free(tmp_indicator_size); - gtk_border_free(tmp_indicator_spacing); - - return MOZ_GTK_SUCCESS; -} - gint moz_gtk_splitter_get_metrics(gint orientation, gint* size) { @@ -716,6 +947,25 @@ moz_gtk_splitter_get_metrics(gint orientation, gint* size) return MOZ_GTK_SUCCESS; } +gint +moz_gtk_button_get_inner_border(GtkWidget* widget, GtkBorder* inner_border) +{ + static const GtkBorder default_inner_border = { 1, 1, 1, 1 }; + GtkBorder *tmp_border = NULL; + + if (have_2_10) + gtk_widget_style_get (widget, "inner-border", &tmp_border, NULL); + + if (tmp_border) { + *inner_border = *tmp_border; + gtk_border_free(tmp_border); + } + else + *inner_border = default_inner_border; + + return MOZ_GTK_SUCCESS; +} + static gint moz_gtk_toggle_paint(GdkDrawable* drawable, GdkRectangle* rect, GdkRectangle* cliprect, GtkWidgetState* state, @@ -726,6 +976,7 @@ moz_gtk_toggle_paint(GdkDrawable* drawable, GdkRectangle* rect, GtkShadowType shadow_type = (selected)?GTK_SHADOW_IN:GTK_SHADOW_OUT; gint indicator_size, indicator_spacing; gint x, y, width, height; + gint focus_x, focus_y, focus_width, focus_height; GtkWidget *w; GtkStyle *style; @@ -737,11 +988,19 @@ moz_gtk_toggle_paint(GdkDrawable* drawable, GdkRectangle* rect, w = gCheckboxWidget; } - /* offset by indicator_spacing, and centered vertically within the rect */ - x = rect->x + indicator_spacing; + /* + * vertically center in the box, since XUL sometimes ignores our + * GetMinimumWidgetSize in the vertical dimension + */ + x = rect->x; y = rect->y + (rect->height - indicator_size) / 2; width = indicator_size; height = indicator_size; + + focus_x = x - indicator_spacing; + focus_y = y - indicator_spacing; + focus_width = width + 2 * indicator_spacing; + focus_height = height + 2 * indicator_spacing; style = w->style; TSOffsetStyleGCs(style, x, y); @@ -756,8 +1015,8 @@ moz_gtk_toggle_paint(GdkDrawable* drawable, GdkRectangle* rect, width, height); if (state->focused) { gtk_paint_focus(style, drawable, GTK_STATE_ACTIVE, cliprect, - gRadiobuttonWidget, "radiobutton", rect->x, rect->y, - rect->width, rect->height); + gRadiobuttonWidget, "radiobutton", focus_x, focus_y, + focus_width, focus_height); } } else { @@ -765,8 +1024,8 @@ moz_gtk_toggle_paint(GdkDrawable* drawable, GdkRectangle* rect, gCheckboxWidget, "checkbutton", x, y, width, height); if (state->focused) { gtk_paint_focus(style, drawable, GTK_STATE_ACTIVE, cliprect, - gCheckboxWidget, "checkbutton", rect->x, rect->y, - rect->width, rect->height); + gCheckboxWidget, "checkbutton", focus_x, focus_y, + focus_width, focus_height); } } @@ -774,20 +1033,63 @@ moz_gtk_toggle_paint(GdkDrawable* drawable, GdkRectangle* rect, } static gint -calculate_arrow_dimensions(GdkRectangle* rect, GdkRectangle* arrow_rect) +calculate_button_inner_rect(GtkWidget* button, GdkRectangle* rect, + GdkRectangle* inner_rect, + GtkTextDirection direction, + gboolean ignore_focus) +{ + GtkBorder inner_border; + gboolean interior_focus; + gint focus_width, focus_pad; + GtkStyle* style; + + style = button->style; + + /* This mirrors gtkbutton's child positioning */ + moz_gtk_button_get_inner_border(button, &inner_border); + moz_gtk_widget_get_focus(button, &interior_focus, + &focus_width, &focus_pad); + + if (ignore_focus) + focus_width = focus_pad = 0; + + inner_rect->x = rect->x + XTHICKNESS(style) + focus_width + focus_pad; + inner_rect->x += direction == GTK_TEXT_DIR_LTR ? + inner_border.left : inner_border.right; + inner_rect->y = rect->y + inner_border.top + YTHICKNESS(style) + + focus_width + focus_pad; + inner_rect->width = MAX(1, rect->width - inner_border.left - + inner_border.right - (XTHICKNESS(style) + focus_pad + focus_width) * 2); + inner_rect->height = MAX(1, rect->height - inner_border.top - + inner_border.bottom - (YTHICKNESS(style) + focus_pad + focus_width) * 2); + + return MOZ_GTK_SUCCESS; +} + + +static gint +calculate_arrow_rect(GtkWidget* arrow, GdkRectangle* rect, + GdkRectangle* arrow_rect, GtkTextDirection direction) { - GtkMisc* misc = GTK_MISC(gArrowWidget); + /* defined in gtkarrow.c */ + gfloat arrow_scaling = 0.7; + gfloat xalign, xpad; + gint extent; + GtkMisc* misc = GTK_MISC(arrow); - gint extent = MIN(rect->width - misc->xpad * 2, - rect->height - misc->ypad * 2); + if (have_arrow_scaling) + gtk_widget_style_get(arrow, "arrow_scaling", &arrow_scaling, NULL); - arrow_rect->x = ((rect->x + misc->xpad) * (1.0 - misc->xalign) + - (rect->x + rect->width - extent - misc->xpad) * - misc->xalign); + extent = MIN((rect->width - misc->xpad * 2), + (rect->height - misc->ypad * 2)) * arrow_scaling; - arrow_rect->y = ((rect->y + misc->ypad) * (1.0 - misc->yalign) + - (rect->y + rect->height - extent - misc->ypad) * - misc->yalign); + xalign = direction == GTK_TEXT_DIR_LTR ? misc->xalign : 1.0 - misc->xalign; + xpad = misc->xpad + (rect->width - extent) * xalign; + + arrow_rect->x = direction == GTK_TEXT_DIR_LTR ? + floor(rect->x + xpad) : ceil(rect->x + xpad); + arrow_rect->y = floor(rect->y + misc->ypad + + ((rect->height - extent) * misc->yalign)); arrow_rect->width = arrow_rect->height = extent; @@ -803,11 +1105,11 @@ moz_gtk_scrollbar_button_paint(GdkDrawable* drawable, GdkRectangle* rect, GtkStateType state_type = ConvertGtkState(state); GtkShadowType shadow_type = (state->active) ? GTK_SHADOW_IN : GTK_SHADOW_OUT; - GdkRectangle button_rect; GdkRectangle arrow_rect; GtkStyle* style; GtkWidget *scrollbar; GtkArrowType arrow_type; + gint arrow_displacement_x, arrow_displacement_y; const char* detail = (flags & MOZ_GTK_STEPPER_VERTICAL) ? "vscrollbar" : "hscrollbar"; @@ -860,20 +1162,26 @@ moz_gtk_scrollbar_button_paint(GdkDrawable* drawable, GdkRectangle* rect, style = scrollbar->style; - ensure_arrow_widget(); - - calculate_arrow_dimensions(rect, &button_rect); - TSOffsetStyleGCs(style, button_rect.x, button_rect.y); + TSOffsetStyleGCs(style, rect->x, rect->y); gtk_paint_box(style, drawable, state_type, shadow_type, cliprect, - scrollbar, detail, button_rect.x, button_rect.y, - button_rect.width, button_rect.height); + scrollbar, detail, rect->x, rect->y, + rect->width, rect->height); + + arrow_rect.width = rect->width / 2; + arrow_rect.height = rect->height / 2; + arrow_rect.x = rect->x + (rect->width - arrow_rect.width) / 2; + arrow_rect.y = rect->y + (rect->height - arrow_rect.height) / 2; - arrow_rect.width = button_rect.width / 2; - arrow_rect.height = button_rect.height / 2; - arrow_rect.x = button_rect.x + (button_rect.width - arrow_rect.width) / 2; - arrow_rect.y = button_rect.y + - (button_rect.height - arrow_rect.height) / 2; + if (state_type == GTK_STATE_ACTIVE) { + gtk_widget_style_get(scrollbar, + "arrow-displacement-x", &arrow_displacement_x, + "arrow-displacement-y", &arrow_displacement_y, + NULL); + + arrow_rect.x += arrow_displacement_x; + arrow_rect.y += arrow_displacement_y; + } gtk_paint_arrow(style, drawable, state_type, shadow_type, cliprect, scrollbar, detail, arrow_type, TRUE, arrow_rect.x, @@ -928,9 +1236,11 @@ moz_gtk_scrollbar_thumb_paint(GtkThemeWidgetType widget, { GtkStateType state_type = (state->inHover || state->active) ? GTK_STATE_PRELIGHT : GTK_STATE_NORMAL; + GtkShadowType shadow_type = GTK_SHADOW_OUT; GtkStyle* style; GtkScrollbar *scrollbar; GtkAdjustment *adj; + gboolean activate_slider; ensure_scrollbar_widget(); @@ -971,10 +1281,18 @@ moz_gtk_scrollbar_thumb_paint(GtkThemeWidgetType widget, gtk_adjustment_changed(adj); style = GTK_WIDGET(scrollbar)->style; + + gtk_widget_style_get(GTK_WIDGET(scrollbar), "activate-slider", + &activate_slider, NULL); + + if (activate_slider && state->active) { + shadow_type = GTK_SHADOW_IN; + state_type = GTK_STATE_ACTIVE; + } TSOffsetStyleGCs(style, rect->x, rect->y); - gtk_paint_slider(style, drawable, state_type, GTK_SHADOW_OUT, cliprect, + gtk_paint_slider(style, drawable, state_type, shadow_type, cliprect, GTK_WIDGET(scrollbar), "slider", rect->x, rect->y, rect->width, rect->height, (widget == MOZ_GTK_SCROLLBAR_THUMB_HORIZONTAL) ? @@ -1167,52 +1485,87 @@ moz_gtk_vpaned_paint(GdkDrawable* drawable, GdkRectangle* rect, } static gint +moz_gtk_caret_paint(GdkDrawable* drawable, GdkRectangle* rect, + GdkRectangle* cliprect, GtkTextDirection direction) +{ + ensure_entry_widget(); + gtk_draw_insertion_cursor(gEntryWidget, drawable, cliprect, + rect, TRUE, direction, FALSE); + + return MOZ_GTK_SUCCESS; +} + +static gint moz_gtk_entry_paint(GdkDrawable* drawable, GdkRectangle* rect, GdkRectangle* cliprect, GtkWidgetState* state, GtkWidget* widget, GtkTextDirection direction) { + GtkStateType bg_state = state->disabled ? + GTK_STATE_INSENSITIVE : GTK_STATE_NORMAL; gint x, y, width = rect->width, height = rect->height; GtkStyle* style; gboolean interior_focus; + gboolean theme_honors_transparency = FALSE; gint focus_width; gtk_widget_set_direction(widget, direction); style = widget->style; - /* paint the background first */ - x = XTHICKNESS(style); - y = YTHICKNESS(style); + gtk_widget_style_get(widget, + "interior-focus", &interior_focus, + "focus-line-width", &focus_width, + "honors-transparent-bg-hint", &theme_honors_transparency, + NULL); + + /* gtkentry.c uses two windows, one for the entire widget and one for the + * text area inside it. The background of both windows is set to the "base" + * color of the new state in gtk_entry_state_changed, but only the inner + * textarea window uses gtk_paint_flat_box when exposed */ + + TSOffsetStyleGCs(style, rect->x, rect->y); /* This gets us a lovely greyish disabledish look */ gtk_widget_set_sensitive(widget, !state->disabled); - TSOffsetStyleGCs(style, rect->x + x, rect->y + y); - gtk_paint_flat_box(style, drawable, GTK_STATE_NORMAL, GTK_SHADOW_NONE, - cliprect, widget, "entry_bg", rect->x + x, - rect->y + y, rect->width - 2*x, rect->height - 2*y); + /* GTK fills the outer widget window with the base color before drawing the widget. + * Some older themes rely on this behavior, but many themes nowadays use rounded + * corners on their widgets. While most GTK apps are blissfully unaware of this + * problem due to their use of the default window background, we render widgets on + * many kinds of backgrounds on the web. + * If the theme is able to cope with transparency, then we can skip pre-filling + * and notify the theme it will paint directly on the canvas. */ + if (theme_honors_transparency) { + g_object_set_data(G_OBJECT(widget), "transparent-bg-hint", TRUE); + } else { + gdk_draw_rectangle(drawable, style->base_gc[bg_state], TRUE, + cliprect->x, cliprect->y, cliprect->width, cliprect->height); + g_object_set_data(G_OBJECT(widget), "transparent-bg-hint", FALSE); + } - gtk_widget_style_get(widget, - "interior-focus", &interior_focus, - "focus-line-width", &focus_width, - NULL); + /* Get the position of the inner window, see _gtk_entry_get_borders */ + x = XTHICKNESS(style); + y = YTHICKNESS(style); - /* - * Now paint the shadow and focus border. - * - * gtk+ is able to draw over top of the entry when it gains focus, - * so the non-focused text border is implicitly already drawn when - * the entry is drawn in a focused state. - * - * Gecko doesn't quite work this way, so always draw the non-focused - * shadow, then draw the shadow again, inset, if we're focused. - */ + if (!interior_focus) { + x += focus_width; + y += focus_width; + } + + /* Simulate an expose of the inner window */ + gtk_paint_flat_box(style, drawable, bg_state, GTK_SHADOW_NONE, + cliprect, widget, "entry_bg", rect->x + x, + rect->y + y, rect->width - 2*x, rect->height - 2*y); + /* Now paint the shadow and focus border. + * We do like in gtk_entry_draw_frame, we first draw the shadow, a tad + * smaller when focused if the focus is not interior, then the focus. */ x = rect->x; y = rect->y; if (state->focused && !state->disabled) { - /* This will get us the lit borders that focused textboxes enjoy on some themes. */ + /* This will get us the lit borders that focused textboxes enjoy on + * some themes. */ GTK_WIDGET_SET_FLAGS(widget, GTK_HAS_FOCUS); if (!interior_focus) { @@ -1225,19 +1578,18 @@ moz_gtk_entry_paint(GdkDrawable* drawable, GdkRectangle* rect, } } - TSOffsetStyleGCs(style, x, y); gtk_paint_shadow(style, drawable, GTK_STATE_NORMAL, GTK_SHADOW_IN, cliprect, widget, "entry", x, y, width, height); if (state->focused && !state->disabled) { if (!interior_focus) { - TSOffsetStyleGCs(style, rect->x, rect->y); gtk_paint_focus(style, drawable, GTK_STATE_NORMAL, cliprect, widget, "entry", rect->x, rect->y, rect->width, rect->height); } - /* Now unset the focus flag. We don't want other entries to look like they're focused too! */ + /* Now unset the focus flag. We don't want other entries to look + * like they're focused too! */ GTK_WIDGET_UNSET_FLAGS(widget, GTK_HAS_FOCUS); } @@ -1255,7 +1607,10 @@ moz_gtk_treeview_paint(GdkDrawable* drawable, GdkRectangle* rect, GtkStateType state_type; ensure_tree_view_widget(); + ensure_scrolled_window_widget(); + gtk_widget_set_direction(gTreeViewWidget, direction); + gtk_widget_set_direction(gScrolledWindowWidget, direction); /* only handle disabled and normal states, otherwise the whole background * area will be painted differently with other states */ @@ -1267,20 +1622,21 @@ moz_gtk_treeview_paint(GdkDrawable* drawable, GdkRectangle* rect, gtk_widget_modify_bg(gTreeViewWidget, state_type, &gTreeViewWidget->style->base[state_type]); - style = gTreeViewWidget->style; + style = gScrolledWindowWidget->style; xthickness = XTHICKNESS(style); ythickness = YTHICKNESS(style); + TSOffsetStyleGCs(gTreeViewWidget->style, rect->x, rect->y); TSOffsetStyleGCs(style, rect->x, rect->y); - gtk_paint_flat_box(style, drawable, state_type, GTK_SHADOW_NONE, - cliprect, gTreeViewWidget, "treeview", + gtk_paint_flat_box(gTreeViewWidget->style, drawable, state_type, + GTK_SHADOW_NONE, cliprect, gTreeViewWidget, "treeview", rect->x + xthickness, rect->y + ythickness, rect->width - 2 * xthickness, rect->height - 2 * ythickness); gtk_paint_shadow(style, drawable, GTK_STATE_NORMAL, GTK_SHADOW_IN, - cliprect, gTreeViewWidget, "scrolled_window", + cliprect, gScrolledWindowWidget, "scrolled_window", rect->x, rect->y, rect->width, rect->height); return MOZ_GTK_SUCCESS; @@ -1289,8 +1645,11 @@ moz_gtk_treeview_paint(GdkDrawable* drawable, GdkRectangle* rect, static gint moz_gtk_tree_header_cell_paint(GdkDrawable* drawable, GdkRectangle* rect, GdkRectangle* cliprect, GtkWidgetState* state, - GtkTextDirection direction) + gboolean isSorted, GtkTextDirection direction) { + gtk_tree_view_column_set_sort_indicator(GTK_TREE_VIEW_COLUMN(gMiddleTreeViewColumn), + isSorted); + moz_gtk_button_paint(drawable, rect, cliprect, state, GTK_RELIEF_NORMAL, gTreeHeaderCellWidget, direction); return MOZ_GTK_SUCCESS; @@ -1375,73 +1734,84 @@ moz_gtk_expander_paint(GdkDrawable* drawable, GdkRectangle* rect, } static gint -moz_gtk_option_menu_paint(GdkDrawable* drawable, GdkRectangle* rect, - GdkRectangle* cliprect, GtkWidgetState* state, - GtkTextDirection direction) +moz_gtk_combo_box_paint(GdkDrawable* drawable, GdkRectangle* rect, + GdkRectangle* cliprect, GtkWidgetState* state, + gboolean ishtml, GtkTextDirection direction) { - GtkStyle* style; + GdkRectangle arrow_rect, real_arrow_rect; + gint arrow_size, separator_width = 0; + gboolean wide_separators = FALSE; GtkStateType state_type = ConvertGtkState(state); - gint x = rect->x, y=rect->y, width=rect->width, height=rect->height; - gint tab_x, tab_y; - gboolean interior_focus; - GtkRequisition indicator_size; - GtkBorder indicator_spacing; - gint focus_width; - gint focus_pad; + GtkShadowType shadow_type = state->active ? GTK_SHADOW_IN : GTK_SHADOW_OUT; + GtkStyle* style; + GtkRequisition arrow_req; - ensure_option_menu_widget(); - gtk_widget_set_direction(gOptionMenuWidget, direction); - moz_gtk_option_menu_get_metrics(&interior_focus, &indicator_size, - &indicator_spacing, &focus_width, - &focus_pad); + ensure_combo_box_widgets(); - style = gOptionMenuWidget->style; + /* Also sets the direction on gComboBoxButtonWidget, which is then + * inherited by the separator and arrow */ + moz_gtk_button_paint(drawable, rect, cliprect, state, GTK_RELIEF_NORMAL, + gComboBoxButtonWidget, direction); - if (!interior_focus && state->focused) { - x += focus_width + focus_pad; - y += focus_width + focus_pad; - width -= 2 * (focus_width + focus_pad); - height -= 2 * (focus_width + focus_pad); - } + calculate_button_inner_rect(gComboBoxButtonWidget, + rect, &arrow_rect, direction, ishtml); + /* Now arrow_rect contains the inner rect ; we want to correct the width + * to what the arrow needs (see gtk_combo_box_size_allocate) */ + gtk_widget_size_request(gComboBoxArrowWidget, &arrow_req); + if (direction == GTK_TEXT_DIR_LTR) + arrow_rect.x += arrow_rect.width - arrow_req.width; + arrow_rect.width = arrow_req.width; - TSOffsetStyleGCs(style, x, y); - gtk_paint_box(style, drawable, state_type, GTK_SHADOW_OUT, - cliprect, gOptionMenuWidget, "optionmenu", - x, y, width, height); - - if (direction == GTK_TEXT_DIR_RTL) { - tab_x = x + indicator_spacing.right + XTHICKNESS(style); + calculate_arrow_rect(gComboBoxArrowWidget, + &arrow_rect, &real_arrow_rect, direction); + + style = gComboBoxArrowWidget->style; + TSOffsetStyleGCs(style, rect->x, rect->y); + + gtk_widget_size_allocate(gComboBoxWidget, rect); + + gtk_paint_arrow(style, drawable, state_type, shadow_type, cliprect, + gComboBoxArrowWidget, "arrow", GTK_ARROW_DOWN, TRUE, + real_arrow_rect.x, real_arrow_rect.y, + real_arrow_rect.width, real_arrow_rect.height); + + + /* If there is no separator in the theme, there's nothing left to do. */ + if (!gComboBoxSeparatorWidget) + return MOZ_GTK_SUCCESS; + + style = gComboBoxSeparatorWidget->style; + TSOffsetStyleGCs(style, rect->x, rect->y); + + if (have_2_10) + gtk_widget_style_get(gComboBoxSeparatorWidget, + "wide-separators", &wide_separators, + "separator-width", &separator_width, + NULL); + + if (wide_separators) { + if (direction == GTK_TEXT_DIR_LTR) + arrow_rect.x -= separator_width; + else + arrow_rect.x += arrow_rect.width; + + gtk_paint_box(style, drawable, + GTK_STATE_NORMAL, GTK_SHADOW_ETCHED_OUT, + cliprect, gComboBoxSeparatorWidget, "vseparator", + arrow_rect.x, arrow_rect.y, + separator_width, arrow_rect.height); } else { - tab_x = x + width - indicator_size.width - indicator_spacing.right - - XTHICKNESS(style); + if (direction == GTK_TEXT_DIR_LTR) + arrow_rect.x -= XTHICKNESS(style); + else + arrow_rect.x += arrow_rect.width; + + gtk_paint_vline(style, drawable, GTK_STATE_NORMAL, cliprect, + gComboBoxSeparatorWidget, "vseparator", + arrow_rect.y, arrow_rect.y + arrow_rect.height, + arrow_rect.x); } - tab_y = y + (height - indicator_size.height) / 2; - TSOffsetStyleGCs(style, tab_x, tab_y); - gtk_paint_tab(style, drawable, state_type, GTK_SHADOW_OUT, cliprect, - gOptionMenuWidget, "optionmenutab", tab_x, tab_y, - indicator_size.width, indicator_size.height); - - if (state->focused) { - if (interior_focus) { - x += XTHICKNESS(style) + focus_pad; - y += YTHICKNESS(style) + focus_pad; - /* Standard GTK combos have their focus ring around the entire - control, not just the text bit */ - width -= 2 * (XTHICKNESS(style) + focus_pad); - height -= 2 * (YTHICKNESS(style) + focus_pad); - } else { - x -= focus_width + focus_pad; - y -= focus_width + focus_pad; - width += 2 * (focus_width + focus_pad); - height += 2 * (focus_width + focus_pad); - } - - TSOffsetStyleGCs(style, x, y); - gtk_paint_focus (style, drawable, state_type, cliprect, gOptionMenuWidget, - "button", x, y, width, height); - } - return MOZ_GTK_SUCCESS; } @@ -1454,63 +1824,66 @@ moz_gtk_downarrow_paint(GdkDrawable* drawable, GdkRectangle* rect, GtkShadowType shadow_type = state->active ? GTK_SHADOW_IN : GTK_SHADOW_OUT; GdkRectangle arrow_rect; - ensure_arrow_widget(); - style = gArrowWidget->style; + ensure_button_arrow_widget(); + style = gButtonArrowWidget->style; - arrow_rect.x = rect->x + 1 + XTHICKNESS(style); - arrow_rect.y = rect->y + 1 + YTHICKNESS(style); - arrow_rect.width = MAX(1, rect->width - (arrow_rect.x - rect->x) * 2); - arrow_rect.height = MAX(1, rect->height - (arrow_rect.y - rect->y) * 2); + calculate_arrow_rect(gButtonArrowWidget, rect, &arrow_rect, + GTK_TEXT_DIR_LTR); TSOffsetStyleGCs(style, arrow_rect.x, arrow_rect.y); gtk_paint_arrow(style, drawable, state_type, shadow_type, cliprect, - gArrowWidget, "arrow", GTK_ARROW_DOWN, TRUE, + gButtonArrowWidget, "arrow", GTK_ARROW_DOWN, TRUE, arrow_rect.x, arrow_rect.y, arrow_rect.width, arrow_rect.height); return MOZ_GTK_SUCCESS; } static gint -moz_gtk_dropdown_arrow_paint(GdkDrawable* drawable, GdkRectangle* rect, - GdkRectangle* cliprect, GtkWidgetState* state, - GtkTextDirection direction) +moz_gtk_combo_box_entry_button_paint(GdkDrawable* drawable, GdkRectangle* rect, + GdkRectangle* cliprect, + GtkWidgetState* state, + gboolean input_focus, + GtkTextDirection direction) { - static gfloat arrow_scaling = 0.7; - gint real_arrow_padding; + gint x_displacement, y_displacement; GdkRectangle arrow_rect, real_arrow_rect; GtkStateType state_type = ConvertGtkState(state); GtkShadowType shadow_type = state->active ? GTK_SHADOW_IN : GTK_SHADOW_OUT; GtkStyle* style; - ensure_arrow_widget(); - gtk_widget_set_direction(gDropdownButtonWidget, direction); + ensure_combo_box_entry_widgets(); + + if (input_focus) { + /* Some themes draw a complementary focus ring for the dropdown button + * when the dropdown entry has focus */ + GTK_WIDGET_SET_FLAGS(gComboBoxEntryTextareaWidget, GTK_HAS_FOCUS); + } moz_gtk_button_paint(drawable, rect, cliprect, state, GTK_RELIEF_NORMAL, - gDropdownButtonWidget, direction); + gComboBoxEntryButtonWidget, direction); - /* This mirrors gtkbutton's child positioning */ - style = gDropdownButtonWidget->style; - arrow_rect.x = rect->x + 1 + XTHICKNESS(style); - arrow_rect.y = rect->y + 1 + YTHICKNESS(style); - arrow_rect.width = MAX(1, rect->width - (arrow_rect.x - rect->x) * 2); - arrow_rect.height = MAX(1, rect->height - (arrow_rect.y - rect->y) * 2); - - calculate_arrow_dimensions(&arrow_rect, &real_arrow_rect); - style = gArrowWidget->style; - TSOffsetStyleGCs(style, real_arrow_rect.x, real_arrow_rect.y); + if (input_focus) + GTK_WIDGET_UNSET_FLAGS(gComboBoxEntryTextareaWidget, GTK_HAS_FOCUS); + + calculate_button_inner_rect(gComboBoxEntryButtonWidget, + rect, &arrow_rect, direction, FALSE); + if (state_type == GTK_STATE_ACTIVE) { + gtk_widget_style_get(gComboBoxEntryButtonWidget, + "child-displacement-x", &x_displacement, + "child-displacement-y", &y_displacement, + NULL); + arrow_rect.x += x_displacement; + arrow_rect.y += y_displacement; + } - real_arrow_rect.width = real_arrow_rect.height = - MIN (real_arrow_rect.width, real_arrow_rect.height) * arrow_scaling; + calculate_arrow_rect(gComboBoxEntryArrowWidget, + &arrow_rect, &real_arrow_rect, direction); - real_arrow_padding = floor((arrow_rect.width - real_arrow_rect.width) / 2 + 0.5); - real_arrow_rect.x = arrow_rect.x + real_arrow_padding; - if (direction == GTK_TEXT_DIR_RTL) - real_arrow_rect.x = arrow_rect.x + arrow_rect.width - - real_arrow_rect.width - real_arrow_padding; - real_arrow_rect.y = floor (arrow_rect.y + ((arrow_rect.height - real_arrow_rect.height) / 2) + 0.5); + style = gComboBoxEntryArrowWidget->style; + TSOffsetStyleGCs(style, real_arrow_rect.x, real_arrow_rect.y); gtk_paint_arrow(style, drawable, state_type, shadow_type, cliprect, - gDropdownButtonWidget, "arrow", GTK_ARROW_DOWN, TRUE, + gComboBoxEntryArrowWidget, "arrow", GTK_ARROW_DOWN, TRUE, real_arrow_rect.x, real_arrow_rect.y, real_arrow_rect.width, real_arrow_rect.height); @@ -1624,7 +1997,9 @@ moz_gtk_toolbar_paint(GdkDrawable* drawable, GdkRectangle* rect, cliprect, rect->x, rect->y, rect->width, rect->height); - gtk_paint_box (style, drawable, GTK_STATE_NORMAL, gToolbarShadowType, + gtk_widget_style_get(gToolbarWidget, "shadow-type", &shadow_type, NULL); + + gtk_paint_box (style, drawable, GTK_STATE_NORMAL, shadow_type, cliprect, gToolbarWidget, "toolbar", rect->x, rect->y, rect->width, rect->height); @@ -1637,9 +2012,9 @@ moz_gtk_toolbar_separator_paint(GdkDrawable* drawable, GdkRectangle* rect, GtkTextDirection direction) { GtkStyle* style; - gint separator_width; + gint separator_width = 0; gint paint_width; - gboolean wide_separators; + gboolean wide_separators = FALSE; /* Defined as constants in GTK+ 2.10.14 */ const double start_fraction = 0.2; @@ -1650,10 +2025,11 @@ moz_gtk_toolbar_separator_paint(GdkDrawable* drawable, GdkRectangle* rect, style = gToolbarSeparatorWidget->style; - gtk_widget_style_get(gToolbarWidget, - "wide-separators", &wide_separators, - "separator-width", &separator_width, - NULL); + if (have_2_10) + gtk_widget_style_get(gToolbarWidget, + "wide-separators", &wide_separators, + "separator-width", &separator_width, + NULL); TSOffsetStyleGCs(style, rect->x, rect->y); @@ -1965,6 +2341,36 @@ moz_gtk_tabpanels_paint(GdkDrawable* drawable, GdkRectangle* rect, } static gint +moz_gtk_tab_scroll_arrow_paint(GdkDrawable* drawable, GdkRectangle* rect, + GdkRectangle* cliprect, GtkWidgetState* state, + GtkArrowType arrow_type, + GtkTextDirection direction) +{ + GtkStateType state_type = ConvertGtkState(state); + GtkShadowType shadow_type = state->active ? GTK_SHADOW_IN : GTK_SHADOW_OUT; + GtkStyle* style; + gint arrow_size = MIN(rect->width, rect->height); + gint x = rect->x + (rect->width - arrow_size) / 2; + gint y = rect->y + (rect->height - arrow_size) / 2; + + ensure_tab_widget(); + + style = gTabWidget->style; + TSOffsetStyleGCs(style, rect->x, rect->y); + + if (direction == GTK_TEXT_DIR_RTL) { + arrow_type = (arrow_type == GTK_ARROW_LEFT) ? + GTK_ARROW_RIGHT : GTK_ARROW_LEFT; + } + + gtk_paint_arrow(style, drawable, state_type, shadow_type, NULL, + gTabWidget, "notebook", arrow_type, TRUE, + x, y, arrow_size, arrow_size); + + return MOZ_GTK_SUCCESS; +} + +static gint moz_gtk_menu_bar_paint(GdkDrawable* drawable, GdkRectangle* rect, GdkRectangle* cliprect, GtkTextDirection direction) { @@ -1973,13 +2379,16 @@ moz_gtk_menu_bar_paint(GdkDrawable* drawable, GdkRectangle* rect, ensure_menu_bar_widget(); gtk_widget_set_direction(gMenuBarWidget, direction); + gtk_widget_style_get(gMenuBarWidget, "shadow-type", &shadow_type, NULL); + style = gMenuBarWidget->style; TSOffsetStyleGCs(style, rect->x, rect->y); gtk_style_apply_default_background(style, drawable, TRUE, GTK_STATE_NORMAL, cliprect, rect->x, rect->y, rect->width, rect->height); - gtk_paint_box(style, drawable, GTK_STATE_NORMAL, gMenuBarShadowType, + + gtk_paint_box(style, drawable, GTK_STATE_NORMAL, shadow_type, cliprect, gMenuBarWidget, "menubar", rect->x, rect->y, rect->width, rect->height); return MOZ_GTK_SUCCESS; @@ -2011,9 +2420,9 @@ moz_gtk_menu_separator_paint(GdkDrawable* drawable, GdkRectangle* rect, GdkRectangle* cliprect, GtkTextDirection direction) { GtkStyle* style; - gboolean wide_separators; - gint separator_height; - guint horizontal_padding; + gboolean wide_separators = FALSE; + gint separator_height = 0; + guint horizontal_padding = 0; gint paint_height; ensure_menu_separator_widget(); @@ -2021,9 +2430,13 @@ moz_gtk_menu_separator_paint(GdkDrawable* drawable, GdkRectangle* rect, style = gMenuSeparatorWidget->style; + if (have_2_10) + gtk_widget_style_get(gMenuSeparatorWidget, + "wide-separators", &wide_separators, + "separator-height", &separator_height, + NULL); + gtk_widget_style_get(gMenuSeparatorWidget, - "wide-separators", &wide_separators, - "separator-height", &separator_height, "horizontal-padding", &horizontal_padding, NULL); @@ -2077,12 +2490,9 @@ moz_gtk_menu_item_paint(GdkDrawable* drawable, GdkRectangle* rect, style = item_widget->style; TSOffsetStyleGCs(style, rect->x, rect->y); - if (have_menu_shadow_type) { - gtk_widget_style_get(item_widget, "selected_shadow_type", - &shadow_type, NULL); - } else { - shadow_type = GTK_SHADOW_OUT; - } + + gtk_widget_style_get(item_widget, "selected-shadow-type", + &shadow_type, NULL); gtk_paint_box(style, drawable, GTK_STATE_PRELIGHT, shadow_type, cliprect, item_widget, "menuitem", rect->x, rect->y, @@ -2197,8 +2607,7 @@ moz_gtk_get_widget_border(GtkThemeWidgetType widget, gint* left, gint* top, switch (widget) { case MOZ_GTK_BUTTON: { - /* Constant in gtkbutton.c */ - static const gint child_spacing = 1; + GtkBorder inner_border; gboolean interior_focus; gint focus_width, focus_pad; @@ -2209,10 +2618,11 @@ moz_gtk_get_widget_border(GtkThemeWidgetType widget, gint* left, gint* top, become too big and stuff the layout. */ if (!inhtml) { moz_gtk_widget_get_focus(gButtonWidget, &interior_focus, &focus_width, &focus_pad); - *left += focus_width + focus_pad + child_spacing; - *right += focus_width + focus_pad + child_spacing; - *top += focus_width + focus_pad + child_spacing; - *bottom += focus_width + focus_pad + child_spacing; + moz_gtk_button_get_inner_border(gButtonWidget, &inner_border); + *left += focus_width + focus_pad + inner_border.left; + *right += focus_width + focus_pad + inner_border.right; + *top += focus_width + focus_pad + inner_border.top; + *bottom += focus_width + focus_pad + inner_border.bottom; } *left += gButtonWidget->style->xthickness; @@ -2221,11 +2631,6 @@ moz_gtk_get_widget_border(GtkThemeWidgetType widget, gint* left, gint* top, *bottom += gButtonWidget->style->ythickness; return MOZ_GTK_SUCCESS; } - - case MOZ_GTK_TOOLBAR: - ensure_toolbar_widget(); - w = gToolbarWidget; - break; case MOZ_GTK_ENTRY: ensure_entry_widget(); w = gEntryWidget; @@ -2242,19 +2647,19 @@ moz_gtk_get_widget_border(GtkThemeWidgetType widget, gint* left, gint* top, * That is why the following code is the same as for MOZ_GTK_BUTTON. * */ - /* Constant in gtkbutton.c */ - static const gint child_spacing = 1; + GtkBorder inner_border; gboolean interior_focus; gint focus_width, focus_pad; ensure_tree_header_cell_widget(); *left = *top = *right = *bottom = GTK_CONTAINER(gTreeHeaderCellWidget)->border_width; - moz_gtk_widget_get_focus(gTreeHeaderCellWidget, &interior_focus, &focus_width, &focus_pad); - *left += focus_width + focus_pad; - *right += focus_width + focus_pad; - *top += focus_width + focus_pad + child_spacing; - *bottom += focus_width + focus_pad + child_spacing; + moz_gtk_widget_get_focus(gTreeHeaderCellWidget, &interior_focus, &focus_width, &focus_pad); + moz_gtk_button_get_inner_border(gTreeHeaderCellWidget, &inner_border); + *left += focus_width + focus_pad + inner_border.left; + *right += focus_width + focus_pad + inner_border.right; + *top += focus_width + focus_pad + inner_border.top; + *bottom += focus_width + focus_pad + inner_border.bottom; *left += gTreeHeaderCellWidget->style->xthickness; *right += gTreeHeaderCellWidget->style->xthickness; @@ -2267,32 +2672,59 @@ moz_gtk_get_widget_border(GtkThemeWidgetType widget, gint* left, gint* top, w = gTreeHeaderSortArrowWidget; break; case MOZ_GTK_DROPDOWN_ENTRY: - ensure_dropdown_entry_widget(); - w = gDropdownEntryWidget; + ensure_combo_box_entry_widgets(); + w = gComboBoxEntryTextareaWidget; break; case MOZ_GTK_DROPDOWN_ARROW: - ensure_arrow_widget(); - w = gDropdownButtonWidget; + ensure_combo_box_entry_widgets(); + w = gComboBoxEntryButtonWidget; break; case MOZ_GTK_DROPDOWN: { - /* We need to account for the arrow on the dropdown, so text doesn't - come too close to the arrow, or in some cases spill into the arrow. */ - gboolean interior_focus; - GtkRequisition indicator_size; - GtkBorder indicator_spacing; - gint focus_width, focus_pad; + /* We need to account for the arrow on the dropdown, so text + * doesn't come too close to the arrow, or in some cases spill + * into the arrow. */ + gboolean ignored_interior_focus, wide_separators = FALSE; + gint focus_width, focus_pad, separator_width; + GtkRequisition arrow_req; + + ensure_combo_box_widgets(); + + *left = GTK_CONTAINER(gComboBoxButtonWidget)->border_width; + + if (!inhtml) { + moz_gtk_widget_get_focus(gComboBoxButtonWidget, + &ignored_interior_focus, + &focus_width, &focus_pad); + *left += focus_width + focus_pad; + } + + *top = *left + gComboBoxButtonWidget->style->ythickness; + *left += gComboBoxButtonWidget->style->xthickness; + + *right = *left; *bottom = *top; + + /* If there is no separator, don't try to count its width. */ + separator_width = 0; + if (gComboBoxSeparatorWidget) { + if (have_2_10) + gtk_widget_style_get(gComboBoxSeparatorWidget, + "wide-separators", &wide_separators, + "separator-width", &separator_width, + NULL); + + if (!wide_separators) + separator_width = + XTHICKNESS(gComboBoxSeparatorWidget->style); + } - ensure_option_menu_widget(); - *right = *left = gOptionMenuWidget->style->xthickness; - *bottom = *top = gOptionMenuWidget->style->ythickness; - moz_gtk_option_menu_get_metrics(&interior_focus, &indicator_size, - &indicator_spacing, &focus_width, &focus_pad); + gtk_widget_size_request(gComboBoxArrowWidget, &arrow_req); if (direction == GTK_TEXT_DIR_RTL) - *left += indicator_spacing.left + indicator_size.width + indicator_spacing.right; + *left += separator_width + arrow_req.width; else - *right += indicator_spacing.left + indicator_size.width + indicator_spacing.right; + *right += separator_width + arrow_req.width; + return MOZ_GTK_SUCCESS; } case MOZ_GTK_TABPANELS: @@ -2379,10 +2811,6 @@ moz_gtk_get_widget_border(GtkThemeWidgetType widget, gint* left, gint* top, return MOZ_GTK_SUCCESS; } - case MOZ_GTK_MENUBAR: - ensure_menu_bar_widget(); - w = gMenuBarWidget; - break; case MOZ_GTK_MENUPOPUP: ensure_menu_popup_widget(); w = gMenuPopupWidget; @@ -2416,6 +2844,7 @@ moz_gtk_get_widget_border(GtkThemeWidgetType widget, gint* left, gint* top, case MOZ_GTK_GRIPPER: case MOZ_GTK_PROGRESS_CHUNK: case MOZ_GTK_EXPANDER: + case MOZ_GTK_TREEVIEW_EXPANDER: case MOZ_GTK_TOOLBAR_SEPARATOR: case MOZ_GTK_MENUSEPARATOR: /* These widgets have no borders.*/ @@ -2425,6 +2854,10 @@ moz_gtk_get_widget_border(GtkThemeWidgetType widget, gint* left, gint* top, case MOZ_GTK_RESIZER: case MOZ_GTK_MENUARROW: case MOZ_GTK_TOOLBARBUTTON_ARROW: + case MOZ_GTK_TOOLBAR: + case MOZ_GTK_MENUBAR: + case MOZ_GTK_TAB_SCROLLARROW: + case MOZ_GTK_ENTRY_CARET: *left = *top = *right = *bottom = 0; return MOZ_GTK_SUCCESS; default: @@ -2439,22 +2872,48 @@ moz_gtk_get_widget_border(GtkThemeWidgetType widget, gint* left, gint* top, } gint -moz_gtk_get_dropdown_arrow_size(gint* width, gint* height) +moz_gtk_get_combo_box_entry_button_size(gint* width, gint* height) { - const gint min_arrow_size = 15; - ensure_arrow_widget(); - /* - * First get the border of the dropdown arrow, then add in the requested - * size of the arrow. Note that the minimum arrow size is fixed at - * 15 pixels. - */ + * We get the requisition of the drop down button, which includes + * all padding, border and focus line widths the button uses, + * as well as the minimum arrow size and its padding + * */ + GtkRequisition requisition; + ensure_combo_box_entry_widgets(); + + gtk_widget_size_request(gComboBoxEntryButtonWidget, &requisition); + *width = requisition.width; + *height = requisition.height; + + return MOZ_GTK_SUCCESS; +} + +gint +moz_gtk_get_tab_scroll_arrow_size(gint* width, gint* height) +{ + gint arrow_size = 16; + + ensure_tab_widget(); + if (have_2_10) + gtk_widget_style_get(gTabWidget, + "scroll-arrow-hlength", &arrow_size, + NULL); + + *height = *width = arrow_size; - *width = 2 * (1 + XTHICKNESS(gDropdownButtonWidget->style)); - *width += min_arrow_size + GTK_MISC(gArrowWidget)->xpad * 2; + return MOZ_GTK_SUCCESS; +} + +gint +moz_gtk_get_downarrow_size(gint* width, gint* height) +{ + GtkRequisition requisition; + ensure_button_arrow_widget(); - *height = 2 * (1 + YTHICKNESS(gDropdownButtonWidget->style)); - *height += min_arrow_size + GTK_MISC(gArrowWidget)->ypad * 2; + gtk_widget_size_request(gButtonArrowWidget, &requisition); + *width = requisition.width; + *height = requisition.height; return MOZ_GTK_SUCCESS; } @@ -2462,18 +2921,22 @@ moz_gtk_get_dropdown_arrow_size(gint* width, gint* height) gint moz_gtk_get_toolbar_separator_width(gint* size) { - gboolean wide_separators; - gint separator_width; + gboolean wide_separators = FALSE; + gint separator_width = 0; GtkStyle* style; ensure_toolbar_widget(); style = gToolbarWidget->style; + if (have_2_10) + gtk_widget_style_get(gToolbarWidget, + "wide-separators", &wide_separators, + "separator-width", &separator_width, + NULL); + gtk_widget_style_get(gToolbarWidget, "space-size", size, - "wide-separators", &wide_separators, - "separator-width", &separator_width, NULL); /* Just in case... */ @@ -2507,15 +2970,16 @@ moz_gtk_get_treeview_expander_size(gint* size) gint moz_gtk_get_menu_separator_height(gint *size) { - gboolean wide_separators; - gint separator_height; + gboolean wide_separators = FALSE; + gint separator_height = 0; ensure_menu_separator_widget(); - gtk_widget_style_get(gMenuSeparatorWidget, - "wide-separators", &wide_separators, - "separator-height", &separator_height, - NULL); + if (have_2_10) + gtk_widget_style_get(gMenuSeparatorWidget, + "wide-separators", &wide_separators, + "separator-height", &separator_height, + NULL); if (wide_separators) *size = separator_height + gMenuSeparatorWidget->style->ythickness; @@ -2559,6 +3023,19 @@ moz_gtk_get_scrollbar_metrics(MozGtkScrollbarMetrics *metrics) return MOZ_GTK_SUCCESS; } +gboolean +moz_gtk_images_in_menus() +{ + gboolean result; + GtkSettings* settings; + + ensure_image_menu_item_widget(); + settings = gtk_widget_get_settings(gImageMenuItemWidget); + + g_object_get(settings, "gtk-menu-images", &result, NULL); + return result; +} + gint moz_gtk_widget_paint(GtkThemeWidgetType widget, GdkDrawable* drawable, GdkRectangle* rect, GdkRectangle* cliprect, @@ -2634,7 +3111,7 @@ moz_gtk_widget_paint(GtkThemeWidgetType widget, GdkDrawable* drawable, break; case MOZ_GTK_TREE_HEADER_CELL: return moz_gtk_tree_header_cell_paint(drawable, rect, cliprect, state, - direction); + flags, direction); break; case MOZ_GTK_TREE_HEADER_SORTARROW: return moz_gtk_tree_header_sort_arrow_paint(drawable, rect, cliprect, @@ -2655,18 +3132,21 @@ moz_gtk_widget_paint(GtkThemeWidgetType widget, GdkDrawable* drawable, return moz_gtk_entry_paint(drawable, rect, cliprect, state, gEntryWidget, direction); break; + case MOZ_GTK_ENTRY_CARET: + return moz_gtk_caret_paint(drawable, rect, cliprect, direction); + break; case MOZ_GTK_DROPDOWN: - return moz_gtk_option_menu_paint(drawable, rect, cliprect, state, - direction); + return moz_gtk_combo_box_paint(drawable, rect, cliprect, state, + (gboolean) flags, direction); break; case MOZ_GTK_DROPDOWN_ARROW: - return moz_gtk_dropdown_arrow_paint(drawable, rect, cliprect, state, - direction); + return moz_gtk_combo_box_entry_button_paint(drawable, rect, cliprect, + state, flags, direction); break; case MOZ_GTK_DROPDOWN_ENTRY: - ensure_dropdown_entry_widget(); + ensure_combo_box_entry_widgets(); return moz_gtk_entry_paint(drawable, rect, cliprect, state, - gDropdownEntryWidget, direction); + gComboBoxEntryTextareaWidget, direction); break; case MOZ_GTK_CHECKBUTTON_CONTAINER: case MOZ_GTK_RADIOBUTTON_CONTAINER: @@ -2711,6 +3191,10 @@ moz_gtk_widget_paint(GtkThemeWidgetType widget, GdkDrawable* drawable, case MOZ_GTK_TABPANELS: return moz_gtk_tabpanels_paint(drawable, rect, cliprect, direction); break; + case MOZ_GTK_TAB_SCROLLARROW: + return moz_gtk_tab_scroll_arrow_paint(drawable, rect, cliprect, state, + (GtkArrowType) flags, direction); + break; case MOZ_GTK_MENUBAR: return moz_gtk_menu_bar_paint(drawable, rect, cliprect, direction); break; @@ -2766,6 +3250,8 @@ GtkWidget* moz_gtk_get_scrollbar_widget(void) gint moz_gtk_shutdown() { + GtkWidgetClass *entry_class; + if (gTooltipWidget) gtk_widget_destroy(gTooltipWidget); /* This will destroy all of our widgets */ @@ -2775,6 +3261,7 @@ moz_gtk_shutdown() gProtoWindow = NULL; gButtonWidget = NULL; gToggleButtonWidget = NULL; + gButtonArrowWidget = NULL; gCheckboxWidget = NULL; gRadiobuttonWidget = NULL; gHorizScrollbarWidget = NULL; @@ -2783,11 +3270,14 @@ moz_gtk_shutdown() gHScaleWidget = NULL; gVScaleWidget = NULL; gEntryWidget = NULL; - gArrowWidget = NULL; - gOptionMenuWidget = NULL; - gDropdownButtonWidget = NULL; - gDropdownEntryWidget = NULL; + gComboBoxWidget = NULL; + gComboBoxButtonWidget = NULL; + gComboBoxSeparatorWidget = NULL; + gComboBoxArrowWidget = NULL; gComboBoxEntryWidget = NULL; + gComboBoxEntryButtonWidget = NULL; + gComboBoxEntryArrowWidget = NULL; + gComboBoxEntryTextareaWidget = NULL; gHandleBoxWidget = NULL; gToolbarWidget = NULL; gStatusbarWidget = NULL; @@ -2799,8 +3289,10 @@ moz_gtk_shutdown() gMenuBarItemWidget = NULL; gMenuPopupWidget = NULL; gMenuItemWidget = NULL; + gImageMenuItemWidget = NULL; gCheckMenuItemWidget = NULL; gTreeViewWidget = NULL; + gMiddleTreeViewColumn = NULL; gTreeHeaderCellWidget = NULL; gTreeHeaderSortArrowWidget = NULL; gExpanderWidget = NULL; @@ -2808,6 +3300,10 @@ moz_gtk_shutdown() gMenuSeparatorWidget = NULL; gHPanedWidget = NULL; gVPanedWidget = NULL; + gScrolledWindowWidget = NULL; + + entry_class = g_type_class_peek(GTK_TYPE_ENTRY); + g_type_class_unref(entry_class); is_initialized = FALSE; |