| 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 | } |