[Xfce4-commits] <xfce4-appfinder:nick/xfrun4-merge> Initial work on xfce4-appfinder and xfrun4 merge.
Nick Schermer
noreply at xfce.org
Mon Jun 6 20:46:02 CEST 2011
Updating branch refs/heads/nick/xfrun4-merge
to 094addd1fbe47d78d8103d23fd169a239bb92ddb (commit)
from 1622f050f1ff8cae92eef7349a042e1d6039e096 (commit)
commit 094addd1fbe47d78d8103d23fd169a239bb92ddb
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, ®ular_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, ¤t_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, ¤t_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