Ticket 1551: Update GPL version from 2 to 3
[midnight-commander.git] / lib / widget / dialog-switch.c
blobe8d2a29ba9853a7fc6f79ca70ea0e93340304f85
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 /* If TIOCGWINSZ supported, make it available here, because window resizing code
36 * depends on it... */
37 #ifdef HAVE_SYS_IOCTL_H
38 #include <sys/ioctl.h>
39 #endif
40 #include <termios.h>
42 #include "lib/global.h"
43 #include "lib/tty/tty.h" /* LINES, COLS */
44 #include "lib/tty/win.h" /* do_enter_ca_mode() */
45 #include "lib/tty/color.h" /* tty_set_normal_attrs() */
46 #include "lib/widget.h"
47 #include "lib/event.h"
49 /*** global variables ****************************************************************************/
51 Dlg_head *midnight_dlg = NULL;
53 /*** file scope macro definitions ****************************************************************/
55 /*** file scope type declarations ****************************************************************/
57 /*** file scope variables ************************************************************************/
59 /* List of dialogs: filemanagers, editors, viewers */
60 static GList *mc_dialogs = NULL;
61 /* Currently active dialog */
62 static GList *mc_current = NULL;
63 /* Is there any dialogs that we have to run after returning to the manager from another dialog */
64 static gboolean dialog_switch_pending = FALSE;
66 /*** file scope functions ************************************************************************/
67 /* --------------------------------------------------------------------------------------------- */
69 static unsigned char
70 get_hotkey (int n)
72 return (n <= 9) ? '0' + n : 'a' + n - 10;
75 /* --------------------------------------------------------------------------------------------- */
77 static void
78 dialog_switch_goto (GList * dlg)
80 if (mc_current != dlg)
82 Dlg_head *old = (Dlg_head *) mc_current->data;
84 mc_current = dlg;
86 if (old == midnight_dlg)
88 /* switch from panels to another dialog (editor, viewer, etc) */
89 dialog_switch_pending = TRUE;
90 dialog_switch_process_pending ();
92 else
94 /* switch from editor, viewer, etc to another dialog */
95 old->state = DLG_SUSPENDED;
97 if ((Dlg_head *) dlg->data != midnight_dlg)
98 /* switch to another editor, viewer, etc */
99 /* return to panels before run the required dialog */
100 dialog_switch_pending = TRUE;
101 else
102 /* switch to panels */
103 do_refresh ();
108 /* --------------------------------------------------------------------------------------------- */
110 #if defined TIOCGWINSZ
111 static void
112 dlg_resize_cb (void *data, void *user_data)
114 Dlg_head *d = data;
116 (void) user_data;
117 d->callback (d, NULL, DLG_RESIZE, 0, NULL);
119 #endif
121 /* --------------------------------------------------------------------------------------------- */
122 /*** public functions ****************************************************************************/
123 /* --------------------------------------------------------------------------------------------- */
125 void
126 dialog_switch_add (Dlg_head * h)
128 GList *dlg;
130 dlg = g_list_find (mc_dialogs, h);
132 if (dlg != NULL)
133 mc_current = dlg;
134 else
136 mc_dialogs = g_list_prepend (mc_dialogs, h);
137 mc_current = mc_dialogs;
141 /* --------------------------------------------------------------------------------------------- */
143 void
144 dialog_switch_remove (Dlg_head * h)
146 GList *this;
148 if ((Dlg_head *) mc_current->data == h)
149 this = mc_current;
150 else
151 this = g_list_find (mc_dialogs, h);
153 mc_dialogs = g_list_delete_link (mc_dialogs, this);
155 /* adjust current dialog */
156 if (top_dlg != NULL)
157 mc_current = g_list_find (mc_dialogs, (Dlg_head *) top_dlg->data);
158 else
159 mc_current = mc_dialogs;
162 /* --------------------------------------------------------------------------------------------- */
164 size_t
165 dialog_switch_num (void)
167 return g_list_length (mc_dialogs);
170 /* --------------------------------------------------------------------------------------------- */
172 void
173 dialog_switch_next (void)
175 GList *next;
177 if (mc_global.widget.midnight_shutdown || mc_current == NULL)
178 return;
180 next = g_list_next (mc_current);
181 if (next == NULL)
182 next = mc_dialogs;
184 dialog_switch_goto (next);
187 /* --------------------------------------------------------------------------------------------- */
189 void
190 dialog_switch_prev (void)
192 GList *prev;
194 if (mc_global.widget.midnight_shutdown || mc_current == NULL)
195 return;
197 prev = g_list_previous (mc_current);
198 if (prev == NULL)
199 prev = g_list_last (mc_dialogs);
201 dialog_switch_goto (prev);
204 /* --------------------------------------------------------------------------------------------- */
206 void
207 dialog_switch_list (void)
209 const size_t dlg_num = g_list_length (mc_dialogs);
210 int lines, cols;
211 Listbox *listbox;
212 GList *h;
213 int i = 0;
214 int rv;
216 if (mc_global.widget.midnight_shutdown || mc_current == NULL)
217 return;
219 lines = min ((size_t) (LINES * 2 / 3), dlg_num);
220 cols = COLS * 2 / 3;
222 listbox = create_listbox_window (lines, cols, _("Screens"), "[Screen selector]");
224 for (h = mc_dialogs; h != NULL; h = g_list_next (h))
226 Dlg_head *dlg;
227 char *title;
229 dlg = (Dlg_head *) h->data;
231 if ((dlg != NULL) && (dlg->get_title != NULL))
232 title = dlg->get_title (dlg, listbox->list->widget.cols - 2); /* FIXME! */
233 else
234 title = g_strdup ("");
236 listbox_add_item (listbox->list, LISTBOX_APPEND_BEFORE, get_hotkey (i++), title, NULL);
238 g_free (title);
241 listbox_select_entry (listbox->list, dlg_num - 1 - g_list_position (mc_dialogs, mc_current));
242 rv = run_listbox (listbox);
244 if (rv >= 0)
246 h = g_list_nth (mc_dialogs, dlg_num - 1 - rv);
247 dialog_switch_goto (h);
251 /* --------------------------------------------------------------------------------------------- */
254 dialog_switch_process_pending (void)
256 int ret = 0;
258 while (dialog_switch_pending)
260 Dlg_head *h = (Dlg_head *) mc_current->data;
262 dialog_switch_pending = FALSE;
263 h->state = DLG_SUSPENDED;
264 ret = run_dlg (h);
265 if (h->state == DLG_CLOSED)
267 destroy_dlg (h);
268 /* return to panels */
269 if (mc_global.mc_run_mode == MC_RUN_FULL)
271 mc_current = g_list_find (mc_dialogs, midnight_dlg);
272 mc_event_raise (MCEVENT_GROUP_FILEMANAGER, "update_panels", NULL);
277 repaint_screen ();
279 return ret;
282 /* --------------------------------------------------------------------------------------------- */
284 void
285 dialog_switch_got_winch (void)
287 GList *dlg;
289 for (dlg = mc_dialogs; dlg != NULL; dlg = g_list_next (dlg))
290 if (dlg != mc_current)
291 ((Dlg_head *) dlg->data)->winch_pending = TRUE;
294 /* --------------------------------------------------------------------------------------------- */
296 void
297 dialog_switch_shutdown (void)
299 while (mc_dialogs != NULL)
301 Dlg_head *dlg = (Dlg_head *) mc_dialogs->data;
303 run_dlg (dlg);
304 destroy_dlg (dlg);
308 /* --------------------------------------------------------------------------------------------- */
310 void
311 clr_scr (void)
313 tty_set_normal_attrs ();
314 tty_fill_region (0, 0, LINES, COLS, ' ');
315 tty_refresh ();
318 /* --------------------------------------------------------------------------------------------- */
320 void
321 repaint_screen (void)
323 do_refresh ();
324 tty_refresh ();
327 /* --------------------------------------------------------------------------------------------- */
329 void
330 mc_refresh (void)
332 #ifdef WITH_BACKGROUND
333 if (mc_global.we_are_background)
334 return;
335 #endif /* WITH_BACKGROUND */
336 if (!mc_global.tty.winch_flag)
337 tty_refresh ();
338 else
340 /* if winch was caugth, we should do not only redraw screen, but
341 reposition/resize all */
342 dialog_change_screen_size ();
346 /* --------------------------------------------------------------------------------------------- */
348 void
349 dialog_change_screen_size (void)
351 mc_global.tty.winch_flag = FALSE;
352 #if defined(HAVE_SLANG) || NCURSES_VERSION_MAJOR >= 4
353 #if defined TIOCGWINSZ
355 #ifndef NCURSES_VERSION
356 tty_noraw_mode ();
357 tty_reset_screen ();
358 #endif
359 tty_change_screen_size ();
360 #ifdef HAVE_SLANG
361 /* XSI Curses spec states that portable applications shall not invoke
362 * initscr() more than once. This kludge could be done within the scope
363 * of the specification by using endwin followed by a refresh (in fact,
364 * more than one curses implementation does this); it is guaranteed to work
365 * only with slang.
367 SLsmg_init_smg ();
368 do_enter_ca_mode ();
369 tty_keypad (TRUE);
370 tty_nodelay (FALSE);
371 #endif
373 /* Inform all suspending dialogs */
374 dialog_switch_got_winch ();
375 /* Inform all running dialogs */
376 g_list_foreach (top_dlg, (GFunc) dlg_resize_cb, NULL);
378 /* Now, force the redraw */
379 repaint_screen ();
381 #endif /* TIOCGWINSZ */
382 #endif /* defined(HAVE_SLANG) || NCURSES_VERSION_MAJOR >= 4 */
385 /* --------------------------------------------------------------------------------------------- */