2 * @file gtkrequest.c GTK+ Request API
8 * Pidgin is the legal property of its developers, whose names are too numerous
9 * to list here. Please refer to the COPYRIGHT file distributed with this
10 * source distribution.
12 * This program is free software; you can redistribute it and/or modify
13 * it under the terms of the GNU General Public License as published by
14 * the Free Software Foundation; either version 2 of the License, or
15 * (at your option) any later version.
17 * This program is distributed in the hope that it will be useful,
18 * but WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20 * GNU General Public License for more details.
22 * You should have received a copy of the GNU General Public License
23 * along with this program; if not, write to the Free Software
24 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111-1301 USA
32 #include "gtkimhtml.h"
33 #include "gtkimhtmltoolbar.h"
34 #include "gtkrequest.h"
36 #include "pidginstock.h"
39 #include <gdk/gdkkeysyms.h>
41 static GtkWidget
* create_account_field(PurpleRequestField
*field
);
45 PurpleRequestType type
;
68 PurpleRequestFields
*fields
;
84 pidgin_widget_decorate_account(GtkWidget
*cont
, PurpleAccount
*account
)
93 pixbuf
= pidgin_create_prpl_icon(account
, PIDGIN_PRPL_ICON_SMALL
);
94 image
= gtk_image_new_from_pixbuf(pixbuf
);
95 g_object_unref(G_OBJECT(pixbuf
));
97 tips
= gtk_tooltips_new();
98 gtk_tooltips_set_tip(tips
, image
, purple_account_get_username(account
), NULL
);
100 if (GTK_IS_DIALOG(cont
)) {
101 gtk_box_pack_start(GTK_BOX(GTK_DIALOG(cont
)->action_area
), image
, FALSE
, TRUE
, 0);
102 gtk_box_reorder_child(GTK_BOX(GTK_DIALOG(cont
)->action_area
), image
, 0);
103 } else if (GTK_IS_HBOX(cont
)) {
104 gtk_misc_set_alignment(GTK_MISC(image
), 0, 0);
105 gtk_box_pack_end(GTK_BOX(cont
), image
, FALSE
, TRUE
, 0);
107 gtk_widget_show(image
);
111 generic_response_start(PidginRequestData
*data
)
113 g_return_if_fail(data
!= NULL
);
115 /* Tell the user we're doing something. */
116 pidgin_set_cursor(GTK_WIDGET(data
->dialog
), GDK_WATCH
);
120 input_response_cb(GtkDialog
*dialog
, gint id
, PidginRequestData
*data
)
123 char *multiline_value
= NULL
;
125 generic_response_start(data
);
127 if (data
->u
.input
.multiline
) {
128 GtkTextIter start_iter
, end_iter
;
129 GtkTextBuffer
*buffer
=
130 gtk_text_view_get_buffer(GTK_TEXT_VIEW(data
->u
.input
.entry
));
132 gtk_text_buffer_get_start_iter(buffer
, &start_iter
);
133 gtk_text_buffer_get_end_iter(buffer
, &end_iter
);
135 if ((data
->u
.input
.hint
!= NULL
) && (!strcmp(data
->u
.input
.hint
, "html")))
136 multiline_value
= gtk_imhtml_get_markup(GTK_IMHTML(data
->u
.input
.entry
));
138 multiline_value
= gtk_text_buffer_get_text(buffer
, &start_iter
, &end_iter
,
141 value
= multiline_value
;
144 value
= gtk_entry_get_text(GTK_ENTRY(data
->u
.input
.entry
));
146 if (id
< data
->cb_count
&& data
->cbs
[id
] != NULL
)
147 ((PurpleRequestInputCb
)data
->cbs
[id
])(data
->user_data
, value
);
148 else if (data
->cbs
[1] != NULL
)
149 ((PurpleRequestInputCb
)data
->cbs
[1])(data
->user_data
, value
);
151 if (data
->u
.input
.multiline
)
152 g_free(multiline_value
);
154 purple_request_close(PURPLE_REQUEST_INPUT
, data
);
158 action_response_cb(GtkDialog
*dialog
, gint id
, PidginRequestData
*data
)
160 generic_response_start(data
);
162 if (id
< data
->cb_count
&& data
->cbs
[id
] != NULL
)
163 ((PurpleRequestActionCb
)data
->cbs
[id
])(data
->user_data
, id
);
165 purple_request_close(PURPLE_REQUEST_INPUT
, data
);
170 choice_response_cb(GtkDialog
*dialog
, gint id
, PidginRequestData
*data
)
172 GtkWidget
*radio
= g_object_get_data(G_OBJECT(dialog
), "radio");
173 GSList
*group
= gtk_radio_button_get_group(GTK_RADIO_BUTTON(radio
));
175 generic_response_start(data
);
177 if (id
< data
->cb_count
&& data
->cbs
[id
] != NULL
)
179 if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(group
->data
))) {
180 ((PurpleRequestChoiceCb
)data
->cbs
[id
])(data
->user_data
, GPOINTER_TO_INT(g_object_get_data(G_OBJECT(group
->data
), "choice_id")));
185 purple_request_close(PURPLE_REQUEST_INPUT
, data
);
189 field_string_focus_out_cb(GtkWidget
*entry
, GdkEventFocus
*event
,
190 PurpleRequestField
*field
)
194 if (purple_request_field_string_is_multiline(field
))
196 GtkTextBuffer
*buffer
;
197 GtkTextIter start_iter
, end_iter
;
199 buffer
= gtk_text_view_get_buffer(GTK_TEXT_VIEW(entry
));
201 gtk_text_buffer_get_start_iter(buffer
, &start_iter
);
202 gtk_text_buffer_get_end_iter(buffer
, &end_iter
);
204 value
= gtk_text_buffer_get_text(buffer
, &start_iter
, &end_iter
, FALSE
);
207 value
= gtk_entry_get_text(GTK_ENTRY(entry
));
209 purple_request_field_string_set_value(field
,
210 (*value
== '\0' ? NULL
: value
));
216 field_int_focus_out_cb(GtkEntry
*entry
, GdkEventFocus
*event
,
217 PurpleRequestField
*field
)
219 purple_request_field_int_set_value(field
,
220 atoi(gtk_entry_get_text(entry
)));
226 field_bool_cb(GtkToggleButton
*button
, PurpleRequestField
*field
)
228 purple_request_field_bool_set_value(field
,
229 gtk_toggle_button_get_active(button
));
233 field_choice_menu_cb(GtkComboBox
*menu
, PurpleRequestField
*field
)
235 purple_request_field_choice_set_value(field
,
236 gtk_combo_box_get_active(menu
));
240 field_choice_option_cb(GtkRadioButton
*button
, PurpleRequestField
*field
)
242 if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(button
)))
243 purple_request_field_choice_set_value(field
,
244 (g_slist_length(gtk_radio_button_get_group(button
)) -
245 g_slist_index(gtk_radio_button_get_group(button
), button
)) - 1);
249 field_account_cb(GObject
*w
, PurpleAccount
*account
, PurpleRequestField
*field
)
251 purple_request_field_account_set_value(field
, account
);
255 multifield_ok_cb(GtkWidget
*button
, PidginRequestData
*data
)
257 generic_response_start(data
);
259 if (!GTK_WIDGET_HAS_FOCUS(button
))
260 gtk_widget_grab_focus(button
);
262 if (data
->cbs
[0] != NULL
)
263 ((PurpleRequestFieldsCb
)data
->cbs
[0])(data
->user_data
,
264 data
->u
.multifield
.fields
);
266 purple_request_close(PURPLE_REQUEST_FIELDS
, data
);
270 multifield_cancel_cb(GtkWidget
*button
, PidginRequestData
*data
)
272 generic_response_start(data
);
274 if (data
->cbs
[1] != NULL
)
275 ((PurpleRequestFieldsCb
)data
->cbs
[1])(data
->user_data
,
276 data
->u
.multifield
.fields
);
278 purple_request_close(PURPLE_REQUEST_FIELDS
, data
);
282 destroy_multifield_cb(GtkWidget
*dialog
, GdkEvent
*event
,
283 PidginRequestData
*data
)
285 multifield_cancel_cb(NULL
, data
);
290 #define STOCK_ITEMIZE(r, l) \
291 if (!strcmp((r), text)) \
295 text_to_stock(const char *text
)
297 STOCK_ITEMIZE(_("Yes"), GTK_STOCK_YES
);
298 STOCK_ITEMIZE(_("No"), GTK_STOCK_NO
);
299 STOCK_ITEMIZE(_("OK"), GTK_STOCK_OK
);
300 STOCK_ITEMIZE(_("Cancel"), GTK_STOCK_CANCEL
);
301 STOCK_ITEMIZE(_("Apply"), GTK_STOCK_APPLY
);
302 STOCK_ITEMIZE(_("Close"), GTK_STOCK_CLOSE
);
303 STOCK_ITEMIZE(_("Delete"), GTK_STOCK_DELETE
);
304 STOCK_ITEMIZE(_("Add"), GTK_STOCK_ADD
);
305 STOCK_ITEMIZE(_("Remove"), GTK_STOCK_REMOVE
);
306 STOCK_ITEMIZE(_("Save"), GTK_STOCK_SAVE
);
307 STOCK_ITEMIZE(_("Alias"), PIDGIN_STOCK_ALIAS
);
313 pidgin_request_input(const char *title
, const char *primary
,
314 const char *secondary
, const char *default_value
,
315 gboolean multiline
, gboolean masked
, gchar
*hint
,
316 const char *ok_text
, GCallback ok_cb
,
317 const char *cancel_text
, GCallback cancel_cb
,
318 PurpleAccount
*account
, const char *who
, PurpleConversation
*conv
,
321 PidginRequestData
*data
;
330 char *primary_esc
, *secondary_esc
;
332 data
= g_new0(PidginRequestData
, 1);
333 data
->type
= PURPLE_REQUEST_INPUT
;
334 data
->user_data
= user_data
;
337 data
->cbs
= g_new0(GCallback
, 2);
339 data
->cbs
[0] = ok_cb
;
340 data
->cbs
[1] = cancel_cb
;
342 /* Create the dialog. */
343 dialog
= gtk_dialog_new_with_buttons(title
? title
: PIDGIN_ALERT_TITLE
,
345 text_to_stock(cancel_text
), 1,
346 text_to_stock(ok_text
), 0,
348 data
->dialog
= dialog
;
350 g_signal_connect(G_OBJECT(dialog
), "response",
351 G_CALLBACK(input_response_cb
), data
);
353 /* Setup the dialog */
354 gtk_container_set_border_width(GTK_CONTAINER(dialog
), PIDGIN_HIG_BORDER
/2);
355 gtk_container_set_border_width(GTK_CONTAINER(GTK_DIALOG(dialog
)->vbox
), PIDGIN_HIG_BORDER
/2);
357 gtk_window_set_resizable(GTK_WINDOW(dialog
), FALSE
);
358 gtk_dialog_set_has_separator(GTK_DIALOG(dialog
), FALSE
);
359 gtk_dialog_set_default_response(GTK_DIALOG(dialog
), 0);
360 gtk_box_set_spacing(GTK_BOX(GTK_DIALOG(dialog
)->vbox
), PIDGIN_HIG_BORDER
);
362 /* Setup the main horizontal box */
363 hbox
= gtk_hbox_new(FALSE
, PIDGIN_HIG_BORDER
);
364 gtk_container_add(GTK_CONTAINER(GTK_DIALOG(dialog
)->vbox
), hbox
);
367 img
= gtk_image_new_from_stock(PIDGIN_STOCK_DIALOG_QUESTION
,
368 gtk_icon_size_from_name(PIDGIN_ICON_SIZE_TANGO_HUGE
));
369 gtk_misc_set_alignment(GTK_MISC(img
), 0, 0);
370 gtk_box_pack_start(GTK_BOX(hbox
), img
, FALSE
, FALSE
, 0);
373 vbox
= gtk_vbox_new(FALSE
, PIDGIN_HIG_BORDER
);
375 gtk_box_pack_start(GTK_BOX(hbox
), vbox
, TRUE
, TRUE
, 0);
377 pidgin_widget_decorate_account(hbox
, account
);
379 /* Descriptive label */
380 primary_esc
= (primary
!= NULL
) ? g_markup_escape_text(primary
, -1) : NULL
;
381 secondary_esc
= (secondary
!= NULL
) ? g_markup_escape_text(secondary
, -1) : NULL
;
382 label_text
= g_strdup_printf((primary
? "<span weight=\"bold\" size=\"larger\">"
383 "%s</span>%s%s" : "%s%s%s"),
384 (primary
? primary_esc
: ""),
385 ((primary
&& secondary
) ? "\n\n" : ""),
386 (secondary
? secondary_esc
: ""));
388 g_free(secondary_esc
);
390 label
= gtk_label_new(NULL
);
392 gtk_label_set_markup(GTK_LABEL(label
), label_text
);
393 gtk_label_set_line_wrap(GTK_LABEL(label
), TRUE
);
394 gtk_misc_set_alignment(GTK_MISC(label
), 0, 0);
395 gtk_box_pack_start(GTK_BOX(vbox
), label
, FALSE
, FALSE
, 0);
400 data
->u
.input
.multiline
= multiline
;
401 data
->u
.input
.hint
= g_strdup(hint
);
403 gtk_widget_show_all(hbox
);
405 if ((data
->u
.input
.hint
!= NULL
) && (!strcmp(data
->u
.input
.hint
, "html"))) {
409 frame
= pidgin_create_imhtml(TRUE
, &entry
, &toolbar
, NULL
);
410 gtk_widget_set_size_request(entry
, 320, 130);
411 gtk_widget_set_name(entry
, "pidgin_request_imhtml");
412 if (default_value
!= NULL
)
413 gtk_imhtml_append_text(GTK_IMHTML(entry
), default_value
, GTK_IMHTML_NO_SCROLL
);
414 gtk_box_pack_start(GTK_BOX(vbox
), frame
, TRUE
, TRUE
, 0);
415 gtk_widget_show(frame
);
417 gtk_imhtml_set_return_inserts_newline(GTK_IMHTML(entry
));
423 sw
= gtk_scrolled_window_new(NULL
, NULL
);
424 gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(sw
),
425 GTK_POLICY_NEVER
, GTK_POLICY_ALWAYS
);
426 gtk_scrolled_window_set_shadow_type(GTK_SCROLLED_WINDOW(sw
),
429 gtk_widget_set_size_request(sw
, 320, 130);
432 entry
= gtk_text_view_new();
433 gtk_text_view_set_editable(GTK_TEXT_VIEW(entry
), TRUE
);
435 if (default_value
!= NULL
) {
436 GtkTextBuffer
*buffer
;
438 buffer
= gtk_text_view_get_buffer(GTK_TEXT_VIEW(entry
));
439 gtk_text_buffer_set_text(buffer
, default_value
, -1);
442 gtk_text_view_set_wrap_mode(GTK_TEXT_VIEW(entry
), GTK_WRAP_WORD_CHAR
);
444 gtk_box_pack_start(GTK_BOX(vbox
), sw
, TRUE
, TRUE
, 0);
446 if (purple_prefs_get_bool(PIDGIN_PREFS_ROOT
"/conversations/spellcheck"))
447 pidgin_setup_gtkspell(GTK_TEXT_VIEW(entry
));
449 gtk_container_add(GTK_CONTAINER(sw
), entry
);
452 entry
= gtk_entry_new();
454 gtk_entry_set_activates_default(GTK_ENTRY(entry
), TRUE
);
456 gtk_box_pack_start(GTK_BOX(vbox
), entry
, FALSE
, FALSE
, 0);
458 if (default_value
!= NULL
)
459 gtk_entry_set_text(GTK_ENTRY(entry
), default_value
);
463 gtk_entry_set_visibility(GTK_ENTRY(entry
), FALSE
);
464 #if !GTK_CHECK_VERSION(2,16,0)
465 if (gtk_entry_get_invisible_char(GTK_ENTRY(entry
)) == '*')
466 gtk_entry_set_invisible_char(GTK_ENTRY(entry
), PIDGIN_INVISIBLE_CHAR
);
467 #endif /* Less than GTK+ 2.16 */
470 gtk_widget_show_all(vbox
);
473 pidgin_set_accessible_label (entry
, label
);
474 data
->u
.input
.entry
= entry
;
476 pidgin_auto_parent_window(dialog
);
478 /* Show everything. */
479 gtk_widget_show(dialog
);
485 pidgin_request_choice(const char *title
, const char *primary
,
486 const char *secondary
, int default_value
,
487 const char *ok_text
, GCallback ok_cb
,
488 const char *cancel_text
, GCallback cancel_cb
,
489 PurpleAccount
*account
, const char *who
, PurpleConversation
*conv
,
490 void *user_data
, va_list args
)
492 PidginRequestData
*data
;
494 GtkWidget
*vbox
, *vbox2
;
498 GtkWidget
*radio
= NULL
;
501 char *primary_esc
, *secondary_esc
;
503 data
= g_new0(PidginRequestData
, 1);
504 data
->type
= PURPLE_REQUEST_ACTION
;
505 data
->user_data
= user_data
;
508 data
->cbs
= g_new0(GCallback
, 2);
509 data
->cbs
[0] = cancel_cb
;
510 data
->cbs
[1] = ok_cb
;
512 /* Create the dialog. */
513 data
->dialog
= dialog
= gtk_dialog_new();
516 gtk_window_set_title(GTK_WINDOW(dialog
), title
);
518 gtk_window_set_title(GTK_WINDOW(dialog
), PIDGIN_ALERT_TITLE
);
521 gtk_dialog_add_button(GTK_DIALOG(dialog
),
522 text_to_stock(cancel_text
), 0);
524 gtk_dialog_add_button(GTK_DIALOG(dialog
),
525 text_to_stock(ok_text
), 1);
527 g_signal_connect(G_OBJECT(dialog
), "response",
528 G_CALLBACK(choice_response_cb
), data
);
530 /* Setup the dialog */
531 gtk_container_set_border_width(GTK_CONTAINER(dialog
), PIDGIN_HIG_BORDER
/2);
532 gtk_container_set_border_width(GTK_CONTAINER(GTK_DIALOG(dialog
)->vbox
), PIDGIN_HIG_BORDER
/2);
533 gtk_window_set_resizable(GTK_WINDOW(dialog
), FALSE
);
534 gtk_dialog_set_has_separator(GTK_DIALOG(dialog
), FALSE
);
535 gtk_box_set_spacing(GTK_BOX(GTK_DIALOG(dialog
)->vbox
), PIDGIN_HIG_BORDER
);
537 /* Setup the main horizontal box */
538 hbox
= gtk_hbox_new(FALSE
, PIDGIN_HIG_BORDER
);
539 gtk_container_add(GTK_CONTAINER(GTK_DIALOG(dialog
)->vbox
), hbox
);
542 img
= gtk_image_new_from_stock(PIDGIN_STOCK_DIALOG_QUESTION
,
543 gtk_icon_size_from_name(PIDGIN_ICON_SIZE_TANGO_HUGE
));
544 gtk_misc_set_alignment(GTK_MISC(img
), 0, 0);
545 gtk_box_pack_start(GTK_BOX(hbox
), img
, FALSE
, FALSE
, 0);
547 pidgin_widget_decorate_account(hbox
, account
);
550 vbox
= gtk_vbox_new(FALSE
, PIDGIN_HIG_BORDER
);
551 gtk_box_pack_start(GTK_BOX(hbox
), vbox
, FALSE
, FALSE
, 0);
553 /* Descriptive label */
554 primary_esc
= (primary
!= NULL
) ? g_markup_escape_text(primary
, -1) : NULL
;
555 secondary_esc
= (secondary
!= NULL
) ? g_markup_escape_text(secondary
, -1) : NULL
;
556 label_text
= g_strdup_printf((primary
? "<span weight=\"bold\" size=\"larger\">"
557 "%s</span>%s%s" : "%s%s%s"),
558 (primary
? primary_esc
: ""),
559 ((primary
&& secondary
) ? "\n\n" : ""),
560 (secondary
? secondary_esc
: ""));
562 g_free(secondary_esc
);
564 label
= gtk_label_new(NULL
);
566 gtk_label_set_markup(GTK_LABEL(label
), label_text
);
567 gtk_label_set_line_wrap(GTK_LABEL(label
), TRUE
);
568 gtk_misc_set_alignment(GTK_MISC(label
), 0, 0);
569 gtk_box_pack_start(GTK_BOX(vbox
), label
, TRUE
, TRUE
, 0);
573 vbox2
= gtk_vbox_new(FALSE
, PIDGIN_HIG_BOX_SPACE
);
574 gtk_box_pack_start(GTK_BOX(vbox
), vbox2
, FALSE
, FALSE
, 0);
575 while ((radio_text
= va_arg(args
, char*))) {
576 int resp
= va_arg(args
, int);
577 radio
= gtk_radio_button_new_with_label_from_widget(GTK_RADIO_BUTTON(radio
), radio_text
);
578 gtk_box_pack_start(GTK_BOX(vbox2
), radio
, FALSE
, FALSE
, 0);
579 g_object_set_data(G_OBJECT(radio
), "choice_id", GINT_TO_POINTER(resp
));
580 if (resp
== default_value
)
581 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(radio
), TRUE
);
584 g_object_set_data(G_OBJECT(dialog
), "radio", radio
);
586 /* Show everything. */
587 pidgin_auto_parent_window(dialog
);
589 gtk_widget_show_all(dialog
);
595 pidgin_request_action(const char *title
, const char *primary
,
596 const char *secondary
, int default_action
,
597 PurpleAccount
*account
, const char *who
, PurpleConversation
*conv
,
598 void *user_data
, size_t action_count
, va_list actions
)
600 PidginRequestData
*data
;
608 char *primary_esc
, *secondary_esc
;
611 data
= g_new0(PidginRequestData
, 1);
612 data
->type
= PURPLE_REQUEST_ACTION
;
613 data
->user_data
= user_data
;
615 data
->cb_count
= action_count
;
616 data
->cbs
= g_new0(GCallback
, action_count
);
618 /* Reverse the buttons */
619 buttons
= g_new0(void *, action_count
* 2);
621 for (i
= 0; i
< action_count
* 2; i
+= 2) {
622 buttons
[(action_count
* 2) - i
- 2] = va_arg(actions
, char *);
623 buttons
[(action_count
* 2) - i
- 1] = va_arg(actions
, GCallback
);
626 /* Create the dialog. */
627 data
->dialog
= dialog
= gtk_dialog_new();
629 gtk_window_set_deletable(GTK_WINDOW(data
->dialog
), FALSE
);
632 gtk_window_set_title(GTK_WINDOW(dialog
), title
);
635 gtk_window_set_title(GTK_WINDOW(dialog
), PIDGIN_ALERT_TITLE
);
638 for (i
= 0; i
< action_count
; i
++) {
639 gtk_dialog_add_button(GTK_DIALOG(dialog
),
640 text_to_stock(buttons
[2 * i
]), i
);
642 data
->cbs
[i
] = buttons
[2 * i
+ 1];
647 g_signal_connect(G_OBJECT(dialog
), "response",
648 G_CALLBACK(action_response_cb
), data
);
650 /* Setup the dialog */
651 gtk_container_set_border_width(GTK_CONTAINER(dialog
), PIDGIN_HIG_BORDER
/2);
652 gtk_container_set_border_width(GTK_CONTAINER(GTK_DIALOG(dialog
)->vbox
), PIDGIN_HIG_BORDER
/2);
653 gtk_window_set_resizable(GTK_WINDOW(dialog
), FALSE
);
654 gtk_dialog_set_has_separator(GTK_DIALOG(dialog
), FALSE
);
655 gtk_box_set_spacing(GTK_BOX(GTK_DIALOG(dialog
)->vbox
), PIDGIN_HIG_BORDER
);
657 /* Setup the main horizontal box */
658 hbox
= gtk_hbox_new(FALSE
, PIDGIN_HIG_BORDER
);
659 gtk_container_add(GTK_CONTAINER(GTK_DIALOG(dialog
)->vbox
), hbox
);
662 img
= gtk_image_new_from_stock(PIDGIN_STOCK_DIALOG_QUESTION
,
663 gtk_icon_size_from_name(PIDGIN_ICON_SIZE_TANGO_HUGE
));
664 gtk_misc_set_alignment(GTK_MISC(img
), 0, 0);
665 gtk_box_pack_start(GTK_BOX(hbox
), img
, FALSE
, FALSE
, 0);
668 vbox
= gtk_vbox_new(FALSE
, PIDGIN_HIG_BORDER
);
669 gtk_box_pack_start(GTK_BOX(hbox
), vbox
, FALSE
, FALSE
, 0);
671 pidgin_widget_decorate_account(hbox
, account
);
673 /* Descriptive label */
674 primary_esc
= (primary
!= NULL
) ? g_markup_escape_text(primary
, -1) : NULL
;
675 secondary_esc
= (secondary
!= NULL
) ? g_markup_escape_text(secondary
, -1) : NULL
;
676 label_text
= g_strdup_printf((primary
? "<span weight=\"bold\" size=\"larger\">"
677 "%s</span>%s%s" : "%s%s%s"),
678 (primary
? primary_esc
: ""),
679 ((primary
&& secondary
) ? "\n\n" : ""),
680 (secondary
? secondary_esc
: ""));
682 g_free(secondary_esc
);
684 label
= gtk_label_new(NULL
);
686 gtk_label_set_markup(GTK_LABEL(label
), label_text
);
687 gtk_label_set_line_wrap(GTK_LABEL(label
), TRUE
);
688 gtk_misc_set_alignment(GTK_MISC(label
), 0, 0);
689 gtk_label_set_selectable(GTK_LABEL(label
), TRUE
);
690 gtk_box_pack_start(GTK_BOX(vbox
), label
, TRUE
, TRUE
, 0);
695 if (default_action
== PURPLE_DEFAULT_ACTION_NONE
) {
696 GTK_WIDGET_SET_FLAGS(img
, GTK_CAN_DEFAULT
);
697 GTK_WIDGET_SET_FLAGS(img
, GTK_CAN_FOCUS
);
698 gtk_widget_grab_focus(img
);
699 gtk_widget_grab_default(img
);
702 * Need to invert the default_action number because the
703 * buttons are added to the dialog in reverse order.
705 gtk_dialog_set_default_response(GTK_DIALOG(dialog
), action_count
- 1 - default_action
);
707 /* Show everything. */
708 pidgin_auto_parent_window(dialog
);
710 gtk_widget_show_all(dialog
);
716 req_entry_field_changed_cb(GtkWidget
*entry
, PurpleRequestField
*field
)
718 PurpleRequestFieldGroup
*group
;
719 PidginRequestData
*req_data
;
721 if (purple_request_field_string_is_multiline(field
))
724 GtkTextIter start_iter
, end_iter
;
726 gtk_text_buffer_get_start_iter(GTK_TEXT_BUFFER(entry
), &start_iter
);
727 gtk_text_buffer_get_end_iter(GTK_TEXT_BUFFER(entry
), &end_iter
);
729 text
= gtk_text_buffer_get_text(GTK_TEXT_BUFFER(entry
), &start_iter
, &end_iter
, FALSE
);
730 purple_request_field_string_set_value(field
, (!text
|| !*text
) ? NULL
: text
);
735 const char *text
= NULL
;
736 text
= gtk_entry_get_text(GTK_ENTRY(entry
));
737 purple_request_field_string_set_value(field
, (*text
== '\0') ? NULL
: text
);
740 group
= purple_request_field_get_group(field
);
741 req_data
= (PidginRequestData
*)group
->fields_list
->ui_data
;
743 gtk_widget_set_sensitive(req_data
->ok_button
,
744 purple_request_fields_all_required_filled(group
->fields_list
));
748 setup_entry_field(GtkWidget
*entry
, PurpleRequestField
*field
)
750 const char *type_hint
;
752 gtk_entry_set_activates_default(GTK_ENTRY(entry
), TRUE
);
754 if (purple_request_field_is_required(field
))
756 g_signal_connect(G_OBJECT(entry
), "changed",
757 G_CALLBACK(req_entry_field_changed_cb
), field
);
760 if ((type_hint
= purple_request_field_get_type_hint(field
)) != NULL
)
762 if (purple_str_has_prefix(type_hint
, "screenname"))
764 GtkWidget
*optmenu
= NULL
;
765 PurpleRequestFieldGroup
*group
= purple_request_field_get_group(field
);
766 GList
*fields
= group
->fields
;
768 /* Ensure the account option menu is created (if the widget hasn't
769 * been initialized already) for username auto-completion. */
772 PurpleRequestField
*fld
= fields
->data
;
773 fields
= fields
->next
;
775 if (purple_request_field_get_type(fld
) == PURPLE_REQUEST_FIELD_ACCOUNT
&&
776 purple_request_field_is_visible(fld
))
778 const char *type_hint
= purple_request_field_get_type_hint(fld
);
779 if (type_hint
!= NULL
&& strcmp(type_hint
, "account") == 0)
781 optmenu
= GTK_WIDGET(purple_request_field_get_ui_data(fld
));
782 if (optmenu
== NULL
) {
783 optmenu
= GTK_WIDGET(create_account_field(fld
));
784 purple_request_field_set_ui_data(fld
, optmenu
);
790 pidgin_setup_screenname_autocomplete_with_filter(entry
, optmenu
, pidgin_screenname_autocomplete_default_filter
, GINT_TO_POINTER(!strcmp(type_hint
, "screenname-all")));
796 create_string_field(PurpleRequestField
*field
)
801 value
= purple_request_field_string_get_default_value(field
);
803 if (purple_request_field_string_is_multiline(field
))
807 widget
= gtk_scrolled_window_new(NULL
, NULL
);
808 gtk_scrolled_window_set_shadow_type(GTK_SCROLLED_WINDOW(widget
),
810 gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(widget
),
811 GTK_POLICY_NEVER
, GTK_POLICY_ALWAYS
);
813 textview
= gtk_text_view_new();
814 gtk_text_view_set_editable(GTK_TEXT_VIEW(textview
),
816 gtk_text_view_set_wrap_mode(GTK_TEXT_VIEW(textview
),
819 if (purple_prefs_get_bool(PIDGIN_PREFS_ROOT
"/conversations/spellcheck"))
820 pidgin_setup_gtkspell(GTK_TEXT_VIEW(textview
));
822 gtk_container_add(GTK_CONTAINER(widget
), textview
);
823 gtk_widget_show(textview
);
825 gtk_widget_set_size_request(widget
, -1, 75);
829 GtkTextBuffer
*buffer
;
831 buffer
= gtk_text_view_get_buffer(GTK_TEXT_VIEW(textview
));
833 gtk_text_buffer_set_text(buffer
, value
, -1);
836 gtk_text_view_set_editable(GTK_TEXT_VIEW(textview
),
837 purple_request_field_string_is_editable(field
));
839 g_signal_connect(G_OBJECT(textview
), "focus-out-event",
840 G_CALLBACK(field_string_focus_out_cb
), field
);
842 if (purple_request_field_is_required(field
))
844 GtkTextBuffer
*buffer
= gtk_text_view_get_buffer(GTK_TEXT_VIEW(textview
));
845 g_signal_connect(G_OBJECT(buffer
), "changed",
846 G_CALLBACK(req_entry_field_changed_cb
), field
);
851 widget
= gtk_entry_new();
853 setup_entry_field(widget
, field
);
856 gtk_entry_set_text(GTK_ENTRY(widget
), value
);
858 if (purple_request_field_string_is_masked(field
))
860 gtk_entry_set_visibility(GTK_ENTRY(widget
), FALSE
);
861 #if !GTK_CHECK_VERSION(2,16,0)
862 if (gtk_entry_get_invisible_char(GTK_ENTRY(widget
)) == '*')
863 gtk_entry_set_invisible_char(GTK_ENTRY(widget
), PIDGIN_INVISIBLE_CHAR
);
864 #endif /* Less than GTK+ 2.16 */
867 gtk_editable_set_editable(GTK_EDITABLE(widget
),
868 purple_request_field_string_is_editable(field
));
870 g_signal_connect(G_OBJECT(widget
), "focus-out-event",
871 G_CALLBACK(field_string_focus_out_cb
), field
);
878 create_int_field(PurpleRequestField
*field
)
883 widget
= gtk_entry_new();
885 setup_entry_field(widget
, field
);
887 value
= purple_request_field_int_get_default_value(field
);
893 g_snprintf(buf
, sizeof(buf
), "%d", value
);
895 gtk_entry_set_text(GTK_ENTRY(widget
), buf
);
898 g_signal_connect(G_OBJECT(widget
), "focus-out-event",
899 G_CALLBACK(field_int_focus_out_cb
), field
);
905 create_bool_field(PurpleRequestField
*field
)
909 widget
= gtk_check_button_new_with_label(
910 purple_request_field_get_label(field
));
912 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(widget
),
913 purple_request_field_bool_get_default_value(field
));
915 g_signal_connect(G_OBJECT(widget
), "toggled",
916 G_CALLBACK(field_bool_cb
), field
);
922 create_choice_field(PurpleRequestField
*field
)
925 GList
*labels
= purple_request_field_choice_get_labels(field
);
926 int num_labels
= g_list_length(labels
);
931 widget
= gtk_combo_box_new_text();
933 for (l
= labels
; l
!= NULL
; l
= l
->next
)
935 const char *text
= l
->data
;
936 gtk_combo_box_append_text(GTK_COMBO_BOX(widget
), text
);
939 gtk_combo_box_set_active(GTK_COMBO_BOX(widget
),
940 purple_request_field_choice_get_default_value(field
));
942 g_signal_connect(G_OBJECT(widget
), "changed",
943 G_CALLBACK(field_choice_menu_cb
), field
);
948 GtkWidget
*first_radio
= NULL
;
953 box
= gtk_hbox_new(FALSE
, PIDGIN_HIG_BOX_SPACE
);
955 box
= gtk_vbox_new(FALSE
, 0);
959 for (l
= labels
, i
= 0; l
!= NULL
; l
= l
->next
, i
++)
961 const char *text
= l
->data
;
963 radio
= gtk_radio_button_new_with_label_from_widget(
964 GTK_RADIO_BUTTON(first_radio
), text
);
966 if (first_radio
== NULL
)
969 if (i
== purple_request_field_choice_get_default_value(field
))
970 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(radio
), TRUE
);
972 gtk_box_pack_start(GTK_BOX(box
), radio
, TRUE
, TRUE
, 0);
973 gtk_widget_show(radio
);
975 g_signal_connect(G_OBJECT(radio
), "toggled",
976 G_CALLBACK(field_choice_option_cb
), field
);
984 create_image_field(PurpleRequestField
*field
)
987 GdkPixbuf
*buf
, *scale
;
988 GdkPixbufLoader
*loader
;
990 loader
= gdk_pixbuf_loader_new();
991 gdk_pixbuf_loader_write(loader
,
992 (const guchar
*)purple_request_field_image_get_buffer(field
),
993 purple_request_field_image_get_size(field
),
995 gdk_pixbuf_loader_close(loader
, NULL
);
996 buf
= gdk_pixbuf_loader_get_pixbuf(loader
);
998 scale
= gdk_pixbuf_scale_simple(buf
,
999 purple_request_field_image_get_scale_x(field
) * gdk_pixbuf_get_width(buf
),
1000 purple_request_field_image_get_scale_y(field
) * gdk_pixbuf_get_height(buf
),
1001 GDK_INTERP_BILINEAR
);
1002 widget
= gtk_image_new_from_pixbuf(scale
);
1003 g_object_unref(G_OBJECT(loader
));
1004 g_object_unref(G_OBJECT(scale
));
1010 create_account_field(PurpleRequestField
*field
)
1014 widget
= pidgin_account_option_menu_new(
1015 purple_request_field_account_get_default_value(field
),
1016 purple_request_field_account_get_show_all(field
),
1017 G_CALLBACK(field_account_cb
),
1018 purple_request_field_account_get_filter(field
),
1025 select_field_list_item(GtkTreeModel
*model
, GtkTreePath
*path
,
1026 GtkTreeIter
*iter
, gpointer data
)
1028 PurpleRequestField
*field
= (PurpleRequestField
*)data
;
1031 gtk_tree_model_get(model
, iter
, 1, &text
, -1);
1033 purple_request_field_list_add_selected(field
, text
);
1038 list_field_select_changed_cb(GtkTreeSelection
*sel
, PurpleRequestField
*field
)
1040 purple_request_field_list_clear_selected(field
);
1042 gtk_tree_selection_selected_foreach(sel
, select_field_list_item
, field
);
1046 create_list_field(PurpleRequestField
*field
)
1049 GtkWidget
*treeview
;
1050 GtkListStore
*store
;
1051 GtkCellRenderer
*renderer
;
1052 GtkTreeSelection
*sel
;
1053 GtkTreeViewColumn
*column
;
1056 GList
*icons
= NULL
;
1058 icons
= purple_request_field_list_get_icons(field
);
1060 /* Create the scrolled window */
1061 sw
= gtk_scrolled_window_new(NULL
, NULL
);
1062 gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(sw
),
1063 GTK_POLICY_AUTOMATIC
,
1064 GTK_POLICY_AUTOMATIC
);
1065 gtk_scrolled_window_set_shadow_type(GTK_SCROLLED_WINDOW(sw
),
1067 gtk_widget_show(sw
);
1069 /* Create the list store */
1071 store
= gtk_list_store_new(3, G_TYPE_POINTER
, G_TYPE_STRING
, GDK_TYPE_PIXBUF
);
1073 store
= gtk_list_store_new(2, G_TYPE_POINTER
, G_TYPE_STRING
);
1075 /* Create the tree view */
1076 treeview
= gtk_tree_view_new_with_model(GTK_TREE_MODEL(store
));
1077 g_object_unref(G_OBJECT(store
));
1078 gtk_tree_view_set_headers_visible(GTK_TREE_VIEW(treeview
), FALSE
);
1080 sel
= gtk_tree_view_get_selection(GTK_TREE_VIEW(treeview
));
1082 if (purple_request_field_list_get_multi_select(field
))
1083 gtk_tree_selection_set_mode(sel
, GTK_SELECTION_MULTIPLE
);
1085 column
= gtk_tree_view_column_new();
1086 gtk_tree_view_insert_column(GTK_TREE_VIEW(treeview
), column
, -1);
1088 renderer
= gtk_cell_renderer_text_new();
1089 gtk_tree_view_column_pack_start(column
, renderer
, TRUE
);
1090 gtk_tree_view_column_add_attribute(column
, renderer
, "text", 1);
1094 renderer
= gtk_cell_renderer_pixbuf_new();
1095 gtk_tree_view_column_pack_start(column
, renderer
, TRUE
);
1096 gtk_tree_view_column_add_attribute(column
, renderer
, "pixbuf", 2);
1098 gtk_widget_set_size_request(treeview
, 200, 400);
1101 for (l
= purple_request_field_list_get_items(field
); l
!= NULL
; l
= l
->next
)
1103 const char *text
= (const char *)l
->data
;
1105 gtk_list_store_append(store
, &iter
);
1109 const char *icon_path
= (const char *)icons
->data
;
1110 GdkPixbuf
* pixbuf
= NULL
;
1113 pixbuf
= gdk_pixbuf_new_from_file(icon_path
, NULL
);
1115 gtk_list_store_set(store
, &iter
,
1116 0, purple_request_field_list_get_data(field
, text
),
1120 icons
= icons
->next
;
1123 gtk_list_store_set(store
, &iter
,
1124 0, purple_request_field_list_get_data(field
, text
),
1128 if (purple_request_field_list_is_selected(field
, text
))
1129 gtk_tree_selection_select_iter(sel
, &iter
);
1133 * We only want to catch changes made by the user, so it's important
1134 * that we wait until after the list is created to connect this
1135 * handler. If we connect the handler before the loop above and
1136 * there are multiple items selected, then selecting the first iter
1137 * in the tree causes list_field_select_changed_cb to be triggered
1138 * which clears out the rest of the list of selected items.
1140 g_signal_connect(G_OBJECT(sel
), "changed",
1141 G_CALLBACK(list_field_select_changed_cb
), field
);
1143 gtk_container_add(GTK_CONTAINER(sw
), treeview
);
1144 gtk_widget_show(treeview
);
1150 pidgin_request_fields(const char *title
, const char *primary
,
1151 const char *secondary
, PurpleRequestFields
*fields
,
1152 const char *ok_text
, GCallback ok_cb
,
1153 const char *cancel_text
, GCallback cancel_cb
,
1154 PurpleAccount
*account
, const char *who
, PurpleConversation
*conv
,
1157 PidginRequestData
*data
;
1170 PurpleRequestFieldGroup
*group
;
1171 PurpleRequestField
*field
;
1173 char *primary_esc
, *secondary_esc
;
1174 int total_fields
= 0;
1176 data
= g_new0(PidginRequestData
, 1);
1177 data
->type
= PURPLE_REQUEST_FIELDS
;
1178 data
->user_data
= user_data
;
1179 data
->u
.multifield
.fields
= fields
;
1181 fields
->ui_data
= data
;
1184 data
->cbs
= g_new0(GCallback
, 2);
1186 data
->cbs
[0] = ok_cb
;
1187 data
->cbs
[1] = cancel_cb
;
1191 data
->dialog
= win
= pidgin_create_dialog(PIDGIN_ALERT_TITLE
, PIDGIN_HIG_BORDER
, "multifield", TRUE
) ;
1193 data
->dialog
= win
= pidgin_create_dialog(title
, PIDGIN_HIG_BORDER
, "multifield", TRUE
) ;
1196 g_signal_connect(G_OBJECT(win
), "delete_event",
1197 G_CALLBACK(destroy_multifield_cb
), data
);
1199 /* Setup the main horizontal box */
1200 hbox
= gtk_hbox_new(FALSE
, PIDGIN_HIG_BORDER
);
1201 gtk_container_add(GTK_CONTAINER(pidgin_dialog_get_vbox(GTK_DIALOG(win
))), hbox
);
1202 gtk_widget_show(hbox
);
1205 img
= gtk_image_new_from_stock(PIDGIN_STOCK_DIALOG_QUESTION
,
1206 gtk_icon_size_from_name(PIDGIN_ICON_SIZE_TANGO_HUGE
));
1207 gtk_misc_set_alignment(GTK_MISC(img
), 0, 0);
1208 gtk_box_pack_start(GTK_BOX(hbox
), img
, FALSE
, FALSE
, 0);
1209 gtk_widget_show(img
);
1212 button
= pidgin_dialog_add_button(GTK_DIALOG(win
), text_to_stock(cancel_text
), G_CALLBACK(multifield_cancel_cb
), data
);
1213 GTK_WIDGET_SET_FLAGS(button
, GTK_CAN_DEFAULT
);
1216 button
= pidgin_dialog_add_button(GTK_DIALOG(win
), text_to_stock(ok_text
), G_CALLBACK(multifield_ok_cb
), data
);
1217 data
->ok_button
= button
;
1218 GTK_WIDGET_SET_FLAGS(button
, GTK_CAN_DEFAULT
);
1219 gtk_window_set_default(GTK_WINDOW(win
), button
);
1221 pidgin_widget_decorate_account(hbox
, account
);
1223 /* Setup the vbox */
1224 vbox
= gtk_vbox_new(FALSE
, PIDGIN_HIG_BORDER
);
1225 gtk_box_pack_start(GTK_BOX(hbox
), vbox
, TRUE
, TRUE
, 0);
1226 gtk_widget_show(vbox
);
1228 sg
= gtk_size_group_new(GTK_SIZE_GROUP_HORIZONTAL
);
1231 primary_esc
= g_markup_escape_text(primary
, -1);
1232 label_text
= g_strdup_printf(
1233 "<span weight=\"bold\" size=\"larger\">%s</span>", primary_esc
);
1234 g_free(primary_esc
);
1235 label
= gtk_label_new(NULL
);
1237 gtk_label_set_markup(GTK_LABEL(label
), label_text
);
1238 gtk_label_set_line_wrap(GTK_LABEL(label
), TRUE
);
1239 gtk_misc_set_alignment(GTK_MISC(label
), 0, 0);
1240 gtk_box_pack_start(GTK_BOX(vbox
), label
, FALSE
, FALSE
, 0);
1241 gtk_widget_show(label
);
1245 for (gl
= purple_request_fields_get_groups(fields
); gl
!= NULL
;
1247 total_fields
+= g_list_length(purple_request_field_group_get_fields(gl
->data
));
1249 if(total_fields
> 9) {
1250 GtkWidget
*hbox_for_spacing
, *vbox_for_spacing
;
1252 sw
= gtk_scrolled_window_new(NULL
, NULL
);
1253 gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(sw
),
1254 GTK_POLICY_NEVER
, GTK_POLICY_AUTOMATIC
);
1255 gtk_scrolled_window_set_shadow_type(GTK_SCROLLED_WINDOW(sw
),
1257 gtk_widget_set_size_request(sw
, -1, 200);
1258 gtk_box_pack_start(GTK_BOX(vbox
), sw
, TRUE
, TRUE
, 0);
1259 gtk_widget_show(sw
);
1261 hbox_for_spacing
= gtk_hbox_new(FALSE
, PIDGIN_HIG_BORDER
);
1262 gtk_scrolled_window_add_with_viewport(GTK_SCROLLED_WINDOW(sw
),
1264 gtk_widget_show(hbox_for_spacing
);
1266 vbox_for_spacing
= gtk_vbox_new(FALSE
, PIDGIN_HIG_BORDER
);
1267 gtk_box_pack_start(GTK_BOX(hbox_for_spacing
),
1268 vbox_for_spacing
, TRUE
, TRUE
, PIDGIN_HIG_BOX_SPACE
);
1269 gtk_widget_show(vbox_for_spacing
);
1271 vbox2
= gtk_vbox_new(FALSE
, PIDGIN_HIG_BORDER
);
1272 gtk_box_pack_start(GTK_BOX(vbox_for_spacing
),
1273 vbox2
, TRUE
, TRUE
, PIDGIN_HIG_BOX_SPACE
);
1274 gtk_widget_show(vbox2
);
1280 secondary_esc
= g_markup_escape_text(secondary
, -1);
1281 label
= gtk_label_new(NULL
);
1283 gtk_label_set_markup(GTK_LABEL(label
), secondary_esc
);
1284 g_free(secondary_esc
);
1285 gtk_label_set_line_wrap(GTK_LABEL(label
), TRUE
);
1286 gtk_misc_set_alignment(GTK_MISC(label
), 0, 0);
1287 gtk_box_pack_start(GTK_BOX(vbox2
), label
, TRUE
, TRUE
, 0);
1288 gtk_widget_show(label
);
1291 for (gl
= purple_request_fields_get_groups(fields
);
1296 size_t field_count
= 0;
1303 field_list
= purple_request_field_group_get_fields(group
);
1305 if (purple_request_field_group_get_title(group
) != NULL
)
1307 frame
= pidgin_make_frame(vbox2
,
1308 purple_request_field_group_get_title(group
));
1313 field_count
= g_list_length(field_list
);
1315 if (field_count > 9)
1317 rows = field_count / 2;
1326 for (fl
= field_list
; fl
!= NULL
; fl
= fl
->next
)
1328 PurpleRequestFieldType type
;
1330 field
= (PurpleRequestField
*)fl
->data
;
1332 type
= purple_request_field_get_type(field
);
1334 if (type
== PURPLE_REQUEST_FIELD_LABEL
)
1341 else if ((type
== PURPLE_REQUEST_FIELD_LIST
) ||
1342 (type
== PURPLE_REQUEST_FIELD_STRING
&&
1343 purple_request_field_string_is_multiline(field
)))
1353 if (col_num
>= cols
)
1357 table
= gtk_table_new(rows
, 2 * cols
, FALSE
);
1358 gtk_table_set_row_spacings(GTK_TABLE(table
), PIDGIN_HIG_BOX_SPACE
);
1359 gtk_table_set_col_spacings(GTK_TABLE(table
), PIDGIN_HIG_BOX_SPACE
);
1361 gtk_container_add(GTK_CONTAINER(frame
), table
);
1362 gtk_widget_show(table
);
1364 for (row_num
= 0, fl
= field_list
;
1365 row_num
< rows
&& fl
!= NULL
;
1369 col_num
< cols
&& fl
!= NULL
;
1370 col_num
++, fl
= fl
->next
)
1372 size_t col_offset
= col_num
* 2;
1373 PurpleRequestFieldType type
;
1374 GtkWidget
*widget
= NULL
;
1375 const char *field_label
;
1380 if (!purple_request_field_is_visible(field
)) {
1385 type
= purple_request_field_get_type(field
);
1386 field_label
= purple_request_field_get_label(field
);
1388 if (type
!= PURPLE_REQUEST_FIELD_BOOLEAN
&& field_label
)
1392 if (field_label
[strlen(field_label
) - 1] != ':')
1393 text
= g_strdup_printf("%s:", field_label
);
1395 label
= gtk_label_new(NULL
);
1396 gtk_label_set_markup_with_mnemonic(GTK_LABEL(label
), text
? text
: field_label
);
1399 gtk_misc_set_alignment(GTK_MISC(label
), 0, 0.5);
1401 gtk_size_group_add_widget(sg
, label
);
1403 if (type
== PURPLE_REQUEST_FIELD_LABEL
||
1404 type
== PURPLE_REQUEST_FIELD_LIST
||
1405 (type
== PURPLE_REQUEST_FIELD_STRING
&&
1406 purple_request_field_string_is_multiline(field
)))
1411 gtk_table_attach_defaults(GTK_TABLE(table
), label
,
1413 row_num
, row_num
+ 1);
1420 gtk_table_attach_defaults(GTK_TABLE(table
), label
,
1421 col_offset
, col_offset
+ 1,
1422 row_num
, row_num
+ 1);
1425 gtk_widget_show(label
);
1428 widget
= GTK_WIDGET(purple_request_field_get_ui_data(field
));
1431 if (type
== PURPLE_REQUEST_FIELD_STRING
)
1432 widget
= create_string_field(field
);
1433 else if (type
== PURPLE_REQUEST_FIELD_INTEGER
)
1434 widget
= create_int_field(field
);
1435 else if (type
== PURPLE_REQUEST_FIELD_BOOLEAN
)
1436 widget
= create_bool_field(field
);
1437 else if (type
== PURPLE_REQUEST_FIELD_CHOICE
)
1438 widget
= create_choice_field(field
);
1439 else if (type
== PURPLE_REQUEST_FIELD_LIST
)
1440 widget
= create_list_field(field
);
1441 else if (type
== PURPLE_REQUEST_FIELD_IMAGE
)
1442 widget
= create_image_field(field
);
1443 else if (type
== PURPLE_REQUEST_FIELD_ACCOUNT
)
1444 widget
= create_account_field(field
);
1450 gtk_label_set_mnemonic_widget(GTK_LABEL(label
), widget
);
1452 if (type
== PURPLE_REQUEST_FIELD_STRING
&&
1453 purple_request_field_string_is_multiline(field
))
1455 gtk_table_attach(GTK_TABLE(table
), widget
,
1457 row_num
, row_num
+ 1,
1458 GTK_FILL
| GTK_EXPAND
,
1459 GTK_FILL
| GTK_EXPAND
,
1462 else if (type
== PURPLE_REQUEST_FIELD_LIST
)
1464 gtk_table_attach(GTK_TABLE(table
), widget
,
1466 row_num
, row_num
+ 1,
1467 GTK_FILL
| GTK_EXPAND
,
1468 GTK_FILL
| GTK_EXPAND
,
1471 else if (type
== PURPLE_REQUEST_FIELD_BOOLEAN
)
1473 gtk_table_attach(GTK_TABLE(table
), widget
,
1474 col_offset
, col_offset
+ 1,
1475 row_num
, row_num
+ 1,
1476 GTK_FILL
| GTK_EXPAND
,
1477 GTK_FILL
| GTK_EXPAND
,
1482 gtk_table_attach(GTK_TABLE(table
), widget
,
1484 row_num
, row_num
+ 1,
1485 GTK_FILL
| GTK_EXPAND
,
1486 GTK_FILL
| GTK_EXPAND
,
1490 gtk_widget_show(widget
);
1492 purple_request_field_set_ui_data(field
, widget
);
1499 if (!purple_request_fields_all_required_filled(fields
))
1500 gtk_widget_set_sensitive(data
->ok_button
, FALSE
);
1502 pidgin_auto_parent_window(win
);
1504 gtk_widget_show(win
);
1510 file_yes_no_cb(PidginRequestData
*data
, gint id
)
1512 /* Only call the callback if yes was selected, otherwise the request
1513 * (eg. file transfer) will be cancelled, then when a new filename is chosen
1516 if (data
->cbs
[1] != NULL
)
1517 ((PurpleRequestFileCb
)data
->cbs
[1])(data
->user_data
, data
->u
.file
.name
);
1518 purple_request_close(data
->type
, data
);
1520 pidgin_clear_cursor(GTK_WIDGET(data
->dialog
));
1525 file_ok_check_if_exists_cb(GtkWidget
*widget
, gint response
, PidginRequestData
*data
)
1527 gchar
*current_folder
;
1529 generic_response_start(data
);
1531 if (response
!= GTK_RESPONSE_ACCEPT
) {
1532 if (data
->cbs
[0] != NULL
)
1533 ((PurpleRequestFileCb
)data
->cbs
[0])(data
->user_data
, NULL
);
1534 purple_request_close(data
->type
, data
);
1538 data
->u
.file
.name
= gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(data
->dialog
));
1539 current_folder
= gtk_file_chooser_get_current_folder(GTK_FILE_CHOOSER(data
->dialog
));
1540 if (current_folder
!= NULL
) {
1541 if (data
->u
.file
.savedialog
) {
1542 purple_prefs_set_path(PIDGIN_PREFS_ROOT
"/filelocations/last_save_folder", current_folder
);
1544 purple_prefs_set_path(PIDGIN_PREFS_ROOT
"/filelocations/last_open_folder", current_folder
);
1546 g_free(current_folder
);
1548 if ((data
->u
.file
.savedialog
== TRUE
) &&
1549 (g_file_test(data
->u
.file
.name
, G_FILE_TEST_EXISTS
))) {
1550 purple_request_action(data
, NULL
, _("That file already exists"),
1551 _("Would you like to overwrite it?"), 0,
1554 _("Overwrite"), G_CALLBACK(file_yes_no_cb
),
1555 _("Choose New Name"), G_CALLBACK(file_yes_no_cb
));
1557 file_yes_no_cb(data
, 1);
1561 pidgin_request_file(const char *title
, const char *filename
,
1562 gboolean savedialog
,
1563 GCallback ok_cb
, GCallback cancel_cb
,
1564 PurpleAccount
*account
, const char *who
, PurpleConversation
*conv
,
1567 PidginRequestData
*data
;
1569 const gchar
*current_folder
;
1570 gboolean folder_set
= FALSE
;
1572 data
= g_new0(PidginRequestData
, 1);
1573 data
->type
= PURPLE_REQUEST_FILE
;
1574 data
->user_data
= user_data
;
1576 data
->cbs
= g_new0(GCallback
, 2);
1577 data
->cbs
[0] = cancel_cb
;
1578 data
->cbs
[1] = ok_cb
;
1579 data
->u
.file
.savedialog
= savedialog
;
1581 filesel
= gtk_file_chooser_dialog_new(
1582 title
? title
: (savedialog
? _("Save File...")
1583 : _("Open File...")),
1585 savedialog
? GTK_FILE_CHOOSER_ACTION_SAVE
1586 : GTK_FILE_CHOOSER_ACTION_OPEN
,
1587 GTK_STOCK_CANCEL
, GTK_RESPONSE_CANCEL
,
1588 savedialog
? GTK_STOCK_SAVE
1590 GTK_RESPONSE_ACCEPT
,
1592 gtk_dialog_set_default_response(GTK_DIALOG(filesel
), GTK_RESPONSE_ACCEPT
);
1595 current_folder
= purple_prefs_get_path(PIDGIN_PREFS_ROOT
"/filelocations/last_save_folder");
1597 current_folder
= purple_prefs_get_path(PIDGIN_PREFS_ROOT
"/filelocations/last_open_folder");
1600 if ((filename
!= NULL
) && (*filename
!= '\0')) {
1602 gtk_file_chooser_set_current_name(GTK_FILE_CHOOSER(filesel
), filename
);
1603 else if (g_file_test(filename
, G_FILE_TEST_EXISTS
))
1604 gtk_file_chooser_set_filename(GTK_FILE_CHOOSER(filesel
), filename
);
1606 if ((filename
== NULL
|| *filename
== '\0' || !g_file_test(filename
, G_FILE_TEST_EXISTS
)) &&
1607 (current_folder
!= NULL
) && (*current_folder
!= '\0')) {
1608 folder_set
= gtk_file_chooser_set_current_folder(GTK_FILE_CHOOSER(filesel
), current_folder
);
1612 if (!folder_set
&& (filename
== NULL
|| *filename
== '\0' || !g_file_test(filename
, G_FILE_TEST_EXISTS
))) {
1613 char *my_documents
= wpurple_get_special_folder(CSIDL_PERSONAL
);
1615 if (my_documents
!= NULL
) {
1616 gtk_file_chooser_set_current_folder(
1617 GTK_FILE_CHOOSER(filesel
), my_documents
);
1619 g_free(my_documents
);
1624 g_signal_connect(G_OBJECT(GTK_FILE_CHOOSER(filesel
)), "response",
1625 G_CALLBACK(file_ok_check_if_exists_cb
), data
);
1627 pidgin_auto_parent_window(filesel
);
1629 data
->dialog
= filesel
;
1630 gtk_widget_show(filesel
);
1632 return (void *)data
;
1636 pidgin_request_folder(const char *title
, const char *dirname
,
1637 GCallback ok_cb
, GCallback cancel_cb
,
1638 PurpleAccount
*account
, const char *who
, PurpleConversation
*conv
,
1641 PidginRequestData
*data
;
1644 data
= g_new0(PidginRequestData
, 1);
1645 data
->type
= PURPLE_REQUEST_FOLDER
;
1646 data
->user_data
= user_data
;
1648 data
->cbs
= g_new0(GCallback
, 2);
1649 data
->cbs
[0] = cancel_cb
;
1650 data
->cbs
[1] = ok_cb
;
1651 data
->u
.file
.savedialog
= FALSE
;
1653 dirsel
= gtk_file_chooser_dialog_new(
1654 title
? title
: _("Select Folder..."),
1656 GTK_FILE_CHOOSER_ACTION_SELECT_FOLDER
,
1657 GTK_STOCK_CANCEL
, GTK_RESPONSE_CANCEL
,
1658 GTK_STOCK_OK
, GTK_RESPONSE_ACCEPT
,
1660 gtk_dialog_set_default_response(GTK_DIALOG(dirsel
), GTK_RESPONSE_ACCEPT
);
1662 if ((dirname
!= NULL
) && (*dirname
!= '\0'))
1663 gtk_file_chooser_set_current_folder(GTK_FILE_CHOOSER(dirsel
), dirname
);
1665 g_signal_connect(G_OBJECT(GTK_FILE_CHOOSER(dirsel
)), "response",
1666 G_CALLBACK(file_ok_check_if_exists_cb
), data
);
1668 data
->dialog
= dirsel
;
1669 pidgin_auto_parent_window(dirsel
);
1671 gtk_widget_show(dirsel
);
1673 return (void *)data
;
1677 pidgin_close_request(PurpleRequestType type
, void *ui_handle
)
1679 PidginRequestData
*data
= (PidginRequestData
*)ui_handle
;
1683 gtk_widget_destroy(data
->dialog
);
1685 if (type
== PURPLE_REQUEST_FIELDS
)
1686 purple_request_fields_destroy(data
->u
.multifield
.fields
);
1687 else if (type
== PURPLE_REQUEST_FILE
)
1688 g_free(data
->u
.file
.name
);
1693 static PurpleRequestUiOps ops
=
1695 pidgin_request_input
,
1696 pidgin_request_choice
,
1697 pidgin_request_action
,
1698 pidgin_request_fields
,
1699 pidgin_request_file
,
1700 pidgin_close_request
,
1701 pidgin_request_folder
,
1708 PurpleRequestUiOps
*
1709 pidgin_request_get_ui_ops(void)