pidgin/pidgin

Use Meson summary() function.

2021-07-27, Elliott Sales de Andrade
cb640ea0f315
Use Meson summary() function.

Now that we require at least 0.52, we can use Meson's builtin summary printing to display the results of configuration.

Testing Done:
Configured with defaults, and with pixmaps disabled to trigger the warning: https://asciinema.org/a/mV2oxOoVCJNdmrPwgqqUJ3mkU?t=17

Reviewed at https://reviews.imfreedom.org/r/848/
/* pidgin
*
* Pidgin is the legal property of its developers, whose names are too numerous
* to list here. Please refer to the COPYRIGHT file distributed with this
* source distribution.
*
* 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 details.
*
* 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 02111-1301 USA
*/
#include <glib/gi18n-lib.h>
#include <talkatu.h>
#include <purple.h>
#include "gtkrequest.h"
#include "gtkblist.h"
#include "gtkutils.h"
#include "pidginaccountchooser.h"
#include "pidginaccountfilterconnected.h"
#include "pidginaccountstore.h"
#include "pidgincore.h"
#include "pidgindialog.h"
#include "pidginstock.h"
#include <gdk/gdkkeysyms.h>
typedef struct
{
PurpleRequestType type;
void *user_data;
/* May be GtkWidget or GtkNativeDialog */
gpointer dialog;
GtkWidget *ok_button;
size_t cb_count;
GCallback *cbs;
union
{
struct
{
GtkProgressBar *progress_bar;
} wait;
struct
{
GtkWidget *entry;
gboolean multiline;
gchar *hint;
} input;
struct
{
PurpleRequestFields *fields;
} multifield;
struct
{
gboolean savedialog;
gchar *name;
} file;
} u;
} PidginRequestData;
static GHashTable *datasheet_stock = NULL;
static GtkWidget * create_account_field(PurpleRequestField *field);
static void
pidgin_widget_decorate_account(GtkWidget *cont, PurpleAccount *account)
{
GtkWidget *image;
GdkPixbuf *pixbuf;
if(!PURPLE_IS_ACCOUNT(account)) {
return;
}
pixbuf = pidgin_create_protocol_icon(account, PIDGIN_PROTOCOL_ICON_SMALL);
if(!GDK_IS_PIXBUF(pixbuf)) {
return;
}
image = gtk_image_new_from_pixbuf(pixbuf);
g_object_unref(G_OBJECT(pixbuf));
gtk_widget_set_tooltip_text(image, purple_account_get_username(account));
if (GTK_IS_BOX(cont)) {
gtk_widget_set_halign(image, GTK_ALIGN_START);
gtk_widget_set_valign(image, GTK_ALIGN_START);
gtk_box_pack_end(GTK_BOX(cont), image, FALSE, TRUE, 0);
}
gtk_widget_show(image);
}
static void
generic_response_start(PidginRequestData *data)
{
g_return_if_fail(data != NULL);
/* Tell the user we're doing something. */
pidgin_set_cursor(GTK_WIDGET(data->dialog), GDK_WATCH);
g_object_set_data(G_OBJECT(data->dialog),
"pidgin-window-is-closing", GINT_TO_POINTER(TRUE));
gtk_widget_set_visible(GTK_WIDGET(data->dialog), FALSE);
}
static void
input_response_cb(GtkDialog *dialog, gint id, PidginRequestData *data)
{
const char *value;
char *multiline_value = NULL;
generic_response_start(data);
if (data->u.input.multiline || purple_strequal(data->u.input.hint, "html")) {
GtkTextBuffer *buffer =
gtk_text_view_get_buffer(GTK_TEXT_VIEW(data->u.input.entry));
if (purple_strequal(data->u.input.hint, "html")) {
multiline_value = talkatu_markup_get_html(buffer, NULL);
} else {
GtkTextIter start_iter, end_iter;
gtk_text_buffer_get_start_iter(buffer, &start_iter);
gtk_text_buffer_get_end_iter(buffer, &end_iter);
multiline_value = gtk_text_buffer_get_text(buffer, &start_iter, &end_iter,
FALSE);
}
value = multiline_value;
}
else {
value = gtk_entry_get_text(GTK_ENTRY(data->u.input.entry));
}
if (id >= 0 && (gsize)id < data->cb_count && data->cbs[id] != NULL)
((PurpleRequestInputCb)data->cbs[id])(data->user_data, value);
else if (data->cbs[1] != NULL)
((PurpleRequestInputCb)data->cbs[1])(data->user_data, value);
if (data->u.input.multiline) {
g_free(multiline_value);
}
purple_request_close(PURPLE_REQUEST_INPUT, data);
}
static void
action_response_cb(GtkDialog *dialog, gint id, PidginRequestData *data)
{
generic_response_start(data);
if (id >= 0 && (gsize)id < data->cb_count && data->cbs[id] != NULL)
((PurpleRequestActionCb)data->cbs[id])(data->user_data, id);
purple_request_close(PURPLE_REQUEST_INPUT, data);
}
static void
choice_response_cb(GtkDialog *dialog, gint id, PidginRequestData *data)
{
GtkWidget *radio = g_object_get_data(G_OBJECT(dialog), "radio");
GSList *group = gtk_radio_button_get_group(GTK_RADIO_BUTTON(radio));
generic_response_start(data);
if (id >= 0 && (gsize)id < data->cb_count && data->cbs[id] != NULL)
while (group) {
if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(group->data))) {
((PurpleRequestChoiceCb)data->cbs[id])(data->user_data, g_object_get_data(G_OBJECT(group->data), "choice_value"));
break;
}
group = group->next;
}
purple_request_close(PURPLE_REQUEST_INPUT, data);
}
static gboolean
field_string_focus_out_cb(GtkWidget *entry, GdkEventFocus *event,
PurpleRequestField *field)
{
const char *value;
if (purple_request_field_string_is_multiline(field))
{
GtkTextBuffer *buffer;
GtkTextIter start_iter, end_iter;
buffer = gtk_text_view_get_buffer(GTK_TEXT_VIEW(entry));
gtk_text_buffer_get_start_iter(buffer, &start_iter);
gtk_text_buffer_get_end_iter(buffer, &end_iter);
value = gtk_text_buffer_get_text(buffer, &start_iter, &end_iter, FALSE);
}
else
value = gtk_entry_get_text(GTK_ENTRY(entry));
purple_request_field_string_set_value(field,
(*value == '\0' ? NULL : value));
return FALSE;
}
static void
field_bool_cb(GtkToggleButton *button, PurpleRequestField *field)
{
purple_request_field_bool_set_value(field,
gtk_toggle_button_get_active(button));
}
static void
field_choice_menu_cb(GtkComboBox *menu, PurpleRequestField *field)
{
int active = gtk_combo_box_get_active(menu);
gpointer *values = g_object_get_data(G_OBJECT(menu), "values");
g_return_if_fail(values != NULL);
g_return_if_fail(active >= 0);
purple_request_field_choice_set_value(field, values[active]);
}
static void
field_choice_option_cb(GtkRadioButton *button, PurpleRequestField *field)
{
int active;
gpointer *values = g_object_get_data(G_OBJECT(g_object_get_data(
G_OBJECT(button), "box")), "values");
if (!gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(button)))
return;
active = (g_slist_length(gtk_radio_button_get_group(button)) -
g_slist_index(gtk_radio_button_get_group(button), button)) - 1;
g_return_if_fail(values != NULL);
g_return_if_fail(active >= 0);
purple_request_field_choice_set_value(field, values[active]);
}
static void
field_account_cb(GObject *w, PurpleRequestField *field)
{
PidginAccountChooser *chooser = PIDGIN_ACCOUNT_CHOOSER(w);
purple_request_field_account_set_value(
field, pidgin_account_chooser_get_selected(chooser));
}
static void
multifield_ok_cb(GtkWidget *button, PidginRequestData *data)
{
generic_response_start(data);
if (!gtk_widget_has_focus(button))
gtk_widget_grab_focus(button);
if (data->cbs[0] != NULL)
((PurpleRequestFieldsCb)data->cbs[0])(data->user_data,
data->u.multifield.fields);
purple_request_close(PURPLE_REQUEST_FIELDS, data);
}
static void
multifield_cancel_cb(GtkWidget *button, PidginRequestData *data)
{
generic_response_start(data);
if (data->cbs[1] != NULL)
((PurpleRequestFieldsCb)data->cbs[1])(data->user_data,
data->u.multifield.fields);
purple_request_close(PURPLE_REQUEST_FIELDS, data);
}
static void
multifield_extra_cb(GtkWidget *button, PidginRequestData *data)
{
PurpleRequestFieldsCb cb;
generic_response_start(data);
cb = g_object_get_data(G_OBJECT(button), "extra-cb");
if (cb != NULL)
cb(data->user_data, data->u.multifield.fields);
purple_request_close(PURPLE_REQUEST_FIELDS, data);
}
static gboolean
destroy_multifield_cb(GtkWidget *dialog, GdkEvent *event,
PidginRequestData *data)
{
multifield_cancel_cb(NULL, data);
return FALSE;
}
static gchar *
pidgin_request_escape(PurpleRequestCommonParameters *cpar, const gchar *text)
{
if (text == NULL)
return NULL;
if (purple_request_cpar_is_html(cpar)) {
gboolean valid;
valid = pango_parse_markup(text, -1, 0, NULL, NULL, NULL, NULL);
if (valid)
return g_strdup(text);
else {
purple_debug_error("pidgin", "Passed label text is not "
"a valid markup. Falling back to plain text.");
}
}
return g_markup_escape_text(text, -1);
}
static GtkWidget *
pidgin_request_dialog_icon(PurpleRequestType dialog_type,
PurpleRequestCommonParameters *cpar)
{
GtkWidget *img = NULL;
PurpleRequestIconType icon_type;
gconstpointer icon_data;
gsize icon_size;
const gchar *icon_name = "dialog-question";
/* Dialog icon. */
icon_data = purple_request_cpar_get_custom_icon(cpar, &icon_size);
if (icon_data) {
GdkPixbuf *pixbuf;
pixbuf = pidgin_pixbuf_from_data(icon_data, icon_size);
if (pixbuf) {
/* scale the image if it is too large */
int width = gdk_pixbuf_get_width(pixbuf);
int height = gdk_pixbuf_get_height(pixbuf);
if (width > 128 || height > 128) {
int scaled_width = width > height ?
128 : (128 * width) / height;
int scaled_height = height > width ?
128 : (128 * height) / width;
GdkPixbuf *scaled;
purple_debug_info("pidgin", "dialog icon was "
"too large, scaling it down");
scaled = gdk_pixbuf_scale_simple(pixbuf,
scaled_width, scaled_height,
GDK_INTERP_BILINEAR);
if (scaled) {
g_object_unref(pixbuf);
pixbuf = scaled;
}
}
img = gtk_image_new_from_pixbuf(pixbuf);
g_object_unref(pixbuf);
} else {
purple_debug_info("pidgin",
"failed to parse dialog icon");
}
}
if (img)
return img;
icon_type = purple_request_cpar_get_icon(cpar);
switch (icon_type)
{
case PURPLE_REQUEST_ICON_DEFAULT:
icon_name = NULL;
break;
case PURPLE_REQUEST_ICON_REQUEST:
icon_name = "dialog-question";
break;
case PURPLE_REQUEST_ICON_DIALOG:
case PURPLE_REQUEST_ICON_INFO:
case PURPLE_REQUEST_ICON_WAIT: /* TODO: we need another icon */
icon_name = "dialog-information";
break;
case PURPLE_REQUEST_ICON_WARNING:
icon_name = "dialog-warning";
break;
case PURPLE_REQUEST_ICON_ERROR:
icon_name = "dialog-error";
break;
/* intentionally no default value */
}
if (icon_name == 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_name = "dialog-question";
break;
case PURPLE_REQUEST_WAIT:
icon_name = "dialog-information";
break;
/* intentionally no default value */
}
}
img = gtk_image_new_from_icon_name(icon_name, GTK_ICON_SIZE_DIALOG);
if (img || icon_type == PURPLE_REQUEST_ICON_REQUEST)
return img;
return gtk_image_new_from_icon_name("dialog-question",
GTK_ICON_SIZE_DIALOG);
}
static void
pidgin_request_help_clicked(GtkButton *button, gpointer _unused)
{
PurpleRequestHelpCb cb;
gpointer data;
cb = g_object_get_data(G_OBJECT(button), "pidgin-help-cb");
data = g_object_get_data(G_OBJECT(button), "pidgin-help-data");
g_return_if_fail(cb != NULL);
cb(data);
}
static void
pidgin_request_add_help(GtkDialog *dialog, PurpleRequestCommonParameters *cpar)
{
GtkWidget *button;
PurpleRequestHelpCb help_cb;
gpointer help_data;
help_cb = purple_request_cpar_get_help_cb(cpar, &help_data);
if (help_cb == NULL)
return;
button = gtk_dialog_add_button(dialog, _("_Help"), GTK_RESPONSE_HELP);
g_object_set_data(G_OBJECT(button), "pidgin-help-cb", help_cb);
g_object_set_data(G_OBJECT(button), "pidgin-help-data", help_data);
g_signal_connect(G_OBJECT(button), "clicked",
G_CALLBACK(pidgin_request_help_clicked), NULL);
}
static void *
pidgin_request_input(const char *title, const char *primary,
const char *secondary, const char *default_value,
gboolean multiline, gboolean masked, gchar *hint,
const char *ok_text, GCallback ok_cb,
const char *cancel_text, GCallback cancel_cb,
PurpleRequestCommonParameters *cpar,
void *user_data)
{
PidginRequestData *data;
GtkWidget *dialog;
GtkWidget *vbox;
GtkWidget *hbox;
GtkLabel *label;
GtkWidget *img;
char *label_text;
char *primary_esc, *secondary_esc;
data = g_new0(PidginRequestData, 1);
data->type = PURPLE_REQUEST_INPUT;
data->user_data = user_data;
data->cb_count = 2;
data->cbs = g_new0(GCallback, 2);
data->cbs[0] = ok_cb;
data->cbs[1] = cancel_cb;
/* Create the dialog. */
dialog = gtk_dialog_new_with_buttons(title ? title : PIDGIN_ALERT_TITLE,
NULL, 0,
cancel_text, 1,
ok_text, 0,
NULL);
data->dialog = dialog;
g_signal_connect(G_OBJECT(dialog), "response",
G_CALLBACK(input_response_cb), data);
/* Setup the dialog */
gtk_container_set_border_width(GTK_CONTAINER(dialog), 6);
gtk_container_set_border_width(GTK_CONTAINER(gtk_dialog_get_content_area(GTK_DIALOG(dialog))),
6);
if (!multiline)
gtk_window_set_resizable(GTK_WINDOW(dialog), FALSE);
gtk_dialog_set_default_response(GTK_DIALOG(dialog), 0);
gtk_box_set_spacing(GTK_BOX(gtk_dialog_get_content_area(GTK_DIALOG(dialog))),
12);
/* Setup the main horizontal box */
hbox = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 12);
gtk_container_add(GTK_CONTAINER(gtk_dialog_get_content_area(GTK_DIALOG(dialog))),
hbox);
/* Dialog icon. */
img = pidgin_request_dialog_icon(PURPLE_REQUEST_INPUT, cpar);
gtk_widget_set_halign(img, GTK_ALIGN_START);
gtk_widget_set_valign(img, GTK_ALIGN_START);
gtk_box_pack_start(GTK_BOX(hbox), img, FALSE, FALSE, 0);
pidgin_request_add_help(GTK_DIALOG(dialog), cpar);
/* Vertical box */
vbox = gtk_box_new(GTK_ORIENTATION_VERTICAL, 12);
gtk_box_pack_start(GTK_BOX(hbox), vbox, TRUE, TRUE, 0);
pidgin_widget_decorate_account(hbox, purple_request_cpar_get_account(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(gtk_label_new(NULL));
gtk_label_set_markup(label, label_text);
gtk_label_set_line_wrap(label, TRUE);
gtk_label_set_xalign(label, 0);
gtk_label_set_yalign(label, 0);
gtk_box_pack_start(GTK_BOX(vbox), GTK_WIDGET(label), FALSE, FALSE, 0);
g_free(label_text);
/* Entry field. */
data->u.input.multiline = multiline;
data->u.input.hint = g_strdup(hint);
gtk_widget_show_all(hbox);
if(multiline || purple_strequal(data->u.input.hint, "html")) {
GtkWidget *editor = talkatu_editor_new();
GtkWidget *input = talkatu_editor_get_input(TALKATU_EDITOR(editor));
GtkTextBuffer *buffer = NULL;
gtk_widget_set_size_request(input, 320, 130);
gtk_widget_set_name(input, "pidgin_request_input");
gtk_box_pack_start(GTK_BOX(vbox), editor, TRUE, TRUE, 0);
gtk_widget_show(editor);
if (purple_strequal(data->u.input.hint, "html")) {
buffer = talkatu_html_buffer_new();
if(default_value != NULL) {
talkatu_markup_set_html(TALKATU_BUFFER(buffer), default_value, -1);
}
} else {
buffer = gtk_text_buffer_new(NULL);
if(default_value != NULL) {
gtk_text_buffer_set_text(buffer, default_value, -1);
}
}
gtk_text_view_set_buffer(GTK_TEXT_VIEW(input), buffer);
data->u.input.entry = input;
} else {
GtkWidget *entry = gtk_entry_new();
gtk_entry_set_activates_default(GTK_ENTRY(entry), TRUE);
gtk_box_pack_start(GTK_BOX(vbox), entry, FALSE, FALSE, 0);
if(default_value != NULL) {
gtk_entry_set_text(GTK_ENTRY(entry), default_value);
}
if(masked) {
gtk_entry_set_visibility(GTK_ENTRY(entry), FALSE);
}
data->u.input.entry = entry;
}
gtk_widget_show_all(vbox);
pidgin_set_accessible_label(data->u.input.entry, label);
pidgin_auto_parent_window(dialog);
/* Show everything. */
gtk_widget_show(dialog);
return data;
}
static void *
pidgin_request_choice(const char *title, const char *primary,
const char *secondary, gpointer default_value, const char *ok_text,
GCallback ok_cb, const char *cancel_text, GCallback cancel_cb,
PurpleRequestCommonParameters *cpar, void *user_data, va_list args)
{
PidginRequestData *data;
GtkWidget *dialog;
GtkWidget *vbox, *vbox2;
GtkWidget *hbox;
GtkWidget *label;
GtkWidget *img;
GtkWidget *radio = NULL;
char *label_text;
char *radio_text;
char *primary_esc, *secondary_esc;
data = g_new0(PidginRequestData, 1);
data->type = PURPLE_REQUEST_ACTION;
data->user_data = user_data;
data->cb_count = 2;
data->cbs = g_new0(GCallback, 2);
data->cbs[0] = cancel_cb;
data->cbs[1] = ok_cb;
/* Create the dialog. */
data->dialog = dialog = gtk_dialog_new();
if (title != NULL)
gtk_window_set_title(GTK_WINDOW(dialog), title);
#ifdef _WIN32
gtk_window_set_title(GTK_WINDOW(dialog), PIDGIN_ALERT_TITLE);
#endif
gtk_dialog_add_button(GTK_DIALOG(dialog), cancel_text, 0);
gtk_dialog_add_button(GTK_DIALOG(dialog), ok_text, 1);
g_signal_connect(G_OBJECT(dialog), "response",
G_CALLBACK(choice_response_cb), data);
/* Setup the dialog */
gtk_container_set_border_width(GTK_CONTAINER(dialog), 6);
gtk_container_set_border_width(GTK_CONTAINER(gtk_dialog_get_content_area(GTK_DIALOG(dialog))),
6);
gtk_window_set_resizable(GTK_WINDOW(dialog), FALSE);
gtk_box_set_spacing(GTK_BOX(gtk_dialog_get_content_area(GTK_DIALOG(dialog))),
12);
/* Setup the main horizontal box */
hbox = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 12);
gtk_container_add(GTK_CONTAINER(gtk_dialog_get_content_area(GTK_DIALOG(dialog))),
hbox);
/* Dialog icon. */
img = pidgin_request_dialog_icon(PURPLE_REQUEST_CHOICE, cpar);
gtk_widget_set_halign(img, GTK_ALIGN_START);
gtk_widget_set_valign(img, GTK_ALIGN_START);
gtk_box_pack_start(GTK_BOX(hbox), img, FALSE, FALSE, 0);
pidgin_widget_decorate_account(hbox, purple_request_cpar_get_account(cpar));
pidgin_request_add_help(GTK_DIALOG(dialog), cpar);
/* Vertical box */
vbox = gtk_box_new(GTK_ORIENTATION_VERTICAL, 12);
gtk_box_pack_start(GTK_BOX(hbox), vbox, FALSE, FALSE, 0);
/* 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_label_set_xalign(GTK_LABEL(label), 0);
gtk_label_set_yalign(GTK_LABEL(label), 0);
gtk_box_pack_start(GTK_BOX(vbox), label, TRUE, TRUE, 0);
g_free(label_text);
vbox2 = gtk_box_new(GTK_ORIENTATION_VERTICAL, 6);
gtk_box_pack_start(GTK_BOX(vbox), vbox2, FALSE, FALSE, 0);
while ((radio_text = va_arg(args, char*))) {
gpointer resp = va_arg(args, gpointer);
radio = gtk_radio_button_new_with_label_from_widget(GTK_RADIO_BUTTON(radio), radio_text);
gtk_box_pack_start(GTK_BOX(vbox2), radio, FALSE, FALSE, 0);
g_object_set_data(G_OBJECT(radio), "choice_value", resp);
if (resp == default_value)
gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(radio), TRUE);
}
g_object_set_data(G_OBJECT(dialog), "radio", radio);
/* Show everything. */
pidgin_auto_parent_window(dialog);
gtk_widget_show_all(dialog);
return data;
}
static void *
pidgin_request_action(const char *title, const char *primary,
const char *secondary, int default_action,
PurpleRequestCommonParameters *cpar, void *user_data,
size_t action_count, va_list actions)
{
PidginRequestData *data;
GtkWidget *dialog;
GtkWidget *vbox;
GtkWidget *hbox;
GtkWidget *label;
GtkWidget *img = NULL;
void **buttons;
char *label_text;
char *primary_esc, *secondary_esc;
gsize i;
data = g_new0(PidginRequestData, 1);
data->type = PURPLE_REQUEST_ACTION;
data->user_data = user_data;
data->cb_count = action_count;
data->cbs = g_new0(GCallback, action_count);
/* Reverse the buttons */
buttons = g_new0(void *, action_count * 2);
for (i = 0; i < action_count * 2; i += 2) {
buttons[(action_count * 2) - i - 2] = va_arg(actions, char *);
buttons[(action_count * 2) - i - 1] = va_arg(actions, GCallback);
}
/* Create the dialog. */
data->dialog = dialog = gtk_dialog_new();
gtk_window_set_deletable(GTK_WINDOW(data->dialog), FALSE);
if (title != NULL)
gtk_window_set_title(GTK_WINDOW(dialog), title);
#ifdef _WIN32
else
gtk_window_set_title(GTK_WINDOW(dialog), PIDGIN_ALERT_TITLE);
#endif
for (i = 0; i < action_count; i++) {
gtk_dialog_add_button(GTK_DIALOG(dialog), buttons[2 * i], i);
data->cbs[i] = buttons[2 * i + 1];
}
g_free(buttons);
g_signal_connect(G_OBJECT(dialog), "response",
G_CALLBACK(action_response_cb), data);
/* Setup the dialog */
gtk_container_set_border_width(GTK_CONTAINER(dialog), 6);
gtk_container_set_border_width(GTK_CONTAINER(gtk_dialog_get_content_area(GTK_DIALOG(dialog))),
6);
gtk_window_set_resizable(GTK_WINDOW(dialog), FALSE);
gtk_box_set_spacing(GTK_BOX(gtk_dialog_get_content_area(GTK_DIALOG(dialog))),
12);
/* Setup the main horizontal box */
hbox = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 12);
gtk_container_add(GTK_CONTAINER(gtk_dialog_get_content_area(GTK_DIALOG(dialog))),
hbox);
img = pidgin_request_dialog_icon(PURPLE_REQUEST_ACTION, cpar);
gtk_widget_set_halign(img, GTK_ALIGN_START);
gtk_widget_set_valign(img, GTK_ALIGN_START);
gtk_box_pack_start(GTK_BOX(hbox), img, FALSE, FALSE, 0);
/* Vertical box */
vbox = gtk_box_new(GTK_ORIENTATION_VERTICAL, 12);
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_label_set_xalign(GTK_LABEL(label), 0);
gtk_label_set_yalign(GTK_LABEL(label), 0);
gtk_label_set_selectable(GTK_LABEL(label), TRUE);
gtk_box_pack_start(GTK_BOX(vbox), label, TRUE, TRUE, 0);
g_free(label_text);
if (default_action == PURPLE_DEFAULT_ACTION_NONE) {
gtk_widget_set_can_default(img, TRUE);
gtk_widget_set_can_focus(img, TRUE);
gtk_widget_grab_focus(img);
gtk_widget_grab_default(img);
} else
/*
* Need to invert the default_action number because the
* buttons are added to the dialog in reverse order.
*/
gtk_dialog_set_default_response(GTK_DIALOG(dialog), action_count - 1 - default_action);
/* Show everything. */
pidgin_auto_parent_window(dialog);
gtk_widget_show_all(dialog);
return data;
}
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), 6);
gtk_container_set_border_width(GTK_CONTAINER(
gtk_dialog_get_content_area(GTK_DIALOG(dialog))), 6);
gtk_window_set_resizable(GTK_WINDOW(dialog), FALSE);
gtk_box_set_spacing(GTK_BOX(gtk_dialog_get_content_area(
GTK_DIALOG(dialog))), 12);
/* Setup the main horizontal box */
hbox = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 12);
gtk_container_add(GTK_CONTAINER(gtk_dialog_get_content_area(
GTK_DIALOG(dialog))), hbox);
img = pidgin_request_dialog_icon(PURPLE_REQUEST_WAIT, cpar);
gtk_widget_set_halign(img, GTK_ALIGN_START);
gtk_widget_set_valign(img, GTK_ALIGN_START);
gtk_box_pack_start(GTK_BOX(hbox), img, FALSE, FALSE, 0);
/* Cancel button */
button = pidgin_dialog_add_button(GTK_DIALOG(dialog), _("Cancel"),
G_CALLBACK(wait_cancel_cb), data);
gtk_widget_set_can_default(button, FALSE);
/* Vertical box */
vbox = gtk_box_new(GTK_ORIENTATION_VERTICAL, 12);
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_label_set_xalign(GTK_LABEL(label), 0);
gtk_label_set_yalign(GTK_LABEL(label), 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_field_type(field) == PURPLE_REQUEST_FIELD_INTEGER) {
int value = gtk_spin_button_get_value_as_int(GTK_SPIN_BUTTON(entry));
purple_request_field_int_set_value(field, value);
return;
}
if (purple_request_field_string_is_multiline(field))
{
char *text;
GtkTextIter start_iter, end_iter;
gtk_text_buffer_get_start_iter(GTK_TEXT_BUFFER(entry), &start_iter);
gtk_text_buffer_get_end_iter(GTK_TEXT_BUFFER(entry), &end_iter);
text = gtk_text_buffer_get_text(GTK_TEXT_BUFFER(entry), &start_iter, &end_iter, FALSE);
purple_request_field_string_set_value(field, (!text || !*text) ? NULL : text);
g_free(text);
}
else
{
const char *text = NULL;
text = gtk_entry_get_text(GTK_ENTRY(entry));
purple_request_field_string_set_value(field, (*text == '\0') ? NULL : text);
}
}
static void
req_field_changed_cb(GtkWidget *widget, PurpleRequestField *field)
{
PurpleRequestFieldGroup *group;
PurpleRequestFields *fields;
PidginRequestData *req_data;
const GList *it;
group = purple_request_field_get_group(field);
fields = purple_request_field_group_get_fields_list(group);
req_data = purple_request_fields_get_ui_data(fields);
gtk_widget_set_sensitive(req_data->ok_button,
purple_request_fields_all_required_filled(fields) &&
purple_request_fields_all_valid(fields));
it = purple_request_fields_get_autosensitive(fields);
for (; it != NULL; it = g_list_next(it)) {
PurpleRequestField *field = it->data;
GtkWidget *widget = purple_request_field_get_ui_data(field);
gboolean sensitive;
sensitive = purple_request_field_is_sensitive(field);
gtk_widget_set_sensitive(widget, sensitive);
/* XXX: and what about multiline? */
if (GTK_IS_EDITABLE(widget))
gtk_editable_set_editable(GTK_EDITABLE(widget), sensitive);
}
}
static void
setup_entry_field(GtkWidget *entry, PurpleRequestField *field)
{
const char *type_hint;
gtk_entry_set_activates_default(GTK_ENTRY(entry), TRUE);
g_signal_connect(G_OBJECT(entry), "changed",
G_CALLBACK(req_entry_field_changed_cb), field);
g_signal_connect(G_OBJECT(entry), "changed",
G_CALLBACK(req_field_changed_cb), field);
if ((type_hint = purple_request_field_get_field_type_hint(field)) != NULL)
{
if (g_str_has_prefix(type_hint, "screenname")) {
GtkWidget *optmenu = NULL;
PurpleRequestFieldGroup *group = purple_request_field_get_group(field);
GList *fields = purple_request_field_group_get_fields(group);
/* Ensure the account option menu is created (if the widget hasn't
* been initialized already) for username auto-completion. */
while (fields)
{
PurpleRequestField *fld = fields->data;
fields = fields->next;
if (purple_request_field_get_field_type(fld) == PURPLE_REQUEST_FIELD_ACCOUNT &&
purple_request_field_is_visible(fld))
{
const char *type_hint = purple_request_field_get_field_type_hint(fld);
if (purple_strequal(type_hint, "account"))
{
optmenu = GTK_WIDGET(purple_request_field_get_ui_data(fld));
if (optmenu == NULL) {
optmenu = GTK_WIDGET(create_account_field(fld));
purple_request_field_set_ui_data(fld, optmenu);
}
break;
}
}
}
pidgin_setup_screenname_autocomplete(entry, optmenu, pidgin_screenname_autocomplete_default_filter, GINT_TO_POINTER(purple_strequal(type_hint, "screenname-all")));
}
}
}
static GtkWidget *
create_string_field(PurpleRequestField *field)
{
const char *value;
GtkWidget *widget;
gboolean is_editable;
value = purple_request_field_string_get_default_value(field);
is_editable = purple_request_field_is_sensitive(field);
if (purple_request_field_string_is_multiline(field))
{
GtkWidget *textview;
textview = gtk_text_view_new();
gtk_text_view_set_editable(GTK_TEXT_VIEW(textview),
TRUE);
gtk_text_view_set_wrap_mode(GTK_TEXT_VIEW(textview),
GTK_WRAP_WORD_CHAR);
gtk_widget_show(textview);
if (value != NULL)
{
GtkTextBuffer *buffer;
buffer = gtk_text_view_get_buffer(GTK_TEXT_VIEW(textview));
gtk_text_buffer_set_text(buffer, value, -1);
}
gtk_widget_set_tooltip_text(textview, purple_request_field_get_tooltip(field));
gtk_text_view_set_editable(GTK_TEXT_VIEW(textview), is_editable);
g_signal_connect(G_OBJECT(textview), "focus-out-event",
G_CALLBACK(field_string_focus_out_cb), field);
if (purple_request_field_is_required(field))
{
GtkTextBuffer *buffer = gtk_text_view_get_buffer(GTK_TEXT_VIEW(textview));
g_signal_connect(G_OBJECT(buffer), "changed",
G_CALLBACK(req_entry_field_changed_cb), field);
}
widget = pidgin_make_scrollable(textview, GTK_POLICY_NEVER, GTK_POLICY_ALWAYS, GTK_SHADOW_IN, -1, 75);
}
else
{
widget = gtk_entry_new();
setup_entry_field(widget, field);
if (value != NULL)
gtk_entry_set_text(GTK_ENTRY(widget), value);
gtk_widget_set_tooltip_text(widget, purple_request_field_get_tooltip(field));
if (purple_request_field_string_is_masked(field))
{
gtk_entry_set_visibility(GTK_ENTRY(widget), FALSE);
}
gtk_editable_set_editable(GTK_EDITABLE(widget), is_editable);
g_signal_connect(G_OBJECT(widget), "focus-out-event",
G_CALLBACK(field_string_focus_out_cb), field);
}
return widget;
}
static GtkWidget *
create_int_field(PurpleRequestField *field)
{
int value;
GtkWidget *widget;
widget = gtk_spin_button_new_with_range(
purple_request_field_int_get_lower_bound(field),
purple_request_field_int_get_upper_bound(field), 1);
setup_entry_field(widget, field);
value = purple_request_field_int_get_default_value(field);
gtk_spin_button_set_value(GTK_SPIN_BUTTON(widget), value);
gtk_widget_set_tooltip_text(widget, purple_request_field_get_tooltip(field));
return widget;
}
static GtkWidget *
create_bool_field(PurpleRequestField *field,
PurpleRequestCommonParameters *cpar)
{
GtkWidget *widget;
gchar *label;
label = pidgin_request_escape(cpar,
purple_request_field_get_label(field));
widget = gtk_check_button_new_with_label(label);
g_free(label);
gtk_widget_set_tooltip_text(widget, purple_request_field_get_tooltip(field));
gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(widget),
purple_request_field_bool_get_default_value(field));
g_signal_connect(G_OBJECT(widget), "toggled",
G_CALLBACK(field_bool_cb), field);
g_signal_connect(widget, "toggled",
G_CALLBACK(req_field_changed_cb), field);
return widget;
}
static GtkWidget *
create_choice_field(PurpleRequestField *field,
PurpleRequestCommonParameters *cpar)
{
GtkWidget *widget;
GList *elements = purple_request_field_choice_get_elements(field);
guint num_labels = g_list_length(elements);
gpointer *values = g_new(gpointer, num_labels);
gpointer default_value;
gboolean default_found = FALSE;
int i;
default_value = purple_request_field_choice_get_value(field);
if (num_labels > 5 || purple_request_cpar_is_compact(cpar))
{
int default_index = 0;
widget = gtk_combo_box_text_new();
i = 0;
for (GList *l = elements; l != NULL; l = g_list_next(l))
{
PurpleKeyValuePair *choice = l->data;
gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(widget), choice->key);
if (choice->value == default_value) {
default_index = i;
default_found = TRUE;
}
values[i++] = choice->value;
}
gtk_combo_box_set_active(GTK_COMBO_BOX(widget), default_index);
gtk_widget_set_tooltip_text(widget, purple_request_field_get_tooltip(field));
g_signal_connect(G_OBJECT(widget), "changed",
G_CALLBACK(field_choice_menu_cb), field);
}
else
{
GtkWidget *box;
GtkWidget *first_radio = NULL;
GtkWidget *radio;
if (num_labels == 2)
box = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 6);
else
box = gtk_box_new(GTK_ORIENTATION_VERTICAL, 0);
widget = box;
gtk_widget_set_tooltip_text(widget, purple_request_field_get_tooltip(field));
i = 0;
for (GList *l = elements; l != NULL; l = g_list_next(l))
{
PurpleKeyValuePair *choice = l->data;
radio = gtk_radio_button_new_with_label_from_widget(
GTK_RADIO_BUTTON(first_radio), choice->key);
g_object_set_data(G_OBJECT(radio), "box", box);
if (first_radio == NULL)
first_radio = radio;
if (choice->value == default_value) {
gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(radio), TRUE);
default_found = TRUE;
}
values[i++] = choice->value;
gtk_box_pack_start(GTK_BOX(box), radio, TRUE, TRUE, 0);
gtk_widget_show(radio);
g_signal_connect(G_OBJECT(radio), "toggled",
G_CALLBACK(field_choice_option_cb), field);
}
}
if (!default_found && i > 0)
purple_request_field_choice_set_value(field, values[0]);
g_object_set_data_full(G_OBJECT(widget), "values", values, g_free);
return widget;
}
static GtkWidget *
create_image_field(PurpleRequestField *field)
{
GtkWidget *widget;
GdkPixbuf *buf, *scale;
buf = pidgin_pixbuf_from_data(
(const guchar *)purple_request_field_image_get_buffer(field),
purple_request_field_image_get_size(field));
scale = gdk_pixbuf_scale_simple(buf,
purple_request_field_image_get_scale_x(field) * gdk_pixbuf_get_width(buf),
purple_request_field_image_get_scale_y(field) * gdk_pixbuf_get_height(buf),
GDK_INTERP_BILINEAR);
widget = gtk_image_new_from_pixbuf(scale);
g_object_unref(G_OBJECT(buf));
g_object_unref(G_OBJECT(scale));
gtk_widget_set_tooltip_text(widget, purple_request_field_get_tooltip(field));
return widget;
}
static GtkWidget *
create_account_field(PurpleRequestField *field)
{
GtkWidget *widget;
PurpleAccount *account;
widget = pidgin_account_chooser_new();
account = purple_request_field_account_get_default_value(field);
if(purple_request_field_account_get_show_all(field)) {
GtkListStore *store = pidgin_account_store_new();
gtk_combo_box_set_model(GTK_COMBO_BOX(widget), GTK_TREE_MODEL(store));
g_object_unref(G_OBJECT(store));
} else {
GtkListStore *store = NULL;
GtkTreeModel *filter = NULL;
store = pidgin_account_store_new();
filter = pidgin_account_filter_connected_new(GTK_TREE_MODEL(store),
NULL);
g_object_unref(G_OBJECT(store));
gtk_combo_box_set_model(GTK_COMBO_BOX(widget), GTK_TREE_MODEL(filter));
g_object_unref(G_OBJECT(filter));
}
pidgin_account_chooser_set_selected(PIDGIN_ACCOUNT_CHOOSER(widget),
account);
pidgin_account_chooser_set_filter_func(
PIDGIN_ACCOUNT_CHOOSER(widget),
purple_request_field_account_get_filter(field));
g_signal_connect(widget, "changed", G_CALLBACK(field_account_cb),
field);
gtk_widget_set_tooltip_text(widget, purple_request_field_get_tooltip(field));
g_signal_connect(widget, "changed",
G_CALLBACK(req_field_changed_cb), field);
gtk_widget_show(widget);
return widget;
}
static void
select_field_list_item(GtkTreeModel *model, GtkTreePath *path,
GtkTreeIter *iter, gpointer data)
{
PurpleRequestField *field = (PurpleRequestField *)data;
char *text;
gtk_tree_model_get(model, iter, 1, &text, -1);
purple_request_field_list_add_selected(field, text);
g_free(text);
}
static void
list_field_select_changed_cb(GtkTreeSelection *sel, PurpleRequestField *field)
{
purple_request_field_list_clear_selected(field);
gtk_tree_selection_selected_foreach(sel, select_field_list_item, field);
}
static GtkWidget *
create_list_field(PurpleRequestField *field)
{
GtkWidget *treeview;
GtkListStore *store;
GtkCellRenderer *renderer;
GtkTreeSelection *sel;
GtkTreeViewColumn *column;
GtkTreeIter iter;
GList *l;
gboolean has_icons;
has_icons = purple_request_field_list_has_icons(field);
/* Create the list store */
if (has_icons) {
store = gtk_list_store_new(3, G_TYPE_POINTER, G_TYPE_STRING, GDK_TYPE_PIXBUF);
} else {
store = gtk_list_store_new(2, G_TYPE_POINTER, G_TYPE_STRING);
}
/* Create the tree view */
treeview = gtk_tree_view_new_with_model(GTK_TREE_MODEL(store));
g_object_unref(G_OBJECT(store));
gtk_tree_view_set_headers_visible(GTK_TREE_VIEW(treeview), FALSE);
sel = gtk_tree_view_get_selection(GTK_TREE_VIEW(treeview));
if (purple_request_field_list_get_multi_select(field))
gtk_tree_selection_set_mode(sel, GTK_SELECTION_MULTIPLE);
column = gtk_tree_view_column_new();
gtk_tree_view_insert_column(GTK_TREE_VIEW(treeview), column, -1);
renderer = gtk_cell_renderer_text_new();
gtk_tree_view_column_pack_start(column, renderer, TRUE);
gtk_tree_view_column_add_attribute(column, renderer, "text", 1);
if (has_icons) {
renderer = gtk_cell_renderer_pixbuf_new();
gtk_tree_view_column_pack_start(column, renderer, TRUE);
gtk_tree_view_column_add_attribute(column, renderer, "pixbuf", 2);
gtk_widget_set_size_request(treeview, 200, 400);
}
for (l = purple_request_field_list_get_items(field); l != NULL; l = l->next)
{
PurpleKeyValuePair *item = l->data;
const char *text = (const char *)item->key;
gtk_list_store_append(store, &iter);
if (has_icons) {
const char *icon_path = (const char *)item->value;
GdkPixbuf* pixbuf = NULL;
if (icon_path)
pixbuf = pidgin_pixbuf_new_from_file(icon_path);
gtk_list_store_set(store, &iter,
0, purple_request_field_list_get_data(field, text),
1, text,
2, pixbuf,
-1);
} else {
gtk_list_store_set(store, &iter,
0, purple_request_field_list_get_data(field, text),
1, text,
-1);
}
if (purple_request_field_list_is_selected(field, text)) {
gtk_tree_selection_select_iter(sel, &iter);
}
}
/*
* We only want to catch changes made by the user, so it's important
* that we wait until after the list is created to connect this
* handler. If we connect the handler before the loop above and
* there are multiple items selected, then selecting the first iter
* in the tree causes list_field_select_changed_cb to be triggered
* which clears out the rest of the list of selected items.
*/
g_signal_connect(G_OBJECT(sel), "changed",
G_CALLBACK(list_field_select_changed_cb), field);
gtk_widget_show(treeview);
return pidgin_make_scrollable(treeview, GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC, GTK_SHADOW_IN, -1, -1);
}
static GdkPixbuf*
_pidgin_datasheet_stock_icon_get(const gchar *stock_name)
{
GdkPixbuf *image = NULL;
gchar *domain, *id;
if (stock_name == NULL)
return NULL;
/* core is quitting */
if (datasheet_stock == NULL)
return NULL;
if (g_hash_table_lookup_extended(datasheet_stock, stock_name,
NULL, (gpointer*)&image))
{
return image;
}
domain = g_strdup(stock_name);
id = strchr(domain, '/');
if (!id) {
g_free(domain);
return NULL;
}
id[0] = '\0';
id++;
if (purple_strequal(domain, "protocol")) {
PurpleAccount *account;
gchar *protocol_id, *accountname;
protocol_id = id;
accountname = strchr(id, ':');
if (!accountname) {
g_free(domain);
return NULL;
}
accountname[0] = '\0';
accountname++;
account = purple_accounts_find(accountname, protocol_id);
if (account) {
image = pidgin_create_protocol_icon(account,
PIDGIN_PROTOCOL_ICON_SMALL);
}
} else {
purple_debug_error("gtkrequest", "Unknown domain: %s", domain);
g_free(domain);
return NULL;
}
g_hash_table_insert(datasheet_stock, g_strdup(stock_name), image);
return image;
}
static PurpleRequestDatasheetRecord*
datasheet_get_selected_row(GtkWidget *sheet_widget)
{
PurpleRequestDatasheet *sheet;
GtkTreeView *view;
GtkTreeSelection *selection;
GtkTreeModel *model;
GtkTreeIter iter;
GList *sel_list;
gpointer key;
g_return_val_if_fail(sheet_widget != NULL, NULL);
view = GTK_TREE_VIEW(g_object_get_data(G_OBJECT(sheet_widget), "view"));
sheet = g_object_get_data(G_OBJECT(sheet_widget), "sheet");
g_return_val_if_fail(view != NULL, NULL);
g_return_val_if_fail(sheet != NULL, NULL);
selection = gtk_tree_view_get_selection(view);
if (gtk_tree_selection_count_selected_rows(selection) != 1)
return NULL;
sel_list = gtk_tree_selection_get_selected_rows(selection, &model);
gtk_tree_model_get_iter(model, &iter, sel_list->data);
g_list_free_full(sel_list, (GDestroyNotify)gtk_tree_path_free);
gtk_tree_model_get(model, &iter, 0, &key, -1);
return purple_request_datasheet_record_find(sheet, key);
}
static void
datasheet_button_check_sens(GtkWidget *button, gpointer _sheet_widget)
{
PurpleRequestDatasheetAction *act;
GtkWidget *sheet_widget = GTK_WIDGET(_sheet_widget);
g_return_if_fail(sheet_widget != NULL);
act = g_object_get_data(G_OBJECT(button), "action");
g_return_if_fail(act != NULL);
gtk_widget_set_sensitive(button,
purple_request_datasheet_action_is_sensitive(act,
datasheet_get_selected_row(sheet_widget)));
}
static void
datasheet_selection_changed(GtkWidget *sheet_widget)
{
gpointer buttons_box;
g_return_if_fail(sheet_widget != NULL);
buttons_box = g_object_get_data(G_OBJECT(sheet_widget), "buttons");
gtk_container_foreach(GTK_CONTAINER(buttons_box),
datasheet_button_check_sens, sheet_widget);
}
static void
datasheet_update_rec(PurpleRequestDatasheetRecord *rec, GtkListStore *model,
GtkTreeIter *iter)
{
guint i, col_count;
PurpleRequestDatasheet *sheet;
g_return_if_fail(rec != NULL);
g_return_if_fail(model != NULL);
g_return_if_fail(iter != NULL);
sheet = purple_request_datasheet_record_get_datasheet(rec);
g_return_if_fail(sheet != NULL);
col_count = purple_request_datasheet_get_column_count(sheet);
for (i = 0; i < col_count; i++) {
PurpleRequestDatasheetColumnType type;
type = purple_request_datasheet_get_column_type(
sheet, i);
if (type == PURPLE_REQUEST_DATASHEET_COLUMN_STRING) {
GValue val;
val.g_type = 0;
g_value_init(&val, G_TYPE_STRING);
g_value_set_string(&val,
purple_request_datasheet_record_get_string_data(
rec, i));
gtk_list_store_set_value(model, iter,
i + 1, &val);
} else if (type ==
PURPLE_REQUEST_DATASHEET_COLUMN_IMAGE)
{
GdkPixbuf *pixbuf;
pixbuf = _pidgin_datasheet_stock_icon_get(
purple_request_datasheet_record_get_image_data(
rec, i));
gtk_list_store_set(model, iter, i + 1,
pixbuf, -1);
} else
g_warn_if_reached();
}
}
static void
datasheet_fill(PurpleRequestDatasheet *sheet, GtkListStore *model)
{
const GList *it;
gtk_list_store_clear(model);
it = purple_request_datasheet_get_records(sheet);
for (; it != NULL; it = g_list_next(it)) {
PurpleRequestDatasheetRecord *rec = it->data;
GtkTreeIter iter;
gtk_list_store_append(model, &iter);
gtk_list_store_set(model, &iter, 0,
purple_request_datasheet_record_get_key(rec), -1);
datasheet_update_rec(rec, model, &iter);
}
datasheet_selection_changed(GTK_WIDGET(g_object_get_data(
G_OBJECT(model), "sheet-widget")));
}
static void
datasheet_update(PurpleRequestDatasheet *sheet, gpointer key,
GtkListStore *model)
{
PurpleRequestDatasheetRecord *rec;
GtkTreeIter iter;
GtkTreeModel *tmodel = GTK_TREE_MODEL(model);
gboolean found = FALSE;
g_return_if_fail(tmodel != NULL);
if (key == NULL) {
datasheet_fill(sheet, model);
return;
}
rec = purple_request_datasheet_record_find(sheet, key);
if (gtk_tree_model_get_iter_first(tmodel, &iter)) {
do {
gpointer ikey;
gtk_tree_model_get(tmodel, &iter, 0, &ikey, -1);
if (key == ikey) {
found = TRUE;
break;
}
} while (gtk_tree_model_iter_next(tmodel, &iter));
}
if (rec == NULL && !found)
return;
if (rec == NULL) {
gtk_list_store_remove(model, &iter);
return;
}
if (!found) {
gtk_list_store_append(model, &iter);
gtk_list_store_set(model, &iter, 0, key, -1);
}
datasheet_update_rec(rec, model, &iter);
datasheet_selection_changed(GTK_WIDGET(g_object_get_data(
G_OBJECT(model), "sheet-widget")));
}
static void
datasheet_selection_changed_cb(GtkTreeSelection *sel, gpointer sheet_widget)
{
datasheet_selection_changed(GTK_WIDGET(sheet_widget));
}
static void
datasheet_action_clicked(GtkButton *btn, PurpleRequestDatasheetAction *act)
{
GtkWidget *sheet_widget;
sheet_widget = g_object_get_data(G_OBJECT(btn), "sheet-widget");
g_return_if_fail(sheet_widget != NULL);
purple_request_datasheet_action_call(act, datasheet_get_selected_row(
sheet_widget));
}
static GtkWidget *
create_datasheet_field(PurpleRequestField *field, GtkSizeGroup *buttons_sg)
{
PurpleRequestDatasheet *sheet;
guint i, col_count;
GType *col_types;
GtkListStore *model;
GtkTreeView *view;
GtkTreeSelection *sel;
GtkWidget *scrollable;
GtkCellRenderer *renderer_image = NULL, *renderer_text = NULL;
GtkTreeViewColumn *id_column;
GtkWidget *main_box;
GtkWidget *buttons_box;
const GList *it;
sheet = purple_request_field_datasheet_get_sheet(field);
main_box = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 0);
col_count = purple_request_datasheet_get_column_count(sheet);
col_types = g_new0(GType, col_count + 1);
col_types[0] = G_TYPE_POINTER;
for (i = 0; i < col_count; i++) {
PurpleRequestDatasheetColumnType type;
type = purple_request_datasheet_get_column_type(sheet, i);
if (type == PURPLE_REQUEST_DATASHEET_COLUMN_STRING)
col_types[i + 1] = G_TYPE_STRING;
else if (type == PURPLE_REQUEST_DATASHEET_COLUMN_IMAGE)
col_types[i + 1] = GDK_TYPE_PIXBUF;
else
g_warn_if_reached();
}
model = gtk_list_store_newv(col_count + 1, col_types);
g_free(col_types);
view = GTK_TREE_VIEW(gtk_tree_view_new_with_model(
GTK_TREE_MODEL(model)));
g_object_set_data(G_OBJECT(model), "sheet-widget", main_box);
g_object_unref(G_OBJECT(model));
id_column = gtk_tree_view_column_new();
gtk_tree_view_column_set_visible(id_column, FALSE);
gtk_tree_view_append_column(view, id_column);
for (i = 0; i < col_count; i++) {
PurpleRequestDatasheetColumnType type;
const gchar *title;
GtkCellRenderer *renderer = NULL;
const gchar *type_str = "";
type = purple_request_datasheet_get_column_type(sheet, i);
title = purple_request_datasheet_get_column_title(sheet, i);
if (type == PURPLE_REQUEST_DATASHEET_COLUMN_STRING) {
type_str = "text";
if (!renderer_text)
renderer_text = gtk_cell_renderer_text_new();
renderer = renderer_text;
}
else if (type == PURPLE_REQUEST_DATASHEET_COLUMN_IMAGE) {
type_str = "pixbuf";
if (!renderer_image)
renderer_image = gtk_cell_renderer_pixbuf_new();
renderer = renderer_image;
} else
g_warn_if_reached();
if (title == NULL)
title = "";
gtk_tree_view_insert_column_with_attributes(
view, -1, title, renderer, type_str,
i + 1, NULL);
}
gtk_widget_set_size_request(GTK_WIDGET(view), 400, 250);
scrollable = pidgin_make_scrollable(GTK_WIDGET(view),
GTK_POLICY_AUTOMATIC, GTK_POLICY_ALWAYS, GTK_SHADOW_IN, -1, -1);
gtk_widget_show(GTK_WIDGET(view));
buttons_box = gtk_box_new(GTK_ORIENTATION_VERTICAL, 12);
gtk_size_group_add_widget(buttons_sg, buttons_box);
gtk_box_pack_start(GTK_BOX(main_box), scrollable, TRUE, TRUE, 0);
gtk_box_pack_start(GTK_BOX(main_box), buttons_box,
FALSE, FALSE, 0);
gtk_widget_show(scrollable);
gtk_widget_show(buttons_box);
it = purple_request_datasheet_get_actions(sheet);
for (; it != NULL; it = g_list_next(it)) {
PurpleRequestDatasheetAction *act = it->data;
GtkButton *btn;
const gchar *label;
label = purple_request_datasheet_action_get_label(act);
btn = GTK_BUTTON(gtk_button_new_with_label(label ? label : ""));
g_object_set_data(G_OBJECT(btn), "action", act);
g_object_set_data(G_OBJECT(btn), "sheet-widget", main_box);
g_signal_connect(G_OBJECT(btn), "clicked",
G_CALLBACK(datasheet_action_clicked), act);
gtk_box_pack_start(GTK_BOX(buttons_box), GTK_WIDGET(btn),
FALSE, FALSE, 0);
gtk_widget_show(GTK_WIDGET(btn));
}
g_object_set_data(G_OBJECT(main_box), "view", view);
g_object_set_data(G_OBJECT(main_box), "buttons", buttons_box);
g_object_set_data(G_OBJECT(main_box), "sheet", sheet);
datasheet_fill(sheet, model);
purple_signal_connect(sheet, "record-changed",
pidgin_request_get_handle(),
PURPLE_CALLBACK(datasheet_update), model);
sel = gtk_tree_view_get_selection(view);
g_signal_connect(G_OBJECT(sel), "changed",
G_CALLBACK(datasheet_selection_changed_cb), main_box);
return main_box;
}
static void *
pidgin_request_fields(const char *title, const char *primary,
const char *secondary, PurpleRequestFields *fields, const char *ok_text,
GCallback ok_cb, const char *cancel_text, GCallback cancel_cb,
PurpleRequestCommonParameters *cpar, void *user_data)
{
PidginRequestData *data;
GtkWidget *win;
GtkNotebook *notebook;
GtkWidget **pages;
GtkWidget *hbox, *vbox;
GtkWidget *frame;
GtkWidget *label;
GtkWidget *grid;
GtkWidget *button;
GtkWidget *img;
GtkSizeGroup *sg, *datasheet_buttons_sg;
GList *gl, *fl;
PurpleRequestFieldGroup *group;
PurpleRequestField *field;
char *label_text;
char *primary_esc, *secondary_esc;
const gboolean compact = purple_request_cpar_is_compact(cpar);
GSList *extra_actions;
size_t i;
const gchar **tab_names;
guint tab_count;
gboolean ok_btn = (ok_text != NULL);
data = g_new0(PidginRequestData, 1);
data->type = PURPLE_REQUEST_FIELDS;
data->user_data = user_data;
data->u.multifield.fields = fields;
purple_request_fields_set_ui_data(fields, data);
extra_actions = purple_request_cpar_get_extra_actions(cpar);
data->cb_count = 2;
data->cbs = g_new0(GCallback, 2);
data->cbs[0] = ok_cb;
data->cbs[1] = cancel_cb;
data->dialog = win = pidgin_dialog_new(title, 12, "multifield", TRUE) ;
g_signal_connect(G_OBJECT(win), "delete_event",
G_CALLBACK(destroy_multifield_cb), data);
/* Setup the main horizontal box */
hbox = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 12);
gtk_container_add(GTK_CONTAINER(pidgin_dialog_get_vbox(GTK_DIALOG(win))), hbox);
gtk_widget_show(hbox);
/* Dialog icon. */
img = pidgin_request_dialog_icon(PURPLE_REQUEST_FIELDS, cpar);
gtk_widget_set_halign(img, GTK_ALIGN_START);
gtk_widget_set_valign(img, GTK_ALIGN_START);
gtk_box_pack_start(GTK_BOX(hbox), img, FALSE, FALSE, 0);
gtk_widget_show(img);
pidgin_request_add_help(GTK_DIALOG(win), cpar);
for (GSList *it = extra_actions; it != NULL; it = it->next) {
PurpleKeyValuePair *extra_action = it->data;
button = pidgin_dialog_add_button(GTK_DIALOG(win), extra_action->key,
G_CALLBACK(multifield_extra_cb), data);
g_object_set_data(G_OBJECT(button), "extra-cb", extra_action->value);
}
/* Cancel button */
button = pidgin_dialog_add_button(GTK_DIALOG(win), cancel_text,
G_CALLBACK(multifield_cancel_cb), data);
gtk_widget_set_can_default(button, TRUE);
/* OK button */
if (!ok_btn) {
gtk_window_set_default(GTK_WINDOW(win), button);
} else {
button = pidgin_dialog_add_button(GTK_DIALOG(win), ok_text,
G_CALLBACK(multifield_ok_cb), data);
data->ok_button = button;
gtk_widget_set_can_default(button, TRUE);
gtk_window_set_default(GTK_WINDOW(win), button);
}
pidgin_widget_decorate_account(hbox,
purple_request_cpar_get_account(cpar));
/* Setup the vbox */
vbox = gtk_box_new(GTK_ORIENTATION_VERTICAL, 12);
gtk_box_pack_start(GTK_BOX(hbox), vbox, TRUE, TRUE, 0);
gtk_widget_show(vbox);
sg = gtk_size_group_new(GTK_SIZE_GROUP_HORIZONTAL);
datasheet_buttons_sg = gtk_size_group_new(GTK_SIZE_GROUP_HORIZONTAL);
if(primary) {
primary_esc = pidgin_request_escape(cpar, primary);
label_text = g_strdup_printf(
"<span weight=\"bold\" size=\"larger\">%s</span>", primary_esc);
g_free(primary_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_label_set_xalign(GTK_LABEL(label), 0);
gtk_label_set_yalign(GTK_LABEL(label), 0);
gtk_box_pack_start(GTK_BOX(vbox), label, FALSE, FALSE, 0);
gtk_widget_show(label);
g_free(label_text);
}
/* Setup tabs */
tab_names = purple_request_fields_get_tab_names(fields);
if (tab_names == NULL) {
notebook = NULL;
tab_count = 1;
pages = g_new0(GtkWidget*, 1);
pages[0] = vbox;
} else {
tab_count = g_strv_length((gchar **)tab_names);
notebook = GTK_NOTEBOOK(gtk_notebook_new());
pages = g_new0(GtkWidget*, tab_count);
for (i = 0; i < tab_count; i++) {
pages[i] = gtk_box_new(GTK_ORIENTATION_VERTICAL, 12);
gtk_container_set_border_width(GTK_CONTAINER(pages[i]), 12);
gtk_notebook_append_page(notebook, pages[i], NULL);
gtk_notebook_set_tab_label_text(notebook, pages[i], tab_names[i]);
gtk_widget_show(pages[i]);
}
}
for (i = 0; i < tab_count; i++) {
guint total_fields = 0;
GList *it;
it = purple_request_fields_get_groups(fields);
for (; it != NULL; it = g_list_next(it)) {
group = it->data;
if (purple_request_field_group_get_tab(group) != i)
continue;
total_fields += g_list_length(
purple_request_field_group_get_fields(group));
}
if(total_fields > 9) {
GtkWidget *hbox_for_spacing, *vbox_for_spacing;
gtk_container_set_border_width(
GTK_CONTAINER(pages[i]), 0);
hbox_for_spacing =
gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 12);
gtk_box_pack_start(GTK_BOX(pages[i]),
pidgin_make_scrollable(hbox_for_spacing,
GTK_POLICY_NEVER, GTK_POLICY_AUTOMATIC,
GTK_SHADOW_NONE, -1, 200),
TRUE, TRUE, 0);
gtk_widget_show(hbox_for_spacing);
vbox_for_spacing =
gtk_box_new(GTK_ORIENTATION_VERTICAL, 12);
gtk_box_pack_start(GTK_BOX(hbox_for_spacing),
vbox_for_spacing, TRUE, TRUE,
6);
gtk_widget_show(vbox_for_spacing);
pages[i] = gtk_box_new(GTK_ORIENTATION_VERTICAL, 12);
gtk_box_pack_start(GTK_BOX(vbox_for_spacing),
pages[i], TRUE, TRUE, 6);
gtk_widget_show(pages[i]);
}
if (notebook == NULL)
vbox = pages[0];
}
if (secondary) {
secondary_esc = pidgin_request_escape(cpar, secondary);
label = gtk_label_new(NULL);
gtk_label_set_markup(GTK_LABEL(label), secondary_esc);
g_free(secondary_esc);
gtk_label_set_line_wrap(GTK_LABEL(label), TRUE);
gtk_label_set_xalign(GTK_LABEL(label), 0);
gtk_label_set_yalign(GTK_LABEL(label), 0);
gtk_box_pack_start(GTK_BOX(vbox), label, (notebook == NULL),
(notebook == NULL), 0);
gtk_widget_show(label);
}
if (notebook != NULL) {
gtk_box_pack_start(GTK_BOX(vbox), GTK_WIDGET(notebook), TRUE, TRUE, 0);
gtk_widget_show(GTK_WIDGET(notebook));
}
for (gl = purple_request_fields_get_groups(fields);
gl != NULL;
gl = gl->next)
{
GList *field_list;
size_t field_count = 0;
size_t cols = 1;
size_t rows;
#if 0
size_t col_num;
#endif
size_t row_num = 0;
guint tab_no;
gboolean contains_resizable = FALSE, frame_fill;
group = gl->data;
field_list = purple_request_field_group_get_fields(group);
tab_no = purple_request_field_group_get_tab(group);
if (tab_no >= tab_count) {
purple_debug_warning("gtkrequest",
"Invalid tab number: %d", tab_no);
tab_no = 0;
}
if (purple_request_field_group_get_title(group) != NULL)
{
frame = pidgin_make_frame(pages[tab_no],
purple_request_field_group_get_title(group));
}
else
frame = pages[tab_no];
field_count = g_list_length(field_list);
#if 0
if (field_count > 9)
{
rows = field_count / 2;
cols++;
}
else
#endif
rows = field_count;
#if 0
col_num = 0;
#endif
for (fl = field_list; fl != NULL; fl = fl->next)
{
PurpleRequestFieldType type;
field = (PurpleRequestField *)fl->data;
type = purple_request_field_get_field_type(field);
if (type == PURPLE_REQUEST_FIELD_DATASHEET)
contains_resizable = TRUE;
if (type == PURPLE_REQUEST_FIELD_LABEL)
{
#if 0
if (col_num > 0)
rows++;
#endif
rows++;
}
else if ((type == PURPLE_REQUEST_FIELD_LIST) ||
(type == PURPLE_REQUEST_FIELD_STRING &&
purple_request_field_string_is_multiline(field)))
{
#if 0
if (col_num > 0)
rows++;
#endif
rows += 2;
} else if (compact && type != PURPLE_REQUEST_FIELD_BOOLEAN)
rows++;
#if 0
col_num++;
if (col_num >= cols)
col_num = 0;
#endif
}
grid = gtk_grid_new();
gtk_grid_set_row_spacing(GTK_GRID(grid), 6);
gtk_grid_set_column_spacing(GTK_GRID(grid), 6);
frame_fill = (notebook == NULL || contains_resizable);
gtk_box_pack_start(GTK_BOX(frame), grid, frame_fill, frame_fill, 0);
gtk_widget_show(grid);
for (row_num = 0, fl = field_list;
row_num < rows && fl != NULL;
row_num++)
{
#if 0
for (col_num = 0;
col_num < cols && fl != NULL;
col_num++, fl = fl->next)
#else
gboolean dummy_counter = TRUE;
/* it's the same as loop above */
for (; dummy_counter && fl != NULL; dummy_counter = FALSE, fl = fl->next)
#endif
{
#if 0
size_t col_offset = col_num * 2;
#else
size_t col_offset = 0;
#endif
PurpleRequestFieldType type;
GtkWidget *widget = NULL;
gchar *field_label;
label = NULL;
field = fl->data;
if (!purple_request_field_is_visible(field)) {
#if 0
col_num--;
#endif
continue;
}
type = purple_request_field_get_field_type(field);
field_label = pidgin_request_escape(cpar,
purple_request_field_get_label(field));
if (type != PURPLE_REQUEST_FIELD_BOOLEAN && field_label)
{
char *text = NULL;
if (field_label[strlen(field_label) - 1] != ':' &&
field_label[strlen(field_label) - 1] != '?' &&
type != PURPLE_REQUEST_FIELD_LABEL)
{
text = g_strdup_printf("%s:", field_label);
}
label = gtk_label_new(NULL);
gtk_label_set_markup_with_mnemonic(GTK_LABEL(label), text ? text : field_label);
g_free(text);
gtk_widget_set_hexpand(label, TRUE);
gtk_widget_set_vexpand(label, TRUE);
gtk_label_set_xalign(GTK_LABEL(label), 0);
gtk_size_group_add_widget(sg, label);
if (type == PURPLE_REQUEST_FIELD_LABEL ||
type == PURPLE_REQUEST_FIELD_LIST ||
(type == PURPLE_REQUEST_FIELD_STRING &&
purple_request_field_string_is_multiline(field)))
{
#if 0
if(col_num > 0)
row_num++;
#endif
gtk_grid_attach(GTK_GRID(grid), label,
0, row_num, 2 * cols, 1);
row_num++;
#if 0
col_num=cols;
#endif
}
else
{
gtk_grid_attach(GTK_GRID(grid), label,
col_offset, row_num, 1, 1);
}
gtk_widget_show(label);
g_free(field_label);
}
widget = GTK_WIDGET(purple_request_field_get_ui_data(field));
if (widget == NULL)
{
if (type == PURPLE_REQUEST_FIELD_STRING)
widget = create_string_field(field);
else if (type == PURPLE_REQUEST_FIELD_INTEGER)
widget = create_int_field(field);
else if (type == PURPLE_REQUEST_FIELD_BOOLEAN)
widget = create_bool_field(field, cpar);
else if (type == PURPLE_REQUEST_FIELD_CHOICE)
widget = create_choice_field(field, cpar);
else if (type == PURPLE_REQUEST_FIELD_LIST)
widget = create_list_field(field);
else if (type == PURPLE_REQUEST_FIELD_IMAGE)
widget = create_image_field(field);
else if (type == PURPLE_REQUEST_FIELD_ACCOUNT)
widget = create_account_field(field);
else if (type == PURPLE_REQUEST_FIELD_DATASHEET)
widget = create_datasheet_field(field, datasheet_buttons_sg);
else
continue;
}
gtk_widget_set_sensitive(widget,
purple_request_field_is_sensitive(field));
if (label)
gtk_label_set_mnemonic_widget(GTK_LABEL(label), widget);
gtk_widget_set_hexpand(widget, TRUE);
gtk_widget_set_vexpand(widget, TRUE);
gtk_widget_set_margin_start(widget, 5);
gtk_widget_set_margin_end(widget, 5);
if (type == PURPLE_REQUEST_FIELD_STRING &&
purple_request_field_string_is_multiline(field))
{
gtk_grid_attach(GTK_GRID(grid), widget,
0, row_num, 2 * cols, 1);
}
else if (type == PURPLE_REQUEST_FIELD_LIST)
{
gtk_grid_attach(GTK_GRID(grid), widget,
0, row_num, 2 * cols, 1);
}
else if (type == PURPLE_REQUEST_FIELD_BOOLEAN)
{
gtk_grid_attach(GTK_GRID(grid), widget,
col_offset, row_num, 1, 1);
}
else if (compact) {
row_num++;
gtk_grid_attach(GTK_GRID(grid), widget,
0, row_num, 2 * cols, 1);
} else {
gtk_grid_attach(GTK_GRID(grid), widget,
1, row_num, 2 * cols - 1, 1);
}
gtk_widget_show(widget);
purple_request_field_set_ui_data(field, widget);
}
}
}
g_object_unref(sg);
g_object_unref(datasheet_buttons_sg);
if (!purple_request_fields_all_required_filled(fields))
gtk_widget_set_sensitive(data->ok_button, FALSE);
if (!purple_request_fields_all_valid(fields))
gtk_widget_set_sensitive(data->ok_button, FALSE);
g_free(pages);
pidgin_auto_parent_window(win);
gtk_widget_show(win);
return data;
}
static void
file_ok_check_if_exists_cb(GtkWidget *widget, gint response, PidginRequestData *data)
{
gchar *current_folder;
if (response != GTK_RESPONSE_ACCEPT) {
if (data->cbs[0] != NULL)
((PurpleRequestFileCb)data->cbs[0])(data->user_data, NULL);
purple_request_close(data->type, data);
return;
}
data->u.file.name = gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(data->dialog));
current_folder = gtk_file_chooser_get_current_folder(GTK_FILE_CHOOSER(data->dialog));
if (current_folder != NULL) {
if (data->u.file.savedialog) {
purple_prefs_set_path(PIDGIN_PREFS_ROOT "/filelocations/last_save_folder", current_folder);
} else {
purple_prefs_set_path(PIDGIN_PREFS_ROOT "/filelocations/last_open_folder", current_folder);
}
g_free(current_folder);
}
if (data->cbs[1] != NULL) {
((PurpleRequestFileCb)data->cbs[1])(data->user_data, data->u.file.name);
}
purple_request_close(data->type, data);
}
static void *
pidgin_request_file(const char *title, const char *filename,
gboolean savedialog, GCallback ok_cb, GCallback cancel_cb,
PurpleRequestCommonParameters *cpar, void *user_data)
{
PidginRequestData *data;
GtkFileChooserNative *filesel;
#ifdef _WIN32
const gchar *current_folder;
gboolean folder_set = FALSE;
#endif
data = g_new0(PidginRequestData, 1);
data->type = PURPLE_REQUEST_FILE;
data->user_data = user_data;
data->cb_count = 2;
data->cbs = g_new0(GCallback, 2);
data->cbs[0] = cancel_cb;
data->cbs[1] = ok_cb;
data->u.file.savedialog = savedialog;
filesel = gtk_file_chooser_native_new(
title ? title
: (savedialog ? _("Save File...") : _("Open File...")),
NULL,
savedialog ? GTK_FILE_CHOOSER_ACTION_SAVE
: GTK_FILE_CHOOSER_ACTION_OPEN,
savedialog ? _("_Save") : _("_Open"), _("_Cancel"));
gtk_file_chooser_set_do_overwrite_confirmation(GTK_FILE_CHOOSER(filesel),
TRUE);
if ((filename != NULL) && (*filename != '\0')) {
if (savedialog)
gtk_file_chooser_set_current_name(GTK_FILE_CHOOSER(filesel), filename);
else if (g_file_test(filename, G_FILE_TEST_EXISTS))
gtk_file_chooser_set_filename(GTK_FILE_CHOOSER(filesel), filename);
}
#ifdef _WIN32
if (savedialog) {
current_folder = purple_prefs_get_path(PIDGIN_PREFS_ROOT "/filelocations/last_save_folder");
} else {
current_folder = purple_prefs_get_path(PIDGIN_PREFS_ROOT "/filelocations/last_open_folder");
}
if ((filename == NULL || *filename == '\0' || !g_file_test(filename, G_FILE_TEST_EXISTS)) &&
(current_folder != NULL) && (*current_folder != '\0')) {
folder_set = gtk_file_chooser_set_current_folder(GTK_FILE_CHOOSER(filesel), current_folder);
}
if (!folder_set && (filename == NULL || *filename == '\0' || !g_file_test(filename, G_FILE_TEST_EXISTS))) {
char *my_documents = wpurple_get_special_folder(CSIDL_PERSONAL);
if (my_documents != NULL) {
gtk_file_chooser_set_current_folder(
GTK_FILE_CHOOSER(filesel), my_documents);
g_free(my_documents);
}
}
#endif
g_signal_connect(G_OBJECT(GTK_FILE_CHOOSER(filesel)), "response",
G_CALLBACK(file_ok_check_if_exists_cb), data);
#if 0
/* FIXME: Not implemented for native dialogs. */
pidgin_auto_parent_window(filesel);
#endif
data->dialog = filesel;
gtk_native_dialog_show(GTK_NATIVE_DIALOG(filesel));
return (void *)data;
}
static void *
pidgin_request_folder(const char *title, const char *dirname, GCallback ok_cb,
GCallback cancel_cb, PurpleRequestCommonParameters *cpar,
void *user_data)
{
PidginRequestData *data;
GtkFileChooserNative *dirsel;
data = g_new0(PidginRequestData, 1);
data->type = PURPLE_REQUEST_FOLDER;
data->user_data = user_data;
data->cb_count = 2;
data->cbs = g_new0(GCallback, 2);
data->cbs[0] = cancel_cb;
data->cbs[1] = ok_cb;
data->u.file.savedialog = FALSE;
dirsel = gtk_file_chooser_native_new(
title ? title : _("Select Folder..."), NULL,
GTK_FILE_CHOOSER_ACTION_SELECT_FOLDER, _("_OK"), _("_Cancel"));
if ((dirname != NULL) && (*dirname != '\0'))
gtk_file_chooser_set_current_folder(GTK_FILE_CHOOSER(dirsel), dirname);
g_signal_connect(G_OBJECT(GTK_FILE_CHOOSER(dirsel)), "response",
G_CALLBACK(file_ok_check_if_exists_cb), data);
data->dialog = dirsel;
#if 0
/* FIXME: Not implemented for native dialogs. */
pidgin_auto_parent_window(dirsel);
#endif
gtk_native_dialog_show(GTK_NATIVE_DIALOG(dirsel));
return (void *)data;
}
/* if request callback issues another request, it should be attached to the
* primary request parent */
static void
pidgin_window_detach_children(GtkWindow* win)
{
GList *it;
GtkWindow *par;
g_return_if_fail(win != NULL);
par = gtk_window_get_transient_for(win);
it = gtk_window_list_toplevels();
for (it = g_list_first(it); it != NULL; it = g_list_delete_link(it, it)) {
GtkWindow *child = GTK_WINDOW(it->data);
if (gtk_window_get_transient_for(child) != win)
continue;
if (gtk_window_get_destroy_with_parent(child)) {
#ifdef _WIN32
/* XXX test/verify it: Win32 gtk ignores
* gtk_window_set_destroy_with_parent(..., FALSE). */
gtk_window_set_transient_for(child, NULL);
#endif
continue;
}
gtk_window_set_transient_for(child, par);
}
}
static void
pidgin_close_request(PurpleRequestType type, void *ui_handle)
{
PidginRequestData *data = (PidginRequestData *)ui_handle;
g_free(data->cbs);
if (type == PURPLE_REQUEST_FILE || type == PURPLE_REQUEST_FOLDER) {
/* Will be a GtkNativeDialog, not GtkDialog. */
g_object_unref(data->dialog);
} else {
pidgin_window_detach_children(GTK_WINDOW(data->dialog));
gtk_widget_destroy(data->dialog);
}
if (type == PURPLE_REQUEST_FIELDS)
purple_request_fields_destroy(data->u.multifield.fields);
else if (type == PURPLE_REQUEST_FILE)
g_free(data->u.file.name);
g_free(data);
}
GtkWindow *
pidgin_request_get_dialog_window(void *ui_handle)
{
PidginRequestData *data = ui_handle;
g_return_val_if_fail(
purple_request_is_valid_ui_handle(data, NULL), NULL);
if (data->type == PURPLE_REQUEST_FILE ||
data->type == PURPLE_REQUEST_FOLDER) {
/* Not a GtkWidget, but a GtkFileChooserNative. Eventually this function
* should not be needed, once we don't need to auto-parent. */
return NULL;
}
return GTK_WINDOW(data->dialog);
}
static PurpleRequestUiOps ops =
{
PURPLE_REQUEST_FEATURE_HTML,
pidgin_request_input,
pidgin_request_choice,
pidgin_request_action,
pidgin_request_wait,
pidgin_request_wait_update,
pidgin_request_fields,
pidgin_request_file,
pidgin_request_folder,
pidgin_close_request,
NULL,
NULL,
NULL,
NULL
};
PurpleRequestUiOps *
pidgin_request_get_ui_ops(void)
{
return &ops;
}
void *
pidgin_request_get_handle(void)
{
static int handle;
return &handle;
}
static void
pidgin_request_datasheet_stock_remove(gpointer obj)
{
if (obj == NULL)
return;
g_object_unref(obj);
}
void
pidgin_request_init(void)
{
datasheet_stock = g_hash_table_new_full(g_str_hash, g_str_equal,
g_free, pidgin_request_datasheet_stock_remove);
}
void
pidgin_request_uninit(void)
{
purple_signals_disconnect_by_handle(pidgin_request_get_handle());
g_hash_table_destroy(datasheet_stock);
datasheet_stock = NULL;
}