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