• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
60 static GtkWidget* gProtoWindow;
61 static GtkWidget* gProtoLayout;
62 static GtkWidget* gButtonWidget;
63 static GtkWidget* gToggleButtonWidget;
64 static GtkWidget* gButtonArrowWidget;
65 static GtkWidget* gCheckboxWidget;
66 static GtkWidget* gRadiobuttonWidget;
67 static GtkWidget* gHorizScrollbarWidget;
68 static GtkWidget* gVertScrollbarWidget;
69 static GtkWidget* gSpinWidget;
70 static GtkWidget* gHScaleWidget;
71 static GtkWidget* gVScaleWidget;
72 static GtkWidget* gEntryWidget;
73 static GtkWidget* gComboBoxWidget;
74 static GtkWidget* gComboBoxButtonWidget;
75 static GtkWidget* gComboBoxArrowWidget;
76 static GtkWidget* gComboBoxSeparatorWidget;
77 static GtkWidget* gComboBoxEntryWidget;
78 static GtkWidget* gComboBoxEntryTextareaWidget;
79 static GtkWidget* gComboBoxEntryButtonWidget;
80 static GtkWidget* gComboBoxEntryArrowWidget;
81 static GtkWidget* gHandleBoxWidget;
82 static GtkWidget* gToolbarWidget;
83 static GtkWidget* gFrameWidget;
84 static GtkWidget* gStatusbarWidget;
85 static GtkWidget* gProgressWidget;
86 static GtkWidget* gTabWidget;
87 static GtkWidget* gTooltipWidget;
88 static GtkWidget* gMenuBarWidget;
89 static GtkWidget* gMenuBarItemWidget;
90 static GtkWidget* gMenuPopupWidget;
91 static GtkWidget* gMenuItemWidget;
92 static GtkWidget* gImageMenuItemWidget;
93 static GtkWidget* gCheckMenuItemWidget;
94 static GtkWidget* gTreeViewWidget;
95 static GtkTreeViewColumn* gMiddleTreeViewColumn;
96 static GtkWidget* gTreeHeaderCellWidget;
97 static GtkWidget* gTreeHeaderSortArrowWidget;
98 static GtkWidget* gExpanderWidget;
99 static GtkWidget* gToolbarSeparatorWidget;
100 static GtkWidget* gMenuSeparatorWidget;
101 static GtkWidget* gHPanedWidget;
102 static GtkWidget* gVPanedWidget;
103 static GtkWidget* gScrolledWindowWidget;
104 
105 static style_prop_t style_prop_func;
106 static gboolean have_arrow_scaling;
107 static 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. */
112 static void
moz_gtk_set_widget_name(GtkWidget * widget)113 moz_gtk_set_widget_name(GtkWidget* widget)
114 {
115     gtk_widget_set_name(widget, "MozillaGtkWidget");
116 }
117 
118 gint
moz_gtk_enable_style_props(style_prop_t styleGetProp)119 moz_gtk_enable_style_props(style_prop_t styleGetProp)
120 {
121     style_prop_func = styleGetProp;
122     return MOZ_GTK_SUCCESS;
123 }
124 
125 static gint
ensure_window_widget()126 ensure_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 
136 static gint
setup_widget_prototype(GtkWidget * widget)137 setup_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 
151 static gint
ensure_button_widget()152 ensure_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 
161 static gint
ensure_hpaned_widget()162 ensure_hpaned_widget()
163 {
164     if (!gHPanedWidget) {
165         gHPanedWidget = gtk_hpaned_new();
166         setup_widget_prototype(gHPanedWidget);
167     }
168     return MOZ_GTK_SUCCESS;
169 }
170 
171 static gint
ensure_vpaned_widget()172 ensure_vpaned_widget()
173 {
174     if (!gVPanedWidget) {
175         gVPanedWidget = gtk_vpaned_new();
176         setup_widget_prototype(gVPanedWidget);
177     }
178     return MOZ_GTK_SUCCESS;
179 }
180 
181 static gint
ensure_toggle_button_widget()182 ensure_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 
193 static gint
ensure_button_arrow_widget()194 ensure_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 
206 static gint
ensure_checkbox_widget()207 ensure_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 
216 static gint
ensure_radiobutton_widget()217 ensure_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 
226 static gint
ensure_scrollbar_widget()227 ensure_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 
240 static gint
ensure_spin_widget()241 ensure_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 
250 static gint
ensure_scale_widget()251 ensure_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 
264 static gint
ensure_entry_widget()265 ensure_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. */
284 static void
moz_gtk_get_combo_box_inner_button(GtkWidget * widget,gpointer client_data)285 moz_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 
296 static void
moz_gtk_get_combo_box_button_inner_widgets(GtkWidget * widget,gpointer client_data)297 moz_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 
314 static gint
ensure_combo_box_widgets()315 ensure_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. */
387 static void
moz_gtk_get_combo_box_entry_inner_widgets(GtkWidget * widget,gpointer client_data)388 moz_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 
405 static void
moz_gtk_get_combo_box_entry_arrow(GtkWidget * widget,gpointer client_data)406 moz_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 
417 static gint
ensure_combo_box_entry_widgets()418 ensure_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 
487 static gint
ensure_handlebox_widget()488 ensure_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 
497 static gint
ensure_toolbar_widget()498 ensure_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 
510 static gint
ensure_toolbar_separator_widget()511 ensure_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 
521 static gint
ensure_tooltip_widget()522 ensure_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 
532 static gint
ensure_tab_widget()533 ensure_tab_widget()
534 {
535     if (!gTabWidget) {
536         gTabWidget = gtk_notebook_new();
537         setup_widget_prototype(gTabWidget);
538     }
539     return MOZ_GTK_SUCCESS;
540 }
541 
542 static gint
ensure_progress_widget()543 ensure_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 
552 static gint
ensure_statusbar_widget()553 ensure_statusbar_widget()
554 {
555     if (!gStatusbarWidget) {
556       gStatusbarWidget = gtk_statusbar_new();
557       setup_widget_prototype(gStatusbarWidget);
558     }
559     return MOZ_GTK_SUCCESS;
560 }
561 
562 static gint
ensure_frame_widget()563 ensure_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 
574 static gint
ensure_menu_bar_widget()575 ensure_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 
584 static gint
ensure_menu_bar_item_widget()585 ensure_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 
599 static gint
ensure_menu_popup_widget()600 ensure_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 
614 static gint
ensure_menu_item_widget()615 ensure_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 
629 static gint
ensure_image_menu_item_widget()630 ensure_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 
644 static gint
ensure_menu_separator_widget()645 ensure_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 
659 static gint
ensure_check_menu_item_widget()660 ensure_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 
674 static gint
ensure_tree_view_widget()675 ensure_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 
684 static gint
ensure_tree_header_cell_widget()685 ensure_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 
731 static gint
ensure_expander_widget()732 ensure_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 
741 static gint
ensure_scrolled_window_widget()742 ensure_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 
751 static GtkStateType
ConvertGtkState(GtkWidgetState * state)752 ConvertGtkState(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 
764 static gint
TSOffsetStyleGCArray(GdkGC ** gcs,gint xorigin,gint yorigin)765 TSOffsetStyleGCArray(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 
774 static gint
TSOffsetStyleGCs(GtkStyle * style,gint xorigin,gint yorigin)775 TSOffsetStyleGCs(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 
789 static gint
moz_gtk_button_paint(GdkDrawable * drawable,GdkRectangle * rect,GdkRectangle * cliprect,GtkWidgetState * state,GtkReliefStyle relief,GtkWidget * widget,GtkTextDirection direction)790 moz_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 
873 gint
moz_gtk_init()874 moz_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 
896 gint
moz_gtk_checkbox_get_metrics(gint * indicator_size,gint * indicator_spacing)897 moz_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 
909 gint
moz_gtk_radio_get_metrics(gint * indicator_size,gint * indicator_spacing)910 moz_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 
922 gint
moz_gtk_widget_get_focus(GtkWidget * widget,gboolean * interior_focus,gint * focus_width,gint * focus_pad)923 moz_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 
935 gint
moz_gtk_splitter_get_metrics(gint orientation,gint * size)936 moz_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 
948 gint
moz_gtk_button_get_inner_border(GtkWidget * widget,GtkBorder * inner_border)949 moz_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 
966 static gint
moz_gtk_toggle_paint(GdkDrawable * drawable,GdkRectangle * rect,GdkRectangle * cliprect,GtkWidgetState * state,gboolean selected,gboolean inconsistent,gboolean isradio,GtkTextDirection direction)967 moz_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 
1049 static gint
calculate_button_inner_rect(GtkWidget * button,GdkRectangle * rect,GdkRectangle * inner_rect,GtkTextDirection direction,gboolean ignore_focus)1050 calculate_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 
1084 static gint
calculate_arrow_rect(GtkWidget * arrow,GdkRectangle * rect,GdkRectangle * arrow_rect,GtkTextDirection direction)1085 calculate_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 
1113 static gint
moz_gtk_scrollbar_button_paint(GdkDrawable * drawable,GdkRectangle * rect,GdkRectangle * cliprect,GtkWidgetState * state,GtkScrollbarButtonFlags flags,GtkTextDirection direction)1114 moz_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 
1207 static gint
moz_gtk_scrollbar_trough_paint(GtkThemeWidgetType widget,GdkDrawable * drawable,GdkRectangle * rect,GdkRectangle * cliprect,GtkWidgetState * state,GtkTextDirection direction)1208 moz_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 
1245 static gint
moz_gtk_scrollbar_thumb_paint(GtkThemeWidgetType widget,GdkDrawable * drawable,GdkRectangle * rect,GdkRectangle * cliprect,GtkWidgetState * state,GtkTextDirection direction)1246 moz_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 
1318 static gint
moz_gtk_spin_paint(GdkDrawable * drawable,GdkRectangle * rect,GtkTextDirection direction)1319 moz_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 
1335 static gint
moz_gtk_spin_updown_paint(GdkDrawable * drawable,GdkRectangle * rect,gboolean isDown,GtkWidgetState * state,GtkTextDirection direction)1336 moz_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 
1371 static gint
moz_gtk_scale_paint(GdkDrawable * drawable,GdkRectangle * rect,GdkRectangle * cliprect,GtkWidgetState * state,GtkOrientation flags,GtkTextDirection direction)1372 moz_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 
1412 static gint
moz_gtk_scale_thumb_paint(GdkDrawable * drawable,GdkRectangle * rect,GdkRectangle * cliprect,GtkWidgetState * state,GtkOrientation flags,GtkTextDirection direction)1413 moz_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 
1448 static gint
moz_gtk_gripper_paint(GdkDrawable * drawable,GdkRectangle * rect,GdkRectangle * cliprect,GtkWidgetState * state,GtkTextDirection direction)1449 moz_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 
1471 static gint
moz_gtk_hpaned_paint(GdkDrawable * drawable,GdkRectangle * rect,GdkRectangle * cliprect,GtkWidgetState * state)1472 moz_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 
1486 static gint
moz_gtk_vpaned_paint(GdkDrawable * drawable,GdkRectangle * rect,GdkRectangle * cliprect,GtkWidgetState * state)1487 moz_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 
1501 static gint
moz_gtk_caret_paint(GdkDrawable * drawable,GdkRectangle * rect,GdkRectangle * cliprect,GtkTextDirection direction)1502 moz_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 
1518 static gint
moz_gtk_entry_paint(GdkDrawable * drawable,GdkRectangle * rect,GdkRectangle * cliprect,GtkWidgetState * state,GtkWidget * widget,GtkTextDirection direction)1519 moz_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 
1619 static gint
moz_gtk_treeview_paint(GdkDrawable * drawable,GdkRectangle * rect,GdkRectangle * cliprect,GtkWidgetState * state,GtkTextDirection direction)1620 moz_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 
1665 static gint
moz_gtk_tree_header_cell_paint(GdkDrawable * drawable,GdkRectangle * rect,GdkRectangle * cliprect,GtkWidgetState * state,gboolean isSorted,GtkTextDirection direction)1666 moz_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 
1678 static gint
moz_gtk_tree_header_sort_arrow_paint(GdkDrawable * drawable,GdkRectangle * rect,GdkRectangle * cliprect,GtkWidgetState * state,GtkArrowType flags,GtkTextDirection direction)1679 moz_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 
1710 static gint
moz_gtk_treeview_expander_paint(GdkDrawable * drawable,GdkRectangle * rect,GdkRectangle * cliprect,GtkWidgetState * state,GtkExpanderStyle expander_state,GtkTextDirection direction)1711 moz_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 
1735 static gint
moz_gtk_expander_paint(GdkDrawable * drawable,GdkRectangle * rect,GdkRectangle * cliprect,GtkWidgetState * state,GtkExpanderStyle expander_state,GtkTextDirection direction)1736 moz_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 
1756 static gint
moz_gtk_combo_box_paint(GdkDrawable * drawable,GdkRectangle * rect,GdkRectangle * cliprect,GtkWidgetState * state,gboolean ishtml,GtkTextDirection direction)1757 moz_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 
1837 static gint
moz_gtk_downarrow_paint(GdkDrawable * drawable,GdkRectangle * rect,GdkRectangle * cliprect,GtkWidgetState * state)1838 moz_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 
1860 static gint
moz_gtk_combo_box_entry_button_paint(GdkDrawable * drawable,GdkRectangle * rect,GdkRectangle * cliprect,GtkWidgetState * state,gboolean input_focus,GtkTextDirection direction)1861 moz_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 
1912 static gint
moz_gtk_container_paint(GdkDrawable * drawable,GdkRectangle * rect,GdkRectangle * cliprect,GtkWidgetState * state,gboolean isradio,GtkTextDirection direction)1913 moz_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 
1961 static gint
moz_gtk_toggle_label_paint(GdkDrawable * drawable,GdkRectangle * rect,GdkRectangle * cliprect,GtkWidgetState * state,gboolean isradio,GtkTextDirection direction)1962 moz_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 
2000 static gint
moz_gtk_toolbar_paint(GdkDrawable * drawable,GdkRectangle * rect,GdkRectangle * cliprect,GtkTextDirection direction)2001 moz_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 
2028 static gint
moz_gtk_toolbar_separator_paint(GdkDrawable * drawable,GdkRectangle * rect,GdkRectangle * cliprect,GtkTextDirection direction)2029 moz_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 
2083 static gint
moz_gtk_tooltip_paint(GdkDrawable * drawable,GdkRectangle * rect,GdkRectangle * cliprect,GtkTextDirection direction)2084 moz_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 
2105 static gint
moz_gtk_resizer_paint(GdkDrawable * drawable,GdkRectangle * rect,GdkRectangle * cliprect,GtkWidgetState * state,GtkTextDirection direction)2106 moz_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 
2128 static gint
moz_gtk_frame_paint(GdkDrawable * drawable,GdkRectangle * rect,GdkRectangle * cliprect,GtkTextDirection direction)2129 moz_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 
2150 static gint
moz_gtk_progressbar_paint(GdkDrawable * drawable,GdkRectangle * rect,GdkRectangle * cliprect,GtkTextDirection direction)2151 moz_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 
2169 static gint
moz_gtk_progress_chunk_paint(GdkDrawable * drawable,GdkRectangle * rect,GdkRectangle * cliprect,GtkTextDirection direction)2170 moz_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 
2188 gint
moz_gtk_get_tab_thickness(void)2189 moz_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 
2198 static gint
moz_gtk_tab_paint(GdkDrawable * drawable,GdkRectangle * rect,GdkRectangle * cliprect,GtkTabFlags flags,GtkTextDirection direction)2199 moz_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 
2337 static gint
moz_gtk_tabpanels_paint(GdkDrawable * drawable,GdkRectangle * rect,GdkRectangle * cliprect,GtkTextDirection direction)2338 moz_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 
2361 static gint
moz_gtk_tab_scroll_arrow_paint(GdkDrawable * drawable,GdkRectangle * rect,GdkRectangle * cliprect,GtkWidgetState * state,GtkArrowType arrow_type,GtkTextDirection direction)2362 moz_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 
2391 static gint
moz_gtk_menu_bar_paint(GdkDrawable * drawable,GdkRectangle * rect,GdkRectangle * cliprect,GtkTextDirection direction)2392 moz_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 
2415 static gint
moz_gtk_menu_popup_paint(GdkDrawable * drawable,GdkRectangle * rect,GdkRectangle * cliprect,GtkTextDirection direction)2416 moz_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 
2436 static gint
moz_gtk_menu_separator_paint(GdkDrawable * drawable,GdkRectangle * rect,GdkRectangle * cliprect,GtkTextDirection direction)2437 moz_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 
2486 static gint
moz_gtk_menu_item_paint(GdkDrawable * drawable,GdkRectangle * rect,GdkRectangle * cliprect,GtkWidgetState * state,gint flags,GtkTextDirection direction)2487 moz_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 
2519 static gint
moz_gtk_menu_arrow_paint(GdkDrawable * drawable,GdkRectangle * rect,GdkRectangle * cliprect,GtkWidgetState * state,GtkTextDirection direction)2520 moz_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 
2542 static gint
moz_gtk_check_menu_item_paint(GdkDrawable * drawable,GdkRectangle * rect,GdkRectangle * cliprect,GtkWidgetState * state,gboolean checked,gboolean isradio,GtkTextDirection direction)2543 moz_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 
2595 static gint
moz_gtk_window_paint(GdkDrawable * drawable,GdkRectangle * rect,GdkRectangle * cliprect,GtkTextDirection direction)2596 moz_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 
2614 gint
moz_gtk_get_widget_border(GtkThemeWidgetType widget,gint * left,gint * top,gint * right,gint * bottom,GtkTextDirection direction,gboolean inhtml)2615 moz_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 
2887 gint
moz_gtk_get_combo_box_entry_button_size(gint * width,gint * height)2888 moz_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 
2905 gint
moz_gtk_get_tab_scroll_arrow_size(gint * width,gint * height)2906 moz_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 
2920 gint
moz_gtk_get_downarrow_size(gint * width,gint * height)2921 moz_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 
2933 gint
moz_gtk_get_toolbar_separator_width(gint * size)2934 moz_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 
2956 gint
moz_gtk_get_expander_size(gint * size)2957 moz_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 
2967 gint
moz_gtk_get_treeview_expander_size(gint * size)2968 moz_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 
2978 gint
moz_gtk_get_menu_separator_height(gint * size)2979 moz_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 
2999 gint
moz_gtk_get_scalethumb_metrics(GtkOrientation orient,gint * thumb_length,gint * thumb_height)3000 moz_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 
3015 gint
moz_gtk_get_scrollbar_metrics(MozGtkScrollbarMetrics * metrics)3016 moz_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 
3033 gboolean
moz_gtk_images_in_menus()3034 moz_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 
3046 gint
moz_gtk_widget_paint(GtkThemeWidgetType widget,GdkDrawable * drawable,GdkRectangle * rect,GdkRectangle * cliprect,GtkWidgetState * state,gint flags,GtkTextDirection direction)3047 moz_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:
3160     case MOZ_GTK_RADIOBUTTON_CONTAINER:
3161         return moz_gtk_container_paint(drawable, rect, cliprect, state,
3162                                        (widget == MOZ_GTK_RADIOBUTTON_CONTAINER),
3163                                        direction);
3164         break;
3165     case MOZ_GTK_CHECKBUTTON_LABEL:
3166     case MOZ_GTK_RADIOBUTTON_LABEL:
3167         return moz_gtk_toggle_label_paint(drawable, rect, cliprect, state,
3168                                           (widget == MOZ_GTK_RADIOBUTTON_LABEL),
3169                                           direction);
3170         break;
3171     case MOZ_GTK_TOOLBAR:
3172         return moz_gtk_toolbar_paint(drawable, rect, cliprect, direction);
3173         break;
3174     case MOZ_GTK_TOOLBAR_SEPARATOR:
3175         return moz_gtk_toolbar_separator_paint(drawable, rect, cliprect,
3176                                                direction);
3177         break;
3178     case MOZ_GTK_TOOLTIP:
3179         return moz_gtk_tooltip_paint(drawable, rect, cliprect, direction);
3180         break;
3181     case MOZ_GTK_FRAME:
3182         return moz_gtk_frame_paint(drawable, rect, cliprect, direction);
3183         break;
3184     case MOZ_GTK_RESIZER:
3185         return moz_gtk_resizer_paint(drawable, rect, cliprect, state,
3186                                      direction);
3187         break;
3188     case MOZ_GTK_PROGRESSBAR:
3189         return moz_gtk_progressbar_paint(drawable, rect, cliprect, direction);
3190         break;
3191     case MOZ_GTK_PROGRESS_CHUNK:
3192         return moz_gtk_progress_chunk_paint(drawable, rect, cliprect,
3193                                             direction);
3194         break;
3195     case MOZ_GTK_TAB:
3196         return moz_gtk_tab_paint(drawable, rect, cliprect,
3197                                  (GtkTabFlags) flags, direction);
3198         break;
3199     case MOZ_GTK_TABPANELS:
3200         return moz_gtk_tabpanels_paint(drawable, rect, cliprect, direction);
3201         break;
3202     case MOZ_GTK_TAB_SCROLLARROW:
3203         return moz_gtk_tab_scroll_arrow_paint(drawable, rect, cliprect, state,
3204                                               (GtkArrowType) flags, direction);
3205         break;
3206     case MOZ_GTK_MENUBAR:
3207         return moz_gtk_menu_bar_paint(drawable, rect, cliprect, direction);
3208         break;
3209     case MOZ_GTK_MENUPOPUP:
3210         return moz_gtk_menu_popup_paint(drawable, rect, cliprect, direction);
3211         break;
3212     case MOZ_GTK_MENUSEPARATOR:
3213         return moz_gtk_menu_separator_paint(drawable, rect, cliprect,
3214                                             direction);
3215         break;
3216     case MOZ_GTK_MENUITEM:
3217         return moz_gtk_menu_item_paint(drawable, rect, cliprect, state, flags,
3218                                        direction);
3219         break;
3220     case MOZ_GTK_MENUARROW:
3221         return moz_gtk_menu_arrow_paint(drawable, rect, cliprect, state,
3222                                         direction);
3223         break;
3224     case MOZ_GTK_TOOLBARBUTTON_ARROW:
3225         return moz_gtk_downarrow_paint(drawable, rect, cliprect, state);
3226         break;
3227     case MOZ_GTK_CHECKMENUITEM:
3228     case MOZ_GTK_RADIOMENUITEM:
3229         return moz_gtk_check_menu_item_paint(drawable, rect, cliprect, state,
3230                                              (gboolean) flags,
3231                                              (widget == MOZ_GTK_RADIOMENUITEM),
3232                                              direction);
3233         break;
3234     case MOZ_GTK_SPLITTER_HORIZONTAL:
3235         return moz_gtk_vpaned_paint(drawable, rect, cliprect, state);
3236         break;
3237     case MOZ_GTK_SPLITTER_VERTICAL:
3238         return moz_gtk_hpaned_paint(drawable, rect, cliprect, state);
3239         break;
3240     case MOZ_GTK_WINDOW:
3241         return moz_gtk_window_paint(drawable, rect, cliprect, direction);
3242         break;
3243     default:
3244         g_warning("Unknown widget type: %d", widget);
3245     }
3246 
3247     return MOZ_GTK_UNKNOWN_WIDGET;
3248 }
3249 
moz_gtk_get_scrollbar_widget(void)3250 GtkWidget* moz_gtk_get_scrollbar_widget(void)
3251 {
3252     if (!is_initialized)
3253         return NULL;
3254     ensure_scrollbar_widget();
3255     return gHorizScrollbarWidget;
3256 }
3257 
3258 gint
moz_gtk_shutdown()3259 moz_gtk_shutdown()
3260 {
3261     GtkWidgetClass *entry_class;
3262 
3263     if (gTooltipWidget)
3264         gtk_widget_destroy(gTooltipWidget);
3265     /* This will destroy all of our widgets */
3266     if (gProtoWindow)
3267         gtk_widget_destroy(gProtoWindow);
3268 
3269     gProtoWindow = NULL;
3270     gProtoLayout = NULL;
3271     gButtonWidget = NULL;
3272     gToggleButtonWidget = NULL;
3273     gButtonArrowWidget = NULL;
3274     gCheckboxWidget = NULL;
3275     gRadiobuttonWidget = NULL;
3276     gHorizScrollbarWidget = NULL;
3277     gVertScrollbarWidget = NULL;
3278     gSpinWidget = NULL;
3279     gHScaleWidget = NULL;
3280     gVScaleWidget = NULL;
3281     gEntryWidget = NULL;
3282     gComboBoxWidget = NULL;
3283     gComboBoxButtonWidget = NULL;
3284     gComboBoxSeparatorWidget = NULL;
3285     gComboBoxArrowWidget = NULL;
3286     gComboBoxEntryWidget = NULL;
3287     gComboBoxEntryButtonWidget = NULL;
3288     gComboBoxEntryArrowWidget = NULL;
3289     gComboBoxEntryTextareaWidget = NULL;
3290     gHandleBoxWidget = NULL;
3291     gToolbarWidget = NULL;
3292     gStatusbarWidget = NULL;
3293     gFrameWidget = NULL;
3294     gProgressWidget = NULL;
3295     gTabWidget = NULL;
3296     gTooltipWidget = NULL;
3297     gMenuBarWidget = NULL;
3298     gMenuBarItemWidget = NULL;
3299     gMenuPopupWidget = NULL;
3300     gMenuItemWidget = NULL;
3301     gImageMenuItemWidget = NULL;
3302     gCheckMenuItemWidget = NULL;
3303     gTreeViewWidget = NULL;
3304     gMiddleTreeViewColumn = NULL;
3305     gTreeHeaderCellWidget = NULL;
3306     gTreeHeaderSortArrowWidget = NULL;
3307     gExpanderWidget = NULL;
3308     gToolbarSeparatorWidget = NULL;
3309     gMenuSeparatorWidget = NULL;
3310     gHPanedWidget = NULL;
3311     gVPanedWidget = NULL;
3312     gScrolledWindowWidget = NULL;
3313 
3314     entry_class = g_type_class_peek(GTK_TYPE_ENTRY);
3315     g_type_class_unref(entry_class);
3316 
3317     is_initialized = FALSE;
3318 
3319     return MOZ_GTK_SUCCESS;
3320 }
3321