I’m making a top bar like waybar using gtk4-layer-shell
. Is there any way to display current time with seconds without using polling script? How gnome-clocks does the same?
Well, the GNOME Shell top bar — and possibly Clocks as well — uses the GnomeWallClock
facility of libgnome-desktop (which is written in C) to display its own clock. The library class emits a signal when the time changes, telling the label widget in the top bar to update itself. Here are the relevant bits of js/ui/dateMenu.js
in gnome-shell
:
export const DateMenuButton = GObject.registerClass(
class DateMenuButton extends PanelMenu.Button {
_init() {
let hbox;
super._init(0.5);
this._clockDisplay = new St.Label({style_class: 'clock'});
this._clockDisplay.clutter_text.y_align = Clutter.ActorAlign.CENTER;
this._clockDisplay.clutter_text.ellipsize = Pango.EllipsizeMode.NONE;
// ...
this._clock = new GnomeDesktop.WallClock();
this._clock.bind_property('clock', this._clockDisplay, 'text', GObject.BindingFlags.SYNC_CREATE);
this._clock.connect('notify::timezone', this._updateTimeZone.bind(this));
gnome-wall-clock.c
ultimately uses gnome-datetime-source.c
(also in libgnome-desktop) to generate clock update events either once per second or once per minute, depending whether the seconds display is enabled for the clock.
You don’t have to use a C library to display a clock — JS has robust support for time by way of its Date
class, which is also extremely user-friendly.
// Get a long-form string representation of the current local time
Date() // "Tue Dec 31 2024 19:58:04 GMT-0500 (Eastern Standard Time)"
// Get a date object representing the current time (in UTC by default)
let d = new Date()
// d's value is now 2025-01-01T00:59:24.741Z
d.toLocaleString() // "12/31/2024, 7:59:24 PM"
d.toLocaleDateString() // "12/31/2024"
d.toLocaleTimeString() // "7:59:24 PM"
// There's also Date.now() which returns a UNIX epoch time value,
// and is very fast if all you want to do is compare time values,
// e.g.
const start = Date.now();
// ... stuff ...
if (Date.now() - start > 1000)
console.log("Stuff took more than one second.");
// You can also pass those epoch time values to the Date constructor
// to get Date objects for specific times
let ten_seconds_from_now = new Date(Date.now() + 10000);
The reason the GNOME Shell clock isn’t written in pure JS is, I’m sure, for performance. But even if it’s written in C, at some point something is going to have to poll a clock source on a timer to get updated values at regular intervals. So, you could use JS’s setInterval()
to schedule that regular polling in JavaScript instead. e.g.
let cur_time;
function update_time() {
t = new Date().toLocaleTimeString();
if (t === cur_time)
return;
cur_time = t;
console.log(cur_time);
}
let clock_intvl;
setTimeout(() => {
clock_intvl = setInterval(update_time, 1000);
}, 1000 - new Date().getMilliseconds());
(The initial setTimeout()
with that bit of math at the end tries to get the setInterval()
timer scheduled to fire around the start of each second.)
In gjs, setInterval
is implemented as a GLib.Source
(same as what gnome-datetime-source.c
uses), so it may require that the main loop be running before it will fire. (At least, it didn’t have any effect when I tried it in gjs
interactively, unlike in the Chrome console where it will immediately start logging the current time.)
A running clock_intvl = setInterval(...)
can be stopped with clearInterval(clock_intvl)
.
You can see the source of gnome-shell/js/ui/dateMenu.js
and gnome-desktop/libgnome-desktop/
(focus on gnome-datetime-source.c
and gnome-wall-clock.c
) for more detail about the way it’s done in GNOME Shell.
This topic was automatically closed 30 days after the last reply. New replies are no longer allowed.