From b73b77f43a7dcb9d6f28806bf2c3cba0fc6f7aa2 Mon Sep 17 00:00:00 2001 From: Nikias Bassen Date: Mon, 12 Jul 2010 14:02:57 +0200 Subject: Add support for new iconstate format and displaying folder icons --- src/device.c | 12 +++- src/device.h | 2 +- src/gui.c | 214 +++++++++++++++++++++++++++++++++++++++++++++-------------- src/sbitem.c | 17 +++++ src/sbitem.h | 4 ++ src/sbmgr.c | 143 +++++++++++++++++++++++++++++++++------ 6 files changed, 316 insertions(+), 76 deletions(-) (limited to 'src') diff --git a/src/device.c b/src/device.c index c36a47b..46a01ee 100644 --- a/src/device.c +++ b/src/device.c @@ -115,14 +115,20 @@ void device_sbs_free(sbservices_client_t sbc) } } -gboolean device_sbs_get_iconstate(sbservices_client_t sbc, plist_t *iconstate, GError **error) +gboolean device_sbs_get_iconstate(sbservices_client_t sbc, plist_t *iconstate, const char *format_version, GError **error) { plist_t iconstate_loc = NULL; gboolean ret = FALSE; *iconstate = NULL; if (sbc) { - if (sbservices_get_icon_state(sbc, &iconstate_loc) != SBSERVICES_E_SUCCESS || !iconstate_loc) { + sbservices_error_t err; +#ifdef HAVE_LIBIMOBILEDEVICE_1_1 + err = sbservices_get_icon_state(sbc, &iconstate_loc, format_version); +#else + err = sbservices_get_icon_state(sbc, &iconstate_loc); +#endif + if (err != SBSERVICES_E_SUCCESS || !iconstate_loc) { if (error) *error = g_error_new(device_domain, EIO, _("Could not get icon state!")); goto leave_cleanup; @@ -133,7 +139,7 @@ gboolean device_sbs_get_iconstate(sbservices_client_t sbc, plist_t *iconstate, G goto leave_cleanup; } *iconstate = iconstate_loc; - ret = TRUE; + ret = TRUE; } leave_cleanup: diff --git a/src/device.h b/src/device.h index a12da88..f6d0adf 100644 --- a/src/device.h +++ b/src/device.h @@ -39,7 +39,7 @@ typedef struct device_info_int *device_info_t; void device_init(); sbservices_client_t device_sbs_new(const char *uuid, uint32_t *osversion, GError **error); void device_sbs_free(sbservices_client_t sbc); -gboolean device_sbs_get_iconstate(sbservices_client_t sbc, plist_t *iconstate, GError **error); +gboolean device_sbs_get_iconstate(sbservices_client_t sbc, plist_t *iconstate, const char *format_version, GError **error); gboolean device_sbs_save_icon(sbservices_client_t sbc, char *display_identifier, char *filename, GError **error); gboolean device_sbs_set_iconstate(sbservices_client_t sbc, plist_t iconstate, GError **error); gboolean device_sbs_save_wallpaper(sbservices_client_t sbc, const char *filename, GError **error); diff --git a/src/gui.c b/src/gui.c index 1c88591..1e385ff 100644 --- a/src/gui.c +++ b/src/gui.c @@ -103,6 +103,7 @@ GList *sbpages = NULL; guint num_dock_items = 0; sbservices_client_t sbc = NULL; +uint32_t osversion = 0; device_info_t device_info = NULL; static finished_cb_t finished_callback = NULL; @@ -561,32 +562,77 @@ static void gui_show_previous_page() gui_set_current_page(current_page-1, TRUE); } -plist_t gui_get_iconstate() +static plist_t sbitem_get_subitems(SBItem *item) +{ + plist_t result = plist_new_array(); + if (item && item->subitems) { + guint i; + for (i = 0; i < g_list_length(item->subitems); i++) { + SBItem *subitem = g_list_nth_data(item->subitems, i); + plist_t node = plist_dict_get_item(subitem->node, "displayIdentifier"); + if (!node) { + printf("could not get displayIdentifier\n"); + continue; + } + plist_array_append_item(result, plist_copy(node)); + } + } + return result; +} + +static plist_t sbitem_to_plist(SBItem *item) +{ + plist_t result = plist_new_dict(); + if (!item) { + return result; + } + plist_t node; + if (item->is_folder) { + node = plist_dict_get_item(item->node, "displayName"); + if (!node) { + printf("could not get displayName for folder!\n"); + return result; + } + plist_dict_insert_item(result, "displayName", plist_copy(node)); + plist_t iconlists = plist_new_array(); + plist_array_append_item(iconlists, sbitem_get_subitems(item)); + plist_dict_insert_item(result, "iconLists", iconlists); + } else { + node = plist_dict_get_item(item->node, "displayIdentifier"); + if (!node) { + printf("could not get displayIdentifier\n"); + return result; + } + plist_dict_insert_item(result, "displayIdentifier", plist_copy(node)); + } + return result; +} + +plist_t gui_get_iconstate(const char *format_version) { plist_t iconstate = NULL; plist_t pdockarray = NULL; plist_t pdockitems = NULL; guint i; + int use_version = 1; + if (format_version && (strcmp(format_version, "2") == 0)) { + use_version = 2; + } + 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; + if (item && item->node) { + plist_array_append_item(pdockitems, sbitem_to_plist(item)); } - - 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)); + + if (use_version == 1) { + 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); @@ -604,25 +650,23 @@ plist_t gui_get_iconstate() } plist_t ppage = plist_new_array(); plist_t row = NULL; + if (use_version == 2) { + row = plist_new_array(); + plist_array_append_item(ppage, row); + } 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 (use_version == 1) { + 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); + plist_array_append_item(row, sbitem_to_plist(item)); } else { - plist_array_append_item(row, plist_new_bool(0)); + if (use_version == 1) + plist_array_append_item(row, plist_new_bool(0)); } } plist_array_append_item(iconstate, plist_copy(ppage)); @@ -879,6 +923,27 @@ static gboolean stage_key_press_cb(ClutterActor *actor, ClutterEvent *event, gpo return TRUE; } +static void gui_draw_subitems(SBItem *item) +{ + ClutterActor *grp = clutter_actor_get_parent(item->texture); + guint i; + for (i = 0; i < g_list_length(item->subitems); i++) { + SBItem *subitem = (SBItem*)g_list_nth_data(item->subitems, i); + if (subitem && subitem->texture && !subitem->drawn && subitem->node) { + subitem->is_dock_item = FALSE; + ClutterActor *suba = subitem->texture; + clutter_container_add_actor(CLUTTER_CONTAINER(grp), suba); + clutter_actor_set_scale(suba, 0.22, 0.22); + clutter_actor_set_position(suba, 8.0 + (i%3)*15.0, 8.0 + ((double)(int)((int)i/(int)3))*16.0); + if (i < 9) + clutter_actor_show(suba); + else + clutter_actor_hide(suba); + subitem->drawn = TRUE; + } + } +} + static void gui_show_icons() { guint i; @@ -892,7 +957,7 @@ static void gui_show_icons() debug_printf("%s: showing dock icons\n", __func__); for (i = 0; i < g_list_length(dockitems); i++) { SBItem *item = (SBItem*)g_list_nth_data(dockitems, i); - if (item && item->texture && !CLUTTER_ACTOR_IS_VISIBLE(item->texture) && item->node) { + if (item && item->texture && !item->drawn && item->node) { item->is_dock_item = TRUE; ClutterActor *grp = clutter_group_new(); ClutterActor *actor = item->texture; @@ -908,6 +973,11 @@ static void gui_show_icons() clutter_actor_show(actor); clutter_container_add_actor(CLUTTER_CONTAINER(grp), actor); clutter_container_add_actor(CLUTTER_CONTAINER(the_dock), grp); + item->drawn = TRUE; + } + /* process subitems */ + if (item->texture && item->is_folder && item->subitems) { + gui_draw_subitems(item); } } gui_dock_align_icons(FALSE); @@ -922,7 +992,7 @@ static void gui_show_icons() debug_printf("%s: showing page icons for page %d\n", __func__, j); for (i = 0; i < g_list_length(cpage); i++) { SBItem *item = (SBItem*)g_list_nth_data(cpage, i); - if (item && item->texture && !CLUTTER_ACTOR_IS_VISIBLE(item->texture) && item->node) { + if (item && item->texture && !item->drawn && item->node) { item->is_dock_item = FALSE; ClutterActor *grp = clutter_group_new(); ClutterActor *actor = item->texture; @@ -938,6 +1008,11 @@ static void gui_show_icons() clutter_actor_show(actor); clutter_container_add_actor(CLUTTER_CONTAINER(grp), actor); clutter_container_add_actor(CLUTTER_CONTAINER(the_sb), grp); + item->drawn = TRUE; + } + /* process subitems */ + if (item->texture && item->is_folder && item->subitems) { + gui_draw_subitems(item); } } gui_page_align_icons(j, FALSE); @@ -949,7 +1024,12 @@ static void gui_show_icons() static gboolean sbitem_texture_new(gpointer data) { SBItem *item = (SBItem *)data; - char *icon_filename = sbitem_get_icon_filename(item); + char *icon_filename; + if (item->is_folder) { + icon_filename = g_strdup(SBMGR_DATA "/folder.png"); + } else { + icon_filename = sbitem_get_icon_filename(item); + } GError *err = NULL; /* create and load texture */ @@ -1011,26 +1091,50 @@ static guint gui_load_icon_row(plist_t items, GList **row) count = plist_array_get_size(items); for (i = 0; i < count; i++) { plist_t icon_info = plist_array_get_item(items, i); - item = sbitem_new(icon_info); - if (item != NULL) { - /* load texture of icon in a new thread */ - g_thread_create(sbitem_thread_load_texture, item, FALSE, NULL); + plist_t subitems = plist_dict_get_item(icon_info, "iconLists"); + if (subitems) { + /* this is a folder, so we need to load the subitems */ + GList *folderitems = NULL; + if (plist_get_node_type(subitems) == PLIST_ARRAY) { + subitems = plist_array_get_item(subitems, 0); + if (plist_get_node_type(subitems) == PLIST_ARRAY) { + icon_count += gui_load_icon_row(subitems, &folderitems); + } + } + if (folderitems) { + item = sbitem_new_with_subitems(icon_info, folderitems); + if (item != NULL) { + clutter_threads_add_idle((GSourceFunc)sbitem_texture_new, item); + *row = g_list_append(*row, item); + icon_count++; + } + } + } else { + item = sbitem_new(icon_info); + if (item != NULL) { + /* load texture of icon in a new thread */ + g_thread_create(sbitem_thread_load_texture, item, FALSE, NULL); - *row = g_list_append(*row, item); - icon_count++; + *row = g_list_append(*row, item); + icon_count++; + } } } return icon_count; } -static void gui_set_iconstate(plist_t iconstate) +static void gui_set_iconstate(plist_t iconstate, const char *format_version) { int total; /* get total number of pages */ - total = plist_array_get_size(iconstate); + if (plist_get_node_type(iconstate) != PLIST_ARRAY) { + fprintf(stderr, "ERROR: Invalid icon state format!\n"); + return; + } + total = plist_array_get_size(iconstate); if (total < 1) { fprintf(stderr, "ERROR: No icons returned in icon state\n"); return; @@ -1041,10 +1145,13 @@ static void gui_set_iconstate(plist_t iconstate) fprintf(stderr, "ERROR: error getting outer dock icon array!\n"); return; } - dock = plist_array_get_item(dock, 0); - if (plist_get_node_type(dock) != PLIST_ARRAY) { - fprintf(stderr, "ERROR: error getting inner dock icon array!\n"); - return; + + if (!format_version || (strcmp(format_version, "2") != 0)) { + dock = plist_array_get_item(dock, 0); + if (plist_get_node_type(dock) != PLIST_ARRAY) { + fprintf(stderr, "ERROR: error getting inner dock icon array!\n"); + return; + } } /* load dock icons */ @@ -1062,9 +1169,11 @@ static void gui_set_iconstate(plist_t iconstate) fprintf(stderr, "ERROR: error getting outer page icon array!\n"); return; } - /* rows */ - rows = plist_array_get_size(npage); - for (r = 0; r < rows; r++) { + + if (!format_version || (strcmp(format_version, "2") != 0)) { + /* rows */ + rows = plist_array_get_size(npage); + for (r = 0; r < rows; r++) { debug_printf("%s: processing page %d, row %d\n", __func__, p, r); plist_t nrow = plist_array_get_item(npage, r); @@ -1073,6 +1182,9 @@ static void gui_set_iconstate(plist_t iconstate) return; } total_icons += gui_load_icon_row(nrow, &page); + } + } else { + total_icons += gui_load_icon_row(npage, &page); } if (page) { @@ -1138,7 +1250,6 @@ static void gui_set_wallpaper(const char *wp) static gboolean gui_pages_init_cb(gpointer user_data) { const char *uuid = (const char*)user_data; - uint32_t osversion = 0; GError *error = NULL; plist_t iconstate = NULL; @@ -1159,17 +1270,19 @@ static gboolean gui_pages_init_cb(gpointer user_data) } if (sbc) { + const char *fmt_version = NULL; #ifdef HAVE_LIBIMOBILEDEVICE_1_1 if (osversion >= 0x04000000) { - /* Load wallpaper if available */ + fmt_version = "2"; + /* Load wallpaper if available */ if (device_sbs_save_wallpaper(sbc, "/tmp/wallpaper.png", &error)) { gui_set_wallpaper("/tmp/wallpaper.png"); } } #endif /* Load icon data */ - if (device_sbs_get_iconstate(sbc, &iconstate, &error)) { - gui_set_iconstate(iconstate); + if (device_sbs_get_iconstate(sbc, &iconstate, fmt_version, &error)) { + gui_set_iconstate(iconstate, fmt_version); plist_free(iconstate); } } @@ -1228,6 +1341,7 @@ void gui_pages_free() if (sbc) { device_sbs_free(sbc); sbc = NULL; + osversion = 0; } } diff --git a/src/sbitem.c b/src/sbitem.c index a53949e..b49a98f 100644 --- a/src/sbitem.c +++ b/src/sbitem.c @@ -63,11 +63,24 @@ SBItem *sbitem_new(plist_t icon_info) item = g_new0(SBItem, 1); item->node = plist_copy(icon_info); item->texture = NULL; + item->drawn = FALSE; item->is_dock_item = FALSE; + item->is_folder = FALSE; + item->subitems = NULL; return item; } +SBItem *sbitem_new_with_subitems(plist_t icon_info, GList *subitems) +{ + SBItem *item = sbitem_new(icon_info); + if (item) { + item->subitems = subitems; + item->is_folder = TRUE; + } + return item; +} + void sbitem_free(SBItem *item) { if (item) { @@ -85,6 +98,10 @@ void sbitem_free(SBItem *item) item->texture = NULL; } } + if (item->subitems) { + g_list_foreach(item->subitems, (GFunc)(g_func_sbitem_free), NULL); + g_list_free(item->subitems); + } if (item->label && CLUTTER_IS_ACTOR(item->label)) { clutter_actor_destroy(item->label); item->label = NULL; diff --git a/src/sbitem.h b/src/sbitem.h index 2c6bd66..c4e660e 100644 --- a/src/sbitem.h +++ b/src/sbitem.h @@ -34,7 +34,10 @@ typedef struct { plist_t node; ClutterActor *texture; ClutterActor *label; + gboolean drawn; gboolean is_dock_item; + gboolean is_folder; + GList *subitems; } SBItem; char *sbitem_get_display_name(SBItem *item); @@ -42,6 +45,7 @@ char *sbitem_get_display_identifier(SBItem *item); char *sbitem_get_icon_filename(SBItem *item); SBItem *sbitem_new(plist_t icon_info); +SBItem *sbitem_new_with_subitems(plist_t icon_info, GList *subitems); void sbitem_free(SBItem *item); void g_func_sbitem_free(SBItem *item, gpointer data); diff --git a/src/sbmgr.c b/src/sbmgr.c index 2a3502c..ec6d707 100644 --- a/src/sbmgr.c +++ b/src/sbmgr.c @@ -23,6 +23,7 @@ * USA */ +#include #include #include #include @@ -62,7 +63,7 @@ void sbmgr_load(const char *uuid, device_info_cb_t info_cb, finished_cb_t finish g_thread_create((GThreadFunc)gui_pages_load_cb, (gpointer)uuid, FALSE, NULL); } -static gboolean iconstate_changed(plist_t current_state, plist_t new_state) +static gboolean iconstate_changed_v1(plist_t current_state, plist_t new_state) { if (!current_state || !new_state) { return FALSE; @@ -124,44 +125,142 @@ static gboolean iconstate_changed(plist_t current_state, plist_t new_state) return FALSE; } -void sbmgr_save(const char *uuid) +static gboolean iconstate_changed_v2(plist_t current_state, plist_t new_state) { - plist_t iconstate = gui_get_iconstate(); - if (iconstate) { - GError *error = NULL; - sbservices_client_t sbc; + if (!current_state || !new_state) { + return FALSE; + } - sbc = device_sbs_new(uuid, NULL, &error); + /* compare new state with last saved state */ + uint32_t cur_cnt = plist_array_get_size(current_state); + uint32_t new_cnt = plist_array_get_size(new_state); + debug_printf("%s: old %d, new %d\n", __func__, cur_cnt, new_cnt); + if (cur_cnt != new_cnt) { + /* number of pages has changed! */ + debug_printf("%s: number of pages changed!\n", __func__); + return TRUE; + } - if (error) { - g_printerr("%s", error->message); - g_error_free(error); - error = NULL; + /* now dig deeper */ + uint32_t i; + for (i = 0; i < new_cnt; i++) { + plist_t cur_pp = plist_array_get_item(current_state, i); + plist_t new_pp = plist_array_get_item(new_state, i); + if (plist_get_node_type(plist_array_get_item(new_pp, 0)) == PLIST_ARRAY) { + new_pp = plist_array_get_item(new_pp, 0); + } + if (plist_get_node_type(plist_array_get_item(cur_pp, 0)) == PLIST_ARRAY) { + cur_pp = plist_array_get_item(cur_pp, 0); } - if (sbc) { - plist_t current_state = NULL; - device_sbs_get_iconstate(sbc, ¤t_state, &error); + uint32_t cur_item_cnt = plist_array_get_size(cur_pp); + uint32_t new_item_cnt = plist_array_get_size(new_pp); + if (cur_item_cnt != new_item_cnt) { + fprintf(stderr, "%s: number of items on page %d changed: old %d, new %d\n", __func__, i, cur_item_cnt, new_item_cnt); + return TRUE; + } + uint32_t k; + for (k = 0; k < cur_item_cnt; k++) { + plist_t cur_node = plist_array_get_item(cur_pp, k); + plist_t new_node = plist_array_get_item(new_pp, k); + if (plist_get_node_type(cur_node) == PLIST_DICT) { + /* ok, compare the displayIdentifier */ + plist_t cur_di = plist_dict_get_item(cur_node, "displayIdentifier"); + plist_t new_di = plist_dict_get_item(new_node, "displayIdentifier"); + if (!cur_di && !new_di) { + cur_di = plist_dict_get_item(cur_node, "displayName"); + new_di = plist_dict_get_item(new_node, "displayName"); + if (plist_compare_node_value(cur_di, new_di) == FALSE) { + debug_printf("%s: page %d folder item %d displayName changed!\n", __func__, i, k); + return TRUE; + } + cur_di = plist_dict_get_item(cur_di, "iconLists"); + new_di = plist_dict_get_item(new_di, "iconLists"); + cur_di = plist_array_get_item(cur_di, 0); + new_di = plist_array_get_item(new_di, 0); + if (plist_array_get_size(cur_di) != plist_array_get_size(new_di)) { + debug_printf("%s: page %d folder item %d subitem count changed!\n", __func__, i, k); + return TRUE; + } + uint32_t j; + for (j = 0; j < plist_array_get_size(cur_di); j++) { + plist_t cur_si = plist_array_get_item(cur_di, j); + plist_t new_si = plist_array_get_item(new_di, j); + if (plist_compare_node_value(cur_si, new_si) == FALSE) { + debug_printf("%s: page %d folder item %d subitem %d changed!\n", __func__, i, k, j); + return TRUE; + } + } + } else if ((!cur_di && new_di) || (cur_di && !new_di)) { + debug_printf("%s: page %d item %d changed!\n", __func__, i, k); + return TRUE; + } else { + if (plist_compare_node_value(cur_di, new_di) == FALSE) { + debug_printf("%s: page %d item %d changed!\n", __func__, i, k); + return TRUE; + } + } + } + } + } + + /* no change found */ + debug_printf("%s: no change!\n", __func__); + return FALSE; +} + +static gboolean iconstate_changed(plist_t current_state, plist_t new_state, const char *format_version) +{ + if (format_version && (strcmp(format_version, "2") == 0)) { + return iconstate_changed_v2(current_state, new_state); + } else { + return iconstate_changed_v1(current_state, new_state); + } +} + +void sbmgr_save(const char *uuid) +{ + GError *error = NULL; + sbservices_client_t sbc; + uint32_t osversion = 0; + + sbc = device_sbs_new(uuid, &osversion, &error); + + if (error) { + g_printerr("%s", error->message); + g_error_free(error); + error = NULL; + } + + if (sbc) { + plist_t current_state = NULL; + const char *fmt_version = NULL; + if (osversion >= 0x04000000) { + fmt_version = "2"; + } + plist_t iconstate = gui_get_iconstate(fmt_version); + if (iconstate) { + device_sbs_get_iconstate(sbc, ¤t_state, fmt_version, &error); if (error) { g_printerr("%s", error->message); g_error_free(error); error = NULL; } - if (iconstate_changed(current_state, iconstate) == TRUE) { + if (iconstate_changed(current_state, iconstate, fmt_version) == TRUE) { device_sbs_set_iconstate(sbc, iconstate, &error); } if (current_state) { plist_free(current_state); } - device_sbs_free(sbc); + plist_free(iconstate); } - plist_free(iconstate); + device_sbs_free(sbc); + } - if (error) { - g_printerr("%s", error->message); - g_error_free(error); - error = NULL; - } + if (error) { + g_printerr("%s", error->message); + g_error_free(error); + error = NULL; } } -- cgit v1.1-32-gdbae