dialog-switch.c 11 KB

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