~walkerlee/totem/pre-interview

« back to all changes in this revision

Viewing changes to debian/patches/02_revert_clutter.patch

  • Committer: Package Import Robot
  • Author(s): Jeremy Bicha
  • Date: 2013-05-26 00:07:51 UTC
  • mfrom: (1.6.1) (24.1.4 experimental)
  • Revision ID: package-import@ubuntu.com-20130526000751-kv8ap3x1di4qq8j2
Tags: 3.8.2-0ubuntu1
* Sync with Debian. Remaining changes: 
* debian/control.in:
  - Drop build-depends on libepc-ui-dev and libgrilo-0.2-dev (in universe)
  - Drop libxtst-dev build-depends so that the (redundant) fake key presses
    for inhibiting the screensaver are disabled (LP: #1007438)
  - Build-depend on libzeitgeist-dev
  - Suggest rather than recommend gstreamer components in universe
  - Add totem-plugins-extra
  - Add XB-Npp-Description and XB-Npp-Filename header to the 
    totem-mozilla package to improve ubufox/ubuntu plugin db integration 
  - Refer to Firefox in totem-mozilla description instead of Iceweasel
  - Don't have totem-mozilla recommend any particular browser
  - Drop obsolete python library dependencies since iplayer is no longer
    included
* debian/totem-common.install, debian/source_totem.py:
  - Install Ubuntu apport debugging hook
* debian/totem-plugins-extra.install:
  - Universe plugins split out of totem-plugins (currently only gromit)
* debian/totem-plugins.install:    
  - Skip the plugins split to -extra and add the zeitgeist plugin
* debian/rules:
  - Build with --fail-missing, to ensure we install everything. 
    + Ignore libtotem.{,l}a since we delibrately don't install these.
  - Re-enable hardening, make sure both PIE and BINDNOW are used
    by setting hardening=+all. (LP: #1039604)
* debian/patches/91_quicklist_entries.patch:
  - Add static quicklist
* debian/patches/92_gst-plugins-good.patch:
  - Build without unnecessary gstreamer1.0-bad dependency
* debian/patches/93_grilo_optional.patch:
  - Allow building without grilo while grilo MIR is still pending
* debian/patches/correct_desktop_mimetypes.patch:
  - Don't list the mimetypes after the unity lists
* debian/patches/revert_shell_menu.patch: 
  - revert the use of a shell menu until indicator-appmenu can handle
    the mixed shell/traditional menus itself
* New upstream release

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
Reverts upstream commits:
2
 
 cb53bbda 2011-04-04 13:00:50 backend: Use clutter-gst to draw video
3
 
 f782e2e1 2011-04-04 16:14:28 backend: Use copy/pasted version of MxAspectFrame
4
 
 7e74539e 2011-04-05 18:28:13 backend: Remove some dead code
5
 
 f9e8196b 2011-04-05 18:42:41 build: Update clutter-gst dependency
6
 
 45cfd99b 2011-04-06 22:05:25 build: Bump clutter-gst reqs
7
 
 65f5b9e1 2011-04-07 18:40:19 backend: Add FIXME about motion events
8
 
 aa649822 2011-04-08 16:06:04 backend: Remove bacon_video_widget_init_backend()
9
 
 67ab568f 2011-07-13 12:03:35 backend: name clutter actors so that plugins can query them
10
 
 0a684af8 2011-08-03 13:00:41 plugins: add rotation plugin
11
 
 
12
 
Index: totem-3.2.1/src/backend/bacon-video-widget-gst-0.10.c
13
 
===================================================================
14
 
--- totem-3.2.1.orig/src/backend/bacon-video-widget-gst-0.10.c  2011-12-17 00:28:45.340452915 +0100
15
 
+++ totem-3.2.1/src/backend/bacon-video-widget-gst-0.10.c       2011-12-17 00:57:33.420901072 +0100
16
 
@@ -46,6 +46,7 @@
17
 
 #include <gst/gst.h>
18
 
 
19
 
 /* GStreamer Interfaces */
20
 
+#include <gst/interfaces/xoverlay.h>
21
 
 #include <gst/interfaces/navigation.h>
22
 
 #include <gst/interfaces/colorbalance.h>
23
 
 /* for detecting sources of errors */
24
 
@@ -63,10 +64,6 @@
25
 
 /* for the cover metadata info */
26
 
 #include <gst/tag/tag.h>
27
 
 
28
 
-#include <clutter-gst/clutter-gst.h>
29
 
-#include <mx/mx.h>
30
 
-#include "totem-aspect-frame.h"
31
 
-
32
 
 /* system */
33
 
 #include <unistd.h>
34
 
 #include <time.h>
35
 
@@ -91,6 +88,8 @@
36
 
 
37
 
 #define FORWARD_RATE 1.0
38
 
 #define REVERSE_RATE -1.0
39
 
+#define SMALL_STREAM_WIDTH 200
40
 
+#define SMALL_STREAM_HEIGHT 120
41
 
 /* Maximum size of the logo */
42
 
 #define LOGO_SIZE 256
43
 
 #define NANOSECS_IN_SEC 1000000000
44
 
@@ -102,7 +101,7 @@
45
 
 
46
 
 #define I_(string) (g_intern_static_string (string))
47
 
 
48
 
-G_DEFINE_TYPE (BaconVideoWidget, bacon_video_widget, GTK_CLUTTER_TYPE_EMBED)
49
 
+G_DEFINE_TYPE (BaconVideoWidget, bacon_video_widget, GTK_TYPE_EVENT_BOX)
50
 
 
51
 
 /* Signals */
52
 
 enum
53
 
@@ -163,8 +162,11 @@ struct BaconVideoWidgetPrivate
54
 
 
55
 
   GstElement                  *play;
56
 
   GstElement                  *source;
57
 
-  GstColorBalance             *balance;
58
 
-  GstNavigation               *navigation;
59
 
+  GstXOverlay                 *xoverlay;      /* protect with lock */
60
 
+  GstColorBalance             *balance;       /* protect with lock */
61
 
+  GstNavigation               *navigation;    /* protect with lock */
62
 
+  guint                        interface_update_id;  /* protect with lock */
63
 
+  GMutex                      *lock;
64
 
 
65
 
   guint                        update_id;
66
 
   guint                        fill_id;
67
 
@@ -190,13 +192,7 @@ struct BaconVideoWidgetPrivate
68
 
 
69
 
   gboolean                     got_redirect;
70
 
 
71
 
-  ClutterActor                *stage;
72
 
-  ClutterActor                *texture;
73
 
-  ClutterActor                *frame;
74
 
-
75
 
-  ClutterActor                *logo_frame;
76
 
-  ClutterActor                *logo;
77
 
-
78
 
+  GdkWindow                   *video_window;
79
 
   GdkCursor                   *cursor;
80
 
 
81
 
   /* Visual effects */
82
 
@@ -227,12 +223,15 @@ struct BaconVideoWidgetPrivate
83
 
   gint                         video_fps_n;
84
 
   gint                         video_fps_d;
85
 
 
86
 
+  gdouble                      zoom;
87
 
+  
88
 
   gchar                       *media_device;
89
 
 
90
 
   BvwAudioOutputType           speakersetup;
91
 
   gint                         connection_speed;
92
 
 
93
 
   GstBus                      *bus;
94
 
+  gulong                       sig_bus_sync;
95
 
   gulong                       sig_bus_async;
96
 
 
97
 
   gint                         eos_id;
98
 
@@ -282,8 +281,11 @@ static void bacon_video_widget_get_prope
99
 
 
100
 
 static void bacon_video_widget_finalize (GObject * object);
101
 
 
102
 
+static void bvw_update_interface_implementations (BaconVideoWidget *bvw);
103
 
 static void setup_vis (BaconVideoWidget * bvw);
104
 
 static GList * get_visualization_features (void);
105
 
+static gboolean bacon_video_widget_configure_event (GtkWidget *widget,
106
 
+    GdkEventConfigure *event, BaconVideoWidget *bvw);
107
 
 static void size_changed_cb (GdkScreen *screen, BaconVideoWidget *bvw);
108
 
 static void bvw_stop_play_pipeline (BaconVideoWidget * bvw);
109
 
 static GError* bvw_error_from_gst_error (BaconVideoWidget *bvw, GstMessage *m);
110
 
@@ -306,6 +308,8 @@ static GtkWidgetClass *parent_class = NU
111
 
 
112
 
 static int bvw_signals[LAST_SIGNAL] = { 0 };
113
 
 
114
 
+static GThread *gui_thread;
115
 
+
116
 
 GST_DEBUG_CATEGORY (_totem_gst_debug_cat);
117
 
 #define GST_CAT_DEFAULT _totem_gst_debug_cat
118
 
 
119
 
@@ -395,50 +399,6 @@ bvw_check_if_video_decoder_is_missing (B
120
 
 }
121
 
 
122
 
 static void
123
 
-set_display_pixel_aspect_ratio (GdkScreen *screen,
124
 
-                               GValue    *value)
125
 
-{
126
 
-  static const gint par[][2] = {
127
 
-    {1, 1},                     /* regular screen */
128
 
-    {16, 15},                   /* PAL TV */
129
 
-    {11, 10},                   /* 525 line Rec.601 video */
130
 
-    {54, 59},                   /* 625 line Rec.601 video */
131
 
-    {64, 45},                   /* 1280x1024 on 16:9 display */
132
 
-    {5, 3},                     /* 1280x1024 on 4:3 display */
133
 
-    {4, 3}                      /*  800x600 on 16:9 display */
134
 
-  };
135
 
-  guint i;
136
 
-  gint par_index;
137
 
-  gdouble ratio;
138
 
-  gdouble delta;
139
 
-
140
 
-#define DELTA(idx) (ABS (ratio - ((gdouble) par[idx][0] / par[idx][1])))
141
 
-
142
 
-  /* first calculate the "real" ratio based on the X values;
143
 
-   *    * which is the "physical" w/h divided by the w/h in pixels of the display */
144
 
-  ratio = (gdouble) (gdk_screen_get_width_mm (screen) * gdk_screen_get_height (screen))
145
 
-    / (gdk_screen_get_height_mm (screen) * gdk_screen_get_width (screen));
146
 
-
147
 
-  GST_DEBUG ("calculated pixel aspect ratio: %f", ratio);
148
 
-  /* now find the one from par[][2] with the lowest delta to the real one */
149
 
-  delta = DELTA (0);
150
 
-  par_index = 0;
151
 
-
152
 
-  for (i = 1; i < sizeof (par) / (sizeof (gint) * 2); ++i) {
153
 
-    gdouble this_delta = DELTA (i);
154
 
-
155
 
-    if (this_delta < delta) {
156
 
-      par_index = i;
157
 
-      delta = this_delta;
158
 
-    }
159
 
-  }
160
 
-
161
 
-  GST_DEBUG ("Decided on index %d (%d/%d)", par_index,
162
 
-            par[par_index][0], par[par_index][1]);
163
 
-  gst_value_set_fraction (value, par[par_index][0], par[par_index][1]);
164
 
-}
165
 
-
166
 
-static void
167
 
 get_media_size (BaconVideoWidget *bvw, gint *width, gint *height)
168
 
 {
169
 
   if (bvw->priv->logo_mode) {
170
 
@@ -461,22 +421,42 @@ get_media_size (BaconVideoWidget *bvw, g
171
 
     if (bvw->priv->media_has_video) {
172
 
       GValue disp_par = {0, };
173
 
       guint movie_par_n, movie_par_d, disp_par_n, disp_par_d, num, den;
174
 
-
175
 
+      
176
 
       /* Create and init the fraction value */
177
 
       g_value_init (&disp_par, GST_TYPE_FRACTION);
178
 
 
179
 
       /* Square pixel is our default */
180
 
       gst_value_set_fraction (&disp_par, 1, 1);
181
 
-
182
 
+    
183
 
       /* Now try getting display's pixel aspect ratio */
184
 
-      if (gtk_widget_get_realized (GTK_WIDGET (bvw)))
185
 
-       set_display_pixel_aspect_ratio (gtk_widget_get_screen (GTK_WIDGET (bvw)), &disp_par);
186
 
+      if (bvw->priv->xoverlay) {
187
 
+        GObjectClass *klass;
188
 
+        GParamSpec *pspec;
189
 
+
190
 
+        klass = G_OBJECT_GET_CLASS (bvw->priv->xoverlay);
191
 
+        pspec = g_object_class_find_property (klass, "pixel-aspect-ratio");
192
 
+      
193
 
+        if (pspec != NULL) {
194
 
+          GValue disp_par_prop = { 0, };
195
 
 
196
 
+          g_value_init (&disp_par_prop, pspec->value_type);
197
 
+          g_object_get_property (G_OBJECT (bvw->priv->xoverlay),
198
 
+              "pixel-aspect-ratio", &disp_par_prop);
199
 
+
200
 
+          if (!g_value_transform (&disp_par_prop, &disp_par)) {
201
 
+            GST_WARNING ("Transform failed, assuming pixel-aspect-ratio = 1/1");
202
 
+            gst_value_set_fraction (&disp_par, 1, 1);
203
 
+          }
204
 
+        
205
 
+          g_value_unset (&disp_par_prop);
206
 
+        }
207
 
+      }
208
 
+      
209
 
       disp_par_n = gst_value_get_fraction_numerator (&disp_par);
210
 
       disp_par_d = gst_value_get_fraction_denominator (&disp_par);
211
 
-
212
 
+      
213
 
       GST_DEBUG ("display PAR is %d/%d", disp_par_n, disp_par_d);
214
 
-
215
 
+      
216
 
       /* If movie pixel aspect ratio is enforced, use that */
217
 
       if (bvw->priv->ratio_type != BVW_RATIO_AUTO) {
218
 
         switch (bvw->priv->ratio_type) {
219
 
@@ -503,12 +483,13 @@ get_media_size (BaconVideoWidget *bvw, g
220
 
             movie_par_d = 0;
221
 
             g_assert_not_reached ();
222
 
         }
223
 
-      } else {
224
 
+      }
225
 
+      else {
226
 
         /* Use the movie pixel aspect ratio if any */
227
 
         movie_par_n = bvw->priv->movie_par_n;
228
 
         movie_par_d = bvw->priv->movie_par_d;
229
 
       }
230
 
-
231
 
+      
232
 
       GST_DEBUG ("movie PAR is %d/%d", movie_par_n, movie_par_d);
233
 
 
234
 
       if (bvw->priv->video_width == 0 || bvw->priv->video_height == 0) {
235
 
@@ -568,39 +549,150 @@ static void
236
 
 bacon_video_widget_realize (GtkWidget * widget)
237
 
 {
238
 
   BaconVideoWidget *bvw = BACON_VIDEO_WIDGET (widget);
239
 
+  GdkWindowAttr attributes;
240
 
+  gint attributes_mask;
241
 
+  GdkColor black = { 0, 0, 0 };
242
 
+  GdkWindow *window;
243
 
+  GdkEventMask event_mask;
244
 
+  GtkAllocation allocation;
245
 
   GtkWidget *toplevel;
246
 
 
247
 
+  event_mask = gtk_widget_get_events (widget)
248
 
+    | GDK_POINTER_MOTION_MASK
249
 
+    | GDK_KEY_PRESS_MASK;
250
 
+  gtk_widget_set_events (widget, event_mask);
251
 
+
252
 
   GTK_WIDGET_CLASS (parent_class)->realize (widget);
253
 
 
254
 
+  window = gtk_widget_get_window (widget);
255
 
+  gdk_window_ensure_native (window);
256
 
+
257
 
+  /* Creating our video window */
258
 
+  attributes.window_type = GDK_WINDOW_CHILD;
259
 
+  attributes.x = 0;
260
 
+  attributes.y = 0;
261
 
+  gtk_widget_get_allocation (widget, &allocation);
262
 
+  attributes.visual = gdk_screen_get_system_visual (gtk_widget_get_screen (widget));
263
 
+  attributes.width = allocation.width;
264
 
+  attributes.height = allocation.height;
265
 
+  attributes.wclass = GDK_INPUT_OUTPUT;
266
 
+  attributes.event_mask = gtk_widget_get_events (widget);
267
 
+  attributes.event_mask |= GDK_EXPOSURE_MASK |
268
 
+                           GDK_POINTER_MOTION_MASK |
269
 
+                           GDK_BUTTON_PRESS_MASK |
270
 
+                           GDK_KEY_PRESS_MASK;
271
 
+  attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL;
272
 
+
273
 
+  bvw->priv->video_window = gdk_window_new (window,
274
 
+      &attributes, attributes_mask);
275
 
+  gdk_window_ensure_native (bvw->priv->video_window);
276
 
+  gdk_window_set_user_data (bvw->priv->video_window, widget);
277
 
+  gdk_window_set_background (window, &black);
278
 
+
279
 
+  gdk_window_set_background (window, &black);
280
 
+
281
 
   gtk_widget_set_realized (widget, TRUE);
282
 
 
283
 
+  /* Connect to configure event on the top level window */
284
 
+  g_signal_connect (G_OBJECT (gtk_widget_get_toplevel (widget)),
285
 
+      "configure-event", G_CALLBACK (bacon_video_widget_configure_event), bvw);
286
 
+
287
 
   /* get screen size changes */
288
 
   g_signal_connect (G_OBJECT (gtk_widget_get_screen (widget)),
289
 
-                   "size-changed", G_CALLBACK (size_changed_cb), bvw);
290
 
+      "size-changed", G_CALLBACK (size_changed_cb), bvw);
291
 
 
292
 
   /* setup the toplevel, ready to be resized */
293
 
   toplevel = gtk_widget_get_toplevel (widget);
294
 
-  if (gtk_widget_is_toplevel (toplevel) &&
295
 
-      gtk_widget_get_parent (widget) != toplevel)
296
 
+  if (gtk_widget_is_toplevel (toplevel))
297
 
     gtk_window_set_geometry_hints (GTK_WINDOW (toplevel), widget, NULL, 0);
298
 
 
299
 
   bacon_video_widget_gst_missing_plugins_setup (bvw);
300
 
 }
301
 
 
302
 
 static void
303
 
+bacon_video_widget_show (GtkWidget *widget)
304
 
+{
305
 
+  BaconVideoWidget *bvw = BACON_VIDEO_WIDGET (widget);
306
 
+  GdkWindow *window;
307
 
+
308
 
+  window = gtk_widget_get_window (widget);
309
 
+  if (window)
310
 
+    gdk_window_show (window);
311
 
+  if (bvw->priv->video_window)
312
 
+    gdk_window_show (bvw->priv->video_window);
313
 
+
314
 
+  if (GTK_WIDGET_CLASS (parent_class)->show)
315
 
+    GTK_WIDGET_CLASS (parent_class)->show (widget);
316
 
+}
317
 
+
318
 
+static void
319
 
+bacon_video_widget_hide (GtkWidget *widget)
320
 
+{
321
 
+  BaconVideoWidget *bvw = BACON_VIDEO_WIDGET (widget);
322
 
+  GdkWindow *window;
323
 
+
324
 
+  window = gtk_widget_get_window (widget);
325
 
+  if (window)
326
 
+    gdk_window_hide (window);
327
 
+  if (bvw->priv->video_window)
328
 
+    gdk_window_hide (bvw->priv->video_window);
329
 
+
330
 
+  if (GTK_WIDGET_CLASS (parent_class)->hide)
331
 
+    GTK_WIDGET_CLASS (parent_class)->hide (widget);
332
 
+}
333
 
+
334
 
+static gboolean
335
 
+bacon_video_widget_configure_event (GtkWidget *widget, GdkEventConfigure *event,
336
 
+    BaconVideoWidget *bvw)
337
 
+{
338
 
+  GstXOverlay *xoverlay = NULL;
339
 
+  
340
 
+  g_return_val_if_fail (bvw != NULL, FALSE);
341
 
+  g_return_val_if_fail (BACON_IS_VIDEO_WIDGET (bvw), FALSE);
342
 
+  
343
 
+  xoverlay = bvw->priv->xoverlay;
344
 
+  
345
 
+  if (xoverlay != NULL && GST_IS_X_OVERLAY (xoverlay)) {
346
 
+    gst_x_overlay_expose (xoverlay);
347
 
+  }
348
 
+  
349
 
+  return FALSE;
350
 
+}
351
 
+
352
 
+static void
353
 
 size_changed_cb (GdkScreen *screen, BaconVideoWidget *bvw)
354
 
 {
355
 
   /* FIXME */
356
 
   setup_vis (bvw);
357
 
 }
358
 
 
359
 
-static void
360
 
-set_current_actor (BaconVideoWidget *bvw)
361
 
+static gboolean
362
 
+bacon_video_widget_draw (GtkWidget *widget, cairo_t *cr)
363
 
 {
364
 
+  BaconVideoWidget *bvw = BACON_VIDEO_WIDGET (widget);
365
 
+  GstXOverlay *xoverlay;
366
 
   gboolean draw_logo;
367
 
+  XID window;
368
 
+  GtkAllocation allocation;
369
 
 
370
 
-  if (bvw->priv->stage == NULL)
371
 
-    return;
372
 
+  g_mutex_lock (bvw->priv->lock);
373
 
+  xoverlay = bvw->priv->xoverlay;
374
 
+  if (xoverlay == NULL) {
375
 
+    bvw_update_interface_implementations (bvw);
376
 
+    xoverlay = bvw->priv->xoverlay;
377
 
+  }
378
 
+  if (xoverlay != NULL)
379
 
+    gst_object_ref (xoverlay);
380
 
+
381
 
+  g_mutex_unlock (bvw->priv->lock);
382
 
+
383
 
+  window = gdk_x11_window_get_xid (bvw->priv->video_window);
384
 
+
385
 
+  if (xoverlay != NULL && GST_IS_X_OVERLAY (xoverlay))
386
 
+    gst_x_overlay_set_xwindow_id (xoverlay, window);
387
 
+
388
 
+  /* Start with a nice black canvas */
389
 
+  gtk_widget_get_allocation (widget, &allocation);
390
 
 
391
 
   /* If there's only audio and no visualisation, draw the logo as well.
392
 
    * If we have a cover image to display, we display it regardless of whether we're
393
 
@@ -613,32 +705,76 @@ set_current_actor (BaconVideoWidget *bvw
394
 
 
395
 
     pixbuf = bvw_get_logo_pixbuf (bvw);
396
 
     if (pixbuf != NULL) {
397
 
-      gboolean ret;
398
 
-      GError *err = NULL;
399
 
+      /* draw logo here */
400
 
+      gint s_width, s_height, d_width, d_height;
401
 
+      gfloat ratio;
402
 
+
403
 
+      s_width = gdk_pixbuf_get_width (pixbuf);
404
 
+      s_height = gdk_pixbuf_get_height (pixbuf);
405
 
+      d_width = allocation.width;
406
 
+      d_height = allocation.height;
407
 
+
408
 
+      /* Limit the width/height to 256×256 pixels, but only if we're displaying the logo proper */
409
 
+      if (!bvw->priv->cover_pixbuf && d_width > LOGO_SIZE && d_height > LOGO_SIZE)
410
 
+        d_width = d_height = LOGO_SIZE;
411
 
 
412
 
-      ret = clutter_texture_set_from_rgb_data (CLUTTER_TEXTURE (bvw->priv->logo),
413
 
-                                              gdk_pixbuf_get_pixels (pixbuf),
414
 
-                                              gdk_pixbuf_get_has_alpha (pixbuf),
415
 
-                                              gdk_pixbuf_get_width (pixbuf),
416
 
-                                              gdk_pixbuf_get_height (pixbuf),
417
 
-                                              gdk_pixbuf_get_rowstride (pixbuf),
418
 
-                                              gdk_pixbuf_get_has_alpha (pixbuf) ? 4 : 3,
419
 
-                                              CLUTTER_TEXTURE_NONE, &err);
420
 
-      if (ret == FALSE) {
421
 
-       g_message ("clutter_texture_set_from_rgb_data failed %s", err->message);
422
 
-       g_error_free (err);
423
 
+      if ((gfloat) d_width / s_width > (gfloat) d_height / s_height) {
424
 
+        ratio = (gfloat) d_height / s_height;
425
 
       } else {
426
 
-       clutter_actor_show (CLUTTER_ACTOR (bvw->priv->logo_frame));
427
 
-       clutter_actor_hide (CLUTTER_ACTOR (bvw->priv->frame));
428
 
-       return;
429
 
+        ratio = (gfloat) d_width / s_width;
430
 
       }
431
 
+
432
 
+      /* center the current point, then scale the context so the logo fills up
433
 
+       * all the space */
434
 
+      cairo_translate (cr, allocation.width / 2, allocation.height / 2);
435
 
+      cairo_scale (cr, ratio, ratio);
436
 
+
437
 
+      /* fill with black */
438
 
+      cairo_set_source_rgb (cr, 0, 0, 0);
439
 
+      cairo_paint (cr);
440
 
+
441
 
+      /* then draw logo on top */
442
 
+      gdk_cairo_set_source_pixbuf (cr, pixbuf, - s_width / 2, - s_height / 2);
443
 
+      cairo_paint (cr);
444
 
+    }
445
 
+  } else if (xoverlay != NULL && GST_IS_X_OVERLAY (xoverlay)) {
446
 
+    /* no logo, use gst */
447
 
+
448
 
+    /* Paint the non-video parts black */
449
 
+    if (gtk_cairo_should_draw_window (cr, gtk_widget_get_window (widget))) {
450
 
+      cairo_set_operator (cr, CAIRO_OPERATOR_CLEAR);
451
 
+      cairo_paint (cr);
452
 
     }
453
 
+
454
 
+    /* let gst paint the video */
455
 
+    if (gtk_cairo_should_draw_window (cr, bvw->priv->video_window))
456
 
+      gst_x_overlay_expose (xoverlay);
457
 
+  } else {
458
 
+    /* if not even gst exists, just paint black */
459
 
+    cairo_set_source_rgb (cr, 0, 0, 0);
460
 
+    cairo_paint (cr);
461
 
   }
462
 
 
463
 
-  clutter_actor_show (CLUTTER_ACTOR (bvw->priv->frame));
464
 
-  clutter_actor_hide (CLUTTER_ACTOR (bvw->priv->logo_frame));
465
 
+  if (xoverlay != NULL)
466
 
+    gst_object_unref (xoverlay);
467
 
+
468
 
+  return FALSE;
469
 
 }
470
 
 
471
 
+static GstNavigation *
472
 
+bvw_get_navigation_iface (BaconVideoWidget *bvw, gboolean update_interfaces)
473
 
+{
474
 
+  GstNavigation *nav = NULL;
475
 
+  g_mutex_lock (bvw->priv->lock);
476
 
+  if (bvw->priv->navigation == NULL && update_interfaces == TRUE)
477
 
+    bvw_update_interface_implementations (bvw);
478
 
+  if (bvw->priv->navigation)
479
 
+    nav = gst_object_ref (GST_OBJECT (bvw->priv->navigation));
480
 
+  g_mutex_unlock (bvw->priv->lock);
481
 
+
482
 
+  return nav;
483
 
+}
484
 
+    
485
 
 /* need to use gstnavigation interface for these vmethods, to allow for the sink
486
 
    to map screen coordinates to video coordinates in the presence of e.g.
487
 
    hardware scaling */
488
 
@@ -651,8 +787,13 @@ bacon_video_widget_motion_notify (GtkWid
489
 
 
490
 
   g_return_val_if_fail (bvw->priv->play != NULL, FALSE);
491
 
 
492
 
-  if (!bvw->priv->logo_mode)
493
 
-    gst_navigation_send_mouse_event (bvw->priv->navigation, "mouse-move", 0, event->x, event->y);
494
 
+  if (!bvw->priv->logo_mode) {
495
 
+    GstNavigation *nav = bvw_get_navigation_iface (bvw, FALSE);
496
 
+    if (nav) {
497
 
+      gst_navigation_send_mouse_event (nav, "mouse-move", 0, event->x, event->y);
498
 
+      gst_object_unref (GST_OBJECT (nav));
499
 
+    }
500
 
+  }
501
 
 
502
 
   if (GTK_WIDGET_CLASS (parent_class)->motion_notify_event)
503
 
     res |= GTK_WIDGET_CLASS (parent_class)->motion_notify_event (widget, event);
504
 
@@ -669,12 +810,16 @@ bacon_video_widget_button_press (GtkWidg
505
 
   g_return_val_if_fail (bvw->priv->play != NULL, FALSE);
506
 
 
507
 
   if (!bvw->priv->logo_mode) {
508
 
-    gst_navigation_send_mouse_event (bvw->priv->navigation,
509
 
-                                    "mouse-button-press", event->button, event->x, event->y);
510
 
-
511
 
-    /* FIXME need to check whether the backend will have handled
512
 
-     * the button press
513
 
-     res = TRUE; */
514
 
+    GstNavigation *nav = bvw_get_navigation_iface (bvw, FALSE);
515
 
+    if (nav) {
516
 
+      gst_navigation_send_mouse_event (nav,
517
 
+          "mouse-button-press", event->button, event->x, event->y);
518
 
+      gst_object_unref (GST_OBJECT (nav));
519
 
+
520
 
+      /* FIXME need to check whether the backend will have handled
521
 
+       * the button press
522
 
+      res = TRUE; */
523
 
+    }
524
 
   }
525
 
 
526
 
   if (GTK_WIDGET_CLASS (parent_class)->button_press_event)
527
 
@@ -692,10 +837,14 @@ bacon_video_widget_button_release (GtkWi
528
 
   g_return_val_if_fail (bvw->priv->play != NULL, FALSE);
529
 
 
530
 
   if (!bvw->priv->logo_mode) {
531
 
-    gst_navigation_send_mouse_event (bvw->priv->navigation,
532
 
-                                    "mouse-button-release", event->button, event->x, event->y);
533
 
+    GstNavigation *nav = bvw_get_navigation_iface (bvw, FALSE);
534
 
+    if (nav) {
535
 
+      gst_navigation_send_mouse_event (nav,
536
 
+          "mouse-button-release", event->button, event->x, event->y);
537
 
+      gst_object_unref (GST_OBJECT (nav));
538
 
 
539
 
-    res = TRUE;
540
 
+      res = TRUE;
541
 
+    }
542
 
   }
543
 
 
544
 
   if (GTK_WIDGET_CLASS (parent_class)->button_release_event)
545
 
@@ -720,6 +869,66 @@ bacon_video_widget_get_preferred_height
546
 
   *minimum = *natural = 180;
547
 
 }
548
 
 
549
 
+static void
550
 
+resize_video_window (BaconVideoWidget *bvw)
551
 
+{
552
 
+  GtkAllocation allocation;
553
 
+  gfloat width, height, ratio, x, y;
554
 
+  int w, h;
555
 
+
556
 
+  g_return_if_fail (bvw != NULL);
557
 
+  g_return_if_fail (BACON_IS_VIDEO_WIDGET (bvw));
558
 
+
559
 
+  gtk_widget_get_allocation (GTK_WIDGET (bvw), &allocation);
560
 
+
561
 
+  get_media_size (bvw, &w, &h);
562
 
+  if (!w || !h) {
563
 
+    w = allocation.width;
564
 
+    h = allocation.height;
565
 
+  }
566
 
+  width = w;
567
 
+  height = h;
568
 
+
569
 
+  /* calculate ratio for fitting video into the available space */
570
 
+  if ((gfloat) allocation.width / width >
571
 
+      (gfloat) allocation.height / height) {
572
 
+    ratio = (gfloat) allocation.height / height;
573
 
+  } else {
574
 
+    ratio = (gfloat) allocation.width / width;
575
 
+  }
576
 
+
577
 
+  /* apply zoom factor */
578
 
+  ratio = ratio * bvw->priv->zoom;
579
 
+
580
 
+  width *= ratio;
581
 
+  height *= ratio;
582
 
+  x = (allocation.width - width) / 2;
583
 
+  y = (allocation.height - height) / 2;
584
 
+
585
 
+  gdk_window_move_resize (bvw->priv->video_window, x, y, width, height);
586
 
+  gtk_widget_queue_draw (GTK_WIDGET (bvw));
587
 
+}
588
 
+
589
 
+static void
590
 
+bacon_video_widget_size_allocate (GtkWidget *widget, GtkAllocation *allocation)
591
 
+{
592
 
+  BaconVideoWidget *bvw = BACON_VIDEO_WIDGET (widget);
593
 
+
594
 
+  g_return_if_fail (widget != NULL);
595
 
+  g_return_if_fail (BACON_IS_VIDEO_WIDGET (widget));
596
 
+
597
 
+  gtk_widget_set_allocation (widget, allocation);
598
 
+
599
 
+  if (gtk_widget_get_realized (widget)) {
600
 
+
601
 
+    gdk_window_move_resize (gtk_widget_get_window (widget),
602
 
+                            allocation->x, allocation->y,
603
 
+                            allocation->width, allocation->height);
604
 
+
605
 
+    resize_video_window (bvw);
606
 
+  }
607
 
+}
608
 
+
609
 
 static gboolean
610
 
 bvw_boolean_handled_accumulator (GSignalInvocationHint * ihint,
611
 
     GValue * return_accu, const GValue * handler_return, gpointer foobar)
612
 
@@ -750,10 +959,11 @@ bacon_video_widget_class_init (BaconVide
613
 
   /* GtkWidget */
614
 
   widget_class->get_preferred_width = bacon_video_widget_get_preferred_width;
615
 
   widget_class->get_preferred_height = bacon_video_widget_get_preferred_height;
616
 
+  widget_class->size_allocate = bacon_video_widget_size_allocate;
617
 
   widget_class->realize = bacon_video_widget_realize;
618
 
-
619
 
-  /* FIXME: Remove those when GtkClutterEmbedded passes on GDK XI 1.2
620
 
-   * events properly */
621
 
+  widget_class->show = bacon_video_widget_show;
622
 
+  widget_class->hide = bacon_video_widget_hide;
623
 
+  widget_class->draw = bacon_video_widget_draw;
624
 
   widget_class->motion_notify_event = bacon_video_widget_motion_notify;
625
 
   widget_class->button_press_event = bacon_video_widget_button_press;
626
 
   widget_class->button_release_event = bacon_video_widget_button_release;
627
 
@@ -1143,6 +1353,7 @@ bacon_video_widget_init (BaconVideoWidge
628
 
   BaconVideoWidgetPrivate *priv;
629
 
 
630
 
   gtk_widget_set_can_focus (GTK_WIDGET (bvw), TRUE);
631
 
+  gtk_widget_set_double_buffered (GTK_WIDGET (bvw), FALSE);
632
 
 
633
 
   g_type_class_ref (BVW_TYPE_METADATA_TYPE);
634
 
   g_type_class_ref (BVW_TYPE_DVD_EVENT);
635
 
@@ -1153,6 +1364,7 @@ bacon_video_widget_init (BaconVideoWidge
636
 
   priv->tagcache = NULL;
637
 
   priv->audiotags = NULL;
638
 
   priv->videotags = NULL;
639
 
+  priv->zoom = 1.0;
640
 
   priv->volume = -1.0;
641
 
   priv->movie_par_n = priv->movie_par_d = 1;
642
 
   priv->rate = FORWARD_RATE;
643
 
@@ -1160,6 +1372,8 @@ bacon_video_widget_init (BaconVideoWidge
644
 
   priv->tag_update_queue = g_async_queue_new_full ((GDestroyNotify) update_tags_delayed_data_destroy);
645
 
   priv->tag_update_id = 0;
646
 
 
647
 
+  priv->lock = g_mutex_new ();
648
 
+
649
 
   priv->seek_mutex = g_mutex_new ();
650
 
   priv->clock = gst_system_clock_obtain ();
651
 
   priv->seek_req_time = GST_CLOCK_TIME_NONE;
652
 
@@ -1193,6 +1407,7 @@ static void
653
 
 bvw_handle_application_message (BaconVideoWidget *bvw, GstMessage *msg)
654
 
 {
655
 
   const gchar *msg_name;
656
 
+  GtkAllocation allocation;
657
 
 
658
 
   msg_name = gst_structure_get_name (msg->structure);
659
 
   g_return_if_fail (msg_name != NULL);
660
 
@@ -1203,22 +1418,18 @@ bvw_handle_application_message (BaconVid
661
 
     bvw_update_stream_info (bvw);
662
 
   }
663
 
   else if (strcmp (msg_name, "video-size") == 0) {
664
 
-    int w, h;
665
 
-
666
 
     g_signal_emit (bvw, bvw_signals[SIGNAL_GOT_METADATA], 0, NULL);
667
 
 
668
 
-    /* This is necessary for the pixel-aspect-ratio of the
669
 
-     * display to be taken into account. */
670
 
-    get_media_size (bvw, &w, &h);
671
 
-    clutter_actor_set_size (bvw->priv->texture, w, h);
672
 
-
673
 
     if (bvw->priv->auto_resize
674
 
        && !bvw->priv->fullscreen_mode
675
 
        && !bvw->priv->window_resized) {
676
 
       bacon_video_widget_set_scale_ratio (bvw, 0.0);
677
 
+    } else {
678
 
+      gtk_widget_get_allocation (GTK_WIDGET (bvw), &allocation);
679
 
+      bacon_video_widget_size_allocate (GTK_WIDGET (bvw),
680
 
+                                        &allocation);
681
 
     }
682
 
     bvw->priv->window_resized = TRUE;
683
 
-    set_current_actor (bvw);
684
 
   } else {
685
 
     g_message ("Unhandled application message %s", msg_name);
686
 
   }
687
 
@@ -1227,7 +1438,16 @@ bvw_handle_application_message (BaconVid
688
 
 static gboolean
689
 
 bvw_do_navigation_query (BaconVideoWidget * bvw, GstQuery *query)
690
 
 {
691
 
-  return gst_element_query (GST_ELEMENT_CAST (bvw->priv->navigation), query);
692
 
+  GstNavigation *nav = bvw_get_navigation_iface (bvw, TRUE);
693
 
+  gboolean res;
694
 
+
695
 
+  if (G_UNLIKELY (nav == NULL || !GST_IS_ELEMENT (nav)))
696
 
+    return FALSE;
697
 
+
698
 
+  res = gst_element_query (GST_ELEMENT_CAST (nav), query);
699
 
+  gst_object_unref (GST_OBJECT (nav));
700
 
+
701
 
+  return res;
702
 
 }
703
 
 
704
 
 static void
705
 
@@ -1307,6 +1527,10 @@ bvw_handle_element_message (BaconVideoWi
706
 
         g_signal_emit (bvw, bvw_signals[SIGNAL_BUFFERING], 0, percent);
707
 
     }
708
 
     goto done;
709
 
+  } else if (strcmp (type_name, "prepare-xwindow-id") == 0 ||
710
 
+      strcmp (type_name, "have-xwindow-id") == 0) {
711
 
+    /* we handle these synchronously or want to ignore them */
712
 
+    goto done;
713
 
   } else if (gst_is_missing_plugin_message (msg)) {
714
 
     bvw->priv->missing_plugins =
715
 
       g_list_prepend (bvw->priv->missing_plugins, gst_message_ref (msg));
716
 
@@ -1678,8 +1902,6 @@ bvw_update_tags (BaconVideoWidget * bvw,
717
 
   bvw_check_for_cover_pixbuf (bvw);
718
 
 
719
 
   g_signal_emit (bvw, bvw_signals[SIGNAL_GOT_METADATA], 0);
720
 
-
721
 
-  set_current_actor (bvw);
722
 
 }
723
 
 
724
 
 static void
725
 
@@ -2378,13 +2600,13 @@ parse_stream_info (BaconVideoWidget *bvw
726
 
   g_object_get (G_OBJECT (bvw->priv->play), "n-audio", &n_audio,
727
 
       "n-video", &n_video, NULL);
728
 
 
729
 
-  bvw_check_for_cover_pixbuf (bvw);
730
 
-
731
 
   bvw->priv->media_has_video = FALSE;
732
 
   if (n_video > 0) {
733
 
     gint i;
734
 
 
735
 
     bvw->priv->media_has_video = TRUE;
736
 
+    if (bvw->priv->video_window)
737
 
+      gdk_window_show (bvw->priv->video_window);
738
 
 
739
 
     for (i = 0; i < n_video && videopad == NULL; i++)
740
 
       g_signal_emit_by_name (bvw->priv->play, "get-video-pad", i, &videopad);
741
 
@@ -2393,14 +2615,19 @@ parse_stream_info (BaconVideoWidget *bvw
742
 
   bvw->priv->media_has_audio = FALSE;
743
 
   if (n_audio > 0) {
744
 
     bvw->priv->media_has_audio = TRUE;
745
 
-    if (!bvw->priv->media_has_video) {
746
 
+    if (!bvw->priv->media_has_video && bvw->priv->video_window) {
747
 
       gint flags;
748
 
 
749
 
       g_object_get (bvw->priv->play, "flags", &flags, NULL);
750
 
-      if (bvw->priv->show_vfx && !bvw->priv->cover_pixbuf)
751
 
+      if (bvw->priv->show_vfx) {
752
 
+        gdk_window_show (bvw->priv->video_window);
753
 
+       gtk_widget_set_double_buffered (GTK_WIDGET (bvw), FALSE);
754
 
        flags |= GST_PLAY_FLAG_VIS;
755
 
-      else
756
 
+      } else {
757
 
+        gdk_window_hide (bvw->priv->video_window);
758
 
+       gtk_widget_set_double_buffered (GTK_WIDGET (bvw), TRUE);
759
 
        flags &= ~GST_PLAY_FLAG_VIS;
760
 
+      }
761
 
       g_object_set (bvw->priv->play, "flags", flags, NULL);
762
 
     }
763
 
   }
764
 
@@ -2419,8 +2646,6 @@ parse_stream_info (BaconVideoWidget *bvw
765
 
     get_visualization_size (bvw, &bvw->priv->video_width,
766
 
         &bvw->priv->video_height, NULL, NULL);
767
 
   }
768
 
-
769
 
-  set_current_actor (bvw);
770
 
 }
771
 
 
772
 
 static void
773
 
@@ -2451,6 +2676,9 @@ bacon_video_widget_finalize (GObject * o
774
 
      * called again (main loop might be run again to display error dialog) */
775
 
     gst_bus_set_flushing (bvw->priv->bus, TRUE);
776
 
 
777
 
+    if (bvw->priv->sig_bus_sync)
778
 
+      g_signal_handler_disconnect (bvw->priv->bus, bvw->priv->sig_bus_sync);
779
 
+
780
 
     if (bvw->priv->sig_bus_async)
781
 
       g_signal_handler_disconnect (bvw->priv->bus, bvw->priv->sig_bus_async);
782
 
 
783
 
@@ -2504,6 +2732,11 @@ bacon_video_widget_finalize (GObject * o
784
 
     bvw->priv->update_id = 0;
785
 
   }
786
 
 
787
 
+  if (bvw->priv->interface_update_id) {
788
 
+    g_source_remove (bvw->priv->interface_update_id);
789
 
+    bvw->priv->interface_update_id = 0;
790
 
+  }
791
 
+
792
 
   if (bvw->priv->tagcache) {
793
 
     gst_tag_list_free (bvw->priv->tagcache);
794
 
     bvw->priv->tagcache = NULL;
795
 
@@ -2535,6 +2768,7 @@ bacon_video_widget_finalize (GObject * o
796
 
     bvw->priv->mount_cancellable = NULL;
797
 
   }
798
 
 
799
 
+  g_mutex_free (bvw->priv->lock);
800
 
   g_mutex_free (bvw->priv->seek_mutex);
801
 
 
802
 
   G_OBJECT_CLASS (parent_class)->finalize (object);
803
 
@@ -3495,6 +3729,7 @@ bacon_video_widget_open (BaconVideoWidge
804
 
 gboolean
805
 
 bacon_video_widget_play (BaconVideoWidget * bvw, GError ** error)
806
 
 {
807
 
+  GtkAllocation allocation;
808
 
   GstState cur_state;
809
 
 
810
 
   g_return_val_if_fail (bvw != NULL, FALSE);
811
 
@@ -3502,6 +3737,16 @@ bacon_video_widget_play (BaconVideoWidge
812
 
   g_return_val_if_fail (GST_IS_ELEMENT (bvw->priv->play), FALSE);
813
 
   g_return_val_if_fail (bvw->priv->mrl != NULL, FALSE);
814
 
 
815
 
+  /* We hide the video window for now. Will show when video of vfx comes up */
816
 
+  if (bvw->priv->video_window) {
817
 
+    gdk_window_hide (bvw->priv->video_window);
818
 
+    /* We also take the whole widget until we know video size */
819
 
+    gtk_widget_get_allocation (GTK_WIDGET (bvw), &allocation);
820
 
+    gdk_window_move_resize (bvw->priv->video_window, 0, 0,
821
 
+                            allocation.width,
822
 
+                            allocation.height);
823
 
+  }
824
 
+
825
 
   if (bvw->priv->ready_idle_id) {
826
 
     g_source_remove (bvw->priv->ready_idle_id);
827
 
     bvw->priv->ready_idle_id = 0;
828
 
@@ -3864,7 +4109,12 @@ bacon_video_widget_close (BaconVideoWidg
829
 
 static void
830
 
 bvw_do_navigation_command (BaconVideoWidget * bvw, GstNavigationCommand command)
831
 
 {
832
 
-  gst_navigation_send_command (bvw->priv->navigation, command);
833
 
+  GstNavigation *nav = bvw_get_navigation_iface (bvw, TRUE);
834
 
+  if (nav == NULL)
835
 
+    return;
836
 
+
837
 
+  gst_navigation_send_command (nav, command);
838
 
+  gst_object_unref (GST_OBJECT (nav));
839
 
 }
840
 
 
841
 
 /**
842
 
@@ -3988,10 +4238,7 @@ bacon_video_widget_set_logo (BaconVideoW
843
 
   if (error) {
844
 
     g_warning ("An error occurred trying to open logo %s: %s", name, error->message);
845
 
     g_error_free (error);
846
 
-    return;
847
 
   }
848
 
-
849
 
-  set_current_actor (bvw);
850
 
 }
851
 
 
852
 
 /**
853
 
@@ -4017,10 +4264,21 @@ bacon_video_widget_set_logo_mode (BaconV
854
 
   if (priv->logo_mode != logo_mode) {
855
 
     priv->logo_mode = logo_mode;
856
 
 
857
 
-    set_current_actor (bvw);
858
 
+    if (priv->video_window) {
859
 
+      if (logo_mode) {
860
 
+        gdk_window_hide (priv->video_window);
861
 
+       gtk_widget_set_double_buffered (GTK_WIDGET (bvw), TRUE);
862
 
+      } else {
863
 
+        gdk_window_show (priv->video_window);
864
 
+       gtk_widget_set_double_buffered (GTK_WIDGET (bvw), FALSE);
865
 
+      }
866
 
+    }
867
 
 
868
 
     g_object_notify (G_OBJECT (bvw), "logo_mode");
869
 
     g_object_notify (G_OBJECT (bvw), "seekable");
870
 
+
871
 
+    /* Queue a redraw of the widget */
872
 
+    gtk_widget_queue_draw (GTK_WIDGET (bvw));
873
 
   }
874
 
 }
875
 
 
876
 
@@ -4377,13 +4635,8 @@ get_visualization_size (BaconVideoWidget
877
 
   g_return_if_fail (h != NULL);
878
 
   g_return_if_fail (bvw->priv->visq < G_N_ELEMENTS (vis_qualities));
879
 
 
880
 
-  if (gtk_widget_get_realized (GTK_WIDGET (bvw)) == FALSE) {
881
 
-    if (fps_n)
882
 
-      *fps_n = 1;
883
 
-    if (fps_d)
884
 
-      *fps_d = 1;
885
 
+  if (!bvw->priv->video_window)
886
 
     return;
887
 
-  }
888
 
 
889
 
   *h = vis_qualities[bvw->priv->visq].height;
890
 
   new_fps_n = vis_qualities[bvw->priv->visq].fps;
891
 
@@ -4391,9 +4644,9 @@ get_visualization_size (BaconVideoWidget
892
 
   screen = gtk_widget_get_screen (GTK_WIDGET (bvw));
893
 
   *w = *h * gdk_screen_get_width (screen) / gdk_screen_get_height (screen);
894
 
 
895
 
-  if (fps_n)
896
 
+  if (fps_n) 
897
 
     *fps_n = new_fps_n;
898
 
-  if (fps_d)
899
 
+  if (fps_d) 
900
 
     *fps_d = 1;
901
 
 }
902
 
 
903
 
@@ -4439,11 +4692,7 @@ setup_vis (BaconVideoWidget * bvw)
904
 
 
905
 
   GST_DEBUG ("setup_vis called, show_vfx %d, vis element %s",
906
 
       bvw->priv->show_vfx, bvw->priv->vis_element_name);
907
 
-
908
 
-  /* Check to see if we have an embedded cover image. If we do, don't show visualisations.
909
 
-   * FIXME probably wrong now, hide that and use an OSD instead */
910
 
-  bvw_check_for_cover_pixbuf (bvw);
911
 
-
912
 
+  
913
 
   if (bvw->priv->show_vfx && !bvw->priv->cover_pixbuf && bvw->priv->vis_element_name) {
914
 
     GstElement *vis_element = NULL, *vis_capsfilter = NULL;
915
 
     GstPad *pad = NULL;
916
 
@@ -4539,17 +4788,26 @@ setup_vis (BaconVideoWidget * bvw)
917
 
     }
918
 
   }
919
 
 
920
 
+  /* Check to see if we have an embedded cover image. If we do, don't show visualisations. */
921
 
+  bvw_check_for_cover_pixbuf (bvw);
922
 
+
923
 
   if (bvw->priv->media_has_audio &&
924
 
-      !bvw->priv->media_has_video) {
925
 
+      !bvw->priv->media_has_video && bvw->priv->video_window) {
926
 
     gint flags;
927
 
 
928
 
     g_object_get (bvw->priv->play, "flags", &flags, NULL);
929
 
     if (bvw->priv->show_vfx && !bvw->priv->cover_pixbuf) {
930
 
+      gdk_window_show (bvw->priv->video_window);
931
 
+      gtk_widget_set_double_buffered (GTK_WIDGET (bvw), FALSE);
932
 
       flags |= GST_PLAY_FLAG_VIS;
933
 
     } else {
934
 
+      gdk_window_hide (bvw->priv->video_window);
935
 
+      gtk_widget_set_double_buffered (GTK_WIDGET (bvw), TRUE);
936
 
       flags &= ~GST_PLAY_FLAG_VIS;
937
 
     }
938
 
     g_object_set (bvw->priv->play, "flags", flags, NULL);
939
 
+
940
 
+    gtk_widget_queue_draw (GTK_WIDGET (bvw));
941
 
   }
942
 
 
943
 
 beach:
944
 
@@ -4580,7 +4838,6 @@ bacon_video_widget_set_show_visualizatio
945
 
 
946
 
   bvw->priv->show_vfx = show_visualizations;
947
 
   setup_vis (bvw);
948
 
-  set_current_actor (bvw);
949
 
 }
950
 
 
951
 
 static gboolean
952
 
@@ -4795,6 +5052,9 @@ bacon_video_widget_set_scale_ratio (Baco
953
 
 
954
 
   GST_DEBUG ("ratio = %.2f", ratio);
955
 
 
956
 
+  if (bvw->priv->video_window == NULL)
957
 
+    return;
958
 
+
959
 
   if (!bvw->priv->media_has_video && bvw->priv->show_vfx) {
960
 
     get_visualization_size (bvw, &w, &h, NULL, NULL);
961
 
   } else {
962
 
@@ -4829,42 +5089,41 @@ bacon_video_widget_set_scale_ratio (Baco
963
 
 /**
964
 
  * bacon_video_widget_set_zoom:
965
 
  * @bvw: a #BaconVideoWidget
966
 
- * @mode: the #BvwZoomMode
967
 
+ * @zoom: a percentage zoom factor
968
 
  *
969
 
- * Sets the zoom type applied to the video when it is displayed.
970
 
+ * Sets the zoom factor applied to the video when it is displayed,
971
 
+ * as an integeric percentage between %0 and %1
972
 
+ * (e.g. set @zoom to %1 to not zoom at all).
973
 
  **/
974
 
 void
975
 
 bacon_video_widget_set_zoom (BaconVideoWidget *bvw,
976
 
-                             BvwZoomMode       mode)
977
 
+                             double            zoom)
978
 
 {
979
 
   g_return_if_fail (bvw != NULL);
980
 
   g_return_if_fail (BACON_IS_VIDEO_WIDGET (bvw));
981
 
 
982
 
-  if (bvw->priv->frame == NULL)
983
 
-    return;
984
 
-
985
 
-  totem_aspect_frame_set_expand (TOTEM_ASPECT_FRAME (bvw->priv->frame),
986
 
-                             (mode == BVW_ZOOM_EXPAND));
987
 
+  bvw->priv->zoom = zoom;
988
 
+  if (bvw->priv->video_window != NULL)
989
 
+    resize_video_window (bvw);
990
 
 }
991
 
 
992
 
 /**
993
 
  * bacon_video_widget_get_zoom:
994
 
  * @bvw: a #BaconVideoWidget
995
 
  *
996
 
- * Returns the zoom mode applied to videos displayed by the widget.
997
 
+ * Returns the zoom factor applied to videos displayed by the widget,
998
 
+ * as an integeric percentage between %0 and %1
999
 
+ * (e.g. %1 means no zooming at all).
1000
 
  *
1001
 
- * Return value: a #BvwZoomMode
1002
 
+ * Return value: the zoom factor
1003
 
  **/
1004
 
-BvwZoomMode
1005
 
+double
1006
 
 bacon_video_widget_get_zoom (BaconVideoWidget *bvw)
1007
 
 {
1008
 
-  gboolean expand;
1009
 
-
1010
 
   g_return_val_if_fail (bvw != NULL, 1.0);
1011
 
   g_return_val_if_fail (BACON_IS_VIDEO_WIDGET (bvw), 1.0);
1012
 
 
1013
 
-  expand = totem_aspect_frame_get_expand (TOTEM_ASPECT_FRAME (bvw->priv->frame));
1014
 
-  return expand ? BVW_ZOOM_EXPAND : BVW_ZOOM_NONE;
1015
 
+  return bvw->priv->zoom;
1016
 
 }
1017
 
 
1018
 
 /* Search for the color balance channel corresponding to type and return it. */
1019
 
@@ -4913,6 +5172,8 @@ bacon_video_widget_get_video_property (B
1020
 
   g_return_val_if_fail (bvw != NULL, 65535/2);
1021
 
   g_return_val_if_fail (BACON_IS_VIDEO_WIDGET (bvw), 65535/2);
1022
 
   
1023
 
+  g_mutex_lock (bvw->priv->lock);
1024
 
+
1025
 
   ret = 0;
1026
 
   
1027
 
   if (bvw->priv->balance && GST_IS_COLOR_BALANCE (bvw->priv->balance))
1028
 
@@ -4936,7 +5197,7 @@ bacon_video_widget_get_video_property (B
1029
 
 
1030
 
         GST_DEBUG ("channel %s: returning value %d", found_channel->label, ret);
1031
 
         g_object_unref (found_channel);
1032
 
-        return ret;
1033
 
+        goto done;
1034
 
       } else {
1035
 
        ret = -1;
1036
 
       }
1037
 
@@ -4944,6 +5205,9 @@ bacon_video_widget_get_video_property (B
1038
 
 
1039
 
   GST_DEBUG ("nothing found for type %d, returning value %d", type, ret);
1040
 
 
1041
 
+done:
1042
 
+
1043
 
+  g_mutex_unlock (bvw->priv->lock);
1044
 
   return ret;
1045
 
 }
1046
 
 
1047
 
@@ -5871,6 +6135,9 @@ bacon_video_widget_get_current_frame (Ba
1048
 
 /*                                             */
1049
 
 /* =========================================== */
1050
 
 
1051
 
+/* applications must use exactly one of bacon_video_widget_get_option_group()
1052
 
+ * OR bacon_video_widget_init_backend(), but not both */
1053
 
+
1054
 
 /**
1055
 
  * bacon_video_widget_get_option_group:
1056
 
  *
1057
 
@@ -5884,10 +6151,26 @@ bacon_video_widget_get_current_frame (Ba
1058
 
 GOptionGroup*
1059
 
 bacon_video_widget_get_option_group (void)
1060
 
 {
1061
 
-  gtk_clutter_init (NULL, NULL);
1062
 
   return gst_init_get_option_group ();
1063
 
 }
1064
 
 
1065
 
+/**
1066
 
+ * bacon_video_widget_init_backend:
1067
 
+ * @argc: pointer to application's argc
1068
 
+ * @argv: pointer to application's argv
1069
 
+ *
1070
 
+ * Initialises #BaconVideoWidget's GStreamer backend. If this fails
1071
 
+ * for the GStreamer backend, your application will be terminated.
1072
 
+ *
1073
 
+ * Applications must call either this or bacon_video_widget_get_option_group() exactly
1074
 
+ * once; but not both.
1075
 
+ **/
1076
 
+void
1077
 
+bacon_video_widget_init_backend (int *argc, char ***argv)
1078
 
+{
1079
 
+  gst_init (argc, argv);
1080
 
+}
1081
 
+
1082
 
 GQuark
1083
 
 bacon_video_widget_error_quark (void)
1084
 
 {
1085
 
@@ -5899,6 +6182,191 @@ bacon_video_widget_error_quark (void)
1086
 
   return q;
1087
 
 }
1088
 
 
1089
 
+/* fold function to pick the best colorspace element */
1090
 
+static gboolean
1091
 
+find_colorbalance_element (GstElement *element, GValue * ret, GstElement **cb)
1092
 
+{
1093
 
+  GstColorBalanceClass *cb_class;
1094
 
+
1095
 
+  GST_DEBUG ("Checking element %s ...", GST_OBJECT_NAME (element));
1096
 
+
1097
 
+  if (!GST_IS_COLOR_BALANCE (element))
1098
 
+    return TRUE;
1099
 
+
1100
 
+  GST_DEBUG ("Element %s is a color balance", GST_OBJECT_NAME (element));
1101
 
+
1102
 
+  cb_class = GST_COLOR_BALANCE_GET_CLASS (element);
1103
 
+  if (GST_COLOR_BALANCE_TYPE (cb_class) == GST_COLOR_BALANCE_HARDWARE) {
1104
 
+    gst_object_replace ((GstObject **) cb, (GstObject *) element);
1105
 
+    /* shortcuts the fold */
1106
 
+    return FALSE;
1107
 
+  } else if (*cb == NULL) {
1108
 
+    gst_object_replace ((GstObject **) cb, (GstObject *) element);
1109
 
+    return TRUE;
1110
 
+  } else {
1111
 
+    return TRUE;
1112
 
+  }
1113
 
+}
1114
 
+
1115
 
+static gboolean
1116
 
+bvw_update_interfaces_delayed (BaconVideoWidget *bvw)
1117
 
+{
1118
 
+  GST_DEBUG ("Delayed updating interface implementations");
1119
 
+  g_mutex_lock (bvw->priv->lock);
1120
 
+  bvw_update_interface_implementations (bvw);
1121
 
+  bvw->priv->interface_update_id = 0;
1122
 
+  g_mutex_unlock (bvw->priv->lock);
1123
 
+
1124
 
+  return FALSE;
1125
 
+}
1126
 
+
1127
 
+/* Must be called with bvw->priv->lock held */
1128
 
+static void
1129
 
+bvw_update_interface_implementations (BaconVideoWidget *bvw)
1130
 
+{
1131
 
+  GstColorBalance *old_balance = bvw->priv->balance;
1132
 
+  GstXOverlay *old_xoverlay = bvw->priv->xoverlay;
1133
 
+  GstElement *video_sink = NULL;
1134
 
+  GstElement *element = NULL;
1135
 
+  GstIterator *iter;
1136
 
+  GstElement *play;
1137
 
+
1138
 
+  if (g_thread_self() != gui_thread) {
1139
 
+    if (bvw->priv->balance)
1140
 
+      gst_object_unref (bvw->priv->balance);
1141
 
+    bvw->priv->balance = NULL;
1142
 
+    if (bvw->priv->xoverlay)
1143
 
+      gst_object_unref (bvw->priv->xoverlay);
1144
 
+    bvw->priv->xoverlay = NULL;
1145
 
+    if (bvw->priv->navigation)
1146
 
+      gst_object_unref (bvw->priv->navigation);
1147
 
+    bvw->priv->navigation = NULL;
1148
 
+
1149
 
+    if (bvw->priv->interface_update_id)
1150
 
+       g_source_remove (bvw->priv->interface_update_id);
1151
 
+    bvw->priv->interface_update_id =
1152
 
+        g_idle_add ((GSourceFunc) bvw_update_interfaces_delayed, bvw);
1153
 
+    return;
1154
 
+  }
1155
 
+
1156
 
+  play = gst_object_ref(bvw->priv->play);
1157
 
+
1158
 
+  g_mutex_unlock (bvw->priv->lock);
1159
 
+  g_object_get (bvw->priv->play, "video-sink", &video_sink, NULL);
1160
 
+  g_assert (video_sink != NULL);
1161
 
+  g_mutex_lock (bvw->priv->lock);
1162
 
+
1163
 
+  gst_object_unref(play);
1164
 
+
1165
 
+  /* We try to get an element supporting XOverlay interface */
1166
 
+  if (GST_IS_BIN (video_sink)) {
1167
 
+    GST_DEBUG ("Retrieving xoverlay from bin ...");
1168
 
+    element = gst_bin_get_by_interface (GST_BIN (video_sink),
1169
 
+                                        GST_TYPE_X_OVERLAY);
1170
 
+  } else {
1171
 
+    element = gst_object_ref(video_sink);
1172
 
+  }
1173
 
+
1174
 
+  if (GST_IS_X_OVERLAY (element)) {
1175
 
+    GST_DEBUG ("Found xoverlay: %s", GST_OBJECT_NAME (element));
1176
 
+    bvw->priv->xoverlay = GST_X_OVERLAY (element);
1177
 
+  } else {
1178
 
+    GST_DEBUG ("No xoverlay found");
1179
 
+    if (element)
1180
 
+      gst_object_unref (element);
1181
 
+    bvw->priv->xoverlay = NULL;
1182
 
+  }
1183
 
+
1184
 
+  /* Try to find the navigation interface */
1185
 
+  if (GST_IS_BIN (video_sink)) {
1186
 
+    GST_DEBUG ("Retrieving navigation from bin ...");
1187
 
+    element = gst_bin_get_by_interface (GST_BIN (video_sink),
1188
 
+                                        GST_TYPE_NAVIGATION);
1189
 
+  } else {
1190
 
+    element = gst_object_ref(video_sink);
1191
 
+  }
1192
 
+
1193
 
+  if (GST_IS_NAVIGATION (element)) {
1194
 
+    GST_DEBUG ("Found navigation: %s", GST_OBJECT_NAME (element));
1195
 
+    bvw->priv->navigation = GST_NAVIGATION (element);
1196
 
+  } else {
1197
 
+    GST_DEBUG ("No navigation found");
1198
 
+    if (element)
1199
 
+      gst_object_unref (element);
1200
 
+    bvw->priv->navigation = NULL;
1201
 
+  }
1202
 
+
1203
 
+  /* Find best color balance element (using custom iterator so
1204
 
+   * we can prefer hardware implementations to software ones) */
1205
 
+
1206
 
+  /* FIXME: this doesn't work reliably yet, most of the time
1207
 
+   * the fold function doesn't even get called, while sometimes
1208
 
+   * it does ... */
1209
 
+  iter = gst_bin_iterate_all_by_interface (GST_BIN (bvw->priv->play),
1210
 
+                                           GST_TYPE_COLOR_BALANCE);
1211
 
+  /* naively assume no resync */
1212
 
+  element = NULL;
1213
 
+  gst_iterator_fold (iter,
1214
 
+      (GstIteratorFoldFunction) find_colorbalance_element, NULL, &element);
1215
 
+  gst_iterator_free (iter);
1216
 
+
1217
 
+  if (element) {
1218
 
+    bvw->priv->balance = GST_COLOR_BALANCE (element);
1219
 
+    GST_DEBUG ("Best colorbalance found: %s",
1220
 
+        GST_OBJECT_NAME (bvw->priv->balance));
1221
 
+  } else if (GST_IS_COLOR_BALANCE (bvw->priv->xoverlay)) {
1222
 
+    bvw->priv->balance = GST_COLOR_BALANCE (bvw->priv->xoverlay);
1223
 
+    gst_object_ref (bvw->priv->balance);
1224
 
+    GST_DEBUG ("Colorbalance backup found: %s",
1225
 
+        GST_OBJECT_NAME (bvw->priv->balance));
1226
 
+  } else {
1227
 
+    GST_DEBUG ("No colorbalance found");
1228
 
+    bvw->priv->balance = NULL;
1229
 
+  }
1230
 
+
1231
 
+  if (old_xoverlay)
1232
 
+    gst_object_unref (GST_OBJECT (old_xoverlay));
1233
 
+
1234
 
+  if (old_balance)
1235
 
+    gst_object_unref (GST_OBJECT (old_balance));
1236
 
+
1237
 
+  gst_object_unref (video_sink);
1238
 
+}
1239
 
+
1240
 
+static void
1241
 
+bvw_element_msg_sync (GstBus *bus, GstMessage *msg, gpointer data)
1242
 
+{
1243
 
+  BaconVideoWidget *bvw = BACON_VIDEO_WIDGET (data);
1244
 
+
1245
 
+  g_assert (msg->type == GST_MESSAGE_ELEMENT);
1246
 
+
1247
 
+  if (msg->structure == NULL)
1248
 
+    return;
1249
 
+
1250
 
+  /* This only gets sent if we haven't set an ID yet. This is our last
1251
 
+   * chance to set it before the video sink will create its own window */
1252
 
+  if (gst_structure_has_name (msg->structure, "prepare-xwindow-id")) {
1253
 
+    XID window;
1254
 
+
1255
 
+    GST_DEBUG ("Handling sync prepare-xwindow-id message");
1256
 
+
1257
 
+    g_mutex_lock (bvw->priv->lock);
1258
 
+    bvw_update_interface_implementations (bvw);
1259
 
+    if (bvw->priv->xoverlay == NULL) {
1260
 
+      GstObject *sender = GST_MESSAGE_SRC (msg);
1261
 
+      if (sender && GST_IS_X_OVERLAY (sender))
1262
 
+        bvw->priv->xoverlay = GST_X_OVERLAY (gst_object_ref (sender));
1263
 
+    }
1264
 
+    g_mutex_unlock (bvw->priv->lock);
1265
 
+
1266
 
+    g_return_if_fail (bvw->priv->xoverlay != NULL);
1267
 
+    g_return_if_fail (bvw->priv->video_window != NULL);
1268
 
+
1269
 
+    window = gdk_x11_window_get_xid (bvw->priv->video_window);
1270
 
+    gst_x_overlay_set_xwindow_id (bvw->priv->xoverlay, window);
1271
 
+  }
1272
 
+}
1273
 
+
1274
 
 static gboolean
1275
 
 bvw_set_playback_direction (BaconVideoWidget *bvw, gboolean forward)
1276
 
 {
1277
 
@@ -5961,8 +6429,21 @@ bvw_set_playback_direction (BaconVideoWi
1278
 
   return retval;
1279
 
 }
1280
 
 
1281
 
+static void
1282
 
+got_new_video_sink_bin_element (GstBin *video_sink, GstElement *element,
1283
 
+                                gpointer data)
1284
 
+{
1285
 
+  BaconVideoWidget *bvw = BACON_VIDEO_WIDGET (data);
1286
 
+
1287
 
+  g_mutex_lock (bvw->priv->lock);
1288
 
+  bvw_update_interface_implementations (bvw);
1289
 
+  g_mutex_unlock (bvw->priv->lock);
1290
 
+}
1291
 
+
1292
 
 /**
1293
 
  * bacon_video_widget_new:
1294
 
+ * @width: initial or expected video width, in pixels, or %-1
1295
 
+ * @height: initial or expected video height, in pixels, or %-1
1296
 
  * @error: a #GError, or %NULL
1297
 
  *
1298
 
  * Creates a new #BaconVideoWidget.
1299
 
@@ -5975,16 +6456,13 @@ bvw_set_playback_direction (BaconVideoWi
1300
 
  * Return value: a new #BaconVideoWidget, or %NULL; destroy with gtk_widget_destroy()
1301
 
  **/
1302
 
 GtkWidget *
1303
 
-bacon_video_widget_new (GError ** error)
1304
 
+bacon_video_widget_new (int width, int height,
1305
 
+                        GError ** error)
1306
 
 {
1307
 
   BaconVideoWidget *bvw;
1308
 
   GstElement *audio_sink = NULL, *video_sink = NULL;
1309
 
   gchar *version_str;
1310
 
   GstPlayFlags flags;
1311
 
-  ClutterColor black = { 0x00, 0x00, 0x00, 0xff };
1312
 
-  ClutterConstraint *constraint;
1313
 
-  GstElement *balance, *sink, *bin;
1314
 
-  GstPad *pad, *ghostpad;
1315
 
 
1316
 
 #ifndef GST_DISABLE_GST_DEBUG
1317
 
   if (_totem_gst_debug_cat == NULL) {
1318
 
@@ -6043,61 +6521,69 @@ bacon_video_widget_new (GError ** error)
1319
 
 
1320
 
   audio_sink = gst_element_factory_make ("autoaudiosink", "audio-sink");
1321
 
 
1322
 
+  if (width > 0 && width < SMALL_STREAM_WIDTH &&
1323
 
+      height > 0 && height < SMALL_STREAM_HEIGHT) {
1324
 
+    GST_INFO ("forcing ximagesink, image size only %dx%d", width, height);
1325
 
+    video_sink = gst_element_factory_make ("ximagesink", "video-sink");
1326
 
+  } else {
1327
 
+    video_sink = gst_element_factory_make ("gconfvideosink", "video-sink");
1328
 
+    if (video_sink == NULL) {
1329
 
+      g_warning ("Could not create element 'gconfvideosink'");
1330
 
+      /* Try to fallback on ximagesink */
1331
 
+      video_sink = gst_element_factory_make ("ximagesink", "video-sink");
1332
 
+    }
1333
 
+  }
1334
 
 
1335
 
-  bvw->priv->stage = gtk_clutter_embed_get_stage (GTK_CLUTTER_EMBED (bvw));
1336
 
-  clutter_stage_set_color (CLUTTER_STAGE (bvw->priv->stage), &black);
1337
 
+  /* Set the display if the video sink supports it */
1338
 
+  if (g_object_class_find_property (G_OBJECT_GET_CLASS (video_sink), "display")) {
1339
 
+    const char *display;
1340
 
 
1341
 
-  /* Bin */
1342
 
-  bin = gst_bin_new ("video_sink_bin");
1343
 
+    display = gdk_get_display_arg_name();
1344
 
+    if (display != NULL)
1345
 
+      g_object_set (G_OBJECT (video_sink), "display", display, NULL);
1346
 
+  }
1347
 
 
1348
 
-  /* Video sink, with aspect frame */
1349
 
-  bvw->priv->texture = g_object_new (CLUTTER_TYPE_TEXTURE,
1350
 
-                                    "disable-slicing", TRUE,
1351
 
-                                    NULL);
1352
 
-  sink = clutter_gst_video_sink_new (CLUTTER_TEXTURE (bvw->priv->texture));
1353
 
-  bvw->priv->navigation = GST_NAVIGATION (sink);
1354
 
-  if (sink == NULL)
1355
 
-    g_critical ("Could not create Clutter video sink");
1356
 
-
1357
 
-  /* The logo */
1358
 
-  bvw->priv->logo_frame = totem_aspect_frame_new ();
1359
 
-  clutter_actor_set_name (bvw->priv->logo_frame, "logo-frame");
1360
 
-  bvw->priv->logo = clutter_texture_new ();
1361
 
-  mx_bin_set_child (MX_BIN (bvw->priv->logo_frame), bvw->priv->logo);
1362
 
-  clutter_container_add_actor (CLUTTER_CONTAINER (bvw->priv->stage), bvw->priv->logo_frame);
1363
 
-  mx_bin_set_fill (MX_BIN (bvw->priv->logo_frame), FALSE, FALSE);
1364
 
-  mx_bin_set_alignment (MX_BIN (bvw->priv->logo_frame), MX_ALIGN_MIDDLE, MX_ALIGN_MIDDLE);
1365
 
-  clutter_actor_set_size (bvw->priv->logo, LOGO_SIZE, LOGO_SIZE);
1366
 
-  constraint = clutter_bind_constraint_new (bvw->priv->stage, CLUTTER_BIND_SIZE, 0.0);
1367
 
-  clutter_actor_add_constraint_with_name (bvw->priv->logo_frame, "size", constraint);
1368
 
-  clutter_actor_hide (CLUTTER_ACTOR (bvw->priv->logo_frame));
1369
 
-
1370
 
-  /* The video */
1371
 
-  bvw->priv->frame = totem_aspect_frame_new ();
1372
 
-  clutter_actor_set_name (bvw->priv->frame, "frame");
1373
 
-  mx_bin_set_child (MX_BIN (bvw->priv->frame), bvw->priv->texture);
1374
 
-
1375
 
-  clutter_container_add_actor (CLUTTER_CONTAINER (bvw->priv->stage), bvw->priv->frame);
1376
 
-  constraint = clutter_bind_constraint_new (bvw->priv->stage, CLUTTER_BIND_SIZE, 0.0);
1377
 
-  clutter_actor_add_constraint_with_name (bvw->priv->frame, "size", constraint);
1378
 
-
1379
 
-  clutter_actor_raise (CLUTTER_ACTOR (bvw->priv->frame),
1380
 
-                      CLUTTER_ACTOR (bvw->priv->logo_frame));
1381
 
-
1382
 
-  gst_bin_add (GST_BIN (bin), sink);
1383
 
-
1384
 
-  /* Add video balance */
1385
 
-  balance = gst_element_factory_make ("videobalance", "video_balance");
1386
 
-  gst_bin_add (GST_BIN (bin), balance);
1387
 
-  bvw->priv->balance = GST_COLOR_BALANCE (balance);
1388
 
-  pad = gst_element_get_static_pad (balance, "sink");
1389
 
-  ghostpad = gst_ghost_pad_new ("sink", pad);
1390
 
-  gst_element_add_pad (bin, ghostpad);
1391
 
+  if (video_sink) {
1392
 
+    GstStateChangeReturn ret;
1393
 
 
1394
 
-  gst_element_link (balance, sink);
1395
 
+    /* need to set bus explicitly as it's not in a bin yet and
1396
 
+     * poll_for_state_change() needs one to catch error messages */
1397
 
+    gst_element_set_bus (video_sink, bvw->priv->bus);
1398
 
+    /* state change NULL => READY should always be synchronous */
1399
 
+    ret = gst_element_set_state (video_sink, GST_STATE_READY);
1400
 
+    if (ret == GST_STATE_CHANGE_FAILURE) {
1401
 
+      /* Drop this video sink */
1402
 
+      gst_element_set_state (video_sink, GST_STATE_NULL);
1403
 
+      gst_object_unref (video_sink);
1404
 
+      /* Try again with ximagesink */
1405
 
+      video_sink = gst_element_factory_make ("ximagesink", "video-sink");
1406
 
+      gst_element_set_bus (video_sink, bvw->priv->bus);
1407
 
+      ret = gst_element_set_state (video_sink, GST_STATE_READY);
1408
 
+      if (ret == GST_STATE_CHANGE_FAILURE) {
1409
 
+        GstMessage *err_msg;
1410
 
 
1411
 
-  video_sink = bin;
1412
 
-  gst_element_set_state (video_sink, GST_STATE_READY);
1413
 
+        err_msg = gst_bus_poll (bvw->priv->bus, GST_MESSAGE_ERROR, 0);
1414
 
+        if (err_msg == NULL) {
1415
 
+          g_warning ("Should have gotten an error message, please file a bug.");
1416
 
+          g_set_error_literal (error, BVW_ERROR, BVW_ERROR_VIDEO_PLUGIN,
1417
 
+               _("Failed to open video output. It may not be available. "
1418
 
+                 "Please select another video output in the Multimedia "
1419
 
+                 "Systems Selector."));
1420
 
+        } else if (error) {
1421
 
+          *error = bvw_error_from_gst_error (bvw, err_msg);
1422
 
+          gst_message_unref (err_msg);
1423
 
+        }
1424
 
+        goto sink_error;
1425
 
+      }
1426
 
+    }
1427
 
+  } else {
1428
 
+    g_set_error_literal (error, BVW_ERROR, BVW_ERROR_VIDEO_PLUGIN,
1429
 
+                 _("Could not find the video output. "
1430
 
+                   "You may need to install additional GStreamer plugins, "
1431
 
+                   "or select another video output in the Multimedia Systems "
1432
 
+                   "Selector."));
1433
 
+    goto sink_error;
1434
 
+  }
1435
 
 
1436
 
   if (audio_sink) {
1437
 
     GstStateChangeReturn ret;
1438
 
@@ -6153,8 +6639,7 @@ bacon_video_widget_new (GError ** error)
1439
 
   }
1440
 
 
1441
 
   /* set back to NULL to close device again in order to avoid interrupts
1442
 
-   * being generated after startup while there's nothing to play yet
1443
 
-   * FIXME not needed anymore, PulseAudio? */
1444
 
+   * being generated after startup while there's nothing to play yet */
1445
 
   gst_element_set_state (audio_sink, GST_STATE_NULL);
1446
 
 
1447
 
   do {
1448
 
@@ -6202,6 +6687,25 @@ bacon_video_widget_new (GError ** error)
1449
 
   g_signal_connect (bvw->priv->play, "text-tags-changed",
1450
 
       G_CALLBACK (text_tags_changed_cb), bvw);
1451
 
 
1452
 
+  /* assume we're always called from the main Gtk+ GUI thread */
1453
 
+  gui_thread = g_thread_self();
1454
 
+
1455
 
+  /* we want to catch "prepare-xwindow-id" element messages synchronously */
1456
 
+  gst_bus_set_sync_handler (bvw->priv->bus, gst_bus_sync_signal_handler, bvw);
1457
 
+
1458
 
+  bvw->priv->sig_bus_sync = 
1459
 
+      g_signal_connect (bvw->priv->bus, "sync-message::element",
1460
 
+                        G_CALLBACK (bvw_element_msg_sync), bvw);
1461
 
+
1462
 
+  if (GST_IS_BIN (video_sink)) {
1463
 
+    /* video sink bins like gconfvideosink might remove their children and
1464
 
+     * create new ones when set to NULL state, and they are currently set
1465
 
+     * to NULL state whenever playbin re-creates its internal video bin
1466
 
+     * (it sets all elements to NULL state before gst_bin_remove()ing them) */
1467
 
+    g_signal_connect (video_sink, "element-added",
1468
 
+                      G_CALLBACK (got_new_video_sink_bin_element), bvw);
1469
 
+  }
1470
 
+
1471
 
   return GTK_WIDGET (bvw);
1472
 
 
1473
 
   /* errors */
1474
 
Index: totem-3.2.1/configure.in
1475
 
===================================================================
1476
 
--- totem-3.2.1.orig/configure.in       2011-12-17 00:28:44.952451020 +0100
1477
 
+++ totem-3.2.1/configure.in    2011-12-17 00:46:31.137663344 +0100
1478
 
@@ -47,7 +47,7 @@ GTK_REQS=2.99.3
1479
 
 TOTEM_PLPARSER_REQS=2.32.4
1480
 
 GNOMEICON_REQS=2.15.90
1481
 
 DBUS_REQS=0.82
1482
 
-VALA_REQS=0.12.1
1483
 
+VALA_REQS=0.11.1
1484
 
 PEAS_REQS=1.1.0
1485
 
 PYTHON_REQS=2.3
1486
 
 PYGOBJECT_REQS=2.90.3
1487
 
@@ -68,7 +68,7 @@ AC_SUBST(TOTEM_API_VERSION)
1488
 
 AC_DEFINE_UNQUOTED(TOTEM_API_VERSION, ["$TOTEM_API_VERSION"], [Define to the Totem plugin API version])
1489
 
 
1490
 
 # The full list of plugins
1491
 
-allowed_plugins="bemused brasero-disc-recorder chapters dbusservice im-status gromit iplayer lirc media-player-keys ontop opensubtitles properties publish pythonconsole rotation save-file samplepython sample-vala screensaver screenshot sidebar-test skipto youtube zeitgeist-dp grilo"
1492
 
+allowed_plugins="bemused brasero-disc-recorder chapters dbusservice im-status gromit iplayer lirc media-player-keys ontop opensubtitles properties publish pythonconsole save-file samplepython sample-vala screensaver screenshot sidebar-test skipto youtube zeitgeist-dp grilo"
1493
 
 
1494
 
 PLUGINDIR='${libdir}/totem/plugins'
1495
 
 AC_SUBST(PLUGINDIR)
1496
 
@@ -78,9 +78,6 @@ dnl release versions.
1497
 
 GST_MAJORMINOR=0.10
1498
 
 GST_REQS=0.10.30
1499
 
 GSTPLUG_REQS=0.10.30
1500
 
-CLUTTER_REQS=1.6.8
1501
 
-CLUTTER_GST_REQS=1.3.9
1502
 
-CLUTTER_GTK_REQS=1.0.2
1503
 
 
1504
 
 HAVE_GSTREAMER=no
1505
 
 
1506
 
@@ -114,7 +111,7 @@ if test "x$enable_easy_codec_installatio
1507
 
        ])
1508
 
 fi
1509
 
 
1510
 
-MM="gstreamer-0.10 >= $GST_REQS gstreamer-base-0.10 >= $GST_REQS gstreamer-plugins-base-0.10 >= $GSTPLUG_REQS gstreamer-tag-0.10 >= $GSTPLUG_REQS clutter-1.0 >= $CLUTTER_REQS clutter-gst-1.0 >= $CLUTTER_GST_REQS clutter-gtk-1.0 mx-1.0"
1511
 
+MM="gstreamer-0.10 >= $GST_REQS gstreamer-base-0.10 >= $GST_REQS gstreamer-plugins-base-0.10 >= $GSTPLUG_REQS gstreamer-tag-0.10 >= $GSTPLUG_REQS"
1512
 
 PKG_CHECK_MODULES(GST, $MM)
1513
 
 GST_LIBS="$GST_LIBS -lgstbase-$GST_MAJORMINOR -lgstinterfaces-$GST_MAJORMINOR -lgstvideo-$GST_MAJORMINOR -lgstaudio-$GST_MAJORMINOR -lgstpbutils-$GST_MAJORMINOR -lgsttag-$GST_MAJORMINOR"
1514
 
 AC_SUBST(GST_LIBS)
1515
 
@@ -220,7 +217,6 @@ PKG_CHECK_MODULES([DEPENDENCY],[
1516
 
   gmodule-2.0
1517
 
   totem-plparser >= $TOTEM_PLPARSER_REQS
1518
 
   gstreamer-tag-0.10 >= 0.10.26
1519
 
-  clutter-gtk-1.0 >= $CLUTTER_GTK_REQS
1520
 
   cairo])
1521
 
 
1522
 
 PKG_CHECK_MODULES(MM, $MM)
1523
 
@@ -457,12 +453,6 @@ for plugin in ${used_plugins}; do
1524
 
                                add_plugin="0"
1525
 
                        fi
1526
 
                ;;
1527
 
-               rotation)
1528
 
-                       if test "${with_vala}" != "yes" ; then
1529
 
-                               plugin_error_or_ignore "you need vala installed to use the rotation plugin"
1530
 
-                               add_plugin="0"
1531
 
-                       fi
1532
 
-               ;;
1533
 
                sample-vala)
1534
 
                        if test "${with_vala}" != "yes" ; then
1535
 
                                plugin_error_or_ignore "you need vala installed to use the sample-vala plugin"
1536
 
@@ -788,7 +778,6 @@ src/plugins/media-player-keys/Makefile
1537
 
 src/plugins/opensubtitles/Makefile
1538
 
 src/plugins/opensubtitles/org.gnome.totem.plugins.opensubtitles.gschema.xml.in
1539
 
 src/plugins/properties/Makefile
1540
 
-src/plugins/rotation/Makefile
1541
 
 src/plugins/save-file/Makefile
1542
 
 src/plugins/sidebar-test/Makefile
1543
 
 src/plugins/skipto/Makefile
1544
 
Index: totem-3.2.1/src/backend/bacon-video-widget.h
1545
 
===================================================================
1546
 
--- totem-3.2.1.orig/src/backend/bacon-video-widget.h   2011-12-17 00:28:45.276452603 +0100
1547
 
+++ totem-3.2.1/src/backend/bacon-video-widget.h        2011-12-17 00:46:31.137663344 +0100
1548
 
@@ -28,7 +28,7 @@
1549
 
 #ifndef HAVE_BACON_VIDEO_WIDGET_H
1550
 
 #define HAVE_BACON_VIDEO_WIDGET_H
1551
 
 
1552
 
-#include <clutter-gtk/clutter-gtk.h>
1553
 
+#include <gtk/gtk.h>
1554
 
 /* for optical disc enumeration type */
1555
 
 #include <totem-disc.h>
1556
 
 
1557
 
@@ -51,7 +51,7 @@ typedef struct BaconVideoWidgetCommon Ba
1558
 
  **/
1559
 
 typedef struct {
1560
 
        /*< private >*/
1561
 
-       GtkClutterEmbed parent;
1562
 
+       GtkEventBox parent;
1563
 
        BaconVideoWidgetPrivate *priv;
1564
 
 } BaconVideoWidget;
1565
 
 
1566
 
@@ -62,7 +62,7 @@ typedef struct {
1567
 
  **/
1568
 
 typedef struct {
1569
 
        /*< private >*/
1570
 
-       GtkClutterEmbedClass parent_class;
1571
 
+       GtkEventBoxClass parent_class;
1572
 
 
1573
 
        void (*error) (GtkWidget *bvw, const char *message,
1574
 
                        gboolean playback_stopped, gboolean fatal);
1575
 
@@ -139,8 +139,11 @@ typedef enum {
1576
 
 GQuark bacon_video_widget_error_quark           (void) G_GNUC_CONST;
1577
 
 GType bacon_video_widget_get_type                (void);
1578
 
 GOptionGroup* bacon_video_widget_get_option_group (void);
1579
 
+/* This can be used if the app does not use popt */
1580
 
+void bacon_video_widget_init_backend            (int *argc, char ***argv);
1581
 
 
1582
 
-GtkWidget *bacon_video_widget_new               (GError **error);
1583
 
+GtkWidget *bacon_video_widget_new               (int width, int height,
1584
 
+                                                  GError **error);
1585
 
 
1586
 
 char *bacon_video_widget_get_backend_name (BaconVideoWidget *bvw);
1587
 
 
1588
 
@@ -368,19 +371,6 @@ typedef enum {
1589
 
        BVW_RATIO_DVB = 4
1590
 
 } BvwAspectRatio;
1591
 
 
1592
 
-/**
1593
 
- * BvwZoomMode:
1594
 
- * @BVW_ZOOM_NONE: No video zooming/cropping
1595
 
- * @BVW_ZOOM_EXPAND: Fill area with video, and crop the excess
1596
 
- *
1597
 
- * The zoom mode used by the video widget, as set by
1598
 
- * bacon_video_widget_set_zoom().
1599
 
- **/
1600
 
-typedef enum {
1601
 
-       BVW_ZOOM_NONE = 0,
1602
 
-       BVW_ZOOM_EXPAND = 1
1603
 
-} BvwZoomMode;
1604
 
-
1605
 
 void bacon_video_widget_set_deinterlacing        (BaconVideoWidget *bvw,
1606
 
                                                  gboolean deinterlace);
1607
 
 gboolean bacon_video_widget_get_deinterlacing    (BaconVideoWidget *bvw);
1608
 
@@ -394,8 +384,8 @@ void bacon_video_widget_set_scale_ratio
1609
 
                                                  float ratio);
1610
 
 
1611
 
 void bacon_video_widget_set_zoom                (BaconVideoWidget *bvw,
1612
 
-                                                 BvwZoomMode       mode);
1613
 
-BvwZoomMode bacon_video_widget_get_zoom                 (BaconVideoWidget *bvw);
1614
 
+                                                 double zoom);
1615
 
+double bacon_video_widget_get_zoom              (BaconVideoWidget *bvw);
1616
 
 
1617
 
 int bacon_video_widget_get_video_property        (BaconVideoWidget *bvw,
1618
 
                                                  BvwVideoProperty type);
1619
 
Index: totem-3.2.1/src/backend/Makefile.am
1620
 
===================================================================
1621
 
--- totem-3.2.1.orig/src/backend/Makefile.am    2011-12-17 00:28:45.236452408 +0100
1622
 
+++ totem-3.2.1/src/backend/Makefile.am 2011-12-17 00:46:31.137663344 +0100
1623
 
@@ -12,7 +12,6 @@ bvw_test_CPPFLAGS = \
1624
 
 
1625
 
 bvw_test_CFLAGS = \
1626
 
        $(DEPENDENCY_CFLAGS)    \
1627
 
-       $(MM_CFLAGS)            \
1628
 
        $(AM_CFLAGS)
1629
 
 
1630
 
 bvw_test_LDADD = \
1631
 
@@ -54,9 +53,7 @@ libbaconvideowidget_la_SOURCES = \
1632
 
        video-utils.c video-utils.h                     \
1633
 
        bacon-video-widget-gst-0.10.c                   \
1634
 
        bacon-video-widget-gst-missing-plugins.c        \
1635
 
-       bacon-video-widget-gst-missing-plugins.h        \
1636
 
-       totem-aspect-frame.h                            \
1637
 
-       totem-aspect-frame.c
1638
 
+       bacon-video-widget-gst-missing-plugins.h
1639
 
 
1640
 
 libbaconvideowidget_la_CPPFLAGS = \
1641
 
        -D_REENTRANT                            \
1642
 
Index: totem-3.2.1/data/totem.ui
1643
 
===================================================================
1644
 
--- totem-3.2.1.orig/data/totem.ui      2011-12-17 00:28:44.916450849 +0100
1645
 
+++ totem-3.2.1/data/totem.ui   2011-12-17 00:46:31.141663355 +0100
1646
 
@@ -362,15 +362,36 @@
1647
 
                <property name="hide-if-empty">False</property>
1648
 
             </object>
1649
 
          </child>
1650
 
-
1651
 
+      </object>
1652
 
+   </child>
1653
 
+   <child>
1654
 
+      <object class="GtkActionGroup" id="zoom-action-group">
1655
 
          <child>
1656
 
-            <object class="GtkToggleAction" id="zoom-toggle">
1657
 
+            <object class="GtkAction" id="zoom-in">
1658
 
                <property name="label" translatable="yes">Zoom In</property>
1659
 
                <property name="stock-id">gtk-zoom-in</property>
1660
 
                <property name="tooltip" translatable="yes">Zoom in</property>
1661
 
-               <signal name="activate" handler="zoom_toggle_action_callback"/>
1662
 
+               <signal name="activate" handler="zoom_in_action_callback"/>
1663
 
+            </object>
1664
 
+            <accelerator key="R" modifiers="GDK_CONTROL_MASK"/>
1665
 
+         </child>
1666
 
+         <child>
1667
 
+            <object class="GtkAction" id="zoom-reset">
1668
 
+               <property name="label" translatable="yes">Zoom Reset</property>
1669
 
+               <property name="stock-id">gtk-zoom-100</property>
1670
 
+               <property name="tooltip" translatable="yes">Zoom reset</property>
1671
 
+               <signal name="activate" handler="zoom_reset_action_callback"/>
1672
 
+            </object>
1673
 
+            <accelerator key="0" modifiers="GDK_CONTROL_MASK"/>
1674
 
+         </child>
1675
 
+         <child>
1676
 
+            <object class="GtkAction" id="zoom-out">
1677
 
+               <property name="label" translatable="yes">Zoom Out</property>
1678
 
+               <property name="stock-id">gtk-zoom-out</property>
1679
 
+               <property name="tooltip" translatable="yes">Zoom out</property>
1680
 
+               <signal name="activate" handler="zoom_out_action_callback"/>
1681
 
             </object>
1682
 
-            <accelerator key="Z" modifiers="GDK_CONTROL_MASK"/>
1683
 
+            <accelerator key="T" modifiers="GDK_CONTROL_MASK"/>
1684
 
          </child>
1685
 
       </object>
1686
 
    </child>
1687
 
@@ -431,7 +452,9 @@
1688
 
                <menuitem name="zoom-1-1" action="zoom-1-1"/>
1689
 
                <menuitem name="zoom-2-1" action="zoom-2-1"/>
1690
 
             </menu>
1691
 
-            <menuitem name="zoom-toggle" action="zoom-toggle"/>
1692
 
+            <menuitem name="zoom-in" action="zoom-in"/>
1693
 
+            <menuitem name="zoom-reset" action="zoom-reset"/>
1694
 
+            <menuitem name="zoom-out" action="zoom-out"/>
1695
 
             <separator/>
1696
 
             <menu name="aspect-ratio" action="aspect-ratio-menu">
1697
 
                <menuitem name="aspect-ratio-auto" action="aspect-ratio-auto"/>
1698
 
Index: totem-3.2.1/src/backend/bvw-test.c
1699
 
===================================================================
1700
 
--- totem-3.2.1.orig/src/backend/bvw-test.c     2011-12-17 00:28:45.200452237 +0100
1701
 
+++ totem-3.2.1/src/backend/bvw-test.c  2011-12-17 00:46:31.141663355 +0100
1702
 
@@ -76,6 +76,8 @@ int main
1703
 
        GOptionGroup *baconoptiongroup;
1704
 
        GError *error = NULL;
1705
 
        GtkWidget *win, *bvw;
1706
 
+       guint32 height = 500;
1707
 
+       guint32 width = 500;
1708
 
 
1709
 
 #ifdef GDK_WINDOWING_X11
1710
 
        XInitThreads ();
1711
 
@@ -105,13 +107,12 @@ int main
1712
 
        }
1713
 
 
1714
 
        win = gtk_window_new (GTK_WINDOW_TOPLEVEL);
1715
 
-       gtk_window_set_default_size (GTK_WINDOW (win), 500, 500);
1716
 
+       gtk_window_set_default_size (GTK_WINDOW (win), width, height);
1717
 
        g_signal_connect (G_OBJECT (win), "destroy",
1718
 
                        G_CALLBACK (gtk_main_quit), NULL);
1719
 
 
1720
 
-       bvw = bacon_video_widget_new (NULL);
1721
 
+       bvw = bacon_video_widget_new (width, height, NULL);
1722
 
        bacon_video_widget_set_logo (BACON_VIDEO_WIDGET (bvw), "totem");
1723
 
-       bacon_video_widget_set_show_visualizations (BACON_VIDEO_WIDGET (bvw), TRUE);
1724
 
 
1725
 
        g_signal_connect (G_OBJECT (bvw), "eos", G_CALLBACK (on_eos_event), NULL);
1726
 
        g_signal_connect (G_OBJECT (bvw), "got-metadata", G_CALLBACK (on_got_metadata), NULL);
1727
 
@@ -126,13 +127,10 @@ int main
1728
 
        gtk_widget_show (win);
1729
 
        gtk_widget_show (bvw);
1730
 
 
1731
 
-       if (filenames && filenames[0]) {
1732
 
-               test_bvw_set_mrl (bvw, filenames[0]);
1733
 
-               argument = g_strdup (filenames[0]);
1734
 
-               bacon_video_widget_play (BACON_VIDEO_WIDGET (bvw), NULL);
1735
 
-       } else {
1736
 
-               bacon_video_widget_set_logo_mode (BACON_VIDEO_WIDGET (bvw), TRUE);
1737
 
-       }
1738
 
+       mrl = NULL;
1739
 
+       test_bvw_set_mrl (bvw, (filenames && filenames[0]) ? filenames[0] : LOGO_PATH);
1740
 
+       argument = g_strdup ((filenames && filenames[0]) ? filenames[0] : LOGO_PATH);
1741
 
+       bacon_video_widget_play (BACON_VIDEO_WIDGET (bvw), NULL);
1742
 
 
1743
 
        gtk_main ();
1744
 
 
1745
 
Index: totem-3.2.1/browser-plugin/totem-plugin-viewer.c
1746
 
===================================================================
1747
 
--- totem-3.2.1.orig/browser-plugin/totem-plugin-viewer.c       2011-12-17 00:28:44.872450633 +0100
1748
 
+++ totem-3.2.1/browser-plugin/totem-plugin-viewer.c    2011-12-17 00:46:31.141663355 +0100
1749
 
@@ -1760,7 +1760,7 @@ totem_embedded_construct (TotemEmbedded
1750
 
 
1751
 
        /* if (emb->hidden || emb->audioonly != FALSE)
1752
 
         * FIXME disable video decoding */
1753
 
-       emb->bvw = BACON_VIDEO_WIDGET (bacon_video_widget_new (&err));
1754
 
+       emb->bvw = BACON_VIDEO_WIDGET (bacon_video_widget_new (width, height, &err));
1755
 
 
1756
 
        /* FIXME: check the UA strings of the legacy plugins themselves */
1757
 
        /* FIXME: at least hxplayer seems to send different UAs depending on the protocol!? */
1758
 
Index: totem-3.2.1/src/totem-menu.c
1759
 
===================================================================
1760
 
--- totem-3.2.1.orig/src/totem-menu.c   2011-12-17 00:28:45.108451785 +0100
1761
 
+++ totem-3.2.1/src/totem-menu.c        2011-12-17 00:46:31.141663355 +0100
1762
 
@@ -53,7 +53,9 @@ G_MODULE_EXPORT void fullscreen_action_c
1763
 
 G_MODULE_EXPORT void zoom_1_2_action_callback (GtkAction *action, Totem *totem);
1764
 
 G_MODULE_EXPORT void zoom_1_1_action_callback (GtkAction *action, Totem *totem);
1765
 
 G_MODULE_EXPORT void zoom_2_1_action_callback (GtkAction *action, Totem *totem);
1766
 
-G_MODULE_EXPORT void zoom_toggle_action_callback (GtkToggleAction *action, Totem *totem);
1767
 
+G_MODULE_EXPORT void zoom_in_action_callback (GtkAction *action, Totem *totem);
1768
 
+G_MODULE_EXPORT void zoom_reset_action_callback (GtkAction *action, Totem *totem);
1769
 
+G_MODULE_EXPORT void zoom_out_action_callback (GtkAction *action, Totem *totem);
1770
 
 G_MODULE_EXPORT void next_angle_action_callback (GtkAction *action, Totem *totem);
1771
 
 G_MODULE_EXPORT void dvd_root_menu_action_callback (GtkAction *action, Totem *totem);
1772
 
 G_MODULE_EXPORT void dvd_title_menu_action_callback (GtkAction *action, Totem *totem);
1773
 
@@ -1073,11 +1075,21 @@ zoom_2_1_action_callback (GtkAction *act
1774
 
 }
1775
 
 
1776
 
 void
1777
 
-zoom_toggle_action_callback (GtkToggleAction *action,
1778
 
-                            Totem           *totem)
1779
 
+zoom_in_action_callback (GtkAction *action, Totem *totem)
1780
 
 {
1781
 
-       bacon_video_widget_set_zoom (totem->bvw,
1782
 
-                                    gtk_toggle_action_get_active (action) ? BVW_ZOOM_EXPAND : BVW_ZOOM_NONE);
1783
 
+       totem_action_zoom_relative (totem, ZOOM_IN_OFFSET);
1784
 
+}
1785
 
+
1786
 
+void
1787
 
+zoom_reset_action_callback (GtkAction *action, Totem *totem)
1788
 
+{
1789
 
+       totem_action_zoom_reset (totem);
1790
 
+}
1791
 
+
1792
 
+void
1793
 
+zoom_out_action_callback (GtkAction *action, Totem *totem)
1794
 
+{
1795
 
+       totem_action_zoom_relative (totem, ZOOM_OUT_OFFSET);
1796
 
 }
1797
 
 
1798
 
 void
1799
 
@@ -1367,6 +1379,7 @@ void
1800
 
 totem_ui_manager_setup (Totem *totem)
1801
 
 {
1802
 
        totem->main_action_group = GTK_ACTION_GROUP (gtk_builder_get_object (totem->xml, "main-action-group"));
1803
 
+       totem->zoom_action_group = GTK_ACTION_GROUP (gtk_builder_get_object (totem->xml, "zoom-action-group"));
1804
 
 
1805
 
        /* FIXME: Moving these to GtkBuilder depends on bug #457631 */
1806
 
        if (gtk_widget_get_direction (totem->win) == GTK_TEXT_DIR_RTL) {
1807
 
Index: totem-3.2.1/src/totem-object.c
1808
 
===================================================================
1809
 
--- totem-3.2.1.orig/src/totem-object.c 2011-12-17 00:28:45.072451608 +0100
1810
 
+++ totem-3.2.1/src/totem-object.c      2011-12-17 00:46:31.145663367 +0100
1811
 
@@ -81,6 +81,12 @@
1812
 
 #define SEEK_FORWARD_LONG_OFFSET 10*60
1813
 
 #define SEEK_BACKWARD_LONG_OFFSET -3*60
1814
 
 
1815
 
+#define ZOOM_UPPER 2.0
1816
 
+#define ZOOM_RESET 1.0
1817
 
+#define ZOOM_LOWER 0.1
1818
 
+#define ZOOM_DISABLE (ZOOM_LOWER - 1)
1819
 
+#define ZOOM_ENABLE (ZOOM_UPPER + 1)
1820
 
+
1821
 
 #define DEFAULT_WINDOW_W 650
1822
 
 #define DEFAULT_WINDOW_H 500
1823
 
 
1824
 
@@ -1996,14 +2002,58 @@ totem_object_action_seek_time (TotemObje
1825
 
        totem_seek_time_rel (totem, msec, FALSE, accurate);
1826
 
 }
1827
 
 
1828
 
-void
1829
 
-totem_action_set_zoom (TotemObject *totem,
1830
 
-                      gboolean     zoom)
1831
 
+static void
1832
 
+totem_action_zoom (TotemObject *totem, double zoom)
1833
 
 {
1834
 
        GtkAction *action;
1835
 
+       gboolean zoom_reset, zoom_in, zoom_out;
1836
 
+
1837
 
+       if (totem->bvw == NULL)
1838
 
+               return;
1839
 
+
1840
 
+       if (zoom == ZOOM_ENABLE)
1841
 
+               zoom = bacon_video_widget_get_zoom (totem->bvw);
1842
 
+
1843
 
+       if (zoom == ZOOM_DISABLE) {
1844
 
+               zoom_reset = zoom_in = zoom_out = FALSE;
1845
 
+       } else if (zoom < ZOOM_LOWER || zoom > ZOOM_UPPER) {
1846
 
+               return;
1847
 
+       } else {
1848
 
+               bacon_video_widget_set_zoom (totem->bvw, zoom);
1849
 
+               zoom_reset = (zoom != ZOOM_RESET);
1850
 
+               zoom_out = zoom != ZOOM_LOWER;
1851
 
+               zoom_in = zoom != ZOOM_UPPER;
1852
 
+       }
1853
 
+
1854
 
+       action = gtk_action_group_get_action (totem->zoom_action_group,
1855
 
+                       "zoom-in");
1856
 
+       gtk_action_set_sensitive (action, zoom_in);
1857
 
+
1858
 
+       action = gtk_action_group_get_action (totem->zoom_action_group,
1859
 
+                       "zoom-out");
1860
 
+       gtk_action_set_sensitive (action, zoom_out);
1861
 
+
1862
 
+       action = gtk_action_group_get_action (totem->zoom_action_group,
1863
 
+                       "zoom-reset");
1864
 
+       gtk_action_set_sensitive (action, zoom_reset);
1865
 
+}
1866
 
 
1867
 
-       action = gtk_action_group_get_action (totem->main_action_group, "zoom-toggle");
1868
 
-       gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (action), zoom);
1869
 
+void
1870
 
+totem_action_zoom_relative (TotemObject *totem, double off_pct)
1871
 
+{
1872
 
+       double zoom;
1873
 
+
1874
 
+       if (totem->bvw == NULL)
1875
 
+               return;
1876
 
+
1877
 
+       zoom = bacon_video_widget_get_zoom (totem->bvw);
1878
 
+       totem_action_zoom (totem, zoom + off_pct);
1879
 
+}
1880
 
+
1881
 
+void
1882
 
+totem_action_zoom_reset (TotemObject *totem)
1883
 
+{
1884
 
+       totem_action_zoom (totem, ZOOM_RESET);
1885
 
 }
1886
 
 
1887
 
 /**
1888
 
@@ -2656,6 +2706,14 @@ property_notify_cb_volume (BaconVideoWid
1889
 
 }
1890
 
 
1891
 
 static void
1892
 
+property_notify_cb_logo_mode (BaconVideoWidget *bvw, GParamSpec *spec, TotemObject *totem)
1893
 
+{
1894
 
+       gboolean enabled;
1895
 
+       enabled = bacon_video_widget_get_logo_mode (totem->bvw);
1896
 
+       totem_action_zoom (totem, enabled ? ZOOM_DISABLE : ZOOM_ENABLE);
1897
 
+}
1898
 
+
1899
 
+static void
1900
 
 property_notify_cb_seekable (BaconVideoWidget *bvw, GParamSpec *spec, TotemObject *totem)
1901
 
 {
1902
 
        update_seekable (totem);
1903
 
@@ -3143,10 +3201,10 @@ totem_object_action_remote (TotemObject
1904
 
                                BVW_DVD_ROOT_MENU);
1905
 
                break;
1906
 
        case TOTEM_REMOTE_COMMAND_ZOOM_UP:
1907
 
-               totem_action_set_zoom (totem, TRUE);
1908
 
+               totem_action_zoom_relative (totem, ZOOM_IN_OFFSET);
1909
 
                break;
1910
 
        case TOTEM_REMOTE_COMMAND_ZOOM_DOWN:
1911
 
-               totem_action_set_zoom (totem, FALSE);
1912
 
+               totem_action_zoom_relative (totem, ZOOM_OUT_OFFSET);
1913
 
                break;
1914
 
        case TOTEM_REMOTE_COMMAND_EJECT:
1915
 
                totem_action_eject (totem);
1916
 
@@ -3606,12 +3664,12 @@ totem_action_handle_key_press (TotemObje
1917
 
        case GDK_KEY_r:
1918
 
        case GDK_KEY_R:
1919
 
        case GDK_KEY_ZoomIn:
1920
 
-               totem_action_set_zoom (totem, TRUE);
1921
 
+               totem_action_zoom_relative (totem, ZOOM_IN_OFFSET);
1922
 
                break;
1923
 
        case GDK_KEY_t:
1924
 
        case GDK_KEY_T:
1925
 
        case GDK_KEY_ZoomOut:
1926
 
-               totem_action_set_zoom (totem, FALSE);
1927
 
+               totem_action_zoom_relative (totem, ZOOM_OUT_OFFSET);
1928
 
                break;
1929
 
        case GDK_KEY_Eject:
1930
 
                totem_action_eject (totem);
1931
 
@@ -3683,7 +3741,7 @@ totem_action_handle_key_press (TotemObje
1932
 
                break;
1933
 
        case GDK_KEY_0:
1934
 
                if (event->state & GDK_CONTROL_MASK)
1935
 
-                       totem_action_set_zoom (totem, FALSE);
1936
 
+                       totem_action_zoom_reset (totem);
1937
 
                else
1938
 
                        totem_action_set_scale_ratio (totem, 0.5);
1939
 
                break;
1940
 
@@ -3707,18 +3765,18 @@ totem_action_handle_key_press (TotemObje
1941
 
                break;
1942
 
        case GDK_KEY_equal:
1943
 
                if (event->state & GDK_CONTROL_MASK)
1944
 
-                       totem_action_set_zoom (totem, TRUE);
1945
 
+                       totem_action_zoom_relative (totem, ZOOM_IN_OFFSET);
1946
 
                break;
1947
 
        case GDK_KEY_hyphen:
1948
 
                if (event->state & GDK_CONTROL_MASK)
1949
 
-                       totem_action_set_zoom (totem, FALSE);
1950
 
+                       totem_action_zoom_relative (totem, ZOOM_OUT_OFFSET);
1951
 
                break;
1952
 
        case GDK_KEY_plus:
1953
 
        case GDK_KEY_KP_Add:
1954
 
                if (!(event->state & GDK_CONTROL_MASK)) {
1955
 
                        totem_action_next (totem);
1956
 
                } else {
1957
 
-                       totem_action_set_zoom (totem, TRUE);
1958
 
+                       totem_action_zoom_relative (totem, ZOOM_IN_OFFSET);
1959
 
                }
1960
 
                break;
1961
 
        case GDK_KEY_minus:
1962
 
@@ -3726,7 +3784,7 @@ totem_action_handle_key_press (TotemObje
1963
 
                if (!(event->state & GDK_CONTROL_MASK)) {
1964
 
                        totem_action_previous (totem);
1965
 
                } else {
1966
 
-                       totem_action_set_zoom (totem, FALSE);
1967
 
+                       totem_action_zoom_relative (totem, ZOOM_OUT_OFFSET);
1968
 
                }
1969
 
                break;
1970
 
        case GDK_KEY_KP_Up:
1971
 
@@ -4219,7 +4277,7 @@ video_widget_create (TotemObject *totem)
1972
 
        GtkContainer *container;
1973
 
        BaconVideoWidget **bvw;
1974
 
 
1975
 
-       totem->bvw = BACON_VIDEO_WIDGET (bacon_video_widget_new (&err));
1976
 
+       totem->bvw = BACON_VIDEO_WIDGET (bacon_video_widget_new (-1, -1, &err));
1977
 
 
1978
 
        if (totem->bvw == NULL) {
1979
 
                totem_action_error_and_exit (_("Totem could not startup."), err != NULL ? err->message : _("No reason."), totem);
1980
 
@@ -4227,6 +4285,8 @@ video_widget_create (TotemObject *totem)
1981
 
                        g_error_free (err);
1982
 
        }
1983
 
 
1984
 
+       totem_action_zoom (totem, ZOOM_RESET);
1985
 
+
1986
 
        g_signal_connect_after (G_OBJECT (totem->bvw),
1987
 
                        "button-press-event",
1988
 
                        G_CALLBACK (on_video_button_press_event),
1989
 
@@ -4298,6 +4358,8 @@ video_widget_create (TotemObject *totem)
1990
 
 
1991
 
        g_signal_connect (G_OBJECT (totem->bvw), "notify::volume",
1992
 
                        G_CALLBACK (property_notify_cb_volume), totem);
1993
 
+       g_signal_connect (G_OBJECT (totem->bvw), "notify::logo-mode",
1994
 
+                       G_CALLBACK (property_notify_cb_logo_mode), totem);
1995
 
        g_signal_connect (G_OBJECT (totem->bvw), "notify::seekable",
1996
 
                        G_CALLBACK (property_notify_cb_seekable), totem);
1997
 
        update_volume_sliders (totem);
1998
 
Index: totem-3.2.1/src/totem-private.h
1999
 
===================================================================
2000
 
--- totem-3.2.1.orig/src/totem-private.h        2011-12-17 00:28:45.028451391 +0100
2001
 
+++ totem-3.2.1/src/totem-private.h     2011-12-17 00:46:31.145663367 +0100
2002
 
@@ -80,6 +80,7 @@ struct _TotemObject {
2003
 
 
2004
 
        /* UI manager */
2005
 
        GtkActionGroup *main_action_group;
2006
 
+       GtkActionGroup *zoom_action_group;
2007
 
        GtkUIManager *ui_manager;
2008
 
 
2009
 
        GtkActionGroup *devices_action_group;
2010
 
@@ -176,7 +177,8 @@ GtkWidget *totem_volume_create (void);
2011
 
 void   totem_action_open                       (Totem *totem);
2012
 
 void   totem_action_open_location              (Totem *totem);
2013
 
 void   totem_action_eject                      (Totem *totem);
2014
 
-void   totem_action_set_zoom                   (Totem *totem, gboolean zoom);
2015
 
+void   totem_action_zoom_relative              (Totem *totem, double off_pct);
2016
 
+void   totem_action_zoom_reset                 (Totem *totem);
2017
 
 void   totem_action_show_help                  (Totem *totem);
2018
 
 void   totem_action_show_properties            (Totem *totem);
2019
 
 gboolean totem_action_open_files               (Totem *totem, char **list);