1 /* Helper functions for gtk-engines
2 *
3 * Copyright (C) 2006 Andrew Johnson <acjgenius@earthlink.net>
4 * Copyright (C) 2006-2007 Benjamin Berg <benjamin@sipsolutions.net>
5 *
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
10 *
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
15 *
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
19 *
20 * Project contact: <gnome-themes-list@gnome.org>
21 *
22 *
23 * Written by Andrew Johnson <acjgenius@earthlink.net>
24 * Written by Benjamin Berg <benjamin@sipsolutions.net>
25 * modified by Andrea Cimitan <andrea.cimitan@gmail.com>
26 *
27 */
28
29 #include <gtk/gtk.h>
30
31 #include "general-support.h"
32 #include "widget-information.h"
33 #include "config.h"
34 #include <math.h>
35 #include <string.h>
36
37 static gchar ge_widget_hints[] =
38 "treeview\0"
39 "treeview-header\0"
40 "statusbar\0"
41 "comboboxentry\0"
42 "spinbutton\0"
43 "scale\0"
44 "vscale\0"
45 "hscale\0"
46 "scrollbar\0"
47 "vscrollbar\0"
48 "hscrollbar\0"
49 "progressbar\0"
50 "menubar\0";
51
52 gboolean
ge_check_hint(GEHint hint,GQuark style_hint,GtkWidget * widget)53 ge_check_hint (GEHint hint,
54 GQuark style_hint,
55 GtkWidget *widget)
56 {
57 static GEHint quark_hint_lookup[GE_HINT_COUNT] = {0};
58
59 g_assert ((hint >= 0) && (hint < GE_HINT_COUNT));
60
61 /* Initilize lookup table */
62 if (G_UNLIKELY (quark_hint_lookup[0] == 0))
63 {
64 guint i = 0;
65 gchar *cur_hint_str = ge_widget_hints;
66 while ((i < GE_HINT_COUNT) && cur_hint_str[0])
67 {
68 /* Can't use _from_static_string as the engine may be unloaded. */
69 quark_hint_lookup[i] = g_quark_from_string (cur_hint_str);
70 cur_hint_str += strlen(cur_hint_str) + 1;
71 i++;
72 }
73 g_assert (i == GE_HINT_COUNT && cur_hint_str[0] == '\0');
74 }
75
76
77 if (quark_hint_lookup[hint] == style_hint)
78 return TRUE;
79
80
81 /* Try to decide based on other hints, eg. hscale is also a scale. */
82 if (hint == GE_HINT_SCALE)
83 if (ge_check_hint (GE_HINT_VSCALE, style_hint, widget) ||
84 ge_check_hint (GE_HINT_HSCALE, style_hint, widget))
85 return TRUE;
86 if (hint == GE_HINT_SCROLLBAR)
87 if (ge_check_hint (GE_HINT_VSCROLLBAR, style_hint, widget) ||
88 ge_check_hint (GE_HINT_HSCROLLBAR, style_hint, widget))
89 return TRUE;
90 if (hint == GE_HINT_TREEVIEW)
91 if (ge_check_hint (GE_HINT_TREEVIEW_HEADER, style_hint, widget))
92 return TRUE;
93
94
95 /* These may be caused by applications so we never want to disable them.
96 * TODO: This does not catch the case where the theme uses appears-as-list
97 * and the application turns it off again. Though this case
98 * is even less likely. */
99 switch (hint) {
100 case GE_HINT_COMBOBOX_ENTRY:
101 if (widget && ge_object_is_a (G_OBJECT (widget), "GtkComboBox"))
102 {
103 gboolean appears_as_list = FALSE;
104
105 gtk_widget_style_get (widget, "appears-as-list", &appears_as_list, NULL);
106
107 if (appears_as_list)
108 return TRUE;
109 }
110 break;
111 default:
112 break;
113 }
114
115
116 #ifdef ENABLE_WIDGET_CHECKS
117 /* If a style_hint *was* set, and nothing matched, just give up right away.
118 * A theme shall either support it fully, or not at all. */
119 if (style_hint != 0)
120 return FALSE;
121
122 /* No widget? Just give up. Nothing we can do. */
123 if (widget == NULL)
124 return FALSE;
125
126 /* Try to do something based on the passed in widget pointer. */
127 switch (hint) {
128 case GE_HINT_TREEVIEW:
129 if (widget->parent && (ge_object_is_a (G_OBJECT (widget->parent), "GtkTreeView")))
130 return TRUE;
131 break;
132 case GE_HINT_TREEVIEW_HEADER:
133 if (ge_object_is_a (G_OBJECT (widget), "GtkButton") && widget->parent &&
134 (ge_object_is_a (G_OBJECT (widget->parent), "GtkTreeView") || ge_object_is_a (G_OBJECT (widget->parent), "GtkCList") ||
135 ge_object_is_a (G_OBJECT (widget->parent), "GtkCTree")))
136 return TRUE;
137 if (widget->parent && ge_object_is_a (G_OBJECT (widget->parent), "ETreeView"))
138 return TRUE;
139 break;
140 case GE_HINT_COMBOBOX_ENTRY:
141 if (ge_is_in_combo_box (widget))
142 return TRUE;
143 break;
144 case GE_HINT_SPINBUTTON:
145 if (ge_object_is_a (G_OBJECT (widget), "GtkSpinButton"))
146 return TRUE;
147 break;
148 case GE_HINT_STATUSBAR:
149 if (widget->parent && ge_object_is_a (G_OBJECT (widget), "GtkStatusbar"))
150 return TRUE;
151 break;
152 case GE_HINT_SCALE:
153 if (ge_object_is_a (G_OBJECT (widget), "GtkScale"))
154 return TRUE;
155 break;
156 case GE_HINT_HSCALE:
157 if (ge_object_is_a (G_OBJECT (widget), "GtkHScale"))
158 return TRUE;
159 break;
160 case GE_HINT_VSCALE:
161 if (ge_object_is_a (G_OBJECT (widget), "GtkVScale"))
162 return TRUE;
163 break;
164 case GE_HINT_SCROLLBAR:
165 if (ge_object_is_a (G_OBJECT (widget), "GtkScrollbar"))
166 return TRUE;
167 break;
168 case GE_HINT_HSCROLLBAR:
169 if (ge_object_is_a (G_OBJECT (widget), "GtkHScrollbar"))
170 return TRUE;
171 break;
172 case GE_HINT_VSCROLLBAR:
173 if (ge_object_is_a (G_OBJECT (widget), "GtkVScrollbar"))
174 return TRUE;
175 break;
176 case GE_HINT_PROGRESSBAR:
177 if (ge_object_is_a (G_OBJECT (widget), "GtkProgressBar"))
178 return TRUE;
179 break;
180 case GE_HINT_MENUBAR:
181 if (ge_object_is_a (G_OBJECT (widget), "GtkMenuBar") ||
182 ge_object_is_a (G_OBJECT (widget->parent), "GtkMenuBar"))
183 return TRUE;
184 break;
185
186 default:
187 break;
188 }
189
190 #endif
191
192
193 return FALSE;
194 }
195
196 /* Widget Type Lookups/Macros
197
198 Based on/modified from functions in
199 Smooth-Engine.
200 */
201 gboolean
ge_object_is_a(const GObject * object,const gchar * type_name)202 ge_object_is_a (const GObject * object, const gchar * type_name)
203 {
204 gboolean result = FALSE;
205
206 if ((object))
207 {
208 GType tmp = g_type_from_name (type_name);
209
210 if (tmp)
211 result = g_type_check_instance_is_a ((GTypeInstance *) object, tmp);
212 }
213
214 return result;
215 }
216
217 gboolean
ge_is_combo_box_entry(GtkWidget * widget)218 ge_is_combo_box_entry (GtkWidget * widget)
219 {
220 gboolean result = FALSE;
221
222 if ((widget) && (widget->parent))
223 {
224 if (GE_IS_COMBO_BOX_ENTRY (widget->parent))
225 result = TRUE;
226 else
227 result = ge_is_combo_box_entry (widget->parent);
228 }
229 return result;
230 }
231
232 static gboolean
ge_combo_box_is_using_list(GtkWidget * widget)233 ge_combo_box_is_using_list (GtkWidget * widget)
234 {
235 gboolean result = FALSE;
236
237 if (GE_IS_COMBO_BOX (widget))
238 gtk_widget_style_get (widget, "appears-as-list", &result, NULL);
239
240 return result;
241 }
242
243 gboolean
ge_is_combo_box(GtkWidget * widget,gboolean as_list)244 ge_is_combo_box (GtkWidget * widget, gboolean as_list)
245 {
246 gboolean result = FALSE;
247
248 if ((widget) && (widget->parent))
249 {
250 if (GE_IS_COMBO_BOX (widget->parent))
251 {
252 if (as_list)
253 result = (ge_combo_box_is_using_list(widget->parent));
254 else
255 result = (!ge_combo_box_is_using_list(widget->parent));
256 }
257 else
258 result = ge_is_combo_box (widget->parent, as_list);
259 }
260 return result;
261 }
262
263 gboolean
ge_is_combo(GtkWidget * widget)264 ge_is_combo (GtkWidget * widget)
265 {
266 gboolean result = FALSE;
267
268 if ((widget) && (widget->parent))
269 {
270 if (GE_IS_COMBO (widget->parent))
271 result = TRUE;
272 else
273 result = ge_is_combo (widget->parent);
274 }
275 return result;
276 }
277
278 gboolean
ge_is_in_combo_box(GtkWidget * widget)279 ge_is_in_combo_box (GtkWidget * widget)
280 {
281 return ((ge_is_combo (widget) || ge_is_combo_box (widget, TRUE) || ge_is_combo_box_entry (widget)));
282 }
283
284 gboolean
ge_is_toolbar_item(GtkWidget * widget)285 ge_is_toolbar_item (GtkWidget * widget)
286 {
287 gboolean result = FALSE;
288
289 if ((widget) && (widget->parent)) {
290 if ((GE_IS_BONOBO_TOOLBAR (widget->parent))
291 || (GE_IS_BONOBO_DOCK_ITEM (widget->parent))
292 || (GE_IS_EGG_TOOLBAR (widget->parent))
293 || (GE_IS_TOOLBAR (widget->parent))
294 || (GE_IS_HANDLE_BOX (widget->parent)))
295 result = TRUE;
296 else
297 result = ge_is_toolbar_item (widget->parent);
298 }
299 return result;
300 }
301
302 gboolean
ge_is_panel_widget_item(GtkWidget * widget)303 ge_is_panel_widget_item (GtkWidget * widget)
304 {
305 gboolean result = FALSE;
306
307 if ((widget) && (widget->parent))
308 {
309 if (GE_IS_PANEL_WIDGET (widget->parent))
310 result = TRUE;
311 else
312 result = ge_is_panel_widget_item (widget->parent);
313 }
314 return result;
315 }
316
317 gboolean
ge_is_bonobo_dock_item(GtkWidget * widget)318 ge_is_bonobo_dock_item (GtkWidget * widget)
319 {
320 gboolean result = FALSE;
321
322 if ((widget))
323 {
324 if (GE_IS_BONOBO_DOCK_ITEM(widget) || GE_IS_BONOBO_DOCK_ITEM (widget->parent))
325 result = TRUE;
326 else if (GE_IS_BOX(widget) || GE_IS_BOX(widget->parent))
327 {
328 GtkContainer *box = GE_IS_BOX(widget)?GTK_CONTAINER(widget):GTK_CONTAINER(widget->parent);
329 GList *children = NULL, *child = NULL;
330
331 children = gtk_container_get_children(box);
332
333 for (child = g_list_first(children); child; child = g_list_next(child))
334 {
335 if (GE_IS_BONOBO_DOCK_ITEM_GRIP(child->data))
336 {
337 result = TRUE;
338 child = NULL;
339 }
340 }
341
342 if (children)
343 g_list_free(children);
344 }
345 }
346 return result;
347 }
348
349 static GtkWidget *
ge_find_combo_box_entry_widget(GtkWidget * widget)350 ge_find_combo_box_entry_widget (GtkWidget * widget)
351 {
352 GtkWidget *result = NULL;
353
354 if (widget)
355 {
356 if (GE_IS_COMBO_BOX_ENTRY (widget))
357 result = widget;
358 else
359 result = ge_find_combo_box_entry_widget (widget->parent);
360 }
361
362 return result;
363 }
364
365 static GtkWidget *
ge_find_combo_box_widget(GtkWidget * widget,gboolean as_list)366 ge_find_combo_box_widget (GtkWidget * widget, gboolean as_list)
367 {
368 GtkWidget *result = NULL;
369
370 if (widget)
371 {
372 if (GE_IS_COMBO_BOX (widget))
373 {
374 if (as_list)
375 result = (ge_combo_box_is_using_list(widget))?widget:NULL;
376 else
377 result = (!ge_combo_box_is_using_list(widget))?widget:NULL;
378 }
379 else
380 result = ge_find_combo_box_widget (widget->parent, as_list);
381 }
382 return result;
383 }
384
385 static GtkWidget *
ge_find_combo_widget(GtkWidget * widget)386 ge_find_combo_widget (GtkWidget * widget)
387 {
388 GtkWidget *result = NULL;
389
390 if (widget)
391 {
392 if (GE_IS_COMBO (widget))
393 result = widget;
394 else
395 result = ge_find_combo_widget(widget->parent);
396 }
397 return result;
398 }
399
400 GtkWidget*
ge_find_combo_box_widget_parent(GtkWidget * widget)401 ge_find_combo_box_widget_parent (GtkWidget * widget)
402 {
403 GtkWidget *result = NULL;
404
405 if (!result)
406 result = ge_find_combo_widget(widget);
407
408 if (!result)
409 result = ge_find_combo_box_widget(widget, TRUE);
410
411 if (!result)
412 result = ge_find_combo_box_entry_widget(widget);
413
414 return result;
415 }
416
417 /***********************************************
418 * option_menu_get_props -
419 *
420 * Find Option Menu Size and Spacing
421 *
422 * Taken from Smooth
423 ***********************************************/
424 void
ge_option_menu_get_props(GtkWidget * widget,GtkRequisition * indicator_size,GtkBorder * indicator_spacing)425 ge_option_menu_get_props (GtkWidget * widget,
426 GtkRequisition * indicator_size,
427 GtkBorder * indicator_spacing)
428 {
429 GtkRequisition default_size = { 9, 5 };
430 GtkBorder default_spacing = { 7, 5, 2, 2 };
431 GtkRequisition *tmp_size = NULL;
432 GtkBorder *tmp_spacing = NULL;
433
434 if ((widget) && GE_IS_OPTION_MENU(widget))
435 gtk_widget_style_get (widget,
436 "indicator_size", &tmp_size,
437 "indicator_spacing", &tmp_spacing, NULL);
438
439 if (tmp_size)
440 {
441 *indicator_size = *tmp_size;
442 gtk_requisition_free (tmp_size);
443 }
444 else
445 *indicator_size = default_size;
446
447 if (tmp_spacing)
448 {
449 *indicator_spacing = *tmp_spacing;
450 gtk_border_free (tmp_spacing);
451 }
452 else
453 *indicator_spacing = default_spacing;
454 }
455
456 void
ge_button_get_default_border(GtkWidget * widget,GtkBorder * border)457 ge_button_get_default_border (GtkWidget *widget,
458 GtkBorder *border)
459 {
460 GtkBorder default_border = {1, 1, 1, 1};
461 GtkBorder *tmp_border = NULL;
462
463 if (widget && GE_IS_BUTTON (widget))
464 gtk_widget_style_get (widget, "default-border", &tmp_border, NULL);
465
466 if (tmp_border)
467 {
468 *border = *tmp_border;
469 gtk_border_free (tmp_border);
470 }
471 else
472 {
473 *border = default_border;
474 }
475 }
476
477 gboolean
ge_widget_is_ltr(GtkWidget * widget)478 ge_widget_is_ltr (GtkWidget *widget)
479 {
480 GtkTextDirection dir = GTK_TEXT_DIR_NONE;
481
482 if (GE_IS_WIDGET (widget))
483 dir = gtk_widget_get_direction (widget);
484
485 if (dir == GTK_TEXT_DIR_NONE)
486 dir = gtk_widget_get_default_direction ();
487
488 if (dir == GTK_TEXT_DIR_RTL)
489 return FALSE;
490 else
491 return TRUE;
492 }
493
494 guint
ge_rc_parse_hint(GScanner * scanner,GQuark * quark)495 ge_rc_parse_hint (GScanner *scanner,
496 GQuark *quark)
497 {
498 guint token;
499
500 /* Skip 'hint' */
501 token = g_scanner_get_next_token(scanner);
502
503 token = g_scanner_get_next_token(scanner);
504 if (token != G_TOKEN_EQUAL_SIGN)
505 return G_TOKEN_EQUAL_SIGN;
506
507 token = g_scanner_get_next_token(scanner);
508 if (token != G_TOKEN_STRING)
509 return G_TOKEN_STRING;
510
511 *quark = g_quark_from_string (scanner->value.v_string);
512
513 return G_TOKEN_NONE;
514 }
515
516