pidgin/pidgin
Clone
Summary
Browse
Changes
Graph
Use Meson summary() function.
2021-07-27, Elliott Sales de Andrade
cb640ea0f315
Use Meson summary() function.
Now that we require at least 0.52, we can use Meson's builtin summary printing to display the results of configuration.
Testing Done:
Configured with defaults, and with pixmaps disabled to trigger the warning: https://asciinema.org/a/mV2oxOoVCJNdmrPwgqqUJ3mkU?t=17
Reviewed at https://reviews.imfreedom.org/r/848/
/* pidgin
*
* Pidgin is the legal property of its developers, whose names are too numerous
* to list here. Please refer to the COPYRIGHT file distributed with this
* source distribution.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111-1301 USA
*
*/
#ifdef HAVE_CONFIG_H
#
include
<config.h>
#endif
#include
<errno.h>
#include
<math.h>
#include
<glib/gi18n-lib.h>
#include
<glib/gstdio.h>
#include
<nice.h>
#include
<talkatu.h>
#include
<purple.h>
#include
"gtkblist.h"
#include
"gtkconv.h"
#include
"gtkdialogs.h"
#include
"gtksavedstatuses.h"
#include
"gtksmiley-theme.h"
#include
"gtkstatus-icon-theme.h"
#include
"gtkutils.h"
#include
"pidgincore.h"
#include
"pidgindebug.h"
#include
"pidginprefs.h"
#include
"pidginstock.h"
#ifdef USE_VV
#include
<gst/video/videooverlay.h>
#ifdef GDK_WINDOWING_WIN32
#include
<gdk/gdkwin32.h>
#endif
#ifdef GDK_WINDOWING_X11
#include
<gdk/gdkx.h>
#endif
#ifdef GDK_WINDOWING_QUARTZ
#include
<gdk/gdkquartz.h>
#endif
#endif
#include
<libsoup/soup.h>
#define PREFS_OPTIMAL_ICON_SIZE 32
/* 25MB */
#define PREFS_MAX_DOWNLOADED_THEME_SIZE 26214400
struct
theme_info
{
gchar
*
type
;
gchar
*
extension
;
gchar
*
original_name
;
};
typedef
struct
_PidginPrefCombo
PidginPrefCombo
;
typedef
void
(
*
PidginPrefsBindDropdownCallback
)(
GtkComboBox
*
combo_box
,
PidginPrefCombo
*
combo
);
struct
_PidginPrefCombo
{
GtkWidget
*
combo
;
PurplePrefType
type
;
const
gchar
*
key
;
union
{
const
char
*
string
;
int
integer
;
gboolean
boolean
;
}
value
;
gint
previously_active
;
gint
current_active
;
PidginPrefsBindDropdownCallback
cb
;
};
struct
_PidginPrefsWindow
{
GtkDialog
parent
;
/* Stack */
GtkWidget
*
stack
;
/* Interface page */
struct
{
struct
{
PidginPrefCombo
hide_new
;
}
im
;
struct
{
GtkWidget
*
minimize_new_convs
;
}
win32
;
struct
{
GtkWidget
*
tabs
;
GtkWidget
*
tabs_vbox
;
GtkWidget
*
close_on_tabs
;
PidginPrefCombo
tab_side
;
}
conversations
;
}
iface
;
/* Conversations page */
struct
{
PidginPrefCombo
notification_chat
;
GtkWidget
*
show_incoming_formatting
;
struct
{
GtkWidget
*
close_immediately
;
GtkWidget
*
send_typing
;
}
im
;
GtkWidget
*
use_smooth_scrolling
;
struct
{
GtkWidget
*
blink_im
;
}
win32
;
GtkWidget
*
resize_custom_smileys
;
GtkWidget
*
custom_smileys_size
;
GtkWidget
*
minimum_entry_lines
;
GtkTextBuffer
*
format_buffer
;
GtkWidget
*
format_view
;
/* Win32 specific frame */
GtkWidget
*
font_frame
;
GtkWidget
*
use_theme_font
;
GtkWidget
*
custom_font_hbox
;
GtkWidget
*
custom_font
;
}
conversations
;
/* Logging page */
struct
{
PidginPrefCombo
format
;
GtkWidget
*
log_ims
;
GtkWidget
*
log_chats
;
GtkWidget
*
log_system
;
}
logging
;
/* Network page */
struct
{
GtkWidget
*
stun_server
;
GtkWidget
*
auto_ip
;
GtkWidget
*
public_ip
;
GtkWidget
*
public_ip_hbox
;
GtkWidget
*
map_ports
;
GtkWidget
*
ports_range_use
;
GtkWidget
*
ports_range_hbox
;
GtkWidget
*
ports_range_start
;
GtkWidget
*
ports_range_end
;
GtkWidget
*
turn_server
;
GtkWidget
*
turn_port_udp
;
GtkWidget
*
turn_port_tcp
;
GtkWidget
*
turn_username
;
GtkWidget
*
turn_password
;
}
network
;
/* Proxy page */
struct
{
GtkWidget
*
stack
;
/* GNOME version */
GtkWidget
*
gnome_not_found
;
GtkWidget
*
gnome_program
;
gchar
*
gnome_program_path
;
/* Non-GNOME version */
GtkWidget
*
socks4_remotedns
;
PidginPrefCombo
type
;
GtkWidget
*
options
;
GtkWidget
*
host
;
GtkWidget
*
port
;
GtkWidget
*
username
;
GtkWidget
*
password
;
}
proxy
;
/* Away page */
struct
{
PidginPrefCombo
idle_reporting
;
GtkWidget
*
mins_before_away
;
GtkWidget
*
idle_hbox
;
GtkWidget
*
away_when_idle
;
PidginPrefCombo
auto_reply
;
GtkWidget
*
startup_current_status
;
GtkWidget
*
startup_hbox
;
GtkWidget
*
startup_label
;
}
away
;
/* Themes page */
struct
{
SoupSession
*
session
;
GtkWidget
*
status
;
GtkWidget
*
smiley
;
}
theme
;
#ifdef USE_VV
/* Voice/Video page */
struct
{
struct
{
PidginPrefCombo
input
;
PidginPrefCombo
output
;
GtkWidget
*
level
;
GtkWidget
*
threshold
;
GtkWidget
*
volume
;
GtkWidget
*
test
;
GstElement
*
pipeline
;
}
voice
;
struct
{
PidginPrefCombo
input
;
PidginPrefCombo
output
;
GtkWidget
*
frame
;
GtkWidget
*
sink_widget
;
GtkWidget
*
test
;
GstElement
*
pipeline
;
}
video
;
}
vv
;
#endif
};
/* Main dialog */
static
PidginPrefsWindow
*
prefs
=
NULL
;
/* Themes page */
static
GtkWidget
*
prefs_status_themes_combo_box
;
static
GtkWidget
*
prefs_smiley_themes_combo_box
;
/* These exist outside the lifetime of the prefs dialog */
static
GtkListStore
*
prefs_status_icon_themes
;
static
GtkListStore
*
prefs_smiley_themes
;
/*
* PROTOTYPES
*/
G_DEFINE_TYPE
(
PidginPrefsWindow
,
pidgin_prefs_window
,
GTK_TYPE_DIALOG
);
static
void
delete_prefs
(
GtkWidget
*
,
void
*
);
static
void
update_spin_value
(
GtkWidget
*
w
,
GtkWidget
*
spin
)
{
const
char
*
key
=
g_object_get_data
(
G_OBJECT
(
spin
),
"val"
);
int
value
;
value
=
gtk_spin_button_get_value_as_int
(
GTK_SPIN_BUTTON
(
spin
));
purple_prefs_set_int
(
key
,
value
);
}
GtkWidget
*
pidgin_prefs_labeled_spin_button
(
GtkWidget
*
box
,
const
gchar
*
title
,
const
char
*
key
,
int
min
,
int
max
,
GtkSizeGroup
*
sg
)
{
GtkWidget
*
spin
;
GtkAdjustment
*
adjust
;
int
val
;
val
=
purple_prefs_get_int
(
key
);
adjust
=
GTK_ADJUSTMENT
(
gtk_adjustment_new
(
val
,
min
,
max
,
1
,
1
,
0
));
spin
=
gtk_spin_button_new
(
adjust
,
1
,
0
);
g_object_set_data
(
G_OBJECT
(
spin
),
"val"
,
(
char
*
)
key
);
if
(
max
<
10000
)
gtk_widget_set_size_request
(
spin
,
50
,
-1
);
else
gtk_widget_set_size_request
(
spin
,
60
,
-1
);
g_signal_connect
(
G_OBJECT
(
adjust
),
"value-changed"
,
G_CALLBACK
(
update_spin_value
),
GTK_WIDGET
(
spin
));
gtk_widget_show
(
spin
);
return
pidgin_add_widget_to_vbox
(
GTK_BOX
(
box
),
title
,
sg
,
spin
,
FALSE
,
NULL
);
}
static
void
pidgin_prefs_bind_spin_button
(
const
char
*
key
,
GtkWidget
*
spin
)
{
GtkAdjustment
*
adjust
;
int
val
;
val
=
purple_prefs_get_int
(
key
);
adjust
=
gtk_spin_button_get_adjustment
(
GTK_SPIN_BUTTON
(
spin
));
gtk_adjustment_set_value
(
adjust
,
val
);
g_object_set_data
(
G_OBJECT
(
spin
),
"val"
,
(
char
*
)
key
);
g_signal_connect
(
G_OBJECT
(
adjust
),
"value-changed"
,
G_CALLBACK
(
update_spin_value
),
GTK_WIDGET
(
spin
));
}
static
void
entry_set
(
GtkEntry
*
entry
,
gpointer
data
)
{
const
char
*
key
=
(
const
char
*
)
data
;
purple_prefs_set_string
(
key
,
gtk_entry_get_text
(
entry
));
}
GtkWidget
*
pidgin_prefs_labeled_entry
(
GtkWidget
*
page
,
const
gchar
*
title
,
const
char
*
key
,
GtkSizeGroup
*
sg
)
{
GtkWidget
*
entry
;
const
gchar
*
value
;
value
=
purple_prefs_get_string
(
key
);
entry
=
gtk_entry_new
();
gtk_entry_set_text
(
GTK_ENTRY
(
entry
),
value
);
g_signal_connect
(
G_OBJECT
(
entry
),
"changed"
,
G_CALLBACK
(
entry_set
),
(
char
*
)
key
);
gtk_widget_show
(
entry
);
return
pidgin_add_widget_to_vbox
(
GTK_BOX
(
page
),
title
,
sg
,
entry
,
TRUE
,
NULL
);
}
static
void
pidgin_prefs_bind_entry
(
const
char
*
key
,
GtkWidget
*
entry
)
{
const
gchar
*
value
;
value
=
purple_prefs_get_string
(
key
);
gtk_entry_set_text
(
GTK_ENTRY
(
entry
),
value
);
g_signal_connect
(
G_OBJECT
(
entry
),
"changed"
,
G_CALLBACK
(
entry_set
),
(
char
*
)
key
);
}
GtkWidget
*
pidgin_prefs_labeled_password
(
GtkWidget
*
page
,
const
gchar
*
title
,
const
char
*
key
,
GtkSizeGroup
*
sg
)
{
GtkWidget
*
entry
;
const
gchar
*
value
;
value
=
purple_prefs_get_string
(
key
);
entry
=
gtk_entry_new
();
gtk_entry_set_visibility
(
GTK_ENTRY
(
entry
),
FALSE
);
gtk_entry_set_text
(
GTK_ENTRY
(
entry
),
value
);
g_signal_connect
(
G_OBJECT
(
entry
),
"changed"
,
G_CALLBACK
(
entry_set
),
(
char
*
)
key
);
gtk_widget_show
(
entry
);
return
pidgin_add_widget_to_vbox
(
GTK_BOX
(
page
),
title
,
sg
,
entry
,
TRUE
,
NULL
);
}
/* TODO: Maybe move this up somewheres... */
enum
{
PREF_DROPDOWN_TEXT
,
PREF_DROPDOWN_VALUE
,
PREF_DROPDOWN_COUNT
};
typedef
struct
{
PurplePrefType
type
;
union
{
const
char
*
string
;
int
integer
;
gboolean
boolean
;
}
value
;
}
PidginPrefValue
;
typedef
void
(
*
PidginPrefsDropdownCallback
)(
GtkComboBox
*
combo_box
,
PidginPrefValue
value
);
static
void
dropdown_set
(
GtkComboBox
*
combo_box
,
gpointer
_cb
)
{
PidginPrefsDropdownCallback
cb
=
_cb
;
GtkTreeIter
iter
;
GtkTreeModel
*
tree_model
;
PidginPrefValue
active
;
tree_model
=
gtk_combo_box_get_model
(
combo_box
);
if
(
!
gtk_combo_box_get_active_iter
(
combo_box
,
&
iter
))
return
;
active
.
type
=
GPOINTER_TO_INT
(
g_object_get_data
(
G_OBJECT
(
combo_box
),
"type"
));
g_object_set_data
(
G_OBJECT
(
combo_box
),
"previously_active"
,
g_object_get_data
(
G_OBJECT
(
combo_box
),
"current_active"
));
g_object_set_data
(
G_OBJECT
(
combo_box
),
"current_active"
,
GINT_TO_POINTER
(
gtk_combo_box_get_active
(
combo_box
)));
if
(
active
.
type
==
PURPLE_PREF_INT
)
{
gtk_tree_model_get
(
tree_model
,
&
iter
,
PREF_DROPDOWN_VALUE
,
&
active
.
value
.
integer
,
-1
);
}
else
if
(
active
.
type
==
PURPLE_PREF_STRING
)
{
gtk_tree_model_get
(
tree_model
,
&
iter
,
PREF_DROPDOWN_VALUE
,
&
active
.
value
.
string
,
-1
);
}
else
if
(
active
.
type
==
PURPLE_PREF_BOOLEAN
)
{
gtk_tree_model_get
(
tree_model
,
&
iter
,
PREF_DROPDOWN_VALUE
,
&
active
.
value
.
boolean
,
-1
);
}
cb
(
combo_box
,
active
);
}
static
GtkWidget
*
pidgin_prefs_dropdown_from_list_with_cb
(
GtkWidget
*
box
,
const
gchar
*
title
,
GtkComboBox
**
dropdown_out
,
GList
*
menuitems
,
PidginPrefValue
initial
,
PidginPrefsDropdownCallback
cb
)
{
GtkWidget
*
dropdown
;
GtkWidget
*
label
=
NULL
;
GtkListStore
*
store
=
NULL
;
GtkTreeIter
iter
;
GtkTreeIter
active
;
GtkCellRenderer
*
renderer
;
gpointer
current_active
;
g_return_val_if_fail
(
menuitems
!=
NULL
,
NULL
);
if
(
initial
.
type
==
PURPLE_PREF_INT
)
{
store
=
gtk_list_store_new
(
PREF_DROPDOWN_COUNT
,
G_TYPE_STRING
,
G_TYPE_INT
);
}
else
if
(
initial
.
type
==
PURPLE_PREF_STRING
)
{
store
=
gtk_list_store_new
(
PREF_DROPDOWN_COUNT
,
G_TYPE_STRING
,
G_TYPE_STRING
);
}
else
if
(
initial
.
type
==
PURPLE_PREF_BOOLEAN
)
{
store
=
gtk_list_store_new
(
PREF_DROPDOWN_COUNT
,
G_TYPE_STRING
,
G_TYPE_BOOLEAN
);
}
else
{
g_warn_if_reached
();
return
NULL
;
}
dropdown
=
gtk_combo_box_new_with_model
(
GTK_TREE_MODEL
(
store
));
if
(
dropdown_out
!=
NULL
)
*
dropdown_out
=
GTK_COMBO_BOX
(
dropdown
);
g_object_set_data
(
G_OBJECT
(
dropdown
),
"type"
,
GINT_TO_POINTER
(
initial
.
type
));
for
(;
menuitems
!=
NULL
;
menuitems
=
g_list_next
(
menuitems
))
{
const
PurpleKeyValuePair
*
menu_item
=
menuitems
->
data
;
int
int_value
=
0
;
const
char
*
str_value
=
NULL
;
gboolean
bool_value
=
FALSE
;
if
(
menu_item
->
key
==
NULL
)
{
break
;
}
gtk_list_store_append
(
store
,
&
iter
);
gtk_list_store_set
(
store
,
&
iter
,
PREF_DROPDOWN_TEXT
,
menu_item
->
key
,
-1
);
if
(
initial
.
type
==
PURPLE_PREF_INT
)
{
int_value
=
GPOINTER_TO_INT
(
menu_item
->
value
);
gtk_list_store_set
(
store
,
&
iter
,
PREF_DROPDOWN_VALUE
,
int_value
,
-1
);
}
else
if
(
initial
.
type
==
PURPLE_PREF_STRING
)
{
str_value
=
(
const
char
*
)
menu_item
->
value
;
gtk_list_store_set
(
store
,
&
iter
,
PREF_DROPDOWN_VALUE
,
str_value
,
-1
);
}
else
if
(
initial
.
type
==
PURPLE_PREF_BOOLEAN
)
{
bool_value
=
(
gboolean
)
GPOINTER_TO_INT
(
menu_item
->
value
);
gtk_list_store_set
(
store
,
&
iter
,
PREF_DROPDOWN_VALUE
,
bool_value
,
-1
);
}
if
((
initial
.
type
==
PURPLE_PREF_INT
&&
initial
.
value
.
integer
==
int_value
)
||
(
initial
.
type
==
PURPLE_PREF_STRING
&&
purple_strequal
(
initial
.
value
.
string
,
str_value
))
||
(
initial
.
type
==
PURPLE_PREF_BOOLEAN
&&
(
initial
.
value
.
boolean
==
bool_value
)))
{
active
=
iter
;
}
}
renderer
=
gtk_cell_renderer_text_new
();
gtk_cell_layout_pack_start
(
GTK_CELL_LAYOUT
(
dropdown
),
renderer
,
TRUE
);
gtk_cell_layout_set_attributes
(
GTK_CELL_LAYOUT
(
dropdown
),
renderer
,
"text"
,
0
,
NULL
);
gtk_combo_box_set_active_iter
(
GTK_COMBO_BOX
(
dropdown
),
&
active
);
current_active
=
GINT_TO_POINTER
(
gtk_combo_box_get_active
(
GTK_COMBO_BOX
(
dropdown
)));
g_object_set_data
(
G_OBJECT
(
dropdown
),
"current_active"
,
current_active
);
g_object_set_data
(
G_OBJECT
(
dropdown
),
"previously_active"
,
current_active
);
g_signal_connect
(
G_OBJECT
(
dropdown
),
"changed"
,
G_CALLBACK
(
dropdown_set
),
cb
);
pidgin_add_widget_to_vbox
(
GTK_BOX
(
box
),
title
,
NULL
,
dropdown
,
FALSE
,
&
label
);
return
label
;
}
static
void
pidgin_prefs_dropdown_from_list_cb
(
GtkComboBox
*
combo_box
,
PidginPrefValue
value
)
{
const
char
*
key
;
key
=
g_object_get_data
(
G_OBJECT
(
combo_box
),
"key"
);
if
(
value
.
type
==
PURPLE_PREF_INT
)
{
purple_prefs_set_int
(
key
,
value
.
value
.
integer
);
}
else
if
(
value
.
type
==
PURPLE_PREF_STRING
)
{
purple_prefs_set_string
(
key
,
value
.
value
.
string
);
}
else
if
(
value
.
type
==
PURPLE_PREF_BOOLEAN
)
{
purple_prefs_set_bool
(
key
,
value
.
value
.
boolean
);
}
else
{
g_return_if_reached
();
}
}
GtkWidget
*
pidgin_prefs_dropdown_from_list
(
GtkWidget
*
box
,
const
gchar
*
title
,
PurplePrefType
type
,
const
char
*
key
,
GList
*
menuitems
)
{
PidginPrefValue
initial
;
GtkComboBox
*
dropdown
=
NULL
;
GtkWidget
*
label
;
initial
.
type
=
type
;
if
(
type
==
PURPLE_PREF_INT
)
{
initial
.
value
.
integer
=
purple_prefs_get_int
(
key
);
}
else
if
(
type
==
PURPLE_PREF_STRING
)
{
initial
.
value
.
string
=
purple_prefs_get_string
(
key
);
}
else
if
(
type
==
PURPLE_PREF_BOOLEAN
)
{
initial
.
value
.
boolean
=
purple_prefs_get_bool
(
key
);
}
else
{
g_return_val_if_reached
(
NULL
);
}
label
=
pidgin_prefs_dropdown_from_list_with_cb
(
box
,
title
,
&
dropdown
,
menuitems
,
initial
,
pidgin_prefs_dropdown_from_list_cb
);
g_object_set_data
(
G_OBJECT
(
dropdown
),
"key"
,
(
gpointer
)
key
);
return
label
;
}
GtkWidget
*
pidgin_prefs_dropdown
(
GtkWidget
*
box
,
const
gchar
*
title
,
PurplePrefType
type
,
const
char
*
key
,
...)
{
va_list
ap
;
GList
*
menuitems
=
NULL
;
GtkWidget
*
dropdown
=
NULL
;
char
*
name
;
g_return_val_if_fail
(
type
==
PURPLE_PREF_BOOLEAN
||
type
==
PURPLE_PREF_INT
||
type
==
PURPLE_PREF_STRING
,
NULL
);
va_start
(
ap
,
key
);
while
((
name
=
va_arg
(
ap
,
char
*
))
!=
NULL
)
{
PurpleKeyValuePair
*
kvp
;
if
(
type
==
PURPLE_PREF_INT
||
type
==
PURPLE_PREF_BOOLEAN
)
{
kvp
=
purple_key_value_pair_new
(
name
,
GINT_TO_POINTER
(
va_arg
(
ap
,
int
)));
}
else
{
kvp
=
purple_key_value_pair_new
(
name
,
va_arg
(
ap
,
char
*
));
}
menuitems
=
g_list_prepend
(
menuitems
,
kvp
);
}
va_end
(
ap
);
g_return_val_if_fail
(
menuitems
!=
NULL
,
NULL
);
menuitems
=
g_list_reverse
(
menuitems
);
dropdown
=
pidgin_prefs_dropdown_from_list
(
box
,
title
,
type
,
key
,
menuitems
);
g_list_free_full
(
menuitems
,
(
GDestroyNotify
)
purple_key_value_pair_free
);
return
dropdown
;
}
static
void
pidgin_prefs_bind_dropdown_from_list_cb
(
GtkComboBox
*
combo_box
,
PidginPrefCombo
*
combo
)
{
if
(
combo
->
type
==
PURPLE_PREF_INT
)
{
purple_prefs_set_int
(
combo
->
key
,
combo
->
value
.
integer
);
}
else
if
(
combo
->
type
==
PURPLE_PREF_STRING
)
{
purple_prefs_set_string
(
combo
->
key
,
combo
->
value
.
string
);
}
else
if
(
combo
->
type
==
PURPLE_PREF_BOOLEAN
)
{
purple_prefs_set_bool
(
combo
->
key
,
combo
->
value
.
boolean
);
}
else
{
g_return_if_reached
();
}
}
static
void
bind_dropdown_set
(
GtkComboBox
*
combo_box
,
gpointer
data
)
{
PidginPrefCombo
*
combo
=
data
;
GtkTreeIter
iter
;
GtkTreeModel
*
tree_model
;
tree_model
=
gtk_combo_box_get_model
(
combo_box
);
if
(
!
gtk_combo_box_get_active_iter
(
combo_box
,
&
iter
))
return
;
combo
->
previously_active
=
combo
->
current_active
;
combo
->
current_active
=
gtk_combo_box_get_active
(
combo_box
);
if
(
combo
->
type
==
PURPLE_PREF_INT
)
{
gtk_tree_model_get
(
tree_model
,
&
iter
,
PREF_DROPDOWN_VALUE
,
&
combo
->
value
.
integer
,
-1
);
}
else
if
(
combo
->
type
==
PURPLE_PREF_STRING
)
{
gtk_tree_model_get
(
tree_model
,
&
iter
,
PREF_DROPDOWN_VALUE
,
&
combo
->
value
.
string
,
-1
);
}
else
if
(
combo
->
type
==
PURPLE_PREF_BOOLEAN
)
{
gtk_tree_model_get
(
tree_model
,
&
iter
,
PREF_DROPDOWN_VALUE
,
&
combo
->
value
.
boolean
,
-1
);
}
combo
->
cb
(
combo_box
,
combo
);
}
static
void
pidgin_prefs_bind_dropdown_from_list
(
PidginPrefCombo
*
combo
,
GList
*
menuitems
)
{
gchar
*
text
;
GtkListStore
*
store
=
NULL
;
GtkTreeIter
iter
;
GtkTreeIter
active
;
g_return_if_fail
(
menuitems
!=
NULL
);
if
(
combo
->
type
==
PURPLE_PREF_INT
)
{
combo
->
value
.
integer
=
purple_prefs_get_int
(
combo
->
key
);
}
else
if
(
combo
->
type
==
PURPLE_PREF_STRING
)
{
combo
->
value
.
string
=
purple_prefs_get_string
(
combo
->
key
);
}
else
if
(
combo
->
type
==
PURPLE_PREF_BOOLEAN
)
{
combo
->
value
.
boolean
=
purple_prefs_get_bool
(
combo
->
key
);
}
else
{
g_return_if_reached
();
}
store
=
GTK_LIST_STORE
(
gtk_combo_box_get_model
(
GTK_COMBO_BOX
(
combo
->
combo
)));
while
(
menuitems
!=
NULL
&&
(
text
=
(
char
*
)
menuitems
->
data
)
!=
NULL
)
{
int
int_value
=
0
;
const
char
*
str_value
=
NULL
;
gboolean
bool_value
=
FALSE
;
menuitems
=
g_list_next
(
menuitems
);
g_return_if_fail
(
menuitems
!=
NULL
);
gtk_list_store_append
(
store
,
&
iter
);
gtk_list_store_set
(
store
,
&
iter
,
PREF_DROPDOWN_TEXT
,
text
,
-1
);
if
(
combo
->
type
==
PURPLE_PREF_INT
)
{
int_value
=
GPOINTER_TO_INT
(
menuitems
->
data
);
gtk_list_store_set
(
store
,
&
iter
,
PREF_DROPDOWN_VALUE
,
int_value
,
-1
);
}
else
if
(
combo
->
type
==
PURPLE_PREF_STRING
)
{
str_value
=
(
const
char
*
)
menuitems
->
data
;
gtk_list_store_set
(
store
,
&
iter
,
PREF_DROPDOWN_VALUE
,
str_value
,
-1
);
}
else
if
(
combo
->
type
==
PURPLE_PREF_BOOLEAN
)
{
bool_value
=
(
gboolean
)
GPOINTER_TO_INT
(
menuitems
->
data
);
gtk_list_store_set
(
store
,
&
iter
,
PREF_DROPDOWN_VALUE
,
bool_value
,
-1
);
}
if
((
combo
->
type
==
PURPLE_PREF_INT
&&
combo
->
value
.
integer
==
int_value
)
||
(
combo
->
type
==
PURPLE_PREF_STRING
&&
purple_strequal
(
combo
->
value
.
string
,
str_value
))
||
(
combo
->
type
==
PURPLE_PREF_BOOLEAN
&&
(
combo
->
value
.
boolean
==
bool_value
)))
{
active
=
iter
;
}
menuitems
=
g_list_next
(
menuitems
);
}
gtk_combo_box_set_active_iter
(
GTK_COMBO_BOX
(
combo
->
combo
),
&
active
);
combo
->
current_active
=
gtk_combo_box_get_active
(
GTK_COMBO_BOX
(
combo
->
combo
));
combo
->
previously_active
=
combo
->
current_active
;
combo
->
cb
=
pidgin_prefs_bind_dropdown_from_list_cb
;
g_signal_connect
(
G_OBJECT
(
combo
->
combo
),
"changed"
,
G_CALLBACK
(
bind_dropdown_set
),
combo
);
}
static
void
pidgin_prefs_bind_dropdown
(
PidginPrefCombo
*
combo
)
{
GtkTreeModel
*
store
=
NULL
;
GtkTreeIter
iter
;
GtkTreeIter
active
;
if
(
combo
->
type
==
PURPLE_PREF_INT
)
{
combo
->
value
.
integer
=
purple_prefs_get_int
(
combo
->
key
);
}
else
if
(
combo
->
type
==
PURPLE_PREF_STRING
)
{
combo
->
value
.
string
=
purple_prefs_get_string
(
combo
->
key
);
}
else
if
(
combo
->
type
==
PURPLE_PREF_BOOLEAN
)
{
combo
->
value
.
boolean
=
purple_prefs_get_bool
(
combo
->
key
);
}
else
{
g_return_if_reached
();
}
store
=
gtk_combo_box_get_model
(
GTK_COMBO_BOX
(
combo
->
combo
));
if
(
!
gtk_tree_model_get_iter_first
(
store
,
&
iter
))
{
g_return_if_reached
();
}
do
{
int
int_value
=
0
;
const
char
*
str_value
=
NULL
;
gboolean
bool_value
=
FALSE
;
if
(
combo
->
type
==
PURPLE_PREF_INT
)
{
gtk_tree_model_get
(
store
,
&
iter
,
PREF_DROPDOWN_VALUE
,
&
int_value
,
-1
);
if
(
combo
->
value
.
integer
==
int_value
)
{
active
=
iter
;
break
;
}
}
else
if
(
combo
->
type
==
PURPLE_PREF_STRING
)
{
gtk_tree_model_get
(
store
,
&
iter
,
PREF_DROPDOWN_VALUE
,
&
str_value
,
-1
);
if
(
purple_strequal
(
combo
->
value
.
string
,
str_value
))
{
active
=
iter
;
break
;
}
}
else
if
(
combo
->
type
==
PURPLE_PREF_BOOLEAN
)
{
gtk_tree_model_get
(
store
,
&
iter
,
PREF_DROPDOWN_VALUE
,
&
bool_value
,
-1
);
if
(
combo
->
value
.
boolean
==
bool_value
)
{
active
=
iter
;
break
;
}
}
}
while
(
gtk_tree_model_iter_next
(
store
,
&
iter
));
gtk_combo_box_set_active_iter
(
GTK_COMBO_BOX
(
combo
->
combo
),
&
active
);
combo
->
current_active
=
gtk_combo_box_get_active
(
GTK_COMBO_BOX
(
combo
->
combo
));
combo
->
previously_active
=
combo
->
current_active
;
combo
->
cb
=
pidgin_prefs_bind_dropdown_from_list_cb
;
g_signal_connect
(
G_OBJECT
(
combo
->
combo
),
"changed"
,
G_CALLBACK
(
bind_dropdown_set
),
combo
);
}
static
void
set_bool_pref
(
GtkWidget
*
w
,
const
char
*
key
)
{
purple_prefs_set_bool
(
key
,
gtk_toggle_button_get_active
(
GTK_TOGGLE_BUTTON
(
w
)));
}
GtkWidget
*
pidgin_prefs_checkbox
(
const
char
*
text
,
const
char
*
key
,
GtkWidget
*
page
)
{
GtkWidget
*
button
;
button
=
gtk_check_button_new_with_mnemonic
(
text
);
gtk_toggle_button_set_active
(
GTK_TOGGLE_BUTTON
(
button
),
purple_prefs_get_bool
(
key
));
gtk_box_pack_start
(
GTK_BOX
(
page
),
button
,
FALSE
,
FALSE
,
0
);
g_signal_connect
(
G_OBJECT
(
button
),
"clicked"
,
G_CALLBACK
(
set_bool_pref
),
(
char
*
)
key
);
gtk_widget_show
(
button
);
return
button
;
}
static
void
pidgin_prefs_bind_checkbox
(
const
char
*
key
,
GtkWidget
*
button
)
{
gtk_toggle_button_set_active
(
GTK_TOGGLE_BUTTON
(
button
),
purple_prefs_get_bool
(
key
));
g_signal_connect
(
G_OBJECT
(
button
),
"toggled"
,
G_CALLBACK
(
set_bool_pref
),
(
char
*
)
key
);
}
static
void
delete_prefs
(
GtkWidget
*
asdf
,
void
*
gdsa
)
{
/* Close any request dialogs */
purple_request_close_with_handle
(
prefs
);
purple_notify_close_with_handle
(
prefs
);
g_clear_object
(
&
prefs
->
theme
.
session
);
/* Unregister callbacks. */
purple_prefs_disconnect_by_handle
(
prefs
);
/* NULL-ify globals */
prefs_status_themes_combo_box
=
NULL
;
prefs_smiley_themes_combo_box
=
NULL
;
g_free
(
prefs
->
proxy
.
gnome_program_path
);
prefs
=
NULL
;
}
static
gchar
*
get_theme_markup
(
const
char
*
name
,
gboolean
custom
,
const
char
*
author
,
const
char
*
description
)
{
return
g_strdup_printf
(
"<b>%s</b>%s%s%s%s
\n
<span foreground='dim grey'>%s</span>"
,
name
,
custom
?
" "
:
""
,
custom
?
_
(
"(Custom)"
)
:
""
,
author
!=
NULL
?
" - "
:
""
,
author
!=
NULL
?
author
:
""
,
description
!=
NULL
?
description
:
""
);
}
static
void
smileys_refresh_theme_list
(
void
)
{
GList
*
it
;
GtkTreeIter
iter
;
gchar
*
description
;
description
=
get_theme_markup
(
_
(
"none"
),
FALSE
,
_
(
"Penguin Pimps"
),
_
(
"Selecting this disables graphical emoticons."
));
gtk_list_store_append
(
prefs_smiley_themes
,
&
iter
);
gtk_list_store_set
(
prefs_smiley_themes
,
&
iter
,
0
,
NULL
,
1
,
description
,
2
,
"none"
,
-1
);
g_free
(
description
);
for
(
it
=
pidgin_smiley_theme_get_all
();
it
;
it
=
g_list_next
(
it
))
{
PidginSmileyTheme
*
theme
=
it
->
data
;
description
=
get_theme_markup
(
_
(
pidgin_smiley_theme_get_name
(
theme
)),
FALSE
,
_
(
pidgin_smiley_theme_get_author
(
theme
)),
_
(
pidgin_smiley_theme_get_description
(
theme
)));
gtk_list_store_append
(
prefs_smiley_themes
,
&
iter
);
gtk_list_store_set
(
prefs_smiley_themes
,
&
iter
,
0
,
pidgin_smiley_theme_get_icon
(
theme
),
1
,
description
,
2
,
pidgin_smiley_theme_get_name
(
theme
),
-1
);
g_free
(
description
);
}
}
/* adds the themes to the theme list from the manager so they can be displayed in prefs */
static
void
prefs_themes_sort
(
PurpleTheme
*
theme
)
{
GdkPixbuf
*
pixbuf
=
NULL
;
GtkTreeIter
iter
;
gchar
*
image_full
=
NULL
,
*
markup
;
const
gchar
*
name
,
*
author
,
*
description
;
if
(
PIDGIN_IS_STATUS_ICON_THEME
(
theme
)){
GtkListStore
*
store
;
store
=
prefs_status_icon_themes
;
image_full
=
purple_theme_get_image_full
(
theme
);
if
(
image_full
!=
NULL
){
pixbuf
=
pidgin_pixbuf_new_from_file_at_scale
(
image_full
,
PREFS_OPTIMAL_ICON_SIZE
,
PREFS_OPTIMAL_ICON_SIZE
,
TRUE
);
g_free
(
image_full
);
}
else
pixbuf
=
NULL
;
name
=
purple_theme_get_name
(
theme
);
author
=
purple_theme_get_author
(
theme
);
description
=
purple_theme_get_description
(
theme
);
markup
=
get_theme_markup
(
name
,
FALSE
,
author
,
description
);
gtk_list_store_append
(
store
,
&
iter
);
gtk_list_store_set
(
store
,
&
iter
,
0
,
pixbuf
,
1
,
markup
,
2
,
name
,
-1
);
g_free
(
markup
);
if
(
pixbuf
!=
NULL
)
g_object_unref
(
G_OBJECT
(
pixbuf
));
}
}
static
void
prefs_set_active_theme_combo
(
GtkWidget
*
combo_box
,
GtkListStore
*
store
,
const
gchar
*
current_theme
)
{
GtkTreeIter
iter
;
gchar
*
theme
=
NULL
;
gboolean
unset
=
TRUE
;
if
(
current_theme
&&
*
current_theme
&&
gtk_tree_model_get_iter_first
(
GTK_TREE_MODEL
(
store
),
&
iter
))
{
do
{
gtk_tree_model_get
(
GTK_TREE_MODEL
(
store
),
&
iter
,
2
,
&
theme
,
-1
);
if
(
purple_strequal
(
current_theme
,
theme
))
{
gtk_combo_box_set_active_iter
(
GTK_COMBO_BOX
(
combo_box
),
&
iter
);
unset
=
FALSE
;
}
g_free
(
theme
);
}
while
(
gtk_tree_model_iter_next
(
GTK_TREE_MODEL
(
store
),
&
iter
));
}
if
(
unset
)
gtk_combo_box_set_active
(
GTK_COMBO_BOX
(
combo_box
),
0
);
}
static
void
prefs_themes_refresh
(
void
)
{
GdkPixbuf
*
pixbuf
=
NULL
;
gchar
*
tmp
;
GtkTreeIter
iter
;
/* refresh the list of themes in the manager */
purple_theme_manager_refresh
();
tmp
=
g_build_filename
(
PURPLE_DATADIR
,
"icons"
,
"hicolor"
,
"32x32"
,
"apps"
,
"im.pidgin.Pidgin3.png"
,
NULL
);
pixbuf
=
pidgin_pixbuf_new_from_file_at_scale
(
tmp
,
PREFS_OPTIMAL_ICON_SIZE
,
PREFS_OPTIMAL_ICON_SIZE
,
TRUE
);
g_free
(
tmp
);
/* status icon themes */
gtk_list_store_clear
(
prefs_status_icon_themes
);
gtk_list_store_append
(
prefs_status_icon_themes
,
&
iter
);
tmp
=
get_theme_markup
(
_
(
"Default"
),
FALSE
,
_
(
"Penguin Pimps"
),
_
(
"The default Pidgin status icon theme"
));
gtk_list_store_set
(
prefs_status_icon_themes
,
&
iter
,
0
,
pixbuf
,
1
,
tmp
,
2
,
""
,
-1
);
g_free
(
tmp
);
if
(
pixbuf
)
g_object_unref
(
G_OBJECT
(
pixbuf
));
/* smiley themes */
gtk_list_store_clear
(
prefs_smiley_themes
);
purple_theme_manager_for_each_theme
(
prefs_themes_sort
);
smileys_refresh_theme_list
();
/* set active */
prefs_set_active_theme_combo
(
prefs_status_themes_combo_box
,
prefs_status_icon_themes
,
purple_prefs_get_string
(
PIDGIN_PREFS_ROOT
"/status/icon-theme"
));
prefs_set_active_theme_combo
(
prefs_smiley_themes_combo_box
,
prefs_smiley_themes
,
purple_prefs_get_string
(
PIDGIN_PREFS_ROOT
"/smileys/theme"
));
}
/* init all the theme variables so that the themes can be sorted later and used by pref pages */
static
void
prefs_themes_init
(
void
)
{
prefs_status_icon_themes
=
gtk_list_store_new
(
3
,
GDK_TYPE_PIXBUF
,
G_TYPE_STRING
,
G_TYPE_STRING
);
prefs_smiley_themes
=
gtk_list_store_new
(
3
,
GDK_TYPE_PIXBUF
,
G_TYPE_STRING
,
G_TYPE_STRING
);
}
/*
* prefs_theme_find_theme:
* @path: A directory containing a theme. The theme could be at the
* top level of this directory or in any subdirectory thereof.
* @type: The type of theme to load. The loader for this theme type
* will be used and this loader will determine what constitutes a
* "theme."
*
* Attempt to load the given directory as a theme. If we are unable to
* open the path as a theme then we recurse into path and attempt to
* load each subdirectory that we encounter.
*
* Returns: A new reference to a #PurpleTheme.
*/
static
PurpleTheme
*
prefs_theme_find_theme
(
const
gchar
*
path
,
const
gchar
*
type
)
{
PurpleTheme
*
theme
=
purple_theme_manager_load_theme
(
path
,
type
);
GDir
*
dir
=
g_dir_open
(
path
,
0
,
NULL
);
const
gchar
*
next
;
while
(
!
PURPLE_IS_THEME
(
theme
)
&&
(
next
=
g_dir_read_name
(
dir
)))
{
gchar
*
next_path
=
g_build_filename
(
path
,
next
,
NULL
);
if
(
g_file_test
(
next_path
,
G_FILE_TEST_IS_DIR
))
theme
=
prefs_theme_find_theme
(
next_path
,
type
);
g_free
(
next_path
);
}
g_dir_close
(
dir
);
return
theme
;
}
/* Eww. Seriously ewww. But thanks, grim! This is taken from guifications2 */
static
gboolean
purple_theme_file_copy
(
const
gchar
*
source
,
const
gchar
*
destination
)
{
FILE
*
src
,
*
dest
;
gint
chr
=
EOF
;
if
(
!
(
src
=
g_fopen
(
source
,
"rb"
)))
return
FALSE
;
if
(
!
(
dest
=
g_fopen
(
destination
,
"wb"
)))
{
fclose
(
src
);
return
FALSE
;
}
while
((
chr
=
fgetc
(
src
))
!=
EOF
)
{
fputc
(
chr
,
dest
);
}
fclose
(
dest
);
fclose
(
src
);
return
TRUE
;
}
static
void
free_theme_info
(
struct
theme_info
*
info
)
{
if
(
info
!=
NULL
)
{
g_free
(
info
->
type
);
g_free
(
info
->
extension
);
g_free
(
info
->
original_name
);
g_free
(
info
);
}
}
/* installs a theme, info is freed by function */
static
void
theme_install_theme
(
char
*
path
,
struct
theme_info
*
info
)
{
gchar
*
destdir
;
const
char
*
tail
;
gboolean
is_smiley_theme
,
is_archive
;
PurpleTheme
*
theme
=
NULL
;
if
(
info
==
NULL
)
return
;
/* check the extension */
tail
=
info
->
extension
?
info
->
extension
:
strrchr
(
path
,
'.'
);
if
(
!
tail
)
{
free_theme_info
(
info
);
return
;
}
is_archive
=
!
g_ascii_strcasecmp
(
tail
,
".gz"
)
||
!
g_ascii_strcasecmp
(
tail
,
".tgz"
);
/* Just to be safe */
g_strchomp
(
path
);
if
((
is_smiley_theme
=
purple_strequal
(
info
->
type
,
"smiley"
)))
destdir
=
g_build_filename
(
purple_data_dir
(),
"smileys"
,
NULL
);
else
destdir
=
g_build_filename
(
purple_data_dir
(),
"themes"
,
"temp"
,
NULL
);
/* We'll check this just to make sure. This also lets us do something different on
* other platforms, if need be */
if
(
is_archive
)
{
#ifndef _WIN32
gchar
*
path_escaped
=
g_shell_quote
(
path
);
gchar
*
destdir_escaped
=
g_shell_quote
(
destdir
);
gchar
*
command
;
if
(
!
g_file_test
(
destdir
,
G_FILE_TEST_IS_DIR
))
{
g_mkdir_with_parents
(
destdir
,
S_IRUSR
|
S_IWUSR
|
S_IXUSR
);
}
command
=
g_strdup_printf
(
"tar > /dev/null xzf %s -C %s"
,
path_escaped
,
destdir_escaped
);
g_free
(
path_escaped
);
g_free
(
destdir_escaped
);
/* Fire! */
if
(
system
(
command
))
{
purple_notify_error
(
NULL
,
NULL
,
_
(
"Theme failed to unpack."
),
NULL
,
NULL
);
g_free
(
command
);
g_free
(
destdir
);
free_theme_info
(
info
);
return
;
}
g_free
(
command
);
#else
if
(
!
winpidgin_gz_untar
(
path
,
destdir
))
{
purple_notify_error
(
NULL
,
NULL
,
_
(
"Theme failed to unpack."
),
NULL
,
NULL
);
g_free
(
destdir
);
free_theme_info
(
info
);
return
;
}
#endif
}
if
(
is_smiley_theme
)
{
/* just extract the folder to the smiley directory */
prefs_themes_refresh
();
}
else
if
(
is_archive
)
{
theme
=
prefs_theme_find_theme
(
destdir
,
info
->
type
);
if
(
PURPLE_IS_THEME
(
theme
))
{
/* create the location for the theme */
gchar
*
theme_dest
=
g_build_filename
(
purple_data_dir
(),
"themes"
,
purple_theme_get_name
(
theme
),
"purple"
,
info
->
type
,
NULL
);
if
(
!
g_file_test
(
theme_dest
,
G_FILE_TEST_IS_DIR
))
{
g_mkdir_with_parents
(
theme_dest
,
S_IRUSR
|
S_IWUSR
|
S_IXUSR
);
}
g_free
(
theme_dest
);
theme_dest
=
g_build_filename
(
purple_data_dir
(),
"themes"
,
purple_theme_get_name
(
theme
),
"purple"
,
info
->
type
,
NULL
);
/* move the entire directory to new location */
if
(
g_rename
(
purple_theme_get_dir
(
theme
),
theme_dest
))
{
purple_debug_error
(
"gtkprefs"
,
"Error renaming %s to %s: "
"%s
\n
"
,
purple_theme_get_dir
(
theme
),
theme_dest
,
g_strerror
(
errno
));
}
g_free
(
theme_dest
);
if
(
g_remove
(
destdir
)
!=
0
)
{
purple_debug_error
(
"gtkprefs"
,
"couldn't remove temp (dest) path
\n
"
);
}
g_object_unref
(
theme
);
prefs_themes_refresh
();
}
else
{
/* something was wrong with the theme archive */
g_unlink
(
destdir
);
purple_notify_error
(
NULL
,
NULL
,
_
(
"Theme failed to load."
),
NULL
,
NULL
);
}
}
else
{
/* just a single file so copy it to a new temp directory and attempt to load it*/
gchar
*
temp_path
,
*
temp_file
;
temp_path
=
g_build_filename
(
purple_data_dir
(),
"themes"
,
"temp"
,
"sub_folder"
,
NULL
);
if
(
info
->
original_name
!=
NULL
)
{
/* name was changed from the original (probably a dnd) change it back before loading */
temp_file
=
g_build_filename
(
temp_path
,
info
->
original_name
,
NULL
);
}
else
{
gchar
*
source_name
=
g_path_get_basename
(
path
);
temp_file
=
g_build_filename
(
temp_path
,
source_name
,
NULL
);
g_free
(
source_name
);
}
if
(
!
g_file_test
(
temp_path
,
G_FILE_TEST_IS_DIR
))
{
g_mkdir_with_parents
(
temp_path
,
S_IRUSR
|
S_IWUSR
|
S_IXUSR
);
}
if
(
purple_theme_file_copy
(
path
,
temp_file
))
{
/* find the theme, could be in subfolder */
theme
=
prefs_theme_find_theme
(
temp_path
,
info
->
type
);
if
(
PURPLE_IS_THEME
(
theme
))
{
gchar
*
theme_dest
=
g_build_filename
(
purple_data_dir
(),
"themes"
,
purple_theme_get_name
(
theme
),
"purple"
,
info
->
type
,
NULL
);
if
(
!
g_file_test
(
theme_dest
,
G_FILE_TEST_IS_DIR
))
{
g_mkdir_with_parents
(
theme_dest
,
S_IRUSR
|
S_IWUSR
|
S_IXUSR
);
}
if
(
g_rename
(
purple_theme_get_dir
(
theme
),
theme_dest
))
{
purple_debug_error
(
"gtkprefs"
,
"Error renaming %s to %s: "
"%s
\n
"
,
purple_theme_get_dir
(
theme
),
theme_dest
,
g_strerror
(
errno
));
}
g_free
(
theme_dest
);
g_object_unref
(
theme
);
prefs_themes_refresh
();
}
else
{
if
(
g_remove
(
temp_path
)
!=
0
)
{
purple_debug_error
(
"gtkprefs"
,
"couldn't remove temp path"
);
}
purple_notify_error
(
NULL
,
NULL
,
_
(
"Theme failed to load."
),
NULL
,
NULL
);
}
}
else
{
purple_notify_error
(
NULL
,
NULL
,
_
(
"Theme failed to copy."
),
NULL
,
NULL
);
}
g_free
(
temp_file
);
g_free
(
temp_path
);
}
g_free
(
destdir
);
free_theme_info
(
info
);
}
static
void
theme_got_url
(
G_GNUC_UNUSED
SoupSession
*
session
,
SoupMessage
*
msg
,
gpointer
_info
)
{
struct
theme_info
*
info
=
_info
;
FILE
*
f
;
gchar
*
path
;
size_t
wc
;
if
(
!
SOUP_STATUS_IS_SUCCESSFUL
(
msg
->
status_code
))
{
free_theme_info
(
info
);
return
;
}
f
=
purple_mkstemp
(
&
path
,
TRUE
);
wc
=
fwrite
(
msg
->
response_body
->
data
,
msg
->
response_body
->
length
,
1
,
f
);
if
(
wc
!=
1
)
{
purple_debug_warning
(
"theme_got_url"
,
"Unable to write theme data.
\n
"
);
fclose
(
f
);
g_unlink
(
path
);
g_free
(
path
);
free_theme_info
(
info
);
return
;
}
fclose
(
f
);
theme_install_theme
(
path
,
info
);
g_unlink
(
path
);
g_free
(
path
);
}
static
void
theme_dnd_recv
(
GtkWidget
*
widget
,
GdkDragContext
*
dc
,
guint
x
,
guint
y
,
GtkSelectionData
*
sd
,
guint
info
,
guint
t
,
gpointer
user_data
)
{
gchar
*
name
=
g_strchomp
((
gchar
*
)
gtk_selection_data_get_data
(
sd
));
if
((
gtk_selection_data_get_length
(
sd
)
>=
0
)
&&
(
gtk_selection_data_get_format
(
sd
)
==
8
))
{
/* Well, it looks like the drag event was cool.
* Let's do something with it */
gchar
*
temp
;
struct
theme_info
*
info
=
g_new0
(
struct
theme_info
,
1
);
info
->
type
=
g_strdup
((
gchar
*
)
user_data
);
info
->
extension
=
g_strdup
(
g_strrstr
(
name
,
"."
));
temp
=
g_strrstr
(
name
,
"/"
);
info
->
original_name
=
temp
?
g_strdup
(
++
temp
)
:
NULL
;
if
(
!
g_ascii_strncasecmp
(
name
,
"file://"
,
7
))
{
GError
*
converr
=
NULL
;
gchar
*
tmp
;
/* It looks like we're dealing with a local file. Let's
* just untar it in the right place */
if
(
!
(
tmp
=
g_filename_from_uri
(
name
,
NULL
,
&
converr
)))
{
purple_debug_error
(
"theme dnd"
,
"%s"
,
converr
?
converr
->
message
:
"g_filename_from_uri error"
);
free_theme_info
(
info
);
return
;
}
theme_install_theme
(
tmp
,
info
);
g_free
(
tmp
);
}
else
if
(
!
g_ascii_strncasecmp
(
name
,
"http://"
,
7
)
||
!
g_ascii_strncasecmp
(
name
,
"https://"
,
8
))
{
/* Oo, a web drag and drop. This is where things
* will start to get interesting */
SoupMessage
*
msg
;
if
(
prefs
->
theme
.
session
==
NULL
)
{
prefs
->
theme
.
session
=
soup_session_new
();
}
soup_session_abort
(
prefs
->
theme
.
session
);
msg
=
soup_message_new
(
"GET"
,
name
);
// purple_http_request_set_max_len(msg, PREFS_MAX_DOWNLOADED_THEME_SIZE);
soup_session_queue_message
(
prefs
->
theme
.
session
,
msg
,
theme_got_url
,
info
);
}
else
free_theme_info
(
info
);
gtk_drag_finish
(
dc
,
TRUE
,
FALSE
,
t
);
}
gtk_drag_finish
(
dc
,
FALSE
,
FALSE
,
t
);
}
/* builds a theme combo box from a list store with colums: icon preview, markup, theme name */
static
void
prefs_build_theme_combo_box
(
GtkWidget
*
combo_box
,
GtkListStore
*
store
,
const
char
*
current_theme
,
const
char
*
type
)
{
GtkTargetEntry
te
[
3
]
=
{
{
"text/plain"
,
0
,
0
},
{
"text/uri-list"
,
0
,
1
},
{
"STRING"
,
0
,
2
}
};
g_return_if_fail
(
store
!=
NULL
&&
current_theme
!=
NULL
);
gtk_combo_box_set_model
(
GTK_COMBO_BOX
(
combo_box
),
GTK_TREE_MODEL
(
store
));
gtk_drag_dest_set
(
combo_box
,
GTK_DEST_DEFAULT_MOTION
|
GTK_DEST_DEFAULT_HIGHLIGHT
|
GTK_DEST_DEFAULT_DROP
,
te
,
sizeof
(
te
)
/
sizeof
(
GtkTargetEntry
)
,
GDK_ACTION_COPY
|
GDK_ACTION_MOVE
);
g_signal_connect
(
G_OBJECT
(
combo_box
),
"drag_data_received"
,
G_CALLBACK
(
theme_dnd_recv
),
(
gpointer
)
type
);
}
/* sets the current smiley theme */
static
void
prefs_set_smiley_theme_cb
(
GtkComboBox
*
combo_box
,
gpointer
user_data
)
{
gchar
*
new_theme
;
GtkTreeIter
new_iter
;
if
(
gtk_combo_box_get_active_iter
(
combo_box
,
&
new_iter
))
{
gtk_tree_model_get
(
GTK_TREE_MODEL
(
prefs_smiley_themes
),
&
new_iter
,
2
,
&
new_theme
,
-1
);
purple_prefs_set_string
(
PIDGIN_PREFS_ROOT
"/smileys/theme"
,
new_theme
);
g_free
(
new_theme
);
}
}
/* Does same as normal sort, except "none" is sorted first */
static
gint
pidgin_sort_smileys
(
GtkTreeModel
*
model
,
GtkTreeIter
*
a
,
GtkTreeIter
*
b
,
gpointer
userdata
)
{
gint
ret
=
0
;
gchar
*
name1
=
NULL
,
*
name2
=
NULL
;
gtk_tree_model_get
(
model
,
a
,
2
,
&
name1
,
-1
);
gtk_tree_model_get
(
model
,
b
,
2
,
&
name2
,
-1
);
if
(
name1
==
NULL
||
name2
==
NULL
)
{
if
(
!
(
name1
==
NULL
&&
name2
==
NULL
))
ret
=
(
name1
==
NULL
)
?
-1
:
1
;
}
else
if
(
!
g_ascii_strcasecmp
(
name1
,
"none"
))
{
if
(
!
g_utf8_collate
(
name1
,
name2
))
ret
=
0
;
else
/* Sort name1 first */
ret
=
-1
;
}
else
if
(
!
g_ascii_strcasecmp
(
name2
,
"none"
))
{
/* Sort name2 first */
ret
=
1
;
}
else
{
/* Neither string is "none", default to normal sort */
ret
=
purple_utf8_strcasecmp
(
name1
,
name2
);
}
g_free
(
name1
);
g_free
(
name2
);
return
ret
;
}
/* sets the current icon theme */
static
void
prefs_set_status_icon_theme_cb
(
GtkComboBox
*
combo_box
,
gpointer
user_data
)
{
PidginStatusIconTheme
*
theme
=
NULL
;
GtkTreeIter
iter
;
gchar
*
name
=
NULL
;
if
(
gtk_combo_box_get_active_iter
(
combo_box
,
&
iter
))
{
gtk_tree_model_get
(
GTK_TREE_MODEL
(
prefs_status_icon_themes
),
&
iter
,
2
,
&
name
,
-1
);
if
(
!
name
||
*
name
)
theme
=
PIDGIN_STATUS_ICON_THEME
(
purple_theme_manager_find_theme
(
name
,
"status-icon"
));
g_free
(
name
);
pidgin_stock_load_status_icon_theme
(
theme
);
pidgin_blist_refresh
(
purple_blist_get_default
());
}
}
static
void
bind_theme_page
(
PidginPrefsWindow
*
win
)
{
/* Status Icon Themes */
prefs_build_theme_combo_box
(
win
->
theme
.
status
,
prefs_status_icon_themes
,
PIDGIN_PREFS_ROOT
"/status/icon-theme"
,
"icon"
);
prefs_status_themes_combo_box
=
win
->
theme
.
status
;
/* Smiley Themes */
prefs_build_theme_combo_box
(
win
->
theme
.
smiley
,
prefs_smiley_themes
,
PIDGIN_PREFS_ROOT
"/smileys/theme"
,
"smiley"
);
prefs_smiley_themes_combo_box
=
win
->
theme
.
smiley
;
/* Custom sort so "none" theme is at top of list */
gtk_tree_sortable_set_sort_func
(
GTK_TREE_SORTABLE
(
prefs_smiley_themes
),
2
,
pidgin_sort_smileys
,
NULL
,
NULL
);
gtk_tree_sortable_set_sort_column_id
(
GTK_TREE_SORTABLE
(
prefs_smiley_themes
),
2
,
GTK_SORT_ASCENDING
);
}
static
void
formatting_toggle_cb
(
TalkatuActionGroup
*
ag
,
GAction
*
action
,
const
gchar
*
name
,
gpointer
data
)
{
gboolean
activated
=
talkatu_action_group_get_action_activated
(
ag
,
name
);
if
(
g_ascii_strcasecmp
(
TALKATU_ACTION_FORMAT_BOLD
,
name
)
!=
0
)
{
purple_prefs_set_bool
(
PIDGIN_PREFS_ROOT
"/conversations/send_bold"
,
activated
);
}
else
if
(
g_ascii_strcasecmp
(
TALKATU_ACTION_FORMAT_ITALIC
,
name
)
!=
0
)
{
purple_prefs_set_bool
(
PIDGIN_PREFS_ROOT
"/conversations/send_italic"
,
activated
);
}
else
if
(
g_ascii_strcasecmp
(
TALKATU_ACTION_FORMAT_UNDERLINE
,
name
)
!=
0
)
{
purple_prefs_set_bool
(
PIDGIN_PREFS_ROOT
"/conversations/send_underline"
,
activated
);
}
else
if
(
g_ascii_strcasecmp
(
TALKATU_ACTION_FORMAT_STRIKETHROUGH
,
name
)
!=
0
)
{
purple_prefs_set_bool
(
PIDGIN_PREFS_ROOT
"/conversations/send_strike"
,
activated
);
}
}
static
void
bind_interface_page
(
PidginPrefsWindow
*
win
)
{
/* System Tray */
win
->
iface
.
im
.
hide_new
.
type
=
PURPLE_PREF_STRING
;
win
->
iface
.
im
.
hide_new
.
key
=
PIDGIN_PREFS_ROOT
"/conversations/im/hide_new"
;
pidgin_prefs_bind_dropdown
(
&
win
->
iface
.
im
.
hide_new
);
#ifdef _WIN32
pidgin_prefs_bind_checkbox
(
PIDGIN_PREFS_ROOT
"/win32/minimize_new_convs"
,
win
->
iface
.
win32
.
minimize_new_convs
);
#else
gtk_widget_hide
(
win
->
iface
.
win32
.
minimize_new_convs
);
#endif
/* All the tab options! */
pidgin_prefs_bind_checkbox
(
PIDGIN_PREFS_ROOT
"/conversations/tabs"
,
win
->
iface
.
conversations
.
tabs
);
/*
* Connect a signal to the above preference. When conversations are not
* shown in a tabbed window then all tabbing options should be disabled.
*/
g_object_bind_property
(
win
->
iface
.
conversations
.
tabs
,
"active"
,
win
->
iface
.
conversations
.
tabs_vbox
,
"sensitive"
,
G_BINDING_SYNC_CREATE
);
pidgin_prefs_bind_checkbox
(
PIDGIN_PREFS_ROOT
"/conversations/close_on_tabs"
,
win
->
iface
.
conversations
.
close_on_tabs
);
win
->
iface
.
conversations
.
tab_side
.
type
=
PURPLE_PREF_INT
;
win
->
iface
.
conversations
.
tab_side
.
key
=
PIDGIN_PREFS_ROOT
"/conversations/tab_side"
;
pidgin_prefs_bind_dropdown
(
&
win
->
iface
.
conversations
.
tab_side
);
}
/* This is also Win32-specific, but must be visible for Glade binding. */
static
void
apply_custom_font
(
GtkWidget
*
unused
,
PidginPrefsWindow
*
win
)
{
PangoFontDescription
*
desc
=
NULL
;
if
(
!
purple_prefs_get_bool
(
PIDGIN_PREFS_ROOT
"/conversations/use_theme_font"
))
{
const
char
*
font
=
purple_prefs_get_string
(
PIDGIN_PREFS_ROOT
"/conversations/custom_font"
);
desc
=
pango_font_description_from_string
(
font
);
}
gtk_widget_override_font
(
win
->
conversations
.
format_view
,
desc
);
if
(
desc
)
pango_font_description_free
(
desc
);
}
static
void
pidgin_custom_font_set
(
GtkWidget
*
font_button
,
PidginPrefsWindow
*
win
)
{
purple_prefs_set_string
(
PIDGIN_PREFS_ROOT
"/conversations/custom_font"
,
gtk_font_chooser_get_font
(
GTK_FONT_CHOOSER
(
font_button
)));
apply_custom_font
(
font_button
,
win
);
}
static
void
bind_conv_page
(
PidginPrefsWindow
*
win
)
{
GSimpleActionGroup
*
ag
=
NULL
;
win
->
conversations
.
notification_chat
.
type
=
PURPLE_PREF_INT
;
win
->
conversations
.
notification_chat
.
key
=
PIDGIN_PREFS_ROOT
"/conversations/notification_chat"
;
pidgin_prefs_bind_dropdown
(
&
win
->
conversations
.
notification_chat
);
pidgin_prefs_bind_checkbox
(
PIDGIN_PREFS_ROOT
"/conversations/show_incoming_formatting"
,
win
->
conversations
.
show_incoming_formatting
);
pidgin_prefs_bind_checkbox
(
PIDGIN_PREFS_ROOT
"/conversations/im/close_immediately"
,
win
->
conversations
.
im
.
close_immediately
);
pidgin_prefs_bind_checkbox
(
"/purple/conversations/im/send_typing"
,
win
->
conversations
.
im
.
send_typing
);
pidgin_prefs_bind_checkbox
(
PIDGIN_PREFS_ROOT
"/conversations/use_smooth_scrolling"
,
win
->
conversations
.
use_smooth_scrolling
);
#ifdef _WIN32
pidgin_prefs_bind_checkbox
(
PIDGIN_PREFS_ROOT
"/win32/blink_im"
,
win
->
conversations
.
win32
.
blink_im
);
#else
gtk_widget_hide
(
win
->
conversations
.
win32
.
blink_im
);
#endif
#if 0
/* TODO: it's not implemented */
pidgin_prefs_bind_checkbox(
PIDGIN_PREFS_ROOT "/conversations/resize_custom_smileys",
win->conversations.resize_custom_smileys);
pidgin_prefs_bind_spin_button(
PIDGIN_PREFS_ROOT "/conversations/custom_smileys_size",
win->conversations.custom_smileys_size);
g_object_bind_property(win->conversations.resize_custom_smileys, "active",
win->conversations.custom_smileys_size, "sensitive",
G_BINDING_SYNC_CREATE);
#endif
pidgin_prefs_bind_spin_button
(
PIDGIN_PREFS_ROOT
"/conversations/minimum_entry_lines"
,
win
->
conversations
.
minimum_entry_lines
);
#ifdef _WIN32
{
const
char
*
font_name
;
gtk_widget_show
(
win
->
conversations
.
font_frame
);
pidgin_prefs_bind_checkbox
(
PIDGIN_PREFS_ROOT
"/conversations/use_theme_font"
,
win
->
conversations
.
use_theme_font
);
font_name
=
purple_prefs_get_string
(
PIDGIN_PREFS_ROOT
"/conversations/custom_font"
);
if
(
font_name
!=
NULL
&&
*
font_name
!=
'\0'
)
{
gtk_font_chooser_set_font
(
GTK_FONT_CHOOSER
(
win
->
conversations
.
custom_font
),
font_name
);
}
g_object_bind_property
(
win
->
conversations
.
use_theme_font
,
"active"
,
win
->
conversations
.
custom_font_hbox
,
"sensitive"
,
G_BINDING_SYNC_CREATE
|
G_BINDING_INVERT_BOOLEAN
);
}
#endif
ag
=
talkatu_buffer_get_action_group
(
TALKATU_BUFFER
(
win
->
conversations
.
format_buffer
));
g_signal_connect_after
(
G_OBJECT
(
ag
),
"action-activated"
,
G_CALLBACK
(
formatting_toggle_cb
),
NULL
);
}
static
void
network_ip_changed
(
GtkEntry
*
entry
,
gpointer
data
)
{
const
gchar
*
text
=
gtk_entry_get_text
(
entry
);
GtkStyleContext
*
context
=
gtk_widget_get_style_context
(
GTK_WIDGET
(
entry
));
if
(
text
&&
*
text
)
{
if
(
g_hostname_is_ip_address
(
text
))
{
purple_network_set_public_ip
(
text
);
gtk_style_context_add_class
(
context
,
"good-ip"
);
gtk_style_context_remove_class
(
context
,
"bad-ip"
);
}
else
{
gtk_style_context_add_class
(
context
,
"bad-ip"
);
gtk_style_context_remove_class
(
context
,
"good-ip"
);
}
}
else
{
purple_network_set_public_ip
(
""
);
gtk_style_context_remove_class
(
context
,
"bad-ip"
);
gtk_style_context_remove_class
(
context
,
"good-ip"
);
}
}
static
gboolean
network_stun_server_changed_cb
(
GtkWidget
*
widget
,
GdkEventFocus
*
event
,
gpointer
data
)
{
GtkEntry
*
entry
=
GTK_ENTRY
(
widget
);
purple_prefs_set_string
(
"/purple/network/stun_server"
,
gtk_entry_get_text
(
entry
));
purple_network_set_stun_server
(
gtk_entry_get_text
(
entry
));
return
FALSE
;
}
static
gboolean
network_turn_server_changed_cb
(
GtkWidget
*
widget
,
GdkEventFocus
*
event
,
gpointer
data
)
{
GtkEntry
*
entry
=
GTK_ENTRY
(
widget
);
purple_prefs_set_string
(
"/purple/network/turn_server"
,
gtk_entry_get_text
(
entry
));
purple_network_set_turn_server
(
gtk_entry_get_text
(
entry
));
return
FALSE
;
}
static
void
proxy_changed_cb
(
const
char
*
name
,
PurplePrefType
type
,
gconstpointer
value
,
gpointer
data
)
{
PidginPrefsWindow
*
win
=
data
;
const
char
*
proxy
=
value
;
if
(
!
purple_strequal
(
proxy
,
"none"
)
&&
!
purple_strequal
(
proxy
,
"envvar"
))
gtk_widget_show_all
(
win
->
proxy
.
options
);
else
gtk_widget_hide
(
win
->
proxy
.
options
);
}
static
void
proxy_print_option
(
GtkWidget
*
entry
,
PidginPrefsWindow
*
win
)
{
if
(
entry
==
win
->
proxy
.
host
)
{
purple_prefs_set_string
(
"/purple/proxy/host"
,
gtk_entry_get_text
(
GTK_ENTRY
(
entry
)));
}
else
if
(
entry
==
win
->
proxy
.
port
)
{
purple_prefs_set_int
(
"/purple/proxy/port"
,
gtk_spin_button_get_value_as_int
(
GTK_SPIN_BUTTON
(
entry
)));
}
else
if
(
entry
==
win
->
proxy
.
username
)
{
purple_prefs_set_string
(
"/purple/proxy/username"
,
gtk_entry_get_text
(
GTK_ENTRY
(
entry
)));
}
else
if
(
entry
==
win
->
proxy
.
password
)
{
purple_prefs_set_string
(
"/purple/proxy/password"
,
gtk_entry_get_text
(
GTK_ENTRY
(
entry
)));
}
}
static
void
proxy_button_clicked_cb
(
GtkWidget
*
button
,
PidginPrefsWindow
*
win
)
{
GError
*
err
=
NULL
;
if
(
g_spawn_command_line_async
(
win
->
proxy
.
gnome_program_path
,
&
err
))
return
;
purple_notify_error
(
NULL
,
NULL
,
_
(
"Cannot start proxy configuration program."
),
err
->
message
,
NULL
);
g_error_free
(
err
);
}
static
void
auto_ip_button_clicked_cb
(
GtkWidget
*
button
,
gpointer
null
)
{
const
char
*
ip
;
PurpleStunNatDiscovery
*
stun
;
char
*
auto_ip_text
;
GList
*
list
=
NULL
;
/* Make a lookup for the auto-detected IP ourselves. */
if
(
purple_prefs_get_bool
(
"/purple/network/auto_ip"
))
{
/* Check if STUN discovery was already done */
stun
=
purple_stun_discover
(
NULL
);
if
((
stun
!=
NULL
)
&&
(
stun
->
status
==
PURPLE_STUN_STATUS_DISCOVERED
))
{
ip
=
stun
->
publicip
;
}
else
{
/* Attempt to get the IP from a NAT device using UPnP */
ip
=
purple_upnp_get_public_ip
();
if
(
ip
==
NULL
)
{
/* Attempt to get the IP from a NAT device using NAT-PMP */
ip
=
purple_pmp_get_public_ip
();
if
(
ip
==
NULL
)
{
/* Just fetch the first IP of the local system */
list
=
nice_interfaces_get_local_ips
(
FALSE
);
if
(
list
)
{
ip
=
list
->
data
;
}
else
{
ip
=
"0.0.0.0"
;
}
}
}
}
}
else
{
ip
=
_
(
"Disabled"
);
}
auto_ip_text
=
g_strdup_printf
(
_
(
"Use _automatically detected IP address: %s"
),
ip
);
gtk_button_set_label
(
GTK_BUTTON
(
button
),
auto_ip_text
);
g_free
(
auto_ip_text
);
g_list_free_full
(
list
,
g_free
);
}
static
void
bind_network_page
(
PidginPrefsWindow
*
win
)
{
GtkStyleContext
*
context
;
GtkCssProvider
*
ip_css
;
const
gchar
*
res
=
"/im/pidgin/Pidgin/Prefs/ip.css"
;
gtk_entry_set_text
(
GTK_ENTRY
(
win
->
network
.
stun_server
),
purple_prefs_get_string
(
"/purple/network/stun_server"
));
pidgin_prefs_bind_checkbox
(
"/purple/network/auto_ip"
,
win
->
network
.
auto_ip
);
auto_ip_button_clicked_cb
(
win
->
network
.
auto_ip
,
NULL
);
/* Update label */
gtk_entry_set_text
(
GTK_ENTRY
(
win
->
network
.
public_ip
),
purple_network_get_public_ip
());
ip_css
=
gtk_css_provider_new
();
gtk_css_provider_load_from_resource
(
ip_css
,
res
);
context
=
gtk_widget_get_style_context
(
win
->
network
.
public_ip
);
gtk_style_context_add_provider
(
context
,
GTK_STYLE_PROVIDER
(
ip_css
),
GTK_STYLE_PROVIDER_PRIORITY_APPLICATION
);
g_object_bind_property
(
win
->
network
.
auto_ip
,
"active"
,
win
->
network
.
public_ip_hbox
,
"sensitive"
,
G_BINDING_SYNC_CREATE
|
G_BINDING_INVERT_BOOLEAN
);
pidgin_prefs_bind_checkbox
(
"/purple/network/map_ports"
,
win
->
network
.
map_ports
);
pidgin_prefs_bind_checkbox
(
"/purple/network/ports_range_use"
,
win
->
network
.
ports_range_use
);
g_object_bind_property
(
win
->
network
.
ports_range_use
,
"active"
,
win
->
network
.
ports_range_hbox
,
"sensitive"
,
G_BINDING_SYNC_CREATE
);
pidgin_prefs_bind_spin_button
(
"/purple/network/ports_range_start"
,
win
->
network
.
ports_range_start
);
pidgin_prefs_bind_spin_button
(
"/purple/network/ports_range_end"
,
win
->
network
.
ports_range_end
);
/* TURN server */
gtk_entry_set_text
(
GTK_ENTRY
(
win
->
network
.
turn_server
),
purple_prefs_get_string
(
"/purple/network/turn_server"
));
pidgin_prefs_bind_spin_button
(
"/purple/network/turn_port"
,
win
->
network
.
turn_port_udp
);
pidgin_prefs_bind_spin_button
(
"/purple/network/turn_port_tcp"
,
win
->
network
.
turn_port_tcp
);
pidgin_prefs_bind_entry
(
"/purple/network/turn_username"
,
win
->
network
.
turn_username
);
pidgin_prefs_bind_entry
(
"/purple/network/turn_password"
,
win
->
network
.
turn_password
);
}
static
void
bind_proxy_page
(
PidginPrefsWindow
*
win
)
{
PurpleProxyInfo
*
proxy_info
;
if
(
purple_running_gnome
())
{
gchar
*
path
=
NULL
;
gtk_stack_set_visible_child_name
(
GTK_STACK
(
win
->
proxy
.
stack
),
"gnome"
);
path
=
g_find_program_in_path
(
"gnome-network-properties"
);
if
(
path
==
NULL
)
path
=
g_find_program_in_path
(
"gnome-network-preferences"
);
if
(
path
==
NULL
)
{
path
=
g_find_program_in_path
(
"gnome-control-center"
);
if
(
path
!=
NULL
)
{
char
*
tmp
=
g_strdup_printf
(
"%s network"
,
path
);
g_free
(
path
);
path
=
tmp
;
}
}
win
->
proxy
.
gnome_program_path
=
path
;
gtk_widget_set_visible
(
win
->
proxy
.
gnome_not_found
,
path
==
NULL
);
gtk_widget_set_visible
(
win
->
proxy
.
gnome_program
,
path
!=
NULL
);
}
else
{
gtk_stack_set_visible_child_name
(
GTK_STACK
(
win
->
proxy
.
stack
),
"nongnome"
);
/* This is a global option that affects SOCKS4 usage even with
* account-specific proxy settings */
pidgin_prefs_bind_checkbox
(
"/purple/proxy/socks4_remotedns"
,
win
->
proxy
.
socks4_remotedns
);
win
->
proxy
.
type
.
type
=
PURPLE_PREF_STRING
;
win
->
proxy
.
type
.
key
=
"/purple/proxy/type"
;
pidgin_prefs_bind_dropdown
(
&
win
->
proxy
.
type
);
proxy_info
=
purple_global_proxy_get_info
();
purple_prefs_connect_callback
(
prefs
,
"/purple/proxy/type"
,
proxy_changed_cb
,
win
);
if
(
proxy_info
!=
NULL
)
{
if
(
purple_proxy_info_get_host
(
proxy_info
))
{
gtk_entry_set_text
(
GTK_ENTRY
(
win
->
proxy
.
host
),
purple_proxy_info_get_host
(
proxy_info
));
}
if
(
purple_proxy_info_get_port
(
proxy_info
)
!=
0
)
{
gtk_spin_button_set_value
(
GTK_SPIN_BUTTON
(
win
->
proxy
.
port
),
purple_proxy_info_get_port
(
proxy_info
));
}
if
(
purple_proxy_info_get_username
(
proxy_info
)
!=
NULL
)
{
gtk_entry_set_text
(
GTK_ENTRY
(
win
->
proxy
.
username
),
purple_proxy_info_get_username
(
proxy_info
));
}
if
(
purple_proxy_info_get_password
(
proxy_info
)
!=
NULL
)
{
gtk_entry_set_text
(
GTK_ENTRY
(
win
->
proxy
.
password
),
purple_proxy_info_get_password
(
proxy_info
));
}
}
proxy_changed_cb
(
"/purple/proxy/type"
,
PURPLE_PREF_STRING
,
purple_prefs_get_string
(
"/purple/proxy/type"
),
win
);
}
}
static
void
bind_logging_page
(
PidginPrefsWindow
*
win
)
{
GList
*
names
;
win
->
logging
.
format
.
type
=
PURPLE_PREF_STRING
;
win
->
logging
.
format
.
key
=
"/purple/logging/format"
;
names
=
purple_log_logger_get_options
();
pidgin_prefs_bind_dropdown_from_list
(
&
win
->
logging
.
format
,
names
);
g_list_free
(
names
);
pidgin_prefs_bind_checkbox
(
"/purple/logging/log_ims"
,
win
->
logging
.
log_ims
);
pidgin_prefs_bind_checkbox
(
"/purple/logging/log_chats"
,
win
->
logging
.
log_chats
);
pidgin_prefs_bind_checkbox
(
"/purple/logging/log_system"
,
win
->
logging
.
log_system
);
}
static
void
set_idle_away
(
PurpleSavedStatus
*
status
)
{
purple_prefs_set_int
(
"/purple/savedstatus/idleaway"
,
purple_savedstatus_get_creation_time
(
status
));
}
static
void
set_startupstatus
(
PurpleSavedStatus
*
status
)
{
purple_prefs_set_int
(
"/purple/savedstatus/startup"
,
purple_savedstatus_get_creation_time
(
status
));
}
static
void
bind_away_page
(
PidginPrefsWindow
*
win
)
{
GtkWidget
*
menu
;
/* Idle stuff */
win
->
away
.
idle_reporting
.
type
=
PURPLE_PREF_STRING
;
win
->
away
.
idle_reporting
.
key
=
"/purple/away/idle_reporting"
;
pidgin_prefs_bind_dropdown
(
&
win
->
away
.
idle_reporting
);
pidgin_prefs_bind_spin_button
(
"/purple/away/mins_before_away"
,
win
->
away
.
mins_before_away
);
pidgin_prefs_bind_checkbox
(
"/purple/away/away_when_idle"
,
win
->
away
.
away_when_idle
);
/* TODO: Show something useful if we don't have any saved statuses. */
menu
=
pidgin_status_menu
(
purple_savedstatus_get_idleaway
(),
G_CALLBACK
(
set_idle_away
));
gtk_widget_show_all
(
menu
);
gtk_box_pack_start
(
GTK_BOX
(
win
->
away
.
idle_hbox
),
menu
,
FALSE
,
FALSE
,
0
);
g_object_bind_property
(
win
->
away
.
away_when_idle
,
"active"
,
menu
,
"sensitive"
,
G_BINDING_SYNC_CREATE
);
/* Away stuff */
win
->
away
.
auto_reply
.
type
=
PURPLE_PREF_STRING
;
win
->
away
.
auto_reply
.
key
=
"/purple/away/auto_reply"
;
pidgin_prefs_bind_dropdown
(
&
win
->
away
.
auto_reply
);
/* Signon status stuff */
pidgin_prefs_bind_checkbox
(
"/purple/savedstatus/startup_current_status"
,
win
->
away
.
startup_current_status
);
/* TODO: Show something useful if we don't have any saved statuses. */
menu
=
pidgin_status_menu
(
purple_savedstatus_get_startup
(),
G_CALLBACK
(
set_startupstatus
));
gtk_widget_show_all
(
menu
);
gtk_box_pack_start
(
GTK_BOX
(
win
->
away
.
startup_hbox
),
menu
,
FALSE
,
FALSE
,
0
);
gtk_label_set_mnemonic_widget
(
GTK_LABEL
(
win
->
away
.
startup_label
),
menu
);
pidgin_set_accessible_label
(
menu
,
GTK_LABEL
(
win
->
away
.
startup_label
));
g_object_bind_property
(
win
->
away
.
startup_current_status
,
"active"
,
win
->
away
.
startup_hbox
,
"sensitive"
,
G_BINDING_SYNC_CREATE
|
G_BINDING_INVERT_BOOLEAN
);
}
#ifdef USE_VV
static
GList
*
get_vv_device_menuitems
(
PurpleMediaElementType
type
)
{
GList
*
result
=
NULL
;
GList
*
i
;
i
=
purple_media_manager_enumerate_elements
(
purple_media_manager_get
(),
type
);
for
(;
i
;
i
=
g_list_delete_link
(
i
,
i
))
{
PurpleMediaElementInfo
*
info
=
i
->
data
;
result
=
g_list_append
(
result
,
purple_media_element_info_get_name
(
info
));
result
=
g_list_append
(
result
,
purple_media_element_info_get_id
(
info
));
g_object_unref
(
info
);
}
return
result
;
}
static
GstElement
*
create_test_element
(
PurpleMediaElementType
type
)
{
PurpleMediaElementInfo
*
element_info
;
element_info
=
purple_media_manager_get_active_element
(
purple_media_manager_get
(),
type
);
g_return_val_if_fail
(
element_info
,
NULL
);
return
purple_media_element_info_call_create
(
element_info
,
NULL
,
NULL
,
NULL
);
}
static
void
vv_test_switch_page_cb
(
GtkStack
*
stack
,
G_GNUC_UNUSED
GParamSpec
*
pspec
,
gpointer
data
)
{
PidginPrefsWindow
*
win
=
data
;
if
(
!
g_str_equal
(
gtk_stack_get_visible_child_name
(
stack
),
"vv"
))
{
/* Disable any running test pipelines. */
gtk_toggle_button_set_active
(
GTK_TOGGLE_BUTTON
(
win
->
vv
.
voice
.
test
),
FALSE
);
gtk_toggle_button_set_active
(
GTK_TOGGLE_BUTTON
(
win
->
vv
.
video
.
test
),
FALSE
);
}
}
static
GstElement
*
create_voice_pipeline
(
void
)
{
GstElement
*
pipeline
;
GstElement
*
src
,
*
sink
;
GstElement
*
volume
;
GstElement
*
level
;
GstElement
*
valve
;
pipeline
=
gst_pipeline_new
(
"voicetest"
);
src
=
create_test_element
(
PURPLE_MEDIA_ELEMENT_AUDIO
|
PURPLE_MEDIA_ELEMENT_SRC
);
sink
=
create_test_element
(
PURPLE_MEDIA_ELEMENT_AUDIO
|
PURPLE_MEDIA_ELEMENT_SINK
);
volume
=
gst_element_factory_make
(
"volume"
,
"volume"
);
level
=
gst_element_factory_make
(
"level"
,
"level"
);
valve
=
gst_element_factory_make
(
"valve"
,
"valve"
);
gst_bin_add_many
(
GST_BIN
(
pipeline
),
src
,
volume
,
level
,
valve
,
sink
,
NULL
);
gst_element_link_many
(
src
,
volume
,
level
,
valve
,
sink
,
NULL
);
purple_debug_info
(
"gtkprefs"
,
"create_voice_pipeline: setting pipeline "
"state to GST_STATE_PLAYING - it may hang here on win32
\n
"
);
gst_element_set_state
(
GST_ELEMENT
(
pipeline
),
GST_STATE_PLAYING
);
purple_debug_info
(
"gtkprefs"
,
"create_voice_pipeline: state is set
\n
"
);
return
pipeline
;
}
static
void
on_volume_change_cb
(
GtkWidget
*
w
,
gdouble
value
,
gpointer
data
)
{
PidginPrefsWindow
*
win
=
PIDGIN_PREFS_WINDOW
(
data
);
GstElement
*
volume
;
if
(
!
win
->
vv
.
voice
.
pipeline
)
{
return
;
}
volume
=
gst_bin_get_by_name
(
GST_BIN
(
win
->
vv
.
voice
.
pipeline
),
"volume"
);
g_object_set
(
volume
,
"volume"
,
gtk_scale_button_get_value
(
GTK_SCALE_BUTTON
(
w
))
/
100.0
,
NULL
);
}
static
gdouble
gst_msg_db_to_percent
(
GstMessage
*
msg
,
gchar
*
value_name
)
{
const
GValue
*
list
;
const
GValue
*
value
;
gdouble
value_db
;
gdouble
percent
;
list
=
gst_structure_get_value
(
gst_message_get_structure
(
msg
),
value_name
);
G_GNUC_BEGIN_IGNORE_DEPRECATIONS
value
=
g_value_array_get_nth
(
g_value_get_boxed
(
list
),
0
);
G_GNUC_END_IGNORE_DEPRECATIONS
value_db
=
g_value_get_double
(
value
);
percent
=
pow
(
10
,
value_db
/
20
);
return
(
percent
>
1.0
)
?
1.0
:
percent
;
}
static
gboolean
gst_bus_cb
(
GstBus
*
bus
,
GstMessage
*
msg
,
gpointer
data
)
{
PidginPrefsWindow
*
win
=
PIDGIN_PREFS_WINDOW
(
data
);
if
(
GST_MESSAGE_TYPE
(
msg
)
==
GST_MESSAGE_ELEMENT
&&
gst_structure_has_name
(
gst_message_get_structure
(
msg
),
"level"
))
{
GstElement
*
src
=
GST_ELEMENT
(
GST_MESSAGE_SRC
(
msg
));
gchar
*
name
=
gst_element_get_name
(
src
);
if
(
purple_strequal
(
name
,
"level"
))
{
gdouble
percent
;
gdouble
threshold
;
GstElement
*
valve
;
percent
=
gst_msg_db_to_percent
(
msg
,
"rms"
);
gtk_progress_bar_set_fraction
(
GTK_PROGRESS_BAR
(
win
->
vv
.
voice
.
level
),
percent
);
percent
=
gst_msg_db_to_percent
(
msg
,
"decay"
);
threshold
=
gtk_range_get_value
(
GTK_RANGE
(
win
->
vv
.
voice
.
threshold
))
/
100.0
;
valve
=
gst_bin_get_by_name
(
GST_BIN
(
GST_ELEMENT_PARENT
(
src
)),
"valve"
);
g_object_set
(
valve
,
"drop"
,
(
percent
<
threshold
),
NULL
);
g_object_set
(
win
->
vv
.
voice
.
level
,
"text"
,
(
percent
<
threshold
)
?
_
(
"DROP"
)
:
" "
,
NULL
);
}
g_free
(
name
);
}
return
TRUE
;
}
static
void
voice_test_destroy_cb
(
GtkWidget
*
w
,
gpointer
data
)
{
PidginPrefsWindow
*
win
=
PIDGIN_PREFS_WINDOW
(
data
);
if
(
!
win
->
vv
.
voice
.
pipeline
)
{
return
;
}
gst_element_set_state
(
win
->
vv
.
voice
.
pipeline
,
GST_STATE_NULL
);
g_clear_pointer
(
&
win
->
vv
.
voice
.
pipeline
,
gst_object_unref
);
}
static
void
enable_voice_test
(
PidginPrefsWindow
*
win
)
{
GstBus
*
bus
;
win
->
vv
.
voice
.
pipeline
=
create_voice_pipeline
();
bus
=
gst_pipeline_get_bus
(
GST_PIPELINE
(
win
->
vv
.
voice
.
pipeline
));
gst_bus_add_signal_watch
(
bus
);
g_signal_connect
(
bus
,
"message"
,
G_CALLBACK
(
gst_bus_cb
),
win
);
gst_object_unref
(
bus
);
}
static
void
toggle_voice_test_cb
(
GtkToggleButton
*
test
,
gpointer
data
)
{
PidginPrefsWindow
*
win
=
PIDGIN_PREFS_WINDOW
(
data
);
if
(
gtk_toggle_button_get_active
(
test
))
{
gtk_widget_set_sensitive
(
win
->
vv
.
voice
.
level
,
TRUE
);
enable_voice_test
(
win
);
g_signal_connect
(
win
->
vv
.
voice
.
volume
,
"value-changed"
,
G_CALLBACK
(
on_volume_change_cb
),
win
);
g_signal_connect
(
test
,
"destroy"
,
G_CALLBACK
(
voice_test_destroy_cb
),
win
);
}
else
{
gtk_progress_bar_set_fraction
(
GTK_PROGRESS_BAR
(
win
->
vv
.
voice
.
level
),
0.0
);
gtk_widget_set_sensitive
(
win
->
vv
.
voice
.
level
,
FALSE
);
g_object_disconnect
(
win
->
vv
.
voice
.
volume
,
"any-signal::value-changed"
,
G_CALLBACK
(
on_volume_change_cb
),
win
,
NULL
);
g_object_disconnect
(
test
,
"any-signal::destroy"
,
G_CALLBACK
(
voice_test_destroy_cb
),
win
,
NULL
);
voice_test_destroy_cb
(
NULL
,
win
);
}
}
static
void
volume_changed_cb
(
GtkScaleButton
*
button
,
gdouble
value
,
gpointer
data
)
{
purple_prefs_set_int
(
"/purple/media/audio/volume/input"
,
value
*
100
);
}
static
void
threshold_value_changed_cb
(
GtkScale
*
scale
,
GtkWidget
*
label
)
{
int
value
;
char
*
tmp
;
value
=
(
int
)
gtk_range_get_value
(
GTK_RANGE
(
scale
));
tmp
=
g_strdup_printf
(
_
(
"Silence threshold: %d%%"
),
value
);
gtk_label_set_label
(
GTK_LABEL
(
label
),
tmp
);
g_free
(
tmp
);
purple_prefs_set_int
(
"/purple/media/audio/silence_threshold"
,
value
);
}
static
void
bind_voice_test
(
PidginPrefsWindow
*
win
,
GtkBuilder
*
builder
)
{
GObject
*
test
;
GObject
*
label
;
GObject
*
volume
;
GObject
*
threshold
;
char
*
tmp
;
volume
=
gtk_builder_get_object
(
builder
,
"vv.voice.volume"
);
win
->
vv
.
voice
.
volume
=
GTK_WIDGET
(
volume
);
gtk_scale_button_set_value
(
GTK_SCALE_BUTTON
(
volume
),
purple_prefs_get_int
(
"/purple/media/audio/volume/input"
)
/
100.0
);
g_signal_connect
(
volume
,
"value-changed"
,
G_CALLBACK
(
volume_changed_cb
),
NULL
);
label
=
gtk_builder_get_object
(
builder
,
"vv.voice.threshold_label"
);
tmp
=
g_strdup_printf
(
_
(
"Silence threshold: %d%%"
),
purple_prefs_get_int
(
"/purple/media/audio/silence_threshold"
));
gtk_label_set_text
(
GTK_LABEL
(
label
),
tmp
);
g_free
(
tmp
);
threshold
=
gtk_builder_get_object
(
builder
,
"vv.voice.threshold"
);
win
->
vv
.
voice
.
threshold
=
GTK_WIDGET
(
threshold
);
gtk_range_set_value
(
GTK_RANGE
(
threshold
),
purple_prefs_get_int
(
"/purple/media/audio/silence_threshold"
));
g_signal_connect
(
threshold
,
"value-changed"
,
G_CALLBACK
(
threshold_value_changed_cb
),
label
);
win
->
vv
.
voice
.
level
=
GTK_WIDGET
(
gtk_builder_get_object
(
builder
,
"vv.voice.level"
));
test
=
gtk_builder_get_object
(
builder
,
"vv.voice.test"
);
g_signal_connect
(
test
,
"toggled"
,
G_CALLBACK
(
toggle_voice_test_cb
),
win
);
win
->
vv
.
voice
.
test
=
GTK_WIDGET
(
test
);
}
static
GstElement
*
create_video_pipeline
(
void
)
{
GstElement
*
pipeline
;
GstElement
*
src
,
*
sink
;
GstElement
*
videoconvert
;
GstElement
*
videoscale
;
pipeline
=
gst_pipeline_new
(
"videotest"
);
src
=
create_test_element
(
PURPLE_MEDIA_ELEMENT_VIDEO
|
PURPLE_MEDIA_ELEMENT_SRC
);
sink
=
create_test_element
(
PURPLE_MEDIA_ELEMENT_VIDEO
|
PURPLE_MEDIA_ELEMENT_SINK
);
videoconvert
=
gst_element_factory_make
(
"videoconvert"
,
NULL
);
videoscale
=
gst_element_factory_make
(
"videoscale"
,
NULL
);
g_object_set_data
(
G_OBJECT
(
pipeline
),
"sink"
,
sink
);
gst_bin_add_many
(
GST_BIN
(
pipeline
),
src
,
videoconvert
,
videoscale
,
sink
,
NULL
);
gst_element_link_many
(
src
,
videoconvert
,
videoscale
,
sink
,
NULL
);
return
pipeline
;
}
static
void
video_test_destroy_cb
(
GtkWidget
*
w
,
gpointer
data
)
{
PidginPrefsWindow
*
win
=
PIDGIN_PREFS_WINDOW
(
data
);
if
(
!
win
->
vv
.
video
.
pipeline
)
{
return
;
}
gst_element_set_state
(
win
->
vv
.
video
.
pipeline
,
GST_STATE_NULL
);
g_clear_pointer
(
&
win
->
vv
.
video
.
pipeline
,
gst_object_unref
);
}
static
void
enable_video_test
(
PidginPrefsWindow
*
win
)
{
GtkWidget
*
video
=
NULL
;
GstElement
*
sink
=
NULL
;
win
->
vv
.
video
.
pipeline
=
create_video_pipeline
();
sink
=
g_object_get_data
(
G_OBJECT
(
win
->
vv
.
video
.
pipeline
),
"sink"
);
g_object_get
(
sink
,
"widget"
,
&
video
,
NULL
);
gtk_widget_show
(
video
);
g_clear_pointer
(
&
win
->
vv
.
video
.
sink_widget
,
gtk_widget_destroy
);
gtk_container_add
(
GTK_CONTAINER
(
win
->
vv
.
video
.
frame
),
video
);
win
->
vv
.
video
.
sink_widget
=
video
;
gst_element_set_state
(
GST_ELEMENT
(
win
->
vv
.
video
.
pipeline
),
GST_STATE_PLAYING
);
}
static
void
toggle_video_test_cb
(
GtkToggleButton
*
test
,
gpointer
data
)
{
PidginPrefsWindow
*
win
=
PIDGIN_PREFS_WINDOW
(
data
);
if
(
gtk_toggle_button_get_active
(
test
))
{
enable_video_test
(
win
);
g_signal_connect
(
test
,
"destroy"
,
G_CALLBACK
(
video_test_destroy_cb
),
win
);
}
else
{
g_object_disconnect
(
test
,
"any-signal::destroy"
,
G_CALLBACK
(
video_test_destroy_cb
),
win
,
NULL
);
video_test_destroy_cb
(
NULL
,
win
);
}
}
static
void
bind_video_test
(
PidginPrefsWindow
*
win
,
GtkBuilder
*
builder
)
{
GObject
*
test
;
win
->
vv
.
video
.
frame
=
GTK_WIDGET
(
gtk_builder_get_object
(
builder
,
"vv.video.frame"
));
test
=
gtk_builder_get_object
(
builder
,
"vv.video.test"
);
g_signal_connect
(
test
,
"toggled"
,
G_CALLBACK
(
toggle_video_test_cb
),
win
);
win
->
vv
.
video
.
test
=
GTK_WIDGET
(
test
);
}
static
void
vv_device_changed_cb
(
const
gchar
*
name
,
PurplePrefType
type
,
gconstpointer
value
,
gpointer
data
)
{
PidginPrefsWindow
*
win
=
PIDGIN_PREFS_WINDOW
(
data
);
PurpleMediaManager
*
manager
;
PurpleMediaElementInfo
*
info
;
manager
=
purple_media_manager_get
();
info
=
purple_media_manager_get_element_info
(
manager
,
value
);
purple_media_manager_set_active_element
(
manager
,
info
);
/* Refresh test viewers */
if
(
strstr
(
name
,
"audio"
)
&&
win
->
vv
.
voice
.
pipeline
)
{
voice_test_destroy_cb
(
NULL
,
win
);
enable_voice_test
(
win
);
}
else
if
(
strstr
(
name
,
"video"
)
&&
win
->
vv
.
video
.
pipeline
)
{
video_test_destroy_cb
(
NULL
,
win
);
enable_video_test
(
win
);
}
}
static
const
char
*
purple_media_type_to_preference_key
(
PurpleMediaElementType
type
)
{
if
(
type
&
PURPLE_MEDIA_ELEMENT_AUDIO
)
{
if
(
type
&
PURPLE_MEDIA_ELEMENT_SRC
)
{
return
PIDGIN_PREFS_ROOT
"/vvconfig/audio/src/device"
;
}
else
if
(
type
&
PURPLE_MEDIA_ELEMENT_SINK
)
{
return
PIDGIN_PREFS_ROOT
"/vvconfig/audio/sink/device"
;
}
}
else
if
(
type
&
PURPLE_MEDIA_ELEMENT_VIDEO
)
{
if
(
type
&
PURPLE_MEDIA_ELEMENT_SRC
)
{
return
PIDGIN_PREFS_ROOT
"/vvconfig/video/src/device"
;
}
else
if
(
type
&
PURPLE_MEDIA_ELEMENT_SINK
)
{
return
PIDGIN_PREFS_ROOT
"/vvconfig/video/sink/device"
;
}
}
return
NULL
;
}
static
void
bind_vv_dropdown
(
PidginPrefCombo
*
combo
,
PurpleMediaElementType
element_type
)
{
const
gchar
*
preference_key
;
GList
*
devices
;
preference_key
=
purple_media_type_to_preference_key
(
element_type
);
devices
=
get_vv_device_menuitems
(
element_type
);
if
(
g_list_find_custom
(
devices
,
purple_prefs_get_string
(
preference_key
),
(
GCompareFunc
)
strcmp
)
==
NULL
)
{
GList
*
next
=
g_list_next
(
devices
);
if
(
next
)
purple_prefs_set_string
(
preference_key
,
next
->
data
);
}
combo
->
type
=
PURPLE_PREF_STRING
;
combo
->
key
=
preference_key
;
pidgin_prefs_bind_dropdown_from_list
(
combo
,
devices
);
g_list_free_full
(
devices
,
g_free
);
}
static
void
bind_vv_frame
(
PidginPrefsWindow
*
win
,
PidginPrefCombo
*
combo
,
PurpleMediaElementType
type
)
{
bind_vv_dropdown
(
combo
,
type
);
purple_prefs_connect_callback
(
combo
->
combo
,
purple_media_type_to_preference_key
(
type
),
vv_device_changed_cb
,
win
);
g_signal_connect_swapped
(
combo
->
combo
,
"destroy"
,
G_CALLBACK
(
purple_prefs_disconnect_by_handle
),
combo
->
combo
);
g_object_set_data
(
G_OBJECT
(
combo
->
combo
),
"vv_media_type"
,
(
gpointer
)
type
);
g_object_set_data
(
G_OBJECT
(
combo
->
combo
),
"vv_combo"
,
combo
);
}
static
void
device_list_changed_cb
(
PurpleMediaManager
*
manager
,
GtkWidget
*
widget
)
{
PidginPrefCombo
*
combo
;
PurpleMediaElementType
media_type
;
GtkTreeModel
*
model
;
combo
=
g_object_get_data
(
G_OBJECT
(
widget
),
"vv_combo"
);
media_type
=
(
PurpleMediaElementType
)
g_object_get_data
(
G_OBJECT
(
widget
),
"vv_media_type"
);
/* Unbind original connections so we can repopulate the combo box. */
g_object_disconnect
(
combo
->
combo
,
"any-signal::changed"
,
G_CALLBACK
(
bind_dropdown_set
),
combo
,
NULL
);
model
=
gtk_combo_box_get_model
(
GTK_COMBO_BOX
(
combo
->
combo
));
gtk_list_store_clear
(
GTK_LIST_STORE
(
model
));
bind_vv_dropdown
(
combo
,
media_type
);
}
static
GtkWidget
*
vv_page
(
PidginPrefsWindow
*
win
)
{
GtkBuilder
*
builder
;
GtkWidget
*
ret
;
PurpleMediaManager
*
manager
;
builder
=
gtk_builder_new_from_resource
(
"/im/pidgin/Pidgin/Prefs/vv.ui"
);
gtk_builder_set_translation_domain
(
builder
,
PACKAGE
);
ret
=
GTK_WIDGET
(
gtk_builder_get_object
(
builder
,
"vv.page"
));
manager
=
purple_media_manager_get
();
win
->
vv
.
voice
.
input
.
combo
=
GTK_WIDGET
(
gtk_builder_get_object
(
builder
,
"vv.voice.input.combo"
));
bind_vv_frame
(
win
,
&
win
->
vv
.
voice
.
input
,
PURPLE_MEDIA_ELEMENT_AUDIO
|
PURPLE_MEDIA_ELEMENT_SRC
);
g_signal_connect_object
(
manager
,
"elements-changed::audiosrc"
,
G_CALLBACK
(
device_list_changed_cb
),
win
->
vv
.
voice
.
input
.
combo
,
0
);
win
->
vv
.
voice
.
output
.
combo
=
GTK_WIDGET
(
gtk_builder_get_object
(
builder
,
"vv.voice.output.combo"
));
bind_vv_frame
(
win
,
&
win
->
vv
.
voice
.
output
,
PURPLE_MEDIA_ELEMENT_AUDIO
|
PURPLE_MEDIA_ELEMENT_SINK
);
g_signal_connect_object
(
manager
,
"elements-changed::audiosink"
,
G_CALLBACK
(
device_list_changed_cb
),
win
->
vv
.
voice
.
output
.
combo
,
0
);
bind_voice_test
(
win
,
builder
);
win
->
vv
.
video
.
input
.
combo
=
GTK_WIDGET
(
gtk_builder_get_object
(
builder
,
"vv.video.input.combo"
));
bind_vv_frame
(
win
,
&
win
->
vv
.
video
.
input
,
PURPLE_MEDIA_ELEMENT_VIDEO
|
PURPLE_MEDIA_ELEMENT_SRC
);
g_signal_connect_object
(
manager
,
"elements-changed::videosrc"
,
G_CALLBACK
(
device_list_changed_cb
),
win
->
vv
.
video
.
input
.
combo
,
0
);
win
->
vv
.
video
.
output
.
combo
=
GTK_WIDGET
(
gtk_builder_get_object
(
builder
,
"vv.video.output.combo"
));
bind_vv_frame
(
win
,
&
win
->
vv
.
video
.
output
,
PURPLE_MEDIA_ELEMENT_VIDEO
|
PURPLE_MEDIA_ELEMENT_SINK
);
g_signal_connect_object
(
manager
,
"elements-changed::videosink"
,
G_CALLBACK
(
device_list_changed_cb
),
win
->
vv
.
video
.
output
.
combo
,
0
);
bind_video_test
(
win
,
builder
);
g_signal_connect
(
win
->
stack
,
"notify::visible-child"
,
G_CALLBACK
(
vv_test_switch_page_cb
),
win
);
g_object_ref
(
ret
);
g_object_unref
(
builder
);
return
ret
;
}
#endif
static
void
prefs_stack_init
(
PidginPrefsWindow
*
win
)
{
#ifdef USE_VV
GtkStack
*
stack
=
GTK_STACK
(
win
->
stack
);
GtkWidget
*
vv
;
#endif
bind_interface_page
(
win
);
bind_conv_page
(
win
);
bind_logging_page
(
win
);
bind_network_page
(
win
);
bind_proxy_page
(
win
);
bind_away_page
(
win
);
bind_theme_page
(
win
);
#ifdef USE_VV
vv
=
vv_page
(
win
);
gtk_container_add_with_properties
(
GTK_CONTAINER
(
stack
),
vv
,
"name"
,
"vv"
,
"title"
,
_
(
"Voice/Video"
),
NULL
);
g_object_unref
(
vv
);
#endif
}
static
void
pidgin_prefs_window_class_init
(
PidginPrefsWindowClass
*
klass
)
{
GtkWidgetClass
*
widget_class
=
GTK_WIDGET_CLASS
(
klass
);
gtk_widget_class_set_template_from_resource
(
widget_class
,
"/im/pidgin/Pidgin/Prefs/prefs.ui"
);
/* Main window */
gtk_widget_class_bind_template_child
(
widget_class
,
PidginPrefsWindow
,
stack
);
gtk_widget_class_bind_template_callback
(
widget_class
,
delete_prefs
);
/* Interface page */
gtk_widget_class_bind_template_child
(
widget_class
,
PidginPrefsWindow
,
iface
.
im
.
hide_new
.
combo
);
gtk_widget_class_bind_template_child
(
widget_class
,
PidginPrefsWindow
,
iface
.
win32
.
minimize_new_convs
);
gtk_widget_class_bind_template_child
(
widget_class
,
PidginPrefsWindow
,
iface
.
conversations
.
tabs
);
gtk_widget_class_bind_template_child
(
widget_class
,
PidginPrefsWindow
,
iface
.
conversations
.
tabs_vbox
);
gtk_widget_class_bind_template_child
(
widget_class
,
PidginPrefsWindow
,
iface
.
conversations
.
close_on_tabs
);
gtk_widget_class_bind_template_child
(
widget_class
,
PidginPrefsWindow
,
iface
.
conversations
.
tab_side
.
combo
);
/* Conversations page */
gtk_widget_class_bind_template_child
(
widget_class
,
PidginPrefsWindow
,
conversations
.
notification_chat
.
combo
);
gtk_widget_class_bind_template_child
(
widget_class
,
PidginPrefsWindow
,
conversations
.
show_incoming_formatting
);
gtk_widget_class_bind_template_child
(
widget_class
,
PidginPrefsWindow
,
conversations
.
im
.
close_immediately
);
gtk_widget_class_bind_template_child
(
widget_class
,
PidginPrefsWindow
,
conversations
.
im
.
send_typing
);
gtk_widget_class_bind_template_child
(
widget_class
,
PidginPrefsWindow
,
conversations
.
use_smooth_scrolling
);
gtk_widget_class_bind_template_child
(
widget_class
,
PidginPrefsWindow
,
conversations
.
win32
.
blink_im
);
gtk_widget_class_bind_template_child
(
widget_class
,
PidginPrefsWindow
,
conversations
.
resize_custom_smileys
);
gtk_widget_class_bind_template_child
(
widget_class
,
PidginPrefsWindow
,
conversations
.
custom_smileys_size
);
gtk_widget_class_bind_template_child
(
widget_class
,
PidginPrefsWindow
,
conversations
.
minimum_entry_lines
);
gtk_widget_class_bind_template_child
(
widget_class
,
PidginPrefsWindow
,
conversations
.
format_buffer
);
gtk_widget_class_bind_template_child
(
widget_class
,
PidginPrefsWindow
,
conversations
.
format_view
);
#ifdef WIN32
gtk_widget_class_bind_template_child
(
widget_class
,
PidginPrefsWindow
,
conversations
.
font_frame
);
gtk_widget_class_bind_template_child
(
widget_class
,
PidginPrefsWindow
,
conversations
.
use_theme_font
);
gtk_widget_class_bind_template_child
(
widget_class
,
PidginPrefsWindow
,
conversations
.
custom_font_hbox
);
gtk_widget_class_bind_template_child
(
widget_class
,
PidginPrefsWindow
,
conversations
.
custom_font
);
#endif
/* Even though Win32-specific, must be bound to avoid Glade warnings. */
gtk_widget_class_bind_template_callback
(
widget_class
,
apply_custom_font
);
gtk_widget_class_bind_template_callback
(
widget_class
,
pidgin_custom_font_set
);
/* Logging page */
gtk_widget_class_bind_template_child
(
widget_class
,
PidginPrefsWindow
,
logging
.
format
.
combo
);
gtk_widget_class_bind_template_child
(
widget_class
,
PidginPrefsWindow
,
logging
.
log_ims
);
gtk_widget_class_bind_template_child
(
widget_class
,
PidginPrefsWindow
,
logging
.
log_chats
);
gtk_widget_class_bind_template_child
(
widget_class
,
PidginPrefsWindow
,
logging
.
log_system
);
/* Network page */
gtk_widget_class_bind_template_child
(
widget_class
,
PidginPrefsWindow
,
network
.
stun_server
);
gtk_widget_class_bind_template_child
(
widget_class
,
PidginPrefsWindow
,
network
.
auto_ip
);
gtk_widget_class_bind_template_child
(
widget_class
,
PidginPrefsWindow
,
network
.
public_ip
);
gtk_widget_class_bind_template_child
(
widget_class
,
PidginPrefsWindow
,
network
.
public_ip_hbox
);
gtk_widget_class_bind_template_child
(
widget_class
,
PidginPrefsWindow
,
network
.
map_ports
);
gtk_widget_class_bind_template_child
(
widget_class
,
PidginPrefsWindow
,
network
.
ports_range_use
);
gtk_widget_class_bind_template_child
(
widget_class
,
PidginPrefsWindow
,
network
.
ports_range_hbox
);
gtk_widget_class_bind_template_child
(
widget_class
,
PidginPrefsWindow
,
network
.
ports_range_start
);
gtk_widget_class_bind_template_child
(
widget_class
,
PidginPrefsWindow
,
network
.
ports_range_end
);
gtk_widget_class_bind_template_child
(
widget_class
,
PidginPrefsWindow
,
network
.
turn_server
);
gtk_widget_class_bind_template_child
(
widget_class
,
PidginPrefsWindow
,
network
.
turn_port_udp
);
gtk_widget_class_bind_template_child
(
widget_class
,
PidginPrefsWindow
,
network
.
turn_port_tcp
);
gtk_widget_class_bind_template_child
(
widget_class
,
PidginPrefsWindow
,
network
.
turn_username
);
gtk_widget_class_bind_template_child
(
widget_class
,
PidginPrefsWindow
,
network
.
turn_password
);
gtk_widget_class_bind_template_callback
(
widget_class
,
network_stun_server_changed_cb
);
gtk_widget_class_bind_template_callback
(
widget_class
,
auto_ip_button_clicked_cb
);
gtk_widget_class_bind_template_callback
(
widget_class
,
network_ip_changed
);
gtk_widget_class_bind_template_callback
(
widget_class
,
network_turn_server_changed_cb
);
/* Proxy page */
gtk_widget_class_bind_template_child
(
widget_class
,
PidginPrefsWindow
,
proxy
.
stack
);
gtk_widget_class_bind_template_child
(
widget_class
,
PidginPrefsWindow
,
proxy
.
gnome_not_found
);
gtk_widget_class_bind_template_child
(
widget_class
,
PidginPrefsWindow
,
proxy
.
gnome_program
);
gtk_widget_class_bind_template_child
(
widget_class
,
PidginPrefsWindow
,
proxy
.
socks4_remotedns
);
gtk_widget_class_bind_template_child
(
widget_class
,
PidginPrefsWindow
,
proxy
.
type
.
combo
);
gtk_widget_class_bind_template_child
(
widget_class
,
PidginPrefsWindow
,
proxy
.
options
);
gtk_widget_class_bind_template_child
(
widget_class
,
PidginPrefsWindow
,
proxy
.
host
);
gtk_widget_class_bind_template_child
(
widget_class
,
PidginPrefsWindow
,
proxy
.
port
);
gtk_widget_class_bind_template_child
(
widget_class
,
PidginPrefsWindow
,
proxy
.
username
);
gtk_widget_class_bind_template_child
(
widget_class
,
PidginPrefsWindow
,
proxy
.
password
);
gtk_widget_class_bind_template_callback
(
widget_class
,
proxy_button_clicked_cb
);
gtk_widget_class_bind_template_callback
(
widget_class
,
proxy_print_option
);
/* Away page */
gtk_widget_class_bind_template_child
(
widget_class
,
PidginPrefsWindow
,
away
.
idle_reporting
.
combo
);
gtk_widget_class_bind_template_child
(
widget_class
,
PidginPrefsWindow
,
away
.
mins_before_away
);
gtk_widget_class_bind_template_child
(
widget_class
,
PidginPrefsWindow
,
away
.
away_when_idle
);
gtk_widget_class_bind_template_child
(
widget_class
,
PidginPrefsWindow
,
away
.
idle_hbox
);
gtk_widget_class_bind_template_child
(
widget_class
,
PidginPrefsWindow
,
away
.
auto_reply
.
combo
);
gtk_widget_class_bind_template_child
(
widget_class
,
PidginPrefsWindow
,
away
.
startup_current_status
);
gtk_widget_class_bind_template_child
(
widget_class
,
PidginPrefsWindow
,
away
.
startup_hbox
);
gtk_widget_class_bind_template_child
(
widget_class
,
PidginPrefsWindow
,
away
.
startup_label
);
/* Themes page */
gtk_widget_class_bind_template_child
(
widget_class
,
PidginPrefsWindow
,
theme
.
status
);
gtk_widget_class_bind_template_child
(
widget_class
,
PidginPrefsWindow
,
theme
.
smiley
);
gtk_widget_class_bind_template_callback
(
widget_class
,
prefs_set_status_icon_theme_cb
);
gtk_widget_class_bind_template_callback
(
widget_class
,
prefs_set_smiley_theme_cb
);
}
static
void
pidgin_prefs_window_init
(
PidginPrefsWindow
*
win
)
{
/* copy the preferences to tmp values...
* I liked "take affect immediately" Oh well :-( */
/* (that should have been "effect," right?) */
/* Back to instant-apply! I win! BU-HAHAHA! */
/* Create the window */
gtk_widget_init_template
(
GTK_WIDGET
(
win
));
prefs_stack_init
(
win
);
/* Refresh the list of themes before showing the preferences window */
prefs_themes_refresh
();
}
void
pidgin_prefs_show
(
void
)
{
if
(
prefs
==
NULL
)
{
prefs
=
PIDGIN_PREFS_WINDOW
(
g_object_new
(
pidgin_prefs_window_get_type
(),
NULL
));
}
gtk_window_present
(
GTK_WINDOW
(
prefs
));
}
static
void
smiley_theme_pref_cb
(
const
char
*
name
,
PurplePrefType
type
,
gconstpointer
value
,
gpointer
data
)
{
const
gchar
*
theme_name
=
value
;
GList
*
themes
,
*
it
;
if
(
purple_strequal
(
theme_name
,
"none"
))
{
purple_smiley_theme_set_current
(
NULL
);
return
;
}
/* XXX: could be cached when initializing prefs view */
themes
=
pidgin_smiley_theme_get_all
();
for
(
it
=
themes
;
it
;
it
=
g_list_next
(
it
))
{
PidginSmileyTheme
*
theme
=
it
->
data
;
if
(
!
purple_strequal
(
pidgin_smiley_theme_get_name
(
theme
),
theme_name
))
continue
;
purple_smiley_theme_set_current
(
PURPLE_SMILEY_THEME
(
theme
));
}
}
void
pidgin_prefs_init
(
void
)
{
purple_prefs_add_none
(
PIDGIN_PREFS_ROOT
""
);
purple_prefs_add_none
(
"/plugins/gtk"
);
/* Plugins */
purple_prefs_add_none
(
PIDGIN_PREFS_ROOT
"/plugins"
);
purple_prefs_add_path_list
(
PIDGIN_PREFS_ROOT
"/plugins/loaded"
,
NULL
);
/* File locations */
purple_prefs_add_none
(
PIDGIN_PREFS_ROOT
"/filelocations"
);
purple_prefs_add_path
(
PIDGIN_PREFS_ROOT
"/filelocations/last_save_folder"
,
""
);
purple_prefs_add_path
(
PIDGIN_PREFS_ROOT
"/filelocations/last_open_folder"
,
""
);
purple_prefs_add_path
(
PIDGIN_PREFS_ROOT
"/filelocations/last_icon_folder"
,
""
);
/* Themes */
prefs_themes_init
();
/* Smiley Themes */
purple_prefs_add_none
(
PIDGIN_PREFS_ROOT
"/smileys"
);
purple_prefs_add_string
(
PIDGIN_PREFS_ROOT
"/smileys/theme"
,
"Default"
);
/* Smiley Callbacks */
purple_prefs_connect_callback
(
&
prefs
,
PIDGIN_PREFS_ROOT
"/smileys/theme"
,
smiley_theme_pref_cb
,
NULL
);
#ifdef USE_VV
/* Voice/Video */
purple_prefs_add_none
(
PIDGIN_PREFS_ROOT
"/vvconfig"
);
purple_prefs_add_none
(
PIDGIN_PREFS_ROOT
"/vvconfig/audio"
);
purple_prefs_add_none
(
PIDGIN_PREFS_ROOT
"/vvconfig/audio/src"
);
purple_prefs_add_string
(
PIDGIN_PREFS_ROOT
"/vvconfig/audio/src/device"
,
""
);
purple_prefs_add_none
(
PIDGIN_PREFS_ROOT
"/vvconfig/audio/sink"
);
purple_prefs_add_string
(
PIDGIN_PREFS_ROOT
"/vvconfig/audio/sink/device"
,
""
);
purple_prefs_add_none
(
PIDGIN_PREFS_ROOT
"/vvconfig/video"
);
purple_prefs_add_none
(
PIDGIN_PREFS_ROOT
"/vvconfig/video/src"
);
purple_prefs_add_string
(
PIDGIN_PREFS_ROOT
"/vvconfig/video/src/device"
,
""
);
purple_prefs_add_none
(
PIDGIN_PREFS_ROOT
"/vvconfig/video"
);
purple_prefs_add_none
(
PIDGIN_PREFS_ROOT
"/vvconfig/video/sink"
);
purple_prefs_add_string
(
PIDGIN_PREFS_ROOT
"/vvconfig/video/sink/device"
,
""
);
#endif
pidgin_prefs_update_old
();
}
void
pidgin_prefs_update_old
(
void
)
{
const
gchar
*
video_sink
=
NULL
;
/* Rename some old prefs */
purple_prefs_rename
(
PIDGIN_PREFS_ROOT
"/logging/log_ims"
,
"/purple/logging/log_ims"
);
purple_prefs_rename
(
PIDGIN_PREFS_ROOT
"/logging/log_chats"
,
"/purple/logging/log_chats"
);
purple_prefs_rename
(
PIDGIN_PREFS_ROOT
"/conversations/im/raise_on_events"
,
"/plugins/gtk/X11/notify/method_raise"
);
purple_prefs_rename_boolean_toggle
(
PIDGIN_PREFS_ROOT
"/conversations/ignore_colors"
,
PIDGIN_PREFS_ROOT
"/conversations/show_incoming_formatting"
);
/* Remove some no-longer-used prefs */
purple_prefs_remove
(
PIDGIN_PREFS_ROOT
"/blist/auto_expand_contacts"
);
purple_prefs_remove
(
PIDGIN_PREFS_ROOT
"/blist/button_style"
);
purple_prefs_remove
(
PIDGIN_PREFS_ROOT
"/blist/grey_idle_buddies"
);
purple_prefs_remove
(
PIDGIN_PREFS_ROOT
"/blist/raise_on_events"
);
purple_prefs_remove
(
PIDGIN_PREFS_ROOT
"/blist/show_group_count"
);
purple_prefs_remove
(
PIDGIN_PREFS_ROOT
"/blist/show_warning_level"
);
purple_prefs_remove
(
PIDGIN_PREFS_ROOT
"/blist/tooltip_delay"
);
purple_prefs_remove
(
PIDGIN_PREFS_ROOT
"/blist/x"
);
purple_prefs_remove
(
PIDGIN_PREFS_ROOT
"/blist/y"
);
purple_prefs_remove
(
PIDGIN_PREFS_ROOT
"/browsers"
);
purple_prefs_remove
(
PIDGIN_PREFS_ROOT
"/browsers/browser"
);
purple_prefs_remove
(
PIDGIN_PREFS_ROOT
"/browsers/command"
);
purple_prefs_remove
(
PIDGIN_PREFS_ROOT
"/browsers/place"
);
purple_prefs_remove
(
PIDGIN_PREFS_ROOT
"/browsers/manual_command"
);
purple_prefs_remove
(
PIDGIN_PREFS_ROOT
"/conversations/button_type"
);
purple_prefs_remove
(
PIDGIN_PREFS_ROOT
"/conversations/ctrl_enter_sends"
);
purple_prefs_remove
(
PIDGIN_PREFS_ROOT
"/conversations/enter_sends"
);
purple_prefs_remove
(
PIDGIN_PREFS_ROOT
"/conversations/escape_closes"
);
purple_prefs_remove
(
PIDGIN_PREFS_ROOT
"/conversations/html_shortcuts"
);
purple_prefs_remove
(
PIDGIN_PREFS_ROOT
"/conversations/icons_on_tabs"
);
purple_prefs_remove
(
PIDGIN_PREFS_ROOT
"/conversations/send_formatting"
);
purple_prefs_remove
(
PIDGIN_PREFS_ROOT
"/conversations/show_smileys"
);
purple_prefs_remove
(
PIDGIN_PREFS_ROOT
"/conversations/show_urls_as_links"
);
purple_prefs_remove
(
PIDGIN_PREFS_ROOT
"/conversations/smiley_shortcuts"
);
purple_prefs_remove
(
PIDGIN_PREFS_ROOT
"/conversations/use_custom_bgcolor"
);
purple_prefs_remove
(
PIDGIN_PREFS_ROOT
"/conversations/use_custom_fgcolor"
);
purple_prefs_remove
(
PIDGIN_PREFS_ROOT
"/conversations/use_custom_font"
);
purple_prefs_remove
(
PIDGIN_PREFS_ROOT
"/conversations/use_custom_size"
);
purple_prefs_remove
(
PIDGIN_PREFS_ROOT
"/conversations/chat/old_tab_complete"
);
purple_prefs_remove
(
PIDGIN_PREFS_ROOT
"/conversations/chat/tab_completion"
);
purple_prefs_remove
(
PIDGIN_PREFS_ROOT
"/conversations/im/hide_on_send"
);
purple_prefs_remove
(
PIDGIN_PREFS_ROOT
"/conversations/chat/color_nicks"
);
purple_prefs_remove
(
PIDGIN_PREFS_ROOT
"/conversations/chat/raise_on_events"
);
purple_prefs_remove
(
PIDGIN_PREFS_ROOT
"/conversations/ignore_fonts"
);
purple_prefs_remove
(
PIDGIN_PREFS_ROOT
"/conversations/ignore_font_sizes"
);
purple_prefs_remove
(
PIDGIN_PREFS_ROOT
"/conversations/passthrough_unknown_commands"
);
purple_prefs_remove
(
PIDGIN_PREFS_ROOT
"/debug/timestamps"
);
purple_prefs_remove
(
PIDGIN_PREFS_ROOT
"/idle"
);
purple_prefs_remove
(
PIDGIN_PREFS_ROOT
"/logging/individual_logs"
);
purple_prefs_remove
(
PIDGIN_PREFS_ROOT
"/sound/signon"
);
purple_prefs_remove
(
PIDGIN_PREFS_ROOT
"/sound/silent_signon"
);
purple_prefs_remove
(
PIDGIN_PREFS_ROOT
"/sound/command"
);
purple_prefs_remove
(
PIDGIN_PREFS_ROOT
"/sound/conv_focus"
);
purple_prefs_remove
(
PIDGIN_PREFS_ROOT
"/sound/enabled/chat_msg_recv"
);
purple_prefs_remove
(
PIDGIN_PREFS_ROOT
"/sound/enabled/first_im_recv"
);
purple_prefs_remove
(
PIDGIN_PREFS_ROOT
"/sound/enabled/got_attention"
);
purple_prefs_remove
(
PIDGIN_PREFS_ROOT
"/sound/enabled/im_recv"
);
purple_prefs_remove
(
PIDGIN_PREFS_ROOT
"/sound/enabled/join_chat"
);
purple_prefs_remove
(
PIDGIN_PREFS_ROOT
"/sound/enabled/left_chat"
);
purple_prefs_remove
(
PIDGIN_PREFS_ROOT
"/sound/enabled/login"
);
purple_prefs_remove
(
PIDGIN_PREFS_ROOT
"/sound/enabled/logout"
);
purple_prefs_remove
(
PIDGIN_PREFS_ROOT
"/sound/enabled/nick_said"
);
purple_prefs_remove
(
PIDGIN_PREFS_ROOT
"/sound/enabled/pounce_default"
);
purple_prefs_remove
(
PIDGIN_PREFS_ROOT
"/sound/enabled/send_chat_msg"
);
purple_prefs_remove
(
PIDGIN_PREFS_ROOT
"/sound/enabled/send_im"
);
purple_prefs_remove
(
PIDGIN_PREFS_ROOT
"/sound/enabled/sent_attention"
);
purple_prefs_remove
(
PIDGIN_PREFS_ROOT
"/sound/enabled"
);
purple_prefs_remove
(
PIDGIN_PREFS_ROOT
"/sound/file/chat_msg_recv"
);
purple_prefs_remove
(
PIDGIN_PREFS_ROOT
"/sound/file/first_im_recv"
);
purple_prefs_remove
(
PIDGIN_PREFS_ROOT
"/sound/file/got_attention"
);
purple_prefs_remove
(
PIDGIN_PREFS_ROOT
"/sound/file/im_recv"
);
purple_prefs_remove
(
PIDGIN_PREFS_ROOT
"/sound/file/join_chat"
);
purple_prefs_remove
(
PIDGIN_PREFS_ROOT
"/sound/file/left_chat"
);
purple_prefs_remove
(
PIDGIN_PREFS_ROOT
"/sound/file/login"
);
purple_prefs_remove
(
PIDGIN_PREFS_ROOT
"/sound/file/logout"
);
purple_prefs_remove
(
PIDGIN_PREFS_ROOT
"/sound/file/nick_said"
);
purple_prefs_remove
(
PIDGIN_PREFS_ROOT
"/sound/file/pounce_default"
);
purple_prefs_remove
(
PIDGIN_PREFS_ROOT
"/sound/file/send_chat_msg"
);
purple_prefs_remove
(
PIDGIN_PREFS_ROOT
"/sound/file/send_im"
);
purple_prefs_remove
(
PIDGIN_PREFS_ROOT
"/sound/file/sent_attention"
);
purple_prefs_remove
(
PIDGIN_PREFS_ROOT
"/sound/file"
);
purple_prefs_remove
(
PIDGIN_PREFS_ROOT
"/sound/method"
);
purple_prefs_remove
(
PIDGIN_PREFS_ROOT
"/sound/mute"
);
purple_prefs_remove
(
PIDGIN_PREFS_ROOT
"/sound/theme"
);
purple_prefs_remove
(
PIDGIN_PREFS_ROOT
"/sound"
);
/* Convert old queuing prefs to hide_new 3-way pref. */
if
(
purple_prefs_exists
(
"/plugins/gtk/docklet/queue_messages"
)
&&
purple_prefs_get_bool
(
"/plugins/gtk/docklet/queue_messages"
))
{
purple_prefs_set_string
(
PIDGIN_PREFS_ROOT
"/conversations/im/hide_new"
,
"always"
);
}
else
if
(
purple_prefs_exists
(
PIDGIN_PREFS_ROOT
"/away/queue_messages"
)
&&
purple_prefs_get_bool
(
PIDGIN_PREFS_ROOT
"/away/queue_messages"
))
{
purple_prefs_set_string
(
PIDGIN_PREFS_ROOT
"/conversations/im/hide_new"
,
"away"
);
}
purple_prefs_remove
(
PIDGIN_PREFS_ROOT
"/away/queue_messages"
);
purple_prefs_remove
(
PIDGIN_PREFS_ROOT
"/away"
);
purple_prefs_remove
(
"/plugins/gtk/docklet/queue_messages"
);
purple_prefs_remove
(
PIDGIN_PREFS_ROOT
"/conversations/chat/default_width"
);
purple_prefs_remove
(
PIDGIN_PREFS_ROOT
"/conversations/chat/default_height"
);
purple_prefs_remove
(
PIDGIN_PREFS_ROOT
"/conversations/im/default_width"
);
purple_prefs_remove
(
PIDGIN_PREFS_ROOT
"/conversations/im/default_height"
);
purple_prefs_rename
(
PIDGIN_PREFS_ROOT
"/conversations/x"
,
PIDGIN_PREFS_ROOT
"/conversations/im/x"
);
purple_prefs_rename
(
PIDGIN_PREFS_ROOT
"/conversations/y"
,
PIDGIN_PREFS_ROOT
"/conversations/im/y"
);
/* Fixup vvconfig plugin prefs */
if
(
purple_prefs_exists
(
"/plugins/core/vvconfig/audio/src/device"
))
{
purple_prefs_set_string
(
PIDGIN_PREFS_ROOT
"/vvconfig/audio/src/device"
,
purple_prefs_get_string
(
"/plugins/core/vvconfig/audio/src/device"
));
}
if
(
purple_prefs_exists
(
"/plugins/core/vvconfig/audio/sink/device"
))
{
purple_prefs_set_string
(
PIDGIN_PREFS_ROOT
"/vvconfig/audio/sink/device"
,
purple_prefs_get_string
(
"/plugins/core/vvconfig/audio/sink/device"
));
}
if
(
purple_prefs_exists
(
"/plugins/core/vvconfig/video/src/device"
))
{
purple_prefs_set_string
(
PIDGIN_PREFS_ROOT
"/vvconfig/video/src/device"
,
purple_prefs_get_string
(
"/plugins/core/vvconfig/video/src/device"
));
}
if
(
purple_prefs_exists
(
"/plugins/gtk/vvconfig/video/sink/device"
))
{
purple_prefs_set_string
(
PIDGIN_PREFS_ROOT
"/vvconfig/video/sink/device"
,
purple_prefs_get_string
(
"/plugins/gtk/vvconfig/video/sink/device"
));
}
video_sink
=
purple_prefs_get_string
(
PIDGIN_PREFS_ROOT
"/vvconfig/video/sink/device"
);
if
(
purple_strequal
(
video_sink
,
"glimagesink"
)
||
purple_strequal
(
video_sink
,
"directdrawsink"
))
{
/* Accelerated sinks move to GTK GL. */
/* video_sink = "gtkglsink"; */
/* FIXME: I haven't been able to get gtkglsink to work yet: */
video_sink
=
"gtksink"
;
}
else
{
/* Everything else, including default will be moved to GTK sink. */
video_sink
=
"gtksink"
;
}
purple_prefs_set_string
(
PIDGIN_PREFS_ROOT
"/vvconfig/video/sink/device"
,
video_sink
);
purple_prefs_remove
(
"/plugins/core/vvconfig"
);
purple_prefs_remove
(
"/plugins/gtk/vvconfig"
);
purple_prefs_remove
(
PIDGIN_PREFS_ROOT
"/vvconfig/audio/src/plugin"
);
purple_prefs_remove
(
PIDGIN_PREFS_ROOT
"/vvconfig/audio/sink/plugin"
);
purple_prefs_remove
(
PIDGIN_PREFS_ROOT
"/vvconfig/video/src/plugin"
);
purple_prefs_remove
(
PIDGIN_PREFS_ROOT
"/vvconfig/video/sink/plugin"
);
}