From bae0b805eac1bd058dba3607ac57dce405231a1a Mon Sep 17 00:00:00 2001 From: Rafostar <40623528+Rafostar@users.noreply.github.com> Date: Mon, 5 Oct 2020 21:19:29 +0200 Subject: [PATCH 01/21] Initial GTK4 port Port most of the player to GTK4. Some things are still broken or disabled due to GTK change, but will be gradually fixed. --- clapper_src/app.js | 65 +++++++++++++++++++++++------------ clapper_src/buttons.js | 30 ++++++++--------- clapper_src/controls.js | 52 ++++++++++++++++------------ clapper_src/headerbar.js | 73 ++++++++++++++++++++++++++++++++++++++++ clapper_src/interface.js | 68 ++++++++++++++++--------------------- clapper_src/player.js | 18 ++++++++-- clapper_src/revealers.js | 26 +++++++------- clapper_src/window.js | 10 +++--- gjs-1.0/clapper.js.in | 4 +-- main.js | 4 +-- 10 files changed, 229 insertions(+), 121 deletions(-) create mode 100644 clapper_src/headerbar.js diff --git a/clapper_src/app.js b/clapper_src/app.js index 98b1397e..dc4644f5 100644 --- a/clapper_src/app.js +++ b/clapper_src/app.js @@ -1,5 +1,6 @@ const { Gdk, GLib, GObject, Gtk, GstPlayer } = imports.gi; const Debug = imports.clapper_src.debug; +const { HeaderBar } = imports.clapper_src.headerbar; const { Interface } = imports.clapper_src.interface; const { Player } = imports.clapper_src.player; const { Window } = imports.clapper_src.window; @@ -47,24 +48,31 @@ var App = GObject.registerClass({ super.vfunc_startup(); this.window = new Window(this, APP_NAME); + this.window.connect('close-request', this._onWindowCloseRequest.bind(this)); + this.window.connect('unmap', () => this.quit()); + this.windowRealizeSignal = this.window.connect( 'realize', this._onWindowRealize.bind(this) ); +/* this.window.connect( 'key-press-event', this._onWindowKeyPressEvent.bind(this) ); +*/ this.window.connect( 'fullscreen-changed', this._onWindowFullscreenChanged.bind(this) ); this.interface = new Interface(); - let headerBar = new Gtk.HeaderBar({ - title: APP_NAME, - show_close_button: true, - }); - headerBar.pack_end(this.interface.controls.openMenuButton); - headerBar.pack_end(this.interface.controls.fullscreenButton); + + let headerStart = []; + let headerEnd = [ + this.interface.controls.openMenuButton, + this.interface.controls.fullscreenButton + ]; + let headerBar = new HeaderBar(this.window, headerStart, headerEnd); this.interface.addHeaderBar(headerBar, APP_NAME); + this.interface.controls.fullscreenButton.connect( 'clicked', () => this._onInterfaceToggleFullscreenClicked(true) ); @@ -73,13 +81,19 @@ var App = GObject.registerClass({ ); this.window.set_titlebar(this.interface.headerBar); - this.window.add(this.interface); + this.window.set_child(this.interface); } vfunc_activate() { super.vfunc_activate(); - this.window.show_all(); + + this.window.show(); + Gtk.StyleContext.add_provider_for_display( + Gdk.Display.get_default(), + this.cssProvider, + Gtk.STYLE_PROVIDER_PRIORITY_APPLICATION + ); } run(arr) @@ -146,24 +160,23 @@ var App = GObject.registerClass({ { this.window.disconnect(this.windowRealizeSignal); - Gtk.StyleContext.add_provider_for_screen( - Gdk.Screen.get_default(), - this.cssProvider, - Gtk.STYLE_PROVIDER_PRIORITY_APPLICATION - ); - this.player = new Player(); + + if(!this.player.widget) + return this.quit(); +/* this.player.widget.add_events( Gdk.EventMask.SCROLL_MASK | Gdk.EventMask.ENTER_NOTIFY_MASK | Gdk.EventMask.LEAVE_NOTIFY_MASK ); +*/ this.interface.addPlayer(this.player); this.player.connect('warning', this._onPlayerWarning.bind(this)); this.player.connect('error', this._onPlayerError.bind(this)); this.player.connect('state-changed', this._onPlayerStateChanged.bind(this)); - +/* this.player.connectWidget( 'button-press-event', this._onPlayerButtonPressEvent.bind(this) ); @@ -176,13 +189,13 @@ var App = GObject.registerClass({ this.player.connectWidget( 'motion-notify-event', this._onPlayerMotionNotifyEvent.bind(this) ); - +*/ /* Widget signals that are disconnected after first run */ this._playerRealizeSignal = this.player.widget.connect( 'realize', this._onPlayerRealize.bind(this) ); - this._playerDrawSignal = this.player.widget.connect( - 'draw', this._onPlayerDraw.bind(this) + this._playerMapSignal = this.player.widget.connect( + 'map', this._onPlayerMap.bind(this) ); } @@ -265,7 +278,7 @@ var App = GObject.registerClass({ this.player.renderer.expose(); let display = this.player.widget.get_display(); - +/* this.defaultCursor = Gdk.Cursor.new_from_name( display, 'default' ); @@ -274,12 +287,13 @@ var App = GObject.registerClass({ ); this.playerWindow = this.player.widget.get_window(); +*/ this.setHideCursorTimeout(); } - _onPlayerDraw(self, data) + _onPlayerMap(self, data) { - this.player.widget.disconnect(this._playerDrawSignal); + this.player.widget.disconnect(this._playerMapSignal); this.emit('ready', true); if(this.playlist.length) @@ -312,7 +326,7 @@ var App = GObject.registerClass({ this.inhibitCookie = null; } - debug('set prevent suspend to: ' + this.is_inhibited(flags)); + //debug('set prevent suspend to: ' + this.is_inhibited(flags)); } _onPlayerButtonPressEvent(self, event) @@ -420,4 +434,11 @@ var App = GObject.registerClass({ { debug(error); } + + _onWindowCloseRequest() + { + this.window.destroy(); + this.player.widget.emit('destroy'); + this.interface.emit('destroy'); + } }); diff --git a/clapper_src/buttons.js b/clapper_src/buttons.js index a4597396..2efce995 100644 --- a/clapper_src/buttons.js +++ b/clapper_src/buttons.js @@ -9,26 +9,26 @@ class BoxedIconButton extends Gtk.Button margin_top: 4, margin_bottom: 4, can_focus: false, - can_default: false, + //can_default: false, }); this.isFullscreen = isFullscreen || false; size = size || Gtk.IconSize.SMALL_TOOLBAR; - let image = Gtk.Image.new_from_icon_name(icon, size); - - if(image) - this.set_image(image); + let image = Gtk.Image.new_from_icon_name(icon); + //if(image) + //this.set_image(image); +/* this.image.defaultSize = size; this.image.fullscreenSize = (size === Gtk.IconSize.SMALL_TOOLBAR) ? Gtk.IconSize.LARGE_TOOLBAR : Gtk.IconSize.DND; - - this.get_style_context().add_class('flat'); +*/ + this.add_css_class('flat'); this.box = new Gtk.Box(); - this.box.pack_start(this, false, false, 0); + this.box.append(this); super.show(); } @@ -49,12 +49,12 @@ class BoxedIconButton extends Gtk.Button this.isFullscreen = isFullscreen; } - +/* show_all() { this.box.show_all(); } - +*/ show() { this.box.show(); @@ -74,16 +74,16 @@ class BoxedPopoverButton extends BoxedIconButton super._init(icon, size, isFullscreen); this.popover = new Gtk.Popover({ - relative_to: this.box + default_widget: this.box }); this.popoverBox = new Gtk.Box({ orientation: Gtk.Orientation.VERTICAL }); - this.popover.add(this.popoverBox); + this.popover.set_child(this.popoverBox); this.popoverBox.show(); if(this.isFullscreen) - this.popover.get_style_context().add_class('osd'); + this.popover.add_css_class('osd'); } setFullscreenMode(isEnabled) @@ -91,8 +91,8 @@ class BoxedPopoverButton extends BoxedIconButton if(this.isFullscreen === isEnabled) return; - let action = (isEnabled) ? 'add_class' : 'remove_class'; - this.popover.get_style_context()[action]('osd'); + let action = (isEnabled) ? 'add' : 'remove'; + this.popover[action + '_css_class']('osd'); super.setFullscreenMode(isEnabled); } diff --git a/clapper_src/controls.js b/clapper_src/controls.js index 2c60e6e0..841b1870 100644 --- a/clapper_src/controls.js +++ b/clapper_src/controls.js @@ -57,19 +57,18 @@ var Controls = GObject.registerClass({ ); this.fullscreenButton = Gtk.Button.new_from_icon_name( 'view-fullscreen-symbolic', - Gtk.IconSize.SMALL_TOOLBAR + //Gtk.IconSize.SMALL_TOOLBAR ); this.setDefaultWidgetBehaviour(this.fullscreenButton); this.openMenuButton = Gtk.Button.new_from_icon_name( 'open-menu-symbolic', - Gtk.IconSize.SMALL_TOOLBAR + //Gtk.IconSize.SMALL_TOOLBAR ); this.setDefaultWidgetBehaviour(this.openMenuButton); - this.forall(this.setDefaultWidgetBehaviour); + //this.forall(this.setDefaultWidgetBehaviour); - this.realizeSignal = this.connect( - 'realize', this._onControlsRealize.bind(this) - ); + this.realizeSignal = this.connect('realize', this._onControlsRealize.bind(this)); + this.destroySignal = this.connect('destroy', this._onControlsDestroy.bind(this)); } pack_start(widget, expand, fill, padding) @@ -81,7 +80,7 @@ var Controls = GObject.registerClass({ ) widget = widget.box; - super.pack_start(widget, expand, fill, padding); + super.append(widget); } setFullscreenMode(isFullscreen) @@ -121,6 +120,8 @@ var Controls = GObject.registerClass({ addRadioButtons(box, array, activeId) { + return; + let group = null; let children = box.get_children(); let lastEl = (children.length > array.length) @@ -175,7 +176,7 @@ var Controls = GObject.registerClass({ setDefaultWidgetBehaviour(widget) { widget.can_focus = false; - widget.can_default = false; + //widget.can_default = false; } setVolumeMarks(isAdded) @@ -212,17 +213,21 @@ var Controls = GObject.registerClass({ ); this.togglePlayButton.setPlayImage = () => { +/* this.togglePlayButton.image.set_from_icon_name( 'media-playback-start-symbolic', this.togglePlayButton.image.icon_size ); +*/ } this.togglePlayButton.setPauseImage = () => { +/* this.togglePlayButton.image.set_from_icon_name( 'media-playback-pause-symbolic', this.togglePlayButton.image.icon_size ); +*/ } } @@ -234,19 +239,18 @@ var Controls = GObject.registerClass({ draw_value: true, hexpand: true, }); - let style = this.positionScale.get_style_context(); - style.add_class('positionscale'); - - this.positionScale.connect( - 'format-value', this._onPositionScaleFormatValue.bind(this) + this.positionScale.add_css_class('positionscale'); + this.positionScale.set_format_value_func( + this._onPositionScaleFormatValue.bind(this) ); +/* this.positionScale.connect( 'button-press-event', this._onPositionScaleButtonPressEvent.bind(this) ); this.positionScale.connect( 'button-release-event', this._onPositionScaleButtonReleaseEvent.bind(this) ); - +*/ this.positionAdjustment = this.positionScale.get_adjustment(); this.pack_start(this.positionScale, true, true, 0); } @@ -256,10 +260,10 @@ var Controls = GObject.registerClass({ this.volumeButton = this.addPopoverButton( 'audio-volume-muted-symbolic' ); - this.volumeButton.add_events(Gdk.EventMask.SCROLL_MASK); - this.volumeButton.connect( - 'scroll-event', (self, event) => this._onScrollEvent(event) - ); + //this.volumeButton.add_events(Gdk.EventMask.SCROLL_MASK); + //this.volumeButton.connect( + // 'scroll-event', (self, event) => this._onScrollEvent(event) + //); this.volumeScale = new Gtk.Scale({ orientation: Gtk.Orientation.VERTICAL, inverted: true, @@ -268,7 +272,7 @@ var Controls = GObject.registerClass({ round_digits: 2, vexpand: true, }); - this.volumeScale.get_style_context().add_class('volumescale'); + this.volumeScale.add_css_class('volumescale'); this.volumeAdjustment = this.volumeScale.get_adjustment(); this.volumeAdjustment.set_upper(2); @@ -276,8 +280,8 @@ var Controls = GObject.registerClass({ this.volumeAdjustment.set_page_increment(0.05); this.setDefaultWidgetBehaviour(this.volumeScale); - this.volumeButton.popoverBox.add(this.volumeScale); - this.volumeButton.popoverBox.show_all(); + this.volumeButton.popoverBox.append(this.volumeScale); + //this.volumeButton.popoverBox.show_all(); this.setVolumeMarks(true); } @@ -375,4 +379,10 @@ var Controls = GObject.registerClass({ break; } } + + _onControlsDestroy() + { + this.disconnect(this.destroySignal); + this.positionScale.set_format_value_func(null); + } }); diff --git a/clapper_src/headerbar.js b/clapper_src/headerbar.js new file mode 100644 index 00000000..3a44d25c --- /dev/null +++ b/clapper_src/headerbar.js @@ -0,0 +1,73 @@ +const { GLib, GObject, Gtk, Pango } = imports.gi; + +var HeaderBar = GObject.registerClass( +class ClapperHeaderBar extends Gtk.HeaderBar +{ + _init(window, startButtons, endButtons) + { + super._init(); + + this.set_title_widget(this._createWidgetForWindow(window)); + startButtons.forEach(btn => this.pack_start(btn)); + endButtons.forEach(btn => this.pack_end(btn)); + } + + updateHeaderBar(mediaInfo) + { + let title = mediaInfo.get_title(); + let subtitle = mediaInfo.get_uri() || null; + + if(subtitle && subtitle.startsWith('file://')) { + subtitle = GLib.filename_from_uri(subtitle)[0]; + subtitle = GLib.path_get_basename(subtitle); + } + + if(!title) { + title = (!subtitle) + ? this.defaultTitle + : (subtitle.includes('.')) + ? subtitle.split('.').slice(0, -1).join('.') + : subtitle; + + subtitle = null; + } + + this.titleLabel.label = title; + this.subtitleLabel.visible = (subtitle !== null); + + if(subtitle) + this.subtitleLabel.label = subtitle; + } + + _createWidgetForWindow(window) + { + let box = new Gtk.Box ({ + orientation: Gtk.Orientation.VERTICAL, + valign: Gtk.Align.CENTER + }); + + this.titleLabel = new Gtk.Label({ + halign: Gtk.Align.CENTER, + single_line_mode: true, + ellipsize: Pango.EllipsizeMode.END, + width_chars: 5, + }); + this.titleLabel.add_css_class('title'); + this.titleLabel.set_parent(box); + + window.bind_property('title', this.titleLabel, 'label', + GObject.BindingFlags.SYNC_CREATE + ); + + this.subtitleLabel = new Gtk.Label({ + halign: Gtk.Align.CENTER, + single_line_mode: true, + ellipsize: Pango.EllipsizeMode.END, + }); + this.subtitleLabel.add_css_class('subtitle'); + this.subtitleLabel.set_parent(box); + this.subtitleLabel.visible = false; + + return box; + } +}); diff --git a/clapper_src/interface.js b/clapper_src/interface.js index d53e593e..fc12fb7f 100644 --- a/clapper_src/interface.js +++ b/clapper_src/interface.js @@ -33,29 +33,33 @@ class ClapperInterface extends Gtk.Grid this.revealerBottom = new Revealers.RevealerBottom(); this.controls = new Controls(); - this.videoBox.get_style_context().add_class('videobox'); - this.videoBox.pack_start(this.overlay, true, true, 0); + this.videoBox.add_css_class('videobox'); + this.videoBox.append(this.overlay); this.attach(this.videoBox, 0, 0, 1, 1); this.attach(this.controls, 0, 1, 1, 1); + + this.destroySignal = this.connect('destroy', this._onInterfaceDestroy.bind(this)); } addPlayer(player) { this._player = player; - this._player.widget.expand = true; + this._player.widget.vexpand = true; + this._player.widget.hexpand = true; this._player.connect('state-changed', this._onPlayerStateChanged.bind(this)); this._player.connect('volume-changed', this._onPlayerVolumeChanged.bind(this)); this._player.connect('duration-changed', this._onPlayerDurationChanged.bind(this)); this._player.connect('position-updated', this._onPlayerPositionUpdated.bind(this)); - +/* this._player.connectWidget( 'scroll-event', (self, event) => this.controls._onScrollEvent(event) ); +*/ this.controls.togglePlayButton.connect( 'clicked', this._onControlsTogglePlayClicked.bind(this) ); - this.controls.positionScale.connect( + this.scaleSig = this.controls.positionScale.connect( 'value-changed', this._onControlsPositionChanged.bind(this) ); this.controls.volumeScale.connect( @@ -70,9 +74,9 @@ class ClapperInterface extends Gtk.Grid this.controls.connect( 'visualization-change-requested', this._onVisualizationChangeRequested.bind(this) ); - this.revealerTop.connect('event-after', (self, event) => this._player.widget.event(event)); + //this.revealerTop.connect('event-after', (self, event) => this._player.widget.event(event)); - this.overlay.add(this._player.widget); + this.overlay.set_child(this._player.widget); this.overlay.add_overlay(this.revealerTop); this.overlay.add_overlay(this.revealerBottom); @@ -122,8 +126,8 @@ class ClapperInterface extends Gtk.Grid { let mediaInfo = this._player.get_media_info(); - // set titlebar media title and path - this.updateHeaderBar(mediaInfo); + /* Set titlebar media title and path */ + this.updateTitles(mediaInfo); // we can also check if video is "live" or "seekable" (right now unused) // it might be a good idea to hide position seek bar and disable seeking @@ -220,32 +224,12 @@ class ClapperInterface extends Gtk.Grid } } - updateHeaderBar(mediaInfo) + updateTitles(mediaInfo) { - if(!this.headerBar) - return; + if(this.headerBar) + this.headerBar.updateHeaderBar(mediaInfo); - let title = mediaInfo.get_title(); - let subtitle = mediaInfo.get_uri() || null; - - if(subtitle.startsWith('file://')) { - subtitle = GLib.filename_from_uri(subtitle)[0]; - subtitle = GLib.path_get_basename(subtitle); - } - - if(!title) { - title = (!subtitle) - ? this.defaultTitle - : (subtitle.includes('.')) - ? subtitle.split('.').slice(0, -1).join('.') - : subtitle; - - subtitle = null; - } - - this.headerBar.set_title(title); - this.headerBar.set_subtitle(subtitle); - this.revealerTop.setMediaTitle(title); + this.revealerTop.setMediaTitle(this.headerBar.titleLabel.label); } updateTime() @@ -300,8 +284,8 @@ class ClapperInterface extends Gtk.Grid _onTrackChangeRequested(self, type, activeId) { - // reenabling audio is slow (as expected), - // so it is better to toggle mute instead + /* Reenabling audio is slow (as expected), + * so it is better to toggle mute instead */ if(type === 'audio') { if(activeId < 0) return this._player.set_mute(true); @@ -313,8 +297,8 @@ class ClapperInterface extends Gtk.Grid } if(activeId < 0) { - // disabling video leaves last frame frozen, - // so we hide it by making it transparent + /* Disabling video leaves last frame frozen, + * so we hide it by making it transparent */ if(type === 'video') this._player.widget.set_opacity(0); @@ -468,7 +452,7 @@ class ClapperInterface extends Gtk.Grid : 'overamplified'; let iconName = `audio-volume-${icon}-symbolic`; - +/* if(this.controls.volumeButton.image.icon_name !== iconName) { debug(`set volume icon: ${icon}`); @@ -477,11 +461,17 @@ class ClapperInterface extends Gtk.Grid this.controls.volumeButton.image.icon_size ); } - +*/ if(volume === this.lastVolumeValue) return; this.lastVolumeValue = volume; this._player.set_volume(volume); } + + _onInterfaceDestroy() + { + this.disconnect(this.destroySignal); + this.controls.emit('destroy'); + } }); diff --git a/clapper_src/player.js b/clapper_src/player.js index 6592b052..bfe8510f 100644 --- a/clapper_src/player.js +++ b/clapper_src/player.js @@ -21,7 +21,16 @@ class ClapperPlayer extends GstPlayer.Player if(!Gst.is_initialized()) Gst.init(null); - let gtkglsink = Gst.ElementFactory.make('gtkglsink', null); + let plugin = 'gtk4glsink'; + let gtkglsink = Gst.ElementFactory.make(plugin, null); + + if(!gtkglsink) { + return debug(new Error( + `Could not load "${plugin}".` + + ' Do you have gstreamer-plugins-good-gtk4 installed?' + )); + } + let glsinkbin = Gst.ElementFactory.make('glsinkbin', null); glsinkbin.sink = gtkglsink; @@ -35,8 +44,7 @@ class ClapperPlayer extends GstPlayer.Player video_renderer: renderer }); - // assign elements to player for later access - // and make sure that GJS will not free them early + /* Assign elements to player for later access */ this.gtkglsink = gtkglsink; this.glsinkbin = glsinkbin; this.dispatcher = dispatcher; @@ -61,6 +69,10 @@ class ClapperPlayer extends GstPlayer.Player this.set_config(config); this.set_mute(false); + /* FIXME: remove once GUI buttons are back */ + this.set_volume(0.5); + this.set_plugin_rank('vah264dec', 300); + this.loop = GLib.MainLoop.new(null, false); this.run_loop = opts.run_loop || false; this.widget = gtkglsink.widget; diff --git a/clapper_src/revealers.js b/clapper_src/revealers.js index 020e2d57..4d65d573 100644 --- a/clapper_src/revealers.js +++ b/clapper_src/revealers.js @@ -130,7 +130,7 @@ class ClapperRevealerTop extends CustomRevealer }); this.revealerName = 'top'; - +/* this.set_events( Gdk.EventMask.BUTTON_PRESS_MASK | Gdk.EventMask.BUTTON_RELEASE_MASK @@ -141,7 +141,7 @@ class ClapperRevealerTop extends CustomRevealer | Gdk.EventMask.ENTER_NOTIFY_MASK | Gdk.EventMask.LEAVE_NOTIFY_MASK ); - +*/ let initTime = GLib.DateTime.new_now_local().format('%X'); this.timeFormat = (initTime.length > 8) ? '%I:%M %p' @@ -150,13 +150,13 @@ class ClapperRevealerTop extends CustomRevealer this.revealerGrid = new Gtk.Grid({ column_spacing: 8 }); - let gridContext = this.revealerGrid.get_style_context(); - gridContext.add_class('osd'); - gridContext.add_class('reavealertop'); + this.revealerGrid.add_css_class('osd'); + this.revealerGrid.add_css_class('reavealertop'); this.mediaTitle = new Gtk.Label({ ellipsize: Pango.EllipsizeMode.END, - expand: true, + vexpand: true, + hexpand: true, margin_top: 14, margin_start: 12, xalign: 0, @@ -169,17 +169,17 @@ class ClapperRevealerTop extends CustomRevealer yalign: 0, }; this.currentTime = new Gtk.Label(timeLabelOpts); - this.currentTime.get_style_context().add_class('osdtime'); + this.currentTime.add_css_class('osdtime'); this.endTime = new Gtk.Label(timeLabelOpts); - this.endTime.get_style_context().add_class('osdendtime'); + this.endTime.add_css_class('osdendtime'); this.revealerGrid.attach(this.mediaTitle, 0, 0, 1, 1); this.revealerGrid.attach(this.currentTime, 1, 0, 1, 1); this.revealerGrid.attach(this.endTime, 1, 0, 1, 1); - this.add(this.revealerGrid); - this.revealerGrid.show_all(); + this.set_child(this.revealerGrid); + //this.revealerGrid.show_all(); } setMediaTitle(title) @@ -217,10 +217,10 @@ class ClapperRevealerBottom extends CustomRevealer this.revealerName = 'bottom'; this.revealerBox = new Gtk.Box(); - this.revealerBox.get_style_context().add_class('osd'); + this.revealerBox.add_css_class('osd'); - this.add(this.revealerBox); - this.revealerBox.show_all(); + this.set_child(this.revealerBox); + //this.revealerBox.show_all(); } addWidget(widget) diff --git a/clapper_src/window.js b/clapper_src/window.js index 1625f48d..51ae3343 100644 --- a/clapper_src/window.js +++ b/clapper_src/window.js @@ -13,11 +13,12 @@ var Window = GObject.registerClass({ super._init({ application: application, title: title || 'Clapper', - border_width: 0, + //border_width: 0, resizable: true, - window_position: Gtk.WindowPosition.CENTER, + //window_position: Gtk.WindowPosition.CENTER, width_request: 960, - height_request: 642 + height_request: 642, + destroy_with_parent: true, }); this.isFullscreen = false; } @@ -27,7 +28,7 @@ var Window = GObject.registerClass({ let un = (this.isFullscreen) ? 'un' : ''; this[`${un}fullscreen`](); } - +/* vfunc_window_state_event(event) { super.vfunc_window_state_event(event); @@ -43,4 +44,5 @@ var Window = GObject.registerClass({ this.isFullscreen = isFullscreen; this.emit('fullscreen-changed', this.isFullscreen); } +*/ }); diff --git a/gjs-1.0/clapper.js.in b/gjs-1.0/clapper.js.in index 91dabb16..e5ba93ca 100644 --- a/gjs-1.0/clapper.js.in +++ b/gjs-1.0/clapper.js.in @@ -1,5 +1,5 @@ -imports.gi.versions.Gdk = '3.0'; -imports.gi.versions.Gtk = '3.0'; +imports.gi.versions.Gdk = '4.0'; +imports.gi.versions.Gtk = '4.0'; imports.searchPath.unshift('@importspath@'); const ClapperSrc = imports.clapper_src; diff --git a/main.js b/main.js index ce9ffdc1..efa88d3b 100644 --- a/main.js +++ b/main.js @@ -1,5 +1,5 @@ -imports.gi.versions.Gdk = '3.0'; -imports.gi.versions.Gtk = '3.0'; +imports.gi.versions.Gdk = '4.0'; +imports.gi.versions.Gtk = '4.0'; const { Gst } = imports.gi; const { App } = imports.clapper_src.app; From dbdb6988a234f73373a0ce20a697323b49e48e08 Mon Sep 17 00:00:00 2001 From: Rafostar <40623528+Rafostar@users.noreply.github.com> Date: Tue, 6 Oct 2020 12:04:28 +0200 Subject: [PATCH 02/21] Fix window "fullscreen-changed" signal --- clapper_src/app.js | 3 +++ clapper_src/window.js | 26 +++++++++++++------------- 2 files changed, 16 insertions(+), 13 deletions(-) diff --git a/clapper_src/app.js b/clapper_src/app.js index dc4644f5..b609e066 100644 --- a/clapper_src/app.js +++ b/clapper_src/app.js @@ -164,6 +164,9 @@ var App = GObject.registerClass({ if(!this.player.widget) return this.quit(); + + this.player.widget.width_request = 960; + this.player.widget.height_request = 540; /* this.player.widget.add_events( Gdk.EventMask.SCROLL_MASK diff --git a/clapper_src/window.js b/clapper_src/window.js index 51ae3343..5ca1d546 100644 --- a/clapper_src/window.js +++ b/clapper_src/window.js @@ -13,14 +13,11 @@ var Window = GObject.registerClass({ super._init({ application: application, title: title || 'Clapper', - //border_width: 0, resizable: true, - //window_position: Gtk.WindowPosition.CENTER, - width_request: 960, - height_request: 642, destroy_with_parent: true, }); this.isFullscreen = false; + this.mapSignal = this.connect('map', this._onMap.bind(this)); } toggleFullscreen() @@ -28,15 +25,11 @@ var Window = GObject.registerClass({ let un = (this.isFullscreen) ? 'un' : ''; this[`${un}fullscreen`](); } -/* - vfunc_window_state_event(event) - { - super.vfunc_window_state_event(event); - let isFullscreen = Boolean( - event.new_window_state - & Gdk.WindowState.FULLSCREEN - ); + _onStateNotify(toplevel) + { + let { state } = toplevel; + let isFullscreen = Boolean(state & Gdk.ToplevelState.FULLSCREEN); if(this.isFullscreen === isFullscreen) return; @@ -44,5 +37,12 @@ var Window = GObject.registerClass({ this.isFullscreen = isFullscreen; this.emit('fullscreen-changed', this.isFullscreen); } -*/ + + _onMap() + { + this.disconnect(this.mapSignal); + + let surface = this.get_surface(); + surface.connect('notify::state', this._onStateNotify.bind(this)); + } }); From 041b31c16134d1a8ef5d8ffbe78846f9c088368d Mon Sep 17 00:00:00 2001 From: Rafostar <40623528+Rafostar@users.noreply.github.com> Date: Wed, 7 Oct 2020 16:40:42 +0200 Subject: [PATCH 03/21] Fix enter fullscreen and popover buttons --- clapper_src/app.js | 16 +--- clapper_src/buttons.js | 122 ++++++++++++----------------- clapper_src/controls.js | 160 ++++++++++++++++----------------------- clapper_src/interface.js | 31 ++++---- clapper_src/revealers.js | 7 +- css/styles.css | 3 +- 6 files changed, 138 insertions(+), 201 deletions(-) diff --git a/clapper_src/app.js b/clapper_src/app.js index b609e066..fb6cd21b 100644 --- a/clapper_src/app.js +++ b/clapper_src/app.js @@ -21,8 +21,6 @@ var App = GObject.registerClass({ { _init(opts) { - GLib.set_prgname(APP_NAME); - super._init({ application_id: pkg.name }); @@ -204,27 +202,15 @@ var App = GObject.registerClass({ _onWindowFullscreenChanged(window, isFullscreen) { - // when changing fullscreen pango layout of popup is lost - // and we need to re-add marks to the new layout - this.interface.controls.setVolumeMarks(false); - if(isFullscreen) { this.setUpdateTimeInterval(); this.setHideControlsTimeout(); - this.interface.controls.unfullscreenButton.set_sensitive(true); - this.interface.controls.unfullscreenButton.show(); - this.interface.showControls(true); } else { this.clearTimeout('updateTime'); - this.interface.controls.unfullscreenButton.set_sensitive(false); - this.interface.controls.unfullscreenButton.hide(); - this.interface.showControls(false); } - this.interface.setControlsOnVideo(isFullscreen); - this.interface.controls.setVolumeMarks(true); - this.interface.controls.setFullscreenMode(isFullscreen); + this.interface.setFullscreenMode(isFullscreen); } _onWindowKeyPressEvent(self, event) diff --git a/clapper_src/buttons.js b/clapper_src/buttons.js index 2efce995..aaa514ca 100644 --- a/clapper_src/buttons.js +++ b/clapper_src/buttons.js @@ -1,41 +1,51 @@ const { GObject, Gtk } = imports.gi; -var BoxedIconButton = GObject.registerClass( -class BoxedIconButton extends Gtk.Button +var IconButton = GObject.registerClass( +class ClapperIconButton extends Gtk.Button { - _init(icon, size, isFullscreen) + _init(icon) { super._init({ margin_top: 4, margin_bottom: 4, + margin_start: 1, + margin_end: 1, can_focus: false, - //can_default: false, + icon_name: icon, }); - this.isFullscreen = isFullscreen || false; - - size = size || Gtk.IconSize.SMALL_TOOLBAR; - let image = Gtk.Image.new_from_icon_name(icon); - - //if(image) - //this.set_image(image); -/* - this.image.defaultSize = size; - this.image.fullscreenSize = (size === Gtk.IconSize.SMALL_TOOLBAR) - ? Gtk.IconSize.LARGE_TOOLBAR - : Gtk.IconSize.DND; -*/ + this.isFullscreen = false; this.add_css_class('flat'); - - this.box = new Gtk.Box(); - this.box.append(this); - - super.show(); } - get visible() + setFullscreenMode(isFullscreen) { - return this.box.visible; + this.isFullscreen = isFullscreen; + } +}); + +var PopoverButton = GObject.registerClass( +class ClapperPopoverButton extends IconButton +{ + _init(icon) + { + super._init(icon); + + this.popover = new Gtk.Popover({ + position: Gtk.PositionType.TOP, + }); + this.popoverBox = new Gtk.Box({ + orientation: Gtk.Orientation.VERTICAL, + }); + + this.popover.set_parent(this); + this.popover.set_child(this.popoverBox); + this.popover.set_offset(0, -this.margin_top); + + if(this.isFullscreen) + this.popover.add_css_class('osd'); + + this.destroySignal = this.connect('destroy', this._onDestroy.bind(this)); } setFullscreenMode(isFullscreen) @@ -43,62 +53,30 @@ class BoxedIconButton extends Gtk.Button if(this.isFullscreen === isFullscreen) return; - this.image.icon_size = (isFullscreen) - ? this.image.fullscreenSize - : this.image.defaultSize; + this.margin_top = (isFullscreen) ? 6 : 4; + this.popover.set_offset(0, -this.margin_top); - this.isFullscreen = isFullscreen; - } -/* - show_all() - { - this.box.show_all(); - } -*/ - show() - { - this.box.show(); - } - - hide() - { - this.box.hide(); - } -}); - -var BoxedPopoverButton = GObject.registerClass( -class BoxedPopoverButton extends BoxedIconButton -{ - _init(icon, size, isFullscreen) - { - super._init(icon, size, isFullscreen); - - this.popover = new Gtk.Popover({ - default_widget: this.box - }); - this.popoverBox = new Gtk.Box({ - orientation: Gtk.Orientation.VERTICAL - }); - this.popover.set_child(this.popoverBox); - this.popoverBox.show(); - - if(this.isFullscreen) - this.popover.add_css_class('osd'); - } - - setFullscreenMode(isEnabled) - { - if(this.isFullscreen === isEnabled) + let cssClass = 'osd'; + if(isFullscreen == this.popover.has_css_class(cssClass)) return; - let action = (isEnabled) ? 'add' : 'remove'; - this.popover[action + '_css_class']('osd'); + let action = (isFullscreen) ? 'add' : 'remove'; + this.popover[action + '_css_class'](cssClass); - super.setFullscreenMode(isEnabled); + super.setFullscreenMode(isFullscreen); } vfunc_clicked() { this.popover.popup(); } + + _onDestroy() + { + this.disconnect(this.destroySignal); + + this.popover.unparent(); + this.popoverBox.emit('destroy'); + this.popover.emit('destroy'); + } }); diff --git a/clapper_src/controls.js b/clapper_src/controls.js index 841b1870..19032930 100644 --- a/clapper_src/controls.js +++ b/clapper_src/controls.js @@ -31,7 +31,6 @@ var Controls = GObject.registerClass({ valign: Gtk.Align.END, }); - this.fullscreenMode = false; this.durationFormated = '00:00:00'; this.buttonsArr = []; @@ -52,124 +51,100 @@ var Controls = GObject.registerClass({ this._addVolumeButton(); this.unfullscreenButton = this.addButton( 'view-restore-symbolic', - Gtk.IconSize.SMALL_TOOLBAR, - true ); + this.unfullscreenButton.set_visible(false); this.fullscreenButton = Gtk.Button.new_from_icon_name( 'view-fullscreen-symbolic', - //Gtk.IconSize.SMALL_TOOLBAR ); this.setDefaultWidgetBehaviour(this.fullscreenButton); this.openMenuButton = Gtk.Button.new_from_icon_name( 'open-menu-symbolic', - //Gtk.IconSize.SMALL_TOOLBAR ); this.setDefaultWidgetBehaviour(this.openMenuButton); //this.forall(this.setDefaultWidgetBehaviour); - this.realizeSignal = this.connect('realize', this._onControlsRealize.bind(this)); - this.destroySignal = this.connect('destroy', this._onControlsDestroy.bind(this)); - } - - pack_start(widget, expand, fill, padding) - { - if( - widget.box - && widget.box.constructor - && widget.box.constructor === Gtk.Box - ) - widget = widget.box; - - super.append(widget); + this.realizeSignal = this.connect('realize', this._onRealize.bind(this)); + this.destroySignal = this.connect('destroy', this._onDestroy.bind(this)); } setFullscreenMode(isFullscreen) { - if(isFullscreen === this.fullscreenMode) - return; - for(let button of this.buttonsArr) button.setFullscreenMode(isFullscreen); - this.fullscreenMode = isFullscreen; + this.unfullscreenButton.set_visible(isFullscreen); } - addButton(iconName, size, noPack) + addButton(iconName) { - let button = new Buttons.BoxedIconButton( - iconName, size, this.fullscreenMode - ); - - if(!noPack) - this.pack_start(button, false, false, 0); - - this.buttonsArr.push(button); - return button; - } - - addPopoverButton(iconName, size) - { - let button = new Buttons.BoxedPopoverButton( - iconName, size, this.fullscreenMode - ); - this.pack_start(button, false, false, 0); + let button = new Buttons.IconButton(iconName); + this.append(button); this.buttonsArr.push(button); return button; } - addRadioButtons(box, array, activeId) + addPopoverButton(iconName) { - return; + let button = new Buttons.PopoverButton(iconName); + this.append(button); + this.buttonsArr.push(button); + return button; + } + + addCheckButtons(box, array, activeId) + { let group = null; - let children = box.get_children(); - let lastEl = (children.length > array.length) - ? children.length - : array.length; + let child = box.get_first_child(); + let i = 0; - for(let i = 0; i < lastEl; i++) { + while(child || i < array.length) { if(i >= array.length) { - children[i].hide(); - debug(`hiding unused ${children[i].type} radioButton nr: ${i}`); + child.hide(); + debug(`hiding unused ${child.type} checkButton nr: ${i}`); + i++; + child = child.get_next_sibling(); continue; } let el = array[i]; - let radioButton; + let checkButton; - if(i < children.length) { - radioButton = children[i]; - debug(`reusing ${el.type} radioButton nr: ${i}`); + if(child) { + checkButton = child; + debug(`reusing ${el.type} checkButton nr: ${i}`); } else { - debug(`creating new ${el.type} radioButton nr: ${i}`); - radioButton = new Gtk.RadioButton({ + debug(`creating new ${el.type} checkButton nr: ${i}`); + checkButton = new Gtk.CheckButton({ group: group, }); - radioButton.connect( + checkButton.connect( 'toggled', - this._onRadioButtonToggled.bind(this, radioButton) + this._onCheckButtonToggled.bind(this, checkButton) ); - this.setDefaultWidgetBehaviour(radioButton); - box.add(radioButton); + this.setDefaultWidgetBehaviour(checkButton); + box.append(checkButton); } - radioButton.label = el.label; - debug(`radioButton label: ${radioButton.label}`); - radioButton.type = el.type; - debug(`radioButton type: ${radioButton.type}`); - radioButton.activeId = el.activeId; - debug(`radioButton id: ${radioButton.activeId}`); + checkButton.label = el.label; + debug(`checkButton label: ${checkButton.label}`); + checkButton.type = el.type; + debug(`checkButton type: ${checkButton.type}`); + checkButton.activeId = el.activeId; + debug(`checkButton id: ${checkButton.activeId}`); - if(radioButton.activeId === activeId) { - radioButton.set_active(true); - debug(`activated ${el.type} radioButton nr: ${i}`); + if(checkButton.activeId === activeId) { + checkButton.set_active(true); + debug(`activated ${el.type} checkButton nr: ${i}`); } if(!group) - group = radioButton; + group = checkButton; - radioButton.show(); + i++; + if(child) + child = child.get_next_sibling(); } } @@ -179,16 +154,6 @@ var Controls = GObject.registerClass({ //widget.can_default = false; } - setVolumeMarks(isAdded) - { - if(!isAdded) - return this.volumeScale.clear_marks(); - - this.volumeScale.add_mark(0, Gtk.PositionType.LEFT, '0%'); - this.volumeScale.add_mark(1, Gtk.PositionType.LEFT, '100%'); - this.volumeScale.add_mark(2, Gtk.PositionType.LEFT, '200%'); - } - handleScaleIncrement(type, isUp) { let value = this[`${type}Scale`].get_value(); @@ -252,7 +217,7 @@ var Controls = GObject.registerClass({ ); */ this.positionAdjustment = this.positionScale.get_adjustment(); - this.pack_start(this.positionScale, true, true, 0); + this.append(this.positionScale); } _addVolumeButton() @@ -280,10 +245,11 @@ var Controls = GObject.registerClass({ this.volumeAdjustment.set_page_increment(0.05); this.setDefaultWidgetBehaviour(this.volumeScale); + for(let i = 0; i <= 2; i++) { + let text = (i) ? `${i}00%` : '0%'; + this.volumeScale.add_mark(i, Gtk.PositionType.LEFT, text); + } this.volumeButton.popoverBox.append(this.volumeScale); - //this.volumeButton.popoverBox.show_all(); - - this.setVolumeMarks(true); } _getFormatedTime(time) @@ -297,25 +263,25 @@ var Controls = GObject.registerClass({ return `${hours}:${minutes}:${seconds}`; } - _onRadioButtonToggled(self, radioButton) + _onCheckButtonToggled(self, checkButton) { - if(!radioButton.get_active()) + if(!checkButton.get_active()) return; - switch(radioButton.type) { + switch(checkButton.type) { case 'video': case 'audio': case 'subtitle': this.emit( 'track-change-requested', - radioButton.type, - radioButton.activeId + checkButton.type, + checkButton.activeId ); break; case 'visualization': this.emit( - `${radioButton.type}-change-requested`, - radioButton.activeId + `${checkButton.type}-change-requested`, + checkButton.activeId ); break; default: @@ -341,7 +307,7 @@ var Controls = GObject.registerClass({ this.emit('position-seeking-changed', this.isPositionSeeking); } - _onControlsRealize() + _onRealize() { this.disconnect(this.realizeSignal); @@ -380,9 +346,15 @@ var Controls = GObject.registerClass({ } } - _onControlsDestroy() + _onDestroy() { this.disconnect(this.destroySignal); + this.positionScale.set_format_value_func(null); + this.visualizationsButton.emit('destroy'); + this.videoTracksButton.emit('destroy'); + this.audioTracksButton.emit('destroy'); + this.subtitleTracksButton.emit('destroy'); + this.volumeButton.emit('destroy'); } }); diff --git a/clapper_src/interface.js b/clapper_src/interface.js index fc12fb7f..985c79f3 100644 --- a/clapper_src/interface.js +++ b/clapper_src/interface.js @@ -19,7 +19,7 @@ class ClapperInterface extends Gtk.Grid }; Object.assign(this, defaults, opts); - this.controlsInVideo = false; + this.fullscreenMode = false; this.lastVolumeValue = null; this.lastPositionValue = 0; this.lastRevealerEventTime = 0; @@ -38,7 +38,7 @@ class ClapperInterface extends Gtk.Grid this.attach(this.videoBox, 0, 0, 1, 1); this.attach(this.controls, 0, 1, 1, 1); - this.destroySignal = this.connect('destroy', this._onInterfaceDestroy.bind(this)); + this.destroySignal = this.connect('destroy', this._onDestroy.bind(this)); } addPlayer(player) @@ -102,24 +102,25 @@ class ClapperInterface extends Gtk.Grid this[`revealer${pos}`].showChild(isShow); } - setControlsOnVideo(isOnVideo) + setFullscreenMode(isFullscreen) { - if(this.controlsInVideo === isOnVideo) + if(this.fullscreenMode === isFullscreen) return; - if(isOnVideo) { + if(isFullscreen) { this.remove(this.controls); - this.controls.pack_start(this.controls.unfullscreenButton.box, false, false, 0); - this.revealerBottom.addWidget(this.controls); + this.revealerBottom.append(this.controls); } else { - this.revealerBottom.removeWidget(this.controls); - this.controls.remove(this.controls.unfullscreenButton.box); + this.revealerBottom.remove(this.controls); this.attach(this.controls, 0, 1, 1, 1); } - this.controlsInVideo = isOnVideo; - debug(`placed controls in overlay: ${isOnVideo}`); + this.controls.setFullscreenMode(isFullscreen); + this.showControls(isFullscreen); + + this.fullscreenMode = isFullscreen; + debug(`interface in fullscreen mode: ${isFullscreen}`); } updateMediaTracks() @@ -212,7 +213,7 @@ class ClapperInterface extends Gtk.Grid } continue; } - this.controls.addRadioButtons( + this.controls.addCheckButtons( this.controls[`${type}TracksButton`].popoverBox, parsedInfo[`${type}Tracks`], activeId @@ -265,7 +266,7 @@ class ClapperInterface extends Gtk.Grid }); }); - this.controls.addRadioButtons( + this.controls.addCheckButtons( this.controls.visualizationsButton.popoverBox, parsedVisArr, null @@ -433,7 +434,7 @@ class ClapperInterface extends Gtk.Grid this.lastPositionValue = positionSeconds; this._player.seek_seconds(positionSeconds); - if(this.controls.fullscreenMode) + if(this.fullscreenMode) this.updateTime(); } @@ -469,7 +470,7 @@ class ClapperInterface extends Gtk.Grid this._player.set_volume(volume); } - _onInterfaceDestroy() + _onDestroy() { this.disconnect(this.destroySignal); this.controls.emit('destroy'); diff --git a/clapper_src/revealers.js b/clapper_src/revealers.js index 4d65d573..f148b4ef 100644 --- a/clapper_src/revealers.js +++ b/clapper_src/revealers.js @@ -220,15 +220,14 @@ class ClapperRevealerBottom extends CustomRevealer this.revealerBox.add_css_class('osd'); this.set_child(this.revealerBox); - //this.revealerBox.show_all(); } - addWidget(widget) + append(widget) { - this.revealerBox.pack_start(widget, false, true, 0); + this.revealerBox.append(widget); } - removeWidget(widget) + remove(widget) { this.revealerBox.remove(widget); } diff --git a/css/styles.css b/css/styles.css index b0332d2d..140dab30 100644 --- a/css/styles.css +++ b/css/styles.css @@ -8,7 +8,8 @@ scale marks { font-weight: 500; } .osd button { - margin: 2px; + margin-left: 1px; + margin-right: 1px; min-width: 36px; min-height: 36px; } From 352eff89b7ede345938ca5442f2c504422d56ed4 Mon Sep 17 00:00:00 2001 From: Rafostar <40623528+Rafostar@users.noreply.github.com> Date: Wed, 7 Oct 2020 18:18:44 +0200 Subject: [PATCH 04/21] Fix volume button icon and window key events --- clapper_src/app.js | 34 ++++++++++------------------------ clapper_src/interface.js | 10 +++------- clapper_src/player.js | 15 ++++++++++++--- clapper_src/window.js | 4 ++++ 4 files changed, 29 insertions(+), 34 deletions(-) diff --git a/clapper_src/app.js b/clapper_src/app.js index fb6cd21b..7ac6a64a 100644 --- a/clapper_src/app.js +++ b/clapper_src/app.js @@ -52,11 +52,9 @@ var App = GObject.registerClass({ this.windowRealizeSignal = this.window.connect( 'realize', this._onWindowRealize.bind(this) ); -/* - this.window.connect( - 'key-press-event', this._onWindowKeyPressEvent.bind(this) + this.window.keyController.connect( + 'key-pressed', this._onWindowKeyPressEvent.bind(this) ); -*/ this.window.connect( 'fullscreen-changed', this._onWindowFullscreenChanged.bind(this) ); @@ -173,9 +171,6 @@ var App = GObject.registerClass({ ); */ this.interface.addPlayer(this.player); - - this.player.connect('warning', this._onPlayerWarning.bind(this)); - this.player.connect('error', this._onPlayerError.bind(this)); this.player.connect('state-changed', this._onPlayerStateChanged.bind(this)); /* this.player.connectWidget( @@ -213,15 +208,11 @@ var App = GObject.registerClass({ this.interface.setFullscreenMode(isFullscreen); } - _onWindowKeyPressEvent(self, event) + _onWindowKeyPressEvent(self, keyval, keycode, state) { - let [res, key] = event.get_keyval(); - if(!res) return; - - //let keyName = Gdk.keyval_name(key); let bool = false; - switch(key) { + switch(keyval) { case Gdk.KEY_space: case Gdk.KEY_Return: this.player.toggle_play(); @@ -294,6 +285,7 @@ var App = GObject.registerClass({ if(state === GstPlayer.PlayerState.BUFFERING) return; + let isInhibited = false; let flags = Gtk.ApplicationInhibitFlags.SUSPEND | Gtk.ApplicationInhibitFlags.IDLE; @@ -306,6 +298,10 @@ var App = GObject.registerClass({ flags, 'video is playing' ); + if(!this.inhibitCookie) + debug(new Error('could not inhibit session!')); + + isInhibited = (this.inhibitCookie > 0); } else { if(!this.inhibitCookie) @@ -315,7 +311,7 @@ var App = GObject.registerClass({ this.inhibitCookie = null; } - //debug('set prevent suspend to: ' + this.is_inhibited(flags)); + debug(`set prevent suspend to: ${isInhibited}`); } _onPlayerButtonPressEvent(self, event) @@ -414,16 +410,6 @@ var App = GObject.registerClass({ ); } - _onPlayerWarning(self, error) - { - debug(error.message, 'LEVEL_WARNING'); - } - - _onPlayerError(self, error) - { - debug(error); - } - _onWindowCloseRequest() { this.window.destroy(); diff --git a/clapper_src/interface.js b/clapper_src/interface.js index 985c79f3..a39611c9 100644 --- a/clapper_src/interface.js +++ b/clapper_src/interface.js @@ -453,16 +453,12 @@ class ClapperInterface extends Gtk.Grid : 'overamplified'; let iconName = `audio-volume-${icon}-symbolic`; -/* - if(this.controls.volumeButton.image.icon_name !== iconName) + if(this.controls.volumeButton.icon_name !== iconName) { debug(`set volume icon: ${icon}`); - this.controls.volumeButton.image.set_from_icon_name( - iconName, - this.controls.volumeButton.image.icon_size - ); + this.controls.volumeButton.set_icon_name(iconName); } -*/ + if(volume === this.lastVolumeValue) return; diff --git a/clapper_src/player.js b/clapper_src/player.js index bfe8510f..d0f4259d 100644 --- a/clapper_src/player.js +++ b/clapper_src/player.js @@ -68,9 +68,6 @@ class ClapperPlayer extends GstPlayer.Player this.set_config(config); this.set_mute(false); - - /* FIXME: remove once GUI buttons are back */ - this.set_volume(0.5); this.set_plugin_rank('vah264dec', 300); this.loop = GLib.MainLoop.new(null, false); @@ -86,6 +83,8 @@ class ClapperPlayer extends GstPlayer.Player this.connect('state-changed', this._onStateChanged.bind(this)); this.connect('uri-loaded', this._onUriLoaded.bind(this)); this.connect('end-of-stream', this._onStreamEnded.bind(this)); + this.connect('warning', this._onPlayerWarning.bind(this)); + this.connect('error', this._onPlayerError.bind(this)); this.connectWidget('destroy', this._onWidgetDestroy.bind(this)); } @@ -253,6 +252,16 @@ class ClapperPlayer extends GstPlayer.Player this.loop.run(); } + _onPlayerWarning(self, error) + { + debug(error.message, 'LEVEL_WARNING'); + } + + _onPlayerError(self, error) + { + debug(error); + } + _onWidgetDestroy() { while(this._widgetSignals.length) diff --git a/clapper_src/window.js b/clapper_src/window.js index 5ca1d546..0b8b011b 100644 --- a/clapper_src/window.js +++ b/clapper_src/window.js @@ -17,6 +17,10 @@ var Window = GObject.registerClass({ destroy_with_parent: true, }); this.isFullscreen = false; + + this.keyController = new Gtk.EventControllerKey(); + this.add_controller(this.keyController); + this.mapSignal = this.connect('map', this._onMap.bind(this)); } From 4c5d922d47b3ffeb45517dd4ffdc076bddd38993 Mon Sep 17 00:00:00 2001 From: Rafostar <40623528+Rafostar@users.noreply.github.com> Date: Wed, 7 Oct 2020 20:22:02 +0200 Subject: [PATCH 05/21] Fix toggle play button icon change --- clapper_src/buttons.js | 58 +++++++++++++++++++++++++++++++++------- clapper_src/controls.js | 45 ++++++++++++++----------------- clapper_src/interface.js | 4 +-- css/styles.css | 7 ++--- 4 files changed, 75 insertions(+), 39 deletions(-) diff --git a/clapper_src/buttons.js b/clapper_src/buttons.js index aaa514ca..60e9671c 100644 --- a/clapper_src/buttons.js +++ b/clapper_src/buttons.js @@ -1,18 +1,22 @@ const { GObject, Gtk } = imports.gi; -var IconButton = GObject.registerClass( -class ClapperIconButton extends Gtk.Button +var CustomButton = GObject.registerClass( +class ClapperCustomButton extends Gtk.Button { - _init(icon) + _init(opts) { - super._init({ + opts = opts || {}; + + let defaults = { margin_top: 4, margin_bottom: 4, margin_start: 1, margin_end: 1, can_focus: false, - icon_name: icon, - }); + }; + Object.assign(opts, defaults); + + super._init(opts); this.isFullscreen = false; this.add_css_class('flat'); @@ -20,10 +24,47 @@ class ClapperIconButton extends Gtk.Button setFullscreenMode(isFullscreen) { + if(this.isFullscreen === isFullscreen) + return; + + this.margin_top = (isFullscreen) ? 6 : 4; this.isFullscreen = isFullscreen; } }); +var IconButton = GObject.registerClass( +class ClapperIconButton extends CustomButton +{ + _init(icon) + { + super._init({ + icon_name: icon, + }); + } +}); + +var IconToggleButton = GObject.registerClass( +class ClapperIconToggleButton extends IconButton +{ + _init(primaryIcon, secondaryIcon) + { + super._init(primaryIcon); + + this.primaryIcon = primaryIcon; + this.secondaryIcon = secondaryIcon; + } + + setPrimaryIcon() + { + this.icon_name = this.primaryIcon; + } + + setSecondaryIcon() + { + this.icon_name = this.secondaryIcon; + } +}); + var PopoverButton = GObject.registerClass( class ClapperPopoverButton extends IconButton { @@ -53,7 +94,8 @@ class ClapperPopoverButton extends IconButton if(this.isFullscreen === isFullscreen) return; - this.margin_top = (isFullscreen) ? 6 : 4; + super.setFullscreenMode(isFullscreen); + this.popover.set_offset(0, -this.margin_top); let cssClass = 'osd'; @@ -62,8 +104,6 @@ class ClapperPopoverButton extends IconButton let action = (isFullscreen) ? 'add' : 'remove'; this.popover[action + '_css_class'](cssClass); - - super.setFullscreenMode(isFullscreen); } vfunc_clicked() diff --git a/clapper_src/controls.js b/clapper_src/controls.js index 19032930..d5239bb1 100644 --- a/clapper_src/controls.js +++ b/clapper_src/controls.js @@ -63,6 +63,8 @@ var Controls = GObject.registerClass({ this.setDefaultWidgetBehaviour(this.openMenuButton); //this.forall(this.setDefaultWidgetBehaviour); + this.add_css_class('playercontrols'); + this.realizeSignal = this.connect('realize', this._onRealize.bind(this)); this.destroySignal = this.connect('destroy', this._onDestroy.bind(this)); } @@ -75,9 +77,12 @@ var Controls = GObject.registerClass({ this.unfullscreenButton.set_visible(isFullscreen); } - addButton(iconName) + addButton(buttonIcon) { - let button = new Buttons.IconButton(iconName); + let button = (buttonIcon instanceof Gtk.Button) + ? buttonIcon + : new Buttons.IconButton(buttonIcon); + this.append(button); this.buttonsArr.push(button); @@ -87,10 +92,8 @@ var Controls = GObject.registerClass({ addPopoverButton(iconName) { let button = new Buttons.PopoverButton(iconName); - this.append(button); - this.buttonsArr.push(button); - return button; + return this.addButton(button); } addCheckButtons(box, array, activeId) @@ -172,28 +175,11 @@ var Controls = GObject.registerClass({ _addTogglePlayButton() { - this.togglePlayButton = this.addButton( + this.togglePlayButton = new Buttons.IconToggleButton( 'media-playback-start-symbolic', - Gtk.IconSize.LARGE_TOOLBAR + 'media-playback-pause-symbolic' ); - this.togglePlayButton.setPlayImage = () => - { -/* - this.togglePlayButton.image.set_from_icon_name( - 'media-playback-start-symbolic', - this.togglePlayButton.image.icon_size - ); -*/ - } - this.togglePlayButton.setPauseImage = () => - { -/* - this.togglePlayButton.image.set_from_icon_name( - 'media-playback-pause-symbolic', - this.togglePlayButton.image.icon_size - ); -*/ - } + this.addButton(this.togglePlayButton); } _addPositionScale() @@ -203,7 +189,16 @@ var Controls = GObject.registerClass({ value_pos: Gtk.PositionType.LEFT, draw_value: true, hexpand: true, + valign: Gtk.Align.CENTER, }); + + this.togglePlayButton.bind_property('margin_top', + this.positionScale, 'margin_top', GObject.BindingFlags.SYNC_CREATE + ); + this.togglePlayButton.bind_property('margin_bottom', + this.positionScale, 'margin_bottom', GObject.BindingFlags.SYNC_CREATE + ); + this.positionScale.add_css_class('positionscale'); this.positionScale.set_format_value_func( this._onPositionScaleFormatValue.bind(this) diff --git a/clapper_src/interface.js b/clapper_src/interface.js index a39611c9..9240e945 100644 --- a/clapper_src/interface.js +++ b/clapper_src/interface.js @@ -350,10 +350,10 @@ class ClapperInterface extends Gtk.Grid case GstPlayer.PlayerState.STOPPED: this.needsTracksUpdate = true; case GstPlayer.PlayerState.PAUSED: - this.controls.togglePlayButton.setPlayImage(); + this.controls.togglePlayButton.setPrimaryIcon(); break; case GstPlayer.PlayerState.PLAYING: - this.controls.togglePlayButton.setPauseImage(); + this.controls.togglePlayButton.setSecondaryIcon(); if(this.needsTracksUpdate) { this.needsTracksUpdate = false; this.updateMediaTracks(); diff --git a/css/styles.css b/css/styles.css index 140dab30..1a91276c 100644 --- a/css/styles.css +++ b/css/styles.css @@ -7,9 +7,10 @@ scale marks { font-size: 22px; font-weight: 500; } +.osd .playercontrols { + -gtk-icon-size: 24px; +} .osd button { - margin-left: 1px; - margin-right: 1px; min-width: 36px; min-height: 36px; } @@ -28,7 +29,7 @@ scale marks { } .reavealertop { min-height: 100px; - box-shadow: inset 0px 200px 10px -124px rgba(0,0,0,0.4); + box-shadow: inset 0px 200px 10px -124px rgba(0,0,0,0.3); font-family: 'Cantarell', 'Noto Sans', sans-serif; font-size: 30px; font-weight: 500; From 43a54920ef82d872385658a2db902673404f5513 Mon Sep 17 00:00:00 2001 From: Rafostar <40623528+Rafostar@users.noreply.github.com> Date: Wed, 7 Oct 2020 23:10:11 +0200 Subject: [PATCH 06/21] Change elapsed time into button --- clapper_src/app.js | 4 +++- clapper_src/buttons.js | 25 +++++++++++++++++++++++++ clapper_src/controls.js | 23 ++++++++++++++++------- css/styles.css | 29 ++++++++++------------------- 4 files changed, 54 insertions(+), 27 deletions(-) diff --git a/clapper_src/app.js b/clapper_src/app.js index 7ac6a64a..86d27304 100644 --- a/clapper_src/app.js +++ b/clapper_src/app.js @@ -84,7 +84,7 @@ var App = GObject.registerClass({ { super.vfunc_activate(); - this.window.show(); + this.window.present(); Gtk.StyleContext.add_provider_for_display( Gdk.Display.get_default(), this.cssProvider, @@ -307,8 +307,10 @@ var App = GObject.registerClass({ if(!this.inhibitCookie) return; + /* Uninhibit seems to be broken as of GTK 3.99.2 this.uninhibit(this.inhibitCookie); this.inhibitCookie = null; + */ } debug(`set prevent suspend to: ${isInhibited}`); diff --git a/clapper_src/buttons.js b/clapper_src/buttons.js index 60e9671c..2c4f4d94 100644 --- a/clapper_src/buttons.js +++ b/clapper_src/buttons.js @@ -65,6 +65,31 @@ class ClapperIconToggleButton extends IconButton } }); +var LabelButton = GObject.registerClass( +class ClapperLabelButton extends CustomButton +{ + _init(text) + { + super._init({ + margin_start: 0, + margin_end: 0, + }); + + this.customLabel = new Gtk.Label({ + label: text, + single_line_mode: true, + }); + + this.customLabel.add_css_class('labelbutton'); + this.set_child(this.customLabel); + } + + set_label(text) + { + this.customLabel.set_text(text); + } +}); + var PopoverButton = GObject.registerClass( class ClapperPopoverButton extends IconButton { diff --git a/clapper_src/controls.js b/clapper_src/controls.js index d5239bb1..240b442d 100644 --- a/clapper_src/controls.js +++ b/clapper_src/controls.js @@ -32,6 +32,7 @@ var Controls = GObject.registerClass({ }); this.durationFormated = '00:00:00'; + this.elapsedInitial = '00:00:00/00:00:00'; this.buttonsArr = []; this._addTogglePlayButton(); @@ -89,6 +90,14 @@ var Controls = GObject.registerClass({ return button; } + addLabelButton(text) + { + text = text || ''; + let button = new Buttons.LabelButton(text); + + return this.addButton(button); + } + addPopoverButton(iconName) { let button = new Buttons.PopoverButton(iconName); @@ -184,10 +193,11 @@ var Controls = GObject.registerClass({ _addPositionScale() { + this.elapsedButton = this.addLabelButton(this.elapsedInitial); this.positionScale = new Gtk.Scale({ orientation: Gtk.Orientation.HORIZONTAL, value_pos: Gtk.PositionType.LEFT, - draw_value: true, + draw_value: false, hexpand: true, valign: Gtk.Align.CENTER, }); @@ -200,9 +210,7 @@ var Controls = GObject.registerClass({ ); this.positionScale.add_css_class('positionscale'); - this.positionScale.set_format_value_func( - this._onPositionScaleFormatValue.bind(this) - ); + this.positionScale.connect('value-changed', this._onPositionScaleValueChanged.bind(this)); /* this.positionScale.connect( 'button-press-event', this._onPositionScaleButtonPressEvent.bind(this) @@ -284,10 +292,12 @@ var Controls = GObject.registerClass({ } } - _onPositionScaleFormatValue(self, value) + _onPositionScaleValueChanged() { - return this._getFormatedTime(value) + let elapsed = this._getFormatedTime(this.positionScale.get_value()) + '/' + this.durationFormated; + + this.elapsedButton.set_label(elapsed); } _onPositionScaleButtonPressEvent() @@ -345,7 +355,6 @@ var Controls = GObject.registerClass({ { this.disconnect(this.destroySignal); - this.positionScale.set_format_value_func(null); this.visualizationsButton.emit('destroy'); this.videoTracksButton.emit('destroy'); this.audioTracksButton.emit('destroy'); diff --git a/css/styles.css b/css/styles.css index 1a91276c..6ab5421d 100644 --- a/css/styles.css +++ b/css/styles.css @@ -24,6 +24,11 @@ scale marks { min-width: 18px; min-height: 18px; } +.labelbutton { + font-family: 'Cantarell', 'Noto Sans', sans-serif; + font-variant-numeric: tabular-nums; + font-weight: 600; +} .videobox { background: black; } @@ -45,25 +50,13 @@ scale marks { font-size: 24px; font-weight: 600; } - -/* Position Scale */ -.positionscale value { - font-weight: 600; - color: currentColor; -} -.positionscale trough highlight { - min-height: 4px; -} -.osd .positionscale value { +.osd .labelbutton { font-size: 24px; } -.positionscale contents { - margin-left: 4px; - margin-right: 2px; -} -.osd .positionscale contents { - margin-left: 8px; - margin-right: 2px; + +/* Position Scale */ +.positionscale trough highlight { + min-height: 4px; } .osd .positionscale trough slider { color: transparent; @@ -77,12 +70,10 @@ scale marks { /* Volume Scale */ .volumescale { - margin-left: 4px; min-height: 180px; } .osd .volumescale { margin: 6px; - margin-left: 10px; min-height: 280px; } .volumescale marks label { From e2d6cc440db8197476754cb581951be6e31d1a04 Mon Sep 17 00:00:00 2001 From: Rafostar <40623528+Rafostar@users.noreply.github.com> Date: Wed, 7 Oct 2020 23:41:12 +0200 Subject: [PATCH 07/21] Tweak play/pause icons size --- clapper_src/controls.js | 1 + css/styles.css | 6 ++++++ 2 files changed, 7 insertions(+) diff --git a/clapper_src/controls.js b/clapper_src/controls.js index 240b442d..513dca2d 100644 --- a/clapper_src/controls.js +++ b/clapper_src/controls.js @@ -188,6 +188,7 @@ var Controls = GObject.registerClass({ 'media-playback-start-symbolic', 'media-playback-pause-symbolic' ); + this.togglePlayButton.add_css_class('playbackicon'); this.addButton(this.togglePlayButton); } diff --git a/css/styles.css b/css/styles.css index 6ab5421d..04b845c0 100644 --- a/css/styles.css +++ b/css/styles.css @@ -24,6 +24,12 @@ scale marks { min-width: 18px; min-height: 18px; } +.playbackicon { + -gtk-icon-size: 20px; +} +.osd .playbackicon { + -gtk-icon-size: 28px; +} .labelbutton { font-family: 'Cantarell', 'Noto Sans', sans-serif; font-variant-numeric: tabular-nums; From d3e4f3bb0ff4f09458d04b3e794c0822547aec6e Mon Sep 17 00:00:00 2001 From: Rafostar <40623528+Rafostar@users.noreply.github.com> Date: Mon, 12 Oct 2020 16:25:54 +0200 Subject: [PATCH 08/21] Add player motion and key controllers --- clapper_src/app.js | 60 +++++++++++++++++++++------------------- clapper_src/player.js | 8 +++++- clapper_src/revealers.js | 7 +++++ clapper_src/window.js | 4 --- css/styles.css | 2 +- 5 files changed, 46 insertions(+), 35 deletions(-) diff --git a/clapper_src/app.js b/clapper_src/app.js index 86d27304..730335e1 100644 --- a/clapper_src/app.js +++ b/clapper_src/app.js @@ -39,6 +39,9 @@ var App = GObject.registerClass({ this.interface = null; this.player = null; this.dragStartReady = false; + + this.posX = 0; + this.posY = 0; } vfunc_startup() @@ -46,18 +49,15 @@ var App = GObject.registerClass({ super.vfunc_startup(); this.window = new Window(this, APP_NAME); - this.window.connect('close-request', this._onWindowCloseRequest.bind(this)); - this.window.connect('unmap', () => this.quit()); - this.windowRealizeSignal = this.window.connect( 'realize', this._onWindowRealize.bind(this) ); - this.window.keyController.connect( - 'key-pressed', this._onWindowKeyPressEvent.bind(this) - ); this.window.connect( 'fullscreen-changed', this._onWindowFullscreenChanged.bind(this) ); + this.window.connect( + 'close-request', this._onWindowCloseRequest.bind(this) + ); this.interface = new Interface(); @@ -104,8 +104,8 @@ var App = GObject.registerClass({ this.hideCursorTimeout = GLib.timeout_add_seconds(GLib.PRIORITY_DEFAULT, 1, () => { this.hideCursorTimeout = null; - if(this.isCursorInPlayer) - this.playerWindow.set_cursor(this.blankCursor); + if(this.player.motionController.is_pointer) + this.player.widget.set_cursor(this.blankCursor); return GLib.SOURCE_REMOVE; }); @@ -182,10 +182,14 @@ var App = GObject.registerClass({ this.player.connectWidget( 'leave-notify-event', this._onPlayerLeaveNotifyEvent.bind(this) ); - this.player.connectWidget( - 'motion-notify-event', this._onPlayerMotionNotifyEvent.bind(this) - ); */ + this.player.keyController.connect( + 'key-pressed', this._onPlayerKeyPress.bind(this) + ); + this.player.motionController.connect( + 'motion', this._onPlayerMotion.bind(this) + ); + /* Widget signals that are disconnected after first run */ this._playerRealizeSignal = this.player.widget.connect( 'realize', this._onPlayerRealize.bind(this) @@ -208,7 +212,7 @@ var App = GObject.registerClass({ this.interface.setFullscreenMode(isFullscreen); } - _onWindowKeyPressEvent(self, keyval, keycode, state) + _onPlayerKeyPress(self, keyval, keycode, state) { let bool = false; @@ -237,7 +241,7 @@ var App = GObject.registerClass({ break; case Gdk.KEY_q: case Gdk.KEY_Q: - this.window.destroy(); + this._onWindowCloseRequest(); break; default: break; @@ -257,17 +261,9 @@ var App = GObject.registerClass({ this.player.widget.disconnect(this._playerRealizeSignal); this.player.renderer.expose(); - let display = this.player.widget.get_display(); -/* - this.defaultCursor = Gdk.Cursor.new_from_name( - display, 'default' - ); - this.blankCursor = Gdk.Cursor.new_for_display( - display, Gdk.CursorType.BLANK_CURSOR - ); + this.defaultCursor = Gdk.Cursor.new_from_name('default', null); + this.blankCursor = Gdk.Cursor.new_from_name('none', null); - this.playerWindow = this.player.widget.get_window(); -*/ this.setHideCursorTimeout(); } @@ -374,9 +370,16 @@ var App = GObject.registerClass({ this.clearTimeout('hideControls'); } - _onPlayerMotionNotifyEvent(self, event) + _onPlayerMotion(self, posX, posY) { - this.playerWindow.set_cursor(this.defaultCursor); + /* GTK4 sometimes generates motions with same coords */ + if(this.posX === posX && this.posY === posY) + return; + + this.posX = posX; + this.posY = posY; + + this.player.widget.set_cursor(this.defaultCursor); this.setHideCursorTimeout(); if(this.window.isFullscreen) { @@ -393,11 +396,8 @@ var App = GObject.registerClass({ if(!this.dragStartReady || this.window.isFullscreen) return; - let [res, x, y] = event.get_root_coords(); - if(!res) return; - let startDrag = this.player.widget.drag_check_threshold( - this.dragStartX, this.dragStartY, x, y + this.dragStartX, this.dragStartY, posX, posY ); if(!startDrag) return; @@ -417,5 +417,7 @@ var App = GObject.registerClass({ this.window.destroy(); this.player.widget.emit('destroy'); this.interface.emit('destroy'); + + this.quit(); } }); diff --git a/clapper_src/player.js b/clapper_src/player.js index d0f4259d..f297cdf6 100644 --- a/clapper_src/player.js +++ b/clapper_src/player.js @@ -1,4 +1,4 @@ -const { Gio, GLib, GObject, Gst, GstPlayer } = imports.gi; +const { Gio, GLib, GObject, Gst, GstPlayer, Gtk } = imports.gi; const ByteArray = imports.byteArray; const Debug = imports.clapper_src.debug; @@ -80,6 +80,12 @@ class ClapperPlayer extends GstPlayer.Player this._trackId = 0; this.playlist_ext = opts.playlist_ext || 'claps'; + this.keyController = new Gtk.EventControllerKey(); + this.motionController = new Gtk.EventControllerMotion(); + + this.widget.add_controller(this.keyController); + this.widget.add_controller(this.motionController); + this.connect('state-changed', this._onStateChanged.bind(this)); this.connect('uri-loaded', this._onUriLoaded.bind(this)); this.connect('end-of-stream', this._onStreamEnded.bind(this)); diff --git a/clapper_src/revealers.js b/clapper_src/revealers.js index f148b4ef..7eb95e38 100644 --- a/clapper_src/revealers.js +++ b/clapper_src/revealers.js @@ -10,6 +10,13 @@ class ClapperCustomRevealer extends Gtk.Revealer { _init(opts) { + opts = opts || {}; + + let defaults = { + visible: false, + }; + Object.assign(opts, defaults); + super._init(opts); this.revealerName = ''; diff --git a/clapper_src/window.js b/clapper_src/window.js index 0b8b011b..5ca1d546 100644 --- a/clapper_src/window.js +++ b/clapper_src/window.js @@ -17,10 +17,6 @@ var Window = GObject.registerClass({ destroy_with_parent: true, }); this.isFullscreen = false; - - this.keyController = new Gtk.EventControllerKey(); - this.add_controller(this.keyController); - this.mapSignal = this.connect('map', this._onMap.bind(this)); } diff --git a/css/styles.css b/css/styles.css index 04b845c0..8fe8f4ad 100644 --- a/css/styles.css +++ b/css/styles.css @@ -39,7 +39,7 @@ scale marks { background: black; } .reavealertop { - min-height: 100px; + min-height: 90px; box-shadow: inset 0px 200px 10px -124px rgba(0,0,0,0.3); font-family: 'Cantarell', 'Noto Sans', sans-serif; font-size: 30px; From e4309567520cea4e86c514ad927e01a8a6167bfc Mon Sep 17 00:00:00 2001 From: Rafostar <40623528+Rafostar@users.noreply.github.com> Date: Tue, 13 Oct 2020 20:27:58 +0200 Subject: [PATCH 09/21] Allow navigating over buttons via keyboard --- clapper_src/controls.js | 12 +----------- clapper_src/headerbar.js | 6 ++++-- clapper_src/window.js | 5 +++-- 3 files changed, 8 insertions(+), 15 deletions(-) diff --git a/clapper_src/controls.js b/clapper_src/controls.js index 513dca2d..d86a4cc3 100644 --- a/clapper_src/controls.js +++ b/clapper_src/controls.js @@ -57,12 +57,9 @@ var Controls = GObject.registerClass({ this.fullscreenButton = Gtk.Button.new_from_icon_name( 'view-fullscreen-symbolic', ); - this.setDefaultWidgetBehaviour(this.fullscreenButton); this.openMenuButton = Gtk.Button.new_from_icon_name( 'open-menu-symbolic', ); - this.setDefaultWidgetBehaviour(this.openMenuButton); - //this.forall(this.setDefaultWidgetBehaviour); this.add_css_class('playercontrols'); @@ -136,7 +133,6 @@ var Controls = GObject.registerClass({ 'toggled', this._onCheckButtonToggled.bind(this, checkButton) ); - this.setDefaultWidgetBehaviour(checkButton); box.append(checkButton); } @@ -160,12 +156,6 @@ var Controls = GObject.registerClass({ } } - setDefaultWidgetBehaviour(widget) - { - widget.can_focus = false; - //widget.can_default = false; - } - handleScaleIncrement(type, isUp) { let value = this[`${type}Scale`].get_value(); @@ -201,6 +191,7 @@ var Controls = GObject.registerClass({ draw_value: false, hexpand: true, valign: Gtk.Align.CENTER, + can_focus: false, }); this.togglePlayButton.bind_property('margin_top', @@ -247,7 +238,6 @@ var Controls = GObject.registerClass({ this.volumeAdjustment.set_upper(2); this.volumeAdjustment.set_step_increment(0.05); this.volumeAdjustment.set_page_increment(0.05); - this.setDefaultWidgetBehaviour(this.volumeScale); for(let i = 0; i <= 2; i++) { let text = (i) ? `${i}00%` : '0%'; diff --git a/clapper_src/headerbar.js b/clapper_src/headerbar.js index 3a44d25c..017b4ab4 100644 --- a/clapper_src/headerbar.js +++ b/clapper_src/headerbar.js @@ -5,7 +5,9 @@ class ClapperHeaderBar extends Gtk.HeaderBar { _init(window, startButtons, endButtons) { - super._init(); + super._init({ + can_focus: false, + }); this.set_title_widget(this._createWidgetForWindow(window)); startButtons.forEach(btn => this.pack_start(btn)); @@ -43,7 +45,7 @@ class ClapperHeaderBar extends Gtk.HeaderBar { let box = new Gtk.Box ({ orientation: Gtk.Orientation.VERTICAL, - valign: Gtk.Align.CENTER + valign: Gtk.Align.CENTER, }); this.titleLabel = new Gtk.Label({ diff --git a/clapper_src/window.js b/clapper_src/window.js index 5ca1d546..a9228202 100644 --- a/clapper_src/window.js +++ b/clapper_src/window.js @@ -28,8 +28,9 @@ var Window = GObject.registerClass({ _onStateNotify(toplevel) { - let { state } = toplevel; - let isFullscreen = Boolean(state & Gdk.ToplevelState.FULLSCREEN); + let isFullscreen = Boolean( + toplevel.state & Gdk.ToplevelState.FULLSCREEN + ); if(this.isFullscreen === isFullscreen) return; From cdfafd52afe31f58923ddc21141b91c95d3670d3 Mon Sep 17 00:00:00 2001 From: Rafostar <40623528+Rafostar@users.noreply.github.com> Date: Tue, 13 Oct 2020 20:29:14 +0200 Subject: [PATCH 10/21] Set popover button checked state --- clapper_src/buttons.js | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/clapper_src/buttons.js b/clapper_src/buttons.js index 2c4f4d94..0e16a9b5 100644 --- a/clapper_src/buttons.js +++ b/clapper_src/buttons.js @@ -12,7 +12,6 @@ class ClapperCustomButton extends Gtk.Button margin_bottom: 4, margin_start: 1, margin_end: 1, - can_focus: false, }; Object.assign(opts, defaults); @@ -111,6 +110,9 @@ class ClapperPopoverButton extends IconButton if(this.isFullscreen) this.popover.add_css_class('osd'); + this.changeStateSignal = this.popover.connect('closed', () => + this.unset_state_flags(Gtk.StateFlags.CHECKED) + ); this.destroySignal = this.connect('destroy', this._onDestroy.bind(this)); } @@ -133,6 +135,7 @@ class ClapperPopoverButton extends IconButton vfunc_clicked() { + this.set_state_flags(Gtk.StateFlags.CHECKED, false); this.popover.popup(); } @@ -140,6 +143,7 @@ class ClapperPopoverButton extends IconButton { this.disconnect(this.destroySignal); + this.popover.disconnect(this.changeStateSignal); this.popover.unparent(); this.popoverBox.emit('destroy'); this.popover.emit('destroy'); From 3e96a13f002c364ec98ec06594112c5e3a2e1ea7 Mon Sep 17 00:00:00 2001 From: Rafostar <40623528+Rafostar@users.noreply.github.com> Date: Tue, 13 Oct 2020 20:32:59 +0200 Subject: [PATCH 11/21] Restore window dragging by drag on player --- clapper_src/app.js | 47 ++++++++++++++++++++----------------------- clapper_src/player.js | 2 ++ 2 files changed, 24 insertions(+), 25 deletions(-) diff --git a/clapper_src/app.js b/clapper_src/app.js index 730335e1..820e3437 100644 --- a/clapper_src/app.js +++ b/clapper_src/app.js @@ -38,7 +38,6 @@ var App = GObject.registerClass({ this.window = null; this.interface = null; this.player = null; - this.dragStartReady = false; this.posX = 0; this.posY = 0; @@ -189,6 +188,9 @@ var App = GObject.registerClass({ this.player.motionController.connect( 'motion', this._onPlayerMotion.bind(this) ); + this.player.dragGesture.connect( + 'drag-update', this._onPlayerDragUpdate.bind(this) + ); /* Widget signals that are disconnected after first run */ this._playerRealizeSignal = this.player.widget.connect( @@ -317,8 +319,6 @@ var App = GObject.registerClass({ let [res, button] = event.get_button(); if(!res) return; - this.dragStartReady = false; - switch(button) { case Gdk.BUTTON_PRIMARY: this._handlePrimaryButtonPress(event, button); @@ -337,14 +337,6 @@ var App = GObject.registerClass({ let eventType = event.get_event_type(); switch(eventType) { - case Gdk.EventType.BUTTON_PRESS: - let [res, x, y] = event.get_root_coords(); - if(!res) - break; - this.dragStartX = x; - this.dragStartY = y; - this.dragStartReady = true; - break; case Gdk.EventType.DOUBLE_BUTTON_PRESS: this.window.toggleFullscreen(); break; @@ -392,24 +384,29 @@ var App = GObject.registerClass({ else if(this.hideControlsTimeout) { this.clearTimeout('hideControls'); } + } - if(!this.dragStartReady || this.window.isFullscreen) - return; + _onPlayerDragUpdate(gesture, offsetX, offsetY) + { + let { gtk_double_click_distance } = this.player.widget.get_settings(); - let startDrag = this.player.widget.drag_check_threshold( - this.dragStartX, this.dragStartY, posX, posY - ); - if(!startDrag) return; + if ( + Math.abs(offsetX) > gtk_double_click_distance + || Math.abs(offsetY) > gtk_double_click_distance + ) { + let [isActive, startX, startY] = gesture.get_start_point(); + if(!isActive) return; - this.dragStartReady = false; - let timestamp = event.get_time(); + this.activeWindow.get_surface().begin_move( + gesture.get_device(), + gesture.get_current_button(), + startX, + startY, + gesture.get_current_event_time() + ); - this.window.begin_move_drag( - Gdk.BUTTON_PRIMARY, - this.dragStartX, - this.dragStartY, - timestamp - ); + gesture.reset(); + } } _onWindowCloseRequest() diff --git a/clapper_src/player.js b/clapper_src/player.js index f297cdf6..151afa37 100644 --- a/clapper_src/player.js +++ b/clapper_src/player.js @@ -82,9 +82,11 @@ class ClapperPlayer extends GstPlayer.Player this.keyController = new Gtk.EventControllerKey(); this.motionController = new Gtk.EventControllerMotion(); + this.dragGesture = new Gtk.GestureDrag(); this.widget.add_controller(this.keyController); this.widget.add_controller(this.motionController); + this.widget.add_controller(this.dragGesture); this.connect('state-changed', this._onStateChanged.bind(this)); this.connect('uri-loaded', this._onUriLoaded.bind(this)); From 80b9eb7c97bf537581a559de5e538bf0bce32723 Mon Sep 17 00:00:00 2001 From: Rafostar <40623528+Rafostar@users.noreply.github.com> Date: Tue, 13 Oct 2020 21:36:11 +0200 Subject: [PATCH 12/21] Fix volume button scroll --- clapper_src/controls.js | 37 ++++++++++++++----------------------- clapper_src/headerbar.js | 5 +++-- 2 files changed, 17 insertions(+), 25 deletions(-) diff --git a/clapper_src/controls.js b/clapper_src/controls.js index d86a4cc3..dc368ffd 100644 --- a/clapper_src/controls.js +++ b/clapper_src/controls.js @@ -220,10 +220,14 @@ var Controls = GObject.registerClass({ this.volumeButton = this.addPopoverButton( 'audio-volume-muted-symbolic' ); - //this.volumeButton.add_events(Gdk.EventMask.SCROLL_MASK); - //this.volumeButton.connect( - // 'scroll-event', (self, event) => this._onScrollEvent(event) - //); + let scrollController = new Gtk.EventControllerScroll(); + scrollController.set_flags( + Gtk.EventControllerScrollFlags.VERTICAL + | Gtk.EventControllerScrollFlags.DISCRETE + ); + scrollController.connect('scroll', this._onScroll.bind(this)); + this.volumeButton.add_controller(scrollController); + this.volumeScale = new Gtk.Scale({ orientation: Gtk.Orientation.VERTICAL, inverted: true, @@ -318,28 +322,15 @@ var Controls = GObject.registerClass({ this[`${name}Button`].hide(); } - _onScrollEvent(event) + _onScroll(controller, dx, dy) { - let [res, direction] = event.get_scroll_direction(); - if(!res) return; + let isVertical = Math.abs(dy) >= Math.abs(dx); + let isIncrease = (isVertical) ? dy < 0 : dx < 0; + let type = (isVertical) ? 'volume' : 'position'; - let type = 'volume'; + this.handleScaleIncrement(type, isIncrease); - switch(direction) { - case Gdk.ScrollDirection.RIGHT: - case Gdk.ScrollDirection.LEFT: - type = 'position'; - case Gdk.ScrollDirection.UP: - case Gdk.ScrollDirection.DOWN: - let isUp = ( - direction === Gdk.ScrollDirection.UP - || direction === Gdk.ScrollDirection.RIGHT - ); - this.handleScaleIncrement(type, isUp); - break; - default: - break; - } + return true; } _onDestroy() diff --git a/clapper_src/headerbar.js b/clapper_src/headerbar.js index 017b4ab4..2fdbffa2 100644 --- a/clapper_src/headerbar.js +++ b/clapper_src/headerbar.js @@ -20,8 +20,9 @@ class ClapperHeaderBar extends Gtk.HeaderBar let subtitle = mediaInfo.get_uri() || null; if(subtitle && subtitle.startsWith('file://')) { - subtitle = GLib.filename_from_uri(subtitle)[0]; - subtitle = GLib.path_get_basename(subtitle); + subtitle = GLib.path_get_basename( + GLib.filename_from_uri(subtitle)[0] + ); } if(!title) { From b1ca9c15bc9b2f793907a263ec6191dc4af1a577 Mon Sep 17 00:00:00 2001 From: Rafostar <40623528+Rafostar@users.noreply.github.com> Date: Tue, 13 Oct 2020 22:07:22 +0200 Subject: [PATCH 13/21] Restore scrolling on player --- clapper_src/interface.js | 7 +++---- clapper_src/player.js | 6 ++++++ 2 files changed, 9 insertions(+), 4 deletions(-) diff --git a/clapper_src/interface.js b/clapper_src/interface.js index 9240e945..602fbf8f 100644 --- a/clapper_src/interface.js +++ b/clapper_src/interface.js @@ -51,11 +51,10 @@ class ClapperInterface extends Gtk.Grid this._player.connect('volume-changed', this._onPlayerVolumeChanged.bind(this)); this._player.connect('duration-changed', this._onPlayerDurationChanged.bind(this)); this._player.connect('position-updated', this._onPlayerPositionUpdated.bind(this)); -/* - this._player.connectWidget( - 'scroll-event', (self, event) => this.controls._onScrollEvent(event) + + this._player.scrollController.connect( + 'scroll', (ctl, dx, dy) => this.controls._onScroll(ctl, dx, dy) ); -*/ this.controls.togglePlayButton.connect( 'clicked', this._onControlsTogglePlayClicked.bind(this) ); diff --git a/clapper_src/player.js b/clapper_src/player.js index 151afa37..971e6c23 100644 --- a/clapper_src/player.js +++ b/clapper_src/player.js @@ -82,10 +82,16 @@ class ClapperPlayer extends GstPlayer.Player this.keyController = new Gtk.EventControllerKey(); this.motionController = new Gtk.EventControllerMotion(); + this.scrollController = new Gtk.EventControllerScroll(); this.dragGesture = new Gtk.GestureDrag(); + this.scrollController.set_flags( + Gtk.EventControllerScrollFlags.BOTH_AXES + ); + this.widget.add_controller(this.keyController); this.widget.add_controller(this.motionController); + this.widget.add_controller(this.scrollController); this.widget.add_controller(this.dragGesture); this.connect('state-changed', this._onStateChanged.bind(this)); From 1f6a9b59d6651e2f6903e5c3a2546a9d29da6f1e Mon Sep 17 00:00:00 2001 From: Rafostar <40623528+Rafostar@users.noreply.github.com> Date: Tue, 13 Oct 2020 23:47:13 +0200 Subject: [PATCH 14/21] Restore button presses --- clapper_src/app.js | 53 ++++++++++++++++--------------------------- clapper_src/player.js | 3 +++ 2 files changed, 22 insertions(+), 34 deletions(-) diff --git a/clapper_src/app.js b/clapper_src/app.js index 820e3437..333f4644 100644 --- a/clapper_src/app.js +++ b/clapper_src/app.js @@ -38,6 +38,7 @@ var App = GObject.registerClass({ this.window = null; this.interface = null; this.player = null; + this.dragAllowed = false; this.posX = 0; this.posY = 0; @@ -69,10 +70,10 @@ var App = GObject.registerClass({ this.interface.addHeaderBar(headerBar, APP_NAME); this.interface.controls.fullscreenButton.connect( - 'clicked', () => this._onInterfaceToggleFullscreenClicked(true) + 'clicked', () => this.activeWindow.fullscreen() ); this.interface.controls.unfullscreenButton.connect( - 'clicked', () => this._onInterfaceToggleFullscreenClicked(false) + 'clicked', () => this.activeWindow.unfullscreen() ); this.window.set_titlebar(this.interface.headerBar); @@ -171,10 +172,11 @@ var App = GObject.registerClass({ */ this.interface.addPlayer(this.player); this.player.connect('state-changed', this._onPlayerStateChanged.bind(this)); -/* - this.player.connectWidget( - 'button-press-event', this._onPlayerButtonPressEvent.bind(this) + + this.player.clickGesture.connect( + 'pressed', this._onPlayerPressed.bind(this) ); +/* this.player.connectWidget( 'enter-notify-event', this._onPlayerEnterNotifyEvent.bind(this) ); @@ -183,7 +185,7 @@ var App = GObject.registerClass({ ); */ this.player.keyController.connect( - 'key-pressed', this._onPlayerKeyPress.bind(this) + 'key-pressed', this._onPlayerKeyPressed.bind(this) ); this.player.motionController.connect( 'motion', this._onPlayerMotion.bind(this) @@ -214,7 +216,7 @@ var App = GObject.registerClass({ this.interface.setFullscreenMode(isFullscreen); } - _onPlayerKeyPress(self, keyval, keycode, state) + _onPlayerKeyPressed(self, keyval, keycode, state) { let bool = false; @@ -250,14 +252,6 @@ var App = GObject.registerClass({ } } - _onInterfaceToggleFullscreenClicked(isFsRequested) - { - if(this.window.isFullscreen === isFsRequested) - return; - - this.window.toggleFullscreen(); - } - _onPlayerRealize() { this.player.widget.disconnect(this._playerRealizeSignal); @@ -314,31 +308,19 @@ var App = GObject.registerClass({ debug(`set prevent suspend to: ${isInhibited}`); } - _onPlayerButtonPressEvent(self, event) + _onPlayerPressed(gesture, nPress, x, y) { - let [res, button] = event.get_button(); - if(!res) return; + let button = gesture.get_current_button(); + let isDouble = (nPress % 2 == 0); + this.dragAllowed = !isDouble; switch(button) { case Gdk.BUTTON_PRIMARY: - this._handlePrimaryButtonPress(event, button); + if(isDouble) + this.window.toggleFullscreen(); break; case Gdk.BUTTON_SECONDARY: - if(event.get_event_type() === Gdk.EventType.BUTTON_PRESS) - this.player.toggle_play(); - break; - default: - break; - } - } - - _handlePrimaryButtonPress(event, button) - { - let eventType = event.get_event_type(); - - switch(eventType) { - case Gdk.EventType.DOUBLE_BUTTON_PRESS: - this.window.toggleFullscreen(); + this.player.toggle_play(); break; default: break; @@ -388,6 +370,9 @@ var App = GObject.registerClass({ _onPlayerDragUpdate(gesture, offsetX, offsetY) { + if(!this.dragAllowed || this.activeWindow.isFullscreen) + return; + let { gtk_double_click_distance } = this.player.widget.get_settings(); if ( diff --git a/clapper_src/player.js b/clapper_src/player.js index 971e6c23..fc59430d 100644 --- a/clapper_src/player.js +++ b/clapper_src/player.js @@ -83,15 +83,18 @@ class ClapperPlayer extends GstPlayer.Player this.keyController = new Gtk.EventControllerKey(); this.motionController = new Gtk.EventControllerMotion(); this.scrollController = new Gtk.EventControllerScroll(); + this.clickGesture = new Gtk.GestureClick(); this.dragGesture = new Gtk.GestureDrag(); this.scrollController.set_flags( Gtk.EventControllerScrollFlags.BOTH_AXES ); + this.clickGesture.set_button(0); this.widget.add_controller(this.keyController); this.widget.add_controller(this.motionController); this.widget.add_controller(this.scrollController); + this.widget.add_controller(this.clickGesture); this.widget.add_controller(this.dragGesture); this.connect('state-changed', this._onStateChanged.bind(this)); From 1069f151f0bb3eda7247ba53ca7d13eee37ea2e1 Mon Sep 17 00:00:00 2001 From: Rafostar <40623528+Rafostar@users.noreply.github.com> Date: Wed, 14 Oct 2020 10:57:43 +0200 Subject: [PATCH 15/21] Restore automatic menu hiding --- clapper_src/app.js | 24 +++++-------- clapper_src/revealers.js | 78 +++++++++------------------------------- 2 files changed, 25 insertions(+), 77 deletions(-) diff --git a/clapper_src/app.js b/clapper_src/app.js index 333f4644..93f9e219 100644 --- a/clapper_src/app.js +++ b/clapper_src/app.js @@ -117,7 +117,7 @@ var App = GObject.registerClass({ this.hideControlsTimeout = GLib.timeout_add_seconds(GLib.PRIORITY_DEFAULT, 3, () => { this.hideControlsTimeout = null; - if(this.window.isFullscreen && this.isCursorInPlayer) { + if(this.window.isFullscreen && this.player.motionController.is_pointer) { this.clearTimeout('updateTime'); this.interface.revealControls(false); } @@ -176,17 +176,15 @@ var App = GObject.registerClass({ this.player.clickGesture.connect( 'pressed', this._onPlayerPressed.bind(this) ); -/* - this.player.connectWidget( - 'enter-notify-event', this._onPlayerEnterNotifyEvent.bind(this) - ); - this.player.connectWidget( - 'leave-notify-event', this._onPlayerLeaveNotifyEvent.bind(this) - ); -*/ this.player.keyController.connect( 'key-pressed', this._onPlayerKeyPressed.bind(this) ); + this.player.motionController.connect( + 'enter', this._onPlayerEnter.bind(this) + ); + this.player.motionController.connect( + 'leave', this._onPlayerLeave.bind(this) + ); this.player.motionController.connect( 'motion', this._onPlayerMotion.bind(this) ); @@ -327,19 +325,15 @@ var App = GObject.registerClass({ } } - _onPlayerEnterNotifyEvent(self, event) + _onPlayerEnter(controller, x, y) { - this.isCursorInPlayer = true; - this.setHideCursorTimeout(); if(this.window.isFullscreen) this.setHideControlsTimeout(); } - _onPlayerLeaveNotifyEvent(self, event) + _onPlayerLeave(controller) { - this.isCursorInPlayer = false; - this.clearTimeout('hideCursor'); this.clearTimeout('hideControls'); } diff --git a/clapper_src/revealers.js b/clapper_src/revealers.js index 7eb95e38..73204289 100644 --- a/clapper_src/revealers.js +++ b/clapper_src/revealers.js @@ -26,10 +26,7 @@ class ClapperCustomRevealer extends Gtk.Revealer { if(isReveal) { this._clearTimeout(); - if(!this.visible) - this.show(); - - this._setShowTimeout(); + this.set_visible(isReveal); } else this._setHideTimeout(); @@ -37,68 +34,37 @@ class ClapperCustomRevealer extends Gtk.Revealer this._timedReveal(isReveal, REVEAL_TIME); } - show() - { - if(this.visible) - return; - - // Decreased size = lower CPU usage - this._setTopAlign('START'); - - super.show(); - debug(`showing ${this.revealerName} revealer in drawing area`); - } - - hide() - { - if(!this.visible) - return; - - super.hide(); - debug(`removed ${this.revealerName} revealer from drawing area`); - } - showChild(isReveal) { this._clearTimeout(); - - if(isReveal) - this.show(); - else if(!isReveal) - this.hide(); - + this.set_visible(isReveal); this._timedReveal(isReveal, 0); } + set_visible(isVisible) + { + if(this.visible === isVisible) + return; + + super.set_visible(isVisible); + debug(`${this.revealerName} revealer visible: ${isVisible}`); + } + _timedReveal(isReveal, time) { this.set_transition_duration(time); this.set_reveal_child(isReveal); } - // Drawing revealers on top of video frames - // increases CPU usage, so we hide them + /* Drawing revealers on top of video frames + * increases CPU usage, so we hide them */ _setHideTimeout() { this._clearTimeout(); - this._setTopAlign('FILL'); this._revealerTimeout = GLib.timeout_add(GLib.PRIORITY_DEFAULT, REVEAL_TIME + 20, () => { this._revealerTimeout = null; - this.hide(); - - return GLib.SOURCE_REMOVE; - }); - } - - _setShowTimeout() - { - this._clearTimeout(); - this._setTopAlign('FILL'); - - this._revealerTimeout = GLib.timeout_add(GLib.PRIORITY_DEFAULT, REVEAL_TIME + 20, () => { - this._revealerTimeout = null; - this._setTopAlign('START'); + this.set_visible(false); return GLib.SOURCE_REMOVE; }); @@ -112,17 +78,6 @@ class ClapperCustomRevealer extends Gtk.Revealer GLib.source_remove(this._revealerTimeout); this._revealerTimeout = null; } - - _setTopAlign(align) - { - if( - this.revealerName !== 'top' - || this.valign === Gtk.Align[align] - ) - return; - - this.valign = Gtk.Align[align]; - } }); var RevealerTop = GObject.registerClass( @@ -186,7 +141,6 @@ class ClapperRevealerTop extends CustomRevealer this.revealerGrid.attach(this.endTime, 1, 0, 1, 1); this.set_child(this.revealerGrid); - //this.revealerGrid.show_all(); } setMediaTitle(title) @@ -202,8 +156,8 @@ class ClapperRevealerTop extends CustomRevealer this.currentTime.set_label(now); this.endTime.set_label(end); - // Make sure that next timeout is always run after clock changes, - // by delaying it for additional few milliseconds + /* Make sure that next timeout is always run after clock changes, + * by delaying it for additional few milliseconds */ let nextUpdate = 60002 - parseInt(currTime.get_seconds() * 1000); debug(`updated current time: ${now}`); From d78d3c145056f71c879b629e345113ce00aa065b Mon Sep 17 00:00:00 2001 From: Rafostar <40623528+Rafostar@users.noreply.github.com> Date: Wed, 14 Oct 2020 12:25:46 +0200 Subject: [PATCH 16/21] Set position slider minimal fill to zero --- css/styles.css | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/css/styles.css b/css/styles.css index 8fe8f4ad..267c24de 100644 --- a/css/styles.css +++ b/css/styles.css @@ -15,7 +15,7 @@ scale marks { min-height: 36px; } .osd scale trough highlight { - min-width: 6px; + min-width: 0px; min-height: 6px; } .osd radio { @@ -90,3 +90,6 @@ scale marks { .osd .volumescale marks label { margin-bottom: -8px; } +.osd .volumescale trough highlight { + min-width: 6px; +} From 05c95287237464a8b2ca8c7822469452a42bc022 Mon Sep 17 00:00:00 2001 From: Rafostar <40623528+Rafostar@users.noreply.github.com> Date: Wed, 14 Oct 2020 12:30:57 +0200 Subject: [PATCH 17/21] Auto change focus between player and controls --- clapper_src/revealers.js | 33 ++++++++++++++++++++++++++++++++- 1 file changed, 32 insertions(+), 1 deletion(-) diff --git a/clapper_src/revealers.js b/clapper_src/revealers.js index 73204289..3d52656c 100644 --- a/clapper_src/revealers.js +++ b/clapper_src/revealers.js @@ -44,10 +44,12 @@ class ClapperCustomRevealer extends Gtk.Revealer set_visible(isVisible) { if(this.visible === isVisible) - return; + return false; super.set_visible(isVisible); debug(`${this.revealerName} revealer visible: ${isVisible}`); + + return true; } _timedReveal(isReveal, time) @@ -192,4 +194,33 @@ class ClapperRevealerBottom extends CustomRevealer { this.revealerBox.remove(widget); } + + set_visible(isVisible) + { + let isChange = super.set_visible(isVisible); + if(!isChange) return; + + if(isVisible) { + let box = this.get_first_child(); + if(!box) return; + + let controls = box.get_first_child(); + if(!controls) return; + + let togglePlayButton = controls.get_first_child(); + if(togglePlayButton) { + togglePlayButton.grab_focus(); + debug('focus moved to toggle play button'); + } + } + else { + let parent = this.get_parent(); + let playerWidget = parent.get_first_child(); + + if(playerWidget) { + playerWidget.grab_focus(); + debug('focus moved to player widget'); + } + } + } }); From a20a0c81606cdc4198b758056204dea1cf0bc4d1 Mon Sep 17 00:00:00 2001 From: Rafostar <40623528+Rafostar@users.noreply.github.com> Date: Wed, 14 Oct 2020 12:52:11 +0200 Subject: [PATCH 18/21] Grab player focus only when controls are not visible --- clapper_src/app.js | 2 +- clapper_src/revealers.js | 15 ++++++++------- 2 files changed, 9 insertions(+), 8 deletions(-) diff --git a/clapper_src/app.js b/clapper_src/app.js index 93f9e219..cfd89f48 100644 --- a/clapper_src/app.js +++ b/clapper_src/app.js @@ -294,7 +294,7 @@ var App = GObject.registerClass({ isInhibited = (this.inhibitCookie > 0); } else { - if(!this.inhibitCookie) + //if(!this.inhibitCookie) return; /* Uninhibit seems to be broken as of GTK 3.99.2 diff --git a/clapper_src/revealers.js b/clapper_src/revealers.js index 3d52656c..6af461a6 100644 --- a/clapper_src/revealers.js +++ b/clapper_src/revealers.js @@ -200,6 +200,10 @@ class ClapperRevealerBottom extends CustomRevealer let isChange = super.set_visible(isVisible); if(!isChange) return; + let parent = this.get_parent(); + let playerWidget = parent.get_first_child(); + if(!playerWidget) return; + if(isVisible) { let box = this.get_first_child(); if(!box) return; @@ -212,15 +216,12 @@ class ClapperRevealerBottom extends CustomRevealer togglePlayButton.grab_focus(); debug('focus moved to toggle play button'); } + playerWidget.set_can_focus(false); } else { - let parent = this.get_parent(); - let playerWidget = parent.get_first_child(); - - if(playerWidget) { - playerWidget.grab_focus(); - debug('focus moved to player widget'); - } + playerWidget.set_can_focus(true); + playerWidget.grab_focus(); + debug('focus moved to player widget'); } } }); From ea8226f1d3eb0bd0bc14cce278a261fb66c81ce8 Mon Sep 17 00:00:00 2001 From: Rafostar <40623528+Rafostar@users.noreply.github.com> Date: Wed, 14 Oct 2020 16:45:09 +0200 Subject: [PATCH 19/21] Restore seek on drop behavior --- clapper_src/app.js | 8 +------- clapper_src/controls.js | 25 ++++++++++++------------- 2 files changed, 13 insertions(+), 20 deletions(-) diff --git a/clapper_src/app.js b/clapper_src/app.js index cfd89f48..53a69a8c 100644 --- a/clapper_src/app.js +++ b/clapper_src/app.js @@ -163,13 +163,7 @@ var App = GObject.registerClass({ this.player.widget.width_request = 960; this.player.widget.height_request = 540; -/* - this.player.widget.add_events( - Gdk.EventMask.SCROLL_MASK - | Gdk.EventMask.ENTER_NOTIFY_MASK - | Gdk.EventMask.LEAVE_NOTIFY_MASK - ); -*/ + this.interface.addPlayer(this.player); this.player.connect('state-changed', this._onPlayerStateChanged.bind(this)); diff --git a/clapper_src/controls.js b/clapper_src/controls.js index dc368ffd..96608eb2 100644 --- a/clapper_src/controls.js +++ b/clapper_src/controls.js @@ -203,14 +203,14 @@ var Controls = GObject.registerClass({ this.positionScale.add_css_class('positionscale'); this.positionScale.connect('value-changed', this._onPositionScaleValueChanged.bind(this)); -/* + + /* GTK4 is missing pressed/released signals for GtkRange/GtkScale. + * We cannot add controllers, cause it already has them, so we + * workaround this by observing css classes it currently has */ this.positionScale.connect( - 'button-press-event', this._onPositionScaleButtonPressEvent.bind(this) + 'notify::css-classes', this._onPositionScaleDragging.bind(this) ); - this.positionScale.connect( - 'button-release-event', this._onPositionScaleButtonReleaseEvent.bind(this) - ); -*/ + this.positionAdjustment = this.positionScale.get_adjustment(); this.append(this.positionScale); } @@ -295,15 +295,14 @@ var Controls = GObject.registerClass({ this.elapsedButton.set_label(elapsed); } - _onPositionScaleButtonPressEvent() + _onPositionScaleDragging(scale) { - this.isPositionSeeking = true; - this.emit('position-seeking-changed', this.isPositionSeeking); - } + let isPositionSeeking = scale.has_css_class('dragging'); - _onPositionScaleButtonReleaseEvent() - { - this.isPositionSeeking = false; + if(this.isPositionSeeking === isPositionSeeking) + return; + + this.isPositionSeeking = isPositionSeeking; this.emit('position-seeking-changed', this.isPositionSeeking); } From f8a4465fed44b75bcf98f9cd45c8fb7cf306293d Mon Sep 17 00:00:00 2001 From: Rafostar <40623528+Rafostar@users.noreply.github.com> Date: Wed, 14 Oct 2020 17:17:00 +0200 Subject: [PATCH 20/21] Add required GTK4 and GStreamer versions to pkgs --- pkgs/arch/PKGBUILD | 8 ++++---- pkgs/deb/debian/control | 6 +++--- pkgs/rpm/clapper.spec | 18 ++++++++++-------- 3 files changed, 17 insertions(+), 15 deletions(-) diff --git a/pkgs/arch/PKGBUILD b/pkgs/arch/PKGBUILD index cfe5f321..c70ad9f2 100644 --- a/pkgs/arch/PKGBUILD +++ b/pkgs/arch/PKGBUILD @@ -27,13 +27,13 @@ arch=(any) url="https://github.com/Rafostar/clapper" license=("GPL-3.0") depends=( - "gtk3>=3.19.4" + "gtk4>=3.99.2" "hicolor-icon-theme" "gjs" "gst-plugins-base-libs" "gst-plugins-good" - "gst-plugins-bad-libs>=1.16.0" - "gst-plugin-gtk" + "gst-plugins-bad-libs>=1.18.0" + "gst-plugin-gtk4" ) makedepends=( "meson>=0.50" @@ -44,7 +44,7 @@ optdepends=( "gst-libav: Popular video decoders" "gstreamer-vaapi: Intel/AMD video acceleration" ) -source=("${pkgname%-git}::git+https://github.com/Rafostar/${pkgname%-git}.git#branch=master") +source=("${pkgname%-git}::git+https://github.com/Rafostar/${pkgname%-git}.git") provides=("${pkgname%-git}") replaces=("${pkgname%-git}") conflicts=("${pkgname%-git}") diff --git a/pkgs/deb/debian/control b/pkgs/deb/debian/control index ddc16735..a8e5ceeb 100644 --- a/pkgs/deb/debian/control +++ b/pkgs/deb/debian/control @@ -14,14 +14,14 @@ Build-Depends: debhelper (>= 10), Package: clapper Architecture: all Depends: gjs (>= 1.50), - gir1.2-gtk-3.0 (>= 3.19), + gir1.2-gtk-4.0 (>= 3.99.2), hicolor-icon-theme, libgstreamer1.0-0, gstreamer1.0-plugins-base, gstreamer1.0-plugins-good, - gstreamer1.0-plugins-bad (>= 1.16), + gstreamer1.0-plugins-bad (>= 1.18), gstreamer1.0-gl, - gstreamer1.0-gtk3 + gstreamer1.0-gtk4 Recommends: gstreamer1.0-libav, gstreamer1.0-pulseaudio Suggests: gstreamer-plugins-ugly, diff --git a/pkgs/rpm/clapper.spec b/pkgs/rpm/clapper.spec index c002bee0..4ce0e835 100644 --- a/pkgs/rpm/clapper.spec +++ b/pkgs/rpm/clapper.spec @@ -19,8 +19,8 @@ %global appname com.github.rafostar.Clapper -%global gst_version 1.16.0 -%global gtk3_version 3.19.4 +%global gst_version 1.18.0 +%global gtk4_version 3.99.2 Name: clapper Version: 0.0.0 @@ -39,7 +39,7 @@ BuildRequires: desktop-file-utils BuildRequires: hicolor-icon-theme Requires: gjs -Requires: gtk3 >= %{gtk3_version} +Requires: gtk4 >= %{gtk4_version} Requires: hicolor-icon-theme %if 0%{?suse_version} @@ -51,7 +51,7 @@ BuildRequires: update-desktop-files Requires: gstreamer Requires: gstreamer-plugins-base Requires: gstreamer-plugins-good -Requires: gstreamer-plugins-good-gtk +Requires: gstreamer-plugins-good-gtk4 Requires: gstreamer-plugins-bad Requires: libgstplayer-1_0-0 >= %{gst_version} @@ -62,14 +62,12 @@ Recommends: gstreamer-plugins-libav Suggests: gstreamer-plugins-ugly # Intel/AMD video acceleration Suggests: gstreamer-plugins-vaapi -%endif - -%if 0%{?fedora} || 0%{?rhel_version} || 0%{?centos_version} +%else BuildRequires: glibc-all-langpacks Requires: gstreamer1 Requires: gstreamer1-plugins-base Requires: gstreamer1-plugins-good -Requires: gstreamer1-plugins-good-gtk +Requires: gstreamer1-plugins-good-gtk4 # Contains GstPlayer lib Requires: gstreamer1-plugins-bad-free >= %{gst_version} @@ -113,7 +111,11 @@ desktop-file-validate %{buildroot}%{_datadir}/applications/*.desktop %{_datadir}/mime/packages/%{appname}.xml %changelog +* Wed Oct 14 2020 Rafostar - 0.0.0-3 +- Update to GTK4 + * Sat Sep 19 22:02:00 CEST 2020 sp1rit - 0.0.0-2 - Added suse_update_desktop_file macro for SuSE packages + * Fri Sep 18 2020 Rafostar - 0.0.0-1 - Initial package From 8fb41b41b4e5fd8abd4234b724f231109eb49d20 Mon Sep 17 00:00:00 2001 From: Rafostar <40623528+Rafostar@users.noreply.github.com> Date: Wed, 14 Oct 2020 18:40:23 +0200 Subject: [PATCH 21/21] Update README.md --- README.md | 132 ++++++++++++++++++++++++++++++++---------------------- 1 file changed, 78 insertions(+), 54 deletions(-) diff --git a/README.md b/README.md index b84ed129..b006da0a 100644 --- a/README.md +++ b/README.md @@ -28,10 +28,11 @@ Using hardware acceleration is highly recommended. As stated in `GStreamer` wiki In the case of OpenGL based elements, the buffers have the GstVideoGLTextureUploadMeta meta, which efficiently copies the content of the VA-API surface into a GL texture. ``` -Clapper uses `OpenGL` based sinks, so when `VA-API` is available, both CPU and RAM usage is much lower. +Clapper uses `OpenGL` based sinks, so when `VA-API` is available, both CPU and RAM usage is much lower. Especially if you have `gst-plugins-bad` 1.18+ with new `vah264dec` decoder which shares a single GL context with Clapper and uses DRM connection. If you have an AMD/Intel GPU, I highly recommend this new decoder. -To use `VA-API` make sure you have `gstreamer1-vaapi` installed. Verify with: +To use `VA-API` with H.264 videos, make sure you have `gst-plugins-bad` 1.18+. For other codecs additionally install `gstreamer1-vaapi`. Verify with: ```shell +gst-inspect-1.0 vah264dec gst-inspect-1.0 vaapi ``` On some older GPUs you might need to export `GST_VAAPI_ALL_DRIVERS=1` environment variable. @@ -40,11 +41,13 @@ Other acceleration methods (supported by `GStreamer`) should also work, but I ha ## Requirements -Clapper uses `GStreamer` bindings from `GI` repository, so if your distro ships them as separate package, they must be installed first. +Clapper uses GTK4 along with `GStreamer` bindings from `GI` repository, so if your distro ships them as separate package, they must be installed first. Additionally Clapper requires these `GStreamer` elements: -* [gtkglsink](https://gstreamer.freedesktop.org/documentation/gtk/gtkglsink.html) +* [gtk4glsink](https://gstreamer.freedesktop.org/documentation/gtk/gtkglsink.html) * [glsinkbin](https://gstreamer.freedesktop.org/documentation/opengl/glsinkbin.html) +**Attention:** `gtk4glsink` is my own port of current GStreamer `gtkglsink` to GTK4. The element is not part of GStreamer yet (pending review). Fedora package is available in my OBS repository. It will be installed along with Clapper if you add my repo to `dnf` package manager. Otherwise you might want to build it yourself from [source code](https://gitlab.freedesktop.org/Rafostar/gst-plugins-good/-/tree/GTK4) of my gstreamer GTK4 branch. + Other required plugins (codecs) depend on video format. Recommended additional packages you should install manually via package manager: @@ -53,69 +56,90 @@ Recommended additional packages you should install manually via package manager: Please note that packages naming varies by distro. -## Installation -Run in terminal: -```shell -meson builddir --prefix=/usr/local -sudo meson install -C builddir -``` - -Additional GStreamer elements installation: -
- Fedora - -Enable RPM Fusion and run: -```shell -sudo dnf install \ - gstreamer1-plugins-base \ - gstreamer1-plugins-good-gtk \ - gstreamer1-libav \ - gstreamer1-vaapi -``` -
- -
- openSUSE - -```shell -sudo zypper install \ - gstreamer-plugins-base \ - gstreamer-plugins-good \ - gstreamer-plugins-libav \ - gstreamer-plugins-vaapi -``` -
- -
- Arch Linux - -```shell -sudo pacman -S \ - gst-plugins-base \ - gst-plugin-gtk \ - gst-libav \ - gstreamer-vaapi -``` -
- ## Packages The [pkgs folder](https://github.com/Rafostar/clapper/tree/master/pkgs) in this repository contains build scripts for various package formats. You can use them to build package yourself or download one of pre-built packages:
- Fedora, openSUSE & SLE (rpm) + Debian, Fedora, openSUSE & Ubuntu -Pre-built packages are available here:
-[software.opensuse.org//download.html?project=home:sp1rit&package=clapper](https://software.opensuse.org//download.html?project=home%3Asp1rit&package=clapper) ([See status](https://build.opensuse.org/package/show/home:sp1rit/clapper)) +Pre-built packages are available in [my repo](https://software.opensuse.org//download.html?project=home%3ARafostar&package=clapper) ([see status](https://build.opensuse.org/package/show/home:Rafostar/clapper))
-Arch Linux +Arch Linux -You can get clapper from the AUR: [clapper-git](https://aur.archlinux.org/packages/clapper-git), or +You can get Clapper from the AUR: [clapper-git](https://aur.archlinux.org/packages/clapper-git), or ```shell cd pkgs/arch makepkg -si ```
+## Installation from source code +Run in terminal: +```shell +meson builddir --prefix=/usr/local +sudo meson install -C builddir +``` + +GStreamer elements installation: +
+ Debian/Ubuntu + +```shell +sudo apt install \ + gstreamer1.0-plugins-base \ + gstreamer1.0-plugins-good \ + gstreamer1.0-plugins-bad \ + gstreamer1.0-gl \ + gstreamer1.0-gtk4 \ + gstreamer1.0-libav \ + gstreamer-vaapi +``` +
+ +
+ Fedora + +Enable RPM Fusion and run: +```shell +sudo dnf install \ + gstreamer1-plugins-base \ + gstreamer1-plugins-good \ + gstreamer1-plugins-good-gtk4 \ + gstreamer1-plugins-bad-free \ + gstreamer1-plugins-bad-free-extras \ + gstreamer1-libav \ + gstreamer1-vaapi +``` +
+ +
+ openSUSE + +```shell +sudo zypper install \ + gstreamer-plugins-base \ + gstreamer-plugins-good \ + gstreamer-plugins-good-gtk4 \ + gstreamer-plugins-bad \ + gstreamer-plugins-libav \ + gstreamer-plugins-vaapi +``` +
+ +
+ Arch Linux + +```shell +sudo pacman -S \ + gst-plugins-base \ + gst-plugins-good \ + gst-plugin-gtk4 \ + gst-plugins-bad-libs \ + gst-libav \ + gstreamer-vaapi +``` +
+ ## Special Thanks Many thanks to [sp1ritCS](https://github.com/sp1ritCS) for creating and maintaining package build files.