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
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
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 */
25
/* for the cover metadata info */
26
#include <gst/tag/tag.h>
28
-#include <clutter-gst/clutter-gst.h>
30
-#include "totem-aspect-frame.h"
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 */
43
#define NANOSECS_IN_SEC 1000000000
46
#define I_(string) (g_intern_static_string (string))
48
-G_DEFINE_TYPE (BaconVideoWidget, bacon_video_widget, GTK_CLUTTER_TYPE_EMBED)
49
+G_DEFINE_TYPE (BaconVideoWidget, bacon_video_widget, GTK_TYPE_EVENT_BOX)
53
@@ -163,8 +162,11 @@ struct BaconVideoWidgetPrivate
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 */
67
@@ -190,13 +192,7 @@ struct BaconVideoWidgetPrivate
69
gboolean got_redirect;
71
- ClutterActor *stage;
72
- ClutterActor *texture;
73
- ClutterActor *frame;
75
- ClutterActor *logo_frame;
78
+ GdkWindow *video_window;
82
@@ -227,12 +223,15 @@ struct BaconVideoWidgetPrivate
90
BvwAudioOutputType speakersetup;
91
gint connection_speed;
94
+ gulong sig_bus_sync;
98
@@ -282,8 +281,11 @@ static void bacon_video_widget_get_prope
100
static void bacon_video_widget_finalize (GObject * object);
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
112
static int bvw_signals[LAST_SIGNAL] = { 0 };
114
+static GThread *gui_thread;
116
GST_DEBUG_CATEGORY (_totem_gst_debug_cat);
117
#define GST_CAT_DEFAULT _totem_gst_debug_cat
119
@@ -395,50 +399,6 @@ bvw_check_if_video_decoder_is_missing (B
123
-set_display_pixel_aspect_ratio (GdkScreen *screen,
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 */
140
-#define DELTA(idx) (ABS (ratio - ((gdouble) par[idx][0] / par[idx][1])))
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));
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 */
152
- for (i = 1; i < sizeof (par) / (sizeof (gint) * 2); ++i) {
153
- gdouble this_delta = DELTA (i);
155
- if (this_delta < delta) {
157
- delta = this_delta;
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]);
167
get_media_size (BaconVideoWidget *bvw, gint *width, gint *height)
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;
176
/* Create and init the fraction value */
177
g_value_init (&disp_par, GST_TYPE_FRACTION);
179
/* Square pixel is our default */
180
gst_value_set_fraction (&disp_par, 1, 1);
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;
190
+ klass = G_OBJECT_GET_CLASS (bvw->priv->xoverlay);
191
+ pspec = g_object_class_find_property (klass, "pixel-aspect-ratio");
193
+ if (pspec != NULL) {
194
+ GValue disp_par_prop = { 0, };
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);
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);
205
+ g_value_unset (&disp_par_prop);
209
disp_par_n = gst_value_get_fraction_numerator (&disp_par);
210
disp_par_d = gst_value_get_fraction_denominator (&disp_par);
213
GST_DEBUG ("display PAR is %d/%d", disp_par_n, disp_par_d);
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
221
g_assert_not_reached ();
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;
232
GST_DEBUG ("movie PAR is %d/%d", movie_par_n, movie_par_d);
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)
238
BaconVideoWidget *bvw = BACON_VIDEO_WIDGET (widget);
239
+ GdkWindowAttr attributes;
240
+ gint attributes_mask;
241
+ GdkColor black = { 0, 0, 0 };
243
+ GdkEventMask event_mask;
244
+ GtkAllocation allocation;
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);
252
GTK_WIDGET_CLASS (parent_class)->realize (widget);
254
+ window = gtk_widget_get_window (widget);
255
+ gdk_window_ensure_native (window);
257
+ /* Creating our video window */
258
+ attributes.window_type = GDK_WINDOW_CHILD;
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;
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);
279
+ gdk_window_set_background (window, &black);
281
gtk_widget_set_realized (widget, TRUE);
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);
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);
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);
299
bacon_video_widget_gst_missing_plugins_setup (bvw);
303
+bacon_video_widget_show (GtkWidget *widget)
305
+ BaconVideoWidget *bvw = BACON_VIDEO_WIDGET (widget);
308
+ window = gtk_widget_get_window (widget);
310
+ gdk_window_show (window);
311
+ if (bvw->priv->video_window)
312
+ gdk_window_show (bvw->priv->video_window);
314
+ if (GTK_WIDGET_CLASS (parent_class)->show)
315
+ GTK_WIDGET_CLASS (parent_class)->show (widget);
319
+bacon_video_widget_hide (GtkWidget *widget)
321
+ BaconVideoWidget *bvw = BACON_VIDEO_WIDGET (widget);
324
+ window = gtk_widget_get_window (widget);
326
+ gdk_window_hide (window);
327
+ if (bvw->priv->video_window)
328
+ gdk_window_hide (bvw->priv->video_window);
330
+ if (GTK_WIDGET_CLASS (parent_class)->hide)
331
+ GTK_WIDGET_CLASS (parent_class)->hide (widget);
335
+bacon_video_widget_configure_event (GtkWidget *widget, GdkEventConfigure *event,
336
+ BaconVideoWidget *bvw)
338
+ GstXOverlay *xoverlay = NULL;
340
+ g_return_val_if_fail (bvw != NULL, FALSE);
341
+ g_return_val_if_fail (BACON_IS_VIDEO_WIDGET (bvw), FALSE);
343
+ xoverlay = bvw->priv->xoverlay;
345
+ if (xoverlay != NULL && GST_IS_X_OVERLAY (xoverlay)) {
346
+ gst_x_overlay_expose (xoverlay);
353
size_changed_cb (GdkScreen *screen, BaconVideoWidget *bvw)
360
-set_current_actor (BaconVideoWidget *bvw)
362
+bacon_video_widget_draw (GtkWidget *widget, cairo_t *cr)
364
+ BaconVideoWidget *bvw = BACON_VIDEO_WIDGET (widget);
365
+ GstXOverlay *xoverlay;
368
+ GtkAllocation allocation;
370
- if (bvw->priv->stage == NULL)
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;
378
+ if (xoverlay != NULL)
379
+ gst_object_ref (xoverlay);
381
+ g_mutex_unlock (bvw->priv->lock);
383
+ window = gdk_x11_window_get_xid (bvw->priv->video_window);
385
+ if (xoverlay != NULL && GST_IS_X_OVERLAY (xoverlay))
386
+ gst_x_overlay_set_xwindow_id (xoverlay, window);
388
+ /* Start with a nice black canvas */
389
+ gtk_widget_get_allocation (widget, &allocation);
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
395
pixbuf = bvw_get_logo_pixbuf (bvw);
396
if (pixbuf != NULL) {
398
- GError *err = NULL;
399
+ /* draw logo here */
400
+ gint s_width, s_height, d_width, d_height;
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;
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;
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;
426
- clutter_actor_show (CLUTTER_ACTOR (bvw->priv->logo_frame));
427
- clutter_actor_hide (CLUTTER_ACTOR (bvw->priv->frame));
429
+ ratio = (gfloat) d_width / s_width;
432
+ /* center the current point, then scale the context so the logo fills up
434
+ cairo_translate (cr, allocation.width / 2, allocation.height / 2);
435
+ cairo_scale (cr, ratio, ratio);
437
+ /* fill with black */
438
+ cairo_set_source_rgb (cr, 0, 0, 0);
441
+ /* then draw logo on top */
442
+ gdk_cairo_set_source_pixbuf (cr, pixbuf, - s_width / 2, - s_height / 2);
445
+ } else if (xoverlay != NULL && GST_IS_X_OVERLAY (xoverlay)) {
446
+ /* no logo, use gst */
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);
454
+ /* let gst paint the video */
455
+ if (gtk_cairo_should_draw_window (cr, bvw->priv->video_window))
456
+ gst_x_overlay_expose (xoverlay);
458
+ /* if not even gst exists, just paint black */
459
+ cairo_set_source_rgb (cr, 0, 0, 0);
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);
471
+static GstNavigation *
472
+bvw_get_navigation_iface (BaconVideoWidget *bvw, gboolean update_interfaces)
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);
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.
488
@@ -651,8 +787,13 @@ bacon_video_widget_motion_notify (GtkWid
490
g_return_val_if_fail (bvw->priv->play != NULL, FALSE);
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);
497
+ gst_navigation_send_mouse_event (nav, "mouse-move", 0, event->x, event->y);
498
+ gst_object_unref (GST_OBJECT (nav));
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);
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);
511
- /* FIXME need to check whether the backend will have handled
514
+ GstNavigation *nav = bvw_get_navigation_iface (bvw, FALSE);
516
+ gst_navigation_send_mouse_event (nav,
517
+ "mouse-button-press", event->button, event->x, event->y);
518
+ gst_object_unref (GST_OBJECT (nav));
520
+ /* FIXME need to check whether the backend will have handled
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);
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);
535
+ gst_navigation_send_mouse_event (nav,
536
+ "mouse-button-release", event->button, event->x, event->y);
537
+ gst_object_unref (GST_OBJECT (nav));
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;
550
+resize_video_window (BaconVideoWidget *bvw)
552
+ GtkAllocation allocation;
553
+ gfloat width, height, ratio, x, y;
556
+ g_return_if_fail (bvw != NULL);
557
+ g_return_if_fail (BACON_IS_VIDEO_WIDGET (bvw));
559
+ gtk_widget_get_allocation (GTK_WIDGET (bvw), &allocation);
561
+ get_media_size (bvw, &w, &h);
563
+ w = allocation.width;
564
+ h = allocation.height;
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;
574
+ ratio = (gfloat) allocation.width / width;
577
+ /* apply zoom factor */
578
+ ratio = ratio * bvw->priv->zoom;
582
+ x = (allocation.width - width) / 2;
583
+ y = (allocation.height - height) / 2;
585
+ gdk_window_move_resize (bvw->priv->video_window, x, y, width, height);
586
+ gtk_widget_queue_draw (GTK_WIDGET (bvw));
590
+bacon_video_widget_size_allocate (GtkWidget *widget, GtkAllocation *allocation)
592
+ BaconVideoWidget *bvw = BACON_VIDEO_WIDGET (widget);
594
+ g_return_if_fail (widget != NULL);
595
+ g_return_if_fail (BACON_IS_VIDEO_WIDGET (widget));
597
+ gtk_widget_set_allocation (widget, allocation);
599
+ if (gtk_widget_get_realized (widget)) {
601
+ gdk_window_move_resize (gtk_widget_get_window (widget),
602
+ allocation->x, allocation->y,
603
+ allocation->width, allocation->height);
605
+ resize_video_window (bvw);
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
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;
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;
630
gtk_widget_set_can_focus (GTK_WIDGET (bvw), TRUE);
631
+ gtk_widget_set_double_buffered (GTK_WIDGET (bvw), FALSE);
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;
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;
647
+ priv->lock = g_mutex_new ();
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)
655
const gchar *msg_name;
656
+ GtkAllocation allocation;
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);
663
else if (strcmp (msg_name, "video-size") == 0) {
666
g_signal_emit (bvw, bvw_signals[SIGNAL_GOT_METADATA], 0, NULL);
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);
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);
678
+ gtk_widget_get_allocation (GTK_WIDGET (bvw), &allocation);
679
+ bacon_video_widget_size_allocate (GTK_WIDGET (bvw),
682
bvw->priv->window_resized = TRUE;
683
- set_current_actor (bvw);
685
g_message ("Unhandled application message %s", msg_name);
687
@@ -1227,7 +1438,16 @@ bvw_handle_application_message (BaconVid
689
bvw_do_navigation_query (BaconVideoWidget * bvw, GstQuery *query)
691
- return gst_element_query (GST_ELEMENT_CAST (bvw->priv->navigation), query);
692
+ GstNavigation *nav = bvw_get_navigation_iface (bvw, TRUE);
695
+ if (G_UNLIKELY (nav == NULL || !GST_IS_ELEMENT (nav)))
698
+ res = gst_element_query (GST_ELEMENT_CAST (nav), query);
699
+ gst_object_unref (GST_OBJECT (nav));
705
@@ -1307,6 +1527,10 @@ bvw_handle_element_message (BaconVideoWi
706
g_signal_emit (bvw, bvw_signals[SIGNAL_BUFFERING], 0, percent);
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 */
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);
719
g_signal_emit (bvw, bvw_signals[SIGNAL_GOT_METADATA], 0);
721
- set_current_actor (bvw);
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);
729
- bvw_check_for_cover_pixbuf (bvw);
731
bvw->priv->media_has_video = FALSE;
735
bvw->priv->media_has_video = TRUE;
736
+ if (bvw->priv->video_window)
737
+ gdk_window_show (bvw->priv->video_window);
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;
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) {
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;
757
+ gdk_window_hide (bvw->priv->video_window);
758
+ gtk_widget_set_double_buffered (GTK_WIDGET (bvw), TRUE);
759
flags &= ~GST_PLAY_FLAG_VIS;
761
g_object_set (bvw->priv->play, "flags", flags, NULL);
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);
769
- set_current_actor (bvw);
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);
777
+ if (bvw->priv->sig_bus_sync)
778
+ g_signal_handler_disconnect (bvw->priv->bus, bvw->priv->sig_bus_sync);
780
if (bvw->priv->sig_bus_async)
781
g_signal_handler_disconnect (bvw->priv->bus, bvw->priv->sig_bus_async);
783
@@ -2504,6 +2732,11 @@ bacon_video_widget_finalize (GObject * o
784
bvw->priv->update_id = 0;
787
+ if (bvw->priv->interface_update_id) {
788
+ g_source_remove (bvw->priv->interface_update_id);
789
+ bvw->priv->interface_update_id = 0;
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;
799
+ g_mutex_free (bvw->priv->lock);
800
g_mutex_free (bvw->priv->seek_mutex);
802
G_OBJECT_CLASS (parent_class)->finalize (object);
803
@@ -3495,6 +3729,7 @@ bacon_video_widget_open (BaconVideoWidge
805
bacon_video_widget_play (BaconVideoWidget * bvw, GError ** error)
807
+ GtkAllocation allocation;
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);
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,
822
+ allocation.height);
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
830
bvw_do_navigation_command (BaconVideoWidget * bvw, GstNavigationCommand command)
832
- gst_navigation_send_command (bvw->priv->navigation, command);
833
+ GstNavigation *nav = bvw_get_navigation_iface (bvw, TRUE);
837
+ gst_navigation_send_command (nav, command);
838
+ gst_object_unref (GST_OBJECT (nav));
842
@@ -3988,10 +4238,7 @@ bacon_video_widget_set_logo (BaconVideoW
844
g_warning ("An error occurred trying to open logo %s: %s", name, error->message);
845
g_error_free (error);
849
- set_current_actor (bvw);
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;
857
- set_current_actor (bvw);
858
+ if (priv->video_window) {
860
+ gdk_window_hide (priv->video_window);
861
+ gtk_widget_set_double_buffered (GTK_WIDGET (bvw), TRUE);
863
+ gdk_window_show (priv->video_window);
864
+ gtk_widget_set_double_buffered (GTK_WIDGET (bvw), FALSE);
868
g_object_notify (G_OBJECT (bvw), "logo_mode");
869
g_object_notify (G_OBJECT (bvw), "seekable");
871
+ /* Queue a redraw of the widget */
872
+ gtk_widget_queue_draw (GTK_WIDGET (bvw));
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));
880
- if (gtk_widget_get_realized (GTK_WIDGET (bvw)) == FALSE) {
885
+ if (!bvw->priv->video_window)
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);
903
@@ -4439,11 +4692,7 @@ setup_vis (BaconVideoWidget * bvw)
905
GST_DEBUG ("setup_vis called, show_vfx %d, vis element %s",
906
bvw->priv->show_vfx, bvw->priv->vis_element_name);
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);
913
if (bvw->priv->show_vfx && !bvw->priv->cover_pixbuf && bvw->priv->vis_element_name) {
914
GstElement *vis_element = NULL, *vis_capsfilter = NULL;
916
@@ -4539,17 +4788,26 @@ setup_vis (BaconVideoWidget * bvw)
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);
923
if (bvw->priv->media_has_audio &&
924
- !bvw->priv->media_has_video) {
925
+ !bvw->priv->media_has_video && bvw->priv->video_window) {
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;
934
+ gdk_window_hide (bvw->priv->video_window);
935
+ gtk_widget_set_double_buffered (GTK_WIDGET (bvw), TRUE);
936
flags &= ~GST_PLAY_FLAG_VIS;
938
g_object_set (bvw->priv->play, "flags", flags, NULL);
940
+ gtk_widget_queue_draw (GTK_WIDGET (bvw));
944
@@ -4580,7 +4838,6 @@ bacon_video_widget_set_show_visualizatio
946
bvw->priv->show_vfx = show_visualizations;
948
- set_current_actor (bvw);
952
@@ -4795,6 +5052,9 @@ bacon_video_widget_set_scale_ratio (Baco
954
GST_DEBUG ("ratio = %.2f", ratio);
956
+ if (bvw->priv->video_window == NULL)
959
if (!bvw->priv->media_has_video && bvw->priv->show_vfx) {
960
get_visualization_size (bvw, &w, &h, NULL, NULL);
962
@@ -4829,42 +5089,41 @@ bacon_video_widget_set_scale_ratio (Baco
964
* bacon_video_widget_set_zoom:
965
* @bvw: a #BaconVideoWidget
966
- * @mode: the #BvwZoomMode
967
+ * @zoom: a percentage zoom factor
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).
975
bacon_video_widget_set_zoom (BaconVideoWidget *bvw,
979
g_return_if_fail (bvw != NULL);
980
g_return_if_fail (BACON_IS_VIDEO_WIDGET (bvw));
982
- if (bvw->priv->frame == NULL)
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);
993
* bacon_video_widget_get_zoom:
994
* @bvw: a #BaconVideoWidget
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).
1001
- * Return value: a #BvwZoomMode
1002
+ * Return value: the zoom factor
1006
bacon_video_widget_get_zoom (BaconVideoWidget *bvw)
1010
g_return_val_if_fail (bvw != NULL, 1.0);
1011
g_return_val_if_fail (BACON_IS_VIDEO_WIDGET (bvw), 1.0);
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;
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);
1023
+ g_mutex_lock (bvw->priv->lock);
1027
if (bvw->priv->balance && GST_IS_COLOR_BALANCE (bvw->priv->balance))
1028
@@ -4936,7 +5197,7 @@ bacon_video_widget_get_video_property (B
1030
GST_DEBUG ("channel %s: returning value %d", found_channel->label, ret);
1031
g_object_unref (found_channel);
1037
@@ -4944,6 +5205,9 @@ bacon_video_widget_get_video_property (B
1039
GST_DEBUG ("nothing found for type %d, returning value %d", type, ret);
1043
+ g_mutex_unlock (bvw->priv->lock);
1047
@@ -5871,6 +6135,9 @@ bacon_video_widget_get_current_frame (Ba
1049
/* =========================================== */
1051
+/* applications must use exactly one of bacon_video_widget_get_option_group()
1052
+ * OR bacon_video_widget_init_backend(), but not both */
1055
* bacon_video_widget_get_option_group:
1057
@@ -5884,10 +6151,26 @@ bacon_video_widget_get_current_frame (Ba
1059
bacon_video_widget_get_option_group (void)
1061
- gtk_clutter_init (NULL, NULL);
1062
return gst_init_get_option_group ();
1066
+ * bacon_video_widget_init_backend:
1067
+ * @argc: pointer to application's argc
1068
+ * @argv: pointer to application's argv
1070
+ * Initialises #BaconVideoWidget's GStreamer backend. If this fails
1071
+ * for the GStreamer backend, your application will be terminated.
1073
+ * Applications must call either this or bacon_video_widget_get_option_group() exactly
1074
+ * once; but not both.
1077
+bacon_video_widget_init_backend (int *argc, char ***argv)
1079
+ gst_init (argc, argv);
1083
bacon_video_widget_error_quark (void)
1085
@@ -5899,6 +6182,191 @@ bacon_video_widget_error_quark (void)
1089
+/* fold function to pick the best colorspace element */
1091
+find_colorbalance_element (GstElement *element, GValue * ret, GstElement **cb)
1093
+ GstColorBalanceClass *cb_class;
1095
+ GST_DEBUG ("Checking element %s ...", GST_OBJECT_NAME (element));
1097
+ if (!GST_IS_COLOR_BALANCE (element))
1100
+ GST_DEBUG ("Element %s is a color balance", GST_OBJECT_NAME (element));
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 */
1107
+ } else if (*cb == NULL) {
1108
+ gst_object_replace ((GstObject **) cb, (GstObject *) element);
1116
+bvw_update_interfaces_delayed (BaconVideoWidget *bvw)
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);
1127
+/* Must be called with bvw->priv->lock held */
1129
+bvw_update_interface_implementations (BaconVideoWidget *bvw)
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;
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;
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);
1156
+ play = gst_object_ref(bvw->priv->play);
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);
1163
+ gst_object_unref(play);
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);
1171
+ element = gst_object_ref(video_sink);
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);
1178
+ GST_DEBUG ("No xoverlay found");
1180
+ gst_object_unref (element);
1181
+ bvw->priv->xoverlay = NULL;
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);
1190
+ element = gst_object_ref(video_sink);
1193
+ if (GST_IS_NAVIGATION (element)) {
1194
+ GST_DEBUG ("Found navigation: %s", GST_OBJECT_NAME (element));
1195
+ bvw->priv->navigation = GST_NAVIGATION (element);
1197
+ GST_DEBUG ("No navigation found");
1199
+ gst_object_unref (element);
1200
+ bvw->priv->navigation = NULL;
1203
+ /* Find best color balance element (using custom iterator so
1204
+ * we can prefer hardware implementations to software ones) */
1206
+ /* FIXME: this doesn't work reliably yet, most of the time
1207
+ * the fold function doesn't even get called, while sometimes
1209
+ iter = gst_bin_iterate_all_by_interface (GST_BIN (bvw->priv->play),
1210
+ GST_TYPE_COLOR_BALANCE);
1211
+ /* naively assume no resync */
1213
+ gst_iterator_fold (iter,
1214
+ (GstIteratorFoldFunction) find_colorbalance_element, NULL, &element);
1215
+ gst_iterator_free (iter);
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));
1227
+ GST_DEBUG ("No colorbalance found");
1228
+ bvw->priv->balance = NULL;
1232
+ gst_object_unref (GST_OBJECT (old_xoverlay));
1235
+ gst_object_unref (GST_OBJECT (old_balance));
1237
+ gst_object_unref (video_sink);
1241
+bvw_element_msg_sync (GstBus *bus, GstMessage *msg, gpointer data)
1243
+ BaconVideoWidget *bvw = BACON_VIDEO_WIDGET (data);
1245
+ g_assert (msg->type == GST_MESSAGE_ELEMENT);
1247
+ if (msg->structure == NULL)
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")) {
1255
+ GST_DEBUG ("Handling sync prepare-xwindow-id message");
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));
1264
+ g_mutex_unlock (bvw->priv->lock);
1266
+ g_return_if_fail (bvw->priv->xoverlay != NULL);
1267
+ g_return_if_fail (bvw->priv->video_window != NULL);
1269
+ window = gdk_x11_window_get_xid (bvw->priv->video_window);
1270
+ gst_x_overlay_set_xwindow_id (bvw->priv->xoverlay, window);
1275
bvw_set_playback_direction (BaconVideoWidget *bvw, gboolean forward)
1277
@@ -5961,8 +6429,21 @@ bvw_set_playback_direction (BaconVideoWi
1282
+got_new_video_sink_bin_element (GstBin *video_sink, GstElement *element,
1285
+ BaconVideoWidget *bvw = BACON_VIDEO_WIDGET (data);
1287
+ g_mutex_lock (bvw->priv->lock);
1288
+ bvw_update_interface_implementations (bvw);
1289
+ g_mutex_unlock (bvw->priv->lock);
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
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()
1303
-bacon_video_widget_new (GError ** error)
1304
+bacon_video_widget_new (int width, int height,
1307
BaconVideoWidget *bvw;
1308
GstElement *audio_sink = NULL, *video_sink = NULL;
1311
- ClutterColor black = { 0x00, 0x00, 0x00, 0xff };
1312
- ClutterConstraint *constraint;
1313
- GstElement *balance, *sink, *bin;
1314
- GstPad *pad, *ghostpad;
1316
#ifndef GST_DISABLE_GST_DEBUG
1317
if (_totem_gst_debug_cat == NULL) {
1318
@@ -6043,61 +6521,69 @@ bacon_video_widget_new (GError ** error)
1320
audio_sink = gst_element_factory_make ("autoaudiosink", "audio-sink");
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");
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");
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;
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);
1348
- /* Video sink, with aspect frame */
1349
- bvw->priv->texture = g_object_new (CLUTTER_TYPE_TEXTURE,
1350
- "disable-slicing", TRUE,
1352
- sink = clutter_gst_video_sink_new (CLUTTER_TEXTURE (bvw->priv->texture));
1353
- bvw->priv->navigation = GST_NAVIGATION (sink);
1355
- g_critical ("Could not create Clutter video sink");
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));
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);
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);
1379
- clutter_actor_raise (CLUTTER_ACTOR (bvw->priv->frame),
1380
- CLUTTER_ACTOR (bvw->priv->logo_frame));
1382
- gst_bin_add (GST_BIN (bin), sink);
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);
1392
+ GstStateChangeReturn ret;
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;
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);
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 "
1437
GstStateChangeReturn ret;
1438
@@ -6153,8 +6639,7 @@ bacon_video_widget_new (GError ** error)
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);
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);
1452
+ /* assume we're always called from the main Gtk+ GUI thread */
1453
+ gui_thread = g_thread_self();
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);
1458
+ bvw->priv->sig_bus_sync =
1459
+ g_signal_connect (bvw->priv->bus, "sync-message::element",
1460
+ G_CALLBACK (bvw_element_msg_sync), bvw);
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);
1471
return GTK_WIDGET (bvw);
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
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])
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"
1494
PLUGINDIR='${libdir}/totem/plugins'
1496
@@ -78,9 +78,6 @@ dnl release versions.
1499
GSTPLUG_REQS=0.10.30
1501
-CLUTTER_GST_REQS=1.3.9
1502
-CLUTTER_GTK_REQS=1.0.2
1506
@@ -114,7 +111,7 @@ if test "x$enable_easy_codec_installatio
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"
1515
@@ -220,7 +217,6 @@ PKG_CHECK_MODULES([DEPENDENCY],[
1517
totem-plparser >= $TOTEM_PLPARSER_REQS
1518
gstreamer-tag-0.10 >= 0.10.26
1519
- clutter-gtk-1.0 >= $CLUTTER_GTK_REQS
1522
PKG_CHECK_MODULES(MM, $MM)
1523
@@ -457,12 +453,6 @@ for plugin in ${used_plugins}; do
1528
- if test "${with_vala}" != "yes" ; then
1529
- plugin_error_or_ignore "you need vala installed to use the rotation plugin"
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
1549
#ifndef HAVE_BACON_VIDEO_WIDGET_H
1550
#define HAVE_BACON_VIDEO_WIDGET_H
1552
-#include <clutter-gtk/clutter-gtk.h>
1553
+#include <gtk/gtk.h>
1554
/* for optical disc enumeration type */
1555
#include <totem-disc.h>
1557
@@ -51,7 +51,7 @@ typedef struct BaconVideoWidgetCommon Ba
1561
- GtkClutterEmbed parent;
1562
+ GtkEventBox parent;
1563
BaconVideoWidgetPrivate *priv;
1566
@@ -62,7 +62,7 @@ typedef struct {
1570
- GtkClutterEmbedClass parent_class;
1571
+ GtkEventBoxClass parent_class;
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);
1582
-GtkWidget *bacon_video_widget_new (GError **error);
1583
+GtkWidget *bacon_video_widget_new (int width, int height,
1586
char *bacon_video_widget_get_backend_name (BaconVideoWidget *bvw);
1588
@@ -368,19 +371,6 @@ typedef enum {
1594
- * @BVW_ZOOM_NONE: No video zooming/cropping
1595
- * @BVW_ZOOM_EXPAND: Fill area with video, and crop the excess
1597
- * The zoom mode used by the video widget, as set by
1598
- * bacon_video_widget_set_zoom().
1601
- BVW_ZOOM_NONE = 0,
1602
- BVW_ZOOM_EXPAND = 1
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
1611
void bacon_video_widget_set_zoom (BaconVideoWidget *bvw,
1612
- BvwZoomMode mode);
1613
-BvwZoomMode bacon_video_widget_get_zoom (BaconVideoWidget *bvw);
1615
+double bacon_video_widget_get_zoom (BaconVideoWidget *bvw);
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 = \
1626
$(DEPENDENCY_CFLAGS) \
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
1640
libbaconvideowidget_la_CPPFLAGS = \
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>
1654
+ <object class="GtkActionGroup" id="zoom-action-group">
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"/>
1664
+ <accelerator key="R" modifiers="GDK_CONTROL_MASK"/>
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"/>
1673
+ <accelerator key="0" modifiers="GDK_CONTROL_MASK"/>
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"/>
1682
- <accelerator key="Z" modifiers="GDK_CONTROL_MASK"/>
1683
+ <accelerator key="T" modifiers="GDK_CONTROL_MASK"/>
1688
<menuitem name="zoom-1-1" action="zoom-1-1"/>
1689
<menuitem name="zoom-2-1" action="zoom-2-1"/>
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"/>
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;
1709
#ifdef GDK_WINDOWING_X11
1711
@@ -105,13 +107,12 @@ int main
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);
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);
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);
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);
1736
- bacon_video_widget_set_logo_mode (BACON_VIDEO_WIDGET (bvw), TRUE);
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);
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
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));
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
1777
-zoom_toggle_action_callback (GtkToggleAction *action,
1779
+zoom_in_action_callback (GtkAction *action, Totem *totem)
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);
1787
+zoom_reset_action_callback (GtkAction *action, Totem *totem)
1789
+ totem_action_zoom_reset (totem);
1793
+zoom_out_action_callback (GtkAction *action, Totem *totem)
1795
+ totem_action_zoom_relative (totem, ZOOM_OUT_OFFSET);
1799
@@ -1367,6 +1379,7 @@ void
1800
totem_ui_manager_setup (Totem *totem)
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"));
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
1812
#define SEEK_FORWARD_LONG_OFFSET 10*60
1813
#define SEEK_BACKWARD_LONG_OFFSET -3*60
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)
1821
#define DEFAULT_WINDOW_W 650
1822
#define DEFAULT_WINDOW_H 500
1824
@@ -1996,14 +2002,58 @@ totem_object_action_seek_time (TotemObje
1825
totem_seek_time_rel (totem, msec, FALSE, accurate);
1829
-totem_action_set_zoom (TotemObject *totem,
1832
+totem_action_zoom (TotemObject *totem, double zoom)
1835
+ gboolean zoom_reset, zoom_in, zoom_out;
1837
+ if (totem->bvw == NULL)
1840
+ if (zoom == ZOOM_ENABLE)
1841
+ zoom = bacon_video_widget_get_zoom (totem->bvw);
1843
+ if (zoom == ZOOM_DISABLE) {
1844
+ zoom_reset = zoom_in = zoom_out = FALSE;
1845
+ } else if (zoom < ZOOM_LOWER || zoom > ZOOM_UPPER) {
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;
1854
+ action = gtk_action_group_get_action (totem->zoom_action_group,
1856
+ gtk_action_set_sensitive (action, zoom_in);
1858
+ action = gtk_action_group_get_action (totem->zoom_action_group,
1860
+ gtk_action_set_sensitive (action, zoom_out);
1862
+ action = gtk_action_group_get_action (totem->zoom_action_group,
1864
+ gtk_action_set_sensitive (action, zoom_reset);
1867
- action = gtk_action_group_get_action (totem->main_action_group, "zoom-toggle");
1868
- gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (action), zoom);
1870
+totem_action_zoom_relative (TotemObject *totem, double off_pct)
1874
+ if (totem->bvw == NULL)
1877
+ zoom = bacon_video_widget_get_zoom (totem->bvw);
1878
+ totem_action_zoom (totem, zoom + off_pct);
1882
+totem_action_zoom_reset (TotemObject *totem)
1884
+ totem_action_zoom (totem, ZOOM_RESET);
1888
@@ -2656,6 +2706,14 @@ property_notify_cb_volume (BaconVideoWid
1892
+property_notify_cb_logo_mode (BaconVideoWidget *bvw, GParamSpec *spec, TotemObject *totem)
1895
+ enabled = bacon_video_widget_get_logo_mode (totem->bvw);
1896
+ totem_action_zoom (totem, enabled ? ZOOM_DISABLE : ZOOM_ENABLE);
1900
property_notify_cb_seekable (BaconVideoWidget *bvw, GParamSpec *spec, TotemObject *totem)
1902
update_seekable (totem);
1903
@@ -3143,10 +3201,10 @@ totem_object_action_remote (TotemObject
1906
case TOTEM_REMOTE_COMMAND_ZOOM_UP:
1907
- totem_action_set_zoom (totem, TRUE);
1908
+ totem_action_zoom_relative (totem, ZOOM_IN_OFFSET);
1910
case TOTEM_REMOTE_COMMAND_ZOOM_DOWN:
1911
- totem_action_set_zoom (totem, FALSE);
1912
+ totem_action_zoom_relative (totem, ZOOM_OUT_OFFSET);
1914
case TOTEM_REMOTE_COMMAND_EJECT:
1915
totem_action_eject (totem);
1916
@@ -3606,12 +3664,12 @@ totem_action_handle_key_press (TotemObje
1919
case GDK_KEY_ZoomIn:
1920
- totem_action_set_zoom (totem, TRUE);
1921
+ totem_action_zoom_relative (totem, ZOOM_IN_OFFSET);
1925
case GDK_KEY_ZoomOut:
1926
- totem_action_set_zoom (totem, FALSE);
1927
+ totem_action_zoom_relative (totem, ZOOM_OUT_OFFSET);
1930
totem_action_eject (totem);
1931
@@ -3683,7 +3741,7 @@ totem_action_handle_key_press (TotemObje
1934
if (event->state & GDK_CONTROL_MASK)
1935
- totem_action_set_zoom (totem, FALSE);
1936
+ totem_action_zoom_reset (totem);
1938
totem_action_set_scale_ratio (totem, 0.5);
1940
@@ -3707,18 +3765,18 @@ totem_action_handle_key_press (TotemObje
1943
if (event->state & GDK_CONTROL_MASK)
1944
- totem_action_set_zoom (totem, TRUE);
1945
+ totem_action_zoom_relative (totem, ZOOM_IN_OFFSET);
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);
1953
case GDK_KEY_KP_Add:
1954
if (!(event->state & GDK_CONTROL_MASK)) {
1955
totem_action_next (totem);
1957
- totem_action_set_zoom (totem, TRUE);
1958
+ totem_action_zoom_relative (totem, ZOOM_IN_OFFSET);
1962
@@ -3726,7 +3784,7 @@ totem_action_handle_key_press (TotemObje
1963
if (!(event->state & GDK_CONTROL_MASK)) {
1964
totem_action_previous (totem);
1966
- totem_action_set_zoom (totem, FALSE);
1967
+ totem_action_zoom_relative (totem, ZOOM_OUT_OFFSET);
1971
@@ -4219,7 +4277,7 @@ video_widget_create (TotemObject *totem)
1972
GtkContainer *container;
1973
BaconVideoWidget **bvw;
1975
- totem->bvw = BACON_VIDEO_WIDGET (bacon_video_widget_new (&err));
1976
+ totem->bvw = BACON_VIDEO_WIDGET (bacon_video_widget_new (-1, -1, &err));
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)
1984
+ totem_action_zoom (totem, ZOOM_RESET);
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)
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 {
2005
GtkActionGroup *main_action_group;
2006
+ GtkActionGroup *zoom_action_group;
2007
GtkUIManager *ui_manager;
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);