qulogic/pidgin
Clone
Summary
Browse
Changes
Graph
Add link local macros in windows terms.
draft
win-mdns
2021-01-05, Elliott Sales de Andrade
9b049f9577a1
Add link local macros in windows terms.
/* pidgin
*
* Pidgin is the legal property of its developers, whose names are too numerous
* to list here. Please refer to the COPYRIGHT file distributed with this
* source distribution.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111-1301 USA
*/
#include
<purpleconfig.h>
#include
<glib/gi18n-lib.h>
#include
<gtk/gtk.h>
#include
<purple.h>
#include
"gtkmedia.h"
#include
"gtkutils.h"
#include
"pidgincore.h"
#include
"pidginkeypad.h"
#define PIDGIN_TYPE_MEDIA (pidgin_media_get_type())
#define PIDGIN_MEDIA(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), PIDGIN_TYPE_MEDIA, PidginMedia))
#define PIDGIN_MEDIA_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), PIDGIN_TYPE_MEDIA, PidginMediaClass))
#define PIDGIN_IS_MEDIA(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), PIDGIN_TYPE_MEDIA))
#define PIDGIN_IS_MEDIA_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), PIDGIN_TYPE_MEDIA))
#define PIDGIN_MEDIA_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), PIDGIN_TYPE_MEDIA, PidginMediaClass))
typedef
struct
_PidginMedia
PidginMedia
;
typedef
struct
_PidginMediaClass
PidginMediaClass
;
typedef
struct
_PidginMediaPrivate
PidginMediaPrivate
;
typedef
enum
{
/* Waiting for response */
PIDGIN_MEDIA_WAITING
=
1
,
/* Got request */
PIDGIN_MEDIA_REQUESTED
,
/* Accepted call */
PIDGIN_MEDIA_ACCEPTED
,
/* Rejected call */
PIDGIN_MEDIA_REJECTED
,
}
PidginMediaState
;
struct
_PidginMediaClass
{
GtkApplicationWindowClass
parent_class
;
};
struct
_PidginMedia
{
GtkApplicationWindow
parent
;
PidginMediaPrivate
*
priv
;
};
struct
_PidginMediaPrivate
{
PurpleMedia
*
media
;
gchar
*
screenname
;
gulong
level_handler_id
;
GtkWidget
*
menubar
;
GtkLabel
*
status
;
GtkWidget
*
hold
;
GtkWidget
*
mute
;
GtkWidget
*
pause
;
GtkWidget
*
send_progress
;
GHashTable
*
recv_progressbars
;
PidginMediaState
state
;
GtkWidget
*
display
;
GtkWidget
*
send_widget
;
GtkWidget
*
recv_widget
;
GtkWidget
*
button_widget
;
GtkWidget
*
local_video
;
GHashTable
*
remote_videos
;
guint
timeout_id
;
PurpleMediaSessionType
request_type
;
};
static
GType
pidgin_media_get_type
(
void
);
G_DEFINE_TYPE_WITH_PRIVATE
(
PidginMedia
,
pidgin_media
,
GTK_TYPE_APPLICATION_WINDOW
);
static
void
pidgin_media_dispose
(
GObject
*
object
);
static
void
pidgin_media_finalize
(
GObject
*
object
);
static
void
pidgin_media_get_property
(
GObject
*
object
,
guint
prop_id
,
GValue
*
value
,
GParamSpec
*
pspec
);
static
void
pidgin_media_set_property
(
GObject
*
object
,
guint
prop_id
,
const
GValue
*
value
,
GParamSpec
*
pspec
);
static
void
pidgin_media_set_state
(
PidginMedia
*
gtkmedia
,
PidginMediaState
state
);
enum
{
PROP_0
,
PROP_MEDIA
,
PROP_SCREENNAME
};
static
gboolean
pidgin_media_close_request_cb
(
G_GNUC_UNUSED
GtkWindow
*
window
,
gpointer
data
)
{
PidginMedia
*
media
=
data
;
if
(
media
->
priv
->
media
)
{
g_action_group_activate_action
(
G_ACTION_GROUP
(
media
),
"Hangup"
,
NULL
);
}
return
FALSE
;
}
static
void
pidgin_media_class_init
(
PidginMediaClass
*
klass
)
{
GObjectClass
*
gobject_class
=
G_OBJECT_CLASS
(
klass
);
GtkWidgetClass
*
widget_class
=
GTK_WIDGET_CLASS
(
klass
);
gobject_class
->
dispose
=
pidgin_media_dispose
;
gobject_class
->
finalize
=
pidgin_media_finalize
;
gobject_class
->
set_property
=
pidgin_media_set_property
;
gobject_class
->
get_property
=
pidgin_media_get_property
;
g_object_class_install_property
(
gobject_class
,
PROP_MEDIA
,
g_param_spec_object
(
"media"
,
"PurpleMedia"
,
"The PurpleMedia associated with this media."
,
PURPLE_TYPE_MEDIA
,
G_PARAM_CONSTRUCT_ONLY
|
G_PARAM_READWRITE
|
G_PARAM_STATIC_STRINGS
));
g_object_class_install_property
(
gobject_class
,
PROP_SCREENNAME
,
g_param_spec_string
(
"screenname"
,
"Screenname"
,
"The screenname of the user this session is with."
,
NULL
,
G_PARAM_CONSTRUCT_ONLY
|
G_PARAM_READWRITE
|
G_PARAM_STATIC_STRINGS
));
gtk_widget_class_set_template_from_resource
(
widget_class
,
"/im/pidgin/Pidgin3/Media/window.ui"
);
gtk_widget_class_bind_template_child_private
(
widget_class
,
PidginMedia
,
display
);
gtk_widget_class_bind_template_child_private
(
widget_class
,
PidginMedia
,
status
);
gtk_widget_class_bind_template_callback
(
widget_class
,
pidgin_media_close_request_cb
);
}
static
void
pidgin_media_hangup_activate_cb
(
G_GNUC_UNUSED
GSimpleAction
*
action
,
G_GNUC_UNUSED
GVariant
*
parameter
,
gpointer
user_data
)
{
PidginMedia
*
media
=
PIDGIN_MEDIA
(
user_data
);
purple_media_stream_info
(
media
->
priv
->
media
,
PURPLE_MEDIA_INFO_HANGUP
,
NULL
,
NULL
,
TRUE
);
}
static
void
pidgin_media_hold_change_state_cb
(
GSimpleAction
*
action
,
GVariant
*
value
,
gpointer
user_data
)
{
PidginMedia
*
media
=
PIDGIN_MEDIA
(
user_data
);
purple_media_stream_info
(
media
->
priv
->
media
,
g_variant_get_boolean
(
value
)
?
PURPLE_MEDIA_INFO_HOLD
:
PURPLE_MEDIA_INFO_UNHOLD
,
NULL
,
NULL
,
TRUE
);
g_simple_action_set_state
(
action
,
value
);
}
static
void
pidgin_media_mute_change_state_cb
(
GSimpleAction
*
action
,
GVariant
*
value
,
gpointer
user_data
)
{
PidginMedia
*
media
=
PIDGIN_MEDIA
(
user_data
);
purple_media_stream_info
(
media
->
priv
->
media
,
g_variant_get_boolean
(
value
)
?
PURPLE_MEDIA_INFO_MUTE
:
PURPLE_MEDIA_INFO_UNMUTE
,
NULL
,
NULL
,
TRUE
);
g_simple_action_set_state
(
action
,
value
);
}
static
void
pidgin_media_pause_change_state_cb
(
GSimpleAction
*
action
,
GVariant
*
value
,
gpointer
user_data
)
{
PidginMedia
*
media
=
PIDGIN_MEDIA
(
user_data
);
purple_media_stream_info
(
media
->
priv
->
media
,
g_variant_get_boolean
(
value
)
?
PURPLE_MEDIA_INFO_PAUSE
:
PURPLE_MEDIA_INFO_UNPAUSE
,
NULL
,
NULL
,
TRUE
);
g_simple_action_set_state
(
action
,
value
);
}
static
const
GActionEntry
media_action_entries
[]
=
{
{
.
name
=
"Hangup"
,
.
activate
=
pidgin_media_hangup_activate_cb
,
},
{
.
name
=
"Hold"
,
.
state
=
"false"
,
.
change_state
=
pidgin_media_hold_change_state_cb
,
},
{
.
name
=
"Mute"
,
.
state
=
"false"
,
.
change_state
=
pidgin_media_mute_change_state_cb
,
},
{
.
name
=
"Pause"
,
.
state
=
"false"
,
.
change_state
=
pidgin_media_pause_change_state_cb
,
},
};
static
void
pidgin_media_init
(
PidginMedia
*
media
)
{
media
->
priv
=
pidgin_media_get_instance_private
(
media
);
gtk_widget_init_template
(
GTK_WIDGET
(
media
));
g_action_map_add_action_entries
(
G_ACTION_MAP
(
media
),
media_action_entries
,
G_N_ELEMENTS
(
media_action_entries
),
media
);
gtk_label_set_text
(
media
->
priv
->
status
,
_
(
"Calling..."
));
media
->
priv
->
recv_progressbars
=
g_hash_table_new_full
(
g_str_hash
,
g_str_equal
,
g_free
,
NULL
);
media
->
priv
->
remote_videos
=
g_hash_table_new_full
(
g_str_hash
,
g_str_equal
,
g_free
,
NULL
);
}
static
gchar
*
create_key
(
const
gchar
*
session_id
,
const
gchar
*
participant
)
{
return
g_strdup_printf
(
"%s_%s"
,
session_id
,
participant
);
}
static
void
pidgin_media_insert_widget
(
PidginMedia
*
gtkmedia
,
GtkWidget
*
widget
,
const
gchar
*
session_id
,
const
gchar
*
participant
)
{
gchar
*
key
=
create_key
(
session_id
,
participant
);
PurpleMediaSessionType
type
=
purple_media_get_session_type
(
gtkmedia
->
priv
->
media
,
session_id
);
if
(
type
&
PURPLE_MEDIA_AUDIO
)
{
g_hash_table_insert
(
gtkmedia
->
priv
->
recv_progressbars
,
key
,
widget
);
}
else
if
(
type
&
PURPLE_MEDIA_VIDEO
)
{
g_hash_table_insert
(
gtkmedia
->
priv
->
remote_videos
,
key
,
widget
);
}
}
static
GtkWidget
*
pidgin_media_get_widget
(
PidginMedia
*
gtkmedia
,
const
gchar
*
session_id
,
const
gchar
*
participant
)
{
GtkWidget
*
widget
=
NULL
;
gchar
*
key
=
create_key
(
session_id
,
participant
);
PurpleMediaSessionType
type
=
purple_media_get_session_type
(
gtkmedia
->
priv
->
media
,
session_id
);
if
(
type
&
PURPLE_MEDIA_AUDIO
)
{
widget
=
g_hash_table_lookup
(
gtkmedia
->
priv
->
recv_progressbars
,
key
);
}
else
if
(
type
&
PURPLE_MEDIA_VIDEO
)
{
widget
=
g_hash_table_lookup
(
gtkmedia
->
priv
->
remote_videos
,
key
);
}
g_free
(
key
);
return
widget
;
}
static
void
pidgin_media_remove_widget
(
PidginMedia
*
gtkmedia
,
const
gchar
*
session_id
,
const
gchar
*
participant
)
{
GtkWidget
*
widget
=
NULL
;
PurpleMediaSessionType
type
=
PURPLE_MEDIA_NONE
;
gchar
*
key
=
NULL
;
widget
=
pidgin_media_get_widget
(
gtkmedia
,
session_id
,
participant
);
if
(
widget
==
NULL
)
{
return
;
}
type
=
purple_media_get_session_type
(
gtkmedia
->
priv
->
media
,
session_id
);
key
=
create_key
(
session_id
,
participant
);
if
(
type
&
PURPLE_MEDIA_AUDIO
)
{
g_hash_table_remove
(
gtkmedia
->
priv
->
recv_progressbars
,
key
);
if
(
g_hash_table_size
(
gtkmedia
->
priv
->
recv_progressbars
)
==
0
&&
gtkmedia
->
priv
->
send_progress
)
{
g_clear_pointer
(
&
gtkmedia
->
priv
->
send_progress
,
gtk_widget_unparent
);
g_clear_pointer
(
&
gtkmedia
->
priv
->
mute
,
gtk_widget_unparent
);
}
}
else
if
(
type
&
PURPLE_MEDIA_VIDEO
)
{
g_hash_table_remove
(
gtkmedia
->
priv
->
remote_videos
,
key
);
if
(
g_hash_table_size
(
gtkmedia
->
priv
->
remote_videos
)
==
0
&&
gtkmedia
->
priv
->
local_video
)
{
g_clear_pointer
(
&
gtkmedia
->
priv
->
local_video
,
gtk_widget_unparent
);
g_clear_pointer
(
&
gtkmedia
->
priv
->
pause
,
gtk_widget_unparent
);
}
}
g_free
(
key
);
gtk_widget_unparent
(
widget
);
}
static
void
level_message_cb
(
G_GNUC_UNUSED
PurpleMedia
*
media
,
char
*
session_id
,
char
*
participant
,
double
level
,
PidginMedia
*
gtkmedia
)
{
GtkWidget
*
progress
=
NULL
;
if
(
participant
==
NULL
)
{
progress
=
gtkmedia
->
priv
->
send_progress
;
}
else
{
progress
=
pidgin_media_get_widget
(
gtkmedia
,
session_id
,
participant
);
}
if
(
progress
)
{
gtk_progress_bar_set_fraction
(
GTK_PROGRESS_BAR
(
progress
),
level
);
}
}
static
void
pidgin_media_disconnect_levels
(
PurpleMedia
*
media
,
PidginMedia
*
gtkmedia
)
{
PurpleMediaManager
*
manager
=
NULL
;
GstElement
*
element
=
NULL
;
GstBus
*
bus
=
NULL
;
manager
=
purple_media_get_manager
(
media
);
element
=
purple_media_manager_get_pipeline
(
manager
);
bus
=
gst_pipeline_get_bus
(
GST_PIPELINE
(
element
));
g_signal_handlers_disconnect_by_func
(
bus
,
level_message_cb
,
gtkmedia
);
}
static
void
pidgin_media_dispose
(
GObject
*
media
)
{
PidginMedia
*
gtkmedia
=
PIDGIN_MEDIA
(
media
);
purple_debug_info
(
"gtkmedia"
,
"pidgin_media_dispose
\n
"
);
if
(
gtkmedia
->
priv
->
media
)
{
purple_request_close_with_handle
(
gtkmedia
);
purple_media_remove_output_windows
(
gtkmedia
->
priv
->
media
);
pidgin_media_disconnect_levels
(
gtkmedia
->
priv
->
media
,
gtkmedia
);
g_clear_object
(
&
gtkmedia
->
priv
->
media
);
}
g_clear_handle_id
(
&
gtkmedia
->
priv
->
timeout_id
,
g_source_remove
);
g_clear_pointer
(
&
gtkmedia
->
priv
->
recv_progressbars
,
g_hash_table_destroy
);
g_clear_pointer
(
&
gtkmedia
->
priv
->
remote_videos
,
g_hash_table_destroy
);
g_clear_pointer
(
&
gtkmedia
->
priv
->
screenname
,
g_free
);
G_OBJECT_CLASS
(
pidgin_media_parent_class
)
->
dispose
(
media
);
}
static
void
pidgin_media_finalize
(
GObject
*
media
)
{
/* PidginMedia *gtkmedia = PIDGIN_MEDIA(media); */
purple_debug_info
(
"gtkmedia"
,
"pidgin_media_finalize
\n
"
);
G_OBJECT_CLASS
(
pidgin_media_parent_class
)
->
finalize
(
media
);
}
static
void
pidgin_media_emit_message
(
PidginMedia
*
gtkmedia
,
const
char
*
msg
)
{
PurpleConversation
*
conv
;
PurpleConversationManager
*
manager
;
PurpleAccount
*
account
;
account
=
purple_media_get_account
(
gtkmedia
->
priv
->
media
);
manager
=
purple_conversation_manager_get_default
();
conv
=
purple_conversation_manager_find
(
manager
,
account
,
gtkmedia
->
priv
->
screenname
);
if
(
PURPLE_IS_CONVERSATION
(
conv
))
{
purple_conversation_write_system_message
(
conv
,
msg
,
0
);
}
g_object_unref
(
account
);
}
static
void
pidgin_media_error_cb
(
G_GNUC_UNUSED
PidginMedia
*
media
,
const
char
*
error
,
PidginMedia
*
gtkmedia
)
{
PurpleConversation
*
conv
;
PurpleConversationManager
*
manager
;
PurpleAccount
*
account
;
account
=
purple_media_get_account
(
gtkmedia
->
priv
->
media
);
manager
=
purple_conversation_manager_get_default
();
conv
=
purple_conversation_manager_find
(
manager
,
account
,
gtkmedia
->
priv
->
screenname
);
if
(
PURPLE_IS_CONVERSATION
(
conv
))
{
purple_conversation_write_system_message
(
conv
,
error
,
PURPLE_MESSAGE_ERROR
);
}
else
{
purple_notify_error
(
NULL
,
NULL
,
_
(
"Media error"
),
error
,
purple_request_cpar_from_conversation
(
conv
));
}
gtk_label_set_text
(
gtkmedia
->
priv
->
status
,
error
);
g_object_unref
(
account
);
}
static
void
pidgin_media_accept_cb
(
PurpleMedia
*
media
,
G_GNUC_UNUSED
int
index
)
{
purple_media_stream_info
(
media
,
PURPLE_MEDIA_INFO_ACCEPT
,
NULL
,
NULL
,
TRUE
);
}
static
void
pidgin_media_reject_cb
(
PurpleMedia
*
media
,
G_GNUC_UNUSED
int
index
)
{
GList
*
iter
=
purple_media_get_session_ids
(
media
);
for
(;
iter
;
iter
=
g_list_delete_link
(
iter
,
iter
))
{
const
gchar
*
sessionid
=
iter
->
data
;
if
(
!
purple_media_accepted
(
media
,
sessionid
,
NULL
))
{
purple_media_stream_info
(
media
,
PURPLE_MEDIA_INFO_REJECT
,
sessionid
,
NULL
,
TRUE
);
}
}
}
static
gboolean
pidgin_request_timeout_cb
(
PidginMedia
*
gtkmedia
)
{
PurpleAccount
*
account
;
PurpleBuddy
*
buddy
;
const
gchar
*
alias
;
PurpleMediaSessionType
type
;
gchar
*
message
=
NULL
;
account
=
purple_media_get_account
(
gtkmedia
->
priv
->
media
);
buddy
=
purple_blist_find_buddy
(
account
,
gtkmedia
->
priv
->
screenname
);
if
(
buddy
!=
NULL
)
{
alias
=
purple_buddy_get_contact_alias
(
buddy
);
}
else
{
alias
=
gtkmedia
->
priv
->
screenname
;
}
type
=
gtkmedia
->
priv
->
request_type
;
gtkmedia
->
priv
->
timeout_id
=
0
;
if
(
type
&
PURPLE_MEDIA_AUDIO
&&
type
&
PURPLE_MEDIA_VIDEO
)
{
message
=
g_strdup_printf
(
_
(
"%s wishes to start an audio/video session with you."
),
alias
);
}
else
if
(
type
&
PURPLE_MEDIA_AUDIO
)
{
message
=
g_strdup_printf
(
_
(
"%s wishes to start an audio session with you."
),
alias
);
}
else
if
(
type
&
PURPLE_MEDIA_VIDEO
)
{
message
=
g_strdup_printf
(
_
(
"%s wishes to start a video session with you."
),
alias
);
}
gtkmedia
->
priv
->
request_type
=
PURPLE_MEDIA_NONE
;
if
(
!
purple_media_accepted
(
gtkmedia
->
priv
->
media
,
NULL
,
NULL
))
{
purple_request_accept_cancel
(
gtkmedia
,
_
(
"Incoming Call"
),
message
,
NULL
,
PURPLE_DEFAULT_ACTION_NONE
,
purple_request_cpar_from_account
(
account
),
gtkmedia
->
priv
->
media
,
pidgin_media_accept_cb
,
pidgin_media_reject_cb
);
}
pidgin_media_emit_message
(
gtkmedia
,
message
);
g_free
(
message
);
g_object_unref
(
account
);
return
FALSE
;
}
static
void
pidgin_media_input_volume_changed
(
G_GNUC_UNUSED
GtkScaleButton
*
range
,
double
value
,
PurpleMedia
*
media
)
{
double
val
=
(
double
)
value
*
100.0
;
purple_media_set_input_volume
(
media
,
NULL
,
val
);
}
static
void
pidgin_media_output_volume_changed
(
G_GNUC_UNUSED
GtkScaleButton
*
range
,
double
value
,
PurpleMedia
*
media
)
{
double
val
=
(
double
)
value
*
100.0
;
purple_media_set_output_volume
(
media
,
NULL
,
NULL
,
val
);
}
static
void
destroy_parent_widget_cb
(
G_GNUC_UNUSED
GtkWidget
*
widget
,
GtkWidget
*
parent
)
{
g_return_if_fail
(
GTK_IS_WIDGET
(
parent
));
gtk_widget_unparent
(
parent
);
}
static
GtkWidget
*
pidgin_media_add_audio_widget
(
PidginMedia
*
gtkmedia
,
PurpleMediaSessionType
type
,
const
gchar
*
sid
)
{
GtkWidget
*
volume_widget
,
*
progress_parent
,
*
volume
,
*
progress
;
double
value
;
static
const
gchar
*
input_volume_icons
[]
=
{
"microphone-sensitivity-muted-symbolic"
,
"microphone-sensitivity-high-symbolic"
,
"microphone-sensitivity-low-symbolic"
,
"microphone-sensitivity-medium-symbolic"
,
NULL
};
if
(
type
&
PURPLE_MEDIA_SEND_AUDIO
)
{
value
=
purple_prefs_get_int
(
"/purple/media/audio/volume/input"
);
}
else
if
(
type
&
PURPLE_MEDIA_RECV_AUDIO
)
{
value
=
purple_prefs_get_int
(
"/purple/media/audio/volume/output"
);
}
else
{
g_return_val_if_reached
(
NULL
);
}
/* Setup widget structure */
volume_widget
=
gtk_box_new
(
GTK_ORIENTATION_HORIZONTAL
,
6
);
progress_parent
=
gtk_box_new
(
GTK_ORIENTATION_VERTICAL
,
0
);
gtk_widget_set_hexpand
(
progress_parent
,
TRUE
);
gtk_box_append
(
GTK_BOX
(
volume_widget
),
progress_parent
);
/* Volume button */
volume
=
gtk_volume_button_new
();
gtk_scale_button_set_value
(
GTK_SCALE_BUTTON
(
volume
),
value
/
100.0
);
gtk_box_append
(
GTK_BOX
(
volume_widget
),
volume
);
/* Volume level indicator */
progress
=
gtk_progress_bar_new
();
gtk_widget_set_size_request
(
progress
,
250
,
10
);
gtk_widget_set_vexpand
(
progress
,
TRUE
);
gtk_box_append
(
GTK_BOX
(
progress_parent
),
progress
);
if
(
type
&
PURPLE_MEDIA_SEND_AUDIO
)
{
g_signal_connect
(
G_OBJECT
(
volume
),
"value-changed"
,
G_CALLBACK
(
pidgin_media_input_volume_changed
),
gtkmedia
->
priv
->
media
);
gtk_scale_button_set_icons
(
GTK_SCALE_BUTTON
(
volume
),
input_volume_icons
);
gtkmedia
->
priv
->
send_progress
=
progress
;
}
else
if
(
type
&
PURPLE_MEDIA_RECV_AUDIO
)
{
g_signal_connect
(
G_OBJECT
(
volume
),
"value-changed"
,
G_CALLBACK
(
pidgin_media_output_volume_changed
),
gtkmedia
->
priv
->
media
);
pidgin_media_insert_widget
(
gtkmedia
,
progress
,
sid
,
gtkmedia
->
priv
->
screenname
);
}
g_signal_connect
(
G_OBJECT
(
progress
),
"destroy"
,
G_CALLBACK
(
destroy_parent_widget_cb
),
volume_widget
);
return
volume_widget
;
}
static
void
pidgin_media_keypad_pressed_cb
(
G_GNUC_UNUSED
PidginKeypad
*
keypad
,
guint
key
,
gpointer
data
)
{
PidginMedia
*
gtkmedia
=
data
;
gchar
*
sid
;
sid
=
g_object_get_data
(
G_OBJECT
(
gtkmedia
),
"session-id"
);
purple_media_send_dtmf
(
gtkmedia
->
priv
->
media
,
sid
,
key
,
25
,
50
);
}
static
GtkWidget
*
pidgin_media_add_dtmf_widget
(
PidginMedia
*
gtkmedia
,
G_GNUC_UNUSED
PurpleMediaSessionType
type
,
const
char
*
_sid
)
{
GtkApplicationWindow
*
win
=
GTK_APPLICATION_WINDOW
(
gtkmedia
);
GtkWidget
*
keypad
=
NULL
;
keypad
=
pidgin_keypad_new
();
pidgin_keypad_set_key_capture_widget
(
PIDGIN_KEYPAD
(
keypad
),
GTK_WIDGET
(
win
));
g_signal_connect
(
keypad
,
"pressed"
,
G_CALLBACK
(
pidgin_media_keypad_pressed_cb
),
gtkmedia
);
g_object_set_data_full
(
G_OBJECT
(
win
),
"session-id"
,
g_strdup
(
_sid
),
g_free
);
return
keypad
;
}
static
void
pidgin_media_ready_cb
(
PurpleMedia
*
media
,
PidginMedia
*
gtkmedia
,
const
gchar
*
sid
)
{
GtkWidget
*
send_widget
=
NULL
,
*
recv_widget
=
NULL
,
*
button_widget
=
NULL
;
PurpleMediaSessionType
type
=
purple_media_get_session_type
(
media
,
sid
);
if
(
gtkmedia
->
priv
->
recv_widget
==
NULL
&&
type
&
(
PURPLE_MEDIA_RECV_VIDEO
|
PURPLE_MEDIA_RECV_AUDIO
))
{
recv_widget
=
gtk_box_new
(
GTK_ORIENTATION_VERTICAL
,
6
);
gtk_widget_set_hexpand
(
recv_widget
,
TRUE
);
gtk_widget_set_vexpand
(
recv_widget
,
TRUE
);
gtk_box_append
(
GTK_BOX
(
gtkmedia
->
priv
->
display
),
recv_widget
);
}
else
{
recv_widget
=
gtkmedia
->
priv
->
recv_widget
;
}
if
(
gtkmedia
->
priv
->
send_widget
==
NULL
&&
type
&
(
PURPLE_MEDIA_SEND_VIDEO
|
PURPLE_MEDIA_SEND_AUDIO
))
{
send_widget
=
gtk_box_new
(
GTK_ORIENTATION_VERTICAL
,
6
);
gtk_box_prepend
(
GTK_BOX
(
gtkmedia
->
priv
->
display
),
send_widget
);
button_widget
=
gtk_box_new
(
GTK_ORIENTATION_HORIZONTAL
,
6
);
gtk_box_append
(
GTK_BOX
(
send_widget
),
button_widget
);
/* Hold button */
gtkmedia
->
priv
->
hold
=
gtk_toggle_button_new_with_mnemonic
(
_
(
"_Hold"
));
gtk_box_prepend
(
GTK_BOX
(
button_widget
),
gtkmedia
->
priv
->
hold
);
gtk_actionable_set_action_name
(
GTK_ACTIONABLE
(
gtkmedia
->
priv
->
hold
),
"win.Hold"
);
}
else
{
send_widget
=
gtkmedia
->
priv
->
send_widget
;
button_widget
=
gtkmedia
->
priv
->
button_widget
;
}
if
(
type
&
PURPLE_MEDIA_RECV_VIDEO
)
{
PidginMediaPrivate
*
priv
=
gtkmedia
->
priv
;
PurpleMediaManager
*
manager
=
NULL
;
GstElement
*
pipeline
=
NULL
;
GstElement
*
sink
=
NULL
;
GtkWidget
*
remote_video
=
NULL
;
purple_media_set_output_window
(
priv
->
media
,
sid
,
priv
->
screenname
);
manager
=
purple_media_get_manager
(
priv
->
media
);
pipeline
=
purple_media_manager_get_pipeline
(
manager
);
sink
=
gst_bin_get_by_name
(
GST_BIN
(
pipeline
),
"gtkglsink"
);
if
(
sink
==
NULL
)
{
sink
=
gst_bin_get_by_name
(
GST_BIN
(
pipeline
),
"gtksink"
);
}
g_object_get
(
G_OBJECT
(
sink
),
"widget"
,
&
remote_video
,
NULL
);
gtk_widget_set_visible
(
remote_video
,
TRUE
);
gtk_widget_set_vexpand
(
remote_video
,
TRUE
);
gtk_box_append
(
GTK_BOX
(
recv_widget
),
remote_video
);
pidgin_media_insert_widget
(
gtkmedia
,
remote_video
,
sid
,
priv
->
screenname
);
}
if
(
type
&
PURPLE_MEDIA_SEND_VIDEO
&&
!
gtkmedia
->
priv
->
local_video
)
{
PidginMediaPrivate
*
priv
=
gtkmedia
->
priv
;
PurpleMediaManager
*
manager
=
NULL
;
GstElement
*
pipeline
=
NULL
;
GstElement
*
sink
=
NULL
;
GtkWidget
*
local_video
=
NULL
;
purple_media_set_output_window
(
priv
->
media
,
sid
,
NULL
);
manager
=
purple_media_get_manager
(
priv
->
media
);
pipeline
=
purple_media_manager_get_pipeline
(
manager
);
sink
=
gst_bin_get_by_name
(
GST_BIN
(
pipeline
),
"gtkglsink"
);
if
(
sink
==
NULL
)
{
sink
=
gst_bin_get_by_name
(
GST_BIN
(
pipeline
),
"gtksink"
);
}
g_object_get
(
G_OBJECT
(
sink
),
"widget"
,
&
local_video
,
NULL
);
gtk_widget_set_visible
(
local_video
,
TRUE
);
gtk_widget_set_vexpand
(
local_video
,
TRUE
);
gtk_box_append
(
GTK_BOX
(
send_widget
),
local_video
);
gtkmedia
->
priv
->
pause
=
gtk_toggle_button_new_with_mnemonic
(
_
(
"_Pause"
));
gtk_box_prepend
(
GTK_BOX
(
button_widget
),
gtkmedia
->
priv
->
pause
);
gtk_actionable_set_action_name
(
GTK_ACTIONABLE
(
gtkmedia
->
priv
->
pause
),
"win.Pause"
);
gtkmedia
->
priv
->
local_video
=
local_video
;
}
if
(
type
&
PURPLE_MEDIA_RECV_AUDIO
)
{
GtkWidget
*
audio
=
NULL
;
audio
=
pidgin_media_add_audio_widget
(
gtkmedia
,
PURPLE_MEDIA_RECV_AUDIO
,
sid
);
gtk_box_prepend
(
GTK_BOX
(
recv_widget
),
audio
);
}
if
(
type
&
PURPLE_MEDIA_SEND_AUDIO
)
{
gtkmedia
->
priv
->
mute
=
gtk_toggle_button_new_with_mnemonic
(
_
(
"_Mute"
));
gtk_box_prepend
(
GTK_BOX
(
button_widget
),
gtkmedia
->
priv
->
mute
);
gtk_actionable_set_action_name
(
GTK_ACTIONABLE
(
gtkmedia
->
priv
->
mute
),
"win.Mute"
);
gtk_box_prepend
(
GTK_BOX
(
recv_widget
),
pidgin_media_add_audio_widget
(
gtkmedia
,
PURPLE_MEDIA_SEND_AUDIO
,
sid
));
gtk_box_prepend
(
GTK_BOX
(
recv_widget
),
pidgin_media_add_dtmf_widget
(
gtkmedia
,
PURPLE_MEDIA_SEND_AUDIO
,
sid
));
}
if
(
type
&
PURPLE_MEDIA_AUDIO
&&
gtkmedia
->
priv
->
level_handler_id
==
0
)
{
gtkmedia
->
priv
->
level_handler_id
=
g_signal_connect
(
media
,
"level"
,
G_CALLBACK
(
level_message_cb
),
gtkmedia
);
}
if
(
send_widget
!=
NULL
)
{
gtkmedia
->
priv
->
send_widget
=
send_widget
;
}
if
(
recv_widget
!=
NULL
)
{
gtkmedia
->
priv
->
recv_widget
=
recv_widget
;
}
if
(
button_widget
!=
NULL
)
{
gtkmedia
->
priv
->
button_widget
=
button_widget
;
}
if
(
purple_media_is_initiator
(
media
,
sid
,
NULL
)
==
FALSE
)
{
g_clear_handle_id
(
&
gtkmedia
->
priv
->
timeout_id
,
g_source_remove
);
gtkmedia
->
priv
->
request_type
|=
type
;
gtkmedia
->
priv
->
timeout_id
=
g_timeout_add
(
500
,
G_SOURCE_FUNC
(
pidgin_request_timeout_cb
),
gtkmedia
);
}
/* set the window icon according to the type */
if
(
type
&
PURPLE_MEDIA_VIDEO
)
{
gtk_window_set_icon_name
(
GTK_WINDOW
(
gtkmedia
),
"video-call"
);
}
else
if
(
type
&
PURPLE_MEDIA_AUDIO
)
{
gtk_window_set_icon_name
(
GTK_WINDOW
(
gtkmedia
),
"audio-call"
);
}
}
static
void
pidgin_media_state_changed_cb
(
PurpleMedia
*
media
,
PurpleMediaState
state
,
gchar
*
sid
,
gchar
*
name
,
PidginMedia
*
gtkmedia
)
{
purple_debug_info
(
"gtkmedia"
,
"state: %d sid: %s name: %s
\n
"
,
state
,
sid
?
sid
:
"(null)"
,
name
?
name
:
"(null)"
);
if
(
state
==
PURPLE_MEDIA_STATE_END
)
{
if
(
sid
!=
NULL
&&
name
!=
NULL
)
{
pidgin_media_remove_widget
(
gtkmedia
,
sid
,
name
);
}
else
if
(
sid
==
NULL
&&
name
==
NULL
)
{
pidgin_media_emit_message
(
gtkmedia
,
_
(
"The call has been terminated."
));
gtk_window_destroy
(
GTK_WINDOW
(
gtkmedia
));
}
}
else
if
(
state
==
PURPLE_MEDIA_STATE_NEW
&&
sid
!=
NULL
&&
name
!=
NULL
)
{
pidgin_media_ready_cb
(
media
,
gtkmedia
,
sid
);
}
}
static
void
pidgin_media_stream_info_cb
(
G_GNUC_UNUSED
PurpleMedia
*
media
,
PurpleMediaInfoType
type
,
G_GNUC_UNUSED
gchar
*
sid
,
G_GNUC_UNUSED
gchar
*
name
,
gboolean
local
,
PidginMedia
*
gtkmedia
)
{
if
(
type
==
PURPLE_MEDIA_INFO_REJECT
)
{
pidgin_media_emit_message
(
gtkmedia
,
_
(
"You have rejected the call."
));
}
else
if
(
type
==
PURPLE_MEDIA_INFO_ACCEPT
)
{
if
(
local
)
{
purple_request_close_with_handle
(
gtkmedia
);
}
pidgin_media_set_state
(
gtkmedia
,
PIDGIN_MEDIA_ACCEPTED
);
pidgin_media_emit_message
(
gtkmedia
,
_
(
"Call in progress."
));
gtk_label_set_text
(
gtkmedia
->
priv
->
status
,
_
(
"Call in progress"
));
gtk_widget_set_visible
(
GTK_WIDGET
(
gtkmedia
),
TRUE
);
}
else
if
(
type
==
PURPLE_MEDIA_INFO_MUTE
&&
!
local
)
{
gtk_toggle_button_set_active
(
GTK_TOGGLE_BUTTON
(
gtkmedia
->
priv
->
mute
),
TRUE
);
}
else
if
(
type
==
PURPLE_MEDIA_INFO_UNMUTE
&&
!
local
)
{
gtk_toggle_button_set_active
(
GTK_TOGGLE_BUTTON
(
gtkmedia
->
priv
->
mute
),
FALSE
);
}
}
static
void
pidgin_media_set_property
(
GObject
*
object
,
guint
prop_id
,
const
GValue
*
value
,
GParamSpec
*
pspec
)
{
PidginMedia
*
media
=
PIDGIN_MEDIA
(
object
);
switch
(
prop_id
)
{
case
PROP_MEDIA
:
g_set_object
(
&
media
->
priv
->
media
,
g_value_get_object
(
value
));
if
(
purple_media_is_initiator
(
media
->
priv
->
media
,
NULL
,
NULL
))
{
pidgin_media_set_state
(
media
,
PIDGIN_MEDIA_WAITING
);
}
else
{
pidgin_media_set_state
(
media
,
PIDGIN_MEDIA_REQUESTED
);
}
g_signal_connect
(
G_OBJECT
(
media
->
priv
->
media
),
"error"
,
G_CALLBACK
(
pidgin_media_error_cb
),
media
);
g_signal_connect
(
G_OBJECT
(
media
->
priv
->
media
),
"state-changed"
,
G_CALLBACK
(
pidgin_media_state_changed_cb
),
media
);
g_signal_connect
(
G_OBJECT
(
media
->
priv
->
media
),
"stream-info"
,
G_CALLBACK
(
pidgin_media_stream_info_cb
),
media
);
break
;
case
PROP_SCREENNAME
:
g_free
(
media
->
priv
->
screenname
);
media
->
priv
->
screenname
=
g_value_dup_string
(
value
);
break
;
default
:
G_OBJECT_WARN_INVALID_PROPERTY_ID
(
object
,
prop_id
,
pspec
);
break
;
}
}
static
void
pidgin_media_get_property
(
GObject
*
object
,
guint
prop_id
,
GValue
*
value
,
GParamSpec
*
pspec
)
{
PidginMedia
*
media
=
PIDGIN_MEDIA
(
object
);
switch
(
prop_id
)
{
case
PROP_MEDIA
:
g_value_set_object
(
value
,
media
->
priv
->
media
);
break
;
case
PROP_SCREENNAME
:
g_value_set_string
(
value
,
media
->
priv
->
screenname
);
break
;
default
:
G_OBJECT_WARN_INVALID_PROPERTY_ID
(
object
,
prop_id
,
pspec
);
break
;
}
}
static
GtkWidget
*
pidgin_media_new
(
PurpleMedia
*
media
,
const
gchar
*
screenname
)
{
PidginMedia
*
gtkmedia
=
g_object_new
(
pidgin_media_get_type
(),
"media"
,
media
,
"screenname"
,
screenname
,
NULL
);
return
GTK_WIDGET
(
gtkmedia
);
}
static
void
pidgin_media_set_state
(
PidginMedia
*
gtkmedia
,
PidginMediaState
state
)
{
gtkmedia
->
priv
->
state
=
state
;
}
static
gboolean
pidgin_media_new_cb
(
G_GNUC_UNUSED
PurpleMediaManager
*
manager
,
PurpleMedia
*
media
,
PurpleAccount
*
account
,
char
*
screenname
,
G_GNUC_UNUSED
gpointer
data
)
{
PidginMedia
*
gtkmedia
=
NULL
;
PurpleBuddy
*
buddy
=
NULL
;
const
gchar
*
alias
=
NULL
;
gtkmedia
=
PIDGIN_MEDIA
(
pidgin_media_new
(
media
,
screenname
));
buddy
=
purple_blist_find_buddy
(
account
,
screenname
);
if
(
buddy
!=
NULL
)
{
alias
=
purple_buddy_get_contact_alias
(
buddy
);
}
else
{
alias
=
screenname
;
}
gtk_window_set_title
(
GTK_WINDOW
(
gtkmedia
),
alias
);
gtk_widget_set_visible
(
GTK_WIDGET
(
gtkmedia
),
purple_media_is_initiator
(
media
,
NULL
,
NULL
));
return
TRUE
;
}
void
pidgin_medias_init
(
void
)
{
PurpleMediaManager
*
manager
=
purple_media_manager_get
();
PurpleMediaElementInfo
*
video_src
=
NULL
;
PurpleMediaElementInfo
*
video_sink
=
NULL
;
PurpleMediaElementInfo
*
audio_src
=
NULL
;
PurpleMediaElementInfo
*
audio_sink
=
NULL
;
const
char
*
pref
;
pref
=
purple_prefs_get_string
(
PIDGIN_PREFS_ROOT
"/vvconfig/video/src/device"
);
if
(
pref
)
{
video_src
=
purple_media_manager_get_element_info
(
manager
,
pref
);
}
if
(
!
video_src
)
{
pref
=
"autovideosrc"
;
purple_prefs_set_string
(
PIDGIN_PREFS_ROOT
"/vvconfig/video/src/device"
,
pref
);
video_src
=
purple_media_manager_get_element_info
(
manager
,
pref
);
}
pref
=
purple_prefs_get_string
(
PIDGIN_PREFS_ROOT
"/vvconfig/video/sink/device"
);
if
(
pref
)
{
video_sink
=
purple_media_manager_get_element_info
(
manager
,
pref
);
}
if
(
!
video_sink
)
{
pref
=
"autovideosink"
;
purple_prefs_set_string
(
PIDGIN_PREFS_ROOT
"/vvconfig/video/sink/device"
,
pref
);
video_sink
=
purple_media_manager_get_element_info
(
manager
,
pref
);
}
pref
=
purple_prefs_get_string
(
PIDGIN_PREFS_ROOT
"/vvconfig/audio/src/device"
);
if
(
pref
)
{
audio_src
=
purple_media_manager_get_element_info
(
manager
,
pref
);
}
if
(
!
audio_src
)
{
pref
=
"autoaudiosrc"
;
purple_prefs_set_string
(
PIDGIN_PREFS_ROOT
"/vvconfig/audio/src/device"
,
pref
);
audio_src
=
purple_media_manager_get_element_info
(
manager
,
pref
);
}
pref
=
purple_prefs_get_string
(
PIDGIN_PREFS_ROOT
"/vvconfig/audio/sink/device"
);
if
(
pref
)
{
audio_sink
=
purple_media_manager_get_element_info
(
manager
,
pref
);
}
if
(
!
audio_sink
)
{
pref
=
"autoaudiosink"
;
purple_prefs_set_string
(
PIDGIN_PREFS_ROOT
"/vvconfig/audio/sink/device"
,
pref
);
audio_sink
=
purple_media_manager_get_element_info
(
manager
,
pref
);
}
g_signal_connect
(
G_OBJECT
(
manager
),
"init-media"
,
G_CALLBACK
(
pidgin_media_new_cb
),
NULL
);
purple_media_manager_set_ui_caps
(
manager
,
PURPLE_MEDIA_CAPS_AUDIO
|
PURPLE_MEDIA_CAPS_AUDIO_SINGLE_DIRECTION
|
PURPLE_MEDIA_CAPS_VIDEO
|
PURPLE_MEDIA_CAPS_VIDEO_SINGLE_DIRECTION
|
PURPLE_MEDIA_CAPS_AUDIO_VIDEO
);
purple_debug_info
(
"gtkmedia"
,
"Registering media element types
\n
"
);
purple_media_manager_set_active_element
(
manager
,
video_src
);
purple_media_manager_set_active_element
(
manager
,
video_sink
);
purple_media_manager_set_active_element
(
manager
,
audio_src
);
purple_media_manager_set_active_element
(
manager
,
audio_sink
);
}