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

Revision 37779, 115.7 KB (checked in by alp@webkit.org, 6 weeks ago)

2008-10-22 Alp Toker <alp@nuanti.com>

Reviewed by Adam Roben.

Fix crashes on older GTK+ versions (2.8). gtk_widget_style_get()
doesn't initialize values if the requested property doesn't exist, so
initialize the values to the documented defaults before calling it
where necessary. Additionally, avoid critical warnings by not calling
gtk_widget_style_get() when we know the property isn't available.

Note that this is an imported source file which doesn't follow the
WebKit coding style.

Avoid critical warnings on older GTK+ versions (2.8) by not checking
for GTK+ setting properties when we know they don't exist.

  • 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 <math.h>
53
54#define XTHICKNESS(style) (style->xthickness)
55#define YTHICKNESS(style) (style->ythickness)
56#define WINDOW_IS_MAPPED(window) ((window) && GDK_IS_WINDOW(window) && gdk_window_is_visible(window))
57
58static GtkWidget* gProtoWindow;
59static GtkWidget* gButtonWidget;
60static GtkWidget* gToggleButtonWidget;
61static GtkWidget* gButtonArrowWidget;
62static GtkWidget* gCheckboxWidget;
63static GtkWidget* gRadiobuttonWidget;
64static GtkWidget* gHorizScrollbarWidget;
65static GtkWidget* gVertScrollbarWidget;
66static GtkWidget* gSpinWidget;
67static GtkWidget* gHScaleWidget;
68static GtkWidget* gVScaleWidget;
69static GtkWidget* gEntryWidget;
70static GtkWidget* gComboBoxWidget;
71static GtkWidget* gComboBoxButtonWidget;
72static GtkWidget* gComboBoxArrowWidget;
73static GtkWidget* gComboBoxSeparatorWidget;
74static GtkWidget* gComboBoxEntryWidget;
75static GtkWidget* gComboBoxEntryTextareaWidget;
76static GtkWidget* gComboBoxEntryButtonWidget;
77static GtkWidget* gComboBoxEntryArrowWidget;
78static GtkWidget* gHandleBoxWidget;
79static GtkWidget* gToolbarWidget;
80static GtkWidget* gFrameWidget;
81static GtkWidget* gStatusbarWidget;
82static GtkWidget* gProgressWidget;
83static GtkWidget* gTabWidget;
84static GtkWidget* gTooltipWidget;
85static GtkWidget* gMenuBarWidget;
86static GtkWidget* gMenuBarItemWidget;
87static GtkWidget* gMenuPopupWidget;
88static GtkWidget* gMenuItemWidget;
89static GtkWidget* gImageMenuItemWidget;
90static GtkWidget* gCheckMenuItemWidget;
91static GtkWidget* gTreeViewWidget;
92static GtkWidget* gMiddleTreeViewColumn;
93static GtkWidget* gTreeHeaderCellWidget;
94static GtkWidget* gTreeHeaderSortArrowWidget;
95static GtkWidget* gExpanderWidget;
96static GtkWidget* gToolbarSeparatorWidget;
97static GtkWidget* gMenuSeparatorWidget;
98static GtkWidget* gHPanedWidget;
99static GtkWidget* gVPanedWidget;
100static GtkWidget* gScrolledWindowWidget;
101
102static style_prop_t style_prop_func;
103static gboolean have_arrow_scaling;
104static gboolean have_2_10;
105static gboolean is_initialized;
106
107/* Because we have such an unconventional way of drawing widgets, signal to the GTK theme engine
108   that they are drawing for Mozilla instead of a conventional GTK app so they can do any specific
109   things they may want to do. */
110static void
111moz_gtk_set_widget_name(GtkWidget* widget)
112{
113    gtk_widget_set_name(widget, "MozillaGtkWidget");
114}
115
116gint
117moz_gtk_enable_style_props(style_prop_t styleGetProp)
118{
119    style_prop_func = styleGetProp;
120    return MOZ_GTK_SUCCESS;
121}
122
123static gint
124ensure_window_widget()
125{
126    if (!gProtoWindow) {
127        gProtoWindow = gtk_window_new(GTK_WINDOW_POPUP);
128        gtk_widget_realize(gProtoWindow);
129        moz_gtk_set_widget_name(gProtoWindow);
130    }
131    return MOZ_GTK_SUCCESS;
132}
133
134static gint
135setup_widget_prototype(GtkWidget* widget)
136{
137    static GtkWidget* protoLayout;
138    ensure_window_widget();
139    if (!protoLayout) {
140        protoLayout = gtk_fixed_new();
141        gtk_container_add(GTK_CONTAINER(gProtoWindow), protoLayout);
142    }
143
144    gtk_container_add(GTK_CONTAINER(protoLayout), widget);
145    gtk_widget_realize(widget);
146    g_object_set_data(G_OBJECT(widget), "transparent-bg-hint", TRUE);
147    return MOZ_GTK_SUCCESS;
148}
149
150static gint
151ensure_button_widget()
152{
153    if (!gButtonWidget) {
154        gButtonWidget = gtk_button_new_with_label("M");
155        setup_widget_prototype(gButtonWidget);
156    }
157    return MOZ_GTK_SUCCESS;
158}
159
160static gint
161ensure_hpaned_widget()
162{
163    if (!gHPanedWidget) {
164        gHPanedWidget = gtk_hpaned_new();
165        setup_widget_prototype(gHPanedWidget);
166    }
167    return MOZ_GTK_SUCCESS;
168}
169
170static gint
171ensure_vpaned_widget()
172{
173    if (!gVPanedWidget) {
174        gVPanedWidget = gtk_vpaned_new();
175        setup_widget_prototype(gVPanedWidget);
176    }
177    return MOZ_GTK_SUCCESS;
178}
179
180static gint
181ensure_toggle_button_widget()
182{
183    if (!gToggleButtonWidget) {
184        gToggleButtonWidget = gtk_toggle_button_new();
185        setup_widget_prototype(gToggleButtonWidget);
186        /* toggle button must be set active to get the right style on hover. */
187        GTK_TOGGLE_BUTTON(gToggleButtonWidget)->active = TRUE;
188  }
189  return MOZ_GTK_SUCCESS;
190}
191
192static gint
193ensure_button_arrow_widget()
194{
195    if (!gButtonArrowWidget) {
196        ensure_toggle_button_widget();
197
198        gButtonArrowWidget = gtk_arrow_new(GTK_ARROW_DOWN, GTK_SHADOW_OUT);
199        gtk_container_add(GTK_CONTAINER(gToggleButtonWidget), gButtonArrowWidget);
200        gtk_widget_realize(gButtonArrowWidget);
201    }
202    return MOZ_GTK_SUCCESS;
203}
204
205static gint
206ensure_checkbox_widget()
207{
208    if (!gCheckboxWidget) {
209        gCheckboxWidget = gtk_check_button_new_with_label("M");
210        setup_widget_prototype(gCheckboxWidget);
211    }
212    return MOZ_GTK_SUCCESS;
213}
214
215static gint
216ensure_radiobutton_widget()
217{
218    if (!gRadiobuttonWidget) {
219        gRadiobuttonWidget = gtk_radio_button_new_with_label(NULL, "M");
220        setup_widget_prototype(gRadiobuttonWidget);
221    }
222    return MOZ_GTK_SUCCESS;
223}
224
225static gint
226ensure_scrollbar_widget()
227{
228    if (!gVertScrollbarWidget) {
229        gVertScrollbarWidget = gtk_vscrollbar_new(NULL);
230        setup_widget_prototype(gVertScrollbarWidget);
231    }
232    if (!gHorizScrollbarWidget) {
233        gHorizScrollbarWidget = gtk_hscrollbar_new(NULL);
234        setup_widget_prototype(gHorizScrollbarWidget);
235    }
236    return MOZ_GTK_SUCCESS;
237}
238
239static gint
240ensure_spin_widget()
241{
242  if (!gSpinWidget) {
243    gSpinWidget = gtk_spin_button_new(NULL, 1, 0);
244    setup_widget_prototype(gSpinWidget);
245  }
246  return MOZ_GTK_SUCCESS;
247}
248
249static gint
250ensure_scale_widget()
251{
252  if (!gHScaleWidget) {
253    gHScaleWidget = gtk_hscale_new(NULL);
254    setup_widget_prototype(gHScaleWidget);
255  }
256  if (!gVScaleWidget) {
257    gVScaleWidget = gtk_vscale_new(NULL);
258    setup_widget_prototype(gVScaleWidget);
259  }
260  return MOZ_GTK_SUCCESS;
261}
262
263static gint
264ensure_entry_widget()
265{
266    if (!gEntryWidget) {
267        gEntryWidget = gtk_entry_new();
268        setup_widget_prototype(gEntryWidget);
269    }
270    return MOZ_GTK_SUCCESS;
271}
272
273/* We need to have pointers to the inner widgets (button, separator, arrow)
274 * of the ComboBox to get the correct rendering from theme engines which
275 * special cases their look. Since the inner layout can change, we ask GTK
276 * to NULL our pointers when they are about to become invalid because the
277 * corresponding widgets don't exist anymore. It's the role of
278 * g_object_add_weak_pointer().
279 * Note that if we don't find the inner widgets (which shouldn't happen), we
280 * fallback to use generic "non-inner" widgets, and they don't need that kind
281 * of weak pointer since they are explicit children of gProtoWindow and as
282 * such GTK holds a strong reference to them. */
283static void
284moz_gtk_get_combo_box_inner_button(GtkWidget *widget, gpointer client_data)
285{
286    if (GTK_IS_TOGGLE_BUTTON(widget)) {
287        gComboBoxButtonWidget = widget;
288        g_object_add_weak_pointer(G_OBJECT(widget),
289                                  (gpointer) &gComboBoxButtonWidget);
290        gtk_widget_realize(widget);
291        g_object_set_data(G_OBJECT(widget), "transparent-bg-hint", TRUE);
292    }
293}
294
295static void
296moz_gtk_get_combo_box_button_inner_widgets(GtkWidget *widget,
297                                           gpointer client_data)
298{
299    if (GTK_IS_SEPARATOR(widget)) {
300        gComboBoxSeparatorWidget = widget;
301        g_object_add_weak_pointer(G_OBJECT(widget),
302                                  (gpointer) &gComboBoxSeparatorWidget);
303    } else if (GTK_IS_ARROW(widget)) {
304        gComboBoxArrowWidget = widget;
305        g_object_add_weak_pointer(G_OBJECT(widget),
306                                  (gpointer) &gComboBoxArrowWidget);
307    } else
308        return;
309    gtk_widget_realize(widget);
310    g_object_set_data(G_OBJECT(widget), "transparent-bg-hint", TRUE);
311}
312
313static gint
314ensure_combo_box_widgets()
315{
316    GtkWidget* buttonChild;
317
318    if (gComboBoxButtonWidget && gComboBoxArrowWidget)
319        return MOZ_GTK_SUCCESS;
320
321    /* Create a ComboBox if needed */
322    if (!gComboBoxWidget) {
323        gComboBoxWidget = gtk_combo_box_new();
324        setup_widget_prototype(gComboBoxWidget);
325    }
326
327    /* Get its inner Button */
328    gtk_container_forall(GTK_CONTAINER(gComboBoxWidget),
329                         moz_gtk_get_combo_box_inner_button,
330                         NULL);
331
332    if (gComboBoxButtonWidget) {
333        /* Get the widgets inside the Button */
334        buttonChild = GTK_BIN(gComboBoxButtonWidget)->child;
335        if (GTK_IS_HBOX(buttonChild)) {
336            /* appears-as-list = FALSE, cell-view = TRUE; the button
337             * contains an hbox. This hbox is there because the ComboBox
338             * needs to place a cell renderer, a separator, and an arrow in
339             * the button when appears-as-list is FALSE. */
340            gtk_container_forall(GTK_CONTAINER(buttonChild),
341                                 moz_gtk_get_combo_box_button_inner_widgets,
342                                 NULL);
343        } else if(GTK_IS_ARROW(buttonChild)) {
344            /* appears-as-list = TRUE, or cell-view = FALSE;
345             * the button only contains an arrow */
346            gComboBoxArrowWidget = buttonChild;
347            g_object_add_weak_pointer(G_OBJECT(buttonChild), (gpointer)
348                                      &gComboBoxArrowWidget);
349            gtk_widget_realize(gComboBoxArrowWidget);
350            g_object_set_data(G_OBJECT(gComboBoxArrowWidget),
351                              "transparent-bg-hint", TRUE);
352        }
353    } else {
354        /* Shouldn't be reached with current internal gtk implementation; we
355         * use a generic toggle button as last resort fallback to avoid
356         * crashing. */
357        ensure_toggle_button_widget();
358        gComboBoxButtonWidget = gToggleButtonWidget;
359    }
360
361    if (!gComboBoxArrowWidget) {
362        /* Shouldn't be reached with current internal gtk implementation;
363         * we gButtonArrowWidget as last resort fallback to avoid
364         * crashing. */
365        ensure_button_arrow_widget();
366        gComboBoxArrowWidget = gButtonArrowWidget;
367    }
368
369    /* We don't test the validity of gComboBoxSeparatorWidget since there
370     * is none when "appears-as-list" = TRUE or "cell-view" = FALSE; if it
371     * is invalid we just won't paint it. */
372
373    return MOZ_GTK_SUCCESS;
374}
375
376/* We need to have pointers to the inner widgets (entry, button, arrow) of
377 * the ComboBoxEntry to get the correct rendering from theme engines which
378 * special cases their look. Since the inner layout can change, we ask GTK
379 * to NULL our pointers when they are about to become invalid because the
380 * corresponding widgets don't exist anymore. It's the role of
381 * g_object_add_weak_pointer().
382 * Note that if we don't find the inner widgets (which shouldn't happen), we
383 * fallback to use generic "non-inner" widgets, and they don't need that kind
384 * of weak pointer since they are explicit children of gProtoWindow and as
385 * such GTK holds a strong reference to them. */
386static void
387moz_gtk_get_combo_box_entry_inner_widgets(GtkWidget *widget,
388                                          gpointer client_data)
389{
390    if (GTK_IS_TOGGLE_BUTTON(widget)) {
391        gComboBoxEntryButtonWidget = widget;
392        g_object_add_weak_pointer(G_OBJECT(widget),
393                                  (gpointer) &gComboBoxEntryButtonWidget);
394    } else if (GTK_IS_ENTRY(widget)) {
395        gComboBoxEntryTextareaWidget = widget;
396        g_object_add_weak_pointer(G_OBJECT(widget),
397                                  (gpointer) &gComboBoxEntryTextareaWidget);
398    } else
399        return;
400    gtk_widget_realize(widget);
401    g_object_set_data(G_OBJECT(widget), "transparent-bg-hint", TRUE);
402}
403
404static void
405moz_gtk_get_combo_box_entry_arrow(GtkWidget *widget, gpointer client_data)
406{
407    if (GTK_IS_ARROW(widget)) {
408        gComboBoxEntryArrowWidget = widget;
409        g_object_add_weak_pointer(G_OBJECT(widget),
410                                  (gpointer) &gComboBoxEntryArrowWidget);
411        gtk_widget_realize(widget);
412        g_object_set_data(G_OBJECT(widget), "transparent-bg-hint", TRUE);
413    }
414}
415
416static gint
417ensure_combo_box_entry_widgets()
418{
419    GtkWidget* buttonChild;
420
421    if (gComboBoxEntryTextareaWidget &&
422            gComboBoxEntryButtonWidget &&
423            gComboBoxEntryArrowWidget)
424        return MOZ_GTK_SUCCESS;
425
426    /* Create a ComboBoxEntry if needed */
427    if (!gComboBoxEntryWidget) {
428        gComboBoxEntryWidget = gtk_combo_box_entry_new();
429        setup_widget_prototype(gComboBoxEntryWidget);
430    }
431
432    /* Get its inner Entry and Button */
433    gtk_container_forall(GTK_CONTAINER(gComboBoxEntryWidget),
434                         moz_gtk_get_combo_box_entry_inner_widgets,
435                         NULL);
436
437    if (!gComboBoxEntryTextareaWidget) {
438        ensure_entry_widget();
439        gComboBoxEntryTextareaWidget = gEntryWidget;
440    }
441
442    if (gComboBoxEntryButtonWidget) {
443        /* Get the Arrow inside the Button */
444        buttonChild = GTK_BIN(gComboBoxEntryButtonWidget)->child;
445        if (GTK_IS_HBOX(buttonChild)) {
446            /* appears-as-list = FALSE, cell-view = TRUE; the button
447             * contains an hbox. This hbox is there because ComboBoxEntry
448             * inherits from ComboBox which needs to place a cell renderer,
449             * a separator, and an arrow in the button when appears-as-list
450             * is FALSE. Here the hbox should only contain an arrow, since
451             * a ComboBoxEntry doesn't need all those widgets in the
452             * button. */
453            gtk_container_forall(GTK_CONTAINER(buttonChild),
454                                 moz_gtk_get_combo_box_entry_arrow,
455                                 NULL);
456        } else if(GTK_IS_ARROW(buttonChild)) {
457            /* appears-as-list = TRUE, or cell-view = FALSE;
458             * the button only contains an arrow */
459            gComboBoxEntryArrowWidget = buttonChild;
460            g_object_add_weak_pointer(G_OBJECT(buttonChild), (gpointer)
461                                      &gComboBoxEntryArrowWidget);
462            gtk_widget_realize(gComboBoxEntryArrowWidget);
463            g_object_set_data(G_OBJECT(gComboBoxEntryArrowWidget),
464                              "transparent-bg-hint", TRUE);
465        }
466    } else {
467        /* Shouldn't be reached with current internal gtk implementation;
468         * we use a generic toggle button as last resort fallback to avoid
469         * crashing. */
470        ensure_toggle_button_widget();
471        gComboBoxEntryButtonWidget = gToggleButtonWidget;
472    }
473
474    if (!gComboBoxEntryArrowWidget) {
475        /* Shouldn't be reached with current internal gtk implementation;
476         * we gButtonArrowWidget as last resort fallback to avoid
477         * crashing. */
478        ensure_button_arrow_widget();
479        gComboBoxEntryArrowWidget = gButtonArrowWidget;
480    }
481
482    return MOZ_GTK_SUCCESS;
483}
484
485
486static gint
487ensure_handlebox_widget()
488{
489    if (!gHandleBoxWidget) {
490        gHandleBoxWidget = gtk_handle_box_new();
491        setup_widget_prototype(gHandleBoxWidget);
492    }
493    return MOZ_GTK_SUCCESS;
494}
495
496static gint
497ensure_toolbar_widget()
498{
499    if (!gToolbarWidget) {
500        ensure_handlebox_widget();
501        gToolbarWidget = gtk_toolbar_new();
502        gtk_container_add(GTK_CONTAINER(gHandleBoxWidget), gToolbarWidget);
503        gtk_widget_realize(gToolbarWidget);
504        g_object_set_data(G_OBJECT(gToolbarWidget), "transparent-bg-hint", TRUE);
505    }
506    return MOZ_GTK_SUCCESS;
507}
508
509static gint
510ensure_toolbar_separator_widget()
511{
512    if (!gToolbarSeparatorWidget) {
513        ensure_toolbar_widget();
514        gToolbarSeparatorWidget = GTK_WIDGET(gtk_separator_tool_item_new());
515        setup_widget_prototype(gToolbarSeparatorWidget);
516    }
517    return MOZ_GTK_SUCCESS;
518}
519
520static gint
521ensure_tooltip_widget()
522{
523    if (!gTooltipWidget) {
524        gTooltipWidget = gtk_window_new(GTK_WINDOW_POPUP);
525        gtk_widget_realize(gTooltipWidget);
526        moz_gtk_set_widget_name(gTooltipWidget);
527    }
528    return MOZ_GTK_SUCCESS;
529}
530
531static gint
532ensure_tab_widget()
533{
534    if (!gTabWidget) {
535        gTabWidget = gtk_notebook_new();
536        setup_widget_prototype(gTabWidget);
537    }
538    return MOZ_GTK_SUCCESS;
539}
540
541static gint
542ensure_progress_widget()
543{
544    if (!gProgressWidget) {
545        gProgressWidget = gtk_progress_bar_new();
546        setup_widget_prototype(gProgressWidget);
547    }
548    return MOZ_GTK_SUCCESS;
549}
550
551static gint
552ensure_statusbar_widget()
553{
554    if (!gStatusbarWidget) {
555      gStatusbarWidget = gtk_statusbar_new();
556      setup_widget_prototype(gStatusbarWidget);
557    }
558    return MOZ_GTK_SUCCESS;
559}
560
561static gint
562ensure_frame_widget()
563{
564    if (!gFrameWidget) {
565        ensure_statusbar_widget();
566        gFrameWidget = gtk_frame_new(NULL);
567        gtk_container_add(GTK_CONTAINER(gStatusbarWidget), gFrameWidget);
568        gtk_widget_realize(gFrameWidget);
569    }
570    return MOZ_GTK_SUCCESS;
571}
572
573static gint
574ensure_menu_bar_widget()
575{
576    if (!gMenuBarWidget) {
577        gMenuBarWidget = gtk_menu_bar_new();
578        setup_widget_prototype(gMenuBarWidget);
579    }
580    return MOZ_GTK_SUCCESS;
581}
582
583static gint
584ensure_menu_bar_item_widget()
585{
586    if (!gMenuBarItemWidget) {
587        ensure_menu_bar_widget();
588        gMenuBarItemWidget = gtk_menu_item_new();
589        gtk_menu_shell_append(GTK_MENU_SHELL(gMenuBarWidget),
590                              gMenuBarItemWidget);
591        gtk_widget_realize(gMenuBarItemWidget);
592        g_object_set_data(G_OBJECT(gMenuBarItemWidget),
593                          "transparent-bg-hint", TRUE);
594    }
595    return MOZ_GTK_SUCCESS;
596}
597
598static gint
599ensure_menu_popup_widget()
600{
601    if (!gMenuPopupWidget) {
602        ensure_menu_bar_item_widget();
603        gMenuPopupWidget = gtk_menu_new();
604        gtk_menu_item_set_submenu(GTK_MENU_ITEM(gMenuBarItemWidget),
605                                  gMenuPopupWidget);
606        gtk_widget_realize(gMenuPopupWidget);
607        g_object_set_data(G_OBJECT(gMenuPopupWidget),
608                          "transparent-bg-hint", TRUE);
609    }
610    return MOZ_GTK_SUCCESS;
611}
612
613static gint
614ensure_menu_item_widget()
615{
616    if (!gMenuItemWidget) {
617        ensure_menu_popup_widget();
618        gMenuItemWidget = gtk_menu_item_new_with_label("M");
619        gtk_menu_shell_append(GTK_MENU_SHELL(gMenuPopupWidget),
620                              gMenuItemWidget);
621        gtk_widget_realize(gMenuItemWidget);
622        g_object_set_data(G_OBJECT(gMenuItemWidget),
623                          "transparent-bg-hint", TRUE);
624    }
625    return MOZ_GTK_SUCCESS;
626}
627
628static gint
629ensure_image_menu_item_widget()
630{
631    if (!gImageMenuItemWidget) {
632        ensure_menu_popup_widget();
633        gImageMenuItemWidget = gtk_image_menu_item_new();
634        gtk_menu_shell_append(GTK_MENU_SHELL(gMenuPopupWidget),
635                              gImageMenuItemWidget);
636        gtk_widget_realize(gImageMenuItemWidget);
637        g_object_set_data(G_OBJECT(gImageMenuItemWidget),
638                          "transparent-bg-hint", TRUE);
639    }
640    return MOZ_GTK_SUCCESS;
641}
642
643static gint
644ensure_menu_separator_widget()
645{
646    if (!gMenuSeparatorWidget) {
647        ensure_menu_popup_widget();
648        gMenuSeparatorWidget = gtk_separator_menu_item_new();
649        gtk_menu_shell_append(GTK_MENU_SHELL(gMenuPopupWidget),
650                              gMenuSeparatorWidget);
651        gtk_widget_realize(gMenuSeparatorWidget);
652        g_object_set_data(G_OBJECT(gMenuSeparatorWidget),
653                          "transparent-bg-hint", TRUE);
654    }
655    return MOZ_GTK_SUCCESS;
656}
657
658static gint
659ensure_check_menu_item_widget()
660{
661    if (!gCheckMenuItemWidget) {
662        ensure_menu_popup_widget();
663        gCheckMenuItemWidget = gtk_check_menu_item_new_with_label("M");
664        gtk_menu_shell_append(GTK_MENU_SHELL(gMenuPopupWidget),
665                              gCheckMenuItemWidget);
666        gtk_widget_realize(gCheckMenuItemWidget);
667        g_object_set_data(G_OBJECT(gCheckMenuItemWidget),
668                          "transparent-bg-hint", TRUE);
669    }
670    return MOZ_GTK_SUCCESS;
671}
672
673static gint
674ensure_tree_view_widget()
675{
676    if (!gTreeViewWidget) {
677        gTreeViewWidget = gtk_tree_view_new();
678        setup_widget_prototype(gTreeViewWidget);
679    }
680    return MOZ_GTK_SUCCESS;
681}
682
683static gint
684ensure_tree_header_cell_widget()
685{
686    if(!gTreeHeaderCellWidget) {
687        /*
688         * Some GTK engines paint the first and last cell
689         * of a TreeView header with a highlight.
690         * Since we do not know where our widget will be relative
691         * to the other buttons in the TreeView header, we must
692         * paint it as a button that is between two others,
693         * thus ensuring it is neither the first or last button
694         * in the header.
695         * GTK doesn't give us a way to do this explicitly,
696         * so we must paint with a button that is between two
697         * others.
698         */
699
700        GtkTreeViewColumn* firstTreeViewColumn;
701        GtkTreeViewColumn* lastTreeViewColumn;
702
703        ensure_tree_view_widget();
704
705        /* Create and append our three columns */
706        firstTreeViewColumn = gtk_tree_view_column_new();
707        gtk_tree_view_column_set_title(firstTreeViewColumn, "M");
708        gtk_tree_view_append_column(GTK_TREE_VIEW(gTreeViewWidget), firstTreeViewColumn);
709
710        gMiddleTreeViewColumn = gtk_tree_view_column_new();
711        gtk_tree_view_column_set_title(GTK_TREE_VIEW_COLUMN(gMiddleTreeViewColumn), "M");
712        gtk_tree_view_append_column(GTK_TREE_VIEW(gTreeViewWidget),
713                                    GTK_TREE_VIEW_COLUMN(gMiddleTreeViewColumn));
714
715        lastTreeViewColumn = gtk_tree_view_column_new();
716        gtk_tree_view_column_set_title(lastTreeViewColumn, "M");
717        gtk_tree_view_append_column(GTK_TREE_VIEW(gTreeViewWidget), lastTreeViewColumn);
718
719        /* Use the middle column's header for our button */
720        gTreeHeaderCellWidget = GTK_TREE_VIEW_COLUMN(gMiddleTreeViewColumn)->button;
721        gTreeHeaderSortArrowWidget = GTK_TREE_VIEW_COLUMN(gMiddleTreeViewColumn)->arrow;
722        g_object_set_data(G_OBJECT(gTreeHeaderCellWidget),
723                          "transparent-bg-hint", TRUE);
724        g_object_set_data(G_OBJECT(gTreeHeaderSortArrowWidget),
725                          "transparent-bg-hint", TRUE);
726    }
727    return MOZ_GTK_SUCCESS;
728}
729
730static gint
731ensure_expander_widget()
732{
733    if (!gExpanderWidget) {
734        gExpanderWidget = gtk_expander_new("M");
735        setup_widget_prototype(gExpanderWidget);
736    }
737    return MOZ_GTK_SUCCESS;
738}
739
740static gint
741ensure_scrolled_window_widget()
742{
743    if (!gScrolledWindowWidget) {
744        gScrolledWindowWidget = gtk_scrolled_window_new(NULL, NULL);
745        setup_widget_prototype(gScrolledWindowWidget);
746    }
747    return MOZ_GTK_SUCCESS;
748}
749
750static GtkStateType
751ConvertGtkState(GtkWidgetState* state)
752{
753    if (state->disabled)
754        return GTK_STATE_INSENSITIVE;
755    else if (state->depressed)
756        return (state->inHover ? GTK_STATE_PRELIGHT : GTK_STATE_ACTIVE);
757    else if (state->inHover)
758        return (state->active ? GTK_STATE_ACTIVE : GTK_STATE_PRELIGHT);
759    else
760        return GTK_STATE_NORMAL;
761}
762
763static gint
764TSOffsetStyleGCArray(GdkGC** gcs, gint xorigin, gint yorigin)
765{
766    int i;
767    /* there are 5 gc's in each array, for each of the widget states */
768    for (i = 0; i < 5; ++i)
769        gdk_gc_set_ts_origin(gcs[i], xorigin, yorigin);
770    return MOZ_GTK_SUCCESS;
771}
772
773static gint
774TSOffsetStyleGCs(GtkStyle* style, gint xorigin, gint yorigin)
775{
776    TSOffsetStyleGCArray(style->fg_gc, xorigin, yorigin);
777    TSOffsetStyleGCArray(style->bg_gc, xorigin, yorigin);
778    TSOffsetStyleGCArray(style->light_gc, xorigin, yorigin);
779    TSOffsetStyleGCArray(style->dark_gc, xorigin, yorigin);
780    TSOffsetStyleGCArray(