1 /* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */
2 
3 /***************************************************************************
4 *            player.c
5 *
6 *  lun mai 30 08:15:01 2005
7 *  Copyright  2005  Philippe Rouquier
8 *  brasero-app@wanadoo.fr
9 ****************************************************************************/
10 
11 /*
12  *  Brasero is free software; you can redistribute it and/or modify
13  *  it under the terms of the GNU General Public License as published by
14  *  the Free Software Foundation; either version 2 of the License, or
15  *  (at your option) any later version.
16  *
17  *  Brasero is distributed in the hope that it will be useful,
18  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
19  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
20  *  GNU Library General Public License for more details.
21  *
22  *  You should have received a copy of the GNU General Public License
23  *  along with this program; if not, write to:
24  * 	The Free Software Foundation, Inc.,
25  * 	51 Franklin Street, Fifth Floor
26  * 	Boston, MA  02110-1301, USA.
27  */
28 
29 #ifdef HAVE_CONFIG_H
30 #  include <config.h>
31 #endif
32 
33 #include <string.h>
34 
35 #include <glib.h>
36 #include <glib/gi18n-lib.h>
37 
38 #include <gtk/gtk.h>
39 
40 #include "brasero-misc.h"
41 #include "brasero-metadata.h"
42 #include "brasero-io.h"
43 
44 #include "brasero-units.h"
45 
46 #include "brasero-setting.h"
47 
48 #include "brasero-player.h"
49 #include "brasero-player-bacon.h"
50 #include "brasero-utils.h"
51 
52 
53 G_DEFINE_TYPE (BraseroPlayer, brasero_player, GTK_TYPE_ALIGNMENT);
54 
55 struct BraseroPlayerPrivate {
56 	GtkWidget *notebook;
57 
58 	GtkWidget *bacon;
59 
60 	GtkWidget *spinner;
61 
62 	GtkWidget *play_image;
63 
64 	gint image_width;
65 	gint image_height;
66 	GdkPixbuf *pixbuf;
67 
68 	GtkWidget *image_display;
69 
70 	GtkWidget *zoom_in;
71 	GtkWidget *zoom_out;
72 
73 	gint video_width;
74 	gint video_height;
75 
76 	BraseroPlayerBaconState state;
77 
78 	BraseroIOJobBase *meta_task;
79 
80 	gchar *uri;
81 	gint64 start;
82 	gint64 end;
83 	gint64 length;
84 
85 	int is_video:1;
86 };
87 
88 typedef enum {
89 	READY_SIGNAL,
90 	ERROR_SIGNAL,
91 	EOF_SIGNAL,
92 	LAST_SIGNAL
93 } BraseroPlayerSignalType;
94 static guint brasero_player_signals [LAST_SIGNAL] = { 0 };
95 
96 static GObjectClass *parent_class = NULL;
97 
98 static void
brasero_player_no_multimedia_stream(BraseroPlayer * player)99 brasero_player_no_multimedia_stream (BraseroPlayer *player)
100 {
101 	gtk_spinner_stop (GTK_SPINNER (player->priv->spinner));
102 	gtk_widget_set_has_tooltip (GTK_WIDGET (player), FALSE);
103 	gtk_notebook_set_current_page (GTK_NOTEBOOK (player->priv->notebook), 2);
104 
105 	player->priv->length = 0;
106 	player->priv->start = 0;
107 	player->priv->end = 0;
108 }
109 
110 static void
brasero_player_video_zoom_out(BraseroPlayer * player)111 brasero_player_video_zoom_out (BraseroPlayer *player)
112 {
113 	player->priv->video_width -= PLAYER_BACON_WIDTH / 3;
114 	player->priv->video_height -= PLAYER_BACON_HEIGHT / 3;
115 
116 	if (player->priv->video_width <= PLAYER_BACON_WIDTH ||
117 	    player->priv->video_height <= PLAYER_BACON_HEIGHT) {
118 		player->priv->video_width = PLAYER_BACON_WIDTH;
119 		player->priv->video_height = PLAYER_BACON_HEIGHT;
120 	}
121 
122 	gtk_widget_set_size_request (GTK_WIDGET (player->priv->bacon),
123 				     player->priv->video_width,
124 				     player->priv->video_height);
125 }
126 
127 static void
brasero_player_video_zoom_in(BraseroPlayer * player)128 brasero_player_video_zoom_in (BraseroPlayer *player)
129 {
130 	player->priv->video_width += PLAYER_BACON_WIDTH / 3;
131 	player->priv->video_height += PLAYER_BACON_HEIGHT / 3;
132 
133 	if (player->priv->video_width >= PLAYER_BACON_WIDTH * 3 ||
134 	    player->priv->video_height >= PLAYER_BACON_HEIGHT * 3) {
135 		player->priv->video_width = PLAYER_BACON_WIDTH * 3;
136 		player->priv->video_height = PLAYER_BACON_HEIGHT * 3;
137 	}
138 
139 	gtk_widget_set_size_request (GTK_WIDGET (player->priv->bacon),
140 				     player->priv->video_width,
141 				     player->priv->video_height);
142 }
143 
144 static gboolean
brasero_player_scale_image(BraseroPlayer * player)145 brasero_player_scale_image (BraseroPlayer *player)
146 {
147 	gint height, width;
148 	GdkPixbuf *scaled;
149 	gdouble ratio;
150 
151 	height = gdk_pixbuf_get_height (player->priv->pixbuf);
152 	width = gdk_pixbuf_get_width (player->priv->pixbuf);
153 
154 	if (player->priv->image_height == height
155 	&&  player->priv->image_width == width) {
156 		gtk_image_set_from_pixbuf (GTK_IMAGE (player->priv->image_display),
157 					   player->priv->pixbuf);
158 		return TRUE;
159 	}
160 
161 	if (width / (gdouble) player->priv->image_width > height / (gdouble) player->priv->image_height)
162 		ratio = (gdouble) width / (gdouble) player->priv->image_width;
163 	else
164 		ratio = (gdouble) height / (gdouble) player->priv->image_height;
165 
166 	scaled = gdk_pixbuf_scale_simple (player->priv->pixbuf,
167 					  width / ratio,
168 					  height / ratio,
169 					  GDK_INTERP_BILINEAR);
170 
171 	if (!scaled)
172 		return FALSE;
173 
174 	gtk_image_set_from_pixbuf (GTK_IMAGE (player->priv->image_display), scaled);
175 	g_object_unref (scaled);
176 
177 	return TRUE;
178 }
179 
180 static void
brasero_player_image_zoom_in(BraseroPlayer * player)181 brasero_player_image_zoom_in (BraseroPlayer *player)
182 {
183 	player->priv->image_width += PLAYER_BACON_WIDTH / 3;
184 	player->priv->image_height += PLAYER_BACON_HEIGHT / 3;
185 
186 	if (player->priv->image_width >= PLAYER_BACON_WIDTH * 3 ||
187 	    player->priv->image_height >= PLAYER_BACON_HEIGHT * 3) {
188 		player->priv->image_width = PLAYER_BACON_WIDTH * 3;
189 		player->priv->image_height = PLAYER_BACON_HEIGHT * 3;
190 	}
191 
192 	if (player->priv->pixbuf)
193 		brasero_player_scale_image (player);
194 }
195 
196 static void
brasero_player_image_zoom_out(BraseroPlayer * player)197 brasero_player_image_zoom_out (BraseroPlayer *player)
198 {
199 	gint min_height, min_width;
200 
201 	if (player->priv->pixbuf) {
202 		min_width = MIN (PLAYER_BACON_WIDTH, gdk_pixbuf_get_width (player->priv->pixbuf));
203 		min_height = MIN (PLAYER_BACON_HEIGHT, gdk_pixbuf_get_height (player->priv->pixbuf));
204 	}
205 	else {
206 		min_width = PLAYER_BACON_WIDTH;
207 		min_height = PLAYER_BACON_HEIGHT;
208 	}
209 
210 	player->priv->image_width -= PLAYER_BACON_WIDTH / 3;
211 	player->priv->image_height -= PLAYER_BACON_HEIGHT / 3;
212 
213 	/* the image itself */
214 	if (player->priv->image_width <= min_width ||
215 	    player->priv->image_height <= min_height) {
216 		player->priv->image_width = min_width;
217 		player->priv->image_height = min_height;
218 	}
219 
220 	if (player->priv->pixbuf)
221 		brasero_player_scale_image (player);
222 }
223 
224 static void
brasero_player_zoom_in_cb(GtkButton * button,BraseroPlayer * player)225 brasero_player_zoom_in_cb (GtkButton *button,
226                            BraseroPlayer *player)
227 {
228 	brasero_player_image_zoom_in (player);
229 	brasero_player_video_zoom_in (player);
230 }
231 
232 static void
brasero_player_zoom_out_cb(GtkButton * button,BraseroPlayer * player)233 brasero_player_zoom_out_cb (GtkButton *button,
234                             BraseroPlayer *player)
235 {
236 	brasero_player_image_zoom_out (player);
237 	brasero_player_video_zoom_out (player);
238 }
239 
240 static gboolean
brasero_bacon_scroll(BraseroPlayerBacon * bacon,GdkEventScroll * event,BraseroPlayer * player)241 brasero_bacon_scroll (BraseroPlayerBacon *bacon,
242                       GdkEventScroll *event,
243                       BraseroPlayer *player)
244 {
245 	switch (gtk_notebook_get_current_page (GTK_NOTEBOOK (player->priv->notebook))) {
246 	case 1:
247 	case 4:
248 		if (event->direction == GDK_SCROLL_UP)
249 			brasero_player_bacon_forward (bacon, GST_SECOND);
250 		else
251 			brasero_player_bacon_backward (bacon, GST_SECOND);
252 		break;
253 
254 	case 0:
255 	case 2:
256 	case 3:
257 	default:
258 		if (event->direction == GDK_SCROLL_UP) {
259 			brasero_player_image_zoom_in (player);
260 			brasero_player_video_zoom_in (player);
261 		}
262 		else {
263 			brasero_player_image_zoom_out (player);
264 			brasero_player_video_zoom_out (player);
265 		}
266 		break;
267 	}
268 
269 	return TRUE;
270 }
271 
272 static gboolean
brasero_bacon_button_release(BraseroPlayerBacon * bacon,GdkEventButton * event,BraseroPlayer * player)273 brasero_bacon_button_release (BraseroPlayerBacon *bacon,
274                               GdkEventButton *event,
275                               BraseroPlayer *player)
276 {
277 	if (event->button != 1)
278 		return FALSE;
279 
280 	if (player->priv->state == BACON_STATE_READY) {
281 		/* This will probably never happen as we display a play button */
282 		gtk_image_set_from_stock (GTK_IMAGE (player->priv->play_image), GTK_STOCK_MEDIA_PLAY, GTK_ICON_SIZE_DIALOG);
283 		gtk_notebook_set_current_page (GTK_NOTEBOOK (player->priv->notebook), 1);
284 		brasero_player_bacon_set_uri (BRASERO_PLAYER_BACON (player->priv->bacon), player->priv->uri);
285 		brasero_player_bacon_play (BRASERO_PLAYER_BACON (player->priv->bacon));
286 	}
287 	else if (player->priv->state == BACON_STATE_PAUSED) {
288 		gtk_image_set_from_stock (GTK_IMAGE (player->priv->play_image), GTK_STOCK_MEDIA_PLAY, GTK_ICON_SIZE_DIALOG);
289 		gtk_notebook_set_current_page (GTK_NOTEBOOK (player->priv->notebook), 1);
290 		brasero_player_bacon_play (BRASERO_PLAYER_BACON (player->priv->bacon));
291 	}
292 	else if (player->priv->state == BACON_STATE_PLAYING) {
293 		gtk_image_set_from_stock (GTK_IMAGE (player->priv->play_image), GTK_STOCK_MEDIA_PAUSE, GTK_ICON_SIZE_DIALOG);
294 		gtk_notebook_set_current_page (GTK_NOTEBOOK (player->priv->notebook), 4);
295 		brasero_player_bacon_stop (BRASERO_PLAYER_BACON (player->priv->bacon));
296 	}
297 
298 	return TRUE;
299 }
300 
301 static gboolean
brasero_player_button_release(GtkWidget * widget,GdkEventButton * event,BraseroPlayer * player)302 brasero_player_button_release (GtkWidget *widget,
303                                GdkEventButton *event,
304                                BraseroPlayer *player)
305 {
306 	if (event->button != 1)
307 		return FALSE;
308 
309 	if (gtk_notebook_get_current_page (GTK_NOTEBOOK (player->priv->notebook)) == 4) {
310 		if (player->priv->state == BACON_STATE_READY) {
311 			gtk_image_set_from_stock (GTK_IMAGE (player->priv->play_image), GTK_STOCK_MEDIA_PAUSE, GTK_ICON_SIZE_DIALOG);
312 			if (player->priv->is_video)
313 				gtk_notebook_set_current_page (GTK_NOTEBOOK (player->priv->notebook), 1);
314 
315 			brasero_player_bacon_set_uri (BRASERO_PLAYER_BACON (player->priv->bacon), player->priv->uri);
316 			brasero_player_bacon_play (BRASERO_PLAYER_BACON (player->priv->bacon));
317 		}
318 		else if (player->priv->state == BACON_STATE_PAUSED) {
319 			gtk_image_set_from_stock (GTK_IMAGE (player->priv->play_image), GTK_STOCK_MEDIA_PAUSE, GTK_ICON_SIZE_DIALOG);
320 			if (player->priv->is_video)
321 				gtk_notebook_set_current_page (GTK_NOTEBOOK (player->priv->notebook), 1);
322 
323 			brasero_player_bacon_play (BRASERO_PLAYER_BACON (player->priv->bacon));
324 		}
325 		else if (player->priv->state == BACON_STATE_PLAYING) {
326 			gtk_image_set_from_stock (GTK_IMAGE (player->priv->play_image), GTK_STOCK_MEDIA_PLAY, GTK_ICON_SIZE_DIALOG);
327 			brasero_player_bacon_stop (BRASERO_PLAYER_BACON (player->priv->bacon));
328 		}
329 	}
330 
331 	return TRUE;
332 }
333 
334 static gboolean
brasero_player_scroll(GtkWidget * widget,GdkEventScroll * event,BraseroPlayer * player)335 brasero_player_scroll (GtkWidget *widget,
336                        GdkEventScroll *event,
337                        BraseroPlayer *player)
338 {
339 	switch (gtk_notebook_get_current_page (GTK_NOTEBOOK (player->priv->notebook))) {
340 	case 1:
341 	case 4:
342 		if (event->direction == GDK_SCROLL_UP)
343 			brasero_player_bacon_forward (BRASERO_PLAYER_BACON (player->priv->bacon), GST_SECOND);
344 		else
345 			brasero_player_bacon_backward (BRASERO_PLAYER_BACON (player->priv->bacon), GST_SECOND);
346 		break;
347 
348 	case 0:
349 	case 2:
350 	case 3:
351 	default:
352 		if (event->direction == GDK_SCROLL_UP) {
353 			brasero_player_image_zoom_in (player);
354 			brasero_player_video_zoom_in (player);
355 		}
356 		else {
357 			brasero_player_image_zoom_out (player);
358 			brasero_player_video_zoom_out (player);
359 		}
360 		break;
361 	}
362 
363 	return TRUE;
364 }
365 
366 static void
brasero_player_image(BraseroPlayer * player)367 brasero_player_image (BraseroPlayer *player)
368 {
369 	GError *error = NULL;
370 	gchar *path;
371 
372 	if (player->priv->pixbuf) {
373 		g_object_unref (player->priv->pixbuf);
374 		player->priv->pixbuf = NULL;
375 	}
376 
377 	/* image */
378 	/* FIXME: this does not allow to preview remote files */
379 	path = g_filename_from_uri (player->priv->uri, NULL, NULL);
380 	player->priv->pixbuf = gdk_pixbuf_new_from_file (path, &error);
381 
382 	if (!player->priv->pixbuf) {
383 		if (error) {
384 			g_warning ("Couldn't load image %s\n", error->message);
385 			g_error_free (error);
386 		}
387 
388 		brasero_player_no_multimedia_stream (player);
389 		g_free (path);
390 		return;
391 	}
392 
393 	brasero_player_scale_image (player);
394 
395 	gtk_widget_show (player->priv->notebook);
396 	gtk_notebook_set_current_page (GTK_NOTEBOOK (player->priv->notebook), 0);
397 	g_signal_emit (player,
398 		       brasero_player_signals [READY_SIGNAL],
399 		       0);
400 }
401 
402 static void
brasero_player_update_tooltip(BraseroPlayer * player,GFileInfo * info)403 brasero_player_update_tooltip (BraseroPlayer *player,
404                                GFileInfo *info)
405 {
406 	gchar *string;
407 	gchar *len_string;
408 	const gchar *title;
409 	const gchar *artist;
410 
411 	/* Update the tooltip */
412 	len_string = brasero_units_get_time_string (g_file_info_get_attribute_uint64 (info, BRASERO_IO_LEN), TRUE, FALSE);
413 	title = g_file_info_get_attribute_string (info, BRASERO_IO_TITLE);
414 	artist = g_file_info_get_attribute_string (info, BRASERO_IO_ARTIST);
415 	if (artist) {
416 		gchar *artist_string;
417 
418 		/* Translators: %s is the name of the artist */
419 		artist_string = g_strdup_printf (_("by %s"), artist);
420 		string = g_markup_printf_escaped ("<span weight=\"bold\">%s</span>"
421 		                                  "\n<i><span size=\"smaller\">%s</span></i>"
422 		                                  "\n%s",
423 		                                  title,
424 		                                  artist_string,
425 		                                  len_string);
426 		g_free (artist_string);
427 	}
428 	else if (title)
429 		string = g_markup_printf_escaped ("<span weight=\"bold\">%s</span>"
430 		                                  "\n%s",
431 		                                  title,
432 		                                  len_string);
433 	else {
434 		gchar *name;
435 		gchar *unescaped_uri;
436 
437 		unescaped_uri = g_uri_unescape_string (player->priv->uri, NULL);
438 		name = g_path_get_basename (unescaped_uri);
439 		g_free (unescaped_uri);
440 		string = g_markup_printf_escaped ("<span weight=\"bold\">%s</span>"
441 		                                  "\n%s",
442 		                                  name,
443 		                                  len_string);
444 		g_free (name);
445 	}
446 
447 	g_free (len_string);
448 
449 	gtk_widget_set_tooltip_markup (GTK_WIDGET (player), string);
450 	g_free (string);
451 }
452 
453 static void
brasero_player_metadata_completed(GObject * obj,GError * error,const gchar * uri,GFileInfo * info,gpointer null_data)454 brasero_player_metadata_completed (GObject *obj,
455 				   GError *error,
456 				   const gchar *uri,
457 				   GFileInfo *info,
458 				   gpointer null_data)
459 {
460 	BraseroPlayer *player = BRASERO_PLAYER (obj);
461 	const gchar *mime;
462 
463 	gtk_spinner_stop (GTK_SPINNER (player->priv->spinner));
464 
465 	if (player->priv->pixbuf) {
466 		gtk_image_set_from_pixbuf (GTK_IMAGE (player->priv->image_display), NULL);
467 		g_object_unref (player->priv->pixbuf);
468 		player->priv->pixbuf = NULL;
469 	}
470 
471 	if (error) {
472 		brasero_player_no_multimedia_stream (player);
473 		g_signal_emit (player,
474 			       brasero_player_signals [ERROR_SIGNAL],
475 			       0);
476 		return;
477 	}
478 
479 	mime = g_file_info_get_content_type (info);
480 
481 	/* based on the mime type, we try to determine the type of file */
482 	if (g_file_info_get_attribute_boolean (info, BRASERO_IO_HAS_VIDEO)) {
483 		if (g_file_info_get_attribute_uint64 (info, BRASERO_IO_LEN) <= 0) {
484 			brasero_player_no_multimedia_stream (player);
485 			g_signal_emit (player,
486 				       brasero_player_signals [ERROR_SIGNAL],
487 				       0);
488 			return;
489 		}
490 
491 		/* video: display play button first */
492 		player->priv->is_video = TRUE;
493 		gtk_image_set_from_stock (GTK_IMAGE (player->priv->play_image), GTK_STOCK_MEDIA_PLAY, GTK_ICON_SIZE_DIALOG);
494 		gtk_notebook_set_current_page (GTK_NOTEBOOK (player->priv->notebook), 4);
495 
496 		brasero_player_update_tooltip (player, info);
497 	}
498 	else if (g_file_info_get_attribute_boolean (info, BRASERO_IO_HAS_AUDIO)) {
499 		if (g_file_info_get_attribute_uint64 (info, BRASERO_IO_LEN) <= 0) {
500 			brasero_player_no_multimedia_stream (player);
501 			g_signal_emit (player,
502 				       brasero_player_signals [ERROR_SIGNAL],
503 				       0);
504 			return;
505 		}
506 
507 		/* Audio */
508 		player->priv->is_video = FALSE;
509 		gtk_image_set_from_stock (GTK_IMAGE (player->priv->play_image), GTK_STOCK_MEDIA_PLAY, GTK_ICON_SIZE_DIALOG);
510 		gtk_notebook_set_current_page (GTK_NOTEBOOK (player->priv->notebook), 4);
511 
512 		brasero_player_update_tooltip (player, info);
513 	}
514 	else if (mime && !strncmp ("image/", mime, 6)) {
515 		gchar *size_string;
516 		gchar *string;
517 		gchar *path;
518 		gchar *name;
519 		gint height;
520 		gint width;
521 
522 		/* Only do that if the image is < 20 M otherwise that's crap
523 		 * FIXME: maybe a sort of error message here? or use thumbnail? */
524 		if (g_file_info_get_size (info) > 100000000LL) {
525 			brasero_player_no_multimedia_stream (player);
526 			g_signal_emit (player,
527 				       brasero_player_signals [ERROR_SIGNAL],
528 				       0);
529 			return;
530 		}
531 
532 		brasero_player_image (player);
533 
534 		path = g_filename_from_uri (player->priv->uri, NULL, NULL);
535 		BRASERO_GET_BASENAME_FOR_DISPLAY (path, name);
536 		g_free (path);
537 
538 		height = gdk_pixbuf_get_height (player->priv->pixbuf);
539 		width = gdk_pixbuf_get_width (player->priv->pixbuf);
540 		size_string = g_strdup_printf (_("%i \303\227 %i pixels"), width, height);
541 
542 		string = g_strdup_printf ("<span weight=\"bold\">%s</span>\n"
543 		                          "<i><span size=\"smaller\">%s</span></i>",
544 		                          name,
545 		                          size_string);
546 		g_free (name);
547 		g_free (size_string);
548 
549 		gtk_widget_set_tooltip_markup (GTK_WIDGET (player), string);
550 		g_free (string);
551 		return;
552 	}
553 	else {
554 		brasero_player_no_multimedia_stream (player);
555 		g_signal_emit (player,
556 			       brasero_player_signals [ERROR_SIGNAL],
557 			       0);
558 	       return;
559 	}
560 
561 	if (player->priv->end <= 0)
562 		player->priv->end = g_file_info_get_attribute_uint64 (info, BRASERO_IO_LEN);
563 
564 	player->priv->length = g_file_info_get_attribute_uint64 (info, BRASERO_IO_LEN);
565 
566 	player->priv->state = BACON_STATE_READY;
567 	g_signal_emit (player,
568 		       brasero_player_signals [READY_SIGNAL],
569 		       0);
570 }
571 
572 static void
brasero_player_retrieve_metadata(BraseroPlayer * player)573 brasero_player_retrieve_metadata (BraseroPlayer *player)
574 {
575 	if (!player->priv->meta_task)
576 		player->priv->meta_task = brasero_io_register (G_OBJECT (player),
577 							       brasero_player_metadata_completed,
578 							       NULL,
579 							       NULL);
580 
581 	brasero_io_get_file_info (player->priv->uri,
582 				  player->priv->meta_task,
583 				  BRASERO_IO_INFO_METADATA|
584 				  BRASERO_IO_INFO_MIME,
585 				  NULL);
586 }
587 
588 void
brasero_player_set_boundaries(BraseroPlayer * player,gint64 start,gint64 end)589 brasero_player_set_boundaries (BraseroPlayer *player,
590 			       gint64 start,
591 			       gint64 end)
592 {
593 	if (start <= 0)
594 		player->priv->start = 0;
595 	else
596 		player->priv->start = start;
597 
598 	if (end <= 0)
599 		player->priv->end = player->priv->length;
600 	else
601 		player->priv->end = end;
602 
603 	if (player->priv->bacon)
604 		brasero_player_bacon_set_boundaries (BRASERO_PLAYER_BACON (player->priv->bacon),
605 						     player->priv->start,
606 						     player->priv->end);
607 }
608 
609 void
brasero_player_set_uri(BraseroPlayer * player,const gchar * uri)610 brasero_player_set_uri (BraseroPlayer *player,
611 			const gchar *uri)
612 {
613 	/* avoid reloading everything if it's the same uri */
614 	if (!g_strcmp0 (uri, player->priv->uri)) {
615 		/* if it's not loaded yet just return */
616 		/* the existence of progress is the surest way to know
617 		 * if that uri was successfully loaded */
618 		if (uri)
619 			g_signal_emit (player,
620 				       brasero_player_signals [READY_SIGNAL],
621 				       0);
622 		else
623 			g_signal_emit (player,
624 				       brasero_player_signals [ERROR_SIGNAL],
625 				       0);
626 		return;
627 	}
628 
629 	if (player->priv->uri)
630 		g_free (player->priv->uri);
631 
632 	player->priv->uri = g_strdup (uri);
633 	player->priv->length = 0;
634 	player->priv->start = 0;
635 	player->priv->end = 0;
636 
637 	if (player->priv->meta_task)
638 		brasero_io_cancel_by_base (player->priv->meta_task);
639 
640 	/* That stops the pipeline from playing */
641 	brasero_player_bacon_set_uri (BRASERO_PLAYER_BACON (player->priv->bacon), NULL);
642 	if (!uri) {
643 		brasero_player_no_multimedia_stream (player);
644 		return;
645 	}
646 
647 	gtk_widget_set_has_tooltip (GTK_WIDGET (player), FALSE);
648 	gtk_notebook_set_current_page (GTK_NOTEBOOK (player->priv->notebook), 3);
649 	gtk_spinner_start (GTK_SPINNER (player->priv->spinner));
650 
651 	brasero_player_retrieve_metadata (player);
652 }
653 
654 static void
brasero_player_eof_cb(BraseroPlayerBacon * bacon,BraseroPlayer * player)655 brasero_player_eof_cb (BraseroPlayerBacon *bacon, BraseroPlayer *player)
656 {
657 	brasero_player_bacon_stop (BRASERO_PLAYER_BACON (player->priv->bacon));
658 	brasero_player_bacon_set_pos (BRASERO_PLAYER_BACON (player->priv->bacon), player->priv->start);
659 	player->priv->state = BACON_STATE_PAUSED;
660 	gtk_image_set_from_stock (GTK_IMAGE (player->priv->play_image), GTK_STOCK_MEDIA_PLAY, GTK_ICON_SIZE_DIALOG);
661 }
662 
663 static void
brasero_player_state_changed_cb(BraseroPlayerBacon * bacon,BraseroPlayerBaconState state,BraseroPlayer * player)664 brasero_player_state_changed_cb (BraseroPlayerBacon *bacon,
665 				 BraseroPlayerBaconState state,
666 				 BraseroPlayer *player)
667 {
668 	if (player->priv->state == state)
669 		return;
670 
671 	switch (state) {
672 	case BACON_STATE_ERROR:
673 		brasero_player_no_multimedia_stream (player);
674 		break;
675 
676 	default:
677 		break;
678 	}
679 
680 	player->priv->state = state;
681 }
682 
683 static void
brasero_player_destroy(GtkWidget * obj)684 brasero_player_destroy (GtkWidget *obj)
685 {
686 	BraseroPlayer *player;
687 
688 	player = BRASERO_PLAYER (obj);
689 
690 	brasero_setting_set_value (brasero_setting_get_default (),
691 	                           BRASERO_SETTING_IMAGE_SIZE_WIDTH,
692 	                           GINT_TO_POINTER (player->priv->image_width));
693 	brasero_setting_set_value (brasero_setting_get_default (),
694 	                           BRASERO_SETTING_IMAGE_SIZE_HEIGHT,
695 	                           GINT_TO_POINTER (player->priv->image_height));
696 	brasero_setting_set_value (brasero_setting_get_default (),
697 	                           BRASERO_SETTING_VIDEO_SIZE_WIDTH,
698 	                           GINT_TO_POINTER (player->priv->video_width));
699 	brasero_setting_set_value (brasero_setting_get_default (),
700 	                           BRASERO_SETTING_VIDEO_SIZE_HEIGHT,
701 	                           GINT_TO_POINTER (player->priv->video_height));
702 
703 	if (player->priv->pixbuf) {
704 		g_object_unref (player->priv->pixbuf);
705 		player->priv->pixbuf = NULL;
706 	}
707 
708 	if (player->priv->uri) {
709 		g_free (player->priv->uri);
710 		player->priv->uri = NULL;
711 	}
712 
713 	if (player->priv->meta_task){
714 		brasero_io_cancel_by_base (player->priv->meta_task);
715 		brasero_io_job_base_free (player->priv->meta_task);
716 		player->priv->meta_task = 0;
717 	}
718 
719 	if (GTK_WIDGET_CLASS (parent_class)->destroy)
720 		GTK_WIDGET_CLASS (parent_class)->destroy (obj);
721 }
722 
723 static void
brasero_player_finalize(GObject * object)724 brasero_player_finalize (GObject *object)
725 {
726 	BraseroPlayer *cobj;
727 
728 	cobj = BRASERO_PLAYER (object);
729 
730 	g_free (cobj->priv);
731 	G_OBJECT_CLASS (parent_class)->finalize (object);
732 }
733 
734 static void
brasero_player_class_init(BraseroPlayerClass * klass)735 brasero_player_class_init (BraseroPlayerClass *klass)
736 {
737 	GObjectClass *object_class = G_OBJECT_CLASS (klass);
738 	GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass);
739 
740 	parent_class = g_type_class_peek_parent (klass);
741 	object_class->finalize = brasero_player_finalize;
742 
743 	widget_class->destroy = brasero_player_destroy;
744 
745 	brasero_player_signals [ERROR_SIGNAL] =
746 			g_signal_new ("error",
747 				      G_TYPE_FROM_CLASS (klass),
748 				      G_SIGNAL_RUN_LAST,
749 				      G_STRUCT_OFFSET (BraseroPlayerClass, error),
750 				      NULL, NULL,
751 				      g_cclosure_marshal_VOID__VOID,
752 				      G_TYPE_NONE, 0);
753 	brasero_player_signals [READY_SIGNAL] =
754 			g_signal_new ("ready",
755 				      G_TYPE_FROM_CLASS (klass),
756 				      G_SIGNAL_RUN_LAST,
757 				      G_STRUCT_OFFSET (BraseroPlayerClass, ready),
758 				      NULL, NULL,
759 				      g_cclosure_marshal_VOID__VOID,
760 				      G_TYPE_NONE, 0);
761 }
762 
763 static void
brasero_player_volume_changed_cb(GtkScaleButton * button,gdouble volume,BraseroPlayer * player)764 brasero_player_volume_changed_cb (GtkScaleButton *button,
765 				  gdouble volume,
766 				  BraseroPlayer *player)
767 {
768 	brasero_player_bacon_set_volume (BRASERO_PLAYER_BACON (player->priv->bacon), volume);
769 }
770 
771 static void
brasero_player_init(BraseroPlayer * obj)772 brasero_player_init (BraseroPlayer *obj)
773 {
774 	GtkWidget *volume;
775 	GtkWidget *image;
776 	GtkWidget *label;
777 	GtkWidget *event;
778 	GtkWidget *zoom;
779 	GtkWidget *hbox;
780 	GtkWidget *vbox;
781 	gpointer value;
782 	gchar *string;
783 
784 	obj->priv = g_new0 (BraseroPlayerPrivate, 1);
785 
786 	gtk_alignment_set (GTK_ALIGNMENT (obj), 0.5, 0.5, 0.0, 0.0);
787 
788 	vbox = gtk_box_new (GTK_ORIENTATION_VERTICAL, 2);
789 	gtk_widget_show (vbox);
790 	gtk_container_add (GTK_CONTAINER (obj), vbox);
791 
792 	/* The notebook and all views */
793 	event = gtk_event_box_new ();
794 	gtk_box_pack_start (GTK_BOX (vbox), event, FALSE, FALSE, 0);
795 	gtk_event_box_set_above_child (GTK_EVENT_BOX (event), TRUE);
796 	gtk_event_box_set_visible_window (GTK_EVENT_BOX (event), FALSE);
797 	g_signal_connect (event,
798 			  "button-release-event",
799 			  G_CALLBACK (brasero_player_button_release),
800 			  obj);
801 	g_signal_connect (event,
802 			  "scroll-event",
803 			  G_CALLBACK (brasero_player_scroll),
804 			  obj);
805 	gtk_widget_show (event);
806 
807 	obj->priv->notebook = gtk_notebook_new ();
808 	gtk_widget_show (obj->priv->notebook);
809 	gtk_container_add (GTK_CONTAINER (event), obj->priv->notebook);
810 	gtk_notebook_set_show_tabs (GTK_NOTEBOOK (obj->priv->notebook), FALSE);
811 
812 	/* Images */
813 	obj->priv->image_display = gtk_image_new ();
814 	gtk_widget_show (obj->priv->image_display);
815 	gtk_misc_set_alignment (GTK_MISC (obj->priv->image_display), 0.5, 0.5);
816 	gtk_notebook_append_page (GTK_NOTEBOOK (obj->priv->notebook),
817 				  obj->priv->image_display,
818 				  NULL);
819 
820 	/* Video */
821 	obj->priv->bacon = brasero_player_bacon_new ();
822 	gtk_widget_show (obj->priv->bacon);
823 	g_signal_connect (obj->priv->bacon,
824 			  "button-release-event",
825 			  G_CALLBACK (brasero_bacon_button_release),
826 			  obj);
827 	g_signal_connect (obj->priv->bacon,
828 			  "scroll-event",
829 			  G_CALLBACK (brasero_bacon_scroll),
830 			  obj);
831 	g_signal_connect (obj->priv->bacon,
832 			  "state-change",
833 			  G_CALLBACK (brasero_player_state_changed_cb),
834 			  obj);
835 	g_signal_connect (obj->priv->bacon,
836 			  "eof",
837 			  G_CALLBACK (brasero_player_eof_cb),
838 			  obj);
839 
840 	gtk_notebook_append_page (GTK_NOTEBOOK (obj->priv->notebook),
841 				  obj->priv->bacon,
842 				  NULL);
843 
844 	/* No Preview view */
845 	string = g_strdup_printf ("<span color='grey'><big><b>%s</b></big></span>", _("No preview"));
846 	label = gtk_label_new (string);
847 	g_free (string);
848 
849 	gtk_label_set_use_markup (GTK_LABEL (label), TRUE);
850 	gtk_widget_show (label);
851 	gtk_notebook_append_page (GTK_NOTEBOOK (obj->priv->notebook),
852 	                          label,
853 	                          NULL);
854 	gtk_notebook_set_current_page (GTK_NOTEBOOK (obj->priv->notebook), 2);
855 
856 	/* Loading view */
857 	obj->priv->spinner = gtk_spinner_new ();
858 	gtk_widget_show (obj->priv->spinner);
859 	gtk_notebook_append_page (GTK_NOTEBOOK (obj->priv->notebook),
860 	                          obj->priv->spinner,
861 	                          NULL);
862 
863 	/* Music */
864 	image = gtk_image_new_from_stock (GTK_STOCK_MEDIA_PLAY, GTK_ICON_SIZE_DIALOG);
865 	gtk_widget_show (image);
866 	gtk_notebook_append_page (GTK_NOTEBOOK (obj->priv->notebook),
867 	                          image,
868 	                          NULL);
869 	obj->priv->play_image = image;
870 
871 	/* Set the saved sizes */
872 	brasero_setting_get_value (brasero_setting_get_default (),
873 	                           BRASERO_SETTING_IMAGE_SIZE_WIDTH,
874 	                           &value);
875 	obj->priv->image_width = GPOINTER_TO_INT (value);
876 
877 	if (obj->priv->image_width > PLAYER_BACON_WIDTH * 3
878 	||  obj->priv->image_width < PLAYER_BACON_WIDTH)
879 		obj->priv->image_width = PLAYER_BACON_WIDTH;
880 
881 	brasero_setting_get_value (brasero_setting_get_default (),
882 	                           BRASERO_SETTING_IMAGE_SIZE_HEIGHT,
883 	                           &value);
884 	obj->priv->image_height = GPOINTER_TO_INT (value);
885 
886 	if (obj->priv->image_height > PLAYER_BACON_HEIGHT * 3
887 	||  obj->priv->image_height < PLAYER_BACON_HEIGHT)
888 		obj->priv->image_height = PLAYER_BACON_HEIGHT;
889 
890 	brasero_setting_get_value (brasero_setting_get_default (),
891 	                           BRASERO_SETTING_VIDEO_SIZE_WIDTH,
892 	                           &value);
893 	obj->priv->video_width = GPOINTER_TO_INT (value);
894 
895 	if (obj->priv->video_width > PLAYER_BACON_WIDTH * 3
896 	||  obj->priv->video_width < PLAYER_BACON_WIDTH)
897 		obj->priv->video_width = PLAYER_BACON_WIDTH;
898 
899 	brasero_setting_get_value (brasero_setting_get_default (),
900 	                           BRASERO_SETTING_VIDEO_SIZE_HEIGHT,
901 	                           &value);
902 	obj->priv->video_height = GPOINTER_TO_INT (value);
903 
904 	if (obj->priv->video_height > PLAYER_BACON_HEIGHT * 3
905 	||  obj->priv->video_height < PLAYER_BACON_HEIGHT)
906 		obj->priv->video_height = PLAYER_BACON_HEIGHT;
907 
908 	gtk_widget_set_size_request (obj->priv->bacon,
909 				     obj->priv->video_width,
910 				     obj->priv->video_height);
911 
912 	/* A few controls */
913 	hbox = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 0);
914 	gtk_widget_show (hbox);
915 	gtk_box_pack_start (GTK_BOX (vbox), hbox, FALSE, FALSE, 0);
916 
917 	image = gtk_image_new_from_stock (GTK_STOCK_ZOOM_OUT, GTK_ICON_SIZE_BUTTON);
918 	zoom = gtk_button_new ();
919 	gtk_widget_show (zoom);
920 	gtk_widget_show (image);
921 	gtk_button_set_image (GTK_BUTTON (zoom), image);
922 	gtk_button_set_relief (GTK_BUTTON (zoom), GTK_RELIEF_NONE);
923 	gtk_button_set_focus_on_click (GTK_BUTTON (zoom), FALSE);
924 	g_signal_connect (zoom,
925 			  "clicked",
926 			  G_CALLBACK (brasero_player_zoom_out_cb),
927 			  obj);
928 	gtk_box_pack_start (GTK_BOX (hbox),
929 	                    zoom,
930 	                    FALSE,
931 	                    FALSE,
932 	                    0);
933 	obj->priv->zoom_out = zoom;
934 
935 	image = gtk_image_new_from_stock (GTK_STOCK_ZOOM_IN, GTK_ICON_SIZE_BUTTON);
936 	zoom = gtk_button_new ();
937 	gtk_widget_show (zoom);
938 	gtk_widget_show (image);
939 	gtk_button_set_image (GTK_BUTTON (zoom), image);
940 	gtk_button_set_relief (GTK_BUTTON (zoom), GTK_RELIEF_NONE);
941 	gtk_button_set_focus_on_click (GTK_BUTTON (zoom), FALSE);
942 	g_signal_connect (zoom,
943 			  "clicked",
944 			  G_CALLBACK (brasero_player_zoom_in_cb),
945 			  obj);
946 	gtk_box_pack_start (GTK_BOX (hbox),
947 	                    zoom,
948 	                    FALSE,
949 	                    FALSE,
950 	                    0);
951 	obj->priv->zoom_in = zoom;
952 
953 	volume = gtk_volume_button_new ();
954 	gtk_widget_show (volume);
955 	gtk_box_pack_end (GTK_BOX (hbox),
956 			  volume,
957 			  FALSE,
958 			  FALSE,
959 			  0);
960 
961 	gtk_scale_button_set_value (GTK_SCALE_BUTTON (volume),
962 				    brasero_player_bacon_get_volume (BRASERO_PLAYER_BACON (obj->priv->bacon)));
963 
964 	g_signal_connect (volume,
965 			  "value-changed",
966 			  G_CALLBACK (brasero_player_volume_changed_cb),
967 			  obj);
968 }
969 
970 GtkWidget *
brasero_player_new()971 brasero_player_new ()
972 {
973 	BraseroPlayer *obj;
974 
975 	obj = BRASERO_PLAYER (g_object_new (BRASERO_TYPE_PLAYER, NULL));
976 
977 	return GTK_WIDGET (obj);
978 
979 }
980