summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/Makefile.am19
-rw-r--r--src/device.c6
-rw-r--r--src/device.h1
-rw-r--r--src/gui.c (renamed from src/sbmanager.c)428
-rw-r--r--src/gui.h46
-rw-r--r--src/iconstate.c113
-rw-r--r--src/iconstate.h40
-rw-r--r--src/main.c309
-rw-r--r--src/sbmgr.c101
-rw-r--r--src/sbmgr.h40
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