root/trunk/WebCore/platform/gtk/gtk2drawing.c

Revision 42904, 116.3 KB (checked in by kov@webkit.org, 6 months ago)

2009-04-27 Gustavo Noronha Silva < gns@gnome.org>

Unreviewed debug build fix.

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