Coverage Report

Created: 2026-05-30 06:39

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/tmux/window-clock.c
Line
Count
Source
1
/* $OpenBSD$ */
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 cmd_find_state *, struct args *);
29
static void window_clock_free(struct window_mode_entry *);
30
static void window_clock_resize(struct window_mode_entry *, u_int, u_int);
31
static void window_clock_key(struct window_mode_entry *, struct client *,
32
         struct session *, struct winlink *, key_code,
33
         struct mouse_event *);
34
35
static void window_clock_timer_callback(int, short, void *);
36
static void window_clock_draw_screen(struct window_mode_entry *);
37
38
const struct window_mode window_clock_mode = {
39
  .name = "clock-mode",
40
41
  .init = window_clock_init,
42
  .free = window_clock_free,
43
  .resize = window_clock_resize,
44
  .key = window_clock_key,
45
};
46
47
struct window_clock_mode_data {
48
  struct screen   screen;
49
  time_t      tim;
50
  struct event    timer;
51
};
52
53
const char window_clock_table[14][5][5] = {
54
  { { 1,1,1,1,1 }, /* 0 */
55
    { 1,0,0,0,1 },
56
    { 1,0,0,0,1 },
57
    { 1,0,0,0,1 },
58
    { 1,1,1,1,1 } },
59
  { { 0,0,0,0,1 }, /* 1 */
60
    { 0,0,0,0,1 },
61
    { 0,0,0,0,1 },
62
    { 0,0,0,0,1 },
63
    { 0,0,0,0,1 } },
64
  { { 1,1,1,1,1 }, /* 2 */
65
    { 0,0,0,0,1 },
66
    { 1,1,1,1,1 },
67
    { 1,0,0,0,0 },
68
    { 1,1,1,1,1 } },
69
  { { 1,1,1,1,1 }, /* 3 */
70
    { 0,0,0,0,1 },
71
    { 1,1,1,1,1 },
72
    { 0,0,0,0,1 },
73
    { 1,1,1,1,1 } },
74
  { { 1,0,0,0,1 }, /* 4 */
75
    { 1,0,0,0,1 },
76
    { 1,1,1,1,1 },
77
    { 0,0,0,0,1 },
78
    { 0,0,0,0,1 } },
79
  { { 1,1,1,1,1 }, /* 5 */
80
    { 1,0,0,0,0 },
81
    { 1,1,1,1,1 },
82
    { 0,0,0,0,1 },
83
    { 1,1,1,1,1 } },
84
  { { 1,1,1,1,1 }, /* 6 */
85
    { 1,0,0,0,0 },
86
    { 1,1,1,1,1 },
87
    { 1,0,0,0,1 },
88
    { 1,1,1,1,1 } },
89
  { { 1,1,1,1,1 }, /* 7 */
90
    { 0,0,0,0,1 },
91
    { 0,0,0,0,1 },
92
    { 0,0,0,0,1 },
93
    { 0,0,0,0,1 } },
94
  { { 1,1,1,1,1 }, /* 8 */
95
    { 1,0,0,0,1 },
96
    { 1,1,1,1,1 },
97
    { 1,0,0,0,1 },
98
    { 1,1,1,1,1 } },
99
  { { 1,1,1,1,1 }, /* 9 */
100
    { 1,0,0,0,1 },
101
    { 1,1,1,1,1 },
102
    { 0,0,0,0,1 },
103
    { 1,1,1,1,1 } },
104
  { { 0,0,0,0,0 }, /* : */
105
    { 0,0,1,0,0 },
106
    { 0,0,0,0,0 },
107
    { 0,0,1,0,0 },
108
    { 0,0,0,0,0 } },
109
  { { 1,1,1,1,1 }, /* A */
110
    { 1,0,0,0,1 },
111
    { 1,1,1,1,1 },
112
    { 1,0,0,0,1 },
113
    { 1,0,0,0,1 } },
114
  { { 1,1,1,1,1 }, /* P */
115
    { 1,0,0,0,1 },
116
    { 1,1,1,1,1 },
117
    { 1,0,0,0,0 },
118
    { 1,0,0,0,0 } },
119
  { { 1,0,0,0,1 }, /* M */
120
    { 1,1,0,1,1 },
121
    { 1,0,1,0,1 },
122
    { 1,0,0,0,1 },
123
    { 1,0,0,0,1 } },
124
};
125
126
static void
127
window_clock_start_timer(struct window_mode_entry *wme)
128
0
{
129
0
  struct window_clock_mode_data *data = wme->data;
130
0
  struct timeval       tv;
131
0
  struct timespec      ts;
132
0
  long         delay;
133
134
0
  clock_gettime(CLOCK_REALTIME, &ts);
135
0
  delay = 1000000 - (ts.tv_nsec / 1000);
136
137
0
  tv.tv_sec = delay / 1000000;
138
0
  tv.tv_usec = delay % 1000000;
139
0
  if (tv.tv_sec < 0 || (tv.tv_sec == 0 && tv.tv_usec <= 0)) {
140
0
    tv.tv_sec = 1;
141
0
    tv.tv_usec = 0;
142
0
  }
143
0
  evtimer_add(&data->timer, &tv);
144
0
}
145
146
static void
147
window_clock_timer_callback(__unused int fd, __unused short events, void *arg)
148
0
{
149
0
  struct window_mode_entry  *wme = arg;
150
0
  struct window_pane    *wp = wme->wp;
151
0
  struct window_clock_mode_data *data = wme->data;
152
0
  struct tm      now, then;
153
0
  time_t         t;
154
155
0
  evtimer_del(&data->timer);
156
157
0
  t = time(NULL);
158
0
  gmtime_r(&t, &now);
159
0
  gmtime_r(&data->tim, &then);
160
161
0
  if (now.tm_sec != then.tm_sec) {
162
0
    data->tim = t;
163
0
    window_clock_draw_screen(wme);
164
0
    wp->flags |= PANE_REDRAW;
165
0
  }
166
167
0
  window_clock_start_timer(wme);
168
0
}
169
170
static struct screen *
171
window_clock_init(struct window_mode_entry *wme,
172
    __unused struct cmd_find_state *fs, __unused struct args *args)
173
0
{
174
0
  struct window_pane    *wp = wme->wp;
175
0
  struct window_clock_mode_data *data;
176
0
  struct screen     *s;
177
178
0
  wme->data = data = xmalloc(sizeof *data);
179
0
  data->tim = time(NULL);
180
181
0
  evtimer_set(&data->timer, window_clock_timer_callback, wme);
182
0
  window_clock_start_timer(wme);
183
184
0
  s = &data->screen;
185
0
  screen_init(s, screen_size_x(&wp->base), screen_size_y(&wp->base), 0);
186
0
  s->mode &= ~MODE_CURSOR;
187
188
0
  window_clock_draw_screen(wme);
189
190
0
  return (s);
191
0
}
192
193
static void
194
window_clock_free(struct window_mode_entry *wme)
195
0
{
196
0
  struct window_clock_mode_data *data = wme->data;
197
198
0
  evtimer_del(&data->timer);
199
0
  screen_free(&data->screen);
200
0
  free(data);
201
0
}
202
203
static void
204
window_clock_resize(struct window_mode_entry *wme, u_int sx, u_int sy)
205
0
{
206
0
  struct window_clock_mode_data *data = wme->data;
207
0
  struct screen     *s = &data->screen;
208
209
0
  screen_resize(s, sx, sy, 0);
210
0
  window_clock_draw_screen(wme);
211
0
}
212
213
static void
214
window_clock_key(struct window_mode_entry *wme, __unused struct client *c,
215
    __unused struct session *s, __unused struct winlink *wl,
216
    __unused key_code key, __unused struct mouse_event *m)
217
0
{
218
0
  window_pane_reset_mode(wme->wp);
219
0
}
220
221
static void
222
window_clock_draw_screen(struct window_mode_entry *wme)
223
0
{
224
0
  struct window_pane    *wp = wme->wp;
225
0
  struct window_clock_mode_data *data = wme->data;
226
0
  struct screen_write_ctx    ctx;
227
0
  int        colour, style;
228
0
  struct screen     *s = &data->screen;
229
0
  struct grid_cell     gc;
230
0
  char         tim[64], *ptr;
231
0
  time_t         t;
232
0
  struct tm     *tm;
233
0
  u_int        i, j, x, y, idx;
234
235
0
  colour = options_get_number(wp->window->options, "clock-mode-colour");
236
0
  style = options_get_number(wp->window->options, "clock-mode-style");
237
238
0
  screen_write_start(&ctx, s);
239
240
0
  t = time(NULL);
241
0
  tm = localtime(&t);
242
0
  if (style == 0 || style == 2) {
243
0
    if (style == 2)
244
0
      strftime(tim, sizeof tim, "%l:%M:%S ", localtime(&t));
245
0
    else
246
0
      strftime(tim, sizeof tim, "%l:%M ", localtime(&t));
247
0
    if (tm->tm_hour >= 12)
248
0
      strlcat(tim, "PM", sizeof tim);
249
0
    else
250
0
      strlcat(tim, "AM", sizeof tim);
251
0
  } else {
252
0
    if (style == 3)
253
0
      strftime(tim, sizeof tim, "%H:%M:%S", tm);
254
0
    else
255
0
      strftime(tim, sizeof tim, "%H:%M", tm);
256
0
  }
257
258
0
  screen_write_clearscreen(&ctx, 8);
259
260
0
  if (screen_size_x(s) < 6 * strlen(tim) || screen_size_y(s) < 6) {
261
0
    if (screen_size_x(s) >= strlen(tim) && screen_size_y(s) != 0) {
262
0
      x = (screen_size_x(s) / 2) - (strlen(tim) / 2);
263
0
      y = screen_size_y(s) / 2;
264
0
      screen_write_cursormove(&ctx, x, y, 0);
265
266
0
      memcpy(&gc, &grid_default_cell, sizeof gc);
267
0
      gc.flags |= GRID_FLAG_NOPALETTE;
268
0
      gc.fg = colour;
269
0
      screen_write_puts(&ctx, &gc, "%s", tim);
270
0
    }
271
272
0
    screen_write_stop(&ctx);
273
0
    return;
274
0
  }
275
276
0
  x = (screen_size_x(s) / 2) - 3 * strlen(tim);
277
0
  y = (screen_size_y(s) / 2) - 3;
278
279
0
  memcpy(&gc, &grid_default_cell, sizeof gc);
280
0
  gc.flags |= GRID_FLAG_NOPALETTE;
281
0
  gc.bg = colour;
282
0
  gc.fg = colour;
283
0
  for (ptr = tim; *ptr != '\0'; ptr++) {
284
0
    if (*ptr >= '0' && *ptr <= '9')
285
0
      idx = *ptr - '0';
286
0
    else if (*ptr == ':')
287
0
      idx = 10;
288
0
    else if (*ptr == 'A')
289
0
      idx = 11;
290
0
    else if (*ptr == 'P')
291
0
      idx = 12;
292
0
    else if (*ptr == 'M')
293
0
      idx = 13;
294
0
    else {
295
0
      x += 6;
296
0
      continue;
297
0
    }
298
299
0
    for (j = 0; j < 5; j++) {
300
0
      for (i = 0; i < 5; i++) {
301
0
        screen_write_cursormove(&ctx, x + i, y + j, 0);
302
0
        if (window_clock_table[idx][j][i])
303
0
          screen_write_putc(&ctx, &gc, '#');
304
0
      }
305
0
    }
306
0
    x += 6;
307
0
  }
308
309
0
  screen_write_stop(&ctx);
310
0
}