diff options
Diffstat (limited to 'plugins/shellexecui')
-rw-r--r-- | plugins/shellexecui/Makefile.am | 46 | ||||
-rw-r--r-- | plugins/shellexecui/callbacks.c | 11 | ||||
-rw-r--r-- | plugins/shellexecui/callbacks.h | 30 | ||||
-rw-r--r-- | plugins/shellexecui/interface.c | 277 | ||||
-rw-r--r-- | plugins/shellexecui/interface.h | 6 | ||||
-rw-r--r-- | plugins/shellexecui/shellexec.glade | 521 | ||||
-rw-r--r-- | plugins/shellexecui/shellexec.gladep | 12 | ||||
-rw-r--r-- | plugins/shellexecui/shellexecui.c | 443 | ||||
-rw-r--r-- | plugins/shellexecui/support.c | 221 | ||||
-rw-r--r-- | plugins/shellexecui/support.h | 146 |
10 files changed, 1713 insertions, 0 deletions
diff --git a/plugins/shellexecui/Makefile.am b/plugins/shellexecui/Makefile.am new file mode 100644 index 00000000..688d271f --- /dev/null +++ b/plugins/shellexecui/Makefile.am @@ -0,0 +1,46 @@ +if HAVE_SHELLEXECUI + +EXTRA_DIST = shellexec.glade + +if HAVE_GTK2 +if HAVE_GTK3 +pkglib_LTLIBRARIES = shellexecui_gtk2.la shellexecui_gtk3.la +else +pkglib_LTLIBRARIES = shellexecui_gtk2.la +endif +else +if HAVE_GTK3 +pkglib_LTLIBRARIES = shellexecui_gtk3.la +endif +endif + +AM_CFLAGS = $(CFLAGS) -std=c99 -fPIC + +if HAVE_GTK2 +shellexecui_gtk2_la_SOURCES = shellexecui.c interface.c support.c callbacks.c interface.h support.h callbacks.h +shellexecui_gtk2_la_LDFLAGS = -module +endif +if HAVE_GTK3 +shellexecui_gtk3_la_SOURCES = shellexecui.c interface.c support.c callbacks.c interface.h support.h callbacks.h +shellexecui_gtk3_la_LDFLAGS = -module +endif + +if STATICLINK +GTK_ROOT=@top_srcdir@/$(LIB)/gtk-2.12.12/usr + +shellexecui_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 + +shellexecui_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 +shellexecui_gtk2_la_LIBADD = $(LDADD) $(GTK2_DEPS_LIBS) +shellexecui_gtk2_la_CFLAGS = -std=c99 $(GTK2_DEPS_CFLAGS) +endif +if HAVE_GTK3 +shellexecui_gtk3_la_LIBADD = $(LDADD) $(GTK3_DEPS_LIBS) +shellexecui_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..ee41ed1d --- /dev/null +++ b/plugins/shellexecui/interface.c @@ -0,0 +1,277 @@ +/* + * 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 *vbox1; + 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); + + vbox1 = gtk_vbox_new (FALSE, 8); + gtk_widget_show (vbox1); + gtk_box_pack_start (GTK_BOX (dialog_vbox), vbox1, TRUE, TRUE, 0); + + hbox1 = gtk_hbox_new (FALSE, 8); + gtk_widget_show (hbox1); + gtk_box_pack_start (GTK_BOX (vbox1), 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_start (GTK_BOX (vbox1), 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); + + 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, vbox1, "vbox1"); + 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 *cmd_entry; + GtkWidget *name_label; + GtkWidget *title_entry; + GtkWidget *name_entry; + GtkWidget *single_check; + GtkWidget *multiple_check; + GtkWidget *local_check; + GtkWidget *remote_check; + GtkWidget *playlist_check; + GtkWidget *common_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); + + 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 (_("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); + + 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_widget_set_tooltip_text (cmd_entry, _("Arbitrary shell command. Will be executed in the shell context which the main application was started from. Title formatting can be used. Example: xdg-open %D")); + gtk_entry_set_invisible_char (GTK_ENTRY (cmd_entry), 8226); + + name_label = gtk_label_new (_("ID:")); + 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_widget_set_tooltip_text (title_entry, _("Free-form name, for example \"My Shell Command\"")); + gtk_entry_set_invisible_char (GTK_ENTRY (title_entry), 8226); + + 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_widget_set_tooltip_text (name_entry, _("Command ID, normally it should be something short, for example \"youtube_open\". It must be unique.")); + gtk_entry_set_invisible_char (GTK_ENTRY (name_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); + gtk_widget_set_tooltip_text (single_check, _("Works on single track.")); + + 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); + gtk_widget_set_tooltip_text (multiple_check, _("Works on multiple tracks.")); + + 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); + gtk_widget_set_tooltip_text (local_check, _("Works on local files.")); + + 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); + gtk_widget_set_tooltip_text (remote_check, _("Works on remote files (e.g. http:// streams)")); + + 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); + gtk_widget_set_tooltip_text (playlist_check, _("Item should appear on the playlist tab context menu")); + + common_check = gtk_check_button_new_with_mnemonic (_("Common")); + gtk_widget_show (common_check); + gtk_box_pack_start (GTK_BOX (dialog_vbox1), common_check, FALSE, FALSE, 0); + gtk_widget_set_tooltip_text (common_check, _("Item should appear in the main menu")); + + 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, 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, name_entry, "name_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, common_check, "common_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/shellexec.glade b/plugins/shellexecui/shellexec.glade new file mode 100644 index 00000000..d2f21b35 --- /dev/null +++ b/plugins/shellexecui/shellexec.glade @@ -0,0 +1,521 @@ +<?xml version="1.0" standalone="no"?> <!--*- mode: xml -*--> +<!DOCTYPE glade-interface SYSTEM "http://glade.gnome.org/glade-2.0.dtd"> + +<glade-interface> + +<widget class="GtkDialog" id="shellexec_conf_dialog"> + <property name="border_width">12</property> + <property name="visible">True</property> + <property name="title" translatable="yes">Custom Shell Commands</property> + <property name="type">GTK_WINDOW_TOPLEVEL</property> + <property name="window_position">GTK_WIN_POS_NONE</property> + <property name="modal">False</property> + <property name="resizable">True</property> + <property name="destroy_with_parent">False</property> + <property name="decorated">True</property> + <property name="skip_taskbar_hint">False</property> + <property name="skip_pager_hint">False</property> + <property name="type_hint">GDK_WINDOW_TYPE_HINT_DIALOG</property> + <property name="gravity">GDK_GRAVITY_NORTH_WEST</property> + <property name="focus_on_map">True</property> + <property name="urgency_hint">False</property> + <property name="has_separator">False</property> + + <child internal-child="vbox"> + <widget class="GtkVBox" id="dialog-vbox"> + <property name="visible">True</property> + <property name="homogeneous">False</property> + <property name="spacing">8</property> + + <child internal-child="action_area"> + <widget class="GtkHButtonBox" id="dialog-action_area"> + <property name="visible">True</property> + <property name="layout_style">GTK_BUTTONBOX_END</property> + + <child> + <widget class="GtkButton" id="save_button"> + <property name="visible">True</property> + <property name="can_default">True</property> + <property name="can_focus">True</property> + <property name="label" translatable="yes">Close</property> + <property name="use_underline">True</property> + <property name="relief">GTK_RELIEF_NORMAL</property> + <property name="focus_on_click">True</property> + <property name="response_id">0</property> + <signal name="clicked" handler="on_save_button_clicked" last_modification_time="Sat, 28 Jan 2012 03:21:29 GMT"/> + </widget> + </child> + </widget> + <packing> + <property name="padding">0</property> + <property name="expand">False</property> + <property name="fill">True</property> + <property name="pack_type">GTK_PACK_END</property> + </packing> + </child> + + <child> + <widget class="GtkVBox" id="vbox1"> + <property name="visible">True</property> + <property name="homogeneous">False</property> + <property name="spacing">8</property> + + <child> + <widget class="GtkHBox" id="hbox1"> + <property name="visible">True</property> + <property name="homogeneous">False</property> + <property name="spacing">8</property> + + <child> + <widget class="GtkButton" id="add_button"> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="label" translatable="yes">Add</property> + <property name="use_underline">True</property> + <property name="relief">GTK_RELIEF_NORMAL</property> + <property name="focus_on_click">True</property> + <signal name="clicked" handler="on_add_button_clicked" last_modification_time="Sat, 28 Jan 2012 11:02:39 GMT"/> + </widget> + <packing> + <property name="padding">0</property> + <property name="expand">True</property> + <property name="fill">True</property> + </packing> + </child> + + <child> + <widget class="GtkButton" id="remove_button"> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="label" translatable="yes">Remove</property> + <property name="use_underline">True</property> + <property name="relief">GTK_RELIEF_NORMAL</property> + <property name="focus_on_click">True</property> + <signal name="clicked" handler="on_remove_button_clicked" last_modification_time="Sat, 28 Jan 2012 11:02:47 GMT"/> + </widget> + <packing> + <property name="padding">0</property> + <property name="expand">True</property> + <property name="fill">True</property> + </packing> + </child> + + <child> + <widget class="GtkButton" id="edit_button"> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="label" translatable="yes">Edit</property> + <property name="use_underline">True</property> + <property name="relief">GTK_RELIEF_NORMAL</property> + <property name="focus_on_click">True</property> + <signal name="clicked" handler="on_edit_button_clicked" last_modification_time="Sat, 31 Mar 2012 22:29:32 GMT"/> + </widget> + <packing> + <property name="padding">0</property> + <property name="expand">True</property> + <property name="fill">True</property> + </packing> + </child> + </widget> + <packing> + <property name="padding">0</property> + <property name="expand">False</property> + <property name="fill">True</property> + </packing> + </child> + + <child> + <widget class="GtkScrolledWindow" id="scrolledwindow"> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="hscrollbar_policy">GTK_POLICY_AUTOMATIC</property> + <property name="vscrollbar_policy">GTK_POLICY_AUTOMATIC</property> + <property name="shadow_type">GTK_SHADOW_IN</property> + <property name="window_placement">GTK_CORNER_TOP_LEFT</property> + + <child> + <widget class="GtkTreeView" id="command_treeview"> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="headers_visible">True</property> + <property name="rules_hint">False</property> + <property name="reorderable">False</property> + <property name="enable_search">True</property> + <property name="fixed_height_mode">False</property> + <property name="hover_selection">False</property> + <property name="hover_expand">False</property> + </widget> + </child> + </widget> + <packing> + <property name="padding">0</property> + <property name="expand">True</property> + <property name="fill">True</property> + </packing> + </child> + </widget> + <packing> + <property name="padding">0</property> + <property name="expand">True</property> + <property name="fill">True</property> + </packing> + </child> + </widget> + </child> +</widget> + +<widget class="GtkDialog" id="shellexec_conf_edit_dialog"> + <property name="border_width">12</property> + <property name="visible">True</property> + <property name="title" translatable="yes">Edit Command</property> + <property name="type">GTK_WINDOW_TOPLEVEL</property> + <property name="window_position">GTK_WIN_POS_NONE</property> + <property name="modal">True</property> + <property name="resizable">True</property> + <property name="destroy_with_parent">False</property> + <property name="decorated">True</property> + <property name="skip_taskbar_hint">False</property> + <property name="skip_pager_hint">False</property> + <property name="type_hint">GDK_WINDOW_TYPE_HINT_DIALOG</property> + <property name="gravity">GDK_GRAVITY_NORTH_WEST</property> + <property name="focus_on_map">True</property> + <property name="urgency_hint">False</property> + <property name="has_separator">False</property> + + <child internal-child="vbox"> + <widget class="GtkVBox" id="dialog-vbox1"> + <property name="visible">True</property> + <property name="homogeneous">False</property> + <property name="spacing">8</property> + + <child internal-child="action_area"> + <widget class="GtkHButtonBox" id="dialog-action_area1"> + <property name="visible">True</property> + <property name="layout_style">GTK_BUTTONBOX_END</property> + + <child> + <widget class="GtkButton" id="edit_cancel_button"> + <property name="visible">True</property> + <property name="can_default">True</property> + <property name="can_focus">True</property> + <property name="label">gtk-cancel</property> + <property name="use_stock">True</property> + <property name="relief">GTK_RELIEF_NORMAL</property> + <property name="focus_on_click">True</property> + <property name="response_id">-6</property> + <signal name="clicked" handler="on_edit_cancel_button_clicked" last_modification_time="Sun, 01 Apr 2012 05:14:42 GMT"/> + </widget> + </child> + + <child> + <widget class="GtkButton" id="edit_ok_button"> + <property name="visible">True</property> + <property name="can_default">True</property> + <property name="can_focus">True</property> + <property name="label">gtk-ok</property> + <property name="use_stock">True</property> + <property name="relief">GTK_RELIEF_NORMAL</property> + <property name="focus_on_click">True</property> + <property name="response_id">-5</property> + <signal name="clicked" handler="on_edit_ok_button_clicked" last_modification_time="Sun, 01 Apr 2012 07:44:07 GMT"/> + </widget> + </child> + </widget> + <packing> + <property name="padding">0</property> + <property name="expand">False</property> + <property name="fill">True</property> + <property name="pack_type">GTK_PACK_END</property> + </packing> + </child> + + <child> + <widget class="GtkTable" id="table1"> + <property name="visible">True</property> + <property name="n_rows">3</property> + <property name="n_columns">2</property> + <property name="homogeneous">False</property> + <property name="row_spacing">8</property> + <property name="column_spacing">8</property> + + <child> + <widget class="GtkLabel" id="title_label"> + <property name="visible">True</property> + <property name="label" translatable="yes">Title:</property> + <property name="use_underline">False</property> + <property name="use_markup">False</property> + <property name="justify">GTK_JUSTIFY_LEFT</property> + <property name="wrap">False</property> + <property name="selectable">False</property> + <property name="xalign">0</property> + <property name="yalign">0.5</property> + <property name="xpad">0</property> + <property name="ypad">0</property> + <property name="ellipsize">PANGO_ELLIPSIZE_NONE</property> + <property name="width_chars">-1</property> + <property name="single_line_mode">False</property> + <property name="angle">0</property> + </widget> + <packing> + <property name="left_attach">0</property> + <property name="right_attach">1</property> + <property name="top_attach">1</property> + <property name="bottom_attach">2</property> + <property name="x_options">fill</property> + <property name="y_options"></property> + </packing> + </child> + + <child> + <widget class="GtkLabel" id="cmd_label"> + <property name="visible">True</property> + <property name="label" translatable="yes">Command:</property> + <property name="use_underline">False</property> + <property name="use_markup">False</property> + <property name="justify">GTK_JUSTIFY_LEFT</property> + <property name="wrap">False</property> + <property name="selectable">False</property> + <property name="xalign">0</property> + <property name="yalign">0.5</property> + <property name="xpad">0</property> + <property name="ypad">0</property> + <property name="ellipsize">PANGO_ELLIPSIZE_NONE</property> + <property name="width_chars">-1</property> + <property name="single_line_mode">False</property> + <property name="angle">0</property> + </widget> + <packing> + <property name="left_attach">0</property> + <property name="right_attach">1</property> + <property name="top_attach">2</property> + <property name="bottom_attach">3</property> + <property name="x_options">fill</property> + <property name="y_options"></property> + </packing> + </child> + + <child> + <widget class="GtkEntry" id="cmd_entry"> + <property name="visible">True</property> + <property name="tooltip" translatable="yes">Arbitrary shell command. Will be executed in the shell context which the main application was started from. Title formatting can be used. Example: xdg-open %D</property> + <property name="can_focus">True</property> + <property name="editable">True</property> + <property name="visibility">True</property> + <property name="max_length">0</property> + <property name="text" translatable="yes"></property> + <property name="has_frame">True</property> + <property name="invisible_char">•</property> + <property name="activates_default">False</property> + </widget> + <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> + <property name="y_options"></property> + </packing> + </child> + + <child> + <widget class="GtkLabel" id="name_label"> + <property name="visible">True</property> + <property name="label" translatable="yes">ID:</property> + <property name="use_underline">False</property> + <property name="use_markup">False</property> + <property name="justify">GTK_JUSTIFY_LEFT</property> + <property name="wrap">False</property> + <property name="selectable">False</property> + <property name="xalign">0</property> + <property name="yalign">0.5</property> + <property name="xpad">0</property> + <property name="ypad">0</property> + <property name="ellipsize">PANGO_ELLIPSIZE_NONE</property> + <property name="width_chars">-1</property> + <property name="single_line_mode">False</property> + <property name="angle">0</property> + </widget> + <packing> + <property name="left_attach">0</property> + <property name="right_attach">1</property> + <property name="top_attach">0</property> + <property name="bottom_attach">1</property> + <property name="x_options">fill</property> + <property name="y_options"></property> + </packing> + </child> + + <child> + <widget class="GtkEntry" id="title_entry"> + <property name="visible">True</property> + <property name="tooltip" translatable="yes">Free-form name, for example "My Shell Command"</property> + <property name="can_focus">True</property> + <property name="editable">True</property> + <property name="visibility">True</property> + <property name="max_length">0</property> + <property name="text" translatable="yes"></property> + <property name="has_frame">True</property> + <property name="invisible_char">•</property> + <property name="activates_default">False</property> + </widget> + <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="y_options"></property> + </packing> + </child> + + <child> + <widget class="GtkEntry" id="name_entry"> + <property name="visible">True</property> + <property name="tooltip" translatable="yes">Command ID, normally it should be something short, for example "youtube_open". It must be unique.</property> + <property name="can_focus">True</property> + <property name="editable">True</property> + <property name="visibility">True</property> + <property name="max_length">0</property> + <property name="text" translatable="yes"></property> + <property name="has_frame">True</property> + <property name="invisible_char">•</property> + <property name="activates_default">False</property> + </widget> + <packing> + <property name="left_attach">1</property> + <property name="right_attach">2</property> + <property name="top_attach">0</property> + <property name="bottom_attach">1</property> + <property name="y_options"></property> + </packing> + </child> + </widget> + <packing> + <property name="padding">0</property> + <property name="expand">False</property> + <property name="fill">True</property> + </packing> + </child> + + <child> + <widget class="GtkCheckButton" id="single_check"> + <property name="visible">True</property> + <property name="tooltip" translatable="yes">Works on single track.</property> + <property name="can_focus">True</property> + <property name="label" translatable="yes">Single Tracks</property> + <property name="use_underline">True</property> + <property name="relief">GTK_RELIEF_NORMAL</property> + <property name="focus_on_click">True</property> + <property name="active">False</property> + <property name="inconsistent">False</property> + <property name="draw_indicator">True</property> + </widget> + <packing> + <property name="padding">0</property> + <property name="expand">False</property> + <property name="fill">False</property> + </packing> + </child> + + <child> + <widget class="GtkCheckButton" id="multiple_check"> + <property name="visible">True</property> + <property name="tooltip" translatable="yes">Works on multiple tracks.</property> + <property name="can_focus">True</property> + <property name="label" translatable="yes">Multiple Tracks</property> + <property name="use_underline">True</property> + <property name="relief">GTK_RELIEF_NORMAL</property> + <property name="focus_on_click">True</property> + <property name="active">False</property> + <property name="inconsistent">False</property> + <property name="draw_indicator">True</property> + </widget> + <packing> + <property name="padding">0</property> + <property name="expand">False</property> + <property name="fill">False</property> + </packing> + </child> + + <child> + <widget class="GtkCheckButton" id="local_check"> + <property name="visible">True</property> + <property name="tooltip" translatable="yes">Works on local files.</property> + <property name="can_focus">True</property> + <property name="label" translatable="yes">Local</property> + <property name="use_underline">True</property> + <property name="relief">GTK_RELIEF_NORMAL</property> + <property name="focus_on_click">True</property> + <property name="active">False</property> + <property name="inconsistent">False</property> + <property name="draw_indicator">True</property> + </widget> + <packing> + <property name="padding">0</property> + <property name="expand">False</property> + <property name="fill">False</property> + </packing> + </child> + + <child> + <widget class="GtkCheckButton" id="remote_check"> + <property name="visible">True</property> + <property name="tooltip" translatable="yes">Works on remote files (e.g. http:// streams)</property> + <property name="can_focus">True</property> + <property name="label" translatable="yes">Remote</property> + <property name="use_underline">True</property> + <property name="relief">GTK_RELIEF_NORMAL</property> + <property name="focus_on_click">True</property> + <property name="active">False</property> + <property name="inconsistent">False</property> + <property name="draw_indicator">True</property> + </widget> + <packing> + <property name="padding">0</property> + <property name="expand">False</property> + <property name="fill">False</property> + </packing> + </child> + + <child> + <widget class="GtkCheckButton" id="playlist_check"> + <property name="visible">True</property> + <property name="tooltip" translatable="yes">Item should appear on the playlist tab context menu</property> + <property name="can_focus">True</property> + <property name="label" translatable="yes">Playlist</property> + <property name="use_underline">True</property> + <property name="relief">GTK_RELIEF_NORMAL</property> + <property name="focus_on_click">True</property> + <property name="active">False</property> + <property name="inconsistent">False</property> + <property name="draw_indicator">True</property> + </widget> + <packing> + <property name="padding">0</property> + <property name="expand">False</property> + <property name="fill">False</property> + </packing> + </child> + + <child> + <widget class="GtkCheckButton" id="common_check"> + <property name="visible">True</property> + <property name="tooltip" translatable="yes">Item should appear in the main menu</property> + <property name="can_focus">True</property> + <property name="label" translatable="yes">Common</property> + <property name="use_underline">True</property> + <property name="relief">GTK_RELIEF_NORMAL</property> + <property name="focus_on_click">True</property> + <property name="active">False</property> + <property name="inconsistent">False</property> + <property name="draw_indicator">True</property> + </widget> + <packing> + <property name="padding">0</property> + <property name="expand">False</property> + <property name="fill">False</property> + </packing> + </child> + </widget> + </child> +</widget> + +</glade-interface> diff --git a/plugins/shellexecui/shellexec.gladep b/plugins/shellexecui/shellexec.gladep new file mode 100644 index 00000000..3daaaba7 --- /dev/null +++ b/plugins/shellexecui/shellexec.gladep @@ -0,0 +1,12 @@ +<?xml version="1.0" standalone="no"?> <!--*- mode: xml -*--> +<!DOCTYPE glade-project SYSTEM "http://glade.gnome.org/glade-project-2.0.dtd"> + +<glade-project> + <name>Shellexecui</name> + <program_name>shellexecui</program_name> + <source_directory></source_directory> + <gnome_support>FALSE</gnome_support> + <output_main_file>FALSE</output_main_file> + <output_support_files>FALSE</output_support_files> + <output_build_files>FALSE</output_build_files> +</glade-project> diff --git a/plugins/shellexecui/shellexecui.c b/plugins/shellexecui/shellexecui.c new file mode 100644 index 00000000..b2a60230 --- /dev/null +++ b/plugins/shellexecui/shellexecui.c @@ -0,0 +1,443 @@ +/* + Copyright (C) 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 <gtk/gtk.h> +#include "interface.h" +#include "callbacks.h" +#include "support.h" +#include "../../deadbeef.h" +#include "../gtkui/gtkui_api.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 + +enum { + COL_TITLE = 0, + COL_META, + COL_COUNT, +}; + +static int +name_exists(const char *name, Shx_action_t *skip) { + DB_plugin_t **p = deadbeef->plug_get_list (); + for (int i = 0; p[i]; i++) { + if (!p[i]->get_actions) { + continue; + } + DB_plugin_action_t *action = p[i]->get_actions (NULL); + while(action) { + if(action != (DB_plugin_action_t*)skip && action->name && !strcmp(action->name, name)) { + return 1; + } + action = action->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) { + 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) && suffix < 1000) { // create a unique name + snprintf(name, sizeof (name), "new_cmd%d", suffix); + suffix++; + } + if (name_exists (name, NULL)) { + return; + } + // 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), + "%s", _("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 + shellexec_plugin->action_remove (action); + actions = (Shx_action_t *)shellexec_plugin->misc.plugin.get_actions(NULL); + + 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); + + shellexec_plugin->save_actions(); + deadbeef->sendmessage (DB_EV_ACTIONSCHANGED, 0, 0, 0); + } +} + +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, ¤t_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, "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); + gtk_toggle_button_set_active( + GTK_TOGGLE_BUTTON(lookup_widget(edit_dlg, "common_check")), + current_action->parent.flags & DB_ACTION_COMMON); + + 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, _("ID must 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 must 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 must 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), + "%s", 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 = shellexec_plugin->action_add (); + actions = (Shx_action_t *)shellexec_plugin->misc.plugin.get_actions(NULL); + 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, "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); + active = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(lookup_widget(edit_dlg, "common_check"))); + flags = (flags & ~DB_ACTION_COMMON) | (active?DB_ACTION_COMMON: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; + + shellexec_plugin->save_actions(); + deadbeef->sendmessage (DB_EV_ACTIONSCHANGED, 0, 0, 0); +} + +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 = (Shx_action_t *)shellexec_plugin->misc.plugin.get_actions(NULL); + 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 gboolean +shellexecui_action_gtk (void *data) +{ + conf_dlg = create_shellexec_conf_dialog(); + gtk_widget_set_size_request (conf_dlg, 400, 400); + gtk_window_set_transient_for(GTK_WINDOW(conf_dlg), + GTK_WINDOW(gtkui_plugin->get_mainwin())); + init_treeview(); + gtk_widget_show(conf_dlg); + return FALSE; +} + +static int +shellexecui_action_callback(DB_plugin_action_t *action, + void *user_data) { + g_idle_add (shellexecui_action_gtk, NULL); + 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, +#if GTK_CHECK_VERSION(3,0,0) + .plugin.id = "shellexecui_gtk3", + .plugin.name = "Shellexec GTK3 UI", +#else + .plugin.id = "shellexecui_gtk2", + .plugin.name = "Shellexec GTK2 UI", +#endif + .plugin.descr = "A GTK UI for the Shellexec plugin", + .plugin.copyright = + "Copyright (C) 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) +shellexecui_gtk3_load (DB_functions_t *api) { +#else +shellexecui_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..c0d93fe4 --- /dev/null +++ b/plugins/shellexecui/support.c @@ -0,0 +1,221 @@ +/* + * 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); + } +} + +#if GTK_CHECK_VERSION(3,0,0) +GtkWidget * +gtk_combo_box_entry_new_text(void) { + return gtk_combo_box_text_new_with_entry (); +} + +void +gtk_dialog_set_has_separator (GtkDialog *dlg, gboolean has) { +} +#endif + +#if !GTK_CHECK_VERSION(2,22,0) +GdkDragAction +gdk_drag_context_get_selected_action (GdkDragContext *context) { + return context->action; +} +GList * +gdk_drag_context_list_targets (GdkDragContext *context) { + return context->targets; +} +#endif + +#if !GTK_CHECK_VERSION(2,24,0) +#define GTK_COMBO_BOX_TEXT GTK_COMBO_BOX +GtkWidget * +gtk_combo_box_text_new () { + return gtk_combo_box_new_text (); +} + +GtkWidget * +gtk_combo_box_text_new_with_entry (void) { + return gtk_combo_box_entry_new (); +} + +void +gtk_combo_box_text_append_text (GtkComboBoxText *combo_box, const gchar *text) { + gtk_combo_box_append_text (combo_box, text); +} + +void +gtk_combo_box_text_insert_text (GtkComboBoxText *combo_box, gint position, const gchar *text) { + gtk_combo_box_insert_text (combo_box, position, text); +} + +void +gtk_combo_box_text_prepend_text (GtkComboBoxText *combo_box, const gchar *text) { + gtk_combo_box_prepend_text (combo_box, text); +} +gchar * +gtk_combo_box_text_get_active_text (GtkComboBoxText *combo_box) { + return gtk_combo_box_get_active_text (combo_box); +} + +#endif + +#if !GTK_CHECK_VERSION(2,18,0) +void +gtk_widget_set_allocation (GtkWidget *widget, const GtkAllocation *allocation) { + widget->allocation.x = (allocation)->x; + widget->allocation.y = (allocation)->y; + widget->allocation.width = (allocation)->width; + widget->allocation.height = (allocation)->height; +} + +void +gtk_widget_get_allocation (GtkWidget *widget, GtkAllocation *allocation) { + (allocation)->x = widget->allocation.x; + (allocation)->y = widget->allocation.y; + (allocation)->width = widget->allocation.width; + (allocation)->height = widget->allocation.height; +} + +void +gtk_widget_set_window(GtkWidget *widget, GdkWindow *window) { + widget->window = window; +} +#endif diff --git a/plugins/shellexecui/support.h b/plugins/shellexecui/support.h new file mode 100644 index 00000000..b7800a1d --- /dev/null +++ b/plugins/shellexecui/support.h @@ -0,0 +1,146 @@ +#ifndef __SUPPORT_H +#define __SUPPORT_H + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif + +#include <gtk/gtk.h> +#if GTK_CHECK_VERSION(3,0,0) +#include <gdk/gdkkeysyms-compat.h> +#else +#include <gdk/gdkkeysyms.h> +#endif + +/* + * 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) +#ifndef _ +# define _(String) (String) +#endif +# 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); + +#if GTK_CHECK_VERSION(3,0,0) +GtkWidget * +gtk_combo_box_entry_new_text(void); + +void +gtk_dialog_set_has_separator (GtkDialog *dlg, gboolean has); +#endif + +#if !GTK_CHECK_VERSION(2,20,0) +#define gtk_widget_set_realized(widget, realized) {if (realized) GTK_WIDGET_SET_FLAGS (widget, GTK_REALIZED); else GTK_WIDGET_UNSET_FLAGS(widget, GTK_REALIZED);} +#define gtk_widget_get_realized(widget) (GTK_WIDGET_REALIZED (widget)) +#endif + +#if !GTK_CHECK_VERSION(2,22,0) +GdkDragAction +gdk_drag_context_get_selected_action (GdkDragContext *context); +GList * +gdk_drag_context_list_targets (GdkDragContext *context); +#endif + +#if !GTK_CHECK_VERSION(2,24,0) +#define GTK_COMBO_BOX_TEXT GTK_COMBO_BOX +typedef GtkComboBox GtkComboBoxText; +GtkWidget *gtk_combo_box_text_new (); +GtkWidget *gtk_combo_box_text_new_with_entry (void); +void gtk_combo_box_text_append_text (GtkComboBoxText *combo_box, const gchar *text); +void gtk_combo_box_text_insert_text (GtkComboBoxText *combo_box, gint position, const gchar *text); +void gtk_combo_box_text_prepend_text (GtkComboBoxText *combo_box, const gchar *text); +gchar *gtk_combo_box_text_get_active_text (GtkComboBoxText *combo_box); +#endif + +#if !GTK_CHECK_VERSION(2,14,0) +#define gtk_widget_get_window(widget) ((widget)->window) +#define gtk_selection_data_get_target(data) (data->target) +#define gtk_dialog_get_content_area(dialog) (dialog->vbox) +#define gtk_dialog_get_action_area(dialog) (dialog->action_area) +#define gtk_selection_data_get_data(data) (data->data) +#define gtk_selection_data_get_length(data) (data->length) +#define gtk_selection_data_get_format(data) (data->format) +#define gtk_adjustment_get_lower(adj) (adj->lower) +#define gtk_adjustment_get_upper(adj) (adj->upper) +#endif + +#if !GTK_CHECK_VERSION(2,18,0) +#define gtk_widget_set_has_window(widget, has_window) \ + if (has_window) GTK_WIDGET_UNSET_FLAGS (widget, GTK_NO_WINDOW); \ + else GTK_WIDGET_SET_FLAGS (widget, GTK_NO_WINDOW); + +#define gtk_widget_get_visible(widget) (GTK_WIDGET_VISIBLE(widget)) +#define gtk_widget_get_has_window(widget) (!GTK_WIDGET_NO_WINDOW(widget)) +void gtk_widget_set_window(GtkWidget *widget, GdkWindow *window); +#endif + + +#if !GTK_CHECK_VERSION(2,18,0) +void gtk_widget_set_allocation (GtkWidget *widget, + const GtkAllocation *allocation); + +void gtk_widget_get_allocation (GtkWidget *widget, + GtkAllocation *allocation); + +#define gtk_widget_set_can_focus(widget, canfocus) {if (canfocus) GTK_WIDGET_SET_FLAGS (widget, GTK_CAN_FOCUS); else GTK_WIDGET_UNSET_FLAGS(widget, GTK_CAN_FOCUS);} + +#define gtk_widget_get_can_focus(widget) (GTK_WIDGET_CAN_FOCUS (widget)); + +#define gtk_widget_set_can_default(widget, candefault) {if (candefault) GTK_WIDGET_SET_FLAGS (widget, GTK_CAN_DEFAULT); else GTK_WIDGET_UNSET_FLAGS(widget, GTK_CAN_DEFAULT);} + +#define gtk_widget_get_can_default(widget) (GTK_WIDGET_CAN_DEFAULT (widget)); +#endif + +#endif |