summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGravatar Alan Fitton <ajf@eth0.org.uk>2011-09-29 20:54:42 +0000
committerGravatar Alan Fitton <ajf@eth0.org.uk>2011-09-29 20:54:42 +0000
commit37f5bcc29fb404bb1a87d05230ab71c5f31650dc (patch)
tree9d45a3f0d1c284e00b17caf976b0423c965b8719
parent0a8310af38022a5794c6ec8f0b5a6e745debfdea (diff)
the foundation of remote command execution. still lots of work to do here, but it works for me and seems like a good start.
-rw-r--r--src/Makefile.am3
-rw-r--r--src/trg-main-window.c81
-rw-r--r--src/trg-preferences-dialog.c226
-rw-r--r--src/trg-prefs.c66
-rw-r--r--src/trg-prefs.h7
-rw-r--r--src/trg-state-selector.c4
-rw-r--r--src/util.c12
-rw-r--r--src/util.h1
8 files changed, 346 insertions, 54 deletions
diff --git a/src/Makefile.am b/src/Makefile.am
index 13d1680..03b5e2e 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -20,7 +20,7 @@ desktopdir = $(datadir)/applications
desktop_DATA = transmission-remote-gtk.desktop
bin_PROGRAMS = transmission-remote-gtk
-INCLUDES = --pedantic -Wall -Wno-format -I.. -DTRGLICENSE=\""$(trglicense)"\" $(libcurl_CFLAGS) $(jsonglib_CFLAGS) $(gthread_CFLAGS) $(gtk_CFLAGS) $(gio_CFLAGS) $(unique_CFLAGS) $(notify_CFLAGS) $(libproxy_CFLAGS) -std=gnu99
+INCLUDES = --pedantic -Wall -Wno-format -Wno-overflow -I.. -DTRGLICENSE=\""$(trglicense)"\" $(libcurl_CFLAGS) $(jsonglib_CFLAGS) $(gthread_CFLAGS) $(gtk_CFLAGS) $(gio_CFLAGS) $(unique_CFLAGS) $(notify_CFLAGS) $(libproxy_CFLAGS) -std=gnu99
transmission_remote_gtk_SOURCES = main.c \
requests.c \
@@ -70,6 +70,7 @@ transmission_remote_gtk_SOURCES = main.c \
bencode.c \
trg-prefs.c \
trg-destination-combo.c \
+ remote-exec.c \
$(NULL)
transmission_remote_gtk_LDFLAGS = -lm $(jsonglib_LIBS) $(gtk_LIBS) $(gthread_LIBS) $(GEOIP_LIBS) $(gio_LIBS) $(unique_LIBS) $(notify_LIBS) $(libproxy_LIBS) $(libcurl_LIBS)
diff --git a/src/trg-main-window.c b/src/trg-main-window.c
index 909156b..e763100 100644
--- a/src/trg-main-window.c
+++ b/src/trg-main-window.c
@@ -43,6 +43,7 @@
#include "session-get.h"
#include "torrent.h"
#include "protocol-constants.h"
+#include "remote-exec.h"
#include "trg-main-window.h"
#include "trg-about-window.h"
@@ -104,7 +105,6 @@ static void open_props_cb(GtkWidget * w, gpointer data);
static gint confirm_action_dialog(GtkWindow * win,
GtkTreeSelection * selection, gchar * question_single,
gchar * question_multi, gchar * action_stock);
-static GtkWidget *my_scrolledwin_new(GtkWidget * child);
static void view_stats_toggled_cb(GtkWidget * w, gpointer data);
static void view_states_toggled_cb(GtkCheckMenuItem * w, gpointer data);
static void view_notebook_toggled_cb(GtkCheckMenuItem * w, gpointer data);
@@ -142,7 +142,7 @@ static void status_icon_activated(GtkStatusIcon * icon, gpointer data);
static void clear_filter_entry_cb(GtkWidget * w, gpointer data);
static gboolean torrent_tv_key_press_event(GtkWidget * w, GdkEventKey * key,
gpointer data);
-static GtkWidget *trg_imagemenuitem_new(GtkMenuShell * shell, char *text,
+static GtkWidget *trg_imagemenuitem_new(GtkMenuShell * shell, const gchar *text,
char *stock_id, gboolean sensitive, GCallback cb, gpointer cbdata);
static void set_limit_cb(GtkWidget * w, gpointer data);
static GtkWidget *limit_item_new(TrgMainWindow * win, GtkWidget * menu,
@@ -688,14 +688,6 @@ static void delete_cb(GtkWidget * w G_GNUC_UNUSED, gpointer data) {
json_array_unref(ids);
}
-static GtkWidget *my_scrolledwin_new(GtkWidget * child) {
- GtkWidget *scrolled_win = gtk_scrolled_window_new(NULL, NULL);
- gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scrolled_win),
- GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
- gtk_container_add(GTK_CONTAINER(scrolled_win), child);
- return scrolled_win;
-}
-
static void view_stats_toggled_cb(GtkWidget * w, gpointer data) {
TrgMainWindowPrivate *priv = TRG_MAIN_WINDOW_GET_PRIVATE(data);
@@ -1322,7 +1314,7 @@ static gboolean torrent_tv_key_press_event(GtkWidget * w, GdkEventKey * key,
return FALSE;
}
-static GtkWidget *trg_imagemenuitem_new(GtkMenuShell * shell, char *text,
+static GtkWidget *trg_imagemenuitem_new(GtkMenuShell * shell, const gchar *text,
char *stock_id, gboolean sensitive, GCallback cb, gpointer cbdata) {
GtkWidget *item = gtk_image_menu_item_new_with_label(stock_id);
@@ -1457,11 +1449,44 @@ static GtkWidget *limit_menu_new(TrgMainWindow * win, gchar * title,
return toplevel;
}
+static void exec_cmd_cb(GtkWidget *w, gpointer data)
+{
+ TrgMainWindowPrivate *priv = TRG_MAIN_WINDOW_GET_PRIVATE(data);
+ JsonObject *cmd_obj = (JsonObject*)g_object_get_data(G_OBJECT(w), "cmd-object");
+ GtkTreeSelection *selection;
+ gint rowCount;
+
+ selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(priv->torrentTreeView));
+ rowCount = gtk_tree_selection_count_selected_rows(selection);
+
+ if (rowCount==1) {
+ JsonObject *json;
+ GError *cmd_error;
+ gchar *cmd_line, **argv;
+ if (!get_torrent_data(trg_client_get_torrent_table(priv->client),
+ priv->selectedTorrentId, &json,
+ NULL))
+ return;
+ cmd_line = build_remote_exec_cmd(json, json_object_get_string_member(cmd_obj, "cmd"));
+ g_debug("Exec: %s",cmd_line);
+ //GTK has bug, won't let you pass a string here containing a quoted param, so use parse and then spawn
+ // rather than g_spawn_command_line_async(cmd_line,&cmd_error);
+ g_shell_parse_argv(cmd_line, NULL, &argv, NULL);
+ g_spawn_async( NULL, argv, NULL, G_SPAWN_SEARCH_PATH,
+ NULL, NULL, NULL, &cmd_error );
+ g_strfreev( argv );
+ g_free( cmd_line );
+ }
+}
+
static void trg_torrent_tv_view_menu(GtkWidget * treeview,
GdkEventButton * event, gpointer data) {
TrgMainWindowPrivate *priv = TRG_MAIN_WINDOW_GET_PRIVATE(data);
+ TrgPrefs *prefs = trg_client_get_prefs(priv->client);
GtkWidget *menu;
+ gint n_cmds;
JsonArray *ids;
+ JsonArray *cmds;
menu = gtk_menu_new();
ids = build_json_id_array(TRG_TORRENT_TREE_VIEW(treeview));
@@ -1483,6 +1508,40 @@ static void trg_torrent_tv_view_menu(GtkWidget * treeview,
trg_imagemenuitem_new(GTK_MENU_SHELL(menu), _("Remove & Delete"),
GTK_STOCK_CLEAR, TRUE, G_CALLBACK(delete_cb), data);
+ cmds = trg_prefs_get_array(prefs, TRG_PREFS_KEY_EXEC_COMMANDS, TRG_PREFS_PROFILE);
+ n_cmds = json_array_get_length(cmds);
+
+ if (n_cmds > 0) {
+ GList *cmds_list = json_array_get_elements(cmds);
+ GtkMenuShell *cmds_shell;
+ GList *cmds_li;
+
+ if (n_cmds < 3) {
+ gtk_menu_shell_append(GTK_MENU_SHELL(menu), gtk_separator_menu_item_new());
+ cmds_shell = GTK_MENU_SHELL(menu);
+ } else {
+ GtkImageMenuItem *cmds_menu = GTK_IMAGE_MENU_ITEM(gtk_image_menu_item_new_with_label(GTK_STOCK_EXECUTE));
+ gtk_image_menu_item_set_use_stock(cmds_menu, TRUE);
+ gtk_image_menu_item_set_always_show_image(cmds_menu, TRUE);
+ gtk_menu_item_set_label(GTK_MENU_ITEM(cmds_menu), _("Remote Commands"));
+
+ cmds_shell = GTK_MENU_SHELL(gtk_menu_new());
+ gtk_menu_item_set_submenu(GTK_MENU_ITEM(cmds_menu), GTK_WIDGET(cmds_shell));
+ gtk_menu_shell_append(GTK_MENU_SHELL(menu), GTK_WIDGET(cmds_menu));
+ }
+
+ for (cmds_li = cmds_list; cmds_li; cmds_li = g_list_next(cmds_li))
+ {
+ JsonObject *cmd_obj = json_node_get_object((JsonNode*)cmds_li->data);
+ const gchar *cmd_label = json_object_get_string_member(cmd_obj, "label");
+ GtkWidget *item = trg_imagemenuitem_new(cmds_shell, cmd_label,
+ GTK_STOCK_EXECUTE, TRUE, G_CALLBACK(exec_cmd_cb), data);
+ g_object_set_data(G_OBJECT(item), "cmd-object", cmd_obj);
+ }
+
+ g_list_free(cmds_list);
+ }
+
gtk_menu_shell_append(GTK_MENU_SHELL(menu), gtk_separator_menu_item_new());
if (priv->queuesEnabled) {
diff --git a/src/trg-preferences-dialog.c b/src/trg-preferences-dialog.c
index 28a9b6b..b9e87a6 100644
--- a/src/trg-preferences-dialog.c
+++ b/src/trg-preferences-dialog.c
@@ -52,6 +52,9 @@ struct _TrgPreferencesDialogPrivate {
GtkWidget *profileComboBox;
GtkWidget *profileNameEntry;
GtkWidget *fullUpdateCheck;
+ GtkWidget *execDelButton;
+ GtkWidget *etv;
+ GtkTreeViewColumn *etvLabelColumn;
GList *widgets;
};
@@ -126,9 +129,10 @@ static void trg_preferences_response_cb(GtkDialog * dlg, gint res_id,
gpointer data G_GNUC_UNUSED) {
TrgPreferencesDialogPrivate *priv = TRG_PREFERENCES_DIALOG_GET_PRIVATE(dlg);
- trg_pref_widget_save_all(TRG_PREFERENCES_DIALOG(dlg));
-
- trg_prefs_save(priv->prefs);
+ if (res_id == GTK_RESPONSE_OK) {
+ trg_pref_widget_save_all(TRG_PREFERENCES_DIALOG(dlg));
+ trg_prefs_save(priv->prefs);
+ }
GList *li;
for (li = priv->widgets; li; li = g_list_next(li))
@@ -385,7 +389,7 @@ static GtkWidget *trg_prefs_desktopPage(TrgPreferencesDialog *dlg) {
w = trgp_check_new(dlg, _("Torrent added notifications"),
TRG_PREFS_KEY_ADD_NOTIFY, TRG_PREFS_GLOBAL, NULL);
gtk_widget_set_sensitive(w, gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON
- (tray)));
+ (tray)));
g_signal_connect(G_OBJECT(tray), "toggled",
G_CALLBACK(toggle_active_arg_is_sensitive), w);
hig_workarea_add_wide_control(t, &row, w);
@@ -393,7 +397,7 @@ static GtkWidget *trg_prefs_desktopPage(TrgPreferencesDialog *dlg) {
w = trgp_check_new(dlg, _("Torrent complete notifications"),
TRG_PREFS_KEY_COMPLETE_NOTIFY, TRG_PREFS_GLOBAL, NULL);
gtk_widget_set_sensitive(w, gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON
- (tray)));
+ (tray)));
g_signal_connect(G_OBJECT(tray), "toggled",
G_CALLBACK(toggle_active_arg_is_sensitive), w);
hig_workarea_add_wide_control(t, &row, w);
@@ -550,7 +554,205 @@ static void trgp_double_special_dependent(GtkWidget *widget, gpointer data) {
GTK_WIDGET(data),
gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(widget))
&& gtk_widget_get_sensitive(priv->fullUpdateCheck)
- && gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(priv->fullUpdateCheck)));
+ && gtk_toggle_button_get_active(
+ GTK_TOGGLE_BUTTON(priv->fullUpdateCheck)));
+}
+
+static void exec_selection_changed(GtkTreeSelection *selection, gpointer data) {
+ TrgPreferencesDialogPrivate *priv =
+ TRG_PREFERENCES_DIALOG_GET_PRIVATE(data);
+
+ if (gtk_tree_selection_get_selected(selection, NULL, NULL))
+ gtk_widget_set_sensitive(priv->execDelButton, TRUE);
+ else
+ gtk_widget_set_sensitive(priv->execDelButton, FALSE);
+}
+
+static void trg_etc_edited(GtkCellRendererText * renderer, gchar * path,
+ gchar * new_text, gint model_column, gpointer user_data) {
+ GtkTreeModel *model = GTK_TREE_MODEL(user_data);
+ GtkTreeIter iter;
+
+ gtk_tree_model_get_iter_from_string(model, &iter, path);
+ gtk_list_store_set(GTK_LIST_STORE(model), &iter, model_column, new_text, -1);
+}
+
+static void trg_etv_label_edited(GtkCellRendererText * renderer, gchar * path,
+ gchar * new_text, gpointer user_data) {
+ trg_etc_edited(renderer, path, new_text, 0, user_data);
+}
+
+static void trg_etv_cmd_edited(GtkCellRendererText * renderer, gchar * path,
+ gchar * new_text, gpointer user_data) {
+ trg_etc_edited(renderer, path, new_text, 1, user_data);
+}
+
+static void trg_prefs_etv_refresh(TrgPrefs *prefs, void *wdp) {
+ trg_pref_widget_desc *wd = (trg_pref_widget_desc*) wdp;
+ GtkListStore *model =
+ GTK_LIST_STORE(gtk_tree_view_get_model(GTK_TREE_VIEW(wd->widget)));
+ GtkTreeIter iter;
+ JsonArray *ja;
+ GList *ja_list, *li;
+
+ ja = trg_prefs_get_array(prefs, wd->key, wd->flags);
+
+ gtk_list_store_clear(model);
+
+ if (!ja)
+ return;
+
+ ja_list = json_array_get_elements(ja);
+
+ for (li = ja_list; li; li = g_list_next(li)) {
+ JsonNode *ja_node = (JsonNode*) li->data;
+ JsonObject *jobj = json_node_get_object(ja_node);
+ gtk_list_store_append(model, &iter);
+ gtk_list_store_set(model, &iter, 0,
+ json_object_get_string_member(jobj, "label"), 1,
+ json_object_get_string_member(jobj, "cmd"), -1);
+ }
+
+ g_list_free(ja_list);
+}
+
+static gboolean trg_prefs_etc_save_foreachfunc(GtkTreeModel *model,
+ GtkTreePath *path, GtkTreeIter *iter, gpointer data) {
+ gchar *label, *cmd;
+ JsonArray *ja = (JsonArray*) data;
+ JsonObject *new = json_object_new();
+
+ gtk_tree_model_get(model, iter, 0, &label, 1, &cmd, -1);
+
+ json_object_set_string_member(new, "label", label);
+ json_object_set_string_member(new, "cmd", cmd);
+
+ json_array_add_object_element(ja, new);
+
+ g_free(label);
+ g_free(cmd);
+
+ return FALSE;
+}
+
+static void trg_prefs_etv_save(TrgPrefs *prefs, void *wdp) {
+ trg_pref_widget_desc *wd = (trg_pref_widget_desc*) wdp;
+ JsonNode *node = trg_prefs_get_value(prefs, wd->key, JSON_NODE_ARRAY,
+ wd->flags | TRG_PREFS_REPLACENODE);
+ JsonArray *ja = json_array_new();
+ GtkTreeView *tv = GTK_TREE_VIEW(wd->widget);
+ GtkTreeModel *model = gtk_tree_view_get_model(tv);
+
+ gtk_tree_model_foreach(model, trg_prefs_etc_save_foreachfunc, ja);
+ json_node_take_array(node, ja);
+ trg_prefs_changed_emit_signal(prefs, wd->key);
+}
+
+static GtkWidget *trg_prefs_execTreeView(TrgPreferencesDialog *dlg) {
+ TrgPreferencesDialogPrivate *priv = TRG_PREFERENCES_DIALOG_GET_PRIVATE(dlg);
+ GtkListStore *model = gtk_list_store_new(2, G_TYPE_STRING, G_TYPE_STRING);
+ GtkWidget *tv = gtk_tree_view_new_with_model(GTK_TREE_MODEL(model));
+ GtkTreeViewColumn *column;
+ GtkCellRenderer *renderer;
+ GtkTreeSelection *selection;
+ trg_pref_widget_desc *wd;
+
+ g_object_unref(G_OBJECT(model));
+
+ gtk_tree_view_set_rubber_banding(GTK_TREE_VIEW(tv), TRUE);
+ //gtk_tree_view_set_headers_visible(GTK_TREE_VIEW(tv), FALSE);
+
+ renderer = gtk_cell_renderer_text_new();
+ g_object_set(G_OBJECT(renderer), "editable", TRUE, NULL);
+ g_signal_connect(renderer, "edited",
+ G_CALLBACK(trg_etv_label_edited), model);
+ column = priv->etvLabelColumn = gtk_tree_view_column_new_with_attributes(
+ _("Label"), renderer, "text", 0, NULL);
+ gtk_tree_view_append_column(GTK_TREE_VIEW(tv), column);
+
+ renderer = gtk_cell_renderer_text_new();
+ g_object_set(G_OBJECT(renderer), "editable", TRUE, NULL);
+ g_signal_connect(renderer, "edited",
+ G_CALLBACK(trg_etv_cmd_edited), model);
+ column = gtk_tree_view_column_new_with_attributes(_("Command"), renderer,
+ "text", 1, NULL);
+ gtk_tree_view_append_column(GTK_TREE_VIEW(tv), column);
+
+ selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(tv));
+
+ g_signal_connect(G_OBJECT(selection), "changed",
+ G_CALLBACK(exec_selection_changed), dlg);
+
+ wd = trg_pref_widget_desc_new(tv, TRG_PREFS_KEY_EXEC_COMMANDS,
+ TRG_PREFS_PROFILE);
+ wd->saveFunc = &trg_prefs_etv_save;
+ wd->refreshFunc = &trg_prefs_etv_refresh;
+ priv->widgets = g_list_append(priv->widgets, wd);
+
+ trg_prefs_etv_refresh(priv->prefs, wd);
+
+ return tv;
+}
+
+static void trg_prefs_add_exec_cb(GtkWidget *w, gpointer data) {
+ TrgPreferencesDialogPrivate *priv =
+ TRG_PREFERENCES_DIALOG_GET_PRIVATE(data);
+ GtkTreeModel *model = gtk_tree_view_get_model(GTK_TREE_VIEW(priv->etv));
+ GtkTreeIter iter;
+ GtkTreePath *path;
+
+ gtk_list_store_append(GTK_LIST_STORE(model), &iter);
+ path = gtk_tree_model_get_path(model, &iter);
+ gtk_tree_view_set_cursor(GTK_TREE_VIEW(priv->etv), path,
+ priv->etvLabelColumn, TRUE);
+ gtk_tree_path_free(path);
+}
+
+static void trg_prefs_del_exec_cb(GtkWidget *w, gpointer data) {
+ GtkTreeView *tv = GTK_TREE_VIEW(data);
+ GtkTreeSelection *selection = gtk_tree_view_get_selection(tv);
+ GtkTreeModel *model;
+ GtkTreeIter iter;
+
+ if (gtk_tree_selection_get_selected(selection, &model, &iter))
+ gtk_list_store_remove(GTK_LIST_STORE(model), &iter);
+}
+
+static GtkWidget *trg_prefs_openExecPage(TrgPreferencesDialog *dlg) {
+ TrgPreferencesDialogPrivate *priv = TRG_PREFERENCES_DIALOG_GET_PRIVATE(dlg);
+ GtkWidget *t, *hbox, *w;
+ gint row = 0;
+
+ t = hig_workarea_create();
+
+ //frame = gtk_frame_new("Profile name...");
+
+ hig_workarea_add_section_title(t, &row, _("Remote Commands"));
+
+ priv->etv = trg_prefs_execTreeView(dlg);
+
+ gtk_table_attach(GTK_TABLE(t), my_scrolledwin_new(priv->etv), 1, 2, row,
+ row + 1, GTK_EXPAND | GTK_SHRINK | GTK_FILL,
+ GTK_FILL | GTK_EXPAND | GTK_SHRINK, 0, 0);
+
+ row++;
+
+ hbox = gtk_hbox_new(FALSE, 0);
+ w = gtk_button_new_from_stock(GTK_STOCK_ADD);
+ g_signal_connect(w, "clicked", G_CALLBACK(trg_prefs_add_exec_cb), dlg);
+ gtk_box_pack_start(GTK_BOX(hbox), w, FALSE, FALSE, 4);
+
+ w = priv->execDelButton = gtk_button_new_from_stock(GTK_STOCK_DELETE);
+ gtk_widget_set_sensitive(w, FALSE);
+ g_signal_connect(w, "clicked", G_CALLBACK(trg_prefs_del_exec_cb), priv->etv);
+ gtk_box_pack_start(GTK_BOX(hbox), w, FALSE, FALSE, 4);
+
+ hig_workarea_add_wide_control(t, &row, hbox);
+
+ //gtk_container_add(GTK_CONTAINER(frame), t);
+ //return frame;
+
+ return t;
}
static GtkWidget *trg_prefs_serverPage(TrgPreferencesDialog *dlg) {
@@ -678,14 +880,15 @@ static GObject *trg_preferences_dialog_constructor(GType type,
n_construct_properties, construct_params);
priv = TRG_PREFERENCES_DIALOG_GET_PRIVATE(object);
- contentvbox = gtk_dialog_get_content_area (GTK_DIALOG(object));
+ contentvbox = gtk_dialog_get_content_area(GTK_DIALOG(object));
gtk_window_set_transient_for(GTK_WINDOW(object), GTK_WINDOW(priv->win));
gtk_window_set_destroy_with_parent(GTK_WINDOW(object), TRUE);
gtk_dialog_add_button(GTK_DIALOG(object), GTK_STOCK_CLOSE,
GTK_RESPONSE_CLOSE);
+ gtk_dialog_add_button(GTK_DIALOG(object), GTK_STOCK_OK, GTK_RESPONSE_OK);
- gtk_dialog_set_default_response(GTK_DIALOG(object), GTK_RESPONSE_CLOSE);
+ gtk_dialog_set_default_response(GTK_DIALOG(object), GTK_RESPONSE_OK);
gtk_window_set_title(GTK_WINDOW(object), _("Local Preferences"));
gtk_container_set_border_width(GTK_CONTAINER(object), GUI_PAD);
@@ -701,6 +904,10 @@ static GObject *trg_preferences_dialog_constructor(GType type,
gtk_label_new(_("Connection")));
gtk_notebook_append_page(GTK_NOTEBOOK(notebook),
+ trg_prefs_openExecPage(TRG_PREFERENCES_DIALOG(object)),
+ gtk_label_new(_("Remote Execute")));
+
+ gtk_notebook_append_page(GTK_NOTEBOOK(notebook),
trg_prefs_desktopPage(TRG_PREFERENCES_DIALOG(object)),
gtk_label_new(_("Desktop")));
@@ -710,8 +917,7 @@ static GObject *trg_preferences_dialog_constructor(GType type,
gtk_container_set_border_width(GTK_CONTAINER(notebook), GUI_PAD);
- gtk_box_pack_start(GTK_BOX(contentvbox), notebook, TRUE, TRUE,
- 0);
+ gtk_box_pack_start(GTK_BOX(contentvbox), notebook, TRUE, TRUE, 0);
return object;
}
diff --git a/src/trg-prefs.c b/src/trg-prefs.c
index 471036d..c54ed90 100644
--- a/src/trg-prefs.c
+++ b/src/trg-prefs.c
@@ -50,7 +50,7 @@ enum {
static guint signals[PREFS_SIGNAL_COUNT] = { 0 };
-static void trg_prefs_changed_emit_signal(TrgPrefs *p, gchar *key)
+void trg_prefs_changed_emit_signal(TrgPrefs *p, gchar *key)
{
g_signal_emit(p, signals[PREF_CHANGE], 0, key);
}
@@ -175,26 +175,35 @@ gint trg_prefs_get_profile_id(TrgPrefs *p) {
TRG_PREFS_KEY_PROFILE_ID);
}
-JsonNode *trg_prefs_get_value(TrgPrefs *p, gchar *key, int flags) {
+static JsonNode *trg_prefs_get_value_inner(JsonObject *obj, gchar *key, int type, int flags)
+{
+ if (json_object_has_member(obj, key)) {
+ if ((flags & TRG_PREFS_REPLACENODE))
+ json_object_remove_member(obj, key);
+ else
+ return json_object_get_member(obj, key);
+ }
+
+ if ((flags & TRG_PREFS_NEWNODE) || (flags & TRG_PREFS_REPLACENODE)) {
+ JsonNode *newNode = json_node_new(type);
+ json_object_set_member(obj, key, newNode);
+ return newNode;
+ }
+
+ return NULL;
+}
+
+JsonNode *trg_prefs_get_value(TrgPrefs *p, gchar *key, int type, int flags) {
TrgPrefsPrivate *priv = GET_PRIVATE(p);
+ JsonNode *res;
if ((flags & TRG_PREFS_PROFILE)) {
JsonObject *profile = trg_prefs_get_profile(p);
- if (json_object_has_member(profile, key)) {
- return json_object_get_member(profile, key);
- } else if ((flags & TRG_PREFS_NEWNODE)) {
- JsonNode *newNode = json_node_new(JSON_NODE_VALUE);
- json_object_set_member(profile, key, newNode);
- return newNode;
- }
+ if ((res = trg_prefs_get_value_inner(profile, key, type, flags)))
+ return res;
} else {
- if (json_object_has_member(priv->userObj, key)) {
- return json_object_get_member(priv->userObj, key);
- } else if ((flags & TRG_PREFS_NEWNODE)) {
- JsonNode *newNode = json_node_new(JSON_NODE_VALUE);
- json_object_set_member(priv->userObj, key, newNode);
- return newNode;
- }
+ if ((res = trg_prefs_get_value_inner(priv->userObj, key, type, flags)))
+ return res;
}
if (priv->defaultsObj && json_object_has_member(priv->defaultsObj, key))
@@ -204,15 +213,24 @@ JsonNode *trg_prefs_get_value(TrgPrefs *p, gchar *key, int flags) {
}
gchar *trg_prefs_get_string(TrgPrefs *p, gchar *key, int flags) {
- JsonNode *node = trg_prefs_get_value(p, key, flags);
+ JsonNode *node = trg_prefs_get_value(p, key, JSON_NODE_VALUE, flags);
if (node)
return g_strdup(json_node_get_string(node));
else
return NULL;
}
+JsonArray *trg_prefs_get_array(TrgPrefs *p, gchar *key, int flags)
+{
+ JsonNode *node = trg_prefs_get_value(p, key, JSON_NODE_ARRAY, flags);
+ if (node)
+ return json_node_get_array(node);
+ else
+ return NULL;
+}
+
gint64 trg_prefs_get_int(TrgPrefs *p, gchar *key, int flags) {
- JsonNode *node = trg_prefs_get_value(p, key, flags);
+ JsonNode *node = trg_prefs_get_value(p, key, JSON_NODE_VALUE, flags);
if (node)
return json_node_get_int(node);
else
@@ -220,7 +238,7 @@ gint64 trg_prefs_get_int(TrgPrefs *p, gchar *key, int flags) {
}
gdouble trg_prefs_get_double(TrgPrefs *p, gchar *key, int flags) {
- JsonNode *node = trg_prefs_get_value(p, key, flags);
+ JsonNode *node = trg_prefs_get_value(p, key, JSON_NODE_VALUE, flags);
if (node)
return json_node_get_double(node);
else
@@ -228,7 +246,7 @@ gdouble trg_prefs_get_double(TrgPrefs *p, gchar *key, int flags) {
}
gboolean trg_prefs_get_bool(TrgPrefs *p, gchar *key, int flags) {
- JsonNode *node = trg_prefs_get_value(p, key, flags);
+ JsonNode *node = trg_prefs_get_value(p, key, JSON_NODE_VALUE, flags);
if (node)
return json_node_get_boolean(node);
else
@@ -236,14 +254,14 @@ gboolean trg_prefs_get_bool(TrgPrefs *p, gchar *key, int flags) {
}
void trg_prefs_set_int(TrgPrefs *p, gchar *key, int value, int flags) {
- JsonNode *node = trg_prefs_get_value(p, key, flags | TRG_PREFS_NEWNODE);
+ JsonNode *node = trg_prefs_get_value(p, key, JSON_NODE_VALUE, flags | TRG_PREFS_NEWNODE);
json_node_set_int(node, (gint64) value);
trg_prefs_changed_emit_signal(p, key);
}
void trg_prefs_set_string(TrgPrefs *p, gchar *key, const gchar *value,
int flags) {
- JsonNode *node = trg_prefs_get_value(p, key, flags | TRG_PREFS_NEWNODE);
+ JsonNode *node = trg_prefs_get_value(p, key, JSON_NODE_VALUE, flags | TRG_PREFS_NEWNODE);
json_node_set_string(node, value);
trg_prefs_changed_emit_signal(p, key);
}
@@ -307,13 +325,13 @@ JsonArray* trg_prefs_get_profiles(TrgPrefs *p) {
}
void trg_prefs_set_double(TrgPrefs *p, gchar *key, gdouble value, int flags) {
- JsonNode *node = trg_prefs_get_value(p, key, flags | TRG_PREFS_NEWNODE);
+ JsonNode *node = trg_prefs_get_value(p, key, JSON_NODE_VALUE, flags | TRG_PREFS_NEWNODE);
json_node_set_double(node, value);
trg_prefs_changed_emit_signal(p, key);
}
void trg_prefs_set_bool(TrgPrefs *p, gchar *key, gboolean value, int flags) {
- JsonNode *node = trg_prefs_get_value(p, key, flags | TRG_PREFS_NEWNODE);
+ JsonNode *node = trg_prefs_get_value(p, key, JSON_NODE_VALUE, flags | TRG_PREFS_NEWNODE);
json_node_set_boolean(node, value);
trg_prefs_changed_emit_signal(p, key);
}
diff --git a/src/trg-prefs.h b/src/trg-prefs.h
index 7fcfb87..6d89531 100644
--- a/src/trg-prefs.h
+++ b/src/trg-prefs.h
@@ -68,11 +68,13 @@
#define TRG_PREFS_KEY_TV_WIDTHS "widths"
#define TRG_PREFS_KEY_NOTEBOOK_PANED_POS "notebook-paned-pos"
#define TRG_PREFS_KEY_STATES_PANED_POS "states-paned-pos"
+#define TRG_PREFS_KEY_EXEC_COMMANDS "exec-commands"
#define TRG_PREFS_NOFLAGS (1 << 0) /* 0x00 */
#define TRG_PREFS_GLOBAL (1 << 1) /* 0x01 */
#define TRG_PREFS_PROFILE (1 << 2) /* 0x02 */
#define TRG_PREFS_NEWNODE (1 << 3) /* 0x04 */
+#define TRG_PREFS_REPLACENODE (1 << 4) /* 0x08 */
G_BEGIN_DECLS
@@ -111,7 +113,7 @@ void trg_prefs_add_default_string(TrgPrefs *p, gchar *key, gchar *value);
void trg_prefs_add_default_double(TrgPrefs *p, gchar *key, double value);
void trg_prefs_add_default_bool_true(TrgPrefs *p, gchar *key);
-JsonNode *trg_prefs_get_value(TrgPrefs *p, gchar *key, int flags);
+JsonNode *trg_prefs_get_value(TrgPrefs *p, gchar *key, int type, int flags);
gchar *trg_prefs_get_string(TrgPrefs *p, gchar *key, int flags);
gint64 trg_prefs_get_int(TrgPrefs *p, gchar *key, int flags);
gdouble trg_prefs_get_double(TrgPrefs *p, gchar *key, int flags);
@@ -124,6 +126,7 @@ void trg_prefs_set_profile(TrgPrefs *p, JsonObject *profile);
JsonObject *trg_prefs_new_profile(TrgPrefs *p);
JsonObject *trg_get_current_profile(TrgPrefs *p);
JsonObject *trg_prefs_get_root(TrgPrefs *p);
+JsonArray *trg_prefs_get_array(TrgPrefs *p, gchar *key, int flags);
void trg_prefs_set_int(TrgPrefs *p, gchar *key, int value, int flags);
void trg_prefs_set_string(TrgPrefs *p, gchar *key, const gchar *value, int flags);
@@ -132,7 +135,7 @@ void trg_prefs_set_bool(TrgPrefs *p, gchar *key, gboolean value, int flags);
gboolean trg_prefs_save(TrgPrefs *p);
void trg_prefs_load(TrgPrefs *p);
-
+void trg_prefs_changed_emit_signal(TrgPrefs *p, gchar *key);
guint trg_prefs_get_add_flags(TrgPrefs *p);
G_END_DECLS
diff --git a/src/trg-state-selector.c b/src/trg-state-selector.c
index beef747..1fdf2fb 100644
--- a/src/trg-state-selector.c
+++ b/src/trg-state-selector.c
@@ -71,15 +71,11 @@ guint32 trg_state_selector_get_flag(TrgStateSelector * s) {
static void state_selection_changed(GtkTreeSelection * selection, gpointer data) {
TrgStateSelectorPrivate *priv;
GtkTreeIter iter;
- GtkTreeView *tv;
GtkTreeModel *stateModel;
guint index = 0;
priv = TRG_STATE_SELECTOR_GET_PRIVATE(data);
- tv = gtk_tree_selection_get_tree_view(selection);
- stateModel = gtk_tree_view_get_model(tv);
-
if (gtk_tree_selection_get_selected(selection, &stateModel, &iter))
gtk_tree_model_get(stateModel, &iter, STATE_SELECTOR_BIT, &priv->flag,
STATE_SELECTOR_INDEX, &index, -1);
diff --git a/src/util.c b/src/util.c
index a9123c6..ed667be 100644
--- a/src/util.c
+++ b/src/util.c
@@ -53,8 +53,16 @@ void g_str_slist_free(GSList * list)
GRegex *trg_uri_host_regex_new(void)
{
- return g_regex_new("^[^:/?#]+:?//([^/?#:]*)", G_REGEX_OPTIMIZE, 0,
- NULL);
+ return g_regex_new("^[^:/?#]+:?//(?:www\\.|tracker\\.)?([^/?#:]*)",
+ G_REGEX_OPTIMIZE, 0, NULL);
+}
+
+GtkWidget *my_scrolledwin_new(GtkWidget * child) {
+ GtkWidget *scrolled_win = gtk_scrolled_window_new(NULL, NULL);
+ gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scrolled_win),
+ GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
+ gtk_container_add(GTK_CONTAINER(scrolled_win), child);
+ return scrolled_win;
}
gchar *trg_gregex_get_first(GRegex * rx, const gchar * src)
diff --git a/src/util.h b/src/util.h
index 76a9719..9727476 100644
--- a/src/util.h
+++ b/src/util.h
@@ -67,5 +67,6 @@ void rm_trailing_slashes(gchar *str);
void trg_widget_set_visible(GtkWidget * w, gboolean visible);
gdouble json_double_to_progress(JsonNode *n);
gchar *trg_base64encode(const gchar *filename);
+GtkWidget *my_scrolledwin_new(GtkWidget * child);
#endif /* UTIL_H_ */