3 * Pidgin is the legal property of its developers, whose names are too numerous
4 * to list here. Please refer to the COPYRIGHT file distributed with this
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2 of the License, or
10 * (at your option) any later version.
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111-1301 USA
23 #include "glibcompat.h"
34 #include "savedstatuses.h"
36 #include "sound-theme.h"
38 #include "theme-manager.h"
46 #include "gtkconv-theme.h"
48 #include "gtkdialogs.h"
50 #include "gtksavedstatuses.h"
51 #include "gtksmiley-theme.h"
53 #include "gtkstatus-icon-theme.h"
55 #include "gtkwebview.h"
56 #include "pidginstock.h"
58 #include "media-gst.h"
59 #include <gst/video/videooverlay.h>
60 #ifdef GDK_WINDOWING_WIN32
61 #include <gdk/gdkwin32.h>
63 #ifdef GDK_WINDOWING_X11
66 #ifdef GDK_WINDOWING_QUARTZ
67 #include <gdk/gdkquartz.h>
71 #include "gtk3compat.h"
78 #define PREFS_OPTIMAL_ICON_SIZE 32
81 #define PREFS_MAX_DOWNLOADED_THEME_SIZE 26214400
90 static GtkWidget
*prefs
= NULL
;
93 static GtkWidget
*prefsnotebook
= NULL
;
94 static int notebook_page
= 0;
96 /* Conversations page */
97 static GtkWidget
*sample_webview
= NULL
;
100 static GtkWidget
*prefs_sound_themes_combo_box
;
101 static GtkWidget
*prefs_blist_themes_combo_box
;
102 static GtkWidget
*prefs_conv_themes_combo_box
;
103 static GtkWidget
*prefs_conv_variants_combo_box
;
104 static GtkWidget
*prefs_status_themes_combo_box
;
105 static GtkWidget
*prefs_smiley_themes_combo_box
;
106 static PurpleHttpConnection
*prefs_conv_themes_running_request
= NULL
;
109 static GtkWidget
*keyring_page_instance
= NULL
;
110 static GtkComboBox
*keyring_combo
= NULL
;
111 static GtkBox
*keyring_vbox
= NULL
;
112 static PurpleRequestFields
*keyring_settings
= NULL
;
113 static GList
*keyring_settings_fields
= NULL
;
114 static GtkWidget
*keyring_apply
= NULL
;
116 /* Sound theme specific */
117 static GtkWidget
*sound_entry
= NULL
;
118 static int sound_row_sel
= 0;
119 static gboolean prefs_sound_themes_loading
;
121 /* These exist outside the lifetime of the prefs dialog */
122 static GtkListStore
*prefs_sound_themes
;
123 static GtkListStore
*prefs_blist_themes
;
124 static GtkListStore
*prefs_conv_themes
;
125 static GtkListStore
*prefs_conv_variants
;
126 static GtkListStore
*prefs_status_icon_themes
;
127 static GtkListStore
*prefs_smiley_themes
;
131 static GtkWidget
*voice_level
;
132 static GtkWidget
*voice_threshold
;
133 static GtkWidget
*voice_volume
;
134 static GstElement
*voice_pipeline
;
136 static GtkWidget
*video_drawing_area
;
137 static GstElement
*video_pipeline
;
144 static void delete_prefs(GtkWidget
*, void *);
147 update_spin_value(GtkWidget
*w
, GtkWidget
*spin
)
149 const char *key
= g_object_get_data(G_OBJECT(spin
), "val");
152 value
= gtk_spin_button_get_value_as_int(GTK_SPIN_BUTTON(spin
));
154 purple_prefs_set_int(key
, value
);
158 pidgin_prefs_labeled_spin_button(GtkWidget
*box
, const gchar
*title
,
159 const char *key
, int min
, int max
, GtkSizeGroup
*sg
)
162 GtkAdjustment
*adjust
;
165 val
= purple_prefs_get_int(key
);
167 adjust
= GTK_ADJUSTMENT(gtk_adjustment_new(val
, min
, max
, 1, 1, 0));
168 spin
= gtk_spin_button_new(adjust
, 1, 0);
169 g_object_set_data(G_OBJECT(spin
), "val", (char *)key
);
171 gtk_widget_set_size_request(spin
, 50, -1);
173 gtk_widget_set_size_request(spin
, 60, -1);
174 g_signal_connect(G_OBJECT(adjust
), "value-changed",
175 G_CALLBACK(update_spin_value
), GTK_WIDGET(spin
));
176 gtk_widget_show(spin
);
178 return pidgin_add_widget_to_vbox(GTK_BOX(box
), title
, sg
, spin
, FALSE
, NULL
);
182 entry_set(GtkEntry
*entry
, gpointer data
)
184 const char *key
= (const char*)data
;
186 purple_prefs_set_string(key
, gtk_entry_get_text(entry
));
190 pidgin_prefs_labeled_entry(GtkWidget
*page
, const gchar
*title
,
191 const char *key
, GtkSizeGroup
*sg
)
196 value
= purple_prefs_get_string(key
);
198 entry
= gtk_entry_new();
199 gtk_entry_set_text(GTK_ENTRY(entry
), value
);
200 g_signal_connect(G_OBJECT(entry
), "changed",
201 G_CALLBACK(entry_set
), (char*)key
);
202 gtk_widget_show(entry
);
204 return pidgin_add_widget_to_vbox(GTK_BOX(page
), title
, sg
, entry
, TRUE
, NULL
);
208 pidgin_prefs_labeled_password(GtkWidget
*page
, const gchar
*title
,
209 const char *key
, GtkSizeGroup
*sg
)
214 value
= purple_prefs_get_string(key
);
216 entry
= gtk_entry_new();
217 gtk_entry_set_visibility(GTK_ENTRY(entry
), FALSE
);
218 gtk_entry_set_text(GTK_ENTRY(entry
), value
);
219 g_signal_connect(G_OBJECT(entry
), "changed",
220 G_CALLBACK(entry_set
), (char*)key
);
221 gtk_widget_show(entry
);
223 return pidgin_add_widget_to_vbox(GTK_BOX(page
), title
, sg
, entry
, TRUE
, NULL
);
226 /* TODO: Maybe move this up somewheres... */
243 typedef void (*PidginPrefsDropdownCallback
)(GtkComboBox
*combo_box
,
244 PidginPrefValue value
);
247 dropdown_set(GtkComboBox
*combo_box
, gpointer _cb
)
249 PidginPrefsDropdownCallback cb
= _cb
;
251 GtkTreeModel
*tree_model
;
252 PidginPrefValue active
;
254 tree_model
= gtk_combo_box_get_model(combo_box
);
255 if (!gtk_combo_box_get_active_iter(combo_box
, &iter
))
257 active
.type
= GPOINTER_TO_INT(g_object_get_data(G_OBJECT(combo_box
),
260 g_object_set_data(G_OBJECT(combo_box
), "previously_active",
261 g_object_get_data(G_OBJECT(combo_box
), "current_active"));
262 g_object_set_data(G_OBJECT(combo_box
), "current_active",
263 GINT_TO_POINTER(gtk_combo_box_get_active(combo_box
)));
265 if (active
.type
== PURPLE_PREF_INT
) {
266 gtk_tree_model_get(tree_model
, &iter
, PREF_DROPDOWN_VALUE
,
267 &active
.value
.integer
, -1);
269 else if (active
.type
== PURPLE_PREF_STRING
) {
270 gtk_tree_model_get(tree_model
, &iter
, PREF_DROPDOWN_VALUE
,
271 &active
.value
.string
, -1);
273 else if (active
.type
== PURPLE_PREF_BOOLEAN
) {
274 gtk_tree_model_get(tree_model
, &iter
, PREF_DROPDOWN_VALUE
,
275 &active
.value
.boolean
, -1);
278 cb(combo_box
, active
);
281 static void pidgin_prefs_dropdown_revert_active(GtkComboBox
*combo_box
)
283 gint previously_active
;
285 g_return_if_fail(combo_box
!= NULL
);
287 previously_active
= GPOINTER_TO_INT(g_object_get_data(
288 G_OBJECT(combo_box
), "previously_active"));
289 g_object_set_data(G_OBJECT(combo_box
), "current_active",
290 GINT_TO_POINTER(previously_active
));
292 gtk_combo_box_set_active(combo_box
, previously_active
);
296 pidgin_prefs_dropdown_from_list_with_cb(GtkWidget
*box
, const gchar
*title
,
297 GtkComboBox
**dropdown_out
, GList
*menuitems
,
298 PidginPrefValue initial
, PidginPrefsDropdownCallback cb
)
301 GtkWidget
*label
= NULL
;
303 GtkListStore
*store
= NULL
;
306 GtkCellRenderer
*renderer
;
307 gpointer current_active
;
309 g_return_val_if_fail(menuitems
!= NULL
, NULL
);
311 if (initial
.type
== PURPLE_PREF_INT
) {
312 store
= gtk_list_store_new(PREF_DROPDOWN_COUNT
, G_TYPE_STRING
, G_TYPE_INT
);
313 } else if (initial
.type
== PURPLE_PREF_STRING
) {
314 store
= gtk_list_store_new(PREF_DROPDOWN_COUNT
, G_TYPE_STRING
, G_TYPE_STRING
);
315 } else if (initial
.type
== PURPLE_PREF_BOOLEAN
) {
316 store
= gtk_list_store_new(PREF_DROPDOWN_COUNT
, G_TYPE_STRING
, G_TYPE_BOOLEAN
);
322 dropdown
= gtk_combo_box_new_with_model(GTK_TREE_MODEL(store
));
323 if (dropdown_out
!= NULL
)
324 *dropdown_out
= GTK_COMBO_BOX(dropdown
);
325 g_object_set_data(G_OBJECT(dropdown
), "type", GINT_TO_POINTER(initial
.type
));
327 while (menuitems
!= NULL
&& (text
= (char *)menuitems
->data
) != NULL
) {
329 const char *str_value
= NULL
;
330 gboolean bool_value
= FALSE
;
332 menuitems
= g_list_next(menuitems
);
333 g_return_val_if_fail(menuitems
!= NULL
, NULL
);
335 gtk_list_store_append(store
, &iter
);
336 gtk_list_store_set(store
, &iter
,
337 PREF_DROPDOWN_TEXT
, text
,
340 if (initial
.type
== PURPLE_PREF_INT
) {
341 int_value
= GPOINTER_TO_INT(menuitems
->data
);
342 gtk_list_store_set(store
, &iter
,
343 PREF_DROPDOWN_VALUE
, int_value
,
346 else if (initial
.type
== PURPLE_PREF_STRING
) {
347 str_value
= (const char *)menuitems
->data
;
348 gtk_list_store_set(store
, &iter
,
349 PREF_DROPDOWN_VALUE
, str_value
,
352 else if (initial
.type
== PURPLE_PREF_BOOLEAN
) {
353 bool_value
= (gboolean
)GPOINTER_TO_INT(menuitems
->data
);
354 gtk_list_store_set(store
, &iter
,
355 PREF_DROPDOWN_VALUE
, bool_value
,
359 if ((initial
.type
== PURPLE_PREF_INT
&&
360 initial
.value
.integer
== int_value
) ||
361 (initial
.type
== PURPLE_PREF_STRING
&&
362 !g_strcmp0(initial
.value
.string
, str_value
)) ||
363 (initial
.type
== PURPLE_PREF_BOOLEAN
&&
364 (initial
.value
.boolean
== bool_value
))) {
369 menuitems
= g_list_next(menuitems
);
372 renderer
= gtk_cell_renderer_text_new();
373 gtk_cell_layout_pack_start(GTK_CELL_LAYOUT(dropdown
), renderer
, TRUE
);
374 gtk_cell_layout_set_attributes(GTK_CELL_LAYOUT(dropdown
), renderer
,
378 gtk_combo_box_set_active_iter(GTK_COMBO_BOX(dropdown
), &active
);
379 current_active
= GINT_TO_POINTER(gtk_combo_box_get_active(GTK_COMBO_BOX(
381 g_object_set_data(G_OBJECT(dropdown
), "current_active", current_active
);
382 g_object_set_data(G_OBJECT(dropdown
), "previously_active", current_active
);
384 g_signal_connect(G_OBJECT(dropdown
), "changed",
385 G_CALLBACK(dropdown_set
), cb
);
387 pidgin_add_widget_to_vbox(GTK_BOX(box
), title
, NULL
, dropdown
, FALSE
, &label
);
393 pidgin_prefs_dropdown_from_list_cb(GtkComboBox
*combo_box
,
394 PidginPrefValue value
)
398 key
= g_object_get_data(G_OBJECT(combo_box
), "key");
400 if (value
.type
== PURPLE_PREF_INT
) {
401 purple_prefs_set_int(key
, value
.value
.integer
);
402 } else if (value
.type
== PURPLE_PREF_STRING
) {
403 purple_prefs_set_string(key
, value
.value
.string
);
404 } else if (value
.type
== PURPLE_PREF_BOOLEAN
) {
405 purple_prefs_set_bool(key
, value
.value
.boolean
);
407 g_return_if_reached();
412 pidgin_prefs_dropdown_from_list(GtkWidget
*box
, const gchar
*title
,
413 PurplePrefType type
, const char *key
, GList
*menuitems
)
415 PidginPrefValue initial
;
416 GtkComboBox
*dropdown
= NULL
;
420 if (type
== PURPLE_PREF_INT
) {
421 initial
.value
.integer
= purple_prefs_get_int(key
);
422 } else if (type
== PURPLE_PREF_STRING
) {
423 initial
.value
.string
= purple_prefs_get_string(key
);
424 } else if (type
== PURPLE_PREF_BOOLEAN
) {
425 initial
.value
.boolean
= purple_prefs_get_bool(key
);
427 g_return_val_if_reached(NULL
);
430 label
= pidgin_prefs_dropdown_from_list_with_cb(box
, title
, &dropdown
,
431 menuitems
, initial
, pidgin_prefs_dropdown_from_list_cb
);
433 g_object_set_data(G_OBJECT(dropdown
), "key", (gpointer
)key
);
439 pidgin_prefs_dropdown(GtkWidget
*box
, const gchar
*title
, PurplePrefType type
,
440 const char *key
, ...)
443 GList
*menuitems
= NULL
;
444 GtkWidget
*dropdown
= NULL
;
447 const char *str_value
;
449 g_return_val_if_fail(type
== PURPLE_PREF_BOOLEAN
|| type
== PURPLE_PREF_INT
||
450 type
== PURPLE_PREF_STRING
, NULL
);
453 while ((name
= va_arg(ap
, char *)) != NULL
) {
455 menuitems
= g_list_prepend(menuitems
, name
);
457 if (type
== PURPLE_PREF_INT
|| type
== PURPLE_PREF_BOOLEAN
) {
458 int_value
= va_arg(ap
, int);
459 menuitems
= g_list_prepend(menuitems
, GINT_TO_POINTER(int_value
));
462 str_value
= va_arg(ap
, const char *);
463 menuitems
= g_list_prepend(menuitems
, (char *)str_value
);
468 g_return_val_if_fail(menuitems
!= NULL
, NULL
);
470 menuitems
= g_list_reverse(menuitems
);
472 dropdown
= pidgin_prefs_dropdown_from_list(box
, title
, type
, key
,
475 g_list_free(menuitems
);
480 static void keyring_page_cleanup(void);
483 delete_prefs(GtkWidget
*asdf
, void *gdsa
)
485 /* Cancel HTTP requests */
486 purple_http_conn_cancel(prefs_conv_themes_running_request
);
487 prefs_conv_themes_running_request
= NULL
;
489 /* Close any "select sound" request dialogs */
490 purple_request_close_with_handle(prefs
);
492 purple_notify_close_with_handle(prefs
);
494 /* Unregister callbacks. */
495 purple_prefs_disconnect_by_handle(prefs
);
497 /* NULL-ify globals */
500 prefs_sound_themes_loading
= FALSE
;
502 prefs_sound_themes_combo_box
= NULL
;
503 prefs_blist_themes_combo_box
= NULL
;
504 prefs_conv_themes_combo_box
= NULL
;
505 prefs_conv_variants_combo_box
= NULL
;
506 prefs_status_themes_combo_box
= NULL
;
507 prefs_smiley_themes_combo_box
= NULL
;
509 keyring_page_cleanup();
511 sample_webview
= NULL
;
515 voice_threshold
= NULL
;
517 video_drawing_area
= NULL
;
521 prefsnotebook
= NULL
;
526 get_theme_markup(const char *name
, gboolean custom
, const char *author
,
527 const char *description
)
530 return g_strdup_printf("<b>%s</b>%s%s%s%s\n<span foreground='dim grey'>%s</span>",
531 name
, custom
? " " : "", custom
? _("(Custom)") : "",
532 author
!= NULL
? " - " : "", author
!= NULL
? author
: "",
533 description
!= NULL
? description
: "");
537 smileys_refresh_theme_list(void)
543 description
= get_theme_markup(_("none"), FALSE
, _("Penguin Pimps"),
544 _("Selecting this disables graphical emoticons."));
545 gtk_list_store_append(prefs_smiley_themes
, &iter
);
546 gtk_list_store_set(prefs_smiley_themes
, &iter
,
547 0, NULL
, 1, description
, 2, "none", -1);
550 for (it
= pidgin_smiley_theme_get_all(); it
; it
= g_list_next(it
)) {
551 PidginSmileyTheme
*theme
= it
->data
;
553 description
= get_theme_markup(
554 _(pidgin_smiley_theme_get_name(theme
)), FALSE
,
555 _(pidgin_smiley_theme_get_author(theme
)),
556 _(pidgin_smiley_theme_get_description(theme
)));
558 gtk_list_store_append(prefs_smiley_themes
, &iter
);
559 gtk_list_store_set(prefs_smiley_themes
, &iter
,
560 0, pidgin_smiley_theme_get_icon(theme
),
562 2, pidgin_smiley_theme_get_name(theme
),
569 /* Rebuild the markup for the sound theme selection for "(Custom)" themes */
571 pref_sound_generate_markup(void)
573 gboolean print_custom
, customized
;
574 const gchar
*author
, *description
, *current_theme
;
575 gchar
*name
, *markup
;
576 PurpleSoundTheme
*theme
;
579 customized
= pidgin_sound_is_customized();
580 current_theme
= purple_prefs_get_string(PIDGIN_PREFS_ROOT
"/sound/theme");
582 if (gtk_tree_model_get_iter_first(GTK_TREE_MODEL(prefs_sound_themes
), &iter
)) {
584 gtk_tree_model_get(GTK_TREE_MODEL(prefs_sound_themes
), &iter
, 2, &name
, -1);
586 print_custom
= customized
&& name
&& g_str_equal(current_theme
, name
);
588 if (!name
|| *name
== '\0') {
590 name
= g_strdup(_("Default"));
591 author
= _("Penguin Pimps");
592 description
= _("The default Pidgin sound theme");
594 theme
= PURPLE_SOUND_THEME(purple_theme_manager_find_theme(name
, "sound"));
595 author
= purple_theme_get_author(PURPLE_THEME(theme
));
596 description
= purple_theme_get_description(PURPLE_THEME(theme
));
599 markup
= get_theme_markup(name
, print_custom
, author
, description
);
601 gtk_list_store_set(prefs_sound_themes
, &iter
, 1, markup
, -1);
606 } while (gtk_tree_model_iter_next(GTK_TREE_MODEL(prefs_sound_themes
), &iter
));
610 /* adds the themes to the theme list from the manager so they can be displayed in prefs */
612 prefs_themes_sort(PurpleTheme
*theme
)
614 GdkPixbuf
*pixbuf
= NULL
;
616 gchar
*image_full
= NULL
, *markup
;
617 const gchar
*name
, *author
, *description
;
619 if (PURPLE_IS_SOUND_THEME(theme
)){
621 image_full
= purple_theme_get_image_full(theme
);
622 if (image_full
!= NULL
){
623 pixbuf
= pidgin_pixbuf_new_from_file_at_scale(image_full
, PREFS_OPTIMAL_ICON_SIZE
, PREFS_OPTIMAL_ICON_SIZE
, TRUE
);
628 gtk_list_store_append(prefs_sound_themes
, &iter
);
629 gtk_list_store_set(prefs_sound_themes
, &iter
, 0, pixbuf
, 2, purple_theme_get_name(theme
), -1);
632 g_object_unref(G_OBJECT(pixbuf
));
634 } else if (PIDGIN_IS_BLIST_THEME(theme
) || PIDGIN_IS_STATUS_ICON_THEME(theme
)){
637 if (PIDGIN_IS_BLIST_THEME(theme
))
638 store
= prefs_blist_themes
;
640 store
= prefs_status_icon_themes
;
642 image_full
= purple_theme_get_image_full(theme
);
643 if (image_full
!= NULL
){
644 pixbuf
= pidgin_pixbuf_new_from_file_at_scale(image_full
, PREFS_OPTIMAL_ICON_SIZE
, PREFS_OPTIMAL_ICON_SIZE
, TRUE
);
649 name
= purple_theme_get_name(theme
);
650 author
= purple_theme_get_author(theme
);
651 description
= purple_theme_get_description(theme
);
653 markup
= get_theme_markup(name
, FALSE
, author
, description
);
655 gtk_list_store_append(store
, &iter
);
656 gtk_list_store_set(store
, &iter
, 0, pixbuf
, 1, markup
, 2, name
, -1);
660 g_object_unref(G_OBJECT(pixbuf
));
662 } else if (PIDGIN_IS_CONV_THEME(theme
)) {
663 /* No image available? */
665 name
= purple_theme_get_name(theme
);
666 /* No author available */
667 /* No description available */
669 markup
= get_theme_markup(name
, FALSE
, NULL
, NULL
);
671 gtk_list_store_append(prefs_conv_themes
, &iter
);
672 gtk_list_store_set(prefs_conv_themes
, &iter
, 1, markup
, 2, name
, -1);
677 prefs_set_active_theme_combo(GtkWidget
*combo_box
, GtkListStore
*store
, const gchar
*current_theme
)
681 gboolean unset
= TRUE
;
683 if (current_theme
&& *current_theme
&& gtk_tree_model_get_iter_first(GTK_TREE_MODEL(store
), &iter
)) {
685 gtk_tree_model_get(GTK_TREE_MODEL(store
), &iter
, 2, &theme
, -1);
687 if (g_str_equal(current_theme
, theme
)) {
688 gtk_combo_box_set_active_iter(GTK_COMBO_BOX(combo_box
), &iter
);
693 } while (gtk_tree_model_iter_next(GTK_TREE_MODEL(store
), &iter
));
697 gtk_combo_box_set_active(GTK_COMBO_BOX(combo_box
), 0);
701 prefs_themes_refresh(void)
703 GdkPixbuf
*pixbuf
= NULL
;
707 prefs_sound_themes_loading
= TRUE
;
708 /* refresh the list of themes in the manager */
709 purple_theme_manager_refresh();
711 tmp
= g_build_filename(PURPLE_DATADIR
, "icons", "hicolor", "32x32",
712 "apps", "pidgin.png", NULL
);
713 pixbuf
= pidgin_pixbuf_new_from_file_at_scale(tmp
, PREFS_OPTIMAL_ICON_SIZE
, PREFS_OPTIMAL_ICON_SIZE
, TRUE
);
717 gtk_list_store_clear(prefs_sound_themes
);
718 gtk_list_store_append(prefs_sound_themes
, &iter
);
719 gtk_list_store_set(prefs_sound_themes
, &iter
, 0, pixbuf
, 2, "", -1);
722 gtk_list_store_clear(prefs_blist_themes
);
723 gtk_list_store_append(prefs_blist_themes
, &iter
);
724 tmp
= get_theme_markup(_("Default"), FALSE
, _("Penguin Pimps"),
725 _("The default Pidgin buddy list theme"));
726 gtk_list_store_set(prefs_blist_themes
, &iter
, 0, pixbuf
, 1, tmp
, 2, "", -1);
729 /* conversation themes */
730 gtk_list_store_clear(prefs_conv_themes
);
731 gtk_list_store_append(prefs_conv_themes
, &iter
);
732 tmp
= get_theme_markup(_("Default"), FALSE
, _("Penguin Pimps"),
733 _("The default Pidgin conversation theme"));
734 gtk_list_store_set(prefs_conv_themes
, &iter
, 0, pixbuf
, 1, tmp
, 2, "", -1);
737 /* conversation theme variants */
738 gtk_list_store_clear(prefs_conv_variants
);
740 /* status icon themes */
741 gtk_list_store_clear(prefs_status_icon_themes
);
742 gtk_list_store_append(prefs_status_icon_themes
, &iter
);
743 tmp
= get_theme_markup(_("Default"), FALSE
, _("Penguin Pimps"),
744 _("The default Pidgin status icon theme"));
745 gtk_list_store_set(prefs_status_icon_themes
, &iter
, 0, pixbuf
, 1, tmp
, 2, "", -1);
748 g_object_unref(G_OBJECT(pixbuf
));
751 gtk_list_store_clear(prefs_smiley_themes
);
753 purple_theme_manager_for_each_theme(prefs_themes_sort
);
754 pref_sound_generate_markup();
755 smileys_refresh_theme_list();
758 prefs_set_active_theme_combo(prefs_sound_themes_combo_box
, prefs_sound_themes
, purple_prefs_get_string(PIDGIN_PREFS_ROOT
"/sound/theme"));
759 prefs_set_active_theme_combo(prefs_blist_themes_combo_box
, prefs_blist_themes
, purple_prefs_get_string(PIDGIN_PREFS_ROOT
"/blist/theme"));
760 prefs_set_active_theme_combo(prefs_conv_themes_combo_box
, prefs_conv_themes
, purple_prefs_get_string(PIDGIN_PREFS_ROOT
"/conversations/theme"));
761 prefs_set_active_theme_combo(prefs_status_themes_combo_box
, prefs_status_icon_themes
, purple_prefs_get_string(PIDGIN_PREFS_ROOT
"/status/icon-theme"));
762 prefs_set_active_theme_combo(prefs_smiley_themes_combo_box
, prefs_smiley_themes
, purple_prefs_get_string(PIDGIN_PREFS_ROOT
"/smileys/theme"));
763 prefs_sound_themes_loading
= FALSE
;
766 /* init all the theme variables so that the themes can be sorted later and used by pref pages */
768 prefs_themes_init(void)
770 prefs_sound_themes
= gtk_list_store_new(3, GDK_TYPE_PIXBUF
, G_TYPE_STRING
, G_TYPE_STRING
);
772 prefs_blist_themes
= gtk_list_store_new(3, GDK_TYPE_PIXBUF
, G_TYPE_STRING
, G_TYPE_STRING
);
774 prefs_conv_themes
= gtk_list_store_new(3, GDK_TYPE_PIXBUF
, G_TYPE_STRING
, G_TYPE_STRING
);
776 prefs_conv_variants
= gtk_list_store_new(1, G_TYPE_STRING
);
778 prefs_status_icon_themes
= gtk_list_store_new(3, GDK_TYPE_PIXBUF
, G_TYPE_STRING
, G_TYPE_STRING
);
780 prefs_smiley_themes
= gtk_list_store_new(3, GDK_TYPE_PIXBUF
, G_TYPE_STRING
, G_TYPE_STRING
);
784 * prefs_theme_find_theme:
785 * @path: A directory containing a theme. The theme could be at the
786 * top level of this directory or in any subdirectory thereof.
787 * @type: The type of theme to load. The loader for this theme type
788 * will be used and this loader will determine what constitutes a
791 * Attempt to load the given directory as a theme. If we are unable to
792 * open the path as a theme then we recurse into path and attempt to
793 * load each subdirectory that we encounter.
795 * Returns: A new reference to a #PurpleTheme.
798 prefs_theme_find_theme(const gchar
*path
, const gchar
*type
)
800 PurpleTheme
*theme
= purple_theme_manager_load_theme(path
, type
);
801 GDir
*dir
= g_dir_open(path
, 0, NULL
);
804 while (!PURPLE_IS_THEME(theme
) && (next
= g_dir_read_name(dir
))) {
805 gchar
*next_path
= g_build_filename(path
, next
, NULL
);
807 if (g_file_test(next_path
, G_FILE_TEST_IS_DIR
))
808 theme
= prefs_theme_find_theme(next_path
, type
);
818 /* Eww. Seriously ewww. But thanks, grim! This is taken from guifications2 */
820 purple_theme_file_copy(const gchar
*source
, const gchar
*destination
)
825 if(!(src
= g_fopen(source
, "rb")))
827 if(!(dest
= g_fopen(destination
, "wb"))) {
832 while((chr
= fgetc(src
)) != EOF
) {
843 free_theme_info(struct theme_info
*info
)
847 g_free(info
->extension
);
848 g_free(info
->original_name
);
853 /* installs a theme, info is freed by function */
855 theme_install_theme(char *path
, struct theme_info
*info
)
862 gboolean is_smiley_theme
, is_archive
;
863 PurpleTheme
*theme
= NULL
;
868 /* check the extension */
869 tail
= info
->extension
? info
->extension
: strrchr(path
, '.');
872 free_theme_info(info
);
876 is_archive
= !g_ascii_strcasecmp(tail
, ".gz") || !g_ascii_strcasecmp(tail
, ".tgz");
878 /* Just to be safe */
881 if ((is_smiley_theme
= g_str_equal(info
->type
, "smiley")))
882 destdir
= g_build_filename(purple_user_dir(), "smileys", NULL
);
884 destdir
= g_build_filename(purple_user_dir(), "themes", "temp", NULL
);
886 /* We'll check this just to make sure. This also lets us do something different on
887 * other platforms, if need be */
890 gchar
*path_escaped
= g_shell_quote(path
);
891 gchar
*destdir_escaped
= g_shell_quote(destdir
);
893 if (!g_file_test(destdir
, G_FILE_TEST_IS_DIR
))
894 purple_build_dir(destdir
, S_IRUSR
| S_IWUSR
| S_IXUSR
);
896 command
= g_strdup_printf("tar > /dev/null xzf %s -C %s", path_escaped
, destdir_escaped
);
897 g_free(path_escaped
);
898 g_free(destdir_escaped
);
901 if (system(command
)) {
902 purple_notify_error(NULL
, NULL
, _("Theme failed to unpack."), NULL
, NULL
);
905 free_theme_info(info
);
909 if (!winpidgin_gz_untar(path
, destdir
)) {
910 purple_notify_error(NULL
, NULL
, _("Theme failed to unpack."), NULL
, NULL
);
912 free_theme_info(info
);
918 if (is_smiley_theme
) {
919 /* just extract the folder to the smiley directory */
920 prefs_themes_refresh();
922 } else if (is_archive
) {
923 theme
= prefs_theme_find_theme(destdir
, info
->type
);
925 if (PURPLE_IS_THEME(theme
)) {
926 /* create the location for the theme */
927 gchar
*theme_dest
= g_build_filename(purple_user_dir(), "themes",
928 purple_theme_get_name(theme
),
929 "purple", info
->type
, NULL
);
931 if (!g_file_test(theme_dest
, G_FILE_TEST_IS_DIR
))
932 purple_build_dir(theme_dest
, S_IRUSR
| S_IWUSR
| S_IXUSR
);
935 theme_dest
= g_build_filename(purple_user_dir(), "themes",
936 purple_theme_get_name(theme
),
937 "purple", info
->type
, NULL
);
939 /* move the entire directory to new location */
940 if (g_rename(purple_theme_get_dir(theme
), theme_dest
)) {
941 purple_debug_error("gtkprefs", "Error renaming %s to %s: "
942 "%s\n", purple_theme_get_dir(theme
), theme_dest
,
947 if (g_remove(destdir
) != 0) {
948 purple_debug_error("gtkprefs",
949 "couldn't remove temp (dest) path\n");
951 g_object_unref(theme
);
953 prefs_themes_refresh();
956 /* something was wrong with the theme archive */
958 purple_notify_error(NULL
, NULL
, _("Theme failed to load."), NULL
, NULL
);
961 } else { /* just a single file so copy it to a new temp directory and attempt to load it*/
962 gchar
*temp_path
, *temp_file
;
964 temp_path
= g_build_filename(purple_user_dir(), "themes", "temp", "sub_folder", NULL
);
966 if (info
->original_name
!= NULL
) {
967 /* name was changed from the original (probably a dnd) change it back before loading */
968 temp_file
= g_build_filename(temp_path
, info
->original_name
, NULL
);
971 gchar
*source_name
= g_path_get_basename(path
);
972 temp_file
= g_build_filename(temp_path
, source_name
, NULL
);
976 if (!g_file_test(temp_path
, G_FILE_TEST_IS_DIR
))
977 purple_build_dir(temp_path
, S_IRUSR
| S_IWUSR
| S_IXUSR
);
979 if (purple_theme_file_copy(path
, temp_file
)) {
980 /* find the theme, could be in subfolder */
981 theme
= prefs_theme_find_theme(temp_path
, info
->type
);
983 if (PURPLE_IS_THEME(theme
)) {
984 gchar
*theme_dest
= g_build_filename(purple_user_dir(), "themes",
985 purple_theme_get_name(theme
),
986 "purple", info
->type
, NULL
);
988 if(!g_file_test(theme_dest
, G_FILE_TEST_IS_DIR
))
989 purple_build_dir(theme_dest
, S_IRUSR
| S_IWUSR
| S_IXUSR
);
991 if (g_rename(purple_theme_get_dir(theme
), theme_dest
)) {
992 purple_debug_error("gtkprefs", "Error renaming %s to %s: "
993 "%s\n", purple_theme_get_dir(theme
), theme_dest
,
998 g_object_unref(theme
);
1000 prefs_themes_refresh();
1002 if (g_remove(temp_path
) != 0) {
1003 purple_debug_error("gtkprefs",
1004 "couldn't remove temp path");
1006 purple_notify_error(NULL
, NULL
, _("Theme failed to load."), NULL
, NULL
);
1009 purple_notify_error(NULL
, NULL
, _("Theme failed to copy."), NULL
, NULL
);
1017 free_theme_info(info
);
1021 theme_got_url(PurpleHttpConnection
*http_conn
, PurpleHttpResponse
*response
,
1024 struct theme_info
*info
= _info
;
1025 const gchar
*themedata
;
1031 g_assert(http_conn
== prefs_conv_themes_running_request
);
1032 prefs_conv_themes_running_request
= NULL
;
1034 if (!purple_http_response_is_successful(response
)) {
1035 free_theme_info(info
);
1039 themedata
= purple_http_response_get_data(response
, &len
);
1041 f
= purple_mkstemp(&path
, TRUE
);
1042 wc
= fwrite(themedata
, len
, 1, f
);
1044 purple_debug_warning("theme_got_url", "Unable to write theme data.\n");
1048 free_theme_info(info
);
1053 theme_install_theme(path
, info
);
1060 theme_dnd_recv(GtkWidget
*widget
, GdkDragContext
*dc
, guint x
, guint y
,
1061 GtkSelectionData
*sd
, guint info
, guint t
, gpointer user_data
)
1063 gchar
*name
= g_strchomp((gchar
*)gtk_selection_data_get_data(sd
));
1065 if ((gtk_selection_data_get_length(sd
) >= 0)
1066 && (gtk_selection_data_get_format(sd
) == 8)) {
1067 /* Well, it looks like the drag event was cool.
1068 * Let's do something with it */
1070 struct theme_info
*info
= g_new0(struct theme_info
, 1);
1071 info
->type
= g_strdup((gchar
*)user_data
);
1072 info
->extension
= g_strdup(g_strrstr(name
,"."));
1073 temp
= g_strrstr(name
, "/");
1074 info
->original_name
= temp
? g_strdup(++temp
) : NULL
;
1076 if (!g_ascii_strncasecmp(name
, "file://", 7)) {
1077 GError
*converr
= NULL
;
1079 /* It looks like we're dealing with a local file. Let's
1080 * just untar it in the right place */
1081 if(!(tmp
= g_filename_from_uri(name
, NULL
, &converr
))) {
1082 purple_debug(PURPLE_DEBUG_ERROR
, "theme dnd", "%s\n",
1083 (converr
? converr
->message
:
1084 "g_filename_from_uri error"));
1085 free_theme_info(info
);
1088 theme_install_theme(tmp
, info
);
1090 } else if (!g_ascii_strncasecmp(name
, "http://", 7) ||
1091 !g_ascii_strncasecmp(name
, "https://", 8)) {
1092 /* Oo, a web drag and drop. This is where things
1093 * will start to get interesting */
1094 PurpleHttpRequest
*hr
;
1095 purple_http_conn_cancel(prefs_conv_themes_running_request
);
1097 hr
= purple_http_request_new(name
);
1098 purple_http_request_set_max_len(hr
,
1099 PREFS_MAX_DOWNLOADED_THEME_SIZE
);
1100 prefs_conv_themes_running_request
= purple_http_request(
1101 NULL
, hr
, theme_got_url
, info
);
1102 purple_http_request_unref(hr
);
1104 free_theme_info(info
);
1106 gtk_drag_finish(dc
, TRUE
, FALSE
, t
);
1109 gtk_drag_finish(dc
, FALSE
, FALSE
, t
);
1112 /* builds a theme combo box from a list store with colums: icon preview, markup, theme name */
1114 prefs_build_theme_combo_box(GtkListStore
*store
, const char *current_theme
, const char *type
)
1116 GtkCellRenderer
*cell_rend
;
1117 GtkWidget
*combo_box
;
1118 GtkTargetEntry te
[3] = {
1119 {"text/plain", 0, 0},
1120 {"text/uri-list", 0, 1},
1124 g_return_val_if_fail(store
!= NULL
&& current_theme
!= NULL
, NULL
);
1126 combo_box
= gtk_combo_box_new_with_model(GTK_TREE_MODEL(store
));
1128 cell_rend
= gtk_cell_renderer_pixbuf_new();
1129 gtk_cell_renderer_set_fixed_size(cell_rend
, PREFS_OPTIMAL_ICON_SIZE
, PREFS_OPTIMAL_ICON_SIZE
);
1130 gtk_cell_layout_pack_start(GTK_CELL_LAYOUT (combo_box
), cell_rend
, FALSE
);
1131 gtk_cell_layout_set_attributes(GTK_CELL_LAYOUT(combo_box
), cell_rend
, "pixbuf", 0, NULL
);
1133 cell_rend
= gtk_cell_renderer_text_new();
1134 gtk_cell_layout_pack_start(GTK_CELL_LAYOUT (combo_box
), cell_rend
, TRUE
);
1135 gtk_cell_layout_set_attributes(GTK_CELL_LAYOUT(combo_box
), cell_rend
, "markup", 1, NULL
);
1136 g_object_set(cell_rend
, "ellipsize", PANGO_ELLIPSIZE_END
, NULL
);
1138 gtk_drag_dest_set(combo_box
, GTK_DEST_DEFAULT_MOTION
| GTK_DEST_DEFAULT_HIGHLIGHT
| GTK_DEST_DEFAULT_DROP
, te
,
1139 sizeof(te
) / sizeof(GtkTargetEntry
) , GDK_ACTION_COPY
| GDK_ACTION_MOVE
);
1141 g_signal_connect(G_OBJECT(combo_box
), "drag_data_received", G_CALLBACK(theme_dnd_recv
), (gpointer
) type
);
1146 /* sets the current sound theme */
1148 prefs_set_sound_theme_cb(GtkComboBox
*combo_box
, gpointer user_data
)
1153 GtkTreeIter new_iter
;
1155 if(gtk_combo_box_get_active_iter(combo_box
, &new_iter
) && !prefs_sound_themes_loading
) {
1157 gtk_tree_model_get(GTK_TREE_MODEL(prefs_sound_themes
), &new_iter
, 2, &new_theme
, -1);
1159 purple_prefs_set_string(PIDGIN_PREFS_ROOT
"/sound/theme", new_theme
);
1161 /* New theme removes all customization */
1162 for(i
= 0; i
< PURPLE_NUM_SOUNDS
; i
++){
1163 pref
= g_strdup_printf(PIDGIN_PREFS_ROOT
"/sound/file/%s",
1164 pidgin_sound_get_event_option(i
));
1165 purple_prefs_set_path(pref
, "");
1169 /* gets rid of the "(Custom)" from the last selection */
1170 pref_sound_generate_markup();
1172 gtk_entry_set_text(GTK_ENTRY(sound_entry
), _("(default)"));
1178 /* sets the current smiley theme */
1180 prefs_set_smiley_theme_cb(GtkComboBox
*combo_box
, gpointer user_data
)
1183 GtkTreeIter new_iter
;
1185 if (gtk_combo_box_get_active_iter(combo_box
, &new_iter
)) {
1187 gtk_tree_model_get(GTK_TREE_MODEL(prefs_smiley_themes
), &new_iter
, 2, &new_theme
, -1);
1189 purple_prefs_set_string(PIDGIN_PREFS_ROOT
"/smileys/theme", new_theme
);
1192 /* TODO: update smileys in sample_webview input box. */
1193 update_smileys_in_webview_input_box(sample_webview
);
1201 /* Does same as normal sort, except "none" is sorted first */
1202 static gint
pidgin_sort_smileys (GtkTreeModel
*model
,
1208 gchar
*name1
= NULL
, *name2
= NULL
;
1210 gtk_tree_model_get(model
, a
, 2, &name1
, -1);
1211 gtk_tree_model_get(model
, b
, 2, &name2
, -1);
1213 if (name1
== NULL
|| name2
== NULL
) {
1214 if (!(name1
== NULL
&& name2
== NULL
))
1215 ret
= (name1
== NULL
) ? -1: 1;
1216 } else if (!g_ascii_strcasecmp(name1
, "none")) {
1217 if (!g_utf8_collate(name1
, name2
))
1220 /* Sort name1 first */
1222 } else if (!g_ascii_strcasecmp(name2
, "none")) {
1223 /* Sort name2 first */
1226 /* Neither string is "none", default to normal sort */
1227 ret
= purple_utf8_strcasecmp(name1
, name2
);
1236 /* sets the current buddy list theme */
1238 prefs_set_blist_theme_cb(GtkComboBox
*combo_box
, gpointer user_data
)
1240 PidginBlistTheme
*theme
= NULL
;
1244 if(gtk_combo_box_get_active_iter(combo_box
, &iter
)) {
1246 gtk_tree_model_get(GTK_TREE_MODEL(prefs_blist_themes
), &iter
, 2, &name
, -1);
1248 if(!name
|| !g_str_equal(name
, ""))
1249 theme
= PIDGIN_BLIST_THEME(purple_theme_manager_find_theme(name
, "blist"));
1253 pidgin_blist_set_theme(theme
);
1257 /* sets the current conversation theme variant */
1259 prefs_set_conv_variant_cb(GtkComboBox
*combo_box
, gpointer user_data
)
1261 PidginConvTheme
*theme
= NULL
;
1265 if (gtk_combo_box_get_active_iter(GTK_COMBO_BOX(prefs_conv_themes_combo_box
), &iter
)) {
1266 gtk_tree_model_get(GTK_TREE_MODEL(prefs_conv_themes
), &iter
, 2, &name
, -1);
1268 theme
= PIDGIN_CONV_THEME(purple_theme_manager_find_theme(name
, "conversation"));
1270 theme
= PIDGIN_CONV_THEME(pidgin_conversations_get_default_theme());
1273 if (gtk_combo_box_get_active_iter(combo_box
, &iter
)) {
1274 gtk_tree_model_get(GTK_TREE_MODEL(prefs_conv_variants
), &iter
, 0, &name
, -1);
1275 pidgin_conversation_theme_set_variant(theme
, name
);
1281 /* sets the current conversation theme */
1283 prefs_set_conv_theme_cb(GtkComboBox
*combo_box
, gpointer user_data
)
1287 if (gtk_combo_box_get_active_iter(combo_box
, &iter
)) {
1289 PidginConvTheme
*theme
;
1290 const char *current_variant
;
1291 const GList
*variants
;
1292 gboolean unset
= TRUE
;
1294 gtk_tree_model_get(GTK_TREE_MODEL(prefs_conv_themes
), &iter
, 2, &name
, -1);
1296 purple_prefs_set_string(PIDGIN_PREFS_ROOT
"/conversations/theme", name
);
1298 g_signal_handlers_block_by_func(prefs_conv_variants_combo_box
,
1299 prefs_set_conv_variant_cb
, NULL
);
1301 /* Update list of variants */
1302 gtk_list_store_clear(prefs_conv_variants
);
1305 theme
= PIDGIN_CONV_THEME(purple_theme_manager_find_theme(name
, "conversation"));
1307 theme
= PIDGIN_CONV_THEME(pidgin_conversations_get_default_theme());
1309 current_variant
= pidgin_conversation_theme_get_variant(theme
);
1311 variants
= pidgin_conversation_theme_get_variants(theme
);
1312 for (; variants
&& current_variant
; variants
= g_list_next(variants
)) {
1313 gtk_list_store_append(prefs_conv_variants
, &iter
);
1314 gtk_list_store_set(prefs_conv_variants
, &iter
, 0, variants
->data
, -1);
1316 if (g_str_equal(variants
->data
, current_variant
)) {
1317 gtk_combo_box_set_active_iter(GTK_COMBO_BOX(prefs_conv_variants_combo_box
), &iter
);
1323 gtk_combo_box_set_active(GTK_COMBO_BOX(prefs_conv_variants_combo_box
), 0);
1325 g_signal_handlers_unblock_by_func(prefs_conv_variants_combo_box
,
1326 prefs_set_conv_variant_cb
, NULL
);
1331 /* sets the current icon theme */
1333 prefs_set_status_icon_theme_cb(GtkComboBox
*combo_box
, gpointer user_data
)
1335 PidginStatusIconTheme
*theme
= NULL
;
1339 if(gtk_combo_box_get_active_iter(combo_box
, &iter
)) {
1341 gtk_tree_model_get(GTK_TREE_MODEL(prefs_status_icon_themes
), &iter
, 2, &name
, -1);
1343 if(!name
|| !g_str_equal(name
, ""))
1344 theme
= PIDGIN_STATUS_ICON_THEME(purple_theme_manager_find_theme(name
, "status-icon"));
1348 pidgin_stock_load_status_icon_theme(theme
);
1349 pidgin_blist_refresh(purple_blist_get_buddy_list());
1354 add_theme_prefs_combo(GtkWidget
*vbox
,
1355 GtkSizeGroup
*combo_sg
, GtkSizeGroup
*label_sg
,
1356 GtkListStore
*theme_store
,
1357 GCallback combo_box_cb
, gpointer combo_box_cb_user_data
,
1358 const char *label_str
, const char *prefs_path
,
1359 const char *theme_type
)
1362 GtkWidget
*combo_box
= NULL
;
1363 GtkWidget
*themesel_hbox
= gtk_box_new(GTK_ORIENTATION_HORIZONTAL
, PIDGIN_HIG_BOX_SPACE
);
1365 label
= gtk_label_new(label_str
);
1366 gtk_widget_set_halign(label
, GTK_ALIGN_START
);
1367 gtk_widget_set_valign(label
, GTK_ALIGN_CENTER
);
1368 gtk_size_group_add_widget(label_sg
, label
);
1369 gtk_box_pack_start(GTK_BOX(themesel_hbox
), label
, FALSE
, FALSE
, 0);
1371 combo_box
= prefs_build_theme_combo_box(theme_store
,
1372 purple_prefs_get_string(prefs_path
),
1374 g_signal_connect(G_OBJECT(combo_box
), "changed",
1375 (GCallback
)combo_box_cb
, combo_box_cb_user_data
);
1376 gtk_size_group_add_widget(combo_sg
, combo_box
);
1377 gtk_box_pack_start(GTK_BOX(themesel_hbox
), combo_box
, TRUE
, TRUE
, 0);
1379 gtk_box_pack_start(GTK_BOX(vbox
), themesel_hbox
, FALSE
, FALSE
, 0);
1385 add_child_theme_prefs_combo(GtkWidget
*vbox
, GtkSizeGroup
*combo_sg
,
1386 GtkSizeGroup
*label_sg
, GtkListStore
*theme_store
,
1387 GCallback combo_box_cb
, gpointer combo_box_cb_user_data
,
1388 const char *label_str
)
1391 GtkWidget
*combo_box
;
1392 GtkWidget
*themesel_hbox
;
1393 GtkCellRenderer
*cell_rend
;
1395 themesel_hbox
= gtk_box_new(GTK_ORIENTATION_HORIZONTAL
, PIDGIN_HIG_BOX_SPACE
);
1396 gtk_box_pack_start(GTK_BOX(vbox
), themesel_hbox
, FALSE
, FALSE
, 0);
1398 label
= gtk_label_new(label_str
);
1399 gtk_widget_set_halign(label
, GTK_ALIGN_END
);
1400 gtk_widget_set_valign(label
, GTK_ALIGN_CENTER
);
1401 gtk_size_group_add_widget(label_sg
, label
);
1402 gtk_box_pack_start(GTK_BOX(themesel_hbox
), label
, FALSE
, FALSE
, 0);
1404 combo_box
= gtk_combo_box_new_with_model(GTK_TREE_MODEL(theme_store
));
1406 cell_rend
= gtk_cell_renderer_text_new();
1407 gtk_cell_layout_pack_start(GTK_CELL_LAYOUT(combo_box
), cell_rend
, TRUE
);
1408 gtk_cell_layout_set_attributes(GTK_CELL_LAYOUT(combo_box
), cell_rend
, "text", 0, NULL
);
1409 g_object_set(cell_rend
, "ellipsize", PANGO_ELLIPSIZE_END
, NULL
);
1411 g_signal_connect(G_OBJECT(combo_box
), "changed",
1412 (GCallback
)combo_box_cb
, combo_box_cb_user_data
);
1413 gtk_size_group_add_widget(combo_sg
, combo_box
);
1414 gtk_box_pack_start(GTK_BOX(themesel_hbox
), combo_box
, TRUE
, TRUE
, 0);
1423 GtkWidget
*ret
, *vbox
;
1424 GtkSizeGroup
*label_sg
= gtk_size_group_new(GTK_SIZE_GROUP_HORIZONTAL
);
1425 GtkSizeGroup
*combo_sg
= gtk_size_group_new(GTK_SIZE_GROUP_HORIZONTAL
);
1427 ret
= gtk_box_new(GTK_ORIENTATION_VERTICAL
, PIDGIN_HIG_CAT_SPACE
);
1428 gtk_container_set_border_width (GTK_CONTAINER (ret
), PIDGIN_HIG_BORDER
);
1430 vbox
= pidgin_make_frame(ret
, _("Theme Selections"));
1433 label
= gtk_label_new(_("Select a theme that you would like to use from "
1434 "the lists below.\nNew themes can be installed by "
1435 "dragging and dropping them onto the theme list."));
1437 gtk_widget_set_halign(label
, GTK_ALIGN_START
);
1438 gtk_widget_set_valign(label
, GTK_ALIGN_CENTER
);
1439 gtk_label_set_justify(GTK_LABEL(label
), GTK_JUSTIFY_LEFT
);
1441 gtk_box_pack_start(GTK_BOX(vbox
), label
, TRUE
, FALSE
, 0);
1442 gtk_widget_show(label
);
1444 /* Buddy List Themes */
1445 prefs_blist_themes_combo_box
= add_theme_prefs_combo(
1446 vbox
, combo_sg
, label_sg
, prefs_blist_themes
,
1447 (GCallback
)prefs_set_blist_theme_cb
, NULL
,
1448 _("Buddy List Theme:"), PIDGIN_PREFS_ROOT
"/blist/theme", "blist");
1450 /* Conversation Themes */
1451 prefs_conv_themes_combo_box
= add_theme_prefs_combo(
1452 vbox
, combo_sg
, label_sg
, prefs_conv_themes
,
1453 (GCallback
)prefs_set_conv_theme_cb
, NULL
,
1454 _("Conversation Theme:"), PIDGIN_PREFS_ROOT
"/conversations/theme", "conversation");
1456 /* Conversation Theme Variants */
1457 prefs_conv_variants_combo_box
= add_child_theme_prefs_combo(
1458 vbox
, combo_sg
, label_sg
, prefs_conv_variants
,
1459 (GCallback
)prefs_set_conv_variant_cb
, NULL
, _("\tVariant:"));
1461 gtk_tree_sortable_set_sort_column_id(GTK_TREE_SORTABLE(prefs_conv_variants
),
1462 0, GTK_SORT_ASCENDING
);
1464 /* Status Icon Themes */
1465 prefs_status_themes_combo_box
= add_theme_prefs_combo(
1466 vbox
, combo_sg
, label_sg
, prefs_status_icon_themes
,
1467 (GCallback
)prefs_set_status_icon_theme_cb
, NULL
,
1468 _("Status Icon Theme:"), PIDGIN_PREFS_ROOT
"/status/icon-theme", "icon");
1471 prefs_sound_themes_combo_box
= add_theme_prefs_combo(
1472 vbox
, combo_sg
, label_sg
, prefs_sound_themes
,
1473 (GCallback
)prefs_set_sound_theme_cb
, NULL
,
1474 _("Sound Theme:"), PIDGIN_PREFS_ROOT
"/sound/theme", "sound");
1477 prefs_smiley_themes_combo_box
= add_theme_prefs_combo(
1478 vbox
, combo_sg
, label_sg
, prefs_smiley_themes
,
1479 (GCallback
)prefs_set_smiley_theme_cb
, NULL
,
1480 _("Smiley Theme:"), PIDGIN_PREFS_ROOT
"/smileys/theme", "smiley");
1482 /* Custom sort so "none" theme is at top of list */
1483 gtk_tree_sortable_set_sort_func(GTK_TREE_SORTABLE(prefs_smiley_themes
),
1484 2, pidgin_sort_smileys
, NULL
, NULL
);
1485 gtk_tree_sortable_set_sort_column_id(GTK_TREE_SORTABLE(prefs_smiley_themes
),
1486 2, GTK_SORT_ASCENDING
);
1488 gtk_widget_show_all(ret
);
1494 formatting_toggle_cb(PidginWebView
*webview
, PidginWebViewButtons buttons
, void *data
)
1496 gboolean bold
, italic
, uline
, strike
;
1498 pidgin_webview_get_current_format(webview
, &bold
, &italic
, &uline
, &strike
);
1500 if (buttons
& PIDGIN_WEBVIEW_BOLD
)
1501 purple_prefs_set_bool(PIDGIN_PREFS_ROOT
"/conversations/send_bold",
1503 if (buttons
& PIDGIN_WEBVIEW_ITALIC
)
1504 purple_prefs_set_bool(PIDGIN_PREFS_ROOT
"/conversations/send_italic",
1506 if (buttons
& PIDGIN_WEBVIEW_UNDERLINE
)
1507 purple_prefs_set_bool(PIDGIN_PREFS_ROOT
"/conversations/send_underline",
1509 if (buttons
& PIDGIN_WEBVIEW_STRIKE
)
1510 purple_prefs_set_bool(PIDGIN_PREFS_ROOT
"/conversations/send_strike",
1513 if (buttons
& PIDGIN_WEBVIEW_GROW
|| buttons
& PIDGIN_WEBVIEW_SHRINK
)
1514 purple_prefs_set_int(PIDGIN_PREFS_ROOT
"/conversations/font_size",
1515 pidgin_webview_get_current_fontsize(webview
));
1516 if (buttons
& PIDGIN_WEBVIEW_FACE
) {
1517 char *face
= pidgin_webview_get_current_fontface(webview
);
1520 purple_prefs_set_string(PIDGIN_PREFS_ROOT
"/conversations/font_face", face
);
1522 purple_prefs_set_string(PIDGIN_PREFS_ROOT
"/conversations/font_face", "");
1527 if (buttons
& PIDGIN_WEBVIEW_FORECOLOR
) {
1528 char *color
= pidgin_webview_get_current_forecolor(webview
);
1531 purple_prefs_set_string(PIDGIN_PREFS_ROOT
"/conversations/fgcolor", color
);
1533 purple_prefs_set_string(PIDGIN_PREFS_ROOT
"/conversations/fgcolor", "");
1538 if (buttons
& PIDGIN_WEBVIEW_BACKCOLOR
) {
1539 char *color
= pidgin_webview_get_current_backcolor(webview
);
1542 purple_prefs_set_string(PIDGIN_PREFS_ROOT
"/conversations/bgcolor", color
);
1544 purple_prefs_set_string(PIDGIN_PREFS_ROOT
"/conversations/bgcolor", "");
1551 formatting_clear_cb(PidginWebView
*webview
, void *data
)
1553 purple_prefs_set_bool(PIDGIN_PREFS_ROOT
"/conversations/send_bold", FALSE
);
1554 purple_prefs_set_bool(PIDGIN_PREFS_ROOT
"/conversations/send_italic", FALSE
);
1555 purple_prefs_set_bool(PIDGIN_PREFS_ROOT
"/conversations/send_underline", FALSE
);
1556 purple_prefs_set_bool(PIDGIN_PREFS_ROOT
"/conversations/send_strike", FALSE
);
1558 purple_prefs_set_int(PIDGIN_PREFS_ROOT
"/conversations/font_size", 3);
1560 purple_prefs_set_string(PIDGIN_PREFS_ROOT
"/conversations/font_face", "");
1561 purple_prefs_set_string(PIDGIN_PREFS_ROOT
"/conversations/fgcolor", "");
1562 purple_prefs_set_string(PIDGIN_PREFS_ROOT
"/conversations/bgcolor", "");
1566 conversation_usetabs_cb(const char *name
, PurplePrefType type
,
1567 gconstpointer value
, gpointer data
)
1569 gboolean usetabs
= GPOINTER_TO_INT(value
);
1572 gtk_widget_set_sensitive(GTK_WIDGET(data
), TRUE
);
1574 gtk_widget_set_sensitive(GTK_WIDGET(data
), FALSE
);
1578 #define CONVERSATION_CLOSE_ACCEL_PATH "<Actions>/ConversationActions/Close"
1580 /* Filled in in keyboard_shortcuts(). */
1581 static GtkAccelKey ctrl_w
= { 0, 0, 0 };
1582 static GtkAccelKey escape
= { 0, 0, 0 };
1584 static guint escape_closes_conversation_cb_id
= 0;
1587 accel_is_escape(GtkAccelKey
*k
)
1589 return (k
->accel_key
== escape
.accel_key
1590 && k
->accel_mods
== escape
.accel_mods
);
1593 /* Update the tickybox in Preferences when the keybinding for Conversation ->
1594 * Close is changed via Gtk.
1597 conversation_close_accel_changed_cb (GtkAccelMap
*object
,
1600 GdkModifierType accel_mods
,
1603 GtkToggleButton
*checkbox
= GTK_TOGGLE_BUTTON(checkbox_
);
1604 GtkAccelKey
new = { accel_key
, accel_mods
, 0 };
1606 g_signal_handler_block(checkbox
, escape_closes_conversation_cb_id
);
1607 gtk_toggle_button_set_active(checkbox
, accel_is_escape(&new));
1608 g_signal_handler_unblock(checkbox
, escape_closes_conversation_cb_id
);
1613 escape_closes_conversation_cb(GtkWidget
*w
,
1616 gboolean active
= gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(w
));
1618 GtkAccelKey
*new_key
= active
? &escape
: &ctrl_w
;
1620 changed
= gtk_accel_map_change_entry(CONVERSATION_CLOSE_ACCEL_PATH
,
1621 new_key
->accel_key
, new_key
->accel_mods
, TRUE
);
1623 /* If another path is already bound to the new accelerator,
1624 * _change_entry tries to delete that binding (because it was passed
1625 * replace=TRUE). If that other path is locked, then _change_entry
1626 * will fail. We don't ever lock any accelerator paths, so this case
1627 * should never arise.
1630 purple_debug_warning("gtkprefs", "Escape accel failed to change\n");
1634 /* Creates preferences for keyboard shortcuts that it's hard to change with the
1635 * standard Gtk accelerator-changing mechanism.
1638 keyboard_shortcuts(GtkWidget
*page
)
1640 GtkWidget
*vbox
= pidgin_make_frame(page
, _("Keyboard Shortcuts"));
1641 GtkWidget
*checkbox
;
1642 GtkAccelKey current
= { 0, 0, 0 };
1643 GtkAccelMap
*map
= gtk_accel_map_get();
1645 /* Maybe it would be better just to hardcode the values?
1646 * -- resiak, 2007-04-30
1648 if (ctrl_w
.accel_key
== 0)
1650 gtk_accelerator_parse ("<Control>w", &(ctrl_w
.accel_key
),
1651 &(ctrl_w
.accel_mods
));
1652 g_assert(ctrl_w
.accel_key
!= 0);
1654 gtk_accelerator_parse ("Escape", &(escape
.accel_key
),
1655 &(escape
.accel_mods
));
1656 g_assert(escape
.accel_key
!= 0);
1659 checkbox
= gtk_check_button_new_with_mnemonic(
1660 _("Cl_ose conversations with the Escape key"));
1661 gtk_accel_map_lookup_entry(CONVERSATION_CLOSE_ACCEL_PATH
, ¤t
);
1662 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(checkbox
),
1663 accel_is_escape(¤t
));
1665 escape_closes_conversation_cb_id
= g_signal_connect(checkbox
,
1666 "clicked", G_CALLBACK(escape_closes_conversation_cb
), NULL
);
1668 g_signal_connect_object(map
, "changed::" CONVERSATION_CLOSE_ACCEL_PATH
,
1669 G_CALLBACK(conversation_close_accel_changed_cb
), checkbox
, (GConnectFlags
)0);
1671 gtk_box_pack_start(GTK_BOX(vbox
), checkbox
, FALSE
, FALSE
, 0);
1675 interface_page(void)
1682 GList
*names
= NULL
;
1684 ret
= gtk_box_new(GTK_ORIENTATION_VERTICAL
, PIDGIN_HIG_CAT_SPACE
);
1685 gtk_container_set_border_width(GTK_CONTAINER(ret
), PIDGIN_HIG_BORDER
);
1687 sg
= gtk_size_group_new(GTK_SIZE_GROUP_HORIZONTAL
);
1690 vbox
= pidgin_make_frame(ret
, _("System Tray Icon"));
1691 label
= pidgin_prefs_dropdown(vbox
, _("_Show system tray icon:"), PURPLE_PREF_STRING
,
1692 PIDGIN_PREFS_ROOT
"/docklet/show",
1693 _("Always"), "always",
1694 _("On unread messages"), "pending",
1695 _("Never"), "never",
1697 gtk_size_group_add_widget(sg
, label
);
1698 gtk_widget_set_halign(label
, GTK_ALIGN_START
);
1699 gtk_widget_set_valign(label
, GTK_ALIGN_CENTER
);
1701 vbox
= pidgin_make_frame(ret
, _("Conversation Window"));
1702 label
= pidgin_prefs_dropdown(vbox
, _("_Hide new IM conversations:"),
1703 PURPLE_PREF_STRING
, PIDGIN_PREFS_ROOT
"/conversations/im/hide_new",
1704 _("Never"), "never",
1705 _("When away"), "away",
1706 _("Always"), "always",
1708 gtk_size_group_add_widget(sg
, label
);
1709 gtk_widget_set_halign(label
, GTK_ALIGN_START
);
1710 gtk_widget_set_valign(label
, GTK_ALIGN_CENTER
);
1713 pidgin_prefs_checkbox(_("Minimi_ze new conversation windows"), PIDGIN_PREFS_ROOT
"/win32/minimize_new_convs", vbox
);
1716 /* All the tab options! */
1717 vbox
= pidgin_make_frame(ret
, _("Tabs"));
1719 pidgin_prefs_checkbox(_("Show IMs and chats in _tabbed windows"),
1720 PIDGIN_PREFS_ROOT
"/conversations/tabs", vbox
);
1723 * Connect a signal to the above preference. When conversations are not
1724 * shown in a tabbed window then all tabbing options should be disabled.
1726 vbox2
= gtk_box_new(GTK_ORIENTATION_VERTICAL
, 9);
1727 gtk_box_pack_start(GTK_BOX(vbox
), vbox2
, FALSE
, FALSE
, 0);
1728 purple_prefs_connect_callback(prefs
, PIDGIN_PREFS_ROOT
"/conversations/tabs",
1729 conversation_usetabs_cb
, vbox2
);
1730 if (!purple_prefs_get_bool(PIDGIN_PREFS_ROOT
"/conversations/tabs"))
1731 gtk_widget_set_sensitive(vbox2
, FALSE
);
1733 pidgin_prefs_checkbox(_("Show close b_utton on tabs"),
1734 PIDGIN_PREFS_ROOT
"/conversations/close_on_tabs", vbox2
);
1736 label
= pidgin_prefs_dropdown(vbox2
, _("_Placement:"), PURPLE_PREF_INT
,
1737 PIDGIN_PREFS_ROOT
"/conversations/tab_side",
1738 _("Top"), GTK_POS_TOP
,
1739 _("Bottom"), GTK_POS_BOTTOM
,
1740 _("Left"), GTK_POS_LEFT
,
1741 _("Right"), GTK_POS_RIGHT
,
1742 _("Left Vertical"), GTK_POS_LEFT
|8,
1743 _("Right Vertical"), GTK_POS_RIGHT
|8,
1745 gtk_size_group_add_widget(sg
, label
);
1746 gtk_widget_set_halign(label
, GTK_ALIGN_START
);
1747 gtk_widget_set_valign(label
, GTK_ALIGN_CENTER
);
1749 names
= pidgin_conv_placement_get_options();
1750 label
= pidgin_prefs_dropdown_from_list(vbox2
, _("N_ew conversations:"),
1751 PURPLE_PREF_STRING
, PIDGIN_PREFS_ROOT
"/conversations/placement", names
);
1752 gtk_widget_set_halign(label
, GTK_ALIGN_START
);
1753 gtk_widget_set_valign(label
, GTK_ALIGN_CENTER
);
1755 gtk_size_group_add_widget(sg
, label
);
1759 keyboard_shortcuts(ret
);
1761 gtk_widget_show_all(ret
);
1768 apply_custom_font(void)
1770 PangoFontDescription
*desc
= NULL
;
1771 if (!purple_prefs_get_bool(PIDGIN_PREFS_ROOT
"/conversations/use_theme_font")) {
1772 const char *font
= purple_prefs_get_string(PIDGIN_PREFS_ROOT
"/conversations/custom_font");
1773 desc
= pango_font_description_from_string(font
);
1776 gtk_widget_modify_font(sample_webview
, desc
);
1778 pango_font_description_free(desc
);
1782 pidgin_custom_font_set(GtkFontButton
*font_button
, gpointer nul
)
1785 purple_prefs_set_string(PIDGIN_PREFS_ROOT
"/conversations/custom_font",
1786 gtk_font_button_get_font_name(font_button
));
1788 apply_custom_font();
1797 GtkWidget
*iconpref1
;
1798 GtkWidget
*iconpref2
;
1803 GtkWidget
*checkbox
;
1804 GtkWidget
*spin_button
;
1807 ret
= gtk_box_new(GTK_ORIENTATION_VERTICAL
, PIDGIN_HIG_CAT_SPACE
);
1808 gtk_container_set_border_width(GTK_CONTAINER(ret
), PIDGIN_HIG_BORDER
);
1810 vbox
= pidgin_make_frame(ret
, _("Conversations"));
1812 pidgin_prefs_dropdown(vbox
, _("Chat notification:"),
1813 PURPLE_PREF_INT
, PIDGIN_PREFS_ROOT
"/conversations/notification_chat",
1814 _("On unseen events"), PIDGIN_UNSEEN_EVENT
,
1815 _("On unseen text"), PIDGIN_UNSEEN_TEXT
,
1816 _("On unseen text and the nick was said"), PIDGIN_UNSEEN_NICK
,
1819 pidgin_prefs_checkbox(_("Show _formatting on incoming messages"),
1820 PIDGIN_PREFS_ROOT
"/conversations/show_incoming_formatting", vbox
);
1821 pidgin_prefs_checkbox(_("Close IMs immediately when the tab is closed"),
1822 PIDGIN_PREFS_ROOT
"/conversations/im/close_immediately", vbox
);
1824 iconpref1
= pidgin_prefs_checkbox(_("Show _detailed information"),
1825 PIDGIN_PREFS_ROOT
"/conversations/im/show_buddy_icons", vbox
);
1826 iconpref2
= pidgin_prefs_checkbox(_("Enable buddy ic_on animation"),
1827 PIDGIN_PREFS_ROOT
"/conversations/im/animate_buddy_icons", vbox
);
1828 if (!purple_prefs_get_bool(PIDGIN_PREFS_ROOT
"/conversations/im/show_buddy_icons"))
1829 gtk_widget_set_sensitive(iconpref2
, FALSE
);
1830 g_signal_connect(G_OBJECT(iconpref1
), "clicked",
1831 G_CALLBACK(pidgin_toggle_sensitive
), iconpref2
);
1833 pidgin_prefs_checkbox(_("_Notify buddies that you are typing to them"),
1834 "/purple/conversations/im/send_typing", vbox
);
1835 pidgin_prefs_checkbox(_("Highlight _misspelled words"),
1836 PIDGIN_PREFS_ROOT
"/conversations/spellcheck", vbox
);
1838 pidgin_prefs_checkbox(_("Use smooth-scrolling"), PIDGIN_PREFS_ROOT
"/conversations/use_smooth_scrolling", vbox
);
1841 pidgin_prefs_checkbox(_("F_lash window when IMs are received"), PIDGIN_PREFS_ROOT
"/win32/blink_im", vbox
);
1845 /* TODO: it's not implemented */
1846 hbox
= gtk_box_new(GTK_ORIENTATION_HORIZONTAL
, PIDGIN_HIG_BOX_SPACE
);
1848 checkbox
= pidgin_prefs_checkbox(_("Resize incoming custom smileys"),
1849 PIDGIN_PREFS_ROOT
"/conversations/resize_custom_smileys", hbox
);
1851 spin_button
= pidgin_prefs_labeled_spin_button(hbox
,
1853 PIDGIN_PREFS_ROOT
"/conversations/custom_smileys_size",
1856 if (!purple_prefs_get_bool(
1857 PIDGIN_PREFS_ROOT
"/conversations/resize_custom_smileys"))
1858 gtk_widget_set_sensitive(GTK_WIDGET(spin_button
), FALSE
);
1860 g_signal_connect(G_OBJECT(checkbox
), "clicked",
1861 G_CALLBACK(pidgin_toggle_sensitive
), spin_button
);
1863 pidgin_add_widget_to_vbox(GTK_BOX(vbox
), NULL
, NULL
, hbox
, TRUE
, NULL
);
1866 pidgin_prefs_labeled_spin_button(vbox
,
1867 _("Minimum input area height in lines:"),
1868 PIDGIN_PREFS_ROOT
"/conversations/minimum_entry_lines",
1873 GtkWidget
*fontpref
, *font_button
, *hbox
;
1874 const char *font_name
;
1875 vbox
= pidgin_make_frame(ret
, _("Font"));
1877 fontpref
= pidgin_prefs_checkbox(_("Use font from _theme"),
1878 PIDGIN_PREFS_ROOT
"/conversations/use_theme_font", vbox
);
1880 font_name
= purple_prefs_get_string(PIDGIN_PREFS_ROOT
"/conversations/custom_font");
1881 if ((font_name
== NULL
) || (*font_name
== '\0')) {
1882 font_button
= gtk_font_button_new();
1884 font_button
= gtk_font_button_new_with_font(font_name
);
1887 gtk_font_button_set_show_style(GTK_FONT_BUTTON(font_button
), TRUE
);
1888 hbox
= pidgin_add_widget_to_vbox(GTK_BOX(vbox
), _("Conversation _font:"), NULL
, font_button
, FALSE
, NULL
);
1889 if (purple_prefs_get_bool(PIDGIN_PREFS_ROOT
"/conversations/use_theme_font"))
1890 gtk_widget_set_sensitive(hbox
, FALSE
);
1891 g_signal_connect(G_OBJECT(fontpref
), "clicked", G_CALLBACK(pidgin_toggle_sensitive
), hbox
);
1892 g_signal_connect(G_OBJECT(fontpref
), "clicked", G_CALLBACK(apply_custom_font
), hbox
);
1893 g_signal_connect(G_OBJECT(font_button
), "font-set", G_CALLBACK(pidgin_custom_font_set
), NULL
);
1898 vbox
= pidgin_make_frame(ret
, _("Default Formatting"));
1900 frame
= pidgin_create_webview(TRUE
, &webview
, NULL
);
1901 gtk_widget_show(frame
);
1902 gtk_widget_set_name(webview
, "pidgin_prefs_font_webview");
1903 gtk_widget_set_size_request(frame
, 450, -1);
1904 pidgin_webview_set_whole_buffer_formatting_only(PIDGIN_WEBVIEW(webview
), TRUE
);
1905 pidgin_webview_set_format_functions(PIDGIN_WEBVIEW(webview
),
1906 PIDGIN_WEBVIEW_BOLD
|
1907 PIDGIN_WEBVIEW_ITALIC
|
1908 PIDGIN_WEBVIEW_UNDERLINE
|
1909 PIDGIN_WEBVIEW_STRIKE
|
1910 PIDGIN_WEBVIEW_GROW
|
1911 PIDGIN_WEBVIEW_SHRINK
|
1912 PIDGIN_WEBVIEW_FACE
|
1913 PIDGIN_WEBVIEW_FORECOLOR
|
1914 PIDGIN_WEBVIEW_BACKCOLOR
);
1916 pidgin_webview_append_html(PIDGIN_WEBVIEW(webview
),
1917 _("This is how your outgoing message text will "
1918 "appear when you use protocols that support "
1921 gtk_box_pack_start(GTK_BOX(vbox
), frame
, TRUE
, TRUE
, 0);
1923 pidgin_webview_setup_entry(PIDGIN_WEBVIEW(webview
),
1924 PURPLE_CONNECTION_FLAG_HTML
|
1925 PURPLE_CONNECTION_FLAG_FORMATTING_WBFO
);
1927 g_signal_connect_after(G_OBJECT(webview
), "format-toggled",
1928 G_CALLBACK(formatting_toggle_cb
), NULL
);
1929 g_signal_connect_after(G_OBJECT(webview
), "format-cleared",
1930 G_CALLBACK(formatting_clear_cb
), NULL
);
1931 sample_webview
= webview
;
1933 gtk_widget_show(ret
);
1939 network_ip_changed(GtkEntry
*entry
, gpointer data
)
1941 const gchar
*text
= gtk_entry_get_text(entry
);
1942 GtkStyleContext
*context
= gtk_widget_get_style_context(GTK_WIDGET(entry
));
1944 if (text
&& *text
) {
1945 if (purple_ip_address_is_valid(text
)) {
1946 purple_network_set_public_ip(text
);
1947 gtk_style_context_add_class(context
, "good-ip");
1948 gtk_style_context_remove_class(context
, "bad-ip");
1950 gtk_style_context_add_class(context
, "bad-ip");
1951 gtk_style_context_remove_class(context
, "good-ip");
1955 purple_network_set_public_ip("");
1956 gtk_style_context_remove_class(context
, "bad-ip");
1957 gtk_style_context_remove_class(context
, "good-ip");
1962 network_stun_server_changed_cb(GtkWidget
*widget
,
1963 GdkEventFocus
*event
, gpointer data
)
1965 GtkEntry
*entry
= GTK_ENTRY(widget
);
1966 purple_prefs_set_string("/purple/network/stun_server",
1967 gtk_entry_get_text(entry
));
1968 purple_network_set_stun_server(gtk_entry_get_text(entry
));
1974 network_turn_server_changed_cb(GtkWidget
*widget
,
1975 GdkEventFocus
*event
, gpointer data
)
1977 GtkEntry
*entry
= GTK_ENTRY(widget
);
1978 purple_prefs_set_string("/purple/network/turn_server",
1979 gtk_entry_get_text(entry
));
1980 purple_network_set_turn_server(gtk_entry_get_text(entry
));
1986 proxy_changed_cb(const char *name
, PurplePrefType type
,
1987 gconstpointer value
, gpointer data
)
1989 GtkWidget
*frame
= data
;
1990 const char *proxy
= value
;
1992 if (strcmp(proxy
, "none") && strcmp(proxy
, "envvar"))
1993 gtk_widget_show_all(frame
);
1995 gtk_widget_hide(frame
);
1999 proxy_print_option(GtkEntry
*entry
, int entrynum
)
2001 if (entrynum
== PROXYHOST
)
2002 purple_prefs_set_string("/purple/proxy/host", gtk_entry_get_text(entry
));
2003 else if (entrynum
== PROXYPORT
)
2004 purple_prefs_set_int("/purple/proxy/port", atoi(gtk_entry_get_text(entry
)));
2005 else if (entrynum
== PROXYUSER
)
2006 purple_prefs_set_string("/purple/proxy/username", gtk_entry_get_text(entry
));
2007 else if (entrynum
== PROXYPASS
)
2008 purple_prefs_set_string("/purple/proxy/password", gtk_entry_get_text(entry
));
2012 proxy_button_clicked_cb(GtkWidget
*button
, gchar
*program
)
2016 if (g_spawn_command_line_async(program
, &err
))
2019 purple_notify_error(NULL
, NULL
, _("Cannot start proxy configuration program."), err
->message
, NULL
);
2025 browser_button_clicked_cb(GtkWidget
*button
, gchar
*path
)
2029 if (g_spawn_command_line_async(path
, &err
))
2032 purple_notify_error(NULL
, NULL
, _("Cannot start browser configuration program."), err
->message
, NULL
);
2038 auto_ip_button_clicked_cb(GtkWidget
*button
, gpointer null
)
2041 PurpleStunNatDiscovery
*stun
;
2044 /* purple_network_get_my_ip will return the IP that was set by the user with
2045 purple_network_set_public_ip, so make a lookup for the auto-detected IP
2048 if (purple_prefs_get_bool("/purple/network/auto_ip")) {
2049 /* Check if STUN discovery was already done */
2050 stun
= purple_stun_discover(NULL
);
2051 if ((stun
!= NULL
) && (stun
->status
== PURPLE_STUN_STATUS_DISCOVERED
)) {
2052 ip
= stun
->publicip
;
2054 /* Attempt to get the IP from a NAT device using UPnP */
2055 ip
= purple_upnp_get_public_ip();
2057 /* Attempt to get the IP from a NAT device using NAT-PMP */
2058 ip
= purple_pmp_get_public_ip();
2060 /* Just fetch the IP of the local system */
2061 ip
= purple_network_get_local_system_ip(-1);
2069 auto_ip_text
= g_strdup_printf(_("Use _automatically detected IP address: %s"), ip
);
2070 gtk_button_set_label(GTK_BUTTON(button
), auto_ip_text
);
2071 g_free(auto_ip_text
);
2078 GtkWidget
*vbox
, *hbox
, *entry
;
2079 GtkWidget
*label
, *auto_ip_checkbox
, *ports_checkbox
, *spin_button
;
2081 GtkStyleContext
*context
;
2082 GtkCssProvider
*ip_css
;
2083 const gchar ip_style
[] =
2085 "color: @error_fg_color;"
2086 "text-shadow: 0 1px @error_text_shadow;"
2087 "background-image: none;"
2088 "background-color: @error_bg_color;"
2091 "color: @question_fg_color;"
2092 "text-shadow: 0 1px @question_text_shadow;"
2093 "background-image: none;"
2094 "background-color: @success_color;"
2097 ret
= gtk_box_new(GTK_ORIENTATION_VERTICAL
, PIDGIN_HIG_CAT_SPACE
);
2098 gtk_container_set_border_width (GTK_CONTAINER (ret
), PIDGIN_HIG_BORDER
);
2100 vbox
= pidgin_make_frame (ret
, _("IP Address"));
2101 sg
= gtk_size_group_new(GTK_SIZE_GROUP_HORIZONTAL
);
2103 entry
= gtk_entry_new();
2104 gtk_entry_set_text(GTK_ENTRY(entry
), purple_prefs_get_string(
2105 "/purple/network/stun_server"));
2106 g_signal_connect(G_OBJECT(entry
), "focus-out-event",
2107 G_CALLBACK(network_stun_server_changed_cb
), NULL
);
2108 gtk_widget_show(entry
);
2110 pidgin_add_widget_to_vbox(GTK_BOX(vbox
), _("ST_UN server:"),
2111 sg
, entry
, TRUE
, NULL
);
2113 hbox
= gtk_box_new(GTK_ORIENTATION_HORIZONTAL
, PIDGIN_HIG_BOX_SPACE
);
2114 gtk_container_add(GTK_CONTAINER(vbox
), hbox
);
2116 label
= gtk_label_new(NULL
);
2117 gtk_container_add(GTK_CONTAINER(hbox
), label
);
2118 gtk_size_group_add_widget(sg
, label
);
2120 label
= gtk_label_new(NULL
);
2121 gtk_label_set_markup(GTK_LABEL(label
),
2122 _("<span style=\"italic\">Example: stunserver.org</span>"));
2123 gtk_widget_set_halign(label
, GTK_ALIGN_START
);
2124 gtk_widget_set_valign(label
, GTK_ALIGN_CENTER
);
2125 gtk_container_add(GTK_CONTAINER(hbox
), label
);
2127 auto_ip_checkbox
= pidgin_prefs_checkbox("Use _automatically detected IP address",
2128 "/purple/network/auto_ip", vbox
);
2129 g_signal_connect(G_OBJECT(auto_ip_checkbox
), "clicked",
2130 G_CALLBACK(auto_ip_button_clicked_cb
), NULL
);
2131 auto_ip_button_clicked_cb(auto_ip_checkbox
, NULL
); /* Update label */
2133 entry
= gtk_entry_new();
2134 gtk_entry_set_text(GTK_ENTRY(entry
), purple_network_get_public_ip());
2135 g_signal_connect(G_OBJECT(entry
), "changed",
2136 G_CALLBACK(network_ip_changed
), NULL
);
2138 ip_css
= gtk_css_provider_new();
2139 gtk_css_provider_load_from_data(ip_css
, ip_style
, -1, NULL
);
2140 context
= gtk_widget_get_style_context(entry
);
2141 gtk_style_context_add_provider(context
,
2142 GTK_STYLE_PROVIDER(ip_css
),
2143 GTK_STYLE_PROVIDER_PRIORITY_APPLICATION
);
2145 hbox
= pidgin_add_widget_to_vbox(GTK_BOX(vbox
), _("Public _IP:"),
2146 sg
, entry
, TRUE
, NULL
);
2148 if (purple_prefs_get_bool("/purple/network/auto_ip")) {
2149 gtk_widget_set_sensitive(GTK_WIDGET(hbox
), FALSE
);
2152 g_signal_connect(G_OBJECT(auto_ip_checkbox
), "clicked",
2153 G_CALLBACK(pidgin_toggle_sensitive
), hbox
);
2157 vbox
= pidgin_make_frame (ret
, _("Ports"));
2158 sg
= gtk_size_group_new(GTK_SIZE_GROUP_HORIZONTAL
);
2160 pidgin_prefs_checkbox(_("_Enable automatic router port forwarding"),
2161 "/purple/network/map_ports", vbox
);
2163 hbox
= gtk_box_new(GTK_ORIENTATION_HORIZONTAL
, PIDGIN_HIG_BOX_SPACE
);
2165 ports_checkbox
= pidgin_prefs_checkbox(_("_Manually specify range of ports to listen on:"),
2166 "/purple/network/ports_range_use", hbox
);
2168 spin_button
= pidgin_prefs_labeled_spin_button(hbox
, _("_Start:"),
2169 "/purple/network/ports_range_start", 0, 65535, sg
);
2170 if (!purple_prefs_get_bool("/purple/network/ports_range_use"))
2171 gtk_widget_set_sensitive(GTK_WIDGET(spin_button
), FALSE
);
2172 g_signal_connect(G_OBJECT(ports_checkbox
), "clicked",
2173 G_CALLBACK(pidgin_toggle_sensitive
), spin_button
);
2175 spin_button
= pidgin_prefs_labeled_spin_button(hbox
, _("_End:"),
2176 "/purple/network/ports_range_end", 0, 65535, sg
);
2177 if (!purple_prefs_get_bool("/purple/network/ports_range_use"))
2178 gtk_widget_set_sensitive(GTK_WIDGET(spin_button
), FALSE
);
2179 g_signal_connect(G_OBJECT(ports_checkbox
), "clicked",
2180 G_CALLBACK(pidgin_toggle_sensitive
), spin_button
);
2182 pidgin_add_widget_to_vbox(GTK_BOX(vbox
), NULL
, NULL
, hbox
, TRUE
, NULL
);
2187 vbox
= pidgin_make_frame(ret
, _("Relay Server (TURN)"));
2188 sg
= gtk_size_group_new(GTK_SIZE_GROUP_HORIZONTAL
);
2190 entry
= gtk_entry_new();
2191 gtk_entry_set_text(GTK_ENTRY(entry
), purple_prefs_get_string(
2192 "/purple/network/turn_server"));
2193 g_signal_connect(G_OBJECT(entry
), "focus-out-event",
2194 G_CALLBACK(network_turn_server_changed_cb
), NULL
);
2195 gtk_widget_show(entry
);
2197 hbox
= pidgin_add_widget_to_vbox(GTK_BOX(vbox
), _("_TURN server:"),
2198 sg
, entry
, TRUE
, NULL
);
2200 pidgin_prefs_labeled_spin_button(hbox
, _("_UDP Port:"),
2201 "/purple/network/turn_port", 0, 65535, NULL
);
2203 pidgin_prefs_labeled_spin_button(hbox
, _("T_CP Port:"),
2204 "/purple/network/turn_port_tcp", 0, 65535, NULL
);
2206 hbox
= pidgin_prefs_labeled_entry(vbox
, _("Use_rname:"),
2207 "/purple/network/turn_username", sg
);
2208 pidgin_prefs_labeled_password(hbox
, _("Pass_word:"),
2209 "/purple/network/turn_password", NULL
);
2211 gtk_widget_show_all(ret
);
2219 manual_browser_set(GtkWidget
*entry
, GdkEventFocus
*event
, gpointer data
)
2221 const char *program
= gtk_entry_get_text(GTK_ENTRY(entry
));
2223 purple_prefs_set_string(PIDGIN_PREFS_ROOT
"/browsers/manual_command", program
);
2225 /* carry on normally */
2230 get_available_browsers(void)
2237 /* Sorted reverse alphabetically */
2238 static const struct browser possible_browsers
[] = {
2239 {N_("Seamonkey"), "seamonkey"},
2240 {N_("Opera"), "opera"},
2241 {N_("Mozilla"), "mozilla"},
2242 {N_("Konqueror"), "kfmclient"},
2243 {N_("Google Chrome"), "google-chrome"},
2244 /* Do not move the line below. Code below expects gnome-open to be in
2245 * this list immediately after xdg-open! */
2246 {N_("Desktop Default"), "xdg-open"},
2247 {N_("GNOME Default"), "gnome-open"},
2248 {N_("Galeon"), "galeon"},
2249 {N_("Firefox"), "firefox"},
2250 {N_("Firebird"), "mozilla-firebird"},
2251 {N_("Epiphany"), "epiphany"},
2252 /* Translators: please do not translate "chromium-browser" here! */
2253 {N_("Chromium (chromium-browser)"), "chromium-browser"},
2254 /* Translators: please do not translate "chrome" here! */
2255 {N_("Chromium (chrome)"), "chrome"}
2257 static const int num_possible_browsers
= G_N_ELEMENTS(possible_browsers
);
2259 GList
*browsers
= NULL
;
2261 char *browser_setting
= (char *)purple_prefs_get_string(PIDGIN_PREFS_ROOT
"/browsers/browser");
2263 browsers
= g_list_prepend(browsers
, (gpointer
)"custom");
2264 browsers
= g_list_prepend(browsers
, (gpointer
)_("Manual"));
2266 for (i
= 0; i
< num_possible_browsers
; i
++) {
2267 if (purple_program_is_valid(possible_browsers
[i
].command
)) {
2268 browsers
= g_list_prepend(browsers
,
2269 possible_browsers
[i
].command
);
2270 browsers
= g_list_prepend(browsers
, (gpointer
)_(possible_browsers
[i
].name
));
2271 if(browser_setting
&& !strcmp(possible_browsers
[i
].command
, browser_setting
))
2272 browser_setting
= NULL
;
2273 /* If xdg-open is valid, prefer it over gnome-open and skip forward */
2274 if(!strcmp(possible_browsers
[i
].command
, "xdg-open")) {
2275 if (browser_setting
&& !strcmp("gnome-open", browser_setting
)) {
2276 purple_prefs_set_string(PIDGIN_PREFS_ROOT
"/browsers/browser", possible_browsers
[i
].command
);
2277 browser_setting
= NULL
;
2285 purple_prefs_set_string(PIDGIN_PREFS_ROOT
"/browsers/browser", "custom");
2291 browser_changed1_cb(const char *name
, PurplePrefType type
,
2292 gconstpointer value
, gpointer data
)
2294 GtkWidget
*hbox
= data
;
2295 const char *browser
= value
;
2297 gtk_widget_set_sensitive(hbox
, strcmp(browser
, "custom"));
2301 browser_changed2_cb(const char *name
, PurplePrefType type
,
2302 gconstpointer value
, gpointer data
)
2304 GtkWidget
*hbox
= data
;
2305 const char *browser
= value
;
2307 gtk_widget_set_sensitive(hbox
, !strcmp(browser
, "custom"));
2313 GtkWidget
*ret
, *vbox
, *hbox
, *label
, *entry
, *browser_button
;
2315 GList
*browsers
= NULL
;
2317 ret
= gtk_box_new(GTK_ORIENTATION_VERTICAL
, PIDGIN_HIG_CAT_SPACE
);
2318 gtk_container_set_border_width (GTK_CONTAINER (ret
), PIDGIN_HIG_BORDER
);
2320 vbox
= pidgin_make_frame (ret
, _("Browser Selection"));
2322 if (purple_running_gnome()) {
2325 hbox
= gtk_box_new(GTK_ORIENTATION_HORIZONTAL
, PIDGIN_HIG_BOX_SPACE
);
2326 label
= gtk_label_new(_("Browser preferences are configured in GNOME preferences"));
2327 gtk_container_add(GTK_CONTAINER(vbox
), hbox
);
2328 gtk_box_pack_start(GTK_BOX(hbox
), label
, FALSE
, FALSE
, 0);
2330 hbox
= gtk_box_new(GTK_ORIENTATION_HORIZONTAL
, PIDGIN_HIG_BOX_SPACE
);
2331 gtk_container_add(GTK_CONTAINER(vbox
), hbox
);
2333 path
= g_find_program_in_path("gnome-control-center");
2335 gchar
*tmp
= g_strdup_printf("%s info", path
);
2339 path
= g_find_program_in_path("gnome-default-applications-properties");
2343 label
= gtk_label_new(NULL
);
2344 gtk_label_set_markup(GTK_LABEL(label
),
2345 _("<b>Browser configuration program was not found.</b>"));
2346 gtk_box_pack_start(GTK_BOX(hbox
), label
, FALSE
, FALSE
, 0);
2348 browser_button
= gtk_button_new_with_mnemonic(_("Configure _Browser"));
2349 g_signal_connect_data(G_OBJECT(browser_button
), "clicked",
2350 G_CALLBACK(browser_button_clicked_cb
), path
,
2351 (GClosureNotify
)g_free
, 0);
2352 gtk_box_pack_start(GTK_BOX(hbox
), browser_button
, FALSE
, FALSE
, 0);
2355 gtk_widget_show_all(ret
);
2357 sg
= gtk_size_group_new(GTK_SIZE_GROUP_HORIZONTAL
);
2359 browsers
= get_available_browsers();
2360 if (browsers
!= NULL
) {
2361 label
= pidgin_prefs_dropdown_from_list(vbox
,_("_Browser:"), PURPLE_PREF_STRING
,
2362 PIDGIN_PREFS_ROOT
"/browsers/browser",
2364 g_list_free(browsers
);
2365 gtk_widget_set_halign(label
, GTK_ALIGN_START
);
2366 gtk_widget_set_valign(label
, GTK_ALIGN_CENTER
);
2367 gtk_size_group_add_widget(sg
, label
);
2369 hbox
= gtk_box_new(GTK_ORIENTATION_HORIZONTAL
, 0);
2370 label
= pidgin_prefs_dropdown(hbox
, _("_Open link in:"), PURPLE_PREF_INT
,
2371 PIDGIN_PREFS_ROOT
"/browsers/place",
2372 _("Browser default"), PIDGIN_BROWSER_DEFAULT
,
2373 _("New window"), PIDGIN_BROWSER_NEW_WINDOW
,
2374 _("New tab"), PIDGIN_BROWSER_NEW_TAB
,
2376 gtk_widget_set_halign(label
, GTK_ALIGN_START
);
2377 gtk_widget_set_valign(label
, GTK_ALIGN_CENTER
);
2378 gtk_size_group_add_widget(sg
, label
);
2379 gtk_box_pack_start(GTK_BOX(vbox
), hbox
, FALSE
, FALSE
, 0);
2381 if (!strcmp(purple_prefs_get_string(PIDGIN_PREFS_ROOT
"/browsers/browser"), "custom"))
2382 gtk_widget_set_sensitive(hbox
, FALSE
);
2383 purple_prefs_connect_callback(prefs
, PIDGIN_PREFS_ROOT
"/browsers/browser",
2384 browser_changed1_cb
, hbox
);
2387 entry
= gtk_entry_new();
2388 gtk_entry_set_text(GTK_ENTRY(entry
),
2389 purple_prefs_get_string(PIDGIN_PREFS_ROOT
"/browsers/manual_command"));
2390 g_signal_connect(G_OBJECT(entry
), "focus-out-event",
2391 G_CALLBACK(manual_browser_set
), NULL
);
2392 hbox
= pidgin_add_widget_to_vbox(GTK_BOX(vbox
), _("_Manual:\n(%s for URL)"), sg
, entry
, TRUE
, NULL
);
2393 if (strcmp(purple_prefs_get_string(PIDGIN_PREFS_ROOT
"/browsers/browser"), "custom"))
2394 gtk_widget_set_sensitive(hbox
, FALSE
);
2395 purple_prefs_connect_callback(prefs
, PIDGIN_PREFS_ROOT
"/browsers/browser",
2396 browser_changed2_cb
, hbox
);
2398 gtk_widget_show_all(ret
);
2409 GtkWidget
*ret
= NULL
, *vbox
= NULL
, *hbox
= NULL
;
2410 GtkWidget
*grid
= NULL
, *entry
= NULL
, *proxy_button
= NULL
;
2411 GtkWidget
*label
= NULL
;
2412 GtkWidget
*prefs_proxy_frame
= NULL
;
2413 PurpleProxyInfo
*proxy_info
;
2415 ret
= gtk_box_new(GTK_ORIENTATION_VERTICAL
, PIDGIN_HIG_CAT_SPACE
);
2416 gtk_container_set_border_width(GTK_CONTAINER(ret
), PIDGIN_HIG_BORDER
);
2417 vbox
= pidgin_make_frame(ret
, _("Proxy Server"));
2418 prefs_proxy_frame
= gtk_box_new(GTK_ORIENTATION_VERTICAL
, PIDGIN_HIG_BOX_SPACE
);
2420 if(purple_running_gnome()) {
2423 hbox
= gtk_box_new(GTK_ORIENTATION_HORIZONTAL
, PIDGIN_HIG_BOX_SPACE
);
2424 label
= gtk_label_new(_("Proxy preferences are configured in "
2425 "GNOME preferences"));
2426 gtk_container_add(GTK_CONTAINER(vbox
), hbox
);
2427 gtk_box_pack_start(GTK_BOX(hbox
), label
, FALSE
, FALSE
, 0);
2429 hbox
= gtk_box_new(GTK_ORIENTATION_HORIZONTAL
, PIDGIN_HIG_BOX_SPACE
);
2430 gtk_container_add(GTK_CONTAINER(vbox
), hbox
);
2432 path
= g_find_program_in_path("gnome-network-properties");
2434 path
= g_find_program_in_path("gnome-network-preferences");
2436 path
= g_find_program_in_path("gnome-control-center");
2438 char *tmp
= g_strdup_printf("%s network", path
);
2445 label
= gtk_label_new(NULL
);
2446 gtk_label_set_markup(GTK_LABEL(label
),
2447 _("<b>Proxy configuration program was "
2449 gtk_box_pack_start(GTK_BOX(hbox
), label
, FALSE
, FALSE
, 0);
2451 proxy_button
= gtk_button_new_with_mnemonic(_("Configure _Proxy"));
2452 g_signal_connect(G_OBJECT(proxy_button
), "clicked",
2453 G_CALLBACK(proxy_button_clicked_cb
),
2455 gtk_box_pack_start(GTK_BOX(hbox
), proxy_button
, FALSE
, FALSE
, 0);
2458 /* NOTE: path leaks, but only when the prefs window is destroyed,
2460 gtk_widget_show_all(ret
);
2462 GtkWidget
*prefs_proxy_subframe
= gtk_box_new(GTK_ORIENTATION_VERTICAL
, 0);
2464 /* This is a global option that affects SOCKS4 usage even with
2465 * account-specific proxy settings */
2466 pidgin_prefs_checkbox(_("Use remote _DNS with SOCKS4 proxies"),
2467 "/purple/proxy/socks4_remotedns", prefs_proxy_frame
);
2468 gtk_box_pack_start(GTK_BOX(vbox
), prefs_proxy_frame
, 0, 0, 0);
2470 pidgin_prefs_dropdown(prefs_proxy_frame
, _("Proxy t_ype:"), PURPLE_PREF_STRING
,
2471 "/purple/proxy/type",
2472 _("No proxy"), "none",
2473 _("SOCKS 4"), "socks4",
2474 _("SOCKS 5"), "socks5",
2475 _("Tor/Privacy (SOCKS5)"), "tor",
2477 _("Use Environmental Settings"), "envvar",
2479 gtk_box_pack_start(GTK_BOX(prefs_proxy_frame
), prefs_proxy_subframe
, 0, 0, 0);
2480 proxy_info
= purple_global_proxy_get_info();
2482 gtk_widget_show_all(ret
);
2484 purple_prefs_connect_callback(prefs
, "/purple/proxy/type",
2485 proxy_changed_cb
, prefs_proxy_subframe
);
2487 grid
= gtk_grid_new();
2488 gtk_container_set_border_width(GTK_CONTAINER(grid
), 0);
2489 gtk_grid_set_column_spacing(GTK_GRID(grid
), 5);
2490 gtk_grid_set_row_spacing(GTK_GRID(grid
), 10);
2491 gtk_container_add(GTK_CONTAINER(prefs_proxy_subframe
), grid
);
2493 label
= gtk_label_new_with_mnemonic(_("_Host:"));
2494 gtk_widget_set_halign(label
, GTK_ALIGN_END
);
2495 gtk_widget_set_valign(label
, GTK_ALIGN_CENTER
);
2496 gtk_grid_attach(GTK_GRID(grid
), label
, 0, 0, 1, 1);
2498 entry
= gtk_entry_new();
2499 gtk_label_set_mnemonic_widget(GTK_LABEL(label
), entry
);
2500 gtk_widget_set_valign(entry
, GTK_ALIGN_CENTER
);
2501 gtk_grid_attach(GTK_GRID(grid
), entry
, 1, 0, 1, 1);
2503 g_signal_connect(G_OBJECT(entry
), "changed",
2504 G_CALLBACK(proxy_print_option
), (void *)PROXYHOST
);
2506 if (proxy_info
!= NULL
&& purple_proxy_info_get_host(proxy_info
))
2507 gtk_entry_set_text(GTK_ENTRY(entry
),
2508 purple_proxy_info_get_host(proxy_info
));
2510 hbox
= gtk_box_new(GTK_ORIENTATION_HORIZONTAL
, 5);
2511 gtk_box_set_homogeneous(GTK_BOX(hbox
), TRUE
);
2512 gtk_box_pack_start(GTK_BOX(vbox
), hbox
, FALSE
, FALSE
, 0);
2513 pidgin_set_accessible_label(entry
, GTK_LABEL(label
));
2515 label
= gtk_label_new_with_mnemonic(_("P_ort:"));
2516 gtk_widget_set_halign(label
, GTK_ALIGN_END
);
2517 gtk_widget_set_valign(label
, GTK_ALIGN_CENTER
);
2518 gtk_grid_attach(GTK_GRID(grid
), label
, 2, 0, 1, 1);
2520 entry
= gtk_spin_button_new_with_range(0, 65535, 1);
2521 gtk_label_set_mnemonic_widget(GTK_LABEL(label
), entry
);
2522 gtk_widget_set_valign(entry
, GTK_ALIGN_CENTER
);
2523 gtk_grid_attach(GTK_GRID(grid
), entry
, 3, 0, 1, 1);
2525 g_signal_connect(G_OBJECT(entry
), "changed",
2526 G_CALLBACK(proxy_print_option
), (void *)PROXYPORT
);
2528 if (proxy_info
!= NULL
&& purple_proxy_info_get_port(proxy_info
) != 0) {
2529 gtk_spin_button_set_value(GTK_SPIN_BUTTON(entry
),
2530 purple_proxy_info_get_port(proxy_info
));
2532 pidgin_set_accessible_label(entry
, GTK_LABEL(label
));
2534 label
= gtk_label_new_with_mnemonic(_("User_name:"));
2535 gtk_widget_set_halign(label
, GTK_ALIGN_END
);
2536 gtk_widget_set_valign(label
, GTK_ALIGN_CENTER
);
2537 gtk_grid_attach(GTK_GRID(grid
), label
, 0, 1, 1, 1);
2539 entry
= gtk_entry_new();
2540 gtk_label_set_mnemonic_widget(GTK_LABEL(label
), entry
);
2541 gtk_widget_set_valign(entry
, GTK_ALIGN_CENTER
);
2542 gtk_grid_attach(GTK_GRID(grid
), entry
, 1, 1, 1, 1);
2544 g_signal_connect(G_OBJECT(entry
), "changed",
2545 G_CALLBACK(proxy_print_option
), (void *)PROXYUSER
);
2547 if (proxy_info
!= NULL
&& purple_proxy_info_get_username(proxy_info
) != NULL
)
2548 gtk_entry_set_text(GTK_ENTRY(entry
),
2549 purple_proxy_info_get_username(proxy_info
));
2551 hbox
= gtk_box_new(GTK_ORIENTATION_HORIZONTAL
, 5);
2552 gtk_box_set_homogeneous(GTK_BOX(hbox
), TRUE
);
2553 gtk_box_pack_start(GTK_BOX(vbox
), hbox
, FALSE
, FALSE
, 0);
2554 pidgin_set_accessible_label(entry
, GTK_LABEL(label
));
2556 label
= gtk_label_new_with_mnemonic(_("Pa_ssword:"));
2557 gtk_widget_set_halign(label
, GTK_ALIGN_END
);
2558 gtk_widget_set_valign(label
, GTK_ALIGN_CENTER
);
2559 gtk_grid_attach(GTK_GRID(grid
), label
, 2, 1, 1, 1);
2561 entry
= gtk_entry_new();
2562 gtk_label_set_mnemonic_widget(GTK_LABEL(label
), entry
);
2563 gtk_widget_set_valign(entry
, GTK_ALIGN_CENTER
);
2564 gtk_grid_attach(GTK_GRID(grid
), entry
, 3, 1, 1, 1);
2566 gtk_entry_set_visibility(GTK_ENTRY(entry
), FALSE
);
2567 g_signal_connect(G_OBJECT(entry
), "changed",
2568 G_CALLBACK(proxy_print_option
), (void *)PROXYPASS
);
2570 if (proxy_info
!= NULL
&& purple_proxy_info_get_password(proxy_info
) != NULL
)
2571 gtk_entry_set_text(GTK_ENTRY(entry
),
2572 purple_proxy_info_get_password(proxy_info
));
2573 pidgin_set_accessible_label(entry
, GTK_LABEL(label
));
2575 proxy_changed_cb("/purple/proxy/type", PURPLE_PREF_STRING
,
2576 purple_prefs_get_string("/purple/proxy/type"),
2577 prefs_proxy_subframe
);
2591 ret
= gtk_box_new(GTK_ORIENTATION_VERTICAL
, PIDGIN_HIG_CAT_SPACE
);
2592 gtk_container_set_border_width (GTK_CONTAINER (ret
), PIDGIN_HIG_BORDER
);
2595 vbox
= pidgin_make_frame (ret
, _("Logging"));
2596 names
= purple_log_logger_get_options();
2598 pidgin_prefs_dropdown_from_list(vbox
, _("Log _format:"), PURPLE_PREF_STRING
,
2599 "/purple/logging/format", names
);
2603 pidgin_prefs_checkbox(_("Log all _instant messages"),
2604 "/purple/logging/log_ims", vbox
);
2605 pidgin_prefs_checkbox(_("Log all c_hats"),
2606 "/purple/logging/log_chats", vbox
);
2607 pidgin_prefs_checkbox(_("Log all _status changes to system log"),
2608 "/purple/logging/log_system", vbox
);
2610 gtk_widget_show_all(ret
);
2615 /*** keyring page *******************************************************/
2618 keyring_page_settings_changed(GtkWidget
*widget
, gpointer _setting
)
2620 PurpleRequestField
*setting
= _setting
;
2621 PurpleRequestFieldType field_type
;
2623 gtk_widget_set_sensitive(keyring_apply
, TRUE
);
2625 field_type
= purple_request_field_get_field_type(setting
);
2627 if (field_type
== PURPLE_REQUEST_FIELD_BOOLEAN
) {
2628 purple_request_field_bool_set_value(setting
,
2629 gtk_toggle_button_get_active(
2630 GTK_TOGGLE_BUTTON(widget
)));
2631 } else if (field_type
== PURPLE_REQUEST_FIELD_STRING
) {
2632 purple_request_field_string_set_value(setting
,
2633 gtk_entry_get_text(GTK_ENTRY(widget
)));
2634 } else if (field_type
== PURPLE_REQUEST_FIELD_INTEGER
) {
2635 purple_request_field_int_set_value(setting
,
2636 gtk_spin_button_get_value_as_int(
2637 GTK_SPIN_BUTTON(widget
)));
2639 g_return_if_reached();
2643 keyring_page_add_settings_field(GtkBox
*vbox
, PurpleRequestField
*setting
,
2646 GtkWidget
*widget
, *hbox
;
2647 PurpleRequestFieldType field_type
;
2650 label
= purple_request_field_get_label(setting
);
2652 field_type
= purple_request_field_get_field_type(setting
);
2653 if (field_type
== PURPLE_REQUEST_FIELD_BOOLEAN
) {
2654 widget
= gtk_check_button_new_with_label(label
);
2656 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(widget
),
2657 purple_request_field_bool_get_value(setting
));
2658 g_signal_connect(G_OBJECT(widget
), "toggled",
2659 G_CALLBACK(keyring_page_settings_changed
), setting
);
2660 } else if (field_type
== PURPLE_REQUEST_FIELD_STRING
) {
2661 widget
= gtk_entry_new();
2662 gtk_entry_set_text(GTK_ENTRY(widget
),
2663 purple_request_field_string_get_value(setting
));
2664 if (purple_request_field_string_is_masked(setting
))
2665 gtk_entry_set_visibility(GTK_ENTRY(widget
), FALSE
);
2666 g_signal_connect(G_OBJECT(widget
), "changed",
2667 G_CALLBACK(keyring_page_settings_changed
), setting
);
2668 } else if (field_type
== PURPLE_REQUEST_FIELD_INTEGER
) {
2669 widget
= gtk_spin_button_new_with_range(
2670 purple_request_field_int_get_lower_bound(setting
),
2671 purple_request_field_int_get_upper_bound(setting
), 1);
2672 gtk_spin_button_set_value(GTK_SPIN_BUTTON(widget
),
2673 purple_request_field_int_get_value(setting
));
2674 g_signal_connect(G_OBJECT(widget
), "value-changed",
2675 G_CALLBACK(keyring_page_settings_changed
), setting
);
2677 purple_debug_error("gtkprefs", "Unsupported field type\n");
2681 hbox
= pidgin_add_widget_to_vbox(vbox
, label
, sg
, widget
,
2683 return ((void*)hbox
== (void*)vbox
) ? widget
: hbox
;
2686 /* XXX: it could be available for all plugins, not keyrings only */
2688 keyring_page_add_settings(PurpleRequestFields
*settings
)
2690 GList
*it
, *groups
, *added_fields
;
2693 sg
= gtk_size_group_new(GTK_SIZE_GROUP_HORIZONTAL
);
2695 added_fields
= NULL
;
2696 groups
= purple_request_fields_get_groups(settings
);
2697 for (it
= g_list_first(groups
); it
!= NULL
; it
= g_list_next(it
)) {
2698 GList
*it2
, *fields
;
2700 PurpleRequestFieldGroup
*group
;
2701 const gchar
*group_title
;
2704 group_title
= purple_request_field_group_get_title(group
);
2706 vbox
= GTK_BOX(pidgin_make_frame(
2707 GTK_WIDGET(keyring_vbox
), group_title
));
2708 added_fields
= g_list_prepend(added_fields
,
2709 g_object_get_data(G_OBJECT(vbox
), "main-vbox"));
2711 vbox
= keyring_vbox
;
2713 fields
= purple_request_field_group_get_fields(group
);
2714 for (it2
= g_list_first(fields
); it2
!= NULL
;
2715 it2
= g_list_next(it2
)) {
2716 GtkWidget
*added
= keyring_page_add_settings_field(vbox
,
2718 if (added
== NULL
|| vbox
!= keyring_vbox
)
2720 added_fields
= g_list_prepend(added_fields
, added
);
2726 return added_fields
;
2730 keyring_page_settings_apply(GtkButton
*button
, gpointer _unused
)
2732 if (!purple_keyring_apply_settings(prefs
, keyring_settings
))
2735 gtk_widget_set_sensitive(keyring_apply
, FALSE
);
2739 keyring_page_update_settings()
2741 if (keyring_settings
!= NULL
)
2742 purple_request_fields_destroy(keyring_settings
);
2743 keyring_settings
= purple_keyring_read_settings();
2744 if (!keyring_settings
)
2747 keyring_settings_fields
= keyring_page_add_settings(keyring_settings
);
2749 keyring_apply
= gtk_button_new_with_mnemonic(_("_Apply"));
2750 gtk_box_pack_start(keyring_vbox
, keyring_apply
, FALSE
, FALSE
, 1);
2751 gtk_widget_set_sensitive(keyring_apply
, FALSE
);
2752 keyring_settings_fields
= g_list_prepend(keyring_settings_fields
,
2754 g_signal_connect(G_OBJECT(keyring_apply
), "clicked",
2755 G_CALLBACK(keyring_page_settings_apply
), NULL
);
2757 gtk_widget_show_all(keyring_page_instance
);
2761 keyring_page_pref_set_inuse(GError
*error
, gpointer _keyring_page_instance
)
2763 PurpleKeyring
*in_use
= purple_keyring_get_inuse();
2765 if (_keyring_page_instance
!= keyring_page_instance
) {
2766 purple_debug_info("gtkprefs", "pref window already closed\n");
2770 gtk_widget_set_sensitive(GTK_WIDGET(keyring_combo
), TRUE
);
2772 if (error
!= NULL
) {
2773 pidgin_prefs_dropdown_revert_active(keyring_combo
);
2774 purple_notify_error(NULL
, _("Keyring"),
2775 _("Failed to set new keyring"), error
->message
, NULL
);
2779 g_return_if_fail(in_use
!= NULL
);
2780 purple_prefs_set_string("/purple/keyring/active",
2781 purple_keyring_get_id(in_use
));
2783 keyring_page_update_settings();
2787 keyring_page_pref_changed(GtkComboBox
*combo_box
, PidginPrefValue value
)
2789 const char *keyring_id
;
2790 PurpleKeyring
*keyring
;
2793 g_return_if_fail(combo_box
!= NULL
);
2794 g_return_if_fail(value
.type
== PURPLE_PREF_STRING
);
2796 keyring_id
= value
.value
.string
;
2797 keyring
= purple_keyring_find_keyring_by_id(keyring_id
);
2798 if (keyring
== NULL
) {
2799 pidgin_prefs_dropdown_revert_active(keyring_combo
);
2800 purple_notify_error(NULL
, _("Keyring"),
2801 _("Selected keyring is disabled"), NULL
, NULL
);
2805 gtk_widget_set_sensitive(GTK_WIDGET(combo_box
), FALSE
);
2807 for (it
= keyring_settings_fields
; it
!= NULL
; it
= g_list_next(it
))
2809 GtkWidget
*widget
= it
->data
;
2810 gtk_container_remove(
2811 GTK_CONTAINER(gtk_widget_get_parent(widget
)), widget
);
2813 gtk_widget_show_all(keyring_page_instance
);
2814 g_list_free(keyring_settings_fields
);
2815 keyring_settings_fields
= NULL
;
2816 if (keyring_settings
)
2817 purple_request_fields_destroy(keyring_settings
);
2818 keyring_settings
= NULL
;
2820 purple_keyring_set_inuse(keyring
, FALSE
, keyring_page_pref_set_inuse
,
2821 keyring_page_instance
);
2825 keyring_page_cleanup(void)
2827 keyring_page_instance
= NULL
;
2828 keyring_combo
= NULL
;
2829 keyring_vbox
= NULL
;
2830 g_list_free(keyring_settings_fields
);
2831 keyring_settings_fields
= NULL
;
2832 if (keyring_settings
)
2833 purple_request_fields_destroy(keyring_settings
);
2834 keyring_settings
= NULL
;
2835 keyring_apply
= NULL
;
2842 PidginPrefValue initial
;
2844 g_return_val_if_fail(keyring_page_instance
== NULL
,
2845 keyring_page_instance
);
2847 keyring_page_instance
= gtk_box_new(GTK_ORIENTATION_VERTICAL
, PIDGIN_HIG_CAT_SPACE
);
2848 gtk_container_set_border_width(GTK_CONTAINER(keyring_page_instance
),
2851 /* Keyring selection */
2852 keyring_vbox
= GTK_BOX(pidgin_make_frame(keyring_page_instance
,
2854 names
= purple_keyring_get_options();
2855 initial
.type
= PURPLE_PREF_STRING
;
2856 initial
.value
.string
= purple_prefs_get_string("/purple/keyring/active");
2857 pidgin_prefs_dropdown_from_list_with_cb(GTK_WIDGET(keyring_vbox
),
2858 _("Keyring:"), &keyring_combo
, names
, initial
,
2859 keyring_page_pref_changed
);
2862 keyring_page_update_settings();
2864 gtk_widget_show_all(keyring_page_instance
);
2866 return keyring_page_instance
;
2869 /*** keyring page - end *************************************************/
2872 sound_cmd_yeah(GtkEntry
*entry
, gpointer d
)
2874 purple_prefs_set_path(PIDGIN_PREFS_ROOT
"/sound/command",
2875 gtk_entry_get_text(GTK_ENTRY(entry
)));
2880 sound_changed1_cb(const char *name
, PurplePrefType type
,
2881 gconstpointer value
, gpointer data
)
2883 GtkWidget
*hbox
= data
;
2884 const char *method
= value
;
2886 gtk_widget_set_sensitive(hbox
, !strcmp(method
, "custom"));
2890 sound_changed2_cb(const char *name
, PurplePrefType type
,
2891 gconstpointer value
, gpointer data
)
2893 GtkWidget
*vbox
= data
;
2894 const char *method
= value
;
2896 gtk_widget_set_sensitive(vbox
, strcmp(method
, "none"));
2901 event_toggled(GtkCellRendererToggle
*cell
, gchar
*pth
, gpointer data
)
2903 GtkTreeModel
*model
= (GtkTreeModel
*)data
;
2905 GtkTreePath
*path
= gtk_tree_path_new_from_string(pth
);
2908 gtk_tree_model_get_iter (model
, &iter
, path
);
2909 gtk_tree_model_get (model
, &iter
,
2913 purple_prefs_set_bool(pref
, !gtk_cell_renderer_toggle_get_active(cell
));
2916 gtk_list_store_set(GTK_LIST_STORE (model
), &iter
,
2917 0, !gtk_cell_renderer_toggle_get_active(cell
),
2920 gtk_tree_path_free(path
);
2924 test_sound(GtkWidget
*button
, gpointer i_am_NULL
)
2927 gboolean temp_enabled
;
2930 pref
= g_strdup_printf(PIDGIN_PREFS_ROOT
"/sound/enabled/%s",
2931 pidgin_sound_get_event_option(sound_row_sel
));
2933 temp_enabled
= purple_prefs_get_bool(pref
);
2934 temp_mute
= purple_prefs_get_bool(PIDGIN_PREFS_ROOT
"/sound/mute");
2936 if (!temp_enabled
) purple_prefs_set_bool(pref
, TRUE
);
2937 if (temp_mute
) purple_prefs_set_bool(PIDGIN_PREFS_ROOT
"/sound/mute", FALSE
);
2939 purple_sound_play_event(sound_row_sel
, NULL
);
2941 if (!temp_enabled
) purple_prefs_set_bool(pref
, FALSE
);
2942 if (temp_mute
) purple_prefs_set_bool(PIDGIN_PREFS_ROOT
"/sound/mute", TRUE
);
2948 * Resets a sound file back to default.
2951 reset_sound(GtkWidget
*button
, gpointer i_am_also_NULL
)
2955 pref
= g_strdup_printf(PIDGIN_PREFS_ROOT
"/sound/file/%s",
2956 pidgin_sound_get_event_option(sound_row_sel
));
2957 purple_prefs_set_path(pref
, "");
2960 gtk_entry_set_text(GTK_ENTRY(sound_entry
), _("(default)"));
2962 pref_sound_generate_markup();
2966 sound_chosen_cb(void *user_data
, const char *filename
)
2971 sound
= GPOINTER_TO_INT(user_data
);
2973 /* Set it -- and forget it */
2974 pref
= g_strdup_printf(PIDGIN_PREFS_ROOT
"/sound/file/%s",
2975 pidgin_sound_get_event_option(sound
));
2976 purple_prefs_set_path(pref
, filename
);
2980 * If the sound we just changed is still the currently selected
2981 * sound, then update the box showing the file name.
2983 if (sound
== sound_row_sel
)
2984 gtk_entry_set_text(GTK_ENTRY(sound_entry
), filename
);
2986 pref_sound_generate_markup();
2990 select_sound(GtkWidget
*button
, gpointer being_NULL_is_fun
)
2993 const char *filename
;
2995 pref
= g_strdup_printf(PIDGIN_PREFS_ROOT
"/sound/file/%s",
2996 pidgin_sound_get_event_option(sound_row_sel
));
2997 filename
= purple_prefs_get_path(pref
);
3000 if (*filename
== '\0')
3003 purple_request_file(prefs
, _("Sound Selection"), filename
, FALSE
,
3004 G_CALLBACK(sound_chosen_cb
), NULL
, NULL
,
3005 GINT_TO_POINTER(sound_row_sel
));
3009 prefs_sound_sel(GtkTreeSelection
*sel
, GtkTreeModel
*model
)
3016 if (! gtk_tree_selection_get_selected (sel
, &model
, &iter
))
3020 gtk_tree_model_get_value (model
, &iter
, 3, &val
);
3021 sound_row_sel
= g_value_get_uint(&val
);
3023 pref
= g_strdup_printf(PIDGIN_PREFS_ROOT
"/sound/file/%s",
3024 pidgin_sound_get_event_option(sound_row_sel
));
3025 file
= purple_prefs_get_path(pref
);
3028 gtk_entry_set_text(GTK_ENTRY(sound_entry
), (file
&& *file
!= '\0') ? file
: _("(default)"));
3029 g_value_unset (&val
);
3031 pref_sound_generate_markup();
3036 mute_changed_cb(const char *pref_name
,
3037 PurplePrefType pref_type
,
3041 GtkToggleButton
*button
= data
;
3042 gboolean muted
= GPOINTER_TO_INT(val
);
3044 g_return_if_fail(!strcmp (pref_name
, PIDGIN_PREFS_ROOT
"/sound/mute"));
3046 /* Block the handler that re-sets the preference. */
3047 g_signal_handlers_block_matched(button
, G_SIGNAL_MATCH_DATA
, 0, 0, NULL
, NULL
, (gpointer
)pref_name
);
3048 gtk_toggle_button_set_active (button
, muted
);
3049 g_signal_handlers_unblock_matched(button
, G_SIGNAL_MATCH_DATA
, 0, 0, NULL
, NULL
, (gpointer
)pref_name
);
3057 GtkWidget
*vbox
, *vbox2
, *button
, *parent
, *parent_parent
, *parent_parent_parent
;
3060 GtkWidget
*event_view
;
3061 GtkListStore
*event_store
;
3062 GtkCellRenderer
*rend
;
3063 GtkTreeViewColumn
*col
;
3064 GtkTreeSelection
*sel
;
3074 ret
= gtk_box_new(GTK_ORIENTATION_VERTICAL
, PIDGIN_HIG_CAT_SPACE
);
3075 gtk_container_set_border_width (GTK_CONTAINER (ret
), PIDGIN_HIG_BORDER
);
3077 sg
= gtk_size_group_new(GTK_SIZE_GROUP_HORIZONTAL
);
3079 vbox2
= pidgin_make_frame(ret
, _("Sound Options"));
3081 vbox
= gtk_box_new(GTK_ORIENTATION_VERTICAL
, PIDGIN_HIG_BOX_SPACE
);
3082 gtk_box_pack_start(GTK_BOX(vbox2
), vbox
, FALSE
, FALSE
, 0);
3084 dd
= pidgin_prefs_dropdown(vbox2
, _("_Method:"), PURPLE_PREF_STRING
,
3085 PIDGIN_PREFS_ROOT
"/sound/method",
3086 _("Automatic"), "automatic",
3087 #ifdef USE_GSTREAMER
3089 /* "WaveForm", "waveform", */
3090 "DirectSound", "directsound",
3095 #endif /* USE_GSTREAMER */
3097 "PlaySound", "playsoundw",
3099 _("Console beep"), "beep",
3100 _("Command"), "custom",
3102 _("No sounds"), "none",
3104 gtk_size_group_add_widget(sg
, dd
);
3105 gtk_widget_set_halign(dd
, GTK_ALIGN_START
);
3106 gtk_widget_set_valign(dd
, GTK_ALIGN_CENTER
);
3108 entry
= gtk_entry_new();
3109 gtk_editable_set_editable(GTK_EDITABLE(entry
), TRUE
);
3110 cmd
= purple_prefs_get_path(PIDGIN_PREFS_ROOT
"/sound/command");
3112 gtk_entry_set_text(GTK_ENTRY(entry
), cmd
);
3113 g_signal_connect(G_OBJECT(entry
), "changed",
3114 G_CALLBACK(sound_cmd_yeah
), NULL
);
3116 hbox
= pidgin_add_widget_to_vbox(GTK_BOX(vbox
), _("Sound c_ommand:\n(%s for filename)"), sg
, entry
, TRUE
, NULL
);
3117 purple_prefs_connect_callback(prefs
, PIDGIN_PREFS_ROOT
"/sound/method",
3118 sound_changed1_cb
, hbox
);
3119 gtk_widget_set_sensitive(hbox
,
3120 !strcmp(purple_prefs_get_string(PIDGIN_PREFS_ROOT
"/sound/method"),
3123 button
= pidgin_prefs_checkbox(_("M_ute sounds"), PIDGIN_PREFS_ROOT
"/sound/mute", vbox
);
3124 purple_prefs_connect_callback(prefs
, PIDGIN_PREFS_ROOT
"/sound/mute", mute_changed_cb
, button
);
3126 pidgin_prefs_checkbox(_("Sounds when conversation has _focus"),
3127 PIDGIN_PREFS_ROOT
"/sound/conv_focus", vbox
);
3128 pidgin_prefs_dropdown(vbox
, _("_Enable sounds:"),
3129 PURPLE_PREF_INT
, "/purple/sound/while_status",
3130 _("Only when available"), PURPLE_SOUND_STATUS_AVAILABLE
,
3131 _("Only when not available"), PURPLE_SOUND_STATUS_AWAY
,
3132 _("Always"), PURPLE_SOUND_STATUS_ALWAYS
,
3135 gtk_widget_set_sensitive(vbox
,
3136 strcmp(purple_prefs_get_string(PIDGIN_PREFS_ROOT
"/sound/method"), "none"));
3137 purple_prefs_connect_callback(prefs
, PIDGIN_PREFS_ROOT
"/sound/method",
3138 sound_changed2_cb
, vbox
);
3139 vbox
= pidgin_make_frame(ret
, _("Sound Events"));
3141 /* The following is an ugly hack to make the frame expand so the
3142 * sound events list is big enough to be usable */
3143 parent
= gtk_widget_get_parent(vbox
);
3144 parent_parent
= gtk_widget_get_parent(parent
);
3145 parent_parent_parent
= gtk_widget_get_parent(parent_parent
);
3146 gtk_box_set_child_packing(GTK_BOX(parent
), vbox
, TRUE
, TRUE
, 0,
3148 gtk_box_set_child_packing(GTK_BOX(parent_parent
),
3149 parent
, TRUE
, TRUE
, 0, GTK_PACK_START
);
3150 gtk_box_set_child_packing(GTK_BOX(parent_parent_parent
),
3151 parent_parent
, TRUE
, TRUE
, 0, GTK_PACK_START
);
3153 /* SOUND SELECTION */
3154 event_store
= gtk_list_store_new (4, G_TYPE_BOOLEAN
, G_TYPE_STRING
, G_TYPE_STRING
, G_TYPE_UINT
);
3156 for (j
=0; j
< PURPLE_NUM_SOUNDS
; j
++) {
3157 char *pref
= g_strdup_printf(PIDGIN_PREFS_ROOT
"/sound/enabled/%s",
3158 pidgin_sound_get_event_option(j
));
3159 const char *label
= pidgin_sound_get_event_label(j
);
3161 if (label
== NULL
) {
3166 gtk_list_store_append (event_store
, &iter
);
3167 gtk_list_store_set(event_store
, &iter
,
3168 0, purple_prefs_get_bool(pref
),
3176 event_view
= gtk_tree_view_new_with_model (GTK_TREE_MODEL(event_store
));
3178 rend
= gtk_cell_renderer_toggle_new();
3179 sel
= gtk_tree_view_get_selection (GTK_TREE_VIEW (event_view
));
3180 g_signal_connect (G_OBJECT (sel
), "changed",
3181 G_CALLBACK (prefs_sound_sel
),
3183 g_signal_connect (G_OBJECT(rend
), "toggled",
3184 G_CALLBACK(event_toggled
), event_store
);
3185 path
= gtk_tree_path_new_first();
3186 gtk_tree_selection_select_path(sel
, path
);
3187 gtk_tree_path_free(path
);
3189 col
= gtk_tree_view_column_new_with_attributes (_("Play"),
3193 gtk_tree_view_append_column (GTK_TREE_VIEW(event_view
), col
);
3195 rend
= gtk_cell_renderer_text_new();
3196 col
= gtk_tree_view_column_new_with_attributes (_("Event"),
3200 gtk_tree_view_append_column (GTK_TREE_VIEW(event_view
), col
);
3201 g_object_unref(G_OBJECT(event_store
));
3202 gtk_box_pack_start(GTK_BOX(vbox
),
3203 pidgin_make_scrollable(event_view
, GTK_POLICY_NEVER
, GTK_POLICY_AUTOMATIC
, GTK_SHADOW_IN
, -1, 100),
3206 hbox
= gtk_box_new(GTK_ORIENTATION_HORIZONTAL
, PIDGIN_HIG_BOX_SPACE
);
3207 gtk_box_pack_start(GTK_BOX(vbox
), hbox
, FALSE
, FALSE
, 0);
3208 sound_entry
= gtk_entry_new();
3209 pref
= g_strdup_printf(PIDGIN_PREFS_ROOT
"/sound/file/%s",
3210 pidgin_sound_get_event_option(0));
3211 file
= purple_prefs_get_path(pref
);
3213 gtk_entry_set_text(GTK_ENTRY(sound_entry
), (file
&& *file
!= '\0') ? file
: _("(default)"));
3214 gtk_editable_set_editable(GTK_EDITABLE(sound_entry
), FALSE
);
3215 gtk_box_pack_start(GTK_BOX(hbox
), sound_entry
, FALSE
, FALSE
, PIDGIN_HIG_BOX_SPACE
);
3217 button
= gtk_button_new_with_mnemonic(_("_Browse..."));
3218 g_signal_connect(G_OBJECT(button
), "clicked", G_CALLBACK(select_sound
), NULL
);
3219 gtk_box_pack_start(GTK_BOX(hbox
), button
, FALSE
, FALSE
, 1);
3221 button
= gtk_button_new_with_mnemonic(_("Pre_view"));
3222 g_signal_connect(G_OBJECT(button
), "clicked", G_CALLBACK(test_sound
), NULL
);
3223 gtk_box_pack_start(GTK_BOX(hbox
), button
, FALSE
, FALSE
, 1);
3225 button
= gtk_button_new_with_mnemonic(_("_Reset"));
3226 g_signal_connect(G_OBJECT(button
), "clicked", G_CALLBACK(reset_sound
), NULL
);
3227 gtk_box_pack_start(GTK_BOX(hbox
), button
, FALSE
, FALSE
, 1);
3229 gtk_widget_show_all(ret
);
3237 set_idle_away(PurpleSavedStatus
*status
)
3239 purple_prefs_set_int("/purple/savedstatus/idleaway", purple_savedstatus_get_creation_time(status
));
3243 set_startupstatus(PurpleSavedStatus
*status
)
3245 purple_prefs_set_int("/purple/savedstatus/startup", purple_savedstatus_get_creation_time(status
));
3260 ret
= gtk_box_new(GTK_ORIENTATION_VERTICAL
, PIDGIN_HIG_CAT_SPACE
);
3261 gtk_container_set_border_width (GTK_CONTAINER (ret
), PIDGIN_HIG_BORDER
);
3263 sg
= gtk_size_group_new(GTK_SIZE_GROUP_HORIZONTAL
);
3266 vbox
= pidgin_make_frame(ret
, _("Idle"));
3268 dd
= pidgin_prefs_dropdown(vbox
, _("_Report idle time:"),
3269 PURPLE_PREF_STRING
, "/purple/away/idle_reporting",
3271 _("From last sent message"), "purple",
3272 #if defined(USE_SCREENSAVER) || defined(HAVE_IOKIT)
3273 _("Based on keyboard or mouse use"), "system",
3276 gtk_size_group_add_widget(sg
, dd
);
3277 gtk_widget_set_halign(dd
, GTK_ALIGN_START
);
3278 gtk_widget_set_valign(dd
, GTK_ALIGN_CENTER
);
3280 pidgin_prefs_labeled_spin_button(vbox
,
3281 _("_Minutes before becoming idle:"), "/purple/away/mins_before_away",
3284 hbox
= gtk_box_new(GTK_ORIENTATION_HORIZONTAL
, PIDGIN_HIG_BOX_SPACE
);
3285 gtk_box_pack_start(GTK_BOX(vbox
), hbox
, FALSE
, FALSE
, 0);
3287 button
= pidgin_prefs_checkbox(_("Change to this status when _idle:"),
3288 "/purple/away/away_when_idle", hbox
);
3289 gtk_size_group_add_widget(sg
, button
);
3291 /* TODO: Show something useful if we don't have any saved statuses. */
3292 menu
= pidgin_status_menu(purple_savedstatus_get_idleaway(), G_CALLBACK(set_idle_away
));
3293 gtk_size_group_add_widget(sg
, menu
);
3294 gtk_box_pack_start(GTK_BOX(hbox
), menu
, FALSE
, FALSE
, 0);
3296 g_signal_connect(G_OBJECT(button
), "clicked",
3297 G_CALLBACK(pidgin_toggle_sensitive
), menu
);
3299 if(!purple_prefs_get_bool("/purple/away/away_when_idle"))
3300 gtk_widget_set_sensitive(GTK_WIDGET(menu
), FALSE
);
3303 vbox
= pidgin_make_frame(ret
, _("Away"));
3305 dd
= pidgin_prefs_dropdown(vbox
, _("_Auto-reply:"),
3306 PURPLE_PREF_STRING
, "/purple/away/auto_reply",
3307 _("Never"), "never",
3308 _("When away"), "away",
3309 _("When both away and idle"), "awayidle",
3311 gtk_size_group_add_widget(sg
, dd
);
3312 gtk_widget_set_halign(dd
, GTK_ALIGN_START
);
3313 gtk_widget_set_valign(dd
, GTK_ALIGN_CENTER
);
3315 /* Signon status stuff */
3316 vbox
= pidgin_make_frame(ret
, _("Status at Startup"));
3318 button
= pidgin_prefs_checkbox(_("Use status from last _exit at startup"),
3319 "/purple/savedstatus/startup_current_status", vbox
);
3320 gtk_size_group_add_widget(sg
, button
);
3322 /* TODO: Show something useful if we don't have any saved statuses. */
3323 menu
= pidgin_status_menu(purple_savedstatus_get_startup(), G_CALLBACK(set_startupstatus
));
3324 gtk_size_group_add_widget(sg
, menu
);
3325 g_signal_connect(G_OBJECT(button
), "clicked",
3326 G_CALLBACK(pidgin_toggle_sensitive
), menu
);
3327 pidgin_add_widget_to_vbox(GTK_BOX(vbox
), _("Status to a_pply at startup:"), sg
, menu
, TRUE
, &label
);
3328 g_signal_connect(G_OBJECT(button
), "clicked",
3329 G_CALLBACK(pidgin_toggle_sensitive
), label
);
3331 if(purple_prefs_get_bool("/purple/savedstatus/startup_current_status")) {
3332 gtk_widget_set_sensitive(GTK_WIDGET(menu
), FALSE
);
3333 gtk_widget_set_sensitive(GTK_WIDGET(label
), FALSE
);
3336 gtk_widget_show_all(ret
);
3344 get_vv_device_menuitems(PurpleMediaElementType type
)
3346 GList
*result
= NULL
;
3349 i
= purple_media_manager_enumerate_elements(purple_media_manager_get(),
3351 for (; i
; i
= g_list_delete_link(i
, i
)) {
3352 PurpleMediaElementInfo
*info
= i
->data
;
3354 result
= g_list_append(result
,
3355 purple_media_element_info_get_name(info
));
3356 result
= g_list_append(result
,
3357 purple_media_element_info_get_id(info
));
3358 g_object_unref(info
);
3365 create_test_element(PurpleMediaElementType type
)
3367 PurpleMediaElementInfo
*element_info
;
3369 element_info
= purple_media_manager_get_active_element(purple_media_manager_get(), type
);
3371 g_return_val_if_fail(element_info
, NULL
);
3373 return purple_media_element_info_call_create(element_info
,
3378 vv_test_switch_page_cb(GtkNotebook
*notebook
, GtkWidget
*page
, guint num
, gpointer data
)
3380 GtkWidget
*test
= data
;
3381 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(test
), FALSE
);
3385 create_voice_pipeline(void)
3387 GstElement
*pipeline
;
3388 GstElement
*src
, *sink
;
3393 pipeline
= gst_pipeline_new("voicetest");
3395 src
= create_test_element(PURPLE_MEDIA_ELEMENT_AUDIO
| PURPLE_MEDIA_ELEMENT_SRC
);
3396 sink
= create_test_element(PURPLE_MEDIA_ELEMENT_AUDIO
| PURPLE_MEDIA_ELEMENT_SINK
);
3397 volume
= gst_element_factory_make("volume", "volume");
3398 level
= gst_element_factory_make("level", "level");
3399 valve
= gst_element_factory_make("valve", "valve");
3401 gst_bin_add_many(GST_BIN(pipeline
), src
, volume
, level
, valve
, sink
, NULL
);
3402 gst_element_link_many(src
, volume
, level
, valve
, sink
, NULL
);
3404 purple_debug_info("gtkprefs", "create_voice_pipeline: setting pipeline "
3405 "state to GST_STATE_PLAYING - it may hang here on win32\n");
3406 gst_element_set_state(GST_ELEMENT(pipeline
), GST_STATE_PLAYING
);
3407 purple_debug_info("gtkprefs", "create_voice_pipeline: state is set\n");
3413 on_volume_change_cb(GtkWidget
*w
, gdouble value
, gpointer data
)
3417 if (!voice_pipeline
)
3420 volume
= gst_bin_get_by_name(GST_BIN(voice_pipeline
), "volume");
3421 g_object_set(volume
, "volume",
3422 gtk_scale_button_get_value(GTK_SCALE_BUTTON(w
)) * 10.0, NULL
);
3426 gst_msg_db_to_percent(GstMessage
*msg
, gchar
*value_name
)
3429 const GValue
*value
;
3433 list
= gst_structure_get_value(gst_message_get_structure(msg
), value_name
);
3434 #if GST_CHECK_VERSION(1,0,0)
3435 G_GNUC_BEGIN_IGNORE_DEPRECATIONS
3436 value
= g_value_array_get_nth(g_value_get_boxed(list
), 0);
3437 G_GNUC_END_IGNORE_DEPRECATIONS
3439 value
= gst_value_list_get_value(list
, 0);
3441 value_db
= g_value_get_double(value
);
3442 percent
= pow(10, value_db
/ 20);
3443 return (percent
> 1.0) ? 1.0 : percent
;
3447 gst_bus_cb(GstBus
*bus
, GstMessage
*msg
, gpointer data
)
3449 if (GST_MESSAGE_TYPE(msg
) == GST_MESSAGE_ELEMENT
&&
3450 gst_structure_has_name(gst_message_get_structure(msg
), "level")) {
3452 GstElement
*src
= GST_ELEMENT(GST_MESSAGE_SRC(msg
));
3453 gchar
*name
= gst_element_get_name(src
);
3455 if (!strcmp(name
, "level")) {
3460 percent
= gst_msg_db_to_percent(msg
, "rms");
3461 gtk_progress_bar_set_fraction(GTK_PROGRESS_BAR(voice_level
), percent
);
3463 percent
= gst_msg_db_to_percent(msg
, "decay");
3464 threshold
= gtk_range_get_value(GTK_RANGE(voice_threshold
)) / 100.0;
3465 valve
= gst_bin_get_by_name(GST_BIN(GST_ELEMENT_PARENT(src
)), "valve");
3466 g_object_set(valve
, "drop", (percent
< threshold
), NULL
);
3467 g_object_set(voice_level
, "text",
3468 (percent
< threshold
) ? _("DROP") : " ", NULL
);
3478 voice_test_destroy_cb(GtkWidget
*w
, gpointer data
)
3480 if (!voice_pipeline
)
3483 gst_element_set_state(voice_pipeline
, GST_STATE_NULL
);
3484 gst_object_unref(voice_pipeline
);
3485 voice_pipeline
= NULL
;
3489 enable_voice_test(void)
3493 voice_pipeline
= create_voice_pipeline();
3494 bus
= gst_pipeline_get_bus(GST_PIPELINE(voice_pipeline
));
3495 gst_bus_add_signal_watch(bus
);
3496 g_signal_connect(bus
, "message", G_CALLBACK(gst_bus_cb
), NULL
);
3497 gst_object_unref(bus
);
3501 toggle_voice_test_cb(GtkToggleButton
*test
, gpointer data
)
3503 if (gtk_toggle_button_get_active(test
)) {
3504 gtk_widget_set_sensitive(voice_level
, TRUE
);
3505 enable_voice_test();
3507 g_signal_connect(voice_volume
, "value-changed",
3508 G_CALLBACK(on_volume_change_cb
), NULL
);
3509 g_signal_connect(test
, "destroy",
3510 G_CALLBACK(voice_test_destroy_cb
), NULL
);
3511 g_signal_connect(prefsnotebook
, "switch-page",
3512 G_CALLBACK(vv_test_switch_page_cb
), test
);
3514 gtk_progress_bar_set_fraction(GTK_PROGRESS_BAR(voice_level
), 0.0);
3515 gtk_widget_set_sensitive(voice_level
, FALSE
);
3516 g_object_disconnect(voice_volume
, "any-signal::value-changed",
3517 G_CALLBACK(on_volume_change_cb
), NULL
,
3519 g_object_disconnect(test
, "any-signal::destroy",
3520 G_CALLBACK(voice_test_destroy_cb
), NULL
,
3522 g_object_disconnect(prefsnotebook
, "any-signal::switch-page",
3523 G_CALLBACK(vv_test_switch_page_cb
), test
,
3525 voice_test_destroy_cb(NULL
, NULL
);
3530 volume_changed_cb(GtkScaleButton
*button
, gdouble value
, gpointer data
)
3532 purple_prefs_set_int("/purple/media/audio/volume/input", value
* 100);
3536 threshold_value_changed_cb(GtkScale
*scale
, GtkWidget
*label
)
3541 value
= (int)gtk_range_get_value(GTK_RANGE(scale
));
3542 tmp
= g_strdup_printf(_("Silence threshold: %d%%"), value
);
3543 gtk_label_set_label(GTK_LABEL(label
), tmp
);
3546 purple_prefs_set_int("/purple/media/audio/silence_threshold", value
);
3550 make_voice_test(GtkWidget
*vbox
)
3557 GtkWidget
*threshold
;
3560 label
= gtk_label_new(NULL
);
3561 gtk_box_pack_start(GTK_BOX(vbox
), label
, TRUE
, TRUE
, 0);
3563 hbox
= gtk_box_new(GTK_ORIENTATION_HORIZONTAL
, PIDGIN_HIG_CAT_SPACE
);
3564 gtk_box_pack_start(GTK_BOX(vbox
), hbox
, FALSE
, FALSE
, 0);
3565 label
= gtk_label_new(_("Volume:"));
3566 gtk_box_pack_start(GTK_BOX(hbox
), label
, FALSE
, FALSE
, 0);
3567 volume
= gtk_volume_button_new();
3568 gtk_box_pack_start(GTK_BOX(hbox
), volume
, TRUE
, TRUE
, 0);
3569 gtk_scale_button_set_value(GTK_SCALE_BUTTON(volume
),
3570 purple_prefs_get_int("/purple/media/audio/volume/input") / 100.0);
3571 g_signal_connect(volume
, "value-changed",
3572 G_CALLBACK(volume_changed_cb
), NULL
);
3574 tmp
= g_strdup_printf(_("Silence threshold: %d%%"),
3575 purple_prefs_get_int("/purple/media/audio/silence_threshold"));
3576 label
= gtk_label_new(tmp
);
3577 gtk_box_pack_start(GTK_BOX(vbox
), label
, FALSE
, FALSE
, 0);
3578 gtk_widget_set_halign(label
, GTK_ALIGN_START
);
3579 gtk_widget_set_valign(label
, GTK_ALIGN_CENTER
);
3581 threshold
= gtk_scale_new_with_range(GTK_ORIENTATION_HORIZONTAL
,
3583 gtk_box_pack_start(GTK_BOX(vbox
), threshold
, FALSE
, FALSE
, 0);
3584 gtk_range_set_value(GTK_RANGE(threshold
),
3585 purple_prefs_get_int("/purple/media/audio/silence_threshold"));
3586 gtk_scale_set_draw_value(GTK_SCALE(threshold
), FALSE
);
3587 g_signal_connect(threshold
, "value-changed",
3588 G_CALLBACK(threshold_value_changed_cb
), label
);
3590 test
= gtk_toggle_button_new_with_label(_("Test Audio"));
3591 gtk_box_pack_start(GTK_BOX(vbox
), test
, FALSE
, FALSE
, 0);
3593 level
= gtk_progress_bar_new();
3594 gtk_box_pack_start(GTK_BOX(vbox
), level
, FALSE
, FALSE
, 0);
3595 gtk_widget_set_sensitive(level
, FALSE
);
3597 voice_volume
= volume
;
3598 voice_level
= level
;
3599 voice_threshold
= threshold
;
3600 g_signal_connect(test
, "toggled",
3601 G_CALLBACK(toggle_voice_test_cb
), NULL
);
3605 create_video_pipeline(void)
3607 GstElement
*pipeline
;
3608 GstElement
*src
, *sink
;
3609 GstElement
*videoconvert
;
3610 GstElement
*videoscale
;
3612 pipeline
= gst_pipeline_new("videotest");
3613 src
= create_test_element(PURPLE_MEDIA_ELEMENT_VIDEO
| PURPLE_MEDIA_ELEMENT_SRC
);
3614 sink
= create_test_element(PURPLE_MEDIA_ELEMENT_VIDEO
| PURPLE_MEDIA_ELEMENT_SINK
);
3615 videoconvert
= gst_element_factory_make("videoconvert", NULL
);
3616 videoscale
= gst_element_factory_make("videoscale", NULL
);
3618 g_object_set_data(G_OBJECT(pipeline
), "sink", sink
);
3620 gst_bin_add_many(GST_BIN(pipeline
), src
, videoconvert
, videoscale
, sink
,
3622 gst_element_link_many(src
, videoconvert
, videoscale
, sink
, NULL
);
3628 video_test_destroy_cb(GtkWidget
*w
, gpointer data
)
3630 if (!video_pipeline
)
3633 gst_element_set_state(video_pipeline
, GST_STATE_NULL
);
3634 gst_object_unref(video_pipeline
);
3635 video_pipeline
= NULL
;
3639 window_id_cb(GstBus
*bus
, GstMessage
*msg
, gulong window_id
)
3641 if (GST_MESSAGE_TYPE(msg
) != GST_MESSAGE_ELEMENT
3642 #if GST_CHECK_VERSION(1,0,0)
3643 || !gst_is_video_overlay_prepare_window_handle_message(msg
))
3645 /* there may be have-xwindow-id also, in case something went wrong */
3646 || !gst_structure_has_name(msg
->structure
, "prepare-xwindow-id"))
3650 g_signal_handlers_disconnect_matched(bus
,
3651 G_SIGNAL_MATCH_FUNC
| G_SIGNAL_MATCH_DATA
,
3652 0, 0, NULL
, window_id_cb
,
3653 (gpointer
)window_id
);
3655 #if GST_CHECK_VERSION(1,0,0)
3656 gst_video_overlay_set_window_handle(GST_VIDEO_OVERLAY(GST_MESSAGE_SRC(msg
)),
3658 #elif GST_CHECK_VERSION(0,10,31)
3659 gst_x_overlay_set_window_handle(GST_X_OVERLAY(GST_MESSAGE_SRC(msg
)),
3662 gst_x_overlay_set_xwindow_id(GST_X_OVERLAY(GST_MESSAGE_SRC(msg
)),
3668 enable_video_test(void)
3671 GdkWindow
*window
= gtk_widget_get_window(video_drawing_area
);
3672 gulong window_id
= 0;
3674 #ifdef GDK_WINDOWING_WIN32
3675 if (GDK_IS_WIN32_WINDOW(window
))
3676 window_id
= GPOINTER_TO_UINT(GDK_WINDOW_HWND(window
));
3679 #ifdef GDK_WINDOWING_X11
3680 if (GDK_IS_X11_WINDOW(window
))
3681 window_id
= gdk_x11_window_get_xid(window
);
3684 #ifdef GDK_WINDOWING_QUARTZ
3685 if (GDK_IS_QUARTZ_WINDOW(window
))
3686 window_id
= (gulong
)gdk_quartz_window_get_nsview(window
);
3689 g_warning("Unsupported GDK backend");
3690 #if !(defined(GDK_WINDOWING_WIN32) \
3691 || defined(GDK_WINDOWING_X11) \
3692 || defined(GDK_WINDOWING_QUARTZ))
3693 # error "Unsupported GDK windowing system"
3696 video_pipeline
= create_video_pipeline();
3697 bus
= gst_pipeline_get_bus(GST_PIPELINE(video_pipeline
));
3698 #if GST_CHECK_VERSION(1,0,0)
3699 gst_bus_set_sync_handler(bus
, gst_bus_sync_signal_handler
, NULL
, NULL
);
3701 gst_bus_set_sync_handler(bus
, gst_bus_sync_signal_handler
, NULL
);
3703 g_signal_connect(bus
, "sync-message::element",
3704 G_CALLBACK(window_id_cb
), (gpointer
)window_id
);
3705 gst_object_unref(bus
);
3707 gst_element_set_state(GST_ELEMENT(video_pipeline
), GST_STATE_PLAYING
);
3711 toggle_video_test_cb(GtkToggleButton
*test
, gpointer data
)
3713 if (gtk_toggle_button_get_active(test
)) {
3714 enable_video_test();
3715 g_signal_connect(test
, "destroy",
3716 G_CALLBACK(video_test_destroy_cb
), NULL
);
3717 g_signal_connect(prefsnotebook
, "switch-page",
3718 G_CALLBACK(vv_test_switch_page_cb
), test
);
3720 g_object_disconnect(test
, "any-signal::destroy",
3721 G_CALLBACK(video_test_destroy_cb
), NULL
,
3723 g_object_disconnect(prefsnotebook
, "any-signal::switch-page",
3724 G_CALLBACK(vv_test_switch_page_cb
), test
,
3726 video_test_destroy_cb(NULL
, NULL
);
3731 make_video_test(GtkWidget
*vbox
)
3736 video_drawing_area
= video
= pidgin_create_video_widget();
3737 gtk_box_pack_start(GTK_BOX(vbox
), video
, TRUE
, TRUE
, 0);
3738 gtk_widget_set_size_request(GTK_WIDGET(video
), 240, 180);
3740 test
= gtk_toggle_button_new_with_label(_("Test Video"));
3741 gtk_box_pack_start(GTK_BOX(vbox
), test
, FALSE
, FALSE
, 0);
3743 g_signal_connect(test
, "toggled",
3744 G_CALLBACK(toggle_video_test_cb
), NULL
);
3748 vv_device_changed_cb(const gchar
*name
, PurplePrefType type
,
3749 gconstpointer value
, gpointer data
)
3751 PurpleMediaManager
*manager
;
3752 PurpleMediaElementInfo
*info
;
3754 manager
= purple_media_manager_get();
3755 info
= purple_media_manager_get_element_info(manager
, value
);
3756 purple_media_manager_set_active_element(manager
, info
);
3758 /* Refresh test viewers */
3759 if (strstr(name
, "audio") && voice_pipeline
) {
3760 voice_test_destroy_cb(NULL
, NULL
);
3761 enable_voice_test();
3762 } else if(strstr(name
, "video") && video_pipeline
) {
3763 video_test_destroy_cb(NULL
, NULL
);
3764 enable_video_test();
3769 purple_media_type_to_preference_key(PurpleMediaElementType type
)
3771 if (type
& PURPLE_MEDIA_ELEMENT_AUDIO
) {
3772 if (type
& PURPLE_MEDIA_ELEMENT_SRC
) {
3773 return PIDGIN_PREFS_ROOT
"/vvconfig/audio/src/device";
3774 } else if (type
& PURPLE_MEDIA_ELEMENT_SINK
) {
3775 return PIDGIN_PREFS_ROOT
"/vvconfig/audio/sink/device";
3777 } else if (type
& PURPLE_MEDIA_ELEMENT_VIDEO
) {
3778 if (type
& PURPLE_MEDIA_ELEMENT_SRC
) {
3779 return PIDGIN_PREFS_ROOT
"/vvconfig/video/src/device";
3780 } else if (type
& PURPLE_MEDIA_ELEMENT_SINK
) {
3781 return PIDGIN_PREFS_ROOT
"/vvconfig/video/sink/device";
3789 make_vv_dropdown(GtkWidget
*parent
, GtkSizeGroup
*size_group
,
3790 PurpleMediaElementType element_type
)
3793 const gchar
*preference_key
;
3796 preference_key
= purple_media_type_to_preference_key(element_type
);
3797 devices
= get_vv_device_menuitems(element_type
);
3799 if (g_list_find_custom(devices
, purple_prefs_get_string(preference_key
),
3800 (GCompareFunc
)strcmp
) == NULL
)
3802 GList
*next
= g_list_next(devices
);
3804 purple_prefs_set_string(preference_key
, next
->data
);
3807 label
= pidgin_prefs_dropdown_from_list(parent
, _("_Device"),
3808 PURPLE_PREF_STRING
, preference_key
, devices
);
3810 g_list_free_full(devices
, g_free
);
3812 gtk_size_group_add_widget(size_group
, label
);
3813 gtk_widget_set_halign(label
, GTK_ALIGN_START
);
3814 gtk_widget_set_valign(label
, GTK_ALIGN_CENTER
);
3816 /* Return the parent GtkBox of dropdown and label, which was created
3817 * in pidgin_prefs_dropdown_from_list(). */
3818 return gtk_widget_get_parent(label
);
3822 make_vv_frame(GtkWidget
*parent
, GtkSizeGroup
*sg
,
3823 const gchar
*name
, PurpleMediaElementType type
)
3826 GtkWidget
*dropdown
;
3828 vbox
= pidgin_make_frame(parent
, name
);
3830 dropdown
= make_vv_dropdown(vbox
, sg
, type
);
3832 purple_prefs_connect_callback(vbox
,
3833 purple_media_type_to_preference_key(type
),
3834 vv_device_changed_cb
, vbox
);
3835 g_signal_connect_swapped(vbox
, "destroy",
3836 G_CALLBACK(purple_prefs_disconnect_by_handle
), vbox
);
3838 g_object_set_data(G_OBJECT(vbox
), "vv_frame", vbox
);
3839 g_object_set_data(G_OBJECT(vbox
), "vv_dropdown", dropdown
);
3840 g_object_set_data(G_OBJECT(vbox
), "vv_size_group", sg
);
3841 g_object_set_data(G_OBJECT(vbox
), "vv_media_type", (gpointer
)type
);
3847 device_list_changed_cb(PurpleMediaManager
*manager
, GtkWidget
*widget
)
3850 GtkWidget
*dropdown
;
3851 PurpleMediaElementType media_type
;
3853 gtk_widget_destroy(g_object_get_data(G_OBJECT(widget
), "vv_dropdown"));
3855 frame
= g_object_get_data(G_OBJECT(widget
), "vv_frame");
3856 media_type
= (PurpleMediaElementType
)g_object_get_data(G_OBJECT(widget
),
3859 dropdown
= make_vv_dropdown(frame
,
3860 g_object_get_data(G_OBJECT(widget
), "vv_size_group"),
3863 g_object_set_data(G_OBJECT(widget
), "vv_dropdown", dropdown
);
3873 PurpleMediaManager
*manager
;
3875 ret
= gtk_box_new(GTK_ORIENTATION_HORIZONTAL
, PIDGIN_HIG_CAT_SPACE
);
3876 gtk_container_set_border_width(GTK_CONTAINER(ret
), PIDGIN_HIG_BORDER
);
3878 sg
= gtk_size_group_new(GTK_SIZE_GROUP_HORIZONTAL
);
3880 manager
= purple_media_manager_get();
3882 vbox
= pidgin_make_frame(ret
, _("Audio"));
3883 frame
= make_vv_frame(vbox
, sg
, _("Input"),
3884 PURPLE_MEDIA_ELEMENT_AUDIO
| PURPLE_MEDIA_ELEMENT_SRC
);
3885 g_signal_connect_object(manager
, "elements-changed::audiosrc",
3886 G_CALLBACK(device_list_changed_cb
), frame
, 0);
3888 frame
= make_vv_frame(vbox
, sg
, _("Output"),
3889 PURPLE_MEDIA_ELEMENT_AUDIO
| PURPLE_MEDIA_ELEMENT_SINK
);
3890 g_signal_connect_object(manager
, "elements-changed::audiosink",
3891 G_CALLBACK(device_list_changed_cb
), frame
, 0);
3893 make_voice_test(vbox
);
3895 vbox
= pidgin_make_frame(ret
, _("Video"));
3896 frame
= make_vv_frame(vbox
, sg
, _("Input"),
3897 PURPLE_MEDIA_ELEMENT_VIDEO
| PURPLE_MEDIA_ELEMENT_SRC
);
3898 g_signal_connect_object(manager
, "elements-changed::videosrc",
3899 G_CALLBACK(device_list_changed_cb
), frame
, 0);
3901 frame
= make_vv_frame(vbox
, sg
, _("Output"),
3902 PURPLE_MEDIA_ELEMENT_VIDEO
| PURPLE_MEDIA_ELEMENT_SINK
);
3903 g_signal_connect_object(manager
, "elements-changed::videosink",
3904 G_CALLBACK(device_list_changed_cb
), frame
, 0);
3906 make_video_test(vbox
);
3908 gtk_widget_show_all(ret
);
3915 prefs_notebook_add_page(const char *text
, GtkWidget
*page
, int ind
)
3917 return gtk_notebook_append_page(GTK_NOTEBOOK(prefsnotebook
), page
, gtk_label_new(text
));
3921 prefs_notebook_init(void)
3923 prefs_notebook_add_page(_("Interface"), interface_page(), notebook_page
++);
3926 /* We use the registered default browser in windows */
3927 /* if the user is running Mac OS X, hide the browsers tab */
3928 if(purple_running_osx() == FALSE
)
3929 prefs_notebook_add_page(_("Browser"), browser_page(), notebook_page
++);
3932 prefs_notebook_add_page(_("Conversations"), conv_page(), notebook_page
++);
3933 prefs_notebook_add_page(_("Logging"), logging_page(), notebook_page
++);
3934 prefs_notebook_add_page(_("Network"), network_page(), notebook_page
++);
3935 prefs_notebook_add_page(_("Proxy"), proxy_page(), notebook_page
++);
3936 prefs_notebook_add_page(_("Password Storage"), keyring_page(), notebook_page
++);
3938 prefs_notebook_add_page(_("Sounds"), sound_page(), notebook_page
++);
3939 prefs_notebook_add_page(_("Status / Idle"), away_page(), notebook_page
++);
3940 prefs_notebook_add_page(_("Themes"), theme_page(), notebook_page
++);
3942 prefs_notebook_add_page(_("Voice/Video"), vv_page(), notebook_page
++);
3947 pidgin_prefs_show(void)
3950 GtkWidget
*notebook
;
3954 gtk_window_present(GTK_WINDOW(prefs
));
3958 /* copy the preferences to tmp values...
3959 * I liked "take affect immediately" Oh well :-( */
3960 /* (that should have been "effect," right?) */
3962 /* Back to instant-apply! I win! BU-HAHAHA! */
3964 /* Create the window */
3965 prefs
= pidgin_create_dialog(_("Preferences"), 0, "preferences", FALSE
);
3966 g_signal_connect(G_OBJECT(prefs
), "destroy",
3967 G_CALLBACK(delete_prefs
), NULL
);
3969 vbox
= pidgin_dialog_get_vbox_with_properties(GTK_DIALOG(prefs
), FALSE
, PIDGIN_HIG_BORDER
);
3972 prefsnotebook
= notebook
= gtk_notebook_new ();
3973 gtk_notebook_set_tab_pos(GTK_NOTEBOOK(notebook
), GTK_POS_LEFT
);
3974 gtk_box_pack_start(GTK_BOX (vbox
), notebook
, FALSE
, FALSE
, 0);
3975 gtk_widget_show(prefsnotebook
);
3977 button
= pidgin_dialog_add_button(GTK_DIALOG(prefs
), GTK_STOCK_CLOSE
, NULL
, NULL
);
3978 g_signal_connect_swapped(G_OBJECT(button
), "clicked",
3979 G_CALLBACK(gtk_widget_destroy
), prefs
);
3981 prefs_notebook_init();
3983 /* Refresh the list of themes before showing the preferences window */
3984 prefs_themes_refresh();
3986 /* Show everything. */
3987 gtk_widget_show(prefs
);
3991 set_bool_pref(GtkWidget
*w
, const char *key
)
3993 purple_prefs_set_bool(key
,
3994 gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(w
)));
3998 pidgin_prefs_checkbox(const char *text
, const char *key
, GtkWidget
*page
)
4002 button
= gtk_check_button_new_with_mnemonic(text
);
4003 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(button
),
4004 purple_prefs_get_bool(key
));
4006 gtk_box_pack_start(GTK_BOX(page
), button
, FALSE
, FALSE
, 0);
4008 g_signal_connect(G_OBJECT(button
), "clicked",
4009 G_CALLBACK(set_bool_pref
), (char *)key
);
4011 gtk_widget_show(button
);
4017 smiley_theme_pref_cb(const char *name
, PurplePrefType type
,
4018 gconstpointer value
, gpointer data
)
4020 const gchar
*theme_name
= value
;
4023 if (g_strcmp0(theme_name
, "none") == 0) {
4024 purple_smiley_theme_set_current(NULL
);
4028 /* XXX: could be cached when initializing prefs view */
4029 themes
= pidgin_smiley_theme_get_all();
4031 for (it
= themes
; it
; it
= g_list_next(it
)) {
4032 PidginSmileyTheme
*theme
= it
->data
;
4034 if (g_strcmp0(pidgin_smiley_theme_get_name(theme
), theme_name
))
4037 purple_smiley_theme_set_current(PURPLE_SMILEY_THEME(theme
));
4042 pidgin_prefs_init(void)
4044 purple_prefs_add_none(PIDGIN_PREFS_ROOT
"");
4045 purple_prefs_add_none("/plugins/gtk");
4049 purple_prefs_add_none(PIDGIN_PREFS_ROOT
"/browsers");
4050 purple_prefs_add_int(PIDGIN_PREFS_ROOT
"/browsers/place", PIDGIN_BROWSER_DEFAULT
);
4051 purple_prefs_add_string(PIDGIN_PREFS_ROOT
"/browsers/manual_command", "");
4052 purple_prefs_add_string(PIDGIN_PREFS_ROOT
"/browsers/browser", "xdg-open");
4056 purple_prefs_add_none(PIDGIN_PREFS_ROOT
"/plugins");
4057 purple_prefs_add_path_list(PIDGIN_PREFS_ROOT
"/plugins/loaded", NULL
);
4059 /* File locations */
4060 purple_prefs_add_none(PIDGIN_PREFS_ROOT
"/filelocations");
4061 purple_prefs_add_path(PIDGIN_PREFS_ROOT
"/filelocations/last_save_folder", "");
4062 purple_prefs_add_path(PIDGIN_PREFS_ROOT
"/filelocations/last_open_folder", "");
4063 purple_prefs_add_path(PIDGIN_PREFS_ROOT
"/filelocations/last_icon_folder", "");
4066 prefs_themes_init();
4068 /* Conversation Themes */
4069 purple_prefs_add_none(PIDGIN_PREFS_ROOT
"/conversations");
4070 purple_prefs_add_string(PIDGIN_PREFS_ROOT
"/conversations/theme", "Default");
4073 purple_prefs_add_none(PIDGIN_PREFS_ROOT
"/smileys");
4074 purple_prefs_add_string(PIDGIN_PREFS_ROOT
"/smileys/theme", "Default");
4076 /* Smiley Callbacks */
4077 purple_prefs_connect_callback(&prefs
, PIDGIN_PREFS_ROOT
"/smileys/theme",
4078 smiley_theme_pref_cb
, NULL
);
4082 purple_prefs_add_none(PIDGIN_PREFS_ROOT
"/vvconfig");
4083 purple_prefs_add_none(PIDGIN_PREFS_ROOT
"/vvconfig/audio");
4084 purple_prefs_add_none(PIDGIN_PREFS_ROOT
"/vvconfig/audio/src");
4085 purple_prefs_add_string(PIDGIN_PREFS_ROOT
"/vvconfig/audio/src/device", "");
4086 purple_prefs_add_none(PIDGIN_PREFS_ROOT
"/vvconfig/audio/sink");
4087 purple_prefs_add_string(PIDGIN_PREFS_ROOT
"/vvconfig/audio/sink/device", "");
4088 purple_prefs_add_none(PIDGIN_PREFS_ROOT
"/vvconfig/video");
4089 purple_prefs_add_none(PIDGIN_PREFS_ROOT
"/vvconfig/video/src");
4090 purple_prefs_add_string(PIDGIN_PREFS_ROOT
"/vvconfig/video/src/device", "");
4091 purple_prefs_add_none(PIDGIN_PREFS_ROOT
"/vvconfig/video");
4092 purple_prefs_add_none(PIDGIN_PREFS_ROOT
"/vvconfig/video/sink");
4093 purple_prefs_add_string(PIDGIN_PREFS_ROOT
"/vvconfig/video/sink/device", "");
4096 pidgin_prefs_update_old();
4100 pidgin_prefs_update_old(void)
4102 /* Rename some old prefs */
4103 purple_prefs_rename(PIDGIN_PREFS_ROOT
"/logging/log_ims", "/purple/logging/log_ims");
4104 purple_prefs_rename(PIDGIN_PREFS_ROOT
"/logging/log_chats", "/purple/logging/log_chats");
4105 purple_prefs_rename("/purple/conversations/placement",
4106 PIDGIN_PREFS_ROOT
"/conversations/placement");
4108 purple_prefs_rename(PIDGIN_PREFS_ROOT
"/conversations/im/raise_on_events", "/plugins/gtk/X11/notify/method_raise");
4110 purple_prefs_rename_boolean_toggle(PIDGIN_PREFS_ROOT
"/conversations/ignore_colors",
4111 PIDGIN_PREFS_ROOT
"/conversations/show_incoming_formatting");
4114 * This path pref changed to a string, so migrate. I know this will
4115 * break things for and confuse users that use multiple versions with
4116 * the same config directory, but I'm not inclined to want to deal with
4117 * that at the moment. -- rekkanoryo
4119 if (purple_prefs_exists(PIDGIN_PREFS_ROOT
"/browsers/command") &&
4120 purple_prefs_get_pref_type(PIDGIN_PREFS_ROOT
"/browsers/command") ==
4123 const char *str
= purple_prefs_get_path(
4124 PIDGIN_PREFS_ROOT
"/browsers/command");
4125 purple_prefs_set_string(
4126 PIDGIN_PREFS_ROOT
"/browsers/manual_command", str
);
4127 purple_prefs_remove(PIDGIN_PREFS_ROOT
"/browsers/command");
4130 /* Remove some no-longer-used prefs */
4131 purple_prefs_remove(PIDGIN_PREFS_ROOT
"/blist/auto_expand_contacts");
4132 purple_prefs_remove(PIDGIN_PREFS_ROOT
"/blist/button_style");
4133 purple_prefs_remove(PIDGIN_PREFS_ROOT
"/blist/grey_idle_buddies");
4134 purple_prefs_remove(PIDGIN_PREFS_ROOT
"/blist/raise_on_events");
4135 purple_prefs_remove(PIDGIN_PREFS_ROOT
"/blist/show_group_count");
4136 purple_prefs_remove(PIDGIN_PREFS_ROOT
"/blist/show_warning_level");
4137 purple_prefs_remove(PIDGIN_PREFS_ROOT
"/blist/tooltip_delay");
4138 purple_prefs_remove(PIDGIN_PREFS_ROOT
"/conversations/button_type");
4139 purple_prefs_remove(PIDGIN_PREFS_ROOT
"/conversations/ctrl_enter_sends");
4140 purple_prefs_remove(PIDGIN_PREFS_ROOT
"/conversations/enter_sends");
4141 purple_prefs_remove(PIDGIN_PREFS_ROOT
"/conversations/escape_closes");
4142 purple_prefs_remove(PIDGIN_PREFS_ROOT
"/conversations/html_shortcuts");
4143 purple_prefs_remove(PIDGIN_PREFS_ROOT
"/conversations/icons_on_tabs");
4144 purple_prefs_remove(PIDGIN_PREFS_ROOT
"/conversations/send_formatting");
4145 purple_prefs_remove(PIDGIN_PREFS_ROOT
"/conversations/show_smileys");
4146 purple_prefs_remove(PIDGIN_PREFS_ROOT
"/conversations/show_urls_as_links");
4147 purple_prefs_remove(PIDGIN_PREFS_ROOT
"/conversations/smiley_shortcuts");
4148 purple_prefs_remove(PIDGIN_PREFS_ROOT
"/conversations/use_custom_bgcolor");
4149 purple_prefs_remove(PIDGIN_PREFS_ROOT
"/conversations/use_custom_fgcolor");
4150 purple_prefs_remove(PIDGIN_PREFS_ROOT
"/conversations/use_custom_font");
4151 purple_prefs_remove(PIDGIN_PREFS_ROOT
"/conversations/use_custom_size");
4152 purple_prefs_remove(PIDGIN_PREFS_ROOT
"/conversations/chat/old_tab_complete");
4153 purple_prefs_remove(PIDGIN_PREFS_ROOT
"/conversations/chat/tab_completion");
4154 purple_prefs_remove(PIDGIN_PREFS_ROOT
"/conversations/im/hide_on_send");
4155 purple_prefs_remove(PIDGIN_PREFS_ROOT
"/conversations/chat/color_nicks");
4156 purple_prefs_remove(PIDGIN_PREFS_ROOT
"/conversations/chat/raise_on_events");
4157 purple_prefs_remove(PIDGIN_PREFS_ROOT
"/conversations/ignore_fonts");
4158 purple_prefs_remove(PIDGIN_PREFS_ROOT
"/conversations/ignore_font_sizes");
4159 purple_prefs_remove(PIDGIN_PREFS_ROOT
"/conversations/passthrough_unknown_commands");
4160 purple_prefs_remove(PIDGIN_PREFS_ROOT
"/debug/timestamps");
4161 purple_prefs_remove(PIDGIN_PREFS_ROOT
"/idle");
4162 purple_prefs_remove(PIDGIN_PREFS_ROOT
"/logging/individual_logs");
4163 purple_prefs_remove(PIDGIN_PREFS_ROOT
"/sound/signon");
4164 purple_prefs_remove(PIDGIN_PREFS_ROOT
"/sound/silent_signon");
4166 /* Convert old queuing prefs to hide_new 3-way pref. */
4167 if (purple_prefs_exists("/plugins/gtk/docklet/queue_messages") &&
4168 purple_prefs_get_bool("/plugins/gtk/docklet/queue_messages"))
4170 purple_prefs_set_string(PIDGIN_PREFS_ROOT
"/conversations/im/hide_new", "always");
4172 else if (purple_prefs_exists(PIDGIN_PREFS_ROOT
"/away/queue_messages") &&
4173 purple_prefs_get_bool(PIDGIN_PREFS_ROOT
"/away/queue_messages"))
4175 purple_prefs_set_string(PIDGIN_PREFS_ROOT
"/conversations/im/hide_new", "away");
4177 purple_prefs_remove(PIDGIN_PREFS_ROOT
"/away/queue_messages");
4178 purple_prefs_remove(PIDGIN_PREFS_ROOT
"/away");
4179 purple_prefs_remove("/plugins/gtk/docklet/queue_messages");
4181 purple_prefs_remove(PIDGIN_PREFS_ROOT
"/conversations/chat/default_width");
4182 purple_prefs_remove(PIDGIN_PREFS_ROOT
"/conversations/chat/default_height");
4183 purple_prefs_remove(PIDGIN_PREFS_ROOT
"/conversations/im/default_width");
4184 purple_prefs_remove(PIDGIN_PREFS_ROOT
"/conversations/im/default_height");
4185 purple_prefs_rename(PIDGIN_PREFS_ROOT
"/conversations/x",
4186 PIDGIN_PREFS_ROOT
"/conversations/im/x");
4187 purple_prefs_rename(PIDGIN_PREFS_ROOT
"/conversations/y",
4188 PIDGIN_PREFS_ROOT
"/conversations/im/y");
4190 /* Fixup vvconfig plugin prefs */
4191 if (purple_prefs_exists("/plugins/core/vvconfig/audio/src/device")) {
4192 purple_prefs_set_string(PIDGIN_PREFS_ROOT
"/vvconfig/audio/src/device",
4193 purple_prefs_get_string("/plugins/core/vvconfig/audio/src/device"));
4195 if (purple_prefs_exists("/plugins/core/vvconfig/audio/sink/device")) {
4196 purple_prefs_set_string(PIDGIN_PREFS_ROOT
"/vvconfig/audio/sink/device",
4197 purple_prefs_get_string("/plugins/core/vvconfig/audio/sink/device"));
4199 if (purple_prefs_exists("/plugins/core/vvconfig/video/src/device")) {
4200 purple_prefs_set_string(PIDGIN_PREFS_ROOT
"/vvconfig/video/src/device",
4201 purple_prefs_get_string("/plugins/core/vvconfig/video/src/device"));
4203 if (purple_prefs_exists("/plugins/gtk/vvconfig/video/sink/device")) {
4204 purple_prefs_set_string(PIDGIN_PREFS_ROOT
"/vvconfig/video/sink/device",
4205 purple_prefs_get_string("/plugins/gtk/vvconfig/video/sink/device"));
4208 purple_prefs_remove("/plugins/core/vvconfig");
4209 purple_prefs_remove("/plugins/gtk/vvconfig");
4211 purple_prefs_remove(PIDGIN_PREFS_ROOT
"/vvconfig/audio/src/plugin");
4212 purple_prefs_remove(PIDGIN_PREFS_ROOT
"/vvconfig/audio/sink/plugin");
4213 purple_prefs_remove(PIDGIN_PREFS_ROOT
"/vvconfig/video/src/plugin");
4214 purple_prefs_remove(PIDGIN_PREFS_ROOT
"/vvconfig/video/sink/plugin");
4217 /* Added in 3.0.0. */
4218 if (purple_prefs_get_int(PIDGIN_PREFS_ROOT
"/browsers/place") == 1) {
4219 /* If the "open link in" pref is set to the old value for "existing
4220 window" then change it to "default." */
4221 purple_prefs_set_int(PIDGIN_PREFS_ROOT
"/browsers/place",
4222 PIDGIN_BROWSER_DEFAULT
);
4225 /* Added in 3.0.0. */
4227 purple_prefs_get_string(PIDGIN_PREFS_ROOT
"/browsers/browser"),
4229 purple_prefs_set_string(PIDGIN_PREFS_ROOT
"/browsers/browser", "xdg-open");
4231 #endif /* !_WIN32 */