summaryrefslogtreecommitdiff
path: root/plugins/shellexecui
diff options
context:
space:
mode:
Diffstat (limited to 'plugins/shellexecui')
-rw-r--r--plugins/shellexecui/Makefile.am44
-rw-r--r--plugins/shellexecui/callbacks.c11
-rw-r--r--plugins/shellexecui/callbacks.h30
-rw-r--r--plugins/shellexecui/interface.c265
-rw-r--r--plugins/shellexecui/interface.h6
-rw-r--r--plugins/shellexecui/shellexecui.c450
-rw-r--r--plugins/shellexecui/support.c144
-rw-r--r--plugins/shellexecui/support.h69
8 files changed, 1019 insertions, 0 deletions
diff --git a/plugins/shellexecui/Makefile.am b/plugins/shellexecui/Makefile.am
new file mode 100644
index 00000000..a7a3c050
--- /dev/null
+++ b/plugins/shellexecui/Makefile.am
@@ -0,0 +1,44 @@
+if HAVE_SHELLEXECUI
+
+if HAVE_GTK2
+if HAVE_GTK3
+pkglib_LTLIBRARIES = shellexec_gtk2.la shellexec_gtk3.la
+else
+pkglib_LTLIBRARIES = shellexec_gtk2.la
+endif
+else
+if HAVE_GTK3
+pkglib_LTLIBRARIES = shellexec_gtk3.la
+endif
+endif
+
+AM_CFLAGS = $(CFLAGS) -std=c99 -fPIC
+
+if HAVE_GTK2
+shellexec_gtk2_la_SOURCES = shellexecui.c interface.c support.c callbacks.c interface.h support.h callbacks.h
+shellexec_gtk2_la_LDFLAGS = -module
+endif
+if HAVE_GTK3
+shellexec_gtk3_la_SOURCES = shellexecui.c interface.c support.c callbacks.c interface.h support.h callbacks.h
+shellexec_gtk3_la_LDFLAGS = -module
+endif
+
+if STATICLINK
+GTK_ROOT=@top_srcdir@/$(LIB)/gtk-2.12.12/usr
+
+shellexec_gtk2_la_LIBADD = $(LDADD) -L$(GTK_ROOT)/lib $(GTK_ROOT)/lib/libgtk-x11-2.0.la $(GTK_ROOT)/lib/libgdk-x11-2.0.la $(GTK_ROOT)/lib/libpangoft2-1.0.la $(GTK_ROOT)/lib/libpangocairo-1.0.la $(GTK_ROOT)/lib/libgdk_pixbuf-2.0.la -lm $(GTK_ROOT)/lib/libcairo.la $(GTK_ROOT)/lib/libpango-1.0.la $(GTK_ROOT)/lib/libgobject-2.0.la $(GTK_ROOT)/lib/libgmodule-2.0.la $(GTK_ROOT)/lib/libgthread-2.0.la -lrt $(GTK_ROOT)/lib/libglib-2.0.la
+
+shellexec_gtk2_la_CFLAGS = -std=c99 -I $(GTK_ROOT)/include -I $(GTK_ROOT)/lib/gtk-2.0/include -I $(GTK_ROOT)/include/glib-2.0 -I $(GTK_ROOT)/include/gtk-2.0 -I $(GTK_ROOT)/include/cairo -I $(GTK_ROOT)/lib/glib-2.0/include/ -I $(GTK_ROOT)/include/pango-1.0 -I $(GTK_ROOT)/include/atk-1.0 -DULTRA_COMPATIBLE=1
+else
+if HAVE_GTK2
+shellexec_gtk2_la_LIBADD = $(LDADD) $(GTK2_DEPS_LIBS)
+shellexec_gtk2_la_CFLAGS = -std=c99 $(GTK2_DEPS_CFLAGS)
+endif
+if HAVE_GTK3
+shellexec_gtk3_la_LIBADD = $(LDADD) $(GTK3_DEPS_LIBS)
+shellexec_gtk3_la_CFLAGS = -std=c99 $(GTK3_DEPS_CFLAGS)
+endif
+
+endif
+
+endif
diff --git a/plugins/shellexecui/callbacks.c b/plugins/shellexecui/callbacks.c
new file mode 100644
index 00000000..b8fb56d3
--- /dev/null
+++ b/plugins/shellexecui/callbacks.c
@@ -0,0 +1,11 @@
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include <gtk/gtk.h>
+
+#include "callbacks.h"
+#include "interface.h"
+#include "support.h"
+
+
diff --git a/plugins/shellexecui/callbacks.h b/plugins/shellexecui/callbacks.h
new file mode 100644
index 00000000..c4b57687
--- /dev/null
+++ b/plugins/shellexecui/callbacks.h
@@ -0,0 +1,30 @@
+#include <gtk/gtk.h>
+
+
+void
+on_add_button_clicked (GtkButton *button,
+ gpointer user_data);
+
+void
+on_remove_button_clicked (GtkButton *button,
+ gpointer user_data);
+
+void
+on_cancel_button_clicked (GtkButton *button,
+ gpointer user_data);
+
+void
+on_save_button_clicked (GtkButton *button,
+ gpointer user_data);
+
+void
+on_edit_button_clicked (GtkButton *button,
+ gpointer user_data);
+
+void
+on_edit_cancel_button_clicked (GtkButton *button,
+ gpointer user_data);
+
+void
+on_edit_ok_button_clicked (GtkButton *button,
+ gpointer user_data);
diff --git a/plugins/shellexecui/interface.c b/plugins/shellexecui/interface.c
new file mode 100644
index 00000000..fe13ced8
--- /dev/null
+++ b/plugins/shellexecui/interface.c
@@ -0,0 +1,265 @@
+/*
+ * DO NOT EDIT THIS FILE - it is generated by Glade.
+ */
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <unistd.h>
+#include <string.h>
+#include <stdio.h>
+
+#include <gdk/gdkkeysyms.h>
+#include <gtk/gtk.h>
+
+#include "callbacks.h"
+#include "interface.h"
+#include "support.h"
+
+#define GLADE_HOOKUP_OBJECT(component,widget,name) \
+ g_object_set_data_full (G_OBJECT (component), name, \
+ g_object_ref(G_OBJECT(widget)), (GDestroyNotify) g_object_unref)
+
+#define GLADE_HOOKUP_OBJECT_NO_REF(component,widget,name) \
+ g_object_set_data (G_OBJECT (component), name, widget)
+
+GtkWidget*
+create_shellexec_conf_dialog (void)
+{
+ GtkWidget *shellexec_conf_dialog;
+ GtkWidget *dialog_vbox;
+ GtkWidget *hbox1;
+ GtkWidget *add_button;
+ GtkWidget *remove_button;
+ GtkWidget *edit_button;
+ GtkWidget *scrolledwindow;
+ GtkWidget *command_treeview;
+ GtkWidget *dialog_action_area;
+ GtkWidget *save_button;
+
+ shellexec_conf_dialog = gtk_dialog_new ();
+ gtk_container_set_border_width (GTK_CONTAINER (shellexec_conf_dialog), 12);
+ gtk_window_set_title (GTK_WINDOW (shellexec_conf_dialog), _("Custom Shell Commands"));
+ gtk_window_set_type_hint (GTK_WINDOW (shellexec_conf_dialog), GDK_WINDOW_TYPE_HINT_DIALOG);
+ gtk_dialog_set_has_separator (GTK_DIALOG (shellexec_conf_dialog), FALSE);
+
+ dialog_vbox = gtk_dialog_get_content_area (GTK_DIALOG (shellexec_conf_dialog));
+ gtk_widget_show (dialog_vbox);
+ gtk_box_set_spacing(GTK_BOX(dialog_vbox), 8);
+
+ hbox1 = gtk_hbox_new (FALSE, 8);
+ gtk_widget_show (hbox1);
+ gtk_box_pack_start (GTK_BOX (dialog_vbox), hbox1, FALSE, TRUE, 0);
+
+ add_button = gtk_button_new_with_mnemonic (_("Add"));
+ gtk_widget_show (add_button);
+ gtk_box_pack_start (GTK_BOX (hbox1), add_button, TRUE, TRUE, 0);
+
+ remove_button = gtk_button_new_with_mnemonic (_("Remove"));
+ gtk_widget_show (remove_button);
+ gtk_box_pack_start (GTK_BOX (hbox1), remove_button, TRUE, TRUE, 0);
+
+ edit_button = gtk_button_new_with_mnemonic (_("Edit"));
+ gtk_widget_show (edit_button);
+ gtk_box_pack_start (GTK_BOX (hbox1), edit_button, TRUE, TRUE, 0);
+
+ scrolledwindow = gtk_scrolled_window_new (NULL, NULL);
+ gtk_widget_show (scrolledwindow);
+ gtk_box_pack_end (GTK_BOX (dialog_vbox), scrolledwindow, TRUE, TRUE, 0);
+ gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scrolledwindow), GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
+ gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW (scrolledwindow), GTK_SHADOW_IN);
+
+ command_treeview = gtk_tree_view_new ();
+ gtk_widget_show (command_treeview);
+ gtk_container_add (GTK_CONTAINER (scrolledwindow), command_treeview);
+ gtk_widget_set_size_request (command_treeview, 300, 200);
+
+ dialog_action_area = gtk_dialog_get_action_area (GTK_DIALOG (shellexec_conf_dialog));
+ gtk_widget_show (dialog_action_area);
+ gtk_button_box_set_layout (GTK_BUTTON_BOX (dialog_action_area), GTK_BUTTONBOX_END);
+
+ save_button = gtk_button_new_with_mnemonic (_("Close"));
+ gtk_widget_show (save_button);
+ gtk_dialog_add_action_widget (GTK_DIALOG (shellexec_conf_dialog), save_button, 0);
+ gtk_widget_set_can_default(save_button, TRUE);
+
+ g_signal_connect ((gpointer) add_button, "clicked",
+ G_CALLBACK (on_add_button_clicked),
+ NULL);
+ g_signal_connect ((gpointer) remove_button, "clicked",
+ G_CALLBACK (on_remove_button_clicked),
+ NULL);
+ g_signal_connect ((gpointer) edit_button, "clicked",
+ G_CALLBACK (on_edit_button_clicked),
+ NULL);
+ g_signal_connect ((gpointer) save_button, "clicked",
+ G_CALLBACK (on_save_button_clicked),
+ NULL);
+
+ /* Store pointers to all widgets, for use by lookup_widget(). */
+ GLADE_HOOKUP_OBJECT_NO_REF (shellexec_conf_dialog, shellexec_conf_dialog, "shellexec_conf_dialog");
+ GLADE_HOOKUP_OBJECT_NO_REF (shellexec_conf_dialog, dialog_vbox, "dialog_vbox");
+ GLADE_HOOKUP_OBJECT (shellexec_conf_dialog, hbox1, "hbox1");
+ GLADE_HOOKUP_OBJECT (shellexec_conf_dialog, add_button, "add_button");
+ GLADE_HOOKUP_OBJECT (shellexec_conf_dialog, remove_button, "remove_button");
+ GLADE_HOOKUP_OBJECT (shellexec_conf_dialog, edit_button, "edit_button");
+ GLADE_HOOKUP_OBJECT (shellexec_conf_dialog, scrolledwindow, "scrolledwindow");
+ GLADE_HOOKUP_OBJECT (shellexec_conf_dialog, command_treeview, "command_treeview");
+ GLADE_HOOKUP_OBJECT_NO_REF (shellexec_conf_dialog, dialog_action_area, "dialog_action_area");
+ GLADE_HOOKUP_OBJECT (shellexec_conf_dialog, save_button, "save_button");
+
+ return shellexec_conf_dialog;
+}
+
+GtkWidget*
+create_shellexec_conf_edit_dialog (void)
+{
+ GtkWidget *shellexec_conf_edit_dialog;
+ GtkWidget *dialog_vbox1;
+ GtkWidget *table1;
+ GtkWidget *title_label;
+ GtkWidget *cmd_label;
+ GtkWidget *name_entry;
+ GtkWidget *cmd_entry;
+ GtkWidget *name_label;
+ GtkWidget *title_entry;
+ GtkWidget *single_check;
+ GtkWidget *multiple_check;
+ GtkWidget *local_check;
+ GtkWidget *remote_check;
+ GtkWidget *playlist_check;
+ GtkWidget *disabled_check;
+ GtkWidget *dialog_action_area1;
+ GtkWidget *edit_cancel_button;
+ GtkWidget *edit_ok_button;
+
+ shellexec_conf_edit_dialog = gtk_dialog_new ();
+ gtk_container_set_border_width (GTK_CONTAINER (shellexec_conf_edit_dialog), 12);
+ gtk_window_set_title (GTK_WINDOW (shellexec_conf_edit_dialog), _("Edit Command"));
+ gtk_window_set_modal (GTK_WINDOW (shellexec_conf_edit_dialog), TRUE);
+ gtk_window_set_type_hint (GTK_WINDOW (shellexec_conf_edit_dialog), GDK_WINDOW_TYPE_HINT_DIALOG);
+ gtk_dialog_set_has_separator (GTK_DIALOG (shellexec_conf_edit_dialog), FALSE);
+
+ dialog_vbox1 = gtk_dialog_get_content_area (GTK_DIALOG (shellexec_conf_edit_dialog));
+ gtk_widget_show (dialog_vbox1);
+ gtk_box_set_spacing(GTK_BOX(dialog_vbox1), 8);
+
+ table1 = gtk_table_new (3, 2, FALSE);
+ gtk_widget_show (table1);
+ gtk_box_pack_start (GTK_BOX (dialog_vbox1), table1, FALSE, TRUE, 0);
+ gtk_table_set_row_spacings (GTK_TABLE (table1), 8);
+ gtk_table_set_col_spacings (GTK_TABLE (table1), 8);
+
+ title_label = gtk_label_new (_("Title:"));
+ gtk_widget_show (title_label);
+ gtk_table_attach (GTK_TABLE (table1), title_label, 0, 1, 1, 2,
+ (GtkAttachOptions) (GTK_FILL),
+ (GtkAttachOptions) (0), 0, 0);
+ gtk_misc_set_alignment (GTK_MISC (title_label), 0, 0.5);
+
+ cmd_label = gtk_label_new (_("Shell Command:"));
+ gtk_widget_show (cmd_label);
+ gtk_table_attach (GTK_TABLE (table1), cmd_label, 0, 1, 2, 3,
+ (GtkAttachOptions) (GTK_FILL),
+ (GtkAttachOptions) (0), 0, 0);
+ gtk_misc_set_alignment (GTK_MISC (cmd_label), 0, 0.5);
+
+ name_entry = gtk_entry_new ();
+ gtk_widget_show (name_entry);
+ gtk_table_attach (GTK_TABLE (table1), name_entry, 1, 2, 0, 1,
+ (GtkAttachOptions) (GTK_EXPAND | GTK_FILL),
+ (GtkAttachOptions) (0), 0, 0);
+ gtk_entry_set_invisible_char (GTK_ENTRY (name_entry), 8226);
+
+ cmd_entry = gtk_entry_new ();
+ gtk_widget_show (cmd_entry);
+ gtk_table_attach (GTK_TABLE (table1), cmd_entry, 1, 2, 2, 3,
+ (GtkAttachOptions) (GTK_EXPAND | GTK_FILL),
+ (GtkAttachOptions) (0), 0, 0);
+ gtk_entry_set_invisible_char (GTK_ENTRY (cmd_entry), 8226);
+
+ name_label = gtk_label_new (_("Name:"));
+ gtk_widget_show (name_label);
+ gtk_table_attach (GTK_TABLE (table1), name_label, 0, 1, 0, 1,
+ (GtkAttachOptions) (GTK_FILL),
+ (GtkAttachOptions) (0), 0, 0);
+ gtk_misc_set_alignment (GTK_MISC (name_label), 0, 0.5);
+
+ title_entry = gtk_entry_new ();
+ gtk_widget_show (title_entry);
+ gtk_table_attach (GTK_TABLE (table1), title_entry, 1, 2, 1, 2,
+ (GtkAttachOptions) (GTK_EXPAND | GTK_FILL),
+ (GtkAttachOptions) (0), 0, 0);
+ gtk_entry_set_invisible_char (GTK_ENTRY (title_entry), 8226);
+
+ single_check = gtk_check_button_new_with_mnemonic (_("Single Tracks"));
+ gtk_widget_show (single_check);
+ gtk_box_pack_start (GTK_BOX (dialog_vbox1), single_check, FALSE, FALSE, 0);
+
+ multiple_check = gtk_check_button_new_with_mnemonic (_("Multiple Tracks"));
+ gtk_widget_show (multiple_check);
+ gtk_box_pack_start (GTK_BOX (dialog_vbox1), multiple_check, FALSE, FALSE, 0);
+
+ local_check = gtk_check_button_new_with_mnemonic (_("Local"));
+ gtk_widget_show (local_check);
+ gtk_box_pack_start (GTK_BOX (dialog_vbox1), local_check, FALSE, FALSE, 0);
+
+ remote_check = gtk_check_button_new_with_mnemonic (_("Remote"));
+ gtk_widget_show (remote_check);
+ gtk_box_pack_start (GTK_BOX (dialog_vbox1), remote_check, FALSE, FALSE, 0);
+
+ playlist_check = gtk_check_button_new_with_mnemonic (_("Playlist"));
+ gtk_widget_show (playlist_check);
+ gtk_box_pack_start (GTK_BOX (dialog_vbox1), playlist_check, FALSE, FALSE, 0);
+
+ disabled_check = gtk_check_button_new_with_mnemonic (_("Disabled"));
+ gtk_widget_show (disabled_check);
+ gtk_box_pack_start (GTK_BOX (dialog_vbox1), disabled_check, FALSE, FALSE, 0);
+
+ dialog_action_area1 = gtk_dialog_get_action_area (GTK_DIALOG (shellexec_conf_edit_dialog));
+ gtk_widget_show (dialog_action_area1);
+ gtk_button_box_set_layout (GTK_BUTTON_BOX (dialog_action_area1), GTK_BUTTONBOX_END);
+
+ edit_cancel_button = gtk_button_new_from_stock ("gtk-cancel");
+ gtk_widget_show (edit_cancel_button);
+ gtk_dialog_add_action_widget (GTK_DIALOG (shellexec_conf_edit_dialog), edit_cancel_button, GTK_RESPONSE_CANCEL);
+ gtk_widget_set_can_default(edit_cancel_button, TRUE);
+
+ edit_ok_button = gtk_button_new_from_stock ("gtk-ok");
+ gtk_widget_show (edit_ok_button);
+ gtk_dialog_add_action_widget (GTK_DIALOG (shellexec_conf_edit_dialog), edit_ok_button, GTK_RESPONSE_OK);
+ gtk_widget_set_can_default(edit_ok_button, TRUE);
+
+ g_signal_connect ((gpointer) edit_cancel_button, "clicked",
+ G_CALLBACK (on_edit_cancel_button_clicked),
+ NULL);
+ g_signal_connect ((gpointer) edit_ok_button, "clicked",
+ G_CALLBACK (on_edit_ok_button_clicked),
+ NULL);
+
+ /* Store pointers to all widgets, for use by lookup_widget(). */
+ GLADE_HOOKUP_OBJECT_NO_REF (shellexec_conf_edit_dialog, shellexec_conf_edit_dialog, "shellexec_conf_edit_dialog");
+ GLADE_HOOKUP_OBJECT_NO_REF (shellexec_conf_edit_dialog, dialog_vbox1, "dialog_vbox1");
+ GLADE_HOOKUP_OBJECT (shellexec_conf_edit_dialog, table1, "table1");
+ GLADE_HOOKUP_OBJECT (shellexec_conf_edit_dialog, title_label, "title_label");
+ GLADE_HOOKUP_OBJECT (shellexec_conf_edit_dialog, cmd_label, "cmd_label");
+ GLADE_HOOKUP_OBJECT (shellexec_conf_edit_dialog, name_entry, "name_entry");
+ GLADE_HOOKUP_OBJECT (shellexec_conf_edit_dialog, cmd_entry, "cmd_entry");
+ GLADE_HOOKUP_OBJECT (shellexec_conf_edit_dialog, name_label, "name_label");
+ GLADE_HOOKUP_OBJECT (shellexec_conf_edit_dialog, title_entry, "title_entry");
+ GLADE_HOOKUP_OBJECT (shellexec_conf_edit_dialog, single_check, "single_check");
+ GLADE_HOOKUP_OBJECT (shellexec_conf_edit_dialog, multiple_check, "multiple_check");
+ GLADE_HOOKUP_OBJECT (shellexec_conf_edit_dialog, local_check, "local_check");
+ GLADE_HOOKUP_OBJECT (shellexec_conf_edit_dialog, remote_check, "remote_check");
+ GLADE_HOOKUP_OBJECT (shellexec_conf_edit_dialog, playlist_check, "playlist_check");
+ GLADE_HOOKUP_OBJECT (shellexec_conf_edit_dialog, disabled_check, "disabled_check");
+ GLADE_HOOKUP_OBJECT_NO_REF (shellexec_conf_edit_dialog, dialog_action_area1, "dialog_action_area1");
+ GLADE_HOOKUP_OBJECT (shellexec_conf_edit_dialog, edit_cancel_button, "edit_cancel_button");
+ GLADE_HOOKUP_OBJECT (shellexec_conf_edit_dialog, edit_ok_button, "edit_ok_button");
+
+ return shellexec_conf_edit_dialog;
+}
+
diff --git a/plugins/shellexecui/interface.h b/plugins/shellexecui/interface.h
new file mode 100644
index 00000000..8bfea88d
--- /dev/null
+++ b/plugins/shellexecui/interface.h
@@ -0,0 +1,6 @@
+/*
+ * DO NOT EDIT THIS FILE - it is generated by Glade.
+ */
+
+GtkWidget* create_shellexec_conf_dialog (void);
+GtkWidget* create_shellexec_conf_edit_dialog (void);
diff --git a/plugins/shellexecui/shellexecui.c b/plugins/shellexecui/shellexecui.c
new file mode 100644
index 00000000..8fd41d41
--- /dev/null
+++ b/plugins/shellexecui/shellexecui.c
@@ -0,0 +1,450 @@
+/*
+ Copyright (C) 2010-2012 Azeem Arshad <kr00r4n@gmail.com>
+
+ 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.
+*/
+#include <stdlib.h>
+#include <string.h>
+#include <deadbeef/deadbeef.h>
+#include <gtk/gtk.h>
+#include <deadbeef/gtkui_api.h>
+#include <glib/gprintf.h>
+#include "interface.h"
+#include "callbacks.h"
+#include "support.h"
+#include "../shellexec/shellexec.h"
+
+#define trace(...) { fprintf(stderr, __VA_ARGS__); }
+
+DB_functions_t *deadbeef;
+static DB_misc_t plugin;
+static ddb_gtkui_t *gtkui_plugin;
+static Shx_plugin_t *shellexec_plugin;
+
+static Shx_action_t *actions; // list of actions being edited
+static GtkWidget *conf_dlg;
+static GtkWidget *edit_dlg;
+static Shx_action_t *current_action; // selection action when edit window is active
+
+static int dirty = 0;
+
+enum {
+ COL_TITLE = 0,
+ COL_META,
+ COL_COUNT,
+};
+
+static int
+name_exists(const char *name, Shx_action_t *skip) {
+ Shx_action_t *action = actions;
+ while(action) {
+ if(action != skip && strcmp(action->parent.name, name) == 0) {
+ return 1;
+ }
+ action = (Shx_action_t*)action->parent.next;
+ }
+ return 0;
+}
+
+static int
+is_empty(const char *name) {
+ char *p = (char *)name;
+ while(*p) {
+ if(*p != ' ' || *p != '\t') {
+ return 0;
+ }
+ p++;
+ }
+ return 1;
+}
+
+void
+on_save_button_clicked (GtkButton *button,
+ gpointer user_data) {
+ if(dirty) {
+ shellexec_plugin->shx_save_actions(actions);
+ }
+ gtk_widget_destroy(conf_dlg);
+}
+
+GtkWidget *create_edit_dlg() {
+ GtkWidget *dlg = create_shellexec_conf_edit_dialog();
+ gtk_window_set_transient_for(GTK_WINDOW(dlg),
+ GTK_WINDOW(conf_dlg));
+ return dlg;
+}
+
+void
+on_add_button_clicked (GtkButton *button,
+ gpointer user_data) {
+ current_action = NULL;
+ edit_dlg = create_edit_dlg();
+ gtk_window_set_title(GTK_WINDOW(edit_dlg), _("Add Command"));
+
+ // generate unique command name
+ char name[15] = "new_cmd";
+ int suffix = 0;
+ while(name_exists(name, NULL)) { // create a unique name
+ snprintf(name, 15, "new_cmd%d", suffix);
+ suffix++;
+ }
+ // Set default values in text fields
+ gtk_entry_set_text(
+ GTK_ENTRY(lookup_widget(edit_dlg, "name_entry")),
+ name);
+ gtk_entry_set_text(
+ GTK_ENTRY(lookup_widget(edit_dlg, "title_entry")),
+ "New Command");
+
+ // Set default values in check boxes
+ gtk_toggle_button_set_active(
+ GTK_TOGGLE_BUTTON(lookup_widget(edit_dlg, "single_check")),
+ TRUE);
+ gtk_toggle_button_set_active(
+ GTK_TOGGLE_BUTTON(lookup_widget(edit_dlg, "local_check")),
+ TRUE);
+
+ gtk_widget_show(edit_dlg);
+}
+
+void
+on_remove_button_clicked (GtkButton *button,
+ gpointer user_data) {
+ GtkTreeView *treeview = GTK_TREE_VIEW(lookup_widget(conf_dlg, "command_treeview"));
+ GtkTreeModel *treemodel = gtk_tree_view_get_model(treeview);
+ GtkTreeIter iter;
+ GtkTreeSelection *selection;
+ selection = gtk_tree_view_get_selection(treeview);
+ if(gtk_tree_selection_get_selected(selection, &treemodel, &iter)) {
+ // ask confirmation
+ GtkWidget *confirm_dlg = gtk_message_dialog_new (GTK_WINDOW(conf_dlg), GTK_DIALOG_MODAL,
+ GTK_MESSAGE_WARNING, GTK_BUTTONS_YES_NO,
+ _("Delete"));
+ gtk_message_dialog_format_secondary_text (GTK_MESSAGE_DIALOG (confirm_dlg),
+ _("This action will delete the selected shell command. Are you sure?"));
+ gtk_window_set_transient_for(GTK_WINDOW (confirm_dlg), GTK_WINDOW (conf_dlg));
+ gtk_window_set_title (GTK_WINDOW (confirm_dlg), _("Confirm Remove"));
+ int response = gtk_dialog_run (GTK_DIALOG (confirm_dlg));
+ gtk_widget_destroy(confirm_dlg);
+ if(response == GTK_RESPONSE_NO) {
+ return;
+ }
+
+ Shx_action_t *action;
+ gtk_tree_model_get(treemodel, &iter, COL_META, &action, -1);
+
+ //remove action from list
+ if(actions == action) {
+ actions = (Shx_action_t*)action->parent.next;
+ }
+ else {
+ Shx_action_t *prev = actions;
+ while(((Shx_action_t*)prev->parent.next) != action) {
+ prev = (Shx_action_t*)prev->parent.next;
+ }
+ prev->parent.next = action->parent.next;
+ }
+ free((void *)action->shcommand);
+ free((void *)action->parent.name);
+ free((void *)action->parent.title);
+ free(action);
+
+ GtkTreeIter next_iter = iter;
+ if(gtk_tree_model_iter_next(treemodel, &next_iter)) {
+ gtk_tree_selection_select_iter(selection, &next_iter);
+ }
+ else {
+ int count = gtk_tree_model_iter_n_children(treemodel, NULL);
+ if(count >= 2) {
+ GtkTreePath *last = gtk_tree_path_new_from_indices(count-2, -1);
+ gtk_tree_selection_select_path(selection, last);
+ }
+ }
+ gtk_list_store_remove(GTK_LIST_STORE(treemodel), &iter);
+
+ dirty = 1;
+ }
+}
+
+void
+on_edit_button_clicked(GtkButton *button, gpointer user_data) {
+ GtkTreeView *treeview = GTK_TREE_VIEW(lookup_widget(conf_dlg, "command_treeview"));
+ GtkTreeModel *treemodel = gtk_tree_view_get_model(treeview);
+ GtkTreeSelection *selection = gtk_tree_view_get_selection(treeview);
+ GtkTreeIter iter;
+ if(gtk_tree_selection_get_selected(selection, &treemodel, &iter)) {
+ gtk_tree_model_get(treemodel, &iter, COL_META, &current_action, -1);
+ edit_dlg = create_edit_dlg();
+ // Set text fields
+ gtk_entry_set_text(
+ GTK_ENTRY(lookup_widget(edit_dlg, "name_entry")),
+ current_action->parent.name);
+ gtk_entry_set_text(
+ GTK_ENTRY(lookup_widget(edit_dlg, "title_entry")),
+ current_action->parent.title);
+ gtk_entry_set_text(
+ GTK_ENTRY(lookup_widget(edit_dlg, "cmd_entry")),
+ current_action->shcommand);
+
+ // Set check boxes
+ gtk_toggle_button_set_active(
+ GTK_TOGGLE_BUTTON(lookup_widget(edit_dlg, "single_check")),
+ current_action->parent.flags & DB_ACTION_SINGLE_TRACK);
+ gtk_toggle_button_set_active(
+ GTK_TOGGLE_BUTTON(lookup_widget(edit_dlg, "multiple_check")),
+ current_action->parent.flags & DB_ACTION_ALLOW_MULTIPLE_TRACKS);
+ gtk_toggle_button_set_active(
+ GTK_TOGGLE_BUTTON(lookup_widget(edit_dlg, "disabled_check")),
+ current_action->parent.flags & DB_ACTION_DISABLED);
+ gtk_toggle_button_set_active(
+ GTK_TOGGLE_BUTTON(lookup_widget(edit_dlg, "playlist_check")),
+ current_action->parent.flags & DB_ACTION_PLAYLIST);
+ gtk_toggle_button_set_active(
+ GTK_TOGGLE_BUTTON(lookup_widget(edit_dlg, "local_check")),
+ current_action->shx_flags & SHX_ACTION_LOCAL_ONLY);
+ gtk_toggle_button_set_active(
+ GTK_TOGGLE_BUTTON(lookup_widget(edit_dlg, "remote_check")),
+ current_action->shx_flags & SHX_ACTION_REMOTE_ONLY);
+
+ //disable_button(edit_dlg, "edit_ok_button"); // OK button is disabled by default
+ gtk_widget_show(edit_dlg);
+ }
+}
+
+void
+on_edit_cancel_button_clicked (GtkButton *button, gpointer user_data) {
+ gtk_widget_destroy(edit_dlg);
+}
+
+static int
+validate_command_edit () {
+ const char *text;
+ char message[256] = "";
+ int valid = 1;
+
+ text = gtk_entry_get_text(GTK_ENTRY(lookup_widget(edit_dlg, "name_entry")));
+ if(is_empty(text) || name_exists(text, current_action)) {
+ strcat(message, _("Name should be non-empty and unique\n"));
+ valid = 0;
+ }
+
+ text = gtk_entry_get_text(GTK_ENTRY(lookup_widget(edit_dlg, "title_entry")));
+ if(is_empty(text)) {
+ strcat(message, _("Title should be non-empty\n"));
+ valid = 0;
+ }
+
+ text = gtk_entry_get_text(GTK_ENTRY(lookup_widget(edit_dlg, "cmd_entry")));
+ if(is_empty(text)) {
+ strcat(message, _("Shell Command should be non-empty\n"));
+ valid = 0;
+ }
+
+ if(!valid) {
+ GtkWidget *invalid_dlg = gtk_message_dialog_new (GTK_WINDOW(conf_dlg), GTK_DIALOG_MODAL,
+ GTK_MESSAGE_WARNING, GTK_BUTTONS_OK,
+ _("Invalid Values"));
+ gtk_message_dialog_format_secondary_text (GTK_MESSAGE_DIALOG (invalid_dlg),
+ message);
+ gtk_window_set_transient_for(GTK_WINDOW (invalid_dlg), GTK_WINDOW (conf_dlg));
+ gtk_window_set_title (GTK_WINDOW (invalid_dlg), _("Invalid Values"));
+ gtk_dialog_run (GTK_DIALOG (invalid_dlg));
+ gtk_widget_destroy(invalid_dlg);
+ }
+ return valid;
+}
+
+void
+on_edit_ok_button_clicked (GtkButton *button, gpointer user_data) {
+ if(!validate_command_edit()) {
+ return;
+ }
+ // Update the main window tree view
+ GtkTreeView *treeview = GTK_TREE_VIEW(lookup_widget(conf_dlg, "command_treeview"));
+ GtkTreeModel *treemodel = gtk_tree_view_get_model(treeview);
+ GtkTreeSelection *selection = gtk_tree_view_get_selection(treeview);
+ GtkTreeIter iter;
+
+ if(current_action == NULL) {
+ current_action = calloc(sizeof(Shx_action_t), 1);
+ if(!actions) {
+ actions = current_action;
+ }
+ else {
+ Shx_action_t *last = actions;
+ while(last->parent.next) {
+ last = (Shx_action_t *)last->parent.next;
+ }
+ last->parent.next = (DB_plugin_action_t*)current_action;
+ }
+ gtk_list_store_append(GTK_LIST_STORE(treemodel), &iter);
+ gtk_list_store_set(GTK_LIST_STORE(treemodel), &iter, COL_META, current_action, -1);
+ gtk_tree_selection_select_iter(selection, &iter);
+ }
+ else {
+ gtk_tree_selection_get_selected(selection, &treemodel, &iter);
+ }
+ // Store all the text fields in the current action
+ GtkEntry *entry;
+ entry = GTK_ENTRY(lookup_widget(edit_dlg, "name_entry"));
+ current_action->parent.name = strdup(gtk_entry_get_text(entry));
+ entry = GTK_ENTRY(lookup_widget(edit_dlg, "title_entry"));
+ current_action->parent.title = strdup(gtk_entry_get_text(entry));
+ entry = GTK_ENTRY(lookup_widget(edit_dlg, "cmd_entry"));
+ current_action->shcommand = strdup(gtk_entry_get_text(entry));
+
+ gboolean active;
+ int flags = current_action->parent.flags;
+ int shx_flags = current_action->shx_flags;
+ // Store all the check button values in the current action
+ active = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(lookup_widget(edit_dlg, "single_check")));
+ flags = (flags & ~DB_ACTION_SINGLE_TRACK) | (active?DB_ACTION_SINGLE_TRACK:0);
+ active = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(lookup_widget(edit_dlg, "multiple_check")));
+ flags = (flags & ~DB_ACTION_ALLOW_MULTIPLE_TRACKS) | (active?DB_ACTION_ALLOW_MULTIPLE_TRACKS:0);
+ active = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(lookup_widget(edit_dlg, "playlist_check")));
+ flags = (flags & ~DB_ACTION_PLAYLIST) | (active?DB_ACTION_PLAYLIST:0);
+ active = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(lookup_widget(edit_dlg, "disabled_check")));
+ flags = (flags & ~DB_ACTION_DISABLED) | (active?DB_ACTION_DISABLED:0);
+ active = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(lookup_widget(edit_dlg, "local_check")));
+ shx_flags = (shx_flags & ~SHX_ACTION_LOCAL_ONLY) | (active?SHX_ACTION_LOCAL_ONLY:0);
+ active = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(lookup_widget(edit_dlg, "remote_check")));
+ shx_flags = (shx_flags & ~SHX_ACTION_REMOTE_ONLY) | (active?SHX_ACTION_REMOTE_ONLY:0);
+
+ current_action->parent.flags = flags;
+ current_action->shx_flags = shx_flags;
+
+ gtk_list_store_set(GTK_LIST_STORE(treemodel), &iter,
+ COL_TITLE, current_action->parent.title, -1);
+
+ gtk_widget_destroy(edit_dlg);
+ edit_dlg = NULL;
+ current_action = NULL;
+
+ dirty = 1;
+ //enable_button(conf_dlg, "save_button");
+}
+
+static void
+init_treeview() {
+ // Create the tree view and cell renderers
+ GtkTreeView *treeview = GTK_TREE_VIEW(lookup_widget(conf_dlg, "command_treeview"));
+ GtkCellRenderer *cell_renderer;
+ cell_renderer = gtk_cell_renderer_text_new();
+ gtk_tree_view_insert_column_with_attributes(treeview, -1, _("Title"), cell_renderer,
+ "text", COL_TITLE, NULL);
+
+ // Create the tree view data model and fill it with values
+ GtkListStore *liststore;
+ liststore = gtk_list_store_new(COL_COUNT,
+ G_TYPE_STRING,
+ //G_TYPE_BOOLEAN,
+ G_TYPE_POINTER);
+ actions = shellexec_plugin->shx_get_actions(NULL, FALSE);
+ Shx_action_t *action = actions;
+ GtkTreeIter iter;
+ while(action) {
+ gtk_list_store_append(liststore, &iter);
+ gtk_list_store_set(liststore, &iter,
+ COL_TITLE, action->parent.title,
+ COL_META, action, -1);
+ action = (Shx_action_t *)action->parent.next;
+ }
+
+ gtk_tree_view_set_model(treeview, GTK_TREE_MODEL(liststore));
+ g_object_unref(liststore);
+}
+
+static int
+shellexecui_action_callback(DB_plugin_action_t *action,
+ void *user_data) {
+ conf_dlg = create_shellexec_conf_dialog();
+ dirty = 0;
+ gtk_window_set_transient_for(GTK_WINDOW(conf_dlg),
+ GTK_WINDOW(gtkui_plugin->get_mainwin()));
+ init_treeview();
+ //disable_button(conf_dlg, "save_button");
+ gtk_widget_show(conf_dlg);
+ return 0;
+}
+
+static DB_plugin_action_t shellexecui_action = {
+ .title = "Edit/Configure custom shell commands",
+ .name = "shellexec_conf",
+ .flags = DB_ACTION_COMMON,
+ .callback = shellexecui_action_callback,
+ .next = NULL,
+};
+
+static DB_plugin_action_t *
+shxui_getactions(DB_playItem_t *it) {
+ return &shellexecui_action;
+}
+
+int shxui_connect() {
+#if GTK_CHECK_VERSION(3,0,0)
+ gtkui_plugin = (ddb_gtkui_t *)deadbeef->plug_get_for_id ("gtkui3");
+#else
+ gtkui_plugin = (ddb_gtkui_t *)deadbeef->plug_get_for_id ("gtkui");
+#endif
+ shellexec_plugin = (Shx_plugin_t *)deadbeef->plug_get_for_id ("shellexec");
+ if(!gtkui_plugin || !shellexec_plugin) {
+ return -1;
+ }
+ if(shellexec_plugin->misc.plugin.version_major == 1 &&
+ shellexec_plugin->misc.plugin.version_minor < 1) {
+ return -1;
+ }
+ return 0;
+}
+
+static DB_misc_t plugin = {
+ .plugin.type = DB_PLUGIN_MISC,
+ .plugin.api_vmajor = 1,
+ .plugin.api_vminor = 0,
+ .plugin.version_major = 1,
+ .plugin.version_minor = 0,
+ .plugin.id = "shellexecui",
+ .plugin.name = "Shellexec GTK UI",
+ .plugin.descr = "A GTK UI for the Shellexec plugin",
+ .plugin.copyright =
+ "Copyright (C) 2010-2012 Azeem Arshad <kr00r4n@gmail.com>\n"
+ "\n"
+ "This program is free software; you can redistribute it and/or\n"
+ "modify it under the terms of the GNU General Public License\n"
+ "as published by the Free Software Foundation; either version 2\n"
+ "of the License, or (at your option) any later version.\n"
+ "\n"
+ "This program is distributed in the hope that it will be useful,\n"
+ "but WITHOUT ANY WARRANTY; without even the implied warranty of\n"
+ "MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n"
+ "GNU General Public License for more details.\n"
+ "\n"
+ "You should have received a copy of the GNU General Public License\n"
+ "along with this program; if not, write to the Free Software\n"
+ "Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.\n",
+ .plugin.website = "http://azeemarshad.in",
+ .plugin.get_actions = shxui_getactions,
+ .plugin.connect = shxui_connect,
+};
+
+DB_plugin_t *
+#if GTK_CHECK_VERSION(3,0,0)
+shellexec_gtk3_load (DB_functions_t *api) {
+#else
+shellexec_gtk2_load (DB_functions_t *api) {
+#endif
+ deadbeef = api;
+ return DB_PLUGIN(&plugin);
+}
diff --git a/plugins/shellexecui/support.c b/plugins/shellexecui/support.c
new file mode 100644
index 00000000..7965ef51
--- /dev/null
+++ b/plugins/shellexecui/support.c
@@ -0,0 +1,144 @@
+/*
+ * DO NOT EDIT THIS FILE - it is generated by Glade.
+ */
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <unistd.h>
+#include <string.h>
+#include <stdio.h>
+
+#include <gtk/gtk.h>
+
+#include "support.h"
+
+GtkWidget*
+lookup_widget (GtkWidget *widget,
+ const gchar *widget_name)
+{
+ GtkWidget *parent, *found_widget;
+
+ for (;;)
+ {
+ if (GTK_IS_MENU (widget))
+ parent = gtk_menu_get_attach_widget (GTK_MENU (widget));
+ else
+ parent = gtk_widget_get_parent (widget);
+ if (!parent)
+ parent = (GtkWidget*) g_object_get_data (G_OBJECT (widget), "GladeParentKey");
+ if (parent == NULL)
+ break;
+ widget = parent;
+ }
+
+ found_widget = (GtkWidget*) g_object_get_data (G_OBJECT (widget),
+ widget_name);
+ if (!found_widget)
+ g_warning ("Widget not found: %s", widget_name);
+ return found_widget;
+}
+
+static GList *pixmaps_directories = NULL;
+
+/* Use this function to set the directory containing installed pixmaps. */
+void
+add_pixmap_directory (const gchar *directory)
+{
+ pixmaps_directories = g_list_prepend (pixmaps_directories,
+ g_strdup (directory));
+}
+
+/* This is an internally used function to find pixmap files. */
+static gchar*
+find_pixmap_file (const gchar *filename)
+{
+ GList *elem;
+
+ /* We step through each of the pixmaps directory to find it. */
+ elem = pixmaps_directories;
+ while (elem)
+ {
+ gchar *pathname = g_strdup_printf ("%s%s%s", (gchar*)elem->data,
+ G_DIR_SEPARATOR_S, filename);
+ if (g_file_test (pathname, G_FILE_TEST_EXISTS))
+ return pathname;
+ g_free (pathname);
+ elem = elem->next;
+ }
+ return NULL;
+}
+
+/* This is an internally used function to create pixmaps. */
+GtkWidget*
+create_pixmap (GtkWidget *widget,
+ const gchar *filename)
+{
+ gchar *pathname = NULL;
+ GtkWidget *pixmap;
+
+ if (!filename || !filename[0])
+ return gtk_image_new ();
+
+ pathname = find_pixmap_file (filename);
+
+ if (!pathname)
+ {
+ g_warning (_("Couldn't find pixmap file: %s"), filename);
+ return gtk_image_new ();
+ }
+
+ pixmap = gtk_image_new_from_file (pathname);
+ g_free (pathname);
+ return pixmap;
+}
+
+/* This is an internally used function to create pixmaps. */
+GdkPixbuf*
+create_pixbuf (const gchar *filename)
+{
+ gchar *pathname = NULL;
+ GdkPixbuf *pixbuf;
+ GError *error = NULL;
+
+ if (!filename || !filename[0])
+ return NULL;
+
+ pathname = find_pixmap_file (filename);
+
+ if (!pathname)
+ {
+ g_warning (_("Couldn't find pixmap file: %s"), filename);
+ return NULL;
+ }
+
+ pixbuf = gdk_pixbuf_new_from_file (pathname, &error);
+ if (!pixbuf)
+ {
+ fprintf (stderr, "Failed to load pixbuf file: %s: %s\n",
+ pathname, error->message);
+ g_error_free (error);
+ }
+ g_free (pathname);
+ return pixbuf;
+}
+
+/* This is used to set ATK action descriptions. */
+void
+glade_set_atk_action_description (AtkAction *action,
+ const gchar *action_name,
+ const gchar *description)
+{
+ gint n_actions, i;
+
+ n_actions = atk_action_get_n_actions (action);
+ for (i = 0; i < n_actions; i++)
+ {
+ if (!strcmp (atk_action_get_name (action, i), action_name))
+ atk_action_set_description (action, i, description);
+ }
+}
+
diff --git a/plugins/shellexecui/support.h b/plugins/shellexecui/support.h
new file mode 100644
index 00000000..a32649e5
--- /dev/null
+++ b/plugins/shellexecui/support.h
@@ -0,0 +1,69 @@
+/*
+ * DO NOT EDIT THIS FILE - it is generated by Glade.
+ */
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include <gtk/gtk.h>
+
+/*
+ * Standard gettext macros.
+ */
+#ifdef ENABLE_NLS
+# include <libintl.h>
+# undef _
+# define _(String) dgettext (PACKAGE, String)
+# define Q_(String) g_strip_context ((String), gettext (String))
+# ifdef gettext_noop
+# define N_(String) gettext_noop (String)
+# else
+# define N_(String) (String)
+# endif
+#else
+# define textdomain(String) (String)
+# define gettext(String) (String)
+# define dgettext(Domain,Message) (Message)
+# define dcgettext(Domain,Message,Type) (Message)
+# define bindtextdomain(Domain,Directory) (Domain)
+# define _(String) (String)
+# define Q_(String) g_strip_context ((String), (String))
+# define N_(String) (String)
+#endif
+
+
+/*
+ * Public Functions.
+ */
+
+/*
+ * This function returns a widget in a component created by Glade.
+ * Call it with the toplevel widget in the component (i.e. a window/dialog),
+ * or alternatively any widget in the component, and the name of the widget
+ * you want returned.
+ */
+GtkWidget* lookup_widget (GtkWidget *widget,
+ const gchar *widget_name);
+
+
+/* Use this function to set the directory containing installed pixmaps. */
+void add_pixmap_directory (const gchar *directory);
+
+
+/*
+ * Private Functions.
+ */
+
+/* This is used to create the pixmaps used in the interface. */
+GtkWidget* create_pixmap (GtkWidget *widget,
+ const gchar *filename);
+
+/* This is used to create the pixbufs used in the interface. */
+GdkPixbuf* create_pixbuf (const gchar *filename);
+
+/* This is used to set ATK action descriptions. */
+void glade_set_atk_action_description (AtkAction *action,
+ const gchar *action_name,
+ const gchar *description);
+