Hello community, here is the log from the commit of package menu-cache for openSUSE:Factory checked in at 2014-10-24 10:48:05 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Comparing /work/SRC/openSUSE:Factory/menu-cache (Old) and /work/SRC/openSUSE:Factory/.menu-cache.new (New) ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Package is "menu-cache" Changes: -------- --- /work/SRC/openSUSE:Factory/menu-cache/menu-cache.changes 2014-09-15 18:24:33.000000000 +0200 +++ /work/SRC/openSUSE:Factory/.menu-cache.new/menu-cache.changes 2014-10-24 10:48:15.000000000 +0200 @@ -1,0 +2,40 @@ +Mon Sep 29 20:52:33 UTC 2014 - t...@gmx.com + +- update to pre-release version 1.0.0 + * A little code optimization + * Fix compilation warning + * Fix DISTCLEANFILES in docs - generated files should be cleaned + * Add Log Domain "Menu-Cache" for better library logging + messages + * Fixed bug when cache was not updated while it should + * Added new cache file format generation support with changes: + - invisible directories (NoDisplay=true or empty) can be put + into the cache too but with flag (not displayed) set; + - content of TryExec field is added to contents of cache file; + - the working dir to execute application is added to cache + file; + - list of categories is added to contents of cache file; + - list of keywords is added to contents of cache file. + * Fixed crash in menu_cache_item_get_file_dirname() for a + non-existent file (might happen for directories without + .directory file). + * Made menu_cache_app_get_working_dir() actually work. + * Made menu_cache_lookup() faster (do not load cache immediately + but on idle instead). + * Eliminated secondary cache reload in menu_cache_lookup_sync() + - server response in such case will be ahead of idle reload + (since main thread is in wait ATM) and therefore idle call + will be supressed. + * Added new API menu_cache_app_get_categories() to get list of + categories for the application. + * Added new APIs for applications: + menu_cache_list_all_for_category() and + menu_cache_list_all_for_keyword() that return list of + applications matching criteria. + * Fixed problem if some string in the desktop entry file + contained a new line character. That broke cache file format, + now it's replaced with a "\n" string and converted back into + new line in the library. +- applied spec-cleaner + +------------------------------------------------------------------- Old: ---- menu-cache-0.7.0.tar.xz New: ---- menu-cache-1.0.0.tar.xz ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Other differences: ------------------ ++++++ menu-cache.spec ++++++ --- /var/tmp/diff_new_pack.K7unB6/_old 2014-10-24 10:48:17.000000000 +0200 +++ /var/tmp/diff_new_pack.K7unB6/_new 2014-10-24 10:48:17.000000000 +0200 @@ -1,7 +1,7 @@ # # spec file for package menu-cache # -# Copyright (c) 2013 SUSE LINUX Products GmbH, Nuernberg, Germany. +# Copyright (c) 2014 SUSE LINUX Products GmbH, Nuernberg, Germany. # # All modifications and additions to the file contributed by third parties # remain the property of their copyright owners, unless otherwise agreed @@ -17,15 +17,18 @@ Name: menu-cache -Version: 0.7.0 +Version: 1.0.0 Release: 0 Summary: A tool speed up menus License: GPL-2.0+ and LGPL-2.1+ Group: System/GUI/LXDE Url: http://www.lxde.org Source0: %{name}-%{version}.tar.xz +BuildRequires: fdupes +BuildRequires: gtk-doc BuildRequires: gtk2-devel -BuildRequires: pkg-config +BuildRequires: intltool +BuildRequires: libtool BuildRequires: pkgconfig(libfm-extra) BuildRoot: %{_tmppath}/%{name}-%{version}-build @@ -63,7 +66,8 @@ %install %make_install -find %{buildroot} -name '*.la' -exec rm -f {} ';' +find %{buildroot} -type f -name "*.la" -delete -print +%fdupes %{buildroot} %post -n libmenu-cache3 -p /sbin/ldconfig @@ -83,6 +87,6 @@ %files -n libmenu-cache3 %defattr(-,root,root) %{_libdir}/libmenu-cache.so.3 -%{_libdir}/libmenu-cache.so.3.0.4 +%{_libdir}/libmenu-cache.so.3.1.0 %changelog ++++++ menu-cache-0.7.0.tar.xz -> menu-cache-1.0.0.tar.xz ++++++ ++++ 1791 lines of diff (skipped) ++++ retrying with extended exclude list diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' --exclude Makefile.in --exclude configure --exclude config.guess --exclude '*.pot' --exclude mkinstalldirs --exclude aclocal.m4 --exclude config.sub --exclude depcomp --exclude install-sh --exclude ltmain.sh old/menu-cache-0.7.0/AUTHORS new/menu-cache-1.0.0/AUTHORS --- old/menu-cache-0.7.0/AUTHORS 2014-09-06 18:27:45.000000000 +0200 +++ new/menu-cache-1.0.0/AUTHORS 2014-09-28 18:00:07.000000000 +0200 @@ -1,10 +1,10 @@ Upstream Authors: - LXDE team: http://lxde.org Hong Jen Yee (PCMan) <pcman...@gmail.com> + Jürgen Hötzel <juer...@archlinux.org> Andriy Grytsenko (LStranger) <and...@rep.kiev.ua> Copyright: - Copyright (c) 2012-2014 LXQt team + LXDE team: http://lxde.org -License: GPL-2 and LGPL-2.1+ -The full text of the licenses can be found in the 'COPYING' file. +License: LGPL-2.1+ +The full text of the license can be found in the 'COPYING' file. diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' --exclude Makefile.in --exclude configure --exclude config.guess --exclude '*.pot' --exclude mkinstalldirs --exclude aclocal.m4 --exclude config.sub --exclude depcomp --exclude install-sh --exclude ltmain.sh old/menu-cache-0.7.0/Makefile.am new/menu-cache-1.0.0/Makefile.am --- old/menu-cache-0.7.0/Makefile.am 2014-08-26 19:17:39.000000000 +0200 +++ new/menu-cache-1.0.0/Makefile.am 2014-09-28 19:11:28.000000000 +0200 @@ -1,12 +1,19 @@ +## Process this file with automake to produce Makefile.in + +ACLOCAL_AMFLAGS= -I m4 + NULL = SUBDIRS_DOCS = docs EXTRA_DIST_DOCS = \ gtk-doc.make \ - docs/Makefile.* \ - docs/reference/Makefile.* \ - docs/reference/libmenu-cache/Makefile.* \ + docs/Makefile.am \ + docs/Makefile.in \ + docs/reference/Makefile.am \ + docs/reference/Makefile.in \ + docs/reference/libmenu-cache/Makefile.am \ + docs/reference/libmenu-cache/Makefile.in \ $(NULL) ALL_SUBDIRS = \ @@ -27,3 +34,5 @@ else EXTRA_DIST += $(EXTRA_DIST_DOCS) endif + +DISTCHECK_CONFIGURE_FLAGS=--enable-gtk-doc diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' --exclude Makefile.in --exclude configure --exclude config.guess --exclude '*.pot' --exclude mkinstalldirs --exclude aclocal.m4 --exclude config.sub --exclude depcomp --exclude install-sh --exclude ltmain.sh old/menu-cache-0.7.0/NEWS new/menu-cache-1.0.0/NEWS --- old/menu-cache-0.7.0/NEWS 2014-09-06 18:27:45.000000000 +0200 +++ new/menu-cache-1.0.0/NEWS 2014-10-23 15:12:12.000000000 +0200 @@ -1,3 +1,44 @@ +Changes in 1.0.0 since 0.7.0: + +* Added new cache file format generation support with changes: + - invisible directories (NoDisplay=true or empty) can be put into the + cache too but with flag (not displayed) set; + - content of TryExec field is added to contents of cache file; + - the working dir to execute application is added to cache file; + - list of categories is added to contents of cache file; + - list of keywords is added to contents of cache file. + +* Fixed crash in menu_cache_item_get_file_dirname() for a non-existent + file (might happen for directories without .directory file). + +* Made menu_cache_app_get_working_dir() actually work. + +* Made menu_cache_lookup() faster (do not load cache immediately but on + idle instead). + +* Eliminated secondary cache reload in menu_cache_lookup_sync() - server + response in such case will be ahead of idle reload (since main thread + is in wait ATM) and therefore idle call will be supressed. + +* Added new API menu_cache_app_get_categories() to get list of categories + for the application. + +* Added new APIs for applications: menu_cache_list_all_for_category() and + menu_cache_list_all_for_keyword() that return list of applications + matching criteria. + +* Fixed problem if some string in the desktop entry file contained a new + line character. That broke cache file format, now it's replaced with + a "\n" string and converted back into new line in the library. + +* Fixed bug when cache was not updated while it should: check if the last + modification time for directory is more recent than modification time + for cache may not always be valid - some .desktop entry might be just + changed by update and that will lead to falsed cache contents. + +* Added Log Domain "Menu-Cache" for better library logging messages. + + Changes in 0.7.0 since 0.6.1: * Added bit of support for multiple supported cache file versions, using diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' --exclude Makefile.in --exclude configure --exclude config.guess --exclude '*.pot' --exclude mkinstalldirs --exclude aclocal.m4 --exclude config.sub --exclude depcomp --exclude install-sh --exclude ltmain.sh old/menu-cache-0.7.0/README new/menu-cache-1.0.0/README --- old/menu-cache-0.7.0/README 2014-09-06 18:27:45.000000000 +0200 +++ new/menu-cache-1.0.0/README 2014-09-28 18:00:07.000000000 +0200 @@ -48,7 +48,8 @@ Format of the cached menu file, line by line. (Spaces before the lines are for easier demostration of hierarchy. - There are no spaces in the real cached file.): + There are no spaces in the real cached file. + Fields marked with [**] added only in the file format 1.2): version number (major.minor) menu name> @@ -66,6 +67,7 @@ dir in which menu directory file locates (use this number as index to get the string from array of preceding list of monitored files) + [**] bitmask flags: (--)|(--)|(not displayed) -application desktop id (NOTE: desktop id is not necessarily the basename of desktop file) title @@ -77,8 +79,12 @@ preceding list of monitored files) generic name exec command line - bitmask flags: (use terminal)|(use startup notification) + bitmask flags: (use terminal)|(use startup notification)|(not displayed) show_in_flags: bitwise or of masks for various DEs. + [**] executable name to test for availability + [**] working dir for exec + [**] categories: list divided by semicolon + [**] keywords: list divided by comma +sub dir id title comment diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' --exclude Makefile.in --exclude configure --exclude config.guess --exclude '*.pot' --exclude mkinstalldirs --exclude aclocal.m4 --exclude config.sub --exclude depcomp --exclude install-sh --exclude ltmain.sh old/menu-cache-0.7.0/configure.ac new/menu-cache-1.0.0/configure.ac --- old/menu-cache-0.7.0/configure.ac 2014-09-06 18:27:45.000000000 +0200 +++ new/menu-cache-1.0.0/configure.ac 2014-10-23 15:12:12.000000000 +0200 @@ -1,6 +1,10 @@ -AC_INIT([menu-cache], [0.7.0], +dnl Process this file with autoconf to produce a configure script. + +AC_INIT([menu-cache], [1.0.0], [http://lxde.org/]) +AC_CONFIG_MACRO_DIR([m4]) + AM_INIT_AUTOMAKE([no-dist-gzip dist-xz]) AM_CONFIG_HEADER(config.h) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' --exclude Makefile.in --exclude configure --exclude config.guess --exclude '*.pot' --exclude mkinstalldirs --exclude aclocal.m4 --exclude config.sub --exclude depcomp --exclude install-sh --exclude ltmain.sh old/menu-cache-0.7.0/docs/reference/libmenu-cache/Makefile.am new/menu-cache-1.0.0/docs/reference/libmenu-cache/Makefile.am --- old/menu-cache-0.7.0/docs/reference/libmenu-cache/Makefile.am 2014-08-26 19:17:39.000000000 +0200 +++ new/menu-cache-1.0.0/docs/reference/libmenu-cache/Makefile.am 2014-10-23 15:12:12.000000000 +0200 @@ -29,7 +29,7 @@ # Extra options to supply to gtkdoc-scan. # e.g. SCAN_OPTIONS=--deprecated-guards="GTK_DISABLE_DEPRECATED" -SCAN_OPTIONS=--rebuild-types --deprecated-guards="G_DISABLE_DEPRECATED" +SCAN_OPTIONS=--rebuild-sections --rebuild-types --deprecated-guards="G_DISABLE_DEPRECATED" # Extra options to supply to gtkdoc-mkdb. # e.g. MKDB_OPTIONS=--xml-mode --output-format=xml @@ -91,7 +91,10 @@ # Files not to distribute # for --rebuild-types in $(SCAN_OPTIONS), e.g. $(DOC_MODULE).types # for --rebuild-sections in $(SCAN_OPTIONS) e.g. $(DOC_MODULE)-sections.txt -#DISTCLEANFILES += +DISTCLEANFILES = $(DOC_MODULE).types $(DOC_MODULE)-sections.txt + +# Fix parallel build - we need this file built before continuing +$(DOC_MAIN_SGML_FILE): sgml-build.stamp # Comment this out if you want 'make check' to test you doc status # and run some sanity checks diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' --exclude Makefile.in --exclude configure --exclude config.guess --exclude '*.pot' --exclude mkinstalldirs --exclude aclocal.m4 --exclude config.sub --exclude depcomp --exclude install-sh --exclude ltmain.sh old/menu-cache-0.7.0/libmenu-cache/Makefile.am new/menu-cache-1.0.0/libmenu-cache/Makefile.am --- old/menu-cache-0.7.0/libmenu-cache/Makefile.am 2014-09-06 18:27:45.000000000 +0200 +++ new/menu-cache-1.0.0/libmenu-cache/Makefile.am 2014-10-23 15:12:12.000000000 +0200 @@ -1,30 +1,28 @@ NULL = -INCLUDES = \ - $(GLIB_CFLAGS) \ - $(MONITOR_CFLAGS) \ +AM_CPPFLAGS = \ + $(GLIB_CFLAGS) \ $(DEBUG_CFLAGS) \ $(ADDITIONAL_FLAGS) \ -Werror-implicit-function-declaration \ -DMENUCACHE_LIBEXECDIR="\"$(pkglibexecdir)\"" \ + -DG_LOG_DOMAIN=\"Menu-Cache\" \ $(NULL) lib_LTLIBRARIES = libmenu-cache.la libmenu_cache_la_SOURCES = \ - version.h \ menu-cache.c \ - $(MONITOR_SOURCES) \ $(NULL) libmenu_cache_la_LIBADD = \ $(GLIB_LIBS) \ - $(MONITOR_LIBS) \ $(NULL) + libmenu_cache_la_LDFLAGS = \ -no-undefined \ -export-symbols-regex menu_cache \ - -version-info 3:4:0 \ + -version-info 4:0:1 \ $(NULL) lib_menu_cache_includedir = $(includedir)/menu-cache @@ -34,6 +32,7 @@ $(NULL) EXTRA_DIST = \ + version.h \ libmenu-cache.pc.in \ $(NULL) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' --exclude Makefile.in --exclude configure --exclude config.guess --exclude '*.pot' --exclude mkinstalldirs --exclude aclocal.m4 --exclude config.sub --exclude depcomp --exclude install-sh --exclude ltmain.sh old/menu-cache-0.7.0/libmenu-cache/menu-cache.c new/menu-cache-1.0.0/libmenu-cache/menu-cache.c --- old/menu-cache-0.7.0/libmenu-cache/menu-cache.c 2014-09-06 18:27:45.000000000 +0200 +++ new/menu-cache-1.0.0/libmenu-cache/menu-cache.c 2014-09-28 18:00:07.000000000 +0200 @@ -2,22 +2,22 @@ * menu-cache.c * * Copyright 2008 PCMan <pcman...@gmail.com> + * Copyright 2009 Jürgen Hötzel <juer...@archlinux.org> * Copyright 2012-2014 Andriy Grytsenko (LStranger) <and...@rep.kiev.ua> * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. * - * This program is distributed in the hope that it will be useful, + * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, - * MA 02110-1301, USA. + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #ifdef HAVE_CONFIG_H @@ -99,6 +99,7 @@ { MenuCacheItem item; GSList* children; + guint32 flags; }; struct _MenuCacheApp @@ -108,8 +109,10 @@ char* exec; char* working_dir; guint32 show_in_flags; -/* char** categories; */ guint32 flags; + char* try_exec; + const char **categories; + char* keywords; }; struct _MenuCache @@ -125,6 +128,7 @@ GThread* thr; GCancellable* cancellable; guint version; + guint reload_id; gboolean ready : 1; /* used for sync access */ }; @@ -164,6 +168,18 @@ MenuCacheFileDir** all_used_files, int n_all_used_files) { MenuCacheItem* item; + char *line; + gsize len; + + /* nodisplay flag */ + if (cache->version >= 2) + { + line = g_data_input_stream_read_line(f, &len, cache->cancellable, NULL); + if (G_UNLIKELY(line == NULL)) + return; + dir->flags = (guint32)atoi(line); + g_free(line); + } /* load child items in the dir */ while( (item = read_item( f, cache, all_used_files, n_all_used_files )) ) @@ -175,19 +191,61 @@ } dir->children = g_slist_reverse( dir->children ); + + /* set flag by children if working with old cache generator */ + if (cache->version == 1) + { + if (dir->children == NULL) + dir->flags = FLAG_IS_NODISPLAY; + else if ((line = menu_cache_item_get_file_path(MENU_CACHE_ITEM(dir))) != NULL) + { + GKeyFile *kf = g_key_file_new(); + if (g_key_file_load_from_file(kf, line, G_KEY_FILE_NONE, NULL) && + g_key_file_get_boolean(kf, G_KEY_FILE_DESKTOP_GROUP, + G_KEY_FILE_DESKTOP_KEY_NO_DISPLAY, NULL)) + dir->flags = FLAG_IS_NODISPLAY; + g_key_file_free(kf); + g_free(line); + } + } +} + +static char *_unescape_lf(char *str) +{ + char *c, *p = str; + gsize len = 0; + + while ((c = strchr(p, '\\')) != NULL) + { + if (p != &str[len]) + memmove(&str[len], p, c - p); + len += (c - p); + if (c[1] == 'n') + { + str[len++] = '\n'; + c++; + } + else if (c != &str[len]) + str[len++] = *c; + p = &c[1]; + } + if (p != &str[len]) + memmove(&str[len], p, strlen(p) + 1); + return str; } static void read_app(GDataInputStream* f, MenuCacheApp* app, MenuCache* cache) { char *line; gsize len; + GString *str; /* generic name */ line = g_data_input_stream_read_line(f, &len, cache->cancellable, NULL); if(G_UNLIKELY(line == NULL)) return; if(G_LIKELY(len > 0)) - app->generic_name = line; + app->generic_name = _unescape_lf(line); else g_free(line); @@ -196,7 +254,7 @@ if(G_UNLIKELY(line == NULL)) return; if(G_LIKELY(len > 0)) - app->exec = line; + app->exec = _unescape_lf(line); else g_free(line); @@ -213,6 +271,82 @@ return; app->show_in_flags = (guint32)atol(line); g_free(line); + + if (cache->version < 2) + return; + + /* TryExec */ + line = g_data_input_stream_read_line(f, &len, cache->cancellable, NULL); + if (G_UNLIKELY(line == NULL)) + return; + if (G_LIKELY(len > 0)) + app->try_exec = g_strchomp(line); + else + g_free(line); + + /* Path */ + line = g_data_input_stream_read_line(f, &len, cache->cancellable, NULL); + if (G_UNLIKELY(line == NULL)) + return; + if (G_LIKELY(len > 0)) + app->working_dir = line; + else + g_free(line); + + /* Categories */ + line = g_data_input_stream_read_line(f, &len, cache->cancellable, NULL); + if (G_UNLIKELY(line == NULL)) + return; + if (G_LIKELY(len > 0)) + { + const char **x; + + /* split and intern all the strings so categories can be processed + later for search doing g_quark_try_string()+g_quark_to_string() */ + app->categories = x = (const char **)g_strsplit(line, ";", 0); + while (*x != NULL) + { + char *cat = (char *)*x; + *x = g_intern_string(cat); + g_free(cat); + x++; + } + } + g_free(line); + + /* Keywords */ + str = g_string_new(MENU_CACHE_ITEM(app)->name); + if (G_LIKELY(app->exec != NULL)) + { + char *sp = strchr(app->exec, ' '); + char *bn = strrchr(app->exec, G_DIR_SEPARATOR); + + g_string_append_c(str, ','); + if (bn == NULL && sp == NULL) + g_string_append(str, app->exec); + else if (bn == NULL || (sp != NULL && sp < bn)) + g_string_append_len(str, app->exec, sp - app->exec); + else if (sp == NULL) + g_string_append(str, &bn[1]); + else + g_string_append_len(str, &bn[1], sp - &bn[1]); + } + if (app->generic_name != NULL) + { + g_string_append_c(str, ','); + g_string_append(str, app->generic_name); + } + line = g_data_input_stream_read_line(f, &len, cache->cancellable, NULL); + if (G_UNLIKELY(line == NULL)) + return; + if (len > 0) + { + g_string_append_c(str, ','); + g_string_append(str, line); + } + app->keywords = g_utf8_casefold(str->str, str->len); + g_string_free(str, TRUE); + g_free(line); } static MenuCacheItem* read_item(GDataInputStream* f, MenuCache* cache, @@ -265,7 +399,7 @@ if(G_UNLIKELY(line == NULL)) goto _fail; if(G_LIKELY(len > 0)) - item->name = line; + item->name = _unescape_lf(line); else g_free(line); @@ -274,7 +408,7 @@ if(G_UNLIKELY(line == NULL)) goto _fail; if(G_LIKELY(len > 0)) - item->comment = line; + item->comment = _unescape_lf(line); else g_free(line); @@ -439,6 +573,7 @@ MENU_CACHE_LOCK; if( g_atomic_int_dec_and_test(&cache->n_ref) ) { + /* g_assert(cache->reload_id != 0); */ unregister_menu_from_server( cache ); /* DEBUG("unregister to server"); */ g_hash_table_remove( hash, cache->menu_name ); @@ -537,6 +672,14 @@ return item; } +static gboolean menu_cache_reload_idle(gpointer cache) +{ + /* do reload once */ + if (!g_source_is_destroyed(g_main_current_source())) + menu_cache_reload(cache); + return FALSE; +} + typedef struct _CacheReloadNotifier { MenuCacheReloadNotify func; @@ -572,10 +715,13 @@ MENU_CACHE_LOCK; is_first = (cache->root_dir == NULL && cache->notifiers == NULL); cache->notifiers = g_slist_concat( cache->notifiers, l ); - MENU_CACHE_UNLOCK; /* reload existing file first so it will be ready right away */ - if(is_first) - menu_cache_reload(cache); + if(is_first && cache->reload_id == 0) + cache->reload_id = g_idle_add_full(G_PRIORITY_HIGH_IDLE, + menu_cache_reload_idle, + menu_cache_ref(cache), + (GDestroyNotify)menu_cache_unref); + MENU_CACHE_UNLOCK; return (MenuCacheNotifyId)l; } @@ -634,6 +780,11 @@ int i, n; int ver_maj, ver_min; + MENU_CACHE_LOCK; + if (cache->reload_id) + g_source_remove(cache->reload_id); + cache->reload_id = 0; + MENU_CACHE_UNLOCK; file = g_file_new_for_path(cache->cache_file); if(!file) return FALSE; @@ -661,6 +812,7 @@ else goto _fail; + g_debug("menu cache: got file version 1.%d", ver_min); /* the second line is menu name */ line = g_data_input_stream_read_line(f, &len, cache->cancellable, NULL); if(G_UNLIKELY(line == NULL)) @@ -772,6 +924,10 @@ { MenuCacheApp* app = MENU_CACHE_APP(item); g_free( app->exec ); + g_free(app->try_exec); + g_free(app->working_dir); + g_free(app->categories); + g_free(app->keywords); g_slice_free( MenuCacheApp, app ); } } @@ -891,7 +1047,7 @@ */ const char* menu_cache_item_get_file_dirname( MenuCacheItem* item ) { - return item->file_dir->dir + 1; + return item->file_dir ? item->file_dir->dir + 1 : NULL; } /** @@ -1074,7 +1230,7 @@ */ gboolean menu_cache_dir_is_visible(MenuCacheDir *dir) { - return (dir->children != NULL); + return ((dir->flags & FLAG_IS_NODISPLAY) == 0); } /** @@ -1109,12 +1265,21 @@ return app->working_dir; } -/* -char** menu_cache_app_get_categories( MenuCacheApp* app ) +/** + * menu_cache_app_get_categories + * @app: a menu cache item + * + * Retrieves list of categories for @app. Returned data are owned by menu + * cache and should be not freed by caller. + * + * Returns: (transfer none): list of categories or %NULL. + * + * Since: 1.0.0 + */ +const char * const * menu_cache_app_get_categories(MenuCacheApp* app) { - return NULL; + return app->categories; } -*/ /** * menu_cache_app_get_use_terminal @@ -1161,6 +1326,17 @@ return app->show_in_flags; } +static gboolean _can_be_exec(MenuCacheApp *app) +{ + char *path; + + if (app->try_exec == NULL) + return TRUE; + path = g_find_program_in_path(app->try_exec); + g_free(path); + return (path != NULL); +} + /** * menu_cache_app_get_is_visible * @app: a menu cache item @@ -1177,7 +1353,8 @@ { if(app->flags & FLAG_IS_NODISPLAY) return FALSE; - return !app->show_in_flags || (app->show_in_flags & de_flags); + return (!app->show_in_flags || (app->show_in_flags & de_flags)) && + _can_be_exec(app); } /* @@ -1677,13 +1854,14 @@ /** * menu_cache_lookup - * @menu_name: a menu cache root + * @menu_name: a menu name * - * Searches for connection to menu-cached for @menu_name. If no such - * connection exists then creates new one. Caller can be notified when - * cache is ready by adding callback. + * Searches for connection to menu-cached for @menu_name. If there is no + * such connection exist then creates new one. Caller can be notified + * when cache is (re)loaded by adding callback. Caller should check if + * the cache is already loaded trying to retrieve its root. * - * See also: menu_cache_add_reload_notify(). + * See also: menu_cache_add_reload_notify(), menu_cache_item_dup_parent(). * * Returns: (transfer full): menu cache descriptor. * @@ -1728,7 +1906,7 @@ /** * menu_cache_lookup_sync - * @menu_name: a menu cache root + * @menu_name: a menu name * * Searches for data from menu-cached for @menu_name. If no connection * exists yet then creates new one and retrieves all data. @@ -1918,5 +2096,119 @@ return item; } -/* TODO: -const char **menu_cache_app_get_categories(MenuCacheApp *app) */ \ No newline at end of file +static GSList* list_app_in_dir_for_cat(MenuCacheDir *dir, GSList *list, const char *id) +{ + const char **cat; + GSList *l; + + for (l = dir->children; l; l = l->next) + { + MenuCacheItem *item = MENU_CACHE_ITEM(l->data); + switch (item->type) + { + case MENU_CACHE_TYPE_DIR: + list = list_app_in_dir_for_cat(MENU_CACHE_DIR(item), list, id); + break; + case MENU_CACHE_TYPE_APP: + cat = MENU_CACHE_APP(item)->categories; + if (cat) while (*cat) + if (*cat++ == id) + { + list = g_slist_prepend(list, menu_cache_item_ref(item)); + break; + } + break; + case MENU_CACHE_TYPE_NONE: + case MENU_CACHE_TYPE_SEP: + break; + } + } + return list; +} + +/** + * menu_cache_list_all_for_category + * @cache: a menu cache descriptor + * @category: category to list items + * + * Retrieves list of applications in menu cache which have @category in + * their list of categories. The search is case-sensitive. Returned list + * should be freed with g_slist_free_full(list, menu_cache_item_unref) + * after usage. + * + * Returns: (transfer full) (element-type MenuCacheItem): list of items. + * + * Since: 1.0.0 + */ +GSList *menu_cache_list_all_for_category(MenuCache* cache, const char *category) +{ + GQuark q; + GSList *list; + + g_return_val_if_fail(cache != NULL && category != NULL, NULL); + q = g_quark_try_string(category); + if (q == 0) + return NULL; + MENU_CACHE_LOCK; + if (G_UNLIKELY(cache->root_dir == NULL)) + list = NULL; + else + list = list_app_in_dir_for_cat(cache->root_dir, NULL, g_quark_to_string(q)); + MENU_CACHE_UNLOCK; + return list; +} + +static GSList* list_app_in_dir_for_kw(MenuCacheDir *dir, GSList *list, const char *kw) +{ + GSList *l; + + for (l = dir->children; l; l = l->next) + { + MenuCacheItem *item = MENU_CACHE_ITEM(l->data); + switch (item->type) + { + case MENU_CACHE_TYPE_DIR: + list = list_app_in_dir_for_kw(MENU_CACHE_DIR(item), list, kw); + break; + case MENU_CACHE_TYPE_APP: + if (strstr(MENU_CACHE_APP(item)->keywords, kw) != NULL) + list = g_slist_prepend(list, menu_cache_item_ref(item)); + break; + case MENU_CACHE_TYPE_NONE: + case MENU_CACHE_TYPE_SEP: + break; + } + } + return list; +} + +/** + * menu_cache_list_all_for_keyword + * @cache: a menu cache descriptor + * @keyword: a keyword to search + * + * Retrieves list of applications in menu cache which have a @keyword + * as either a word or part of word in exec command, name, generic name + * or defined keywords. The search is case-insensitive. Returned list + * should be freed with g_slist_free_full(list, menu_cache_item_unref) + * after usage. + * + * Returns: (transfer full) (element-type MenuCacheItem): list of items. + * + * Since: 1.0.0 + */ +GSList *menu_cache_list_all_for_keyword(MenuCache* cache, const char *keyword) +{ + char *casefolded = g_utf8_casefold(keyword, -1); + GSList *list; + + g_return_val_if_fail(cache != NULL && keyword != NULL, NULL); + MENU_CACHE_LOCK; + if (G_UNLIKELY(cache->root_dir == NULL)) + list = NULL; + else + list = list_app_in_dir_for_kw(cache->root_dir, NULL, casefolded); + MENU_CACHE_UNLOCK; + g_free(casefolded); + return list; +} diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' --exclude Makefile.in --exclude configure --exclude config.guess --exclude '*.pot' --exclude mkinstalldirs --exclude aclocal.m4 --exclude config.sub --exclude depcomp --exclude install-sh --exclude ltmain.sh old/menu-cache-0.7.0/libmenu-cache/menu-cache.h.in new/menu-cache-1.0.0/libmenu-cache/menu-cache.h.in --- old/menu-cache-0.7.0/libmenu-cache/menu-cache.h.in 2014-08-26 19:17:39.000000000 +0200 +++ new/menu-cache-1.0.0/libmenu-cache/menu-cache.h.in 2014-09-28 18:37:12.000000000 +0200 @@ -5,22 +5,21 @@ * caches of freedesktop.org menus generated by menu-cache-gen. * * Copyright 2008 PCMan <pcman...@gmail.com> - * Copyright 2012-2013 Andriy Grytsenko (LStranger) <and...@rep.kiev.ua> + * Copyright 2012-2014 Andriy Grytsenko (LStranger) <and...@rep.kiev.ua> * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. * - * This program is distributed in the hope that it will be useful, + * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, - * MA 02110-1301, USA. + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #ifndef __MENU_CACHE_H__ @@ -105,7 +104,6 @@ MenuCache* menu_cache_lookup( const char* menu_name ); MenuCache* menu_cache_lookup_sync( const char* menu_name ); -/* MenuCache* menu_cache_lookup_by_cache_id( const char* md5 ); */ MenuCache* menu_cache_ref(MenuCache* cache); void menu_cache_unref(MenuCache* cache); @@ -129,7 +127,6 @@ guint32 menu_cache_get_desktop_env_flag( MenuCache* cache, const char* desktop_env ); - MenuCacheItem* menu_cache_item_ref(MenuCacheItem* item); gboolean menu_cache_item_unref(MenuCacheItem* item); @@ -156,6 +153,7 @@ const char* menu_cache_app_get_exec( MenuCacheApp* app ); const char* menu_cache_app_get_working_dir( MenuCacheApp* app ); +const char* const *menu_cache_app_get_categories(MenuCacheApp* app); guint32 menu_cache_app_get_show_flags( MenuCacheApp* app ); gboolean menu_cache_app_get_is_visible( MenuCacheApp* app, guint32 de_flags ); @@ -165,6 +163,8 @@ gboolean menu_cache_app_get_use_sn( MenuCacheApp* app ); GSList* menu_cache_list_all_apps(MenuCache* cache); +GSList *menu_cache_list_all_for_category(MenuCache* cache, const char *category); +GSList *menu_cache_list_all_for_keyword(MenuCache* cache, const char *keyword); MenuCacheItem *menu_cache_find_item_by_id(MenuCache *cache, const char *id); /* @@ -173,4 +173,3 @@ G_END_DECLS #endif - diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' --exclude Makefile.in --exclude configure --exclude config.guess --exclude '*.pot' --exclude mkinstalldirs --exclude aclocal.m4 --exclude config.sub --exclude depcomp --exclude install-sh --exclude ltmain.sh old/menu-cache-0.7.0/libmenu-cache/version.h new/menu-cache-1.0.0/libmenu-cache/version.h --- old/menu-cache-0.7.0/libmenu-cache/version.h 2014-09-06 18:27:45.000000000 +0200 +++ new/menu-cache-1.0.0/libmenu-cache/version.h 2014-09-28 18:00:07.000000000 +0200 @@ -4,7 +4,7 @@ /* change these numbers if you change enums in menu-cache.h note that will break compatibility for generated cache */ #define VER_MAJOR 1 -#define VER_MINOR 1 +#define VER_MINOR 2 /* This is for backward compatibility on transitions */ #define VER_MINOR_SUPPORTED 1 diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' --exclude Makefile.in --exclude configure --exclude config.guess --exclude '*.pot' --exclude mkinstalldirs --exclude aclocal.m4 --exclude config.sub --exclude depcomp --exclude install-sh --exclude ltmain.sh old/menu-cache-0.7.0/m4/gtk-doc.m4 new/menu-cache-1.0.0/m4/gtk-doc.m4 --- old/menu-cache-0.7.0/m4/gtk-doc.m4 1970-01-01 01:00:00.000000000 +0100 +++ new/menu-cache-1.0.0/m4/gtk-doc.m4 2014-10-23 15:13:26.000000000 +0200 @@ -0,0 +1,67 @@ +dnl -*- mode: autoconf -*- + +# serial 1 + +dnl Usage: +dnl GTK_DOC_CHECK([minimum-gtk-doc-version]) +AC_DEFUN([GTK_DOC_CHECK], +[ + AC_REQUIRE([PKG_PROG_PKG_CONFIG]) + AC_BEFORE([AC_PROG_LIBTOOL],[$0])dnl setup libtool first + AC_BEFORE([AM_PROG_LIBTOOL],[$0])dnl setup libtool first + + dnl check for tools we added during development + AC_PATH_PROG([GTKDOC_CHECK],[gtkdoc-check]) + AC_PATH_PROGS([GTKDOC_REBASE],[gtkdoc-rebase],[true]) + AC_PATH_PROG([GTKDOC_MKPDF],[gtkdoc-mkpdf]) + + dnl for overriding the documentation installation directory + AC_ARG_WITH([html-dir], + AS_HELP_STRING([--with-html-dir=PATH], [path to installed docs]),, + [with_html_dir='${datadir}/gtk-doc/html']) + HTML_DIR="$with_html_dir" + AC_SUBST([HTML_DIR]) + + dnl enable/disable documentation building + AC_ARG_ENABLE([gtk-doc], + AS_HELP_STRING([--enable-gtk-doc], + [use gtk-doc to build documentation [[default=no]]]),, + [enable_gtk_doc=no]) + + if test x$enable_gtk_doc = xyes; then + ifelse([$1],[], + [PKG_CHECK_EXISTS([gtk-doc],, + AC_MSG_ERROR([gtk-doc not installed and --enable-gtk-doc requested]))], + [PKG_CHECK_EXISTS([gtk-doc >= $1],, + AC_MSG_ERROR([You need to have gtk-doc >= $1 installed to build $PACKAGE_NAME]))]) + dnl don't check for glib if we build glib + if test "x$PACKAGE_NAME" != "xglib"; then + dnl don't fail if someone does not have glib + PKG_CHECK_MODULES(GTKDOC_DEPS, glib-2.0 >= 2.10.0 gobject-2.0 >= 2.10.0,,) + fi + fi + + AC_MSG_CHECKING([whether to build gtk-doc documentation]) + AC_MSG_RESULT($enable_gtk_doc) + + dnl enable/disable output formats + AC_ARG_ENABLE([gtk-doc-html], + AS_HELP_STRING([--enable-gtk-doc-html], + [build documentation in html format [[default=yes]]]),, + [enable_gtk_doc_html=yes]) + AC_ARG_ENABLE([gtk-doc-pdf], + AS_HELP_STRING([--enable-gtk-doc-pdf], + [build documentation in pdf format [[default=no]]]),, + [enable_gtk_doc_pdf=no]) + + if test -z "$GTKDOC_MKPDF"; then + enable_gtk_doc_pdf=no + fi + + + AM_CONDITIONAL([ENABLE_GTK_DOC], [test x$enable_gtk_doc = xyes]) + AM_CONDITIONAL([GTK_DOC_BUILD_HTML], [test x$enable_gtk_doc_html = xyes]) + AM_CONDITIONAL([GTK_DOC_BUILD_PDF], [test x$enable_gtk_doc_pdf = xyes]) + AM_CONDITIONAL([GTK_DOC_USE_LIBTOOL], [test -n "$LIBTOOL"]) + AM_CONDITIONAL([GTK_DOC_USE_REBASE], [test -n "$GTKDOC_REBASE"]) +]) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' --exclude Makefile.in --exclude configure --exclude config.guess --exclude '*.pot' --exclude mkinstalldirs --exclude aclocal.m4 --exclude config.sub --exclude depcomp --exclude install-sh --exclude ltmain.sh old/menu-cache-0.7.0/menu-cache-daemon/Makefile.am new/menu-cache-1.0.0/menu-cache-daemon/Makefile.am --- old/menu-cache-0.7.0/menu-cache-daemon/Makefile.am 2014-08-26 19:17:39.000000000 +0200 +++ new/menu-cache-1.0.0/menu-cache-daemon/Makefile.am 2014-09-28 18:00:07.000000000 +0200 @@ -1,11 +1,10 @@ NULL = -INCLUDES = \ - -I$(top_srcdir)/libmenu-cache \ - $(GLIB_CFLAGS) \ - $(MONITOR_CFLAGS) \ - $(DEBUG_CFLAGS) \ - $(WARN_CFLAGS) \ +AM_CPPFLAGS = \ + -I$(top_srcdir)/libmenu-cache \ + -I$(top_builddir)/libmenu-cache \ + $(GLIB_CFLAGS) \ + $(DEBUG_CFLAGS) \ $(ADDITIONAL_FLAGS) \ -DMENUCACHE_LIBEXECDIR="\"$(pkglibexecdir)\"" \ -Werror-implicit-function-declaration \ @@ -23,5 +22,3 @@ menu_cached_LDFLAGS = \ -no-undefined \ $(NULL) -EXTRA_DIST = \ - $(NULL) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' --exclude Makefile.in --exclude configure --exclude config.guess --exclude '*.pot' --exclude mkinstalldirs --exclude aclocal.m4 --exclude config.sub --exclude depcomp --exclude install-sh --exclude ltmain.sh old/menu-cache-0.7.0/menu-cache-daemon/menu-cached.c new/menu-cache-1.0.0/menu-cache-daemon/menu-cached.c --- old/menu-cache-0.7.0/menu-cache-daemon/menu-cached.c 2014-09-06 18:27:45.000000000 +0200 +++ new/menu-cache-1.0.0/menu-cache-daemon/menu-cached.c 2014-10-23 15:12:12.000000000 +0200 @@ -2,22 +2,25 @@ * menu-cached.c * * Copyright 2008 - 2010 PCMan <pcman...@gmail.com> - * Copyright 2012-2013 Andriy Grytsenko (LStranger) <and...@rep.kiev.ua> + * Copyright 2009 Jürgen Hötzel <juer...@archlinux.org> + * Copyright 2012-2014 Andriy Grytsenko (LStranger) <and...@rep.kiev.ua> * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. + * This file is a part of libmenu-cache package and created program + * should be not used without the library. * - * This program is distributed in the hope that it will be useful, + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, - * MA 02110-1301, USA. + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #ifdef HAVE_CONFIG_H @@ -140,7 +143,8 @@ return FALSE; if( sscanf(line, "%d.%d", &ver_maj, &ver_min)< 2 ) return FALSE; - if( ver_maj != VER_MAJOR || ver_min != VER_MINOR ) + if (ver_maj != VER_MAJOR || + ver_min > VER_MINOR || ver_min < VER_MINOR_SUPPORTED) return FALSE; /* skip the second line containing menu name */ @@ -157,7 +161,7 @@ for( i = 0, x = 0; i < n; ++i ) { int len; - GFile *gfile; + if( ! fgets( line, G_N_ELEMENTS(line), f ) ) return FALSE; @@ -165,8 +169,7 @@ if( len <= 1 ) return FALSE; files[ x ] = g_strndup( line, len - 1 ); /* don't include \n */ - gfile = g_file_new_for_path(files[x]+1); - if (g_file_query_exists(gfile, NULL)) + if (g_file_test(files[x]+1, G_FILE_TEST_EXISTS)) x++; else { @@ -174,7 +177,6 @@ g_free(files[x]); files[x] = NULL; } - g_object_unref(gfile); } *n_files = x; *used_files = files; @@ -393,9 +395,11 @@ { gboolean ret = FALSE; struct stat st; +#if 0 time_t cache_mtime; char** files; int n, i; +#endif FILE* f; f = fopen( cache_file, "r" ); @@ -403,6 +407,7 @@ { if( fstat( fileno(f), &st) == 0 ) { +#if 0 cache_mtime = st.st_mtime; if( read_all_used_files(f, &n, &files) ) { @@ -421,6 +426,9 @@ *used_files = files; } } +#else + ret = read_all_used_files(f, n_used_files, used_files); +#endif } fclose( f ); } @@ -589,6 +597,12 @@ DEBUG("regeneration of cache failed!!"); } } + else + { + /* file loaded, schedule update anyway */ + cache->delayed_reload_handler = g_timeout_add_seconds_full(G_PRIORITY_LOW, 3, + (GSourceFunc)delayed_reload, cache, NULL); + } memcpy( cache->md5, md5, 33 ); cache->n_files = n_files; cache->files = files; diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' --exclude Makefile.in --exclude configure --exclude config.guess --exclude '*.pot' --exclude mkinstalldirs --exclude aclocal.m4 --exclude config.sub --exclude depcomp --exclude install-sh --exclude ltmain.sh old/menu-cache-0.7.0/menu-cache-gen/Makefile.am new/menu-cache-1.0.0/menu-cache-gen/Makefile.am --- old/menu-cache-0.7.0/menu-cache-gen/Makefile.am 2014-09-06 18:27:45.000000000 +0200 +++ new/menu-cache-1.0.0/menu-cache-gen/Makefile.am 2014-09-28 18:00:07.000000000 +0200 @@ -1,6 +1,7 @@ NULL = -INCLUDES = \ +AM_CPPFLAGS = \ + -I$(top_builddir)/libmenu-cache \ -I$(top_srcdir)/libmenu-cache \ $(GLIB_CFLAGS) \ $(LIBFM_EXTRA_CFLAGS) \ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' --exclude Makefile.in --exclude configure --exclude config.guess --exclude '*.pot' --exclude mkinstalldirs --exclude aclocal.m4 --exclude config.sub --exclude depcomp --exclude install-sh --exclude ltmain.sh old/menu-cache-0.7.0/menu-cache-gen/menu-compose.c new/menu-cache-1.0.0/menu-cache-gen/menu-compose.c --- old/menu-cache-0.7.0/menu-cache-gen/menu-compose.c 2014-09-06 18:27:45.000000000 +0200 +++ new/menu-cache-1.0.0/menu-cache-gen/menu-compose.c 2014-09-28 18:00:07.000000000 +0200 @@ -26,6 +26,7 @@ #endif #include "menu-tags.h" +#include "version.h" #include <string.h> #include <stdio.h> @@ -35,6 +36,8 @@ static GSList *DEs = NULL; +static guint req_version = 1; /* old compatibility default */ + static void menu_app_reset(MenuApp *app) { g_free(app->filename); @@ -45,8 +48,10 @@ g_free(app->icon); g_free(app->generic_name); g_free(app->exec); + g_free(app->try_exec); g_free(app->wd); g_free(app->categories); + g_free(app->keywords); g_free(app->show_in); g_free(app->hide_in); } @@ -62,6 +67,33 @@ g_slice_free(MenuApp, app); } +static char *_escape_lf(char *str) +{ + char *c; + + if (str != NULL && (c = strchr(str, '\n')) != NULL) + { + GString *s = g_string_new_len(str, c - str); + + while (*c) + { + if (*c == '\n') + g_string_append(s, "\\n"); + else + g_string_append_c(s, *c); + c++; + } + g_free(str); + str = g_string_free(s, FALSE); + } + return str; +} + +static char *_get_string(GKeyFile *kf, const char *key) +{ + return _escape_lf(g_key_file_get_string(kf, G_KEY_FILE_DESKTOP_GROUP, key, NULL)); +} + /* g_key_file_get_locale_string is too much limited so implement replacement */ static char *_get_language_string(GKeyFile *kf, const char *key) { @@ -71,12 +103,45 @@ for (lang = languages; lang[0] != NULL; lang++) { try_key = g_strdup_printf("%s[%s]", key, lang[0]); - str = g_key_file_get_string(kf, G_KEY_FILE_DESKTOP_GROUP, try_key, NULL); + str = _get_string(kf, try_key); g_free(try_key); if (str != NULL) return str; } - return g_key_file_get_locale_string(kf, G_KEY_FILE_DESKTOP_GROUP, key, languages[0], NULL); + return _escape_lf(g_key_file_get_locale_string(kf, G_KEY_FILE_DESKTOP_GROUP, + key, languages[0], NULL)); +} + +static char **_get_string_list(GKeyFile *kf, const char *key, gsize *lp) +{ + char **str, **p; + + str = g_key_file_get_string_list(kf, G_KEY_FILE_DESKTOP_GROUP, key, lp, NULL); + if (str != NULL) + for (p = str; p[0] != NULL; p++) + p[0] = _escape_lf(p[0]); + return str; +} + +static char **_get_language_string_list(GKeyFile *kf, const char *key, gsize *lp) +{ + char **lang; + char *try_key, **str; + + for (lang = languages; lang[0] != NULL; lang++) + { + try_key = g_strdup_printf("%s[%s]", key, lang[0]); + str = _get_string_list(kf, try_key, lp); + g_free(try_key); + if (str != NULL) + return str; + } + str = g_key_file_get_locale_string_list(kf, G_KEY_FILE_DESKTOP_GROUP, key, + languages[0], lp, NULL); + if (str != NULL) + for (lang = str; lang[0] != NULL; lang++) + lang[0] = _escape_lf(lang[0]); + return str; } static void _fill_menu_from_file(MenuMenu *menu, const char *path) @@ -90,8 +155,7 @@ goto exit; menu->title = _get_language_string(kf, G_KEY_FILE_DESKTOP_KEY_NAME); menu->comment = _get_language_string(kf, G_KEY_FILE_DESKTOP_KEY_COMMENT); - menu->icon = g_key_file_get_string(kf, G_KEY_FILE_DESKTOP_GROUP, - G_KEY_FILE_DESKTOP_KEY_ICON, NULL); + menu->icon = _get_string(kf, G_KEY_FILE_DESKTOP_KEY_ICON); menu->layout.nodisplay = g_key_file_get_boolean(kf, G_KEY_FILE_DESKTOP_GROUP, G_KEY_FILE_DESKTOP_KEY_NO_DISPLAY, NULL); menu->layout.is_set = TRUE; @@ -100,12 +164,17 @@ } static const char **menu_app_intern_key_file_list(GKeyFile *kf, const char *key, + gboolean localized, gboolean add_to_des) { gsize len, i; - char **val = g_key_file_get_string_list(kf, G_KEY_FILE_DESKTOP_GROUP, key, &len, NULL); + char **val; const char **res; + if (localized) + val = _get_language_string_list(kf, key, &len); + else + val = _get_string_list(kf, key, &len); if (val == NULL) return NULL; res = (const char **)g_new(char *, len + 1); @@ -124,15 +193,18 @@ { app->title = _get_language_string(kf, G_KEY_FILE_DESKTOP_KEY_NAME); app->comment = _get_language_string(kf, G_KEY_FILE_DESKTOP_KEY_COMMENT); - app->icon = g_key_file_get_string(kf, G_KEY_FILE_DESKTOP_GROUP, - G_KEY_FILE_DESKTOP_KEY_ICON, NULL); + app->icon = _get_string(kf, G_KEY_FILE_DESKTOP_KEY_ICON); app->generic_name = _get_language_string(kf, G_KEY_FILE_DESKTOP_KEY_GENERIC_NAME); - app->exec = g_key_file_get_string(kf, G_KEY_FILE_DESKTOP_GROUP, - G_KEY_FILE_DESKTOP_KEY_EXEC, NULL); - //app->wd = - app->categories = menu_app_intern_key_file_list(kf, G_KEY_FILE_DESKTOP_KEY_CATEGORIES, FALSE); - app->show_in = menu_app_intern_key_file_list(kf, G_KEY_FILE_DESKTOP_KEY_ONLY_SHOW_IN, TRUE); - app->hide_in = menu_app_intern_key_file_list(kf, G_KEY_FILE_DESKTOP_KEY_NOT_SHOW_IN, TRUE); + app->exec = _get_string(kf, G_KEY_FILE_DESKTOP_KEY_EXEC); + app->try_exec = _get_string(kf, G_KEY_FILE_DESKTOP_KEY_TRY_EXEC); + app->wd = _get_string(kf, G_KEY_FILE_DESKTOP_KEY_PATH); + app->categories = menu_app_intern_key_file_list(kf, G_KEY_FILE_DESKTOP_KEY_CATEGORIES, + FALSE, FALSE); + app->keywords = menu_app_intern_key_file_list(kf, "Keywords", TRUE, FALSE); + app->show_in = menu_app_intern_key_file_list(kf, G_KEY_FILE_DESKTOP_KEY_ONLY_SHOW_IN, + FALSE, TRUE); + app->hide_in = menu_app_intern_key_file_list(kf, G_KEY_FILE_DESKTOP_KEY_NOT_SHOW_IN, + FALSE, TRUE); app->use_terminal = g_key_file_get_boolean(kf, G_KEY_FILE_DESKTOP_GROUP, G_KEY_FILE_DESKTOP_KEY_TERMINAL, NULL); app->use_notification = g_key_file_get_boolean(kf, G_KEY_FILE_DESKTOP_GROUP, @@ -805,8 +877,7 @@ /* do recursion */ if (_stage2(child->data, with_hidden) > 0) count++; - else - /* if (!with_hidden || req_version < 2) */ + else if (!with_hidden || req_version < 2) to_delete = g_list_prepend(to_delete, child); child = next; break; @@ -833,6 +904,8 @@ { if (menu->layout.show_empty) count++; + else + menu->layout.nodisplay = TRUE; } return count; } @@ -850,6 +923,23 @@ return x; } +static gboolean write_app_extra(FILE *f, MenuApp *app) +{ + gboolean ret; + char *cats, *keywords; + char *null_list[] = { NULL }; + + if (req_version < 2) + return TRUE; + cats = g_strjoinv(";", app->categories ? (char **)app->categories : null_list); + keywords = g_strjoinv(",", app->keywords ? (char **)app->keywords : null_list); + ret = fprintf(f, "%s\n%s\n%s\n%s\n", NONULL(app->try_exec), NONULL(app->wd), + cats, keywords) > 0; + g_free(cats); + g_free(keywords); + return ret; +} + static gboolean write_app(FILE *f, MenuApp *app, gboolean with_hidden) { int index; @@ -872,7 +962,7 @@ return fprintf(f, "-%s\n%s\n%s\n%s\n%s\n%d\n%s\n%s\n%u\n%d\n", app->id, NONULL(app->title), NONULL(app->comment), NONULL(app->icon), NONULL(app->filename), index, NONULL(app->generic_name), - NONULL(app->exec), flags, show) > 0; + NONULL(app->exec), flags, show) > 0 && write_app_extra(f, app); } static gboolean write_menu(FILE *f, MenuMenu *menu, gboolean with_hidden) @@ -883,14 +973,17 @@ if (!with_hidden && !menu->layout.show_empty && menu->children == NULL) return TRUE; - if (menu->layout.nodisplay/* && (!with_hidden || req_version < 2)*/) + if (menu->layout.nodisplay && (!with_hidden || req_version < 2)) return TRUE; index = g_slist_index(DirDirs, menu->dir); if (fprintf(f, "+%s\n%s\n%s\n%s\n%s\n%d\n", menu->name, NONULL(menu->title), NONULL(menu->comment), NONULL(menu->icon), menu->id ? (const char *)menu->id->data : "", index) < 0) return FALSE; - /* FIXME: should pass show_empty into file somehow - v.1.2 may be */ + /* pass show_empty into file if format is v.1.2 */ + if (req_version >= 2 && + fprintf(f, "%d\n", menu->layout.nodisplay ? FLAG_IS_NODISPLAY : 0) < 0) + return FALSE; for (child = menu->children; ok && child != NULL; child = child->next) { index = ((MenuApp *)child->data)->type; @@ -929,6 +1022,16 @@ int i; gboolean ok = FALSE; + tmp = (char *)g_getenv("CACHE_GEN_VERSION"); + if (sscanf(tmp, "%d.%u", &i, &req_version) == 2) + { + if (i != VER_MAJOR) /* unsupported format requested */ + return FALSE; + } + if (req_version < VER_MINOR_SUPPORTED) /* unsupported format requested */ + return FALSE; + if (req_version > VER_MINOR) /* fallback to maximal supported format */ + req_version = VER_MINOR; all_apps = g_hash_table_new_full(g_str_hash, g_str_equal, NULL, menu_app_free); for (i = 0; i < N_KNOWN_DESKTOPS; i++) DEs = g_slist_append(DEs, (gpointer)g_intern_static_string(de_names[i])); @@ -953,7 +1056,7 @@ if (f == NULL) goto failed; /* Write common data */ - fprintf(f, "1.1\n%s%s\n%d\n", /* FIXME: use CACHE_GEN_VERSION */ + fprintf(f, "1.%d\n%s%s\n%d\n", req_version, /* use CACHE_GEN_VERSION */ menuname, with_hidden ? "+hidden" : "", g_slist_length(DirDirs) + g_slist_length(AppDirs) + g_slist_length(MenuDirs) + g_slist_length(MenuFiles)); diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' --exclude Makefile.in --exclude configure --exclude config.guess --exclude '*.pot' --exclude mkinstalldirs --exclude aclocal.m4 --exclude config.sub --exclude depcomp --exclude install-sh --exclude ltmain.sh old/menu-cache-0.7.0/menu-cache-gen/menu-tags.h new/menu-cache-1.0.0/menu-cache-gen/menu-tags.h --- old/menu-cache-0.7.0/menu-cache-gen/menu-tags.h 2014-09-06 18:27:45.000000000 +0200 +++ new/menu-cache-1.0.0/menu-cache-gen/menu-tags.h 2014-09-28 18:00:07.000000000 +0200 @@ -137,8 +137,10 @@ char *icon; char *generic_name; char *exec; + char *try_exec; char *wd; const char **categories; /* all char ** keep interned values */ + const char **keywords; const char **show_in; const char **hide_in; } MenuApp; -- To unsubscribe, e-mail: opensuse-commit+unsubscr...@opensuse.org For additional commands, e-mail: opensuse-commit+h...@opensuse.org