From 044aa17aa11627449e7c28d54f0a9440a57b1b8f Mon Sep 17 00:00:00 2001 From: JosephMcc Date: Sun, 2 Feb 2025 11:46:05 -0800 Subject: [PATCH] Add new extension OsdWithNumber --- OsdWithNumber@JosephMcc/README.md | 7 + .../OsdWithNumber@josephMcc/extension.js | 43 ++++ .../OsdWithNumber@josephMcc/metadata.json | 10 + .../OsdWithNumber@josephMcc/osdWithNumber.js | 236 ++++++++++++++++++ .../OsdWithNumber@josephMcc/stylesheet.css | 5 + OsdWithNumber@JosephMcc/info.json | 5 + OsdWithNumber@JosephMcc/screenshot.png | Bin 0 -> 18367 bytes 7 files changed, 306 insertions(+) create mode 100644 OsdWithNumber@JosephMcc/README.md create mode 100644 OsdWithNumber@JosephMcc/files/OsdWithNumber@josephMcc/extension.js create mode 100644 OsdWithNumber@JosephMcc/files/OsdWithNumber@josephMcc/metadata.json create mode 100644 OsdWithNumber@JosephMcc/files/OsdWithNumber@josephMcc/osdWithNumber.js create mode 100644 OsdWithNumber@JosephMcc/files/OsdWithNumber@josephMcc/stylesheet.css create mode 100644 OsdWithNumber@JosephMcc/info.json create mode 100644 OsdWithNumber@JosephMcc/screenshot.png diff --git a/OsdWithNumber@JosephMcc/README.md b/OsdWithNumber@JosephMcc/README.md new file mode 100644 index 00000000..2d154d76 --- /dev/null +++ b/OsdWithNumber@JosephMcc/README.md @@ -0,0 +1,7 @@ +# OSD with Numbers + +Make the volume and brightness OSD's show a number in addition to the level bar. + +OSD Preview: + +![Preview](./screenshot.png) diff --git a/OsdWithNumber@JosephMcc/files/OsdWithNumber@josephMcc/extension.js b/OsdWithNumber@JosephMcc/files/OsdWithNumber@josephMcc/extension.js new file mode 100644 index 00000000..7f93207d --- /dev/null +++ b/OsdWithNumber@JosephMcc/files/OsdWithNumber@josephMcc/extension.js @@ -0,0 +1,43 @@ +const Main = imports.ui.main; +const OsdWindow = imports.ui.osdWindow; + +const OsdWithNumbers = require('./osdWithNumber'); + +class MyExtension { + constructor(meta) { + this._meta = meta; + } + + enable() { + Main.osdWindowManager = new OsdWithNumbers.OsdWindowManager(); + } + + disable() { + Main.osdWindowManager = new OsdWindow.OsdWindowManager(); + } +} + +let extension = null; + +function enable() { + try { + extension.enable(); + } catch (err) { + extension.disable(); + throw err; + } +} + +function disable() { + try { + extension.disable(); + } catch (err) { + global.logError(err); + } finally { + extension = null; + } +} + +function init(metadata) { + extension = new MyExtension(metadata); +} diff --git a/OsdWithNumber@JosephMcc/files/OsdWithNumber@josephMcc/metadata.json b/OsdWithNumber@JosephMcc/files/OsdWithNumber@josephMcc/metadata.json new file mode 100644 index 00000000..b6fa89ed --- /dev/null +++ b/OsdWithNumber@JosephMcc/files/OsdWithNumber@josephMcc/metadata.json @@ -0,0 +1,10 @@ +{ + "uuid": "osdWithNumber@josephMcc", + "name": "OSD with numbers", + "author": "JosephMcc", + "version": "1.0.0", + "description": "OSD that shows the level in digits", + "url": "https://github.com/JosephMcc/osdWithNumber", + "website": "https://github.com/JosephMcc/osdWithNumber", + "cinnamon-version": [ "6.4" ] +} \ No newline at end of file diff --git a/OsdWithNumber@JosephMcc/files/OsdWithNumber@josephMcc/osdWithNumber.js b/OsdWithNumber@JosephMcc/files/OsdWithNumber@josephMcc/osdWithNumber.js new file mode 100644 index 00000000..48d93960 --- /dev/null +++ b/OsdWithNumber@JosephMcc/files/OsdWithNumber@josephMcc/osdWithNumber.js @@ -0,0 +1,236 @@ +// -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*- + +const Clutter = imports.gi.Clutter; +const Gdk = imports.gi.Gdk; +const Gio = imports.gi.Gio; +const GLib = imports.gi.GLib; +const GObject = imports.gi.GObject; +const Meta = imports.gi.Meta; +const St = imports.gi.St; + +const BarLevel = imports.ui.barLevel; +const Layout = imports.ui.layout; +const Main = imports.ui.main; + +const LEVEL_ANIMATION_TIME = 100; +const FADE_TIME = 100; +const HIDE_TIMEOUT = 1500; + +function convertGdkIndex(monitorIndex) { + let screen = Gdk.Screen.get_default(); + let rect = screen.get_monitor_geometry(monitorIndex); + let cx = rect.x + rect.width / 2; + let cy = rect.y + rect.height / 2; + for (let i = 0; i < Main.layoutManager.monitors.length; i++) { + let monitor = Main.layoutManager.monitors[i]; + if (cx >= monitor.x && cx < monitor.x + monitor.width && + cy >= monitor.y && cy < monitor.y + monitor.height) + monitorIndex = i; + } + + return monitorIndex; +}; + +var OsdWindow = GObject.registerClass( +class OsdWindow extends Clutter.Actor { + _init(monitorIndex) { + super._init({ + x_expand: true, + y_expand: true, + x_align: Clutter.ActorAlign.CENTER, + y_align: Clutter.ActorAlign.END, + }); + + this._monitorIndex = monitorIndex; + let constraint = new Layout.MonitorConstraint({ + index: monitorIndex, + work_area: true, + }); + this.add_constraint(constraint); + + this._hbox = new St.BoxLayout({ + style_class: 'media-keys-osd', + important: true, + x_align: Clutter.ActorAlign.CENTER, + }); + this.add_actor(this._hbox); + + this._icon = new St.Icon({ y_expand: true }); + this._hbox.add_child(this._icon); + + this._vbox = new St.BoxLayout({ + vertical: true, + y_align: Clutter.ActorAlign.CENTER, + }); + this._hbox.add_child(this._vbox); + + this._label = new St.Label(); + this._vbox.add_child(this._label); + + this._level = new BarLevel.BarLevel({ + style_class: 'level', + value: 0, + }); + this._vbox.add_child(this._level); + + this._percentage = new St.Label({ + style_class: 'level-number', + y_align: Clutter.ActorAlign.CENTER, + x_align: Clutter.ActorAlign.CENTER, + }); + this._hbox.add_child(this._percentage); + + this._hideTimeoutId = 0; + this._reset(); + Main.uiGroup.add_child(this); + } + + setIcon(icon) { + this._icon.gicon = icon; + } + + setLabel(label) { + this._label.visible = label != null; + if (this._label.visible) + this._label.text = label; + } + + setLevel(value) { + this._level.visible = value != null; + if (this._level.visible) { + let intValue = value.toString(); + value = value / 100; + if (this.visible) { + this._level.ease_property('value', value, { + mode: Clutter.AnimationMode.EASE_OUT_QUAD, + duration: LEVEL_ANIMATION_TIME, + }); + + this._percentage.set_text(intValue); + } else { + this._level.value = value; + this._percentage.set_text(intValue); + } + } + } + + setMaxLevel(maxLevel = 1) { + this._level.maximum_value = maxLevel; + } + + show() { + if (!this._icon.gicon) + return; + + if (!this.visible) { + Meta.disable_unredirect_for_display(global.display); + super.show(); + this.opacity = 0; + this.get_parent().set_child_above_sibling(this, null); + + this.ease({ + opacity: 255, + duration: FADE_TIME, + mode: Clutter.AnimationMode.EASE_OUT_QUAD, + }); + } + + if (this._hideTimeoutId) + GLib.source_remove(this._hideTimeoutId); + this._hideTimeoutId = GLib.timeout_add( + GLib.PRIORITY_DEFAULT, HIDE_TIMEOUT, this._hide.bind(this)); + GLib.Source.set_name_by_id(this._hideTimeoutId, '[cinnamon] this._hide'); + } + + cancel() { + if (!this._hideTimeoutId) + return; + + GLib.source_remove(this._hideTimeoutId); + this._hide(); + } + + _hide() { + this._hideTimeoutId = 0; + this.ease({ + opacity: 0, + duration: FADE_TIME, + mode: Clutter.AnimationMode.EASE_OUT_QUAD, + onComplete: () => { + this._reset(); + Meta.enable_unredirect_for_display(global.display); + }, + }); + return GLib.SOURCE_REMOVE; + } + + _reset() { + super.hide(); + this.setLabel(null); + this.setMaxLevel(null); + this.setLevel(null); + } +}); + +var OsdWindowManager = class { + constructor() { + this._osdWindows = []; + + Main.layoutManager.connect('monitors-changed', this._layoutChanged.bind(this)); + this._osdSettings = new Gio.Settings({ schema_id: "org.cinnamon" }); + this._osdSettings.connect("changed::show-media-keys-osd", this._layoutChanged.bind(this)); + + this._layoutChanged(); + } + + _layoutChanged() { + this._osdWindows.forEach((osd) => { + osd.destroy(); + }) + + this._osdWindows = []; + + if (!this._osdSettings.get_boolean("show-media-keys-osd")) + return; + + for (let i = 0; i < Main.layoutManager.monitors.length; i++) { + if (this._osdWindows[i] === undefined) + this._osdWindows[i] = new OsdWindow(i); + } + } + + _showOsdWindow(monitorIndex, icon, label, level) { + this._osdWindows[monitorIndex].setIcon(icon); + this._osdWindows[monitorIndex].setLabel(label); + this._osdWindows[monitorIndex].setMaxLevel(1); + this._osdWindows[monitorIndex].setLevel(level); + this._osdWindows[monitorIndex].show(); + } + + show(monitorIndex, icon, label, level, convertIndex) { + if (this._osdWindows.length === 0) + return; + + if (monitorIndex !== -1) { + if (convertIndex) + monitorIndex = convertGdkIndex(monitorIndex); + for (let i = 0; i < this._osdWindows.length; i++) { + if (i === monitorIndex) + this._showOsdWindow(i, icon, label, level); + else + this._osdWindows[i].cancel(); + } + } else { + for (let i = 0; i < this._osdWindows.length; i++) + this._showOsdWindow(i, icon, label, level); + } + } + + hideAll() { + if (this._osdWindows.length === 0) + return; + + for (let i = 0; i < this._osdWindows.length; i++) + this._osdWindows[i].cancel(); + } +}; diff --git a/OsdWithNumber@JosephMcc/files/OsdWithNumber@josephMcc/stylesheet.css b/OsdWithNumber@JosephMcc/files/OsdWithNumber@josephMcc/stylesheet.css new file mode 100644 index 00000000..fd9e83e1 --- /dev/null +++ b/OsdWithNumber@JosephMcc/files/OsdWithNumber@josephMcc/stylesheet.css @@ -0,0 +1,5 @@ +/* This is just an easy way to keep the osd horizontal size from + changing when the level number changes */ +.level-number { + min-width: 1.5em; +} diff --git a/OsdWithNumber@JosephMcc/info.json b/OsdWithNumber@JosephMcc/info.json new file mode 100644 index 00000000..5cc583db --- /dev/null +++ b/OsdWithNumber@JosephMcc/info.json @@ -0,0 +1,5 @@ +{ + "author": "JosephMcc", + "original_author": "JosephMcc", + "license": "GPL-3.0" +} diff --git a/OsdWithNumber@JosephMcc/screenshot.png b/OsdWithNumber@JosephMcc/screenshot.png new file mode 100644 index 0000000000000000000000000000000000000000..77e28f6cb3fc3076006718f8658bc40f58f58183 GIT binary patch literal 18367 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 anExMOMNwXYa