Refactoring of subshell support.
[midnight-commander.git] / lib / widget / dialog-switch.c
blob3f9a9f07b9e95a182d4f41c297a8284b80d4857c
1 /*
2 Support of multiply editors and viewers.
4 Original idea and code: Oleg "Olegarch" Konovalov <olegarch@linuxinside.com>
6 Copyright (c) 2009, 2010, 2011
7 The Free Software Foundation
9 Written by:
10 Daniel Borca <dborca@yahoo.com>, 2007
11 Andrew Borodin <aborodin@vmail.ru>, 2010
13 This file is part of the Midnight Commander.
15 The Midnight Commander is free software: you can redistribute it
16 and/or modify it under the terms of the GNU General Public License as
17 published by the Free Software Foundation, either version 3 of the License,
18 or (at your option) any later version.
20 The Midnight Commander is distributed in the hope that it will be useful,
21 but WITHOUT ANY WARRANTY; without even the implied warranty of
22 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
23 GNU General Public License for more details.
25 You should have received a copy of the GNU General Public License
26 along with this program. If not, see <http://www.gnu.org/licenses/>.
29 /** \file dialog-switch.c
30 * \brief Source: support of multiply editors and viewers.
33 #include <config.h>
35 #include "lib/global.h"
36 #include "lib/tty/tty.h" /* LINES, COLS */
37 #include "lib/tty/color.h" /* tty_set_normal_attrs() */
38 #include "lib/widget.h"
39 #include "lib/event.h"
41 /*** global variables ****************************************************************************/
43 Dlg_head *midnight_dlg = NULL;
45 /*** file scope macro definitions ****************************************************************/
47 /*** file scope type declarations ****************************************************************/
49 /*** file scope variables ************************************************************************/
51 /* List of dialogs: filemanagers, editors, viewers */
52 static GList *mc_dialogs = NULL;
53 /* Currently active dialog */
54 static GList *mc_current = NULL;
55 /* Is there any dialogs that we have to run after returning to the manager from another dialog */
56 static gboolean dialog_switch_pending = FALSE;
58 /*** file scope functions ************************************************************************/
59 /* --------------------------------------------------------------------------------------------- */
61 static unsigned char
62 get_hotkey (int n)
64 return (n <= 9) ? '0' + n : 'a' + n - 10;
67 /* --------------------------------------------------------------------------------------------- */
69 static void
70 dialog_switch_suspend (void *data, void *user_data)
72 (void) user_data;
74 if (data != mc_current->data)
75 ((Dlg_head *) data)->state = DLG_SUSPENDED;
78 /* --------------------------------------------------------------------------------------------- */
80 static void
81 dialog_switch_goto (GList * dlg)
83 if (mc_current != dlg)
85 Dlg_head *old = (Dlg_head *) mc_current->data;
87 mc_current = dlg;
89 if (old == midnight_dlg)
91 /* switch from panels to another dialog (editor, viewer, etc) */
92 dialog_switch_pending = TRUE;
93 dialog_switch_process_pending ();
95 else
97 /* switch from editor, viewer, etc to another dialog */
98 old->state = DLG_SUSPENDED;
100 if ((Dlg_head *) dlg->data != midnight_dlg)
101 /* switch to another editor, viewer, etc */
102 /* return to panels before run the required dialog */
103 dialog_switch_pending = TRUE;
104 else
106 /* switch to panels */
107 midnight_dlg->state = DLG_ACTIVE;
108 do_refresh ();
114 /* --------------------------------------------------------------------------------------------- */
116 static void
117 dlg_resize_cb (void *data, void *user_data)
119 Dlg_head *d = data;
121 (void) user_data;
122 if (d->state == DLG_ACTIVE)
123 d->callback (d, NULL, DLG_RESIZE, 0, NULL);
124 else
125 d->winch_pending = TRUE;
128 /* --------------------------------------------------------------------------------------------- */
129 /*** public functions ****************************************************************************/
130 /* --------------------------------------------------------------------------------------------- */
132 void
133 dialog_switch_add (Dlg_head * h)
135 GList *dlg;
137 dlg = g_list_find (mc_dialogs, h);
139 if (dlg != NULL)
140 mc_current = dlg;
141 else
143 mc_dialogs = g_list_prepend (mc_dialogs, h);
144 mc_current = mc_dialogs;
147 /* suspend forced all other screens */
148 g_list_foreach (mc_dialogs, dialog_switch_suspend, NULL);
151 /* --------------------------------------------------------------------------------------------- */
153 void
154 dialog_switch_remove (Dlg_head * h)
156 GList *this;
158 if ((Dlg_head *) mc_current->data == h)
159 this = mc_current;
160 else
161 this = g_list_find (mc_dialogs, h);
163 mc_dialogs = g_list_delete_link (mc_dialogs, this);
165 /* adjust current dialog */
166 if (top_dlg != NULL)
167 mc_current = g_list_find (mc_dialogs, (Dlg_head *) top_dlg->data);
168 else
169 mc_current = mc_dialogs;
171 /* resume forced the current screen */
172 if (mc_current != NULL)
173 ((Dlg_head *) mc_current->data)->state = DLG_ACTIVE;
176 /* --------------------------------------------------------------------------------------------- */
178 size_t
179 dialog_switch_num (void)
181 return g_list_length (mc_dialogs);
184 /* --------------------------------------------------------------------------------------------- */
186 void
187 dialog_switch_next (void)
189 GList *next;
191 if (mc_global.midnight_shutdown || mc_current == NULL)
192 return;
194 next = g_list_next (mc_current);
195 if (next == NULL)
196 next = mc_dialogs;
198 dialog_switch_goto (next);
201 /* --------------------------------------------------------------------------------------------- */
203 void
204 dialog_switch_prev (void)
206 GList *prev;
208 if (mc_global.midnight_shutdown || mc_current == NULL)
209 return;
211 prev = g_list_previous (mc_current);
212 if (prev == NULL)
213 prev = g_list_last (mc_dialogs);
215 dialog_switch_goto (prev);
218 /* --------------------------------------------------------------------------------------------- */
220 void
221 dialog_switch_list (void)
223 const size_t dlg_num = g_list_length (mc_dialogs);
224 int lines, cols;
225 Listbox *listbox;
226 GList *h;
227 int i = 0;
228 int rv;
230 if (mc_global.midnight_shutdown || mc_current == NULL)
231 return;
233 lines = min ((size_t) (LINES * 2 / 3), dlg_num);
234 cols = COLS * 2 / 3;
236 listbox = create_listbox_window (lines, cols, _("Screens"), "[Screen selector]");
238 for (h = mc_dialogs; h != NULL; h = g_list_next (h))
240 Dlg_head *dlg;
241 char *title;
243 dlg = (Dlg_head *) h->data;
245 if ((dlg != NULL) && (dlg->get_title != NULL))
246 title = dlg->get_title (dlg, listbox->list->widget.cols - 2); /* FIXME! */
247 else
248 title = g_strdup ("");
250 listbox_add_item (listbox->list, LISTBOX_APPEND_BEFORE, get_hotkey (i++), title, NULL);
252 g_free (title);
255 listbox_select_entry (listbox->list, dlg_num - 1 - g_list_position (mc_dialogs, mc_current));
256 rv = run_listbox (listbox);
258 if (rv >= 0)
260 h = g_list_nth (mc_dialogs, dlg_num - 1 - rv);
261 dialog_switch_goto (h);
265 /* --------------------------------------------------------------------------------------------- */
268 dialog_switch_process_pending (void)
270 int ret = 0;
272 while (dialog_switch_pending)
274 Dlg_head *h = (Dlg_head *) mc_current->data;
276 dialog_switch_pending = FALSE;
277 h->state = DLG_SUSPENDED;
278 ret = run_dlg (h);
279 if (h->state == DLG_CLOSED)
281 destroy_dlg (h);
283 /* return to panels */
284 if (mc_global.mc_run_mode == MC_RUN_FULL)
286 mc_current = g_list_find (mc_dialogs, midnight_dlg);
287 mc_event_raise (MCEVENT_GROUP_FILEMANAGER, "update_panels", NULL);
292 repaint_screen ();
294 return ret;
297 /* --------------------------------------------------------------------------------------------- */
299 void
300 dialog_switch_got_winch (void)
302 GList *dlg;
304 for (dlg = mc_dialogs; dlg != NULL; dlg = g_list_next (dlg))
305 if (dlg != mc_current)
306 ((Dlg_head *) dlg->data)->winch_pending = TRUE;
309 /* --------------------------------------------------------------------------------------------- */
311 void
312 dialog_switch_shutdown (void)
314 while (mc_dialogs != NULL)
316 Dlg_head *dlg = (Dlg_head *) mc_dialogs->data;
318 run_dlg (dlg);
319 destroy_dlg (dlg);
323 /* --------------------------------------------------------------------------------------------- */
325 void
326 clr_scr (void)
328 tty_set_normal_attrs ();
329 tty_fill_region (0, 0, LINES, COLS, ' ');
330 tty_refresh ();
333 /* --------------------------------------------------------------------------------------------- */
335 void
336 repaint_screen (void)
338 do_refresh ();
339 tty_refresh ();
342 /* --------------------------------------------------------------------------------------------- */
344 void
345 mc_refresh (void)
347 #ifdef ENABLE_BACKGROUND
348 if (mc_global.we_are_background)
349 return;
350 #endif /* ENABLE_BACKGROUND */
351 if (!mc_global.tty.winch_flag)
352 tty_refresh ();
353 else
355 /* if winch was caugth, we should do not only redraw screen, but
356 reposition/resize all */
357 dialog_change_screen_size ();
361 /* --------------------------------------------------------------------------------------------- */
363 void
364 dialog_change_screen_size (void)
366 mc_global.tty.winch_flag = FALSE;
368 tty_change_screen_size ();
370 #ifdef ENABLE_SUBSHELL
371 if (mc_global.tty.use_subshell)
372 tty_resize (mc_global.tty.subshell_pty);
373 #endif
375 /* Inform all suspending dialogs */
376 dialog_switch_got_winch ();
377 /* Inform all running dialogs */
378 g_list_foreach (top_dlg, (GFunc) dlg_resize_cb, NULL);
380 /* Now, force the redraw */
381 repaint_screen ();
384 /* --------------------------------------------------------------------------------------------- */