/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 | } |