From 1d24a49220e44ab25665ac2344b36f9dd83492a0 Mon Sep 17 00:00:00 2001 From: Jason Fairchild <50913812+Tweekism@users.noreply.github.com> Date: Mon, 4 May 2026 01:22:13 +1000 Subject: [PATCH 1/7] Start of Dash to Panel multi-clock support --- extension.js | 80 ++++++++++++++++++++++++++++++++++++---------------- 1 file changed, 56 insertions(+), 24 deletions(-) diff --git a/extension.js b/extension.js index b38dcc4..5894a47 100644 --- a/extension.js +++ b/extension.js @@ -6,30 +6,41 @@ import { Extension } from "resource:///org/gnome/shell/extensions/extension.js"; import * as Main from "resource:///org/gnome/shell/ui/main.js"; import GLib from "gi://GLib"; import Gio from "gi://Gio"; +import St from 'gi://St'; +import Clutter from 'gi://Clutter'; export default class IsoClock extends Extension { enable() { - const dateMenu = Main.panel.statusArea.dateMenu; + this.originalClockLabel = this.getClockFromPanel(Main.panel) - const clockDisplayBox = dateMenu - .get_children() - .find((x) => x.style_class === "clock-display-box"); - - this.label = clockDisplayBox?.get_children().find( - (x) => x.style_class === "clock" - ); - - if (!this.label) { + if (!this.originalClockLabel) { console.error("No clock label? Aborting."); return; } + // Hide the original clock and create our own + this.isoClockLabel = new St.Label({ + style_class: 'clock', + text: 'Initializing...', + y_align: Clutter.ActorAlign.CENTER + }); + + this.originalClockLabel.get_parent().add_child(this.isoClockLabel); + + // If Dash to Panel is running, get those clock labels too + if (global.dashToPanel) { + this.dashToPanelClocks = []; + global.dashToPanel.panels.forEach(panel => { + this.dashToPanelClocks.push(this.getClockFromPanel(panel)); + }); + } + const gnomeSettings = Gio.Settings.new("org.gnome.desktop.interface"); this.gnomeCalendar = Gio.Settings.new("org.gnome.desktop.calendar"); const override = () => { // Don't do anything if the clock label hasn't actually changed - if (this.newClock == this.label.get_text()) { + if (this.isoTimeString == this.originalClockLabel.get_text()) { return; } @@ -62,23 +73,31 @@ export default class IsoClock extends Extension { // Keep a copy of the default clock text so that we can revert it when the // extension is disabled - this.defaultClock = this.label.get_text(); + this.defaultTimeString = this.originalClockLabel.get_text(); // Set the clock label to our new custom format const now = GLib.DateTime.new_now_local(); - this.newClock = now.format(format); - this.label.set_text(this.newClock); + this.isoTimeString = now.format(format); + this.originalClockLabel.set_text(this.isoTimeString); + this.isoClockLabel.set_text(now.format(format)); + + this.dashToPanelClocks.forEach(clock => { + if (clock) { + clock.set_text(this.isoTimeString); + clock.hide(); + } + }) }; // Whenever the clock label updates override with our custom clock format - this.labelHandleId = this.label.connect("notify::text", override); + this.mainClockHandleId = this.originalClockLabel.connect("notify::text", override); // We also need to know when the "Week Numbers" setting changes, as week numbers // don't appear in the default clock. Trigger a refresh by setting clock back to // its default value. This prevents an edge case where disabling the extension // after a week number setting change causes unexpected behaviour this.calendarHandleId = this.gnomeCalendar.connect("changed::show-weekdate", () => { - this.label.set_text(this.defaultClock); + this.originalClockLabel.set_text(this.defaultTimeString); }) override(); } @@ -89,18 +108,31 @@ export default class IsoClock extends Extension { this.calendarHandleId = null; } - if (this.labelHandleId) { - this.label.disconnect(this.labelHandleId); - this.labelHandleId = null; + if (this.mainClockHandleId) { + this.originalClockLabel.disconnect(this.mainClockHandleId); + this.mainClockHandleId = null; } - if (this.defaultClock) { - this.label.set_text(this.defaultClock); + if (this.defaultTimeString) { + this.originalClockLabel.set_text(this.defaultTimeString); } this.gnomeCalendar = null - this.label = null; - this.newClock = null; - this.defaultClock = null; + this.originalClockLabel = null; + this.isoTimeString = null; + this.defaultTimeString = null; + } + + getClockFromPanel(panel) { + const dateMenu = panel?.statusArea?.dateMenu; + if (!dateMenu) return null; + + const clockDisplayBox = dateMenu + .get_children() + .find((x) => x.style_class === "clock-display-box"); + + return clockDisplayBox?.get_children().find( + (x) => x.style_class === "clock" + ) || null; } } From 46dda3e1109bcd7db7aaaf2eb8ccfb4c95536a07 Mon Sep 17 00:00:00 2001 From: Jason Fairchild <50913812+Tweekism@users.noreply.github.com> Date: Mon, 4 May 2026 12:56:08 +1000 Subject: [PATCH 2/7] Create new clock labels instead of ninja editing the originals --- extension.js | 60 ++++++++++++++++++++++++++-------------------------- 1 file changed, 30 insertions(+), 30 deletions(-) diff --git a/extension.js b/extension.js index 5894a47..c2f6446 100644 --- a/extension.js +++ b/extension.js @@ -18,20 +18,15 @@ export default class IsoClock extends Extension { return; } - // Hide the original clock and create our own - this.isoClockLabel = new St.Label({ - style_class: 'clock', - text: 'Initializing...', - y_align: Clutter.ActorAlign.CENTER - }); + this.isoClocks = [] - this.originalClockLabel.get_parent().add_child(this.isoClockLabel); + // Hide the original clock and create our own + this.isoClocks.push(this.cloneClock(this.originalClockLabel)); - // If Dash to Panel is running, get those clock labels too + // If Dash to Panel is running, clone those too if (global.dashToPanel) { - this.dashToPanelClocks = []; global.dashToPanel.panels.forEach(panel => { - this.dashToPanelClocks.push(this.getClockFromPanel(panel)); + this.isoClocks.push(this.cloneClock(this.getClockFromPanel(panel))); }); } @@ -71,33 +66,23 @@ export default class IsoClock extends Extension { const format = [day, date, week, time].filter(v => v).join(" "); - // Keep a copy of the default clock text so that we can revert it when the - // extension is disabled - this.defaultTimeString = this.originalClockLabel.get_text(); - // Set the clock label to our new custom format const now = GLib.DateTime.new_now_local(); - this.isoTimeString = now.format(format); - this.originalClockLabel.set_text(this.isoTimeString); - this.isoClockLabel.set_text(now.format(format)); - - this.dashToPanelClocks.forEach(clock => { - if (clock) { - clock.set_text(this.isoTimeString); - clock.hide(); - } - }) + this.isoClocks.forEach(clock => { + clock.set_text(now.format(format)); + }); }; // Whenever the clock label updates override with our custom clock format this.mainClockHandleId = this.originalClockLabel.connect("notify::text", override); + // TODO: Update this comment, as it's no longer true // We also need to know when the "Week Numbers" setting changes, as week numbers // don't appear in the default clock. Trigger a refresh by setting clock back to // its default value. This prevents an edge case where disabling the extension // after a week number setting change causes unexpected behaviour this.calendarHandleId = this.gnomeCalendar.connect("changed::show-weekdate", () => { - this.originalClockLabel.set_text(this.defaultTimeString); + override(); }) override(); } @@ -113,14 +98,16 @@ export default class IsoClock extends Extension { this.mainClockHandleId = null; } - if (this.defaultTimeString) { - this.originalClockLabel.set_text(this.defaultTimeString); - } + this.isoClocks.forEach(clock => { + if (clock) { + clock.destroy(); + } + }); + this.isoClocks = []; + this.originalClockLabel.show(); this.gnomeCalendar = null this.originalClockLabel = null; - this.isoTimeString = null; - this.defaultTimeString = null; } getClockFromPanel(panel) { @@ -135,4 +122,17 @@ export default class IsoClock extends Extension { (x) => x.style_class === "clock" ) || null; } + + cloneClock(original) { + const clock = new St.Label({ + style_class: 'clock', + text: 'Initializing...', + y_expand: 0, + y_align: 0 + }); + clock.get_clutter_text().set_y_align(Clutter.ActorAlign.CENTER); + original.get_parent().insert_child_above(clock, original); + // original.hide(); + return clock + } } From 122ea69ffa5745e2637ba5ac86751a43102dd933 Mon Sep 17 00:00:00 2001 From: Jason Fairchild <50913812+Tweekism@users.noreply.github.com> Date: Mon, 4 May 2026 13:43:20 +1000 Subject: [PATCH 3/7] Refactor into createClocks and destroyClocks functions --- extension.js | 39 +++++++++++++++++++++++---------------- 1 file changed, 23 insertions(+), 16 deletions(-) diff --git a/extension.js b/extension.js index c2f6446..f3e384a 100644 --- a/extension.js +++ b/extension.js @@ -19,16 +19,7 @@ export default class IsoClock extends Extension { } this.isoClocks = [] - - // Hide the original clock and create our own - this.isoClocks.push(this.cloneClock(this.originalClockLabel)); - - // If Dash to Panel is running, clone those too - if (global.dashToPanel) { - global.dashToPanel.panels.forEach(panel => { - this.isoClocks.push(this.cloneClock(this.getClockFromPanel(panel))); - }); - } + this.createClocks(); const gnomeSettings = Gio.Settings.new("org.gnome.desktop.interface"); this.gnomeCalendar = Gio.Settings.new("org.gnome.desktop.calendar"); @@ -98,12 +89,7 @@ export default class IsoClock extends Extension { this.mainClockHandleId = null; } - this.isoClocks.forEach(clock => { - if (clock) { - clock.destroy(); - } - }); - this.isoClocks = []; + this.destroyClocks(); this.originalClockLabel.show(); this.gnomeCalendar = null @@ -135,4 +121,25 @@ export default class IsoClock extends Extension { // original.hide(); return clock } + + createClocks() { + // Hide the original clock and create our own + this.isoClocks.push(this.cloneClock(this.originalClockLabel)); + + // If Dash to Panel is running, clone those too + if (global.dashToPanel) { + global.dashToPanel.panels.forEach(panel => { + this.isoClocks.push(this.cloneClock(this.getClockFromPanel(panel))); + }); + } + } + + destroyClocks() { + this.isoClocks.forEach(clock => { + if (clock) { + clock.destroy(); + } + }); + this.isoClocks = []; + } } From 6f507c28b7919fdfb2bc5d24f345816fd752d520 Mon Sep 17 00:00:00 2001 From: Jason Fairchild <50913812+Tweekism@users.noreply.github.com> Date: Mon, 4 May 2026 14:14:22 +1000 Subject: [PATCH 4/7] If Dash to Panel is re-using the main clock, don't clone it twice --- extension.js | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/extension.js b/extension.js index f3e384a..ebcc5af 100644 --- a/extension.js +++ b/extension.js @@ -129,7 +129,11 @@ export default class IsoClock extends Extension { // If Dash to Panel is running, clone those too if (global.dashToPanel) { global.dashToPanel.panels.forEach(panel => { - this.isoClocks.push(this.cloneClock(this.getClockFromPanel(panel))); + const clock = this.getClockFromPanel(panel); + // If Dash to Panel is re-using the main clock, don't clone it again + if (clock !== this.originalClockLabel) { + this.isoClocks.push(this.cloneClock(clock)); + } }); } } From 3ab8922c0269961f68aa8fee8e4bf1854782dbe2 Mon Sep 17 00:00:00 2001 From: Jason Fairchild <50913812+Tweekism@users.noreply.github.com> Date: Mon, 4 May 2026 14:39:47 +1000 Subject: [PATCH 5/7] Remove remaining ninja logic --- extension.js | 37 +++++++++++++++---------------------- 1 file changed, 15 insertions(+), 22 deletions(-) diff --git a/extension.js b/extension.js index ebcc5af..8632e18 100644 --- a/extension.js +++ b/extension.js @@ -11,9 +11,9 @@ import Clutter from 'gi://Clutter'; export default class IsoClock extends Extension { enable() { - this.originalClockLabel = this.getClockFromPanel(Main.panel) + this.mainClock = this.getClockFromPanel(Main.panel) - if (!this.originalClockLabel) { + if (!this.mainClock) { console.error("No clock label? Aborting."); return; } @@ -24,12 +24,7 @@ export default class IsoClock extends Extension { const gnomeSettings = Gio.Settings.new("org.gnome.desktop.interface"); this.gnomeCalendar = Gio.Settings.new("org.gnome.desktop.calendar"); - const override = () => { - // Don't do anything if the clock label hasn't actually changed - if (this.isoTimeString == this.originalClockLabel.get_text()) { - return; - } - + const updateClocks = () => { // Setup the custom clock format based on the clock settings in Gnome Settings let day, date, week, time; @@ -64,18 +59,16 @@ export default class IsoClock extends Extension { }); }; - // Whenever the clock label updates override with our custom clock format - this.mainClockHandleId = this.originalClockLabel.connect("notify::text", override); + // Whenever the main clock label changes, update all our clocks + this.mainClockHandleId = this.mainClock.connect("notify::text", updateClocks); - // TODO: Update this comment, as it's no longer true - // We also need to know when the "Week Numbers" setting changes, as week numbers - // don't appear in the default clock. Trigger a refresh by setting clock back to - // its default value. This prevents an edge case where disabling the extension - // after a week number setting change causes unexpected behaviour + // Also update clocks when the "Week Numbers" setting changes. Week numbers + // don't appear in the default clock, so we'll watch the Gnome Settings + // handle for that. this.calendarHandleId = this.gnomeCalendar.connect("changed::show-weekdate", () => { - override(); + updateClocks(); }) - override(); + updateClocks(); } disable() { @@ -85,15 +78,15 @@ export default class IsoClock extends Extension { } if (this.mainClockHandleId) { - this.originalClockLabel.disconnect(this.mainClockHandleId); + this.mainClock.disconnect(this.mainClockHandleId); this.mainClockHandleId = null; } this.destroyClocks(); - this.originalClockLabel.show(); + this.mainClock.show(); this.gnomeCalendar = null - this.originalClockLabel = null; + this.mainClock = null; } getClockFromPanel(panel) { @@ -124,14 +117,14 @@ export default class IsoClock extends Extension { createClocks() { // Hide the original clock and create our own - this.isoClocks.push(this.cloneClock(this.originalClockLabel)); + this.isoClocks.push(this.cloneClock(this.mainClock)); // If Dash to Panel is running, clone those too if (global.dashToPanel) { global.dashToPanel.panels.forEach(panel => { const clock = this.getClockFromPanel(panel); // If Dash to Panel is re-using the main clock, don't clone it again - if (clock !== this.originalClockLabel) { + if (clock !== this.mainClock) { this.isoClocks.push(this.cloneClock(clock)); } }); From e2f714c0f95c44998dace7be53fe5c51eaf50e5d Mon Sep 17 00:00:00 2001 From: Jason Fairchild <50913812+Tweekism@users.noreply.github.com> Date: Mon, 4 May 2026 15:53:22 +1000 Subject: [PATCH 6/7] Move iso format logic into its own method --- extension.js | 67 ++++++++++++++++++++++++++-------------------------- 1 file changed, 34 insertions(+), 33 deletions(-) diff --git a/extension.js b/extension.js index 8632e18..fead3de 100644 --- a/extension.js +++ b/extension.js @@ -12,50 +12,20 @@ import Clutter from 'gi://Clutter'; export default class IsoClock extends Extension { enable() { this.mainClock = this.getClockFromPanel(Main.panel) - if (!this.mainClock) { console.error("No clock label? Aborting."); return; } + this.gnomeCalendar = Gio.Settings.new("org.gnome.desktop.calendar"); this.isoClocks = [] this.createClocks(); - const gnomeSettings = Gio.Settings.new("org.gnome.desktop.interface"); - this.gnomeCalendar = Gio.Settings.new("org.gnome.desktop.calendar"); - const updateClocks = () => { - // Setup the custom clock format based on the clock settings in Gnome Settings - let day, date, week, time; - - if (gnomeSettings.get_boolean("clock-show-weekday")) { - day = "%A" - } - - if (gnomeSettings.get_boolean("clock-show-date")) { - date = "%Y-%m-%d"; - } - - if (this.gnomeCalendar.get_boolean("show-weekdate")) { - week = "W%V-%u" - } - - if (gnomeSettings.get_string("clock-format") === '24h') { - time = "%H:%M"; - } else { - time = "%I:%M %p"; - } - - if (gnomeSettings.get_boolean("clock-show-seconds")) { - time = time.replace("%M","%M:%S"); - } - - const format = [day, date, week, time].filter(v => v).join(" "); - - // Set the clock label to our new custom format + // Set our clock labels to our new custom format const now = GLib.DateTime.new_now_local(); this.isoClocks.forEach(clock => { - clock.set_text(now.format(format)); + clock.set_text(now.format(this.getIsoFormat())); }); }; @@ -139,4 +109,35 @@ export default class IsoClock extends Extension { }); this.isoClocks = []; } + + getIsoFormat() { + // Setup the custom clock format based on the clock settings in Gnome Settings + const gnomeSettings = Gio.Settings.new("org.gnome.desktop.interface"); + + let day, date, week, time; + + if (gnomeSettings.get_boolean("clock-show-weekday")) { + day = "%A" + } + + if (gnomeSettings.get_boolean("clock-show-date")) { + date = "%Y-%m-%d"; + } + + if (this.gnomeCalendar.get_boolean("show-weekdate")) { + week = "W%V-%u" + } + + if (gnomeSettings.get_string("clock-format") === '24h') { + time = "%H:%M"; + } else { + time = "%I:%M %p"; + } + + if (gnomeSettings.get_boolean("clock-show-seconds")) { + time = time.replace("%M","%M:%S"); + } + + return [day, date, week, time].filter(v => v).join(" "); + } } From 36355db7a48468e78963de92fd3f994c05be6aa8 Mon Sep 17 00:00:00 2001 From: Jason Fairchild <50913812+Tweekism@users.noreply.github.com> Date: Mon, 4 May 2026 16:11:48 +1000 Subject: [PATCH 7/7] Enable hiding and showing of original clock labels On enable will hide default clocks and on disable bring them back again --- extension.js | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/extension.js b/extension.js index fead3de..430a182 100644 --- a/extension.js +++ b/extension.js @@ -54,7 +54,6 @@ export default class IsoClock extends Extension { this.destroyClocks(); - this.mainClock.show(); this.gnomeCalendar = null this.mainClock = null; } @@ -88,6 +87,7 @@ export default class IsoClock extends Extension { createClocks() { // Hide the original clock and create our own this.isoClocks.push(this.cloneClock(this.mainClock)); + this.mainClock.hide(); // If Dash to Panel is running, clone those too if (global.dashToPanel) { @@ -96,6 +96,7 @@ export default class IsoClock extends Extension { // If Dash to Panel is re-using the main clock, don't clone it again if (clock !== this.mainClock) { this.isoClocks.push(this.cloneClock(clock)); + clock.hide(); } }); } @@ -108,6 +109,12 @@ export default class IsoClock extends Extension { } }); this.isoClocks = []; + + global.dashToPanel?.panels?.forEach(panel => { + this.getClockFromPanel(panel)?.show(); + }); + + this.mainClock.show(); } getIsoFormat() {