Request API: PURPLE_REQUEST_WAIT with progress bar

Wed, 18 Sep 2013 18:24:28 +0200

author
Tomasz Wasilczyk <twasilczyk@pidgin.im>
date
Wed, 18 Sep 2013 18:24:28 +0200
changeset 34448
e15d91a77cb3
parent 34447
be84e0a7e68d
child 34449
bbcb198650b7
child 34953
14109bfbe008

Request API: PURPLE_REQUEST_WAIT with progress bar

finch/gntrequest.c file | annotate | diff | comparison | revisions
libpurple/protocols/gg/gg.c file | annotate | diff | comparison | revisions
libpurple/request.c file | annotate | diff | comparison | revisions
libpurple/request.h file | annotate | diff | comparison | revisions
pidgin/gtkrequest.c file | annotate | diff | comparison | revisions
--- 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,

mercurial