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