michael@0: /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ michael@0: /* This Source Code Form is subject to the terms of the Mozilla Public michael@0: * License, v. 2.0. If a copy of the MPL was not distributed with this michael@0: * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ michael@0: michael@0: /* michael@0: * This file contains painting functions for each of the gtk2 widgets. michael@0: * Adapted from the gtkdrawing.c, and gtk+2.0 source. michael@0: */ michael@0: michael@0: #include michael@0: #include michael@0: #include michael@0: #include "gtkdrawing.h" michael@0: #include "nsDebug.h" michael@0: #include "prinrval.h" michael@0: michael@0: #include michael@0: michael@0: #define XTHICKNESS(style) (style->xthickness) michael@0: #define YTHICKNESS(style) (style->ythickness) michael@0: #define WINDOW_IS_MAPPED(window) ((window) && GDK_IS_WINDOW(window) && gdk_window_is_visible(window)) michael@0: michael@0: static GtkWidget* gProtoWindow; michael@0: static GtkWidget* gProtoLayout; michael@0: static GtkWidget* gButtonWidget; michael@0: static GtkWidget* gToggleButtonWidget; michael@0: static GtkWidget* gButtonArrowWidget; michael@0: static GtkWidget* gCheckboxWidget; michael@0: static GtkWidget* gRadiobuttonWidget; michael@0: static GtkWidget* gHorizScrollbarWidget; michael@0: static GtkWidget* gVertScrollbarWidget; michael@0: static GtkWidget* gSpinWidget; michael@0: static GtkWidget* gHScaleWidget; michael@0: static GtkWidget* gVScaleWidget; michael@0: static GtkWidget* gEntryWidget; michael@0: static GtkWidget* gComboBoxWidget; michael@0: static GtkWidget* gComboBoxButtonWidget; michael@0: static GtkWidget* gComboBoxArrowWidget; michael@0: static GtkWidget* gComboBoxSeparatorWidget; michael@0: static GtkWidget* gComboBoxEntryWidget; michael@0: static GtkWidget* gComboBoxEntryTextareaWidget; michael@0: static GtkWidget* gComboBoxEntryButtonWidget; michael@0: static GtkWidget* gComboBoxEntryArrowWidget; michael@0: static GtkWidget* gHandleBoxWidget; michael@0: static GtkWidget* gToolbarWidget; michael@0: static GtkWidget* gFrameWidget; michael@0: static GtkWidget* gStatusbarWidget; michael@0: static GtkWidget* gProgressWidget; michael@0: static GtkWidget* gTabWidget; michael@0: static GtkWidget* gTooltipWidget; michael@0: static GtkWidget* gMenuBarWidget; michael@0: static GtkWidget* gMenuBarItemWidget; michael@0: static GtkWidget* gMenuPopupWidget; michael@0: static GtkWidget* gMenuItemWidget; michael@0: static GtkWidget* gImageMenuItemWidget; michael@0: static GtkWidget* gCheckMenuItemWidget; michael@0: static GtkWidget* gTreeViewWidget; michael@0: static GtkTreeViewColumn* gMiddleTreeViewColumn; michael@0: static GtkWidget* gTreeHeaderCellWidget; michael@0: static GtkWidget* gTreeHeaderSortArrowWidget; michael@0: static GtkWidget* gExpanderWidget; michael@0: static GtkWidget* gToolbarSeparatorWidget; michael@0: static GtkWidget* gMenuSeparatorWidget; michael@0: static GtkWidget* gHPanedWidget; michael@0: static GtkWidget* gVPanedWidget; michael@0: static GtkWidget* gScrolledWindowWidget; michael@0: michael@0: static style_prop_t style_prop_func; michael@0: static gboolean have_arrow_scaling; michael@0: static gboolean is_initialized; michael@0: michael@0: /* Because we have such an unconventional way of drawing widgets, signal to the GTK theme engine michael@0: that they are drawing for Mozilla instead of a conventional GTK app so they can do any specific michael@0: things they may want to do. */ michael@0: static void michael@0: moz_gtk_set_widget_name(GtkWidget* widget) michael@0: { michael@0: gtk_widget_set_name(widget, "MozillaGtkWidget"); michael@0: } michael@0: michael@0: gint michael@0: moz_gtk_enable_style_props(style_prop_t styleGetProp) michael@0: { michael@0: style_prop_func = styleGetProp; michael@0: return MOZ_GTK_SUCCESS; michael@0: } michael@0: michael@0: static gint michael@0: ensure_window_widget() michael@0: { michael@0: if (!gProtoWindow) { michael@0: gProtoWindow = gtk_window_new(GTK_WINDOW_POPUP); michael@0: gtk_widget_realize(gProtoWindow); michael@0: moz_gtk_set_widget_name(gProtoWindow); michael@0: } michael@0: return MOZ_GTK_SUCCESS; michael@0: } michael@0: michael@0: static gint michael@0: setup_widget_prototype(GtkWidget* widget) michael@0: { michael@0: ensure_window_widget(); michael@0: if (!gProtoLayout) { michael@0: gProtoLayout = gtk_fixed_new(); michael@0: gtk_container_add(GTK_CONTAINER(gProtoWindow), gProtoLayout); michael@0: } michael@0: michael@0: gtk_container_add(GTK_CONTAINER(gProtoLayout), widget); michael@0: gtk_widget_realize(widget); michael@0: g_object_set_data(G_OBJECT(widget), "transparent-bg-hint", GINT_TO_POINTER(TRUE)); michael@0: return MOZ_GTK_SUCCESS; michael@0: } michael@0: michael@0: static gint michael@0: ensure_button_widget() michael@0: { michael@0: if (!gButtonWidget) { michael@0: gButtonWidget = gtk_button_new_with_label("M"); michael@0: setup_widget_prototype(gButtonWidget); michael@0: } michael@0: return MOZ_GTK_SUCCESS; michael@0: } michael@0: michael@0: static gint michael@0: ensure_hpaned_widget() michael@0: { michael@0: if (!gHPanedWidget) { michael@0: gHPanedWidget = gtk_hpaned_new(); michael@0: setup_widget_prototype(gHPanedWidget); michael@0: } michael@0: return MOZ_GTK_SUCCESS; michael@0: } michael@0: michael@0: static gint michael@0: ensure_vpaned_widget() michael@0: { michael@0: if (!gVPanedWidget) { michael@0: gVPanedWidget = gtk_vpaned_new(); michael@0: setup_widget_prototype(gVPanedWidget); michael@0: } michael@0: return MOZ_GTK_SUCCESS; michael@0: } michael@0: michael@0: static gint michael@0: ensure_toggle_button_widget() michael@0: { michael@0: if (!gToggleButtonWidget) { michael@0: gToggleButtonWidget = gtk_toggle_button_new(); michael@0: setup_widget_prototype(gToggleButtonWidget); michael@0: /* toggle button must be set active to get the right style on hover. */ michael@0: GTK_TOGGLE_BUTTON(gToggleButtonWidget)->active = TRUE; michael@0: } michael@0: return MOZ_GTK_SUCCESS; michael@0: } michael@0: michael@0: static gint michael@0: ensure_button_arrow_widget() michael@0: { michael@0: if (!gButtonArrowWidget) { michael@0: ensure_toggle_button_widget(); michael@0: michael@0: gButtonArrowWidget = gtk_arrow_new(GTK_ARROW_DOWN, GTK_SHADOW_OUT); michael@0: gtk_container_add(GTK_CONTAINER(gToggleButtonWidget), gButtonArrowWidget); michael@0: gtk_widget_realize(gButtonArrowWidget); michael@0: } michael@0: return MOZ_GTK_SUCCESS; michael@0: } michael@0: michael@0: static gint michael@0: ensure_checkbox_widget() michael@0: { michael@0: if (!gCheckboxWidget) { michael@0: gCheckboxWidget = gtk_check_button_new_with_label("M"); michael@0: setup_widget_prototype(gCheckboxWidget); michael@0: } michael@0: return MOZ_GTK_SUCCESS; michael@0: } michael@0: michael@0: static gint michael@0: ensure_radiobutton_widget() michael@0: { michael@0: if (!gRadiobuttonWidget) { michael@0: gRadiobuttonWidget = gtk_radio_button_new_with_label(NULL, "M"); michael@0: setup_widget_prototype(gRadiobuttonWidget); michael@0: } michael@0: return MOZ_GTK_SUCCESS; michael@0: } michael@0: michael@0: static gint michael@0: ensure_scrollbar_widget() michael@0: { michael@0: if (!gVertScrollbarWidget) { michael@0: gVertScrollbarWidget = gtk_vscrollbar_new(NULL); michael@0: setup_widget_prototype(gVertScrollbarWidget); michael@0: } michael@0: if (!gHorizScrollbarWidget) { michael@0: gHorizScrollbarWidget = gtk_hscrollbar_new(NULL); michael@0: setup_widget_prototype(gHorizScrollbarWidget); michael@0: } michael@0: return MOZ_GTK_SUCCESS; michael@0: } michael@0: michael@0: static gint michael@0: ensure_spin_widget() michael@0: { michael@0: if (!gSpinWidget) { michael@0: gSpinWidget = gtk_spin_button_new(NULL, 1, 0); michael@0: setup_widget_prototype(gSpinWidget); michael@0: } michael@0: return MOZ_GTK_SUCCESS; michael@0: } michael@0: michael@0: static gint michael@0: ensure_scale_widget() michael@0: { michael@0: if (!gHScaleWidget) { michael@0: gHScaleWidget = gtk_hscale_new(NULL); michael@0: setup_widget_prototype(gHScaleWidget); michael@0: } michael@0: if (!gVScaleWidget) { michael@0: gVScaleWidget = gtk_vscale_new(NULL); michael@0: setup_widget_prototype(gVScaleWidget); michael@0: } michael@0: return MOZ_GTK_SUCCESS; michael@0: } michael@0: michael@0: static gint michael@0: ensure_entry_widget() michael@0: { michael@0: if (!gEntryWidget) { michael@0: gEntryWidget = gtk_entry_new(); michael@0: setup_widget_prototype(gEntryWidget); michael@0: } michael@0: return MOZ_GTK_SUCCESS; michael@0: } michael@0: michael@0: /* We need to have pointers to the inner widgets (button, separator, arrow) michael@0: * of the ComboBox to get the correct rendering from theme engines which michael@0: * special cases their look. Since the inner layout can change, we ask GTK michael@0: * to NULL our pointers when they are about to become invalid because the michael@0: * corresponding widgets don't exist anymore. It's the role of michael@0: * g_object_add_weak_pointer(). michael@0: * Note that if we don't find the inner widgets (which shouldn't happen), we michael@0: * fallback to use generic "non-inner" widgets, and they don't need that kind michael@0: * of weak pointer since they are explicit children of gProtoWindow and as michael@0: * such GTK holds a strong reference to them. */ michael@0: static void michael@0: moz_gtk_get_combo_box_inner_button(GtkWidget *widget, gpointer client_data) michael@0: { michael@0: if (GTK_IS_TOGGLE_BUTTON(widget)) { michael@0: gComboBoxButtonWidget = widget; michael@0: g_object_add_weak_pointer(G_OBJECT(widget), michael@0: (gpointer) &gComboBoxButtonWidget); michael@0: gtk_widget_realize(widget); michael@0: g_object_set_data(G_OBJECT(widget), "transparent-bg-hint", GINT_TO_POINTER(TRUE)); michael@0: } michael@0: } michael@0: michael@0: static void michael@0: moz_gtk_get_combo_box_button_inner_widgets(GtkWidget *widget, michael@0: gpointer client_data) michael@0: { michael@0: if (GTK_IS_SEPARATOR(widget)) { michael@0: gComboBoxSeparatorWidget = widget; michael@0: g_object_add_weak_pointer(G_OBJECT(widget), michael@0: (gpointer) &gComboBoxSeparatorWidget); michael@0: } else if (GTK_IS_ARROW(widget)) { michael@0: gComboBoxArrowWidget = widget; michael@0: g_object_add_weak_pointer(G_OBJECT(widget), michael@0: (gpointer) &gComboBoxArrowWidget); michael@0: } else michael@0: return; michael@0: gtk_widget_realize(widget); michael@0: g_object_set_data(G_OBJECT(widget), "transparent-bg-hint", GINT_TO_POINTER(TRUE)); michael@0: } michael@0: michael@0: static gint michael@0: ensure_combo_box_widgets() michael@0: { michael@0: GtkWidget* buttonChild; michael@0: michael@0: if (gComboBoxButtonWidget && gComboBoxArrowWidget) michael@0: return MOZ_GTK_SUCCESS; michael@0: michael@0: /* Create a ComboBox if needed */ michael@0: if (!gComboBoxWidget) { michael@0: gComboBoxWidget = gtk_combo_box_new(); michael@0: setup_widget_prototype(gComboBoxWidget); michael@0: } michael@0: michael@0: /* Get its inner Button */ michael@0: gtk_container_forall(GTK_CONTAINER(gComboBoxWidget), michael@0: moz_gtk_get_combo_box_inner_button, michael@0: NULL); michael@0: michael@0: if (gComboBoxButtonWidget) { michael@0: /* Get the widgets inside the Button */ michael@0: buttonChild = GTK_BIN(gComboBoxButtonWidget)->child; michael@0: if (GTK_IS_HBOX(buttonChild)) { michael@0: /* appears-as-list = FALSE, cell-view = TRUE; the button michael@0: * contains an hbox. This hbox is there because the ComboBox michael@0: * needs to place a cell renderer, a separator, and an arrow in michael@0: * the button when appears-as-list is FALSE. */ michael@0: gtk_container_forall(GTK_CONTAINER(buttonChild), michael@0: moz_gtk_get_combo_box_button_inner_widgets, michael@0: NULL); michael@0: } else if(GTK_IS_ARROW(buttonChild)) { michael@0: /* appears-as-list = TRUE, or cell-view = FALSE; michael@0: * the button only contains an arrow */ michael@0: gComboBoxArrowWidget = buttonChild; michael@0: g_object_add_weak_pointer(G_OBJECT(buttonChild), (gpointer) michael@0: &gComboBoxArrowWidget); michael@0: gtk_widget_realize(gComboBoxArrowWidget); michael@0: g_object_set_data(G_OBJECT(gComboBoxArrowWidget), michael@0: "transparent-bg-hint", GINT_TO_POINTER(TRUE)); michael@0: } michael@0: } else { michael@0: /* Shouldn't be reached with current internal gtk implementation; we michael@0: * use a generic toggle button as last resort fallback to avoid michael@0: * crashing. */ michael@0: ensure_toggle_button_widget(); michael@0: gComboBoxButtonWidget = gToggleButtonWidget; michael@0: } michael@0: michael@0: if (!gComboBoxArrowWidget) { michael@0: /* Shouldn't be reached with current internal gtk implementation; michael@0: * we gButtonArrowWidget as last resort fallback to avoid michael@0: * crashing. */ michael@0: ensure_button_arrow_widget(); michael@0: gComboBoxArrowWidget = gButtonArrowWidget; michael@0: } michael@0: michael@0: /* We don't test the validity of gComboBoxSeparatorWidget since there michael@0: * is none when "appears-as-list" = TRUE or "cell-view" = FALSE; if it michael@0: * is invalid we just won't paint it. */ michael@0: michael@0: return MOZ_GTK_SUCCESS; michael@0: } michael@0: michael@0: /* We need to have pointers to the inner widgets (entry, button, arrow) of michael@0: * the ComboBoxEntry to get the correct rendering from theme engines which michael@0: * special cases their look. Since the inner layout can change, we ask GTK michael@0: * to NULL our pointers when they are about to become invalid because the michael@0: * corresponding widgets don't exist anymore. It's the role of michael@0: * g_object_add_weak_pointer(). michael@0: * Note that if we don't find the inner widgets (which shouldn't happen), we michael@0: * fallback to use generic "non-inner" widgets, and they don't need that kind michael@0: * of weak pointer since they are explicit children of gProtoWindow and as michael@0: * such GTK holds a strong reference to them. */ michael@0: static void michael@0: moz_gtk_get_combo_box_entry_inner_widgets(GtkWidget *widget, michael@0: gpointer client_data) michael@0: { michael@0: if (GTK_IS_TOGGLE_BUTTON(widget)) { michael@0: gComboBoxEntryButtonWidget = widget; michael@0: g_object_add_weak_pointer(G_OBJECT(widget), michael@0: (gpointer) &gComboBoxEntryButtonWidget); michael@0: } else if (GTK_IS_ENTRY(widget)) { michael@0: gComboBoxEntryTextareaWidget = widget; michael@0: g_object_add_weak_pointer(G_OBJECT(widget), michael@0: (gpointer) &gComboBoxEntryTextareaWidget); michael@0: } else michael@0: return; michael@0: gtk_widget_realize(widget); michael@0: g_object_set_data(G_OBJECT(widget), "transparent-bg-hint", GINT_TO_POINTER(TRUE)); michael@0: } michael@0: michael@0: static void michael@0: moz_gtk_get_combo_box_entry_arrow(GtkWidget *widget, gpointer client_data) michael@0: { michael@0: if (GTK_IS_ARROW(widget)) { michael@0: gComboBoxEntryArrowWidget = widget; michael@0: g_object_add_weak_pointer(G_OBJECT(widget), michael@0: (gpointer) &gComboBoxEntryArrowWidget); michael@0: gtk_widget_realize(widget); michael@0: g_object_set_data(G_OBJECT(widget), "transparent-bg-hint", GINT_TO_POINTER(TRUE)); michael@0: } michael@0: } michael@0: michael@0: static gint michael@0: ensure_combo_box_entry_widgets() michael@0: { michael@0: GtkWidget* buttonChild; michael@0: michael@0: if (gComboBoxEntryTextareaWidget && michael@0: gComboBoxEntryButtonWidget && michael@0: gComboBoxEntryArrowWidget) michael@0: return MOZ_GTK_SUCCESS; michael@0: michael@0: /* Create a ComboBoxEntry if needed */ michael@0: if (!gComboBoxEntryWidget) { michael@0: gComboBoxEntryWidget = gtk_combo_box_entry_new(); michael@0: setup_widget_prototype(gComboBoxEntryWidget); michael@0: } michael@0: michael@0: /* Get its inner Entry and Button */ michael@0: gtk_container_forall(GTK_CONTAINER(gComboBoxEntryWidget), michael@0: moz_gtk_get_combo_box_entry_inner_widgets, michael@0: NULL); michael@0: michael@0: if (!gComboBoxEntryTextareaWidget) { michael@0: ensure_entry_widget(); michael@0: gComboBoxEntryTextareaWidget = gEntryWidget; michael@0: } michael@0: michael@0: if (gComboBoxEntryButtonWidget) { michael@0: /* Get the Arrow inside the Button */ michael@0: buttonChild = GTK_BIN(gComboBoxEntryButtonWidget)->child; michael@0: if (GTK_IS_HBOX(buttonChild)) { michael@0: /* appears-as-list = FALSE, cell-view = TRUE; the button michael@0: * contains an hbox. This hbox is there because ComboBoxEntry michael@0: * inherits from ComboBox which needs to place a cell renderer, michael@0: * a separator, and an arrow in the button when appears-as-list michael@0: * is FALSE. Here the hbox should only contain an arrow, since michael@0: * a ComboBoxEntry doesn't need all those widgets in the michael@0: * button. */ michael@0: gtk_container_forall(GTK_CONTAINER(buttonChild), michael@0: moz_gtk_get_combo_box_entry_arrow, michael@0: NULL); michael@0: } else if(GTK_IS_ARROW(buttonChild)) { michael@0: /* appears-as-list = TRUE, or cell-view = FALSE; michael@0: * the button only contains an arrow */ michael@0: gComboBoxEntryArrowWidget = buttonChild; michael@0: g_object_add_weak_pointer(G_OBJECT(buttonChild), (gpointer) michael@0: &gComboBoxEntryArrowWidget); michael@0: gtk_widget_realize(gComboBoxEntryArrowWidget); michael@0: g_object_set_data(G_OBJECT(gComboBoxEntryArrowWidget), michael@0: "transparent-bg-hint", GINT_TO_POINTER(TRUE)); michael@0: } michael@0: } else { michael@0: /* Shouldn't be reached with current internal gtk implementation; michael@0: * we use a generic toggle button as last resort fallback to avoid michael@0: * crashing. */ michael@0: ensure_toggle_button_widget(); michael@0: gComboBoxEntryButtonWidget = gToggleButtonWidget; michael@0: } michael@0: michael@0: if (!gComboBoxEntryArrowWidget) { michael@0: /* Shouldn't be reached with current internal gtk implementation; michael@0: * we gButtonArrowWidget as last resort fallback to avoid michael@0: * crashing. */ michael@0: ensure_button_arrow_widget(); michael@0: gComboBoxEntryArrowWidget = gButtonArrowWidget; michael@0: } michael@0: michael@0: return MOZ_GTK_SUCCESS; michael@0: } michael@0: michael@0: michael@0: static gint michael@0: ensure_handlebox_widget() michael@0: { michael@0: if (!gHandleBoxWidget) { michael@0: gHandleBoxWidget = gtk_handle_box_new(); michael@0: setup_widget_prototype(gHandleBoxWidget); michael@0: } michael@0: return MOZ_GTK_SUCCESS; michael@0: } michael@0: michael@0: static gint michael@0: ensure_toolbar_widget() michael@0: { michael@0: if (!gToolbarWidget) { michael@0: ensure_handlebox_widget(); michael@0: gToolbarWidget = gtk_toolbar_new(); michael@0: gtk_container_add(GTK_CONTAINER(gHandleBoxWidget), gToolbarWidget); michael@0: gtk_widget_realize(gToolbarWidget); michael@0: g_object_set_data(G_OBJECT(gToolbarWidget), "transparent-bg-hint", GINT_TO_POINTER(TRUE)); michael@0: } michael@0: return MOZ_GTK_SUCCESS; michael@0: } michael@0: michael@0: static gint michael@0: ensure_toolbar_separator_widget() michael@0: { michael@0: if (!gToolbarSeparatorWidget) { michael@0: ensure_toolbar_widget(); michael@0: gToolbarSeparatorWidget = GTK_WIDGET(gtk_separator_tool_item_new()); michael@0: setup_widget_prototype(gToolbarSeparatorWidget); michael@0: } michael@0: return MOZ_GTK_SUCCESS; michael@0: } michael@0: michael@0: static gint michael@0: ensure_tooltip_widget() michael@0: { michael@0: if (!gTooltipWidget) { michael@0: gTooltipWidget = gtk_window_new(GTK_WINDOW_POPUP); michael@0: gtk_widget_realize(gTooltipWidget); michael@0: moz_gtk_set_widget_name(gTooltipWidget); michael@0: } michael@0: return MOZ_GTK_SUCCESS; michael@0: } michael@0: michael@0: static gint michael@0: ensure_tab_widget() michael@0: { michael@0: if (!gTabWidget) { michael@0: gTabWidget = gtk_notebook_new(); michael@0: setup_widget_prototype(gTabWidget); michael@0: } michael@0: return MOZ_GTK_SUCCESS; michael@0: } michael@0: michael@0: static gint michael@0: ensure_progress_widget() michael@0: { michael@0: if (!gProgressWidget) { michael@0: gProgressWidget = gtk_progress_bar_new(); michael@0: setup_widget_prototype(gProgressWidget); michael@0: } michael@0: return MOZ_GTK_SUCCESS; michael@0: } michael@0: michael@0: static gint michael@0: ensure_statusbar_widget() michael@0: { michael@0: if (!gStatusbarWidget) { michael@0: gStatusbarWidget = gtk_statusbar_new(); michael@0: setup_widget_prototype(gStatusbarWidget); michael@0: } michael@0: return MOZ_GTK_SUCCESS; michael@0: } michael@0: michael@0: static gint michael@0: ensure_frame_widget() michael@0: { michael@0: if (!gFrameWidget) { michael@0: ensure_statusbar_widget(); michael@0: gFrameWidget = gtk_frame_new(NULL); michael@0: gtk_container_add(GTK_CONTAINER(gStatusbarWidget), gFrameWidget); michael@0: gtk_widget_realize(gFrameWidget); michael@0: } michael@0: return MOZ_GTK_SUCCESS; michael@0: } michael@0: michael@0: static gint michael@0: ensure_menu_bar_widget() michael@0: { michael@0: if (!gMenuBarWidget) { michael@0: gMenuBarWidget = gtk_menu_bar_new(); michael@0: setup_widget_prototype(gMenuBarWidget); michael@0: } michael@0: return MOZ_GTK_SUCCESS; michael@0: } michael@0: michael@0: static gint michael@0: ensure_menu_bar_item_widget() michael@0: { michael@0: if (!gMenuBarItemWidget) { michael@0: ensure_menu_bar_widget(); michael@0: gMenuBarItemWidget = gtk_menu_item_new(); michael@0: gtk_menu_shell_append(GTK_MENU_SHELL(gMenuBarWidget), michael@0: gMenuBarItemWidget); michael@0: gtk_widget_realize(gMenuBarItemWidget); michael@0: g_object_set_data(G_OBJECT(gMenuBarItemWidget), michael@0: "transparent-bg-hint", GINT_TO_POINTER(TRUE)); michael@0: } michael@0: return MOZ_GTK_SUCCESS; michael@0: } michael@0: michael@0: static gint michael@0: ensure_menu_popup_widget() michael@0: { michael@0: if (!gMenuPopupWidget) { michael@0: ensure_menu_bar_item_widget(); michael@0: gMenuPopupWidget = gtk_menu_new(); michael@0: gtk_menu_item_set_submenu(GTK_MENU_ITEM(gMenuBarItemWidget), michael@0: gMenuPopupWidget); michael@0: gtk_widget_realize(gMenuPopupWidget); michael@0: g_object_set_data(G_OBJECT(gMenuPopupWidget), michael@0: "transparent-bg-hint", GINT_TO_POINTER(TRUE)); michael@0: } michael@0: return MOZ_GTK_SUCCESS; michael@0: } michael@0: michael@0: static gint michael@0: ensure_menu_item_widget() michael@0: { michael@0: if (!gMenuItemWidget) { michael@0: ensure_menu_popup_widget(); michael@0: gMenuItemWidget = gtk_menu_item_new_with_label("M"); michael@0: gtk_menu_shell_append(GTK_MENU_SHELL(gMenuPopupWidget), michael@0: gMenuItemWidget); michael@0: gtk_widget_realize(gMenuItemWidget); michael@0: g_object_set_data(G_OBJECT(gMenuItemWidget), michael@0: "transparent-bg-hint", GINT_TO_POINTER(TRUE)); michael@0: } michael@0: return MOZ_GTK_SUCCESS; michael@0: } michael@0: michael@0: static gint michael@0: ensure_image_menu_item_widget() michael@0: { michael@0: if (!gImageMenuItemWidget) { michael@0: ensure_menu_popup_widget(); michael@0: gImageMenuItemWidget = gtk_image_menu_item_new(); michael@0: gtk_menu_shell_append(GTK_MENU_SHELL(gMenuPopupWidget), michael@0: gImageMenuItemWidget); michael@0: gtk_widget_realize(gImageMenuItemWidget); michael@0: g_object_set_data(G_OBJECT(gImageMenuItemWidget), michael@0: "transparent-bg-hint", GINT_TO_POINTER(TRUE)); michael@0: } michael@0: return MOZ_GTK_SUCCESS; michael@0: } michael@0: michael@0: static gint michael@0: ensure_menu_separator_widget() michael@0: { michael@0: if (!gMenuSeparatorWidget) { michael@0: ensure_menu_popup_widget(); michael@0: gMenuSeparatorWidget = gtk_separator_menu_item_new(); michael@0: gtk_menu_shell_append(GTK_MENU_SHELL(gMenuPopupWidget), michael@0: gMenuSeparatorWidget); michael@0: gtk_widget_realize(gMenuSeparatorWidget); michael@0: g_object_set_data(G_OBJECT(gMenuSeparatorWidget), michael@0: "transparent-bg-hint", GINT_TO_POINTER(TRUE)); michael@0: } michael@0: return MOZ_GTK_SUCCESS; michael@0: } michael@0: michael@0: static gint michael@0: ensure_check_menu_item_widget() michael@0: { michael@0: if (!gCheckMenuItemWidget) { michael@0: ensure_menu_popup_widget(); michael@0: gCheckMenuItemWidget = gtk_check_menu_item_new_with_label("M"); michael@0: gtk_menu_shell_append(GTK_MENU_SHELL(gMenuPopupWidget), michael@0: gCheckMenuItemWidget); michael@0: gtk_widget_realize(gCheckMenuItemWidget); michael@0: g_object_set_data(G_OBJECT(gCheckMenuItemWidget), michael@0: "transparent-bg-hint", GINT_TO_POINTER(TRUE)); michael@0: } michael@0: return MOZ_GTK_SUCCESS; michael@0: } michael@0: michael@0: static gint michael@0: ensure_tree_view_widget() michael@0: { michael@0: if (!gTreeViewWidget) { michael@0: gTreeViewWidget = gtk_tree_view_new(); michael@0: setup_widget_prototype(gTreeViewWidget); michael@0: } michael@0: return MOZ_GTK_SUCCESS; michael@0: } michael@0: michael@0: static gint michael@0: ensure_tree_header_cell_widget() michael@0: { michael@0: if(!gTreeHeaderCellWidget) { michael@0: /* michael@0: * Some GTK engines paint the first and last cell michael@0: * of a TreeView header with a highlight. michael@0: * Since we do not know where our widget will be relative michael@0: * to the other buttons in the TreeView header, we must michael@0: * paint it as a button that is between two others, michael@0: * thus ensuring it is neither the first or last button michael@0: * in the header. michael@0: * GTK doesn't give us a way to do this explicitly, michael@0: * so we must paint with a button that is between two michael@0: * others. michael@0: */ michael@0: michael@0: GtkTreeViewColumn* firstTreeViewColumn; michael@0: GtkTreeViewColumn* lastTreeViewColumn; michael@0: michael@0: ensure_tree_view_widget(); michael@0: michael@0: /* Create and append our three columns */ michael@0: firstTreeViewColumn = gtk_tree_view_column_new(); michael@0: gtk_tree_view_column_set_title(firstTreeViewColumn, "M"); michael@0: gtk_tree_view_append_column(GTK_TREE_VIEW(gTreeViewWidget), firstTreeViewColumn); michael@0: michael@0: gMiddleTreeViewColumn = gtk_tree_view_column_new(); michael@0: gtk_tree_view_column_set_title(gMiddleTreeViewColumn, "M"); michael@0: gtk_tree_view_append_column(GTK_TREE_VIEW(gTreeViewWidget), michael@0: gMiddleTreeViewColumn); michael@0: michael@0: lastTreeViewColumn = gtk_tree_view_column_new(); michael@0: gtk_tree_view_column_set_title(lastTreeViewColumn, "M"); michael@0: gtk_tree_view_append_column(GTK_TREE_VIEW(gTreeViewWidget), lastTreeViewColumn); michael@0: michael@0: /* Use the middle column's header for our button */ michael@0: gTreeHeaderCellWidget = gMiddleTreeViewColumn->button; michael@0: gTreeHeaderSortArrowWidget = gMiddleTreeViewColumn->arrow; michael@0: g_object_set_data(G_OBJECT(gTreeHeaderCellWidget), michael@0: "transparent-bg-hint", GINT_TO_POINTER(TRUE)); michael@0: g_object_set_data(G_OBJECT(gTreeHeaderSortArrowWidget), michael@0: "transparent-bg-hint", GINT_TO_POINTER(TRUE)); michael@0: } michael@0: return MOZ_GTK_SUCCESS; michael@0: } michael@0: michael@0: static gint michael@0: ensure_expander_widget() michael@0: { michael@0: if (!gExpanderWidget) { michael@0: gExpanderWidget = gtk_expander_new("M"); michael@0: setup_widget_prototype(gExpanderWidget); michael@0: } michael@0: return MOZ_GTK_SUCCESS; michael@0: } michael@0: michael@0: static gint michael@0: ensure_scrolled_window_widget() michael@0: { michael@0: if (!gScrolledWindowWidget) { michael@0: gScrolledWindowWidget = gtk_scrolled_window_new(NULL, NULL); michael@0: setup_widget_prototype(gScrolledWindowWidget); michael@0: } michael@0: return MOZ_GTK_SUCCESS; michael@0: } michael@0: michael@0: static GtkStateType michael@0: ConvertGtkState(GtkWidgetState* state) michael@0: { michael@0: if (state->disabled) michael@0: return GTK_STATE_INSENSITIVE; michael@0: else if (state->depressed) michael@0: return (state->inHover ? GTK_STATE_PRELIGHT : GTK_STATE_ACTIVE); michael@0: else if (state->inHover) michael@0: return (state->active ? GTK_STATE_ACTIVE : GTK_STATE_PRELIGHT); michael@0: else michael@0: return GTK_STATE_NORMAL; michael@0: } michael@0: michael@0: static gint michael@0: TSOffsetStyleGCArray(GdkGC** gcs, gint xorigin, gint yorigin) michael@0: { michael@0: int i; michael@0: /* there are 5 gc's in each array, for each of the widget states */ michael@0: for (i = 0; i < 5; ++i) michael@0: gdk_gc_set_ts_origin(gcs[i], xorigin, yorigin); michael@0: return MOZ_GTK_SUCCESS; michael@0: } michael@0: michael@0: static gint michael@0: TSOffsetStyleGCs(GtkStyle* style, gint xorigin, gint yorigin) michael@0: { michael@0: TSOffsetStyleGCArray(style->fg_gc, xorigin, yorigin); michael@0: TSOffsetStyleGCArray(style->bg_gc, xorigin, yorigin); michael@0: TSOffsetStyleGCArray(style->light_gc, xorigin, yorigin); michael@0: TSOffsetStyleGCArray(style->dark_gc, xorigin, yorigin); michael@0: TSOffsetStyleGCArray(style->mid_gc, xorigin, yorigin); michael@0: TSOffsetStyleGCArray(style->text_gc, xorigin, yorigin); michael@0: TSOffsetStyleGCArray(style->base_gc, xorigin, yorigin); michael@0: gdk_gc_set_ts_origin(style->black_gc, xorigin, yorigin); michael@0: gdk_gc_set_ts_origin(style->white_gc, xorigin, yorigin); michael@0: return MOZ_GTK_SUCCESS; michael@0: } michael@0: michael@0: gint michael@0: moz_gtk_init() michael@0: { michael@0: GtkWidgetClass *entry_class; michael@0: michael@0: if (is_initialized) michael@0: return MOZ_GTK_SUCCESS; michael@0: michael@0: is_initialized = TRUE; michael@0: have_arrow_scaling = (gtk_major_version > 2 || michael@0: (gtk_major_version == 2 && gtk_minor_version >= 12)); michael@0: michael@0: /* Add style property to GtkEntry. michael@0: * Adding the style property to the normal GtkEntry class means that it michael@0: * will work without issues inside GtkComboBox and for Spinbuttons. */ michael@0: entry_class = g_type_class_ref(GTK_TYPE_ENTRY); michael@0: gtk_widget_class_install_style_property(entry_class, michael@0: g_param_spec_boolean("honors-transparent-bg-hint", michael@0: "Transparent BG enabling flag", michael@0: "If TRUE, the theme is able to draw the GtkEntry on non-prefilled background.", michael@0: FALSE, michael@0: G_PARAM_READWRITE)); michael@0: michael@0: return MOZ_GTK_SUCCESS; michael@0: } michael@0: michael@0: GdkColormap* michael@0: moz_gtk_widget_get_colormap() michael@0: { michael@0: /* Child widgets inherit the colormap from the GtkWindow. */ michael@0: ensure_window_widget(); michael@0: return gtk_widget_get_colormap(gProtoWindow); michael@0: } michael@0: michael@0: gint michael@0: moz_gtk_checkbox_get_metrics(gint* indicator_size, gint* indicator_spacing) michael@0: { michael@0: ensure_checkbox_widget(); michael@0: michael@0: gtk_widget_style_get (gCheckboxWidget, michael@0: "indicator_size", indicator_size, michael@0: "indicator_spacing", indicator_spacing, michael@0: NULL); michael@0: michael@0: return MOZ_GTK_SUCCESS; michael@0: } michael@0: michael@0: gint michael@0: moz_gtk_radio_get_metrics(gint* indicator_size, gint* indicator_spacing) michael@0: { michael@0: ensure_radiobutton_widget(); michael@0: michael@0: gtk_widget_style_get (gRadiobuttonWidget, michael@0: "indicator_size", indicator_size, michael@0: "indicator_spacing", indicator_spacing, michael@0: NULL); michael@0: michael@0: return MOZ_GTK_SUCCESS; michael@0: } michael@0: michael@0: gint michael@0: moz_gtk_widget_get_focus(GtkWidget* widget, gboolean* interior_focus, michael@0: gint* focus_width, gint* focus_pad) michael@0: { michael@0: gtk_widget_style_get (widget, michael@0: "interior-focus", interior_focus, michael@0: "focus-line-width", focus_width, michael@0: "focus-padding", focus_pad, michael@0: NULL); michael@0: michael@0: return MOZ_GTK_SUCCESS; michael@0: } michael@0: michael@0: gint michael@0: moz_gtk_menuitem_get_horizontal_padding(gint* horizontal_padding) michael@0: { michael@0: ensure_menu_item_widget(); michael@0: michael@0: gtk_widget_style_get (gMenuItemWidget, michael@0: "horizontal-padding", horizontal_padding, michael@0: NULL); michael@0: michael@0: return MOZ_GTK_SUCCESS; michael@0: } michael@0: michael@0: gint michael@0: moz_gtk_checkmenuitem_get_horizontal_padding(gint* horizontal_padding) michael@0: { michael@0: ensure_check_menu_item_widget(); michael@0: michael@0: gtk_widget_style_get (gCheckMenuItemWidget, michael@0: "horizontal-padding", horizontal_padding, michael@0: NULL); michael@0: michael@0: return MOZ_GTK_SUCCESS; michael@0: } michael@0: michael@0: gint michael@0: moz_gtk_button_get_default_overflow(gint* border_top, gint* border_left, michael@0: gint* border_bottom, gint* border_right) michael@0: { michael@0: GtkBorder* default_outside_border; michael@0: michael@0: ensure_button_widget(); michael@0: gtk_widget_style_get(gButtonWidget, michael@0: "default-outside-border", &default_outside_border, michael@0: NULL); michael@0: michael@0: if (default_outside_border) { michael@0: *border_top = default_outside_border->top; michael@0: *border_left = default_outside_border->left; michael@0: *border_bottom = default_outside_border->bottom; michael@0: *border_right = default_outside_border->right; michael@0: gtk_border_free(default_outside_border); michael@0: } else { michael@0: *border_top = *border_left = *border_bottom = *border_right = 0; michael@0: } michael@0: return MOZ_GTK_SUCCESS; michael@0: } michael@0: michael@0: static gint michael@0: moz_gtk_button_get_default_border(gint* border_top, gint* border_left, michael@0: gint* border_bottom, gint* border_right) michael@0: { michael@0: GtkBorder* default_border; michael@0: michael@0: ensure_button_widget(); michael@0: gtk_widget_style_get(gButtonWidget, michael@0: "default-border", &default_border, michael@0: NULL); michael@0: michael@0: if (default_border) { michael@0: *border_top = default_border->top; michael@0: *border_left = default_border->left; michael@0: *border_bottom = default_border->bottom; michael@0: *border_right = default_border->right; michael@0: gtk_border_free(default_border); michael@0: } else { michael@0: /* see gtkbutton.c */ michael@0: *border_top = *border_left = *border_bottom = *border_right = 1; michael@0: } michael@0: return MOZ_GTK_SUCCESS; michael@0: } michael@0: michael@0: gint michael@0: moz_gtk_splitter_get_metrics(gint orientation, gint* size) michael@0: { michael@0: if (orientation == GTK_ORIENTATION_HORIZONTAL) { michael@0: ensure_hpaned_widget(); michael@0: gtk_widget_style_get(gHPanedWidget, "handle_size", size, NULL); michael@0: } else { michael@0: ensure_vpaned_widget(); michael@0: gtk_widget_style_get(gVPanedWidget, "handle_size", size, NULL); michael@0: } michael@0: return MOZ_GTK_SUCCESS; michael@0: } michael@0: michael@0: gint michael@0: moz_gtk_button_get_inner_border(GtkWidget* widget, GtkBorder* inner_border) michael@0: { michael@0: static const GtkBorder default_inner_border = { 1, 1, 1, 1 }; michael@0: GtkBorder *tmp_border; michael@0: michael@0: gtk_widget_style_get (widget, "inner-border", &tmp_border, NULL); michael@0: michael@0: if (tmp_border) { michael@0: *inner_border = *tmp_border; michael@0: gtk_border_free(tmp_border); michael@0: } michael@0: else michael@0: *inner_border = default_inner_border; michael@0: michael@0: return MOZ_GTK_SUCCESS; michael@0: } michael@0: michael@0: static gint michael@0: moz_gtk_button_paint(GdkDrawable* drawable, GdkRectangle* rect, michael@0: GdkRectangle* cliprect, GtkWidgetState* state, michael@0: GtkReliefStyle relief, GtkWidget* widget, michael@0: GtkTextDirection direction) michael@0: { michael@0: GtkShadowType shadow_type; michael@0: GtkStyle* style = widget->style; michael@0: GtkStateType button_state = ConvertGtkState(state); michael@0: gint x = rect->x, y=rect->y, width=rect->width, height=rect->height; michael@0: michael@0: gboolean interior_focus; michael@0: gint focus_width, focus_pad; michael@0: michael@0: moz_gtk_widget_get_focus(widget, &interior_focus, &focus_width, &focus_pad); michael@0: michael@0: if (WINDOW_IS_MAPPED(drawable)) { michael@0: gdk_window_set_back_pixmap(drawable, NULL, TRUE); michael@0: gdk_window_clear_area(drawable, cliprect->x, cliprect->y, michael@0: cliprect->width, cliprect->height); michael@0: } michael@0: michael@0: gtk_widget_set_state(widget, button_state); michael@0: gtk_widget_set_direction(widget, direction); michael@0: michael@0: if (state->isDefault) michael@0: GTK_WIDGET_SET_FLAGS(widget, GTK_HAS_DEFAULT); michael@0: michael@0: GTK_BUTTON(widget)->relief = relief; michael@0: michael@0: /* Some theme engines love to cause us pain in that gtk_paint_focus is a michael@0: no-op on buttons and button-like widgets. They only listen to this flag. */ michael@0: if (state->focused && !state->disabled) michael@0: GTK_WIDGET_SET_FLAGS(widget, GTK_HAS_FOCUS); michael@0: michael@0: if (!interior_focus && state->focused) { michael@0: x += focus_width + focus_pad; michael@0: y += focus_width + focus_pad; michael@0: width -= 2 * (focus_width + focus_pad); michael@0: height -= 2 * (focus_width + focus_pad); michael@0: } michael@0: michael@0: shadow_type = button_state == GTK_STATE_ACTIVE || michael@0: state->depressed ? GTK_SHADOW_IN : GTK_SHADOW_OUT; michael@0: michael@0: if (state->isDefault && relief == GTK_RELIEF_NORMAL) { michael@0: /* handle default borders both outside and inside the button */ michael@0: gint default_top, default_left, default_bottom, default_right; michael@0: moz_gtk_button_get_default_overflow(&default_top, &default_left, michael@0: &default_bottom, &default_right); michael@0: x -= default_left; michael@0: y -= default_top; michael@0: width += default_left + default_right; michael@0: height += default_top + default_bottom; michael@0: gtk_paint_box(style, drawable, GTK_STATE_NORMAL, GTK_SHADOW_IN, cliprect, michael@0: widget, "buttondefault", x, y, width, height); michael@0: michael@0: moz_gtk_button_get_default_border(&default_top, &default_left, michael@0: &default_bottom, &default_right); michael@0: x += default_left; michael@0: y += default_top; michael@0: width -= (default_left + default_right); michael@0: height -= (default_top + default_bottom); michael@0: } michael@0: michael@0: if (relief != GTK_RELIEF_NONE || state->depressed || michael@0: (button_state != GTK_STATE_NORMAL && michael@0: button_state != GTK_STATE_INSENSITIVE)) { michael@0: TSOffsetStyleGCs(style, x, y); michael@0: /* the following line can trigger an assertion (Crux theme) michael@0: file ../../gdk/gdkwindow.c: line 1846 (gdk_window_clear_area): michael@0: assertion `GDK_IS_WINDOW (window)' failed */ michael@0: gtk_paint_box(style, drawable, button_state, shadow_type, cliprect, michael@0: widget, "button", x, y, width, height); michael@0: } michael@0: michael@0: if (state->focused) { michael@0: if (interior_focus) { michael@0: x += widget->style->xthickness + focus_pad; michael@0: y += widget->style->ythickness + focus_pad; michael@0: width -= 2 * (widget->style->xthickness + focus_pad); michael@0: height -= 2 * (widget->style->ythickness + focus_pad); michael@0: } else { michael@0: x -= focus_width + focus_pad; michael@0: y -= focus_width + focus_pad; michael@0: width += 2 * (focus_width + focus_pad); michael@0: height += 2 * (focus_width + focus_pad); michael@0: } michael@0: michael@0: TSOffsetStyleGCs(style, x, y); michael@0: gtk_paint_focus(style, drawable, button_state, cliprect, michael@0: widget, "button", x, y, width, height); michael@0: } michael@0: michael@0: GTK_WIDGET_UNSET_FLAGS(widget, GTK_HAS_DEFAULT); michael@0: GTK_WIDGET_UNSET_FLAGS(widget, GTK_HAS_FOCUS); michael@0: return MOZ_GTK_SUCCESS; michael@0: } michael@0: michael@0: static gint michael@0: moz_gtk_toggle_paint(GdkDrawable* drawable, GdkRectangle* rect, michael@0: GdkRectangle* cliprect, GtkWidgetState* state, michael@0: gboolean selected, gboolean inconsistent, michael@0: gboolean isradio, GtkTextDirection direction) michael@0: { michael@0: GtkStateType state_type = ConvertGtkState(state); michael@0: GtkShadowType shadow_type = (selected)?GTK_SHADOW_IN:GTK_SHADOW_OUT; michael@0: gint indicator_size, indicator_spacing; michael@0: gint x, y, width, height; michael@0: gint focus_x, focus_y, focus_width, focus_height; michael@0: GtkWidget *w; michael@0: GtkStyle *style; michael@0: michael@0: if (isradio) { michael@0: moz_gtk_radio_get_metrics(&indicator_size, &indicator_spacing); michael@0: w = gRadiobuttonWidget; michael@0: } else { michael@0: moz_gtk_checkbox_get_metrics(&indicator_size, &indicator_spacing); michael@0: w = gCheckboxWidget; michael@0: } michael@0: michael@0: // XXX we should assert rect->height >= indicator_size too michael@0: // after bug 369581 is fixed. michael@0: NS_ASSERTION(rect->width >= indicator_size, michael@0: "GetMinimumWidgetSize was ignored"); michael@0: michael@0: // Paint it center aligned in the rect. michael@0: x = rect->x + (rect->width - indicator_size) / 2; michael@0: y = rect->y + (rect->height - indicator_size) / 2; michael@0: width = indicator_size; michael@0: height = indicator_size; michael@0: michael@0: focus_x = x - indicator_spacing; michael@0: focus_y = y - indicator_spacing; michael@0: focus_width = width + 2 * indicator_spacing; michael@0: focus_height = height + 2 * indicator_spacing; michael@0: michael@0: style = w->style; michael@0: TSOffsetStyleGCs(style, x, y); michael@0: michael@0: gtk_widget_set_sensitive(w, !state->disabled); michael@0: gtk_widget_set_direction(w, direction); michael@0: GTK_TOGGLE_BUTTON(w)->active = selected; michael@0: michael@0: if (isradio) { michael@0: gtk_paint_option(style, drawable, state_type, shadow_type, cliprect, michael@0: gRadiobuttonWidget, "radiobutton", x, y, michael@0: width, height); michael@0: if (state->focused) { michael@0: gtk_paint_focus(style, drawable, GTK_STATE_ACTIVE, cliprect, michael@0: gRadiobuttonWidget, "radiobutton", focus_x, focus_y, michael@0: focus_width, focus_height); michael@0: } michael@0: } michael@0: else { michael@0: /* michael@0: * 'indeterminate' type on checkboxes. In GTK, the shadow type michael@0: * must also be changed for the state to be drawn. michael@0: */ michael@0: if (inconsistent) { michael@0: gtk_toggle_button_set_inconsistent(GTK_TOGGLE_BUTTON(gCheckboxWidget), TRUE); michael@0: shadow_type = GTK_SHADOW_ETCHED_IN; michael@0: } else { michael@0: gtk_toggle_button_set_inconsistent(GTK_TOGGLE_BUTTON(gCheckboxWidget), FALSE); michael@0: } michael@0: michael@0: gtk_paint_check(style, drawable, state_type, shadow_type, cliprect, michael@0: gCheckboxWidget, "checkbutton", x, y, width, height); michael@0: if (state->focused) { michael@0: gtk_paint_focus(style, drawable, GTK_STATE_ACTIVE, cliprect, michael@0: gCheckboxWidget, "checkbutton", focus_x, focus_y, michael@0: focus_width, focus_height); michael@0: } michael@0: } michael@0: michael@0: return MOZ_GTK_SUCCESS; michael@0: } michael@0: michael@0: static gint michael@0: calculate_button_inner_rect(GtkWidget* button, GdkRectangle* rect, michael@0: GdkRectangle* inner_rect, michael@0: GtkTextDirection direction, michael@0: gboolean ignore_focus) michael@0: { michael@0: GtkBorder inner_border; michael@0: gboolean interior_focus; michael@0: gint focus_width, focus_pad; michael@0: GtkStyle* style; michael@0: michael@0: style = button->style; michael@0: michael@0: /* This mirrors gtkbutton's child positioning */ michael@0: moz_gtk_button_get_inner_border(button, &inner_border); michael@0: moz_gtk_widget_get_focus(button, &interior_focus, michael@0: &focus_width, &focus_pad); michael@0: michael@0: if (ignore_focus) michael@0: focus_width = focus_pad = 0; michael@0: michael@0: inner_rect->x = rect->x + XTHICKNESS(style) + focus_width + focus_pad; michael@0: inner_rect->x += direction == GTK_TEXT_DIR_LTR ? michael@0: inner_border.left : inner_border.right; michael@0: inner_rect->y = rect->y + inner_border.top + YTHICKNESS(style) + michael@0: focus_width + focus_pad; michael@0: inner_rect->width = MAX(1, rect->width - inner_border.left - michael@0: inner_border.right - (XTHICKNESS(style) + focus_pad + focus_width) * 2); michael@0: inner_rect->height = MAX(1, rect->height - inner_border.top - michael@0: inner_border.bottom - (YTHICKNESS(style) + focus_pad + focus_width) * 2); michael@0: michael@0: return MOZ_GTK_SUCCESS; michael@0: } michael@0: michael@0: michael@0: static gint michael@0: calculate_arrow_rect(GtkWidget* arrow, GdkRectangle* rect, michael@0: GdkRectangle* arrow_rect, GtkTextDirection direction) michael@0: { michael@0: /* defined in gtkarrow.c */ michael@0: gfloat arrow_scaling = 0.7; michael@0: gfloat xalign, xpad; michael@0: gint extent; michael@0: GtkMisc* misc = GTK_MISC(arrow); michael@0: michael@0: if (have_arrow_scaling) michael@0: gtk_widget_style_get(arrow, "arrow_scaling", &arrow_scaling, NULL); michael@0: michael@0: extent = MIN((rect->width - misc->xpad * 2), michael@0: (rect->height - misc->ypad * 2)) * arrow_scaling; michael@0: michael@0: xalign = direction == GTK_TEXT_DIR_LTR ? misc->xalign : 1.0 - misc->xalign; michael@0: xpad = misc->xpad + (rect->width - extent) * xalign; michael@0: michael@0: arrow_rect->x = direction == GTK_TEXT_DIR_LTR ? michael@0: floor(rect->x + xpad) : ceil(rect->x + xpad); michael@0: arrow_rect->y = floor(rect->y + misc->ypad + michael@0: ((rect->height - extent) * misc->yalign)); michael@0: michael@0: arrow_rect->width = arrow_rect->height = extent; michael@0: michael@0: return MOZ_GTK_SUCCESS; michael@0: } michael@0: michael@0: static gint michael@0: moz_gtk_scrollbar_button_paint(GdkDrawable* drawable, GdkRectangle* rect, michael@0: GdkRectangle* cliprect, GtkWidgetState* state, michael@0: GtkScrollbarButtonFlags flags, michael@0: GtkTextDirection direction) michael@0: { michael@0: GtkStateType state_type = ConvertGtkState(state); michael@0: GtkShadowType shadow_type = (state->active) ? michael@0: GTK_SHADOW_IN : GTK_SHADOW_OUT; michael@0: GdkRectangle arrow_rect; michael@0: GtkStyle* style; michael@0: GtkWidget *scrollbar; michael@0: GtkArrowType arrow_type; michael@0: gint arrow_displacement_x, arrow_displacement_y; michael@0: const char* detail = (flags & MOZ_GTK_STEPPER_VERTICAL) ? michael@0: "vscrollbar" : "hscrollbar"; michael@0: michael@0: ensure_scrollbar_widget(); michael@0: michael@0: if (flags & MOZ_GTK_STEPPER_VERTICAL) michael@0: scrollbar = gVertScrollbarWidget; michael@0: else michael@0: scrollbar = gHorizScrollbarWidget; michael@0: michael@0: gtk_widget_set_direction(scrollbar, direction); michael@0: michael@0: /* Some theme engines (i.e., ClearLooks) check the scrollbar's allocation michael@0: to determine where it should paint rounded corners on the buttons. michael@0: We need to trick them into drawing the buttons the way we want them. */ michael@0: michael@0: scrollbar->allocation.x = rect->x; michael@0: scrollbar->allocation.y = rect->y; michael@0: scrollbar->allocation.width = rect->width; michael@0: scrollbar->allocation.height = rect->height; michael@0: michael@0: if (flags & MOZ_GTK_STEPPER_VERTICAL) { michael@0: scrollbar->allocation.height *= 5; michael@0: if (flags & MOZ_GTK_STEPPER_DOWN) { michael@0: arrow_type = GTK_ARROW_DOWN; michael@0: if (flags & MOZ_GTK_STEPPER_BOTTOM) michael@0: scrollbar->allocation.y -= 4 * rect->height; michael@0: else michael@0: scrollbar->allocation.y -= rect->height; michael@0: michael@0: } else { michael@0: arrow_type = GTK_ARROW_UP; michael@0: if (flags & MOZ_GTK_STEPPER_BOTTOM) michael@0: scrollbar->allocation.y -= 3 * rect->height; michael@0: } michael@0: } else { michael@0: scrollbar->allocation.width *= 5; michael@0: if (flags & MOZ_GTK_STEPPER_DOWN) { michael@0: arrow_type = GTK_ARROW_RIGHT; michael@0: if (flags & MOZ_GTK_STEPPER_BOTTOM) michael@0: scrollbar->allocation.x -= 4 * rect->width; michael@0: else michael@0: scrollbar->allocation.x -= rect->width; michael@0: } else { michael@0: arrow_type = GTK_ARROW_LEFT; michael@0: if (flags & MOZ_GTK_STEPPER_BOTTOM) michael@0: scrollbar->allocation.x -= 3 * rect->width; michael@0: } michael@0: } michael@0: michael@0: style = scrollbar->style; michael@0: michael@0: TSOffsetStyleGCs(style, rect->x, rect->y); michael@0: michael@0: gtk_paint_box(style, drawable, state_type, shadow_type, cliprect, michael@0: scrollbar, detail, rect->x, rect->y, michael@0: rect->width, rect->height); michael@0: michael@0: arrow_rect.width = rect->width / 2; michael@0: arrow_rect.height = rect->height / 2; michael@0: arrow_rect.x = rect->x + (rect->width - arrow_rect.width) / 2; michael@0: arrow_rect.y = rect->y + (rect->height - arrow_rect.height) / 2; michael@0: michael@0: if (state_type == GTK_STATE_ACTIVE) { michael@0: gtk_widget_style_get(scrollbar, michael@0: "arrow-displacement-x", &arrow_displacement_x, michael@0: "arrow-displacement-y", &arrow_displacement_y, michael@0: NULL); michael@0: michael@0: arrow_rect.x += arrow_displacement_x; michael@0: arrow_rect.y += arrow_displacement_y; michael@0: } michael@0: michael@0: gtk_paint_arrow(style, drawable, state_type, shadow_type, cliprect, michael@0: scrollbar, detail, arrow_type, TRUE, arrow_rect.x, michael@0: arrow_rect.y, arrow_rect.width, arrow_rect.height); michael@0: michael@0: return MOZ_GTK_SUCCESS; michael@0: } michael@0: michael@0: static gint michael@0: moz_gtk_scrollbar_trough_paint(GtkThemeWidgetType widget, michael@0: GdkDrawable* drawable, GdkRectangle* rect, michael@0: GdkRectangle* cliprect, GtkWidgetState* state, michael@0: GtkTextDirection direction) michael@0: { michael@0: GtkStyle* style; michael@0: GtkScrollbar *scrollbar; michael@0: michael@0: ensure_scrollbar_widget(); michael@0: michael@0: if (widget == MOZ_GTK_SCROLLBAR_TRACK_HORIZONTAL) michael@0: scrollbar = GTK_SCROLLBAR(gHorizScrollbarWidget); michael@0: else michael@0: scrollbar = GTK_SCROLLBAR(gVertScrollbarWidget); michael@0: michael@0: gtk_widget_set_direction(GTK_WIDGET(scrollbar), direction); michael@0: michael@0: style = GTK_WIDGET(scrollbar)->style; michael@0: michael@0: TSOffsetStyleGCs(style, rect->x, rect->y); michael@0: gtk_style_apply_default_background(style, drawable, TRUE, GTK_STATE_ACTIVE, michael@0: cliprect, rect->x, rect->y, michael@0: rect->width, rect->height); michael@0: michael@0: gtk_paint_box(style, drawable, GTK_STATE_ACTIVE, GTK_SHADOW_IN, cliprect, michael@0: GTK_WIDGET(scrollbar), "trough", rect->x, rect->y, michael@0: rect->width, rect->height); michael@0: michael@0: if (state->focused) { michael@0: gtk_paint_focus(style, drawable, GTK_STATE_ACTIVE, cliprect, michael@0: GTK_WIDGET(scrollbar), "trough", michael@0: rect->x, rect->y, rect->width, rect->height); michael@0: } michael@0: michael@0: return MOZ_GTK_SUCCESS; michael@0: } michael@0: michael@0: static gint michael@0: moz_gtk_scrollbar_thumb_paint(GtkThemeWidgetType widget, michael@0: GdkDrawable* drawable, GdkRectangle* rect, michael@0: GdkRectangle* cliprect, GtkWidgetState* state, michael@0: GtkTextDirection direction) michael@0: { michael@0: GtkStateType state_type = (state->inHover || state->active) ? michael@0: GTK_STATE_PRELIGHT : GTK_STATE_NORMAL; michael@0: GtkShadowType shadow_type = GTK_SHADOW_OUT; michael@0: GtkStyle* style; michael@0: GtkScrollbar *scrollbar; michael@0: GtkAdjustment *adj; michael@0: gboolean activate_slider; michael@0: michael@0: ensure_scrollbar_widget(); michael@0: michael@0: if (widget == MOZ_GTK_SCROLLBAR_THUMB_HORIZONTAL) michael@0: scrollbar = GTK_SCROLLBAR(gHorizScrollbarWidget); michael@0: else michael@0: scrollbar = GTK_SCROLLBAR(gVertScrollbarWidget); michael@0: michael@0: gtk_widget_set_direction(GTK_WIDGET(scrollbar), direction); michael@0: michael@0: /* Make sure to set the scrollbar range before painting so that michael@0: everything is drawn properly. At least the bluecurve (and michael@0: maybe other) themes don't draw the top or bottom black line michael@0: surrounding the scrollbar if the theme thinks that it's butted michael@0: up against the scrollbar arrows. Note the increases of the michael@0: clip rect below. */ michael@0: adj = gtk_range_get_adjustment(GTK_RANGE(scrollbar)); michael@0: michael@0: if (widget == MOZ_GTK_SCROLLBAR_THUMB_HORIZONTAL) { michael@0: adj->page_size = rect->width; michael@0: } michael@0: else { michael@0: adj->page_size = rect->height; michael@0: } michael@0: michael@0: adj->lower = 0; michael@0: adj->value = state->curpos; michael@0: adj->upper = state->maxpos; michael@0: gtk_adjustment_changed(adj); michael@0: michael@0: style = GTK_WIDGET(scrollbar)->style; michael@0: michael@0: gtk_widget_style_get(GTK_WIDGET(scrollbar), "activate-slider", michael@0: &activate_slider, NULL); michael@0: michael@0: if (activate_slider && state->active) { michael@0: shadow_type = GTK_SHADOW_IN; michael@0: state_type = GTK_STATE_ACTIVE; michael@0: } michael@0: michael@0: TSOffsetStyleGCs(style, rect->x, rect->y); michael@0: michael@0: gtk_paint_slider(style, drawable, state_type, shadow_type, cliprect, michael@0: GTK_WIDGET(scrollbar), "slider", rect->x, rect->y, michael@0: rect->width, rect->height, michael@0: (widget == MOZ_GTK_SCROLLBAR_THUMB_HORIZONTAL) ? michael@0: GTK_ORIENTATION_HORIZONTAL : GTK_ORIENTATION_VERTICAL); michael@0: michael@0: return MOZ_GTK_SUCCESS; michael@0: } michael@0: michael@0: static gint michael@0: moz_gtk_spin_paint(GdkDrawable* drawable, GdkRectangle* rect, michael@0: GtkTextDirection direction) michael@0: { michael@0: GtkStyle* style; michael@0: michael@0: ensure_spin_widget(); michael@0: gtk_widget_set_direction(gSpinWidget, direction); michael@0: style = gSpinWidget->style; michael@0: michael@0: TSOffsetStyleGCs(style, rect->x, rect->y); michael@0: gtk_paint_box(style, drawable, GTK_STATE_NORMAL, GTK_SHADOW_IN, NULL, michael@0: gSpinWidget, "spinbutton", michael@0: rect->x, rect->y, rect->width, rect->height); michael@0: return MOZ_GTK_SUCCESS; michael@0: } michael@0: michael@0: static gint michael@0: moz_gtk_spin_updown_paint(GdkDrawable* drawable, GdkRectangle* rect, michael@0: gboolean isDown, GtkWidgetState* state, michael@0: GtkTextDirection direction) michael@0: { michael@0: GdkRectangle arrow_rect; michael@0: GtkStateType state_type = ConvertGtkState(state); michael@0: GtkShadowType shadow_type = state_type == GTK_STATE_ACTIVE ? michael@0: GTK_SHADOW_IN : GTK_SHADOW_OUT; michael@0: GtkStyle* style; michael@0: michael@0: ensure_spin_widget(); michael@0: style = gSpinWidget->style; michael@0: gtk_widget_set_direction(gSpinWidget, direction); michael@0: michael@0: TSOffsetStyleGCs(style, rect->x, rect->y); michael@0: gtk_paint_box(style, drawable, state_type, shadow_type, NULL, gSpinWidget, michael@0: isDown ? "spinbutton_down" : "spinbutton_up", michael@0: rect->x, rect->y, rect->width, rect->height); michael@0: michael@0: /* hard code these values */ michael@0: arrow_rect.width = 6; michael@0: arrow_rect.height = 6; michael@0: arrow_rect.x = rect->x + (rect->width - arrow_rect.width) / 2; michael@0: arrow_rect.y = rect->y + (rect->height - arrow_rect.height) / 2; michael@0: arrow_rect.y += isDown ? -1 : 1; michael@0: michael@0: gtk_paint_arrow(style, drawable, state_type, shadow_type, NULL, michael@0: gSpinWidget, "spinbutton", michael@0: isDown ? GTK_ARROW_DOWN : GTK_ARROW_UP, TRUE, michael@0: arrow_rect.x, arrow_rect.y, michael@0: arrow_rect.width, arrow_rect.height); michael@0: michael@0: return MOZ_GTK_SUCCESS; michael@0: } michael@0: michael@0: static gint michael@0: moz_gtk_scale_paint(GdkDrawable* drawable, GdkRectangle* rect, michael@0: GdkRectangle* cliprect, GtkWidgetState* state, michael@0: GtkOrientation flags, GtkTextDirection direction) michael@0: { michael@0: gint x = 0, y = 0; michael@0: GtkStateType state_type = ConvertGtkState(state); michael@0: GtkStyle* style; michael@0: GtkWidget* widget; michael@0: michael@0: ensure_scale_widget(); michael@0: widget = ((flags == GTK_ORIENTATION_HORIZONTAL) ? gHScaleWidget : gVScaleWidget); michael@0: gtk_widget_set_direction(widget, direction); michael@0: michael@0: style = widget->style; michael@0: michael@0: if (flags == GTK_ORIENTATION_HORIZONTAL) { michael@0: x = XTHICKNESS(style); michael@0: y++; michael@0: } michael@0: else { michael@0: x++; michael@0: y = YTHICKNESS(style); michael@0: } michael@0: michael@0: TSOffsetStyleGCs(style, rect->x, rect->y); michael@0: michael@0: gtk_paint_box(style, drawable, GTK_STATE_ACTIVE, GTK_SHADOW_IN, cliprect, michael@0: widget, "trough", rect->x + x, rect->y + y, michael@0: rect->width - 2*x, rect->height - 2*y); michael@0: michael@0: if (state->focused) michael@0: gtk_paint_focus(style, drawable, state_type, cliprect, widget, "trough", michael@0: rect->x, rect->y, rect->width, rect->height); michael@0: michael@0: return MOZ_GTK_SUCCESS; michael@0: } michael@0: michael@0: static gint michael@0: moz_gtk_scale_thumb_paint(GdkDrawable* drawable, GdkRectangle* rect, michael@0: GdkRectangle* cliprect, GtkWidgetState* state, michael@0: GtkOrientation flags, GtkTextDirection direction) michael@0: { michael@0: GtkStateType state_type = ConvertGtkState(state); michael@0: GtkStyle* style; michael@0: GtkWidget* widget; michael@0: gint thumb_width, thumb_height, x, y; michael@0: michael@0: ensure_scale_widget(); michael@0: widget = ((flags == GTK_ORIENTATION_HORIZONTAL) ? gHScaleWidget : gVScaleWidget); michael@0: gtk_widget_set_direction(widget, direction); michael@0: michael@0: style = widget->style; michael@0: michael@0: /* determine the thumb size, and position the thumb in the center in the opposite axis */ michael@0: if (flags == GTK_ORIENTATION_HORIZONTAL) { michael@0: moz_gtk_get_scalethumb_metrics(GTK_ORIENTATION_HORIZONTAL, &thumb_width, &thumb_height); michael@0: x = rect->x; michael@0: y = rect->y + (rect->height - thumb_height) / 2; michael@0: } michael@0: else { michael@0: moz_gtk_get_scalethumb_metrics(GTK_ORIENTATION_VERTICAL, &thumb_height, &thumb_width); michael@0: x = rect->x + (rect->width - thumb_width) / 2; michael@0: y = rect->y; michael@0: } michael@0: michael@0: TSOffsetStyleGCs(style, rect->x, rect->y); michael@0: gtk_paint_slider(style, drawable, state_type, GTK_SHADOW_OUT, cliprect, michael@0: widget, (flags == GTK_ORIENTATION_HORIZONTAL) ? "hscale" : "vscale", michael@0: x, y, thumb_width, thumb_height, flags); michael@0: michael@0: return MOZ_GTK_SUCCESS; michael@0: } michael@0: michael@0: static gint michael@0: moz_gtk_gripper_paint(GdkDrawable* drawable, GdkRectangle* rect, michael@0: GdkRectangle* cliprect, GtkWidgetState* state, michael@0: GtkTextDirection direction) michael@0: { michael@0: GtkStateType state_type = ConvertGtkState(state); michael@0: GtkShadowType shadow_type; michael@0: GtkStyle* style; michael@0: michael@0: ensure_handlebox_widget(); michael@0: gtk_widget_set_direction(gHandleBoxWidget, direction); michael@0: michael@0: style = gHandleBoxWidget->style; michael@0: shadow_type = GTK_HANDLE_BOX(gHandleBoxWidget)->shadow_type; michael@0: michael@0: TSOffsetStyleGCs(style, rect->x, rect->y); michael@0: gtk_paint_box(style, drawable, state_type, shadow_type, cliprect, michael@0: gHandleBoxWidget, "handlebox_bin", rect->x, rect->y, michael@0: rect->width, rect->height); michael@0: michael@0: return MOZ_GTK_SUCCESS; michael@0: } michael@0: michael@0: static gint michael@0: moz_gtk_hpaned_paint(GdkDrawable* drawable, GdkRectangle* rect, michael@0: GdkRectangle* cliprect, GtkWidgetState* state) michael@0: { michael@0: GtkStateType hpaned_state = ConvertGtkState(state); michael@0: michael@0: ensure_hpaned_widget(); michael@0: gtk_paint_handle(gHPanedWidget->style, drawable, hpaned_state, michael@0: GTK_SHADOW_NONE, cliprect, gHPanedWidget, "paned", michael@0: rect->x, rect->y, rect->width, rect->height, michael@0: GTK_ORIENTATION_VERTICAL); michael@0: michael@0: return MOZ_GTK_SUCCESS; michael@0: } michael@0: michael@0: static gint michael@0: moz_gtk_vpaned_paint(GdkDrawable* drawable, GdkRectangle* rect, michael@0: GdkRectangle* cliprect, GtkWidgetState* state) michael@0: { michael@0: GtkStateType vpaned_state = ConvertGtkState(state); michael@0: michael@0: ensure_vpaned_widget(); michael@0: gtk_paint_handle(gVPanedWidget->style, drawable, vpaned_state, michael@0: GTK_SHADOW_NONE, cliprect, gVPanedWidget, "paned", michael@0: rect->x, rect->y, rect->width, rect->height, michael@0: GTK_ORIENTATION_HORIZONTAL); michael@0: michael@0: return MOZ_GTK_SUCCESS; michael@0: } michael@0: michael@0: static gint michael@0: moz_gtk_entry_paint(GdkDrawable* drawable, GdkRectangle* rect, michael@0: GdkRectangle* cliprect, GtkWidgetState* state, michael@0: GtkWidget* widget, GtkTextDirection direction) michael@0: { michael@0: GtkStateType bg_state = state->disabled ? michael@0: GTK_STATE_INSENSITIVE : GTK_STATE_NORMAL; michael@0: gint x, y, width = rect->width, height = rect->height; michael@0: GtkStyle* style; michael@0: gboolean interior_focus; michael@0: gboolean theme_honors_transparency = FALSE; michael@0: gint focus_width; michael@0: michael@0: gtk_widget_set_direction(widget, direction); michael@0: michael@0: style = widget->style; michael@0: michael@0: gtk_widget_style_get(widget, michael@0: "interior-focus", &interior_focus, michael@0: "focus-line-width", &focus_width, michael@0: "honors-transparent-bg-hint", &theme_honors_transparency, michael@0: NULL); michael@0: michael@0: /* gtkentry.c uses two windows, one for the entire widget and one for the michael@0: * text area inside it. The background of both windows is set to the "base" michael@0: * color of the new state in gtk_entry_state_changed, but only the inner michael@0: * textarea window uses gtk_paint_flat_box when exposed */ michael@0: michael@0: TSOffsetStyleGCs(style, rect->x, rect->y); michael@0: michael@0: /* This gets us a lovely greyish disabledish look */ michael@0: gtk_widget_set_sensitive(widget, !state->disabled); michael@0: michael@0: /* GTK fills the outer widget window with the base color before drawing the widget. michael@0: * Some older themes rely on this behavior, but many themes nowadays use rounded michael@0: * corners on their widgets. While most GTK apps are blissfully unaware of this michael@0: * problem due to their use of the default window background, we render widgets on michael@0: * many kinds of backgrounds on the web. michael@0: * If the theme is able to cope with transparency, then we can skip pre-filling michael@0: * and notify the theme it will paint directly on the canvas. */ michael@0: if (theme_honors_transparency) { michael@0: g_object_set_data(G_OBJECT(widget), "transparent-bg-hint", GINT_TO_POINTER(TRUE)); michael@0: } else { michael@0: GdkRectangle clipped_rect; michael@0: gdk_rectangle_intersect(rect, cliprect, &clipped_rect); michael@0: if (clipped_rect.width != 0) { michael@0: gdk_draw_rectangle(drawable, style->base_gc[bg_state], TRUE, michael@0: clipped_rect.x, clipped_rect.y, michael@0: clipped_rect.width, clipped_rect.height); michael@0: } michael@0: g_object_set_data(G_OBJECT(widget), "transparent-bg-hint", GINT_TO_POINTER(FALSE)); michael@0: } michael@0: michael@0: /* Get the position of the inner window, see _gtk_entry_get_borders */ michael@0: x = XTHICKNESS(style); michael@0: y = YTHICKNESS(style); michael@0: michael@0: if (!interior_focus) { michael@0: x += focus_width; michael@0: y += focus_width; michael@0: } michael@0: michael@0: /* Simulate an expose of the inner window */ michael@0: gtk_paint_flat_box(style, drawable, bg_state, GTK_SHADOW_NONE, michael@0: cliprect, widget, "entry_bg", rect->x + x, michael@0: rect->y + y, rect->width - 2*x, rect->height - 2*y); michael@0: michael@0: /* Now paint the shadow and focus border. michael@0: * We do like in gtk_entry_draw_frame, we first draw the shadow, a tad michael@0: * smaller when focused if the focus is not interior, then the focus. */ michael@0: x = rect->x; michael@0: y = rect->y; michael@0: michael@0: if (state->focused && !state->disabled) { michael@0: /* This will get us the lit borders that focused textboxes enjoy on michael@0: * some themes. */ michael@0: GTK_WIDGET_SET_FLAGS(widget, GTK_HAS_FOCUS); michael@0: michael@0: if (!interior_focus) { michael@0: /* Indent the border a little bit if we have exterior focus michael@0: (this is what GTK does to draw native entries) */ michael@0: x += focus_width; michael@0: y += focus_width; michael@0: width -= 2 * focus_width; michael@0: height -= 2 * focus_width; michael@0: } michael@0: } michael@0: michael@0: gtk_paint_shadow(style, drawable, GTK_STATE_NORMAL, GTK_SHADOW_IN, michael@0: cliprect, widget, "entry", x, y, width, height); michael@0: michael@0: if (state->focused && !state->disabled) { michael@0: if (!interior_focus) { michael@0: gtk_paint_focus(style, drawable, GTK_STATE_NORMAL, cliprect, michael@0: widget, "entry", michael@0: rect->x, rect->y, rect->width, rect->height); michael@0: } michael@0: michael@0: /* Now unset the focus flag. We don't want other entries to look michael@0: * like they're focused too! */ michael@0: GTK_WIDGET_UNSET_FLAGS(widget, GTK_HAS_FOCUS); michael@0: } michael@0: michael@0: return MOZ_GTK_SUCCESS; michael@0: } michael@0: michael@0: static gint michael@0: moz_gtk_treeview_paint(GdkDrawable* drawable, GdkRectangle* rect, michael@0: GdkRectangle* cliprect, GtkWidgetState* state, michael@0: GtkTextDirection direction) michael@0: { michael@0: gint xthickness, ythickness; michael@0: michael@0: GtkStyle *style; michael@0: GtkStateType state_type; michael@0: michael@0: ensure_tree_view_widget(); michael@0: ensure_scrolled_window_widget(); michael@0: michael@0: gtk_widget_set_direction(gTreeViewWidget, direction); michael@0: gtk_widget_set_direction(gScrolledWindowWidget, direction); michael@0: michael@0: /* only handle disabled and normal states, otherwise the whole background michael@0: * area will be painted differently with other states */ michael@0: state_type = state->disabled ? GTK_STATE_INSENSITIVE : GTK_STATE_NORMAL; michael@0: michael@0: /* In GTK the treeview sets the background of the window michael@0: * which contains the cells to the treeview base color. michael@0: * If we don't set it here the background color will not be correct.*/ michael@0: gtk_widget_modify_bg(gTreeViewWidget, state_type, michael@0: &gTreeViewWidget->style->base[state_type]); michael@0: michael@0: style = gScrolledWindowWidget->style; michael@0: xthickness = XTHICKNESS(style); michael@0: ythickness = YTHICKNESS(style); michael@0: michael@0: TSOffsetStyleGCs(gTreeViewWidget->style, rect->x, rect->y); michael@0: TSOffsetStyleGCs(style, rect->x, rect->y); michael@0: michael@0: gtk_paint_flat_box(gTreeViewWidget->style, drawable, state_type, michael@0: GTK_SHADOW_NONE, cliprect, gTreeViewWidget, "treeview", michael@0: rect->x + xthickness, rect->y + ythickness, michael@0: rect->width - 2 * xthickness, michael@0: rect->height - 2 * ythickness); michael@0: michael@0: gtk_paint_shadow(style, drawable, GTK_STATE_NORMAL, GTK_SHADOW_IN, michael@0: cliprect, gScrolledWindowWidget, "scrolled_window", michael@0: rect->x, rect->y, rect->width, rect->height); michael@0: michael@0: return MOZ_GTK_SUCCESS; michael@0: } michael@0: michael@0: static gint michael@0: moz_gtk_tree_header_cell_paint(GdkDrawable* drawable, GdkRectangle* rect, michael@0: GdkRectangle* cliprect, GtkWidgetState* state, michael@0: gboolean isSorted, GtkTextDirection direction) michael@0: { michael@0: gtk_tree_view_column_set_sort_indicator(gMiddleTreeViewColumn, michael@0: isSorted); michael@0: michael@0: moz_gtk_button_paint(drawable, rect, cliprect, state, GTK_RELIEF_NORMAL, michael@0: gTreeHeaderCellWidget, direction); michael@0: return MOZ_GTK_SUCCESS; michael@0: } michael@0: michael@0: static gint michael@0: moz_gtk_tree_header_sort_arrow_paint(GdkDrawable* drawable, GdkRectangle* rect, michael@0: GdkRectangle* cliprect, michael@0: GtkWidgetState* state, GtkArrowType flags, michael@0: GtkTextDirection direction) michael@0: { michael@0: GdkRectangle arrow_rect; michael@0: GtkStateType state_type = ConvertGtkState(state); michael@0: GtkShadowType shadow_type = GTK_SHADOW_IN; michael@0: GtkArrowType arrow_type = flags; michael@0: GtkStyle* style; michael@0: michael@0: ensure_tree_header_cell_widget(); michael@0: gtk_widget_set_direction(gTreeHeaderSortArrowWidget, direction); michael@0: michael@0: /* hard code these values */ michael@0: arrow_rect.width = 11; michael@0: arrow_rect.height = 11; michael@0: arrow_rect.x = rect->x + (rect->width - arrow_rect.width) / 2; michael@0: arrow_rect.y = rect->y + (rect->height - arrow_rect.height) / 2; michael@0: michael@0: style = gTreeHeaderSortArrowWidget->style; michael@0: TSOffsetStyleGCs(style, arrow_rect.x, arrow_rect.y); michael@0: michael@0: gtk_paint_arrow(style, drawable, state_type, shadow_type, cliprect, michael@0: gTreeHeaderSortArrowWidget, "arrow", arrow_type, TRUE, michael@0: arrow_rect.x, arrow_rect.y, michael@0: arrow_rect.width, arrow_rect.height); michael@0: michael@0: return MOZ_GTK_SUCCESS; michael@0: } michael@0: michael@0: static gint michael@0: moz_gtk_treeview_expander_paint(GdkDrawable* drawable, GdkRectangle* rect, michael@0: GdkRectangle* cliprect, GtkWidgetState* state, michael@0: GtkExpanderStyle expander_state, michael@0: GtkTextDirection direction) michael@0: { michael@0: GtkStyle *style; michael@0: GtkStateType state_type; michael@0: michael@0: ensure_tree_view_widget(); michael@0: gtk_widget_set_direction(gTreeViewWidget, direction); michael@0: michael@0: style = gTreeViewWidget->style; michael@0: michael@0: /* Because the frame we get is of the entire treeview, we can't get the precise michael@0: * event state of one expander, thus rendering hover and active feedback useless. */ michael@0: state_type = state->disabled ? GTK_STATE_INSENSITIVE : GTK_STATE_NORMAL; michael@0: michael@0: TSOffsetStyleGCs(style, rect->x, rect->y); michael@0: gtk_paint_expander(style, drawable, state_type, cliprect, gTreeViewWidget, "treeview", michael@0: rect->x + rect->width / 2, rect->y + rect->height / 2, expander_state); michael@0: michael@0: return MOZ_GTK_SUCCESS; michael@0: } michael@0: michael@0: static gint michael@0: moz_gtk_combo_box_paint(GdkDrawable* drawable, GdkRectangle* rect, michael@0: GdkRectangle* cliprect, GtkWidgetState* state, michael@0: gboolean ishtml, GtkTextDirection direction) michael@0: { michael@0: GdkRectangle arrow_rect, real_arrow_rect; michael@0: gint arrow_size, separator_width; michael@0: gboolean wide_separators; michael@0: GtkStateType state_type = ConvertGtkState(state); michael@0: GtkShadowType shadow_type = state->active ? GTK_SHADOW_IN : GTK_SHADOW_OUT; michael@0: GtkStyle* style; michael@0: GtkRequisition arrow_req; michael@0: michael@0: ensure_combo_box_widgets(); michael@0: michael@0: /* Also sets the direction on gComboBoxButtonWidget, which is then michael@0: * inherited by the separator and arrow */ michael@0: moz_gtk_button_paint(drawable, rect, cliprect, state, GTK_RELIEF_NORMAL, michael@0: gComboBoxButtonWidget, direction); michael@0: michael@0: calculate_button_inner_rect(gComboBoxButtonWidget, michael@0: rect, &arrow_rect, direction, ishtml); michael@0: /* Now arrow_rect contains the inner rect ; we want to correct the width michael@0: * to what the arrow needs (see gtk_combo_box_size_allocate) */ michael@0: gtk_widget_size_request(gComboBoxArrowWidget, &arrow_req); michael@0: if (direction == GTK_TEXT_DIR_LTR) michael@0: arrow_rect.x += arrow_rect.width - arrow_req.width; michael@0: arrow_rect.width = arrow_req.width; michael@0: michael@0: calculate_arrow_rect(gComboBoxArrowWidget, michael@0: &arrow_rect, &real_arrow_rect, direction); michael@0: michael@0: style = gComboBoxArrowWidget->style; michael@0: TSOffsetStyleGCs(style, rect->x, rect->y); michael@0: michael@0: gtk_widget_size_allocate(gComboBoxWidget, rect); michael@0: michael@0: gtk_paint_arrow(style, drawable, state_type, shadow_type, cliprect, michael@0: gComboBoxArrowWidget, "arrow", GTK_ARROW_DOWN, TRUE, michael@0: real_arrow_rect.x, real_arrow_rect.y, michael@0: real_arrow_rect.width, real_arrow_rect.height); michael@0: michael@0: michael@0: /* If there is no separator in the theme, there's nothing left to do. */ michael@0: if (!gComboBoxSeparatorWidget) michael@0: return MOZ_GTK_SUCCESS; michael@0: michael@0: style = gComboBoxSeparatorWidget->style; michael@0: TSOffsetStyleGCs(style, rect->x, rect->y); michael@0: michael@0: gtk_widget_style_get(gComboBoxSeparatorWidget, michael@0: "wide-separators", &wide_separators, michael@0: "separator-width", &separator_width, michael@0: NULL); michael@0: michael@0: if (wide_separators) { michael@0: if (direction == GTK_TEXT_DIR_LTR) michael@0: arrow_rect.x -= separator_width; michael@0: else michael@0: arrow_rect.x += arrow_rect.width; michael@0: michael@0: gtk_paint_box(style, drawable, michael@0: GTK_STATE_NORMAL, GTK_SHADOW_ETCHED_OUT, michael@0: cliprect, gComboBoxSeparatorWidget, "vseparator", michael@0: arrow_rect.x, arrow_rect.y, michael@0: separator_width, arrow_rect.height); michael@0: } else { michael@0: if (direction == GTK_TEXT_DIR_LTR) michael@0: arrow_rect.x -= XTHICKNESS(style); michael@0: else michael@0: arrow_rect.x += arrow_rect.width; michael@0: michael@0: gtk_paint_vline(style, drawable, GTK_STATE_NORMAL, cliprect, michael@0: gComboBoxSeparatorWidget, "vseparator", michael@0: arrow_rect.y, arrow_rect.y + arrow_rect.height, michael@0: arrow_rect.x); michael@0: } michael@0: michael@0: return MOZ_GTK_SUCCESS; michael@0: } michael@0: michael@0: static gint michael@0: moz_gtk_arrow_paint(GdkDrawable* drawable, GdkRectangle* rect, michael@0: GdkRectangle* cliprect, GtkWidgetState* state, michael@0: GtkArrowType arrow_type, GtkTextDirection direction) michael@0: { michael@0: GtkStyle* style; michael@0: GtkStateType state_type = ConvertGtkState(state); michael@0: GtkShadowType shadow_type = state->active ? GTK_SHADOW_IN : GTK_SHADOW_OUT; michael@0: GdkRectangle arrow_rect; michael@0: michael@0: ensure_button_arrow_widget(); michael@0: style = gButtonArrowWidget->style; michael@0: gtk_widget_set_direction(gButtonArrowWidget, direction); michael@0: michael@0: calculate_arrow_rect(gButtonArrowWidget, rect, &arrow_rect, michael@0: direction); michael@0: michael@0: if (direction == GTK_TEXT_DIR_RTL) { michael@0: if (arrow_type == GTK_ARROW_LEFT) michael@0: arrow_type = GTK_ARROW_RIGHT; michael@0: else if (arrow_type == GTK_ARROW_RIGHT) michael@0: arrow_type = GTK_ARROW_LEFT; michael@0: } michael@0: michael@0: TSOffsetStyleGCs(style, arrow_rect.x, arrow_rect.y); michael@0: gtk_paint_arrow(style, drawable, state_type, shadow_type, cliprect, michael@0: gButtonArrowWidget, "arrow", arrow_type, TRUE, michael@0: arrow_rect.x, arrow_rect.y, arrow_rect.width, arrow_rect.height); michael@0: michael@0: return MOZ_GTK_SUCCESS; michael@0: } michael@0: michael@0: static gint michael@0: moz_gtk_combo_box_entry_button_paint(GdkDrawable* drawable, GdkRectangle* rect, michael@0: GdkRectangle* cliprect, michael@0: GtkWidgetState* state, michael@0: gboolean input_focus, michael@0: GtkTextDirection direction) michael@0: { michael@0: gint x_displacement, y_displacement; michael@0: GdkRectangle arrow_rect, real_arrow_rect; michael@0: GtkStateType state_type = ConvertGtkState(state); michael@0: GtkShadowType shadow_type = state->active ? GTK_SHADOW_IN : GTK_SHADOW_OUT; michael@0: GtkStyle* style; michael@0: michael@0: ensure_combo_box_entry_widgets(); michael@0: michael@0: if (input_focus) { michael@0: /* Some themes draw a complementary focus ring for the dropdown button michael@0: * when the dropdown entry has focus */ michael@0: GTK_WIDGET_SET_FLAGS(gComboBoxEntryTextareaWidget, GTK_HAS_FOCUS); michael@0: } michael@0: michael@0: moz_gtk_button_paint(drawable, rect, cliprect, state, GTK_RELIEF_NORMAL, michael@0: gComboBoxEntryButtonWidget, direction); michael@0: michael@0: if (input_focus) michael@0: GTK_WIDGET_UNSET_FLAGS(gComboBoxEntryTextareaWidget, GTK_HAS_FOCUS); michael@0: michael@0: calculate_button_inner_rect(gComboBoxEntryButtonWidget, michael@0: rect, &arrow_rect, direction, FALSE); michael@0: if (state_type == GTK_STATE_ACTIVE) { michael@0: gtk_widget_style_get(gComboBoxEntryButtonWidget, michael@0: "child-displacement-x", &x_displacement, michael@0: "child-displacement-y", &y_displacement, michael@0: NULL); michael@0: arrow_rect.x += x_displacement; michael@0: arrow_rect.y += y_displacement; michael@0: } michael@0: michael@0: calculate_arrow_rect(gComboBoxEntryArrowWidget, michael@0: &arrow_rect, &real_arrow_rect, direction); michael@0: michael@0: style = gComboBoxEntryArrowWidget->style; michael@0: TSOffsetStyleGCs(style, real_arrow_rect.x, real_arrow_rect.y); michael@0: michael@0: gtk_paint_arrow(style, drawable, state_type, shadow_type, cliprect, michael@0: gComboBoxEntryArrowWidget, "arrow", GTK_ARROW_DOWN, TRUE, michael@0: real_arrow_rect.x, real_arrow_rect.y, michael@0: real_arrow_rect.width, real_arrow_rect.height); michael@0: michael@0: return MOZ_GTK_SUCCESS; michael@0: } michael@0: michael@0: static gint michael@0: moz_gtk_container_paint(GdkDrawable* drawable, GdkRectangle* rect, michael@0: GdkRectangle* cliprect, GtkWidgetState* state, michael@0: gboolean isradio, GtkTextDirection direction) michael@0: { michael@0: GtkStateType state_type = ConvertGtkState(state); michael@0: GtkStyle* style; michael@0: GtkWidget *widget; michael@0: gboolean interior_focus; michael@0: gint focus_width, focus_pad; michael@0: michael@0: if (isradio) { michael@0: ensure_radiobutton_widget(); michael@0: widget = gRadiobuttonWidget; michael@0: } else { michael@0: ensure_checkbox_widget(); michael@0: widget = gCheckboxWidget; michael@0: } michael@0: gtk_widget_set_direction(widget, direction); michael@0: michael@0: style = widget->style; michael@0: moz_gtk_widget_get_focus(widget, &interior_focus, &focus_width, michael@0: &focus_pad); michael@0: michael@0: TSOffsetStyleGCs(style, rect->x, rect->y); michael@0: michael@0: /* The detail argument for the gtk_paint_* calls below are "checkbutton" michael@0: even for radio buttons, to match what gtk does. */ michael@0: michael@0: /* this is for drawing a prelight box */ michael@0: if (state_type == GTK_STATE_PRELIGHT || state_type == GTK_STATE_ACTIVE) { michael@0: gtk_paint_flat_box(style, drawable, GTK_STATE_PRELIGHT, michael@0: GTK_SHADOW_ETCHED_OUT, cliprect, widget, michael@0: "checkbutton", michael@0: rect->x, rect->y, rect->width, rect->height); michael@0: } michael@0: michael@0: if (state_type != GTK_STATE_NORMAL && state_type != GTK_STATE_PRELIGHT) michael@0: state_type = GTK_STATE_NORMAL; michael@0: michael@0: if (state->focused && !interior_focus) { michael@0: gtk_paint_focus(style, drawable, state_type, cliprect, widget, michael@0: "checkbutton", michael@0: rect->x, rect->y, rect->width, rect->height); michael@0: } michael@0: michael@0: return MOZ_GTK_SUCCESS; michael@0: } michael@0: michael@0: static gint michael@0: moz_gtk_toggle_label_paint(GdkDrawable* drawable, GdkRectangle* rect, michael@0: GdkRectangle* cliprect, GtkWidgetState* state, michael@0: gboolean isradio, GtkTextDirection direction) michael@0: { michael@0: GtkStateType state_type; michael@0: GtkStyle *style; michael@0: GtkWidget *widget; michael@0: gboolean interior_focus; michael@0: michael@0: if (!state->focused) michael@0: return MOZ_GTK_SUCCESS; michael@0: michael@0: if (isradio) { michael@0: ensure_radiobutton_widget(); michael@0: widget = gRadiobuttonWidget; michael@0: } else { michael@0: ensure_checkbox_widget(); michael@0: widget = gCheckboxWidget; michael@0: } michael@0: gtk_widget_set_direction(widget, direction); michael@0: michael@0: gtk_widget_style_get(widget, "interior-focus", &interior_focus, NULL); michael@0: if (!interior_focus) michael@0: return MOZ_GTK_SUCCESS; michael@0: michael@0: state_type = ConvertGtkState(state); michael@0: michael@0: style = widget->style; michael@0: TSOffsetStyleGCs(style, rect->x, rect->y); michael@0: michael@0: /* Always "checkbutton" to match gtkcheckbutton.c */ michael@0: gtk_paint_focus(style, drawable, state_type, cliprect, widget, michael@0: "checkbutton", michael@0: rect->x, rect->y, rect->width, rect->height); michael@0: michael@0: return MOZ_GTK_SUCCESS; michael@0: } michael@0: michael@0: static gint michael@0: moz_gtk_toolbar_paint(GdkDrawable* drawable, GdkRectangle* rect, michael@0: GdkRectangle* cliprect, GtkTextDirection direction) michael@0: { michael@0: GtkStyle* style; michael@0: GtkShadowType shadow_type; michael@0: michael@0: ensure_toolbar_widget(); michael@0: gtk_widget_set_direction(gToolbarWidget, direction); michael@0: michael@0: style = gToolbarWidget->style; michael@0: michael@0: TSOffsetStyleGCs(style, rect->x, rect->y); michael@0: michael@0: gtk_style_apply_default_background(style, drawable, TRUE, michael@0: GTK_STATE_NORMAL, michael@0: cliprect, rect->x, rect->y, michael@0: rect->width, rect->height); michael@0: michael@0: gtk_widget_style_get(gToolbarWidget, "shadow-type", &shadow_type, NULL); michael@0: michael@0: gtk_paint_box (style, drawable, GTK_STATE_NORMAL, shadow_type, michael@0: cliprect, gToolbarWidget, "toolbar", michael@0: rect->x, rect->y, rect->width, rect->height); michael@0: michael@0: return MOZ_GTK_SUCCESS; michael@0: } michael@0: michael@0: static gint michael@0: moz_gtk_toolbar_separator_paint(GdkDrawable* drawable, GdkRectangle* rect, michael@0: GdkRectangle* cliprect, michael@0: GtkTextDirection direction) michael@0: { michael@0: GtkStyle* style; michael@0: gint separator_width; michael@0: gint paint_width; michael@0: gboolean wide_separators; michael@0: michael@0: /* Defined as constants in GTK+ 2.10.14 */ michael@0: const double start_fraction = 0.2; michael@0: const double end_fraction = 0.8; michael@0: michael@0: ensure_toolbar_separator_widget(); michael@0: gtk_widget_set_direction(gToolbarSeparatorWidget, direction); michael@0: michael@0: style = gToolbarSeparatorWidget->style; michael@0: michael@0: gtk_widget_style_get(gToolbarWidget, michael@0: "wide-separators", &wide_separators, michael@0: "separator-width", &separator_width, michael@0: NULL); michael@0: michael@0: TSOffsetStyleGCs(style, rect->x, rect->y); michael@0: michael@0: if (wide_separators) { michael@0: if (separator_width > rect->width) michael@0: separator_width = rect->width; michael@0: michael@0: gtk_paint_box(style, drawable, michael@0: GTK_STATE_NORMAL, GTK_SHADOW_ETCHED_OUT, michael@0: cliprect, gToolbarWidget, "vseparator", michael@0: rect->x + (rect->width - separator_width) / 2, michael@0: rect->y + rect->height * start_fraction, michael@0: separator_width, michael@0: rect->height * (end_fraction - start_fraction)); michael@0: michael@0: } else { michael@0: paint_width = style->xthickness; michael@0: michael@0: if (paint_width > rect->width) michael@0: paint_width = rect->width; michael@0: michael@0: gtk_paint_vline(style, drawable, michael@0: GTK_STATE_NORMAL, cliprect, gToolbarSeparatorWidget, michael@0: "toolbar", michael@0: rect->y + rect->height * start_fraction, michael@0: rect->y + rect->height * end_fraction, michael@0: rect->x + (rect->width - paint_width) / 2); michael@0: } michael@0: michael@0: return MOZ_GTK_SUCCESS; michael@0: } michael@0: michael@0: static gint michael@0: moz_gtk_tooltip_paint(GdkDrawable* drawable, GdkRectangle* rect, michael@0: GdkRectangle* cliprect, GtkTextDirection direction) michael@0: { michael@0: GtkStyle* style; michael@0: michael@0: ensure_tooltip_widget(); michael@0: gtk_widget_set_direction(gTooltipWidget, direction); michael@0: michael@0: style = gtk_rc_get_style_by_paths(gtk_settings_get_default(), michael@0: "gtk-tooltips", "GtkWindow", michael@0: GTK_TYPE_WINDOW); michael@0: michael@0: style = gtk_style_attach(style, gTooltipWidget->window); michael@0: TSOffsetStyleGCs(style, rect->x, rect->y); michael@0: gtk_paint_flat_box(style, drawable, GTK_STATE_NORMAL, GTK_SHADOW_OUT, michael@0: cliprect, gTooltipWidget, "tooltip", michael@0: rect->x, rect->y, rect->width, rect->height); michael@0: michael@0: return MOZ_GTK_SUCCESS; michael@0: } michael@0: michael@0: static gint michael@0: moz_gtk_resizer_paint(GdkDrawable* drawable, GdkRectangle* rect, michael@0: GdkRectangle* cliprect, GtkWidgetState* state, michael@0: GtkTextDirection direction) michael@0: { michael@0: GtkStyle* style; michael@0: GtkStateType state_type = ConvertGtkState(state); michael@0: michael@0: ensure_frame_widget(); michael@0: gtk_widget_set_direction(gStatusbarWidget, direction); michael@0: michael@0: style = gStatusbarWidget->style; michael@0: michael@0: TSOffsetStyleGCs(style, rect->x, rect->y); michael@0: michael@0: gtk_paint_resize_grip(style, drawable, state_type, cliprect, gStatusbarWidget, michael@0: "statusbar", (direction == GTK_TEXT_DIR_LTR) ? michael@0: GDK_WINDOW_EDGE_SOUTH_EAST : michael@0: GDK_WINDOW_EDGE_SOUTH_WEST, michael@0: rect->x, rect->y, rect->width, rect->height); michael@0: return MOZ_GTK_SUCCESS; michael@0: } michael@0: michael@0: static gint michael@0: moz_gtk_frame_paint(GdkDrawable* drawable, GdkRectangle* rect, michael@0: GdkRectangle* cliprect, GtkTextDirection direction) michael@0: { michael@0: GtkStyle* style; michael@0: GtkShadowType shadow_type; michael@0: michael@0: ensure_frame_widget(); michael@0: gtk_widget_set_direction(gFrameWidget, direction); michael@0: michael@0: style = gFrameWidget->style; michael@0: michael@0: gtk_widget_style_get(gStatusbarWidget, "shadow-type", &shadow_type, NULL); michael@0: michael@0: TSOffsetStyleGCs(style, rect->x, rect->y); michael@0: gtk_paint_shadow(style, drawable, GTK_STATE_NORMAL, shadow_type, michael@0: cliprect, gFrameWidget, "frame", rect->x, rect->y, michael@0: rect->width, rect->height); michael@0: michael@0: return MOZ_GTK_SUCCESS; michael@0: } michael@0: michael@0: static gint michael@0: moz_gtk_progressbar_paint(GdkDrawable* drawable, GdkRectangle* rect, michael@0: GdkRectangle* cliprect, GtkTextDirection direction) michael@0: { michael@0: GtkStyle* style; michael@0: michael@0: ensure_progress_widget(); michael@0: gtk_widget_set_direction(gProgressWidget, direction); michael@0: michael@0: style = gProgressWidget->style; michael@0: michael@0: TSOffsetStyleGCs(style, rect->x, rect->y); michael@0: gtk_paint_box(style, drawable, GTK_STATE_NORMAL, GTK_SHADOW_IN, michael@0: cliprect, gProgressWidget, "trough", rect->x, rect->y, michael@0: rect->width, rect->height); michael@0: michael@0: return MOZ_GTK_SUCCESS; michael@0: } michael@0: michael@0: static gint michael@0: moz_gtk_progress_chunk_paint(GdkDrawable* drawable, GdkRectangle* rect, michael@0: GdkRectangle* cliprect, GtkTextDirection direction, michael@0: GtkThemeWidgetType widget) michael@0: { michael@0: GtkStyle* style; michael@0: michael@0: ensure_progress_widget(); michael@0: gtk_widget_set_direction(gProgressWidget, direction); michael@0: michael@0: style = gProgressWidget->style; michael@0: michael@0: TSOffsetStyleGCs(style, rect->x, rect->y); michael@0: michael@0: if (widget == MOZ_GTK_PROGRESS_CHUNK_INDETERMINATE || michael@0: widget == MOZ_GTK_PROGRESS_CHUNK_VERTICAL_INDETERMINATE) { michael@0: /** michael@0: * The bar's size and the bar speed are set depending of the progress' michael@0: * size. These could also be constant for all progress bars easily. michael@0: */ michael@0: gboolean vertical = (widget == MOZ_GTK_PROGRESS_CHUNK_VERTICAL_INDETERMINATE); michael@0: michael@0: /* The size of the dimension we are going to use for the animation. */ michael@0: const gint progressSize = vertical ? rect->height : rect->width; michael@0: michael@0: /* The bar is using a fifth of the element size, based on GtkProgressBar michael@0: * activity-blocks property. */ michael@0: const gint barSize = MAX(1, progressSize / 5); michael@0: michael@0: /* Represents the travel that has to be done for a complete cycle. */ michael@0: const gint travel = 2 * (progressSize - barSize); michael@0: michael@0: /* period equals to travel / pixelsPerMillisecond michael@0: * where pixelsPerMillisecond equals progressSize / 1000.0. michael@0: * This is equivalent to 1600. */ michael@0: static const guint period = 1600; michael@0: const gint t = PR_IntervalToMilliseconds(PR_IntervalNow()) % period; michael@0: const gint dx = travel * t / period; michael@0: michael@0: if (vertical) { michael@0: rect->y += (dx < travel / 2) ? dx : travel - dx; michael@0: rect->height = barSize; michael@0: } else { michael@0: rect->x += (dx < travel / 2) ? dx : travel - dx; michael@0: rect->width = barSize; michael@0: } michael@0: } michael@0: michael@0: gtk_paint_box(style, drawable, GTK_STATE_PRELIGHT, GTK_SHADOW_OUT, michael@0: cliprect, gProgressWidget, "bar", rect->x, rect->y, michael@0: rect->width, rect->height); michael@0: michael@0: return MOZ_GTK_SUCCESS; michael@0: } michael@0: michael@0: gint michael@0: moz_gtk_get_tab_thickness(void) michael@0: { michael@0: ensure_tab_widget(); michael@0: if (YTHICKNESS(gTabWidget->style) < 2) michael@0: return 2; /* some themes don't set ythickness correctly */ michael@0: michael@0: return YTHICKNESS(gTabWidget->style); michael@0: } michael@0: michael@0: static gint michael@0: moz_gtk_tab_paint(GdkDrawable* drawable, GdkRectangle* rect, michael@0: GdkRectangle* cliprect, GtkWidgetState* state, michael@0: GtkTabFlags flags, GtkTextDirection direction) michael@0: { michael@0: /* When the tab isn't selected, we just draw a notebook extension. michael@0: * When it is selected, we overwrite the adjacent border of the tabpanel michael@0: * touching the tab with a pierced border (called "the gap") to make the michael@0: * tab appear physically attached to the tabpanel; see details below. */ michael@0: michael@0: GtkStyle* style; michael@0: GdkRectangle focusRect; michael@0: michael@0: ensure_tab_widget(); michael@0: gtk_widget_set_direction(gTabWidget, direction); michael@0: michael@0: style = gTabWidget->style; michael@0: focusRect = *rect; michael@0: TSOffsetStyleGCs(style, rect->x, rect->y); michael@0: michael@0: if ((flags & MOZ_GTK_TAB_SELECTED) == 0) { michael@0: /* Only draw the tab */ michael@0: gtk_paint_extension(style, drawable, GTK_STATE_ACTIVE, GTK_SHADOW_OUT, michael@0: cliprect, gTabWidget, "tab", michael@0: rect->x, rect->y, rect->width, rect->height, michael@0: (flags & MOZ_GTK_TAB_BOTTOM) ? michael@0: GTK_POS_TOP : GTK_POS_BOTTOM ); michael@0: } else { michael@0: /* Draw the tab and the gap michael@0: * We want the gap to be positioned exactly on the tabpanel top michael@0: * border; since tabbox.css may set a negative margin so that the tab michael@0: * frame rect already overlaps the tabpanel frame rect, we need to take michael@0: * that into account when drawing. To that effect, nsNativeThemeGTK michael@0: * passes us this negative margin (bmargin in the graphic below) in the michael@0: * lowest bits of |flags|. We use it to set gap_voffset, the distance michael@0: * between the top of the gap and the bottom of the tab (resp. the michael@0: * bottom of the gap and the top of the tab when we draw a bottom tab), michael@0: * while ensuring that the gap always touches the border of the tab, michael@0: * i.e. 0 <= gap_voffset <= gap_height, to avoid surprinsing results michael@0: * with big negative or positive margins. michael@0: * Here is a graphical explanation in the case of top tabs: michael@0: * ___________________________ michael@0: * / \ michael@0: * | T A B | michael@0: * ----------|. . . . . . . . . . . . . . .|----- top of tabpanel michael@0: * : ^ bmargin : ^ michael@0: * : | (-negative margin, : | michael@0: * bottom : v passed in flags) : | gap_height michael@0: * of -> :.............................: | (the size of the michael@0: * the tab . part of the gap . | tabpanel top border) michael@0: * . outside of the tab . v michael@0: * ---------------------------------------------- michael@0: * michael@0: * To draw the gap, we use gtk_paint_box_gap(), see comment in michael@0: * moz_gtk_tabpanels_paint(). This box_gap is made 3 * gap_height tall, michael@0: * which should suffice to ensure that the only visible border is the michael@0: * pierced one. If the tab is in the middle, we make the box_gap begin michael@0: * a bit to the left of the tab and end a bit to the right, adjusting michael@0: * the gap position so it still is under the tab, because we want the michael@0: * rendering of a gap in the middle of a tabpanel. This is the role of michael@0: * the gints gap_{l,r}_offset. On the contrary, if the tab is the michael@0: * first, we align the start border of the box_gap with the start michael@0: * border of the tab (left if LTR, right if RTL), by setting the michael@0: * appropriate offset to 0.*/ michael@0: gint gap_loffset, gap_roffset, gap_voffset, gap_height; michael@0: michael@0: /* Get height needed by the gap */ michael@0: gap_height = moz_gtk_get_tab_thickness(); michael@0: michael@0: /* Extract gap_voffset from the first bits of flags */ michael@0: gap_voffset = flags & MOZ_GTK_TAB_MARGIN_MASK; michael@0: if (gap_voffset > gap_height) michael@0: gap_voffset = gap_height; michael@0: michael@0: /* Set gap_{l,r}_offset to appropriate values */ michael@0: gap_loffset = gap_roffset = 20; /* should be enough */ michael@0: if (flags & MOZ_GTK_TAB_FIRST) { michael@0: if (direction == GTK_TEXT_DIR_RTL) michael@0: gap_roffset = 0; michael@0: else michael@0: gap_loffset = 0; michael@0: } michael@0: michael@0: if (flags & MOZ_GTK_TAB_BOTTOM) { michael@0: /* Draw the tab */ michael@0: focusRect.y += gap_voffset; michael@0: focusRect.height -= gap_voffset; michael@0: gtk_paint_extension(style, drawable, GTK_STATE_NORMAL, michael@0: GTK_SHADOW_OUT, cliprect, gTabWidget, "tab", michael@0: rect->x, rect->y + gap_voffset, rect->width, michael@0: rect->height - gap_voffset, GTK_POS_TOP); michael@0: michael@0: /* Draw the gap; erase with background color before painting in michael@0: * case theme does not */ michael@0: gtk_style_apply_default_background(style, drawable, TRUE, michael@0: GTK_STATE_NORMAL, cliprect, michael@0: rect->x, michael@0: rect->y + gap_voffset michael@0: - gap_height, michael@0: rect->width, gap_height); michael@0: gtk_paint_box_gap(style, drawable, GTK_STATE_NORMAL, GTK_SHADOW_OUT, michael@0: cliprect, gTabWidget, "notebook", michael@0: rect->x - gap_loffset, michael@0: rect->y + gap_voffset - 3 * gap_height, michael@0: rect->width + gap_loffset + gap_roffset, michael@0: 3 * gap_height, GTK_POS_BOTTOM, michael@0: gap_loffset, rect->width); michael@0: } else { michael@0: /* Draw the tab */ michael@0: focusRect.height -= gap_voffset; michael@0: gtk_paint_extension(style, drawable, GTK_STATE_NORMAL, michael@0: GTK_SHADOW_OUT, cliprect, gTabWidget, "tab", michael@0: rect->x, rect->y, rect->width, michael@0: rect->height - gap_voffset, GTK_POS_BOTTOM); michael@0: michael@0: /* Draw the gap; erase with background color before painting in michael@0: * case theme does not */ michael@0: gtk_style_apply_default_background(style, drawable, TRUE, michael@0: GTK_STATE_NORMAL, cliprect, michael@0: rect->x, michael@0: rect->y + rect->height michael@0: - gap_voffset, michael@0: rect->width, gap_height); michael@0: gtk_paint_box_gap(style, drawable, GTK_STATE_NORMAL, GTK_SHADOW_OUT, michael@0: cliprect, gTabWidget, "notebook", michael@0: rect->x - gap_loffset, michael@0: rect->y + rect->height - gap_voffset, michael@0: rect->width + gap_loffset + gap_roffset, michael@0: 3 * gap_height, GTK_POS_TOP, michael@0: gap_loffset, rect->width); michael@0: } michael@0: michael@0: } michael@0: michael@0: if (state->focused) { michael@0: /* Paint the focus ring */ michael@0: focusRect.x += XTHICKNESS(style); michael@0: focusRect.width -= XTHICKNESS(style) * 2; michael@0: focusRect.y += YTHICKNESS(style); michael@0: focusRect.height -= YTHICKNESS(style) * 2; michael@0: michael@0: gtk_paint_focus(style, drawable, michael@0: /* Believe it or not, NORMAL means a selected tab and michael@0: ACTIVE means an unselected tab. */ michael@0: (flags & MOZ_GTK_TAB_SELECTED) ? GTK_STATE_NORMAL michael@0: : GTK_STATE_ACTIVE, michael@0: cliprect, gTabWidget, "tab", michael@0: focusRect.x, focusRect.y, focusRect.width, focusRect.height); michael@0: } michael@0: michael@0: return MOZ_GTK_SUCCESS; michael@0: } michael@0: michael@0: static gint michael@0: moz_gtk_tabpanels_paint(GdkDrawable* drawable, GdkRectangle* rect, michael@0: GdkRectangle* cliprect, GtkTextDirection direction) michael@0: { michael@0: /* We have three problems here: michael@0: * - Most engines draw gtk_paint_box differently to gtk_paint_box_gap, the michael@0: * former implies there are no tabs, eg. Clearlooks. michael@0: * - Wanting a gap of width 0 doesn't actually guarantee a zero-width gap, eg. michael@0: * Clearlooks. michael@0: * - Our old approach of a negative X position could cause rendering errors michael@0: * on the box's corner, eg. themes using the Pixbuf engine. michael@0: */ michael@0: GtkStyle* style; michael@0: GdkRectangle halfClipRect; michael@0: michael@0: ensure_tab_widget(); michael@0: gtk_widget_set_direction(gTabWidget, direction); michael@0: michael@0: style = gTabWidget->style; michael@0: TSOffsetStyleGCs(style, rect->x, rect->y); michael@0: michael@0: /* Our approach is as follows: michael@0: * - Draw the box in two passes. Pass in a clip rect to draw the left half of the michael@0: * box, with the gap specified to the right outside the clip rect so that it is michael@0: * not drawn. michael@0: * - The right half is drawn with the gap to the left outside the modified clip rect. michael@0: */ michael@0: if (!gdk_rectangle_intersect(rect, cliprect, &halfClipRect)) michael@0: return MOZ_GTK_SUCCESS; michael@0: michael@0: halfClipRect.width = (halfClipRect.width / 2) + 1; michael@0: gtk_paint_box_gap(style, drawable, GTK_STATE_NORMAL, GTK_SHADOW_OUT, michael@0: &halfClipRect, gTabWidget, "notebook", rect->x, rect->y, michael@0: rect->width, rect->height, michael@0: GTK_POS_TOP, halfClipRect.width + 1, 0); michael@0: michael@0: halfClipRect.x += halfClipRect.width; michael@0: gtk_paint_box_gap(style, drawable, GTK_STATE_NORMAL, GTK_SHADOW_OUT, michael@0: &halfClipRect, gTabWidget, "notebook", rect->x, rect->y, michael@0: rect->width, rect->height, michael@0: GTK_POS_TOP, -10, 0); michael@0: michael@0: return MOZ_GTK_SUCCESS; michael@0: } michael@0: michael@0: static gint michael@0: moz_gtk_tab_scroll_arrow_paint(GdkDrawable* drawable, GdkRectangle* rect, michael@0: GdkRectangle* cliprect, GtkWidgetState* state, michael@0: GtkArrowType arrow_type, michael@0: GtkTextDirection direction) michael@0: { michael@0: GtkStateType state_type = ConvertGtkState(state); michael@0: GtkShadowType shadow_type = state->active ? GTK_SHADOW_IN : GTK_SHADOW_OUT; michael@0: GtkStyle* style; michael@0: gint arrow_size = MIN(rect->width, rect->height); michael@0: gint x = rect->x + (rect->width - arrow_size) / 2; michael@0: gint y = rect->y + (rect->height - arrow_size) / 2; michael@0: michael@0: ensure_tab_widget(); michael@0: michael@0: style = gTabWidget->style; michael@0: TSOffsetStyleGCs(style, rect->x, rect->y); michael@0: michael@0: if (direction == GTK_TEXT_DIR_RTL) { michael@0: arrow_type = (arrow_type == GTK_ARROW_LEFT) ? michael@0: GTK_ARROW_RIGHT : GTK_ARROW_LEFT; michael@0: } michael@0: michael@0: gtk_paint_arrow(style, drawable, state_type, shadow_type, NULL, michael@0: gTabWidget, "notebook", arrow_type, TRUE, michael@0: x, y, arrow_size, arrow_size); michael@0: michael@0: return MOZ_GTK_SUCCESS; michael@0: } michael@0: michael@0: static gint michael@0: moz_gtk_menu_bar_paint(GdkDrawable* drawable, GdkRectangle* rect, michael@0: GdkRectangle* cliprect, GtkTextDirection direction) michael@0: { michael@0: GtkStyle* style; michael@0: GtkShadowType shadow_type; michael@0: ensure_menu_bar_widget(); michael@0: gtk_widget_set_direction(gMenuBarWidget, direction); michael@0: michael@0: gtk_widget_style_get(gMenuBarWidget, "shadow-type", &shadow_type, NULL); michael@0: michael@0: style = gMenuBarWidget->style; michael@0: michael@0: TSOffsetStyleGCs(style, rect->x, rect->y); michael@0: gtk_style_apply_default_background(style, drawable, TRUE, GTK_STATE_NORMAL, michael@0: cliprect, rect->x, rect->y, michael@0: rect->width, rect->height); michael@0: michael@0: gtk_paint_box(style, drawable, GTK_STATE_NORMAL, shadow_type, michael@0: cliprect, gMenuBarWidget, "menubar", rect->x, rect->y, michael@0: rect->width, rect->height); michael@0: return MOZ_GTK_SUCCESS; michael@0: } michael@0: michael@0: static gint michael@0: moz_gtk_menu_popup_paint(GdkDrawable* drawable, GdkRectangle* rect, michael@0: GdkRectangle* cliprect, GtkTextDirection direction) michael@0: { michael@0: GtkStyle* style; michael@0: ensure_menu_popup_widget(); michael@0: gtk_widget_set_direction(gMenuPopupWidget, direction); michael@0: michael@0: style = gMenuPopupWidget->style; michael@0: michael@0: TSOffsetStyleGCs(style, rect->x, rect->y); michael@0: gtk_style_apply_default_background(style, drawable, TRUE, GTK_STATE_NORMAL, michael@0: cliprect, rect->x, rect->y, michael@0: rect->width, rect->height); michael@0: gtk_paint_box(style, drawable, GTK_STATE_NORMAL, GTK_SHADOW_OUT, michael@0: cliprect, gMenuPopupWidget, "menu", michael@0: rect->x, rect->y, rect->width, rect->height); michael@0: michael@0: return MOZ_GTK_SUCCESS; michael@0: } michael@0: michael@0: static gint michael@0: moz_gtk_menu_separator_paint(GdkDrawable* drawable, GdkRectangle* rect, michael@0: GdkRectangle* cliprect, GtkTextDirection direction) michael@0: { michael@0: GtkStyle* style; michael@0: gboolean wide_separators; michael@0: gint separator_height; michael@0: guint horizontal_padding; michael@0: gint paint_height; michael@0: michael@0: ensure_menu_separator_widget(); michael@0: gtk_widget_set_direction(gMenuSeparatorWidget, direction); michael@0: michael@0: style = gMenuSeparatorWidget->style; michael@0: michael@0: gtk_widget_style_get(gMenuSeparatorWidget, michael@0: "wide-separators", &wide_separators, michael@0: "separator-height", &separator_height, michael@0: "horizontal-padding", &horizontal_padding, michael@0: NULL); michael@0: michael@0: TSOffsetStyleGCs(style, rect->x, rect->y); michael@0: michael@0: if (wide_separators) { michael@0: if (separator_height > rect->height) michael@0: separator_height = rect->height; michael@0: michael@0: gtk_paint_box(style, drawable, michael@0: GTK_STATE_NORMAL, GTK_SHADOW_ETCHED_OUT, michael@0: cliprect, gMenuSeparatorWidget, "hseparator", michael@0: rect->x + horizontal_padding + style->xthickness, michael@0: rect->y + (rect->height - separator_height - style->ythickness) / 2, michael@0: rect->width - 2 * (horizontal_padding + style->xthickness), michael@0: separator_height); michael@0: } else { michael@0: paint_height = style->ythickness; michael@0: if (paint_height > rect->height) michael@0: paint_height = rect->height; michael@0: michael@0: gtk_paint_hline(style, drawable, michael@0: GTK_STATE_NORMAL, cliprect, gMenuSeparatorWidget, michael@0: "menuitem", michael@0: rect->x + horizontal_padding + style->xthickness, michael@0: rect->x + rect->width - horizontal_padding - style->xthickness - 1, michael@0: rect->y + (rect->height - style->ythickness) / 2); michael@0: } michael@0: michael@0: return MOZ_GTK_SUCCESS; michael@0: } michael@0: michael@0: static gint michael@0: moz_gtk_menu_item_paint(GdkDrawable* drawable, GdkRectangle* rect, michael@0: GdkRectangle* cliprect, GtkWidgetState* state, michael@0: gint flags, GtkTextDirection direction) michael@0: { michael@0: GtkStyle* style; michael@0: GtkShadowType shadow_type; michael@0: GtkWidget* item_widget; michael@0: michael@0: if (state->inHover && !state->disabled) { michael@0: if (flags & MOZ_TOPLEVEL_MENU_ITEM) { michael@0: ensure_menu_bar_item_widget(); michael@0: item_widget = gMenuBarItemWidget; michael@0: } else { michael@0: ensure_menu_item_widget(); michael@0: item_widget = gMenuItemWidget; michael@0: } michael@0: gtk_widget_set_direction(item_widget, direction); michael@0: michael@0: style = item_widget->style; michael@0: TSOffsetStyleGCs(style, rect->x, rect->y); michael@0: michael@0: gtk_widget_style_get(item_widget, "selected-shadow-type", michael@0: &shadow_type, NULL); michael@0: michael@0: gtk_paint_box(style, drawable, GTK_STATE_PRELIGHT, shadow_type, michael@0: cliprect, item_widget, "menuitem", rect->x, rect->y, michael@0: rect->width, rect->height); michael@0: } michael@0: michael@0: return MOZ_GTK_SUCCESS; michael@0: } michael@0: michael@0: static gint michael@0: moz_gtk_menu_arrow_paint(GdkDrawable* drawable, GdkRectangle* rect, michael@0: GdkRectangle* cliprect, GtkWidgetState* state, michael@0: GtkTextDirection direction) michael@0: { michael@0: GtkStyle* style; michael@0: GtkStateType state_type = ConvertGtkState(state); michael@0: michael@0: ensure_menu_item_widget(); michael@0: gtk_widget_set_direction(gMenuItemWidget, direction); michael@0: michael@0: style = gMenuItemWidget->style; michael@0: michael@0: TSOffsetStyleGCs(style, rect->x, rect->y); michael@0: gtk_paint_arrow(style, drawable, state_type, michael@0: (state_type == GTK_STATE_PRELIGHT) ? GTK_SHADOW_IN : GTK_SHADOW_OUT, michael@0: cliprect, gMenuItemWidget, "menuitem", michael@0: (direction == GTK_TEXT_DIR_LTR) ? GTK_ARROW_RIGHT : GTK_ARROW_LEFT, michael@0: TRUE, rect->x, rect->y, rect->width, rect->height); michael@0: michael@0: return MOZ_GTK_SUCCESS; michael@0: } michael@0: michael@0: static gint michael@0: moz_gtk_check_menu_item_paint(GdkDrawable* drawable, GdkRectangle* rect, michael@0: GdkRectangle* cliprect, GtkWidgetState* state, michael@0: gboolean checked, gboolean isradio, michael@0: GtkTextDirection direction) michael@0: { michael@0: GtkStateType state_type = ConvertGtkState(state); michael@0: GtkStyle* style; michael@0: GtkShadowType shadow_type = (checked)?GTK_SHADOW_IN:GTK_SHADOW_OUT; michael@0: gint offset; michael@0: gint indicator_size, horizontal_padding; michael@0: gint x, y; michael@0: michael@0: moz_gtk_menu_item_paint(drawable, rect, cliprect, state, FALSE, direction); michael@0: michael@0: ensure_check_menu_item_widget(); michael@0: gtk_widget_set_direction(gCheckMenuItemWidget, direction); michael@0: michael@0: gtk_widget_style_get (gCheckMenuItemWidget, michael@0: "indicator-size", &indicator_size, michael@0: "horizontal-padding", &horizontal_padding, michael@0: NULL); michael@0: michael@0: if (checked || GTK_CHECK_MENU_ITEM(gCheckMenuItemWidget)->always_show_toggle) { michael@0: style = gCheckMenuItemWidget->style; michael@0: michael@0: offset = GTK_CONTAINER(gCheckMenuItemWidget)->border_width + michael@0: gCheckMenuItemWidget->style->xthickness + 2; michael@0: michael@0: x = (direction == GTK_TEXT_DIR_RTL) ? michael@0: rect->width - indicator_size - offset - horizontal_padding: rect->x + offset + horizontal_padding; michael@0: y = rect->y + (rect->height - indicator_size) / 2; michael@0: michael@0: TSOffsetStyleGCs(style, x, y); michael@0: gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(gCheckMenuItemWidget), michael@0: checked); michael@0: michael@0: if (isradio) { michael@0: gtk_paint_option(style, drawable, state_type, shadow_type, cliprect, michael@0: gCheckMenuItemWidget, "option", michael@0: x, y, indicator_size, indicator_size); michael@0: } else { michael@0: gtk_paint_check(style, drawable, state_type, shadow_type, cliprect, michael@0: gCheckMenuItemWidget, "check", michael@0: x, y, indicator_size, indicator_size); michael@0: } michael@0: } michael@0: michael@0: return MOZ_GTK_SUCCESS; michael@0: } michael@0: michael@0: static gint michael@0: moz_gtk_window_paint(GdkDrawable* drawable, GdkRectangle* rect, michael@0: GdkRectangle* cliprect, GtkTextDirection direction) michael@0: { michael@0: GtkStyle* style; michael@0: michael@0: ensure_window_widget(); michael@0: gtk_widget_set_direction(gProtoWindow, direction); michael@0: michael@0: style = gProtoWindow->style; michael@0: michael@0: TSOffsetStyleGCs(style, rect->x, rect->y); michael@0: gtk_style_apply_default_background(style, drawable, TRUE, michael@0: GTK_STATE_NORMAL, michael@0: cliprect, rect->x, rect->y, michael@0: rect->width, rect->height); michael@0: return MOZ_GTK_SUCCESS; michael@0: } michael@0: michael@0: gint michael@0: moz_gtk_get_widget_border(GtkThemeWidgetType widget, gint* left, gint* top, michael@0: gint* right, gint* bottom, GtkTextDirection direction, michael@0: gboolean inhtml) michael@0: { michael@0: GtkWidget* w; michael@0: michael@0: switch (widget) { michael@0: case MOZ_GTK_BUTTON: michael@0: { michael@0: GtkBorder inner_border; michael@0: gboolean interior_focus; michael@0: gint focus_width, focus_pad; michael@0: michael@0: ensure_button_widget(); michael@0: *left = *top = *right = *bottom = GTK_CONTAINER(gButtonWidget)->border_width; michael@0: michael@0: /* Don't add this padding in HTML, otherwise the buttons will michael@0: become too big and stuff the layout. */ michael@0: if (!inhtml) { michael@0: moz_gtk_widget_get_focus(gButtonWidget, &interior_focus, &focus_width, &focus_pad); michael@0: moz_gtk_button_get_inner_border(gButtonWidget, &inner_border); michael@0: *left += focus_width + focus_pad + inner_border.left; michael@0: *right += focus_width + focus_pad + inner_border.right; michael@0: *top += focus_width + focus_pad + inner_border.top; michael@0: *bottom += focus_width + focus_pad + inner_border.bottom; michael@0: } michael@0: michael@0: *left += gButtonWidget->style->xthickness; michael@0: *right += gButtonWidget->style->xthickness; michael@0: *top += gButtonWidget->style->ythickness; michael@0: *bottom += gButtonWidget->style->ythickness; michael@0: return MOZ_GTK_SUCCESS; michael@0: } michael@0: case MOZ_GTK_ENTRY: michael@0: ensure_entry_widget(); michael@0: w = gEntryWidget; michael@0: break; michael@0: case MOZ_GTK_TREEVIEW: michael@0: ensure_tree_view_widget(); michael@0: w = gTreeViewWidget; michael@0: break; michael@0: case MOZ_GTK_TREE_HEADER_CELL: michael@0: { michael@0: /* A Tree Header in GTK is just a different styled button michael@0: * It must be placed in a TreeView for getting the correct style michael@0: * assigned. michael@0: * That is why the following code is the same as for MOZ_GTK_BUTTON. michael@0: * */ michael@0: michael@0: GtkBorder inner_border; michael@0: gboolean interior_focus; michael@0: gint focus_width, focus_pad; michael@0: michael@0: ensure_tree_header_cell_widget(); michael@0: *left = *top = *right = *bottom = GTK_CONTAINER(gTreeHeaderCellWidget)->border_width; michael@0: michael@0: moz_gtk_widget_get_focus(gTreeHeaderCellWidget, &interior_focus, &focus_width, &focus_pad); michael@0: moz_gtk_button_get_inner_border(gTreeHeaderCellWidget, &inner_border); michael@0: *left += focus_width + focus_pad + inner_border.left; michael@0: *right += focus_width + focus_pad + inner_border.right; michael@0: *top += focus_width + focus_pad + inner_border.top; michael@0: *bottom += focus_width + focus_pad + inner_border.bottom; michael@0: michael@0: *left += gTreeHeaderCellWidget->style->xthickness; michael@0: *right += gTreeHeaderCellWidget->style->xthickness; michael@0: *top += gTreeHeaderCellWidget->style->ythickness; michael@0: *bottom += gTreeHeaderCellWidget->style->ythickness; michael@0: return MOZ_GTK_SUCCESS; michael@0: } michael@0: case MOZ_GTK_TREE_HEADER_SORTARROW: michael@0: ensure_tree_header_cell_widget(); michael@0: w = gTreeHeaderSortArrowWidget; michael@0: break; michael@0: case MOZ_GTK_DROPDOWN_ENTRY: michael@0: ensure_combo_box_entry_widgets(); michael@0: w = gComboBoxEntryTextareaWidget; michael@0: break; michael@0: case MOZ_GTK_DROPDOWN_ARROW: michael@0: ensure_combo_box_entry_widgets(); michael@0: w = gComboBoxEntryButtonWidget; michael@0: break; michael@0: case MOZ_GTK_DROPDOWN: michael@0: { michael@0: /* We need to account for the arrow on the dropdown, so text michael@0: * doesn't come too close to the arrow, or in some cases spill michael@0: * into the arrow. */ michael@0: gboolean ignored_interior_focus, wide_separators; michael@0: gint focus_width, focus_pad, separator_width; michael@0: GtkRequisition arrow_req; michael@0: michael@0: ensure_combo_box_widgets(); michael@0: michael@0: *left = GTK_CONTAINER(gComboBoxButtonWidget)->border_width; michael@0: michael@0: if (!inhtml) { michael@0: moz_gtk_widget_get_focus(gComboBoxButtonWidget, michael@0: &ignored_interior_focus, michael@0: &focus_width, &focus_pad); michael@0: *left += focus_width + focus_pad; michael@0: } michael@0: michael@0: *top = *left + gComboBoxButtonWidget->style->ythickness; michael@0: *left += gComboBoxButtonWidget->style->xthickness; michael@0: michael@0: *right = *left; *bottom = *top; michael@0: michael@0: /* If there is no separator, don't try to count its width. */ michael@0: separator_width = 0; michael@0: if (gComboBoxSeparatorWidget) { michael@0: gtk_widget_style_get(gComboBoxSeparatorWidget, michael@0: "wide-separators", &wide_separators, michael@0: "separator-width", &separator_width, michael@0: NULL); michael@0: michael@0: if (!wide_separators) michael@0: separator_width = michael@0: XTHICKNESS(gComboBoxSeparatorWidget->style); michael@0: } michael@0: michael@0: gtk_widget_size_request(gComboBoxArrowWidget, &arrow_req); michael@0: michael@0: if (direction == GTK_TEXT_DIR_RTL) michael@0: *left += separator_width + arrow_req.width; michael@0: else michael@0: *right += separator_width + arrow_req.width; michael@0: michael@0: return MOZ_GTK_SUCCESS; michael@0: } michael@0: case MOZ_GTK_TABPANELS: michael@0: ensure_tab_widget(); michael@0: w = gTabWidget; michael@0: break; michael@0: case MOZ_GTK_PROGRESSBAR: michael@0: ensure_progress_widget(); michael@0: w = gProgressWidget; michael@0: break; michael@0: case MOZ_GTK_SPINBUTTON_ENTRY: michael@0: case MOZ_GTK_SPINBUTTON_UP: michael@0: case MOZ_GTK_SPINBUTTON_DOWN: michael@0: ensure_spin_widget(); michael@0: w = gSpinWidget; michael@0: break; michael@0: case MOZ_GTK_SCALE_HORIZONTAL: michael@0: ensure_scale_widget(); michael@0: w = gHScaleWidget; michael@0: break; michael@0: case MOZ_GTK_SCALE_VERTICAL: michael@0: ensure_scale_widget(); michael@0: w = gVScaleWidget; michael@0: break; michael@0: case MOZ_GTK_FRAME: michael@0: ensure_frame_widget(); michael@0: w = gFrameWidget; michael@0: break; michael@0: case MOZ_GTK_CHECKBUTTON_LABEL: michael@0: case MOZ_GTK_RADIOBUTTON_LABEL: michael@0: { michael@0: gboolean interior_focus; michael@0: gint focus_width, focus_pad; michael@0: michael@0: /* If the focus is interior, then the label has a border of michael@0: (focus_width + focus_pad). */ michael@0: if (widget == MOZ_GTK_CHECKBUTTON_LABEL) { michael@0: ensure_checkbox_widget(); michael@0: moz_gtk_widget_get_focus(gCheckboxWidget, &interior_focus, michael@0: &focus_width, &focus_pad); michael@0: } michael@0: else { michael@0: ensure_radiobutton_widget(); michael@0: moz_gtk_widget_get_focus(gRadiobuttonWidget, &interior_focus, michael@0: &focus_width, &focus_pad); michael@0: } michael@0: michael@0: if (interior_focus) michael@0: *left = *top = *right = *bottom = (focus_width + focus_pad); michael@0: else michael@0: *left = *top = *right = *bottom = 0; michael@0: michael@0: return MOZ_GTK_SUCCESS; michael@0: } michael@0: michael@0: case MOZ_GTK_CHECKBUTTON_CONTAINER: michael@0: case MOZ_GTK_RADIOBUTTON_CONTAINER: michael@0: { michael@0: gboolean interior_focus; michael@0: gint focus_width, focus_pad; michael@0: michael@0: /* If the focus is _not_ interior, then the container has a border michael@0: of (focus_width + focus_pad). */ michael@0: if (widget == MOZ_GTK_CHECKBUTTON_CONTAINER) { michael@0: ensure_checkbox_widget(); michael@0: moz_gtk_widget_get_focus(gCheckboxWidget, &interior_focus, michael@0: &focus_width, &focus_pad); michael@0: w = gCheckboxWidget; michael@0: } else { michael@0: ensure_radiobutton_widget(); michael@0: moz_gtk_widget_get_focus(gRadiobuttonWidget, &interior_focus, michael@0: &focus_width, &focus_pad); michael@0: w = gRadiobuttonWidget; michael@0: } michael@0: michael@0: *left = *top = *right = *bottom = GTK_CONTAINER(w)->border_width; michael@0: michael@0: if (!interior_focus) { michael@0: *left += (focus_width + focus_pad); michael@0: *right += (focus_width + focus_pad); michael@0: *top += (focus_width + focus_pad); michael@0: *bottom += (focus_width + focus_pad); michael@0: } michael@0: michael@0: return MOZ_GTK_SUCCESS; michael@0: } michael@0: case MOZ_GTK_MENUPOPUP: michael@0: ensure_menu_popup_widget(); michael@0: w = gMenuPopupWidget; michael@0: break; michael@0: case MOZ_GTK_MENUITEM: michael@0: ensure_menu_item_widget(); michael@0: ensure_menu_bar_item_widget(); michael@0: w = gMenuItemWidget; michael@0: break; michael@0: case MOZ_GTK_CHECKMENUITEM: michael@0: case MOZ_GTK_RADIOMENUITEM: michael@0: ensure_check_menu_item_widget(); michael@0: w = gCheckMenuItemWidget; michael@0: break; michael@0: case MOZ_GTK_TAB: michael@0: ensure_tab_widget(); michael@0: w = gTabWidget; michael@0: break; michael@0: /* These widgets have no borders, since they are not containers. */ michael@0: case MOZ_GTK_SPLITTER_HORIZONTAL: michael@0: case MOZ_GTK_SPLITTER_VERTICAL: michael@0: case MOZ_GTK_CHECKBUTTON: michael@0: case MOZ_GTK_RADIOBUTTON: michael@0: case MOZ_GTK_SCROLLBAR_BUTTON: michael@0: case MOZ_GTK_SCROLLBAR_TRACK_HORIZONTAL: michael@0: case MOZ_GTK_SCROLLBAR_TRACK_VERTICAL: michael@0: case MOZ_GTK_SCROLLBAR_THUMB_HORIZONTAL: michael@0: case MOZ_GTK_SCROLLBAR_THUMB_VERTICAL: michael@0: case MOZ_GTK_SCALE_THUMB_HORIZONTAL: michael@0: case MOZ_GTK_SCALE_THUMB_VERTICAL: michael@0: case MOZ_GTK_GRIPPER: michael@0: case MOZ_GTK_PROGRESS_CHUNK: michael@0: case MOZ_GTK_PROGRESS_CHUNK_INDETERMINATE: michael@0: case MOZ_GTK_PROGRESS_CHUNK_VERTICAL_INDETERMINATE: michael@0: case MOZ_GTK_TREEVIEW_EXPANDER: michael@0: case MOZ_GTK_TOOLBAR_SEPARATOR: michael@0: case MOZ_GTK_MENUSEPARATOR: michael@0: /* These widgets have no borders.*/ michael@0: case MOZ_GTK_SPINBUTTON: michael@0: case MOZ_GTK_TOOLTIP: michael@0: case MOZ_GTK_WINDOW: michael@0: case MOZ_GTK_RESIZER: michael@0: case MOZ_GTK_MENUARROW: michael@0: case MOZ_GTK_TOOLBARBUTTON_ARROW: michael@0: case MOZ_GTK_TOOLBAR: michael@0: case MOZ_GTK_MENUBAR: michael@0: case MOZ_GTK_TAB_SCROLLARROW: michael@0: *left = *top = *right = *bottom = 0; michael@0: return MOZ_GTK_SUCCESS; michael@0: default: michael@0: g_warning("Unsupported widget type: %d", widget); michael@0: return MOZ_GTK_UNKNOWN_WIDGET; michael@0: } michael@0: michael@0: *right = *left = XTHICKNESS(w->style); michael@0: *bottom = *top = YTHICKNESS(w->style); michael@0: michael@0: return MOZ_GTK_SUCCESS; michael@0: } michael@0: michael@0: gint michael@0: moz_gtk_get_combo_box_entry_button_size(gint* width, gint* height) michael@0: { michael@0: /* michael@0: * We get the requisition of the drop down button, which includes michael@0: * all padding, border and focus line widths the button uses, michael@0: * as well as the minimum arrow size and its padding michael@0: * */ michael@0: GtkRequisition requisition; michael@0: ensure_combo_box_entry_widgets(); michael@0: michael@0: gtk_widget_size_request(gComboBoxEntryButtonWidget, &requisition); michael@0: *width = requisition.width; michael@0: *height = requisition.height; michael@0: michael@0: return MOZ_GTK_SUCCESS; michael@0: } michael@0: michael@0: gint michael@0: moz_gtk_get_tab_scroll_arrow_size(gint* width, gint* height) michael@0: { michael@0: gint arrow_size; michael@0: michael@0: ensure_tab_widget(); michael@0: gtk_widget_style_get(gTabWidget, michael@0: "scroll-arrow-hlength", &arrow_size, michael@0: NULL); michael@0: michael@0: *height = *width = arrow_size; michael@0: michael@0: return MOZ_GTK_SUCCESS; michael@0: } michael@0: michael@0: gint michael@0: moz_gtk_get_arrow_size(gint* width, gint* height) michael@0: { michael@0: GtkRequisition requisition; michael@0: ensure_button_arrow_widget(); michael@0: michael@0: gtk_widget_size_request(gButtonArrowWidget, &requisition); michael@0: *width = requisition.width; michael@0: *height = requisition.height; michael@0: michael@0: return MOZ_GTK_SUCCESS; michael@0: } michael@0: michael@0: gint michael@0: moz_gtk_get_toolbar_separator_width(gint* size) michael@0: { michael@0: gboolean wide_separators; michael@0: gint separator_width; michael@0: GtkStyle* style; michael@0: michael@0: ensure_toolbar_widget(); michael@0: michael@0: style = gToolbarWidget->style; michael@0: michael@0: gtk_widget_style_get(gToolbarWidget, michael@0: "space-size", size, michael@0: "wide-separators", &wide_separators, michael@0: "separator-width", &separator_width, michael@0: NULL); michael@0: michael@0: /* Just in case... */ michael@0: *size = MAX(*size, (wide_separators ? separator_width : style->xthickness)); michael@0: michael@0: return MOZ_GTK_SUCCESS; michael@0: } michael@0: michael@0: gint michael@0: moz_gtk_get_expander_size(gint* size) michael@0: { michael@0: ensure_expander_widget(); michael@0: gtk_widget_style_get(gExpanderWidget, michael@0: "expander-size", size, michael@0: NULL); michael@0: michael@0: return MOZ_GTK_SUCCESS; michael@0: } michael@0: michael@0: gint michael@0: moz_gtk_get_treeview_expander_size(gint* size) michael@0: { michael@0: ensure_tree_view_widget(); michael@0: gtk_widget_style_get(gTreeViewWidget, michael@0: "expander-size", size, michael@0: NULL); michael@0: michael@0: return MOZ_GTK_SUCCESS; michael@0: } michael@0: michael@0: gint michael@0: moz_gtk_get_menu_separator_height(gint *size) michael@0: { michael@0: gboolean wide_separators; michael@0: gint separator_height; michael@0: michael@0: ensure_menu_separator_widget(); michael@0: michael@0: gtk_widget_style_get(gMenuSeparatorWidget, michael@0: "wide-separators", &wide_separators, michael@0: "separator-height", &separator_height, michael@0: NULL); michael@0: michael@0: if (wide_separators) michael@0: *size = separator_height + gMenuSeparatorWidget->style->ythickness; michael@0: else michael@0: *size = gMenuSeparatorWidget->style->ythickness * 2; michael@0: michael@0: return MOZ_GTK_SUCCESS; michael@0: } michael@0: michael@0: gint michael@0: moz_gtk_get_scalethumb_metrics(GtkOrientation orient, gint* thumb_length, gint* thumb_height) michael@0: { michael@0: GtkWidget* widget; michael@0: michael@0: ensure_scale_widget(); michael@0: widget = ((orient == GTK_ORIENTATION_HORIZONTAL) ? gHScaleWidget : gVScaleWidget); michael@0: michael@0: gtk_widget_style_get (widget, michael@0: "slider_length", thumb_length, michael@0: "slider_width", thumb_height, michael@0: NULL); michael@0: michael@0: return MOZ_GTK_SUCCESS; michael@0: } michael@0: michael@0: gint michael@0: moz_gtk_get_scrollbar_metrics(MozGtkScrollbarMetrics *metrics) michael@0: { michael@0: ensure_scrollbar_widget(); michael@0: michael@0: gtk_widget_style_get (gHorizScrollbarWidget, michael@0: "slider_width", &metrics->slider_width, michael@0: "trough_border", &metrics->trough_border, michael@0: "stepper_size", &metrics->stepper_size, michael@0: "stepper_spacing", &metrics->stepper_spacing, michael@0: NULL); michael@0: michael@0: metrics->min_slider_size = michael@0: GTK_RANGE(gHorizScrollbarWidget)->min_slider_size; michael@0: michael@0: return MOZ_GTK_SUCCESS; michael@0: } michael@0: michael@0: gboolean michael@0: moz_gtk_images_in_menus() michael@0: { michael@0: gboolean result; michael@0: GtkSettings* settings; michael@0: michael@0: ensure_image_menu_item_widget(); michael@0: settings = gtk_widget_get_settings(gImageMenuItemWidget); michael@0: michael@0: g_object_get(settings, "gtk-menu-images", &result, NULL); michael@0: return result; michael@0: } michael@0: michael@0: gboolean michael@0: moz_gtk_images_in_buttons() michael@0: { michael@0: gboolean result; michael@0: GtkSettings* settings; michael@0: michael@0: ensure_button_widget(); michael@0: settings = gtk_widget_get_settings(gButtonWidget); michael@0: michael@0: g_object_get(settings, "gtk-button-images", &result, NULL); michael@0: return result; michael@0: } michael@0: michael@0: gint michael@0: moz_gtk_widget_paint(GtkThemeWidgetType widget, GdkDrawable* drawable, michael@0: GdkRectangle* rect, GdkRectangle* cliprect, michael@0: GtkWidgetState* state, gint flags, michael@0: GtkTextDirection direction) michael@0: { michael@0: switch (widget) { michael@0: case MOZ_GTK_BUTTON: michael@0: if (state->depressed) { michael@0: ensure_toggle_button_widget(); michael@0: return moz_gtk_button_paint(drawable, rect, cliprect, state, michael@0: (GtkReliefStyle) flags, michael@0: gToggleButtonWidget, direction); michael@0: } michael@0: ensure_button_widget(); michael@0: return moz_gtk_button_paint(drawable, rect, cliprect, state, michael@0: (GtkReliefStyle) flags, gButtonWidget, michael@0: direction); michael@0: break; michael@0: case MOZ_GTK_CHECKBUTTON: michael@0: case MOZ_GTK_RADIOBUTTON: michael@0: return moz_gtk_toggle_paint(drawable, rect, cliprect, state, michael@0: !!(flags & MOZ_GTK_WIDGET_CHECKED), michael@0: !!(flags & MOZ_GTK_WIDGET_INCONSISTENT), michael@0: (widget == MOZ_GTK_RADIOBUTTON), michael@0: direction); michael@0: break; michael@0: case MOZ_GTK_SCROLLBAR_BUTTON: michael@0: return moz_gtk_scrollbar_button_paint(drawable, rect, cliprect, state, michael@0: (GtkScrollbarButtonFlags) flags, michael@0: direction); michael@0: break; michael@0: case MOZ_GTK_SCROLLBAR_TRACK_HORIZONTAL: michael@0: case MOZ_GTK_SCROLLBAR_TRACK_VERTICAL: michael@0: return moz_gtk_scrollbar_trough_paint(widget, drawable, rect, michael@0: cliprect, state, direction); michael@0: break; michael@0: case MOZ_GTK_SCROLLBAR_THUMB_HORIZONTAL: michael@0: case MOZ_GTK_SCROLLBAR_THUMB_VERTICAL: michael@0: return moz_gtk_scrollbar_thumb_paint(widget, drawable, rect, michael@0: cliprect, state, direction); michael@0: break; michael@0: case MOZ_GTK_SCALE_HORIZONTAL: michael@0: case MOZ_GTK_SCALE_VERTICAL: michael@0: return moz_gtk_scale_paint(drawable, rect, cliprect, state, michael@0: (GtkOrientation) flags, direction); michael@0: break; michael@0: case MOZ_GTK_SCALE_THUMB_HORIZONTAL: michael@0: case MOZ_GTK_SCALE_THUMB_VERTICAL: michael@0: return moz_gtk_scale_thumb_paint(drawable, rect, cliprect, state, michael@0: (GtkOrientation) flags, direction); michael@0: break; michael@0: case MOZ_GTK_SPINBUTTON: michael@0: return moz_gtk_spin_paint(drawable, rect, direction); michael@0: break; michael@0: case MOZ_GTK_SPINBUTTON_UP: michael@0: case MOZ_GTK_SPINBUTTON_DOWN: michael@0: return moz_gtk_spin_updown_paint(drawable, rect, michael@0: (widget == MOZ_GTK_SPINBUTTON_DOWN), michael@0: state, direction); michael@0: break; michael@0: case MOZ_GTK_SPINBUTTON_ENTRY: michael@0: ensure_spin_widget(); michael@0: return moz_gtk_entry_paint(drawable, rect, cliprect, state, michael@0: gSpinWidget, direction); michael@0: break; michael@0: case MOZ_GTK_GRIPPER: michael@0: return moz_gtk_gripper_paint(drawable, rect, cliprect, state, michael@0: direction); michael@0: break; michael@0: case MOZ_GTK_TREEVIEW: michael@0: return moz_gtk_treeview_paint(drawable, rect, cliprect, state, michael@0: direction); michael@0: break; michael@0: case MOZ_GTK_TREE_HEADER_CELL: michael@0: return moz_gtk_tree_header_cell_paint(drawable, rect, cliprect, state, michael@0: flags, direction); michael@0: break; michael@0: case MOZ_GTK_TREE_HEADER_SORTARROW: michael@0: return moz_gtk_tree_header_sort_arrow_paint(drawable, rect, cliprect, michael@0: state, michael@0: (GtkArrowType) flags, michael@0: direction); michael@0: break; michael@0: case MOZ_GTK_TREEVIEW_EXPANDER: michael@0: return moz_gtk_treeview_expander_paint(drawable, rect, cliprect, state, michael@0: (GtkExpanderStyle) flags, direction); michael@0: break; michael@0: case MOZ_GTK_ENTRY: michael@0: ensure_entry_widget(); michael@0: return moz_gtk_entry_paint(drawable, rect, cliprect, state, michael@0: gEntryWidget, direction); michael@0: break; michael@0: case MOZ_GTK_DROPDOWN: michael@0: return moz_gtk_combo_box_paint(drawable, rect, cliprect, state, michael@0: (gboolean) flags, direction); michael@0: break; michael@0: case MOZ_GTK_DROPDOWN_ARROW: michael@0: return moz_gtk_combo_box_entry_button_paint(drawable, rect, cliprect, michael@0: state, flags, direction); michael@0: break; michael@0: case MOZ_GTK_DROPDOWN_ENTRY: michael@0: ensure_combo_box_entry_widgets(); michael@0: return moz_gtk_entry_paint(drawable, rect, cliprect, state, michael@0: gComboBoxEntryTextareaWidget, direction); michael@0: break; michael@0: case MOZ_GTK_CHECKBUTTON_CONTAINER: michael@0: case MOZ_GTK_RADIOBUTTON_CONTAINER: michael@0: return moz_gtk_container_paint(drawable, rect, cliprect, state, michael@0: (widget == MOZ_GTK_RADIOBUTTON_CONTAINER), michael@0: direction); michael@0: break; michael@0: case MOZ_GTK_CHECKBUTTON_LABEL: michael@0: case MOZ_GTK_RADIOBUTTON_LABEL: michael@0: return moz_gtk_toggle_label_paint(drawable, rect, cliprect, state, michael@0: (widget == MOZ_GTK_RADIOBUTTON_LABEL), michael@0: direction); michael@0: break; michael@0: case MOZ_GTK_TOOLBAR: michael@0: return moz_gtk_toolbar_paint(drawable, rect, cliprect, direction); michael@0: break; michael@0: case MOZ_GTK_TOOLBAR_SEPARATOR: michael@0: return moz_gtk_toolbar_separator_paint(drawable, rect, cliprect, michael@0: direction); michael@0: break; michael@0: case MOZ_GTK_TOOLTIP: michael@0: return moz_gtk_tooltip_paint(drawable, rect, cliprect, direction); michael@0: break; michael@0: case MOZ_GTK_FRAME: michael@0: return moz_gtk_frame_paint(drawable, rect, cliprect, direction); michael@0: break; michael@0: case MOZ_GTK_RESIZER: michael@0: return moz_gtk_resizer_paint(drawable, rect, cliprect, state, michael@0: direction); michael@0: break; michael@0: case MOZ_GTK_PROGRESSBAR: michael@0: return moz_gtk_progressbar_paint(drawable, rect, cliprect, direction); michael@0: break; michael@0: case MOZ_GTK_PROGRESS_CHUNK: michael@0: case MOZ_GTK_PROGRESS_CHUNK_INDETERMINATE: michael@0: case MOZ_GTK_PROGRESS_CHUNK_VERTICAL_INDETERMINATE: michael@0: return moz_gtk_progress_chunk_paint(drawable, rect, cliprect, michael@0: direction, widget); michael@0: break; michael@0: case MOZ_GTK_TAB: michael@0: return moz_gtk_tab_paint(drawable, rect, cliprect, state, michael@0: (GtkTabFlags) flags, direction); michael@0: break; michael@0: case MOZ_GTK_TABPANELS: michael@0: return moz_gtk_tabpanels_paint(drawable, rect, cliprect, direction); michael@0: break; michael@0: case MOZ_GTK_TAB_SCROLLARROW: michael@0: return moz_gtk_tab_scroll_arrow_paint(drawable, rect, cliprect, state, michael@0: (GtkArrowType) flags, direction); michael@0: break; michael@0: case MOZ_GTK_MENUBAR: michael@0: return moz_gtk_menu_bar_paint(drawable, rect, cliprect, direction); michael@0: break; michael@0: case MOZ_GTK_MENUPOPUP: michael@0: return moz_gtk_menu_popup_paint(drawable, rect, cliprect, direction); michael@0: break; michael@0: case MOZ_GTK_MENUSEPARATOR: michael@0: return moz_gtk_menu_separator_paint(drawable, rect, cliprect, michael@0: direction); michael@0: break; michael@0: case MOZ_GTK_MENUITEM: michael@0: return moz_gtk_menu_item_paint(drawable, rect, cliprect, state, flags, michael@0: direction); michael@0: break; michael@0: case MOZ_GTK_MENUARROW: michael@0: return moz_gtk_menu_arrow_paint(drawable, rect, cliprect, state, michael@0: direction); michael@0: break; michael@0: case MOZ_GTK_TOOLBARBUTTON_ARROW: michael@0: return moz_gtk_arrow_paint(drawable, rect, cliprect, state, michael@0: (GtkArrowType) flags, direction); michael@0: break; michael@0: case MOZ_GTK_CHECKMENUITEM: michael@0: case MOZ_GTK_RADIOMENUITEM: michael@0: return moz_gtk_check_menu_item_paint(drawable, rect, cliprect, state, michael@0: (gboolean) flags, michael@0: (widget == MOZ_GTK_RADIOMENUITEM), michael@0: direction); michael@0: break; michael@0: case MOZ_GTK_SPLITTER_HORIZONTAL: michael@0: return moz_gtk_vpaned_paint(drawable, rect, cliprect, state); michael@0: break; michael@0: case MOZ_GTK_SPLITTER_VERTICAL: michael@0: return moz_gtk_hpaned_paint(drawable, rect, cliprect, state); michael@0: break; michael@0: case MOZ_GTK_WINDOW: michael@0: return moz_gtk_window_paint(drawable, rect, cliprect, direction); michael@0: break; michael@0: default: michael@0: g_warning("Unknown widget type: %d", widget); michael@0: } michael@0: michael@0: return MOZ_GTK_UNKNOWN_WIDGET; michael@0: } michael@0: michael@0: GtkWidget* moz_gtk_get_scrollbar_widget(void) michael@0: { michael@0: NS_ASSERTION(is_initialized, "Forgot to call moz_gtk_init()"); michael@0: ensure_scrollbar_widget(); michael@0: return gHorizScrollbarWidget; michael@0: } michael@0: michael@0: gint michael@0: moz_gtk_shutdown() michael@0: { michael@0: GtkWidgetClass *entry_class; michael@0: michael@0: if (gTooltipWidget) michael@0: gtk_widget_destroy(gTooltipWidget); michael@0: /* This will destroy all of our widgets */ michael@0: if (gProtoWindow) michael@0: gtk_widget_destroy(gProtoWindow); michael@0: michael@0: gProtoWindow = NULL; michael@0: gProtoLayout = NULL; michael@0: gButtonWidget = NULL; michael@0: gToggleButtonWidget = NULL; michael@0: gButtonArrowWidget = NULL; michael@0: gCheckboxWidget = NULL; michael@0: gRadiobuttonWidget = NULL; michael@0: gHorizScrollbarWidget = NULL; michael@0: gVertScrollbarWidget = NULL; michael@0: gSpinWidget = NULL; michael@0: gHScaleWidget = NULL; michael@0: gVScaleWidget = NULL; michael@0: gEntryWidget = NULL; michael@0: gComboBoxWidget = NULL; michael@0: gComboBoxButtonWidget = NULL; michael@0: gComboBoxSeparatorWidget = NULL; michael@0: gComboBoxArrowWidget = NULL; michael@0: gComboBoxEntryWidget = NULL; michael@0: gComboBoxEntryButtonWidget = NULL; michael@0: gComboBoxEntryArrowWidget = NULL; michael@0: gComboBoxEntryTextareaWidget = NULL; michael@0: gHandleBoxWidget = NULL; michael@0: gToolbarWidget = NULL; michael@0: gStatusbarWidget = NULL; michael@0: gFrameWidget = NULL; michael@0: gProgressWidget = NULL; michael@0: gTabWidget = NULL; michael@0: gTooltipWidget = NULL; michael@0: gMenuBarWidget = NULL; michael@0: gMenuBarItemWidget = NULL; michael@0: gMenuPopupWidget = NULL; michael@0: gMenuItemWidget = NULL; michael@0: gImageMenuItemWidget = NULL; michael@0: gCheckMenuItemWidget = NULL; michael@0: gTreeViewWidget = NULL; michael@0: gMiddleTreeViewColumn = NULL; michael@0: gTreeHeaderCellWidget = NULL; michael@0: gTreeHeaderSortArrowWidget = NULL; michael@0: gExpanderWidget = NULL; michael@0: gToolbarSeparatorWidget = NULL; michael@0: gMenuSeparatorWidget = NULL; michael@0: gHPanedWidget = NULL; michael@0: gVPanedWidget = NULL; michael@0: gScrolledWindowWidget = NULL; michael@0: michael@0: entry_class = g_type_class_peek(GTK_TYPE_ENTRY); michael@0: g_type_class_unref(entry_class); michael@0: michael@0: is_initialized = FALSE; michael@0: michael@0: return MOZ_GTK_SUCCESS; michael@0: }