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