summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGravatar Alan Fitton <ajf@eth0.org.uk>2012-01-18 23:30:02 +0000
committerGravatar Alan Fitton <ajf@eth0.org.uk>2012-01-18 23:30:02 +0000
commitc427fa73c4f7853de992eda9de1c818c2ee525aa (patch)
treec1203a6a808f242038cb063eba4843cf97f2c40f
parent2512c508cb6b8edeefed308a3dce61054d58bb06 (diff)
full and default gtk3 support, almost. the graph is disabled as the drawing api has changed quite a bit. yet another implementation to pass arguments, which made a cleanup of main.c necessary.
-rw-r--r--configure.ac33
-rw-r--r--src/Makefile.am3
-rw-r--r--src/main.c388
-rw-r--r--src/trg-cell-renderer-file-icon.c2
-rw-r--r--src/trg-gtk-app.c236
-rw-r--r--src/trg-gtk-app.h55
-rw-r--r--src/trg-main-window.c70
-rw-r--r--src/trg-main-window.h3
-rw-r--r--src/trg-menu-bar.c14
-rw-r--r--src/trg-preferences-dialog.c7
-rw-r--r--src/trg-remote-prefs-dialog.c6
-rw-r--r--src/trg-sortable-filtered-model.h1
-rw-r--r--src/trg-stats-dialog.c5
-rw-r--r--src/trg-status-bar.c15
-rw-r--r--src/trg-status-bar.h3
-rw-r--r--src/trg-toolbar.c2
-rw-r--r--src/trg-torrent-graph.c8
-rw-r--r--src/trg-torrent-graph.h10
-rw-r--r--src/trg-torrent-props-dialog.c6
-rw-r--r--src/trg-tree-view.c33
-rw-r--r--src/util.c56
-rw-r--r--src/util.h4
-rw-r--r--src/win32-mailslot.c192
-rw-r--r--src/win32-mailslot.h29
24 files changed, 810 insertions, 371 deletions
diff --git a/configure.ac b/configure.ac
index 217d32b..32c1108 100644
--- a/configure.ac
+++ b/configure.ac
@@ -55,12 +55,6 @@ AC_SUBST(GETTEXT_PACKAGE)
AC_DEFINE(GETTEXT_PACKAGE, "AC_PACKAGE_NAME", [foo])
AC_DEFINE_DIR([LOCALEDIR], [datarootdir/locale], [gettext catalogs])
-PKG_CHECK_MODULES([jsonglib], [json-glib-1.0 >= 0.8])
-PKG_CHECK_MODULES([gthread], [gthread-2.0])
-PKG_CHECK_MODULES([gtk], [gtk+-2.0 >= 2.16])
-PKG_CHECK_MODULES([libcurl], [libcurl])
-PKG_CHECK_MODULES([gio], [gio-2.0 >= 2.22])
-
AC_ARG_WITH([libgeoip], AC_HELP_STRING([--without-libgeoip], [disable GeoIP support]))
have_libgeoip=no
if test x$with_libgeoip != xno; then
@@ -75,24 +69,21 @@ AM_CONDITIONAL([HAVE_GEOIP], [test "x$have_geoip" = "xyes"])
AC_ARG_WITH([libunique], AC_HELP_STRING([--without-libunique], [disable libunique]))
have_libunique=no
-if test x$with_libunique != xno; then
- PKG_CHECK_MODULES([unique], [unique-1.0], AC_DEFINE(HAVE_LIBUNIQUE, 1, [Define if libunique is available]), AC_MSG_WARN([libunique is required for opening torrents on non-win32]))
-fi
-
AC_ARG_WITH([libnotify], AC_HELP_STRING([--without-libnotify], [disable libnotify]))
have_libnotify=no
+AC_ARG_WITH([libproxy], AC_HELP_STRING([--without-libproxy], [disable libproxy]))
+have_libproxy=no
+AC_ARG_WITH([libappindicator], AC_HELP_STRING([--without-libappindicator], [disable libappindicator]))
+have_libappindicator=no
+
if test x$with_libnotify != xno; then
PKG_CHECK_MODULES([notify], [libnotify], AC_DEFINE(HAVE_LIBNOTIFY, 1, [Define if libnotify is available]), AC_MSG_WARN([libnotify is required for popup desktop notifications]))
fi
-AC_ARG_WITH([libproxy], AC_HELP_STRING([--without-libproxy], [disable libproxy]))
-have_libproxy=no
if test x$with_libproxy != xno; then
PKG_CHECK_MODULES([libproxy], [libproxy-1.0], AC_DEFINE(HAVE_LIBPROXY, 1, [Define if libproxy is available]), AC_MSG_WARN([libproxy is required for HTTP proxy support]))
fi
-AC_ARG_WITH([libappindicator], AC_HELP_STRING([--without-libappindicator], [disable libappindicator]))
-have_libappindicator=no
if test x$with_libappindicator != xno; then
PKG_CHECK_MODULES([libappindicator], [appindicator-0.1], AC_DEFINE(HAVE_LIBAPPINDICATOR, 1, [Define if libappindicator is available]), AC_MSG_WARN([Ubuntu Unity users should consider building with libappindicator]))
fi
@@ -103,4 +94,18 @@ if test x$enable_debug = xyes; then
AC_DEFINE([DEBUG], [], [enable debugging])
fi
+PKG_CHECK_MODULES([jsonglib], [json-glib-1.0 >= 0.8])
+PKG_CHECK_MODULES([gthread], [gthread-2.0])
+
+PKG_CHECK_MODULES([gtk], [gtk+-3.0 >= 3.00], [], [
+AC_MSG_WARN([gtk+-3.0 not found, trying gtk+-2.0])
+PKG_CHECK_MODULES([gtk], [gtk+-2.0 >= 2.16])
+if test x$with_libunique != xno; then
+ PKG_CHECK_MODULES([unique], [unique-1.0], AC_DEFINE(HAVE_LIBUNIQUE, 1, [Define if libunique is available]), AC_MSG_WARN([libunique is required for opening torrents on gtk+-2.0. not needed for gtk+-3.0 or win32. ]))
+fi
+])
+
+PKG_CHECK_MODULES([libcurl], [libcurl])
+PKG_CHECK_MODULES([gio], [gio-2.0 >= 2.22])
+
AC_OUTPUT([Makefile po/Makefile.in src/Makefile])
diff --git a/src/Makefile.am b/src/Makefile.am
index 7cf5167..d564181 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -101,6 +101,7 @@ transmission_remote_gtk_SOURCES = main.c \
trg-prefs.c \
trg-destination-combo.c \
remote-exec.c \
+ trg-gtk-app.c \
$(NULL)
transmission_remote_gtk_LDFLAGS = -lm $(jsonglib_LIBS) $(gtk_LIBS) $(gthread_LIBS) $(GEOIP_LIBS) $(gio_LIBS) $(unique_LIBS) $(notify_LIBS) $(libproxy_LIBS) $(libcurl_LIBS) $(libappindicator_LIBS)
@@ -112,7 +113,7 @@ if WIN32
windres $^ -o $@
AM_CFLAGS = -mms-bitfields -mwin32 -mwindows
-transmission_remote_gtk_SOURCES += win32.rc
+transmission_remote_gtk_SOURCES += win32.rc win32-mailslot.c
INCLUDES += -O2
else
%.1: %.pod
diff --git a/src/main.c b/src/main.c
index e2c61f7..980e719 100644
--- a/src/main.c
+++ b/src/main.c
@@ -30,30 +30,32 @@
#include <glib-object.h>
#include <gtk/gtk.h>
#include <json-glib/json-glib.h>
-#ifdef HAVE_LIBUNIQUE
+
+#if !GTK_CHECK_VERSION( 3, 0, 0 ) && HAVE_LIBUNIQUE
#include <unique/unique.h>
+#elif GTK_CHECK_VERSION( 3, 0, 0 )
+#include "trg-gtk-app.h"
#elif WIN32
-#include <windows.h>
+#include "win32-mailslot.h"
#endif
#include "trg-main-window.h"
#include "trg-client.h"
#include "util.h"
-/* The file with the main() function. It converts arguments into a NULL terminated
- * array, with relative paths converted to absolute paths.
+/* Handle arguments and start the main window. Unfortunately, there's three
+ * different ways to achieve a unique instance and pass arguments around. :(
*
- * Much of the code here is to optionally handle passing torrent files/URLs to
- * a first instance. UNIX can use libunique (should alternatively use
- * GApplication for GNOME3). Windows uses the mailslot feature in the
- * native Win32 API, so there is no dependency on dbus etc.
+ * 1) libunique - GTK2 (non-win32). deprecated in GTK3 for GtkApplication.
+ * 2) GtkApplication - replaces libunique, GTK3 only, and non-win32.
+ * 3) win32 API mailslots.
*/
-#define TRG_LIBUNIQUE_DOMAIN "uk.org.eth0.trg"
-#define TRG_MAILSLOT_NAME "\\\\.\\mailslot\\TransmissionRemoteGTK" //Name given to the Mailslot
-#define MAILSLOT_BUFFER_SIZE 1024*32
+/*
+ * libunique.
+ */
-#ifdef HAVE_LIBUNIQUE
+#if !GTK_CHECK_VERSION( 3, 0, 0 ) && HAVE_LIBUNIQUE
enum {
COMMAND_0,
@@ -94,320 +96,152 @@ message_received_cb(UniqueApp * app G_GNUC_UNUSED,
return res;
}
-#elif WIN32
-
-struct trg_mailslot_recv_args {
- TrgMainWindow *win;
- gchar **uris;
- gboolean present;
-};
-
-/* to be queued into the glib main loop with g_idle_add() */
-
-static gboolean mailslot_recv_args(gpointer data)
+static gint trg_libunique_init(TrgClient * client, int argc,
+ gchar * argv[], gchar ** args)
{
- struct trg_mailslot_recv_args *args =
- (struct trg_mailslot_recv_args *) data;
+ UniqueApp *app = unique_app_new_with_commands("uk.org.eth0.trg", NULL,
+ "add", COMMAND_ADD,
+ NULL);
+ TrgMainWindow *window;
- if (args->present) {
- gtk_window_deiconify(GTK_WINDOW(args->win));
- gtk_window_present(GTK_WINDOW(args->win));
- }
+ if (unique_app_is_running(app)) {
+ UniqueCommand command;
+ UniqueResponse response;
+ UniqueMessageData *message;
- if (args->uris)
- trg_add_from_filename(args->win, args->uris);
+ if (args) {
+ command = COMMAND_ADD;
+ message = unique_message_data_new();
+ unique_message_data_set_uris(message, args);
+ g_strfreev(args);
+ } else {
+ command = UNIQUE_ACTIVATE;
+ message = NULL;
+ }
- g_free(args);
+ response = unique_app_send_message(app, command, message);
+ unique_message_data_free(message);
- return FALSE;
-}
+ if (response != UNIQUE_RESPONSE_OK)
+ return EXIT_FAILURE;
+ } else {
+ window =
+ trg_main_window_new(client, should_be_minimised(argc, argv));
+ g_signal_connect(app, "message-received",
+ G_CALLBACK(message_received_cb), window);
-static gpointer mailslot_recv_thread(gpointer data)
-{
- TrgMainWindow *win = TRG_MAIN_WINDOW(data);
- JsonParser *parser;
- char szBuffer[MAILSLOT_BUFFER_SIZE];
- HANDLE hMailslot;
- DWORD cbBytes;
- BOOL bResult;
-
- hMailslot = CreateMailslot(TRG_MAILSLOT_NAME, // mailslot name
- MAILSLOT_BUFFER_SIZE, // input buffer size
- MAILSLOT_WAIT_FOREVER, // no timeout
- NULL); // default security attribute
-
- if (INVALID_HANDLE_VALUE == hMailslot) {
- g_error("\nError occurred while creating the mailslot: %d",
- GetLastError());
- return NULL; //Error
+ auto_connect_if_required(window, args);
+ gtk_main();
}
- while (1) {
- bResult = ReadFile(hMailslot, // handle to mailslot
- szBuffer, // buffer to receive data
- sizeof(szBuffer), // size of buffer
- &cbBytes, // number of bytes read
- NULL); // not overlapped I/O
+ g_object_unref(app);
- if ((!bResult) || (0 == cbBytes)) {
- g_error("Mailslot error from client: %d", GetLastError());
- break;
- }
+ return EXIT_SUCCESS;
+}
- parser = json_parser_new();
+#elif GTK_CHECK_VERSION( 3, 0, 0 )
- if (json_parser_load_from_data(parser, szBuffer, cbBytes, NULL)) {
- JsonNode *node = json_parser_get_root(parser);
- JsonObject *obj = json_node_get_object(node);
- struct trg_mailslot_recv_args *args =
- g_new0(struct trg_mailslot_recv_args, 1);
+/* GtkApplication - the replacement for libunique.
+ * This is implemented in trg-gtk-app.c
+ */
- args->present = json_object_has_member(obj, "present")
- && json_object_get_boolean_member(obj, "present");
- args->win = win;
+static gint trg_gtkapp_init(TrgClient * client, int argc, char *argv[])
+{
+ TrgGtkApp *gtk_app = trg_gtk_app_new(client);
- if (json_object_has_member(obj, "args")) {
- JsonArray *array =
- json_object_get_array_member(obj, "args");
- GList *arrayList = json_array_get_elements(array);
+ gint exitCode = g_application_run(G_APPLICATION(gtk_app), argc, argv);
- if (arrayList) {
- guint arrayLength = g_list_length(arrayList);
- guint i = 0;
- GList *li;
+ g_object_unref(gtk_app);
- args->uris = g_new0(gchar *, arrayLength + 1);
+ return exitCode;
+}
- for (li = arrayList; li; li = g_list_next(li)) {
- const gchar *liStr =
- json_node_get_string((JsonNode *) li->data);
- args->uris[i++] = g_strdup(liStr);
- }
+#else
- g_list_free(arrayList);
- }
- }
+static gint trg_simple_init(TrgClient * client, int argc, char *argv[], gchar **args)
+{
+ TrgMainWindow *window =
+ trg_main_window_new(client, should_be_minimised(argc, argv));
+ auto_connect_if_required(window, args);
+ gtk_main();
- json_node_free(node);
+ return EXIT_SUCCESS;
+}
- g_idle_add(mailslot_recv_args, args);
- }
+#endif
- g_object_unref(parser);
- }
- CloseHandle(hMailslot);
- return NULL; //Success
-}
+/* Win32 mailslots. I've implemented this in win32-mailslot.c */
-static int mailslot_send_message(HANDLE h, gchar ** args)
+#ifdef WIN32
+static gint trg_win32_init(TrgClient * client, int argc, char *argv[],
+ gchar ** args)
{
- DWORD cbBytes;
- JsonNode *node = json_node_new(JSON_NODE_OBJECT);
- JsonObject *obj = json_object_new();
- JsonArray *array = json_array_new();
- JsonGenerator *generator;
- gchar *msg;
- int i;
-
- if (args) {
- for (i = 0; args[i]; i++)
- json_array_add_string_element(array, args[i]);
+ gchar *moddir =
+ g_win32_get_package_installation_directory_of_module(NULL);
+ gchar *localedir =
+ g_build_path(G_DIR_SEPARATOR_S, moddir, "share", "locale",
+ NULL);
- json_object_set_array_member(obj, "args", array);
+ bindtextdomain(GETTEXT_PACKAGE, localedir);
+ g_free(moddir);
+ g_free(localedir);
- g_strfreev(args);
- } else {
- json_object_set_boolean_member(obj, "present", TRUE);
+ if (!mailslot_send_message(args)) {
+ TrgMainWindow *window =
+ trg_main_window_new(client, should_be_minimised(argc, argv));
+ auto_connect_if_required(window, args);
+ mailslot_start_background_listener(window);
+ gtk_main();
}
- json_node_take_object(node, obj);
-
- generator = json_generator_new();
- json_generator_set_root(generator, node);
- msg = json_generator_to_data(generator, NULL);
-
- json_node_free(node);
- g_object_unref(generator);
-
- WriteFile(h, // handle to mailslot
- msg, // buffer to write from
- strlen(msg) + 1, // number of bytes to write, include the NULL
- &cbBytes, // number of bytes written
- NULL);
-
- CloseHandle(h);
- g_free(msg);
-
- return 0;
-}
-
-#endif
-
-static gboolean is_minimised_arg(gchar * arg)
-{
- return !g_strcmp0(arg, "-m")
- || !g_strcmp0(arg, "--minimized")
- || !g_strcmp0(arg, "/m");
+ return EXIT_SUCCESS;
}
-
-static gboolean should_be_minimised(int argc, char *argv[])
+#else
+static void trg_non_win32_init()
{
- int i;
- for (i = 1; i < argc; i++)
- if (is_minimised_arg(argv[i]))
- return TRUE;
-
- return FALSE;
+ bindtextdomain(GETTEXT_PACKAGE, LOCALEDIR);
}
+#endif
-static gchar **convert_args(int argc, char *argv[])
+static void trg_cleanup()
{
- gchar *cwd = g_get_current_dir();
- gchar **files = NULL;
-
- if (argc > 1) {
- GSList *list = NULL;
- int i;
-
- for (i = 1; i < argc; i++) {
- if (is_minimised_arg(argv[i])) {
- continue;
- } else if (!is_url(argv[i]) && !is_magnet(argv[i])
- && g_file_test(argv[i], G_FILE_TEST_IS_REGULAR)
- && !g_path_is_absolute(argv[i])) {
- list = g_slist_append(list,
- g_build_path(G_DIR_SEPARATOR_S, cwd,
- argv[i], NULL));
- } else {
- list = g_slist_append(list, g_strdup(argv[i]));
- }
- }
-
- if (list) {
- GSList *li;
- files = g_new0(gchar *, g_slist_length(list) + 1);
- i = 0;
- for (li = list; li; li = g_slist_next(li)) {
- files[i++] = li->data;
- }
- g_slist_free(list);
- }
- }
-
- g_free(cwd);
-
- return files;
+ curl_global_cleanup();
}
int main(int argc, char *argv[])
{
- int returnValue = EXIT_SUCCESS;
- TrgMainWindow *window;
- TrgClient *client;
+#if WIN32 || !GTK_CHECK_VERSION( 3, 0, 0 )
gchar **args = convert_args(argc, argv);
- gboolean withUnique;
-#ifdef HAVE_LIBUNIQUE
- UniqueApp *app = NULL;
-#endif
-#ifdef WIN32
- gchar *localedir, *moddir;
- HANDLE hMailSlot;
-#endif
-#ifdef TRG_MEMPROFILE
- GMemVTable gmvt = { malloc, realloc, free, calloc, malloc, realloc };
- g_mem_set_vtable(&gmvt);
- g_mem_set_vtable(glib_mem_profiler_table);
- g_mem_profile();
#endif
+ gint exitCode = EXIT_SUCCESS;
+ TrgClient *client;
g_type_init();
g_thread_init(NULL);
gtk_init(&argc, &argv);
+ curl_global_init(CURL_GLOBAL_ALL);
+ client = trg_client_new();
+
g_set_application_name(PACKAGE_NAME);
-#ifdef WIN32
- moddir = g_win32_get_package_installation_directory_of_module(NULL);
- localedir = g_build_path(G_DIR_SEPARATOR_S, moddir, "share", "locale",
- NULL);
- g_free(moddir);
- bindtextdomain(GETTEXT_PACKAGE, localedir);
- g_free(localedir);
-#else
- bindtextdomain(GETTEXT_PACKAGE, LOCALEDIR);
-#endif
bind_textdomain_codeset(GETTEXT_PACKAGE, "UTF-8");
textdomain(GETTEXT_PACKAGE);
- withUnique = (g_getenv("TRG_NOUNIQUE") == NULL);
-
-#ifdef HAVE_LIBUNIQUE
- if (withUnique)
- app = unique_app_new_with_commands(TRG_LIBUNIQUE_DOMAIN, NULL,
- "add", COMMAND_ADD, NULL);
-
- if (withUnique && unique_app_is_running(app)) {
- UniqueCommand command;
- UniqueResponse response;
- UniqueMessageData *message;
-
- if (args) {
- command = COMMAND_ADD;
- message = unique_message_data_new();
- unique_message_data_set_uris(message, args);
- g_strfreev(args);
- } else {
- command = UNIQUE_ACTIVATE;
- message = NULL;
- }
-
- response = unique_app_send_message(app, command, message);
- unique_message_data_free(message);
-
- if (response != UNIQUE_RESPONSE_OK)
- returnValue = EXIT_FAILURE;
- } else {
-#elif WIN32
- hMailSlot = CreateFile(TRG_MAILSLOT_NAME, // mailslot name
- GENERIC_WRITE, // mailslot write only
- FILE_SHARE_READ, // required for mailslots
- NULL, // default security attributes
- OPEN_EXISTING, // opens existing mailslot
- FILE_ATTRIBUTE_NORMAL, // normal attributes
- NULL); // no template file
-
- if (INVALID_HANDLE_VALUE != hMailSlot) {
- returnValue = mailslot_send_message(hMailSlot, args);
- } else {
+#ifdef WIN32
+ exitCode = trg_win32_init(client, argc, argv, args);
+#else
+ trg_non_win32_init();
+#if !GTK_CHECK_VERSION( 3, 0, 0 ) && HAVE_LIBUNIQUE
+ exitCode = trg_libunique_init(client, argc, argv, args);
+#elif GTK_CHECK_VERSION( 3, 0, 0 )
+ exitCode = trg_gtkapp_init(client, argc, argv);
+#else
+ exitCode = trg_simple_init(client, argc, argv, args);
#endif
- client = trg_client_new();
-
- curl_global_init(CURL_GLOBAL_ALL);
-
- window =
- trg_main_window_new(client, should_be_minimised(argc, argv));
-
-#ifdef HAVE_LIBUNIQUE
- if (withUnique) {
- g_signal_connect(app, "message-received",
- G_CALLBACK(message_received_cb), window);
- }
-#elif WIN32
- g_thread_create(mailslot_recv_thread, window, FALSE, NULL);
#endif
- auto_connect_if_required(window, args);
- gtk_main();
-
- curl_global_cleanup();
-#ifdef HAVE_LIBUNIQUE
- }
-
- if (withUnique)
- g_object_unref(app);
-#elif WIN32
- }
-#endif
+ trg_cleanup();
- return returnValue;
+ return exitCode;
}
diff --git a/src/trg-cell-renderer-file-icon.c b/src/trg-cell-renderer-file-icon.c
index d61729c..fddd0a5 100644
--- a/src/trg-cell-renderer-file-icon.c
+++ b/src/trg-cell-renderer-file-icon.c
@@ -91,7 +91,7 @@ static void trg_cell_renderer_file_icon_refresh(TrgCellRendererFileIcon *
g_object_set(fi, "stock-id", GTK_STOCK_FILE, NULL);
}
#else
- g_object_set(fi, "stock-id", GTK_STOCK_FILE, NULL);
+ g_object_set(fi, "stock-id", GTK_STOCK_FILE, NULL);
#endif
}
}
diff --git a/src/trg-gtk-app.c b/src/trg-gtk-app.c
new file mode 100644
index 0000000..5a45a80
--- /dev/null
+++ b/src/trg-gtk-app.c
@@ -0,0 +1,236 @@
+/*
+ * transmission-remote-gtk - A GTK RPC client to Transmission
+ * Copyright (C) 2011 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 <gtk/gtk.h>
+
+#if GTK_CHECK_VERSION( 3, 0, 0 )
+
+#include "trg-main-window.h"
+#include "trg-gtk-app.h"
+#include "util.h"
+
+enum {
+ PROP_0, PROP_CLIENT, PROP_START_ARGS, PROP_MINIMISE_ON_START
+};
+
+G_DEFINE_TYPE(TrgGtkApp, trg_gtk_app, GTK_TYPE_APPLICATION)
+#define GET_PRIVATE(o) \
+ (G_TYPE_INSTANCE_GET_PRIVATE ((o), TRG_TYPE_GTK_APP, TrgGtkAppPrivate))
+typedef struct _TrgGtkAppPrivate TrgGtkAppPrivate;
+
+struct _TrgGtkAppPrivate {
+ TrgClient *client;
+ gboolean min_start;
+};
+
+static void
+trg_gtk_app_get_property(GObject * object, guint property_id,
+ GValue * value, GParamSpec * pspec)
+{
+ TrgGtkAppPrivate *priv = GET_PRIVATE(object);
+ switch (property_id) {
+ case PROP_CLIENT:
+ g_value_set_pointer(value, priv->client);
+ break;
+ case PROP_MINIMISE_ON_START:
+ g_value_set_boolean(value, priv->min_start);
+ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID(object, property_id, pspec);
+ break;
+ }
+}
+
+static void
+trg_gtk_app_set_property(GObject * object, guint property_id,
+ const GValue * value, GParamSpec * pspec)
+{
+ TrgGtkAppPrivate *priv = GET_PRIVATE(object);
+ switch (property_id) {
+ case PROP_CLIENT:
+ priv->client = g_value_get_pointer(value);
+ break;
+ case PROP_MINIMISE_ON_START:
+ priv->min_start = g_value_get_boolean(value);
+ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID(object, property_id, pspec);
+ break;
+ }
+}
+
+static void trg_gtk_app_dispose(GObject * object)
+{
+ G_OBJECT_CLASS(trg_gtk_app_parent_class)->dispose(object);
+}
+
+static void trg_gtk_app_finalize(GObject * object)
+{
+ G_OBJECT_CLASS(trg_gtk_app_parent_class)->finalize(object);
+}
+
+static void trg_gtk_app_startup(GtkApplication * app, gpointer data)
+{
+ TrgGtkAppPrivate *priv = GET_PRIVATE(app);
+ TrgMainWindow *window =
+ trg_main_window_new(priv->client, priv->min_start);
+ gtk_window_set_application(GTK_WINDOW(window), app);
+
+}
+
+static int
+trg_gtk_app_command_line(GApplication * application,
+ GApplicationCommandLine * cmdline)
+{
+ GList *windows =
+ gtk_application_get_windows(GTK_APPLICATION(application));
+ gchar **argv = g_application_command_line_get_arguments(cmdline, NULL);
+
+ if (argv && argv[0])
+ auto_connect_if_required(TRG_MAIN_WINDOW(windows->data), argv);
+
+ /*if (argv && argv[0])
+ trg_main_window_set_start_args(TRG_MAIN_WINDOW(windows->data),
+ argv);*/
+
+
+ return 0;
+}
+
+static void shift_args(gchar ** argv, int i)
+{
+ gint j;
+ g_free(argv[i]);
+ for (j = i; argv[j]; j++)
+ argv[j] = argv[j + 1];
+}
+
+static gboolean
+test_local_cmdline(GApplication * application,
+ gchar *** arguments, gint * exit_status)
+{
+ TrgGtkAppPrivate *priv = GET_PRIVATE(application);
+ gchar **argv;
+ gchar *cwd = g_get_current_dir();
+ gchar *tmp;
+ gint i;
+
+ argv = *arguments;
+ shift_args(argv, 0);
+
+ i = 1;
+ while (argv[i]) {
+ if (is_minimised_arg(argv[i])) {
+ shift_args(argv, i);
+ priv->min_start = TRUE;
+ } else if (!is_url(argv[i]) && !is_magnet(argv[i])
+ && g_file_test(argv[i], G_FILE_TEST_IS_REGULAR)
+ && !g_path_is_absolute(argv[i])) {
+ tmp = g_build_path(G_DIR_SEPARATOR_S, cwd, argv[i], NULL);
+ g_free(argv[i]);
+ argv[i] = tmp;
+ }
+ i++;
+ }
+
+ *exit_status = 0;
+
+ g_free(cwd);
+
+ return FALSE;
+}
+
+static void trg_gtk_app_class_init(TrgGtkAppClass * klass)
+{
+ GObjectClass *object_class = G_OBJECT_CLASS(klass);
+ GApplicationClass *app_class = G_APPLICATION_CLASS(klass);
+
+ g_type_class_add_private(klass, sizeof(TrgGtkAppPrivate));
+
+ object_class->get_property = trg_gtk_app_get_property;
+ object_class->set_property = trg_gtk_app_set_property;
+ object_class->dispose = trg_gtk_app_dispose;
+ object_class->finalize = trg_gtk_app_finalize;
+ app_class->local_command_line = test_local_cmdline;
+
+ 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_MINIMISE_ON_START,
+ g_param_spec_boolean("min-on-start",
+ "Min On Start",
+ "Min On Start",
+ FALSE,
+ 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_START_ARGS,
+ g_param_spec_pointer("start-args",
+ "start args",
+ "start args",
+ G_PARAM_READWRITE
+ |
+ G_PARAM_CONSTRUCT_ONLY
+ |
+ G_PARAM_STATIC_NAME
+ |
+ G_PARAM_STATIC_NICK
+ |
+ G_PARAM_STATIC_BLURB));
+}
+
+static void trg_gtk_app_init(TrgGtkApp * self)
+{
+ g_application_set_inactivity_timeout(G_APPLICATION(self), 10000);
+ g_signal_connect(self, "command-line",
+ G_CALLBACK(trg_gtk_app_command_line), NULL);
+ g_signal_connect(self, "startup", G_CALLBACK(trg_gtk_app_startup),
+ NULL);
+}
+
+TrgGtkApp *trg_gtk_app_new(TrgClient * client)
+{
+ return g_object_new(TRG_TYPE_GTK_APP,
+ "application-id", "uk.org.eth0.trg",
+ "flags", G_APPLICATION_HANDLES_COMMAND_LINE,
+ "trg-client", client, NULL);
+}
+
+#endif
diff --git a/src/trg-gtk-app.h b/src/trg-gtk-app.h
new file mode 100644
index 0000000..0374321
--- /dev/null
+++ b/src/trg-gtk-app.h
@@ -0,0 +1,55 @@
+/*
+ * transmission-remote-gtk - A GTK RPC client to Transmission
+ * Copyright (C) 2011 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 <gtk/gtk.h>
+
+#ifndef TRG_GTKAPP_
+#define TRG_GTKAPP_
+#if GTK_CHECK_VERSION( 3, 0, 0 )
+
+#include <glib-object.h>
+
+#include "trg-client.h"
+
+G_BEGIN_DECLS
+#define TRG_TYPE_GTK_APP trg_gtk_app_get_type()
+#define TRG_GTK_APP(obj) \
+ (G_TYPE_CHECK_INSTANCE_CAST ((obj), TRG_TYPE_GTK_APP, TrgGtkApp))
+#define TRG_GTK_APP_CLASS(klass) \
+ (G_TYPE_CHECK_CLASS_CAST ((klass), TRG_TYPE_GTK_APP, TrgGtkAppClass))
+#define TRG_IS_GTK_APP(obj) \
+ (G_TYPE_CHECK_INSTANCE_TYPE ((obj), TRG_TYPE_GTK_APP))
+#define TRG_IS_GTK_APP_CLASS(klass) \
+ (G_TYPE_CHECK_CLASS_TYPE ((klass), TRG_TYPE_GTK_APP))
+#define TRG_GTK_APP_GET_CLASS(obj) \
+ (G_TYPE_INSTANCE_GET_CLASS ((obj), TRG_TYPE_GTK_APP, TrgGtkAppClass))
+ typedef struct {
+ GtkApplication parent;
+} TrgGtkApp;
+
+typedef struct {
+ GtkApplicationClass parent_class;
+} TrgGtkAppClass;
+
+GType trg_gtk_app_get_type(void);
+
+TrgGtkApp *trg_gtk_app_new(TrgClient * client);
+
+#endif
+#endif
diff --git a/src/trg-main-window.c b/src/trg-main-window.c
index 23c83e6..27b09a4 100644
--- a/src/trg-main-window.c
+++ b/src/trg-main-window.c
@@ -66,9 +66,7 @@
#include "trg-trackers-tree-view.h"
#include "trg-trackers-model.h"
#include "trg-state-selector.h"
-#ifndef TRG_NO_GRAPH
#include "trg-torrent-graph.h"
-#endif
#include "trg-torrent-move-dialog.h"
#include "trg-torrent-props-dialog.h"
#include "trg-torrent-add-url-dialog.h"
@@ -200,6 +198,7 @@ static gboolean window_state_event(GtkWidget * widget,
GdkEventWindowState * event,
gpointer trayIcon);
+
G_DEFINE_TYPE(TrgMainWindow, trg_main_window, GTK_TYPE_WINDOW)
#define TRG_MAIN_WINDOW_GET_PRIVATE(o) \
(G_TYPE_INSTANCE_GET_PRIVATE ((o), TRG_TYPE_MAIN_WINDOW, TrgMainWindowPrivate))
@@ -240,7 +239,7 @@ struct _TrgMainWindowPrivate {
TrgPeersModel *peersModel;
TrgPeersTreeView *peersTreeView;
-#ifndef TRG_NO_GRAPH
+#if TRG_WITH_GRAPH
TrgTorrentGraph *graph;
#endif
gint graphNotebookIndex;
@@ -430,8 +429,7 @@ static void add_url_cb(GtkWidget * w G_GNUC_UNUSED, gpointer data)
TrgMainWindowPrivate *priv = TRG_MAIN_WINDOW_GET_PRIVATE(data);
TrgTorrentAddUrlDialog *dlg = trg_torrent_add_url_dialog_new(win,
- priv->
- client);
+ priv->client);
gtk_widget_show_all(GTK_WIDGET(dlg));
}
@@ -463,7 +461,7 @@ static void pause_all_cb(GtkWidget * w G_GNUC_UNUSED, gpointer data)
on_generic_interactive_action, data);
}
-gboolean trg_add_from_filename(TrgMainWindow * win, gchar ** uris)
+gint trg_add_from_filename(TrgMainWindow * win, gchar ** uris)
{
TrgMainWindowPrivate *priv = TRG_MAIN_WINDOW_GET_PRIVATE(win);
TrgClient *client = priv->client;
@@ -472,7 +470,8 @@ gboolean trg_add_from_filename(TrgMainWindow * win, gchar ** uris)
int i;
for (i = 0; uris[i]; i++)
- filesList = g_slist_append(filesList, uris[i]);
+ if (uris[i])
+ filesList = g_slist_append(filesList, uris[i]);
if (trg_prefs_get_bool(prefs, TRG_PREFS_KEY_ADD_OPTIONS_DIALOG,
TRG_PREFS_GLOBAL)) {
@@ -497,9 +496,15 @@ gboolean trg_add_from_filename(TrgMainWindow * win, gchar ** uris)
priv->args = NULL;
- return TRUE;
+ return EXIT_SUCCESS;
}
+/*void trg_main_window_set_start_args(TrgMainWindow * window, gchar ** args)
+{
+ TrgMainWindowPrivate *priv = TRG_MAIN_WINDOW_GET_PRIVATE(window);
+ priv->args = args;
+}*/
+
static void resume_all_cb(GtkWidget * w G_GNUC_UNUSED, gpointer data)
{
TrgMainWindowPrivate *priv = TRG_MAIN_WINDOW_GET_PRIVATE(data);
@@ -874,11 +879,13 @@ static void view_stats_toggled_cb(GtkWidget * w, gpointer data)
{
TrgMainWindowPrivate *priv = TRG_MAIN_WINDOW_GET_PRIVATE(data);
- TrgStatsDialog *dlg =
- trg_stats_dialog_get_instance(TRG_MAIN_WINDOW(data),
- priv->client);
+ if (trg_client_is_connected(priv->client)) {
+ TrgStatsDialog *dlg =
+ trg_stats_dialog_get_instance(TRG_MAIN_WINDOW(data),
+ priv->client);
- gtk_widget_show_all(GTK_WIDGET(dlg));
+ gtk_widget_show_all(GTK_WIDGET(dlg));
+ }
}
static void view_states_toggled_cb(GtkCheckMenuItem * w, gpointer data)
@@ -895,7 +902,7 @@ static void view_notebook_toggled_cb(GtkCheckMenuItem * w, gpointer data)
gtk_check_menu_item_get_active(w));
}
-#ifndef TRG_NO_GRAPH
+#if TRG_WITH_GRAPH
static void trg_main_window_toggle_graph_cb(GtkCheckMenuItem * w,
gpointer win)
{
@@ -963,7 +970,7 @@ static GtkWidget *trg_main_window_notebook_new(TrgMainWindow * win)
(priv->peersTreeView)),
gtk_label_new(_("Peers")));
-#ifndef TRG_NO_GRAPH
+#if TRG_WITH_GRAPH
if (trg_prefs_get_bool
(prefs, TRG_PREFS_KEY_SHOW_GRAPH, TRG_PREFS_GLOBAL))
trg_main_window_add_graph(win, FALSE);
@@ -1021,7 +1028,9 @@ static gboolean on_session_get(gpointer data)
return FALSE;
}
- if ((version = session_get_version(newSession)) < TRANSMISSION_MIN_SUPPORTED) {
+ if ((version =
+ session_get_version(newSession)) <
+ TRANSMISSION_MIN_SUPPORTED) {
gchar *msg =
g_strdup_printf(_
("This application supports Transmission %g and later, you have %g."),
@@ -1088,8 +1097,8 @@ static void connchange_whatever_statusicon(TrgMainWindow * win,
TrgMainWindowPrivate *priv = TRG_MAIN_WINDOW_GET_PRIVATE(win);
TrgPrefs *prefs = trg_client_get_prefs(priv->client);
const gchar *display = connected ?
- trg_prefs_get_string(prefs, TRG_PREFS_KEY_PROFILE_NAME,
- TRG_PREFS_CONNECTION) : _("Disconnected");
+ trg_prefs_get_string(prefs, TRG_PREFS_KEY_PROFILE_NAME,
+ TRG_PREFS_CONNECTION) : _("Disconnected");
#ifdef HAVE_LIBAPPINDICATOR
if (priv->appIndicator) {
@@ -1126,16 +1135,16 @@ static void update_whatever_statusicon(TrgMainWindow * win,
trg_strlsize(buf, stats->downRateTotal);
downloadingLabel = g_strdup_printf(_("%d Downloading @ %s"),
- stats->down, buf);
+ stats->down, buf);
gtk_menu_item_set_label(GTK_MENU_ITEM(priv->iconDownloadingItem),
downloadingLabel);
g_free(downloadingLabel);
trg_strlsize(buf, stats->upRateTotal);
seedingLabel = g_strdup_printf(_("%d Seeding @ %s"),
- stats->seeding, buf);
+ stats->seeding, buf);
gtk_menu_item_set_label(GTK_MENU_ITEM(priv->iconSeedingItem),
- seedingLabel);
+ seedingLabel);
g_free(seedingLabel);
}
}
@@ -1209,7 +1218,7 @@ static gboolean on_torrent_get(gpointer data, int mode)
trg_status_bar_update(priv->statusBar, stats, client);
update_whatever_statusicon(win, stats);
-#ifndef TRG_NO_GRAPH
+#if TRG_WITH_GRAPH
if (priv->graphNotebookIndex >= 0)
trg_torrent_graph_set_speed(priv->graph, stats);
#endif
@@ -1318,8 +1327,7 @@ static gboolean trg_torrent_tree_view_visible_func(GtkTreeModel * model,
matchesTracker = (!json
|| !torrent_has_tracker(json,
trg_state_selector_get_url_host_regex
- (priv->
- stateSelector),
+ (priv->stateSelector),
text));
g_free(text);
if (matchesTracker)
@@ -1531,7 +1539,7 @@ void trg_main_window_conn_changed(TrgMainWindow * win, gboolean connected)
trg_main_window_torrent_scrub(win);
trg_state_selector_disconnect(priv->stateSelector);
-#ifndef TRG_NO_GRAPH
+#if TRG_WITH_GRAPH
if (priv->graphNotebookIndex >= 0)
trg_torrent_graph_set_nothing(priv->graph);
#endif
@@ -1597,7 +1605,7 @@ static TrgMenuBar *trg_main_window_menu_bar_new(TrgMainWindow * win)
*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,
-#ifndef TRG_NO_GRAPH
+#if TRG_WITH_GRAPH
*b_show_graph,
#endif
*b_start_now;
@@ -1624,7 +1632,7 @@ static TrgMenuBar *trg_main_window_menu_bar_new(TrgMainWindow * win)
&b_view_stats, "about-button", &b_about, "quit-button",
&b_quit, "dir-filters", &b_dir_filters, "tracker-filters",
&b_tracker_filters,
-#ifndef TRG_NO_GRAPH
+#if TRG_WITH_GRAPH
"show-graph", &b_show_graph,
#endif
"up-queue", &b_up_queue, "down-queue", &b_down_queue,
@@ -1671,7 +1679,7 @@ 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);
-#ifndef TRG_NO_GRAPH
+#if TRG_WITH_GRAPH
g_signal_connect(b_show_graph, "toggled",
G_CALLBACK(trg_main_window_toggle_graph_cb), win);
#endif
@@ -2300,7 +2308,7 @@ void trg_main_window_remove_status_icon(TrgMainWindow * win)
#endif
}
-#ifndef TRG_NO_GRAPH
+#if TRG_WITH_GRAPH
void trg_main_window_add_graph(TrgMainWindow * win, gboolean show)
{
TrgMainWindowPrivate *priv = TRG_MAIN_WINDOW_GET_PRIVATE(win);
@@ -2513,8 +2521,7 @@ static GObject *trg_main_window_constructor(GType type,
self, NULL);
priv->torrentTreeView = trg_main_window_torrent_tree_view_new(self,
- priv->
- filteredTorrentModel);
+ priv->filteredTorrentModel);
g_signal_connect(priv->torrentTreeView, "popup-menu",
G_CALLBACK(torrent_tv_popup_menu_cb), self);
g_signal_connect(priv->torrentTreeView, "button-press-event",
@@ -2562,8 +2569,7 @@ static GObject *trg_main_window_constructor(GType type,
FALSE, FALSE);
gtk_paned_pack2(GTK_PANED(priv->hpaned), my_scrolledwin_new(GTK_WIDGET
- (priv->
- torrentTreeView)),
+ (priv->torrentTreeView)),
TRUE, TRUE);
g_signal_connect(G_OBJECT(priv->stateSelector),
diff --git a/src/trg-main-window.h b/src/trg-main-window.h
index 9a60ea3..e9f3d6d 100644
--- a/src/trg-main-window.h
+++ b/src/trg-main-window.h
@@ -57,7 +57,7 @@ typedef struct {
#define TORRENT_ADD_NOTIFY_TMOUT 3000
GType trg_main_window_get_type(void);
-gboolean trg_add_from_filename(TrgMainWindow * win, gchar ** uris);
+gint trg_add_from_filename(TrgMainWindow * win, gchar ** uris);
gboolean on_session_set(gpointer data);
gboolean on_generic_interactive_action(gpointer data);
void auto_connect_if_required(TrgMainWindow * win, gchar ** args);
@@ -73,6 +73,7 @@ void trg_main_window_notebook_set_visible(TrgMainWindow * win,
gboolean visible);
void connect_cb(GtkWidget * w, gpointer data);
void trg_main_window_reload_dir_aliases(TrgMainWindow * win);
+void trg_main_window_set_start_args(TrgMainWindow * window, gchar ** args);
#if !GTK_CHECK_VERSION(2, 21, 1)
#define gdk_drag_context_get_actions(context) context->actions
diff --git a/src/trg-menu-bar.c b/src/trg-menu-bar.c
index b5e049f..23ec34a 100644
--- a/src/trg-menu-bar.c
+++ b/src/trg-menu-bar.c
@@ -20,7 +20,11 @@
#include <glib/gi18n.h>
#include <gtk/gtk.h>
#include <gdk/gdkkeysyms.h>
+#if GTK_CHECK_VERSION( 3, 0, 0 )
+#include <gdk/gdkkeysyms-compat.h>
+#endif
+#include "trg-torrent-graph.h"
#include "trg-main-window.h"
#include "trg-menu-bar.h"
@@ -52,7 +56,9 @@ enum {
PROP_ACCEL_GROUP,
PROP_DIR_FILTERS,
PROP_TRACKER_FILTERS,
+#if TRG_WITH_GRAPH
PROP_VIEW_SHOW_GRAPH,
+#endif
PROP_MOVE_DOWN_QUEUE,
PROP_MOVE_UP_QUEUE,
PROP_MOVE_BOTTOM_QUEUE,
@@ -91,7 +97,9 @@ struct _TrgMenuBarPrivate {
GtkWidget *mb_quit;
GtkWidget *mb_directory_filters;
GtkWidget *mb_tracker_filters;
+#if TRG_WITH_GRAPH
GtkWidget *mb_view_graph;
+#endif
GtkWidget *mb_down_queue;
GtkWidget *mb_up_queue;
GtkWidget *mb_bottom_queue;
@@ -241,9 +249,11 @@ trg_menu_bar_get_property(GObject * object, guint property_id,
case PROP_ABOUT_BUTTON:
g_value_set_object(value, priv->mb_about);
break;
+#if TRG_WITH_GRAPH
case PROP_VIEW_SHOW_GRAPH:
g_value_set_object(value, priv->mb_view_graph);
break;
+#endif
case PROP_VIEW_STATES_BUTTON:
g_value_set_object(value, priv->mb_view_states);
break;
@@ -412,11 +422,13 @@ static GtkWidget *trg_menu_bar_view_menu_new(TrgMenuBar * mb)
gtk_menu_shell_append(GTK_MENU_SHELL(viewMenu),
priv->mb_view_notebook);
+#if TRG_WITH_GRAPH
priv->mb_view_graph =
trg_menu_bar_view_item_new(priv->prefs, TRG_PREFS_KEY_SHOW_GRAPH,
_("Graph"), priv->mb_view_notebook);
trg_menu_bar_accel_add(mb, priv->mb_view_graph, GDK_F6, 0);
gtk_menu_shell_append(GTK_MENU_SHELL(viewMenu), priv->mb_view_graph);
+#endif
priv->mb_view_stats =
gtk_menu_item_new_with_mnemonic(_("_Statistics"));
@@ -774,8 +786,10 @@ static void trg_menu_bar_class_init(TrgMenuBarClass * klass)
"dir-filters", "Dir Filters");
trg_menu_bar_install_widget_prop(object_class, PROP_TRACKER_FILTERS,
"tracker-filters", "Tracker Filters");
+#if TRG_WITH_GRAPH
trg_menu_bar_install_widget_prop(object_class, PROP_VIEW_SHOW_GRAPH,
"show-graph", "Show Graph");
+#endif
trg_menu_bar_install_widget_prop(object_class, PROP_MOVE_DOWN_QUEUE,
"down-queue", "Down Queue");
trg_menu_bar_install_widget_prop(object_class, PROP_MOVE_UP_QUEUE,
diff --git a/src/trg-preferences-dialog.c b/src/trg-preferences-dialog.c
index 4c774ec..d4f5680 100644
--- a/src/trg-preferences-dialog.c
+++ b/src/trg-preferences-dialog.c
@@ -330,7 +330,7 @@ static void toggle_filter_trackers(GtkToggleButton * w, gpointer win)
gtk_toggle_button_get_active(w));
}
-#ifndef TRG_NO_GRAPH
+#if TRG_WITH_GRAPH
static void toggle_graph(GtkToggleButton * w, gpointer win)
{
if (gtk_toggle_button_get_active(w))
@@ -385,8 +385,7 @@ static void trgp_double_special_dependent(GtkWidget * widget,
(priv->fullUpdateCheck)
&&
gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON
- (priv->
- fullUpdateCheck)));
+ (priv->fullUpdateCheck)));
}
static GtkWidget *trg_prefs_generalPage(TrgPreferencesDialog * dlg)
@@ -696,7 +695,7 @@ static GtkWidget *trg_prefs_viewPage(TrgPreferencesDialog * dlg)
G_CALLBACK(notebook_toggled_cb), priv->win);
hig_workarea_add_wide_control(t, &row, w);
-#ifndef TRG_NO_GRAPH
+#if TRG_WITH_GRAPH
w = trgp_check_new(dlg, _("Show graph"), TRG_PREFS_KEY_SHOW_GRAPH,
TRG_PREFS_GLOBAL, GTK_TOGGLE_BUTTON(w));
g_signal_connect(G_OBJECT(w), "toggled", G_CALLBACK(toggle_graph),
diff --git a/src/trg-remote-prefs-dialog.c b/src/trg-remote-prefs-dialog.c
index 8f866ea..8c921e4 100644
--- a/src/trg-remote-prefs-dialog.c
+++ b/src/trg-remote-prefs-dialog.c
@@ -159,12 +159,10 @@ static void trg_remote_prefs_double_special_dependent(GtkWidget * widget,
gtk_widget_set_sensitive(GTK_WIDGET(data),
gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON
- (priv->
- alt_time_check))
+ (priv->alt_time_check))
||
gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON
- (priv->
- alt_check)));
+ (priv->alt_check)));
}
static void trg_rprefs_time_widget_savefunc(GtkWidget * w,
diff --git a/src/trg-sortable-filtered-model.h b/src/trg-sortable-filtered-model.h
index 9440b32..55e525c 100644
--- a/src/trg-sortable-filtered-model.h
+++ b/src/trg-sortable-filtered-model.h
@@ -49,6 +49,5 @@ GtkTreeModel *trg_sortable_filtered_model_new(GtkTreeSortable *
child_model,
GtkTreePath * root);
-
G_END_DECLS
#endif /* _TRG_SORTABLE_FILTERED_MODEL */
diff --git a/src/trg-stats-dialog.c b/src/trg-stats-dialog.c
index 20d8ea2..7348d5e 100644
--- a/src/trg-stats-dialog.c
+++ b/src/trg-stats-dialog.c
@@ -232,8 +232,9 @@ static gboolean trg_update_stats_timerfunc(gpointer data)
if (TRG_IS_STATS_DIALOG(data)) {
priv = TRG_STATS_DIALOG_GET_PRIVATE(data);
- dispatch_async(priv->client, session_stats(), on_stats_reply,
- data);
+ if (trg_client_is_connected(priv->client))
+ dispatch_async(priv->client, session_stats(), on_stats_reply,
+ data);
}
return FALSE;
diff --git a/src/trg-status-bar.c b/src/trg-status-bar.c
index 0f0b293..94ebab9 100644
--- a/src/trg-status-bar.c
+++ b/src/trg-status-bar.c
@@ -128,23 +128,26 @@ void trg_status_bar_push_connection_msg(TrgStatusBar * sb,
gtk_label_set_text(GTK_LABEL(priv->info_lbl), msg);
}
-void trg_status_bar_connect(TrgStatusBar * sb, JsonObject * session, TrgClient *client)
+void trg_status_bar_connect(TrgStatusBar * sb, JsonObject * session,
+ TrgClient * client)
{
TrgStatusBarPrivate *priv = TRG_STATUS_BAR_GET_PRIVATE(sb);
TrgPrefs *prefs = trg_client_get_prefs(client);
gdouble version = session_get_version(session);
gchar *statusMsg =
- g_strdup_printf(_
- ("Connected: %s (Transmission %g)"),
- trg_prefs_get_string(prefs, TRG_PREFS_KEY_PROFILE_NAME, TRG_PREFS_CONNECTION),
+ g_strdup_printf(_("Connected: %s (Transmission %g)"),
+ trg_prefs_get_string(prefs,
+ TRG_PREFS_KEY_PROFILE_NAME,
+ TRG_PREFS_CONNECTION),
version);
g_message("%s", statusMsg);
trg_status_bar_push_connection_msg(sb, statusMsg);
g_free(statusMsg);
- gtk_label_set_text(GTK_LABEL(priv->speed_lbl), _("Updating torrents..."));
+ gtk_label_set_text(GTK_LABEL(priv->speed_lbl),
+ _("Updating torrents..."));
}
void trg_status_bar_session_update(TrgStatusBar * sb, JsonObject * session)
@@ -244,7 +247,9 @@ TrgStatusBar *trg_status_bar_new(TrgMainWindow * win, TrgClient * client)
{
TrgStatusBar *sb = g_object_new(TRG_TYPE_STATUS_BAR, NULL);
TrgStatusBarPrivate *priv = TRG_STATUS_BAR_GET_PRIVATE(sb);
+
priv->client = client;
priv->win = win;
+
return sb;
}
diff --git a/src/trg-status-bar.h b/src/trg-status-bar.h
index e0ba8d5..c1ee82a 100644
--- a/src/trg-status-bar.h
+++ b/src/trg-status-bar.h
@@ -55,7 +55,8 @@ G_END_DECLS
TrgClient * client);
void trg_status_bar_session_update(TrgStatusBar * sb,
JsonObject * session);
-void trg_status_bar_connect(TrgStatusBar * sb, JsonObject * session, TrgClient *client);
+void trg_status_bar_connect(TrgStatusBar * sb, JsonObject * session,
+ TrgClient * client);
void trg_status_bar_push_connection_msg(TrgStatusBar * sb,
const gchar * msg);
void trg_status_bar_reset(TrgStatusBar * sb);
diff --git a/src/trg-toolbar.c b/src/trg-toolbar.c
index 2fc7149..d829dcc 100644
--- a/src/trg-toolbar.c
+++ b/src/trg-toolbar.c
@@ -261,7 +261,9 @@ static GObject *trg_toolbar_constructor(GType type,
trg_toolbar_item_new(TRG_TOOLBAR(obj), _("Remote Preferences"),
&position, GTK_STOCK_NETWORK, FALSE);
+#if !GTK_CHECK_VERSION( 3, 0, 0 )
gtk_toolbar_set_tooltips(GTK_TOOLBAR(obj), TRUE);
+#endif
g_signal_connect(G_OBJECT(priv->prefs), "pref-profile-changed",
G_CALLBACK(trg_toolbar_refresh_menu), obj);
diff --git a/src/trg-torrent-graph.c b/src/trg-torrent-graph.c
index 94c4ecc..0b47bab 100644
--- a/src/trg-torrent-graph.c
+++ b/src/trg-torrent-graph.c
@@ -27,13 +27,15 @@
* on this widget but with some improvements I didn't do.
*/
+#include "trg-torrent-graph.h"
+
+#if TRG_WITH_GRAPH
+
#include <math.h>
#include <glib.h>
#include <cairo.h>
#include <glib/gi18n.h>
#include <gtk/gtk.h>
-
-#include "trg-torrent-graph.h"
#include "util.h"
/* damn you freebsd */
@@ -633,3 +635,5 @@ unsigned trg_torrent_graph_get_num_bars(TrgTorrentGraph * g)
return n;
}
+
+#endif
diff --git a/src/trg-torrent-graph.h b/src/trg-torrent-graph.h
index c71f3b6..914a184 100644
--- a/src/trg-torrent-graph.h
+++ b/src/trg-torrent-graph.h
@@ -3,9 +3,13 @@
#ifndef _TRG_TORRENT_GRAPH
#define _TRG_TORRENT_GRAPH
-#include <glib-object.h>
#include <gtk/gtk.h>
+#define TRG_WITH_GRAPH !GTK_CHECK_VERSION( 3, 0, 0 )
+
+#if TRG_WITH_GRAPH
+
+#include <glib-object.h>
#include "trg-torrent-model.h"
G_BEGIN_DECLS
@@ -49,4 +53,6 @@ void trg_torrent_graph_set_speed(TrgTorrentGraph * g,
void trg_torrent_graph_set_nothing(TrgTorrentGraph * g);
G_END_DECLS
-#endif /* _TRG_TORRENT_GRAPH */
+
+#endif
+#endif /* _TRG_TORRENT_GRAPH */
diff --git a/src/trg-torrent-props-dialog.c b/src/trg-torrent-props-dialog.c
index d18b577..a0ae22a 100644
--- a/src/trg-torrent-props-dialog.c
+++ b/src/trg-torrent-props-dialog.c
@@ -136,10 +136,12 @@ trg_torrent_props_response_cb(GtkDialog * dlg, gint res_id,
json_object_set_int_member(args, FIELD_SEED_RATIO_MODE,
gtk_combo_box_get_active(GTK_COMBO_BOX
- (priv->seedRatioMode)));
+ (priv->
+ seedRatioMode)));
json_object_set_int_member(args, FIELD_BANDWIDTH_PRIORITY,
gtk_combo_box_get_active(GTK_COMBO_BOX
- (priv->bandwidthPriorityCombo))
+ (priv->
+ bandwidthPriorityCombo))
- 1);
trg_json_widgets_save(priv->widgets, args);
diff --git a/src/trg-tree-view.c b/src/trg-tree-view.c
index 4265c7d..54c5cf5 100644
--- a/src/trg-tree-view.c
+++ b/src/trg-tree-view.c
@@ -313,8 +313,7 @@ static void trg_tree_view_add_column_after(TrgTreeView * tv,
gtk_cell_renderer_text_new();
column = gtk_tree_view_column_new_with_attributes(desc->header,
renderer, "text",
- desc->
- model_column,
+ desc->model_column,
NULL);
break;
@@ -323,8 +322,7 @@ static void trg_tree_view_add_column_after(TrgTreeView * tv,
column = gtk_tree_view_column_new_with_attributes(desc->header,
renderer,
"speed-value",
- desc->
- model_column,
+ desc->model_column,
NULL);
break;
case TRG_COLTYPE_EPOCH:
@@ -332,8 +330,7 @@ static void trg_tree_view_add_column_after(TrgTreeView * tv,
column = gtk_tree_view_column_new_with_attributes(desc->header,
renderer,
"epoch-value",
- desc->
- model_column,
+ desc->model_column,
NULL);
break;
case TRG_COLTYPE_ETA:
@@ -341,8 +338,7 @@ static void trg_tree_view_add_column_after(TrgTreeView * tv,
column = gtk_tree_view_column_new_with_attributes(desc->header,
renderer,
"eta-value",
- desc->
- model_column,
+ desc->model_column,
NULL);
break;
case TRG_COLTYPE_SIZE:
@@ -350,8 +346,7 @@ static void trg_tree_view_add_column_after(TrgTreeView * tv,
column = gtk_tree_view_column_new_with_attributes(desc->header,
renderer,
"size-value",
- desc->
- model_column,
+ desc->model_column,
NULL);
break;
case TRG_COLTYPE_PROG:
@@ -359,8 +354,7 @@ static void trg_tree_view_add_column_after(TrgTreeView * tv,
column = gtk_tree_view_column_new_with_attributes(desc->header,
renderer,
"value",
- desc->
- model_column,
+ desc->model_column,
NULL);
break;
case TRG_COLTYPE_RATIO:
@@ -368,8 +362,7 @@ static void trg_tree_view_add_column_after(TrgTreeView * tv,
column = gtk_tree_view_column_new_with_attributes(desc->header,
renderer,
"ratio-value",
- desc->
- model_column,
+ desc->model_column,
NULL);
break;
case TRG_COLTYPE_WANTED:
@@ -394,8 +387,7 @@ static void trg_tree_view_add_column_after(TrgTreeView * tv,
column = gtk_tree_view_column_new_with_attributes(desc->header,
renderer,
"priority-value",
- desc->
- model_column,
+ desc->model_column,
NULL);
break;
case TRG_COLTYPE_NUMGTZERO:
@@ -403,8 +395,7 @@ static void trg_tree_view_add_column_after(TrgTreeView * tv,
column = gtk_tree_view_column_new_with_attributes(desc->header,
renderer,
"value",
- desc->
- model_column,
+ desc->model_column,
NULL);
break;
case TRG_COLTYPE_NUMGTEQZERO:
@@ -412,8 +403,7 @@ static void trg_tree_view_add_column_after(TrgTreeView * tv,
column = gtk_tree_view_column_new_with_attributes(desc->header,
renderer,
"value",
- desc->
- model_column,
+ desc->model_column,
NULL);
break;
}
@@ -567,8 +557,7 @@ void trg_tree_view_setup_columns(TrgTreeView * tv)
json_node_get_string
((JsonNode
*)
- cli->
- data));
+ cli->data));
if (desc) {
gint64 width = json_node_get_int((JsonNode *) wli->data);
trg_tree_view_add_column(tv, desc, width);
diff --git a/src/util.c b/src/util.c
index 7594c46..944be9a 100644
--- a/src/util.c
+++ b/src/util.c
@@ -533,3 +533,59 @@ evutil_vsnprintf(char *buf, size_t buflen, const char *format, va_list ap)
return r;
#endif
}
+
+gboolean is_minimised_arg(gchar * arg)
+{
+ return !g_strcmp0(arg, "-m")
+ || !g_strcmp0(arg, "--minimized")
+ || !g_strcmp0(arg, "/m");
+}
+
+gboolean should_be_minimised(int argc, char *argv[])
+{
+ int i;
+ for (i = 1; i < argc; i++)
+ if (is_minimised_arg(argv[i]))
+ return TRUE;
+
+ return FALSE;
+}
+
+gchar **convert_args(int argc, char *argv[])
+{
+ gchar *cwd = g_get_current_dir();
+ gchar **files = NULL;
+
+ if (argc > 1) {
+ GSList *list = NULL;
+ int i;
+
+ for (i = 1; i < argc; i++) {
+ if (is_minimised_arg(argv[i])) {
+ continue;
+ } else if (!is_url(argv[i]) && !is_magnet(argv[i])
+ && g_file_test(argv[i], G_FILE_TEST_IS_REGULAR)
+ && !g_path_is_absolute(argv[i])) {
+ list = g_slist_append(list,
+ g_build_path(G_DIR_SEPARATOR_S, cwd,
+ argv[i], NULL));
+ } else {
+ list = g_slist_append(list, g_strdup(argv[i]));
+ }
+ }
+
+ if (list) {
+ GSList *li;
+ files = g_new0(gchar *, g_slist_length(list) + 1);
+ i = 0;
+ for (li = list; li; li = g_slist_next(li)) {
+ files[i++] = li->data;
+ }
+ g_slist_free(list);
+ }
+ }
+
+ g_free(cwd);
+
+ return files;
+}
diff --git a/src/util.h b/src/util.h
index 07ab0bf..d6187c1 100644
--- a/src/util.h
+++ b/src/util.h
@@ -90,4 +90,8 @@ gboolean is_url(gchar * string);
gboolean is_magnet(gchar * string);
GtkWidget *gtr_combo_box_new_enum(const char *text_1, ...);
+gchar **convert_args(int argc, char *argv[]);
+gboolean should_be_minimised(int argc, char *argv[]);
+gboolean is_minimised_arg(gchar * arg);
+
#endif /* UTIL_H_ */
diff --git a/src/win32-mailslot.c b/src/win32-mailslot.c
new file mode 100644
index 0000000..50fadad
--- /dev/null
+++ b/src/win32-mailslot.c
@@ -0,0 +1,192 @@
+/*
+ * transmission-remote-gtk - A GTK RPC client to Transmission
+ * Copyright (C) 2011 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.
+ */
+
+#define TRG_MAILSLOT_NAME "\\\\.\\mailslot\\TransmissionRemoteGTK" //Name given to the Mailslot
+#define MAILSLOT_BUFFER_SIZE 1024*32
+
+#include <windows.h>
+#include <glib-object.h>
+#include <gtk/gtk.h>
+#include <json-glib/json-glib.h>
+
+#include "trg-main-window.h"
+#include "win32-mailslot.h"
+
+struct trg_mailslot_recv_args {
+ TrgMainWindow *win;
+ gchar **uris;
+ gboolean present;
+};
+
+/* to be queued into the glib main loop with g_idle_add() */
+
+static gboolean mailslot_recv_args(gpointer data)
+{
+ struct trg_mailslot_recv_args *args =
+ (struct trg_mailslot_recv_args *) data;
+
+ if (args->present) {
+ gtk_window_deiconify(GTK_WINDOW(args->win));
+ gtk_window_present(GTK_WINDOW(args->win));
+ }
+
+ if (args->uris)
+ trg_add_from_filename(args->win, args->uris);
+
+ g_free(args);
+
+ return FALSE;
+}
+
+static gpointer mailslot_recv_thread(gpointer data)
+{
+ TrgMainWindow *win = TRG_MAIN_WINDOW(data);
+ JsonParser *parser;
+ char szBuffer[MAILSLOT_BUFFER_SIZE];
+ HANDLE hMailslot;
+ DWORD cbBytes;
+ BOOL bResult;
+
+ hMailslot = CreateMailslot(TRG_MAILSLOT_NAME, // mailslot name
+ MAILSLOT_BUFFER_SIZE, // input buffer size
+ MAILSLOT_WAIT_FOREVER, // no timeout
+ NULL); // default security attribute
+
+ if (INVALID_HANDLE_VALUE == hMailslot) {
+ g_error("\nError occurred while creating the mailslot: %d",
+ GetLastError());
+ return NULL; //Error
+ }
+
+ while (1) {
+ bResult = ReadFile(hMailslot, // handle to mailslot
+ szBuffer, // buffer to receive data
+ sizeof(szBuffer), // size of buffer
+ &cbBytes, // number of bytes read
+ NULL); // not overlapped I/O
+
+ if ((!bResult) || (0 == cbBytes)) {
+ g_error("Mailslot error from client: %d", GetLastError());
+ break;
+ }
+
+ parser = json_parser_new();
+
+ if (json_parser_load_from_data(parser, szBuffer, cbBytes, NULL)) {
+ JsonNode *node = json_parser_get_root(parser);
+ JsonObject *obj = json_node_get_object(node);
+ struct trg_mailslot_recv_args *args =
+ g_new0(struct trg_mailslot_recv_args, 1);
+
+ args->present = json_object_has_member(obj, "present")
+ && json_object_get_boolean_member(obj, "present");
+ args->win = win;
+
+ if (json_object_has_member(obj, "args")) {
+ JsonArray *array =
+ json_object_get_array_member(obj, "args");
+ GList *arrayList = json_array_get_elements(array);
+
+ if (arrayList) {
+ guint arrayLength = g_list_length(arrayList);
+ guint i = 0;
+ GList *li;
+
+ args->uris = g_new0(gchar *, arrayLength + 1);
+
+ for (li = arrayList; li; li = g_list_next(li)) {
+ const gchar *liStr =
+ json_node_get_string((JsonNode *) li->data);
+ args->uris[i++] = g_strdup(liStr);
+ }
+
+ g_list_free(arrayList);
+ }
+ }
+
+ json_node_free(node);
+
+ g_idle_add(mailslot_recv_args, args);
+ }
+
+ g_object_unref(parser);
+ }
+
+ CloseHandle(hMailslot);
+ return NULL; //Success
+}
+
+void mailslot_start_background_listener(TrgMainWindow * win)
+{
+ g_thread_create(mailslot_recv_thread, win, FALSE, NULL);
+}
+
+gboolean mailslot_send_message(gchar ** args)
+{
+ HANDLE hMailSlot = CreateFile(TRG_MAILSLOT_NAME, // mailslot name
+ GENERIC_WRITE, // mailslot write only
+ FILE_SHARE_READ, // required for mailslots
+ NULL, // default security attributes
+ OPEN_EXISTING, // opens existing mailslot
+ FILE_ATTRIBUTE_NORMAL, // normal attributes
+ NULL); // no template file
+
+ if (hMailSlot != INVALID_HANDLE_VALUE) {
+ DWORD cbBytes;
+ JsonNode *node = json_node_new(JSON_NODE_OBJECT);
+ JsonObject *obj = json_object_new();
+ JsonArray *array = json_array_new();
+ JsonGenerator *generator;
+ gchar *msg;
+ int i;
+
+ if (args) {
+ for (i = 0; args[i]; i++)
+ json_array_add_string_element(array, args[i]);
+
+ json_object_set_array_member(obj, "args", array);
+
+ g_strfreev(args);
+ } else {
+ json_object_set_boolean_member(obj, "present", TRUE);
+ }
+
+ json_node_take_object(node, obj);
+
+ generator = json_generator_new();
+ json_generator_set_root(generator, node);
+ msg = json_generator_to_data(generator, NULL);
+
+ json_node_free(node);
+ g_object_unref(generator);
+
+ WriteFile(hMailSlot, // handle to mailslot
+ msg, // buffer to write from
+ strlen(msg) + 1, // number of bytes to write, include the NULL
+ &cbBytes, // number of bytes written
+ NULL);
+
+ CloseHandle(hMailSlot);
+ g_free(msg);
+
+ return TRUE;
+ }
+
+ return FALSE;
+}
diff --git a/src/win32-mailslot.h b/src/win32-mailslot.h
new file mode 100644
index 0000000..66ff2a5
--- /dev/null
+++ b/src/win32-mailslot.h
@@ -0,0 +1,29 @@
+/*
+ * transmission-remote-gtk - A GTK RPC client to Transmission
+ * Copyright (C) 2011 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 WIN32_MAILSLOT_H_
+#define WIN32_MAILSLOT_H_
+
+#include <windows.h>
+#include "trg-main-window.h"
+
+void mailslot_start_background_listener(TrgMainWindow * win);
+int mailslot_send_message(gchar ** args);
+
+#endif /* WIN32_MAILSLOT_H_ */