Coverage Report

Created: 2023-06-07 06:15

/src/neomutt/index/ibar.c
Line
Count
Source (jump to first uncovered line)
1
/**
2
 * @file
3
 * Index Bar (status)
4
 *
5
 * @authors
6
 * Copyright (C) 2021 Richard Russon <rich@flatcap.org>
7
 *
8
 * @copyright
9
 * This program is free software: you can redistribute it and/or modify it under
10
 * the terms of the GNU General Public License as published by the Free Software
11
 * Foundation, either version 2 of the License, or (at your option) any later
12
 * version.
13
 *
14
 * This program is distributed in the hope that it will be useful, but WITHOUT
15
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
16
 * FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more
17
 * details.
18
 *
19
 * You should have received a copy of the GNU General Public License along with
20
 * this program.  If not, see <http://www.gnu.org/licenses/>.
21
 */
22
23
/**
24
 * @page index_ibar Index Bar (status)
25
 *
26
 * The Index Bar Window displays status info about the email list.
27
 *
28
 * ## Windows
29
 *
30
 * | Name             | Type          | See Also   |
31
 * | :--------------- | :------------ | :--------- |
32
 * | Index Bar Window | WT_STATUS_BAR | ibar_new() |
33
 *
34
 * **Parent**
35
 * - @ref index_ipanel
36
 *
37
 * **Children**
38
 *
39
 * None.
40
 *
41
 * ## Data
42
 * - #IBarPrivateData
43
 *
44
 * The Index Bar Window stores its data (#IBarPrivateData) in
45
 * MuttWindow::wdata.
46
 *
47
 * ## Events
48
 *
49
 * Once constructed, it is controlled by the following events:
50
 *
51
 * | Event Type            | Handler                 |
52
 * | :-------------------- | :---------------------- |
53
 * | #NT_COLOR             | ibar_color_observer()   |
54
 * | #NT_CONFIG            | ibar_config_observer()  |
55
 * | #NT_INDEX             | ibar_index_observer()   |
56
 * | #NT_MENU              | ibar_menu_observer()    |
57
 * | #NT_WINDOW            | ibar_window_observer()  |
58
 * | MuttWindow::recalc()  | ibar_recalc()           |
59
 * | MuttWindow::repaint() | ibar_repaint()          |
60
 */
61
62
#include "config.h"
63
#include <stdbool.h>
64
#include "mutt/lib.h"
65
#include "config/lib.h"
66
#include "core/lib.h"
67
#include "gui/lib.h"
68
#include "lib.h"
69
#include "color/lib.h"
70
#include "private_data.h"
71
#include "shared_data.h"
72
#include "status.h"
73
74
/**
75
 * struct IBarPrivateData - Data to draw the Index Bar
76
 */
77
struct IBarPrivateData
78
{
79
  struct IndexSharedData *shared; ///< Shared Index data
80
  struct IndexPrivateData *priv;  ///< Private Index data
81
  char *status_format;            ///< Cached screen status string
82
  char *ts_status_format;         ///< Cached terminal status string
83
  char *ts_icon_format;           ///< Cached terminal icon string
84
};
85
86
/**
87
 * ibar_recalc - Recalculate the Window data - Implements MuttWindow::recalc() - @ingroup window_recalc
88
 */
89
static int ibar_recalc(struct MuttWindow *win)
90
0
{
91
0
  char buf[1024] = { 0 };
92
93
0
  struct IBarPrivateData *ibar_data = win->wdata;
94
0
  struct IndexSharedData *shared = ibar_data->shared;
95
0
  struct IndexPrivateData *priv = ibar_data->priv;
96
97
0
  const char *c_status_format = cs_subset_string(shared->sub, "status_format");
98
0
  menu_status_line(buf, sizeof(buf), shared, priv->menu, win->state.cols,
99
0
                   NONULL(c_status_format));
100
101
0
  if (!mutt_str_equal(buf, ibar_data->status_format))
102
0
  {
103
0
    mutt_str_replace(&ibar_data->status_format, buf);
104
0
    win->actions |= WA_REPAINT;
105
0
    mutt_debug(LL_DEBUG5, "recalc done, request WA_REPAINT\n");
106
0
  }
107
108
0
  const bool c_ts_enabled = cs_subset_bool(shared->sub, "ts_enabled");
109
0
  if (c_ts_enabled && TsSupported)
110
0
  {
111
0
    const char *c_ts_status_format = cs_subset_string(shared->sub, "ts_status_format");
112
0
    menu_status_line(buf, sizeof(buf), shared, priv->menu, sizeof(buf),
113
0
                     NONULL(c_ts_status_format));
114
0
    if (!mutt_str_equal(buf, ibar_data->ts_status_format))
115
0
    {
116
0
      mutt_str_replace(&ibar_data->ts_status_format, buf);
117
0
      win->actions |= WA_REPAINT;
118
0
      mutt_debug(LL_DEBUG5, "recalc done, request WA_REPAINT\n");
119
0
    }
120
121
0
    const char *c_ts_icon_format = cs_subset_string(shared->sub, "ts_icon_format");
122
0
    menu_status_line(buf, sizeof(buf), shared, priv->menu, sizeof(buf),
123
0
                     NONULL(c_ts_icon_format));
124
0
    if (!mutt_str_equal(buf, ibar_data->ts_icon_format))
125
0
    {
126
0
      mutt_str_replace(&ibar_data->ts_icon_format, buf);
127
0
      win->actions |= WA_REPAINT;
128
0
      mutt_debug(LL_DEBUG5, "recalc done, request WA_REPAINT\n");
129
0
    }
130
0
  }
131
132
0
  return 0;
133
0
}
134
135
/**
136
 * ibar_repaint - Repaint the Window - Implements MuttWindow::repaint() - @ingroup window_repaint
137
 */
138
static int ibar_repaint(struct MuttWindow *win)
139
0
{
140
0
  struct IBarPrivateData *ibar_data = win->wdata;
141
0
  struct IndexSharedData *shared = ibar_data->shared;
142
143
0
  mutt_window_move(win, 0, 0);
144
0
  mutt_curses_set_normal_backed_color_by_id(MT_COLOR_STATUS);
145
0
  mutt_window_clrtoeol(win);
146
147
0
  mutt_window_move(win, 0, 0);
148
0
  mutt_draw_statusline(win, win->state.cols, ibar_data->status_format,
149
0
                       mutt_str_len(ibar_data->status_format));
150
0
  mutt_curses_set_color_by_id(MT_COLOR_NORMAL);
151
152
0
  const bool c_ts_enabled = cs_subset_bool(shared->sub, "ts_enabled");
153
0
  if (c_ts_enabled && TsSupported)
154
0
  {
155
0
    mutt_ts_status(ibar_data->ts_status_format);
156
0
    mutt_ts_icon(ibar_data->ts_icon_format);
157
0
  }
158
159
0
  mutt_debug(LL_DEBUG5, "repaint done\n");
160
0
  return 0;
161
0
}
162
163
/**
164
 * ibar_color_observer - Notification that a Color has changed - Implements ::observer_t - @ingroup observer_api
165
 */
166
static int ibar_color_observer(struct NotifyCallback *nc)
167
0
{
168
0
  if (nc->event_type != NT_COLOR)
169
0
    return 0;
170
0
  if (!nc->global_data || !nc->event_data)
171
0
    return -1;
172
173
0
  struct EventColor *ev_c = nc->event_data;
174
175
  // MT_COLOR_MAX is sent on `uncolor *`
176
0
  if ((ev_c->cid != MT_COLOR_STATUS) && (ev_c->cid != MT_COLOR_NORMAL) &&
177
0
      (ev_c->cid != MT_COLOR_MAX))
178
0
  {
179
0
    return 0;
180
0
  }
181
182
0
  struct MuttWindow *win_ibar = nc->global_data;
183
0
  win_ibar->actions |= WA_REPAINT;
184
0
  mutt_debug(LL_DEBUG5, "color done, request WA_REPAINT\n");
185
186
0
  return 0;
187
0
}
188
189
/**
190
 * ibar_config_observer - Notification that a Config Variable has changed - Implements ::observer_t - @ingroup observer_api
191
 */
192
static int ibar_config_observer(struct NotifyCallback *nc)
193
0
{
194
0
  if (nc->event_type != NT_CONFIG)
195
0
    return 0;
196
0
  if (!nc->global_data || !nc->event_data)
197
0
    return -1;
198
199
0
  struct EventConfig *ev_c = nc->event_data;
200
0
  if (!ev_c->name)
201
0
    return 0;
202
0
  if ((ev_c->name[0] != 's') && (ev_c->name[0] != 't'))
203
0
    return 0;
204
205
0
  if (!mutt_str_equal(ev_c->name, "status_format") &&
206
0
      !mutt_str_equal(ev_c->name, "ts_enabled") &&
207
0
      !mutt_str_equal(ev_c->name, "ts_icon_format") &&
208
0
      !mutt_str_equal(ev_c->name, "ts_status_format"))
209
0
  {
210
0
    return 0;
211
0
  }
212
213
0
  struct MuttWindow *win_ibar = nc->global_data;
214
0
  win_ibar->actions |= WA_RECALC;
215
0
  mutt_debug(LL_DEBUG5, "config done, request WA_RECALC\n");
216
217
0
  return 0;
218
0
}
219
220
/**
221
 * ibar_index_observer - Notification that the Index has changed - Implements ::observer_t - @ingroup observer_api
222
 *
223
 * This function receives two sorts of notification:
224
 * - NT_INDEX:
225
 *   User has changed to a different Mailbox/Email
226
 * - NT_ACCOUNT/NT_MVIEW/NT_MAILBOX/NT_EMAIL:
227
 *   The state of an object has changed
228
 */
229
static int ibar_index_observer(struct NotifyCallback *nc)
230
0
{
231
0
  if (!nc->global_data)
232
0
    return -1;
233
234
0
  struct MuttWindow *win_ibar = nc->global_data;
235
0
  win_ibar->actions |= WA_RECALC;
236
0
  mutt_debug(LL_DEBUG5, "index done, request WA_RECALC\n");
237
238
0
  return 0;
239
0
}
240
241
/**
242
 * ibar_menu_observer - Notification that a Menu has changed - Implements ::observer_t - @ingroup observer_api
243
 */
244
static int ibar_menu_observer(struct NotifyCallback *nc)
245
0
{
246
0
  if (nc->event_type != NT_MENU)
247
0
    return 0;
248
0
  if (!nc->global_data)
249
0
    return -1;
250
251
0
  struct MuttWindow *win_ibar = nc->global_data;
252
0
  win_ibar->actions |= WA_RECALC;
253
0
  mutt_debug(LL_DEBUG5, "menu done, request WA_RECALC\n");
254
255
0
  return 0;
256
0
}
257
258
/**
259
 * ibar_window_observer - Notification that a Window has changed - Implements ::observer_t - @ingroup observer_api
260
 */
261
static int ibar_window_observer(struct NotifyCallback *nc)
262
0
{
263
0
  if (nc->event_type != NT_WINDOW)
264
0
    return 0;
265
0
  if (!nc->global_data)
266
0
    return -1;
267
268
0
  struct MuttWindow *win_ibar = nc->global_data;
269
0
  struct EventWindow *ev_w = nc->event_data;
270
0
  if (ev_w->win != win_ibar)
271
0
    return 0;
272
273
0
  if (nc->event_subtype == NT_WINDOW_STATE)
274
0
  {
275
0
    win_ibar->actions |= WA_REPAINT;
276
0
    mutt_debug(LL_DEBUG5, "window state done, request WA_REPAINT\n");
277
0
  }
278
0
  else if (nc->event_subtype == NT_WINDOW_DELETE)
279
0
  {
280
0
    struct MuttWindow *dlg = window_find_parent(win_ibar, WT_DLG_INDEX);
281
0
    struct IndexSharedData *shared = dlg->wdata;
282
283
0
    notify_observer_remove(NeoMutt->notify, ibar_color_observer, win_ibar);
284
0
    notify_observer_remove(NeoMutt->notify, ibar_config_observer, win_ibar);
285
0
    notify_observer_remove(shared->notify, ibar_index_observer, win_ibar);
286
0
    notify_observer_remove(win_ibar->parent->notify, ibar_menu_observer, win_ibar);
287
0
    notify_observer_remove(win_ibar->notify, ibar_window_observer, win_ibar);
288
289
0
    mutt_debug(LL_DEBUG5, "window delete done\n");
290
0
  }
291
292
0
  return 0;
293
0
}
294
295
/**
296
 * ibar_data_free - Free the private data attached to the MuttWindow - Implements MuttWindow::wdata_free() - @ingroup window_wdata_free
297
 */
298
static void ibar_data_free(struct MuttWindow *win, void **ptr)
299
0
{
300
0
  struct IBarPrivateData *ibar_data = *ptr;
301
302
0
  FREE(&ibar_data->status_format);
303
0
  FREE(&ibar_data->ts_status_format);
304
0
  FREE(&ibar_data->ts_icon_format);
305
306
0
  FREE(ptr);
307
0
}
308
309
/**
310
 * ibar_data_new - Free the private data attached to the MuttWindow
311
 * @param shared Shared Index data
312
 * @param priv   Private Index data
313
 * @retval ptr New IBar
314
 */
315
static struct IBarPrivateData *ibar_data_new(struct IndexSharedData *shared,
316
                                             struct IndexPrivateData *priv)
317
0
{
318
0
  struct IBarPrivateData *ibar_data = mutt_mem_calloc(1, sizeof(struct IBarPrivateData));
319
320
0
  ibar_data->shared = shared;
321
0
  ibar_data->priv = priv;
322
323
0
  return ibar_data;
324
0
}
325
326
/**
327
 * ibar_new - Create the Index Bar (status)
328
 * @param parent Parent Window
329
 * @param shared Shared Index data
330
 * @param priv   Private Index data
331
 * @retval ptr New Index Bar
332
 */
333
struct MuttWindow *ibar_new(struct MuttWindow *parent, struct IndexSharedData *shared,
334
                            struct IndexPrivateData *priv)
335
0
{
336
0
  struct MuttWindow *win_ibar = mutt_window_new(WT_STATUS_BAR, MUTT_WIN_ORIENT_VERTICAL,
337
0
                                                MUTT_WIN_SIZE_FIXED,
338
0
                                                MUTT_WIN_SIZE_UNLIMITED, 1);
339
340
0
  win_ibar->wdata = ibar_data_new(shared, priv);
341
0
  win_ibar->wdata_free = ibar_data_free;
342
0
  win_ibar->recalc = ibar_recalc;
343
0
  win_ibar->repaint = ibar_repaint;
344
345
0
  notify_observer_add(NeoMutt->notify, NT_COLOR, ibar_color_observer, win_ibar);
346
0
  notify_observer_add(NeoMutt->notify, NT_CONFIG, ibar_config_observer, win_ibar);
347
0
  notify_observer_add(shared->notify, NT_ALL, ibar_index_observer, win_ibar);
348
0
  notify_observer_add(parent->notify, NT_MENU, ibar_menu_observer, win_ibar);
349
0
  notify_observer_add(win_ibar->notify, NT_WINDOW, ibar_window_observer, win_ibar);
350
351
0
  return win_ibar;
352
0
}