diff options
-rw-r--r-- | src/Makefile.am | 19 | ||||
-rw-r--r-- | src/device.c | 6 | ||||
-rw-r--r-- | src/device.h | 1 | ||||
-rw-r--r-- | src/gui.c (renamed from src/sbmanager.c) | 428 | ||||
-rw-r--r-- | src/gui.h | 46 | ||||
-rw-r--r-- | src/iconstate.c | 113 | ||||
-rw-r--r-- | src/iconstate.h | 40 | ||||
-rw-r--r-- | src/main.c | 309 | ||||
-rw-r--r-- | src/sbmgr.c | 101 | ||||
-rw-r--r-- | src/sbmgr.h | 40 |
10 files changed, 759 insertions, 344 deletions
diff --git a/src/Makefile.am b/src/Makefile.am index fde2b9c..fe69ce7 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -22,13 +22,16 @@ AM_LDFLAGS = \ bin_PROGRAMS = sbmanager -sbmanager_SOURCES = device.c \ - device.h \ - utility.c \ - utility.h \ - sbitem.c \ - sbitem.h \ - sbmanager.c +noinst_LTLIBRARIES = libsbmanager.la +libsbmanager_la_SOURCES = device.c device.h \ + utility.c utility.h \ + gui.c gui.h \ + sbitem.c sbitem.h \ + sbmgr.c sbmgr.h +libsbmanager_la_CFLAGS = $(AM_CFLAGS) +libsbmanager_la_LIBADD = $(AM_LDFLAGS) + +sbmanager_SOURCES = main.c sbmanager_CFLAGS = $(AM_CFLAGS) sbmanager_LDFLAGS = $(AM_LDFLAGS) - +sbmanager_LDADD = libsbmanager.la diff --git a/src/device.c b/src/device.c index 9cfd667..bf2f2a2 100644 --- a/src/device.c +++ b/src/device.c @@ -54,6 +54,8 @@ sbservices_client_t device_sbs_new(const char *uuid, GError **error) lockdownd_client_t client = NULL; uint16_t port = 0; + printf("%s: %s\n", __func__, uuid); + g_mutex_lock(libiphone_mutex); if (IPHONE_E_SUCCESS != iphone_device_new(&phone, uuid)) { if (error) @@ -208,10 +210,14 @@ gboolean device_get_info(const char *uuid, device_info_t *device_info, GError ** lockdownd_client_t client = NULL; gboolean res = FALSE; + printf("%s: %s\n", __func__, uuid); + if (!device_info) { return res; } + printf("%s\n", __func__); + g_mutex_lock(libiphone_mutex); if (IPHONE_E_SUCCESS != iphone_device_new(&phone, uuid)) { *error = g_error_new(device_domain, ENODEV, _("No device found, is it plugged in?")); diff --git a/src/device.h b/src/device.h index 6afaa84..1fa7c4b 100644 --- a/src/device.h +++ b/src/device.h @@ -28,6 +28,7 @@ #include <libiphone/sbservices.h> struct device_info_int { + char *uuid; char *device_name; char *device_type; guint battery_capacity; diff --git a/src/sbmanager.c b/src/gui.c index 6cb01e5..e7466d0 100644 --- a/src/sbmanager.c +++ b/src/gui.c @@ -1,5 +1,6 @@ /** - * sbmanager -- Manage iPhone/iPod Touch SpringBoard icons from your computer! + * gui.c + * GUI implementations. * * Copyright (C) 2009-2010 Nikias Bassen <nikias@gmx.li> * Copyright (C) 2009-2010 Martin Szulecki <opensuse@sukimashita.com> @@ -41,9 +42,11 @@ #include <clutter-gtk/clutter-gtk.h> #include <gdk-pixbuf/gdk-pixbuf.h> +#include "sbmgr.h" #include "utility.h" #include "device.h" #include "sbitem.h" +#include "gui.h" #define STAGE_WIDTH 320 #define STAGE_HEIGHT 480 @@ -61,14 +64,7 @@ ClutterColor stage_color = { 0x00, 0x00, 0x00, 0xff }; /* Black */ ClutterColor battery_color = { 0xff, 0xff, 0xff, 0x9f }; ClutterColor spinner_color = { 0xff, 0xff, 0xff, 0xf0 }; -GtkWidget *main_window; -GtkWidget *statusbar; -GtkWidget *toolbar; - -typedef struct { - char *uuid; - device_info_t device_info; -} SBManagerApp; +GtkWidget *clutter_gtk_widget; const ClutterActorBox dock_area = { 0.0, STAGE_HEIGHT - DOCK_HEIGHT, STAGE_WIDTH, STAGE_HEIGHT }; @@ -88,6 +84,7 @@ ClutterActor *page_indicator_group = NULL; ClutterActor *fade_rectangle = NULL; ClutterActor *spinner = NULL; ClutterTimeline *spinner_timeline = NULL; +ClutterTimeline *clock_timeline = NULL; GMutex *selected_mutex = NULL; SBItem *selected_item = NULL; @@ -106,8 +103,11 @@ GList *sbpages = NULL; guint num_dock_items = 0; -char *match_uuid = NULL; sbservices_client_t sbc = NULL; +device_info_t device_info = NULL; + +static finished_cb_t finished_callback = NULL; +static device_info_cb_t device_info_callback = NULL; int current_page = 0; struct timeval last_page_switch; @@ -265,33 +265,6 @@ static GList *iconlist_insert_item_at(GList *iconlist, SBItem *newitem, gfloat i return g_list_insert(iconlist, newitem, newpos >= MAX_PAGE_ITEMS ? 15:newpos); } - -/* window */ -static gboolean win_map_cb(GtkWidget *widget, GdkEvent *event, SBManagerApp *app) -{ - debug_printf("%s: mapped\n", __func__); - clutter_stage_ensure_redraw(CLUTTER_STAGE(stage)); - - return TRUE; -} - -static gboolean win_focus_change_cb(GtkWidget *widget, GdkEventFocus *event, gpointer user_data) -{ - if (!user_data) { - return FALSE; - } - - ClutterActor *actor = (ClutterActor*)user_data; - - if (event->in) { - clutter_timeline_start(CLUTTER_TIMELINE(actor)); - } else { - clutter_timeline_pause(CLUTTER_TIMELINE(actor)); - } - - return TRUE; -} - /* clock */ static void clock_set_time(ClutterActor *label, time_t t) { @@ -302,7 +275,7 @@ static void clock_set_time(ClutterActor *label, time_t t) g_free(ctext); } -static void clock_update_cb(ClutterTimeline *timeline, gint msecs, SBManagerApp *app) +static void clock_update_cb(ClutterTimeline *timeline, gint msecs, gpointer data) { clock_set_time(clock_label, time(NULL)); } @@ -581,7 +554,7 @@ static void gui_show_previous_page() gui_set_current_page(current_page-1, TRUE); } -static plist_t gui_get_iconstate() +plist_t gui_get_iconstate() { plist_t iconstate = NULL; plist_t pdockarray = NULL; @@ -1105,19 +1078,17 @@ static void gui_set_iconstate(plist_t iconstate) static void gui_disable_controls() { - gtk_widget_set_sensitive(toolbar, FALSE); gui_fade_start(); gui_spinner_start(); } static void gui_enable_controls() { - gtk_widget_set_sensitive(toolbar, TRUE); gui_spinner_stop(); gui_fade_stop(); } -static gboolean wait_icon_load_finished(gpointer data) +static gboolean wait_icon_load_finished(gpointer user_data) { gboolean res = TRUE; g_mutex_lock(icon_loader_mutex); @@ -1125,14 +1096,18 @@ static gboolean wait_icon_load_finished(gpointer data) if (icons_loaded >= total_icons) { gui_enable_controls(); res = FALSE; + if (finished_callback) { + finished_callback(TRUE); + finished_callback = NULL; + } } g_mutex_unlock(icon_loader_mutex); return res; } -static gboolean gui_pages_init_cb(gpointer data) +static gboolean gui_pages_init_cb(gpointer user_data) { - SBManagerApp *app = (SBManagerApp *)data; + const char *uuid = (const char*)user_data; GError *error = NULL; plist_t iconstate = NULL; @@ -1144,7 +1119,7 @@ static gboolean gui_pages_init_cb(gpointer data) /* connect to sbservices */ if (!sbc) - sbc = device_sbs_new(app->uuid, &error); + sbc = device_sbs_new(uuid, &error); if (error) { g_printerr("%s", error->message); @@ -1171,152 +1146,64 @@ static gboolean gui_pages_init_cb(gpointer data) return FALSE; } -static gboolean reload_button_clicked_cb(GtkButton *button, gpointer user_data) +static gboolean update_device_info_cb(gpointer user_data) { - SBManagerApp *app = (SBManagerApp *)user_data; - clutter_threads_add_idle((GSourceFunc)gui_pages_init_cb, app); - return TRUE; -} - -static gboolean set_icon_state_cb(gpointer user_data) -{ - SBManagerApp *app = (SBManagerApp *)user_data; - - plist_t iconstate = gui_get_iconstate(); - if (iconstate) { - GError *error = NULL; - - if (!sbc) - sbc = device_sbs_new(app->uuid, &error); - - if (error) { - g_printerr("%s", error->message); - g_error_free(error); - error = NULL; - } - - if (sbc) { - device_sbs_set_iconstate(sbc, iconstate, &error); - device_sbs_free(sbc); - sbc = NULL; - plist_free(iconstate); - } - - if (error) { - g_printerr("%s", error->message); - g_error_free(error); - error = NULL; - } - } - return FALSE; -} - -static gboolean apply_button_clicked_cb(GtkButton *button, gpointer user_data) -{ - SBManagerApp *app = (SBManagerApp *)user_data; - - clutter_threads_add_idle((GSourceFunc)set_icon_state_cb, app); - - return TRUE; -} - -static gboolean info_button_clicked_cb(GtkButton *button, gpointer user_data) -{ - const gchar *authors[] = { - "Nikias Bassen <nikias@gmx.li>", - "Martin Szulecki <opensuse@sukimashita.com>", - NULL - }; - const gchar *copyright = "Copyright © 2009-2010 Nikias Bassen, Martin Szulecki; All Rights Reserved."; - const gchar *program_name = PACKAGE_NAME; - const gchar *version = PACKAGE_VERSION; - const gchar *comments = _("Manage iPhone/iPod Touch SpringBoard from the computer"); - const gchar *website = "http://cgit.sukimashita.com/sbmanager.git"; - const gchar *website_label = _("Project Site"); - const gchar *translators = "Français: Christophe Fergeau\n"; - - gtk_show_about_dialog(GTK_WINDOW(main_window), - "authors", authors, - "copyright", copyright, - "program-name", program_name, - "version", version, - "comments", comments, - "website", website, - "website-label", website_label, - "translator-credits", translators, - NULL); - return TRUE; -} - -static void quit_program_cb(GtkWidget *widget, gpointer user_data) -{ - /* cleanup */ - if (sbc) - device_sbs_free(sbc); - - iphone_event_unsubscribe(); - gtk_main_quit(); -} - -static gboolean quit_button_clicked_cb(GtkButton *button, gpointer user_data) -{ - quit_program_cb(GTK_WIDGET(button), user_data); - return TRUE; -} - -static void gui_error_dialog(const gchar *string) -{ - GtkWidget *dialog = gtk_message_dialog_new_with_markup (GTK_WINDOW(main_window), GTK_DIALOG_DESTROY_WITH_PARENT, GTK_MESSAGE_ERROR, GTK_BUTTONS_CLOSE, "<b>%s</b>", _("Error")); - gtk_window_set_title(GTK_WINDOW(dialog), PACKAGE_NAME); - gtk_message_dialog_format_secondary_text(GTK_MESSAGE_DIALOG(dialog), "%s", string); - g_signal_connect_swapped (dialog, "response", G_CALLBACK(gtk_widget_destroy), dialog); - gtk_widget_show(dialog); -} - -static gboolean update_device_info_cb(gpointer data) -{ - if (!data) - return FALSE; - SBManagerApp *app = (SBManagerApp*)data; - if (app->device_info && app->device_info->device_name) { - gchar *wndtitle = g_strdup_printf("%s - " PACKAGE_NAME, app->device_info->device_name); - gtk_window_set_title(GTK_WINDOW(main_window), wndtitle); - g_free(wndtitle); + device_info_t di = (device_info_t)user_data; + if (di) { + clutter_text_set_text(CLUTTER_TEXT(type_label), di->device_type); } else { - gtk_window_set_title(GTK_WINDOW(main_window), PACKAGE_NAME); + clutter_text_set_text(CLUTTER_TEXT(type_label), NULL); } - clutter_text_set_text(CLUTTER_TEXT(type_label), app->device_info->device_type); return FALSE; } static gboolean update_battery_info_cb(gpointer user_data) { - SBManagerApp *app = (SBManagerApp*)user_data; + const char *uuid = (const char*)user_data; GError *error = NULL; gboolean res = TRUE; - if (device_get_info(app->uuid, &app->device_info, &error)) { - clutter_actor_set_size(battery_level, (guint) (((double) (app->device_info->battery_capacity) / 100.0) * 15), 6); - if (app->device_info->battery_capacity == 100) { + if (device_get_info(uuid, &device_info, &error)) { + clutter_actor_set_size(battery_level, (guint) (((double) (device_info->battery_capacity) / 100.0) * 15), 6); + if (device_info->battery_capacity == 100) { res = FALSE; } } return res; } -static gpointer device_add_cb(gpointer user_data) +static gboolean init_battery_info_cb(gpointer user_data) +{ + clutter_actor_set_size(battery_level, (guint) (((double) (device_info->battery_capacity) / 100.0) * 15), 6); + return FALSE; +} + +void gui_pages_free() +{ + clutter_threads_add_timeout(0, (GSourceFunc)(update_device_info_cb), NULL); + pages_free(); + if (sbc) { + device_sbs_free(sbc); + sbc = NULL; + } +} + +static gboolean device_info_cb(gpointer user_data) { - SBManagerApp *app = (SBManagerApp*)user_data; GError *error = NULL; - if (device_get_info(app->uuid, &app->device_info, &error)) { + const char *uuid = (const char*)user_data; + if (device_get_info(uuid, &device_info, &error)) { /* Update device info */ - clutter_threads_add_idle((GSourceFunc)update_device_info_cb, app); + clutter_threads_add_idle((GSourceFunc)update_device_info_cb, device_info); /* Update battery information */ - clutter_threads_add_idle((GSourceFunc)update_battery_info_cb, app); + clutter_threads_add_idle((GSourceFunc)init_battery_info_cb, NULL); /* Register battery state read timeout */ - clutter_threads_add_timeout(app->device_info->battery_poll_interval * 1000, (GSourceFunc)update_battery_info_cb, app); - /* Load icons */ - clutter_threads_add_idle((GSourceFunc)gui_pages_init_cb, app); + clutter_threads_add_timeout(device_info->battery_poll_interval * 1000, (GSourceFunc)update_battery_info_cb, (gpointer)uuid); + + if (device_info_callback) { + device_info_callback(device_info->device_name, device_info->device_name); + device_info_callback = NULL; + } } else { if (error) { g_printerr("%s", error->message); @@ -1324,92 +1211,48 @@ static gpointer device_add_cb(gpointer user_data) } else { g_printerr(_("Unknown error occurred")); } - } - return NULL; -} - -static void device_event_cb(const iphone_event_t *event, void *user_data) -{ - SBManagerApp *app = (SBManagerApp*)user_data; - if (event->event == IPHONE_DEVICE_ADD) { - if (!app->uuid && (!match_uuid || !strcasecmp(match_uuid, event->uuid))) { - debug_printf("Device add event: adding device %s\n", event->uuid); - app->uuid = g_strdup(event->uuid); - g_thread_create(device_add_cb, app, FALSE, NULL); - } else { - debug_printf("Device add event: ignoring device %s\n", event->uuid); - } - } else if (event->event == IPHONE_DEVICE_REMOVE) { - if (app->uuid && !strcasecmp(app->uuid, event->uuid)) { - debug_printf("Device remove event: removing device %s\n", event->uuid); - free(app->uuid); - app->uuid = NULL; - device_info_free(app->device_info); - clutter_threads_add_timeout(0, (GSourceFunc)(update_device_info_cb), app); - pages_free(); - } else { - debug_printf("Device remove event: ignoring device %s\n", event->uuid); + if (finished_callback) { + finished_callback(FALSE); + finished_callback = NULL; } } + return FALSE; } -static void gui_init(SBManagerApp* app) +void gui_pages_load(const char *uuid, device_info_cb_t info_cb, finished_cb_t finished_cb) { - ClutterTimeline *timeline; - ClutterActor *actor; - - main_window = gtk_window_new(GTK_WINDOW_TOPLEVEL); - gtk_window_set_resizable(GTK_WINDOW(main_window), FALSE); - - gtk_window_set_title(GTK_WINDOW(main_window), PACKAGE_NAME); - - GtkWidget *vbox = gtk_vbox_new(FALSE, 6); - gtk_container_add(GTK_CONTAINER(main_window), vbox); - gtk_widget_show(vbox); + printf("%s: %s\n", __func__, uuid); + finished_callback = finished_cb; + device_info_callback = info_cb; - /* create a toolbar */ - toolbar = gtk_toolbar_new(); - gtk_box_pack_start(GTK_BOX(vbox), toolbar, FALSE, FALSE, 0); + /* Load icons */ + clutter_threads_add_idle((GSourceFunc)gui_pages_init_cb, (gpointer)uuid); - GtkToolItem *btn_reload = gtk_tool_button_new_from_stock(GTK_STOCK_REFRESH); - gtk_tool_item_set_tooltip_text(btn_reload, _("Reload icons from device")); - gtk_toolbar_insert(GTK_TOOLBAR(toolbar), btn_reload, -1); + /* Load device information */ + g_thread_create((GThreadFunc)device_info_cb, (gpointer)uuid, FALSE, NULL); +} - GtkToolItem *btn_apply = gtk_tool_button_new_from_stock(GTK_STOCK_APPLY); - gtk_tool_item_set_tooltip_text(btn_apply, _("Upload changes to device")); - gtk_toolbar_insert(GTK_TOOLBAR(toolbar), btn_apply, -1); +GtkWidget *gui_init() +{ + device_info = device_info_new(); + ClutterActor *actor; - GtkToolItem *btn_info = gtk_tool_button_new_from_stock(GTK_STOCK_INFO); - gtk_tool_item_set_tooltip_text(btn_info, _("Get info about this cool program")); - gtk_toolbar_insert(GTK_TOOLBAR(toolbar), btn_info, -1); + if (!g_thread_supported()) + g_thread_init(NULL); - GtkToolItem *spacer = gtk_tool_item_new(); - gtk_tool_item_set_expand(spacer, TRUE); - gtk_toolbar_insert(GTK_TOOLBAR(toolbar), spacer, -1); + icon_loader_mutex = g_mutex_new(); - GtkToolItem *btn_quit = gtk_tool_button_new_from_stock(GTK_STOCK_QUIT); - gtk_tool_item_set_tooltip_text(btn_quit, _("Quit this program")); - gtk_toolbar_insert(GTK_TOOLBAR(toolbar), btn_quit, -1); + /* initialize clutter threading environment */ + clutter_threads_init(); - gtk_widget_show(toolbar); + if (gtk_clutter_init(NULL, NULL) != CLUTTER_INIT_SUCCESS) { + g_error("Unable to initialize GtkClutter"); + } - /* set up signal handlers */ - g_signal_connect(btn_reload, "clicked", G_CALLBACK(reload_button_clicked_cb), app); - g_signal_connect(btn_apply, "clicked", G_CALLBACK(apply_button_clicked_cb), app); - g_signal_connect(btn_info, "clicked", G_CALLBACK(info_button_clicked_cb), NULL); - g_signal_connect(btn_quit, "clicked", G_CALLBACK(quit_button_clicked_cb), NULL); + gettimeofday(&last_page_switch, NULL); /* Create the clutter widget */ GtkWidget *clutter_widget = gtk_clutter_embed_new(); - gtk_box_pack_start(GTK_BOX(vbox), clutter_widget, TRUE, TRUE, 0); - gtk_widget_show(clutter_widget); - gtk_widget_grab_focus(clutter_widget); - - /* create a statusbar */ - statusbar = gtk_statusbar_new(); - gtk_statusbar_set_has_resize_grip(GTK_STATUSBAR(statusbar), FALSE); - gtk_box_pack_start(GTK_BOX(vbox), statusbar, FALSE, FALSE, 0); - gtk_widget_show(statusbar); /* Set the size of the widget, because we should not set the size of its * stage when using GtkClutterEmbed. @@ -1421,8 +1264,8 @@ static void gui_init(SBManagerApp* app) clutter_stage_set_color(CLUTTER_STAGE(stage), &stage_color); /* attach to stage signals */ - g_signal_connect(stage, "motion-event", G_CALLBACK(stage_motion_cb), app); - g_signal_connect(stage, "key-press-event", G_CALLBACK(stage_key_press_cb), app); + g_signal_connect(stage, "motion-event", G_CALLBACK(stage_motion_cb), NULL); + g_signal_connect(stage, "key-press-event", G_CALLBACK(stage_key_press_cb), NULL); /* Load ui background */ GError *err = NULL; @@ -1488,27 +1331,17 @@ static void gui_init(SBManagerApp* app) clutter_actor_show(stage); /* Create a timeline to manage animation */ - timeline = clutter_timeline_new(200); - clutter_timeline_set_loop(timeline, TRUE); /* have it loop */ + clock_timeline = clutter_timeline_new(200); + clutter_timeline_set_loop(clock_timeline, TRUE); /* have it loop */ /* fire a callback for frame change */ - g_signal_connect(timeline, "completed", G_CALLBACK(clock_update_cb), app); + g_signal_connect(clock_timeline, "completed", G_CALLBACK(clock_update_cb), NULL); /* and start it */ - clutter_timeline_start(timeline); - - /* attach to window signals */ - g_signal_connect(G_OBJECT(main_window), "map-event", G_CALLBACK(win_map_cb), app); - g_signal_connect(G_OBJECT(main_window), "focus-in-event", G_CALLBACK(win_focus_change_cb), timeline); - g_signal_connect(G_OBJECT(main_window), "focus-out-event", G_CALLBACK(win_focus_change_cb), timeline); + clutter_timeline_start(clock_timeline); selected_mutex = g_mutex_new(); - /* Show the window. This also sets the stage's bounding box. */ - gtk_widget_show_all(GTK_WIDGET(main_window)); - - g_set_printerr_handler((GPrintFunc)gui_error_dialog); - /* Position and update the clock */ clock_set_time(clock_label, time(NULL)); clutter_actor_show(clock_label); @@ -1518,88 +1351,11 @@ static void gui_init(SBManagerApp* app) clutter_group_add(CLUTTER_GROUP(stage), battery_level); clutter_actor_set_position(battery_level, 298, 6); - /* Stop the application when the window is closed */ - g_signal_connect(main_window, "hide", G_CALLBACK(quit_program_cb), app); - - /* get notified when plug in/out events occur */ - iphone_event_subscribe(device_event_cb, app); + return clutter_widget; } -/* main */ -static void print_usage(int argc, char **argv) +void gui_deinit() { - char *name = NULL; - - name = strrchr(argv[0], '/'); - printf("Usage: %s [OPTIONS]\n", (name ? name + 1 : argv[0])); - printf("Manage SpringBoard icons of an iPhone/iPod Touch.\n\n"); - printf(" -d, --debug\t\tenable communication debugging\n"); - printf(" -D, --debug-app\tenable application debug messages\n"); - printf(" -u, --uuid UUID\ttarget specific device by its 40-digit device UUID\n"); - printf(" -h, --help\t\tprints usage information\n"); - printf("\n"); -} - -int main(int argc, char **argv) -{ - SBManagerApp *app; - int i; - - app = g_new0(SBManagerApp, 1); - if (!app) { - printf("Error: out of memory!\n"); - return -1; - } - - gettimeofday(&last_page_switch, NULL); - - app->uuid = NULL; - - /* parse cmdline args */ - for (i = 1; i < argc; i++) { - if (!strcmp(argv[i], "-d") || !strcmp(argv[i], "--debug")) { - iphone_set_debug_level(1); - continue; - } else if (!strcmp(argv[i], "-D") || !strcmp(argv[i], "--debug-app")) { - set_debug(TRUE); - continue; - } else if (!strcmp(argv[i], "-u") || !strcmp(argv[i], "--uuid")) { - i++; - if (!argv[i] || (strlen(argv[i]) != 40)) { - print_usage(argc, argv); - return 0; - } - match_uuid = g_strndup(argv[i], 40); - continue; - } else if (!strcmp(argv[i], "-h") || !strcmp(argv[i], "--help")) { - print_usage(argc, argv); - return 0; - } else { - print_usage(argc, argv); - return 0; - } - } - - if (!g_thread_supported()) - g_thread_init(NULL); - - icon_loader_mutex = g_mutex_new(); - - /* initialize device communication environment */ - device_init(); - - /* initialize clutter threading environment */ - clutter_threads_init(); - - if (gtk_clutter_init(&argc, &argv) != CLUTTER_INIT_SUCCESS) { - g_error("Unable to initialize GtkClutter"); - } - - /* Create the window and some child widgets */ - gui_init(app); - - /* Start the main loop, so we can respond to events */ - gtk_main(); - - return 0; + clutter_timeline_stop(clock_timeline); + device_info_free(device_info); } diff --git a/src/gui.h b/src/gui.h new file mode 100644 index 0000000..e00ce9d --- /dev/null +++ b/src/gui.h @@ -0,0 +1,46 @@ +/** + * gui.h + * GUI definitions. + * + * Copyright (C) 2009-2010 Nikias Bassen <nikias@gmx.li> + * Copyright (C) 2009-2010 Martin Szulecki <opensuse@sukimashita.com> + * + * Licensed under the GNU General Public License Version 2 + * + * 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 profile. + * + * 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 GUI_H +#define GUI_H + +#include <gtk/gtk.h> +#include <plist/plist.h> +#include "sbmgr.h" + +typedef struct { + char *uuid; + device_info_t device_info; +} SBManagerData; + +GtkWidget *gui_init(); +void gui_deinit(); +void gui_pages_load(const char *uuid, device_info_cb_t info_callback, finished_cb_t finshed_callback); +void gui_pages_free(); + +plist_t gui_get_iconstate(); + + +#endif diff --git a/src/iconstate.c b/src/iconstate.c new file mode 100644 index 0000000..91d528a --- /dev/null +++ b/src/iconstate.c @@ -0,0 +1,113 @@ +/** + * iconstate.c + * Serialization of iconstate from/to GList's + * + * Copyright (C) 2009-2010 Nikias Bassen <nikias@gmx.li> + * Copyright (C) 2009-2010 Martin Szulecki <opensuse@sukimashita.com> + * + * Licensed under the GNU General Public License Version 2 + * + * 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 profile. + * + * 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 + */ + +#ifdef HAVE_CONFIG_H + #include <config.h> +#endif + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <plist/plist.h> +#include <glib.h> + +#include "iconstate.h" + +GList * iconstate_to_g_list(plist_t iconstate, GError **error) +{ + +} + +plist_t g_list_to_iconstate(GList *iconstate, GError **error) +{ + plist_t iconstate = NULL; + plist_t pdockarray = NULL; + plist_t pdockitems = NULL; + guint i; + + guint count = g_list_length(dockitems); + pdockitems = plist_new_array(); + for (i = 0; i < count; i++) { + SBItem *item = g_list_nth_data(dockitems, i); + if (!item) { + continue; + } + plist_t valuenode = plist_dict_get_item(item->node, "displayIdentifier"); + if (!valuenode) { + printf("could not get displayIdentifier\n"); + continue; + } + + plist_t pitem = plist_new_dict(); + plist_dict_insert_item(pitem, "displayIdentifier", plist_copy(valuenode)); + plist_array_append_item(pdockitems, pitem); + } + for (i = count; i < num_dock_items; i++) { + plist_array_append_item(pdockitems, plist_new_bool(0)); + } + pdockarray = plist_new_array(); + plist_array_append_item(pdockarray, pdockitems); + + iconstate = plist_new_array(); + plist_array_append_item(iconstate, pdockarray); + + for (i = 0; i < g_list_length(sbpages); i++) { + GList *page = g_list_nth_data(sbpages, i); + if (page) { + guint j; + count = g_list_length(page); + if (count <= 0) { + continue; + } + plist_t ppage = plist_new_array(); + plist_t row = NULL; + for (j = 0; j < 16; j++) { + SBItem *item = g_list_nth_data(page, j); + if ((j % 4) == 0) { + row = plist_new_array(); + plist_array_append_item(ppage, row); + } + if (item && item->node) { + plist_t valuenode = plist_dict_get_item(item->node, + "displayIdentifier"); + if (!valuenode) { + printf("could not get displayIdentifier\n"); + continue; + } + + plist_t pitem = plist_new_dict(); + plist_dict_insert_item(pitem, "displayIdentifier", plist_copy(valuenode)); + plist_array_append_item(row, pitem); + } else { + plist_array_append_item(row, plist_new_bool(0)); + } + } + plist_array_append_item(iconstate, plist_copy(ppage)); + plist_free(ppage); + } + } + + return iconstate; +} diff --git a/src/iconstate.h b/src/iconstate.h new file mode 100644 index 0000000..e3b2065 --- /dev/null +++ b/src/iconstate.h @@ -0,0 +1,40 @@ +/** + * iconstate.h + * Serialization of iconstate from/to GList's (header file) + * + * Copyright (C) 2009-2010 Nikias Bassen <nikias@gmx.li> + * Copyright (C) 2009-2010 Martin Szulecki <opensuse@sukimashita.com> + * + * Licensed under the GNU General Public License Version 2 + * + * 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 profile. + * + * 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 ICONSTATE_H +#define ICONSTATE_H + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <plist/plist.h> +#include <glib.h> + +#include "iconstate.h" + +GList * iconstate_to_g_list(plist_t iconstate, GError **error); +plist_t g_list_to_iconstate(GList *iconstate, GError **error); + +#endif diff --git a/src/main.c b/src/main.c new file mode 100644 index 0000000..2246c29 --- /dev/null +++ b/src/main.c @@ -0,0 +1,309 @@ +/** + * sbmanager -- Manage iPhone/iPod Touch SpringBoard icons from your computer! + * + * Copyright (C) 2009-2010 Nikias Bassen <nikias@gmx.li> + * Copyright (C) 2009-2010 Martin Szulecki <opensuse@sukimashita.com> + * + * Licensed under the GNU General Public License Version 2 + * + * 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 profile. + * + * 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 + */ + +#ifdef HAVE_CONFIG_H + #include <config.h> /* for GETTEXT_PACKAGE */ +#endif +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <libiphone/libiphone.h> +#include <libiphone/sbservices.h> +#include <plist/plist.h> +#include <time.h> +#include <sys/time.h> +#include <glib.h> +#include <glib/gi18n-lib.h> + +#include <gtk/gtk.h> +#include <clutter/clutter.h> +#include <clutter-gtk/clutter-gtk.h> +#include <gdk-pixbuf/gdk-pixbuf.h> + +#include "sbmgr.h" +#include "utility.h" + +GtkWidget *main_window; +GtkWidget *btn_reload; +GtkWidget *btn_apply; + +char *match_uuid = NULL; +char *current_uuid = NULL; + +static gboolean win_map_cb(GtkWidget *widget, GdkEvent *event, gpointer *data) +{ + debug_printf("%s: mapped\n", __func__); + + return TRUE; +} + +static void update_device_info_cb(const char *device_name, const char *device_type) +{ + if (device_name) { + gchar *wndtitle = g_strdup_printf("%s - " PACKAGE_NAME, device_name); + gtk_window_set_title(GTK_WINDOW(main_window), wndtitle); + g_free(wndtitle); + } else { + gtk_window_set_title(GTK_WINDOW(main_window), PACKAGE_NAME); + } +} + +static void finished_cb(gboolean success) +{ + gtk_widget_set_sensitive(btn_reload, TRUE); + gtk_widget_set_sensitive(btn_apply, TRUE); + if (success) { + printf("successfully loaded icons\n"); + } else { + printf("there was an error loading the icons\n"); + } +} + +static gboolean reload_button_clicked_cb(GtkButton *button, gpointer user_data) +{ + gtk_widget_set_sensitive(btn_reload, FALSE); + gtk_widget_set_sensitive(btn_apply, FALSE); + sbmgr_load(user_data, update_device_info_cb, finished_cb); + return TRUE; +} + +static gboolean apply_button_clicked_cb(GtkButton *button, gpointer user_data) +{ + gtk_widget_set_sensitive(btn_reload, FALSE); + gtk_widget_set_sensitive(btn_apply, FALSE); + sbmgr_save(user_data); + gtk_widget_set_sensitive(btn_reload, TRUE); + gtk_widget_set_sensitive(btn_apply, TRUE); + return TRUE; +} + +static gboolean info_button_clicked_cb(GtkButton *button, gpointer user_data) +{ + const gchar *authors[] = { + "Nikias Bassen <nikias@gmx.li>", + "Martin Szulecki <opensuse@sukimashita.com>", + NULL + }; + const gchar *copyright = "Copyright © 2009-2010 Nikias Bassen, Martin Szulecki; All Rights Reserved."; + const gchar *program_name = PACKAGE_NAME; + const gchar *version = PACKAGE_VERSION; + const gchar *comments = _("Manage iPhone/iPod Touch SpringBoard from the computer"); + const gchar *website = "http://cgit.sukimashita.com/sbmanager.git"; + const gchar *website_label = _("Project Site"); + const gchar *translators = "Français: Christophe Fergeau\n"; + + gtk_show_about_dialog(GTK_WINDOW(main_window), + "authors", authors, + "copyright", copyright, + "program-name", program_name, + "version", version, + "comments", comments, + "website", website, + "website-label", website_label, + "translator-credits", translators, + NULL); + return TRUE; +} + +static void quit_program_cb(GtkWidget *widget, gpointer user_data) +{ + /* cleanup */ + sbmgr_finalize(); + iphone_event_unsubscribe(); + gtk_main_quit(); +} + +static gboolean quit_button_clicked_cb(GtkButton *button, gpointer user_data) +{ + quit_program_cb(GTK_WIDGET(button), user_data); + return TRUE; +} + +static void gui_error_dialog(const gchar *string) +{ + GtkWidget *dialog = gtk_message_dialog_new_with_markup (GTK_WINDOW(main_window), GTK_DIALOG_DESTROY_WITH_PARENT, GTK_MESSAGE_ERROR, GTK_BUTTONS_CLOSE, "<b>%s</b>", _("Error")); + gtk_window_set_title(GTK_WINDOW(dialog), PACKAGE_NAME); + gtk_message_dialog_format_secondary_text(GTK_MESSAGE_DIALOG(dialog), "%s", string); + g_signal_connect_swapped (dialog, "response", G_CALLBACK(gtk_widget_destroy), dialog); + gtk_widget_show(dialog); +} + +static gpointer device_add_cb(gpointer user_data) +{ + const char *uuid = (const char*)user_data; + sbmgr_load(uuid, update_device_info_cb, finished_cb); + return NULL; +} + +static void device_event_cb(const iphone_event_t *event, void *user_data) +{ + if (event->event == IPHONE_DEVICE_ADD) { + if (!current_uuid && (!match_uuid || !strcasecmp(match_uuid, event->uuid))) { + debug_printf("Device add event: adding device %s\n", event->uuid); + current_uuid = g_strdup(event->uuid); + g_thread_create(device_add_cb, current_uuid, FALSE, NULL); + } else { + debug_printf("Device add event: ignoring device %s\n", event->uuid); + } + } else if (event->event == IPHONE_DEVICE_REMOVE) { + if (current_uuid && !strcasecmp(current_uuid, event->uuid)) { + debug_printf("Device remove event: removing device %s\n", event->uuid); + free(current_uuid); + current_uuid = NULL; + sbmgr_cleanup(); + } else { + debug_printf("Device remove event: ignoring device %s\n", event->uuid); + } + } +} + +static void wnd_init() +{ + /* Create the clutter widget */ + GtkWidget *sbmgr_widget = sbmgr_new(); + if (!sbmgr_widget) { + return; + } + + main_window = gtk_window_new(GTK_WINDOW_TOPLEVEL); + gtk_window_set_resizable(GTK_WINDOW(main_window), FALSE); + + gtk_window_set_title(GTK_WINDOW(main_window), PACKAGE_NAME); + + GtkWidget *vbox = gtk_vbox_new(FALSE, 6); + gtk_container_add(GTK_CONTAINER(main_window), vbox); + gtk_widget_show(vbox); + + /* create a toolbar */ + GtkWidget *toolbar = gtk_toolbar_new(); + gtk_box_pack_start(GTK_BOX(vbox), toolbar, FALSE, FALSE, 0); + + btn_reload = (GtkWidget*)gtk_tool_button_new_from_stock(GTK_STOCK_REFRESH); + gtk_tool_item_set_tooltip_text(GTK_TOOL_ITEM(btn_reload), _("Reload icons from device")); + gtk_toolbar_insert(GTK_TOOLBAR(toolbar), GTK_TOOL_ITEM(btn_reload), -1); + + btn_apply = (GtkWidget*)gtk_tool_button_new_from_stock(GTK_STOCK_APPLY); + gtk_tool_item_set_tooltip_text(GTK_TOOL_ITEM(btn_apply), _("Upload changes to device")); + gtk_toolbar_insert(GTK_TOOLBAR(toolbar), GTK_TOOL_ITEM(btn_apply), -1); + + GtkToolItem *btn_info = gtk_tool_button_new_from_stock(GTK_STOCK_INFO); + gtk_tool_item_set_tooltip_text(btn_info, _("Get info about this cool program")); + gtk_toolbar_insert(GTK_TOOLBAR(toolbar), btn_info, -1); + + GtkToolItem *spacer = gtk_tool_item_new(); + gtk_tool_item_set_expand(spacer, TRUE); + gtk_toolbar_insert(GTK_TOOLBAR(toolbar), spacer, -1); + + GtkToolItem *btn_quit = gtk_tool_button_new_from_stock(GTK_STOCK_QUIT); + gtk_tool_item_set_tooltip_text(btn_quit, _("Quit this program")); + gtk_toolbar_insert(GTK_TOOLBAR(toolbar), btn_quit, -1); + + gtk_widget_set_sensitive(btn_reload, FALSE); + gtk_widget_set_sensitive(btn_apply, FALSE); + gtk_widget_show(toolbar); + + /* set up signal handlers */ + g_signal_connect(btn_reload, "clicked", G_CALLBACK(reload_button_clicked_cb), match_uuid); + g_signal_connect(btn_apply, "clicked", G_CALLBACK(apply_button_clicked_cb), match_uuid); + g_signal_connect(btn_info, "clicked", G_CALLBACK(info_button_clicked_cb), NULL); + g_signal_connect(btn_quit, "clicked", G_CALLBACK(quit_button_clicked_cb), NULL); + + /* insert sbmgr widget */ + gtk_box_pack_start(GTK_BOX(vbox), sbmgr_widget, TRUE, TRUE, 0); + gtk_widget_show(sbmgr_widget); + gtk_widget_grab_focus(sbmgr_widget); + + /* create a statusbar */ +/* statusbar = gtk_statusbar_new(); + gtk_statusbar_set_has_resize_grip(GTK_STATUSBAR(statusbar), FALSE); + gtk_box_pack_start(GTK_BOX(vbox), statusbar, FALSE, FALSE, 0); + gtk_widget_show(statusbar); +*/ + /* attach to window signals */ + g_signal_connect(G_OBJECT(main_window), "map-event", G_CALLBACK(win_map_cb), NULL); + + /* Show the window. This also sets the stage's bounding box. */ + gtk_widget_show_all(GTK_WIDGET(main_window)); + + g_set_printerr_handler((GPrintFunc)gui_error_dialog); + + /* Stop the application when the window is closed */ + g_signal_connect(main_window, "hide", G_CALLBACK(quit_program_cb), NULL); + + /* get notified when plug in/out events occur */ + iphone_event_subscribe(device_event_cb, NULL); +} + +/* main */ +static void print_usage(int argc, char **argv) +{ + char *name = NULL; + + name = strrchr(argv[0], '/'); + printf("Usage: %s [OPTIONS]\n", (name ? name + 1 : argv[0])); + printf("Manage SpringBoard icons of an iPhone/iPod Touch.\n\n"); + printf(" -d, --debug\t\tenable communication debugging\n"); + printf(" -D, --debug-app\tenable application debug messages\n"); + printf(" -u, --uuid UUID\ttarget specific device by its 40-digit device UUID\n"); + printf(" -h, --help\t\tprints usage information\n"); + printf("\n"); +} + +int main(int argc, char **argv) +{ + int i; + + /* parse cmdline args */ + for (i = 1; i < argc; i++) { + if (!strcmp(argv[i], "-d") || !strcmp(argv[i], "--debug")) { + iphone_set_debug_level(1); + continue; + } else if (!strcmp(argv[i], "-D") || !strcmp(argv[i], "--debug-app")) { + set_debug(TRUE); + continue; + } else if (!strcmp(argv[i], "-u") || !strcmp(argv[i], "--uuid")) { + i++; + if (!argv[i] || (strlen(argv[i]) != 40)) { + print_usage(argc, argv); + return 0; + } + match_uuid = g_strndup(argv[i], 40); + continue; + } else if (!strcmp(argv[i], "-h") || !strcmp(argv[i], "--help")) { + print_usage(argc, argv); + return 0; + } else { + print_usage(argc, argv); + return 0; + } + } + + /* Create the window and some child widgets */ + wnd_init(); + + /* Start the main loop, so we can respond to events */ + gtk_main(); + + return 0; +} diff --git a/src/sbmgr.c b/src/sbmgr.c new file mode 100644 index 0000000..e534209 --- /dev/null +++ b/src/sbmgr.c @@ -0,0 +1,101 @@ +/** + * sbmgr.c + * SBManager Widget implementation. + * + * Copyright (C) 2009-2010 Nikias Bassen <nikias@gmx.li> + * Copyright (C) 2009-2010 Martin Szulecki <opensuse@sukimashita.com> + * + * Licensed under the GNU General Public License Version 2 + * + * 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 profile. + * + * 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 <glib.h> +#include <gtk/gtk.h> + +#include "sbmgr.h" +#include "device.h" +#include "gui.h" + +static device_info_cb_t device_info_callback = NULL; +static finished_cb_t finished_callback = NULL; + +GtkWidget *sbmgr_new() +{ + if (!g_thread_supported()) + g_thread_init(NULL); + + /* initialize device communication environment */ + device_init(); + + /* Create the clutter widget and return it */ + return gui_init(); +} + +static gpointer gui_pages_load_cb(gpointer user_data) +{ + const char *uuid = (const char*)user_data; + gui_pages_load(uuid, device_info_callback, finished_callback); + return NULL; +} + +void sbmgr_load(const char *uuid, device_info_cb_t info_cb, finished_cb_t finished_cb) +{ + /* load icons */ + device_info_callback = info_cb; + finished_callback = finished_cb; + g_thread_create((GThreadFunc)gui_pages_load_cb, (gpointer)uuid, FALSE, NULL); +} + +void sbmgr_save(const char *uuid) +{ + plist_t iconstate = gui_get_iconstate(); + if (iconstate) { + GError *error = NULL; + sbservices_client_t sbc; + + sbc = device_sbs_new(uuid, &error); + + if (error) { + g_printerr("%s", error->message); + g_error_free(error); + error = NULL; + } + + if (sbc) { + device_sbs_set_iconstate(sbc, iconstate, &error); + device_sbs_free(sbc); + } + plist_free(iconstate); + + if (error) { + g_printerr("%s", error->message); + g_error_free(error); + error = NULL; + } + } +} + +void sbmgr_cleanup() +{ + gui_pages_free(); +} + +void sbmgr_finalize() +{ + sbmgr_cleanup(); + gui_deinit(); +} diff --git a/src/sbmgr.h b/src/sbmgr.h new file mode 100644 index 0000000..5846df2 --- /dev/null +++ b/src/sbmgr.h @@ -0,0 +1,40 @@ +/** + * sbmgr.h + * SBManager Widget definitions. + * + * Copyright (C) 2009-2010 Nikias Bassen <nikias@gmx.li> + * Copyright (C) 2009-2010 Martin Szulecki <opensuse@sukimashita.com> + * + * Licensed under the GNU General Public License Version 2 + * + * 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 profile. + * + * 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 SBMGR_H +#define SBMGR_H + +#include <gtk/gtk.h> + +typedef void (*device_info_cb_t)(const char *device_name, const char *device_type); +typedef void (*finished_cb_t)(gboolean success); + +GtkWidget *sbmgr_new(); +void sbmgr_load(const char *uuid, device_info_cb_t info_callback, finished_cb_t finished_callback); +void sbmgr_save(const char *uuid); +void sbmgr_cleanup(); +void sbmgr_finalize(); + +#endif |