[Xfce4-commits] <xfce4-appfinder:nick/properties-dialog> Initial work on custom actions.
Nick Schermer
noreply at xfce.org
Mon Sep 19 21:10:01 CEST 2011
Updating branch refs/heads/nick/properties-dialog
to 710bf82fbb6e7e28d44e6bae2811f99fc0ccbcd0 (commit)
from de1b26d156b3a76ca94a3e0949a2b642fcfc8c8d (commit)
commit 710bf82fbb6e7e28d44e6bae2811f99fc0ccbcd0
Author: Nick Schermer <nick at xfce.org>
Date: Sun Aug 7 14:55:02 2011 +0200
Initial work on custom actions.
Action removing and adding is not working yet.
src/Makefile.am | 2 +
src/appfinder-actions.c | 524 +++++++++++++++++++++++++++++++++++++++
src/appfinder-actions.h | 57 +++++
src/appfinder-preferences.c | 280 ++++++++++++++++++++--
src/appfinder-preferences.glade | 134 +++++-----
src/appfinder-window.c | 71 ++----
6 files changed, 934 insertions(+), 134 deletions(-)
diff --git a/src/Makefile.am b/src/Makefile.am
index 91065af..37e1509 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -13,6 +13,8 @@ xfce4_appfinder_built_sources = \
xfce4_appfinder_SOURCES = \
$(xfce4_appfinder_built_sources) \
+ appfinder-actions.c \
+ appfinder-actions.h \
appfinder-category-model.c \
appfinder-category-model.h \
appfinder-model.c \
diff --git a/src/appfinder-actions.c b/src/appfinder-actions.c
new file mode 100644
index 0000000..cfb5b46
--- /dev/null
+++ b/src/appfinder-actions.c
@@ -0,0 +1,524 @@
+/*
+ * 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 <xfconf/xfconf.h>
+
+#include <src/appfinder-actions.h>
+#include <src/appfinder-private.h>
+
+
+
+static void xfce_appfinder_actions_finalize (GObject *object);
+static void xfce_appfinder_actions_free (XfceAppfinderAction *action);
+static void xfce_appfinder_actions_load (XfceAppfinderActions *actions);
+static void xfce_appfinder_actions_save (XfceAppfinderActions *actions,
+ gboolean save_actions);
+static void xfce_appfinder_actions_changed (XfconfChannel *channel,
+ const gchar *prop_name,
+ const GValue *value,
+ XfceAppfinderActions *actions);
+
+
+
+struct _XfceAppfinderActionsClass
+{
+ GObjectClass __parent__;
+};
+
+struct _XfceAppfinderActions
+{
+ GObject __parent__;
+
+ XfconfChannel *channel;
+ gulong property_watch_id;
+
+ GSList *actions;
+};
+
+typedef enum
+{
+ XFCE_APPFINDER_ACTION_TYPE_PREFIX,
+ XFCE_APPFINDER_ACTION_TYPE_REGEX
+}
+AppfinderActionType;
+
+struct _XfceAppfinderAction
+{
+ AppfinderActionType type;
+
+ gint unique_id;
+ gchar *pattern;
+ gchar *command;
+
+ GRegex *regex;
+};
+
+
+
+G_DEFINE_TYPE (XfceAppfinderActions, xfce_appfinder_actions, G_TYPE_OBJECT)
+
+
+
+static void
+xfce_appfinder_actions_class_init (XfceAppfinderActionsClass *klass)
+{
+ GObjectClass *gobject_class;
+
+ gobject_class = G_OBJECT_CLASS (klass);
+ gobject_class->finalize = xfce_appfinder_actions_finalize;
+}
+
+
+
+static void
+xfce_appfinder_actions_init (XfceAppfinderActions *actions)
+{
+ actions->channel = xfconf_channel_get ("xfce4-appfinder");
+
+ xfce_appfinder_actions_load (actions);
+
+ actions->property_watch_id =
+ g_signal_connect (G_OBJECT (actions->channel), "property-changed",
+ G_CALLBACK (xfce_appfinder_actions_changed), actions);
+}
+
+
+
+static void
+xfce_appfinder_actions_finalize (GObject *object)
+{
+ XfceAppfinderActions *actions = XFCE_APPFINDER_ACTIONS (object);
+
+ g_signal_handler_disconnect (actions->channel, actions->property_watch_id);
+
+ g_slist_foreach (actions->actions, (GFunc) xfce_appfinder_actions_free, NULL);
+ g_slist_free (actions->actions);
+
+ (*G_OBJECT_CLASS (xfce_appfinder_actions_parent_class)->finalize) (object);
+}
+
+
+
+static void
+xfce_appfinder_actions_free (XfceAppfinderAction *action)
+{
+ g_free (action->pattern);
+ g_free (action->command);
+
+ if (action->regex != NULL)
+ g_regex_unref (action->regex);
+
+ g_slice_free (XfceAppfinderAction, action);
+}
+
+
+
+static void
+xfce_appfinder_actions_load_defaults (XfceAppfinderActions *actions)
+{
+ guint i;
+ XfceAppfinderAction *action;
+ XfceAppfinderAction defaults[] =
+ {
+ { XFCE_APPFINDER_ACTION_TYPE_PREFIX, 0,
+ "#",
+ "exo-open --launch TerminalEmulator man %s",
+ NULL },
+ { XFCE_APPFINDER_ACTION_TYPE_PREFIX, 0,
+ "!",
+ "exo-open --launch TerminalEmulator %s",
+ NULL },
+ { XFCE_APPFINDER_ACTION_TYPE_PREFIX, 0,
+ "!w",
+ "exo-open --launch WebBrowser http://en.wikipedia.org/wiki/%s",
+ NULL },
+ { XFCE_APPFINDER_ACTION_TYPE_REGEX, 0,
+ "^(file|http|https):\\/\\/(.*)$",
+ "exo-open \\0",
+ NULL }
+ };
+
+ APPFINDER_DEBUG ("loaded default actions");
+
+ for (i = 0; i < G_N_ELEMENTS (defaults); i++)
+ {
+ action = g_slice_new0 (XfceAppfinderAction);
+ action->type = defaults[i].type;
+ action->unique_id = i + 1;
+ action->pattern = g_strdup (defaults[i].pattern);
+ action->command = g_strdup (defaults[i].command);
+
+ actions->actions = g_slist_prepend (actions->actions, action);
+ }
+}
+
+
+
+static gint
+xfce_appfinder_actions_sort (gconstpointer a,
+ gconstpointer b)
+{
+ const XfceAppfinderAction *action_a = a;
+ const XfceAppfinderAction *action_b = b;
+
+ if (action_a->type != action_b->type)
+ return action_a->type == XFCE_APPFINDER_ACTION_TYPE_PREFIX ? -1 : 1;
+
+ /* reverse the order so prefixes are properly matched */
+ return -g_strcmp0 (action_a->pattern, action_b->pattern);
+}
+
+
+
+static void
+xfce_appfinder_actions_load (XfceAppfinderActions *actions)
+{
+ XfceAppfinderAction *action;
+ gchar prop[32];
+ gint type;
+ gchar *pattern, *command;
+ const GValue *value;
+ guint i;
+ gint unique_id;
+ GPtrArray *array;
+
+ if (xfconf_channel_has_property (actions->channel, "/actions"))
+ {
+ array = xfconf_channel_get_arrayv (actions->channel, "/actions");
+ if (G_LIKELY (array != NULL))
+ {
+ for (i = 0; i < array->len; i++)
+ {
+ value = g_ptr_array_index (array, i);
+ appfinder_assert (value != NULL);
+ unique_id = g_value_get_int (value);
+
+ g_snprintf (prop, sizeof (prop), "/actions/action-%d/type", unique_id);
+ type = xfconf_channel_get_int (actions->channel, prop, -1);
+ if (type < XFCE_APPFINDER_ACTION_TYPE_PREFIX
+ || type > XFCE_APPFINDER_ACTION_TYPE_REGEX)
+ continue;
+
+ g_snprintf (prop, sizeof (prop), "/actions/action-%d/pattern", unique_id);
+ pattern = xfconf_channel_get_string (actions->channel, prop, NULL);
+
+ g_snprintf (prop, sizeof (prop), "/actions/action-%d/command", unique_id);
+ command = xfconf_channel_get_string (actions->channel, prop, NULL);
+
+ if (pattern != NULL && command != NULL)
+ {
+ action = g_slice_new0 (XfceAppfinderAction);
+ action->type = type;
+ action->unique_id = unique_id;
+ action->pattern = pattern;
+ action->command = command;
+
+ actions->actions = g_slist_prepend (actions->actions, action);
+ }
+ else
+ {
+ g_free (pattern);
+ g_free (command);
+ }
+ }
+
+ xfconf_array_free (array);
+ }
+ }
+ else
+ {
+ xfce_appfinder_actions_load_defaults (actions);
+
+ xfce_appfinder_actions_save (actions, TRUE);
+ }
+
+ actions->actions = g_slist_sort (actions->actions, xfce_appfinder_actions_sort);
+
+ APPFINDER_DEBUG ("loaded %d actions", g_slist_length (actions->actions));
+}
+
+
+
+static void
+xfce_appfinder_actions_save (XfceAppfinderActions *actions,
+ gboolean save_actions)
+{
+ XfceAppfinderAction *action;
+ GSList *li;
+ GValue *value;
+ GPtrArray *array;
+ gchar prop[32];
+
+ g_signal_handler_block (actions->channel, actions->property_watch_id);
+
+ array = g_ptr_array_new ();
+
+ for (li = actions->actions; li != NULL; li = li->next)
+ {
+ value = g_new0 (GValue, 1);
+ g_value_init (value, G_TYPE_INT);
+
+ action = li->data;
+ g_value_set_int (value, action->unique_id);
+ g_ptr_array_add (array, value);
+
+ if (save_actions)
+ {
+ g_snprintf (prop, sizeof (prop), "/actions/action-%d/type", action->unique_id);
+ xfconf_channel_set_int (actions->channel, prop, action->type);
+
+ g_snprintf (prop, sizeof (prop), "/actions/action-%d/pattern", action->unique_id);
+ xfconf_channel_set_string (actions->channel, prop, action->pattern);
+
+ g_snprintf (prop, sizeof (prop), "/actions/action-%d/command", action->unique_id);
+ xfconf_channel_set_string (actions->channel, prop, action->command);
+ }
+ }
+
+ xfconf_channel_set_arrayv (actions->channel, "/actions", array);
+
+ xfconf_array_free (array);
+
+ g_signal_handler_unblock (actions->channel, actions->property_watch_id);
+}
+
+
+
+static void
+xfce_appfinder_actions_changed (XfconfChannel *channel,
+ const gchar *prop_name,
+ const GValue *value,
+ XfceAppfinderActions *actions)
+{
+ gint unique_id;
+ gchar field[32];
+ GSList *li;
+ XfceAppfinderAction *action;
+
+ if (prop_name == NULL)
+ return;
+
+ if (strcmp (prop_name, "/actions") == 0)
+ {
+
+ }
+ else if (sscanf (prop_name, "/actions/action-%d/%30s",
+ &unique_id, field) == 2)
+ {
+ for (li = actions->actions; li != NULL; li = li->next)
+ {
+ action = li->data;
+
+ if (action->unique_id == unique_id)
+ {
+ if (strcmp (field, "type") == 0
+ && G_VALUE_HOLDS_INT (value))
+ {
+ action->type = g_value_get_int (value);
+ }
+ else if (strcmp (field, "pattern") == 0
+ && G_VALUE_HOLDS_STRING (value))
+ {
+ g_free (action->pattern);
+ action->pattern = g_value_dup_string (value);
+
+ if (action->regex != NULL)
+ {
+ g_regex_unref (action->regex);
+ action->regex = NULL;
+ }
+ }
+ else if (strcmp (field, "command") == 0
+ && G_VALUE_HOLDS_STRING (value))
+ {
+ g_free (action->command);
+ action->command = g_value_dup_string (value);
+ }
+
+ break;
+ }
+ }
+ }
+}
+
+
+
+static gchar *
+xfce_appfinder_actions_expand_command (XfceAppfinderAction *action,
+ const gchar *text)
+{
+ GString *string;
+ const gchar *p;
+ gsize len;
+ gchar *trim;
+
+ if (G_UNLIKELY (action->command == NULL))
+ return NULL;
+
+ string = g_string_sized_new (128);
+ len = strlen (action->pattern);
+
+ for (p = action->command; *p != '\0'; ++p)
+ {
+ if (G_UNLIKELY (p[0] == '%' && p[1] != '\0'))
+ {
+ switch (*++p)
+ {
+ case 's':
+ trim = g_strdup (text + len);
+ g_string_append (string, g_strchug (trim));
+ g_free (trim);
+ break;
+
+ case 'S':
+ g_string_append (string, text);
+ break;
+
+ case '%':
+ g_string_append_c (string, '%');
+ break;
+ }
+ }
+ else
+ {
+ g_string_append_c (string, *p);
+ }
+ }
+
+ return g_string_free (string, FALSE);
+}
+
+
+
+XfceAppfinderActions *
+xfce_appfinder_actions_get (void)
+{
+ static XfceAppfinderActions *actions = NULL;
+
+ if (G_LIKELY (actions != NULL))
+ {
+ g_object_ref (G_OBJECT (actions));
+ }
+ else
+ {
+ actions = g_object_new (XFCE_TYPE_APPFINDER_ACTIONS, NULL);
+ g_object_add_weak_pointer (G_OBJECT (actions), (gpointer) &actions);
+ APPFINDER_DEBUG ("allocate actions");
+ }
+
+ return actions;
+}
+
+
+
+XfceAppfinderActionsResult
+xfce_appfinder_actions_execute (XfceAppfinderActions *actions,
+ const gchar *text,
+ GdkScreen *screen,
+ GError **error)
+{
+ GSList *li;
+ XfceAppfinderAction *action;
+ XfceAppfinderActionsResult result = XFCE_APPFINDER_ACTIONS_NOTHING_FOUND;
+ GError *err = NULL;
+ gchar *cmd = NULL;
+ GMatchInfo *match_info = NULL;
+ gchar *expanded;
+
+ appfinder_return_val_if_fail (error != NULL && *error == NULL, XFCE_APPFINDER_ACTIONS_NOTHING_FOUND);
+ appfinder_return_val_if_fail (GDK_IS_SCREEN (screen), XFCE_APPFINDER_ACTIONS_NOTHING_FOUND);
+ appfinder_return_val_if_fail (XFCE_IS_APPFINDER_ACTIONS (actions), XFCE_APPFINDER_ACTIONS_NOTHING_FOUND);
+ appfinder_return_val_if_fail (text != NULL, XFCE_APPFINDER_ACTIONS_NOTHING_FOUND);
+
+ for (li = actions->actions;
+ result == XFCE_APPFINDER_ACTIONS_NOTHING_FOUND && li != NULL;
+ li = li->next)
+ {
+ action = li->data;
+
+ switch (action->type)
+ {
+ case XFCE_APPFINDER_ACTION_TYPE_PREFIX:
+ if (g_str_has_prefix (text, action->pattern))
+ {
+ cmd = xfce_appfinder_actions_expand_command (action, text);
+ result = XFCE_APPFINDER_ACTIONS_SUCCEED;
+ }
+ break;
+
+ case XFCE_APPFINDER_ACTION_TYPE_REGEX:
+ if (action->regex == NULL)
+ {
+ action->regex = g_regex_new (action->pattern, 0, 0, &err);
+ if (action->regex == NULL)
+ {
+ g_message ("Failed to create regex for \"%s\": %s",
+ action->pattern, err->message);
+ g_error_free (err);
+
+ break;
+ }
+ }
+
+ if (g_regex_match (action->regex, text, 0, &match_info))
+ {
+ /* expand the command string */
+ cmd = g_match_info_expand_references (match_info, action->command, &err);
+
+ if (G_UNLIKELY (err != NULL))
+ *error = err;
+ }
+
+ if (match_info != NULL)
+ g_match_info_free (match_info);
+
+ break;
+ }
+ }
+
+ if (result == XFCE_APPFINDER_ACTIONS_SUCCEED
+ && cmd != NULL
+ && *error == NULL)
+ {
+ /* also expand variables... */
+ expanded = xfce_expand_variables (cmd, NULL);
+ g_free (cmd);
+ cmd = expanded;
+
+ APPFINDER_DEBUG ("spawn command \"%s\"", cmd);
+
+ if (xfce_spawn_command_line_on_screen (screen, cmd, FALSE, FALSE, error))
+ result = XFCE_APPFINDER_ACTIONS_SUCCEED;
+ else
+ result = XFCE_APPFINDER_ACTIONS_ERROR;
+ }
+
+ g_free (cmd);
+
+ return result;
+}
diff --git a/src/appfinder-actions.h b/src/appfinder-actions.h
new file mode 100644
index 0000000..97ceb80
--- /dev/null
+++ b/src/appfinder-actions.h
@@ -0,0 +1,57 @@
+/*
+ * 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_ACTIONS_H__
+#define __XFCE_APPFINDER_ACTIONS_H__
+
+#include <gtk/gtk.h>
+#include <garcon/garcon.h>
+
+G_BEGIN_DECLS
+
+typedef struct _XfceAppfinderActionsClass XfceAppfinderActionsClass;
+typedef struct _XfceAppfinderActions XfceAppfinderActions;
+typedef struct _XfceAppfinderAction XfceAppfinderAction;
+
+#define XFCE_TYPE_APPFINDER_ACTIONS (xfce_appfinder_actions_get_type ())
+#define XFCE_APPFINDER_ACTIONS(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), XFCE_TYPE_APPFINDER_ACTIONS, XfceAppfinderActions))
+#define XFCE_APPFINDER_ACTIONS_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), XFCE_TYPE_APPFINDER_ACTIONS, XfceAppfinderActionsClass))
+#define XFCE_IS_APPFINDER_ACTIONS(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), XFCE_TYPE_APPFINDER_ACTIONS))
+#define XFCE_IS_APPFINDER_ACTIONS_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), XFCE_TYPE_APPFINDER_ACTIONS))
+#define XFCE_APPFINDER_ACTIONS_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), XFCE_TYPE_APPFINDER_ACTIONS, XfceAppfinderActionsClass))
+
+typedef enum
+{
+ XFCE_APPFINDER_ACTIONS_SUCCEED, /* launched an action */
+ XFCE_APPFINDER_ACTIONS_NOTHING_FOUND, /* no suitable action found */
+ XFCE_APPFINDER_ACTIONS_ERROR /* action found, but spawn error */
+}
+XfceAppfinderActionsResult;
+
+GType xfce_appfinder_actions_get_type (void) G_GNUC_CONST;
+
+XfceAppfinderActions *xfce_appfinder_actions_get (void) G_GNUC_MALLOC;
+
+XfceAppfinderActionsResult xfce_appfinder_actions_execute (XfceAppfinderActions *actions,
+ const gchar *text,
+ GdkScreen *screen,
+ GError **error);
+
+G_END_DECLS
+
+#endif /* !__XFCE_APPFINDER_ACTIONS_H__ */
diff --git a/src/appfinder-preferences.c b/src/appfinder-preferences.c
index 026acfd..a277f0f 100644
--- a/src/appfinder-preferences.c
+++ b/src/appfinder-preferences.c
@@ -35,10 +35,20 @@
-static void xfce_appfinder_preferences_response (GtkWidget *window,
- gint response_id,
- XfceAppfinderPreferences *preferences);
-static void xfce_appfinder_preferences_clear_history (XfceAppfinderPreferences *preferences);
+static void xfce_appfinder_preferences_response (GtkWidget *window,
+ gint response_id,
+ XfceAppfinderPreferences *preferences);
+static void xfce_appfinder_preferences_clear_history (XfceAppfinderPreferences *preferences);
+static void xfce_appfinder_preferences_action_add (XfceAppfinderPreferences *preferences);
+static void xfce_appfinder_preferences_action_remove (GtkWidget *button,
+ XfceAppfinderPreferences *preferences);
+static void xfce_appfinder_preferences_action_changed (XfconfChannel *channel,
+ const gchar *prop_name,
+ const GValue *value,
+ XfceAppfinderPreferences *preferences);
+static void xfce_appfinder_preferences_action_populate (XfceAppfinderPreferences *preferences);
+static void xfce_appfinder_preferences_selection_changed (GtkTreeSelection *selection,
+ XfceAppfinderPreferences *preferences);
@@ -51,7 +61,18 @@ struct _XfceAppfinderPreferences
{
GtkBuilder __parent__;
- GObject *dialog;
+ GObject *dialog;
+
+ XfconfChannel *channel;
+
+ gulong bindings[3];
+ gulong property_watch_id;
+};
+
+enum
+{
+ COLUMN_PATTERN,
+ COLUMN_UNIQUE_ID
};
@@ -70,8 +91,11 @@ xfce_appfinder_preferences_class_init (XfceAppfinderPreferencesClass *klass)
static void
xfce_appfinder_preferences_init (XfceAppfinderPreferences *preferences)
{
- XfconfChannel *channel;
- GObject *object;
+ GObject *object;
+ GtkTreeSelection *selection;
+ GtkTreePath *path;
+
+ preferences->channel = xfconf_channel_get ("xfce4-appfinder");
/* load the builder data into the object */
gtk_builder_add_from_string (GTK_BUILDER (preferences), appfinder_preferences_ui,
@@ -82,19 +106,41 @@ xfce_appfinder_preferences_init (XfceAppfinderPreferences *preferences)
g_signal_connect (G_OBJECT (preferences->dialog), "response",
G_CALLBACK (xfce_appfinder_preferences_response), preferences);
- channel = xfconf_channel_get ("xfce4-appfinder");
-
object = gtk_builder_get_object (GTK_BUILDER (preferences), "remember-category");
- xfconf_g_property_bind (channel, "/RememberCategory", G_TYPE_BOOLEAN,
+ xfconf_g_property_bind (preferences->channel, "/remember-category", G_TYPE_BOOLEAN,
G_OBJECT (object), "active");
object = gtk_builder_get_object (GTK_BUILDER (preferences), "always-center");
- xfconf_g_property_bind (channel, "/AlwaysCenter", G_TYPE_BOOLEAN,
+ xfconf_g_property_bind (preferences->channel, "/always-center", G_TYPE_BOOLEAN,
G_OBJECT (object), "active");
object = gtk_builder_get_object (GTK_BUILDER (preferences), "button-clear");
g_signal_connect_swapped (G_OBJECT (object), "clicked",
G_CALLBACK (xfce_appfinder_preferences_clear_history), preferences);
+
+ object = gtk_builder_get_object (GTK_BUILDER (preferences), "button-add");
+ g_signal_connect_swapped (G_OBJECT (object), "clicked",
+ G_CALLBACK (xfce_appfinder_preferences_action_add), preferences);
+
+ object = gtk_builder_get_object (GTK_BUILDER (preferences), "button-remove");
+ g_signal_connect (G_OBJECT (object), "clicked",
+ G_CALLBACK (xfce_appfinder_preferences_action_remove), preferences);
+
+ xfce_appfinder_preferences_action_populate (preferences);
+
+ object = gtk_builder_get_object (GTK_BUILDER (preferences), "actions-treeview");
+
+ selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (object));
+ g_signal_connect (G_OBJECT (selection), "changed",
+ G_CALLBACK (xfce_appfinder_preferences_selection_changed), preferences);
+
+ path = gtk_tree_path_new_first ();
+ gtk_tree_selection_select_path (selection, path);
+ gtk_tree_path_free (path);
+
+ preferences->property_watch_id =
+ g_signal_connect (G_OBJECT (preferences->channel), "property-changed",
+ G_CALLBACK (xfce_appfinder_preferences_action_changed), preferences);
}
@@ -107,7 +153,10 @@ xfce_appfinder_preferences_response (GtkWidget *window,
appfinder_return_if_fail (GTK_IS_DIALOG (window));
appfinder_return_if_fail (XFCE_IS_APPFINDER_PREFERENCES (preferences));
+ g_signal_handler_disconnect (preferences->channel, preferences->property_watch_id);
+
gtk_widget_destroy (window);
+
g_object_unref (G_OBJECT (preferences));
}
@@ -117,11 +166,10 @@ static void
xfce_appfinder_preferences_clear_history (XfceAppfinderPreferences *preferences)
{
XfceAppfinderModel *model;
-
+
appfinder_return_if_fail (XFCE_IS_APPFINDER_PREFERENCES (preferences));
-
- if (xfce_dialog_confirm (GTK_WINDOW (preferences->dialog), GTK_STOCK_CLEAR,
- _("Clear Command History"),
+
+ if (xfce_dialog_confirm (GTK_WINDOW (preferences->dialog), GTK_STOCK_CLEAR, _("C_lear"),
_("This will permanently clear the custom command history."),
_("Are you sure you want to clear the command history?")))
{
@@ -133,6 +181,208 @@ xfce_appfinder_preferences_clear_history (XfceAppfinderPreferences *preferences)
+static void
+xfce_appfinder_preferences_action_add (XfceAppfinderPreferences *preferences)
+{
+
+}
+
+
+
+static void
+xfce_appfinder_preferences_action_remove (GtkWidget *button,
+ XfceAppfinderPreferences *preferences)
+{
+ GObject *object;
+
+ object = gtk_builder_get_object (GTK_BUILDER (preferences), "pattern");
+ if (xfce_dialog_confirm (GTK_WINDOW (gtk_widget_get_toplevel (button)),
+ GTK_STOCK_DELETE, NULL,
+ _("The custom action will be deleted permanently."),
+ _("Are you sure you want to delete pattern \"%s\"?"),
+ gtk_entry_get_text (GTK_ENTRY (object))))
+ {
+
+ }
+}
+
+
+
+typedef struct
+{
+ gint unique_id;
+ const GValue *value;
+}
+UpdateContext;
+
+
+
+static gboolean
+xfce_appfinder_preferences_action_changed_func (GtkTreeModel *model,
+ GtkTreePath *path,
+ GtkTreeIter *iter,
+ gpointer data)
+{
+ gint unique_id;
+ UpdateContext *context = data;
+
+ gtk_tree_model_get (model, iter, COLUMN_UNIQUE_ID, &unique_id, -1);
+
+ if (context->unique_id == unique_id)
+ {
+ gtk_list_store_set (GTK_LIST_STORE (model), iter, COLUMN_PATTERN,
+ g_value_get_string (context->value),
+ -1);
+
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+
+
+static void
+xfce_appfinder_preferences_action_changed (XfconfChannel *channel,
+ const gchar *prop_name,
+ const GValue *value,
+ XfceAppfinderPreferences *preferences)
+{
+ gint unique_id;
+ GObject *store;
+ UpdateContext context;
+
+ if (prop_name == NULL)
+ return;
+
+ if (strcmp (prop_name, "/actions") == 0)
+ {
+ xfce_appfinder_preferences_action_populate (preferences);
+ }
+ else if (sscanf (prop_name, "/actions/action-%d/pattern", &unique_id) == 1
+ && G_VALUE_HOLDS_STRING (value))
+ {
+ context.unique_id = unique_id;
+ context.value = value;
+
+ store = gtk_builder_get_object (GTK_BUILDER (preferences), "actions-store");
+ gtk_tree_model_foreach (GTK_TREE_MODEL (store),
+ xfce_appfinder_preferences_action_changed_func, &context);
+ }
+}
+
+
+static void
+xfce_appfinder_preferences_action_populate (XfceAppfinderPreferences *preferences)
+{
+ GPtrArray *array;
+ GObject *store;
+ const GValue *value;
+ gint unique_id;
+ gchar prop[32];
+ gchar *pattern, *command;
+ guint i;
+
+ store = gtk_builder_get_object (GTK_BUILDER (preferences), "actions-store");
+ appfinder_assert (GTK_IS_LIST_STORE (store));
+ gtk_list_store_clear (GTK_LIST_STORE (store));
+
+ array = xfconf_channel_get_arrayv (preferences->channel, "/actions");
+ if (G_LIKELY (array != NULL))
+ {
+ for (i = 0; i < array->len; i++)
+ {
+ value = g_ptr_array_index (array, i);
+ appfinder_assert (value != NULL);
+ unique_id = g_value_get_int (value);
+
+ g_snprintf (prop, sizeof (prop), "/actions/action-%d/pattern", unique_id);
+ pattern = xfconf_channel_get_string (preferences->channel, prop, NULL);
+
+ g_snprintf (prop, sizeof (prop), "/actions/action-%d/command", unique_id);
+ command = xfconf_channel_get_string (preferences->channel, prop, NULL);
+
+ gtk_list_store_insert_with_values (GTK_LIST_STORE (store), NULL, i,
+ COLUMN_UNIQUE_ID, unique_id,
+ COLUMN_PATTERN, pattern,
+ -1);
+
+ g_free (pattern);
+ g_free (command);
+ }
+
+ xfconf_array_free (array);
+ }
+}
+
+
+
+typedef struct
+{
+ const gchar *name;
+ const gchar *prop_name;
+ GType prop_type;
+}
+dialog_object;
+
+
+
+static void
+xfce_appfinder_preferences_selection_changed (GtkTreeSelection *selection,
+ XfceAppfinderPreferences *preferences)
+{
+ GtkTreeModel *store;
+ GtkTreeIter iter;
+ gint unique_id;
+ GObject *object;
+ guint i;
+ gchar prop[32];
+ dialog_object objects[] =
+ {
+ { "type", "active", G_TYPE_INT },
+ { "pattern", "text", G_TYPE_STRING },
+ { "command", "text", G_TYPE_STRING }
+ };
+
+ appfinder_return_if_fail (GTK_IS_TREE_SELECTION (selection));
+ appfinder_return_if_fail (XFCE_IS_APPFINDER_PREFERENCES (preferences));
+ appfinder_return_if_fail (G_N_ELEMENTS (preferences->bindings) == G_N_ELEMENTS (objects));
+
+ /* drop old bindings */
+ for (i = 0; i < G_N_ELEMENTS (preferences->bindings); i++)
+ {
+ if (preferences->bindings[i] != 0)
+ {
+ xfconf_g_property_unbind (preferences->bindings[i]);
+ preferences->bindings[i] = 0;
+ }
+ }
+
+ if (gtk_tree_selection_get_selected (selection, &store, &iter))
+ gtk_tree_model_get (store, &iter, COLUMN_UNIQUE_ID, &unique_id, -1);
+ else
+ unique_id = -1;
+
+ for (i = 0; i < G_N_ELEMENTS (objects); i++)
+ {
+ object = gtk_builder_get_object (GTK_BUILDER (preferences), objects[i].name);
+ appfinder_return_if_fail (GTK_IS_WIDGET (object));
+ gtk_widget_set_sensitive (GTK_WIDGET (object), unique_id != -1);
+ if (unique_id > -1)
+ {
+ g_snprintf (prop, sizeof (prop), "/actions/action-%d/%s", unique_id, objects[i].name);
+ preferences->bindings[i] = xfconf_g_property_bind (preferences->channel, prop,
+ objects[i].prop_type, object,
+ objects[i].prop_name);
+ }
+ }
+
+ object = gtk_builder_get_object (GTK_BUILDER (preferences), "button-remove");
+ gtk_widget_set_sensitive (GTK_WIDGET (object), unique_id != -1);
+}
+
+
+
void
xfce_appfinder_preferences_show (GdkScreen *screen)
{
diff --git a/src/appfinder-preferences.glade b/src/appfinder-preferences.glade
index a4dad9c..3eb3b02 100644
--- a/src/appfinder-preferences.glade
+++ b/src/appfinder-preferences.glade
@@ -3,14 +3,26 @@
<requires lib="gtk+" version="2.20"/>
<!-- interface-requires libxfce4ui 4.5 -->
<!-- interface-naming-policy project-wide -->
- <object class="GtkListStore" id="actions-store">
+ <object class="GtkListStore" id="action-types">
<columns>
- <!-- column-name icon-name -->
- <column type="gchararray"/>
- <!-- column-name prefix -->
+ <!-- column-name title -->
<column type="gchararray"/>
- <!-- column-name command -->
+ </columns>
+ <data>
+ <row>
+ <col id="0" translatable="yes">Prefix</col>
+ </row>
+ <row>
+ <col id="0" translatable="yes">Regular Expression</col>
+ </row>
+ </data>
+ </object>
+ <object class="GtkListStore" id="actions-store">
+ <columns>
+ <!-- column-name pattern -->
<column type="gchararray"/>
+ <!-- column-name unique-id -->
+ <column type="gint"/>
</columns>
</object>
<object class="XfceTitledDialog" id="dialog">
@@ -220,34 +232,12 @@
<property name="enable_search">False</property>
<property name="search_column">0</property>
<child>
- <object class="GtkTreeViewColumn" id="treeviewcolumn3">
- <property name="title" translatable="yes">Icon</property>
- <child>
- <object class="GtkCellRendererPixbuf" id="cellrendererpixbuf1"/>
- <attributes>
- <attribute name="icon-name">0</attribute>
- </attributes>
- </child>
- </object>
- </child>
- <child>
<object class="GtkTreeViewColumn" id="treeviewcolumn1">
- <property name="title" translatable="yes">Prefix</property>
+ <property name="title" translatable="yes">Pattern</property>
<child>
<object class="GtkCellRendererText" id="cellrenderertext1"/>
<attributes>
- <attribute name="text">1</attribute>
- </attributes>
- </child>
- </object>
- </child>
- <child>
- <object class="GtkTreeViewColumn" id="treeviewcolumn2">
- <property name="title" translatable="yes">Command</property>
- <child>
- <object class="GtkCellRendererText" id="cellrenderertext2"/>
- <attributes>
- <attribute name="text">2</attribute>
+ <attribute name="text">0</attribute>
</attributes>
</child>
</object>
@@ -340,32 +330,40 @@
<property name="column_spacing">12</property>
<property name="row_spacing">6</property>
<child>
- <object class="GtkEntry" id="action-prefix">
+ <object class="GtkEntry" id="command">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="invisible_char">•</property>
<property name="invisible_char_set">True</property>
<property name="primary_icon_activatable">False</property>
<property name="secondary_icon_activatable">False</property>
+ <property name="tooltip_text" translatable="yes">If the type is set to prefix, %s will be replaced with the string after the pattern, %S with the complete entry text. For regular expressions you can use \0 and \<num>.</property>
<property name="primary_icon_sensitive">True</property>
<property name="secondary_icon_sensitive">True</property>
</object>
<packing>
<property name="left_attach">1</property>
<property name="right_attach">2</property>
+ <property name="top_attach">2</property>
+ <property name="bottom_attach">3</property>
</packing>
</child>
<child>
- <object class="GtkLabel" id="label3">
+ <object class="GtkEntry" id="pattern">
<property name="visible">True</property>
- <property name="can_focus">False</property>
- <property name="xalign">0</property>
- <property name="label" translatable="yes">P_refix:</property>
- <property name="use_underline">True</property>
- <property name="mnemonic_widget">action-prefix</property>
+ <property name="can_focus">True</property>
+ <property name="invisible_char">•</property>
+ <property name="invisible_char_set">True</property>
+ <property name="primary_icon_activatable">False</property>
+ <property name="secondary_icon_activatable">False</property>
+ <property name="primary_icon_sensitive">True</property>
+ <property name="secondary_icon_sensitive">True</property>
</object>
<packing>
- <property name="x_options">GTK_FILL</property>
+ <property name="left_attach">1</property>
+ <property name="right_attach">2</property>
+ <property name="top_attach">1</property>
+ <property name="bottom_attach">2</property>
</packing>
</child>
<child>
@@ -375,63 +373,65 @@
<property name="xalign">0</property>
<property name="label" translatable="yes">Co_mmand:</property>
<property name="use_underline">True</property>
- <property name="mnemonic_widget">action-cmd</property>
+ <property name="mnemonic_widget">command</property>
</object>
<packing>
- <property name="top_attach">1</property>
- <property name="bottom_attach">2</property>
+ <property name="top_attach">2</property>
+ <property name="bottom_attach">3</property>
<property name="x_options">GTK_FILL</property>
</packing>
</child>
<child>
- <object class="GtkLabel" id="label5">
+ <object class="GtkLabel" id="label3">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="xalign">0</property>
- <property name="label" translatable="yes">_Icon:</property>
+ <property name="label" translatable="yes">Patte_rn:</property>
<property name="use_underline">True</property>
- <property name="mnemonic_widget">action-icon</property>
+ <property name="mnemonic_widget">pattern</property>
</object>
<packing>
- <property name="top_attach">2</property>
- <property name="bottom_attach">3</property>
+ <property name="top_attach">1</property>
+ <property name="bottom_attach">2</property>
<property name="x_options">GTK_FILL</property>
</packing>
</child>
<child>
- <object class="GtkEntry" id="action-cmd">
+ <object class="GtkLabel" id="label8">
<property name="visible">True</property>
- <property name="can_focus">True</property>
- <property name="invisible_char">•</property>
- <property name="invisible_char_set">True</property>
- <property name="primary_icon_activatable">False</property>
- <property name="secondary_icon_activatable">False</property>
- <property name="primary_icon_sensitive">True</property>
- <property name="secondary_icon_sensitive">True</property>
+ <property name="can_focus">False</property>
+ <property name="xalign">0</property>
+ <property name="label" translatable="yes">_Type:</property>
+ <property name="use_underline">True</property>
+ <property name="mnemonic_widget">type</property>
</object>
<packing>
- <property name="left_attach">1</property>
- <property name="right_attach">2</property>
- <property name="top_attach">1</property>
- <property name="bottom_attach">2</property>
+ <property name="x_options">GTK_FILL</property>
</packing>
</child>
<child>
- <object class="GtkEntry" id="action-icon">
+ <object class="GtkAlignment" id="alignment4">
<property name="visible">True</property>
- <property name="can_focus">True</property>
- <property name="invisible_char">•</property>
- <property name="invisible_char_set">True</property>
- <property name="primary_icon_activatable">False</property>
- <property name="secondary_icon_activatable">False</property>
- <property name="primary_icon_sensitive">True</property>
- <property name="secondary_icon_sensitive">True</property>
+ <property name="can_focus">False</property>
+ <property name="xalign">0</property>
+ <property name="xscale">0</property>
+ <child>
+ <object class="GtkComboBox" id="type">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="model">action-types</property>
+ <child>
+ <object class="GtkCellRendererText" id="cellrenderertext3"/>
+ <attributes>
+ <attribute name="text">0</attribute>
+ </attributes>
+ </child>
+ </object>
+ </child>
</object>
<packing>
<property name="left_attach">1</property>
<property name="right_attach">2</property>
- <property name="top_attach">2</property>
- <property name="bottom_attach">3</property>
</packing>
</child>
</object>
diff --git a/src/appfinder-window.c b/src/appfinder-window.c
index e78a3ac..5f50b73 100644
--- a/src/appfinder-window.c
+++ b/src/appfinder-window.c
@@ -33,6 +33,7 @@
#include <src/appfinder-model.h>
#include <src/appfinder-category-model.h>
#include <src/appfinder-preferences.h>
+#include <src/appfinder-actions.h>
#include <src/appfinder-private.h>
@@ -171,17 +172,17 @@ xfce_appfinder_window_init (XfceAppfinderWindow *window)
gint integer;
window->channel = xfconf_channel_get ("xfce4-appfinder");
- window->last_window_height = xfconf_channel_get_int (window->channel, "/LastWindowHeight", DEFAULT_WINDOW_HEIGHT);
+ window->last_window_height = xfconf_channel_get_int (window->channel, "/last/window-height", DEFAULT_WINDOW_HEIGHT);
window->category_model = xfce_appfinder_category_model_new ();
window->model = xfce_appfinder_model_get ();
gtk_window_set_title (GTK_WINDOW (window), _("Application Finder"));
- integer = xfconf_channel_get_int (window->channel, "/LastWindowWidth", DEFAULT_WINDOW_WIDTH);
+ integer = xfconf_channel_get_int (window->channel, "/last/window-width", DEFAULT_WINDOW_WIDTH);
gtk_window_set_default_size (GTK_WINDOW (window), integer, -1);
gtk_window_set_icon_name (GTK_WINDOW (window), GTK_STOCK_EXECUTE);
- if (xfconf_channel_get_bool (window->channel, "/AlwaysCenter", FALSE))
+ if (xfconf_channel_get_bool (window->channel, "/always-center", FALSE))
gtk_window_set_position (GTK_WINDOW (window), GTK_WIN_POS_CENTER);
vbox = gtk_vbox_new (FALSE, 6);
@@ -233,7 +234,7 @@ xfce_appfinder_window_init (XfceAppfinderWindow *window)
window->paned = pane = gtk_hpaned_new ();
gtk_box_pack_start (GTK_BOX (vbox), pane, TRUE, TRUE, 0);
- integer = xfconf_channel_get_int (window->channel, "/LastPanedPosition", DEFAULT_PANED_POSITION);
+ integer = xfconf_channel_get_int (window->channel, "/last/pane-position", DEFAULT_PANED_POSITION);
gtk_paned_set_position (GTK_PANED (pane), integer);
g_object_set (G_OBJECT (pane), "position-set", TRUE, NULL);
@@ -399,9 +400,9 @@ xfce_appfinder_window_unmap (GtkWidget *widget)
(*GTK_WIDGET_CLASS (xfce_appfinder_window_parent_class)->unmap) (widget);
- xfconf_channel_set_int (window->channel, "/LastWindowHeight", height);
- xfconf_channel_set_int (window->channel, "/LastWindowWidth", width);
- xfconf_channel_set_int (window->channel, "/LastPanedPosition", position);
+ xfconf_channel_set_int (window->channel, "/last/window-height", height);
+ xfconf_channel_set_int (window->channel, "/last/window-width", width);
+ xfconf_channel_set_int (window->channel, "/last/pane-position", position);
}
@@ -666,8 +667,8 @@ xfce_appfinder_window_category_changed (GtkTreeSelection *selection,
gtk_tree_model_filter_refilter (GTK_TREE_MODEL_FILTER (model));
/* store last category */
- if (xfconf_channel_get_bool (window->channel, "/RememberCategory", FALSE))
- xfconf_channel_set_string (window->channel, "/LastCategory", name);
+ if (xfconf_channel_get_bool (window->channel, "/remember-category", FALSE))
+ xfconf_channel_set_string (window->channel, "/last/category", name);
}
g_free (name);
@@ -691,8 +692,8 @@ xfce_appfinder_window_category_set_categories (XfceAppfinderWindow *window)
if (categories != NULL)
xfce_appfinder_category_model_set_categories (window->category_model, categories);
- if (xfconf_channel_get_bool (window->channel, "/RememberCategory", FALSE))
- name = xfconf_channel_get_string (window->channel, "/LastCategory", NULL);
+ if (xfconf_channel_get_bool (window->channel, "/remember-category", FALSE))
+ name = xfconf_channel_get_string (window->channel, "/last/category", NULL);
else
name = NULL;
@@ -792,51 +793,17 @@ 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;
+ XfceAppfinderActions *actions;
+ gboolean succeed = 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;
+ actions = xfce_appfinder_actions_get ();
- 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);
- }
- }
+ if (xfce_appfinder_actions_execute (actions, cmd, screen, error) == XFCE_APPFINDER_ACTIONS_SUCCEED)
+ succeed = TRUE;
- g_free (cmdline);
+ g_object_unref (G_OBJECT (actions));
- return result;
+ return succeed;
}
More information about the Xfce4-commits
mailing list