Codebase list cinnamon-menus / upstream/3.0.1
Imported Upstream version 3.0.1 Margarita Manterola 7 years ago
4 changed file(s) with 156 addition(s) and 52 deletion(s). Raw diff Collapse all Expand all
00 AC_PREREQ(2.62)
11
2 AC_INIT([cinnamon-menus], [3.0.0])
2 AC_INIT([cinnamon-menus], [3.0.1])
33 AC_CONFIG_SRCDIR(libmenu/gmenu-tree.h)
44
55 AM_INIT_AUTOMAKE([1.11 foreign no-dist-gzip dist-xz])
262262 return TRUE;
263263 }
264264
265 static gboolean
265 static DesktopEntryResultCode
266266 desktop_entry_load (DesktopEntry *entry)
267267 {
268 DesktopEntryResultCode rescode = DESKTOP_ENTRY_LOAD_FAIL_OTHER;
269
268270 if (strstr (entry->path, "/menu-xdg/"))
269 return FALSE;
271 return rescode;
272
270273 if (entry->type == DESKTOP_ENTRY_DESKTOP)
271274 {
272275 GKeyFile *key_file = NULL;
273276 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))
280281 {
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 }
283314 }
284
285 categories_str = g_desktop_app_info_get_categories (entry_desktop->appinfo);
286 if (categories_str)
315 else
287316 {
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;
298319 }
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
307320 g_key_file_free (key_file);
308
309 return TRUE;
310321 }
311322 else if (entry->type == DESKTOP_ENTRY_DIRECTORY)
312323 {
313324 GKeyFile *key_file = NULL;
314325 GError *error = NULL;
315 gboolean retval = FALSE;
326 rescode = DESKTOP_ENTRY_LOAD_SUCCESS;
316327
317328 key_file = g_key_file_new ();
318329
319330 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 }
321335
322336 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;
326343
327344 out:
328345 g_key_file_free (key_file);
329346
330 if (!retval)
347 if (rescode == DESKTOP_ENTRY_LOAD_FAIL_OTHER)
331348 {
332349 if (error)
333350 {
337354 else
338355 menu_verbose ("Failed to load \"%s\"\n", entry->path);
339356 }
340
341 return retval;
342357 }
343358 else
344359 g_assert_not_reached ();
345360
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;
347369 }
348370
349371 DesktopEntry *
350 desktop_entry_new (const char *path)
372 desktop_entry_new (const char *path,
373 DesktopEntryResultCode *res_code)
351374 {
352375 DesktopEntryType type;
353376 DesktopEntry *retval;
377 DesktopEntryResultCode code;
354378
355379 menu_verbose ("Loading desktop entry \"%s\"\n", path);
356380
368392 {
369393 menu_verbose ("Unknown desktop entry suffix in \"%s\"\n",
370394 path);
395 *res_code = DESKTOP_ENTRY_LOAD_FAIL_OTHER;
371396 return NULL;
372397 }
373398
376401 retval->path = g_strdup (path);
377402 retval->basename = unix_basename_from_path (retval->path);
378403
379 if (!desktop_entry_load (retval))
404 code = desktop_entry_load (retval);
405 *res_code = code;
406
407 if (code_failed (code))
380408 {
381409 desktop_entry_unref (retval);
382410 return NULL;
418446 else
419447 g_assert_not_reached ();
420448
421 if (!desktop_entry_load (entry))
449 if (code_failed (desktop_entry_load (entry)))
422450 {
423451 desktop_entry_unref (entry);
424452 return NULL;
3030 DESKTOP_ENTRY_DIRECTORY
3131 } DesktopEntryType;
3232
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
3340 typedef struct DesktopEntry DesktopEntry;
3441
35 DesktopEntry *desktop_entry_new (const char *path);
42 DesktopEntry *desktop_entry_new (const char *path,
43 DesktopEntryResultCode *res_code);
3644
3745 DesktopEntry *desktop_entry_ref (DesktopEntry *entry);
3846 DesktopEntry *desktop_entry_copy (DesktopEntry *entry);
5656
5757 GSList *entries;
5858 GSList *subdirs;
59 GSList *retry_later_desktop_entries;
5960
6061 MenuMonitor *dir_monitor;
6162 GSList *monitors;
160161 g_slist_free (dir->subdirs);
161162 dir->subdirs = NULL;
162163
164 g_slist_free_full (dir->retry_later_desktop_entries, g_free);
165 dir->retry_later_desktop_entries = NULL;
166
163167 g_free (dir->name);
164168 g_free (dir);
165169 }
313317 const char *path)
314318 {
315319 DesktopEntry *entry;
316
317 entry = desktop_entry_new (path);
320 DesktopEntryResultCode code;
321
322 entry = desktop_entry_new (path, &code);
318323 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 }
320334
321335 dir->entries = g_slist_prepend (dir->entries, entry);
322336
524538 CachedDir *dir)
525539 {
526540 gboolean handled = FALSE;
541 gboolean retry_changes = FALSE;
542
527543 char *basename;
528544 char *dirname;
529545
557573 break;
558574 }
559575 }
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 }
560628 else /* Try recursing */
561629 {
562630 switch (event)
583651
584652 if (handled)
585653 {
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))
588656 {
589657 _entry_directory_list_empty_desktop_cache ();
590658 }