Home | History | Annotate | Download | only in gtk
      1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
      2 /* ***** BEGIN LICENSE BLOCK *****
      3  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
      4  *
      5  * The contents of this file are subject to the Mozilla Public License Version
      6  * 1.1 (the "License"); you may not use this file except in compliance with
      7  * the License. You may obtain a copy of the License at
      8  * http://www.mozilla.org/MPL/
      9  *
     10  * Software distributed under the License is distributed on an "AS IS" basis,
     11  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
     12  * for the specific language governing rights and limitations under the
     13  * License.
     14  *
     15  * The Original Code is mozilla.org code.
     16  *
     17  * The Initial Developer of the Original Code is
     18  * Netscape Communications Corporation.
     19  * Portions created by the Initial Developer are Copyright (C) 2002
     20  * the Initial Developer. All Rights Reserved.
     21  *
     22  * Contributor(s):
     23  *  Brian Ryner <bryner (at) brianryner.com>  (Original Author)
     24  *  Pierre Chanial <p_ch (at) verizon.net>
     25  *  Michael Ventnor <m.ventnor (at) gmail.com>
     26  *  Alp Toker <alp (at) nuanti.com>
     27  *
     28  * Alternatively, the contents of this file may be used under the terms of
     29  * either the GNU General Public License Version 2 or later (the "GPL"), or
     30  * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
     31  * in which case the provisions of the GPL or the LGPL are applicable instead
     32  * of those above. If you wish to allow use of your version of this file only
     33  * under the terms of either the GPL or the LGPL, and not to allow others to
     34  * use your version of this file under the terms of the MPL, indicate your
     35  * decision by deleting the provisions above and replace them with the notice
     36  * and other provisions required by the GPL or the LGPL. If you do not delete
     37  * the provisions above, a recipient may use your version of this file under
     38  * the terms of any one of the MPL, the GPL or the LGPL.
     39  *
     40  * ***** END LICENSE BLOCK ***** */
     41 
     42 /*
     43  * This file contains painting functions for each of the gtk2 widgets.
     44  * Adapted from the gtkdrawing.c, and gtk+2.0 source.
     45  */
     46 
     47 #include <gdk/gdkprivate.h>
     48 #include "gtkdrawing.h"
     49 
     50 #include "Assertions.h"
     51 
     52 #include <math.h>
     53 #include <string.h>
     54 
     55 #define XTHICKNESS(style) (style->xthickness)
     56 #define YTHICKNESS(style) (style->ythickness)
     57 #define WINDOW_IS_MAPPED(window) ((window) && GDK_IS_WINDOW(window) && gdk_window_is_visible(window))
     58 
     59 static GtkThemeParts *gParts = NULL;
     60 static style_prop_t style_prop_func;
     61 static gboolean have_arrow_scaling;
     62 static gboolean is_initialized;
     63 
     64 void
     65 moz_gtk_use_theme_parts(GtkThemeParts* parts)
     66 {
     67     gParts = parts;
     68 }
     69 
     70 /* Because we have such an unconventional way of drawing widgets, signal to the GTK theme engine
     71    that they are drawing for Mozilla instead of a conventional GTK app so they can do any specific
     72    things they may want to do. */
     73 static void
     74 moz_gtk_set_widget_name(GtkWidget* widget)
     75 {
     76     gtk_widget_set_name(widget, "MozillaGtkWidget");
     77 }
     78 
     79 gint
     80 moz_gtk_enable_style_props(style_prop_t styleGetProp)
     81 {
     82     style_prop_func = styleGetProp;
     83     return MOZ_GTK_SUCCESS;
     84 }
     85 
     86 static gint
     87 ensure_window_widget()
     88 {
     89     if (!gParts->protoWindow) {
     90         gParts->protoWindow = gtk_window_new(GTK_WINDOW_POPUP);
     91 
     92         if (gParts->colormap)
     93             gtk_widget_set_colormap(gParts->protoWindow, gParts->colormap);
     94 
     95         gtk_widget_realize(gParts->protoWindow);
     96         moz_gtk_set_widget_name(gParts->protoWindow);
     97     }
     98     return MOZ_GTK_SUCCESS;
     99 }
    100 
    101 static gint
    102 setup_widget_prototype(GtkWidget* widget)
    103 {
    104     ensure_window_widget();
    105     if (!gParts->protoLayout) {
    106         gParts->protoLayout = gtk_fixed_new();
    107         gtk_container_add(GTK_CONTAINER(gParts->protoWindow), gParts->protoLayout);
    108     }
    109 
    110     gtk_container_add(GTK_CONTAINER(gParts->protoLayout), widget);
    111     gtk_widget_realize(widget);
    112     g_object_set_data(G_OBJECT(widget), "transparent-bg-hint", GINT_TO_POINTER(TRUE));
    113     return MOZ_GTK_SUCCESS;
    114 }
    115 
    116 static gint
    117 ensure_button_widget()
    118 {
    119     if (!gParts->buttonWidget) {
    120         gParts->buttonWidget = gtk_button_new_with_label("M");
    121         setup_widget_prototype(gParts->buttonWidget);
    122     }
    123     return MOZ_GTK_SUCCESS;
    124 }
    125 
    126 static gint
    127 ensure_hpaned_widget()
    128 {
    129     if (!gParts->hpanedWidget) {
    130         gParts->hpanedWidget = gtk_hpaned_new();
    131         setup_widget_prototype(gParts->hpanedWidget);
    132     }
    133     return MOZ_GTK_SUCCESS;
    134 }
    135 
    136 static gint
    137 ensure_vpaned_widget()
    138 {
    139     if (!gParts->vpanedWidget) {
    140         gParts->vpanedWidget = gtk_vpaned_new();
    141         setup_widget_prototype(gParts->vpanedWidget);
    142     }
    143     return MOZ_GTK_SUCCESS;
    144 }
    145 
    146 static gint
    147 ensure_toggle_button_widget()
    148 {
    149     if (!gParts->toggleButtonWidget) {
    150         gParts->toggleButtonWidget = gtk_toggle_button_new();
    151         setup_widget_prototype(gParts->toggleButtonWidget);
    152         /* toggle button must be set active to get the right style on hover. */
    153         GTK_TOGGLE_BUTTON(gParts->toggleButtonWidget)->active = TRUE;
    154   }
    155   return MOZ_GTK_SUCCESS;
    156 }
    157 
    158 static gint
    159 ensure_button_arrow_widget()
    160 {
    161     if (!gParts->buttonArrowWidget) {
    162         ensure_toggle_button_widget();
    163 
    164         gParts->buttonArrowWidget = gtk_arrow_new(GTK_ARROW_DOWN, GTK_SHADOW_OUT);
    165         gtk_container_add(GTK_CONTAINER(gParts->toggleButtonWidget), gParts->buttonArrowWidget);
    166         gtk_widget_realize(gParts->buttonArrowWidget);
    167     }
    168     return MOZ_GTK_SUCCESS;
    169 }
    170 
    171 static gint
    172 ensure_checkbox_widget()
    173 {
    174     if (!gParts->checkboxWidget) {
    175         gParts->checkboxWidget = gtk_check_button_new_with_label("M");
    176         setup_widget_prototype(gParts->checkboxWidget);
    177     }
    178     return MOZ_GTK_SUCCESS;
    179 }
    180 
    181 static gint
    182 ensure_radiobutton_widget()
    183 {
    184     if (!gParts->radiobuttonWidget) {
    185         gParts->radiobuttonWidget = gtk_radio_button_new_with_label(NULL, "M");
    186         setup_widget_prototype(gParts->radiobuttonWidget);
    187     }
    188     return MOZ_GTK_SUCCESS;
    189 }
    190 
    191 static gint
    192 ensure_scrollbar_widget()
    193 {
    194     if (!gParts->vertScrollbarWidget) {
    195         gParts->vertScrollbarWidget = gtk_vscrollbar_new(NULL);
    196         setup_widget_prototype(gParts->vertScrollbarWidget);
    197     }
    198     if (!gParts->horizScrollbarWidget) {
    199         gParts->horizScrollbarWidget = gtk_hscrollbar_new(NULL);
    200         setup_widget_prototype(gParts->horizScrollbarWidget);
    201     }
    202     return MOZ_GTK_SUCCESS;
    203 }
    204 
    205 static gint
    206 ensure_spin_widget()
    207 {
    208   if (!gParts->spinWidget) {
    209     gParts->spinWidget = gtk_spin_button_new(NULL, 1, 0);
    210     setup_widget_prototype(gParts->spinWidget);
    211   }
    212   return MOZ_GTK_SUCCESS;
    213 }
    214 
    215 static gint
    216 ensure_scale_widget()
    217 {
    218   if (!gParts->hScaleWidget) {
    219     gParts->hScaleWidget = gtk_hscale_new(NULL);
    220     setup_widget_prototype(gParts->hScaleWidget);
    221   }
    222   if (!gParts->vScaleWidget) {
    223     gParts->vScaleWidget = gtk_vscale_new(NULL);
    224     setup_widget_prototype(gParts->vScaleWidget);
    225   }
    226   return MOZ_GTK_SUCCESS;
    227 }
    228 
    229 static gint
    230 ensure_entry_widget()
    231 {
    232     if (!gParts->entryWidget) {
    233         gParts->entryWidget = gtk_entry_new();
    234         setup_widget_prototype(gParts->entryWidget);
    235     }
    236     return MOZ_GTK_SUCCESS;
    237 }
    238 
    239 /* We need to have pointers to the inner widgets (button, separator, arrow)
    240  * of the ComboBox to get the correct rendering from theme engines which
    241  * special cases their look. Since the inner layout can change, we ask GTK
    242  * to NULL our pointers when they are about to become invalid because the
    243  * corresponding widgets don't exist anymore. It's the role of
    244  * g_object_add_weak_pointer().
    245  * Note that if we don't find the inner widgets (which shouldn't happen), we
    246  * fallback to use generic "non-inner" widgets, and they don't need that kind
    247  * of weak pointer since they are explicit children of gParts->protoWindow and as
    248  * such GTK holds a strong reference to them. */
    249 static void
    250 moz_gtk_get_combo_box_inner_button(GtkWidget *widget, gpointer client_data)
    251 {
    252     if (GTK_IS_TOGGLE_BUTTON(widget)) {
    253         gParts->comboBoxButtonWidget = widget;
    254         g_object_add_weak_pointer(G_OBJECT(widget),
    255                                   (gpointer) &gParts->comboBoxButtonWidget);
    256         gtk_widget_realize(widget);
    257         g_object_set_data(G_OBJECT(widget), "transparent-bg-hint", GINT_TO_POINTER(TRUE));
    258     }
    259 }
    260 
    261 static void
    262 moz_gtk_get_combo_box_button_inner_widgets(GtkWidget *widget,
    263                                            gpointer client_data)
    264 {
    265     if (GTK_IS_SEPARATOR(widget)) {
    266         gParts->comboBoxSeparatorWidget = widget;
    267         g_object_add_weak_pointer(G_OBJECT(widget),
    268                                   (gpointer) &gParts->comboBoxSeparatorWidget);
    269     } else if (GTK_IS_ARROW(widget)) {
    270         gParts->comboBoxArrowWidget = widget;
    271         g_object_add_weak_pointer(G_OBJECT(widget),
    272                                   (gpointer) &gParts->comboBoxArrowWidget);
    273     } else
    274         return;
    275     gtk_widget_realize(widget);
    276     g_object_set_data(G_OBJECT(widget), "transparent-bg-hint", GINT_TO_POINTER(TRUE));
    277 }
    278 
    279 static gint
    280 ensure_combo_box_widgets()
    281 {
    282     GtkWidget* buttonChild;
    283 
    284     if (gParts->comboBoxButtonWidget && gParts->comboBoxArrowWidget)
    285         return MOZ_GTK_SUCCESS;
    286 
    287     /* Create a ComboBox if needed */
    288     if (!gParts->comboBoxWidget) {
    289         gParts->comboBoxWidget = gtk_combo_box_new();
    290         setup_widget_prototype(gParts->comboBoxWidget);
    291     }
    292 
    293     /* Get its inner Button */
    294     gtk_container_forall(GTK_CONTAINER(gParts->comboBoxWidget),
    295                          moz_gtk_get_combo_box_inner_button,
    296                          NULL);
    297 
    298     if (gParts->comboBoxButtonWidget) {
    299         /* Get the widgets inside the Button */
    300         buttonChild = GTK_BIN(gParts->comboBoxButtonWidget)->child;
    301         if (GTK_IS_HBOX(buttonChild)) {
    302             /* appears-as-list = FALSE, cell-view = TRUE; the button
    303              * contains an hbox. This hbox is there because the ComboBox
    304              * needs to place a cell renderer, a separator, and an arrow in
    305              * the button when appears-as-list is FALSE. */
    306             gtk_container_forall(GTK_CONTAINER(buttonChild),
    307                                  moz_gtk_get_combo_box_button_inner_widgets,
    308                                  NULL);
    309         } else if(GTK_IS_ARROW(buttonChild)) {
    310             /* appears-as-list = TRUE, or cell-view = FALSE;
    311              * the button only contains an arrow */
    312             gParts->comboBoxArrowWidget = buttonChild;
    313             g_object_add_weak_pointer(G_OBJECT(buttonChild), (gpointer)
    314                                       &gParts->comboBoxArrowWidget);
    315             gtk_widget_realize(gParts->comboBoxArrowWidget);
    316             g_object_set_data(G_OBJECT(gParts->comboBoxArrowWidget),
    317                               "transparent-bg-hint", GINT_TO_POINTER(TRUE));
    318         }
    319     } else {
    320         /* Shouldn't be reached with current internal gtk implementation; we
    321          * use a generic toggle button as last resort fallback to avoid
    322          * crashing. */
    323         ensure_toggle_button_widget();
    324         gParts->comboBoxButtonWidget = gParts->toggleButtonWidget;
    325     }
    326 
    327     if (!gParts->comboBoxArrowWidget) {
    328         /* Shouldn't be reached with current internal gtk implementation;
    329          * we gParts->buttonArrowWidget as last resort fallback to avoid
    330          * crashing. */
    331         ensure_button_arrow_widget();
    332         gParts->comboBoxArrowWidget = gParts->buttonArrowWidget;
    333     }
    334 
    335     /* We don't test the validity of gParts->comboBoxSeparatorWidget since there
    336      * is none when "appears-as-list" = TRUE or "cell-view" = FALSE; if it
    337      * is invalid we just won't paint it. */
    338 
    339     return MOZ_GTK_SUCCESS;
    340 }
    341 
    342 /* We need to have pointers to the inner widgets (entry, button, arrow) of
    343  * the ComboBoxEntry to get the correct rendering from theme engines which
    344  * special cases their look. Since the inner layout can change, we ask GTK
    345  * to NULL our pointers when they are about to become invalid because the
    346  * corresponding widgets don't exist anymore. It's the role of
    347  * g_object_add_weak_pointer().
    348  * Note that if we don't find the inner widgets (which shouldn't happen), we
    349  * fallback to use generic "non-inner" widgets, and they don't need that kind
    350  * of weak pointer since they are explicit children of gParts->protoWindow and as
    351  * such GTK holds a strong reference to them. */
    352 static void
    353 moz_gtk_get_combo_box_entry_inner_widgets(GtkWidget *widget,
    354                                           gpointer client_data)
    355 {
    356     if (GTK_IS_TOGGLE_BUTTON(widget)) {
    357         gParts->comboBoxEntryButtonWidget = widget;
    358         g_object_add_weak_pointer(G_OBJECT(widget),
    359                                   (gpointer) &gParts->comboBoxEntryButtonWidget);
    360     } else if (GTK_IS_ENTRY(widget)) {
    361         gParts->comboBoxEntryTextareaWidget = widget;
    362         g_object_add_weak_pointer(G_OBJECT(widget),
    363                                   (gpointer) &gParts->comboBoxEntryTextareaWidget);
    364     } else
    365         return;
    366     gtk_widget_realize(widget);
    367     g_object_set_data(G_OBJECT(widget), "transparent-bg-hint", GINT_TO_POINTER(TRUE));
    368 }
    369 
    370 static void
    371 moz_gtk_get_combo_box_entry_arrow(GtkWidget *widget, gpointer client_data)
    372 {
    373     if (GTK_IS_ARROW(widget)) {
    374         gParts->comboBoxEntryArrowWidget = widget;
    375         g_object_add_weak_pointer(G_OBJECT(widget),
    376                                   (gpointer) &gParts->comboBoxEntryArrowWidget);
    377         gtk_widget_realize(widget);
    378         g_object_set_data(G_OBJECT(widget), "transparent-bg-hint", GINT_TO_POINTER(TRUE));
    379     }
    380 }
    381 
    382 static gint
    383 ensure_combo_box_entry_widgets()
    384 {
    385     GtkWidget* buttonChild;
    386 
    387     if (gParts->comboBoxEntryTextareaWidget &&
    388             gParts->comboBoxEntryButtonWidget &&
    389             gParts->comboBoxEntryArrowWidget)
    390         return MOZ_GTK_SUCCESS;
    391 
    392     /* Create a ComboBoxEntry if needed */
    393     if (!gParts->comboBoxEntryWidget) {
    394         gParts->comboBoxEntryWidget = gtk_combo_box_entry_new();
    395         setup_widget_prototype(gParts->comboBoxEntryWidget);
    396     }
    397 
    398     /* Get its inner Entry and Button */
    399     gtk_container_forall(GTK_CONTAINER(gParts->comboBoxEntryWidget),
    400                          moz_gtk_get_combo_box_entry_inner_widgets,
    401                          NULL);
    402 
    403     if (!gParts->comboBoxEntryTextareaWidget) {
    404         ensure_entry_widget();
    405         gParts->comboBoxEntryTextareaWidget = gParts->entryWidget;
    406     }
    407 
    408     if (gParts->comboBoxEntryButtonWidget) {
    409         /* Get the Arrow inside the Button */
    410         buttonChild = GTK_BIN(gParts->comboBoxEntryButtonWidget)->child;
    411         if (GTK_IS_HBOX(buttonChild)) {
    412             /* appears-as-list = FALSE, cell-view = TRUE; the button
    413              * contains an hbox. This hbox is there because ComboBoxEntry
    414              * inherits from ComboBox which needs to place a cell renderer,
    415              * a separator, and an arrow in the button when appears-as-list
    416              * is FALSE. Here the hbox should only contain an arrow, since
    417              * a ComboBoxEntry doesn't need all those widgets in the
    418              * button. */
    419             gtk_container_forall(GTK_CONTAINER(buttonChild),
    420                                  moz_gtk_get_combo_box_entry_arrow,
    421                                  NULL);
    422         } else if(GTK_IS_ARROW(buttonChild)) {
    423             /* appears-as-list = TRUE, or cell-view = FALSE;
    424              * the button only contains an arrow */
    425             gParts->comboBoxEntryArrowWidget = buttonChild;
    426             g_object_add_weak_pointer(G_OBJECT(buttonChild), (gpointer)
    427                                       &gParts->comboBoxEntryArrowWidget);
    428             gtk_widget_realize(gParts->comboBoxEntryArrowWidget);
    429             g_object_set_data(G_OBJECT(gParts->comboBoxEntryArrowWidget),
    430                               "transparent-bg-hint", GINT_TO_POINTER(TRUE));
    431         }
    432     } else {
    433         /* Shouldn't be reached with current internal gtk implementation;
    434          * we use a generic toggle button as last resort fallback to avoid
    435          * crashing. */
    436         ensure_toggle_button_widget();
    437         gParts->comboBoxEntryButtonWidget = gParts->toggleButtonWidget;
    438     }
    439 
    440     if (!gParts->comboBoxEntryArrowWidget) {
    441         /* Shouldn't be reached with current internal gtk implementation;
    442          * we gParts->buttonArrowWidget as last resort fallback to avoid
    443          * crashing. */
    444         ensure_button_arrow_widget();
    445         gParts->comboBoxEntryArrowWidget = gParts->buttonArrowWidget;
    446     }
    447 
    448     return MOZ_GTK_SUCCESS;
    449 }
    450 
    451 
    452 static gint
    453 ensure_handlebox_widget()
    454 {
    455     if (!gParts->handleBoxWidget) {
    456         gParts->handleBoxWidget = gtk_handle_box_new();
    457         setup_widget_prototype(gParts->handleBoxWidget);
    458     }
    459     return MOZ_GTK_SUCCESS;
    460 }
    461 
    462 static gint
    463 ensure_toolbar_widget()
    464 {
    465     if (!gParts->toolbarWidget) {
    466         ensure_handlebox_widget();
    467         gParts->toolbarWidget = gtk_toolbar_new();
    468         gtk_container_add(GTK_CONTAINER(gParts->handleBoxWidget), gParts->toolbarWidget);
    469         gtk_widget_realize(gParts->toolbarWidget);
    470         g_object_set_data(G_OBJECT(gParts->toolbarWidget), "transparent-bg-hint", GINT_TO_POINTER(TRUE));
    471     }
    472     return MOZ_GTK_SUCCESS;
    473 }
    474 
    475 static gint
    476 ensure_toolbar_separator_widget()
    477 {
    478     if (!gParts->toolbarSeparatorWidget) {
    479         ensure_toolbar_widget();
    480         gParts->toolbarSeparatorWidget = GTK_WIDGET(gtk_separator_tool_item_new());
    481         setup_widget_prototype(gParts->toolbarSeparatorWidget);
    482     }
    483     return MOZ_GTK_SUCCESS;
    484 }
    485 
    486 static gint
    487 ensure_tooltip_widget()
    488 {
    489     if (!gParts->tooltipWidget) {
    490         gParts->tooltipWidget = gtk_window_new(GTK_WINDOW_POPUP);
    491         gtk_widget_realize(gParts->tooltipWidget);
    492         moz_gtk_set_widget_name(gParts->tooltipWidget);
    493     }
    494     return MOZ_GTK_SUCCESS;
    495 }
    496 
    497 static gint
    498 ensure_tab_widget()
    499 {
    500     if (!gParts->tabWidget) {
    501         gParts->tabWidget = gtk_notebook_new();
    502         setup_widget_prototype(gParts->tabWidget);
    503     }
    504     return MOZ_GTK_SUCCESS;
    505 }
    506 
    507 static gint
    508 ensure_progress_widget()
    509 {
    510     if (!gParts->progresWidget) {
    511         gParts->progresWidget = gtk_progress_bar_new();
    512         setup_widget_prototype(gParts->progresWidget);
    513     }
    514     return MOZ_GTK_SUCCESS;
    515 }
    516 
    517 static gint
    518 ensure_statusbar_widget()
    519 {
    520     if (!gParts->statusbarWidget) {
    521       gParts->statusbarWidget = gtk_statusbar_new();
    522       setup_widget_prototype(gParts->statusbarWidget);
    523     }
    524     return MOZ_GTK_SUCCESS;
    525 }
    526 
    527 static gint
    528 ensure_frame_widget()
    529 {
    530     if (!gParts->frameWidget) {
    531         ensure_statusbar_widget();
    532         gParts->frameWidget = gtk_frame_new(NULL);
    533         gtk_container_add(GTK_CONTAINER(gParts->statusbarWidget), gParts->frameWidget);
    534         gtk_widget_realize(gParts->frameWidget);
    535     }
    536     return MOZ_GTK_SUCCESS;
    537 }
    538 
    539 static gint
    540 ensure_menu_bar_widget()
    541 {
    542     if (!gParts->menuBarWidget) {
    543         gParts->menuBarWidget = gtk_menu_bar_new();
    544         setup_widget_prototype(gParts->menuBarWidget);
    545     }
    546     return MOZ_GTK_SUCCESS;
    547 }
    548 
    549 static gint
    550 ensure_menu_bar_item_widget()
    551 {
    552     if (!gParts->menuBarItemWidget) {
    553         ensure_menu_bar_widget();
    554         gParts->menuBarItemWidget = gtk_menu_item_new();
    555         gtk_menu_shell_append(GTK_MENU_SHELL(gParts->menuBarWidget),
    556                               gParts->menuBarItemWidget);
    557         gtk_widget_realize(gParts->menuBarItemWidget);
    558         g_object_set_data(G_OBJECT(gParts->menuBarItemWidget),
    559                           "transparent-bg-hint", GINT_TO_POINTER(TRUE));
    560     }
    561     return MOZ_GTK_SUCCESS;
    562 }
    563 
    564 static gint
    565 ensure_menu_popup_widget()
    566 {
    567     if (!gParts->menuPopupWidget) {
    568         ensure_menu_bar_item_widget();
    569         gParts->menuPopupWidget = gtk_menu_new();
    570         gtk_menu_item_set_submenu(GTK_MENU_ITEM(gParts->menuBarItemWidget),
    571                                   gParts->menuPopupWidget);
    572         gtk_widget_realize(gParts->menuPopupWidget);
    573         g_object_set_data(G_OBJECT(gParts->menuPopupWidget),
    574                           "transparent-bg-hint", GINT_TO_POINTER(TRUE));
    575     }
    576     return MOZ_GTK_SUCCESS;
    577 }
    578 
    579 static gint
    580 ensure_menu_item_widget()
    581 {
    582     if (!gParts->menuItemWidget) {
    583         ensure_menu_popup_widget();
    584         gParts->menuItemWidget = gtk_menu_item_new_with_label("M");
    585         gtk_menu_shell_append(GTK_MENU_SHELL(gParts->menuPopupWidget),
    586                               gParts->menuItemWidget);
    587         gtk_widget_realize(gParts->menuItemWidget);
    588         g_object_set_data(G_OBJECT(gParts->menuItemWidget),
    589                           "transparent-bg-hint", GINT_TO_POINTER(TRUE));
    590     }
    591     return MOZ_GTK_SUCCESS;
    592 }
    593 
    594 static gint
    595 ensure_image_menu_item_widget()
    596 {
    597     if (!gParts->imageMenuItemWidget) {
    598         ensure_menu_popup_widget();
    599         gParts->imageMenuItemWidget = gtk_image_menu_item_new();
    600         gtk_menu_shell_append(GTK_MENU_SHELL(gParts->menuPopupWidget),
    601                               gParts->imageMenuItemWidget);
    602         gtk_widget_realize(gParts->imageMenuItemWidget);
    603         g_object_set_data(G_OBJECT(gParts->imageMenuItemWidget),
    604                           "transparent-bg-hint", GINT_TO_POINTER(TRUE));
    605     }
    606     return MOZ_GTK_SUCCESS;
    607 }
    608 
    609 static gint
    610 ensure_menu_separator_widget()
    611 {
    612     if (!gParts->menuSeparatorWidget) {
    613         ensure_menu_popup_widget();
    614         gParts->menuSeparatorWidget = gtk_separator_menu_item_new();
    615         gtk_menu_shell_append(GTK_MENU_SHELL(gParts->menuPopupWidget),
    616                               gParts->menuSeparatorWidget);
    617         gtk_widget_realize(gParts->menuSeparatorWidget);
    618         g_object_set_data(G_OBJECT(gParts->menuSeparatorWidget),
    619                           "transparent-bg-hint", GINT_TO_POINTER(TRUE));
    620     }
    621     return MOZ_GTK_SUCCESS;
    622 }
    623 
    624 static gint
    625 ensure_check_menu_item_widget()
    626 {
    627     if (!gParts->checkMenuItemWidget) {
    628         ensure_menu_popup_widget();
    629         gParts->checkMenuItemWidget = gtk_check_menu_item_new_with_label("M");
    630         gtk_menu_shell_append(GTK_MENU_SHELL(gParts->menuPopupWidget),
    631                               gParts->checkMenuItemWidget);
    632         gtk_widget_realize(gParts->checkMenuItemWidget);
    633         g_object_set_data(G_OBJECT(gParts->checkMenuItemWidget),
    634                           "transparent-bg-hint", GINT_TO_POINTER(TRUE));
    635     }
    636     return MOZ_GTK_SUCCESS;
    637 }
    638 
    639 static gint
    640 ensure_tree_view_widget()
    641 {
    642     if (!gParts->treeViewWidget) {
    643         gParts->treeViewWidget = gtk_tree_view_new();
    644         setup_widget_prototype(gParts->treeViewWidget);
    645     }
    646     return MOZ_GTK_SUCCESS;
    647 }
    648 
    649 static gint
    650 ensure_tree_header_cell_widget()
    651 {
    652     if(!gParts->treeHeaderCellWidget) {
    653         /*
    654          * Some GTK engines paint the first and last cell
    655          * of a TreeView header with a highlight.
    656          * Since we do not know where our widget will be relative
    657          * to the other buttons in the TreeView header, we must
    658          * paint it as a button that is between two others,
    659          * thus ensuring it is neither the first or last button
    660          * in the header.
    661          * GTK doesn't give us a way to do this explicitly,
    662          * so we must paint with a button that is between two
    663          * others.
    664          */
    665 
    666         GtkTreeViewColumn* firstTreeViewColumn;
    667         GtkTreeViewColumn* lastTreeViewColumn;
    668 
    669         ensure_tree_view_widget();
    670 
    671         /* Create and append our three columns */
    672         firstTreeViewColumn = gtk_tree_view_column_new();
    673         gtk_tree_view_column_set_title(firstTreeViewColumn, "M");
    674         gtk_tree_view_append_column(GTK_TREE_VIEW(gParts->treeViewWidget), firstTreeViewColumn);
    675 
    676         gParts->middleTreeViewColumn = gtk_tree_view_column_new();
    677         gtk_tree_view_column_set_title(gParts->middleTreeViewColumn, "M");
    678         gtk_tree_view_append_column(GTK_TREE_VIEW(gParts->treeViewWidget),
    679                                     gParts->middleTreeViewColumn);
    680 
    681         lastTreeViewColumn = gtk_tree_view_column_new();
    682         gtk_tree_view_column_set_title(lastTreeViewColumn, "M");
    683         gtk_tree_view_append_column(GTK_TREE_VIEW(gParts->treeViewWidget), lastTreeViewColumn);
    684 
    685         /* Use the middle column's header for our button */
    686         gParts->treeHeaderCellWidget = gParts->middleTreeViewColumn->button;
    687         gParts->treeHeaderSortArrowWidget = gParts->middleTreeViewColumn->arrow;
    688         g_object_set_data(G_OBJECT(gParts->treeHeaderCellWidget),
    689                           "transparent-bg-hint", GINT_TO_POINTER(TRUE));
    690         g_object_set_data(G_OBJECT(gParts->treeHeaderSortArrowWidget),
    691                           "transparent-bg-hint", GINT_TO_POINTER(TRUE));
    692     }
    693     return MOZ_GTK_SUCCESS;
    694 }
    695 
    696 static gint
    697 ensure_expander_widget()
    698 {
    699     if (!gParts->expanderWidget) {
    700         gParts->expanderWidget = gtk_expander_new("M");
    701         setup_widget_prototype(gParts->expanderWidget);
    702     }
    703     return MOZ_GTK_SUCCESS;
    704 }
    705 
    706 static gint
    707 ensure_scrolled_window_widget()
    708 {
    709     if (!gParts->scrolledWindowWidget) {
    710         gParts->scrolledWindowWidget = gtk_scrolled_window_new(NULL, NULL);
    711         setup_widget_prototype(gParts->scrolledWindowWidget);
    712     }
    713     return MOZ_GTK_SUCCESS;
    714 }
    715 
    716 static GtkStateType
    717 ConvertGtkState(GtkWidgetState* state)
    718 {
    719     if (state->disabled)
    720         return GTK_STATE_INSENSITIVE;
    721     else if (state->depressed)
    722         return (state->inHover ? GTK_STATE_PRELIGHT : GTK_STATE_ACTIVE);
    723     else if (state->inHover)
    724         return (state->active ? GTK_STATE_ACTIVE : GTK_STATE_PRELIGHT);
    725     else
    726         return GTK_STATE_NORMAL;
    727 }
    728 
    729 static gint
    730 TSOffsetStyleGCArray(GdkGC** gcs, gint xorigin, gint yorigin)
    731 {
    732     int i;
    733     /* there are 5 gc's in each array, for each of the widget states */
    734     for (i = 0; i < 5; ++i)
    735         gdk_gc_set_ts_origin(gcs[i], xorigin, yorigin);
    736     return MOZ_GTK_SUCCESS;
    737 }
    738 
    739 static gint
    740 TSOffsetStyleGCs(GtkStyle* style, gint xorigin, gint yorigin)
    741 {
    742     TSOffsetStyleGCArray(style->fg_gc, xorigin, yorigin);
    743     TSOffsetStyleGCArray(style->bg_gc, xorigin, yorigin);
    744     TSOffsetStyleGCArray(style->light_gc, xorigin, yorigin);
    745     TSOffsetStyleGCArray(style->dark_gc, xorigin, yorigin);
    746     TSOffsetStyleGCArray(style->mid_gc, xorigin, yorigin);
    747     TSOffsetStyleGCArray(style->text_gc, xorigin, yorigin);
    748     TSOffsetStyleGCArray(style->base_gc, xorigin, yorigin);
    749     gdk_gc_set_ts_origin(style->black_gc, xorigin, yorigin);
    750     gdk_gc_set_ts_origin(style->white_gc, xorigin, yorigin);
    751     return MOZ_GTK_SUCCESS;
    752 }
    753 
    754 static gint
    755 moz_gtk_button_paint(GdkDrawable* drawable, GdkRectangle* rect,
    756                      GdkRectangle* cliprect, GtkWidgetState* state,
    757                      GtkReliefStyle relief, GtkWidget* widget,
    758                      GtkTextDirection direction)
    759 {
    760     GtkShadowType shadow_type;
    761     GtkStyle* style = widget->style;
    762     GtkStateType button_state = ConvertGtkState(state);
    763     gint x = rect->x, y=rect->y, width=rect->width, height=rect->height;
    764 
    765     gboolean interior_focus;
    766     gint focus_width, focus_pad;
    767 
    768     moz_gtk_widget_get_focus(widget, &interior_focus, &focus_width, &focus_pad);
    769 
    770     if (WINDOW_IS_MAPPED(drawable)) {
    771         gdk_window_set_back_pixmap(drawable, NULL, TRUE);
    772         gdk_window_clear_area(drawable, cliprect->x, cliprect->y,
    773                               cliprect->width, cliprect->height);
    774     }
    775 
    776     gtk_widget_set_state(widget, button_state);
    777     gtk_widget_set_direction(widget, direction);
    778 
    779     if (state->isDefault)
    780         GTK_WIDGET_SET_FLAGS(widget, GTK_HAS_DEFAULT);
    781 
    782     GTK_BUTTON(widget)->relief = relief;
    783 
    784     /* Some theme engines love to cause us pain in that gtk_paint_focus is a
    785        no-op on buttons and button-like widgets. They only listen to this flag. */
    786     if (state->focused && !state->disabled)
    787         GTK_WIDGET_SET_FLAGS(widget, GTK_HAS_FOCUS);
    788 
    789     if (!interior_focus && state->focused) {
    790         x += focus_width + focus_pad;
    791         y += focus_width + focus_pad;
    792         width -= 2 * (focus_width + focus_pad);
    793         height -= 2 * (focus_width + focus_pad);
    794     }
    795 
    796     shadow_type = button_state == GTK_STATE_ACTIVE ||
    797                       state->depressed ? GTK_SHADOW_IN : GTK_SHADOW_OUT;
    798 
    799     if (state->isDefault && relief == GTK_RELIEF_NORMAL) {
    800         gtk_paint_box(style, drawable, button_state, shadow_type, cliprect,
    801                       widget, "buttondefault", x, y, width, height);
    802     }
    803 
    804     if (relief != GTK_RELIEF_NONE || state->depressed ||
    805            (button_state != GTK_STATE_NORMAL &&
    806             button_state != GTK_STATE_INSENSITIVE)) {
    807         TSOffsetStyleGCs(style, x, y);
    808         /* the following line can trigger an assertion (Crux theme)
    809            file ../../gdk/gdkwindow.c: line 1846 (gdk_window_clear_area):
    810            assertion `GDK_IS_WINDOW (window)' failed */
    811         gtk_paint_box(style, drawable, button_state, shadow_type, cliprect,
    812                       widget, "button", x, y, width, height);
    813     }
    814 
    815     if (state->focused) {
    816         if (interior_focus) {
    817             x += widget->style->xthickness + focus_pad;
    818             y += widget->style->ythickness + focus_pad;
    819             width -= 2 * (widget->style->xthickness + focus_pad);
    820             height -= 2 * (widget->style->ythickness + focus_pad);
    821         } else {
    822             x -= focus_width + focus_pad;
    823             y -= focus_width + focus_pad;
    824             width += 2 * (focus_width + focus_pad);
    825             height += 2 * (focus_width + focus_pad);
    826         }
    827 
    828         TSOffsetStyleGCs(style, x, y);
    829         gtk_paint_focus(style, drawable, button_state, cliprect,
    830                         widget, "button", x, y, width, height);
    831     }
    832 
    833     GTK_WIDGET_UNSET_FLAGS(widget, GTK_HAS_DEFAULT);
    834     GTK_WIDGET_UNSET_FLAGS(widget, GTK_HAS_FOCUS);
    835     return MOZ_GTK_SUCCESS;
    836 }
    837 
    838 gint
    839 moz_gtk_init()
    840 {
    841     GtkWidgetClass *entry_class;
    842 
    843     is_initialized = TRUE;
    844     have_arrow_scaling = (gtk_major_version > 2 ||
    845                           (gtk_major_version == 2 && gtk_minor_version >= 12));
    846 
    847     /* Add style property to GtkEntry.
    848      * Adding the style property to the normal GtkEntry class means that it
    849      * will work without issues inside GtkComboBox and for Spinbuttons. */
    850     entry_class = g_type_class_ref(GTK_TYPE_ENTRY);
    851     gtk_widget_class_install_style_property(entry_class,
    852         g_param_spec_boolean("honors-transparent-bg-hint",
    853                              "Transparent BG enabling flag",
    854                              "If TRUE, the theme is able to draw the GtkEntry on non-prefilled background.",
    855                              FALSE,
    856                              G_PARAM_READWRITE));
    857 
    858     return MOZ_GTK_SUCCESS;
    859 }
    860 
    861 gint
    862 moz_gtk_checkbox_get_metrics(gint* indicator_size, gint* indicator_spacing)
    863 {
    864     ensure_checkbox_widget();
    865 
    866     gtk_widget_style_get (gParts->checkboxWidget,
    867                           "indicator_size", indicator_size,
    868                           "indicator_spacing", indicator_spacing,
    869                           NULL);
    870 
    871     return MOZ_GTK_SUCCESS;
    872 }
    873 
    874 gint
    875 moz_gtk_radio_get_metrics(gint* indicator_size, gint* indicator_spacing)
    876 {
    877     ensure_radiobutton_widget();
    878 
    879     gtk_widget_style_get (gParts->radiobuttonWidget,
    880                           "indicator_size", indicator_size,
    881                           "indicator_spacing", indicator_spacing,
    882                           NULL);
    883 
    884     return MOZ_GTK_SUCCESS;
    885 }
    886 
    887 gint
    888 moz_gtk_widget_get_focus(GtkWidget* widget, gboolean* interior_focus,
    889                          gint* focus_width, gint* focus_pad)
    890 {
    891     gtk_widget_style_get (widget,
    892                           "interior-focus", interior_focus,
    893                           "focus-line-width", focus_width,
    894                           "focus-padding", focus_pad,
    895                           NULL);
    896 
    897     return MOZ_GTK_SUCCESS;
    898 }
    899 
    900 gint
    901 moz_gtk_splitter_get_metrics(gint orientation, gint* size)
    902 {
    903     if (orientation == GTK_ORIENTATION_HORIZONTAL) {
    904         ensure_hpaned_widget();
    905         gtk_widget_style_get(gParts->hpanedWidget, "handle_size", size, NULL);
    906     } else {
    907         ensure_vpaned_widget();
    908         gtk_widget_style_get(gParts->vpanedWidget, "handle_size", size, NULL);
    909     }
    910     return MOZ_GTK_SUCCESS;
    911 }
    912 
    913 gint
    914 moz_gtk_button_get_inner_border(GtkWidget* widget, GtkBorder* inner_border)
    915 {
    916     static const GtkBorder default_inner_border = { 1, 1, 1, 1 };
    917     GtkBorder *tmp_border;
    918 
    919     gtk_widget_style_get (widget, "inner-border", &tmp_border, NULL);
    920 
    921     if (tmp_border) {
    922         *inner_border = *tmp_border;
    923         gtk_border_free(tmp_border);
    924     }
    925     else
    926         *inner_border = default_inner_border;
    927 
    928     return MOZ_GTK_SUCCESS;
    929 }
    930 
    931 static gint
    932 moz_gtk_toggle_paint(GdkDrawable* drawable, GdkRectangle* rect,
    933                      GdkRectangle* cliprect, GtkWidgetState* state,
    934                      gboolean selected, gboolean inconsistent,
    935                      gboolean isradio, GtkTextDirection direction)
    936 {
    937     GtkStateType state_type = ConvertGtkState(state);
    938     GtkShadowType shadow_type = (selected)?GTK_SHADOW_IN:GTK_SHADOW_OUT;
    939     gint indicator_size, indicator_spacing;
    940     gint x, y, width, height;
    941     gint focus_x, focus_y, focus_width, focus_height;
    942     GtkWidget *w;
    943     GtkStyle *style;
    944 
    945     if (isradio) {
    946         moz_gtk_radio_get_metrics(&indicator_size, &indicator_spacing);
    947         w = gParts->radiobuttonWidget;
    948     } else {
    949         moz_gtk_checkbox_get_metrics(&indicator_size, &indicator_spacing);
    950         w = gParts->checkboxWidget;
    951     }
    952 
    953     // "GetMinimumWidgetSize was ignored"
    954     // FIXME: This assert causes a build failure in WebKitGTK+ debug
    955     // builds, because it uses 'false' in its definition. We may want
    956     // to force this file to be built with g++, by renaming it.
    957     // ASSERT(rect->width == indicator_size);
    958 
    959     /*
    960      * vertically center in the box, since XUL sometimes ignores our
    961      * GetMinimumWidgetSize in the vertical dimension
    962      */
    963     x = rect->x;
    964     y = rect->y + (rect->height - indicator_size) / 2;
    965     width = indicator_size;
    966     height = indicator_size;
    967 
    968     focus_x = x - indicator_spacing;
    969     focus_y = y - indicator_spacing;
    970     focus_width = width + 2 * indicator_spacing;
    971     focus_height = height + 2 * indicator_spacing;
    972 
    973     style = w->style;
    974     TSOffsetStyleGCs(style, x, y);
    975 
    976     gtk_widget_set_sensitive(w, !state->disabled);
    977     gtk_widget_set_direction(w, direction);
    978     GTK_TOGGLE_BUTTON(w)->active = selected;
    979 
    980     if (isradio) {
    981         gtk_paint_option(style, drawable, state_type, shadow_type, cliprect,
    982                          gParts->radiobuttonWidget, "radiobutton", x, y,
    983                          width, height);
    984         if (state->focused) {
    985             gtk_paint_focus(style, drawable, GTK_STATE_ACTIVE, cliprect,
    986                             gParts->radiobuttonWidget, "radiobutton", 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         if (inconsistent) {
    996             gtk_toggle_button_set_inconsistent(GTK_TOGGLE_BUTTON(gParts->checkboxWidget), TRUE);
    997             shadow_type = GTK_SHADOW_ETCHED_IN;
    998         } else {
    999             gtk_toggle_button_set_inconsistent(GTK_TOGGLE_BUTTON(gParts->checkboxWidget), FALSE);
   1000         }
   1001 
   1002         gtk_paint_check(style, drawable, state_type, shadow_type, cliprect,
   1003                         gParts->checkboxWidget, "checkbutton", x, y, width, height);
   1004         if (state->focused) {
   1005             gtk_paint_focus(style, drawable, GTK_STATE_ACTIVE, cliprect,
   1006                             gParts->checkboxWidget, "checkbutton", focus_x, focus_y,
   1007                             focus_width, focus_height);
   1008         }
   1009     }
   1010 
   1011     return MOZ_GTK_SUCCESS;
   1012 }
   1013 
   1014 static gint
   1015 calculate_button_inner_rect(GtkWidget* button, GdkRectangle* rect,
   1016                             GdkRectangle* inner_rect,
   1017                             GtkTextDirection direction,
   1018                             gboolean ignore_focus)
   1019 {
   1020     GtkBorder inner_border;
   1021     gboolean interior_focus;
   1022     gint focus_width, focus_pad;
   1023     GtkStyle* style;
   1024 
   1025     style = button->style;
   1026 
   1027     /* This mirrors gtkbutton's child positioning */
   1028     moz_gtk_button_get_inner_border(button, &inner_border);
   1029     moz_gtk_widget_get_focus(button, &interior_focus,
   1030                              &focus_width, &focus_pad);
   1031 
   1032     if (ignore_focus)
   1033         focus_width = focus_pad = 0;
   1034 
   1035     inner_rect->x = rect->x + XTHICKNESS(style) + focus_width + focus_pad;
   1036     inner_rect->x += direction == GTK_TEXT_DIR_LTR ?
   1037                         inner_border.left : inner_border.right;
   1038     inner_rect->y = rect->y + inner_border.top + YTHICKNESS(style) +
   1039                     focus_width + focus_pad;
   1040     inner_rect->width = MAX(1, rect->width - inner_border.left -
   1041        inner_border.right - (XTHICKNESS(style) + focus_pad + focus_width) * 2);
   1042     inner_rect->height = MAX(1, rect->height - inner_border.top -
   1043        inner_border.bottom - (YTHICKNESS(style) + focus_pad + focus_width) * 2);
   1044 
   1045     return MOZ_GTK_SUCCESS;
   1046 }
   1047 
   1048 
   1049 static gint
   1050 calculate_arrow_rect(GtkWidget* arrow, GdkRectangle* rect,
   1051                      GdkRectangle* arrow_rect, GtkTextDirection direction)
   1052 {
   1053     /* defined in gtkarrow.c */
   1054     gfloat arrow_scaling = 0.7;
   1055     gfloat xalign, xpad;
   1056     gint extent;
   1057     GtkMisc* misc = GTK_MISC(arrow);
   1058 
   1059     if (have_arrow_scaling)
   1060         gtk_widget_style_get(arrow, "arrow_scaling", &arrow_scaling, NULL);
   1061 
   1062     extent = MIN((rect->width - misc->xpad * 2),
   1063                  (rect->height - misc->ypad * 2)) * arrow_scaling;
   1064 
   1065     xalign = direction == GTK_TEXT_DIR_LTR ? misc->xalign : 1.0 - misc->xalign;
   1066     xpad = misc->xpad + (rect->width - extent) * xalign;
   1067 
   1068     arrow_rect->x = direction == GTK_TEXT_DIR_LTR ?
   1069                         floor(rect->x + xpad) : ceil(rect->x + xpad);
   1070     arrow_rect->y = floor(rect->y + misc->ypad +
   1071                           ((rect->height - extent) * misc->yalign));
   1072 
   1073     arrow_rect->width = arrow_rect->height = extent;
   1074 
   1075     return MOZ_GTK_SUCCESS;
   1076 }
   1077 
   1078 static gint
   1079 moz_gtk_scrollbar_button_paint(GdkDrawable* drawable, GdkRectangle* rect,
   1080                                GdkRectangle* cliprect, GtkWidgetState* state,
   1081                                GtkScrollbarButtonFlags flags,
   1082                                GtkTextDirection direction)
   1083 {
   1084     GtkStateType state_type = ConvertGtkState(state);
   1085     GtkShadowType shadow_type = (state->active) ?
   1086         GTK_SHADOW_IN : GTK_SHADOW_OUT;
   1087     GdkRectangle arrow_rect;
   1088     GtkStyle* style;
   1089     GtkWidget *scrollbar;
   1090     GtkArrowType arrow_type;
   1091     gint arrow_displacement_x, arrow_displacement_y;
   1092     const char* detail = (flags & MOZ_GTK_STEPPER_VERTICAL) ?
   1093                            "vscrollbar" : "hscrollbar";
   1094 
   1095     ensure_scrollbar_widget();
   1096 
   1097     if (flags & MOZ_GTK_STEPPER_VERTICAL)
   1098         scrollbar = gParts->vertScrollbarWidget;
   1099     else
   1100         scrollbar = gParts->horizScrollbarWidget;
   1101 
   1102     gtk_widget_set_direction(scrollbar, direction);
   1103 
   1104     /* Some theme engines (i.e., ClearLooks) check the scrollbar's allocation
   1105        to determine where it should paint rounded corners on the buttons.
   1106        We need to trick them into drawing the buttons the way we want them. */
   1107 
   1108     scrollbar->allocation.x = rect->x;
   1109     scrollbar->allocation.y = rect->y;
   1110     scrollbar->allocation.width = rect->width;
   1111     scrollbar->allocation.height = rect->height;
   1112 
   1113     if (flags & MOZ_GTK_STEPPER_VERTICAL) {
   1114         scrollbar->allocation.height *= 5;
   1115         if (flags & MOZ_GTK_STEPPER_DOWN) {
   1116             arrow_type = GTK_ARROW_DOWN;
   1117             if (flags & MOZ_GTK_STEPPER_BOTTOM)
   1118                 scrollbar->allocation.y -= 4 * rect->height;
   1119             else
   1120                 scrollbar->allocation.y -= rect->height;
   1121 
   1122         } else {
   1123             arrow_type = GTK_ARROW_UP;
   1124             if (flags & MOZ_GTK_STEPPER_BOTTOM)
   1125                 scrollbar->allocation.y -= 3 * rect->height;
   1126         }
   1127     } else {
   1128         scrollbar->allocation.width *= 5;
   1129         if (flags & MOZ_GTK_STEPPER_DOWN) {
   1130             arrow_type = GTK_ARROW_RIGHT;
   1131             if (flags & MOZ_GTK_STEPPER_BOTTOM)
   1132                 scrollbar->allocation.x -= 4 * rect->width;
   1133             else
   1134                 scrollbar->allocation.x -= rect->width;
   1135         } else {
   1136             arrow_type = GTK_ARROW_LEFT;
   1137             if (flags & MOZ_GTK_STEPPER_BOTTOM)
   1138                 scrollbar->allocation.x -= 3 * rect->width;
   1139         }
   1140     }
   1141 
   1142     style = scrollbar->style;
   1143 
   1144     TSOffsetStyleGCs(style, rect->x, rect->y);
   1145 
   1146     gtk_paint_box(style, drawable, state_type, shadow_type, cliprect,
   1147                   scrollbar, detail, rect->x, rect->y,
   1148                   rect->width, rect->height);
   1149 
   1150     arrow_rect.width = rect->width / 2;
   1151     arrow_rect.height = rect->height / 2;
   1152     arrow_rect.x = rect->x + (rect->width - arrow_rect.width) / 2;
   1153     arrow_rect.y = rect->y + (rect->height - arrow_rect.height) / 2;
   1154 
   1155     if (state_type == GTK_STATE_ACTIVE) {
   1156         gtk_widget_style_get(scrollbar,
   1157                              "arrow-displacement-x", &arrow_displacement_x,
   1158                              "arrow-displacement-y", &arrow_displacement_y,
   1159                              NULL);
   1160 
   1161         arrow_rect.x += arrow_displacement_x;
   1162         arrow_rect.y += arrow_displacement_y;
   1163     }
   1164 
   1165     gtk_paint_arrow(style, drawable, state_type, shadow_type, cliprect,
   1166                     scrollbar, detail, arrow_type, TRUE, arrow_rect.x,
   1167                     arrow_rect.y, arrow_rect.width, arrow_rect.height);
   1168 
   1169     return MOZ_GTK_SUCCESS;
   1170 }
   1171 
   1172 static gint
   1173 moz_gtk_scrollbar_trough_paint(GtkThemeWidgetType widget,
   1174                                GdkDrawable* drawable, GdkRectangle* rect,
   1175                                GdkRectangle* cliprect, GtkWidgetState* state,
   1176                                GtkTextDirection direction)
   1177 {
   1178     GtkStyle* style;
   1179     GtkScrollbar *scrollbar;
   1180 
   1181     ensure_scrollbar_widget();
   1182 
   1183     if (widget ==  MOZ_GTK_SCROLLBAR_TRACK_HORIZONTAL)
   1184         scrollbar = GTK_SCROLLBAR(gParts->horizScrollbarWidget);
   1185     else
   1186         scrollbar = GTK_SCROLLBAR(gParts->vertScrollbarWidget);
   1187 
   1188     gtk_widget_set_direction(GTK_WIDGET(scrollbar), direction);
   1189 
   1190     style = GTK_WIDGET(scrollbar)->style;
   1191 
   1192     TSOffsetStyleGCs(style, rect->x, rect->y);
   1193     gtk_style_apply_default_background(style, drawable, TRUE, GTK_STATE_ACTIVE,
   1194                                        cliprect, rect->x, rect->y,
   1195                                        rect->width, rect->height);
   1196 
   1197     gtk_paint_box(style, drawable, GTK_STATE_ACTIVE, GTK_SHADOW_IN, cliprect,
   1198                   GTK_WIDGET(scrollbar), "trough", rect->x, rect->y,
   1199                   rect->width, rect->height);
   1200 
   1201     if (state->focused) {
   1202         gtk_paint_focus(style, drawable, GTK_STATE_ACTIVE, cliprect,
   1203                         GTK_WIDGET(scrollbar), "trough",
   1204                         rect->x, rect->y, rect->width, rect->height);
   1205     }
   1206 
   1207     return MOZ_GTK_SUCCESS;
   1208 }
   1209 
   1210 static gint
   1211 moz_gtk_scrollbar_thumb_paint(GtkThemeWidgetType widget,
   1212                               GdkDrawable* drawable, GdkRectangle* rect,
   1213                               GdkRectangle* cliprect, GtkWidgetState* state,
   1214                               GtkTextDirection direction)
   1215 {
   1216     GtkStateType state_type = (state->inHover || state->active) ?
   1217         GTK_STATE_PRELIGHT : GTK_STATE_NORMAL;
   1218     GtkShadowType shadow_type = GTK_SHADOW_OUT;
   1219     GtkStyle* style;
   1220     GtkScrollbar *scrollbar;
   1221     GtkAdjustment *adj;
   1222     gboolean activate_slider;
   1223 
   1224     ensure_scrollbar_widget();
   1225 
   1226     if (widget == MOZ_GTK_SCROLLBAR_THUMB_HORIZONTAL)
   1227         scrollbar = GTK_SCROLLBAR(gParts->horizScrollbarWidget);
   1228     else
   1229         scrollbar = GTK_SCROLLBAR(gParts->vertScrollbarWidget);
   1230 
   1231     gtk_widget_set_direction(GTK_WIDGET(scrollbar), direction);
   1232 
   1233     /* Make sure to set the scrollbar range before painting so that
   1234        everything is drawn properly.  At least the bluecurve (and
   1235        maybe other) themes don't draw the top or bottom black line
   1236        surrounding the scrollbar if the theme thinks that it's butted
   1237        up against the scrollbar arrows.  Note the increases of the
   1238        clip rect below. */
   1239     /* Changing the cliprect is pretty bogus. This lets themes draw
   1240        outside the frame, which means we don't invalidate them
   1241        correctly. See bug 297508. But some themes do seem to need
   1242        it. So we modify the frame's overflow area to account for what
   1243        we're doing here; see nsNativeThemeGTK::GetWidgetOverflow. */
   1244     adj = gtk_range_get_adjustment(GTK_RANGE(scrollbar));
   1245 
   1246     if (widget == MOZ_GTK_SCROLLBAR_THUMB_HORIZONTAL) {
   1247         cliprect->x -= 1;
   1248         cliprect->width += 2;
   1249         adj->page_size = rect->width;
   1250     }
   1251     else {
   1252         cliprect->y -= 1;
   1253         cliprect->height += 2;
   1254         adj->page_size = rect->height;
   1255     }
   1256 
   1257     adj->lower = 0;
   1258     adj->value = state->curpos;
   1259     adj->upper = state->maxpos;
   1260     gtk_adjustment_changed(adj);
   1261 
   1262     style = GTK_WIDGET(scrollbar)->style;
   1263 
   1264     gtk_widget_style_get(GTK_WIDGET(scrollbar), "activate-slider",
   1265                          &activate_slider, NULL);
   1266 
   1267     if (activate_slider && state->active) {
   1268         shadow_type = GTK_SHADOW_IN;
   1269         state_type = GTK_STATE_ACTIVE;
   1270     }
   1271 
   1272     TSOffsetStyleGCs(style, rect->x, rect->y);
   1273 
   1274     gtk_paint_slider(style, drawable, state_type, shadow_type, cliprect,
   1275                      GTK_WIDGET(scrollbar), "slider", rect->x, rect->y,
   1276                      rect->width,  rect->height,
   1277                      (widget == MOZ_GTK_SCROLLBAR_THUMB_HORIZONTAL) ?
   1278                      GTK_ORIENTATION_HORIZONTAL : GTK_ORIENTATION_VERTICAL);
   1279 
   1280     return MOZ_GTK_SUCCESS;
   1281 }
   1282 
   1283 static gint
   1284 moz_gtk_spin_paint(GdkDrawable* drawable, GdkRectangle* rect,
   1285                    GtkTextDirection direction)
   1286 {
   1287     GtkStyle* style;
   1288 
   1289     ensure_spin_widget();
   1290     gtk_widget_set_direction(gParts->spinWidget, direction);
   1291     style = gParts->spinWidget->style;
   1292 
   1293     TSOffsetStyleGCs(style, rect->x, rect->y);
   1294     gtk_paint_box(style, drawable, GTK_STATE_NORMAL, GTK_SHADOW_IN, NULL,
   1295                   gParts->spinWidget, "spinbutton",
   1296                   rect->x, rect->y, rect->width, rect->height);
   1297     return MOZ_GTK_SUCCESS;
   1298 }
   1299 
   1300 static gint
   1301 moz_gtk_spin_updown_paint(GdkDrawable* drawable, GdkRectangle* rect,
   1302                           gboolean isDown, GtkWidgetState* state,
   1303                           GtkTextDirection direction)
   1304 {
   1305     GdkRectangle arrow_rect;
   1306     GtkStateType state_type = ConvertGtkState(state);
   1307     GtkShadowType shadow_type = state_type == GTK_STATE_ACTIVE ?
   1308                                   GTK_SHADOW_IN : GTK_SHADOW_OUT;
   1309     GtkStyle* style;
   1310 
   1311     ensure_spin_widget();
   1312     style = gParts->spinWidget->style;
   1313     gtk_widget_set_direction(gParts->spinWidget, direction);
   1314 
   1315     TSOffsetStyleGCs(style, rect->x, rect->y);
   1316     gtk_paint_box(style, drawable, state_type, shadow_type, NULL, gParts->spinWidget,
   1317                   isDown ? "spinbutton_down" : "spinbutton_up",
   1318                   rect->x, rect->y, rect->width, rect->height);
   1319 
   1320     /* hard code these values */
   1321     arrow_rect.width = 6;
   1322     arrow_rect.height = 6;
   1323     arrow_rect.x = rect->x + (rect->width - arrow_rect.width) / 2;
   1324     arrow_rect.y = rect->y + (rect->height - arrow_rect.height) / 2;
   1325     arrow_rect.y += isDown ? -1 : 1;
   1326 
   1327     gtk_paint_arrow(style, drawable, state_type, shadow_type, NULL,
   1328                     gParts->spinWidget, "spinbutton",
   1329                     isDown ? GTK_ARROW_DOWN : GTK_ARROW_UP, TRUE,
   1330                     arrow_rect.x, arrow_rect.y,
   1331                     arrow_rect.width, arrow_rect.height);
   1332 
   1333     return MOZ_GTK_SUCCESS;
   1334 }
   1335 
   1336 static gint
   1337 moz_gtk_scale_paint(GdkDrawable* drawable, GdkRectangle* rect,
   1338                     GdkRectangle* cliprect, GtkWidgetState* state,
   1339                     GtkOrientation flags, GtkTextDirection direction)
   1340 {
   1341   gint x = 0, y = 0;
   1342   GtkStateType state_type = ConvertGtkState(state);
   1343   GtkStyle* style;
   1344   GtkWidget* widget;
   1345 
   1346   ensure_scale_widget();
   1347   widget = ((flags == GTK_ORIENTATION_HORIZONTAL) ? gParts->hScaleWidget : gParts->vScaleWidget);
   1348   gtk_widget_set_direction(widget, direction);
   1349 
   1350   style = widget->style;
   1351 
   1352   if (flags == GTK_ORIENTATION_HORIZONTAL) {
   1353     x = XTHICKNESS(style);
   1354     y++;
   1355   }
   1356   else {
   1357     x++;
   1358     y = YTHICKNESS(style);
   1359   }
   1360 
   1361   TSOffsetStyleGCs(style, rect->x, rect->y);
   1362   gtk_style_apply_default_background(style, drawable, TRUE, GTK_STATE_NORMAL,
   1363                                      cliprect, rect->x, rect->y,
   1364                                      rect->width, rect->height);
   1365 
   1366   gtk_paint_box(style, drawable, GTK_STATE_ACTIVE, GTK_SHADOW_IN, cliprect,
   1367                 widget, "trough", rect->x + x, rect->y + y,
   1368                 rect->width - 2*x, rect->height - 2*y);
   1369 
   1370   if (state->focused)
   1371     gtk_paint_focus(style, drawable, state_type, cliprect, widget, "trough",
   1372                     rect->x, rect->y, rect->width, rect->height);
   1373 
   1374   return MOZ_GTK_SUCCESS;
   1375 }
   1376 
   1377 static gint
   1378 moz_gtk_scale_thumb_paint(GdkDrawable* drawable, GdkRectangle* rect,
   1379                           GdkRectangle* cliprect, GtkWidgetState* state,
   1380                           GtkOrientation flags, GtkTextDirection direction)
   1381 {
   1382   GtkStateType state_type = ConvertGtkState(state);
   1383   GtkStyle* style;
   1384   GtkWidget* widget;
   1385   gint thumb_width, thumb_height, x, y;
   1386 
   1387   ensure_scale_widget();
   1388   widget = ((flags == GTK_ORIENTATION_HORIZONTAL) ? gParts->hScaleWidget : gParts->vScaleWidget);
   1389   gtk_widget_set_direction(widget, direction);
   1390 
   1391   style = widget->style;
   1392 
   1393   /* determine the thumb size, and position the thumb in the center in the opposite axis */
   1394   if (flags == GTK_ORIENTATION_HORIZONTAL) {
   1395     moz_gtk_get_scalethumb_metrics(GTK_ORIENTATION_HORIZONTAL, &thumb_width, &thumb_height);
   1396     x = rect->x;
   1397     y = rect->y + (rect->height - thumb_height) / 2;
   1398   }
   1399   else {
   1400     moz_gtk_get_scalethumb_metrics(GTK_ORIENTATION_VERTICAL, &thumb_height, &thumb_width);
   1401     x = rect->x + (rect->width - thumb_width) / 2;
   1402     y = rect->y;
   1403   }
   1404 
   1405   TSOffsetStyleGCs(style, rect->x, rect->y);
   1406   gtk_paint_slider(style, drawable, state_type, GTK_SHADOW_OUT, cliprect,
   1407                    widget, (flags == GTK_ORIENTATION_HORIZONTAL) ? "hscale" : "vscale",
   1408                    x, y, thumb_width, thumb_height, flags);
   1409 
   1410   return MOZ_GTK_SUCCESS;
   1411 }
   1412 
   1413 static gint
   1414 moz_gtk_gripper_paint(GdkDrawable* drawable, GdkRectangle* rect,
   1415                       GdkRectangle* cliprect, GtkWidgetState* state,
   1416                       GtkTextDirection direction)
   1417 {
   1418     GtkStateType state_type = ConvertGtkState(state);
   1419     GtkShadowType shadow_type;
   1420     GtkStyle* style;
   1421 
   1422     ensure_handlebox_widget();
   1423     gtk_widget_set_direction(gParts->handleBoxWidget, direction);
   1424 
   1425     style = gParts->handleBoxWidget->style;
   1426     shadow_type = GTK_HANDLE_BOX(gParts->handleBoxWidget)->shadow_type;
   1427 
   1428     TSOffsetStyleGCs(style, rect->x, rect->y);
   1429     gtk_paint_box(style, drawable, state_type, shadow_type, cliprect,
   1430                   gParts->handleBoxWidget, "handlebox_bin", rect->x, rect->y,
   1431                   rect->width, rect->height);
   1432 
   1433     return MOZ_GTK_SUCCESS;
   1434 }
   1435 
   1436 static gint
   1437 moz_gtk_hpaned_paint(GdkDrawable* drawable, GdkRectangle* rect,
   1438                      GdkRectangle* cliprect, GtkWidgetState* state)
   1439 {
   1440     GtkStateType hpaned_state = ConvertGtkState(state);
   1441 
   1442     ensure_hpaned_widget();
   1443     gtk_paint_handle(gParts->hpanedWidget->style, drawable, hpaned_state,
   1444                      GTK_SHADOW_NONE, cliprect, gParts->hpanedWidget, "paned",
   1445                      rect->x, rect->y, rect->width, rect->height,
   1446                      GTK_ORIENTATION_VERTICAL);
   1447 
   1448     return MOZ_GTK_SUCCESS;
   1449 }
   1450 
   1451 static gint
   1452 moz_gtk_vpaned_paint(GdkDrawable* drawable, GdkRectangle* rect,
   1453                      GdkRectangle* cliprect, GtkWidgetState* state)
   1454 {
   1455     GtkStateType vpaned_state = ConvertGtkState(state);
   1456 
   1457     ensure_vpaned_widget();
   1458     gtk_paint_handle(gParts->vpanedWidget->style, drawable, vpaned_state,
   1459                      GTK_SHADOW_NONE, cliprect, gParts->vpanedWidget, "paned",
   1460                      rect->x, rect->y, rect->width, rect->height,
   1461                      GTK_ORIENTATION_HORIZONTAL);
   1462 
   1463     return MOZ_GTK_SUCCESS;
   1464 }
   1465 
   1466 static gint
   1467 moz_gtk_caret_paint(GdkDrawable* drawable, GdkRectangle* rect,
   1468                     GdkRectangle* cliprect, GtkTextDirection direction)
   1469 {
   1470     GdkRectangle location = *rect;
   1471     if (direction == GTK_TEXT_DIR_RTL) {
   1472         /* gtk_draw_insertion_cursor ignores location.width */
   1473         location.x = rect->x + rect->width;
   1474     }
   1475 
   1476     ensure_entry_widget();
   1477     gtk_draw_insertion_cursor(gParts->entryWidget, drawable, cliprect,
   1478                               &location, TRUE, direction, FALSE);
   1479 
   1480     return MOZ_GTK_SUCCESS;
   1481 }
   1482 
   1483 static gint
   1484 moz_gtk_entry_paint(GdkDrawable* drawable, GdkRectangle* rect,
   1485                     GdkRectangle* cliprect, GtkWidgetState* state,
   1486                     GtkWidget* widget, GtkTextDirection direction)
   1487 {
   1488     GtkStateType bg_state = state->disabled ?
   1489                                 GTK_STATE_INSENSITIVE : GTK_STATE_NORMAL;
   1490     gint x, y, width = rect->width, height = rect->height;
   1491     GtkStyle* style;
   1492     gboolean interior_focus;
   1493     gboolean theme_honors_transparency = FALSE;
   1494     gint focus_width;
   1495 
   1496     gtk_widget_set_direction(widget, direction);
   1497 
   1498     style = widget->style;
   1499 
   1500     gtk_widget_style_get(widget,
   1501                          "interior-focus", &interior_focus,
   1502                          "focus-line-width", &focus_width,
   1503                          "honors-transparent-bg-hint", &theme_honors_transparency,
   1504                          NULL);
   1505 
   1506     /* gtkentry.c uses two windows, one for the entire widget and one for the
   1507      * text area inside it. The background of both windows is set to the "base"
   1508      * color of the new state in gtk_entry_state_changed, but only the inner
   1509      * textarea window uses gtk_paint_flat_box when exposed */
   1510 
   1511     TSOffsetStyleGCs(style, rect->x, rect->y);
   1512 
   1513     /* This gets us a lovely greyish disabledish look */
   1514     gtk_widget_set_sensitive(widget, !state->disabled);
   1515 
   1516     /* GTK fills the outer widget window with the base color before drawing the widget.
   1517      * Some older themes rely on this behavior, but many themes nowadays use rounded
   1518      * corners on their widgets. While most GTK apps are blissfully unaware of this
   1519      * problem due to their use of the default window background, we render widgets on
   1520      * many kinds of backgrounds on the web.
   1521      * If the theme is able to cope with transparency, then we can skip pre-filling
   1522      * and notify the theme it will paint directly on the canvas. */
   1523     if (theme_honors_transparency) {
   1524         g_object_set_data(G_OBJECT(widget), "transparent-bg-hint", GINT_TO_POINTER(TRUE));
   1525     } else {
   1526         gdk_draw_rectangle(drawable, style->base_gc[bg_state], TRUE,
   1527                            cliprect->x, cliprect->y, cliprect->width, cliprect->height);
   1528         g_object_set_data(G_OBJECT(widget), "transparent-bg-hint", GINT_TO_POINTER(FALSE));
   1529     }
   1530 
   1531     /* Get the position of the inner window, see _gtk_entry_get_borders */
   1532     x = XTHICKNESS(style);
   1533     y = YTHICKNESS(style);
   1534 
   1535     if (!interior_focus) {
   1536         x += focus_width;
   1537         y += focus_width;
   1538     }
   1539 
   1540     /* Simulate an expose of the inner window */
   1541     gtk_paint_flat_box(style, drawable, bg_state, GTK_SHADOW_NONE,
   1542                        cliprect, widget, "entry_bg",  rect->x + x,
   1543                        rect->y + y, rect->width - 2*x, rect->height - 2*y);
   1544 
   1545     /* Now paint the shadow and focus border.
   1546      * We do like in gtk_entry_draw_frame, we first draw the shadow, a tad
   1547      * smaller when focused if the focus is not interior, then the focus. */
   1548     x = rect->x;
   1549     y = rect->y;
   1550 
   1551     if (state->focused && !state->disabled) {
   1552         /* This will get us the lit borders that focused textboxes enjoy on
   1553          * some themes. */
   1554         GTK_WIDGET_SET_FLAGS(widget, GTK_HAS_FOCUS);
   1555 
   1556         if (!interior_focus) {
   1557             /* Indent the border a little bit if we have exterior focus
   1558                (this is what GTK does to draw native entries) */
   1559             x += focus_width;
   1560             y += focus_width;
   1561             width -= 2 * focus_width;
   1562             height -= 2 * focus_width;
   1563         }
   1564     }
   1565 
   1566     gtk_paint_shadow(style, drawable, GTK_STATE_NORMAL, GTK_SHADOW_IN,
   1567                      cliprect, widget, "entry", x, y, width, height);
   1568 
   1569     if (state->focused && !state->disabled) {
   1570         if (!interior_focus) {
   1571             gtk_paint_focus(style, drawable,  GTK_STATE_NORMAL, cliprect,
   1572                             widget, "entry",
   1573                             rect->x, rect->y, rect->width, rect->height);
   1574         }
   1575 
   1576         /* Now unset the focus flag. We don't want other entries to look
   1577          * like they're focused too! */
   1578         GTK_WIDGET_UNSET_FLAGS(widget, GTK_HAS_FOCUS);
   1579     }
   1580 
   1581     return MOZ_GTK_SUCCESS;
   1582 }
   1583 
   1584 static gint
   1585 moz_gtk_treeview_paint(GdkDrawable* drawable, GdkRectangle* rect,
   1586                        GdkRectangle* cliprect, GtkWidgetState* state,
   1587                        GtkTextDirection direction)
   1588 {
   1589     gint xthickness, ythickness;
   1590 
   1591     GtkStyle *style;
   1592     GtkStateType state_type;
   1593 
   1594     ensure_tree_view_widget();
   1595     ensure_scrolled_window_widget();
   1596 
   1597     gtk_widget_set_direction(gParts->treeViewWidget, direction);
   1598     gtk_widget_set_direction(gParts->scrolledWindowWidget, direction);
   1599 
   1600     /* only handle disabled and normal states, otherwise the whole background
   1601      * area will be painted differently with other states */
   1602     state_type = state->disabled ? GTK_STATE_INSENSITIVE : GTK_STATE_NORMAL;
   1603 
   1604     /* In GTK the treeview sets the background of the window
   1605      * which contains the cells to the treeview base color.
   1606      * If we don't set it here the background color will not be correct.*/
   1607     gtk_widget_modify_bg(gParts->treeViewWidget, state_type,
   1608                          &gParts->treeViewWidget->style->base[state_type]);
   1609 
   1610     style = gParts->scrolledWindowWidget->style;
   1611     xthickness = XTHICKNESS(style);
   1612     ythickness = YTHICKNESS(style);
   1613 
   1614     TSOffsetStyleGCs(gParts->treeViewWidget->style, rect->x, rect->y);
   1615     TSOffsetStyleGCs(style, rect->x, rect->y);
   1616 
   1617     gtk_paint_flat_box(gParts->treeViewWidget->style, drawable, state_type,
   1618                        GTK_SHADOW_NONE, cliprect, gParts->treeViewWidget, "treeview",
   1619                        rect->x + xthickness, rect->y + ythickness,
   1620                        rect->width - 2 * xthickness,
   1621                        rect->height - 2 * ythickness);
   1622 
   1623     gtk_paint_shadow(style, drawable, GTK_STATE_NORMAL, GTK_SHADOW_IN,
   1624                      cliprect, gParts->scrolledWindowWidget, "scrolled_window",
   1625                      rect->x, rect->y, rect->width, rect->height);
   1626 
   1627     return MOZ_GTK_SUCCESS;
   1628 }
   1629 
   1630 static gint
   1631 moz_gtk_tree_header_cell_paint(GdkDrawable* drawable, GdkRectangle* rect,
   1632                                GdkRectangle* cliprect, GtkWidgetState* state,
   1633                                gboolean isSorted, GtkTextDirection direction)
   1634 {
   1635     gtk_tree_view_column_set_sort_indicator(gParts->middleTreeViewColumn,
   1636                                             isSorted);
   1637 
   1638     moz_gtk_button_paint(drawable, rect, cliprect, state, GTK_RELIEF_NORMAL,
   1639                          gParts->treeHeaderCellWidget, direction);
   1640     return MOZ_GTK_SUCCESS;
   1641 }
   1642 
   1643 static gint
   1644 moz_gtk_tree_header_sort_arrow_paint(GdkDrawable* drawable, GdkRectangle* rect,
   1645                                      GdkRectangle* cliprect,
   1646                                      GtkWidgetState* state, GtkArrowType flags,
   1647                                      GtkTextDirection direction)
   1648 {
   1649     GdkRectangle arrow_rect;
   1650     GtkStateType state_type = ConvertGtkState(state);
   1651     GtkShadowType shadow_type = GTK_SHADOW_IN;
   1652     GtkArrowType arrow_type = flags;
   1653     GtkStyle* style;
   1654 
   1655     ensure_tree_header_cell_widget();
   1656     gtk_widget_set_direction(gParts->treeHeaderSortArrowWidget, direction);
   1657 
   1658     /* hard code these values */
   1659     arrow_rect.width = 11;
   1660     arrow_rect.height = 11;
   1661     arrow_rect.x = rect->x + (rect->width - arrow_rect.width) / 2;
   1662     arrow_rect.y = rect->y + (rect->height - arrow_rect.height) / 2;
   1663 
   1664     style = gParts->treeHeaderSortArrowWidget->style;
   1665     TSOffsetStyleGCs(style, arrow_rect.x, arrow_rect.y);
   1666 
   1667     gtk_paint_arrow(style, drawable, state_type, shadow_type, cliprect,
   1668                     gParts->treeHeaderSortArrowWidget, "arrow",  arrow_type, TRUE,
   1669                     arrow_rect.x, arrow_rect.y,
   1670                     arrow_rect.width, arrow_rect.height);
   1671 
   1672     return MOZ_GTK_SUCCESS;
   1673 }
   1674 
   1675 static gint
   1676 moz_gtk_treeview_expander_paint(GdkDrawable* drawable, GdkRectangle* rect,
   1677                                 GdkRectangle* cliprect, GtkWidgetState* state,
   1678                                 GtkExpanderStyle expander_state,
   1679                                 GtkTextDirection direction)
   1680 {
   1681     GtkStyle *style;
   1682     GtkStateType state_type;
   1683 
   1684     ensure_tree_view_widget();
   1685     gtk_widget_set_direction(gParts->treeViewWidget, direction);
   1686 
   1687     style = gParts->treeViewWidget->style;
   1688 
   1689     /* Because the frame we get is of the entire treeview, we can't get the precise
   1690      * event state of one expander, thus rendering hover and active feedback useless. */
   1691     state_type = state->disabled ? GTK_STATE_INSENSITIVE : GTK_STATE_NORMAL;
   1692 
   1693     TSOffsetStyleGCs(style, rect->x, rect->y);
   1694     gtk_paint_expander(style, drawable, state_type, cliprect, gParts->treeViewWidget, "treeview",
   1695                        rect->x + rect->width / 2, rect->y + rect->height / 2, expander_state);
   1696 
   1697     return MOZ_GTK_SUCCESS;
   1698 }
   1699 
   1700 static gint
   1701 moz_gtk_expander_paint(GdkDrawable* drawable, GdkRectangle* rect,
   1702                        GdkRectangle* cliprect, GtkWidgetState* state,
   1703                        GtkExpanderStyle expander_state,
   1704                        GtkTextDirection direction)
   1705 {
   1706     GtkStyle *style;
   1707     GtkStateType state_type = ConvertGtkState(state);
   1708 
   1709     ensure_expander_widget();
   1710     gtk_widget_set_direction(gParts->expanderWidget, direction);
   1711 
   1712     style = gParts->expanderWidget->style;
   1713 
   1714     TSOffsetStyleGCs(style, rect->x, rect->y);
   1715     gtk_paint_expander(style, drawable, state_type, cliprect, gParts->expanderWidget, "expander",
   1716                        rect->x + rect->width / 2, rect->y + rect->height / 2, expander_state);
   1717 
   1718     return MOZ_GTK_SUCCESS;
   1719 }
   1720 
   1721 static gint
   1722 moz_gtk_combo_box_paint(GdkDrawable* drawable, GdkRectangle* rect,
   1723                         GdkRectangle* cliprect, GtkWidgetState* state,
   1724                         gboolean ishtml, GtkTextDirection direction)
   1725 {
   1726     GdkRectangle arrow_rect, real_arrow_rect;
   1727     gint /* arrow_size, */ separator_width;
   1728     gboolean wide_separators;
   1729     GtkStateType state_type = ConvertGtkState(state);
   1730     GtkShadowType shadow_type = state->active ? GTK_SHADOW_IN : GTK_SHADOW_OUT;
   1731     GtkStyle* style;
   1732     GtkRequisition arrow_req;
   1733 
   1734     ensure_combo_box_widgets();
   1735 
   1736     /* Also sets the direction on gParts->comboBoxButtonWidget, which is then
   1737      * inherited by the separator and arrow */
   1738     moz_gtk_button_paint(drawable, rect, cliprect, state, GTK_RELIEF_NORMAL,
   1739                          gParts->comboBoxButtonWidget, direction);
   1740 
   1741     calculate_button_inner_rect(gParts->comboBoxButtonWidget,
   1742                                 rect, &arrow_rect, direction, ishtml);
   1743     /* Now arrow_rect contains the inner rect ; we want to correct the width
   1744      * to what the arrow needs (see gtk_combo_box_size_allocate) */
   1745     gtk_widget_size_request(gParts->comboBoxArrowWidget, &arrow_req);
   1746     if (direction == GTK_TEXT_DIR_LTR)
   1747         arrow_rect.x += arrow_rect.width - arrow_req.width;
   1748     arrow_rect.width = arrow_req.width;
   1749 
   1750     calculate_arrow_rect(gParts->comboBoxArrowWidget,
   1751                          &arrow_rect, &real_arrow_rect, direction);
   1752 
   1753     style = gParts->comboBoxArrowWidget->style;
   1754     TSOffsetStyleGCs(style, rect->x, rect->y);
   1755 
   1756     gtk_widget_size_allocate(gParts->comboBoxWidget, rect);
   1757 
   1758     gtk_paint_arrow(style, drawable, state_type, shadow_type, cliprect,
   1759                     gParts->comboBoxArrowWidget, "arrow",  GTK_ARROW_DOWN, TRUE,
   1760                     real_arrow_rect.x, real_arrow_rect.y,
   1761                     real_arrow_rect.width, real_arrow_rect.height);
   1762 
   1763 
   1764     /* If there is no separator in the theme, there's nothing left to do. */
   1765     if (!gParts->comboBoxSeparatorWidget)
   1766         return MOZ_GTK_SUCCESS;
   1767 
   1768     style = gParts->comboBoxSeparatorWidget->style;
   1769     TSOffsetStyleGCs(style, rect->x, rect->y);
   1770 
   1771     gtk_widget_style_get(gParts->comboBoxSeparatorWidget,
   1772                          "wide-separators", &wide_separators,
   1773                          "separator-width", &separator_width,
   1774                          NULL);
   1775 
   1776     if (wide_separators) {
   1777         if (direction == GTK_TEXT_DIR_LTR)
   1778             arrow_rect.x -= separator_width;
   1779         else
   1780             arrow_rect.x += arrow_rect.width;
   1781 
   1782         gtk_paint_box(style, drawable,
   1783                       GTK_STATE_NORMAL, GTK_SHADOW_ETCHED_OUT,
   1784                       cliprect, gParts->comboBoxSeparatorWidget, "vseparator",
   1785                       arrow_rect.x, arrow_rect.y,
   1786                       separator_width, arrow_rect.height);
   1787     } else {
   1788         if (direction == GTK_TEXT_DIR_LTR)
   1789             arrow_rect.x -= XTHICKNESS(style);
   1790         else
   1791             arrow_rect.x += arrow_rect.width;
   1792 
   1793         gtk_paint_vline(style, drawable, GTK_STATE_NORMAL, cliprect,
   1794                         gParts->comboBoxSeparatorWidget, "vseparator",
   1795                         arrow_rect.y, arrow_rect.y + arrow_rect.height,
   1796                         arrow_rect.x);
   1797     }
   1798 
   1799     return MOZ_GTK_SUCCESS;
   1800 }
   1801 
   1802 static gint
   1803 moz_gtk_downarrow_paint(GdkDrawable* drawable, GdkRectangle* rect,
   1804                         GdkRectangle* cliprect, GtkWidgetState* state)
   1805 {
   1806     GtkStyle* style;
   1807     GtkStateType state_type = ConvertGtkState(state);
   1808     GtkShadowType shadow_type = state->active ? GTK_SHADOW_IN : GTK_SHADOW_OUT;
   1809     GdkRectangle arrow_rect;
   1810 
   1811     ensure_button_arrow_widget();
   1812     style = gParts->buttonArrowWidget->style;
   1813 
   1814     calculate_arrow_rect(gParts->buttonArrowWidget, rect, &arrow_rect,
   1815                          GTK_TEXT_DIR_LTR);
   1816 
   1817     TSOffsetStyleGCs(style, arrow_rect.x, arrow_rect.y);
   1818     gtk_paint_arrow(style, drawable, state_type, shadow_type, cliprect,
   1819                     gParts->buttonArrowWidget, "arrow",  GTK_ARROW_DOWN, TRUE,
   1820                     arrow_rect.x, arrow_rect.y, arrow_rect.width, arrow_rect.height);
   1821 
   1822     return MOZ_GTK_SUCCESS;
   1823 }
   1824 
   1825 static gint
   1826 moz_gtk_combo_box_entry_button_paint(GdkDrawable* drawable, GdkRectangle* rect,
   1827                                      GdkRectangle* cliprect,
   1828                                      GtkWidgetState* state,
   1829                                      gboolean input_focus,
   1830                                      GtkTextDirection direction)
   1831 {
   1832     gint x_displacement, y_displacement;
   1833     GdkRectangle arrow_rect, real_arrow_rect;
   1834     GtkStateType state_type = ConvertGtkState(state);
   1835     GtkShadowType shadow_type = state->active ? GTK_SHADOW_IN : GTK_SHADOW_OUT;
   1836     GtkStyle* style;
   1837 
   1838     ensure_combo_box_entry_widgets();
   1839 
   1840     if (input_focus) {
   1841         /* Some themes draw a complementary focus ring for the dropdown button
   1842          * when the dropdown entry has focus */
   1843         GTK_WIDGET_SET_FLAGS(gParts->comboBoxEntryTextareaWidget, GTK_HAS_FOCUS);
   1844     }
   1845 
   1846     moz_gtk_button_paint(drawable, rect, cliprect, state, GTK_RELIEF_NORMAL,
   1847                          gParts->comboBoxEntryButtonWidget, direction);
   1848 
   1849     if (input_focus)
   1850         GTK_WIDGET_UNSET_FLAGS(gParts->comboBoxEntryTextareaWidget, GTK_HAS_FOCUS);
   1851 
   1852     calculate_button_inner_rect(gParts->comboBoxEntryButtonWidget,
   1853                                 rect, &arrow_rect, direction, FALSE);
   1854     if (state_type == GTK_STATE_ACTIVE) {
   1855         gtk_widget_style_get(gParts->comboBoxEntryButtonWidget,
   1856                              "child-displacement-x", &x_displacement,
   1857                              "child-displacement-y", &y_displacement,
   1858                              NULL);
   1859         arrow_rect.x += x_displacement;
   1860         arrow_rect.y += y_displacement;
   1861     }
   1862 
   1863     calculate_arrow_rect(gParts->comboBoxEntryArrowWidget,
   1864                          &arrow_rect, &real_arrow_rect, direction);
   1865 
   1866     style = gParts->comboBoxEntryArrowWidget->style;
   1867     TSOffsetStyleGCs(style, real_arrow_rect.x, real_arrow_rect.y);
   1868 
   1869     gtk_paint_arrow(style, drawable, state_type, shadow_type, cliprect,
   1870                     gParts->comboBoxEntryArrowWidget, "arrow",  GTK_ARROW_DOWN, TRUE,
   1871                     real_arrow_rect.x, real_arrow_rect.y,
   1872                     real_arrow_rect.width, real_arrow_rect.height);
   1873 
   1874     return MOZ_GTK_SUCCESS;
   1875 }
   1876 
   1877 static gint
   1878 moz_gtk_container_paint(GdkDrawable* drawable, GdkRectangle* rect,
   1879                         GdkRectangle* cliprect, GtkWidgetState* state,
   1880                         gboolean isradio, GtkTextDirection direction)
   1881 {
   1882     GtkStateType state_type = ConvertGtkState(state);
   1883     GtkStyle* style;
   1884     GtkWidget *widget;
   1885     gboolean interior_focus;
   1886     gint focus_width, focus_pad;
   1887 
   1888     if (isradio) {
   1889         ensure_radiobutton_widget();
   1890         widget = gParts->radiobuttonWidget;
   1891     } else {
   1892         ensure_checkbox_widget();
   1893         widget = gParts->checkboxWidget;
   1894     }
   1895     gtk_widget_set_direction(widget, direction);
   1896 
   1897     style = widget->style;
   1898     moz_gtk_widget_get_focus(widget, &interior_focus, &focus_width,
   1899                              &focus_pad);
   1900 
   1901     TSOffsetStyleGCs(style, rect->x, rect->y);
   1902 
   1903     /* The detail argument for the gtk_paint_* calls below are "checkbutton"
   1904        even for radio buttons, to match what gtk does. */
   1905 
   1906     /* this is for drawing a prelight box */
   1907     if (state_type == GTK_STATE_PRELIGHT || state_type == GTK_STATE_ACTIVE) {
   1908         gtk_paint_flat_box(style, drawable, GTK_STATE_PRELIGHT,
   1909                            GTK_SHADOW_ETCHED_OUT, cliprect, widget,
   1910                            "checkbutton",
   1911                            rect->x, rect->y, rect->width, rect->height);
   1912     }
   1913 
   1914     if (state_type != GTK_STATE_NORMAL && state_type != GTK_STATE_PRELIGHT)
   1915         state_type = GTK_STATE_NORMAL;
   1916 
   1917     if (state->focused && !interior_focus) {
   1918         gtk_paint_focus(style, drawable, state_type, cliprect, widget,
   1919                         "checkbutton",
   1920                         rect->x, rect->y, rect->width, rect->height);
   1921     }
   1922 
   1923     return MOZ_GTK_SUCCESS;
   1924 }
   1925 
   1926 static gint
   1927 moz_gtk_toggle_label_paint(GdkDrawable* drawable, GdkRectangle* rect,
   1928                            GdkRectangle* cliprect, GtkWidgetState* state,
   1929                            gboolean isradio, GtkTextDirection direction)
   1930 {
   1931     GtkStateType state_type;
   1932     GtkStyle *style;
   1933     GtkWidget *widget;
   1934     gboolean interior_focus;
   1935 
   1936     if (!state->focused)
   1937         return MOZ_GTK_SUCCESS;
   1938 
   1939     if (isradio) {
   1940         ensure_radiobutton_widget();
   1941         widget = gParts->radiobuttonWidget;
   1942     } else {
   1943         ensure_checkbox_widget();
   1944         widget = gParts->checkboxWidget;
   1945     }
   1946     gtk_widget_set_direction(widget, direction);
   1947 
   1948     gtk_widget_style_get(widget, "interior-focus", &interior_focus, NULL);
   1949     if (!interior_focus)
   1950         return MOZ_GTK_SUCCESS;
   1951 
   1952     state_type = ConvertGtkState(state);
   1953 
   1954     style = widget->style;
   1955     TSOffsetStyleGCs(style, rect->x, rect->y);
   1956 
   1957     /* Always "checkbutton" to match gtkcheckbutton.c */
   1958     gtk_paint_focus(style, drawable, state_type, cliprect, widget,
   1959                     "checkbutton",
   1960                     rect->x, rect->y, rect->width, rect->height);
   1961 
   1962     return MOZ_GTK_SUCCESS;
   1963 }
   1964 
   1965 static gint
   1966 moz_gtk_toolbar_paint(GdkDrawable* drawable, GdkRectangle* rect,
   1967                       GdkRectangle* cliprect, GtkTextDirection direction)
   1968 {
   1969     GtkStyle* style;
   1970     GtkShadowType shadow_type;
   1971 
   1972     ensure_toolbar_widget();
   1973     gtk_widget_set_direction(gParts->toolbarWidget, direction);
   1974 
   1975     style = gParts->toolbarWidget->style;
   1976 
   1977     TSOffsetStyleGCs(style, rect->x, rect->y);
   1978 
   1979     gtk_style_apply_default_background(style, drawable, TRUE,
   1980                                        GTK_STATE_NORMAL,
   1981                                        cliprect, rect->x, rect->y,
   1982                                        rect->width, rect->height);
   1983 
   1984     gtk_widget_style_get(gParts->toolbarWidget, "shadow-type", &shadow_type, NULL);
   1985 
   1986     gtk_paint_box (style, drawable, GTK_STATE_NORMAL, shadow_type,
   1987                    cliprect, gParts->toolbarWidget, "toolbar",
   1988                    rect->x, rect->y, rect->width, rect->height);
   1989 
   1990     return MOZ_GTK_SUCCESS;
   1991 }
   1992 
   1993 static gint
   1994 moz_gtk_toolbar_separator_paint(GdkDrawable* drawable, GdkRectangle* rect,
   1995                                 GdkRectangle* cliprect,
   1996                                 GtkTextDirection direction)
   1997 {
   1998     GtkStyle* style;
   1999     gint     separator_width;
   2000     gint     paint_width;
   2001     gboolean wide_separators;
   2002 
   2003     /* Defined as constants in GTK+ 2.10.14 */
   2004     const double start_fraction = 0.2;
   2005     const double end_fraction = 0.8;
   2006 
   2007     ensure_toolbar_separator_widget();
   2008     gtk_widget_set_direction(gParts->toolbarSeparatorWidget, direction);
   2009 
   2010     style = gParts->toolbarSeparatorWidget->style;
   2011 
   2012     gtk_widget_style_get(gParts->toolbarWidget,
   2013                          "wide-separators", &wide_separators,
   2014                          "separator-width", &separator_width,
   2015                          NULL);
   2016 
   2017     TSOffsetStyleGCs(style, rect->x, rect->y);
   2018 
   2019     if (wide_separators) {
   2020         if (separator_width > rect->width)
   2021             separator_width = rect->width;
   2022 
   2023         gtk_paint_box(style, drawable,
   2024                       GTK_STATE_NORMAL, GTK_SHADOW_ETCHED_OUT,
   2025                       cliprect, gParts->toolbarWidget, "vseparator",
   2026                       rect->x + (rect->width - separator_width) / 2,
   2027                       rect->y + rect->height * start_fraction,
   2028                       separator_width,
   2029                       rect->height * (end_fraction - start_fraction));
   2030 
   2031     } else {
   2032         paint_width = style->xthickness;
   2033 
   2034         if (paint_width > rect->width)
   2035             paint_width = rect->width;
   2036 
   2037         gtk_paint_vline(style, drawable,
   2038                         GTK_STATE_NORMAL, cliprect, gParts->toolbarSeparatorWidget,
   2039                         "toolbar",
   2040                         rect->y + rect->height * start_fraction,
   2041                         rect->y + rect->height * end_fraction,
   2042                         rect->x + (rect->width - paint_width) / 2);
   2043     }
   2044 
   2045     return MOZ_GTK_SUCCESS;
   2046 }
   2047 
   2048 static gint
   2049 moz_gtk_tooltip_paint(GdkDrawable* drawable, GdkRectangle* rect,
   2050                       GdkRectangle* cliprect, GtkTextDirection direction)
   2051 {
   2052     GtkStyle* style;
   2053 
   2054     ensure_tooltip_widget();
   2055     gtk_widget_set_direction(gParts->tooltipWidget, direction);
   2056 
   2057     style = gtk_rc_get_style_by_paths(gtk_settings_get_default(),
   2058                                       "gtk-tooltips", "GtkWindow",
   2059                                       GTK_TYPE_WINDOW);
   2060 
   2061     style = gtk_style_attach(style, gParts->tooltipWidget->window);
   2062     TSOffsetStyleGCs(style, rect->x, rect->y);
   2063     gtk_paint_flat_box(style, drawable, GTK_STATE_NORMAL, GTK_SHADOW_OUT,
   2064                        cliprect, gParts->tooltipWidget, "tooltip",
   2065                        rect->x, rect->y, rect->width, rect->height);
   2066 
   2067     return MOZ_GTK_SUCCESS;
   2068 }
   2069 
   2070 static gint
   2071 moz_gtk_resizer_paint(GdkDrawable* drawable, GdkRectangle* rect,
   2072                       GdkRectangle* cliprect, GtkWidgetState* state,
   2073                       GtkTextDirection direction)
   2074 {
   2075     GtkStyle* style;
   2076     GtkStateType state_type = ConvertGtkState(state);
   2077 
   2078     ensure_window_widget();
   2079     gtk_widget_set_direction(gParts->protoWindow, direction);
   2080 
   2081     style = gParts->protoWindow->style;
   2082 
   2083     TSOffsetStyleGCs(style, rect->x, rect->y);
   2084 
   2085     gtk_paint_resize_grip(style, drawable, state_type, cliprect, gParts->protoWindow,
   2086                           NULL, (direction == GTK_TEXT_DIR_LTR) ?
   2087                           GDK_WINDOW_EDGE_SOUTH_EAST :
   2088                           GDK_WINDOW_EDGE_SOUTH_WEST,
   2089                           rect->x, rect->y, rect->width, rect->height);
   2090     return MOZ_GTK_SUCCESS;
   2091 }
   2092 
   2093 static gint
   2094 moz_gtk_frame_paint(GdkDrawable* drawable, GdkRectangle* rect,
   2095                     GdkRectangle* cliprect, GtkTextDirection direction)
   2096 {
   2097     GtkStyle* style;
   2098     GtkShadowType shadow_type;
   2099 
   2100     ensure_frame_widget();
   2101     gtk_widget_set_direction(gParts->frameWidget, direction);
   2102 
   2103     style = gParts->frameWidget->style;
   2104 
   2105     gtk_widget_style_get(gParts->statusbarWidget, "shadow-type", &shadow_type, NULL);
   2106 
   2107     TSOffsetStyleGCs(style, rect->x, rect->y);
   2108     gtk_paint_shadow(style, drawable, GTK_STATE_NORMAL, shadow_type,
   2109                      cliprect, gParts->frameWidget, "frame", rect->x, rect->y,
   2110                      rect->width, rect->height);
   2111 
   2112     return MOZ_GTK_SUCCESS;
   2113 }
   2114 
   2115 static gint
   2116 moz_gtk_progressbar_paint(GdkDrawable* drawable, GdkRectangle* rect,
   2117                           GdkRectangle* cliprect, GtkTextDirection direction)
   2118 {
   2119     GtkStyle* style;
   2120 
   2121     ensure_progress_widget();
   2122     gtk_widget_set_direction(gParts->progresWidget, direction);
   2123 
   2124     style = gParts->progresWidget->style;
   2125 
   2126     TSOffsetStyleGCs(style, rect->x, rect->y);
   2127     gtk_paint_box(style, drawable, GTK_STATE_NORMAL, GTK_SHADOW_IN,
   2128                   cliprect, gParts->progresWidget, "trough", rect->x, rect->y,
   2129                   rect->width, rect->height);
   2130 
   2131     return MOZ_GTK_SUCCESS;
   2132 }
   2133 
   2134 static gint
   2135 moz_gtk_progress_chunk_paint(GdkDrawable* drawable, GdkRectangle* rect,
   2136                              GdkRectangle* cliprect, GtkTextDirection direction)
   2137 {
   2138     GtkStyle* style;
   2139 
   2140     ensure_progress_widget();
   2141     gtk_widget_set_direction(gParts->progresWidget, direction);
   2142 
   2143     style = gParts->progresWidget->style;
   2144 
   2145     TSOffsetStyleGCs(style, rect->x, rect->y);
   2146     gtk_paint_box(style, drawable, GTK_STATE_PRELIGHT, GTK_SHADOW_OUT,
   2147                   cliprect, gParts->progresWidget, "bar", rect->x, rect->y,
   2148                   rect->width, rect->height);
   2149 
   2150     return MOZ_GTK_SUCCESS;
   2151 }
   2152 
   2153 gint
   2154 moz_gtk_get_tab_thickness(void)
   2155 {
   2156     ensure_tab_widget();
   2157     if (YTHICKNESS(gParts->tabWidget->style) < 2)
   2158         return 2; /* some themes don't set ythickness correctly */
   2159 
   2160     return YTHICKNESS(gParts->tabWidget->style);
   2161 }
   2162 
   2163 static gint
   2164 moz_gtk_tab_paint(GdkDrawable* drawable, GdkRectangle* rect,
   2165                   GdkRectangle* cliprect, GtkTabFlags flags,
   2166                   GtkTextDirection direction)
   2167 {
   2168     /* When the tab isn't selected, we just draw a notebook extension.
   2169      * When it is selected, we overwrite the adjacent border of the tabpanel
   2170      * touching the tab with a pierced border (called "the gap") to make the
   2171      * tab appear physically attached to the tabpanel; see details below. */
   2172 
   2173     GtkStyle* style;
   2174 
   2175     ensure_tab_widget();
   2176     gtk_widget_set_direction(gParts->tabWidget, direction);
   2177 
   2178     style = gParts->tabWidget->style;
   2179     TSOffsetStyleGCs(style, rect->x, rect->y);
   2180 
   2181     if ((flags & MOZ_GTK_TAB_SELECTED) == 0) {
   2182         /* Only draw the tab */
   2183         gtk_paint_extension(style, drawable, GTK_STATE_ACTIVE, GTK_SHADOW_OUT,
   2184                             cliprect, gParts->tabWidget, "tab",
   2185                             rect->x, rect->y, rect->width, rect->height,
   2186                             (flags & MOZ_GTK_TAB_BOTTOM) ?
   2187                                 GTK_POS_TOP : GTK_POS_BOTTOM );
   2188     } else {
   2189         /* Draw the tab and the gap
   2190          * We want the gap to be positionned exactly on the tabpanel top
   2191          * border; since tabbox.css may set a negative margin so that the tab
   2192          * frame rect already overlaps the tabpanel frame rect, we need to take
   2193          * that into account when drawing. To that effect, nsNativeThemeGTK
   2194          * passes us this negative margin (bmargin in the graphic below) in the
   2195          * lowest bits of |flags|.  We use it to set gap_voffset, the distance
   2196          * between the top of the gap and the bottom of the tab (resp. the
   2197          * bottom of the gap and the top of the tab when we draw a bottom tab),
   2198          * while ensuring that the gap always touches the border of the tab,
   2199          * i.e. 0 <= gap_voffset <= gap_height, to avoid surprinsing results
   2200          * with big negative or positive margins.
   2201          * Here is a graphical explanation in the case of top tabs:
   2202          *             ___________________________
   2203          *            /                           \
   2204          *           |            T A B            |
   2205          * ----------|. . . . . . . . . . . . . . .|----- top of tabpanel
   2206          *           :    ^       bmargin          :  ^
   2207          *           :    | (-negative margin,     :  |
   2208          *  bottom   :    v  passed in flags)      :  |       gap_height
   2209          *    of  -> :.............................:  |    (the size of the
   2210          * the tab   .       part of the gap       .  |  tabpanel top border)
   2211          *           .      outside of the tab     .  v
   2212          * ----------------------------------------------
   2213          *
   2214          * To draw the gap, we use gtk_paint_box_gap(), see comment in
   2215          * moz_gtk_tabpanels_paint(). This box_gap is made 3 * gap_height tall,
   2216          * which should suffice to ensure that the only visible border is the
   2217          * pierced one.  If the tab is in the middle, we make the box_gap begin
   2218          * a bit to the left of the tab and end a bit to the right, adjusting
   2219          * the gap position so it still is under the tab, because we want the
   2220          * rendering of a gap in the middle of a tabpanel.  This is the role of
   2221          * the gints gap_{l,r}_offset. On the contrary, if the tab is the
   2222          * first, we align the start border of the box_gap with the start
   2223          * border of the tab (left if LTR, right if RTL), by setting the
   2224          * appropriate offset to 0.*/
   2225         gint gap_loffset, gap_roffset, gap_voffset, gap_height;
   2226 
   2227         /* Get height needed by the gap */
   2228         gap_height = moz_gtk_get_tab_thickness();
   2229 
   2230         /* Extract gap_voffset from the first bits of flags */
   2231         gap_voffset = flags & MOZ_GTK_TAB_MARGIN_MASK;
   2232         if (gap_voffset > gap_height)
   2233             gap_voffset = gap_height;
   2234 
   2235         /* Set gap_{l,r}_offset to appropriate values */
   2236         gap_loffset = gap_roffset = 20; /* should be enough */
   2237         if (flags & MOZ_GTK_TAB_FIRST) {
   2238             if (direction == GTK_TEXT_DIR_RTL)
   2239                 gap_roffset = 0;
   2240             else
   2241                 gap_loffset = 0;
   2242         }
   2243 
   2244         if (flags & MOZ_GTK_TAB_BOTTOM) {
   2245             /* Enlarge the cliprect to have room for the full gap height */
   2246             cliprect->height += gap_height - gap_voffset;
   2247             cliprect->y -= gap_height - gap_voffset;
   2248 
   2249             /* Draw the tab */
   2250             gtk_paint_extension(style, drawable, GTK_STATE_NORMAL,
   2251                                 GTK_SHADOW_OUT, cliprect, gParts->tabWidget, "tab",
   2252                                 rect->x, rect->y + gap_voffset, rect->width,
   2253                                 rect->height - gap_voffset, GTK_POS_TOP);
   2254 
   2255             /* Draw the gap; erase with background color before painting in
   2256              * case theme does not */
   2257             gtk_style_apply_default_background(style, drawable, TRUE,
   2258                                                GTK_STATE_NORMAL, cliprect,
   2259                                                rect->x,
   2260                                                rect->y + gap_voffset
   2261                                                        - gap_height,
   2262                                                rect->width, gap_height);
   2263             gtk_paint_box_gap(style, drawable, GTK_STATE_NORMAL, GTK_SHADOW_OUT,
   2264                               cliprect, gParts->tabWidget, "notebook",
   2265                               rect->x - gap_loffset,
   2266                               rect->y + gap_voffset - 3 * gap_height,
   2267                               rect->width + gap_loffset + gap_roffset,
   2268                               3 * gap_height, GTK_POS_BOTTOM,
   2269                               gap_loffset, rect->width);
   2270         } else {
   2271             /* Enlarge the cliprect to have room for the full gap height */
   2272             cliprect->height += gap_height - gap_voffset;
   2273 
   2274             /* Draw the tab */
   2275             gtk_paint_extension(style, drawable, GTK_STATE_NORMAL,
   2276                                 GTK_SHADOW_OUT, cliprect, gParts->tabWidget, "tab",
   2277                                 rect->x, rect->y, rect->width,
   2278                                 rect->height - gap_voffset, GTK_POS_BOTTOM);
   2279 
   2280             /* Draw the gap; erase with background color before painting in
   2281              * case theme does not */
   2282             gtk_style_apply_default_background(style, drawable, TRUE,
   2283                                                GTK_STATE_NORMAL, cliprect,
   2284                                                rect->x,
   2285                                                rect->y + rect->height
   2286                                                        - gap_voffset,
   2287                                                rect->width, gap_height);
   2288             gtk_paint_box_gap(style, drawable, GTK_STATE_NORMAL, GTK_SHADOW_OUT,
   2289                               cliprect, gParts->tabWidget, "notebook",
   2290                               rect->x - gap_loffset,
   2291                               rect->y + rect->height - gap_voffset,
   2292                               rect->width + gap_loffset + gap_roffset,
   2293                               3 * gap_height, GTK_POS_TOP,
   2294                               gap_loffset, rect->width);
   2295         }
   2296 
   2297     }
   2298 
   2299     return MOZ_GTK_SUCCESS;
   2300 }
   2301 
   2302 static gint
   2303 moz_gtk_tabpanels_paint(GdkDrawable* drawable, GdkRectangle* rect,
   2304                         GdkRectangle* cliprect, GtkTextDirection direction)
   2305 {
   2306     /* We use gtk_paint_box_gap() to draw the tabpanels widget. gtk_paint_box()
   2307      * draws an all-purpose box, which a lot of themes render differently.
   2308      * A zero-width gap is still visible in most themes, so we hide it to the
   2309      * left (10px should be enough) */
   2310     GtkStyle* style;
   2311 
   2312     ensure_tab_widget();
   2313     gtk_widget_set_direction(gParts->tabWidget, direction);
   2314 
   2315     style = gParts->tabWidget->style;
   2316 
   2317     TSOffsetStyleGCs(style, rect->x, rect->y);
   2318     gtk_paint_box_gap(style, drawable, GTK_STATE_NORMAL, GTK_SHADOW_OUT,
   2319                       cliprect, gParts->tabWidget, "notebook", rect->x, rect->y,
   2320                       rect->width, rect->height,
   2321                       GTK_POS_TOP, -10, 0);
   2322 
   2323     return MOZ_GTK_SUCCESS;
   2324 }
   2325 
   2326 static gint
   2327 moz_gtk_tab_scroll_arrow_paint(GdkDrawable* drawable, GdkRectangle* rect,
   2328                                GdkRectangle* cliprect, GtkWidgetState* state,
   2329                                GtkArrowType arrow_type,
   2330                                GtkTextDirection direction)
   2331 {
   2332     GtkStateType state_type = ConvertGtkState(state);
   2333     GtkShadowType shadow_type = state->active ? GTK_SHADOW_IN : GTK_SHADOW_OUT;
   2334     GtkStyle* style;
   2335     gint arrow_size = MIN(rect->width, rect->height);
   2336     gint x = rect->x + (rect->width - arrow_size) / 2;
   2337     gint y = rect->y + (rect->height - arrow_size) / 2;
   2338 
   2339     ensure_tab_widget();
   2340 
   2341     style = gParts->tabWidget->style;
   2342     TSOffsetStyleGCs(style, rect->x, rect->y);
   2343 
   2344     if (direction == GTK_TEXT_DIR_RTL) {
   2345         arrow_type = (arrow_type == GTK_ARROW_LEFT) ?
   2346                          GTK_ARROW_RIGHT : GTK_ARROW_LEFT;
   2347     }
   2348 
   2349     gtk_paint_arrow(style, drawable, state_type, shadow_type, NULL,
   2350                     gParts->tabWidget, "notebook", arrow_type, TRUE,
   2351                     x, y, arrow_size, arrow_size);
   2352 
   2353     return MOZ_GTK_SUCCESS;
   2354 }
   2355 
   2356 static gint
   2357 moz_gtk_menu_bar_paint(GdkDrawable* drawable, GdkRectangle* rect,
   2358                        GdkRectangle* cliprect, GtkTextDirection direction)
   2359 {
   2360     GtkStyle* style;
   2361     GtkShadowType shadow_type;
   2362     ensure_menu_bar_widget();
   2363     gtk_widget_set_direction(gParts->menuBarWidget, direction);
   2364 
   2365     gtk_widget_style_get(gParts->menuBarWidget, "shadow-type", &shadow_type, NULL);
   2366 
   2367     style = gParts->menuBarWidget->style;
   2368 
   2369     TSOffsetStyleGCs(style, rect->x, rect->y);
   2370     gtk_style_apply_default_background(style, drawable, TRUE, GTK_STATE_NORMAL,
   2371                                        cliprect, rect->x, rect->y,
   2372                                        rect->width, rect->height);
   2373 
   2374     gtk_paint_box(style, drawable, GTK_STATE_NORMAL, shadow_type,
   2375                   cliprect, gParts->menuBarWidget, "menubar", rect->x, rect->y,
   2376                   rect->width, rect->height);
   2377     return MOZ_GTK_SUCCESS;
   2378 }
   2379 
   2380 static gint
   2381 moz_gtk_menu_popup_paint(GdkDrawable* drawable, GdkRectangle* rect,
   2382                          GdkRectangle* cliprect, GtkTextDirection direction)
   2383 {
   2384     GtkStyle* style;
   2385     ensure_menu_popup_widget();
   2386     gtk_widget_set_direction(gParts->menuPopupWidget, direction);
   2387 
   2388     style = gParts->menuPopupWidget->style;
   2389 
   2390     TSOffsetStyleGCs(style, rect->x, rect->y);
   2391     gtk_style_apply_default_background(style, drawable, TRUE, GTK_STATE_NORMAL,
   2392                                        cliprect, rect->x, rect->y,
   2393                                        rect->width, rect->height);
   2394     gtk_paint_box(style, drawable, GTK_STATE_NORMAL, GTK_SHADOW_OUT,
   2395                   cliprect, gParts->menuPopupWidget, "menu",
   2396                   rect->x, rect->y, rect->width, rect->height);
   2397 
   2398     return MOZ_GTK_SUCCESS;
   2399 }
   2400 
   2401 static gint
   2402 moz_gtk_menu_separator_paint(GdkDrawable* drawable, GdkRectangle* rect,
   2403                              GdkRectangle* cliprect, GtkTextDirection direction)
   2404 {
   2405     GtkStyle* style;
   2406     gboolean wide_separators;
   2407     gint separator_height;
   2408     guint horizontal_padding;
   2409     gint paint_height;
   2410 
   2411     ensure_menu_separator_widget();
   2412     gtk_widget_set_direction(gParts->menuSeparatorWidget, direction);
   2413 
   2414     style = gParts->menuSeparatorWidget->style;
   2415 
   2416     gtk_widget_style_get(gParts->menuSeparatorWidget,
   2417                          "wide-separators",    &wide_separators,
   2418                          "separator-height",   &separator_height,
   2419                          "horizontal-padding", &horizontal_padding,
   2420                          NULL);
   2421 
   2422     TSOffsetStyleGCs(style, rect->x, rect->y);
   2423 
   2424     if (wide_separators) {
   2425         if (separator_height > rect->height)
   2426             separator_height = rect->height;
   2427 
   2428         gtk_paint_box(style, drawable,
   2429                       GTK_STATE_NORMAL, GTK_SHADOW_ETCHED_OUT,
   2430                       cliprect, gParts->menuSeparatorWidget, "hseparator",
   2431                       rect->x + horizontal_padding + style->xthickness,
   2432                       rect->y + (rect->height - separator_height - style->ythickness) / 2,
   2433                       rect->width - 2 * (horizontal_padding + style->xthickness),
   2434                       separator_height);
   2435     } else {
   2436         paint_height = style->ythickness;
   2437         if (paint_height > rect->height)
   2438             paint_height = rect->height;
   2439 
   2440         gtk_paint_hline(style, drawable,
   2441                         GTK_STATE_NORMAL, cliprect, gParts->menuSeparatorWidget,
   2442                         "menuitem",
   2443                         rect->x + horizontal_padding + style->xthickness,
   2444                         rect->x + rect->width - horizontal_padding - style->xthickness - 1,
   2445                         rect->y + (rect->height - style->ythickness) / 2);
   2446     }
   2447 
   2448     return MOZ_GTK_SUCCESS;
   2449 }
   2450 
   2451 static gint
   2452 moz_gtk_menu_item_paint(GdkDrawable* drawable, GdkRectangle* rect,
   2453                         GdkRectangle* cliprect, GtkWidgetState* state,
   2454                         gint flags, GtkTextDirection direction)
   2455 {
   2456     GtkStyle* style;
   2457     GtkShadowType shadow_type;
   2458     GtkWidget* item_widget;
   2459 
   2460     if (state->inHover && !state->disabled) {
   2461         if (flags & MOZ_TOPLEVEL_MENU_ITEM) {
   2462             ensure_menu_bar_item_widget();
   2463             item_widget = gParts->menuBarItemWidget;
   2464         } else {
   2465             ensure_menu_item_widget();
   2466             item_widget = gParts->menuItemWidget;
   2467         }
   2468         gtk_widget_set_direction(item_widget, direction);
   2469 
   2470         style = item_widget->style;
   2471         TSOffsetStyleGCs(style, rect->x, rect->y);
   2472 
   2473         gtk_widget_style_get(item_widget, "selected-shadow-type",
   2474                              &shadow_type, NULL);
   2475 
   2476         gtk_paint_box(style, drawable, GTK_STATE_PRELIGHT, shadow_type,
   2477                       cliprect, item_widget, "menuitem", rect->x, rect->y,
   2478                       rect->width, rect->height);
   2479     }
   2480 
   2481     return MOZ_GTK_SUCCESS;
   2482 }
   2483 
   2484 static gint
   2485 moz_gtk_menu_arrow_paint(GdkDrawable* drawable, GdkRectangle* rect,
   2486                          GdkRectangle* cliprect, GtkWidgetState* state,
   2487                          GtkTextDirection direction)
   2488 {
   2489     GtkStyle* style;
   2490     GtkStateType state_type = ConvertGtkState(state);
   2491 
   2492     ensure_menu_item_widget();
   2493     gtk_widget_set_direction(gParts->menuItemWidget, direction);
   2494 
   2495     style = gParts->menuItemWidget->style;
   2496 
   2497     TSOffsetStyleGCs(style, rect->x, rect->y);
   2498     gtk_paint_arrow(style, drawable, state_type,
   2499                     (state_type == GTK_STATE_PRELIGHT) ? GTK_SHADOW_IN : GTK_SHADOW_OUT,
   2500                     cliprect, gParts->menuItemWidget, "menuitem",
   2501                     (direction == GTK_TEXT_DIR_LTR) ? GTK_ARROW_RIGHT : GTK_ARROW_LEFT,
   2502                     TRUE, rect->x, rect->y, rect->width, rect->height);
   2503 
   2504     return MOZ_GTK_SUCCESS;
   2505 }
   2506 
   2507 static gint
   2508 moz_gtk_check_menu_item_paint(GdkDrawable* drawable, GdkRectangle* rect,
   2509                               GdkRectangle* cliprect, GtkWidgetState* state,
   2510                               gboolean checked, gboolean isradio,
   2511                               GtkTextDirection direction)
   2512 {
   2513     GtkStateType state_type = ConvertGtkState(state);
   2514     GtkStyle* style;
   2515     GtkShadowType shadow_type = (checked)?GTK_SHADOW_IN:GTK_SHADOW_OUT;
   2516     gint offset;
   2517     gint indicator_size;
   2518     gint x, y;
   2519 
   2520     moz_gtk_menu_item_paint(drawable, rect, cliprect, state, FALSE, direction);
   2521 
   2522     ensure_check_menu_item_widget();
   2523     gtk_widget_set_direction(gParts->checkMenuItemWidget, direction);
   2524 
   2525     gtk_widget_style_get (gParts->checkMenuItemWidget,
   2526                           "indicator-size", &indicator_size,
   2527                           NULL);
   2528 
   2529     if (checked || GTK_CHECK_MENU_ITEM(gParts->checkMenuItemWidget)->always_show_toggle) {
   2530       style = gParts->checkMenuItemWidget->style;
   2531 
   2532       offset = GTK_CONTAINER(gParts->checkMenuItemWidget)->border_width +
   2533              gParts->checkMenuItemWidget->style->xthickness + 2;
   2534 
   2535       /* while normally this "3" would be the horizontal-padding style value, passing it to Gecko
   2536          as the value of menuitem padding causes problems with dropdowns (bug 406129), so in the menu.css
   2537          file this is hardcoded as 3px. Yes it sucks, but we don't really have a choice. */
   2538       x = (direction == GTK_TEXT_DIR_RTL) ?
   2539             rect->width - indicator_size - offset - 3: rect->x + offset + 3;
   2540       y = rect->y + (rect->height - indicator_size) / 2;
   2541 
   2542       TSOffsetStyleGCs(style, x, y);
   2543       gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(gParts->checkMenuItemWidget),
   2544                                      checked);
   2545 
   2546       if (isradio) {
   2547         gtk_paint_option(style, drawable, state_type, shadow_type, cliprect,
   2548                          gParts->checkMenuItemWidget, "option",
   2549                          x, y, indicator_size, indicator_size);
   2550       } else {
   2551         gtk_paint_check(style, drawable, state_type, shadow_type, cliprect,
   2552                         gParts->checkMenuItemWidget, "check",
   2553                         x, y, indicator_size, indicator_size);
   2554       }
   2555     }
   2556 
   2557     return MOZ_GTK_SUCCESS;
   2558 }
   2559 
   2560 static gint
   2561 moz_gtk_window_paint(GdkDrawable* drawable, GdkRectangle* rect,
   2562                      GdkRectangle* cliprect, GtkTextDirection direction)
   2563 {
   2564     GtkStyle* style;
   2565 
   2566     ensure_window_widget();
   2567     gtk_widget_set_direction(gParts->protoWindow, direction);
   2568 
   2569     style = gParts->protoWindow->style;
   2570 
   2571     TSOffsetStyleGCs(style, rect->x, rect->y);
   2572     gtk_style_apply_default_background(style, drawable, TRUE,
   2573                                        GTK_STATE_NORMAL,
   2574                                        cliprect, rect->x, rect->y,
   2575                                        rect->width, rect->height);
   2576     return MOZ_GTK_SUCCESS;
   2577 }
   2578 
   2579 gint
   2580 moz_gtk_get_widget_border(GtkThemeWidgetType widget, gint* left, gint* top,
   2581                           gint* right, gint* bottom, GtkTextDirection direction,
   2582                           gboolean inhtml)
   2583 {
   2584     GtkWidget* w;
   2585 
   2586     switch (widget) {
   2587     case MOZ_GTK_BUTTON:
   2588         {
   2589             GtkBorder inner_border;
   2590             gboolean interior_focus;
   2591             gint focus_width, focus_pad;
   2592 
   2593             ensure_button_widget();
   2594             *left = *top = *right = *bottom = GTK_CONTAINER(gParts->buttonWidget)->border_width;
   2595 
   2596             /* Don't add this padding in HTML, otherwise the buttons will
   2597                become too big and stuff the layout. */
   2598             if (!inhtml) {
   2599                 moz_gtk_widget_get_focus(gParts->buttonWidget, &interior_focus, &focus_width, &focus_pad);
   2600                 moz_gtk_button_get_inner_border(gParts->buttonWidget, &inner_border);
   2601                 *left += focus_width + focus_pad + inner_border.left;
   2602                 *right += focus_width + focus_pad + inner_border.right;
   2603                 *top += focus_width + focus_pad + inner_border.top;
   2604                 *bottom += focus_width + focus_pad + inner_border.bottom;
   2605             }
   2606 
   2607             *left += gParts->buttonWidget->style->xthickness;
   2608             *right += gParts->buttonWidget->style->xthickness;
   2609             *top += gParts->buttonWidget->style->ythickness;
   2610             *bottom += gParts->buttonWidget->style->ythickness;
   2611             return MOZ_GTK_SUCCESS;
   2612         }
   2613     case MOZ_GTK_ENTRY:
   2614         ensure_entry_widget();
   2615         w = gParts->entryWidget;
   2616         break;
   2617     case MOZ_GTK_TREEVIEW:
   2618         ensure_tree_view_widget();
   2619         w = gParts->treeViewWidget;
   2620         break;
   2621     case MOZ_GTK_TREE_HEADER_CELL:
   2622         {
   2623             /* A Tree Header in GTK is just a different styled button
   2624              * It must be placed in a TreeView for getting the correct style
   2625              * assigned.
   2626              * That is why the following code is the same as for MOZ_GTK_BUTTON.
   2627              * */
   2628 
   2629             GtkBorder inner_border;
   2630             gboolean interior_focus;
   2631             gint focus_width, focus_pad;
   2632 
   2633             ensure_tree_header_cell_widget();
   2634             *left = *top = *right = *bottom = GTK_CONTAINER(gParts->treeHeaderCellWidget)->border_width;
   2635 
   2636             moz_gtk_widget_get_focus(gParts->treeHeaderCellWidget, &interior_focus, &focus_width, &focus_pad);
   2637             moz_gtk_button_get_inner_border(gParts->treeHeaderCellWidget, &inner_border);
   2638             *left += focus_width + focus_pad + inner_border.left;
   2639             *right += focus_width + focus_pad + inner_border.right;
   2640             *top += focus_width + focus_pad + inner_border.top;
   2641             *bottom += focus_width + focus_pad + inner_border.bottom;
   2642 
   2643             *left += gParts->treeHeaderCellWidget->style->xthickness;
   2644             *right += gParts->treeHeaderCellWidget->style->xthickness;
   2645             *top += gParts->treeHeaderCellWidget->style->ythickness;
   2646             *bottom += gParts->treeHeaderCellWidget->style->ythickness;
   2647             return MOZ_GTK_SUCCESS;
   2648         }
   2649     case MOZ_GTK_TREE_HEADER_SORTARROW:
   2650         ensure_tree_header_cell_widget();
   2651         w = gParts->treeHeaderSortArrowWidget;
   2652         break;
   2653     case MOZ_GTK_DROPDOWN_ENTRY:
   2654         ensure_combo_box_entry_widgets();
   2655         w = gParts->comboBoxEntryTextareaWidget;
   2656         break;
   2657     case MOZ_GTK_DROPDOWN_ARROW:
   2658         ensure_combo_box_entry_widgets();
   2659         w = gParts->comboBoxEntryButtonWidget;
   2660         break;
   2661     case MOZ_GTK_DROPDOWN:
   2662         {
   2663             /* We need to account for the arrow on the dropdown, so text
   2664              * doesn't come too close to the arrow, or in some cases spill
   2665              * into the arrow. */
   2666             gboolean ignored_interior_focus, wide_separators;
   2667             gint focus_width, focus_pad, separator_width;
   2668             GtkRequisition arrow_req;
   2669 
   2670             ensure_combo_box_widgets();
   2671 
   2672             *left = GTK_CONTAINER(gParts->comboBoxButtonWidget)->border_width;
   2673 
   2674             if (!inhtml) {
   2675                 moz_gtk_widget_get_focus(gParts->comboBoxButtonWidget,
   2676                                          &ignored_interior_focus,
   2677                                          &focus_width, &focus_pad);
   2678                 *left += focus_width + focus_pad;
   2679             }
   2680 
   2681             *top = *left + gParts->comboBoxButtonWidget->style->ythickness;
   2682             *left += gParts->comboBoxButtonWidget->style->xthickness;
   2683 
   2684             *right = *left; *bottom = *top;
   2685 
   2686             /* If there is no separator, don't try to count its width. */
   2687             separator_width = 0;
   2688             if (gParts->comboBoxSeparatorWidget) {
   2689                 gtk_widget_style_get(gParts->comboBoxSeparatorWidget,
   2690                                      "wide-separators", &wide_separators,
   2691                                      "separator-width", &separator_width,
   2692                                      NULL);
   2693 
   2694                 if (!wide_separators)
   2695                     separator_width =
   2696                         XTHICKNESS(gParts->comboBoxSeparatorWidget->style);
   2697             }
   2698 
   2699             gtk_widget_size_request(gParts->comboBoxArrowWidget, &arrow_req);
   2700 
   2701             if (direction == GTK_TEXT_DIR_RTL)
   2702                 *left += separator_width + arrow_req.width;
   2703             else
   2704                 *right += separator_width + arrow_req.width;
   2705 
   2706             return MOZ_GTK_SUCCESS;
   2707         }
   2708     case MOZ_GTK_TABPANELS:
   2709         ensure_tab_widget();
   2710         w = gParts->tabWidget;
   2711         break;
   2712     case MOZ_GTK_PROGRESSBAR:
   2713         ensure_progress_widget();
   2714         w = gParts->progresWidget;
   2715         break;
   2716     case MOZ_GTK_SPINBUTTON_ENTRY:
   2717     case MOZ_GTK_SPINBUTTON_UP:
   2718     case MOZ_GTK_SPINBUTTON_DOWN:
   2719         ensure_spin_widget();
   2720         w = gParts->spinWidget;
   2721         break;
   2722     case MOZ_GTK_SCALE_HORIZONTAL:
   2723         ensure_scale_widget();
   2724         w = gParts->hScaleWidget;
   2725         break;
   2726     case MOZ_GTK_SCALE_VERTICAL:
   2727         ensure_scale_widget();
   2728         w = gParts->vScaleWidget;
   2729         break;
   2730     case MOZ_GTK_FRAME:
   2731         ensure_frame_widget();
   2732         w = gParts->frameWidget;
   2733         break;
   2734     case MOZ_GTK_CHECKBUTTON_LABEL:
   2735     case MOZ_GTK_RADIOBUTTON_LABEL:
   2736         {
   2737             gboolean interior_focus;
   2738             gint focus_width, focus_pad;
   2739 
   2740             /* If the focus is interior, then the label has a border of
   2741                (focus_width + focus_pad). */
   2742             if (widget == MOZ_GTK_CHECKBUTTON_LABEL) {
   2743                 ensure_checkbox_widget();
   2744                 moz_gtk_widget_get_focus(gParts->checkboxWidget, &interior_focus,
   2745                                            &focus_width, &focus_pad);
   2746             }
   2747             else {
   2748                 ensure_radiobutton_widget();
   2749                 moz_gtk_widget_get_focus(gParts->radiobuttonWidget, &interior_focus,
   2750                                         &focus_width, &focus_pad);
   2751             }
   2752 
   2753             if (interior_focus)
   2754                 *left = *top = *right = *bottom = (focus_width + focus_pad);
   2755             else
   2756                 *left = *top = *right = *bottom = 0;
   2757 
   2758             return MOZ_GTK_SUCCESS;
   2759         }
   2760 
   2761     case MOZ_GTK_CHECKBUTTON_CONTAINER:
   2762     case MOZ_GTK_RADIOBUTTON_CONTAINER:
   2763         {
   2764             gboolean interior_focus;
   2765             gint focus_width, focus_pad;
   2766 
   2767             /* If the focus is _not_ interior, then the container has a border
   2768                of (focus_width + focus_pad). */
   2769             if (widget == MOZ_GTK_CHECKBUTTON_CONTAINER) {
   2770                 ensure_checkbox_widget();
   2771                 moz_gtk_widget_get_focus(gParts->checkboxWidget, &interior_focus,
   2772                                            &focus_width, &focus_pad);
   2773                 w = gParts->checkboxWidget;
   2774             } else {
   2775                 ensure_radiobutton_widget();
   2776                 moz_gtk_widget_get_focus(gParts->radiobuttonWidget, &interior_focus,
   2777                                         &focus_width, &focus_pad);
   2778                 w = gParts->radiobuttonWidget;
   2779             }
   2780 
   2781             *left = *top = *right = *bottom = GTK_CONTAINER(w)->border_width;
   2782 
   2783             if (!interior_focus) {
   2784                 *left += (focus_width + focus_pad);
   2785                 *right += (focus_width + focus_pad);
   2786                 *top += (focus_width + focus_pad);
   2787                 *bottom += (focus_width + focus_pad);
   2788             }
   2789 
   2790             return MOZ_GTK_SUCCESS;
   2791         }
   2792     case MOZ_GTK_MENUPOPUP:
   2793         ensure_menu_popup_widget();
   2794         w = gParts->menuPopupWidget;
   2795         break;
   2796     case MOZ_GTK_MENUITEM:
   2797         ensure_menu_item_widget();
   2798         ensure_menu_bar_item_widget();
   2799         w = gParts->menuItemWidget;
   2800         break;
   2801     case MOZ_GTK_CHECKMENUITEM:
   2802     case MOZ_GTK_RADIOMENUITEM:
   2803         ensure_check_menu_item_widget();
   2804         w = gParts->checkMenuItemWidget;
   2805         break;
   2806     case MOZ_GTK_TAB:
   2807         ensure_tab_widget();
   2808         w = gParts->tabWidget;
   2809         break;
   2810     /* These widgets have no borders, since they are not containers. */
   2811     case MOZ_GTK_SPLITTER_HORIZONTAL:
   2812     case MOZ_GTK_SPLITTER_VERTICAL:
   2813     case MOZ_GTK_CHECKBUTTON:
   2814     case MOZ_GTK_RADIOBUTTON:
   2815     case MOZ_GTK_SCROLLBAR_BUTTON:
   2816     case MOZ_GTK_SCROLLBAR_TRACK_HORIZONTAL:
   2817     case MOZ_GTK_SCROLLBAR_TRACK_VERTICAL:
   2818     case MOZ_GTK_SCROLLBAR_THUMB_HORIZONTAL:
   2819     case MOZ_GTK_SCROLLBAR_THUMB_VERTICAL:
   2820     case MOZ_GTK_SCALE_THUMB_HORIZONTAL:
   2821     case MOZ_GTK_SCALE_THUMB_VERTICAL:
   2822     case MOZ_GTK_GRIPPER:
   2823     case MOZ_GTK_PROGRESS_CHUNK:
   2824     case MOZ_GTK_EXPANDER:
   2825     case MOZ_GTK_TREEVIEW_EXPANDER:
   2826     case MOZ_GTK_TOOLBAR_SEPARATOR:
   2827     case MOZ_GTK_MENUSEPARATOR:
   2828     /* These widgets have no borders.*/
   2829     case MOZ_GTK_SPINBUTTON:
   2830     case MOZ_GTK_TOOLTIP:
   2831     case MOZ_GTK_WINDOW:
   2832     case MOZ_GTK_RESIZER:
   2833     case MOZ_GTK_MENUARROW:
   2834     case MOZ_GTK_TOOLBARBUTTON_ARROW:
   2835     case MOZ_GTK_TOOLBAR:
   2836     case MOZ_GTK_MENUBAR:
   2837     case MOZ_GTK_TAB_SCROLLARROW:
   2838     case MOZ_GTK_ENTRY_CARET:
   2839         *left = *top = *right = *bottom = 0;
   2840         return MOZ_GTK_SUCCESS;
   2841     default:
   2842         g_warning("Unsupported widget type: %d", widget);
   2843         return MOZ_GTK_UNKNOWN_WIDGET;
   2844     }
   2845 
   2846     *right = *left = XTHICKNESS(w->style);
   2847     *bottom = *top = YTHICKNESS(w->style);
   2848 
   2849     return MOZ_GTK_SUCCESS;
   2850 }
   2851 
   2852 gint
   2853 moz_gtk_get_combo_box_entry_button_size(gint* width, gint* height)
   2854 {
   2855     /*
   2856      * We get the requisition of the drop down button, which includes
   2857      * all padding, border and focus line widths the button uses,
   2858      * as well as the minimum arrow size and its padding
   2859      * */
   2860     GtkRequisition requisition;
   2861     ensure_combo_box_entry_widgets();
   2862 
   2863     gtk_widget_size_request(gParts->comboBoxEntryButtonWidget, &requisition);
   2864     *width = requisition.width;
   2865     *height = requisition.height;
   2866 
   2867     return MOZ_GTK_SUCCESS;
   2868 }
   2869 
   2870 gint
   2871 moz_gtk_get_tab_scroll_arrow_size(gint* width, gint* height)
   2872 {
   2873     gint arrow_size;
   2874 
   2875     ensure_tab_widget();
   2876     gtk_widget_style_get(gParts->tabWidget,
   2877                          "scroll-arrow-hlength", &arrow_size,
   2878                          NULL);
   2879 
   2880     *height = *width = arrow_size;
   2881 
   2882     return MOZ_GTK_SUCCESS;
   2883 }
   2884 
   2885 gint
   2886 moz_gtk_get_downarrow_size(gint* width, gint* height)
   2887 {
   2888     GtkRequisition requisition;
   2889     ensure_button_arrow_widget();
   2890 
   2891     gtk_widget_size_request(gParts->buttonArrowWidget, &requisition);
   2892     *width = requisition.width;
   2893     *height = requisition.height;
   2894 
   2895     return MOZ_GTK_SUCCESS;
   2896 }
   2897 
   2898 gint
   2899 moz_gtk_get_toolbar_separator_width(gint* size)
   2900 {
   2901     gboolean wide_separators;
   2902     gint separator_width;
   2903     GtkStyle* style;
   2904 
   2905     ensure_toolbar_widget();
   2906 
   2907     style = gParts->toolbarWidget->style;
   2908 
   2909     gtk_widget_style_get(gParts->toolbarWidget,
   2910                          "space-size", size,
   2911                          "wide-separators",  &wide_separators,
   2912                          "separator-width", &separator_width,
   2913                          NULL);
   2914 
   2915     /* Just in case... */
   2916     *size = MAX(*size, (wide_separators ? separator_width : style->xthickness));
   2917 
   2918     return MOZ_GTK_SUCCESS;
   2919 }
   2920 
   2921 gint
   2922 moz_gtk_get_expander_size(gint* size)
   2923 {
   2924     ensure_expander_widget();
   2925     gtk_widget_style_get(gParts->expanderWidget,
   2926                          "expander-size", size,
   2927                          NULL);
   2928 
   2929     return MOZ_GTK_SUCCESS;
   2930 }
   2931 
   2932 gint
   2933 moz_gtk_get_treeview_expander_size(gint* size)
   2934 {
   2935     ensure_tree_view_widget();
   2936     gtk_widget_style_get(gParts->treeViewWidget,
   2937                          "expander-size", size,
   2938                          NULL);
   2939 
   2940     return MOZ_GTK_SUCCESS;
   2941 }
   2942 
   2943 gint
   2944 moz_gtk_get_menu_separator_height(gint *size)
   2945 {
   2946     gboolean wide_separators;
   2947     gint     separator_height;
   2948 
   2949     ensure_menu_separator_widget();
   2950 
   2951     gtk_widget_style_get(gParts->menuSeparatorWidget,
   2952                           "wide-separators",  &wide_separators,
   2953                           "separator-height", &separator_height,
   2954                           NULL);
   2955 
   2956     if (wide_separators)
   2957         *size = separator_height + gParts->menuSeparatorWidget->style->ythickness;
   2958     else
   2959         *size = gParts->menuSeparatorWidget->style->ythickness * 2;
   2960 
   2961     return MOZ_GTK_SUCCESS;
   2962 }
   2963 
   2964 gint
   2965 moz_gtk_get_scalethumb_metrics(GtkOrientation orient, gint* thumb_length, gint* thumb_height)
   2966 {
   2967   GtkWidget* widget;
   2968 
   2969   ensure_scale_widget();
   2970   widget = ((orient == GTK_ORIENTATION_HORIZONTAL) ? gParts->hScaleWidget : gParts->vScaleWidget);
   2971 
   2972   gtk_widget_style_get (widget,
   2973                         "slider_length", thumb_length,
   2974                         "slider_width", thumb_height,
   2975                         NULL);
   2976 
   2977   return MOZ_GTK_SUCCESS;
   2978 }
   2979 
   2980 gint
   2981 moz_gtk_get_scrollbar_metrics(MozGtkScrollbarMetrics *metrics)
   2982 {
   2983     ensure_scrollbar_widget();
   2984 
   2985     gtk_widget_style_get (gParts->horizScrollbarWidget,
   2986                           "slider_width", &metrics->slider_width,
   2987                           "trough_border", &metrics->trough_border,
   2988                           "stepper_size", &metrics->stepper_size,
   2989                           "stepper_spacing", &metrics->stepper_spacing,
   2990                           NULL);
   2991 
   2992     metrics->min_slider_size =
   2993         GTK_RANGE(gParts->horizScrollbarWidget)->min_slider_size;
   2994 
   2995     return MOZ_GTK_SUCCESS;
   2996 }
   2997 
   2998 gboolean
   2999 moz_gtk_images_in_menus()
   3000 {
   3001     gboolean result;
   3002     GtkSettings* settings;
   3003 
   3004     ensure_image_menu_item_widget();
   3005     settings = gtk_widget_get_settings(gParts->imageMenuItemWidget);
   3006 
   3007     g_object_get(settings, "gtk-menu-images", &result, NULL);
   3008     return result;
   3009 }
   3010 
   3011 gint
   3012 moz_gtk_widget_paint(GtkThemeWidgetType widget, GdkDrawable* drawable,
   3013                      GdkRectangle* rect, GdkRectangle* cliprect,
   3014                      GtkWidgetState* state, gint flags,
   3015                      GtkTextDirection direction)
   3016 {
   3017     switch (widget) {
   3018     case MOZ_GTK_BUTTON:
   3019         if (state->depressed) {
   3020             ensure_toggle_button_widget();
   3021             return moz_gtk_button_paint(drawable, rect, cliprect, state,
   3022                                         (GtkReliefStyle) flags,
   3023                                         gParts->toggleButtonWidget, direction);
   3024         }
   3025         ensure_button_widget();
   3026         return moz_gtk_button_paint(drawable, rect, cliprect, state,
   3027                                     (GtkReliefStyle) flags, gParts->buttonWidget,
   3028                                     direction);
   3029         break;
   3030     case MOZ_GTK_CHECKBUTTON:
   3031     case MOZ_GTK_RADIOBUTTON:
   3032         return moz_gtk_toggle_paint(drawable, rect, cliprect, state,
   3033                                     !!(flags & MOZ_GTK_WIDGET_CHECKED),
   3034                                     !!(flags & MOZ_GTK_WIDGET_INCONSISTENT),
   3035                                     (widget == MOZ_GTK_RADIOBUTTON),
   3036                                     direction);
   3037         break;
   3038     case MOZ_GTK_SCROLLBAR_BUTTON:
   3039         return moz_gtk_scrollbar_button_paint(drawable, rect, cliprect, state,
   3040                                               (GtkScrollbarButtonFlags) flags,
   3041                                               direction);
   3042         break;
   3043     case MOZ_GTK_SCROLLBAR_TRACK_HORIZONTAL:
   3044     case MOZ_GTK_SCROLLBAR_TRACK_VERTICAL:
   3045         return moz_gtk_scrollbar_trough_paint(widget, drawable, rect,
   3046                                               cliprect, state, direction);
   3047         break;
   3048     case MOZ_GTK_SCROLLBAR_THUMB_HORIZONTAL:
   3049     case MOZ_GTK_SCROLLBAR_THUMB_VERTICAL:
   3050         return moz_gtk_scrollbar_thumb_paint(widget, drawable, rect,
   3051                                              cliprect, state, direction);
   3052         break;
   3053     case MOZ_GTK_SCALE_HORIZONTAL:
   3054     case MOZ_GTK_SCALE_VERTICAL:
   3055         return moz_gtk_scale_paint(drawable, rect, cliprect, state,
   3056                                    (GtkOrientation) flags, direction);
   3057         break;
   3058     case MOZ_GTK_SCALE_THUMB_HORIZONTAL:
   3059     case MOZ_GTK_SCALE_THUMB_VERTICAL:
   3060         return moz_gtk_scale_thumb_paint(drawable, rect, cliprect, state,
   3061                                          (GtkOrientation) flags, direction);
   3062         break;
   3063     case MOZ_GTK_SPINBUTTON:
   3064         return moz_gtk_spin_paint(drawable, rect, direction);
   3065         break;
   3066     case MOZ_GTK_SPINBUTTON_UP:
   3067     case MOZ_GTK_SPINBUTTON_DOWN:
   3068         return moz_gtk_spin_updown_paint(drawable, rect,
   3069                                          (widget == MOZ_GTK_SPINBUTTON_DOWN),
   3070                                          state, direction);
   3071         break;
   3072     case MOZ_GTK_SPINBUTTON_ENTRY:
   3073         ensure_spin_widget();
   3074         return moz_gtk_entry_paint(drawable, rect, cliprect, state,
   3075                                    gParts->spinWidget, direction);
   3076         break;
   3077     case MOZ_GTK_GRIPPER:
   3078         return moz_gtk_gripper_paint(drawable, rect, cliprect, state,
   3079                                      direction);
   3080         break;
   3081     case MOZ_GTK_TREEVIEW:
   3082         return moz_gtk_treeview_paint(drawable, rect, cliprect, state,
   3083                                       direction);
   3084         break;
   3085     case MOZ_GTK_TREE_HEADER_CELL:
   3086         return moz_gtk_tree_header_cell_paint(drawable, rect, cliprect, state,
   3087                                               flags, direction);
   3088         break;
   3089     case MOZ_GTK_TREE_HEADER_SORTARROW:
   3090         return moz_gtk_tree_header_sort_arrow_paint(drawable, rect, cliprect,
   3091                                                     state,
   3092                                                     (GtkArrowType) flags,
   3093                                                     direction);
   3094         break;
   3095     case MOZ_GTK_TREEVIEW_EXPANDER:
   3096         return moz_gtk_treeview_expander_paint(drawable, rect, cliprect, state,
   3097                                                (GtkExpanderStyle) flags, direction);
   3098         break;
   3099     case MOZ_GTK_EXPANDER:
   3100         return moz_gtk_expander_paint(drawable, rect, cliprect, state,
   3101                                       (GtkExpanderStyle) flags, direction);
   3102         break;
   3103     case MOZ_GTK_ENTRY:
   3104         ensure_entry_widget();
   3105         return moz_gtk_entry_paint(drawable, rect, cliprect, state,
   3106                                    gParts->entryWidget, direction);
   3107         break;
   3108     case MOZ_GTK_ENTRY_CARET:
   3109         return moz_gtk_caret_paint(drawable, rect, cliprect, direction);
   3110         break;
   3111     case MOZ_GTK_DROPDOWN:
   3112         return moz_gtk_combo_box_paint(drawable, rect, cliprect, state,
   3113                                        (gboolean) flags, direction);
   3114         break;
   3115     case MOZ_GTK_DROPDOWN_ARROW:
   3116         return moz_gtk_combo_box_entry_button_paint(drawable, rect, cliprect,
   3117                                                     state, flags, direction);
   3118         break;
   3119     case MOZ_GTK_DROPDOWN_ENTRY:
   3120         ensure_combo_box_entry_widgets();
   3121         return moz_gtk_entry_paint(drawable, rect, cliprect, state,
   3122                                    gParts->comboBoxEntryTextareaWidget, direction);
   3123         break;
   3124     case MOZ_GTK_CHECKBUTTON_CONTAINER:
   3125     case MOZ_GTK_RADIOBUTTON_CONTAINER:
   3126         return moz_gtk_container_paint(drawable, rect, cliprect, state,
   3127                                        (widget == MOZ_GTK_RADIOBUTTON_CONTAINER),
   3128                                        direction);
   3129         break;
   3130     case MOZ_GTK_CHECKBUTTON_LABEL:
   3131     case MOZ_GTK_RADIOBUTTON_LABEL:
   3132         return moz_gtk_toggle_label_paint(drawable, rect, cliprect, state,
   3133                                           (widget == MOZ_GTK_RADIOBUTTON_LABEL),
   3134                                           direction);
   3135         break;
   3136     case MOZ_GTK_TOOLBAR:
   3137         return moz_gtk_toolbar_paint(drawable, rect, cliprect, direction);
   3138         break;
   3139     case MOZ_GTK_TOOLBAR_SEPARATOR:
   3140         return moz_gtk_toolbar_separator_paint(drawable, rect, cliprect,
   3141                                                direction);
   3142         break;
   3143     case MOZ_GTK_TOOLTIP:
   3144         return moz_gtk_tooltip_paint(drawable, rect, cliprect, direction);
   3145         break;
   3146     case MOZ_GTK_FRAME:
   3147         return moz_gtk_frame_paint(drawable, rect, cliprect, direction);
   3148         break;
   3149     case MOZ_GTK_RESIZER:
   3150         return moz_gtk_resizer_paint(drawable, rect, cliprect, state,
   3151                                      direction);
   3152         break;
   3153     case MOZ_GTK_PROGRESSBAR:
   3154         return moz_gtk_progressbar_paint(drawable, rect, cliprect, direction);
   3155         break;
   3156     case MOZ_GTK_PROGRESS_CHUNK:
   3157         return moz_gtk_progress_chunk_paint(drawable, rect, cliprect,
   3158                                             direction);
   3159         break;
   3160     case MOZ_GTK_TAB:
   3161         return moz_gtk_tab_paint(drawable, rect, cliprect,
   3162                                  (GtkTabFlags) flags, direction);
   3163         break;
   3164     case MOZ_GTK_TABPANELS:
   3165         return moz_gtk_tabpanels_paint(drawable, rect, cliprect, direction);
   3166         break;
   3167     case MOZ_GTK_TAB_SCROLLARROW:
   3168         return moz_gtk_tab_scroll_arrow_paint(drawable, rect, cliprect, state,
   3169                                               (GtkArrowType) flags, direction);
   3170         break;
   3171     case MOZ_GTK_MENUBAR:
   3172         return moz_gtk_menu_bar_paint(drawable, rect, cliprect, direction);
   3173         break;
   3174     case MOZ_GTK_MENUPOPUP:
   3175         return moz_gtk_menu_popup_paint(drawable, rect, cliprect, direction);
   3176         break;
   3177     case MOZ_GTK_MENUSEPARATOR:
   3178         return moz_gtk_menu_separator_paint(drawable, rect, cliprect,
   3179                                             direction);
   3180         break;
   3181     case MOZ_GTK_MENUITEM:
   3182         return moz_gtk_menu_item_paint(drawable, rect, cliprect, state, flags,
   3183                                        direction);
   3184         break;
   3185     case MOZ_GTK_MENUARROW:
   3186         return moz_gtk_menu_arrow_paint(drawable, rect, cliprect, state,
   3187                                         direction);
   3188         break;
   3189     case MOZ_GTK_TOOLBARBUTTON_ARROW:
   3190         return moz_gtk_downarrow_paint(drawable, rect, cliprect, state);
   3191         break;
   3192     case MOZ_GTK_CHECKMENUITEM:
   3193     case MOZ_GTK_RADIOMENUITEM:
   3194         return moz_gtk_check_menu_item_paint(drawable, rect, cliprect, state,
   3195                                              (gboolean) flags,
   3196                                              (widget == MOZ_GTK_RADIOMENUITEM),
   3197                                              direction);
   3198         break;
   3199     case MOZ_GTK_SPLITTER_HORIZONTAL:
   3200         return moz_gtk_vpaned_paint(drawable, rect, cliprect, state);
   3201         break;
   3202     case MOZ_GTK_SPLITTER_VERTICAL:
   3203         return moz_gtk_hpaned_paint(drawable, rect, cliprect, state);
   3204         break;
   3205     case MOZ_GTK_WINDOW:
   3206         return moz_gtk_window_paint(drawable, rect, cliprect, direction);
   3207         break;
   3208     default:
   3209         g_warning("Unknown widget type: %d", widget);
   3210     }
   3211 
   3212     return MOZ_GTK_UNKNOWN_WIDGET;
   3213 }
   3214 
   3215 GtkWidget* moz_gtk_get_scrollbar_widget(void)
   3216 {
   3217     if (!is_initialized)
   3218         return NULL;
   3219     ensure_scrollbar_widget();
   3220     return gParts->horizScrollbarWidget;
   3221 }
   3222 
   3223 gint
   3224 moz_gtk_shutdown()
   3225 {
   3226     GtkWidgetClass *entry_class;
   3227     entry_class = g_type_class_peek(GTK_TYPE_ENTRY);
   3228     g_type_class_unref(entry_class);
   3229 
   3230     is_initialized = FALSE;
   3231 
   3232     return MOZ_GTK_SUCCESS;
   3233 }
   3234 
   3235 void moz_gtk_destroy_theme_parts_widgets(GtkThemeParts* parts)
   3236 {
   3237     if (!parts)
   3238         return;
   3239 
   3240     if (parts->tooltipWidget) {
   3241         gtk_widget_destroy(parts->tooltipWidget);
   3242         parts->tooltipWidget = NULL;
   3243     }
   3244 
   3245     if (parts->protoWindow) {
   3246         gtk_widget_destroy(parts->protoWindow);
   3247         parts->protoWindow = NULL;
   3248     }
   3249 }
   3250