dialog-switch.c 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401
  1. /*
  2. Support of multiply editors and viewers.
  3. Original idea and code: Oleg "Olegarch" Konovalov <olegarch@linuxinside.com>
  4. Copyright (C) 2009-2015
  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. #ifdef HAVE_SLANG
  29. #include "lib/tty/win.h" /* do_enter_ca_mode() */
  30. #endif
  31. #include "lib/widget.h"
  32. #include "event.h"
  33. /*** global variables ****************************************************************************/
  34. WDialog *midnight_dlg = NULL;
  35. /*** file scope macro definitions ****************************************************************/
  36. /*** file scope type declarations ****************************************************************/
  37. /*** file scope variables ************************************************************************/
  38. /* List of dialogs: filemanagers, editors, viewers */
  39. static GList *mc_dialogs = NULL;
  40. /* Currently active dialog */
  41. static GList *mc_current = NULL;
  42. /* Is there any dialogs that we have to run after returning to the manager from another dialog */
  43. static gboolean dialog_switch_pending = FALSE;
  44. /*** file scope functions ************************************************************************/
  45. /* --------------------------------------------------------------------------------------------- */
  46. static unsigned char
  47. get_hotkey (int n)
  48. {
  49. return (n <= 9) ? '0' + n : 'a' + n - 10;
  50. }
  51. /* --------------------------------------------------------------------------------------------- */
  52. static void
  53. dialog_switch_suspend (void *data, void *user_data)
  54. {
  55. (void) user_data;
  56. if (data != mc_current->data)
  57. DIALOG (data)->state = DLG_SUSPENDED;
  58. }
  59. /* --------------------------------------------------------------------------------------------- */
  60. static void
  61. dialog_switch_goto (GList * dlg)
  62. {
  63. if (mc_current != dlg)
  64. {
  65. WDialog *old = DIALOG (mc_current->data);
  66. mc_current = dlg;
  67. if (old == midnight_dlg)
  68. {
  69. /* switch from panels to another dialog (editor, viewer, etc) */
  70. dialog_switch_pending = TRUE;
  71. dialog_switch_process_pending ();
  72. }
  73. else
  74. {
  75. /* switch from editor, viewer, etc to another dialog */
  76. old->state = DLG_SUSPENDED;
  77. if (DIALOG (dlg->data) != midnight_dlg)
  78. /* switch to another editor, viewer, etc */
  79. /* return to panels before run the required dialog */
  80. dialog_switch_pending = TRUE;
  81. else
  82. {
  83. /* switch to panels */
  84. midnight_dlg->state = DLG_ACTIVE;
  85. do_refresh ();
  86. }
  87. }
  88. }
  89. }
  90. /* --------------------------------------------------------------------------------------------- */
  91. static void
  92. dlg_resize_cb (void *data, void *user_data)
  93. {
  94. WDialog *d = data;
  95. (void) user_data;
  96. if (d->state == DLG_ACTIVE)
  97. send_message (d, NULL, MSG_RESIZE, 0, NULL);
  98. else
  99. d->winch_pending = TRUE;
  100. }
  101. /* --------------------------------------------------------------------------------------------- */
  102. /*** public functions ****************************************************************************/
  103. /* --------------------------------------------------------------------------------------------- */
  104. void
  105. dialog_switch_add (WDialog * h)
  106. {
  107. GList *dlg;
  108. dlg = g_list_find (mc_dialogs, h);
  109. if (dlg != NULL)
  110. mc_current = dlg;
  111. else
  112. {
  113. mc_dialogs = g_list_prepend (mc_dialogs, h);
  114. mc_current = mc_dialogs;
  115. }
  116. /* suspend forced all other screens */
  117. g_list_foreach (mc_dialogs, dialog_switch_suspend, NULL);
  118. }
  119. /* --------------------------------------------------------------------------------------------- */
  120. void
  121. dialog_switch_remove (WDialog * h)
  122. {
  123. GList *this;
  124. if (DIALOG (mc_current->data) == h)
  125. this = mc_current;
  126. else
  127. this = g_list_find (mc_dialogs, h);
  128. mc_dialogs = g_list_delete_link (mc_dialogs, this);
  129. /* adjust current dialog */
  130. if (top_dlg != NULL)
  131. mc_current = g_list_find (mc_dialogs, DIALOG (top_dlg->data));
  132. else
  133. mc_current = mc_dialogs;
  134. /* resume forced the current screen */
  135. if (mc_current != NULL)
  136. DIALOG (mc_current->data)->state = DLG_ACTIVE;
  137. }
  138. /* --------------------------------------------------------------------------------------------- */
  139. size_t
  140. dialog_switch_num (void)
  141. {
  142. return g_list_length (mc_dialogs);
  143. }
  144. /* --------------------------------------------------------------------------------------------- */
  145. void
  146. dialog_switch_next (void)
  147. {
  148. GList *next;
  149. if (mc_global.midnight_shutdown || mc_current == NULL)
  150. return;
  151. next = g_list_next (mc_current);
  152. if (next == NULL)
  153. next = mc_dialogs;
  154. dialog_switch_goto (next);
  155. }
  156. /* --------------------------------------------------------------------------------------------- */
  157. void
  158. dialog_switch_prev (void)
  159. {
  160. GList *prev;
  161. if (mc_global.midnight_shutdown || mc_current == NULL)
  162. return;
  163. prev = g_list_previous (mc_current);
  164. if (prev == NULL)
  165. prev = g_list_last (mc_dialogs);
  166. dialog_switch_goto (prev);
  167. }
  168. /* --------------------------------------------------------------------------------------------- */
  169. /* event callback */
  170. gboolean
  171. mc_widget_dialog_show_dialog_list (event_info_t * event_info, gpointer data, GError ** error)
  172. {
  173. WDialog *dialog = (WDialog *) data;
  174. const size_t dlg_num = g_list_length (mc_dialogs);
  175. int lines, cols;
  176. Listbox *listbox;
  177. GList *h;
  178. int i = 0;
  179. int rv;
  180. (void) error;
  181. if (dialog != NULL && dialog->modal)
  182. {
  183. event_info->ret->b = FALSE;
  184. return TRUE;
  185. }
  186. if (mc_global.midnight_shutdown || mc_current == NULL)
  187. return TRUE;
  188. lines = min ((size_t) (LINES * 2 / 3), dlg_num);
  189. cols = COLS * 2 / 3;
  190. listbox = create_listbox_window (lines, cols, _("Screens"), "[Screen selector]");
  191. for (h = mc_dialogs; h != NULL; h = g_list_next (h))
  192. {
  193. WDialog *dlg;
  194. char *title;
  195. dlg = DIALOG (h->data);
  196. if ((dlg != NULL) && (dlg->get_title != NULL))
  197. title = dlg->get_title (dlg, WIDGET (listbox->list)->cols - 2);
  198. else
  199. title = g_strdup ("");
  200. listbox_add_item (listbox->list, LISTBOX_APPEND_BEFORE, get_hotkey (i++), title, NULL);
  201. g_free (title);
  202. }
  203. listbox_select_entry (listbox->list, dlg_num - 1 - g_list_position (mc_dialogs, mc_current));
  204. rv = run_listbox (listbox);
  205. if (rv >= 0)
  206. {
  207. h = g_list_nth (mc_dialogs, dlg_num - 1 - rv);
  208. dialog_switch_goto (h);
  209. }
  210. return TRUE;
  211. }
  212. /* --------------------------------------------------------------------------------------------- */
  213. int
  214. dialog_switch_process_pending (void)
  215. {
  216. int ret = 0;
  217. while (dialog_switch_pending)
  218. {
  219. WDialog *h = DIALOG (mc_current->data);
  220. dialog_switch_pending = FALSE;
  221. h->state = DLG_SUSPENDED;
  222. ret = dlg_run (h);
  223. if (h->state == DLG_CLOSED)
  224. {
  225. dlg_destroy (h);
  226. /* return to panels */
  227. if (mc_global.mc_run_mode == MC_RUN_FULL)
  228. {
  229. mc_current = g_list_find (mc_dialogs, midnight_dlg);
  230. mc_event_dispatch (MCEVENT_GROUP_FILEMANAGER_PANEL, "update_panels", NULL, NULL,
  231. NULL);
  232. }
  233. }
  234. }
  235. repaint_screen ();
  236. return ret;
  237. }
  238. /* --------------------------------------------------------------------------------------------- */
  239. void
  240. dialog_switch_got_winch (void)
  241. {
  242. GList *dlg;
  243. for (dlg = mc_dialogs; dlg != NULL; dlg = g_list_next (dlg))
  244. if (dlg != mc_current)
  245. DIALOG (dlg->data)->winch_pending = TRUE;
  246. }
  247. /* --------------------------------------------------------------------------------------------- */
  248. void
  249. dialog_switch_shutdown (void)
  250. {
  251. while (mc_dialogs != NULL)
  252. {
  253. WDialog *dlg = DIALOG (mc_dialogs->data);
  254. dlg_run (dlg);
  255. dlg_destroy (dlg);
  256. }
  257. }
  258. /* --------------------------------------------------------------------------------------------- */
  259. void
  260. clr_scr (void)
  261. {
  262. tty_set_normal_attrs ();
  263. tty_fill_region (0, 0, LINES, COLS, ' ');
  264. tty_refresh ();
  265. }
  266. /* --------------------------------------------------------------------------------------------- */
  267. void
  268. repaint_screen (void)
  269. {
  270. do_refresh ();
  271. tty_refresh ();
  272. }
  273. /* --------------------------------------------------------------------------------------------- */
  274. void
  275. mc_refresh (void)
  276. {
  277. #ifdef ENABLE_BACKGROUND
  278. if (mc_global.we_are_background)
  279. return;
  280. #endif /* ENABLE_BACKGROUND */
  281. if (mc_global.tty.winch_flag == 0)
  282. tty_refresh ();
  283. else
  284. {
  285. /* if winch was caugth, we should do not only redraw screen, but
  286. reposition/resize all */
  287. dialog_change_screen_size ();
  288. }
  289. }
  290. /* --------------------------------------------------------------------------------------------- */
  291. void
  292. dialog_change_screen_size (void)
  293. {
  294. mc_global.tty.winch_flag = 0;
  295. tty_change_screen_size ();
  296. #ifdef HAVE_SLANG
  297. do_enter_ca_mode ();
  298. tty_keypad (TRUE);
  299. tty_nodelay (FALSE);
  300. #endif
  301. /* Inform all suspending dialogs */
  302. dialog_switch_got_winch ();
  303. /* Inform all running dialogs */
  304. g_list_foreach (top_dlg, (GFunc) dlg_resize_cb, NULL);
  305. /* Now, force the redraw */
  306. repaint_screen ();
  307. }
  308. /* --------------------------------------------------------------------------------------------- */