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;