ClutterActor *preview_rectangle_box2;
ClutterActor *preview_rectangle_box3;
ClutterActor *preview_rectangle_box4;
+ ClutterActor *preview_spinner_actor;
+ GtkWidget *preview_spinner_widget;
GtkWidget *video_container;
GtkWidget *remote_user_avatar_widget;
GtkWidget *remote_user_avatar_toolbar;
g_object_set (self->priv->preview_rectangle4, "visible", show, NULL);
}
+static void
+empathy_call_window_get_preview_coordinates (EmpathyCallWindow *self,
+ PreviewPosition pos,
+ guint *x,
+ guint *y)
+{
+ guint ret_x = 0, ret_y = 0;
+ ClutterGeometry box;
+
+ if (!clutter_actor_has_allocation (self->priv->video_box))
+ goto out;
+
+ clutter_actor_get_geometry (self->priv->video_box, &box);
+
+ switch (pos)
+ {
+ case PREVIEW_POS_TOP_LEFT:
+ ret_x = ret_y = SELF_VIDEO_SECTION_MARGIN;
+ break;
+ case PREVIEW_POS_TOP_RIGHT:
+ ret_x = box.width - SELF_VIDEO_SECTION_MARGIN
+ - SELF_VIDEO_SECTION_WIDTH;
+ ret_y = SELF_VIDEO_SECTION_MARGIN;
+ break;
+ case PREVIEW_POS_BOTTOM_LEFT:
+ ret_x = SELF_VIDEO_SECTION_MARGIN;
+ ret_y = box.height - SELF_VIDEO_SECTION_MARGIN
+ - SELF_VIDEO_SECTION_HEIGHT
+ - FLOATING_TOOLBAR_HEIGHT - FLOATING_TOOLBAR_SPACING;
+ break;
+ case PREVIEW_POS_BOTTOM_RIGHT:
+ ret_x = box.width - SELF_VIDEO_SECTION_MARGIN
+ - SELF_VIDEO_SECTION_WIDTH;
+ ret_y = box.height - SELF_VIDEO_SECTION_MARGIN
+ - SELF_VIDEO_SECTION_HEIGHT - FLOATING_TOOLBAR_HEIGHT
+ - FLOATING_TOOLBAR_SPACING;
+ break;
+ default:
+ g_warn_if_reached ();
+ }
+
+out:
+ if (x != NULL)
+ *x = ret_x;
+
+ if (y != NULL)
+ *y = ret_y;
+}
+
static PreviewPosition
empathy_call_window_get_preview_position (EmpathyCallWindow *self,
gfloat event_x,
empathy_call_window_darken_preview_rectangles (self);
}
+static void
+empathy_call_window_on_animation_completed_cb (ClutterAnimation *animation,
+ ClutterActor *actor)
+{
+ clutter_actor_set_opacity (actor, 255);
+}
+
static void
empathy_call_window_preview_on_drag_end_cb (ClutterDragAction *action,
ClutterActor *actor,
EmpathyCallWindow *self)
{
PreviewPosition pos;
+ guint x, y;
/* Get the position before destroying the drag actor, otherwise the
* preview_box allocation won't be valid and we won't be able to
* calculate the position. */
pos = empathy_call_window_get_preview_position (self, event_x, event_y);
- /* Destroy the video preview copy that we were dragging */
- clutter_actor_destroy (self->priv->drag_preview);
- self->priv->drag_preview = NULL;
+ empathy_call_window_get_preview_coordinates (self,
+ pos != PREVIEW_POS_NONE ? pos : self->priv->preview_pos,
+ &x, &y);
+
+ /* Move the preview to the destination and destroy it afterwards */
+ clutter_actor_animate (self->priv->drag_preview, CLUTTER_LINEAR, 500,
+ "x", (gfloat) x,
+ "y", (gfloat) y,
+ "signal-swapped-after::completed",
+ clutter_actor_destroy, self->priv->drag_preview,
+ "signal-swapped-after::completed",
+ clutter_actor_show, self->priv->preview_shown_button,
+ "signal::completed",
+ empathy_call_window_on_animation_completed_cb, actor,
+ NULL);
- clutter_actor_set_opacity (actor, 255);
- clutter_actor_show (self->priv->preview_shown_button);
+ self->priv->drag_preview = NULL;
if (pos != PREVIEW_POS_NONE)
empathy_call_window_move_video_preview (self, pos);
ClutterAction *action;
GtkWidget *button;
PreviewPosition pos;
+ GdkRGBA transparent = { 0., 0., 0., 0. };
g_assert (priv->video_preview == NULL);
SELF_VIDEO_SECTION_HEIGHT + 2 * SELF_VIDEO_SECTION_MARGIN +
FLOATING_TOOLBAR_HEIGHT + FLOATING_TOOLBAR_SPACING);
+ /* Spinner for when changing the camera device */
+ priv->preview_spinner_widget = gtk_spinner_new ();
+ priv->preview_spinner_actor = empathy_rounded_actor_new ();
+ empathy_rounded_actor_set_round_factor (
+ EMPATHY_ROUNDED_ACTOR (priv->preview_spinner_actor), 16);
+
+ g_object_set (priv->preview_spinner_widget, "expand", TRUE, NULL);
+ gtk_widget_override_background_color (
+ gtk_clutter_actor_get_widget (
+ GTK_CLUTTER_ACTOR (priv->preview_spinner_actor)),
+ GTK_STATE_FLAG_NORMAL, &transparent);
+ gtk_widget_show (priv->preview_spinner_widget);
+
+ gtk_container_add (
+ GTK_CONTAINER (gtk_clutter_actor_get_widget (
+ GTK_CLUTTER_ACTOR (priv->preview_spinner_actor))),
+ priv->preview_spinner_widget);
+ clutter_actor_set_size (priv->preview_spinner_actor,
+ SELF_VIDEO_SECTION_WIDTH, SELF_VIDEO_SECTION_HEIGHT);
+ clutter_actor_set_opacity (priv->preview_spinner_actor, 128);
+ clutter_actor_hide (priv->preview_spinner_actor);
+
/* We have a box with the margins and the video in the middle inside
* a bigger box with an extra bottom margin so we're not on top of
* the floating toolbar. */
SELF_VIDEO_SECTION_HEIGHT + 2 * SELF_VIDEO_SECTION_MARGIN);
clutter_container_add_actor (CLUTTER_CONTAINER (box), preview);
+ clutter_container_add_actor (CLUTTER_CONTAINER (box),
+ priv->preview_spinner_actor);
clutter_container_add_actor (CLUTTER_CONTAINER (priv->video_preview), box);
g_object_set (priv->video_preview_sink,
clutter_actor_set_reactive (priv->preview_shown_button, TRUE);
}
+static void
+empathy_call_window_start_camera_spinning (EmpathyCallWindow *self)
+{
+ clutter_actor_show (self->priv->preview_spinner_actor);
+ gtk_spinner_start (GTK_SPINNER (self->priv->preview_spinner_widget));
+}
+
+static void
+empathy_call_window_stop_camera_spinning (EmpathyCallWindow *self)
+{
+ clutter_actor_hide (self->priv->preview_spinner_actor);
+ gtk_spinner_stop (GTK_SPINNER (self->priv->preview_spinner_widget));
+}
+
void
-empathy_call_window_play_camera (EmpathyCallWindow *window,
+empathy_call_window_play_camera (EmpathyCallWindow *self,
gboolean play)
{
- EmpathyCallWindowPriv *priv = GET_PRIV (window);
+ EmpathyCallWindowPriv *priv = GET_PRIV (self);
GstElement *preview;
GstState state;
if (priv->video_preview == NULL)
{
- create_video_preview (window);
- add_video_preview_to_pipeline (window);
+ create_video_preview (self);
+ add_video_preview_to_pipeline (self);
}
if (play)
- state = GST_STATE_PLAYING;
+ {
+ state = GST_STATE_PLAYING;
+ }
else
- state = GST_STATE_NULL;
+ {
+ empathy_call_window_start_camera_spinning (self);
+ state = GST_STATE_NULL;
+ }
preview = priv->video_preview_sink;
priv = self->priv = G_TYPE_INSTANCE_GET_PRIVATE (self,
EMPATHY_TYPE_CALL_WINDOW, EmpathyCallWindowPriv);
+ priv->settings = g_settings_new (EMPATHY_PREFS_CALL_SCHEMA);
+
filename = empathy_file_lookup ("empathy-call-window.ui", "src");
gui = empathy_builder_get_file (filename,
"call_window_vbox", &top_vbox,
empathy_call_window_show_hangup_button (self, TRUE);
- priv->settings = g_settings_new (EMPATHY_PREFS_CALL_SCHEMA);
-
/* Retrieve initial volume */
priv->volume = g_settings_get_double (priv->settings,
EMPATHY_PREFS_CALL_SOUND_VOLUME) / 100.0;
EmpathyCallWindow *self = EMPATHY_CALL_WINDOW (object);
EmpathyCallWindowPriv *priv = GET_PRIV (self);
TpyCallChannel *call;
+ TpyCallState state;
g_assert (priv->handler != NULL);
g_object_get (priv->handler, "call-channel", &call, NULL);
- priv->outgoing = (call == NULL);
- if (call != NULL)
- g_object_unref (call);
+ state = tpy_call_channel_get_state (call, NULL, NULL);
+ priv->outgoing = (state == TPY_CALL_STATE_PENDING_INITIATOR);
+ tp_clear_object (&call);
g_object_get (priv->handler, "target-contact", &priv->contact, NULL);
g_assert (priv->contact != NULL);
{
EmpathyCallWindow *self = EMPATHY_CALL_WINDOW (user_data);
EmpathyCallWindowPriv *priv = GET_PRIV (self);
- GstState newstate;
+ GstState newstate, pending;
empathy_call_handler_bus_message (priv->handler, bus, message);
start_call (self);
}
}
+ if (GST_MESSAGE_SRC (message) == GST_OBJECT (priv->video_preview_sink))
+ {
+ gst_message_parse_state_changed (message, NULL, &newstate,
+ &pending);
+
+ if (newstate == GST_STATE_PLAYING &&
+ pending == GST_STATE_VOID_PENDING)
+ empathy_call_window_stop_camera_spinning (self);
+ }
break;
case GST_MESSAGE_ERROR:
{
g_signal_connect (priv->handler, "sink-pad-removed",
G_CALLBACK (empathy_call_window_sink_removed_cb), self);
+ /* We connect to ::call-channel unconditionally since we'll
+ * get new channels if we hangup and redial or if we reuse the
+ * call window. */
+ g_signal_connect (priv->handler, "notify::call-channel",
+ G_CALLBACK (call_handler_notify_call_cb), self);
+
g_object_get (priv->handler, "call-channel", &call, NULL);
if (call != NULL)
{
+ /* We won't get notify::call-channel for this channel, so
+ * directly call the callback. */
call_handler_notify_call_cb (priv->handler, NULL, self);
g_object_unref (call);
}
- else
- {
- /* call-channel doesn't exist yet, we'll connect signals once it has been
- * set */
- g_signal_connect (priv->handler, "notify::call-channel",
- G_CALLBACK (call_handler_notify_call_cb), self);
- }
}
static void