NeoMutt
Teaching an old dog new tricks
DOXYGEN
Loading...
Searching...
No Matches
msgwin.c
Go to the documentation of this file.
1
85#include "config.h"
86#include <stddef.h>
87#include <stdbool.h>
88#include <string.h>
89#include <wchar.h>
90#include "mutt/lib.h"
91#include "msgwin.h"
92#include "color/lib.h"
93#include "msgcont.h"
94#include "msgwin_wdata.h"
95#include "mutt_curses.h"
96#include "mutt_window.h"
97
106void measure(struct MwCharArray *chars, const char *str, const struct AttrColor *ac_color)
107{
108 if (!str || !*str)
109 return;
110
111 int total_width = 0;
112 mbstate_t mbstate = { 0 };
113 struct MwChar mwc = { 0 };
114
115 size_t str_len = mutt_str_len(str);
116
117 while (*str && (str_len > 0))
118 {
119 wchar_t wc = L'\0';
120 size_t consumed = mbrtowc(&wc, str, str_len, &mbstate);
121 if (consumed == 0)
122 break;
123
124 if (consumed == ICONV_ILLEGAL_SEQ)
125 {
126 memset(&mbstate, 0, sizeof(mbstate));
127 wc = ReplacementChar;
128 consumed = 1;
129 }
130 else if (consumed == ICONV_BUF_TOO_SMALL)
131 {
132 wc = ReplacementChar;
133 consumed = str_len;
134 }
135
136 int wchar_width = wcwidth(wc);
137 if (wchar_width < 0)
138 wchar_width = 1;
139
140 if (wc == 0xfe0f) // Emoji variation
141 {
142 size_t size = ARRAY_SIZE(chars);
143 if (size > 0)
144 {
145 struct MwChar *es_prev = ARRAY_GET(chars, size - 1);
146 if (es_prev->width == 1)
147 es_prev->width = 2;
148 }
149 }
150
151 mwc = (struct MwChar){ wchar_width, consumed, ac_color };
152 ARRAY_ADD(chars, mwc);
153
154 total_width += wchar_width;
155 str += consumed;
156 str_len -= consumed;
157 }
158}
159
163static int msgwin_recalc(struct MuttWindow *win)
164{
165 win->actions |= WA_REPAINT;
166 mutt_debug(LL_DEBUG5, "recalc done, request WA_REPAINT\n");
167 return 0;
168}
169
180int msgwin_calc_rows(struct MsgWinWindowData *wdata, int cols, const char *str)
181{
182 if (!wdata || !str || !*str)
183 return 0;
184
185 for (int i = 0; i < MSGWIN_MAX_ROWS; i++)
186 {
187 ARRAY_FREE(&wdata->rows[i]);
188 }
189
190 int width = 0;
191 int offset = 0;
192 int row = 0;
193 bool new_row = false;
194
195 struct MwChunk *chunk = NULL;
196 struct MwChar *mwc = NULL;
197 ARRAY_FOREACH(mwc, &wdata->chars)
198 {
199 const bool nl = (mwc->bytes == 1) && (str[offset] == '\n');
200 if (nl)
201 {
202 new_row = true;
203 offset += mwc->bytes;
204 continue;
205 }
206
207 if (((width + mwc->width) > cols) || new_row)
208 {
209 // ROW IS FULL
210 new_row = false;
211
212 row++;
213 if (row >= MSGWIN_MAX_ROWS)
214 {
215 // NO MORE ROOM
216 break;
217 }
218
219 // Start a new row
220 struct MwChunk tmp = { offset, mwc->bytes, mwc->width, mwc->ac_color };
221
222 mutt_debug(LL_DEBUG1, "row = %d\n", row);
223 ARRAY_ADD(&wdata->rows[row], tmp);
224 chunk = ARRAY_LAST(&wdata->rows[row]);
225
226 width = 0;
227 }
228 else if (!chunk || (mwc->ac_color != chunk->ac_color))
229 {
230 // CHANGE OF COLOUR
231 struct MwChunk tmp = { offset, mwc->bytes, mwc->width, mwc->ac_color };
232 ARRAY_ADD(&wdata->rows[row], tmp);
233 chunk = ARRAY_LAST(&wdata->rows[row]);
234 }
235 else
236 {
237 // MORE OF THE SAME
238 chunk->bytes += mwc->bytes;
239 chunk->width += mwc->width;
240 }
241
242 offset += mwc->bytes;
243 width += mwc->width;
244 }
245
246 mutt_debug(LL_DEBUG1, "msgwin_calc_rows() => %d\n", row + 1);
247 return row + 1;
248}
249
253static int msgwin_repaint(struct MuttWindow *win)
254{
255 struct MsgWinWindowData *wdata = win->wdata;
256
257 const char *str = buf_string(wdata->text);
258 for (int i = 0; i < MSGWIN_MAX_ROWS; i++)
259 {
260 mutt_window_move(win, 0, i);
261 if (ARRAY_EMPTY(&wdata->rows[i]))
262 break;
263
264 struct MwChunk *chunk = NULL;
265 ARRAY_FOREACH(chunk, &wdata->rows[i])
266 {
268 mutt_window_addnstr(win, str + chunk->offset, chunk->bytes);
269 }
272 }
275
276 mutt_window_get_coords(win, &wdata->col, &wdata->row);
277
278 mutt_debug(LL_DEBUG1, "msgwin repaint done\n");
279 return 0;
280}
281
285static bool msgwin_recursor(struct MuttWindow *win)
286{
287 struct MsgWinWindowData *wdata = win->wdata;
288
289 mutt_window_move(win, wdata->col, wdata->row);
291
292 mutt_debug(LL_DEBUG1, "msgwin recursor done\n");
293 return true;
294}
295
305void msgwin_set_rows(struct MuttWindow *win, short rows)
306{
307 if (!win)
308 win = msgcont_get_msgwin();
309 if (!win)
310 return;
311
313
314 if (rows != win->state.rows)
315 {
316 win->req_rows = rows;
317 mutt_window_reflow(NULL);
318 }
319}
320
330{
331 if (nc->event_type != NT_WINDOW)
332 return 0;
333 if (!nc->global_data || !nc->event_data)
334 return -1;
335
336 struct MuttWindow *win = nc->global_data;
337 struct EventWindow *ev_w = nc->event_data;
338 if (ev_w->win != win)
339 return 0;
340
342 {
343 if (ev_w->flags & WN_HIDDEN)
344 {
346 }
347
348 if (ev_w->flags & (WN_NARROWER | WN_WIDER))
349 {
350 struct MsgWinWindowData *wdata = win->wdata;
352 buf_string(wdata->text)));
353 win->actions |= WA_RECALC;
354 }
355 else
356 {
357 win->actions |= WA_REPAINT;
358 }
359 mutt_debug(LL_DEBUG1, "window state done, request WA_RECALC\n");
360 }
361 else if (nc->event_subtype == NT_WINDOW_DELETE)
362 {
364 mutt_debug(LL_DEBUG5, "window delete done\n");
365 }
366 return 0;
367}
368
373struct MuttWindow *msgwin_new(bool interactive)
374{
377
378 struct MsgWinWindowData *wdata = msgwin_wdata_new();
379
380 win->wdata = wdata;
382 win->recalc = msgwin_recalc;
383 win->repaint = msgwin_repaint;
384
385 if (interactive)
387
388 // Copy the container's dimensions
390
392
393 return win;
394}
395
403const char *msgwin_get_text(struct MuttWindow *win)
404{
405 if (!win)
406 win = msgcont_get_msgwin();
407 if (!win)
408 return NULL;
409
410 struct MsgWinWindowData *wdata = win->wdata;
411
412 return buf_string(wdata->text);
413}
414
421void msgwin_add_text(struct MuttWindow *win, const char *text, const struct AttrColor *ac_color)
422{
423 if (!win)
424 win = msgcont_get_msgwin();
425 if (!win)
426 return;
427
428 struct MsgWinWindowData *wdata = win->wdata;
429
430 if (text)
431 {
432 buf_addstr(wdata->text, text);
433 measure(&wdata->chars, text, ac_color);
434 mutt_debug(LL_DEBUG1, "MW ADD: %zu, %s\n", buf_len(wdata->text),
435 buf_string(wdata->text));
436 }
437 else
438 {
439 int rows = msgwin_calc_rows(wdata, win->state.cols, buf_string(wdata->text));
440 msgwin_set_rows(win, rows);
441 win->actions |= WA_RECALC;
442 }
443}
444
452void msgwin_add_text_n(struct MuttWindow *win, const char *text, int bytes,
453 const struct AttrColor *ac_color)
454{
455 if (!win)
456 win = msgcont_get_msgwin();
457 if (!win)
458 return;
459
460 struct MsgWinWindowData *wdata = win->wdata;
461
462 if (text)
463 {
464 const char *dptr = wdata->text->dptr;
465 buf_addstr_n(wdata->text, text, bytes);
466 measure(&wdata->chars, dptr, ac_color);
467 mutt_debug(LL_DEBUG1, "MW ADD: %zu, %s\n", buf_len(wdata->text),
468 buf_string(wdata->text));
469 }
470 else
471 {
472 int rows = msgwin_calc_rows(wdata, win->state.cols, buf_string(wdata->text));
473 msgwin_set_rows(win, rows);
474 win->actions |= WA_RECALC;
475 }
476}
477
486void msgwin_set_text(struct MuttWindow *win, const char *text, enum ColorId color)
487{
488 if (!win)
489 win = msgcont_get_msgwin();
490 if (!win)
491 return;
492
493 struct MsgWinWindowData *wdata = win->wdata;
494
495 buf_strcpy(wdata->text, text);
496 ARRAY_FREE(&wdata->chars);
497 if (wdata->text)
498 {
499 const struct AttrColor *ac_color = simple_color_get(color);
500 measure(&wdata->chars, buf_string(wdata->text), ac_color);
501 }
502
503 mutt_debug(LL_DEBUG1, "MW SET: %zu, %s\n", buf_len(wdata->text),
504 buf_string(wdata->text));
505
506 int rows = msgwin_calc_rows(wdata, win->state.cols, buf_string(wdata->text));
507 msgwin_set_rows(win, rows);
508 win->actions |= WA_RECALC;
509}
510
516{
518}
519
527{
528 return msgcont_get_msgwin();
529}
#define ARRAY_ADD(head, elem)
Add an element at the end of the array.
Definition: array.h:155
#define ARRAY_FOREACH(elem, head)
Iterate over all elements of the array.
Definition: array.h:211
#define ARRAY_LAST(head)
Convenience method to get the last element.
Definition: array.h:143
#define ARRAY_EMPTY(head)
Check if an array is empty.
Definition: array.h:73
#define ARRAY_SIZE(head)
The number of elements stored.
Definition: array.h:86
#define ARRAY_FREE(head)
Release all memory.
Definition: array.h:203
#define ARRAY_GET(head, idx)
Return the element at index.
Definition: array.h:108
size_t buf_addstr_n(struct Buffer *buf, const char *s, size_t len)
Add a string to a Buffer, expanding it if necessary.
Definition: buffer.c:108
size_t buf_len(const struct Buffer *buf)
Calculate the length of a Buffer.
Definition: buffer.c:466
size_t buf_addstr(struct Buffer *buf, const char *s)
Add a string to a Buffer.
Definition: buffer.c:238
size_t buf_strcpy(struct Buffer *buf, const char *s)
Copy a string into a Buffer.
Definition: buffer.c:407
static const char * buf_string(const struct Buffer *buf)
Convert a buffer to a const char * "string".
Definition: buffer.h:93
Color and attribute parsing.
struct AttrColor * simple_color_get(enum ColorId cid)
Get the colour of an object by its ID.
Definition: simple.c:81
ColorId
List of all colored objects.
Definition: color.h:38
@ MT_COLOR_NORMAL
Plain text.
Definition: color.h:57
#define mutt_debug(LEVEL,...)
Definition: logging2.h:89
static int msgwin_window_observer(struct NotifyCallback *nc)
Notification that a Window has changed - Implements observer_t -.
Definition: msgwin.c:329
static int msgwin_recalc(struct MuttWindow *win)
Recalculate the display of the Message Window - Implements MuttWindow::recalc() -.
Definition: msgwin.c:163
static bool msgwin_recursor(struct MuttWindow *win)
Recursor the Message Window - Implements MuttWindow::recursor() -.
Definition: msgwin.c:285
static int msgwin_repaint(struct MuttWindow *win)
Redraw the Message Window - Implements MuttWindow::repaint() -.
Definition: msgwin.c:253
void msgwin_wdata_free(struct MuttWindow *win, void **ptr)
Free the private data attached to the Message Window - Implements MuttWindow::wdata_free() -.
Definition: msgwin_wdata.c:37
@ LL_DEBUG5
Log at debug level 5.
Definition: logging2.h:47
@ LL_DEBUG1
Log at debug level 1.
Definition: logging2.h:43
#define CLAMP(val, lo, hi)
Definition: memory.h:33
struct MuttWindow * MessageContainer
Window acting as a stack for the message windows.
Definition: msgcont.c:40
struct MuttWindow * msgcont_get_msgwin(void)
Get the Message Window.
Definition: msgcont.c:117
Message Window.
struct MuttWindow * msgwin_new(bool interactive)
Create the Message Window.
Definition: msgwin.c:373
void msgwin_clear_text(struct MuttWindow *win)
Clear the text in the Message Window.
Definition: msgwin.c:515
void msgwin_add_text(struct MuttWindow *win, const char *text, const struct AttrColor *ac_color)
Add text to the Message Window.
Definition: msgwin.c:421
int msgwin_calc_rows(struct MsgWinWindowData *wdata, int cols, const char *str)
How many rows will a string need?
Definition: msgwin.c:180
struct MuttWindow * msgwin_get_window(void)
Get the Message Window pointer.
Definition: msgwin.c:526
void msgwin_add_text_n(struct MuttWindow *win, const char *text, int bytes, const struct AttrColor *ac_color)
Add some text to the Message Window.
Definition: msgwin.c:452
void measure(struct MwCharArray *chars, const char *str, const struct AttrColor *ac_color)
Measure a string in bytes and cells.
Definition: msgwin.c:106
void msgwin_set_text(struct MuttWindow *win, const char *text, enum ColorId color)
Set the text for the Message Window.
Definition: msgwin.c:486
const char * msgwin_get_text(struct MuttWindow *win)
Get the text from the Message Window.
Definition: msgwin.c:403
void msgwin_set_rows(struct MuttWindow *win, short rows)
Resize the Message Window.
Definition: msgwin.c:305
Message Window.
struct MsgWinWindowData * msgwin_wdata_new(void)
Create new private data for the Message Window.
Definition: msgwin_wdata.c:60
Message Window private data.
#define MSGWIN_MAX_ROWS
Definition: msgwin_wdata.h:30
wchar_t ReplacementChar
When a Unicode character can't be displayed, use this instead.
Definition: charset.c:58
#define ICONV_BUF_TOO_SMALL
Error value for iconv() - Buffer too small.
Definition: charset.h:105
#define ICONV_ILLEGAL_SEQ
Error value for iconv() - Illegal sequence.
Definition: charset.h:103
Convenience wrapper for the library headers.
bool notify_observer_remove(struct Notify *notify, const observer_t callback, const void *global_data)
Remove an observer from an object.
Definition: notify.c:230
bool notify_observer_add(struct Notify *notify, enum NotifyType type, observer_t callback, void *global_data)
Add an observer to an object.
Definition: notify.c:191
size_t mutt_str_len(const char *a)
Calculate the length of a string, safely.
Definition: string.c:568
enum MuttCursorState mutt_curses_set_cursor(enum MuttCursorState state)
Set the cursor state.
Definition: mutt_curses.c:96
const struct AttrColor * mutt_curses_set_color_by_id(enum ColorId cid)
Set the colour and attributes by the colour id.
Definition: mutt_curses.c:81
void mutt_curses_set_color(const struct AttrColor *ac)
Set the colour and attributes for text.
Definition: mutt_curses.c:40
Define wrapper functions around Curses.
@ MUTT_CURSOR_VISIBLE
Display a normal cursor.
Definition: mutt_curses.h:60
void mutt_window_reflow(struct MuttWindow *win)
Resize a Window and its children.
Definition: mutt_window.c:344
struct MuttWindow * mutt_window_new(enum WindowType type, enum MuttWindowOrientation orient, enum MuttWindowSize size, int cols, int rows)
Create a new Window.
Definition: mutt_window.c:182
int mutt_window_move(struct MuttWindow *win, int col, int row)
Move the cursor in a Window.
Definition: mutt_window.c:297
void mutt_window_get_coords(struct MuttWindow *win, int *col, int *row)
Get the cursor position in the Window.
Definition: mutt_window.c:277
int mutt_window_addnstr(struct MuttWindow *win, const char *str, int num)
Write a partial string to a Window.
Definition: mutt_window.c:401
void mutt_window_clrtoeol(struct MuttWindow *win)
Clear to the end of the line.
Definition: mutt_window.c:244
Window management.
#define WA_RECALC
Recalculate the contents of the Window.
Definition: mutt_window.h:110
#define WN_WIDER
Window became wider.
Definition: mutt_window.h:212
@ WT_MESSAGE
Window for messages/errors.
Definition: mutt_window.h:99
@ MUTT_WIN_ORIENT_VERTICAL
Window uses all available vertical space.
Definition: mutt_window.h:38
@ NT_WINDOW_STATE
Window state has changed, e.g. WN_VISIBLE.
Definition: mutt_window.h:230
@ NT_WINDOW_DELETE
Window is about to be deleted.
Definition: mutt_window.h:229
#define WN_HIDDEN
Window became hidden.
Definition: mutt_window.h:216
#define WA_REPAINT
Redraw the contents of the Window.
Definition: mutt_window.h:111
#define MUTT_WIN_SIZE_UNLIMITED
Use as much space as possible.
Definition: mutt_window.h:52
@ MUTT_WIN_SIZE_FIXED
Window has a fixed size.
Definition: mutt_window.h:47
#define WN_NARROWER
Window became narrower.
Definition: mutt_window.h:213
@ NT_WINDOW
MuttWindow has changed, NotifyWindow, EventWindow.
Definition: notify_type.h:57
A curses colour and its attributes.
Definition: attr.h:35
char * dptr
Current read/write position.
Definition: buffer.h:36
An Event that happened to a Window.
Definition: mutt_window.h:239
struct MuttWindow * win
Window that changed.
Definition: mutt_window.h:240
WindowNotifyFlags flags
Attributes of Window that changed.
Definition: mutt_window.h:241
Message Window private Window data.
Definition: msgwin_wdata.h:66
struct Buffer * text
Cached display string.
Definition: msgwin_wdata.h:67
struct MwCharArray chars
Text: Breakdown of bytes and widths.
Definition: msgwin_wdata.h:68
struct MwChunkArray rows[MSGWIN_MAX_ROWS]
String byte counts for each row.
Definition: msgwin_wdata.h:69
int row
Cursor row.
Definition: msgwin_wdata.h:70
int col
Cursor column.
Definition: msgwin_wdata.h:71
int(* repaint)(struct MuttWindow *win)
Definition: mutt_window.h:187
struct WindowState state
Current state of the Window.
Definition: mutt_window.h:127
void * wdata
Private data.
Definition: mutt_window.h:145
struct Notify * notify
Notifications: NotifyWindow, EventWindow.
Definition: mutt_window.h:138
short req_rows
Number of rows required.
Definition: mutt_window.h:125
int(* recalc)(struct MuttWindow *win)
Definition: mutt_window.h:173
void(* wdata_free)(struct MuttWindow *win, void **ptr)
Definition: mutt_window.h:159
WindowActionFlags actions
Actions to be performed, e.g. WA_RECALC.
Definition: mutt_window.h:132
bool(* recursor)(struct MuttWindow *win)
Definition: mutt_window.h:205
Description of a single character.
Definition: msgwin_wdata.h:39
const struct AttrColor * ac_color
Colour to use.
Definition: msgwin_wdata.h:42
unsigned char width
Width in screen cells.
Definition: msgwin_wdata.h:40
unsigned char bytes
Number of bytes to represent.
Definition: msgwin_wdata.h:41
A block of characters of one colour.
Definition: msgwin_wdata.h:54
unsigned short bytes
Number of bytes in the row.
Definition: msgwin_wdata.h:56
unsigned short width
Width of row in screen cells.
Definition: msgwin_wdata.h:57
unsigned short offset
Offset into MsgWinWindowData.text.
Definition: msgwin_wdata.h:55
const struct AttrColor * ac_color
Colour to use.
Definition: msgwin_wdata.h:58
Data passed to a notification function.
Definition: observer.h:34
void * event_data
Data from notify_send()
Definition: observer.h:38
enum NotifyType event_type
Send: Event type, e.g. NT_ACCOUNT.
Definition: observer.h:36
int event_subtype
Send: Event subtype, e.g. NT_ACCOUNT_ADD.
Definition: observer.h:37
void * global_data
Data from notify_observer_add()
Definition: observer.h:39
short cols
Number of columns, can be MUTT_WIN_SIZE_UNLIMITED.
Definition: mutt_window.h:60
short rows
Number of rows, can be MUTT_WIN_SIZE_UNLIMITED.
Definition: mutt_window.h:61