Skip to content

Commit 96f4754

Browse files
authored
OSD150@claudiux v1.0.0: Creation (#822)
1 parent 1c45b05 commit 96f4754

File tree

13 files changed

+373
-0
lines changed

13 files changed

+373
-0
lines changed

OSD150@claudiux/CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
files/OSD150@claudiux/CHANGELOG.md

OSD150@claudiux/README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
files/OSD150@claudiux/README.md
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
### v1.0.0~20250207
2+
* Creation of this extension OSD150@claudiux, fully handled by the sound150@claudiux (Enhanced Sound) applet.
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
OSD Window 150, extension fully handled by the [Enhanced Sound Applet (sound150@claudiux)](https://cinnamon-spices.linuxmint.com/applets/view/306).
2+
3+
This extension allows to display an OSD window that can be:
4+
5+
* with or without level bar,
6+
* with or without level value,
7+
* with or without '%' beside level value,
8+
* horizontal (the level value appears alongside the level bar),
9+
* vertical (the level value appears above the level bar).
10+
11+
All these options can be set from the Sound tab (OSD section) of the Enhanced Sound Applet settings.
Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
const Main = imports.ui.main;
2+
const OsdWindow = imports.ui.osdWindow;
3+
4+
const Osd150 = require('./osd150');
5+
6+
class MyExtension {
7+
constructor(meta) {
8+
this._meta = meta;
9+
}
10+
11+
enable() {
12+
Main.osdWindowManager = new Osd150.OsdWindowManager();
13+
}
14+
15+
disable() {
16+
Main.osdWindowManager = new OsdWindow.OsdWindowManager();
17+
}
18+
}
19+
20+
let extension = null;
21+
22+
function enable() {
23+
try {
24+
extension.enable();
25+
} catch (err) {
26+
extension.disable();
27+
throw err;
28+
}
29+
}
30+
31+
function disable() {
32+
try {
33+
extension.disable();
34+
} catch (err) {
35+
global.logError(err);
36+
} finally {
37+
extension = null;
38+
}
39+
}
40+
41+
function init(metadata) {
42+
extension = new MyExtension(metadata);
43+
}
7.13 KB
Loading
Binary file not shown.
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
{
2+
"uuid": "OSD150@claudiux",
3+
"name": "OSD Window for sound150",
4+
"author": "claudiux",
5+
"version": "1.0.0",
6+
"description": "The OSD Window handled by the Enhanced Sound Applet",
7+
"cinnamon-version": [
8+
"6.4"
9+
],
10+
"url": "https://github.com/claudiux/sound150/tree/main/sound150%40claudiux/extension/OSD150%40claudiux"
11+
}
Lines changed: 247 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,247 @@
1+
const Clutter = imports.gi.Clutter;
2+
const Gdk = imports.gi.Gdk;
3+
const Gio = imports.gi.Gio;
4+
const GLib = imports.gi.GLib;
5+
const GObject = imports.gi.GObject;
6+
const Meta = imports.gi.Meta;
7+
const St = imports.gi.St;
8+
9+
const BarLevel = imports.ui.barLevel;
10+
const Layout = imports.ui.layout;
11+
const Main = imports.ui.main;
12+
13+
const LEVEL_ANIMATION_TIME = 100;
14+
const FADE_TIME = 100;
15+
const HIDE_TIMEOUT = 1500;
16+
17+
function convertGdkIndex(monitorIndex) {
18+
let screen = Gdk.Screen.get_default();
19+
let rect = screen.get_monitor_geometry(monitorIndex);
20+
let cx = rect.x + rect.width / 2;
21+
let cy = rect.y + rect.height / 2;
22+
for (let i = 0; i < Main.layoutManager.monitors.length; i++) {
23+
let monitor = Main.layoutManager.monitors[i];
24+
if (cx >= monitor.x && cx < monitor.x + monitor.width &&
25+
cy >= monitor.y && cy < monitor.y + monitor.height)
26+
monitorIndex = i;
27+
}
28+
29+
return monitorIndex;
30+
};
31+
32+
var OsdWindow = GObject.registerClass(
33+
class OsdWindow extends Clutter.Actor {
34+
constructor(monitorIndex) {
35+
super({
36+
x_expand: true,
37+
y_expand: true,
38+
x_align: Clutter.ActorAlign.CENTER,
39+
y_align: Clutter.ActorAlign.END,
40+
});
41+
42+
this._monitorIndex = monitorIndex;
43+
let constraint = new Layout.MonitorConstraint({
44+
index: monitorIndex,
45+
work_area: true,
46+
});
47+
this.add_constraint(constraint);
48+
49+
this._hbox = new St.BoxLayout({
50+
style_class: 'media-keys-osd',
51+
important: true,
52+
x_align: Clutter.ActorAlign.CENTER,
53+
});
54+
this.add_actor(this._hbox);
55+
56+
this._icon = new St.Icon({ y_expand: true });
57+
this._hbox.add_child(this._icon);
58+
59+
this._vbox = new St.BoxLayout({
60+
vertical: true,
61+
y_align: Clutter.ActorAlign.CENTER,
62+
});
63+
this._hbox.add_child(this._vbox);
64+
65+
this._label = new St.Label();
66+
this._vbox.add_child(this._label);
67+
68+
this._level = new BarLevel.BarLevel({
69+
style_class: 'level',
70+
value: 0,
71+
});
72+
this._vbox.add_child(this._level);
73+
74+
this._hideTimeoutId = 0;
75+
this._reset();
76+
Main.uiGroup.add_child(this);
77+
}
78+
79+
setIcon(icon) {
80+
this._icon.gicon = icon;
81+
}
82+
83+
setLabel(label) {
84+
this._label.visible = label != null;
85+
if (this._label.visible)
86+
this._label.text = label;
87+
}
88+
89+
setLevel(value) {
90+
this._level.visible = value != null;
91+
if (this._level.visible) {
92+
value = value / 100;
93+
if (this.visible)
94+
this._level.ease_property('value', value, {
95+
mode: Clutter.AnimationMode.EASE_OUT_QUAD,
96+
duration: LEVEL_ANIMATION_TIME,
97+
});
98+
else
99+
this._level.value = value;
100+
}
101+
}
102+
103+
setMaxLevel(maxLevel = 1) {
104+
this._level.maximum_value = maxLevel;
105+
}
106+
107+
show() {
108+
if (!this._icon.gicon)
109+
return;
110+
111+
if (!this.visible) {
112+
Meta.disable_unredirect_for_display(global.display);
113+
super.show();
114+
this.opacity = 0;
115+
this.get_parent().set_child_above_sibling(this, null);
116+
117+
this.ease({
118+
opacity: 255,
119+
duration: FADE_TIME,
120+
mode: Clutter.AnimationMode.EASE_OUT_QUAD,
121+
});
122+
}
123+
124+
if (this._hideTimeoutId)
125+
GLib.source_remove(this._hideTimeoutId);
126+
this._hideTimeoutId = GLib.timeout_add(
127+
GLib.PRIORITY_DEFAULT, HIDE_TIMEOUT, () => { this._hide() });
128+
GLib.Source.set_name_by_id(this._hideTimeoutId, '[cinnamon] this._hide');
129+
}
130+
131+
cancel() {
132+
if (!this._hideTimeoutId)
133+
return;
134+
135+
GLib.source_remove(this._hideTimeoutId);
136+
this._hide();
137+
}
138+
139+
_hide() {
140+
this._hideTimeoutId = 0;
141+
this.ease({
142+
opacity: 0,
143+
duration: FADE_TIME,
144+
mode: Clutter.AnimationMode.EASE_OUT_QUAD,
145+
onComplete: () => {
146+
this._reset();
147+
Meta.enable_unredirect_for_display(global.display);
148+
},
149+
});
150+
return GLib.SOURCE_REMOVE;
151+
}
152+
153+
_reset() {
154+
super.hide();
155+
this.setLabel(null);
156+
this.setMaxLevel(null);
157+
this.setLevel(null);
158+
}
159+
}
160+
);
161+
162+
var OsdWindowManager = class {
163+
constructor() {
164+
this._osdWindows = [];
165+
166+
Main.layoutManager.connect('monitors-changed', () => { this._layoutChanged() });
167+
this._osdSettings = new Gio.Settings({ schema_id: "org.cinnamon" });
168+
this._osdSettings.connect("changed::show-media-keys-osd", () => { this._layoutChanged() });
169+
170+
this._layoutChanged();
171+
}
172+
173+
_layoutChanged() {
174+
this._osdWindows.forEach((osd) => {
175+
osd.destroy();
176+
})
177+
178+
this._osdWindows = [];
179+
180+
if (!this._osdSettings.get_boolean("show-media-keys-osd"))
181+
return;
182+
183+
for (let i = 0; i < Main.layoutManager.monitors.length; i++) {
184+
if (this._osdWindows[i] === undefined)
185+
this._osdWindows[i] = new OsdWindow(i);
186+
}
187+
}
188+
189+
_showOsdWindow(monitorIndex, icon, label, level, maxLevel, horizontal) {
190+
//~ global.log("horizontal: "+horizontal);
191+
if (horizontal == null)
192+
horizontal = false;
193+
if (maxLevel == null)
194+
maxLevel = 1;
195+
if (maxLevel>1.5) maxLevel=1.5;
196+
else if (maxLevel < 0.3) maxLevel=0.3;
197+
198+
this._osdWindows[monitorIndex]._vbox.remove_all_children();
199+
this._osdWindows[monitorIndex]._hbox.remove_all_children();
200+
201+
this._osdWindows[monitorIndex]._hbox.add_child(this._osdWindows[monitorIndex]._icon);
202+
this._osdWindows[monitorIndex]._hbox.add_child(this._osdWindows[monitorIndex]._vbox);
203+
if (horizontal) {
204+
this._osdWindows[monitorIndex]._label.y_align = Clutter.ActorAlign.CENTER;
205+
this._osdWindows[monitorIndex]._hbox.add_child(this._osdWindows[monitorIndex]._label);
206+
} else {
207+
this._osdWindows[monitorIndex]._label.y_align = Clutter.ActorAlign.FILL;
208+
this._osdWindows[monitorIndex]._vbox.add_child(this._osdWindows[monitorIndex]._label);
209+
}
210+
this._osdWindows[monitorIndex]._level.maximum_value = maxLevel;
211+
this._osdWindows[monitorIndex]._vbox.add_child(this._osdWindows[monitorIndex]._level);
212+
213+
this._osdWindows[monitorIndex].setIcon(icon);
214+
this._osdWindows[monitorIndex].setLabel(label);
215+
this._osdWindows[monitorIndex].setMaxLevel(maxLevel);
216+
this._osdWindows[monitorIndex].setLevel(level);
217+
this._osdWindows[monitorIndex].show();
218+
}
219+
220+
show(monitorIndex, icon, label, level, maxLevel, horizontal, convertIndex) {
221+
if (this._osdWindows.length === 0)
222+
return;
223+
224+
if (monitorIndex !== -1) {
225+
if (convertIndex)
226+
monitorIndex = convertGdkIndex(monitorIndex);
227+
for (let i = 0; i < this._osdWindows.length; i++) {
228+
if (i === monitorIndex)
229+
this._showOsdWindow(i, icon, label, level, maxLevel, horizontal);
230+
else
231+
this._osdWindows[i].cancel();
232+
}
233+
} else {
234+
for (let i = 0; i < this._osdWindows.length; i++)
235+
this._showOsdWindow(i, icon, label, level, maxLevel, horizontal);
236+
}
237+
}
238+
239+
hideAll() {
240+
if (this._osdWindows.length === 0)
241+
return;
242+
243+
for (let i = 0; i < this._osdWindows.length; i++)
244+
this._osdWindows[i].cancel();
245+
}
246+
};
247+
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
# OSD WINDOW FOR SOUND150
2+
# This file is put in the public domain.
3+
# claudiux, 2017
4+
#
5+
#, fuzzy
6+
msgid ""
7+
msgstr ""
8+
"Project-Id-Version: OSD150@claudiux 1.0.0\n"
9+
"Report-Msgid-Bugs-To: https://github.com/linuxmint/cinnamon-spices-"
10+
"extensions/issues\n"
11+
"POT-Creation-Date: 2025-02-09 00:05+0100\n"
12+
"PO-Revision-Date: \n"
13+
"Last-Translator: \n"
14+
"Language-Team: \n"
15+
"Language: \n"
16+
"MIME-Version: 1.0\n"
17+
"Content-Type: text/plain; charset=UTF-8\n"
18+
"Content-Transfer-Encoding: 8bit\n"
19+
20+
#. metadata.json->name
21+
msgid "OSD Window for sound150"
22+
msgstr ""
23+
24+
#. metadata.json->description
25+
msgid "The OSD Window handled by the Enhanced Sound Applet"
26+
msgstr ""
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
# OSD WINDOW FOR SOUND150
2+
# This file is put in the public domain.
3+
# claudiux, 2017
4+
#
5+
#, fuzzy
6+
msgid ""
7+
msgstr ""
8+
"Project-Id-Version: OSD150@claudiux 1.0.0\n"
9+
"Report-Msgid-Bugs-To: https://github.com/linuxmint/cinnamon-spices-"
10+
"extensions/issues\n"
11+
"POT-Creation-Date: 2025-02-09 00:05+0100\n"
12+
"PO-Revision-Date: \n"
13+
"Last-Translator: claudiux\n"
14+
"Language-Team: \n"
15+
"Language: fr\n"
16+
"MIME-Version: 1.0\n"
17+
"Content-Type: text/plain; charset=UTF-8\n"
18+
"Content-Transfer-Encoding: 8bit\n"
19+
"X-Generator: Poedit 3.4.2\n"
20+
21+
#. metadata.json->name
22+
msgid "OSD Window for sound150"
23+
msgstr "Fenêtre OSD pour sound150"
24+
25+
#. metadata.json->description
26+
msgid "The OSD Window handled by the Enhanced Sound Applet"
27+
msgstr "La fenêtre OSD gérée par l'Applet Son améliorée"

OSD150@claudiux/info.json

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
{
2+
"author": "claudiux",
3+
"license": "GPL-3.0"
4+
}

OSD150@claudiux/screenshot.png

14.3 KB
Loading

0 commit comments

Comments
 (0)