From 62573d3a88f18c6edc4dbd265a34fc65bc26be3d Mon Sep 17 00:00:00 2001
From: Rafostar <40623528+Rafostar@users.noreply.github.com>
Date: Fri, 11 Dec 2020 14:55:50 +0100
Subject: [PATCH 01/26] Move main.js to source files dir
---
bin/com.github.rafostar.Clapper.in | 2 +-
main.js => clapper_src/main.js | 0
meson.build | 1 -
3 files changed, 1 insertion(+), 2 deletions(-)
rename main.js => clapper_src/main.js (100%)
diff --git a/bin/com.github.rafostar.Clapper.in b/bin/com.github.rafostar.Clapper.in
index b62c9a2d..78cd7495 100644
--- a/bin/com.github.rafostar.Clapper.in
+++ b/bin/com.github.rafostar.Clapper.in
@@ -9,4 +9,4 @@ Package.init({
libdir: '@libdir@',
datadir: '@datadir@',
});
-Package.run(imports.main);
+Package.run(imports.clapper_src.main);
diff --git a/main.js b/clapper_src/main.js
similarity index 100%
rename from main.js
rename to clapper_src/main.js
diff --git a/meson.build b/meson.build
index beee3093..52327a32 100644
--- a/meson.build
+++ b/meson.build
@@ -23,6 +23,5 @@ installdir = join_paths(get_option('prefix'), 'share', meson.project_name())
install_subdir('clapper_src', install_dir : installdir)
install_subdir('css', install_dir : installdir)
install_subdir('ui', install_dir : installdir)
-install_data('main.js', install_dir : installdir)
meson.add_install_script('build-aux/meson/postinstall.py')
From 083445a830cef0a7385230c1ce171481dd75486f Mon Sep 17 00:00:00 2001
From: Rafostar <40623528+Rafostar@users.noreply.github.com>
Date: Fri, 11 Dec 2020 15:22:35 +0100
Subject: [PATCH 02/26] Split header bar source file into two
This allows creating another headerbar with different functionality from the same source code.
---
clapper_src/headerbar.js | 108 ++---------------------------
clapper_src/headerbarBase.js | 129 +++++++++++++++++++++++++++++++++++
2 files changed, 134 insertions(+), 103 deletions(-)
create mode 100644 clapper_src/headerbarBase.js
diff --git a/clapper_src/headerbar.js b/clapper_src/headerbar.js
index 9060b80b..c300b9ba 100644
--- a/clapper_src/headerbar.js
+++ b/clapper_src/headerbar.js
@@ -1,94 +1,17 @@
-const { GObject, Gtk, Pango } = imports.gi;
+const { GObject } = imports.gi;
+const { HeaderBarBase } = imports.clapper_src.headerbarBase;
var HeaderBar = GObject.registerClass(
-class ClapperHeaderBar extends Gtk.HeaderBar
+class ClapperHeaderBar extends HeaderBarBase
{
- _init(window, models)
+ _init(window)
{
- super._init({
- can_focus: false,
- });
- this.add_css_class('noborder');
+ super._init(window);
- this.set_title_widget(this._createWidgetForWindow(window));
let clapperWidget = window.get_child();
-
- let addMediaButton = new Gtk.MenuButton({
- icon_name: 'list-add-symbolic',
- });
- let addMediaPopover = new HeaderBarPopover(models.addMediaMenu);
- addMediaButton.set_popover(addMediaPopover);
- this.pack_start(addMediaButton);
-
- let openMenuButton = new Gtk.MenuButton({
- icon_name: 'open-menu-symbolic',
- });
- let settingsPopover = new HeaderBarPopover(models.settingsMenu);
- openMenuButton.set_popover(settingsPopover);
- this.pack_end(openMenuButton);
-
- let buttonsBox = new Gtk.Box({
- orientation: Gtk.Orientation.HORIZONTAL,
- });
- buttonsBox.add_css_class('linked');
-
- let floatButton = new Gtk.Button({
- icon_name: 'preferences-desktop-remote-desktop-symbolic',
- });
- floatButton.connect('clicked', this._onFloatButtonClicked.bind(this));
clapperWidget.controls.unfloatButton.bind_property('visible', this, 'visible',
GObject.BindingFlags.INVERT_BOOLEAN
);
- buttonsBox.append(floatButton);
-
- let fullscreenButton = new Gtk.Button({
- icon_name: 'view-fullscreen-symbolic',
- });
- fullscreenButton.connect('clicked', this._onFullscreenButtonClicked.bind(this));
-
- buttonsBox.append(fullscreenButton);
- this.pack_end(buttonsBox);
- }
-
- updateHeaderBar(title, subtitle)
- {
- 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;
}
_onFloatButtonClicked()
@@ -103,24 +26,3 @@ class ClapperHeaderBar extends Gtk.HeaderBar
window.fullscreen();
}
});
-
-var HeaderBarPopover = GObject.registerClass(
-class ClapperHeaderBarPopover extends Gtk.PopoverMenu
-{
- _init(model)
- {
- super._init({
- menu_model: model,
- });
-
- this.connect('closed', this._onClosed.bind(this));
- }
-
- _onClosed()
- {
- let root = this.get_root();
- let clapperWidget = root.get_child();
-
- clapperWidget.player.widget.grab_focus();
- }
-});
diff --git a/clapper_src/headerbarBase.js b/clapper_src/headerbarBase.js
new file mode 100644
index 00000000..09d32b40
--- /dev/null
+++ b/clapper_src/headerbarBase.js
@@ -0,0 +1,129 @@
+const { GObject, Gtk, Pango } = imports.gi;
+const Misc = imports.clapper_src.misc;
+
+var HeaderBarBase = GObject.registerClass(
+class ClapperHeaderBarBase extends Gtk.HeaderBar
+{
+ _init(window)
+ {
+ super._init({
+ can_focus: false,
+ });
+
+ let clapperPath = Misc.getClapperPath();
+ let uiBuilder = Gtk.Builder.new_from_file(
+ `${clapperPath}/ui/clapper.ui`
+ );
+ let models = {
+ addMediaMenu: uiBuilder.get_object('addMediaMenu'),
+ settingsMenu: uiBuilder.get_object('settingsMenu'),
+ };
+
+ this.add_css_class('noborder');
+ this.set_title_widget(this._createWidgetForWindow(window));
+
+ let addMediaButton = new Gtk.MenuButton({
+ icon_name: 'list-add-symbolic',
+ });
+ let addMediaPopover = new HeaderBarPopover(models.addMediaMenu);
+ addMediaButton.set_popover(addMediaPopover);
+ this.pack_start(addMediaButton);
+
+ let openMenuButton = new Gtk.MenuButton({
+ icon_name: 'open-menu-symbolic',
+ });
+ let settingsPopover = new HeaderBarPopover(models.settingsMenu);
+ openMenuButton.set_popover(settingsPopover);
+ this.pack_end(openMenuButton);
+
+ let buttonsBox = new Gtk.Box({
+ orientation: Gtk.Orientation.HORIZONTAL,
+ });
+ buttonsBox.add_css_class('linked');
+
+ let floatButton = new Gtk.Button({
+ icon_name: 'preferences-desktop-remote-desktop-symbolic',
+ });
+ floatButton.connect('clicked', this._onFloatButtonClicked.bind(this));
+ buttonsBox.append(floatButton);
+
+ let fullscreenButton = new Gtk.Button({
+ icon_name: 'view-fullscreen-symbolic',
+ });
+ fullscreenButton.connect('clicked', this._onFullscreenButtonClicked.bind(this));
+
+ buttonsBox.append(fullscreenButton);
+ this.pack_end(buttonsBox);
+ }
+
+ updateHeaderBar(title, subtitle)
+ {
+ 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;
+ }
+
+ _onFloatButtonClicked()
+ {
+ }
+
+ _onFullscreenButtonClicked()
+ {
+ }
+});
+
+var HeaderBarPopover = GObject.registerClass(
+class ClapperHeaderBarPopover extends Gtk.PopoverMenu
+{
+ _init(model)
+ {
+ super._init({
+ menu_model: model,
+ });
+
+ this.connect('closed', this._onClosed.bind(this));
+ }
+
+ _onClosed()
+ {
+ let root = this.get_root();
+ let clapperWidget = root.get_child();
+
+ if(clapperWidget && clapperWidget.player)
+ clapperWidget.player.widget.grab_focus();
+ }
+});
From 6315669933b2e5e806f80bae3129a9f798609bd0 Mon Sep 17 00:00:00 2001
From: Rafostar <40623528+Rafostar@users.noreply.github.com>
Date: Fri, 11 Dec 2020 15:32:05 +0100
Subject: [PATCH 03/26] Split app source file into two
This allows creating different app from the same source code.
---
clapper_src/app.js | 119 ++++-------------------------------------
clapper_src/appBase.js | 112 ++++++++++++++++++++++++++++++++++++++
2 files changed, 123 insertions(+), 108 deletions(-)
create mode 100644 clapper_src/appBase.js
diff --git a/clapper_src/app.js b/clapper_src/app.js
index c7d38900..575b3808 100644
--- a/clapper_src/app.js
+++ b/clapper_src/app.js
@@ -1,136 +1,39 @@
-const { Gio, GObject, Gtk } = imports.gi;
+const { GObject } = imports.gi;
+const { AppBase } = imports.clapper_src.appBase;
const { HeaderBar } = imports.clapper_src.headerbar;
const { Widget } = imports.clapper_src.widget;
const Debug = imports.clapper_src.debug;
-const Menu = imports.clapper_src.menu;
-const Misc = imports.clapper_src.misc;
let { debug } = Debug;
-let { settings } = Misc;
var App = GObject.registerClass(
-class ClapperApp extends Gtk.Application
+class ClapperApp extends AppBase
{
- _init(opts)
- {
- super._init({
- application_id: Misc.appId
- });
-
- let defaults = {
- playlist: [],
- };
- Object.assign(this, defaults, opts);
-
- this.doneFirstActivate = false;
- }
-
vfunc_startup()
{
super.vfunc_startup();
- let window = new Gtk.ApplicationWindow({
- application: this,
- title: Misc.appName,
- });
- window.isClapperApp = true;
- window.add_css_class('nobackground');
-
- if(!settings.get_boolean('render-shadows'))
- window.add_css_class('gpufriendly');
-
- if(
- settings.get_boolean('dark-theme')
- && settings.get_boolean('brighter-sliders')
- )
- window.add_css_class('brightscale');
-
- for(let action in Menu.actions) {
- let simpleAction = new Gio.SimpleAction({
- name: action
- });
- simpleAction.connect(
- 'activate', () => Menu.actions[action](this.active_window)
- );
- this.add_action(simpleAction);
- }
+ this.active_window.isClapperApp = true;
+ this.active_window.add_css_class('nobackground');
let clapperWidget = new Widget();
- window.set_child(clapperWidget);
+ this.active_window.set_child(clapperWidget);
+
+ let headerBar = new HeaderBar(this.active_window);
+ this.active_window.set_titlebar(headerBar);
let size = clapperWidget.windowSize;
- window.set_default_size(size[0], size[1]);
+ this.active_window.set_default_size(size[0], size[1]);
debug(`restored window size: ${size[0]}x${size[1]}`);
-
- let clapperPath = Misc.getClapperPath();
- let uiBuilder = Gtk.Builder.new_from_file(
- `${clapperPath}/ui/clapper.ui`
- );
- let models = {
- addMediaMenu: uiBuilder.get_object('addMediaMenu'),
- settingsMenu: uiBuilder.get_object('settingsMenu'),
- };
- let headerBar = new HeaderBar(window, models);
- window.set_titlebar(headerBar);
- }
-
- vfunc_activate()
- {
- super.vfunc_activate();
-
- if(!this.doneFirstActivate)
- this._onFirstActivate();
-
- this.active_window.present();
- }
-
- run(arr)
- {
- super.run(arr || []);
- }
-
- _onFirstActivate()
- {
- let gtkSettings = Gtk.Settings.get_default();
- settings.bind(
- 'dark-theme', gtkSettings,
- 'gtk-application-prefer-dark-theme',
- Gio.SettingsBindFlags.GET
- );
- this._onThemeChanged(gtkSettings);
- gtkSettings.connect('notify::gtk-theme-name', this._onThemeChanged.bind(this));
-
- this.windowShowSignal = this.active_window.connect(
- 'show', this._onWindowShow.bind(this)
- );
-
- this.doneFirstActivate = true;
}
_onWindowShow(window)
{
- window.disconnect(this.windowShowSignal);
- this.windowShowSignal = null;
+ super._onWindowShow(window);
if(this.playlist.length) {
let { player } = window.get_child();
player.set_playlist(this.playlist);
}
}
-
- _onThemeChanged(gtkSettings)
- {
- const theme = gtkSettings.gtk_theme_name;
- debug(`user selected theme: ${theme}`);
-
- if(!theme.endsWith('-dark'))
- return;
-
- /* We need to request a default theme with optional dark variant
- to make the "gtk_application_prefer_dark_theme" setting work */
- const parsedTheme = theme.substring(0, theme.lastIndexOf('-'));
-
- gtkSettings.gtk_theme_name = parsedTheme;
- debug(`set theme: ${parsedTheme}`);
- }
});
diff --git a/clapper_src/appBase.js b/clapper_src/appBase.js
new file mode 100644
index 00000000..b2224612
--- /dev/null
+++ b/clapper_src/appBase.js
@@ -0,0 +1,112 @@
+const { Gio, GObject, Gtk } = imports.gi;
+const Debug = imports.clapper_src.debug;
+const Menu = imports.clapper_src.menu;
+const Misc = imports.clapper_src.misc;
+
+let { debug } = Debug;
+let { settings } = Misc;
+
+var AppBase = GObject.registerClass(
+class ClapperAppBase extends Gtk.Application
+{
+ _init(opts)
+ {
+ opts = opts || {};
+
+ let defaults = {
+ idPostfix: '',
+ playlist: [],
+ };
+ Object.assign(this, defaults, opts);
+
+ super._init({
+ application_id: Misc.appId + this.idPostfix
+ });
+
+ this.doneFirstActivate = false;
+ }
+
+ vfunc_startup()
+ {
+ super.vfunc_startup();
+
+ let window = new Gtk.ApplicationWindow({
+ application: this,
+ title: Misc.appName,
+ });
+
+ if(!settings.get_boolean('render-shadows'))
+ window.add_css_class('gpufriendly');
+
+ if(
+ settings.get_boolean('dark-theme')
+ && settings.get_boolean('brighter-sliders')
+ )
+ window.add_css_class('brightscale');
+
+ for(let action in Menu.actions) {
+ let simpleAction = new Gio.SimpleAction({
+ name: action
+ });
+ simpleAction.connect(
+ 'activate', () => Menu.actions[action](this.active_window)
+ );
+ this.add_action(simpleAction);
+ }
+ }
+
+ vfunc_activate()
+ {
+ super.vfunc_activate();
+
+ if(!this.doneFirstActivate)
+ this._onFirstActivate();
+
+ this.active_window.present();
+ }
+
+ run(arr)
+ {
+ super.run(arr || []);
+ }
+
+ _onFirstActivate()
+ {
+ let gtkSettings = Gtk.Settings.get_default();
+ settings.bind(
+ 'dark-theme', gtkSettings,
+ 'gtk-application-prefer-dark-theme',
+ Gio.SettingsBindFlags.GET
+ );
+ this._onThemeChanged(gtkSettings);
+ gtkSettings.connect('notify::gtk-theme-name', this._onThemeChanged.bind(this));
+
+ this.windowShowSignal = this.active_window.connect(
+ 'show', this._onWindowShow.bind(this)
+ );
+
+ this.doneFirstActivate = true;
+ }
+
+ _onWindowShow(window)
+ {
+ window.disconnect(this.windowShowSignal);
+ this.windowShowSignal = null;
+ }
+
+ _onThemeChanged(gtkSettings)
+ {
+ const theme = gtkSettings.gtk_theme_name;
+ debug(`user selected theme: ${theme}`);
+
+ if(!theme.endsWith('-dark'))
+ return;
+
+ /* We need to request a default theme with optional dark variant
+ to make the "gtk_application_prefer_dark_theme" setting work */
+ const parsedTheme = theme.substring(0, theme.lastIndexOf('-'));
+
+ gtkSettings.gtk_theme_name = parsedTheme;
+ debug(`set theme: ${parsedTheme}`);
+ }
+});
From 4875a31be4521674d1e3a06d05b324da5274adcf Mon Sep 17 00:00:00 2001
From: Rafostar <40623528+Rafostar@users.noreply.github.com>
Date: Fri, 11 Dec 2020 15:38:25 +0100
Subject: [PATCH 04/26] Add initial ClapperRemote app
---
bin/com.github.rafostar.ClapperRemote.in | 12 ++++++++++++
bin/meson.build | 20 ++++++++++++--------
clapper_src/appRemote.js | 17 +++++++++++++++++
clapper_src/mainRemote.js | 17 +++++++++++++++++
4 files changed, 58 insertions(+), 8 deletions(-)
create mode 100644 bin/com.github.rafostar.ClapperRemote.in
create mode 100644 clapper_src/appRemote.js
create mode 100644 clapper_src/mainRemote.js
diff --git a/bin/com.github.rafostar.ClapperRemote.in b/bin/com.github.rafostar.ClapperRemote.in
new file mode 100644
index 00000000..e567a7b9
--- /dev/null
+++ b/bin/com.github.rafostar.ClapperRemote.in
@@ -0,0 +1,12 @@
+#!@GJS@
+
+const Package = imports.package;
+
+Package.init({
+ name: '@PACKAGE_NAME@',
+ version: '@PACKAGE_VERSION@',
+ prefix: '@prefix@',
+ libdir: '@libdir@',
+ datadir: '@datadir@',
+});
+Package.run(imports.clapper_src.mainRemote);
diff --git a/bin/meson.build b/bin/meson.build
index 2cdf501d..6a3aec8e 100644
--- a/bin/meson.build
+++ b/bin/meson.build
@@ -6,11 +6,15 @@ bin_conf.set('prefix', get_option('prefix'))
bin_conf.set('libdir', join_paths(get_option('prefix'), get_option('libdir')))
bin_conf.set('datadir', join_paths(get_option('prefix'), get_option('datadir')))
-configure_file(
- input: 'com.github.rafostar.Clapper.in',
- output: 'com.github.rafostar.Clapper',
- configuration: bin_conf,
- install: true,
- install_dir: get_option('bindir'),
- install_mode: 'rwxr-xr-x'
-)
+clapper_apps = [ '', 'Remote' ]
+
+foreach id_postfix : clapper_apps
+ configure_file(
+ input: 'com.github.rafostar.Clapper' + id_postfix + '.in',
+ output: 'com.github.rafostar.Clapper' + id_postfix,
+ configuration: bin_conf,
+ install: true,
+ install_dir: get_option('bindir'),
+ install_mode: 'rwxr-xr-x'
+ )
+endforeach
diff --git a/clapper_src/appRemote.js b/clapper_src/appRemote.js
new file mode 100644
index 00000000..ae34f9c2
--- /dev/null
+++ b/clapper_src/appRemote.js
@@ -0,0 +1,17 @@
+const { GObject } = imports.gi;
+const { AppBase } = imports.clapper_src.appBase;
+const { HeaderBarBase } = imports.clapper_src.headerbarBase;
+
+var AppRemote = GObject.registerClass(
+class ClapperAppRemote extends AppBase
+{
+ vfunc_startup()
+ {
+ super.vfunc_startup();
+
+ let headerBar = new HeaderBarBase(this.active_window);
+ this.active_window.set_titlebar(headerBar);
+
+ this.active_window.maximize();
+ }
+});
diff --git a/clapper_src/mainRemote.js b/clapper_src/mainRemote.js
new file mode 100644
index 00000000..6321f769
--- /dev/null
+++ b/clapper_src/mainRemote.js
@@ -0,0 +1,17 @@
+imports.gi.versions.Gdk = '4.0';
+imports.gi.versions.Gtk = '4.0';
+
+const { AppRemote } = imports.clapper_src.appRemote;
+const Misc = imports.clapper_src.misc;
+
+const opts = {
+ idPostfix: 'Remote',
+};
+
+Misc.clapperPath = pkg.datadir + '/' +
+ pkg.name.substring(0, pkg.name.lastIndexOf(opts.idPostfix));
+
+function main()
+{
+ new AppRemote(opts).run();
+}
From 26f8b6994eedcb668475b931469d79d3329e1650 Mon Sep 17 00:00:00 2001
From: Rafostar <40623528+Rafostar@users.noreply.github.com>
Date: Fri, 11 Dec 2020 22:06:00 +0100
Subject: [PATCH 05/26] Add WebSocket server
---
clapper_src/webserver.js | 158 +++++++++++++++++++++++++++++++++++++++
1 file changed, 158 insertions(+)
create mode 100644 clapper_src/webserver.js
diff --git a/clapper_src/webserver.js b/clapper_src/webserver.js
new file mode 100644
index 00000000..2548003a
--- /dev/null
+++ b/clapper_src/webserver.js
@@ -0,0 +1,158 @@
+const { Soup, GObject } = imports.gi;
+const ByteArray = imports.byteArray;
+const Debug = imports.clapper_src.debug;
+
+let { debug } = Debug;
+
+var WebServer = GObject.registerClass({
+ Signals: {
+ 'websocket-data': {
+ flags: GObject.SignalFlags.RUN_FIRST,
+ param_types: [
+ GObject.TYPE_STRING,
+ GObject.TYPE_INT || GObject.TYPE_STRING
+ ]
+ }
+ }
+}, class ClapperWebServer extends Soup.Server
+{
+ _init(port)
+ {
+ super._init();
+
+ this.isListening = false;
+ this.listeningPort = null;
+ this.wsConns = [];
+
+ if(port)
+ this.setListeningPort(port);
+ }
+
+ setListeningPort(port)
+ {
+ if(!port)
+ return;
+
+ const wasListening = this.isListening;
+
+ if(wasListening)
+ this.stopListening();
+
+ this.listeningPort = port;
+
+ if(wasListening)
+ this.startListening();
+ }
+
+ startListening()
+ {
+ if(this.isListening || !this.listeningPort)
+ return;
+
+ let isListening = false;
+
+ this.add_handler('/', this._onDefaultAccess.bind(this));
+ this.add_websocket_handler('/websocket', null, null, this._onWsConnection.bind(this));
+
+ try {
+ isListening = this.listen_local(this.listeningPort, Soup.ServerListenOptions.IPV4_ONLY);
+ }
+ catch(err) {
+ debug(err);
+ }
+
+ if(isListening) {
+ const uris = this.get_uris();
+ const usedPort = uris[0].get_port();
+ debug(`WebSocket server listening on port: ${usedPort}`);
+ }
+ else {
+ debug(new Error('WebSocket server could not start listening'));
+ this._closeCleanup();
+ }
+
+ this.isListening = isListening;
+ }
+
+ stopListening()
+ {
+ if(!this.isListening)
+ return;
+
+ this._closeCleanup();
+ this.disconnect();
+
+ this.isListening = false;
+ this.listeningPort = null;
+ }
+
+ sendMessage(data)
+ {
+ for(const connection of this.wsConns) {
+ if(connection.state !== Soup.WebsocketState.OPEN)
+ continue;
+
+ connection.send_text(JSON.stringify(data));
+ }
+ }
+
+ _closeCleanup()
+ {
+ while(this.wsConns.length) {
+ const connection = this.wsConns.pop();
+
+ if(connection.state !== Soup.WebsocketState.OPEN)
+ continue;
+
+ connection.close(Soup.WebsocketCloseCode.NORMAL, null);
+ }
+
+ this.remove_handler('/websocket');
+ this.remove_handler('/');
+ }
+
+ _onWsConnection(server, connection)
+ {
+ debug('new WebSocket connection');
+
+ connection.connect('message', this._onWsMessage.bind(this));
+ connection.connect('closed', this._onWsClosed.bind(this));
+
+ this.wsConns.push(connection);
+ debug(`total WebSocket connections: ${this.wsConns.length}`);
+ }
+
+ _onWsMessage(connection, dataType, bytes)
+ {
+ if(dataType !== Soup.WebsocketDataType.TEXT)
+ return debug('ignoring non-text WebSocket message');
+
+ const msg = bytes.get_data();
+ let parsedMsg = null;
+
+ try {
+ parsedMsg = JSON.parse(ByteArray.toString(msg));
+ }
+ catch(err) {
+ debug(err);
+ }
+
+ if(!parsedMsg || !parsedMsg.action)
+ return debug('no "action" in parsed WebSocket message');
+
+ this.emit('websocket-data', parsedMsg.action, parsedMsg.value || 0);
+ }
+
+ _onWsClosed(connection)
+ {
+ debug('closed WebSocket connection');
+
+ this.wsConns = this.wsConns.filter(conn => conn !== connection);
+ debug(`remaining WebSocket connections: ${this.wsConns.length}`);
+ }
+
+ _onDefaultAccess(server, msg)
+ {
+ msg.status_code = 404;
+ }
+});
From d5d5aa9bac05b46cc026d4f077359a8f3815e5b5 Mon Sep 17 00:00:00 2001
From: Rafostar <40623528+Rafostar@users.noreply.github.com>
Date: Fri, 11 Dec 2020 23:38:49 +0100
Subject: [PATCH 06/26] Integrate basic web server functionality into player
---
clapper_src/player.js | 16 +++++++++
clapper_src/playerBase.js | 34 ++++++++++++++++++++
data/com.github.rafostar.Clapper.gschema.xml | 10 ++++++
3 files changed, 60 insertions(+)
diff --git a/clapper_src/player.js b/clapper_src/player.js
index 776ed62c..be06fddc 100644
--- a/clapper_src/player.js
+++ b/clapper_src/player.js
@@ -639,6 +639,22 @@ class ClapperPlayer extends PlayerBase
return true;
}
+ _onWsData(server, action, value)
+ {
+ switch(action) {
+ case 'toggle-play':
+ this.toggle_play();
+ break;
+ case 'play':
+ case 'pause':
+ this[action]();
+ break;
+ default:
+ super._onWsData(server, action, value);
+ break;
+ }
+ }
+
_onCloseRequest(window)
{
this._performCloseCleanup(window);
diff --git a/clapper_src/playerBase.js b/clapper_src/playerBase.js
index d703ff33..ceabf855 100644
--- a/clapper_src/playerBase.js
+++ b/clapper_src/playerBase.js
@@ -2,6 +2,8 @@ const { Gio, GLib, GObject, Gst, GstPlayer, Gtk } = imports.gi;
const Debug = imports.clapper_src.debug;
const Misc = imports.clapper_src.misc;
+let WebServer;
+
/* PlayFlags are not exported through GI */
Gst.PlayFlags = {
VIDEO: 1,
@@ -66,6 +68,9 @@ class ClapperPlayerBase extends GstPlayer.Player
this.state = GstPlayer.PlayerState.STOPPED;
this.visualization_enabled = false;
+ this.webserver = null;
+ this.websocketSignal = null;
+
this.set_all_plugins_ranks();
this.set_initial_config();
this.set_and_bind_settings();
@@ -89,6 +94,7 @@ class ClapperPlayerBase extends GstPlayer.Player
'audio-offset',
'subtitle-offset',
'play-flags',
+ 'webserver-enabled',
];
for(let key of settingsToSet)
@@ -175,6 +181,11 @@ class ClapperPlayerBase extends GstPlayer.Player
this.widget.queue_render();
}
+ _onWsData(server, action, value)
+ {
+ debug(`unhandled WebSocket action: ${action}`);
+ }
+
_onSettingsKeyChanged(settings, key)
{
let root, value, action;
@@ -267,6 +278,29 @@ class ClapperPlayerBase extends GstPlayer.Player
this.pipeline.flags = settingsFlags;
debug(`changed play flags: ${initialFlags} -> ${settingsFlags}`);
break;
+ case 'webserver-enabled':
+ const webserverEnabled = settings.get_boolean(key);
+
+ if(webserverEnabled) {
+ if(!WebServer) {
+ /* Probably most users will not use this,
+ * so conditional import for faster startup */
+ WebServer = imports.clapper_src.webserver.WebServer;
+ }
+
+ if(!this.webserver)
+ this.webserver = new WebServer(settings.get_int('webserver-port'));
+
+ this.webserver.startListening();
+ this.websocketSignal = this.webserver.connect(
+ 'websocket-data', this._onWsData.bind(this)
+ );
+ }
+ else if(this.webserver) {
+ this.webserver.disconnect(this.websocketSignal);
+ this.webserver.stopListening();
+ }
+ break;
default:
break;
}
diff --git a/data/com.github.rafostar.Clapper.gschema.xml b/data/com.github.rafostar.Clapper.gschema.xml
index c18218b1..15f85b95 100644
--- a/data/com.github.rafostar.Clapper.gschema.xml
+++ b/data/com.github.rafostar.Clapper.gschema.xml
@@ -49,6 +49,16 @@
The subtitles font description
+
+
+ false
+ Enable WebSocket server for remote playback control
+
+
+ 6446
+ Listening port to use for incoming WebSocket connections
+
+
true
From 104db83a1cff704bebb5425ff4318047adcbb3ee Mon Sep 17 00:00:00 2001
From: Rafostar <40623528+Rafostar@users.noreply.github.com>
Date: Sat, 12 Dec 2020 00:13:02 +0100
Subject: [PATCH 07/26] Clean websocket signal properly
---
clapper_src/playerBase.js | 10 +++++++---
1 file changed, 7 insertions(+), 3 deletions(-)
diff --git a/clapper_src/playerBase.js b/clapper_src/playerBase.js
index ceabf855..f4aa4633 100644
--- a/clapper_src/playerBase.js
+++ b/clapper_src/playerBase.js
@@ -292,12 +292,16 @@ class ClapperPlayerBase extends GstPlayer.Player
this.webserver = new WebServer(settings.get_int('webserver-port'));
this.webserver.startListening();
- this.websocketSignal = this.webserver.connect(
- 'websocket-data', this._onWsData.bind(this)
- );
+
+ if(!this.websocketSignal) {
+ this.websocketSignal = this.webserver.connect(
+ 'websocket-data', this._onWsData.bind(this)
+ );
+ }
}
else if(this.webserver) {
this.webserver.disconnect(this.websocketSignal);
+ this.websocketSignal = null;
this.webserver.stopListening();
}
break;
From 7a039af7986b121e2dd699b127fe6562ee03dd86 Mon Sep 17 00:00:00 2001
From: Rafostar <40623528+Rafostar@users.noreply.github.com>
Date: Sat, 12 Dec 2020 00:16:39 +0100
Subject: [PATCH 08/26] Allow changing web server port during playback
---
clapper_src/playerBase.js | 6 ++++++
1 file changed, 6 insertions(+)
diff --git a/clapper_src/playerBase.js b/clapper_src/playerBase.js
index f4aa4633..17f1ddd8 100644
--- a/clapper_src/playerBase.js
+++ b/clapper_src/playerBase.js
@@ -305,6 +305,12 @@ class ClapperPlayerBase extends GstPlayer.Player
this.webserver.stopListening();
}
break;
+ case 'webserver-port':
+ if(!this.webserver)
+ break;
+
+ this.webserver.setListeningPort(settings.get_int(key));
+ break;
default:
break;
}
From ea7b712b2e05a31effaea5e4600773b62513af0c Mon Sep 17 00:00:00 2001
From: Rafostar <40623528+Rafostar@users.noreply.github.com>
Date: Sat, 12 Dec 2020 19:37:07 +0100
Subject: [PATCH 09/26] Send player state via WebSockets
---
clapper_src/player.js | 3 +++
clapper_src/playerBase.js | 8 ++++++++
2 files changed, 11 insertions(+)
diff --git a/clapper_src/player.js b/clapper_src/player.js
index be06fddc..fc396493 100644
--- a/clapper_src/player.js
+++ b/clapper_src/player.js
@@ -334,6 +334,7 @@ class ClapperPlayer extends PlayerBase
_onStateChanged(player, state)
{
this.state = state;
+ this.emitWs('state-changed', state);
if(state !== GstPlayer.PlayerState.BUFFERING) {
let root = player.widget.get_root();
@@ -362,6 +363,8 @@ class ClapperPlayer extends PlayerBase
_onStreamEnded(player)
{
debug('stream ended');
+ this.emitWs('stream-ended', this._trackId);
+
this._trackId++;
if(this._trackId < this._playlist.length)
diff --git a/clapper_src/playerBase.js b/clapper_src/playerBase.js
index 17f1ddd8..3e24179a 100644
--- a/clapper_src/playerBase.js
+++ b/clapper_src/playerBase.js
@@ -181,6 +181,14 @@ class ClapperPlayerBase extends GstPlayer.Player
this.widget.queue_render();
}
+ emitWs(action, value)
+ {
+ if(!this.webserver)
+ return;
+
+ this.webserver.sendMessage({ action, value });
+ }
+
_onWsData(server, action, value)
{
debug(`unhandled WebSocket action: ${action}`);
From 660b5c6c48e5717968d4d28f493ed274ac3a1ce8 Mon Sep 17 00:00:00 2001
From: Rafostar <40623528+Rafostar@users.noreply.github.com>
Date: Sat, 12 Dec 2020 20:10:06 +0100
Subject: [PATCH 10/26] Use underscore in WebSocket API
---
clapper_src/player.js | 13 ++++++-------
1 file changed, 6 insertions(+), 7 deletions(-)
diff --git a/clapper_src/player.js b/clapper_src/player.js
index fc396493..e5884192 100644
--- a/clapper_src/player.js
+++ b/clapper_src/player.js
@@ -334,7 +334,7 @@ class ClapperPlayer extends PlayerBase
_onStateChanged(player, state)
{
this.state = state;
- this.emitWs('state-changed', state);
+ this.emitWs('state_changed', state);
if(state !== GstPlayer.PlayerState.BUFFERING) {
let root = player.widget.get_root();
@@ -362,8 +362,8 @@ class ClapperPlayer extends PlayerBase
_onStreamEnded(player)
{
- debug('stream ended');
- this.emitWs('stream-ended', this._trackId);
+ debug(`end of stream: ${this._trackId}`);
+ this.emitWs('end_of_stream', this._trackId);
this._trackId++;
@@ -645,12 +645,11 @@ class ClapperPlayer extends PlayerBase
_onWsData(server, action, value)
{
switch(action) {
- case 'toggle-play':
- this.toggle_play();
- break;
+ case 'toggle_play':
case 'play':
case 'pause':
- this[action]();
+ case 'set_media':
+ this[action](value);
break;
default:
super._onWsData(server, action, value);
From 018a750fbc0ef32474c7236c04d68f6960570f3b Mon Sep 17 00:00:00 2001
From: Rafostar <40623528+Rafostar@users.noreply.github.com>
Date: Sat, 12 Dec 2020 21:56:35 +0100
Subject: [PATCH 11/26] Add web app for broadway backend
---
clapper_src/webapp.js | 36 ++++++++++++++++++++++++++++++++++++
1 file changed, 36 insertions(+)
create mode 100644 clapper_src/webapp.js
diff --git a/clapper_src/webapp.js b/clapper_src/webapp.js
new file mode 100644
index 00000000..3c43933b
--- /dev/null
+++ b/clapper_src/webapp.js
@@ -0,0 +1,36 @@
+const { Gio, GObject } = imports.gi;
+const Debug = imports.clapper_src.debug;
+const Misc = imports.clapper_src.misc;
+
+let { debug } = Debug;
+
+var WebApp = GObject.registerClass(
+class ClapperWebApp extends Gio.SubprocessLauncher
+{
+ _init()
+ {
+ const flags = Gio.SubprocessFlags.STDOUT_SILENCE
+ | Gio.SubprocessFlags.STDERR_SILENCE;
+
+ super._init(flags);
+ }
+
+ startRemoteApp()
+ {
+ this.setenv('GDK_BACKEND', 'broadway', true);
+ this.setenv('BROADWAY_DISPLAY', '6', true);
+
+ this.remoteApp = this.spawnv(Misc.appId);
+ this.remoteApp.wait_async(null, this._onRemoteClosed.bind(this));
+
+ debug('remote app started');
+ }
+
+ _onRemoteClosed(remoteApp, res)
+ {
+ debug('remote app closed');
+
+ this.setenv('GDK_BACKEND', '', true);
+ this.setenv('BROADWAY_DISPLAY', '', true);
+ }
+});
From ea67e1e62014d2f753e0e1aee4feaa62a178a4fc Mon Sep 17 00:00:00 2001
From: Rafostar <40623528+Rafostar@users.noreply.github.com>
Date: Mon, 14 Dec 2020 11:19:12 +0100
Subject: [PATCH 12/26] Flatpak: compile GTK4 with broadway backend
---
pkgs/flatpak/lib/gtk4.json | 4 +++-
1 file changed, 3 insertions(+), 1 deletion(-)
diff --git a/pkgs/flatpak/lib/gtk4.json b/pkgs/flatpak/lib/gtk4.json
index 5f2a38eb..4a8da02a 100644
--- a/pkgs/flatpak/lib/gtk4.json
+++ b/pkgs/flatpak/lib/gtk4.json
@@ -3,6 +3,7 @@
"buildsystem": "meson",
"config-opts": [
"--wrap-mode=nofallback",
+ "-Dbroadway-backend=true",
"-Dwin32-backend=false",
"-Dmacos-backend=false",
"-Dmedia-ffmpeg=disabled",
@@ -10,7 +11,8 @@
"-Dprint-cloudprint=disabled",
"-Dintrospection=enabled",
"-Ddemos=false",
- "-Dbuild-examples=false"
+ "-Dbuild-examples=false",
+ "-Dbuild-tests=false"
],
"sources": [
{
From 062a30761386652b6d7f2d4f887d28bf8b14dd6e Mon Sep 17 00:00:00 2001
From: Rafostar <40623528+Rafostar@users.noreply.github.com>
Date: Tue, 15 Dec 2020 11:51:25 +0100
Subject: [PATCH 13/26] Add stop method for web app
---
clapper_src/webapp.js | 43 +++++++++++++++++++++++++++++++++++--------
1 file changed, 35 insertions(+), 8 deletions(-)
diff --git a/clapper_src/webapp.js b/clapper_src/webapp.js
index 3c43933b..f5dca76f 100644
--- a/clapper_src/webapp.js
+++ b/clapper_src/webapp.js
@@ -12,25 +12,52 @@ class ClapperWebApp extends Gio.SubprocessLauncher
const flags = Gio.SubprocessFlags.STDOUT_SILENCE
| Gio.SubprocessFlags.STDERR_SILENCE;
- super._init(flags);
+ super._init({ flags });
+
+ this.remoteApp = null;
+ this.isRemoteClosing = false;
+
+ this.setenv('GDK_BACKEND', 'broadway', true);
}
startRemoteApp()
{
- this.setenv('GDK_BACKEND', 'broadway', true);
- this.setenv('BROADWAY_DISPLAY', '6', true);
+ if(this.remoteApp)
+ return;
- this.remoteApp = this.spawnv(Misc.appId);
+ this.remoteApp = this.spawnv([Misc.appId + 'Remote']);
this.remoteApp.wait_async(null, this._onRemoteClosed.bind(this));
debug('remote app started');
}
- _onRemoteClosed(remoteApp, res)
+ stopRemoteApp()
{
- debug('remote app closed');
+ if(!this.remoteApp || this.isRemoteClosing)
+ return;
- this.setenv('GDK_BACKEND', '', true);
- this.setenv('BROADWAY_DISPLAY', '', true);
+ this.isRemoteClosing = true;
+ this.remoteApp.force_exit();
+
+ debug('send stop signal to remote app');
+ }
+
+ _onRemoteClosed(proc, result)
+ {
+ let hadError;
+
+ try {
+ hadError = proc.wait_finish(result);
+ }
+ catch(err) {
+ debug(err);
+ }
+
+ this.remoteApp = null;
+
+ if(hadError)
+ debug('remote app exited with error');
+
+ debug('remote app closed');
}
});
From b756c15e46f3d5ef7e0f9d7d9eb7fdb7417739d5 Mon Sep 17 00:00:00 2001
From: Rafostar <40623528+Rafostar@users.noreply.github.com>
Date: Tue, 15 Dec 2020 11:59:05 +0100
Subject: [PATCH 14/26] Fix non-updated closing state
---
clapper_src/webapp.js | 1 +
1 file changed, 1 insertion(+)
diff --git a/clapper_src/webapp.js b/clapper_src/webapp.js
index f5dca76f..e5bd1168 100644
--- a/clapper_src/webapp.js
+++ b/clapper_src/webapp.js
@@ -54,6 +54,7 @@ class ClapperWebApp extends Gio.SubprocessLauncher
}
this.remoteApp = null;
+ this.isRemoteClosing = false;
if(hadError)
debug('remote app exited with error');
From b4e52d654b6450a77ad74e541254d20daf990724 Mon Sep 17 00:00:00 2001
From: Rafostar <40623528+Rafostar@users.noreply.github.com>
Date: Tue, 15 Dec 2020 12:36:06 +0100
Subject: [PATCH 15/26] Pass WebSocket data without additional signal
connection
---
clapper_src/player.js | 30 +++++++++++++++---------------
clapper_src/playerBase.js | 12 ++----------
clapper_src/webserver.js | 19 +++++++------------
3 files changed, 24 insertions(+), 37 deletions(-)
diff --git a/clapper_src/player.js b/clapper_src/player.js
index e5884192..dc0091d6 100644
--- a/clapper_src/player.js
+++ b/clapper_src/player.js
@@ -251,6 +251,21 @@ class ClapperPlayer extends PlayerBase
this[action]();
}
+ receiveWs(action, value)
+ {
+ switch(action) {
+ case 'toggle_play':
+ case 'play':
+ case 'pause':
+ case 'set_media':
+ this[action](value);
+ break;
+ default:
+ super.receiveWs(action, value);
+ break;
+ }
+ }
+
_setHideCursorTimeout()
{
this._clearTimeout('hideCursor');
@@ -642,21 +657,6 @@ class ClapperPlayer extends PlayerBase
return true;
}
- _onWsData(server, action, value)
- {
- switch(action) {
- case 'toggle_play':
- case 'play':
- case 'pause':
- case 'set_media':
- this[action](value);
- break;
- default:
- super._onWsData(server, action, value);
- break;
- }
- }
-
_onCloseRequest(window)
{
this._performCloseCleanup(window);
diff --git a/clapper_src/playerBase.js b/clapper_src/playerBase.js
index 3e24179a..7708539c 100644
--- a/clapper_src/playerBase.js
+++ b/clapper_src/playerBase.js
@@ -69,7 +69,6 @@ class ClapperPlayerBase extends GstPlayer.Player
this.visualization_enabled = false;
this.webserver = null;
- this.websocketSignal = null;
this.set_all_plugins_ranks();
this.set_initial_config();
@@ -189,7 +188,7 @@ class ClapperPlayerBase extends GstPlayer.Player
this.webserver.sendMessage({ action, value });
}
- _onWsData(server, action, value)
+ receiveWs(action, value)
{
debug(`unhandled WebSocket action: ${action}`);
}
@@ -300,16 +299,9 @@ class ClapperPlayerBase extends GstPlayer.Player
this.webserver = new WebServer(settings.get_int('webserver-port'));
this.webserver.startListening();
-
- if(!this.websocketSignal) {
- this.websocketSignal = this.webserver.connect(
- 'websocket-data', this._onWsData.bind(this)
- );
- }
+ this.webserver.passMsgData = this.receiveWs.bind(this);
}
else if(this.webserver) {
- this.webserver.disconnect(this.websocketSignal);
- this.websocketSignal = null;
this.webserver.stopListening();
}
break;
diff --git a/clapper_src/webserver.js b/clapper_src/webserver.js
index 2548003a..626a110e 100644
--- a/clapper_src/webserver.js
+++ b/clapper_src/webserver.js
@@ -4,17 +4,8 @@ const Debug = imports.clapper_src.debug;
let { debug } = Debug;
-var WebServer = GObject.registerClass({
- Signals: {
- 'websocket-data': {
- flags: GObject.SignalFlags.RUN_FIRST,
- param_types: [
- GObject.TYPE_STRING,
- GObject.TYPE_INT || GObject.TYPE_STRING
- ]
- }
- }
-}, class ClapperWebServer extends Soup.Server
+var WebServer = GObject.registerClass(
+class ClapperWebServer extends Soup.Server
{
_init(port)
{
@@ -96,6 +87,10 @@ var WebServer = GObject.registerClass({
}
}
+ passMsgData(action, value)
+ {
+ }
+
_closeCleanup()
{
while(this.wsConns.length) {
@@ -140,7 +135,7 @@ var WebServer = GObject.registerClass({
if(!parsedMsg || !parsedMsg.action)
return debug('no "action" in parsed WebSocket message');
- this.emit('websocket-data', parsedMsg.action, parsedMsg.value || 0);
+ this.passMsgData(parsedMsg.action, parsedMsg.value || 0);
}
_onWsClosed(connection)
From ca6322339f6e336de0071511d78c20079c3a00ed Mon Sep 17 00:00:00 2001
From: Rafostar <40623528+Rafostar@users.noreply.github.com>
Date: Tue, 15 Dec 2020 14:05:48 +0100
Subject: [PATCH 16/26] Do not forget port after web server is stopped
---
clapper_src/webserver.js | 1 -
1 file changed, 1 deletion(-)
diff --git a/clapper_src/webserver.js b/clapper_src/webserver.js
index 626a110e..0824f344 100644
--- a/clapper_src/webserver.js
+++ b/clapper_src/webserver.js
@@ -74,7 +74,6 @@ class ClapperWebServer extends Soup.Server
this.disconnect();
this.isListening = false;
- this.listeningPort = null;
}
sendMessage(data)
From 6d4cd494fe68b54f6f63244e9d45bfbd9813e5a3 Mon Sep 17 00:00:00 2001
From: Rafostar <40623528+Rafostar@users.noreply.github.com>
Date: Tue, 15 Dec 2020 14:16:31 +0100
Subject: [PATCH 17/26] Customize web server listening port
---
clapper_src/prefs.js | 8 ++++++++
1 file changed, 8 insertions(+)
diff --git a/clapper_src/prefs.js b/clapper_src/prefs.js
index 43e4467b..634647e5 100644
--- a/clapper_src/prefs.js
+++ b/clapper_src/prefs.js
@@ -95,8 +95,16 @@ class ClapperNetworkPage extends PrefsBase.Grid
{
super._init();
+ let checkButton;
+ let spinButton;
+
this.addTitle('Client');
this.addPlayFlagCheckButton('Progressive download buffering', Gst.PlayFlags.DOWNLOAD);
+
+ this.addTitle('Server');
+ checkButton = this.addCheckButton('Allow remote control of the player', 'webserver-enabled');
+ spinButton = this.addSpinButton('Listening port', 1024, 65535, 'webserver-port');
+ checkButton.bind_property('active', spinButton, 'visible', GObject.BindingFlags.SYNC_CREATE);
}
});
From 7431f5803464c95d64d5f2ccccac7b3527e51ec9 Mon Sep 17 00:00:00 2001
From: Rafostar <40623528+Rafostar@users.noreply.github.com>
Date: Tue, 15 Dec 2020 18:15:40 +0100
Subject: [PATCH 18/26] Prefer "set_playlist" over "set_media" method
---
clapper_src/dialogs.js | 2 +-
clapper_src/player.js | 2 +-
2 files changed, 2 insertions(+), 2 deletions(-)
diff --git a/clapper_src/dialogs.js b/clapper_src/dialogs.js
index 94d698b7..8e36ab9e 100644
--- a/clapper_src/dialogs.js
+++ b/clapper_src/dialogs.js
@@ -133,7 +133,7 @@ class ClapperUriDialog extends Gtk.Dialog
openUri(uri)
{
let { player } = this.get_transient_for().get_child();
- player.set_media(uri);
+ player.set_playlist([uri]);
this.close();
}
diff --git a/clapper_src/player.js b/clapper_src/player.js
index dc0091d6..48f09e29 100644
--- a/clapper_src/player.js
+++ b/clapper_src/player.js
@@ -257,7 +257,7 @@ class ClapperPlayer extends PlayerBase
case 'toggle_play':
case 'play':
case 'pause':
- case 'set_media':
+ case 'set_playlist':
this[action](value);
break;
default:
From 4c6e5607fb6ded472f5b3513145dbaa75c184c2f Mon Sep 17 00:00:00 2001
From: Rafostar <40623528+Rafostar@users.noreply.github.com>
Date: Tue, 15 Dec 2020 18:16:59 +0100
Subject: [PATCH 19/26] Check if player has widget before trying to focus it
---
clapper_src/headerbarBase.js | 10 ++++++++--
1 file changed, 8 insertions(+), 2 deletions(-)
diff --git a/clapper_src/headerbarBase.js b/clapper_src/headerbarBase.js
index 09d32b40..6eed791c 100644
--- a/clapper_src/headerbarBase.js
+++ b/clapper_src/headerbarBase.js
@@ -123,7 +123,13 @@ class ClapperHeaderBarPopover extends Gtk.PopoverMenu
let root = this.get_root();
let clapperWidget = root.get_child();
- if(clapperWidget && clapperWidget.player)
- clapperWidget.player.widget.grab_focus();
+ if(
+ !clapperWidget
+ || !clapperWidget.player
+ || !clapperWidget.player.widget
+ )
+ return;
+
+ clapperWidget.player.widget.grab_focus();
}
});
From 8564cc96179c7915b02bc578cdd6a3c2a11e8eb5 Mon Sep 17 00:00:00 2001
From: Rafostar <40623528+Rafostar@users.noreply.github.com>
Date: Tue, 15 Dec 2020 18:19:24 +0100
Subject: [PATCH 20/26] Move WebSocket message parsing to another file
Allows reusing the same code for the client app
---
clapper_src/webHelpers.js | 30 ++++++++++++++++++++++++++++++
clapper_src/webserver.js | 21 ++++-----------------
2 files changed, 34 insertions(+), 17 deletions(-)
create mode 100644 clapper_src/webHelpers.js
diff --git a/clapper_src/webHelpers.js b/clapper_src/webHelpers.js
new file mode 100644
index 00000000..571e6726
--- /dev/null
+++ b/clapper_src/webHelpers.js
@@ -0,0 +1,30 @@
+const { Soup } = imports.gi;
+const ByteArray = imports.byteArray;
+const Debug = imports.clapper_src.debug;
+
+let { debug } = Debug;
+
+function parseData(dataType, bytes)
+{
+ if(dataType !== Soup.WebsocketDataType.TEXT) {
+ debug('ignoring non-text WebSocket message');
+ return [false];
+ }
+
+ let parsedMsg = null;
+ const msg = bytes.get_data();
+
+ try {
+ parsedMsg = JSON.parse(ByteArray.toString(msg));
+ }
+ catch(err) {
+ debug(err);
+ }
+
+ if(!parsedMsg || !parsedMsg.action) {
+ debug('no "action" in parsed WebSocket message');
+ return [false];
+ }
+
+ return [true, parsedMsg];
+}
diff --git a/clapper_src/webserver.js b/clapper_src/webserver.js
index 0824f344..72895564 100644
--- a/clapper_src/webserver.js
+++ b/clapper_src/webserver.js
@@ -1,6 +1,6 @@
const { Soup, GObject } = imports.gi;
-const ByteArray = imports.byteArray;
const Debug = imports.clapper_src.debug;
+const WebHelpers = imports.clapper_src.webHelpers;
let { debug } = Debug;
@@ -118,23 +118,10 @@ class ClapperWebServer extends Soup.Server
_onWsMessage(connection, dataType, bytes)
{
- if(dataType !== Soup.WebsocketDataType.TEXT)
- return debug('ignoring non-text WebSocket message');
+ const [success, parsedMsg] = WebHelpers.parseData(dataType, bytes);
- const msg = bytes.get_data();
- let parsedMsg = null;
-
- try {
- parsedMsg = JSON.parse(ByteArray.toString(msg));
- }
- catch(err) {
- debug(err);
- }
-
- if(!parsedMsg || !parsedMsg.action)
- return debug('no "action" in parsed WebSocket message');
-
- this.passMsgData(parsedMsg.action, parsedMsg.value || 0);
+ if(success)
+ this.passMsgData(parsedMsg.action, parsedMsg.value);
}
_onWsClosed(connection)
From 5231a1f2251003e73aaf08537f758a718c32deab Mon Sep 17 00:00:00 2001
From: Rafostar <40623528+Rafostar@users.noreply.github.com>
Date: Tue, 15 Dec 2020 18:20:48 +0100
Subject: [PATCH 21/26] Add initial WebSocket client app
---
clapper_src/appRemote.js | 4 ++
clapper_src/playerRemote.js | 24 +++++++++++
clapper_src/webClient.js | 82 +++++++++++++++++++++++++++++++++++++
clapper_src/widgetRemote.js | 13 ++++++
4 files changed, 123 insertions(+)
create mode 100644 clapper_src/playerRemote.js
create mode 100644 clapper_src/webClient.js
create mode 100644 clapper_src/widgetRemote.js
diff --git a/clapper_src/appRemote.js b/clapper_src/appRemote.js
index ae34f9c2..2bbc8877 100644
--- a/clapper_src/appRemote.js
+++ b/clapper_src/appRemote.js
@@ -1,6 +1,7 @@
const { GObject } = imports.gi;
const { AppBase } = imports.clapper_src.appBase;
const { HeaderBarBase } = imports.clapper_src.headerbarBase;
+const { WidgetRemote } = imports.clapper_src.widgetRemote;
var AppRemote = GObject.registerClass(
class ClapperAppRemote extends AppBase
@@ -9,6 +10,9 @@ class ClapperAppRemote extends AppBase
{
super.vfunc_startup();
+ let clapperWidget = new WidgetRemote();
+ this.active_window.set_child(clapperWidget);
+
let headerBar = new HeaderBarBase(this.active_window);
this.active_window.set_titlebar(headerBar);
diff --git a/clapper_src/playerRemote.js b/clapper_src/playerRemote.js
new file mode 100644
index 00000000..6a5b4c4d
--- /dev/null
+++ b/clapper_src/playerRemote.js
@@ -0,0 +1,24 @@
+const { GObject } = imports.gi;
+const Misc = imports.clapper_src.misc;
+const { WebClient } = imports.clapper_src.webClient;
+
+let { settings } = Misc;
+
+var PlayerRemote = GObject.registerClass(
+class ClapperPlayerRemote extends GObject.Object
+{
+ _init()
+ {
+ super._init();
+
+ this.webclient = new WebClient(settings.get_int('webserver-port'));
+ }
+
+ set_playlist(playlist)
+ {
+ this.webclient.sendMessage({
+ action: 'set_playlist',
+ value: playlist
+ });
+ }
+});
diff --git a/clapper_src/webClient.js b/clapper_src/webClient.js
new file mode 100644
index 00000000..a1397f45
--- /dev/null
+++ b/clapper_src/webClient.js
@@ -0,0 +1,82 @@
+const { Soup, GObject } = imports.gi;
+const Debug = imports.clapper_src.debug;
+const WebHelpers = imports.clapper_src.webHelpers;
+
+let { debug } = Debug;
+
+var WebClient = GObject.registerClass(
+class ClapperWebClient extends Soup.Session
+{
+ _init(port)
+ {
+ super._init({
+ timeout: 3,
+ use_thread_context: true,
+ });
+
+ this.wsConn = null;
+
+ this.connectWebsocket(port);
+ }
+
+ connectWebsocket(port)
+ {
+ if(this.wsConn)
+ return;
+
+ let message = Soup.Message.new('GET', `ws://127.0.0.1:${port}/websocket`);
+ this.websocket_connect_async(message, null, null, null, this._onWsConnect.bind(this));
+
+ debug('connecting WebSocket to Clapper app');
+ }
+
+ sendMessage(data)
+ {
+ if(
+ !this.wsConn
+ || this.wsConn.state !== Soup.WebsocketState.OPEN
+ )
+ return;
+
+ this.wsConn.send_text(JSON.stringify(data));
+ }
+
+ passMsgData(action, value)
+ {
+ }
+
+ _onWsConnect(session, result)
+ {
+ let connection = null;
+
+ try {
+ connection = this.websocket_connect_finish(result);
+ }
+ catch(err) {
+ debug(err);
+ }
+
+ if(!connection)
+ return;
+
+ connection.connect('message', this._onWsMessage.bind(this));
+ connection.connect('closed', this._onWsClosed.bind(this));
+
+ this.wsConn = connection;
+
+ debug('successfully connected WebSocket');
+ }
+
+ _onWsMessage(connection, dataType, bytes)
+ {
+ const [success, parsedMsg] = WebHelpers.parseData(dataType, bytes);
+
+ if(success)
+ this.passMsgData(parsedMsg.action, parsedMsg.value);
+ }
+
+ _onWsClosed(connection)
+ {
+ debug('closed WebSocket connection');
+ }
+});
diff --git a/clapper_src/widgetRemote.js b/clapper_src/widgetRemote.js
new file mode 100644
index 00000000..79a95961
--- /dev/null
+++ b/clapper_src/widgetRemote.js
@@ -0,0 +1,13 @@
+const { GObject, Gtk } = imports.gi;
+const { PlayerRemote } = imports.clapper_src.playerRemote;
+
+var WidgetRemote = GObject.registerClass(
+class ClapperWidgetRemote extends Gtk.Grid
+{
+ _init(opts)
+ {
+ super._init();
+
+ this.player = new PlayerRemote();
+ }
+});
From dde35270ffb1da2a2932855701cb7e409dc26665 Mon Sep 17 00:00:00 2001
From: Rafostar <40623528+Rafostar@users.noreply.github.com>
Date: Tue, 15 Dec 2020 18:27:18 +0100
Subject: [PATCH 22/26] Consistent source filenames
---
clapper_src/playerBase.js | 2 +-
clapper_src/{webapp.js => webApp.js} | 0
clapper_src/{webserver.js => webServer.js} | 0
3 files changed, 1 insertion(+), 1 deletion(-)
rename clapper_src/{webapp.js => webApp.js} (100%)
rename clapper_src/{webserver.js => webServer.js} (100%)
diff --git a/clapper_src/playerBase.js b/clapper_src/playerBase.js
index 7708539c..facb9ba8 100644
--- a/clapper_src/playerBase.js
+++ b/clapper_src/playerBase.js
@@ -292,7 +292,7 @@ class ClapperPlayerBase extends GstPlayer.Player
if(!WebServer) {
/* Probably most users will not use this,
* so conditional import for faster startup */
- WebServer = imports.clapper_src.webserver.WebServer;
+ WebServer = imports.clapper_src.webServer.WebServer;
}
if(!this.webserver)
diff --git a/clapper_src/webapp.js b/clapper_src/webApp.js
similarity index 100%
rename from clapper_src/webapp.js
rename to clapper_src/webApp.js
diff --git a/clapper_src/webserver.js b/clapper_src/webServer.js
similarity index 100%
rename from clapper_src/webserver.js
rename to clapper_src/webServer.js
From a1e95dc012616375659388c497bc7a8a0cc42b62 Mon Sep 17 00:00:00 2001
From: Rafostar <40623528+Rafostar@users.noreply.github.com>
Date: Tue, 15 Dec 2020 19:03:58 +0100
Subject: [PATCH 23/26] Close remote app on error or disconnect
---
clapper_src/webClient.js | 4 +++-
clapper_src/widgetRemote.js | 13 +++++++++++++
2 files changed, 16 insertions(+), 1 deletion(-)
diff --git a/clapper_src/webClient.js b/clapper_src/webClient.js
index a1397f45..938586dc 100644
--- a/clapper_src/webClient.js
+++ b/clapper_src/webClient.js
@@ -57,7 +57,7 @@ class ClapperWebClient extends Soup.Session
}
if(!connection)
- return;
+ return this.passMsgData('close');
connection.connect('message', this._onWsMessage.bind(this));
connection.connect('closed', this._onWsClosed.bind(this));
@@ -78,5 +78,7 @@ class ClapperWebClient extends Soup.Session
_onWsClosed(connection)
{
debug('closed WebSocket connection');
+
+ this.passMsgData('close');
}
});
diff --git a/clapper_src/widgetRemote.js b/clapper_src/widgetRemote.js
index 79a95961..ba0cddfe 100644
--- a/clapper_src/widgetRemote.js
+++ b/clapper_src/widgetRemote.js
@@ -9,5 +9,18 @@ class ClapperWidgetRemote extends Gtk.Grid
super._init();
this.player = new PlayerRemote();
+ this.player.webclient.passMsgData = this.receiveWs.bind(this);
+ }
+
+ receiveWs(action, value)
+ {
+ switch(action) {
+ case 'close':
+ let root = this.get_root();
+ root.run_dispose();
+ break;
+ default:
+ break;
+ }
}
});
From a056fac1c1f7851d9629e3ca794ef540daa529bf Mon Sep 17 00:00:00 2001
From: Rafostar <40623528+Rafostar@users.noreply.github.com>
Date: Tue, 15 Dec 2020 22:35:14 +0100
Subject: [PATCH 24/26] Add logic responsible for starting web app
---
clapper_src/playerBase.js | 28 ++++++++++++++++----
clapper_src/playerRemote.js | 5 +---
clapper_src/prefs.js | 11 ++++----
clapper_src/webClient.js | 12 ++++++---
clapper_src/webServer.js | 2 +-
data/com.github.rafostar.Clapper.gschema.xml | 4 +++
6 files changed, 42 insertions(+), 20 deletions(-)
diff --git a/clapper_src/playerBase.js b/clapper_src/playerBase.js
index facb9ba8..1dc851fc 100644
--- a/clapper_src/playerBase.js
+++ b/clapper_src/playerBase.js
@@ -1,6 +1,7 @@
const { Gio, GLib, GObject, Gst, GstPlayer, Gtk } = imports.gi;
const Debug = imports.clapper_src.debug;
const Misc = imports.clapper_src.misc;
+const { WebApp } = imports.clapper_src.webApp;
let WebServer;
@@ -69,6 +70,7 @@ class ClapperPlayerBase extends GstPlayer.Player
this.visualization_enabled = false;
this.webserver = null;
+ this.webapp = null;
this.set_all_plugins_ranks();
this.set_initial_config();
@@ -93,7 +95,7 @@ class ClapperPlayerBase extends GstPlayer.Player
'audio-offset',
'subtitle-offset',
'play-flags',
- 'webserver-enabled',
+ 'webserver-enabled'
];
for(let key of settingsToSet)
@@ -286,7 +288,8 @@ class ClapperPlayerBase extends GstPlayer.Player
debug(`changed play flags: ${initialFlags} -> ${settingsFlags}`);
break;
case 'webserver-enabled':
- const webserverEnabled = settings.get_boolean(key);
+ case 'webapp-enabled':
+ const webserverEnabled = settings.get_boolean('webserver-enabled');
if(webserverEnabled) {
if(!WebServer) {
@@ -295,13 +298,28 @@ class ClapperPlayerBase extends GstPlayer.Player
WebServer = imports.clapper_src.webServer.WebServer;
}
- if(!this.webserver)
+ if(!this.webserver) {
this.webserver = new WebServer(settings.get_int('webserver-port'));
-
+ this.webserver.passMsgData = this.receiveWs.bind(this);
+ }
this.webserver.startListening();
- this.webserver.passMsgData = this.receiveWs.bind(this);
+
+ const webappEnabled = settings.get_boolean('webapp-enabled');
+
+ if(!this.webapp && !webappEnabled)
+ break;
+
+ if(webappEnabled) {
+ if(!this.webapp)
+ this.webapp = new WebApp();
+
+ this.webapp.startRemoteApp();
+ }
+ else
+ this.webapp.stopRemoteApp();
}
else if(this.webserver) {
+ /* remote app will close too when connection is lost */
this.webserver.stopListening();
}
break;
diff --git a/clapper_src/playerRemote.js b/clapper_src/playerRemote.js
index 6a5b4c4d..166dd18c 100644
--- a/clapper_src/playerRemote.js
+++ b/clapper_src/playerRemote.js
@@ -1,9 +1,6 @@
const { GObject } = imports.gi;
-const Misc = imports.clapper_src.misc;
const { WebClient } = imports.clapper_src.webClient;
-let { settings } = Misc;
-
var PlayerRemote = GObject.registerClass(
class ClapperPlayerRemote extends GObject.Object
{
@@ -11,7 +8,7 @@ class ClapperPlayerRemote extends GObject.Object
{
super._init();
- this.webclient = new WebClient(settings.get_int('webserver-port'));
+ this.webclient = new WebClient();
}
set_playlist(playlist)
diff --git a/clapper_src/prefs.js b/clapper_src/prefs.js
index 634647e5..57bf7cd5 100644
--- a/clapper_src/prefs.js
+++ b/clapper_src/prefs.js
@@ -95,16 +95,15 @@ class ClapperNetworkPage extends PrefsBase.Grid
{
super._init();
- let checkButton;
- let spinButton;
-
this.addTitle('Client');
this.addPlayFlagCheckButton('Progressive download buffering', Gst.PlayFlags.DOWNLOAD);
this.addTitle('Server');
- checkButton = this.addCheckButton('Allow remote control of the player', 'webserver-enabled');
- spinButton = this.addSpinButton('Listening port', 1024, 65535, 'webserver-port');
- checkButton.bind_property('active', spinButton, 'visible', GObject.BindingFlags.SYNC_CREATE);
+ let webServer = this.addCheckButton('Control player remotely', 'webserver-enabled');
+ let serverPort = this.addSpinButton('Listening port', 1024, 65535, 'webserver-port');
+ webServer.bind_property('active', serverPort, 'visible', GObject.BindingFlags.SYNC_CREATE);
+ //let webApp = this.addCheckButton('Run built-in web application', 'webapp-enabled');
+ //webServer.bind_property('active', webApp, 'visible', GObject.BindingFlags.SYNC_CREATE);
}
});
diff --git a/clapper_src/webClient.js b/clapper_src/webClient.js
index 938586dc..168db203 100644
--- a/clapper_src/webClient.js
+++ b/clapper_src/webClient.js
@@ -1,8 +1,10 @@
-const { Soup, GObject } = imports.gi;
+const { Gio, GObject, Soup } = imports.gi;
const Debug = imports.clapper_src.debug;
+const Misc = imports.clapper_src.misc;
const WebHelpers = imports.clapper_src.webHelpers;
let { debug } = Debug;
+let { settings } = Misc;
var WebClient = GObject.registerClass(
class ClapperWebClient extends Soup.Session
@@ -16,15 +18,16 @@ class ClapperWebClient extends Soup.Session
this.wsConn = null;
- this.connectWebsocket(port);
+ this.connectWebsocket();
}
- connectWebsocket(port)
+ connectWebsocket()
{
if(this.wsConn)
return;
- let message = Soup.Message.new('GET', `ws://127.0.0.1:${port}/websocket`);
+ const port = settings.get_int('webserver-port');
+ const message = Soup.Message.new('GET', `ws://127.0.0.1:${port}/websocket`);
this.websocket_connect_async(message, null, null, null, this._onWsConnect.bind(this));
debug('connecting WebSocket to Clapper app');
@@ -78,6 +81,7 @@ class ClapperWebClient extends Soup.Session
_onWsClosed(connection)
{
debug('closed WebSocket connection');
+ this.wsConn = null;
this.passMsgData('close');
}
diff --git a/clapper_src/webServer.js b/clapper_src/webServer.js
index 72895564..8e30f408 100644
--- a/clapper_src/webServer.js
+++ b/clapper_src/webServer.js
@@ -55,7 +55,7 @@ class ClapperWebServer extends Soup.Server
if(isListening) {
const uris = this.get_uris();
const usedPort = uris[0].get_port();
- debug(`WebSocket server listening on port: ${usedPort}`);
+ debug(`WebSocket server started listening on port: ${usedPort}`);
}
else {
debug(new Error('WebSocket server could not start listening'));
diff --git a/data/com.github.rafostar.Clapper.gschema.xml b/data/com.github.rafostar.Clapper.gschema.xml
index 15f85b95..24a346db 100644
--- a/data/com.github.rafostar.Clapper.gschema.xml
+++ b/data/com.github.rafostar.Clapper.gschema.xml
@@ -58,6 +58,10 @@
6446
Listening port to use for incoming WebSocket connections
+
+ false
+ Run built-in broadway based web application
+
From 234451f62a51927b9b69bcc88a9172d4bd82c67d Mon Sep 17 00:00:00 2001
From: Rafostar <40623528+Rafostar@users.noreply.github.com>
Date: Tue, 15 Dec 2020 22:49:06 +0100
Subject: [PATCH 25/26] Move defined play flags to prefs
They are used only in prefs and it allows starting prefs in web app.
---
clapper_src/playerBase.js | 21 ++-------------------
clapper_src/prefs.js | 17 +++++++++++++++++
2 files changed, 19 insertions(+), 19 deletions(-)
diff --git a/clapper_src/playerBase.js b/clapper_src/playerBase.js
index 1dc851fc..a02ed2e1 100644
--- a/clapper_src/playerBase.js
+++ b/clapper_src/playerBase.js
@@ -3,28 +3,11 @@ const Debug = imports.clapper_src.debug;
const Misc = imports.clapper_src.misc;
const { WebApp } = imports.clapper_src.webApp;
-let WebServer;
-
-/* PlayFlags are not exported through GI */
-Gst.PlayFlags = {
- VIDEO: 1,
- AUDIO: 2,
- TEXT: 4,
- VIS: 8,
- SOFT_VOLUME: 16,
- NATIVE_AUDIO: 32,
- NATIVE_VIDEO: 64,
- DOWNLOAD: 128,
- BUFFERING: 256,
- DEINTERLACE: 512,
- SOFT_COLORBALANCE: 1024,
- FORCE_FILTERS: 2048,
- FORCE_SW_DECODERS: 4096,
-};
-
let { debug } = Debug;
let { settings } = Misc;
+let WebServer;
+
var PlayerBase = GObject.registerClass(
class ClapperPlayerBase extends GstPlayer.Player
{
diff --git a/clapper_src/prefs.js b/clapper_src/prefs.js
index 57bf7cd5..5f1e09ec 100644
--- a/clapper_src/prefs.js
+++ b/clapper_src/prefs.js
@@ -4,6 +4,23 @@ const PrefsBase = imports.clapper_src.prefsBase;
let { settings } = Misc;
+/* PlayFlags are not exported through GI */
+Gst.PlayFlags = {
+ VIDEO: 1,
+ AUDIO: 2,
+ TEXT: 4,
+ VIS: 8,
+ SOFT_VOLUME: 16,
+ NATIVE_AUDIO: 32,
+ NATIVE_VIDEO: 64,
+ DOWNLOAD: 128,
+ BUFFERING: 256,
+ DEINTERLACE: 512,
+ SOFT_COLORBALANCE: 1024,
+ FORCE_FILTERS: 2048,
+ FORCE_SW_DECODERS: 4096,
+};
+
var GeneralPage = GObject.registerClass(
class ClapperGeneralPage extends PrefsBase.Grid
{
From b6c947efa6a59fd49c29b8712141c4f86aa18f07 Mon Sep 17 00:00:00 2001
From: Rafostar <40623528+Rafostar@users.noreply.github.com>
Date: Tue, 15 Dec 2020 23:26:24 +0100
Subject: [PATCH 26/26] Fix custom CSS loading for remote app
---
clapper_src/misc.js | 15 ++++++++++++++-
clapper_src/widget.js | 18 ++++--------------
clapper_src/widgetRemote.js | 3 +++
3 files changed, 21 insertions(+), 15 deletions(-)
diff --git a/clapper_src/misc.js b/clapper_src/misc.js
index b1ef3e2f..46b234f4 100644
--- a/clapper_src/misc.js
+++ b/clapper_src/misc.js
@@ -1,4 +1,4 @@
-const { Gio, GstAudio, GstPlayer, Gtk } = imports.gi;
+const { Gio, GstAudio, GstPlayer, Gdk, Gtk } = imports.gi;
const Debug = imports.clapper_src.debug;
var appName = 'Clapper';
@@ -34,6 +34,19 @@ function getClapperVersion()
: '';
}
+function loadCustomCss()
+{
+ const clapperPath = getClapperPath();
+ const cssProvider = new Gtk.CssProvider();
+
+ cssProvider.load_from_path(`${clapperPath}/css/styles.css`);
+ Gtk.StyleContext.add_provider_for_display(
+ Gdk.Display.get_default(),
+ cssProvider,
+ Gtk.STYLE_PROVIDER_PRIORITY_APPLICATION
+ );
+}
+
function inhibitForState(state, window)
{
let isInhibited = false;
diff --git a/clapper_src/widget.js b/clapper_src/widget.js
index 707174a1..c1acab14 100644
--- a/clapper_src/widget.js
+++ b/clapper_src/widget.js
@@ -16,25 +16,15 @@ var Widget = GObject.registerClass({
}
}, class ClapperWidget extends Gtk.Grid
{
- _init(opts)
+ _init()
{
Debug.gstVersionCheck();
super._init();
- let clapperPath = Misc.getClapperPath();
- let defaults = {
- cssPath: `${clapperPath}/css/styles.css`,
- };
- Object.assign(this, defaults, opts);
-
- let cssProvider = new Gtk.CssProvider();
- cssProvider.load_from_path(this.cssPath);
- Gtk.StyleContext.add_provider_for_display(
- Gdk.Display.get_default(),
- cssProvider,
- Gtk.STYLE_PROVIDER_PRIORITY_APPLICATION
- );
+ /* load CSS here to allow using this class
+ * separately as a pre-made GTK widget */
+ Misc.loadCustomCss();
this.windowSize = JSON.parse(settings.get_string('window-size'));
this.floatSize = JSON.parse(settings.get_string('float-size'));
diff --git a/clapper_src/widgetRemote.js b/clapper_src/widgetRemote.js
index ba0cddfe..9cf6c107 100644
--- a/clapper_src/widgetRemote.js
+++ b/clapper_src/widgetRemote.js
@@ -1,4 +1,5 @@
const { GObject, Gtk } = imports.gi;
+const Misc = imports.clapper_src.misc;
const { PlayerRemote } = imports.clapper_src.playerRemote;
var WidgetRemote = GObject.registerClass(
@@ -8,6 +9,8 @@ class ClapperWidgetRemote extends Gtk.Grid
{
super._init();
+ Misc.loadCustomCss();
+
this.player = new PlayerRemote();
this.player.webclient.passMsgData = this.receiveWs.bind(this);
}