Coverage Report

Created: 2023-09-25 07:17

/src/neomutt/gui/dialog.c
Line
Count
Source (jump to first uncovered line)
1
/**
2
 * @file
3
 * Dialog Windows
4
 *
5
 * @authors
6
 * Copyright (C) 2020 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 gui_dialog Dialog Windows
25
 *
26
 * A Dialog is an interactive set of windows allowing the user to perform some
27
 * task.  See @ref gui_dlg
28
 *
29
 * @defgroup gui_dlg GUI: Dialog Windows
30
 *
31
 * A Dialog is an interactive set of windows allowing the user to perform some
32
 * task.
33
 *
34
 * The All Dialogs window is a container window and not visible.  All active dialogs
35
 * will be children of this window, though only one will be active at a time.
36
 *
37
 * ## Windows
38
 *
39
 * | Name        | Type            | Constructor      |
40
 * | :---------- | :-------------- | :--------------- |
41
 * | All Dialogs | #WT_ALL_DIALOGS | alldialogs_new() |
42
 *
43
 * **Parent**
44
 * - @ref gui_rootwin
45
 *
46
 * **Children**
47
 *
48
 * The All Dialogs window has many possible children, e.g.
49
 *
50
 * - @ref alias_dlg_alias
51
 * - @ref compose_dlg_compose
52
 * - @ref crypt_dlg_gpgme
53
 * - ...
54
 *
55
 * ## Data
56
 *
57
 * The All Dialogs window has no data.
58
 *
59
 * ## Events
60
 *
61
 * Once constructed, it is controlled by the following events:
62
 *
63
 * | Event Type  | Handler                      |
64
 * | :---------- | :--------------------------- |
65
 * | #NT_WINDOW  | alldialogs_window_observer() |
66
 *
67
 * The All Dialogs window does not implement MuttWindow::recalc() or MuttWindow::repaint().
68
 */
69
70
#include "config.h"
71
#include <stddef.h>
72
#include <stdbool.h>
73
#include "mutt/lib.h"
74
#include "dialog.h"
75
#include "mutt_window.h"
76
#ifdef USE_DEBUG_WINDOW
77
#include "debug/lib.h"
78
#endif
79
80
struct MuttWindow *AllDialogsWindow = NULL; ///< Parent of all Dialogs
81
82
/**
83
 * dialog_find - Find the parent Dialog of a Window
84
 * @param win Window
85
 * @retval ptr Dialog
86
 *
87
 * Dialog Windows will be owned by a MuttWindow of type #WT_ALL_DIALOGS.
88
 */
89
struct MuttWindow *dialog_find(struct MuttWindow *win)
90
0
{
91
0
  for (; win && win->parent; win = win->parent)
92
0
  {
93
0
    if (win->parent->type == WT_ALL_DIALOGS)
94
0
      return win;
95
0
  }
96
97
0
  return NULL;
98
0
}
99
100
/**
101
 * dialog_push - Display a Window to the user
102
 * @param dlg Window to display
103
 *
104
 * The Dialog Windows are kept in a stack.
105
 * The topmost is visible to the user, whilst the others are hidden.
106
 *
107
 * When a Window is pushed, the old Window is marked as not visible.
108
 */
109
void dialog_push(struct MuttWindow *dlg)
110
0
{
111
0
  if (!dlg || !AllDialogsWindow)
112
0
    return;
113
114
0
  struct MuttWindow *last = TAILQ_LAST(&AllDialogsWindow->children, MuttWindowList);
115
0
  if (last)
116
0
    last->state.visible = false;
117
118
0
  TAILQ_INSERT_TAIL(&AllDialogsWindow->children, dlg, entries);
119
0
  notify_set_parent(dlg->notify, AllDialogsWindow->notify);
120
121
  // Notify the world, allowing plugins to integrate
122
0
  mutt_debug(LL_NOTIFY, "NT_WINDOW_DIALOG visible: %s, %p\n",
123
0
             mutt_window_win_name(dlg), (void *) dlg);
124
0
  struct EventWindow ev_w = { dlg, WN_VISIBLE };
125
0
  notify_send(dlg->notify, NT_WINDOW, NT_WINDOW_DIALOG, &ev_w);
126
127
0
  dlg->state.visible = true;
128
0
  dlg->parent = AllDialogsWindow;
129
0
  mutt_window_reflow(AllDialogsWindow);
130
131
#ifdef USE_DEBUG_WINDOW
132
  debug_win_dump();
133
#endif
134
0
}
135
136
/**
137
 * dialog_pop - Hide a Window from the user
138
 *
139
 * The topmost (visible) Window is removed from the stack and the next Window
140
 * is marked as visible.
141
 */
142
void dialog_pop(void)
143
0
{
144
0
  if (!AllDialogsWindow)
145
0
    return;
146
147
0
  struct MuttWindow *last = TAILQ_LAST(&AllDialogsWindow->children, MuttWindowList);
148
0
  if (!last)
149
0
    return;
150
151
  // Notify the world, allowing plugins to clean up
152
0
  mutt_debug(LL_NOTIFY, "NT_WINDOW_DIALOG hidden: %s, %p\n",
153
0
             mutt_window_win_name(last), (void *) last);
154
0
  struct EventWindow ev_w = { last, WN_HIDDEN };
155
0
  notify_send(last->notify, NT_WINDOW, NT_WINDOW_DIALOG, &ev_w);
156
157
0
  last->state.visible = false;
158
0
  last->parent = NULL;
159
0
  TAILQ_REMOVE(&AllDialogsWindow->children, last, entries);
160
161
0
  last = TAILQ_LAST(&AllDialogsWindow->children, MuttWindowList);
162
0
  if (last)
163
0
  {
164
0
    last->state.visible = true;
165
0
    mutt_window_reflow(AllDialogsWindow);
166
0
  }
167
0
  else
168
0
  {
169
0
    AllDialogsWindow->focus = NULL;
170
0
  }
171
#ifdef USE_DEBUG_WINDOW
172
  debug_win_dump();
173
#endif
174
0
}
175
176
/**
177
 * alldialogs_window_observer - Notification that a Window has changed - Implements ::observer_t - @ingroup observer_api
178
 *
179
 * This function is triggered by changes to the windows.
180
 *
181
 * - Delete (this window): clean up the resources held by the All Dialogs window
182
 */
183
static int alldialogs_window_observer(struct NotifyCallback *nc)
184
0
{
185
0
  if (nc->event_type != NT_WINDOW)
186
0
    return 0;
187
0
  if (!nc->global_data || !nc->event_data)
188
0
    return -1;
189
0
  if (nc->event_subtype != NT_WINDOW_DELETE)
190
0
    return 0;
191
192
0
  struct MuttWindow *win_alldlgs = nc->global_data;
193
0
  struct EventWindow *ev_w = nc->event_data;
194
0
  if (ev_w->win != win_alldlgs)
195
0
    return 0;
196
197
0
  notify_observer_remove(win_alldlgs->notify, alldialogs_window_observer, win_alldlgs);
198
199
0
  AllDialogsWindow = NULL;
200
0
  mutt_debug(LL_DEBUG5, "window delete done\n");
201
0
  return 0;
202
0
}
203
204
/**
205
 * alldialogs_new - Create the AllDialogs Window
206
 * @retval ptr New AllDialogs Window
207
 *
208
 * Create the container for all the Dialogs.
209
 */
210
struct MuttWindow *alldialogs_new(void)
211
0
{
212
0
  struct MuttWindow *win_alldlgs = mutt_window_new(WT_ALL_DIALOGS, MUTT_WIN_ORIENT_VERTICAL,
213
0
                                                   MUTT_WIN_SIZE_MAXIMISE, MUTT_WIN_SIZE_UNLIMITED,
214
0
                                                   MUTT_WIN_SIZE_UNLIMITED);
215
216
0
  notify_observer_add(win_alldlgs->notify, NT_WINDOW, alldialogs_window_observer, win_alldlgs);
217
218
0
  AllDialogsWindow = win_alldlgs;
219
220
0
  return win_alldlgs;
221
0
}