init
This commit is contained in:
@@ -1,3 +1,18 @@
|
||||
# lxpanel-dtime
|
||||
|
||||
Patch for lxpanel that allows displaying erisian time
|
||||
Patch for lxpanel that allows displaying erisian time. Preparing **lxpanel 0.11.1** for build and installation, featuring an enhanced Digital Clock: display of Erisian (Discordian) time via formatting codes.
|
||||
|
||||
Build scripts for Debian 13 and Gentoo. Written by Qwen 3.8 27B.
|
||||
|
||||
| Code | Value |
|
||||
|-------|-------------------------------------------------------------|
|
||||
| `%eY` | discordian yaer (YOLD) |
|
||||
| `%ey` | erisian year (YOLD−3000) |
|
||||
| `%eS` | name of season (Chaos…Aftermath) |
|
||||
| `%eE` | season number (1–5) |
|
||||
| `%ed` | day of the season (1–73) |
|
||||
| `%eh` | erisian hour (0–9) |
|
||||
| `%em` | erisian minute (00–99) |
|
||||
| `%es` | erisian second (00–99) |
|
||||
| `%ew` | discordian name of the day of the week |
|
||||
| `%ut` | unix time |
|
||||
@@ -0,0 +1,73 @@
|
||||
# lxpanel с эридианскими часами (Digital Clock)
|
||||
|
||||
Готовит к сборке и установке **lxpanel 0.11.1** с расширенным Digital Clock:
|
||||
эридианское (дискордианское) время + unix time через коды форматирования, плюс
|
||||
оптимизация вычислений (кэш даты дня, вывод дек. времени вычитанием).
|
||||
|
||||
## Состав
|
||||
|
||||
| Файл | Назначение |
|
||||
|----------------------|--------------------------------------------------------|
|
||||
| `build.sh` | скрипт: проверка deps → скачивание исходника → патч → сборка → установка |
|
||||
| `erisian-time.patch` | патч: `plugins/dclock.c` + `po/lxpanel.pot` |
|
||||
|
||||
## Быстрый старт (Gentoo)
|
||||
|
||||
```sh
|
||||
tar xf lxpanel-gentoo.tar.gz # если передаёте каталог архивом
|
||||
cd lxpanel-gentoo
|
||||
|
||||
./build.sh --deps # установит ebuild'ы зависимостей и соберёт
|
||||
# далее, если нужно:
|
||||
./build.sh --prefix=/opt/lxpanel # в другую директорию
|
||||
./build.sh --no-install # только собрать
|
||||
```
|
||||
|
||||
Всё (кроме `--deps`) работает и без root; установка идёт в `$PREFIX` (по умолчанию `/usr`).
|
||||
|
||||
## Зависимости (Gentoo ebuild)
|
||||
|
||||
Обязательные (проверяются `pkg-config`):
|
||||
`gtk+-3.0`, `libfm-gtk3`, `libwnck-3.0`, `keybinder-3.0`, `glib-2.0`, `x11`.
|
||||
|
||||
Опциональные (для динамических плагинов по умолчанию):
|
||||
`libmenu-cache` (меню), `net-misc/curl` + `dev-libs/libxml2` (weather),
|
||||
`net-wireless/libiw` (netstat), `media-libs/alsa-lib` (volume).
|
||||
Если плагин без своей зависимости — скрипт **сам отключит** этот плагин, сборка пройдёт.
|
||||
|
||||
Инструменты сборки: `sys-devel/autoconf`, `sys-devel/automake`, `sys-devel/libtool`,
|
||||
`sys-apps/intltool`.
|
||||
|
||||
> Альтернатива: `emerge lxpanel` поставит все зависимости сразу (stock-версию),
|
||||
> а `./build.sh` поверх соберёт нашу.
|
||||
|
||||
## Что меняется в Digital Clock (коды форматирования)
|
||||
|
||||
В поле *Clock Format* / *Tooltip Format* (помимо стандартных `strftime`):
|
||||
|
||||
| Код | Значение |
|
||||
|-------|-------------------------------------------------------------|
|
||||
| `%eY` | эридианский год (YOLD) |
|
||||
| `%ey` | краткий год (YOLD − 3000; григорианский год − 1834) |
|
||||
| `%eS` | сезон — название (Chaos…Aftermath) |
|
||||
| `%eE` | сезон — порядковый № (1–5) |
|
||||
| `%ed` | день сезона (1–73); в день Тиба — `tib` |
|
||||
| `%eh` | дек. час (0–9) |
|
||||
| `%em` | дек. минута (00–99) |
|
||||
| `%es` | дек. секунда (00–99) |
|
||||
| `%ew` | день недели (один из пяти); в день Тиба — `St. Tib's Day` |
|
||||
| `%ut` | unix time |
|
||||
|
||||
`%%` — литеральный `%`. Пример формата:
|
||||
`%eY.%eE.%ed %eh:%em %ew (%Y.%m.%d %R)`
|
||||
|
||||
## Примечания
|
||||
|
||||
* Скрипт качает исходник с **закреплённого коммита** `4dec3d0d` (тот, против
|
||||
которого сделан патч) — `https://codeload.github.com/lxde/lxpanel/tar.gz/4dec3d0d…`.
|
||||
Не подставляйте тег `0.11.1` — это 3 коммита раньше, патч может не лечь.
|
||||
* `make install` кладёт бинарь/плагины/иконки в `$PREFIX`. Если lxpanel уже
|
||||
стоит через `emerge`, наш `make install` перезапишет файлы; для «чистоты»
|
||||
портрeе можно `emerge -C lxpanel` или собрать в отдельный `--prefix`.
|
||||
* Эридианские часы — **встроенный** плагин (`plugins/dclock.c`), собирается в
|
||||
сам `lxpanel` (не отдельный `.so`), поэтому для него не нужны опции `--with-plugins`.
|
||||
Executable
+70
@@ -0,0 +1,70 @@
|
||||
#!/usr/bin/env bash
|
||||
#
|
||||
# build_deb.sh — build the lxpanel .deb with the Erisian/Unix-time
|
||||
# Digital Clock.
|
||||
#
|
||||
# Source: the official Debian source package (3.0 quilt) is unpacked with
|
||||
# the Debian tool "dpkg-source -x", and our modification is applied on top:
|
||||
#
|
||||
# erisian-time.patch (Digital Clock: christian / erisian / unix time)
|
||||
#
|
||||
# One-time setup (needs root):
|
||||
# sudo apt-get update
|
||||
# sudo apt-get install -y dpkg-dev apt-utils build-essential autoconf automake libtool
|
||||
# sudo apt-get build-dep lxpanel
|
||||
#
|
||||
# Build (no root needed):
|
||||
# ./build_deb.sh
|
||||
#
|
||||
set -euo pipefail
|
||||
|
||||
# Use system build tools only — a foreign toolchain earlier in PATH (e.g.
|
||||
# ~/linuxbrew) breaks the final link (libX11 -> libxcb undefined refs).
|
||||
export PATH="/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin"
|
||||
|
||||
HERE="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||
cd "$HERE"
|
||||
|
||||
PKG=lxpanel
|
||||
VER=0.11.1
|
||||
DEBREV=1
|
||||
SRC_DIR="$PKG-$VER"
|
||||
DSC="${PKG}_${VER}-${DEBREV}.dsc"
|
||||
ORIG_TAR="${PKG}_${VER}.orig.tar.gz"
|
||||
DEB_TAR="${PKG}_${VER}-${DEBREV}.debian.tar.xz"
|
||||
PATCH=erisian-time.patch
|
||||
POOL="http://deb.debian.org/debian/pool/main/l/lxpanel"
|
||||
|
||||
# --- 0. sanity -------------------------------------------------------------
|
||||
for t in dpkg-source curl patch; do
|
||||
command -v "$t" >/dev/null 2>&1 || { echo "ERROR: '$t' not found (install dpkg-dev/curl/patch)."; exit 1; }
|
||||
done
|
||||
|
||||
# --- 1. make sure the Debian source tree is unpacked (quilt patches applied) --
|
||||
if [ ! -d "$SRC_DIR/debian" ]; then
|
||||
echo ">> Unpacking Debian source ($DSC) ..."
|
||||
[ -f "$DSC" ] || curl -fsS -o "$DSC" "$POOL/$DSC"
|
||||
[ -f "$ORIG_TAR" ] || curl -fsS -o "$ORIG_TAR" "$POOL/$ORIG_TAR"
|
||||
[ -f "$DEB_TAR" ] || curl -fsS -o "$DEB_TAR" "$POOL/$DEB_TAR"
|
||||
dpkg-source -x "$DSC"
|
||||
fi
|
||||
|
||||
# --- 2. apply our modification (idempotent) --------------------------------
|
||||
if grep -q "dclock_expand_codes" "$SRC_DIR/plugins/dclock.c"; then
|
||||
echo ">> $PATCH already applied — skipping."
|
||||
else
|
||||
echo ">> Applying $PATCH ..."
|
||||
( cd "$SRC_DIR" && patch -p1 < "$HERE/$PATCH" )
|
||||
fi
|
||||
|
||||
# --- 3. build the binary .deb --------------------------------------------
|
||||
echo ">> Building .deb with dpkg-buildpackage ..."
|
||||
( cd "$SRC_DIR" && dpkg-buildpackage -b -us -uc )
|
||||
|
||||
# --- 4. report -----------------------------------------------------------
|
||||
echo
|
||||
echo ">> Built packages (in $HERE):"
|
||||
ls -1 "$HERE"/*.deb
|
||||
echo
|
||||
echo "Install with:"
|
||||
echo " sudo dpkg -i $(ls -1 "$HERE"/${PKG}_*.deb | tr '\n' ' ')"
|
||||
Executable
+143
@@ -0,0 +1,143 @@
|
||||
#!/usr/bin/env bash
|
||||
#
|
||||
# build.sh — build & install lxpanel with the Erisian/Unix-time Digital Clock.
|
||||
#
|
||||
# Target: Gentoo Linux (out-of-tree source build). The same script works on any
|
||||
# autotools-based distro; only the emerge convenience list is Gentoo-specific.
|
||||
#
|
||||
# The build:
|
||||
# 1. verifies build dependencies (pkg-config; optionally `emerge`s them),
|
||||
# 2. downloads lxpanel at the EXACT commit the patch was generated against,
|
||||
# 3. applies erisian-time.patch (idempotent),
|
||||
# 4. runs autogen.sh + configure + make, and (optionally) `make install`.
|
||||
#
|
||||
# Usage:
|
||||
# ./build.sh # build & install to /usr (default)
|
||||
# ./build.sh --deps # also `emerge` the required ebuilds first
|
||||
# ./build.sh --prefix=/opt/lxpanel
|
||||
# ./build.sh --no-install # build only, do not install
|
||||
# ./build.sh --clean # re-download the source fresh
|
||||
#
|
||||
set -euo pipefail
|
||||
|
||||
HERE="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||
cd "$HERE"
|
||||
|
||||
# Prefer system build tools: a foreign toolchain earlier in PATH (e.g. a
|
||||
# linuxbrew gcc/ld) can break the final link. On a clean Gentoo this is a no-op.
|
||||
export PATH="/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin"
|
||||
|
||||
# --- pinned upstream commit (erisian-time.patch was generated against this) --
|
||||
COMMIT=4dec3d0d3d8f9e2a9d14dd1b099d378289b67db4
|
||||
SRC_URL="https://codeload.github.com/lxde/lxpanel/tar.gz/${COMMIT}"
|
||||
SRC_TAR="lxpanel-src.tar.gz"
|
||||
SRC_DIR="lxpanel-${COMMIT}"
|
||||
PATCH=erisian-time.patch
|
||||
|
||||
PREFIX=/usr
|
||||
DO_DEPS=0
|
||||
DO_INSTALL=1
|
||||
DO_CLEAN=0
|
||||
|
||||
for arg in "$@"; do
|
||||
case "$arg" in
|
||||
--deps) DO_DEPS=1 ;;
|
||||
--no-install) DO_INSTALL=0 ;;
|
||||
--clean) DO_CLEAN=1 ;;
|
||||
--prefix=*) PREFIX="${arg#--prefix=}" ;;
|
||||
*) echo "Unknown option: $arg (see header)"; exit 1 ;;
|
||||
esac
|
||||
done
|
||||
|
||||
# run priv-privileged commands with sudo only when not root
|
||||
if [ "$(id -u)" = 0 ]; then SUDO=""; else SUDO="sudo"; fi
|
||||
|
||||
# --- 1. dependencies --------------------------------------------------------
|
||||
# pkg-config modules that configure.ac requires for the GTK3 (default) build.
|
||||
REQUIRED_PC=(gtk+-3.0 libfm-gtk3 libwnck-3.0 keybinder-3.0 glib-2.0 x11)
|
||||
OPTIONAL_PC=(libmenu-cache) # without: menu routines are disabled (warning)
|
||||
|
||||
# Gentoo ebuilds providing the above + the default dynamic-plugin deps.
|
||||
# (best-effort; the pkg-config checks below are the authoritative gate)
|
||||
EBUILDS=(
|
||||
sys-devel/autoconf sys-devel/automake sys-devel/libtool sys-apps/intltool
|
||||
dev-libs/glib x11-libs/gtk+ gnome-extra/libfm-gtk gnome-libs/libwnck
|
||||
x11-libs/keybinder gnome-extra/libmenu-cache x11-libs/libX11
|
||||
net-misc/curl dev-libs/libxml2 net-wireless/libiw media-libs/alsa-lib
|
||||
)
|
||||
|
||||
if [ "$DO_DEPS" = 1 ]; then
|
||||
echo ">> Installing dependencies via emerge ..."
|
||||
$SUDO emerge -av "${EBUILDS[@]}"
|
||||
fi
|
||||
|
||||
echo ">> Checking dependencies (pkg-config) ..."
|
||||
missing=0
|
||||
for m in "${REQUIRED_PC[@]}"; do
|
||||
if pkg-config --exists "$m" 2>/dev/null; then echo " [ok] $m"
|
||||
else echo " [MISS] $m"; missing=1; fi
|
||||
done
|
||||
for m in "${OPTIONAL_PC[@]}"; do
|
||||
if pkg-config --exists "$m" 2>/dev/null; then echo " [ok] $m"
|
||||
else echo " [opt] $m (menu support will be disabled)"; fi
|
||||
done
|
||||
if [ "$missing" = 1 ]; then
|
||||
echo; echo "Missing required dependencies — install the ebuilds above (or rerun with --deps)."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# --- 2. source (pinned commit) ---------------------------------------------
|
||||
if [ "$DO_CLEAN" = 1 ]; then rm -rf "$SRC_DIR" "$SRC_TAR"; fi
|
||||
if [ ! -d "$SRC_DIR" ]; then
|
||||
echo ">> Downloading lxpanel @ ${COMMIT:0:7} ..."
|
||||
curl -fsSL -o "$SRC_TAR" "$SRC_URL"
|
||||
tar xf "$SRC_TAR"
|
||||
fi
|
||||
cd "$SRC_DIR"
|
||||
|
||||
# --- 3. apply the Erisian patch (idempotent) --------------------------------
|
||||
if grep -q "dclock_expand_codes" plugins/dclock.c; then
|
||||
echo ">> ${PATCH} already applied — skipping."
|
||||
else
|
||||
echo ">> Applying ${PATCH} ..."
|
||||
patch -p1 < "$HERE/$PATCH"
|
||||
fi
|
||||
|
||||
# --- 4. build --------------------------------------------------------------
|
||||
# Auto-disable dynamic plugins whose optional deps are absent, so the build
|
||||
# succeeds on a minimal system. The Erisian clock (plugins/dclock.c) is a
|
||||
# built-in plugin compiled into lxpanel itself and is ALWAYS built.
|
||||
EXCLUDES=""
|
||||
if ! command -v curl-config >/dev/null 2>&1 || ! pkg-config --exists libxml-2.0 2>/dev/null; then
|
||||
EXCLUDES="${EXCLUDES},-weather"; echo " [note] weather plugin disabled (need: net-misc/curl, dev-libs/libxml2)"
|
||||
fi
|
||||
if [ ! -e /usr/include/iwlib.h ] && [ ! -e /usr/include/linux/iwlib.h ]; then
|
||||
EXCLUDES="${EXCLUDES},-netstat"; echo " [note] netstat plugin disabled (need: net-wireless/libiw)"
|
||||
fi
|
||||
WITH_PLUGINS_OPT=""
|
||||
[ -n "$EXCLUDES" ] && WITH_PLUGINS_OPT="--with-plugins=all${EXCLUDES}"
|
||||
|
||||
echo ">> autogen.sh ..."
|
||||
sh ./autogen.sh
|
||||
# GTK3 is NOT the configure default (upstream defaults to gtk+-2.0), so
|
||||
# --enable-gtk3=yes is required for the modern gtk+-3.0 build.
|
||||
echo ">> configure --enable-gtk3=yes --prefix=$PREFIX $WITH_PLUGINS_OPT"
|
||||
./configure --enable-gtk3=yes --prefix="$PREFIX" $WITH_PLUGINS_OPT
|
||||
echo ">> make ..."
|
||||
make
|
||||
if [ "$DO_INSTALL" = 1 ]; then
|
||||
echo ">> make install ..."
|
||||
$SUDO make install
|
||||
fi
|
||||
|
||||
echo
|
||||
if [ "$DO_INSTALL" = 1 ]; then
|
||||
echo ">> Done. lxpanel installed under $PREFIX."
|
||||
else
|
||||
echo ">> Done. (built only — not installed)"
|
||||
fi
|
||||
echo " Configure the Digital Clock (Clock Format) with the Erisian/unix codes, e.g.:"
|
||||
echo " %eY.%eE.%ed %eh:%em:%es %ew"
|
||||
echo " Codes: %eY year / %ey short-year / %eS season / %eE season# / %ed day"
|
||||
echo " %eh:%em:%es hour:min:sec / %ew weekday / %ut unix time"
|
||||
echo " St Tib's day (leap year): %ed=tib, %ew=St. Tib's Day"
|
||||
@@ -0,0 +1,264 @@
|
||||
diff --git a/plugins/dclock.c b/plugins/dclock.c
|
||||
index 1a7fe187..2b87a287 100644
|
||||
--- a/plugins/dclock.c
|
||||
+++ b/plugins/dclock.c
|
||||
@@ -169,6 +169,202 @@ static void dclock_timer_set(DClockPlugin * dc, struct timeval *current_time)
|
||||
dc->timer = g_timeout_add(milliseconds, (GSourceFunc) dclock_update_display, (gpointer) dc);
|
||||
}
|
||||
|
||||
+/* Erisian (Discordian) calendar support, ported from dtime-js
|
||||
+ * (https://gitlab.com/zlax/dtime-js).
|
||||
+ * A year has five 73-day seasons plus St. Tib's Day in leap years.
|
||||
+ * A day has ten decimal hours, each a hundred decimal minutes of a hundred
|
||||
+ * decimal seconds (one decimal second equals 864 christian milliseconds).
|
||||
+ */
|
||||
+typedef struct {
|
||||
+ int yold; /* Erisian year (YOLD) */
|
||||
+ int season; /* 0-4 */
|
||||
+ int day; /* 1-73 within the season */
|
||||
+ int hour; /* 0-9 decimal hour */
|
||||
+ int minute; /* 0-99 decimal minute */
|
||||
+ int second; /* 0-99 decimal second */
|
||||
+ int st_tibs; /* 1 on St. Tib's Day */
|
||||
+ char season_name[16]; /* e.g. "Bureaucracy" */
|
||||
+ char weekday_name[32]; /* one of five */
|
||||
+} DClockErisTime;
|
||||
+
|
||||
+/* Easter Island winter time offset used by dtime-js, in seconds. */
|
||||
+#define DCLOCK_ERIS_TZ_OFFSET (-5 * 60 * 60)
|
||||
+
|
||||
+static const char *dclock_eris_seasons[5] = {
|
||||
+ "Chaos", "Discord", "Confusion", "Bureaucracy", "Aftermath"
|
||||
+};
|
||||
+
|
||||
+static const char *dclock_eris_weekdays[5] = {
|
||||
+ "Sweetmorn", "Boomtime", "Pungenday", "Prickle-Prickle", "Setting Orange"
|
||||
+};
|
||||
+
|
||||
+/* Cumulative days before each month (January = index 0); index 12 = total
|
||||
+ * days in the year. Turns a Gregorian date into a day-of-year by lookup. */
|
||||
+static const unsigned short dclock_eris_cum_common[13] = {
|
||||
+ 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334, 365
|
||||
+};
|
||||
+static const unsigned short dclock_eris_cum_leap[13] = {
|
||||
+ 0, 31, 60, 91, 121, 152, 182, 213, 244, 274, 305, 335, 366
|
||||
+};
|
||||
+
|
||||
+static int dclock_eris_leap(int year)
|
||||
+{
|
||||
+ return (year % 4 == 0) && ((year % 100 != 0) || (year % 400 == 0));
|
||||
+}
|
||||
+
|
||||
+/* Day-of-year (1-based) from a Gregorian date, via the cumulative-day table. */
|
||||
+static int dclock_eris_day_of_year(int day, int month, int year)
|
||||
+{
|
||||
+ const unsigned short * cum = dclock_eris_leap(year)
|
||||
+ ? dclock_eris_cum_leap
|
||||
+ : dclock_eris_cum_common;
|
||||
+ return (int)(cum[month - 1] + day);
|
||||
+}
|
||||
+
|
||||
+/* Cached Erisian "day anchor". The Erisian date depends only on the (offset)
|
||||
+ * UTC calendar day, so it changes at most once per day. This structure is
|
||||
+ * refreshed only when that day rolls over; between refreshes the decimal time
|
||||
+ * is derived cheaply (a subtraction from day_start, no modulo). */
|
||||
+typedef struct {
|
||||
+ int64_t day_start; /* shifted unix sec of 00:00:00 of the current day */
|
||||
+ int64_t next; /* shifted unix sec at which the date changes */
|
||||
+ int yold, season, day, st_tibs;
|
||||
+ char weekday_name[32];
|
||||
+ int valid;
|
||||
+} DClockErisDay;
|
||||
+
|
||||
+static DClockErisDay eris_day = { 0 };
|
||||
+
|
||||
+static void dclock_eris_now(const struct timeval *now, DClockErisTime *e);
|
||||
+static char *dclock_expand_codes(const char *fmt, const DClockErisTime *eris,
|
||||
+ long long unix_sec);
|
||||
+
|
||||
+/* Compute the Erisian date (cached; refreshed only when the shifted UTC day
|
||||
+ * changes) and the decimal time (every call) for the current moment. */
|
||||
+static void dclock_eris_now(const struct timeval *now, DClockErisTime *e)
|
||||
+{
|
||||
+ time_t shifted_sec = (time_t)now->tv_sec + DCLOCK_ERIS_TZ_OFFSET;
|
||||
+
|
||||
+ /* Refresh the cached Erisian date only when the shifted UTC day changes —
|
||||
+ * at most once per day. The recompute branch is rare, so mark it unlikely
|
||||
+ * to keep the common cache-hit path lean. */
|
||||
+ if (!eris_day.valid || __builtin_expect(shifted_sec >= eris_day.next, 0)) {
|
||||
+ struct tm utc;
|
||||
+ int dom, mon, year, doy, st_tibs;
|
||||
+ int season, day, yold, sec_since_midnight;
|
||||
+
|
||||
+ gmtime_r(&shifted_sec, &utc);
|
||||
+ dom = utc.tm_mday;
|
||||
+ mon = utc.tm_mon + 1;
|
||||
+ year = utc.tm_year + 1900;
|
||||
+
|
||||
+ doy = dclock_eris_day_of_year(dom, mon, year);
|
||||
+ st_tibs = dclock_eris_leap(year) && (doy == 60);
|
||||
+ if (dclock_eris_leap(year) && doy > 60)
|
||||
+ doy--;
|
||||
+ season = doy / 73;
|
||||
+ day = doy % 73;
|
||||
+ if (day == 0) {
|
||||
+ season--;
|
||||
+ day = 73;
|
||||
+ }
|
||||
+ yold = year + 1166;
|
||||
+
|
||||
+ /* Anchor of the current shifted UTC day (00:00:00) and its end. */
|
||||
+ sec_since_midnight = utc.tm_hour * 3600 + utc.tm_min * 60 + utc.tm_sec;
|
||||
+ eris_day.day_start = (int64_t)shifted_sec - sec_since_midnight;
|
||||
+ eris_day.next = eris_day.day_start + 86400;
|
||||
+
|
||||
+ eris_day.yold = yold;
|
||||
+ eris_day.season = season;
|
||||
+ eris_day.day = day;
|
||||
+ eris_day.st_tibs = st_tibs;
|
||||
+ if (st_tibs)
|
||||
+ eris_day.weekday_name[0] = '\0';
|
||||
+ else
|
||||
+ snprintf(eris_day.weekday_name, sizeof(eris_day.weekday_name),
|
||||
+ "%s", dclock_eris_weekdays[(doy - 1) % 5]);
|
||||
+ eris_day.valid = 1;
|
||||
+ }
|
||||
+
|
||||
+ e->yold = eris_day.yold;
|
||||
+ e->season = eris_day.season;
|
||||
+ e->day = eris_day.day;
|
||||
+ e->st_tibs = eris_day.st_tibs;
|
||||
+ snprintf(e->season_name, sizeof(e->season_name), "%s",
|
||||
+ dclock_eris_seasons[eris_day.season]);
|
||||
+ memcpy(e->weekday_name, eris_day.weekday_name, sizeof(e->weekday_name));
|
||||
+
|
||||
+ /* Decimal time: seconds (and ms) into the current day, derived from the
|
||||
+ * cached day_start by subtraction (no modulo). ds = decimal-second 0-99999. */
|
||||
+ int64_t secs_into_day = (int64_t)shifted_sec - eris_day.day_start;
|
||||
+ int64_t ms_into_day = secs_into_day * 1000 + (int64_t)(now->tv_usec / 1000);
|
||||
+ int64_t ds = ms_into_day / 864;
|
||||
+ e->hour = (int)(ds / 10000);
|
||||
+ e->minute = (int)((ds % 10000) / 100);
|
||||
+ e->second = (int)(ds % 100);
|
||||
+}
|
||||
+
|
||||
+/* Expand the non-strftime codes (%e* and %ut) in a format string, leaving the
|
||||
+ * remaining % codes for strftime(). Returns a newly allocated string. */
|
||||
+static char *dclock_expand_codes(const char *fmt, const DClockErisTime *eris,
|
||||
+ long long unix_sec)
|
||||
+{
|
||||
+ GString *s = g_string_new(NULL);
|
||||
+ const char *p;
|
||||
+
|
||||
+ if (fmt == NULL)
|
||||
+ return g_string_free(s, FALSE);
|
||||
+
|
||||
+ for (p = fmt; *p; ) {
|
||||
+ int advanced = 0;
|
||||
+ if (*p == '%') {
|
||||
+ if (p[1] == '%') {
|
||||
+ g_string_append(s, "%%"); /* literal % — leave for strftime() */
|
||||
+ advanced = 2;
|
||||
+ }
|
||||
+ else if (p[1] == 'e') {
|
||||
+ switch (p[2]) {
|
||||
+ case 'Y': g_string_append_printf(s, "%d", eris->yold); advanced = 3; break;
|
||||
+ case 'y': g_string_append_printf(s, "%d", eris->yold - 3000); advanced = 3; break;
|
||||
+ case 'S': g_string_append(s, eris->season_name); advanced = 3; break;
|
||||
+ case 'E': g_string_append_printf(s, "%d", eris->season + 1); advanced = 3; break;
|
||||
+ case 'd':
|
||||
+ if (eris->st_tibs)
|
||||
+ g_string_append(s, "tib");
|
||||
+ else
|
||||
+ g_string_append_printf(s, "%d", eris->day);
|
||||
+ advanced = 3;
|
||||
+ break;
|
||||
+ case 'h': g_string_append_printf(s, "%d", eris->hour); advanced = 3; break;
|
||||
+ case 'm': g_string_append_printf(s, "%02d", eris->minute); advanced = 3; break;
|
||||
+ case 's': g_string_append_printf(s, "%02d", eris->second); advanced = 3; break;
|
||||
+ case 'w':
|
||||
+ if (eris->st_tibs)
|
||||
+ g_string_append(s, "St. Tib's Day");
|
||||
+ else
|
||||
+ g_string_append(s, eris->weekday_name);
|
||||
+ advanced = 3;
|
||||
+ break;
|
||||
+ default: break;
|
||||
+ }
|
||||
+ }
|
||||
+ else if (p[1] == 'u' && p[2] == 't') {
|
||||
+ g_string_append_printf(s, "%lld", unix_sec);
|
||||
+ advanced = 3;
|
||||
+ }
|
||||
+ }
|
||||
+ if (advanced) {
|
||||
+ p += advanced;
|
||||
+ continue;
|
||||
+ }
|
||||
+ g_string_append_c(s, *p);
|
||||
+ p++;
|
||||
+ }
|
||||
+
|
||||
+ return g_string_free(s, FALSE);
|
||||
+}
|
||||
+
|
||||
/* Periodic timer callback.
|
||||
* Also used during initialization and configuration change to do a redraw. */
|
||||
static gboolean dclock_update_display(DClockPlugin * dc)
|
||||
@@ -183,15 +379,24 @@ static gboolean dclock_update_display(DClockPlugin * dc)
|
||||
dclock_timer_set(dc, &now);
|
||||
current_time = localtime(&now.tv_sec);
|
||||
|
||||
- /* Determine the content of the clock label and tooltip. */
|
||||
- char clock_value[64];
|
||||
- char tooltip_value[64];
|
||||
+ /* Determine the content of the clock label and tooltip.
|
||||
+ * Compute the Erisian date/time once (cached date, cheap decimal time), then
|
||||
+ * expand the Erisian/unix codes in both formats before strftime. */
|
||||
+ DClockErisTime eris;
|
||||
+ dclock_eris_now(&now, &eris);
|
||||
+ char * expanded_clock = dclock_expand_codes(dc->clock_format, &eris, (long long)now.tv_sec);
|
||||
+ char * expanded_tooltip = dclock_expand_codes(dc->tooltip_format, &eris, (long long)now.tv_sec);
|
||||
+
|
||||
+ char clock_value[128];
|
||||
+ char tooltip_value[128];
|
||||
clock_value[0] = '\0';
|
||||
if (dc->clock_format != NULL)
|
||||
- strftime(clock_value, sizeof(clock_value), dc->clock_format, current_time);
|
||||
+ strftime(clock_value, sizeof(clock_value), expanded_clock, current_time);
|
||||
tooltip_value[0] = '\0';
|
||||
if (dc->tooltip_format != NULL)
|
||||
- strftime(tooltip_value, sizeof(tooltip_value), dc->tooltip_format, current_time);
|
||||
+ strftime(tooltip_value, sizeof(tooltip_value), expanded_tooltip, current_time);
|
||||
+ g_free(expanded_clock);
|
||||
+ g_free(expanded_tooltip);
|
||||
|
||||
/* When we write the clock value, it causes the panel to do a full relayout.
|
||||
* Since this function may be called too often while the timing experiment is underway,
|
||||
@@ -435,6 +640,9 @@ static GtkWidget *dclock_configure(LXPanel *panel, GtkWidget *p)
|
||||
_("Clock Format"), &dc->clock_format, CONF_TYPE_STR,
|
||||
_("Tooltip Format"), &dc->tooltip_format, CONF_TYPE_STR,
|
||||
_("Format codes: man 3 strftime; %n for line break"), NULL, CONF_TYPE_TRIM,
|
||||
+ _("Erisian/unix: %eY year %ey short-year %eS season %eE season# %ed day "
|
||||
+ "%eh:%em:%es hour:min:sec %ew weekday (St Tib's day: %ed=tib, %ew=St. Tib's Day) "
|
||||
+ "%ut unix time"), NULL, CONF_TYPE_TRIM,
|
||||
_("Action when clicked (default: display calendar)"), &dc->action, CONF_TYPE_STR,
|
||||
_("Bold font"), &dc->bold, CONF_TYPE_BOOL,
|
||||
_("Tooltip only"), &dc->icon_only, CONF_TYPE_BOOL,
|
||||
diff --git a/po/lxpanel.pot b/po/lxpanel.pot
|
||||
index dc6b1b07..e6e86067 100644
|
||||
--- a/po/lxpanel.pot
|
||||
+++ b/po/lxpanel.pot
|
||||
@@ -716,6 +716,12 @@ msgstr ""
|
||||
msgid "Format codes: man 3 strftime; %n for line break"
|
||||
msgstr ""
|
||||
|
||||
+#: ../plugins/dclock.c
|
||||
+msgid "Erisian/unix: %eY year %ey short-year %eS season %eE season# %ed day "
|
||||
+"%eh:%em:%es hour:min:sec %ew weekday (St Tib's day: %ed=tib, %ew=St. Tib's Day) "
|
||||
+"%ut unix time"
|
||||
+msgstr ""
|
||||
+
|
||||
#: ../plugins/dclock.c:438
|
||||
msgid "Action when clicked (default: display calendar)"
|
||||
msgstr ""
|
||||
Reference in New Issue
Block a user