1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
|
#!/usr/bin/env bash
# ==================================================
# KoolDots (2026)
# Project URL: https://github.com/LinuxBeginnings
# License: GNU GPLv3
# SPDX-License-Identifier: GPL-3.0-or-later
# ==================================================
# Toggle Waybar clock format between 12H and 24H
WAYBAR_DIR="${XDG_CONFIG_HOME:-$HOME/.config}/waybar"
# Files that hold toggleable clock formats
MODULES_FILES=(
"$WAYBAR_DIR/Modules" # clock, clock#2, clock#3, clock#4, clock#5
"$WAYBAR_DIR/ModulesVertical" # clock#vertical
)
# Nerd Font clock glyph (U+F017) used by the "clock" and "clock#2" formats.
# Spelled out as a codepoint on purpose: a literal glyph here is easy to
# replace with a look-alike from a different Private Use range, which would
# make the patterns below stop matching without any visible difference.
CLOCK_GLYPH=$'\uf017'
# Nerd Font calendar glyph (U+F073), used by the clock#vertical formats
CAL_GLYPH=$'\uf073'
# Clock format pairs. FORMATS_12H[n] and FORMATS_24H[n] belong to the same
# module: toggling comments out the one and uncomments the other.
#
# The strings must match the "format" values in MODULES_FILES *verbatim*,
# including the {:L...} locale prefix and every space. A format that is not
# listed here, or listed with a typo, is silently left on whatever it is
# currently set to - so keep this list in sync when adding or editing a clock
# module.
FORMATS_12H=(
"$CLOCK_GLYPH {:%I:%M %p}" # clock
"$CLOCK_GLYPH {:%I:%M %p}" # clock#2
'{:L%I:%M %p - %d/%b}' # clock#3
'{:L%B | %a %d, %Y | %I:%M %p}' # clock#4
'{:%A, %I:%M %P}' # clock#5
"$CLOCK_GLYPH\n{:%I\n%M\n%p\n\n$CAL_GLYPH \n%d\n%m\n%y}" # clock#vertical
)
FORMATS_24H=(
"$CLOCK_GLYPH {:%H:%M:%S}" # clock
"$CLOCK_GLYPH {:%H:%M}" # clock#2
'{:L%H:%M - %d/%b}' # clock#3
'{:L%B | %a %d, %Y | %H:%M}' # clock#4
'{:%a %d | %H:%M}' # clock#5
"$CLOCK_GLYPH\n{:%H\n%M\n%S\n\n$CAL_GLYPH \n%d\n%m\n%y}" # clock#vertical
)
notify_swaync() {
command -v notify-send >/dev/null 2>&1 || return 0
export XDG_RUNTIME_DIR="${XDG_RUNTIME_DIR:-/run/user/$(id -u)}"
local icon="${XDG_CONFIG_HOME:-$HOME/.config}/swaync/images/note.png"
if [ -z "${DBUS_SESSION_BUS_ADDRESS:-}" ]; then
local bus_path="${XDG_RUNTIME_DIR}/bus"
if [ -S "$bus_path" ]; then
export DBUS_SESSION_BUS_ADDRESS="unix:path=$bus_path"
fi
fi
DBUS_SESSION_BUS_ADDRESS="$DBUS_SESSION_BUS_ADDRESS" XDG_RUNTIME_DIR="$XDG_RUNTIME_DIR" \
notify-send -a "Waybar Time" -u low -t 2000 -i "$icon" "$@" >/dev/null 2>&1 || true
}
# Only work on the files that are actually present
FILES=()
for f in "${MODULES_FILES[@]}"; do
[ -f "$f" ] && FILES+=("$f")
done
if [ "${#FILES[@]}" -eq 0 ]; then
notify_swaync "No Waybar modules file found in: $WAYBAR_DIR"
exit 1
fi
# Escape the characters that are special inside a sed BRE, plus the '#' we use
# as the s/// delimiter. Needed because the formats contain '.', '*' and the
# literal backslashes of clock#vertical.
escape_bre() {
printf '%s' "$1" | sed 's/[][\\.*^$#]/\\&/g'
}
# Comment out / re-enable the "format" line carrying the given format string
comment_out() {
local file="$1" esc
esc=$(escape_bre "$2")
sed -i "s#^\([[:space:]]*\)\(\"format\":[[:space:]]*\"${esc}\".*\)#\1//\2#" "$file"
}
uncomment() {
local file="$1" esc
esc=$(escape_bre "$2")
sed -i "s#^\([[:space:]]*\)//[[:space:]]*\(\"format\":[[:space:]]*\"${esc}\".*\)#\1\2#" "$file"
}
# $1: 12h | 24h
apply_format() {
local target="$1" file i
for file in "${FILES[@]}"; do
for i in "${!FORMATS_12H[@]}"; do
if [ "$target" = "24h" ]; then
comment_out "$file" "${FORMATS_12H[$i]}"
uncomment "$file" "${FORMATS_24H[$i]}"
else
comment_out "$file" "${FORMATS_24H[$i]}"
uncomment "$file" "${FORMATS_12H[$i]}"
fi
done
done
}
# True when any clock module is currently on a 12H format. %I is the 12-hour
# hour and appears in every 12H format; the anchor skips commented lines.
is_12h_active() {
grep -qE '^[[:space:]]*"format":.*%I' "${FILES[@]}"
}
snapshot() {
cat "${FILES[@]}" | cksum
}
# Report formats that are not present in any modules file at all. Catches the
# case where a format above drifts away from the modules files, which would
# otherwise leave that one clock module silently stuck on its old setting.
warn_unknown_formats() {
local i missing=0
for i in "${!FORMATS_12H[@]}"; do
grep -qF "\"${FORMATS_12H[$i]}\"" "${FILES[@]}" ||
{ printf 'Waybar Time: 12H format not found in any modules file: %s\n' "${FORMATS_12H[$i]}" >&2; missing=1; }
grep -qF "\"${FORMATS_24H[$i]}\"" "${FILES[@]}" ||
{ printf 'Waybar Time: 24H format not found in any modules file: %s\n' "${FORMATS_24H[$i]}" >&2; missing=1; }
done
return $missing
}
restart_waybar() {
local manage_with_systemd=0
if command -v systemctl >/dev/null 2>&1; then
if systemctl --user --quiet is-active graphical-session.target 2>/dev/null || systemctl --user --quiet is-active wayland-session@*.target 2>/dev/null; then
if systemctl --user --quiet is-active waybar.service 2>/dev/null || systemctl --user --quiet is-enabled waybar.service 2>/dev/null; then
manage_with_systemd=1
fi
fi
fi
if [ "$manage_with_systemd" -eq 1 ]; then
systemctl --user stop waybar.service >/dev/null 2>&1 || true
fi
pkill -INT -x waybar >/dev/null 2>&1 || true
pkill -INT -x '.waybar-wrapped' >/dev/null 2>&1 || true
sleep 0.2
if pgrep -x waybar >/dev/null 2>&1 || pgrep -x '.waybar-wrapped' >/dev/null 2>&1; then
pkill -9 -x waybar >/dev/null 2>&1 || true
pkill -9 -x '.waybar-wrapped' >/dev/null 2>&1 || true
fi
sleep 0.2
if [ "$manage_with_systemd" -eq 1 ]; then
if ! systemctl --user start waybar.service >/dev/null 2>&1; then
waybar >/dev/null 2>&1 &
fi
else
waybar >/dev/null 2>&1 &
fi
}
warn_unknown_formats || true
before=$(snapshot)
if is_12h_active; then
apply_format 24h
mode="24H"
else
apply_format 12h
mode="12H"
fi
# Nothing replaced means the formats above drifted away from the modules files
if [ "$before" = "$(snapshot)" ]; then
notify_swaync "Clock format unchanged - no known format matched"
printf 'Waybar Time: no clock format matched, nothing changed\n' >&2
exit 1
fi
restart_waybar
sleep 0.3
notify_swaync "Switched to ${mode} format"
printf 'Waybar Time: switched to %s format\n' "$mode"
|