Merge lp:~tintou/audience/clutter-gst-3-bis into lp:~audience-members/audience/trunk

Proposed by Corentin Noël
Status: Merged
Approved by: Danielle Foré
Approved revision: 578
Merged at revision: 577
Proposed branch: lp:~tintou/audience/clutter-gst-3-bis
Merge into: lp:~audience-members/audience/trunk
Diff against target: 2736 lines (+742/-1378)
16 files modified
data/org.pantheon.audience.gschema.xml (+0/-5)
src/Audience.vala (+17/-308)
src/CMakeLists.txt (+12/-2)
src/DiskManager.vala (+21/-12)
src/Settings.vala (+0/-1)
src/Utils.vala (+4/-18)
src/Widgets/BottomBar.vala (+21/-30)
src/Widgets/PlayerPage.vala (+168/-286)
src/Widgets/Playlist.vala (+1/-1)
src/Widgets/PlaylistPopover.vala (+12/-15)
src/Widgets/PreviewPopover.vala (+53/-59)
src/Widgets/SettingsPopover.vala (+35/-69)
src/Widgets/TimeWidget.vala (+42/-29)
src/Widgets/VideoPlayer.vala (+0/-491)
src/Widgets/WelcomePage.vala (+38/-52)
src/Window.vala (+318/-0)
To merge this branch: bzr merge lp:~tintou/audience/clutter-gst-3-bis
Reviewer Review Type Date Requested Status
Cody Garver Pending
Nathan Dyer Pending
Review via email: mp+289499@code.launchpad.net

This proposal supersedes a proposal from 2016-01-02.

Commit message

Port to clutter-gst-3.0

To post a comment you must log in.
Revision history for this message
Nathan Dyer (nathandyer) wrote : Posted in a previous version of this proposal

The clutter embed is working as expected, but it appears that there are a lot of regressions here. Window resizing is broken, videos have vertical bars on both sides, and the cursor disappears when over the title bar.

review: Needs Fixing
Revision history for this message
Cody Garver (codygarver) wrote : Posted in a previous version of this proposal

Needs trunk merged in and conflicts resolved

review: Needs Fixing
Revision history for this message
Corentin Noël (tintou) wrote :

Merged with trunk.

Revision history for this message
Cody Garver (codygarver) wrote :

Still has a lot of regressions like:
* Black bars at the bottom and top when starting video windowed
* Black bars left and right after leaving fullscreen
* Cursor disappears for a while when mousing over video
* Can no longer grab and drag window around by the playback area

Revision history for this message
Cody Garver (codygarver) wrote :

* Subtitles aren't shown in the menu

577. By Corentin Noël

Fixed some misbehavior with DVDs

Revision history for this message
Corentin Noël (tintou) wrote :

I fixed the grab&drag window but there is nothing I can do for the black bars, there is a bug with the compositor that triggers misbehaviours when I force the window ratio.
I couldn't reproduce subtitles not showing

Revision history for this message
Danielle Foré (danrabbit) wrote :

Hm I'm getting crashes when the preview popopver appears. It's doing like weird chasing the cursor (vertically) stuff as well. Not sure if this is related. Also the popover contains pillarboxing (black bars on the sides), so it might not be the window manager's fault after all ;p

578. By Corentin Noël

Fixed popover size request

Revision history for this message
Corentin Noël (tintou) wrote :

I fixed the popover preview not being correctly resized, I applied the size to the popover instead of the widget itself. It's still the windows manager fault for the app itself :P

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'data/org.pantheon.audience.gschema.xml'
2--- data/org.pantheon.audience.gschema.xml 2015-05-16 10:36:21 +0000
3+++ data/org.pantheon.audience.gschema.xml 2016-03-20 01:32:19 +0000
4@@ -49,10 +49,5 @@
5 <summary>Cause the audience window to stay on top by default when it's playing</summary>
6 <description>Set the option to keep the audience window above all other windows by default when audience is currently playing</description>
7 </key>
8- <key name="show-window-decoration" type="b">
9- <default>true</default>
10- <summary>Don't show the window decorations</summary>
11- <description>Hide the window decorations. You can close the window with escape</description>
12- </key>
13 </schema>
14 </schemalist>
15
16=== modified file 'src/Audience.vala'
17--- src/Audience.vala 2016-02-23 04:26:42 +0000
18+++ src/Audience.vala 2016-03-20 01:32:19 +0000
19@@ -19,21 +19,9 @@
20 * Artem Anufrij <artem.anufrij@live.de>
21 */
22
23-/*
24-[CCode (cname="gst_navigation_query_parse_commands_length")]
25-public extern bool gst_navigation_query_parse_commands_length (Gst.Query q, out uint n);
26-[CCode (cname="gst_navigation_query_parse_commands_nth")]
27-public extern bool gst_navigation_query_parse_commands_nth (Gst.Query q, uint n, out Gst.NavigationCommand cmd);
28-*/
29 namespace Audience {
30
31- public enum Page {
32- WELCOME,
33- PLAYER
34- }
35-
36 public Audience.Settings settings; //global space for easier access...
37-
38 public class App : Granite.Application {
39
40 /**
41@@ -50,8 +38,11 @@
42 public const string ABOUT_STOCK = N_("About Audience");
43 /// TRANSLATORS: This is the shortcut used to view information about the application itself when its displayed name is the localized equivalent of "Videos".
44 public const string ABOUT_GENERIC = N_("About Videos");
45- public const string ABOUT_TRANSLATORS = N_("translator-credits");
46-
47+ public const string ABOUT_TRANSLATORS = N_("translator-credits");
48+
49+ public Window mainwindow;
50+ public GLib.VolumeMonitor monitor;
51+
52 construct {
53 program_name = "Audience";
54 exec_name = "audience";
55@@ -81,318 +72,36 @@
56 about_license_type = Gtk.License.GPL_3_0;
57 }
58
59- private ZeitgeistManager zeitgeist_manager;
60- private Gtk.HeaderBar header;
61-
62- public Gtk.Window mainwindow;
63-
64- private Page _page;
65- public Page page {
66- get {
67- return _page;
68- }
69- set {
70- switch (value) {
71- case Page.PLAYER:
72- if (page == Page.PLAYER)
73- break;
74-
75- if (mainwindow.get_child()!=null)
76- mainwindow.get_child().destroy ();
77-
78- var new_widget = new PlayerPage ();
79- new_widget.ended.connect (on_player_ended);
80- mainwindow.add (new_widget);
81- mainwindow.show_all ();
82-
83- _page = Page.PLAYER;
84- break;
85- case Page.WELCOME:
86- var pl = mainwindow.get_child () as PlayerPage;
87- if (pl!=null) {
88- pl.ended.disconnect (on_player_ended);
89- pl.destroy ();
90- }
91-
92- var new_widget = new WelcomePage ();
93- mainwindow.add (new_widget);
94- mainwindow.show_all ();
95-
96- _page = Page.WELCOME;
97- break;
98- }
99- }
100- }
101-
102- private static App app; // global App instance
103- public DiskManager disk_manager;
104-
105- public GLib.VolumeMonitor monitor;
106-
107- public signal void media_volumes_changed ();
108-
109 public App () {
110-
111 Gtk.Settings.get_default ().gtk_application_prefer_dark_theme = true;
112 this.flags |= GLib.ApplicationFlags.HANDLES_OPEN;
113-
114- zeitgeist_manager = new ZeitgeistManager ();
115+ settings = new Settings ();
116+ set_default ();
117 }
118
119+ private static App app; // global App instance
120 public static App get_instance () {
121 if (app == null)
122 app = new App ();
123 return app;
124 }
125
126- void build () {
127- settings = new Settings ();
128- if (is_privacy_mode_enabled ()) {
129- clear_video_settings ();
130- }
131-
132- mainwindow = new Gtk.Window ();
133-
134- if (settings.last_folder == "-1")
135- settings.last_folder = Environment.get_home_dir ();
136-
137- header = new Gtk.HeaderBar ();
138- header.set_show_close_button (true);
139- header.get_style_context ().add_class ("compact");
140-
141- disk_manager = DiskManager.get_default ();
142-
143- disk_manager.volume_found.connect ((vol) => {
144- media_volumes_changed ();
145- });
146-
147- disk_manager.volume_removed.connect ((vol) => {
148- media_volumes_changed ();
149- });
150-
151- page = Page.WELCOME;
152-
153- mainwindow.set_application (this);
154- mainwindow.set_titlebar (header);
155- mainwindow.window_position = Gtk.WindowPosition.CENTER;
156- mainwindow.gravity = Gdk.Gravity.CENTER;
157- mainwindow.show_all ();
158- if (!settings.show_window_decoration)
159- mainwindow.decorated = false;
160- set_window_title (program_name);
161-
162- mainwindow.key_press_event.connect (on_key_press_event);
163-
164- mainwindow.destroy.connect (() => {
165- if (is_privacy_mode_enabled ()) {
166- clear_video_settings ();
167- }
168- });
169-
170- setup_drag_n_drop ();
171- }
172-
173- public bool has_media_volumes () {
174- return disk_manager.has_media_volumes ();
175- }
176-
177- private async void read_first_disk () {
178- if (disk_manager.get_volumes ().length () <= 0)
179- return;
180- var volume = disk_manager.get_volumes ().nth_data (0);
181- if (volume.can_mount () == true && volume.get_mount ().can_unmount () == false) {
182- try {
183- yield volume.mount (MountMountFlags.NONE, null);
184- } catch (Error e) {
185- critical (e.message);
186- }
187- }
188-
189- page = Page.PLAYER;
190- var root = volume.get_mount ().get_default_location ();
191- play_file (root.get_uri (), true);
192- }
193-
194- public void set_content_size (double width, double height, double content_height){
195- var geom = Gdk.Geometry ();
196-
197- if (width == 0
198- && height == 0
199- && content_height == 0) {
200- geom.min_aspect = geom.max_aspect = 0;
201- } else {
202- double width_offset = mainwindow.get_allocated_width () - width;
203- double height_offset = mainwindow.get_allocated_height () - content_height;
204-
205- debug ("Width: %f, Height: %f, Offset: %f )\n", width, height, content_height);
206-
207- geom.min_aspect = geom.max_aspect = (width + width_offset) / (height + height_offset);
208- }
209-
210- mainwindow.set_geometry_hints (mainwindow, geom, Gdk.WindowHints.ASPECT);
211- }
212-
213- private void on_player_ended () {
214- page = Page.WELCOME;
215- }
216-
217- public bool on_key_press_event (Gdk.EventKey e) {
218- switch (e.keyval) {
219- case Gdk.Key.o:
220- App.get_instance ().run_open_file ();
221- break;
222- case Gdk.Key.q:
223- App.get_instance ().mainwindow.destroy ();
224- break;
225- default:
226- break;
227- }
228- return false;
229- }
230-
231- private inline void clear_video_settings () {
232- settings.last_stopped = 0;
233- settings.last_played_videos = null;
234- settings.current_video = "";
235- settings.last_folder = "";
236- }
237-
238- public void run_open_file () {
239- var file = new Gtk.FileChooserDialog (_("Open"), mainwindow, Gtk.FileChooserAction.OPEN,
240- _("_Cancel"), Gtk.ResponseType.CANCEL, _("_Open"), Gtk.ResponseType.ACCEPT);
241- file.set_transient_for (mainwindow);
242- file.select_multiple = true;
243-
244- var all_files_filter = new Gtk.FileFilter ();
245- all_files_filter.set_filter_name (_("All files"));
246- all_files_filter.add_pattern ("*");
247-
248- var video_filter = new Gtk.FileFilter ();
249- video_filter.set_filter_name (_("Video files"));
250- video_filter.add_mime_type ("video/*");
251-
252- file.add_filter (video_filter);
253- file.add_filter (all_files_filter);
254-
255- file.set_current_folder (settings.last_folder);
256- if (file.run () == Gtk.ResponseType.ACCEPT) {
257- if (page == Page.WELCOME)
258- clear_video_settings ();
259-
260- File[] files = {};
261- foreach (File item in file.get_files ()) {
262- files += item;
263- }
264-
265- open (files, "");
266- settings.last_folder = file.get_current_folder ();
267- }
268-
269- file.destroy ();
270- }
271-
272- public void run_open_dvd () {
273- read_first_disk.begin ();
274- }
275-
276- /*DnD*/
277- private void setup_drag_n_drop () {
278- Gtk.TargetEntry uris = {"text/uri-list", 0, 0};
279- Gtk.drag_dest_set (mainwindow, Gtk.DestDefaults.ALL, {uris}, Gdk.DragAction.MOVE);
280- mainwindow.drag_data_received.connect ( (ctx, x, y, sel, info, time) => {
281- page = Page.PLAYER;
282- File[] files = {};
283- foreach (var uri in sel.get_uris ()) {
284- var file = File.new_for_uri (uri);
285- files += file;
286- }
287- open (files,"");
288- });
289- }
290-
291- public void resume_last_videos () {
292- page = Page.PLAYER;
293-
294- var player = mainwindow.get_child () as PlayerPage;
295- player.resume_last_videos ();
296- }
297-
298- public void set_window_title (string title) {
299- mainwindow.title = title;
300- }
301-
302- /*
303- make sure we are in player page and play file
304- */
305- internal void play_file (string uri, bool dont_modify = false) {
306- if (page != Page.PLAYER)
307- page = Page.PLAYER;
308-
309- PlayerPage player_page = mainwindow.get_child() as PlayerPage;
310- player_page.play_file (uri);
311-
312- }
313-
314 public override void activate () {
315 if (mainwindow == null) {
316- build ();
317+ if (settings.last_folder == "-1") {
318+ settings.last_folder = Environment.get_user_special_dir (GLib.UserDirectory.VIDEOS);
319+ }
320+
321+ mainwindow = new Window ();
322+ mainwindow.application = this;
323+ mainwindow.title = program_name;
324 }
325 }
326
327 //the application was requested to open some files
328 public override void open (File[] files, string hint) {
329- if (mainwindow == null)
330- build ();
331-
332- if (page != Page.PLAYER)
333- clear_video_settings ();
334-
335- page = Page.PLAYER;
336- var player_page = (mainwindow.get_child () as PlayerPage);
337- string[] videos = {};
338- foreach (var file in files) {
339-
340- if (file.query_file_type (0) == FileType.DIRECTORY) {
341- Audience.recurse_over_dir (file, (file_ret) => {
342- player_page.append_to_playlist (file);
343- videos += file_ret.get_uri ();
344- });
345- } else if (player_page.video_player.playing &&
346- PlayerPage.is_subtitle (file.get_uri ())) {
347- message ("is subtitle");
348- player_page.video_player.set_subtitle_uri (file.get_uri ());
349- } else {
350- player_page.append_to_playlist (file);
351- videos += file.get_uri ();
352- }
353- }
354-
355- if (videos.length == 0)
356- return;
357-
358- // notification when adding video to playlist
359- if (!player_page.video_player.playing // we are paused
360- && (mainwindow.get_window ().get_state () & Gdk.WindowState.FOCUSED) == 0) {
361- if (videos.length == 1)
362- show_notification (_("Video added to playlist"), get_title (videos[0]));
363- else
364- show_notification (_("%i videos added to playlist").printf (videos.length), "");
365- }
366-
367- play_file (videos [0]);
368-
369-
370- }
371-
372- internal bool is_privacy_mode_enabled () {
373- var privacy_settings = new GLib.Settings ("org.gnome.desktop.privacy");
374- bool privacy_mode = !privacy_settings.get_boolean ("remember-recent-files") || !privacy_settings.get_boolean ("remember-app-usage");
375-
376- if (privacy_mode) {
377- return true;
378- }
379-
380- return zeitgeist_manager.app_into_blacklist (exec_name);
381+ activate ();
382+ mainwindow.open_files (files);
383 }
384
385 }
386
387=== modified file 'src/CMakeLists.txt'
388--- src/CMakeLists.txt 2015-10-27 18:43:49 +0000
389+++ src/CMakeLists.txt 2016-03-20 01:32:19 +0000
390@@ -11,7 +11,16 @@
391 # pkgconfig, real C code
392 find_package (PkgConfig)
393
394-set (PKG_DEPS granite>=0.3.0 clutter-gtk-1.0 gstreamer-1.0 gstreamer-pbutils-1.0 gstreamer-video-1.0 gstreamer-tag-1.0)
395+set (PKG_DEPS
396+ granite>=0.3.0
397+ clutter-gtk-1.0
398+ gstreamer-1.0
399+ gstreamer-pbutils-1.0
400+ gstreamer-video-1.0
401+ gstreamer-tag-1.0
402+ clutter-gst-3.0
403+)
404+
405 set (VALA_DEPS
406 granite>=0.3.0
407 clutter-gtk-1.0
408@@ -20,6 +29,7 @@
409 gstreamer-pbutils-1.0
410 gstreamer-video-1.0
411 gstreamer-tag-1.0
412+ clutter-gst-3.0
413 )
414
415 pkg_check_modules (DEPS REQUIRED ${PKG_DEPS})
416@@ -57,13 +67,13 @@
417 Settings.vala
418 Utils.vala
419 DiskManager.vala
420+ Window.vala
421 Widgets/BottomBar.vala
422 Widgets/SettingsPopover.vala
423 Widgets/PreviewPopover.vala
424 Widgets/TimeWidget.vala
425 Widgets/Playlist.vala
426 Widgets/PlaylistPopover.vala
427- Widgets/VideoPlayer.vala
428 Widgets/WelcomePage.vala
429 Widgets/PlayerPage.vala
430 PACKAGES
431
432=== modified file 'src/DiskManager.vala'
433--- src/DiskManager.vala 2015-06-07 13:27:10 +0000
434+++ src/DiskManager.vala 2016-03-20 01:32:19 +0000
435@@ -32,11 +32,18 @@
436 }
437
438 private GLib.VolumeMonitor monitor;
439- private List<Volume> volumes;
440+ private Gee.TreeSet<Volume> volumes;
441
442 private DiskManager () {
443+
444+ }
445+
446+ construct {
447 monitor = GLib.VolumeMonitor.get ();
448- volumes = monitor.get_volumes ();
449+ volumes = new Gee.TreeSet<Volume> ();
450+ monitor.get_volumes ().foreach ((volume) => {
451+ volumes.add (volume);
452+ });
453
454 monitor.drive_changed.connect ((drive) => {
455 debug ("Drive changed: %s\n", drive.get_name ());
456@@ -71,30 +78,32 @@
457 monitor.volume_removed.connect ((volume) => {
458 volumes.remove (volume);
459 volume_removed (volume);
460- debug ("Volume removed: %s"+volumes.length ().to_string (), volume.get_name ());
461+ debug ("Volume removed: %s", volume.get_name ());
462 });
463 }
464
465- public GLib.List<Volume> get_volumes () {
466- return volumes.copy ();
467+ public Gee.TreeSet<Volume> get_volumes () {
468+ return volumes;
469 }
470
471- public GLib.List<Volume> get_media_volumes () {
472- GLib.List<Volume> returnValue = new GLib.List<Volume> ();
473+ public Gee.TreeSet<Volume> get_media_volumes () {
474+ var return_value = new Gee.TreeSet<Volume> ();
475 foreach (Volume volume in volumes) {
476- if (has_dvd_media (volume))
477- returnValue.append (volume);
478+ if (has_dvd_media (volume)) {
479+ return_value.add (volume);
480+ }
481 }
482- return returnValue;
483+
484+ return return_value;
485 }
486
487 public bool has_media_volumes () {
488- return (get_media_volumes ().length () > 0);
489+ return (get_media_volumes ().size > 0);
490 }
491
492 private void check_for_volume (Volume volume) {
493 if (has_dvd_media (volume)) {
494- volumes.append (volume);
495+ volumes.add (volume);
496 volume_found (volume);
497 }
498 }
499
500=== modified file 'src/Settings.vala'
501--- src/Settings.vala 2015-05-16 10:13:38 +0000
502+++ src/Settings.vala 2016-03-20 01:32:19 +0000
503@@ -28,7 +28,6 @@
504 public string last_folder {get; set;}
505 public bool playback_wait {get; set;}
506 public bool stay_on_top {get; set;}
507- public bool show_window_decoration {get; set;}
508 public string subtitle_font {get; set; }
509
510 public Settings () {
511
512=== modified file 'src/Utils.vala'
513--- src/Utils.vala 2015-06-06 14:08:15 +0000
514+++ src/Utils.vala 2016-03-20 01:32:19 +0000
515@@ -68,18 +68,9 @@
516 }
517
518 public static string get_basename (string filename) {
519- uint end = 0;
520- for (uint start=filename.length; start != 0; start--) {
521- if (filename[start] == '/') {
522- start ++;
523- return filename.substring (start, end - start);
524- }
525-
526- if (filename[start] == '.' && end == 0)
527- end = start;
528- }
529-
530- return filename.substring (0, end);
531+ var name = Path.get_basename (filename);
532+
533+ return name.split (".", 2)[0];
534 }
535
536 public static string seconds_to_time (int seconds) {
537@@ -103,8 +94,7 @@
538 }
539
540 public static bool has_dvd () {
541- var disk_manager = DiskManager.get_default ();
542- return disk_manager.get_volumes ().length () > 0;
543+ return !DiskManager.get_default ().get_volumes ().is_empty;
544 }
545
546 public static bool file_exists (string uri) {
547@@ -153,8 +143,4 @@
548 }
549 #endif
550 }
551-
552- private bool modifier_is_pressed (Gdk.EventKey event, Gdk.ModifierType modifier) {
553- return (event.state & modifier) == modifier;
554- }
555 }
556
557=== modified file 'src/Widgets/BottomBar.vala'
558--- src/Widgets/BottomBar.vala 2015-11-30 06:29:31 +0000
559+++ src/Widgets/BottomBar.vala 2016-03-20 01:32:19 +0000
560@@ -24,22 +24,19 @@
561 public signal void unfullscreen ();
562 public signal void seeked (double val);
563
564+ public bool playing { get; set; default=false; }
565 public bool hovered { get; set; default=false; }
566 public bool fullscreen { get; set; default=false; }
567 public SettingsPopover preferences_popover;
568 public PlaylistPopover playlist_popover;
569 public TimeWidget time_widget;
570
571- private Widgets.VideoPlayer player;
572 private Gtk.Button play_button;
573 private Gtk.Button preferences_button;
574 private Gtk.Revealer unfullscreen_revealer;
575- private bool is_playing = false;
576 private uint hiding_timer = 0;
577
578- public BottomBar (Widgets.VideoPlayer player) {
579- this.player = player;
580-
581+ public BottomBar (ClutterGst.Playback playback) {
582 this.events |= Gdk.EventMask.POINTER_MOTION_MASK;
583 this.events |= Gdk.EventMask.LEAVE_NOTIFY_MASK;
584 this.events |= Gdk.EventMask.ENTER_NOTIFY_MASK;
585@@ -63,12 +60,11 @@
586 preferences_button.tooltip_text = _("Settings");
587 preferences_button.clicked.connect (() => {preferences_popover.show_all (); preferences_popover.queue_resize ();});
588
589- time_widget = new TimeWidget ();
590- time_widget.seeked.connect ((val) => {seeked (val);});
591+ time_widget = new TimeWidget (playback);
592
593 playlist_popover = new PlaylistPopover ();
594 playlist_popover.relative_to = playlist_button;
595- preferences_popover = new SettingsPopover (player);
596+ preferences_popover = new SettingsPopover (playback);
597 preferences_popover.relative_to = preferences_button;
598
599 main_actionbar.pack_start (play_button);
600@@ -96,13 +92,25 @@
601 }
602 });
603
604+ play_button.clicked.connect (() => {
605+ playing = !playing;
606+ });
607+
608+ notify["playing"].connect (() => {
609+ if (playing == true) {
610+ ((Gtk.Image) play_button.image).icon_name = "media-playback-pause-symbolic";
611+ play_button.tooltip_text = _("Pause");
612+ reveal_control ();
613+ } else {
614+ ((Gtk.Image) play_button.image).icon_name = "media-playback-start-symbolic";
615+ play_button.tooltip_text = _("Play");
616+ set_reveal_child (true);
617+ }
618+ });
619+
620 show_all ();
621 }
622
623- public void set_preview_uri (string uri) {
624- time_widget.set_preview_uri (uri);
625- }
626-
627 public bool get_repeat () {
628 return playlist_popover.rep.active;
629 }
630@@ -123,19 +131,6 @@
631 return unfullscreen_revealer;
632 }
633
634- public void toggle_play_pause () {
635- is_playing = !is_playing;
636- if (is_playing == true) {
637- play_button.image = new Gtk.Image.from_icon_name ("media-playback-pause-symbolic", Gtk.IconSize.BUTTON);
638- play_button.tooltip_text = _("Pause");
639- reveal_control ();
640- } else {
641- play_button.image = new Gtk.Image.from_icon_name ("media-playback-start-symbolic", Gtk.IconSize.BUTTON);
642- play_button.tooltip_text = _("Play");
643- set_reveal_child (true);
644- }
645- }
646-
647 private new void set_reveal_child (bool reveal) {
648 base.set_reveal_child (reveal);
649 if (reveal == true && fullscreen == true) {
650@@ -156,10 +151,6 @@
651 }
652 }
653
654- public void set_progression_time (double current_time, double total_time) {
655- time_widget.set_progression_time (current_time, total_time);
656- }
657-
658 public void reveal_control () {
659 if (child_revealed == false)
660 set_reveal_child (true);
661@@ -168,7 +159,7 @@
662 Source.remove (hiding_timer);
663
664 hiding_timer = GLib.Timeout.add (2000, () => {
665- if (hovered == true || preferences_popover.visible == true || playlist_popover.visible == true || is_playing == false) {
666+ if (hovered == true || preferences_popover.visible == true || playlist_popover.visible == true || playing == false) {
667 hiding_timer = 0;
668 return false;
669 }
670
671=== modified file 'src/Widgets/PlayerPage.vala'
672--- src/Widgets/PlayerPage.vala 2016-02-23 04:31:53 +0000
673+++ src/Widgets/PlayerPage.vala 2016-03-20 01:32:19 +0000
674@@ -7,21 +7,25 @@
675 "ass",
676 "asc"
677 };
678- public class PlayerPage : Gtk.Bin {
679- public GtkClutter.Embed clutter;
680- public Audience.Widgets.VideoPlayer video_player;
681+
682+ public class PlayerPage : Gtk.EventBox {
683+ public signal void unfullscreen_clicked ();
684+ public signal void ended ();
685+
686+ public GtkClutter.Embed clutter;
687+ private Clutter.Actor video_actor;
688 private Audience.Widgets.BottomBar bottom_bar;
689 private Clutter.Stage stage;
690 private Gtk.Revealer unfullscreen_bar;
691 private GtkClutter.Actor unfullscreen_actor;
692 private GtkClutter.Actor bottom_actor;
693- private GnomeMediaKeys mediakeys;
694+ private GnomeMediaKeys mediakeys;
695+ private ClutterGst.Playback playback;
696
697 public GnomeSessionManager session_manager;
698 uint32 inhibit_cookie;
699
700 private bool mouse_primary_down = false;
701- private bool fullscreened = false;
702
703 public bool repeat {
704 get{
705@@ -33,29 +37,75 @@
706 }
707 }
708
709- public signal void ended ();
710+ public bool playing {
711+ get {
712+ return playback.playing;
713+ }
714+ set {
715+ if (playback.playing == value)
716+ return;
717+
718+ playback.playing = value;
719+ }
720+ }
721+
722+ private bool _fullscreened = false;
723+ public bool fullscreened {
724+ get {
725+ return _fullscreened;
726+ }
727+ set {
728+ _fullscreened = value;
729+ bottom_bar.fullscreen = value;
730+ }
731+ }
732
733 public PlayerPage () {
734- video_player = new Widgets.VideoPlayer();
735- video_player.notify["playing"].connect (() => {
736- bottom_bar.toggle_play_pause ();
737- inhibit_session (video_player.playing);
738+ }
739+
740+ construct {
741+ events |= Gdk.EventMask.POINTER_MOTION_MASK;
742+ events |= Gdk.EventMask.KEY_PRESS_MASK;
743+ events |= Gdk.EventMask.KEY_RELEASE_MASK;
744+ playback = new ClutterGst.Playback ();
745+ playback.set_seek_flags (ClutterGst.SeekFlags.ACCURATE);
746+ playback.notify["playing"].connect (() => {
747+ inhibit_session (playback.playing);
748 });
749
750 clutter = new GtkClutter.Embed ();
751 stage = (Clutter.Stage)clutter.get_stage ();
752 stage.background_color = {0, 0, 0, 0};
753
754- video_player.add_constraint (new Clutter.BindConstraint (stage, Clutter.BindCoordinate.WIDTH, 0));
755- video_player.add_constraint (new Clutter.BindConstraint (stage, Clutter.BindCoordinate.HEIGHT, 0));
756-
757- stage.add_child (video_player);
758-
759- bottom_bar = new Widgets.BottomBar (video_player);
760- bottom_bar.play_toggled.connect (() => { video_player.playing = !video_player.playing; });
761- bottom_bar.seeked.connect ((val) => { video_player.progress = val; });
762- bottom_bar.unfullscreen.connect (()=>{set_fullscreen (false);});
763- bottom_bar.set_repeat (false);
764+ video_actor = new Clutter.Actor ();
765+ var aspect_ratio = ClutterGst.Aspectratio.@new ();
766+ ((ClutterGst.Aspectratio) aspect_ratio).paint_borders = false;
767+ ((ClutterGst.Content) aspect_ratio).player = playback;
768+ /* Commented because of a bug in the compositor
769+ ((ClutterGst.Content) aspect_ratio).size_change.connect ((width, height) => {
770+ double aspect = ((double) width)/((double) height);
771+ var geometry = Gdk.Geometry ();
772+ geometry.min_aspect = aspect;
773+ geometry.max_aspect = aspect;
774+ ((Gtk.Window) get_toplevel ()).set_geometry_hints (get_toplevel (), geometry, Gdk.WindowHints.ASPECT);
775+ });
776+ */
777+ video_actor.content = aspect_ratio;
778+
779+ video_actor.add_constraint (new Clutter.BindConstraint (stage, Clutter.BindCoordinate.WIDTH, 0));
780+ video_actor.add_constraint (new Clutter.BindConstraint (stage, Clutter.BindCoordinate.HEIGHT, 0));
781+
782+ Signal.connect (clutter, "button-press-event", (GLib.Callback) navigation_event, this);
783+ Signal.connect (clutter, "button-release-event", (GLib.Callback) navigation_event, this);
784+ Signal.connect (clutter, "key-press-event", (GLib.Callback) navigation_event, this);
785+ Signal.connect (clutter, "key-release-event", (GLib.Callback) navigation_event, this);
786+ Signal.connect (clutter, "motion-notify-event", (GLib.Callback) navigation_event, this);
787+
788+ stage.add_child (video_actor);
789+
790+ bottom_bar = new Widgets.BottomBar (playback);
791+ bottom_bar.bind_property ("playing", playback, "playing", BindingFlags.BIDIRECTIONAL);
792+ bottom_bar.unfullscreen.connect (() => unfullscreen_clicked ());
793
794 unfullscreen_bar = bottom_bar.get_unfullscreen_button ();
795
796@@ -71,12 +121,6 @@
797 unfullscreen_actor.add_constraint (new Clutter.AlignConstraint (stage, Clutter.AlignAxis.Y_AXIS, 0));
798 stage.add_child (unfullscreen_actor);
799
800- this.size_allocate.connect (on_size_allocate);
801- App.get_instance ().mainwindow.key_press_event.connect (on_key_press_event);
802- App.get_instance ().mainwindow.window_state_event.connect (on_window_state_event);
803- if (App.get_instance ().mainwindow.is_maximized)
804- set_fullscreen (true);
805-
806 //media keys
807 try {
808 mediakeys = Bus.get_proxy_sync (BusType.SESSION,
809@@ -92,7 +136,7 @@
810 get_playlist_widget ().next ();
811 break;
812 case "Play":
813- video_player.playing = !video_player.playing;
814+ playback.playing = !playback.playing;
815 break;
816 default:
817 break;
818@@ -104,7 +148,7 @@
819 warning (e.message);
820 }
821
822- App.get_instance ().mainwindow.motion_notify_event.connect ((event) => {
823+ this.motion_notify_event.connect ((event) => {
824 if (mouse_primary_down && settings.move_window) {
825 mouse_primary_down = false;
826 App.get_instance ().mainwindow.begin_move_drag (Gdk.BUTTON_PRIMARY,
827@@ -117,13 +161,6 @@
828 });
829
830 this.button_press_event.connect ((event) => {
831- if (event.button == Gdk.BUTTON_PRIMARY
832- && event.type == Gdk.EventType.2BUTTON_PRESS) // double left click
833- set_fullscreen(!fullscreened);
834-
835- if (event.button == Gdk.BUTTON_SECONDARY) // right click
836- bottom_bar.play_toggled ();
837-
838 if (event.button == Gdk.BUTTON_PRIMARY)
839 mouse_primary_down = true;
840
841@@ -151,31 +188,25 @@
842
843 this.destroy.connect (() => {
844 // FIXME:should find better way to decide if its end of playlist
845- if (video_player.progress > 0.99)
846+ if (playback.progress > 0.99)
847 settings.last_stopped = 0;
848 else
849- settings.last_stopped = video_player.progress;
850+ settings.last_stopped = playback.progress;
851
852 get_playlist_widget ().save_playlist ();
853 });
854
855- /*events*/
856- video_player.text_tags_changed.connect (bottom_bar.preferences_popover.setup_text);
857- video_player.audio_tags_changed.connect (bottom_bar.preferences_popover.setup_audio);
858- video_player.progression_changed.connect ((current_time, total_time) => {
859- bottom_bar.set_progression_time (current_time, total_time);
860- });
861-
862 //end
863- video_player.ended.connect (() => {
864+ playback.eos.connect (() => {
865 Idle.add (() => {
866- video_player.progress = 0;
867+ playback.progress = 0;
868 if (!get_playlist_widget ().next ()) {
869 if (repeat) {
870 play_file (get_playlist_widget ().get_first_item ().get_uri ());
871- video_player.playing = true;
872+ playback.playing = true;
873 } else {
874- video_player.playing = false;
875+ playback.playing = false;
876+ settings.last_stopped = 0;
877 ended ();
878 }
879 }
880@@ -183,26 +214,6 @@
881 });
882 });
883
884- video_player.error.connect (() => {
885- App.get_instance ().page = Page.WELCOME;
886- });
887-
888- video_player.plugin_install_done.connect (() => {
889- App.get_instance ().page = Page.PLAYER;
890- });
891-
892- video_player.notify["playing"].connect (() => {
893- App.get_instance ().mainwindow.set_keep_above (video_player.playing && settings.stay_on_top);
894- });
895-
896- bottom_bar.time_widget.slider_motion_event.connect ((event) => {
897- int x, y;
898- bottom_bar.translate_coordinates (App.get_instance ().mainwindow, (int)event.x, (int)event.y, out x, out y);
899- Gtk.Allocation allocation;
900- clutter.get_allocation (out allocation);
901- update_pointer_position (y, allocation.height);
902- });
903-
904 //playlist wants us to open a file
905 get_playlist_widget ().play.connect ((file) => {
906 this.play_file (file.get_uri ());
907@@ -212,56 +223,35 @@
908 if (bottom_bar.child_revealed == true) {
909 App.get_instance ().mainwindow.get_window ().set_cursor (null);
910 } else {
911- App.get_instance ().mainwindow.get_window ().set_cursor (new Gdk.Cursor (Gdk.CursorType.BLANK_CURSOR));
912+ var window = App.get_instance ().mainwindow.get_window ();
913+ var display = window.get_display ();
914+ var cursor = new Gdk.Cursor.for_display (display, Gdk.CursorType.BLANK_CURSOR);
915+ window.set_cursor (cursor);
916 }
917 });
918
919 add (clutter);
920-
921 show_all ();
922-
923- }
924-
925- ~PlayerPage () {
926- video_player.playing = false;
927-
928- App.get_instance ().set_content_size (0, 0, 0);
929- this.size_allocate.disconnect (on_size_allocate);
930- App.get_instance ().mainwindow.window_state_event.disconnect (on_window_state_event);
931- App.get_instance ().mainwindow.key_press_event.disconnect (on_key_press_event);
932- if (App.get_instance ().mainwindow.get_window () != null)
933- App.get_instance ().mainwindow.get_window ().set_cursor (null);
934-
935- App.get_instance ().mainwindow.unfullscreen ();
936- if (fullscreened)
937- App.get_instance ().mainwindow.maximize ();
938-
939- video_player.text_tags_changed.disconnect (bottom_bar.preferences_popover.setup_text);
940- video_player.audio_tags_changed.disconnect (bottom_bar.preferences_popover.setup_audio);
941 }
942
943 public void play_file (string uri, bool from_beginning = true) {
944 debug ("Opening %s", uri);
945- video_player.uri = uri;
946 get_playlist_widget ().set_current (uri);
947- bottom_bar.set_preview_uri (uri);
948+ playback.uri = uri;
949
950 string? sub_uri = get_subtitle_for_uri (uri);
951- if (sub_uri != null)
952- video_player.set_subtitle_uri (sub_uri);
953-
954- App.get_instance ().set_window_title (get_title (uri));
955- video_player.relayout ();
956-
957- int target_width, target_height, center_x, center_y;
958- get_target_size (out target_width, out target_height, out center_x, out center_y);
959- get_window ().move_resize (center_x, center_y, target_width, target_height);
960-
961- update_aspect_ratio ();
962- video_player.playing = !settings.playback_wait;
963- if (from_beginning)
964- video_player.progress = 0.0;
965-
966+ if (sub_uri != null && sub_uri != uri)
967+ playback.set_subtitle_uri (sub_uri);
968+
969+ App.get_instance ().mainwindow.title = get_title (uri);
970+
971+ if (from_beginning) {
972+ playback.progress = 0.0;
973+ } else {
974+ playback.progress = settings.last_stopped;
975+ }
976+
977+ playback.playing = !settings.playback_wait;
978 Gtk.RecentManager recent_manager = Gtk.RecentManager.get_default ();
979 recent_manager.add_item (uri);
980
981@@ -270,6 +260,10 @@
982 bottom_bar.preferences_popover.setup_audio ();
983 }
984
985+ public string get_played_uri () {
986+ return playback.uri;
987+ }
988+
989 public void next () {
990 get_playlist_widget ().next ();
991 }
992@@ -280,26 +274,46 @@
993
994 public void resume_last_videos () {
995 play_file (settings.current_video);
996- video_player.playing = false;
997- Idle.add (() => {
998- if (settings.resume_videos)
999- video_player.progress = settings.last_stopped;
1000- else
1001- video_player.progress = 0.0;
1002+ playback.playing = false;
1003+ if (settings.resume_videos) {
1004+ playback.progress = settings.last_stopped;
1005+ } else {
1006+ playback.progress = 0.0;
1007+ }
1008
1009- return false;
1010- });
1011- video_player.playing = !settings.playback_wait;
1012+ playback.playing = !settings.playback_wait;
1013 }
1014
1015 public void append_to_playlist (File file) {
1016- get_playlist_widget ().add_item (file);
1017+ if (playback.playing && is_subtitle (file.get_uri ())) {
1018+ playback.set_subtitle_uri (file.get_uri ());
1019+ } else {
1020+ get_playlist_widget ().add_item (file);
1021+ }
1022 }
1023
1024 public void play_first_in_playlist () {
1025 var file = get_playlist_widget ().get_first_item ();
1026 play_file (file.get_uri ());
1027- video_player.progress = 0.0;
1028+ }
1029+
1030+ public void reveal_control () {
1031+ bottom_bar.reveal_control ();
1032+ }
1033+
1034+ public void next_audio () {
1035+ bottom_bar.preferences_popover.next_audio ();
1036+ }
1037+
1038+ public void next_text () {
1039+ bottom_bar.preferences_popover.next_text ();
1040+ }
1041+
1042+ public void seek_jump_seconds (int seconds) {
1043+ var duration = playback.duration;
1044+ var progress = playback.progress;
1045+ var new_progress = ((duration * progress) + (double)seconds)/duration;
1046+ playback.progress = double.min (new_progress, 1.0);
1047 }
1048
1049 private Widgets.Playlist get_playlist_widget () {
1050@@ -324,7 +338,7 @@
1051 return null;
1052 }
1053
1054- public static bool is_subtitle (string uri) {
1055+ private bool is_subtitle (string uri) {
1056 if (uri.length < 4 || uri.get_char (uri.length-4) != '.')
1057 return false;
1058
1059@@ -344,174 +358,42 @@
1060 return false;
1061 }
1062
1063- private void get_target_size (out int target_width, out int target_height,
1064- out int center_x, out int center_y) {
1065- Gdk.Rectangle monitor;
1066- var screen = Gdk.Screen.get_default ();
1067- screen.get_monitor_geometry (screen.get_monitor_at_window (get_window ()),
1068- out monitor);
1069-
1070- if (monitor.width > video_player.video_width
1071- && monitor.height > video_player.video_height) {
1072- target_width = (int) video_player.video_width;
1073- target_height = (int) video_player.video_height;
1074- } else {
1075- target_width = (int)(monitor.width * 0.9);
1076- target_height = (int)((double) video_player.video_height / video_player.video_width * target_width);
1077- }
1078- center_x = monitor.width / 2 - target_width /2 + monitor.x;
1079- center_y = monitor.height / 2 - target_height /2 + monitor.y;
1080- }
1081-
1082- private bool on_key_press_event (Gdk.EventKey e) {
1083- switch (e.keyval) {
1084- case Gdk.Key.p:
1085- case Gdk.Key.space:
1086- video_player.playing = !video_player.playing;
1087- break;
1088- case Gdk.Key.Escape:
1089- if (fullscreened) {
1090- set_fullscreen (false);
1091- } else {
1092- App.get_instance ().mainwindow.destroy ();
1093- }
1094- return true;
1095- case Gdk.Key.Down:
1096- if (modifier_is_pressed (e, Gdk.ModifierType.SHIFT_MASK)) {
1097- video_player.seek_jump_seconds (-5); // 5 secs
1098- } else {
1099- video_player.seek_jump_seconds (-60); // 1 min
1100- }
1101- bottom_bar.reveal_control ();
1102- break;
1103- case Gdk.Key.Left:
1104- if (modifier_is_pressed (e, Gdk.ModifierType.SHIFT_MASK)) {
1105- video_player.seek_jump_seconds (-1); // 1 sec
1106- } else {
1107- video_player.seek_jump_seconds (-10); // 10 secs
1108- }
1109- bottom_bar.reveal_control ();
1110- break;
1111- case Gdk.Key.Right:
1112- if (modifier_is_pressed (e, Gdk.ModifierType.SHIFT_MASK)) {
1113- video_player.seek_jump_seconds (1); // 1 sec
1114- } else {
1115- video_player.seek_jump_seconds (10); // 10 secs
1116- }
1117- bottom_bar.reveal_control ();
1118- break;
1119- case Gdk.Key.Up:
1120- if (modifier_is_pressed (e, Gdk.ModifierType.SHIFT_MASK)) {
1121- video_player.seek_jump_seconds (5); // 5 secs
1122- } else {
1123- video_player.seek_jump_seconds (60); // 1 min
1124- }
1125- bottom_bar.reveal_control ();
1126- break;
1127- case Gdk.Key.Page_Down:
1128- video_player.seek_jump_seconds (-600); // 10 mins
1129- bottom_bar.reveal_control ();
1130- break;
1131- case Gdk.Key.Page_Up:
1132- video_player.seek_jump_seconds (600); // 10 mins
1133- bottom_bar.reveal_control ();
1134- break;
1135- case Gdk.Key.a:
1136- bottom_bar.preferences_popover.next_audio ();
1137- break;
1138- case Gdk.Key.s:
1139- bottom_bar.preferences_popover.next_text ();
1140- break;
1141- case Gdk.Key.f:
1142- if (fullscreened)
1143- set_fullscreen (false);
1144- else
1145- set_fullscreen (true);
1146-
1147- break;
1148- default:
1149- break;
1150- }
1151-
1152- return false;
1153- }
1154-
1155- private bool on_window_state_event (Gdk.EventWindowState e){
1156- switch (e.changed_mask){
1157- case Gdk.WindowState.FULLSCREEN:
1158- fullscreened= ((e.new_window_state & Gdk.WindowState.FULLSCREEN)!=0);
1159- break;
1160- case Gdk.WindowState.MAXIMIZED:
1161- bool currently_maximixed = ((e.new_window_state & Gdk.WindowState.MAXIMIZED)!=0);
1162- set_fullscreen (currently_maximixed);
1163- break;
1164- }
1165- return false;
1166- }
1167-
1168- private void set_fullscreen (bool full){
1169- fullscreened = full;
1170- if (full) {
1171- App.get_instance ().mainwindow.fullscreen ();
1172- } else {
1173- // unfullscreen shoulnd't be call from elsewhere other than here
1174- App.get_instance ().mainwindow.maximize ();
1175- App.get_instance ().mainwindow.unfullscreen ();
1176- }
1177- bottom_bar.fullscreen = full;
1178- }
1179-
1180- private uint update_aspect_ratio_timeout = 0;
1181- private bool update_aspect_ratio_locked = false;
1182- private int prev_width = 0;
1183- private int prev_height = 0;
1184- private int old_h = -1;
1185- private int old_w = -1;
1186- /**
1187- * Updates the window's aspect ratio locking if enabled.
1188- * Return type is just there to make it compatible with Idle.add()
1189- */
1190- private bool update_aspect_ratio () {
1191- if (!settings.keep_aspect
1192- || video_player.video_width < 1
1193- || video_player.height < 1
1194- || !clutter.visible)
1195- return false;
1196-
1197- if (update_aspect_ratio_timeout != 0)
1198- Source.remove (update_aspect_ratio_timeout);
1199-
1200- update_aspect_ratio_timeout = Timeout.add (200, () => {
1201- Gtk.Allocation a;
1202- clutter.get_allocation (out a);
1203- debug ("%i %i %i,%i\n", a.x, a.y, (this.get_allocated_width () - this.clutter.get_allocated_width ()) / 2, (this.get_allocated_height () - this.clutter.get_allocated_height ()) / 2);
1204-
1205- double width, height;
1206- width = clutter.get_allocated_width ();
1207- height = width * video_player.video_height / (double) video_player.video_width;
1208-
1209- App.get_instance ().set_content_size (width, height,clutter.get_allocated_height ());
1210-
1211- prev_width = this.get_allocated_width ();
1212- prev_height = this.get_allocated_height ();
1213-
1214- update_aspect_ratio_timeout = 0;
1215-
1216- return false;
1217- });
1218-
1219- return false;
1220- }
1221- private void on_size_allocate (Gtk.Allocation alloc) {
1222- if (alloc.width != old_w || alloc.height != old_h) {
1223- if (video_player.relayout ()) {
1224- old_w = alloc.width;
1225- old_h = alloc.height;
1226- }
1227- }
1228-
1229- if (prev_width != this.get_allocated_width () || prev_height != this.get_allocated_height ())
1230- Idle.add (update_aspect_ratio);
1231+ [CCode (instance_pos = -1)]
1232+ private bool navigation_event (GtkClutter.Embed embed, Clutter.Event event) {
1233+ var video_sink = playback.get_video_sink ();
1234+ var frame = video_sink.get_frame ();
1235+
1236+ if (frame == null)
1237+ return true;
1238+
1239+ float x, y;
1240+ event.get_coords (out x, out y);
1241+ // Transform event coordinates into the actor's coordinates
1242+ video_actor.transform_stage_point (x, y, out x, out y);
1243+ float actor_width, actor_height;
1244+ video_actor.get_size (out actor_width, out actor_height);
1245+
1246+ /* Convert event's coordinates into the frame's coordinates. */
1247+ x = x * frame.resolution.width / actor_width;
1248+ y = y * frame.resolution.height / actor_height;
1249+
1250+ switch (event.type) {
1251+ case Clutter.EventType.MOTION:
1252+ ((Gst.Video.Navigation) video_sink).send_mouse_event ("mouse-move", 0, x, y);
1253+ break;
1254+ case Clutter.EventType.BUTTON_PRESS:
1255+ ((Gst.Video.Navigation) video_sink).send_mouse_event ("mouse-button-press", (int)event.button.button, x, y);
1256+ break;
1257+ case Clutter.EventType.KEY_PRESS:
1258+ warning (X.keysym_to_string (event.key.keyval));
1259+ ((Gst.Video.Navigation) video_sink).send_key_event ("key-press", X.keysym_to_string (event.key.keyval));
1260+ break;
1261+ case Clutter.EventType.KEY_RELEASE:
1262+ ((Gst.Video.Navigation) video_sink).send_key_event ("key-release", X.keysym_to_string (event.key.keyval));
1263+ break;
1264+ }
1265+
1266+ return false;
1267 }
1268
1269 X.Display dpy;
1270
1271=== modified file 'src/Widgets/Playlist.vala'
1272--- src/Widgets/Playlist.vala 2015-10-26 18:28:19 +0000
1273+++ src/Widgets/Playlist.vala 2016-03-20 01:32:19 +0000
1274@@ -197,7 +197,7 @@
1275 }
1276
1277 public void save_playlist () {
1278- if (Audience.App.get_instance ().is_privacy_mode_enabled ()) {
1279+ if (Audience.App.get_instance ().mainwindow.is_privacy_mode_enabled ()) {
1280 return;
1281 }
1282
1283
1284=== modified file 'src/Widgets/PlaylistPopover.vala'
1285--- src/Widgets/PlaylistPopover.vala 2015-06-08 05:53:03 +0000
1286+++ src/Widgets/PlaylistPopover.vala 2016-03-20 01:32:19 +0000
1287@@ -35,8 +35,6 @@
1288 fil.set_tooltip_text (_("Open file"));
1289 dvd = new Gtk.Button.from_icon_name ("media-optical-symbolic", Gtk.IconSize.BUTTON);
1290 dvd.set_tooltip_text (_("Play from Disc"));
1291- dvd.no_show_all = true;
1292- set_dvd_visibility (App.get_instance ().has_media_volumes ());
1293
1294 rep = new Gtk.ToggleButton ();
1295 rep.set_image (new Gtk.Image.from_icon_name ("media-playlist-no-repeat-symbolic", Gtk.IconSize.BUTTON));
1296@@ -45,19 +43,18 @@
1297 playlist_scrolled = new Gtk.ScrolledWindow (null, null);
1298 playlist_scrolled.set_min_content_height (100);
1299 playlist_scrolled.set_min_content_width (260);
1300- var app = ((Audience.App) GLib.Application.get_default ());
1301
1302 playlist = new Playlist ();
1303 playlist_scrolled.add (playlist);
1304
1305 fil.clicked.connect ( () => {
1306 hide ();
1307- app.run_open_file ();
1308+ App.get_instance ().mainwindow.run_open_file ();
1309 });
1310
1311 dvd.clicked.connect ( () => {
1312 hide ();
1313- app.run_open_dvd ();
1314+ App.get_instance ().mainwindow.run_open_dvd ();
1315 });
1316
1317 rep.toggled.connect ( () => {
1318@@ -78,19 +75,19 @@
1319
1320 add (grid);
1321
1322- App.get_instance ().media_volumes_changed.connect (on_media_volumes_changed);
1323- }
1324-
1325- ~PlaylistPopover () {
1326- App.get_instance ().media_volumes_changed.disconnect (on_media_volumes_changed);
1327- }
1328-
1329- private void on_media_volumes_changed () {
1330- set_dvd_visibility (App.get_instance ().has_media_volumes ());
1331+ var disk_manager = DiskManager.get_default ();
1332+ set_dvd_visibility (disk_manager.has_media_volumes ());
1333+ disk_manager.volume_found.connect ((vol) => {
1334+ set_dvd_visibility (disk_manager.has_media_volumes ());
1335+ });
1336+
1337+ disk_manager.volume_removed.connect ((vol) => {
1338+ set_dvd_visibility (disk_manager.has_media_volumes ());
1339+ });
1340 }
1341
1342 private void set_dvd_visibility (bool visible) {
1343- dvd.no_show_all = true;
1344+ dvd.no_show_all = !visible;
1345 dvd.visible = visible;
1346 }
1347
1348
1349=== modified file 'src/Widgets/PreviewPopover.vala'
1350--- src/Widgets/PreviewPopover.vala 2015-06-07 13:27:10 +0000
1351+++ src/Widgets/PreviewPopover.vala 2016-03-20 01:32:19 +0000
1352@@ -19,85 +19,79 @@
1353 */
1354
1355 public class Audience.Widgets.PreviewPopover : Gtk.Popover {
1356- public Clutter.Actor preview_actor;
1357- dynamic Gst.Element preview_playbin;
1358- Clutter.Texture video;
1359- double ratio = 0;
1360+ private enum PlayFlags {
1361+ VIDEO = (1 << 0),
1362+ AUDIO = (1 << 1),
1363+ TEXT = (1 << 2),
1364+ VIS = (1 << 3),
1365+ SOFT_VOLUME = (1 << 4),
1366+ NATIVE_AUDIO = (1 << 5),
1367+ NATIVE_VIDEO = (1 << 6),
1368+ DOWNLOAD = (1 << 7),
1369+ BUFFERING = (1 << 8),
1370+ DEINTERLACE = (1 << 9),
1371+ SOFT_COLORBALANCE = (1 << 10)
1372+ }
1373+
1374+ ClutterGst.Playback playback;
1375+ GtkClutter.Embed clutter;
1376 uint? timer_id = null;
1377- public PreviewPopover () {
1378+
1379+ public PreviewPopover (ClutterGst.Playback main_playback) {
1380 opacity = GLOBAL_OPACITY;
1381 can_focus = false;
1382 sensitive = false;
1383 modal = false;
1384
1385- // connect gstreamer stuff
1386- preview_playbin = Gst.ElementFactory.make ("playbin", "play");
1387- preview_playbin.get_bus ().add_signal_watch ();
1388- preview_playbin.get_bus ().message.connect ((msg) => {
1389- switch (msg.type) {
1390- case Gst.MessageType.STATE_CHANGED:
1391- break;
1392- case Gst.MessageType.ASYNC_DONE:
1393- break;
1394- }
1395+ playback = new ClutterGst.Playback ();
1396+ playback.ready.connect (() => {
1397+ unowned Gst.Element pipeline = playback.get_pipeline ();
1398+ int flags;
1399+ pipeline.get ("flags", out flags);
1400+ flags &= ~PlayFlags.TEXT; //disable subtitle
1401+ flags &= ~PlayFlags.AUDIO; //disable audio sink
1402+ pipeline.set ("flags", flags);
1403 });
1404- video = new Clutter.Texture ();
1405
1406- dynamic Gst.Element video_sink = Gst.ElementFactory.make ("cluttersink", "source");
1407- video_sink.texture = video;
1408- preview_playbin.video_sink = video_sink;
1409- var clutter = new GtkClutter.Embed ();
1410- clutter.margin = 6;
1411+ playback.set_seek_flags (ClutterGst.SeekFlags.ACCURATE);
1412+ playback.uri = main_playback.uri;
1413+ playback.playing = false;
1414+ clutter = new GtkClutter.Embed ();
1415+ clutter.margin = 3;
1416 var stage = (Clutter.Stage)clutter.get_stage ();
1417 stage.background_color = {0, 0, 0, 0};
1418- stage.use_alpha = true;
1419-
1420- video.add_constraint (new Clutter.BindConstraint (stage, Clutter.BindCoordinate.WIDTH, 0));
1421- video.add_constraint (new Clutter.BindConstraint (stage, Clutter.BindCoordinate.HEIGHT, 0));
1422-
1423- stage.add_child (video);
1424+
1425+ var video_actor = new Clutter.Actor ();
1426+ var aspect_ratio = ClutterGst.Aspectratio.@new ();
1427+ ((ClutterGst.Aspectratio) aspect_ratio).paint_borders = false;
1428+ ((ClutterGst.Content) aspect_ratio).player = playback;
1429+ video_actor.content = aspect_ratio;
1430+ ((ClutterGst.Content) aspect_ratio).size_change.connect ((width, height) => {
1431+ clutter.set_size_request (200, (int)(((double) (height*200))/((double) width)));
1432+ });
1433+
1434+ video_actor.add_constraint (new Clutter.BindConstraint (stage, Clutter.BindCoordinate.WIDTH, 0));
1435+ video_actor.add_constraint (new Clutter.BindConstraint (stage, Clutter.BindCoordinate.HEIGHT, 0));
1436+
1437+ stage.add_child (video_actor);
1438 add (clutter);
1439- //show_all ();
1440+
1441 closed.connect (() => {
1442- preview_playbin.set_state (Gst.State.PAUSED);
1443+ playback.playing = false;
1444 cancel_loop_timer ();
1445 });
1446 }
1447+
1448 ~PreviewPopover () {
1449- preview_playbin.set_state (Gst.State.NULL);
1450- }
1451-
1452- public void set_preview_uri (string uri) {
1453- preview_playbin.set_state (Gst.State.READY);
1454- preview_playbin.uri = uri;
1455- int flags;
1456- preview_playbin.get ("flags", out flags);
1457- flags &= ~PlayFlags.TEXT; //disable subtitle
1458- flags &= ~PlayFlags.AUDIO; //disable audio sink
1459- preview_playbin.set ("flags", flags);
1460-
1461- try {
1462- var info = new Gst.PbUtils.Discoverer (10 * Gst.SECOND).discover_uri (uri);
1463- var video = info.get_video_streams ();
1464- if (video != null && video.data != null) {
1465- var video_info = (Gst.PbUtils.DiscovererVideoInfo)video.data;
1466- uint video_width = video_info.get_width ();
1467- uint video_height = video_info.get_height ();
1468- ratio = ((double) video_height) / ((double) video_width);
1469- set_size_request (200, (int) (ratio*200));
1470- }
1471- } catch (Error e) {
1472- warning (e.message);
1473- return;
1474- }
1475+ playback.playing = false;
1476+ cancel_loop_timer ();
1477 }
1478
1479 public void set_preview_progress (double progress) {
1480 cancel_loop_timer ();
1481- int64 length;
1482- preview_playbin.query_duration (Gst.Format.TIME, out length);
1483- preview_playbin.seek_simple (Gst.Format.TIME, Gst.SeekFlags.FLUSH | Gst.SeekFlags.ACCURATE, (int64)(double.max (progress, 0.0) * length));
1484- preview_playbin.set_state (Gst.State.PLAYING);
1485+ playback.progress = progress;
1486+ playback.playing = true;
1487+
1488 timer_id = Timeout.add_seconds (5, () => {
1489 set_preview_progress (progress);
1490 return false;
1491
1492=== modified file 'src/Widgets/SettingsPopover.vala'
1493--- src/Widgets/SettingsPopover.vala 2015-06-14 07:02:09 +0000
1494+++ src/Widgets/SettingsPopover.vala 2016-03-20 01:32:19 +0000
1495@@ -22,14 +22,14 @@
1496 private Gtk.ComboBoxText languages;
1497 private Gtk.ComboBoxText subtitles;
1498 private Gtk.FileChooserButton external_subtitle_file;
1499- private Widgets.VideoPlayer player;
1500+ private ClutterGst.Playback playback;
1501
1502- public SettingsPopover (Widgets.VideoPlayer player) {
1503+ public SettingsPopover (ClutterGst.Playback playback) {
1504+ this.playback = playback;
1505 opacity = GLOBAL_OPACITY;
1506
1507 languages = new Gtk.ComboBoxText ();
1508 subtitles = new Gtk.ComboBoxText ();
1509- this.player = player;
1510
1511 var all_files_filter = new Gtk.FileFilter ();
1512 all_files_filter.set_filter_name (_("All files"));
1513@@ -68,118 +68,84 @@
1514 setupgrid.column_spacing = 12;
1515
1516 external_subtitle_file.file_set.connect (() => {
1517- player.set_subtitle_uri (external_subtitle_file.get_uri ());
1518+ playback.set_subtitle_uri (external_subtitle_file.get_uri ());
1519 });
1520
1521- player.external_subtitle_changed.connect ((uri) => {
1522- external_subtitle_file.select_uri (uri);
1523+ playback.notify["subtitle_uri"].connect (() => {
1524+ external_subtitle_file.select_uri (playback.subtitle_uri);
1525 });
1526
1527 subtitles.changed.connect (() => {
1528- if (subtitles.active_id == null)
1529- return;
1530-
1531- var id = int.parse (subtitles.active_id);
1532- player.current_text = id;
1533+ if (subtitles.active <= -1)
1534+ return;
1535+
1536+ if (subtitles.active_id == "none") {
1537+ playback.subtitle_track = -1;
1538+ return;
1539+ }
1540+
1541+ playback.subtitle_track = subtitles.active;
1542 });
1543
1544 languages.changed.connect ( () => { //place it here to not get problems
1545- if (languages.active_id == null)
1546+ if (languages.active <= -1 || languages.active_id == "def")
1547 return;
1548
1549- player.current_audio = int.parse (languages.active_id);
1550+ playback.audio_stream = languages.active;
1551 });
1552
1553 add (setupgrid);
1554 }
1555
1556 public void setup_text () {
1557- subtitles.sensitive = false;
1558 if (subtitles.model.iter_n_children (null) > 0)
1559 subtitles.remove_all ();
1560
1561- int n_text;
1562- player.playbin.get ("n-text", out n_text);
1563- for (var i=0; i<n_text; i++) {
1564- Gst.TagList tags = null;
1565- Signal.emit_by_name (player.playbin, "get-text-tags", i, out tags);
1566- if (tags == null)
1567- continue;
1568-
1569- string desc;
1570- string readable = null;
1571- tags.get_string (Gst.Tags.LANGUAGE_CODE, out desc);
1572- if (desc == null)
1573- tags.get_string (Gst.Tags.CODEC, out desc);
1574-
1575- if (desc != null) {
1576- readable = Gst.Tag.get_language_name (desc);
1577- var language = Gst.Tag.get_language_name (desc);
1578- subtitles.append (i.to_string (), language == null ? desc : language);
1579- subtitles.sensitive = true;
1580- }
1581- }
1582-
1583- subtitles.append ("-1", _("None"));
1584- subtitles.active_id = player.current_text.to_string ();
1585+ playback.get_subtitle_tracks ().foreach ((lang) => {
1586+ subtitles.append (lang, lang);
1587+ });
1588+
1589+ subtitles.append ("none", _("None"));
1590+ subtitles.active = playback.subtitle_track;
1591+ subtitles.sensitive = subtitles.model.iter_n_children (null) > 1;
1592 }
1593
1594 public void setup_audio () {
1595- languages.sensitive = false;
1596 if (languages.model.iter_n_children (null) > 0)
1597 languages.remove_all ();
1598
1599- int n_audio;
1600- player.playbin.get ("n-audio", out n_audio);
1601- for (var i=0; i<n_audio; i++) {
1602- Gst.TagList tags = null;
1603- Signal.emit_by_name (player.playbin, "get-audio-tags", i, out tags);
1604- if (tags == null)
1605- continue;
1606-
1607- string desc;
1608- string readable = null;
1609- tags.get_string (Gst.Tags.LANGUAGE_CODE, out desc);
1610- if (desc == null)
1611- tags.get_string (Gst.Tags.CODEC, out desc);
1612-
1613- if (desc != null) {
1614- readable = Gst.Tag.get_language_name (desc);
1615- languages.append (i.to_string (), readable == null ? desc : readable);
1616- }
1617- }
1618-
1619- var audio_items = languages.model.iter_n_children (null);
1620- if (audio_items <= 0) {
1621+ playback.get_audio_streams ().foreach ((lang) => {
1622+ languages.append (lang, lang);
1623+ });
1624+
1625+ languages.sensitive = languages.model.iter_n_children (null) > 0;
1626+ if (!languages.sensitive) {
1627 languages.append ("def", _("Default"));
1628 languages.active = 0;
1629 } else {
1630- if (audio_items != 1)
1631- languages.sensitive = true;
1632-
1633- languages.active_id = player.current_audio.to_string ();
1634+ languages.active = playback.subtitle_track;
1635 }
1636 }
1637
1638 public void next_audio () {
1639- int current = int.parse (languages.active_id);
1640+ int current = languages.active;
1641 if (current < languages.model.iter_n_children (null) - 1) {
1642 current++;
1643 } else {
1644 current = 0;
1645 }
1646
1647- languages.active_id = current.to_string ();
1648+ languages.active = current;
1649 }
1650
1651 public void next_text () {
1652- int current = int.parse (subtitles.active_id);
1653+ int current = subtitles.active;
1654 if (current < subtitles.model.iter_n_children (null)) {
1655 current++;
1656 } else {
1657 current = 0;
1658 }
1659
1660- subtitles.active_id = current.to_string ();
1661+ subtitles.active = current;
1662 }
1663 }
1664
1665=== modified file 'src/Widgets/TimeWidget.vala'
1666--- src/Widgets/TimeWidget.vala 2014-11-30 22:46:15 +0000
1667+++ src/Widgets/TimeWidget.vala 2016-03-20 01:32:19 +0000
1668@@ -20,25 +20,39 @@
1669 */
1670
1671 public class Audience.Widgets.TimeWidget : Gtk.Grid {
1672- public signal void slider_motion_event (Gdk.EventMotion event);
1673-
1674+ unowned ClutterGst.Playback main_playback;
1675 public Gtk.Label progression_label;
1676 public Gtk.Label time_label;
1677 public Gtk.Scale scale;
1678- public signal void seeked (double val);
1679 private Audience.Widgets.PreviewPopover preview_popover;
1680- private bool is_seeking = false;
1681 private bool released = true;
1682 private uint timeout_id = 0;
1683 private int original = 0;
1684
1685- public TimeWidget () {
1686+ public TimeWidget (ClutterGst.Playback main_playback) {
1687+ this.main_playback = main_playback;
1688 orientation = Gtk.Orientation.HORIZONTAL;
1689 column_spacing = 12;
1690 halign = Gtk.Align.CENTER;
1691 progression_label = new Gtk.Label ("");
1692 time_label = new Gtk.Label ("");
1693
1694+ main_playback.notify["progress"].connect (progress_callback);
1695+
1696+ main_playback.notify["duration"].connect (() => {
1697+ if (preview_popover != null) {
1698+ preview_popover.destroy ();
1699+ }
1700+ time_label.label = seconds_to_time ((int) main_playback.duration);
1701+ progress_callback ();
1702+ // Don't allow to change the time if there is none.
1703+ sensitive = (main_playback.duration != 0);
1704+ if (sensitive) {
1705+ preview_popover = new Audience.Widgets.PreviewPopover (main_playback);
1706+ preview_popover.relative_to = this;
1707+ }
1708+ });
1709+
1710 scale = new Gtk.Scale.with_range (Gtk.Orientation.HORIZONTAL, 0, 1, 0.1);
1711 scale.expand = true;
1712 scale.draw_value = false;
1713@@ -47,8 +61,8 @@
1714 scale.events |= Gdk.EventMask.LEAVE_NOTIFY_MASK;
1715 scale.events |= Gdk.EventMask.ENTER_NOTIFY_MASK;
1716 scale.button_press_event.connect ((event) => {
1717- is_seeking = true;
1718 released = false;
1719+ main_playback.notify["progress"].disconnect (progress_callback);
1720
1721 if (timeout_id != 0)
1722 Source.remove (timeout_id);
1723@@ -56,9 +70,8 @@
1724 timeout_id = Timeout.add (300, () => {
1725 if (released == false)
1726 return true;
1727- seeked (scale.get_value ());
1728- is_seeking = false;
1729
1730+ main_playback.progress = scale.get_value ();
1731 timeout_id = 0;
1732
1733 return false;
1734@@ -68,12 +81,20 @@
1735 });
1736
1737 scale.enter_notify_event.connect ((event) => {
1738- preview_popover.show_all ();
1739+ if (event.detail != Gdk.NotifyType.INFERIOR && event.detail != Gdk.NotifyType.NONLINEAR) {
1740+ preview_popover.show_all ();
1741+ return false;
1742+ }
1743+
1744 return false;
1745 });
1746
1747 scale.leave_notify_event.connect ((event) => {
1748- preview_popover.hide ();
1749+ if (event.detail != Gdk.NotifyType.INFERIOR && event.detail != Gdk.NotifyType.NONLINEAR) {
1750+ preview_popover.hide ();
1751+ return false;
1752+ }
1753+
1754 return false;
1755 });
1756
1757@@ -87,25 +108,20 @@
1758 pointing.x = (int)(event.x) - event.window.get_width ()/2 - distance/2;
1759 preview_popover.set_pointing_to ((Gdk.Rectangle)pointing);
1760 preview_popover.set_preview_progress (((double)event.x)/((double)event.window.get_width ()));
1761-
1762- slider_motion_event (event);
1763-
1764- return false;
1765- });
1766-
1767- scale.button_release_event.connect ((event) => {released = true; return false;});
1768- preview_popover = new Audience.Widgets.PreviewPopover ();
1769- preview_popover.relative_to = this;
1770+ return false;
1771+ });
1772+
1773+ scale.button_release_event.connect ((event) => {
1774+ released = true;
1775+ main_playback.notify["progress"].connect (progress_callback);
1776+ return false;
1777+ });
1778
1779 add (progression_label);
1780 add (scale);
1781 add (time_label);
1782 }
1783
1784- public void set_preview_uri (string uri) {
1785- preview_popover.set_preview_uri (uri);
1786- }
1787-
1788 public override void get_preferred_width (out int minimum_width, out int natural_width) {
1789 base.get_preferred_width (out minimum_width, out natural_width);
1790
1791@@ -117,11 +133,8 @@
1792 }
1793 }
1794
1795- public void set_progression_time (double current_time, double total_time) {
1796- if (is_seeking == true)
1797- return;
1798- scale.set_value (current_time/total_time);
1799- progression_label.label = seconds_to_time ((int)(current_time / 1000000000));
1800- time_label.label = seconds_to_time ((int)((total_time - current_time) / 1000000000));
1801+ private void progress_callback () {
1802+ scale.set_value (main_playback.progress);
1803+ progression_label.label = seconds_to_time ((int) (main_playback.duration * main_playback.progress));
1804 }
1805 }
1806
1807=== removed file 'src/Widgets/VideoPlayer.vala'
1808--- src/Widgets/VideoPlayer.vala 2016-02-23 04:31:53 +0000
1809+++ src/Widgets/VideoPlayer.vala 1970-01-01 00:00:00 +0000
1810@@ -1,491 +0,0 @@
1811-// -*- Mode: vala; indent-tabs-mode: nil; tab-width: 4 -*-
1812-/*-
1813- * Copyright (c) 2013-2014 Audience Developers (http://launchpad.net/pantheon-chat)
1814- *
1815- * This program is free software: you can redistribute it and/or modify
1816- * it under the terms of the GNU General Public License as published by
1817- * the Free Software Foundation, either version 3 of the License, or
1818- * (at your option) any later version.
1819-
1820- * This program is distributed in the hope that it will be useful,
1821- * but WITHOUT ANY WARRANTY; without even the implied warranty of
1822- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
1823- * GNU General Public License for more details.
1824-
1825- * You should have received a copy of the GNU General Public License
1826- * along with this program. If not, see <http://www.gnu.org/licenses/>.
1827- *
1828- * Authored by: Tom Beckmann <tomjonabc@gmail.com>
1829- * Corentin Noël <corentin@elementaryos.org>
1830- */
1831-
1832-using Clutter;
1833-
1834-enum PlayFlags {
1835- VIDEO = (1 << 0),
1836- AUDIO = (1 << 1),
1837- TEXT = (1 << 2),
1838- VIS = (1 << 3),
1839- SOFT_VOLUME = (1 << 4),
1840- NATIVE_AUDIO = (1 << 5),
1841- NATIVE_VIDEO = (1 << 6),
1842- DOWNLOAD = (1 << 7),
1843- BUFFERING = (1 << 8),
1844- DEINTERLACE = (1 << 9),
1845- SOFT_COLORBALANCE = (1 << 10)
1846-}
1847-
1848-/* use internal function while
1849- * https://bugzilla.gnome.org/show_bug.cgi?id=754567
1850- * isn't fixed
1851- */
1852-[CCode (cprefix = "Gst", gir_namespace="GstVideo", gir_version="1.0", lower_case_cprefix="gst_video_", cheader_filename = "gst/video/video.h")]
1853-namespace GstVideo {
1854- [CCode (cheader_filename = "gst/video/video.h")]
1855- public static extern bool calculate_display_ratio (out uint dar_n, out uint dar_d, uint video_width, uint video_height, uint video_par_n, uint video_par_d, uint display_par_n, uint display_par_d);
1856-}
1857-
1858-namespace Audience.Widgets {
1859- public class VideoPlayer : Actor {
1860-
1861- bool _playing;
1862- public bool playing {
1863- get {
1864- return _playing;
1865- }
1866- set {
1867- if (value == playing)
1868- return;
1869-
1870- playbin.set_state (value ? Gst.State.PLAYING : Gst.State.PAUSED);
1871- _playing = value;
1872- }
1873- }
1874-
1875- public double progress {
1876- get {
1877- int64 length, prog;
1878- playbin.query_duration (Gst.Format.TIME, out length);
1879- playbin.query_position (Gst.Format.TIME, out prog);
1880- if (length == 0)
1881- return 0;
1882-
1883- return prog / (double)length;
1884- }
1885- set {
1886- int64 length;
1887- playbin.query_duration (Gst.Format.TIME, out length);
1888- playbin.seek_simple (Gst.Format.TIME, Gst.SeekFlags.FLUSH | Gst.SeekFlags.ACCURATE, (int64)(double.max (value, 0.0) * length));
1889- }
1890- }
1891-
1892- public double volume {
1893- get {
1894- return playbin.volume;
1895- }
1896- set {
1897- playbin.volume = value;
1898- }
1899- }
1900-
1901- public string uri {
1902- owned get {
1903- return playbin.current_uri;
1904- }
1905- set {
1906- if (value == (string)playbin.uri)
1907- return;
1908-
1909- playbin.get_bus ().set_flushing (true);
1910- playing = false;
1911- playbin.set_state (Gst.State.READY);
1912- playbin.suburi = null;
1913- subtitle_uri = null;
1914- playbin.get_bus ().set_flushing (false);
1915- playbin.uri = value;
1916- volume = 1.0;
1917-
1918- relayout ();
1919- playing = false;
1920-
1921- // this has to be done after setting uri playbin, if not codec checking will fail
1922- try {
1923- var info = new Gst.PbUtils.Discoverer (10 * Gst.SECOND).discover_uri (value);
1924- var video = info.get_video_streams ();
1925- if (video != null && video.data != null) {
1926- var video_info = (Gst.PbUtils.DiscovererVideoInfo)video.data;
1927- uint w, h;
1928- get_media_size (video_info, out w, out h);
1929- video_width = w;
1930- video_height = h;
1931- }
1932- } catch (Error e) {
1933- warning (e.message);
1934- return;
1935- }
1936- }
1937- }
1938-
1939- public int current_audio {
1940- get {
1941- return playbin.current_audio;
1942- }
1943- set {
1944- playbin.current_audio = value;
1945- }
1946- }
1947-
1948- string? subtitle_uri = null;
1949-
1950- // currently used text stream. Set to -1 to disable subtitles
1951- public int current_text {
1952- get {
1953- return playbin.current_text;
1954- }
1955- set {
1956- if (value == current_text)
1957- return;
1958-
1959- int flags;
1960- playbin.get ("flags", out flags);
1961-
1962- var disable = value < 0;
1963- if (disable)
1964- playbin.current_text = -1;
1965-
1966- check_text_layer (!disable);
1967- if (!disable) {
1968- playbin.current_text = value;
1969- }
1970- }
1971- }
1972-
1973- private string _subtitle_font;
1974- public string subtitle_font {
1975- get {
1976- return _subtitle_font;
1977- }
1978- set {
1979- _subtitle_font = value;
1980- playbin.set ("subtitle-font-desc", _subtitle_font);
1981- }
1982- }
1983-
1984- public dynamic Gst.Element playbin;
1985- Clutter.Texture video;
1986-
1987- public uint video_width { get; private set; }
1988- public uint video_height { get; private set; }
1989-
1990- public signal void ended ();
1991- public signal void toggle_side_pane (bool show);
1992- public signal void text_tags_changed ();
1993- public signal void audio_tags_changed ();
1994- public signal void error ();
1995- public signal void plugin_install_done ();
1996- public signal void progression_changed (double current_time, double total_time);
1997- public signal void external_subtitle_changed (string? uri);
1998-
1999- public VideoPlayer () {
2000- video = new Clutter.Texture ();
2001- playbin = Gst.ElementFactory.make ("playbin", "playbin");
2002- build ();
2003-
2004- playbin.text_tags_changed.connect ((el) => {
2005- var structure = new Gst.Structure.empty ("tags-changed");
2006- structure.set_value ("type", "text");
2007- el.post_message (new Gst.Message.application (el, (owned) structure));
2008- });
2009-
2010- playbin.audio_tags_changed.connect ((el) => {
2011- var structure = new Gst.Structure.empty ("tags-changed");
2012- structure.set_value ("type", "audio");
2013- el.post_message (new Gst.Message.application (el, (owned) structure));
2014- });
2015-
2016- Timeout.add (100, () => {
2017- int64 length, prog;
2018- playbin.query_position (Gst.Format.TIME, out prog);
2019- playbin.query_duration (Gst.Format.TIME, out length);
2020- if (length == 0)
2021- return true;
2022-
2023- progression_changed ((double)prog, (double)length);
2024- return true;
2025- });
2026-
2027- playbin.get_bus ().add_signal_watch ();
2028- playbin.get_bus ().message.connect (watch);
2029- }
2030-
2031- ~VideoPlayer () {
2032- playbin.set_state (Gst.State.NULL);
2033- playbin.get_bus ().message.disconnect (watch);
2034- message ("video player destroyed");
2035- }
2036-
2037- public void build (){
2038-
2039- if (video.get_parent ()!=null)
2040- remove_child (video);
2041- dynamic Gst.Element video_sink = Gst.ElementFactory.make ("cluttersink", "source");
2042- video_sink.texture = video;
2043- playbin.video_sink = video_sink;
2044- add_child(video);
2045- update_subtitle_font ();
2046- settings.changed.connect (() => {
2047- update_subtitle_font ();
2048- });
2049- }
2050-
2051- void watch (Gst.Message msg) {
2052-
2053- switch (msg.type) {
2054- case Gst.MessageType.APPLICATION:
2055- if (msg.get_structure ().get_name () == "tags-changed") {
2056- if (msg.get_structure ().get_string ("type") == "text")
2057- text_tags_changed ();
2058- else
2059- audio_tags_changed ();
2060- }
2061- break;
2062- case Gst.MessageType.ERROR:
2063- GLib.Error e; string detail;
2064- msg.parse_error (out e, out detail);
2065- playbin.set_state (Gst.State.NULL);
2066-
2067- warning (detail);
2068-
2069- show_error (e.message);
2070- break;
2071- case Gst.MessageType.EOS:
2072- Idle.add (()=>{
2073- ended ();
2074- return false;
2075- });
2076- break;
2077- case Gst.MessageType.ELEMENT:
2078- if (msg.get_structure () == null)
2079- break;
2080-
2081- if (Gst.PbUtils.is_missing_plugin_message (msg)) {
2082- error ();
2083- playbin.set_state (Gst.State.NULL);
2084-
2085- handle_missing_plugin (msg);
2086- /*TODO } else { //may be navigation command
2087- var nav_msg = Gst.Navigation.message_get_type (msg);
2088-
2089- if (nav_msg == Gst.NavigationMessageType.COMMANDS_CHANGED) {
2090- var q = Gst.Navigation.query_new_commands ();
2091- pipeline.query (q);
2092-
2093- uint n;
2094- gst_navigation_query_parse_commands_length (q, out n);
2095- for (var i=0;i<n;i++) {
2096- Gst.NavigationCommand cmd;
2097- gst_navigation_query_parse_commands_nth (q, 0, out cmd);
2098- debug ("Got command: %i", (int)cmd);
2099- }
2100- }*/
2101- }
2102- break;
2103- default:
2104- break;
2105- }
2106- }
2107-
2108- public void set_subtitle_uri (string? uri) {
2109- subtitle_uri = uri;
2110- if (!check_text_layer (subtitle_uri != null)) {
2111- apply_subtitles ();
2112- external_subtitle_changed (uri);
2113- };
2114- }
2115-
2116- // checks whether text layer has to be enabled
2117- // returns if apply_subtitles has been called
2118- bool check_text_layer (bool enable) {
2119- int flags;
2120- playbin.get ("flags", out flags);
2121-
2122- if (!enable && (flags & PlayFlags.TEXT) > 0) {
2123- flags &= ~PlayFlags.TEXT;
2124- playbin.set ("flags", flags);
2125- } else if (enable && (flags & PlayFlags.TEXT) < 1) {
2126- flags |= PlayFlags.TEXT;
2127- playbin.set ("flags", flags);
2128- apply_subtitles ();
2129- return true;
2130- }
2131-
2132- return false;
2133- }
2134-
2135- // ported from totem bvw widget set_subtitle_uri
2136- void apply_subtitles () {
2137- int64 time;
2138- playbin.query_position (Gst.Format.TIME, out time);
2139-
2140- playbin.get_state (null, null, Gst.CLOCK_TIME_NONE);
2141-
2142- Gst.State current;
2143- playbin.get_state (out current, null, Gst.CLOCK_TIME_NONE);
2144- if (current > Gst.State.READY) {
2145- playbin.set_state (Gst.State.READY);
2146- playbin.get_state (null, null, Gst.CLOCK_TIME_NONE);
2147- }
2148-
2149- playbin.suburi = subtitle_uri;
2150- if (current > Gst.State.READY) {
2151- playbin.set_state (current);
2152- playbin.get_state (null, null, Gst.CLOCK_TIME_NONE);
2153- }
2154-
2155- playbin.set_state (Gst.State.PAUSED);
2156- playbin.seek (1.0, Gst.Format.TIME,
2157- Gst.SeekFlags.FLUSH | Gst.SeekFlags.ACCURATE,
2158- Gst.SeekType.SET, time,
2159- Gst.SeekType.NONE, (int64)Gst.CLOCK_TIME_NONE);
2160-
2161- if (current > Gst.State.READY) {
2162- playbin.set_state (current);
2163- playbin.get_state (null, null, Gst.CLOCK_TIME_NONE);
2164- }
2165- }
2166-
2167- public bool relayout () {
2168- if (video_width < 1 || video_height < 1 || uri == null)
2169- return false;
2170-
2171- var stage = get_stage ();
2172- var aspect = stage.width / video_width < stage.height / video_height ?
2173- stage.width / video_width : stage.height / video_height;
2174- video.width = video_width * aspect;
2175- video.height = video_height * aspect;
2176- video.x = (stage.width - video.width) / 2;
2177- video.y = (stage.height - video.height) / 2;
2178-
2179- return true;
2180- }
2181-
2182- void show_error (string? message=null) {
2183- var dlg = new Gtk.Dialog.with_buttons (_("Error"), null, Gtk.DialogFlags.MODAL, _("_OK"), Gtk.ResponseType.OK);
2184- var grid = new Gtk.Grid ();
2185- var err = new Gtk.Image.from_icon_name ("dialog-error", Gtk.IconSize.DIALOG);
2186- err.margin_right = 12;
2187-
2188- var err_label = new Gtk.Label ("");
2189- err_label.set_markup ("<b>%s</b>".printf (_("Oops! Audience can't play this file!")));
2190-
2191- grid.margin = 12;
2192- grid.attach (err, 0, 0, 1, 1);
2193- grid.attach (err_label, 1, 0, 1, 1);
2194- if (message != null)
2195- grid.attach (new Gtk.Label (message), 1, 1, 1, 2);
2196-
2197- error ();
2198- ((Gtk.Box)dlg.get_content_area ()).add (grid);
2199- dlg.show_all ();
2200- dlg.run ();
2201- dlg.destroy ();
2202- }
2203-
2204- void handle_missing_plugin (Gst.Message msg) {
2205- var detail = Gst.PbUtils.missing_plugin_message_get_description (msg);
2206- var dlg = new Gtk.Dialog.with_buttons ("Missing plugin", null, Gtk.DialogFlags.MODAL);
2207- var grid = new Gtk.Grid ();
2208- var err = new Gtk.Image.from_icon_name ("dialog-error", Gtk.IconSize.DIALOG);
2209- var phrase = new Gtk.Label (_("Some media files need extra software to be played. Audience can install this software automatically."));
2210-
2211- err.margin_right = 12;
2212-
2213- var err_label = new Gtk.Label ("");
2214- err_label.set_markup ("<b>%s</b>".printf (_("Audience needs %s to play this file.").printf (detail)));
2215-
2216- grid.margin = 12;
2217- grid.attach (err, 0, 0, 1, 1);
2218- grid.attach (err_label, 1, 0, 1, 1);
2219- grid.attach (phrase, 1, 1, 1, 2);
2220-
2221- dlg.add_button (_("Don't install"), 1);
2222- dlg.add_button (_("Install")+" "+detail, 0);
2223-
2224- (dlg.get_content_area () as Gtk.Container).add (grid);
2225- dlg.show_all ();
2226- if (dlg.run () == 0) {
2227- var installer = Gst.PbUtils.missing_plugin_message_get_installer_detail (msg);
2228- var context = new Gst.PbUtils.InstallPluginsContext ();
2229- Gst.PbUtils.install_plugins_async ({installer}, context, () => { //finished
2230- debug ("Finished plugin install");
2231- Gst.update_registry ();
2232- plugin_install_done ();
2233- playing = true;
2234- });
2235- }
2236-
2237- dlg.destroy ();
2238- }
2239-
2240- public void seek_jump_seconds (int seconds) {
2241- int64 position;
2242- playbin.query_position (Gst.Format.TIME, out position);
2243-
2244- var gst_seconds = 1000000000 * (int64)seconds;
2245- var new_position = position + gst_seconds;
2246-
2247- if (new_position < 0) {
2248- playbin.seek_simple (Gst.Format.TIME, Gst.SeekFlags.FLUSH | Gst.SeekFlags.ACCURATE, int64.max (new_position, 1));
2249- return;
2250- }
2251-
2252- playbin.seek_simple (Gst.Format.TIME, Gst.SeekFlags.FLUSH | Gst.SeekFlags.ACCURATE, new_position);
2253- }
2254-
2255-
2256-
2257- private void get_media_size (Gst.PbUtils.DiscovererVideoInfo video_info, out uint video_width, out uint video_height) {
2258- var video_w = video_info.get_width ();
2259- var video_h = video_info.get_height ();
2260- var video_par_n = video_info.get_par_num ();
2261- var video_par_d = video_info.get_par_denom ();
2262- if (video_par_n == 0 || video_par_d == 0) {
2263- debug ("width and/or height 0, assumming 1/1");
2264- video_par_n = 1;
2265- video_par_d = 1;
2266- }
2267- debug ("video PAR %u/%u", video_par_n, video_par_d);
2268-
2269- uint num;
2270- uint den;
2271- if (!GstVideo.calculate_display_ratio (out num, out den, video_w, video_h, video_par_n, video_par_d, 1, 1)) {
2272- warning ("overflow calculating display ratio");
2273- num = 1;
2274- den = 1;
2275- }
2276- debug ("calculated scale ratio %u / %u for %ux%u", num, den, video_w, video_h);
2277-
2278- if (video_w % num == 0) {
2279- debug ("keeping video width");
2280- video_width = video_w;
2281- video_height = (uint) Gst.Util.uint64_scale (video_w, den, num);
2282- } else {
2283- debug ("keeping video height");
2284- video_width = (uint) Gst.Util.uint64_scale (video_h, num, den);
2285- video_height = video_h;
2286- }
2287- debug ("scaling to %ux%u", video_width, video_height);
2288- }
2289-
2290- void update_subtitle_font () {
2291- debug ("Updating subtitle font");
2292- var font = settings.subtitle_font;
2293-
2294- if (font == "") {
2295- var gnome_settings = new GLib.Settings ("org.gnome.desktop.interface");
2296- font = gnome_settings.get_string ("font-name");
2297- }
2298- subtitle_font = font;
2299- }
2300- }
2301-}
2302
2303=== modified file 'src/Widgets/WelcomePage.vala'
2304--- src/Widgets/WelcomePage.vala 2015-06-15 08:29:35 +0000
2305+++ src/Widgets/WelcomePage.vala 2016-03-20 01:32:19 +0000
2306@@ -1,10 +1,12 @@
2307 namespace Audience {
2308 public class WelcomePage : Granite.Widgets.Welcome {
2309+ private DiskManager disk_manager;
2310 public WelcomePage () {
2311 base (_("No Videos Open"), _("Select a source to begin playing."));
2312- this.append ("document-open", _("Open file"), _("Open a saved file."));
2313+ }
2314
2315- this.set_size_request (350, 300);
2316+ construct {
2317+ append ("document-open", _("Open file"), _("Open a saved file."));
2318
2319 var filename = settings.current_video;
2320 var last_file = File.new_for_uri (filename);
2321@@ -13,58 +15,42 @@
2322 show_last_file = false;
2323 }
2324
2325- if (settings.last_stopped == 0.0 || !settings.resume_videos)
2326- this.append ("media-playlist-repeat", _("Replay last video"), get_title (last_file.get_basename ()));
2327- else
2328- this.append ("media-playback-start", _("Resume last video"), get_title (last_file.get_basename ()));
2329- this.set_item_visible (1, show_last_file);
2330+ if (settings.last_stopped == 0.0 || !settings.resume_videos) {
2331+ append ("media-playlist-repeat", _("Replay last video"), get_title (last_file.get_basename ()));
2332+ } else {
2333+ append ("media-playback-start", _("Resume last video"), get_title (last_file.get_basename ()));
2334+ }
2335+
2336+ set_item_visible (1, show_last_file);
2337
2338 //look for dvd
2339- this.append ("media-cdrom", _("Play from Disc"), _("Watch a DVD or open a file from disc"));
2340- this.set_item_visible (2, App.get_instance ().has_media_volumes ());
2341- App.get_instance ().media_volumes_changed.connect (() => {
2342- this.set_item_visible (2, App.get_instance ().has_media_volumes ());
2343- });
2344-
2345- //handle welcome
2346- this.activated.connect (on_activate);
2347-
2348- App.get_instance ().set_window_title (App.get_instance ().program_name);
2349- // FIXME : dont know why but cant move this to Audience.vala
2350- App.get_instance ().mainwindow.set_default_size (960, 640);
2351-
2352- App.get_instance ().mainwindow.key_press_event.connect (on_key_press_event);
2353-
2354- }
2355- ~WelcomePage () {
2356- this.activated.disconnect (on_activate);
2357- App.get_instance ().mainwindow.key_press_event.disconnect (on_key_press_event);
2358- }
2359- private void on_activate (int index) {
2360- switch (index) {
2361- case 0:
2362- // Open file
2363- App.get_instance ().run_open_file ();
2364- break;
2365- case 1:
2366- App.get_instance ().resume_last_videos ();
2367- break;
2368- case 2:
2369- App.get_instance ().run_open_dvd ();
2370- break;
2371- }
2372- }
2373- private bool on_key_press_event (Gdk.EventKey e) {
2374- switch (e.keyval) {
2375- case Gdk.Key.p:
2376- case Gdk.Key.space:
2377- App.get_instance ().resume_last_videos ();
2378- break;
2379- default:
2380- break;
2381- }
2382-
2383- return false;
2384+ disk_manager = DiskManager.get_default ();
2385+ disk_manager.volume_found.connect ((vol) => {
2386+ set_item_visible (2, disk_manager.has_media_volumes ());
2387+ });
2388+
2389+ disk_manager.volume_removed.connect ((vol) => {
2390+ set_item_visible (2, disk_manager.has_media_volumes ());
2391+ });
2392+
2393+ append ("media-cdrom", _("Play from Disc"), _("Watch a DVD or open a file from disc"));
2394+ set_item_visible (2, disk_manager.has_media_volumes ());
2395+
2396+ activated.connect ((index) => {
2397+ var window = App.get_instance ().mainwindow;
2398+ switch (index) {
2399+ case 0:
2400+ // Open file
2401+ window.run_open_file ();
2402+ break;
2403+ case 1:
2404+ window.resume_last_videos ();
2405+ break;
2406+ case 2:
2407+ window.run_open_dvd ();
2408+ break;
2409+ }
2410+ });
2411 }
2412 }
2413 }
2414
2415=== added file 'src/Window.vala'
2416--- src/Window.vala 1970-01-01 00:00:00 +0000
2417+++ src/Window.vala 2016-03-20 01:32:19 +0000
2418@@ -0,0 +1,318 @@
2419+// -*- Mode: vala; indent-tabs-mode: nil; tab-width: 4 -*-
2420+/*-
2421+ * Copyright (c) 2013-2016 elementary LLC.
2422+ *
2423+ * This program is free software: you can redistribute it and/or modify
2424+ * it under the terms of the GNU General Public License as published by
2425+ * the Free Software Foundation, either version 3 of the License, or
2426+ * (at your option) any later version.
2427+
2428+ * This program is distributed in the hope that it will be useful,
2429+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
2430+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
2431+ * GNU General Public License for more details.
2432+
2433+ * You should have received a copy of the GNU General Public License
2434+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
2435+ *
2436+ * Authored by: Tom Beckmann <tomjonabc@gmail.com>
2437+ * Cody Garver <cody@elementaryos.org>
2438+ * Artem Anufrij <artem.anufrij@live.de>
2439+ * Corentin Noël <corentin@elementary.io>
2440+ */
2441+
2442+public class Audience.Window : Gtk.Window {
2443+ private Gtk.Stack main_stack;
2444+ private Gtk.HeaderBar header;
2445+ private PlayerPage player_page;
2446+ private WelcomePage welcome_page;
2447+ private ZeitgeistManager zeitgeist_manager;
2448+
2449+ public signal void media_volumes_changed ();
2450+
2451+ public Window () {
2452+
2453+ }
2454+
2455+ construct {
2456+ zeitgeist_manager = new ZeitgeistManager ();
2457+ window_position = Gtk.WindowPosition.CENTER;
2458+ gravity = Gdk.Gravity.CENTER;
2459+ set_default_geometry (1000, 680);
2460+
2461+ header = new Gtk.HeaderBar ();
2462+ header.set_show_close_button (true);
2463+ header.get_style_context ().add_class ("compact");
2464+ set_titlebar (header);
2465+
2466+ welcome_page = new WelcomePage ();
2467+
2468+ player_page = new PlayerPage ();
2469+ player_page.ended.connect (on_player_ended);
2470+ player_page.unfullscreen_clicked.connect (() => {
2471+ unfullscreen ();
2472+ });
2473+
2474+ player_page.notify["playing"].connect (() => {
2475+ set_keep_above (player_page.playing && settings.stay_on_top);
2476+ });
2477+
2478+ main_stack = new Gtk.Stack ();
2479+ main_stack.add (welcome_page);
2480+ main_stack.add (player_page);
2481+
2482+ add (main_stack);
2483+ show_all ();
2484+ main_stack.set_visible_child (welcome_page);
2485+
2486+ Gtk.TargetEntry uris = {"text/uri-list", 0, 0};
2487+ Gtk.drag_dest_set (this, Gtk.DestDefaults.ALL, {uris}, Gdk.DragAction.MOVE);
2488+ drag_data_received.connect ((ctx, x, y, sel, info, time) => {
2489+ File[] files = {};
2490+ foreach (var uri in sel.get_uris ()) {
2491+ var file = File.new_for_uri (uri);
2492+ files += file;
2493+ }
2494+
2495+ open_files (files);
2496+ });
2497+
2498+ player_page.button_press_event.connect ((event) => {
2499+ // double left click
2500+ if (event.button == Gdk.BUTTON_PRIMARY && event.type == Gdk.EventType.2BUTTON_PRESS) {
2501+ if (player_page.fullscreened) {
2502+ unfullscreen ();
2503+ } else {
2504+ fullscreen ();
2505+ }
2506+ }
2507+
2508+ // right click
2509+ if (event.button == Gdk.BUTTON_SECONDARY) {
2510+ player_page.playing = !player_page.playing;
2511+ }
2512+ return false;
2513+ });
2514+ }
2515+
2516+ public override bool key_press_event (Gdk.EventKey e) {
2517+ switch (e.keyval) {
2518+ case Gdk.Key.o:
2519+ run_open_file ();
2520+ return true;
2521+ case Gdk.Key.p:
2522+ case Gdk.Key.space:
2523+ resume_last_videos ();
2524+ return true;
2525+ case Gdk.Key.q:
2526+ destroy ();
2527+ return true;
2528+ }
2529+
2530+ if (main_stack.get_visible_child () == player_page) {
2531+ switch (e.keyval) {
2532+ case Gdk.Key.p:
2533+ case Gdk.Key.space:
2534+ player_page.playing = !player_page.playing;
2535+ break;
2536+ case Gdk.Key.Escape:
2537+ if (player_page.fullscreened) {
2538+ unfullscreen ();
2539+ } else {
2540+ destroy ();
2541+ }
2542+
2543+ return true;
2544+ case Gdk.Key.Down:
2545+ if (Gdk.ModifierType.SHIFT_MASK in e.state) {
2546+ player_page.seek_jump_seconds (-5); // 5 secs
2547+ } else {
2548+ player_page.seek_jump_seconds (-60); // 1 min
2549+ }
2550+
2551+ player_page.reveal_control ();
2552+ break;
2553+ case Gdk.Key.Left:
2554+ if (Gdk.ModifierType.SHIFT_MASK in e.state) {
2555+ player_page.seek_jump_seconds (-1); // 1 sec
2556+ } else {
2557+ player_page.seek_jump_seconds (-10); // 10 secs
2558+ }
2559+
2560+ player_page.reveal_control ();
2561+ break;
2562+ case Gdk.Key.Right:
2563+ if (Gdk.ModifierType.SHIFT_MASK in e.state) {
2564+ player_page.seek_jump_seconds (1); // 1 sec
2565+ } else {
2566+ player_page.seek_jump_seconds (10); // 10 secs
2567+ }
2568+
2569+ player_page.reveal_control ();
2570+ break;
2571+ case Gdk.Key.Up:
2572+ if (Gdk.ModifierType.SHIFT_MASK in e.state) {
2573+ player_page.seek_jump_seconds (5); // 5 secs
2574+ } else {
2575+ player_page.seek_jump_seconds (60); // 1 min
2576+ }
2577+
2578+ player_page.reveal_control ();
2579+ break;
2580+ case Gdk.Key.Page_Down:
2581+ player_page.seek_jump_seconds (-600); // 10 mins
2582+ player_page.reveal_control ();
2583+ break;
2584+ case Gdk.Key.Page_Up:
2585+ player_page.seek_jump_seconds (600); // 10 mins
2586+ player_page.reveal_control ();
2587+ break;
2588+ case Gdk.Key.a:
2589+ player_page.next_audio ();
2590+ break;
2591+ case Gdk.Key.s:
2592+ player_page.next_text ();
2593+ break;
2594+ case Gdk.Key.f:
2595+ if (player_page.fullscreened) {
2596+ unfullscreen ();
2597+ } else {
2598+ fullscreen ();
2599+ }
2600+
2601+ break;
2602+ default:
2603+ break;
2604+ }
2605+ }
2606+
2607+ return false;
2608+ }
2609+
2610+ public override bool window_state_event (Gdk.EventWindowState e) {
2611+ if (Gdk.WindowState.FULLSCREEN in e.changed_mask) {
2612+ player_page.fullscreened = Gdk.WindowState.FULLSCREEN in e.new_window_state;
2613+ header.visible = !player_page.fullscreened;
2614+ }
2615+
2616+ if (Gdk.WindowState.MAXIMIZED in e.changed_mask) {
2617+ bool currently_maximixed = Gdk.WindowState.MAXIMIZED in e.new_window_state;
2618+ if (main_stack.get_visible_child () == player_page && currently_maximixed) {
2619+ fullscreen ();
2620+ }
2621+ }
2622+
2623+ return false;
2624+ }
2625+
2626+ public void open_files (File[] files) {
2627+ string[] videos = {};
2628+ foreach (var file in files) {
2629+ if (file.query_file_type (0) == FileType.DIRECTORY) {
2630+ Audience.recurse_over_dir (file, (file_ret) => {
2631+ player_page.append_to_playlist (file);
2632+ videos += file_ret.get_uri ();
2633+ });
2634+ } else {
2635+ player_page.append_to_playlist (file);
2636+ videos += file.get_uri ();
2637+ }
2638+ }
2639+
2640+
2641+ if (videos.length == 0) {
2642+ return;
2643+ }
2644+
2645+ // notification when adding video to playlist
2646+ if (!player_page.playing && (Gdk.WindowState.FOCUSED in get_window ().get_state ())) {
2647+ var text = ngettext (_("%u Video added to Playlist"), _("%u Videos added to Playlist"), videos.length).printf (videos.length);
2648+ show_notification (text, (videos.length == 1) ? Audience.get_title (videos[0]) : "");
2649+ }
2650+
2651+ play_file (videos [0]);
2652+ }
2653+
2654+ public void resume_last_videos () {
2655+ play_file (settings.current_video, false);
2656+ }
2657+
2658+ public void run_open_dvd () {
2659+ read_first_disk.begin ();
2660+ }
2661+
2662+ public void run_open_file () {
2663+ var file = new Gtk.FileChooserDialog (_("Open"), this, Gtk.FileChooserAction.OPEN,
2664+ _("_Cancel"), Gtk.ResponseType.CANCEL, _("_Open"), Gtk.ResponseType.ACCEPT);
2665+ file.set_transient_for (this);
2666+ file.select_multiple = true;
2667+
2668+ var all_files_filter = new Gtk.FileFilter ();
2669+ all_files_filter.set_filter_name (_("All files"));
2670+ all_files_filter.add_pattern ("*");
2671+
2672+ var video_filter = new Gtk.FileFilter ();
2673+ video_filter.set_filter_name (_("Video files"));
2674+ video_filter.add_mime_type ("video/*");
2675+
2676+ file.add_filter (video_filter);
2677+ file.add_filter (all_files_filter);
2678+
2679+ file.set_current_folder (settings.last_folder);
2680+ if (file.run () == Gtk.ResponseType.ACCEPT) {
2681+ File[] files = {};
2682+ foreach (File item in file.get_files ()) {
2683+ files += item;
2684+ }
2685+
2686+ open_files (files);
2687+ settings.last_folder = file.get_current_folder ();
2688+ }
2689+
2690+ file.destroy ();
2691+ }
2692+
2693+ public bool is_privacy_mode_enabled () {
2694+ var privacy_settings = new GLib.Settings ("org.gnome.desktop.privacy");
2695+ bool privacy_mode = !privacy_settings.get_boolean ("remember-recent-files") || !privacy_settings.get_boolean ("remember-app-usage");
2696+
2697+ if (privacy_mode) {
2698+ return true;
2699+ }
2700+
2701+ return zeitgeist_manager.app_into_blacklist (Audience.App.get_instance ().exec_name);
2702+ }
2703+
2704+ private async void read_first_disk () {
2705+ var disk_manager = DiskManager.get_default ();
2706+ if (disk_manager.get_volumes ().is_empty)
2707+ return;
2708+
2709+ var volume = disk_manager.get_volumes ().first ();
2710+ if (volume.can_mount () == true && volume.get_mount ().can_unmount () == false) {
2711+ try {
2712+ yield volume.mount (MountMountFlags.NONE, null);
2713+ } catch (Error e) {
2714+ critical (e.message);
2715+ }
2716+ }
2717+
2718+ var root = volume.get_mount ().get_default_location ();
2719+ play_file (root.get_uri ().replace ("file:///", "dvd:///"));
2720+ }
2721+
2722+ private void on_player_ended () {
2723+ main_stack.set_visible_child (welcome_page);
2724+ title = App.get_instance ().program_name;
2725+ get_window ().set_cursor (null);
2726+ unfullscreen ();
2727+ }
2728+
2729+ private void play_file (string uri, bool from_beginning = true) {
2730+ main_stack.set_visible_child (player_page);
2731+ player_page.play_file (uri, from_beginning);
2732+ if (is_maximized) {
2733+ fullscreen ();
2734+ }
2735+ }
2736+}

Subscribers

People subscribed via source and target branches