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

Reply via email to