]> git.0d.be Git - empathy.git/commitdiff
Video playback fullscreen mode
authorjtellier <jtellier@Jospin.localdomain>
Thu, 7 May 2009 19:13:04 +0000 (15:13 -0400)
committerjtellier <jtellier@Jospin.localdomain>
Thu, 7 May 2009 19:13:04 +0000 (15:13 -0400)
See http://bugzilla.gnome.org/show_bug.cgi?id=580771

src/Makefile.am
src/empathy-call-window-fullscreen.c [new file with mode: 0644]
src/empathy-call-window-fullscreen.h [new file with mode: 0644]
src/empathy-call-window-fullscreen.ui [new file with mode: 0644]
src/empathy-call-window.c
src/empathy-call-window.ui

index f24ef3e95aa6873f2c60a4d8704b2d8939ffb0cb..9641a183751d809c2d76c1a900fa268ae9d7d740 100644 (file)
@@ -28,6 +28,7 @@ empathy_SOURCES =                                                     \
        empathy-about-dialog.c empathy-about-dialog.h                   \
        empathy-accounts-dialog.c empathy-accounts-dialog.h             \
        empathy-call-window.c empathy-call-window.h                     \
+       empathy-call-window-fullscreen.c empathy-call-window-fullscreen.h                       \
        empathy-chatrooms-window.c empathy-chatrooms-window.h           \
        empathy-chat-window.c empathy-chat-window.h                     \
        empathy-event-manager.c empathy-event-manager.h                 \
@@ -51,6 +52,7 @@ uidir = $(datadir)/empathy
 ui_DATA =                                      \
        empathy-accounts-dialog.ui              \
        empathy-call-window.ui                  \
+       empathy-call-window-fullscreen.ui                       \
        empathy-chatrooms-window.ui             \
        empathy-chat-window.ui                  \
        empathy-ft-manager.ui                   \
diff --git a/src/empathy-call-window-fullscreen.c b/src/empathy-call-window-fullscreen.c
new file mode 100644 (file)
index 0000000..d01d65b
--- /dev/null
@@ -0,0 +1,330 @@
+/*
+ * empathy-call-window.c - Source for EmpathyCallWindow
+ * Copyright (C) 2009 Collabora Ltd.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ */
+
+#include "empathy-call-window-fullscreen.h"
+
+#include <gtk/gtk.h>
+
+#include <libempathy/empathy-utils.h>
+#include <libempathy-gtk/empathy-ui-utils.h>
+
+/* The number of seconds fo which the "leave fullscreen" popup should be shown */
+#define FULLSCREEN_POPUP_TIMEOUT 5
+
+G_DEFINE_TYPE (EmpathyCallWindowFullscreen, empathy_call_window_fullscreen, GTK_TYPE_WINDOW)
+
+/* private structure */
+typedef struct _EmpathyCallWindowFullscreenPriv EmpathyCallWindowFullscreenPriv;
+
+struct _EmpathyCallWindowFullscreenPriv
+{
+  EmpathyCallWindow *parent_window;
+    
+  GtkWidget *leave_fullscreen_popup;
+  GtkWidget *video_widget;
+
+  gulong motion_handler_id;
+  guint popup_timeout;
+  gboolean popup_creation_in_progress;
+  gboolean dispose_has_run;
+};
+
+#define GET_PRIV(o) \
+  (G_TYPE_INSTANCE_GET_PRIVATE ((o), EMPATHY_TYPE_CALL_WINDOW_FULLSCREEN, \
+    EmpathyCallWindowFullscreenPriv))
+
+static void empathy_call_window_fullscreen_dispose (GObject *object);
+static void empathy_call_window_fullscreen_finalize (GObject *object);
+
+static gboolean empathy_call_window_fullscreen_motion_notify (GtkWidget *widget,
+    GdkEventMotion *event, EmpathyCallWindowFullscreen *fs);
+static gboolean empathy_call_window_fullscreen_hide_popup (EmpathyCallWindowFullscreen *fs);
+
+static void
+empathy_call_window_fullscreen_set_cursor_visible (EmpathyCallWindowFullscreen *fs,
+    gboolean show_cursor)
+{
+  EmpathyCallWindowFullscreenPriv *priv = GET_PRIV (fs);
+
+  if (priv->video_widget != NULL && !show_cursor)
+    gdk_window_set_cursor (priv->video_widget->window, gdk_cursor_new (GDK_BLANK_CURSOR));
+  else
+    gdk_window_set_cursor (priv->video_widget->window, NULL);
+}
+
+static void
+empathy_call_window_fullscreen_add_popup_timeout (EmpathyCallWindowFullscreen *self)
+{
+  EmpathyCallWindowFullscreenPriv *priv = GET_PRIV (self);
+
+  if (priv->popup_timeout == 0)
+    {
+         priv->popup_timeout = g_timeout_add_seconds (FULLSCREEN_POPUP_TIMEOUT,
+                           (GSourceFunc) empathy_call_window_fullscreen_hide_popup, self);
+    }
+}
+
+static void
+empathy_call_window_fullscreen_remove_popup_timeout (EmpathyCallWindowFullscreen *self)
+{
+  EmpathyCallWindowFullscreenPriv *priv = GET_PRIV (self);
+
+  if (priv->popup_timeout != 0)
+    {
+                 g_source_remove (priv->popup_timeout);
+                 priv->popup_timeout = 0;
+       }
+}
+
+static void
+empathy_call_window_fullscreen_show_popup (EmpathyCallWindowFullscreen *self)
+{
+  g_assert (self->is_fullscreen);
+
+  gint leave_fullscreen_width, leave_fullscreen_height;
+       GdkScreen *screen;
+       GdkRectangle fullscreen_rect;
+       EmpathyCallWindowFullscreenPriv *priv = GET_PRIV (self);
+
+  g_return_if_fail (priv->parent_window != NULL);
+
+  if (priv->popup_creation_in_progress)
+    return;
+
+  if (!gtk_window_is_active (GTK_WINDOW (priv->parent_window)))
+               return;
+
+  priv->popup_creation_in_progress = TRUE;
+
+  empathy_call_window_fullscreen_set_cursor_visible (self, TRUE);
+
+       /* Obtaining the screen rectangle */
+       screen = gtk_window_get_screen (GTK_WINDOW (priv->parent_window));
+       gdk_screen_get_monitor_geometry (screen,
+           gdk_screen_get_monitor_at_window (screen, GTK_WIDGET (priv->parent_window)->window),
+                           &fullscreen_rect);
+
+       /* Getting the popup window sizes */
+       gtk_window_get_size (GTK_WINDOW (priv->leave_fullscreen_popup),
+                            &leave_fullscreen_width, &leave_fullscreen_height);
+
+  /* Moving the popup to the top-left corner */
+  gtk_window_move (GTK_WINDOW (priv->leave_fullscreen_popup),
+      fullscreen_rect.width + fullscreen_rect.x - leave_fullscreen_width,
+      fullscreen_rect.y);
+
+  gtk_widget_show_all (priv->leave_fullscreen_popup);
+  empathy_call_window_fullscreen_add_popup_timeout (self);
+  
+  priv->popup_creation_in_progress = FALSE;
+}
+
+static gboolean
+empathy_call_window_fullscreen_hide_popup (EmpathyCallWindowFullscreen *fs)
+{
+  EmpathyCallWindowFullscreenPriv *priv = GET_PRIV (fs);
+
+  if (priv->video_widget == NULL || !fs->is_fullscreen)
+    return TRUE;
+
+  gtk_widget_hide (priv->leave_fullscreen_popup);
+  empathy_call_window_fullscreen_remove_popup_timeout (fs);
+
+  empathy_call_window_fullscreen_set_cursor_visible (fs, FALSE);
+
+  return FALSE;
+}
+
+static void
+empathy_call_window_fullscreen_init (EmpathyCallWindowFullscreen *self)
+{
+  EmpathyCallWindowFullscreenPriv *priv = GET_PRIV (self);
+  GtkBuilder *gui;
+  gchar *filename;
+
+  filename = empathy_file_lookup ("empathy-call-window-fullscreen.ui", "src");
+  gui = empathy_builder_get_file (filename,
+    "leave_fullscreen_window", &priv->leave_fullscreen_popup,
+    "leave_fullscreen_button", &self->leave_fullscreen_button,
+    NULL); 
+
+  gtk_widget_add_events (priv->leave_fullscreen_popup, GDK_POINTER_MOTION_MASK);
+
+  g_object_unref (gui);
+  g_free (filename);
+}
+
+static void
+empathy_call_window_fullscreen_class_init (
+  EmpathyCallWindowFullscreenClass *empathy_call_window_fullscreen_class)
+{
+  GObjectClass *object_class = G_OBJECT_CLASS (empathy_call_window_fullscreen_class);
+
+  g_type_class_add_private (empathy_call_window_fullscreen_class,
+    sizeof (EmpathyCallWindowFullscreenPriv));
+
+  object_class->dispose = empathy_call_window_fullscreen_dispose;
+  object_class->finalize = empathy_call_window_fullscreen_finalize;
+}
+
+void
+empathy_call_window_fullscreen_dispose (GObject *object)
+{
+  EmpathyCallWindowFullscreen *self = EMPATHY_CALL_WINDOW_FULLSCREEN (object);
+  EmpathyCallWindowFullscreenPriv *priv = GET_PRIV (self);
+
+  if (priv->dispose_has_run)
+    return;
+
+  if (priv->parent_window != NULL)
+    g_object_unref (priv->parent_window);
+  priv->parent_window = NULL;
+  
+  if (priv->leave_fullscreen_popup != NULL)
+    gtk_widget_destroy (priv->leave_fullscreen_popup);
+  priv->leave_fullscreen_popup = NULL;
+
+  if (self->leave_fullscreen_button != NULL)
+    gtk_widget_destroy (self->leave_fullscreen_button);
+  self->leave_fullscreen_button = NULL;
+
+  if (G_OBJECT_CLASS (empathy_call_window_fullscreen_parent_class)->dispose)
+    G_OBJECT_CLASS (empathy_call_window_fullscreen_parent_class)->dispose (object);
+
+  priv->dispose_has_run = TRUE;  
+}
+
+void
+empathy_call_window_fullscreen_finalize (GObject *object)
+{
+  EmpathyCallWindowFullscreen *self = EMPATHY_CALL_WINDOW_FULLSCREEN (object);
+  EmpathyCallWindowFullscreenPriv *priv = GET_PRIV (self);
+
+  empathy_call_window_fullscreen_remove_popup_timeout (self);
+
+  if (priv->motion_handler_id != 0)
+    {
+                 g_signal_handler_disconnect (G_OBJECT (priv->video_widget),
+                           priv->motion_handler_id);
+                 priv->motion_handler_id = 0;
+       }
+
+  G_OBJECT_CLASS (empathy_call_window_fullscreen_parent_class)->finalize (object);
+}
+
+static void
+empathy_call_window_fullscreen_parent_window_notify (GtkWidget *parent_window,
+    GParamSpec *property, EmpathyCallWindowFullscreen *fs)
+{
+  EmpathyCallWindowFullscreenPriv *priv = GET_PRIV (fs);
+
+       if (!fs->is_fullscreen)
+               return;
+
+       if (parent_window == GTK_WIDGET (priv->parent_window) &&
+             gtk_window_is_active (GTK_WINDOW (parent_window)) == FALSE)
+    {
+               empathy_call_window_fullscreen_hide_popup (fs);
+      empathy_call_window_fullscreen_set_cursor_visible (fs, TRUE);
+    }
+}
+
+EmpathyCallWindowFullscreen *
+empathy_call_window_fullscreen_new (EmpathyCallWindow *parent_window)
+{
+  EmpathyCallWindowFullscreen *self = EMPATHY_CALL_WINDOW_FULLSCREEN (
+    g_object_new (EMPATHY_TYPE_CALL_WINDOW_FULLSCREEN, NULL));
+  EmpathyCallWindowFullscreenPriv *priv = GET_PRIV (self);
+
+  priv->parent_window = parent_window;
+  g_signal_connect (G_OBJECT (priv->parent_window), "notify::is-active",
+                         G_CALLBACK (empathy_call_window_fullscreen_parent_window_notify), self);
+
+  return self;
+}
+
+void
+empathy_call_window_fullscreen_set_fullscreen (EmpathyCallWindowFullscreen *fs,
+  gboolean sidebar_was_visible,
+  gint original_width,
+  gint original_height)
+{
+  g_return_if_fail (!fs->is_fullscreen);
+
+  EmpathyCallWindowFullscreenPriv *priv = GET_PRIV (fs);
+  
+  empathy_call_window_fullscreen_remove_popup_timeout (fs);
+  empathy_call_window_fullscreen_set_cursor_visible (fs, FALSE);
+  
+  fs->sidebar_was_visible = sidebar_was_visible;
+  fs->original_width = original_width;
+  fs->original_height = original_height;
+
+  if (priv->motion_handler_id == 0 && priv->video_widget != NULL)
+    {
+           priv->motion_handler_id = g_signal_connect (G_OBJECT (priv->video_widget),
+        "motion-notify-event", G_CALLBACK (empathy_call_window_fullscreen_motion_notify),
+        fs);
+       }
+  
+  fs->is_fullscreen = TRUE;
+}
+
+void
+empathy_call_window_fullscreen_unset_fullscreen (EmpathyCallWindowFullscreen *fs)
+{
+  g_return_if_fail (fs->is_fullscreen);
+
+  EmpathyCallWindowFullscreenPriv *priv = GET_PRIV (fs);
+  empathy_call_window_fullscreen_hide_popup (fs);
+  empathy_call_window_fullscreen_set_cursor_visible (fs, TRUE);
+
+  if (priv->motion_handler_id != 0)
+    {
+                 g_signal_handler_disconnect (G_OBJECT (priv->video_widget),
+          priv->motion_handler_id);
+                 priv->motion_handler_id = 0;
+    }
+
+  fs->is_fullscreen = FALSE;
+}
+
+void
+empathy_call_window_fullscreen_set_video_widget (EmpathyCallWindowFullscreen *fs,
+    GtkWidget *video_widget)
+{
+  EmpathyCallWindowFullscreenPriv *priv = GET_PRIV (fs);
+
+  priv->video_widget = video_widget;
+       if (fs->is_fullscreen == TRUE && priv->motion_handler_id == 0) {
+                 priv->motion_handler_id = g_signal_connect (G_OBJECT (priv->video_widget),
+          "motion-notify-event", G_CALLBACK (empathy_call_window_fullscreen_motion_notify),
+          fs);
+       }
+}
+
+static gboolean
+empathy_call_window_fullscreen_motion_notify (GtkWidget *widget,
+    GdkEventMotion *event, EmpathyCallWindowFullscreen *self)
+{
+  empathy_call_window_fullscreen_show_popup (self);
+  return FALSE;
+}
\ No newline at end of file
diff --git a/src/empathy-call-window-fullscreen.h b/src/empathy-call-window-fullscreen.h
new file mode 100644 (file)
index 0000000..543f7ac
--- /dev/null
@@ -0,0 +1,82 @@
+/*
+ * empathy-call-window.c - Source for EmpathyCallWindow
+ * Copyright (C) 2009 Collabora Ltd.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ */
+
+#ifndef __EMPATHY_CALL_WINDOW_FULLSCREEN_H__
+#define __EMPATHY_CALL_WINDOW_FULLSCREEN_H__
+
+#include <glib-object.h>
+#include <gtk/gtk.h>
+
+#include "empathy-call-window.h"
+
+G_BEGIN_DECLS
+
+typedef struct _EmpathyCallWindowFullscreen EmpathyCallWindowFullscreen;
+typedef struct _EmpathyCallWindowFullscreenClass EmpathyCallWindowFullscreenClass;
+
+struct _EmpathyCallWindowFullscreenClass {
+  GtkWindowClass parent_class;
+};
+
+struct _EmpathyCallWindowFullscreen {
+  GtkWindow parent;
+  gboolean is_fullscreen;
+
+  GtkWidget *leave_fullscreen_button;
+
+  /* Those fields represent the state of the parent empathy_call_window before 
+     it actually was in fullscreen mode. */
+  gboolean sidebar_was_visible;
+  gint original_width;
+  gint original_height;
+};
+
+GType empathy_call_window_fullscreen_get_type(void);
+
+/* TYPE MACROS */
+#define EMPATHY_TYPE_CALL_WINDOW_FULLSCREEN \
+  (empathy_call_window_fullscreen_get_type())
+#define EMPATHY_CALL_WINDOW_FULLSCREEN(obj) \
+  (G_TYPE_CHECK_INSTANCE_CAST((obj), EMPATHY_TYPE_CALL_WINDOW_FULLSCREEN, \
+    EmpathyCallWindowFullscreen))
+#define EMPATHY_CALL_WINDOW_FULLSCREEN_CLASS(klass) \
+  (G_TYPE_CHECK_CLASS_CAST((klass), EMPATHY_TYPE_CALL_WINDOW_FULLSCREEN, \
+    EmpathyCallWindowClassFullscreen))
+#define EMPATHY_IS_CALL_WINDOW_FULLSCREEN(obj) \
+  (G_TYPE_CHECK_INSTANCE_TYPE((obj), EMPATHY_TYPE_CALL_WINDOW_FULLSCREEN))
+#define EMPATHY_IS_CALL_WINDOW_FULLSCREEN_CLASS(klass) \
+  (G_TYPE_CHECK_CLASS_TYPE((klass), EMPATHY_TYPE_CALL_WINDOW_FULLSCREEN))
+#define EMPATHY_CALL_WINDOW_FULLSCREEN_GET_CLASS(obj) \
+  (G_TYPE_INSTANCE_GET_CLASS ((obj), EMPATHY_TYPE_CALL_WINDOW_FULLSCREEN, \
+    EmpathyCallWindowFullscreenClass))
+
+EmpathyCallWindowFullscreen *
+empathy_call_window_fullscreen_new (EmpathyCallWindow *parent);
+
+void empathy_call_window_fullscreen_set_fullscreen (EmpathyCallWindowFullscreen *fs,
+    gboolean sidebar_was_visible,
+    gint original_width,
+    gint original_height);
+void empathy_call_window_fullscreen_unset_fullscreen (EmpathyCallWindowFullscreen *fs);
+void empathy_call_window_fullscreen_set_video_widget (EmpathyCallWindowFullscreen *fs,
+    GtkWidget *video_widget);
+
+G_END_DECLS
+
+#endif /* #ifndef __EMPATHY_CALL_WINDOW_FULLSCREEN_H__*/
\ No newline at end of file
diff --git a/src/empathy-call-window-fullscreen.ui b/src/empathy-call-window-fullscreen.ui
new file mode 100644 (file)
index 0000000..90ac333
--- /dev/null
@@ -0,0 +1,23 @@
+<?xml version="1.0"?>
+<interface>
+  <requires lib="gtk+" version="2.16"/>
+  <!-- interface-naming-policy toplevel-contextual -->
+  <object class="GtkWindow" id="leave_fullscreen_window">
+    <property name="type">popup</property>
+    <property name="resizable">False</property>
+    <property name="skip_taskbar_hint">True</property>
+    <property name="skip_pager_hint">True</property>
+    <property name="decorated">False</property>
+    <property name="deletable">False</property>
+    <signal name="motion_notify_event" handler="empathy_call_window_fullscreen_motion_notify_cb"/>
+    <child>
+      <object class="GtkButton" id="leave_fullscreen_button">
+        <property name="label" translatable="yes">gtk-fullscreen</property>
+        <property name="visible">True</property>
+        <property name="can_focus">True</property>
+        <property name="receives_default">True</property>
+        <property name="use_stock">True</property>
+      </object>
+    </child>
+  </object>
+</interface>
index 22a9eef44e1ee28b31f2021e8de286622fea202d..b05999d8c4cf8f1ec072a90c28657f5cd12c0e3a 100644 (file)
@@ -24,6 +24,7 @@
 
 #include <math.h>
 
+#include <gdk/gdkkeysyms.h>
 #include <gst/gst.h>
 #include <gtk/gtk.h>
 #include <glib/gi18n.h>
 
 #include "empathy-call-window.h"
 
+#include "empathy-call-window-fullscreen.h"
 #include "empathy-sidebar.h"
 
 #define BUTTON_ID "empathy-call-dtmf-button-id"
 
+#define CONTENT_HBOX_BORDER_WIDTH 6
+#define CONTENT_HBOX_SPACING 3
+#define CONTENT_HBOX_CHILDREN_PACKING_PADDING 3
+
 G_DEFINE_TYPE(EmpathyCallWindow, empathy_call_window, GTK_TYPE_WINDOW)
 
 /* signal enum */
@@ -83,6 +89,14 @@ struct _EmpathyCallWindowPriv
   GtkWidget *pane;
   GtkAction *send_video;
 
+  /* We keep a reference on the hbox which contains the main content so we can
+     easilly repack everything when toggling fullscreen */
+  GtkWidget *content_hbox;
+
+  /* This vbox is contained in the content_hbox. When toggling fullscreen,
+     it needs to be repacked. We keep a reference on it for easier access. */
+  GtkWidget *vbox;
+
   gdouble volume;
   GtkAdjustment *audio_input_adj;
 
@@ -109,6 +123,8 @@ struct _EmpathyCallWindowPriv
   GMutex *lock;
   gboolean call_started;
   gboolean sending_video;
+
+  EmpathyCallWindowFullscreen *fullscreen;
 };
 
 #define GET_PRIV(o) \
@@ -119,7 +135,10 @@ static void empathy_call_window_realized_cb (GtkWidget *widget,
   EmpathyCallWindow *window);
 
 static gboolean empathy_call_window_delete_cb (GtkWidget *widget,
-  GdkEvent*event, EmpathyCallWindow *window);
+  GdkEvent *event, EmpathyCallWindow *window);
+
+static gboolean empathy_call_window_state_event_cb (GtkWidget *widget,
+  GdkEventWindowState *event, EmpathyCallWindow *window);
 
 static void empathy_call_window_sidebar_toggled_cb (GtkToggleButton *toggle,
   EmpathyCallWindow *window);
@@ -139,9 +158,26 @@ static void empathy_call_window_mic_toggled_cb (
 static void empathy_call_window_sidebar_hidden_cb (EmpathySidebar *sidebar,
   EmpathyCallWindow *window);
 
+static void empathy_call_window_sidebar_shown_cb (EmpathySidebar *sidebar,
+  EmpathyCallWindow *window);
+
 static void empathy_call_window_hangup_cb (gpointer object,
   EmpathyCallWindow *window);
 
+static void empathy_call_window_fullscreen_cb (gpointer object,
+  EmpathyCallWindow *window);
+
+static void empathy_call_window_fullscreen_toggle (EmpathyCallWindow *window);
+
+static gboolean empathy_call_window_video_button_press_cb (GtkWidget *video_output,
+  GdkEventButton *event, EmpathyCallWindow *window);
+
+static gboolean empathy_call_window_key_press_cb (GtkWidget *video_output,
+  GdkEventKey *event, EmpathyCallWindow *window);
+
+static void empathy_call_window_video_menu_popup (EmpathyCallWindow *window,
+  guint button);
+
 static void empathy_call_window_status_message (EmpathyCallWindow *window,
   gchar *message);
 
@@ -459,8 +495,8 @@ empathy_call_window_init (EmpathyCallWindow *self)
 {
   EmpathyCallWindowPriv *priv = GET_PRIV (self);
   GtkBuilder *gui;
-  GtkWidget *vbox, *top_vbox;
-  GtkWidget *hbox, *h;
+  GtkWidget *top_vbox;
+  GtkWidget *h;
   GtkWidget *arrow;
   GtkWidget *page;
   GstBus *bus;
@@ -485,6 +521,7 @@ empathy_call_window_init (EmpathyCallWindow *self)
     "camera", "toggled", empathy_call_window_camera_toggled_cb,
     "send_video", "toggled", empathy_call_window_send_video_toggled_cb,
     "show_preview", "toggled", empathy_call_window_show_preview_toggled_cb,
+    "menufullscreen", "activate", empathy_call_window_fullscreen_cb,
     NULL);
 
   priv->lock = g_mutex_new ();
@@ -495,27 +532,34 @@ empathy_call_window_init (EmpathyCallWindow *self)
 
   priv->pipeline = gst_pipeline_new (NULL);
 
-  hbox = gtk_hbox_new (FALSE, 3);
-  gtk_container_set_border_width (GTK_CONTAINER (hbox), 6);
-  gtk_paned_pack1 (GTK_PANED (priv->pane), hbox, TRUE, FALSE);
+  priv->content_hbox = gtk_hbox_new (FALSE, CONTENT_HBOX_SPACING);
+  gtk_container_set_border_width (GTK_CONTAINER (priv->content_hbox), 
+                                  CONTENT_HBOX_BORDER_WIDTH);
+  gtk_paned_pack1 (GTK_PANED (priv->pane), priv->content_hbox, TRUE, FALSE);
 
   bus = gst_pipeline_get_bus (GST_PIPELINE (priv->pipeline));
 
   gst_bus_add_watch (bus, empathy_call_window_bus_message, self);
 
   priv->video_output = empathy_video_widget_new (bus);
-  gtk_box_pack_start (GTK_BOX (hbox), priv->video_output, TRUE, TRUE, 3);
+  gtk_box_pack_start (GTK_BOX (priv->content_hbox), priv->video_output,
+                      TRUE, TRUE, CONTENT_HBOX_CHILDREN_PACKING_PADDING);
+  gtk_widget_add_events (priv->video_output,
+      GDK_BUTTON_PRESS_MASK | GDK_POINTER_MOTION_MASK);
+  g_signal_connect (G_OBJECT (priv->video_output), "button-press-event",
+      G_CALLBACK (empathy_call_window_video_button_press_cb), self);
 
   priv->video_tee = gst_element_factory_make ("tee", NULL);
   gst_object_ref (priv->video_tee);
   gst_object_sink (priv->video_tee);
 
-  vbox = gtk_vbox_new (FALSE, 3);
-  gtk_box_pack_start (GTK_BOX (hbox), vbox, FALSE, FALSE, 3);
+  priv->vbox = gtk_vbox_new (FALSE, 3);
+  gtk_box_pack_start (GTK_BOX (priv->content_hbox), priv->vbox,
+                      FALSE, FALSE, CONTENT_HBOX_CHILDREN_PACKING_PADDING);
 
   priv->video_preview = empathy_video_widget_new_with_size (bus, 160, 120);
   g_object_set (priv->video_preview, "sync", FALSE, "async", TRUE, NULL);
-  gtk_box_pack_start (GTK_BOX (vbox), priv->video_preview, FALSE, FALSE, 0);
+  gtk_box_pack_start (GTK_BOX (priv->vbox), priv->video_preview, FALSE, FALSE, 0);
 
   priv->video_input = empathy_video_src_new ();
   gst_object_ref (priv->video_input);
@@ -539,13 +583,14 @@ empathy_call_window_init (EmpathyCallWindow *self)
   gtk_button_set_image (GTK_BUTTON (priv->sidebar_button), arrow);
 
   h = gtk_hbox_new (FALSE, 3);
-  gtk_box_pack_end (GTK_BOX (vbox), h, FALSE, FALSE, 3);
+  gtk_box_pack_end (GTK_BOX (priv->vbox), h, FALSE, FALSE, 3);
   gtk_box_pack_end (GTK_BOX (h), priv->sidebar_button, FALSE, FALSE, 3);
 
   priv->sidebar = empathy_sidebar_new ();
   g_signal_connect (G_OBJECT (priv->sidebar),
-    "hide", G_CALLBACK (empathy_call_window_sidebar_hidden_cb),
-    self);
+    "hide", G_CALLBACK (empathy_call_window_sidebar_hidden_cb), self);
+  g_signal_connect (G_OBJECT (priv->sidebar),
+    "show", G_CALLBACK (empathy_call_window_sidebar_shown_cb), self);
   gtk_paned_pack2 (GTK_PANED (priv->pane), priv->sidebar, FALSE, FALSE);
 
   priv->dtmf_panel = empathy_call_window_create_dtmf (self);
@@ -566,18 +611,30 @@ empathy_call_window_init (EmpathyCallWindow *self)
 
   gtk_widget_hide (priv->sidebar);
 
+  priv->fullscreen = empathy_call_window_fullscreen_new (self);
+  empathy_call_window_fullscreen_set_video_widget (priv->fullscreen, priv->video_output);
+  g_signal_connect (G_OBJECT (priv->fullscreen->leave_fullscreen_button),
+      "clicked", G_CALLBACK (empathy_call_window_fullscreen_cb), self);
+
   g_signal_connect (G_OBJECT (self), "realize",
     G_CALLBACK (empathy_call_window_realized_cb), self);
 
   g_signal_connect (G_OBJECT (self), "delete-event",
     G_CALLBACK (empathy_call_window_delete_cb), self);
 
+  g_signal_connect (G_OBJECT (self), "window-state-event",
+    G_CALLBACK (empathy_call_window_state_event_cb), self);
+
+  g_signal_connect (G_OBJECT (self), "key-press-event",
+      G_CALLBACK (empathy_call_window_key_press_cb), self);
+
   empathy_call_window_status_message (self, _("Connecting..."));
 
   priv->timer = g_timer_new ();
 
   g_object_ref (priv->ui_manager);
   g_object_unref (gui);
+  g_free (filename);
 }
 
 static void
@@ -1165,6 +1222,91 @@ empathy_call_window_delete_cb (GtkWidget *widget, GdkEvent*event,
   return FALSE;
 }
 
+static void
+show_controls (EmpathyCallWindow *window, gboolean set_fullscreen)
+{
+  GtkWidget *menu;
+  EmpathyCallWindowPriv *priv = GET_PRIV (window);
+
+  menu = gtk_ui_manager_get_widget (priv->ui_manager,
+            "/menubar1");
+
+  if (set_fullscreen)
+    {
+      gtk_widget_hide (priv->sidebar);
+      gtk_widget_hide (menu);
+      gtk_widget_hide (priv->vbox);
+      gtk_widget_hide (priv->statusbar);
+      gtk_widget_hide (priv->toolbar);
+    }
+  else
+    {
+      if (priv->fullscreen->sidebar_was_visible)
+        gtk_widget_show (priv->sidebar);
+
+      gtk_widget_show (menu);
+      gtk_widget_show (priv->vbox);
+      gtk_widget_show (priv->statusbar);
+      gtk_widget_show (priv->toolbar);
+
+      gtk_window_resize (GTK_WINDOW (window),
+                         priv->fullscreen->original_width,
+                         priv->fullscreen->original_height);
+    }  
+}
+
+static void
+show_borders (EmpathyCallWindow *window, gboolean set_fullscreen)
+{
+  EmpathyCallWindowPriv *priv = GET_PRIV (window);
+
+  gtk_container_set_border_width (GTK_CONTAINER (priv->content_hbox),
+      set_fullscreen ? 0 : CONTENT_HBOX_BORDER_WIDTH);
+  gtk_box_set_spacing (GTK_BOX (priv->content_hbox),
+      set_fullscreen ? 0 : CONTENT_HBOX_SPACING);
+  gtk_box_set_child_packing (GTK_BOX (priv->content_hbox),
+      priv->video_output, TRUE, TRUE,
+      set_fullscreen ? 0 : CONTENT_HBOX_CHILDREN_PACKING_PADDING,
+      GTK_PACK_START);
+  gtk_box_set_child_packing (GTK_BOX (priv->content_hbox),
+      priv->vbox, TRUE, TRUE,
+      set_fullscreen ? 0 : CONTENT_HBOX_CHILDREN_PACKING_PADDING,
+      GTK_PACK_START);   
+}
+
+static gboolean
+empathy_call_window_state_event_cb (GtkWidget *widget,
+  GdkEventWindowState *event, EmpathyCallWindow *window)
+{
+  if (event->changed_mask & GDK_WINDOW_STATE_FULLSCREEN)
+    {
+      EmpathyCallWindowPriv *priv = GET_PRIV (window);
+      gboolean set_fullscreen = event->new_window_state & GDK_WINDOW_STATE_FULLSCREEN;
+
+      if (set_fullscreen)
+        {
+          gboolean sidebar_was_visible;
+          gint original_width = GTK_WIDGET (window)->allocation.width;
+          gint original_height = GTK_WIDGET (window)->allocation.height;
+
+          g_object_get (priv->sidebar, "visible",
+                    &sidebar_was_visible, NULL);
+
+          empathy_call_window_fullscreen_set_fullscreen (priv->fullscreen, 
+              sidebar_was_visible, original_width, original_height);
+        }
+      else
+        {
+          empathy_call_window_fullscreen_unset_fullscreen(priv->fullscreen);
+        }
+
+      show_controls (window, set_fullscreen);
+      show_borders (window, set_fullscreen);
+  }
+
+  return FALSE;
+}
+
 static void
 empathy_call_window_sidebar_toggled_cb (GtkToggleButton *toggle,
   EmpathyCallWindow *window)
@@ -1289,6 +1431,16 @@ empathy_call_window_sidebar_hidden_cb (EmpathySidebar *sidebar,
     FALSE);
 }
 
+static void
+empathy_call_window_sidebar_shown_cb (EmpathySidebar *sidebar,
+  EmpathyCallWindow *window)
+{
+  EmpathyCallWindowPriv *priv = GET_PRIV (window);
+
+  gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (priv->sidebar_button),
+    TRUE);
+}
+
 static void
 empathy_call_window_hangup_cb (gpointer object,
                                EmpathyCallWindow *window)
@@ -1299,6 +1451,68 @@ empathy_call_window_hangup_cb (gpointer object,
   gtk_widget_destroy (GTK_WIDGET (window));
 }
 
+static void
+empathy_call_window_fullscreen_cb (gpointer object,
+                                   EmpathyCallWindow *window)
+{
+  empathy_call_window_fullscreen_toggle (window);
+}
+
+static void
+empathy_call_window_fullscreen_toggle (EmpathyCallWindow *window)
+{
+  EmpathyCallWindowPriv *priv = GET_PRIV (window);
+
+  if (priv->fullscreen->is_fullscreen)
+    gtk_window_unfullscreen (GTK_WINDOW (window));
+  else
+    gtk_window_fullscreen (GTK_WINDOW (window));
+}
+
+static gboolean
+empathy_call_window_video_button_press_cb (GtkWidget *video_output,
+  GdkEventButton *event, EmpathyCallWindow *window)
+{
+  if (event->button == 3 && event->type == GDK_BUTTON_PRESS)
+    {
+      empathy_call_window_video_menu_popup (window, event->button);
+      return TRUE;
+    }
+
+  return FALSE;
+}
+
+static gboolean
+empathy_call_window_key_press_cb (GtkWidget *video_output,
+  GdkEventKey *event, EmpathyCallWindow *window)
+{
+  EmpathyCallWindowPriv *priv = GET_PRIV (window);
+  
+  if (priv->fullscreen->is_fullscreen && event->keyval == GDK_Escape)
+    {
+      /* Since we are in fullscreen mode, toggling will bring us back to
+         normal mode. */
+      empathy_call_window_fullscreen_toggle (window);
+      return TRUE;
+    }
+
+  return FALSE;
+}
+
+static void
+empathy_call_window_video_menu_popup (EmpathyCallWindow *window,
+  guint button)
+{
+  GtkWidget *menu;
+  EmpathyCallWindowPriv *priv = GET_PRIV (window);
+
+  menu = gtk_ui_manager_get_widget (priv->ui_manager,
+            "/video-popup");
+  gtk_menu_popup (GTK_MENU (menu), NULL, NULL, NULL, NULL,
+                       button, gtk_get_current_event_time ());
+       gtk_menu_shell_select_first (GTK_MENU_SHELL (menu), FALSE);
+}
+
 static void
 empathy_call_window_status_message (EmpathyCallWindow *window,
   gchar *message)
index ce3d85b56e11e1b0d264f2d7b9907948097c67e1..33a71eef624d59741d1a7fa40a9d17836c11f7ab 100644 (file)
             <property name="label" translatable="yes">Video preview</property>
           </object>
         </child>
+        <child>
+          <object class="GtkAction" id="menufullscreen">
+            <property name="stock_id">gtk-fullscreen</property>
+            <property name="name">menufullscreen</property>
+            <property name="label" translatable="yes">Fullscreen</property>
+          </object>
+          <accelerator key="F11"/>
+        </child>
       </object>
     </child>
     <ui>
         </menu>
         <menu action="view">
           <menuitem action="show_preview"/>
+          <menuitem action="menufullscreen"/>
         </menu>
       </menubar>
+      <popup name="video-popup">
+          <menuitem name="menufullscreen" action="menufullscreen"/>
+      </popup>
     </ui>
   </object>
       <object class="GtkVBox" id="call_window_vbox">