dialog-switch.c 9.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360
  1. /*
  2. * Copyright (c) 2009, 2010 Free Software Foundation
  3. *
  4. * This program is free software; you can redistribute it and/or modify
  5. * it under the terms of the GNU General Public License as published by
  6. * the Free Software Foundation; either version 2 of the License, or
  7. * (at your option) any later version.
  8. *
  9. * This program is distributed in the hope that it will be useful,
  10. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  12. * GNU General Public License for more details.
  13. *
  14. * You should have received a copy of the GNU General Public License
  15. * along with this program; if not, write to the Free Software
  16. * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
  17. *
  18. * Original idea and code: Oleg "Olegarch" Konovalov <olegarch@linuxinside.com>
  19. * Written by: 2007 Daniel Borca <dborca@yahoo.com>
  20. * 2010 Andrew Borodin <aborodin@vmail.ru>
  21. */
  22. /** \file dialog-switch.c
  23. * \brief Source: support of multiply editors and viewers.
  24. */
  25. #include <config.h>
  26. /* If TIOCGWINSZ supported, make it available here, because window resizing code
  27. * depends on it... */
  28. #ifdef HAVE_SYS_IOCTL_H
  29. #include <sys/ioctl.h>
  30. #endif
  31. #include <termios.h>
  32. #include "lib/global.h"
  33. #include "lib/tty/tty.h" /* LINES, COLS */
  34. #include "lib/tty/win.h" /* do_enter_ca_mode() */
  35. #include "lib/tty/color.h" /* tty_set_normal_attrs() */
  36. #include "lib/widget.h"
  37. #include "lib/event.h"
  38. /*** global variables ****************************************************************************/
  39. Dlg_head *midnight_dlg = NULL;
  40. /*** file scope macro definitions ****************************************************************/
  41. /*** file scope type declarations ****************************************************************/
  42. /*** file scope variables ************************************************************************/
  43. /* List of dialogs: filemanagers, editors, viewers */
  44. static GList *mc_dialogs = NULL;
  45. /* Currently active dialog */
  46. static GList *mc_current = NULL;
  47. /* Is there any dialogs that we have to run after returning to the manager from another dialog */
  48. static gboolean dialog_switch_pending = FALSE;
  49. /*** file scope functions ************************************************************************/
  50. /* --------------------------------------------------------------------------------------------- */
  51. static unsigned char
  52. get_hotkey (int n)
  53. {
  54. return (n <= 9) ? '0' + n : 'a' + n - 10;
  55. }
  56. /* --------------------------------------------------------------------------------------------- */
  57. static void
  58. dialog_switch_goto (GList * dlg)
  59. {
  60. if (mc_current != dlg)
  61. {
  62. Dlg_head *old = (Dlg_head *) mc_current->data;
  63. mc_current = dlg;
  64. if (old == midnight_dlg)
  65. {
  66. /* switch from panels to another dialog (editor, viewer, etc) */
  67. dialog_switch_pending = TRUE;
  68. dialog_switch_process_pending ();
  69. }
  70. else
  71. {
  72. /* switch from editor, viewer, etc to another dialog */
  73. old->state = DLG_SUSPENDED;
  74. if ((Dlg_head *) dlg->data != midnight_dlg)
  75. /* switch to another editor, viewer, etc */
  76. /* return to panels before run the required dialog */
  77. dialog_switch_pending = TRUE;
  78. else
  79. /* switch to panels */
  80. do_refresh ();
  81. }
  82. }
  83. }
  84. /* --------------------------------------------------------------------------------------------- */
  85. #if defined TIOCGWINSZ
  86. static void
  87. dlg_resize_cb (void *data, void *user_data)
  88. {
  89. Dlg_head *d = data;
  90. (void) user_data;
  91. d->callback (d, NULL, DLG_RESIZE, 0, NULL);
  92. }
  93. #endif
  94. /* --------------------------------------------------------------------------------------------- */
  95. /*** public functions ****************************************************************************/
  96. /* --------------------------------------------------------------------------------------------- */
  97. void
  98. dialog_switch_add (Dlg_head * h)
  99. {
  100. GList *dlg;
  101. dlg = g_list_find (mc_dialogs, h);
  102. if (dlg != NULL)
  103. mc_current = dlg;
  104. else
  105. {
  106. mc_dialogs = g_list_prepend (mc_dialogs, h);
  107. mc_current = mc_dialogs;
  108. }
  109. }
  110. /* --------------------------------------------------------------------------------------------- */
  111. void
  112. dialog_switch_remove (Dlg_head * h)
  113. {
  114. GList *this;
  115. if ((Dlg_head *) mc_current->data == h)
  116. this = mc_current;
  117. else
  118. this = g_list_find (mc_dialogs, h);
  119. mc_dialogs = g_list_delete_link (mc_dialogs, this);
  120. /* adjust current dialog */
  121. if (top_dlg != NULL)
  122. mc_current = g_list_find (mc_dialogs, (Dlg_head *) top_dlg->data);
  123. else
  124. mc_current = mc_dialogs;
  125. }
  126. /* --------------------------------------------------------------------------------------------- */
  127. size_t
  128. dialog_switch_num (void)
  129. {
  130. return g_list_length (mc_dialogs);
  131. }
  132. /* --------------------------------------------------------------------------------------------- */
  133. void
  134. dialog_switch_next (void)
  135. {
  136. GList *next;
  137. if (mc_global.widget.midnight_shutdown || mc_current == NULL)
  138. return;
  139. next = g_list_next (mc_current);
  140. if (next == NULL)
  141. next = mc_dialogs;
  142. dialog_switch_goto (next);
  143. }
  144. /* --------------------------------------------------------------------------------------------- */
  145. void
  146. dialog_switch_prev (void)
  147. {
  148. GList *prev;
  149. if (mc_global.widget.midnight_shutdown || mc_current == NULL)
  150. return;
  151. prev = g_list_previous (mc_current);
  152. if (prev == NULL)
  153. prev = g_list_last (mc_dialogs);
  154. dialog_switch_goto (prev);
  155. }
  156. /* --------------------------------------------------------------------------------------------- */
  157. void
  158. dialog_switch_list (void)
  159. {
  160. const size_t dlg_num = g_list_length (mc_dialogs);
  161. int lines, cols;
  162. Listbox *listbox;
  163. GList *h;
  164. int i = 0;
  165. int rv;
  166. if (mc_global.widget.midnight_shutdown || mc_current == NULL)
  167. return;
  168. lines = min ((size_t) (LINES * 2 / 3), dlg_num);
  169. cols = COLS * 2 / 3;
  170. listbox = create_listbox_window (lines, cols, _("Screens"), "[Screen selector]");
  171. for (h = mc_dialogs; h != NULL; h = g_list_next (h))
  172. {
  173. Dlg_head *dlg;
  174. char *title;
  175. dlg = (Dlg_head *) h->data;
  176. if ((dlg != NULL) && (dlg->get_title != NULL))
  177. title = dlg->get_title (dlg, listbox->list->widget.cols - 2); /* FIXME! */
  178. else
  179. title = g_strdup ("");
  180. listbox_add_item (listbox->list, LISTBOX_APPEND_BEFORE, get_hotkey (i++), title, NULL);
  181. g_free (title);
  182. }
  183. listbox_select_entry (listbox->list, dlg_num - 1 - g_list_position (mc_dialogs, mc_current));
  184. rv = run_listbox (listbox);
  185. if (rv >= 0)
  186. {
  187. h = g_list_nth (mc_dialogs, dlg_num - 1 - rv);
  188. dialog_switch_goto (h);
  189. }
  190. }
  191. /* --------------------------------------------------------------------------------------------- */
  192. int
  193. dialog_switch_process_pending (void)
  194. {
  195. int ret = 0;
  196. while (dialog_switch_pending)
  197. {
  198. Dlg_head *h = (Dlg_head *) mc_current->data;
  199. dialog_switch_pending = FALSE;
  200. h->state = DLG_SUSPENDED;
  201. ret = run_dlg (h);
  202. if (h->state == DLG_CLOSED)
  203. {
  204. destroy_dlg (h);
  205. /* return to panels */
  206. if (mc_global.mc_run_mode == MC_RUN_FULL)
  207. {
  208. mc_current = g_list_find (mc_dialogs, midnight_dlg);
  209. mc_event_raise (MCEVENT_GROUP_FILEMANAGER, "update_panels", NULL);
  210. }
  211. }
  212. }
  213. repaint_screen ();
  214. return ret;
  215. }
  216. /* --------------------------------------------------------------------------------------------- */
  217. void
  218. dialog_switch_got_winch (void)
  219. {
  220. GList *dlg;
  221. for (dlg = mc_dialogs; dlg != NULL; dlg = g_list_next (dlg))
  222. if (dlg != mc_current)
  223. ((Dlg_head *) dlg->data)->winch_pending = TRUE;
  224. }
  225. /* --------------------------------------------------------------------------------------------- */
  226. void
  227. dialog_switch_shutdown (void)
  228. {
  229. while (mc_dialogs != NULL)
  230. {
  231. Dlg_head *dlg = (Dlg_head *) mc_dialogs->data;
  232. run_dlg (dlg);
  233. destroy_dlg (dlg);
  234. }
  235. }
  236. /* --------------------------------------------------------------------------------------------- */
  237. void
  238. clr_scr (void)
  239. {
  240. tty_set_normal_attrs ();
  241. tty_fill_region (0, 0, LINES, COLS, ' ');
  242. tty_refresh ();
  243. }
  244. /* --------------------------------------------------------------------------------------------- */
  245. void
  246. repaint_screen (void)
  247. {
  248. do_refresh ();
  249. tty_refresh ();
  250. }
  251. /* --------------------------------------------------------------------------------------------- */
  252. void
  253. dialog_change_screen_size (void)
  254. {
  255. mc_global.tty.winch_flag = FALSE;
  256. #if defined(HAVE_SLANG) || NCURSES_VERSION_MAJOR >= 4
  257. #if defined TIOCGWINSZ
  258. #ifndef NCURSES_VERSION
  259. tty_noraw_mode ();
  260. tty_reset_screen ();
  261. #endif
  262. tty_low_level_change_screen_size ();
  263. #ifdef HAVE_SLANG
  264. /* XSI Curses spec states that portable applications shall not invoke
  265. * initscr() more than once. This kludge could be done within the scope
  266. * of the specification by using endwin followed by a refresh (in fact,
  267. * more than one curses implementation does this); it is guaranteed to work
  268. * only with slang.
  269. */
  270. SLsmg_init_smg ();
  271. do_enter_ca_mode ();
  272. tty_keypad (TRUE);
  273. tty_nodelay (FALSE);
  274. #endif
  275. /* Inform all suspending dialogs */
  276. dialog_switch_got_winch ();
  277. /* Inform all running dialogs */
  278. g_list_foreach (top_dlg, (GFunc) dlg_resize_cb, NULL);
  279. /* Now, force the redraw */
  280. repaint_screen ();
  281. #endif /* TIOCGWINSZ */
  282. #endif /* defined(HAVE_SLANG) || NCURSES_VERSION_MAJOR >= 4 */
  283. }
  284. /* --------------------------------------------------------------------------------------------- */