]> Pileus Git - ~andy/gtk/blob - gtk/gtkwidgetpath.c
6fe08f558a99011e54bd606ca884310d2745d929
[~andy/gtk] / gtk / gtkwidgetpath.c
1 /* GTK - The GIMP Toolkit
2  * Copyright (C) 2010 Carlos Garnacho <carlosg@gnome.org>
3  *
4  * This library is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU Lesser General Public
6  * License as published by the Free Software Foundation; either
7  * version 2 of the License, or (at your option) any later version.
8  *
9  * This library is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12  * Lesser General Public License for more details.
13  *
14  * You should have received a copy of the GNU Lesser General Public
15  * License along with this library; if not, write to the
16  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
17  * Boston, MA 02111-1307, USA.
18  */
19
20 #include "config.h"
21
22 #include <string.h>
23
24 #include "gtkwidget.h"
25 #include "gtkwidgetpath.h"
26
27 typedef struct GtkPathElement GtkPathElement;
28
29 struct GtkPathElement
30 {
31   GType type;
32   GQuark name;
33   GHashTable *regions;
34   GArray *classes;
35 };
36
37 struct GtkWidgetPath
38 {
39   GArray *elems; /* First element contains the described widget */
40 };
41
42 GtkWidgetPath *
43 gtk_widget_path_new (void)
44 {
45   GtkWidgetPath *path;
46
47   path = g_slice_new0 (GtkWidgetPath);
48   path->elems = g_array_new (FALSE, TRUE, sizeof (GtkPathElement));
49
50   return path;
51 }
52
53 GtkWidgetPath *
54 gtk_widget_path_copy (const GtkWidgetPath *path)
55 {
56   GtkWidgetPath *new_path;
57   guint i;
58
59   g_return_val_if_fail (path != NULL, NULL);
60
61   new_path = gtk_widget_path_new ();
62
63   for (i = 0; i < path->elems->len; i++)
64     {
65       GtkPathElement *elem, new = { 0 };
66
67       elem = &g_array_index (path->elems, GtkPathElement, i);
68
69       new.type = elem->type;
70       new.name = elem->name;
71
72       if (elem->regions)
73         {
74           GHashTableIter iter;
75           gpointer key, value;
76
77           g_hash_table_iter_init (&iter, elem->regions);
78           new.regions = g_hash_table_new (NULL, NULL);
79
80           while (g_hash_table_iter_next (&iter, &key, &value))
81             g_hash_table_insert (new.regions, key, value);
82         }
83
84       g_array_append_val (new_path->elems, new);
85     }
86
87   return new_path;
88 }
89
90 void
91 gtk_widget_path_free (GtkWidgetPath *path)
92 {
93   guint i;
94
95   g_return_if_fail (path != NULL);
96
97   for (i = 0; i < path->elems->len; i++)
98     {
99       GtkPathElement *elem;
100
101       elem = &g_array_index (path->elems, GtkPathElement, i);
102
103       if (elem->regions)
104         g_hash_table_destroy (elem->regions);
105     }
106
107   g_array_free (path->elems, TRUE);
108   g_slice_free (GtkWidgetPath, path);
109 }
110
111 guint
112 gtk_widget_path_length (const GtkWidgetPath *path)
113 {
114   g_return_val_if_fail (path != NULL, 0);
115
116   return path->elems->len;
117 }
118
119 guint
120 gtk_widget_path_prepend_type (GtkWidgetPath *path,
121                               GType          type)
122 {
123   GtkPathElement new = { 0 };
124
125   g_return_val_if_fail (path != NULL, 0);
126   g_return_val_if_fail (g_type_is_a (type, GTK_TYPE_WIDGET), 0);
127
128   new.type = type;
129   g_array_append_val (path->elems, new);
130
131   return path->elems->len - 1;
132 }
133
134 GType
135 gtk_widget_path_iter_get_widget_type (const GtkWidgetPath *path,
136                                       guint                pos)
137 {
138   GtkPathElement *elem;
139
140   g_return_val_if_fail (path != NULL, G_TYPE_INVALID);
141   g_return_val_if_fail (pos < path->elems->len, G_TYPE_INVALID);
142
143   elem = &g_array_index (path->elems, GtkPathElement, pos);
144   return elem->type;
145 }
146
147 void
148 gtk_widget_path_iter_set_widget_type (GtkWidgetPath *path,
149                                       guint          pos,
150                                       GType          type)
151 {
152   GtkPathElement *elem;
153
154   g_return_if_fail (path != NULL);
155   g_return_if_fail (pos < path->elems->len);
156   g_return_if_fail (g_type_is_a (type, GTK_TYPE_WIDGET));
157
158   elem = &g_array_index (path->elems, GtkPathElement, pos);
159   elem->type = type;
160 }
161
162 G_CONST_RETURN gchar *
163 gtk_widget_path_iter_get_name (const GtkWidgetPath *path,
164                                guint                pos)
165 {
166   GtkPathElement *elem;
167
168   g_return_val_if_fail (path != NULL, NULL);
169   g_return_val_if_fail (pos < path->elems->len, NULL);
170
171   elem = &g_array_index (path->elems, GtkPathElement, pos);
172   return g_quark_to_string (elem->name);
173 }
174
175 void
176 gtk_widget_path_iter_set_name (GtkWidgetPath *path,
177                                guint          pos,
178                                const gchar   *name)
179 {
180   GtkPathElement *elem;
181
182   g_return_if_fail (path != NULL);
183   g_return_if_fail (pos < path->elems->len);
184   g_return_if_fail (name != NULL);
185
186   elem = &g_array_index (path->elems, GtkPathElement, pos);
187
188   elem->name = g_quark_from_string (name);
189 }
190
191 gboolean
192 gtk_widget_path_iter_has_qname (const GtkWidgetPath *path,
193                                 guint                pos,
194                                 GQuark               qname)
195 {
196   GtkPathElement *elem;
197
198   g_return_val_if_fail (path != NULL, FALSE);
199   g_return_val_if_fail (qname != 0, FALSE);
200   g_return_val_if_fail (pos < path->elems->len, FALSE);
201
202   elem = &g_array_index (path->elems, GtkPathElement, pos);
203
204   return (elem->name == qname);
205 }
206
207 gboolean
208 gtk_widget_path_iter_has_name (const GtkWidgetPath *path,
209                                guint                pos,
210                                const gchar         *name)
211 {
212   GQuark qname;
213
214   g_return_val_if_fail (path != NULL, FALSE);
215   g_return_val_if_fail (name != NULL, FALSE);
216   g_return_val_if_fail (pos < path->elems->len, FALSE);
217
218   qname = g_quark_try_string (name);
219
220   if (qname == 0)
221     return FALSE;
222
223   return gtk_widget_path_iter_has_qname (path, pos, qname);
224 }
225
226 void
227 gtk_widget_path_iter_add_class (GtkWidgetPath *path,
228                                 guint          pos,
229                                 const gchar   *name)
230 {
231   GtkPathElement *elem;
232   gboolean added = FALSE;
233   GQuark qname;
234   guint i;
235
236   g_return_if_fail (path != NULL);
237   g_return_if_fail (pos < path->elems->len);
238   g_return_if_fail (name != NULL);
239
240   elem = &g_array_index (path->elems, GtkPathElement, pos);
241   qname = g_quark_from_string (name);
242
243   if (!elem->classes)
244     elem->classes = g_array_new (FALSE, FALSE, sizeof (GQuark));
245
246   for (i = 0; i < elem->classes->len; i++)
247     {
248       GQuark quark;
249
250       quark = g_array_index (elem->classes, GQuark, i);
251
252       if (qname == quark)
253         {
254           /* Already there */
255           added = TRUE;
256           break;
257         }
258       if (qname < quark)
259         {
260           g_array_insert_val (elem->classes, i, qname);
261           added = TRUE;
262           break;
263         }
264     }
265
266   if (!added)
267     g_array_append_val (elem->classes, qname);
268 }
269
270 void
271 gtk_widget_path_iter_remove_class (GtkWidgetPath *path,
272                                    guint          pos,
273                                    const gchar   *name)
274 {
275   GtkPathElement *elem;
276   GQuark qname;
277   guint i;
278
279   g_return_if_fail (path != NULL);
280   g_return_if_fail (pos < path->elems->len);
281   g_return_if_fail (name != NULL);
282
283   qname = g_quark_try_string (name);
284
285   if (qname == 0)
286     return;
287
288   elem = &g_array_index (path->elems, GtkPathElement, pos);
289
290   if (!elem->classes)
291     return;
292
293   for (i = 0; i < elem->classes->len; i++)
294     {
295       GQuark quark;
296
297       quark = g_array_index (elem->classes, GQuark, i);
298
299       if (quark > qname)
300         break;
301       else if (quark == qname)
302         {
303           g_array_remove_index (elem->classes, i);
304           break;
305         }
306     }
307 }
308
309 void
310 gtk_widget_path_iter_clear_classes (GtkWidgetPath *path,
311                                     guint          pos)
312 {
313   GtkPathElement *elem;
314
315   g_return_if_fail (path != NULL);
316   g_return_if_fail (pos < path->elems->len);
317
318   elem = &g_array_index (path->elems, GtkPathElement, pos);
319
320   if (!elem->classes)
321     return;
322
323   if (elem->classes->len > 0)
324     g_array_remove_range (elem->classes, 0, elem->classes->len);
325 }
326
327 GSList *
328 gtk_widget_path_iter_list_classes (const GtkWidgetPath *path,
329                                    guint                pos)
330 {
331   GtkPathElement *elem;
332   GSList *list = NULL;
333   guint i;
334
335   g_return_val_if_fail (path != NULL, NULL);
336   g_return_val_if_fail (pos < path->elems->len, NULL);
337
338   elem = &g_array_index (path->elems, GtkPathElement, pos);
339
340   if (!elem->classes)
341     return NULL;
342
343   for (i = 0; i < elem->classes->len; i++)
344     {
345       GQuark quark;
346
347       quark = g_array_index (elem->classes, GQuark, i);
348       list = g_slist_prepend (list, (gchar *) g_quark_to_string (quark));
349     }
350
351   return g_slist_reverse (list);
352 }
353
354 gboolean
355 gtk_widget_path_iter_has_qclass (const GtkWidgetPath *path,
356                                  guint                pos,
357                                  GQuark               qname)
358 {
359   GtkPathElement *elem;
360   guint i;
361
362   g_return_val_if_fail (path != NULL, FALSE);
363   g_return_val_if_fail (pos < path->elems->len, FALSE);
364   g_return_val_if_fail (qname != 0, FALSE);
365
366   elem = &g_array_index (path->elems, GtkPathElement, pos);
367
368   if (!elem->classes)
369     return FALSE;
370
371   for (i = 0; i < elem->classes->len; i++)
372     {
373       GQuark quark;
374
375       quark = g_array_index (elem->classes, GQuark, i);
376
377       if (quark == qname)
378         return TRUE;
379       else if (quark > qname)
380         break;
381     }
382
383   return FALSE;
384 }
385
386 gboolean
387 gtk_widget_path_iter_has_class (const GtkWidgetPath *path,
388                                 guint                pos,
389                                 const gchar         *name)
390 {
391   GQuark qname;
392
393   g_return_val_if_fail (path != NULL, FALSE);
394   g_return_val_if_fail (pos < path->elems->len, FALSE);
395   g_return_val_if_fail (name != NULL, FALSE);
396
397   qname = g_quark_try_string (name);
398
399   if (qname == 0)
400     return FALSE;
401
402   return gtk_widget_path_iter_has_qclass (path, pos, qname);
403 }
404
405 void
406 gtk_widget_path_iter_add_region (GtkWidgetPath  *path,
407                                  guint           pos,
408                                  const gchar    *name,
409                                  GtkRegionFlags  flags)
410 {
411   GtkPathElement *elem;
412   GQuark qname;
413
414   g_return_if_fail (path != NULL);
415   g_return_if_fail (pos < path->elems->len);
416   g_return_if_fail (name != NULL);
417
418   elem = &g_array_index (path->elems, GtkPathElement, pos);
419   qname = g_quark_from_string (name);
420
421   if (!elem->regions)
422     elem->regions = g_hash_table_new (NULL, NULL);
423
424   g_hash_table_insert (elem->regions,
425                        GUINT_TO_POINTER (qname),
426                        GUINT_TO_POINTER (flags));
427 }
428
429 void
430 gtk_widget_path_iter_remove_region (GtkWidgetPath *path,
431                                     guint          pos,
432                                     const gchar   *name)
433 {
434   GtkPathElement *elem;
435   GQuark qname;
436
437   g_return_if_fail (path != NULL);
438   g_return_if_fail (pos < path->elems->len);
439   g_return_if_fail (name != NULL);
440
441   qname = g_quark_try_string (name);
442
443   if (qname == 0)
444     return;
445
446   elem = &g_array_index (path->elems, GtkPathElement, pos);
447
448   if (elem->regions)
449     g_hash_table_remove (elem->regions, GUINT_TO_POINTER (qname));
450 }
451
452 void
453 gtk_widget_path_iter_clear_regions (GtkWidgetPath *path,
454                                     guint          pos)
455 {
456   GtkPathElement *elem;
457
458   g_return_if_fail (path != NULL);
459   g_return_if_fail (pos < path->elems->len);
460
461   elem = &g_array_index (path->elems, GtkPathElement, pos);
462
463   if (elem->regions)
464     g_hash_table_remove_all (elem->regions);
465 }
466
467 GSList *
468 gtk_widget_path_iter_list_regions (const GtkWidgetPath *path,
469                                    guint                pos)
470 {
471   GtkPathElement *elem;
472   GHashTableIter iter;
473   GSList *list = NULL;
474   gpointer key;
475
476   g_return_val_if_fail (path != NULL, NULL);
477   g_return_val_if_fail (pos < path->elems->len, NULL);
478
479   elem = &g_array_index (path->elems, GtkPathElement, pos);
480
481   if (!elem->regions)
482     return NULL;
483
484   g_hash_table_iter_init (&iter, elem->regions);
485
486   while (g_hash_table_iter_next (&iter, &key, NULL))
487     {
488       GQuark qname;
489
490       qname = GPOINTER_TO_UINT (key);
491       list = g_slist_prepend (list, (gchar *) g_quark_to_string (qname));
492     }
493
494   return list;
495 }
496
497 gboolean
498 gtk_widget_path_iter_has_qregion (const GtkWidgetPath *path,
499                                   guint                pos,
500                                   GQuark               qname,
501                                   GtkRegionFlags      *flags)
502 {
503   GtkPathElement *elem;
504   gpointer value;
505
506   g_return_val_if_fail (path != NULL, FALSE);
507   g_return_val_if_fail (pos < path->elems->len, FALSE);
508   g_return_val_if_fail (qname != 0, FALSE);
509
510   elem = &g_array_index (path->elems, GtkPathElement, pos);
511
512   if (!elem->regions)
513     return FALSE;
514
515   if (!g_hash_table_lookup_extended (elem->regions,
516                                      GUINT_TO_POINTER (qname),
517                                      NULL, &value))
518     return FALSE;
519
520   if (flags)
521     *flags = GPOINTER_TO_UINT (value);
522
523   return TRUE;
524 }
525
526 gboolean
527 gtk_widget_path_iter_has_region (const GtkWidgetPath *path,
528                                  guint                pos,
529                                  const gchar         *name,
530                                  GtkRegionFlags      *flags)
531 {
532   GQuark qname;
533
534   g_return_val_if_fail (path != NULL, FALSE);
535   g_return_val_if_fail (pos < path->elems->len, FALSE);
536   g_return_val_if_fail (name != NULL, FALSE);
537
538   qname = g_quark_try_string (name);
539
540   if (qname == 0)
541     return FALSE;
542
543   return gtk_widget_path_iter_has_qregion (path, pos, qname, flags);
544 }
545
546 GType
547 gtk_widget_path_get_widget_type (const GtkWidgetPath *path)
548 {
549   GtkPathElement *elem;
550
551   g_return_val_if_fail (path != NULL, G_TYPE_INVALID);
552
553   elem = &g_array_index (path->elems, GtkPathElement, 0);
554   return elem->type;
555 }
556
557 gboolean
558 gtk_widget_path_is_type (const GtkWidgetPath *path,
559                          GType                type)
560 {
561   GtkPathElement *elem;
562
563   g_return_val_if_fail (path != NULL, FALSE);
564   g_return_val_if_fail (g_type_is_a (type, GTK_TYPE_WIDGET), FALSE);
565
566   elem = &g_array_index (path->elems, GtkPathElement, 0);
567
568   if (elem->type == type ||
569       g_type_is_a (elem->type, type))
570     return TRUE;
571
572   return FALSE;
573 }
574
575 gboolean
576 gtk_widget_path_has_parent (const GtkWidgetPath *path,
577                             GType                type)
578 {
579   guint i;
580
581   g_return_val_if_fail (path != NULL, FALSE);
582   g_return_val_if_fail (g_type_is_a (type, GTK_TYPE_WIDGET), FALSE);
583
584   for (i = 1; i < path->elems->len; i++)
585     {
586       GtkPathElement *elem;
587
588       elem = &g_array_index (path->elems, GtkPathElement, i);
589
590       if (elem->type == type ||
591           g_type_is_a (elem->type, type))
592         return TRUE;
593     }
594
595   return FALSE;
596 }
597
598 #define __GTK_WIDGET_PATH_C__
599 #include "gtkaliasdef.c"