Manual pages: mcmcdiffmceditmcview

root/lib/widget/dialog-switch.c

/* [previous][next][first][last][top][bottom][index][help]  */

DEFINITIONS

This source file includes following definitions.
  1. get_hotkey
  2. dialog_switch_suspend
  3. dialog_switch_goto
  4. dialog_switch_resize
  5. dialog_switch_add
  6. dialog_switch_remove
  7. dialog_switch_num
  8. dialog_switch_next
  9. dialog_switch_prev
  10. dialog_switch_list
  11. dialog_switch_process_pending
  12. dialog_switch_got_winch
  13. dialog_switch_shutdown
  14. do_refresh
  15. repaint_screen
  16. mc_refresh
  17. dialog_change_screen_size

   1 /*
   2    Support of multiply editors and viewers.
   3 
   4    Original idea and code: Oleg "Olegarch" Konovalov <olegarch@linuxinside.com>
   5 
   6    Copyright (C) 2009-2026
   7    Free Software Foundation, Inc.
   8 
   9    Written by:
  10    Daniel Borca <dborca@yahoo.com>, 2007
  11    Andrew Borodin <aborodin@vmail.ru>, 2010-2022
  12 
  13    This file is part of the Midnight Commander.
  14 
  15    The Midnight Commander is free software: you can redistribute it
  16    and/or modify it under the terms of the GNU General Public License as
  17    published by the Free Software Foundation, either version 3 of the License,
  18    or (at your option) any later version.
  19 
  20    The Midnight Commander is distributed in the hope that it will be useful,
  21    but WITHOUT ANY WARRANTY; without even the implied warranty of
  22    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  23    GNU General Public License for more details.
  24 
  25    You should have received a copy of the GNU General Public License
  26    along with this program.  If not, see <https://www.gnu.org/licenses/>.
  27  */
  28 
  29 /** \file dialog-switch.c
  30  *  \brief Source: support of multiply editors and viewers.
  31  */
  32 
  33 #include <config.h>
  34 
  35 #include "lib/global.h"
  36 #include "lib/tty/tty.h"  // LINES, COLS
  37 #include "lib/widget.h"
  38 #include "lib/event.h"
  39 
  40 /*** global variables ****************************************************************************/
  41 
  42 /* Primitive way to check if the the current dialog is our dialog */
  43 /* This is needed by async routines like load_prompt */
  44 GList *top_dlg = NULL;
  45 
  46 WDialog *filemanager = NULL;
  47 
  48 /*** file scope macro definitions ****************************************************************/
  49 
  50 /*** file scope type declarations ****************************************************************/
  51 
  52 /*** forward declarations (file scope functions) *************************************************/
  53 
  54 /*** file scope variables ************************************************************************/
  55 
  56 /* List of dialogs: filemanagers, editors, viewers */
  57 static GList *mc_dialogs = NULL;
  58 /* Currently active dialog */
  59 static GList *mc_current = NULL;
  60 /* Is there any dialogs that we have to run after returning to the manager from another dialog */
  61 static gboolean dialog_switch_pending = FALSE;
  62 
  63 /* --------------------------------------------------------------------------------------------- */
  64 /*** file scope functions ************************************************************************/
  65 /* --------------------------------------------------------------------------------------------- */
  66 
  67 static unsigned char
  68 get_hotkey (int n)
     /* [previous][next][first][last][top][bottom][index][help]  */
  69 {
  70     return (n <= 9) ? '0' + n : 'a' + n - 10;
  71 }
  72 
  73 /* --------------------------------------------------------------------------------------------- */
  74 
  75 static void
  76 dialog_switch_suspend (void *data, void *user_data)
     /* [previous][next][first][last][top][bottom][index][help]  */
  77 {
  78     (void) user_data;
  79 
  80     if (data != mc_current->data)
  81         widget_set_state (WIDGET (data), WST_SUSPENDED, TRUE);
  82 }
  83 
  84 /* --------------------------------------------------------------------------------------------- */
  85 
  86 static void
  87 dialog_switch_goto (GList *dlg)
     /* [previous][next][first][last][top][bottom][index][help]  */
  88 {
  89     if (mc_current != dlg)
  90     {
  91         WDialog *old = DIALOG (mc_current->data);
  92 
  93         mc_current = dlg;
  94 
  95         if (old == filemanager)
  96         {
  97             // switch from panels to another dialog (editor, viewer, etc)
  98             dialog_switch_pending = TRUE;
  99             dialog_switch_process_pending ();
 100         }
 101         else
 102         {
 103             // switch from editor, viewer, etc to another dialog
 104             widget_set_state (WIDGET (old), WST_SUSPENDED, TRUE);
 105 
 106             if (DIALOG (dlg->data) != filemanager)
 107                 // switch to another editor, viewer, etc
 108                 // return to panels before run the required dialog
 109                 dialog_switch_pending = TRUE;
 110             else
 111             {
 112                 // switch to panels
 113                 widget_set_state (WIDGET (filemanager), WST_ACTIVE, TRUE);
 114                 do_refresh ();
 115             }
 116         }
 117     }
 118 }
 119 
 120 /* --------------------------------------------------------------------------------------------- */
 121 
 122 static void
 123 dialog_switch_resize (WDialog *d)
     /* [previous][next][first][last][top][bottom][index][help]  */
 124 {
 125     if (widget_get_state (WIDGET (d), WST_ACTIVE))
 126         send_message (d, NULL, MSG_RESIZE, 0, NULL);
 127     else
 128         GROUP (d)->winch_pending = TRUE;
 129 }
 130 
 131 /* --------------------------------------------------------------------------------------------- */
 132 /*** public functions ****************************************************************************/
 133 /* --------------------------------------------------------------------------------------------- */
 134 
 135 void
 136 dialog_switch_add (WDialog *h)
     /* [previous][next][first][last][top][bottom][index][help]  */
 137 {
 138     GList *dlg;
 139 
 140     dlg = g_list_find (mc_dialogs, h);
 141 
 142     if (dlg != NULL)
 143         mc_current = dlg;
 144     else
 145     {
 146         mc_dialogs = g_list_prepend (mc_dialogs, h);
 147         mc_current = mc_dialogs;
 148     }
 149 
 150     // suspend forced all other screens
 151     g_list_foreach (mc_dialogs, dialog_switch_suspend, NULL);
 152 }
 153 
 154 /* --------------------------------------------------------------------------------------------- */
 155 
 156 void
 157 dialog_switch_remove (WDialog *h)
     /* [previous][next][first][last][top][bottom][index][help]  */
 158 {
 159     GList *this;
 160 
 161     if (DIALOG (mc_current->data) == h)
 162         this = mc_current;
 163     else
 164         this = g_list_find (mc_dialogs, h);
 165 
 166     mc_dialogs = g_list_delete_link (mc_dialogs, this);
 167 
 168     // adjust current dialog
 169     if (top_dlg != NULL)
 170         mc_current = g_list_find (mc_dialogs, DIALOG (top_dlg->data));
 171     else
 172         mc_current = mc_dialogs;
 173 
 174     // resume forced the current screen
 175     if (mc_current != NULL)
 176         widget_set_state (WIDGET (mc_current->data), WST_ACTIVE, TRUE);
 177 }
 178 
 179 /* --------------------------------------------------------------------------------------------- */
 180 
 181 size_t
 182 dialog_switch_num (void)
     /* [previous][next][first][last][top][bottom][index][help]  */
 183 {
 184     return g_list_length (mc_dialogs);
 185 }
 186 
 187 /* --------------------------------------------------------------------------------------------- */
 188 
 189 void
 190 dialog_switch_next (void)
     /* [previous][next][first][last][top][bottom][index][help]  */
 191 {
 192     GList *next;
 193 
 194     if (mc_global.midnight_shutdown || mc_current == NULL)
 195         return;
 196 
 197     next = g_list_next (mc_current);
 198     if (next == NULL)
 199         next = mc_dialogs;
 200 
 201     dialog_switch_goto (next);
 202 }
 203 
 204 /* --------------------------------------------------------------------------------------------- */
 205 
 206 void
 207 dialog_switch_prev (void)
     /* [previous][next][first][last][top][bottom][index][help]  */
 208 {
 209     GList *prev;
 210 
 211     if (mc_global.midnight_shutdown || mc_current == NULL)
 212         return;
 213 
 214     prev = g_list_previous (mc_current);
 215     if (prev == NULL)
 216         prev = g_list_last (mc_dialogs);
 217 
 218     dialog_switch_goto (prev);
 219 }
 220 
 221 /* --------------------------------------------------------------------------------------------- */
 222 
 223 void
 224 dialog_switch_list (void)
     /* [previous][next][first][last][top][bottom][index][help]  */
 225 {
 226     const size_t dlg_num = g_list_length (mc_dialogs);
 227     int lines, cols;
 228     Listbox *listbox;
 229     GList *h, *selected;
 230     int i = 0;
 231 
 232     if (mc_global.midnight_shutdown || mc_current == NULL)
 233         return;
 234 
 235     lines = MIN ((size_t) (LINES * 2 / 3), dlg_num);
 236     cols = COLS * 2 / 3;
 237 
 238     listbox = listbox_window_new (lines, cols, _ ("Screens"), "[Screen selector]");
 239 
 240     for (h = mc_dialogs; h != NULL; h = g_list_next (h))
 241     {
 242         WDialog *dlg = DIALOG (h->data);
 243         char *title;
 244 
 245         if (dlg->get_title != NULL)
 246             title = dlg->get_title (dlg, WIDGET (listbox->list)->rect.cols - 2);
 247         else
 248             title = g_strdup ("");
 249 
 250         listbox_add_item_take (listbox->list, LISTBOX_APPEND_BEFORE, get_hotkey (i++), title, h,
 251                                FALSE);
 252     }
 253 
 254     selected = listbox_run_with_data (listbox, mc_current);
 255     if (selected != NULL)
 256         dialog_switch_goto (selected);
 257 }
 258 
 259 /* --------------------------------------------------------------------------------------------- */
 260 
 261 int
 262 dialog_switch_process_pending (void)
     /* [previous][next][first][last][top][bottom][index][help]  */
 263 {
 264     int ret = 0;
 265 
 266     if (mc_current == NULL)
 267         return ret;
 268 
 269     if (!dialog_switch_pending)
 270     {
 271         WDialog *h = DIALOG (mc_current->data);
 272 
 273         // return to panels and reload them forced
 274         if (mc_global.mc_run_mode == MC_RUN_FULL && h == filemanager)
 275             mc_event_raise (MCEVENT_GROUP_FILEMANAGER, "update_panels", NULL);
 276     }
 277     else
 278         while (dialog_switch_pending)
 279         {
 280             WDialog *h = DIALOG (mc_current->data);
 281             Widget *wh = WIDGET (h);
 282 
 283             dialog_switch_pending = FALSE;
 284             widget_set_state (wh, WST_SUSPENDED, TRUE);
 285             ret = dlg_run (h);
 286             if (widget_get_state (wh, WST_CLOSED))
 287             {
 288                 widget_destroy (wh);
 289 
 290                 // return to panels
 291                 if (mc_global.mc_run_mode == MC_RUN_FULL)
 292                 {
 293                     mc_current = g_list_find (mc_dialogs, filemanager);
 294                     mc_event_raise (MCEVENT_GROUP_FILEMANAGER, "update_panels", NULL);
 295                 }
 296             }
 297         }
 298 
 299     repaint_screen ();
 300 
 301     return ret;
 302 }
 303 
 304 /* --------------------------------------------------------------------------------------------- */
 305 
 306 void
 307 dialog_switch_got_winch (void)
     /* [previous][next][first][last][top][bottom][index][help]  */
 308 {
 309     GList *dlg;
 310 
 311     for (dlg = mc_dialogs; dlg != NULL; dlg = g_list_next (dlg))
 312         if (dlg != mc_current)
 313             GROUP (dlg->data)->winch_pending = TRUE;
 314 }
 315 
 316 /* --------------------------------------------------------------------------------------------- */
 317 
 318 void
 319 dialog_switch_shutdown (void)
     /* [previous][next][first][last][top][bottom][index][help]  */
 320 {
 321     while (mc_dialogs != NULL)
 322     {
 323         WDialog *dlg = DIALOG (mc_dialogs->data);
 324 
 325         dlg_run (dlg);
 326         widget_destroy (WIDGET (dlg));
 327     }
 328 }
 329 
 330 /* --------------------------------------------------------------------------------------------- */
 331 
 332 void
 333 do_refresh (void)
     /* [previous][next][first][last][top][bottom][index][help]  */
 334 {
 335     GList *d = top_dlg;
 336 
 337     // Search first fullscreen dialog
 338     for (; d != NULL; d = g_list_next (d))
 339         if ((WIDGET (d->data)->pos_flags & WPOS_FULLSCREEN) != 0)
 340             break;
 341 
 342     /* when small dialog (i.e. error message) is created first,
 343        there is no fullscreen dialog in the stack */
 344     if (d == NULL)
 345         d = g_list_last (top_dlg);
 346 
 347     // back to top dialog
 348     for (; d != NULL; d = g_list_previous (d))
 349         widget_draw (WIDGET (d->data));
 350 }
 351 
 352 /* --------------------------------------------------------------------------------------------- */
 353 
 354 void
 355 repaint_screen (void)
     /* [previous][next][first][last][top][bottom][index][help]  */
 356 {
 357     do_refresh ();
 358     tty_refresh ();
 359 }
 360 
 361 /* --------------------------------------------------------------------------------------------- */
 362 
 363 void
 364 mc_refresh (void)
     /* [previous][next][first][last][top][bottom][index][help]  */
 365 {
 366 #ifdef ENABLE_BACKGROUND
 367     if (mc_global.we_are_background)
 368         return;
 369 #endif
 370 
 371     if (!tty_got_winch ())
 372         tty_refresh ();
 373     else
 374     {
 375         /* if winch was caugth, we should do not only redraw screen, but
 376            reposition/resize all */
 377         dialog_change_screen_size ();
 378     }
 379 }
 380 
 381 /* --------------------------------------------------------------------------------------------- */
 382 
 383 void
 384 dialog_change_screen_size (void)
     /* [previous][next][first][last][top][bottom][index][help]  */
 385 {
 386     GList *d;
 387 
 388     /* On startup, when mc reads directories top_dlg isn't created yet. If window is resized
 389      * at this time, SIGWINCH can be missed because tty_flush_winch() is called here before
 390      * a first tty_got_winch() call in frontend_dlg_run().
 391      *
 392      * Keep SIGWINCH events in pipe if top_dlg isn't created yet. */
 393     if (top_dlg == NULL)
 394         return;
 395 
 396     tty_flush_winch ();
 397     tty_change_screen_size ();
 398 
 399 #ifdef HAVE_SLANG
 400     tty_keypad (TRUE);
 401     tty_nodelay (FALSE);
 402 #endif
 403 
 404     // Inform all suspending dialogs
 405     dialog_switch_got_winch ();
 406 
 407     // Inform all running dialogs from first to last
 408     for (d = g_list_last (top_dlg); d != NULL; d = g_list_previous (d))
 409         dialog_switch_resize (DIALOG (d->data));
 410 
 411     // Now, force the redraw
 412     repaint_screen ();
 413 }
 414 
 415 /* --------------------------------------------------------------------------------------------- */

/* [previous][next][first][last][top][bottom][index][help]  */