diff options
author | Alan Fitton <ajf@eth0.org.uk> | 2011-09-29 20:54:42 +0000 |
---|---|---|
committer | Alan Fitton <ajf@eth0.org.uk> | 2011-09-29 20:54:42 +0000 |
commit | 37f5bcc29fb404bb1a87d05230ab71c5f31650dc (patch) | |
tree | 9d45a3f0d1c284e00b17caf976b0423c965b8719 | |
parent | 0a8310af38022a5794c6ec8f0b5a6e745debfdea (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.am | 3 | ||||
-rw-r--r-- | src/trg-main-window.c | 81 | ||||
-rw-r--r-- | src/trg-preferences-dialog.c | 226 | ||||
-rw-r--r-- | src/trg-prefs.c | 66 | ||||
-rw-r--r-- | src/trg-prefs.h | 7 | ||||
-rw-r--r-- | src/trg-state-selector.c | 4 | ||||
-rw-r--r-- | src/util.c | 12 | ||||
-rw-r--r-- | src/util.h | 1 |
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); @@ -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) @@ -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_ */ |