Skip to content

Commit c9c943c

Browse files
KAMI911claude
andcommitted
feat(calendarium@kami911): auto-detect primary location from system timezone
When "Use manual location" is off, the desklet no longer hard-codes Budapest. It resolves the computer's system IANA timezone (via GLib.TimeZone, /etc/timezone or the /etc/localtime symlink) and looks up approximate coordinates for it in tzdata's zone1970.tab / zone.tab. Budapest remains the fallback when the timezone cannot be resolved. The settings panel wording is updated accordingly, and the result is cached for the desklet's lifetime. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01PNasJnrStmVjJgJ8MULzcG
1 parent f57d757 commit c9c943c

4 files changed

Lines changed: 122 additions & 9 deletions

File tree

calendarium@kami911/files/calendarium@kami911/desklet.js

Lines changed: 102 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -87,7 +87,9 @@ const Calendars = imports.calendars.Calendars;
8787

8888
Geocoder.init(DESKLET_DIR);
8989

90-
// ── Default location: Budapest, Hungary ───────────────────────────────────
90+
// ── Default location ─────────────────────────────────────────────────────
91+
// Used only as a last-resort fallback when the computer's system timezone
92+
// cannot be resolved to coordinates (see _systemLocation). Budapest, Hungary.
9193
const DEFAULT_LAT = 47.4979;
9294
const DEFAULT_LON = 19.0402;
9395
const FOLKDAY_DIR = DESKLET_DIR + "/data/folkdays";
@@ -332,6 +334,99 @@ CalendariumDesklet.prototype = {
332334
return this._getCityUtcOffsetHours(this.primary_tz);
333335
},
334336

337+
/**
338+
* The computer's own IANA timezone name (e.g. "Europe/Budapest"), or null
339+
* if it cannot be determined.
340+
*/
341+
_systemTimezoneName: function() {
342+
try {
343+
let id = GLib.TimeZone.new_local().get_identifier();
344+
if (id && id.indexOf("/") !== -1) return id;
345+
} catch (e) {}
346+
try {
347+
let [ok, contents] = GLib.file_get_contents("/etc/timezone");
348+
if (ok) {
349+
let s = ((contents instanceof Uint8Array)
350+
? new TextDecoder().decode(contents)
351+
: imports.byteArray.toString(contents)).trim();
352+
if (s.indexOf("/") !== -1) return s;
353+
}
354+
} catch (e) {}
355+
try {
356+
let target = Gio.File.new_for_path("/etc/localtime")
357+
.query_info("standard::symlink-target",
358+
Gio.FileQueryInfoFlags.NOFOLLOW_SYMLINKS, null)
359+
.get_symlink_target();
360+
let m = target && target.match(/zoneinfo\/(.+)$/);
361+
if (m) return m[1];
362+
} catch (e) {}
363+
return null;
364+
},
365+
366+
/**
367+
* Parse an ISO 6709 "±DDMM[SS]±DDDMM[SS]" string (as used in tzdata's
368+
* zone1970.tab) to { lat, lon } decimal degrees, or null.
369+
*/
370+
_parseIso6709: function(s) {
371+
let m = s.match(/^([+-]\d{2})(\d{2})(\d{2})?([+-]\d{3})(\d{2})(\d{2})?$/);
372+
if (!m) return null;
373+
let latSign = m[1][0] === "-" ? -1 : 1;
374+
let lonSign = m[4][0] === "-" ? -1 : 1;
375+
let lat = parseInt(m[1], 10)
376+
+ latSign * (parseInt(m[2], 10) + (m[3] ? parseInt(m[3], 10) : 0) / 60) / 60;
377+
let lon = parseInt(m[4], 10)
378+
+ lonSign * (parseInt(m[5], 10) + (m[6] ? parseInt(m[6], 10) : 0) / 60) / 60;
379+
return { lat: Math.round(lat * 10000) / 10000,
380+
lon: Math.round(lon * 10000) / 10000 };
381+
},
382+
383+
/**
384+
* Approximate coordinates of a system IANA timezone, looked up in the
385+
* tzdata zone1970.tab / zone.tab table. Returns { lat, lon } or null.
386+
*/
387+
_tzTabCoords: function(tzName) {
388+
let paths = ["/usr/share/zoneinfo/zone1970.tab",
389+
"/usr/share/zoneinfo/zone.tab"];
390+
for (let p = 0; p < paths.length; p++) {
391+
let text;
392+
try {
393+
let [ok, contents] = GLib.file_get_contents(paths[p]);
394+
if (!ok) continue;
395+
text = (contents instanceof Uint8Array)
396+
? new TextDecoder().decode(contents)
397+
: imports.byteArray.toString(contents);
398+
} catch (e) { continue; }
399+
let lines = text.split("\n");
400+
for (let i = 0; i < lines.length; i++) {
401+
if (!lines[i] || lines[i][0] === "#") continue;
402+
let cols = lines[i].split("\t");
403+
if (cols.length < 3) continue;
404+
if (cols[2].trim() !== tzName) continue;
405+
return this._parseIso6709(cols[1].trim());
406+
}
407+
}
408+
return null;
409+
},
410+
411+
/**
412+
* Approximate location of the computer, derived from its system IANA
413+
* timezone. Result is { lat, lon, tz }; cached for the desklet's lifetime.
414+
* Falls back to DEFAULT_LAT/DEFAULT_LON (Budapest) when the timezone
415+
* cannot be resolved to coordinates.
416+
*/
417+
_systemLocation: function() {
418+
if (this._sysLoc) return this._sysLoc;
419+
let loc = { lat: DEFAULT_LAT, lon: DEFAULT_LON, tz: null };
420+
let tzName = this._systemTimezoneName();
421+
loc.tz = tzName;
422+
if (tzName) {
423+
let coords = this._tzTabCoords(tzName);
424+
if (coords) { loc.lat = coords.lat; loc.lon = coords.lon; }
425+
}
426+
this._sysLoc = loc;
427+
return loc;
428+
},
429+
335430
/**
336431
* Format a UTC offset in hours as a "UTC±H" or "UTC±H:MM" string.
337432
*/
@@ -1115,8 +1210,9 @@ CalendariumDesklet.prototype = {
11151210
if (!this.show_sun) return;
11161211

11171212
// Primary location
1118-
let lat = this.use_manual_location ? this.latitude : DEFAULT_LAT;
1119-
let lon = this.use_manual_location ? this.longitude : DEFAULT_LON;
1213+
let sysLoc = this._systemLocation();
1214+
let lat = this.use_manual_location ? this.latitude : sysLoc.lat;
1215+
let lon = this.use_manual_location ? this.longitude : sysLoc.lon;
11201216
let sun = Sun.getSunTimes(now, lat, lon, this._getPrimaryUtcOffsetHours());
11211217

11221218
let sunriseStr = this._sunStr(sun, "sunrise");
@@ -1260,8 +1356,9 @@ CalendariumDesklet.prototype = {
12601356
this._moonRiseRow.visible = this.show_moonrise;
12611357
if (!this.show_moonrise) return;
12621358

1263-
let lat = this.use_manual_location ? this.latitude : DEFAULT_LAT;
1264-
let lon = this.use_manual_location ? this.longitude : DEFAULT_LON;
1359+
let sysLoc = this._systemLocation();
1360+
let lat = this.use_manual_location ? this.latitude : sysLoc.lat;
1361+
let lon = this.use_manual_location ? this.longitude : sysLoc.lon;
12651362
let mt = Sun.getMoonTimes(now, lat, lon, this._getPrimaryUtcOffsetHours());
12661363

12671364
let riseStr = mt.moonrise || _("No data");

calendarium@kami911/files/calendarium@kami911/po/calendarium@kami911.pot

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -652,7 +652,13 @@ msgid "Show equinox and solstice"
652652
msgstr ""
653653

654654
#. settings-schema.json->use-manual-location->description
655-
msgid "Use manual location (default: Budapest, Hungary)"
655+
msgid "Use manual location"
656+
msgstr ""
657+
658+
#. settings-schema.json->use-manual-location->tooltip
659+
msgid ""
660+
"When off, the location is detected automatically from the computer's system "
661+
"timezone (falling back to Budapest, Hungary if it cannot be determined)."
656662
msgstr ""
657663

658664
#. settings-schema.json->location-search->description

calendarium@kami911/files/calendarium@kami911/po/hu.po

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -667,8 +667,17 @@ msgid "Show equinox and solstice"
667667
msgstr "Napéjegyenlőség és napforduló megjelenítése"
668668

669669
#. settings-schema.json->use-manual-location->description
670-
msgid "Use manual location (default: Budapest, Hungary)"
671-
msgstr "Manuális helyszín megadása (alap: Budapest, Magyarország)"
670+
msgid "Use manual location"
671+
msgstr "Manuális helyszín megadása"
672+
673+
#. settings-schema.json->use-manual-location->tooltip
674+
msgid ""
675+
"When off, the location is detected automatically from the computer's system "
676+
"timezone (falling back to Budapest, Hungary if it cannot be determined)."
677+
msgstr ""
678+
"Kikapcsolva a helyszín automatikusan a számítógép rendszeridőzónája alapján "
679+
"kerül meghatározásra (ha ez nem sikerül, Budapest, Magyarország az "
680+
"alapértelmezés)."
672681

673682
#. settings-schema.json->location-search->description
674683
msgid "Search city to auto-fill coordinates"

calendarium@kami911/files/calendarium@kami911/settings-schema.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -354,7 +354,8 @@
354354
"use-manual-location": {
355355
"type": "checkbox",
356356
"default": false,
357-
"description": "Use manual location (default: Budapest, Hungary)"
357+
"description": "Use manual location",
358+
"tooltip": "When off, the location is detected automatically from the computer's system timezone (falling back to Budapest, Hungary if it cannot be determined)."
358359
},
359360
"location-search": {
360361
"type": "entry",

0 commit comments

Comments
 (0)