Coverage Report

Created: 2026-07-16 06:55

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/tmux/window-clock.c
Line
Count
Source
1
/* $OpenBSD: window-clock.c,v 1.35 2026/07/14 17:17:18 nicm Exp $ */
2
3
/*
4
 * Copyright (c) 2009 Nicholas Marriott <nicholas.marriott@gmail.com>
5
 *
6
 * Permission to use, copy, modify, and distribute this software for any
7
 * purpose with or without fee is hereby granted, provided that the above
8
 * copyright notice and this permission notice appear in all copies.
9
 *
10
 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11
 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12
 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13
 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14
 * WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER
15
 * IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
16
 * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17
 */
18
19
#include <sys/types.h>
20
21
#include <stdlib.h>
22
#include <string.h>
23
#include <time.h>
24
25
#include "tmux.h"
26
27
static struct screen *window_clock_init(struct window_mode_entry *,
28
         struct cmdq_item *, struct cmd_find_state *,
29
         struct args *);
30
static void window_clock_free(struct window_mode_entry *);
31
static void window_clock_resize(struct window_mode_entry *, u_int, u_int);
32
static void window_clock_key(struct window_mode_entry *, struct client *,
33
         struct session *, struct winlink *, key_code,
34
         struct mouse_event *);
35
36
static void window_clock_timer_callback(int, short, void *);
37
static void window_clock_draw_screen(struct window_mode_entry *);
38
39
const struct window_mode window_clock_mode = {
40
  .name = "clock-mode",
41
42
  .init = window_clock_init,
43
  .free = window_clock_free,
44
  .resize = window_clock_resize,
45
  .key = window_clock_key,
46
};
47
48
struct window_clock_mode_data {
49
  struct screen   screen;
50
  time_t      tim;
51
  struct event    timer;
52
};
53
54
const char window_clock_table[14][5][5] = {
55
  { { 1,1,1,1,1 }, /* 0 */
56
    { 1,0,0,0,1 },
57
    { 1,0,0,0,1 },
58
    { 1,0,0,0,1 },
59
    { 1,1,1,1,1 } },
60
  { { 0,0,0,0,1 }, /* 1 */
61
    { 0,0,0,0,1 },
62
    { 0,0,0,0,1 },
63
    { 0,0,0,0,1 },
64
    { 0,0,0,0,1 } },
65
  { { 1,1,1,1,1 }, /* 2 */
66
    { 0,0,0,0,1 },
67
    { 1,1,1,1,1 },
68
    { 1,0,0,0,0 },
69
    { 1,1,1,1,1 } },
70
  { { 1,1,1,1,1 }, /* 3 */
71
    { 0,0,0,0,1 },
72
    { 1,1,1,1,1 },
73
    { 0,0,0,0,1 },
74
    { 1,1,1,1,1 } },
75
  { { 1,0,0,0,1 }, /* 4 */
76
    { 1,0,0,0,1 },
77
    { 1,1,1,1,1 },
78
    { 0,0,0,0,1 },
79
    { 0,0,0,0,1 } },
80
  { { 1,1,1,1,1 }, /* 5 */
81
    { 1,0,0,0,0 },
82
    { 1,1,1,1,1 },
83
    { 0,0,0,0,1 },
84
    { 1,1,1,1,1 } },
85
  { { 1,1,1,1,1 }, /* 6 */
86
    { 1,0,0,0,0 },
87
    { 1,1,1,1,1 },
88
    { 1,0,0,0,1 },
89
    { 1,1,1,1,1 } },
90
  { { 1,1,1,1,1 }, /* 7 */
91
    { 0,0,0,0,1 },
92
    { 0,0,0,0,1 },
93
    { 0,0,0,0,1 },
94
    { 0,0,0,0,1 } },
95
  { { 1,1,1,1,1 }, /* 8 */
96
    { 1,0,0,0,1 },
97
    { 1,1,1,1,1 },
98
    { 1,0,0,0,1 },
99
    { 1,1,1,1,1 } },
100
  { { 1,1,1,1,1 }, /* 9 */
101
    { 1,0,0,0,1 },
102
    { 1,1,1,1,1 },
103
    { 0,0,0,0,1 },
104
    { 1,1,1,1,1 } },
105
  { { 0,0,0,0,0 }, /* : */
106
    { 0,0,1,0,0 },
107
    { 0,0,0,0,0 },
108
    { 0,0,1,0,0 },
109
    { 0,0,0,0,0 } },
110
  { { 1,1,1,1,1 }, /* A */
111
    { 1,0,0,0,1 },
112
    { 1,1,1,1,1 },
113
    { 1,0,0,0,1 },
114
    { 1,0,0,0,1 } },
115
  { { 1,1,1,1,1 }, /* P */
116
    { 1,0,0,0,1 },
117
    { 1,1,1,1,1 },
118
    { 1,0,0,0,0 },
119
    { 1,0,0,0,0 } },
120
  { { 1,0,0,0,1 }, /* M */
121
    { 1,1,0,1,1 },
122
    { 1,0,1,0,1 },
123
    { 1,0,0,0,1 },
124
    { 1,0,0,0,1 } },
125
};
126
127
static void
128
window_clock_start_timer(struct window_mode_entry *wme)
129
0
{
130
0
  struct window_clock_mode_data *data = wme->data;
131
0
  struct timeval       tv;
132
0
  struct timespec      ts;
133
0
  long         delay;
134
135
0
  clock_gettime(CLOCK_REALTIME, &ts);
136
0
  delay = 1000000 - (ts.tv_nsec / 1000);
137
138
0
  tv.tv_sec = delay / 1000000;
139
0
  tv.tv_usec = delay % 1000000;
140
0
  if (tv.tv_sec < 0 || (tv.tv_sec == 0 && tv.tv_usec <= 0)) {
141
0
    tv.tv_sec = 1;
142
0
    tv.tv_usec = 0;
143
0
  }
144
0
  evtimer_add(&data->timer, &tv);
145
0
}
146
147
static void
148
window_clock_timer_callback(__unused int fd, __unused short events, void *arg)
149
0
{
150
0
  struct window_mode_entry  *wme = arg;
151
0
  struct window_pane    *wp = wme->wp;
152
0
  struct window_clock_mode_data *data = wme->data;
153
0
  struct tm      now, then;
154
0
  time_t         t;
155
156
0
  evtimer_del(&data->timer);
157
158
0
  t = time(NULL);
159
0
  gmtime_r(&t, &now);
160
0
  gmtime_r(&data->tim, &then);
161
162
0
  if (now.tm_sec != then.tm_sec) {
163
0
    data->tim = t;
164
0
    window_clock_draw_screen(wme);
165
0
    wp->flags |= PANE_REDRAW;
166
0
  }
167
168
0
  window_clock_start_timer(wme);
169
0
}
170
171
static struct screen *
172
window_clock_init(struct window_mode_entry *wme,
173
    __unused struct cmdq_item *item, __unused struct cmd_find_state *fs,
174
    __unused struct args *args)
175
0
{
176
0
  struct window_pane    *wp = wme->wp;
177
0
  struct window_clock_mode_data *data;
178
0
  struct screen     *s;
179
180
0
  wme->data = data = xcalloc(1, sizeof *data);
181
0
  data->tim = time(NULL);
182
183
0
  evtimer_set(&data->timer, window_clock_timer_callback, wme);
184
0
  window_clock_start_timer(wme);
185
186
0
  s = &data->screen;
187
0
  screen_init(s, screen_size_x(&wp->base), screen_size_y(&wp->base), 0);
188
0
  s->mode &= ~MODE_CURSOR;
189
190
0
  window_clock_draw_screen(wme);
191
192
0
  return (s);
193
0
}
194
195
static void
196
window_clock_free(struct window_mode_entry *wme)
197
0
{
198
0
  struct window_clock_mode_data *data = wme->data;
199
200
0
  evtimer_del(&data->timer);
201
0
  screen_free(&data->screen);
202
0
  free(data);
203
0
}
204
205
static void
206
window_clock_resize(struct window_mode_entry *wme, u_int sx, u_int sy)
207
0
{
208
0
  struct window_clock_mode_data *data = wme->data;
209
0
  struct screen     *s = &data->screen;
210
211
0
  screen_resize(s, sx, sy, 0);
212
0
  window_clock_draw_screen(wme);
213
0
}
214
215
static void
216
window_clock_key(struct window_mode_entry *wme, __unused struct client *c,
217
    __unused struct session *s, __unused struct winlink *wl,
218
    __unused key_code key, __unused struct mouse_event *m)
219
0
{
220
0
  window_pane_reset_mode(wme->wp);
221
0
}
222
223
static void
224
window_clock_draw_screen(struct window_mode_entry *wme)
225
0
{
226
0
  struct window_pane    *wp = wme->wp;
227
0
  struct window     *w = wp->window;
228
0
  struct window_clock_mode_data *data = wme->data;
229
0
  struct screen_write_ctx    ctx;
230
0
  int        colour, style;
231
0
  struct screen     *s = &data->screen;
232
0
  struct grid_cell     gc;
233
0
  struct format_tree    *ft;
234
0
  char         tim[64], *ptr;
235
0
  time_t         t;
236
0
  struct tm     *tm;
237
0
  u_int        i, j, x, y, idx;
238
239
0
  ft = format_create_defaults(NULL, NULL, NULL, NULL, wp);
240
0
  style_apply(&gc, w->options, "clock-mode-colour", ft);
241
0
  format_free(ft);
242
0
  colour = gc.fg;
243
0
  style = options_get_number(w->options, "clock-mode-style");
244
245
0
  screen_write_start(&ctx, s);
246
247
0
  t = time(NULL);
248
0
  tm = localtime(&t);
249
0
  if (style == 0 || style == 2) {
250
0
    if (style == 2)
251
0
      strftime(tim, sizeof tim, "%l:%M:%S ", localtime(&t));
252
0
    else
253
0
      strftime(tim, sizeof tim, "%l:%M ", localtime(&t));
254
0
    if (tm->tm_hour >= 12)
255
0
      strlcat(tim, "PM", sizeof tim);
256
0
    else
257
0
      strlcat(tim, "AM", sizeof tim);
258
0
  } else {
259
0
    if (style == 3)
260
0
      strftime(tim, sizeof tim, "%H:%M:%S", tm);
261
0
    else
262
0
      strftime(tim, sizeof tim, "%H:%M", tm);
263
0
  }
264
265
0
  screen_write_clearscreen(&ctx, 8);
266
267
0
  if (screen_size_x(s) < 6 * strlen(tim) || screen_size_y(s) < 6) {
268
0
    if (screen_size_x(s) >= strlen(tim) && screen_size_y(s) != 0) {
269
0
      x = (screen_size_x(s) / 2) - (strlen(tim) / 2);
270
0
      y = screen_size_y(s) / 2;
271
0
      screen_write_cursormove(&ctx, x, y, 0);
272
273
0
      memcpy(&gc, &grid_default_cell, sizeof gc);
274
0
      gc.flags |= GRID_FLAG_NOPALETTE;
275
0
      gc.fg = colour;
276
0
      screen_write_puts(&ctx, &gc, "%s", tim);
277
0
    }
278
279
0
    screen_write_stop(&ctx);
280
0
    return;
281
0
  }
282
283
0
  x = (screen_size_x(s) / 2) - 3 * strlen(tim);
284
0
  y = (screen_size_y(s) / 2) - 3;
285
286
0
  memcpy(&gc, &grid_default_cell, sizeof gc);
287
0
  gc.flags |= GRID_FLAG_NOPALETTE;
288
0
  gc.bg = colour;
289
0
  gc.fg = colour;
290
0
  for (ptr = tim; *ptr != '\0'; ptr++) {
291
0
    if (*ptr >= '0' && *ptr <= '9')
292
0
      idx = *ptr - '0';
293
0
    else if (*ptr == ':')
294
0
      idx = 10;
295
0
    else if (*ptr == 'A')
296
0
      idx = 11;
297
0
    else if (*ptr == 'P')
298
0
      idx = 12;
299
0
    else if (*ptr == 'M')
300
0
      idx = 13;
301
0
    else {
302
0
      x += 6;
303
0
      continue;
304
0
    }
305
306
0
    for (j = 0; j < 5; j++) {
307
0
      for (i = 0; i < 5; i++) {
308
0
        screen_write_cursormove(&ctx, x + i, y + j, 0);
309
0
        if (window_clock_table[idx][j][i])
310
0
          screen_write_putc(&ctx, &gc, '#');
311
0
      }
312
0
    }
313
0
    x += 6;
314
0
  }
315
316
0
  screen_write_stop(&ctx);
317
0
}