roundabout,
created on Sunday, 20 July 2025, 10:30:58 (1753007458),
received on Saturday, 26 July 2025, 07:40:05 (1753515605)
Author identity: vlad <vlad.muntoiu@gmail.com>
b6ed74922ffa0511460b8765f47a716772d42a20
applets/clock/__init__.py
@@ -1,14 +1,28 @@
import os from pathlib import Pathimport panorama_panel import gi gi.require_version("Gtk", "4.0") from gi.repository import Gtk, GLibfrom gi.repository import Gtk, GLib, Gio, GdkSECOND_PLACEHOLDERS = ("%c", "%s", "%S", "%T", "%X") module_directory = Path(__file__).resolve().parent @Gtk.Template(filename=str(module_directory / "panorama-clock-options.ui")) class ClockOptions(Gtk.Window): __gtype_name__ = "ClockOptions" format_entry: Gtk.Entry = Gtk.Template.Child() def __init__(self, **kwargs): super().__init__(**kwargs) class ClockApplet(panorama_panel.Applet): name = "Clock" description = "Read the current time and date"
@@ -35,19 +49,78 @@ class ClockApplet(panorama_panel.Applet):
# Some placeholders require second precision, but not all of them. If not required, # use minute precision self.has_second_precision = any(placeholder in self.formatting for placeholder in SECOND_PLACEHOLDERS) self.next_update = None self.set_time() self.context_menu = self.make_context_menu() right_click_controller = Gtk.GestureClick() right_click_controller.set_button(3) right_click_controller.connect("pressed", self.show_context_menu) self.add_controller(right_click_controller) action_group = Gio.SimpleActionGroup() options_action = Gio.SimpleAction.new("options", None) options_action.connect("activate", self.show_options) action_group.add_action(options_action) self.insert_action_group("applet", action_group) self.options_window = None def make_context_menu(self): menu = Gio.Menu() menu.append("Clock _options", "applet.options") context_menu = Gtk.PopoverMenu.new_from_model(menu) context_menu.set_has_arrow(False) context_menu.set_parent(self) context_menu.set_halign(Gtk.Align.START) context_menu.set_flags(Gtk.PopoverMenuFlags.NESTED) return context_menu def show_context_menu(self, gesture, n_presses, x, y): rect = Gdk.Rectangle() rect.x = int(x) rect.y = int(y) rect.width = 1 rect.height = 1 self.context_menu.set_pointing_to(rect) self.context_menu.popup() def update_formatting(self, entry): self.formatting = entry.get_text() # Some placeholders require second precision, but not all of them. If not required, # use minute precision self.has_second_precision = any(placeholder in self.formatting for placeholder in SECOND_PLACEHOLDERS) if self.next_update is not None: GLib.source_remove(self.next_update) self.next_update = Noneself.set_time() def show_options(self, _0=None, _1=None): if not self.options_window: self.options_window = ClockOptions() self.options_window.format_entry.set_text(self.formatting) self.options_window.format_entry.connect("changed", self.update_formatting) self.options_window.present() def set_time(self): datetime = GLib.DateTime.new_now_local() self.label.set_text(datetime.format(self.formatting))formatted_time = datetime.format(self.formatting) if formatted_time is not None: self.label.set_text(datetime.format(self.formatting)) else: self.label.set_text("Invalid time formatting") return Falseif self.has_second_precision: current_ms = GLib.DateTime.new_now_local().get_microsecond() // 1000 GLib.timeout_add(1000 - current_ms + 1, self.set_time) # 1ms is added to ensure the clock is updatedself.next_update = GLib.timeout_add(1000 - current_ms + 1, self.set_time) # 1ms is added to ensure the clock is updatedelse: now = GLib.DateTime.new_now_local() current_ms = now.get_second() * 1000 + now.get_microsecond() // 1000 GLib.timeout_add(60000 - current_ms + 1, self.set_time)self.next_update = GLib.timeout_add(60000 - current_ms + 1, self.set_time)return False # Do not rerun the current timeout; a new one has been scheduled def get_config(self):
applets/clock/panorama-clock-options.cmb
@@ -0,0 +1,6 @@
<?xml version='1.0' encoding='UTF-8' standalone='no'?> <!DOCTYPE cambalache-project SYSTEM "cambalache-project.dtd"> <!-- Created with Cambalache 0.96.1 --> <cambalache-project version="0.96.0" target_tk="gtk-4.0"> <ui template-class="ClockOptions" filename="panorama-clock-options.ui" sha256="d183407b347a36fc200e673b53bfbfff8682eca6dfe7d89bcaacca565f7248a8"/> </cambalache-project>
applets/clock/panorama-clock-options.ui
@@ -0,0 +1,70 @@
<?xml version='1.0' encoding='UTF-8'?> <!-- Created with Cambalache 0.96.1 --> <interface> <!-- interface-name panorama-clock-options.ui --> <requires lib="gtk" version="4.0"/> <template class="ClockOptions" parent="GtkWindow"> <property name="default-height">320</property> <property name="default-width">576</property> <property name="title" translatable="yes">Clock options</property> <child> <object class="GtkScrolledWindow"> <child> <object class="GtkViewport"> <child> <object class="GtkBox"> <property name="margin-bottom">32</property> <property name="margin-end">32</property> <property name="margin-start">32</property> <property name="margin-top">32</property> <property name="orientation">vertical</property> <property name="spacing">4</property> <child> <object class="GtkFrame"> <property name="label-widget"> <object class="GtkLabel"> <property name="label" translatable="yes">Formatting</property> <attributes> <attribute name="weight" value="bold"/> </attributes> </object> </property> <child> <object class="GtkListBox"> <property name="activate-on-single-click">False</property> <property name="selection-mode">none</property> <child> <object class="GtkListBoxRow"> <child> <object class="GtkBox"> <child> <object class="GtkLabel"> <property name="halign">start</property> <property name="hexpand">True</property> <property name="label" translatable="yes">Time format <span font_weight="light">Using <tt>strftime()</tt> syntax. Note: using seconds may increase system load.</span></property> <property name="use-markup">True</property> <property name="wrap">True</property> </object> </child> <child> <object class="GtkEntry" id="format_entry"> <property name="placeholder-text">strftime format</property> </object> </child> </object> </child> </object> </child> </object> </child> </object> </child> </object> </child> </object> </child> </object> </child> </template> </interface>