9455480876595aaedf926f7986e3ed21bfca1463
[midnight-commander.git] / lib / widget / dialog-switch.c
blob9455480876595aaedf926f7986e3ed21bfca1463
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 #ifdef HAVE_SLANG
39 #include "lib/tty/win.h" /* do_enter_ca_mode() */
40 #endif
41 #include "lib/widget.h"
42 #include "lib/event.h"
44 /*** global variables ****************************************************************************/
46 Dlg_head *midnight_dlg = NULL;
48 /*** file scope macro definitions ****************************************************************/
50 /*** file scope type declarations ****************************************************************/
52 /*** file scope variables ************************************************************************/
54 /* List of dialogs: filemanagers, editors, viewers */
55 static GList *mc_dialogs = NULL;
56 /* Currently active dialog */
57 static GList *mc_current = NULL;
58 /* Is there any dialogs that we have to run after returning to the manager from another dialog */
59 static gboolean dialog_switch_pending = FALSE;
61 /*** file scope functions ************************************************************************/
62 /* --------------------------------------------------------------------------------------------- */
64 static unsigned char
65 get_hotkey (int n)
67 return (n <= 9) ? '0' + n : 'a' + n - 10;
70 /* --------------------------------------------------------------------------------------------- */
72 static void
73 dialog_switch_suspend (void *data, void *user_data)
75 (void) user_data;
77 if (data != mc_current->data)
78 ((Dlg_head *) data)->state = DLG_SUSPENDED;
81 /* --------------------------------------------------------------------------------------------- */
83 static void
84 dialog_switch_goto (GList * dlg)
86 if (mc_current != dlg)
88 Dlg_head *old = (Dlg_head *) mc_current->data;
90 mc_current = dlg;
92 if (old == midnight_dlg)
94 /* switch from panels to another dialog (editor, viewer, etc) */
95 dialog_switch_pending = TRUE;
96 dialog_switch_process_pending ();
98 else
100 /* switch from editor, viewer, etc to another dialog */
101 old->state = DLG_SUSPENDED;
103 if ((Dlg_head *) dlg->data != midnight_dlg)
104 /* switch to another editor, viewer, etc */
105 /* return to panels before run the required dialog */
106 dialog_switch_pending = TRUE;
107 else
109 /* switch to panels */
110 midnight_dlg->state = DLG_ACTIVE;
111 do_refresh ();
117 /* --------------------------------------------------------------------------------------------- */
119 static void
120 dlg_resize_cb (void *data, void *user_data)
122 Dlg_head *d = data;
124 (void) user_data;
125 if (d->state == DLG_ACTIVE)
126 d->callback (d, NULL, DLG_RESIZE, 0, NULL);
127 else
128 d->winch_pending = TRUE;
131 /* --------------------------------------------------------------------------------------------- */
132 /*** public functions ****************************************************************************/
133 /* --------------------------------------------------------------------------------------------- */
135 void
136 dialog_switch_add (Dlg_head * h)
138 GList *dlg;
140 dlg = g_list_find (mc_dialogs, h);
142 if (dlg != NULL)
143 mc_current = dlg;
144 else
146 mc_dialogs = g_list_prepend (mc_dialogs, h);
147 mc_current = mc_dialogs;
150 /* suspend forced all other screens */
151 g_list_foreach (mc_dialogs, dialog_switch_suspend, NULL);
154 /* --------------------------------------------------------------------------------------------- */
156 void
157 dialog_switch_remove (Dlg_head * h)
159 GList *this;
161 if ((Dlg_head *) mc_current->data == h)
162 this = mc_current;
163 else
164 this = g_list_find (mc_dialogs, h);
166 mc_dialogs = g_list_delete_link (mc_dialogs, this);
168 /* adjust current dialog */
169 if (top_dlg != NULL)
170 mc_current = g_list_find (mc_dialogs, (Dlg_head *) top_dlg->data);
171 else
172 mc_current = mc_dialogs;
174 /* resume forced the current screen */
175 if (mc_current != NULL)
176 ((Dlg_head *) mc_current->data)->state = DLG_ACTIVE;
179 /* --------------------------------------------------------------------------------------------- */
181 size_t
182 dialog_switch_num (void)
184 return g_list_length (mc_dialogs);
187 /* --------------------------------------------------------------------------------------------- */
189 void
190 dialog_switch_next (void)
192 GList *next;
194 if (mc_global.midnight_shutdown || mc_current == NULL)
195 return;
197 next = g_list_next (mc_current);
198 if (next == NULL)
199 next = mc_dialogs;
201 dialog_switch_goto (next);
204 /* --------------------------------------------------------------------------------------------- */
206 void
207 dialog_switch_prev (void)
209 GList *prev;
211 if (mc_global.midnight_shutdown || mc_current == NULL)
212 return;
214 prev = g_list_previous (mc_current);
215 if (prev == NULL)
216 prev = g_list_last (mc_dialogs);
218 dialog_switch_goto (prev);
221 /* --------------------------------------------------------------------------------------------- */
223 void
224 dialog_switch_list (void)
226 const size_t dlg_num = g_list_length (mc_dialogs);
227 int lines, cols;
228 Listbox *listbox;
229 GList *h;
230 int i = 0;
231 int rv;
233 if (mc_global.midnight_shutdown || mc_current == NULL)
234 return;
236 lines = min ((size_t) (LINES * 2 / 3), dlg_num);
237 cols = COLS * 2 / 3;
239 listbox = create_listbox_window (lines, cols, _("Screens"), "[Screen selector]");
241 for (h = mc_dialogs; h != NULL; h = g_list_next (h))
243 Dlg_head *dlg;
244 char *title;
246 dlg = (Dlg_head *) h->data;
248 if ((dlg != NULL) && (dlg->get_title != NULL))
249 title = dlg->get_title (dlg, listbox->list->widget.cols - 2); /* FIXME! */
250 else
251 title = g_strdup ("");
253 listbox_add_item (listbox->list, LISTBOX_APPEND_BEFORE, get_hotkey (i++), title, NULL);
255 g_free (title);
258 listbox_select_entry (listbox->list, dlg_num - 1 - g_list_position (mc_dialogs, mc_current));
259 rv = run_listbox (listbox);
261 if (rv >= 0)
263 h = g_list_nth (mc_dialogs, dlg_num - 1 - rv);
264 dialog_switch_goto (h);
268 /* --------------------------------------------------------------------------------------------- */
271 dialog_switch_process_pending (void)
273 int ret = 0;
275 while (dialog_switch_pending)
277 Dlg_head *h = (Dlg_head *) mc_current->data;
279 dialog_switch_pending = FALSE;
280 h->state = DLG_SUSPENDED;
281 ret = run_dlg (h);
282 if (h->state == DLG_CLOSED)
284 destroy_dlg (h);
286 /* return to panels */
287 if (mc_global.mc_run_mode == MC_RUN_FULL)
289 mc_current = g_list_find (mc_dialogs, midnight_dlg);
290 mc_event_raise (MCEVENT_GROUP_FILEMANAGER, "update_panels", NULL);
295 repaint_screen ();
297 return ret;
300 /* --------------------------------------------------------------------------------------------- */
302 void
303 dialog_switch_got_winch (void)
305 GList *dlg;
307 for (dlg = mc_dialogs; dlg != NULL; dlg = g_list_next (dlg))
308 if (dlg != mc_current)
309 ((Dlg_head *) dlg->data)->winch_pending = TRUE;
312 /* --------------------------------------------------------------------------------------------- */
314 void
315 dialog_switch_shutdown (void)
317 while (mc_dialogs != NULL)
319 Dlg_head *dlg = (Dlg_head *) mc_dialogs->data;
321 run_dlg (dlg);
322 destroy_dlg (dlg);
326 /* --------------------------------------------------------------------------------------------- */
328 void
329 clr_scr (void)
331 tty_set_normal_attrs ();
332 tty_fill_region (0, 0, LINES, COLS, ' ');
333 tty_refresh ();
336 /* --------------------------------------------------------------------------------------------- */
338 void
339 repaint_screen (void)
341 do_refresh ();
342 tty_refresh ();
345 /* --------------------------------------------------------------------------------------------- */
347 void
348 mc_refresh (void)
350 #ifdef ENABLE_BACKGROUND
351 if (mc_global.we_are_background)
352 return;
353 #endif /* ENABLE_BACKGROUND */
354 if (!mc_global.tty.winch_flag)
355 tty_refresh ();
356 else
358 /* if winch was caugth, we should do not only redraw screen, but
359 reposition/resize all */
360 dialog_change_screen_size ();
364 /* --------------------------------------------------------------------------------------------- */
366 void
367 dialog_change_screen_size (void)
369 mc_global.tty.winch_flag = FALSE;
371 tty_change_screen_size ();
373 #ifdef HAVE_SLANG
374 do_enter_ca_mode ();
375 tty_keypad (TRUE);
376 tty_nodelay (FALSE);
377 #endif
379 /* Inform all suspending dialogs */
380 dialog_switch_got_winch ();
381 /* Inform all running dialogs */
382 g_list_foreach (top_dlg, (GFunc) dlg_resize_cb, NULL);
384 /* Now, force the redraw */
385 repaint_screen ();
388 /* --------------------------------------------------------------------------------------------- */