File: | cafemenu-tree.c |
Warning: | line 832, column 12 This statement is never executed |
Press '?' to see keyboard shortcuts
Keyboard shortcuts:
1 | /* |
2 | * Copyright (C) 2003, 2004 Red Hat, Inc. |
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., 51 Franklin St, Fifth Floor, |
17 | * Boston, MA 02110-1301, USA. |
18 | */ |
19 | |
20 | #include <config.h> |
21 | |
22 | #include "cafemenu-tree.h" |
23 | |
24 | #include <gio/gio.h> |
25 | #include <string.h> |
26 | #include <errno(*__errno_location ()).h> |
27 | #include <stdlib.h> |
28 | |
29 | #include "menu-layout.h" |
30 | #include "menu-monitor.h" |
31 | #include "menu-util.h" |
32 | |
33 | /* private */ |
34 | typedef struct CafeMenuTreeItem CafeMenuTreeItem; |
35 | #define CAFEMENU_TREE_ITEM(i)((CafeMenuTreeItem *)(i)) ((CafeMenuTreeItem *)(i)) |
36 | #define CAFEMENU_TREE_DIRECTORY(i)((CafeMenuTreeDirectory *)(i)) ((CafeMenuTreeDirectory *)(i)) |
37 | #define CAFEMENU_TREE_ENTRY(i)((CafeMenuTreeEntry *)(i)) ((CafeMenuTreeEntry *)(i)) |
38 | #define CAFEMENU_TREE_SEPARATOR(i)((CafeMenuTreeSeparator *)(i)) ((CafeMenuTreeSeparator *)(i)) |
39 | #define CAFEMENU_TREE_HEADER(i)((CafeMenuTreeHeader *)(i)) ((CafeMenuTreeHeader *)(i)) |
40 | #define CAFEMENU_TREE_ALIAS(i)((CafeMenuTreeAlias *)(i)) ((CafeMenuTreeAlias *)(i)) |
41 | |
42 | enum { |
43 | PROP_0, |
44 | |
45 | PROP_MENU_BASENAME, |
46 | PROP_MENU_PATH, |
47 | PROP_FLAGS |
48 | }; |
49 | |
50 | /* Signals */ |
51 | enum |
52 | { |
53 | CHANGED, |
54 | LAST_SIGNAL |
55 | }; |
56 | |
57 | static guint cafemenu_tree_signals [LAST_SIGNAL] = { 0 }; |
58 | |
59 | struct _CafeMenuTree |
60 | { |
61 | GObject parent_instance; |
62 | |
63 | char *basename; |
64 | char *non_prefixed_basename; |
65 | char *path; |
66 | char *canonical_path; |
67 | |
68 | CafeMenuTreeFlags flags; |
69 | |
70 | GSList *menu_file_monitors; |
71 | |
72 | MenuLayoutNode *layout; |
73 | CafeMenuTreeDirectory *root; |
74 | GHashTable *entries_by_id; |
75 | |
76 | guint canonical : 1; |
77 | guint loaded : 1; |
78 | }; |
79 | |
80 | G_DEFINE_TYPE (CafeMenuTree, cafemenu_tree, G_TYPE_OBJECT)static void cafemenu_tree_init (CafeMenuTree *self); static void cafemenu_tree_class_init (CafeMenuTreeClass *klass); static GType cafemenu_tree_get_type_once (void); static gpointer cafemenu_tree_parent_class = ((void*)0); static gint CafeMenuTree_private_offset; static void cafemenu_tree_class_intern_init (gpointer klass) { cafemenu_tree_parent_class = g_type_class_peek_parent (klass); if (CafeMenuTree_private_offset != 0) g_type_class_adjust_private_offset (klass, &CafeMenuTree_private_offset ); cafemenu_tree_class_init ((CafeMenuTreeClass*) klass); } __attribute__ ((__unused__)) static inline gpointer cafemenu_tree_get_instance_private (CafeMenuTree *self) { return (((gpointer) ((guint8*) (self) + (glong) (CafeMenuTree_private_offset)))); } GType cafemenu_tree_get_type (void) { static GType static_g_define_type_id = 0; if ((__extension__ ({ _Static_assert (sizeof *(&static_g_define_type_id) == sizeof (gpointer), "Expression evaluates to false"); (void) ( 0 ? (gpointer) * (&static_g_define_type_id) : ((void*)0)) ; (!(__extension__ ({ _Static_assert (sizeof *(&static_g_define_type_id ) == sizeof (gpointer), "Expression evaluates to false"); __typeof__ (*(&static_g_define_type_id)) gapg_temp_newval; __typeof__ ((&static_g_define_type_id)) gapg_temp_atomic = (&static_g_define_type_id ); __atomic_load (gapg_temp_atomic, &gapg_temp_newval, 5) ; gapg_temp_newval; })) && g_once_init_enter_pointer ( &static_g_define_type_id)); })) ) { GType g_define_type_id = cafemenu_tree_get_type_once (); (__extension__ ({ _Static_assert (sizeof *(&static_g_define_type_id) == sizeof (gpointer) , "Expression evaluates to false"); 0 ? (void) (*(&static_g_define_type_id ) = (g_define_type_id)) : (void) 0; g_once_init_leave_pointer ((&static_g_define_type_id), (gpointer) (guintptr) (g_define_type_id )); })) ; } return static_g_define_type_id; } __attribute__ ( (__noinline__)) static GType cafemenu_tree_get_type_once (void ) { GType g_define_type_id = g_type_register_static_simple (( (GType) ((20) << (2))), g_intern_static_string ("CafeMenuTree" ), sizeof (CafeMenuTreeClass), (GClassInitFunc)(void (*)(void )) cafemenu_tree_class_intern_init, sizeof (CafeMenuTree), (GInstanceInitFunc )(void (*)(void)) cafemenu_tree_init, (GTypeFlags) 0); { {{}; } } return g_define_type_id; } |
81 | |
82 | struct CafeMenuTreeItem |
83 | { |
84 | volatile gint refcount; |
85 | |
86 | CafeMenuTreeItemType type; |
87 | |
88 | CafeMenuTreeDirectory *parent; |
89 | CafeMenuTree *tree; |
90 | }; |
91 | |
92 | struct CafeMenuTreeIter |
93 | { |
94 | volatile gint refcount; |
95 | |
96 | CafeMenuTreeItem *item; |
97 | GSList *contents; |
98 | GSList *contents_iter; |
99 | }; |
100 | |
101 | struct CafeMenuTreeDirectory |
102 | { |
103 | CafeMenuTreeItem item; |
104 | |
105 | DesktopEntry *directory_entry; |
106 | char *name; |
107 | |
108 | GSList *entries; |
109 | GSList *subdirs; |
110 | |
111 | MenuLayoutValues default_layout_values; |
112 | GSList *default_layout_info; |
113 | GSList *layout_info; |
114 | GSList *contents; |
115 | |
116 | guint only_unallocated : 1; |
117 | guint is_nodisplay : 1; |
118 | guint layout_pending_separator : 1; |
119 | guint preprocessed : 1; |
120 | |
121 | /* 16 bits should be more than enough; G_MAXUINT16 means no inline header */ |
122 | guint will_inline_header : 16; |
123 | }; |
124 | |
125 | struct CafeMenuTreeEntry |
126 | { |
127 | CafeMenuTreeItem item; |
128 | |
129 | DesktopEntry *desktop_entry; |
130 | char *desktop_file_id; |
131 | |
132 | guint is_excluded : 1; |
133 | guint is_unallocated : 1; |
134 | }; |
135 | |
136 | struct CafeMenuTreeSeparator |
137 | { |
138 | CafeMenuTreeItem item; |
139 | }; |
140 | |
141 | struct CafeMenuTreeHeader |
142 | { |
143 | CafeMenuTreeItem item; |
144 | |
145 | CafeMenuTreeDirectory *directory; |
146 | }; |
147 | |
148 | struct CafeMenuTreeAlias |
149 | { |
150 | CafeMenuTreeItem item; |
151 | |
152 | CafeMenuTreeDirectory *directory; |
153 | CafeMenuTreeItem *aliased_item; |
154 | }; |
155 | |
156 | static gboolean cafemenu_tree_load_layout (CafeMenuTree *tree, |
157 | GError **error); |
158 | static void cafemenu_tree_force_reload (CafeMenuTree *tree); |
159 | static gboolean cafemenu_tree_build_from_layout (CafeMenuTree *tree, |
160 | GError **error); |
161 | static void cafemenu_tree_force_rebuild (CafeMenuTree *tree); |
162 | static void cafemenu_tree_resolve_files (CafeMenuTree *tree, |
163 | GHashTable *loaded_menu_files, |
164 | MenuLayoutNode *layout); |
165 | static void cafemenu_tree_force_recanonicalize (CafeMenuTree *tree); |
166 | static void cafemenu_tree_invoke_monitors (CafeMenuTree *tree); |
167 | |
168 | static void cafemenu_tree_item_unref_and_unset_parent (gpointer itemp); |
169 | |
170 | typedef enum |
171 | { |
172 | MENU_FILE_MONITOR_INVALID = 0, |
173 | MENU_FILE_MONITOR_FILE, |
174 | MENU_FILE_MONITOR_NONEXISTENT_FILE, |
175 | MENU_FILE_MONITOR_DIRECTORY |
176 | } MenuFileMonitorType; |
177 | |
178 | typedef struct |
179 | { |
180 | MenuFileMonitorType type; |
181 | MenuMonitor *monitor; |
182 | } MenuFileMonitor; |
183 | |
184 | static void |
185 | handle_nonexistent_menu_file_changed (MenuMonitor *monitor G_GNUC_UNUSED__attribute__ ((__unused__)), |
186 | MenuMonitorEvent event, |
187 | const char *path G_GNUC_UNUSED__attribute__ ((__unused__)), |
188 | CafeMenuTree *tree) |
189 | { |
190 | if (event == MENU_MONITOR_EVENT_CHANGED || |
191 | event == MENU_MONITOR_EVENT_CREATED) |
192 | { |
193 | menu_verbose ("\"%s\" %s, marking tree for recanonicalization\n", |
194 | path, |
195 | event == MENU_MONITOR_EVENT_CREATED ? "created" : "changed"); |
196 | |
197 | cafemenu_tree_force_recanonicalize (tree); |
198 | cafemenu_tree_invoke_monitors (tree); |
199 | } |
200 | } |
201 | |
202 | static void |
203 | handle_menu_file_changed (MenuMonitor *monitor G_GNUC_UNUSED__attribute__ ((__unused__)), |
204 | MenuMonitorEvent event G_GNUC_UNUSED__attribute__ ((__unused__)), |
205 | const char *path G_GNUC_UNUSED__attribute__ ((__unused__)), |
206 | CafeMenuTree *tree) |
207 | { |
208 | menu_verbose ("\"%s\" %s, marking tree for recanicalization\n", |
209 | path, |
210 | event == MENU_MONITOR_EVENT_CREATED ? "created" : |
211 | event == MENU_MONITOR_EVENT_CHANGED ? "changed" : "deleted"); |
212 | |
213 | cafemenu_tree_force_recanonicalize (tree); |
214 | cafemenu_tree_invoke_monitors (tree); |
215 | } |
216 | |
217 | static void |
218 | handle_menu_file_directory_changed (MenuMonitor *monitor G_GNUC_UNUSED__attribute__ ((__unused__)), |
219 | MenuMonitorEvent event G_GNUC_UNUSED__attribute__ ((__unused__)), |
220 | const char *path, |
221 | CafeMenuTree *tree) |
222 | { |
223 | if (!g_str_has_suffix (path, ".menu")(__builtin_constant_p (".menu")? __extension__ ({ const char * const __str = (path); const char * const __suffix = (".menu" ); gboolean __result = (0); if (__str == ((void*)0) || __suffix == ((void*)0)) __result = (g_str_has_suffix) (__str, __suffix ); else { const size_t __str_len = strlen (((__str) + !(__str ))); const size_t __suffix_len = strlen (((__suffix) + !(__suffix ))); if (__str_len >= __suffix_len) __result = memcmp (__str + __str_len - __suffix_len, ((__suffix) + !(__suffix)), __suffix_len ) == 0; } __result; }) : (g_str_has_suffix) (path, ".menu") )) |
224 | return; |
225 | |
226 | menu_verbose ("\"%s\" %s, marking tree for recanicalization\n", |
227 | path, |
228 | event == MENU_MONITOR_EVENT_CREATED ? "created" : |
229 | event == MENU_MONITOR_EVENT_CHANGED ? "changed" : "deleted"); |
230 | |
231 | cafemenu_tree_force_recanonicalize (tree); |
232 | cafemenu_tree_invoke_monitors (tree); |
233 | } |
234 | |
235 | static void |
236 | cafemenu_tree_add_menu_file_monitor (CafeMenuTree *tree, |
237 | const char *path, |
238 | MenuFileMonitorType type) |
239 | { |
240 | MenuFileMonitor *monitor; |
241 | |
242 | monitor = g_slice_new0 (MenuFileMonitor)((MenuFileMonitor*) g_slice_alloc0 (sizeof (MenuFileMonitor)) ); |
243 | |
244 | monitor->type = type; |
245 | |
246 | switch (type) |
247 | { |
248 | case MENU_FILE_MONITOR_FILE: |
249 | menu_verbose ("Adding a menu file monitor for \"%s\"\n", path); |
250 | |
251 | monitor->monitor = menu_get_file_monitor (path); |
252 | menu_monitor_add_notify (monitor->monitor, |
253 | (MenuMonitorNotifyFunc) handle_menu_file_changed, |
254 | tree); |
255 | break; |
256 | |
257 | case MENU_FILE_MONITOR_NONEXISTENT_FILE: |
258 | menu_verbose ("Adding a menu file monitor for non-existent \"%s\"\n", path); |
259 | |
260 | monitor->monitor = menu_get_file_monitor (path); |
261 | menu_monitor_add_notify (monitor->monitor, |
262 | (MenuMonitorNotifyFunc) handle_nonexistent_menu_file_changed, |
263 | tree); |
264 | break; |
265 | |
266 | case MENU_FILE_MONITOR_DIRECTORY: |
267 | menu_verbose ("Adding a menu directory monitor for \"%s\"\n", path); |
268 | |
269 | monitor->monitor = menu_get_directory_monitor (path); |
270 | menu_monitor_add_notify (monitor->monitor, |
271 | (MenuMonitorNotifyFunc) handle_menu_file_directory_changed, |
272 | tree); |
273 | break; |
274 | |
275 | default: |
276 | g_assert_not_reached ()do { g_assertion_message_expr (((gchar*) 0), "cafemenu-tree.c" , 276, ((const char*) (__func__)), ((void*)0)); } while (0); |
277 | break; |
278 | } |
279 | |
280 | tree->menu_file_monitors = g_slist_prepend (tree->menu_file_monitors, monitor); |
281 | } |
282 | |
283 | static void |
284 | remove_menu_file_monitor (MenuFileMonitor *monitor, |
285 | CafeMenuTree *tree) |
286 | { |
287 | switch (monitor->type) |
288 | { |
289 | case MENU_FILE_MONITOR_FILE: |
290 | menu_monitor_remove_notify (monitor->monitor, |
291 | (MenuMonitorNotifyFunc) handle_menu_file_changed, |
292 | tree); |
293 | break; |
294 | |
295 | case MENU_FILE_MONITOR_NONEXISTENT_FILE: |
296 | menu_monitor_remove_notify (monitor->monitor, |
297 | (MenuMonitorNotifyFunc) handle_nonexistent_menu_file_changed, |
298 | tree); |
299 | break; |
300 | |
301 | case MENU_FILE_MONITOR_DIRECTORY: |
302 | menu_monitor_remove_notify (monitor->monitor, |
303 | (MenuMonitorNotifyFunc) handle_menu_file_directory_changed, |
304 | tree); |
305 | break; |
306 | |
307 | default: |
308 | g_assert_not_reached ()do { g_assertion_message_expr (((gchar*) 0), "cafemenu-tree.c" , 308, ((const char*) (__func__)), ((void*)0)); } while (0); |
309 | break; |
310 | } |
311 | |
312 | menu_monitor_unref (monitor->monitor); |
313 | monitor->monitor = NULL((void*)0); |
314 | |
315 | monitor->type = MENU_FILE_MONITOR_INVALID; |
316 | |
317 | g_slice_free (MenuFileMonitor, monitor)do { if (1) g_slice_free1 (sizeof (MenuFileMonitor), (monitor )); else (void) ((MenuFileMonitor*) 0 == (monitor)); } while ( 0); |
318 | } |
319 | |
320 | static void |
321 | cafemenu_tree_remove_menu_file_monitors (CafeMenuTree *tree) |
322 | { |
323 | menu_verbose ("Removing all menu file monitors\n"); |
324 | |
325 | g_slist_foreach (tree->menu_file_monitors, |
326 | (GFunc) remove_menu_file_monitor, |
327 | tree); |
328 | g_slist_free (tree->menu_file_monitors); |
329 | tree->menu_file_monitors = NULL((void*)0); |
330 | } |
331 | |
332 | static gboolean |
333 | canonicalize_path (CafeMenuTree *tree, |
334 | const char *path) |
335 | { |
336 | tree->canonical_path = realpath (path, NULL((void*)0)); |
337 | if (tree->canonical_path) |
338 | { |
339 | tree->canonical = TRUE(!(0)); |
340 | cafemenu_tree_add_menu_file_monitor (tree, |
341 | tree->canonical_path, |
342 | MENU_FILE_MONITOR_FILE); |
343 | } |
344 | else |
345 | { |
346 | cafemenu_tree_add_menu_file_monitor (tree, |
347 | path, |
348 | MENU_FILE_MONITOR_NONEXISTENT_FILE); |
349 | } |
350 | |
351 | return tree->canonical; |
352 | } |
353 | |
354 | static gboolean |
355 | canonicalize_basename_with_config_dir (CafeMenuTree *tree, |
356 | const char *basename, |
357 | const char *config_dir) |
358 | { |
359 | gboolean ret; |
360 | char *path; |
361 | |
362 | path = g_build_filename (config_dir, "menus", basename, NULL((void*)0)); |
363 | ret = canonicalize_path (tree, path); |
364 | g_free (path); |
365 | |
366 | return ret; |
367 | } |
368 | |
369 | static void |
370 | canonicalize_basename (CafeMenuTree *tree, |
371 | const char *basename) |
372 | { |
373 | if (!canonicalize_basename_with_config_dir (tree, |
374 | basename, |
375 | g_get_user_config_dir ())) |
376 | { |
377 | const char * const *system_config_dirs; |
378 | int i; |
379 | |
380 | system_config_dirs = g_get_system_config_dirs (); |
381 | |
382 | i = 0; |
383 | while (system_config_dirs[i] != NULL((void*)0)) |
384 | { |
385 | if (canonicalize_basename_with_config_dir (tree, |
386 | basename, |
387 | system_config_dirs[i])) |
388 | break; |
389 | |
390 | ++i; |
391 | } |
392 | } |
393 | } |
394 | |
395 | static gboolean cafemenu_tree_canonicalize_path(CafeMenuTree* tree, |
396 | GError **error) |
397 | { |
398 | const char *menu_file = NULL((void*)0); |
399 | |
400 | if (tree->canonical) |
401 | return TRUE(!(0)); |
402 | |
403 | g_assert(tree->canonical_path == NULL)do { if (tree->canonical_path == ((void*)0)) ; else g_assertion_message_expr (((gchar*) 0), "cafemenu-tree.c", 403, ((const char*) (__func__ )), "tree->canonical_path == NULL"); } while (0); |
404 | |
405 | cafemenu_tree_remove_menu_file_monitors (tree); |
406 | |
407 | if (tree->path) |
408 | { |
409 | menu_file = tree->path; |
410 | canonicalize_path (tree, tree->path); |
411 | } |
412 | else |
413 | { |
414 | const gchar *xdg_menu_prefix; |
415 | |
416 | menu_file = tree->basename; |
417 | xdg_menu_prefix = g_getenv ("XDG_MENU_PREFIX"); |
418 | |
419 | if (xdg_menu_prefix != NULL((void*)0)) |
420 | { |
421 | gchar *prefixed_basename; |
422 | |
423 | prefixed_basename = g_strdup_printf ("%sapplications.menu", |
424 | xdg_menu_prefix); |
425 | |
426 | /* Some gnome-menus using applications just use "applications.menu" |
427 | * as the basename and expect gnome-menus to prefix it. Others (e.g. |
428 | * Alacarte) explicitly use "${XDG_MENU_PREFIX}applications.menu" as |
429 | * the basename, because they want to save changes to the right files |
430 | * in ~. In both cases, we want to use "applications-merged" as the |
431 | * merge directory (as required by the fd.o menu spec), so we save |
432 | * the non-prefixed basename and use it later when calling |
433 | * menu_layout_load(). |
434 | */ |
435 | if (!g_strcmp0 (tree->basename, "cafe-applications.menu") || |
436 | !g_strcmp0 (tree->basename, prefixed_basename)) |
437 | { |
438 | canonicalize_basename (tree, prefixed_basename); |
439 | g_free (tree->non_prefixed_basename); |
440 | tree->non_prefixed_basename = g_strdup ("cafe-applications.menu")g_strdup_inline ("cafe-applications.menu"); |
441 | } |
442 | g_free (prefixed_basename); |
443 | } |
444 | |
445 | if (!tree->canonical) |
446 | canonicalize_basename (tree, tree->basename); |
447 | } |
448 | |
449 | if (tree->canonical) |
450 | { |
451 | menu_verbose ("Successfully looked up menu_file for \"%s\": %s\n", |
452 | menu_file, tree->canonical_path); |
453 | return TRUE(!(0)); |
454 | } |
455 | else |
456 | { |
457 | g_set_error (error, |
458 | G_IO_ERRORg_io_error_quark(), |
459 | G_IO_ERROR_FAILED, |
460 | "Failed to look up menu_file for \"%s\"\n", |
461 | menu_file); |
462 | return FALSE(0); |
463 | } |
464 | } |
465 | |
466 | static void |
467 | cafemenu_tree_force_recanonicalize (CafeMenuTree *tree) |
468 | { |
469 | cafemenu_tree_remove_menu_file_monitors (tree); |
470 | |
471 | if (tree->canonical) |
472 | { |
473 | cafemenu_tree_force_reload (tree); |
474 | |
475 | g_free (tree->canonical_path); |
476 | tree->canonical_path = NULL((void*)0); |
477 | |
478 | tree->canonical = FALSE(0); |
479 | } |
480 | } |
481 | |
482 | /** |
483 | * cafemenu_tree_new: |
484 | * @menu_basename: Basename of menu file |
485 | * @flags: Flags controlling menu content |
486 | * |
487 | * Returns: (transfer full): A new #CafeMenuTree instance |
488 | */ |
489 | CafeMenuTree * |
490 | cafemenu_tree_new (const char *menu_basename, |
491 | CafeMenuTreeFlags flags) |
492 | { |
493 | g_return_val_if_fail (menu_basename != NULL, NULL)do { if ((menu_basename != ((void*)0))) { } else { g_return_if_fail_warning (((gchar*) 0), ((const char*) (__func__)), "menu_basename != NULL" ); return (((void*)0)); } } while (0); |
494 | |
495 | return g_object_new (CAFEMENU_TYPE_TREE(cafemenu_tree_get_type ()), |
496 | "menu-basename", menu_basename, |
497 | "flags", flags, |
498 | NULL((void*)0)); |
499 | } |
500 | |
501 | /** |
502 | * cafemenu_tree_new_fo_path: |
503 | * @menu_path: Path of menu file |
504 | * @flags: Flags controlling menu content |
505 | * |
506 | * Returns: (transfer full): A new #CafeMenuTree instance |
507 | */ |
508 | CafeMenuTree * |
509 | cafemenu_tree_new_for_path (const char *menu_path, |
510 | CafeMenuTreeFlags flags) |
511 | { |
512 | g_return_val_if_fail (menu_path != NULL, NULL)do { if ((menu_path != ((void*)0))) { } else { g_return_if_fail_warning (((gchar*) 0), ((const char*) (__func__)), "menu_path != NULL" ); return (((void*)0)); } } while (0); |
513 | |
514 | return g_object_new (CAFEMENU_TYPE_TREE(cafemenu_tree_get_type ()), |
515 | "menu-path", menu_path, |
516 | "flags", flags, |
517 | NULL((void*)0)); |
518 | } |
519 | |
520 | static GObject * |
521 | cafemenu_tree_constructor (GType type, |
522 | guint n_construct_properties, |
523 | GObjectConstructParam *construct_properties) |
524 | { |
525 | GObject *obj; |
526 | CafeMenuTree *self; |
527 | |
528 | obj = G_OBJECT_CLASS (cafemenu_tree_parent_class)((((GObjectClass*) (void *) g_type_check_class_cast ((GTypeClass *) ((cafemenu_tree_parent_class)), (((GType) ((20) << ( 2))))))))->constructor (type, |
529 | n_construct_properties, |
530 | construct_properties); |
531 | |
532 | /* If CafeMenuTree:menu-path is set, then we should make sure that |
533 | * CafeMenuTree:menu-basename is unset (especially as it has a default |
534 | * value). This has to be done here, in the constructor, since the |
535 | * properties are construct-only. */ |
536 | |
537 | self = CAFEMENU_TREE (obj)((((CafeMenuTree*) (void *) g_type_check_instance_cast ((GTypeInstance *) ((obj)), ((cafemenu_tree_get_type ())))))); |
538 | |
539 | if (self->path != NULL((void*)0)) |
540 | g_object_set (self, "menu-basename", NULL((void*)0), NULL((void*)0)); |
541 | |
542 | return obj; |
543 | } |
544 | |
545 | static void |
546 | cafemenu_tree_set_property (GObject *object, |
547 | guint prop_id, |
548 | const GValue *value, |
549 | GParamSpec *pspec) |
550 | { |
551 | CafeMenuTree *self = CAFEMENU_TREE (object)((((CafeMenuTree*) (void *) g_type_check_instance_cast ((GTypeInstance *) ((object)), ((cafemenu_tree_get_type ())))))); |
552 | |
553 | switch (prop_id) |
554 | { |
555 | case PROP_MENU_BASENAME: |
556 | self->basename = g_value_dup_string (value); |
557 | break; |
558 | |
559 | case PROP_MENU_PATH: |
560 | self->path = g_value_dup_string (value); |
561 | break; |
562 | |
563 | case PROP_FLAGS: |
564 | self->flags = g_value_get_flags (value); |
565 | break; |
566 | |
567 | default: |
568 | G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec)do { GObject *_glib__object = (GObject*) ((object)); GParamSpec *_glib__pspec = (GParamSpec*) ((pspec)); guint _glib__property_id = ((prop_id)); g_warning ("%s:%d: invalid %s id %u for \"%s\" of type '%s' in '%s'" , "cafemenu-tree.c", 568, ("property"), _glib__property_id, _glib__pspec ->name, g_type_name ((((((GTypeClass*) (((GTypeInstance*) ( _glib__pspec))->g_class))->g_type)))), (g_type_name ((( (((GTypeClass*) (((GTypeInstance*) (_glib__object))->g_class ))->g_type)))))); } while (0); |
569 | break; |
570 | } |
571 | } |
572 | |
573 | static void |
574 | cafemenu_tree_get_property (GObject *object, |
575 | guint prop_id, |
576 | GValue *value, |
577 | GParamSpec *pspec) |
578 | { |
579 | CafeMenuTree *self = CAFEMENU_TREE (object)((((CafeMenuTree*) (void *) g_type_check_instance_cast ((GTypeInstance *) ((object)), ((cafemenu_tree_get_type ())))))); |
580 | |
581 | switch (prop_id) |
582 | { |
583 | case PROP_MENU_BASENAME: |
584 | g_value_set_string (value, self->basename); |
585 | break; |
586 | case PROP_MENU_PATH: |
587 | g_value_set_string (value, self->path); |
588 | break; |
589 | case PROP_FLAGS: |
590 | g_value_set_flags (value, self->flags); |
591 | break; |
592 | default: |
593 | G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec)do { GObject *_glib__object = (GObject*) ((object)); GParamSpec *_glib__pspec = (GParamSpec*) ((pspec)); guint _glib__property_id = ((prop_id)); g_warning ("%s:%d: invalid %s id %u for \"%s\" of type '%s' in '%s'" , "cafemenu-tree.c", 593, ("property"), _glib__property_id, _glib__pspec ->name, g_type_name ((((((GTypeClass*) (((GTypeInstance*) ( _glib__pspec))->g_class))->g_type)))), (g_type_name ((( (((GTypeClass*) (((GTypeInstance*) (_glib__object))->g_class ))->g_type)))))); } while (0); |
594 | break; |
595 | } |
596 | } |
597 | |
598 | static void |
599 | cafemenu_tree_finalize (GObject *object) |
600 | { |
601 | CafeMenuTree *tree = CAFEMENU_TREE (object)((((CafeMenuTree*) (void *) g_type_check_instance_cast ((GTypeInstance *) ((object)), ((cafemenu_tree_get_type ())))))); |
602 | |
603 | cafemenu_tree_force_recanonicalize (tree); |
604 | |
605 | if (tree->basename != NULL((void*)0)) |
606 | g_free (tree->basename); |
607 | tree->basename = NULL((void*)0); |
608 | |
609 | g_free (tree->non_prefixed_basename); |
610 | tree->non_prefixed_basename = NULL((void*)0); |
611 | |
612 | if (tree->path != NULL((void*)0)) |
613 | g_free (tree->path); |
614 | tree->path = NULL((void*)0); |
615 | |
616 | if (tree->canonical_path != NULL((void*)0)) |
617 | g_free (tree->canonical_path); |
618 | tree->canonical_path = NULL((void*)0); |
619 | |
620 | g_hash_table_destroy (tree->entries_by_id); |
621 | tree->entries_by_id = NULL((void*)0); |
622 | |
623 | G_OBJECT_CLASS (cafemenu_tree_parent_class)((((GObjectClass*) (void *) g_type_check_class_cast ((GTypeClass *) ((cafemenu_tree_parent_class)), (((GType) ((20) << ( 2))))))))->finalize (object); |
624 | } |
625 | |
626 | static void |
627 | cafemenu_tree_init (CafeMenuTree *self) |
628 | { |
629 | self->entries_by_id = g_hash_table_new (g_str_hash, g_str_equal); |
630 | } |
631 | |
632 | static void |
633 | cafemenu_tree_class_init (CafeMenuTreeClass *klass) |
634 | { |
635 | GObjectClass *gobject_class = G_OBJECT_CLASS (klass)((((GObjectClass*) (void *) g_type_check_class_cast ((GTypeClass *) ((klass)), (((GType) ((20) << (2)))))))); |
636 | |
637 | gobject_class->constructor = cafemenu_tree_constructor; |
638 | gobject_class->get_property = cafemenu_tree_get_property; |
639 | gobject_class->set_property = cafemenu_tree_set_property; |
640 | gobject_class->finalize = cafemenu_tree_finalize; |
641 | |
642 | /** |
643 | * CafeMenuTree:menu-basename: |
644 | * |
645 | * The name of the menu file; must be a basename or a relative path. The file |
646 | * will be looked up in $XDG_CONFIG_DIRS/menus/. See the Desktop Menu |
647 | * specification. |
648 | */ |
649 | g_object_class_install_property (gobject_class, |
650 | PROP_MENU_BASENAME, |
651 | g_param_spec_string ("menu-basename", "", "", |
652 | "applications.menu", |
653 | G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY)); |
654 | /** |
655 | * CafeMenuTree:menu-path: |
656 | * |
657 | * The full path of the menu file. If set, CafeMenuTree:menu-basename will get |
658 | * ignored. |
659 | */ |
660 | g_object_class_install_property (gobject_class, |
661 | PROP_MENU_PATH, |
662 | g_param_spec_string ("menu-path", "", "", |
663 | NULL((void*)0), |
664 | G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY)); |
665 | /** |
666 | * CafeMenuTree:flags: |
667 | * |
668 | * Flags controlling the content of the menu. |
669 | */ |
670 | g_object_class_install_property (gobject_class, |
671 | PROP_FLAGS, |
672 | g_param_spec_flags ("flags", "", "", |
673 | CAFEMENU_TYPE_TREE_FLAGS(cafemenu_tree_flags_get_type ()), |
674 | CAFEMENU_TREE_FLAGS_NONE, |
675 | G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY)); |
676 | |
677 | /** |
678 | * CafeMenuTree:changed: |
679 | * |
680 | * This signal is emitted when applications are added, removed, or |
681 | * upgraded. But note the new data will only be visible after |
682 | * cafemenu_tree_load_sync() or a variant thereof is invoked. |
683 | */ |
684 | cafemenu_tree_signals[CHANGED] = |
685 | g_signal_new ("changed", |
686 | G_TYPE_FROM_CLASS (klass)(((GTypeClass*) (klass))->g_type), |
687 | G_SIGNAL_RUN_LAST, |
688 | 0, |
689 | NULL((void*)0), NULL((void*)0), |
690 | g_cclosure_marshal_VOID__VOID, |
691 | G_TYPE_NONE((GType) ((1) << (2))), 0); |
692 | } |
693 | |
694 | /** |
695 | * cafemenu_tree_get_canonical_menu_path: |
696 | * @tree: a #CafeMenuTree |
697 | * |
698 | * This function is only available if the tree has been loaded via |
699 | * cafemenu_tree_load_sync() or a variant thereof. |
700 | * |
701 | * Returns: The absolute and canonicalized path to the loaded menu file |
702 | */ |
703 | const char * |
704 | cafemenu_tree_get_canonical_menu_path (CafeMenuTree *tree) |
705 | { |
706 | g_return_val_if_fail (CAFEMENU_IS_TREE (tree), NULL)do { if (((((__extension__ ({ GTypeInstance *__inst = (GTypeInstance *) ((tree)); GType __t = ((cafemenu_tree_get_type ())); gboolean __r; if (!__inst) __r = (0); else if (__inst->g_class && __inst->g_class->g_type == __t) __r = (!(0)); else __r = g_type_check_instance_is_a (__inst, __t); __r; })))))) { } else { g_return_if_fail_warning (((gchar*) 0), ((const char* ) (__func__)), "CAFEMENU_IS_TREE (tree)"); return (((void*)0) ); } } while (0); |
707 | g_return_val_if_fail (tree->loaded, NULL)do { if ((tree->loaded)) { } else { g_return_if_fail_warning (((gchar*) 0), ((const char*) (__func__)), "tree->loaded" ); return (((void*)0)); } } while (0); |
708 | |
709 | return tree->canonical_path; |
710 | } |
711 | |
712 | /** |
713 | * cafemenu_tree_load_sync: |
714 | * @tree: a #CafeMenuTree |
715 | * @error: a #GError |
716 | * |
717 | * Synchronously load the menu contents. This function |
718 | * performs a significant amount of blocking I/O if the |
719 | * tree has not been loaded yet. |
720 | * |
721 | * Returns: %TRUE on success, %FALSE on error |
722 | */ |
723 | gboolean |
724 | cafemenu_tree_load_sync (CafeMenuTree *tree, |
725 | GError **error) |
726 | { |
727 | GError *local_error = NULL((void*)0); |
728 | |
729 | if (tree->loaded) |
730 | return TRUE(!(0)); |
731 | |
732 | if (!cafemenu_tree_build_from_layout (tree, &local_error)) |
733 | { |
734 | if (local_error) |
735 | g_propagate_error (error, local_error); |
736 | return FALSE(0); |
737 | } |
738 | |
739 | tree->loaded = TRUE(!(0)); |
740 | |
741 | return TRUE(!(0)); |
742 | } |
743 | |
744 | /** |
745 | * cafemenu_tree_get_root_directory: |
746 | * @tree: a #CafeMenuTree |
747 | * |
748 | * Get the root directory; you must have loaded the tree first (at |
749 | * least once) via cafemenu_tree_load_sync() or a variant thereof. |
750 | * |
751 | * Returns: (transfer full): Root of the tree |
752 | */ |
753 | CafeMenuTreeDirectory * |
754 | cafemenu_tree_get_root_directory (CafeMenuTree *tree) |
755 | { |
756 | g_return_val_if_fail (tree != NULL, NULL)do { if ((tree != ((void*)0))) { } else { g_return_if_fail_warning (((gchar*) 0), ((const char*) (__func__)), "tree != NULL"); return (((void*)0)); } } while (0); |
757 | g_return_val_if_fail (tree->loaded, NULL)do { if ((tree->loaded)) { } else { g_return_if_fail_warning (((gchar*) 0), ((const char*) (__func__)), "tree->loaded" ); return (((void*)0)); } } while (0); |
758 | |
759 | return cafemenu_tree_item_ref (tree->root); |
760 | } |
761 | |
762 | static CafeMenuTreeDirectory * |
763 | find_path (CafeMenuTreeDirectory *directory, |
764 | const char *path) |
765 | { |
766 | const char *name; |
767 | char *slash; |
768 | char *freeme; |
769 | GSList *tmp; |
770 | |
771 | while (path[0] == G_DIR_SEPARATOR'/') path++; |
772 | |
773 | if (path[0] == '\0') |
774 | return directory; |
775 | |
776 | freeme = NULL((void*)0); |
777 | slash = strchr (path, G_DIR_SEPARATOR'/'); |
778 | if (slash) |
779 | { |
780 | name = freeme = g_strndup (path, slash - path); |
781 | path = slash + 1; |
782 | } |
783 | else |
784 | { |
785 | name = path; |
786 | path = NULL((void*)0); |
787 | } |
788 | |
789 | tmp = directory->contents; |
790 | while (tmp != NULL((void*)0)) |
791 | { |
792 | CafeMenuTreeItem *item = tmp->data; |
793 | |
794 | if (item->type != CAFEMENU_TREE_ITEM_DIRECTORY) |
795 | { |
796 | tmp = tmp->next; |
797 | continue; |
798 | } |
799 | |
800 | if (!strcmp (name, CAFEMENU_TREE_DIRECTORY (item)((CafeMenuTreeDirectory *)(item))->name)) |
801 | { |
802 | g_free (freeme); |
803 | |
804 | if (path) |
805 | return find_path (CAFEMENU_TREE_DIRECTORY (item)((CafeMenuTreeDirectory *)(item)), path); |
806 | else |
807 | return CAFEMENU_TREE_DIRECTORY (item)((CafeMenuTreeDirectory *)(item)); |
808 | } |
809 | |
810 | tmp = tmp->next; |
811 | } |
812 | |
813 | g_free (freeme); |
814 | |
815 | return NULL((void*)0); |
816 | } |
817 | |
818 | CafeMenuTreeDirectory * |
819 | cafemenu_tree_get_directory_from_path (CafeMenuTree *tree, |
820 | const char *path) |
821 | { |
822 | CafeMenuTreeDirectory *root; |
823 | CafeMenuTreeDirectory *directory; |
824 | |
825 | g_return_val_if_fail (tree != NULL, NULL)do { if ((tree != ((void*)0))) { } else { g_return_if_fail_warning (((gchar*) 0), ((const char*) (__func__)), "tree != NULL"); return (((void*)0)); } } while (0); |
826 | g_return_val_if_fail (path != NULL, NULL)do { if ((path != ((void*)0))) { } else { g_return_if_fail_warning (((gchar*) 0), ((const char*) (__func__)), "path != NULL"); return (((void*)0)); } } while (0); |
827 | |
828 | if (path[0] != G_DIR_SEPARATOR'/') |
829 | return NULL((void*)0); |
830 | |
831 | if (!(root = cafemenu_tree_get_root_directory (tree))) |
832 | return NULL((void*)0); |
This statement is never executed | |
833 | |
834 | directory = find_path (root, path); |
835 | |
836 | cafemenu_tree_item_unref (root); |
837 | |
838 | return directory ? cafemenu_tree_item_ref (directory) : NULL((void*)0); |
839 | } |
840 | |
841 | /** |
842 | * cafemenu_tree_get_entry_by_id: |
843 | * @tree: a #CafeMenuTree |
844 | * @id: a desktop file ID |
845 | * |
846 | * Look up the entry corresponding to the given "desktop file id". |
847 | * |
848 | * Returns: (transfer full): A newly referenced #CafeMenuTreeEntry, or %NULL if none |
849 | */ |
850 | CafeMenuTreeEntry * |
851 | cafemenu_tree_get_entry_by_id (CafeMenuTree *tree, |
852 | const char *id) |
853 | { |
854 | CafeMenuTreeEntry *entry; |
855 | |
856 | g_return_val_if_fail (tree->loaded, NULL)do { if ((tree->loaded)) { } else { g_return_if_fail_warning (((gchar*) 0), ((const char*) (__func__)), "tree->loaded" ); return (((void*)0)); } } while (0); |
857 | |
858 | entry = g_hash_table_lookup (tree->entries_by_id, id); |
859 | if (entry != NULL((void*)0)) |
860 | cafemenu_tree_item_ref (entry); |
861 | |
862 | return entry; |
863 | } |
864 | |
865 | static void |
866 | cafemenu_tree_invoke_monitors (CafeMenuTree *tree) |
867 | { |
868 | g_signal_emit (tree, cafemenu_tree_signals[CHANGED], 0); |
869 | } |
870 | |
871 | static CafeMenuTreeDirectory * |
872 | get_parent (CafeMenuTreeItem *item) |
873 | { |
874 | g_return_val_if_fail (item != NULL, NULL)do { if ((item != ((void*)0))) { } else { g_return_if_fail_warning (((gchar*) 0), ((const char*) (__func__)), "item != NULL"); return (((void*)0)); } } while (0); |
875 | return item->parent ? cafemenu_tree_item_ref (item->parent) : NULL((void*)0); |
876 | } |
877 | |
878 | /** |
879 | * cafemenu_tree_directory_get_parent: |
880 | * @directory: a #CafeMenuTreeDirectory |
881 | * |
882 | * Returns: (transfer full): The parent directory, or %NULL if none |
883 | */ |
884 | CafeMenuTreeDirectory * |
885 | cafemenu_tree_directory_get_parent (CafeMenuTreeDirectory *directory) |
886 | { |
887 | return get_parent ((CafeMenuTreeItem *)directory); |
888 | } |
889 | |
890 | /** |
891 | * cafemenu_tree_entry_get_parent: |
892 | * @entry: a #CafeMenuTreeEntry |
893 | * |
894 | * Returns: (transfer full): The parent directory, or %NULL if none |
895 | */ |
896 | CafeMenuTreeDirectory * |
897 | cafemenu_tree_entry_get_parent (CafeMenuTreeEntry *entry) |
898 | { |
899 | return get_parent ((CafeMenuTreeItem *)entry); |
900 | } |
901 | |
902 | /** |
903 | * cafemenu_tree_alias_get_parent: |
904 | * @alias: a #CafeMenuTreeAlias |
905 | * |
906 | * Returns: (transfer full): The parent directory, or %NULL if none |
907 | */ |
908 | CafeMenuTreeDirectory * |
909 | cafemenu_tree_alias_get_parent (CafeMenuTreeAlias *alias) |
910 | { |
911 | return get_parent ((CafeMenuTreeItem *)alias); |
912 | } |
913 | |
914 | /** |
915 | * cafemenu_tree_header_get_parent: |
916 | * @header: a #CafeMenuTreeHeader |
917 | * |
918 | * Returns: (transfer full): The parent directory, or %NULL if none |
919 | */ |
920 | CafeMenuTreeDirectory * |
921 | cafemenu_tree_header_get_parent (CafeMenuTreeHeader *header) |
922 | { |
923 | return get_parent ((CafeMenuTreeItem *)header); |
924 | } |
925 | |
926 | /** |
927 | * cafemenu_tree_separator_get_parent: |
928 | * @separator: a #CafeMenuTreeSeparator |
929 | * |
930 | * Returns: (transfer full): The parent directory, or %NULL if none |
931 | */ |
932 | CafeMenuTreeDirectory * |
933 | cafemenu_tree_separator_get_parent (CafeMenuTreeSeparator *separator) |
934 | { |
935 | return get_parent ((CafeMenuTreeItem *)separator); |
936 | } |
937 | |
938 | static void |
939 | cafemenu_tree_item_set_parent (CafeMenuTreeItem *item, |
940 | CafeMenuTreeDirectory *parent) |
941 | { |
942 | g_return_if_fail (item != NULL)do { if ((item != ((void*)0))) { } else { g_return_if_fail_warning (((gchar*) 0), ((const char*) (__func__)), "item != NULL"); return ; } } while (0); |
943 | |
944 | item->parent = parent; |
945 | } |
946 | |
947 | /** |
948 | * cafemenu_tree_iter_ref: (skip) |
949 | * @iter: iter |
950 | * |
951 | * Increment the reference count of @iter |
952 | */ |
953 | CafeMenuTreeIter * |
954 | cafemenu_tree_iter_ref (CafeMenuTreeIter *iter) |
955 | { |
956 | g_atomic_int_inc (&iter->refcount)(__extension__ ({ _Static_assert (sizeof *(&iter->refcount ) == sizeof (gint), "Expression evaluates to false"); (void) ( 0 ? *(&iter->refcount) ^ *(&iter->refcount) : 1 ); (void) __atomic_fetch_add ((&iter->refcount), 1, 5) ; })); |
957 | return iter; |
958 | } |
959 | |
960 | /** |
961 | * cafemenu_tree_iter_unref: (skip) |
962 | * @iter: iter |
963 | * |
964 | * Decrement the reference count of @iter |
965 | */ |
966 | void |
967 | cafemenu_tree_iter_unref (CafeMenuTreeIter *iter) |
968 | { |
969 | if (!g_atomic_int_dec_and_test (&iter->refcount)(__extension__ ({ _Static_assert (sizeof *(&iter->refcount ) == sizeof (gint), "Expression evaluates to false"); (void) ( 0 ? *(&iter->refcount) ^ *(&iter->refcount) : 1 ); __atomic_fetch_sub ((&iter->refcount), 1, 5) == 1; } ))) |
970 | return; |
971 | |
972 | g_slist_foreach (iter->contents, (GFunc)cafemenu_tree_item_unref, NULL((void*)0)); |
973 | g_slist_free (iter->contents); |
974 | |
975 | g_slice_free (CafeMenuTreeIter, iter)do { if (1) g_slice_free1 (sizeof (CafeMenuTreeIter), (iter)) ; else (void) ((CafeMenuTreeIter*) 0 == (iter)); } while (0); |
976 | } |
977 | |
978 | /** |
979 | * cafemenu_tree_directory_iter: |
980 | * @directory: directory |
981 | * |
982 | * Returns: (transfer full): A new iterator over the directory contents |
983 | */ |
984 | CafeMenuTreeIter * |
985 | cafemenu_tree_directory_iter (CafeMenuTreeDirectory *directory) |
986 | { |
987 | CafeMenuTreeIter *iter; |
988 | |
989 | g_return_val_if_fail (directory != NULL, NULL)do { if ((directory != ((void*)0))) { } else { g_return_if_fail_warning (((gchar*) 0), ((const char*) (__func__)), "directory != NULL" ); return (((void*)0)); } } while (0); |
990 | |
991 | iter = g_slice_new0 (CafeMenuTreeIter)((CafeMenuTreeIter*) g_slice_alloc0 (sizeof (CafeMenuTreeIter ))); |
992 | iter->refcount = 1; |
993 | |
994 | iter->contents = g_slist_copy (directory->contents); |
995 | iter->contents_iter = iter->contents; |
996 | g_slist_foreach (iter->contents, (GFunc) cafemenu_tree_item_ref, NULL((void*)0)); |
997 | |
998 | return iter; |
999 | } |
1000 | |
1001 | /** |
1002 | * cafemenu_tree_iter_next: |
1003 | * @iter: iter |
1004 | * |
1005 | * Change the iterator to the next item, and return its type. If |
1006 | * there are no more items, %CAFEMENU_TREE_ITEM_INVALID is returned. |
1007 | * |
1008 | * Returns: The type of the next item that can be retrived from the iterator |
1009 | */ |
1010 | CafeMenuTreeItemType |
1011 | cafemenu_tree_iter_next (CafeMenuTreeIter *iter) |
1012 | { |
1013 | g_return_val_if_fail (iter != NULL, CAFEMENU_TREE_ITEM_INVALID)do { if ((iter != ((void*)0))) { } else { g_return_if_fail_warning (((gchar*) 0), ((const char*) (__func__)), "iter != NULL"); return (CAFEMENU_TREE_ITEM_INVALID); } } while (0); |
1014 | |
1015 | if (iter->contents_iter) |
1016 | { |
1017 | iter->item = iter->contents_iter->data; |
1018 | iter->contents_iter = iter->contents_iter->next; |
1019 | return iter->item->type; |
1020 | } |
1021 | else |
1022 | return CAFEMENU_TREE_ITEM_INVALID; |
1023 | } |
1024 | |
1025 | /** |
1026 | * cafemenu_tree_iter_get_directory: |
1027 | * @iter: iter |
1028 | * |
1029 | * This method may only be called if cafemenu_tree_iter_next() |
1030 | * returned CAFEMENU_TREE_ITEM_DIRECTORY. |
1031 | * |
1032 | * Returns: (transfer full): A directory |
1033 | */ |
1034 | CafeMenuTreeDirectory * |
1035 | cafemenu_tree_iter_get_directory (CafeMenuTreeIter *iter) |
1036 | { |
1037 | g_return_val_if_fail (iter != NULL, NULL)do { if ((iter != ((void*)0))) { } else { g_return_if_fail_warning (((gchar*) 0), ((const char*) (__func__)), "iter != NULL"); return (((void*)0)); } } while (0); |
1038 | g_return_val_if_fail (iter->item != NULL, NULL)do { if ((iter->item != ((void*)0))) { } else { g_return_if_fail_warning (((gchar*) 0), ((const char*) (__func__)), "iter->item != NULL" ); return (((void*)0)); } } while (0); |
1039 | g_return_val_if_fail (iter->item->type == CAFEMENU_TREE_ITEM_DIRECTORY, NULL)do { if ((iter->item->type == CAFEMENU_TREE_ITEM_DIRECTORY )) { } else { g_return_if_fail_warning (((gchar*) 0), ((const char*) (__func__)), "iter->item->type == CAFEMENU_TREE_ITEM_DIRECTORY" ); return (((void*)0)); } } while (0); |
1040 | |
1041 | return (CafeMenuTreeDirectory*)cafemenu_tree_item_ref (iter->item); |
1042 | } |
1043 | |
1044 | /** |
1045 | * cafemenu_tree_iter_get_entry: |
1046 | * @iter: iter |
1047 | * |
1048 | * This method may only be called if cafemenu_tree_iter_next() |
1049 | * returned CAFEMENU_TREE_ITEM_ENTRY. |
1050 | * |
1051 | * Returns: (transfer full): An entry |
1052 | */ |
1053 | CafeMenuTreeEntry * |
1054 | cafemenu_tree_iter_get_entry (CafeMenuTreeIter *iter) |
1055 | { |
1056 | g_return_val_if_fail (iter != NULL, NULL)do { if ((iter != ((void*)0))) { } else { g_return_if_fail_warning (((gchar*) 0), ((const char*) (__func__)), "iter != NULL"); return (((void*)0)); } } while (0); |
1057 | g_return_val_if_fail (iter->item != NULL, NULL)do { if ((iter->item != ((void*)0))) { } else { g_return_if_fail_warning (((gchar*) 0), ((const char*) (__func__)), "iter->item != NULL" ); return (((void*)0)); } } while (0); |
1058 | g_return_val_if_fail (iter->item->type == CAFEMENU_TREE_ITEM_ENTRY, NULL)do { if ((iter->item->type == CAFEMENU_TREE_ITEM_ENTRY) ) { } else { g_return_if_fail_warning (((gchar*) 0), ((const char *) (__func__)), "iter->item->type == CAFEMENU_TREE_ITEM_ENTRY" ); return (((void*)0)); } } while (0); |
1059 | |
1060 | return (CafeMenuTreeEntry*)cafemenu_tree_item_ref (iter->item); |
1061 | } |
1062 | |
1063 | /** |
1064 | * cafemenu_tree_iter_get_header: |
1065 | * @iter: iter |
1066 | * |
1067 | * This method may only be called if cafemenu_tree_iter_next() |
1068 | * returned CAFEMENU_TREE_ITEM_HEADER. |
1069 | * |
1070 | * Returns: (transfer full): A header |
1071 | */ |
1072 | CafeMenuTreeHeader * |
1073 | cafemenu_tree_iter_get_header (CafeMenuTreeIter *iter) |
1074 | { |
1075 | g_return_val_if_fail (iter != NULL, NULL)do { if ((iter != ((void*)0))) { } else { g_return_if_fail_warning (((gchar*) 0), ((const char*) (__func__)), "iter != NULL"); return (((void*)0)); } } while (0); |
1076 | g_return_val_if_fail (iter->item != NULL, NULL)do { if ((iter->item != ((void*)0))) { } else { g_return_if_fail_warning (((gchar*) 0), ((const char*) (__func__)), "iter->item != NULL" ); return (((void*)0)); } } while (0); |
1077 | g_return_val_if_fail (iter->item->type == CAFEMENU_TREE_ITEM_HEADER, NULL)do { if ((iter->item->type == CAFEMENU_TREE_ITEM_HEADER )) { } else { g_return_if_fail_warning (((gchar*) 0), ((const char*) (__func__)), "iter->item->type == CAFEMENU_TREE_ITEM_HEADER" ); return (((void*)0)); } } while (0); |
1078 | |
1079 | return (CafeMenuTreeHeader*)cafemenu_tree_item_ref (iter->item); |
1080 | } |
1081 | |
1082 | /** |
1083 | * cafemenu_tree_iter_get_alias: |
1084 | * @iter: iter |
1085 | * |
1086 | * This method may only be called if cafemenu_tree_iter_next() |
1087 | * returned CAFEMENU_TREE_ITEM_ALIAS. |
1088 | * |
1089 | * Returns: (transfer full): An alias |
1090 | */ |
1091 | CafeMenuTreeAlias * |
1092 | cafemenu_tree_iter_get_alias (CafeMenuTreeIter *iter) |
1093 | { |
1094 | g_return_val_if_fail (iter != NULL, NULL)do { if ((iter != ((void*)0))) { } else { g_return_if_fail_warning (((gchar*) 0), ((const char*) (__func__)), "iter != NULL"); return (((void*)0)); } } while (0); |
1095 | g_return_val_if_fail (iter->item != NULL, NULL)do { if ((iter->item != ((void*)0))) { } else { g_return_if_fail_warning (((gchar*) 0), ((const char*) (__func__)), "iter->item != NULL" ); return (((void*)0)); } } while (0); |
1096 | g_return_val_if_fail (iter->item->type == CAFEMENU_TREE_ITEM_ALIAS, NULL)do { if ((iter->item->type == CAFEMENU_TREE_ITEM_ALIAS) ) { } else { g_return_if_fail_warning (((gchar*) 0), ((const char *) (__func__)), "iter->item->type == CAFEMENU_TREE_ITEM_ALIAS" ); return (((void*)0)); } } while (0); |
1097 | |
1098 | return (CafeMenuTreeAlias*)cafemenu_tree_item_ref (iter->item); |
1099 | } |
1100 | |
1101 | /** |
1102 | * cafemenu_tree_iter_get_separator: |
1103 | * @iter: iter |
1104 | * |
1105 | * This method may only be called if cafemenu_tree_iter_next() |
1106 | * returned #CAFEMENU_TREE_ITEM_SEPARATOR. |
1107 | * |
1108 | * Returns: (transfer full): A separator |
1109 | */ |
1110 | CafeMenuTreeSeparator * |
1111 | cafemenu_tree_iter_get_separator (CafeMenuTreeIter *iter) |
1112 | { |
1113 | g_return_val_if_fail (iter != NULL, NULL)do { if ((iter != ((void*)0))) { } else { g_return_if_fail_warning (((gchar*) 0), ((const char*) (__func__)), "iter != NULL"); return (((void*)0)); } } while (0); |
1114 | g_return_val_if_fail (iter->item != NULL, NULL)do { if ((iter->item != ((void*)0))) { } else { g_return_if_fail_warning (((gchar*) 0), ((const char*) (__func__)), "iter->item != NULL" ); return (((void*)0)); } } while (0); |
1115 | g_return_val_if_fail (iter->item->type == CAFEMENU_TREE_ITEM_SEPARATOR, NULL)do { if ((iter->item->type == CAFEMENU_TREE_ITEM_SEPARATOR )) { } else { g_return_if_fail_warning (((gchar*) 0), ((const char*) (__func__)), "iter->item->type == CAFEMENU_TREE_ITEM_SEPARATOR" ); return (((void*)0)); } } while (0); |
1116 | |
1117 | return (CafeMenuTreeSeparator*)cafemenu_tree_item_ref (iter->item); |
1118 | } |
1119 | |
1120 | const char * |
1121 | cafemenu_tree_directory_get_name (CafeMenuTreeDirectory *directory) |
1122 | { |
1123 | g_return_val_if_fail (directory != NULL, NULL)do { if ((directory != ((void*)0))) { } else { g_return_if_fail_warning (((gchar*) 0), ((const char*) (__func__)), "directory != NULL" ); return (((void*)0)); } } while (0); |
1124 | |
1125 | if (!directory->directory_entry) |
1126 | return directory->name; |
1127 | |
1128 | return desktop_entry_get_name (directory->directory_entry); |
1129 | } |
1130 | |
1131 | const char * |
1132 | cafemenu_tree_directory_get_generic_name (CafeMenuTreeDirectory *directory) |
1133 | { |
1134 | g_return_val_if_fail (directory != NULL, NULL)do { if ((directory != ((void*)0))) { } else { g_return_if_fail_warning (((gchar*) 0), ((const char*) (__func__)), "directory != NULL" ); return (((void*)0)); } } while (0); |
1135 | |
1136 | if (!directory->directory_entry) |
1137 | return NULL((void*)0); |
1138 | |
1139 | return desktop_entry_get_generic_name (directory->directory_entry); |
1140 | } |
1141 | |
1142 | const char * |
1143 | cafemenu_tree_directory_get_comment (CafeMenuTreeDirectory *directory) |
1144 | { |
1145 | g_return_val_if_fail (directory != NULL, NULL)do { if ((directory != ((void*)0))) { } else { g_return_if_fail_warning (((gchar*) 0), ((const char*) (__func__)), "directory != NULL" ); return (((void*)0)); } } while (0); |
1146 | |
1147 | if (!directory->directory_entry) |
1148 | return NULL((void*)0); |
1149 | |
1150 | return desktop_entry_get_comment (directory->directory_entry); |
1151 | } |
1152 | |
1153 | /** |
1154 | * cafemenu_tree_directory_get_icon: |
1155 | * @directory: a #CafeMenuTreeDirectory |
1156 | * |
1157 | * Gets the icon for the directory. |
1158 | * |
1159 | * Returns: (transfer none): The #GIcon for this directory |
1160 | */ |
1161 | GIcon * |
1162 | cafemenu_tree_directory_get_icon (CafeMenuTreeDirectory *directory) |
1163 | { |
1164 | g_return_val_if_fail(directory != NULL, NULL)do { if ((directory != ((void*)0))) { } else { g_return_if_fail_warning (((gchar*) 0), ((const char*) (__func__)), "directory != NULL" ); return (((void*)0)); } } while (0); |
1165 | |
1166 | if (!directory->directory_entry) |
1167 | return NULL((void*)0); |
1168 | |
1169 | return desktop_entry_get_icon(directory->directory_entry); |
1170 | } |
1171 | |
1172 | const char * |
1173 | cafemenu_tree_directory_get_desktop_file_path (CafeMenuTreeDirectory *directory) |
1174 | { |
1175 | g_return_val_if_fail (directory != NULL, NULL)do { if ((directory != ((void*)0))) { } else { g_return_if_fail_warning (((gchar*) 0), ((const char*) (__func__)), "directory != NULL" ); return (((void*)0)); } } while (0); |
1176 | |
1177 | if (!directory->directory_entry) |
1178 | return NULL((void*)0); |
1179 | |
1180 | return desktop_entry_get_path (directory->directory_entry); |
1181 | } |
1182 | |
1183 | const char * |
1184 | cafemenu_tree_directory_get_menu_id (CafeMenuTreeDirectory *directory) |
1185 | { |
1186 | g_return_val_if_fail (directory != NULL, NULL)do { if ((directory != ((void*)0))) { } else { g_return_if_fail_warning (((gchar*) 0), ((const char*) (__func__)), "directory != NULL" ); return (((void*)0)); } } while (0); |
1187 | |
1188 | return directory->name; |
1189 | } |
1190 | |
1191 | gboolean |
1192 | cafemenu_tree_directory_get_is_nodisplay (CafeMenuTreeDirectory *directory) |
1193 | { |
1194 | g_return_val_if_fail (directory != NULL, FALSE)do { if ((directory != ((void*)0))) { } else { g_return_if_fail_warning (((gchar*) 0), ((const char*) (__func__)), "directory != NULL" ); return ((0)); } } while (0); |
1195 | |
1196 | return directory->is_nodisplay; |
1197 | } |
1198 | |
1199 | /** |
1200 | * cafemenu_tree_directory_get_tree: |
1201 | * @directory: A #CafeMenuTreeDirectory |
1202 | * |
1203 | * Grab the tree associated with a #CafeMenuTreeItem. |
1204 | * |
1205 | * Returns: (transfer full): The #CafeMenuTree |
1206 | */ |
1207 | CafeMenuTree * |
1208 | cafemenu_tree_directory_get_tree (CafeMenuTreeDirectory *directory) |
1209 | { |
1210 | g_return_val_if_fail (directory != NULL, NULL)do { if ((directory != ((void*)0))) { } else { g_return_if_fail_warning (((gchar*) 0), ((const char*) (__func__)), "directory != NULL" ); return (((void*)0)); } } while (0); |
1211 | |
1212 | return g_object_ref (directory->item.tree)((__typeof__ (directory->item.tree)) (g_object_ref) (directory ->item.tree)); |
1213 | } |
1214 | |
1215 | static void |
1216 | append_directory_path (CafeMenuTreeDirectory *directory, |
1217 | GString *path) |
1218 | { |
1219 | |
1220 | if (!directory->item.parent) |
1221 | { |
1222 | g_string_append_c (path, G_DIR_SEPARATOR)g_string_append_c_inline (path, '/'); |
1223 | return; |
1224 | } |
1225 | |
1226 | append_directory_path (directory->item.parent, path); |
1227 | |
1228 | g_string_append (path, directory->name)(__builtin_constant_p (directory->name) ? __extension__ ({ const char * const __val = (directory->name); g_string_append_len_inline (path, __val, (__val != ((void*)0)) ? (gssize) strlen (((__val ) + !(__val))) : (gssize) -1); }) : g_string_append_len_inline (path, directory->name, (gssize) -1)); |
1229 | g_string_append_c (path, G_DIR_SEPARATOR)g_string_append_c_inline (path, '/'); |
1230 | } |
1231 | |
1232 | char * |
1233 | cafemenu_tree_directory_make_path (CafeMenuTreeDirectory *directory, |
1234 | CafeMenuTreeEntry *entry) |
1235 | { |
1236 | GString *path; |
1237 | |
1238 | g_return_val_if_fail (directory != NULL, NULL)do { if ((directory != ((void*)0))) { } else { g_return_if_fail_warning (((gchar*) 0), ((const char*) (__func__)), "directory != NULL" ); return (((void*)0)); } } while (0); |
1239 | |
1240 | path = g_string_new (NULL((void*)0)); |
1241 | |
1242 | append_directory_path (directory, path); |
1243 | |
1244 | if (entry != NULL((void*)0)) |
1245 | g_string_append (path,(__builtin_constant_p (desktop_entry_get_basename (entry-> desktop_entry)) ? __extension__ ({ const char * const __val = (desktop_entry_get_basename (entry->desktop_entry)); g_string_append_len_inline (path, __val, (__val != ((void*)0)) ? (gssize) strlen (((__val ) + !(__val))) : (gssize) -1); }) : g_string_append_len_inline (path, desktop_entry_get_basename (entry->desktop_entry), (gssize) -1)) |
1246 | desktop_entry_get_basename (entry->desktop_entry))(__builtin_constant_p (desktop_entry_get_basename (entry-> desktop_entry)) ? __extension__ ({ const char * const __val = (desktop_entry_get_basename (entry->desktop_entry)); g_string_append_len_inline (path, __val, (__val != ((void*)0)) ? (gssize) strlen (((__val ) + !(__val))) : (gssize) -1); }) : g_string_append_len_inline (path, desktop_entry_get_basename (entry->desktop_entry), (gssize) -1)); |
1247 | |
1248 | return g_string_free (path, FALSE)(__builtin_constant_p ((0)) ? (((0)) ? (g_string_free) ((path ), ((0))) : g_string_free_and_steal (path)) : (g_string_free) ((path), ((0)))); |
1249 | } |
1250 | |
1251 | /** |
1252 | * cafemenu_tree_entry_get_app_info: |
1253 | * @entry: a #CafeMenuTreeEntry |
1254 | * |
1255 | * Returns: (transfer none): The #GDesktopAppInfo for this entry |
1256 | */ |
1257 | GDesktopAppInfo * |
1258 | cafemenu_tree_entry_get_app_info (CafeMenuTreeEntry *entry) |
1259 | { |
1260 | g_return_val_if_fail (entry != NULL, NULL)do { if ((entry != ((void*)0))) { } else { g_return_if_fail_warning (((gchar*) 0), ((const char*) (__func__)), "entry != NULL"); return (((void*)0)); } } while (0); |
1261 | |
1262 | return desktop_entry_get_app_info (entry->desktop_entry); |
1263 | } |
1264 | |
1265 | const char * |
1266 | cafemenu_tree_entry_get_desktop_file_path (CafeMenuTreeEntry *entry) |
1267 | { |
1268 | g_return_val_if_fail (entry != NULL, NULL)do { if ((entry != ((void*)0))) { } else { g_return_if_fail_warning (((gchar*) 0), ((const char*) (__func__)), "entry != NULL"); return (((void*)0)); } } while (0); |
1269 | |
1270 | return desktop_entry_get_path (entry->desktop_entry); |
1271 | } |
1272 | |
1273 | const char * |
1274 | cafemenu_tree_entry_get_desktop_file_id (CafeMenuTreeEntry *entry) |
1275 | { |
1276 | g_return_val_if_fail (entry != NULL, NULL)do { if ((entry != ((void*)0))) { } else { g_return_if_fail_warning (((gchar*) 0), ((const char*) (__func__)), "entry != NULL"); return (((void*)0)); } } while (0); |
1277 | |
1278 | return entry->desktop_file_id; |
1279 | } |
1280 | |
1281 | gboolean |
1282 | cafemenu_tree_entry_get_is_nodisplay_recurse (CafeMenuTreeEntry *entry) |
1283 | { |
1284 | CafeMenuTreeDirectory *directory; |
1285 | GDesktopAppInfo *app_info; |
1286 | |
1287 | g_return_val_if_fail (entry != NULL, FALSE)do { if ((entry != ((void*)0))) { } else { g_return_if_fail_warning (((gchar*) 0), ((const char*) (__func__)), "entry != NULL"); return ((0)); } } while (0); |
1288 | |
1289 | app_info = cafemenu_tree_entry_get_app_info (entry); |
1290 | |
1291 | if (g_desktop_app_info_get_nodisplay (app_info)) |
1292 | return TRUE(!(0)); |
1293 | |
1294 | directory = entry->item.parent; |
1295 | while (directory != NULL((void*)0)) |
1296 | { |
1297 | if (directory->is_nodisplay) |
1298 | return TRUE(!(0)); |
1299 | |
1300 | directory = directory->item.parent; |
1301 | } |
1302 | |
1303 | return FALSE(0); |
1304 | } |
1305 | |
1306 | gboolean |
1307 | cafemenu_tree_entry_get_is_excluded (CafeMenuTreeEntry *entry) |
1308 | { |
1309 | g_return_val_if_fail(entry != NULL, FALSE)do { if ((entry != ((void*)0))) { } else { g_return_if_fail_warning (((gchar*) 0), ((const char*) (__func__)), "entry != NULL"); return ((0)); } } while (0); |
1310 | |
1311 | return entry->is_excluded; |
1312 | } |
1313 | |
1314 | gboolean |
1315 | cafemenu_tree_entry_get_is_unallocated (CafeMenuTreeEntry *entry) |
1316 | { |
1317 | g_return_val_if_fail (entry != NULL, FALSE)do { if ((entry != ((void*)0))) { } else { g_return_if_fail_warning (((gchar*) 0), ((const char*) (__func__)), "entry != NULL"); return ((0)); } } while (0); |
1318 | |
1319 | return entry->is_unallocated; |
1320 | } |
1321 | |
1322 | /** |
1323 | * cafemenu_tree_entry_get_tree: |
1324 | * @entry: A #CafeMenuTreeEntry |
1325 | * |
1326 | * Grab the tree associated with a #CafeMenuTreeEntry. |
1327 | * |
1328 | * Returns: (transfer full): The #CafeMenuTree |
1329 | */ |
1330 | CafeMenuTree * |
1331 | cafemenu_tree_entry_get_tree (CafeMenuTreeEntry *entry) |
1332 | { |
1333 | g_return_val_if_fail(entry != NULL, NULL)do { if ((entry != ((void*)0))) { } else { g_return_if_fail_warning (((gchar*) 0), ((const char*) (__func__)), "entry != NULL"); return (((void*)0)); } } while (0); |
1334 | |
1335 | return g_object_ref (entry->item.tree)((__typeof__ (entry->item.tree)) (g_object_ref) (entry-> item.tree)); |
1336 | } |
1337 | |
1338 | CafeMenuTreeDirectory * |
1339 | cafemenu_tree_header_get_directory (CafeMenuTreeHeader *header) |
1340 | { |
1341 | g_return_val_if_fail (header != NULL, NULL)do { if ((header != ((void*)0))) { } else { g_return_if_fail_warning (((gchar*) 0), ((const char*) (__func__)), "header != NULL") ; return (((void*)0)); } } while (0); |
1342 | |
1343 | return cafemenu_tree_item_ref (header->directory); |
1344 | } |
1345 | |
1346 | /** |
1347 | * cafemenu_tree_header_get_tree: |
1348 | * @header: A #CafeMenuTreeHeader |
1349 | * |
1350 | * Grab the tree associated with a #CafeMenuTreeHeader. |
1351 | * |
1352 | * Returns: (transfer full): The #CafeMenuTree |
1353 | */ |
1354 | CafeMenuTree * |
1355 | cafemenu_tree_header_get_tree (CafeMenuTreeHeader *header) |
1356 | { |
1357 | g_return_val_if_fail (header != NULL, NULL)do { if ((header != ((void*)0))) { } else { g_return_if_fail_warning (((gchar*) 0), ((const char*) (__func__)), "header != NULL") ; return (((void*)0)); } } while (0); |
1358 | |
1359 | return g_object_ref (header->item.tree)((__typeof__ (header->item.tree)) (g_object_ref) (header-> item.tree)); |
1360 | } |
1361 | |
1362 | CafeMenuTreeItemType |
1363 | cafemenu_tree_alias_get_aliased_item_type (CafeMenuTreeAlias *alias) |
1364 | { |
1365 | g_return_val_if_fail (alias != NULL, CAFEMENU_TREE_ITEM_INVALID)do { if ((alias != ((void*)0))) { } else { g_return_if_fail_warning (((gchar*) 0), ((const char*) (__func__)), "alias != NULL"); return (CAFEMENU_TREE_ITEM_INVALID); } } while (0); |
1366 | |
1367 | g_assert (alias->aliased_item != NULL)do { if (alias->aliased_item != ((void*)0)) ; else g_assertion_message_expr (((gchar*) 0), "cafemenu-tree.c", 1367, ((const char*) (__func__ )), "alias->aliased_item != NULL"); } while (0); |
1368 | return alias->aliased_item->type; |
1369 | } |
1370 | |
1371 | CafeMenuTreeDirectory* cafemenu_tree_alias_get_directory(CafeMenuTreeAlias* alias) |
1372 | { |
1373 | g_return_val_if_fail (alias != NULL, NULL)do { if ((alias != ((void*)0))) { } else { g_return_if_fail_warning (((gchar*) 0), ((const char*) (__func__)), "alias != NULL"); return (((void*)0)); } } while (0); |
1374 | |
1375 | return cafemenu_tree_item_ref(alias->directory); |
1376 | } |
1377 | |
1378 | /** |
1379 | * cafemenu_tree_alias_get_tree: |
1380 | * @alias: A #CafeMenuTreeAlias |
1381 | * |
1382 | * Grab the tree associated with a #CafeMenuTreeAlias. |
1383 | * |
1384 | * Returns: (transfer full): The #CafeMenuTree |
1385 | */ |
1386 | CafeMenuTree * |
1387 | cafemenu_tree_alias_get_tree (CafeMenuTreeAlias *alias) |
1388 | { |
1389 | g_return_val_if_fail (alias != NULL, NULL)do { if ((alias != ((void*)0))) { } else { g_return_if_fail_warning (((gchar*) 0), ((const char*) (__func__)), "alias != NULL"); return (((void*)0)); } } while (0); |
1390 | |
1391 | return g_object_ref (alias->item.tree)((__typeof__ (alias->item.tree)) (g_object_ref) (alias-> item.tree)); |
1392 | } |
1393 | |
1394 | /** |
1395 | * cafemenu_tree_separator_get_tree: |
1396 | * @separator: A #CafeMenuTreeSeparator |
1397 | * |
1398 | * Grab the tree associated with a #CafeMenuTreeSeparator. |
1399 | * |
1400 | * Returns: (transfer full): The #CafeMenuTree |
1401 | */ |
1402 | CafeMenuTree * |
1403 | cafemenu_tree_separator_get_tree (CafeMenuTreeSeparator *separator) |
1404 | { |
1405 | g_return_val_if_fail (separator != NULL, NULL)do { if ((separator != ((void*)0))) { } else { g_return_if_fail_warning (((gchar*) 0), ((const char*) (__func__)), "separator != NULL" ); return (((void*)0)); } } while (0); |
1406 | |
1407 | return g_object_ref (separator->item.tree)((__typeof__ (separator->item.tree)) (g_object_ref) (separator ->item.tree)); |
1408 | } |
1409 | |
1410 | /** |
1411 | * cafemenu_tree_alias_get_aliased_directory: |
1412 | * @alias: alias |
1413 | * |
1414 | * Returns: (transfer full): The aliased directory entry |
1415 | */ |
1416 | CafeMenuTreeDirectory * |
1417 | cafemenu_tree_alias_get_aliased_directory (CafeMenuTreeAlias *alias) |
1418 | { |
1419 | g_return_val_if_fail (alias != NULL, NULL)do { if ((alias != ((void*)0))) { } else { g_return_if_fail_warning (((gchar*) 0), ((const char*) (__func__)), "alias != NULL"); return (((void*)0)); } } while (0); |
1420 | g_return_val_if_fail (alias->aliased_item->type == CAFEMENU_TREE_ITEM_DIRECTORY, NULL)do { if ((alias->aliased_item->type == CAFEMENU_TREE_ITEM_DIRECTORY )) { } else { g_return_if_fail_warning (((gchar*) 0), ((const char*) (__func__)), "alias->aliased_item->type == CAFEMENU_TREE_ITEM_DIRECTORY" ); return (((void*)0)); } } while (0); |
1421 | |
1422 | return (CafeMenuTreeDirectory *) cafemenu_tree_item_ref (alias->aliased_item); |
1423 | } |
1424 | |
1425 | /** |
1426 | * cafemenu_tree_alias_get_aliased_entry: |
1427 | * @alias: alias |
1428 | * |
1429 | * Returns: (transfer full): The aliased entry |
1430 | */ |
1431 | CafeMenuTreeEntry * |
1432 | cafemenu_tree_alias_get_aliased_entry (CafeMenuTreeAlias *alias) |
1433 | { |
1434 | g_return_val_if_fail (alias != NULL, NULL)do { if ((alias != ((void*)0))) { } else { g_return_if_fail_warning (((gchar*) 0), ((const char*) (__func__)), "alias != NULL"); return (((void*)0)); } } while (0); |
1435 | g_return_val_if_fail (alias->aliased_item->type == CAFEMENU_TREE_ITEM_ENTRY, NULL)do { if ((alias->aliased_item->type == CAFEMENU_TREE_ITEM_ENTRY )) { } else { g_return_if_fail_warning (((gchar*) 0), ((const char*) (__func__)), "alias->aliased_item->type == CAFEMENU_TREE_ITEM_ENTRY" ); return (((void*)0)); } } while (0); |
1436 | |
1437 | return (CafeMenuTreeEntry *) cafemenu_tree_item_ref (alias->aliased_item); |
1438 | } |
1439 | |
1440 | static CafeMenuTreeDirectory * |
1441 | cafemenu_tree_directory_new (CafeMenuTree *tree, |
1442 | CafeMenuTreeDirectory *parent, |
1443 | const char *name) |
1444 | { |
1445 | CafeMenuTreeDirectory *retval; |
1446 | |
1447 | retval = g_slice_new0 (CafeMenuTreeDirectory)((CafeMenuTreeDirectory*) g_slice_alloc0 (sizeof (CafeMenuTreeDirectory ))); |
1448 | |
1449 | retval->item.type = CAFEMENU_TREE_ITEM_DIRECTORY; |
1450 | retval->item.parent = parent; |
1451 | retval->item.refcount = 1; |
1452 | retval->item.tree = tree; |
1453 | |
1454 | retval->name = g_strdup (name)g_strdup_inline (name); |
1455 | retval->directory_entry = NULL((void*)0); |
1456 | retval->entries = NULL((void*)0); |
1457 | retval->subdirs = NULL((void*)0); |
1458 | retval->default_layout_info = NULL((void*)0); |
1459 | retval->layout_info = NULL((void*)0); |
1460 | retval->contents = NULL((void*)0); |
1461 | retval->only_unallocated = FALSE(0); |
1462 | retval->is_nodisplay = FALSE(0); |
1463 | retval->layout_pending_separator = FALSE(0); |
1464 | retval->preprocessed = FALSE(0); |
1465 | retval->will_inline_header = G_MAXUINT16((guint16) 0xffff); |
1466 | |
1467 | retval->default_layout_values.mask = MENU_LAYOUT_VALUES_NONE; |
1468 | retval->default_layout_values.show_empty = FALSE(0); |
1469 | retval->default_layout_values.inline_menus = FALSE(0); |
1470 | retval->default_layout_values.inline_limit = 4; |
1471 | retval->default_layout_values.inline_header = FALSE(0); |
1472 | retval->default_layout_values.inline_alias = FALSE(0); |
1473 | |
1474 | return retval; |
1475 | } |
1476 | |
1477 | static void |
1478 | cafemenu_tree_directory_finalize (CafeMenuTreeDirectory *directory) |
1479 | { |
1480 | g_assert (directory->item.refcount == 0)do { if (directory->item.refcount == 0) ; else g_assertion_message_expr (((gchar*) 0), "cafemenu-tree.c", 1480, ((const char*) (__func__ )), "directory->item.refcount == 0"); } while (0); |
1481 | |
1482 | g_slist_foreach (directory->contents, |
1483 | (GFunc) cafemenu_tree_item_unref_and_unset_parent, |
1484 | NULL((void*)0)); |
1485 | g_slist_free (directory->contents); |
1486 | directory->contents = NULL((void*)0); |
1487 | |
1488 | g_slist_foreach (directory->default_layout_info, |
1489 | (GFunc) menu_layout_node_unref, |
1490 | NULL((void*)0)); |
1491 | g_slist_free (directory->default_layout_info); |
1492 | directory->default_layout_info = NULL((void*)0); |
1493 | |
1494 | g_slist_foreach (directory->layout_info, |
1495 | (GFunc) menu_layout_node_unref, |
1496 | NULL((void*)0)); |
1497 | g_slist_free (directory->layout_info); |
1498 | directory->layout_info = NULL((void*)0); |
1499 | |
1500 | g_slist_foreach (directory->subdirs, |
1501 | (GFunc) cafemenu_tree_item_unref_and_unset_parent, |
1502 | NULL((void*)0)); |
1503 | g_slist_free (directory->subdirs); |
1504 | directory->subdirs = NULL((void*)0); |
1505 | |
1506 | g_slist_foreach (directory->entries, |
1507 | (GFunc) cafemenu_tree_item_unref_and_unset_parent, |
1508 | NULL((void*)0)); |
1509 | g_slist_free (directory->entries); |
1510 | directory->entries = NULL((void*)0); |
1511 | |
1512 | if (directory->directory_entry) |
1513 | desktop_entry_unref (directory->directory_entry); |
1514 | directory->directory_entry = NULL((void*)0); |
1515 | |
1516 | g_free (directory->name); |
1517 | directory->name = NULL((void*)0); |
1518 | |
1519 | g_slice_free (CafeMenuTreeDirectory, directory)do { if (1) g_slice_free1 (sizeof (CafeMenuTreeDirectory), (directory )); else (void) ((CafeMenuTreeDirectory*) 0 == (directory)); } while (0); |
1520 | } |
1521 | |
1522 | static CafeMenuTreeSeparator * |
1523 | cafemenu_tree_separator_new (CafeMenuTreeDirectory *parent) |
1524 | { |
1525 | CafeMenuTreeSeparator *retval; |
1526 | |
1527 | retval = g_slice_new0 (CafeMenuTreeSeparator)((CafeMenuTreeSeparator*) g_slice_alloc0 (sizeof (CafeMenuTreeSeparator ))); |
1528 | |
1529 | retval->item.type = CAFEMENU_TREE_ITEM_SEPARATOR; |
1530 | retval->item.parent = parent; |
1531 | retval->item.refcount = 1; |
1532 | retval->item.tree = parent->item.tree; |
1533 | |
1534 | return retval; |
1535 | } |
1536 | |
1537 | static void |
1538 | cafemenu_tree_separator_finalize (CafeMenuTreeSeparator *separator) |
1539 | { |
1540 | g_assert (separator->item.refcount == 0)do { if (separator->item.refcount == 0) ; else g_assertion_message_expr (((gchar*) 0), "cafemenu-tree.c", 1540, ((const char*) (__func__ )), "separator->item.refcount == 0"); } while (0); |
1541 | |
1542 | g_slice_free (CafeMenuTreeSeparator, separator)do { if (1) g_slice_free1 (sizeof (CafeMenuTreeSeparator), (separator )); else (void) ((CafeMenuTreeSeparator*) 0 == (separator)); } while (0); |
1543 | } |
1544 | |
1545 | static CafeMenuTreeHeader * |
1546 | cafemenu_tree_header_new (CafeMenuTreeDirectory *parent, |
1547 | CafeMenuTreeDirectory *directory) |
1548 | { |
1549 | CafeMenuTreeHeader *retval; |
1550 | |
1551 | retval = g_slice_new0 (CafeMenuTreeHeader)((CafeMenuTreeHeader*) g_slice_alloc0 (sizeof (CafeMenuTreeHeader ))); |
1552 | |
1553 | retval->item.type = CAFEMENU_TREE_ITEM_HEADER; |
1554 | retval->item.parent = parent; |
1555 | retval->item.refcount = 1; |
1556 | retval->item.tree = parent->item.tree; |
1557 | |
1558 | retval->directory = cafemenu_tree_item_ref (directory); |
1559 | |
1560 | cafemenu_tree_item_set_parent (CAFEMENU_TREE_ITEM (retval->directory)((CafeMenuTreeItem *)(retval->directory)), NULL((void*)0)); |
1561 | |
1562 | return retval; |
1563 | } |
1564 | |
1565 | static void |
1566 | cafemenu_tree_header_finalize (CafeMenuTreeHeader *header) |
1567 | { |
1568 | g_assert (header->item.refcount == 0)do { if (header->item.refcount == 0) ; else g_assertion_message_expr (((gchar*) 0), "cafemenu-tree.c", 1568, ((const char*) (__func__ )), "header->item.refcount == 0"); } while (0); |
1569 | |
1570 | if (header->directory != NULL((void*)0)) |
1571 | cafemenu_tree_item_unref (header->directory); |
1572 | header->directory = NULL((void*)0); |
1573 | |
1574 | g_slice_free (CafeMenuTreeHeader, header)do { if (1) g_slice_free1 (sizeof (CafeMenuTreeHeader), (header )); else (void) ((CafeMenuTreeHeader*) 0 == (header)); } while (0); |
1575 | } |
1576 | |
1577 | static CafeMenuTreeAlias * |
1578 | cafemenu_tree_alias_new (CafeMenuTreeDirectory *parent, |
1579 | CafeMenuTreeDirectory *directory, |
1580 | CafeMenuTreeItem *item) |
1581 | { |
1582 | CafeMenuTreeAlias *retval; |
1583 | |
1584 | retval = g_slice_new0 (CafeMenuTreeAlias)((CafeMenuTreeAlias*) g_slice_alloc0 (sizeof (CafeMenuTreeAlias ))); |
1585 | |
1586 | retval->item.type = CAFEMENU_TREE_ITEM_ALIAS; |
1587 | retval->item.parent = parent; |
1588 | retval->item.refcount = 1; |
1589 | retval->item.tree = parent->item.tree; |
1590 | |
1591 | retval->directory = cafemenu_tree_item_ref (directory); |
1592 | if (item->type != CAFEMENU_TREE_ITEM_ALIAS) |
1593 | retval->aliased_item = cafemenu_tree_item_ref (item); |
1594 | else |
1595 | { |
1596 | CafeMenuTreeAlias *alias = CAFEMENU_TREE_ALIAS (item)((CafeMenuTreeAlias *)(item)); |
1597 | retval->aliased_item = cafemenu_tree_item_ref (alias->aliased_item); |
1598 | } |
1599 | |
1600 | cafemenu_tree_item_set_parent (CAFEMENU_TREE_ITEM (retval->directory)((CafeMenuTreeItem *)(retval->directory)), NULL((void*)0)); |
1601 | cafemenu_tree_item_set_parent (retval->aliased_item, NULL((void*)0)); |
1602 | |
1603 | return retval; |
1604 | } |
1605 | |
1606 | static void |
1607 | cafemenu_tree_alias_finalize (CafeMenuTreeAlias *alias) |
1608 | { |
1609 | g_assert (alias->item.refcount == 0)do { if (alias->item.refcount == 0) ; else g_assertion_message_expr (((gchar*) 0), "cafemenu-tree.c", 1609, ((const char*) (__func__ )), "alias->item.refcount == 0"); } while (0); |
1610 | |
1611 | if (alias->directory != NULL((void*)0)) |
1612 | cafemenu_tree_item_unref (alias->directory); |
1613 | alias->directory = NULL((void*)0); |
1614 | |
1615 | if (alias->aliased_item != NULL((void*)0)) |
1616 | cafemenu_tree_item_unref (alias->aliased_item); |
1617 | alias->aliased_item = NULL((void*)0); |
1618 | |
1619 | g_slice_free (CafeMenuTreeAlias, alias)do { if (1) g_slice_free1 (sizeof (CafeMenuTreeAlias), (alias )); else (void) ((CafeMenuTreeAlias*) 0 == (alias)); } while ( 0); |
1620 | } |
1621 | |
1622 | static CafeMenuTreeEntry * |
1623 | cafemenu_tree_entry_new (CafeMenuTreeDirectory *parent, |
1624 | DesktopEntry *desktop_entry, |
1625 | const char *desktop_file_id, |
1626 | gboolean is_excluded, |
1627 | gboolean is_unallocated) |
1628 | { |
1629 | CafeMenuTreeEntry *retval; |
1630 | |
1631 | retval = g_slice_new0 (CafeMenuTreeEntry)((CafeMenuTreeEntry*) g_slice_alloc0 (sizeof (CafeMenuTreeEntry ))); |
1632 | |
1633 | retval->item.type = CAFEMENU_TREE_ITEM_ENTRY; |
1634 | retval->item.parent = parent; |
1635 | retval->item.refcount = 1; |
1636 | retval->item.tree = parent->item.tree; |
1637 | |
1638 | retval->desktop_entry = desktop_entry_ref (desktop_entry); |
1639 | retval->desktop_file_id = g_strdup (desktop_file_id)g_strdup_inline (desktop_file_id); |
1640 | retval->is_excluded = is_excluded != FALSE(0); |
1641 | retval->is_unallocated = is_unallocated != FALSE(0); |
1642 | |
1643 | return retval; |
1644 | } |
1645 | |
1646 | static void |
1647 | cafemenu_tree_entry_finalize (CafeMenuTreeEntry *entry) |
1648 | { |
1649 | g_assert (entry->item.refcount == 0)do { if (entry->item.refcount == 0) ; else g_assertion_message_expr (((gchar*) 0), "cafemenu-tree.c", 1649, ((const char*) (__func__ )), "entry->item.refcount == 0"); } while (0); |
1650 | |
1651 | g_free (entry->desktop_file_id); |
1652 | entry->desktop_file_id = NULL((void*)0); |
1653 | |
1654 | if (entry->desktop_entry) |
1655 | desktop_entry_unref (entry->desktop_entry); |
1656 | entry->desktop_entry = NULL((void*)0); |
1657 | |
1658 | g_slice_free (CafeMenuTreeEntry, entry)do { if (1) g_slice_free1 (sizeof (CafeMenuTreeEntry), (entry )); else (void) ((CafeMenuTreeEntry*) 0 == (entry)); } while ( 0); |
1659 | } |
1660 | |
1661 | static int |
1662 | cafemenu_tree_entry_compare_by_id (CafeMenuTreeItem *a, |
1663 | CafeMenuTreeItem *b) |
1664 | { |
1665 | if (a->type == CAFEMENU_TREE_ITEM_ALIAS) |
1666 | a = CAFEMENU_TREE_ALIAS (a)((CafeMenuTreeAlias *)(a))->aliased_item; |
1667 | |
1668 | if (b->type == CAFEMENU_TREE_ITEM_ALIAS) |
1669 | b = CAFEMENU_TREE_ALIAS (b)((CafeMenuTreeAlias *)(b))->aliased_item; |
1670 | |
1671 | return strcmp (CAFEMENU_TREE_ENTRY (a)((CafeMenuTreeEntry *)(a))->desktop_file_id, |
1672 | CAFEMENU_TREE_ENTRY (b)((CafeMenuTreeEntry *)(b))->desktop_file_id); |
1673 | } |
1674 | |
1675 | /** |
1676 | * cafemenu_tree_item_ref: |
1677 | * @item: a #CafeMenuTreeItem |
1678 | * |
1679 | * Returns: (transfer full): The same @item, or %NULL if @item is not a valid #CafeMenuTreeItem |
1680 | */ |
1681 | gpointer |
1682 | cafemenu_tree_item_ref (gpointer itemp) |
1683 | { |
1684 | CafeMenuTreeItem* item = (CafeMenuTreeItem*) itemp; |
1685 | |
1686 | g_return_val_if_fail(item != NULL, NULL)do { if ((item != ((void*)0))) { } else { g_return_if_fail_warning (((gchar*) 0), ((const char*) (__func__)), "item != NULL"); return (((void*)0)); } } while (0); |
1687 | g_return_val_if_fail(item->refcount > 0, NULL)do { if ((item->refcount > 0)) { } else { g_return_if_fail_warning (((gchar*) 0), ((const char*) (__func__)), "item->refcount > 0" ); return (((void*)0)); } } while (0); |
1688 | |
1689 | g_atomic_int_inc (&item->refcount)(__extension__ ({ _Static_assert (sizeof *(&item->refcount ) == sizeof (gint), "Expression evaluates to false"); (void) ( 0 ? *(&item->refcount) ^ *(&item->refcount) : 1 ); (void) __atomic_fetch_add ((&item->refcount), 1, 5) ; })); |
1690 | |
1691 | return item; |
1692 | } |
1693 | |
1694 | void |
1695 | cafemenu_tree_item_unref (gpointer itemp) |
1696 | { |
1697 | CafeMenuTreeItem *item; |
1698 | |
1699 | item = (CafeMenuTreeItem *) itemp; |
1700 | |
1701 | g_return_if_fail (item != NULL)do { if ((item != ((void*)0))) { } else { g_return_if_fail_warning (((gchar*) 0), ((const char*) (__func__)), "item != NULL"); return ; } } while (0); |
1702 | g_return_if_fail (item->refcount > 0)do { if ((item->refcount > 0)) { } else { g_return_if_fail_warning (((gchar*) 0), ((const char*) (__func__)), "item->refcount > 0" ); return; } } while (0); |
1703 | |
1704 | if (g_atomic_int_dec_and_test (&(item->refcount))(__extension__ ({ _Static_assert (sizeof *(&(item->refcount )) == sizeof (gint), "Expression evaluates to false"); (void) (0 ? *(&(item->refcount)) ^ *(&(item->refcount )) : 1); __atomic_fetch_sub ((&(item->refcount)), 1, 5 ) == 1; }))) |
1705 | { |
1706 | switch (item->type) |
1707 | { |
1708 | case CAFEMENU_TREE_ITEM_DIRECTORY: |
1709 | cafemenu_tree_directory_finalize (CAFEMENU_TREE_DIRECTORY (item)((CafeMenuTreeDirectory *)(item))); |
1710 | break; |
1711 | |
1712 | case CAFEMENU_TREE_ITEM_ENTRY: |
1713 | cafemenu_tree_entry_finalize (CAFEMENU_TREE_ENTRY (item)((CafeMenuTreeEntry *)(item))); |
1714 | break; |
1715 | |
1716 | case CAFEMENU_TREE_ITEM_SEPARATOR: |
1717 | cafemenu_tree_separator_finalize (CAFEMENU_TREE_SEPARATOR (item)((CafeMenuTreeSeparator *)(item))); |
1718 | break; |
1719 | |
1720 | case CAFEMENU_TREE_ITEM_HEADER: |
1721 | cafemenu_tree_header_finalize (CAFEMENU_TREE_HEADER (item)((CafeMenuTreeHeader *)(item))); |
1722 | break; |
1723 | |
1724 | case CAFEMENU_TREE_ITEM_ALIAS: |
1725 | cafemenu_tree_alias_finalize (CAFEMENU_TREE_ALIAS (item)((CafeMenuTreeAlias *)(item))); |
1726 | break; |
1727 | |
1728 | default: |
1729 | g_assert_not_reached ()do { g_assertion_message_expr (((gchar*) 0), "cafemenu-tree.c" , 1729, ((const char*) (__func__)), ((void*)0)); } while (0); |
1730 | break; |
1731 | } |
1732 | } |
1733 | } |
1734 | |
1735 | static void |
1736 | cafemenu_tree_item_unref_and_unset_parent (gpointer itemp) |
1737 | { |
1738 | CafeMenuTreeItem *item; |
1739 | |
1740 | item = (CafeMenuTreeItem *) itemp; |
1741 | |
1742 | g_return_if_fail (item != NULL)do { if ((item != ((void*)0))) { } else { g_return_if_fail_warning (((gchar*) 0), ((const char*) (__func__)), "item != NULL"); return ; } } while (0); |
1743 | |
1744 | cafemenu_tree_item_set_parent (item, NULL((void*)0)); |
1745 | cafemenu_tree_item_unref (item); |
1746 | } |
1747 | |
1748 | static inline const char * |
1749 | cafemenu_tree_item_compare_get_name_helper (CafeMenuTreeItem *item, |
1750 | CafeMenuTreeFlags flags) |
1751 | { |
1752 | const char *name; |
1753 | |
1754 | name = NULL((void*)0); |
1755 | |
1756 | switch (item->type) |
1757 | { |
1758 | case CAFEMENU_TREE_ITEM_DIRECTORY: |
1759 | if (CAFEMENU_TREE_DIRECTORY (item)((CafeMenuTreeDirectory *)(item))->directory_entry) |
1760 | name = desktop_entry_get_name (CAFEMENU_TREE_DIRECTORY (item)((CafeMenuTreeDirectory *)(item))->directory_entry); |
1761 | else |
1762 | name = CAFEMENU_TREE_DIRECTORY (item)((CafeMenuTreeDirectory *)(item))->name; |
1763 | break; |
1764 | |
1765 | case CAFEMENU_TREE_ITEM_ENTRY: |
1766 | if (flags & CAFEMENU_TREE_FLAGS_SORT_DISPLAY_NAME) |
1767 | name = g_app_info_get_display_name (G_APP_INFO (cafemenu_tree_entry_get_app_info (CAFEMENU_TREE_ENTRY (item)))((((GAppInfo*) (void *) g_type_check_instance_cast ((GTypeInstance *) ((cafemenu_tree_entry_get_app_info (((CafeMenuTreeEntry *) (item))))), ((g_app_info_get_type ()))))))); |
1768 | else |
1769 | name = desktop_entry_get_name (CAFEMENU_TREE_ENTRY (item)((CafeMenuTreeEntry *)(item))->desktop_entry); |
1770 | break; |
1771 | |
1772 | case CAFEMENU_TREE_ITEM_ALIAS: |
1773 | { |
1774 | CafeMenuTreeItem *dir; |
1775 | dir = CAFEMENU_TREE_ITEM (CAFEMENU_TREE_ALIAS (item)->directory)((CafeMenuTreeItem *)(((CafeMenuTreeAlias *)(item))->directory )); |
1776 | name = cafemenu_tree_item_compare_get_name_helper (dir, flags); |
1777 | } |
1778 | break; |
1779 | |
1780 | case CAFEMENU_TREE_ITEM_SEPARATOR: |
1781 | case CAFEMENU_TREE_ITEM_HEADER: |
1782 | default: |
1783 | g_assert_not_reached ()do { g_assertion_message_expr (((gchar*) 0), "cafemenu-tree.c" , 1783, ((const char*) (__func__)), ((void*)0)); } while (0); |
1784 | break; |
1785 | } |
1786 | |
1787 | return name; |
1788 | } |
1789 | |
1790 | static int |
1791 | cafemenu_tree_item_compare (CafeMenuTreeItem *a, |
1792 | CafeMenuTreeItem *b, |
1793 | gpointer flags_p) |
1794 | { |
1795 | const char *name_a; |
1796 | const char *name_b; |
1797 | CafeMenuTreeFlags flags; |
1798 | |
1799 | flags = GPOINTER_TO_INT (flags_p)((gint) (glong) (flags_p)); |
1800 | |
1801 | name_a = cafemenu_tree_item_compare_get_name_helper (a, flags); |
1802 | name_b = cafemenu_tree_item_compare_get_name_helper (b, flags); |
1803 | |
1804 | return g_utf8_collate (name_a, name_b); |
1805 | } |
1806 | |
1807 | static MenuLayoutNode * |
1808 | find_menu_child (MenuLayoutNode *layout) |
1809 | { |
1810 | MenuLayoutNode *child; |
1811 | |
1812 | child = menu_layout_node_get_children (layout); |
1813 | while (child && menu_layout_node_get_type (child) != MENU_LAYOUT_NODE_MENU) |
1814 | child = menu_layout_node_get_next (child); |
1815 | |
1816 | return child; |
1817 | } |
1818 | |
1819 | static void |
1820 | merge_resolved_children (CafeMenuTree *tree, |
1821 | GHashTable *loaded_menu_files, |
1822 | MenuLayoutNode *where, |
1823 | MenuLayoutNode *from) |
1824 | { |
1825 | MenuLayoutNode *insert_after; |
1826 | MenuLayoutNode *menu_child; |
1827 | MenuLayoutNode *from_child; |
1828 | |
1829 | cafemenu_tree_resolve_files (tree, loaded_menu_files, from); |
1830 | |
1831 | insert_after = where; |
1832 | g_assert (menu_layout_node_get_type (insert_after) != MENU_LAYOUT_NODE_ROOT)do { if (menu_layout_node_get_type (insert_after) != MENU_LAYOUT_NODE_ROOT ) ; else g_assertion_message_expr (((gchar*) 0), "cafemenu-tree.c" , 1832, ((const char*) (__func__)), "menu_layout_node_get_type (insert_after) != MENU_LAYOUT_NODE_ROOT" ); } while (0); |
1833 | g_assert (menu_layout_node_get_parent (insert_after) != NULL)do { if (menu_layout_node_get_parent (insert_after) != ((void *)0)) ; else g_assertion_message_expr (((gchar*) 0), "cafemenu-tree.c" , 1833, ((const char*) (__func__)), "menu_layout_node_get_parent (insert_after) != NULL" ); } while (0); |
1834 | |
1835 | /* skip root node */ |
1836 | menu_child = find_menu_child (from); |
1837 | g_assert (menu_child != NULL)do { if (menu_child != ((void*)0)) ; else g_assertion_message_expr (((gchar*) 0), "cafemenu-tree.c", 1837, ((const char*) (__func__ )), "menu_child != NULL"); } while (0); |
1838 | g_assert (menu_layout_node_get_type (menu_child) == MENU_LAYOUT_NODE_MENU)do { if (menu_layout_node_get_type (menu_child) == MENU_LAYOUT_NODE_MENU ) ; else g_assertion_message_expr (((gchar*) 0), "cafemenu-tree.c" , 1838, ((const char*) (__func__)), "menu_layout_node_get_type (menu_child) == MENU_LAYOUT_NODE_MENU" ); } while (0); |
1839 | |
1840 | /* merge children of toplevel <Menu> */ |
1841 | from_child = menu_layout_node_get_children (menu_child); |
1842 | while (from_child != NULL((void*)0)) |
1843 | { |
1844 | MenuLayoutNode *next; |
1845 | |
1846 | next = menu_layout_node_get_next (from_child); |
1847 | |
1848 | menu_verbose ("Merging "); |
1849 | menu_debug_print_layout (from_child, FALSE); |
1850 | menu_verbose (" after "); |
1851 | menu_debug_print_layout (insert_after, FALSE); |
1852 | |
1853 | switch (menu_layout_node_get_type (from_child)) |
1854 | { |
1855 | case MENU_LAYOUT_NODE_NAME: |
1856 | menu_layout_node_unlink (from_child); /* delete this */ |
1857 | break; |
1858 | |
1859 | default: |
1860 | menu_layout_node_steal (from_child); |
1861 | menu_layout_node_insert_after (insert_after, from_child); |
1862 | menu_layout_node_unref (from_child); |
1863 | |
1864 | insert_after = from_child; |
1865 | break; |
1866 | } |
1867 | |
1868 | from_child = next; |
1869 | } |
1870 | } |
1871 | |
1872 | static gboolean |
1873 | load_merge_file (CafeMenuTree *tree, |
1874 | GHashTable *loaded_menu_files, |
1875 | const char *filename, |
1876 | gboolean is_canonical, |
1877 | gboolean add_monitor, |
1878 | MenuLayoutNode *where) |
1879 | { |
1880 | MenuLayoutNode *to_merge; |
1881 | const char *canonical; |
1882 | char *freeme; |
1883 | gboolean retval; |
1884 | |
1885 | freeme = NULL((void*)0); |
1886 | retval = FALSE(0); |
1887 | |
1888 | if (!is_canonical) |
1889 | { |
1890 | canonical = freeme = realpath (filename, NULL((void*)0)); |
1891 | if (canonical == NULL((void*)0)) |
1892 | { |
1893 | if (add_monitor) |
1894 | cafemenu_tree_add_menu_file_monitor (tree, |
1895 | filename, |
1896 | MENU_FILE_MONITOR_NONEXISTENT_FILE); |
1897 | |
1898 | menu_verbose ("Failed to canonicalize merge file path \"%s\": %s\n", |
1899 | filename, g_strerror (errno)); |
1900 | goto out; |
1901 | } |
1902 | } |
1903 | else |
1904 | { |
1905 | canonical = filename; |
1906 | } |
1907 | |
1908 | if (g_hash_table_lookup (loaded_menu_files, canonical) != NULL((void*)0)) |
1909 | { |
1910 | g_warning ("Not loading \"%s\": recursive loop detected in .menu files", |
1911 | canonical); |
1912 | retval = TRUE(!(0)); |
1913 | goto out; |
1914 | } |
1915 | |
1916 | menu_verbose ("Merging file \"%s\"\n", canonical); |
1917 | |
1918 | to_merge = menu_layout_load (canonical, tree->non_prefixed_basename, NULL((void*)0)); |
1919 | if (to_merge == NULL((void*)0)) |
1920 | { |
1921 | menu_verbose ("No menu for file \"%s\" found when merging\n", |
1922 | canonical); |
1923 | goto out; |
1924 | } |
1925 | |
1926 | retval = TRUE(!(0)); |
1927 | |
1928 | g_hash_table_insert (loaded_menu_files, (char *) canonical, GUINT_TO_POINTER (TRUE)((gpointer) (gulong) ((!(0))))); |
1929 | |
1930 | if (add_monitor) |
1931 | cafemenu_tree_add_menu_file_monitor (tree, |
1932 | canonical, |
1933 | MENU_FILE_MONITOR_FILE); |
1934 | |
1935 | merge_resolved_children (tree, loaded_menu_files, where, to_merge); |
1936 | |
1937 | g_hash_table_remove (loaded_menu_files, canonical); |
1938 | |
1939 | menu_layout_node_unref (to_merge); |
1940 | |
1941 | out: |
1942 | if (freeme) |
1943 | g_free (freeme); |
1944 | |
1945 | return retval; |
1946 | } |
1947 | |
1948 | static gboolean |
1949 | load_merge_file_with_config_dir (CafeMenuTree *tree, |
1950 | GHashTable *loaded_menu_files, |
1951 | const char *menu_file, |
1952 | const char *config_dir, |
1953 | MenuLayoutNode *where) |
1954 | { |
1955 | char *merge_file; |
1956 | gboolean loaded; |
1957 | |
1958 | loaded = FALSE(0); |
1959 | |
1960 | merge_file = g_build_filename (config_dir, "menus", menu_file, NULL((void*)0)); |
1961 | |
1962 | if (load_merge_file (tree, loaded_menu_files, merge_file, FALSE(0), TRUE(!(0)), where)) |
1963 | loaded = TRUE(!(0)); |
1964 | |
1965 | g_free (merge_file); |
1966 | |
1967 | return loaded; |
1968 | } |
1969 | |
1970 | static gboolean |
1971 | compare_basedir_to_config_dir (const char *canonical_basedir, |
1972 | const char *config_dir) |
1973 | { |
1974 | char *dirname; |
1975 | char *canonical_menus_dir; |
1976 | gboolean retval; |
1977 | |
1978 | menu_verbose ("Checking to see if basedir '%s' is in '%s'\n", |
1979 | canonical_basedir, config_dir); |
1980 | |
1981 | dirname = g_build_filename (config_dir, "menus", NULL((void*)0)); |
1982 | |
1983 | retval = FALSE(0); |
1984 | |
1985 | canonical_menus_dir = realpath (dirname, NULL((void*)0)); |
1986 | if (canonical_menus_dir != NULL((void*)0) && |
1987 | strcmp (canonical_basedir, canonical_menus_dir) == 0) |
1988 | { |
1989 | retval = TRUE(!(0)); |
1990 | } |
1991 | |
1992 | g_free (canonical_menus_dir); |
1993 | g_free (dirname); |
1994 | |
1995 | return retval; |
1996 | } |
1997 | |
1998 | static gboolean |
1999 | load_parent_merge_file_from_basename (CafeMenuTree *tree, |
2000 | GHashTable *loaded_menu_files, |
2001 | MenuLayoutNode *layout, |
2002 | const char *menu_file, |
2003 | const char *canonical_basedir) |
2004 | { |
2005 | gboolean found_basedir; |
2006 | const char * const *system_config_dirs; |
2007 | int i; |
2008 | |
2009 | /* We're not interested in menu files that are in directories which are not a |
2010 | * parent of the base directory of this menu file */ |
2011 | found_basedir = compare_basedir_to_config_dir (canonical_basedir, |
2012 | g_get_user_config_dir ()); |
2013 | |
2014 | system_config_dirs = g_get_system_config_dirs (); |
2015 | |
2016 | i = 0; |
2017 | while (system_config_dirs[i] != NULL((void*)0)) |
2018 | { |
2019 | if (!found_basedir) |
2020 | { |
2021 | found_basedir = compare_basedir_to_config_dir (canonical_basedir, |
2022 | system_config_dirs[i]); |
2023 | } |
2024 | else |
2025 | { |
2026 | menu_verbose ("Looking for parent menu file '%s' in '%s'\n", |
2027 | menu_file, system_config_dirs[i]); |
2028 | |
2029 | if (load_merge_file_with_config_dir (tree, |
2030 | loaded_menu_files, |
2031 | menu_file, |
2032 | system_config_dirs[i], |
2033 | layout)) |
2034 | { |
2035 | break; |
2036 | } |
2037 | } |
2038 | |
2039 | ++i; |
2040 | } |
2041 | |
2042 | return system_config_dirs[i] != NULL((void*)0); |
2043 | } |
2044 | |
2045 | static gboolean load_parent_merge_file(CafeMenuTree* tree, GHashTable* loaded_menu_files, MenuLayoutNode* layout) |
2046 | { |
2047 | MenuLayoutNode* root; |
2048 | const char* basedir; |
2049 | const char* menu_name; |
2050 | char* canonical_basedir; |
2051 | char* menu_file; |
2052 | gboolean found; |
2053 | |
2054 | root = menu_layout_node_get_root(layout); |
2055 | |
2056 | basedir = menu_layout_node_root_get_basedir(root); |
2057 | menu_name = menu_layout_node_root_get_name(root); |
2058 | |
2059 | canonical_basedir = realpath (basedir, NULL((void*)0)); |
2060 | |
2061 | if (canonical_basedir == NULL((void*)0)) |
2062 | { |
2063 | menu_verbose("Menu basedir '%s' no longer exists, not merging parent\n", basedir); |
2064 | return FALSE(0); |
2065 | } |
2066 | |
2067 | found = FALSE(0); |
2068 | menu_file = g_strconcat(menu_name, ".menu", NULL((void*)0)); |
2069 | |
2070 | if (strcmp(menu_file, "cafe-applications.menu") == 0 && g_getenv("XDG_MENU_PREFIX")) |
2071 | { |
2072 | char* prefixed_basename; |
2073 | prefixed_basename = g_strdup_printf("%s%s", g_getenv("XDG_MENU_PREFIX"), menu_file); |
2074 | found = load_parent_merge_file_from_basename(tree, loaded_menu_files, layout, prefixed_basename, canonical_basedir); |
2075 | g_free(prefixed_basename); |
2076 | } |
2077 | |
2078 | if (!found) |
2079 | { |
2080 | found = load_parent_merge_file_from_basename(tree, loaded_menu_files, layout, menu_file, canonical_basedir); |
2081 | } |
2082 | |
2083 | g_free(menu_file); |
2084 | g_free(canonical_basedir); |
2085 | |
2086 | return found; |
2087 | } |
2088 | |
2089 | static void |
2090 | load_merge_dir (CafeMenuTree *tree, |
2091 | GHashTable *loaded_menu_files, |
2092 | const char *dirname, |
2093 | MenuLayoutNode *where) |
2094 | { |
2095 | GDir *dir; |
2096 | const char *menu_file; |
2097 | |
2098 | menu_verbose ("Loading merge dir \"%s\"\n", dirname); |
2099 | |
2100 | cafemenu_tree_add_menu_file_monitor (tree, |
2101 | dirname, |
2102 | MENU_FILE_MONITOR_DIRECTORY); |
2103 | |
2104 | if ((dir = g_dir_open (dirname, 0, NULL((void*)0))) == NULL((void*)0)) |
2105 | return; |
2106 | |
2107 | while ((menu_file = g_dir_read_name (dir))) |
2108 | { |
2109 | if (g_str_has_suffix (menu_file, ".menu")(__builtin_constant_p (".menu")? __extension__ ({ const char * const __str = (menu_file); const char * const __suffix = (".menu" ); gboolean __result = (0); if (__str == ((void*)0) || __suffix == ((void*)0)) __result = (g_str_has_suffix) (__str, __suffix ); else { const size_t __str_len = strlen (((__str) + !(__str ))); const size_t __suffix_len = strlen (((__suffix) + !(__suffix ))); if (__str_len >= __suffix_len) __result = memcmp (__str + __str_len - __suffix_len, ((__suffix) + !(__suffix)), __suffix_len ) == 0; } __result; }) : (g_str_has_suffix) (menu_file, ".menu" ) )) |
2110 | { |
2111 | char *full_path; |
2112 | |
2113 | full_path = g_build_filename (dirname, menu_file, NULL((void*)0)); |
2114 | |
2115 | load_merge_file (tree, loaded_menu_files, full_path, TRUE(!(0)), FALSE(0), where); |
2116 | |
2117 | g_free (full_path); |
2118 | } |
2119 | } |
2120 | |
2121 | g_dir_close (dir); |
2122 | } |
2123 | |
2124 | static void |
2125 | load_merge_dir_with_config_dir (CafeMenuTree *tree, |
2126 | GHashTable *loaded_menu_files, |
2127 | const char *config_dir, |
2128 | const char *dirname, |
2129 | MenuLayoutNode *where) |
2130 | { |
2131 | char *path; |
2132 | |
2133 | path = g_build_filename (config_dir, "menus", dirname, NULL((void*)0)); |
2134 | |
2135 | load_merge_dir (tree, loaded_menu_files, path, where); |
2136 | |
2137 | g_free (path); |
2138 | } |
2139 | |
2140 | static void |
2141 | resolve_merge_file (CafeMenuTree *tree, |
2142 | GHashTable *loaded_menu_files, |
2143 | MenuLayoutNode *layout) |
2144 | { |
2145 | char *filename; |
2146 | |
2147 | if (menu_layout_node_merge_file_get_type (layout) == MENU_MERGE_FILE_TYPE_PARENT) |
2148 | { |
2149 | if (load_parent_merge_file (tree, loaded_menu_files, layout)) |
2150 | return; |
2151 | } |
2152 | |
2153 | filename = menu_layout_node_get_content_as_path (layout); |
2154 | if (filename == NULL((void*)0)) |
2155 | { |
2156 | menu_verbose ("didn't get node content as a path, not merging file\n"); |
2157 | } |
2158 | else |
2159 | { |
2160 | load_merge_file (tree, loaded_menu_files, filename, FALSE(0), TRUE(!(0)), layout); |
2161 | |
2162 | g_free (filename); |
2163 | } |
2164 | |
2165 | /* remove the now-replaced node */ |
2166 | menu_layout_node_unlink (layout); |
2167 | } |
2168 | |
2169 | static void |
2170 | resolve_merge_dir (CafeMenuTree *tree, |
2171 | GHashTable *loaded_menu_files, |
2172 | MenuLayoutNode *layout) |
2173 | { |
2174 | char *path; |
2175 | |
2176 | path = menu_layout_node_get_content_as_path (layout); |
2177 | if (path == NULL((void*)0)) |
2178 | { |
2179 | menu_verbose ("didn't get layout node content as a path, not merging dir\n"); |
2180 | } |
2181 | else |
2182 | { |
2183 | load_merge_dir (tree, loaded_menu_files, path, layout); |
2184 | |
2185 | g_free (path); |
2186 | } |
2187 | |
2188 | /* remove the now-replaced node */ |
2189 | menu_layout_node_unlink (layout); |
2190 | } |
2191 | |
2192 | static MenuLayoutNode * |
2193 | add_app_dir (CafeMenuTree *tree G_GNUC_UNUSED__attribute__ ((__unused__)), |
2194 | MenuLayoutNode *before, |
2195 | const char *data_dir) |
2196 | { |
2197 | MenuLayoutNode *tmp; |
2198 | char *dirname; |
2199 | |
2200 | tmp = menu_layout_node_new (MENU_LAYOUT_NODE_APP_DIR); |
2201 | dirname = g_build_filename (data_dir, "applications", NULL((void*)0)); |
2202 | menu_layout_node_set_content (tmp, dirname); |
2203 | menu_layout_node_insert_before (before, tmp); |
2204 | menu_layout_node_unref (before); |
2205 | |
2206 | menu_verbose ("Adding <AppDir>%s</AppDir> in <DefaultAppDirs/>\n", |
2207 | dirname); |
2208 | |
2209 | g_free (dirname); |
2210 | |
2211 | return tmp; |
2212 | } |
2213 | |
2214 | static void |
2215 | resolve_default_app_dirs (CafeMenuTree *tree, |
2216 | MenuLayoutNode *layout) |
2217 | { |
2218 | MenuLayoutNode *before; |
2219 | const char * const *system_data_dirs; |
2220 | int i; |
2221 | |
2222 | system_data_dirs = g_get_system_data_dirs (); |
2223 | |
2224 | before = add_app_dir (tree, |
2225 | menu_layout_node_ref (layout), |
2226 | g_get_user_data_dir ()); |
2227 | |
2228 | i = 0; |
2229 | while (system_data_dirs[i] != NULL((void*)0)) |
2230 | { |
2231 | before = add_app_dir (tree, before, system_data_dirs[i]); |
2232 | |
2233 | ++i; |
2234 | } |
2235 | |
2236 | menu_layout_node_unref (before); |
2237 | |
2238 | /* remove the now-replaced node */ |
2239 | menu_layout_node_unlink (layout); |
2240 | } |
2241 | |
2242 | static MenuLayoutNode* add_directory_dir (CafeMenuTree *tree G_GNUC_UNUSED__attribute__ ((__unused__)), |
2243 | MenuLayoutNode *before, |
2244 | const char *data_dir) |
2245 | { |
2246 | MenuLayoutNode* tmp; |
2247 | char* dirname; |
2248 | |
2249 | tmp = menu_layout_node_new(MENU_LAYOUT_NODE_DIRECTORY_DIR); |
2250 | dirname = g_build_filename(data_dir, "desktop-directories", NULL((void*)0)); |
2251 | menu_layout_node_set_content(tmp, dirname); |
2252 | menu_layout_node_insert_before(before, tmp); |
2253 | menu_layout_node_unref(before); |
2254 | |
2255 | menu_verbose("Adding <DirectoryDir>%s</DirectoryDir> in <DefaultDirectoryDirs/>\n", dirname); |
2256 | |
2257 | g_free(dirname); |
2258 | |
2259 | return tmp; |
2260 | } |
2261 | |
2262 | /* According to desktop spec, since our menu file is called 'cafe-applications', our |
2263 | * merged menu folders need to be called 'cafe-applications-merged'. We'll setup the folder |
2264 | * 'applications-merged' if it doesn't exist yet, and a symlink pointing to it in the |
2265 | * ~/.config/menus directory |
2266 | */ |
2267 | static void |
2268 | setup_merge_dir_symlink(void) |
2269 | { |
2270 | gchar *user_config = (gchar *) g_get_user_config_dir(); |
2271 | gchar *merge_path = g_build_filename (user_config, "menus", "applications-merged", NULL((void*)0)); |
2272 | GFile *merge_file = g_file_new_for_path (merge_path); |
2273 | gchar *sym_path; |
2274 | GFile *sym_file; |
2275 | |
2276 | g_file_make_directory_with_parents (merge_file, NULL((void*)0), NULL((void*)0)); |
2277 | |
2278 | sym_path = g_build_filename (user_config, "menus", "cafe-applications-merged", NULL((void*)0)); |
2279 | sym_file = g_file_new_for_path (sym_path); |
2280 | if (!g_file_query_exists (sym_file, NULL((void*)0))) { |
2281 | g_file_make_symbolic_link (sym_file, merge_path, NULL((void*)0), NULL((void*)0)); |
2282 | } |
2283 | |
2284 | g_free (merge_path); |
2285 | g_free (sym_path); |
2286 | g_object_unref (merge_file); |
2287 | g_object_unref (sym_file); |
2288 | } |
2289 | |
2290 | static void |
2291 | resolve_default_directory_dirs (CafeMenuTree *tree, |
2292 | MenuLayoutNode *layout) |
2293 | { |
2294 | MenuLayoutNode *before; |
2295 | const char * const *system_data_dirs; |
2296 | int i; |
2297 | |
2298 | system_data_dirs = g_get_system_data_dirs (); |
2299 | |
2300 | before = add_directory_dir (tree, |
2301 | menu_layout_node_ref (layout), |
2302 | g_get_user_data_dir ()); |
2303 | |
2304 | i = 0; |
2305 | while (system_data_dirs[i] != NULL((void*)0)) |
2306 | { |
2307 | /* Parche para tomar las carpetas /cafe/ */ |
2308 | char* path = g_build_filename(system_data_dirs[i], "cafe", NULL((void*)0)); |
2309 | before = add_directory_dir(tree, before, path); |
2310 | g_free(path); |
2311 | /* /fin parche */ |
2312 | before = add_directory_dir (tree, before, system_data_dirs[i]); |
2313 | |
2314 | ++i; |
2315 | } |
2316 | |
2317 | menu_layout_node_unref (before); |
2318 | |
2319 | /* remove the now-replaced node */ |
2320 | menu_layout_node_unlink (layout); |
2321 | } |
2322 | |
2323 | static void |
2324 | resolve_default_merge_dirs (CafeMenuTree *tree, |
2325 | GHashTable *loaded_menu_files, |
2326 | MenuLayoutNode *layout) |
2327 | { |
2328 | MenuLayoutNode *root; |
2329 | const char *menu_name; |
2330 | char *merge_name; |
2331 | const char * const *system_config_dirs; |
2332 | int i; |
2333 | |
2334 | setup_merge_dir_symlink(); |
2335 | |
2336 | root = menu_layout_node_get_root (layout); |
2337 | menu_name = menu_layout_node_root_get_name (root); |
2338 | |
2339 | merge_name = g_strconcat (menu_name, "-merged", NULL((void*)0)); |
2340 | |
2341 | system_config_dirs = g_get_system_config_dirs (); |
2342 | |
2343 | /* Merge in reverse order */ |
2344 | i = 0; |
2345 | while (system_config_dirs[i] != NULL((void*)0)) i++; |
2346 | while (i > 0) |
2347 | { |
2348 | i--; |
2349 | load_merge_dir_with_config_dir (tree, |
2350 | loaded_menu_files, |
2351 | system_config_dirs[i], |
2352 | merge_name, |
2353 | layout); |
2354 | } |
2355 | |
2356 | load_merge_dir_with_config_dir (tree, |
2357 | loaded_menu_files, |
2358 | g_get_user_config_dir (), |
2359 | merge_name, |
2360 | layout); |
2361 | |
2362 | g_free (merge_name); |
2363 | |
2364 | /* remove the now-replaced node */ |
2365 | menu_layout_node_unlink (layout); |
2366 | } |
2367 | |
2368 | static void |
2369 | add_filename_include (const char *desktop_file_id, |
2370 | DesktopEntry *entry, |
2371 | MenuLayoutNode *include) |
2372 | { |
2373 | if (!desktop_entry_has_categories (entry)) |
2374 | { |
2375 | MenuLayoutNode *node; |
2376 | |
2377 | node = menu_layout_node_new (MENU_LAYOUT_NODE_FILENAME); |
2378 | menu_layout_node_set_content (node, desktop_file_id); |
2379 | |
2380 | menu_layout_node_append_child (include, node); |
2381 | menu_layout_node_unref (node); |
2382 | } |
2383 | } |
2384 | |
2385 | static void |
2386 | is_dot_directory (const char *basename, |
2387 | DesktopEntry *entry G_GNUC_UNUSED__attribute__ ((__unused__)), |
2388 | gboolean *has_dot_directory) |
2389 | { |
2390 | if (!strcmp (basename, ".directory")) |
2391 | *has_dot_directory = TRUE(!(0)); |
2392 | } |
2393 | |
2394 | static gboolean |
2395 | add_menu_for_legacy_dir (MenuLayoutNode *parent, |
2396 | const char *legacy_dir, |
2397 | const char *relative_path, |
2398 | const char *legacy_prefix, |
2399 | const char *menu_name) |
2400 | { |
2401 | EntryDirectory *ed; |
2402 | DesktopEntrySet *desktop_entries; |
2403 | DesktopEntrySet *directory_entries; |
2404 | GSList *subdirs; |
2405 | gboolean menu_added; |
2406 | gboolean has_dot_directory; |
2407 | |
2408 | ed = entry_directory_new_legacy (DESKTOP_ENTRY_INVALID, legacy_dir, legacy_prefix); |
2409 | if (!ed) |
2410 | return FALSE(0); |
2411 | |
2412 | subdirs = NULL((void*)0); |
2413 | desktop_entries = desktop_entry_set_new (); |
2414 | directory_entries = desktop_entry_set_new (); |
2415 | |
2416 | entry_directory_get_flat_contents (ed, |
2417 | desktop_entries, |
2418 | directory_entries, |
2419 | &subdirs); |
2420 | entry_directory_unref (ed); |
2421 | |
2422 | has_dot_directory = FALSE(0); |
2423 | desktop_entry_set_foreach (directory_entries, |
2424 | (DesktopEntrySetForeachFunc) is_dot_directory, |
2425 | &has_dot_directory); |
2426 | desktop_entry_set_unref (directory_entries); |
2427 | |
2428 | menu_added = FALSE(0); |
2429 | if (desktop_entry_set_get_count (desktop_entries) > 0 || subdirs) |
2430 | { |
2431 | MenuLayoutNode *menu; |
2432 | MenuLayoutNode *node; |
2433 | GString *subdir_path; |
2434 | GString *subdir_relative; |
2435 | GSList *tmp; |
2436 | int legacy_dir_len; |
2437 | int relative_path_len; |
2438 | |
2439 | menu = menu_layout_node_new (MENU_LAYOUT_NODE_MENU); |
2440 | menu_layout_node_append_child (parent, menu); |
2441 | |
2442 | menu_added = TRUE(!(0)); |
2443 | |
2444 | g_assert (menu_name != NULL)do { if (menu_name != ((void*)0)) ; else g_assertion_message_expr (((gchar*) 0), "cafemenu-tree.c", 2444, ((const char*) (__func__ )), "menu_name != NULL"); } while (0); |
2445 | |
2446 | node = menu_layout_node_new (MENU_LAYOUT_NODE_NAME); |
2447 | menu_layout_node_set_content (node, menu_name); |
2448 | menu_layout_node_append_child (menu, node); |
2449 | menu_layout_node_unref (node); |
2450 | |
2451 | if (has_dot_directory) |
2452 | { |
2453 | node = menu_layout_node_new (MENU_LAYOUT_NODE_DIRECTORY); |
2454 | if (relative_path != NULL((void*)0)) |
2455 | { |
2456 | char *directory_entry_path; |
2457 | |
2458 | directory_entry_path = g_strdup_printf ("%s/.directory", relative_path); |
2459 | menu_layout_node_set_content (node, directory_entry_path); |
2460 | g_free (directory_entry_path); |
2461 | } |
2462 | else |
2463 | { |
2464 | menu_layout_node_set_content (node, ".directory"); |
2465 | } |
2466 | menu_layout_node_append_child (menu, node); |
2467 | menu_layout_node_unref (node); |
2468 | } |
2469 | |
2470 | if (desktop_entry_set_get_count (desktop_entries) > 0) |
2471 | { |
2472 | MenuLayoutNode *include; |
2473 | |
2474 | include = menu_layout_node_new (MENU_LAYOUT_NODE_INCLUDE); |
2475 | menu_layout_node_append_child (menu, include); |
2476 | |
2477 | desktop_entry_set_foreach (desktop_entries, |
2478 | (DesktopEntrySetForeachFunc) add_filename_include, |
2479 | include); |
2480 | |
2481 | menu_layout_node_unref (include); |
2482 | } |
2483 | |
2484 | subdir_path = g_string_new (legacy_dir); |
2485 | legacy_dir_len = strlen (legacy_dir); |
2486 | |
2487 | subdir_relative = g_string_new (relative_path); |
2488 | relative_path_len = relative_path ? strlen (relative_path) : 0; |
2489 | |
2490 | tmp = subdirs; |
2491 | while (tmp != NULL((void*)0)) |
2492 | { |
2493 | const char *subdir = tmp->data; |
2494 | |
2495 | g_string_append_c (subdir_path, G_DIR_SEPARATOR)g_string_append_c_inline (subdir_path, '/'); |
2496 | g_string_append (subdir_path, subdir)(__builtin_constant_p (subdir) ? __extension__ ({ const char * const __val = (subdir); g_string_append_len_inline (subdir_path , __val, (__val != ((void*)0)) ? (gssize) strlen (((__val) + ! (__val))) : (gssize) -1); }) : g_string_append_len_inline (subdir_path , subdir, (gssize) -1)); |
2497 | |
2498 | if (relative_path_len) |
2499 | { |
2500 | g_string_append_c (subdir_relative, G_DIR_SEPARATOR)g_string_append_c_inline (subdir_relative, '/'); |
2501 | } |
2502 | g_string_append (subdir_relative, subdir)(__builtin_constant_p (subdir) ? __extension__ ({ const char * const __val = (subdir); g_string_append_len_inline (subdir_relative , __val, (__val != ((void*)0)) ? (gssize) strlen (((__val) + ! (__val))) : (gssize) -1); }) : g_string_append_len_inline (subdir_relative , subdir, (gssize) -1)); |
2503 | |
2504 | add_menu_for_legacy_dir (menu, |
2505 | subdir_path->str, |
2506 | subdir_relative->str, |
2507 | legacy_prefix, |
2508 | subdir); |
2509 | |
2510 | g_string_truncate (subdir_relative, relative_path_len)g_string_truncate_inline (subdir_relative, relative_path_len); |
2511 | g_string_truncate (subdir_path, legacy_dir_len)g_string_truncate_inline (subdir_path, legacy_dir_len); |
2512 | |
2513 | tmp = tmp->next; |
2514 | } |
2515 | |
2516 | g_string_free (subdir_path, TRUE)(__builtin_constant_p ((!(0))) ? (((!(0))) ? (g_string_free) ( (subdir_path), ((!(0)))) : g_string_free_and_steal (subdir_path )) : (g_string_free) ((subdir_path), ((!(0))))); |
2517 | g_string_free (subdir_relative, TRUE)(__builtin_constant_p ((!(0))) ? (((!(0))) ? (g_string_free) ( (subdir_relative), ((!(0)))) : g_string_free_and_steal (subdir_relative )) : (g_string_free) ((subdir_relative), ((!(0))))); |
2518 | |
2519 | menu_layout_node_unref (menu); |
2520 | } |
2521 | |
2522 | desktop_entry_set_unref (desktop_entries); |
2523 | |
2524 | g_slist_foreach (subdirs, (GFunc) g_free, NULL((void*)0)); |
2525 | g_slist_free (subdirs); |
2526 | |
2527 | return menu_added; |
2528 | } |
2529 | |
2530 | static void |
2531 | resolve_legacy_dir (CafeMenuTree *tree, |
2532 | GHashTable *loaded_menu_files, |
2533 | MenuLayoutNode *legacy) |
2534 | { |
2535 | MenuLayoutNode *to_merge; |
2536 | MenuLayoutNode *menu; |
2537 | |
2538 | to_merge = menu_layout_node_new (MENU_LAYOUT_NODE_ROOT); |
2539 | |
2540 | menu = menu_layout_node_get_parent (legacy); |
2541 | g_assert (menu_layout_node_get_type (menu) == MENU_LAYOUT_NODE_MENU)do { if (menu_layout_node_get_type (menu) == MENU_LAYOUT_NODE_MENU ) ; else g_assertion_message_expr (((gchar*) 0), "cafemenu-tree.c" , 2541, ((const char*) (__func__)), "menu_layout_node_get_type (menu) == MENU_LAYOUT_NODE_MENU" ); } while (0); |
2542 | |
2543 | if (add_menu_for_legacy_dir (to_merge, |
2544 | menu_layout_node_get_content (legacy), |
2545 | NULL((void*)0), |
2546 | menu_layout_node_legacy_dir_get_prefix (legacy), |
2547 | menu_layout_node_menu_get_name (menu))) |
2548 | { |
2549 | merge_resolved_children (tree, loaded_menu_files, legacy, to_merge); |
2550 | } |
2551 | |
2552 | menu_layout_node_unref (to_merge); |
2553 | } |
2554 | |
2555 | static MenuLayoutNode * |
2556 | add_legacy_dir (CafeMenuTree *tree, |
2557 | GHashTable *loaded_menu_files, |
2558 | MenuLayoutNode *before, |
2559 | const char *data_dir) |
2560 | { |
2561 | MenuLayoutNode *legacy; |
2562 | char *dirname; |
2563 | |
2564 | dirname = g_build_filename (data_dir, "applnk", NULL((void*)0)); |
2565 | |
2566 | legacy = menu_layout_node_new (MENU_LAYOUT_NODE_LEGACY_DIR); |
2567 | menu_layout_node_set_content (legacy, dirname); |
2568 | menu_layout_node_legacy_dir_set_prefix (legacy, "kde"); |
2569 | menu_layout_node_insert_before (before, legacy); |
2570 | menu_layout_node_unref (before); |
2571 | |
2572 | menu_verbose ("Adding <LegacyDir>%s</LegacyDir> in <KDELegacyDirs/>\n", |
2573 | dirname); |
2574 | |
2575 | resolve_legacy_dir (tree, loaded_menu_files, legacy); |
2576 | |
2577 | g_free (dirname); |
2578 | |
2579 | return legacy; |
2580 | } |
2581 | |
2582 | static void |
2583 | resolve_kde_legacy_dirs (CafeMenuTree *tree, |
2584 | GHashTable *loaded_menu_files, |
2585 | MenuLayoutNode *layout) |
2586 | { |
2587 | MenuLayoutNode *before; |
2588 | const char * const *system_data_dirs; |
2589 | int i; |
2590 | |
2591 | system_data_dirs = g_get_system_data_dirs (); |
2592 | |
2593 | before = add_legacy_dir (tree, |
2594 | loaded_menu_files, |
2595 | menu_layout_node_ref (layout), |
2596 | g_get_user_data_dir ()); |
2597 | |
2598 | i = 0; |
2599 | while (system_data_dirs[i] != NULL((void*)0)) |
2600 | { |
2601 | before = add_legacy_dir (tree, loaded_menu_files, before, system_data_dirs[i]); |
2602 | |
2603 | ++i; |
2604 | } |
2605 | |
2606 | menu_layout_node_unref (before); |
2607 | |
2608 | /* remove the now-replaced node */ |
2609 | menu_layout_node_unlink (layout); |
2610 | } |
2611 | |
2612 | static void |
2613 | cafemenu_tree_resolve_files (CafeMenuTree *tree, |
2614 | GHashTable *loaded_menu_files, |
2615 | MenuLayoutNode *layout) |
2616 | { |
2617 | MenuLayoutNode *child; |
2618 | |
2619 | menu_verbose ("Resolving files in: "); |
2620 | menu_debug_print_layout (layout, TRUE); |
2621 | |
2622 | switch (menu_layout_node_get_type (layout)) |
2623 | { |
2624 | case MENU_LAYOUT_NODE_MERGE_FILE: |
2625 | resolve_merge_file (tree, loaded_menu_files, layout); |
2626 | break; |
2627 | |
2628 | case MENU_LAYOUT_NODE_MERGE_DIR: |
2629 | resolve_merge_dir (tree, loaded_menu_files, layout); |
2630 | break; |
2631 | |
2632 | case MENU_LAYOUT_NODE_DEFAULT_APP_DIRS: |
2633 | resolve_default_app_dirs (tree, layout); |
2634 | break; |
2635 | |
2636 | case MENU_LAYOUT_NODE_DEFAULT_DIRECTORY_DIRS: |
2637 | resolve_default_directory_dirs (tree, layout); |
2638 | break; |
2639 | |
2640 | case MENU_LAYOUT_NODE_DEFAULT_MERGE_DIRS: |
2641 | resolve_default_merge_dirs (tree, loaded_menu_files, layout); |
2642 | break; |
2643 | |
2644 | case MENU_LAYOUT_NODE_LEGACY_DIR: |
2645 | resolve_legacy_dir (tree, loaded_menu_files, layout); |
2646 | break; |
2647 | |
2648 | case MENU_LAYOUT_NODE_KDE_LEGACY_DIRS: |
2649 | resolve_kde_legacy_dirs (tree, loaded_menu_files, layout); |
2650 | break; |
2651 | |
2652 | case MENU_LAYOUT_NODE_PASSTHROUGH: |
2653 | /* Just get rid of these, we don't need the memory usage */ |
2654 | menu_layout_node_unlink (layout); |
2655 | break; |
2656 | |
2657 | default: |
2658 | /* Recurse */ |
2659 | child = menu_layout_node_get_children (layout); |
2660 | while (child != NULL((void*)0)) |
2661 | { |
2662 | MenuLayoutNode *next = menu_layout_node_get_next (child); |
2663 | |
2664 | cafemenu_tree_resolve_files (tree, loaded_menu_files, child); |
2665 | |
2666 | child = next; |
2667 | } |
2668 | break; |
2669 | } |
2670 | } |
2671 | |
2672 | static void |
2673 | move_children (MenuLayoutNode *from, |
2674 | MenuLayoutNode *to) |
2675 | { |
2676 | MenuLayoutNode *from_child; |
2677 | MenuLayoutNode *insert_before; |
2678 | |
2679 | insert_before = menu_layout_node_get_children (to); |
2680 | from_child = menu_layout_node_get_children (from); |
2681 | |
2682 | while (from_child != NULL((void*)0)) |
2683 | { |
2684 | MenuLayoutNode *next; |
2685 | |
2686 | next = menu_layout_node_get_next (from_child); |
2687 | |
2688 | menu_layout_node_steal (from_child); |
2689 | |
2690 | if (menu_layout_node_get_type (from_child) == MENU_LAYOUT_NODE_NAME) |
2691 | { |
2692 | ; /* just drop the Name in the old <Menu> */ |
2693 | } |
2694 | else if (insert_before) |
2695 | { |
2696 | menu_layout_node_insert_before (insert_before, from_child); |
2697 | g_assert (menu_layout_node_get_next (from_child) == insert_before)do { if (menu_layout_node_get_next (from_child) == insert_before ) ; else g_assertion_message_expr (((gchar*) 0), "cafemenu-tree.c" , 2697, ((const char*) (__func__)), "menu_layout_node_get_next (from_child) == insert_before" ); } while (0); |
2698 | } |
2699 | else |
2700 | { |
2701 | menu_layout_node_append_child (to, from_child); |
2702 | } |
2703 | |
2704 | menu_layout_node_unref (from_child); |
2705 | |
2706 | from_child = next; |
2707 | } |
2708 | } |
2709 | |
2710 | static int |
2711 | null_safe_strcmp (const char *a, |
2712 | const char *b) |
2713 | { |
2714 | if (a == NULL((void*)0) && b == NULL((void*)0)) |
2715 | return 0; |
2716 | else if (a == NULL((void*)0)) |
2717 | return -1; |
2718 | else if (b == NULL((void*)0)) |
2719 | return 1; |
2720 | else |
2721 | return strcmp (a, b); |
2722 | } |
2723 | |
2724 | static int |
2725 | node_compare_func (const void *a, |
2726 | const void *b) |
2727 | { |
2728 | MenuLayoutNode *node_a = (MenuLayoutNode*) a; |
2729 | MenuLayoutNode *node_b = (MenuLayoutNode*) b; |
2730 | MenuLayoutNodeType t_a = menu_layout_node_get_type (node_a); |
2731 | MenuLayoutNodeType t_b = menu_layout_node_get_type (node_b); |
2732 | |
2733 | if (t_a < t_b) |
2734 | return -1; |
2735 | else if (t_a > t_b) |
2736 | return 1; |
2737 | else |
2738 | { |
2739 | const char *c_a = menu_layout_node_get_content (node_a); |
2740 | const char *c_b = menu_layout_node_get_content (node_b); |
2741 | |
2742 | return null_safe_strcmp (c_a, c_b); |
2743 | } |
2744 | } |
2745 | |
2746 | static int |
2747 | node_menu_compare_func (const void *a, |
2748 | const void *b) |
2749 | { |
2750 | MenuLayoutNode *node_a = (MenuLayoutNode*) a; |
2751 | MenuLayoutNode *node_b = (MenuLayoutNode*) b; |
2752 | MenuLayoutNode *parent_a = menu_layout_node_get_parent (node_a); |
2753 | MenuLayoutNode *parent_b = menu_layout_node_get_parent (node_b); |
2754 | |
2755 | if (parent_a < parent_b) |
2756 | return -1; |
2757 | else if (parent_a > parent_b) |
2758 | return 1; |
2759 | else |
2760 | return null_safe_strcmp (menu_layout_node_menu_get_name (node_a), |
2761 | menu_layout_node_menu_get_name (node_b)); |
2762 | } |
2763 | |
2764 | static void |
2765 | cafemenu_tree_strip_duplicate_children (CafeMenuTree *tree, |
2766 | MenuLayoutNode *layout) |
2767 | { |
2768 | MenuLayoutNode *child; |
2769 | GSList *simple_nodes; |
2770 | GSList *menu_layout_nodes; |
2771 | GSList *prev; |
2772 | GSList *tmp; |
2773 | |
2774 | /* to strip dups, we find all the child nodes where |
2775 | * we want to kill dups, sort them, |
2776 | * then nuke the adjacent nodes that are equal |
2777 | */ |
2778 | |
2779 | simple_nodes = NULL((void*)0); |
2780 | menu_layout_nodes = NULL((void*)0); |
2781 | |
2782 | child = menu_layout_node_get_children (layout); |
2783 | while (child != NULL((void*)0)) |
2784 | { |
2785 | switch (menu_layout_node_get_type (child)) |
2786 | { |
2787 | /* These are dups if their content is the same */ |
2788 | case MENU_LAYOUT_NODE_APP_DIR: |
2789 | case MENU_LAYOUT_NODE_DIRECTORY_DIR: |
2790 | case MENU_LAYOUT_NODE_DIRECTORY: |
2791 | simple_nodes = g_slist_prepend (simple_nodes, child); |
2792 | break; |
2793 | |
2794 | /* These have to be merged in a more complicated way, |
2795 | * and then recursed |
2796 | */ |
2797 | case MENU_LAYOUT_NODE_MENU: |
2798 | menu_layout_nodes = g_slist_prepend (menu_layout_nodes, child); |
2799 | break; |
2800 | |
2801 | default: |
2802 | break; |
2803 | } |
2804 | |
2805 | child = menu_layout_node_get_next (child); |
2806 | } |
2807 | |
2808 | /* Note that the lists are all backward. So we want to keep |
2809 | * the items that are earlier in the list, because they were |
2810 | * later in the file |
2811 | */ |
2812 | |
2813 | /* stable sort the simple nodes */ |
2814 | simple_nodes = g_slist_sort (simple_nodes, |
2815 | node_compare_func); |
2816 | |
2817 | prev = NULL((void*)0); |
2818 | tmp = simple_nodes; |
2819 | while (tmp != NULL((void*)0)) |
2820 | { |
2821 | GSList *next = tmp->next; |
2822 | |
2823 | if (prev) |
2824 | { |
2825 | MenuLayoutNode *p = prev->data; |
2826 | MenuLayoutNode *n = tmp->data; |
2827 | |
2828 | if (node_compare_func (p, n) == 0) |
2829 | { |
2830 | /* nuke it! */ |
2831 | menu_layout_node_unlink (n); |
2832 | simple_nodes = g_slist_delete_link (simple_nodes, tmp); |
2833 | tmp = prev; |
2834 | } |
2835 | } |
2836 | |
2837 | prev = tmp; |
2838 | tmp = next; |
2839 | } |
2840 | |
2841 | g_slist_free (simple_nodes); |
2842 | simple_nodes = NULL((void*)0); |
2843 | |
2844 | /* stable sort the menu nodes (the sort includes the |
2845 | * parents of the nodes in the comparison). Remember |
2846 | * the list is backward. |
2847 | */ |
2848 | menu_layout_nodes = g_slist_sort (menu_layout_nodes, |
2849 | node_menu_compare_func); |
2850 | |
2851 | prev = NULL((void*)0); |
2852 | tmp = menu_layout_nodes; |
2853 | while (tmp != NULL((void*)0)) |
2854 | { |
2855 | GSList *next = tmp->next; |
2856 | |
2857 | if (prev) |
2858 | { |
2859 | MenuLayoutNode *p = prev->data; |
2860 | MenuLayoutNode *n = tmp->data; |
2861 | |
2862 | if (node_menu_compare_func (p, n) == 0) |
2863 | { |
2864 | /* Move children of first menu to the start of second |
2865 | * menu and nuke the first menu |
2866 | */ |
2867 | move_children (n, p); |
2868 | menu_layout_node_unlink (n); |
2869 | menu_layout_nodes = g_slist_delete_link (menu_layout_nodes, tmp); |
2870 | tmp = prev; |
2871 | } |
2872 | } |
2873 | |
2874 | prev = tmp; |
2875 | tmp = next; |
2876 | } |
2877 | |
2878 | g_slist_free (menu_layout_nodes); |
2879 | menu_layout_nodes = NULL((void*)0); |
2880 | |
2881 | /* Recursively clean up all children */ |
2882 | child = menu_layout_node_get_children (layout); |
2883 | while (child != NULL((void*)0)) |
2884 | { |
2885 | if (menu_layout_node_get_type (child) == MENU_LAYOUT_NODE_MENU) |
2886 | cafemenu_tree_strip_duplicate_children (tree, child); |
2887 | |
2888 | child = menu_layout_node_get_next (child); |
2889 | } |
2890 | } |
2891 | |
2892 | static MenuLayoutNode * |
2893 | find_submenu (MenuLayoutNode *layout, |
2894 | const char *path, |
2895 | gboolean create_if_not_found) |
2896 | { |
2897 | MenuLayoutNode *child; |
2898 | const char *slash; |
2899 | const char *next_path; |
2900 | char *name; |
2901 | |
2902 | menu_verbose (" (splitting \"%s\")\n", path); |
2903 | |
2904 | if (path[0] == '\0' || path[0] == G_DIR_SEPARATOR'/') |
2905 | return NULL((void*)0); |
2906 | |
2907 | slash = strchr (path, G_DIR_SEPARATOR'/'); |
2908 | if (slash != NULL((void*)0)) |
2909 | { |
2910 | name = g_strndup (path, slash - path); |
2911 | next_path = slash + 1; |
2912 | if (*next_path == '\0') |
2913 | next_path = NULL((void*)0); |
2914 | } |
2915 | else |
2916 | { |
2917 | name = g_strdup (path)g_strdup_inline (path); |
2918 | next_path = NULL((void*)0); |
2919 | } |
2920 | |
2921 | child = menu_layout_node_get_children (layout); |
2922 | while (child != NULL((void*)0)) |
2923 | { |
2924 | switch (menu_layout_node_get_type (child)) |
2925 | { |
2926 | case MENU_LAYOUT_NODE_MENU: |
2927 | { |
2928 | if (strcmp (name, menu_layout_node_menu_get_name (child)) == 0) |
2929 | { |
2930 | menu_verbose ("MenuNode %p found for path component \"%s\"\n", |
2931 | child, name); |
2932 | |
2933 | g_free (name); |
2934 | |
2935 | if (!next_path) |
2936 | { |
2937 | menu_verbose (" Found menu node %p parent is %p\n", |
2938 | child, layout); |
2939 | return child; |
2940 | } |
2941 | |
2942 | return find_submenu (child, next_path, create_if_not_found); |
2943 | } |
2944 | } |
2945 | break; |
2946 | |
2947 | default: |
2948 | break; |
2949 | } |
2950 | |
2951 | child = menu_layout_node_get_next (child); |
2952 | } |
2953 | |
2954 | if (create_if_not_found) |
2955 | { |
2956 | MenuLayoutNode *name_node; |
2957 | |
2958 | child = menu_layout_node_new (MENU_LAYOUT_NODE_MENU); |
2959 | menu_layout_node_append_child (layout, child); |
2960 | |
2961 | name_node = menu_layout_node_new (MENU_LAYOUT_NODE_NAME); |
2962 | menu_layout_node_set_content (name_node, name); |
2963 | menu_layout_node_append_child (child, name_node); |
2964 | menu_layout_node_unref (name_node); |
2965 | |
2966 | menu_verbose (" Created menu node %p parent is %p\n", |
2967 | child, layout); |
2968 | |
2969 | menu_layout_node_unref (child); |
2970 | g_free (name); |
2971 | |
2972 | if (!next_path) |
2973 | return child; |
2974 | |
2975 | return find_submenu (child, next_path, create_if_not_found); |
2976 | } |
2977 | else |
2978 | { |
2979 | g_free (name); |
2980 | return NULL((void*)0); |
2981 | } |
2982 | } |
2983 | |
2984 | /* To call this you first have to strip duplicate children once, |
2985 | * otherwise when you move a menu Foo to Bar then you may only |
2986 | * move one of Foo, not all the merged Foo. |
2987 | */ |
2988 | static void |
2989 | cafemenu_tree_execute_moves (CafeMenuTree *tree, |
2990 | MenuLayoutNode *layout, |
2991 | gboolean *need_remove_dups_p) |
2992 | { |
2993 | MenuLayoutNode *child; |
2994 | gboolean need_remove_dups; |
2995 | GSList *move_nodes; |
2996 | GSList *tmp; |
2997 | |
2998 | need_remove_dups = FALSE(0); |
2999 | |
3000 | move_nodes = NULL((void*)0); |
3001 | |
3002 | child = menu_layout_node_get_children (layout); |
3003 | while (child != NULL((void*)0)) |
3004 | { |
3005 | switch (menu_layout_node_get_type (child)) |
3006 | { |
3007 | case MENU_LAYOUT_NODE_MENU: |
3008 | /* Recurse - we recurse first and process the current node |
3009 | * second, as the spec dictates. |
3010 | */ |
3011 | cafemenu_tree_execute_moves (tree, child, &need_remove_dups); |
3012 | break; |
3013 | |
3014 | case MENU_LAYOUT_NODE_MOVE: |
3015 | move_nodes = g_slist_prepend (move_nodes, child); |
3016 | break; |
3017 | |
3018 | default: |
3019 | break; |
3020 | } |
3021 | |
3022 | child = menu_layout_node_get_next (child); |
3023 | } |
3024 | |
3025 | /* We need to execute the move operations in the order that they appear */ |
3026 | move_nodes = g_slist_reverse (move_nodes); |
3027 | |
3028 | tmp = move_nodes; |
3029 | while (tmp != NULL((void*)0)) |
3030 | { |
3031 | MenuLayoutNode *move_node = tmp->data; |
3032 | MenuLayoutNode *old_node; |
3033 | GSList *next = tmp->next; |
3034 | const char *old; |
3035 | const char *new; |
3036 | |
3037 | old = menu_layout_node_move_get_old (move_node); |
3038 | new = menu_layout_node_move_get_new (move_node); |
3039 | g_assert (old != NULL && new != NULL)do { if (old != ((void*)0) && new != ((void*)0)) ; else g_assertion_message_expr (((gchar*) 0), "cafemenu-tree.c", 3039 , ((const char*) (__func__)), "old != NULL && new != NULL" ); } while (0); |
3040 | |
3041 | menu_verbose ("executing <Move> old = \"%s\" new = \"%s\"\n", |
3042 | old, new); |
3043 | |
3044 | old_node = find_submenu (layout, old, FALSE(0)); |
3045 | if (old_node != NULL((void*)0)) |
3046 | { |
3047 | MenuLayoutNode *new_node; |
3048 | |
3049 | /* here we can create duplicates anywhere below the |
3050 | * node |
3051 | */ |
3052 | need_remove_dups = TRUE(!(0)); |
3053 | |
3054 | /* look up new node creating it and its parents if |
3055 | * required |
3056 | */ |
3057 | new_node = find_submenu (layout, new, TRUE(!(0))); |
3058 | g_assert (new_node != NULL)do { if (new_node != ((void*)0)) ; else g_assertion_message_expr (((gchar*) 0), "cafemenu-tree.c", 3058, ((const char*) (__func__ )), "new_node != NULL"); } while (0); |
3059 | |
3060 | move_children (old_node, new_node); |
3061 | |
3062 | menu_layout_node_unlink (old_node); |
3063 | } |
3064 | |
3065 | menu_layout_node_unlink (move_node); |
3066 | |
3067 | tmp = next; |
3068 | } |
3069 | |
3070 | g_slist_free (move_nodes); |
3071 | |
3072 | /* This oddness is to ensure we only remove dups once, |
3073 | * at the root, instead of recursing the tree over |
3074 | * and over. |
3075 | */ |
3076 | if (need_remove_dups_p) |
3077 | *need_remove_dups_p = need_remove_dups; |
3078 | else if (need_remove_dups) |
3079 | cafemenu_tree_strip_duplicate_children (tree, layout); |
3080 | } |
3081 | |
3082 | static gboolean |
3083 | cafemenu_tree_load_layout (CafeMenuTree *tree, |
3084 | GError **error) |
3085 | { |
3086 | GHashTable *loaded_menu_files; |
3087 | |
3088 | if (tree->layout) |
3089 | return TRUE(!(0)); |
3090 | |
3091 | if (!cafemenu_tree_canonicalize_path (tree, error)) |
3092 | return FALSE(0); |
3093 | |
3094 | menu_verbose ("Loading menu layout from \"%s\"\n", |
3095 | tree->canonical_path); |
3096 | |
3097 | tree->layout = menu_layout_load (tree->canonical_path, |
3098 | tree->non_prefixed_basename, |
3099 | error); |
3100 | if (!tree->layout) |
3101 | return FALSE(0); |
3102 | |
3103 | loaded_menu_files = g_hash_table_new (g_str_hash, g_str_equal); |
3104 | g_hash_table_insert (loaded_menu_files, tree->canonical_path, GUINT_TO_POINTER (TRUE)((gpointer) (gulong) ((!(0))))); |
3105 | cafemenu_tree_resolve_files (tree, loaded_menu_files, tree->layout); |
3106 | g_hash_table_destroy (loaded_menu_files); |
3107 | |
3108 | cafemenu_tree_strip_duplicate_children (tree, tree->layout); |
3109 | cafemenu_tree_execute_moves (tree, tree->layout, NULL((void*)0)); |
3110 | |
3111 | return TRUE(!(0)); |
3112 | } |
3113 | |
3114 | static void |
3115 | cafemenu_tree_force_reload (CafeMenuTree *tree) |
3116 | { |
3117 | cafemenu_tree_force_rebuild (tree); |
3118 | |
3119 | if (tree->layout) |
3120 | menu_layout_node_unref (tree->layout); |
3121 | tree->layout = NULL((void*)0); |
3122 | } |
3123 | |
3124 | typedef struct |
3125 | { |
3126 | DesktopEntrySet *set; |
3127 | const char *category; |
3128 | } GetByCategoryForeachData; |
3129 | |
3130 | static void |
3131 | get_by_category_foreach (const char *file_id, |
3132 | DesktopEntry *entry, |
3133 | GetByCategoryForeachData *data) |
3134 | { |
3135 | if (desktop_entry_has_category (entry, data->category)) |
3136 | desktop_entry_set_add_entry (data->set, entry, file_id); |
3137 | } |
3138 | |
3139 | static void |
3140 | get_by_category (DesktopEntrySet *entry_pool, |
3141 | DesktopEntrySet *set, |
3142 | const char *category) |
3143 | { |
3144 | GetByCategoryForeachData data; |
3145 | |
3146 | data.set = set; |
3147 | data.category = category; |
3148 | |
3149 | desktop_entry_set_foreach (entry_pool, |
3150 | (DesktopEntrySetForeachFunc) get_by_category_foreach, |
3151 | &data); |
3152 | } |
3153 | |
3154 | static DesktopEntrySet * |
3155 | process_include_rules (MenuLayoutNode *layout, |
3156 | DesktopEntrySet *entry_pool) |
3157 | { |
3158 | DesktopEntrySet *set = NULL((void*)0); |
3159 | |
3160 | switch (menu_layout_node_get_type (layout)) |
3161 | { |
3162 | case MENU_LAYOUT_NODE_AND: |
3163 | { |
3164 | MenuLayoutNode *child; |
3165 | |
3166 | menu_verbose ("Processing <And>\n"); |
3167 | |
3168 | child = menu_layout_node_get_children (layout); |
3169 | while (child != NULL((void*)0)) |
3170 | { |
3171 | DesktopEntrySet *child_set; |
3172 | |
3173 | child_set = process_include_rules (child, entry_pool); |
3174 | |
3175 | if (set == NULL((void*)0)) |
3176 | { |
3177 | set = child_set; |
3178 | } |
3179 | else |
3180 | { |
3181 | desktop_entry_set_intersection (set, child_set); |
3182 | desktop_entry_set_unref (child_set); |
3183 | } |
3184 | |
3185 | /* as soon as we get empty results, we can bail, |
3186 | * because it's an AND |
3187 | */ |
3188 | if (desktop_entry_set_get_count (set) == 0) |
3189 | break; |
3190 | |
3191 | child = menu_layout_node_get_next (child); |
3192 | } |
3193 | menu_verbose ("Processed <And>\n"); |
3194 | } |
3195 | break; |
3196 | |
3197 | case MENU_LAYOUT_NODE_OR: |
3198 | { |
3199 | MenuLayoutNode *child; |
3200 | |
3201 | menu_verbose ("Processing <Or>\n"); |
3202 | |
3203 | child = menu_layout_node_get_children (layout); |
3204 | while (child != NULL((void*)0)) |
3205 | { |
3206 | DesktopEntrySet *child_set; |
3207 | |
3208 | child_set = process_include_rules (child, entry_pool); |
3209 | |
3210 | if (set == NULL((void*)0)) |
3211 | { |
3212 | set = child_set; |
3213 | } |
3214 | else |
3215 | { |
3216 | desktop_entry_set_union (set, child_set); |
3217 | desktop_entry_set_unref (child_set); |
3218 | } |
3219 | |
3220 | child = menu_layout_node_get_next (child); |
3221 | } |
3222 | menu_verbose ("Processed <Or>\n"); |
3223 | } |
3224 | break; |
3225 | |
3226 | case MENU_LAYOUT_NODE_NOT: |
3227 | { |
3228 | /* First get the OR of all the rules */ |
3229 | MenuLayoutNode *child; |
3230 | |
3231 | menu_verbose ("Processing <Not>\n"); |
3232 | |
3233 | child = menu_layout_node_get_children (layout); |
3234 | while (child != NULL((void*)0)) |
3235 | { |
3236 | DesktopEntrySet *child_set; |
3237 | |
3238 | child_set = process_include_rules (child, entry_pool); |
3239 | |
3240 | if (set == NULL((void*)0)) |
3241 | { |
3242 | set = child_set; |
3243 | } |
3244 | else |
3245 | { |
3246 | desktop_entry_set_union (set, child_set); |
3247 | desktop_entry_set_unref (child_set); |
3248 | } |
3249 | |
3250 | child = menu_layout_node_get_next (child); |
3251 | } |
3252 | |
3253 | if (set != NULL((void*)0)) |
3254 | { |
3255 | DesktopEntrySet *inverted; |
3256 | |
3257 | /* Now invert the result */ |
3258 | inverted = desktop_entry_set_new (); |
3259 | desktop_entry_set_union (inverted, entry_pool); |
3260 | desktop_entry_set_subtract (inverted, set); |
3261 | desktop_entry_set_unref (set); |
3262 | set = inverted; |
3263 | } |
3264 | menu_verbose ("Processed <Not>\n"); |
3265 | } |
3266 | break; |
3267 | |
3268 | case MENU_LAYOUT_NODE_ALL: |
3269 | menu_verbose ("Processing <All>\n"); |
3270 | set = desktop_entry_set_new (); |
3271 | desktop_entry_set_union (set, entry_pool); |
3272 | menu_verbose ("Processed <All>\n"); |
3273 | break; |
3274 | |
3275 | case MENU_LAYOUT_NODE_FILENAME: |
3276 | { |
3277 | DesktopEntry *entry; |
3278 | |
3279 | menu_verbose ("Processing <Filename>%s</Filename>\n", |
3280 | menu_layout_node_get_content (layout)); |
3281 | |
3282 | entry = desktop_entry_set_lookup (entry_pool, |
3283 | menu_layout_node_get_content (layout)); |
3284 | if (entry != NULL((void*)0)) |
3285 | { |
3286 | set = desktop_entry_set_new (); |
3287 | desktop_entry_set_add_entry (set, |
3288 | entry, |
3289 | menu_layout_node_get_content (layout)); |
3290 | } |
3291 | menu_verbose ("Processed <Filename>%s</Filename>\n", |
3292 | menu_layout_node_get_content (layout)); |
3293 | } |
3294 | break; |
3295 | |
3296 | case MENU_LAYOUT_NODE_CATEGORY: |
3297 | menu_verbose ("Processing <Category>%s</Category>\n", |
3298 | menu_layout_node_get_content (layout)); |
3299 | set = desktop_entry_set_new (); |
3300 | get_by_category (entry_pool, set, menu_layout_node_get_content (layout)); |
3301 | menu_verbose ("Processed <Category>%s</Category>\n", |
3302 | menu_layout_node_get_content (layout)); |
3303 | break; |
3304 | |
3305 | default: |
3306 | break; |
3307 | } |
3308 | |
3309 | if (set == NULL((void*)0)) |
3310 | set = desktop_entry_set_new (); /* create an empty set */ |
3311 | |
3312 | menu_verbose ("Matched %d entries\n", desktop_entry_set_get_count (set)); |
3313 | |
3314 | return set; |
3315 | } |
3316 | |
3317 | static void |
3318 | collect_layout_info (MenuLayoutNode *layout, |
3319 | GSList **layout_info) |
3320 | { |
3321 | MenuLayoutNode *iter; |
3322 | |
3323 | g_slist_foreach (*layout_info, |
3324 | (GFunc) menu_layout_node_unref, |
3325 | NULL((void*)0)); |
3326 | g_slist_free (*layout_info); |
3327 | *layout_info = NULL((void*)0); |
3328 | |
3329 | iter = menu_layout_node_get_children (layout); |
3330 | while (iter != NULL((void*)0)) |
3331 | { |
3332 | switch (menu_layout_node_get_type (iter)) |
3333 | { |
3334 | case MENU_LAYOUT_NODE_MENUNAME: |
3335 | case MENU_LAYOUT_NODE_FILENAME: |
3336 | case MENU_LAYOUT_NODE_SEPARATOR: |
3337 | case MENU_LAYOUT_NODE_MERGE: |
3338 | *layout_info = g_slist_prepend (*layout_info, |
3339 | menu_layout_node_ref (iter)); |
3340 | break; |
3341 | |
3342 | default: |
3343 | break; |
3344 | } |
3345 | |
3346 | iter = menu_layout_node_get_next (iter); |
3347 | } |
3348 | |
3349 | *layout_info = g_slist_reverse (*layout_info); |
3350 | } |
3351 | |
3352 | static void |
3353 | entries_listify_foreach (const char *desktop_file_id, |
3354 | DesktopEntry *desktop_entry, |
3355 | CafeMenuTreeDirectory *directory) |
3356 | { |
3357 | directory->entries = |
3358 | g_slist_prepend (directory->entries, |
3359 | cafemenu_tree_entry_new (directory, |
3360 | desktop_entry, |
3361 | desktop_file_id, |
3362 | FALSE(0), |
3363 | FALSE(0))); |
3364 | } |
3365 | |
3366 | static void |
3367 | excluded_entries_listify_foreach (const char *desktop_file_id, |
3368 | DesktopEntry *desktop_entry, |
3369 | CafeMenuTreeDirectory *directory) |
3370 | { |
3371 | directory->entries = |
3372 | g_slist_prepend (directory->entries, |
3373 | cafemenu_tree_entry_new (directory, |
3374 | desktop_entry, |
3375 | desktop_file_id, |
3376 | TRUE(!(0)), |
3377 | FALSE(0))); |
3378 | } |
3379 | |
3380 | static void |
3381 | unallocated_entries_listify_foreach (const char *desktop_file_id, |
3382 | DesktopEntry *desktop_entry, |
3383 | CafeMenuTreeDirectory *directory) |
3384 | { |
3385 | directory->entries = |
3386 | g_slist_prepend (directory->entries, |
3387 | cafemenu_tree_entry_new (directory, |
3388 | desktop_entry, |
3389 | desktop_file_id, |
3390 | FALSE(0), |
3391 | TRUE(!(0)))); |
3392 | } |
3393 | |
3394 | static void |
3395 | set_default_layout_values (CafeMenuTreeDirectory *parent, |
3396 | CafeMenuTreeDirectory *child) |
3397 | { |
3398 | GSList *tmp; |
3399 | |
3400 | /* if the child has a defined default layout, we don't want to override its |
3401 | * values. The parent might have a non-defined layout info (ie, no child of |
3402 | * the DefaultLayout node) but it doesn't meant the default layout values |
3403 | * (ie, DefaultLayout attributes) aren't different from the global defaults. |
3404 | */ |
3405 | if (child->default_layout_info != NULL((void*)0) || |
3406 | child->default_layout_values.mask != MENU_LAYOUT_VALUES_NONE) |
3407 | return; |
3408 | |
3409 | child->default_layout_values = parent->default_layout_values; |
3410 | |
3411 | tmp = child->subdirs; |
3412 | while (tmp != NULL((void*)0)) |
3413 | { |
3414 | CafeMenuTreeDirectory *subdir = tmp->data; |
3415 | |
3416 | set_default_layout_values (child, subdir); |
3417 | |
3418 | tmp = tmp->next; |
3419 | } |
3420 | } |
3421 | |
3422 | static CafeMenuTreeDirectory * |
3423 | process_layout (CafeMenuTree *tree, |
3424 | CafeMenuTreeDirectory *parent, |
3425 | MenuLayoutNode *layout, |
3426 | DesktopEntrySet *allocated) |
3427 | { |
3428 | MenuLayoutNode *layout_iter; |
3429 | CafeMenuTreeDirectory *directory; |
3430 | DesktopEntrySet *entry_pool; |
3431 | DesktopEntrySet *entries; |
3432 | DesktopEntrySet *allocated_set; |
3433 | DesktopEntrySet *excluded_set; |
3434 | gboolean deleted; |
3435 | gboolean only_unallocated; |
3436 | GSList *tmp; |
3437 | |
3438 | g_assert (menu_layout_node_get_type (layout) == MENU_LAYOUT_NODE_MENU)do { if (menu_layout_node_get_type (layout) == MENU_LAYOUT_NODE_MENU ) ; else g_assertion_message_expr (((gchar*) 0), "cafemenu-tree.c" , 3438, ((const char*) (__func__)), "menu_layout_node_get_type (layout) == MENU_LAYOUT_NODE_MENU" ); } while (0); |
3439 | g_assert (menu_layout_node_menu_get_name (layout) != NULL)do { if (menu_layout_node_menu_get_name (layout) != ((void*)0 )) ; else g_assertion_message_expr (((gchar*) 0), "cafemenu-tree.c" , 3439, ((const char*) (__func__)), "menu_layout_node_menu_get_name (layout) != NULL" ); } while (0); |
3440 | |
3441 | directory = cafemenu_tree_directory_new (tree, parent, |
3442 | menu_layout_node_menu_get_name (layout)); |
3443 | |
3444 | menu_verbose ("=== Menu name = %s ===\n", directory->name); |
3445 | |
3446 | |
3447 | deleted = FALSE(0); |
3448 | only_unallocated = FALSE(0); |
3449 | |
3450 | entries = desktop_entry_set_new (); |
3451 | allocated_set = desktop_entry_set_new (); |
3452 | |
3453 | if (tree->flags & CAFEMENU_TREE_FLAGS_INCLUDE_EXCLUDED) |
3454 | excluded_set = desktop_entry_set_new (); |
3455 | else |
3456 | excluded_set = NULL((void*)0); |
3457 | |
3458 | entry_pool = _entry_directory_list_get_all_desktops (menu_layout_node_menu_get_app_dirs (layout)); |
3459 | |
3460 | layout_iter = menu_layout_node_get_children (layout); |
3461 | while (layout_iter != NULL((void*)0)) |
3462 | { |
3463 | switch (menu_layout_node_get_type (layout_iter)) |
3464 | { |
3465 | case MENU_LAYOUT_NODE_MENU: |
3466 | /* recurse */ |
3467 | { |
3468 | CafeMenuTreeDirectory *child_dir; |
3469 | |
3470 | menu_verbose ("Processing <Menu>\n"); |
3471 | |
3472 | child_dir = process_layout (tree, |
3473 | directory, |
3474 | layout_iter, |
3475 | allocated); |
3476 | if (child_dir) |
3477 | directory->subdirs = g_slist_prepend (directory->subdirs, |
3478 | child_dir); |
3479 | |
3480 | menu_verbose ("Processed <Menu>\n"); |
3481 | } |
3482 | break; |
3483 | |
3484 | case MENU_LAYOUT_NODE_INCLUDE: |
3485 | { |
3486 | /* The match rule children of the <Include> are |
3487 | * independent (logical OR) so we can process each one by |
3488 | * itself |
3489 | */ |
3490 | MenuLayoutNode *rule; |
3491 | |
3492 | menu_verbose ("Processing <Include> (%d entries)\n", |
3493 | desktop_entry_set_get_count (entries)); |
3494 | |
3495 | rule = menu_layout_node_get_children (layout_iter); |
3496 | while (rule != NULL((void*)0)) |
3497 | { |
3498 | DesktopEntrySet *rule_set; |
3499 | |
3500 | rule_set = process_include_rules (rule, entry_pool); |
3501 | if (rule_set != NULL((void*)0)) |
3502 | { |
3503 | desktop_entry_set_union (entries, rule_set); |
3504 | desktop_entry_set_union (allocated_set, rule_set); |
3505 | if (excluded_set != NULL((void*)0)) |
3506 | desktop_entry_set_subtract (excluded_set, rule_set); |
3507 | desktop_entry_set_unref (rule_set); |
3508 | } |
3509 | |
3510 | rule = menu_layout_node_get_next (rule); |
3511 | } |
3512 | |
3513 | menu_verbose ("Processed <Include> (%d entries)\n", |
3514 | desktop_entry_set_get_count (entries)); |
3515 | } |
3516 | break; |
3517 | |
3518 | case MENU_LAYOUT_NODE_EXCLUDE: |
3519 | { |
3520 | /* The match rule children of the <Exclude> are |
3521 | * independent (logical OR) so we can process each one by |
3522 | * itself |
3523 | */ |
3524 | MenuLayoutNode *rule; |
3525 | |
3526 | menu_verbose ("Processing <Exclude> (%d entries)\n", |
3527 | desktop_entry_set_get_count (entries)); |
3528 | |
3529 | rule = menu_layout_node_get_children (layout_iter); |
3530 | while (rule != NULL((void*)0)) |
3531 | { |
3532 | DesktopEntrySet *rule_set; |
3533 | |
3534 | rule_set = process_include_rules (rule, entry_pool); |
3535 | if (rule_set != NULL((void*)0)) |
3536 | { |
3537 | if (excluded_set != NULL((void*)0)) |
3538 | desktop_entry_set_union (excluded_set, rule_set); |
3539 | desktop_entry_set_subtract (entries, rule_set); |
3540 | desktop_entry_set_unref (rule_set); |
3541 | } |
3542 | |
3543 | rule = menu_layout_node_get_next (rule); |
3544 | } |
3545 | |
3546 | menu_verbose ("Processed <Exclude> (%d entries)\n", |
3547 | desktop_entry_set_get_count (entries)); |
3548 | } |
3549 | break; |
3550 | |
3551 | case MENU_LAYOUT_NODE_DIRECTORY: |
3552 | { |
3553 | DesktopEntry *entry; |
3554 | |
3555 | menu_verbose ("Processing <Directory>%s</Directory>\n", |
3556 | menu_layout_node_get_content (layout_iter)); |
3557 | |
3558 | /* |
3559 | * The last <Directory> to exist wins, so we always try overwriting |
3560 | */ |
3561 | entry = entry_directory_list_get_directory (menu_layout_node_menu_get_directory_dirs (layout), |
3562 | menu_layout_node_get_content (layout_iter)); |
3563 | |
3564 | if (entry != NULL((void*)0)) |
3565 | { |
3566 | if (!desktop_entry_get_hidden (entry)) |
3567 | { |
3568 | if (directory->directory_entry) |
3569 | desktop_entry_unref (directory->directory_entry); |
3570 | directory->directory_entry = entry; /* pass ref ownership */ |
3571 | } |
3572 | else |
3573 | { |
3574 | desktop_entry_unref (entry); |
3575 | } |
3576 | } |
3577 | |
3578 | menu_verbose ("Processed <Directory> new directory entry = %p (%s)\n", |
3579 | directory->directory_entry, |
3580 | directory->directory_entry? desktop_entry_get_path (directory->directory_entry) : "null"); |
3581 | } |
3582 | break; |
3583 | |
3584 | case MENU_LAYOUT_NODE_DELETED: |
3585 | menu_verbose ("Processed <Deleted/>\n"); |
3586 | deleted = TRUE(!(0)); |
3587 | break; |
3588 | |
3589 | case MENU_LAYOUT_NODE_NOT_DELETED: |
3590 | menu_verbose ("Processed <NotDeleted/>\n"); |
3591 | deleted = FALSE(0); |
3592 | break; |
3593 | |
3594 | case MENU_LAYOUT_NODE_ONLY_UNALLOCATED: |
3595 | menu_verbose ("Processed <OnlyUnallocated/>\n"); |
3596 | only_unallocated = TRUE(!(0)); |
3597 | break; |
3598 | |
3599 | case MENU_LAYOUT_NODE_NOT_ONLY_UNALLOCATED: |
3600 | menu_verbose ("Processed <NotOnlyUnallocated/>\n"); |
3601 | only_unallocated = FALSE(0); |
3602 | break; |
3603 | |
3604 | case MENU_LAYOUT_NODE_DEFAULT_LAYOUT: |
3605 | menu_layout_node_default_layout_get_values (layout_iter, |
3606 | &directory->default_layout_values); |
3607 | collect_layout_info (layout_iter, &directory->default_layout_info); |
3608 | menu_verbose ("Processed <DefaultLayout/>\n"); |
3609 | break; |
3610 | |
3611 | case MENU_LAYOUT_NODE_LAYOUT: |
3612 | collect_layout_info (layout_iter, &directory->layout_info); |
3613 | menu_verbose ("Processed <Layout/>\n"); |
3614 | break; |
3615 | |
3616 | default: |
3617 | break; |
3618 | } |
3619 | |
3620 | layout_iter = menu_layout_node_get_next (layout_iter); |
3621 | } |
3622 | |
3623 | desktop_entry_set_unref (entry_pool); |
3624 | |
3625 | directory->only_unallocated = only_unallocated; |
3626 | |
3627 | if (!directory->only_unallocated) |
3628 | desktop_entry_set_union (allocated, allocated_set); |
3629 | |
3630 | desktop_entry_set_unref (allocated_set); |
3631 | |
3632 | if (directory->directory_entry) |
3633 | { |
3634 | if (desktop_entry_get_no_display (directory->directory_entry)) |
3635 | { |
3636 | directory->is_nodisplay = TRUE(!(0)); |
3637 | |
3638 | if (!(tree->flags & CAFEMENU_TREE_FLAGS_INCLUDE_NODISPLAY)) |
3639 | { |
3640 | menu_verbose ("Not showing menu %s because NoDisplay=true\n", |
3641 | desktop_entry_get_name (directory->directory_entry)); |
3642 | deleted = TRUE(!(0)); |
3643 | } |
3644 | } |
3645 | |
3646 | if (!desktop_entry_get_show_in (directory->directory_entry)) |
3647 | { |
3648 | menu_verbose ("Not showing menu %s because OnlyShowIn!=$DESKTOP or NotShowIn=$DESKTOP (with $DESKTOP=${XDG_CURRENT_DESKTOP:-GNOME})\n", |
3649 | desktop_entry_get_name (directory->directory_entry)); |
3650 | deleted = TRUE(!(0)); |
3651 | } |
3652 | } |
3653 | |
3654 | if (deleted) |
3655 | { |
3656 | if (excluded_set != NULL((void*)0)) |
3657 | desktop_entry_set_unref (excluded_set); |
3658 | desktop_entry_set_unref (entries); |
3659 | cafemenu_tree_item_unref (directory); |
3660 | return NULL((void*)0); |
3661 | } |
3662 | |
3663 | desktop_entry_set_foreach (entries, |
3664 | (DesktopEntrySetForeachFunc) entries_listify_foreach, |
3665 | directory); |
3666 | desktop_entry_set_unref (entries); |
3667 | |
3668 | if (excluded_set != NULL((void*)0)) |
3669 | { |
3670 | desktop_entry_set_foreach (excluded_set, |
3671 | (DesktopEntrySetForeachFunc) excluded_entries_listify_foreach, |
3672 | directory); |
3673 | desktop_entry_set_unref (excluded_set); |
3674 | } |
3675 | |
3676 | tmp = directory->subdirs; |
3677 | while (tmp != NULL((void*)0)) |
3678 | { |
3679 | CafeMenuTreeDirectory *subdir = tmp->data; |
3680 | |
3681 | set_default_layout_values (directory, subdir); |
3682 | |
3683 | tmp = tmp->next; |
3684 | } |
3685 | |
3686 | tmp = directory->entries; |
3687 | while (tmp != NULL((void*)0)) |
3688 | { |
3689 | CafeMenuTreeEntry *entry = tmp->data; |
3690 | GSList *next = tmp->next; |
3691 | gboolean delete = FALSE(0); |
3692 | |
3693 | /* If adding a new condition to delete here, it has to be added to |
3694 | * get_still_unallocated_foreach() too */ |
3695 | |
3696 | if (desktop_entry_get_hidden (entry->desktop_entry)) |
3697 | { |
3698 | menu_verbose ("Deleting %s because Hidden=true\n", |
3699 | desktop_entry_get_name (entry->desktop_entry)); |
3700 | delete = TRUE(!(0)); |
3701 | } |
3702 | |
3703 | if (!(tree->flags & CAFEMENU_TREE_FLAGS_INCLUDE_NODISPLAY) && |
3704 | desktop_entry_get_no_display (entry->desktop_entry)) |
3705 | { |
3706 | menu_verbose ("Deleting %s because NoDisplay=true\n", |
3707 | desktop_entry_get_name (entry->desktop_entry)); |
3708 | delete = TRUE(!(0)); |
3709 | } |
3710 | |
3711 | if (!desktop_entry_get_show_in (entry->desktop_entry)) |
3712 | { |
3713 | menu_verbose ("Deleting %s because OnlyShowIn!=$DESKTOP or NotShowIn=$DESKTOP (with $DESKTOP=${XDG_CURRENT_DESKTOP:-GNOME})\n", |
3714 | desktop_entry_get_name (entry->desktop_entry)); |
3715 | delete = TRUE(!(0)); |
3716 | } |
3717 | |
3718 | /* No need to filter out based on TryExec since GDesktopAppInfo cannot |
3719 | * deal with .desktop files with a failed TryExec. */ |
3720 | |
3721 | if (delete) |
3722 | { |
3723 | directory->entries = g_slist_delete_link (directory->entries, |
3724 | tmp); |
3725 | cafemenu_tree_item_unref_and_unset_parent (entry); |
3726 | } |
3727 | |
3728 | tmp = next; |
3729 | } |
3730 | |
3731 | g_assert (directory->name != NULL)do { if (directory->name != ((void*)0)) ; else g_assertion_message_expr (((gchar*) 0), "cafemenu-tree.c", 3731, ((const char*) (__func__ )), "directory->name != NULL"); } while (0); |
3732 | |
3733 | return directory; |
3734 | } |
3735 | |
3736 | static void |
3737 | process_only_unallocated (CafeMenuTree *tree, |
3738 | CafeMenuTreeDirectory *directory, |
3739 | DesktopEntrySet *allocated, |
3740 | DesktopEntrySet *unallocated_used) |
3741 | { |
3742 | GSList *tmp; |
3743 | |
3744 | /* For any directory marked only_unallocated, we have to remove any |
3745 | * entries that were in fact allocated. |
3746 | */ |
3747 | |
3748 | if (directory->only_unallocated) |
3749 | { |
3750 | tmp = directory->entries; |
3751 | while (tmp != NULL((void*)0)) |
3752 | { |
3753 | CafeMenuTreeEntry *entry = tmp->data; |
3754 | GSList *next = tmp->next; |
3755 | |
3756 | if (desktop_entry_set_lookup (allocated, entry->desktop_file_id)) |
3757 | { |
3758 | directory->entries = g_slist_delete_link (directory->entries, |
3759 | tmp); |
3760 | cafemenu_tree_item_unref_and_unset_parent (entry); |
3761 | } |
3762 | else |
3763 | { |
3764 | desktop_entry_set_add_entry (unallocated_used, entry->desktop_entry, entry->desktop_file_id); |
3765 | } |
3766 | |
3767 | tmp = next; |
3768 | } |
3769 | } |
3770 | |
3771 | tmp = directory->subdirs; |
3772 | while (tmp != NULL((void*)0)) |
3773 | { |
3774 | CafeMenuTreeDirectory *subdir = tmp->data; |
3775 | |
3776 | process_only_unallocated (tree, subdir, allocated, unallocated_used); |
3777 | |
3778 | tmp = tmp->next; |
3779 | } |
3780 | } |
3781 | |
3782 | typedef struct |
3783 | { |
3784 | CafeMenuTree *tree; |
3785 | DesktopEntrySet *allocated; |
3786 | DesktopEntrySet *unallocated_used; |
3787 | DesktopEntrySet *still_unallocated; |
3788 | } GetStillUnallocatedForeachData; |
3789 | |
3790 | static void |
3791 | get_still_unallocated_foreach (const char *file_id, |
3792 | DesktopEntry *entry, |
3793 | GetStillUnallocatedForeachData *data) |
3794 | { |
3795 | if (desktop_entry_set_lookup (data->allocated, file_id)) |
3796 | return; |
3797 | |
3798 | if (desktop_entry_set_lookup (data->unallocated_used, file_id)) |
3799 | return; |
3800 | |
3801 | /* Same rules than at the end of process_layout() */ |
3802 | if (desktop_entry_get_hidden (entry)) |
3803 | return; |
3804 | |
3805 | if (!(data->tree->flags & CAFEMENU_TREE_FLAGS_INCLUDE_NODISPLAY) && |
3806 | desktop_entry_get_no_display (entry)) |
3807 | return; |
3808 | |
3809 | if (!desktop_entry_get_show_in (entry)) |
3810 | return; |
3811 | |
3812 | desktop_entry_set_add_entry (data->still_unallocated, entry, file_id); |
3813 | } |
3814 | |
3815 | static void preprocess_layout_info (CafeMenuTree *tree, |
3816 | CafeMenuTreeDirectory *directory); |
3817 | |
3818 | static GSList * |
3819 | get_layout_info (CafeMenuTreeDirectory *directory, |
3820 | gboolean *is_default_layout) |
3821 | { |
3822 | CafeMenuTreeDirectory *iter; |
3823 | |
3824 | if (directory->layout_info != NULL((void*)0)) |
3825 | { |
3826 | if (is_default_layout) |
3827 | { |
3828 | *is_default_layout = FALSE(0); |
3829 | } |
3830 | return directory->layout_info; |
3831 | } |
3832 | |
3833 | /* Even if there's no layout information at all, the result will be an |
3834 | * implicit default layout */ |
3835 | if (is_default_layout) |
3836 | { |
3837 | *is_default_layout = TRUE(!(0)); |
3838 | } |
3839 | |
3840 | iter = directory; |
3841 | while (iter != NULL((void*)0)) |
3842 | { |
3843 | /* FIXME: this is broken: we might skip real parent in the |
3844 | * XML structure, that are hidden because of inlining. */ |
3845 | if (iter->default_layout_info != NULL((void*)0)) |
3846 | { |
3847 | return iter->default_layout_info; |
3848 | } |
3849 | |
3850 | iter = CAFEMENU_TREE_ITEM (iter)((CafeMenuTreeItem *)(iter))->parent; |
3851 | } |
3852 | |
3853 | return NULL((void*)0); |
3854 | } |
3855 | |
3856 | static void |
3857 | get_values_with_defaults (MenuLayoutNode *node, |
3858 | MenuLayoutValues *layout_values, |
3859 | MenuLayoutValues *default_layout_values) |
3860 | { |
3861 | menu_layout_node_menuname_get_values (node, layout_values); |
3862 | |
3863 | if (!(layout_values->mask & MENU_LAYOUT_VALUES_SHOW_EMPTY)) |
3864 | layout_values->show_empty = default_layout_values->show_empty; |
3865 | |
3866 | if (!(layout_values->mask & MENU_LAYOUT_VALUES_INLINE_MENUS)) |
3867 | layout_values->inline_menus = default_layout_values->inline_menus; |
3868 | |
3869 | if (!(layout_values->mask & MENU_LAYOUT_VALUES_INLINE_LIMIT)) |
3870 | layout_values->inline_limit = default_layout_values->inline_limit; |
3871 | |
3872 | if (!(layout_values->mask & MENU_LAYOUT_VALUES_INLINE_HEADER)) |
3873 | layout_values->inline_header = default_layout_values->inline_header; |
3874 | |
3875 | if (!(layout_values->mask & MENU_LAYOUT_VALUES_INLINE_ALIAS)) |
3876 | layout_values->inline_alias = default_layout_values->inline_alias; |
3877 | } |
3878 | |
3879 | static guint |
3880 | get_real_subdirs_len (CafeMenuTreeDirectory *directory) |
3881 | { |
3882 | guint len; |
3883 | GSList *tmp; |
3884 | |
3885 | len = 0; |
3886 | |
3887 | tmp = directory->subdirs; |
3888 | while (tmp != NULL((void*)0)) |
3889 | { |
3890 | CafeMenuTreeDirectory *subdir = tmp->data; |
3891 | |
3892 | tmp = tmp->next; |
3893 | |
3894 | if (subdir->will_inline_header != G_MAXUINT16((guint16) 0xffff)) |
3895 | { |
3896 | len += get_real_subdirs_len (subdir) + g_slist_length (subdir->entries) + 1; |
3897 | } |
3898 | else |
3899 | len += 1; |
3900 | } |
3901 | |
3902 | return len; |
3903 | } |
3904 | |
3905 | static void |
3906 | preprocess_layout_info_subdir_helper (CafeMenuTree *tree, |
3907 | CafeMenuTreeDirectory *directory, |
3908 | CafeMenuTreeDirectory *subdir, |
3909 | MenuLayoutValues *layout_values, |
3910 | gboolean *contents_added, |
3911 | gboolean *should_remove) |
3912 | { |
3913 | preprocess_layout_info (tree, subdir); |
3914 | |
3915 | *should_remove = FALSE(0); |
3916 | *contents_added = FALSE(0); |
3917 | |
3918 | if (subdir->subdirs == NULL((void*)0) && subdir->entries == NULL((void*)0)) |
3919 | { |
3920 | if (!(tree->flags & CAFEMENU_TREE_FLAGS_SHOW_EMPTY) && |
3921 | !layout_values->show_empty) |
3922 | { |
3923 | menu_verbose ("Not showing empty menu '%s'\n", subdir->name); |
3924 | *should_remove = TRUE(!(0)); |
3925 | } |
3926 | } |
3927 | |
3928 | else if (layout_values->inline_menus) |
3929 | { |
3930 | guint real_subdirs_len; |
3931 | |
3932 | real_subdirs_len = get_real_subdirs_len (subdir); |
3933 | |
3934 | if (layout_values->inline_alias && |
3935 | real_subdirs_len + g_slist_length (subdir->entries) == 1) |
3936 | { |
3937 | CafeMenuTreeAlias *alias; |
3938 | CafeMenuTreeItem *item; |
3939 | GSList *list; |
3940 | |
3941 | if (subdir->subdirs != NULL((void*)0)) |
3942 | list = subdir->subdirs; |
3943 | else |
3944 | list = subdir->entries; |
3945 | |
3946 | item = CAFEMENU_TREE_ITEM (list->data)((CafeMenuTreeItem *)(list->data)); |
3947 | |
3948 | menu_verbose ("Inline aliasing '%s' to '%s'\n", |
3949 | item->type == CAFEMENU_TREE_ITEM_ENTRY ? |
3950 | g_app_info_get_name (G_APP_INFO (cafemenu_tree_entry_get_app_info (CAFEMENU_TREE_ENTRY (item)))) : |
3951 | (item->type == CAFEMENU_TREE_ITEM_DIRECTORY ? |
3952 | cafemenu_tree_directory_get_name (CAFEMENU_TREE_DIRECTORY (item)) : |
3953 | cafemenu_tree_directory_get_name (CAFEMENU_TREE_ALIAS (item)->directory)), |
3954 | subdir->name); |
3955 | |
3956 | alias = cafemenu_tree_alias_new (directory, subdir, item); |
3957 | |
3958 | g_slist_foreach (list, |
3959 | (GFunc) cafemenu_tree_item_unref_and_unset_parent, |
3960 | NULL((void*)0)); |
3961 | g_slist_free (list); |
3962 | subdir->subdirs = NULL((void*)0); |
3963 | subdir->entries = NULL((void*)0); |
3964 | |
3965 | if (item->type == CAFEMENU_TREE_ITEM_DIRECTORY) |
3966 | directory->subdirs = g_slist_append (directory->subdirs, alias); |
3967 | else |
3968 | directory->entries = g_slist_append (directory->entries, alias); |
3969 | |
3970 | *contents_added = TRUE(!(0)); |
3971 | *should_remove = TRUE(!(0)); |
3972 | } |
3973 | |
3974 | else if (layout_values->inline_limit == 0 || |
3975 | layout_values->inline_limit >= real_subdirs_len + g_slist_length (subdir->entries)) |
3976 | { |
3977 | if (layout_values->inline_header) |
3978 | { |
3979 | menu_verbose ("Creating inline header with name '%s'\n", subdir->name); |
3980 | /* we're limited to 16-bits to spare some memory; if the limit is |
3981 | * higher than that (would be crazy), we just consider it's |
3982 | * unlimited */ |
3983 | if (layout_values->inline_limit < G_MAXUINT16((guint16) 0xffff)) |
3984 | subdir->will_inline_header = layout_values->inline_limit; |
3985 | else |
3986 | subdir->will_inline_header = 0; |
3987 | } |
3988 | else |
3989 | { |
3990 | g_slist_foreach (subdir->subdirs, |
3991 | (GFunc) cafemenu_tree_item_set_parent, |
3992 | directory); |
3993 | directory->subdirs = g_slist_concat (directory->subdirs, |
3994 | subdir->subdirs); |
3995 | subdir->subdirs = NULL((void*)0); |
3996 | |
3997 | g_slist_foreach (subdir->entries, |
3998 | (GFunc) cafemenu_tree_item_set_parent, |
3999 | directory); |
4000 | directory->entries = g_slist_concat (directory->entries, |
4001 | subdir->entries); |
4002 | subdir->entries = NULL((void*)0); |
4003 | |
4004 | *contents_added = TRUE(!(0)); |
4005 | *should_remove = TRUE(!(0)); |
4006 | } |
4007 | |
4008 | menu_verbose ("Inlining directory contents of '%s' to '%s'\n", |
4009 | subdir->name, directory->name); |
4010 | } |
4011 | } |
4012 | } |
4013 | |
4014 | static void |
4015 | preprocess_layout_info (CafeMenuTree *tree, |
4016 | CafeMenuTreeDirectory *directory) |
4017 | { |
4018 | GSList *tmp; |
4019 | GSList *layout_info; |
4020 | gboolean using_default_layout; |
4021 | GSList *last_subdir; |
4022 | gboolean strip_duplicates; |
4023 | gboolean contents_added; |
4024 | gboolean should_remove; |
4025 | GSList *subdirs_sentinel; |
4026 | |
4027 | /* Note: we need to preprocess all menus, even if the layout mask for a menu |
4028 | * is MENU_LAYOUT_VALUES_NONE: in this case, we need to remove empty menus; |
4029 | * and the layout mask can be different for a submenu anyway */ |
4030 | |
4031 | menu_verbose ("Processing menu layout inline hints for %s\n", directory->name); |
4032 | g_assert (!directory->preprocessed)do { if (!directory->preprocessed) ; else g_assertion_message_expr (((gchar*) 0), "cafemenu-tree.c", 4032, ((const char*) (__func__ )), "!directory->preprocessed"); } while (0); |
4033 | |
4034 | strip_duplicates = FALSE(0); |
4035 | /* we use last_subdir to track the last non-inlined subdirectory */ |
4036 | last_subdir = g_slist_last (directory->subdirs); |
4037 | |
4038 | /* |
4039 | * First process subdirectories with explicit layout |
4040 | */ |
4041 | layout_info = get_layout_info (directory, &using_default_layout); |
4042 | tmp = layout_info; |
4043 | /* see comment below about Menuname to understand why we leave the loop if |
4044 | * last_subdir is NULL */ |
4045 | while (tmp != NULL((void*)0) && last_subdir != NULL((void*)0)) |
4046 | { |
4047 | MenuLayoutNode *node = tmp->data; |
4048 | MenuLayoutValues layout_values; |
4049 | const char *name; |
4050 | CafeMenuTreeDirectory *subdir; |
4051 | GSList *subdir_l; |
4052 | |
4053 | tmp = tmp->next; |
4054 | |
4055 | /* only Menuname nodes are relevant here */ |
4056 | if (menu_layout_node_get_type (node) != MENU_LAYOUT_NODE_MENUNAME) |
4057 | continue; |
4058 | |
4059 | get_values_with_defaults (node, |
4060 | &layout_values, |
4061 | &directory->default_layout_values); |
4062 | |
4063 | /* find the subdirectory that is affected by those attributes */ |
4064 | name = menu_layout_node_get_content (node); |
4065 | subdir = NULL((void*)0); |
4066 | subdir_l = directory->subdirs; |
4067 | while (subdir_l != NULL((void*)0)) |
4068 | { |
4069 | subdir = subdir_l->data; |
4070 | |
4071 | if (!strcmp (subdir->name, name)) |
4072 | break; |
4073 | |
4074 | subdir = NULL((void*)0); |
4075 | subdir_l = subdir_l->next; |
4076 | |
4077 | /* We do not want to use Menuname on a menu that appeared via |
4078 | * inlining: without inlining, the Menuname wouldn't have matched |
4079 | * anything, and we want to keep the same behavior. |
4080 | * Unless the layout is a default layout, in which case the Menuname |
4081 | * does match the subdirectory. */ |
4082 | if (!using_default_layout && subdir_l == last_subdir) |
4083 | { |
4084 | subdir_l = NULL((void*)0); |
4085 | break; |
4086 | } |
4087 | } |
4088 | |
4089 | if (subdir == NULL((void*)0)) |
4090 | continue; |
4091 | |
4092 | preprocess_layout_info_subdir_helper (tree, directory, |
4093 | subdir, &layout_values, |
4094 | &contents_added, &should_remove); |
4095 | strip_duplicates = strip_duplicates || contents_added; |
4096 | if (should_remove) |
4097 | { |
4098 | if (last_subdir == subdir_l) |
4099 | { |
4100 | /* we need to recompute last_subdir since we'll remove it from |
4101 | * the list */ |
4102 | GSList *buf; |
4103 | |
4104 | if (subdir_l == directory->subdirs) |
4105 | last_subdir = NULL((void*)0); |
4106 | else |
4107 | { |
4108 | buf = directory->subdirs; |
4109 | while (buf != NULL((void*)0) && buf->next != subdir_l) |
4110 | buf = buf->next; |
4111 | last_subdir = buf; |
4112 | } |
4113 | } |
4114 | |
4115 | directory->subdirs = g_slist_remove (directory->subdirs, subdir); |
4116 | cafemenu_tree_item_unref_and_unset_parent (CAFEMENU_TREE_ITEM (subdir)((CafeMenuTreeItem *)(subdir))); |
4117 | } |
4118 | } |
4119 | |
4120 | /* |
4121 | * Now process the subdirectories with no explicit layout |
4122 | */ |
4123 | /* this is bogus data, but we just need the pointer anyway */ |
4124 | subdirs_sentinel = g_slist_prepend (directory->subdirs, PACKAGE"cafe-menus"); |
4125 | directory->subdirs = subdirs_sentinel; |
4126 | |
4127 | tmp = directory->subdirs; |
4128 | while (tmp->next != NULL((void*)0)) |
4129 | { |
4130 | CafeMenuTreeDirectory *subdir = tmp->next->data; |
4131 | |
4132 | if (subdir->preprocessed) |
4133 | { |
4134 | tmp = tmp->next; |
4135 | continue; |
4136 | } |
4137 | |
4138 | preprocess_layout_info_subdir_helper (tree, directory, |
4139 | subdir, &directory->default_layout_values, |
4140 | &contents_added, &should_remove); |
4141 | strip_duplicates = strip_duplicates || contents_added; |
4142 | if (should_remove) |
4143 | { |
4144 | tmp = g_slist_delete_link (tmp, tmp->next); |
4145 | cafemenu_tree_item_unref_and_unset_parent (CAFEMENU_TREE_ITEM (subdir)((CafeMenuTreeItem *)(subdir))); |
4146 | } |
4147 | else |
4148 | tmp = tmp->next; |
4149 | } |
4150 | |
4151 | /* remove the sentinel */ |
4152 | directory->subdirs = g_slist_delete_link (directory->subdirs, |
4153 | directory->subdirs); |
4154 | |
4155 | /* |
4156 | * Finally, remove duplicates if needed |
4157 | */ |
4158 | if (strip_duplicates) |
4159 | { |
4160 | /* strip duplicate entries; there should be no duplicate directories */ |
4161 | directory->entries = g_slist_sort (directory->entries, |
4162 | (GCompareFunc) cafemenu_tree_entry_compare_by_id); |
4163 | tmp = directory->entries; |
4164 | while (tmp != NULL((void*)0) && tmp->next != NULL((void*)0)) |
4165 | { |
4166 | CafeMenuTreeItem *a = tmp->data; |
4167 | CafeMenuTreeItem *b = tmp->next->data; |
4168 | |
4169 | if (a->type == CAFEMENU_TREE_ITEM_ALIAS) |
4170 | a = CAFEMENU_TREE_ALIAS (a)((CafeMenuTreeAlias *)(a))->aliased_item; |
4171 | |
4172 | if (b->type == CAFEMENU_TREE_ITEM_ALIAS) |
4173 | b = CAFEMENU_TREE_ALIAS (b)((CafeMenuTreeAlias *)(b))->aliased_item; |
4174 | |
4175 | if (strcmp (CAFEMENU_TREE_ENTRY (a)((CafeMenuTreeEntry *)(a))->desktop_file_id, |
4176 | CAFEMENU_TREE_ENTRY (b)((CafeMenuTreeEntry *)(b))->desktop_file_id) == 0) |
4177 | { |
4178 | tmp = g_slist_delete_link (tmp, tmp->next); |
4179 | cafemenu_tree_item_unref (b); |
4180 | } |
4181 | else |
4182 | tmp = tmp->next; |
4183 | } |
4184 | } |
4185 | |
4186 | directory->preprocessed = TRUE(!(0)); |
4187 | } |
4188 | |
4189 | static void process_layout_info (CafeMenuTree *tree, |
4190 | CafeMenuTreeDirectory *directory); |
4191 | |
4192 | static void |
4193 | check_pending_separator (CafeMenuTreeDirectory *directory) |
4194 | { |
4195 | if (directory->layout_pending_separator) |
4196 | { |
4197 | menu_verbose ("Adding pending separator in '%s'\n", directory->name); |
4198 | |
4199 | directory->contents = g_slist_append (directory->contents, |
4200 | cafemenu_tree_separator_new (directory)); |
4201 | directory->layout_pending_separator = FALSE(0); |
4202 | } |
4203 | } |
4204 | |
4205 | static void |
4206 | merge_alias (CafeMenuTree *tree, |
4207 | CafeMenuTreeDirectory *directory, |
4208 | CafeMenuTreeAlias *alias) |
4209 | { |
4210 | menu_verbose ("Merging alias '%s' in directory '%s'\n", |
4211 | alias->directory->name, directory->name); |
4212 | |
4213 | if (alias->aliased_item->type == CAFEMENU_TREE_ITEM_DIRECTORY) |
4214 | { |
4215 | process_layout_info (tree, CAFEMENU_TREE_DIRECTORY (alias->aliased_item)((CafeMenuTreeDirectory *)(alias->aliased_item))); |
4216 | } |
4217 | |
4218 | check_pending_separator (directory); |
4219 | |
4220 | directory->contents = g_slist_append (directory->contents, |
4221 | cafemenu_tree_item_ref (alias)); |
4222 | } |
4223 | |
4224 | static void |
4225 | merge_subdir (CafeMenuTree *tree, |
4226 | CafeMenuTreeDirectory *directory, |
4227 | CafeMenuTreeDirectory *subdir) |
4228 | { |
4229 | menu_verbose ("Merging subdir '%s' in directory '%s'\n", |
4230 | subdir->name, directory->name); |
4231 | |
4232 | process_layout_info (tree, subdir); |
4233 | |
4234 | check_pending_separator (directory); |
4235 | |
4236 | if (subdir->will_inline_header == 0 || |
4237 | (subdir->will_inline_header != G_MAXUINT16((guint16) 0xffff) && |
4238 | g_slist_length (subdir->contents) <= subdir->will_inline_header)) |
4239 | { |
4240 | CafeMenuTreeHeader *header; |
4241 | |
4242 | header = cafemenu_tree_header_new (directory, subdir); |
4243 | directory->contents = g_slist_append (directory->contents, header); |
4244 | |
4245 | g_slist_foreach (subdir->contents, |
4246 | (GFunc) cafemenu_tree_item_set_parent, |
4247 | directory); |
4248 | directory->contents = g_slist_concat (directory->contents, |
4249 | subdir->contents); |
4250 | subdir->contents = NULL((void*)0); |
4251 | subdir->will_inline_header = G_MAXUINT16((guint16) 0xffff); |
4252 | |
4253 | cafemenu_tree_item_set_parent (CAFEMENU_TREE_ITEM (subdir)((CafeMenuTreeItem *)(subdir)), NULL((void*)0)); |
4254 | } |
4255 | else |
4256 | { |
4257 | directory->contents = g_slist_append (directory->contents, |
4258 | cafemenu_tree_item_ref (subdir)); |
4259 | } |
4260 | } |
4261 | |
4262 | static void |
4263 | merge_subdir_by_name (CafeMenuTree *tree, |
4264 | CafeMenuTreeDirectory *directory, |
4265 | const char *subdir_name) |
4266 | { |
4267 | GSList *tmp; |
4268 | |
4269 | menu_verbose ("Attempting to merge subdir '%s' in directory '%s'\n", |
4270 | subdir_name, directory->name); |
4271 | |
4272 | tmp = directory->subdirs; |
4273 | while (tmp != NULL((void*)0)) |
4274 | { |
4275 | CafeMenuTreeDirectory *subdir = tmp->data; |
4276 | GSList *next = tmp->next; |
4277 | |
4278 | /* if it's an alias, then it cannot be affected by |
4279 | * the Merge nodes in the layout */ |
4280 | if (CAFEMENU_TREE_ITEM (subdir)((CafeMenuTreeItem *)(subdir))->type == CAFEMENU_TREE_ITEM_ALIAS) |
4281 | continue; |
4282 | |
4283 | if (!strcmp (subdir->name, subdir_name)) |
4284 | { |
4285 | directory->subdirs = g_slist_delete_link (directory->subdirs, tmp); |
4286 | merge_subdir (tree, directory, subdir); |
4287 | cafemenu_tree_item_unref (subdir); |
4288 | } |
4289 | |
4290 | tmp = next; |
4291 | } |
4292 | } |
4293 | |
4294 | static void |
4295 | merge_entry (CafeMenuTree *tree G_GNUC_UNUSED__attribute__ ((__unused__)), |
4296 | CafeMenuTreeDirectory *directory, |
4297 | CafeMenuTreeEntry *entry) |
4298 | { |
4299 | menu_verbose ("Merging entry '%s' in directory '%s'\n", |
4300 | entry->desktop_file_id, directory->name); |
4301 | |
4302 | check_pending_separator (directory); |
4303 | directory->contents = g_slist_append (directory->contents, |
4304 | cafemenu_tree_item_ref (entry)); |
4305 | } |
4306 | |
4307 | static void |
4308 | merge_entry_by_id (CafeMenuTree *tree, |
4309 | CafeMenuTreeDirectory *directory, |
4310 | const char *file_id) |
4311 | { |
4312 | GSList *tmp; |
4313 | |
4314 | menu_verbose ("Attempting to merge entry '%s' in directory '%s'\n", |
4315 | file_id, directory->name); |
4316 | |
4317 | tmp = directory->entries; |
4318 | while (tmp != NULL((void*)0)) |
4319 | { |
4320 | CafeMenuTreeEntry *entry = tmp->data; |
4321 | GSList *next = tmp->next; |
4322 | |
4323 | /* if it's an alias, then it cannot be affected by |
4324 | * the Merge nodes in the layout */ |
4325 | if (CAFEMENU_TREE_ITEM (entry)((CafeMenuTreeItem *)(entry))->type == CAFEMENU_TREE_ITEM_ALIAS) |
4326 | continue; |
4327 | |
4328 | if (!strcmp (entry->desktop_file_id, file_id)) |
4329 | { |
4330 | directory->entries = g_slist_delete_link (directory->entries, tmp); |
4331 | merge_entry (tree, directory, entry); |
4332 | cafemenu_tree_item_unref (entry); |
4333 | } |
4334 | |
4335 | tmp = next; |
4336 | } |
4337 | } |
4338 | |
4339 | static inline gboolean |
4340 | find_name_in_list (const char *name, |
4341 | GSList *list) |
4342 | { |
4343 | while (list != NULL((void*)0)) |
4344 | { |
4345 | if (!strcmp (name, list->data)) |
4346 | return TRUE(!(0)); |
4347 | |
4348 | list = list->next; |
4349 | } |
4350 | |
4351 | return FALSE(0); |
4352 | } |
4353 | |
4354 | static void |
4355 | merge_subdirs (CafeMenuTree *tree, |
4356 | CafeMenuTreeDirectory *directory, |
4357 | GSList *except) |
4358 | { |
4359 | GSList *subdirs; |
4360 | GSList *tmp; |
4361 | |
4362 | menu_verbose ("Merging subdirs in directory '%s'\n", directory->name); |
4363 | |
4364 | subdirs = directory->subdirs; |
4365 | directory->subdirs = NULL((void*)0); |
4366 | |
4367 | subdirs = g_slist_sort_with_data (subdirs, |
4368 | (GCompareDataFunc) cafemenu_tree_item_compare, |
4369 | GINT_TO_POINTER (CAFEMENU_TREE_FLAGS_NONE)((gpointer) (glong) (CAFEMENU_TREE_FLAGS_NONE))); |
4370 | |
4371 | tmp = subdirs; |
4372 | while (tmp != NULL((void*)0)) |
4373 | { |
4374 | CafeMenuTreeDirectory *subdir = tmp->data; |
4375 | |
4376 | if (CAFEMENU_TREE_ITEM (subdir)((CafeMenuTreeItem *)(subdir))->type == CAFEMENU_TREE_ITEM_ALIAS) |
4377 | { |
4378 | merge_alias (tree, directory, CAFEMENU_TREE_ALIAS (subdir)((CafeMenuTreeAlias *)(subdir))); |
4379 | cafemenu_tree_item_unref (subdir); |
4380 | } |
4381 | else if (!find_name_in_list (subdir->name, except)) |
4382 | { |
4383 | merge_subdir (tree, directory, subdir); |
4384 | cafemenu_tree_item_unref (subdir); |
4385 | } |
4386 | else |
4387 | { |
4388 | menu_verbose ("Not merging directory '%s' yet\n", subdir->name); |
4389 | directory->subdirs = g_slist_append (directory->subdirs, subdir); |
4390 | } |
4391 | |
4392 | tmp = tmp->next; |
4393 | } |
4394 | |
4395 | g_slist_free (subdirs); |
4396 | g_slist_free (except); |
4397 | } |
4398 | |
4399 | static void |
4400 | merge_entries (CafeMenuTree *tree, |
4401 | CafeMenuTreeDirectory *directory, |
4402 | GSList *except) |
4403 | { |
4404 | GSList *entries; |
4405 | GSList *tmp; |
4406 | |
4407 | menu_verbose ("Merging entries in directory '%s'\n", directory->name); |
4408 | |
4409 | entries = directory->entries; |
4410 | directory->entries = NULL((void*)0); |
4411 | |
4412 | entries = g_slist_sort_with_data (entries, |
4413 | (GCompareDataFunc) cafemenu_tree_item_compare, |
4414 | GINT_TO_POINTER (tree->flags)((gpointer) (glong) (tree->flags))); |
4415 | |
4416 | tmp = entries; |
4417 | while (tmp != NULL((void*)0)) |
4418 | { |
4419 | CafeMenuTreeEntry *entry = tmp->data; |
4420 | |
4421 | if (CAFEMENU_TREE_ITEM (entry)((CafeMenuTreeItem *)(entry))->type == CAFEMENU_TREE_ITEM_ALIAS) |
4422 | { |
4423 | merge_alias (tree, directory, CAFEMENU_TREE_ALIAS (entry)((CafeMenuTreeAlias *)(entry))); |
4424 | cafemenu_tree_item_unref (entry); |
4425 | } |
4426 | else if (!find_name_in_list (entry->desktop_file_id, except)) |
4427 | { |
4428 | merge_entry (tree, directory, entry); |
4429 | cafemenu_tree_item_unref (entry); |
4430 | } |
4431 | else |
4432 | { |
4433 | menu_verbose ("Not merging entry '%s' yet\n", entry->desktop_file_id); |
4434 | directory->entries = g_slist_append (directory->entries, entry); |
4435 | } |
4436 | |
4437 | tmp = tmp->next; |
4438 | } |
4439 | |
4440 | g_slist_free (entries); |
4441 | g_slist_free (except); |
4442 | } |
4443 | |
4444 | static void |
4445 | merge_subdirs_and_entries (CafeMenuTree *tree, |
4446 | CafeMenuTreeDirectory *directory, |
4447 | GSList *except_subdirs, |
4448 | GSList *except_entries) |
4449 | { |
4450 | GSList *items; |
4451 | GSList *tmp; |
4452 | |
4453 | menu_verbose ("Merging subdirs and entries together in directory %s\n", |
4454 | directory->name); |
4455 | |
4456 | items = g_slist_concat (directory->subdirs, directory->entries); |
4457 | |
4458 | directory->subdirs = NULL((void*)0); |
4459 | directory->entries = NULL((void*)0); |
4460 | |
4461 | items = g_slist_sort_with_data (items, |
4462 | (GCompareDataFunc) cafemenu_tree_item_compare, |
4463 | GINT_TO_POINTER (tree->flags)((gpointer) (glong) (tree->flags))); |
4464 | |
4465 | tmp = items; |
4466 | while (tmp != NULL((void*)0)) |
4467 | { |
4468 | CafeMenuTreeItem *item = tmp->data; |
4469 | CafeMenuTreeItemType type; |
4470 | |
4471 | type = item->type; |
4472 | |
4473 | if (type == CAFEMENU_TREE_ITEM_ALIAS) |
4474 | { |
4475 | merge_alias (tree, directory, CAFEMENU_TREE_ALIAS (item)((CafeMenuTreeAlias *)(item))); |
4476 | cafemenu_tree_item_unref (item); |
4477 | } |
4478 | else if (type == CAFEMENU_TREE_ITEM_DIRECTORY) |
4479 | { |
4480 | if (!find_name_in_list (CAFEMENU_TREE_DIRECTORY (item)((CafeMenuTreeDirectory *)(item))->name, except_subdirs)) |
4481 | { |
4482 | merge_subdir (tree, |
4483 | directory, |
4484 | CAFEMENU_TREE_DIRECTORY (item)((CafeMenuTreeDirectory *)(item))); |
4485 | cafemenu_tree_item_unref (item); |
4486 | } |
4487 | else |
4488 | { |
4489 | menu_verbose ("Not merging directory '%s' yet\n", |
4490 | CAFEMENU_TREE_DIRECTORY (item)->name); |
4491 | directory->subdirs = g_slist_append (directory->subdirs, item); |
4492 | } |
4493 | } |
4494 | else if (type == CAFEMENU_TREE_ITEM_ENTRY) |
4495 | { |
4496 | if (!find_name_in_list (CAFEMENU_TREE_ENTRY (item)((CafeMenuTreeEntry *)(item))->desktop_file_id, except_entries)) |
4497 | { |
4498 | merge_entry (tree, directory, CAFEMENU_TREE_ENTRY (item)((CafeMenuTreeEntry *)(item))); |
4499 | cafemenu_tree_item_unref (item); |
4500 | } |
4501 | else |
4502 | { |
4503 | menu_verbose ("Not merging entry '%s' yet\n", |
4504 | CAFEMENU_TREE_ENTRY (item)->desktop_file_id); |
4505 | directory->entries = g_slist_append (directory->entries, item); |
4506 | } |
4507 | } |
4508 | else |
4509 | { |
4510 | g_assert_not_reached ()do { g_assertion_message_expr (((gchar*) 0), "cafemenu-tree.c" , 4510, ((const char*) (__func__)), ((void*)0)); } while (0); |
4511 | } |
4512 | |
4513 | tmp = tmp->next; |
4514 | } |
4515 | |
4516 | g_slist_free (items); |
4517 | g_slist_free (except_subdirs); |
4518 | g_slist_free (except_entries); |
4519 | } |
4520 | |
4521 | static GSList * |
4522 | get_subdirs_from_layout_info (GSList *layout_info) |
4523 | { |
4524 | GSList *subdirs; |
4525 | GSList *tmp; |
4526 | |
4527 | subdirs = NULL((void*)0); |
4528 | |
4529 | tmp = layout_info; |
4530 | while (tmp != NULL((void*)0)) |
4531 | { |
4532 | MenuLayoutNode *node = tmp->data; |
4533 | |
4534 | if (menu_layout_node_get_type (node) == MENU_LAYOUT_NODE_MENUNAME) |
4535 | { |
4536 | subdirs = g_slist_append (subdirs, |
4537 | (char *) menu_layout_node_get_content (node)); |
4538 | } |
4539 | |
4540 | tmp = tmp->next; |
4541 | } |
4542 | |
4543 | return subdirs; |
4544 | } |
4545 | |
4546 | static GSList * |
4547 | get_entries_from_layout_info (GSList *layout_info) |
4548 | { |
4549 | GSList *entries; |
4550 | GSList *tmp; |
4551 | |
4552 | entries = NULL((void*)0); |
4553 | |
4554 | tmp = layout_info; |
4555 | while (tmp != NULL((void*)0)) |
4556 | { |
4557 | MenuLayoutNode *node = tmp->data; |
4558 | |
4559 | if (menu_layout_node_get_type (node) == MENU_LAYOUT_NODE_FILENAME) |
4560 | { |
4561 | entries = g_slist_append (entries, |
4562 | (char *) menu_layout_node_get_content (node)); |
4563 | } |
4564 | |
4565 | tmp = tmp->next; |
4566 | } |
4567 | |
4568 | return entries; |
4569 | } |
4570 | |
4571 | static void |
4572 | process_layout_info (CafeMenuTree *tree, |
4573 | CafeMenuTreeDirectory *directory) |
4574 | { |
4575 | GSList *layout_info; |
4576 | |
4577 | menu_verbose ("Processing menu layout hints for %s\n", directory->name); |
4578 | |
4579 | g_slist_foreach (directory->contents, |
4580 | (GFunc) cafemenu_tree_item_unref_and_unset_parent, |
4581 | NULL((void*)0)); |
4582 | g_slist_free (directory->contents); |
4583 | directory->contents = NULL((void*)0); |
4584 | directory->layout_pending_separator = FALSE(0); |
4585 | |
4586 | layout_info = get_layout_info (directory, NULL((void*)0)); |
4587 | |
4588 | if (layout_info == NULL((void*)0)) |
4589 | { |
4590 | merge_subdirs (tree, directory, NULL((void*)0)); |
4591 | merge_entries (tree, directory, NULL((void*)0)); |
4592 | } |
4593 | else |
4594 | { |
4595 | GSList *tmp; |
4596 | |
4597 | tmp = layout_info; |
4598 | while (tmp != NULL((void*)0)) |
4599 | { |
4600 | MenuLayoutNode *node = tmp->data; |
4601 | |
4602 | switch (menu_layout_node_get_type (node)) |
4603 | { |
4604 | case MENU_LAYOUT_NODE_MENUNAME: |
4605 | merge_subdir_by_name (tree, |
4606 | directory, |
4607 | menu_layout_node_get_content (node)); |
4608 | break; |
4609 | |
4610 | case MENU_LAYOUT_NODE_FILENAME: |
4611 | merge_entry_by_id (tree, |
4612 | directory, |
4613 | menu_layout_node_get_content (node)); |
4614 | break; |
4615 | |
4616 | case MENU_LAYOUT_NODE_SEPARATOR: |
4617 | /* Unless explicitly told to show all separators, do not show a |
4618 | * separator at the beginning of a menu. Note that we don't add |
4619 | * the separators now, and instead make it pending. This way, we |
4620 | * won't show two consecutive separators nor will we show a |
4621 | * separator at the end of a menu. */ |
4622 | if (tree->flags & CAFEMENU_TREE_FLAGS_SHOW_ALL_SEPARATORS) |
4623 | { |
4624 | directory->layout_pending_separator = TRUE(!(0)); |
4625 | check_pending_separator (directory); |
4626 | } |
4627 | else if (directory->contents) |
4628 | { |
4629 | menu_verbose ("Adding a potential separator in '%s'\n", |
4630 | directory->name); |
4631 | |
4632 | directory->layout_pending_separator = TRUE(!(0)); |
4633 | } |
4634 | else |
4635 | { |
4636 | menu_verbose ("Skipping separator at the beginning of '%s'\n", |
4637 | directory->name); |
4638 | } |
4639 | break; |
4640 | |
4641 | case MENU_LAYOUT_NODE_MERGE: |
4642 | switch (menu_layout_node_merge_get_type (node)) |
4643 | { |
4644 | case MENU_LAYOUT_MERGE_NONE: |
4645 | break; |
4646 | |
4647 | case MENU_LAYOUT_MERGE_MENUS: |
4648 | merge_subdirs (tree, |
4649 | directory, |
4650 | get_subdirs_from_layout_info (tmp->next)); |
4651 | break; |
4652 | |
4653 | case MENU_LAYOUT_MERGE_FILES: |
4654 | merge_entries (tree, |
4655 | directory, |
4656 | get_entries_from_layout_info (tmp->next)); |
4657 | break; |
4658 | |
4659 | case MENU_LAYOUT_MERGE_ALL: |
4660 | merge_subdirs_and_entries (tree, |
4661 | directory, |
4662 | get_subdirs_from_layout_info (tmp->next), |
4663 | get_entries_from_layout_info (tmp->next)); |
4664 | break; |
4665 | |
4666 | default: |
4667 | g_assert_not_reached ()do { g_assertion_message_expr (((gchar*) 0), "cafemenu-tree.c" , 4667, ((const char*) (__func__)), ((void*)0)); } while (0); |
4668 | break; |
4669 | } |
4670 | break; |
4671 | |
4672 | default: |
4673 | g_assert_not_reached ()do { g_assertion_message_expr (((gchar*) 0), "cafemenu-tree.c" , 4673, ((const char*) (__func__)), ((void*)0)); } while (0); |
4674 | break; |
4675 | } |
4676 | |
4677 | tmp = tmp->next; |
4678 | } |
4679 | } |
4680 | |
4681 | g_slist_foreach (directory->subdirs, |
4682 | (GFunc) cafemenu_tree_item_unref, |
4683 | NULL((void*)0)); |
4684 | g_slist_free (directory->subdirs); |
4685 | directory->subdirs = NULL((void*)0); |
4686 | |
4687 | g_slist_foreach (directory->entries, |
4688 | (GFunc) cafemenu_tree_item_unref, |
4689 | NULL((void*)0)); |
4690 | g_slist_free (directory->entries); |
4691 | directory->entries = NULL((void*)0); |
4692 | |
4693 | g_slist_foreach (directory->default_layout_info, |
4694 | (GFunc) menu_layout_node_unref, |
4695 | NULL((void*)0)); |
4696 | g_slist_free (directory->default_layout_info); |
4697 | directory->default_layout_info = NULL((void*)0); |
4698 | |
4699 | g_slist_foreach (directory->layout_info, |
4700 | (GFunc) menu_layout_node_unref, |
4701 | NULL((void*)0)); |
4702 | g_slist_free (directory->layout_info); |
4703 | directory->layout_info = NULL((void*)0); |
4704 | } |
4705 | |
4706 | static void |
4707 | handle_entries_changed (MenuLayoutNode *layout, |
4708 | CafeMenuTree *tree) |
4709 | { |
4710 | if (tree->layout == layout) |
4711 | { |
4712 | cafemenu_tree_force_rebuild (tree); |
4713 | cafemenu_tree_invoke_monitors (tree); |
4714 | } |
4715 | } |
4716 | |
4717 | static void |
4718 | update_entry_index (CafeMenuTree *tree, |
4719 | CafeMenuTreeDirectory *dir) |
4720 | { |
4721 | CafeMenuTreeIter *iter = cafemenu_tree_directory_iter (dir); |
4722 | CafeMenuTreeItemType next_type; |
4723 | |
4724 | while ((next_type = cafemenu_tree_iter_next (iter)) != CAFEMENU_TREE_ITEM_INVALID) |
4725 | { |
4726 | gpointer item = NULL((void*)0); |
4727 | |
4728 | switch (next_type) |
4729 | { |
4730 | case CAFEMENU_TREE_ITEM_ENTRY: |
4731 | { |
4732 | const char *id; |
4733 | |
4734 | item = cafemenu_tree_iter_get_entry (iter); |
4735 | id = cafemenu_tree_entry_get_desktop_file_id (item); |
4736 | if (id != NULL((void*)0)) |
4737 | g_hash_table_insert (tree->entries_by_id, (char*)id, item); |
4738 | } |
4739 | break; |
4740 | case CAFEMENU_TREE_ITEM_DIRECTORY: |
4741 | { |
4742 | item = cafemenu_tree_iter_get_directory (iter); |
4743 | update_entry_index (tree, (CafeMenuTreeDirectory*)item); |
4744 | } |
4745 | break; |
4746 | default: |
4747 | break; |
4748 | } |
4749 | if (item != NULL((void*)0)) |
4750 | cafemenu_tree_item_unref (item); |
4751 | } |
4752 | |
4753 | cafemenu_tree_iter_unref (iter); |
4754 | } |
4755 | |
4756 | static gboolean |
4757 | cafemenu_tree_build_from_layout (CafeMenuTree *tree, |
4758 | GError **error) |
4759 | { |
4760 | DesktopEntrySet *allocated; |
4761 | |
4762 | if (tree->root) |
4763 | return TRUE(!(0)); |
4764 | |
4765 | if (!cafemenu_tree_load_layout (tree, error)) |
4766 | return FALSE(0); |
4767 | |
4768 | menu_verbose ("Building menu tree from layout\n"); |
4769 | |
4770 | allocated = desktop_entry_set_new (); |
4771 | |
4772 | /* create the menu structure */ |
4773 | tree->root = process_layout (tree, |
4774 | NULL((void*)0), |
4775 | find_menu_child (tree->layout), |
4776 | allocated); |
4777 | if (tree->root) |
4778 | { |
4779 | DesktopEntrySet *unallocated_used; |
4780 | |
4781 | unallocated_used = desktop_entry_set_new (); |
4782 | |
4783 | process_only_unallocated (tree, tree->root, allocated, unallocated_used); |
4784 | if (tree->flags & CAFEMENU_TREE_FLAGS_INCLUDE_UNALLOCATED) |
4785 | { |
4786 | DesktopEntrySet *entry_pool; |
4787 | DesktopEntrySet *still_unallocated; |
4788 | GetStillUnallocatedForeachData data; |
4789 | |
4790 | entry_pool = _entry_directory_list_get_all_desktops (menu_layout_node_menu_get_app_dirs (find_menu_child (tree->layout))); |
4791 | still_unallocated = desktop_entry_set_new (); |
4792 | |
4793 | data.tree = tree; |
4794 | data.allocated = allocated; |
4795 | data.unallocated_used = unallocated_used; |
4796 | data.still_unallocated = still_unallocated; |
4797 | |
4798 | desktop_entry_set_foreach (entry_pool, |
4799 | (DesktopEntrySetForeachFunc) get_still_unallocated_foreach, |
4800 | &data); |
4801 | |
4802 | desktop_entry_set_unref (entry_pool); |
4803 | |
4804 | desktop_entry_set_foreach (still_unallocated, |
4805 | (DesktopEntrySetForeachFunc) unallocated_entries_listify_foreach, |
4806 | tree->root); |
4807 | |
4808 | desktop_entry_set_unref (still_unallocated); |
4809 | } |
4810 | |
4811 | desktop_entry_set_unref (unallocated_used); |
4812 | |
4813 | /* process the layout info part that can move/remove items: |
4814 | * inline, show_empty, etc. */ |
4815 | preprocess_layout_info (tree, tree->root); |
4816 | /* populate the menu structure that we got with the items, and order it |
4817 | * according to the layout info */ |
4818 | process_layout_info (tree, tree->root); |
4819 | |
4820 | update_entry_index (tree, tree->root); |
4821 | |
4822 | menu_layout_node_root_add_entries_monitor (tree->layout, |
4823 | (MenuLayoutNodeEntriesChangedFunc) handle_entries_changed, |
4824 | tree); |
4825 | } |
4826 | |
4827 | desktop_entry_set_unref (allocated); |
4828 | |
4829 | return TRUE(!(0)); |
4830 | } |
4831 | |
4832 | static void |
4833 | cafemenu_tree_force_rebuild (CafeMenuTree *tree) |
4834 | { |
4835 | if (tree->root) |
4836 | { |
4837 | g_hash_table_remove_all (tree->entries_by_id); |
4838 | cafemenu_tree_item_unref (tree->root); |
4839 | tree->root = NULL((void*)0); |
4840 | tree->loaded = FALSE(0); |
4841 | |
4842 | g_assert (tree->layout != NULL)do { if (tree->layout != ((void*)0)) ; else g_assertion_message_expr (((gchar*) 0), "cafemenu-tree.c", 4842, ((const char*) (__func__ )), "tree->layout != NULL"); } while (0); |
4843 | |
4844 | menu_layout_node_root_remove_entries_monitor (tree->layout, |
4845 | (MenuLayoutNodeEntriesChangedFunc) handle_entries_changed, |
4846 | tree); |
4847 | } |
4848 | } |
4849 | |
4850 | GType |
4851 | cafemenu_tree_iter_get_type (void) |
4852 | { |
4853 | static GType gtype = G_TYPE_INVALID((GType) ((0) << (2))); |
4854 | if (gtype == G_TYPE_INVALID((GType) ((0) << (2)))) |
4855 | { |
4856 | gtype = g_boxed_type_register_static ("CafeMenuTreeIter", |
4857 | (GBoxedCopyFunc)cafemenu_tree_iter_ref, |
4858 | (GBoxedFreeFunc)cafemenu_tree_iter_unref); |
4859 | } |
4860 | return gtype; |
4861 | } |
4862 | |
4863 | GType |
4864 | cafemenu_tree_directory_get_type (void) |
4865 | { |
4866 | static GType gtype = G_TYPE_INVALID((GType) ((0) << (2))); |
4867 | if (gtype == G_TYPE_INVALID((GType) ((0) << (2)))) |
4868 | { |
4869 | gtype = g_boxed_type_register_static ("CafeMenuTreeDirectory", |
4870 | (GBoxedCopyFunc)cafemenu_tree_item_ref, |
4871 | (GBoxedFreeFunc)cafemenu_tree_item_unref); |
4872 | } |
4873 | return gtype; |
4874 | } |
4875 | |
4876 | GType |
4877 | cafemenu_tree_entry_get_type (void) |
4878 | { |
4879 | static GType gtype = G_TYPE_INVALID((GType) ((0) << (2))); |
4880 | if (gtype == G_TYPE_INVALID((GType) ((0) << (2)))) |
4881 | { |
4882 | gtype = g_boxed_type_register_static ("CafeMenuTreeEntry", |
4883 | (GBoxedCopyFunc)cafemenu_tree_item_ref, |
4884 | (GBoxedFreeFunc)cafemenu_tree_item_unref); |
4885 | } |
4886 | return gtype; |
4887 | } |
4888 | |
4889 | GType |
4890 | cafemenu_tree_separator_get_type (void) |
4891 | { |
4892 | static GType gtype = G_TYPE_INVALID((GType) ((0) << (2))); |
4893 | if (gtype == G_TYPE_INVALID((GType) ((0) << (2)))) |
4894 | { |
4895 | gtype = g_boxed_type_register_static ("CafeMenuTreeSeparator", |
4896 | (GBoxedCopyFunc)cafemenu_tree_item_ref, |
4897 | (GBoxedFreeFunc)cafemenu_tree_item_unref); |
4898 | } |
4899 | return gtype; |
4900 | } |
4901 | |
4902 | GType |
4903 | cafemenu_tree_header_get_type (void) |
4904 | { |
4905 | static GType gtype = G_TYPE_INVALID((GType) ((0) << (2))); |
4906 | if (gtype == G_TYPE_INVALID((GType) ((0) << (2)))) |
4907 | { |
4908 | gtype = g_boxed_type_register_static ("CafeMenuTreeHeader", |
4909 | (GBoxedCopyFunc)cafemenu_tree_item_ref, |
4910 | (GBoxedFreeFunc)cafemenu_tree_item_unref); |
4911 | } |
4912 | return gtype; |
4913 | } |
4914 | |
4915 | GType |
4916 | cafemenu_tree_alias_get_type (void) |
4917 | { |
4918 | static GType gtype = G_TYPE_INVALID((GType) ((0) << (2))); |
4919 | if (gtype == G_TYPE_INVALID((GType) ((0) << (2)))) |
4920 | { |
4921 | gtype = g_boxed_type_register_static ("CafeMenuTreeAlias", |
4922 | (GBoxedCopyFunc)cafemenu_tree_item_ref, |
4923 | (GBoxedFreeFunc)cafemenu_tree_item_unref); |
4924 | } |
4925 | return gtype; |
4926 | } |
4927 | |
4928 | GType |
4929 | cafemenu_tree_flags_get_type (void) |
4930 | { |
4931 | static GType enum_type_id = 0; |
4932 | if (G_UNLIKELY (!enum_type_id)(!enum_type_id)) |
4933 | { |
4934 | static const GFlagsValue values[] = { |
4935 | { CAFEMENU_TREE_FLAGS_NONE, "CAFEMENU_TREE_FLAGS_NONE", "none" }, |
4936 | { CAFEMENU_TREE_FLAGS_INCLUDE_EXCLUDED, "CAFEMENU_TREE_FLAGS_INCLUDE_EXCLUDED", "include-excluded" }, |
4937 | { CAFEMENU_TREE_FLAGS_SHOW_EMPTY, "CAFEMENU_TREE_FLAGS_SHOW_EMPTY", "show-empty" }, |
4938 | { CAFEMENU_TREE_FLAGS_INCLUDE_NODISPLAY, "CAFEMENU_TREE_FLAGS_INCLUDE_NODISPLAY", "include-nodisplay" }, |
4939 | { CAFEMENU_TREE_FLAGS_SHOW_ALL_SEPARATORS, "CAFEMENU_TREE_FLAGS_SHOW_ALL_SEPARATORS", "show-all-separators" }, |
4940 | { CAFEMENU_TREE_FLAGS_SORT_DISPLAY_NAME, "CAFEMENU_TREE_FLAGS_SORT_DISPLAY_NAME", "sort-display-name" }, |
4941 | { CAFEMENU_TREE_FLAGS_INCLUDE_UNALLOCATED, "CAFEMENU_TREE_FLAGS_INCLUDE_UNALLOCATED,", "include-unallocated" }, |
4942 | { 0, NULL((void*)0), NULL((void*)0) } |
4943 | }; |
4944 | enum_type_id = g_flags_register_static ("CafeMenuTreeFlags", values); |
4945 | } |
4946 | return enum_type_id; |
4947 | } |