aboutsummaryrefslogtreecommitdiffstats
path: root/src/empathy-call-window.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/empathy-call-window.c')
-rw-r--r--src/empathy-call-window.c374
1 files changed, 370 insertions, 4 deletions
diff --git a/src/empathy-call-window.c b/src/empathy-call-window.c
index eb88d85bc..b56613ca5 100644
--- a/src/empathy-call-window.c
+++ b/src/empathy-call-window.c
@@ -113,6 +113,14 @@ typedef enum {
CAMERA_STATE_ON,
} CameraState;
+typedef enum {
+ PREVIEW_POS_NONE,
+ PREVIEW_POS_TOP_LEFT,
+ PREVIEW_POS_TOP_RIGHT,
+ PREVIEW_POS_BOTTOM_LEFT,
+ PREVIEW_POS_BOTTOM_RIGHT,
+} PreviewPosition;
+
struct _EmpathyCallWindowPriv
{
gboolean dispose_has_run;
@@ -132,6 +140,10 @@ struct _EmpathyCallWindowPriv
ClutterActor *video_output;
ClutterActor *video_preview;
ClutterActor *preview_hidden_button;
+ ClutterActor *preview_rectangle1;
+ ClutterActor *preview_rectangle2;
+ ClutterActor *preview_rectangle3;
+ ClutterActor *preview_rectangle4;
GtkWidget *video_container;
GtkWidget *remote_user_avatar_widget;
GtkWidget *remote_user_avatar_toolbar;
@@ -157,6 +169,11 @@ struct _EmpathyCallWindowPriv
ClutterActor *video_box;
ClutterLayoutManager *video_layout;
+ /* Coordinates of the preview drag event's start. */
+ PreviewPosition preview_pos;
+ gfloat event_x;
+ gfloat event_y;
+
/* We keep a reference on the hbox which contains the main content so we can
easilly repack everything when toggling fullscreen */
GtkWidget *content_hbox;
@@ -586,6 +603,330 @@ empathy_call_window_preview_hidden_button_clicked_cb (GtkButton *button,
gtk_menu_shell_select_first (GTK_MENU_SHELL (menu), FALSE);
}
+static ClutterActor *
+empathy_call_window_create_preview_rectangle (EmpathyCallWindow *self,
+ ClutterBinAlignment x,
+ ClutterBinAlignment y)
+{
+ ClutterLayoutManager *layout1, *layout2;
+ ClutterActor *rectangle;
+ ClutterActor *box1, *box2;
+
+ layout1 = clutter_bin_layout_new (CLUTTER_BIN_ALIGNMENT_CENTER,
+ CLUTTER_BIN_ALIGNMENT_START);
+
+ box1 = clutter_box_new (layout1);
+
+ rectangle = clutter_rectangle_new_with_color (
+ CLUTTER_COLOR_Transparent);
+
+ clutter_rectangle_set_border_width (CLUTTER_RECTANGLE (rectangle),
+ 1);
+
+ clutter_actor_set_size (box1,
+ SELF_VIDEO_SECTION_WIDTH + 2 * SELF_VIDEO_SECTION_MARGIN,
+ SELF_VIDEO_SECTION_HEIGTH + 2 * SELF_VIDEO_SECTION_MARGIN +
+ FLOATING_TOOLBAR_HEIGHT + FLOATING_TOOLBAR_SPACING);
+
+ layout2 = clutter_bin_layout_new (CLUTTER_BIN_ALIGNMENT_CENTER,
+ CLUTTER_BIN_ALIGNMENT_CENTER);
+
+ /* 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. */
+ box2 = clutter_box_new (layout2);
+
+ clutter_actor_set_size (box2,
+ SELF_VIDEO_SECTION_WIDTH + 2 * SELF_VIDEO_SECTION_MARGIN,
+ SELF_VIDEO_SECTION_HEIGTH + 2 * SELF_VIDEO_SECTION_MARGIN);
+
+ clutter_actor_set_size (rectangle,
+ SELF_VIDEO_SECTION_WIDTH + 5, SELF_VIDEO_SECTION_HEIGTH + 5);
+
+ clutter_container_add_actor (CLUTTER_CONTAINER (box1), box2);
+ clutter_container_add_actor (CLUTTER_CONTAINER (box2), rectangle);
+
+ clutter_bin_layout_add (CLUTTER_BIN_LAYOUT (self->priv->video_layout),
+ box1, x, y);
+
+ clutter_actor_hide (rectangle);
+
+ return rectangle;
+}
+
+static void
+empathy_call_window_create_preview_rectangles (EmpathyCallWindow *self)
+{
+ self->priv->preview_rectangle1 =
+ empathy_call_window_create_preview_rectangle (self,
+ CLUTTER_BIN_ALIGNMENT_START, CLUTTER_BIN_ALIGNMENT_START);
+ self->priv->preview_rectangle2 =
+ empathy_call_window_create_preview_rectangle (self,
+ CLUTTER_BIN_ALIGNMENT_START, CLUTTER_BIN_ALIGNMENT_END);
+ self->priv->preview_rectangle3 =
+ empathy_call_window_create_preview_rectangle (self,
+ CLUTTER_BIN_ALIGNMENT_END, CLUTTER_BIN_ALIGNMENT_START);
+ self->priv->preview_rectangle4 =
+ empathy_call_window_create_preview_rectangle (self,
+ CLUTTER_BIN_ALIGNMENT_END, CLUTTER_BIN_ALIGNMENT_END);
+}
+
+static void
+empathy_call_window_show_preview_rectangles (EmpathyCallWindow *self,
+ gboolean show)
+{
+ g_object_set (self->priv->preview_rectangle1, "visible", show, NULL);
+ g_object_set (self->priv->preview_rectangle2, "visible", show, NULL);
+ g_object_set (self->priv->preview_rectangle3, "visible", show, NULL);
+ g_object_set (self->priv->preview_rectangle4, "visible", show, NULL);
+}
+
+static PreviewPosition
+empathy_call_window_get_preview_position (EmpathyCallWindow *self,
+ gfloat event_x,
+ gfloat event_y)
+{
+ ClutterGeometry box;
+ PreviewPosition pos = PREVIEW_POS_NONE;
+
+ clutter_actor_get_geometry (self->priv->video_box, &box);
+
+ if (0 + SELF_VIDEO_SECTION_MARGIN <= event_x &&
+ event_x <= (0 + SELF_VIDEO_SECTION_MARGIN + (gint) SELF_VIDEO_SECTION_WIDTH) &&
+ 0 + SELF_VIDEO_SECTION_MARGIN <= event_y &&
+ event_y <= (0 + SELF_VIDEO_SECTION_MARGIN + (gint) SELF_VIDEO_SECTION_HEIGTH))
+ {
+ pos = PREVIEW_POS_TOP_LEFT;
+ }
+ else if (box.width - SELF_VIDEO_SECTION_MARGIN >= event_x &&
+ event_x >= (box.width - SELF_VIDEO_SECTION_MARGIN - (gint) SELF_VIDEO_SECTION_WIDTH) &&
+ 0 + SELF_VIDEO_SECTION_MARGIN <= event_y &&
+ event_y <= (0 + SELF_VIDEO_SECTION_MARGIN + (gint) SELF_VIDEO_SECTION_HEIGTH))
+ {
+ pos = PREVIEW_POS_TOP_RIGHT;
+ }
+ else if (0 + SELF_VIDEO_SECTION_MARGIN <= event_x &&
+ event_x <= (0 + SELF_VIDEO_SECTION_MARGIN + (gint) SELF_VIDEO_SECTION_WIDTH) &&
+ box.height - SELF_VIDEO_SECTION_MARGIN - FLOATING_TOOLBAR_HEIGHT - FLOATING_TOOLBAR_SPACING >= event_y &&
+ event_y >= (box.height - SELF_VIDEO_SECTION_MARGIN - FLOATING_TOOLBAR_HEIGHT - FLOATING_TOOLBAR_SPACING - (gint) SELF_VIDEO_SECTION_HEIGTH))
+ {
+ pos = PREVIEW_POS_BOTTOM_LEFT;
+ }
+ else if (box.width - SELF_VIDEO_SECTION_MARGIN >= event_x &&
+ event_x >= (box.width - SELF_VIDEO_SECTION_MARGIN - (gint) SELF_VIDEO_SECTION_WIDTH) &&
+ box.height - SELF_VIDEO_SECTION_MARGIN - SELF_VIDEO_SECTION_MARGIN - FLOATING_TOOLBAR_HEIGHT - FLOATING_TOOLBAR_SPACING >= event_y &&
+ event_y >= (box.height - SELF_VIDEO_SECTION_MARGIN - FLOATING_TOOLBAR_HEIGHT - FLOATING_TOOLBAR_SPACING - (gint) SELF_VIDEO_SECTION_HEIGTH))
+ {
+ pos = PREVIEW_POS_BOTTOM_RIGHT;
+ }
+
+ return pos;
+}
+
+static ClutterActor *
+empathy_call_window_get_preview_rectangle (EmpathyCallWindow *self,
+ PreviewPosition pos)
+{
+ ClutterActor *rectangle;
+
+ switch (pos)
+ {
+ case PREVIEW_POS_TOP_LEFT:
+ rectangle = self->priv->preview_rectangle1;
+ break;
+ case PREVIEW_POS_TOP_RIGHT:
+ rectangle = self->priv->preview_rectangle3;
+ break;
+ case PREVIEW_POS_BOTTOM_LEFT:
+ rectangle = self->priv->preview_rectangle2;
+ break;
+ case PREVIEW_POS_BOTTOM_RIGHT:
+ rectangle = self->priv->preview_rectangle4;
+ break;
+ default:
+ rectangle = NULL;
+ }
+
+ return rectangle;
+}
+
+static void
+empathy_call_window_move_video_preview (EmpathyCallWindow *self,
+ PreviewPosition pos)
+{
+ ClutterBinLayout *layout = CLUTTER_BIN_LAYOUT (self->priv->video_layout);
+
+ DEBUG ("moving the video preview to %d", pos);
+
+ self->priv->preview_pos = pos;
+
+ switch (pos)
+ {
+ case PREVIEW_POS_TOP_LEFT:
+ clutter_bin_layout_set_alignment (layout,
+ self->priv->video_preview,
+ CLUTTER_BIN_ALIGNMENT_START,
+ CLUTTER_BIN_ALIGNMENT_START);
+ break;
+ case PREVIEW_POS_TOP_RIGHT:
+ clutter_bin_layout_set_alignment (layout,
+ self->priv->video_preview,
+ CLUTTER_BIN_ALIGNMENT_END,
+ CLUTTER_BIN_ALIGNMENT_START);
+ break;
+ case PREVIEW_POS_BOTTOM_LEFT:
+ clutter_bin_layout_set_alignment (layout,
+ self->priv->video_preview,
+ CLUTTER_BIN_ALIGNMENT_START,
+ CLUTTER_BIN_ALIGNMENT_END);
+ break;
+ case PREVIEW_POS_BOTTOM_RIGHT:
+ clutter_bin_layout_set_alignment (layout,
+ self->priv->video_preview,
+ CLUTTER_BIN_ALIGNMENT_END,
+ CLUTTER_BIN_ALIGNMENT_END);
+ break;
+ default:
+ g_warn_if_reached ();
+ }
+}
+
+static void
+empathy_call_window_highlight_preview_rectangle (EmpathyCallWindow *self,
+ PreviewPosition pos)
+{
+ ClutterActor *rectangle;
+
+ rectangle = empathy_call_window_get_preview_rectangle (self, pos);
+
+ clutter_rectangle_set_border_width (CLUTTER_RECTANGLE (rectangle), 3);
+ clutter_rectangle_set_border_color (CLUTTER_RECTANGLE (rectangle),
+ CLUTTER_COLOR_Red);
+}
+
+static void
+empathy_call_window_darken_preview_rectangle (EmpathyCallWindow *self,
+ ClutterActor *rectangle)
+{
+ clutter_rectangle_set_border_width (CLUTTER_RECTANGLE (rectangle), 1);
+ clutter_rectangle_set_border_color (CLUTTER_RECTANGLE (rectangle),
+ CLUTTER_COLOR_Black);
+}
+
+static void
+empathy_call_window_darken_preview_rectangles (EmpathyCallWindow *self)
+{
+ ClutterActor *rectangle;
+
+ rectangle = empathy_call_window_get_preview_rectangle (self,
+ self->priv->preview_pos);
+
+ /* We don't want to darken the rectangle where the preview
+ * currently is. */
+
+ if (self->priv->preview_rectangle1 != rectangle)
+ empathy_call_window_darken_preview_rectangle (self,
+ self->priv->preview_rectangle1);
+
+ if (self->priv->preview_rectangle2 != rectangle)
+ empathy_call_window_darken_preview_rectangle (self,
+ self->priv->preview_rectangle2);
+
+ if (self->priv->preview_rectangle3 != rectangle)
+ empathy_call_window_darken_preview_rectangle (self,
+ self->priv->preview_rectangle3);
+
+ if (self->priv->preview_rectangle4 != rectangle)
+ empathy_call_window_darken_preview_rectangle (self,
+ self->priv->preview_rectangle4);
+}
+
+static void
+empathy_call_window_preview_on_drag_begin_cb (ClutterDragAction *action,
+ ClutterActor *actor,
+ gfloat event_x,
+ gfloat event_y,
+ ClutterModifierType modifiers,
+ EmpathyCallWindow *self)
+{
+ empathy_call_window_show_preview_rectangles (self, TRUE);
+ empathy_call_window_darken_preview_rectangles (self);
+
+ self->priv->event_x = event_x;
+ self->priv->event_y = event_y;
+}
+
+static void
+empathy_call_window_preview_on_drag_end_cb (ClutterDragAction *action,
+ ClutterActor *actor,
+ gfloat event_x,
+ gfloat event_y,
+ ClutterModifierType modifiers,
+ EmpathyCallWindow *self)
+{
+ PreviewPosition pos;
+
+ pos = empathy_call_window_get_preview_position (self, event_x, event_y);
+
+ if (pos != PREVIEW_POS_NONE)
+ empathy_call_window_move_video_preview (self, pos);
+
+ empathy_call_window_show_preview_rectangles (self, FALSE);
+}
+
+static void
+empathy_call_window_preview_on_drag_motion_cb (ClutterDragAction *action,
+ ClutterActor *actor,
+ gfloat delta_x,
+ gfloat delta_y,
+ EmpathyCallWindow *self)
+{
+ PreviewPosition pos;
+
+ pos = empathy_call_window_get_preview_position (self,
+ self->priv->event_x - delta_x, self->priv->event_y + delta_y);
+
+ if (pos != PREVIEW_POS_NONE)
+ empathy_call_window_highlight_preview_rectangle (self, pos);
+ else
+ empathy_call_window_darken_preview_rectangles (self);
+}
+
+static gboolean
+empathy_call_window_preview_enter_event_cb (ClutterActor *actor,
+ ClutterCrossingEvent *event,
+ EmpathyCallWindow *self)
+{
+ ClutterActor *rectangle;
+ PreviewPosition pos;
+
+ pos = empathy_call_window_get_preview_position (self, event->x, event->y);
+ rectangle = empathy_call_window_get_preview_rectangle (self, pos);
+
+ empathy_call_window_highlight_preview_rectangle (self, pos);
+
+ clutter_actor_show (rectangle);
+
+ return FALSE;
+}
+
+static gboolean
+empathy_call_window_preview_leave_event_cb (ClutterActor *actor,
+ ClutterCrossingEvent *event,
+ EmpathyCallWindow *self)
+{
+ ClutterActor *rectangle;
+
+ rectangle = empathy_call_window_get_preview_rectangle (self,
+ self->priv->preview_pos);
+
+ empathy_call_window_darken_preview_rectangle (self, rectangle);
+
+ clutter_actor_hide (rectangle);
+
+ return FALSE;
+}
+
static void
create_video_preview (EmpathyCallWindow *self)
{
@@ -594,6 +935,7 @@ create_video_preview (EmpathyCallWindow *self)
ClutterActor *preview;
ClutterActor *box;
ClutterActor *b;
+ ClutterAction *action;
GtkWidget *button;
g_assert (priv->video_preview == NULL);
@@ -613,19 +955,23 @@ create_video_preview (EmpathyCallWindow *self)
0.0);
/* Add a little offset to the video preview */
- layout = clutter_bin_layout_new (CLUTTER_BIN_ALIGNMENT_END,
+ layout = clutter_bin_layout_new (CLUTTER_BIN_ALIGNMENT_CENTER,
CLUTTER_BIN_ALIGNMENT_START);
priv->video_preview = clutter_box_new (layout);
clutter_actor_set_size (priv->video_preview,
- SELF_VIDEO_SECTION_WIDTH + SELF_VIDEO_SECTION_MARGIN,
- SELF_VIDEO_SECTION_HEIGTH + SELF_VIDEO_SECTION_MARGIN +
+ SELF_VIDEO_SECTION_WIDTH + 2 * SELF_VIDEO_SECTION_MARGIN,
+ SELF_VIDEO_SECTION_HEIGTH + 2 * SELF_VIDEO_SECTION_MARGIN +
FLOATING_TOOLBAR_HEIGHT + FLOATING_TOOLBAR_SPACING);
+ /* 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. */
layout_center = clutter_bin_layout_new (CLUTTER_BIN_ALIGNMENT_CENTER,
CLUTTER_BIN_ALIGNMENT_CENTER);
box = clutter_box_new (layout_center);
clutter_actor_set_size (box,
- SELF_VIDEO_SECTION_WIDTH, SELF_VIDEO_SECTION_HEIGTH);
+ SELF_VIDEO_SECTION_WIDTH + 2 * SELF_VIDEO_SECTION_MARGIN,
+ SELF_VIDEO_SECTION_HEIGTH + 2 * SELF_VIDEO_SECTION_MARGIN);
clutter_container_add_actor (CLUTTER_CONTAINER (box), preview);
clutter_container_add_actor (CLUTTER_CONTAINER (priv->video_preview), box);
@@ -660,6 +1006,8 @@ create_video_preview (EmpathyCallWindow *self)
CLUTTER_BIN_ALIGNMENT_START,
CLUTTER_BIN_ALIGNMENT_END);
+ self->priv->preview_pos = PREVIEW_POS_BOTTOM_LEFT;
+
clutter_actor_hide (priv->preview_hidden_button);
g_signal_connect (button, "clicked",
@@ -670,6 +1018,22 @@ create_video_preview (EmpathyCallWindow *self)
priv->video_preview,
CLUTTER_BIN_ALIGNMENT_START,
CLUTTER_BIN_ALIGNMENT_END);
+
+ action = clutter_drag_action_new ();
+ g_signal_connect (action, "drag-begin",
+ G_CALLBACK (empathy_call_window_preview_on_drag_begin_cb), self);
+ g_signal_connect (action, "drag-end",
+ G_CALLBACK (empathy_call_window_preview_on_drag_end_cb), self);
+ g_signal_connect (action, "drag-motion",
+ G_CALLBACK (empathy_call_window_preview_on_drag_motion_cb), self);
+
+ g_signal_connect (preview, "enter-event",
+ G_CALLBACK (empathy_call_window_preview_enter_event_cb), self);
+ g_signal_connect (preview, "leave-event",
+ G_CALLBACK (empathy_call_window_preview_leave_event_cb), self);
+
+ clutter_actor_add_action (preview, action);
+ clutter_actor_set_reactive (preview, TRUE);
}
static void
@@ -1052,6 +1416,8 @@ empathy_call_window_init (EmpathyCallWindow *self)
clutter_container_add_actor (CLUTTER_CONTAINER (priv->video_box),
remote_avatar);
+ empathy_call_window_create_preview_rectangles (self);
+
gtk_box_pack_start (GTK_BOX (priv->content_hbox),
priv->video_container, TRUE, TRUE,
CONTENT_HBOX_CHILDREN_PACKING_PADDING);