static void construct_user_data (SwServicePlurk* plurk, JsonNode *root) { SwServicePlurkPrivate *priv = GET_PRIVATE (plurk); JsonNode *node; JsonObject *object; const gchar *uid; gint64 id, avatar, has_profile; object = json_node_get_object (root); node = json_object_get_member (object, "user_info"); if (!node) return; object = json_node_get_object (node); if (json_object_get_null_member (object, "uid")) return; id = json_object_get_int_member (object, "uid"); avatar = json_object_get_int_member (object, "avatar"); has_profile = json_object_get_int_member (object, "has_profile_image"); uid = g_strdup_printf ("%lld", id); priv->user_id = (char *) uid; priv->image_url = construct_image_url (uid, avatar, has_profile); }
/* TODO: We might want to put this into a utils.c later */ static gboolean usable_json_value (JsonObject *object, const char *name) { if (!json_object_has_member (object, name)) return FALSE; return !json_object_get_null_member (object, name); }
/* * Callback function for when a channel receives data from the ipc socket. * Emits the corresponding signal with the reply. */ static gboolean ipc_on_data(GIOChannel *channel, GIOCondition condition, i3ipcConnection *conn) { if (condition != G_IO_IN) return TRUE; GIOStatus status; uint32_t reply_length; uint32_t reply_type; gchar *reply; GError *err = NULL; JsonParser *parser; JsonObject *json_reply; status = ipc_recv_message(channel, &reply_type, &reply_length, &reply, &err); if (status == G_IO_STATUS_EOF) { g_signal_emit(conn, connection_signals[IPC_SHUTDOWN], 0); if (conn->priv->main_loop != NULL) i3ipc_connection_main_quit(conn); return FALSE; } if (err) { g_warning("could not get event reply\n"); g_error_free(err); g_free(reply); return TRUE; } reply[reply_length] = '\0'; parser = json_parser_new(); json_parser_load_from_data(parser, reply, -1, &err); if (err) { g_warning("could not parse event reply json (%s)\n", err->message); g_error_free(err); g_free(reply); g_object_unref(parser); return TRUE; } json_reply = json_node_get_object(json_parser_get_root(parser)); switch (1 << (reply_type & 0x7F)) { case I3IPC_EVENT_WORKSPACE: { i3ipcWorkspaceEvent *e = g_slice_new0(i3ipcWorkspaceEvent); e->change = g_strdup(json_object_get_string_member(json_reply, "change")); if (json_object_has_member(json_reply, "current") && !json_object_get_null_member(json_reply, "current")) e->current = i3ipc_con_new(NULL, json_object_get_object_member(json_reply, "current"), conn); if (json_object_has_member(json_reply, "old") && !json_object_get_null_member(json_reply, "old")) e->old = i3ipc_con_new(NULL, json_object_get_object_member(json_reply, "old"), conn); g_signal_emit(conn, connection_signals[WORKSPACE], g_quark_from_string(e->change), e); break; } case I3IPC_EVENT_OUTPUT: { i3ipcGenericEvent *e = g_slice_new0(i3ipcGenericEvent); e->change = g_strdup(json_object_get_string_member(json_reply, "change")); g_signal_emit(conn, connection_signals[OUTPUT], g_quark_from_string(e->change), e); break; } case I3IPC_EVENT_MODE: { i3ipcGenericEvent *e = g_slice_new0(i3ipcGenericEvent); e->change = g_strdup(json_object_get_string_member(json_reply, "change")); g_signal_emit(conn, connection_signals[MODE], g_quark_from_string(e->change), e); break; } case I3IPC_EVENT_WINDOW: { i3ipcWindowEvent *e = g_slice_new0(i3ipcWindowEvent); e->change = g_strdup(json_object_get_string_member(json_reply, "change")); if (json_object_has_member(json_reply, "container") && !json_object_get_null_member(json_reply, "container")) e->container = i3ipc_con_new(NULL, json_object_get_object_member(json_reply, "container"), conn); g_signal_emit(conn, connection_signals[WINDOW], g_quark_from_string(e->change), e); break; } case I3IPC_EVENT_BARCONFIG_UPDATE: { i3ipcBarconfigUpdateEvent *e = g_slice_new0(i3ipcBarconfigUpdateEvent); e->id = g_strdup(json_object_get_string_member(json_reply, "id")); e->hidden_state = g_strdup(json_object_get_string_member(json_reply, "hidden_state")); e->mode = g_strdup(json_object_get_string_member(json_reply, "mode")); g_signal_emit(conn, connection_signals[BARCONFIG_UPDATE], 0, e); break; } case I3IPC_EVENT_BINDING: { i3ipcBindingEvent *e = g_slice_new0(i3ipcBindingEvent); e->change = g_strdup(json_object_get_string_member(json_reply, "change")); JsonObject *json_binding_info = json_object_get_object_member(json_reply, "binding"); e->binding = g_slice_new0(i3ipcBindingInfo); e->binding->command = g_strdup(json_object_get_string_member(json_binding_info, "command")); e->binding->input_code = json_object_get_int_member(json_binding_info, "input_code"); e->binding->input_type = g_strdup(json_object_get_string_member(json_binding_info, "input_type")); e->binding->symbol = g_strdup(json_object_get_string_member(json_binding_info, "symbol")); JsonArray *mods = json_object_get_array_member(json_binding_info, "mods"); gint mods_len = json_array_get_length(mods); for (int i = 0; i < mods_len; i += 1) { e->binding->mods = g_slist_append(e->binding->mods, g_strdup(json_array_get_string_element(mods, i))); } g_signal_emit(conn, connection_signals[BINDING], g_quark_from_string(e->change), e); break; } default: g_warning("got unknown event\n"); break; } g_object_unref(parser); g_free(reply); return TRUE; }
void cb_mini_tweet_parse_entities (CbMiniTweet *t, JsonObject *status) { JsonObject *extended_obj = status; JsonObject *entities; JsonArray *urls; JsonArray *hashtags; JsonArray *user_mentions; JsonArray *media_arrays[2]; int media_count; guint i, p; int url_index = 0; guint n_media_arrays = 0; guint n_reply_users = 0; guint non_reply_mentions = 0; int max_entities; gboolean direct_duplicate = FALSE; if (json_object_has_member (status, "extended_tweet")) extended_obj = json_object_get_object_member (status, "extended_tweet"); entities = json_object_get_object_member (extended_obj, "entities"); urls = json_object_get_array_member (entities, "urls"); hashtags = json_object_get_array_member (entities, "hashtags"); user_mentions = json_object_get_array_member (entities, "user_mentions"); media_count = json_object_get_member_size (entities, "media"); if (json_object_has_member (status, "extended_entities")) media_count += json_object_get_member_size (json_object_get_object_member (status, "extended_entities"), "media"); if (json_object_has_member (status, "in_reply_to_status_id") && !json_object_get_null_member (status, "in_reply_to_status_id")) { guint reply_index = 0; gint64 reply_to_user_id = 0; reply_to_user_id = json_object_get_int_member (status, "in_reply_to_user_id"); /* Check how many of the user mentions are reply mentions */ t->reply_id = json_object_get_int_member (status, "in_reply_to_status_id"); for (i = 0, p = json_array_get_length (user_mentions); i < p; i ++) { JsonObject *mention = json_node_get_object (json_array_get_element (user_mentions, i)); JsonArray *indices = json_object_get_array_member (mention, "indices"); gint64 user_id = json_object_get_int_member (mention, "id"); if (json_array_get_int_element (indices, 1) <= t->display_range_start) n_reply_users ++; else break; if (i == 0 && user_id == reply_to_user_id) direct_duplicate = TRUE; } if (!direct_duplicate) n_reply_users ++; t->reply_users = g_new0 (CbUserIdentity, n_reply_users); t->n_reply_users = n_reply_users; if (!direct_duplicate) { t->reply_users[0].id = reply_to_user_id; t->reply_users[0].screen_name = g_strdup (json_object_get_string_member (status, "in_reply_to_screen_name")); t->reply_users[0].user_name = g_strdup (""); reply_index = 1; } /* Now fill ->reply_users. The very first entry is always the user this tweet * *actually* replies to. */ for (i = 0; i < n_reply_users - (direct_duplicate ? 0 : 1); i ++) { JsonObject *mention = json_node_get_object (json_array_get_element (user_mentions, i)); t->reply_users[reply_index].id = json_object_get_int_member (mention, "id"); t->reply_users[reply_index].screen_name = g_strdup (json_object_get_string_member (mention, "screen_name")); t->reply_users[reply_index].user_name = g_strdup (json_object_get_string_member (mention, "name")); reply_index ++; } non_reply_mentions = n_reply_users - 1; } max_entities = json_array_get_length (urls) + json_array_get_length (hashtags) + json_array_get_length (user_mentions) - non_reply_mentions + media_count; media_count += (int)json_array_get_length (urls); t->medias = g_new0 (CbMedia*, media_count); t->entities = g_new0 (CbTextEntity, max_entities); /* * TODO: display_text and tooltip_text are often the same here, can we just set them to the * same value and only free one? */ /* URLS */ for (i = 0, p = json_array_get_length (urls); i < p; i ++) { JsonObject *url = json_node_get_object (json_array_get_element (urls, i)); const char *expanded_url = json_object_get_string_member (url, "expanded_url"); JsonArray *indices; if (is_media_candidate (expanded_url)) { t->medias[t->n_medias] = cb_media_new (); t->medias[t->n_medias]->url = g_strdup (expanded_url); t->medias[t->n_medias]->type = cb_media_type_from_url (expanded_url); t->medias[t->n_medias]->target_url = g_strdup (expanded_url); t->n_medias ++; } indices = json_object_get_array_member (url, "indices"); t->entities[url_index].from = json_array_get_int_element (indices, 0); t->entities[url_index].to = json_array_get_int_element (indices, 1); t->entities[url_index].display_text = cb_utils_escape_ampersands (json_object_get_string_member (url, "display_url")); t->entities[url_index].tooltip_text = cb_utils_escape_ampersands (expanded_url); t->entities[url_index].target = cb_utils_escape_ampersands (expanded_url); url_index ++; } /* HASHTAGS */ for (i = 0, p = json_array_get_length (hashtags); i < p; i ++) { JsonObject *hashtag = json_node_get_object (json_array_get_element (hashtags, i)); JsonArray *indices = json_object_get_array_member (hashtag, "indices"); const char *text = json_object_get_string_member (hashtag, "text"); t->entities[url_index].from = json_array_get_int_element (indices, 0); t->entities[url_index].to = json_array_get_int_element (indices, 1); t->entities[url_index].display_text = g_strdup_printf ("#%s", text); t->entities[url_index].tooltip_text = g_strdup_printf ("#%s", text); t->entities[url_index].target = NULL; url_index ++; } /* USER MENTIONS */ if (direct_duplicate) i = n_reply_users; else i = n_reply_users == 0 ? 0 : n_reply_users - 1; for (p = json_array_get_length (user_mentions); i < p; i ++) { JsonObject *mention = json_node_get_object (json_array_get_element (user_mentions, i)); JsonArray *indices = json_object_get_array_member (mention, "indices"); const char *screen_name = json_object_get_string_member (mention, "screen_name"); const char *id_str = json_object_get_string_member (mention, "id_str"); t->entities[url_index].from = json_array_get_int_element (indices, 0); t->entities[url_index].to = json_array_get_int_element (indices, 1); t->entities[url_index].display_text = g_strdup_printf ("@%s", screen_name); t->entities[url_index].tooltip_text = cb_utils_escape_ampersands (json_object_get_string_member (mention, "name")); t->entities[url_index].target = g_strdup_printf ("@%s/@%s", id_str, screen_name); url_index ++; } /* MEDIA */ if (json_object_has_member (entities, "media")) { JsonArray *medias = json_object_get_array_member (entities, "media"); for (i = 0, p = json_array_get_length (medias); i < p; i ++) { JsonObject *url = json_node_get_object (json_array_get_element (medias, i)); JsonArray *indices = json_object_get_array_member (url, "indices"); char *url_str = cb_utils_escape_ampersands (json_object_get_string_member (url, "url")); int k; gboolean duplicate = FALSE; /* Check for duplicates */ for (k = 0; k < url_index; k ++) { const char *target = t->entities[k].target; if (target != NULL && strcmp (target, url_str) == 0) { duplicate = TRUE; break; } } if (duplicate) { g_free (url_str); continue; } t->entities[url_index].from = json_array_get_int_element (indices, 0); t->entities[url_index].to = json_array_get_int_element (indices, 1); t->entities[url_index].display_text = cb_utils_escape_ampersands (json_object_get_string_member (url, "display_url")); t->entities[url_index].target = url_str; url_index ++; } } /* entities->media and extended_entities contain exactly the same media objects, but extended_entities is not always present, and entities->media doesn't contain all the attached media, so parse both the same way... */ if (json_object_has_member (entities, "media")) { media_arrays[n_media_arrays] = json_object_get_array_member (entities, "media"); n_media_arrays ++; } if (json_object_has_member (status, "extended_entities")) { media_arrays[n_media_arrays] = json_object_get_array_member (json_object_get_object_member (status, "extended_entities"), "media"); n_media_arrays ++; } for (i = 0; i < n_media_arrays; i ++) { guint x, k; for (x = 0, p = json_array_get_length (media_arrays[i]); x < p; x ++) { JsonObject *media_obj = json_node_get_object (json_array_get_element (media_arrays[i], x)); const char *media_type = json_object_get_string_member (media_obj, "type"); if (strcmp (media_type, "photo") == 0) { const char *url = json_object_get_string_member (media_obj, "media_url"); gboolean dup = FALSE; /* Remove duplicates */ for (k = 0; k < t->n_medias; k ++) { if (t->medias[k] != NULL && strcmp (t->medias[k]->url, url) == 0) { dup = TRUE; break; } } if (dup) continue; if (is_media_candidate (url)) { t->medias[t->n_medias] = cb_media_new (); t->medias[t->n_medias]->type = CB_MEDIA_TYPE_IMAGE; t->medias[t->n_medias]->url = g_strdup (url); t->medias[t->n_medias]->target_url = g_strdup_printf ("%s:orig", url); if (json_object_has_member (media_obj, "sizes")) { JsonObject *sizes = json_object_get_object_member (media_obj, "sizes"); JsonObject *medium = json_object_get_object_member (sizes, "medium"); t->medias[t->n_medias]->width = json_object_get_int_member (medium, "w"); t->medias[t->n_medias]->height = json_object_get_int_member (medium, "h"); } t->n_medias ++; } } else if (strcmp (media_type, "video") == 0 || strcmp (media_type, "animated_gif") == 0) { JsonObject *video_info = json_object_get_object_member (media_obj, "video_info"); JsonArray *variants = json_object_get_array_member (video_info, "variants"); JsonObject *variant = NULL; int thumb_width = -1; int thumb_height = -1; guint q; if (json_object_has_member (media_obj, "sizes")) { JsonObject *sizes = json_object_get_object_member (media_obj, "sizes"); JsonObject *medium = json_object_get_object_member (sizes, "medium"); thumb_width = json_object_get_int_member (medium, "w"); thumb_height = json_object_get_int_member (medium, "h"); } for (k = 0, q = json_array_get_length (variants); k < q; k ++) { JsonObject *v = json_node_get_object (json_array_get_element (variants, k)); if (strcmp (json_object_get_string_member (v, "content_type"), "application/x-mpegURL") == 0) { variant = v; break; } } if (variant == NULL && json_array_get_length (variants) > 0) variant = json_node_get_object (json_array_get_element (variants, 0)); if (variant != NULL) { guint n_media = t->n_medias; const char *thumb_url = json_object_get_string_member (media_obj, "media_url"); /* Some tweets have both a video and a thumbnail for that video attached. The tweet json * will list the image first. The url of the image and the thumb_url of the video will match */ for (k = 0; k < t->n_medias; k ++) { if (t->medias[k] != NULL && t->medias[k]->type == CB_MEDIA_TYPE_IMAGE && strcmp (t->medias[k]->url, thumb_url) == 0) { /* Replace this media */ g_object_unref (t->medias[k]); n_media = k; break; } } t->medias[n_media] = cb_media_new (); t->medias[n_media]->url = g_strdup (json_object_get_string_member (variant, "url")); t->medias[n_media]->thumb_url = g_strdup (thumb_url); t->medias[n_media]->type = CB_MEDIA_TYPE_TWITTER_VIDEO; t->medias[n_media]->width = thumb_width; t->medias[n_media]->height = thumb_height; if (n_media == t->n_medias) t->n_medias ++; } } else { g_debug ("Unhandled media type: %s", media_type); } } } t->n_entities = url_index; #if 0 g_debug ("Wasted entities: %d", max_entities - t->n_entities); g_debug ("Wasted media : %d", media_count - t->n_medias); #endif if (t->n_medias > 0) cb_media_downloader_load_all (cb_media_downloader_get_default (), t); if (t->n_entities > 0) { guint i, k; /* Sort entities. */ for (i = 0; i < t->n_entities; i ++) for (k = 0; k < t->n_entities; k++) if (t->entities[i].from < t->entities[k].from) { CbTextEntity tmp = { 0 }; cb_text_entity_copy (&t->entities[i], &tmp); cb_text_entity_copy (&t->entities[k], &t->entities[i]); cb_text_entity_copy (&tmp, &t->entities[k]); cb_text_entity_free (&tmp); } } }
i3ipcCon *i3ipc_con_new(i3ipcCon *parent, JsonObject *data, i3ipcConnection *conn) { i3ipcCon *con; con = g_object_new(I3IPC_TYPE_CON, NULL); g_object_ref(conn); con->priv->conn = conn; if (!json_object_get_null_member(data, "percent")) con->priv->percent = json_object_get_double_member(data, "percent"); if (!json_object_get_null_member(data, "window")) con->priv->window = json_object_get_int_member(data, "window"); if (json_object_has_member(data, "window_properties")) { JsonObject *window_properties = json_object_get_object_member(data, "window_properties"); if (json_object_has_member(window_properties, "class")) con->priv->window_class = g_strdup(json_object_get_string_member(window_properties, "class")); } if (json_object_has_member(data, "mark")) { con->priv->mark = g_strdup(json_object_get_string_member(data, "mark")); } con->priv->name = g_strdup(json_object_get_string_member(data, "name")); con->priv->focused = json_object_get_boolean_member(data, "focused"); con->priv->fullscreen_mode = json_object_get_boolean_member(data, "fullscreen_mode"); con->priv->urgent = json_object_get_boolean_member(data, "urgent"); con->priv->layout = g_strdup(json_object_get_string_member(data, "layout")); con->priv->orientation = g_strdup(json_object_get_string_member(data, "orientation")); con->priv->current_border_width = json_object_get_int_member(data, "current_border_width"); con->priv->border = g_strdup(json_object_get_string_member(data, "border")); con->priv->id = json_object_get_int_member(data, "id"); JsonNode *con_type_node = json_object_get_member(data, "type"); /* XXX: In the development version, the "type" property is a string of the * type, but in the current stable version (4.7.2) it is an integer as * defined in i3's data header. When the next version comes out, the case * where type is a number should be removed. */ if (json_node_get_value_type(con_type_node) == G_TYPE_STRING) { con->priv->type = g_strdup(json_node_get_string(con_type_node)); } else { int con_type_int = (int)json_node_get_int(con_type_node); switch (con_type_int) { case 0: con->priv->type = g_strdup("root"); break; case 1: con->priv->type = g_strdup("output"); break; case 2: case 3: con->priv->type = g_strdup("con"); break; case 4: con->priv->type = g_strdup("workspace"); break; case 5: con->priv->type = g_strdup("dockarea"); break; } } if (parent) { g_object_ref(parent); con->priv->parent = parent; } JsonObject *rect_data = json_object_get_object_member(data, "rect"); con->priv->rect->x = json_object_get_int_member(rect_data, "x"); con->priv->rect->y = json_object_get_int_member(rect_data, "y"); con->priv->rect->width = json_object_get_int_member(rect_data, "width"); con->priv->rect->height = json_object_get_int_member(rect_data, "height"); if (json_object_has_member(data, "deco_rect")) { JsonObject *deco_rect_data = json_object_get_object_member(data, "deco_rect"); con->priv->deco_rect->x = json_object_get_int_member(deco_rect_data, "x"); con->priv->deco_rect->y = json_object_get_int_member(deco_rect_data, "y"); con->priv->deco_rect->width = json_object_get_int_member(deco_rect_data, "width"); con->priv->deco_rect->height = json_object_get_int_member(deco_rect_data, "height"); } JsonArray *nodes_array = json_object_get_array_member(data, "nodes"); json_array_foreach_element(nodes_array, i3ipc_con_initialize_nodes, con); JsonArray *floating_nodes_array = json_object_get_array_member(data, "floating_nodes"); json_array_foreach_element(floating_nodes_array, i3ipc_con_initialize_floating_nodes, con); JsonArray *focus_array = json_object_get_array_member(data, "focus"); guint len = json_array_get_length(focus_array); for (int i = 0; i < len; i += 1) { con->priv->focus = g_list_append(con->priv->focus, GINT_TO_POINTER(json_array_get_int_element(focus_array, i))); } return con; }
static void skypeweb_got_info(SkypeWebAccount *sa, JsonNode *node, gpointer user_data) { gchar *username = user_data; PurpleNotifyUserInfo *user_info; JsonObject *userobj; PurpleBuddy *buddy; SkypeWebBuddy *sbuddy; const gchar *new_avatar; if (node == NULL || json_node_get_node_type(node) != JSON_NODE_OBJECT) return; userobj = json_node_get_object(node); user_info = purple_notify_user_info_new(); #define _SKYPE_USER_INFO(prop, key) if (prop && json_object_has_member(userobj, (prop)) && !json_object_get_null_member(userobj, (prop))) \ purple_notify_user_info_add_pair_html(user_info, _(key), json_object_get_string_member(userobj, (prop))); _SKYPE_USER_INFO("firstname", "First Name"); _SKYPE_USER_INFO("lastname", "Last Name"); _SKYPE_USER_INFO("birthday", "Birthday"); //_SKYPE_USER_INFO("gender", "Gender"); if (json_object_has_member(userobj, "gender") && !json_object_get_null_member(userobj, "gender")) { const gchar *gender = json_object_get_string_member(userobj, "gender"); const gchar *gender_output; if (*gender == '1') { gender_output = _("Male"); } else if (*gender == '2') { gender_output = _("Female"); } else { gender_output = _("Unknown"); } purple_notify_user_info_add_pair_html(user_info, _("Gender"), gender_output); } _SKYPE_USER_INFO("language", "Language"); _SKYPE_USER_INFO("country", "Country"); _SKYPE_USER_INFO("province", "Province"); _SKYPE_USER_INFO("city", "City"); _SKYPE_USER_INFO("homepage", "Homepage"); _SKYPE_USER_INFO("about", "About"); _SKYPE_USER_INFO("jobtitle", "Job Title"); _SKYPE_USER_INFO("phoneMobile", "Phone - Mobile"); _SKYPE_USER_INFO("phoneHome", "Phone - Home"); _SKYPE_USER_INFO("phoneOffice", "Phone - Office"); //_SKYPE_USER_INFO("mood", "Mood"); //_SKYPE_USER_INFO("richMood", "Mood"); //_SKYPE_USER_INFO("avatarUrl", "Avatar"); buddy = purple_find_buddy(sa->account, username); if (buddy) { sbuddy = purple_buddy_get_protocol_data(buddy); if (sbuddy == NULL) { sbuddy = g_new0(SkypeWebBuddy, 1); purple_buddy_set_protocol_data(buddy, sbuddy); sbuddy->skypename = g_strdup(username); sbuddy->sa = sa; } new_avatar = json_object_get_string_member(userobj, "avatarUrl"); if (new_avatar && (!sbuddy->avatar_url || !g_str_equal(sbuddy->avatar_url, new_avatar))) { g_free(sbuddy->avatar_url); sbuddy->avatar_url = g_strdup(new_avatar); skypeweb_get_icon(buddy); } g_free(sbuddy->mood); sbuddy->mood = g_strdup(json_object_get_string_member(userobj, "mood")); } purple_notify_userinfo(sa->pc, username, user_info, NULL, NULL); g_free(username); }
/** Refresh albums */ static void _piwigo_refresh_albums(dt_storage_piwigo_gui_data_t *ui, const gchar *select_album) { gtk_widget_set_sensitive(GTK_WIDGET(ui->album_list), FALSE); gtk_widget_set_sensitive(GTK_WIDGET(ui->parent_album_list), FALSE); if(ui->api == NULL || ui->api->authenticated == FALSE) { _piwigo_authenticate(ui); if(ui->api == NULL || !ui->api->authenticated) return; } gchar *to_select; int index = 0; // get the new album name, it will be checked in the if(select_album == NULL) { to_select = g_strdup(dt_bauhaus_combobox_get_text(ui->album_list)); if(to_select) { // cut the count of picture in album to get the name only gchar *p = to_select; while(*p) { if(*p == ' ' && *(p+1) == '(') { *p = '\0'; break; } p++; } } } else to_select = g_strdup(select_album); // First clear the combobox except first 2 items (none / create new album) dt_bauhaus_combobox_clear(ui->album_list); dt_bauhaus_combobox_clear(ui->parent_album_list); g_list_free(ui->albums); ui->albums = NULL; GList *args = NULL; args = _piwigo_query_add_arguments(args, "method", "pwg.categories.getList"); args = _piwigo_query_add_arguments(args, "cat_id", "0"); args = _piwigo_query_add_arguments(args, "recursive", "true"); _piwigo_api_post(ui->api, args, NULL, FALSE); g_list_free(args); if(ui->api->response && !ui->api->error_occured) { dt_bauhaus_combobox_add(ui->album_list, _("create new album")); dt_bauhaus_combobox_add(ui->parent_album_list, _("---")); JsonObject *result = json_node_get_object(json_object_get_member(ui->api->response, "result")); JsonArray *albums = json_object_get_array_member(result, "categories"); if(json_array_get_length(albums)>0 && index==0) index = 1; if(index > json_array_get_length(albums) - 1) index = json_array_get_length(albums) - 1; for(int i = 0; i < json_array_get_length(albums); i++) { char data[MAX_ALBUM_NAME_SIZE] = { 0 }; JsonObject *album = json_array_get_object_element(albums, i); _piwigo_album_t *new_album = g_malloc0(sizeof(struct _piwigo_album_t)); g_strlcpy(new_album->name, json_object_get_string_member(album, "name"), sizeof(new_album->name)); new_album->id = json_object_get_int_member(album, "id"); new_album->size = json_object_get_int_member(album, "nb_images"); const int isroot = json_object_get_null_member(album, "id_uppercat"); int indent = 0; if(!isroot) { const char *hierarchy = json_object_get_string_member(album, "uppercats"); char const *p = hierarchy; while(*p++) if(*p == ',') indent++; } snprintf(data, sizeof(data), "%*c%s (%"PRId64")", indent * 3, ' ', new_album->name, new_album->size); if(to_select && !strcmp(new_album->name, to_select)) index = i + 1; g_strlcpy(new_album->label, data, sizeof(new_album->label)); ui->albums = g_list_append(ui->albums, new_album); dt_bauhaus_combobox_add_aligned(ui->album_list, data, DT_BAUHAUS_COMBOBOX_ALIGN_LEFT); dt_bauhaus_combobox_add_aligned(ui->parent_album_list, data, DT_BAUHAUS_COMBOBOX_ALIGN_LEFT); } } else dt_control_log(_("cannot refresh albums")); g_free(to_select); gtk_widget_set_sensitive(GTK_WIDGET(ui->album_list), TRUE); gtk_widget_set_sensitive(GTK_WIDGET(ui->parent_album_list), TRUE); dt_bauhaus_combobox_set(ui->album_list, index); }