From 37d2c80cfa0bdd8e4af4e2a246c5395bb6681074 Mon Sep 17 00:00:00 2001 From: Alan F Date: Wed, 5 Feb 2014 21:13:12 +0000 Subject: the very first steps of an RSS viewer - bit of autotools integration with rss-glib and an empty window. --- src/Makefile.am | 5 +++-- src/trg-main-window.c | 20 ++++++++++++++++++-- src/trg-menu-bar.c | 17 ++++++++++++++++- 3 files changed, 37 insertions(+), 5 deletions(-) (limited to 'src') diff --git a/src/Makefile.am b/src/Makefile.am index e43e66f..1feb5fb 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -44,7 +44,7 @@ desktop_DATA = transmission-remote-gtk.desktop endif bin_PROGRAMS = transmission-remote-gtk -INCLUDES = -std=c99 -Wall -I.. -Wno-overflow -DTRGLICENSE=\""$(trglicense)"\" $(libcurl_CFLAGS) $(jsonglib_CFLAGS) $(gthread_CFLAGS) $(gtk_CFLAGS) $(gio_CFLAGS) $(notify_CFLAGS) $(libproxy_CFLAGS) $(libappindicator_CFLAGS) +INCLUDES = -std=c99 -Wall -I.. -Wno-overflow -DTRGLICENSE=\""$(trglicense)"\" $(libcurl_CFLAGS) $(jsonglib_CFLAGS) $(gthread_CFLAGS) $(gtk_CFLAGS) $(gio_CFLAGS) $(notify_CFLAGS) $(libproxy_CFLAGS) $(libappindicator_CFLAGS) $(rssglib_CFLAGS) transmission_remote_gtk_SOURCES = \ trg-cell-renderer-speed.c \ @@ -105,9 +105,10 @@ transmission_remote_gtk_SOURCES = \ trg-client.c \ trg-main-window.c \ main.c \ + trg-rss-dialog.c \ $(NULL) -transmission_remote_gtk_LDFLAGS = -lm $(jsonglib_LIBS) $(gtk_LIBS) $(gthread_LIBS) $(GEOIP_LIBS) $(gio_LIBS) $(notify_LIBS) $(libproxy_LIBS) $(libcurl_LIBS) $(libappindicator_LIBS) +transmission_remote_gtk_LDFLAGS = -lm $(jsonglib_LIBS) $(gtk_LIBS) $(gthread_LIBS) $(GEOIP_LIBS) $(gio_LIBS) $(notify_LIBS) $(libproxy_LIBS) $(libcurl_LIBS) $(libappindicator_LIBS) $(rssglib_LIBS) if WIN32 .rc.o: diff --git a/src/trg-main-window.c b/src/trg-main-window.c index 906a384..cc72527 100644 --- a/src/trg-main-window.c +++ b/src/trg-main-window.c @@ -73,6 +73,7 @@ #include "trg-menu-bar.h" #include "trg-status-bar.h" #include "trg-stats-dialog.h" +#include "trg-rss-dialog.h" #include "trg-remote-prefs-dialog.h" #include "trg-preferences-dialog.h" @@ -924,6 +925,19 @@ static void view_stats_toggled_cb(GtkWidget * w, gpointer data) } } +static void view_rss_toggled_cb(GtkWidget * w, gpointer data) +{ + TrgMainWindow *win = TRG_MAIN_WINDOW(data); + TrgMainWindowPrivate *priv = win->priv; + + if (trg_client_is_connected(priv->client)) { + TrgRssDialog *dlg = + trg_rss_dialog_get_instance(TRG_MAIN_WINDOW(data)); + + gtk_widget_show_all(GTK_WIDGET(dlg)); + } +} + static void view_states_toggled_cb(GtkCheckMenuItem * w, TrgMainWindow * win) { @@ -1731,7 +1745,7 @@ static TrgMenuBar *trg_main_window_menu_bar_new(TrgMainWindow * win) GObject *b_disconnect, *b_add, *b_resume, *b_pause, *b_verify, *b_remove, *b_delete, *b_props, *b_local_prefs, *b_remote_prefs, - *b_about, *b_view_states, *b_view_notebook, *b_view_stats, + *b_about, *b_view_states, *b_view_notebook, *b_view_stats, *b_view_rss, *b_add_url, *b_quit, *b_move, *b_reannounce, *b_pause_all, *b_resume_all, *b_dir_filters, *b_tracker_filters, *b_up_queue, *b_down_queue, *b_top_queue, *b_bottom_queue, @@ -1762,7 +1776,7 @@ static TrgMenuBar *trg_main_window_menu_bar_new(TrgMainWindow * win) "view-states-button", &b_view_states, "view-stats-button", &b_view_stats, "about-button", &b_about, "quit-button", &b_quit, "dir-filters", &b_dir_filters, "tracker-filters", - &b_tracker_filters, + &b_tracker_filters, "view-rss-button", &b_view_rss, #if TRG_WITH_GRAPH "show-graph", &b_show_graph, #endif @@ -1810,6 +1824,8 @@ static TrgMenuBar *trg_main_window_menu_bar_new(TrgMainWindow * win) G_CALLBACK(view_states_toggled_cb), win); g_signal_connect(b_view_stats, "activate", G_CALLBACK(view_stats_toggled_cb), win); + g_signal_connect(b_view_rss, "activate", + G_CALLBACK(view_rss_toggled_cb), win); #if TRG_WITH_GRAPH g_signal_connect(b_show_graph, "toggled", G_CALLBACK(trg_main_window_toggle_graph_cb), win); diff --git a/src/trg-menu-bar.c b/src/trg-menu-bar.c index df96240..f6ca4c5 100644 --- a/src/trg-menu-bar.c +++ b/src/trg-menu-bar.c @@ -49,6 +49,7 @@ enum { PROP_LOCAL_PREFS_BUTTON, PROP_ABOUT_BUTTON, PROP_VIEW_STATS_BUTTON, + PROP_VIEW_RSS_BUTTON, PROP_VIEW_STATES_BUTTON, PROP_VIEW_NOTEBOOK_BUTTON, PROP_QUIT, @@ -96,6 +97,7 @@ struct _TrgMenuBarPrivate { GtkWidget *mb_view_states; GtkWidget *mb_view_notebook; GtkWidget *mb_view_stats; + GtkWidget *mb_view_rss; GtkWidget *mb_about; GtkWidget *mb_quit; GtkWidget *mb_directory_filters; @@ -140,6 +142,7 @@ void trg_menu_bar_connected_change(TrgMenuBar * mb, gboolean connected) gtk_widget_set_sensitive(priv->mb_disconnect, connected); gtk_widget_set_sensitive(priv->mb_remote_prefs, connected); gtk_widget_set_sensitive(priv->mb_view_stats, connected); + gtk_widget_set_sensitive(priv->mb_view_rss, connected); gtk_widget_set_sensitive(priv->mb_resume_all, connected); gtk_widget_set_sensitive(priv->mb_pause_all, connected); } @@ -273,6 +276,9 @@ trg_menu_bar_get_property(GObject * object, guint property_id, case PROP_VIEW_STATS_BUTTON: g_value_set_object(value, priv->mb_view_stats); break; + case PROP_VIEW_RSS_BUTTON: + g_value_set_object(value, priv->mb_view_rss); + break; case PROP_QUIT: g_value_set_object(value, priv->mb_quit); break; @@ -542,6 +548,12 @@ static GtkWidget *trg_menu_bar_view_menu_new(TrgMenuBar * mb) gtk_widget_set_sensitive(priv->mb_view_stats, FALSE); gtk_menu_shell_append(GTK_MENU_SHELL(viewMenu), priv->mb_view_stats); + priv->mb_view_rss = + gtk_menu_item_new_with_mnemonic(_("_RSS")); + //trg_menu_bar_accel_add(mb, priv->mb_view_rss, GDK_F7, 0); + gtk_widget_set_sensitive(priv->mb_view_rss, FALSE); + gtk_menu_shell_append(GTK_MENU_SHELL(viewMenu), priv->mb_view_rss); + return view; } @@ -578,7 +590,7 @@ trg_menu_bar_file_connect_item_new(TrgMainWindow * win, { GtkWidget *item = gtk_check_menu_item_new_with_label(text); - gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(item), checked); + gtk_check_menu_item_set_active( GTK_CHECK_MENU_ITEM(item), checked); g_object_set_data(G_OBJECT(item), "profile", profile); gtk_check_menu_item_set_draw_as_radio(GTK_CHECK_MENU_ITEM(item), TRUE); @@ -870,6 +882,9 @@ static void trg_menu_bar_class_init(TrgMenuBarClass * klass) trg_menu_bar_install_widget_prop(object_class, PROP_VIEW_STATS_BUTTON, "view-stats-button", "View stats button"); + trg_menu_bar_install_widget_prop(object_class, PROP_VIEW_RSS_BUTTON, + "view-rss-button", + "View rss button"); trg_menu_bar_install_widget_prop(object_class, PROP_VIEW_STATES_BUTTON, "view-states-button", "View states Button"); -- cgit v1.2.3 From 9c83dab456ebeeb2bebd9ceae7e0cc53133b1cd5 Mon Sep 17 00:00:00 2001 From: Alan F Date: Sun, 9 Feb 2014 11:49:18 +0000 Subject: refactor the TrgClient, so the thread pool and CURL clients are available for making general HTTP GET, so don't send our username, password, and session. --- src/trg-client.c | 177 ++++++++++++++++++++++++++++++++++++------------------- src/trg-client.h | 7 +++ 2 files changed, 122 insertions(+), 62 deletions(-) (limited to 'src') diff --git a/src/trg-client.c b/src/trg-client.c index 1ffde9b..3ce5637 100644 --- a/src/trg-client.c +++ b/src/trg-client.c @@ -82,6 +82,7 @@ struct _TrgClientPrivate { TrgPrefs *prefs; GPrivate *tlsKey; gint configSerial; + guint http_class; GMutex *configMutex; gboolean seedRatioLimited; gdouble seedRatioLimit; @@ -443,6 +444,8 @@ void trg_response_free(trg_response * response) { if (response->obj) json_object_unref(response->obj); + if (response->raw) + g_free(response->raw); g_free(response); } @@ -483,61 +486,20 @@ header_callback(void *ptr, size_t size, size_t nmemb, void *data) return (nmemb * size); } -static void trg_tls_update(TrgClient * tc, trg_tls * tls, gint serial) -{ - gchar *proxy; - - curl_easy_setopt(tls->curl, CURLOPT_PASSWORD, - trg_client_get_password(tc)); - curl_easy_setopt(tls->curl, CURLOPT_USERNAME, - trg_client_get_username(tc)); - curl_easy_setopt(tls->curl, CURLOPT_URL, trg_client_get_url(tc)); - -#ifndef CURL_NO_SSL - if (trg_client_get_ssl(tc) && !trg_client_get_ssl_validate(tc)) { - - curl_easy_setopt(tls->curl, CURLOPT_SSL_VERIFYHOST, 0); - curl_easy_setopt(tls->curl, CURLOPT_SSL_VERIFYPEER, 0); - } -#endif - - proxy = trg_client_get_proxy(tc); - if (proxy) { - curl_easy_setopt(tls->curl, CURLOPT_PROXYTYPE, CURLPROXY_HTTP); - curl_easy_setopt(tls->curl, CURLOPT_PROXY, proxy); - } - - tls->serial = serial; -} - trg_tls *trg_tls_new(TrgClient * tc) { trg_tls *tls = g_new0(trg_tls, 1); tls->curl = curl_easy_init(); - curl_easy_setopt(tls->curl, CURLOPT_USERAGENT, PACKAGE_NAME); - curl_easy_setopt(tls->curl, CURLOPT_HTTPAUTH, CURLAUTH_BASIC); - curl_easy_setopt(tls->curl, CURLOPT_WRITEFUNCTION, - &http_receive_callback); - curl_easy_setopt(tls->curl, CURLOPT_HEADERFUNCTION, &header_callback); - curl_easy_setopt(tls->curl, CURLOPT_WRITEHEADER, (void *) tc); - tls->serial = -1; return tls; } -static int -trg_http_perform_inner(TrgClient * tc, gchar * reqstr, - trg_response * response, gboolean recurse) -{ - TrgClientPrivate *priv = tc->priv; - TrgPrefs *prefs = trg_client_get_prefs(tc); - gpointer threadLocalStorage = g_private_get(priv->tlsKey); - trg_tls *tls; - long httpCode = 0; - gchar *session_id; - struct curl_slist *headers = NULL; +static trg_tls *get_tls(TrgClient *tc) { + TrgClientPrivate *priv = tc->priv; + gpointer threadLocalStorage = g_private_get(priv->tlsKey); + trg_tls *tls; if (!threadLocalStorage) { tls = trg_tls_new(tc); @@ -546,36 +508,95 @@ trg_http_perform_inner(TrgClient * tc, gchar * reqstr, tls = (trg_tls *) threadLocalStorage; } + return tls; +} + +static CURL* get_curl(TrgClient *tc, guint http_class) +{ + TrgClientPrivate *priv = tc->priv; + TrgPrefs *prefs = trg_client_get_prefs(tc); + trg_tls *tls = get_tls(tc); + CURL *curl = tls->curl; + struct curl_slist *headers = NULL; + gchar *session_id = NULL; + g_mutex_lock(priv->configMutex); - if (priv->configSerial > tls->serial) - trg_tls_update(tc, tls, priv->configSerial); + if (priv->configSerial > tls->serial || http_class != priv->http_class) { + gchar *proxy; - session_id = trg_client_get_session_id(tc); - if (session_id) { - headers = curl_slist_append(NULL, session_id); - curl_easy_setopt(tls->curl, CURLOPT_HTTPHEADER, headers); + curl_easy_reset(curl); + + curl_easy_setopt(curl, CURLOPT_USERAGENT, PACKAGE_NAME); + curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, + &http_receive_callback); + + if (http_class == HTTP_CLASS_TRANSMISSION) { + curl_easy_setopt(curl, CURLOPT_WRITEHEADER, (void *) tc); + curl_easy_setopt(curl, CURLOPT_HTTPAUTH, CURLAUTH_BASIC); + curl_easy_setopt(curl, CURLOPT_HEADERFUNCTION, &header_callback); + curl_easy_setopt(curl, CURLOPT_PASSWORD, + trg_client_get_password(tc)); + curl_easy_setopt(curl, CURLOPT_USERNAME, + trg_client_get_username(tc)); + curl_easy_setopt(curl, CURLOPT_URL, trg_client_get_url(tc)); + } + + #ifndef CURL_NO_SSL + if (trg_client_get_ssl(tc) && !trg_client_get_ssl_validate(tc)) { + + curl_easy_setopt(curl, CURLOPT_SSL_VERIFYHOST, 0); + curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, 0); + } + #endif + + proxy = trg_client_get_proxy(tc); + if (proxy) { + curl_easy_setopt(curl, CURLOPT_PROXYTYPE, CURLPROXY_HTTP); + curl_easy_setopt(curl, CURLOPT_PROXY, proxy); + } + + tls->serial = priv->configSerial; + priv->http_class = http_class; + } + + if (http_class == HTTP_CLASS_TRANSMISSION) { + session_id = trg_client_get_session_id(tc); + if (session_id) { + headers = curl_slist_append(NULL, session_id); + curl_easy_setopt(curl, CURLOPT_HTTPHEADER, headers); + } + + curl_easy_setopt(curl, CURLOPT_URL, trg_client_get_url(tc)); } - curl_easy_setopt(tls->curl, CURLOPT_TIMEOUT, - (long) trg_prefs_get_int(prefs, TRG_PREFS_KEY_TIMEOUT, - TRG_PREFS_CONNECTION)); + curl_easy_setopt(curl, CURLOPT_TIMEOUT, + (long) trg_prefs_get_int(prefs, TRG_PREFS_KEY_TIMEOUT, + TRG_PREFS_CONNECTION)); g_mutex_unlock(priv->configMutex); + return curl; + +} + +static int +trg_http_perform_inner(TrgClient * tc, gchar * reqstr, + trg_response * response, gboolean recurse) +{ + CURL* curl = get_curl(tc, HTTP_CLASS_TRANSMISSION); + + long httpCode = 0; + response->size = 0; response->raw = NULL; - curl_easy_setopt(tls->curl, CURLOPT_POSTFIELDS, reqstr); - curl_easy_setopt(tls->curl, CURLOPT_WRITEDATA, (void *) response); - response->status = curl_easy_perform(tls->curl); + curl_easy_setopt(curl, CURLOPT_POSTFIELDS, reqstr); + curl_easy_setopt(curl, CURLOPT_WRITEDATA, (void *) response); - if (session_id) { - g_free(session_id); - curl_slist_free_all(headers); - } + response->status = curl_easy_perform(curl); - curl_easy_getinfo(tls->curl, CURLINFO_RESPONSE_CODE, &httpCode); + curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, &httpCode); if (response->status == CURLE_OK) { if (httpCode == HTTP_CONFLICT && recurse == TRUE) @@ -605,6 +626,29 @@ trg_response *dispatch(TrgClient * tc, JsonNode * req) return dispatch_str(tc, serialized); } +trg_response *dispatch_public_http(TrgClient *tc, const gchar *url) { + trg_response *response = g_new0(trg_response, 1); + + CURL* curl = get_curl(tc, HTTP_CLASS_PUBLIC); + + long httpCode = 0; + + response->size = 0; + response->raw = NULL; + + curl_easy_setopt(curl, CURLOPT_URL, url); + + response->status = curl_easy_perform(curl); + + curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, &httpCode); + + if (response->status == CURLE_OK && httpCode != HTTP_OK) { + response->status = (-httpCode) - 100; + } + + return response; +} + trg_response *dispatch_str(TrgClient * tc, gchar * req) { trg_response *response = g_new0(trg_response, 1); @@ -645,6 +689,8 @@ static void dispatch_async_threadfunc(trg_request * req, TrgClient * tc) if (req->str) rsp = dispatch_str(tc, req->str); + else if (req->url) + rsp = dispatch_public_http(tc, req->url); else rsp = dispatch(tc, req->node); @@ -701,6 +747,13 @@ dispatch_async_str(TrgClient * tc, gchar * req, return dispatch_async_common(tc, trg_req, callback, data); } +gboolean async_http_request(TrgClient *tc, gchar *url, GSourceFunc callback, gpointer data) { + trg_request *trg_req = g_new0(trg_request, 1); + trg_req->url = url; + + return dispatch_async_common(tc, trg_req, callback, data); +} + gboolean trg_client_update_session(TrgClient * tc, GSourceFunc callback, gpointer data) { diff --git a/src/trg-client.h b/src/trg-client.h index a0bee33..21833fc 100644 --- a/src/trg-client.h +++ b/src/trg-client.h @@ -57,6 +57,9 @@ #define FAIL_RESPONSE_UNSUCCESSFUL -3 #define DISPATCH_POOL_SIZE 3 +#define HTTP_CLASS_TRANSMISSION 0 +#define HTTP_CLASS_PUBLIC 1 + typedef struct { int status; int size; @@ -69,6 +72,7 @@ typedef struct { gint connid; JsonNode *node; gchar *str; + gchar *url; GSourceFunc callback; gpointer cb_data; } trg_request; @@ -109,6 +113,7 @@ typedef struct { * We lock updating (and checking for updates) with priv->configMutex */ int serial; + guint client_class; CURL *curl; } trg_tls; @@ -123,6 +128,8 @@ trg_response *dispatch(TrgClient * client, JsonNode * req); trg_response *dispatch_str(TrgClient * client, gchar * req); gboolean dispatch_async(TrgClient * client, JsonNode * req, GSourceFunc callback, gpointer data); +gboolean async_http_request(TrgClient *tc, gchar *url, GSourceFunc callback, gpointer data); + /* end dispatch.c*/ GType trg_client_get_type(void); -- cgit v1.2.3 From adf06453574270bf467b5f37e632c04c153ee90a Mon Sep 17 00:00:00 2001 From: Alan F Date: Mon, 10 Feb 2014 18:53:52 +0000 Subject: RSS viewer now gets feed URLS from the config JSON, and displays the item titles in a treeview. --- src/Makefile.am | 3 +- src/trg-client.c | 34 +++++--- src/trg-client.h | 1 + src/trg-main-window.c | 8 +- src/trg-prefs.c | 6 ++ src/trg-prefs.h | 2 + src/trg-rss-model.c | 215 ++++++++++++++++++++++++++++++++++++++++++++++++++ src/trg-rss-model.h | 63 +++++++++++++++ src/trg-rss-window.c | 212 +++++++++++++++++++++++++++++++++++++++++++++++++ src/trg-rss-window.h | 53 +++++++++++++ 10 files changed, 580 insertions(+), 17 deletions(-) create mode 100644 src/trg-rss-model.c create mode 100644 src/trg-rss-model.h create mode 100644 src/trg-rss-window.c create mode 100644 src/trg-rss-window.h (limited to 'src') diff --git a/src/Makefile.am b/src/Makefile.am index 1feb5fb..f82a7f5 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -105,7 +105,8 @@ transmission_remote_gtk_SOURCES = \ trg-client.c \ trg-main-window.c \ main.c \ - trg-rss-dialog.c \ + trg-rss-window.c \ + trg-rss-model.c \ $(NULL) transmission_remote_gtk_LDFLAGS = -lm $(jsonglib_LIBS) $(gtk_LIBS) $(gthread_LIBS) $(GEOIP_LIBS) $(gio_LIBS) $(notify_LIBS) $(libproxy_LIBS) $(libcurl_LIBS) $(libappindicator_LIBS) $(rssglib_LIBS) diff --git a/src/trg-client.c b/src/trg-client.c index 3ce5637..6f33b36 100644 --- a/src/trg-client.c +++ b/src/trg-client.c @@ -517,8 +517,6 @@ static CURL* get_curl(TrgClient *tc, guint http_class) TrgPrefs *prefs = trg_client_get_prefs(tc); trg_tls *tls = get_tls(tc); CURL *curl = tls->curl; - struct curl_slist *headers = NULL; - gchar *session_id = NULL; g_mutex_lock(priv->configMutex); @@ -530,6 +528,7 @@ static CURL* get_curl(TrgClient *tc, guint http_class) curl_easy_setopt(curl, CURLOPT_USERAGENT, PACKAGE_NAME); curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, &http_receive_callback); + //curl_easy_setopt(curl, CURLOPT_VERBOSE, 1); if (http_class == HTTP_CLASS_TRANSMISSION) { curl_easy_setopt(curl, CURLOPT_WRITEHEADER, (void *) tc); @@ -561,12 +560,6 @@ static CURL* get_curl(TrgClient *tc, guint http_class) } if (http_class == HTTP_CLASS_TRANSMISSION) { - session_id = trg_client_get_session_id(tc); - if (session_id) { - headers = curl_slist_append(NULL, session_id); - curl_easy_setopt(curl, CURLOPT_HTTPHEADER, headers); - } - curl_easy_setopt(curl, CURLOPT_URL, trg_client_get_url(tc)); } @@ -586,6 +579,8 @@ trg_http_perform_inner(TrgClient * tc, gchar * reqstr, { CURL* curl = get_curl(tc, HTTP_CLASS_TRANSMISSION); + struct curl_slist *headers = NULL; + gchar *session_id = NULL; long httpCode = 0; response->size = 0; @@ -594,10 +589,21 @@ trg_http_perform_inner(TrgClient * tc, gchar * reqstr, curl_easy_setopt(curl, CURLOPT_POSTFIELDS, reqstr); curl_easy_setopt(curl, CURLOPT_WRITEDATA, (void *) response); + session_id = trg_client_get_session_id(tc); + if (session_id) { + headers = curl_slist_append(NULL, session_id); + curl_easy_setopt(curl, CURLOPT_HTTPHEADER, headers); + } + response->status = curl_easy_perform(curl); curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, &httpCode); + if (session_id) { + g_free(session_id); + curl_slist_free_all(headers); + } + if (response->status == CURLE_OK) { if (httpCode == HTTP_CONFLICT && recurse == TRUE) return trg_http_perform_inner(tc, reqstr, response, FALSE); @@ -626,7 +632,7 @@ trg_response *dispatch(TrgClient * tc, JsonNode * req) return dispatch_str(tc, serialized); } -trg_response *dispatch_public_http(TrgClient *tc, const gchar *url) { +trg_response *dispatch_public_http(TrgClient *tc, trg_request *req) { trg_response *response = g_new0(trg_response, 1); CURL* curl = get_curl(tc, HTTP_CLASS_PUBLIC); @@ -636,10 +642,14 @@ trg_response *dispatch_public_http(TrgClient *tc, const gchar *url) { response->size = 0; response->raw = NULL; - curl_easy_setopt(curl, CURLOPT_URL, url); + curl_easy_setopt(curl, CURLOPT_URL, req->url); + curl_easy_setopt(curl, CURLOPT_WRITEDATA, (void *) response); response->status = curl_easy_perform(curl); + g_free(req->url); + req->url = NULL; + curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, &httpCode); if (response->status == CURLE_OK && httpCode != HTTP_OK) { @@ -690,7 +700,7 @@ static void dispatch_async_threadfunc(trg_request * req, TrgClient * tc) if (req->str) rsp = dispatch_str(tc, req->str); else if (req->url) - rsp = dispatch_public_http(tc, req->url); + rsp = dispatch_public_http(tc, req); else rsp = dispatch(tc, req->node); @@ -749,7 +759,7 @@ dispatch_async_str(TrgClient * tc, gchar * req, gboolean async_http_request(TrgClient *tc, gchar *url, GSourceFunc callback, gpointer data) { trg_request *trg_req = g_new0(trg_request, 1); - trg_req->url = url; + trg_req->url = g_strdup(url); return dispatch_async_common(tc, trg_req, callback, data); } diff --git a/src/trg-client.h b/src/trg-client.h index 21833fc..ce98a4e 100644 --- a/src/trg-client.h +++ b/src/trg-client.h @@ -126,6 +126,7 @@ int trg_http_perform(TrgClient * client, gchar * reqstr, /* stuff that used to be in dispatch.c */ trg_response *dispatch(TrgClient * client, JsonNode * req); trg_response *dispatch_str(TrgClient * client, gchar * req); +trg_response *dispatch_public_http(TrgClient *tc, trg_request *req); gboolean dispatch_async(TrgClient * client, JsonNode * req, GSourceFunc callback, gpointer data); gboolean async_http_request(TrgClient *tc, gchar *url, GSourceFunc callback, gpointer data); diff --git a/src/trg-main-window.c b/src/trg-main-window.c index cc72527..f4e479c 100644 --- a/src/trg-main-window.c +++ b/src/trg-main-window.c @@ -73,7 +73,7 @@ #include "trg-menu-bar.h" #include "trg-status-bar.h" #include "trg-stats-dialog.h" -#include "trg-rss-dialog.h" +#include "trg-rss-window.h" #include "trg-remote-prefs-dialog.h" #include "trg-preferences-dialog.h" @@ -931,10 +931,10 @@ static void view_rss_toggled_cb(GtkWidget * w, gpointer data) TrgMainWindowPrivate *priv = win->priv; if (trg_client_is_connected(priv->client)) { - TrgRssDialog *dlg = - trg_rss_dialog_get_instance(TRG_MAIN_WINDOW(data)); + TrgRssWindow *rss = + trg_rss_window_get_instance(TRG_MAIN_WINDOW(data), priv->client); - gtk_widget_show_all(GTK_WIDGET(dlg)); + gtk_widget_show_all(GTK_WIDGET(rss)); } } diff --git a/src/trg-prefs.c b/src/trg-prefs.c index b559479..811c575 100644 --- a/src/trg-prefs.c +++ b/src/trg-prefs.c @@ -421,6 +421,12 @@ JsonArray *trg_prefs_get_profiles(TrgPrefs * p) TRG_PREFS_KEY_PROFILES); } +JsonArray *trg_prefs_get_rss(TrgPrefs *p) { + TrgPrefsPrivate *priv = p->priv; + return json_object_get_array_member(priv->userObj, + TRG_PREFS_KEY_RSS); +} + void trg_prefs_set_double(TrgPrefs * p, const gchar * key, gdouble value, int flags) diff --git a/src/trg-prefs.h b/src/trg-prefs.h index 9dda148..d8afe8f 100644 --- a/src/trg-prefs.h +++ b/src/trg-prefs.h @@ -33,6 +33,7 @@ #define TRG_PREFS_KEY_RPC_URL_PATH "rpc-url-path" #define TRG_PREFS_KEY_PROFILE_ID "profile-id" #define TRG_PREFS_KEY_PROFILES "profiles" +#define TRG_PREFS_KEY_RSS "rss" #define TRG_PREFS_KEY_PROFILE_NAME "profile-name" #define TRG_PREFS_KEY_HOSTNAME "hostname" #define TRG_PREFS_KEY_PORT "port" @@ -139,6 +140,7 @@ gboolean trg_prefs_get_bool(TrgPrefs * p, const gchar * key, int flags); JsonObject *trg_prefs_get_profile(TrgPrefs * p); JsonObject *trg_prefs_get_connection(TrgPrefs * p); JsonArray *trg_prefs_get_profiles(TrgPrefs * p); +JsonArray *trg_prefs_get_rss(TrgPrefs *p); void trg_prefs_set_connection(TrgPrefs * p, JsonObject * profile); gint trg_prefs_get_profile_id(TrgPrefs * p); void trg_prefs_del_profile(TrgPrefs * p, JsonObject * profile); diff --git a/src/trg-rss-model.c b/src/trg-rss-model.c new file mode 100644 index 0000000..bc43ef7 --- /dev/null +++ b/src/trg-rss-model.c @@ -0,0 +1,215 @@ +/* + * transmission-remote-gtk - A GTK RPC client to Transmission + * Copyright (C) 2011-2013 Alan Fitton + + * 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 +#include +#include + +#include "config.h" +#include "torrent.h" +#include "trg-client.h" +#include "trg-model.h" +#include "trg-rss-model.h" + +enum { + PROP_0, PROP_CLIENT +}; + +G_DEFINE_TYPE(TrgRssModel, trg_rss_model, GTK_TYPE_LIST_STORE) +#define TRG_RSS_MODEL_GET_PRIVATE(o) \ + (G_TYPE_INSTANCE_GET_PRIVATE ((o), TRG_TYPE_RSS_MODEL, TrgRssModelPrivate)) +typedef struct _TrgRssModelPrivate TrgRssModelPrivate; + +struct _TrgRssModelPrivate { + TrgClient *client; + GHashTable *table; +}; + +typedef struct { + TrgRssModel *model; + gchar *feed_id; + gchar *feed_url; + gint status; + RssParser *parser; + gboolean success; + GError *error; +} feed_update; + +static void feed_update_free(feed_update *update) { + if (update->error) + g_error_free(update->error); + + g_free(update->feed_id); + g_free(update->feed_url); + + if (update->parser) + g_object_unref(update->parser); + + g_free(update); +} + +static gboolean on_rss_receive_idle(gpointer data) { + feed_update *update = (feed_update*) data; + TrgRssModel *model = update->model; + TrgRssModelPrivate *priv = TRG_RSS_MODEL_GET_PRIVATE(model); + + if (update->success) { + RssDocument *doc = rss_parser_get_document(update->parser); + GtkTreeIter iter; + GList *list, *tmp; + gchar *title; + + list = rss_document_get_items(doc); + + for (tmp = list; tmp != NULL; tmp = tmp->next) { + RssItem *item = (RssItem*) tmp->data; + const gchar *guid = rss_item_get_guid(item); + if (g_hash_table_lookup(priv->table, guid) != (void*) 1) { + gtk_list_store_append(GTK_LIST_STORE(model), &iter); + gtk_list_store_set(GTK_LIST_STORE(model), &iter, RSSCOL_ID, + guid, RSSCOL_TITLE, rss_item_get_title(item), + RSSCOL_LINK, rss_item_get_link(item), -1); + g_hash_table_insert(priv->table, g_strdup(guid), (void*) 1); + } + } + + g_list_free(list); + g_object_unref(doc); + } + + feed_update_free(update); + + return FALSE; +} + +static gboolean on_rss_receive(gpointer data) { + trg_response *response = (trg_response *) data; + feed_update *update = (feed_update*) response->cb_data; + + update->status = response->status; + + if (response->status == CURLE_OK) { + update->parser = rss_parser_new(); + update->success = rss_parser_load_from_data(update->parser, + response->raw, response->size, &(update->error)); + } + + g_idle_add(on_rss_receive_idle, update); + + trg_response_free(response); + + return FALSE; +} + +void trg_rss_model_update(TrgRssModel * model) { + TrgRssModelPrivate *priv = TRG_RSS_MODEL_GET_PRIVATE(model); + TrgPrefs *prefs = trg_client_get_prefs(priv->client); + JsonArray *feeds = trg_prefs_get_rss(prefs); + GList *li; + + if (!feeds) + return; + + for (li = json_array_get_elements(feeds); li != NULL; li = g_list_next(li)) { + JsonObject *feed = json_node_get_object((JsonNode *) li->data); + const gchar *url = json_object_get_string_member(feed, "url"); + const gchar *id = json_object_get_string_member(feed, "id"); + + if (!url || !id) + continue; + + feed_update *update = g_new0(feed_update, 1); + update->feed_url = g_strdup(url); + update->feed_id = g_strdup(id); + update->model = model; + + async_http_request(priv->client, update->feed_url, on_rss_receive, + update); + } + + /*trg_model_remove_removed(GTK_LIST_STORE(model), + RSSCOL_UPDATESERIAL, updateSerial);*/ +} + +static void trg_rss_model_set_property(GObject * object, guint prop_id, + const GValue * value, GParamSpec * pspec G_GNUC_UNUSED) { + TrgRssModelPrivate *priv = TRG_RSS_MODEL_GET_PRIVATE(object); + + switch (prop_id) { + case PROP_CLIENT: + priv->client = g_value_get_pointer(value); + break; + } +} + +static void trg_rss_model_get_property(GObject * object, guint prop_id, + GValue * value, GParamSpec * pspec G_GNUC_UNUSED) { +} + +static GObject *trg_rss_model_constructor(GType type, + guint n_construct_properties, GObjectConstructParam * construct_params) { + GObject *obj = G_OBJECT_CLASS + (trg_rss_model_parent_class)->constructor(type, + n_construct_properties, construct_params); + TrgRssModelPrivate *priv = TRG_RSS_MODEL_GET_PRIVATE(obj); + + priv->table = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, NULL); + + return obj; +} + +static void trg_rss_model_dispose(GObject * object) +{ + TrgRssModelPrivate *priv = TRG_RSS_MODEL_GET_PRIVATE(object); + g_hash_table_destroy(priv->table); + G_OBJECT_CLASS(trg_rss_model_parent_class)->dispose(object); +} + +static void trg_rss_model_class_init(TrgRssModelClass * klass) { + GObjectClass *object_class = G_OBJECT_CLASS(klass); + + g_type_class_add_private(klass, sizeof(TrgRssModelPrivate)); + + object_class->set_property = trg_rss_model_set_property; + object_class->get_property = trg_rss_model_get_property; + object_class->constructor = trg_rss_model_constructor; + object_class->dispose = trg_rss_model_dispose; + + g_object_class_install_property(object_class, PROP_CLIENT, + g_param_spec_pointer("client", "client", "client", + G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY + | G_PARAM_STATIC_NAME | G_PARAM_STATIC_NICK + | G_PARAM_STATIC_BLURB)); +} + +static void trg_rss_model_init(TrgRssModel * self) { + //TrgRssModelPrivate *priv = TRG_RSS_MODEL_GET_PRIVATE(self); + GType column_types[RSSCOL_COLUMNS]; + + column_types[RSSCOL_ID] = G_TYPE_STRING; + column_types[RSSCOL_TITLE] = G_TYPE_STRING; + column_types[RSSCOL_LINK] = G_TYPE_STRING; + + gtk_list_store_set_column_types(GTK_LIST_STORE(self), RSSCOL_COLUMNS, + column_types); +} + +TrgRssModel *trg_rss_model_new(TrgClient *client) { + return g_object_new(TRG_TYPE_RSS_MODEL, "client", client, NULL); +} diff --git a/src/trg-rss-model.h b/src/trg-rss-model.h new file mode 100644 index 0000000..9befa48 --- /dev/null +++ b/src/trg-rss-model.h @@ -0,0 +1,63 @@ +/* + * transmission-remote-gtk - A GTK RPC client to Transmission + * Copyright (C) 2011-2013 Alan Fitton + + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#ifndef TRG_RSS_MODEL_H_ +#define TRG_RSS_MODEL_H_ + +#include +#include + +#include "trg-client.h" +#include "trg-model.h" + +G_BEGIN_DECLS +#define TRG_TYPE_RSS_MODEL trg_rss_model_get_type() +#define TRG_RSS_MODEL(obj) \ + (G_TYPE_CHECK_INSTANCE_CAST ((obj), TRG_TYPE_RSS_MODEL, TrgRssModel)) +#define TRG_RSS_MODEL_CLASS(klass) \ + (G_TYPE_CHECK_CLASS_CAST ((klass), TRG_TYPE_RSS_MODEL, TrgRssModelClass)) +#define TRG_IS_RSS_MODEL(obj) \ + (G_TYPE_CHECK_INSTANCE_TYPE ((obj), TRG_TYPE_RSS_MODEL)) +#define TRG_IS_RSS_MODEL_CLASS(klass) \ + (G_TYPE_CHECK_CLASS_TYPE ((klass), TRG_TYPE_RSS_MODEL)) +#define TRG_RSS_MODEL_GET_CLASS(obj) \ + (G_TYPE_INSTANCE_GET_CLASS ((obj), TRG_TYPE_RSS_MODEL, TrgRssModelClass)) + typedef struct { + GtkListStore parent; +} TrgRssModel; + +typedef struct { + GtkListStoreClass parent_class; +} TrgRssModelClass; + +GType trg_rss_model_get_type(void); + +TrgRssModel *trg_rss_model_new(TrgClient *client); + +G_END_DECLS +void trg_rss_model_update(TrgRssModel * model); + +enum { + RSSCOL_ID, + RSSCOL_TITLE, + RSSCOL_LINK, + RSSCOL_COLUMNS +}; + +#endif /* TRG_RSS_MODEL_H_ */ diff --git a/src/trg-rss-window.c b/src/trg-rss-window.c new file mode 100644 index 0000000..52a096f --- /dev/null +++ b/src/trg-rss-window.c @@ -0,0 +1,212 @@ +/* + * transmission-remote-gtk - A GTK RPC client to Transmission + * Copyright (C) 2011-2013 Alan Fitton + + * 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 +#include +#include + +#include "trg-rss-window.h" +#include "trg-rss-model.h" +#include "trg-client.h" +#include "util.h" + +G_DEFINE_TYPE(TrgRssWindow, trg_rss_window, + GTK_TYPE_WINDOW) +#define TRG_RSS_WINDOW_GET_PRIVATE(o) \ +(G_TYPE_INSTANCE_GET_PRIVATE ((o), TRG_TYPE_RSS_WINDOW, TrgRssWindowPrivate)) +enum { + PROP_0, PROP_PARENT, PROP_CLIENT +}; + +typedef struct _TrgRssWindowPrivate TrgRssWindowPrivate; + +struct _TrgRssWindowPrivate { + TrgMainWindow *parent; + TrgClient *client; +}; + +static GObject *instance = NULL; + +static void +trg_rss_window_get_property(GObject * object, + guint property_id, + GValue * value, GParamSpec * pspec) +{ + TrgRssWindowPrivate *priv = + TRG_RSS_WINDOW_GET_PRIVATE(object); + switch (property_id) { + case PROP_CLIENT: + g_value_set_pointer(value, priv->client); + break; + case PROP_PARENT: + g_value_set_object(value, priv->parent); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID(object, property_id, pspec); + break; + } +} + +static void +trg_rss_window_set_property(GObject * object, + guint property_id, + const GValue * value, + GParamSpec * pspec) +{ + TrgRssWindowPrivate *priv = + TRG_RSS_WINDOW_GET_PRIVATE(object); + switch (property_id) { + case PROP_PARENT: + priv->parent = g_value_get_object(value); + break; + case PROP_CLIENT: + priv->client = g_value_get_pointer(value); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID(object, property_id, pspec); + break; + } +} + +static void +trg_rss_window_response_cb(GtkDialog * dlg, gint res_id, + gpointer data G_GNUC_UNUSED) +{ + TrgRssWindowPrivate *priv = + TRG_RSS_WINDOW_GET_PRIVATE(dlg); + + gtk_widget_destroy(GTK_WIDGET(dlg)); + instance = NULL; +} + +static GObject *trg_rss_window_constructor(GType type, + guint + n_construct_properties, + GObjectConstructParam * + construct_params) +{ + GObject *object; + TrgRssWindowPrivate *priv; + TrgRssModel *model; + GtkTreeView *view; + GtkWidget *vbox, *toolbar, *contentbox; + GtkToolItem *item; + + object = G_OBJECT_CLASS + (trg_rss_window_parent_class)->constructor(type, + n_construct_properties, + construct_params); + priv = TRG_RSS_WINDOW_GET_PRIVATE(object); + + model = trg_rss_model_new(priv->client); + trg_rss_model_update(model); + + view = GTK_TREE_VIEW(gtk_tree_view_new()); + gtk_tree_view_set_model(view, GTK_TREE_MODEL(model)); + gtk_tree_view_insert_column_with_attributes(view, -1, "Title", gtk_cell_renderer_text_new(), "text", RSSCOL_TITLE, NULL); + + gtk_window_set_title(GTK_WINDOW(object), _("RSS Viewer")); + + //contentbox = gtk_dialog_get_content_area(GTK_DIALOG(object)); + + toolbar = gtk_toolbar_new(); + + item = gtk_tool_button_new_from_stock(GTK_STOCK_PREFERENCES); + gtk_widget_set_sensitive(GTK_WIDGET(item), TRUE); + gtk_tool_item_set_tooltip_text(item, "Configure"); + gtk_toolbar_insert(GTK_TOOLBAR(toolbar), item, 0); + + vbox = trg_vbox_new(FALSE, 0); + + gtk_box_pack_start(GTK_BOX(vbox), GTK_WIDGET(toolbar), + FALSE, FALSE, 0); + gtk_box_pack_start(GTK_BOX(vbox), GTK_WIDGET(view), + TRUE, TRUE, 0); + + gtk_container_add(GTK_CONTAINER(object), vbox); + + /*g_signal_connect(object, "response", + G_CALLBACK(trg_rss_window_response_cb), NULL);*/ + + return object; +} + +static void trg_rss_window_dispose(GObject * object) +{ + instance = NULL; + G_OBJECT_CLASS(trg_rss_window_parent_class)->dispose(object); +} + +static void +trg_rss_window_class_init(TrgRssWindowClass * klass) +{ + GObjectClass *object_class = G_OBJECT_CLASS(klass); + + g_type_class_add_private(klass, sizeof(TrgRssWindowPrivate)); + + object_class->constructor = trg_rss_window_constructor; + object_class->get_property = trg_rss_window_get_property; + object_class->set_property = trg_rss_window_set_property; + object_class->dispose = trg_rss_window_dispose; + + g_object_class_install_property(object_class, + PROP_CLIENT, + g_param_spec_pointer("trg-client", + "TClient", + "Client", + G_PARAM_READWRITE + | + G_PARAM_CONSTRUCT_ONLY + | + G_PARAM_STATIC_NAME + | + G_PARAM_STATIC_NICK + | + G_PARAM_STATIC_BLURB)); + + g_object_class_install_property(object_class, + PROP_PARENT, + g_param_spec_object("parent-window", + "Parent window", + "Parent window", + TRG_TYPE_MAIN_WINDOW, + G_PARAM_READWRITE | + G_PARAM_CONSTRUCT_ONLY + | + G_PARAM_STATIC_NAME + | + G_PARAM_STATIC_NICK + | + G_PARAM_STATIC_BLURB)); +} + +static void +trg_rss_window_init(TrgRssWindow * self G_GNUC_UNUSED) +{ +} + +TrgRssWindow *trg_rss_window_get_instance(TrgMainWindow *parent, TrgClient *client) +{ + if (instance == NULL) { + instance = + g_object_new(TRG_TYPE_RSS_WINDOW, "parent-window", parent, "trg-client", client, NULL); + } + + return TRG_RSS_WINDOW(instance); +} diff --git a/src/trg-rss-window.h b/src/trg-rss-window.h new file mode 100644 index 0000000..c628a6b --- /dev/null +++ b/src/trg-rss-window.h @@ -0,0 +1,53 @@ +/* + * transmission-remote-gtk - A GTK RPC client to Transmission + * Copyright (C) 2011-2013 Alan Fitton + + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#ifndef TRG_RSS_WINDOW_H_ +#define TRG_RSS_WINDOW_H_ + +#include +#include + +#include "trg-main-window.h" + +G_BEGIN_DECLS +#define TRG_TYPE_RSS_WINDOW trg_rss_window_get_type() +#define TRG_RSS_WINDOW(obj) \ + (G_TYPE_CHECK_INSTANCE_CAST ((obj), TRG_TYPE_RSS_WINDOW, TrgRssWindow)) +#define TRG_RSS_WINDOW_CLASS(klass) \ + (G_TYPE_CHECK_CLASS_CAST ((klass), TRG_TYPE_RSS_WINDOW, TrgRssWindowClass)) +#define TRG_IS_RSS_WINDOW(obj) \ + (G_TYPE_CHECK_INSTANCE_TYPE ((obj), TRG_TYPE_RSS_WINDOW)) +#define TRG_IS_RSS_WINDOW_CLASS(klass) \ + (G_TYPE_CHECK_CLASS_TYPE ((klass), TRG_TYPE_RSS_WINDOW)) +#define TRG_RSS_WINDOW_GET_CLASS(obj) \ + (G_TYPE_INSTANCE_GET_CLASS ((obj), TRG_TYPE_RSS_WINDOW, TrgRssWindowClass)) + typedef struct { + GtkWindow parent; +} TrgRssWindow; + +typedef struct { + GtkWindowClass parent_class; +} TrgRssWindowClass; + +GType trg_rss_window_get_type(void); + +TrgRssWindow *trg_rss_window_get_instance(TrgMainWindow *parent, TrgClient *client); + +G_END_DECLS +#endif /* TRG_RSS_WINDOW_H_ */ -- cgit v1.2.3 From 1d6f77d4c4fafd0a9cafddd2797249557e601dba Mon Sep 17 00:00:00 2001 From: Alan F Date: Wed, 19 Feb 2014 08:54:10 +0000 Subject: refactor the torrent upload code (it's called from a few places so is probably worth it), and make it easier to use a HTTP response as the input. --- src/Makefile.am | 1 + src/requests.c | 17 ++++- src/requests.h | 5 +- src/trg-client.c | 18 ++--- src/trg-files-tree-view.c | 2 +- src/trg-main-window.c | 75 +++++++++++--------- src/trg-main-window.h | 3 +- src/trg-rss-model.c | 94 ++++++++++++------------- src/trg-rss-model.h | 2 + src/trg-rss-window.c | 68 ++++++++++++++++--- src/trg-torrent-add-dialog.c | 143 +++++++++++++-------------------------- src/trg-torrent-add-dialog.h | 16 ----- src/trg-torrent-add-url-dialog.c | 2 +- src/trg-torrent-move-dialog.c | 2 +- src/trg-torrent-props-dialog.c | 2 +- src/trg-trackers-tree-view.c | 2 +- src/upload.c | 62 +++++++++++++++++ src/upload.h | 25 +++++++ 18 files changed, 317 insertions(+), 222 deletions(-) create mode 100644 src/upload.c create mode 100644 src/upload.h (limited to 'src') diff --git a/src/Makefile.am b/src/Makefile.am index f82a7f5..bb11db2 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -107,6 +107,7 @@ transmission_remote_gtk_SOURCES = \ main.c \ trg-rss-window.c \ trg-rss-model.c \ + upload.c \ $(NULL) transmission_remote_gtk_LDFLAGS = -lm $(jsonglib_LIBS) $(gtk_LIBS) $(gthread_LIBS) $(GEOIP_LIBS) $(gio_LIBS) $(notify_LIBS) $(libproxy_LIBS) $(libcurl_LIBS) $(libappindicator_LIBS) $(rssglib_LIBS) diff --git a/src/requests.c b/src/requests.c index 95be1d7..43a8561 100644 --- a/src/requests.c +++ b/src/requests.c @@ -227,7 +227,22 @@ JsonNode *torrent_add_url(const gchar * url, gboolean paused) return root; } -JsonNode *torrent_add(gchar * target, gint flags) +JsonNode *torrent_add_from_response(trg_response *response, gint flags) { + JsonNode *root = base_request(METHOD_TORRENT_ADD); + JsonObject *args = node_get_arguments(root); + gchar *encoded = g_base64_encode((guchar *)response->raw, response->size); + + json_object_set_string_member(args, PARAM_METAINFO, + encoded); + g_free(encoded); + + json_object_set_boolean_member(args, PARAM_PAUSED, + (flags & TORRENT_ADD_FLAG_PAUSED)); + + return root; +} + +JsonNode *torrent_add_from_file(gchar * target, gint flags) { JsonNode *root; JsonObject *args; diff --git a/src/requests.h b/src/requests.h index 5ea9b2a..7430fda 100644 --- a/src/requests.h +++ b/src/requests.h @@ -23,6 +23,8 @@ #include #include +#include "trg-client.h" + JsonNode *generic_request(gchar * method, JsonArray * array); JsonNode *session_set(void); @@ -34,7 +36,8 @@ JsonNode *torrent_start(JsonArray * array); JsonNode *torrent_verify(JsonArray * array); JsonNode *torrent_reannounce(JsonArray * array); JsonNode *torrent_remove(JsonArray * array, int removeData); -JsonNode *torrent_add(gchar * filename, gint flags); +JsonNode *torrent_add_from_response(trg_response *response, gint flags); +JsonNode *torrent_add_from_file(gchar * filename, gint flags); JsonNode *torrent_add_url(const gchar * url, gboolean paused); JsonNode *torrent_set_location(JsonArray * array, gchar * location, gboolean move); diff --git a/src/trg-client.c b/src/trg-client.c index 6f33b36..8ab2afd 100644 --- a/src/trg-client.c +++ b/src/trg-client.c @@ -442,11 +442,15 @@ void trg_client_configunlock(TrgClient * tc) void trg_response_free(trg_response * response) { - if (response->obj) - json_object_unref(response->obj); - if (response->raw) - g_free(response->raw); - g_free(response); + if (response) { + if (response->obj) + json_object_unref(response->obj); + + if (response->raw) + g_free(response->raw); + + g_free(response); + } } static size_t @@ -559,10 +563,6 @@ static CURL* get_curl(TrgClient *tc, guint http_class) priv->http_class = http_class; } - if (http_class == HTTP_CLASS_TRANSMISSION) { - curl_easy_setopt(curl, CURLOPT_URL, trg_client_get_url(tc)); - } - curl_easy_setopt(curl, CURLOPT_TIMEOUT, (long) trg_prefs_get_int(prefs, TRG_PREFS_KEY_TIMEOUT, TRG_PREFS_CONNECTION)); diff --git a/src/trg-files-tree-view.c b/src/trg-files-tree-view.c index 1c93ad6..ae9e071 100644 --- a/src/trg-files-tree-view.c +++ b/src/trg-files-tree-view.c @@ -93,7 +93,7 @@ static gboolean on_files_update(gpointer data) response->cb_data = priv->win; - return on_generic_interactive_action(data); + return on_generic_interactive_action_response(data); } static void send_updated_file_prefs(TrgFilesTreeView * tv) diff --git a/src/trg-main-window.c b/src/trg-main-window.c index f4e479c..3066c4d 100644 --- a/src/trg-main-window.c +++ b/src/trg-main-window.c @@ -76,6 +76,7 @@ #include "trg-rss-window.h" #include "trg-remote-prefs-dialog.h" #include "trg-preferences-dialog.h" +#include "upload.h" /* The rather large main window class, which glues everything together. */ @@ -480,7 +481,7 @@ static void pause_cb(GtkWidget * w G_GNUC_UNUSED, TrgMainWindow * win) dispatch_async(priv->client, torrent_pause(build_json_id_array (priv->torrentTreeView)), - on_generic_interactive_action, win); + on_generic_interactive_action_response, win); } static void pause_all_cb(GtkWidget * w G_GNUC_UNUSED, TrgMainWindow * win) @@ -489,7 +490,7 @@ static void pause_all_cb(GtkWidget * w G_GNUC_UNUSED, TrgMainWindow * win) if (trg_client_is_connected(priv->client)) dispatch_async(priv->client, torrent_pause(NULL), - on_generic_interactive_action, win); + on_generic_interactive_action_response, win); } gint trg_add_from_filename(TrgMainWindow * win, gchar ** uris) @@ -505,10 +506,14 @@ gint trg_add_from_filename(TrgMainWindow * win, gchar ** uris) return EXIT_SUCCESS; } - if (uris) - for (i = 0; uris[i]; i++) - if (uris[i]) + if (uris) { + for (i = 0; uris[i]; i++) { + if (is_minimised_arg(uris[i])) + g_free(uris[i]); + else if (uris[i]) filesList = g_slist_append(filesList, uris[i]); + } + } g_free(uris); @@ -518,20 +523,20 @@ gint trg_add_from_filename(TrgMainWindow * win, gchar ** uris) if (trg_prefs_get_bool(prefs, TRG_PREFS_KEY_ADD_OPTIONS_DIALOG, TRG_PREFS_GLOBAL)) { TrgTorrentAddDialog *dialog = - trg_torrent_add_dialog_new(win, client, + trg_torrent_add_dialog_new_from_filenames(win, client, filesList); gtk_widget_show_all(GTK_WIDGET(dialog)); } else { - struct add_torrent_threadfunc_args *args = - g_new0(struct add_torrent_threadfunc_args, 1); - args->list = filesList; - args->cb_data = win; - args->client = client; - args->extraArgs = FALSE; - args->flags = trg_prefs_get_add_flags(prefs); - - launch_add_thread(args); + trg_upload *upload = g_new0(trg_upload, 1); + + upload->list = filesList; + upload->main_window = win; + upload->client = client; + upload->extra_args = FALSE; + upload->flags = trg_prefs_get_add_flags(prefs); + + trg_do_upload(upload); } return EXIT_SUCCESS; @@ -543,7 +548,7 @@ static void resume_all_cb(GtkWidget * w G_GNUC_UNUSED, TrgMainWindow * win) if (trg_client_is_connected(priv->client)) dispatch_async(priv->client, torrent_start(NULL), - on_generic_interactive_action, win); + on_generic_interactive_action_response, win); } static void resume_cb(GtkWidget * w G_GNUC_UNUSED, TrgMainWindow * win) @@ -554,7 +559,7 @@ static void resume_cb(GtkWidget * w G_GNUC_UNUSED, TrgMainWindow * win) dispatch_async(priv->client, torrent_start(build_json_id_array (priv->torrentTreeView)), - on_generic_interactive_action, win); + on_generic_interactive_action_response, win); } static void disconnect_cb(GtkWidget * w G_GNUC_UNUSED, gpointer data) @@ -713,7 +718,7 @@ static void reannounce_cb(GtkWidget * w G_GNUC_UNUSED, TrgMainWindow * win) dispatch_async(priv->client, torrent_reannounce(build_json_id_array (priv->torrentTreeView)), - on_generic_interactive_action, win); + on_generic_interactive_action_response, win); } static void verify_cb(GtkWidget * w G_GNUC_UNUSED, TrgMainWindow * win) @@ -724,7 +729,7 @@ static void verify_cb(GtkWidget * w G_GNUC_UNUSED, TrgMainWindow * win) dispatch_async(priv->client, torrent_verify(build_json_id_array (priv->torrentTreeView)), - on_generic_interactive_action, win); + on_generic_interactive_action_response, win); } static void start_now_cb(GtkWidget * w G_GNUC_UNUSED, TrgMainWindow * win) @@ -735,7 +740,7 @@ static void start_now_cb(GtkWidget * w G_GNUC_UNUSED, TrgMainWindow * win) dispatch_async(priv->client, torrent_start_now(build_json_id_array (priv->torrentTreeView)), - on_generic_interactive_action, win); + on_generic_interactive_action_response, win); } static void up_queue_cb(GtkWidget * w G_GNUC_UNUSED, TrgMainWindow * win) @@ -746,7 +751,7 @@ static void up_queue_cb(GtkWidget * w G_GNUC_UNUSED, TrgMainWindow * win) dispatch_async(priv->client, torrent_queue_move_up(build_json_id_array (priv->torrentTreeView)), - on_generic_interactive_action, win); + on_generic_interactive_action_response, win); } static void top_queue_cb(GtkWidget * w G_GNUC_UNUSED, TrgMainWindow * win) @@ -757,7 +762,7 @@ static void top_queue_cb(GtkWidget * w G_GNUC_UNUSED, TrgMainWindow * win) dispatch_async(priv->client, torrent_queue_move_top(build_json_id_array (priv->torrentTreeView)), - on_generic_interactive_action, win); + on_generic_interactive_action_response, win); } static void @@ -769,7 +774,7 @@ bottom_queue_cb(GtkWidget * w G_GNUC_UNUSED, TrgMainWindow * win) dispatch_async(priv->client, torrent_queue_move_bottom(build_json_id_array (priv->torrentTreeView)), - on_generic_interactive_action, win); + on_generic_interactive_action_response, win); } static void down_queue_cb(GtkWidget * w G_GNUC_UNUSED, TrgMainWindow * win) @@ -780,7 +785,7 @@ static void down_queue_cb(GtkWidget * w G_GNUC_UNUSED, TrgMainWindow * win) dispatch_async(priv->client, torrent_queue_move_down(build_json_id_array (priv->torrentTreeView)), - on_generic_interactive_action, win); + on_generic_interactive_action_response, win); } static gint @@ -882,7 +887,7 @@ static void remove_cb(GtkWidget * w G_GNUC_UNUSED, TrgMainWindow * win) _("Remove %d torrents?"), GTK_STOCK_REMOVE) == GTK_RESPONSE_ACCEPT) dispatch_async(priv->client, torrent_remove(ids, FALSE), - on_generic_interactive_action, win); + on_generic_interactive_action_response, win); else json_array_unref(ids); } @@ -1584,13 +1589,10 @@ gboolean on_delete_complete(gpointer data) trg_client_update_session(priv->client, on_session_get, response->cb_data); - return on_generic_interactive_action(data); + return on_generic_interactive_action_response(data); } -gboolean on_generic_interactive_action(gpointer data) -{ - trg_response *response = (trg_response *) data; - TrgMainWindow *win = TRG_MAIN_WINDOW(response->cb_data); +void on_generic_interactive_action(TrgMainWindow *win, trg_response *response) { TrgMainWindowPrivate *priv = win->priv; TrgClient *tc = priv->client; @@ -1610,6 +1612,15 @@ gboolean on_generic_interactive_action(gpointer data) } trg_response_free(response); +} + +gboolean on_generic_interactive_action_response(gpointer data) +{ + trg_response *response = (trg_response *) data; + TrgMainWindow *win = TRG_MAIN_WINDOW(response->cb_data); + + on_generic_interactive_action(win, response); + return FALSE; } @@ -1944,7 +1955,7 @@ static void set_limit_cb(GtkWidget * w, TrgMainWindow * win) json_object_set_boolean_member(args, enabledKey, speed >= 0); if (limitIds) - dispatch_async(priv->client, req, on_generic_interactive_action, + dispatch_async(priv->client, req, on_generic_interactive_action_response, win); else dispatch_async(priv->client, req, on_session_set, win); @@ -1969,7 +1980,7 @@ static void set_priority_cb(GtkWidget * w, TrgMainWindow * win) json_object_set_int_member(args, FIELD_BANDWIDTH_PRIORITY, priority); - dispatch_async(priv->client, req, on_generic_interactive_action, win); + dispatch_async(priv->client, req, on_generic_interactive_action_response, win); } static GtkWidget *limit_item_new(TrgMainWindow * win, GtkWidget * menu, diff --git a/src/trg-main-window.h b/src/trg-main-window.h index 3c6ace5..3fb69af 100644 --- a/src/trg-main-window.h +++ b/src/trg-main-window.h @@ -63,7 +63,8 @@ GType trg_main_window_get_type(void); gint trg_add_from_filename(TrgMainWindow * win, gchar ** uris); gboolean on_session_set(gpointer data); gboolean on_delete_complete(gpointer data); -gboolean on_generic_interactive_action(gpointer data); +void on_generic_interactive_action(TrgMainWindow *win, trg_response *response); +gboolean on_generic_interactive_action_response(gpointer data); void auto_connect_if_required(TrgMainWindow * win); void trg_main_window_set_start_args(TrgMainWindow * win, gchar ** args); TrgMainWindow *trg_main_window_new(TrgClient * tc, gboolean minonstart); diff --git a/src/trg-rss-model.c b/src/trg-rss-model.c index bc43ef7..12b2d2b 100644 --- a/src/trg-rss-model.c +++ b/src/trg-rss-model.c @@ -45,10 +45,8 @@ typedef struct { TrgRssModel *model; gchar *feed_id; gchar *feed_url; - gint status; - RssParser *parser; - gboolean success; GError *error; + trg_response *response; } feed_update; static void feed_update_free(feed_update *update) { @@ -58,61 +56,52 @@ static void feed_update_free(feed_update *update) { g_free(update->feed_id); g_free(update->feed_url); - if (update->parser) - g_object_unref(update->parser); - g_free(update); } -static gboolean on_rss_receive_idle(gpointer data) { - feed_update *update = (feed_update*) data; - TrgRssModel *model = update->model; - TrgRssModelPrivate *priv = TRG_RSS_MODEL_GET_PRIVATE(model); - - if (update->success) { - RssDocument *doc = rss_parser_get_document(update->parser); - GtkTreeIter iter; - GList *list, *tmp; - gchar *title; - - list = rss_document_get_items(doc); - - for (tmp = list; tmp != NULL; tmp = tmp->next) { - RssItem *item = (RssItem*) tmp->data; - const gchar *guid = rss_item_get_guid(item); - if (g_hash_table_lookup(priv->table, guid) != (void*) 1) { - gtk_list_store_append(GTK_LIST_STORE(model), &iter); - gtk_list_store_set(GTK_LIST_STORE(model), &iter, RSSCOL_ID, - guid, RSSCOL_TITLE, rss_item_get_title(item), - RSSCOL_LINK, rss_item_get_link(item), -1); - g_hash_table_insert(priv->table, g_strdup(guid), (void*) 1); - } - } - - g_list_free(list); - g_object_unref(doc); - } - - feed_update_free(update); - - return FALSE; -} - static gboolean on_rss_receive(gpointer data) { trg_response *response = (trg_response *) data; feed_update *update = (feed_update*) response->cb_data; - - update->status = response->status; + TrgRssModel *model = update->model; + TrgRssModelPrivate *priv = TRG_RSS_MODEL_GET_PRIVATE(model); if (response->status == CURLE_OK) { - update->parser = rss_parser_new(); - update->success = rss_parser_load_from_data(update->parser, - response->raw, response->size, &(update->error)); - } + RssParser* parser = rss_parser_new(); + GError *error = NULL; + if (rss_parser_load_from_data(parser, response->raw, + response->size, &error)) { + RssDocument *doc = rss_parser_get_document(parser); + GtkTreeIter iter; + GList *list, *tmp; + gchar *title; + + list = rss_document_get_items(doc); + + for (tmp = list; tmp != NULL; tmp = tmp->next) { + RssItem *item = (RssItem*) tmp->data; + const gchar *guid = rss_item_get_guid(item); + if (g_hash_table_lookup(priv->table, guid) != (void*) 1) { + gtk_list_store_append(GTK_LIST_STORE(model), &iter); + gtk_list_store_set(GTK_LIST_STORE(model), &iter, RSSCOL_ID, + guid, RSSCOL_TITLE, rss_item_get_title(item), + RSSCOL_LINK, rss_item_get_link(item), RSSCOL_FEED, + update->feed_id, RSSCOL_PUBDATE, + rss_item_get_pub_date(item), -1); + g_hash_table_insert(priv->table, g_strdup(guid), (void*) 1); + } + } - g_idle_add(on_rss_receive_idle, update); + g_list_free(list); + g_object_unref(doc); + g_object_unref(parser); + } else { + g_error_free(error); + g_message("parse error?"); + } + } trg_response_free(response); + feed_update_free(update); return FALSE; } @@ -126,7 +115,8 @@ void trg_rss_model_update(TrgRssModel * model) { if (!feeds) return; - for (li = json_array_get_elements(feeds); li != NULL; li = g_list_next(li)) { + for (li = json_array_get_elements(feeds); li != NULL; + li = g_list_next(li)) { JsonObject *feed = json_node_get_object((JsonNode *) li->data); const gchar *url = json_object_get_string_member(feed, "url"); const gchar *id = json_object_get_string_member(feed, "id"); @@ -174,11 +164,10 @@ static GObject *trg_rss_model_constructor(GType type, return obj; } -static void trg_rss_model_dispose(GObject * object) -{ +static void trg_rss_model_dispose(GObject * object) { TrgRssModelPrivate *priv = TRG_RSS_MODEL_GET_PRIVATE(object); g_hash_table_destroy(priv->table); - G_OBJECT_CLASS(trg_rss_model_parent_class)->dispose(object); + G_OBJECT_CLASS(trg_rss_model_parent_class)->dispose(object); } static void trg_rss_model_class_init(TrgRssModelClass * klass) { @@ -199,12 +188,13 @@ static void trg_rss_model_class_init(TrgRssModelClass * klass) { } static void trg_rss_model_init(TrgRssModel * self) { - //TrgRssModelPrivate *priv = TRG_RSS_MODEL_GET_PRIVATE(self); GType column_types[RSSCOL_COLUMNS]; column_types[RSSCOL_ID] = G_TYPE_STRING; column_types[RSSCOL_TITLE] = G_TYPE_STRING; column_types[RSSCOL_LINK] = G_TYPE_STRING; + column_types[RSSCOL_FEED] = G_TYPE_STRING; + column_types[RSSCOL_PUBDATE] = G_TYPE_STRING; gtk_list_store_set_column_types(GTK_LIST_STORE(self), RSSCOL_COLUMNS, column_types); diff --git a/src/trg-rss-model.h b/src/trg-rss-model.h index 9befa48..799629a 100644 --- a/src/trg-rss-model.h +++ b/src/trg-rss-model.h @@ -57,6 +57,8 @@ enum { RSSCOL_ID, RSSCOL_TITLE, RSSCOL_LINK, + RSSCOL_FEED, + RSSCOL_PUBDATE, RSSCOL_COLUMNS }; diff --git a/src/trg-rss-window.c b/src/trg-rss-window.c index 52a096f..942dddc 100644 --- a/src/trg-rss-window.c +++ b/src/trg-rss-window.c @@ -23,7 +23,9 @@ #include "trg-rss-window.h" #include "trg-rss-model.h" +#include "trg-torrent-add-dialog.h" #include "trg-client.h" +#include "upload.h" #include "util.h" G_DEFINE_TYPE(TrgRssWindow, trg_rss_window, @@ -84,15 +86,59 @@ trg_rss_window_set_property(GObject * object, } } +static gboolean on_torrent_receive(gpointer data) { + trg_response *response = (trg_response *) data; + TrgRssWindow *win = TRG_RSS_WINDOW(response->cb_data); + TrgRssWindowPrivate *priv = TRG_RSS_WINDOW_GET_PRIVATE(response->cb_data); + TrgClient *client = priv->client; + TrgPrefs *prefs = trg_client_get_prefs(client); + TrgMainWindow *main_win = priv->parent; + + if (response->status == CURLE_OK) { + if (trg_prefs_get_bool(prefs, TRG_PREFS_KEY_ADD_OPTIONS_DIALOG, + TRG_PREFS_GLOBAL)) { + /*TrgTorrentAddDialog *dialog = + trg_torrent_add_dialog_new_from_filenames(main_win, client, + filesList); + gtk_widget_show_all(GTK_WIDGET(dialog));*/ + } else { + trg_upload *upload = g_new0(trg_upload, 1); + + upload->upload_response = response; + upload->main_window = main_win; + upload->client = client; + upload->extra_args = FALSE; + upload->flags = trg_prefs_get_add_flags(prefs); + + trg_do_upload(upload); + } + } else { + trg_error_dialog(GTK_WINDOW(win), response); + trg_response_free(response); + } + + return FALSE; +} + static void -trg_rss_window_response_cb(GtkDialog * dlg, gint res_id, - gpointer data G_GNUC_UNUSED) +rss_item_activated(GtkTreeView * treeview, + GtkTreePath * path, + GtkTreeViewColumn * + col G_GNUC_UNUSED, gpointer userdata) { - TrgRssWindowPrivate *priv = - TRG_RSS_WINDOW_GET_PRIVATE(dlg); + TrgRssWindow *win = TRG_RSS_WINDOW(userdata); + TrgRssWindowPrivate *priv = TRG_RSS_WINDOW_GET_PRIVATE(win); + GtkTreeModel *model = gtk_tree_view_get_model(treeview); + GtkTreeIter iter; + gchar *link; + + gtk_tree_model_get_iter(model, &iter, path); + + gtk_tree_model_get(model, &iter, RSSCOL_LINK, &link, -1); + + async_http_request(priv->client, link, on_torrent_receive, userdata); - gtk_widget_destroy(GTK_WIDGET(dlg)); - instance = NULL; + g_free(link); } static GObject *trg_rss_window_constructor(GType type, @@ -105,7 +151,7 @@ static GObject *trg_rss_window_constructor(GType type, TrgRssWindowPrivate *priv; TrgRssModel *model; GtkTreeView *view; - GtkWidget *vbox, *toolbar, *contentbox; + GtkWidget *vbox, *toolbar; GtkToolItem *item; object = G_OBJECT_CLASS @@ -120,10 +166,14 @@ static GObject *trg_rss_window_constructor(GType type, view = GTK_TREE_VIEW(gtk_tree_view_new()); gtk_tree_view_set_model(view, GTK_TREE_MODEL(model)); gtk_tree_view_insert_column_with_attributes(view, -1, "Title", gtk_cell_renderer_text_new(), "text", RSSCOL_TITLE, NULL); + gtk_tree_view_insert_column_with_attributes(view, -1, "Feed", gtk_cell_renderer_text_new(), "text", RSSCOL_FEED, NULL); + gtk_tree_view_insert_column_with_attributes(view, -1, "Published", gtk_cell_renderer_text_new(), "text", RSSCOL_PUBDATE, NULL); + gtk_tree_view_insert_column_with_attributes(view, -1, "URL", gtk_cell_renderer_text_new(), "text", RSSCOL_LINK, NULL); - gtk_window_set_title(GTK_WINDOW(object), _("RSS Viewer")); + g_signal_connect(view, "row-activated", + G_CALLBACK(rss_item_activated), object); - //contentbox = gtk_dialog_get_content_area(GTK_DIALOG(object)); + gtk_window_set_title(GTK_WINDOW(object), _("RSS Feeds")); toolbar = gtk_toolbar_new(); diff --git a/src/trg-torrent-add-dialog.c b/src/trg-torrent-add-dialog.c index 517797e..702efd4 100644 --- a/src/trg-torrent-add-dialog.c +++ b/src/trg-torrent-add-dialog.c @@ -45,9 +45,10 @@ #include "torrent.h" #include "json.h" #include "protocol-constants.h" +#include "upload.h" enum { - PROP_0, PROP_FILENAME, PROP_PARENT, PROP_CLIENT + PROP_0, PROP_FILENAME, PROP_PARENT, PROP_CLIENT, PROP_RESPONSE }; enum { @@ -63,6 +64,7 @@ struct _TrgTorrentAddDialogPrivate { TrgClient *client; TrgMainWindow *parent; GSList *filenames; + trg_response *response; GtkWidget *source_chooser; GtkWidget *dest_combo; GtkWidget *priority_combo; @@ -115,65 +117,6 @@ trg_torrent_add_dialog_get_property(GObject * object, } } -static void -add_set_common_args(JsonObject * args, gint priority, gchar * dir) -{ - json_object_set_string_member(args, FIELD_FILE_DOWNLOAD_DIR, dir); - json_object_set_int_member(args, FIELD_BANDWIDTH_PRIORITY, - (gint64) priority); -} - -static gpointer add_files_threadfunc(gpointer data) -{ - struct add_torrent_threadfunc_args *files_thread_data = - (struct add_torrent_threadfunc_args *) data; - - GSList *li; - - for (li = files_thread_data->list; li; li = g_slist_next(li)) { - gchar *fileName = (gchar *) li->data; - JsonNode *request = - torrent_add(fileName, files_thread_data->flags); - JsonObject *args; - trg_response *response; - - if (!request) - continue; - - args = node_get_arguments(request); - - if (files_thread_data->extraArgs) - add_set_common_args(args, files_thread_data->priority, - files_thread_data->dir); - - response = dispatch(files_thread_data->client, request); - response->cb_data = files_thread_data->cb_data; - g_idle_add(on_generic_interactive_action, response); - } - - g_str_slist_free(files_thread_data->list); - - if (files_thread_data->extraArgs) - g_free(files_thread_data->dir); - - g_free(files_thread_data); - - return NULL; -} - -void launch_add_thread(struct add_torrent_threadfunc_args *args) -{ - GError *error = NULL; - g_thread_create(add_files_threadfunc, args, FALSE, &error); - - if (error) { - g_error("thread creation error: %s", error->message); - g_error_free(error); - g_str_slist_free(args->list); - g_free(args); - } -} - static gboolean add_file_indexes_foreachfunc(GtkTreeModel * model, GtkTreePath * @@ -226,32 +169,17 @@ trg_torrent_add_response_cb(GtkDialog * dlg, gint res_id, gpointer data) trg_destination_combo_get_dir(TRG_DESTINATION_COMBO (priv->dest_combo)); - if (g_slist_length(priv->filenames) == 1) { - JsonNode *req = - torrent_add((gchar *) priv->filenames->data, flags); - if (req) { - JsonObject *args = node_get_arguments(req); - gtk_tree_model_foreach(GTK_TREE_MODEL(priv->store), - add_file_indexes_foreachfunc, args); - add_set_common_args(args, priority, dir); - dispatch_async(priv->client, req, - on_generic_interactive_action, - priv->parent); - } - g_str_slist_free(priv->filenames); - } else { - struct add_torrent_threadfunc_args *args = - g_new(struct add_torrent_threadfunc_args, 1); - args->list = priv->filenames; - args->cb_data = priv->parent; - args->client = priv->client; - args->dir = g_strdup(dir); - args->priority = priority; - args->flags = flags; - args->extraArgs = TRUE; - - launch_add_thread(args); - } + trg_upload *upload = g_new0(trg_upload, 1); + + upload->list = priv->filenames; + upload->main_window = priv->parent; + upload->client = priv->client; + upload->dir = dir; + upload->priority = priority; + upload->flags = flags; + upload->extra_args = TRUE; + + trg_do_upload(upload); trg_destination_combo_save_selection(TRG_DESTINATION_COMBO (priv->dest_combo)); @@ -867,6 +795,21 @@ trg_torrent_add_dialog_class_init(TrgTorrentAddDialogClass * klass) | G_PARAM_STATIC_BLURB)); + g_object_class_install_property(object_class, + PROP_RESPONSE, + g_param_spec_pointer("response", + "response", + "response", + G_PARAM_READWRITE + | + G_PARAM_CONSTRUCT_ONLY + | + G_PARAM_STATIC_NAME + | + G_PARAM_STATIC_NICK + | + G_PARAM_STATIC_BLURB)); + g_object_class_install_property(object_class, PROP_CLIENT, g_param_spec_pointer("client", @@ -902,7 +845,7 @@ static void trg_torrent_add_dialog_init(TrgTorrentAddDialog * self) { } -TrgTorrentAddDialog *trg_torrent_add_dialog_new(TrgMainWindow * parent, +TrgTorrentAddDialog *trg_torrent_add_dialog_new_from_filenames(TrgMainWindow * parent, TrgClient * client, GSList * filenames) { @@ -911,6 +854,15 @@ TrgTorrentAddDialog *trg_torrent_add_dialog_new(TrgMainWindow * parent, NULL); } +TrgTorrentAddDialog *trg_torrent_add_dialog_new_from_response(TrgMainWindow * parent, + TrgClient * client, + trg_response *response) +{ + return g_object_new(TRG_TYPE_TORRENT_ADD_DIALOG, "response", + response, "parent", parent, "client", client, + NULL); +} + void trg_torrent_add_dialog(TrgMainWindow * win, TrgClient * client) { GtkWidget *w; @@ -937,22 +889,21 @@ void trg_torrent_add_dialog(TrgMainWindow * win, TrgClient * client) prefs); if (showOptions) { - TrgTorrentAddDialog *dialog = trg_torrent_add_dialog_new(win, + TrgTorrentAddDialog *dialog = trg_torrent_add_dialog_new_from_filenames(win, client, l); gtk_widget_show_all(GTK_WIDGET(dialog)); } else { - struct add_torrent_threadfunc_args *args = - g_new0(struct add_torrent_threadfunc_args, 1); + trg_upload *upload = g_new0(trg_upload, 1); - args->list = l; - args->cb_data = win; - args->client = client; - args->extraArgs = FALSE; - args->flags = trg_prefs_get_add_flags(prefs); + upload->list = l; + upload->main_window = win; + upload->client = client; + upload->extra_args = FALSE; + upload->flags = trg_prefs_get_add_flags(prefs); - launch_add_thread(args); + trg_do_upload(upload); } } diff --git a/src/trg-torrent-add-dialog.h b/src/trg-torrent-add-dialog.h index 0f45e2c..ab6721e 100644 --- a/src/trg-torrent-add-dialog.h +++ b/src/trg-torrent-add-dialog.h @@ -46,28 +46,12 @@ typedef struct { GtkDialogClass parent_class; } TrgTorrentAddDialogClass; -/* Use synchronous dispatch() in our dedicated thread function. - * This means torrents are added in sequence, instead of dispatch_async() - * working concurrently for each upload. - */ - -struct add_torrent_threadfunc_args { - GSList *list; - TrgClient *client; - gpointer cb_data; - guint flags; - gchar *dir; - gint priority; - gboolean extraArgs; -}; - GType trg_torrent_add_dialog_get_type(void); TrgTorrentAddDialog *trg_torrent_add_dialog_new(TrgMainWindow * win, TrgClient * client, GSList * filenames); void trg_torrent_add_dialog(TrgMainWindow * win, TrgClient * client); -void launch_add_thread(struct add_torrent_threadfunc_args *args); G_END_DECLS #endif /* TRG_TORRENT_ADD_DIALOG_H_ */ diff --git a/src/trg-torrent-add-url-dialog.c b/src/trg-torrent-add-url-dialog.c index 7f6335e..8ed15d8 100644 --- a/src/trg-torrent-add-url-dialog.c +++ b/src/trg-torrent-add-url-dialog.c @@ -90,7 +90,7 @@ trg_torrent_add_url_response_cb(TrgTorrentAddUrlDialog * dlg, gint res_id, gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON(priv->startCheck))); dispatch_async(priv->client, request, - on_generic_interactive_action, data); + on_generic_interactive_action_response, data); } gtk_widget_destroy(GTK_WIDGET(dlg)); diff --git a/src/trg-torrent-move-dialog.c b/src/trg-torrent-move-dialog.c index 7669545..99a11fb 100644 --- a/src/trg-torrent-move-dialog.c +++ b/src/trg-torrent-move-dialog.c @@ -69,7 +69,7 @@ trg_torrent_move_response_cb(GtkDialog * dlg, gint res_id, gpointer data) trg_destination_combo_save_selection(TRG_DESTINATION_COMBO (priv->location_combo)); dispatch_async(priv->client, request, - on_generic_interactive_action, data); + on_generic_interactive_action_response, data); } else { json_array_unref(priv->ids); } diff --git a/src/trg-torrent-props-dialog.c b/src/trg-torrent-props-dialog.c index 90ef4e3..71a9c71 100644 --- a/src/trg-torrent-props-dialog.c +++ b/src/trg-torrent-props-dialog.c @@ -172,7 +172,7 @@ static void trg_torrent_props_response_cb(GtkDialog * dialog, gint res_id, trg_json_widgets_save(priv->widgets, args); trg_json_widget_desc_list_free(priv->widgets); - dispatch_async(priv->client, request, on_generic_interactive_action, + dispatch_async(priv->client, request, on_generic_interactive_action_response, priv->parent); } diff --git a/src/trg-trackers-tree-view.c b/src/trg-trackers-tree-view.c index 7ce05b7..54948f3 100644 --- a/src/trg-trackers-tree-view.c +++ b/src/trg-trackers-tree-view.c @@ -66,7 +66,7 @@ static gboolean on_trackers_update(gpointer data) trg_trackers_model_set_accept(TRG_TRACKERS_MODEL(model), TRUE); response->cb_data = priv->win; - return on_generic_interactive_action(data); + return on_generic_interactive_action_response(data); } void diff --git a/src/upload.c b/src/upload.c new file mode 100644 index 0000000..5bac869 --- /dev/null +++ b/src/upload.c @@ -0,0 +1,62 @@ +#include "protocol-constants.h" +#include "requests.h" +#include "trg-client.h" +#include "upload.h" +#include "util.h" +#include "trg-main-window.h" + +static gboolean upload_complete_callback(gpointer data); +static void next_upload(trg_upload *upload); + +static void +add_set_common_args(JsonObject * args, gint priority, gchar * dir) +{ + json_object_set_string_member(args, FIELD_FILE_DOWNLOAD_DIR, dir); + json_object_set_int_member(args, FIELD_BANDWIDTH_PRIORITY, + (gint64) priority); +} + +void trg_upload_free(trg_upload *upload) { + g_str_slist_free(upload->list); + g_free(upload->dir); + trg_response_free(upload->upload_response); + g_free(upload); +} + +static void next_upload(trg_upload *upload) { + if (upload->upload_response && upload->progress_index < 1) { + JsonNode *req = torrent_add_from_response(upload->upload_response, 0); + /*JsonObject *args = + if (upload->extra_args) + add_set_common_args()*/ + upload->progress_index++; + dispatch_async(upload->client, req, upload_complete_callback, upload); + } else if (upload->list && upload->progress_index < g_slist_length(upload->list)) { + JsonNode *req = torrent_add_from_file((gchar*)g_slist_nth_data(upload->list, upload->progress_index), 0); + upload->progress_index++; + dispatch_async(upload->client, req, upload_complete_callback, upload); + } else { + trg_upload_free(upload); + } +} + +static gboolean upload_complete_callback(gpointer data) { + trg_response *response = (trg_response*)data; + trg_upload *upload = (trg_upload*)response->cb_data; + + next_upload(upload); + + /* the callback we're delegating to will destroy the response */ + + if (upload->main_window) + on_generic_interactive_action(upload->main_window, response); + else /* otherwise need to do it here */ + trg_response_free(response); + + return FALSE; +} + +void trg_do_upload(trg_upload *upload) +{ + next_upload(upload); +} diff --git a/src/upload.h b/src/upload.h new file mode 100644 index 0000000..9f3f719 --- /dev/null +++ b/src/upload.h @@ -0,0 +1,25 @@ +#ifndef UPLOAD_H_ +#define UPLOAD_H_ + +#include + +#include "trg-client.h" +#include "trg-main-window.h" + +typedef struct { + GSList *list; // list of filenames + trg_response *upload_response; // OR: a HTTP response containing a torrent + TrgClient *client; + gpointer cb_data; + TrgMainWindow *main_window; // a parent window to attach any error dialogs to + guint flags; + gchar *dir; + gint priority; + gboolean extra_args; + guint progress_index; + +} trg_upload; + +void trg_do_upload(trg_upload *upload); + +#endif -- cgit v1.2.3 From 907636d97b1893e9df4ef28489c92d32118c6fa2 Mon Sep 17 00:00:00 2001 From: Alan F Date: Mon, 24 Feb 2014 18:48:23 +0000 Subject: plug the RSS feeds into the preferences dialog and put ifdefs so it should compile without rss-glib --- src/Makefile.am | 2 +- src/trg-client.c | 6 +++++ src/trg-main-window.c | 18 ++++++++++---- src/trg-menu-bar.c | 14 +++++++++++ src/trg-persistent-tree-view.c | 25 +++++++++++++++---- src/trg-persistent-tree-view.h | 2 +- src/trg-preferences-dialog.c | 53 +++++++++++++++++++++++++++++++++++++---- src/trg-prefs.h | 3 +++ src/trg-rss-model.c | 54 +++++++++++++++++++++++++++++++++++++++++- src/trg-rss-model.h | 20 ++++++++++++++++ src/trg-rss-window.c | 40 +++++++++++++++++++++++++++++++ src/trg-rss-window.h | 7 ++++++ src/util.c | 2 +- 13 files changed, 230 insertions(+), 16 deletions(-) (limited to 'src') diff --git a/src/Makefile.am b/src/Makefile.am index bb11db2..fc4902e 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -105,8 +105,8 @@ transmission_remote_gtk_SOURCES = \ trg-client.c \ trg-main-window.c \ main.c \ - trg-rss-window.c \ trg-rss-model.c \ + trg-rss-window.c \ upload.c \ $(NULL) diff --git a/src/trg-client.c b/src/trg-client.c index 8ab2afd..25a78dd 100644 --- a/src/trg-client.c +++ b/src/trg-client.c @@ -563,12 +563,18 @@ static CURL* get_curl(TrgClient *tc, guint http_class) priv->http_class = http_class; } + if (http_class == HTTP_CLASS_TRANSMISSION) + curl_easy_setopt(curl, CURLOPT_URL, trg_client_get_url(tc)); + curl_easy_setopt(curl, CURLOPT_TIMEOUT, (long) trg_prefs_get_int(prefs, TRG_PREFS_KEY_TIMEOUT, TRG_PREFS_CONNECTION)); g_mutex_unlock(priv->configMutex); + /* Headers are set on each use, then freed, so make sure invalid headers aren't still around. */ + curl_easy_setopt(curl, CURLOPT_HTTPHEADER, NULL); + return curl; } diff --git a/src/trg-main-window.c b/src/trg-main-window.c index 3066c4d..32212f6 100644 --- a/src/trg-main-window.c +++ b/src/trg-main-window.c @@ -17,9 +17,7 @@ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ -#ifdef HAVE_CONFIG_H #include "config.h" -#endif #include #include @@ -73,7 +71,9 @@ #include "trg-menu-bar.h" #include "trg-status-bar.h" #include "trg-stats-dialog.h" +#ifdef HAVE_RSSGLIB #include "trg-rss-window.h" +#endif #include "trg-remote-prefs-dialog.h" #include "trg-preferences-dialog.h" #include "upload.h" @@ -930,6 +930,7 @@ static void view_stats_toggled_cb(GtkWidget * w, gpointer data) } } +#ifdef HAVE_RSSGLIB static void view_rss_toggled_cb(GtkWidget * w, gpointer data) { TrgMainWindow *win = TRG_MAIN_WINDOW(data); @@ -942,6 +943,7 @@ static void view_rss_toggled_cb(GtkWidget * w, gpointer data) gtk_widget_show_all(GTK_WIDGET(rss)); } } +#endif static void view_states_toggled_cb(GtkCheckMenuItem * w, TrgMainWindow * win) @@ -1756,12 +1758,15 @@ static TrgMenuBar *trg_main_window_menu_bar_new(TrgMainWindow * win) GObject *b_disconnect, *b_add, *b_resume, *b_pause, *b_verify, *b_remove, *b_delete, *b_props, *b_local_prefs, *b_remote_prefs, - *b_about, *b_view_states, *b_view_notebook, *b_view_stats, *b_view_rss, + *b_about, *b_view_states, *b_view_notebook, *b_view_stats, *b_add_url, *b_quit, *b_move, *b_reannounce, *b_pause_all, *b_resume_all, *b_dir_filters, *b_tracker_filters, *b_up_queue, *b_down_queue, *b_top_queue, *b_bottom_queue, #if TRG_WITH_GRAPH *b_show_graph, +#endif +#ifdef HAVE_RSSGLIB + *b_view_rss, #endif *b_start_now; @@ -1787,9 +1792,12 @@ static TrgMenuBar *trg_main_window_menu_bar_new(TrgMainWindow * win) "view-states-button", &b_view_states, "view-stats-button", &b_view_stats, "about-button", &b_about, "quit-button", &b_quit, "dir-filters", &b_dir_filters, "tracker-filters", - &b_tracker_filters, "view-rss-button", &b_view_rss, + &b_tracker_filters, #if TRG_WITH_GRAPH "show-graph", &b_show_graph, +#endif +#ifdef HAVE_RSSGLIB + "view-rss-button", &b_view_rss, #endif "up-queue", &b_up_queue, "down-queue", &b_down_queue, "top-queue", &b_top_queue, "bottom-queue", @@ -1835,8 +1843,10 @@ static TrgMenuBar *trg_main_window_menu_bar_new(TrgMainWindow * win) G_CALLBACK(view_states_toggled_cb), win); g_signal_connect(b_view_stats, "activate", G_CALLBACK(view_stats_toggled_cb), win); +#ifdef HAVE_RSSGLIB g_signal_connect(b_view_rss, "activate", G_CALLBACK(view_rss_toggled_cb), win); +#endif #if TRG_WITH_GRAPH g_signal_connect(b_show_graph, "toggled", G_CALLBACK(trg_main_window_toggle_graph_cb), win); diff --git a/src/trg-menu-bar.c b/src/trg-menu-bar.c index f6ca4c5..37c6c2c 100644 --- a/src/trg-menu-bar.c +++ b/src/trg-menu-bar.c @@ -17,6 +17,8 @@ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ +#include "config.h" + #include #include #include @@ -49,7 +51,9 @@ enum { PROP_LOCAL_PREFS_BUTTON, PROP_ABOUT_BUTTON, PROP_VIEW_STATS_BUTTON, +#ifdef HAVE_RSSGLIB PROP_VIEW_RSS_BUTTON, +#endif PROP_VIEW_STATES_BUTTON, PROP_VIEW_NOTEBOOK_BUTTON, PROP_QUIT, @@ -97,7 +101,9 @@ struct _TrgMenuBarPrivate { GtkWidget *mb_view_states; GtkWidget *mb_view_notebook; GtkWidget *mb_view_stats; +#ifdef HAVE_RSSGLIB GtkWidget *mb_view_rss; +#endif GtkWidget *mb_about; GtkWidget *mb_quit; GtkWidget *mb_directory_filters; @@ -142,7 +148,9 @@ void trg_menu_bar_connected_change(TrgMenuBar * mb, gboolean connected) gtk_widget_set_sensitive(priv->mb_disconnect, connected); gtk_widget_set_sensitive(priv->mb_remote_prefs, connected); gtk_widget_set_sensitive(priv->mb_view_stats, connected); +#ifdef HAVE_RSSGLIB gtk_widget_set_sensitive(priv->mb_view_rss, connected); +#endif gtk_widget_set_sensitive(priv->mb_resume_all, connected); gtk_widget_set_sensitive(priv->mb_pause_all, connected); } @@ -276,9 +284,11 @@ trg_menu_bar_get_property(GObject * object, guint property_id, case PROP_VIEW_STATS_BUTTON: g_value_set_object(value, priv->mb_view_stats); break; +#ifdef HAVE_RSSGLIB case PROP_VIEW_RSS_BUTTON: g_value_set_object(value, priv->mb_view_rss); break; +#endif case PROP_QUIT: g_value_set_object(value, priv->mb_quit); break; @@ -548,11 +558,13 @@ static GtkWidget *trg_menu_bar_view_menu_new(TrgMenuBar * mb) gtk_widget_set_sensitive(priv->mb_view_stats, FALSE); gtk_menu_shell_append(GTK_MENU_SHELL(viewMenu), priv->mb_view_stats); +#ifdef HAVE_RSSGLIB priv->mb_view_rss = gtk_menu_item_new_with_mnemonic(_("_RSS")); //trg_menu_bar_accel_add(mb, priv->mb_view_rss, GDK_F7, 0); gtk_widget_set_sensitive(priv->mb_view_rss, FALSE); gtk_menu_shell_append(GTK_MENU_SHELL(viewMenu), priv->mb_view_rss); +#endif return view; } @@ -882,9 +894,11 @@ static void trg_menu_bar_class_init(TrgMenuBarClass * klass) trg_menu_bar_install_widget_prop(object_class, PROP_VIEW_STATS_BUTTON, "view-stats-button", "View stats button"); +#ifdef HAVE_RSSGLIB trg_menu_bar_install_widget_prop(object_class, PROP_VIEW_RSS_BUTTON, "view-rss-button", "View rss button"); +#endif trg_menu_bar_install_widget_prop(object_class, PROP_VIEW_STATES_BUTTON, "view-states-button", "View states Button"); diff --git a/src/trg-persistent-tree-view.c b/src/trg-persistent-tree-view.c index e116fdf..c608acb 100644 --- a/src/trg-persistent-tree-view.c +++ b/src/trg-persistent-tree-view.c @@ -37,7 +37,7 @@ typedef struct _TrgPersistentTreeViewPrivate TrgPersistentTreeViewPrivate; enum { - PROP_0, PROP_PREFS, PROP_KEY, PROP_MODEL + PROP_0, PROP_PREFS, PROP_KEY, PROP_MODEL, PROP_CONF_FLAGS }; struct _TrgPersistentTreeViewPrivate { @@ -52,6 +52,7 @@ struct _TrgPersistentTreeViewPrivate { trg_pref_widget_desc *wd; GtkTreeModel *model; trg_persistent_tree_view_column *addSelect; + gint conf_flags; }; static void selection_changed(TrgPersistentTreeView * ptv, @@ -322,6 +323,9 @@ trg_persistent_tree_view_set_property(GObject * object, case PROP_MODEL: priv->model = g_value_get_object(value); break; + case PROP_CONF_FLAGS: + priv->conf_flags = g_value_get_int(value); + break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID(object, property_id, pspec); break; @@ -411,7 +415,7 @@ static GObject *trg_persistent_tree_view_constructor(GType type, gtk_box_pack_start(GTK_BOX(object), hbox, FALSE, FALSE, 4); priv->wd = trg_pref_widget_desc_new(GTK_WIDGET(priv->tv), priv->key, - TRG_PREFS_PROFILE); + priv->conf_flags); priv->wd->widget = GTK_WIDGET(object); priv->wd->saveFunc = &trg_persistent_tree_view_save; priv->wd->refreshFunc = &trg_persistent_tree_view_refresh; @@ -461,6 +465,19 @@ trg_persistent_tree_view_class_init(TrgPersistentTreeViewClass * klass) | G_PARAM_STATIC_BLURB)); + g_object_class_install_property(object_class, + PROP_CONF_FLAGS, + g_param_spec_int("conf-flags", + "Conf Flags", + "Conf Flags", + INT_MIN, + INT_MAX, + TRG_PREFS_PROFILE, + G_PARAM_READWRITE | + G_PARAM_STATIC_NAME | + G_PARAM_STATIC_NICK | + G_PARAM_STATIC_BLURB)); + g_object_class_install_property(object_class, PROP_MODEL, g_param_spec_object("persistent-model", @@ -483,12 +500,12 @@ static void trg_persistent_tree_view_init(TrgPersistentTreeView * self) TrgPersistentTreeView *trg_persistent_tree_view_new(TrgPrefs * prefs, GtkListStore * model, - const gchar * key) + const gchar * key, gint conf_flags) { GObject *obj = g_object_new(TRG_TYPE_PERSISTENT_TREE_VIEW, "prefs", prefs, "conf-key", key, "persistent-model", - model, + model, "conf-flags", conf_flags, NULL); return TRG_PERSISTENT_TREE_VIEW(obj); diff --git a/src/trg-persistent-tree-view.h b/src/trg-persistent-tree-view.h index a5a7c8f..0d16fb6 100644 --- a/src/trg-persistent-tree-view.h +++ b/src/trg-persistent-tree-view.h @@ -57,7 +57,7 @@ typedef struct { TrgPersistentTreeView *trg_persistent_tree_view_new(TrgPrefs * prefs, GtkListStore * model, - const gchar * key); + const gchar * key, gint conf_flags); trg_pref_widget_desc * trg_persistent_tree_view_get_widget_desc(TrgPersistentTreeView * diff --git a/src/trg-preferences-dialog.c b/src/trg-preferences-dialog.c index b9327c6..e7434d3 100644 --- a/src/trg-preferences-dialog.c +++ b/src/trg-preferences-dialog.c @@ -17,9 +17,7 @@ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ -#ifdef HAVE_CONFIG_H #include "config.h" -#endif #include #include @@ -601,7 +599,7 @@ static GtkWidget *trg_prefs_openExecPage(TrgPreferencesDialog * dlg) model = gtk_list_store_new(2, G_TYPE_STRING, G_TYPE_STRING); ptv = trg_persistent_tree_view_new(priv->prefs, model, - TRG_PREFS_KEY_EXEC_COMMANDS); + TRG_PREFS_KEY_EXEC_COMMANDS, TRG_PREFS_PROFILE); trg_persistent_tree_view_set_add_select(ptv, trg_persistent_tree_view_add_column (ptv, 0, @@ -621,6 +619,46 @@ static GtkWidget *trg_prefs_openExecPage(TrgPreferencesDialog * dlg) return t; } +#ifdef HAVE_RSSGLIB +static GtkWidget *trg_prefs_rss_page(TrgPreferencesDialog * dlg) { + TrgPreferencesDialogPrivate *priv = + TRG_PREFERENCES_DIALOG_GET_PRIVATE(dlg); + GtkWidget *t; + guint row = 0; + TrgPersistentTreeView *ptv; + trg_pref_widget_desc *wd; + GtkListStore *model; + + t = hig_workarea_create(); + + hig_workarea_add_section_title(t, &row, + _("RSS Feeds")); + + model = gtk_list_store_new(2, G_TYPE_STRING, G_TYPE_STRING); + + ptv = trg_persistent_tree_view_new(priv->prefs, model, + TRG_PREFS_KEY_RSS, TRG_PREFS_GLOBAL); + trg_persistent_tree_view_set_add_select(ptv, + trg_persistent_tree_view_add_column + (ptv, 0, + TRG_PREFS_RSS_SUBKEY_ID, + _("Name"))); + trg_persistent_tree_view_add_column(ptv, 1, + TRG_PREFS_RSS_SUBKEY_URL, + _("URL")); + + wd = trg_persistent_tree_view_get_widget_desc(ptv); + trg_pref_widget_refresh(dlg, wd); + priv->widgets = g_list_append(priv->widgets, wd); + + gtk_table_attach(GTK_TABLE(t), GTK_WIDGET(ptv), 1, 2, row, row + 1, + GTK_EXPAND | GTK_SHRINK | GTK_FILL, + GTK_FILL | GTK_EXPAND | GTK_SHRINK, 0, 0); + + return t; +} +#endif + static GtkWidget *trg_prefs_dirsPage(TrgPreferencesDialog * dlg) { TrgPreferencesDialogPrivate *priv = @@ -639,7 +677,7 @@ static GtkWidget *trg_prefs_dirsPage(TrgPreferencesDialog * dlg) model = gtk_list_store_new(2, G_TYPE_STRING, G_TYPE_STRING); ptv = trg_persistent_tree_view_new(priv->prefs, model, - TRG_PREFS_KEY_DESTINATIONS); + TRG_PREFS_KEY_DESTINATIONS, TRG_PREFS_GLOBAL); trg_persistent_tree_view_set_add_select(ptv, trg_persistent_tree_view_add_column (ptv, 0, @@ -917,6 +955,13 @@ static GObject *trg_preferences_dialog_constructor(GType type, (object)), gtk_label_new(_("Directories"))); +#ifdef HAVE_RSSGLIB + gtk_notebook_append_page(GTK_NOTEBOOK(notebook), + trg_prefs_rss_page(TRG_PREFERENCES_DIALOG + (object)), + gtk_label_new(_("RSS Feeds"))); +#endif + gtk_container_set_border_width(GTK_CONTAINER(notebook), GUI_PAD); gtk_box_pack_start(GTK_BOX(contentvbox), notebook, TRUE, TRUE, 0); diff --git a/src/trg-prefs.h b/src/trg-prefs.h index d8afe8f..4245505 100644 --- a/src/trg-prefs.h +++ b/src/trg-prefs.h @@ -79,6 +79,9 @@ #define TRG_PREFS_KEY_EXEC_COMMANDS "exec-commands" #define TRG_PREFS_KEY_EXEC_COMMANDS_SUBKEY_CMD "cmd" #define TRG_PREFS_KEY_DESTINATIONS "destinations" +#define TRG_PREFS_KEY_RSS "rss" +#define TRG_PREFS_RSS_SUBKEY_ID "id" +#define TRG_PREFS_RSS_SUBKEY_URL "url" #define TRG_PREFS_KEY_LAST_MOVE_DESTINATION "last-move-destination" #define TRG_PREFS_KEY_LAST_ADD_DESTINATION "last-add-destination" #define TRG_PREFS_KEY_DESTINATIONS_SUBKEY_DIR "dir" diff --git a/src/trg-rss-model.c b/src/trg-rss-model.c index 12b2d2b..813652f 100644 --- a/src/trg-rss-model.c +++ b/src/trg-rss-model.c @@ -17,6 +17,10 @@ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ +#include "config.h" + +#ifdef HAVE_RSSGLIB + #include #include #include @@ -31,6 +35,12 @@ enum { PROP_0, PROP_CLIENT }; +enum { + SIGNAL_GET_ERROR, SIGNAL_PARSE_ERROR, SIGNAL_COUNT +}; + +static guint signals[SIGNAL_COUNT] = { 0 }; + G_DEFINE_TYPE(TrgRssModel, trg_rss_model, GTK_TYPE_LIST_STORE) #define TRG_RSS_MODEL_GET_PRIVATE(o) \ (G_TYPE_INSTANCE_GET_PRIVATE ((o), TRG_TYPE_RSS_MODEL, TrgRssModelPrivate)) @@ -95,9 +105,23 @@ static gboolean on_rss_receive(gpointer data) { g_object_unref(doc); g_object_unref(parser); } else { + rss_parse_error perror; + perror.error = error; + perror.feed_id = update->feed_id; + + g_signal_emit(model, signals[SIGNAL_PARSE_ERROR], 0, + &perror); + + g_message("parse error: %s", error->message); g_error_free(error); - g_message("parse error?"); } + } else { + rss_get_error get_error; + get_error.error_code = response->status; + get_error.feed_id = update->feed_id; + + g_signal_emit(model, signals[SIGNAL_GET_ERROR], 0, + &get_error); } trg_response_free(response); @@ -185,6 +209,32 @@ static void trg_rss_model_class_init(TrgRssModelClass * klass) { G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_NAME | G_PARAM_STATIC_NICK | G_PARAM_STATIC_BLURB)); + + signals[SIGNAL_GET_ERROR] = g_signal_new("get-error", + G_TYPE_FROM_CLASS + (object_class), + G_SIGNAL_RUN_LAST | + G_SIGNAL_ACTION, + G_STRUCT_OFFSET + (TrgRssModelClass, + get_error), + NULL, NULL, + g_cclosure_marshal_VOID__POINTER, + G_TYPE_NONE, 1, + G_TYPE_POINTER); + + signals[SIGNAL_PARSE_ERROR] = g_signal_new("parse-error", + G_TYPE_FROM_CLASS + (object_class), + G_SIGNAL_RUN_LAST | + G_SIGNAL_ACTION, + G_STRUCT_OFFSET + (TrgRssModelClass, + parse_error), + NULL, NULL, + g_cclosure_marshal_VOID__POINTER, + G_TYPE_NONE, 1, + G_TYPE_POINTER); } static void trg_rss_model_init(TrgRssModel * self) { @@ -203,3 +253,5 @@ static void trg_rss_model_init(TrgRssModel * self) { TrgRssModel *trg_rss_model_new(TrgClient *client) { return g_object_new(TRG_TYPE_RSS_MODEL, "client", client, NULL); } + +#endif diff --git a/src/trg-rss-model.h b/src/trg-rss-model.h index 799629a..a931c37 100644 --- a/src/trg-rss-model.h +++ b/src/trg-rss-model.h @@ -20,6 +20,10 @@ #ifndef TRG_RSS_MODEL_H_ #define TRG_RSS_MODEL_H_ +#include "config.h" + +#ifdef HAVE_RSSGLIB + #include #include @@ -42,8 +46,22 @@ G_BEGIN_DECLS GtkListStore parent; } TrgRssModel; +typedef struct { + gchar *feed_id; + gint error_code; +} rss_get_error; + +typedef struct { + GError *error; + gchar *feed_id; +} rss_parse_error; + typedef struct { GtkListStoreClass parent_class; + void (*get_error) (TrgRssModel * model, + rss_get_error *error); + void (*parse_error) (TrgRssModel * model, + rss_parse_error *error); } TrgRssModelClass; GType trg_rss_model_get_type(void); @@ -62,4 +80,6 @@ enum { RSSCOL_COLUMNS }; +#endif + #endif /* TRG_RSS_MODEL_H_ */ diff --git a/src/trg-rss-window.c b/src/trg-rss-window.c index 942dddc..5caedf0 100644 --- a/src/trg-rss-window.c +++ b/src/trg-rss-window.c @@ -17,6 +17,10 @@ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ +#include "config.h" + +#ifdef HAVE_RSSGLIB + #include #include #include @@ -141,6 +145,34 @@ rss_item_activated(GtkTreeView * treeview, g_free(link); } +static void *trg_rss_on_get_error(TrgRssModel *model, rss_get_error *error, gpointer data) { + GtkWindow *win = GTK_WINDOW(data); + gchar *msg = g_strdup_printf(_("Error while fetching RSS feed \"%s\": %s"), error->feed_id, curl_easy_strerror(error->error_code)); + GtkWidget *dialog = gtk_message_dialog_new(win, + GTK_DIALOG_MODAL, + GTK_MESSAGE_ERROR, + GTK_BUTTONS_OK, + msg); + g_free(msg); + gtk_window_set_title(GTK_WINDOW(dialog), _("Error")); + gtk_dialog_run(GTK_DIALOG(dialog)); + gtk_widget_destroy(dialog); +} + +static void *trg_rss_on_parse_error(TrgRssModel *model, rss_parse_error *error, gpointer data) { + GtkWindow *win = GTK_WINDOW(data); + gchar *msg = g_strdup_printf(_("Error parsing RSS feed \"%s\": %s"), error->feed_id, error->error->message); + GtkWidget *dialog = gtk_message_dialog_new(win, + GTK_DIALOG_MODAL, + GTK_MESSAGE_ERROR, + GTK_BUTTONS_OK, + msg); + g_free(msg); + gtk_window_set_title(GTK_WINDOW(dialog), _("Error")); + gtk_dialog_run(GTK_DIALOG(dialog)); + gtk_widget_destroy(dialog); +} + static GObject *trg_rss_window_constructor(GType type, guint n_construct_properties, @@ -161,6 +193,12 @@ static GObject *trg_rss_window_constructor(GType type, priv = TRG_RSS_WINDOW_GET_PRIVATE(object); model = trg_rss_model_new(priv->client); + + g_signal_connect(model, "get-error", + G_CALLBACK(trg_rss_on_get_error), NULL); + g_signal_connect(model, "parse-error", + G_CALLBACK(trg_rss_on_parse_error), NULL); + trg_rss_model_update(model); view = GTK_TREE_VIEW(gtk_tree_view_new()); @@ -260,3 +298,5 @@ TrgRssWindow *trg_rss_window_get_instance(TrgMainWindow *parent, TrgClient *clie return TRG_RSS_WINDOW(instance); } + +#endif diff --git a/src/trg-rss-window.h b/src/trg-rss-window.h index c628a6b..5ce8690 100644 --- a/src/trg-rss-window.h +++ b/src/trg-rss-window.h @@ -20,6 +20,10 @@ #ifndef TRG_RSS_WINDOW_H_ #define TRG_RSS_WINDOW_H_ +#include "config.h" + +#ifdef HAVE_RSSGLIB + #include #include @@ -50,4 +54,7 @@ GType trg_rss_window_get_type(void); TrgRssWindow *trg_rss_window_get_instance(TrgMainWindow *parent, TrgClient *client); G_END_DECLS + +#endif + #endif /* TRG_RSS_WINDOW_H_ */ diff --git a/src/util.c b/src/util.c index 5ef7768..8dcbb65 100644 --- a/src/util.c +++ b/src/util.c @@ -340,7 +340,7 @@ gchar *make_error_message(JsonObject * response, int status) { if (status == FAIL_JSON_DECODE) { return g_strdup(_("JSON decoding error.")); - } else if (status == FAIL_RESPONSE_UNSUCCESSFUL) { + } else if (response && status == FAIL_RESPONSE_UNSUCCESSFUL) { const gchar *resultStr = json_object_get_string_member(response, "result"); if (resultStr == NULL) -- cgit v1.2.3 From 361cde21cdc9fff703c63e393e48a2a3409d162a Mon Sep 17 00:00:00 2001 From: Alan F Date: Tue, 25 Feb 2014 09:50:50 +0000 Subject: put rss tree view in a scroll window, display HTTP error codes on error (only use curl_strerror for communications error, != CURLE_OK) --- src/trg-client.c | 2 +- src/trg-rss-window.c | 23 ++++++++++++++--------- 2 files changed, 15 insertions(+), 10 deletions(-) (limited to 'src') diff --git a/src/trg-client.c b/src/trg-client.c index 25a78dd..7e1a784 100644 --- a/src/trg-client.c +++ b/src/trg-client.c @@ -532,7 +532,7 @@ static CURL* get_curl(TrgClient *tc, guint http_class) curl_easy_setopt(curl, CURLOPT_USERAGENT, PACKAGE_NAME); curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, &http_receive_callback); - //curl_easy_setopt(curl, CURLOPT_VERBOSE, 1); + curl_easy_setopt(curl, CURLOPT_VERBOSE, 1); if (http_class == HTTP_CLASS_TRANSMISSION) { curl_easy_setopt(curl, CURLOPT_WRITEHEADER, (void *) tc); diff --git a/src/trg-rss-window.c b/src/trg-rss-window.c index 5caedf0..224cbb7 100644 --- a/src/trg-rss-window.c +++ b/src/trg-rss-window.c @@ -145,9 +145,14 @@ rss_item_activated(GtkTreeView * treeview, g_free(link); } -static void *trg_rss_on_get_error(TrgRssModel *model, rss_get_error *error, gpointer data) { +static void trg_rss_on_get_error(TrgRssModel *model, rss_get_error *error, gpointer data) { GtkWindow *win = GTK_WINDOW(data); - gchar *msg = g_strdup_printf(_("Error while fetching RSS feed \"%s\": %s"), error->feed_id, curl_easy_strerror(error->error_code)); + gchar *msg; + if (error->error_code <= -100) { + msg = g_strdup_printf(_("Request failed with HTTP code %d"), -(error->error_code + 100)); + } else { + msg = g_strdup(curl_easy_strerror(error->error_code)); + } GtkWidget *dialog = gtk_message_dialog_new(win, GTK_DIALOG_MODAL, GTK_MESSAGE_ERROR, @@ -159,7 +164,7 @@ static void *trg_rss_on_get_error(TrgRssModel *model, rss_get_error *error, gpoi gtk_widget_destroy(dialog); } -static void *trg_rss_on_parse_error(TrgRssModel *model, rss_parse_error *error, gpointer data) { +static void trg_rss_on_parse_error(TrgRssModel *model, rss_parse_error *error, gpointer data) { GtkWindow *win = GTK_WINDOW(data); gchar *msg = g_strdup_printf(_("Error parsing RSS feed \"%s\": %s"), error->feed_id, error->error->message); GtkWidget *dialog = gtk_message_dialog_new(win, @@ -183,7 +188,7 @@ static GObject *trg_rss_window_constructor(GType type, TrgRssWindowPrivate *priv; TrgRssModel *model; GtkTreeView *view; - GtkWidget *vbox, *toolbar; + GtkWidget *vbox; GtkToolItem *item; object = G_OBJECT_CLASS @@ -213,18 +218,18 @@ static GObject *trg_rss_window_constructor(GType type, gtk_window_set_title(GTK_WINDOW(object), _("RSS Feeds")); - toolbar = gtk_toolbar_new(); + /*toolbar = gtk_toolbar_new(); item = gtk_tool_button_new_from_stock(GTK_STOCK_PREFERENCES); gtk_widget_set_sensitive(GTK_WIDGET(item), TRUE); gtk_tool_item_set_tooltip_text(item, "Configure"); - gtk_toolbar_insert(GTK_TOOLBAR(toolbar), item, 0); + gtk_toolbar_insert(GTK_TOOLBAR(toolbar), item, 0);*/ vbox = trg_vbox_new(FALSE, 0); - gtk_box_pack_start(GTK_BOX(vbox), GTK_WIDGET(toolbar), - FALSE, FALSE, 0); - gtk_box_pack_start(GTK_BOX(vbox), GTK_WIDGET(view), + /*gtk_box_pack_start(GTK_BOX(vbox), GTK_WIDGET(toolbar), + FALSE, FALSE, 0);*/ + gtk_box_pack_start(GTK_BOX(vbox), my_scrolledwin_new(GTK_WIDGET(view)), TRUE, TRUE, 0); gtk_container_add(GTK_CONTAINER(object), vbox); -- cgit v1.2.3 From 178dcc788892a216b346d4937970efa351bc4863 Mon Sep 17 00:00:00 2001 From: Alan F Date: Fri, 28 Feb 2014 09:54:43 +0000 Subject: a cell renderer for RSS items --- src/Makefile.am | 1 + src/torrent-cell-renderer.c | 2 - src/trg-rss-cell-renderer.c | 414 ++++++++++++++++++++++++++++++++++++++++++++ src/trg-rss-cell-renderer.h | 55 ++++++ src/trg-rss-model.c | 1 + src/trg-rss-model.h | 1 + src/trg-rss-window.c | 11 +- src/trg-toolbar.h | 1 - src/util.h | 1 + 9 files changed, 481 insertions(+), 6 deletions(-) create mode 100644 src/trg-rss-cell-renderer.c create mode 100644 src/trg-rss-cell-renderer.h (limited to 'src') diff --git a/src/Makefile.am b/src/Makefile.am index fc4902e..7cb7801 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -107,6 +107,7 @@ transmission_remote_gtk_SOURCES = \ main.c \ trg-rss-model.c \ trg-rss-window.c \ + trg-rss-cell-renderer.c \ upload.c \ $(NULL) diff --git a/src/torrent-cell-renderer.c b/src/torrent-cell-renderer.c index 654d7bd..5c6abd2 100644 --- a/src/torrent-cell-renderer.c +++ b/src/torrent-cell-renderer.c @@ -445,8 +445,6 @@ get_size_compact(TorrentCellRenderer * cell, g_object_unref(icon); } -#define MAX3(a,b,c) MAX(a,MAX(b,c)) - static void get_size_full(TorrentCellRenderer * cell, GtkWidget * widget, gint * width, gint * height) diff --git a/src/trg-rss-cell-renderer.c b/src/trg-rss-cell-renderer.c new file mode 100644 index 0000000..5cae5c7 --- /dev/null +++ b/src/trg-rss-cell-renderer.c @@ -0,0 +1,414 @@ +#include "config.h" + +#ifdef HAVE_RSSGLIB + +#include +#include +#include + +#include "icons.h" +#include "hig.h" +#include "util.h" +#include "trg-rss-cell-renderer.h" + +enum { + PROP_TITLE = 1, + PROP_FEED, + PROP_PUBLISHED +}; + +#define SMALL_SCALE 0.9 +#define COMPACT_ICON_SIZE GTK_ICON_SIZE_MENU +#define FULL_ICON_SIZE GTK_ICON_SIZE_DND + +#define FOREGROUND_COLOR_KEY "foreground-rgba" +typedef GdkRGBA GtrColor; +typedef cairo_t GtrDrawable; +typedef GtkRequisition GtrRequisition; + +struct TrgRssCellRendererPrivate { + GtkCellRenderer *text_renderer; + GtkCellRenderer *icon_renderer; + GString *gstr1; + GString *gstr2; + gchar *title; + gchar *published; + gchar *feed; +}; + +static void +trg_rss_cell_renderer_render(GtkCellRenderer * cell, + GtrDrawable * window, GtkWidget * widget, + const GdkRectangle * background_area, + const GdkRectangle * cell_area, + GtkCellRendererState flags); + +static void +gtr_cell_renderer_render(GtkCellRenderer * renderer, + GtrDrawable * drawable, + GtkWidget * widget, + const GdkRectangle * area, + GtkCellRendererState flags) +{ + gtk_cell_renderer_render(renderer, drawable, widget, area, area, + flags); +} + +static void trg_rss_cell_renderer_set_property(GObject * object, + guint property_id, + const GValue * v, + GParamSpec * pspec) +{ + TrgRssCellRenderer *self = TRG_RSS_CELL_RENDERER(object); + struct TrgRssCellRendererPrivate *p = self->priv; + + switch (property_id) { + case PROP_TITLE: + g_free(p->title); + p->title = g_value_dup_string(v); + break; + case PROP_PUBLISHED: + g_free(p->published); + p->published = g_value_dup_string(v); + break; + case PROP_FEED: + g_free(p->feed); + p->feed = g_value_dup_string(v); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID(object, property_id, pspec); + break; + } +} + +static void +trg_rss_cell_renderer_get_property(GObject * object, + guint property_id, + GValue * v, GParamSpec * pspec) +{ + G_OBJECT_WARN_INVALID_PROPERTY_ID(object, property_id, pspec); +} + +G_DEFINE_TYPE(TrgRssCellRenderer, trg_rss_cell_renderer, + GTK_TYPE_CELL_RENDERER) + +static void trg_rss_cell_renderer_dispose(GObject * o) +{ + TrgRssCellRenderer *r = TRG_RSS_CELL_RENDERER(o); + + if (r && r->priv) { + struct TrgRssCellRendererPrivate *priv = r->priv; + + g_string_free(priv->gstr1, TRUE); + g_free(priv->feed); + g_free(priv->published); + g_free(priv->title); + g_object_unref(G_OBJECT(priv->text_renderer)); + g_object_unref(G_OBJECT(priv->icon_renderer)); + r->priv = NULL; + } + + G_OBJECT_CLASS(trg_rss_cell_renderer_parent_class)->dispose(o); +} + +static GdkPixbuf *get_icon(TrgRssCellRenderer * r, GtkIconSize icon_size, + GtkWidget * for_widget) +{ + const char *mime_type = "file"; + + return gtr_get_mime_type_icon(mime_type, icon_size, for_widget); +} + +static void +trg_rss_cell_renderer_get_size(GtkCellRenderer * cell, GtkWidget * widget, + const GdkRectangle * cell_area, + gint * x_offset, + gint * y_offset, + gint * width, gint * height) +{ + TrgRssCellRenderer *self = TRG_RSS_CELL_RENDERER(cell); + + if (self) { + struct TrgRssCellRendererPrivate *p = self->priv; + int xpad, ypad; + int h, w; + GtkRequisition icon_size; + GtkRequisition name_size; + GtkRequisition stat_size; + GtkRequisition prog_size; + GdkPixbuf *icon; + + icon = get_icon(self, FULL_ICON_SIZE, widget); + + gtk_cell_renderer_get_padding(cell, &xpad, &ypad); + + /* get the idealized cell dimensions */ + g_object_set(p->icon_renderer, "pixbuf", icon, NULL); + gtk_cell_renderer_get_preferred_size(p->icon_renderer, widget, NULL, + &icon_size); + g_object_set(p->text_renderer, "text", p->title, + "weight", PANGO_WEIGHT_BOLD, "scale", 1.0, "ellipsize", + PANGO_ELLIPSIZE_NONE, NULL); + gtk_cell_renderer_get_preferred_size(p->text_renderer, widget, NULL, + &name_size); + g_object_set(p->text_renderer, "text", p->feed, "weight", + PANGO_WEIGHT_NORMAL, "scale", SMALL_SCALE, NULL); + gtk_cell_renderer_get_preferred_size(p->text_renderer, widget, NULL, + &prog_size); + g_object_set(p->text_renderer, "text", p->published, NULL); + gtk_cell_renderer_get_preferred_size(p->text_renderer, widget, NULL, + &stat_size); + + /** + *** LAYOUT + **/ + + if (width != NULL) + *width = w = + xpad * 2 + icon_size.width + GUI_PAD + MAX3(name_size.width, + prog_size.width, + stat_size.width); + if (height != NULL) + *height = h = + ypad * 2 + name_size.height + prog_size.height + + GUI_PAD_SMALL + stat_size.height; + + /* cleanup */ + g_object_unref(icon); + + if (x_offset) + *x_offset = cell_area ? cell_area->x : 0; + + if (y_offset) { + int xpad, ypad; + gtk_cell_renderer_get_padding(cell, &xpad, &ypad); + *y_offset = + cell_area ? (int) ((cell_area->height - (ypad * 2 + h)) / + 2.0) : 0; + } + } +} + +static void +trg_rss_cell_renderer_class_init(TrgRssCellRendererClass * klass) +{ + GObjectClass *gobject_class = G_OBJECT_CLASS(klass); + GtkCellRendererClass *cell_class = GTK_CELL_RENDERER_CLASS(klass); + + g_type_class_add_private(klass, + sizeof(struct TrgRssCellRendererPrivate)); + + cell_class->render = trg_rss_cell_renderer_render; + cell_class->get_size = trg_rss_cell_renderer_get_size; + gobject_class->set_property = trg_rss_cell_renderer_set_property; + gobject_class->get_property = trg_rss_cell_renderer_get_property; + gobject_class->dispose = trg_rss_cell_renderer_dispose; + + g_object_class_install_property(gobject_class, + PROP_TITLE, + g_param_spec_string("title", + "title", + "Title", + NULL, + G_PARAM_READWRITE | + G_PARAM_STATIC_NAME + | + G_PARAM_STATIC_NICK + | + G_PARAM_STATIC_BLURB)); + + g_object_class_install_property(gobject_class, + PROP_PUBLISHED, + g_param_spec_string("published", + "published", + "Published", + NULL, + G_PARAM_READWRITE | + G_PARAM_STATIC_NAME + | + G_PARAM_STATIC_NICK + | + G_PARAM_STATIC_BLURB)); + + g_object_class_install_property(gobject_class, + PROP_FEED, + g_param_spec_string("feed", + "feed", + "Feed", + NULL, + G_PARAM_READWRITE | + G_PARAM_STATIC_NAME + | + G_PARAM_STATIC_NICK + | + G_PARAM_STATIC_BLURB)); + + /*g_object_class_install_property(gobject_class, P_BAR_HEIGHT, + g_param_spec_int("bar-height", NULL, + "Bar Height", + 1, INT_MAX, + DEFAULT_BAR_HEIGHT, + G_PARAM_READWRITE));*/ + +} + +static void trg_rss_cell_renderer_init(TrgRssCellRenderer * self) +{ + struct TrgRssCellRendererPrivate *p; + + p = self->priv = G_TYPE_INSTANCE_GET_PRIVATE(self, + TRG_RSS_CELL_RENDERER_TYPE, + struct + TrgRssCellRendererPrivate); + + p->gstr1 = g_string_new(NULL); + p->gstr2 = g_string_new(NULL); + p->text_renderer = gtk_cell_renderer_text_new(); + g_object_set(p->text_renderer, "xpad", 0, "ypad", 0, NULL); + p->icon_renderer = gtk_cell_renderer_pixbuf_new(); + g_object_ref_sink(p->text_renderer); + g_object_ref_sink(p->icon_renderer); +} + + +GtkCellRenderer *trg_rss_cell_renderer_new(void) +{ + return (GtkCellRenderer *) g_object_new(TRG_RSS_CELL_RENDERER_TYPE, + NULL); +} + +static void +get_text_color(TrgRssCellRenderer * r, GtkWidget * widget, + GtrColor * setme) +{ + /*struct TrgRssCellRendererPrivate *p = r->priv; + static const GdkRGBA red = { 1.0, 0, 0, 0 }; + + if (p->error) + *setme = red; + else if (p->flags & TORRENT_FLAG_PAUSED) + gtk_style_context_get_color(gtk_widget_get_style_context(widget), + GTK_STATE_FLAG_INSENSITIVE, setme); + else*/ + gtk_style_context_get_color(gtk_widget_get_style_context(widget), + GTK_STATE_FLAG_NORMAL, setme); +} + +static void +trg_rss_cell_renderer_render(GtkCellRenderer * cell, + GtrDrawable * window, GtkWidget * widget, + const GdkRectangle * background_area, + const GdkRectangle * cell_area, + GtkCellRendererState flags) +{ + TrgRssCellRenderer *self = TRG_RSS_CELL_RENDERER(cell); + int xpad, ypad; + GtkRequisition size; + GdkRectangle fill_area; + GdkRectangle icon_area; + GdkRectangle name_area; + GdkRectangle stat_area; + GdkRectangle prog_area; + GdkRectangle prct_area; + GdkPixbuf *icon; + GtrColor text_color; + struct TrgRssCellRendererPrivate *p; + + if (!self) + return; + + p = self->priv; + + icon = get_icon(self, FULL_ICON_SIZE, widget); + gtk_cell_renderer_get_padding(GTK_CELL_RENDERER(cell), &xpad, &ypad); + get_text_color(self, widget, &text_color); + + /* get the idealized cell dimensions */ + g_object_set(p->icon_renderer, "pixbuf", icon, NULL); + gtk_cell_renderer_get_preferred_size(p->icon_renderer, widget, NULL, + &size); + icon_area.width = size.width; + icon_area.height = size.height; + g_object_set(p->text_renderer, "text", p->title, + "weight", PANGO_WEIGHT_BOLD, "ellipsize", + PANGO_ELLIPSIZE_NONE, "scale", 1.0, NULL); + gtk_cell_renderer_get_preferred_size(p->text_renderer, widget, NULL, + &size); + name_area.width = size.width; + name_area.height = size.height; + g_object_set(p->text_renderer, "text", p->feed, "weight", + PANGO_WEIGHT_NORMAL, "scale", SMALL_SCALE, NULL); + gtk_cell_renderer_get_preferred_size(p->text_renderer, widget, NULL, + &size); + prog_area.width = size.width; + prog_area.height = size.height; + g_object_set(p->text_renderer, "text", p->published, NULL); + gtk_cell_renderer_get_preferred_size(p->text_renderer, widget, NULL, + &size); + stat_area.width = size.width; + stat_area.height = size.height; + + /** + *** LAYOUT + **/ + + fill_area = *background_area; + fill_area.x += xpad; + fill_area.y += ypad; + fill_area.width -= xpad * 2; + fill_area.height -= ypad * 2; + + /* icon */ + icon_area.x = fill_area.x; + icon_area.y = fill_area.y + (fill_area.height - icon_area.height) / 2; + + /* name */ + name_area.x = icon_area.x + icon_area.width + GUI_PAD; + name_area.y = fill_area.y; + name_area.width = + fill_area.width - GUI_PAD - icon_area.width - GUI_PAD_SMALL; + + /* prog */ + prog_area.x = name_area.x; + prog_area.y = name_area.y + name_area.height; + prog_area.width = name_area.width; + + /* progressbar */ + prct_area.x = prog_area.x; + prct_area.y = prog_area.y + prog_area.height + GUI_PAD_SMALL; + prct_area.width = prog_area.width; + prct_area.height = 0; + + /* status */ + stat_area.x = prct_area.x; + stat_area.y = prct_area.y + prct_area.height + GUI_PAD_SMALL; + stat_area.width = prct_area.width; + + /** + *** RENDER + **/ + + g_object_set(p->icon_renderer, "pixbuf", icon, "sensitive", TRUE, + NULL); + gtr_cell_renderer_render(p->icon_renderer, window, widget, &icon_area, + flags); + g_object_set(p->text_renderer, "text", p->title, + "scale", 1.0, FOREGROUND_COLOR_KEY, &text_color, + "ellipsize", PANGO_ELLIPSIZE_END, "weight", + PANGO_WEIGHT_BOLD, NULL); + gtr_cell_renderer_render(p->text_renderer, window, widget, &name_area, + flags); + g_object_set(p->text_renderer, "text", p->feed, "scale", + SMALL_SCALE, "weight", PANGO_WEIGHT_NORMAL, NULL); + gtr_cell_renderer_render(p->text_renderer, window, widget, &prog_area, + flags); + g_object_set(p->text_renderer, "text", p->published, + FOREGROUND_COLOR_KEY, &text_color, NULL); + gtr_cell_renderer_render(p->text_renderer, window, widget, &stat_area, + flags); + + /* cleanup */ + g_object_unref(icon); +} + +#endif diff --git a/src/trg-rss-cell-renderer.h b/src/trg-rss-cell-renderer.h new file mode 100644 index 0000000..a255d90 --- /dev/null +++ b/src/trg-rss-cell-renderer.h @@ -0,0 +1,55 @@ +/* + * transmission-remote-gtk - A GTK RPC client to Transmission + * Copyright (C) 2011-2013 Alan Fitton + + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#ifndef TRG_RSS_CELL_RENDERER_H +#define TRG_RSS_CELL_RENDERER_H + +#include "config.h" + +#ifdef HAVE_RSSGLIB + +#include + +#define TRG_RSS_CELL_RENDERER_TYPE ( trg_rss_cell_renderer_get_type( ) ) + +#define TRG_RSS_CELL_RENDERER( o ) \ + ( G_TYPE_CHECK_INSTANCE_CAST( ( o ), \ + TRG_RSS_CELL_RENDERER_TYPE, \ + TrgRssCellRenderer ) ) + +typedef struct TrgRssCellRenderer TrgRssCellRenderer; + +typedef struct TrgRssCellRendererClass TrgRssCellRendererClass; + +struct TrgRssCellRenderer { + GtkCellRenderer parent; + struct TrgRssCellRendererPrivate *priv; +}; + +struct TrgRssCellRendererClass { + GtkCellRendererClass parent; +}; + +GType trg_rss_cell_renderer_get_type(void) G_GNUC_CONST; + +GtkCellRenderer *trg_rss_cell_renderer_new(void); + +#endif + +#endif /* TRG_RSS_CELL_RENDERER_H */ diff --git a/src/trg-rss-model.c b/src/trg-rss-model.c index 813652f..b6ee229 100644 --- a/src/trg-rss-model.c +++ b/src/trg-rss-model.c @@ -245,6 +245,7 @@ static void trg_rss_model_init(TrgRssModel * self) { column_types[RSSCOL_LINK] = G_TYPE_STRING; column_types[RSSCOL_FEED] = G_TYPE_STRING; column_types[RSSCOL_PUBDATE] = G_TYPE_STRING; + column_types[RSSCOL_SENSITIVE] = G_TYPE_BOOLEAN; gtk_list_store_set_column_types(GTK_LIST_STORE(self), RSSCOL_COLUMNS, column_types); diff --git a/src/trg-rss-model.h b/src/trg-rss-model.h index a931c37..8ddddd4 100644 --- a/src/trg-rss-model.h +++ b/src/trg-rss-model.h @@ -77,6 +77,7 @@ enum { RSSCOL_LINK, RSSCOL_FEED, RSSCOL_PUBDATE, + RSSCOL_SENSITIVE, RSSCOL_COLUMNS }; diff --git a/src/trg-rss-window.c b/src/trg-rss-window.c index 224cbb7..c4091a5 100644 --- a/src/trg-rss-window.c +++ b/src/trg-rss-window.c @@ -27,6 +27,7 @@ #include "trg-rss-window.h" #include "trg-rss-model.h" +#include "trg-rss-cell-renderer.h" #include "trg-torrent-add-dialog.h" #include "trg-client.h" #include "upload.h" @@ -189,7 +190,7 @@ static GObject *trg_rss_window_constructor(GType type, TrgRssModel *model; GtkTreeView *view; GtkWidget *vbox; - GtkToolItem *item; + //GtkToolItem *item; object = G_OBJECT_CLASS (trg_rss_window_parent_class)->constructor(type, @@ -207,11 +208,13 @@ static GObject *trg_rss_window_constructor(GType type, trg_rss_model_update(model); view = GTK_TREE_VIEW(gtk_tree_view_new()); + gtk_tree_view_set_headers_visible(view, FALSE); gtk_tree_view_set_model(view, GTK_TREE_MODEL(model)); - gtk_tree_view_insert_column_with_attributes(view, -1, "Title", gtk_cell_renderer_text_new(), "text", RSSCOL_TITLE, NULL); + /*gtk_tree_view_insert_column_with_attributes(view, -1, "Title", gtk_cell_renderer_text_new(), "text", RSSCOL_TITLE, NULL); gtk_tree_view_insert_column_with_attributes(view, -1, "Feed", gtk_cell_renderer_text_new(), "text", RSSCOL_FEED, NULL); gtk_tree_view_insert_column_with_attributes(view, -1, "Published", gtk_cell_renderer_text_new(), "text", RSSCOL_PUBDATE, NULL); - gtk_tree_view_insert_column_with_attributes(view, -1, "URL", gtk_cell_renderer_text_new(), "text", RSSCOL_LINK, NULL); + gtk_tree_view_insert_column_with_attributes(view, -1, "URL", gtk_cell_renderer_text_new(), "text", RSSCOL_LINK, NULL);*/ + gtk_tree_view_insert_column_with_attributes(view, -1, NULL, trg_rss_cell_renderer_new(), "title", RSSCOL_TITLE, "feed", RSSCOL_FEED, "published", RSSCOL_PUBDATE, NULL); g_signal_connect(view, "row-activated", G_CALLBACK(rss_item_activated), object); @@ -237,6 +240,8 @@ static GObject *trg_rss_window_constructor(GType type, /*g_signal_connect(object, "response", G_CALLBACK(trg_rss_window_response_cb), NULL);*/ + gtk_widget_set_size_request(GTK_WIDGET(object), 500, 300); + return object; } diff --git a/src/trg-toolbar.h b/src/trg-toolbar.h index 7d12b2d..6887a16 100644 --- a/src/trg-toolbar.h +++ b/src/trg-toolbar.h @@ -17,7 +17,6 @@ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ - #ifndef TRG_TOOLBAR_H_ #define TRG_TOOLBAR_H_ diff --git a/src/util.h b/src/util.h index 351f565..8134952 100644 --- a/src/util.h +++ b/src/util.h @@ -32,6 +32,7 @@ #define trg_strlpercent(a, b) tr_strlpercent(a, b, sizeof(a)) #define trg_strlsize(a, b) tr_formatter_size_B(a, b, sizeof(a)) #define trg_strlratio(a, b) tr_strlratio(a, b, sizeof(a)) +#define MAX3(a,b,c) MAX(a,MAX(b,c)) #define TR_RATIO_NA -1 #define TR_RATIO_INF -2 -- cgit v1.2.3 From 56a60210894a344d66ec3c77f807c2867491f45d Mon Sep 17 00:00:00 2001 From: Alan F Date: Sun, 9 Mar 2014 17:25:32 +0000 Subject: hacking to support the options dialog from rss feeds --- src/trg-client.c | 4 +- src/trg-destination-combo.c | 2 +- src/trg-file-parser.c | 56 +++++++++-------- src/trg-main-window.c | 1 + src/trg-preferences-dialog.c | 8 ++- src/trg-preferences-dialog.h | 1 + src/trg-rss-cell-renderer.c | 29 ++++++--- src/trg-rss-model.c | 3 +- src/trg-rss-model.h | 2 +- src/trg-rss-window.c | 141 +++++++++++++++++++++++++++++-------------- src/trg-torrent-add-dialog.c | 99 ++++++++++++++++++++---------- src/trg-torrent-add-dialog.h | 6 +- src/upload.c | 63 +++++++++++++++---- src/upload.h | 7 ++- 14 files changed, 296 insertions(+), 126 deletions(-) (limited to 'src') diff --git a/src/trg-client.c b/src/trg-client.c index 7e1a784..f03e893 100644 --- a/src/trg-client.c +++ b/src/trg-client.c @@ -532,7 +532,7 @@ static CURL* get_curl(TrgClient *tc, guint http_class) curl_easy_setopt(curl, CURLOPT_USERAGENT, PACKAGE_NAME); curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, &http_receive_callback); - curl_easy_setopt(curl, CURLOPT_VERBOSE, 1); + //curl_easy_setopt(curl, CURLOPT_VERBOSE, 1); if (http_class == HTTP_CLASS_TRANSMISSION) { curl_easy_setopt(curl, CURLOPT_WRITEHEADER, (void *) tc); @@ -633,7 +633,7 @@ trg_response *dispatch(TrgClient * tc, JsonNode * req) json_node_free(req); #ifdef DEBUG if (g_getenv("TRG_SHOW_OUTGOING")) - g_debug("=>(OUTgoing)=>: %s", serialized); + g_message("=>(OUTgoing)=>: %s", serialized); #endif return dispatch_str(tc, serialized); } diff --git a/src/trg-destination-combo.c b/src/trg-destination-combo.c index 099b6a5..f7fc2f0 100644 --- a/src/trg-destination-combo.c +++ b/src/trg-destination-combo.c @@ -397,7 +397,7 @@ gchar *trg_destination_combo_get_dir(TrgDestinationCombo * combo) if (type == DEST_LABEL) { gtk_tree_model_get(model, &iter, DEST_COLUMN_DIR, &value, -1); - return value; + return g_strdup(value); } } diff --git a/src/trg-file-parser.c b/src/trg-file-parser.c index fbfb6aa..ff4ac62 100644 --- a/src/trg-file-parser.c +++ b/src/trg-file-parser.c @@ -134,32 +134,11 @@ static trg_files_tree_node *trg_parse_torrent_file_nodes(be_node * return top_node; } -trg_torrent_file *trg_parse_torrent_file(const gchar * filename) -{ - GError *error = NULL; - GMappedFile *mf; - be_node *top_node, *info_node, *name_node; - trg_torrent_file *ret = NULL; - - if (!g_file_test(filename, G_FILE_TEST_IS_REGULAR)) { - g_message("%s does not exist", filename); - return NULL; - } - - mf = g_mapped_file_new(filename, FALSE, &error); +trg_torrent_file *trg_parse_torrent_data(const gchar *data, gsize length) { + trg_torrent_file *ret = NULL; + be_node *top_node, *info_node, *name_node; - if (error) { - g_error("%s", error->message); - g_error_free(error); - g_mapped_file_unref(mf); - return NULL; - } else { - top_node = - be_decoden(g_mapped_file_get_contents(mf), - g_mapped_file_get_length(mf)); - } - - g_mapped_file_unref(mf); + top_node = be_decoden(data, length); if (!top_node) { return NULL; @@ -199,3 +178,30 @@ trg_torrent_file *trg_parse_torrent_file(const gchar * filename) be_free(top_node); return ret; } + +trg_torrent_file *trg_parse_torrent_file(const gchar * filename) +{ + GError *error = NULL; + trg_torrent_file *ret = NULL; + GMappedFile *mf; + + if (!g_file_test(filename, G_FILE_TEST_IS_REGULAR)) { + g_message("%s does not exist", filename); + return NULL; + } + + mf = g_mapped_file_new(filename, FALSE, &error); + + if (error) { + g_error("%s", error->message); + g_error_free(error); + g_mapped_file_unref(mf); + return NULL; + } else { + ret = trg_parse_torrent_data(g_mapped_file_get_contents(mf), g_mapped_file_get_length(mf)); + } + + g_mapped_file_unref(mf); + + return ret; +} diff --git a/src/trg-main-window.c b/src/trg-main-window.c index 32212f6..4cf6047 100644 --- a/src/trg-main-window.c +++ b/src/trg-main-window.c @@ -941,6 +941,7 @@ static void view_rss_toggled_cb(GtkWidget * w, gpointer data) trg_rss_window_get_instance(TRG_MAIN_WINDOW(data), priv->client); gtk_widget_show_all(GTK_WIDGET(rss)); + gtk_window_present(GTK_WINDOW(rss)); } } #endif diff --git a/src/trg-preferences-dialog.c b/src/trg-preferences-dialog.c index e7434d3..53e4fe9 100644 --- a/src/trg-preferences-dialog.c +++ b/src/trg-preferences-dialog.c @@ -58,6 +58,7 @@ struct _TrgPreferencesDialogPrivate { GtkWidget *profileNameEntry; GtkWidget *fullUpdateCheck; GList *widgets; + GtkWidget *notebook; }; static GObject *instance = NULL; @@ -928,7 +929,7 @@ static GObject *trg_preferences_dialog_constructor(GType type, g_signal_connect(G_OBJECT(object), "response", G_CALLBACK(trg_preferences_response_cb), NULL); - notebook = gtk_notebook_new(); + notebook = priv->notebook = gtk_notebook_new(); gtk_notebook_append_page(GTK_NOTEBOOK(notebook), trg_prefs_serverPage(TRG_PREFERENCES_DIALOG @@ -969,6 +970,11 @@ static GObject *trg_preferences_dialog_constructor(GType type, return object; } +void trg_preferences_dialog_set_page(TrgPreferencesDialog *pref_dlg, guint page) { + TrgPreferencesDialogPrivate *priv = TRG_PREFERENCES_DIALOG_GET_PRIVATE(pref_dlg); + gtk_notebook_set_current_page(GTK_NOTEBOOK(priv->notebook), page); +} + static void trg_preferences_dialog_init(TrgPreferencesDialog * pref_dlg) { } diff --git a/src/trg-preferences-dialog.h b/src/trg-preferences-dialog.h index f5e9825..e163964 100644 --- a/src/trg-preferences-dialog.h +++ b/src/trg-preferences-dialog.h @@ -60,6 +60,7 @@ GtkWidget *trg_preferences_dialog_get_instance(TrgMainWindow * win, TrgClient * client); trg_pref_widget_desc *trg_pref_widget_desc_new(GtkWidget * w, gchar * key, int flags); +void trg_preferences_dialog_set_page(TrgPreferencesDialog *pref_dlg, guint page); G_END_DECLS #endif /* TRG_PREFERENCES_WINDOW_H_ */ diff --git a/src/trg-rss-cell-renderer.c b/src/trg-rss-cell-renderer.c index 5cae5c7..4765f2c 100644 --- a/src/trg-rss-cell-renderer.c +++ b/src/trg-rss-cell-renderer.c @@ -14,7 +14,8 @@ enum { PROP_TITLE = 1, PROP_FEED, - PROP_PUBLISHED + PROP_PUBLISHED, + PROP_UPLOADED }; #define SMALL_SCALE 0.9 @@ -34,6 +35,7 @@ struct TrgRssCellRendererPrivate { gchar *title; gchar *published; gchar *feed; + gboolean uploaded; }; static void @@ -75,6 +77,9 @@ static void trg_rss_cell_renderer_set_property(GObject * object, g_free(p->feed); p->feed = g_value_dup_string(v); break; + case PROP_UPLOADED: + p->uploaded = g_value_get_boolean(v); + break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID(object, property_id, pspec); break; @@ -243,6 +248,19 @@ trg_rss_cell_renderer_class_init(TrgRssCellRendererClass * klass) | G_PARAM_STATIC_BLURB)); + g_object_class_install_property(gobject_class, + PROP_UPLOADED, + g_param_spec_boolean("uploaded", + "uploaded", + "Uploaded", + FALSE, + G_PARAM_READWRITE | + G_PARAM_STATIC_NAME + | + G_PARAM_STATIC_NICK + | + G_PARAM_STATIC_BLURB)); + /*g_object_class_install_property(gobject_class, P_BAR_HEIGHT, g_param_spec_int("bar-height", NULL, "Bar Height", @@ -281,15 +299,12 @@ static void get_text_color(TrgRssCellRenderer * r, GtkWidget * widget, GtrColor * setme) { - /*struct TrgRssCellRendererPrivate *p = r->priv; - static const GdkRGBA red = { 1.0, 0, 0, 0 }; + struct TrgRssCellRendererPrivate *p = r->priv; - if (p->error) - *setme = red; - else if (p->flags & TORRENT_FLAG_PAUSED) + if (p->uploaded) gtk_style_context_get_color(gtk_widget_get_style_context(widget), GTK_STATE_FLAG_INSENSITIVE, setme); - else*/ + else gtk_style_context_get_color(gtk_widget_get_style_context(widget), GTK_STATE_FLAG_NORMAL, setme); } diff --git a/src/trg-rss-model.c b/src/trg-rss-model.c index b6ee229..f898f34 100644 --- a/src/trg-rss-model.c +++ b/src/trg-rss-model.c @@ -49,6 +49,7 @@ typedef struct _TrgRssModelPrivate TrgRssModelPrivate; struct _TrgRssModelPrivate { TrgClient *client; GHashTable *table; + guint index; }; typedef struct { @@ -245,7 +246,7 @@ static void trg_rss_model_init(TrgRssModel * self) { column_types[RSSCOL_LINK] = G_TYPE_STRING; column_types[RSSCOL_FEED] = G_TYPE_STRING; column_types[RSSCOL_PUBDATE] = G_TYPE_STRING; - column_types[RSSCOL_SENSITIVE] = G_TYPE_BOOLEAN; + column_types[RSSCOL_UPLOADED] = G_TYPE_BOOLEAN; gtk_list_store_set_column_types(GTK_LIST_STORE(self), RSSCOL_COLUMNS, column_types); diff --git a/src/trg-rss-model.h b/src/trg-rss-model.h index 8ddddd4..206ee41 100644 --- a/src/trg-rss-model.h +++ b/src/trg-rss-model.h @@ -77,7 +77,7 @@ enum { RSSCOL_LINK, RSSCOL_FEED, RSSCOL_PUBDATE, - RSSCOL_SENSITIVE, + RSSCOL_UPLOADED, RSSCOL_COLUMNS }; diff --git a/src/trg-rss-window.c b/src/trg-rss-window.c index c4091a5..64c1452 100644 --- a/src/trg-rss-window.c +++ b/src/trg-rss-window.c @@ -29,6 +29,7 @@ #include "trg-rss-model.h" #include "trg-rss-cell-renderer.h" #include "trg-torrent-add-dialog.h" +#include "trg-preferences-dialog.h" #include "trg-client.h" #include "upload.h" #include "util.h" @@ -46,6 +47,8 @@ typedef struct _TrgRssWindowPrivate TrgRssWindowPrivate; struct _TrgRssWindowPrivate { TrgMainWindow *parent; TrgClient *client; + GtkTreeView *tree_view; + TrgRssModel *tree_model; }; static GObject *instance = NULL; @@ -91,35 +94,57 @@ trg_rss_window_set_property(GObject * object, } } +static gboolean upload_complete_searchfunc(GtkTreeModel *model, + GtkTreePath *path, + GtkTreeIter *iter, + gpointer data) { + trg_upload *upload = (trg_upload*)data; + gchar *item_guid = NULL; + + gtk_tree_model_get(model, iter, RSSCOL_ID, &item_guid, -1); + + if (!g_strcmp0(item_guid, upload->uid)) { + gtk_list_store_set(GTK_LIST_STORE(model), iter, RSSCOL_UPLOADED, TRUE, -1); + return TRUE; + } + + return FALSE; +} + +static gboolean on_upload_complete(gpointer data) { + trg_response *response = (trg_response*)data; + trg_upload *upload = (trg_upload*)response->cb_data; + TrgRssWindowPrivate *priv = TRG_RSS_WINDOW_GET_PRIVATE(upload->cb_data); + + if (response->status == CURLE_OK) + gtk_tree_model_foreach(GTK_TREE_MODEL(priv->tree_model), upload_complete_searchfunc, upload); + + return FALSE; +} + static gboolean on_torrent_receive(gpointer data) { trg_response *response = (trg_response *) data; - TrgRssWindow *win = TRG_RSS_WINDOW(response->cb_data); - TrgRssWindowPrivate *priv = TRG_RSS_WINDOW_GET_PRIVATE(response->cb_data); + trg_upload *upload = (trg_upload*)response->cb_data; + TrgRssWindowPrivate *priv = TRG_RSS_WINDOW_GET_PRIVATE(upload->cb_data); TrgClient *client = priv->client; TrgPrefs *prefs = trg_client_get_prefs(client); TrgMainWindow *main_win = priv->parent; + upload->upload_response = response; + if (response->status == CURLE_OK) { if (trg_prefs_get_bool(prefs, TRG_PREFS_KEY_ADD_OPTIONS_DIALOG, TRG_PREFS_GLOBAL)) { - /*TrgTorrentAddDialog *dialog = - trg_torrent_add_dialog_new_from_filenames(main_win, client, - filesList); - gtk_widget_show_all(GTK_WIDGET(dialog));*/ + TrgTorrentAddDialog *dialog = + trg_torrent_add_dialog_new_from_upload(main_win, client, + upload); + gtk_widget_show_all(GTK_WIDGET(dialog)); } else { - trg_upload *upload = g_new0(trg_upload, 1); - - upload->upload_response = response; - upload->main_window = main_win; - upload->client = client; - upload->extra_args = FALSE; - upload->flags = trg_prefs_get_add_flags(prefs); - - trg_do_upload(upload); + trg_do_upload(upload); } } else { - trg_error_dialog(GTK_WINDOW(win), response); - trg_response_free(response); + trg_error_dialog(GTK_WINDOW(main_win), response); + trg_upload_free(upload); } return FALSE; @@ -133,15 +158,28 @@ rss_item_activated(GtkTreeView * treeview, { TrgRssWindow *win = TRG_RSS_WINDOW(userdata); TrgRssWindowPrivate *priv = TRG_RSS_WINDOW_GET_PRIVATE(win); + TrgClient *client = priv->client; + TrgPrefs *prefs = trg_client_get_prefs(client); GtkTreeModel *model = gtk_tree_view_get_model(treeview); + trg_upload *upload = g_new0(trg_upload, 1); GtkTreeIter iter; - gchar *link; + gchar *link, *uid; + + //upload->upload_response = response; + upload->main_window = priv->parent; + upload->client = client; + upload->extra_args = FALSE; + upload->flags = trg_prefs_get_add_flags(prefs); + upload->callback = on_upload_complete; + upload->cb_data = win; gtk_tree_model_get_iter(model, &iter, path); - gtk_tree_model_get(model, &iter, RSSCOL_LINK, &link, -1); + gtk_tree_model_get(model, &iter, RSSCOL_LINK, &link, RSSCOL_ID, &uid, -1); + + upload->uid = uid; - async_http_request(priv->client, link, on_torrent_receive, userdata); + async_http_request(priv->client, link, on_torrent_receive, upload); g_free(link); } @@ -179,6 +217,18 @@ static void trg_rss_on_parse_error(TrgRssModel *model, rss_parse_error *error, g gtk_widget_destroy(dialog); } +static void on_configure(GtkWidget *widget, gpointer data) { + TrgRssWindowPrivate *priv = TRG_RSS_WINDOW_GET_PRIVATE(data); + GtkWidget *dlg = trg_preferences_dialog_get_instance(priv->parent, priv->client); + gtk_widget_show_all(dlg); + trg_preferences_dialog_set_page(TRG_PREFERENCES_DIALOG(dlg), 5); +} + +static void on_refresh(GtkWidget *widget, gpointer data) { + TrgRssWindowPrivate *priv = TRG_RSS_WINDOW_GET_PRIVATE(data); + trg_rss_model_update(priv->tree_model); +} + static GObject *trg_rss_window_constructor(GType type, guint n_construct_properties, @@ -187,10 +237,9 @@ static GObject *trg_rss_window_constructor(GType type, { GObject *object; TrgRssWindowPrivate *priv; - TrgRssModel *model; - GtkTreeView *view; GtkWidget *vbox; - //GtkToolItem *item; + GtkToolItem *item; + GtkWidget *toolbar; object = G_OBJECT_CLASS (trg_rss_window_parent_class)->constructor(type, @@ -198,41 +247,45 @@ static GObject *trg_rss_window_constructor(GType type, construct_params); priv = TRG_RSS_WINDOW_GET_PRIVATE(object); - model = trg_rss_model_new(priv->client); + priv->tree_model = trg_rss_model_new(priv->client); - g_signal_connect(model, "get-error", - G_CALLBACK(trg_rss_on_get_error), NULL); - g_signal_connect(model, "parse-error", - G_CALLBACK(trg_rss_on_parse_error), NULL); + g_signal_connect(priv->tree_model, "get-error", + G_CALLBACK(trg_rss_on_get_error), object); + g_signal_connect(priv->tree_model, "parse-error", + G_CALLBACK(trg_rss_on_parse_error), object); - trg_rss_model_update(model); + trg_rss_model_update(priv->tree_model); - view = GTK_TREE_VIEW(gtk_tree_view_new()); - gtk_tree_view_set_headers_visible(view, FALSE); - gtk_tree_view_set_model(view, GTK_TREE_MODEL(model)); - /*gtk_tree_view_insert_column_with_attributes(view, -1, "Title", gtk_cell_renderer_text_new(), "text", RSSCOL_TITLE, NULL); - gtk_tree_view_insert_column_with_attributes(view, -1, "Feed", gtk_cell_renderer_text_new(), "text", RSSCOL_FEED, NULL); - gtk_tree_view_insert_column_with_attributes(view, -1, "Published", gtk_cell_renderer_text_new(), "text", RSSCOL_PUBDATE, NULL); - gtk_tree_view_insert_column_with_attributes(view, -1, "URL", gtk_cell_renderer_text_new(), "text", RSSCOL_LINK, NULL);*/ - gtk_tree_view_insert_column_with_attributes(view, -1, NULL, trg_rss_cell_renderer_new(), "title", RSSCOL_TITLE, "feed", RSSCOL_FEED, "published", RSSCOL_PUBDATE, NULL); + priv->tree_view = GTK_TREE_VIEW(gtk_tree_view_new()); + gtk_tree_view_set_headers_visible(priv->tree_view, FALSE); + gtk_tree_view_set_model(priv->tree_view, GTK_TREE_MODEL(priv->tree_model)); - g_signal_connect(view, "row-activated", + gtk_tree_view_insert_column_with_attributes(priv->tree_view, -1, NULL, trg_rss_cell_renderer_new(), "title", RSSCOL_TITLE, "feed", RSSCOL_FEED, "published", RSSCOL_PUBDATE, "uploaded", RSSCOL_UPLOADED, NULL); + + g_signal_connect(priv->tree_view, "row-activated", G_CALLBACK(rss_item_activated), object); gtk_window_set_title(GTK_WINDOW(object), _("RSS Feeds")); - /*toolbar = gtk_toolbar_new(); + toolbar = gtk_toolbar_new(); + + item = gtk_tool_button_new_from_stock(GTK_STOCK_REFRESH); + gtk_widget_set_sensitive(GTK_WIDGET(item), TRUE); + gtk_tool_item_set_tooltip_text(item, "Refresh"); + g_signal_connect(G_OBJECT(item), "clicked", G_CALLBACK(on_refresh), object); + gtk_toolbar_insert(GTK_TOOLBAR(toolbar), item, 0); item = gtk_tool_button_new_from_stock(GTK_STOCK_PREFERENCES); gtk_widget_set_sensitive(GTK_WIDGET(item), TRUE); - gtk_tool_item_set_tooltip_text(item, "Configure"); - gtk_toolbar_insert(GTK_TOOLBAR(toolbar), item, 0);*/ + gtk_tool_item_set_tooltip_text(item, "Configure Feeds"); + g_signal_connect(G_OBJECT(item), "clicked", G_CALLBACK(on_configure), object); + gtk_toolbar_insert(GTK_TOOLBAR(toolbar), item, 0); vbox = trg_vbox_new(FALSE, 0); - /*gtk_box_pack_start(GTK_BOX(vbox), GTK_WIDGET(toolbar), - FALSE, FALSE, 0);*/ - gtk_box_pack_start(GTK_BOX(vbox), my_scrolledwin_new(GTK_WIDGET(view)), + gtk_box_pack_start(GTK_BOX(vbox), GTK_WIDGET(toolbar), + FALSE, FALSE, 0); + gtk_box_pack_start(GTK_BOX(vbox), my_scrolledwin_new(GTK_WIDGET(priv->tree_view)), TRUE, TRUE, 0); gtk_container_add(GTK_CONTAINER(object), vbox); diff --git a/src/trg-torrent-add-dialog.c b/src/trg-torrent-add-dialog.c index 702efd4..aa63166 100644 --- a/src/trg-torrent-add-dialog.c +++ b/src/trg-torrent-add-dialog.c @@ -48,7 +48,7 @@ #include "upload.h" enum { - PROP_0, PROP_FILENAME, PROP_PARENT, PROP_CLIENT, PROP_RESPONSE + PROP_0, PROP_FILENAME, PROP_PARENT, PROP_CLIENT, PROP_UPLOAD }; enum { @@ -64,7 +64,7 @@ struct _TrgTorrentAddDialogPrivate { TrgClient *client; TrgMainWindow *parent; GSList *filenames; - trg_response *response; + trg_upload *upload; GtkWidget *source_chooser; GtkWidget *dest_combo; GtkWidget *priority_combo; @@ -72,6 +72,7 @@ struct _TrgTorrentAddDialogPrivate { GtkTreeStore *store; GtkWidget *paused_check; GtkWidget *delete_check; + guint n_files; }; #define MAGNET_MAX_LINK_WIDTH 75 @@ -92,6 +93,9 @@ static void trg_torrent_add_dialog_set_property(GObject * object, case PROP_PARENT: priv->parent = g_value_get_object(value); break; + case PROP_UPLOAD: + priv->upload = g_value_get_pointer(value); + break; case PROP_CLIENT: priv->client = g_value_get_pointer(value); break; @@ -123,7 +127,7 @@ add_file_indexes_foreachfunc(GtkTreeModel * model, path G_GNUC_UNUSED, GtkTreeIter * iter, gpointer data) { - JsonObject *args = (JsonObject *) data; + trg_upload *upload = (trg_upload *) data; gint priority, index, wanted; gtk_tree_model_get(model, iter, FC_PRIORITY, &priority, FC_ENABLED, @@ -132,17 +136,8 @@ add_file_indexes_foreachfunc(GtkTreeModel * model, if (gtk_tree_model_iter_has_child(model, iter) || index < 0) return FALSE; - if (wanted) - add_file_id_to_array(args, FIELD_FILES_WANTED, index); - else - add_file_id_to_array(args, FIELD_FILES_UNWANTED, index); - - if (priority == TR_PRI_LOW) - add_file_id_to_array(args, FIELD_FILES_PRIORITY_LOW, index); - else if (priority == TR_PRI_HIGH) - add_file_id_to_array(args, FIELD_FILES_PRIORITY_HIGH, index); - else - add_file_id_to_array(args, FIELD_FILES_PRIORITY_NORMAL, index); + upload->file_wanted[index] = wanted; + upload->file_priorities[index] = priority; return FALSE; } @@ -168,10 +163,15 @@ trg_torrent_add_response_cb(GtkDialog * dlg, gint res_id, gpointer data) gchar *dir = trg_destination_combo_get_dir(TRG_DESTINATION_COMBO (priv->dest_combo)); + trg_upload *upload; - trg_upload *upload = g_new0(trg_upload, 1); + if (priv->upload) { + upload = priv->upload; + } else { + upload = g_new0(trg_upload, 1); + upload->list = priv->filenames; + } - upload->list = priv->filenames; upload->main_window = priv->parent; upload->client = priv->client; upload->dir = dir; @@ -179,12 +179,17 @@ trg_torrent_add_response_cb(GtkDialog * dlg, gint res_id, gpointer data) upload->flags = flags; upload->extra_args = TRUE; + upload->n_files = priv->n_files; + upload->file_priorities = g_new0(gint, priv->n_files); + upload->file_wanted = g_new0(gint, priv->n_files); + + gtk_tree_model_foreach(GTK_TREE_MODEL(priv->store), + add_file_indexes_foreachfunc, upload); + trg_do_upload(upload); trg_destination_combo_save_selection(TRG_DESTINATION_COMBO (priv->dest_combo)); - - g_free(dir); } else { g_str_slist_free(priv->filenames); } @@ -393,7 +398,7 @@ static void addTorrentFilters(GtkFileChooser * chooser) static void store_add_node(GtkTreeStore * store, GtkTreeIter * parent, - trg_files_tree_node * node) + trg_files_tree_node * node, guint *n_files) { GtkTreeIter child; GList *li; @@ -404,11 +409,12 @@ store_add_node(GtkTreeStore * store, GtkTreeIter * parent, 1, FC_INDEX, node->index, FC_PRIORITY, TR_PRI_NORMAL, FC_SIZE, node->length, -1); + *n_files = *n_files + 1; } for (li = node->children; li; li = g_list_next(li)) store_add_node(store, node->name ? &child : NULL, - (trg_files_tree_node *) li->data); + (trg_files_tree_node *) li->data, n_files); } static void torrent_not_parsed_warning(GtkWindow * parent) @@ -438,6 +444,28 @@ static void torrent_not_found_error(GtkWindow * parent, gchar * file) gtk_widget_destroy(dialog); } +static void +trg_torrent_add_dialog_set_upload(TrgTorrentAddDialog *d, trg_upload *upload) { + TrgTorrentAddDialogPrivate *priv = + TRG_TORRENT_ADD_DIALOG_GET_PRIVATE(d); + GtkButton *chooser = GTK_BUTTON(priv->source_chooser); + trg_torrent_file *tor_data = NULL; + + if (upload->uid) + gtk_button_set_label(chooser, upload->uid); + + tor_data = trg_parse_torrent_data(upload->upload_response->raw, upload->upload_response->size); + + if (!tor_data) { + torrent_not_parsed_warning(GTK_WINDOW(priv->parent)); + } else { + store_add_node(priv->store, NULL, tor_data->top_node, &priv->n_files); + trg_torrent_file_free(tor_data); + } + + gtk_widget_set_sensitive(priv->file_list, tor_data != NULL); +} + static void trg_torrent_add_dialog_set_filenames(TrgTorrentAddDialog * d, GSList * filenames) @@ -449,6 +477,11 @@ trg_torrent_add_dialog_set_filenames(TrgTorrentAddDialog * d, gtk_tree_store_clear(priv->store); + if (priv->upload) { + trg_upload_free(priv->upload); + priv->upload = NULL; + } + if (nfiles == 1) { gchar *file_name = (gchar *) filenames->data; if (is_url(file_name) || is_magnet(file_name)) { @@ -484,7 +517,7 @@ trg_torrent_add_dialog_set_filenames(TrgTorrentAddDialog * d, if (!tor_data) { torrent_not_parsed_warning(GTK_WINDOW(priv->parent)); } else { - store_add_node(priv->store, NULL, tor_data->top_node); + store_add_node(priv->store, NULL, tor_data->top_node, &priv->n_files); trg_torrent_file_free(tor_data); } } else { @@ -712,8 +745,12 @@ static GObject *trg_torrent_add_dialog_constructor(GType type, priv->source_chooser = gtk_button_new(); gtk_button_set_alignment(GTK_BUTTON(priv->source_chooser), 0.0f, 0.5f); - trg_torrent_add_dialog_set_filenames(TRG_TORRENT_ADD_DIALOG(obj), - priv->filenames); + + if (priv->filenames) + trg_torrent_add_dialog_set_filenames(TRG_TORRENT_ADD_DIALOG(obj), + priv->filenames); + else if (priv->upload) + trg_torrent_add_dialog_set_upload(TRG_TORRENT_ADD_DIALOG(obj), priv->upload); gtk_table_attach(GTK_TABLE(t), priv->source_chooser, 1, 2, 0, 1, ~0, 0, 0, 0); @@ -796,10 +833,10 @@ trg_torrent_add_dialog_class_init(TrgTorrentAddDialogClass * klass) G_PARAM_STATIC_BLURB)); g_object_class_install_property(object_class, - PROP_RESPONSE, - g_param_spec_pointer("response", - "response", - "response", + PROP_UPLOAD, + g_param_spec_pointer("upload", + "upload", + "upload", G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY @@ -854,12 +891,12 @@ TrgTorrentAddDialog *trg_torrent_add_dialog_new_from_filenames(TrgMainWindow * p NULL); } -TrgTorrentAddDialog *trg_torrent_add_dialog_new_from_response(TrgMainWindow * parent, +TrgTorrentAddDialog *trg_torrent_add_dialog_new_from_upload(TrgMainWindow * parent, TrgClient * client, - trg_response *response) + trg_upload *upload) { - return g_object_new(TRG_TYPE_TORRENT_ADD_DIALOG, "response", - response, "parent", parent, "client", client, + return g_object_new(TRG_TYPE_TORRENT_ADD_DIALOG, "upload", + upload, "parent", parent, "client", client, NULL); } diff --git a/src/trg-torrent-add-dialog.h b/src/trg-torrent-add-dialog.h index ab6721e..eebea45 100644 --- a/src/trg-torrent-add-dialog.h +++ b/src/trg-torrent-add-dialog.h @@ -24,6 +24,7 @@ #include #include "trg-client.h" +#include "upload.h" #include "trg-main-window.h" G_BEGIN_DECLS @@ -48,9 +49,12 @@ typedef struct { GType trg_torrent_add_dialog_get_type(void); -TrgTorrentAddDialog *trg_torrent_add_dialog_new(TrgMainWindow * win, +TrgTorrentAddDialog *trg_torrent_add_dialog_new_from_filenames(TrgMainWindow * parent, TrgClient * client, GSList * filenames); +TrgTorrentAddDialog *trg_torrent_add_dialog_new_from_upload(TrgMainWindow * parent, + TrgClient * client, + trg_upload *upload); void trg_torrent_add_dialog(TrgMainWindow * win, TrgClient * client); G_END_DECLS diff --git a/src/upload.c b/src/upload.c index 5bac869..2f16c51 100644 --- a/src/upload.c +++ b/src/upload.c @@ -1,9 +1,10 @@ #include "protocol-constants.h" #include "requests.h" #include "trg-client.h" -#include "upload.h" #include "util.h" #include "trg-main-window.h" +#include "json.h" +#include "upload.h" static gboolean upload_complete_callback(gpointer data); static void next_upload(trg_upload *upload); @@ -19,20 +20,57 @@ add_set_common_args(JsonObject * args, gint priority, gchar * dir) void trg_upload_free(trg_upload *upload) { g_str_slist_free(upload->list); g_free(upload->dir); + g_free(upload->uid); + g_free(upload->file_wanted); + g_free(upload->file_priorities); trg_response_free(upload->upload_response); g_free(upload); } +static void add_priorities(JsonObject *args, gint* priorities, gint n_files) +{ + gint i; + for (i = 0; i < n_files; i++) { + gint priority = priorities[i]; + if (priority == TR_PRI_LOW) + add_file_id_to_array(args, FIELD_FILES_PRIORITY_LOW, i); + else if (priority == TR_PRI_HIGH) + add_file_id_to_array(args, FIELD_FILES_PRIORITY_HIGH, i); + else + add_file_id_to_array(args, FIELD_FILES_PRIORITY_NORMAL, i); + } +} + +static void add_wanteds(JsonObject *args, gint* wanteds, gint n_files) { + gint i; + for (i = 0; i < n_files; i++) { + if (wanteds[i]) + add_file_id_to_array(args, FIELD_FILES_WANTED, i); + else + add_file_id_to_array(args, FIELD_FILES_UNWANTED, i); + } +} + static void next_upload(trg_upload *upload) { - if (upload->upload_response && upload->progress_index < 1) { - JsonNode *req = torrent_add_from_response(upload->upload_response, 0); - /*JsonObject *args = + JsonNode *req = NULL; + + if (upload->upload_response && upload->progress_index < 1) + req = torrent_add_from_response(upload->upload_response, upload->flags); + else if (upload->list && upload->progress_index < g_slist_length(upload->list)) + req = torrent_add_from_file((gchar*)g_slist_nth_data(upload->list, upload->progress_index), upload->flags); + + if (req) { + JsonObject *args = node_get_arguments(req); + if (upload->extra_args) - add_set_common_args()*/ - upload->progress_index++; - dispatch_async(upload->client, req, upload_complete_callback, upload); - } else if (upload->list && upload->progress_index < g_slist_length(upload->list)) { - JsonNode *req = torrent_add_from_file((gchar*)g_slist_nth_data(upload->list, upload->progress_index), 0); + add_set_common_args(args, upload->priority, upload->dir); + + if (upload->file_wanted) + add_wanteds(args, upload->file_wanted, upload->n_files); + + if (upload->file_priorities) + add_priorities(args, upload->file_priorities, upload->n_files); + upload->progress_index++; dispatch_async(upload->client, req, upload_complete_callback, upload); } else { @@ -44,15 +82,18 @@ static gboolean upload_complete_callback(gpointer data) { trg_response *response = (trg_response*)data; trg_upload *upload = (trg_upload*)response->cb_data; - next_upload(upload); + if (upload->callback) + upload->callback(data); /* the callback we're delegating to will destroy the response */ if (upload->main_window) on_generic_interactive_action(upload->main_window, response); - else /* otherwise need to do it here */ + else trg_response_free(response); + next_upload(upload); + return FALSE; } diff --git a/src/upload.h b/src/upload.h index 9f3f719..5dc17e2 100644 --- a/src/upload.h +++ b/src/upload.h @@ -15,11 +15,16 @@ typedef struct { guint flags; gchar *dir; gint priority; + gint* file_priorities; + gint* file_wanted; + guint n_files; gboolean extra_args; guint progress_index; - + GSourceFunc callback; + gchar *uid; } trg_upload; +void trg_upload_free(trg_upload *upload); void trg_do_upload(trg_upload *upload); #endif -- cgit v1.2.3 From 118b702bec50d9872699357a379413f69e9b176e Mon Sep 17 00:00:00 2001 From: Alan F Date: Mon, 10 Mar 2014 09:10:07 +0000 Subject: fix a memory leak found in new RSS window found by valgrind --- src/trg-rss-window.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) (limited to 'src') diff --git a/src/trg-rss-window.c b/src/trg-rss-window.c index 64c1452..442cce9 100644 --- a/src/trg-rss-window.c +++ b/src/trg-rss-window.c @@ -100,15 +100,18 @@ static gboolean upload_complete_searchfunc(GtkTreeModel *model, gpointer data) { trg_upload *upload = (trg_upload*)data; gchar *item_guid = NULL; + gboolean stop = FALSE; gtk_tree_model_get(model, iter, RSSCOL_ID, &item_guid, -1); if (!g_strcmp0(item_guid, upload->uid)) { gtk_list_store_set(GTK_LIST_STORE(model), iter, RSSCOL_UPLOADED, TRUE, -1); - return TRUE; + stop = TRUE; } - return FALSE; + g_free(item_guid); + + return stop; } static gboolean on_upload_complete(gpointer data) { -- cgit v1.2.3