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