[Xfce4-commits] <xfce4-appfinder:master> Make a start with dbus, model sharing and settings.
Nick Schermer
noreply at xfce.org
Sat Jul 9 16:18:04 CEST 2011
Updating branch refs/heads/master
to a36909d9ad7e1369b1057f5f87296151f8aa653e (commit)
from 126620ac040126189b2e12dabd47725bb05f70e2 (commit)
commit a36909d9ad7e1369b1057f5f87296151f8aa653e
Author: Nick Schermer <nick at xfce.org>
Date: Sat Jun 11 21:42:30 2011 +0200
Make a start with dbus, model sharing and settings.
Couple of things are not working yet.
- Keep the model around if there are no windows.
- Categories are not working in the 2nd window.
- Forking to the background.
- envp + screen over dbus.
configure.ac.in | 2 +
data/xfce4-appfinder.desktop.in | 2 +-
src/Makefile.am | 7 +-
src/appfinder-category-model.c | 1 +
src/appfinder-model.c | 187 ++++++-----------------
src/appfinder-model.h | 31 +---
src/appfinder-private.h | 39 +++++
src/appfinder-window.c | 160 ++++++++++++++------
src/appfinder-window.h | 2 -
src/main.c | 319 +++++++++++++++++++++++++++++++++++++--
10 files changed, 519 insertions(+), 231 deletions(-)
diff --git a/configure.ac.in b/configure.ac.in
index c65d770..62fd416 100644
--- a/configure.ac.in
+++ b/configure.ac.in
@@ -76,6 +76,8 @@ 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.7])
+XDT_CHECK_PACKAGE([DBUS_GLIB], [dbus-glib-1], [0.84])
+XDT_CHECK_PACKAGE([XFCONF], [libxfconf-0], [4.8.0])
dnl ***********************************
dnl *** Check for debugging support ***
diff --git a/data/xfce4-appfinder.desktop.in b/data/xfce4-appfinder.desktop.in
index f79f952..2b4bec2 100644
--- a/data/xfce4-appfinder.desktop.in
+++ b/data/xfce4-appfinder.desktop.in
@@ -1,6 +1,6 @@
[Desktop Entry]
Version=1.0
-Exec=xfce4-appfinder --finder
+Exec=xfce4-appfinder -x
Icon=gtk-find
StartupNotify=true
Terminal=false
diff --git a/src/Makefile.am b/src/Makefile.am
index b32ae27..2c6551f 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -13,16 +13,20 @@ xfce4_appfinder_SOURCES = \
appfinder-category-model.h \
appfinder-model.c \
appfinder-model.h \
+ appfinder-private.h \
appfinder-window.c \
appfinder-window.h \
main.c
xfce4_appfinder_CFLAGS = \
+ $(GLIB_CFLAGS) \
$(GTHREAD_CFLAGS) \
$(GTK_CFLAGS) \
$(LIBXFCE4UTIL_CFLAGS) \
$(LIBXFCE4UI_CFLAGS) \
$(GARCON_CFLAGS) \
+ $(DBUS_GLIB_CFLAGS) \
+ $(XFCONF_CFLAGS) \
$(PLATFORM_CFLAGS)
xfce4_appfinder_LDADD = \
@@ -32,7 +36,8 @@ xfce4_appfinder_LDADD = \
$(LIBXFCE4UTIL_LIBS) \
$(LIBXFCE4UI_LIBS) \
$(GARCON_LIBS) \
- $(LIBXFCONF_LIBS)
+ $(XFCONF_LIBS) \
+ $(DBUS_GLIB_LIBS)
xfce4_appfinder_LDFLAGS = \
-no-undefined \
diff --git a/src/appfinder-category-model.c b/src/appfinder-category-model.c
index 957029f..06d208d 100644
--- a/src/appfinder-category-model.c
+++ b/src/appfinder-category-model.c
@@ -29,6 +29,7 @@
#include <src/appfinder-model.h>
#include <src/appfinder-category-model.h>
+#include <src/appfinder-private.h>
diff --git a/src/appfinder-model.c b/src/appfinder-model.c
index 0d49e5c..470eec0 100644
--- a/src/appfinder-model.c
+++ b/src/appfinder-model.c
@@ -29,6 +29,7 @@
#include <garcon/garcon.h>
#include <src/appfinder-model.h>
+#include <src/appfinder-private.h>
@@ -89,10 +90,6 @@ struct _XfceAppfinderModel
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;
@@ -109,7 +106,6 @@ typedef struct
GPtrArray *categories;
gchar *command;
gchar *tooltip;
- guint visible : 1;
GdkPixbuf *icon_small;
GdkPixbuf *icon_large;
@@ -124,7 +120,7 @@ enum
-static guint model_signals[LAST_SIGNAL];
+static guint model_signals[LAST_SIGNAL];
@@ -207,16 +203,10 @@ xfce_appfinder_model_finalize (GObject *object)
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));
@@ -259,9 +249,6 @@ xfce_appfinder_model_get_column_type (GtkTreeModel *tree_model,
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;
@@ -334,11 +321,6 @@ xfce_appfinder_model_get_value (GtkTreeModel *tree_model,
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)
{
@@ -704,7 +686,6 @@ xfce_appfinder_model_item_new (GarconMenuItem *menu_item)
item = g_slice_new0 (ModelItem);
item->item = g_object_ref (G_OBJECT (menu_item));
- item->visible = TRUE;
command = garcon_menu_item_get_command (menu_item);
if (G_LIKELY (command != NULL))
@@ -983,153 +964,77 @@ xfce_appfinder_model_collect_thread (gpointer user_data)
-static gboolean
-xfce_appfinder_model_filter_idle (gpointer data)
+XfceAppfinderModel *
+xfce_appfinder_model_get (void)
{
- XfceAppfinderModel *model = XFCE_APPFINDER_MODEL (data);
- GSList *li;
- gint idx;
- ModelItem *item;
- gboolean visible;
- GtkTreeIter iter;
- GtkTreePath *path;
+ static XfceAppfinderModel *model = NULL;
- GDK_THREADS_ENTER ();
-
- for (li = model->items, idx = 0; li != NULL; li = li->next, idx++)
+ if (G_LIKELY (model != NULL))
{
- 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);
- }
+ g_object_ref (G_OBJECT (model));
}
-
- 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)
+ else
{
- model->filter_idle_id = g_idle_add_full (G_PRIORITY_HIGH_IDLE, xfce_appfinder_model_filter_idle,
- model, xfce_appfinder_model_filter_idle_destroyed);
+ model = g_object_new (XFCE_TYPE_APPFINDER_MODEL, NULL);
+ g_message ("new model");
+ g_object_add_weak_pointer (G_OBJECT (model), (gpointer) &model);
}
-}
-
-
-XfceAppfinderModel *
-xfce_appfinder_model_new (void)
-{
- return g_object_new (XFCE_TYPE_APPFINDER_MODEL, NULL);
+ return model;
}
-void
-xfce_appfinder_model_filter_category (XfceAppfinderModel *model,
- const gchar *category)
+gboolean
+xfce_appfinder_model_get_visible (XfceAppfinderModel *model,
+ const GtkTreeIter *iter,
+ const gchar *category,
+ const gchar *string)
{
- 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);
-}
-
+ ModelItem *item;
+ g_return_val_if_fail (XFCE_IS_APPFINDER_MODEL (model), FALSE);
+ g_return_val_if_fail (iter->stamp == model->stamp, FALSE);
-void
-xfce_appfinder_model_filter_string (XfceAppfinderModel *model,
- const gchar *seach_string)
-{
- gchar *normalized;
+ item = ITER_GET_DATA (iter);
- g_return_if_fail (XFCE_IS_APPFINDER_MODEL (model));
+ if (item->item != NULL)
+ {
+ g_return_val_if_fail (GARCON_IS_MENU_ITEM (item->item), FALSE);
- if (model->filter_string == seach_string)
- return;
+ if (category != NULL
+ && (*category == '\0'
+ || !xfce_appfinder_model_ptr_array_strcmp (item->categories, category)))
+ return FALSE;
- g_free (model->filter_string);
+ if (string != NULL)
+ {
+ if (item->key == NULL)
+ item->key = xfce_appfinder_model_item_key (item->item);
- 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);
+ return strstr (item->key, string) != NULL;
+ }
}
- else
+ else /* command item */
{
- model->filter_string = NULL;
+ g_return_val_if_fail (item->command != NULL, FALSE);
+
+ /* nul string will filter out the commands */
+ if (category == NULL || *category != '\0')
+ return FALSE;
+
+ if (string != NULL)
+ return strstr (item->command, string) != NULL;
}
- xfce_appfinder_model_filter (model);
+ return TRUE;
}
gboolean
xfce_appfinder_model_execute (XfceAppfinderModel *model,
- GtkTreeIter *iter,
+ const GtkTreeIter *iter,
GdkScreen *screen,
gboolean *is_regular_command,
GError **error)
@@ -1385,7 +1290,7 @@ xfce_appfinder_model_icon_theme_changed (XfceAppfinderModel *model)
item->icon_large = g_object_ref (G_OBJECT (model->command_icon_large));
}
- if (item_changed && item->visible)
+ if (item_changed)
{
path = gtk_tree_path_new_from_indices (idx, -1);
ITER_INIT (iter, model->stamp, li);
diff --git a/src/appfinder-model.h b/src/appfinder-model.h
index a4b018b..e192d0e 100644
--- a/src/appfinder-model.h
+++ b/src/appfinder-model.h
@@ -33,29 +33,11 @@ typedef struct _XfceAppfinderModel XfceAppfinderModel;
#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')
-
-#ifdef DEBUG
-#define APPFINDER_DEBUG(...) g_print ("xfce4-appfinder: "); g_print (__VA_ARGS__); g_print ("\n")
-#else
-#define APPFINDER_DEBUG(...) G_STMT_START{ (void)0; }G_STMT_END
-#endif
-
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,
@@ -66,16 +48,15 @@ enum
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);
+XfceAppfinderModel *xfce_appfinder_model_get (void) G_GNUC_MALLOC;
-void xfce_appfinder_model_filter_string (XfceAppfinderModel *model,
- const gchar *seach_string);
+gboolean xfce_appfinder_model_get_visible (XfceAppfinderModel *model,
+ const GtkTreeIter *iter,
+ const gchar *category,
+ const gchar *string);
gboolean xfce_appfinder_model_execute (XfceAppfinderModel *model,
- GtkTreeIter *iter,
+ const GtkTreeIter *iter,
GdkScreen *screen,
gboolean *is_regular_command,
GError **error);
diff --git a/src/appfinder-private.h b/src/appfinder-private.h
new file mode 100644
index 0000000..43b2c73
--- /dev/null
+++ b/src/appfinder-private.h
@@ -0,0 +1,39 @@
+/*
+ * 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_PRIVATE_H__
+#define __XFCE_APPFINDER_PRIVATE_H__
+
+#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')
+
+#ifdef DEBUG
+#define APPFINDER_DEBUG(...) g_print ("xfce4-appfinder: "); g_print (__VA_ARGS__); g_print ("\n")
+#else
+#define APPFINDER_DEBUG(...) G_STMT_START{ (void)0; }G_STMT_END
+#endif
+
+#endif /* !__XFCE_APPFINDER_PRIVATE_H__ */
diff --git a/src/appfinder-window.c b/src/appfinder-window.c
index 68dfbfd..eec8863 100644
--- a/src/appfinder-window.c
+++ b/src/appfinder-window.c
@@ -27,18 +27,25 @@
#include <libxfce4util/libxfce4util.h>
#include <libxfce4ui/libxfce4ui.h>
#include <gdk/gdkkeysyms.h>
+#include <xfconf/xfconf.h>
#include <src/appfinder-window.h>
#include <src/appfinder-model.h>
#include <src/appfinder-category-model.h>
+#include <src/appfinder-private.h>
+
+
+
+#define DEFAULT_WINDOW_WIDTH 400
+#define DEFAULT_WINDOW_HEIGHT 400
+#define DEFAULT_PANED_POSITION 180
static void xfce_appfinder_window_finalize (GObject *object);
+static void xfce_appfinder_window_unmap (GtkWidget *widget);
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);
@@ -62,6 +69,9 @@ static void xfce_appfinder_window_drag_data_get (GtkWidget
XfceAppfinderWindow *window);
static void xfce_appfinder_window_category_changed (GtkTreeSelection *selection,
XfceAppfinderWindow *window);
+static gboolean xfce_appfinder_window_item_visible (GtkTreeModel *model,
+ GtkTreeIter *iter,
+ gpointer data);
static void xfce_appfinder_window_item_changed (XfceAppfinderWindow *window);
static void xfce_appfinder_window_row_activated (XfceAppfinderWindow *window);
static void xfce_appfinder_window_icon_theme_changed (XfceAppfinderWindow *window);
@@ -78,25 +88,28 @@ struct _XfceAppfinderWindow
{
GtkWindow __parent__;
- XfceAppfinderModel *model;
+ XfceAppfinderModel *model;
XfceAppfinderCategoryModel *category_model;
- GtkEntryCompletion *completion;
+ GtkEntryCompletion *completion;
+
+ GtkWidget *paned;
+ GtkWidget *entry;
+ GtkWidget *image;
+ GtkWidget *treeview;
- GtkWidget *paned;
- GtkWidget *entry;
- GtkWidget *image;
- GtkWidget *treeview;
+ GdkPixbuf *icon_find;
- GdkPixbuf *icon_find;
+ GtkWidget *bbox;
+ GtkWidget *button_launch;
+ GtkWidget *bin_collapsed;
+ GtkWidget *bin_expanded;
- GtkWidget *bbox;
- GtkWidget *button_launch;
- GtkWidget *bin_collapsed;
- GtkWidget *bin_expanded;
+ gchar *filter_category;
+ gchar *filter_text;
- gint last_window_height;
+ gint last_window_height;
};
static const GtkTargetEntry target_list[] =
@@ -120,8 +133,8 @@ xfce_appfinder_window_class_init (XfceAppfinderWindowClass *klass)
gobject_class->finalize = xfce_appfinder_window_finalize;
gtkwidget_class = GTK_WIDGET_CLASS (klass);
+ gtkwidget_class->unmap = xfce_appfinder_window_unmap;
gtkwidget_class->key_press_event = xfce_appfinder_window_key_press_event;
- gtkwidget_class->delete_event = xfce_appfinder_window_delete_event;
}
@@ -147,17 +160,21 @@ xfce_appfinder_window_init (XfceAppfinderWindow *window)
GtkTreePath *path;
GtkEntryCompletion *completion;
GtkIconTheme *icon_theme;
+ XfconfChannel *channel;
+ gint integer;
- window->last_window_height = 400;
+ channel = xfconf_channel_get ("xfce4-appfinder");
+ window->last_window_height = xfconf_channel_get_int (channel, "/LastWindowHeight", DEFAULT_WINDOW_HEIGHT);
- window->model = xfce_appfinder_model_new ();
+ window->model = xfce_appfinder_model_get ();
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);
+ integer = xfconf_channel_get_int (channel, "/LastWindowWidth", DEFAULT_WINDOW_WIDTH);
+ gtk_window_set_default_size (GTK_WINDOW (window), integer, -1);
gtk_window_set_icon_name (GTK_WINDOW (window), GTK_STOCK_EXECUTE);
vbox = gtk_vbox_new (FALSE, 6);
@@ -209,7 +226,9 @@ xfce_appfinder_window_init (XfceAppfinderWindow *window)
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 */);
+ integer = xfconf_channel_get_int (channel, "/LastPanedPosition", DEFAULT_PANED_POSITION);
+ gtk_paned_set_position (GTK_PANED (pane), integer);
+ g_object_set (G_OBJECT (pane), "position-set", TRUE, NULL);
scroll = gtk_scrolled_window_new (NULL, NULL);
gtk_paned_add1 (GTK_PANED (pane), scroll);
@@ -257,7 +276,7 @@ xfce_appfinder_window_init (XfceAppfinderWindow *window)
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);
+ gtk_tree_model_filter_set_visible_func (GTK_TREE_MODEL_FILTER (filter_model), xfce_appfinder_window_item_visible, window, NULL);
window->treeview = treeview = gtk_tree_view_new_with_model (filter_model);
gtk_tree_view_set_headers_visible (GTK_TREE_VIEW (treeview), FALSE);
@@ -305,7 +324,7 @@ xfce_appfinder_window_init (XfceAppfinderWindow *window)
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);
+ g_signal_connect_swapped (G_OBJECT (button), "clicked", G_CALLBACK (gtk_widget_destroy), window);
gtk_widget_show (button);
window->button_launch = button = gtk_button_new_with_mnemonic ("La_unch");
@@ -335,18 +354,44 @@ xfce_appfinder_window_finalize (GObject *object)
g_object_unref (G_OBJECT (window->completion));
g_object_unref (G_OBJECT (window->icon_find));
+ g_free (window->filter_category);
+ g_free (window->filter_text);
+
(*G_OBJECT_CLASS (xfce_appfinder_window_parent_class)->finalize) (object);
}
+static void
+xfce_appfinder_window_unmap (GtkWidget *widget)
+{
+ XfceAppfinderWindow *window = XFCE_APPFINDER_WINDOW (widget);
+ gint width, height;
+ gint position;
+ XfconfChannel *channel;
+
+ position = gtk_paned_get_position (GTK_PANED (window->paned));
+ gtk_window_get_size (GTK_WINDOW (window), &width, &height);
+ if (!gtk_widget_get_visible (window->paned))
+ height = window->last_window_height;
+
+ (*GTK_WIDGET_CLASS (xfce_appfinder_window_parent_class)->unmap) (widget);
+
+ channel = xfconf_channel_get ("xfce4-appfinder");
+ xfconf_channel_set_int (channel, "/LastWindowHeight", height);
+ xfconf_channel_set_int (channel, "/LastWindowWidth", width);
+ xfconf_channel_set_int (channel, "/LastPanedPosition", position);
+}
+
+
+
static gboolean
xfce_appfinder_window_key_press_event (GtkWidget *widget,
GdkEventKey *event)
{
if (event->keyval == GDK_Escape)
{
- gtk_main_quit ();
+ gtk_widget_destroy (widget);
return TRUE;
}
@@ -355,17 +400,6 @@ xfce_appfinder_window_key_press_event (GtkWidget *widget,
-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)
@@ -396,14 +430,30 @@ xfce_appfinder_window_set_padding (GtkWidget *entry,
static void
xfce_appfinder_window_entry_changed (XfceAppfinderWindow *window)
{
- const gchar *text;
- GdkPixbuf *pixbuf;
+ const gchar *text;
+ GdkPixbuf *pixbuf;
+ gchar *normalized;
+ GtkTreeModel *model;
text = gtk_entry_get_text (GTK_ENTRY (window->entry));
if (gtk_widget_get_visible (window->paned))
{
- xfce_appfinder_model_filter_string (window->model, text);
+ g_free (window->filter_text);
+
+ if (IS_STRING (text))
+ {
+ normalized = g_utf8_normalize (text, -1, G_NORMALIZE_ALL);
+ window->filter_text = g_utf8_casefold (normalized, -1);
+ g_free (normalized);
+ }
+ else
+ {
+ window->filter_text = NULL;
+ }
+
+ model = gtk_tree_view_get_model (GTK_TREE_VIEW (window->treeview));
+ gtk_tree_model_filter_refilter (GTK_TREE_MODEL_FILTER (model));
}
else
{
@@ -547,19 +597,37 @@ xfce_appfinder_window_category_changed (GtkTreeSelection *selection,
{
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");
+ g_free (window->filter_category);
+
+ if (g_strcmp0 (category, _("All Applications")) == 0)
+ window->filter_category = NULL;
+ else if (g_strcmp0 (category, _("Commands History")) == 0)
+ window->filter_category = g_strdup ("\0");
else
- xfce_appfinder_model_filter_category (window->model, category);
+ window->filter_category = g_strdup (category);
g_free (category);
+
+ model = gtk_tree_view_get_model (GTK_TREE_VIEW (window->treeview));
+ gtk_tree_model_filter_refilter (GTK_TREE_MODEL_FILTER (model));
}
}
+static gboolean
+xfce_appfinder_window_item_visible (GtkTreeModel *model,
+ GtkTreeIter *iter,
+ gpointer data)
+{
+ XfceAppfinderWindow *window = XFCE_APPFINDER_WINDOW (data);
+
+ return xfce_appfinder_model_get_visible (XFCE_APPFINDER_MODEL (model), iter,
+ window->filter_category, window->filter_text);
+}
+
+
+
static void
xfce_appfinder_window_item_changed (XfceAppfinderWindow *window)
{
@@ -726,15 +794,7 @@ xfce_appfinder_window_execute (XfceAppfinderWindow *window)
}
if (result)
- gtk_main_quit ();
-}
-
-
-
-GtkWidget *
-xfce_appfinder_window_new (void)
-{
- return g_object_new (XFCE_TYPE_APPFINDER_WINDOW, NULL);
+ gtk_widget_destroy (GTK_WIDGET (window));
}
diff --git a/src/appfinder-window.h b/src/appfinder-window.h
index f100f66..95b935d 100644
--- a/src/appfinder-window.h
+++ b/src/appfinder-window.h
@@ -35,8 +35,6 @@ typedef struct _XfceAppfinderWindow XfceAppfinderWindow;
GType xfce_appfinder_window_get_type (void) G_GNUC_CONST;
-GtkWidget *xfce_appfinder_window_new (void) G_GNUC_MALLOC;
-
void xfce_appfinder_window_set_expanded (XfceAppfinderWindow *window,
gboolean expanded);
diff --git a/src/main.c b/src/main.c
index 5750b82..0e5cd8f 100644
--- a/src/main.c
+++ b/src/main.c
@@ -27,34 +27,255 @@
#include <gtk/gtk.h>
#include <libxfce4util/libxfce4util.h>
#include <garcon/garcon.h>
+#include <xfconf/xfconf.h>
+
+#include <dbus/dbus.h>
+#include <dbus/dbus-glib-lowlevel.h>
-#include <src/appfinder-model.h>
#include <src/appfinder-window.h>
+#include <src/appfinder-private.h>
+
+
+#define APPFINDER_DBUS_SERVICE "org.xfce.Appfinder"
+#define APPFINDER_DBUS_INTERFACE APPFINDER_DBUS_SERVICE
+#define APPFINDER_DBUS_PATH "/org/xfce/Appfinder"
+#define APPFINDER_DBUS_METHOD_OPEN "OpenWindow"
+#define APPFINDER_DBUS_METHOD_QUIT "Quit"
+#define APPFINDER_DBUS_ERROR APPFINDER_DBUS_SERVICE ".Error"
-static gboolean opt_finder = FALSE;
+
+static gboolean opt_expanded = FALSE;
static gboolean opt_version = FALSE;
+static gboolean opt_replace = FALSE;
+static gboolean opt_quit = FALSE;
static gchar *opt_filename = NULL;
+static GSList *windows = NULL;
+static gboolean service_owner = FALSE;
static GOptionEntry option_entries[] =
{
- { "finder", '\0', 0, G_OPTION_ARG_NONE, &opt_finder, N_("Start in expanded mode"), NULL },
+ { "expanded", 'x', 0, G_OPTION_ARG_NONE, &opt_expanded, N_("Start in expanded mode"), NULL },
{ "version", 'V', 0, G_OPTION_ARG_NONE, &opt_version, N_("Print version information and exit"), NULL },
+ { "replace", 'r', 0, G_OPTION_ARG_NONE, &opt_replace, N_("Replace the existing service"), NULL },
+ { "quit", 'q', 0, G_OPTION_ARG_NONE, &opt_quit, N_("Quit all instances"), NULL },
{ G_OPTION_REMAINING, '\0', 0, G_OPTION_ARG_FILENAME, &opt_filename, NULL, NULL },
{ NULL }
};
+static void appfinder_dbus_unregister (DBusConnection *dbus_connection);
+
+
+
+static void
+appfinder_window_destroyed (GtkWidget *window)
+{
+ if (windows == NULL)
+ return;
+
+ /* remove from internal list */
+ windows = g_slist_remove (windows, window);
+
+ /* leave if all windows are closed and we're not service owner */
+ if (windows == NULL && !service_owner)
+ gtk_main_quit ();
+}
+
+
+
+static void
+appfinder_window_new (const gchar *startup_id,
+ gboolean expanded,
+ const gchar *menu_filename)
+{
+ GtkWidget *window;
+
+ window = g_object_new (XFCE_TYPE_APPFINDER_WINDOW,
+ "startup-id", IS_STRING (startup_id) ? startup_id : NULL,
+ NULL);
+ xfce_appfinder_window_set_expanded (XFCE_APPFINDER_WINDOW (window), expanded);
+ gtk_widget_show (window);
+
+ windows = g_slist_prepend (windows, window);
+ g_signal_connect (G_OBJECT (window), "destroy",
+ G_CALLBACK (appfinder_window_destroyed), NULL);
+}
+
+
+
+static DBusHandlerResult
+appfinder_dbus_message (DBusConnection *dbus_connection,
+ DBusMessage *message,
+ gpointer user_data)
+{
+ DBusMessage *reply;
+ gboolean expanded;
+ gchar *startup_id;
+ DBusError derror;
+ gchar *menu_filename;
+
+ if (dbus_message_is_method_call (message, APPFINDER_DBUS_INTERFACE, APPFINDER_DBUS_METHOD_OPEN))
+ {
+ dbus_error_init (&derror);
+ if (dbus_message_get_args (message, &derror,
+ DBUS_TYPE_BOOLEAN, &expanded,
+ DBUS_TYPE_STRING, &startup_id,
+ DBUS_TYPE_STRING, &menu_filename,
+ DBUS_TYPE_INVALID))
+ {
+ appfinder_window_new (startup_id, expanded, menu_filename);
+ reply = dbus_message_new_method_return (message);
+ }
+ else
+ {
+ reply = dbus_message_new_error (message, APPFINDER_DBUS_ERROR, derror.message);
+ dbus_error_free (&derror);
+ }
+
+ dbus_connection_send (dbus_connection, reply, NULL);
+ dbus_message_unref (reply);
+ }
+ else if (dbus_message_is_method_call (message, APPFINDER_DBUS_INTERFACE, APPFINDER_DBUS_METHOD_QUIT))
+ {
+ /* close all windows and quit */
+ g_printerr ("%s: %s.\n", PACKAGE_NAME, _("Forced to quit"));
+ gtk_main_quit ();
+ }
+ else if (dbus_message_is_signal (message, DBUS_INTERFACE_LOCAL, "Disconnected")
+ || dbus_message_is_signal (message, DBUS_INTERFACE_DBUS, "NameOwnerChanged"))
+ {
+ if (windows != NULL)
+ {
+ /* don't respond to dbus signals and close on last window */
+ appfinder_dbus_unregister (dbus_connection);
+ }
+ else
+ {
+ /* no active windows, just exit the instance */
+ gtk_main_quit ();
+ }
+ }
+ else
+ {
+ return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
+ }
+
+ return DBUS_HANDLER_RESULT_HANDLED;
+}
+
+
+
+static gboolean
+appfinder_dbus_open_window (DBusConnection *dbus_connection,
+ const gchar *startup_id,
+ const gchar *menu_filename)
+{
+
+ DBusError derror;
+ DBusMessage *method, *result;
+
+ method = dbus_message_new_method_call (APPFINDER_DBUS_SERVICE,
+ APPFINDER_DBUS_PATH,
+ APPFINDER_DBUS_INTERFACE,
+ APPFINDER_DBUS_METHOD_OPEN);
+
+ if (startup_id == NULL)
+ startup_id = "";
+ if (menu_filename == NULL)
+ menu_filename = "";
+
+ dbus_message_append_args (method,
+ DBUS_TYPE_BOOLEAN, &opt_expanded,
+ DBUS_TYPE_STRING, &startup_id,
+ DBUS_TYPE_STRING, &menu_filename,
+ DBUS_TYPE_INVALID);
+
+ dbus_message_set_auto_start (method, TRUE);
+ dbus_error_init (&derror);
+ result = dbus_connection_send_with_reply_and_block (dbus_connection, method, 5000, &derror);
+ dbus_message_unref (method);
+
+ if (G_UNLIKELY (result == NULL))
+ {
+ g_critical ("Failed to open window: %s", derror.message);
+ dbus_error_free(&derror);
+ return FALSE;
+ }
+
+ dbus_message_unref (result);
+
+ return TRUE;
+}
+
+
+
+static gint
+appfinder_dbus_quit (void)
+{
+ DBusMessage *method;
+ DBusConnection *dbus_connection;
+ DBusError derror;
+ gboolean succeed = FALSE;
+
+ dbus_error_init (&derror);
+ dbus_connection = dbus_bus_get (DBUS_BUS_SESSION, &derror);
+ if (G_LIKELY (dbus_connection != NULL))
+ {
+ method = dbus_message_new_method_call (APPFINDER_DBUS_SERVICE,
+ APPFINDER_DBUS_PATH,
+ APPFINDER_DBUS_INTERFACE,
+ APPFINDER_DBUS_METHOD_QUIT);
+
+ dbus_message_set_auto_start (method, FALSE);
+ succeed = dbus_connection_send (dbus_connection, method, NULL);
+ dbus_message_unref (method);
+
+ dbus_connection_flush (dbus_connection);
+ dbus_connection_unref (dbus_connection);
+ }
+ else
+ {
+ g_warning ("Unable to open D-Bus connection: %s", derror.message);
+ dbus_error_free (&derror);
+ }
+
+ return succeed ? EXIT_SUCCESS : EXIT_FAILURE;
+}
+
+
+
+static void
+appfinder_dbus_unregister (DBusConnection *dbus_connection)
+{
+ if (service_owner)
+ {
+ service_owner = FALSE;
+
+ dbus_connection_remove_filter (dbus_connection, appfinder_dbus_message, NULL);
+ dbus_connection_unregister_object_path (dbus_connection, APPFINDER_DBUS_PATH);
+ dbus_bus_release_name (dbus_connection, APPFINDER_DBUS_SERVICE, NULL);
+ }
+}
+
+
+
gint
main (gint argc, gchar **argv)
{
- GError *error = NULL;
- GtkWidget *window;
- const gchar *desktop;
+ GError *error = NULL;
+ const gchar *desktop;
+ DBusConnection *dbus_connection;
+ guint dbus_flags;
+ DBusObjectPathVTable vtable = { NULL, appfinder_dbus_message, NULL, };
+ gint result;
+ const gchar *startup_id;
+ DBusError derror;
+ GSList *windows_destroy;
/* set translation domain */
xfce_textdomain (GETTEXT_PACKAGE, PACKAGE_LOCALE_DIR, "UTF-8");
@@ -68,6 +289,9 @@ main (gint argc, gchar **argv)
if (!g_thread_supported ())
g_thread_init (NULL);
+ /* get the startup notification id */
+ startup_id = g_getenv ("DESKTOP_STARTUP_ID");
+
if (!gtk_init_with_args (&argc, &argv, _("[MENUFILE]"), option_entries, GETTEXT_PACKAGE, &error))
{
g_printerr ("%s: %s.\n", PACKAGE_NAME, error->message);
@@ -89,6 +313,9 @@ main (gint argc, gchar **argv)
return EXIT_SUCCESS;
}
+ if (opt_quit)
+ return appfinder_dbus_quit ();
+
/* 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");
@@ -98,16 +325,86 @@ main (gint argc, gchar **argv)
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);
+ xfconf_init (NULL);
+
+ /* become the serivce owner or ask the current owner to spawn an instance */
+ dbus_error_init (&derror);
+ dbus_connection = dbus_bus_get (DBUS_BUS_SESSION, &derror);
+ if (G_LIKELY (dbus_connection != NULL))
+ {
+ dbus_connection_set_exit_on_disconnect (dbus_connection, FALSE);
+
+ dbus_flags = DBUS_NAME_FLAG_DO_NOT_QUEUE | DBUS_NAME_FLAG_ALLOW_REPLACEMENT;
+ if (opt_replace)
+ dbus_flags |= DBUS_NAME_FLAG_REPLACE_EXISTING;
+
+ result = dbus_bus_request_name (dbus_connection, APPFINDER_DBUS_SERVICE, dbus_flags, &derror);
+ if (result == DBUS_REQUEST_NAME_REPLY_PRIMARY_OWNER)
+ {
+ dbus_connection_setup_with_g_main (dbus_connection, NULL);
+
+ /* watch owner changes */
+ dbus_bus_add_match (dbus_connection, "type='signal',member='NameOwnerChanged',"
+ "arg0='"APPFINDER_DBUS_SERVICE"'", NULL);
+
+ /* method handling for the appfinder */
+ if (dbus_connection_register_object_path (dbus_connection, APPFINDER_DBUS_PATH, &vtable, NULL)
+ && dbus_connection_add_filter (dbus_connection, appfinder_dbus_message, NULL, NULL))
+ {
+ APPFINDER_DEBUG ("registered dbus service");
+
+ /* successfully registered the service */
+ service_owner = TRUE;
+ }
+ else
+ {
+ g_warning ("Failed to register D-Bus filter or vtable");
+ }
+ }
+ else if (result == DBUS_REQUEST_NAME_REPLY_EXISTS)
+ {
+ if (appfinder_dbus_open_window (dbus_connection, startup_id, opt_filename))
+ {
+ /* successfully opened a window in the other instance */
+ dbus_connection_unref (dbus_connection);
+ return EXIT_SUCCESS;
+ }
+ }
+ else
+ {
+ g_warning ("Unable to request D-Bus name: %s", derror.message);
+ dbus_error_free (&derror);
+ }
+ }
+ else
+ {
+ g_warning ("Unable to open D-Bus connection: %s", derror.message);
+ dbus_error_free (&derror);
+ }
+
+ /* create initial window */
+ appfinder_window_new (NULL, opt_expanded, opt_filename);
APPFINDER_DEBUG ("enter mainloop");
gtk_main ();
- gtk_widget_hide (window);
- gtk_widget_destroy (window);
+ xfconf_shutdown ();
+
+ if (G_LIKELY (dbus_connection != NULL))
+ {
+ appfinder_dbus_unregister (dbus_connection);
+ dbus_connection_unref (dbus_connection);
+ }
+
+ if (windows != NULL)
+ {
+ windows_destroy = windows;
+ windows = NULL;
+
+ /* destroy all windows without poking gtk_main_quit */
+ g_slist_foreach (windows_destroy, (GFunc) gtk_widget_destroy, NULL);
+ }
return EXIT_SUCCESS;
}
More information about the Xfce4-commits
mailing list