[Xfce4-commits] <xfce4-appfinder:master> Initial work on xfce4-appfinder and xfrun4 merge.

Nick Schermer noreply at xfce.org
Sat Jul 9 16:18:01 CEST 2011


Updating branch refs/heads/master
         to e3c64d41664e1ef70c88987fe5d970955c6a7587 (commit)
       from 296cd0521239742e0e9a5d48a4157c9afbd3c459 (commit)

commit e3c64d41664e1ef70c88987fe5d970955c6a7587
Author: Nick Schermer <nick at xfce.org>
Date:   Mon Jun 6 20:43:58 2011 +0200

    Initial work on xfce4-appfinder and xfrun4 merge.
    
    Import the work from the design repository.

 AUTHORS                                            |    1 +
 Makefile.am                                        |    9 +-
 autogen.sh                                         |   19 +-
 configure.in.in => configure.ac.in                 |   17 +-
 data/Makefile.am                                   |   26 +-
 data/xfce4-appfinder.desktop.in                    |    8 +-
 data/xfce4-appfinder.png                           |  Bin 4003 -> 0 bytes
 data/xfce4-run.desktop.in                          |   11 +
 po/POTFILES.in                                     |   11 +-
 src/Makefile.am                                    |   67 +-
 src/appfinder-category-model.c                     |  453 +++++++
 src/appfinder-category-model.h                     |   60 +
 src/appfinder-model.c                              | 1250 ++++++++++++++++++++
 src/appfinder-model.h                              |   89 ++
 src/appfinder-window.c                             |  780 ++++++++++++
 ...{xfce-appfinder-window.h => appfinder-window.h} |   33 +-
 src/frap-icon-entry.c                              |  590 ---------
 src/frap-icon-entry.h                              |   64 -
 src/main.c                                         |  126 +-
 src/xfce-appfinder-window.c                        | 1154 ------------------
 xfce4-appfinder.spec.in                            |   49 -
 21 files changed, 2801 insertions(+), 2016 deletions(-)

diff --git a/AUTHORS b/AUTHORS
index cfcd495..e4fc2e7 100644
--- a/AUTHORS
+++ b/AUTHORS
@@ -1,2 +1,3 @@
 Jannis Pohlmann <jannis at xfce.org>
 Jasper Huijsmans <jasper at xfce.org>
+Nick Schermer <nick at xfce.org>
diff --git a/Makefile.am b/Makefile.am
index 5dcc1fb..5f3fcfe 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -1,16 +1,15 @@
- at SET_MAKE@
 
-SUBDIRS = src data po
+SUBDIRS = \
+	src \
+	data \
+	po
 
 EXTRA_DIST = \
-	TODO \
-	xfce4-appfinder.spec \
 	intltool-extract.in \
 	intltool-merge.in \
 	intltool-update.in
 
 DISTCLEANFILES = \
-	xfce4-appfinder.spec \
 	intltool-extract \
 	intltool-merge \
 	intltool-update
diff --git a/autogen.sh b/autogen.sh
index eaead8c..99e44a9 100755
--- a/autogen.sh
+++ b/autogen.sh
@@ -1,13 +1,26 @@
 #!/bin/sh
 #
-# $Id$
+# Copyright (c) 2002-2011 The Xfce development team. All rights reserved.
 #
-# Copyright (c) 2002-2008
-#         The Xfce development team. All rights reserved.
+# 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 program 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.
+#
+# 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.
 #
 # Written for Xfce by Benedikt Meurer <benny at xfce.org>.
 #
 
+
+
 (type xdt-autogen) >/dev/null 2>&1 || {
   cat >&2 <<EOF
 autogen.sh: You don't seem to have the Xfce development tools installed on
diff --git a/configure.in.in b/configure.ac.in
similarity index 88%
rename from configure.in.in
rename to configure.ac.in
index 355b9c1..c65d770 100644
--- a/configure.in.in
+++ b/configure.ac.in
@@ -1,13 +1,12 @@
-dnl $Id$
 dnl
-dnl Copyright (c) 2008-2011 - Jannis Pohlmann <jannis at xfce.org>
+dnl Copyright (c) 2008-2011 - The Xfce Development Team.
 dnl
 
 dnl ***************************
 dnl *** Version information ***
 dnl ***************************
 m4_define([xfce4_appfinder_version_major], [4])
-m4_define([xfce4_appfinder_version_minor], [8])
+m4_define([xfce4_appfinder_version_minor], [9])
 m4_define([xfce4_appfinder_version_micro], [0])
 m4_define([xfce4_appfinder_version_nano],  []) dnl leave this empty to have no nano version
 m4_define([xfce4_appfinder_version_build], [@REVISION@])
@@ -61,6 +60,7 @@ dnl **********************************
 dnl *** Check for standard headers ***
 dnl **********************************
 AC_HEADER_STDC()
+AC_CHECK_HEADERS([stdlib.h string.h])
 
 dnl ******************************
 dnl *** Check for i18n support ***
@@ -70,14 +70,12 @@ XDT_I18N([@LINGUAS@])
 dnl ***********************************
 dnl *** Check for required packages ***
 dnl ***********************************
-XDT_CHECK_PACKAGE([GLIB], [glib-2.0], [2.16.0])
-XDT_CHECK_PACKAGE([GTHREAD], [gthread-2.0], [2.16.0])
-XDT_CHECK_PACKAGE([GTK], [gtk+-2.0], [2.14.0])
+XDT_CHECK_PACKAGE([GLIB], [glib-2.0], [2.23.0])
+XDT_CHECK_PACKAGE([GTHREAD], [gthread-2.0], [2.23.0])
+XDT_CHECK_PACKAGE([GTK], [gtk+-2.0], [2.20.0])
 XDT_CHECK_PACKAGE([LIBXFCE4UTIL], [libxfce4util-1.0], [4.8.0])
 XDT_CHECK_PACKAGE([LIBXFCE4UI], [libxfce4ui-1], [4.8.0])
-XDT_CHECK_PACKAGE([GARCON], [garcon-1], [0.1.2])
-XDT_CHECK_PACKAGE([LIBXFCONF], [libxfconf-0], [4.8.0])
-XDT_CHECK_PACKAGE([GIO], [gio-2.0], [2.16.0])
+XDT_CHECK_PACKAGE([GARCON], [garcon-1], [0.1.7])
 
 dnl ***********************************
 dnl *** Check for debugging support ***
@@ -107,7 +105,6 @@ Makefile
 data/Makefile
 src/Makefile
 po/Makefile.in
-xfce4-appfinder.spec
 ])
 
 dnl ***************************
diff --git a/data/Makefile.am b/data/Makefile.am
index 523195b..2d232b4 100644
--- a/data/Makefile.am
+++ b/data/Makefile.am
@@ -1,25 +1,15 @@
+
 appsdir = $(datadir)/applications
-apps_in_files = xfce4-appfinder.desktop.in
+apps_in_files = \
+	xfce4-appfinder.desktop.in \
+	xfce4-run.desktop.in
 apps_DATA = $(apps_in_files:.desktop.in=.desktop)
 @INTLTOOL_DESKTOP_RULE@
 
-icondir = $(datadir)/icons/hicolor/48x48/apps
-icon_DATA = xfce4-appfinder.png
-
-EXTRA_DIST = $(icon_DATA) $(apps_in_files)
-DISTCLEANFILES = $(apps_DATA)
-
-gtk_update_icon_cache = gtk-update-icon-cache -f -t $(datadir)/icons/hicolor
+EXTRA_DIST = \
+	$(apps_in_files)
 
-install-data-hook:
-	@-if test -z "$(DESTDIR)"; then                                 \
-                echo "Updating Gtk icon cache.";                        \
-                $(gtk_update_icon_cache);                               \
-        else                                                            \
-                echo "*** Icon cache not updated. Remember to run:";    \
-                echo "***";                                             \
-                echo "***   $(gtk_update_icon_cache)";                  \
-                echo "***";                                             \
-        fi
+DISTCLEANFILES = \
+	$(apps_DATA)
 
 # vi:set ts=8 sw=8 noet ai nocindent:
diff --git a/data/xfce4-appfinder.desktop.in b/data/xfce4-appfinder.desktop.in
index f607e69..f79f952 100644
--- a/data/xfce4-appfinder.desktop.in
+++ b/data/xfce4-appfinder.desktop.in
@@ -1,10 +1,10 @@
 [Desktop Entry]
 Version=1.0
-_Name=Application Finder
-_Comment=Find and launch applications installed on your system
-Exec=xfce4-appfinder
-Icon=xfce4-appfinder
+Exec=xfce4-appfinder --finder
+Icon=gtk-find
 StartupNotify=true
 Terminal=false
 Type=Application
 Categories=X-XFCE;Utility;
+_Name=Application Finder
+_Comment=Find and launch applications installed on your system
diff --git a/data/xfce4-appfinder.png b/data/xfce4-appfinder.png
deleted file mode 100644
index 07a4da7..0000000
Binary files a/data/xfce4-appfinder.png and /dev/null differ
diff --git a/data/xfce4-run.desktop.in b/data/xfce4-run.desktop.in
new file mode 100644
index 0000000..72b5012
--- /dev/null
+++ b/data/xfce4-run.desktop.in
@@ -0,0 +1,11 @@
+[Desktop Entry]
+Version=1.0
+Type=Application
+Exec=xfce4-appfinder
+Icon=gtk-execute
+StartupNotify=true
+Terminal=false
+Categories=Utility;X-XFCE;X-Xfce-Toplevel;
+OnlyShowIn=XFCE;
+_Name=Run Program...
+_Comment=Run a program
diff --git a/po/POTFILES.in b/po/POTFILES.in
index aea7808..657c887 100644
--- a/po/POTFILES.in
+++ b/po/POTFILES.in
@@ -1,9 +1,8 @@
-# List of source files containing translatable strings.
+
+src/appfinder-category-model.c
+src/appfinder-model.c
+src/appfinder-window.c
 src/main.c
-src/xfce-appfinder-window.c
-src/xfce-appfinder-window.h
-src/frap-icon-entry.c
-src/frap-icon-entry.h
 
-# .desktop files
 data/xfce4-appfinder.desktop.in
+data/xfce4-run.desktop.in
diff --git a/src/Makefile.am b/src/Makefile.am
index caa542f..b32ae27 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -1,38 +1,39 @@
-# $Id$
 # vi:set ts=8 sw=8 noet ai nocindent syntax=automake:
 
-bin_PROGRAMS =								\
-	xfce4-appfinder
+INCLUDES = \
+	-I$(top_srcdir) \
+	-DPACKAGE_LOCALE_DIR=\"$(localedir)\" \
+	-DG_LOG_DOMAIN=\"xfce4-appfinder\" \
+	$(PLATFORM_CPPFLAGS)
 
-xfce4_appfinder_SOURCES =						\
-	main.c								\
-	xfce-appfinder-window.h						\
-	xfce-appfinder-window.c						\
-	frap-icon-entry.h						\
-	frap-icon-entry.c
+bin_PROGRAMS = xfce4-appfinder
 
-xfce4_appfinder_CFLAGS = 						\
-	-I$(top_builddir)						\
-	-I$(top_srcdir)							\
-	-DPACKAGE_LOCALE_DIR=\"$(localedir)\"				\
-	-DDATADIR=\"$(datadir)\"					\
-	-DG_LOG_DOMAIN=\"xfce4-appfinder\"				\
-	$(PLATFORM_CFLAGS)						\
-	$(GLIB_CFLAGS)							\
-	$(GTK_CFLAGS)							\
-	$(LIBXFCE4UTIL_CFLAGS)						\
-	$(LIBXFCE4UI_CFLAGS)						\
-	$(GARCON_CFLAGS)						\
-	$(LIBXFCONF_CFLAGS)						\
-	$(GIO_CFLAGS)
+xfce4_appfinder_SOURCES = \
+	appfinder-category-model.c \
+	appfinder-category-model.h \
+	appfinder-model.c \
+	appfinder-model.h \
+	appfinder-window.c \
+	appfinder-window.h \
+	main.c
 
-xfce4_appfinder_LDFLAGS = 						\
-	$(PLATFORM_LIBS)						\
-	$(GLIB_LIBS)							\
-	$(GTHREAD_LIBS)							\
-	$(GTK_LIBS)							\
-	$(LIBXFCE4UTIL_LIBS)						\
-	$(LIBXFCE4UI_LIBS)						\
-	$(GARCON_LIBS)							\
-	$(LIBXFCONF_LIBS)						\
-	$(GIO_LIBS)
+xfce4_appfinder_CFLAGS = \
+	$(GTHREAD_CFLAGS) \
+	$(GTK_CFLAGS) \
+	$(LIBXFCE4UTIL_CFLAGS) \
+	$(LIBXFCE4UI_CFLAGS) \
+	$(GARCON_CFLAGS) \
+	$(PLATFORM_CFLAGS)
+
+xfce4_appfinder_LDADD = \
+	$(GLIB_LIBS) \
+	$(GTHREAD_LIBS) \
+	$(GTK_LIBS) \
+	$(LIBXFCE4UTIL_LIBS) \
+	$(LIBXFCE4UI_LIBS) \
+	$(GARCON_LIBS) \
+	$(LIBXFCONF_LIBS)
+
+xfce4_appfinder_LDFLAGS = \
+	-no-undefined \
+	$(PLATFORM_LDFLAGS)
diff --git a/src/appfinder-category-model.c b/src/appfinder-category-model.c
new file mode 100644
index 0000000..781dda8
--- /dev/null
+++ b/src/appfinder-category-model.c
@@ -0,0 +1,453 @@
+/*
+ * Copyright (C) 2011 Nick Schermer <nick at xfce.org>
+ *
+ * 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 program 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.
+ *
+ * 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.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#ifdef HAVE_STRING_H
+#include <string.h>
+#endif
+
+#include <libxfce4util/libxfce4util.h>
+#include <garcon/garcon.h>
+
+#include <src/appfinder-model.h>
+#include <src/appfinder-category-model.h>
+
+
+
+static void               xfce_appfinder_category_model_tree_model_init       (GtkTreeModelIface        *iface);
+static void               xfce_appfinder_category_model_finalize              (GObject                  *object);
+static GtkTreeModelFlags  xfce_appfinder_category_model_get_flags             (GtkTreeModel             *tree_model);
+static gint               xfce_appfinder_category_model_get_n_columns         (GtkTreeModel             *tree_model);
+static GType              xfce_appfinder_category_model_get_column_type       (GtkTreeModel             *tree_model,
+                                                                               gint                      column);
+static gboolean           xfce_appfinder_category_model_get_iter              (GtkTreeModel             *tree_model,
+                                                                               GtkTreeIter              *iter,
+                                                                               GtkTreePath              *path);
+static GtkTreePath       *xfce_appfinder_category_model_get_path              (GtkTreeModel             *tree_model,
+                                                                               GtkTreeIter              *iter);
+static void               xfce_appfinder_category_model_get_value             (GtkTreeModel             *tree_model,
+                                                                               GtkTreeIter              *iter,
+                                                                               gint                      column,
+                                                                               GValue                   *value);
+static gboolean           xfce_appfinder_category_model_iter_next             (GtkTreeModel             *tree_model,
+                                                                               GtkTreeIter              *iter);
+static gboolean           xfce_appfinder_category_model_iter_children         (GtkTreeModel             *tree_model,
+                                                                               GtkTreeIter              *iter,
+                                                                               GtkTreeIter              *parent);
+static gboolean           xfce_appfinder_category_model_iter_has_child        (GtkTreeModel             *tree_model,
+                                                                               GtkTreeIter              *iter);
+static gint               xfce_appfinder_category_model_iter_n_children       (GtkTreeModel             *tree_model,
+                                                                               GtkTreeIter              *iter);
+static gboolean           xfce_appfinder_category_model_iter_nth_child        (GtkTreeModel             *tree_model,
+                                                                               GtkTreeIter              *iter,
+                                                                               GtkTreeIter              *parent,
+                                                                               gint                      n);
+static gboolean           xfce_appfinder_category_model_iter_parent           (GtkTreeModel             *tree_model,
+                                                                               GtkTreeIter              *iter,
+                                                                               GtkTreeIter              *child);
+static void               xfce_appfinder_category_item_free                   (gpointer                  data);
+
+
+
+struct _XfceAppfinderCategoryModelClass
+{
+  GObjectClass __parent__;
+};
+
+struct _XfceAppfinderCategoryModel
+{
+  GObject            __parent__;
+  gint               stamp;
+
+  GSList *categories;
+};
+
+typedef struct
+{
+  GarconMenuDirectory *directory;
+  GdkPixbuf           *pixbuf;
+}
+Categoryitem;
+
+
+
+G_DEFINE_TYPE_WITH_CODE (XfceAppfinderCategoryModel, xfce_appfinder_category_model, G_TYPE_OBJECT,
+    G_IMPLEMENT_INTERFACE (GTK_TYPE_TREE_MODEL, xfce_appfinder_category_model_tree_model_init))
+
+
+
+static void
+xfce_appfinder_category_model_class_init (XfceAppfinderCategoryModelClass *klass)
+{
+  GObjectClass *gobject_class;
+
+  gobject_class = G_OBJECT_CLASS (klass);
+  gobject_class->finalize = xfce_appfinder_category_model_finalize;
+}
+
+
+
+static void
+xfce_appfinder_category_model_init (XfceAppfinderCategoryModel *model)
+{
+  Categoryitem *item;
+
+  /* generate a unique stamp */
+  model->stamp = g_random_int ();
+
+    /* separator */
+  item = g_slice_new0 (Categoryitem);
+  model->categories = g_slist_prepend (model->categories, item);
+
+  item = g_slice_new0 (Categoryitem);
+  item->directory = g_object_new (GARCON_TYPE_MENU_DIRECTORY,
+                                  "name", _("Commands History"),
+                                  "icon-name", GTK_STOCK_EXECUTE,
+                                  NULL);
+  model->categories = g_slist_prepend (model->categories, item);
+
+  item = g_slice_new0 (Categoryitem);
+  item->directory = g_object_new (GARCON_TYPE_MENU_DIRECTORY,
+                                  "name", _("All Applications"),
+                                  "icon-name", "applications-other",
+                                  NULL);
+  model->categories = g_slist_prepend (model->categories, item);
+}
+
+
+
+static void
+xfce_appfinder_category_model_tree_model_init (GtkTreeModelIface *iface)
+{
+  iface->get_flags = xfce_appfinder_category_model_get_flags;
+  iface->get_n_columns = xfce_appfinder_category_model_get_n_columns;
+  iface->get_column_type = xfce_appfinder_category_model_get_column_type;
+  iface->get_iter = xfce_appfinder_category_model_get_iter;
+  iface->get_path = xfce_appfinder_category_model_get_path;
+  iface->get_value = xfce_appfinder_category_model_get_value;
+  iface->iter_next = xfce_appfinder_category_model_iter_next;
+  iface->iter_children = xfce_appfinder_category_model_iter_children;
+  iface->iter_has_child = xfce_appfinder_category_model_iter_has_child;
+  iface->iter_n_children = xfce_appfinder_category_model_iter_n_children;
+  iface->iter_nth_child = xfce_appfinder_category_model_iter_nth_child;
+  iface->iter_parent = xfce_appfinder_category_model_iter_parent;
+}
+
+
+
+static void
+xfce_appfinder_category_model_finalize (GObject *object)
+{
+  XfceAppfinderCategoryModel *model = XFCE_APPFINDER_CATEGORY_MODEL (object);
+
+  g_slist_foreach (model->categories, (GFunc) xfce_appfinder_category_item_free, NULL);
+  g_slist_free (model->categories);
+
+  (*G_OBJECT_CLASS (xfce_appfinder_category_model_parent_class)->finalize) (object);
+}
+
+
+
+static GtkTreeModelFlags
+xfce_appfinder_category_model_get_flags (GtkTreeModel *tree_model)
+{
+  return GTK_TREE_MODEL_ITERS_PERSIST | GTK_TREE_MODEL_LIST_ONLY;
+}
+
+
+
+static gint
+xfce_appfinder_category_model_get_n_columns (GtkTreeModel *tree_model)
+{
+  return XFCE_APPFINDER_CATEGORY_MODEL_N_COLUMNS;
+}
+
+
+
+static GType
+xfce_appfinder_category_model_get_column_type (GtkTreeModel *tree_model,
+                                               gint          column)
+{
+  switch (column)
+    {
+    case XFCE_APPFINDER_CATEGORY_MODEL_COLUMN_NAME:
+      return G_TYPE_STRING;
+
+    case XFCE_APPFINDER_CATEGORY_MODEL_COLUMN_ICON:
+      return GDK_TYPE_PIXBUF;
+
+    default:
+      g_assert_not_reached ();
+      return G_TYPE_INVALID;
+    }
+}
+
+
+
+static gboolean
+xfce_appfinder_category_model_get_iter (GtkTreeModel *tree_model,
+                                        GtkTreeIter  *iter,
+                                        GtkTreePath  *path)
+{
+  XfceAppfinderCategoryModel *model = XFCE_APPFINDER_CATEGORY_MODEL (tree_model);
+
+  g_return_val_if_fail (XFCE_IS_APPFINDER_CATEGORY_MODEL (model), FALSE);
+  g_return_val_if_fail (gtk_tree_path_get_depth (path) > 0, FALSE);
+
+  iter->stamp = model->stamp;
+  iter->user_data = g_slist_nth (model->categories, gtk_tree_path_get_indices (path)[0]);
+
+  return (iter->user_data != NULL);
+}
+
+
+
+static GtkTreePath*
+xfce_appfinder_category_model_get_path (GtkTreeModel *tree_model,
+                                        GtkTreeIter  *iter)
+{
+  XfceAppfinderCategoryModel *model = XFCE_APPFINDER_CATEGORY_MODEL (tree_model);
+  gint                        idx;
+
+  g_return_val_if_fail (XFCE_IS_APPFINDER_CATEGORY_MODEL (model), NULL);
+  g_return_val_if_fail (iter->stamp == model->stamp, NULL);
+
+  /* determine the index of the iter */
+  idx = g_slist_position (model->categories, iter->user_data);
+  if (G_UNLIKELY (idx < 0))
+    return NULL;
+
+  return gtk_tree_path_new_from_indices (idx, -1);
+}
+
+
+
+static void
+xfce_appfinder_category_model_get_value (GtkTreeModel *tree_model,
+                                         GtkTreeIter  *iter,
+                                         gint          column,
+                                         GValue       *value)
+{
+  XfceAppfinderCategoryModel *model = XFCE_APPFINDER_CATEGORY_MODEL (tree_model);
+  Categoryitem               *item;
+  const gchar                *icon_name;
+
+  g_return_if_fail (XFCE_IS_APPFINDER_CATEGORY_MODEL (model));
+  g_return_if_fail (iter->stamp == model->stamp);
+
+  item = ITER_GET_DATA (iter);
+  g_return_if_fail (item->directory == NULL || GARCON_IS_MENU_DIRECTORY (item->directory));
+
+  switch (column)
+    {
+    case XFCE_APPFINDER_CATEGORY_MODEL_COLUMN_NAME:
+      g_value_init (value, G_TYPE_STRING);
+      if (item->directory != NULL)
+        g_value_set_static_string (value, garcon_menu_directory_get_name (item->directory));
+      break;
+
+    case XFCE_APPFINDER_CATEGORY_MODEL_COLUMN_ICON:
+      if (item->pixbuf == NULL
+          && item->directory != NULL)
+        {
+          icon_name = garcon_menu_directory_get_icon_name (item->directory);
+          item->pixbuf = xfce_appfinder_model_load_pixbuf (icon_name, 24);
+        }
+
+      g_value_init (value, GDK_TYPE_PIXBUF);
+      g_value_set_object (value, item->pixbuf);
+      break;
+
+    default:
+      g_assert_not_reached ();
+      break;
+    }
+}
+
+
+
+static gboolean
+xfce_appfinder_category_model_iter_next (GtkTreeModel *tree_model,
+                                         GtkTreeIter  *iter)
+{
+  g_return_val_if_fail (XFCE_IS_APPFINDER_CATEGORY_MODEL (tree_model), FALSE);
+  g_return_val_if_fail (iter->stamp == XFCE_APPFINDER_CATEGORY_MODEL (tree_model)->stamp, FALSE);
+
+  iter->user_data = g_slist_next (iter->user_data);
+  return (iter->user_data != NULL);
+}
+
+
+
+static gboolean
+xfce_appfinder_category_model_iter_children (GtkTreeModel *tree_model,
+                                             GtkTreeIter  *iter,
+                                             GtkTreeIter  *parent)
+{
+  XfceAppfinderCategoryModel *model = XFCE_APPFINDER_CATEGORY_MODEL (tree_model);
+
+  g_return_val_if_fail (XFCE_IS_APPFINDER_CATEGORY_MODEL (model), FALSE);
+
+  if (G_LIKELY (parent == NULL && model->categories != NULL))
+    {
+      iter->stamp = model->stamp;
+      iter->user_data = model->categories;
+      return TRUE;
+    }
+
+  return FALSE;
+}
+
+
+
+static gboolean
+xfce_appfinder_category_model_iter_has_child (GtkTreeModel *tree_model,
+                                              GtkTreeIter  *iter)
+{
+  return FALSE;
+}
+
+
+
+static gint
+xfce_appfinder_category_model_iter_n_children (GtkTreeModel *tree_model,
+                                               GtkTreeIter  *iter)
+{
+  XfceAppfinderCategoryModel *model = XFCE_APPFINDER_CATEGORY_MODEL (tree_model);
+
+  g_return_val_if_fail (XFCE_IS_APPFINDER_CATEGORY_MODEL (model), 0);
+
+  return (iter == NULL) ? g_slist_length (model->categories) : 0;
+}
+
+
+
+static gboolean
+xfce_appfinder_category_model_iter_nth_child (GtkTreeModel *tree_model,
+                                              GtkTreeIter  *iter,
+                                              GtkTreeIter  *parent,
+                                              gint          n)
+{
+  XfceAppfinderCategoryModel *model = XFCE_APPFINDER_CATEGORY_MODEL (tree_model);
+
+  g_return_val_if_fail (XFCE_IS_APPFINDER_CATEGORY_MODEL (model), FALSE);
+
+  if (G_LIKELY (parent != NULL))
+    {
+      iter->stamp = model->stamp;
+      iter->user_data = g_slist_nth (model->categories, n);
+      return (iter->user_data != NULL);
+    }
+
+  return FALSE;
+}
+
+
+
+static gboolean
+xfce_appfinder_category_model_iter_parent (GtkTreeModel *tree_model,
+                                           GtkTreeIter  *iter,
+                                           GtkTreeIter  *child)
+{
+  return FALSE;
+}
+
+
+
+static void
+xfce_appfinder_category_item_free (gpointer data)
+{
+  Categoryitem *item = data;
+
+  if (item->directory != NULL)
+    g_object_unref (G_OBJECT (item->directory));
+  if (item->pixbuf != NULL)
+    g_object_unref (G_OBJECT (item->pixbuf));
+  g_slice_free (Categoryitem, item);
+}
+
+
+
+XfceAppfinderCategoryModel *
+xfce_appfinder_category_model_new (void)
+{
+  return g_object_new (XFCE_TYPE_APPFINDER_CATEGORY_MODEL, NULL);
+}
+
+
+
+void
+xfce_appfinder_category_model_set_categories (XfceAppfinderCategoryModel *model,
+                                              GSList                     *categories)
+{
+  Categoryitem *item;
+  GSList       *li, *lnext;
+  gint          idx;
+  GtkTreePath  *path;
+  GtkTreeIter   iter;
+
+  g_debug ("insert %d categories", g_slist_length (categories));
+
+  /* remove shortcuts after hard-coded before inserting */
+  li = g_slist_nth (model->categories, 3);
+  for (idx = 3; li != NULL; li = lnext, idx++)
+    {
+      lnext = li->next;
+      item = li->data;
+
+      model->categories = g_slist_delete_link (model->categories, li);
+
+      path = gtk_tree_path_new_from_indices (idx, -1);
+      gtk_tree_model_row_deleted (GTK_TREE_MODEL (model), path);
+      gtk_tree_path_free (path);
+
+      xfce_appfinder_category_item_free (item);
+    }
+
+  /* insert after the hard-coded items */
+  for (li = categories, idx = 3; li != NULL; li = li->next, idx++)
+    {
+      g_return_if_fail (GARCON_IS_MENU_DIRECTORY (li->data));
+
+      item = g_slice_new0 (Categoryitem);
+      item->directory = g_object_ref (G_OBJECT (li->data));
+      model->categories = g_slist_append (model->categories, item);
+
+      path = gtk_tree_path_new_from_indices (idx, -1);
+      gtk_tree_model_get_iter (GTK_TREE_MODEL (model), &iter, path);
+      gtk_tree_model_row_inserted (GTK_TREE_MODEL (model), path, &iter);
+      gtk_tree_path_free (path);
+    }
+}
+
+
+
+gboolean
+xfce_appfinder_category_model_row_separator_func (GtkTreeModel *tree_model,
+                                                  GtkTreeIter  *iter,
+                                                  gpointer      user_data)
+{
+  Categoryitem *item = ITER_GET_DATA (iter);
+
+  g_return_val_if_fail (XFCE_IS_APPFINDER_CATEGORY_MODEL (tree_model), FALSE);
+
+  return (item->directory == NULL);
+}
diff --git a/src/appfinder-category-model.h b/src/appfinder-category-model.h
new file mode 100644
index 0000000..73ffdf5
--- /dev/null
+++ b/src/appfinder-category-model.h
@@ -0,0 +1,60 @@
+/*
+ * Copyright (C) 2011 Nick Schermer <nick at xfce.org>
+ *
+ * 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 program 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.
+ *
+ * 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.
+ */
+
+#ifndef __XFCE_APPFINDER_CATEGORY_MODEL_H__
+#define __XFCE_APPFINDER_CATEGORY_MODEL_H__
+
+#include <gtk/gtk.h>
+
+G_BEGIN_DECLS
+
+typedef struct _XfceAppfinderCategoryModelClass XfceAppfinderCategoryModelClass;
+typedef struct _XfceAppfinderCategoryModel      XfceAppfinderCategoryModel;
+
+#define XFCE_TYPE_APPFINDER_CATEGORY_MODEL            (xfce_appfinder_category_model_get_type ())
+#define XFCE_APPFINDER_CATEGORY_MODEL(obj)            (G_TYPE_CHECK_INSTANCE_CAST ((obj), XFCE_TYPE_APPFINDER_CATEGORY_MODEL, XfceAppfinderCategoryModel))
+#define XFCE_APPFINDER_CATEGORY_MODEL_CLASS(klass)    (G_TYPE_CHECK_CLASS_CAST ((klass), XFCE_TYPE_APPFINDER_CATEGORY_MODEL, XfceAppfinderCategoryModelClass))
+#define XFCE_IS_APPFINDER_CATEGORY_MODEL(obj)         (G_TYPE_CHECK_INSTANCE_TYPE ((obj), XFCE_TYPE_APPFINDER_CATEGORY_MODEL))
+#define XFCE_IS_APPFINDER_CATEGORY_MODEL_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), XFCE_TYPE_APPFINDER_CATEGORY_MODEL))
+#define XFCE_APPFINDER_CATEGORY_MODEL_GET_CLASS(obj)  (G_TYPE_INSTANCE_GET_CLASS ((obj), XFCE_TYPE_APPFINDER_CATEGORY_MODEL, XfceAppfinderCategoryModelClass))
+
+
+
+enum
+{
+  XFCE_APPFINDER_CATEGORY_MODEL_COLUMN_NAME,
+  XFCE_APPFINDER_CATEGORY_MODEL_COLUMN_ICON,
+  XFCE_APPFINDER_CATEGORY_MODEL_N_COLUMNS,
+};
+
+
+
+GType                       xfce_appfinder_category_model_get_type           (void) G_GNUC_CONST;
+
+XfceAppfinderCategoryModel *xfce_appfinder_category_model_new                (void) G_GNUC_MALLOC;
+
+void                        xfce_appfinder_category_model_set_categories     (XfceAppfinderCategoryModel *model,
+                                                                              GSList                     *categories);
+
+gboolean                    xfce_appfinder_category_model_row_separator_func (GtkTreeModel               *tree_model,
+                                                                              GtkTreeIter                *iter,
+                                                                              gpointer                    user_data);
+
+G_END_DECLS
+
+#endif /* !__XFCE_APPFINDER_CATEGORY_MODEL_H__ */
diff --git a/src/appfinder-model.c b/src/appfinder-model.c
new file mode 100644
index 0000000..dd96a93
--- /dev/null
+++ b/src/appfinder-model.c
@@ -0,0 +1,1250 @@
+/*
+ * Copyright (C) 2011 Nick Schermer <nick at xfce.org>
+ *
+ * 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 program 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.
+ *
+ * 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.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#ifdef HAVE_STRING_H
+#include <string.h>
+#endif
+
+#include <libxfce4util/libxfce4util.h>
+#include <libxfce4ui/libxfce4ui.h>
+#include <garcon/garcon.h>
+
+#include <src/appfinder-model.h>
+
+
+
+#define HISTORY_PATH "xfce4/xfce4-appfinder/history"
+
+
+
+static void               xfce_appfinder_model_tree_model_init       (GtkTreeModelIface        *iface);
+static void               xfce_appfinder_model_finalize              (GObject                  *object);
+static GtkTreeModelFlags  xfce_appfinder_model_get_flags             (GtkTreeModel             *tree_model);
+static gint               xfce_appfinder_model_get_n_columns         (GtkTreeModel             *tree_model);
+static GType              xfce_appfinder_model_get_column_type       (GtkTreeModel             *tree_model,
+                                                                      gint                      column);
+static gboolean           xfce_appfinder_model_get_iter              (GtkTreeModel             *tree_model,
+                                                                      GtkTreeIter              *iter,
+                                                                      GtkTreePath              *path);
+static GtkTreePath       *xfce_appfinder_model_get_path              (GtkTreeModel             *tree_model,
+                                                                      GtkTreeIter              *iter);
+static void               xfce_appfinder_model_get_value             (GtkTreeModel             *tree_model,
+                                                                      GtkTreeIter              *iter,
+                                                                      gint                      column,
+                                                                      GValue                   *value);
+static gboolean           xfce_appfinder_model_iter_next             (GtkTreeModel             *tree_model,
+                                                                      GtkTreeIter              *iter);
+static gboolean           xfce_appfinder_model_iter_children         (GtkTreeModel             *tree_model,
+                                                                      GtkTreeIter              *iter,
+                                                                      GtkTreeIter              *parent);
+static gboolean           xfce_appfinder_model_iter_has_child        (GtkTreeModel             *tree_model,
+                                                                      GtkTreeIter              *iter);
+static gint               xfce_appfinder_model_iter_n_children       (GtkTreeModel             *tree_model,
+                                                                      GtkTreeIter              *iter);
+static gboolean           xfce_appfinder_model_iter_nth_child        (GtkTreeModel             *tree_model,
+                                                                      GtkTreeIter              *iter,
+                                                                      GtkTreeIter              *parent,
+                                                                      gint                      n);
+static gboolean           xfce_appfinder_model_iter_parent           (GtkTreeModel             *tree_model,
+                                                                      GtkTreeIter              *iter,
+                                                                      GtkTreeIter              *child);
+static gpointer           xfce_appfinder_model_collect_thread        (gpointer                  user_data);
+static void               xfce_appfinder_model_item_free             (gpointer                  data);
+
+
+
+struct _XfceAppfinderModelClass
+{
+  GObjectClass __parent__;
+};
+
+struct _XfceAppfinderModel
+{
+  GObject            __parent__;
+  gint               stamp;
+
+  GSList            *items;
+  GHashTable        *items_hash;
+  GarconMenu        *menu;
+
+  GdkPixbuf         *command_icon_small;
+  GdkPixbuf         *command_icon_large;
+
+  gchar             *filter_category;
+  gchar             *filter_string;
+  guint              filter_idle_id;
+
+  guint              collect_idle_id;
+  GSList            *collect_items;
+  GSList            *collect_categories;
+  GThread           *collect_thread;
+  volatile gboolean  collect_cancelled;
+  GHashTable        *collect_desktop_ids;
+};
+
+typedef struct
+{
+  GarconMenuItem *item;
+  gchar          *key;
+  gchar          *abstract;
+  GPtrArray      *categories;
+  gchar          *command;
+  gchar          *tooltip;
+  guint           visible : 1;
+
+  GdkPixbuf      *icon_small;
+  GdkPixbuf      *icon_large;
+}
+ModelItem;
+
+enum
+{
+  CATEGORIES_CHANGED,
+  LAST_SIGNAL
+};
+
+
+
+static guint    model_signals[LAST_SIGNAL];
+
+
+
+G_DEFINE_TYPE_WITH_CODE (XfceAppfinderModel, xfce_appfinder_model, G_TYPE_OBJECT,
+    G_IMPLEMENT_INTERFACE (GTK_TYPE_TREE_MODEL, xfce_appfinder_model_tree_model_init))
+
+
+
+static void
+xfce_appfinder_model_class_init (XfceAppfinderModelClass *klass)
+{
+  GObjectClass *gobject_class;
+
+  gobject_class = G_OBJECT_CLASS (klass);
+  gobject_class->finalize = xfce_appfinder_model_finalize;
+
+  model_signals[CATEGORIES_CHANGED] =
+    g_signal_new (g_intern_static_string ("categories-changed"),
+                  G_TYPE_FROM_CLASS (gobject_class),
+                  G_SIGNAL_RUN_LAST,
+                  0, NULL, NULL,
+                  g_cclosure_marshal_VOID__POINTER,
+                  G_TYPE_NONE, 1,
+                  G_TYPE_POINTER /* GSList */);
+}
+
+
+
+static void
+xfce_appfinder_model_init (XfceAppfinderModel *model)
+{
+  /* generate a unique stamp */
+  model->stamp = g_random_int ();
+  model->items_hash = g_hash_table_new (g_str_hash, g_str_equal);
+  model->command_icon_small = xfce_appfinder_model_load_pixbuf (GTK_STOCK_EXECUTE, ICON_SMALL);
+  model->command_icon_large = xfce_appfinder_model_load_pixbuf (GTK_STOCK_EXECUTE, ICON_LARGE);
+
+  model->menu = garcon_menu_new_applications ();
+  model->collect_thread = g_thread_create (xfce_appfinder_model_collect_thread, model, TRUE, NULL);
+}
+
+
+
+static void
+xfce_appfinder_model_tree_model_init (GtkTreeModelIface *iface)
+{
+  iface->get_flags = xfce_appfinder_model_get_flags;
+  iface->get_n_columns = xfce_appfinder_model_get_n_columns;
+  iface->get_column_type = xfce_appfinder_model_get_column_type;
+  iface->get_iter = xfce_appfinder_model_get_iter;
+  iface->get_path = xfce_appfinder_model_get_path;
+  iface->get_value = xfce_appfinder_model_get_value;
+  iface->iter_next = xfce_appfinder_model_iter_next;
+  iface->iter_children = xfce_appfinder_model_iter_children;
+  iface->iter_has_child = xfce_appfinder_model_iter_has_child;
+  iface->iter_n_children = xfce_appfinder_model_iter_n_children;
+  iface->iter_nth_child = xfce_appfinder_model_iter_nth_child;
+  iface->iter_parent = xfce_appfinder_model_iter_parent;
+}
+
+
+
+static void
+xfce_appfinder_model_finalize (GObject *object)
+{
+  XfceAppfinderModel *model = XFCE_APPFINDER_MODEL (object);
+
+  /* join the collector thread */
+  model->collect_cancelled = TRUE;
+  g_thread_join (model->collect_thread);
+
+  /* cancel any pending collect idle source */
+  if (G_UNLIKELY (model->collect_idle_id != 0))
+    g_source_remove (model->collect_idle_id);
+  g_slist_free (model->collect_items);
+  g_slist_free (model->collect_categories);
+
+  g_object_unref (G_OBJECT (model->menu));
+
+  g_slist_foreach (model->items, (GFunc) xfce_appfinder_model_item_free, NULL);
+  g_slist_free (model->items);
+
+  if (G_UNLIKELY (model->filter_idle_id != 0))
+    g_source_remove (model->filter_idle_id);
+
+  if (model->collect_desktop_ids != NULL)
+    g_hash_table_destroy (model->collect_desktop_ids);
+  g_hash_table_destroy (model->items_hash);
+
+  g_free (model->filter_category);
+  g_free (model->filter_string);
+
+  g_object_unref (G_OBJECT (model->command_icon_large));
+  g_object_unref (G_OBJECT (model->command_icon_small));
+
+  g_debug ("model cleared");
+
+  (*G_OBJECT_CLASS (xfce_appfinder_model_parent_class)->finalize) (object);
+}
+
+
+
+static GtkTreeModelFlags
+xfce_appfinder_model_get_flags (GtkTreeModel *tree_model)
+{
+  return GTK_TREE_MODEL_ITERS_PERSIST | GTK_TREE_MODEL_LIST_ONLY;
+}
+
+
+
+static gint
+xfce_appfinder_model_get_n_columns (GtkTreeModel *tree_model)
+{
+  return XFCE_APPFINDER_MODEL_N_COLUMNS;
+}
+
+
+
+static GType
+xfce_appfinder_model_get_column_type (GtkTreeModel *tree_model,
+                                      gint          column)
+{
+  switch (column)
+    {
+    case XFCE_APPFINDER_MODEL_COLUMN_ABSTRACT:
+    case XFCE_APPFINDER_MODEL_COLUMN_URI:
+    case XFCE_APPFINDER_MODEL_COLUMN_COMMAND:
+    case XFCE_APPFINDER_MODEL_COLUMN_TOOLTIP:
+      return G_TYPE_STRING;
+
+    case XFCE_APPFINDER_MODEL_COLUMN_ICON_SMALL:
+    case XFCE_APPFINDER_MODEL_COLUMN_ICON_LARGE:
+      return GDK_TYPE_PIXBUF;
+
+    case XFCE_APPFINDER_MODEL_COLUMN_VISIBLE:
+      return G_TYPE_BOOLEAN;
+
+    default:
+      g_assert_not_reached ();
+      return G_TYPE_INVALID;
+    }
+}
+
+
+
+static gboolean
+xfce_appfinder_model_get_iter (GtkTreeModel *tree_model,
+                               GtkTreeIter  *iter,
+                               GtkTreePath  *path)
+{
+  XfceAppfinderModel *model = XFCE_APPFINDER_MODEL (tree_model);
+
+  g_return_val_if_fail (XFCE_IS_APPFINDER_MODEL (model), FALSE);
+  g_return_val_if_fail (gtk_tree_path_get_depth (path) > 0, FALSE);
+
+  iter->stamp = model->stamp;
+  iter->user_data = g_slist_nth (model->items, gtk_tree_path_get_indices (path)[0]);
+
+  return (iter->user_data != NULL);
+}
+
+
+
+static GtkTreePath*
+xfce_appfinder_model_get_path (GtkTreeModel *tree_model,
+                               GtkTreeIter  *iter)
+{
+  XfceAppfinderModel *model = XFCE_APPFINDER_MODEL (tree_model);
+  gint                idx;
+
+  g_return_val_if_fail (XFCE_IS_APPFINDER_MODEL (model), NULL);
+  g_return_val_if_fail (iter->stamp == model->stamp, NULL);
+
+  /* determine the index of the iter */
+  idx = g_slist_position (model->items, iter->user_data);
+  if (G_UNLIKELY (idx < 0))
+    return NULL;
+
+  return gtk_tree_path_new_from_indices (idx, -1);
+}
+
+
+
+static void
+xfce_appfinder_model_get_value (GtkTreeModel *tree_model,
+                                GtkTreeIter  *iter,
+                                gint          column,
+                                GValue       *value)
+{
+  XfceAppfinderModel  *model = XFCE_APPFINDER_MODEL (tree_model);
+  ModelItem           *item;
+  const gchar         *name;
+  const gchar         *comment;
+  GFile               *file;
+  gchar               *parse_name;
+  GList               *categories, *li;
+  gchar              **cat_arr;
+  gchar               *cat_str;
+  guint                i;
+
+  g_return_if_fail (XFCE_IS_APPFINDER_MODEL (model));
+  g_return_if_fail (iter->stamp == model->stamp);
+
+  item = ITER_GET_DATA (iter);
+  g_return_if_fail ((item->item == NULL && item->command != NULL)
+                    || (item->item != NULL && GARCON_IS_MENU_ITEM (item->item)));
+
+  switch (column)
+    {
+    case XFCE_APPFINDER_MODEL_COLUMN_VISIBLE:
+      g_value_init (value, G_TYPE_BOOLEAN);
+      g_value_set_boolean (value, item->visible);
+      break;
+
+    case XFCE_APPFINDER_MODEL_COLUMN_ABSTRACT:
+      if (item->abstract == NULL)
+        {
+          if (item->item != NULL)
+            {
+              name = garcon_menu_item_get_name (item->item);
+              comment = garcon_menu_item_get_comment (item->item);
+
+              if (comment != NULL)
+                item->abstract = g_markup_printf_escaped ("<b>%s</b>\n%s", name, comment);
+              else
+                item->abstract = g_markup_printf_escaped ("<b>%s</b>", name);
+            }
+          else if (item->command != NULL)
+            {
+              item->abstract = g_markup_escape_text (item->command, -1);
+            }
+        }
+
+      g_value_init (value, G_TYPE_STRING);
+      g_value_set_static_string (value, item->abstract);
+      break;
+
+    case XFCE_APPFINDER_MODEL_COLUMN_COMMAND:
+      g_value_init (value, G_TYPE_STRING);
+      g_value_set_static_string (value, item->command);
+      break;
+
+    case XFCE_APPFINDER_MODEL_COLUMN_ICON_SMALL:
+      if (item->icon_small == NULL
+          && item->item != NULL)
+        {
+          name = garcon_menu_item_get_icon_name (item->item);
+          item->icon_small = xfce_appfinder_model_load_pixbuf (name, ICON_SMALL);
+        }
+
+      g_value_init (value, GDK_TYPE_PIXBUF);
+      g_value_set_object (value, item->icon_small);
+      break;
+
+    case XFCE_APPFINDER_MODEL_COLUMN_ICON_LARGE:
+      if (item->icon_large == NULL
+          && item->item != NULL)
+        {
+          name = garcon_menu_item_get_icon_name (item->item);
+          item->icon_large = xfce_appfinder_model_load_pixbuf (name, ICON_LARGE);
+        }
+
+      g_value_init (value, GDK_TYPE_PIXBUF);
+      g_value_set_object (value, item->icon_large);
+      break;
+
+    case XFCE_APPFINDER_MODEL_COLUMN_TOOLTIP:
+      if (item->item != NULL
+          && item->tooltip == NULL)
+        {
+          file = garcon_menu_item_get_file (item->item);
+          parse_name = g_file_get_parse_name (file);
+          g_object_unref (G_OBJECT (file));
+
+          /* create nice category string */
+          categories = garcon_menu_item_get_categories (item->item);
+          i = g_list_length (categories);
+          cat_arr = g_new0 (gchar *, i + 1);
+          for (li = categories; li != NULL; li = li->next)
+            cat_arr[--i] = li->data;
+          cat_str = g_strjoinv ("; ", cat_arr);
+          g_free (cat_arr);
+
+          item->tooltip = g_markup_printf_escaped ("<b>%s:</b> %s\n"
+                                                   "<b>%s:</b> %s\n"
+                                                   "<b>%s:</b> %s\n"
+                                                   "<b>%s:</b> %s",
+                                                   _("Name"), garcon_menu_item_get_name (item->item),
+                                                   _("Command"), garcon_menu_item_get_command (item->item),
+                                                   _("Categories"), cat_str,
+                                                   _("Filename"), parse_name);
+
+          g_free (parse_name);
+          g_free (cat_str);
+        }
+
+      g_value_init (value, G_TYPE_STRING);
+      g_value_set_string (value, item->tooltip);
+      break;
+
+    case XFCE_APPFINDER_MODEL_COLUMN_URI:
+      g_value_init (value, G_TYPE_STRING);
+      if (item->item != NULL)
+        g_value_take_string (value, garcon_menu_item_get_uri (item->item));
+      break;
+
+    default:
+      g_assert_not_reached ();
+      break;
+    }
+}
+
+
+
+static gboolean
+xfce_appfinder_model_iter_next (GtkTreeModel *tree_model,
+                                GtkTreeIter  *iter)
+{
+  g_return_val_if_fail (XFCE_IS_APPFINDER_MODEL (tree_model), FALSE);
+  g_return_val_if_fail (iter->stamp == XFCE_APPFINDER_MODEL (tree_model)->stamp, FALSE);
+
+  iter->user_data = g_slist_next (iter->user_data);
+  return (iter->user_data != NULL);
+}
+
+
+
+static gboolean
+xfce_appfinder_model_iter_children (GtkTreeModel *tree_model,
+                                    GtkTreeIter  *iter,
+                                    GtkTreeIter  *parent)
+{
+  XfceAppfinderModel *model = XFCE_APPFINDER_MODEL (tree_model);
+
+  g_return_val_if_fail (XFCE_IS_APPFINDER_MODEL (model), FALSE);
+
+  if (G_LIKELY (parent == NULL && model->items != NULL))
+    {
+      iter->stamp = model->stamp;
+      iter->user_data = model->items;
+      return TRUE;
+    }
+
+  return FALSE;
+}
+
+
+
+static gboolean
+xfce_appfinder_model_iter_has_child (GtkTreeModel *tree_model,
+                                     GtkTreeIter  *iter)
+{
+  return FALSE;
+}
+
+
+
+static gint
+xfce_appfinder_model_iter_n_children (GtkTreeModel *tree_model,
+                                      GtkTreeIter  *iter)
+{
+  XfceAppfinderModel *model = XFCE_APPFINDER_MODEL (tree_model);
+
+  g_return_val_if_fail (XFCE_IS_APPFINDER_MODEL (model), 0);
+
+  return (iter == NULL) ? g_slist_length (model->items) : 0;
+}
+
+
+
+static gboolean
+xfce_appfinder_model_iter_nth_child (GtkTreeModel *tree_model,
+                                     GtkTreeIter  *iter,
+                                     GtkTreeIter  *parent,
+                                     gint          n)
+{
+  XfceAppfinderModel *model = XFCE_APPFINDER_MODEL (tree_model);
+
+  g_return_val_if_fail (XFCE_IS_APPFINDER_MODEL (model), FALSE);
+
+  if (G_LIKELY (parent != NULL))
+    {
+      iter->stamp = model->stamp;
+      iter->user_data = g_slist_nth (model->items, n);
+      return (iter->user_data != NULL);
+    }
+
+  return FALSE;
+}
+
+
+
+static gboolean
+xfce_appfinder_model_iter_parent (GtkTreeModel *tree_model,
+                                  GtkTreeIter  *iter,
+                                  GtkTreeIter  *child)
+{
+  return FALSE;
+}
+
+
+
+static gboolean
+xfce_appfinder_model_collect_idle (gpointer user_data)
+{
+  XfceAppfinderModel *model = XFCE_APPFINDER_MODEL (user_data);
+  GtkTreePath        *path;
+  GtkTreeIter         iter;
+  GSList             *li, *lnext;
+
+  g_return_val_if_fail (XFCE_IS_APPFINDER_MODEL (model), FALSE);
+  g_return_val_if_fail (model->items == NULL, FALSE);
+
+  g_debug ("insert idle start");
+
+  GDK_THREADS_ENTER ();
+
+  /* move the collected items "online" */
+  model->items = model->collect_items;
+  model->collect_items = NULL;
+
+  /* emit notifications for all new items */
+  path = gtk_tree_path_new_first ();
+  for (li = model->items; li != NULL; li = li->next)
+    {
+      /* remember the next item */
+      lnext = li->next;
+      li->next = NULL;
+
+      /* generate the iterator */
+      ITER_INIT (iter, model->stamp, li);
+
+      /* emit the "row-inserted" signal */
+      gtk_tree_model_row_inserted (GTK_TREE_MODEL (model), path, &iter);
+
+      /* advance the path */
+      gtk_tree_path_next (path);
+
+      /* reset the next item */
+      li->next = lnext;
+    }
+  gtk_tree_path_free (path);
+
+  /* signal new categories */
+  if (model->collect_categories != NULL)
+    {
+      g_signal_emit (G_OBJECT (model), model_signals[CATEGORIES_CHANGED], 0,
+                     model->collect_categories);
+      g_slist_free (model->collect_categories);
+      model->collect_categories = NULL;
+    }
+
+  GDK_THREADS_LEAVE ();
+
+  g_debug ("insert idle end");
+
+  return FALSE;
+}
+
+
+
+static void
+xfce_appfinder_model_collect_idle_destroy (gpointer user_data)
+{
+  XFCE_APPFINDER_MODEL (user_data)->collect_idle_id = 0;
+}
+
+
+
+static gint
+xfce_appfinder_model_item_compare (gconstpointer a,
+                                   gconstpointer b)
+{
+  const ModelItem *item_a = a, *item_b = b;
+  const gchar     *name_a, *name_b;
+
+  /* sort custom commands before desktop files */
+  if ((item_a->item != NULL) != (item_b->item != NULL))
+    return (item_a->item != NULL) ? 1 : -1;
+
+  /* sort desktop entries */
+  if (item_a->item != NULL)
+    {
+      name_a = garcon_menu_item_get_name (item_a->item);
+      name_b = garcon_menu_item_get_name (item_b->item);
+      return g_utf8_collate (name_a, name_b);
+    }
+
+  /* sort custom commands */
+  return g_utf8_collate (item_a->command, item_b->command);
+}
+
+
+
+static gint
+xfce_appfinder_model_category_compare (gconstpointer a,
+                                       gconstpointer b)
+{
+  g_return_val_if_fail (GARCON_IS_MENU_DIRECTORY (a), 0);
+  g_return_val_if_fail (GARCON_IS_MENU_DIRECTORY (b), 0);
+
+  return g_utf8_collate (garcon_menu_directory_get_name (GARCON_MENU_DIRECTORY (a)),
+                         garcon_menu_directory_get_name (GARCON_MENU_DIRECTORY (b)));
+}
+
+
+
+static void
+xfce_appfinder_model_item_free (gpointer data)
+{
+  ModelItem *item = data;
+
+  if (item->icon_small != NULL)
+    g_object_unref (G_OBJECT (item->icon_small));
+  if (item->icon_large != NULL)
+    g_object_unref (G_OBJECT (item->icon_large));
+  if (item->categories != NULL)
+    g_ptr_array_free (item->categories, TRUE);
+  g_free (item->abstract);
+  g_free (item->key);
+  g_free (item->command);
+  g_free (item->tooltip);
+  g_slice_free (ModelItem, item);
+}
+
+
+
+static gchar *
+xfce_appfinder_model_item_key (GarconMenuItem *item)
+{
+  const gchar *value;
+  GString     *str;
+  gchar       *normalized;
+  gchar       *casefold;
+  gchar       *p;
+
+  str = g_string_sized_new (128);
+
+  value = garcon_menu_item_get_name (item);
+  if (value != NULL)
+    g_string_append (str, value);
+  g_string_append_c (str, '\n');
+
+  value = garcon_menu_item_get_command (item);
+  if (value != NULL)
+    {
+      /* only add first part of the command */
+      p = strchr (value, ' ');
+      g_string_append_len (str, value, p != NULL ? p - value : -1);
+    }
+  g_string_append_c (str, '\n');
+
+  value = garcon_menu_item_get_comment (item);
+  if (value != NULL)
+    g_string_append (str, value);
+
+  normalized = g_utf8_normalize (str->str, str->len, G_NORMALIZE_ALL);
+  casefold = g_utf8_casefold (normalized, -1);
+  g_free (normalized);
+
+  g_string_free (str, TRUE);
+
+  return casefold;
+}
+
+
+
+static gboolean
+xfce_appfinder_model_ptr_array_strcmp (GPtrArray   *array,
+                                       const gchar *str1)
+{
+  guint        i;
+  const gchar *str2;
+
+  if (array != NULL && str1 != NULL)
+    {
+      for (i = 0; i < array->len; i++)
+        {
+          str2 = g_ptr_array_index (array, i);
+          if (str2 != NULL && strcmp (str1, str2) == 0)
+            return TRUE;
+        }
+    }
+
+  return FALSE;
+}
+
+
+
+static gboolean
+xfce_appfinder_model_collect_items (XfceAppfinderModel *model,
+                                    GarconMenu         *menu,
+                                    const gchar        *category)
+{
+  GList               *elements, *li;
+  GarconMenuDirectory *directory;
+  ModelItem           *item;
+  gboolean             has_items = FALSE;
+  const gchar         *desktop_id;
+  const gchar         *command, *p;
+
+  g_return_val_if_fail (GARCON_IS_MENU (menu), FALSE);
+
+  directory = garcon_menu_get_directory (menu);
+  if (directory != NULL)
+    {
+      if (!garcon_menu_directory_get_visible (directory))
+        return FALSE;
+
+      if (category == NULL)
+        category = garcon_menu_directory_get_name (directory);
+    }
+
+  /* collect all the elements in this menu and its sub menus */
+  elements = garcon_menu_get_elements (menu);
+  for (li = elements; li != NULL && !model->collect_cancelled; li = li->next)
+    {
+      if (GARCON_IS_MENU_ITEM (li->data))
+        {
+          if (!garcon_menu_element_get_visible (li->data))
+            continue;
+
+          desktop_id = garcon_menu_item_get_desktop_id (li->data);
+          item = g_hash_table_lookup (model->collect_desktop_ids, desktop_id);
+          if (G_LIKELY (item == NULL))
+            {
+              item = g_slice_new0 (ModelItem);
+              item->visible = TRUE;
+              item->item = li->data;
+              item->visible = FALSE;
+
+              command = garcon_menu_item_get_command (li->data);
+              if (G_LIKELY (command != NULL))
+                {
+                  p = strchr (command, ' ');
+                  if (p != NULL)
+                    item->command = g_strndup (command, p - command);
+                  else
+                    item->command = g_strdup (command);
+                }
+
+              item->categories = g_ptr_array_new_with_free_func (g_free);
+              g_ptr_array_add (item->categories, g_strdup (category));
+
+              model->collect_items = g_slist_prepend (model->collect_items, item);
+              g_hash_table_insert (model->collect_desktop_ids, (gchar *) desktop_id, item);
+              g_hash_table_insert (model->items_hash, item->command, item);
+            }
+          else if (!xfce_appfinder_model_ptr_array_strcmp (item->categories, category))
+            {
+              /* add category to existing item */
+              g_ptr_array_add (item->categories, g_strdup (category));
+              g_debug ("%s is in %d categories", desktop_id, item->categories->len);
+            }
+
+          has_items = TRUE;
+        }
+      else if (GARCON_IS_MENU (li->data))
+        {
+          if (xfce_appfinder_model_collect_items (model, li->data, category))
+            has_items = TRUE;
+        }
+    }
+  g_list_free (elements);
+
+  if (directory != NULL
+      && has_items)
+    model->collect_categories = g_slist_prepend (model->collect_categories, directory);
+
+  return has_items;
+}
+
+
+
+static void
+xfce_appfinder_model_collect_history (XfceAppfinderModel *model,
+                                      GMappedFile        *history)
+{
+  gchar     *contents, *end;
+  gsize      len;
+  ModelItem *item;
+
+  contents = g_mapped_file_get_contents (history);
+  if (contents == NULL)
+    return;
+
+  for (;!model->collect_cancelled;)
+    {
+      end = strchr (contents, '\n');
+      if (G_UNLIKELY (end == NULL))
+        break;
+
+      len = end - contents;
+      if (len > 0)
+        {
+          item = g_slice_new0 (ModelItem);
+          item->command = g_strndup (contents, len);
+          item->icon_small = g_object_ref (G_OBJECT (model->command_icon_small));
+          item->icon_large = g_object_ref (G_OBJECT (model->command_icon_large));
+          model->collect_items = g_slist_prepend (model->collect_items, item);
+
+          g_hash_table_insert (model->items_hash, item->command, item);
+        }
+
+      contents += len + 1;
+    }
+}
+
+
+
+static gpointer
+xfce_appfinder_model_collect_thread (gpointer user_data)
+{
+  XfceAppfinderModel *model = XFCE_APPFINDER_MODEL (user_data);
+  GError             *error = NULL;
+  gchar              *filename;
+  GMappedFile        *history;
+
+  g_return_val_if_fail (GARCON_IS_MENU (model->menu), NULL);
+  g_return_val_if_fail (model->collect_items == NULL, NULL);
+
+  g_debug ("collect thread start");
+
+  /* load menu data */
+  if (G_LIKELY (model->menu != NULL))
+    {
+      if (garcon_menu_load (model->menu, NULL, &error))
+        {
+          model->collect_desktop_ids = g_hash_table_new (g_str_hash, g_str_equal);
+          xfce_appfinder_model_collect_items (model, model->menu, NULL);
+          g_hash_table_destroy (model->collect_desktop_ids);
+          model->collect_desktop_ids = NULL;
+        }
+      else
+        {
+          g_warning ("Failed to load the root menu: %s", error->message);
+          g_clear_error (&error);
+        }
+    }
+
+  /* load command history */
+  filename = xfce_resource_lookup (XFCE_RESOURCE_CACHE, HISTORY_PATH);
+  if (G_LIKELY (filename != NULL))
+    {
+      history = g_mapped_file_new (filename, FALSE, &error);
+      if (G_LIKELY (history != NULL))
+        {
+          xfce_appfinder_model_collect_history (model, history);
+          g_mapped_file_free (history);
+        }
+      else
+        {
+          g_warning ("Failed to open history file: %s", error->message);
+          g_error_free (error);
+        }
+    }
+
+  if (model->collect_items != NULL
+      && !model->collect_cancelled)
+    {
+      model->collect_items = g_slist_sort (model->collect_items, xfce_appfinder_model_item_compare);
+      model->collect_categories = g_slist_sort (model->collect_categories, xfce_appfinder_model_category_compare);
+
+      model->collect_idle_id = g_idle_add_full (G_PRIORITY_LOW, xfce_appfinder_model_collect_idle,
+                                                model, xfce_appfinder_model_collect_idle_destroy);
+    }
+
+  g_debug ("collect thread end");
+
+  return NULL;
+}
+
+
+
+static gboolean
+xfce_appfinder_model_filter_idle (gpointer data)
+{
+  XfceAppfinderModel *model = XFCE_APPFINDER_MODEL (data);
+  GSList             *li;
+  gint                idx;
+  ModelItem          *item;
+  gboolean            visible;
+  GtkTreeIter         iter;
+  GtkTreePath        *path;
+
+  GDK_THREADS_ENTER ();
+
+  for (li = model->items, idx = 0; li != NULL; li = li->next, idx++)
+    {
+      item = li->data;
+      visible = TRUE;
+
+      g_return_val_if_fail ((item->item == NULL && item->command != NULL)
+                            || (item->item != NULL && GARCON_IS_MENU_ITEM (item->item)), FALSE);
+
+      if (item->item != NULL)
+        {
+          if (model->filter_category != NULL
+              && !xfce_appfinder_model_ptr_array_strcmp (item->categories, model->filter_category))
+            {
+              visible = FALSE;
+            }
+          else if (model->filter_string != NULL)
+            {
+              if (item->key == NULL)
+                item->key = xfce_appfinder_model_item_key (item->item);
+
+              visible = strstr (item->key, model->filter_string) != NULL;
+            }
+        }
+      else if (item->command != NULL)
+        {
+          if (model->filter_category == NULL
+              || *model->filter_category != '\0')
+            {
+              visible = FALSE;
+            }
+          else if (model->filter_string != NULL)
+            {
+              visible = strstr (item->command, model->filter_string) != NULL;
+            }
+        }
+
+      if (item->visible != visible)
+        {
+          item->visible = visible;
+
+          /* generate an iterator for the path */
+          ITER_INIT (iter, model->stamp, li);
+
+          /* tell the view that the volume has changed in some way */
+          path = gtk_tree_path_new_from_indices (idx, -1);
+          gtk_tree_model_row_changed (GTK_TREE_MODEL (model), path, &iter);
+          gtk_tree_path_free (path);
+        }
+    }
+
+  GDK_THREADS_LEAVE ();
+
+  return FALSE;
+}
+
+
+
+static void
+xfce_appfinder_model_filter_idle_destroyed (gpointer data)
+{
+  XFCE_APPFINDER_MODEL (data)->filter_idle_id = 0;
+}
+
+
+
+static void
+xfce_appfinder_model_filter (XfceAppfinderModel *model)
+{
+  if (model->filter_idle_id == 0)
+    {
+      model->filter_idle_id = g_idle_add_full (G_PRIORITY_HIGH_IDLE, xfce_appfinder_model_filter_idle,
+                                               model, xfce_appfinder_model_filter_idle_destroyed);
+    }
+}
+
+
+
+XfceAppfinderModel *
+xfce_appfinder_model_new (void)
+{
+  return g_object_new (XFCE_TYPE_APPFINDER_MODEL, NULL);
+}
+
+
+
+void
+xfce_appfinder_model_filter_category (XfceAppfinderModel *model,
+                                      const gchar        *category)
+{
+  g_return_if_fail (XFCE_IS_APPFINDER_MODEL (model));
+
+  if (g_strcmp0 (model->filter_category, category) == 0)
+    return;
+
+  g_free (model->filter_category);
+  model->filter_category = g_strdup (category);
+
+  xfce_appfinder_model_filter (model);
+}
+
+
+
+void
+xfce_appfinder_model_filter_string (XfceAppfinderModel *model,
+                                    const gchar        *seach_string)
+{
+  gchar *normalized;
+
+  g_return_if_fail (XFCE_IS_APPFINDER_MODEL (model));
+
+  if (model->filter_string == seach_string)
+    return;
+
+  g_free (model->filter_string);
+
+  if (IS_STRING (seach_string))
+    {
+      normalized = g_utf8_normalize (seach_string, -1, G_NORMALIZE_ALL);
+      model->filter_string = g_utf8_casefold (normalized, -1);
+      g_free (normalized);
+    }
+  else
+    {
+      model->filter_string = NULL;
+    }
+
+  xfce_appfinder_model_filter (model);
+}
+
+
+
+gboolean
+xfce_appfinder_model_execute (XfceAppfinderModel  *model,
+                              GtkTreeIter         *iter,
+                              GdkScreen           *screen,
+                              gboolean            *is_regular_command,
+                              GError             **error)
+{
+  const gchar     *command, *p;
+  GarconMenuItem  *item;
+  ModelItem       *mitem;
+  GString         *string;
+  gboolean         succeed = FALSE;
+  gchar          **argv;
+
+  g_return_val_if_fail (XFCE_IS_APPFINDER_MODEL (model), FALSE);
+  g_return_val_if_fail (iter->stamp == model->stamp, FALSE);
+  g_return_val_if_fail (GDK_IS_SCREEN (screen), FALSE);
+
+  mitem = ITER_GET_DATA (iter);
+  item = mitem->item;
+
+  /* leave if this is not a menu item */
+  *is_regular_command = (item == NULL);
+  if (item == NULL)
+    return FALSE;
+
+  g_return_val_if_fail (GARCON_IS_MENU_ITEM (item), FALSE);
+
+  command = garcon_menu_item_get_command (item);
+  if (!IS_STRING (command))
+    {
+      g_set_error_literal (error, 0, 0, _("Application has no command"));
+      return FALSE;
+    }
+
+  string = g_string_sized_new (100);
+
+  if (garcon_menu_item_requires_terminal (item))
+    g_string_append (string, "exo-open --launch TerminalEmulator ");
+
+  /* expand the field codes */
+  for (p = command; *p != '\0'; ++p)
+    {
+      if (G_UNLIKELY (p[0] == '%' && p[1] != '\0'))
+        {
+          switch (*++p)
+            {
+            case '%':
+              g_string_append_c (string, '%');
+              break;
+
+            /* skip all the other %? values for now we don't have dnd anyways */
+            }
+        }
+      else
+        {
+          g_string_append_c (string, *p);
+        }
+    }
+
+  if (g_shell_parse_argv (string->str, NULL, &argv, error))
+    {
+      succeed = xfce_spawn_on_screen (screen, garcon_menu_item_get_path (item),
+                                      argv, NULL, G_SPAWN_SEARCH_PATH,
+                                      garcon_menu_item_supports_startup_notification (item),
+                                      gtk_get_current_event_time (),
+                                      garcon_menu_item_get_icon_name (item),
+                                      error);
+
+      g_strfreev (argv);
+    }
+
+  g_string_free (string, TRUE);
+
+  return succeed;
+}
+
+
+GdkPixbuf *
+xfce_appfinder_model_load_pixbuf (const gchar *icon_name,
+                                  gint         size)
+{
+  GdkPixbuf *pixbuf = NULL;
+  GdkPixbuf *scaled;
+
+  g_debug ("load icon %s at %dpx", icon_name, size);
+
+  if (icon_name != NULL)
+    {
+      if (g_path_is_absolute (icon_name))
+        {
+          pixbuf = gdk_pixbuf_new_from_file_at_scale (icon_name, size,
+                                                      size, TRUE, NULL);
+        }
+      else
+        {
+          pixbuf = gtk_icon_theme_load_icon (gtk_icon_theme_get_default (),
+                                             icon_name, size, 0, NULL);
+        }
+    }
+
+  if (G_UNLIKELY (pixbuf == NULL))
+    {
+      pixbuf = gtk_icon_theme_load_icon (gtk_icon_theme_get_default (),
+                                         "applications-other",
+                                         size, 0, NULL);
+    }
+
+  if (pixbuf != NULL
+      && (gdk_pixbuf_get_width (pixbuf) > size
+          || gdk_pixbuf_get_height (pixbuf) > size))
+    {
+      scaled = gdk_pixbuf_scale_simple (pixbuf, size, size, GDK_INTERP_BILINEAR);
+      g_object_unref (G_OBJECT (pixbuf));
+      pixbuf = scaled;
+    }
+
+  return pixbuf;
+}
+
+
+
+gboolean
+xfce_appfinder_model_save_command (XfceAppfinderModel  *model,
+                                   const gchar         *command,
+                                   GError             **error)
+{
+  GSList    *li;
+  GString   *contents;
+  gboolean   succeed = FALSE;
+  gchar     *filename;
+  ModelItem *item;
+
+  g_return_val_if_fail (XFCE_IS_APPFINDER_MODEL (model), FALSE);
+
+  if (!IS_STRING (command)
+      || g_hash_table_lookup (model->items_hash, command) != NULL)
+    return TRUE;
+
+  contents = g_string_new (NULL);
+
+  g_debug ("saving history");
+
+  /* store all the custom commands */
+  for (li = model->items; li != NULL; li = li->next)
+    {
+      item = li->data;
+      if (item->item != NULL
+          || item->command == NULL)
+        continue;
+
+      g_string_append (contents, item->command);
+      g_string_append_c (contents, '\n');
+    }
+
+  /* add the new command */
+  g_string_append (contents, command);
+  g_string_append_c (contents, '\n');
+
+  if (contents->len > 0)
+    {
+      filename = xfce_resource_save_location (XFCE_RESOURCE_CACHE, HISTORY_PATH, TRUE);
+      if (G_LIKELY (filename != NULL))
+        succeed = g_file_set_contents (filename, contents->str, contents->len, error);
+      else
+        g_set_error_literal (error, 0, 0, "Unable to create history cache file");
+      g_free (filename);
+    }
+  else
+    {
+      succeed = TRUE;
+    }
+
+  g_string_free (contents, TRUE);
+
+  return succeed;
+}
+
+
+
+GdkPixbuf *
+xfce_appfinder_model_get_icon_for_command (XfceAppfinderModel *model,
+                                           const gchar        *command)
+{
+  ModelItem   *item;
+  const gchar *icon_name;
+
+  if (IS_STRING (command))
+    {
+      item = g_hash_table_lookup (model->items_hash, command);
+      if (G_LIKELY (item != NULL))
+        {
+          if (item->icon_large == NULL
+              && item->item != NULL)
+            {
+              icon_name = garcon_menu_item_get_icon_name (item->item);
+              item->icon_large = xfce_appfinder_model_load_pixbuf (icon_name, ICON_LARGE);
+            }
+
+          return g_object_ref (G_OBJECT (item->icon_large));
+        }
+    }
+
+  return NULL;
+}
diff --git a/src/appfinder-model.h b/src/appfinder-model.h
new file mode 100644
index 0000000..13dcfa0
--- /dev/null
+++ b/src/appfinder-model.h
@@ -0,0 +1,89 @@
+/*
+ * Copyright (C) 2011 Nick Schermer <nick at xfce.org>
+ *
+ * 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 program 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.
+ *
+ * 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.
+ */
+
+#ifndef __XFCE_APPFINDER_MODEL_H__
+#define __XFCE_APPFINDER_MODEL_H__
+
+#include <gtk/gtk.h>
+
+G_BEGIN_DECLS
+
+typedef struct _XfceAppfinderModelClass XfceAppfinderModelClass;
+typedef struct _XfceAppfinderModel      XfceAppfinderModel;
+
+#define XFCE_TYPE_APPFINDER_MODEL            (xfce_appfinder_model_get_type ())
+#define XFCE_APPFINDER_MODEL(obj)            (G_TYPE_CHECK_INSTANCE_CAST ((obj), XFCE_TYPE_APPFINDER_MODEL, XfceAppfinderModel))
+#define XFCE_APPFINDER_MODEL_CLASS(klass)    (G_TYPE_CHECK_CLASS_CAST ((klass), XFCE_TYPE_APPFINDER_MODEL, XfceAppfinderModelClass))
+#define XFCE_IS_APPFINDER_MODEL(obj)         (G_TYPE_CHECK_INSTANCE_TYPE ((obj), XFCE_TYPE_APPFINDER_MODEL))
+#define XFCE_IS_APPFINDER_MODEL_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), XFCE_TYPE_APPFINDER_MODEL))
+#define XFCE_APPFINDER_MODEL_GET_CLASS(obj)  (G_TYPE_INSTANCE_GET_CLASS ((obj), XFCE_TYPE_APPFINDER_MODEL, XfceAppfinderModelClass))
+
+#define ICON_SMALL   32
+#define ICON_LARGE   48
+
+#define ITER_GET_DATA(iter)          (((GSList *) (iter)->user_data)->data)
+#define ITER_INIT(iter, iter_stamp, iter_data) \
+G_STMT_START { \
+  (iter).stamp = iter_stamp; \
+  (iter).user_data = iter_data; \
+} G_STMT_END
+#define IS_STRING(str) ((str) != NULL && *(str) != '\0')
+
+enum
+{
+  XFCE_APPFINDER_MODEL_COLUMN_ABSTRACT,
+  XFCE_APPFINDER_MODEL_COLUMN_ICON_SMALL,
+  XFCE_APPFINDER_MODEL_COLUMN_ICON_LARGE,
+  XFCE_APPFINDER_MODEL_COLUMN_VISIBLE,
+  XFCE_APPFINDER_MODEL_COLUMN_COMMAND,
+  XFCE_APPFINDER_MODEL_COLUMN_URI,
+  XFCE_APPFINDER_MODEL_COLUMN_TOOLTIP,
+  XFCE_APPFINDER_MODEL_N_COLUMNS,
+};
+
+
+
+GType               xfce_appfinder_model_get_type             (void) G_GNUC_CONST;
+
+XfceAppfinderModel *xfce_appfinder_model_new                  (void) G_GNUC_MALLOC;
+
+void                xfce_appfinder_model_filter_category      (XfceAppfinderModel  *model,
+                                                               const gchar         *category);
+
+void                xfce_appfinder_model_filter_string        (XfceAppfinderModel  *model,
+                                                               const gchar         *seach_string);
+
+gboolean            xfce_appfinder_model_execute              (XfceAppfinderModel  *model,
+                                                               GtkTreeIter         *iter,
+                                                               GdkScreen           *screen,
+                                                               gboolean            *is_regular_command,
+                                                               GError             **error);
+
+GdkPixbuf          *xfce_appfinder_model_load_pixbuf          (const gchar         *icon_name,
+                                                               gint                 size) G_GNUC_MALLOC;
+
+gboolean            xfce_appfinder_model_save_command         (XfceAppfinderModel  *model,
+                                                               const gchar         *command,
+                                                               GError             **error);
+
+GdkPixbuf          *xfce_appfinder_model_get_icon_for_command (XfceAppfinderModel  *model,
+                                                               const gchar         *command);
+
+G_END_DECLS
+
+#endif /* !__XFCE_APPFINDER_MODEL_H__ */
diff --git a/src/appfinder-window.c b/src/appfinder-window.c
new file mode 100644
index 0000000..afe8a31
--- /dev/null
+++ b/src/appfinder-window.c
@@ -0,0 +1,780 @@
+/*
+ * Copyright (C) 2011 Nick Schermer <nick at xfce.org>
+ *
+ * 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 program 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.
+ *
+ * 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.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#ifdef HAVE_STRING_H
+#include <string.h>
+#endif
+
+#include <libxfce4util/libxfce4util.h>
+#include <libxfce4ui/libxfce4ui.h>
+#include <gdk/gdkkeysyms.h>
+
+#include <src/appfinder-window.h>
+#include <src/appfinder-model.h>
+#include <src/appfinder-category-model.h>
+
+
+
+static void       xfce_appfinder_window_finalize                 (GObject                     *object);
+static gboolean   xfce_appfinder_window_key_press_event          (GtkWidget                   *widget,
+                                                                  GdkEventKey                 *event);
+static gboolean   xfce_appfinder_window_delete_event             (GtkWidget                   *widget,
+                                                                  GdkEventAny                 *event);
+static void       xfce_appfinder_window_set_padding              (GtkWidget                   *entry,
+                                                                  GtkWidget                   *align);
+static void       xfce_appfinder_window_entry_changed            (XfceAppfinderWindow         *window);
+static void       xfce_appfinder_window_entry_activate           (GtkEditable                 *entry,
+                                                                  XfceAppfinderWindow         *window);
+static gboolean   xfce_appfinder_window_entry_key_press_event    (GtkWidget                   *entry,
+                                                                  GdkEventKey                 *event,
+                                                                  XfceAppfinderWindow         *window);
+static void       xfce_appfinder_window_entry_icon_released      (GtkEntry                    *entry,
+                                                                  GtkEntryIconPosition         icon_pos,
+                                                                  GdkEvent                    *event,
+                                                                  XfceAppfinderWindow         *window);
+static void       xfce_appfinder_window_drag_begin               (GtkWidget                   *widget,
+                                                                  GdkDragContext              *drag_context,
+                                                                  XfceAppfinderWindow         *window);
+static void       xfce_appfinder_window_drag_data_get            (GtkWidget                   *widget,
+                                                                  GdkDragContext              *drag_context,
+                                                                  GtkSelectionData            *data,
+                                                                  guint                        info,
+                                                                  guint                        drag_time,
+                                                                  XfceAppfinderWindow         *window);
+static void       xfce_appfinder_window_category_changed         (GtkTreeSelection            *selection,
+                                                                  XfceAppfinderWindow         *window);
+static void       xfce_appfinder_window_item_changed             (XfceAppfinderWindow         *window);
+static void       xfce_appfinder_window_row_activated            (XfceAppfinderWindow         *window);
+static void       xfce_appfinder_window_execute                  (XfceAppfinderWindow         *window);
+
+
+
+struct _XfceAppfinderWindowClass
+{
+  GtkWindowClass __parent__;
+};
+
+struct _XfceAppfinderWindow
+{
+  GtkWindow __parent__;
+
+  XfceAppfinderModel *model;
+
+  XfceAppfinderCategoryModel *category_model;
+
+  GtkEntryCompletion *completion;
+
+  GtkWidget *paned;
+  GtkWidget *entry;
+  GtkWidget *image;
+  GtkWidget *treeview;
+
+  GdkPixbuf *icon_find;
+
+  GtkWidget *bbox;
+  GtkWidget *button_launch;
+  GtkWidget *bin_collapsed;
+  GtkWidget *bin_expanded;
+
+  gint       last_window_height;
+};
+
+static const GtkTargetEntry target_list[] =
+{
+  { "text/uri-list", 0, 0 }
+};
+
+
+
+G_DEFINE_TYPE (XfceAppfinderWindow, xfce_appfinder_window, GTK_TYPE_WINDOW)
+
+
+
+static void
+xfce_appfinder_window_class_init (XfceAppfinderWindowClass *klass)
+{
+  GObjectClass   *gobject_class;
+  GtkWidgetClass *gtkwidget_class;
+
+  gobject_class = G_OBJECT_CLASS (klass);
+  gobject_class->finalize = xfce_appfinder_window_finalize;
+
+  gtkwidget_class = GTK_WIDGET_CLASS (klass);
+  gtkwidget_class->key_press_event = xfce_appfinder_window_key_press_event;
+  gtkwidget_class->delete_event = xfce_appfinder_window_delete_event;
+}
+
+
+
+static void
+xfce_appfinder_window_init (XfceAppfinderWindow *window)
+{
+  GtkWidget          *vbox, *vbox2;
+  GtkWidget          *entry;
+  GtkWidget          *pane;
+  GtkWidget          *scroll;
+  GtkWidget          *sidepane;
+  GtkWidget          *treeview;
+  GtkWidget          *image;
+  GtkWidget          *hbox;
+  GtkWidget          *align;
+  GtkTreeViewColumn  *column;
+  GtkCellRenderer    *renderer;
+  GtkTreeModel       *filter_model;
+  GtkTreeSelection   *selection;
+  GtkWidget          *bbox;
+  GtkWidget          *button;
+  GtkTreePath        *path;
+  GtkEntryCompletion *completion;
+
+  window->last_window_height = 400;
+
+  window->model = xfce_appfinder_model_new ();
+  window->category_model = xfce_appfinder_category_model_new ();
+  g_signal_connect_swapped (G_OBJECT (window->model), "categories-changed",
+                            G_CALLBACK (xfce_appfinder_category_model_set_categories),
+                            window->category_model);
+
+  gtk_window_set_title (GTK_WINDOW (window), _("Application Finder"));
+  gtk_window_set_default_size (GTK_WINDOW (window), 500 /* todo, remember */, -1);
+  gtk_window_set_icon_name (GTK_WINDOW (window), GTK_STOCK_EXECUTE);
+
+  vbox = gtk_vbox_new (FALSE, 6);
+  gtk_container_add (GTK_CONTAINER (window), vbox);
+  gtk_container_set_border_width (GTK_CONTAINER (vbox), 6);
+  gtk_widget_show (vbox);
+
+  hbox = gtk_hbox_new (FALSE, 6);
+  gtk_box_pack_start (GTK_BOX (vbox), hbox, FALSE, TRUE, 0);
+  gtk_widget_show (hbox);
+
+  align = gtk_alignment_new (0.5, 0.0, 0.0, 0.0);
+  gtk_box_pack_start (GTK_BOX (hbox), align, FALSE, FALSE, 0);
+  gtk_widget_show (align);
+
+  window->icon_find = xfce_appfinder_model_load_pixbuf (GTK_STOCK_FIND, ICON_LARGE);
+  window->image = image = gtk_image_new_from_pixbuf (window->icon_find);
+  gtk_container_add (GTK_CONTAINER (align), image);
+  gtk_widget_show (image);
+
+  vbox2 = gtk_vbox_new (FALSE, 6);
+  gtk_box_pack_start (GTK_BOX (hbox), vbox2, TRUE, TRUE, 0);
+  gtk_widget_show (vbox2);
+
+  align = gtk_alignment_new (0.0, 0.0, 1.0, 0.0);
+  gtk_box_pack_start (GTK_BOX (vbox2), align, TRUE, TRUE, 0);
+  gtk_widget_show (align);
+
+  window->entry = entry = gtk_entry_new ();
+  gtk_container_add (GTK_CONTAINER (align), entry);
+  g_signal_connect (G_OBJECT (entry), "icon-release", G_CALLBACK (xfce_appfinder_window_entry_icon_released), window);
+  g_signal_connect (G_OBJECT (entry), "realize", G_CALLBACK (xfce_appfinder_window_set_padding), align);
+  g_signal_connect_swapped (G_OBJECT (entry), "changed", G_CALLBACK (xfce_appfinder_window_entry_changed), window);
+  g_signal_connect (G_OBJECT (entry), "activate", G_CALLBACK (xfce_appfinder_window_entry_activate), window);
+  g_signal_connect (G_OBJECT (entry), "key-press-event", G_CALLBACK (xfce_appfinder_window_entry_key_press_event), window);
+  gtk_entry_set_icon_tooltip_text (GTK_ENTRY (window->entry), GTK_ENTRY_ICON_SECONDARY, _("Toggle view mode"));
+  gtk_widget_show (entry);
+
+  window->completion = completion = gtk_entry_completion_new ();
+  gtk_entry_completion_set_model (completion, GTK_TREE_MODEL (window->model));
+  gtk_entry_completion_set_text_column (completion, XFCE_APPFINDER_MODEL_COLUMN_COMMAND);
+  gtk_entry_completion_set_popup_completion (completion, TRUE);
+  gtk_entry_completion_set_popup_single_match (completion, FALSE);
+  gtk_entry_completion_set_inline_completion (completion, TRUE);
+
+  window->bin_collapsed = gtk_alignment_new (0.0, 0.0, 1.0, 1.0);
+  gtk_box_pack_start (GTK_BOX (vbox2), window->bin_collapsed, FALSE, TRUE, 0);
+  gtk_widget_show (window->bin_collapsed);
+
+  window->paned = pane = gtk_hpaned_new ();
+  gtk_box_pack_start (GTK_BOX (vbox), pane, TRUE, TRUE, 0);
+  gtk_paned_set_position (GTK_PANED (pane), 180 /* todo remember */);
+
+  scroll = gtk_scrolled_window_new (NULL, NULL);
+  gtk_paned_add1 (GTK_PANED (pane), scroll);
+  gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW (scroll), GTK_SHADOW_ETCHED_IN);
+  gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scroll), GTK_POLICY_NEVER, GTK_POLICY_AUTOMATIC);
+  gtk_widget_show (scroll);
+
+  sidepane = gtk_tree_view_new_with_model (GTK_TREE_MODEL (window->category_model));
+  gtk_tree_view_set_headers_visible (GTK_TREE_VIEW (sidepane), FALSE);
+  gtk_tree_view_set_enable_search (GTK_TREE_VIEW (sidepane), FALSE);
+  g_signal_connect_swapped (GTK_TREE_VIEW (sidepane), "start-interactive-search", G_CALLBACK (gtk_widget_grab_focus), entry);
+  gtk_tree_view_set_row_separator_func (GTK_TREE_VIEW (sidepane),
+      xfce_appfinder_category_model_row_separator_func, NULL, NULL);
+  gtk_container_add (GTK_CONTAINER (scroll), sidepane);
+  gtk_widget_show (sidepane);
+
+  path = gtk_tree_path_new_first ();
+  gtk_tree_view_set_cursor (GTK_TREE_VIEW (sidepane), path, NULL, FALSE);
+  gtk_tree_path_free (path);
+
+  selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (sidepane));
+  gtk_tree_selection_set_mode (selection, GTK_SELECTION_BROWSE);
+  g_signal_connect (G_OBJECT (selection), "changed",
+      G_CALLBACK (xfce_appfinder_window_category_changed), window);
+
+  column = gtk_tree_view_column_new ();
+  gtk_tree_view_column_set_sizing (column, GTK_TREE_VIEW_COLUMN_FIXED);
+  gtk_tree_view_append_column (GTK_TREE_VIEW (sidepane), GTK_TREE_VIEW_COLUMN (column));
+
+  renderer = gtk_cell_renderer_pixbuf_new ();
+  gtk_tree_view_column_pack_start (GTK_TREE_VIEW_COLUMN (column), renderer, FALSE);
+  gtk_tree_view_column_set_attributes (GTK_TREE_VIEW_COLUMN (column), renderer,
+                                       "pixbuf", XFCE_APPFINDER_CATEGORY_MODEL_COLUMN_ICON, NULL);
+
+  renderer = gtk_cell_renderer_text_new ();
+  g_object_set (renderer, "ellipsize", PANGO_ELLIPSIZE_END, NULL);
+  gtk_tree_view_column_pack_start (GTK_TREE_VIEW_COLUMN (column), renderer, TRUE);
+  gtk_tree_view_column_set_attributes (GTK_TREE_VIEW_COLUMN (column), renderer,
+                                       "text", XFCE_APPFINDER_CATEGORY_MODEL_COLUMN_NAME, NULL);
+
+  scroll = gtk_scrolled_window_new (NULL, NULL);
+  gtk_paned_add2 (GTK_PANED (pane), scroll);
+  gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW (scroll), GTK_SHADOW_ETCHED_IN);
+  gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scroll), GTK_POLICY_NEVER, GTK_POLICY_AUTOMATIC);
+  gtk_widget_show (scroll);
+
+  filter_model = gtk_tree_model_filter_new (GTK_TREE_MODEL (window->model), NULL);
+  gtk_tree_model_filter_set_visible_column (GTK_TREE_MODEL_FILTER (filter_model), XFCE_APPFINDER_MODEL_COLUMN_VISIBLE);
+
+  window->treeview = treeview = gtk_tree_view_new_with_model (filter_model);
+  gtk_tree_view_set_headers_visible (GTK_TREE_VIEW (treeview), FALSE);
+  gtk_tree_view_set_enable_search (GTK_TREE_VIEW (treeview), FALSE);
+  gtk_tree_view_set_fixed_height_mode (GTK_TREE_VIEW (treeview), TRUE);
+  gtk_tree_view_set_tooltip_column (GTK_TREE_VIEW (treeview), XFCE_APPFINDER_MODEL_COLUMN_TOOLTIP);
+  g_signal_connect_swapped (GTK_TREE_VIEW (treeview), "row-activated", G_CALLBACK (xfce_appfinder_window_row_activated), window);
+  g_signal_connect_swapped (GTK_TREE_VIEW (treeview), "start-interactive-search", G_CALLBACK (gtk_widget_grab_focus), entry);
+  gtk_drag_source_set (treeview, GDK_BUTTON1_MASK, target_list, G_N_ELEMENTS (target_list), GDK_ACTION_COPY);
+  g_signal_connect (G_OBJECT (treeview), "drag-begin", G_CALLBACK (xfce_appfinder_window_drag_begin), window);
+  g_signal_connect (G_OBJECT (treeview), "drag-data-get", G_CALLBACK (xfce_appfinder_window_drag_data_get), window);
+  gtk_container_add (GTK_CONTAINER (scroll), treeview);
+  gtk_widget_show (treeview);
+  g_object_unref (G_OBJECT (filter_model));
+
+  selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (treeview));
+  gtk_tree_selection_set_mode (selection, GTK_SELECTION_BROWSE);
+  g_signal_connect_swapped (G_OBJECT (selection), "changed",
+      G_CALLBACK (xfce_appfinder_window_item_changed), window);
+
+  column = gtk_tree_view_column_new ();
+  gtk_tree_view_column_set_spacing (column, 2);
+  gtk_tree_view_column_set_sizing (column, GTK_TREE_VIEW_COLUMN_FIXED);
+  gtk_tree_view_append_column (GTK_TREE_VIEW (treeview), GTK_TREE_VIEW_COLUMN (column));
+
+  renderer = gtk_cell_renderer_pixbuf_new ();
+  gtk_tree_view_column_pack_start (GTK_TREE_VIEW_COLUMN (column), renderer, FALSE);
+  gtk_tree_view_column_set_attributes (GTK_TREE_VIEW_COLUMN (column), renderer,
+                                       "pixbuf", XFCE_APPFINDER_MODEL_COLUMN_ICON_SMALL, NULL);
+
+  renderer = gtk_cell_renderer_text_new ();
+  g_object_set (renderer, "ellipsize", PANGO_ELLIPSIZE_END, NULL);
+  gtk_tree_view_column_pack_start (GTK_TREE_VIEW_COLUMN (column), renderer, TRUE);
+  gtk_tree_view_column_set_attributes (GTK_TREE_VIEW_COLUMN (column), renderer,
+                                       "markup", XFCE_APPFINDER_MODEL_COLUMN_ABSTRACT, NULL);
+
+  window->bin_expanded = gtk_alignment_new (0.0, 0.0, 1.0, 1.0);
+  gtk_box_pack_start (GTK_BOX (vbox), window->bin_expanded, FALSE, TRUE, 0);
+  gtk_widget_show (window->bin_expanded);
+
+  window->bbox = bbox = gtk_hbutton_box_new ();
+  gtk_button_box_set_layout (GTK_BUTTON_BOX (bbox), GTK_BUTTONBOX_END);
+  gtk_button_box_set_spacing (GTK_BUTTON_BOX (bbox), 6);
+  gtk_widget_show (bbox);
+
+  button = gtk_button_new_from_stock (GTK_STOCK_CLOSE);
+  gtk_container_add (GTK_CONTAINER (bbox), button);
+  g_signal_connect (G_OBJECT (button), "clicked", G_CALLBACK (gtk_main_quit), NULL);
+  gtk_widget_show (button);
+
+  window->button_launch = button = gtk_button_new_with_mnemonic ("La_unch");
+  gtk_container_add (GTK_CONTAINER (bbox), button);
+  g_signal_connect_swapped (G_OBJECT (button), "clicked", G_CALLBACK (xfce_appfinder_window_execute), window);
+  gtk_widget_set_sensitive (button, FALSE);
+  gtk_widget_show (button);
+
+  image = gtk_image_new_from_stock (GTK_STOCK_EXECUTE, GTK_ICON_SIZE_BUTTON);
+  gtk_button_set_image (GTK_BUTTON (button), image);
+  gtk_widget_show (image);
+
+  g_debug ("constructed window");
+}
+
+
+
+static void
+xfce_appfinder_window_finalize (GObject *object)
+{
+  XfceAppfinderWindow *window = XFCE_APPFINDER_WINDOW (object);
+
+  g_object_unref (G_OBJECT (window->model));
+  g_object_unref (G_OBJECT (window->category_model));
+  g_object_unref (G_OBJECT (window->completion));
+  g_object_unref (G_OBJECT (window->icon_find));
+
+  (*G_OBJECT_CLASS (xfce_appfinder_window_parent_class)->finalize) (object);
+}
+
+
+
+static gboolean
+xfce_appfinder_window_key_press_event (GtkWidget   *widget,
+                                       GdkEventKey *event)
+{
+  if (event->keyval == GDK_Escape)
+    {
+      gtk_main_quit ();
+      return TRUE;
+    }
+
+  return  (*GTK_WIDGET_CLASS (xfce_appfinder_window_parent_class)->key_press_event) (widget, event);
+}
+
+
+
+static gboolean
+xfce_appfinder_window_delete_event (GtkWidget   *widget,
+                                    GdkEventAny *event)
+{
+  /* destroy the window after the main loop */
+  gtk_main_quit ();
+  return TRUE;
+}
+
+
+
+static void
+xfce_appfinder_window_update_image (XfceAppfinderWindow *window,
+                                    GdkPixbuf           *pixbuf)
+{
+  if (pixbuf == NULL)
+    pixbuf = window->icon_find;
+
+  /* gtk doesn't check this */
+  if (gtk_image_get_pixbuf (GTK_IMAGE (window->image)) != pixbuf)
+    gtk_image_set_from_pixbuf (GTK_IMAGE (window->image), pixbuf);
+}
+
+
+
+static void
+xfce_appfinder_window_set_padding (GtkWidget *entry,
+                                   GtkWidget *align)
+{
+  gint padding;
+
+  padding = (ICON_LARGE - entry->allocation.height) / 2;
+  gtk_alignment_set_padding (GTK_ALIGNMENT (align), MAX (0, padding), 0, 0, 0);
+}
+
+
+
+/* TODO idle */
+static void
+xfce_appfinder_window_entry_changed (XfceAppfinderWindow *window)
+{
+  const gchar *text;
+  GdkPixbuf   *pixbuf;
+
+  text = gtk_entry_get_text (GTK_ENTRY (window->entry));
+
+  if (gtk_widget_get_visible (window->paned))
+    {
+      xfce_appfinder_model_filter_string (window->model, text);
+    }
+  else
+    {
+      gtk_widget_set_sensitive (window->button_launch, IS_STRING (text));
+
+      pixbuf = xfce_appfinder_model_get_icon_for_command (window->model, text);
+      xfce_appfinder_window_update_image (window, pixbuf);
+      if (pixbuf != NULL)
+        g_object_unref (G_OBJECT (pixbuf));
+    }
+}
+
+
+
+static void
+xfce_appfinder_window_entry_activate (GtkEditable         *entry,
+                                      XfceAppfinderWindow *window)
+{
+  GtkTreePath *path;
+
+  if (gtk_widget_get_visible (window->paned))
+    {
+      if (gtk_tree_view_get_visible_range (GTK_TREE_VIEW (window->treeview), &path, NULL))
+        {
+          gtk_tree_view_set_cursor (GTK_TREE_VIEW (window->treeview), path, NULL, FALSE);
+          gtk_tree_path_free (path);
+        }
+
+      gtk_widget_grab_focus (window->treeview);
+    }
+  else if (gtk_widget_get_sensitive (window->button_launch))
+    {
+      gtk_button_clicked (GTK_BUTTON (window->button_launch));
+    }
+}
+
+
+
+static gboolean
+xfce_appfinder_window_entry_key_press_event (GtkWidget           *entry,
+                                             GdkEventKey         *event,
+                                             XfceAppfinderWindow *window)
+{
+  gboolean     expand;
+  const gchar *text;
+
+  if (event->keyval == GDK_KEY_Up || event->keyval == GDK_KEY_Down)
+    {
+      /* only switch modes when there is no text in the entry */
+      text = gtk_entry_get_text (GTK_ENTRY (window->entry));
+      if (IS_STRING (text))
+        return FALSE;
+
+      expand = (event->keyval == GDK_KEY_Down);
+      if (gtk_widget_get_visible (window->paned) != expand)
+        {
+          xfce_appfinder_window_set_expanded (window, expand);
+          return TRUE;
+        }
+    }
+
+  return FALSE;
+}
+
+
+
+static void
+xfce_appfinder_window_drag_begin (GtkWidget           *widget,
+                                  GdkDragContext      *drag_context,
+                                  XfceAppfinderWindow *window)
+{
+  GtkTreeSelection *selection;
+  GtkTreeModel     *model;
+  GtkTreeIter       iter;
+  GdkPixbuf        *pixbuf;
+
+  selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (window->treeview));
+  if (gtk_tree_selection_get_selected (selection, &model, &iter))
+    {
+      gtk_tree_model_get (model, &iter, XFCE_APPFINDER_MODEL_COLUMN_ICON_SMALL, &pixbuf, -1);
+      if (G_LIKELY (pixbuf != NULL))
+        {
+          gtk_drag_set_icon_pixbuf (drag_context, pixbuf, 0, 0);
+          g_object_unref (G_OBJECT (pixbuf));
+        }
+    }
+  else
+    {
+      gtk_drag_set_icon_stock (drag_context, GTK_STOCK_DIALOG_ERROR, 0, 0);
+    }
+}
+
+
+
+static void
+xfce_appfinder_window_drag_data_get (GtkWidget           *widget,
+                                     GdkDragContext      *drag_context,
+                                     GtkSelectionData    *data,
+                                     guint                info,
+                                     guint                drag_time,
+                                     XfceAppfinderWindow *window)
+{
+  GtkTreeSelection *selection;
+  GtkTreeModel     *model;
+  GtkTreeIter       iter;
+  gchar            *uris[2];
+
+  selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (window->treeview));
+  if (gtk_tree_selection_get_selected (selection, &model, &iter))
+    {
+      uris[1] = NULL;
+      gtk_tree_model_get (model, &iter, XFCE_APPFINDER_MODEL_COLUMN_URI, &uris[0], -1);
+      gtk_selection_data_set_uris (data, uris);
+      g_free (uris[0]);
+    }
+}
+
+
+
+static void
+xfce_appfinder_window_entry_icon_released (GtkEntry             *entry,
+                                           GtkEntryIconPosition  icon_pos,
+                                           GdkEvent             *event,
+                                           XfceAppfinderWindow  *window)
+{
+  if (icon_pos == GTK_ENTRY_ICON_SECONDARY)
+    xfce_appfinder_window_set_expanded (window, !gtk_widget_get_visible (window->paned));
+}
+
+
+
+static void
+xfce_appfinder_window_category_changed (GtkTreeSelection    *selection,
+                                        XfceAppfinderWindow *window)
+{
+  GtkTreeIter   iter;
+  GtkTreeModel *model;
+  gchar        *category;
+
+  if (gtk_tree_selection_get_selected (selection, &model, &iter))
+    {
+      gtk_tree_model_get (model, &iter, XFCE_APPFINDER_CATEGORY_MODEL_COLUMN_NAME, &category, -1);
+
+      if (g_utf8_collate (category, _("All Applications")) == 0)
+        xfce_appfinder_model_filter_category (window->model, NULL);
+      else if (g_utf8_collate (category, _("Commands History")) == 0)
+        xfce_appfinder_model_filter_category (window->model, "\0");
+      else
+        xfce_appfinder_model_filter_category (window->model, category);
+
+      g_free (category);
+    }
+}
+
+
+
+static void
+xfce_appfinder_window_item_changed (XfceAppfinderWindow *window)
+{
+  GtkTreeIter       iter;
+  GtkTreeModel     *model;
+  gboolean          can_launch;
+  GtkTreeSelection *selection;
+  GdkPixbuf        *pixbuf;
+
+  if (gtk_widget_get_visible (window->paned))
+    {
+      selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (window->treeview));
+      can_launch = gtk_tree_selection_get_selected (selection, &model, &iter);
+      gtk_widget_set_sensitive (window->button_launch, can_launch);
+
+      if (can_launch)
+        {
+          gtk_tree_model_get (model, &iter, XFCE_APPFINDER_MODEL_COLUMN_ICON_LARGE, &pixbuf, -1);
+          if (G_LIKELY (pixbuf != NULL))
+            {
+              xfce_appfinder_window_update_image (window, pixbuf);
+              g_object_unref (G_OBJECT (pixbuf));
+            }
+        }
+      else
+        {
+          xfce_appfinder_window_update_image (window, NULL);
+        }
+    }
+}
+
+
+
+static void
+xfce_appfinder_window_row_activated (XfceAppfinderWindow *window)
+{
+  if (gtk_widget_get_sensitive (window->button_launch))
+    gtk_button_clicked (GTK_BUTTON (window->button_launch));
+}
+
+
+
+static gboolean
+xfce_appfinder_window_execute_command (const gchar  *cmd,
+                                       GdkScreen    *screen,
+                                       GError      **error)
+{
+  gboolean          in_terminal;
+  gchar            *cmdline, *exo_open;
+  const gchar      *exo_open_prefix[] = { "file://", "http://", "https://" };
+  guint             i;
+  gboolean          result = FALSE;
+
+  if (g_str_has_prefix (cmd, "#"))
+    {
+      /* open manual page in the terminal */
+      cmdline = g_strconcat ("man ", cmd + 1, NULL);
+      in_terminal = TRUE;
+    }
+  else if (g_str_has_prefix (cmd, "$"))
+    {
+      /* open in the terminal */
+      cmdline = xfce_expand_variables (cmd + 1, NULL);
+      in_terminal = TRUE;
+    }
+  else
+    {
+      cmdline = xfce_expand_variables (cmd, NULL);
+      in_terminal = FALSE;
+    }
+
+  result = xfce_spawn_command_line_on_screen (screen, cmdline, in_terminal, FALSE, error);
+  if (!result)
+    {
+      /* TODO instead check the exo exit code */
+      /* check if this is something exo-open can handle */
+      for (i = 0; !result && i < G_N_ELEMENTS (exo_open_prefix); i++)
+        if (g_str_has_prefix (cmdline, exo_open_prefix[i]))
+          result = TRUE;
+
+      if (result)
+        {
+          /* try to spawn again */
+          exo_open = g_strconcat ("exo-open ", cmdline, NULL);
+          result = xfce_spawn_command_line_on_screen (screen, exo_open, FALSE, FALSE, error);
+          g_free (exo_open);
+        }
+    }
+
+  g_free (cmdline);
+
+  return result;
+}
+
+
+
+static void
+xfce_appfinder_window_execute (XfceAppfinderWindow *window)
+{
+  GtkTreeSelection *selection;
+  GtkTreeModel     *model;
+  GtkTreeIter       iter, orig;
+  GError           *error = NULL;
+  gboolean          result = FALSE;
+  GdkScreen        *screen;
+  const gchar      *text;
+  gchar            *cmd = NULL;
+  gboolean          regular_command = FALSE;
+
+  if (!gtk_widget_get_sensitive (window->button_launch))
+    return;
+
+  screen = gtk_window_get_screen (GTK_WINDOW (window));
+  if (gtk_widget_get_visible (window->paned))
+    {
+      selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (window->treeview));
+      if (gtk_tree_selection_get_selected (selection, &model, &iter))
+        {
+          gtk_tree_model_filter_convert_iter_to_child_iter (GTK_TREE_MODEL_FILTER (model), &orig, &iter);
+          result = xfce_appfinder_model_execute (window->model, &orig, screen, &regular_command, &error);
+
+         if (!result && regular_command)
+            {
+              gtk_tree_model_get (model, &iter, XFCE_APPFINDER_MODEL_COLUMN_COMMAND, &cmd, -1);
+              result = xfce_appfinder_window_execute_command (cmd, screen, &error);
+              g_free (cmd);
+            }
+        }
+    }
+  else
+    {
+      text = gtk_entry_get_text (GTK_ENTRY (window->entry));
+      if (xfce_appfinder_window_execute_command (text, screen, &error))
+        result = xfce_appfinder_model_save_command (window->model, text, &error);
+    }
+
+  gtk_entry_set_icon_from_stock (GTK_ENTRY (window->entry), GTK_ENTRY_ICON_PRIMARY,
+                                 result ? NULL : GTK_STOCK_DIALOG_ERROR);
+  gtk_entry_set_icon_tooltip_text (GTK_ENTRY (window->entry), GTK_ENTRY_ICON_PRIMARY,
+                                   error != NULL ? error->message : NULL);
+
+  if (error != NULL)
+    {
+      g_warning ("Failed to execute: %s", error->message);
+      g_error_free (error);
+    }
+
+  if (result)
+    gtk_main_quit ();
+}
+
+
+
+GtkWidget *
+xfce_appfinder_window_new (void)
+{
+  return g_object_new (XFCE_TYPE_APPFINDER_WINDOW, NULL);
+}
+
+
+
+void
+xfce_appfinder_window_set_expanded (XfceAppfinderWindow *window,
+                                    gboolean             expanded)
+{
+  GdkGeometry         hints;
+  gint                width;
+  GtkWidget          *parent;
+  GtkEntryCompletion *completion;
+
+  g_debug ("set expand = %s", expanded ? "true" : "false");
+
+  /* force window geomentry */
+  if (expanded)
+    {
+      gtk_window_set_geometry_hints (GTK_WINDOW (window), NULL, NULL, 0);
+      gtk_window_get_size (GTK_WINDOW (window), &width, NULL);
+      gtk_window_resize (GTK_WINDOW (window), width, window->last_window_height);
+    }
+  else
+    {
+      if (gtk_widget_get_visible (GTK_WIDGET (window)))
+        gtk_window_get_size (GTK_WINDOW (window), NULL, &window->last_window_height);
+
+      hints.max_height = -1;
+      hints.max_width = G_MAXINT;
+      gtk_window_set_geometry_hints (GTK_WINDOW (window), NULL, &hints, GDK_HINT_MAX_SIZE);
+    }
+
+  /* repack the button box */
+  g_object_ref (G_OBJECT (window->bbox));
+  parent = gtk_widget_get_parent (window->bbox);
+  if (parent != NULL)
+    gtk_container_remove (GTK_CONTAINER (parent), window->bbox);
+  if (expanded)
+    gtk_container_add (GTK_CONTAINER (window->bin_expanded), window->bbox);
+  else
+    gtk_container_add (GTK_CONTAINER (window->bin_collapsed), window->bbox);
+  gtk_widget_set_visible (window->bin_expanded, expanded);
+  gtk_widget_set_visible (window->bin_collapsed, !expanded);
+  g_object_unref (G_OBJECT (window->bbox));
+
+  /* show/hide pane with treeviews */
+  gtk_widget_set_visible (window->paned, expanded);
+
+  /* toggle icon */
+  gtk_entry_set_icon_from_icon_name (GTK_ENTRY (window->entry), GTK_ENTRY_ICON_SECONDARY,
+                                     expanded ? GTK_STOCK_GO_UP : GTK_STOCK_GO_DOWN);
+  gtk_entry_set_icon_from_icon_name (GTK_ENTRY (window->entry), GTK_ENTRY_ICON_PRIMARY, NULL);
+
+  /* update completion (remove completed text of restart completion) */
+  completion = gtk_entry_get_completion (GTK_ENTRY (window->entry));
+  if (completion != NULL)
+    gtk_editable_delete_selection (GTK_EDITABLE (window->entry));
+  gtk_entry_set_completion (GTK_ENTRY (window->entry), expanded ? NULL : window->completion);
+  if (!expanded)
+    gtk_entry_completion_insert_prefix (window->completion);
+
+  /* update state */
+  xfce_appfinder_window_entry_changed (window);
+  xfce_appfinder_window_item_changed (window);
+}
diff --git a/src/xfce-appfinder-window.h b/src/appfinder-window.h
similarity index 68%
rename from src/xfce-appfinder-window.h
rename to src/appfinder-window.h
index 6107f1d..f100f66 100644
--- a/src/xfce-appfinder-window.h
+++ b/src/appfinder-window.h
@@ -1,21 +1,19 @@
-/* vi:set sw=2 sts=2 ts=2 et ai: */
-/*-
- * Copyright (c) 2008 Jannis Pohlmann <jannis at xfce.org>.
+/*
+ * Copyright (C) 2011 Nick Schermer <nick at xfce.org>
  *
  * 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.
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
  *
- * This program 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.
+ * This program 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.
  *
- * 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., 59 Temple Place, Suite 330, Boston,
- * MA  02111-1307  USA
+ * 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.
  */
 
 #ifndef __XFCE_APPFINDER_WINDOW_H__
@@ -35,11 +33,14 @@ typedef struct _XfceAppfinderWindow      XfceAppfinderWindow;
 #define XFCE_IS_APPFINDER_WINDOW_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), XFCE_TYPE_APPFINDER_WINDOW))
 #define XFCE_APPFINDER_WINDOW_GET_CLASS(obj)  (G_TYPE_INSTANCE_GET_CLASS ((obj), XFCE_TYPE_APPFINDER_WINDOW, XfceAppfinderWindowClass))
 
-GType     xfce_appfinder_window_get_type (void) G_GNUC_CONST;
+GType      xfce_appfinder_window_get_type     (void) G_GNUC_CONST;
 
-GtkWidget *xfce_appfinder_window_new     (const gchar         *filename) G_GNUC_MALLOC;
-void       xfce_appfinder_window_reload  (XfceAppfinderWindow *window);
+GtkWidget *xfce_appfinder_window_new          (void) G_GNUC_MALLOC;
+
+void       xfce_appfinder_window_set_expanded (XfceAppfinderWindow *window,
+                                               gboolean             expanded);
 
 G_END_DECLS
 
 #endif /* !__XFCE_APPFINDER_WINDOW_H__ */
+
diff --git a/src/frap-icon-entry.c b/src/frap-icon-entry.c
deleted file mode 100644
index 93adcb4..0000000
--- a/src/frap-icon-entry.c
+++ /dev/null
@@ -1,590 +0,0 @@
-/* $Id$ */
-/*-
- * Copyright (c) 2005-2006 Benedikt Meurer <benny at xfce.org>
- *
- * 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 program 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.
- *
- * 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., 59 Temple
- * Place, Suite 330, Boston, MA  02111-1307  USA
- *
- * Based on the ThunarPathEntry class, which is part of the Thunar file manager,
- * Copyright (c) 2004-2006 Benedikt Meurer <benny at xfce.org>.
- */
-
-#ifdef HAVE_CONFIG_H
-#include <config.h>
-#endif
-
-#include "frap-icon-entry.h"
-
-#if !GTK_CHECK_VERSION (2, 16, 0)
-
-/* the margin around the icon */
-#define FRAP_ICON_ENTRY_ICON_MARGIN (2)
-
-
-
-#define FRAP_ICON_ENTRY_GET_PRIVATE(obj) (G_TYPE_INSTANCE_GET_PRIVATE ((obj), FRAP_TYPE_ICON_ENTRY, FrapIconEntryPrivate))
-
-
-
-/* Property identifiers */
-enum
-{
-  PROP_0,
-  PROP_SIZE,
-  PROP_STOCK_ID,
-};
-
-
-
-static void     frap_icon_entry_finalize            (GObject            *object);
-static void     frap_icon_entry_get_property        (GObject            *object,
-                                                     guint               prop_id,
-                                                     GValue             *value,
-                                                     GParamSpec         *pspec);
-static void     frap_icon_entry_set_property        (GObject            *object,
-                                                     guint               prop_id,
-                                                     const GValue       *value,
-                                                     GParamSpec         *pspec);
-static void     frap_icon_entry_size_request        (GtkWidget          *widget,
-                                                     GtkRequisition     *requisition);
-static void     frap_icon_entry_size_allocate       (GtkWidget          *widget,
-                                                     GtkAllocation      *allocation);
-static void     frap_icon_entry_realize             (GtkWidget          *widget);
-static void     frap_icon_entry_unrealize           (GtkWidget          *widget);
-static gboolean frap_icon_entry_expose_event        (GtkWidget          *widget,
-                                                     GdkEventExpose     *event);
-static void     frap_icon_entry_get_borders         (FrapIconEntry      *icon_entry,
-                                                     gint               *xborder_return,
-                                                     gint               *yborder_return);
-static void     frap_icon_entry_get_text_area_size  (FrapIconEntry      *icon_entry,
-                                                     gint               *x_return,
-                                                     gint               *y_return,
-                                                     gint               *width_return,
-                                                     gint               *height_return);
-
-
-
-struct _FrapIconEntryPrivate
-{
-  GtkIconSize size;
-  gchar      *stock_id;
-};
-
-
-
-G_DEFINE_TYPE (FrapIconEntry,
-               frap_icon_entry,
-               GTK_TYPE_ENTRY);
-
-
-
-static void
-frap_icon_entry_class_init (FrapIconEntryClass *klass)
-{
-  GtkWidgetClass *gtkwidget_class;
-  GObjectClass   *gobject_class;
-
-  /* add the private instance data */
-  g_type_class_add_private (klass, sizeof (FrapIconEntryPrivate));
-
-  gobject_class = G_OBJECT_CLASS (klass);
-  gobject_class->finalize = frap_icon_entry_finalize;
-  gobject_class->get_property = frap_icon_entry_get_property;
-  gobject_class->set_property = frap_icon_entry_set_property;
-
-  gtkwidget_class = GTK_WIDGET_CLASS (klass);
-  gtkwidget_class->size_request = frap_icon_entry_size_request;
-  gtkwidget_class->size_allocate = frap_icon_entry_size_allocate;
-  gtkwidget_class->realize = frap_icon_entry_realize;
-  gtkwidget_class->unrealize = frap_icon_entry_unrealize;
-  gtkwidget_class->expose_event = frap_icon_entry_expose_event;
-
-  /**
-   * FrapIconEntry:size:
-   *
-   * The #GtkIconSize for the icon in this entry.
-   **/
-  g_object_class_install_property (gobject_class,
-                                   PROP_SIZE,
-                                   g_param_spec_enum ("size",
-                                                      "Size",
-                                                      "The size of the icon in the entry",
-                                                      GTK_TYPE_ICON_SIZE,
-                                                      GTK_ICON_SIZE_MENU,
-                                                      G_PARAM_CONSTRUCT | G_PARAM_READWRITE));
-
-  /**
-   * FrapIconEntry:stock-id:
-   *
-   * The stock-id of the icon to render, or %NULL if no
-   * icon should be rendered.
-   **/
-  g_object_class_install_property (gobject_class,
-                                   PROP_STOCK_ID,
-                                   g_param_spec_string ("stock-id",
-                                                        "Stock Id",
-                                                        "The stock-id of the icon in the entry",
-                                                        NULL,
-                                                        G_PARAM_READWRITE));
-}
-
-
-
-static void
-frap_icon_entry_init (FrapIconEntry *icon_entry)
-{
-  icon_entry->priv = FRAP_ICON_ENTRY_GET_PRIVATE (icon_entry);
-}
-
-
-
-static void
-frap_icon_entry_finalize (GObject *object)
-{
-  FrapIconEntry *icon_entry = FRAP_ICON_ENTRY (object);
-
-  /* release the stock-id if any */
-  g_free (icon_entry->priv->stock_id);
-
-  (*G_OBJECT_CLASS (frap_icon_entry_parent_class)->finalize) (object);
-}
-
-
-
-static void
-frap_icon_entry_get_property (GObject    *object,
-                              guint       prop_id,
-                              GValue     *value,
-                              GParamSpec *pspec)
-{
-  FrapIconEntry *icon_entry = FRAP_ICON_ENTRY (object);
-
-  switch (prop_id)
-    {
-    case PROP_SIZE:
-      g_value_set_enum (value, frap_icon_entry_get_size (icon_entry));
-      break;
-
-    case PROP_STOCK_ID:
-      g_value_set_string (value, frap_icon_entry_get_stock_id (icon_entry));
-      break;
-
-    default:
-      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
-      break;
-    }
-}
-
-
-
-static void
-frap_icon_entry_set_property (GObject      *object,
-                              guint         prop_id,
-                              const GValue *value,
-                              GParamSpec   *pspec)
-{
-  FrapIconEntry *icon_entry = FRAP_ICON_ENTRY (object);
-
-  switch (prop_id)
-    {
-    case PROP_SIZE:
-      frap_icon_entry_set_size (icon_entry, g_value_get_enum (value));
-      break;
-
-    case PROP_STOCK_ID:
-      frap_icon_entry_set_stock_id (icon_entry, g_value_get_string (value));
-      break;
-
-    default:
-      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
-      break;
-    }
-}
-
-
-
-static void
-frap_icon_entry_size_request (GtkWidget      *widget,
-                              GtkRequisition *requisition)
-{
-  FrapIconEntry *icon_entry = FRAP_ICON_ENTRY (widget);
-  gint           text_height;
-  gint           icon_height;
-  gint           icon_width;
-  gint           xborder;
-  gint           yborder;
-
-  /* determine the size request of the text entry */
-  (*GTK_WIDGET_CLASS (frap_icon_entry_parent_class)->size_request) (widget, requisition);
-
-  /* lookup the icon dimensions */
-  gtk_icon_size_lookup (icon_entry->priv->size, &icon_width, &icon_height);
-
-  /* determine the text area size */
-  frap_icon_entry_get_text_area_size (icon_entry, &xborder, &yborder, NULL, &text_height);
-
-  /* adjust the requisition */
-  requisition->width += icon_width + xborder + 2 * FRAP_ICON_ENTRY_ICON_MARGIN;
-  requisition->height = 2 * yborder + MAX (icon_height + 2 * FRAP_ICON_ENTRY_ICON_MARGIN, text_height);
-}
-
-
-
-static void
-frap_icon_entry_size_allocate (GtkWidget     *widget,
-                               GtkAllocation *allocation)
-{
-  FrapIconEntry *icon_entry = FRAP_ICON_ENTRY (widget);
-  GtkAllocation  text_allocation;
-  GtkAllocation  icon_allocation;
-  gint           text_height;
-  gint           icon_height;
-  gint           icon_width;
-  gint           xborder;
-  gint           yborder;
-
-  /* lookup the icon dimensions */
-  gtk_icon_size_lookup (icon_entry->priv->size, &icon_width, &icon_height);
-
-  /* determine the text area size */
-  frap_icon_entry_get_text_area_size (icon_entry, &xborder, &yborder, NULL, &text_height);
-
-  /* calculate the base text allocation */
-  text_allocation.y = yborder;
-  text_allocation.width = allocation->width - icon_width - 2 * (xborder + FRAP_ICON_ENTRY_ICON_MARGIN);
-  text_allocation.height = text_height;
-
-  /* calculate the base icon allocation */
-  icon_allocation.y = yborder;
-  icon_allocation.width = icon_width + 2 * FRAP_ICON_ENTRY_ICON_MARGIN;
-  icon_allocation.height = MAX (icon_height + 2 * FRAP_ICON_ENTRY_ICON_MARGIN, text_height);
-
-  /* the x offset depends on the text direction */
-  if (gtk_widget_get_direction (widget) == GTK_TEXT_DIR_RTL)
-    {
-      text_allocation.x = xborder;
-      icon_allocation.x = allocation->width - icon_allocation.width - xborder - 2 * FRAP_ICON_ENTRY_ICON_MARGIN;
-    }
-  else
-    {
-      icon_allocation.x = xborder;
-      text_allocation.x = allocation->width - text_allocation.width - xborder;
-    }
-
-  /* setup the text area */
-  (*GTK_WIDGET_CLASS (frap_icon_entry_parent_class)->size_allocate) (widget, allocation);
-
-  /* adjust the dimensions/positions of the areas */
-  if (GTK_WIDGET_REALIZED (widget))
-    {
-      gdk_window_move_resize (GTK_ENTRY (icon_entry)->text_area,
-                              text_allocation.x,
-                              text_allocation.y,
-                              text_allocation.width,
-                              text_allocation.height);
-
-      gdk_window_move_resize (icon_entry->icon_area,
-                              icon_allocation.x,
-                              icon_allocation.y,
-                              icon_allocation.width,
-                              icon_allocation.height);
-    }
-}
-
-
-
-static void
-frap_icon_entry_realize (GtkWidget *widget)
-{
-  FrapIconEntry *icon_entry = FRAP_ICON_ENTRY (widget);
-  GdkWindowAttr  attributes;
-  gint           attributes_mask;
-  gint           text_height;
-  gint           icon_height;
-  gint           icon_width;
-  gint           spacing;
-
-  /* let GtkEntry handle the realization of the text area */
-  (*GTK_WIDGET_CLASS (frap_icon_entry_parent_class)->realize) (widget);
-
-  /* lookup the icon dimensions */
-  gtk_icon_size_lookup (icon_entry->priv->size, &icon_width, &icon_height);
-
-  /* determine the spacing for the icon area */
-  frap_icon_entry_get_text_area_size (icon_entry, NULL, NULL, NULL, &text_height);
-  spacing = widget->requisition.height - text_height;
-
-  /* setup the icon_area attributes */
-  attributes.window_type = GDK_WINDOW_CHILD;
-  attributes.wclass = GDK_INPUT_OUTPUT;
-  attributes.visual = gtk_widget_get_visual (widget);
-  attributes.colormap = gtk_widget_get_colormap (widget);
-  attributes.event_mask = gtk_widget_get_events (widget)
-                        | GDK_EXPOSURE_MASK;
-  attributes.x = widget->allocation.x + widget->allocation.width - icon_width - spacing;
-  attributes.y = widget->allocation.y + (widget->allocation.height - widget->requisition.height) / 2;
-  attributes.width = icon_width + spacing;
-  attributes.height = widget->requisition.height;
-  attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL | GDK_WA_COLORMAP;
-
-  /* setup the window for the icon area */
-  icon_entry->icon_area = gdk_window_new (widget->window, &attributes, attributes_mask);
-  gdk_window_set_user_data (icon_entry->icon_area, widget);
-  gdk_window_set_background (icon_entry->icon_area, &widget->style->base[GTK_WIDGET_STATE (widget)]);
-  gdk_window_show (icon_entry->icon_area);
-
-  /* need to resize the text_area afterwards */
-  gtk_widget_queue_resize (widget);
-}
-
-
-
-static void
-frap_icon_entry_unrealize (GtkWidget *widget)
-{
-  FrapIconEntry *icon_entry = FRAP_ICON_ENTRY (widget);
-
-  /* destroy the icon_area */
-  gdk_window_set_user_data (icon_entry->icon_area, NULL);
-  gdk_window_destroy (icon_entry->icon_area);
-  icon_entry->icon_area = NULL;
-
-  (*GTK_WIDGET_CLASS (frap_icon_entry_parent_class)->unrealize) (widget);
-}
-
-
-
-static gboolean
-frap_icon_entry_expose_event (GtkWidget      *widget,
-                              GdkEventExpose *event)
-{
-  FrapIconEntry *icon_entry = FRAP_ICON_ENTRY (widget);
-  GdkPixbuf     *icon;
-  gint           icon_height;
-  gint           icon_width;
-  gint           height;
-  gint           width;
-
-  /* check if the expose is on the icon_area */
-  if (event->window == icon_entry->icon_area)
-    {
-      /* determine the size of the icon_area */
-      gdk_drawable_get_size (GDK_DRAWABLE (icon_entry->icon_area), &width, &height);
-
-      /* clear the icon area */
-      gtk_paint_flat_box (widget->style, icon_entry->icon_area,
-                          GTK_WIDGET_STATE (widget), GTK_SHADOW_NONE,
-                          NULL, widget, "entry_bg", 0, 0, width, height);
-
-      /* check if a stock-id is set */
-      if (G_LIKELY (icon_entry->priv->stock_id != NULL))
-        {
-          /* try to render the icon for the stock-id */
-          icon = gtk_widget_render_icon (widget, icon_entry->priv->stock_id, icon_entry->priv->size, "icon_entry");
-          if (G_LIKELY (icon != NULL))
-            {
-              /* determine the dimensions of the icon */
-              icon_width = gdk_pixbuf_get_width (icon);
-              icon_height = gdk_pixbuf_get_height (icon);
-
-              /* draw the icon */
-              gdk_draw_pixbuf (icon_entry->icon_area,
-                               widget->style->black_gc,
-                               icon, 0, 0,
-                               (width - icon_width) / 2,
-                               (height - icon_height) / 2,
-                               icon_width, icon_height,
-                               GDK_RGB_DITHER_NORMAL, 0, 0);
-
-              /* release the icon */
-              g_object_unref (G_OBJECT (icon));
-            }
-        }
-    }
-  else
-    {
-      /* the expose is probably for the text_area */
-      return (*GTK_WIDGET_CLASS (frap_icon_entry_parent_class)->expose_event) (widget, event);
-    }
-
-  return TRUE;
-}
-
-
-
-static void
-frap_icon_entry_get_borders (FrapIconEntry *icon_entry,
-                             gint          *xborder_return,
-                             gint          *yborder_return)
-{
-  gboolean interior_focus;
-  gint     focus_width;
-
-  gtk_widget_style_get (GTK_WIDGET (icon_entry),
-                        "focus-line-width", &focus_width,
-                        "interior-focus", &interior_focus,
-                        NULL);
-
-  if (gtk_entry_get_has_frame (GTK_ENTRY (icon_entry)))
-    {
-      *xborder_return = GTK_WIDGET (icon_entry)->style->xthickness;
-      *yborder_return = GTK_WIDGET (icon_entry)->style->ythickness;
-    }
-  else
-    {
-      *xborder_return = 0;
-      *yborder_return = 0;
-    }
-
-  if (!interior_focus)
-    {
-      *xborder_return += focus_width;
-      *yborder_return += focus_width;
-    }
-}
-
-
-
-static void
-frap_icon_entry_get_text_area_size (FrapIconEntry *icon_entry,
-                                    gint          *x_return,
-                                    gint          *y_return,
-                                    gint          *width_return,
-                                    gint          *height_return)
-{
-  GtkRequisition requisition;
-  gint           xborder;
-  gint           yborder;
-
-  gtk_widget_get_child_requisition (GTK_WIDGET (icon_entry), &requisition);
-
-  frap_icon_entry_get_borders (icon_entry, &xborder, &yborder);
-
-  if (x_return != NULL) *x_return = xborder;
-  if (y_return != NULL) *y_return = yborder;
-  if (width_return  != NULL) *width_return  = GTK_WIDGET (icon_entry)->allocation.width - xborder * 2;
-  if (height_return != NULL) *height_return = requisition.height - yborder * 2;
-}
-
-
-
-/**
- * frap_icon_entry_new:
- *
- * Allocates a new #FrapIconEntry instance.
- *
- * Return value: the newly allocated #FrapIconEntry.
- **/
-GtkWidget*
-frap_icon_entry_new (void)
-{
-  return g_object_new (FRAP_TYPE_ICON_ENTRY, NULL);
-}
-
-
-
-/**
- * frap_icon_entry_get_size:
- * @icon_entry : a #FrapIconEntry.
- *
- * Returns the #GtkIconSize that is currently set for the
- * @icon_entry.
- *
- * Return value: the icon size for the @icon_entry.
- **/
-GtkIconSize
-frap_icon_entry_get_size (FrapIconEntry *icon_entry)
-{
-  g_return_val_if_fail (FRAP_IS_ICON_ENTRY (icon_entry), GTK_ICON_SIZE_INVALID);
-  return icon_entry->priv->size;
-}
-
-
-
-/**
- * frap_icon_entry_set_size:
- * @icon_entry : a #FrapIconEntry.
- * @size       : the new icon size for the @icon_entry.
- *
- * Sets the size at which the icon of the @icon_entry is drawn
- * to @size.
- **/
-void
-frap_icon_entry_set_size (FrapIconEntry *icon_entry,
-                          GtkIconSize    size)
-{
-  g_return_if_fail (FRAP_IS_ICON_ENTRY (icon_entry));
-
-  /* check if we have a new setting */
-  if (G_LIKELY (icon_entry->priv->size != size))
-    {
-      /* apply the new setting */
-      icon_entry->priv->size = size;
-
-      /* notify listeners */
-      g_object_notify (G_OBJECT (icon_entry), "size");
-
-      /* schedule a resize */
-      gtk_widget_queue_resize (GTK_WIDGET (icon_entry));
-    }
-}
-
-
-
-/**
- * frap_icon_entry_get_stock_id:
- * @icon_entry : a #FrapIconEntry.
- *
- * Returns the stock-id that is currently set for the @icon_entry
- * or %NULL if no stock-id is set.
- *
- * Return value: the stock-id for the @icon_entry.
- **/
-const gchar*
-frap_icon_entry_get_stock_id (FrapIconEntry *icon_entry)
-{
-  g_return_val_if_fail (FRAP_IS_ICON_ENTRY (icon_entry), NULL);
-  return icon_entry->priv->stock_id;
-}
-
-
-
-/**
- * frap_icon_entry_set_stock_id:
- * @icon_entry : a #FrapIconEntry.
- * @stock_id   : the new stock-id or %NULL to reset.
- *
- * Sets the stock-id of the icon to be drawn in the @icon_entry to
- * @stock_id.
- **/
-void
-frap_icon_entry_set_stock_id (FrapIconEntry *icon_entry,
-                              const gchar   *stock_id)
-{
-  g_return_if_fail (FRAP_IS_ICON_ENTRY (icon_entry));
-
-  /* release the previous stock-id */
-  g_free (icon_entry->priv->stock_id);
-
-  /* apply the new stock-id */
-  icon_entry->priv->stock_id = g_strdup (stock_id);
-
-  /* notify listeners */
-  g_object_notify (G_OBJECT (icon_entry), "stock-id");
-
-  /* schedule a resize */
-  gtk_widget_queue_resize (GTK_WIDGET (icon_entry));
-}
-
-#endif /* !GTK_CHECK_VERSION (2, 16, 0) */
diff --git a/src/frap-icon-entry.h b/src/frap-icon-entry.h
deleted file mode 100644
index 16049ae..0000000
--- a/src/frap-icon-entry.h
+++ /dev/null
@@ -1,64 +0,0 @@
-/* $Id$ */
-/*-
- * Copyright (c) 2005-2006 Benedikt Meurer <benny at xfce.org>
- *
- * 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 program 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.
- *
- * 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., 59 Temple
- * Place, Suite 330, Boston, MA  02111-1307  USA
- */
-
-#ifndef __FRAP_ICON_ENTRY_H__
-#define __FRAP_ICON_ENTRY_H__
-
-#include <gtk/gtk.h>
-
-G_BEGIN_DECLS;
-
-typedef struct _FrapIconEntryPrivate FrapIconEntryPrivate;
-typedef struct _FrapIconEntryClass   FrapIconEntryClass;
-typedef struct _FrapIconEntry        FrapIconEntry;
-
-#define FRAP_TYPE_ICON_ENTRY            (frap_icon_entry_get_type ())
-#define FRAP_ICON_ENTRY(obj)            (G_TYPE_CHECK_INSTANCE_CAST ((obj), FRAP_TYPE_ICON_ENTRY, FrapIconEntry))
-#define FRAP_ICON_ENTRY_CLASS(klass)    (G_TYPE_CHECK_CLASS_CAST ((klass), FRAP_TYPE_ICON_ENTRY, FrapIconEntryClass))
-#define FRAP_IS_ICON_ENTRY(obj)         (G_TYPE_CHECK_INSTANCE_TYPE ((obj), FRAP_TYPE_ICON_ENTRY))
-#define FRAP_IS_ICON_ENTRY_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), FRAP_TYPE_ICON_ENTRY))
-#define FRAP_ICON_ENTRY_GET_CLASS(obj)  (G_TYPE_INSTANCE_GET_CLASS ((obj), FRAP_TYPE_ICON_ENTRY, FrapIconEntryClass))
-
-struct _FrapIconEntryClass
-{
-  GtkEntryClass __parent__;
-};
-
-struct _FrapIconEntry
-{
-  GtkEntry              __parent__;
-  GdkWindow            *icon_area;
-  FrapIconEntryPrivate *priv;
-};
-
-GType        frap_icon_entry_get_type     (void) G_GNUC_CONST;
-
-GtkWidget   *frap_icon_entry_new          (void) G_GNUC_MALLOC;
-
-GtkIconSize  frap_icon_entry_get_size     (FrapIconEntry *icon_entry);
-void         frap_icon_entry_set_size     (FrapIconEntry *icon_entry,
-                                           GtkIconSize    size);
-
-const gchar *frap_icon_entry_get_stock_id (FrapIconEntry *icon_entry);
-void         frap_icon_entry_set_stock_id (FrapIconEntry *icon_entry,
-                                           const gchar   *stock_id);
-
-G_END_DECLS;
-
-#endif /* !__FRAP_ICON_ENTRY_H__ */
diff --git a/src/main.c b/src/main.c
index 148299e..0e8c0a9 100644
--- a/src/main.c
+++ b/src/main.c
@@ -1,21 +1,19 @@
-/* vi:set sw=2 sts=2 ts=2 et ai: */
-/*-
- * Copyright (c) 2008 Jannis Pohlmann <jannis at xfce.org>.
+/*
+ * Copyright (C) 2011 Nick Schermer <nick at xfce.org>
  *
  * 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.
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
  *
- * This program 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.
+ * This program 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.
  *
- * 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., 59 Temple Place, Suite 330, Boston,
- * MA  02111-1307  USA
+ * 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.
  */
 
 #ifdef HAVE_CONFIG_H
@@ -27,56 +25,62 @@
 #endif
 
 #include <gtk/gtk.h>
-
 #include <libxfce4util/libxfce4util.h>
 #include <garcon/garcon.h>
-#include <xfconf/xfconf.h>
 
-#include "xfce-appfinder-window.h"
+#include <src/appfinder-window.h>
+
+
+
+static gboolean  opt_finder = FALSE;
+static gboolean  opt_version = FALSE;
+static gchar    *opt_filename = NULL;
 
 
 
-static gboolean     opt_version = FALSE;
-static gchar      **opt_remaining = NULL;
-static GOptionEntry opt_entries[] = {
-  { "version", 'V', G_OPTION_FLAG_IN_MAIN, G_OPTION_ARG_NONE, &opt_version, N_("Version information"), NULL },
-  { G_OPTION_REMAINING, 0, G_OPTION_FLAG_IN_MAIN, G_OPTION_ARG_FILENAME_ARRAY, &opt_remaining, NULL, N_("[MENUFILE]") },
+static GOptionEntry option_entries[] =
+{
+  { "finder", '\0', 0, G_OPTION_ARG_NONE, &opt_finder, N_("Start in expanded mode"), NULL },
+  { "version", 'V', 0, G_OPTION_ARG_NONE, &opt_version, N_("Print version information and exit"), NULL },
+  { G_OPTION_REMAINING, '\0', 0, G_OPTION_ARG_FILENAME, &opt_filename, NULL, NULL },
+  { NULL }
 };
 
 
 
-int
-main (int    argc,
-      char **argv)
+gint
+main (gint argc, gchar **argv)
 {
-  GtkWidget *window;
-  GError    *error = NULL;
+  GError      *error = NULL;
+  GtkWidget   *window;
+  const gchar *desktop;
 
-  /* Set up translation domain */
+  /* set translation domain */
   xfce_textdomain (GETTEXT_PACKAGE, PACKAGE_LOCALE_DIR, "UTF-8");
 
-  /* Initialize GTK+ and parse command line options */
-  if (G_UNLIKELY (!gtk_init_with_args (&argc, &argv, NULL, opt_entries, PACKAGE, &error)))
-    {
-      if (G_LIKELY (error != NULL))
-        {
-          g_print ("%s: %s.\n", G_LOG_DOMAIN, error->message);
-          g_print (_("Type '%s --help' for usage information."), G_LOG_DOMAIN);
-          g_print ("\n");
+#ifdef G_ENABLE_DEBUG
+  /* do NOT remove this line for now, If something doesn't work,
+   * fix your code instead! */
+  g_log_set_always_fatal (G_LOG_LEVEL_CRITICAL | G_LOG_LEVEL_WARNING);
+#endif
+
+  if (!g_thread_supported ())
+    g_thread_init (NULL);
 
-          g_error_free (error);
-        }
-      else
-        g_error (_("Unable to initialize GTK+."));
+  if (!gtk_init_with_args (&argc, &argv, _("[MENUFILE]"), option_entries, GETTEXT_PACKAGE, &error))
+    {
+      g_printerr ("%s: %s.\n", PACKAGE_NAME, error->message);
+      g_printerr (_("Type \"%s --help\" for usage."), PACKAGE_NAME);
+      g_printerr ("\n");
+      g_error_free (error);
 
       return EXIT_FAILURE;
     }
 
-  /* Print version info and quit whe the user entered --version or -V */
-  if (G_UNLIKELY (opt_version))
+  if (opt_version)
     {
-      g_print ("%s %s (Xfce %s)\n\n", G_LOG_DOMAIN, PACKAGE_VERSION, xfce_version_string ());
-      g_print ("%s\n", "Copyright (c) 2008-2011");
+      g_print ("%s %s (Xfce %s)\n\n", PACKAGE_NAME, PACKAGE_VERSION, xfce_version_string ());
+      g_print ("%s\n", "Copyright (c) 2004-2010");
       g_print ("\t%s\n\n", _("The Xfce development team. All rights reserved."));
       g_print (_("Please report bugs to <%s>."), PACKAGE_BUGREPORT);
       g_print ("\n");
@@ -84,31 +88,25 @@ main (int    argc,
       return EXIT_SUCCESS;
     }
 
-  /* Initialize xfconf */
-  if (G_UNLIKELY (!xfconf_init (&error)))
-    {
-      if (G_LIKELY (error != NULL))
-        {
-          g_error (_("Failed to connect to xfconf daemon. Reason: %s"), error->message);
-          g_error_free (error);
-        }
-      else
-        g_error (_("Failed to connect to xfconf daemon."));
-
-      return EXIT_FAILURE;
-    }
-
-  /* Initialize menu library */
-  garcon_set_environment ("XFCE");
-
-  window = xfce_appfinder_window_new (opt_remaining != NULL ? opt_remaining[0] : NULL);
-  xfce_appfinder_window_reload (XFCE_APPFINDER_WINDOW (window));
+  /* if the value is unset, fallback to XFCE, if the
+   * value is empty, allow all applications in the menu */
+  desktop = g_getenv ("XDG_CURRENT_DESKTOP");
+  if (G_LIKELY (desktop == NULL))
+    desktop = "XFCE";
+  else if (*desktop == '\0')
+    desktop = NULL;
+  garcon_set_environment (desktop);
+
+  window = xfce_appfinder_window_new ();
+  xfce_appfinder_window_set_expanded (XFCE_APPFINDER_WINDOW (window), opt_finder);
   gtk_widget_show (window);
 
+  g_debug ("enter mainloop");
+
   gtk_main ();
 
-  /* Shutdown libraries */
-  xfconf_shutdown ();
+  gtk_widget_hide (window);
+  gtk_widget_destroy (window);
 
   return EXIT_SUCCESS;
 }
diff --git a/src/xfce-appfinder-window.c b/src/xfce-appfinder-window.c
deleted file mode 100644
index 8831810..0000000
--- a/src/xfce-appfinder-window.c
+++ /dev/null
@@ -1,1154 +0,0 @@
-/* vi:set et ai sw=2 sts=2 ts=2: */
-/*-
- * Copyright (c) 2008      Jasper Huijsmans <jasper at xfce.org>
- * Copyright (c) 2008-2010 Jannis Pohlmann <jannis at xfce.org>
- *
- * 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 program 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.
- *
- * 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.
- */
-
-#ifdef HAVE_CONFIG_H
-#include <config.h>
-#endif
-
-#ifdef HAVE_STRING_H
-#include <string.h>
-#endif
-
-#include <gdk/gdk.h>
-#include <gdk/gdkkeysyms.h>
-#include <gtk/gtk.h>
-
-#include <libxfce4util/libxfce4util.h>
-#include <libxfce4ui/libxfce4ui.h>
-#include <garcon/garcon.h>
-#include <gio/gio.h>
-#include <xfconf/xfconf.h>
-
-#include "xfce-appfinder-window.h"
-#include "frap-icon-entry.h"
-
-
-
-#define DEFAULT_WINDOW_WIDTH        640
-#define DEFAULT_WINDOW_HEIGHT       480
-#define DEFAULT_CLOSE_AFTER_EXECUTE FALSE
-#define DEFAULT_CATEGORY            NULL
-
-#define ICON_SIZE 32
-
-#define ICON_COLUMN 0
-#define TEXT_COLUMN 1
-#define CATEGORY_COLUMN 2
-#define ITEM_COLUMN 3
-#define TOOLTIP_COLUMN 4
-
-
-
-enum
-{
-  PROP_0,
-  PROP_MENU_FILENAME
-};
-
-
-
-static void       xfce_appfinder_window_constructed        (GObject                  *object);
-static void       xfce_appfinder_window_dispose            (GObject                  *object);
-static void       xfce_appfinder_window_finalize           (GObject                  *object);
-static void       xfce_appfinder_window_get_property       (GObject                  *object,
-                                                            guint                     prop_id,
-                                                            GValue                   *value,
-                                                            GParamSpec               *pspec);
-static void       xfce_appfinder_window_set_property       (GObject                  *object,
-                                                            guint                     prop_id,
-                                                            const GValue             *value,
-                                                            GParamSpec               *pspec);
-static void       _xfce_appfinder_window_closed            (XfceAppfinderWindow      *window);
-static void       _xfce_appfinder_window_load_menu         (XfceAppfinderWindow      *window,
-                                                            GarconMenu               *menu,
-                                                            const gchar              *category,
-                                                            gint                     *counter,
-                                                            gboolean                  is_root,
-                                                            gboolean                  is_category);
-static void       _xfce_appfinder_window_entry_changed     (GtkEditable              *editable,
-                                                            XfceAppfinderWindow      *window);
-static void       _xfce_appfinder_window_entry_activated   (GtkEntry                 *entry,
-                                                            XfceAppfinderWindow      *window);
-static gboolean   _xfce_appfinder_window_entry_focused     (GtkWidget                *entry,
-                                                            GdkEventFocus            *event,
-                                                            XfceAppfinderWindow      *window);
-static gboolean   _xfce_appfinder_window_entry_key_pressed (GtkWidget                *widget,
-                                                            GdkEventKey              *event,
-                                                            XfceAppfinderWindow      *window);
-static gboolean   _xfce_appfinder_window_radio_key_pressed (GtkWidget                *widget,
-                                                            GdkEventKey              *event,
-                                                            XfceAppfinderWindow      *window);
-static gboolean   _xfce_appfinder_window_view_key_pressed  (GtkWidget                *widget,
-                                                            GdkEventKey              *event,
-                                                            XfceAppfinderWindow      *window);
-static void       _xfce_appfinder_window_category_changed  (XfceAppfinderWindow      *window,
-                                                            GtkToggleButton          *button);
-static void       _xfce_appfinder_window_cursor_changed    (GtkTreeView              *tree_view,
-                                                            XfceAppfinderWindow      *window);
-static void       _xfce_appfinder_window_drag_data_get     (GtkWidget                *widget,
-                                                            GdkDragContext           *drag_context,
-                                                            GtkSelectionData         *data,
-                                                            guint                     info,
-                                                            guint                     drag_time,
-                                                            XfceAppfinderWindow      *window);
-static void       _xfce_appfinder_window_execute           (XfceAppfinderWindow      *window);
-static void       _xfce_appfinder_window_load_menu_item    (XfceAppfinderWindow      *window,
-                                                            GarconMenuItem             *item,
-                                                            const gchar              *category,
-                                                            gint                     *counter);
-static GdkPixbuf *_xfce_appfinder_window_create_item_icon  (GarconMenuItem             *item);
-static gboolean   _xfce_appfinder_window_visible_func      (GtkTreeModel             *filter,
-                                                            GtkTreeIter              *iter,
-                                                            gpointer                  user_data);
-static void       _xfce_appfinder_window_set_category      (XfceAppfinderWindow      *window,
-                                                            const gchar              *category);
-
-
-
-struct _XfceAppfinderWindowClass
-{
-  XfceTitledDialogClass __parent__;
-};
-
-struct _XfceAppfinderWindow
-{
-  XfceTitledDialog __parent__;
-
-  XfconfChannel *channel;
-
-  GtkWidget     *search_entry;
-  GtkWidget     *categories_alignment;
-  GtkWidget     *categories_box;
-  GtkWidget     *execute_button;
-
-  GSList        *categories_group;
-  gchar         *current_category;
-
-  GtkListStore  *list_store;
-  GtkTreeModel  *filter;
-  GtkWidget     *tree_view;
-
-  GarconMenu    *menu;
-  gchar         *menu_filename;
-};
-
-
-
-static const GtkTargetEntry dnd_target_list[] = {
-  { "text/uri-list", 0, 0 }
-};
-
-
-
-G_DEFINE_TYPE (XfceAppfinderWindow, xfce_appfinder_window, XFCE_TYPE_TITLED_DIALOG)
-
-
-
-static void
-xfce_appfinder_window_class_init (XfceAppfinderWindowClass *klass)
-{
-  GObjectClass *gobject_class;
-
-  gobject_class = G_OBJECT_CLASS (klass);
-  gobject_class->constructed = xfce_appfinder_window_constructed;
-  gobject_class->dispose = xfce_appfinder_window_dispose;
-  gobject_class->finalize = xfce_appfinder_window_finalize;
-  gobject_class->get_property = xfce_appfinder_window_get_property;
-  gobject_class->set_property = xfce_appfinder_window_set_property;
-
-  g_object_class_install_property (gobject_class,
-                                   PROP_MENU_FILENAME,
-                                   g_param_spec_string ("menu-filename",
-                                                        "menu-filename",
-                                                        "menu-filename",
-                                                        NULL,
-                                                        G_PARAM_CONSTRUCT_ONLY |
-                                                        G_PARAM_WRITABLE));
-}
-
-
-
-static void
-xfce_appfinder_window_init (XfceAppfinderWindow *window)
-{
-  GtkTreeViewColumn *column;
-  GtkCellRenderer   *renderer;
-  GtkWidget         *vbox2;
-  GtkWidget         *vbox3;
-  GtkWidget         *hbox1;
-  GtkWidget         *hbox2;
-  GtkWidget         *check_button;
-  GtkWidget         *execute_image;
-  GtkWidget         *button;
-  GtkWidget         *label;
-  GtkWidget         *alignment;
-  GtkWidget         *scrollwin;
-  gchar             *text;
-  gint               width;
-  gint               height;
-
-  window->menu = NULL;
-  window->menu_filename = NULL;
-  window->categories_group = NULL;
-  window->current_category = NULL;
-
-  window->channel = xfconf_channel_get ("xfce4-appfinder");
-
-  g_signal_connect (window, "delete-event", G_CALLBACK (_xfce_appfinder_window_closed), NULL);
-
-  gtk_window_set_title (GTK_WINDOW (window), _("Application Finder"));
-  gtk_window_set_icon_name (GTK_WINDOW (window), "xfce4-appfinder");
-  xfce_titled_dialog_set_subtitle (XFCE_TITLED_DIALOG (window), _("Find and launch applications installed on your system"));
-  gtk_dialog_set_has_separator (GTK_DIALOG (window), FALSE);
-
-  width = xfconf_channel_get_int (window->channel, "/window-width", DEFAULT_WINDOW_WIDTH);
-  height = xfconf_channel_get_int (window->channel, "/window-height", DEFAULT_WINDOW_HEIGHT);
-
-  gtk_window_set_default_size (GTK_WINDOW (window), width, height);
-  gtk_window_set_position (GTK_WINDOW (window), GTK_WIN_POS_CENTER);
-
-  vbox2 = gtk_vbox_new (FALSE, 6);
-  gtk_container_set_border_width (GTK_CONTAINER (vbox2), 6);
-  gtk_box_pack_start (GTK_BOX (GTK_DIALOG (window)->vbox), vbox2, TRUE, TRUE, 0);
-  gtk_widget_show (vbox2);
-
-  hbox1 = gtk_hbox_new (FALSE, 12);
-  gtk_container_add (GTK_CONTAINER (vbox2), hbox1);
-  gtk_widget_show (hbox1);
-
-  vbox3 = gtk_vbox_new (FALSE, 6);
-  gtk_box_pack_start (GTK_BOX (hbox1), vbox3, FALSE, TRUE, 0);
-  gtk_widget_show (vbox3);
-
-  label = gtk_label_new (NULL);
-  text = g_strdup_printf ("<span weight=\"bold\" size=\"large\">%s</span>", _("Search"));
-  gtk_label_set_markup (GTK_LABEL (label), text);
-  gtk_misc_set_alignment (GTK_MISC (label), 0.0, 0.5);
-  gtk_widget_modify_fg (label, GTK_STATE_NORMAL, &label->style->fg[GTK_STATE_INSENSITIVE]);
-  gtk_box_pack_start (GTK_BOX (vbox3), label, FALSE, TRUE, 0);
-  gtk_widget_show (label);
-  g_free (text);
-
-  alignment = gtk_alignment_new (0.0, 0.0, 1.0, 1.0);
-  gtk_alignment_set_padding (GTK_ALIGNMENT (alignment), 0, 6, 12, 12);
-  gtk_box_pack_start (GTK_BOX (vbox3), alignment, FALSE, TRUE, 0);
-  gtk_widget_show (alignment);
-
-#if GTK_CHECK_VERSION (2, 16, 0)
-  window->search_entry = gtk_entry_new ();
-  gtk_entry_set_icon_from_stock (GTK_ENTRY (window->search_entry), GTK_ENTRY_ICON_PRIMARY, GTK_STOCK_FIND);
-#else
-  window->search_entry = frap_icon_entry_new ();
-  frap_icon_entry_set_stock_id (FRAP_ICON_ENTRY (window->search_entry), GTK_STOCK_FIND);
-#endif
-  g_signal_connect (window->search_entry, "changed", G_CALLBACK (_xfce_appfinder_window_entry_changed), window);
-  g_signal_connect (window->search_entry, "activate", G_CALLBACK (_xfce_appfinder_window_entry_activated), window);
-  g_signal_connect (window->search_entry, "focus-in-event", G_CALLBACK (_xfce_appfinder_window_entry_focused), window);
-  g_signal_connect (window->search_entry, "key-press-event", G_CALLBACK (_xfce_appfinder_window_entry_key_pressed), window);
-  gtk_container_add (GTK_CONTAINER (alignment), window->search_entry);
-  gtk_widget_show (window->search_entry);
-
-  label = gtk_label_new (NULL);
-  text = g_strdup_printf ("<span weight=\"bold\" size=\"large\">%s</span>", _("Categories"));
-  gtk_label_set_markup (GTK_LABEL (label), text);
-  gtk_misc_set_alignment (GTK_MISC (label), 0.0, 0.5);
-  gtk_widget_modify_fg (label, GTK_STATE_NORMAL, &label->style->fg[GTK_STATE_INSENSITIVE]);
-  gtk_box_pack_start (GTK_BOX (vbox3), label, FALSE, TRUE, 0);
-  gtk_widget_show (label);
-  g_free (text);
-
-  window->categories_alignment = gtk_alignment_new (0.0, 0.0, 1.0, 1.0);
-  gtk_alignment_set_padding (GTK_ALIGNMENT (window->categories_alignment), 0, 6, 12, 12);
-  gtk_box_pack_start (GTK_BOX (vbox3), window->categories_alignment, FALSE, TRUE, 0);
-  gtk_widget_show (window->categories_alignment);
-
-  scrollwin = gtk_scrolled_window_new (NULL, NULL);
-  gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scrollwin), GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
-  gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW (scrollwin), GTK_SHADOW_IN);
-  gtk_container_add (GTK_CONTAINER (hbox1), scrollwin);
-  gtk_widget_show (scrollwin);
-
-  window->list_store =
-    gtk_list_store_new (5, GDK_TYPE_PIXBUF, G_TYPE_STRING, G_TYPE_STRING, GARCON_TYPE_MENU_ITEM, G_TYPE_STRING);
-
-  window->filter = gtk_tree_model_filter_new (GTK_TREE_MODEL (window->list_store), NULL);
-  gtk_tree_model_filter_set_visible_func (GTK_TREE_MODEL_FILTER (window->filter), _xfce_appfinder_window_visible_func, window, NULL);
-
-  window->tree_view = gtk_tree_view_new_with_model (GTK_TREE_MODEL (window->filter));
-  gtk_tree_view_set_headers_visible (GTK_TREE_VIEW (window->tree_view), FALSE);
-  gtk_tree_view_set_tooltip_column (GTK_TREE_VIEW (window->tree_view), TOOLTIP_COLUMN);
-  g_signal_connect (window->tree_view, "cursor-changed", G_CALLBACK (_xfce_appfinder_window_cursor_changed), window);
-  g_signal_connect_swapped (window->tree_view, "row-activated", G_CALLBACK (_xfce_appfinder_window_execute), window);
-  g_signal_connect (window->tree_view, "drag-data-get", G_CALLBACK (_xfce_appfinder_window_drag_data_get), window);
-  g_signal_connect (window->tree_view, "key-press-event", G_CALLBACK (_xfce_appfinder_window_view_key_pressed), window);
-  gtk_container_add (GTK_CONTAINER (scrollwin), window->tree_view);
-  gtk_widget_show (window->tree_view);
-
-  gtk_drag_source_set (window->tree_view, GDK_BUTTON1_MASK, dnd_target_list, G_N_ELEMENTS (dnd_target_list), GDK_ACTION_COPY);
-
-  renderer = gtk_cell_renderer_pixbuf_new ();
-  column = gtk_tree_view_column_new_with_attributes (NULL, renderer, "pixbuf", ICON_COLUMN, NULL);
-  gtk_tree_view_append_column (GTK_TREE_VIEW (window->tree_view), GTK_TREE_VIEW_COLUMN (column));
-
-  renderer = gtk_cell_renderer_text_new ();
-  g_object_set (renderer, "ellipsize", PANGO_ELLIPSIZE_END, NULL);
-  column = gtk_tree_view_column_new_with_attributes (NULL, renderer, "markup", TEXT_COLUMN, NULL);
-  gtk_tree_view_append_column (GTK_TREE_VIEW (window->tree_view), GTK_TREE_VIEW_COLUMN (column));
-
-  hbox2 = gtk_hbox_new (FALSE, 6);
-  gtk_box_pack_start (GTK_BOX (GTK_DIALOG (window)->vbox), hbox2, FALSE, TRUE, 0);
-  gtk_widget_show (hbox2);
-
-  check_button = gtk_check_button_new_with_mnemonic (_("C_lose after launch"));
-  gtk_box_pack_start (GTK_BOX (hbox2), check_button, FALSE, TRUE, 0);
-  gtk_container_set_border_width (GTK_CONTAINER (check_button), 6);
-  gtk_widget_show (check_button);
-
-  xfconf_g_property_bind (window->channel, "/close-after-execute", G_TYPE_BOOLEAN, G_OBJECT (check_button), "active");
-  gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (check_button), xfconf_channel_get_bool (window->channel, "/close-after-execute", DEFAULT_CLOSE_AFTER_EXECUTE));
-
-  window->execute_button = gtk_button_new_with_mnemonic (_("Launch"));
-  execute_image = gtk_image_new_from_stock (GTK_STOCK_EXECUTE, GTK_ICON_SIZE_BUTTON);
-  gtk_button_set_image (GTK_BUTTON (window->execute_button), execute_image);
-  gtk_dialog_add_action_widget (GTK_DIALOG (window), window->execute_button, GTK_RESPONSE_OK);
-  GTK_WIDGET_SET_FLAGS (window->execute_button, GTK_CAN_DEFAULT);
-  gtk_button_set_focus_on_click (GTK_BUTTON (window->execute_button), FALSE);
-  gtk_widget_set_sensitive (window->execute_button, FALSE);
-  g_signal_connect_swapped (window->execute_button, "clicked", G_CALLBACK (_xfce_appfinder_window_execute), window);
-  gtk_widget_show (window->execute_button);
-
-  button = gtk_dialog_add_button (GTK_DIALOG (window), GTK_STOCK_CLOSE, GTK_RESPONSE_CLOSE);
-  g_signal_connect_swapped (button, "clicked", G_CALLBACK (_xfce_appfinder_window_closed), window);
-
-  g_object_ref (G_OBJECT (GTK_DIALOG (window)->action_area));
-  gtk_container_remove (GTK_CONTAINER (GTK_DIALOG (window)->vbox),
-                        GTK_DIALOG (window)->action_area);
-  gtk_box_pack_start (GTK_BOX (hbox2), GTK_DIALOG (window)->action_area, TRUE, TRUE, 0);
-  g_object_unref (G_OBJECT (GTK_DIALOG (window)->action_area));
-
-  if (G_UNLIKELY (window->menu_filename != NULL))
-    window->menu = garcon_menu_new_for_path (window->menu_filename);
-  else
-    window->menu = garcon_menu_new_applications ();
-
-  /* reload the menu when necessary */
-  g_signal_connect_swapped (window->menu, "reload-required", G_CALLBACK (xfce_appfinder_window_reload), window);
-}
-
-
-
-static void
-xfce_appfinder_window_constructed (GObject *object)
-{
-  XfceAppfinderWindow *window = XFCE_APPFINDER_WINDOW (object);
-  gchar               *category;
-
-  category = xfconf_channel_get_string (window->channel, "/category", NULL);
-  if (category != NULL)
-    _xfce_appfinder_window_set_category (window, category);
-  g_free (category);
-}
-
-
-
-static void
-xfce_appfinder_window_dispose (GObject *object)
-{
-  (*G_OBJECT_CLASS (xfce_appfinder_window_parent_class)->dispose) (object);
-}
-
-
-
-static void
-xfce_appfinder_window_finalize (GObject *object)
-{
-  XfceAppfinderWindow *window = XFCE_APPFINDER_WINDOW (object);
-
-  g_free (window->current_category);
-  g_free (window->menu_filename);
-
-  if (G_LIKELY (GARCON_IS_MENU (window->menu)))
-    g_object_unref (window->menu);
-
-  g_slist_free (window->categories_group);
-
-  (*G_OBJECT_CLASS (xfce_appfinder_window_parent_class)->finalize) (object);
-}
-
-
-
-static void
-xfce_appfinder_window_get_property (GObject    *object,
-                                    guint       prop_id,
-                                    GValue     *value,
-                                    GParamSpec *pspec)
-{
-  switch (prop_id)
-    {
-    default:
-      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
-      break;
-    }
-}
-
-
-
-static void
-xfce_appfinder_window_set_property (GObject      *object,
-                                    guint         prop_id,
-                                    const GValue *value,
-                                    GParamSpec   *pspec)
-{
-  XfceAppfinderWindow *window = XFCE_APPFINDER_WINDOW (object);
-
-  switch (prop_id)
-    {
-    case PROP_MENU_FILENAME:
-      g_free (window->menu_filename);
-      window->menu_filename = g_strdup (g_value_get_string (value));
-      break;
-
-    default:
-      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
-      break;
-    }
-}
-
-
-
-GtkWidget *
-xfce_appfinder_window_new (const gchar *filename)
-{
-  return g_object_new (XFCE_TYPE_APPFINDER_WINDOW, "menu-filename", filename, NULL);
-}
-
-
-
-void
-xfce_appfinder_window_reload (XfceAppfinderWindow *window)
-{
-  GtkWidget *button;
-  GError    *error = NULL;
-  gint       counter = 0;
-
-  g_return_if_fail (XFCE_IS_APPFINDER_WINDOW (window));
-
-  gtk_list_store_clear (window->list_store);
-
-  if (!garcon_menu_load (window->menu, NULL, &error))
-    {
-      xfce_dialog_show_error (GTK_WINDOW (window), error, _("Could not load menu from %s"), window->menu_filename);
-      g_error_free (error);
-      return;
-    }
-
-  if (GTK_IS_WIDGET (window->categories_box))
-    gtk_widget_destroy (window->categories_box);
-
-  window->categories_box = gtk_vbox_new (FALSE, 6);
-  gtk_container_add (GTK_CONTAINER (window->categories_alignment), window->categories_box);
-  gtk_widget_show (window->categories_box);
-
-  button = gtk_radio_button_new_with_label (NULL, _("All"));
-  gtk_button_set_focus_on_click (GTK_BUTTON (button), FALSE);
-  g_signal_connect_swapped (button, "toggled", G_CALLBACK (_xfce_appfinder_window_category_changed), window);
-  g_signal_connect (button, "key-press-event", G_CALLBACK (_xfce_appfinder_window_radio_key_pressed), window);
-  gtk_container_add (GTK_CONTAINER (window->categories_box), button);
-  gtk_widget_show (button);
-
-  if (window->current_category == NULL || g_utf8_collate (window->current_category, _("All")) == 0)
-    gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (button), TRUE);
-
-  window->categories_group = gtk_radio_button_get_group (GTK_RADIO_BUTTON (button));
-
-  _xfce_appfinder_window_load_menu (window, window->menu, NULL, &counter, TRUE, FALSE);
-
-  /* reset the current category when the previous one doesn't exist anymore */
-  if (window->current_category != NULL && gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (button)))
-    _xfce_appfinder_window_set_category (window, gtk_button_get_label (GTK_BUTTON (button)));
-}
-
-
-
-static void
-_xfce_appfinder_window_entry_changed (GtkEditable         *editable,
-                                      XfceAppfinderWindow *window)
-{
-  g_return_if_fail (XFCE_IS_APPFINDER_WINDOW (window));
-  gtk_tree_model_filter_refilter (GTK_TREE_MODEL_FILTER (window->filter));
-}
-
-
-
-static void
-_xfce_appfinder_window_entry_activated (GtkEntry            *entry,
-                                        XfceAppfinderWindow *window)
-{
-  GtkTreePath *path;
-  GtkTreePath *start;
-  GtkTreePath *end;
-
-  g_return_if_fail (XFCE_IS_APPFINDER_WINDOW (window));
-
-  if (G_LIKELY (gtk_tree_view_get_visible_range (GTK_TREE_VIEW (window->tree_view), &start, &end)))
-    {
-      path = gtk_tree_path_new_first ();
-      gtk_tree_view_set_cursor (GTK_TREE_VIEW (window->tree_view), path, NULL, FALSE);
-      gtk_tree_path_free (path);
-
-      gtk_tree_path_free (start);
-      gtk_tree_path_free (end);
-
-      gtk_widget_grab_focus (window->tree_view);
-    }
-}
-
-
-
-static gboolean
-_xfce_appfinder_window_entry_focused (GtkWidget           *entry,
-                                      GdkEventFocus       *event,
-                                      XfceAppfinderWindow *window)
-{
-  GtkTreeSelection *selection;
-
-  g_return_val_if_fail (XFCE_IS_APPFINDER_WINDOW (window), FALSE);
-
-  selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (window->tree_view));
-
-  if (G_LIKELY (selection != NULL))
-    gtk_tree_selection_unselect_all (selection);
-
-  gtk_widget_set_sensitive (window->execute_button, FALSE);
-
-  return FALSE;
-}
-
-
-
-static gboolean
-_xfce_appfinder_window_entry_key_pressed (GtkWidget           *widget,
-                                          GdkEventKey         *event,
-                                          XfceAppfinderWindow *window)
-{
-  GtkWidget *child;
-  GList     *children;
-  gboolean   handled = FALSE;
-
-  g_return_val_if_fail (XFCE_IS_APPFINDER_WINDOW (window), FALSE);
-
-  if (event->keyval == GDK_Up || event->keyval == GDK_Down)
-    {
-      children = gtk_container_get_children (GTK_CONTAINER (window->categories_box));
-
-      if (G_LIKELY (children != NULL))
-        {
-          child = event->keyval == GDK_Down ? g_list_first (children)->data : g_list_last (children)->data;
-
-          if (G_LIKELY (GTK_IS_TOGGLE_BUTTON (child)))
-            {
-              gtk_widget_grab_focus (child);
-              gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (child), TRUE);
-
-              handled = TRUE;
-            }
-        }
-    }
-
-  return handled;
-}
-
-
-
-static gboolean
-_xfce_appfinder_window_radio_key_pressed (GtkWidget           *widget,
-                                          GdkEventKey         *event,
-                                          XfceAppfinderWindow *window)
-{
-  GList   *children;
-  gboolean entry_grab = FALSE;
-  gboolean handled = FALSE;
-
-  g_return_val_if_fail (XFCE_IS_APPFINDER_WINDOW (window), FALSE);
-
-  children = gtk_container_get_children (GTK_CONTAINER (window->categories_box));
-
-  switch (event->keyval)
-    {
-    case GDK_Up:
-    case GDK_Down:
-
-      if (G_LIKELY (children != NULL))
-        {
-          if (event->keyval == GDK_Up)
-            entry_grab = (widget == g_list_first (children)->data);
-          else
-            entry_grab = (widget == g_list_last (children)->data);
-
-          if (G_UNLIKELY (entry_grab))
-            {
-              gtk_widget_grab_focus (window->search_entry);
-              handled = TRUE;
-            }
-        }
-
-      break;
-    case GDK_Right:
-      _xfce_appfinder_window_entry_activated (GTK_ENTRY (window->search_entry), window);
-      handled = TRUE;
-    default:
-      break;
-    }
-
-  return handled;
-}
-
-
-
-static gboolean
-_xfce_appfinder_window_view_key_pressed (GtkWidget           *widget,
-                                         GdkEventKey         *event,
-                                         XfceAppfinderWindow *window)
-{
-  g_return_val_if_fail (XFCE_IS_APPFINDER_WINDOW (window), FALSE);
-
-  if (event->keyval == GDK_Left)
-    {
-      gtk_widget_grab_focus (window->search_entry);
-      return TRUE;
-    }
-  else
-    return FALSE;
-}
-
-
-
-static void
-_xfce_appfinder_window_category_changed (XfceAppfinderWindow *window,
-                                         GtkToggleButton     *button)
-{
-  g_return_if_fail (XFCE_IS_APPFINDER_WINDOW (window));
-
-  if (gtk_toggle_button_get_active (button))
-    _xfce_appfinder_window_set_category (window, gtk_button_get_label (GTK_BUTTON (button)));
-}
-
-
-
-static void
-_xfce_appfinder_window_cursor_changed (GtkTreeView         *tree_view,
-                                       XfceAppfinderWindow *window)
-{
-  GtkTreeSelection *selection;
-  GtkTreeModel     *model;
-  GtkTreeIter       iter;
-  GarconMenuItem     *item = NULL;
-
-  g_return_if_fail (XFCE_IS_APPFINDER_WINDOW (window));
-
-  selection = gtk_tree_view_get_selection (tree_view);
-
-  if (G_LIKELY (selection != NULL && gtk_tree_selection_get_selected (selection, &model, &iter)))
-    gtk_tree_model_get (model, &iter, ITEM_COLUMN, &item, -1);
-
-  if (G_LIKELY (item != NULL))
-    {
-      gtk_widget_set_sensitive (window->execute_button, TRUE);
-      gtk_widget_grab_default (window->execute_button);
-      g_object_unref (G_OBJECT (item));
-    }
-  else
-    {
-      gtk_widget_set_sensitive (window->execute_button, FALSE);
-      gtk_widget_grab_focus (window->search_entry);
-    }
-}
-
-
-
-static void
-_xfce_appfinder_window_drag_data_get (GtkWidget           *widget,
-                                      GdkDragContext      *drag_context,
-                                      GtkSelectionData    *data,
-                                      guint                info,
-                                      guint                drag_time,
-                                      XfceAppfinderWindow *window)
-{
-  GarconMenuItem   *item;
-  GtkTreeSelection *selection;
-  GtkTreeModel     *model;
-  GtkTreeIter       iter;
-  gchar            *uri;
-
-  g_return_if_fail (XFCE_IS_APPFINDER_WINDOW (window));
-
-  selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (window->tree_view));
-
-  if (G_UNLIKELY (selection == NULL || !gtk_tree_selection_get_selected (selection, &model, &iter)))
-    return;
-
-  gtk_tree_model_get (model, &iter, ITEM_COLUMN, &item, -1);
-
-  if (G_UNLIKELY (item == NULL))
-    return;
-
-  uri = garcon_menu_item_get_uri (item);
-  g_object_unref (G_OBJECT (item));
-  if (G_LIKELY (uri != NULL))
-    {
-      gtk_selection_data_set (data, data->target, 8, (guchar *) uri, strlen (uri));
-      g_free (uri);
-    }
-}
-
-
-
-static void
-_xfce_appfinder_window_execute (XfceAppfinderWindow *window)
-{
-  GarconMenuItem    *item;
-  GtkTreeSelection  *selection;
-  GtkTreeModel      *model;
-  GtkTreeIter        iter;
-  GError            *error = NULL;
-  const gchar       *command, *p;
-  GString           *string;
-  gchar            **argv;
-  gboolean           result = FALSE;
-
-  g_return_if_fail (XFCE_IS_APPFINDER_WINDOW (window));
-
-  selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (window->tree_view));
-
-  if (selection == NULL
-      || !gtk_tree_selection_get_selected (selection, &model, &iter))
-    return;
-
-  gtk_tree_model_get (model, &iter, ITEM_COLUMN, &item, -1);
-  if (G_UNLIKELY (item == NULL))
-    return;
-
-  command = garcon_menu_item_get_command (item);
-  if (command == NULL || *command == '\0')
-    return;
-
-  string = g_string_sized_new (100);
-
-  if (garcon_menu_item_requires_terminal (item))
-    g_string_append (string, "exo-open --launch TerminalEmulator ");
-
-  /* expand the field codes */
-  for (p = command; *p != '\0'; ++p)
-    {
-      if (G_UNLIKELY (p[0] == '%' && p[1] != '\0'))
-        {
-          switch (*++p)
-            {
-            case '%':
-              g_string_append_c (string, '%');
-              break;
-
-            /* skip all the other %? values for now we don't have dnd anyways */
-            }
-        }
-      else
-        {
-          g_string_append_c (string, *p);
-        }
-    }
-
-  if (g_shell_parse_argv (string->str, NULL, &argv, &error))
-    {
-      result = xfce_spawn_on_screen (gtk_window_get_screen (GTK_WINDOW (window)),
-                                     garcon_menu_item_get_path (item),
-                                     argv, NULL, G_SPAWN_SEARCH_PATH,
-                                     garcon_menu_item_supports_startup_notification (item),
-                                     gtk_get_current_event_time (),
-                                     garcon_menu_item_get_icon_name (item),
-                                     &error);
-
-      g_strfreev (argv);
-    }
-
-  if (G_UNLIKELY (!result))
-    {
-      xfce_dialog_show_error (GTK_WINDOW (window), error, _("Failed to execute command \"%s\"."), command);
-      g_error_free (error);
-    }
-
-  g_string_free (string, TRUE);
-  g_object_unref (G_OBJECT (item));
-
-  if (G_LIKELY (xfconf_channel_get_bool (window->channel, "/close-after-execute", FALSE)))
-    _xfce_appfinder_window_closed (window);
-}
-
-
-
-static void
-_xfce_appfinder_window_closed (XfceAppfinderWindow *window)
-{
-  gint width;
-  gint height;
-
-  g_return_if_fail (XFCE_IS_APPFINDER_WINDOW (window));
-
-  gtk_window_get_size (GTK_WINDOW (window), &width, &height);
-
-  xfconf_channel_set_int (window->channel, "/window-width", width);
-  xfconf_channel_set_int (window->channel, "/window-height", height);
-
-  gtk_main_quit ();
-}
-
-
-
-static void
-_xfce_appfinder_window_load_menu (XfceAppfinderWindow *window,
-                                  GarconMenu          *menu,
-                                  const gchar         *category,
-                                  gint                *counter,
-                                  gboolean             is_root,
-                                  gboolean             is_category)
-{
-  GarconMenuDirectory *directory;
-  GtkWidget           *button;
-  GList               *items;
-  GList               *menus;
-  GList               *iter;
-  const gchar         *name;
-  gint                 current_counter = 0;
-
-  g_return_if_fail (GARCON_IS_MENU (menu));
-  g_return_if_fail (XFCE_IS_APPFINDER_WINDOW (window));
-
-  directory = garcon_menu_get_directory (menu);
-
-  if (G_LIKELY (directory != NULL))
-    if (G_UNLIKELY (!garcon_menu_directory_get_show_in_environment (directory)
-                    || garcon_menu_directory_get_hidden (directory)
-                    || garcon_menu_directory_get_no_display (directory)))
-      {
-        return;
-      }
-
-  /* connect to the directory changed signal of all menus, force a reload when one of the menus changes */
-  g_signal_connect_swapped (menu, "directory-changed", G_CALLBACK (xfce_appfinder_window_reload), window);
-
-  /* Determine menu name */
-  name = garcon_menu_element_get_name (GARCON_MENU_ELEMENT (menu));
-
-  /* Load menu items */
-  items = garcon_menu_get_items (menu);
-  for (iter = items; iter != NULL; iter = g_list_next (iter))
-    _xfce_appfinder_window_load_menu_item (window, GARCON_MENU_ITEM (iter->data), is_category ? name : category, &current_counter);
-  g_list_free (items);
-
-  /* Load sub-menus */
-  menus = garcon_menu_get_menus (menu);
-  for (iter = menus; iter != NULL; iter = g_list_next (iter))
-    _xfce_appfinder_window_load_menu (window, GARCON_MENU (iter->data), is_category ? name : category, &current_counter, FALSE, is_root ? TRUE : FALSE);
-  g_list_free (menus);
-
-  /* Create category widget */
-  if (G_LIKELY (current_counter > 0 && is_category))
-    {
-      if (G_LIKELY (name != NULL))
-        {
-          button = gtk_radio_button_new_with_label (window->categories_group, name);
-          gtk_button_set_focus_on_click (GTK_BUTTON (button), FALSE);
-          g_signal_connect (button, "key-press-event", G_CALLBACK (_xfce_appfinder_window_radio_key_pressed), window);
-          gtk_container_add (GTK_CONTAINER (window->categories_box), button);
-          gtk_widget_show (button);
-
-          if (G_UNLIKELY (window->current_category != NULL && g_utf8_collate (window->current_category, name) == 0))
-            gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (button), TRUE);
-
-          window->categories_group = gtk_radio_button_get_group (GTK_RADIO_BUTTON (button));
-
-          g_signal_connect_swapped (button, "toggled", G_CALLBACK (_xfce_appfinder_window_category_changed), window);
-        }
-    }
-
-  *counter += 1;
-}
-
-
-
-static void
-_xfce_appfinder_window_load_menu_item (XfceAppfinderWindow *window,
-                                       GarconMenuItem      *item,
-                                       const gchar         *category,
-                                       gint                *counter)
-{
-  GtkTreeIter   iter;
-  GdkPixbuf    *pixbuf;
-  GString      *tooltip_str;
-  GList        *categories;
-  GList        *lp;
-  const gchar  *name = NULL;
-  const gchar  *comment;
-  const gchar  *command;
-  gchar       **categories_array;
-  gchar        *categories_string;
-  gchar        *text;
-  gchar        *tooltip = NULL;
-  guint         n;
-
-  g_return_if_fail (XFCE_IS_APPFINDER_WINDOW (window));
-
-  if (G_UNLIKELY (!garcon_menu_item_get_show_in_environment (item) || garcon_menu_item_get_no_display (item)))
-    return;
-
-  if (G_UNLIKELY (garcon_menu_item_only_show_in_environment (item) || garcon_menu_item_has_category (item, "X-XFCE")))
-    {
-      name = garcon_menu_item_get_generic_name (item);
-
-      if (G_UNLIKELY (name == NULL))
-        name = garcon_menu_element_get_name (GARCON_MENU_ELEMENT (item));
-    }
-  else
-    name = garcon_menu_element_get_name (GARCON_MENU_ELEMENT (item));
-
-  comment = garcon_menu_item_get_comment (item);
-  pixbuf = _xfce_appfinder_window_create_item_icon (item);
-  categories = garcon_menu_item_get_categories (item);
-  command = garcon_menu_item_get_command (item);
-
-  if (G_LIKELY (comment != NULL))
-    text = g_markup_printf_escaped ("<b>%s</b>\n%s", name, comment);
-  else
-    text = g_markup_printf_escaped ("<b>%s</b>", name);
-
-  tooltip_str = g_string_new (NULL);
-
-  if (G_LIKELY (categories != NULL))
-    {
-      categories_array = g_new0 (gchar *, g_list_length (categories) + 1);
-
-      for (lp = categories, n = 0; lp != NULL; lp = lp->next, ++n)
-        categories_array[n] = lp->data;
-
-      categories_string = g_strjoinv (", ", categories_array);
-      g_string_append_printf (tooltip_str, _("<b>Categories:</b> %s"), categories_string);
-      g_free (categories_string);
-
-      g_free (categories_array);
-    }
-
-  if (command != NULL && *command != '\0')
-    {
-      if (categories != NULL)
-        g_string_append_c (tooltip_str, '\n');
-
-      g_string_append_printf (tooltip_str, _("<b>Command:</b> %s"), command);
-    }
-
-  tooltip = g_string_free (tooltip_str, FALSE);
-
-  gtk_list_store_append (window->list_store, &iter);
-  gtk_list_store_set (window->list_store, &iter,
-                      ICON_COLUMN, pixbuf,
-                      TEXT_COLUMN, text,
-                      CATEGORY_COLUMN, category,
-                      ITEM_COLUMN, item,
-                      TOOLTIP_COLUMN, tooltip,-1);
-
-  g_free (text);
-  g_free (tooltip);
-
-  if (GDK_IS_PIXBUF (pixbuf))
-    g_object_unref (pixbuf);
-
-  g_signal_connect_swapped (item, "changed", G_CALLBACK (xfce_appfinder_window_reload), window);
-
-  *counter += 1;
-}
-
-
-
-static GdkPixbuf *
-_xfce_appfinder_window_create_item_icon (GarconMenuItem *item)
-{
-  GdkPixbuf    *icon = NULL;
-  GtkIconTheme *icon_theme;
-  const gchar  *icon_name;
-  const gchar  *item_name;
-  gchar        *base_name;
-  gchar        *extension;
-  gchar        *new_item_name;
-  gchar         new_icon_name[1024];
-
-  /* Get current icon theme */
-  icon_theme = gtk_icon_theme_get_default ();
-
-  item_name = garcon_menu_element_get_name (GARCON_MENU_ELEMENT (item));
-  icon_name = garcon_menu_element_get_icon_name (GARCON_MENU_ELEMENT (item));
-
-  if (icon_name == NULL)
-    return NULL;
-
-  /* Check if we have an absolute filename */
-  if (g_path_is_absolute (icon_name) && g_file_test (icon_name, G_FILE_TEST_EXISTS))
-    icon = gdk_pixbuf_new_from_file_at_scale (icon_name, ICON_SIZE, ICON_SIZE, TRUE, NULL);
-  else
-    {
-      /* Try to load the icon name directly using the icon theme */
-      icon = gtk_icon_theme_load_icon (icon_theme, icon_name, ICON_SIZE, GTK_ICON_LOOKUP_USE_BUILTIN, NULL);
-
-      /* If that didn't work, try to remove the filename extension if there is one */
-      if (icon == NULL)
-        {
-          /* Get basename (just to be sure) */
-          base_name = g_path_get_basename (icon_name);
-
-          /* Determine position of the extension */
-          extension = g_utf8_strrchr (base_name, -1, '.');
-
-          /* Make sure we found an extension */
-          if (extension != NULL)
-            {
-              /* Remove extension */
-              g_utf8_strncpy (new_icon_name, base_name, g_utf8_strlen (base_name, -1) - g_utf8_strlen (extension, -1));
-
-              /* Try to load the pixbuf using the new icon name */
-              icon = gtk_icon_theme_load_icon (icon_theme, new_icon_name, ICON_SIZE, GTK_ICON_LOOKUP_USE_BUILTIN, NULL);
-            }
-
-          /* Free basename */
-          g_free (base_name);
-
-          /* As a last fallback, we try to load the icon by lowercase item name */
-          if (icon == NULL && item_name != NULL)
-            {
-              new_item_name = g_utf8_strdown (item_name, -1);
-              icon = gtk_icon_theme_load_icon (icon_theme, new_item_name, ICON_SIZE, GTK_ICON_LOOKUP_USE_BUILTIN, NULL);
-              g_free (new_item_name);
-            }
-        }
-    }
-
-  /* Fallback to default application icon */
-  if (icon == NULL)
-    icon = gtk_icon_theme_load_icon (icon_theme, "applications-other", ICON_SIZE, GTK_ICON_LOOKUP_USE_BUILTIN, NULL);
-
-  /* Scale icon (if needed) */
-  if (icon != NULL)
-    {
-      GdkPixbuf *old_icon = icon;
-      icon = gdk_pixbuf_scale_simple (old_icon, ICON_SIZE, ICON_SIZE, GDK_INTERP_BILINEAR);
-      g_object_unref (old_icon);
-    }
-
-  return icon;
-}
-
-
-
-static gboolean
-_xfce_appfinder_window_visible_func (GtkTreeModel *filter,
-                                     GtkTreeIter  *iter,
-                                     gpointer      user_data)
-{
-  XfceAppfinderWindow *window = user_data;
-  GarconMenuItem      *item;
-  gchar               *category;
-  gchar               *text;
-  gchar               *search_text;
-  gchar               *normalized;
-  gchar               *command;
-  gboolean             visible = FALSE;
-
-  g_return_val_if_fail (XFCE_IS_APPFINDER_WINDOW (window), FALSE);
-
-  gtk_tree_model_get (filter, iter,
-                      CATEGORY_COLUMN, &category,
-                      TEXT_COLUMN, &text,
-                      ITEM_COLUMN, &item, -1);
-
-  if (G_UNLIKELY (text == NULL))
-    return FALSE;
-
-  normalized = g_utf8_normalize (gtk_entry_get_text (GTK_ENTRY (window->search_entry)), -1, G_NORMALIZE_ALL);
-  search_text = g_utf8_casefold (normalized, -1);
-  g_free (normalized);
-
-  normalized = g_utf8_normalize (text, -1, G_NORMALIZE_ALL);
-  g_free (text);
-  text = g_utf8_casefold (normalized, -1);
-  g_free (normalized);
-
-  if (garcon_menu_item_get_command (item) != NULL)
-    {
-      normalized = g_utf8_normalize (garcon_menu_item_get_command (item), -1, G_NORMALIZE_ALL);
-      command = g_utf8_casefold (normalized, -1);
-      g_free (normalized);
-    }
-  else
-    {
-      command = g_strdup ("");
-    }
-
-  if (g_strstr_len (text, -1, search_text) != NULL ||
-      g_strstr_len (command, -1, search_text) != NULL)
-    {
-      if (window->current_category == NULL ||
-          g_utf8_strlen (window->current_category, -1) == 0 ||
-          g_utf8_collate (window->current_category, _("All")) == 0)
-        {
-          visible = TRUE;
-        }
-      else
-        {
-          if (category != NULL && g_utf8_collate (category, window->current_category) == 0)
-            visible = TRUE;
-        }
-    }
-
-  g_free (search_text);
-  g_free (command);
-  g_free (text);
-  g_free (category);
-  g_object_unref (G_OBJECT (item));
-
-  return visible;
-}
-
-
-
-static void
-_xfce_appfinder_window_set_category (XfceAppfinderWindow *window,
-                                     const gchar         *category)
-{
-  g_return_if_fail (XFCE_IS_APPFINDER_WINDOW (window));
-
-  if (G_LIKELY (window->current_category != NULL))
-    if (G_UNLIKELY (g_utf8_collate (window->current_category, category) == 0))
-      return;
-
-  g_free (window->current_category);
-  window->current_category = g_strdup (category);
-
-  gtk_tree_model_filter_refilter (GTK_TREE_MODEL_FILTER (window->filter));
-  gtk_widget_set_sensitive (window->execute_button, FALSE);
-
-  xfconf_channel_set_string (window->channel, "/category", window->current_category);
-}
diff --git a/xfce4-appfinder.spec.in b/xfce4-appfinder.spec.in
deleted file mode 100644
index b2f7f17..0000000
--- a/xfce4-appfinder.spec.in
+++ /dev/null
@@ -1,49 +0,0 @@
-Summary: 	Application finder for the Xfce Desktop Environment
-Name: 		xfce4-appfinder
-Version: 	@VERSION@
-Release: 	1
-License:	GPL
-URL: 		http://www.xfce.org/
-Source0: 	%{name}-%{version}.tar.gz
-Group: 		User Interface/Desktops
-BuildRoot: 	%{_tmppath}/%{name}-root
-Requires:	gtk2 >= @GTK_REQUIRED_VERSION@
-Requires:	libxfce4menu >= @LIBXFCE4MENU_REQUIRED_VERSION@
-BuildRequires:	gtk2-devel >= @GTK_REQUIRED_VERSION@
-BuildRequires:	libxfce4menu-devel >= @LIBXFCE4MENU_CLIENT_REQUIRED_VERSION@
-
-%description
-xfce4-appfinder shows system wide installed applications
-
-%prep
-%setup -q
-
-%build
-%configure --enable-final
-make
-
-%install
-rm -rf $RPM_BUILD_ROOT
-make install DESTDIR=$RPM_BUILD_ROOT mandir=%{_mandir}
-
-%clean
-rm -rf $RPM_BUILD_ROOT
-
-%post
-touch --no-create %{_datadir}/icons/hicolor || :
-if [ -x %{_bindir}/gtk-update-icon-cache ]; then
-   %{_bindir}/gtk-update-icon-cache --quiet %{_datadir}/icons/hicolor || :
-fi
-
-%postun
-touch --no-create %{_datadir}/icons/hicolor || :
-if [ -x %{_bindir}/gtk-update-icon-cache ]; then
-   %{_bindir}/gtk-update-icon-cache --quiet %{_datadir}/icons/hicolor || :
-fi
-
-%files
-%defattr(-,root,root)
-%doc README TODO ChangeLog NEWS INSTALL COPYING AUTHORS
-%{_bindir}/*
-%{_datadir}/*
-



More information about the Xfce4-commits mailing list