[gnome-shell/T27795: 44/138] watermark: introduce a new Watermark feature in GNOME Shell
- From: Georges Basile Stavracas Neto <gbsneto src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gnome-shell/T27795: 44/138] watermark: introduce a new Watermark feature in GNOME Shell
- Date: Tue, 1 Oct 2019 23:33:01 +0000 (UTC)
commit 3706ef9360406c77f3f363c72d5800ad29fbfaa8
Author: Georges Basile Stavracas Neto <georges stavracas gmail com>
Date: Sun Jun 4 01:51:31 2017 -0300
watermark: introduce a new Watermark feature in GNOME Shell
This is not a simple copy-paste of the Watermark extension,
but a fully-integrated watermark manager with verious settings
to tweak the UI.
Also, for backwards compabilitiy, we need to make sure that if we
use a watermark specified by the image builder conf file, we treat
it as always visible (regardless of the gsetting).
https://phabricator.endlessm.com/T15839
https://phabricator.endlessm.com/T18935
data/org.gnome.shell.gschema.xml.in | 53 ++++++++
js/js-resources.gresource.xml | 1 +
js/misc/config.js.in | 2 +
js/misc/meson.build | 1 +
js/ui/main.js | 6 +
js/ui/watermark.js | 257 ++++++++++++++++++++++++++++++++++++
meson.build | 1 +
7 files changed, 321 insertions(+)
---
diff --git a/data/org.gnome.shell.gschema.xml.in b/data/org.gnome.shell.gschema.xml.in
index 79c0c2c784..829fe3f5ee 100644
--- a/data/org.gnome.shell.gschema.xml.in
+++ b/data/org.gnome.shell.gschema.xml.in
@@ -1,4 +1,15 @@
<schemalist>
+ <!-- Keep Endless-specific enumerations at the top of the file -->
+
+ <enum id="org.gnome.shell.watermark.Position">
+ <value nick="center" value="0"/>
+ <value nick="bottom-left" value="1"/>
+ <value nick="bottom-center" value="2"/>
+ <value nick="bottom-right" value="3"/>
+ </enum>
+
+ <!-- End of Endless-specific enumerations -->
+
<schema id="org.gnome.shell" path="/org/gnome/shell/"
gettext-domain="@GETTEXT_PACKAGE@">
<key name="development-tools" type="b">
@@ -453,4 +464,46 @@
</description>
</key>
</schema>
+
+ <!-- Endless-specific schemas beyond this point -->
+
+ <schema id="org.gnome.shell.watermark" path="/org/gnome/shell/watermark/"
+ gettext-domain="@GETTEXT_PACKAGE@">
+ <key type="s" name="watermark-file">
+ <default>''</default>
+ <summary>Watermark file</summary>
+ <description>The full watermark file path</description>
+ </key>
+ <key name="watermark-position" enum="org.gnome.shell.watermark.Position">
+ <default>'bottom-right'</default>
+ <summary>Watermark position</summary>
+ <description>
+ The position of the watermark; valid values are 'center',
+ 'bottom-left', 'bottom-center' and 'bottom-right'
+ </description>
+ </key>
+ <key type="d" name="watermark-size">
+ <range min="5.0" max="30.0"/>
+ <default>9.0</default>
+ <summary>Watermark size</summary>
+ <description>The watermark size in percent relative to the screen width</description>
+ </key>
+ <key type="u" name="watermark-border">
+ <range min="0" max="100"/>
+ <default>40</default>
+ <summary>Watermark border</summary>
+ <description>The watermark around the logo</description>
+ </key>
+ <key type="u" name="watermark-opacity">
+ <range min="0" max="255"/>
+ <default>255</default>
+ <summary>Watermark opacity</summary>
+ <description>The watermark of the logo</description>
+ </key>
+ <key type="b" name="watermark-always-visible">
+ <default>false</default>
+ <summary>Watermark always visible</summary>
+ <description>Show the watermark even on a non default background</description>
+ </key>
+ </schema>
</schemalist>
diff --git a/js/js-resources.gresource.xml b/js/js-resources.gresource.xml
index 48cb070d01..160791a8b6 100644
--- a/js/js-resources.gresource.xml
+++ b/js/js-resources.gresource.xml
@@ -150,5 +150,6 @@
<file>ui/sideComponent.js</file>
<file>ui/status/orientation.js</file>
<file>ui/userMenu.js</file>
+ <file>ui/watermark.js</file>
</gresource>
</gresources>
diff --git a/js/misc/config.js.in b/js/misc/config.js.in
index 065d7a0a2a..d7f16e608f 100644
--- a/js/misc/config.js.in
+++ b/js/misc/config.js.in
@@ -18,3 +18,5 @@ var PKGDATADIR = '@datadir@/@PACKAGE_NAME@';
var VPNDIR = '@vpndir@';
/* g-i package versions */
var LIBMUTTER_API_VERSION = '@LIBMUTTER_API_VERSION@'
+/* used for the watermark feature */
+var LOCALSTATEDIR = '@localstatedir@';
diff --git a/js/misc/meson.build b/js/misc/meson.build
index 5a4871762a..980f1a5495 100644
--- a/js/misc/meson.build
+++ b/js/misc/meson.build
@@ -7,6 +7,7 @@ jsconf.set10('HAVE_BLUETOOTH', bt_dep.found())
jsconf.set10('HAVE_NETWORKMANAGER', have_networkmanager)
jsconf.set('datadir', datadir)
jsconf.set('libexecdir', libexecdir)
+jsconf.set('localstatedir', localstatedir)
jsconf.set('vpndir', vpndir)
config_js = configure_file(
diff --git a/js/ui/main.js b/js/ui/main.js
index 0ca07052fa..f1652b43fc 100644
--- a/js/ui/main.js
+++ b/js/ui/main.js
@@ -47,6 +47,7 @@ const XdndHandler = imports.ui.xdndHandler;
const KbdA11yDialog = imports.ui.kbdA11yDialog;
const LocatePointer = imports.ui.locatePointer;
const PointerA11yTimeout = imports.ui.pointerA11yTimeout;
+const Watermark = imports.ui.watermark;
const A11Y_SCHEMA = 'org.gnome.desktop.a11y.keyboard';
const STICKY_KEYS_ENABLE = 'stickykeys-enable';
@@ -95,6 +96,7 @@ let _a11ySettings = null;
let _themeResource = null;
let _oskResource = null;
let _desktopAppClient = null;
+let _watermarkManager = null;
function _sessionUpdated() {
if (sessionMode.isPrimary)
@@ -273,6 +275,10 @@ function _initializeUI() {
Scripting.runPerfScript(module, perfOutput);
}
});
+
+ /* Initialize watermarks */
+ _watermarkManager = new Watermark.WatermarkManager();
+ _watermarkManager.init();
}
function _getStylesheet(name) {
diff --git a/js/ui/watermark.js b/js/ui/watermark.js
new file mode 100644
index 0000000000..d81ea88b62
--- /dev/null
+++ b/js/ui/watermark.js
@@ -0,0 +1,257 @@
+// -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*-
+
+const { Clutter, Gio, GLib, St } = imports.gi;
+
+const Config = imports.misc.config;
+const Background = imports.ui.background;
+const Main = imports.ui.main;
+const Monitor = imports.ui.monitor;
+
+const WATERMARK_SCHEMA = 'org.gnome.shell.watermark';
+const WATERMARK_CUSTOM_BRANDING_FILE = Config.LOCALSTATEDIR +
'/lib/eos-image-defaults/branding/gnome-shell.conf';
+
+var Watermark = class {
+ constructor(bgManager) {
+ this._bgManager = bgManager;
+
+ this._watermarkFile = null;
+ this._forceWatermarkVisible = false;
+
+ this._settings = new Gio.Settings({ schema_id: WATERMARK_SCHEMA });
+
+ this._settings.connect('changed::watermark-file',
+ this._updateWatermark.bind(this));
+ this._settings.connect('changed::watermark-size',
+ this._updateScale.bind(this));
+ this._settings.connect('changed::watermark-position',
+ this._updatePosition.bind(this));
+ this._settings.connect('changed::watermark-border',
+ this._updateBorder.bind(this));
+ this._settings.connect('changed::watermark-always-visible',
+ this._updateVisibility.bind(this));
+
+ this._textureCache = St.TextureCache.get_default();
+ this._textureCache.connect('texture-file-changed', (cache, file) => {
+ if (!this._watermarkFile || !this._watermarkFile.equal(file))
+ return;
+
+ this._updateWatermarkTexture();
+ });
+
+ this.actor = new St.Widget({
+ layout_manager: new Clutter.BinLayout(),
+ opacity: 0,
+ });
+ bgManager._container.add_actor(this.actor);
+
+ this.actor.connect('destroy', this._onDestroy.bind(this));
+
+ let monitorIndex = bgManager._monitorIndex;
+ let constraint = new Monitor.MonitorConstraint({
+ index: monitorIndex,
+ work_area: true,
+ });
+ this.actor.add_constraint(constraint);
+
+ this._bin = new St.Widget({ x_expand: true, y_expand: true });
+ this.actor.add_actor(this._bin);
+
+ this._settings.bind('watermark-opacity', this._bin, 'opacity',
+ Gio.SettingsBindFlags.DEFAULT);
+
+ this._updateWatermark();
+ this._updatePosition();
+ this._updateBorder();
+
+ this._bgDestroyedId =
+ bgManager.backgroundActor.connect('destroy',
+ this._backgroundDestroyed.bind(this));
+
+ this._bgChangedId =
+ bgManager.connect('changed', this._updateVisibility.bind(this));
+
+ this._updateVisibility();
+ }
+
+ _loadBrandingFile() {
+ try {
+ let keyfile = new GLib.KeyFile();
+ keyfile.load_from_file(WATERMARK_CUSTOM_BRANDING_FILE, GLib.KeyFileFlags.NONE);
+ return keyfile.get_string('Watermark', 'logo');
+ } catch(e) {
+ return null;
+ }
+ }
+
+ _updateWatermark() {
+ let filename = this._settings.get_string('watermark-file');
+ let brandingFile = this._loadBrandingFile();
+
+ // If there's no GSettings file, but there is a custom file, use
+ // the custom file instead and make sure it is visible
+ if (!filename && brandingFile) {
+ filename = brandingFile;
+ this._forceWatermarkVisible = true;
+ } else {
+ this._forceWatermarkVisible = false;
+ }
+
+ let file = Gio.File.new_for_commandline_arg(filename);
+ if (this._watermarkFile && this._watermarkFile.equal(file))
+ return;
+
+ this._watermarkFile = file;
+
+ this._updateWatermarkTexture();
+ }
+
+ _updateWatermarkTexture() {
+ if (this._icon)
+ this._icon.destroy();
+
+ let scaleFactor = St.ThemeContext.get_for_stage(global.stage).scale_factor;
+
+ this._icon = this._textureCache.load_file_async(
+ this._watermarkFile,
+ -1, -1,
+ scaleFactor,
+ this.actor.resource_scale);
+ this._icon.connect('allocation-changed', this._updateScale.bind(this));
+ this._bin.add_actor(this._icon);
+ }
+
+ _updateScale() {
+ if (this._icon.width == 0)
+ return;
+
+ let size = this._settings.get_double('watermark-size');
+ let width = this.actor.width * size / 100;
+ let height = this._icon.height * width / this._icon.width;
+ if (Math.abs(this._icon.height - height) < 1.0 &&
+ Math.abs(this._icon.width - width) < 1.0) {
+ // size of icon would not significantly change, so don't
+ // update the size to avoid recursion in case the
+ // manually set size differs just minimal from the eventually
+ // allocated size
+ return;
+ }
+ this._icon.set_size(width, height);
+ }
+
+ _updatePosition() {
+ let xAlign, yAlign;
+ switch (this._settings.get_string('watermark-position')) {
+ case 'center':
+ xAlign = Clutter.ActorAlign.CENTER;
+ yAlign = Clutter.ActorAlign.CENTER;
+ break;
+ case 'bottom-left':
+ xAlign = Clutter.ActorAlign.START;
+ yAlign = Clutter.ActorAlign.END;
+ break;
+ case 'bottom-center':
+ xAlign = Clutter.ActorAlign.CENTER;
+ yAlign = Clutter.ActorAlign.END;
+ break;
+ case 'bottom-right':
+ xAlign = Clutter.ActorAlign.END;
+ yAlign = Clutter.ActorAlign.END;
+ break;
+ }
+ this._bin.x_align = xAlign;
+ this._bin.y_align = yAlign;
+ }
+
+ _updateBorder() {
+ let border = this._settings.get_uint('watermark-border');
+ this.actor.style = 'padding: %dpx;'.format(border);
+ }
+
+ _updateVisibility() {
+ let background = this._bgManager.backgroundActor.background._delegate;
+ let defaultUri = background._settings.get_default_value('picture-uri');
+ let file = Gio.File.new_for_commandline_arg(defaultUri.deep_unpack());
+
+ let visible;
+ if (this._forceWatermarkVisible ||
+ this._settings.get_boolean('watermark-always-visible'))
+ visible = true;
+ else if (background._file)
+ visible = background._file.equal(file);
+ else // background == NONE
+ visible = false;
+
+ this.actor.ease({
+ opacity: visible ? 255 : 0,
+ duration: Background.FADE_ANIMATION_TIME,
+ mode: Clutter.Animation.EASE_OUT_QUAD,
+ });
+ }
+
+ _backgroundDestroyed() {
+ this._bgDestroyedId = 0;
+
+ if (this._bgManager._backgroundSource) // background swapped
+ this._bgDestroyedId =
+ this._bgManager.backgroundActor.connect('destroy',
+ this._backgroundDestroyed.bind(this));
+ else // bgManager destroyed
+ this.actor.destroy();
+
+ }
+
+ _onDestroy() {
+ this._settings.run_dispose();
+ this._settings = null;
+
+ if (this._bgManager) {
+ if (this._bgDestroyedId)
+ this._bgManager.backgroundActor.disconnect(this._bgDestroyedId);
+
+ if (this._bgChangedId)
+ this._bgManager.disconnect(this._bgChangedId);
+ }
+
+ this._bgDestroyedId = 0;
+ this._bgChangedId = 0;
+
+ this._bgManager = null;
+ this._watermarkFile = null;
+ this.actor = null;
+ }
+};
+
+var WatermarkManager = class WatermarkManager {
+ constructor() {
+ this._watermarks = [];
+ }
+
+ init() {
+ Main.layoutManager.connect('monitors-changed', this._addWatermark.bind(this));
+ Main.layoutManager.connect('startup-prepared', this._addWatermark.bind(this));
+ this._addWatermark();
+ }
+
+ _addWatermark() {
+ this._destroyWatermark();
+ _forEachBackgroundManager((bgManager) => {
+ this._watermarks.push(new Watermark(bgManager));
+ });
+ }
+
+ _destroyWatermark() {
+ this._watermarks.forEach(l => {
+ if (l.actor)
+ l.actor.destroy();
+ });
+ this._watermarks = [];
+ }
+};
+
+function _forEachBackgroundManager(func) {
+ if (Main.overview._bgManagers)
+ Main.overview._bgManagers.forEach(func);
+
+ if (Main.layoutManager._bgManagers)
+ Main.layoutManager._bgManagers.forEach(func);
+}
diff --git a/meson.build b/meson.build
index b22f52af8f..b0e577abe3 100644
--- a/meson.build
+++ b/meson.build
@@ -46,6 +46,7 @@ bindir = join_paths(prefix, get_option('bindir'))
datadir = join_paths(prefix, get_option('datadir'))
libdir = join_paths(prefix, get_option('libdir'))
libexecdir = join_paths(prefix, get_option('libexecdir'))
+localstatedir = join_paths(prefix, get_option('localstatedir'))
mandir = join_paths(prefix, get_option('mandir'))
sysconfdir = join_paths(prefix, get_option('sysconfdir'))
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]