dialog-switch.c 9.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368
  1. /*
  2. Support of multiply editors and viewers.
  3. Original idea and code: Oleg "Olegarch" Konovalov <olegarch@linuxinside.com>
  4. Copyright (C) 2009-2021
  5. Free Software Foundation, Inc.
  6. Written by:
  7. Daniel Borca <dborca@yahoo.com>, 2007
  8. Andrew Borodin <aborodin@vmail.ru>, 2010, 2013
  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. #include "lib/global.h"
  26. #include "lib/tty/tty.h" /* LINES, COLS */
  27. #include "lib/tty/color.h" /* tty_set_normal_attrs() */
  28. #include "lib/widget.h"
  29. #include "lib/event.h"
  30. /*** global variables ****************************************************************************/
  31. WDialog *filemanager = NULL;
  32. /*** file scope macro definitions ****************************************************************/
  33. /*** file scope type declarations ****************************************************************/
  34. /*** file scope variables ************************************************************************/
  35. /* List of dialogs: filemanagers, editors, viewers */
  36. static GList *mc_dialogs = NULL;
  37. /* Currently active dialog */
  38. static GList *mc_current = NULL;
  39. /* Is there any dialogs that we have to run after returning to the manager from another dialog */
  40. static gboolean dialog_switch_pending = FALSE;
  41. /*** file scope functions ************************************************************************/
  42. /* --------------------------------------------------------------------------------------------- */
  43. static unsigned char
  44. get_hotkey (int n)
  45. {
  46. return (n <= 9) ? '0' + n : 'a' + n - 10;
  47. }
  48. /* --------------------------------------------------------------------------------------------- */
  49. static void
  50. dialog_switch_suspend (void *data, void *user_data)
  51. {
  52. (void) user_data;
  53. if (data != mc_current->data)
  54. widget_set_state (WIDGET (data), WST_SUSPENDED, TRUE);
  55. }
  56. /* --------------------------------------------------------------------------------------------- */
  57. static void
  58. dialog_switch_goto (GList * dlg)
  59. {
  60. if (mc_current != dlg)
  61. {
  62. WDialog *old = DIALOG (mc_current->data);
  63. mc_current = dlg;
  64. if (old == filemanager)
  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. widget_set_state (WIDGET (old), WST_SUSPENDED, TRUE);
  74. if (DIALOG (dlg->data) != filemanager)
  75. /* switch to another editor, viewer, etc */
  76. /* return to panels before run the required dialog */
  77. dialog_switch_pending = TRUE;
  78. else
  79. {
  80. /* switch to panels */
  81. widget_set_state (WIDGET (filemanager), WST_ACTIVE, TRUE);
  82. do_refresh ();
  83. }
  84. }
  85. }
  86. }
  87. /* --------------------------------------------------------------------------------------------- */
  88. static void
  89. dialog_switch_resize (WDialog * d)
  90. {
  91. if (widget_get_state (WIDGET (d), WST_ACTIVE))
  92. send_message (d, NULL, MSG_RESIZE, 0, NULL);
  93. else
  94. GROUP (d)->winch_pending = TRUE;
  95. }
  96. /* --------------------------------------------------------------------------------------------- */
  97. /*** public functions ****************************************************************************/
  98. /* --------------------------------------------------------------------------------------------- */
  99. void
  100. dialog_switch_add (WDialog * h)
  101. {
  102. GList *dlg;
  103. dlg = g_list_find (mc_dialogs, h);
  104. if (dlg != NULL)
  105. mc_current = dlg;
  106. else
  107. {
  108. mc_dialogs = g_list_prepend (mc_dialogs, h);
  109. mc_current = mc_dialogs;
  110. }
  111. /* suspend forced all other screens */
  112. g_list_foreach (mc_dialogs, dialog_switch_suspend, NULL);
  113. }
  114. /* --------------------------------------------------------------------------------------------- */
  115. void
  116. dialog_switch_remove (WDialog * h)
  117. {
  118. GList *this;
  119. if (DIALOG (mc_current->data) == h)
  120. this = mc_current;
  121. else
  122. this = g_list_find (mc_dialogs, h);
  123. mc_dialogs = g_list_delete_link (mc_dialogs, this);
  124. /* adjust current dialog */
  125. if (top_dlg != NULL)
  126. mc_current = g_list_find (mc_dialogs, DIALOG (top_dlg->data));
  127. else
  128. mc_current = mc_dialogs;
  129. /* resume forced the current screen */
  130. if (mc_current != NULL)
  131. widget_set_state (WIDGET (mc_current->data), WST_ACTIVE, TRUE);
  132. }
  133. /* --------------------------------------------------------------------------------------------- */
  134. size_t
  135. dialog_switch_num (void)
  136. {
  137. return g_list_length (mc_dialogs);
  138. }
  139. /* --------------------------------------------------------------------------------------------- */
  140. void
  141. dialog_switch_next (void)
  142. {
  143. GList *next;
  144. if (mc_global.midnight_shutdown || mc_current == NULL)
  145. return;
  146. next = g_list_next (mc_current);
  147. if (next == NULL)
  148. next = mc_dialogs;
  149. dialog_switch_goto (next);
  150. }
  151. /* --------------------------------------------------------------------------------------------- */
  152. void
  153. dialog_switch_prev (void)
  154. {
  155. GList *prev;
  156. if (mc_global.midnight_shutdown || mc_current == NULL)
  157. return;
  158. prev = g_list_previous (mc_current);
  159. if (prev == NULL)
  160. prev = g_list_last (mc_dialogs);
  161. dialog_switch_goto (prev);
  162. }
  163. /* --------------------------------------------------------------------------------------------- */
  164. void
  165. dialog_switch_list (void)
  166. {
  167. const size_t dlg_num = g_list_length (mc_dialogs);
  168. int lines, cols;
  169. Listbox *listbox;
  170. GList *h, *selected;
  171. int i = 0;
  172. if (mc_global.midnight_shutdown || mc_current == NULL)
  173. return;
  174. lines = MIN ((size_t) (LINES * 2 / 3), dlg_num);
  175. cols = COLS * 2 / 3;
  176. listbox = create_listbox_window (lines, cols, _("Screens"), "[Screen selector]");
  177. for (h = mc_dialogs; h != NULL; h = g_list_next (h))
  178. {
  179. WDialog *dlg = DIALOG (h->data);
  180. char *title;
  181. if (dlg->get_title != NULL)
  182. title = dlg->get_title (dlg, WIDGET (listbox->list)->cols - 2);
  183. else
  184. title = g_strdup ("");
  185. listbox_add_item (listbox->list, LISTBOX_APPEND_BEFORE, get_hotkey (i++), title, h, FALSE);
  186. g_free (title);
  187. }
  188. selected = run_listbox_with_data (listbox, mc_current);
  189. if (selected != NULL)
  190. dialog_switch_goto (selected);
  191. }
  192. /* --------------------------------------------------------------------------------------------- */
  193. int
  194. dialog_switch_process_pending (void)
  195. {
  196. int ret = 0;
  197. while (dialog_switch_pending)
  198. {
  199. WDialog *h = DIALOG (mc_current->data);
  200. Widget *wh = WIDGET (h);
  201. dialog_switch_pending = FALSE;
  202. widget_set_state (wh, WST_SUSPENDED, TRUE);
  203. ret = dlg_run (h);
  204. if (widget_get_state (wh, WST_CLOSED))
  205. {
  206. widget_destroy (wh);
  207. /* return to panels */
  208. if (mc_global.mc_run_mode == MC_RUN_FULL)
  209. {
  210. mc_current = g_list_find (mc_dialogs, filemanager);
  211. mc_event_raise (MCEVENT_GROUP_FILEMANAGER, "update_panels", NULL);
  212. }
  213. }
  214. }
  215. repaint_screen ();
  216. return ret;
  217. }
  218. /* --------------------------------------------------------------------------------------------- */
  219. void
  220. dialog_switch_got_winch (void)
  221. {
  222. GList *dlg;
  223. for (dlg = mc_dialogs; dlg != NULL; dlg = g_list_next (dlg))
  224. if (dlg != mc_current)
  225. GROUP (dlg->data)->winch_pending = TRUE;
  226. }
  227. /* --------------------------------------------------------------------------------------------- */
  228. void
  229. dialog_switch_shutdown (void)
  230. {
  231. while (mc_dialogs != NULL)
  232. {
  233. WDialog *dlg = DIALOG (mc_dialogs->data);
  234. dlg_run (dlg);
  235. widget_destroy (WIDGET (dlg));
  236. }
  237. }
  238. /* --------------------------------------------------------------------------------------------- */
  239. void
  240. repaint_screen (void)
  241. {
  242. do_refresh ();
  243. tty_refresh ();
  244. }
  245. /* --------------------------------------------------------------------------------------------- */
  246. void
  247. mc_refresh (void)
  248. {
  249. #ifdef ENABLE_BACKGROUND
  250. if (mc_global.we_are_background)
  251. return;
  252. #endif /* ENABLE_BACKGROUND */
  253. if (!tty_got_winch ())
  254. tty_refresh ();
  255. else
  256. {
  257. /* if winch was caugth, we should do not only redraw screen, but
  258. reposition/resize all */
  259. dialog_change_screen_size ();
  260. }
  261. }
  262. /* --------------------------------------------------------------------------------------------- */
  263. void
  264. dialog_change_screen_size (void)
  265. {
  266. GList *d;
  267. tty_flush_winch ();
  268. tty_change_screen_size ();
  269. #ifdef HAVE_SLANG
  270. tty_keypad (TRUE);
  271. tty_nodelay (FALSE);
  272. #endif
  273. /* Inform all suspending dialogs */
  274. dialog_switch_got_winch ();
  275. /* Inform all running dialogs from first to last */
  276. for (d = g_list_last (top_dlg); d != NULL; d = g_list_previous (d))
  277. dialog_switch_resize (DIALOG (d->data));
  278. /* Now, force the redraw */
  279. repaint_screen ();
  280. }
  281. /* --------------------------------------------------------------------------------------------- */