blob: 37c7de595d60f985f6fee09c8208cb87d8cae126 [file] [log] [blame]
alpd8507382007-11-03 14:33:25 +00001/* -*- 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
51#include <math.h>
52
53#define XTHICKNESS(style) (style->xthickness)
54#define YTHICKNESS(style) (style->ythickness)
55#define WINDOW_IS_MAPPED(window) ((window) && GDK_IS_WINDOW(window) && gdk_window_is_visible(window))
56
57static GtkWidget* gProtoWindow;
58static GtkWidget* gButtonWidget;
alp@webkit.org5a4c6982008-01-28 00:04:31 +000059static GtkWidget* gToggleButtonWidget;
alp@webkit.orgd694e942008-09-15 00:20:15 +000060static GtkWidget* gButtonArrowWidget;
alpd8507382007-11-03 14:33:25 +000061static GtkWidget* gCheckboxWidget;
62static GtkWidget* gRadiobuttonWidget;
63static GtkWidget* gHorizScrollbarWidget;
64static GtkWidget* gVertScrollbarWidget;
65static GtkWidget* gSpinWidget;
66static GtkWidget* gHScaleWidget;
67static GtkWidget* gVScaleWidget;
68static GtkWidget* gEntryWidget;
alp@webkit.orgd694e942008-09-15 00:20:15 +000069static GtkWidget* gComboBoxWidget;
70static GtkWidget* gComboBoxButtonWidget;
71static GtkWidget* gComboBoxArrowWidget;
72static GtkWidget* gComboBoxSeparatorWidget;
alp@webkit.org5a4c6982008-01-28 00:04:31 +000073static GtkWidget* gComboBoxEntryWidget;
alp@webkit.orgd694e942008-09-15 00:20:15 +000074static GtkWidget* gComboBoxEntryTextareaWidget;
75static GtkWidget* gComboBoxEntryButtonWidget;
76static GtkWidget* gComboBoxEntryArrowWidget;
alpd8507382007-11-03 14:33:25 +000077static GtkWidget* gHandleBoxWidget;
78static GtkWidget* gToolbarWidget;
79static GtkWidget* gFrameWidget;
alp@webkit.org5a4c6982008-01-28 00:04:31 +000080static GtkWidget* gStatusbarWidget;
alpd8507382007-11-03 14:33:25 +000081static GtkWidget* gProgressWidget;
82static GtkWidget* gTabWidget;
83static GtkWidget* gTooltipWidget;
84static GtkWidget* gMenuBarWidget;
85static GtkWidget* gMenuBarItemWidget;
86static GtkWidget* gMenuPopupWidget;
87static GtkWidget* gMenuItemWidget;
alp@webkit.orgd694e942008-09-15 00:20:15 +000088static GtkWidget* gImageMenuItemWidget;
alpd8507382007-11-03 14:33:25 +000089static GtkWidget* gCheckMenuItemWidget;
alp@webkit.org5a4c6982008-01-28 00:04:31 +000090static GtkWidget* gTreeViewWidget;
alp@webkit.orgd694e942008-09-15 00:20:15 +000091static GtkWidget* gMiddleTreeViewColumn;
alp@webkit.org5a4c6982008-01-28 00:04:31 +000092static GtkWidget* gTreeHeaderCellWidget;
93static GtkWidget* gTreeHeaderSortArrowWidget;
94static GtkWidget* gExpanderWidget;
95static GtkWidget* gToolbarSeparatorWidget;
96static GtkWidget* gMenuSeparatorWidget;
97static GtkWidget* gHPanedWidget;
98static GtkWidget* gVPanedWidget;
alp@webkit.orgd694e942008-09-15 00:20:15 +000099static GtkWidget* gScrolledWindowWidget;
alpd8507382007-11-03 14:33:25 +0000100
101static style_prop_t style_prop_func;
alp@webkit.orgd694e942008-09-15 00:20:15 +0000102static gboolean have_arrow_scaling;
alpd8507382007-11-03 14:33:25 +0000103static gboolean is_initialized;
104
alp@webkit.orgd694e942008-09-15 00:20:15 +0000105/* Because we have such an unconventional way of drawing widgets, signal to the GTK theme engine
106 that they are drawing for Mozilla instead of a conventional GTK app so they can do any specific
107 things they may want to do. */
108static void
109moz_gtk_set_widget_name(GtkWidget* widget)
110{
111 gtk_widget_set_name(widget, "MozillaGtkWidget");
112}
113
alpd8507382007-11-03 14:33:25 +0000114gint
115moz_gtk_enable_style_props(style_prop_t styleGetProp)
116{
117 style_prop_func = styleGetProp;
118 return MOZ_GTK_SUCCESS;
119}
120
121static gint
122ensure_window_widget()
123{
124 if (!gProtoWindow) {
125 gProtoWindow = gtk_window_new(GTK_WINDOW_POPUP);
126 gtk_widget_realize(gProtoWindow);
alp@webkit.orgd694e942008-09-15 00:20:15 +0000127 moz_gtk_set_widget_name(gProtoWindow);
alpd8507382007-11-03 14:33:25 +0000128 }
129 return MOZ_GTK_SUCCESS;
130}
131
132static gint
133setup_widget_prototype(GtkWidget* widget)
134{
135 static GtkWidget* protoLayout;
136 ensure_window_widget();
137 if (!protoLayout) {
alp@webkit.org5a4c6982008-01-28 00:04:31 +0000138 protoLayout = gtk_fixed_new();
alpd8507382007-11-03 14:33:25 +0000139 gtk_container_add(GTK_CONTAINER(gProtoWindow), protoLayout);
140 }
141
142 gtk_container_add(GTK_CONTAINER(protoLayout), widget);
143 gtk_widget_realize(widget);
alp@webkit.orgd694e942008-09-15 00:20:15 +0000144 g_object_set_data(G_OBJECT(widget), "transparent-bg-hint", TRUE);
alpd8507382007-11-03 14:33:25 +0000145 return MOZ_GTK_SUCCESS;
146}
147
148static gint
149ensure_button_widget()
150{
151 if (!gButtonWidget) {
152 gButtonWidget = gtk_button_new_with_label("M");
153 setup_widget_prototype(gButtonWidget);
154 }
155 return MOZ_GTK_SUCCESS;
156}
157
158static gint
alp@webkit.org5a4c6982008-01-28 00:04:31 +0000159ensure_hpaned_widget()
160{
161 if (!gHPanedWidget) {
162 gHPanedWidget = gtk_hpaned_new();
163 setup_widget_prototype(gHPanedWidget);
164 }
165 return MOZ_GTK_SUCCESS;
166}
167
168static gint
169ensure_vpaned_widget()
170{
171 if (!gVPanedWidget) {
172 gVPanedWidget = gtk_vpaned_new();
173 setup_widget_prototype(gVPanedWidget);
174 }
175 return MOZ_GTK_SUCCESS;
176}
177
178static gint
179ensure_toggle_button_widget()
180{
181 if (!gToggleButtonWidget) {
182 gToggleButtonWidget = gtk_toggle_button_new();
183 setup_widget_prototype(gToggleButtonWidget);
184 /* toggle button must be set active to get the right style on hover. */
185 GTK_TOGGLE_BUTTON(gToggleButtonWidget)->active = TRUE;
186 }
187 return MOZ_GTK_SUCCESS;
188}
189
190static gint
alp@webkit.orgd694e942008-09-15 00:20:15 +0000191ensure_button_arrow_widget()
192{
193 if (!gButtonArrowWidget) {
194 ensure_toggle_button_widget();
195
196 gButtonArrowWidget = gtk_arrow_new(GTK_ARROW_DOWN, GTK_SHADOW_OUT);
197 gtk_container_add(GTK_CONTAINER(gToggleButtonWidget), gButtonArrowWidget);
198 gtk_widget_realize(gButtonArrowWidget);
199 }
200 return MOZ_GTK_SUCCESS;
201}
202
203static gint
alpd8507382007-11-03 14:33:25 +0000204ensure_checkbox_widget()
205{
206 if (!gCheckboxWidget) {
207 gCheckboxWidget = gtk_check_button_new_with_label("M");
208 setup_widget_prototype(gCheckboxWidget);
209 }
210 return MOZ_GTK_SUCCESS;
211}
212
213static gint
214ensure_radiobutton_widget()
215{
216 if (!gRadiobuttonWidget) {
217 gRadiobuttonWidget = gtk_radio_button_new_with_label(NULL, "M");
218 setup_widget_prototype(gRadiobuttonWidget);
219 }
220 return MOZ_GTK_SUCCESS;
221}
222
223static gint
224ensure_scrollbar_widget()
225{
226 if (!gVertScrollbarWidget) {
227 gVertScrollbarWidget = gtk_vscrollbar_new(NULL);
228 setup_widget_prototype(gVertScrollbarWidget);
229 }
230 if (!gHorizScrollbarWidget) {
231 gHorizScrollbarWidget = gtk_hscrollbar_new(NULL);
232 setup_widget_prototype(gHorizScrollbarWidget);
233 }
234 return MOZ_GTK_SUCCESS;
235}
236
237static gint
238ensure_spin_widget()
239{
240 if (!gSpinWidget) {
241 gSpinWidget = gtk_spin_button_new(NULL, 1, 0);
242 setup_widget_prototype(gSpinWidget);
243 }
244 return MOZ_GTK_SUCCESS;
245}
246
247static gint
248ensure_scale_widget()
249{
250 if (!gHScaleWidget) {
251 gHScaleWidget = gtk_hscale_new(NULL);
252 setup_widget_prototype(gHScaleWidget);
253 }
254 if (!gVScaleWidget) {
255 gVScaleWidget = gtk_vscale_new(NULL);
256 setup_widget_prototype(gVScaleWidget);
257 }
258 return MOZ_GTK_SUCCESS;
259}
260
261static gint
262ensure_entry_widget()
263{
264 if (!gEntryWidget) {
265 gEntryWidget = gtk_entry_new();
266 setup_widget_prototype(gEntryWidget);
267 }
268 return MOZ_GTK_SUCCESS;
269}
270
alp@webkit.orgd694e942008-09-15 00:20:15 +0000271/* We need to have pointers to the inner widgets (button, separator, arrow)
272 * of the ComboBox to get the correct rendering from theme engines which
273 * special cases their look. Since the inner layout can change, we ask GTK
274 * to NULL our pointers when they are about to become invalid because the
275 * corresponding widgets don't exist anymore. It's the role of
276 * g_object_add_weak_pointer().
277 * Note that if we don't find the inner widgets (which shouldn't happen), we
278 * fallback to use generic "non-inner" widgets, and they don't need that kind
279 * of weak pointer since they are explicit children of gProtoWindow and as
280 * such GTK holds a strong reference to them. */
281static void
282moz_gtk_get_combo_box_inner_button(GtkWidget *widget, gpointer client_data)
alpd8507382007-11-03 14:33:25 +0000283{
alp@webkit.orgd694e942008-09-15 00:20:15 +0000284 if (GTK_IS_TOGGLE_BUTTON(widget)) {
285 gComboBoxButtonWidget = widget;
286 g_object_add_weak_pointer(G_OBJECT(widget),
287 (gpointer) &gComboBoxButtonWidget);
288 gtk_widget_realize(widget);
289 g_object_set_data(G_OBJECT(widget), "transparent-bg-hint", TRUE);
alpd8507382007-11-03 14:33:25 +0000290 }
alp@webkit.orgd694e942008-09-15 00:20:15 +0000291}
292
293static void
294moz_gtk_get_combo_box_button_inner_widgets(GtkWidget *widget,
295 gpointer client_data)
296{
297 if (GTK_IS_SEPARATOR(widget)) {
298 gComboBoxSeparatorWidget = widget;
299 g_object_add_weak_pointer(G_OBJECT(widget),
300 (gpointer) &gComboBoxSeparatorWidget);
301 } else if (GTK_IS_ARROW(widget)) {
302 gComboBoxArrowWidget = widget;
303 g_object_add_weak_pointer(G_OBJECT(widget),
304 (gpointer) &gComboBoxArrowWidget);
305 } else
306 return;
307 gtk_widget_realize(widget);
308 g_object_set_data(G_OBJECT(widget), "transparent-bg-hint", TRUE);
alpd8507382007-11-03 14:33:25 +0000309}
310
311static gint
alp@webkit.orgd694e942008-09-15 00:20:15 +0000312ensure_combo_box_widgets()
alp@webkit.org5a4c6982008-01-28 00:04:31 +0000313{
alp@webkit.orgd694e942008-09-15 00:20:15 +0000314 GtkWidget* buttonChild;
315
316 if (gComboBoxButtonWidget && gComboBoxArrowWidget)
317 return MOZ_GTK_SUCCESS;
318
319 /* Create a ComboBox if needed */
320 if (!gComboBoxWidget) {
321 gComboBoxWidget = gtk_combo_box_new();
322 setup_widget_prototype(gComboBoxWidget);
323 }
324
325 /* Get its inner Button */
326 gtk_container_forall(GTK_CONTAINER(gComboBoxWidget),
327 moz_gtk_get_combo_box_inner_button,
328 NULL);
329
330 if (gComboBoxButtonWidget) {
331 /* Get the widgets inside the Button */
332 buttonChild = GTK_BIN(gComboBoxButtonWidget)->child;
333 if (GTK_IS_HBOX(buttonChild)) {
334 /* appears-as-list = FALSE, cell-view = TRUE; the button
335 * contains an hbox. This hbox is there because the ComboBox
336 * needs to place a cell renderer, a separator, and an arrow in
337 * the button when appears-as-list is FALSE. */
338 gtk_container_forall(GTK_CONTAINER(buttonChild),
339 moz_gtk_get_combo_box_button_inner_widgets,
340 NULL);
341 } else if(GTK_IS_ARROW(buttonChild)) {
342 /* appears-as-list = TRUE, or cell-view = FALSE;
343 * the button only contains an arrow */
344 gComboBoxArrowWidget = buttonChild;
345 g_object_add_weak_pointer(G_OBJECT(buttonChild), (gpointer)
346 &gComboBoxArrowWidget);
347 gtk_widget_realize(gComboBoxArrowWidget);
348 g_object_set_data(G_OBJECT(gComboBoxArrowWidget),
349 "transparent-bg-hint", TRUE);
350 }
351 } else {
352 /* Shouldn't be reached with current internal gtk implementation; we
353 * use a generic toggle button as last resort fallback to avoid
354 * crashing. */
355 ensure_toggle_button_widget();
356 gComboBoxButtonWidget = gToggleButtonWidget;
357 }
358
359 if (!gComboBoxArrowWidget) {
360 /* Shouldn't be reached with current internal gtk implementation;
361 * we gButtonArrowWidget as last resort fallback to avoid
362 * crashing. */
363 ensure_button_arrow_widget();
364 gComboBoxArrowWidget = gButtonArrowWidget;
365 }
366
367 /* We don't test the validity of gComboBoxSeparatorWidget since there
368 * is none when "appears-as-list" = TRUE or "cell-view" = FALSE; if it
369 * is invalid we just won't paint it. */
370
371 return MOZ_GTK_SUCCESS;
372}
373
374/* We need to have pointers to the inner widgets (entry, button, arrow) of
375 * the ComboBoxEntry to get the correct rendering from theme engines which
376 * special cases their look. Since the inner layout can change, we ask GTK
377 * to NULL our pointers when they are about to become invalid because the
378 * corresponding widgets don't exist anymore. It's the role of
379 * g_object_add_weak_pointer().
380 * Note that if we don't find the inner widgets (which shouldn't happen), we
381 * fallback to use generic "non-inner" widgets, and they don't need that kind
382 * of weak pointer since they are explicit children of gProtoWindow and as
383 * such GTK holds a strong reference to them. */
384static void
385moz_gtk_get_combo_box_entry_inner_widgets(GtkWidget *widget,
386 gpointer client_data)
387{
388 if (GTK_IS_TOGGLE_BUTTON(widget)) {
389 gComboBoxEntryButtonWidget = widget;
390 g_object_add_weak_pointer(G_OBJECT(widget),
391 (gpointer) &gComboBoxEntryButtonWidget);
392 } else if (GTK_IS_ENTRY(widget)) {
393 gComboBoxEntryTextareaWidget = widget;
394 g_object_add_weak_pointer(G_OBJECT(widget),
395 (gpointer) &gComboBoxEntryTextareaWidget);
396 } else
397 return;
398 gtk_widget_realize(widget);
399 g_object_set_data(G_OBJECT(widget), "transparent-bg-hint", TRUE);
400}
401
402static void
403moz_gtk_get_combo_box_entry_arrow(GtkWidget *widget, gpointer client_data)
404{
405 if (GTK_IS_ARROW(widget)) {
406 gComboBoxEntryArrowWidget = widget;
407 g_object_add_weak_pointer(G_OBJECT(widget),
408 (gpointer) &gComboBoxEntryArrowWidget);
409 gtk_widget_realize(widget);
410 g_object_set_data(G_OBJECT(widget), "transparent-bg-hint", TRUE);
411 }
412}
413
414static gint
415ensure_combo_box_entry_widgets()
416{
417 GtkWidget* buttonChild;
418
419 if (gComboBoxEntryTextareaWidget &&
420 gComboBoxEntryButtonWidget &&
421 gComboBoxEntryArrowWidget)
422 return MOZ_GTK_SUCCESS;
423
424 /* Create a ComboBoxEntry if needed */
alp@webkit.org5a4c6982008-01-28 00:04:31 +0000425 if (!gComboBoxEntryWidget) {
426 gComboBoxEntryWidget = gtk_combo_box_entry_new();
427 setup_widget_prototype(gComboBoxEntryWidget);
428 }
alp@webkit.org5a4c6982008-01-28 00:04:31 +0000429
alp@webkit.orgd694e942008-09-15 00:20:15 +0000430 /* Get its inner Entry and Button */
431 gtk_container_forall(GTK_CONTAINER(gComboBoxEntryWidget),
432 moz_gtk_get_combo_box_entry_inner_widgets,
433 NULL);
alp@webkit.org5a4c6982008-01-28 00:04:31 +0000434
alp@webkit.orgd694e942008-09-15 00:20:15 +0000435 if (!gComboBoxEntryTextareaWidget) {
436 ensure_entry_widget();
437 gComboBoxEntryTextareaWidget = gEntryWidget;
alp@webkit.org5a4c6982008-01-28 00:04:31 +0000438 }
alp@webkit.org5a4c6982008-01-28 00:04:31 +0000439
alp@webkit.orgd694e942008-09-15 00:20:15 +0000440 if (gComboBoxEntryButtonWidget) {
441 /* Get the Arrow inside the Button */
442 buttonChild = GTK_BIN(gComboBoxEntryButtonWidget)->child;
443 if (GTK_IS_HBOX(buttonChild)) {
444 /* appears-as-list = FALSE, cell-view = TRUE; the button
445 * contains an hbox. This hbox is there because ComboBoxEntry
446 * inherits from ComboBox which needs to place a cell renderer,
447 * a separator, and an arrow in the button when appears-as-list
448 * is FALSE. Here the hbox should only contain an arrow, since
449 * a ComboBoxEntry doesn't need all those widgets in the
450 * button. */
451 gtk_container_forall(GTK_CONTAINER(buttonChild),
452 moz_gtk_get_combo_box_entry_arrow,
453 NULL);
454 } else if(GTK_IS_ARROW(buttonChild)) {
455 /* appears-as-list = TRUE, or cell-view = FALSE;
456 * the button only contains an arrow */
457 gComboBoxEntryArrowWidget = buttonChild;
458 g_object_add_weak_pointer(G_OBJECT(buttonChild), (gpointer)
459 &gComboBoxEntryArrowWidget);
460 gtk_widget_realize(gComboBoxEntryArrowWidget);
461 g_object_set_data(G_OBJECT(gComboBoxEntryArrowWidget),
462 "transparent-bg-hint", TRUE);
463 }
464 } else {
465 /* Shouldn't be reached with current internal gtk implementation;
466 * we use a generic toggle button as last resort fallback to avoid
467 * crashing. */
468 ensure_toggle_button_widget();
469 gComboBoxEntryButtonWidget = gToggleButtonWidget;
alpd8507382007-11-03 14:33:25 +0000470 }
alp@webkit.orgd694e942008-09-15 00:20:15 +0000471
472 if (!gComboBoxEntryArrowWidget) {
473 /* Shouldn't be reached with current internal gtk implementation;
474 * we gButtonArrowWidget as last resort fallback to avoid
475 * crashing. */
476 ensure_button_arrow_widget();
477 gComboBoxEntryArrowWidget = gButtonArrowWidget;
478 }
479
alpd8507382007-11-03 14:33:25 +0000480 return MOZ_GTK_SUCCESS;
481}
482
alp@webkit.orgd694e942008-09-15 00:20:15 +0000483
alpd8507382007-11-03 14:33:25 +0000484static gint
485ensure_handlebox_widget()
486{
487 if (!gHandleBoxWidget) {
488 gHandleBoxWidget = gtk_handle_box_new();
489 setup_widget_prototype(gHandleBoxWidget);
490 }
491 return MOZ_GTK_SUCCESS;
492}
493
494static gint
495ensure_toolbar_widget()
496{
497 if (!gToolbarWidget) {
498 ensure_handlebox_widget();
499 gToolbarWidget = gtk_toolbar_new();
500 gtk_container_add(GTK_CONTAINER(gHandleBoxWidget), gToolbarWidget);
501 gtk_widget_realize(gToolbarWidget);
alp@webkit.orgd694e942008-09-15 00:20:15 +0000502 g_object_set_data(G_OBJECT(gToolbarWidget), "transparent-bg-hint", TRUE);
alpd8507382007-11-03 14:33:25 +0000503 }
504 return MOZ_GTK_SUCCESS;
505}
506
507static gint
alp@webkit.org5a4c6982008-01-28 00:04:31 +0000508ensure_toolbar_separator_widget()
509{
510 if (!gToolbarSeparatorWidget) {
511 ensure_toolbar_widget();
512 gToolbarSeparatorWidget = GTK_WIDGET(gtk_separator_tool_item_new());
513 setup_widget_prototype(gToolbarSeparatorWidget);
514 }
515 return MOZ_GTK_SUCCESS;
516}
517
518static gint
alpd8507382007-11-03 14:33:25 +0000519ensure_tooltip_widget()
520{
521 if (!gTooltipWidget) {
522 gTooltipWidget = gtk_window_new(GTK_WINDOW_POPUP);
523 gtk_widget_realize(gTooltipWidget);
alp@webkit.orgd694e942008-09-15 00:20:15 +0000524 moz_gtk_set_widget_name(gTooltipWidget);
alpd8507382007-11-03 14:33:25 +0000525 }
526 return MOZ_GTK_SUCCESS;
527}
528
529static gint
530ensure_tab_widget()
531{
532 if (!gTabWidget) {
533 gTabWidget = gtk_notebook_new();
534 setup_widget_prototype(gTabWidget);
535 }
536 return MOZ_GTK_SUCCESS;
537}
538
539static gint
540ensure_progress_widget()
541{
542 if (!gProgressWidget) {
543 gProgressWidget = gtk_progress_bar_new();
544 setup_widget_prototype(gProgressWidget);
545 }
546 return MOZ_GTK_SUCCESS;
547}
548
549static gint
alp@webkit.org5a4c6982008-01-28 00:04:31 +0000550ensure_statusbar_widget()
551{
552 if (!gStatusbarWidget) {
553 gStatusbarWidget = gtk_statusbar_new();
554 setup_widget_prototype(gStatusbarWidget);
555 }
556 return MOZ_GTK_SUCCESS;
557}
558
559static gint
alpd8507382007-11-03 14:33:25 +0000560ensure_frame_widget()
561{
562 if (!gFrameWidget) {
alp@webkit.org5a4c6982008-01-28 00:04:31 +0000563 ensure_statusbar_widget();
alpd8507382007-11-03 14:33:25 +0000564 gFrameWidget = gtk_frame_new(NULL);
alp@webkit.org5a4c6982008-01-28 00:04:31 +0000565 gtk_container_add(GTK_CONTAINER(gStatusbarWidget), gFrameWidget);
566 gtk_widget_realize(gFrameWidget);
alpd8507382007-11-03 14:33:25 +0000567 }
568 return MOZ_GTK_SUCCESS;
569}
570
571static gint
572ensure_menu_bar_widget()
573{
574 if (!gMenuBarWidget) {
575 gMenuBarWidget = gtk_menu_bar_new();
576 setup_widget_prototype(gMenuBarWidget);
alpd8507382007-11-03 14:33:25 +0000577 }
578 return MOZ_GTK_SUCCESS;
579}
580
581static gint
582ensure_menu_bar_item_widget()
583{
584 if (!gMenuBarItemWidget) {
585 ensure_menu_bar_widget();
586 gMenuBarItemWidget = gtk_menu_item_new();
587 gtk_menu_shell_append(GTK_MENU_SHELL(gMenuBarWidget),
588 gMenuBarItemWidget);
589 gtk_widget_realize(gMenuBarItemWidget);
alp@webkit.orgd694e942008-09-15 00:20:15 +0000590 g_object_set_data(G_OBJECT(gMenuBarItemWidget),
591 "transparent-bg-hint", TRUE);
alpd8507382007-11-03 14:33:25 +0000592 }
593 return MOZ_GTK_SUCCESS;
594}
595
596static gint
597ensure_menu_popup_widget()
598{
599 if (!gMenuPopupWidget) {
600 ensure_menu_bar_item_widget();
601 gMenuPopupWidget = gtk_menu_new();
602 gtk_menu_item_set_submenu(GTK_MENU_ITEM(gMenuBarItemWidget),
603 gMenuPopupWidget);
604 gtk_widget_realize(gMenuPopupWidget);
alp@webkit.orgd694e942008-09-15 00:20:15 +0000605 g_object_set_data(G_OBJECT(gMenuPopupWidget),
606 "transparent-bg-hint", TRUE);
alpd8507382007-11-03 14:33:25 +0000607 }
608 return MOZ_GTK_SUCCESS;
609}
610
611static gint
612ensure_menu_item_widget()
613{
614 if (!gMenuItemWidget) {
615 ensure_menu_popup_widget();
616 gMenuItemWidget = gtk_menu_item_new_with_label("M");
617 gtk_menu_shell_append(GTK_MENU_SHELL(gMenuPopupWidget),
618 gMenuItemWidget);
619 gtk_widget_realize(gMenuItemWidget);
alp@webkit.orgd694e942008-09-15 00:20:15 +0000620 g_object_set_data(G_OBJECT(gMenuItemWidget),
621 "transparent-bg-hint", TRUE);
622 }
623 return MOZ_GTK_SUCCESS;
624}
625
626static gint
627ensure_image_menu_item_widget()
628{
629 if (!gImageMenuItemWidget) {
630 ensure_menu_popup_widget();
631 gImageMenuItemWidget = gtk_image_menu_item_new();
632 gtk_menu_shell_append(GTK_MENU_SHELL(gMenuPopupWidget),
633 gImageMenuItemWidget);
634 gtk_widget_realize(gImageMenuItemWidget);
635 g_object_set_data(G_OBJECT(gImageMenuItemWidget),
636 "transparent-bg-hint", TRUE);
alpd8507382007-11-03 14:33:25 +0000637 }
638 return MOZ_GTK_SUCCESS;
639}
640
641static gint
alp@webkit.org5a4c6982008-01-28 00:04:31 +0000642ensure_menu_separator_widget()
643{
644 if (!gMenuSeparatorWidget) {
645 ensure_menu_popup_widget();
646 gMenuSeparatorWidget = gtk_separator_menu_item_new();
647 gtk_menu_shell_append(GTK_MENU_SHELL(gMenuPopupWidget),
648 gMenuSeparatorWidget);
649 gtk_widget_realize(gMenuSeparatorWidget);
alp@webkit.orgd694e942008-09-15 00:20:15 +0000650 g_object_set_data(G_OBJECT(gMenuSeparatorWidget),
651 "transparent-bg-hint", TRUE);
alp@webkit.org5a4c6982008-01-28 00:04:31 +0000652 }
653 return MOZ_GTK_SUCCESS;
654}
655
656static gint
alpd8507382007-11-03 14:33:25 +0000657ensure_check_menu_item_widget()
658{
659 if (!gCheckMenuItemWidget) {
660 ensure_menu_popup_widget();
661 gCheckMenuItemWidget = gtk_check_menu_item_new_with_label("M");
662 gtk_menu_shell_append(GTK_MENU_SHELL(gMenuPopupWidget),
663 gCheckMenuItemWidget);
664 gtk_widget_realize(gCheckMenuItemWidget);
alp@webkit.orgd694e942008-09-15 00:20:15 +0000665 g_object_set_data(G_OBJECT(gCheckMenuItemWidget),
666 "transparent-bg-hint", TRUE);
alpd8507382007-11-03 14:33:25 +0000667 }
668 return MOZ_GTK_SUCCESS;
669}
670
alp@webkit.org5a4c6982008-01-28 00:04:31 +0000671static gint
672ensure_tree_view_widget()
673{
674 if (!gTreeViewWidget) {
675 gTreeViewWidget = gtk_tree_view_new();
676 setup_widget_prototype(gTreeViewWidget);
677 }
678 return MOZ_GTK_SUCCESS;
679}
680
681static gint
682ensure_tree_header_cell_widget()
683{
684 if(!gTreeHeaderCellWidget) {
alp@webkit.orgd694e942008-09-15 00:20:15 +0000685 /*
686 * Some GTK engines paint the first and last cell
687 * of a TreeView header with a highlight.
688 * Since we do not know where our widget will be relative
689 * to the other buttons in the TreeView header, we must
690 * paint it as a button that is between two others,
691 * thus ensuring it is neither the first or last button
692 * in the header.
693 * GTK doesn't give us a way to do this explicitly,
694 * so we must paint with a button that is between two
695 * others.
696 */
697
698 GtkTreeViewColumn* firstTreeViewColumn;
699 GtkTreeViewColumn* lastTreeViewColumn;
700
alp@webkit.org5a4c6982008-01-28 00:04:31 +0000701 ensure_tree_view_widget();
702
alp@webkit.orgd694e942008-09-15 00:20:15 +0000703 /* Create and append our three columns */
704 firstTreeViewColumn = gtk_tree_view_column_new();
705 gtk_tree_view_column_set_title(firstTreeViewColumn, "M");
706 gtk_tree_view_append_column(GTK_TREE_VIEW(gTreeViewWidget), firstTreeViewColumn);
alp@webkit.org5a4c6982008-01-28 00:04:31 +0000707
alp@webkit.orgd694e942008-09-15 00:20:15 +0000708 gMiddleTreeViewColumn = gtk_tree_view_column_new();
709 gtk_tree_view_column_set_title(GTK_TREE_VIEW_COLUMN(gMiddleTreeViewColumn), "M");
710 gtk_tree_view_append_column(GTK_TREE_VIEW(gTreeViewWidget),
711 GTK_TREE_VIEW_COLUMN(gMiddleTreeViewColumn));
712
713 lastTreeViewColumn = gtk_tree_view_column_new();
714 gtk_tree_view_column_set_title(lastTreeViewColumn, "M");
715 gtk_tree_view_append_column(GTK_TREE_VIEW(gTreeViewWidget), lastTreeViewColumn);
716
717 /* Use the middle column's header for our button */
718 gTreeHeaderCellWidget = GTK_TREE_VIEW_COLUMN(gMiddleTreeViewColumn)->button;
719 gTreeHeaderSortArrowWidget = GTK_TREE_VIEW_COLUMN(gMiddleTreeViewColumn)->arrow;
720 g_object_set_data(G_OBJECT(gTreeHeaderCellWidget),
721 "transparent-bg-hint", TRUE);
722 g_object_set_data(G_OBJECT(gTreeHeaderSortArrowWidget),
723 "transparent-bg-hint", TRUE);
alp@webkit.org5a4c6982008-01-28 00:04:31 +0000724 }
725 return MOZ_GTK_SUCCESS;
726}
727
728static gint
729ensure_expander_widget()
730{
731 if (!gExpanderWidget) {
732 gExpanderWidget = gtk_expander_new("M");
733 setup_widget_prototype(gExpanderWidget);
734 }
735 return MOZ_GTK_SUCCESS;
736}
737
alp@webkit.orgd694e942008-09-15 00:20:15 +0000738static gint
739ensure_scrolled_window_widget()
740{
741 if (!gScrolledWindowWidget) {
742 gScrolledWindowWidget = gtk_scrolled_window_new(NULL, NULL);
743 setup_widget_prototype(gScrolledWindowWidget);
744 }
745 return MOZ_GTK_SUCCESS;
746}
747
alpd8507382007-11-03 14:33:25 +0000748static GtkStateType
749ConvertGtkState(GtkWidgetState* state)
750{
751 if (state->disabled)
752 return GTK_STATE_INSENSITIVE;
alp@webkit.org5a4c6982008-01-28 00:04:31 +0000753 else if (state->depressed)
754 return (state->inHover ? GTK_STATE_PRELIGHT : GTK_STATE_ACTIVE);
alpd8507382007-11-03 14:33:25 +0000755 else if (state->inHover)
756 return (state->active ? GTK_STATE_ACTIVE : GTK_STATE_PRELIGHT);
757 else
758 return GTK_STATE_NORMAL;
759}
760
761static gint
762TSOffsetStyleGCArray(GdkGC** gcs, gint xorigin, gint yorigin)
763{
764 int i;
765 /* there are 5 gc's in each array, for each of the widget states */
766 for (i = 0; i < 5; ++i)
767 gdk_gc_set_ts_origin(gcs[i], xorigin, yorigin);
768 return MOZ_GTK_SUCCESS;
769}
770
771static gint
772TSOffsetStyleGCs(GtkStyle* style, gint xorigin, gint yorigin)
773{
774 TSOffsetStyleGCArray(style->fg_gc, xorigin, yorigin);
775 TSOffsetStyleGCArray(style->bg_gc, xorigin, yorigin);
776 TSOffsetStyleGCArray(style->light_gc, xorigin, yorigin);
777 TSOffsetStyleGCArray(style->dark_gc, xorigin, yorigin);
778 TSOffsetStyleGCArray(style->mid_gc, xorigin, yorigin);
779 TSOffsetStyleGCArray(style->text_gc, xorigin, yorigin);
780 TSOffsetStyleGCArray(style->base_gc, xorigin, yorigin);
781 gdk_gc_set_ts_origin(style->black_gc, xorigin, yorigin);
782 gdk_gc_set_ts_origin(style->white_gc, xorigin, yorigin);
783 return MOZ_GTK_SUCCESS;
784}
785
786static gint
787moz_gtk_button_paint(GdkDrawable* drawable, GdkRectangle* rect,
788 GdkRectangle* cliprect, GtkWidgetState* state,
alp@webkit.org5a4c6982008-01-28 00:04:31 +0000789 GtkReliefStyle relief, GtkWidget* widget,
790 GtkTextDirection direction)
alpd8507382007-11-03 14:33:25 +0000791{
792 GtkShadowType shadow_type;
793 GtkStyle* style = widget->style;
794 GtkStateType button_state = ConvertGtkState(state);
795 gint x = rect->x, y=rect->y, width=rect->width, height=rect->height;
796
797 gboolean interior_focus;
798 gint focus_width, focus_pad;
799
alp@webkit.org5a4c6982008-01-28 00:04:31 +0000800 moz_gtk_widget_get_focus(widget, &interior_focus, &focus_width, &focus_pad);
alpd8507382007-11-03 14:33:25 +0000801
802 if (WINDOW_IS_MAPPED(drawable)) {
803 gdk_window_set_back_pixmap(drawable, NULL, TRUE);
804 gdk_window_clear_area(drawable, cliprect->x, cliprect->y,
805 cliprect->width, cliprect->height);
806 }
807
808 gtk_widget_set_state(widget, button_state);
alp@webkit.org5a4c6982008-01-28 00:04:31 +0000809 gtk_widget_set_direction(widget, direction);
alpd8507382007-11-03 14:33:25 +0000810
811 if (state->isDefault)
812 GTK_WIDGET_SET_FLAGS(widget, GTK_HAS_DEFAULT);
813
alp@webkit.orgd694e942008-09-15 00:20:15 +0000814 GTK_BUTTON(widget)->relief = relief;
815
816 /* Some theme engines love to cause us pain in that gtk_paint_focus is a
817 no-op on buttons and button-like widgets. They only listen to this flag. */
818 if (state->focused && !state->disabled)
819 GTK_WIDGET_SET_FLAGS(widget, GTK_HAS_FOCUS);
820
alpd8507382007-11-03 14:33:25 +0000821 if (!interior_focus && state->focused) {
822 x += focus_width + focus_pad;
823 y += focus_width + focus_pad;
824 width -= 2 * (focus_width + focus_pad);
825 height -= 2 * (focus_width + focus_pad);
826 }
827
alp@webkit.org5a4c6982008-01-28 00:04:31 +0000828 shadow_type = button_state == GTK_STATE_ACTIVE ||
829 state->depressed ? GTK_SHADOW_IN : GTK_SHADOW_OUT;
830
alp@webkit.orgd694e942008-09-15 00:20:15 +0000831 if (state->isDefault && relief == GTK_RELIEF_NORMAL) {
alp@webkit.org5a4c6982008-01-28 00:04:31 +0000832 gtk_paint_box(style, drawable, button_state, shadow_type, cliprect,
833 widget, "buttondefault", x, y, width, height);
834 }
835
836 if (relief != GTK_RELIEF_NONE || state->depressed ||
837 (button_state != GTK_STATE_NORMAL &&
838 button_state != GTK_STATE_INSENSITIVE)) {
alpd8507382007-11-03 14:33:25 +0000839 TSOffsetStyleGCs(style, x, y);
840 /* the following line can trigger an assertion (Crux theme)
841 file ../../gdk/gdkwindow.c: line 1846 (gdk_window_clear_area):
842 assertion `GDK_IS_WINDOW (window)' failed */
843 gtk_paint_box(style, drawable, button_state, shadow_type, cliprect,
844 widget, "button", x, y, width, height);
845 }
846
847 if (state->focused) {
848 if (interior_focus) {
849 x += widget->style->xthickness + focus_pad;
850 y += widget->style->ythickness + focus_pad;
851 width -= 2 * (widget->style->xthickness + focus_pad);
852 height -= 2 * (widget->style->ythickness + focus_pad);
853 } else {
854 x -= focus_width + focus_pad;
855 y -= focus_width + focus_pad;
856 width += 2 * (focus_width + focus_pad);
857 height += 2 * (focus_width + focus_pad);
858 }
859
860 TSOffsetStyleGCs(style, x, y);
861 gtk_paint_focus(style, drawable, button_state, cliprect,
862 widget, "button", x, y, width, height);
863 }
864
865 GTK_WIDGET_UNSET_FLAGS(widget, GTK_HAS_DEFAULT);
alp@webkit.orgd694e942008-09-15 00:20:15 +0000866 GTK_WIDGET_UNSET_FLAGS(widget, GTK_HAS_FOCUS);
alpd8507382007-11-03 14:33:25 +0000867 return MOZ_GTK_SUCCESS;
868}
869
870gint
871moz_gtk_init()
872{
alp@webkit.orgd694e942008-09-15 00:20:15 +0000873 GtkWidgetClass *entry_class;
874
alpd8507382007-11-03 14:33:25 +0000875 is_initialized = TRUE;
alp@webkit.orgd694e942008-09-15 00:20:15 +0000876 have_arrow_scaling = (gtk_major_version > 2 ||
877 (gtk_major_version == 2 && gtk_minor_version >= 12));
878
879 /* Add style property to GtkEntry.
880 * Adding the style property to the normal GtkEntry class means that it
881 * will work without issues inside GtkComboBox and for Spinbuttons. */
882 entry_class = g_type_class_ref(GTK_TYPE_ENTRY);
883 gtk_widget_class_install_style_property(entry_class,
884 g_param_spec_boolean("honors-transparent-bg-hint",
885 "Transparent BG enabling flag",
886 "If TRUE, the theme is able to draw the GtkEntry on non-prefilled background.",
887 FALSE,
888 G_PARAM_READWRITE));
alpd8507382007-11-03 14:33:25 +0000889
890 return MOZ_GTK_SUCCESS;
891}
892
893gint
894moz_gtk_checkbox_get_metrics(gint* indicator_size, gint* indicator_spacing)
895{
896 ensure_checkbox_widget();
897
898 gtk_widget_style_get (gCheckboxWidget,
899 "indicator_size", indicator_size,
900 "indicator_spacing", indicator_spacing,
901 NULL);
902
903 return MOZ_GTK_SUCCESS;
904}
905
906gint
907moz_gtk_radio_get_metrics(gint* indicator_size, gint* indicator_spacing)
908{
909 ensure_radiobutton_widget();
910
911 gtk_widget_style_get (gRadiobuttonWidget,
912 "indicator_size", indicator_size,
913 "indicator_spacing", indicator_spacing,
914 NULL);
915
916 return MOZ_GTK_SUCCESS;
917}
918
919gint
alp@webkit.org5a4c6982008-01-28 00:04:31 +0000920moz_gtk_widget_get_focus(GtkWidget* widget, gboolean* interior_focus,
921 gint* focus_width, gint* focus_pad)
alpd8507382007-11-03 14:33:25 +0000922{
alp@webkit.org5a4c6982008-01-28 00:04:31 +0000923 gtk_widget_style_get (widget,
alpd8507382007-11-03 14:33:25 +0000924 "interior-focus", interior_focus,
925 "focus-line-width", focus_width,
926 "focus-padding", focus_pad,
927 NULL);
928
929 return MOZ_GTK_SUCCESS;
930}
931
alp@webkit.org5a4c6982008-01-28 00:04:31 +0000932gint
933moz_gtk_splitter_get_metrics(gint orientation, gint* size)
934{
935 if (orientation == GTK_ORIENTATION_HORIZONTAL) {
936 ensure_hpaned_widget();
937 gtk_widget_style_get(gHPanedWidget, "handle_size", size, NULL);
938 } else {
939 ensure_vpaned_widget();
940 gtk_widget_style_get(gVPanedWidget, "handle_size", size, NULL);
941 }
942 return MOZ_GTK_SUCCESS;
943}
944
alp@webkit.orgd694e942008-09-15 00:20:15 +0000945gint
946moz_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 gtk_widget_style_get (widget, "inner-border", &tmp_border, NULL);
952
953 if (tmp_border) {
954 *inner_border = *tmp_border;
955 gtk_border_free(tmp_border);
956 }
957 else
958 *inner_border = default_inner_border;
959
960 return MOZ_GTK_SUCCESS;
961}
962
alpd8507382007-11-03 14:33:25 +0000963static gint
964moz_gtk_toggle_paint(GdkDrawable* drawable, GdkRectangle* rect,
965 GdkRectangle* cliprect, GtkWidgetState* state,
alp@webkit.org5a4c6982008-01-28 00:04:31 +0000966 gboolean selected, gboolean isradio,
967 GtkTextDirection direction)
alpd8507382007-11-03 14:33:25 +0000968{
969 GtkStateType state_type = ConvertGtkState(state);
970 GtkShadowType shadow_type = (selected)?GTK_SHADOW_IN:GTK_SHADOW_OUT;
971 gint indicator_size, indicator_spacing;
972 gint x, y, width, height;
alp@webkit.orgd694e942008-09-15 00:20:15 +0000973 gint focus_x, focus_y, focus_width, focus_height;
alpd8507382007-11-03 14:33:25 +0000974 GtkWidget *w;
975 GtkStyle *style;
976
977 if (isradio) {
978 moz_gtk_radio_get_metrics(&indicator_size, &indicator_spacing);
979 w = gRadiobuttonWidget;
980 } else {
981 moz_gtk_checkbox_get_metrics(&indicator_size, &indicator_spacing);
982 w = gCheckboxWidget;
983 }
984
alp@webkit.orgd694e942008-09-15 00:20:15 +0000985 /*
986 * vertically center in the box, since XUL sometimes ignores our
987 * GetMinimumWidgetSize in the vertical dimension
988 */
989 x = rect->x;
alpd8507382007-11-03 14:33:25 +0000990 y = rect->y + (rect->height - indicator_size) / 2;
991 width = indicator_size;
992 height = indicator_size;
alp@webkit.orgd694e942008-09-15 00:20:15 +0000993
994 focus_x = x - indicator_spacing;
995 focus_y = y - indicator_spacing;
996 focus_width = width + 2 * indicator_spacing;
997 focus_height = height + 2 * indicator_spacing;
alpd8507382007-11-03 14:33:25 +0000998
999 style = w->style;
1000 TSOffsetStyleGCs(style, x, y);
1001
1002 gtk_widget_set_sensitive(w, !state->disabled);
alp@webkit.org5a4c6982008-01-28 00:04:31 +00001003 gtk_widget_set_direction(w, direction);
alpd8507382007-11-03 14:33:25 +00001004 GTK_TOGGLE_BUTTON(w)->active = selected;
1005
1006 if (isradio) {
1007 gtk_paint_option(style, drawable, state_type, shadow_type, cliprect,
1008 gRadiobuttonWidget, "radiobutton", x, y,
1009 width, height);
1010 if (state->focused) {
1011 gtk_paint_focus(style, drawable, GTK_STATE_ACTIVE, cliprect,
alp@webkit.orgd694e942008-09-15 00:20:15 +00001012 gRadiobuttonWidget, "radiobutton", focus_x, focus_y,
1013 focus_width, focus_height);
alpd8507382007-11-03 14:33:25 +00001014 }
1015 }
1016 else {
1017 gtk_paint_check(style, drawable, state_type, shadow_type, cliprect,
1018 gCheckboxWidget, "checkbutton", x, y, width, height);
1019 if (state->focused) {
1020 gtk_paint_focus(style, drawable, GTK_STATE_ACTIVE, cliprect,
alp@webkit.orgd694e942008-09-15 00:20:15 +00001021 gCheckboxWidget, "checkbutton", focus_x, focus_y,
1022 focus_width, focus_height);
alpd8507382007-11-03 14:33:25 +00001023 }
1024 }
1025
1026 return MOZ_GTK_SUCCESS;
1027}
1028
1029static gint
alp@webkit.orgd694e942008-09-15 00:20:15 +00001030calculate_button_inner_rect(GtkWidget* button, GdkRectangle* rect,
1031 GdkRectangle* inner_rect,
1032 GtkTextDirection direction,
1033 gboolean ignore_focus)
alpd8507382007-11-03 14:33:25 +00001034{
alp@webkit.orgd694e942008-09-15 00:20:15 +00001035 GtkBorder inner_border;
1036 gboolean interior_focus;
1037 gint focus_width, focus_pad;
1038 GtkStyle* style;
alpd8507382007-11-03 14:33:25 +00001039
alp@webkit.orgd694e942008-09-15 00:20:15 +00001040 style = button->style;
alpd8507382007-11-03 14:33:25 +00001041
alp@webkit.orgd694e942008-09-15 00:20:15 +00001042 /* This mirrors gtkbutton's child positioning */
1043 moz_gtk_button_get_inner_border(button, &inner_border);
1044 moz_gtk_widget_get_focus(button, &interior_focus,
1045 &focus_width, &focus_pad);
alpd8507382007-11-03 14:33:25 +00001046
alp@webkit.orgd694e942008-09-15 00:20:15 +00001047 if (ignore_focus)
1048 focus_width = focus_pad = 0;
1049
1050 inner_rect->x = rect->x + XTHICKNESS(style) + focus_width + focus_pad;
1051 inner_rect->x += direction == GTK_TEXT_DIR_LTR ?
1052 inner_border.left : inner_border.right;
1053 inner_rect->y = rect->y + inner_border.top + YTHICKNESS(style) +
1054 focus_width + focus_pad;
1055 inner_rect->width = MAX(1, rect->width - inner_border.left -
1056 inner_border.right - (XTHICKNESS(style) + focus_pad + focus_width) * 2);
1057 inner_rect->height = MAX(1, rect->height - inner_border.top -
1058 inner_border.bottom - (YTHICKNESS(style) + focus_pad + focus_width) * 2);
1059
1060 return MOZ_GTK_SUCCESS;
1061}
1062
1063
1064static gint
1065calculate_arrow_rect(GtkWidget* arrow, GdkRectangle* rect,
1066 GdkRectangle* arrow_rect, GtkTextDirection direction)
1067{
1068 /* defined in gtkarrow.c */
1069 gfloat arrow_scaling = 0.7;
1070 gfloat xalign, xpad;
1071 gint extent;
1072 GtkMisc* misc = GTK_MISC(arrow);
1073
1074 if (have_arrow_scaling)
1075 gtk_widget_style_get(arrow, "arrow_scaling", &arrow_scaling, NULL);
1076
1077 extent = MIN((rect->width - misc->xpad * 2),
1078 (rect->height - misc->ypad * 2)) * arrow_scaling;
1079
1080 xalign = direction == GTK_TEXT_DIR_LTR ? misc->xalign : 1.0 - misc->xalign;
1081 xpad = misc->xpad + (rect->width - extent) * xalign;
1082
1083 arrow_rect->x = direction == GTK_TEXT_DIR_LTR ?
1084 floor(rect->x + xpad) : ceil(rect->x + xpad);
1085 arrow_rect->y = floor(rect->y + misc->ypad +
1086 ((rect->height - extent) * misc->yalign));
alpd8507382007-11-03 14:33:25 +00001087
1088 arrow_rect->width = arrow_rect->height = extent;
1089
1090 return MOZ_GTK_SUCCESS;
1091}
1092
1093static gint
1094moz_gtk_scrollbar_button_paint(GdkDrawable* drawable, GdkRectangle* rect,
1095 GdkRectangle* cliprect, GtkWidgetState* state,
alp@webkit.org5a4c6982008-01-28 00:04:31 +00001096 GtkScrollbarButtonFlags flags,
1097 GtkTextDirection direction)
alpd8507382007-11-03 14:33:25 +00001098{
1099 GtkStateType state_type = ConvertGtkState(state);
1100 GtkShadowType shadow_type = (state->active) ?
1101 GTK_SHADOW_IN : GTK_SHADOW_OUT;
alpd8507382007-11-03 14:33:25 +00001102 GdkRectangle arrow_rect;
1103 GtkStyle* style;
alp@webkit.org5a4c6982008-01-28 00:04:31 +00001104 GtkWidget *scrollbar;
1105 GtkArrowType arrow_type;
alp@webkit.orgd694e942008-09-15 00:20:15 +00001106 gint arrow_displacement_x, arrow_displacement_y;
alp@webkit.org5a4c6982008-01-28 00:04:31 +00001107 const char* detail = (flags & MOZ_GTK_STEPPER_VERTICAL) ?
1108 "vscrollbar" : "hscrollbar";
alpd8507382007-11-03 14:33:25 +00001109
1110 ensure_scrollbar_widget();
1111
alp@webkit.org5a4c6982008-01-28 00:04:31 +00001112 if (flags & MOZ_GTK_STEPPER_VERTICAL)
1113 scrollbar = gVertScrollbarWidget;
alpd8507382007-11-03 14:33:25 +00001114 else
alp@webkit.org5a4c6982008-01-28 00:04:31 +00001115 scrollbar = gHorizScrollbarWidget;
1116
1117 gtk_widget_set_direction(scrollbar, direction);
alpd8507382007-11-03 14:33:25 +00001118
1119 /* Some theme engines (i.e., ClearLooks) check the scrollbar's allocation
1120 to determine where it should paint rounded corners on the buttons.
1121 We need to trick them into drawing the buttons the way we want them. */
1122
alp@webkit.org5a4c6982008-01-28 00:04:31 +00001123 scrollbar->allocation.x = rect->x;
1124 scrollbar->allocation.y = rect->y;
1125 scrollbar->allocation.width = rect->width;
1126 scrollbar->allocation.height = rect->height;
alpd8507382007-11-03 14:33:25 +00001127
alp@webkit.org5a4c6982008-01-28 00:04:31 +00001128 if (flags & MOZ_GTK_STEPPER_VERTICAL) {
1129 scrollbar->allocation.height *= 5;
1130 if (flags & MOZ_GTK_STEPPER_DOWN) {
1131 arrow_type = GTK_ARROW_DOWN;
1132 if (flags & MOZ_GTK_STEPPER_BOTTOM)
1133 scrollbar->allocation.y -= 4 * rect->height;
1134 else
1135 scrollbar->allocation.y -= rect->height;
1136
1137 } else {
1138 arrow_type = GTK_ARROW_UP;
1139 if (flags & MOZ_GTK_STEPPER_BOTTOM)
1140 scrollbar->allocation.y -= 3 * rect->height;
1141 }
alpd8507382007-11-03 14:33:25 +00001142 } else {
alp@webkit.org5a4c6982008-01-28 00:04:31 +00001143 scrollbar->allocation.width *= 5;
1144 if (flags & MOZ_GTK_STEPPER_DOWN) {
1145 arrow_type = GTK_ARROW_RIGHT;
1146 if (flags & MOZ_GTK_STEPPER_BOTTOM)
1147 scrollbar->allocation.x -= 4 * rect->width;
1148 else
1149 scrollbar->allocation.x -= rect->width;
1150 } else {
1151 arrow_type = GTK_ARROW_LEFT;
1152 if (flags & MOZ_GTK_STEPPER_BOTTOM)
1153 scrollbar->allocation.x -= 3 * rect->width;
1154 }
alpd8507382007-11-03 14:33:25 +00001155 }
1156
alp@webkit.org5a4c6982008-01-28 00:04:31 +00001157 style = scrollbar->style;
alpd8507382007-11-03 14:33:25 +00001158
alp@webkit.orgd694e942008-09-15 00:20:15 +00001159 TSOffsetStyleGCs(style, rect->x, rect->y);
alpd8507382007-11-03 14:33:25 +00001160
1161 gtk_paint_box(style, drawable, state_type, shadow_type, cliprect,
alp@webkit.orgd694e942008-09-15 00:20:15 +00001162 scrollbar, detail, rect->x, rect->y,
1163 rect->width, rect->height);
alpd8507382007-11-03 14:33:25 +00001164
alp@webkit.orgd694e942008-09-15 00:20:15 +00001165 arrow_rect.width = rect->width / 2;
1166 arrow_rect.height = rect->height / 2;
1167 arrow_rect.x = rect->x + (rect->width - arrow_rect.width) / 2;
1168 arrow_rect.y = rect->y + (rect->height - arrow_rect.height) / 2;
1169
1170 if (state_type == GTK_STATE_ACTIVE) {
1171 gtk_widget_style_get(scrollbar,
1172 "arrow-displacement-x", &arrow_displacement_x,
1173 "arrow-displacement-y", &arrow_displacement_y,
1174 NULL);
1175
1176 arrow_rect.x += arrow_displacement_x;
1177 arrow_rect.y += arrow_displacement_y;
1178 }
alpd8507382007-11-03 14:33:25 +00001179
1180 gtk_paint_arrow(style, drawable, state_type, shadow_type, cliprect,
alp@webkit.org5a4c6982008-01-28 00:04:31 +00001181 scrollbar, detail, arrow_type, TRUE, arrow_rect.x,
1182 arrow_rect.y, arrow_rect.width, arrow_rect.height);
alpd8507382007-11-03 14:33:25 +00001183
1184 return MOZ_GTK_SUCCESS;
1185}
1186
1187static gint
1188moz_gtk_scrollbar_trough_paint(GtkThemeWidgetType widget,
1189 GdkDrawable* drawable, GdkRectangle* rect,
alp@webkit.org5a4c6982008-01-28 00:04:31 +00001190 GdkRectangle* cliprect, GtkWidgetState* state,
1191 GtkTextDirection direction)
alpd8507382007-11-03 14:33:25 +00001192{
1193 GtkStyle* style;
1194 GtkScrollbar *scrollbar;
1195
1196 ensure_scrollbar_widget();
1197
1198 if (widget == MOZ_GTK_SCROLLBAR_TRACK_HORIZONTAL)
1199 scrollbar = GTK_SCROLLBAR(gHorizScrollbarWidget);
1200 else
1201 scrollbar = GTK_SCROLLBAR(gVertScrollbarWidget);
1202
alp@webkit.org5a4c6982008-01-28 00:04:31 +00001203 gtk_widget_set_direction(GTK_WIDGET(scrollbar), direction);
1204
alpd8507382007-11-03 14:33:25 +00001205 style = GTK_WIDGET(scrollbar)->style;
1206
1207 TSOffsetStyleGCs(style, rect->x, rect->y);
1208 gtk_style_apply_default_background(style, drawable, TRUE, GTK_STATE_ACTIVE,
1209 cliprect, rect->x, rect->y,
1210 rect->width, rect->height);
1211
1212 gtk_paint_box(style, drawable, GTK_STATE_ACTIVE, GTK_SHADOW_IN, cliprect,
1213 GTK_WIDGET(scrollbar), "trough", rect->x, rect->y,
1214 rect->width, rect->height);
1215
1216 if (state->focused) {
1217 gtk_paint_focus(style, drawable, GTK_STATE_ACTIVE, cliprect,
1218 GTK_WIDGET(scrollbar), "trough",
1219 rect->x, rect->y, rect->width, rect->height);
1220 }
1221
1222 return MOZ_GTK_SUCCESS;
1223}
1224
1225static gint
1226moz_gtk_scrollbar_thumb_paint(GtkThemeWidgetType widget,
1227 GdkDrawable* drawable, GdkRectangle* rect,
alp@webkit.org5a4c6982008-01-28 00:04:31 +00001228 GdkRectangle* cliprect, GtkWidgetState* state,
1229 GtkTextDirection direction)
alpd8507382007-11-03 14:33:25 +00001230{
1231 GtkStateType state_type = (state->inHover || state->active) ?
1232 GTK_STATE_PRELIGHT : GTK_STATE_NORMAL;
alp@webkit.orgd694e942008-09-15 00:20:15 +00001233 GtkShadowType shadow_type = GTK_SHADOW_OUT;
alpd8507382007-11-03 14:33:25 +00001234 GtkStyle* style;
1235 GtkScrollbar *scrollbar;
1236 GtkAdjustment *adj;
alp@webkit.orgd694e942008-09-15 00:20:15 +00001237 gboolean activate_slider;
alpd8507382007-11-03 14:33:25 +00001238
1239 ensure_scrollbar_widget();
1240
1241 if (widget == MOZ_GTK_SCROLLBAR_THUMB_HORIZONTAL)
1242 scrollbar = GTK_SCROLLBAR(gHorizScrollbarWidget);
1243 else
1244 scrollbar = GTK_SCROLLBAR(gVertScrollbarWidget);
1245
alp@webkit.org5a4c6982008-01-28 00:04:31 +00001246 gtk_widget_set_direction(GTK_WIDGET(scrollbar), direction);
1247
alpd8507382007-11-03 14:33:25 +00001248 /* Make sure to set the scrollbar range before painting so that
1249 everything is drawn properly. At least the bluecurve (and
1250 maybe other) themes don't draw the top or bottom black line
1251 surrounding the scrollbar if the theme thinks that it's butted
1252 up against the scrollbar arrows. Note the increases of the
1253 clip rect below. */
1254 /* Changing the cliprect is pretty bogus. This lets themes draw
1255 outside the frame, which means we don't invalidate them
1256 correctly. See bug 297508. But some themes do seem to need
1257 it. So we modify the frame's overflow area to account for what
1258 we're doing here; see nsNativeThemeGTK::GetWidgetOverflow. */
1259 adj = gtk_range_get_adjustment(GTK_RANGE(scrollbar));
1260
1261 if (widget == MOZ_GTK_SCROLLBAR_THUMB_HORIZONTAL) {
1262 cliprect->x -= 1;
1263 cliprect->width += 2;
1264 adj->page_size = rect->width;
1265 }
1266 else {
1267 cliprect->y -= 1;
1268 cliprect->height += 2;
1269 adj->page_size = rect->height;
1270 }
1271
1272 adj->lower = 0;
1273 adj->value = state->curpos;
1274 adj->upper = state->maxpos;
1275 gtk_adjustment_changed(adj);
1276
1277 style = GTK_WIDGET(scrollbar)->style;
alp@webkit.orgd694e942008-09-15 00:20:15 +00001278
1279 gtk_widget_style_get(GTK_WIDGET(scrollbar), "activate-slider",
1280 &activate_slider, NULL);
1281
1282 if (activate_slider && state->active) {
1283 shadow_type = GTK_SHADOW_IN;
1284 state_type = GTK_STATE_ACTIVE;
1285 }
alpd8507382007-11-03 14:33:25 +00001286
1287 TSOffsetStyleGCs(style, rect->x, rect->y);
1288
alp@webkit.orgd694e942008-09-15 00:20:15 +00001289 gtk_paint_slider(style, drawable, state_type, shadow_type, cliprect,
alpd8507382007-11-03 14:33:25 +00001290 GTK_WIDGET(scrollbar), "slider", rect->x, rect->y,
1291 rect->width, rect->height,
1292 (widget == MOZ_GTK_SCROLLBAR_THUMB_HORIZONTAL) ?
1293 GTK_ORIENTATION_HORIZONTAL : GTK_ORIENTATION_VERTICAL);
1294
1295 return MOZ_GTK_SUCCESS;
1296}
1297
1298static gint
alp@webkit.org5a4c6982008-01-28 00:04:31 +00001299moz_gtk_spin_paint(GdkDrawable* drawable, GdkRectangle* rect,
1300 GtkTextDirection direction)
1301{
1302 GtkStyle* style;
1303
1304 ensure_spin_widget();
1305 gtk_widget_set_direction(gSpinWidget, direction);
1306 style = gSpinWidget->style;
1307
1308 TSOffsetStyleGCs(style, rect->x, rect->y);
1309 gtk_paint_box(style, drawable, GTK_STATE_NORMAL, GTK_SHADOW_IN, NULL,
1310 gSpinWidget, "spinbutton",
1311 rect->x, rect->y, rect->width, rect->height);
1312 return MOZ_GTK_SUCCESS;
1313}
1314
1315static gint
1316moz_gtk_spin_updown_paint(GdkDrawable* drawable, GdkRectangle* rect,
1317 gboolean isDown, GtkWidgetState* state,
1318 GtkTextDirection direction)
alpd8507382007-11-03 14:33:25 +00001319{
1320 GdkRectangle arrow_rect;
1321 GtkStateType state_type = ConvertGtkState(state);
alp@webkit.org5a4c6982008-01-28 00:04:31 +00001322 GtkShadowType shadow_type = state_type == GTK_STATE_ACTIVE ?
1323 GTK_SHADOW_IN : GTK_SHADOW_OUT;
alpd8507382007-11-03 14:33:25 +00001324 GtkStyle* style;
1325
1326 ensure_spin_widget();
1327 style = gSpinWidget->style;
alp@webkit.org5a4c6982008-01-28 00:04:31 +00001328 gtk_widget_set_direction(gSpinWidget, direction);
alpd8507382007-11-03 14:33:25 +00001329
1330 TSOffsetStyleGCs(style, rect->x, rect->y);
1331 gtk_paint_box(style, drawable, state_type, shadow_type, NULL, gSpinWidget,
1332 isDown ? "spinbutton_down" : "spinbutton_up",
1333 rect->x, rect->y, rect->width, rect->height);
1334
1335 /* hard code these values */
1336 arrow_rect.width = 6;
1337 arrow_rect.height = 6;
1338 arrow_rect.x = rect->x + (rect->width - arrow_rect.width) / 2;
1339 arrow_rect.y = rect->y + (rect->height - arrow_rect.height) / 2;
1340 arrow_rect.y += isDown ? -1 : 1;
1341
1342 gtk_paint_arrow(style, drawable, state_type, shadow_type, NULL,
1343 gSpinWidget, "spinbutton",
1344 isDown ? GTK_ARROW_DOWN : GTK_ARROW_UP, TRUE,
1345 arrow_rect.x, arrow_rect.y,
1346 arrow_rect.width, arrow_rect.height);
1347
1348 return MOZ_GTK_SUCCESS;
1349}
1350
1351static gint
1352moz_gtk_scale_paint(GdkDrawable* drawable, GdkRectangle* rect,
1353 GdkRectangle* cliprect, GtkWidgetState* state,
alp@webkit.org5a4c6982008-01-28 00:04:31 +00001354 GtkOrientation flags, GtkTextDirection direction)
alpd8507382007-11-03 14:33:25 +00001355{
1356 gint x = 0, y = 0;
1357 GtkStateType state_type = ConvertGtkState(state);
1358 GtkStyle* style;
1359 GtkWidget* widget;
1360
1361 ensure_scale_widget();
1362 widget = ((flags == GTK_ORIENTATION_HORIZONTAL) ? gHScaleWidget : gVScaleWidget);
alp@webkit.org5a4c6982008-01-28 00:04:31 +00001363 gtk_widget_set_direction(widget, direction);
1364
alpd8507382007-11-03 14:33:25 +00001365 style = widget->style;
1366
1367 if (flags == GTK_ORIENTATION_HORIZONTAL) {
1368 x = XTHICKNESS(style);
1369 y++;
1370 }
1371 else {
1372 x++;
1373 y = YTHICKNESS(style);
1374 }
1375
1376 TSOffsetStyleGCs(style, rect->x, rect->y);
1377 gtk_style_apply_default_background(style, drawable, TRUE, GTK_STATE_NORMAL,
1378 cliprect, rect->x, rect->y,
1379 rect->width, rect->height);
1380
1381 gtk_paint_box(style, drawable, GTK_STATE_ACTIVE, GTK_SHADOW_IN, cliprect,
1382 widget, "trough", rect->x + x, rect->y + y,
1383 rect->width - 2*x, rect->height - 2*y);
1384
1385 if (state->focused)
1386 gtk_paint_focus(style, drawable, state_type, cliprect, widget, "trough",
1387 rect->x, rect->y, rect->width, rect->height);
1388
1389 return MOZ_GTK_SUCCESS;
1390}
1391
1392static gint
1393moz_gtk_scale_thumb_paint(GdkDrawable* drawable, GdkRectangle* rect,
1394 GdkRectangle* cliprect, GtkWidgetState* state,
alp@webkit.org5a4c6982008-01-28 00:04:31 +00001395 GtkOrientation flags, GtkTextDirection direction)
alpd8507382007-11-03 14:33:25 +00001396{
1397 GtkStateType state_type = ConvertGtkState(state);
1398 GtkStyle* style;
1399 GtkWidget* widget;
1400 gint thumb_width, thumb_height, x, y;
1401
1402 ensure_scale_widget();
1403 widget = ((flags == GTK_ORIENTATION_HORIZONTAL) ? gHScaleWidget : gVScaleWidget);
alp@webkit.org5a4c6982008-01-28 00:04:31 +00001404 gtk_widget_set_direction(widget, direction);
1405
alpd8507382007-11-03 14:33:25 +00001406 style = widget->style;
1407
1408 /* determine the thumb size, and position the thumb in the center in the opposite axis */
1409 if (flags == GTK_ORIENTATION_HORIZONTAL) {
1410 moz_gtk_get_scalethumb_metrics(GTK_ORIENTATION_HORIZONTAL, &thumb_width, &thumb_height);
1411 x = rect->x;
1412 y = rect->y + (rect->height - thumb_height) / 2;
1413 }
1414 else {
1415 moz_gtk_get_scalethumb_metrics(GTK_ORIENTATION_VERTICAL, &thumb_height, &thumb_width);
1416 x = rect->x + (rect->width - thumb_width) / 2;
1417 y = rect->y;
1418 }
1419
1420 TSOffsetStyleGCs(style, rect->x, rect->y);
1421 gtk_paint_slider(style, drawable, state_type, GTK_SHADOW_OUT, cliprect,
1422 widget, (flags == GTK_ORIENTATION_HORIZONTAL) ? "hscale" : "vscale",
1423 x, y, thumb_width, thumb_height, flags);
1424
1425 return MOZ_GTK_SUCCESS;
1426}
1427
1428static gint
1429moz_gtk_gripper_paint(GdkDrawable* drawable, GdkRectangle* rect,
alp@webkit.org5a4c6982008-01-28 00:04:31 +00001430 GdkRectangle* cliprect, GtkWidgetState* state,
1431 GtkTextDirection direction)
alpd8507382007-11-03 14:33:25 +00001432{
1433 GtkStateType state_type = ConvertGtkState(state);
1434 GtkShadowType shadow_type;
1435 GtkStyle* style;
1436
1437 ensure_handlebox_widget();
alp@webkit.org5a4c6982008-01-28 00:04:31 +00001438 gtk_widget_set_direction(gHandleBoxWidget, direction);
1439
alpd8507382007-11-03 14:33:25 +00001440 style = gHandleBoxWidget->style;
1441 shadow_type = GTK_HANDLE_BOX(gHandleBoxWidget)->shadow_type;
1442
1443 TSOffsetStyleGCs(style, rect->x, rect->y);
1444 gtk_paint_box(style, drawable, state_type, shadow_type, cliprect,
1445 gHandleBoxWidget, "handlebox_bin", rect->x, rect->y,
1446 rect->width, rect->height);
1447
1448 return MOZ_GTK_SUCCESS;
1449}
1450
1451static gint
alp@webkit.org5a4c6982008-01-28 00:04:31 +00001452moz_gtk_hpaned_paint(GdkDrawable* drawable, GdkRectangle* rect,
1453 GdkRectangle* cliprect, GtkWidgetState* state)
1454{
1455 GtkStateType hpaned_state = ConvertGtkState(state);
1456
1457 ensure_hpaned_widget();
1458 gtk_paint_handle(gHPanedWidget->style, drawable, hpaned_state,
1459 GTK_SHADOW_NONE, cliprect, gHPanedWidget, "paned",
1460 rect->x, rect->y, rect->width, rect->height,
1461 GTK_ORIENTATION_VERTICAL);
1462
1463 return MOZ_GTK_SUCCESS;
1464}
1465
1466static gint
1467moz_gtk_vpaned_paint(GdkDrawable* drawable, GdkRectangle* rect,
1468 GdkRectangle* cliprect, GtkWidgetState* state)
1469{
1470 GtkStateType vpaned_state = ConvertGtkState(state);
1471
1472 ensure_vpaned_widget();
1473 gtk_paint_handle(gVPanedWidget->style, drawable, vpaned_state,
1474 GTK_SHADOW_NONE, cliprect, gVPanedWidget, "paned",
1475 rect->x, rect->y, rect->width, rect->height,
1476 GTK_ORIENTATION_HORIZONTAL);
1477
1478 return MOZ_GTK_SUCCESS;
1479}
1480
1481static gint
alp@webkit.orgd694e942008-09-15 00:20:15 +00001482moz_gtk_caret_paint(GdkDrawable* drawable, GdkRectangle* rect,
1483 GdkRectangle* cliprect, GtkTextDirection direction)
1484{
1485 ensure_entry_widget();
1486 gtk_draw_insertion_cursor(gEntryWidget, drawable, cliprect,
1487 rect, TRUE, direction, FALSE);
1488
1489 return MOZ_GTK_SUCCESS;
1490}
1491
1492static gint
alpd8507382007-11-03 14:33:25 +00001493moz_gtk_entry_paint(GdkDrawable* drawable, GdkRectangle* rect,
alp@webkit.org5a4c6982008-01-28 00:04:31 +00001494 GdkRectangle* cliprect, GtkWidgetState* state,
1495 GtkWidget* widget, GtkTextDirection direction)
alpd8507382007-11-03 14:33:25 +00001496{
alp@webkit.orgd694e942008-09-15 00:20:15 +00001497 GtkStateType bg_state = state->disabled ?
1498 GTK_STATE_INSENSITIVE : GTK_STATE_NORMAL;
alpd8507382007-11-03 14:33:25 +00001499 gint x, y, width = rect->width, height = rect->height;
1500 GtkStyle* style;
1501 gboolean interior_focus;
alp@webkit.orgd694e942008-09-15 00:20:15 +00001502 gboolean theme_honors_transparency = FALSE;
alpd8507382007-11-03 14:33:25 +00001503 gint focus_width;
1504
alp@webkit.org5a4c6982008-01-28 00:04:31 +00001505 gtk_widget_set_direction(widget, direction);
1506
1507 style = widget->style;
alpd8507382007-11-03 14:33:25 +00001508
alp@webkit.orgd694e942008-09-15 00:20:15 +00001509 gtk_widget_style_get(widget,
1510 "interior-focus", &interior_focus,
1511 "focus-line-width", &focus_width,
1512 "honors-transparent-bg-hint", &theme_honors_transparency,
1513 NULL);
1514
1515 /* gtkentry.c uses two windows, one for the entire widget and one for the
1516 * text area inside it. The background of both windows is set to the "base"
1517 * color of the new state in gtk_entry_state_changed, but only the inner
1518 * textarea window uses gtk_paint_flat_box when exposed */
1519
1520 TSOffsetStyleGCs(style, rect->x, rect->y);
alpd8507382007-11-03 14:33:25 +00001521
1522 /* This gets us a lovely greyish disabledish look */
alp@webkit.org5a4c6982008-01-28 00:04:31 +00001523 gtk_widget_set_sensitive(widget, !state->disabled);
alpd8507382007-11-03 14:33:25 +00001524
alp@webkit.orgd694e942008-09-15 00:20:15 +00001525 /* GTK fills the outer widget window with the base color before drawing the widget.
1526 * Some older themes rely on this behavior, but many themes nowadays use rounded
1527 * corners on their widgets. While most GTK apps are blissfully unaware of this
1528 * problem due to their use of the default window background, we render widgets on
1529 * many kinds of backgrounds on the web.
1530 * If the theme is able to cope with transparency, then we can skip pre-filling
1531 * and notify the theme it will paint directly on the canvas. */
1532 if (theme_honors_transparency) {
1533 g_object_set_data(G_OBJECT(widget), "transparent-bg-hint", TRUE);
1534 } else {
1535 gdk_draw_rectangle(drawable, style->base_gc[bg_state], TRUE,
1536 cliprect->x, cliprect->y, cliprect->width, cliprect->height);
1537 g_object_set_data(G_OBJECT(widget), "transparent-bg-hint", FALSE);
1538 }
1539
1540 /* Get the position of the inner window, see _gtk_entry_get_borders */
1541 x = XTHICKNESS(style);
1542 y = YTHICKNESS(style);
1543
1544 if (!interior_focus) {
1545 x += focus_width;
1546 y += focus_width;
1547 }
1548
1549 /* Simulate an expose of the inner window */
1550 gtk_paint_flat_box(style, drawable, bg_state, GTK_SHADOW_NONE,
alp@webkit.org5a4c6982008-01-28 00:04:31 +00001551 cliprect, widget, "entry_bg", rect->x + x,
alpd8507382007-11-03 14:33:25 +00001552 rect->y + y, rect->width - 2*x, rect->height - 2*y);
1553
alp@webkit.orgd694e942008-09-15 00:20:15 +00001554 /* Now paint the shadow and focus border.
1555 * We do like in gtk_entry_draw_frame, we first draw the shadow, a tad
1556 * smaller when focused if the focus is not interior, then the focus. */
alpd8507382007-11-03 14:33:25 +00001557 x = rect->x;
1558 y = rect->y;
1559
1560 if (state->focused && !state->disabled) {
alp@webkit.orgd694e942008-09-15 00:20:15 +00001561 /* This will get us the lit borders that focused textboxes enjoy on
1562 * some themes. */
alp@webkit.org5a4c6982008-01-28 00:04:31 +00001563 GTK_WIDGET_SET_FLAGS(widget, GTK_HAS_FOCUS);
alpd8507382007-11-03 14:33:25 +00001564
1565 if (!interior_focus) {
1566 /* Indent the border a little bit if we have exterior focus
1567 (this is what GTK does to draw native entries) */
1568 x += focus_width;
1569 y += focus_width;
1570 width -= 2 * focus_width;
1571 height -= 2 * focus_width;
1572 }
1573 }
1574
alpd8507382007-11-03 14:33:25 +00001575 gtk_paint_shadow(style, drawable, GTK_STATE_NORMAL, GTK_SHADOW_IN,
alp@webkit.org5a4c6982008-01-28 00:04:31 +00001576 cliprect, widget, "entry", x, y, width, height);
alpd8507382007-11-03 14:33:25 +00001577
1578 if (state->focused && !state->disabled) {
1579 if (!interior_focus) {
alpd8507382007-11-03 14:33:25 +00001580 gtk_paint_focus(style, drawable, GTK_STATE_NORMAL, cliprect,
alp@webkit.org5a4c6982008-01-28 00:04:31 +00001581 widget, "entry",
alpd8507382007-11-03 14:33:25 +00001582 rect->x, rect->y, rect->width, rect->height);
1583 }
1584
alp@webkit.orgd694e942008-09-15 00:20:15 +00001585 /* Now unset the focus flag. We don't want other entries to look
1586 * like they're focused too! */
alp@webkit.org5a4c6982008-01-28 00:04:31 +00001587 GTK_WIDGET_UNSET_FLAGS(widget, GTK_HAS_FOCUS);
alpd8507382007-11-03 14:33:25 +00001588 }
1589
1590 return MOZ_GTK_SUCCESS;
1591}
1592
alp@webkit.org5a4c6982008-01-28 00:04:31 +00001593static gint
1594moz_gtk_treeview_paint(GdkDrawable* drawable, GdkRectangle* rect,
1595 GdkRectangle* cliprect, GtkWidgetState* state,
1596 GtkTextDirection direction)
1597{
1598 gint xthickness, ythickness;
1599
1600 GtkStyle *style;
1601 GtkStateType state_type;
1602
1603 ensure_tree_view_widget();
alp@webkit.orgd694e942008-09-15 00:20:15 +00001604 ensure_scrolled_window_widget();
1605
alp@webkit.org5a4c6982008-01-28 00:04:31 +00001606 gtk_widget_set_direction(gTreeViewWidget, direction);
alp@webkit.orgd694e942008-09-15 00:20:15 +00001607 gtk_widget_set_direction(gScrolledWindowWidget, direction);
alp@webkit.org5a4c6982008-01-28 00:04:31 +00001608
1609 /* only handle disabled and normal states, otherwise the whole background
1610 * area will be painted differently with other states */
1611 state_type = state->disabled ? GTK_STATE_INSENSITIVE : GTK_STATE_NORMAL;
1612
1613 /* In GTK the treeview sets the background of the window
1614 * which contains the cells to the treeview base color.
1615 * If we don't set it here the background color will not be correct.*/
1616 gtk_widget_modify_bg(gTreeViewWidget, state_type,
1617 &gTreeViewWidget->style->base[state_type]);
1618
alp@webkit.orgd694e942008-09-15 00:20:15 +00001619 style = gScrolledWindowWidget->style;
alp@webkit.org5a4c6982008-01-28 00:04:31 +00001620 xthickness = XTHICKNESS(style);
1621 ythickness = YTHICKNESS(style);
1622
alp@webkit.orgd694e942008-09-15 00:20:15 +00001623 TSOffsetStyleGCs(gTreeViewWidget->style, rect->x, rect->y);
alp@webkit.org5a4c6982008-01-28 00:04:31 +00001624 TSOffsetStyleGCs(style, rect->x, rect->y);
1625
alp@webkit.orgd694e942008-09-15 00:20:15 +00001626 gtk_paint_flat_box(gTreeViewWidget->style, drawable, state_type,
1627 GTK_SHADOW_NONE, cliprect, gTreeViewWidget, "treeview",
alp@webkit.org5a4c6982008-01-28 00:04:31 +00001628 rect->x + xthickness, rect->y + ythickness,
1629 rect->width - 2 * xthickness,
1630 rect->height - 2 * ythickness);
1631
1632 gtk_paint_shadow(style, drawable, GTK_STATE_NORMAL, GTK_SHADOW_IN,
alp@webkit.orgd694e942008-09-15 00:20:15 +00001633 cliprect, gScrolledWindowWidget, "scrolled_window",
alp@webkit.org5a4c6982008-01-28 00:04:31 +00001634 rect->x, rect->y, rect->width, rect->height);
1635
1636 return MOZ_GTK_SUCCESS;
1637}
1638
1639static gint
1640moz_gtk_tree_header_cell_paint(GdkDrawable* drawable, GdkRectangle* rect,
1641 GdkRectangle* cliprect, GtkWidgetState* state,
alp@webkit.orgd694e942008-09-15 00:20:15 +00001642 gboolean isSorted, GtkTextDirection direction)
alp@webkit.org5a4c6982008-01-28 00:04:31 +00001643{
alp@webkit.orgd694e942008-09-15 00:20:15 +00001644 gtk_tree_view_column_set_sort_indicator(GTK_TREE_VIEW_COLUMN(gMiddleTreeViewColumn),
1645 isSorted);
1646
alp@webkit.org5a4c6982008-01-28 00:04:31 +00001647 moz_gtk_button_paint(drawable, rect, cliprect, state, GTK_RELIEF_NORMAL,
1648 gTreeHeaderCellWidget, direction);
1649 return MOZ_GTK_SUCCESS;
1650}
1651
1652static gint
1653moz_gtk_tree_header_sort_arrow_paint(GdkDrawable* drawable, GdkRectangle* rect,
1654 GdkRectangle* cliprect,
1655 GtkWidgetState* state, GtkArrowType flags,
1656 GtkTextDirection direction)
1657{
1658 GdkRectangle arrow_rect;
1659 GtkStateType state_type = ConvertGtkState(state);
1660 GtkShadowType shadow_type = GTK_SHADOW_IN;
1661 GtkArrowType arrow_type = flags;
1662 GtkStyle* style;
1663
1664 ensure_tree_header_cell_widget();
1665 gtk_widget_set_direction(gTreeHeaderSortArrowWidget, direction);
1666
1667 /* hard code these values */
1668 arrow_rect.width = 11;
1669 arrow_rect.height = 11;
1670 arrow_rect.x = rect->x + (rect->width - arrow_rect.width) / 2;
1671 arrow_rect.y = rect->y + (rect->height - arrow_rect.height) / 2;
1672
1673 style = gTreeHeaderSortArrowWidget->style;
1674 TSOffsetStyleGCs(style, arrow_rect.x, arrow_rect.y);
1675
1676 gtk_paint_arrow(style, drawable, state_type, shadow_type, cliprect,
1677 gTreeHeaderSortArrowWidget, "arrow", arrow_type, TRUE,
1678 arrow_rect.x, arrow_rect.y,
1679 arrow_rect.width, arrow_rect.height);
1680
1681 return MOZ_GTK_SUCCESS;
1682}
1683
1684static gint
1685moz_gtk_treeview_expander_paint(GdkDrawable* drawable, GdkRectangle* rect,
1686 GdkRectangle* cliprect, GtkWidgetState* state,
1687 GtkExpanderStyle expander_state,
1688 GtkTextDirection direction)
1689{
1690 GtkStyle *style;
1691 GtkStateType state_type;
1692
1693 ensure_tree_view_widget();
1694 gtk_widget_set_direction(gTreeViewWidget, direction);
1695
1696 style = gTreeViewWidget->style;
1697
1698 /* Because the frame we get is of the entire treeview, we can't get the precise
1699 * event state of one expander, thus rendering hover and active feedback useless. */
1700 state_type = state->disabled ? GTK_STATE_INSENSITIVE : GTK_STATE_NORMAL;
1701
1702 TSOffsetStyleGCs(style, rect->x, rect->y);
1703 gtk_paint_expander(style, drawable, state_type, cliprect, gTreeViewWidget, "treeview",
1704 rect->x + rect->width / 2, rect->y + rect->height / 2, expander_state);
1705
1706 return MOZ_GTK_SUCCESS;
1707}
1708
1709static gint
1710moz_gtk_expander_paint(GdkDrawable* drawable, GdkRectangle* rect,
1711 GdkRectangle* cliprect, GtkWidgetState* state,
1712 GtkExpanderStyle expander_state,
1713 GtkTextDirection direction)
1714{
1715 GtkStyle *style;
1716 GtkStateType state_type = ConvertGtkState(state);
1717
1718 ensure_expander_widget();
1719 gtk_widget_set_direction(gExpanderWidget, direction);
1720
1721 style = gExpanderWidget->style;
1722
1723 TSOffsetStyleGCs(style, rect->x, rect->y);
1724 gtk_paint_expander(style, drawable, state_type, cliprect, gExpanderWidget, "expander",
1725 rect->x + rect->width / 2, rect->y + rect->height / 2, expander_state);
1726
1727 return MOZ_GTK_SUCCESS;
1728}
1729
alpd8507382007-11-03 14:33:25 +00001730static gint
alp@webkit.orgd694e942008-09-15 00:20:15 +00001731moz_gtk_combo_box_paint(GdkDrawable* drawable, GdkRectangle* rect,
1732 GdkRectangle* cliprect, GtkWidgetState* state,
1733 gboolean ishtml, GtkTextDirection direction)
alpd8507382007-11-03 14:33:25 +00001734{
alp@webkit.orgd694e942008-09-15 00:20:15 +00001735 GdkRectangle arrow_rect, real_arrow_rect;
1736 gint arrow_size, separator_width;
1737 gboolean wide_separators;
alpd8507382007-11-03 14:33:25 +00001738 GtkStateType state_type = ConvertGtkState(state);
alp@webkit.orgd694e942008-09-15 00:20:15 +00001739 GtkShadowType shadow_type = state->active ? GTK_SHADOW_IN : GTK_SHADOW_OUT;
1740 GtkStyle* style;
1741 GtkRequisition arrow_req;
alpd8507382007-11-03 14:33:25 +00001742
alp@webkit.orgd694e942008-09-15 00:20:15 +00001743 ensure_combo_box_widgets();
alpd8507382007-11-03 14:33:25 +00001744
alp@webkit.orgd694e942008-09-15 00:20:15 +00001745 /* Also sets the direction on gComboBoxButtonWidget, which is then
1746 * inherited by the separator and arrow */
1747 moz_gtk_button_paint(drawable, rect, cliprect, state, GTK_RELIEF_NORMAL,
1748 gComboBoxButtonWidget, direction);
alpd8507382007-11-03 14:33:25 +00001749
alp@webkit.orgd694e942008-09-15 00:20:15 +00001750 calculate_button_inner_rect(gComboBoxButtonWidget,
1751 rect, &arrow_rect, direction, ishtml);
1752 /* Now arrow_rect contains the inner rect ; we want to correct the width
1753 * to what the arrow needs (see gtk_combo_box_size_allocate) */
1754 gtk_widget_size_request(gComboBoxArrowWidget, &arrow_req);
1755 if (direction == GTK_TEXT_DIR_LTR)
1756 arrow_rect.x += arrow_rect.width - arrow_req.width;
1757 arrow_rect.width = arrow_req.width;
alpd8507382007-11-03 14:33:25 +00001758
alp@webkit.orgd694e942008-09-15 00:20:15 +00001759 calculate_arrow_rect(gComboBoxArrowWidget,
1760 &arrow_rect, &real_arrow_rect, direction);
1761
1762 style = gComboBoxArrowWidget->style;
1763 TSOffsetStyleGCs(style, rect->x, rect->y);
1764
1765 gtk_widget_size_allocate(gComboBoxWidget, rect);
1766
1767 gtk_paint_arrow(style, drawable, state_type, shadow_type, cliprect,
1768 gComboBoxArrowWidget, "arrow", GTK_ARROW_DOWN, TRUE,
1769 real_arrow_rect.x, real_arrow_rect.y,
1770 real_arrow_rect.width, real_arrow_rect.height);
1771
1772
1773 /* If there is no separator in the theme, there's nothing left to do. */
1774 if (!gComboBoxSeparatorWidget)
1775 return MOZ_GTK_SUCCESS;
1776
1777 style = gComboBoxSeparatorWidget->style;
1778 TSOffsetStyleGCs(style, rect->x, rect->y);
1779
1780 gtk_widget_style_get(gComboBoxSeparatorWidget,
1781 "wide-separators", &wide_separators,
1782 "separator-width", &separator_width,
1783 NULL);
1784
1785 if (wide_separators) {
1786 if (direction == GTK_TEXT_DIR_LTR)
1787 arrow_rect.x -= separator_width;
1788 else
1789 arrow_rect.x += arrow_rect.width;
1790
1791 gtk_paint_box(style, drawable,
1792 GTK_STATE_NORMAL, GTK_SHADOW_ETCHED_OUT,
1793 cliprect, gComboBoxSeparatorWidget, "vseparator",
1794 arrow_rect.x, arrow_rect.y,
1795 separator_width, arrow_rect.height);
alpd8507382007-11-03 14:33:25 +00001796 } else {
alp@webkit.orgd694e942008-09-15 00:20:15 +00001797 if (direction == GTK_TEXT_DIR_LTR)
1798 arrow_rect.x -= XTHICKNESS(style);
1799 else
1800 arrow_rect.x += arrow_rect.width;
alpd8507382007-11-03 14:33:25 +00001801
alp@webkit.orgd694e942008-09-15 00:20:15 +00001802 gtk_paint_vline(style, drawable, GTK_STATE_NORMAL, cliprect,
1803 gComboBoxSeparatorWidget, "vseparator",
1804 arrow_rect.y, arrow_rect.y + arrow_rect.height,
1805 arrow_rect.x);
alpd8507382007-11-03 14:33:25 +00001806 }
alp@webkit.orgd694e942008-09-15 00:20:15 +00001807
alpd8507382007-11-03 14:33:25 +00001808 return MOZ_GTK_SUCCESS;
1809}
1810
1811static gint
alp@webkit.org5a4c6982008-01-28 00:04:31 +00001812moz_gtk_downarrow_paint(GdkDrawable* drawable, GdkRectangle* rect,
1813 GdkRectangle* cliprect, GtkWidgetState* state)
alpd8507382007-11-03 14:33:25 +00001814{
alp@webkit.org5a4c6982008-01-28 00:04:31 +00001815 GtkStyle* style;
1816 GtkStateType state_type = ConvertGtkState(state);
1817 GtkShadowType shadow_type = state->active ? GTK_SHADOW_IN : GTK_SHADOW_OUT;
1818 GdkRectangle arrow_rect;
1819
alp@webkit.orgd694e942008-09-15 00:20:15 +00001820 ensure_button_arrow_widget();
1821 style = gButtonArrowWidget->style;
alp@webkit.org5a4c6982008-01-28 00:04:31 +00001822
alp@webkit.orgd694e942008-09-15 00:20:15 +00001823 calculate_arrow_rect(gButtonArrowWidget, rect, &arrow_rect,
1824 GTK_TEXT_DIR_LTR);
alp@webkit.org5a4c6982008-01-28 00:04:31 +00001825
1826 TSOffsetStyleGCs(style, arrow_rect.x, arrow_rect.y);
1827 gtk_paint_arrow(style, drawable, state_type, shadow_type, cliprect,
alp@webkit.orgd694e942008-09-15 00:20:15 +00001828 gButtonArrowWidget, "arrow", GTK_ARROW_DOWN, TRUE,
alp@webkit.org5a4c6982008-01-28 00:04:31 +00001829 arrow_rect.x, arrow_rect.y, arrow_rect.width, arrow_rect.height);
1830
1831 return MOZ_GTK_SUCCESS;
1832}
1833
1834static gint
alp@webkit.orgd694e942008-09-15 00:20:15 +00001835moz_gtk_combo_box_entry_button_paint(GdkDrawable* drawable, GdkRectangle* rect,
1836 GdkRectangle* cliprect,
1837 GtkWidgetState* state,
1838 gboolean input_focus,
1839 GtkTextDirection direction)
alp@webkit.org5a4c6982008-01-28 00:04:31 +00001840{
alp@webkit.orgd694e942008-09-15 00:20:15 +00001841 gint x_displacement, y_displacement;
alpd8507382007-11-03 14:33:25 +00001842 GdkRectangle arrow_rect, real_arrow_rect;
1843 GtkStateType state_type = ConvertGtkState(state);
1844 GtkShadowType shadow_type = state->active ? GTK_SHADOW_IN : GTK_SHADOW_OUT;
1845 GtkStyle* style;
1846
alp@webkit.orgd694e942008-09-15 00:20:15 +00001847 ensure_combo_box_entry_widgets();
1848
1849 if (input_focus) {
1850 /* Some themes draw a complementary focus ring for the dropdown button
1851 * when the dropdown entry has focus */
1852 GTK_WIDGET_SET_FLAGS(gComboBoxEntryTextareaWidget, GTK_HAS_FOCUS);
1853 }
alp@webkit.org5a4c6982008-01-28 00:04:31 +00001854
alpd8507382007-11-03 14:33:25 +00001855 moz_gtk_button_paint(drawable, rect, cliprect, state, GTK_RELIEF_NORMAL,
alp@webkit.orgd694e942008-09-15 00:20:15 +00001856 gComboBoxEntryButtonWidget, direction);
alpd8507382007-11-03 14:33:25 +00001857
alp@webkit.orgd694e942008-09-15 00:20:15 +00001858 if (input_focus)
1859 GTK_WIDGET_UNSET_FLAGS(gComboBoxEntryTextareaWidget, GTK_HAS_FOCUS);
alpd8507382007-11-03 14:33:25 +00001860
alp@webkit.orgd694e942008-09-15 00:20:15 +00001861 calculate_button_inner_rect(gComboBoxEntryButtonWidget,
1862 rect, &arrow_rect, direction, FALSE);
1863 if (state_type == GTK_STATE_ACTIVE) {
1864 gtk_widget_style_get(gComboBoxEntryButtonWidget,
1865 "child-displacement-x", &x_displacement,
1866 "child-displacement-y", &y_displacement,
1867 NULL);
1868 arrow_rect.x += x_displacement;
1869 arrow_rect.y += y_displacement;
1870 }
1871
1872 calculate_arrow_rect(gComboBoxEntryArrowWidget,
1873 &arrow_rect, &real_arrow_rect, direction);
1874
1875 style = gComboBoxEntryArrowWidget->style;
alpd8507382007-11-03 14:33:25 +00001876 TSOffsetStyleGCs(style, real_arrow_rect.x, real_arrow_rect.y);
1877
alpd8507382007-11-03 14:33:25 +00001878 gtk_paint_arrow(style, drawable, state_type, shadow_type, cliprect,
alp@webkit.orgd694e942008-09-15 00:20:15 +00001879 gComboBoxEntryArrowWidget, "arrow", GTK_ARROW_DOWN, TRUE,
alpd8507382007-11-03 14:33:25 +00001880 real_arrow_rect.x, real_arrow_rect.y,
1881 real_arrow_rect.width, real_arrow_rect.height);
1882
1883 return MOZ_GTK_SUCCESS;
1884}
1885
1886static gint
1887moz_gtk_container_paint(GdkDrawable* drawable, GdkRectangle* rect,
1888 GdkRectangle* cliprect, GtkWidgetState* state,
alp@webkit.org5a4c6982008-01-28 00:04:31 +00001889 gboolean isradio, GtkTextDirection direction)
alpd8507382007-11-03 14:33:25 +00001890{
1891 GtkStateType state_type = ConvertGtkState(state);
1892 GtkStyle* style;
alp@webkit.org5a4c6982008-01-28 00:04:31 +00001893 GtkWidget *widget;
alpd8507382007-11-03 14:33:25 +00001894 gboolean interior_focus;
1895 gint focus_width, focus_pad;
1896
1897 if (isradio) {
1898 ensure_radiobutton_widget();
alp@webkit.org5a4c6982008-01-28 00:04:31 +00001899 widget = gRadiobuttonWidget;
alpd8507382007-11-03 14:33:25 +00001900 } else {
1901 ensure_checkbox_widget();
alp@webkit.org5a4c6982008-01-28 00:04:31 +00001902 widget = gCheckboxWidget;
alpd8507382007-11-03 14:33:25 +00001903 }
alp@webkit.org5a4c6982008-01-28 00:04:31 +00001904 gtk_widget_set_direction(widget, direction);
1905
1906 style = widget->style;
1907 moz_gtk_widget_get_focus(widget, &interior_focus, &focus_width,
1908 &focus_pad);
alpd8507382007-11-03 14:33:25 +00001909
1910 TSOffsetStyleGCs(style, rect->x, rect->y);
1911
1912 /* The detail argument for the gtk_paint_* calls below are "checkbutton"
1913 even for radio buttons, to match what gtk does. */
1914
1915 /* this is for drawing a prelight box */
1916 if (state_type == GTK_STATE_PRELIGHT || state_type == GTK_STATE_ACTIVE) {
alp@webkit.org5a4c6982008-01-28 00:04:31 +00001917 gtk_paint_flat_box(style, drawable, GTK_STATE_PRELIGHT,
1918 GTK_SHADOW_ETCHED_OUT, cliprect, widget,
alpd8507382007-11-03 14:33:25 +00001919 "checkbutton",
1920 rect->x, rect->y, rect->width, rect->height);
1921 }
1922
1923 if (state_type != GTK_STATE_NORMAL && state_type != GTK_STATE_PRELIGHT)
1924 state_type = GTK_STATE_NORMAL;
1925
1926 if (state->focused && !interior_focus) {
alp@webkit.org5a4c6982008-01-28 00:04:31 +00001927 gtk_paint_focus(style, drawable, state_type, cliprect, widget,
alpd8507382007-11-03 14:33:25 +00001928 "checkbutton",
1929 rect->x, rect->y, rect->width, rect->height);
1930 }
1931
1932 return MOZ_GTK_SUCCESS;
1933}
1934
1935static gint
1936moz_gtk_toggle_label_paint(GdkDrawable* drawable, GdkRectangle* rect,
1937 GdkRectangle* cliprect, GtkWidgetState* state,
alp@webkit.org5a4c6982008-01-28 00:04:31 +00001938 gboolean isradio, GtkTextDirection direction)
alpd8507382007-11-03 14:33:25 +00001939{
1940 GtkStateType state_type;
1941 GtkStyle *style;
1942 GtkWidget *widget;
1943 gboolean interior_focus;
1944
1945 if (!state->focused)
1946 return MOZ_GTK_SUCCESS;
1947
1948 if (isradio) {
1949 ensure_radiobutton_widget();
1950 widget = gRadiobuttonWidget;
1951 } else {
1952 ensure_checkbox_widget();
1953 widget = gCheckboxWidget;
1954 }
alp@webkit.org5a4c6982008-01-28 00:04:31 +00001955 gtk_widget_set_direction(widget, direction);
alpd8507382007-11-03 14:33:25 +00001956
1957 gtk_widget_style_get(widget, "interior-focus", &interior_focus, NULL);
1958 if (!interior_focus)
1959 return MOZ_GTK_SUCCESS;
1960
1961 state_type = ConvertGtkState(state);
1962
1963 style = widget->style;
1964 TSOffsetStyleGCs(style, rect->x, rect->y);
1965
1966 /* Always "checkbutton" to match gtkcheckbutton.c */
1967 gtk_paint_focus(style, drawable, state_type, cliprect, widget,
1968 "checkbutton",
1969 rect->x, rect->y, rect->width, rect->height);
1970
1971 return MOZ_GTK_SUCCESS;
1972}
1973
1974static gint
1975moz_gtk_toolbar_paint(GdkDrawable* drawable, GdkRectangle* rect,
alp@webkit.org5a4c6982008-01-28 00:04:31 +00001976 GdkRectangle* cliprect, GtkTextDirection direction)
alpd8507382007-11-03 14:33:25 +00001977{
1978 GtkStyle* style;
1979 GtkShadowType shadow_type;
1980
1981 ensure_toolbar_widget();
alp@webkit.org5a4c6982008-01-28 00:04:31 +00001982 gtk_widget_set_direction(gToolbarWidget, direction);
1983
alpd8507382007-11-03 14:33:25 +00001984 style = gToolbarWidget->style;
1985
1986 TSOffsetStyleGCs(style, rect->x, rect->y);
1987
1988 gtk_style_apply_default_background(style, drawable, TRUE,
1989 GTK_STATE_NORMAL,
1990 cliprect, rect->x, rect->y,
1991 rect->width, rect->height);
1992
alp@webkit.orgd694e942008-09-15 00:20:15 +00001993 gtk_widget_style_get(gToolbarWidget, "shadow-type", &shadow_type, NULL);
1994
1995 gtk_paint_box (style, drawable, GTK_STATE_NORMAL, shadow_type,
alpd8507382007-11-03 14:33:25 +00001996 cliprect, gToolbarWidget, "toolbar",
1997 rect->x, rect->y, rect->width, rect->height);
1998
1999 return MOZ_GTK_SUCCESS;
2000}
2001
2002static gint
alp@webkit.org5a4c6982008-01-28 00:04:31 +00002003moz_gtk_toolbar_separator_paint(GdkDrawable* drawable, GdkRectangle* rect,
2004 GdkRectangle* cliprect,
2005 GtkTextDirection direction)
2006{
2007 GtkStyle* style;
2008 gint separator_width;
2009 gint paint_width;
2010 gboolean wide_separators;
2011
2012 /* Defined as constants in GTK+ 2.10.14 */
2013 const double start_fraction = 0.2;
2014 const double end_fraction = 0.8;
2015
2016 ensure_toolbar_separator_widget();
2017 gtk_widget_set_direction(gToolbarSeparatorWidget, direction);
2018
2019 style = gToolbarSeparatorWidget->style;
2020
2021 gtk_widget_style_get(gToolbarWidget,
2022 "wide-separators", &wide_separators,
2023 "separator-width", &separator_width,
2024 NULL);
2025
2026 TSOffsetStyleGCs(style, rect->x, rect->y);
2027
2028 if (wide_separators) {
2029 if (separator_width > rect->width)
2030 separator_width = rect->width;
2031
2032 gtk_paint_box(style, drawable,
2033 GTK_STATE_NORMAL, GTK_SHADOW_ETCHED_OUT,
2034 cliprect, gToolbarWidget, "vseparator",
2035 rect->x + (rect->width - separator_width) / 2,
2036 rect->y + rect->height * start_fraction,
2037 separator_width,
2038 rect->height * (end_fraction - start_fraction));
2039
2040 } else {
2041 paint_width = style->xthickness;
2042
2043 if (paint_width > rect->width)
2044 paint_width = rect->width;
2045
2046 gtk_paint_vline(style, drawable,
2047 GTK_STATE_NORMAL, cliprect, gToolbarSeparatorWidget,
2048 "toolbar",
2049 rect->y + rect->height * start_fraction,
2050 rect->y + rect->height * end_fraction,
2051 rect->x + (rect->width - paint_width) / 2);
2052 }
2053
2054 return MOZ_GTK_SUCCESS;
2055}
2056
2057static gint
alpd8507382007-11-03 14:33:25 +00002058moz_gtk_tooltip_paint(GdkDrawable* drawable, GdkRectangle* rect,
alp@webkit.org5a4c6982008-01-28 00:04:31 +00002059 GdkRectangle* cliprect, GtkTextDirection direction)
alpd8507382007-11-03 14:33:25 +00002060{
2061 GtkStyle* style;
2062
2063 ensure_tooltip_widget();
alp@webkit.org5a4c6982008-01-28 00:04:31 +00002064 gtk_widget_set_direction(gTooltipWidget, direction);
2065
alpd8507382007-11-03 14:33:25 +00002066 style = gtk_rc_get_style_by_paths(gtk_settings_get_default(),
2067 "gtk-tooltips", "GtkWindow",
2068 GTK_TYPE_WINDOW);
2069
2070 style = gtk_style_attach(style, gTooltipWidget->window);
2071 TSOffsetStyleGCs(style, rect->x, rect->y);
2072 gtk_paint_flat_box(style, drawable, GTK_STATE_NORMAL, GTK_SHADOW_OUT,
2073 cliprect, gTooltipWidget, "tooltip",
2074 rect->x, rect->y, rect->width, rect->height);
2075
2076 return MOZ_GTK_SUCCESS;
2077}
2078
2079static gint
alp@webkit.org5a4c6982008-01-28 00:04:31 +00002080moz_gtk_resizer_paint(GdkDrawable* drawable, GdkRectangle* rect,
2081 GdkRectangle* cliprect, GtkWidgetState* state,
2082 GtkTextDirection direction)
alpd8507382007-11-03 14:33:25 +00002083{
alp@webkit.org5a4c6982008-01-28 00:04:31 +00002084 GtkStyle* style;
2085 GtkStateType state_type = ConvertGtkState(state);
2086
2087 ensure_window_widget();
2088 gtk_widget_set_direction(gProtoWindow, direction);
2089
2090 style = gProtoWindow->style;
alpd8507382007-11-03 14:33:25 +00002091
2092 TSOffsetStyleGCs(style, rect->x, rect->y);
alp@webkit.org5a4c6982008-01-28 00:04:31 +00002093
2094 gtk_paint_resize_grip(style, drawable, state_type, cliprect, gProtoWindow,
2095 NULL, (direction == GTK_TEXT_DIR_LTR) ?
2096 GDK_WINDOW_EDGE_SOUTH_EAST :
2097 GDK_WINDOW_EDGE_SOUTH_WEST,
2098 rect->x, rect->y, rect->width, rect->height);
2099 return MOZ_GTK_SUCCESS;
2100}
2101
2102static gint
2103moz_gtk_frame_paint(GdkDrawable* drawable, GdkRectangle* rect,
2104 GdkRectangle* cliprect, GtkTextDirection direction)
2105{
2106 GtkStyle* style;
2107 GtkShadowType shadow_type;
alpd8507382007-11-03 14:33:25 +00002108
2109 ensure_frame_widget();
alp@webkit.org5a4c6982008-01-28 00:04:31 +00002110 gtk_widget_set_direction(gFrameWidget, direction);
2111
alpd8507382007-11-03 14:33:25 +00002112 style = gFrameWidget->style;
2113
alp@webkit.org5a4c6982008-01-28 00:04:31 +00002114 gtk_widget_style_get(gStatusbarWidget, "shadow-type", &shadow_type, NULL);
2115
alpd8507382007-11-03 14:33:25 +00002116 TSOffsetStyleGCs(style, rect->x, rect->y);
alp@webkit.org5a4c6982008-01-28 00:04:31 +00002117 gtk_paint_shadow(style, drawable, GTK_STATE_NORMAL, shadow_type,
alpd8507382007-11-03 14:33:25 +00002118 cliprect, gFrameWidget, "frame", rect->x, rect->y,
2119 rect->width, rect->height);
2120
2121 return MOZ_GTK_SUCCESS;
2122}
2123
2124static gint
2125moz_gtk_progressbar_paint(GdkDrawable* drawable, GdkRectangle* rect,
alp@webkit.org5a4c6982008-01-28 00:04:31 +00002126 GdkRectangle* cliprect, GtkTextDirection direction)
alpd8507382007-11-03 14:33:25 +00002127{
2128 GtkStyle* style;
2129
2130 ensure_progress_widget();
alp@webkit.org5a4c6982008-01-28 00:04:31 +00002131 gtk_widget_set_direction(gProgressWidget, direction);
2132
alpd8507382007-11-03 14:33:25 +00002133 style = gProgressWidget->style;
2134
2135 TSOffsetStyleGCs(style, rect->x, rect->y);
2136 gtk_paint_box(style, drawable, GTK_STATE_NORMAL, GTK_SHADOW_IN,
2137 cliprect, gProgressWidget, "trough", rect->x, rect->y,
2138 rect->width, rect->height);
2139
2140 return MOZ_GTK_SUCCESS;
2141}
2142
2143static gint
2144moz_gtk_progress_chunk_paint(GdkDrawable* drawable, GdkRectangle* rect,
alp@webkit.org5a4c6982008-01-28 00:04:31 +00002145 GdkRectangle* cliprect, GtkTextDirection direction)
alpd8507382007-11-03 14:33:25 +00002146{
2147 GtkStyle* style;
2148
2149 ensure_progress_widget();
alp@webkit.org5a4c6982008-01-28 00:04:31 +00002150 gtk_widget_set_direction(gProgressWidget, direction);
2151
alpd8507382007-11-03 14:33:25 +00002152 style = gProgressWidget->style;
2153
2154 TSOffsetStyleGCs(style, rect->x, rect->y);
2155 gtk_paint_box(style, drawable, GTK_STATE_PRELIGHT, GTK_SHADOW_OUT,
2156 cliprect, gProgressWidget, "bar", rect->x, rect->y,
2157 rect->width, rect->height);
2158
2159 return MOZ_GTK_SUCCESS;
2160}
2161
alp@webkit.org5a4c6982008-01-28 00:04:31 +00002162gint
2163moz_gtk_get_tab_thickness(void)
2164{
2165 ensure_tab_widget();
2166 if (YTHICKNESS(gTabWidget->style) < 2)
2167 return 2; /* some themes don't set ythickness correctly */
2168
2169 return YTHICKNESS(gTabWidget->style);
2170}
2171
alpd8507382007-11-03 14:33:25 +00002172static gint
2173moz_gtk_tab_paint(GdkDrawable* drawable, GdkRectangle* rect,
alp@webkit.org5a4c6982008-01-28 00:04:31 +00002174 GdkRectangle* cliprect, GtkTabFlags flags,
2175 GtkTextDirection direction)
alpd8507382007-11-03 14:33:25 +00002176{
alp@webkit.org5a4c6982008-01-28 00:04:31 +00002177 /* When the tab isn't selected, we just draw a notebook extension.
2178 * When it is selected, we overwrite the adjacent border of the tabpanel
2179 * touching the tab with a pierced border (called "the gap") to make the
2180 * tab appear physically attached to the tabpanel; see details below. */
alpd8507382007-11-03 14:33:25 +00002181
2182 GtkStyle* style;
alpd8507382007-11-03 14:33:25 +00002183
alp@webkit.org5a4c6982008-01-28 00:04:31 +00002184 ensure_tab_widget();
2185 gtk_widget_set_direction(gTabWidget, direction);
alpd8507382007-11-03 14:33:25 +00002186
2187 style = gTabWidget->style;
2188 TSOffsetStyleGCs(style, rect->x, rect->y);
alpd8507382007-11-03 14:33:25 +00002189
alp@webkit.org5a4c6982008-01-28 00:04:31 +00002190 if ((flags & MOZ_GTK_TAB_SELECTED) == 0) {
2191 /* Only draw the tab */
2192 gtk_paint_extension(style, drawable, GTK_STATE_ACTIVE, GTK_SHADOW_OUT,
alpd8507382007-11-03 14:33:25 +00002193 cliprect, gTabWidget, "tab",
alp@webkit.org5a4c6982008-01-28 00:04:31 +00002194 rect->x, rect->y, rect->width, rect->height,
2195 (flags & MOZ_GTK_TAB_BOTTOM) ?
2196 GTK_POS_TOP : GTK_POS_BOTTOM );
2197 } else {
2198 /* Draw the tab and the gap
2199 * We want the gap to be positionned exactly on the tabpanel top
2200 * border; since tabbox.css may set a negative margin so that the tab
2201 * frame rect already overlaps the tabpanel frame rect, we need to take
2202 * that into account when drawing. To that effect, nsNativeThemeGTK
2203 * passes us this negative margin (bmargin in the graphic below) in the
2204 * lowest bits of |flags|. We use it to set gap_voffset, the distance
2205 * between the top of the gap and the bottom of the tab (resp. the
2206 * bottom of the gap and the top of the tab when we draw a bottom tab),
2207 * while ensuring that the gap always touches the border of the tab,
2208 * i.e. 0 <= gap_voffset <= gap_height, to avoid surprinsing results
2209 * with big negative or positive margins.
2210 * Here is a graphical explanation in the case of top tabs:
2211 * ___________________________
2212 * / \
2213 * | T A B |
2214 * ----------|. . . . . . . . . . . . . . .|----- top of tabpanel
2215 * : ^ bmargin : ^
2216 * : | (-negative margin, : |
2217 * bottom : v passed in flags) : | gap_height
2218 * of -> :.............................: | (the size of the
2219 * the tab . part of the gap . | tabpanel top border)
2220 * . outside of the tab . v
2221 * ----------------------------------------------
2222 *
2223 * To draw the gap, we use gtk_paint_box_gap(), see comment in
2224 * moz_gtk_tabpanels_paint(). This box_gap is made 3 * gap_height tall,
2225 * which should suffice to ensure that the only visible border is the
2226 * pierced one. If the tab is in the middle, we make the box_gap begin
2227 * a bit to the left of the tab and end a bit to the right, adjusting
2228 * the gap position so it still is under the tab, because we want the
2229 * rendering of a gap in the middle of a tabpanel. This is the role of
2230 * the gints gap_{l,r}_offset. On the contrary, if the tab is the
2231 * first, we align the start border of the box_gap with the start
2232 * border of the tab (left if LTR, right if RTL), by setting the
2233 * appropriate offset to 0.*/
2234 gint gap_loffset, gap_roffset, gap_voffset, gap_height;
2235
2236 /* Get height needed by the gap */
2237 gap_height = moz_gtk_get_tab_thickness();
2238
2239 /* Extract gap_voffset from the first bits of flags */
2240 gap_voffset = flags & MOZ_GTK_TAB_MARGIN_MASK;
2241 if (gap_voffset > gap_height)
2242 gap_voffset = gap_height;
2243
2244 /* Set gap_{l,r}_offset to appropriate values */
2245 gap_loffset = gap_roffset = 20; /* should be enough */
2246 if (flags & MOZ_GTK_TAB_FIRST) {
2247 if (direction == GTK_TEXT_DIR_RTL)
2248 gap_roffset = 0;
2249 else
2250 gap_loffset = 0;
2251 }
2252
2253 if (flags & MOZ_GTK_TAB_BOTTOM) {
2254 /* Enlarge the cliprect to have room for the full gap height */
2255 cliprect->height += gap_height - gap_voffset;
2256 cliprect->y -= gap_height - gap_voffset;
2257
2258 /* Draw the tab */
2259 gtk_paint_extension(style, drawable, GTK_STATE_NORMAL,
2260 GTK_SHADOW_OUT, cliprect, gTabWidget, "tab",
2261 rect->x, rect->y + gap_voffset, rect->width,
2262 rect->height - gap_voffset, GTK_POS_TOP);
2263
2264 /* Draw the gap; erase with background color before painting in
2265 * case theme does not */
2266 gtk_style_apply_default_background(style, drawable, TRUE,
2267 GTK_STATE_NORMAL, cliprect,
2268 rect->x,
2269 rect->y + gap_voffset
2270 - gap_height,
2271 rect->width, gap_height);
2272 gtk_paint_box_gap(style, drawable, GTK_STATE_NORMAL, GTK_SHADOW_OUT,
2273 cliprect, gTabWidget, "notebook",
2274 rect->x - gap_loffset,
2275 rect->y + gap_voffset - 3 * gap_height,
2276 rect->width + gap_loffset + gap_roffset,
2277 3 * gap_height, GTK_POS_BOTTOM,
2278 gap_loffset, rect->width);
2279 } else {
2280 /* Enlarge the cliprect to have room for the full gap height */
2281 cliprect->height += gap_height - gap_voffset;
2282
2283 /* Draw the tab */
2284 gtk_paint_extension(style, drawable, GTK_STATE_NORMAL,
2285 GTK_SHADOW_OUT, cliprect, gTabWidget, "tab",
2286 rect->x, rect->y, rect->width,
2287 rect->height - gap_voffset, GTK_POS_BOTTOM);
2288
2289 /* Draw the gap; erase with background color before painting in
2290 * case theme does not */
2291 gtk_style_apply_default_background(style, drawable, TRUE,
2292 GTK_STATE_NORMAL, cliprect,
2293 rect->x,
2294 rect->y + rect->height
2295 - gap_voffset,
2296 rect->width, gap_height);
2297 gtk_paint_box_gap(style, drawable, GTK_STATE_NORMAL, GTK_SHADOW_OUT,
2298 cliprect, gTabWidget, "notebook",
2299 rect->x - gap_loffset,
2300 rect->y + rect->height - gap_voffset,
2301 rect->width + gap_loffset + gap_roffset,
2302 3 * gap_height, GTK_POS_TOP,
2303 gap_loffset, rect->width);
2304 }
2305
alpd8507382007-11-03 14:33:25 +00002306 }
2307
2308 return MOZ_GTK_SUCCESS;
2309}
2310
2311static gint
2312moz_gtk_tabpanels_paint(GdkDrawable* drawable, GdkRectangle* rect,
alp@webkit.org5a4c6982008-01-28 00:04:31 +00002313 GdkRectangle* cliprect, GtkTextDirection direction)
alpd8507382007-11-03 14:33:25 +00002314{
alp@webkit.org5a4c6982008-01-28 00:04:31 +00002315 /* We use gtk_paint_box_gap() to draw the tabpanels widget. gtk_paint_box()
2316 * draws an all-purpose box, which a lot of themes render differently.
2317 * A zero-width gap is still visible in most themes, so we hide it to the
2318 * left (10px should be enough) */
alpd8507382007-11-03 14:33:25 +00002319 GtkStyle* style;
2320
2321 ensure_tab_widget();
alp@webkit.org5a4c6982008-01-28 00:04:31 +00002322 gtk_widget_set_direction(gTabWidget, direction);
2323
alpd8507382007-11-03 14:33:25 +00002324 style = gTabWidget->style;
2325
2326 TSOffsetStyleGCs(style, rect->x, rect->y);
alp@webkit.org5a4c6982008-01-28 00:04:31 +00002327 gtk_paint_box_gap(style, drawable, GTK_STATE_NORMAL, GTK_SHADOW_OUT,
2328 cliprect, gTabWidget, "notebook", rect->x, rect->y,
2329 rect->width, rect->height,
2330 GTK_POS_TOP, -10, 0);
alpd8507382007-11-03 14:33:25 +00002331
2332 return MOZ_GTK_SUCCESS;
2333}
2334
2335static gint
alp@webkit.orgd694e942008-09-15 00:20:15 +00002336moz_gtk_tab_scroll_arrow_paint(GdkDrawable* drawable, GdkRectangle* rect,
2337 GdkRectangle* cliprect, GtkWidgetState* state,
2338 GtkArrowType arrow_type,
2339 GtkTextDirection direction)
2340{
2341 GtkStateType state_type = ConvertGtkState(state);
2342 GtkShadowType shadow_type = state->active ? GTK_SHADOW_IN : GTK_SHADOW_OUT;
2343 GtkStyle* style;
2344 gint arrow_size = MIN(rect->width, rect->height);
2345 gint x = rect->x + (rect->width - arrow_size) / 2;
2346 gint y = rect->y + (rect->height - arrow_size) / 2;
2347
2348 ensure_tab_widget();
2349
2350 style = gTabWidget->style;
2351 TSOffsetStyleGCs(style, rect->x, rect->y);
2352
2353 if (direction == GTK_TEXT_DIR_RTL) {
2354 arrow_type = (arrow_type == GTK_ARROW_LEFT) ?
2355 GTK_ARROW_RIGHT : GTK_ARROW_LEFT;
2356 }
2357
2358 gtk_paint_arrow(style, drawable, state_type, shadow_type, NULL,
2359 gTabWidget, "notebook", arrow_type, TRUE,
2360 x, y, arrow_size, arrow_size);
2361
2362 return MOZ_GTK_SUCCESS;
2363}
2364
2365static gint
alpd8507382007-11-03 14:33:25 +00002366moz_gtk_menu_bar_paint(GdkDrawable* drawable, GdkRectangle* rect,
alp@webkit.org5a4c6982008-01-28 00:04:31 +00002367 GdkRectangle* cliprect, GtkTextDirection direction)
alpd8507382007-11-03 14:33:25 +00002368{
2369 GtkStyle* style;
2370 GtkShadowType shadow_type;
2371 ensure_menu_bar_widget();
alp@webkit.org5a4c6982008-01-28 00:04:31 +00002372 gtk_widget_set_direction(gMenuBarWidget, direction);
2373
alp@webkit.orgd694e942008-09-15 00:20:15 +00002374 gtk_widget_style_get(gMenuBarWidget, "shadow-type", &shadow_type, NULL);
2375
alpd8507382007-11-03 14:33:25 +00002376 style = gMenuBarWidget->style;
2377
2378 TSOffsetStyleGCs(style, rect->x, rect->y);
2379 gtk_style_apply_default_background(style, drawable, TRUE, GTK_STATE_NORMAL,
2380 cliprect, rect->x, rect->y,
2381 rect->width, rect->height);
alp@webkit.orgd694e942008-09-15 00:20:15 +00002382
2383 gtk_paint_box(style, drawable, GTK_STATE_NORMAL, shadow_type,
alpd8507382007-11-03 14:33:25 +00002384 cliprect, gMenuBarWidget, "menubar", rect->x, rect->y,
2385 rect->width, rect->height);
2386 return MOZ_GTK_SUCCESS;
2387}
2388
2389static gint
2390moz_gtk_menu_popup_paint(GdkDrawable* drawable, GdkRectangle* rect,
alp@webkit.org5a4c6982008-01-28 00:04:31 +00002391 GdkRectangle* cliprect, GtkTextDirection direction)
alpd8507382007-11-03 14:33:25 +00002392{
2393 GtkStyle* style;
2394 ensure_menu_popup_widget();
alp@webkit.org5a4c6982008-01-28 00:04:31 +00002395 gtk_widget_set_direction(gMenuPopupWidget, direction);
2396
alpd8507382007-11-03 14:33:25 +00002397 style = gMenuPopupWidget->style;
2398
2399 TSOffsetStyleGCs(style, rect->x, rect->y);
2400 gtk_style_apply_default_background(style, drawable, TRUE, GTK_STATE_NORMAL,
2401 cliprect, rect->x, rect->y,
2402 rect->width, rect->height);
2403 gtk_paint_box(style, drawable, GTK_STATE_NORMAL, GTK_SHADOW_OUT,
2404 cliprect, gMenuPopupWidget, "menu",
2405 rect->x, rect->y, rect->width, rect->height);
2406
2407 return MOZ_GTK_SUCCESS;
2408}
2409
2410static gint
alp@webkit.org5a4c6982008-01-28 00:04:31 +00002411moz_gtk_menu_separator_paint(GdkDrawable* drawable, GdkRectangle* rect,
2412 GdkRectangle* cliprect, GtkTextDirection direction)
2413{
2414 GtkStyle* style;
2415 gboolean wide_separators;
2416 gint separator_height;
2417 guint horizontal_padding;
2418 gint paint_height;
2419
2420 ensure_menu_separator_widget();
2421 gtk_widget_set_direction(gMenuSeparatorWidget, direction);
2422
2423 style = gMenuSeparatorWidget->style;
2424
2425 gtk_widget_style_get(gMenuSeparatorWidget,
2426 "wide-separators", &wide_separators,
2427 "separator-height", &separator_height,
2428 "horizontal-padding", &horizontal_padding,
2429 NULL);
2430
2431 TSOffsetStyleGCs(style, rect->x, rect->y);
2432
2433 if (wide_separators) {
2434 if (separator_height > rect->height)
2435 separator_height = rect->height;
2436
2437 gtk_paint_box(style, drawable,
2438 GTK_STATE_NORMAL, GTK_SHADOW_ETCHED_OUT,
2439 cliprect, gMenuSeparatorWidget, "hseparator",
2440 rect->x + horizontal_padding + style->xthickness,
2441 rect->y + (rect->height - separator_height - style->ythickness) / 2,
2442 rect->width - 2 * (horizontal_padding + style->xthickness),
2443 separator_height);
2444 } else {
2445 paint_height = style->ythickness;
2446 if (paint_height > rect->height)
2447 paint_height = rect->height;
2448
2449 gtk_paint_hline(style, drawable,
2450 GTK_STATE_NORMAL, cliprect, gMenuSeparatorWidget,
2451 "menuitem",
2452 rect->x + horizontal_padding + style->xthickness,
2453 rect->x + rect->width - horizontal_padding - style->xthickness - 1,
2454 rect->y + (rect->height - style->ythickness) / 2);
2455 }
2456
2457 return MOZ_GTK_SUCCESS;
2458}
2459
2460static gint
alpd8507382007-11-03 14:33:25 +00002461moz_gtk_menu_item_paint(GdkDrawable* drawable, GdkRectangle* rect,
alp@webkit.org5a4c6982008-01-28 00:04:31 +00002462 GdkRectangle* cliprect, GtkWidgetState* state,
2463 gint flags, GtkTextDirection direction)
alpd8507382007-11-03 14:33:25 +00002464{
2465 GtkStyle* style;
2466 GtkShadowType shadow_type;
alp@webkit.org5a4c6982008-01-28 00:04:31 +00002467 GtkWidget* item_widget;
alpd8507382007-11-03 14:33:25 +00002468
2469 if (state->inHover && !state->disabled) {
alp@webkit.org5a4c6982008-01-28 00:04:31 +00002470 if (flags & MOZ_TOPLEVEL_MENU_ITEM) {
2471 ensure_menu_bar_item_widget();
2472 item_widget = gMenuBarItemWidget;
2473 } else {
2474 ensure_menu_item_widget();
2475 item_widget = gMenuItemWidget;
2476 }
2477 gtk_widget_set_direction(item_widget, direction);
2478
2479 style = item_widget->style;
alpd8507382007-11-03 14:33:25 +00002480 TSOffsetStyleGCs(style, rect->x, rect->y);
alp@webkit.orgd694e942008-09-15 00:20:15 +00002481
2482 gtk_widget_style_get(item_widget, "selected-shadow-type",
2483 &shadow_type, NULL);
alpd8507382007-11-03 14:33:25 +00002484
2485 gtk_paint_box(style, drawable, GTK_STATE_PRELIGHT, shadow_type,
alp@webkit.org5a4c6982008-01-28 00:04:31 +00002486 cliprect, item_widget, "menuitem", rect->x, rect->y,
alpd8507382007-11-03 14:33:25 +00002487 rect->width, rect->height);
2488 }
2489
2490 return MOZ_GTK_SUCCESS;
2491}
2492
2493static gint
alp@webkit.org5a4c6982008-01-28 00:04:31 +00002494moz_gtk_menu_arrow_paint(GdkDrawable* drawable, GdkRectangle* rect,
2495 GdkRectangle* cliprect, GtkWidgetState* state,
2496 GtkTextDirection direction)
2497{
2498 GtkStyle* style;
2499 GtkStateType state_type = ConvertGtkState(state);
2500
2501 ensure_menu_item_widget();
2502 gtk_widget_set_direction(gMenuItemWidget, direction);
2503
2504 style = gMenuItemWidget->style;
2505
2506 TSOffsetStyleGCs(style, rect->x, rect->y);
2507 gtk_paint_arrow(style, drawable, state_type,
2508 (state_type == GTK_STATE_PRELIGHT) ? GTK_SHADOW_IN : GTK_SHADOW_OUT,
2509 cliprect, gMenuItemWidget, "menuitem",
2510 (direction == GTK_TEXT_DIR_LTR) ? GTK_ARROW_RIGHT : GTK_ARROW_LEFT,
2511 TRUE, rect->x, rect->y, rect->width, rect->height);
2512
2513 return MOZ_GTK_SUCCESS;
2514}
2515
2516static gint
alpd8507382007-11-03 14:33:25 +00002517moz_gtk_check_menu_item_paint(GdkDrawable* drawable, GdkRectangle* rect,
2518 GdkRectangle* cliprect, GtkWidgetState* state,
alp@webkit.org5a4c6982008-01-28 00:04:31 +00002519 gboolean checked, gboolean isradio,
2520 GtkTextDirection direction)
alpd8507382007-11-03 14:33:25 +00002521{
alp@webkit.org5a4c6982008-01-28 00:04:31 +00002522 GtkStateType state_type = ConvertGtkState(state);
alpd8507382007-11-03 14:33:25 +00002523 GtkStyle* style;
2524 GtkShadowType shadow_type = (checked)?GTK_SHADOW_IN:GTK_SHADOW_OUT;
2525 gint offset;
alp@webkit.org5a4c6982008-01-28 00:04:31 +00002526 gint indicator_size;
alpd8507382007-11-03 14:33:25 +00002527 gint x, y;
alp@webkit.org5a4c6982008-01-28 00:04:31 +00002528
2529 moz_gtk_menu_item_paint(drawable, rect, cliprect, state, FALSE, direction);
2530
alpd8507382007-11-03 14:33:25 +00002531 ensure_check_menu_item_widget();
alp@webkit.org5a4c6982008-01-28 00:04:31 +00002532 gtk_widget_set_direction(gCheckMenuItemWidget, direction);
2533
2534 gtk_widget_style_get (gCheckMenuItemWidget,
2535 "indicator-size", &indicator_size,
2536 NULL);
alpd8507382007-11-03 14:33:25 +00002537
2538 if (checked || GTK_CHECK_MENU_ITEM(gCheckMenuItemWidget)->always_show_toggle) {
2539 style = gCheckMenuItemWidget->style;
alp@webkit.org5a4c6982008-01-28 00:04:31 +00002540
2541 offset = GTK_CONTAINER(gCheckMenuItemWidget)->border_width +
alpd8507382007-11-03 14:33:25 +00002542 gCheckMenuItemWidget->style->xthickness + 2;
alp@webkit.org5a4c6982008-01-28 00:04:31 +00002543
2544 /* while normally this "3" would be the horizontal-padding style value, passing it to Gecko
2545 as the value of menuitem padding causes problems with dropdowns (bug 406129), so in the menu.css
2546 file this is hardcoded as 3px. Yes it sucks, but we don't really have a choice. */
2547 x = (direction == GTK_TEXT_DIR_RTL) ?
2548 rect->width - indicator_size - offset - 3: rect->x + offset + 3;
alpd8507382007-11-03 14:33:25 +00002549 y = rect->y + (rect->height - indicator_size) / 2;
alp@webkit.org5a4c6982008-01-28 00:04:31 +00002550
alpd8507382007-11-03 14:33:25 +00002551 TSOffsetStyleGCs(style, x, y);
2552 gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(gCheckMenuItemWidget),
2553 checked);
alp@webkit.org5a4c6982008-01-28 00:04:31 +00002554
alpd8507382007-11-03 14:33:25 +00002555 if (isradio) {
2556 gtk_paint_option(style, drawable, state_type, shadow_type, cliprect,
2557 gCheckMenuItemWidget, "option",
2558 x, y, indicator_size, indicator_size);
2559 } else {
2560 gtk_paint_check(style, drawable, state_type, shadow_type, cliprect,
2561 gCheckMenuItemWidget, "check",
2562 x, y, indicator_size, indicator_size);
2563 }
2564 }
alp@webkit.org5a4c6982008-01-28 00:04:31 +00002565
alpd8507382007-11-03 14:33:25 +00002566 return MOZ_GTK_SUCCESS;
2567}
2568
2569static gint
2570moz_gtk_window_paint(GdkDrawable* drawable, GdkRectangle* rect,
alp@webkit.org5a4c6982008-01-28 00:04:31 +00002571 GdkRectangle* cliprect, GtkTextDirection direction)
alpd8507382007-11-03 14:33:25 +00002572{
2573 GtkStyle* style;
2574
2575 ensure_window_widget();
alp@webkit.org5a4c6982008-01-28 00:04:31 +00002576 gtk_widget_set_direction(gProtoWindow, direction);
2577
alpd8507382007-11-03 14:33:25 +00002578 style = gProtoWindow->style;
2579
2580 TSOffsetStyleGCs(style, rect->x, rect->y);
2581 gtk_style_apply_default_background(style, drawable, TRUE,
2582 GTK_STATE_NORMAL,
2583 cliprect, rect->x, rect->y,
2584 rect->width, rect->height);
2585 return MOZ_GTK_SUCCESS;
2586}
2587
2588gint
2589moz_gtk_get_widget_border(GtkThemeWidgetType widget, gint* left, gint* top,
alp@webkit.org5a4c6982008-01-28 00:04:31 +00002590 gint* right, gint* bottom, GtkTextDirection direction,
2591 gboolean inhtml)
alpd8507382007-11-03 14:33:25 +00002592{
2593 GtkWidget* w;
2594
2595 switch (widget) {
2596 case MOZ_GTK_BUTTON:
2597 {
alp@webkit.orgd694e942008-09-15 00:20:15 +00002598 GtkBorder inner_border;
alpd8507382007-11-03 14:33:25 +00002599 gboolean interior_focus;
2600 gint focus_width, focus_pad;
2601
2602 ensure_button_widget();
2603 *left = *top = *right = *bottom = GTK_CONTAINER(gButtonWidget)->border_width;
2604
2605 /* Don't add this padding in HTML, otherwise the buttons will
2606 become too big and stuff the layout. */
2607 if (!inhtml) {
alp@webkit.org5a4c6982008-01-28 00:04:31 +00002608 moz_gtk_widget_get_focus(gButtonWidget, &interior_focus, &focus_width, &focus_pad);
alp@webkit.orgd694e942008-09-15 00:20:15 +00002609 moz_gtk_button_get_inner_border(gButtonWidget, &inner_border);
2610 *left += focus_width + focus_pad + inner_border.left;
2611 *right += focus_width + focus_pad + inner_border.right;
2612 *top += focus_width + focus_pad + inner_border.top;
2613 *bottom += focus_width + focus_pad + inner_border.bottom;
alpd8507382007-11-03 14:33:25 +00002614 }
2615
2616 *left += gButtonWidget->style->xthickness;
2617 *right += gButtonWidget->style->xthickness;
2618 *top += gButtonWidget->style->ythickness;
2619 *bottom += gButtonWidget->style->ythickness;
2620 return MOZ_GTK_SUCCESS;
2621 }
alpd8507382007-11-03 14:33:25 +00002622 case MOZ_GTK_ENTRY:
2623 ensure_entry_widget();
2624 w = gEntryWidget;
2625 break;
alp@webkit.org5a4c6982008-01-28 00:04:31 +00002626 case MOZ_GTK_TREEVIEW:
2627 ensure_tree_view_widget();
2628 w = gTreeViewWidget;
2629 break;
2630 case MOZ_GTK_TREE_HEADER_CELL:
2631 {
2632 /* A Tree Header in GTK is just a different styled button
2633 * It must be placed in a TreeView for getting the correct style
2634 * assigned.
2635 * That is why the following code is the same as for MOZ_GTK_BUTTON.
2636 * */
2637
alp@webkit.orgd694e942008-09-15 00:20:15 +00002638 GtkBorder inner_border;
alp@webkit.org5a4c6982008-01-28 00:04:31 +00002639 gboolean interior_focus;
2640 gint focus_width, focus_pad;
2641
2642 ensure_tree_header_cell_widget();
2643 *left = *top = *right = *bottom = GTK_CONTAINER(gTreeHeaderCellWidget)->border_width;
2644
alp@webkit.orgd694e942008-09-15 00:20:15 +00002645 moz_gtk_widget_get_focus(gTreeHeaderCellWidget, &interior_focus, &focus_width, &focus_pad);
2646 moz_gtk_button_get_inner_border(gTreeHeaderCellWidget, &inner_border);
2647 *left += focus_width + focus_pad + inner_border.left;
2648 *right += focus_width + focus_pad + inner_border.right;
2649 *top += focus_width + focus_pad + inner_border.top;
2650 *bottom += focus_width + focus_pad + inner_border.bottom;
alp@webkit.org5a4c6982008-01-28 00:04:31 +00002651
2652 *left += gTreeHeaderCellWidget->style->xthickness;
2653 *right += gTreeHeaderCellWidget->style->xthickness;
2654 *top += gTreeHeaderCellWidget->style->ythickness;
2655 *bottom += gTreeHeaderCellWidget->style->ythickness;
2656 return MOZ_GTK_SUCCESS;
2657 }
2658 case MOZ_GTK_TREE_HEADER_SORTARROW:
2659 ensure_tree_header_cell_widget();
2660 w = gTreeHeaderSortArrowWidget;
2661 break;
2662 case MOZ_GTK_DROPDOWN_ENTRY:
alp@webkit.orgd694e942008-09-15 00:20:15 +00002663 ensure_combo_box_entry_widgets();
2664 w = gComboBoxEntryTextareaWidget;
alp@webkit.org5a4c6982008-01-28 00:04:31 +00002665 break;
alpd8507382007-11-03 14:33:25 +00002666 case MOZ_GTK_DROPDOWN_ARROW:
alp@webkit.orgd694e942008-09-15 00:20:15 +00002667 ensure_combo_box_entry_widgets();
2668 w = gComboBoxEntryButtonWidget;
alpd8507382007-11-03 14:33:25 +00002669 break;
2670 case MOZ_GTK_DROPDOWN:
2671 {
alp@webkit.orgd694e942008-09-15 00:20:15 +00002672 /* We need to account for the arrow on the dropdown, so text
2673 * doesn't come too close to the arrow, or in some cases spill
2674 * into the arrow. */
2675 gboolean ignored_interior_focus, wide_separators;
2676 gint focus_width, focus_pad, separator_width;
2677 GtkRequisition arrow_req;
alpd8507382007-11-03 14:33:25 +00002678
alp@webkit.orgd694e942008-09-15 00:20:15 +00002679 ensure_combo_box_widgets();
2680
2681 *left = GTK_CONTAINER(gComboBoxButtonWidget)->border_width;
2682
2683 if (!inhtml) {
2684 moz_gtk_widget_get_focus(gComboBoxButtonWidget,
2685 &ignored_interior_focus,
2686 &focus_width, &focus_pad);
2687 *left += focus_width + focus_pad;
2688 }
2689
2690 *top = *left + gComboBoxButtonWidget->style->ythickness;
2691 *left += gComboBoxButtonWidget->style->xthickness;
2692
2693 *right = *left; *bottom = *top;
2694
2695 /* If there is no separator, don't try to count its width. */
2696 separator_width = 0;
2697 if (gComboBoxSeparatorWidget) {
2698 gtk_widget_style_get(gComboBoxSeparatorWidget,
2699 "wide-separators", &wide_separators,
2700 "separator-width", &separator_width,
2701 NULL);
2702
2703 if (!wide_separators)
2704 separator_width =
2705 XTHICKNESS(gComboBoxSeparatorWidget->style);
2706 }
2707
2708 gtk_widget_size_request(gComboBoxArrowWidget, &arrow_req);
alpd8507382007-11-03 14:33:25 +00002709
alp@webkit.org5a4c6982008-01-28 00:04:31 +00002710 if (direction == GTK_TEXT_DIR_RTL)
alp@webkit.orgd694e942008-09-15 00:20:15 +00002711 *left += separator_width + arrow_req.width;
alpd8507382007-11-03 14:33:25 +00002712 else
alp@webkit.orgd694e942008-09-15 00:20:15 +00002713 *right += separator_width + arrow_req.width;
2714
alpd8507382007-11-03 14:33:25 +00002715 return MOZ_GTK_SUCCESS;
2716 }
2717 case MOZ_GTK_TABPANELS:
2718 ensure_tab_widget();
2719 w = gTabWidget;
2720 break;
2721 case MOZ_GTK_PROGRESSBAR:
2722 ensure_progress_widget();
2723 w = gProgressWidget;
2724 break;
alp@webkit.org5a4c6982008-01-28 00:04:31 +00002725 case MOZ_GTK_SPINBUTTON_ENTRY:
alpd8507382007-11-03 14:33:25 +00002726 case MOZ_GTK_SPINBUTTON_UP:
2727 case MOZ_GTK_SPINBUTTON_DOWN:
2728 ensure_spin_widget();
2729 w = gSpinWidget;
2730 break;
2731 case MOZ_GTK_SCALE_HORIZONTAL:
2732 ensure_scale_widget();
2733 w = gHScaleWidget;
2734 break;
2735 case MOZ_GTK_SCALE_VERTICAL:
2736 ensure_scale_widget();
2737 w = gVScaleWidget;
2738 break;
2739 case MOZ_GTK_FRAME:
2740 ensure_frame_widget();
2741 w = gFrameWidget;
2742 break;
2743 case MOZ_GTK_CHECKBUTTON_LABEL:
2744 case MOZ_GTK_RADIOBUTTON_LABEL:
2745 {
2746 gboolean interior_focus;
2747 gint focus_width, focus_pad;
2748
2749 /* If the focus is interior, then the label has a border of
2750 (focus_width + focus_pad). */
alp@webkit.org5a4c6982008-01-28 00:04:31 +00002751 if (widget == MOZ_GTK_CHECKBUTTON_LABEL) {
2752 ensure_checkbox_widget();
2753 moz_gtk_widget_get_focus(gCheckboxWidget, &interior_focus,
alpd8507382007-11-03 14:33:25 +00002754 &focus_width, &focus_pad);
alp@webkit.org5a4c6982008-01-28 00:04:31 +00002755 }
2756 else {
2757 ensure_radiobutton_widget();
2758 moz_gtk_widget_get_focus(gRadiobuttonWidget, &interior_focus,
alpd8507382007-11-03 14:33:25 +00002759 &focus_width, &focus_pad);
alp@webkit.org5a4c6982008-01-28 00:04:31 +00002760 }
alpd8507382007-11-03 14:33:25 +00002761
2762 if (interior_focus)
2763 *left = *top = *right = *bottom = (focus_width + focus_pad);
2764 else
2765 *left = *top = *right = *bottom = 0;
2766
2767 return MOZ_GTK_SUCCESS;
2768 }
2769
2770 case MOZ_GTK_CHECKBUTTON_CONTAINER:
2771 case MOZ_GTK_RADIOBUTTON_CONTAINER:
2772 {
2773 gboolean interior_focus;
2774 gint focus_width, focus_pad;
2775
2776 /* If the focus is _not_ interior, then the container has a border
2777 of (focus_width + focus_pad). */
2778 if (widget == MOZ_GTK_CHECKBUTTON_CONTAINER) {
alp@webkit.org5a4c6982008-01-28 00:04:31 +00002779 ensure_checkbox_widget();
2780 moz_gtk_widget_get_focus(gCheckboxWidget, &interior_focus,
alpd8507382007-11-03 14:33:25 +00002781 &focus_width, &focus_pad);
2782 w = gCheckboxWidget;
2783 } else {
alp@webkit.org5a4c6982008-01-28 00:04:31 +00002784 ensure_radiobutton_widget();
2785 moz_gtk_widget_get_focus(gRadiobuttonWidget, &interior_focus,
alpd8507382007-11-03 14:33:25 +00002786 &focus_width, &focus_pad);
2787 w = gRadiobuttonWidget;
2788 }
2789
2790 *left = *top = *right = *bottom = GTK_CONTAINER(w)->border_width;
2791
2792 if (!interior_focus) {
2793 *left += (focus_width + focus_pad);
2794 *right += (focus_width + focus_pad);
2795 *top += (focus_width + focus_pad);
2796 *bottom += (focus_width + focus_pad);
2797 }
2798
2799 return MOZ_GTK_SUCCESS;
2800 }
alpd8507382007-11-03 14:33:25 +00002801 case MOZ_GTK_MENUPOPUP:
2802 ensure_menu_popup_widget();
2803 w = gMenuPopupWidget;
2804 break;
2805 case MOZ_GTK_MENUITEM:
2806 ensure_menu_item_widget();
alp@webkit.org5a4c6982008-01-28 00:04:31 +00002807 ensure_menu_bar_item_widget();
alpd8507382007-11-03 14:33:25 +00002808 w = gMenuItemWidget;
2809 break;
2810 case MOZ_GTK_CHECKMENUITEM:
2811 case MOZ_GTK_RADIOMENUITEM:
2812 ensure_check_menu_item_widget();
2813 w = gCheckMenuItemWidget;
2814 break;
alp@webkit.org5a4c6982008-01-28 00:04:31 +00002815 case MOZ_GTK_TAB:
2816 ensure_tab_widget();
2817 w = gTabWidget;
2818 break;
alpd8507382007-11-03 14:33:25 +00002819 /* These widgets have no borders, since they are not containers. */
alp@webkit.org5a4c6982008-01-28 00:04:31 +00002820 case MOZ_GTK_SPLITTER_HORIZONTAL:
2821 case MOZ_GTK_SPLITTER_VERTICAL:
alpd8507382007-11-03 14:33:25 +00002822 case MOZ_GTK_CHECKBUTTON:
2823 case MOZ_GTK_RADIOBUTTON:
2824 case MOZ_GTK_SCROLLBAR_BUTTON:
2825 case MOZ_GTK_SCROLLBAR_TRACK_HORIZONTAL:
2826 case MOZ_GTK_SCROLLBAR_TRACK_VERTICAL:
2827 case MOZ_GTK_SCROLLBAR_THUMB_HORIZONTAL:
2828 case MOZ_GTK_SCROLLBAR_THUMB_VERTICAL:
2829 case MOZ_GTK_SCALE_THUMB_HORIZONTAL:
2830 case MOZ_GTK_SCALE_THUMB_VERTICAL:
2831 case MOZ_GTK_GRIPPER:
2832 case MOZ_GTK_PROGRESS_CHUNK:
alp@webkit.org5a4c6982008-01-28 00:04:31 +00002833 case MOZ_GTK_EXPANDER:
alp@webkit.orgd694e942008-09-15 00:20:15 +00002834 case MOZ_GTK_TREEVIEW_EXPANDER:
alp@webkit.org5a4c6982008-01-28 00:04:31 +00002835 case MOZ_GTK_TOOLBAR_SEPARATOR:
2836 case MOZ_GTK_MENUSEPARATOR:
alpd8507382007-11-03 14:33:25 +00002837 /* These widgets have no borders.*/
alp@webkit.org5a4c6982008-01-28 00:04:31 +00002838 case MOZ_GTK_SPINBUTTON:
alpd8507382007-11-03 14:33:25 +00002839 case MOZ_GTK_TOOLTIP:
2840 case MOZ_GTK_WINDOW:
alp@webkit.org5a4c6982008-01-28 00:04:31 +00002841 case MOZ_GTK_RESIZER:
2842 case MOZ_GTK_MENUARROW:
2843 case MOZ_GTK_TOOLBARBUTTON_ARROW:
alp@webkit.orgd694e942008-09-15 00:20:15 +00002844 case MOZ_GTK_TOOLBAR:
2845 case MOZ_GTK_MENUBAR:
2846 case MOZ_GTK_TAB_SCROLLARROW:
2847 case MOZ_GTK_ENTRY_CARET:
alpd8507382007-11-03 14:33:25 +00002848 *left = *top = *right = *bottom = 0;
2849 return MOZ_GTK_SUCCESS;
2850 default:
2851 g_warning("Unsupported widget type: %d", widget);
2852 return MOZ_GTK_UNKNOWN_WIDGET;
2853 }
2854
2855 *right = *left = XTHICKNESS(w->style);
2856 *bottom = *top = YTHICKNESS(w->style);
2857
2858 return MOZ_GTK_SUCCESS;
2859}
2860
2861gint
alp@webkit.orgd694e942008-09-15 00:20:15 +00002862moz_gtk_get_combo_box_entry_button_size(gint* width, gint* height)
alpd8507382007-11-03 14:33:25 +00002863{
alpd8507382007-11-03 14:33:25 +00002864 /*
alp@webkit.orgd694e942008-09-15 00:20:15 +00002865 * We get the requisition of the drop down button, which includes
2866 * all padding, border and focus line widths the button uses,
2867 * as well as the minimum arrow size and its padding
2868 * */
2869 GtkRequisition requisition;
2870 ensure_combo_box_entry_widgets();
alpd8507382007-11-03 14:33:25 +00002871
alp@webkit.orgd694e942008-09-15 00:20:15 +00002872 gtk_widget_size_request(gComboBoxEntryButtonWidget, &requisition);
2873 *width = requisition.width;
2874 *height = requisition.height;
alpd8507382007-11-03 14:33:25 +00002875
alp@webkit.orgd694e942008-09-15 00:20:15 +00002876 return MOZ_GTK_SUCCESS;
2877}
2878
2879gint
2880moz_gtk_get_tab_scroll_arrow_size(gint* width, gint* height)
2881{
2882 gint arrow_size;
2883
2884 ensure_tab_widget();
2885 gtk_widget_style_get(gTabWidget,
2886 "scroll-arrow-hlength", &arrow_size,
2887 NULL);
2888
2889 *height = *width = arrow_size;
2890
2891 return MOZ_GTK_SUCCESS;
2892}
2893
2894gint
2895moz_gtk_get_downarrow_size(gint* width, gint* height)
2896{
2897 GtkRequisition requisition;
2898 ensure_button_arrow_widget();
2899
2900 gtk_widget_size_request(gButtonArrowWidget, &requisition);
2901 *width = requisition.width;
2902 *height = requisition.height;
alp@webkit.org5a4c6982008-01-28 00:04:31 +00002903
2904 return MOZ_GTK_SUCCESS;
2905}
2906
2907gint
2908moz_gtk_get_toolbar_separator_width(gint* size)
2909{
2910 gboolean wide_separators;
2911 gint separator_width;
2912 GtkStyle* style;
2913
2914 ensure_toolbar_widget();
2915
2916 style = gToolbarWidget->style;
2917
2918 gtk_widget_style_get(gToolbarWidget,
2919 "space-size", size,
2920 "wide-separators", &wide_separators,
2921 "separator-width", &separator_width,
2922 NULL);
2923
2924 /* Just in case... */
2925 *size = MAX(*size, (wide_separators ? separator_width : style->xthickness));
2926
2927 return MOZ_GTK_SUCCESS;
2928}
2929
2930gint
2931moz_gtk_get_expander_size(gint* size)
2932{
2933 ensure_expander_widget();
2934 gtk_widget_style_get(gExpanderWidget,
2935 "expander-size", size,
2936 NULL);
2937
2938 return MOZ_GTK_SUCCESS;
2939}
2940
2941gint
2942moz_gtk_get_treeview_expander_size(gint* size)
2943{
2944 ensure_tree_view_widget();
2945 gtk_widget_style_get(gTreeViewWidget,
2946 "expander-size", size,
2947 NULL);
2948
2949 return MOZ_GTK_SUCCESS;
2950}
2951
2952gint
2953moz_gtk_get_menu_separator_height(gint *size)
2954{
2955 gboolean wide_separators;
2956 gint separator_height;
2957
2958 ensure_menu_separator_widget();
2959
2960 gtk_widget_style_get(gMenuSeparatorWidget,
2961 "wide-separators", &wide_separators,
2962 "separator-height", &separator_height,
2963 NULL);
2964
2965 if (wide_separators)
2966 *size = separator_height + gMenuSeparatorWidget->style->ythickness;
2967 else
2968 *size = gMenuSeparatorWidget->style->ythickness * 2;
alpd8507382007-11-03 14:33:25 +00002969
2970 return MOZ_GTK_SUCCESS;
2971}
2972
2973gint
2974moz_gtk_get_scalethumb_metrics(GtkOrientation orient, gint* thumb_length, gint* thumb_height)
2975{
2976 GtkWidget* widget;
2977
2978 ensure_scale_widget();
2979 widget = ((orient == GTK_ORIENTATION_HORIZONTAL) ? gHScaleWidget : gVScaleWidget);
2980
2981 gtk_widget_style_get (widget,
2982 "slider_length", thumb_length,
2983 "slider_width", thumb_height,
2984 NULL);
2985
2986 return MOZ_GTK_SUCCESS;
2987}
2988
2989gint
2990moz_gtk_get_scrollbar_metrics(MozGtkScrollbarMetrics *metrics)
2991{
2992 ensure_scrollbar_widget();
2993
2994 gtk_widget_style_get (gHorizScrollbarWidget,
2995 "slider_width", &metrics->slider_width,
2996 "trough_border", &metrics->trough_border,
2997 "stepper_size", &metrics->stepper_size,
2998 "stepper_spacing", &metrics->stepper_spacing,
2999 NULL);
3000
3001 metrics->min_slider_size =
3002 GTK_RANGE(gHorizScrollbarWidget)->min_slider_size;
3003
3004 return MOZ_GTK_SUCCESS;
3005}
3006
alp@webkit.orgd694e942008-09-15 00:20:15 +00003007gboolean
3008moz_gtk_images_in_menus()
3009{
3010 gboolean result;
3011 GtkSettings* settings;
3012
3013 ensure_image_menu_item_widget();
3014 settings = gtk_widget_get_settings(gImageMenuItemWidget);
3015
3016 g_object_get(settings, "gtk-menu-images", &result, NULL);
3017 return result;
3018}
3019
alpd8507382007-11-03 14:33:25 +00003020gint
3021moz_gtk_widget_paint(GtkThemeWidgetType widget, GdkDrawable* drawable,
3022 GdkRectangle* rect, GdkRectangle* cliprect,
alp@webkit.org5a4c6982008-01-28 00:04:31 +00003023 GtkWidgetState* state, gint flags,
3024 GtkTextDirection direction)
alpd8507382007-11-03 14:33:25 +00003025{
3026 switch (widget) {
3027 case MOZ_GTK_BUTTON:
alp@webkit.org5a4c6982008-01-28 00:04:31 +00003028 if (state->depressed) {
3029 ensure_toggle_button_widget();
3030 return moz_gtk_button_paint(drawable, rect, cliprect, state,
3031 (GtkReliefStyle) flags,
3032 gToggleButtonWidget, direction);
3033 }
alpd8507382007-11-03 14:33:25 +00003034 ensure_button_widget();
3035 return moz_gtk_button_paint(drawable, rect, cliprect, state,
alp@webkit.org5a4c6982008-01-28 00:04:31 +00003036 (GtkReliefStyle) flags, gButtonWidget,
3037 direction);
alpd8507382007-11-03 14:33:25 +00003038 break;
3039 case MOZ_GTK_CHECKBUTTON:
3040 case MOZ_GTK_RADIOBUTTON:
3041 return moz_gtk_toggle_paint(drawable, rect, cliprect, state,
3042 (gboolean) flags,
alp@webkit.org5a4c6982008-01-28 00:04:31 +00003043 (widget == MOZ_GTK_RADIOBUTTON),
3044 direction);
alpd8507382007-11-03 14:33:25 +00003045 break;
3046 case MOZ_GTK_SCROLLBAR_BUTTON:
alp@webkit.org5a4c6982008-01-28 00:04:31 +00003047 return moz_gtk_scrollbar_button_paint(drawable, rect, cliprect, state,
3048 (GtkScrollbarButtonFlags) flags,
3049 direction);
alpd8507382007-11-03 14:33:25 +00003050 break;
3051 case MOZ_GTK_SCROLLBAR_TRACK_HORIZONTAL:
3052 case MOZ_GTK_SCROLLBAR_TRACK_VERTICAL:
3053 return moz_gtk_scrollbar_trough_paint(widget, drawable, rect,
alp@webkit.org5a4c6982008-01-28 00:04:31 +00003054 cliprect, state, direction);
alpd8507382007-11-03 14:33:25 +00003055 break;
3056 case MOZ_GTK_SCROLLBAR_THUMB_HORIZONTAL:
3057 case MOZ_GTK_SCROLLBAR_THUMB_VERTICAL:
3058 return moz_gtk_scrollbar_thumb_paint(widget, drawable, rect,
alp@webkit.org5a4c6982008-01-28 00:04:31 +00003059 cliprect, state, direction);
alpd8507382007-11-03 14:33:25 +00003060 break;
3061 case MOZ_GTK_SCALE_HORIZONTAL:
3062 case MOZ_GTK_SCALE_VERTICAL:
alp@webkit.org5a4c6982008-01-28 00:04:31 +00003063 return moz_gtk_scale_paint(drawable, rect, cliprect, state,
3064 (GtkOrientation) flags, direction);
alpd8507382007-11-03 14:33:25 +00003065 break;
3066 case MOZ_GTK_SCALE_THUMB_HORIZONTAL:
3067 case MOZ_GTK_SCALE_THUMB_VERTICAL:
alp@webkit.org5a4c6982008-01-28 00:04:31 +00003068 return moz_gtk_scale_thumb_paint(drawable, rect, cliprect, state,
3069 (GtkOrientation) flags, direction);
3070 break;
3071 case MOZ_GTK_SPINBUTTON:
3072 return moz_gtk_spin_paint(drawable, rect, direction);
alpd8507382007-11-03 14:33:25 +00003073 break;
3074 case MOZ_GTK_SPINBUTTON_UP:
3075 case MOZ_GTK_SPINBUTTON_DOWN:
alp@webkit.org5a4c6982008-01-28 00:04:31 +00003076 return moz_gtk_spin_updown_paint(drawable, rect,
3077 (widget == MOZ_GTK_SPINBUTTON_DOWN),
3078 state, direction);
3079 break;
3080 case MOZ_GTK_SPINBUTTON_ENTRY:
3081 ensure_spin_widget();
3082 return moz_gtk_entry_paint(drawable, rect, cliprect, state,
3083 gSpinWidget, direction);
alpd8507382007-11-03 14:33:25 +00003084 break;
3085 case MOZ_GTK_GRIPPER:
alp@webkit.org5a4c6982008-01-28 00:04:31 +00003086 return moz_gtk_gripper_paint(drawable, rect, cliprect, state,
3087 direction);
3088 break;
3089 case MOZ_GTK_TREEVIEW:
3090 return moz_gtk_treeview_paint(drawable, rect, cliprect, state,
3091 direction);
3092 break;
3093 case MOZ_GTK_TREE_HEADER_CELL:
3094 return moz_gtk_tree_header_cell_paint(drawable, rect, cliprect, state,
alp@webkit.orgd694e942008-09-15 00:20:15 +00003095 flags, direction);
alp@webkit.org5a4c6982008-01-28 00:04:31 +00003096 break;
3097 case MOZ_GTK_TREE_HEADER_SORTARROW:
3098 return moz_gtk_tree_header_sort_arrow_paint(drawable, rect, cliprect,
3099 state,
3100 (GtkArrowType) flags,
3101 direction);
3102 break;
3103 case MOZ_GTK_TREEVIEW_EXPANDER:
3104 return moz_gtk_treeview_expander_paint(drawable, rect, cliprect, state,
3105 (GtkExpanderStyle) flags, direction);
3106 break;
3107 case MOZ_GTK_EXPANDER:
3108 return moz_gtk_expander_paint(drawable, rect, cliprect, state,
3109 (GtkExpanderStyle) flags, direction);
alpd8507382007-11-03 14:33:25 +00003110 break;
3111 case MOZ_GTK_ENTRY:
alp@webkit.org5a4c6982008-01-28 00:04:31 +00003112 ensure_entry_widget();
3113 return moz_gtk_entry_paint(drawable, rect, cliprect, state,
3114 gEntryWidget, direction);
alpd8507382007-11-03 14:33:25 +00003115 break;
alp@webkit.orgd694e942008-09-15 00:20:15 +00003116 case MOZ_GTK_ENTRY_CARET:
3117 return moz_gtk_caret_paint(drawable, rect, cliprect, direction);
3118 break;
alpd8507382007-11-03 14:33:25 +00003119 case MOZ_GTK_DROPDOWN:
alp@webkit.orgd694e942008-09-15 00:20:15 +00003120 return moz_gtk_combo_box_paint(drawable, rect, cliprect, state,
3121 (gboolean) flags, direction);
alpd8507382007-11-03 14:33:25 +00003122 break;
3123 case MOZ_GTK_DROPDOWN_ARROW:
alp@webkit.orgd694e942008-09-15 00:20:15 +00003124 return moz_gtk_combo_box_entry_button_paint(drawable, rect, cliprect,
3125 state, flags, direction);
alp@webkit.org5a4c6982008-01-28 00:04:31 +00003126 break;
3127 case MOZ_GTK_DROPDOWN_ENTRY:
alp@webkit.orgd694e942008-09-15 00:20:15 +00003128 ensure_combo_box_entry_widgets();
alp@webkit.org5a4c6982008-01-28 00:04:31 +00003129 return moz_gtk_entry_paint(drawable, rect, cliprect, state,
alp@webkit.orgd694e942008-09-15 00:20:15 +00003130 gComboBoxEntryTextareaWidget, direction);
alpd8507382007-11-03 14:33:25 +00003131 break;
3132 case MOZ_GTK_CHECKBUTTON_CONTAINER:
3133 case MOZ_GTK_RADIOBUTTON_CONTAINER:
3134 return moz_gtk_container_paint(drawable, rect, cliprect, state,
alp@webkit.org5a4c6982008-01-28 00:04:31 +00003135 (widget == MOZ_GTK_RADIOBUTTON_CONTAINER),
3136 direction);
alpd8507382007-11-03 14:33:25 +00003137 break;
3138 case MOZ_GTK_CHECKBUTTON_LABEL:
3139 case MOZ_GTK_RADIOBUTTON_LABEL:
3140 return moz_gtk_toggle_label_paint(drawable, rect, cliprect, state,
alp@webkit.org5a4c6982008-01-28 00:04:31 +00003141 (widget == MOZ_GTK_RADIOBUTTON_LABEL),
3142 direction);
alpd8507382007-11-03 14:33:25 +00003143 break;
3144 case MOZ_GTK_TOOLBAR:
alp@webkit.org5a4c6982008-01-28 00:04:31 +00003145 return moz_gtk_toolbar_paint(drawable, rect, cliprect, direction);
3146 break;
3147 case MOZ_GTK_TOOLBAR_SEPARATOR:
3148 return moz_gtk_toolbar_separator_paint(drawable, rect, cliprect,
3149 direction);
alpd8507382007-11-03 14:33:25 +00003150 break;
3151 case MOZ_GTK_TOOLTIP:
alp@webkit.org5a4c6982008-01-28 00:04:31 +00003152 return moz_gtk_tooltip_paint(drawable, rect, cliprect, direction);
alpd8507382007-11-03 14:33:25 +00003153 break;
3154 case MOZ_GTK_FRAME:
alp@webkit.org5a4c6982008-01-28 00:04:31 +00003155 return moz_gtk_frame_paint(drawable, rect, cliprect, direction);
3156 break;
3157 case MOZ_GTK_RESIZER:
3158 return moz_gtk_resizer_paint(drawable, rect, cliprect, state,
3159 direction);
alpd8507382007-11-03 14:33:25 +00003160 break;
3161 case MOZ_GTK_PROGRESSBAR:
alp@webkit.org5a4c6982008-01-28 00:04:31 +00003162 return moz_gtk_progressbar_paint(drawable, rect, cliprect, direction);
alpd8507382007-11-03 14:33:25 +00003163 break;
3164 case MOZ_GTK_PROGRESS_CHUNK:
alp@webkit.org5a4c6982008-01-28 00:04:31 +00003165 return moz_gtk_progress_chunk_paint(drawable, rect, cliprect,
3166 direction);
alpd8507382007-11-03 14:33:25 +00003167 break;
3168 case MOZ_GTK_TAB:
alp@webkit.org5a4c6982008-01-28 00:04:31 +00003169 return moz_gtk_tab_paint(drawable, rect, cliprect,
3170 (GtkTabFlags) flags, direction);
alpd8507382007-11-03 14:33:25 +00003171 break;
3172 case MOZ_GTK_TABPANELS:
alp@webkit.org5a4c6982008-01-28 00:04:31 +00003173 return moz_gtk_tabpanels_paint(drawable, rect, cliprect, direction);
alpd8507382007-11-03 14:33:25 +00003174 break;
alp@webkit.orgd694e942008-09-15 00:20:15 +00003175 case MOZ_GTK_TAB_SCROLLARROW:
3176 return moz_gtk_tab_scroll_arrow_paint(drawable, rect, cliprect, state,
3177 (GtkArrowType) flags, direction);
3178 break;
alpd8507382007-11-03 14:33:25 +00003179 case MOZ_GTK_MENUBAR:
alp@webkit.org5a4c6982008-01-28 00:04:31 +00003180 return moz_gtk_menu_bar_paint(drawable, rect, cliprect, direction);
alpd8507382007-11-03 14:33:25 +00003181 break;
3182 case MOZ_GTK_MENUPOPUP:
alp@webkit.org5a4c6982008-01-28 00:04:31 +00003183 return moz_gtk_menu_popup_paint(drawable, rect, cliprect, direction);
3184 break;
3185 case MOZ_GTK_MENUSEPARATOR:
3186 return moz_gtk_menu_separator_paint(drawable, rect, cliprect,
3187 direction);
alpd8507382007-11-03 14:33:25 +00003188 break;
3189 case MOZ_GTK_MENUITEM:
alp@webkit.org5a4c6982008-01-28 00:04:31 +00003190 return moz_gtk_menu_item_paint(drawable, rect, cliprect, state, flags,
3191 direction);
3192 break;
3193 case MOZ_GTK_MENUARROW:
3194 return moz_gtk_menu_arrow_paint(drawable, rect, cliprect, state,
3195 direction);
3196 break;
3197 case MOZ_GTK_TOOLBARBUTTON_ARROW:
3198 return moz_gtk_downarrow_paint(drawable, rect, cliprect, state);
alpd8507382007-11-03 14:33:25 +00003199 break;
3200 case MOZ_GTK_CHECKMENUITEM:
3201 case MOZ_GTK_RADIOMENUITEM:
3202 return moz_gtk_check_menu_item_paint(drawable, rect, cliprect, state,
3203 (gboolean) flags,
alp@webkit.org5a4c6982008-01-28 00:04:31 +00003204 (widget == MOZ_GTK_RADIOMENUITEM),
3205 direction);
3206 break;
3207 case MOZ_GTK_SPLITTER_HORIZONTAL:
3208 return moz_gtk_vpaned_paint(drawable, rect, cliprect, state);
3209 break;
3210 case MOZ_GTK_SPLITTER_VERTICAL:
3211 return moz_gtk_hpaned_paint(drawable, rect, cliprect, state);
alpd8507382007-11-03 14:33:25 +00003212 break;
3213 case MOZ_GTK_WINDOW:
alp@webkit.org5a4c6982008-01-28 00:04:31 +00003214 return moz_gtk_window_paint(drawable, rect, cliprect, direction);
alpd8507382007-11-03 14:33:25 +00003215 break;
3216 default:
3217 g_warning("Unknown widget type: %d", widget);
3218 }
3219
3220 return MOZ_GTK_UNKNOWN_WIDGET;
3221}
3222
3223GtkWidget* moz_gtk_get_scrollbar_widget(void)
3224{
3225 if (!is_initialized)
3226 return NULL;
3227 ensure_scrollbar_widget();
3228 return gHorizScrollbarWidget;
3229}
3230
3231gint
3232moz_gtk_shutdown()
3233{
alp@webkit.orgd694e942008-09-15 00:20:15 +00003234 GtkWidgetClass *entry_class;
3235
alpd8507382007-11-03 14:33:25 +00003236 if (gTooltipWidget)
3237 gtk_widget_destroy(gTooltipWidget);
3238 /* This will destroy all of our widgets */
3239 if (gProtoWindow)
3240 gtk_widget_destroy(gProtoWindow);
3241
3242 gProtoWindow = NULL;
3243 gButtonWidget = NULL;
alp@webkit.org5a4c6982008-01-28 00:04:31 +00003244 gToggleButtonWidget = NULL;
alp@webkit.orgd694e942008-09-15 00:20:15 +00003245 gButtonArrowWidget = NULL;
alpd8507382007-11-03 14:33:25 +00003246 gCheckboxWidget = NULL;
3247 gRadiobuttonWidget = NULL;
3248 gHorizScrollbarWidget = NULL;
3249 gVertScrollbarWidget = NULL;
alp@webkit.org5a4c6982008-01-28 00:04:31 +00003250 gSpinWidget = NULL;
alpd8507382007-11-03 14:33:25 +00003251 gHScaleWidget = NULL;
3252 gVScaleWidget = NULL;
3253 gEntryWidget = NULL;
alp@webkit.orgd694e942008-09-15 00:20:15 +00003254 gComboBoxWidget = NULL;
3255 gComboBoxButtonWidget = NULL;
3256 gComboBoxSeparatorWidget = NULL;
3257 gComboBoxArrowWidget = NULL;
alp@webkit.org5a4c6982008-01-28 00:04:31 +00003258 gComboBoxEntryWidget = NULL;
alp@webkit.orgd694e942008-09-15 00:20:15 +00003259 gComboBoxEntryButtonWidget = NULL;
3260 gComboBoxEntryArrowWidget = NULL;
3261 gComboBoxEntryTextareaWidget = NULL;
alpd8507382007-11-03 14:33:25 +00003262 gHandleBoxWidget = NULL;
3263 gToolbarWidget = NULL;
alp@webkit.org5a4c6982008-01-28 00:04:31 +00003264 gStatusbarWidget = NULL;
alpd8507382007-11-03 14:33:25 +00003265 gFrameWidget = NULL;
3266 gProgressWidget = NULL;
3267 gTabWidget = NULL;
3268 gTooltipWidget = NULL;
3269 gMenuBarWidget = NULL;
3270 gMenuBarItemWidget = NULL;
3271 gMenuPopupWidget = NULL;
3272 gMenuItemWidget = NULL;
alp@webkit.orgd694e942008-09-15 00:20:15 +00003273 gImageMenuItemWidget = NULL;
alpd8507382007-11-03 14:33:25 +00003274 gCheckMenuItemWidget = NULL;
alp@webkit.org5a4c6982008-01-28 00:04:31 +00003275 gTreeViewWidget = NULL;
alp@webkit.orgd694e942008-09-15 00:20:15 +00003276 gMiddleTreeViewColumn = NULL;
alp@webkit.org5a4c6982008-01-28 00:04:31 +00003277 gTreeHeaderCellWidget = NULL;
3278 gTreeHeaderSortArrowWidget = NULL;
3279 gExpanderWidget = NULL;
3280 gToolbarSeparatorWidget = NULL;
3281 gMenuSeparatorWidget = NULL;
3282 gHPanedWidget = NULL;
3283 gVPanedWidget = NULL;
alp@webkit.orgd694e942008-09-15 00:20:15 +00003284 gScrolledWindowWidget = NULL;
3285
3286 entry_class = g_type_class_peek(GTK_TYPE_ENTRY);
3287 g_type_class_unref(entry_class);
alpd8507382007-11-03 14:33:25 +00003288
3289 is_initialized = FALSE;
3290
3291 return MOZ_GTK_SUCCESS;
3292}