From c427fa73c4f7853de992eda9de1c818c2ee525aa Mon Sep 17 00:00:00 2001 From: Alan Fitton Date: Wed, 18 Jan 2012 23:30:02 +0000 Subject: 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. --- src/main.c | 388 ++++++++++++++++++------------------------------------------- 1 file changed, 111 insertions(+), 277 deletions(-) (limited to 'src/main.c') 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 #include #include -#ifdef HAVE_LIBUNIQUE + +#if !GTK_CHECK_VERSION( 3, 0, 0 ) && HAVE_LIBUNIQUE #include +#elif GTK_CHECK_VERSION( 3, 0, 0 ) +#include "trg-gtk-app.h" #elif WIN32 -#include +#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; } -- cgit v1.2.3