File: | menu-layout.c |
Warning: | line 2084, column 15 Value stored to 'prev' is never read |
Press '?' to see keyboard shortcuts
Keyboard shortcuts:
1 | /* Menu layout in-memory data structure (a custom "DOM tree") */ |
2 | |
3 | /* |
4 | * Copyright (C) 2002 - 2004 Red Hat, Inc. |
5 | * |
6 | * This library is free software; you can redistribute it and/or |
7 | * modify it under the terms of the GNU Lesser General Public |
8 | * License as published by the Free Software Foundation; either |
9 | * version 2 of the License, or (at your option) any later version. |
10 | * |
11 | * This library is distributed in the hope that it will be useful, |
12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
14 | * Lesser General Public License for more details. |
15 | * |
16 | * You should have received a copy of the GNU Lesser General Public |
17 | * License along with this library; if not, write to the |
18 | * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, |
19 | * Boston, MA 02110-1301, USA. |
20 | */ |
21 | |
22 | #include <config.h> |
23 | |
24 | #include "menu-layout.h" |
25 | |
26 | #include <string.h> |
27 | #include <stdio.h> |
28 | #include <stdlib.h> |
29 | #include <unistd.h> |
30 | #include <errno(*__errno_location ()).h> |
31 | |
32 | #include "entry-directories.h" |
33 | #include "menu-util.h" |
34 | |
35 | typedef struct MenuLayoutNodeMenu MenuLayoutNodeMenu; |
36 | typedef struct MenuLayoutNodeRoot MenuLayoutNodeRoot; |
37 | typedef struct MenuLayoutNodeLegacyDir MenuLayoutNodeLegacyDir; |
38 | typedef struct MenuLayoutNodeMergeFile MenuLayoutNodeMergeFile; |
39 | typedef struct MenuLayoutNodeDefaultLayout MenuLayoutNodeDefaultLayout; |
40 | typedef struct MenuLayoutNodeMenuname MenuLayoutNodeMenuname; |
41 | typedef struct MenuLayoutNodeMerge MenuLayoutNodeMerge; |
42 | |
43 | struct MenuLayoutNode |
44 | { |
45 | /* Node lists are circular, for length-one lists |
46 | * prev/next point back to the node itself. |
47 | */ |
48 | MenuLayoutNode *prev; |
49 | MenuLayoutNode *next; |
50 | MenuLayoutNode *parent; |
51 | MenuLayoutNode *children; |
52 | |
53 | char *content; |
54 | |
55 | guint refcount : 20; |
56 | guint type : 7; |
57 | }; |
58 | |
59 | struct MenuLayoutNodeRoot |
60 | { |
61 | MenuLayoutNode node; |
62 | |
63 | char *basedir; |
64 | char *name; |
65 | |
66 | GMainContext *main_context; |
67 | |
68 | GSList *monitors; |
69 | GSource *monitors_idle_handler; |
70 | }; |
71 | |
72 | struct MenuLayoutNodeMenu |
73 | { |
74 | MenuLayoutNode node; |
75 | |
76 | MenuLayoutNode *name_node; /* cache of the <Name> node */ |
77 | |
78 | EntryDirectoryList *app_dirs; |
79 | EntryDirectoryList *dir_dirs; |
80 | }; |
81 | |
82 | struct MenuLayoutNodeLegacyDir |
83 | { |
84 | MenuLayoutNode node; |
85 | |
86 | char *prefix; |
87 | }; |
88 | |
89 | struct MenuLayoutNodeMergeFile |
90 | { |
91 | MenuLayoutNode node; |
92 | |
93 | MenuMergeFileType type; |
94 | }; |
95 | |
96 | struct MenuLayoutNodeDefaultLayout |
97 | { |
98 | MenuLayoutNode node; |
99 | |
100 | MenuLayoutValues layout_values; |
101 | }; |
102 | |
103 | struct MenuLayoutNodeMenuname |
104 | { |
105 | MenuLayoutNode node; |
106 | |
107 | MenuLayoutValues layout_values; |
108 | }; |
109 | |
110 | struct MenuLayoutNodeMerge |
111 | { |
112 | MenuLayoutNode node; |
113 | |
114 | MenuLayoutMergeType merge_type; |
115 | }; |
116 | |
117 | typedef struct |
118 | { |
119 | MenuLayoutNodeEntriesChangedFunc callback; |
120 | gpointer user_data; |
121 | } MenuLayoutNodeEntriesMonitor; |
122 | |
123 | |
124 | static inline MenuLayoutNode * |
125 | node_next (MenuLayoutNode *node) |
126 | { |
127 | /* root nodes (no parent) never have siblings */ |
128 | if (node->parent == NULL((void*)0)) |
129 | return NULL((void*)0); |
130 | |
131 | /* circular list */ |
132 | if (node->next == node->parent->children) |
133 | return NULL((void*)0); |
134 | |
135 | return node->next; |
136 | } |
137 | |
138 | static gboolean |
139 | menu_layout_invoke_monitors (MenuLayoutNodeRoot *nr) |
140 | { |
141 | GSList *tmp; |
142 | |
143 | g_assert (nr->node.type == MENU_LAYOUT_NODE_ROOT)do { if (nr->node.type == MENU_LAYOUT_NODE_ROOT) ; else g_assertion_message_expr (((gchar*) 0), "menu-layout.c", 143, ((const char*) (__func__ )), "nr->node.type == MENU_LAYOUT_NODE_ROOT"); } while (0); |
144 | |
145 | nr->monitors_idle_handler = NULL((void*)0); |
146 | |
147 | tmp = nr->monitors; |
148 | while (tmp != NULL((void*)0)) |
149 | { |
150 | MenuLayoutNodeEntriesMonitor *monitor = tmp->data; |
151 | GSList *next = tmp->next; |
152 | |
153 | monitor->callback ((MenuLayoutNode *) nr, monitor->user_data); |
154 | |
155 | tmp = next; |
156 | } |
157 | |
158 | return FALSE(0); |
159 | } |
160 | |
161 | static void |
162 | handle_entry_directory_changed (EntryDirectory *dir G_GNUC_UNUSED__attribute__ ((__unused__)), |
163 | MenuLayoutNode *node) |
164 | { |
165 | MenuLayoutNodeRoot *nr; |
166 | |
167 | g_assert (node->type == MENU_LAYOUT_NODE_MENU)do { if (node->type == MENU_LAYOUT_NODE_MENU) ; else g_assertion_message_expr (((gchar*) 0), "menu-layout.c", 167, ((const char*) (__func__ )), "node->type == MENU_LAYOUT_NODE_MENU"); } while (0); |
168 | |
169 | nr = (MenuLayoutNodeRoot *) menu_layout_node_get_root (node); |
170 | |
171 | if (nr->monitors_idle_handler == NULL((void*)0)) |
172 | { |
173 | nr->monitors_idle_handler = g_idle_source_new (); |
174 | g_source_set_callback (nr->monitors_idle_handler, |
175 | (GSourceFunc) menu_layout_invoke_monitors, nr, NULL((void*)0)); |
176 | g_source_attach (nr->monitors_idle_handler, nr->main_context); |
177 | g_source_unref (nr->monitors_idle_handler); |
178 | } |
179 | } |
180 | |
181 | static void |
182 | remove_entry_directory_list (MenuLayoutNodeMenu *nm, |
183 | EntryDirectoryList **dirs) |
184 | { |
185 | if (*dirs) |
186 | { |
187 | entry_directory_list_remove_monitors (*dirs, |
188 | (EntryDirectoryChangedFunc) handle_entry_directory_changed, |
189 | nm); |
190 | entry_directory_list_unref (*dirs); |
191 | *dirs = NULL((void*)0); |
192 | } |
193 | } |
194 | |
195 | MenuLayoutNode * |
196 | menu_layout_node_ref (MenuLayoutNode *node) |
197 | { |
198 | g_return_val_if_fail (node != NULL, NULL)do { if ((node != ((void*)0))) { } else { g_return_if_fail_warning (((gchar*) 0), ((const char*) (__func__)), "node != NULL"); return (((void*)0)); } } while (0); |
199 | |
200 | node->refcount += 1; |
201 | |
202 | return node; |
203 | } |
204 | |
205 | void |
206 | menu_layout_node_unref (MenuLayoutNode *node) |
207 | { |
208 | g_return_if_fail (node != NULL)do { if ((node != ((void*)0))) { } else { g_return_if_fail_warning (((gchar*) 0), ((const char*) (__func__)), "node != NULL"); return ; } } while (0); |
209 | g_return_if_fail (node->refcount > 0)do { if ((node->refcount > 0)) { } else { g_return_if_fail_warning (((gchar*) 0), ((const char*) (__func__)), "node->refcount > 0" ); return; } } while (0); |
210 | |
211 | node->refcount -= 1; |
212 | if (node->refcount == 0) |
213 | { |
214 | MenuLayoutNode *iter; |
215 | |
216 | iter = node->children; |
217 | while (iter != NULL((void*)0)) |
218 | { |
219 | MenuLayoutNode *next = node_next (iter); |
220 | |
221 | menu_layout_node_unref (iter); |
222 | |
223 | iter = next; |
224 | } |
225 | |
226 | if (node->type == MENU_LAYOUT_NODE_MENU) |
227 | { |
228 | MenuLayoutNodeMenu *nm = (MenuLayoutNodeMenu *) node; |
229 | |
230 | if (nm->name_node) |
231 | menu_layout_node_unref (nm->name_node); |
232 | |
233 | remove_entry_directory_list (nm, &nm->app_dirs); |
234 | remove_entry_directory_list (nm, &nm->dir_dirs); |
235 | } |
236 | else if (node->type == MENU_LAYOUT_NODE_LEGACY_DIR) |
237 | { |
238 | MenuLayoutNodeLegacyDir *legacy = (MenuLayoutNodeLegacyDir *) node; |
239 | |
240 | g_free (legacy->prefix); |
241 | } |
242 | else if (node->type == MENU_LAYOUT_NODE_ROOT) |
243 | { |
244 | MenuLayoutNodeRoot *nr = (MenuLayoutNodeRoot*) node; |
245 | |
246 | g_slist_foreach (nr->monitors, (GFunc) g_free, NULL((void*)0)); |
247 | g_slist_free (nr->monitors); |
248 | |
249 | if (nr->monitors_idle_handler != NULL((void*)0)) |
250 | g_source_destroy (nr->monitors_idle_handler); |
251 | nr->monitors_idle_handler = NULL((void*)0); |
252 | |
253 | if (nr->main_context != NULL((void*)0)) |
254 | g_main_context_unref (nr->main_context); |
255 | nr->main_context = NULL((void*)0); |
256 | |
257 | g_free (nr->basedir); |
258 | g_free (nr->name); |
259 | } |
260 | |
261 | g_free (node->content); |
262 | g_free (node); |
263 | } |
264 | } |
265 | |
266 | MenuLayoutNode * |
267 | menu_layout_node_new (MenuLayoutNodeType type) |
268 | { |
269 | MenuLayoutNode *node; |
270 | |
271 | switch (type) |
272 | { |
273 | case MENU_LAYOUT_NODE_MENU: |
274 | node = (MenuLayoutNode *) g_new0 (MenuLayoutNodeMenu, 1)((MenuLayoutNodeMenu *) g_malloc0_n ((1), sizeof (MenuLayoutNodeMenu ))); |
275 | break; |
276 | |
277 | case MENU_LAYOUT_NODE_LEGACY_DIR: |
278 | node = (MenuLayoutNode *) g_new0 (MenuLayoutNodeLegacyDir, 1)((MenuLayoutNodeLegacyDir *) g_malloc0_n ((1), sizeof (MenuLayoutNodeLegacyDir ))); |
279 | break; |
280 | |
281 | case MENU_LAYOUT_NODE_ROOT: |
282 | node = (MenuLayoutNode*) g_new0 (MenuLayoutNodeRoot, 1)((MenuLayoutNodeRoot *) g_malloc0_n ((1), sizeof (MenuLayoutNodeRoot ))); |
283 | break; |
284 | |
285 | case MENU_LAYOUT_NODE_MERGE_FILE: |
286 | node = (MenuLayoutNode *) g_new0 (MenuLayoutNodeMergeFile, 1)((MenuLayoutNodeMergeFile *) g_malloc0_n ((1), sizeof (MenuLayoutNodeMergeFile ))); |
287 | break; |
288 | |
289 | case MENU_LAYOUT_NODE_DEFAULT_LAYOUT: |
290 | node = (MenuLayoutNode *) g_new0 (MenuLayoutNodeDefaultLayout, 1)((MenuLayoutNodeDefaultLayout *) g_malloc0_n ((1), sizeof (MenuLayoutNodeDefaultLayout ))); |
291 | break; |
292 | |
293 | case MENU_LAYOUT_NODE_MENUNAME: |
294 | node = (MenuLayoutNode *) g_new0 (MenuLayoutNodeMenuname, 1)((MenuLayoutNodeMenuname *) g_malloc0_n ((1), sizeof (MenuLayoutNodeMenuname ))); |
295 | break; |
296 | |
297 | case MENU_LAYOUT_NODE_MERGE: |
298 | node = (MenuLayoutNode *) g_new0 (MenuLayoutNodeMerge, 1)((MenuLayoutNodeMerge *) g_malloc0_n ((1), sizeof (MenuLayoutNodeMerge ))); |
299 | break; |
300 | |
301 | default: |
302 | node = g_new0 (MenuLayoutNode, 1)((MenuLayoutNode *) g_malloc0_n ((1), sizeof (MenuLayoutNode) )); |
303 | break; |
304 | } |
305 | |
306 | node->type = type; |
307 | |
308 | node->refcount = 1; |
309 | |
310 | /* we're in a list of one node */ |
311 | node->next = node; |
312 | node->prev = node; |
313 | |
314 | return node; |
315 | } |
316 | |
317 | MenuLayoutNode * |
318 | menu_layout_node_get_next (MenuLayoutNode *node) |
319 | { |
320 | return node_next (node); |
321 | } |
322 | |
323 | MenuLayoutNode * |
324 | menu_layout_node_get_parent (MenuLayoutNode *node) |
325 | { |
326 | return node->parent; |
327 | } |
328 | |
329 | MenuLayoutNode * |
330 | menu_layout_node_get_children (MenuLayoutNode *node) |
331 | { |
332 | return node->children; |
333 | } |
334 | |
335 | MenuLayoutNode * |
336 | menu_layout_node_get_root (MenuLayoutNode *node) |
337 | { |
338 | MenuLayoutNode *parent; |
339 | |
340 | parent = node; |
341 | while (parent->parent != NULL((void*)0)) |
342 | parent = parent->parent; |
343 | |
344 | g_assert (parent->type == MENU_LAYOUT_NODE_ROOT)do { if (parent->type == MENU_LAYOUT_NODE_ROOT) ; else g_assertion_message_expr (((gchar*) 0), "menu-layout.c", 344, ((const char*) (__func__ )), "parent->type == MENU_LAYOUT_NODE_ROOT"); } while (0); |
345 | |
346 | return parent; |
347 | } |
348 | |
349 | char * |
350 | menu_layout_node_get_content_as_path (MenuLayoutNode *node) |
351 | { |
352 | if (node->content == NULL((void*)0)) |
353 | { |
354 | menu_verbose (" (node has no content to get as a path)\n"); |
355 | return NULL((void*)0); |
356 | } |
357 | |
358 | if (g_path_is_absolute (node->content)) |
359 | { |
360 | return g_strdup (node->content)g_strdup_inline (node->content); |
361 | } |
362 | else |
363 | { |
364 | MenuLayoutNodeRoot *root; |
365 | |
366 | root = (MenuLayoutNodeRoot *) menu_layout_node_get_root (node); |
367 | |
368 | if (root->basedir == NULL((void*)0)) |
369 | { |
370 | menu_verbose ("No basedir available, using \"%s\" as-is\n", |
371 | node->content); |
372 | return g_strdup (node->content)g_strdup_inline (node->content); |
373 | } |
374 | else |
375 | { |
376 | menu_verbose ("Using basedir \"%s\" filename \"%s\"\n", |
377 | root->basedir, node->content); |
378 | return g_build_filename (root->basedir, node->content, NULL((void*)0)); |
379 | } |
380 | } |
381 | } |
382 | |
383 | #define RETURN_IF_NO_PARENT(node)do { if ((node)->parent == ((void*)0)) { g_warning ("To add siblings to a menu node, " "it must not be the root node, " "and must be linked in below some root node\n" "node parent = %p and type = %d", (node)->parent, (node)-> type); return; } } while (0) G_STMT_STARTdo { \ |
384 | if ((node)->parent == NULL((void*)0)) \ |
385 | { \ |
386 | g_warning ("To add siblings to a menu node, " \ |
387 | "it must not be the root node, " \ |
388 | "and must be linked in below some root node\n" \ |
389 | "node parent = %p and type = %d", \ |
390 | (node)->parent, (node)->type); \ |
391 | return; \ |
392 | } \ |
393 | } G_STMT_ENDwhile (0) |
394 | |
395 | #define RETURN_IF_HAS_ENTRY_DIRS(node)do { if ((node)->type == MENU_LAYOUT_NODE_MENU && ( ((MenuLayoutNodeMenu*)(node))->app_dirs != ((void*)0) || ( (MenuLayoutNodeMenu*)(node))->dir_dirs != ((void*)0))) { g_warning ("node acquired ->app_dirs or ->dir_dirs " "while not rooted in a tree\n" ); return; } } while (0) G_STMT_STARTdo { \ |
396 | if ((node)->type == MENU_LAYOUT_NODE_MENU && \ |
397 | (((MenuLayoutNodeMenu*)(node))->app_dirs != NULL((void*)0) || \ |
398 | ((MenuLayoutNodeMenu*)(node))->dir_dirs != NULL((void*)0))) \ |
399 | { \ |
400 | g_warning ("node acquired ->app_dirs or ->dir_dirs " \ |
401 | "while not rooted in a tree\n"); \ |
402 | return; \ |
403 | } \ |
404 | } G_STMT_ENDwhile (0) \ |
405 | |
406 | void |
407 | menu_layout_node_insert_before (MenuLayoutNode *node, |
408 | MenuLayoutNode *new_sibling) |
409 | { |
410 | g_return_if_fail (new_sibling != NULL)do { if ((new_sibling != ((void*)0))) { } else { g_return_if_fail_warning (((gchar*) 0), ((const char*) (__func__)), "new_sibling != NULL" ); return; } } while (0); |
411 | g_return_if_fail (new_sibling->parent == NULL)do { if ((new_sibling->parent == ((void*)0))) { } else { g_return_if_fail_warning (((gchar*) 0), ((const char*) (__func__)), "new_sibling->parent == NULL" ); return; } } while (0); |
412 | |
413 | RETURN_IF_NO_PARENT (node)do { if ((node)->parent == ((void*)0)) { g_warning ("To add siblings to a menu node, " "it must not be the root node, " "and must be linked in below some root node\n" "node parent = %p and type = %d", (node)->parent, (node)-> type); return; } } while (0); |
414 | RETURN_IF_HAS_ENTRY_DIRS (new_sibling)do { if ((new_sibling)->type == MENU_LAYOUT_NODE_MENU && (((MenuLayoutNodeMenu*)(new_sibling))->app_dirs != ((void *)0) || ((MenuLayoutNodeMenu*)(new_sibling))->dir_dirs != ( (void*)0))) { g_warning ("node acquired ->app_dirs or ->dir_dirs " "while not rooted in a tree\n"); return; } } while (0); |
415 | |
416 | new_sibling->next = node; |
417 | new_sibling->prev = node->prev; |
418 | |
419 | node->prev = new_sibling; |
420 | new_sibling->prev->next = new_sibling; |
421 | |
422 | new_sibling->parent = node->parent; |
423 | |
424 | if (node == node->parent->children) |
425 | node->parent->children = new_sibling; |
426 | |
427 | menu_layout_node_ref (new_sibling); |
428 | } |
429 | |
430 | void |
431 | menu_layout_node_insert_after (MenuLayoutNode *node, |
432 | MenuLayoutNode *new_sibling) |
433 | { |
434 | g_return_if_fail (new_sibling != NULL)do { if ((new_sibling != ((void*)0))) { } else { g_return_if_fail_warning (((gchar*) 0), ((const char*) (__func__)), "new_sibling != NULL" ); return; } } while (0); |
435 | g_return_if_fail (new_sibling->parent == NULL)do { if ((new_sibling->parent == ((void*)0))) { } else { g_return_if_fail_warning (((gchar*) 0), ((const char*) (__func__)), "new_sibling->parent == NULL" ); return; } } while (0); |
436 | |
437 | RETURN_IF_NO_PARENT (node)do { if ((node)->parent == ((void*)0)) { g_warning ("To add siblings to a menu node, " "it must not be the root node, " "and must be linked in below some root node\n" "node parent = %p and type = %d", (node)->parent, (node)-> type); return; } } while (0); |
438 | RETURN_IF_HAS_ENTRY_DIRS (new_sibling)do { if ((new_sibling)->type == MENU_LAYOUT_NODE_MENU && (((MenuLayoutNodeMenu*)(new_sibling))->app_dirs != ((void *)0) || ((MenuLayoutNodeMenu*)(new_sibling))->dir_dirs != ( (void*)0))) { g_warning ("node acquired ->app_dirs or ->dir_dirs " "while not rooted in a tree\n"); return; } } while (0); |
439 | |
440 | new_sibling->prev = node; |
441 | new_sibling->next = node->next; |
442 | |
443 | node->next = new_sibling; |
444 | new_sibling->next->prev = new_sibling; |
445 | |
446 | new_sibling->parent = node->parent; |
447 | |
448 | menu_layout_node_ref (new_sibling); |
449 | } |
450 | |
451 | void |
452 | menu_layout_node_prepend_child (MenuLayoutNode *parent, |
453 | MenuLayoutNode *new_child) |
454 | { |
455 | RETURN_IF_HAS_ENTRY_DIRS (new_child)do { if ((new_child)->type == MENU_LAYOUT_NODE_MENU && (((MenuLayoutNodeMenu*)(new_child))->app_dirs != ((void*) 0) || ((MenuLayoutNodeMenu*)(new_child))->dir_dirs != ((void *)0))) { g_warning ("node acquired ->app_dirs or ->dir_dirs " "while not rooted in a tree\n"); return; } } while (0); |
456 | |
457 | if (parent->children) |
458 | { |
459 | menu_layout_node_insert_before (parent->children, new_child); |
460 | } |
461 | else |
462 | { |
463 | parent->children = menu_layout_node_ref (new_child); |
464 | new_child->parent = parent; |
465 | } |
466 | } |
467 | |
468 | void |
469 | menu_layout_node_append_child (MenuLayoutNode *parent, |
470 | MenuLayoutNode *new_child) |
471 | { |
472 | RETURN_IF_HAS_ENTRY_DIRS (new_child)do { if ((new_child)->type == MENU_LAYOUT_NODE_MENU && (((MenuLayoutNodeMenu*)(new_child))->app_dirs != ((void*) 0) || ((MenuLayoutNodeMenu*)(new_child))->dir_dirs != ((void *)0))) { g_warning ("node acquired ->app_dirs or ->dir_dirs " "while not rooted in a tree\n"); return; } } while (0); |
473 | |
474 | if (parent->children) |
475 | { |
476 | menu_layout_node_insert_after (parent->children->prev, new_child); |
477 | } |
478 | else |
479 | { |
480 | parent->children = menu_layout_node_ref (new_child); |
481 | new_child->parent = parent; |
482 | } |
483 | } |
484 | |
485 | void |
486 | menu_layout_node_unlink (MenuLayoutNode *node) |
487 | { |
488 | g_return_if_fail (node != NULL)do { if ((node != ((void*)0))) { } else { g_return_if_fail_warning (((gchar*) 0), ((const char*) (__func__)), "node != NULL"); return ; } } while (0); |
489 | g_return_if_fail (node->parent != NULL)do { if ((node->parent != ((void*)0))) { } else { g_return_if_fail_warning (((gchar*) 0), ((const char*) (__func__)), "node->parent != NULL" ); return; } } while (0); |
490 | |
491 | menu_layout_node_steal (node); |
492 | menu_layout_node_unref (node); |
493 | } |
494 | |
495 | static void |
496 | recursive_clean_entry_directory_lists (MenuLayoutNode *node, |
497 | gboolean apps) |
498 | { |
499 | EntryDirectoryList **dirs; |
500 | MenuLayoutNodeMenu *nm; |
501 | MenuLayoutNode *iter; |
502 | |
503 | if (node->type != MENU_LAYOUT_NODE_MENU) |
504 | return; |
505 | |
506 | nm = (MenuLayoutNodeMenu *) node; |
507 | |
508 | dirs = apps ? &nm->app_dirs : &nm->dir_dirs; |
509 | |
510 | if (*dirs == NULL((void*)0) || entry_directory_list_get_length (*dirs) == 0) |
511 | return; /* child menus continue to have valid lists */ |
512 | |
513 | remove_entry_directory_list (nm, dirs); |
514 | |
515 | iter = node->children; |
516 | while (iter != NULL((void*)0)) |
517 | { |
518 | if (iter->type == MENU_LAYOUT_NODE_MENU) |
519 | recursive_clean_entry_directory_lists (iter, apps); |
520 | |
521 | iter = node_next (iter); |
522 | } |
523 | } |
524 | |
525 | void |
526 | menu_layout_node_steal (MenuLayoutNode *node) |
527 | { |
528 | g_return_if_fail (node != NULL)do { if ((node != ((void*)0))) { } else { g_return_if_fail_warning (((gchar*) 0), ((const char*) (__func__)), "node != NULL"); return ; } } while (0); |
529 | g_return_if_fail (node->parent != NULL)do { if ((node->parent != ((void*)0))) { } else { g_return_if_fail_warning (((gchar*) 0), ((const char*) (__func__)), "node->parent != NULL" ); return; } } while (0); |
530 | |
531 | switch (node->type) |
532 | { |
533 | case MENU_LAYOUT_NODE_NAME: |
534 | { |
535 | MenuLayoutNodeMenu *nm = (MenuLayoutNodeMenu *) node->parent; |
536 | |
537 | if (nm->name_node == node) |
538 | { |
539 | menu_layout_node_unref (nm->name_node); |
540 | nm->name_node = NULL((void*)0); |
541 | } |
542 | } |
543 | break; |
544 | |
545 | case MENU_LAYOUT_NODE_APP_DIR: |
546 | recursive_clean_entry_directory_lists (node->parent, TRUE(!(0))); |
547 | break; |
548 | |
549 | case MENU_LAYOUT_NODE_DIRECTORY_DIR: |
550 | recursive_clean_entry_directory_lists (node->parent, FALSE(0)); |
551 | break; |
552 | |
553 | default: |
554 | break; |
555 | } |
556 | |
557 | if (node->parent && node->parent->children == node) |
558 | { |
559 | if (node->next != node) |
560 | node->parent->children = node->next; |
561 | else |
562 | node->parent->children = NULL((void*)0); |
563 | } |
564 | |
565 | /* these are no-ops for length-one node lists */ |
566 | node->prev->next = node->next; |
567 | node->next->prev = node->prev; |
568 | |
569 | node->parent = NULL((void*)0); |
570 | |
571 | /* point to ourselves, now we're length one */ |
572 | node->next = node; |
573 | node->prev = node; |
574 | } |
575 | |
576 | MenuLayoutNodeType |
577 | menu_layout_node_get_type (MenuLayoutNode *node) |
578 | { |
579 | return node->type; |
580 | } |
581 | |
582 | const char * |
583 | menu_layout_node_get_content (MenuLayoutNode *node) |
584 | { |
585 | return node->content; |
586 | } |
587 | |
588 | void |
589 | menu_layout_node_set_content (MenuLayoutNode *node, |
590 | const char *content) |
591 | { |
592 | if (node->content == content) |
593 | return; |
594 | |
595 | g_free (node->content); |
596 | node->content = g_strdup (content)g_strdup_inline (content); |
597 | } |
598 | |
599 | const char * |
600 | menu_layout_node_root_get_name (MenuLayoutNode *node) |
601 | { |
602 | MenuLayoutNodeRoot *nr; |
603 | |
604 | g_return_val_if_fail (node->type == MENU_LAYOUT_NODE_ROOT, NULL)do { if ((node->type == MENU_LAYOUT_NODE_ROOT)) { } else { g_return_if_fail_warning (((gchar*) 0), ((const char*) (__func__ )), "node->type == MENU_LAYOUT_NODE_ROOT"); return (((void *)0)); } } while (0); |
605 | |
606 | nr = (MenuLayoutNodeRoot*) node; |
607 | |
608 | return nr->name; |
609 | } |
610 | |
611 | const char * |
612 | menu_layout_node_root_get_basedir (MenuLayoutNode *node) |
613 | { |
614 | MenuLayoutNodeRoot *nr; |
615 | |
616 | g_return_val_if_fail (node->type == MENU_LAYOUT_NODE_ROOT, NULL)do { if ((node->type == MENU_LAYOUT_NODE_ROOT)) { } else { g_return_if_fail_warning (((gchar*) 0), ((const char*) (__func__ )), "node->type == MENU_LAYOUT_NODE_ROOT"); return (((void *)0)); } } while (0); |
617 | |
618 | nr = (MenuLayoutNodeRoot*) node; |
619 | |
620 | return nr->basedir; |
621 | } |
622 | |
623 | const char * |
624 | menu_layout_node_menu_get_name (MenuLayoutNode *node) |
625 | { |
626 | MenuLayoutNodeMenu *nm; |
627 | |
628 | g_return_val_if_fail (node->type == MENU_LAYOUT_NODE_MENU, NULL)do { if ((node->type == MENU_LAYOUT_NODE_MENU)) { } else { g_return_if_fail_warning (((gchar*) 0), ((const char*) (__func__ )), "node->type == MENU_LAYOUT_NODE_MENU"); return (((void *)0)); } } while (0); |
629 | |
630 | nm = (MenuLayoutNodeMenu*) node; |
631 | |
632 | if (nm->name_node == NULL((void*)0)) |
633 | { |
634 | MenuLayoutNode *iter; |
635 | |
636 | iter = node->children; |
637 | while (iter != NULL((void*)0)) |
638 | { |
639 | if (iter->type == MENU_LAYOUT_NODE_NAME) |
640 | { |
641 | nm->name_node = menu_layout_node_ref (iter); |
642 | break; |
643 | } |
644 | |
645 | iter = node_next (iter); |
646 | } |
647 | } |
648 | |
649 | if (nm->name_node == NULL((void*)0)) |
650 | return NULL((void*)0); |
651 | |
652 | return menu_layout_node_get_content (nm->name_node); |
653 | } |
654 | |
655 | static void |
656 | ensure_dir_lists (MenuLayoutNodeMenu *nm) |
657 | { |
658 | MenuLayoutNode *node; |
659 | MenuLayoutNode *iter; |
660 | EntryDirectoryList *app_dirs; |
661 | EntryDirectoryList *dir_dirs; |
662 | |
663 | node = (MenuLayoutNode *) nm; |
664 | |
665 | if (nm->app_dirs && nm->dir_dirs) |
666 | return; |
667 | |
668 | app_dirs = NULL((void*)0); |
669 | dir_dirs = NULL((void*)0); |
670 | |
671 | if (nm->app_dirs == NULL((void*)0)) |
672 | { |
673 | app_dirs = entry_directory_list_new (); |
674 | |
675 | if (node->parent && node->parent->type == MENU_LAYOUT_NODE_MENU) |
676 | { |
677 | EntryDirectoryList *dirs; |
678 | |
679 | if ((dirs = menu_layout_node_menu_get_app_dirs (node->parent))) |
680 | entry_directory_list_append_list (app_dirs, dirs); |
681 | } |
682 | } |
683 | |
684 | if (nm->dir_dirs == NULL((void*)0)) |
685 | { |
686 | dir_dirs = entry_directory_list_new (); |
687 | |
688 | if (node->parent && node->parent->type == MENU_LAYOUT_NODE_MENU) |
689 | { |
690 | EntryDirectoryList *dirs; |
691 | |
692 | if ((dirs = menu_layout_node_menu_get_directory_dirs (node->parent))) |
693 | entry_directory_list_append_list (dir_dirs, dirs); |
694 | } |
695 | } |
696 | |
697 | iter = node->children; |
698 | while (iter != NULL((void*)0)) |
699 | { |
700 | EntryDirectory *ed; |
701 | |
702 | if (app_dirs != NULL((void*)0) && iter->type == MENU_LAYOUT_NODE_APP_DIR) |
703 | { |
704 | char *path; |
705 | |
706 | path = menu_layout_node_get_content_as_path (iter); |
707 | |
708 | ed = entry_directory_new (DESKTOP_ENTRY_DESKTOP, path); |
709 | if (ed != NULL((void*)0)) |
710 | { |
711 | entry_directory_list_prepend (app_dirs, ed); |
712 | entry_directory_unref (ed); |
713 | } |
714 | |
715 | g_free (path); |
716 | } |
717 | |
718 | if (dir_dirs != NULL((void*)0) && iter->type == MENU_LAYOUT_NODE_DIRECTORY_DIR) |
719 | { |
720 | char *path; |
721 | |
722 | path = menu_layout_node_get_content_as_path (iter); |
723 | |
724 | ed = entry_directory_new (DESKTOP_ENTRY_DIRECTORY, path); |
725 | if (ed != NULL((void*)0)) |
726 | { |
727 | entry_directory_list_prepend (dir_dirs, ed); |
728 | entry_directory_unref (ed); |
729 | } |
730 | |
731 | g_free (path); |
732 | } |
733 | |
734 | if (iter->type == MENU_LAYOUT_NODE_LEGACY_DIR) |
735 | { |
736 | MenuLayoutNodeLegacyDir *legacy = (MenuLayoutNodeLegacyDir *) iter; |
737 | char *path; |
738 | |
739 | path = menu_layout_node_get_content_as_path (iter); |
740 | |
741 | if (app_dirs != NULL((void*)0)) /* we're loading app dirs */ |
742 | { |
743 | ed = entry_directory_new_legacy (DESKTOP_ENTRY_DESKTOP, |
744 | path, |
745 | legacy->prefix); |
746 | if (ed != NULL((void*)0)) |
747 | { |
748 | entry_directory_list_prepend (app_dirs, ed); |
749 | entry_directory_unref (ed); |
750 | } |
751 | } |
752 | |
753 | if (dir_dirs != NULL((void*)0)) /* we're loading dir dirs */ |
754 | { |
755 | ed = entry_directory_new_legacy (DESKTOP_ENTRY_DIRECTORY, |
756 | path, |
757 | legacy->prefix); |
758 | if (ed != NULL((void*)0)) |
759 | { |
760 | entry_directory_list_prepend (dir_dirs, ed); |
761 | entry_directory_unref (ed); |
762 | } |
763 | } |
764 | |
765 | g_free (path); |
766 | } |
767 | |
768 | iter = node_next (iter); |
769 | } |
770 | |
771 | if (app_dirs) |
772 | { |
773 | g_assert (nm->app_dirs == NULL)do { if (nm->app_dirs == ((void*)0)) ; else g_assertion_message_expr (((gchar*) 0), "menu-layout.c", 773, ((const char*) (__func__ )), "nm->app_dirs == NULL"); } while (0); |
774 | |
775 | nm->app_dirs = app_dirs; |
776 | entry_directory_list_add_monitors (nm->app_dirs, |
777 | (EntryDirectoryChangedFunc) handle_entry_directory_changed, |
778 | nm); |
779 | } |
780 | |
781 | if (dir_dirs) |
782 | { |
783 | g_assert (nm->dir_dirs == NULL)do { if (nm->dir_dirs == ((void*)0)) ; else g_assertion_message_expr (((gchar*) 0), "menu-layout.c", 783, ((const char*) (__func__ )), "nm->dir_dirs == NULL"); } while (0); |
784 | |
785 | nm->dir_dirs = dir_dirs; |
786 | entry_directory_list_add_monitors (nm->dir_dirs, |
787 | (EntryDirectoryChangedFunc) handle_entry_directory_changed, |
788 | nm); |
789 | } |
790 | } |
791 | |
792 | EntryDirectoryList * |
793 | menu_layout_node_menu_get_app_dirs (MenuLayoutNode *node) |
794 | { |
795 | MenuLayoutNodeMenu *nm; |
796 | |
797 | g_return_val_if_fail (node->type == MENU_LAYOUT_NODE_MENU, NULL)do { if ((node->type == MENU_LAYOUT_NODE_MENU)) { } else { g_return_if_fail_warning (((gchar*) 0), ((const char*) (__func__ )), "node->type == MENU_LAYOUT_NODE_MENU"); return (((void *)0)); } } while (0); |
798 | |
799 | nm = (MenuLayoutNodeMenu *) node; |
800 | |
801 | ensure_dir_lists (nm); |
802 | |
803 | return nm->app_dirs; |
804 | } |
805 | |
806 | EntryDirectoryList * |
807 | menu_layout_node_menu_get_directory_dirs (MenuLayoutNode *node) |
808 | { |
809 | MenuLayoutNodeMenu *nm; |
810 | |
811 | g_return_val_if_fail (node->type == MENU_LAYOUT_NODE_MENU, NULL)do { if ((node->type == MENU_LAYOUT_NODE_MENU)) { } else { g_return_if_fail_warning (((gchar*) 0), ((const char*) (__func__ )), "node->type == MENU_LAYOUT_NODE_MENU"); return (((void *)0)); } } while (0); |
812 | |
813 | nm = (MenuLayoutNodeMenu *) node; |
814 | |
815 | ensure_dir_lists (nm); |
816 | |
817 | return nm->dir_dirs; |
818 | } |
819 | |
820 | const char * |
821 | menu_layout_node_move_get_old (MenuLayoutNode *node) |
822 | { |
823 | MenuLayoutNode *iter; |
824 | |
825 | iter = node->children; |
826 | while (iter != NULL((void*)0)) |
827 | { |
828 | if (iter->type == MENU_LAYOUT_NODE_OLD) |
829 | return iter->content; |
830 | |
831 | iter = node_next (iter); |
832 | } |
833 | |
834 | return NULL((void*)0); |
835 | } |
836 | |
837 | const char * |
838 | menu_layout_node_move_get_new (MenuLayoutNode *node) |
839 | { |
840 | MenuLayoutNode *iter; |
841 | |
842 | iter = node->children; |
843 | while (iter != NULL((void*)0)) |
844 | { |
845 | if (iter->type == MENU_LAYOUT_NODE_NEW) |
846 | return iter->content; |
847 | |
848 | iter = node_next (iter); |
849 | } |
850 | |
851 | return NULL((void*)0); |
852 | } |
853 | |
854 | const char * |
855 | menu_layout_node_legacy_dir_get_prefix (MenuLayoutNode *node) |
856 | { |
857 | MenuLayoutNodeLegacyDir *legacy; |
858 | |
859 | g_return_val_if_fail (node->type == MENU_LAYOUT_NODE_LEGACY_DIR, NULL)do { if ((node->type == MENU_LAYOUT_NODE_LEGACY_DIR)) { } else { g_return_if_fail_warning (((gchar*) 0), ((const char*) (__func__ )), "node->type == MENU_LAYOUT_NODE_LEGACY_DIR"); return ( ((void*)0)); } } while (0); |
860 | |
861 | legacy = (MenuLayoutNodeLegacyDir *) node; |
862 | |
863 | return legacy->prefix; |
864 | } |
865 | |
866 | void |
867 | menu_layout_node_legacy_dir_set_prefix (MenuLayoutNode *node, |
868 | const char *prefix) |
869 | { |
870 | MenuLayoutNodeLegacyDir *legacy; |
871 | |
872 | g_return_if_fail (node->type == MENU_LAYOUT_NODE_LEGACY_DIR)do { if ((node->type == MENU_LAYOUT_NODE_LEGACY_DIR)) { } else { g_return_if_fail_warning (((gchar*) 0), ((const char*) (__func__ )), "node->type == MENU_LAYOUT_NODE_LEGACY_DIR"); return; } } while (0); |
873 | |
874 | legacy = (MenuLayoutNodeLegacyDir *) node; |
875 | |
876 | g_free (legacy->prefix); |
877 | legacy->prefix = g_strdup (prefix)g_strdup_inline (prefix); |
878 | } |
879 | |
880 | MenuMergeFileType |
881 | menu_layout_node_merge_file_get_type (MenuLayoutNode *node) |
882 | { |
883 | MenuLayoutNodeMergeFile *merge_file; |
884 | |
885 | g_return_val_if_fail (node->type == MENU_LAYOUT_NODE_MERGE_FILE, FALSE)do { if ((node->type == MENU_LAYOUT_NODE_MERGE_FILE)) { } else { g_return_if_fail_warning (((gchar*) 0), ((const char*) (__func__ )), "node->type == MENU_LAYOUT_NODE_MERGE_FILE"); return ( (0)); } } while (0); |
886 | |
887 | merge_file = (MenuLayoutNodeMergeFile *) node; |
888 | |
889 | return merge_file->type; |
890 | } |
891 | |
892 | void |
893 | menu_layout_node_merge_file_set_type (MenuLayoutNode *node, |
894 | MenuMergeFileType type) |
895 | { |
896 | MenuLayoutNodeMergeFile *merge_file; |
897 | |
898 | g_return_if_fail (node->type == MENU_LAYOUT_NODE_MERGE_FILE)do { if ((node->type == MENU_LAYOUT_NODE_MERGE_FILE)) { } else { g_return_if_fail_warning (((gchar*) 0), ((const char*) (__func__ )), "node->type == MENU_LAYOUT_NODE_MERGE_FILE"); return; } } while (0); |
899 | |
900 | merge_file = (MenuLayoutNodeMergeFile *) node; |
901 | |
902 | merge_file->type = type; |
903 | } |
904 | |
905 | MenuLayoutMergeType |
906 | menu_layout_node_merge_get_type (MenuLayoutNode *node) |
907 | { |
908 | MenuLayoutNodeMerge *merge; |
909 | |
910 | g_return_val_if_fail (node->type == MENU_LAYOUT_NODE_MERGE, 0)do { if ((node->type == MENU_LAYOUT_NODE_MERGE)) { } else { g_return_if_fail_warning (((gchar*) 0), ((const char*) (__func__ )), "node->type == MENU_LAYOUT_NODE_MERGE"); return (0); } } while (0); |
911 | |
912 | merge = (MenuLayoutNodeMerge *) node; |
913 | |
914 | return merge->merge_type; |
915 | } |
916 | |
917 | static void |
918 | menu_layout_node_merge_set_type (MenuLayoutNode *node, |
919 | const char *merge_type) |
920 | { |
921 | MenuLayoutNodeMerge *merge; |
922 | |
923 | g_return_if_fail (node->type == MENU_LAYOUT_NODE_MERGE)do { if ((node->type == MENU_LAYOUT_NODE_MERGE)) { } else { g_return_if_fail_warning (((gchar*) 0), ((const char*) (__func__ )), "node->type == MENU_LAYOUT_NODE_MERGE"); return; } } while (0); |
924 | |
925 | merge = (MenuLayoutNodeMerge *) node; |
926 | |
927 | merge->merge_type = MENU_LAYOUT_MERGE_NONE; |
928 | |
929 | if (strcmp (merge_type, "menus") == 0) |
930 | { |
931 | merge->merge_type = MENU_LAYOUT_MERGE_MENUS; |
932 | } |
933 | else if (strcmp (merge_type, "files") == 0) |
934 | { |
935 | merge->merge_type = MENU_LAYOUT_MERGE_FILES; |
936 | } |
937 | else if (strcmp (merge_type, "all") == 0) |
938 | { |
939 | merge->merge_type = MENU_LAYOUT_MERGE_ALL; |
940 | } |
941 | } |
942 | |
943 | void |
944 | menu_layout_node_default_layout_get_values (MenuLayoutNode *node, |
945 | MenuLayoutValues *values) |
946 | { |
947 | MenuLayoutNodeDefaultLayout *default_layout; |
948 | |
949 | g_return_if_fail (node->type == MENU_LAYOUT_NODE_DEFAULT_LAYOUT)do { if ((node->type == MENU_LAYOUT_NODE_DEFAULT_LAYOUT)) { } else { g_return_if_fail_warning (((gchar*) 0), ((const char *) (__func__)), "node->type == MENU_LAYOUT_NODE_DEFAULT_LAYOUT" ); return; } } while (0); |
950 | g_return_if_fail (values != NULL)do { if ((values != ((void*)0))) { } else { g_return_if_fail_warning (((gchar*) 0), ((const char*) (__func__)), "values != NULL") ; return; } } while (0); |
951 | |
952 | default_layout = (MenuLayoutNodeDefaultLayout *) node; |
953 | |
954 | *values = default_layout->layout_values; |
955 | } |
956 | |
957 | void |
958 | menu_layout_node_menuname_get_values (MenuLayoutNode *node, |
959 | MenuLayoutValues *values) |
960 | { |
961 | MenuLayoutNodeMenuname *menuname; |
962 | |
963 | g_return_if_fail (node->type == MENU_LAYOUT_NODE_MENUNAME)do { if ((node->type == MENU_LAYOUT_NODE_MENUNAME)) { } else { g_return_if_fail_warning (((gchar*) 0), ((const char*) (__func__ )), "node->type == MENU_LAYOUT_NODE_MENUNAME"); return; } } while (0); |
964 | g_return_if_fail (values != NULL)do { if ((values != ((void*)0))) { } else { g_return_if_fail_warning (((gchar*) 0), ((const char*) (__func__)), "values != NULL") ; return; } } while (0); |
965 | |
966 | menuname = (MenuLayoutNodeMenuname *) node; |
967 | |
968 | *values = menuname->layout_values; |
969 | } |
970 | |
971 | static void |
972 | menu_layout_values_set (MenuLayoutValues *values, |
973 | const char *show_empty, |
974 | const char *inline_menus, |
975 | const char *inline_limit, |
976 | const char *inline_header, |
977 | const char *inline_alias) |
978 | { |
979 | values->mask = MENU_LAYOUT_VALUES_NONE; |
980 | values->show_empty = FALSE(0); |
981 | values->inline_menus = FALSE(0); |
982 | values->inline_limit = 4; |
983 | values->inline_header = FALSE(0); |
984 | values->inline_alias = FALSE(0); |
985 | |
986 | if (show_empty != NULL((void*)0)) |
987 | { |
988 | values->show_empty = strcmp (show_empty, "true") == 0; |
989 | values->mask |= MENU_LAYOUT_VALUES_SHOW_EMPTY; |
990 | } |
991 | |
992 | if (inline_menus != NULL((void*)0)) |
993 | { |
994 | values->inline_menus = strcmp (inline_menus, "true") == 0; |
995 | values->mask |= MENU_LAYOUT_VALUES_INLINE_MENUS; |
996 | } |
997 | |
998 | if (inline_limit != NULL((void*)0)) |
999 | { |
1000 | char *end; |
1001 | int limit; |
1002 | |
1003 | limit = strtol (inline_limit, &end, 10); |
1004 | if (*end == '\0') |
1005 | { |
1006 | values->inline_limit = limit; |
1007 | values->mask |= MENU_LAYOUT_VALUES_INLINE_LIMIT; |
1008 | } |
1009 | } |
1010 | |
1011 | if (inline_header != NULL((void*)0)) |
1012 | { |
1013 | values->inline_header = strcmp (inline_header, "true") == 0; |
1014 | values->mask |= MENU_LAYOUT_VALUES_INLINE_HEADER; |
1015 | } |
1016 | |
1017 | if (inline_alias != NULL((void*)0)) |
1018 | { |
1019 | values->inline_alias = strcmp (inline_alias, "true") == 0; |
1020 | values->mask |= MENU_LAYOUT_VALUES_INLINE_ALIAS; |
1021 | } |
1022 | } |
1023 | |
1024 | static void |
1025 | menu_layout_node_default_layout_set_values (MenuLayoutNode *node, |
1026 | const char *show_empty, |
1027 | const char *inline_menus, |
1028 | const char *inline_limit, |
1029 | const char *inline_header, |
1030 | const char *inline_alias) |
1031 | { |
1032 | MenuLayoutNodeDefaultLayout *default_layout; |
1033 | |
1034 | g_return_if_fail (node->type == MENU_LAYOUT_NODE_DEFAULT_LAYOUT)do { if ((node->type == MENU_LAYOUT_NODE_DEFAULT_LAYOUT)) { } else { g_return_if_fail_warning (((gchar*) 0), ((const char *) (__func__)), "node->type == MENU_LAYOUT_NODE_DEFAULT_LAYOUT" ); return; } } while (0); |
1035 | |
1036 | default_layout = (MenuLayoutNodeDefaultLayout *) node; |
1037 | |
1038 | menu_layout_values_set (&default_layout->layout_values, |
1039 | show_empty, |
1040 | inline_menus, |
1041 | inline_limit, |
1042 | inline_header, |
1043 | inline_alias); |
1044 | } |
1045 | |
1046 | static void |
1047 | menu_layout_node_menuname_set_values (MenuLayoutNode *node, |
1048 | const char *show_empty, |
1049 | const char *inline_menus, |
1050 | const char *inline_limit, |
1051 | const char *inline_header, |
1052 | const char *inline_alias) |
1053 | { |
1054 | MenuLayoutNodeMenuname *menuname; |
1055 | |
1056 | g_return_if_fail (node->type == MENU_LAYOUT_NODE_MENUNAME)do { if ((node->type == MENU_LAYOUT_NODE_MENUNAME)) { } else { g_return_if_fail_warning (((gchar*) 0), ((const char*) (__func__ )), "node->type == MENU_LAYOUT_NODE_MENUNAME"); return; } } while (0); |
1057 | |
1058 | menuname = (MenuLayoutNodeMenuname *) node; |
1059 | |
1060 | menu_layout_values_set (&menuname->layout_values, |
1061 | show_empty, |
1062 | inline_menus, |
1063 | inline_limit, |
1064 | inline_header, |
1065 | inline_alias); |
1066 | } |
1067 | |
1068 | void |
1069 | menu_layout_node_root_add_entries_monitor (MenuLayoutNode *node, |
1070 | MenuLayoutNodeEntriesChangedFunc callback, |
1071 | gpointer user_data) |
1072 | { |
1073 | MenuLayoutNodeEntriesMonitor *monitor; |
1074 | MenuLayoutNodeRoot *nr; |
1075 | GSList *tmp; |
1076 | |
1077 | g_return_if_fail (node->type == MENU_LAYOUT_NODE_ROOT)do { if ((node->type == MENU_LAYOUT_NODE_ROOT)) { } else { g_return_if_fail_warning (((gchar*) 0), ((const char*) (__func__ )), "node->type == MENU_LAYOUT_NODE_ROOT"); return; } } while (0); |
1078 | |
1079 | nr = (MenuLayoutNodeRoot *) node; |
1080 | |
1081 | tmp = nr->monitors; |
1082 | while (tmp != NULL((void*)0)) |
1083 | { |
1084 | monitor = tmp->data; |
1085 | |
1086 | if (monitor->callback == callback && |
1087 | monitor->user_data == user_data) |
1088 | break; |
1089 | |
1090 | tmp = tmp->next; |
1091 | } |
1092 | |
1093 | if (tmp == NULL((void*)0)) |
1094 | { |
1095 | monitor = g_new0 (MenuLayoutNodeEntriesMonitor, 1)((MenuLayoutNodeEntriesMonitor *) g_malloc0_n ((1), sizeof (MenuLayoutNodeEntriesMonitor ))); |
1096 | monitor->callback = callback; |
1097 | monitor->user_data = user_data; |
1098 | |
1099 | nr->monitors = g_slist_append (nr->monitors, monitor); |
1100 | } |
1101 | } |
1102 | |
1103 | void |
1104 | menu_layout_node_root_remove_entries_monitor (MenuLayoutNode *node, |
1105 | MenuLayoutNodeEntriesChangedFunc callback, |
1106 | gpointer user_data) |
1107 | { |
1108 | MenuLayoutNodeRoot *nr; |
1109 | GSList *tmp; |
1110 | |
1111 | g_return_if_fail (node->type == MENU_LAYOUT_NODE_ROOT)do { if ((node->type == MENU_LAYOUT_NODE_ROOT)) { } else { g_return_if_fail_warning (((gchar*) 0), ((const char*) (__func__ )), "node->type == MENU_LAYOUT_NODE_ROOT"); return; } } while (0); |
1112 | |
1113 | nr = (MenuLayoutNodeRoot *) node; |
1114 | |
1115 | tmp = nr->monitors; |
1116 | while (tmp != NULL((void*)0)) |
1117 | { |
1118 | MenuLayoutNodeEntriesMonitor *monitor = tmp->data; |
1119 | GSList *next = tmp->next; |
1120 | |
1121 | if (monitor->callback == callback && |
1122 | monitor->user_data == user_data) |
1123 | { |
1124 | nr->monitors = g_slist_delete_link (nr->monitors, tmp); |
1125 | g_free (monitor); |
1126 | } |
1127 | |
1128 | tmp = next; |
1129 | } |
1130 | } |
1131 | |
1132 | |
1133 | /* |
1134 | * Menu file parsing |
1135 | */ |
1136 | |
1137 | typedef struct |
1138 | { |
1139 | MenuLayoutNode *root; |
1140 | MenuLayoutNode *stack_top; |
1141 | } MenuParser; |
1142 | |
1143 | static void set_error (GError **err, |
1144 | GMarkupParseContext *context, |
1145 | int error_domain, |
1146 | int error_code, |
1147 | const char *format, |
1148 | ...) G_GNUC_PRINTF (5, 6)__attribute__((__format__ (__printf__, 5, 6))); |
1149 | |
1150 | static void add_context_to_error (GError **err, |
1151 | GMarkupParseContext *context); |
1152 | |
1153 | static void start_element_handler (GMarkupParseContext *context, |
1154 | const char *element_name, |
1155 | const char **attribute_names, |
1156 | const char **attribute_values, |
1157 | gpointer user_data, |
1158 | GError **error); |
1159 | static void end_element_handler (GMarkupParseContext *context, |
1160 | const char *element_name, |
1161 | gpointer user_data, |
1162 | GError **error); |
1163 | static void text_handler (GMarkupParseContext *context, |
1164 | const char *text, |
1165 | gsize text_len, |
1166 | gpointer user_data, |
1167 | GError **error); |
1168 | static void passthrough_handler (GMarkupParseContext *context, |
1169 | const char *passthrough_text, |
1170 | gsize text_len, |
1171 | gpointer user_data, |
1172 | GError **error); |
1173 | |
1174 | |
1175 | static GMarkupParser menu_funcs = { |
1176 | start_element_handler, |
1177 | end_element_handler, |
1178 | text_handler, |
1179 | passthrough_handler, |
1180 | NULL((void*)0) |
1181 | }; |
1182 | |
1183 | static void |
1184 | set_error (GError **err, |
1185 | GMarkupParseContext *context, |
1186 | int error_domain, |
1187 | int error_code, |
1188 | const char *format, |
1189 | ...) |
1190 | { |
1191 | int line, ch; |
1192 | va_list args; |
1193 | char *str; |
1194 | |
1195 | g_markup_parse_context_get_position (context, &line, &ch); |
1196 | |
1197 | va_start (args, format)__builtin_va_start(args, format); |
1198 | str = g_strdup_vprintf (format, args); |
1199 | va_end (args)__builtin_va_end(args); |
1200 | |
1201 | g_set_error (err, error_domain, error_code, |
1202 | "Line %d character %d: %s", |
1203 | line, ch, str); |
1204 | |
1205 | g_free (str); |
1206 | } |
1207 | |
1208 | static void |
1209 | add_context_to_error (GError **err, |
1210 | GMarkupParseContext *context) |
1211 | { |
1212 | int line, ch; |
1213 | char *str; |
1214 | |
1215 | if (err == NULL((void*)0) || *err == NULL((void*)0)) |
1216 | return; |
1217 | |
1218 | g_markup_parse_context_get_position (context, &line, &ch); |
1219 | |
1220 | str = g_strdup_printf ("Line %d character %d: %s", |
1221 | line, ch, (*err)->message); |
1222 | g_free ((*err)->message); |
1223 | (*err)->message = str; |
1224 | } |
1225 | |
1226 | #define ELEMENT_IS(name)(strcmp (element_name, (name)) == 0) (strcmp (element_name, (name)) == 0) |
1227 | |
1228 | typedef struct |
1229 | { |
1230 | const char *name; |
1231 | const char **retloc; |
1232 | } LocateAttr; |
1233 | |
1234 | static gboolean |
1235 | locate_attributes (GMarkupParseContext *context, |
1236 | const char *element_name, |
1237 | const char **attribute_names, |
1238 | const char **attribute_values, |
1239 | GError **error, |
1240 | const char *first_attribute_name, |
1241 | const char **first_attribute_retloc, |
1242 | ...) |
1243 | { |
1244 | #define MAX_ATTRS 24 |
1245 | LocateAttr attrs[MAX_ATTRS]; |
1246 | int n_attrs; |
1247 | va_list args; |
1248 | const char *name; |
1249 | const char **retloc; |
1250 | gboolean retval; |
1251 | int i; |
1252 | |
1253 | g_return_val_if_fail (first_attribute_name != NULL, FALSE)do { if ((first_attribute_name != ((void*)0))) { } else { g_return_if_fail_warning (((gchar*) 0), ((const char*) (__func__)), "first_attribute_name != NULL" ); return ((0)); } } while (0); |
1254 | g_return_val_if_fail (first_attribute_retloc != NULL, FALSE)do { if ((first_attribute_retloc != ((void*)0))) { } else { g_return_if_fail_warning (((gchar*) 0), ((const char*) (__func__)), "first_attribute_retloc != NULL" ); return ((0)); } } while (0); |
1255 | |
1256 | retval = TRUE(!(0)); |
1257 | |
1258 | n_attrs = 1; |
1259 | attrs[0].name = first_attribute_name; |
1260 | attrs[0].retloc = first_attribute_retloc; |
1261 | *first_attribute_retloc = NULL((void*)0); |
1262 | |
1263 | va_start (args, first_attribute_retloc)__builtin_va_start(args, first_attribute_retloc); |
1264 | |
1265 | name = va_arg (args, const char *)__builtin_va_arg(args, const char *); |
1266 | retloc = va_arg (args, const char **)__builtin_va_arg(args, const char **); |
1267 | |
1268 | while (name != NULL((void*)0)) |
1269 | { |
1270 | g_return_val_if_fail (retloc != NULL, FALSE)do { if ((retloc != ((void*)0))) { } else { g_return_if_fail_warning (((gchar*) 0), ((const char*) (__func__)), "retloc != NULL") ; return ((0)); } } while (0); |
1271 | |
1272 | g_assert (n_attrs < MAX_ATTRS)do { if (n_attrs < MAX_ATTRS) ; else g_assertion_message_expr (((gchar*) 0), "menu-layout.c", 1272, ((const char*) (__func__ )), "n_attrs < MAX_ATTRS"); } while (0); |
1273 | |
1274 | attrs[n_attrs].name = name; |
1275 | attrs[n_attrs].retloc = retloc; |
1276 | n_attrs += 1; |
1277 | *retloc = NULL((void*)0); |
1278 | |
1279 | name = va_arg (args, const char *)__builtin_va_arg(args, const char *); |
1280 | retloc = va_arg (args, const char **)__builtin_va_arg(args, const char **); |
1281 | } |
1282 | |
1283 | va_end (args)__builtin_va_end(args); |
1284 | |
1285 | i = 0; |
1286 | while (attribute_names[i]) |
1287 | { |
1288 | int j; |
1289 | |
1290 | j = 0; |
1291 | while (j < n_attrs) |
1292 | { |
1293 | if (strcmp (attrs[j].name, attribute_names[i]) == 0) |
1294 | { |
1295 | retloc = attrs[j].retloc; |
1296 | |
1297 | if (*retloc != NULL((void*)0)) |
1298 | { |
1299 | set_error (error, context, |
1300 | G_MARKUP_ERRORg_markup_error_quark (), G_MARKUP_ERROR_PARSE, |
1301 | "Attribute \"%s\" repeated twice on the same <%s> element", |
1302 | attrs[j].name, element_name); |
1303 | retval = FALSE(0); |
1304 | goto out; |
1305 | } |
1306 | |
1307 | *retloc = attribute_values[i]; |
1308 | break; |
1309 | } |
1310 | |
1311 | ++j; |
1312 | } |
1313 | |
1314 | if (j == n_attrs) |
1315 | { |
1316 | set_error (error, context, |
1317 | G_MARKUP_ERRORg_markup_error_quark (), G_MARKUP_ERROR_PARSE, |
1318 | "Attribute \"%s\" is invalid on <%s> element in this context", |
1319 | attribute_names[i], element_name); |
1320 | retval = FALSE(0); |
1321 | goto out; |
1322 | } |
1323 | |
1324 | ++i; |
1325 | } |
1326 | |
1327 | out: |
1328 | return retval; |
1329 | |
1330 | #undef MAX_ATTRS |
1331 | } |
1332 | |
1333 | static gboolean |
1334 | check_no_attributes (GMarkupParseContext *context, |
1335 | const char *element_name, |
1336 | const char **attribute_names, |
1337 | const char **attribute_values G_GNUC_UNUSED__attribute__ ((__unused__)), |
1338 | GError **error) |
1339 | { |
1340 | if (attribute_names[0] != NULL((void*)0)) |
1341 | { |
1342 | set_error (error, context, |
1343 | G_MARKUP_ERRORg_markup_error_quark (), G_MARKUP_ERROR_PARSE, |
1344 | "Attribute \"%s\" is invalid on <%s> element in this context", |
1345 | attribute_names[0], element_name); |
1346 | return FALSE(0); |
1347 | } |
1348 | |
1349 | return TRUE(!(0)); |
1350 | } |
1351 | |
1352 | static int |
1353 | has_child_of_type (MenuLayoutNode *node, |
1354 | MenuLayoutNodeType type) |
1355 | { |
1356 | MenuLayoutNode *iter; |
1357 | |
1358 | iter = node->children; |
1359 | while (iter) |
1360 | { |
1361 | if (iter->type == type) |
1362 | return TRUE(!(0)); |
1363 | |
1364 | iter = node_next (iter); |
1365 | } |
1366 | |
1367 | return FALSE(0); |
1368 | } |
1369 | |
1370 | static void |
1371 | push_node (MenuParser *parser, |
1372 | MenuLayoutNodeType type) |
1373 | { |
1374 | MenuLayoutNode *node; |
1375 | |
1376 | node = menu_layout_node_new (type); |
1377 | menu_layout_node_append_child (parser->stack_top, node); |
1378 | menu_layout_node_unref (node); |
1379 | |
1380 | parser->stack_top = node; |
1381 | } |
1382 | |
1383 | static void |
1384 | start_menu_element (MenuParser *parser, |
1385 | GMarkupParseContext *context, |
1386 | const char *element_name, |
1387 | const char **attribute_names, |
1388 | const char **attribute_values, |
1389 | GError **error) |
1390 | { |
1391 | if (!check_no_attributes (context, element_name, |
1392 | attribute_names, attribute_values, |
1393 | error)) |
1394 | return; |
1395 | |
1396 | if (!(parser->stack_top->type == MENU_LAYOUT_NODE_ROOT || |
1397 | parser->stack_top->type == MENU_LAYOUT_NODE_MENU)) |
1398 | { |
1399 | set_error (error, context, |
1400 | G_MARKUP_ERRORg_markup_error_quark (), G_MARKUP_ERROR_PARSE, |
1401 | "<Menu> element can only appear below other <Menu> elements or at toplevel\n"); |
1402 | } |
1403 | else |
1404 | { |
1405 | push_node (parser, MENU_LAYOUT_NODE_MENU); |
1406 | } |
1407 | } |
1408 | |
1409 | static void |
1410 | start_menu_child_element (MenuParser *parser, |
1411 | GMarkupParseContext *context, |
1412 | const char *element_name, |
1413 | const char **attribute_names, |
1414 | const char **attribute_values, |
1415 | GError **error) |
1416 | { |
1417 | if (ELEMENT_IS ("LegacyDir")(strcmp (element_name, ("LegacyDir")) == 0)) |
1418 | { |
1419 | const char *prefix; |
1420 | |
1421 | push_node (parser, MENU_LAYOUT_NODE_LEGACY_DIR); |
1422 | |
1423 | if (!locate_attributes (context, element_name, |
1424 | attribute_names, attribute_values, |
1425 | error, |
1426 | "prefix", &prefix, |
1427 | NULL((void*)0))) |
1428 | return; |
1429 | |
1430 | menu_layout_node_legacy_dir_set_prefix (parser->stack_top, prefix); |
1431 | } |
1432 | else if (ELEMENT_IS ("MergeFile")(strcmp (element_name, ("MergeFile")) == 0)) |
1433 | { |
1434 | const char *type; |
1435 | |
1436 | push_node (parser, MENU_LAYOUT_NODE_MERGE_FILE); |
1437 | |
1438 | if (!locate_attributes (context, element_name, |
1439 | attribute_names, attribute_values, |
1440 | error, |
1441 | "type", &type, |
1442 | NULL((void*)0))) |
1443 | return; |
1444 | |
1445 | if (type != NULL((void*)0) && strcmp (type, "parent") == 0) |
1446 | { |
1447 | menu_layout_node_merge_file_set_type (parser->stack_top, |
1448 | MENU_MERGE_FILE_TYPE_PARENT); |
1449 | } |
1450 | } |
1451 | else if (ELEMENT_IS ("DefaultLayout")(strcmp (element_name, ("DefaultLayout")) == 0)) |
1452 | { |
1453 | const char *show_empty; |
1454 | const char *inline_menus; |
1455 | const char *inline_limit; |
1456 | const char *inline_header; |
1457 | const char *inline_alias; |
1458 | |
1459 | push_node (parser, MENU_LAYOUT_NODE_DEFAULT_LAYOUT); |
1460 | |
1461 | locate_attributes (context, element_name, |
1462 | attribute_names, attribute_values, |
1463 | error, |
1464 | "show_empty", &show_empty, |
1465 | "inline", &inline_menus, |
1466 | "inline_limit", &inline_limit, |
1467 | "inline_header", &inline_header, |
1468 | "inline_alias", &inline_alias, |
1469 | NULL((void*)0)); |
1470 | |
1471 | menu_layout_node_default_layout_set_values (parser->stack_top, |
1472 | show_empty, |
1473 | inline_menus, |
1474 | inline_limit, |
1475 | inline_header, |
1476 | inline_alias); |
1477 | } |
1478 | else |
1479 | { |
1480 | if (!check_no_attributes (context, element_name, |
1481 | attribute_names, attribute_values, |
1482 | error)) |
1483 | return; |
1484 | |
1485 | if (ELEMENT_IS ("AppDir")(strcmp (element_name, ("AppDir")) == 0)) |
1486 | { |
1487 | push_node (parser, MENU_LAYOUT_NODE_APP_DIR); |
1488 | } |
1489 | else if (ELEMENT_IS ("DefaultAppDirs")(strcmp (element_name, ("DefaultAppDirs")) == 0)) |
1490 | { |
1491 | push_node (parser, MENU_LAYOUT_NODE_DEFAULT_APP_DIRS); |
1492 | } |
1493 | else if (ELEMENT_IS ("DirectoryDir")(strcmp (element_name, ("DirectoryDir")) == 0)) |
1494 | { |
1495 | push_node (parser, MENU_LAYOUT_NODE_DIRECTORY_DIR); |
1496 | } |
1497 | else if (ELEMENT_IS ("DefaultDirectoryDirs")(strcmp (element_name, ("DefaultDirectoryDirs")) == 0)) |
1498 | { |
1499 | push_node (parser, MENU_LAYOUT_NODE_DEFAULT_DIRECTORY_DIRS); |
1500 | } |
1501 | else if (ELEMENT_IS ("DefaultMergeDirs")(strcmp (element_name, ("DefaultMergeDirs")) == 0)) |
1502 | { |
1503 | push_node (parser, MENU_LAYOUT_NODE_DEFAULT_MERGE_DIRS); |
1504 | } |
1505 | else if (ELEMENT_IS ("Name")(strcmp (element_name, ("Name")) == 0)) |
1506 | { |
1507 | if (has_child_of_type (parser->stack_top, MENU_LAYOUT_NODE_NAME)) |
1508 | { |
1509 | set_error (error, context, |
1510 | G_MARKUP_ERRORg_markup_error_quark (), G_MARKUP_ERROR_PARSE, |
1511 | "Multiple <Name> elements in a <Menu> element is not allowed\n"); |
1512 | return; |
1513 | } |
1514 | |
1515 | push_node (parser, MENU_LAYOUT_NODE_NAME); |
1516 | } |
1517 | else if (ELEMENT_IS ("Directory")(strcmp (element_name, ("Directory")) == 0)) |
1518 | { |
1519 | push_node (parser, MENU_LAYOUT_NODE_DIRECTORY); |
1520 | } |
1521 | else if (ELEMENT_IS ("OnlyUnallocated")(strcmp (element_name, ("OnlyUnallocated")) == 0)) |
1522 | { |
1523 | push_node (parser, MENU_LAYOUT_NODE_ONLY_UNALLOCATED); |
1524 | } |
1525 | else if (ELEMENT_IS ("NotOnlyUnallocated")(strcmp (element_name, ("NotOnlyUnallocated")) == 0)) |
1526 | { |
1527 | push_node (parser, MENU_LAYOUT_NODE_NOT_ONLY_UNALLOCATED); |
1528 | } |
1529 | else if (ELEMENT_IS ("Include")(strcmp (element_name, ("Include")) == 0)) |
1530 | { |
1531 | push_node (parser, MENU_LAYOUT_NODE_INCLUDE); |
1532 | } |
1533 | else if (ELEMENT_IS ("Exclude")(strcmp (element_name, ("Exclude")) == 0)) |
1534 | { |
1535 | push_node (parser, MENU_LAYOUT_NODE_EXCLUDE); |
1536 | } |
1537 | else if (ELEMENT_IS ("MergeDir")(strcmp (element_name, ("MergeDir")) == 0)) |
1538 | { |
1539 | push_node (parser, MENU_LAYOUT_NODE_MERGE_DIR); |
1540 | } |
1541 | else if (ELEMENT_IS ("KDELegacyDirs")(strcmp (element_name, ("KDELegacyDirs")) == 0)) |
1542 | { |
1543 | push_node (parser, MENU_LAYOUT_NODE_KDE_LEGACY_DIRS); |
1544 | } |
1545 | else if (ELEMENT_IS ("Move")(strcmp (element_name, ("Move")) == 0)) |
1546 | { |
1547 | push_node (parser, MENU_LAYOUT_NODE_MOVE); |
1548 | } |
1549 | else if (ELEMENT_IS ("Deleted")(strcmp (element_name, ("Deleted")) == 0)) |
1550 | { |
1551 | push_node (parser, MENU_LAYOUT_NODE_DELETED); |
1552 | |
1553 | } |
1554 | else if (ELEMENT_IS ("NotDeleted")(strcmp (element_name, ("NotDeleted")) == 0)) |
1555 | { |
1556 | push_node (parser, MENU_LAYOUT_NODE_NOT_DELETED); |
1557 | } |
1558 | else if (ELEMENT_IS ("Layout")(strcmp (element_name, ("Layout")) == 0)) |
1559 | { |
1560 | push_node (parser, MENU_LAYOUT_NODE_LAYOUT); |
1561 | } |
1562 | else |
1563 | { |
1564 | set_error (error, context, |
1565 | G_MARKUP_ERRORg_markup_error_quark (), G_MARKUP_ERROR_UNKNOWN_ELEMENT, |
1566 | "Element <%s> may not appear below <%s>\n", |
1567 | element_name, "Menu"); |
1568 | } |
1569 | } |
1570 | } |
1571 | |
1572 | static void |
1573 | start_matching_rule_element (MenuParser *parser, |
1574 | GMarkupParseContext *context, |
1575 | const char *element_name, |
1576 | const char **attribute_names, |
1577 | const char **attribute_values, |
1578 | GError **error) |
1579 | { |
1580 | if (!check_no_attributes (context, element_name, |
1581 | attribute_names, attribute_values, |
1582 | error)) |
1583 | return; |
1584 | |
1585 | |
1586 | if (ELEMENT_IS ("Filename")(strcmp (element_name, ("Filename")) == 0)) |
1587 | { |
1588 | push_node (parser, MENU_LAYOUT_NODE_FILENAME); |
1589 | } |
1590 | else if (ELEMENT_IS ("Category")(strcmp (element_name, ("Category")) == 0)) |
1591 | { |
1592 | push_node (parser, MENU_LAYOUT_NODE_CATEGORY); |
1593 | } |
1594 | else if (ELEMENT_IS ("All")(strcmp (element_name, ("All")) == 0)) |
1595 | { |
1596 | push_node (parser, MENU_LAYOUT_NODE_ALL); |
1597 | } |
1598 | else if (ELEMENT_IS ("And")(strcmp (element_name, ("And")) == 0)) |
1599 | { |
1600 | push_node (parser, MENU_LAYOUT_NODE_AND); |
1601 | } |
1602 | else if (ELEMENT_IS ("Or")(strcmp (element_name, ("Or")) == 0)) |
1603 | { |
1604 | push_node (parser, MENU_LAYOUT_NODE_OR); |
1605 | } |
1606 | else if (ELEMENT_IS ("Not")(strcmp (element_name, ("Not")) == 0)) |
1607 | { |
1608 | push_node (parser, MENU_LAYOUT_NODE_NOT); |
1609 | } |
1610 | else |
1611 | { |
1612 | set_error (error, context, |
1613 | G_MARKUP_ERRORg_markup_error_quark (), G_MARKUP_ERROR_UNKNOWN_ELEMENT, |
1614 | "Element <%s> may not appear in this context\n", |
1615 | element_name); |
1616 | } |
1617 | } |
1618 | |
1619 | static void |
1620 | start_move_child_element (MenuParser *parser, |
1621 | GMarkupParseContext *context, |
1622 | const char *element_name, |
1623 | const char **attribute_names, |
1624 | const char **attribute_values, |
1625 | GError **error) |
1626 | { |
1627 | if (!check_no_attributes (context, element_name, |
1628 | attribute_names, attribute_values, |
1629 | error)) |
1630 | return; |
1631 | |
1632 | if (ELEMENT_IS ("Old")(strcmp (element_name, ("Old")) == 0)) |
1633 | { |
1634 | push_node (parser, MENU_LAYOUT_NODE_OLD); |
1635 | } |
1636 | else if (ELEMENT_IS ("New")(strcmp (element_name, ("New")) == 0)) |
1637 | { |
1638 | push_node (parser, MENU_LAYOUT_NODE_NEW); |
1639 | } |
1640 | else |
1641 | { |
1642 | set_error (error, context, |
1643 | G_MARKUP_ERRORg_markup_error_quark (), G_MARKUP_ERROR_UNKNOWN_ELEMENT, |
1644 | "Element <%s> may not appear below <%s>\n", |
1645 | element_name, "Move"); |
1646 | } |
1647 | } |
1648 | |
1649 | static void |
1650 | start_layout_child_element (MenuParser *parser, |
1651 | GMarkupParseContext *context, |
1652 | const char *element_name, |
1653 | const char **attribute_names, |
1654 | const char **attribute_values, |
1655 | GError **error) |
1656 | { |
1657 | if (ELEMENT_IS ("Menuname")(strcmp (element_name, ("Menuname")) == 0)) |
1658 | { |
1659 | const char *show_empty; |
1660 | const char *inline_menus; |
1661 | const char *inline_limit; |
1662 | const char *inline_header; |
1663 | const char *inline_alias; |
1664 | |
1665 | push_node (parser, MENU_LAYOUT_NODE_MENUNAME); |
1666 | |
1667 | locate_attributes (context, element_name, |
1668 | attribute_names, attribute_values, |
1669 | error, |
1670 | "show_empty", &show_empty, |
1671 | "inline", &inline_menus, |
1672 | "inline_limit", &inline_limit, |
1673 | "inline_header", &inline_header, |
1674 | "inline_alias", &inline_alias, |
1675 | NULL((void*)0)); |
1676 | |
1677 | menu_layout_node_menuname_set_values (parser->stack_top, |
1678 | show_empty, |
1679 | inline_menus, |
1680 | inline_limit, |
1681 | inline_header, |
1682 | inline_alias); |
1683 | } |
1684 | else if (ELEMENT_IS ("Merge")(strcmp (element_name, ("Merge")) == 0)) |
1685 | { |
1686 | const char *type; |
1687 | |
1688 | push_node (parser, MENU_LAYOUT_NODE_MERGE); |
1689 | |
1690 | locate_attributes (context, element_name, |
1691 | attribute_names, attribute_values, |
1692 | error, |
1693 | "type", &type, |
1694 | NULL((void*)0)); |
1695 | |
1696 | menu_layout_node_merge_set_type (parser->stack_top, type); |
1697 | } |
1698 | else |
1699 | { |
1700 | if (!check_no_attributes (context, element_name, |
1701 | attribute_names, attribute_values, |
1702 | error)) |
1703 | return; |
1704 | |
1705 | if (ELEMENT_IS ("Filename")(strcmp (element_name, ("Filename")) == 0)) |
1706 | { |
1707 | push_node (parser, MENU_LAYOUT_NODE_FILENAME); |
1708 | } |
1709 | else if (ELEMENT_IS ("Separator")(strcmp (element_name, ("Separator")) == 0)) |
1710 | { |
1711 | push_node (parser, MENU_LAYOUT_NODE_SEPARATOR); |
1712 | } |
1713 | else |
1714 | { |
1715 | set_error (error, context, |
1716 | G_MARKUP_ERRORg_markup_error_quark (), G_MARKUP_ERROR_UNKNOWN_ELEMENT, |
1717 | "Element <%s> may not appear below <%s>\n", |
1718 | element_name, "Move"); |
1719 | } |
1720 | } |
1721 | } |
1722 | |
1723 | static void |
1724 | start_element_handler (GMarkupParseContext *context, |
1725 | const char *element_name, |
1726 | const char **attribute_names, |
1727 | const char **attribute_values, |
1728 | gpointer user_data, |
1729 | GError **error) |
1730 | { |
1731 | MenuParser *parser = user_data; |
1732 | |
1733 | if (ELEMENT_IS ("Menu")(strcmp (element_name, ("Menu")) == 0)) |
1734 | { |
1735 | if (parser->stack_top == parser->root && |
1736 | has_child_of_type (parser->root, MENU_LAYOUT_NODE_MENU)) |
1737 | { |
1738 | set_error (error, context, |
1739 | G_MARKUP_ERRORg_markup_error_quark (), G_MARKUP_ERROR_PARSE, |
1740 | "Multiple root elements in menu file, only one toplevel <Menu> is allowed\n"); |
1741 | return; |
1742 | } |
1743 | |
1744 | start_menu_element (parser, context, element_name, |
1745 | attribute_names, attribute_values, |
1746 | error); |
1747 | } |
1748 | else if (parser->stack_top == parser->root) |
1749 | { |
1750 | set_error (error, context, |
1751 | G_MARKUP_ERRORg_markup_error_quark (), G_MARKUP_ERROR_PARSE, |
1752 | "Root element in a menu file must be <Menu>, not <%s>\n", |
1753 | element_name); |
1754 | } |
1755 | else if (parser->stack_top->type == MENU_LAYOUT_NODE_MENU) |
1756 | { |
1757 | start_menu_child_element (parser, context, element_name, |
1758 | attribute_names, attribute_values, |
1759 | error); |
1760 | } |
1761 | else if (parser->stack_top->type == MENU_LAYOUT_NODE_INCLUDE || |
1762 | parser->stack_top->type == MENU_LAYOUT_NODE_EXCLUDE || |
1763 | parser->stack_top->type == MENU_LAYOUT_NODE_AND || |
1764 | parser->stack_top->type == MENU_LAYOUT_NODE_OR || |
1765 | parser->stack_top->type == MENU_LAYOUT_NODE_NOT) |
1766 | { |
1767 | start_matching_rule_element (parser, context, element_name, |
1768 | attribute_names, attribute_values, |
1769 | error); |
1770 | } |
1771 | else if (parser->stack_top->type == MENU_LAYOUT_NODE_MOVE) |
1772 | { |
1773 | start_move_child_element (parser, context, element_name, |
1774 | attribute_names, attribute_values, |
1775 | error); |
1776 | } |
1777 | else if (parser->stack_top->type == MENU_LAYOUT_NODE_LAYOUT || |
1778 | parser->stack_top->type == MENU_LAYOUT_NODE_DEFAULT_LAYOUT) |
1779 | { |
1780 | start_layout_child_element (parser, context, element_name, |
1781 | attribute_names, attribute_values, |
1782 | error); |
1783 | } |
1784 | else |
1785 | { |
1786 | set_error (error, context, |
1787 | G_MARKUP_ERRORg_markup_error_quark (), G_MARKUP_ERROR_UNKNOWN_ELEMENT, |
1788 | "Element <%s> may not appear in this context\n", |
1789 | element_name); |
1790 | } |
1791 | |
1792 | add_context_to_error (error, context); |
1793 | } |
1794 | |
1795 | /* we want to make sure that the <Layout> or <DefaultLayout> is either empty, |
1796 | * or contain one <Merge> of type "all", or contain one <Merge> of type "menus" |
1797 | * and one <Merge> of type "files". If this is not the case, we try to clean up |
1798 | * things: |
1799 | * + if there is at least one <Merge> of type "all", then we only keep the |
1800 | * last <Merge> of type "all" and remove all others <Merge> |
1801 | * + if there is no <Merge> with type "all", we keep only the last <Merge> of |
1802 | * type "menus" and the last <Merge> of type "files". If there's no <Merge> |
1803 | * of type "menus" we append one, and then if there's no <Merge> of type |
1804 | * "files", we append one. (So menus are before files) |
1805 | */ |
1806 | static gboolean |
1807 | fixup_layout_node (GMarkupParseContext *context G_GNUC_UNUSED__attribute__ ((__unused__)), |
1808 | MenuParser *parser G_GNUC_UNUSED__attribute__ ((__unused__)), |
1809 | MenuLayoutNode *node, |
1810 | GError **error G_GNUC_UNUSED__attribute__ ((__unused__))) |
1811 | { |
1812 | MenuLayoutNode *child; |
1813 | MenuLayoutNode *last_all; |
1814 | MenuLayoutNode *last_menus; |
1815 | MenuLayoutNode *last_files; |
1816 | int n_all; |
1817 | int n_menus; |
1818 | int n_files; |
1819 | |
1820 | if (!node->children) |
1821 | { |
1822 | return TRUE(!(0)); |
1823 | } |
1824 | |
1825 | last_all = NULL((void*)0); |
1826 | last_menus = NULL((void*)0); |
1827 | last_files = NULL((void*)0); |
1828 | n_all = 0; |
1829 | n_menus = 0; |
1830 | n_files = 0; |
1831 | |
1832 | child = node->children; |
1833 | while (child != NULL((void*)0)) |
1834 | { |
1835 | switch (child->type) |
1836 | { |
1837 | case MENU_LAYOUT_NODE_MERGE: |
1838 | switch (menu_layout_node_merge_get_type (child)) |
1839 | { |
1840 | case MENU_LAYOUT_MERGE_NONE: |
1841 | break; |
1842 | |
1843 | case MENU_LAYOUT_MERGE_MENUS: |
1844 | last_menus = child; |
1845 | n_menus++; |
1846 | break; |
1847 | |
1848 | case MENU_LAYOUT_MERGE_FILES: |
1849 | last_files = child; |
1850 | n_files++; |
1851 | break; |
1852 | |
1853 | case MENU_LAYOUT_MERGE_ALL: |
1854 | last_all = child; |
1855 | n_all++; |
1856 | break; |
1857 | |
1858 | default: |
1859 | g_assert_not_reached ()do { g_assertion_message_expr (((gchar*) 0), "menu-layout.c", 1859, ((const char*) (__func__)), ((void*)0)); } while (0); |
1860 | break; |
1861 | } |
1862 | break; |
1863 | |
1864 | default: |
1865 | break; |
1866 | } |
1867 | |
1868 | child = node_next (child); |
1869 | } |
1870 | |
1871 | if ((n_all == 1 && n_menus == 0 && n_files == 0) || |
1872 | (n_all == 0 && n_menus == 1 && n_files == 1)) |
1873 | { |
1874 | return TRUE(!(0)); |
1875 | } |
1876 | else if (n_all > 1 || n_menus > 1 || n_files > 1 || |
1877 | (n_all == 1 && (n_menus != 0 || n_files != 0))) |
1878 | { |
1879 | child = node->children; |
1880 | while (child != NULL((void*)0)) |
1881 | { |
1882 | MenuLayoutNode *next; |
1883 | |
1884 | next = node_next (child); |
1885 | |
1886 | switch (child->type) |
1887 | { |
1888 | case MENU_LAYOUT_NODE_MERGE: |
1889 | switch (menu_layout_node_merge_get_type (child)) |
1890 | { |
1891 | case MENU_LAYOUT_MERGE_NONE: |
1892 | break; |
1893 | |
1894 | case MENU_LAYOUT_MERGE_MENUS: |
1895 | if (n_all || last_menus != child) |
1896 | { |
1897 | menu_verbose ("removing duplicated merge menus element\n"); |
1898 | menu_layout_node_unlink (child); |
1899 | } |
1900 | break; |
1901 | |
1902 | case MENU_LAYOUT_MERGE_FILES: |
1903 | if (n_all || last_files != child) |
1904 | { |
1905 | menu_verbose ("removing duplicated merge files element\n"); |
1906 | menu_layout_node_unlink (child); |
1907 | } |
1908 | break; |
1909 | |
1910 | case MENU_LAYOUT_MERGE_ALL: |
1911 | if (last_all != child) |
1912 | { |
1913 | menu_verbose ("removing duplicated merge all element\n"); |
1914 | menu_layout_node_unlink (child); |
1915 | } |
1916 | break; |
1917 | |
1918 | default: |
1919 | g_assert_not_reached ()do { g_assertion_message_expr (((gchar*) 0), "menu-layout.c", 1919, ((const char*) (__func__)), ((void*)0)); } while (0); |
1920 | break; |
1921 | } |
1922 | break; |
1923 | |
1924 | default: |
1925 | break; |
1926 | } |
1927 | |
1928 | child = next; |
1929 | } |
1930 | } |
1931 | |
1932 | if (n_all == 0 && n_menus == 0) |
1933 | { |
1934 | last_menus = menu_layout_node_new (MENU_LAYOUT_NODE_MERGE); |
1935 | menu_layout_node_merge_set_type (last_menus, "menus"); |
1936 | menu_verbose ("appending missing merge menus element\n"); |
1937 | menu_layout_node_append_child (node, last_menus); |
1938 | } |
1939 | |
1940 | if (n_all == 0 && n_files == 0) |
1941 | { |
1942 | last_files = menu_layout_node_new (MENU_LAYOUT_NODE_MERGE); |
1943 | menu_layout_node_merge_set_type (last_files, "files"); |
1944 | menu_verbose ("appending missing merge files element\n"); |
1945 | menu_layout_node_append_child (node, last_files); |
1946 | } |
1947 | |
1948 | return TRUE(!(0)); |
1949 | } |
1950 | |
1951 | /* we want to a) check that we have old-new pairs and b) canonicalize |
1952 | * such that each <Move> has exactly one old-new pair |
1953 | */ |
1954 | static gboolean |
1955 | fixup_move_node (GMarkupParseContext *context, |
1956 | MenuParser *parser G_GNUC_UNUSED__attribute__ ((__unused__)), |
1957 | MenuLayoutNode *node, |
1958 | GError **error) |
1959 | { |
1960 | MenuLayoutNode *child; |
1961 | int n_old; |
1962 | int n_new; |
1963 | |
1964 | n_old = 0; |
1965 | n_new = 0; |
1966 | |
1967 | child = node->children; |
1968 | while (child != NULL((void*)0)) |
1969 | { |
1970 | switch (child->type) |
1971 | { |
1972 | case MENU_LAYOUT_NODE_OLD: |
1973 | if (n_new != n_old) |
1974 | { |
1975 | set_error (error, context, |
1976 | G_MARKUP_ERRORg_markup_error_quark (), G_MARKUP_ERROR_PARSE, |
1977 | "<Old>/<New> elements not paired properly\n"); |
1978 | return FALSE(0); |
1979 | } |
1980 | |
1981 | n_old += 1; |
1982 | |
1983 | break; |
1984 | |
1985 | case MENU_LAYOUT_NODE_NEW: |
1986 | n_new += 1; |
1987 | |
1988 | if (n_new != n_old) |
1989 | { |
1990 | set_error (error, context, |
1991 | G_MARKUP_ERRORg_markup_error_quark (), G_MARKUP_ERROR_PARSE, |
1992 | "<Old>/<New> elements not paired properly\n"); |
1993 | return FALSE(0); |
1994 | } |
1995 | |
1996 | break; |
1997 | |
1998 | default: |
1999 | g_assert_not_reached ()do { g_assertion_message_expr (((gchar*) 0), "menu-layout.c", 1999, ((const char*) (__func__)), ((void*)0)); } while (0); |
2000 | break; |
2001 | } |
2002 | |
2003 | child = node_next (child); |
2004 | } |
2005 | |
2006 | if (n_new == 0 || n_old == 0) |
2007 | { |
2008 | set_error (error, context, |
2009 | G_MARKUP_ERRORg_markup_error_quark (), G_MARKUP_ERROR_PARSE, |
2010 | "<Old>/<New> elements missing under <Move>\n"); |
2011 | return FALSE(0); |
2012 | } |
2013 | |
2014 | g_assert (n_new == n_old)do { if (n_new == n_old) ; else g_assertion_message_expr (((gchar *) 0), "menu-layout.c", 2014, ((const char*) (__func__)), "n_new == n_old" ); } while (0); |
2015 | g_assert ((n_new + n_old) % 2 == 0)do { if ((n_new + n_old) % 2 == 0) ; else g_assertion_message_expr (((gchar*) 0), "menu-layout.c", 2015, ((const char*) (__func__ )), "(n_new + n_old) % 2 == 0"); } while (0); |
2016 | |
2017 | if (n_new > 1) |
2018 | { |
2019 | MenuLayoutNode *prev; |
2020 | MenuLayoutNode *append_after; |
2021 | |
2022 | /* Need to split the <Move> into multiple <Move> */ |
2023 | |
2024 | n_old = 0; |
2025 | n_new = 0; |
2026 | prev = NULL((void*)0); |
2027 | append_after = node; |
2028 | |
2029 | child = node->children; |
2030 | while (child != NULL((void*)0)) |
2031 | { |
2032 | MenuLayoutNode *next; |
2033 | |
2034 | next = node_next (child); |
2035 | |
2036 | switch (child->type) |
2037 | { |
2038 | case MENU_LAYOUT_NODE_OLD: |
2039 | n_old += 1; |
2040 | break; |
2041 | |
2042 | case MENU_LAYOUT_NODE_NEW: |
2043 | n_new += 1; |
2044 | break; |
2045 | |
2046 | default: |
2047 | g_assert_not_reached ()do { g_assertion_message_expr (((gchar*) 0), "menu-layout.c", 2047, ((const char*) (__func__)), ((void*)0)); } while (0); |
2048 | break; |
2049 | } |
2050 | |
2051 | if (n_old == n_new && |
2052 | n_old > 1) |
2053 | { |
2054 | /* Move the just-completed pair */ |
2055 | MenuLayoutNode *new_move; |
2056 | |
2057 | g_assert (prev != NULL)do { if (prev != ((void*)0)) ; else g_assertion_message_expr ( ((gchar*) 0), "menu-layout.c", 2057, ((const char*) (__func__ )), "prev != NULL"); } while (0); |
2058 | |
2059 | new_move = menu_layout_node_new (MENU_LAYOUT_NODE_MOVE); |
2060 | menu_verbose ("inserting new_move after append_after\n"); |
2061 | menu_layout_node_insert_after (append_after, new_move); |
2062 | append_after = new_move; |
2063 | |
2064 | menu_layout_node_steal (prev); |
2065 | menu_layout_node_steal (child); |
2066 | |
2067 | menu_verbose ("appending prev to new_move\n"); |
2068 | menu_layout_node_append_child (new_move, prev); |
2069 | menu_verbose ("appending child to new_move\n"); |
2070 | menu_layout_node_append_child (new_move, child); |
2071 | |
2072 | menu_verbose ("Created new move element old = %s new = %s\n", |
2073 | menu_layout_node_move_get_old (new_move), |
2074 | menu_layout_node_move_get_new (new_move)); |
2075 | |
2076 | menu_layout_node_unref (new_move); |
2077 | menu_layout_node_unref (prev); |
2078 | menu_layout_node_unref (child); |
2079 | |
2080 | prev = NULL((void*)0); |
2081 | } |
2082 | else |
2083 | { |
2084 | prev = child; |
Value stored to 'prev' is never read | |
2085 | } |
2086 | |
2087 | prev = child; |
2088 | child = next; |
2089 | } |
2090 | } |
2091 | |
2092 | return TRUE(!(0)); |
2093 | } |
2094 | |
2095 | static void |
2096 | end_element_handler (GMarkupParseContext *context, |
2097 | const char *element_name, |
2098 | gpointer user_data, |
2099 | GError **error) |
2100 | { |
2101 | MenuParser *parser = user_data; |
2102 | |
2103 | g_assert (parser->stack_top != NULL)do { if (parser->stack_top != ((void*)0)) ; else g_assertion_message_expr (((gchar*) 0), "menu-layout.c", 2103, ((const char*) (__func__ )), "parser->stack_top != NULL"); } while (0); |
2104 | |
2105 | switch (parser->stack_top->type) |
2106 | { |
2107 | case MENU_LAYOUT_NODE_APP_DIR: |
2108 | case MENU_LAYOUT_NODE_DIRECTORY_DIR: |
2109 | case MENU_LAYOUT_NODE_NAME: |
2110 | case MENU_LAYOUT_NODE_DIRECTORY: |
2111 | case MENU_LAYOUT_NODE_FILENAME: |
2112 | case MENU_LAYOUT_NODE_CATEGORY: |
2113 | case MENU_LAYOUT_NODE_MERGE_DIR: |
2114 | case MENU_LAYOUT_NODE_LEGACY_DIR: |
2115 | case MENU_LAYOUT_NODE_OLD: |
2116 | case MENU_LAYOUT_NODE_NEW: |
2117 | case MENU_LAYOUT_NODE_MENUNAME: |
2118 | if (menu_layout_node_get_content (parser->stack_top) == NULL((void*)0)) |
2119 | { |
2120 | set_error (error, context, |
2121 | G_MARKUP_ERRORg_markup_error_quark (), G_MARKUP_ERROR_INVALID_CONTENT, |
2122 | "Element <%s> is required to contain text and was empty\n", |
2123 | element_name); |
2124 | goto out; |
2125 | } |
2126 | break; |
2127 | |
2128 | case MENU_LAYOUT_NODE_MENU: |
2129 | if (!has_child_of_type (parser->stack_top, MENU_LAYOUT_NODE_NAME)) |
2130 | { |
2131 | set_error (error, context, |
2132 | G_MARKUP_ERRORg_markup_error_quark (), G_MARKUP_ERROR_PARSE, |
2133 | "<Menu> elements are required to contain a <Name> element\n"); |
2134 | goto out; |
2135 | } |
2136 | break; |
2137 | |
2138 | case MENU_LAYOUT_NODE_ROOT: |
2139 | case MENU_LAYOUT_NODE_PASSTHROUGH: |
2140 | case MENU_LAYOUT_NODE_DEFAULT_APP_DIRS: |
2141 | case MENU_LAYOUT_NODE_DEFAULT_DIRECTORY_DIRS: |
2142 | case MENU_LAYOUT_NODE_DEFAULT_MERGE_DIRS: |
2143 | case MENU_LAYOUT_NODE_ONLY_UNALLOCATED: |
2144 | case MENU_LAYOUT_NODE_NOT_ONLY_UNALLOCATED: |
2145 | case MENU_LAYOUT_NODE_INCLUDE: |
2146 | case MENU_LAYOUT_NODE_EXCLUDE: |
2147 | case MENU_LAYOUT_NODE_ALL: |
2148 | case MENU_LAYOUT_NODE_AND: |
2149 | case MENU_LAYOUT_NODE_OR: |
2150 | case MENU_LAYOUT_NODE_NOT: |
2151 | case MENU_LAYOUT_NODE_KDE_LEGACY_DIRS: |
2152 | case MENU_LAYOUT_NODE_DELETED: |
2153 | case MENU_LAYOUT_NODE_NOT_DELETED: |
2154 | case MENU_LAYOUT_NODE_SEPARATOR: |
2155 | case MENU_LAYOUT_NODE_MERGE: |
2156 | case MENU_LAYOUT_NODE_MERGE_FILE: |
2157 | break; |
2158 | |
2159 | case MENU_LAYOUT_NODE_LAYOUT: |
2160 | case MENU_LAYOUT_NODE_DEFAULT_LAYOUT: |
2161 | if (!fixup_layout_node (context, parser, parser->stack_top, error)) |
2162 | goto out; |
2163 | break; |
2164 | |
2165 | case MENU_LAYOUT_NODE_MOVE: |
2166 | if (!fixup_move_node (context, parser, parser->stack_top, error)) |
2167 | goto out; |
2168 | break; |
2169 | } |
2170 | |
2171 | out: |
2172 | parser->stack_top = parser->stack_top->parent; |
2173 | } |
2174 | |
2175 | static gboolean |
2176 | all_whitespace (const char *text, |
2177 | int text_len) |
2178 | { |
2179 | const char *p; |
2180 | const char *end; |
2181 | |
2182 | p = text; |
2183 | end = text + text_len; |
2184 | |
2185 | while (p != end) |
2186 | { |
2187 | if (!g_ascii_isspace (*p)((g_ascii_table[(guchar) (*p)] & G_ASCII_SPACE) != 0)) |
2188 | return FALSE(0); |
2189 | |
2190 | p = g_utf8_next_char (p)((p) + g_utf8_skip[*(const guchar *)(p)]); |
2191 | } |
2192 | |
2193 | return TRUE(!(0)); |
2194 | } |
2195 | |
2196 | static void |
2197 | text_handler (GMarkupParseContext *context, |
2198 | const char *text, |
2199 | gsize text_len, |
2200 | gpointer user_data, |
2201 | GError **error) |
2202 | { |
2203 | MenuParser *parser = user_data; |
2204 | |
2205 | switch (parser->stack_top->type) |
2206 | { |
2207 | case MENU_LAYOUT_NODE_APP_DIR: |
2208 | case MENU_LAYOUT_NODE_DIRECTORY_DIR: |
2209 | case MENU_LAYOUT_NODE_NAME: |
2210 | case MENU_LAYOUT_NODE_DIRECTORY: |
2211 | case MENU_LAYOUT_NODE_FILENAME: |
2212 | case MENU_LAYOUT_NODE_CATEGORY: |
2213 | case MENU_LAYOUT_NODE_MERGE_FILE: |
2214 | case MENU_LAYOUT_NODE_MERGE_DIR: |
2215 | case MENU_LAYOUT_NODE_LEGACY_DIR: |
2216 | case MENU_LAYOUT_NODE_OLD: |
2217 | case MENU_LAYOUT_NODE_NEW: |
2218 | case MENU_LAYOUT_NODE_MENUNAME: |
2219 | g_assert (menu_layout_node_get_content (parser->stack_top) == NULL)do { if (menu_layout_node_get_content (parser->stack_top) == ((void*)0)) ; else g_assertion_message_expr (((gchar*) 0), "menu-layout.c" , 2219, ((const char*) (__func__)), "menu_layout_node_get_content (parser->stack_top) == NULL" ); } while (0); |
2220 | |
2221 | menu_layout_node_set_content (parser->stack_top, text); |
2222 | break; |
2223 | |
2224 | case MENU_LAYOUT_NODE_ROOT: |
2225 | case MENU_LAYOUT_NODE_PASSTHROUGH: |
2226 | case MENU_LAYOUT_NODE_MENU: |
2227 | case MENU_LAYOUT_NODE_DEFAULT_APP_DIRS: |
2228 | case MENU_LAYOUT_NODE_DEFAULT_DIRECTORY_DIRS: |
2229 | case MENU_LAYOUT_NODE_DEFAULT_MERGE_DIRS: |
2230 | case MENU_LAYOUT_NODE_ONLY_UNALLOCATED: |
2231 | case MENU_LAYOUT_NODE_NOT_ONLY_UNALLOCATED: |
2232 | case MENU_LAYOUT_NODE_INCLUDE: |
2233 | case MENU_LAYOUT_NODE_EXCLUDE: |
2234 | case MENU_LAYOUT_NODE_ALL: |
2235 | case MENU_LAYOUT_NODE_AND: |
2236 | case MENU_LAYOUT_NODE_OR: |
2237 | case MENU_LAYOUT_NODE_NOT: |
2238 | case MENU_LAYOUT_NODE_KDE_LEGACY_DIRS: |
2239 | case MENU_LAYOUT_NODE_MOVE: |
2240 | case MENU_LAYOUT_NODE_DELETED: |
2241 | case MENU_LAYOUT_NODE_NOT_DELETED: |
2242 | case MENU_LAYOUT_NODE_LAYOUT: |
2243 | case MENU_LAYOUT_NODE_DEFAULT_LAYOUT: |
2244 | case MENU_LAYOUT_NODE_SEPARATOR: |
2245 | case MENU_LAYOUT_NODE_MERGE: |
2246 | if (!all_whitespace (text, text_len)) |
2247 | { |
2248 | set_error (error, context, |
2249 | G_MARKUP_ERRORg_markup_error_quark (), G_MARKUP_ERROR_PARSE, |
2250 | "No text is allowed inside element <%s>", |
2251 | g_markup_parse_context_get_element (context)); |
2252 | } |
2253 | break; |
2254 | } |
2255 | |
2256 | add_context_to_error (error, context); |
2257 | } |
2258 | |
2259 | static void |
2260 | passthrough_handler (GMarkupParseContext *context, |
2261 | const char *passthrough_text, |
2262 | gsize text_len G_GNUC_UNUSED__attribute__ ((__unused__)), |
2263 | gpointer user_data, |
2264 | GError **error) |
2265 | { |
2266 | MenuParser *parser = user_data; |
2267 | MenuLayoutNode *node; |
2268 | |
2269 | /* don't push passthrough on the stack, it's not an element */ |
2270 | |
2271 | node = menu_layout_node_new (MENU_LAYOUT_NODE_PASSTHROUGH); |
2272 | menu_layout_node_set_content (node, passthrough_text); |
2273 | |
2274 | menu_layout_node_append_child (parser->stack_top, node); |
2275 | menu_layout_node_unref (node); |
2276 | |
2277 | add_context_to_error (error, context); |
2278 | } |
2279 | |
2280 | static void |
2281 | menu_parser_init (MenuParser *parser) |
2282 | { |
2283 | parser->root = menu_layout_node_new (MENU_LAYOUT_NODE_ROOT); |
2284 | parser->stack_top = parser->root; |
2285 | } |
2286 | |
2287 | static void |
2288 | menu_parser_free (MenuParser *parser) |
2289 | { |
2290 | if (parser->root) |
2291 | menu_layout_node_unref (parser->root); |
2292 | } |
2293 | |
2294 | MenuLayoutNode * |
2295 | menu_layout_load (const char *filename, |
2296 | const char *non_prefixed_basename, |
2297 | GError **err) |
2298 | { |
2299 | GMainContext *main_context; |
2300 | GMarkupParseContext *context; |
2301 | MenuLayoutNodeRoot *root; |
2302 | MenuLayoutNode *retval; |
2303 | MenuParser parser; |
2304 | GError *error; |
2305 | GString *str; |
2306 | char *text; |
2307 | char *s; |
2308 | gsize length; |
2309 | |
2310 | text = NULL((void*)0); |
2311 | length = 0; |
2312 | retval = NULL((void*)0); |
2313 | context = NULL((void*)0); |
2314 | |
2315 | main_context = g_main_context_get_thread_default (); |
2316 | |
2317 | menu_verbose ("Loading \"%s\" from disk\n", filename); |
2318 | |
2319 | if (!g_file_get_contents (filename, |
2320 | &text, |
2321 | &length, |
2322 | err)) |
2323 | { |
2324 | menu_verbose ("Failed to load \"%s\"\n", |
2325 | filename); |
2326 | return NULL((void*)0); |
2327 | } |
2328 | |
2329 | g_assert (text != NULL)do { if (text != ((void*)0)) ; else g_assertion_message_expr ( ((gchar*) 0), "menu-layout.c", 2329, ((const char*) (__func__ )), "text != NULL"); } while (0); |
2330 | |
2331 | menu_parser_init (&parser); |
2332 | |
2333 | root = (MenuLayoutNodeRoot *) parser.root; |
2334 | |
2335 | root->basedir = g_path_get_dirname (filename); |
2336 | menu_verbose ("Set basedir \"%s\"\n", root->basedir); |
2337 | |
2338 | if (non_prefixed_basename) |
2339 | s = g_strdup (non_prefixed_basename)g_strdup_inline (non_prefixed_basename); |
2340 | else |
2341 | s = g_path_get_basename (filename); |
2342 | str = g_string_new (s); |
2343 | if (g_str_has_suffix (str->str, ".menu")(__builtin_constant_p (".menu")? __extension__ ({ const char * const __str = (str->str); 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 ) (str->str, ".menu") )) |
2344 | g_string_truncate (str, str->len - strlen (".menu"))g_string_truncate_inline (str, str->len - strlen (".menu") ); |
2345 | |
2346 | root->name = str->str; |
2347 | menu_verbose ("Set menu name \"%s\"\n", root->name); |
2348 | |
2349 | g_string_free (str, FALSE)(__builtin_constant_p ((0)) ? (((0)) ? (g_string_free) ((str) , ((0))) : g_string_free_and_steal (str)) : (g_string_free) ( (str), ((0)))); |
2350 | g_free (s); |
2351 | |
2352 | context = g_markup_parse_context_new (&menu_funcs, 0, &parser, NULL((void*)0)); |
2353 | |
2354 | error = NULL((void*)0); |
2355 | if (!g_markup_parse_context_parse (context, |
2356 | text, |
2357 | length, |
2358 | &error)) |
2359 | goto out; |
2360 | |
2361 | error = NULL((void*)0); |
2362 | g_markup_parse_context_end_parse (context, &error); |
2363 | |
2364 | root->main_context = main_context ? g_main_context_ref (main_context) : NULL((void*)0); |
2365 | |
2366 | out: |
2367 | if (context) |
2368 | g_markup_parse_context_free (context); |
2369 | g_free (text); |
2370 | |
2371 | if (error) |
2372 | { |
2373 | menu_verbose ("Error \"%s\" loading \"%s\"\n", |
2374 | error->message, filename); |
2375 | g_propagate_error (err, error); |
2376 | } |
2377 | else if (has_child_of_type (parser.root, MENU_LAYOUT_NODE_MENU)) |
2378 | { |
2379 | menu_verbose ("File loaded OK\n"); |
2380 | retval = parser.root; |
2381 | parser.root = NULL((void*)0); |
2382 | } |
2383 | else |
2384 | { |
2385 | menu_verbose ("Did not have a root element in file\n"); |
2386 | g_set_error (err, G_MARKUP_ERRORg_markup_error_quark (), G_MARKUP_ERROR_PARSE, |
2387 | "Menu file %s did not contain a root <Menu> element", |
2388 | filename); |
2389 | } |
2390 | |
2391 | menu_parser_free (&parser); |
2392 | |
2393 | return retval; |
2394 | } |