Imported Upstream version 3.0.1
Margarita Manterola
6 years ago
0 | 0 | AC_PREREQ(2.62) |
1 | 1 | |
2 | AC_INIT([cinnamon-menus], [3.0.0]) | |
2 | AC_INIT([cinnamon-menus], [3.0.1]) | |
3 | 3 | AC_CONFIG_SRCDIR(libmenu/gmenu-tree.h) |
4 | 4 | |
5 | 5 | AM_INIT_AUTOMAKE([1.11 foreign no-dist-gzip dist-xz]) |
262 | 262 | return TRUE; |
263 | 263 | } |
264 | 264 | |
265 | static gboolean | |
265 | static DesktopEntryResultCode | |
266 | 266 | desktop_entry_load (DesktopEntry *entry) |
267 | 267 | { |
268 | DesktopEntryResultCode rescode = DESKTOP_ENTRY_LOAD_FAIL_OTHER; | |
269 | ||
268 | 270 | if (strstr (entry->path, "/menu-xdg/")) |
269 | return FALSE; | |
271 | return rescode; | |
272 | ||
270 | 273 | if (entry->type == DESKTOP_ENTRY_DESKTOP) |
271 | 274 | { |
272 | 275 | GKeyFile *key_file = NULL; |
273 | 276 | DesktopEntryDesktop *entry_desktop = (DesktopEntryDesktop*)entry; |
274 | const char *categories_str; | |
275 | ||
276 | entry_desktop->appinfo = g_desktop_app_info_new_from_filename (entry->path); | |
277 | if (!entry_desktop->appinfo || | |
278 | !g_app_info_get_name (G_APP_INFO (entry_desktop->appinfo)) || | |
279 | !g_app_info_get_executable (G_APP_INFO (entry_desktop->appinfo))) | |
277 | ||
278 | key_file = g_key_file_new (); | |
279 | ||
280 | if (g_key_file_load_from_file (key_file, entry->path, 0, NULL)) | |
280 | 281 | { |
281 | menu_verbose ("Failed to load \"%s\"\n", entry->path); | |
282 | return FALSE; | |
282 | entry_desktop->appinfo = g_desktop_app_info_new_from_keyfile (key_file); | |
283 | ||
284 | if (!entry_desktop->appinfo || | |
285 | !g_app_info_get_name (G_APP_INFO (entry_desktop->appinfo)) || | |
286 | !g_app_info_get_executable (G_APP_INFO (entry_desktop->appinfo))) | |
287 | { | |
288 | menu_verbose ("Failed to load appinfo for \"%s\"\n", entry->path); | |
289 | rescode = DESKTOP_ENTRY_LOAD_FAIL_APPINFO; | |
290 | } | |
291 | else | |
292 | { | |
293 | const char *categories_str; | |
294 | categories_str = g_desktop_app_info_get_categories (entry_desktop->appinfo); | |
295 | ||
296 | if (categories_str) | |
297 | { | |
298 | char **categories; | |
299 | int i; | |
300 | ||
301 | categories = g_strsplit (categories_str, ";", -1); | |
302 | entry_desktop->categories = g_new0 (GQuark, g_strv_length (categories) + 1); | |
303 | ||
304 | for (i = 0; categories[i]; i++) | |
305 | entry_desktop->categories[i] = g_quark_from_string (categories[i]); | |
306 | ||
307 | g_strfreev (categories); | |
308 | } | |
309 | ||
310 | entry_desktop->showin = key_file_get_show_in (key_file); | |
311 | ||
312 | rescode = DESKTOP_ENTRY_LOAD_SUCCESS; | |
313 | } | |
283 | 314 | } |
284 | ||
285 | categories_str = g_desktop_app_info_get_categories (entry_desktop->appinfo); | |
286 | if (categories_str) | |
315 | else | |
287 | 316 | { |
288 | char **categories; | |
289 | int i; | |
290 | ||
291 | categories = g_strsplit (categories_str, ";", -1); | |
292 | entry_desktop->categories = g_new0 (GQuark, g_strv_length (categories) + 1); | |
293 | ||
294 | for (i = 0; categories[i]; i++) | |
295 | entry_desktop->categories[i] = g_quark_from_string (categories[i]); | |
296 | ||
297 | g_strfreev (categories); | |
317 | menu_verbose ("Failed to read contents of \"%s\"\n", entry->path); | |
318 | rescode = DESKTOP_ENTRY_LOAD_FAIL_OTHER; | |
298 | 319 | } |
299 | ||
300 | key_file = g_key_file_new (); | |
301 | ||
302 | if (!g_key_file_load_from_file (key_file, entry->path, 0, NULL)) | |
303 | entry_desktop->showin = TRUE; | |
304 | else | |
305 | entry_desktop->showin = key_file_get_show_in (key_file); | |
306 | ||
307 | 320 | g_key_file_free (key_file); |
308 | ||
309 | return TRUE; | |
310 | 321 | } |
311 | 322 | else if (entry->type == DESKTOP_ENTRY_DIRECTORY) |
312 | 323 | { |
313 | 324 | GKeyFile *key_file = NULL; |
314 | 325 | GError *error = NULL; |
315 | gboolean retval = FALSE; | |
326 | rescode = DESKTOP_ENTRY_LOAD_SUCCESS; | |
316 | 327 | |
317 | 328 | key_file = g_key_file_new (); |
318 | 329 | |
319 | 330 | if (!g_key_file_load_from_file (key_file, entry->path, 0, &error)) |
320 | goto out; | |
331 | { | |
332 | rescode = DESKTOP_ENTRY_LOAD_FAIL_OTHER; | |
333 | goto out; | |
334 | } | |
321 | 335 | |
322 | 336 | if (!desktop_entry_load_directory (entry, key_file, &error)) |
323 | goto out; | |
324 | ||
325 | retval = TRUE; | |
337 | { | |
338 | rescode = DESKTOP_ENTRY_LOAD_FAIL_OTHER; | |
339 | goto out; | |
340 | } | |
341 | ||
342 | rescode = DESKTOP_ENTRY_LOAD_SUCCESS; | |
326 | 343 | |
327 | 344 | out: |
328 | 345 | g_key_file_free (key_file); |
329 | 346 | |
330 | if (!retval) | |
347 | if (rescode == DESKTOP_ENTRY_LOAD_FAIL_OTHER) | |
331 | 348 | { |
332 | 349 | if (error) |
333 | 350 | { |
337 | 354 | else |
338 | 355 | menu_verbose ("Failed to load \"%s\"\n", entry->path); |
339 | 356 | } |
340 | ||
341 | return retval; | |
342 | 357 | } |
343 | 358 | else |
344 | 359 | g_assert_not_reached (); |
345 | 360 | |
346 | return FALSE; | |
361 | return rescode; | |
362 | } | |
363 | ||
364 | static gboolean | |
365 | code_failed (DesktopEntryResultCode code) | |
366 | { | |
367 | return code == DESKTOP_ENTRY_LOAD_FAIL_OTHER || | |
368 | code == DESKTOP_ENTRY_LOAD_FAIL_APPINFO; | |
347 | 369 | } |
348 | 370 | |
349 | 371 | DesktopEntry * |
350 | desktop_entry_new (const char *path) | |
372 | desktop_entry_new (const char *path, | |
373 | DesktopEntryResultCode *res_code) | |
351 | 374 | { |
352 | 375 | DesktopEntryType type; |
353 | 376 | DesktopEntry *retval; |
377 | DesktopEntryResultCode code; | |
354 | 378 | |
355 | 379 | menu_verbose ("Loading desktop entry \"%s\"\n", path); |
356 | 380 | |
368 | 392 | { |
369 | 393 | menu_verbose ("Unknown desktop entry suffix in \"%s\"\n", |
370 | 394 | path); |
395 | *res_code = DESKTOP_ENTRY_LOAD_FAIL_OTHER; | |
371 | 396 | return NULL; |
372 | 397 | } |
373 | 398 | |
376 | 401 | retval->path = g_strdup (path); |
377 | 402 | retval->basename = unix_basename_from_path (retval->path); |
378 | 403 | |
379 | if (!desktop_entry_load (retval)) | |
404 | code = desktop_entry_load (retval); | |
405 | *res_code = code; | |
406 | ||
407 | if (code_failed (code)) | |
380 | 408 | { |
381 | 409 | desktop_entry_unref (retval); |
382 | 410 | return NULL; |
418 | 446 | else |
419 | 447 | g_assert_not_reached (); |
420 | 448 | |
421 | if (!desktop_entry_load (entry)) | |
449 | if (code_failed (desktop_entry_load (entry))) | |
422 | 450 | { |
423 | 451 | desktop_entry_unref (entry); |
424 | 452 | return NULL; |
30 | 30 | DESKTOP_ENTRY_DIRECTORY |
31 | 31 | } DesktopEntryType; |
32 | 32 | |
33 | typedef enum | |
34 | { | |
35 | DESKTOP_ENTRY_LOAD_SUCCESS = 0, | |
36 | DESKTOP_ENTRY_LOAD_FAIL_OTHER, | |
37 | DESKTOP_ENTRY_LOAD_FAIL_APPINFO | |
38 | } DesktopEntryResultCode; | |
39 | ||
33 | 40 | typedef struct DesktopEntry DesktopEntry; |
34 | 41 | |
35 | DesktopEntry *desktop_entry_new (const char *path); | |
42 | DesktopEntry *desktop_entry_new (const char *path, | |
43 | DesktopEntryResultCode *res_code); | |
36 | 44 | |
37 | 45 | DesktopEntry *desktop_entry_ref (DesktopEntry *entry); |
38 | 46 | DesktopEntry *desktop_entry_copy (DesktopEntry *entry); |
56 | 56 | |
57 | 57 | GSList *entries; |
58 | 58 | GSList *subdirs; |
59 | GSList *retry_later_desktop_entries; | |
59 | 60 | |
60 | 61 | MenuMonitor *dir_monitor; |
61 | 62 | GSList *monitors; |
160 | 161 | g_slist_free (dir->subdirs); |
161 | 162 | dir->subdirs = NULL; |
162 | 163 | |
164 | g_slist_free_full (dir->retry_later_desktop_entries, g_free); | |
165 | dir->retry_later_desktop_entries = NULL; | |
166 | ||
163 | 167 | g_free (dir->name); |
164 | 168 | g_free (dir); |
165 | 169 | } |
313 | 317 | const char *path) |
314 | 318 | { |
315 | 319 | DesktopEntry *entry; |
316 | ||
317 | entry = desktop_entry_new (path); | |
320 | DesktopEntryResultCode code; | |
321 | ||
322 | entry = desktop_entry_new (path, &code); | |
318 | 323 | if (entry == NULL) |
319 | return FALSE; | |
324 | { | |
325 | if (code == DESKTOP_ENTRY_LOAD_FAIL_APPINFO) | |
326 | { | |
327 | menu_verbose ("Adding %s to the retry list (mimeinfo.cache maybe isn't done getting updated yet\n", path); | |
328 | ||
329 | dir->retry_later_desktop_entries = g_slist_prepend (dir->retry_later_desktop_entries, g_strdup (path)); | |
330 | } | |
331 | ||
332 | return FALSE; | |
333 | } | |
320 | 334 | |
321 | 335 | dir->entries = g_slist_prepend (dir->entries, entry); |
322 | 336 | |
524 | 538 | CachedDir *dir) |
525 | 539 | { |
526 | 540 | gboolean handled = FALSE; |
541 | gboolean retry_changes = FALSE; | |
542 | ||
527 | 543 | char *basename; |
528 | 544 | char *dirname; |
529 | 545 | |
557 | 573 | break; |
558 | 574 | } |
559 | 575 | } |
576 | else if (g_strcmp0 (basename, "mimeinfo.cache") == 0) | |
577 | { | |
578 | /* The observed file notifies when a new desktop file is added | |
579 | * (but fails to load) go something like: | |
580 | * | |
581 | * NOTIFY: foo.desktop | |
582 | * NOTIFY: mimeinfo.cache.tempfile | |
583 | * NOTIFY: mimeinfo.cache.tempfile | |
584 | * NOTIFY: mimeinfo.cache | |
585 | * | |
586 | * Additionally, the failure is not upon trying to read the file, | |
587 | * but attempting to get its GAppInfo (g_desktop_app_info_new_from_filename() | |
588 | * in desktop-entries.c ln 277). If you jigger desktop_entry_load() around | |
589 | * and read the file as a keyfile *first*, it succeeds. If you then try | |
590 | * to run g_desktop_app_info_new_from_keyfile(), *then* it fails. | |
591 | * | |
592 | * The theory here is there is a race condition where app info (which includes | |
593 | * mimetype stuff) is unavailable because mimeinfo.cache is updated immediately | |
594 | * after the app is installed. | |
595 | * | |
596 | * What we do here is, when a desktop fails to load, we add it to a temporary | |
597 | * list. We wait until mimeinfo.cache changes, then retry that desktop file, | |
598 | * which succeeds this second time. | |
599 | * | |
600 | * Note: An alternative fix (presented more as a proof than a suggestion) is to | |
601 | * change line 151 in menu-monitor.c to use g_timeout_add_seconds, and delay | |
602 | * for one second. This also avoids the issue (but it remains a race condition). | |
603 | */ | |
604 | ||
605 | GSList *iter; | |
606 | ||
607 | menu_verbose ("mimeinfo changed, checking for failed entries\n"); | |
608 | ||
609 | for (iter = dir->retry_later_desktop_entries; iter != NULL; iter = iter->next) | |
610 | { | |
611 | const gchar *retry_path = iter->data; | |
612 | ||
613 | menu_verbose ("retrying %s\n", retry_path); | |
614 | ||
615 | char *retry_basename = g_path_get_basename (retry_path); | |
616 | ||
617 | if (cached_dir_update_entry (dir, retry_basename, retry_path)) | |
618 | retry_changes = TRUE; | |
619 | ||
620 | g_free (retry_basename); | |
621 | } | |
622 | ||
623 | g_slist_free_full (dir->retry_later_desktop_entries, g_free); | |
624 | dir->retry_later_desktop_entries = NULL; | |
625 | ||
626 | handled = retry_changes; | |
627 | } | |
560 | 628 | else /* Try recursing */ |
561 | 629 | { |
562 | 630 | switch (event) |
583 | 651 | |
584 | 652 | if (handled) |
585 | 653 | { |
586 | /* CHANGED events don't change the set of desktop entries */ | |
587 | if (event == MENU_MONITOR_EVENT_CREATED || event == MENU_MONITOR_EVENT_DELETED) | |
654 | /* CHANGED events don't change the set of desktop entries, unless it's the mimeinfo.cache file changing */ | |
655 | if (retry_changes || (event == MENU_MONITOR_EVENT_CREATED || event == MENU_MONITOR_EVENT_DELETED)) | |
588 | 656 | { |
589 | 657 | _entry_directory_list_empty_desktop_cache (); |
590 | 658 | } |