dialog-switch.c 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408
  1. /*
  2. Support of multiply editors and viewers.
  3. Original idea and code: Oleg "Olegarch" Konovalov <olegarch@linuxinside.com>
  4. Copyright (C) 2009-2024
  5. Free Software Foundation, Inc.
  6. Written by:
  7. Daniel Borca <dborca@yahoo.com>, 2007
  8. Andrew Borodin <aborodin@vmail.ru>, 2010-2022
  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. /* Primitive way to check if the the current dialog is our dialog */
  32. /* This is needed by async routines like load_prompt */
  33. GList *top_dlg = NULL;
  34. /* If set then dialogs just clean the screen when refreshing, else */
  35. /* they do a complete refresh, refreshing all the parts of the program */
  36. gboolean fast_refresh = FALSE;
  37. WDialog *filemanager = NULL;
  38. /*** file scope macro definitions ****************************************************************/
  39. /*** file scope type declarations ****************************************************************/
  40. /*** forward declarations (file scope functions) *************************************************/
  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. /* --------------------------------------------------------------------------------------------- */
  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_suspend (void *data, void *user_data)
  59. {
  60. (void) user_data;
  61. if (data != mc_current->data)
  62. widget_set_state (WIDGET (data), WST_SUSPENDED, TRUE);
  63. }
  64. /* --------------------------------------------------------------------------------------------- */
  65. static void
  66. dialog_switch_goto (GList *dlg)
  67. {
  68. if (mc_current != dlg)
  69. {
  70. WDialog *old = DIALOG (mc_current->data);
  71. mc_current = dlg;
  72. if (old == filemanager)
  73. {
  74. /* switch from panels to another dialog (editor, viewer, etc) */
  75. dialog_switch_pending = TRUE;
  76. dialog_switch_process_pending ();
  77. }
  78. else
  79. {
  80. /* switch from editor, viewer, etc to another dialog */
  81. widget_set_state (WIDGET (old), WST_SUSPENDED, TRUE);
  82. if (DIALOG (dlg->data) != filemanager)
  83. /* switch to another editor, viewer, etc */
  84. /* return to panels before run the required dialog */
  85. dialog_switch_pending = TRUE;
  86. else
  87. {
  88. /* switch to panels */
  89. widget_set_state (WIDGET (filemanager), WST_ACTIVE, TRUE);
  90. do_refresh ();
  91. }
  92. }
  93. }
  94. }
  95. /* --------------------------------------------------------------------------------------------- */
  96. static void
  97. dialog_switch_resize (WDialog *d)
  98. {
  99. if (widget_get_state (WIDGET (d), WST_ACTIVE))
  100. send_message (d, NULL, MSG_RESIZE, 0, NULL);
  101. else
  102. GROUP (d)->winch_pending = TRUE;
  103. }
  104. /* --------------------------------------------------------------------------------------------- */
  105. /*** public functions ****************************************************************************/
  106. /* --------------------------------------------------------------------------------------------- */
  107. void
  108. dialog_switch_add (WDialog *h)
  109. {
  110. GList *dlg;
  111. dlg = g_list_find (mc_dialogs, h);
  112. if (dlg != NULL)
  113. mc_current = dlg;
  114. else
  115. {
  116. mc_dialogs = g_list_prepend (mc_dialogs, h);
  117. mc_current = mc_dialogs;
  118. }
  119. /* suspend forced all other screens */
  120. g_list_foreach (mc_dialogs, dialog_switch_suspend, NULL);
  121. }
  122. /* --------------------------------------------------------------------------------------------- */
  123. void
  124. dialog_switch_remove (WDialog *h)
  125. {
  126. GList *this;
  127. if (DIALOG (mc_current->data) == h)
  128. this = mc_current;
  129. else
  130. this = g_list_find (mc_dialogs, h);
  131. mc_dialogs = g_list_delete_link (mc_dialogs, this);
  132. /* adjust current dialog */
  133. if (top_dlg != NULL)
  134. mc_current = g_list_find (mc_dialogs, DIALOG (top_dlg->data));
  135. else
  136. mc_current = mc_dialogs;
  137. /* resume forced the current screen */
  138. if (mc_current != NULL)
  139. widget_set_state (WIDGET (mc_current->data), WST_ACTIVE, TRUE);
  140. }
  141. /* --------------------------------------------------------------------------------------------- */
  142. size_t
  143. dialog_switch_num (void)
  144. {
  145. return g_list_length (mc_dialogs);
  146. }
  147. /* --------------------------------------------------------------------------------------------- */
  148. void
  149. dialog_switch_next (void)
  150. {
  151. GList *next;
  152. if (mc_global.midnight_shutdown || mc_current == NULL)
  153. return;
  154. next = g_list_next (mc_current);
  155. if (next == NULL)
  156. next = mc_dialogs;
  157. dialog_switch_goto (next);
  158. }
  159. /* --------------------------------------------------------------------------------------------- */
  160. void
  161. dialog_switch_prev (void)
  162. {
  163. GList *prev;
  164. if (mc_global.midnight_shutdown || mc_current == NULL)
  165. return;
  166. prev = g_list_previous (mc_current);
  167. if (prev == NULL)
  168. prev = g_list_last (mc_dialogs);
  169. dialog_switch_goto (prev);
  170. }
  171. /* --------------------------------------------------------------------------------------------- */
  172. void
  173. dialog_switch_list (void)
  174. {
  175. const size_t dlg_num = g_list_length (mc_dialogs);
  176. int lines, cols;
  177. Listbox *listbox;
  178. GList *h, *selected;
  179. int i = 0;
  180. if (mc_global.midnight_shutdown || mc_current == NULL)
  181. return;
  182. lines = MIN ((size_t) (LINES * 2 / 3), dlg_num);
  183. cols = COLS * 2 / 3;
  184. listbox = listbox_window_new (lines, cols, _ ("Screens"), "[Screen selector]");
  185. for (h = mc_dialogs; h != NULL; h = g_list_next (h))
  186. {
  187. WDialog *dlg = DIALOG (h->data);
  188. char *title;
  189. if (dlg->get_title != NULL)
  190. title = dlg->get_title (dlg, WIDGET (listbox->list)->rect.cols - 2);
  191. else
  192. title = g_strdup ("");
  193. listbox_add_item_take (listbox->list, LISTBOX_APPEND_BEFORE, get_hotkey (i++), title, h,
  194. FALSE);
  195. }
  196. selected = listbox_run_with_data (listbox, mc_current);
  197. if (selected != NULL)
  198. dialog_switch_goto (selected);
  199. }
  200. /* --------------------------------------------------------------------------------------------- */
  201. int
  202. dialog_switch_process_pending (void)
  203. {
  204. int ret = 0;
  205. while (dialog_switch_pending)
  206. {
  207. WDialog *h = DIALOG (mc_current->data);
  208. Widget *wh = WIDGET (h);
  209. dialog_switch_pending = FALSE;
  210. widget_set_state (wh, WST_SUSPENDED, TRUE);
  211. ret = dlg_run (h);
  212. if (widget_get_state (wh, WST_CLOSED))
  213. {
  214. widget_destroy (wh);
  215. /* return to panels */
  216. if (mc_global.mc_run_mode == MC_RUN_FULL)
  217. {
  218. mc_current = g_list_find (mc_dialogs, filemanager);
  219. mc_event_raise (MCEVENT_GROUP_FILEMANAGER, "update_panels", NULL);
  220. }
  221. }
  222. }
  223. repaint_screen ();
  224. return ret;
  225. }
  226. /* --------------------------------------------------------------------------------------------- */
  227. void
  228. dialog_switch_got_winch (void)
  229. {
  230. GList *dlg;
  231. for (dlg = mc_dialogs; dlg != NULL; dlg = g_list_next (dlg))
  232. if (dlg != mc_current)
  233. GROUP (dlg->data)->winch_pending = TRUE;
  234. }
  235. /* --------------------------------------------------------------------------------------------- */
  236. void
  237. dialog_switch_shutdown (void)
  238. {
  239. while (mc_dialogs != NULL)
  240. {
  241. WDialog *dlg = DIALOG (mc_dialogs->data);
  242. dlg_run (dlg);
  243. widget_destroy (WIDGET (dlg));
  244. }
  245. }
  246. /* --------------------------------------------------------------------------------------------- */
  247. void
  248. do_refresh (void)
  249. {
  250. GList *d = top_dlg;
  251. if (fast_refresh)
  252. {
  253. if (d != NULL)
  254. widget_draw (WIDGET (d->data));
  255. }
  256. else
  257. {
  258. /* Search first fullscreen dialog */
  259. for (; d != NULL; d = g_list_next (d))
  260. if ((WIDGET (d->data)->pos_flags & WPOS_FULLSCREEN) != 0)
  261. break;
  262. /* when small dialog (i.e. error message) is created first,
  263. there is no fullscreen dialog in the stack */
  264. if (d == NULL)
  265. d = g_list_last (top_dlg);
  266. /* back to top dialog */
  267. for (; d != NULL; d = g_list_previous (d))
  268. widget_draw (WIDGET (d->data));
  269. }
  270. }
  271. /* --------------------------------------------------------------------------------------------- */
  272. void
  273. repaint_screen (void)
  274. {
  275. do_refresh ();
  276. tty_refresh ();
  277. }
  278. /* --------------------------------------------------------------------------------------------- */
  279. void
  280. mc_refresh (void)
  281. {
  282. #ifdef ENABLE_BACKGROUND
  283. if (mc_global.we_are_background)
  284. return;
  285. #endif /* ENABLE_BACKGROUND */
  286. if (!tty_got_winch ())
  287. tty_refresh ();
  288. else
  289. {
  290. /* if winch was caugth, we should do not only redraw screen, but
  291. reposition/resize all */
  292. dialog_change_screen_size ();
  293. }
  294. }
  295. /* --------------------------------------------------------------------------------------------- */
  296. void
  297. dialog_change_screen_size (void)
  298. {
  299. GList *d;
  300. tty_flush_winch ();
  301. tty_change_screen_size ();
  302. #ifdef HAVE_SLANG
  303. tty_keypad (TRUE);
  304. tty_nodelay (FALSE);
  305. #endif
  306. /* Inform all suspending dialogs */
  307. dialog_switch_got_winch ();
  308. /* Inform all running dialogs from first to last */
  309. for (d = g_list_last (top_dlg); d != NULL; d = g_list_previous (d))
  310. dialog_switch_resize (DIALOG (d->data));
  311. /* Now, force the redraw */
  312. repaint_screen ();
  313. }
  314. /* --------------------------------------------------------------------------------------------- */