File: | entry-directories.c |
Warning: | line 404, column 22 Use of memory after it is freed |
Press '?' to see keyboard shortcuts
Keyboard shortcuts:
1 | /* | |||
2 | * Copyright (C) 2002 - 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 "entry-directories.h" | |||
23 | ||||
24 | #include <string.h> | |||
25 | #include <errno(*__errno_location ()).h> | |||
26 | #include <sys/types.h> | |||
27 | #include <dirent.h> | |||
28 | #include <stdlib.h> | |||
29 | ||||
30 | #include "menu-util.h" | |||
31 | #include "menu-monitor.h" | |||
32 | ||||
33 | typedef struct CachedDir CachedDir; | |||
34 | typedef struct CachedDirMonitor CachedDirMonitor; | |||
35 | ||||
36 | struct EntryDirectory { | |||
37 | CachedDir* dir; | |||
38 | char* legacy_prefix; | |||
39 | ||||
40 | guint entry_type: 2; | |||
41 | guint is_legacy: 1; | |||
42 | guint refcount: 24; | |||
43 | }; | |||
44 | ||||
45 | struct EntryDirectoryList { | |||
46 | int refcount; | |||
47 | int length; | |||
48 | GList* dirs; | |||
49 | }; | |||
50 | ||||
51 | struct CachedDir { | |||
52 | CachedDir* parent; | |||
53 | char* name; | |||
54 | ||||
55 | GSList* entries; | |||
56 | GSList* subdirs; | |||
57 | ||||
58 | MenuMonitor* dir_monitor; | |||
59 | GSList* monitors; | |||
60 | ||||
61 | guint have_read_entries: 1; | |||
62 | guint deleted: 1; | |||
63 | ||||
64 | guint references; | |||
65 | ||||
66 | GFunc notify; | |||
67 | gpointer notify_data; | |||
68 | }; | |||
69 | ||||
70 | struct CachedDirMonitor { | |||
71 | EntryDirectory* ed; | |||
72 | EntryDirectoryChangedFunc callback; | |||
73 | gpointer user_data; | |||
74 | }; | |||
75 | ||||
76 | static void cached_dir_add_reference (CachedDir *dir); | |||
77 | static void cached_dir_remove_reference (CachedDir *dir); | |||
78 | static void cached_dir_free (CachedDir *dir); | |||
79 | static gboolean cached_dir_load_entries_recursive (CachedDir *dir, | |||
80 | const char *dirname); | |||
81 | static void cached_dir_unref (CachedDir *dir); | |||
82 | static void cached_dir_unref_noparent (CachedDir *dir); | |||
83 | static CachedDir * cached_dir_add_subdir (CachedDir *dir, | |||
84 | const char *basename, | |||
85 | const char *path); | |||
86 | static gboolean cached_dir_remove_subdir (CachedDir *dir, | |||
87 | const char *basename); | |||
88 | ||||
89 | static void handle_cached_dir_changed (MenuMonitor *monitor, | |||
90 | MenuMonitorEvent event, | |||
91 | const char *path, | |||
92 | CachedDir *dir); | |||
93 | ||||
94 | /* | |||
95 | * Entry directory cache | |||
96 | */ | |||
97 | ||||
98 | static CachedDir* dir_cache = NULL((void*)0); | |||
99 | ||||
100 | static void | |||
101 | clear_cache (CachedDir *dir G_GNUC_UNUSED__attribute__ ((__unused__)), | |||
102 | gpointer *cache) | |||
103 | { | |||
104 | *cache = NULL((void*)0); | |||
105 | } | |||
106 | ||||
107 | static CachedDir * | |||
108 | cached_dir_new (const char *name) | |||
109 | { | |||
110 | CachedDir* dir; | |||
111 | ||||
112 | dir = g_new0 (CachedDir, 1)((CachedDir *) g_malloc0_n ((1), sizeof (CachedDir))); | |||
113 | dir->name = g_strdup (name)g_strdup_inline (name); | |||
114 | ||||
115 | return dir; | |||
116 | } | |||
117 | ||||
118 | static CachedDir * | |||
119 | cached_dir_new_full (const char *name, | |||
120 | GFunc notify, | |||
121 | gpointer notify_data) | |||
122 | { | |||
123 | CachedDir *dir; | |||
124 | ||||
125 | dir = cached_dir_new (name); | |||
126 | ||||
127 | dir->notify = notify; | |||
128 | dir->notify_data = notify_data; | |||
129 | ||||
130 | return dir; | |||
131 | } | |||
132 | ||||
133 | static void | |||
134 | cached_dir_free (CachedDir *dir) | |||
135 | { | |||
136 | if (dir->dir_monitor) | |||
137 | { | |||
138 | menu_monitor_remove_notify (dir->dir_monitor, | |||
139 | (MenuMonitorNotifyFunc) handle_cached_dir_changed, | |||
140 | dir); | |||
141 | menu_monitor_unref (dir->dir_monitor); | |||
142 | dir->dir_monitor = NULL((void*)0); | |||
143 | } | |||
144 | ||||
145 | g_slist_foreach (dir->monitors, (GFunc) g_free, NULL((void*)0)); | |||
146 | g_slist_free (dir->monitors); | |||
147 | dir->monitors = NULL((void*)0); | |||
148 | ||||
149 | g_slist_foreach (dir->entries, | |||
150 | (GFunc) desktop_entry_unref, | |||
151 | NULL((void*)0)); | |||
152 | g_slist_free (dir->entries); | |||
153 | dir->entries = NULL((void*)0); | |||
154 | ||||
155 | g_slist_foreach (dir->subdirs, | |||
156 | (GFunc) cached_dir_unref_noparent, | |||
157 | NULL((void*)0)); | |||
158 | g_slist_free (dir->subdirs); | |||
159 | dir->subdirs = NULL((void*)0); | |||
160 | ||||
161 | g_free (dir->name); | |||
162 | g_free (dir); | |||
163 | } | |||
164 | ||||
165 | static CachedDir * | |||
166 | cached_dir_ref (CachedDir *dir) | |||
167 | { | |||
168 | dir->references++; | |||
169 | return dir; | |||
170 | } | |||
171 | ||||
172 | static void | |||
173 | cached_dir_unref (CachedDir *dir) | |||
174 | { | |||
175 | if (--dir->references == 0) | |||
176 | { | |||
177 | CachedDir *parent; | |||
178 | ||||
179 | parent = dir->parent; | |||
180 | ||||
181 | if (parent != NULL((void*)0)) | |||
182 | cached_dir_remove_subdir (parent, dir->name); | |||
183 | ||||
184 | if (dir->notify) | |||
185 | dir->notify (dir, dir->notify_data); | |||
186 | ||||
187 | cached_dir_free (dir); | |||
188 | } | |||
189 | } | |||
190 | ||||
191 | static void | |||
192 | cached_dir_unref_noparent (CachedDir *dir) | |||
193 | { | |||
194 | if (--dir->references == 0) | |||
195 | { | |||
196 | if (dir->notify) | |||
197 | dir->notify (dir, dir->notify_data); | |||
198 | ||||
199 | cached_dir_free (dir); | |||
200 | } | |||
201 | } | |||
202 | ||||
203 | static inline CachedDir* find_subdir(CachedDir* dir, const char* subdir) | |||
204 | { | |||
205 | GSList *tmp; | |||
206 | ||||
207 | tmp = dir->subdirs; | |||
208 | while (tmp != NULL((void*)0)) | |||
209 | { | |||
210 | CachedDir *sub = tmp->data; | |||
211 | ||||
212 | if (strcmp (sub->name, subdir) == 0) | |||
213 | return sub; | |||
214 | ||||
215 | tmp = tmp->next; | |||
216 | } | |||
217 | ||||
218 | return NULL((void*)0); | |||
219 | } | |||
220 | ||||
221 | static DesktopEntry* find_entry(CachedDir* dir, const char* basename) | |||
222 | { | |||
223 | GSList *tmp; | |||
224 | ||||
225 | tmp = dir->entries; | |||
226 | while (tmp != NULL((void*)0)) | |||
227 | { | |||
228 | if (strcmp (desktop_entry_get_basename (tmp->data), basename) == 0) | |||
229 | return tmp->data; | |||
230 | ||||
231 | tmp = tmp->next; | |||
232 | } | |||
233 | ||||
234 | return NULL((void*)0); | |||
235 | } | |||
236 | ||||
237 | static DesktopEntry* cached_dir_find_relative_path(CachedDir* dir, const char* relative_path) | |||
238 | { | |||
239 | DesktopEntry *retval = NULL((void*)0); | |||
240 | char **split; | |||
241 | int i; | |||
242 | ||||
243 | split = g_strsplit (relative_path, "/", -1); | |||
244 | ||||
245 | i = 0; | |||
246 | while (split[i] != NULL((void*)0)) | |||
247 | { | |||
248 | if (split[i + 1] != NULL((void*)0)) | |||
249 | { | |||
250 | if ((dir = find_subdir (dir, split[i])) == NULL((void*)0)) | |||
251 | break; | |||
252 | } | |||
253 | else | |||
254 | { | |||
255 | retval = find_entry (dir, split[i]); | |||
256 | break; | |||
257 | } | |||
258 | ||||
259 | ++i; | |||
260 | } | |||
261 | ||||
262 | g_strfreev (split); | |||
263 | ||||
264 | return retval; | |||
265 | } | |||
266 | ||||
267 | static CachedDir* cached_dir_lookup(const char* canonical) | |||
268 | { | |||
269 | CachedDir *dir; | |||
270 | char **split; | |||
271 | int i; | |||
272 | ||||
273 | if (dir_cache == NULL((void*)0)) | |||
274 | dir_cache = cached_dir_new_full ("/", | |||
275 | (GFunc) clear_cache, | |||
276 | &dir_cache); | |||
277 | dir = dir_cache; | |||
278 | ||||
279 | g_assert (canonical != NULL && canonical[0] == G_DIR_SEPARATOR)do { if (canonical != ((void*)0) && canonical[0] == '/' ) ; else g_assertion_message_expr (((gchar*) 0), "entry-directories.c" , 279, ((const char*) (__func__)), "canonical != NULL && canonical[0] == G_DIR_SEPARATOR" ); } while (0); | |||
280 | ||||
281 | menu_verbose ("Looking up cached dir \"%s\"\n", canonical); | |||
282 | ||||
283 | split = g_strsplit (canonical + 1, "/", -1); | |||
284 | ||||
285 | i = 0; | |||
286 | while (split[i] != NULL((void*)0)) | |||
287 | { | |||
288 | CachedDir *subdir; | |||
289 | ||||
290 | subdir = cached_dir_add_subdir (dir, split[i], NULL((void*)0)); | |||
291 | ||||
292 | dir = subdir; | |||
293 | ||||
294 | ++i; | |||
295 | } | |||
296 | ||||
297 | g_strfreev (split); | |||
298 | ||||
299 | g_assert (dir != NULL)do { if (dir != ((void*)0)) ; else g_assertion_message_expr ( ((gchar*) 0), "entry-directories.c", 299, ((const char*) (__func__ )), "dir != NULL"); } while (0); | |||
300 | ||||
301 | return dir; | |||
302 | } | |||
303 | ||||
304 | static gboolean cached_dir_add_entry (CachedDir *dir, | |||
305 | const char *basename G_GNUC_UNUSED__attribute__ ((__unused__)), | |||
306 | const char *path) | |||
307 | { | |||
308 | DesktopEntry *entry; | |||
309 | ||||
310 | entry = desktop_entry_new (path); | |||
311 | if (entry == NULL((void*)0)) | |||
312 | return FALSE(0); | |||
313 | ||||
314 | dir->entries = g_slist_prepend (dir->entries, entry); | |||
315 | ||||
316 | return TRUE(!(0)); | |||
317 | } | |||
318 | ||||
319 | static gboolean cached_dir_update_entry(CachedDir* dir, const char* basename, const char* path) | |||
320 | { | |||
321 | GSList *tmp; | |||
322 | ||||
323 | tmp = dir->entries; | |||
324 | while (tmp != NULL((void*)0)) | |||
325 | { | |||
326 | if (strcmp (desktop_entry_get_basename (tmp->data), basename) == 0) | |||
327 | { | |||
328 | if (!desktop_entry_reload (tmp->data)) | |||
329 | { | |||
330 | dir->entries = g_slist_delete_link (dir->entries, tmp); | |||
331 | } | |||
332 | ||||
333 | return TRUE(!(0)); | |||
334 | } | |||
335 | ||||
336 | tmp = tmp->next; | |||
337 | } | |||
338 | ||||
339 | return cached_dir_add_entry (dir, basename, path); | |||
340 | } | |||
341 | ||||
342 | static gboolean cached_dir_remove_entry(CachedDir* dir, const char* basename) | |||
343 | { | |||
344 | GSList *tmp; | |||
345 | ||||
346 | tmp = dir->entries; | |||
347 | while (tmp != NULL((void*)0)) | |||
348 | { | |||
349 | if (strcmp (desktop_entry_get_basename (tmp->data), basename) == 0) | |||
350 | { | |||
351 | desktop_entry_unref (tmp->data); | |||
352 | dir->entries = g_slist_delete_link (dir->entries, tmp); | |||
353 | return TRUE(!(0)); | |||
354 | } | |||
355 | ||||
356 | tmp = tmp->next; | |||
357 | } | |||
358 | ||||
359 | return FALSE(0); | |||
360 | } | |||
361 | ||||
362 | static CachedDir * | |||
363 | cached_dir_add_subdir (CachedDir *dir, | |||
364 | const char *basename, | |||
365 | const char *path) | |||
366 | { | |||
367 | CachedDir *subdir; | |||
368 | ||||
369 | subdir = find_subdir (dir, basename); | |||
370 | ||||
371 | if (subdir != NULL((void*)0)) | |||
372 | { | |||
373 | subdir->deleted = FALSE(0); | |||
374 | return subdir; | |||
375 | } | |||
376 | ||||
377 | subdir = cached_dir_new (basename); | |||
378 | ||||
379 | if (path != NULL((void*)0) && !cached_dir_load_entries_recursive (subdir, path)) | |||
380 | { | |||
381 | cached_dir_free (subdir); | |||
382 | return NULL((void*)0); | |||
383 | } | |||
384 | ||||
385 | menu_verbose ("Caching dir \"%s\"\n", basename); | |||
386 | ||||
387 | subdir->parent = dir; | |||
388 | dir->subdirs = g_slist_prepend (dir->subdirs, cached_dir_ref (subdir)); | |||
389 | ||||
390 | return subdir; | |||
391 | } | |||
392 | ||||
393 | static gboolean cached_dir_remove_subdir(CachedDir* dir, const char* basename) | |||
394 | { | |||
395 | CachedDir *subdir; | |||
396 | ||||
397 | subdir = find_subdir (dir, basename); | |||
398 | ||||
399 | if (subdir != NULL((void*)0)) | |||
400 | { | |||
401 | subdir->deleted = TRUE(!(0)); | |||
402 | ||||
403 | cached_dir_unref (subdir); | |||
404 | dir->subdirs = g_slist_remove (dir->subdirs, subdir); | |||
| ||||
405 | ||||
406 | return TRUE(!(0)); | |||
407 | } | |||
408 | ||||
409 | return FALSE(0); | |||
410 | } | |||
411 | ||||
412 | static guint monitors_idle_handler = 0; | |||
413 | static GSList *pending_monitors_dirs = NULL((void*)0); | |||
414 | ||||
415 | static void | |||
416 | cached_dir_invoke_monitors (CachedDir *dir) | |||
417 | { | |||
418 | GSList *tmp; | |||
419 | ||||
420 | tmp = dir->monitors; | |||
421 | while (tmp != NULL((void*)0)) | |||
422 | { | |||
423 | CachedDirMonitor *monitor = tmp->data; | |||
424 | GSList *next = tmp->next; | |||
425 | ||||
426 | monitor->callback (monitor->ed, monitor->user_data); | |||
427 | ||||
428 | tmp = next; | |||
429 | } | |||
430 | ||||
431 | /* we explicitly don't invoke monitors of the parent since an | |||
432 | * event has been queued for it too */ | |||
433 | } | |||
434 | ||||
435 | static gboolean | |||
436 | emit_monitors_in_idle (void) | |||
437 | { | |||
438 | GSList *monitors_to_emit; | |||
439 | GSList *tmp; | |||
440 | ||||
441 | monitors_to_emit = pending_monitors_dirs; | |||
442 | ||||
443 | pending_monitors_dirs = NULL((void*)0); | |||
444 | monitors_idle_handler = 0; | |||
445 | ||||
446 | tmp = monitors_to_emit; | |||
447 | while (tmp != NULL((void*)0)) | |||
448 | { | |||
449 | CachedDir *dir = tmp->data; | |||
450 | ||||
451 | cached_dir_invoke_monitors (dir); | |||
452 | cached_dir_remove_reference (dir); | |||
453 | ||||
454 | tmp = tmp->next; | |||
455 | } | |||
456 | ||||
457 | g_slist_free (monitors_to_emit); | |||
458 | ||||
459 | return FALSE(0); | |||
460 | } | |||
461 | ||||
462 | static void | |||
463 | cached_dir_queue_monitor_event (CachedDir *dir) | |||
464 | { | |||
465 | GSList *tmp; | |||
466 | ||||
467 | tmp = pending_monitors_dirs; | |||
468 | while (tmp != NULL((void*)0)) | |||
469 | { | |||
470 | CachedDir *d = tmp->data; | |||
471 | GSList *next = tmp->next; | |||
472 | ||||
473 | if (dir->parent == d->parent && | |||
474 | g_strcmp0 (dir->name, d->name) == 0) | |||
475 | break; | |||
476 | ||||
477 | tmp = next; | |||
478 | } | |||
479 | ||||
480 | /* not found, so let's queue it */ | |||
481 | if (tmp == NULL((void*)0)) | |||
482 | { | |||
483 | cached_dir_add_reference (dir); | |||
484 | pending_monitors_dirs = g_slist_append (pending_monitors_dirs, dir); | |||
485 | } | |||
486 | ||||
487 | if (dir->parent) | |||
488 | { | |||
489 | cached_dir_queue_monitor_event (dir->parent); | |||
490 | } | |||
491 | ||||
492 | if (monitors_idle_handler == 0) | |||
493 | { | |||
494 | monitors_idle_handler = g_idle_add ((GSourceFunc) emit_monitors_in_idle, NULL((void*)0)); | |||
495 | } | |||
496 | } | |||
497 | ||||
498 | static void handle_cached_dir_changed (MenuMonitor *monitor G_GNUC_UNUSED__attribute__ ((__unused__)), | |||
499 | MenuMonitorEvent event, | |||
500 | const char *path, | |||
501 | CachedDir *dir) | |||
502 | { | |||
503 | gboolean handled = FALSE(0); | |||
504 | char *basename; | |||
505 | char *dirname; | |||
506 | ||||
507 | dirname = g_path_get_dirname (path); | |||
508 | basename = g_path_get_basename (path); | |||
509 | ||||
510 | dir = cached_dir_lookup (dirname); | |||
511 | cached_dir_add_reference (dir); | |||
512 | ||||
513 | if (g_str_has_suffix (basename, ".desktop")(__builtin_constant_p (".desktop")? __extension__ ({ const char * const __str = (basename); const char * const __suffix = (".desktop" ); 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) (basename, ".desktop" ) ) || | |||
| ||||
514 | g_str_has_suffix (basename, ".directory")(__builtin_constant_p (".directory")? __extension__ ({ const char * const __str = (basename); const char * const __suffix = (".directory" ); 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) (basename, ".directory" ) )) | |||
515 | { | |||
516 | switch (event) | |||
517 | { | |||
518 | case MENU_MONITOR_EVENT_CREATED: | |||
519 | case MENU_MONITOR_EVENT_CHANGED: | |||
520 | handled = cached_dir_update_entry (dir, basename, path); | |||
521 | break; | |||
522 | ||||
523 | case MENU_MONITOR_EVENT_DELETED: | |||
524 | handled = cached_dir_remove_entry (dir, basename); | |||
525 | break; | |||
526 | ||||
527 | default: | |||
528 | g_assert_not_reached ()do { g_assertion_message_expr (((gchar*) 0), "entry-directories.c" , 528, ((const char*) (__func__)), ((void*)0)); } while (0); | |||
529 | break; | |||
530 | } | |||
531 | } | |||
532 | else if (g_file_test (path, G_FILE_TEST_IS_DIR)) /* Try recursing */ | |||
533 | { | |||
534 | switch (event) | |||
535 | { | |||
536 | case MENU_MONITOR_EVENT_CREATED: | |||
537 | handled = cached_dir_add_subdir (dir, basename, path) != NULL((void*)0); | |||
538 | break; | |||
539 | ||||
540 | case MENU_MONITOR_EVENT_CHANGED: | |||
541 | break; | |||
542 | ||||
543 | case MENU_MONITOR_EVENT_DELETED: | |||
544 | handled = cached_dir_remove_subdir (dir, basename); | |||
545 | break; | |||
546 | ||||
547 | default: | |||
548 | g_assert_not_reached ()do { g_assertion_message_expr (((gchar*) 0), "entry-directories.c" , 548, ((const char*) (__func__)), ((void*)0)); } while (0); | |||
549 | break; | |||
550 | } | |||
551 | } | |||
552 | ||||
553 | g_free (basename); | |||
554 | g_free (dirname); | |||
555 | ||||
556 | if (handled) | |||
557 | { | |||
558 | menu_verbose ("'%s' notified of '%s' %s - invalidating cache\n", | |||
559 | dir->name, | |||
560 | path, | |||
561 | event == MENU_MONITOR_EVENT_CREATED ? ("created") : | |||
562 | event == MENU_MONITOR_EVENT_DELETED ? ("deleted") : ("changed")); | |||
563 | ||||
564 | /* CHANGED events don't change the set of desktop entries */ | |||
565 | if (event == MENU_MONITOR_EVENT_CREATED || event == MENU_MONITOR_EVENT_DELETED) | |||
566 | { | |||
567 | _entry_directory_list_empty_desktop_cache (); | |||
568 | } | |||
569 | ||||
570 | cached_dir_queue_monitor_event (dir); | |||
571 | } | |||
572 | ||||
573 | cached_dir_remove_reference (dir); | |||
574 | } | |||
575 | ||||
576 | static void cached_dir_ensure_monitor(CachedDir* dir, const char* dirname) | |||
577 | { | |||
578 | if (dir->dir_monitor == NULL((void*)0)) | |||
579 | { | |||
580 | dir->dir_monitor = menu_get_directory_monitor (dirname); | |||
581 | menu_monitor_add_notify (dir->dir_monitor, | |||
582 | (MenuMonitorNotifyFunc) handle_cached_dir_changed, | |||
583 | dir); | |||
584 | } | |||
585 | } | |||
586 | ||||
587 | static gboolean cached_dir_load_entries_recursive(CachedDir* dir, const char* dirname) | |||
588 | { | |||
589 | DIR *dp; | |||
590 | struct dirent *dent; | |||
591 | GString *fullpath; | |||
592 | gsize fullpath_len; | |||
593 | ||||
594 | g_assert (dir != NULL)do { if (dir != ((void*)0)) ; else g_assertion_message_expr ( ((gchar*) 0), "entry-directories.c", 594, ((const char*) (__func__ )), "dir != NULL"); } while (0); | |||
595 | ||||
596 | if (dir->have_read_entries) | |||
597 | return TRUE(!(0)); | |||
598 | ||||
599 | menu_verbose ("Attempting to read entries from %s (full path %s)\n", | |||
600 | dir->name, dirname); | |||
601 | ||||
602 | dp = opendir (dirname); | |||
603 | if (dp == NULL((void*)0)) | |||
604 | { | |||
605 | menu_verbose ("Unable to list directory \"%s\"\n", | |||
606 | dirname); | |||
607 | return FALSE(0); | |||
608 | } | |||
609 | ||||
610 | cached_dir_ensure_monitor (dir, dirname); | |||
611 | ||||
612 | fullpath = g_string_new (dirname); | |||
613 | if (fullpath->str[fullpath->len - 1] != G_DIR_SEPARATOR'/') | |||
614 | g_string_append_c (fullpath, G_DIR_SEPARATOR)g_string_append_c_inline (fullpath, '/'); | |||
615 | ||||
616 | fullpath_len = fullpath->len; | |||
617 | ||||
618 | while ((dent = readdir (dp)) != NULL((void*)0)) | |||
619 | { | |||
620 | /* ignore . and .. */ | |||
621 | if (dent->d_name[0] == '.' && | |||
622 | (dent->d_name[1] == '\0' || | |||
623 | (dent->d_name[1] == '.' && | |||
624 | dent->d_name[2] == '\0'))) | |||
625 | continue; | |||
626 | ||||
627 | g_string_append (fullpath, dent->d_name)(__builtin_constant_p (dent->d_name) ? __extension__ ({ const char * const __val = (dent->d_name); g_string_append_len_inline (fullpath, __val, (__val != ((void*)0)) ? (gssize) strlen (( (__val) + !(__val))) : (gssize) -1); }) : g_string_append_len_inline (fullpath, dent->d_name, (gssize) -1)); | |||
628 | ||||
629 | if (g_str_has_suffix (dent->d_name, ".desktop")(__builtin_constant_p (".desktop")? __extension__ ({ const char * const __str = (dent->d_name); const char * const __suffix = (".desktop"); 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 ) (dent->d_name, ".desktop") ) || | |||
630 | g_str_has_suffix (dent->d_name, ".directory")(__builtin_constant_p (".directory")? __extension__ ({ const char * const __str = (dent->d_name); const char * const __suffix = (".directory"); 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 ) (dent->d_name, ".directory") )) | |||
631 | { | |||
632 | cached_dir_add_entry (dir, dent->d_name, fullpath->str); | |||
633 | } | |||
634 | else /* Try recursing */ | |||
635 | { | |||
636 | cached_dir_add_subdir (dir, dent->d_name, fullpath->str); | |||
637 | } | |||
638 | ||||
639 | g_string_truncate (fullpath, fullpath_len)g_string_truncate_inline (fullpath, fullpath_len); | |||
640 | } | |||
641 | ||||
642 | closedir (dp); | |||
643 | ||||
644 | g_string_free (fullpath, TRUE)(__builtin_constant_p ((!(0))) ? (((!(0))) ? (g_string_free) ( (fullpath), ((!(0)))) : g_string_free_and_steal (fullpath)) : (g_string_free) ((fullpath), ((!(0))))); | |||
645 | ||||
646 | dir->have_read_entries = TRUE(!(0)); | |||
647 | ||||
648 | return TRUE(!(0)); | |||
649 | } | |||
650 | ||||
651 | static void cached_dir_add_monitor(CachedDir* dir, EntryDirectory* ed, EntryDirectoryChangedFunc callback, gpointer user_data) | |||
652 | { | |||
653 | CachedDirMonitor *monitor; | |||
654 | GSList *tmp; | |||
655 | ||||
656 | tmp = dir->monitors; | |||
657 | while (tmp != NULL((void*)0)) | |||
658 | { | |||
659 | monitor = tmp->data; | |||
660 | ||||
661 | if (monitor->ed == ed && | |||
662 | monitor->callback == callback && | |||
663 | monitor->user_data == user_data) | |||
664 | break; | |||
665 | ||||
666 | tmp = tmp->next; | |||
667 | } | |||
668 | ||||
669 | if (tmp == NULL((void*)0)) | |||
670 | { | |||
671 | monitor = g_new0 (CachedDirMonitor, 1)((CachedDirMonitor *) g_malloc0_n ((1), sizeof (CachedDirMonitor ))); | |||
672 | monitor->ed = ed; | |||
673 | monitor->callback = callback; | |||
674 | monitor->user_data = user_data; | |||
675 | ||||
676 | dir->monitors = g_slist_append (dir->monitors, monitor); | |||
677 | } | |||
678 | } | |||
679 | ||||
680 | static void cached_dir_remove_monitor(CachedDir* dir, EntryDirectory* ed, EntryDirectoryChangedFunc callback, gpointer user_data) | |||
681 | { | |||
682 | GSList *tmp; | |||
683 | ||||
684 | tmp = dir->monitors; | |||
685 | while (tmp != NULL((void*)0)) | |||
686 | { | |||
687 | CachedDirMonitor *monitor = tmp->data; | |||
688 | GSList *next = tmp->next; | |||
689 | ||||
690 | if (monitor->ed == ed && | |||
691 | monitor->callback == callback && | |||
692 | monitor->user_data == user_data) | |||
693 | { | |||
694 | dir->monitors = g_slist_delete_link (dir->monitors, tmp); | |||
695 | g_free (monitor); | |||
696 | } | |||
697 | ||||
698 | tmp = next; | |||
699 | } | |||
700 | } | |||
701 | ||||
702 | static void cached_dir_add_reference(CachedDir* dir) | |||
703 | { | |||
704 | cached_dir_ref (dir); | |||
705 | ||||
706 | if (dir->parent != NULL((void*)0)) | |||
707 | { | |||
708 | cached_dir_add_reference (dir->parent); | |||
709 | } | |||
710 | } | |||
711 | ||||
712 | static void cached_dir_remove_reference(CachedDir* dir) | |||
713 | { | |||
714 | CachedDir *parent; | |||
715 | ||||
716 | parent = dir->parent; | |||
717 | ||||
718 | cached_dir_unref (dir); | |||
719 | ||||
720 | if (parent != NULL((void*)0)) | |||
721 | { | |||
722 | cached_dir_remove_reference (parent); | |||
723 | } | |||
724 | } | |||
725 | ||||
726 | /* | |||
727 | * Entry directories | |||
728 | */ | |||
729 | ||||
730 | static EntryDirectory* entry_directory_new_full(DesktopEntryType entry_type, const char* path, gboolean is_legacy, const char* legacy_prefix) | |||
731 | { | |||
732 | EntryDirectory *ed; | |||
733 | char *canonical; | |||
734 | ||||
735 | menu_verbose ("Loading entry directory \"%s\" (legacy %s)\n", | |||
736 | path, | |||
737 | is_legacy ? "<yes>" : "<no>"); | |||
738 | ||||
739 | canonical = realpath (path, NULL((void*)0)); | |||
740 | if (canonical == NULL((void*)0)) | |||
741 | { | |||
742 | menu_verbose ("Failed to canonicalize \"%s\": %s\n", | |||
743 | path, g_strerror (errno)); | |||
744 | return NULL((void*)0); | |||
745 | } | |||
746 | ||||
747 | ed = g_new0 (EntryDirectory, 1)((EntryDirectory *) g_malloc0_n ((1), sizeof (EntryDirectory) )); | |||
748 | ||||
749 | ed->dir = cached_dir_lookup (canonical); | |||
750 | g_assert (ed->dir != NULL)do { if (ed->dir != ((void*)0)) ; else g_assertion_message_expr (((gchar*) 0), "entry-directories.c", 750, ((const char*) (__func__ )), "ed->dir != NULL"); } while (0); | |||
751 | ||||
752 | cached_dir_add_reference (ed->dir); | |||
753 | cached_dir_load_entries_recursive (ed->dir, canonical); | |||
754 | ||||
755 | ed->legacy_prefix = g_strdup (legacy_prefix)g_strdup_inline (legacy_prefix); | |||
756 | ed->entry_type = entry_type; | |||
757 | ed->is_legacy = is_legacy != FALSE(0); | |||
758 | ed->refcount = 1; | |||
759 | ||||
760 | g_free (canonical); | |||
761 | ||||
762 | return ed; | |||
763 | } | |||
764 | ||||
765 | EntryDirectory* entry_directory_new(DesktopEntryType entry_type, const char* path) | |||
766 | { | |||
767 | return entry_directory_new_full (entry_type, path, FALSE(0), NULL((void*)0)); | |||
768 | } | |||
769 | ||||
770 | EntryDirectory* entry_directory_new_legacy(DesktopEntryType entry_type, const char* path, const char* legacy_prefix) | |||
771 | { | |||
772 | return entry_directory_new_full(entry_type, path, TRUE(!(0)), legacy_prefix); | |||
773 | } | |||
774 | ||||
775 | EntryDirectory* entry_directory_ref(EntryDirectory* ed) | |||
776 | { | |||
777 | g_return_val_if_fail(ed != NULL, NULL)do { if ((ed != ((void*)0))) { } else { g_return_if_fail_warning (((gchar*) 0), ((const char*) (__func__)), "ed != NULL"); return (((void*)0)); } } while (0); | |||
778 | g_return_val_if_fail(ed->refcount > 0, NULL)do { if ((ed->refcount > 0)) { } else { g_return_if_fail_warning (((gchar*) 0), ((const char*) (__func__)), "ed->refcount > 0" ); return (((void*)0)); } } while (0); | |||
779 | ||||
780 | ed->refcount++; | |||
781 | ||||
782 | return ed; | |||
783 | } | |||
784 | ||||
785 | void entry_directory_unref(EntryDirectory* ed) | |||
786 | { | |||
787 | g_return_if_fail (ed != NULL)do { if ((ed != ((void*)0))) { } else { g_return_if_fail_warning (((gchar*) 0), ((const char*) (__func__)), "ed != NULL"); return ; } } while (0); | |||
788 | g_return_if_fail (ed->refcount > 0)do { if ((ed->refcount > 0)) { } else { g_return_if_fail_warning (((gchar*) 0), ((const char*) (__func__)), "ed->refcount > 0" ); return; } } while (0); | |||
789 | ||||
790 | if (--ed->refcount == 0) | |||
791 | { | |||
792 | cached_dir_remove_reference (ed->dir); | |||
793 | ||||
794 | ed->dir = NULL((void*)0); | |||
795 | ed->entry_type = DESKTOP_ENTRY_INVALID; | |||
796 | ed->is_legacy = FALSE(0); | |||
797 | ||||
798 | g_free (ed->legacy_prefix); | |||
799 | ed->legacy_prefix = NULL((void*)0); | |||
800 | ||||
801 | g_free (ed); | |||
802 | } | |||
803 | } | |||
804 | ||||
805 | static void entry_directory_add_monitor(EntryDirectory* ed, EntryDirectoryChangedFunc callback, gpointer user_data) | |||
806 | { | |||
807 | cached_dir_add_monitor (ed->dir, ed, callback, user_data); | |||
808 | } | |||
809 | ||||
810 | static void entry_directory_remove_monitor(EntryDirectory* ed, EntryDirectoryChangedFunc callback, gpointer user_data) | |||
811 | { | |||
812 | cached_dir_remove_monitor (ed->dir, ed, callback, user_data); | |||
813 | } | |||
814 | ||||
815 | static DesktopEntry* entry_directory_get_directory(EntryDirectory* ed, const char* relative_path) | |||
816 | { | |||
817 | DesktopEntry *entry; | |||
818 | ||||
819 | if (ed->entry_type != DESKTOP_ENTRY_DIRECTORY) | |||
820 | return NULL((void*)0); | |||
821 | ||||
822 | entry = cached_dir_find_relative_path (ed->dir, relative_path); | |||
823 | if (entry == NULL((void*)0) || desktop_entry_get_type (entry) != DESKTOP_ENTRY_DIRECTORY) | |||
824 | return NULL((void*)0); | |||
825 | ||||
826 | return desktop_entry_ref (entry); | |||
827 | } | |||
828 | ||||
829 | static char* get_desktop_file_id_from_path(EntryDirectory* ed, DesktopEntryType entry_type, const char* relative_path) | |||
830 | { | |||
831 | char *retval; | |||
832 | ||||
833 | retval = NULL((void*)0); | |||
834 | ||||
835 | if (entry_type == DESKTOP_ENTRY_DESKTOP) | |||
836 | { | |||
837 | if (!ed->is_legacy) | |||
838 | { | |||
839 | retval = g_strdelimit (g_strdup (relative_path)g_strdup_inline (relative_path), "/", '-'); | |||
840 | } | |||
841 | else | |||
842 | { | |||
843 | char *basename; | |||
844 | ||||
845 | basename = g_path_get_basename (relative_path); | |||
846 | ||||
847 | if (ed->legacy_prefix) | |||
848 | { | |||
849 | retval = g_strjoin ("-", ed->legacy_prefix, basename, NULL((void*)0)); | |||
850 | g_free (basename); | |||
851 | } | |||
852 | else | |||
853 | { | |||
854 | retval = basename; | |||
855 | } | |||
856 | } | |||
857 | } | |||
858 | else | |||
859 | { | |||
860 | retval = g_strdup (relative_path)g_strdup_inline (relative_path); | |||
861 | } | |||
862 | ||||
863 | return retval; | |||
864 | } | |||
865 | ||||
866 | typedef gboolean (*EntryDirectoryForeachFunc) (EntryDirectory* ed, DesktopEntry* entry, const char* file_id, DesktopEntrySet* set, gpointer user_data); | |||
867 | ||||
868 | static gboolean entry_directory_foreach_recursive(EntryDirectory* ed, CachedDir* cd, GString* relative_path, EntryDirectoryForeachFunc func, DesktopEntrySet* set, gpointer user_data) | |||
869 | { | |||
870 | GSList *tmp; | |||
871 | int relative_path_len; | |||
872 | ||||
873 | if (cd->deleted) | |||
874 | return TRUE(!(0)); | |||
875 | ||||
876 | relative_path_len = relative_path->len; | |||
877 | ||||
878 | tmp = cd->entries; | |||
879 | while (tmp != NULL((void*)0)) | |||
880 | { | |||
881 | DesktopEntry *entry = tmp->data; | |||
882 | ||||
883 | if (desktop_entry_get_type (entry) == ed->entry_type) | |||
884 | { | |||
885 | gboolean ret; | |||
886 | char *file_id; | |||
887 | ||||
888 | g_string_append (relative_path,(__builtin_constant_p (desktop_entry_get_basename (entry)) ? __extension__ ({ const char * const __val = (desktop_entry_get_basename (entry )); g_string_append_len_inline (relative_path, __val, (__val != ((void*)0)) ? (gssize) strlen (((__val) + !(__val))) : (gssize ) -1); }) : g_string_append_len_inline (relative_path, desktop_entry_get_basename (entry), (gssize) -1)) | |||
889 | desktop_entry_get_basename (entry))(__builtin_constant_p (desktop_entry_get_basename (entry)) ? __extension__ ({ const char * const __val = (desktop_entry_get_basename (entry )); g_string_append_len_inline (relative_path, __val, (__val != ((void*)0)) ? (gssize) strlen (((__val) + !(__val))) : (gssize ) -1); }) : g_string_append_len_inline (relative_path, desktop_entry_get_basename (entry), (gssize) -1)); | |||
890 | ||||
891 | file_id = get_desktop_file_id_from_path (ed, | |||
892 | ed->entry_type, | |||
893 | relative_path->str); | |||
894 | ||||
895 | ret = func (ed, entry, file_id, set, user_data); | |||
896 | ||||
897 | g_free (file_id); | |||
898 | ||||
899 | g_string_truncate (relative_path, relative_path_len)g_string_truncate_inline (relative_path, relative_path_len); | |||
900 | ||||
901 | if (!ret) | |||
902 | return FALSE(0); | |||
903 | } | |||
904 | ||||
905 | tmp = tmp->next; | |||
906 | } | |||
907 | ||||
908 | tmp = cd->subdirs; | |||
909 | while (tmp != NULL((void*)0)) | |||
910 | { | |||
911 | CachedDir *subdir = tmp->data; | |||
912 | ||||
913 | g_string_append (relative_path, subdir->name)(__builtin_constant_p (subdir->name) ? __extension__ ({ const char * const __val = (subdir->name); g_string_append_len_inline (relative_path, __val, (__val != ((void*)0)) ? (gssize) strlen (((__val) + !(__val))) : (gssize) -1); }) : g_string_append_len_inline (relative_path, subdir->name, (gssize) -1)); | |||
914 | g_string_append_c (relative_path, G_DIR_SEPARATOR)g_string_append_c_inline (relative_path, '/'); | |||
915 | ||||
916 | if (!entry_directory_foreach_recursive (ed, | |||
917 | subdir, | |||
918 | relative_path, | |||
919 | func, | |||
920 | set, | |||
921 | user_data)) | |||
922 | return FALSE(0); | |||
923 | ||||
924 | g_string_truncate (relative_path, relative_path_len)g_string_truncate_inline (relative_path, relative_path_len); | |||
925 | ||||
926 | tmp = tmp->next; | |||
927 | } | |||
928 | ||||
929 | return TRUE(!(0)); | |||
930 | } | |||
931 | ||||
932 | static void entry_directory_foreach(EntryDirectory* ed, EntryDirectoryForeachFunc func, DesktopEntrySet* set, gpointer user_data) | |||
933 | { | |||
934 | GString *path; | |||
935 | ||||
936 | path = g_string_new (NULL((void*)0)); | |||
937 | ||||
938 | entry_directory_foreach_recursive (ed, | |||
939 | ed->dir, | |||
940 | path, | |||
941 | func, | |||
942 | set, | |||
943 | user_data); | |||
944 | ||||
945 | g_string_free (path, TRUE)(__builtin_constant_p ((!(0))) ? (((!(0))) ? (g_string_free) ( (path), ((!(0)))) : g_string_free_and_steal (path)) : (g_string_free ) ((path), ((!(0))))); | |||
946 | } | |||
947 | ||||
948 | void entry_directory_get_flat_contents(EntryDirectory* ed, DesktopEntrySet* desktop_entries, DesktopEntrySet* directory_entries, GSList** subdirs) | |||
949 | { | |||
950 | GSList *tmp; | |||
951 | ||||
952 | if (subdirs) | |||
953 | *subdirs = NULL((void*)0); | |||
954 | ||||
955 | tmp = ed->dir->entries; | |||
956 | while (tmp != NULL((void*)0)) | |||
957 | { | |||
958 | DesktopEntry *entry = tmp->data; | |||
959 | const char *basename; | |||
960 | ||||
961 | basename = desktop_entry_get_basename (entry); | |||
962 | ||||
963 | if (desktop_entries && | |||
964 | desktop_entry_get_type (entry) == DESKTOP_ENTRY_DESKTOP) | |||
965 | { | |||
966 | char *file_id; | |||
967 | ||||
968 | file_id = get_desktop_file_id_from_path (ed, | |||
969 | DESKTOP_ENTRY_DESKTOP, | |||
970 | basename); | |||
971 | ||||
972 | desktop_entry_set_add_entry (desktop_entries, | |||
973 | entry, | |||
974 | file_id); | |||
975 | ||||
976 | g_free (file_id); | |||
977 | } | |||
978 | ||||
979 | if (directory_entries && | |||
980 | desktop_entry_get_type (entry) == DESKTOP_ENTRY_DIRECTORY) | |||
981 | { | |||
982 | desktop_entry_set_add_entry (directory_entries, | |||
983 | entry, | |||
984 | basename); | |||
985 | } | |||
986 | ||||
987 | tmp = tmp->next; | |||
988 | } | |||
989 | ||||
990 | if (subdirs) | |||
991 | { | |||
992 | tmp = ed->dir->subdirs; | |||
993 | while (tmp != NULL((void*)0)) | |||
994 | { | |||
995 | CachedDir *cd = tmp->data; | |||
996 | ||||
997 | if (!cd->deleted) | |||
998 | { | |||
999 | *subdirs = g_slist_prepend (*subdirs, g_strdup (cd->name)g_strdup_inline (cd->name)); | |||
1000 | } | |||
1001 | ||||
1002 | tmp = tmp->next; | |||
1003 | } | |||
1004 | } | |||
1005 | ||||
1006 | if (subdirs) | |||
1007 | *subdirs = g_slist_reverse (*subdirs); | |||
1008 | } | |||
1009 | ||||
1010 | /* | |||
1011 | * Entry directory lists | |||
1012 | */ | |||
1013 | ||||
1014 | EntryDirectoryList* entry_directory_list_new(void) | |||
1015 | { | |||
1016 | EntryDirectoryList *list; | |||
1017 | ||||
1018 | list = g_new0 (EntryDirectoryList, 1)((EntryDirectoryList *) g_malloc0_n ((1), sizeof (EntryDirectoryList ))); | |||
1019 | ||||
1020 | list->refcount = 1; | |||
1021 | list->dirs = NULL((void*)0); | |||
1022 | list->length = 0; | |||
1023 | ||||
1024 | return list; | |||
1025 | } | |||
1026 | ||||
1027 | EntryDirectoryList* entry_directory_list_ref(EntryDirectoryList* list) | |||
1028 | { | |||
1029 | g_return_val_if_fail (list != NULL, NULL)do { if ((list != ((void*)0))) { } else { g_return_if_fail_warning (((gchar*) 0), ((const char*) (__func__)), "list != NULL"); return (((void*)0)); } } while (0); | |||
1030 | g_return_val_if_fail (list->refcount > 0, NULL)do { if ((list->refcount > 0)) { } else { g_return_if_fail_warning (((gchar*) 0), ((const char*) (__func__)), "list->refcount > 0" ); return (((void*)0)); } } while (0); | |||
1031 | ||||
1032 | list->refcount += 1; | |||
1033 | ||||
1034 | return list; | |||
1035 | } | |||
1036 | ||||
1037 | void entry_directory_list_unref(EntryDirectoryList* list) | |||
1038 | { | |||
1039 | g_return_if_fail (list != NULL)do { if ((list != ((void*)0))) { } else { g_return_if_fail_warning (((gchar*) 0), ((const char*) (__func__)), "list != NULL"); return ; } } while (0); | |||
1040 | g_return_if_fail (list->refcount > 0)do { if ((list->refcount > 0)) { } else { g_return_if_fail_warning (((gchar*) 0), ((const char*) (__func__)), "list->refcount > 0" ); return; } } while (0); | |||
1041 | ||||
1042 | list->refcount -= 1; | |||
1043 | if (list->refcount == 0) | |||
1044 | { | |||
1045 | g_list_foreach (list->dirs, (GFunc) entry_directory_unref, NULL((void*)0)); | |||
1046 | g_list_free (list->dirs); | |||
1047 | list->dirs = NULL((void*)0); | |||
1048 | list->length = 0; | |||
1049 | g_free (list); | |||
1050 | } | |||
1051 | } | |||
1052 | ||||
1053 | void entry_directory_list_prepend(EntryDirectoryList* list, EntryDirectory* ed) | |||
1054 | { | |||
1055 | list->length += 1; | |||
1056 | list->dirs = g_list_prepend (list->dirs, | |||
1057 | entry_directory_ref (ed)); | |||
1058 | } | |||
1059 | ||||
1060 | int entry_directory_list_get_length(EntryDirectoryList* list) | |||
1061 | { | |||
1062 | return list->length; | |||
1063 | } | |||
1064 | ||||
1065 | void entry_directory_list_append_list(EntryDirectoryList* list, EntryDirectoryList* to_append) | |||
1066 | { | |||
1067 | GList *tmp; | |||
1068 | GList *new_dirs = NULL((void*)0); | |||
1069 | ||||
1070 | if (to_append->length == 0) | |||
1071 | return; | |||
1072 | ||||
1073 | tmp = to_append->dirs; | |||
1074 | while (tmp != NULL((void*)0)) | |||
1075 | { | |||
1076 | list->length += 1; | |||
1077 | new_dirs = g_list_prepend (new_dirs, | |||
1078 | entry_directory_ref (tmp->data)); | |||
1079 | ||||
1080 | tmp = tmp->next; | |||
1081 | } | |||
1082 | ||||
1083 | new_dirs = g_list_reverse (new_dirs); | |||
1084 | list->dirs = g_list_concat (list->dirs, new_dirs); | |||
1085 | } | |||
1086 | ||||
1087 | DesktopEntry* entry_directory_list_get_directory(EntryDirectoryList *list, const char* relative_path) | |||
1088 | { | |||
1089 | DesktopEntry *retval = NULL((void*)0); | |||
1090 | GList *tmp; | |||
1091 | ||||
1092 | tmp = list->dirs; | |||
1093 | while (tmp != NULL((void*)0)) | |||
1094 | { | |||
1095 | if ((retval = entry_directory_get_directory (tmp->data, relative_path)) != NULL((void*)0)) | |||
1096 | break; | |||
1097 | ||||
1098 | tmp = tmp->next; | |||
1099 | } | |||
1100 | ||||
1101 | return retval; | |||
1102 | } | |||
1103 | ||||
1104 | gboolean _entry_directory_list_compare(const EntryDirectoryList* a, const EntryDirectoryList* b) | |||
1105 | { | |||
1106 | GList *al, *bl; | |||
1107 | ||||
1108 | if (a == NULL((void*)0) && b == NULL((void*)0)) | |||
1109 | return TRUE(!(0)); | |||
1110 | ||||
1111 | if ((a == NULL((void*)0) || b == NULL((void*)0))) | |||
1112 | return FALSE(0); | |||
1113 | ||||
1114 | if (a->length != b->length) | |||
1115 | return FALSE(0); | |||
1116 | ||||
1117 | al = a->dirs; bl = b->dirs; | |||
1118 | while (al && bl && al->data == bl->data) | |||
1119 | { | |||
1120 | al = al->next; | |||
1121 | bl = bl->next; | |||
1122 | } | |||
1123 | ||||
1124 | return (al == NULL((void*)0) && bl == NULL((void*)0)); | |||
1125 | } | |||
1126 | ||||
1127 | static gboolean get_all_func (EntryDirectory *ed, | |||
1128 | DesktopEntry *entry, | |||
1129 | const char *file_id, | |||
1130 | DesktopEntrySet *set, | |||
1131 | gpointer user_data G_GNUC_UNUSED__attribute__ ((__unused__))) | |||
1132 | { | |||
1133 | if (ed->is_legacy && !desktop_entry_has_categories (entry)) | |||
1134 | { | |||
1135 | entry = desktop_entry_copy (entry); | |||
1136 | desktop_entry_add_legacy_category (entry); | |||
1137 | } | |||
1138 | else | |||
1139 | { | |||
1140 | entry = desktop_entry_ref (entry); | |||
1141 | } | |||
1142 | ||||
1143 | desktop_entry_set_add_entry (set, entry, file_id); | |||
1144 | desktop_entry_unref (entry); | |||
1145 | ||||
1146 | return TRUE(!(0)); | |||
1147 | } | |||
1148 | ||||
1149 | static DesktopEntrySet* entry_directory_last_set = NULL((void*)0); | |||
1150 | static EntryDirectoryList* entry_directory_last_list = NULL((void*)0); | |||
1151 | ||||
1152 | void _entry_directory_list_empty_desktop_cache(void) | |||
1153 | { | |||
1154 | if (entry_directory_last_set != NULL((void*)0)) | |||
1155 | desktop_entry_set_unref (entry_directory_last_set); | |||
1156 | entry_directory_last_set = NULL((void*)0); | |||
1157 | ||||
1158 | if (entry_directory_last_list != NULL((void*)0)) | |||
1159 | entry_directory_list_unref (entry_directory_last_list); | |||
1160 | entry_directory_last_list = NULL((void*)0); | |||
1161 | } | |||
1162 | ||||
1163 | DesktopEntrySet* _entry_directory_list_get_all_desktops(EntryDirectoryList* list) | |||
1164 | { | |||
1165 | GList *tmp; | |||
1166 | DesktopEntrySet *set; | |||
1167 | ||||
1168 | /* The only tricky thing here is that desktop files later | |||
1169 | * in the search list with the same relative path | |||
1170 | * are "hidden" by desktop files earlier in the path, | |||
1171 | * so we have to do the earlier files first causing | |||
1172 | * the later files to replace the earlier files | |||
1173 | * in the DesktopEntrySet | |||
1174 | * | |||
1175 | * We go from the end of the list so we can just | |||
1176 | * g_hash_table_replace and not have to do two | |||
1177 | * hash lookups (check for existing entry, then insert new | |||
1178 | * entry) | |||
1179 | */ | |||
1180 | ||||
1181 | /* This method is -extremely- slow, so we have a simple | |||
1182 | one-entry cache here */ | |||
1183 | if (_entry_directory_list_compare (list, entry_directory_last_list)) | |||
1184 | { | |||
1185 | menu_verbose (" Hit desktop list (%p) cache\n", list); | |||
1186 | return desktop_entry_set_ref (entry_directory_last_set); | |||
1187 | } | |||
1188 | ||||
1189 | if (entry_directory_last_set != NULL((void*)0)) | |||
1190 | desktop_entry_set_unref (entry_directory_last_set); | |||
1191 | if (entry_directory_last_list != NULL((void*)0)) | |||
1192 | entry_directory_list_unref (entry_directory_last_list); | |||
1193 | ||||
1194 | set = desktop_entry_set_new (); | |||
1195 | menu_verbose (" Storing all of list %p in set %p\n", | |||
1196 | list, set); | |||
1197 | ||||
1198 | tmp = g_list_last (list->dirs); | |||
1199 | while (tmp != NULL((void*)0)) | |||
1200 | { | |||
1201 | entry_directory_foreach (tmp->data, get_all_func, set, NULL((void*)0)); | |||
1202 | ||||
1203 | tmp = tmp->prev; | |||
1204 | } | |||
1205 | ||||
1206 | entry_directory_last_list = entry_directory_list_ref (list); | |||
1207 | entry_directory_last_set = desktop_entry_set_ref (set); | |||
1208 | ||||
1209 | return set; | |||
1210 | } | |||
1211 | ||||
1212 | void entry_directory_list_add_monitors(EntryDirectoryList* list, EntryDirectoryChangedFunc callback, gpointer user_data) | |||
1213 | { | |||
1214 | GList *tmp; | |||
1215 | ||||
1216 | tmp = list->dirs; | |||
1217 | while (tmp != NULL((void*)0)) | |||
1218 | { | |||
1219 | entry_directory_add_monitor (tmp->data, callback, user_data); | |||
1220 | tmp = tmp->next; | |||
1221 | } | |||
1222 | } | |||
1223 | ||||
1224 | void entry_directory_list_remove_monitors(EntryDirectoryList* list, EntryDirectoryChangedFunc callback, gpointer user_data) | |||
1225 | { | |||
1226 | GList *tmp; | |||
1227 | ||||
1228 | tmp = list->dirs; | |||
1229 | while (tmp != NULL((void*)0)) | |||
1230 | { | |||
1231 | entry_directory_remove_monitor (tmp->data, callback, user_data); | |||
1232 | tmp = tmp->next; | |||
1233 | } | |||
1234 | } |