Wed, 18 Sep 2013 18:24:28 +0200
Request API: PURPLE_REQUEST_WAIT with progress bar
--- a/finch/gntrequest.c Tue Sep 17 22:16:32 2013 +0200 +++ b/finch/gntrequest.c Wed Sep 18 18:24:28 2013 +0200 @@ -815,6 +815,7 @@ finch_request_choice, finch_request_action, NULL, + NULL, finch_request_fields, finch_request_file, finch_request_folder,
--- a/libpurple/protocols/gg/gg.c Tue Sep 17 22:16:32 2013 +0200 +++ b/libpurple/protocols/gg/gg.c Wed Sep 18 18:24:28 2013 +0200 @@ -954,7 +954,7 @@ ggp_get_max_message_size(PurpleConversation *conv) { /* TODO: it may depend on protocol version or other factors */ - return 1232; + return 1200; /* no more than 1232 */ } static PurplePluginProtocolInfo prpl_info =
--- a/libpurple/request.c Tue Sep 17 22:16:32 2013 +0200 +++ b/libpurple/request.c Wed Sep 18 18:24:28 2013 +0200 @@ -2058,13 +2058,12 @@ void * purple_request_wait(void *handle, const char *title, const char *primary, - const char *secondary, GCallback cancel_cb, - PurpleRequestCommonParameters *cpar, void *user_data) + const char *secondary, gboolean with_progress, + PurpleRequestCancelCb cancel_cb, PurpleRequestCommonParameters *cpar, + void *user_data) { PurpleRequestUiOps *ops; - if (title == NULL) - title = _("Please wait"); if (primary == NULL) primary = _("Please wait..."); @@ -2080,7 +2079,7 @@ info->type = PURPLE_REQUEST_WAIT; info->handle = handle; info->ui_handle = ops->request_wait(title, primary, secondary, - cancel_cb, cpar, user_data); + with_progress, cancel_cb, cpar, user_data); handles = g_list_append(handles, info); @@ -2099,6 +2098,41 @@ cancel_cb ? 1 : 0, _("Cancel"), cancel_cb); } +void +purple_request_wait_pulse(void *ui_handle) +{ + PurpleRequestUiOps *ops; + + ops = purple_request_get_ui_ops(); + + if (ops == NULL || ops->request_wait_update == NULL) + return; + + ops->request_wait_update(ui_handle, TRUE, 0.0); +} + +void +purple_request_wait_progress(void *ui_handle, gfloat fraction) +{ + PurpleRequestUiOps *ops; + + ops = purple_request_get_ui_ops(); + + if (ops == NULL || ops->request_wait_update == NULL) + return; + + if (fraction < 0.0 || fraction > 1.0) { + purple_debug_warning("request", "Fraction parameter out of " + "range: %f", fraction); + if (fraction < 0.0) + fraction = 0.0; + else /* if (fraction > 1.0) */ + fraction = 1.0; + } + + ops->request_wait_update(ui_handle, FALSE, fraction); +} + static void purple_request_fields_strip_html(PurpleRequestFields *fields) {
--- a/libpurple/request.h Tue Sep 17 22:16:32 2013 +0200 +++ b/libpurple/request.h Wed Sep 18 18:24:28 2013 +0200 @@ -105,6 +105,8 @@ PURPLE_REQUEST_ICON_ERROR } PurpleRequestIconType; +typedef void (*PurpleRequestCancelCb)(gpointer); + /** * Request UI operations. */ @@ -135,9 +137,17 @@ /** @see purple_request_wait(). */ void *(*request_wait)(const char *title, const char *primary, - const char *secondary, GCallback cancel_cb, + const char *secondary, gboolean with_progress, + PurpleRequestCancelCb cancel_cb, PurpleRequestCommonParameters *cpar, void *user_data); + /** + * @see purple_request_wait_pulse(). + * @see purple_request_wait_progress(). + */ + void (*request_wait_update)(void *ui_handle, gboolean pulse, + gfloat fraction); + /** @see purple_request_fields(). */ void *(*request_fields)(const char *title, const char *primary, const char *secondary, PurpleRequestFields *fields, @@ -1758,26 +1768,48 @@ /** * Displays a "please wait" dialog. * - * @param handle The plugin or connection handle. For some things this - * is <em>extremely</em> important. See the comments on - * purple_request_input(). - * @param title The title of the message, or @c NULL if it should have - * default title. - * @param primary The main point of the message, or @c NULL if you're - * feeling enigmatic. - * @param secondary Secondary information, or @c NULL if there is none. - * @param cancel_cb The callback for the @c Cancel button, which may be - * @c NULL. - * @param cpar The #PurpleRequestCommonParameters object, which gets - * unref'ed after this call. - * @param user_data The data to pass to the callback. + * @param handle The plugin or connection handle. For some things this + * is <em>extremely</em> important. See the comments on + * purple_request_input(). + * @param title The title of the message, or @c NULL if it should have + * default title. + * @param primary The main point of the message, or @c NULL if you're + * feeling enigmatic. + * @param secondary Secondary information, or @c NULL if there is none. + * @param with_progress @c TRUE, if we want to display progress bar, @c FALSE + * otherwise + * @param cancel_cb The callback for the @c Cancel button, which may be + * @c NULL. + * @param cpar The #PurpleRequestCommonParameters object, which gets + * unref'ed after this call. + * @param user_data The data to pass to the callback. * * @return A UI-specific handle. */ void * purple_request_wait(void *handle, const char *title, const char *primary, - const char *secondary, GCallback cancel_cb, - PurpleRequestCommonParameters *cpar, void *user_data); + const char *secondary, gboolean with_progress, + PurpleRequestCancelCb cancel_cb, PurpleRequestCommonParameters *cpar, + void *user_data); + +/** + * Notifies the "please wait" dialog that some progress has been made, but you + * don't know how much. + * + * @param ui_handle The request UI handle. + */ +void +purple_request_wait_pulse(void *ui_handle); + +/** + * Notifies the "please wait" dialog about progress has been made. + * + * @param ui_handle The request UI handle. + * @param fraction The part of task that is done (between 0.0 and 1.0, + * inclusive). + */ +void +purple_request_wait_progress(void *ui_handle, gfloat fraction); /** * Displays groups of fields for the user to fill in.
--- a/pidgin/gtkrequest.c Tue Sep 17 22:16:32 2013 +0200 +++ b/pidgin/gtkrequest.c Wed Sep 18 18:24:28 2013 +0200 @@ -66,6 +66,11 @@ { struct { + GtkProgressBar *progress_bar; + } wait; + + struct + { GtkWidget *entry; gboolean multiline; @@ -376,7 +381,8 @@ } static GtkWidget * -pidgin_request_dialog_icon(PurpleRequestCommonParameters *cpar) +pidgin_request_dialog_icon(PurpleRequestType dialog_type, + PurpleRequestCommonParameters *cpar) { GtkWidget *img = NULL; PurpleRequestIconType icon_type; @@ -427,6 +433,8 @@ switch (icon_type) { case PURPLE_REQUEST_ICON_DEFAULT: + icon_stock = NULL; + break; case PURPLE_REQUEST_ICON_REQUEST: icon_stock = PIDGIN_STOCK_DIALOG_QUESTION; break; @@ -444,6 +452,23 @@ /* intentionally no default value */ } + if (icon_stock == NULL) { + switch (dialog_type) { + case PURPLE_REQUEST_INPUT: + case PURPLE_REQUEST_CHOICE: + case PURPLE_REQUEST_ACTION: + case PURPLE_REQUEST_FIELDS: + case PURPLE_REQUEST_FILE: + case PURPLE_REQUEST_FOLDER: + icon_stock = PIDGIN_STOCK_DIALOG_QUESTION; + break; + case PURPLE_REQUEST_WAIT: + icon_stock = PIDGIN_STOCK_DIALOG_INFO; + break; + /* intentionally no default value */ + } + } + img = gtk_image_new_from_stock(icon_stock, gtk_icon_size_from_name(PIDGIN_ICON_SIZE_TANGO_HUGE)); @@ -544,7 +569,7 @@ hbox); /* Dialog icon. */ - img = pidgin_request_dialog_icon(cpar); + img = pidgin_request_dialog_icon(PURPLE_REQUEST_INPUT, cpar); gtk_misc_set_alignment(GTK_MISC(img), 0, 0); gtk_box_pack_start(GTK_BOX(hbox), img, FALSE, FALSE, 0); @@ -704,7 +729,7 @@ hbox); /* Dialog icon. */ - img = pidgin_request_dialog_icon(cpar); + img = pidgin_request_dialog_icon(PURPLE_REQUEST_CHOICE, cpar); gtk_misc_set_alignment(GTK_MISC(img), 0, 0); gtk_box_pack_start(GTK_BOX(hbox), img, FALSE, FALSE, 0); @@ -826,7 +851,7 @@ gtk_container_add(GTK_CONTAINER(gtk_dialog_get_content_area(GTK_DIALOG(dialog))), hbox); - img = pidgin_request_dialog_icon(cpar); + img = pidgin_request_dialog_icon(PURPLE_REQUEST_ACTION, cpar); gtk_misc_set_alignment(GTK_MISC(img), 0, 0); gtk_box_pack_start(GTK_BOX(hbox), img, FALSE, FALSE, 0); @@ -882,6 +907,138 @@ } static void +wait_cancel_cb(GtkWidget *button, PidginRequestData *data) +{ + generic_response_start(data); + + if (data->cbs[0] != NULL) + ((PurpleRequestCancelCb)data->cbs[0])(data->user_data); + + purple_request_close(PURPLE_REQUEST_FIELDS, data); +} + +static void * +pidgin_request_wait(const char *title, const char *primary, + const char *secondary, gboolean with_progress, + PurpleRequestCancelCb cancel_cb, PurpleRequestCommonParameters *cpar, + void *user_data) +{ + PidginRequestData *data; + GtkWidget *dialog; + GtkWidget *hbox, *vbox, *img, *label, *button; + gchar *primary_esc, *secondary_esc, *label_text; + + data = g_new0(PidginRequestData, 1); + data->type = PURPLE_REQUEST_WAIT; + data->user_data = user_data; + + data->cb_count = 1; + data->cbs = g_new0(GCallback, 1); + data->cbs[0] = (GCallback)cancel_cb; + + data->dialog = dialog = gtk_dialog_new(); + + gtk_window_set_deletable(GTK_WINDOW(data->dialog), cancel_cb != NULL); + + if (title != NULL) + gtk_window_set_title(GTK_WINDOW(dialog), title); + else + gtk_window_set_title(GTK_WINDOW(dialog), _("Please wait")); + + /* Setup the dialog */ + gtk_container_set_border_width(GTK_CONTAINER(dialog), + PIDGIN_HIG_BORDER / 2); + gtk_container_set_border_width(GTK_CONTAINER( + gtk_dialog_get_content_area(GTK_DIALOG(dialog))), + PIDGIN_HIG_BORDER / 2); + gtk_window_set_resizable(GTK_WINDOW(dialog), FALSE); + gtk_box_set_spacing(GTK_BOX(gtk_dialog_get_content_area( + GTK_DIALOG(dialog))), PIDGIN_HIG_BORDER); + + /* Setup the main horizontal box */ + hbox = gtk_hbox_new(FALSE, PIDGIN_HIG_BORDER); + gtk_container_add(GTK_CONTAINER(gtk_dialog_get_content_area( + GTK_DIALOG(dialog))), hbox); + + img = pidgin_request_dialog_icon(PURPLE_REQUEST_WAIT, cpar); + gtk_misc_set_alignment(GTK_MISC(img), 0, 0); + gtk_box_pack_start(GTK_BOX(hbox), img, FALSE, FALSE, 0); + + /* Cancel button */ + button = pidgin_dialog_add_button(GTK_DIALOG(dialog), + text_to_stock(_("Cancel")), G_CALLBACK(wait_cancel_cb), data); + gtk_widget_set_can_default(button, FALSE); + + /* Vertical box */ + vbox = gtk_vbox_new(FALSE, PIDGIN_HIG_BORDER); + gtk_box_pack_start(GTK_BOX(hbox), vbox, FALSE, FALSE, 0); + + pidgin_widget_decorate_account(hbox, + purple_request_cpar_get_account(cpar)); + + pidgin_request_add_help(GTK_DIALOG(dialog), cpar); + + /* Descriptive label */ + primary_esc = pidgin_request_escape(cpar, primary); + secondary_esc = pidgin_request_escape(cpar, secondary); + label_text = g_strdup_printf((primary ? "<span weight=\"bold\" " + "size=\"larger\">%s</span>%s%s" : "%s%s%s"), + (primary ? primary_esc : ""), + ((primary && secondary) ? "\n\n" : ""), + (secondary ? secondary_esc : "")); + g_free(primary_esc); + g_free(secondary_esc); + + label = gtk_label_new(NULL); + + gtk_label_set_markup(GTK_LABEL(label), label_text); + gtk_label_set_line_wrap(GTK_LABEL(label), TRUE); + gtk_misc_set_alignment(GTK_MISC(label), 0, 0); + gtk_label_set_selectable(GTK_LABEL(label), FALSE); + gtk_box_pack_start(GTK_BOX(vbox), label, TRUE, TRUE, 0); + + g_free(label_text); + + if (with_progress) { + GtkProgressBar *bar; + + bar = data->u.wait.progress_bar = + GTK_PROGRESS_BAR(gtk_progress_bar_new()); + gtk_progress_bar_set_fraction(bar, 0); + gtk_box_pack_start(GTK_BOX(vbox), GTK_WIDGET(bar), + FALSE, FALSE, 0); + } + + /* Move focus out of cancel button. */ + gtk_widget_set_can_default(img, TRUE); + gtk_widget_set_can_focus(img, TRUE); + gtk_widget_grab_focus(img); + gtk_widget_grab_default(img); + + /* Show everything. */ + pidgin_auto_parent_window(dialog); + + gtk_widget_show_all(dialog); + + return data; +} + +static void +pidgin_request_wait_update(void *ui_handle, gboolean pulse, gfloat fraction) +{ + GtkProgressBar *bar; + PidginRequestData *data = ui_handle; + + g_return_if_fail(data->type == PURPLE_REQUEST_WAIT); + + bar = data->u.wait.progress_bar; + if (pulse) + gtk_progress_bar_pulse(bar); + else + gtk_progress_bar_set_fraction(bar, fraction); +} + +static void req_entry_field_changed_cb(GtkWidget *entry, PurpleRequestField *field) { if (purple_request_field_get_type(field) == PURPLE_REQUEST_FIELD_INTEGER) { @@ -1458,7 +1615,7 @@ gtk_widget_show(hbox); /* Dialog icon. */ - img = pidgin_request_dialog_icon(cpar); + img = pidgin_request_dialog_icon(PURPLE_REQUEST_FIELDS, cpar); gtk_misc_set_alignment(GTK_MISC(img), 0, 0); gtk_box_pack_start(GTK_BOX(hbox), img, FALSE, FALSE, 0); gtk_widget_show(img); @@ -2014,7 +2171,8 @@ pidgin_request_input, pidgin_request_choice, pidgin_request_action, - NULL, + pidgin_request_wait, + pidgin_request_wait_update, pidgin_request_fields, pidgin_request_file, pidgin_request_folder,