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