widget/gtk/gtk3drawing.c

Thu, 15 Jan 2015 15:59:08 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Thu, 15 Jan 2015 15:59:08 +0100
branch
TOR_BUG_9701
changeset 10
ac0c01689b40
permissions
-rw-r--r--

Implement a real Private Browsing Mode condition by changing the API/ABI;
This solves Tor bug #9701, complying with disk avoidance documented in
https://www.torproject.org/projects/torbrowser/design/#disk-avoidance.

     1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
     2 /* This Source Code Form is subject to the terms of the Mozilla Public
     3  * License, v. 2.0. If a copy of the MPL was not distributed with this
     4  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
     6 /*
     7  * This file contains painting functions for each of the gtk2 widgets.
     8  * Adapted from the gtkdrawing.c, and gtk+2.0 source.
     9  */
    11 #include <gtk/gtk.h>
    12 #include <gdk/gdkprivate.h>
    13 #include <string.h>
    14 #include "gtkdrawing.h"
    15 #include "nsDebug.h"
    16 #include "prinrval.h"
    18 #include <math.h>
    20 static GtkWidget* gProtoWindow;
    21 static GtkWidget* gProtoLayout;
    22 static GtkWidget* gButtonWidget;
    23 static GtkWidget* gToggleMenuButtonWidget;
    24 static GtkWidget* gButtonArrowWidget;
    25 static GtkWidget* gCheckboxWidget;
    26 static GtkWidget* gRadiobuttonWidget;
    27 static GtkWidget* gHorizScrollbarWidget;
    28 static GtkWidget* gVertScrollbarWidget;
    29 static GtkWidget* gSpinWidget;
    30 static GtkWidget* gHScaleWidget;
    31 static GtkWidget* gVScaleWidget;
    32 static GtkWidget* gEntryWidget;
    33 static GtkWidget* gComboBoxWidget;
    34 static GtkWidget* gComboBoxButtonWidget;
    35 static GtkWidget* gComboBoxArrowWidget;
    36 static GtkWidget* gComboBoxSeparatorWidget;
    37 static GtkWidget* gComboBoxEntryWidget;
    38 static GtkWidget* gComboBoxEntryTextareaWidget;
    39 static GtkWidget* gComboBoxEntryButtonWidget;
    40 static GtkWidget* gComboBoxEntryArrowWidget;
    41 static GtkWidget* gHandleBoxWidget;
    42 static GtkWidget* gToolbarWidget;
    43 static GtkWidget* gFrameWidget;
    44 static GtkWidget* gStatusbarWidget;
    45 static GtkWidget* gProgressWidget;
    46 static GtkWidget* gTabWidget;
    47 static GtkWidget* gTooltipWidget;
    48 static GtkWidget* gMenuBarWidget;
    49 static GtkWidget* gMenuBarItemWidget;
    50 static GtkWidget* gMenuPopupWidget;
    51 static GtkWidget* gMenuItemWidget;
    52 static GtkWidget* gImageMenuItemWidget;
    53 static GtkWidget* gCheckMenuItemWidget;
    54 static GtkWidget* gTreeViewWidget;
    55 static GtkTreeViewColumn* gMiddleTreeViewColumn;
    56 static GtkWidget* gTreeHeaderCellWidget;
    57 static GtkWidget* gTreeHeaderSortArrowWidget;
    58 static GtkWidget* gExpanderWidget;
    59 static GtkWidget* gToolbarSeparatorWidget;
    60 static GtkWidget* gMenuSeparatorWidget;
    61 static GtkWidget* gHPanedWidget;
    62 static GtkWidget* gVPanedWidget;
    63 static GtkWidget* gScrolledWindowWidget;
    65 static style_prop_t style_prop_func;
    66 static gboolean have_arrow_scaling;
    67 static gboolean is_initialized;
    69 #define ARROW_UP      0
    70 #define ARROW_DOWN    G_PI
    71 #define ARROW_RIGHT   G_PI_2
    72 #define ARROW_LEFT    (G_PI+G_PI_2)
    74 static GtkStateFlags
    75 GetStateFlagsFromGtkWidgetState(GtkWidgetState* state)
    76 {
    77     GtkStateFlags stateFlags = GTK_STATE_FLAG_NORMAL;
    79     if (state->disabled)
    80         stateFlags = GTK_STATE_FLAG_INSENSITIVE;
    81     else {    
    82         if (state->depressed || state->active)
    83             stateFlags |= GTK_STATE_FLAG_ACTIVE;
    84         if (state->inHover)
    85             stateFlags |= GTK_STATE_FLAG_PRELIGHT;
    86         if (state->focused)
    87             stateFlags |= GTK_STATE_FLAG_FOCUSED;
    88     }
    90     return stateFlags;
    91 }
    93 /* Because we have such an unconventional way of drawing widgets, signal to the GTK theme engine
    94    that they are drawing for Mozilla instead of a conventional GTK app so they can do any specific
    95    things they may want to do. */
    96 static void
    97 moz_gtk_set_widget_name(GtkWidget* widget)
    98 {
    99     gtk_widget_set_name(widget, "MozillaGtkWidget");
   100 }
   102 gint
   103 moz_gtk_enable_style_props(style_prop_t styleGetProp)
   104 {
   105     style_prop_func = styleGetProp;
   106     return MOZ_GTK_SUCCESS;
   107 }
   109 static gint
   110 ensure_window_widget()
   111 {
   112     if (!gProtoWindow) {
   113         gProtoWindow = gtk_window_new(GTK_WINDOW_POPUP);
   114         gtk_widget_realize(gProtoWindow);
   115         moz_gtk_set_widget_name(gProtoWindow);
   116     }
   117     return MOZ_GTK_SUCCESS;
   118 }
   120 static gint
   121 setup_widget_prototype(GtkWidget* widget)
   122 {
   123     ensure_window_widget();
   124     if (!gProtoLayout) {
   125         gProtoLayout = gtk_fixed_new();
   126         gtk_container_add(GTK_CONTAINER(gProtoWindow), gProtoLayout);
   127     }
   129     gtk_container_add(GTK_CONTAINER(gProtoLayout), widget);
   130     gtk_widget_realize(widget);
   131     return MOZ_GTK_SUCCESS;
   132 }
   134 static gint
   135 ensure_button_widget()
   136 {
   137     if (!gButtonWidget) {
   138         gButtonWidget = gtk_button_new_with_label("M");
   139         setup_widget_prototype(gButtonWidget);
   140     }
   141     return MOZ_GTK_SUCCESS;
   142 }
   144 static gint
   145 ensure_hpaned_widget()
   146 {
   147     if (!gHPanedWidget) {
   148         gHPanedWidget = gtk_hpaned_new();
   149         setup_widget_prototype(gHPanedWidget);
   150     }
   151     return MOZ_GTK_SUCCESS;
   152 }
   154 static gint
   155 ensure_vpaned_widget()
   156 {
   157     if (!gVPanedWidget) {
   158         gVPanedWidget = gtk_vpaned_new();
   159         setup_widget_prototype(gVPanedWidget);
   160     }
   161     return MOZ_GTK_SUCCESS;
   162 }
   164 static gint
   165 ensure_toggle_menu_button_widget()
   166 {
   167     if (!gToggleMenuButtonWidget) {
   168         gToggleMenuButtonWidget = gtk_menu_button_new();
   169         setup_widget_prototype(gToggleMenuButtonWidget);
   170   }
   171   return MOZ_GTK_SUCCESS;
   172 }
   174 static gint
   175 ensure_button_arrow_widget()
   176 {
   177     if (!gButtonArrowWidget) {
   178         ensure_toggle_menu_button_widget();
   179         gButtonArrowWidget = gtk_bin_get_child(GTK_BIN(gToggleMenuButtonWidget));
   180     }
   181     return MOZ_GTK_SUCCESS;
   182 }
   184 static gint
   185 ensure_checkbox_widget()
   186 {
   187     if (!gCheckboxWidget) {
   188         gCheckboxWidget = gtk_check_button_new_with_label("M");
   189         setup_widget_prototype(gCheckboxWidget);
   190     }
   191     return MOZ_GTK_SUCCESS;
   192 }
   194 static gint
   195 ensure_radiobutton_widget()
   196 {
   197     if (!gRadiobuttonWidget) {
   198         gRadiobuttonWidget = gtk_radio_button_new_with_label(NULL, "M");
   199         setup_widget_prototype(gRadiobuttonWidget);
   200     }
   201     return MOZ_GTK_SUCCESS;
   202 }
   204 static gint
   205 ensure_scrollbar_widget()
   206 {
   207     if (!gVertScrollbarWidget) {
   208         gVertScrollbarWidget = gtk_vscrollbar_new(NULL);
   209         setup_widget_prototype(gVertScrollbarWidget);
   210     }
   211     if (!gHorizScrollbarWidget) {
   212         gHorizScrollbarWidget = gtk_hscrollbar_new(NULL);
   213         setup_widget_prototype(gHorizScrollbarWidget);
   214     }
   215     return MOZ_GTK_SUCCESS;
   216 }
   218 static gint
   219 ensure_spin_widget()
   220 {
   221   if (!gSpinWidget) {
   222     gSpinWidget = gtk_spin_button_new(NULL, 1, 0);
   223     setup_widget_prototype(gSpinWidget);
   224   }
   225   return MOZ_GTK_SUCCESS;
   226 }
   228 static gint
   229 ensure_scale_widget()
   230 {
   231   if (!gHScaleWidget) {
   232     gHScaleWidget = gtk_hscale_new(NULL);
   233     setup_widget_prototype(gHScaleWidget);
   234   }
   235   if (!gVScaleWidget) {
   236     gVScaleWidget = gtk_vscale_new(NULL);
   237     setup_widget_prototype(gVScaleWidget);
   238   }
   239   return MOZ_GTK_SUCCESS;
   240 }
   242 static gint
   243 ensure_entry_widget()
   244 {
   245     if (!gEntryWidget) {
   246         gEntryWidget = gtk_entry_new();
   247         setup_widget_prototype(gEntryWidget);
   248     }
   249     return MOZ_GTK_SUCCESS;
   250 }
   252 /* We need to have pointers to the inner widgets (button, separator, arrow)
   253  * of the ComboBox to get the correct rendering from theme engines which
   254  * special cases their look. Since the inner layout can change, we ask GTK
   255  * to NULL our pointers when they are about to become invalid because the
   256  * corresponding widgets don't exist anymore. It's the role of
   257  * g_object_add_weak_pointer().
   258  * Note that if we don't find the inner widgets (which shouldn't happen), we
   259  * fallback to use generic "non-inner" widgets, and they don't need that kind
   260  * of weak pointer since they are explicit children of gProtoWindow and as
   261  * such GTK holds a strong reference to them. */
   262 static void
   263 moz_gtk_get_combo_box_inner_button(GtkWidget *widget, gpointer client_data)
   264 {
   265     if (GTK_IS_TOGGLE_BUTTON(widget)) {
   266         gComboBoxButtonWidget = widget;
   267         g_object_add_weak_pointer(G_OBJECT(widget),
   268                                   (gpointer) &gComboBoxButtonWidget);
   269         gtk_widget_realize(widget);
   270     }
   271 }
   273 static void
   274 moz_gtk_get_combo_box_button_inner_widgets(GtkWidget *widget,
   275                                            gpointer client_data)
   276 {
   277     if (GTK_IS_SEPARATOR(widget)) {
   278         gComboBoxSeparatorWidget = widget;
   279         g_object_add_weak_pointer(G_OBJECT(widget),
   280                                   (gpointer) &gComboBoxSeparatorWidget);
   281     } else if (GTK_IS_ARROW(widget)) {
   282         gComboBoxArrowWidget = widget;
   283         g_object_add_weak_pointer(G_OBJECT(widget),
   284                                   (gpointer) &gComboBoxArrowWidget);
   285     } else
   286         return;
   287     gtk_widget_realize(widget);
   288 }
   290 static gint
   291 ensure_combo_box_widgets()
   292 {
   293     GtkWidget* buttonChild;
   295     if (gComboBoxButtonWidget && gComboBoxArrowWidget)
   296         return MOZ_GTK_SUCCESS;
   298     /* Create a ComboBox if needed */
   299     if (!gComboBoxWidget) {
   300         gComboBoxWidget = gtk_combo_box_new();
   301         setup_widget_prototype(gComboBoxWidget);
   302     }
   304     /* Get its inner Button */
   305     gtk_container_forall(GTK_CONTAINER(gComboBoxWidget),
   306                          moz_gtk_get_combo_box_inner_button,
   307                          NULL);
   309     if (gComboBoxButtonWidget) {
   310         /* Get the widgets inside the Button */
   311         buttonChild = gtk_bin_get_child(GTK_BIN(gComboBoxButtonWidget));
   312         if (GTK_IS_BOX(buttonChild)) {
   313             /* appears-as-list = FALSE, cell-view = TRUE; the button
   314              * contains an hbox. This hbox is there because the ComboBox
   315              * needs to place a cell renderer, a separator, and an arrow in
   316              * the button when appears-as-list is FALSE. */
   317             gtk_container_forall(GTK_CONTAINER(buttonChild),
   318                                  moz_gtk_get_combo_box_button_inner_widgets,
   319                                  NULL);
   320         } else if(GTK_IS_ARROW(buttonChild)) {
   321             /* appears-as-list = TRUE, or cell-view = FALSE;
   322              * the button only contains an arrow */
   323             gComboBoxArrowWidget = buttonChild;
   324             g_object_add_weak_pointer(G_OBJECT(buttonChild), (gpointer)
   325                                       &gComboBoxArrowWidget);
   326             gtk_widget_realize(gComboBoxArrowWidget);
   327         }
   328     } else {
   329         /* Shouldn't be reached with current internal gtk implementation; we
   330          * use a generic toggle button as last resort fallback to avoid
   331          * crashing. */
   332         ensure_toggle_menu_button_widget();
   333         gComboBoxButtonWidget = gToggleMenuButtonWidget;
   334     }
   336     if (!gComboBoxArrowWidget) {
   337         /* Shouldn't be reached with current internal gtk implementation;
   338          * we gButtonArrowWidget as last resort fallback to avoid
   339          * crashing. */
   340         ensure_button_arrow_widget();
   341         gComboBoxArrowWidget = gButtonArrowWidget;
   342     }
   344     /* We don't test the validity of gComboBoxSeparatorWidget since there
   345      * is none when "appears-as-list" = TRUE or "cell-view" = FALSE; if it
   346      * is invalid we just won't paint it. */
   348     return MOZ_GTK_SUCCESS;
   349 }
   351 /* We need to have pointers to the inner widgets (entry, button, arrow) of
   352  * the ComboBoxEntry to get the correct rendering from theme engines which
   353  * special cases their look. Since the inner layout can change, we ask GTK
   354  * to NULL our pointers when they are about to become invalid because the
   355  * corresponding widgets don't exist anymore. It's the role of
   356  * g_object_add_weak_pointer().
   357  * Note that if we don't find the inner widgets (which shouldn't happen), we
   358  * fallback to use generic "non-inner" widgets, and they don't need that kind
   359  * of weak pointer since they are explicit children of gProtoWindow and as
   360  * such GTK holds a strong reference to them. */
   361 static void
   362 moz_gtk_get_combo_box_entry_inner_widgets(GtkWidget *widget,
   363                                           gpointer client_data)
   364 {
   365     if (GTK_IS_TOGGLE_BUTTON(widget)) {
   366         gComboBoxEntryButtonWidget = widget;
   367         g_object_add_weak_pointer(G_OBJECT(widget),
   368                                   (gpointer) &gComboBoxEntryButtonWidget);
   369     } else if (GTK_IS_ENTRY(widget)) {
   370         gComboBoxEntryTextareaWidget = widget;
   371         g_object_add_weak_pointer(G_OBJECT(widget),
   372                                   (gpointer) &gComboBoxEntryTextareaWidget);
   373     } else
   374         return;
   375     gtk_widget_realize(widget);
   376 }
   378 static void
   379 moz_gtk_get_combo_box_entry_arrow(GtkWidget *widget, gpointer client_data)
   380 {
   381     if (GTK_IS_ARROW(widget)) {
   382         gComboBoxEntryArrowWidget = widget;
   383         g_object_add_weak_pointer(G_OBJECT(widget),
   384                                   (gpointer) &gComboBoxEntryArrowWidget);
   385         gtk_widget_realize(widget);
   386     }
   387 }
   389 static gint
   390 ensure_combo_box_entry_widgets()
   391 {
   392     GtkWidget* buttonChild;
   394     if (gComboBoxEntryTextareaWidget &&
   395             gComboBoxEntryButtonWidget &&
   396             gComboBoxEntryArrowWidget)
   397         return MOZ_GTK_SUCCESS;
   399     /* Create a ComboBoxEntry if needed */
   400     if (!gComboBoxEntryWidget) {
   401         gComboBoxEntryWidget = gtk_combo_box_new_with_entry();
   402         setup_widget_prototype(gComboBoxEntryWidget);
   403     }
   405     /* Get its inner Entry and Button */
   406     gtk_container_forall(GTK_CONTAINER(gComboBoxEntryWidget),
   407                          moz_gtk_get_combo_box_entry_inner_widgets,
   408                          NULL);
   410     if (!gComboBoxEntryTextareaWidget) {
   411         ensure_entry_widget();
   412         gComboBoxEntryTextareaWidget = gEntryWidget;
   413     }
   415     if (gComboBoxEntryButtonWidget) {
   416         /* Get the Arrow inside the Button */
   417         buttonChild = gtk_bin_get_child(GTK_BIN(gComboBoxEntryButtonWidget));
   418         if (GTK_IS_BOX(buttonChild)) {
   419            /* appears-as-list = FALSE, cell-view = TRUE; the button
   420              * contains an hbox. This hbox is there because the ComboBox
   421              * needs to place a cell renderer, a separator, and an arrow in
   422              * the button when appears-as-list is FALSE. */
   423             gtk_container_forall(GTK_CONTAINER(buttonChild),
   424                                  moz_gtk_get_combo_box_entry_arrow,
   425                                  NULL);
   426         } else if(GTK_IS_ARROW(buttonChild)) {
   427             /* appears-as-list = TRUE, or cell-view = FALSE;
   428              * the button only contains an arrow */
   429             gComboBoxEntryArrowWidget = buttonChild;
   430             g_object_add_weak_pointer(G_OBJECT(buttonChild), (gpointer)
   431                                       &gComboBoxEntryArrowWidget);
   432             gtk_widget_realize(gComboBoxEntryArrowWidget);
   433         }
   434     } else {
   435         /* Shouldn't be reached with current internal gtk implementation;
   436          * we use a generic toggle button as last resort fallback to avoid
   437          * crashing. */
   438         ensure_toggle_menu_button_widget();
   439         gComboBoxEntryButtonWidget = gToggleMenuButtonWidget;
   440     }
   442     if (!gComboBoxEntryArrowWidget) {
   443         /* Shouldn't be reached with current internal gtk implementation;
   444          * we gButtonArrowWidget as last resort fallback to avoid
   445          * crashing. */
   446         ensure_button_arrow_widget();
   447         gComboBoxEntryArrowWidget = gButtonArrowWidget;
   448     }
   450     return MOZ_GTK_SUCCESS;
   451 }
   454 static gint
   455 ensure_handlebox_widget()
   456 {
   457     if (!gHandleBoxWidget) {
   458         gHandleBoxWidget = gtk_handle_box_new();
   459         setup_widget_prototype(gHandleBoxWidget);
   460     }
   461     return MOZ_GTK_SUCCESS;
   462 }
   464 static gint
   465 ensure_toolbar_widget()
   466 {
   467     if (!gToolbarWidget) {
   468         ensure_handlebox_widget();
   469         gToolbarWidget = gtk_toolbar_new();
   470         gtk_container_add(GTK_CONTAINER(gHandleBoxWidget), gToolbarWidget);
   471         gtk_widget_realize(gToolbarWidget);
   472     }
   473     return MOZ_GTK_SUCCESS;
   474 }
   476 static gint
   477 ensure_toolbar_separator_widget()
   478 {
   479     if (!gToolbarSeparatorWidget) {
   480         ensure_toolbar_widget();
   481         gToolbarSeparatorWidget = GTK_WIDGET(gtk_separator_tool_item_new());
   482         setup_widget_prototype(gToolbarSeparatorWidget);
   483     }
   484     return MOZ_GTK_SUCCESS;
   485 }
   487 static gint
   488 ensure_tooltip_widget()
   489 {
   490     if (!gTooltipWidget) {
   491         gTooltipWidget = gtk_window_new(GTK_WINDOW_POPUP);
   492         gtk_widget_realize(gTooltipWidget);
   493         moz_gtk_set_widget_name(gTooltipWidget);
   494     }
   495     return MOZ_GTK_SUCCESS;
   496 }
   498 static gint
   499 ensure_tab_widget()
   500 {
   501     if (!gTabWidget) {
   502         gTabWidget = gtk_notebook_new();
   503         setup_widget_prototype(gTabWidget);
   504     }
   505     return MOZ_GTK_SUCCESS;
   506 }
   508 static gint
   509 ensure_progress_widget()
   510 {
   511     if (!gProgressWidget) {
   512         gProgressWidget = gtk_progress_bar_new();
   513         setup_widget_prototype(gProgressWidget);
   514     }
   515     return MOZ_GTK_SUCCESS;
   516 }
   518 static gint
   519 ensure_statusbar_widget()
   520 {
   521     if (!gStatusbarWidget) {
   522       gStatusbarWidget = gtk_statusbar_new();
   523       setup_widget_prototype(gStatusbarWidget);
   524     }
   525     return MOZ_GTK_SUCCESS;
   526 }
   528 static gint
   529 ensure_frame_widget()
   530 {
   531     if (!gFrameWidget) {
   532         ensure_statusbar_widget();
   533         gFrameWidget = gtk_frame_new(NULL);
   534         gtk_container_add(GTK_CONTAINER(gStatusbarWidget), gFrameWidget);
   535         gtk_widget_realize(gFrameWidget);
   536     }
   537     return MOZ_GTK_SUCCESS;
   538 }
   540 static gint
   541 ensure_menu_bar_widget()
   542 {
   543     if (!gMenuBarWidget) {
   544         gMenuBarWidget = gtk_menu_bar_new();
   545         setup_widget_prototype(gMenuBarWidget);
   546     }
   547     return MOZ_GTK_SUCCESS;
   548 }
   550 static gint
   551 ensure_menu_bar_item_widget()
   552 {
   553     if (!gMenuBarItemWidget) {
   554         ensure_menu_bar_widget();
   555         gMenuBarItemWidget = gtk_menu_item_new();
   556         gtk_menu_shell_append(GTK_MENU_SHELL(gMenuBarWidget),
   557                               gMenuBarItemWidget);
   558         gtk_widget_realize(gMenuBarItemWidget);
   559     }
   560     return MOZ_GTK_SUCCESS;
   561 }
   563 static gint
   564 ensure_menu_popup_widget()
   565 {
   566     if (!gMenuPopupWidget) {
   567         ensure_menu_bar_item_widget();
   568         gMenuPopupWidget = gtk_menu_new();
   569         gtk_menu_item_set_submenu(GTK_MENU_ITEM(gMenuBarItemWidget),
   570                                   gMenuPopupWidget);
   571         gtk_widget_realize(gMenuPopupWidget);
   572     }
   573     return MOZ_GTK_SUCCESS;
   574 }
   576 static gint
   577 ensure_menu_item_widget()
   578 {
   579     if (!gMenuItemWidget) {
   580         ensure_menu_popup_widget();
   581         gMenuItemWidget = gtk_menu_item_new_with_label("M");
   582         gtk_menu_shell_append(GTK_MENU_SHELL(gMenuPopupWidget),
   583                               gMenuItemWidget);
   584         gtk_widget_realize(gMenuItemWidget);
   585     }
   586     return MOZ_GTK_SUCCESS;
   587 }
   589 static gint
   590 ensure_image_menu_item_widget()
   591 {
   592     if (!gImageMenuItemWidget) {
   593         ensure_menu_popup_widget();
   594         gImageMenuItemWidget = gtk_image_menu_item_new();
   595         gtk_menu_shell_append(GTK_MENU_SHELL(gMenuPopupWidget),
   596                               gImageMenuItemWidget);
   597         gtk_widget_realize(gImageMenuItemWidget);
   598     }
   599     return MOZ_GTK_SUCCESS;
   600 }
   602 static gint
   603 ensure_menu_separator_widget()
   604 {
   605     if (!gMenuSeparatorWidget) {
   606         ensure_menu_popup_widget();
   607         gMenuSeparatorWidget = gtk_separator_menu_item_new();
   608         gtk_menu_shell_append(GTK_MENU_SHELL(gMenuPopupWidget),
   609                               gMenuSeparatorWidget);
   610         gtk_widget_realize(gMenuSeparatorWidget);
   611     }
   612     return MOZ_GTK_SUCCESS;
   613 }
   615 static gint
   616 ensure_check_menu_item_widget()
   617 {
   618     if (!gCheckMenuItemWidget) {
   619         ensure_menu_popup_widget();
   620         gCheckMenuItemWidget = gtk_check_menu_item_new_with_label("M");
   621         gtk_menu_shell_append(GTK_MENU_SHELL(gMenuPopupWidget),
   622                               gCheckMenuItemWidget);
   623         gtk_widget_realize(gCheckMenuItemWidget);
   624     }
   625     return MOZ_GTK_SUCCESS;
   626 }
   628 static gint
   629 ensure_tree_view_widget()
   630 {
   631     if (!gTreeViewWidget) {
   632         gTreeViewWidget = gtk_tree_view_new();
   633         setup_widget_prototype(gTreeViewWidget);
   634     }
   635     return MOZ_GTK_SUCCESS;
   636 }
   638 static gint
   639 ensure_tree_header_cell_widget()
   640 {
   641     if(!gTreeHeaderCellWidget) {
   642         /*
   643          * Some GTK engines paint the first and last cell
   644          * of a TreeView header with a highlight.
   645          * Since we do not know where our widget will be relative
   646          * to the other buttons in the TreeView header, we must
   647          * paint it as a button that is between two others,
   648          * thus ensuring it is neither the first or last button
   649          * in the header.
   650          * GTK doesn't give us a way to do this explicitly,
   651          * so we must paint with a button that is between two
   652          * others.
   653          */
   655         GtkTreeViewColumn* firstTreeViewColumn;
   656         GtkTreeViewColumn* lastTreeViewColumn;
   658         ensure_tree_view_widget();
   660         /* Create and append our three columns */
   661         firstTreeViewColumn = gtk_tree_view_column_new();
   662         gtk_tree_view_column_set_title(firstTreeViewColumn, "M");
   663         gtk_tree_view_append_column(GTK_TREE_VIEW(gTreeViewWidget), firstTreeViewColumn);
   665         gMiddleTreeViewColumn = gtk_tree_view_column_new();
   666         gtk_tree_view_column_set_title(gMiddleTreeViewColumn, "M");
   667         gtk_tree_view_append_column(GTK_TREE_VIEW(gTreeViewWidget),
   668                                     gMiddleTreeViewColumn);
   670         lastTreeViewColumn = gtk_tree_view_column_new();
   671         gtk_tree_view_column_set_title(lastTreeViewColumn, "M");
   672         gtk_tree_view_append_column(GTK_TREE_VIEW(gTreeViewWidget), lastTreeViewColumn);
   674         /* Use the middle column's header for our button */
   675         gTreeHeaderCellWidget = gtk_tree_view_column_get_button(gMiddleTreeViewColumn);
   676         /* TODO, but it can't be NULL */
   677         gTreeHeaderSortArrowWidget = gtk_button_new();
   678     }
   679     return MOZ_GTK_SUCCESS;
   680 }
   682 static gint
   683 ensure_expander_widget()
   684 {
   685     if (!gExpanderWidget) {
   686         gExpanderWidget = gtk_expander_new("M");
   687         setup_widget_prototype(gExpanderWidget);
   688     }
   689     return MOZ_GTK_SUCCESS;
   690 }
   692 static gint
   693 ensure_scrolled_window_widget()
   694 {
   695     if (!gScrolledWindowWidget) {
   696         gScrolledWindowWidget = gtk_scrolled_window_new(NULL, NULL);
   697         setup_widget_prototype(gScrolledWindowWidget);
   698     }
   699     return MOZ_GTK_SUCCESS;
   700 }
   702 gint
   703 moz_gtk_init()
   704 {
   705     GtkWidgetClass *entry_class;
   707     if (is_initialized)
   708         return MOZ_GTK_SUCCESS;
   710     is_initialized = TRUE;
   711     have_arrow_scaling = (gtk_major_version > 2 ||
   712                           (gtk_major_version == 2 && gtk_minor_version >= 12));
   714     /* Add style property to GtkEntry.
   715      * Adding the style property to the normal GtkEntry class means that it
   716      * will work without issues inside GtkComboBox and for Spinbuttons. */
   717     entry_class = g_type_class_ref(GTK_TYPE_ENTRY);
   719     return MOZ_GTK_SUCCESS;
   720 }
   722 gint
   723 moz_gtk_checkbox_get_metrics(gint* indicator_size, gint* indicator_spacing)
   724 {
   725     ensure_checkbox_widget();
   727     gtk_widget_style_get (gCheckboxWidget,
   728                           "indicator_size", indicator_size,
   729                           "indicator_spacing", indicator_spacing,
   730                           NULL);
   732     return MOZ_GTK_SUCCESS;
   733 }
   735 gint
   736 moz_gtk_radio_get_metrics(gint* indicator_size, gint* indicator_spacing)
   737 {
   738     ensure_radiobutton_widget();
   740     gtk_widget_style_get (gRadiobuttonWidget,
   741                           "indicator_size", indicator_size,
   742                           "indicator_spacing", indicator_spacing,
   743                           NULL);
   745     return MOZ_GTK_SUCCESS;
   746 }
   748 gint
   749 moz_gtk_widget_get_focus(GtkWidget* widget, gboolean* interior_focus,
   750                          gint* focus_width, gint* focus_pad) 
   751 {
   752     gtk_widget_style_get (widget,
   753                           "interior-focus", interior_focus,
   754                           "focus-line-width", focus_width,
   755                           "focus-padding", focus_pad,
   756                           NULL);
   758     return MOZ_GTK_SUCCESS;
   759 }
   761 gint
   762 moz_gtk_menuitem_get_horizontal_padding(gint* horizontal_padding)
   763 {
   764     ensure_menu_item_widget();
   766     gtk_widget_style_get (gMenuItemWidget,
   767                           "horizontal-padding", horizontal_padding,
   768                           NULL);
   770     return MOZ_GTK_SUCCESS;
   771 }
   773 gint
   774 moz_gtk_checkmenuitem_get_horizontal_padding(gint* horizontal_padding)
   775 {
   776     ensure_check_menu_item_widget();
   778     gtk_widget_style_get (gCheckMenuItemWidget,
   779                           "horizontal-padding", horizontal_padding,
   780                           NULL);
   782     return MOZ_GTK_SUCCESS;
   783 }
   785 gint
   786 moz_gtk_button_get_default_overflow(gint* border_top, gint* border_left,
   787                                     gint* border_bottom, gint* border_right)
   788 {
   789     GtkBorder* default_outside_border;
   791     ensure_button_widget();
   792     gtk_widget_style_get(gButtonWidget,
   793                          "default-outside-border", &default_outside_border,
   794                          NULL);
   796     if (default_outside_border) {
   797         *border_top = default_outside_border->top;
   798         *border_left = default_outside_border->left;
   799         *border_bottom = default_outside_border->bottom;
   800         *border_right = default_outside_border->right;
   801         gtk_border_free(default_outside_border);
   802     } else {
   803         *border_top = *border_left = *border_bottom = *border_right = 0;
   804     }
   805     return MOZ_GTK_SUCCESS;
   806 }
   808 static gint
   809 moz_gtk_button_get_default_border(gint* border_top, gint* border_left,
   810                                   gint* border_bottom, gint* border_right)
   811 {
   812     GtkBorder* default_border;
   814     ensure_button_widget();
   815     gtk_widget_style_get(gButtonWidget,
   816                          "default-border", &default_border,
   817                          NULL);
   819     if (default_border) {
   820         *border_top = default_border->top;
   821         *border_left = default_border->left;
   822         *border_bottom = default_border->bottom;
   823         *border_right = default_border->right;
   824         gtk_border_free(default_border);
   825     } else {
   826         /* see gtkbutton.c */
   827         *border_top = *border_left = *border_bottom = *border_right = 1;
   828     }
   829     return MOZ_GTK_SUCCESS;
   830 }
   832 gint
   833 moz_gtk_splitter_get_metrics(gint orientation, gint* size)
   834 {
   835     if (orientation == GTK_ORIENTATION_HORIZONTAL) {
   836         ensure_hpaned_widget();
   837         gtk_widget_style_get(gHPanedWidget, "handle_size", size, NULL);
   838     } else {
   839         ensure_vpaned_widget();
   840         gtk_widget_style_get(gVPanedWidget, "handle_size", size, NULL);
   841     }
   842     return MOZ_GTK_SUCCESS;
   843 }
   845 gint
   846 moz_gtk_button_get_inner_border(GtkWidget* widget, GtkBorder* inner_border)
   847 {
   848     static const GtkBorder default_inner_border = { 1, 1, 1, 1 };
   849     GtkBorder *tmp_border;
   851     gtk_widget_style_get (widget, "inner-border", &tmp_border, NULL);
   853     if (tmp_border) {
   854         *inner_border = *tmp_border;
   855         gtk_border_free(tmp_border);
   856     }
   857     else
   858         *inner_border = default_inner_border;
   860     return MOZ_GTK_SUCCESS;
   861 }
   863 static gint
   864 moz_gtk_button_paint(cairo_t *cr, GdkRectangle* rect,
   865                      GtkWidgetState* state,
   866                      GtkReliefStyle relief, GtkWidget* widget,
   867                      GtkTextDirection direction)
   868 {
   869     GtkStateFlags state_flags = GetStateFlagsFromGtkWidgetState(state);
   870     GtkStyleContext* style = gtk_widget_get_style_context(widget);    
   871     gint x = rect->x, y=rect->y, width=rect->width, height=rect->height;
   873     gboolean interior_focus;
   874     gint focus_width, focus_pad;
   876     moz_gtk_widget_get_focus(widget, &interior_focus, &focus_width, &focus_pad);
   877     gtk_widget_set_direction(widget, direction);
   879     if (!interior_focus && state->focused) {
   880         x += focus_width + focus_pad;
   881         y += focus_width + focus_pad;
   882         width -= 2 * (focus_width + focus_pad);
   883         height -= 2 * (focus_width + focus_pad);
   884     }
   886     gtk_style_context_save(style);
   887     gtk_style_context_set_state(style, state_flags);
   889     if (state->isDefault && relief == GTK_RELIEF_NORMAL) {
   890         /* handle default borders both outside and inside the button */
   891         gint default_top, default_left, default_bottom, default_right;
   892         moz_gtk_button_get_default_overflow(&default_top, &default_left,
   893                                             &default_bottom, &default_right);
   894         x -= default_left;
   895         y -= default_top;
   896         width += default_left + default_right;
   897         height += default_top + default_bottom;
   898         gtk_render_background(style, cr, x, y, width, height);
   899         gtk_render_frame(style, cr, x, y, width, height);
   900         moz_gtk_button_get_default_border(&default_top, &default_left,
   901                                           &default_bottom, &default_right);
   902         x += default_left;
   903         y += default_top;
   904         width -= (default_left + default_right);
   905         height -= (default_top + default_bottom);
   906     }
   908     if (relief != GTK_RELIEF_NONE || state->depressed ||
   909         (state_flags & GTK_STATE_FLAG_PRELIGHT)) {
   910         /* the following line can trigger an assertion (Crux theme)
   911            file ../../gdk/gdkwindow.c: line 1846 (gdk_window_clear_area):
   912            assertion `GDK_IS_WINDOW (window)' failed */
   913         gtk_render_background(style, cr, x, y, width, height);
   914         gtk_render_frame(style, cr, x, y, width, height);
   915     }
   917     if (state->focused) {
   918         if (interior_focus) {
   919             GtkBorder border;
   920             gtk_style_context_get_border(style, state_flags, &border);
   921             x += border.left + focus_pad;
   922             y += border.top + focus_pad;
   923             width -= 2 * (border.left + focus_pad);
   924             height -= 2 * (border.top + focus_pad);
   925         } else {
   926             x -= focus_width + focus_pad;
   927             y -= focus_width + focus_pad;
   928             width += 2 * (focus_width + focus_pad);
   929             height += 2 * (focus_width + focus_pad);
   930         }
   932         gtk_render_focus(style, cr, x, y, width, height);
   933     }
   934     gtk_style_context_restore(style);
   935     return MOZ_GTK_SUCCESS;
   936 }
   938 static gint
   939 moz_gtk_toggle_paint(cairo_t *cr, GdkRectangle* rect,
   940                      GtkWidgetState* state,
   941                      gboolean selected, gboolean inconsistent,
   942                      gboolean isradio, GtkTextDirection direction)
   943 {
   944     gint indicator_size, indicator_spacing;
   945     gint x, y, width, height;
   946     gint focus_x, focus_y, focus_width, focus_height;
   947     GtkWidget *w;
   948     GtkStyleContext *style;
   950     if (isradio) {
   951         moz_gtk_radio_get_metrics(&indicator_size, &indicator_spacing);
   952         w = gRadiobuttonWidget;
   953     } else {
   954         moz_gtk_checkbox_get_metrics(&indicator_size, &indicator_spacing);
   955         w = gCheckboxWidget;
   956     }
   958     // XXX we should assert rect->height >= indicator_size too
   959     // after bug 369581 is fixed.
   960     NS_ASSERTION(rect->width >= indicator_size,
   961                  "GetMinimumWidgetSize was ignored");
   963     // Paint it center aligned in the rect.
   964     x = rect->x + (rect->width - indicator_size) / 2;
   965     y = rect->y + (rect->height - indicator_size) / 2;
   966     width = indicator_size;
   967     height = indicator_size;
   969     focus_x = x - indicator_spacing;
   970     focus_y = y - indicator_spacing;
   971     focus_width = width + 2 * indicator_spacing;
   972     focus_height = height + 2 * indicator_spacing;
   974     style = gtk_widget_get_style_context(w);
   976     gtk_widget_set_sensitive(w, !state->disabled);
   977     gtk_widget_set_direction(w, direction);
   978     gtk_style_context_save(style);
   980     if (isradio) {
   981         gtk_style_context_add_class(style, GTK_STYLE_CLASS_RADIO);
   982         gtk_style_context_set_state(style, selected ? GTK_STATE_FLAG_ACTIVE :
   983                                                       GTK_STATE_FLAG_NORMAL);
   984         gtk_render_option(style, cr, x, y, width, height);
   985         if (state->focused) {
   986             gtk_render_focus(style, cr, focus_x, focus_y,
   987                             focus_width, focus_height);
   988         }
   989     }
   990     else {
   991        /*
   992         * 'indeterminate' type on checkboxes. In GTK, the shadow type
   993         * must also be changed for the state to be drawn.
   994         */        
   995         gtk_style_context_add_class(style, GTK_STYLE_CLASS_CHECK);
   996         if (inconsistent) {
   997             gtk_style_context_set_state(style, GTK_STATE_FLAG_INCONSISTENT);
   998             gtk_toggle_button_set_inconsistent(GTK_TOGGLE_BUTTON(gCheckboxWidget), TRUE);
   999         } else if (selected) {
  1000             gtk_style_context_set_state(style, GTK_STATE_FLAG_ACTIVE);
  1001         } else {
  1002             gtk_toggle_button_set_inconsistent(GTK_TOGGLE_BUTTON(gCheckboxWidget), FALSE);
  1004         gtk_render_check(style, cr, x, y, width, height);        
  1005         if (state->focused) {
  1006             gtk_render_focus(style, cr, 
  1007                              focus_x, focus_y, focus_width, focus_height);
  1010     gtk_style_context_restore(style);
  1012     return MOZ_GTK_SUCCESS;
  1015 static gint
  1016 calculate_button_inner_rect(GtkWidget* button, GdkRectangle* rect,
  1017                             GdkRectangle* inner_rect,
  1018                             GtkTextDirection direction,
  1019                             gboolean ignore_focus)
  1021     GtkBorder inner_border;
  1022     gboolean interior_focus;
  1023     gint focus_width, focus_pad;
  1024     GtkStyleContext* style;
  1025     GtkBorder border;
  1027     style = gtk_widget_get_style_context(button);
  1029     /* This mirrors gtkbutton's child positioning */
  1030     moz_gtk_button_get_inner_border(button, &inner_border);
  1031     moz_gtk_widget_get_focus(button, &interior_focus,
  1032                              &focus_width, &focus_pad);
  1034     if (ignore_focus)
  1035         focus_width = focus_pad = 0;
  1037     gtk_style_context_get_border(style, 0, &border);
  1039     inner_rect->x = rect->x + border.left + focus_width + focus_pad;
  1040     inner_rect->x += direction == GTK_TEXT_DIR_LTR ?
  1041                         inner_border.left : inner_border.right;
  1042     inner_rect->y = rect->y + inner_border.top + border.top +
  1043                     focus_width + focus_pad;
  1044     inner_rect->width = MAX(1, rect->width - inner_border.left -
  1045        inner_border.right - (border.left + focus_pad + focus_width) * 2);
  1046     inner_rect->height = MAX(1, rect->height - inner_border.top -
  1047        inner_border.bottom - (border.top + focus_pad + focus_width) * 2);
  1049     return MOZ_GTK_SUCCESS;
  1053 static gint
  1054 calculate_arrow_rect(GtkWidget* arrow, GdkRectangle* rect,
  1055                      GdkRectangle* arrow_rect, GtkTextDirection direction)
  1057     /* defined in gtkarrow.c */
  1058     gfloat arrow_scaling = 0.7;
  1059     gfloat xalign, xpad;
  1060     gint extent;
  1061     gint mxpad, mypad;
  1062     gfloat mxalign, myalign;
  1063     GtkMisc* misc = GTK_MISC(arrow);
  1065     if (have_arrow_scaling)
  1066         gtk_widget_style_get(arrow, "arrow_scaling", &arrow_scaling, NULL);
  1068     gtk_misc_get_padding(misc, &mxpad, &mypad); 
  1069     extent = MIN((rect->width - mxpad * 2),
  1070                  (rect->height - mypad * 2)) * arrow_scaling;
  1072     gtk_misc_get_alignment(misc, &mxalign, &myalign);
  1074     xalign = direction == GTK_TEXT_DIR_LTR ? mxalign : 1.0 - mxalign;
  1075     xpad = mxpad + (rect->width - extent) * xalign;
  1077     arrow_rect->x = direction == GTK_TEXT_DIR_LTR ?
  1078                         floor(rect->x + xpad) : ceil(rect->x + xpad);
  1079     arrow_rect->y = floor(rect->y + mypad +
  1080                           ((rect->height - extent) * myalign));
  1082     arrow_rect->width = arrow_rect->height = extent;
  1084     return MOZ_GTK_SUCCESS;
  1087 static gint
  1088 moz_gtk_scrollbar_button_paint(cairo_t *cr, GdkRectangle* rect,
  1089                                GtkWidgetState* state,
  1090                                GtkScrollbarButtonFlags flags,
  1091                                GtkTextDirection direction)
  1093     GtkStateFlags state_flags = GetStateFlagsFromGtkWidgetState(state);
  1094     GtkStateType saved_state;
  1095     GdkRectangle arrow_rect;
  1096     gdouble arrow_angle;
  1097     GtkStyleContext* style;
  1098     GtkWidget *scrollbar;
  1099     gint arrow_displacement_x, arrow_displacement_y;
  1100     const char* detail = (flags & MOZ_GTK_STEPPER_VERTICAL) ?
  1101                            "vscrollbar" : "hscrollbar";
  1103     ensure_scrollbar_widget();
  1105     if (flags & MOZ_GTK_STEPPER_VERTICAL)
  1106         scrollbar = gVertScrollbarWidget;
  1107     else
  1108         scrollbar = gHorizScrollbarWidget;
  1110     gtk_widget_set_direction(scrollbar, direction);
  1112     if (flags & MOZ_GTK_STEPPER_VERTICAL) {
  1113         arrow_angle = (flags & MOZ_GTK_STEPPER_DOWN) ? ARROW_DOWN : ARROW_UP;        
  1114     } else {
  1115         arrow_angle = (flags & MOZ_GTK_STEPPER_DOWN) ? ARROW_RIGHT : ARROW_LEFT;        
  1118     style = gtk_widget_get_style_context(scrollbar);
  1120     gtk_style_context_save(style);
  1121     gtk_style_context_add_class(style, GTK_STYLE_CLASS_SCROLLBAR);  
  1122     gtk_style_context_set_state(style, state_flags);
  1124     gtk_render_background(style, cr, rect->x, rect->y, rect->width, rect->height);
  1125     gtk_render_frame(style, cr, rect->x, rect->y, rect->width, rect->height);
  1127     arrow_rect.width = rect->width / 2;
  1128     arrow_rect.height = rect->height / 2;
  1129     arrow_rect.x = rect->x + (rect->width - arrow_rect.width) / 2;
  1130     arrow_rect.y = rect->y + (rect->height - arrow_rect.height) / 2;
  1132     if (state_flags & GTK_STATE_FLAG_ACTIVE) {
  1133         gtk_widget_style_get(scrollbar,
  1134                              "arrow-displacement-x", &arrow_displacement_x,
  1135                              "arrow-displacement-y", &arrow_displacement_y,
  1136                              NULL);
  1138         arrow_rect.x += arrow_displacement_x;
  1139         arrow_rect.y += arrow_displacement_y;
  1142     gtk_render_arrow(style, cr, arrow_angle,
  1143                      arrow_rect.x,
  1144                      arrow_rect.y, 
  1145                      arrow_rect.width);
  1147     gtk_style_context_restore(style);
  1149     return MOZ_GTK_SUCCESS;
  1152 static gint
  1153 moz_gtk_scrollbar_trough_paint(GtkThemeWidgetType widget,
  1154                                cairo_t *cr, GdkRectangle* rect,
  1155                                GtkWidgetState* state,
  1156                                GtkTextDirection direction)
  1158     GtkStyleContext* style;
  1159     GtkScrollbar *scrollbar;
  1161     ensure_scrollbar_widget();
  1163     if (widget ==  MOZ_GTK_SCROLLBAR_TRACK_HORIZONTAL)
  1164         scrollbar = GTK_SCROLLBAR(gHorizScrollbarWidget);
  1165     else
  1166         scrollbar = GTK_SCROLLBAR(gVertScrollbarWidget);
  1168     gtk_widget_set_direction(GTK_WIDGET(scrollbar), direction);
  1170     style = gtk_widget_get_style_context(GTK_WIDGET(scrollbar));
  1171     gtk_style_context_save(style);
  1172     gtk_style_context_add_class(style, GTK_STYLE_CLASS_TROUGH);
  1174     gtk_render_background(style, cr, rect->x, rect->y, rect->width, rect->height);
  1175     gtk_render_frame(style, cr, rect->x, rect->y, rect->width, rect->height);
  1177     if (state->focused) {
  1178         gtk_render_focus(style, cr,
  1179                          rect->x, rect->y, rect->width, rect->height);
  1181     gtk_style_context_restore(style);
  1182     return MOZ_GTK_SUCCESS;
  1185 static gint
  1186 moz_gtk_scrollbar_thumb_paint(GtkThemeWidgetType widget,
  1187                               cairo_t *cr, GdkRectangle* rect,
  1188                               GtkWidgetState* state,
  1189                               GtkTextDirection direction)
  1191     GtkStateFlags state_flags = GetStateFlagsFromGtkWidgetState(state);
  1192     GtkStyleContext* style;
  1193     GtkScrollbar *scrollbar;
  1194     GtkAdjustment *adj;
  1196     ensure_scrollbar_widget();
  1198     if (widget == MOZ_GTK_SCROLLBAR_THUMB_HORIZONTAL)
  1199         scrollbar = GTK_SCROLLBAR(gHorizScrollbarWidget);
  1200     else
  1201         scrollbar = GTK_SCROLLBAR(gVertScrollbarWidget);
  1203     gtk_widget_set_direction(GTK_WIDGET(scrollbar), direction);
  1205     style = gtk_widget_get_style_context(GTK_WIDGET(scrollbar));
  1206     gtk_style_context_save(style);
  1208     gtk_style_context_add_class(style, GTK_STYLE_CLASS_SLIDER);
  1209     gtk_style_context_set_state(style, state_flags);
  1211     gtk_render_slider(style, cr, rect->x, rect->y,
  1212                       rect->width,  rect->height,
  1213                      (widget == MOZ_GTK_SCROLLBAR_THUMB_HORIZONTAL) ?
  1214                      GTK_ORIENTATION_HORIZONTAL : GTK_ORIENTATION_VERTICAL);
  1216     gtk_style_context_restore(style);
  1218     return MOZ_GTK_SUCCESS;
  1221 static gint
  1222 moz_gtk_spin_paint(cairo_t *cr, GdkRectangle* rect,
  1223                    GtkTextDirection direction)
  1225     GtkStyleContext* style;
  1227     ensure_spin_widget();
  1228     gtk_widget_set_direction(gSpinWidget, direction);
  1229     style = gtk_widget_get_style_context(gSpinWidget);
  1230     gtk_style_context_save(style);
  1231     gtk_style_context_add_class(style, GTK_STYLE_CLASS_SPINBUTTON);
  1232     gtk_render_background(style, cr, rect->x, rect->y, rect->width, rect->height);
  1233     gtk_render_frame(style, cr, rect->x, rect->y, rect->width, rect->height);
  1234     gtk_style_context_restore(style);
  1236     return MOZ_GTK_SUCCESS;
  1239 static gint
  1240 moz_gtk_spin_updown_paint(cairo_t *cr, GdkRectangle* rect,
  1241                           gboolean isDown, GtkWidgetState* state,
  1242                           GtkTextDirection direction)
  1244     GdkRectangle arrow_rect;
  1245     GtkStyleContext* style;
  1247     ensure_spin_widget();
  1248     style = gtk_widget_get_style_context(gSpinWidget);
  1249     gtk_style_context_save(style);
  1250     gtk_style_context_add_class(style, GTK_STYLE_CLASS_SPINBUTTON);
  1251     gtk_style_context_set_state(style, GetStateFlagsFromGtkWidgetState(state));
  1252     gtk_widget_set_direction(gSpinWidget, direction);
  1254     gtk_render_background(style, cr, rect->x, rect->y, rect->width, rect->height);
  1255     gtk_render_frame(style, cr, rect->x, rect->y, rect->width, rect->height);
  1258     /* hard code these values */
  1259     arrow_rect.width = 6;
  1260     arrow_rect.height = 6;
  1261     arrow_rect.x = rect->x + (rect->width - arrow_rect.width) / 2;
  1262     arrow_rect.y = rect->y + (rect->height - arrow_rect.height) / 2;
  1263     arrow_rect.y += isDown ? -1 : 1;
  1265     gtk_render_arrow(style, cr, 
  1266                     isDown ? ARROW_DOWN : ARROW_UP,
  1267                     arrow_rect.x, arrow_rect.y,
  1268                     arrow_rect.width);
  1269     gtk_style_context_restore(style);
  1270     return MOZ_GTK_SUCCESS;
  1273 /* See gtk_range_draw() for reference.
  1274 */
  1275 static gint
  1276 moz_gtk_scale_paint(cairo_t *cr, GdkRectangle* rect,
  1277                     GtkWidgetState* state,
  1278                     GtkOrientation flags, GtkTextDirection direction)
  1280   GtkStateFlags state_flags = GetStateFlagsFromGtkWidgetState(state);
  1281   gint x = 0, y = 0;
  1282   GtkStyleContext* style;
  1283   GtkWidget* widget;
  1284   GtkBorder margin;
  1286   ensure_scale_widget();
  1287   widget = ((flags == GTK_ORIENTATION_HORIZONTAL) ? gHScaleWidget : gVScaleWidget);
  1288   gtk_widget_set_direction(widget, direction);
  1290   style = gtk_widget_get_style_context(widget);
  1291   gtk_style_context_save(style);
  1292   gtk_style_context_add_class(style, GTK_STYLE_CLASS_SCALE);
  1293   gtk_style_context_get_margin(style, state_flags, &margin); 
  1295   if (flags == GTK_ORIENTATION_HORIZONTAL) {
  1296     x = margin.left;
  1297     y++;
  1299   else {
  1300     x++;
  1301     y = margin.top;
  1304   gtk_render_frame(style, cr, rect->x + x, rect->y + y,
  1305                    rect->width - 2*x, rect->height - 2*y);
  1307   if (state->focused)
  1308     gtk_render_focus(style, cr, 
  1309                     rect->x, rect->y, rect->width, rect->height);
  1310   gtk_style_context_restore(style);
  1311   return MOZ_GTK_SUCCESS;
  1314 static gint
  1315 moz_gtk_scale_thumb_paint(cairo_t *cr, GdkRectangle* rect,
  1316                           GtkWidgetState* state,
  1317                           GtkOrientation flags, GtkTextDirection direction)
  1319   GtkStateFlags state_flags = GetStateFlagsFromGtkWidgetState(state);
  1320   GtkStyleContext* style;
  1321   GtkWidget* widget;
  1322   gint thumb_width, thumb_height, x, y;
  1324   ensure_scale_widget();
  1325   widget = ((flags == GTK_ORIENTATION_HORIZONTAL) ? gHScaleWidget : gVScaleWidget);
  1326   gtk_widget_set_direction(widget, direction);
  1328   style = gtk_widget_get_style_context(widget);
  1329   gtk_style_context_add_class(style, GTK_STYLE_CLASS_SLIDER);
  1330   gtk_style_context_save(style);
  1331   gtk_style_context_set_state(style, state_flags);
  1332   /* determine the thumb size, and position the thumb in the center in the opposite axis 
  1333   */
  1334   if (flags == GTK_ORIENTATION_HORIZONTAL) {
  1335     moz_gtk_get_scalethumb_metrics(GTK_ORIENTATION_HORIZONTAL, &thumb_width, &thumb_height);
  1336     x = rect->x;
  1337     y = rect->y + (rect->height - thumb_height) / 2;
  1339   else {
  1340     moz_gtk_get_scalethumb_metrics(GTK_ORIENTATION_VERTICAL, &thumb_height, &thumb_width);
  1341     x = rect->x + (rect->width - thumb_width) / 2;
  1342     y = rect->y;
  1345   gtk_render_slider(style, cr, x, y, thumb_width, thumb_height, flags);
  1346   gtk_style_context_restore(style);
  1347   return MOZ_GTK_SUCCESS;
  1350 static gint
  1351 moz_gtk_gripper_paint(cairo_t *cr, GdkRectangle* rect,
  1352                       GtkWidgetState* state,
  1353                       GtkTextDirection direction)
  1355     GtkStyleContext* style;
  1357     ensure_handlebox_widget();
  1358     gtk_widget_set_direction(gHandleBoxWidget, direction);
  1360     style = gtk_widget_get_style_context(gHandleBoxWidget);
  1361     gtk_style_context_save(style);
  1362     gtk_style_context_add_class(style, GTK_STYLE_CLASS_GRIP);
  1363     gtk_style_context_set_state(style, GetStateFlagsFromGtkWidgetState(state));
  1365     gtk_render_background(style, cr, rect->x, rect->y, rect->width, rect->height);
  1366     gtk_render_frame(style, cr, rect->x, rect->y, rect->width, rect->height);
  1367     gtk_style_context_restore(style);
  1369     return MOZ_GTK_SUCCESS;
  1372 static gint
  1373 moz_gtk_hpaned_paint(cairo_t *cr, GdkRectangle* rect,
  1374                      GtkWidgetState* state)
  1376     GtkStyleContext* style;
  1378     ensure_hpaned_widget();
  1379     style = gtk_widget_get_style_context(gHPanedWidget);
  1380     gtk_style_context_save(style);
  1381     gtk_style_context_add_class(style, GTK_STYLE_CLASS_PANE_SEPARATOR);
  1382     gtk_style_context_set_state(style, GetStateFlagsFromGtkWidgetState(state));
  1383     gtk_render_handle(style, cr,
  1384                       rect->x, rect->y, rect->width, rect->height);
  1385     gtk_style_context_restore(style);
  1387     return MOZ_GTK_SUCCESS;
  1390 static gint
  1391 moz_gtk_vpaned_paint(cairo_t *cr, GdkRectangle* rect,
  1392                      GtkWidgetState* state)
  1394     GtkStyleContext* style;
  1396     ensure_vpaned_widget();
  1397     style = gtk_widget_get_style_context(gVPanedWidget);
  1398     gtk_style_context_save(style);
  1399     gtk_style_context_add_class(style, GTK_STYLE_CLASS_PANE_SEPARATOR);
  1400     gtk_style_context_set_state(style, GetStateFlagsFromGtkWidgetState(state));
  1401     gtk_render_handle(style, cr,
  1402                       rect->x, rect->y, rect->width, rect->height);                     
  1403     gtk_style_context_restore(style);
  1405     return MOZ_GTK_SUCCESS;
  1408 // See gtk_entry_draw() for reference.
  1409 static gint
  1410 moz_gtk_entry_paint(cairo_t *cr, GdkRectangle* rect,
  1411                     GtkWidgetState* state,
  1412                     GtkWidget* widget, GtkTextDirection direction)
  1414     gint x = rect->x, y = rect->y, width = rect->width, height = rect->height;
  1415     GtkStyleContext* style;
  1416     gboolean interior_focus;
  1417     gint focus_width;
  1419     gtk_widget_set_direction(widget, direction);
  1421     style = gtk_widget_get_style_context(widget);
  1423     gtk_widget_style_get(widget,
  1424                          "interior-focus", &interior_focus,
  1425                          "focus-line-width", &focus_width,
  1426                          NULL);
  1428     /* gtkentry.c uses two windows, one for the entire widget and one for the
  1429      * text area inside it. The background of both windows is set to the "base"
  1430      * color of the new state in gtk_entry_state_changed, but only the inner
  1431      * textarea window uses gtk_paint_flat_box when exposed */
  1433     /* This gets us a lovely greyish disabledish look */
  1434     gtk_widget_set_sensitive(widget, !state->disabled);
  1436     gtk_style_context_save(style);
  1437     gtk_style_context_add_class(style, GTK_STYLE_CLASS_ENTRY);
  1439     /* Now paint the shadow and focus border.
  1440      * We do like in gtk_entry_draw_frame, we first draw the shadow, a tad
  1441      * smaller when focused if the focus is not interior, then the focus. */
  1443     if (state->focused && !state->disabled) {
  1444         /* This will get us the lit borders that focused textboxes enjoy on
  1445          * some themes. */
  1446         gtk_style_context_set_state(style, GTK_STATE_FLAG_FOCUSED);
  1447         if (!interior_focus) {
  1448             /* Indent the border a little bit if we have exterior focus 
  1449                (this is what GTK does to draw native entries) */
  1450             x += focus_width;
  1451             y += focus_width;
  1452             width -= 2 * focus_width;
  1453             height -= 2 * focus_width;
  1457     if (state->disabled) {
  1458         gtk_style_context_set_state(style, GTK_STATE_FLAG_INSENSITIVE);
  1461     gtk_render_background(style, cr, x, y, width, height);
  1462     gtk_render_frame(style, cr, x, y, width, height);
  1464     if (state->focused && !state->disabled) {
  1465         if (!interior_focus) {
  1466             gtk_render_focus(style, cr, rect->x, rect->y, rect->width, rect->height);
  1469     gtk_style_context_restore(style);
  1471     return MOZ_GTK_SUCCESS;
  1474 static gint 
  1475 moz_gtk_treeview_paint(cairo_t *cr, GdkRectangle* rect,
  1476                        GtkWidgetState* state,
  1477                        GtkTextDirection direction)
  1479     gint xthickness, ythickness;
  1480     GtkStyleContext *style;
  1481     GtkStyleContext *style_tree;
  1482     GtkStateFlags state_flags;
  1483     GtkBorder border;
  1485     ensure_tree_view_widget();
  1486     ensure_scrolled_window_widget();
  1488     gtk_widget_set_direction(gTreeViewWidget, direction);
  1489     gtk_widget_set_direction(gScrolledWindowWidget, direction);
  1491     /* only handle disabled and normal states, otherwise the whole background
  1492      * area will be painted differently with other states */
  1493     state_flags = state->disabled ? GTK_STATE_FLAG_INSENSITIVE : GTK_STATE_FLAG_NORMAL;
  1495     style = gtk_widget_get_style_context(gScrolledWindowWidget);
  1496     gtk_style_context_save(style);
  1497     gtk_style_context_add_class(style, GTK_STYLE_CLASS_FRAME);    
  1498     gtk_style_context_get_border(style, state_flags, &border);
  1499     xthickness = border.left;
  1500     ythickness = border.top;    
  1502     style_tree = gtk_widget_get_style_context(gTreeViewWidget);
  1503     gtk_style_context_save(style_tree);
  1504     gtk_style_context_add_class(style_tree, GTK_STYLE_CLASS_VIEW);
  1506     gtk_render_background(style_tree, cr,
  1507                           rect->x + xthickness, rect->y + ythickness,
  1508                           rect->width - 2 * xthickness,
  1509                           rect->height - 2 * ythickness);
  1510     gtk_render_frame(style, cr, 
  1511                      rect->x, rect->y, rect->width, rect->height); 
  1512     gtk_style_context_restore(style);
  1513     gtk_style_context_restore(style_tree);
  1514     return MOZ_GTK_SUCCESS;
  1517 static gint
  1518 moz_gtk_tree_header_cell_paint(cairo_t *cr, GdkRectangle* rect,
  1519                                GtkWidgetState* state,
  1520                                gboolean isSorted, GtkTextDirection direction)
  1522     moz_gtk_button_paint(cr, rect, state, GTK_RELIEF_NORMAL,
  1523                          gTreeHeaderCellWidget, direction);
  1524     return MOZ_GTK_SUCCESS;
  1527 static gint
  1528 moz_gtk_tree_header_sort_arrow_paint(cairo_t *cr, GdkRectangle* rect,
  1529                                      GtkWidgetState* state, GtkArrowType arrow_type,
  1530                                      GtkTextDirection direction)
  1532     GdkRectangle arrow_rect;
  1533     gdouble arrow_angle;
  1534     GtkStyleContext* style;
  1536     ensure_tree_header_cell_widget();
  1537     gtk_widget_set_direction(gTreeHeaderSortArrowWidget, direction);
  1539     /* hard code these values */
  1540     arrow_rect.width = 11;
  1541     arrow_rect.height = 11;
  1542     arrow_rect.x = rect->x + (rect->width - arrow_rect.width) / 2;
  1543     arrow_rect.y = rect->y + (rect->height - arrow_rect.height) / 2;
  1544     style = gtk_widget_get_style_context(gTreeHeaderSortArrowWidget);
  1545     gtk_style_context_save(style);
  1546     gtk_style_context_set_state(style, GetStateFlagsFromGtkWidgetState(state));
  1548     switch (arrow_type) {
  1549     case GTK_ARROW_LEFT:
  1550         arrow_angle = ARROW_LEFT;
  1551         break;
  1552     case GTK_ARROW_RIGHT:
  1553         arrow_angle = ARROW_RIGHT;
  1554         break;
  1555     case GTK_ARROW_DOWN:
  1556         arrow_angle = ARROW_DOWN;
  1557         break;
  1558     default:
  1559         arrow_angle = ARROW_UP;
  1560         break;
  1562     if (arrow_type != GTK_ARROW_NONE)
  1563         gtk_render_arrow(style, cr, arrow_angle,
  1564                          arrow_rect.x, arrow_rect.y,
  1565                          arrow_rect.width);
  1566     gtk_style_context_restore(style);
  1567     return MOZ_GTK_SUCCESS;
  1570 /* See gtk_expander_paint() for reference. 
  1571  */
  1572 static gint
  1573 moz_gtk_treeview_expander_paint(cairo_t *cr, GdkRectangle* rect,
  1574                                 GtkWidgetState* state,
  1575                                 GtkExpanderStyle expander_state,
  1576                                 GtkTextDirection direction)
  1578     GtkStyleContext *style;
  1579     GtkStateFlags    state_flags;
  1581     ensure_tree_view_widget();
  1582     gtk_widget_set_direction(gTreeViewWidget, direction);
  1584     style = gtk_widget_get_style_context(gTreeViewWidget);
  1585     gtk_style_context_save(style);
  1586     gtk_style_context_add_class(style, GTK_STYLE_CLASS_EXPANDER);
  1588     /* Because the frame we get is of the entire treeview, we can't get the precise
  1589      * event state of one expander, thus rendering hover and active feedback useless. */
  1590     state_flags = state->disabled ? GTK_STATE_INSENSITIVE : GTK_STATE_NORMAL;
  1592     /* GTK_STATE_FLAG_ACTIVE controls expanded/colapsed state rendering
  1593      * in gtk_render_expander()
  1594      */
  1595     if (expander_state == GTK_EXPANDER_EXPANDED)
  1596         state_flags |= GTK_STATE_FLAG_ACTIVE;
  1597     else
  1598         state_flags &= ~(GTK_STATE_FLAG_ACTIVE);
  1600     gtk_style_context_set_state(style, state_flags);
  1602     gtk_render_expander(style, cr,
  1603                         rect->x,
  1604                         rect->y,
  1605                         rect->width,
  1606                         rect->height);
  1608     gtk_style_context_restore(style);
  1609     return MOZ_GTK_SUCCESS;
  1612 /* See gtk_separator_draw() for reference.
  1613 */
  1614 static gint
  1615 moz_gtk_combo_box_paint(cairo_t *cr, GdkRectangle* rect,
  1616                         GtkWidgetState* state,
  1617                         gboolean ishtml, GtkTextDirection direction)
  1619     GdkRectangle arrow_rect, real_arrow_rect;
  1620     gint arrow_size, separator_width;
  1621     gboolean wide_separators;
  1622     GtkStyleContext* style;
  1623     GtkRequisition arrow_req;
  1625     ensure_combo_box_widgets();
  1627     /* Also sets the direction on gComboBoxButtonWidget, which is then
  1628      * inherited by the separator and arrow */
  1629     moz_gtk_button_paint(cr, rect, state, GTK_RELIEF_NORMAL,
  1630                          gComboBoxButtonWidget, direction);
  1632     calculate_button_inner_rect(gComboBoxButtonWidget,
  1633                                 rect, &arrow_rect, direction, ishtml);
  1634     /* Now arrow_rect contains the inner rect ; we want to correct the width
  1635      * to what the arrow needs (see gtk_combo_box_size_allocate) */
  1636     gtk_widget_size_request(gComboBoxArrowWidget, &arrow_req);
  1637     if (direction == GTK_TEXT_DIR_LTR)
  1638         arrow_rect.x += arrow_rect.width - arrow_req.width;
  1639     arrow_rect.width = arrow_req.width;
  1641     calculate_arrow_rect(gComboBoxArrowWidget,
  1642                          &arrow_rect, &real_arrow_rect, direction);
  1644     style = gtk_widget_get_style_context(gComboBoxArrowWidget);
  1645     gtk_render_arrow(style, cr, ARROW_DOWN,
  1646                      real_arrow_rect.x, real_arrow_rect.y,
  1647                      real_arrow_rect.width);
  1649     /* If there is no separator in the theme, there's nothing left to do. */
  1650     if (!gComboBoxSeparatorWidget)
  1651         return MOZ_GTK_SUCCESS;
  1652     style = gtk_widget_get_style_context(gComboBoxSeparatorWidget);
  1653     gtk_widget_style_get(gComboBoxSeparatorWidget,
  1654                          "wide-separators", &wide_separators,
  1655                          "separator-width", &separator_width,
  1656                          NULL);
  1658     if (wide_separators) {
  1659         if (direction == GTK_TEXT_DIR_LTR)
  1660             arrow_rect.x -= separator_width;
  1661         else
  1662             arrow_rect.x += arrow_rect.width;
  1664         gtk_render_frame(style, cr, arrow_rect.x, arrow_rect.y, separator_width, arrow_rect.height);
  1665     } else {
  1666         if (direction == GTK_TEXT_DIR_LTR) {
  1667             GtkBorder padding;
  1668             GtkStateFlags state_flags = GetStateFlagsFromGtkWidgetState(state);
  1669             gtk_style_context_get_padding(style, state_flags, &padding);
  1670             arrow_rect.x -= padding.left;
  1672         else
  1673             arrow_rect.x += arrow_rect.width;
  1675         gtk_render_line(style, cr, 
  1676                         arrow_rect.x, arrow_rect.y, 
  1677                         arrow_rect.x, arrow_rect.y + arrow_rect.height);
  1679     return MOZ_GTK_SUCCESS;
  1682 static gint
  1683 moz_gtk_arrow_paint(cairo_t *cr, GdkRectangle* rect,
  1684                     GtkWidgetState* state,
  1685                     GtkArrowType arrow_type, GtkTextDirection direction)
  1687     GtkStyleContext* style;
  1688     GtkStateFlags state_flags = GetStateFlagsFromGtkWidgetState(state);
  1689     GdkRectangle arrow_rect;
  1690     gdouble arrow_angle = ARROW_UP;
  1692     ensure_button_arrow_widget();
  1693     style = gtk_widget_get_style_context(gButtonArrowWidget);
  1694     gtk_style_context_save(style);
  1695     gtk_style_context_set_state(style, state_flags);
  1696     gtk_widget_set_direction(gButtonArrowWidget, direction);
  1698     calculate_arrow_rect(gButtonArrowWidget, rect, &arrow_rect,
  1699                          direction);
  1701     if (direction == GTK_TEXT_DIR_RTL) {
  1702         if (arrow_type == GTK_ARROW_LEFT)
  1703             arrow_angle = ARROW_RIGHT;
  1704         else if (arrow_type == GTK_ARROW_RIGHT)
  1705             arrow_angle = ARROW_LEFT;
  1706     } else if (arrow_type == GTK_ARROW_DOWN) {
  1707         arrow_angle = ARROW_DOWN;
  1709     if (arrow_type != GTK_ARROW_NONE)
  1710         gtk_render_arrow(style, cr, arrow_angle,
  1711                          arrow_rect.x, arrow_rect.y, arrow_rect.width);                    
  1712     gtk_style_context_restore(style);
  1713     return MOZ_GTK_SUCCESS;
  1716 static gint
  1717 moz_gtk_combo_box_entry_button_paint(cairo_t *cr, GdkRectangle* rect,
  1718                                      GtkWidgetState* state,
  1719                                      gboolean input_focus,
  1720                                      GtkTextDirection direction)
  1722     gint x_displacement, y_displacement;
  1723     GdkRectangle arrow_rect, real_arrow_rect;
  1724     GtkStateFlags state_flags = GetStateFlagsFromGtkWidgetState(state);
  1725     GtkStyleContext* style;
  1727     ensure_combo_box_entry_widgets();
  1729     moz_gtk_button_paint(cr, rect, state, GTK_RELIEF_NORMAL,
  1730                          gComboBoxEntryButtonWidget, direction);
  1732     calculate_button_inner_rect(gComboBoxEntryButtonWidget,
  1733                                 rect, &arrow_rect, direction, FALSE);
  1734     if (state_flags & GTK_STATE_FLAG_ACTIVE) {
  1735         gtk_widget_style_get(gComboBoxEntryButtonWidget,
  1736                              "child-displacement-x", &x_displacement,
  1737                              "child-displacement-y", &y_displacement,
  1738                              NULL);
  1739         arrow_rect.x += x_displacement;
  1740         arrow_rect.y += y_displacement;
  1743     calculate_arrow_rect(gComboBoxEntryArrowWidget,
  1744                          &arrow_rect, &real_arrow_rect, direction);
  1746     style = gtk_widget_get_style_context(gComboBoxEntryArrowWidget);
  1748     gtk_render_arrow(style, cr, ARROW_DOWN,
  1749                     real_arrow_rect.x, real_arrow_rect.y,
  1750                     real_arrow_rect.width);
  1752     return MOZ_GTK_SUCCESS;
  1755 static gint
  1756 moz_gtk_container_paint(cairo_t *cr, GdkRectangle* rect,
  1757                         GtkWidgetState* state, 
  1758                         gboolean isradio, GtkTextDirection direction)
  1760     GtkStateFlags state_flags = GetStateFlagsFromGtkWidgetState(state);
  1761     GtkStyleContext* style;
  1762     GtkWidget *widget;
  1763     gboolean interior_focus;
  1764     gint focus_width, focus_pad;
  1766     if (isradio) {
  1767         ensure_radiobutton_widget();
  1768         widget = gRadiobuttonWidget;
  1769     } else {
  1770         ensure_checkbox_widget();
  1771         widget = gCheckboxWidget;
  1773     gtk_widget_set_direction(widget, direction);
  1775     style = gtk_widget_get_style_context(widget);
  1776     gtk_style_context_save(style);
  1777     moz_gtk_widget_get_focus(widget, &interior_focus, &focus_width, &focus_pad);
  1778     gtk_style_context_set_state(style, state_flags);
  1780     /* this is for drawing a prelight box */
  1781     if (state_flags & GTK_STATE_FLAG_PRELIGHT) {
  1782         gtk_render_background(style, cr,
  1783                               rect->x, rect->y, rect->width, rect->height);
  1786     if (state->focused && !interior_focus) {
  1787         gtk_render_focus(style, cr,
  1788                         rect->x, rect->y, rect->width, rect->height);
  1790     gtk_style_context_restore(style);
  1792     return MOZ_GTK_SUCCESS;
  1795 static gint
  1796 moz_gtk_toggle_label_paint(cairo_t *cr, GdkRectangle* rect,
  1797                            GtkWidgetState* state, 
  1798                            gboolean isradio, GtkTextDirection direction)
  1800     GtkStyleContext *style;
  1801     GtkWidget *widget;
  1802     gboolean interior_focus;
  1804     if (!state->focused)
  1805         return MOZ_GTK_SUCCESS;
  1807     if (isradio) {
  1808         ensure_radiobutton_widget();
  1809         widget = gRadiobuttonWidget;
  1810     } else {
  1811         ensure_checkbox_widget();
  1812         widget = gCheckboxWidget;
  1814     style = gtk_widget_get_style_context(widget);
  1815     gtk_style_context_save(style);
  1816     if (isradio) {
  1817       gtk_style_context_add_class(style, GTK_STYLE_CLASS_RADIO);
  1818     } else {
  1819       gtk_style_context_add_class(style, GTK_STYLE_CLASS_CHECK);
  1821     gtk_widget_set_direction(widget, direction);
  1823     gtk_widget_style_get(widget, "interior-focus", &interior_focus, NULL);
  1824     if (!interior_focus)
  1825         return MOZ_GTK_SUCCESS;
  1827     gtk_style_context_set_state(style, GetStateFlagsFromGtkWidgetState(state));
  1828     gtk_render_focus(style, cr,
  1829                     rect->x, rect->y, rect->width, rect->height);
  1830     gtk_style_context_restore(style);
  1832     return MOZ_GTK_SUCCESS;
  1835 static gint
  1836 moz_gtk_toolbar_paint(cairo_t *cr, GdkRectangle* rect,
  1837                       GtkTextDirection direction)
  1839     GtkStyleContext* style;
  1841     ensure_toolbar_widget();
  1842     gtk_widget_set_direction(gToolbarWidget, direction);
  1844     style = gtk_widget_get_style_context(gToolbarWidget);
  1845     gtk_style_context_save(style);
  1846     gtk_style_context_add_class(style, GTK_STYLE_CLASS_TOOLBAR);
  1848     gtk_render_background(style, cr, rect->x, rect->y, rect->width, rect->height);
  1849     gtk_render_frame(style, cr, rect->x, rect->y, rect->width, rect->height);
  1850     gtk_style_context_restore(style);
  1852     return MOZ_GTK_SUCCESS;
  1855 /* See _gtk_toolbar_paint_space_line() for reference.
  1856 */
  1857 static gint
  1858 moz_gtk_toolbar_separator_paint(cairo_t *cr, GdkRectangle* rect,
  1859                                 GtkTextDirection direction)
  1861     GtkStyleContext* style;
  1862     gint     separator_width;
  1863     gint     paint_width;
  1864     gboolean wide_separators;
  1866     /* Defined as constants in GTK+ 2.10.14 */
  1867     const double start_fraction = 0.2;
  1868     const double end_fraction = 0.8;
  1870     ensure_toolbar_separator_widget();
  1871     gtk_widget_set_direction(gToolbarSeparatorWidget, direction);
  1873     style = gtk_widget_get_style_context(gToolbarSeparatorWidget);
  1875     gtk_widget_style_get(gToolbarWidget,
  1876                          "wide-separators", &wide_separators,
  1877                          "separator-width", &separator_width,
  1878                          NULL);
  1880     if (wide_separators) {
  1881         if (separator_width > rect->width)
  1882             separator_width = rect->width;
  1884         gtk_render_frame(style, cr,
  1885                           rect->x + (rect->width - separator_width) / 2,
  1886                           rect->y + rect->height * start_fraction,
  1887                           separator_width,
  1888                           rect->height * (end_fraction - start_fraction));
  1889     } else {
  1890         GtkBorder padding;
  1891         gtk_style_context_get_padding(style, 0, &padding);
  1893         paint_width = padding.left;
  1894         if (paint_width > rect->width)
  1895             paint_width = rect->width;
  1897         gtk_render_line(style, cr, 
  1898                         rect->x + (rect->width - paint_width) / 2,
  1899                         rect->y + rect->height * start_fraction,
  1900                         rect->x + (rect->width - paint_width) / 2,
  1901                         rect->y + rect->height * end_fraction);
  1904     return MOZ_GTK_SUCCESS;
  1907 static gint
  1908 moz_gtk_tooltip_paint(cairo_t *cr, GdkRectangle* rect,
  1909                       GtkTextDirection direction)
  1911     GtkStyleContext* style;
  1913     ensure_tooltip_widget();
  1914     gtk_widget_set_direction(gTooltipWidget, direction);
  1916     style = gtk_widget_get_style_context(gTooltipWidget);
  1917     gtk_style_context_save(style);
  1918     gtk_style_context_add_class(style, GTK_STYLE_CLASS_TOOLTIP);
  1919     gtk_render_background(style, cr, rect->x, rect->y, rect->width, rect->height);
  1920     gtk_render_frame(style, cr, rect->x, rect->y, rect->width, rect->height);
  1921     gtk_style_context_restore(style);
  1922     return MOZ_GTK_SUCCESS;
  1925 static gint
  1926 moz_gtk_resizer_paint(cairo_t *cr, GdkRectangle* rect,
  1927                       GtkWidgetState* state,
  1928                       GtkTextDirection direction)
  1930     GtkStyleContext* style;
  1932     ensure_frame_widget();
  1933     gtk_widget_set_direction(gStatusbarWidget, direction);
  1935     style = gtk_widget_get_style_context(gStatusbarWidget);
  1936     gtk_style_context_save(style);
  1937     gtk_style_context_add_class(style, GTK_STYLE_CLASS_GRIP);
  1938     gtk_style_context_set_state(style, GetStateFlagsFromGtkWidgetState(state));
  1940     gtk_render_handle(style, cr, rect->x, rect->y, rect->width, rect->height);
  1941     gtk_style_context_restore(style);
  1943     return MOZ_GTK_SUCCESS;
  1946 static gint
  1947 moz_gtk_frame_paint(cairo_t *cr, GdkRectangle* rect,
  1948                     GtkTextDirection direction)
  1950     GtkStyleContext* style;
  1952     ensure_frame_widget();
  1953     gtk_widget_set_direction(gFrameWidget, direction);
  1954     style = gtk_widget_get_style_context(gFrameWidget);
  1955     gtk_style_context_save(style);
  1956     gtk_style_context_add_class(style, GTK_STYLE_CLASS_FRAME);
  1958     gtk_render_frame(style, cr, rect->x, rect->y, rect->width, rect->height);
  1959     gtk_style_context_restore(style);
  1960     return MOZ_GTK_SUCCESS;
  1963 static gint
  1964 moz_gtk_progressbar_paint(cairo_t *cr, GdkRectangle* rect,
  1965                           GtkTextDirection direction)
  1967     GtkStyleContext* style;
  1969     ensure_progress_widget();
  1970     gtk_widget_set_direction(gProgressWidget, direction);
  1972     style = gtk_widget_get_style_context(gProgressWidget);
  1973     gtk_style_context_save(style);
  1974     gtk_style_context_add_class(style, GTK_STYLE_CLASS_TROUGH);
  1976     gtk_render_background(style, cr, rect->x, rect->y, rect->width, rect->height);
  1977     gtk_render_frame(style, cr, rect->x, rect->y, rect->width, rect->height);
  1978     gtk_style_context_restore(style);
  1980     return MOZ_GTK_SUCCESS;
  1983 static gint
  1984 moz_gtk_progress_chunk_paint(cairo_t *cr, GdkRectangle* rect,
  1985                              GtkTextDirection direction,
  1986                              GtkThemeWidgetType widget)
  1988     GtkStyleContext* style;
  1990     ensure_progress_widget();
  1991     gtk_widget_set_direction(gProgressWidget, direction);
  1993     style = gtk_widget_get_style_context(gProgressWidget);
  1994     gtk_style_context_save(style);
  1995     gtk_style_context_add_class(style, GTK_STYLE_CLASS_PROGRESSBAR);
  1997     if (widget == MOZ_GTK_PROGRESS_CHUNK_INDETERMINATE ||
  1998         widget == MOZ_GTK_PROGRESS_CHUNK_VERTICAL_INDETERMINATE) {
  1999       /**
  2000        * The bar's size and the bar speed are set depending of the progress'
  2001        * size. These could also be constant for all progress bars easily.
  2002        */
  2003       gboolean vertical = (widget == MOZ_GTK_PROGRESS_CHUNK_VERTICAL_INDETERMINATE);
  2005       /* The size of the dimension we are going to use for the animation. */
  2006       const gint progressSize = vertical ? rect->height : rect->width;
  2008       /* The bar is using a fifth of the element size, based on GtkProgressBar
  2009        * activity-blocks property. */
  2010       const gint barSize = MAX(1, progressSize / 5);
  2012       /* Represents the travel that has to be done for a complete cycle. */
  2013       const gint travel = 2 * (progressSize - barSize);
  2015       /* period equals to travel / pixelsPerMillisecond
  2016        * where pixelsPerMillisecond equals progressSize / 1000.0.
  2017        * This is equivalent to 1600. */
  2018       static const guint period = 1600;
  2019       const gint t = PR_IntervalToMilliseconds(PR_IntervalNow()) % period;
  2020       const gint dx = travel * t / period;
  2022       if (vertical) {
  2023         rect->y += (dx < travel / 2) ? dx : travel - dx;
  2024         rect->height = barSize;
  2025       } else {
  2026         rect->x += (dx < travel / 2) ? dx : travel - dx;
  2027         rect->width = barSize;
  2031     gtk_render_background(style, cr, rect->x, rect->y, rect->width, rect->height);
  2032     gtk_render_activity(style, cr, rect->x, rect->y, rect->width, rect->height);
  2033     gtk_style_context_restore(style);
  2035     return MOZ_GTK_SUCCESS;
  2038 gint
  2039 moz_gtk_get_tab_thickness(void)
  2041     GtkBorder border;
  2043     ensure_tab_widget();
  2044     GtkStyleContext * style = gtk_widget_get_style_context(gTabWidget);
  2045     gtk_style_context_add_class(style, GTK_STYLE_CLASS_NOTEBOOK);
  2046     gtk_style_context_get_border(style, 0, &border);
  2048     if (border.top < 2)
  2049         return 2; /* some themes don't set ythickness correctly */
  2051     return border.top;
  2054 /* actual small tabs */
  2055 static gint
  2056 moz_gtk_tab_paint(cairo_t *cr, GdkRectangle* rect,
  2057                   GtkWidgetState* state,
  2058                   GtkTabFlags flags, GtkTextDirection direction)
  2060     /* When the tab isn't selected, we just draw a notebook extension.
  2061      * When it is selected, we overwrite the adjacent border of the tabpanel
  2062      * touching the tab with a pierced border (called "the gap") to make the
  2063      * tab appear physically attached to the tabpanel; see details below. */
  2065     GtkStyleContext* style;
  2066     GdkRectangle focusRect;
  2067     GdkRectangle backRect;
  2069     ensure_tab_widget();
  2070     gtk_widget_set_direction(gTabWidget, direction);
  2072     style = gtk_widget_get_style_context(gTabWidget);    
  2073     backRect = focusRect = *rect;
  2075     gtk_style_context_save(style);
  2077     if ((flags & MOZ_GTK_TAB_SELECTED) == 0) {
  2078         /* Only draw the tab */
  2079         gtk_style_context_set_state(style, GTK_STATE_FLAG_NORMAL);
  2080         gtk_render_extension(style, cr,
  2081                              rect->x, rect->y, rect->width, rect->height,
  2082                             (flags & MOZ_GTK_TAB_BOTTOM) ?
  2083                                 GTK_POS_TOP : GTK_POS_BOTTOM );
  2084     } else {
  2085         /* Draw the tab and the gap
  2086          * We want the gap to be positioned exactly on the tabpanel top
  2087          * border; since tabbox.css may set a negative margin so that the tab
  2088          * frame rect already overlaps the tabpanel frame rect, we need to take
  2089          * that into account when drawing. To that effect, nsNativeThemeGTK
  2090          * passes us this negative margin (bmargin in the graphic below) in the
  2091          * lowest bits of |flags|.  We use it to set gap_voffset, the distance
  2092          * between the top of the gap and the bottom of the tab (resp. the
  2093          * bottom of the gap and the top of the tab when we draw a bottom tab),
  2094          * while ensuring that the gap always touches the border of the tab,
  2095          * i.e. 0 <= gap_voffset <= gap_height, to avoid surprinsing results
  2096          * with big negative or positive margins.
  2097          * Here is a graphical explanation in the case of top tabs:
  2098          *             ___________________________
  2099          *            /                           \
  2100          *           |            T A B            |
  2101          * ----------|. . . . . . . . . . . . . . .|----- top of tabpanel
  2102          *           :    ^       bmargin          :  ^
  2103          *           :    | (-negative margin,     :  |
  2104          *  bottom   :    v  passed in flags)      :  |       gap_height
  2105          *    of  -> :.............................:  |    (the size of the
  2106          * the tab   .       part of the gap       .  |  tabpanel top border)
  2107          *           .      outside of the tab     .  v
  2108          * ----------------------------------------------
  2110          * To draw the gap, we use gtk_paint_box_gap(), see comment in
  2111          * moz_gtk_tabpanels_paint(). This box_gap is made 3 * gap_height tall,
  2112          * which should suffice to ensure that the only visible border is the
  2113          * pierced one.  If the tab is in the middle, we make the box_gap begin
  2114          * a bit to the left of the tab and end a bit to the right, adjusting
  2115          * the gap position so it still is under the tab, because we want the
  2116          * rendering of a gap in the middle of a tabpanel.  This is the role of
  2117          * the gints gap_{l,r}_offset. On the contrary, if the tab is the
  2118          * first, we align the start border of the box_gap with the start
  2119          * border of the tab (left if LTR, right if RTL), by setting the
  2120          * appropriate offset to 0.*/
  2121         gint gap_loffset, gap_roffset, gap_voffset, gap_height;
  2123         /* Get height needed by the gap */
  2124         gap_height = moz_gtk_get_tab_thickness();
  2126         /* Extract gap_voffset from the first bits of flags */
  2127         gap_voffset = flags & MOZ_GTK_TAB_MARGIN_MASK;
  2128         if (gap_voffset > gap_height)
  2129             gap_voffset = gap_height;
  2131         /* Set gap_{l,r}_offset to appropriate values */
  2132         gap_loffset = gap_roffset = 20; /* should be enough */
  2133         if (flags & MOZ_GTK_TAB_FIRST) {
  2134             if (direction == GTK_TEXT_DIR_RTL)
  2135                 gap_roffset = 0;
  2136             else
  2137                 gap_loffset = 0;
  2140         gtk_style_context_set_state(style, GTK_STATE_FLAG_ACTIVE);
  2142         /* Adwaita theme engine crashes without it (rhbz#713764) */
  2143         gtk_style_context_add_region(style, GTK_STYLE_REGION_TAB, 0);      
  2145         if (flags & MOZ_GTK_TAB_BOTTOM) {
  2146             /* Draw the tab on bottom */
  2147             focusRect.y += gap_voffset;
  2148             focusRect.height -= gap_voffset;
  2150             gtk_render_extension(style, cr,
  2151                                  rect->x, rect->y + gap_voffset, rect->width,
  2152                                  rect->height - gap_voffset, GTK_POS_TOP);
  2154             gtk_style_context_remove_region(style, GTK_STYLE_REGION_TAB);
  2156             backRect.y += (gap_voffset - gap_height);
  2157             backRect.height = gap_height;
  2159             /* Draw the gap; erase with background color before painting in
  2160              * case theme does not */
  2161             gtk_render_background(style, cr, backRect.x, backRect.y,
  2162                                  backRect.width, backRect.height);
  2163             cairo_save(cr);
  2164             cairo_rectangle(cr, backRect.x, backRect.y, backRect.width, backRect.height);
  2165             cairo_clip(cr);
  2167             gtk_render_frame_gap(style, cr,
  2168                                  rect->x - gap_loffset,
  2169                                  rect->y + gap_voffset - 3 * gap_height,
  2170                                  rect->width + gap_loffset + gap_roffset,
  2171                                  3 * gap_height, GTK_POS_BOTTOM,
  2172                                  gap_loffset, gap_loffset + rect->width);
  2173             cairo_restore(cr);
  2174         } else {
  2175             /* Draw the tab on top */
  2176             focusRect.height -= gap_voffset;
  2177             gtk_render_extension(style, cr,
  2178                                  rect->x, rect->y, rect->width,
  2179                                  rect->height - gap_voffset, GTK_POS_BOTTOM);
  2181             gtk_style_context_remove_region(style, GTK_STYLE_REGION_TAB);
  2183             backRect.y += (rect->height - gap_voffset);
  2184             backRect.height = gap_height;
  2186             /* Draw the gap; erase with background color before painting in
  2187              * case theme does not */
  2188             gtk_render_background(style, cr, backRect.x, backRect.y,
  2189                                   backRect.width, backRect.height);
  2190             cairo_save(cr);
  2191             cairo_rectangle(cr, backRect.x, backRect.y, backRect.width, backRect.height);
  2192             cairo_clip(cr);
  2194             gtk_render_frame_gap(style, cr,
  2195                                  rect->x - gap_loffset,
  2196                                  rect->y + rect->height - gap_voffset,
  2197                                  rect->width + gap_loffset + gap_roffset,
  2198                                  3 * gap_height, GTK_POS_TOP,
  2199                                  gap_loffset, gap_loffset + rect->width);
  2200             cairo_restore(cr);
  2204     if (state->focused) {
  2205       /* Paint the focus ring */
  2206       GtkBorder border;
  2207       gtk_style_context_get_border(style, GetStateFlagsFromGtkWidgetState(state), &border);
  2209       focusRect.x += border.left;
  2210       focusRect.width -= (border.left + border.right);
  2211       focusRect.y += border.top;
  2212       focusRect.height -= (border.top + border.bottom);
  2214       gtk_render_focus(style, cr,
  2215                       focusRect.x, focusRect.y, focusRect.width, focusRect.height);
  2218     gtk_style_context_restore(style);
  2220     return MOZ_GTK_SUCCESS;
  2223 /* tab area*/
  2224 static gint
  2225 moz_gtk_tabpanels_paint(cairo_t *cr, GdkRectangle* rect,
  2226                         GtkTextDirection direction)
  2228     GtkStyleContext* style;
  2230     ensure_tab_widget();
  2231     gtk_widget_set_direction(gTabWidget, direction);
  2233     style = gtk_widget_get_style_context(gTabWidget);
  2234     gtk_style_context_save(style);
  2236     gtk_render_background(style, cr, rect->x, rect->y, 
  2237                           rect->width, rect->height);
  2238     /*
  2239      * The gap size is not needed in moz_gtk_tabpanels_paint because 
  2240      * the gap will be painted with the foreground tab in moz_gtk_tab_paint.
  2242      * However, if moz_gtk_tabpanels_paint just uses gtk_render_frame(), 
  2243      * the theme will think that there are no tabs and may draw something 
  2244      * different.Hence the trick of using two clip regions, and drawing the 
  2245      * gap outside each clip region, to get the correct frame for 
  2246      * a tabpanel with tabs.
  2247      */
  2248     /* left side */
  2249     cairo_save(cr);
  2250     cairo_rectangle(cr, rect->x, rect->y,
  2251                     rect->x + rect->width / 2,
  2252                     rect->y + rect->height);
  2253     cairo_clip(cr);
  2254     gtk_render_frame_gap(style, cr,
  2255                          rect->x, rect->y,
  2256                          rect->width, rect->height,
  2257                          GTK_POS_TOP, rect->width - 1, rect->width);
  2258     cairo_restore(cr);
  2260     /* right side */
  2261     cairo_save(cr);
  2262     cairo_rectangle(cr, rect->x + rect->width / 2, rect->y,
  2263                     rect->x + rect->width,
  2264                     rect->y + rect->height);
  2265     cairo_clip(cr);
  2266     gtk_render_frame_gap(style, cr,
  2267                          rect->x, rect->y,
  2268                          rect->width, rect->height,
  2269                          GTK_POS_TOP, 0, 1);
  2270     cairo_restore(cr);
  2272     gtk_style_context_restore(style);
  2273     return MOZ_GTK_SUCCESS;
  2276 static gint
  2277 moz_gtk_tab_scroll_arrow_paint(cairo_t *cr, GdkRectangle* rect,
  2278                                GtkWidgetState* state,
  2279                                GtkArrowType arrow_type,
  2280                                GtkTextDirection direction)
  2282     GtkStateFlags state_flags = GetStateFlagsFromGtkWidgetState(state);
  2283     GtkStyleContext* style;
  2284     gdouble arrow_angle;
  2285     gint arrow_size = MIN(rect->width, rect->height);
  2286     gint x = rect->x + (rect->width - arrow_size) / 2;
  2287     gint y = rect->y + (rect->height - arrow_size) / 2;
  2289     ensure_tab_widget();
  2291     style = gtk_widget_get_style_context(gTabWidget);
  2292     gtk_style_context_save(style);
  2293     if (direction == GTK_TEXT_DIR_RTL) {
  2294         arrow_type = (arrow_type == GTK_ARROW_LEFT) ?
  2295                          GTK_ARROW_RIGHT : GTK_ARROW_LEFT;
  2297     switch (arrow_type) {
  2298     case GTK_ARROW_LEFT:
  2299         arrow_angle = ARROW_LEFT;
  2300         break;
  2301     case GTK_ARROW_RIGHT:
  2302         arrow_angle = ARROW_RIGHT;
  2303         break;
  2304     case GTK_ARROW_DOWN:
  2305         arrow_angle = ARROW_DOWN;
  2306         break;
  2307     default:
  2308         arrow_angle = ARROW_UP;
  2309         break;      
  2311     if (arrow_type != GTK_ARROW_NONE)  {        
  2312         gtk_style_context_add_class(style, GTK_STYLE_CLASS_NOTEBOOK); /* TODO TEST */
  2313         gtk_style_context_set_state(style, state_flags);
  2314         gtk_render_arrow(style, cr, arrow_angle,
  2315                          x, y, arrow_size);
  2317     gtk_style_context_restore(style);
  2318     return MOZ_GTK_SUCCESS;
  2321 static gint
  2322 moz_gtk_menu_bar_paint(cairo_t *cr, GdkRectangle* rect,
  2323                        GtkTextDirection direction)
  2325     GtkStyleContext* style;
  2327     ensure_menu_bar_widget();
  2328     gtk_widget_set_direction(gMenuBarWidget, direction);
  2330     style = gtk_widget_get_style_context(gMenuBarWidget);
  2331     gtk_style_context_save(style);
  2332     gtk_style_context_add_class(style, GTK_STYLE_CLASS_MENUBAR);
  2333     gtk_render_background(style, cr, rect->x, rect->y, rect->width, rect->height);
  2334     gtk_render_frame(style, cr, rect->x, rect->y, rect->width, rect->height);
  2335     gtk_style_context_restore(style);
  2337     return MOZ_GTK_SUCCESS;
  2340 static gint
  2341 moz_gtk_menu_popup_paint(cairo_t *cr, GdkRectangle* rect,
  2342                          GtkTextDirection direction)
  2344     GtkStyleContext* style;
  2346     ensure_menu_popup_widget();
  2347     gtk_widget_set_direction(gMenuPopupWidget, direction);
  2349     style = gtk_widget_get_style_context(gMenuPopupWidget);
  2350     gtk_style_context_save(style);
  2351     gtk_style_context_add_class(style, GTK_STYLE_CLASS_MENU);
  2353     gtk_render_background(style, cr, rect->x, rect->y, rect->width, rect->height);
  2354     gtk_render_frame(style, cr, rect->x, rect->y, rect->width, rect->height);
  2355     gtk_style_context_restore(style);
  2357     return MOZ_GTK_SUCCESS;
  2360 // See gtk_menu_item_draw() for reference.
  2361 static gint
  2362 moz_gtk_menu_separator_paint(cairo_t *cr, GdkRectangle* rect,
  2363                              GtkTextDirection direction)
  2365     GtkStyleContext* style;
  2366     gboolean wide_separators;
  2367     gint separator_height;
  2368     gint paint_height;
  2369     guint border_width;
  2370     gint x, y, w, h;
  2371     GtkBorder padding;
  2373     ensure_menu_separator_widget();
  2374     gtk_widget_set_direction(gMenuSeparatorWidget, direction);
  2376     border_width = gtk_container_get_border_width(gMenuSeparatorWidget);
  2377     gtk_widget_style_get(gMenuSeparatorWidget,
  2378                          "wide-separators",    &wide_separators,
  2379                          "separator-height",   &separator_height,
  2380                          NULL);
  2382     style = gtk_widget_get_style_context(gMenuSeparatorWidget);
  2383     gtk_style_context_get_padding(style, 0, &padding);
  2385     x = rect->x + border_width;
  2386     y = rect->y + border_width;
  2387     w = rect->width - border_width * 2;
  2388     h = rect->height - border_width * 2;
  2390     if (wide_separators) {
  2391       gtk_render_frame(style, cr,
  2392                        x + padding.left,
  2393                        y + padding.top,
  2394                        w - padding.left - padding.right,
  2395                        separator_height);
  2396     } else {
  2397       gtk_render_line(style, cr,
  2398                       x + padding.left,
  2399                       y + padding.top,
  2400                       x + w - padding.right - 1,
  2401                       y + padding.top);
  2404     return MOZ_GTK_SUCCESS;
  2407 // See gtk_menu_item_draw() for reference.
  2408 static gint
  2409 moz_gtk_menu_item_paint(cairo_t *cr, GdkRectangle* rect,
  2410                         GtkWidgetState* state,
  2411                         gint flags, GtkTextDirection direction)
  2413     GtkStyleContext* style;
  2414     GtkWidget* item_widget;
  2415     guint border_width;
  2416     gint x, y, w, h;
  2418     if (state->inHover && !state->disabled) {   
  2419         if (flags & MOZ_TOPLEVEL_MENU_ITEM) {
  2420             ensure_menu_bar_item_widget();
  2421             item_widget = gMenuBarItemWidget;
  2422         } else {
  2423             ensure_menu_item_widget();
  2424             item_widget = gMenuItemWidget;
  2426         style = gtk_widget_get_style_context(item_widget);
  2427         gtk_style_context_save(style);
  2429         if (flags & MOZ_TOPLEVEL_MENU_ITEM) {
  2430             gtk_style_context_add_class(style, GTK_STYLE_CLASS_MENUBAR);
  2433         gtk_widget_set_direction(item_widget, direction);
  2434         gtk_style_context_add_class(style, GTK_STYLE_CLASS_MENUITEM);
  2435         gtk_style_context_set_state(style, GetStateFlagsFromGtkWidgetState(state));
  2437         border_width = gtk_container_get_border_width(GTK_CONTAINER(item_widget));
  2439         x = rect->x + border_width;
  2440         y = rect->y + border_width;
  2441         w = rect->width - border_width * 2;
  2442         h = rect->height - border_width * 2;
  2444         gtk_render_background(style, cr, x, y, w, h);
  2445         gtk_render_frame(style, cr, x, y, w, h);
  2446         gtk_style_context_restore(style);
  2449     return MOZ_GTK_SUCCESS;
  2452 static gint
  2453 moz_gtk_menu_arrow_paint(cairo_t *cr, GdkRectangle* rect,
  2454                          GtkWidgetState* state,
  2455                          GtkTextDirection direction)
  2457     GtkStyleContext* style;
  2458     GtkStateFlags state_flags = GetStateFlagsFromGtkWidgetState(state);
  2460     ensure_menu_item_widget();
  2461     gtk_widget_set_direction(gMenuItemWidget, direction);
  2463     style = gtk_widget_get_style_context(gMenuItemWidget);
  2464     gtk_style_context_save(style);
  2465     gtk_style_context_add_class(style, GTK_STYLE_CLASS_MENUITEM);
  2466     gtk_style_context_set_state(style, state_flags);
  2467     gtk_render_arrow(style, cr,
  2468                     (direction == GTK_TEXT_DIR_LTR) ? ARROW_RIGHT : ARROW_LEFT,
  2469                     rect->x, rect->y, rect->width);
  2470     gtk_style_context_restore(style);
  2472     return MOZ_GTK_SUCCESS;
  2475 // See gtk_real_check_menu_item_draw_indicator() for reference.
  2476 static gint
  2477 moz_gtk_check_menu_item_paint(cairo_t *cr, GdkRectangle* rect,
  2478                               GtkWidgetState* state,
  2479                               gboolean checked, gboolean isradio,
  2480                               GtkTextDirection direction)
  2482     GtkStateFlags state_flags = GetStateFlagsFromGtkWidgetState(state);
  2483     GtkStyleContext* style;
  2484     GtkBorder padding;
  2485     gint offset;
  2486     gint indicator_size, horizontal_padding;
  2487     gint x, y;
  2489     moz_gtk_menu_item_paint(cr, rect, state, FALSE, direction);
  2491     ensure_check_menu_item_widget();
  2492     gtk_widget_set_direction(gCheckMenuItemWidget, direction);
  2494     gtk_widget_style_get (gCheckMenuItemWidget,
  2495                           "indicator-size", &indicator_size,
  2496                           "horizontal-padding", &horizontal_padding,
  2497                           NULL);
  2499     style = gtk_widget_get_style_context(gCheckMenuItemWidget);
  2500     gtk_style_context_save(style);
  2501     if (isradio) {
  2502       gtk_style_context_add_class(style, GTK_STYLE_CLASS_RADIO);
  2503     } else {
  2504       gtk_style_context_add_class(style, GTK_STYLE_CLASS_CHECK);
  2507     if (checked)
  2508       state_flags |= GTK_STATE_FLAG_ACTIVE;
  2510     gtk_style_context_set_state(style, state_flags);
  2511     gtk_style_context_get_padding(style, state_flags, &padding);
  2513     offset = gtk_container_get_border_width(GTK_CONTAINER(gCheckMenuItemWidget)) +
  2514                                             padding.left + 2;
  2516     if (direction == GTK_TEXT_DIR_RTL) {
  2517         x = rect->width - indicator_size - offset - horizontal_padding;
  2519     else {
  2520         x = rect->x + offset + horizontal_padding;
  2522     y = rect->y + (rect->height - indicator_size) / 2;
  2524     if (isradio) {
  2525       gtk_render_option(style, cr, x, y, indicator_size, indicator_size);
  2526     } else {
  2527       gtk_render_check(style, cr, x, y, indicator_size, indicator_size);
  2529     gtk_style_context_restore(style);
  2531     return MOZ_GTK_SUCCESS;
  2534 static gint
  2535 moz_gtk_window_paint(cairo_t *cr, GdkRectangle* rect,
  2536                      GtkTextDirection direction)
  2538     GtkStyleContext* style;
  2540     ensure_window_widget();
  2541     gtk_widget_set_direction(gProtoWindow, direction);
  2543     style = gtk_widget_get_style_context(gProtoWindow);	
  2544     gtk_style_context_save(style);
  2545     gtk_style_context_add_class(style, GTK_STYLE_CLASS_BACKGROUND);
  2546     gtk_render_background(style, cr, rect->x, rect->y, rect->width, rect->height);
  2547     gtk_style_context_restore(style);
  2549     return MOZ_GTK_SUCCESS;
  2552 static void
  2553 moz_gtk_add_style_border(GtkStyleContext* style,
  2554                          gint* left, gint* top, gint* right, gint* bottom)
  2556     GtkBorder border;
  2558     gtk_style_context_get_border(style, 0, &border);
  2560     *left += border.left;
  2561     *right += border.right;
  2562     *top += border.top;
  2563     *bottom += border.bottom;
  2566 static void
  2567 moz_gtk_add_style_padding(GtkStyleContext* style,
  2568                           gint* left, gint* top, gint* right, gint* bottom)
  2570     GtkBorder padding;
  2572     gtk_style_context_get_padding(style, 0, &padding);
  2574     *left += padding.left;
  2575     *right += padding.right;
  2576     *top += padding.top;
  2577     *bottom += padding.bottom;
  2580 gint
  2581 moz_gtk_get_widget_border(GtkThemeWidgetType widget, gint* left, gint* top,
  2582                           gint* right, gint* bottom, GtkTextDirection direction,
  2583                           gboolean inhtml)
  2585     GtkWidget* w;
  2586     GtkStyleContext* style;
  2587     *left = *top = *right = *bottom = 0;
  2589     switch (widget) {
  2590     case MOZ_GTK_BUTTON:
  2592             GtkBorder inner_border;
  2593             gboolean interior_focus;
  2594             gint focus_width, focus_pad;
  2596             ensure_button_widget();
  2597             *left = *top = *right = *bottom = gtk_container_get_border_width(GTK_CONTAINER(gButtonWidget));
  2599             /* Don't add this padding in HTML, otherwise the buttons will
  2600                become too big and stuff the layout. */
  2601             if (!inhtml) {
  2602                 moz_gtk_widget_get_focus(gButtonWidget, &interior_focus, &focus_width, &focus_pad);
  2603                 moz_gtk_button_get_inner_border(gButtonWidget, &inner_border);
  2604                 *left += focus_width + focus_pad + inner_border.left;
  2605                 *right += focus_width + focus_pad + inner_border.right;
  2606                 *top += focus_width + focus_pad + inner_border.top;
  2607                 *bottom += focus_width + focus_pad + inner_border.bottom;
  2610             moz_gtk_add_style_border(gtk_widget_get_style_context(gButtonWidget), 
  2611                                      left, top, right, bottom);
  2612             return MOZ_GTK_SUCCESS;
  2614     case MOZ_GTK_ENTRY:
  2616             ensure_entry_widget();
  2617             style = gtk_widget_get_style_context(gEntryWidget);
  2618             moz_gtk_add_style_border(style, left, top, right, bottom);
  2619             moz_gtk_add_style_padding(style, left, top, right, bottom);
  2620             return MOZ_GTK_SUCCESS;
  2622     case MOZ_GTK_TREEVIEW:
  2624             ensure_scrolled_window_widget();
  2625             style = gtk_widget_get_style_context(gScrolledWindowWidget);
  2626             gtk_style_context_save(style);
  2627             gtk_style_context_add_class(style, GTK_STYLE_CLASS_FRAME);
  2628             moz_gtk_add_style_border(style, left, top, right, bottom);
  2629             gtk_style_context_restore(style);
  2630             return MOZ_GTK_SUCCESS;
  2632     case MOZ_GTK_TREE_HEADER_CELL:
  2634             /* A Tree Header in GTK is just a different styled button 
  2635              * It must be placed in a TreeView for getting the correct style
  2636              * assigned.
  2637              * That is why the following code is the same as for MOZ_GTK_BUTTON.  
  2638              * */
  2640             GtkBorder inner_border;
  2641             gboolean interior_focus;
  2642             gint focus_width, focus_pad;
  2644             ensure_tree_header_cell_widget();
  2645             *left = *top = *right = *bottom = gtk_container_get_border_width(GTK_CONTAINER(gTreeHeaderCellWidget));
  2647             moz_gtk_widget_get_focus(gTreeHeaderCellWidget, &interior_focus, &focus_width, &focus_pad);
  2648             moz_gtk_button_get_inner_border(gTreeHeaderCellWidget, &inner_border);
  2649             *left += focus_width + focus_pad + inner_border.left;
  2650             *right += focus_width + focus_pad + inner_border.right;
  2651             *top += focus_width + focus_pad + inner_border.top;
  2652             *bottom += focus_width + focus_pad + inner_border.bottom;
  2654             moz_gtk_add_style_border(gtk_widget_get_style_context(gTreeHeaderCellWidget), 
  2655                                      left, top, right, bottom);
  2656             return MOZ_GTK_SUCCESS;
  2658     case MOZ_GTK_TREE_HEADER_SORTARROW:
  2659         ensure_tree_header_cell_widget();
  2660         w = gTreeHeaderSortArrowWidget;
  2661         break;
  2662     case MOZ_GTK_DROPDOWN_ENTRY:
  2663         ensure_combo_box_entry_widgets();
  2664         w = gComboBoxEntryTextareaWidget;
  2665         break;
  2666     case MOZ_GTK_DROPDOWN_ARROW:
  2667         ensure_combo_box_entry_widgets();
  2668         w = gComboBoxEntryButtonWidget;
  2669         break;
  2670     case MOZ_GTK_DROPDOWN:
  2672             /* We need to account for the arrow on the dropdown, so text
  2673              * doesn't come too close to the arrow, or in some cases spill
  2674              * into the arrow. */
  2675             gboolean ignored_interior_focus, wide_separators;
  2676             gint focus_width, focus_pad, separator_width;
  2677             GtkRequisition arrow_req;
  2678             GtkBorder border;
  2680             ensure_combo_box_widgets();
  2682             *left = gtk_container_get_border_width(GTK_CONTAINER(gComboBoxButtonWidget));
  2684             if (!inhtml) {
  2685                 moz_gtk_widget_get_focus(gComboBoxButtonWidget,
  2686                                          &ignored_interior_focus,
  2687                                          &focus_width, &focus_pad);
  2688                 *left += focus_width + focus_pad;
  2691             style = gtk_widget_get_style_context(gComboBoxButtonWidget);
  2692             gtk_style_context_get_border(style, 0, &border);
  2694             *top = *left + border.top;
  2695             *left += border.left;
  2697             *right = *left; *bottom = *top;
  2699             /* If there is no separator, don't try to count its width. */
  2700             separator_width = 0;
  2701             if (gComboBoxSeparatorWidget) {
  2702                 gtk_widget_style_get(gComboBoxSeparatorWidget,
  2703                                      "wide-separators", &wide_separators,
  2704                                      "separator-width", &separator_width,
  2705                                      NULL);
  2707                 if (!wide_separators) {
  2708                     style = gtk_widget_get_style_context(gComboBoxSeparatorWidget);
  2709                     gtk_style_context_get_border(style, 0, &border);
  2710                     separator_width = border.left;
  2714             gtk_widget_size_request(gComboBoxArrowWidget, &arrow_req);
  2716             if (direction == GTK_TEXT_DIR_RTL)
  2717                 *left += separator_width + arrow_req.width;
  2718             else
  2719                 *right += separator_width + arrow_req.width;
  2721             return MOZ_GTK_SUCCESS;
  2723     case MOZ_GTK_TABPANELS:
  2724         ensure_tab_widget();
  2725         w = gTabWidget;
  2726         break;
  2727     case MOZ_GTK_PROGRESSBAR:
  2728         ensure_progress_widget();
  2729         w = gProgressWidget;
  2730         break;
  2731     case MOZ_GTK_SPINBUTTON_ENTRY:
  2732     case MOZ_GTK_SPINBUTTON_UP:
  2733     case MOZ_GTK_SPINBUTTON_DOWN:
  2734         ensure_spin_widget();
  2735         w = gSpinWidget;
  2736         break;
  2737     case MOZ_GTK_SCALE_HORIZONTAL:
  2738         ensure_scale_widget();
  2739         w = gHScaleWidget;
  2740         break;
  2741     case MOZ_GTK_SCALE_VERTICAL:
  2742         ensure_scale_widget();
  2743         w = gVScaleWidget;
  2744         break;
  2745     case MOZ_GTK_FRAME:
  2746         ensure_frame_widget();
  2747         w = gFrameWidget;
  2748         break;
  2749     case MOZ_GTK_CHECKBUTTON_LABEL:
  2750     case MOZ_GTK_RADIOBUTTON_LABEL:
  2752             gboolean interior_focus;
  2753             gint focus_width, focus_pad;
  2755             /* If the focus is interior, then the label has a border of
  2756                (focus_width + focus_pad). */
  2757             if (widget == MOZ_GTK_CHECKBUTTON_LABEL) {
  2758                 ensure_checkbox_widget();
  2759                 moz_gtk_widget_get_focus(gCheckboxWidget, &interior_focus,
  2760                                            &focus_width, &focus_pad);
  2762             else {
  2763                 ensure_radiobutton_widget();
  2764                 moz_gtk_widget_get_focus(gRadiobuttonWidget, &interior_focus,
  2765                                         &focus_width, &focus_pad);
  2768             if (interior_focus)
  2769                 *left = *top = *right = *bottom = (focus_width + focus_pad);
  2771             return MOZ_GTK_SUCCESS;
  2774     case MOZ_GTK_CHECKBUTTON_CONTAINER:
  2775     case MOZ_GTK_RADIOBUTTON_CONTAINER:
  2777             gboolean interior_focus;
  2778             gint focus_width, focus_pad;
  2780             /* If the focus is _not_ interior, then the container has a border
  2781                of (focus_width + focus_pad). */
  2782             if (widget == MOZ_GTK_CHECKBUTTON_CONTAINER) {
  2783                 ensure_checkbox_widget();
  2784                 moz_gtk_widget_get_focus(gCheckboxWidget, &interior_focus,
  2785                                            &focus_width, &focus_pad);
  2786                 w = gCheckboxWidget;
  2787             } else {
  2788                 ensure_radiobutton_widget();
  2789                 moz_gtk_widget_get_focus(gRadiobuttonWidget, &interior_focus,
  2790                                         &focus_width, &focus_pad);
  2791                 w = gRadiobuttonWidget;
  2794             *left = *top = *right = *bottom = gtk_container_get_border_width(GTK_CONTAINER(w));
  2796             if (!interior_focus) {
  2797                 *left += (focus_width + focus_pad);
  2798                 *right += (focus_width + focus_pad);
  2799                 *top += (focus_width + focus_pad);
  2800                 *bottom += (focus_width + focus_pad);
  2803             return MOZ_GTK_SUCCESS;
  2805     case MOZ_GTK_MENUPOPUP:
  2806         ensure_menu_popup_widget();
  2807         w = gMenuPopupWidget;
  2808         break;
  2809     case MOZ_GTK_MENUITEM:
  2810     case MOZ_GTK_CHECKMENUITEM:
  2811     case MOZ_GTK_RADIOMENUITEM:
  2813             if (widget == MOZ_GTK_MENUITEM) {
  2814                 ensure_menu_item_widget();
  2815                 ensure_menu_bar_item_widget();
  2816                 w = gMenuItemWidget;
  2818             else {
  2819                 ensure_check_menu_item_widget();
  2820                 w = gCheckMenuItemWidget;
  2823             *left = *top = *right = *bottom = gtk_container_get_border_width(GTK_CONTAINER(w));
  2824             moz_gtk_add_style_padding(gtk_widget_get_style_context(w),
  2825                                       left, top, right, bottom);
  2826             return MOZ_GTK_SUCCESS;
  2828     case MOZ_GTK_TAB:
  2829         ensure_tab_widget();
  2830         w = gTabWidget;
  2831         break;
  2832     /* These widgets have no borders, since they are not containers. */
  2833     case MOZ_GTK_SPLITTER_HORIZONTAL:
  2834     case MOZ_GTK_SPLITTER_VERTICAL:
  2835     case MOZ_GTK_CHECKBUTTON:
  2836     case MOZ_GTK_RADIOBUTTON:
  2837     case MOZ_GTK_SCROLLBAR_BUTTON:
  2838     case MOZ_GTK_SCROLLBAR_TRACK_HORIZONTAL:
  2839     case MOZ_GTK_SCROLLBAR_TRACK_VERTICAL:
  2840     case MOZ_GTK_SCROLLBAR_THUMB_HORIZONTAL:
  2841     case MOZ_GTK_SCROLLBAR_THUMB_VERTICAL:
  2842     case MOZ_GTK_SCALE_THUMB_HORIZONTAL:
  2843     case MOZ_GTK_SCALE_THUMB_VERTICAL:
  2844     case MOZ_GTK_GRIPPER:
  2845     case MOZ_GTK_PROGRESS_CHUNK:
  2846     case MOZ_GTK_PROGRESS_CHUNK_INDETERMINATE:
  2847     case MOZ_GTK_PROGRESS_CHUNK_VERTICAL_INDETERMINATE:
  2848     case MOZ_GTK_TREEVIEW_EXPANDER:
  2849     case MOZ_GTK_TOOLBAR_SEPARATOR:
  2850     case MOZ_GTK_MENUSEPARATOR:
  2851     /* These widgets have no borders.*/
  2852     case MOZ_GTK_SPINBUTTON:
  2853     case MOZ_GTK_TOOLTIP:
  2854     case MOZ_GTK_WINDOW:
  2855     case MOZ_GTK_RESIZER:
  2856     case MOZ_GTK_MENUARROW:
  2857     case MOZ_GTK_TOOLBARBUTTON_ARROW:
  2858     case MOZ_GTK_TOOLBAR:
  2859     case MOZ_GTK_MENUBAR:
  2860     case MOZ_GTK_TAB_SCROLLARROW:
  2861         return MOZ_GTK_SUCCESS;
  2862     default:
  2863         g_warning("Unsupported widget type: %d", widget);
  2864         return MOZ_GTK_UNKNOWN_WIDGET;
  2866     /* TODO - we're still missing some widget implementations */
  2867     if (w) {
  2868       moz_gtk_add_style_border(gtk_widget_get_style_context(w), 
  2869                                left, top, right, bottom);
  2871     return MOZ_GTK_SUCCESS;
  2874 gint
  2875 moz_gtk_get_combo_box_entry_button_size(gint* width, gint* height)
  2877     /*
  2878      * We get the requisition of the drop down button, which includes
  2879      * all padding, border and focus line widths the button uses,
  2880      * as well as the minimum arrow size and its padding
  2881      * */
  2882     GtkRequisition requisition;
  2883     ensure_combo_box_entry_widgets();
  2885     gtk_widget_size_request(gComboBoxEntryButtonWidget, &requisition);
  2886     *width = requisition.width;
  2887     *height = requisition.height;
  2889     return MOZ_GTK_SUCCESS;
  2892 gint
  2893 moz_gtk_get_tab_scroll_arrow_size(gint* width, gint* height)
  2895     gint arrow_size;
  2897     ensure_tab_widget();
  2898     gtk_widget_style_get(gTabWidget,
  2899                          "scroll-arrow-hlength", &arrow_size,
  2900                          NULL);
  2902     *height = *width = arrow_size;
  2904     return MOZ_GTK_SUCCESS;
  2907 gint
  2908 moz_gtk_get_arrow_size(gint* width, gint* height)
  2910     GtkRequisition requisition;
  2911     ensure_button_arrow_widget();
  2913     gtk_widget_size_request(gButtonArrowWidget, &requisition);
  2914     *width = requisition.width;
  2915     *height = requisition.height;
  2917     return MOZ_GTK_SUCCESS;
  2920 gint
  2921 moz_gtk_get_toolbar_separator_width(gint* size)
  2923     gboolean wide_separators;
  2924     gint separator_width;
  2925     GtkStyleContext* style;
  2926     GtkBorder border;
  2928     ensure_toolbar_widget();
  2929     style = gtk_widget_get_style_context(gToolbarWidget);
  2931     gtk_widget_style_get(gToolbarWidget,
  2932                          "space-size", size,
  2933                          "wide-separators",  &wide_separators,
  2934                          "separator-width", &separator_width,
  2935                          NULL);
  2936     /* Just in case... */
  2937     gtk_style_context_get_border(style, 0, &border);
  2938     *size = MAX(*size, (wide_separators ? separator_width : border.left));
  2939     return MOZ_GTK_SUCCESS;
  2942 gint
  2943 moz_gtk_get_expander_size(gint* size)
  2945     ensure_expander_widget();
  2946     gtk_widget_style_get(gExpanderWidget,
  2947                          "expander-size", size,
  2948                          NULL);
  2950     return MOZ_GTK_SUCCESS;
  2953 gint
  2954 moz_gtk_get_treeview_expander_size(gint* size)
  2956     ensure_tree_view_widget();
  2957     gtk_widget_style_get(gTreeViewWidget,
  2958                          "expander-size", size,
  2959                          NULL);
  2961     return MOZ_GTK_SUCCESS;
  2964 // See gtk_menu_item_draw() for reference.
  2965 gint
  2966 moz_gtk_get_menu_separator_height(gint *size)
  2968     gboolean  wide_separators;
  2969     gint      separator_height;
  2970     GtkBorder padding;
  2971     GtkStyleContext* style;
  2972     guint border_width;
  2974     ensure_menu_separator_widget();
  2976     gtk_widget_style_get(gMenuSeparatorWidget,
  2977                           "wide-separators",  &wide_separators,
  2978                           "separator-height", &separator_height,
  2979                           NULL);
  2981     border_width = gtk_container_get_border_width(GTK_CONTAINER(gMenuSeparatorWidget));
  2983     style = gtk_widget_get_style_context(gMenuSeparatorWidget);
  2984     gtk_style_context_get_padding(style, 0, &padding);
  2986     *size = padding.top + padding.bottom + border_width*2;
  2987     *size += (wide_separators) ? separator_height : 1;
  2989     return MOZ_GTK_SUCCESS;
  2992 gint
  2993 moz_gtk_get_scalethumb_metrics(GtkOrientation orient, gint* thumb_length, gint* thumb_height)
  2995   GtkWidget* widget;
  2997   ensure_scale_widget();
  2998   widget = ((orient == GTK_ORIENTATION_HORIZONTAL) ? gHScaleWidget : gVScaleWidget);
  3000   gtk_widget_style_get (widget,
  3001                         "slider_length", thumb_length,
  3002                         "slider_width", thumb_height,
  3003                         NULL);
  3005   return MOZ_GTK_SUCCESS;
  3008 gint
  3009 moz_gtk_get_scrollbar_metrics(MozGtkScrollbarMetrics *metrics)
  3011     ensure_scrollbar_widget();
  3013     gtk_widget_style_get (gHorizScrollbarWidget,
  3014                           "slider_width", &metrics->slider_width,
  3015                           "trough_border", &metrics->trough_border,
  3016                           "stepper_size", &metrics->stepper_size,
  3017                           "stepper_spacing", &metrics->stepper_spacing,
  3018                           NULL);
  3020     metrics->min_slider_size = 
  3021         gtk_range_get_min_slider_size(GTK_RANGE(gHorizScrollbarWidget));
  3023     return MOZ_GTK_SUCCESS;
  3026 gboolean
  3027 moz_gtk_images_in_menus()
  3029     gboolean result;
  3030     GtkSettings* settings;
  3032     ensure_image_menu_item_widget();
  3033     settings = gtk_widget_get_settings(gImageMenuItemWidget);
  3035     g_object_get(settings, "gtk-menu-images", &result, NULL);
  3036     return result;
  3039 gboolean
  3040 moz_gtk_images_in_buttons()
  3042     gboolean result;
  3043     GtkSettings* settings;
  3045     ensure_button_widget();
  3046     settings = gtk_widget_get_settings(gButtonWidget);
  3048     g_object_get(settings, "gtk-button-images", &result, NULL);
  3049     return result;
  3052 /* cairo_t *cr argument has to be a system-cairo. */
  3053 gint
  3054 moz_gtk_widget_paint(GtkThemeWidgetType widget, cairo_t *cr,
  3055                      GdkRectangle* rect,
  3056                      GtkWidgetState* state, gint flags,
  3057                      GtkTextDirection direction)
  3059     /* A workaround for https://bugzilla.gnome.org/show_bug.cgi?id=694086
  3060      */
  3061     cairo_new_path(cr);
  3063     switch (widget) {
  3064     case MOZ_GTK_BUTTON:
  3065         if (state->depressed) {
  3066             ensure_toggle_menu_button_widget();
  3067             return moz_gtk_button_paint(cr, rect, state,
  3068                                         (GtkReliefStyle) flags,
  3069                                         gToggleMenuButtonWidget, direction);
  3071         ensure_button_widget();
  3072         return moz_gtk_button_paint(cr, rect, state,
  3073                                     (GtkReliefStyle) flags, gButtonWidget,
  3074                                     direction);
  3075         break;
  3076     case MOZ_GTK_CHECKBUTTON:
  3077     case MOZ_GTK_RADIOBUTTON:
  3078         return moz_gtk_toggle_paint(cr, rect, state,
  3079                                     !!(flags & MOZ_GTK_WIDGET_CHECKED),
  3080                                     !!(flags & MOZ_GTK_WIDGET_INCONSISTENT),
  3081                                     (widget == MOZ_GTK_RADIOBUTTON),
  3082                                     direction);
  3083         break;
  3084     case MOZ_GTK_SCROLLBAR_BUTTON:
  3085         return moz_gtk_scrollbar_button_paint(cr, rect, state,
  3086                                               (GtkScrollbarButtonFlags) flags,
  3087                                               direction);
  3088         break;
  3089     case MOZ_GTK_SCROLLBAR_TRACK_HORIZONTAL:
  3090     case MOZ_GTK_SCROLLBAR_TRACK_VERTICAL:
  3091         return moz_gtk_scrollbar_trough_paint(widget, cr, rect,
  3092                                               state, direction);
  3093         break;
  3094     case MOZ_GTK_SCROLLBAR_THUMB_HORIZONTAL:
  3095     case MOZ_GTK_SCROLLBAR_THUMB_VERTICAL:
  3096         return moz_gtk_scrollbar_thumb_paint(widget, cr, rect,
  3097                                              state, direction);
  3098         break;
  3099     case MOZ_GTK_SCALE_HORIZONTAL:
  3100     case MOZ_GTK_SCALE_VERTICAL:
  3101         return moz_gtk_scale_paint(cr, rect, state,
  3102                                    (GtkOrientation) flags, direction);
  3103         break;
  3104     case MOZ_GTK_SCALE_THUMB_HORIZONTAL:
  3105     case MOZ_GTK_SCALE_THUMB_VERTICAL:
  3106         return moz_gtk_scale_thumb_paint(cr, rect, state,
  3107                                          (GtkOrientation) flags, direction);
  3108         break;
  3109     case MOZ_GTK_SPINBUTTON:
  3110         return moz_gtk_spin_paint(cr, rect, direction);
  3111         break;
  3112     case MOZ_GTK_SPINBUTTON_UP:
  3113     case MOZ_GTK_SPINBUTTON_DOWN:
  3114         return moz_gtk_spin_updown_paint(cr, rect,
  3115                                          (widget == MOZ_GTK_SPINBUTTON_DOWN),
  3116                                          state, direction);
  3117         break;
  3118     case MOZ_GTK_SPINBUTTON_ENTRY:
  3119         ensure_spin_widget();
  3120         return moz_gtk_entry_paint(cr, rect, state,
  3121                                    gSpinWidget, direction);
  3122         break;
  3123     case MOZ_GTK_GRIPPER:
  3124         return moz_gtk_gripper_paint(cr, rect, state,
  3125                                      direction);
  3126         break;
  3127     case MOZ_GTK_TREEVIEW:
  3128         return moz_gtk_treeview_paint(cr, rect, state,
  3129                                       direction);
  3130         break;
  3131     case MOZ_GTK_TREE_HEADER_CELL:
  3132         return moz_gtk_tree_header_cell_paint(cr, rect, state,
  3133                                               flags, direction);
  3134         break;
  3135     case MOZ_GTK_TREE_HEADER_SORTARROW:
  3136         return moz_gtk_tree_header_sort_arrow_paint(cr, rect, 
  3137                                                     state,
  3138                                                     (GtkArrowType) flags,
  3139                                                     direction);
  3140         break;
  3141     case MOZ_GTK_TREEVIEW_EXPANDER:
  3142         return moz_gtk_treeview_expander_paint(cr, rect, state,
  3143                                                (GtkExpanderStyle) flags, direction);
  3144         break;
  3145     case MOZ_GTK_ENTRY:
  3146         ensure_entry_widget();
  3147         return moz_gtk_entry_paint(cr, rect, state,
  3148                                    gEntryWidget, direction);
  3149         break;
  3150     case MOZ_GTK_DROPDOWN:
  3151         return moz_gtk_combo_box_paint(cr, rect, state,
  3152                                        (gboolean) flags, direction);
  3153         break;
  3154     case MOZ_GTK_DROPDOWN_ARROW:
  3155         return moz_gtk_combo_box_entry_button_paint(cr, rect,
  3156                                                     state, flags, direction);
  3157         break;
  3158     case MOZ_GTK_DROPDOWN_ENTRY:
  3159         ensure_combo_box_entry_widgets();
  3160         return moz_gtk_entry_paint(cr, rect, state,
  3161                                    gComboBoxEntryTextareaWidget, direction);
  3162         break;
  3163     case MOZ_GTK_CHECKBUTTON_CONTAINER:
  3164     case MOZ_GTK_RADIOBUTTON_CONTAINER:
  3165         return moz_gtk_container_paint(cr, rect, state,
  3166                                        (widget == MOZ_GTK_RADIOBUTTON_CONTAINER),
  3167                                        direction);
  3168         break;
  3169     case MOZ_GTK_CHECKBUTTON_LABEL:
  3170     case MOZ_GTK_RADIOBUTTON_LABEL:
  3171         return moz_gtk_toggle_label_paint(cr, rect, state,
  3172                                           (widget == MOZ_GTK_RADIOBUTTON_LABEL),
  3173                                           direction);
  3174         break;
  3175     case MOZ_GTK_TOOLBAR:
  3176         return moz_gtk_toolbar_paint(cr, rect, direction);
  3177         break;
  3178     case MOZ_GTK_TOOLBAR_SEPARATOR:
  3179         return moz_gtk_toolbar_separator_paint(cr, rect,
  3180                                                direction);
  3181         break;
  3182     case MOZ_GTK_TOOLTIP:
  3183         return moz_gtk_tooltip_paint(cr, rect, direction);
  3184         break;
  3185     case MOZ_GTK_FRAME:
  3186         return moz_gtk_frame_paint(cr, rect, direction);
  3187         break;
  3188     case MOZ_GTK_RESIZER:
  3189         return moz_gtk_resizer_paint(cr, rect, state,
  3190                                      direction);
  3191         break;
  3192     case MOZ_GTK_PROGRESSBAR:
  3193         return moz_gtk_progressbar_paint(cr, rect, direction);
  3194         break;
  3195     case MOZ_GTK_PROGRESS_CHUNK:
  3196     case MOZ_GTK_PROGRESS_CHUNK_INDETERMINATE:
  3197     case MOZ_GTK_PROGRESS_CHUNK_VERTICAL_INDETERMINATE:
  3198         return moz_gtk_progress_chunk_paint(cr, rect,
  3199                                             direction, widget);
  3200         break;
  3201     case MOZ_GTK_TAB:
  3202         return moz_gtk_tab_paint(cr, rect, state,
  3203                                  (GtkTabFlags) flags, direction);
  3204         break;
  3205     case MOZ_GTK_TABPANELS:
  3206         return moz_gtk_tabpanels_paint(cr, rect, direction);
  3207         break;
  3208     case MOZ_GTK_TAB_SCROLLARROW:
  3209         return moz_gtk_tab_scroll_arrow_paint(cr, rect, state,
  3210                                               (GtkArrowType) flags, direction);
  3211         break;
  3212     case MOZ_GTK_MENUBAR:
  3213         return moz_gtk_menu_bar_paint(cr, rect, direction);
  3214         break;
  3215     case MOZ_GTK_MENUPOPUP:
  3216         return moz_gtk_menu_popup_paint(cr, rect, direction);
  3217         break;
  3218     case MOZ_GTK_MENUSEPARATOR:
  3219         return moz_gtk_menu_separator_paint(cr, rect,
  3220                                             direction);
  3221         break;
  3222     case MOZ_GTK_MENUITEM:
  3223         return moz_gtk_menu_item_paint(cr, rect, state, flags,
  3224                                        direction);
  3225         break;
  3226     case MOZ_GTK_MENUARROW:
  3227         return moz_gtk_menu_arrow_paint(cr, rect, state,
  3228                                         direction);
  3229         break;
  3230     case MOZ_GTK_TOOLBARBUTTON_ARROW:
  3231         return moz_gtk_arrow_paint(cr, rect, state,
  3232                                    (GtkArrowType) flags, direction);
  3233         break;
  3234     case MOZ_GTK_CHECKMENUITEM:
  3235     case MOZ_GTK_RADIOMENUITEM:
  3236         return moz_gtk_check_menu_item_paint(cr, rect, state,
  3237                                              (gboolean) flags,
  3238                                              (widget == MOZ_GTK_RADIOMENUITEM),
  3239                                              direction);
  3240         break;
  3241     case MOZ_GTK_SPLITTER_HORIZONTAL:
  3242         return moz_gtk_vpaned_paint(cr, rect, state);
  3243         break;
  3244     case MOZ_GTK_SPLITTER_VERTICAL:
  3245         return moz_gtk_hpaned_paint(cr, rect, state);
  3246         break;
  3247     case MOZ_GTK_WINDOW:
  3248         return moz_gtk_window_paint(cr, rect, direction);
  3249         break;
  3250     default:
  3251         g_warning("Unknown widget type: %d", widget);
  3254     return MOZ_GTK_UNKNOWN_WIDGET;
  3257 GtkWidget* moz_gtk_get_scrollbar_widget(void)
  3259     NS_ASSERTION(is_initialized, "Forgot to call moz_gtk_init()");
  3260     ensure_scrollbar_widget();
  3261     return gHorizScrollbarWidget;
  3264 gint
  3265 moz_gtk_shutdown()
  3267     GtkWidgetClass *entry_class;
  3269     if (gTooltipWidget)
  3270         gtk_widget_destroy(gTooltipWidget);
  3271     /* This will destroy all of our widgets */
  3272     if (gProtoWindow)
  3273         gtk_widget_destroy(gProtoWindow);
  3275     /* TODO - replace it with appropriate widget */
  3276     if (gTreeHeaderSortArrowWidget)
  3277         gtk_widget_destroy(gTreeHeaderSortArrowWidget);
  3279     gProtoWindow = NULL;
  3280     gProtoLayout = NULL;
  3281     gButtonWidget = NULL;
  3282     gToggleMenuButtonWidget = NULL;
  3283     gButtonArrowWidget = NULL;
  3284     gCheckboxWidget = NULL;
  3285     gRadiobuttonWidget = NULL;
  3286     gHorizScrollbarWidget = NULL;
  3287     gVertScrollbarWidget = NULL;
  3288     gSpinWidget = NULL;
  3289     gHScaleWidget = NULL;
  3290     gVScaleWidget = NULL;
  3291     gEntryWidget = NULL;
  3292     gComboBoxWidget = NULL;
  3293     gComboBoxButtonWidget = NULL;
  3294     gComboBoxSeparatorWidget = NULL;
  3295     gComboBoxArrowWidget = NULL;
  3296     gComboBoxEntryWidget = NULL;
  3297     gComboBoxEntryButtonWidget = NULL;
  3298     gComboBoxEntryArrowWidget = NULL;
  3299     gComboBoxEntryTextareaWidget = NULL;
  3300     gHandleBoxWidget = NULL;
  3301     gToolbarWidget = NULL;
  3302     gStatusbarWidget = NULL;
  3303     gFrameWidget = NULL;
  3304     gProgressWidget = NULL;
  3305     gTabWidget = NULL;
  3306     gTooltipWidget = NULL;
  3307     gMenuBarWidget = NULL;
  3308     gMenuBarItemWidget = NULL;
  3309     gMenuPopupWidget = NULL;
  3310     gMenuItemWidget = NULL;
  3311     gImageMenuItemWidget = NULL;
  3312     gCheckMenuItemWidget = NULL;
  3313     gTreeViewWidget = NULL;
  3314     gMiddleTreeViewColumn = NULL;
  3315     gTreeHeaderCellWidget = NULL;
  3316     gTreeHeaderSortArrowWidget = NULL;
  3317     gExpanderWidget = NULL;
  3318     gToolbarSeparatorWidget = NULL;
  3319     gMenuSeparatorWidget = NULL;
  3320     gHPanedWidget = NULL;
  3321     gVPanedWidget = NULL;
  3322     gScrolledWindowWidget = NULL;
  3324     entry_class = g_type_class_peek(GTK_TYPE_ENTRY);
  3325     g_type_class_unref(entry_class);
  3327     is_initialized = FALSE;
  3329     return MOZ_GTK_SUCCESS;

mercurial