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-2024
   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 <http://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/tty/color.h"      /* tty_set_normal_attrs() */
  38 #include "lib/widget.h"
  39 #include "lib/event.h"
  40 
  41 /*** global variables ****************************************************************************/
  42 
  43 /* Primitive way to check if the the current dialog is our dialog */
  44 /* This is needed by async routines like load_prompt */
  45 GList *top_dlg = NULL;
  46 
  47 /* If set then dialogs just clean the screen when refreshing, else */
  48 /* they do a complete refresh, refreshing all the parts of the program */
  49 gboolean fast_refresh = FALSE;
  50 
  51 WDialog *filemanager = NULL;
  52 
  53 /*** file scope macro definitions ****************************************************************/
  54 
  55 /*** file scope type declarations ****************************************************************/
  56 
  57 /*** forward declarations (file scope functions) *************************************************/
  58 
  59 /*** file scope variables ************************************************************************/
  60 
  61 /* List of dialogs: filemanagers, editors, viewers */
  62 static GList *mc_dialogs = NULL;
  63 /* Currently active dialog */
  64 static GList *mc_current = NULL;
  65 /* Is there any dialogs that we have to run after returning to the manager from another dialog */
  66 static gboolean dialog_switch_pending = FALSE;
  67 
  68 /* --------------------------------------------------------------------------------------------- */
  69 /*** file scope functions ************************************************************************/
  70 /* --------------------------------------------------------------------------------------------- */
  71 
  72 static unsigned char
  73 get_hotkey (int n)
     /* [previous][next][first][last][top][bottom][index][help]  */
  74 {
  75     return (n <= 9) ? '0' + n : 'a' + n - 10;
  76 }
  77 
  78 /* --------------------------------------------------------------------------------------------- */
  79 
  80 static void
  81 dialog_switch_suspend (void *data, void *user_data)
     /* [previous][next][first][last][top][bottom][index][help]  */
  82 {
  83     (void) user_data;
  84 
  85     if (data != mc_current->data)
  86         widget_set_state (WIDGET (data), WST_SUSPENDED, TRUE);
  87 }
  88 
  89 /* --------------------------------------------------------------------------------------------- */
  90 
  91 static void
  92 dialog_switch_goto (GList *dlg)
     /* [previous][next][first][last][top][bottom][index][help]  */
  93 {
  94     if (mc_current != dlg)
  95     {
  96         WDialog *old = DIALOG (mc_current->data);
  97 
  98         mc_current = dlg;
  99 
 100         if (old == filemanager)
 101         {
 102             /* switch from panels to another dialog (editor, viewer, etc) */
 103             dialog_switch_pending = TRUE;
 104             dialog_switch_process_pending ();
 105         }
 106         else
 107         {
 108             /* switch from editor, viewer, etc to another dialog */
 109             widget_set_state (WIDGET (old), WST_SUSPENDED, TRUE);
 110 
 111             if (DIALOG (dlg->data) != filemanager)
 112                 /* switch to another editor, viewer, etc */
 113                 /* return to panels before run the required dialog */
 114                 dialog_switch_pending = TRUE;
 115             else
 116             {
 117                 /* switch to panels */
 118                 widget_set_state (WIDGET (filemanager), WST_ACTIVE, TRUE);
 119                 do_refresh ();
 120             }
 121         }
 122     }
 123 }
 124 
 125 /* --------------------------------------------------------------------------------------------- */
 126 
 127 static void
 128 dialog_switch_resize (WDialog *d)
     /* [previous][next][first][last][top][bottom][index][help]  */
 129 {
 130     if (widget_get_state (WIDGET (d), WST_ACTIVE))
 131         send_message (d, NULL, MSG_RESIZE, 0, NULL);
 132     else
 133         GROUP (d)->winch_pending = TRUE;
 134 }
 135 
 136 /* --------------------------------------------------------------------------------------------- */
 137 /*** public functions ****************************************************************************/
 138 /* --------------------------------------------------------------------------------------------- */
 139 
 140 void
 141 dialog_switch_add (WDialog *h)
     /* [previous][next][first][last][top][bottom][index][help]  */
 142 {
 143     GList *dlg;
 144 
 145     dlg = g_list_find (mc_dialogs, h);
 146 
 147     if (dlg != NULL)
 148         mc_current = dlg;
 149     else
 150     {
 151         mc_dialogs = g_list_prepend (mc_dialogs, h);
 152         mc_current = mc_dialogs;
 153     }
 154 
 155     /* suspend forced all other screens */
 156     g_list_foreach (mc_dialogs, dialog_switch_suspend, NULL);
 157 }
 158 
 159 /* --------------------------------------------------------------------------------------------- */
 160 
 161 void
 162 dialog_switch_remove (WDialog *h)
     /* [previous][next][first][last][top][bottom][index][help]  */
 163 {
 164     GList *this;
 165 
 166     if (DIALOG (mc_current->data) == h)
 167         this = mc_current;
 168     else
 169         this = g_list_find (mc_dialogs, h);
 170 
 171     mc_dialogs = g_list_delete_link (mc_dialogs, this);
 172 
 173     /* adjust current dialog */
 174     if (top_dlg != NULL)
 175         mc_current = g_list_find (mc_dialogs, DIALOG (top_dlg->data));
 176     else
 177         mc_current = mc_dialogs;
 178 
 179     /* resume forced the current screen */
 180     if (mc_current != NULL)
 181         widget_set_state (WIDGET (mc_current->data), WST_ACTIVE, TRUE);
 182 }
 183 
 184 /* --------------------------------------------------------------------------------------------- */
 185 
 186 size_t
 187 dialog_switch_num (void)
     /* [previous][next][first][last][top][bottom][index][help]  */
 188 {
 189     return g_list_length (mc_dialogs);
 190 }
 191 
 192 /* --------------------------------------------------------------------------------------------- */
 193 
 194 void
 195 dialog_switch_next (void)
     /* [previous][next][first][last][top][bottom][index][help]  */
 196 {
 197     GList *next;
 198 
 199     if (mc_global.midnight_shutdown || mc_current == NULL)
 200         return;
 201 
 202     next = g_list_next (mc_current);
 203     if (next == NULL)
 204         next = mc_dialogs;
 205 
 206     dialog_switch_goto (next);
 207 }
 208 
 209 /* --------------------------------------------------------------------------------------------- */
 210 
 211 void
 212 dialog_switch_prev (void)
     /* [previous][next][first][last][top][bottom][index][help]  */
 213 {
 214     GList *prev;
 215 
 216     if (mc_global.midnight_shutdown || mc_current == NULL)
 217         return;
 218 
 219     prev = g_list_previous (mc_current);
 220     if (prev == NULL)
 221         prev = g_list_last (mc_dialogs);
 222 
 223     dialog_switch_goto (prev);
 224 }
 225 
 226 /* --------------------------------------------------------------------------------------------- */
 227 
 228 void
 229 dialog_switch_list (void)
     /* [previous][next][first][last][top][bottom][index][help]  */
 230 {
 231     const size_t dlg_num = g_list_length (mc_dialogs);
 232     int lines, cols;
 233     Listbox *listbox;
 234     GList *h, *selected;
 235     int i = 0;
 236 
 237     if (mc_global.midnight_shutdown || mc_current == NULL)
 238         return;
 239 
 240     lines = MIN ((size_t) (LINES * 2 / 3), dlg_num);
 241     cols = COLS * 2 / 3;
 242 
 243     listbox = listbox_window_new (lines, cols, _("Screens"), "[Screen selector]");
 244 
 245     for (h = mc_dialogs; h != NULL; h = g_list_next (h))
 246     {
 247         WDialog *dlg = DIALOG (h->data);
 248         char *title;
 249 
 250         if (dlg->get_title != NULL)
 251             title = dlg->get_title (dlg, WIDGET (listbox->list)->rect.cols - 2);
 252         else
 253             title = g_strdup ("");
 254 
 255         listbox_add_item_take (listbox->list, LISTBOX_APPEND_BEFORE, get_hotkey (i++), title, h,
 256                                FALSE);
 257     }
 258 
 259     selected = listbox_run_with_data (listbox, mc_current);
 260     if (selected != NULL)
 261         dialog_switch_goto (selected);
 262 }
 263 
 264 /* --------------------------------------------------------------------------------------------- */
 265 
 266 int
 267 dialog_switch_process_pending (void)
     /* [previous][next][first][last][top][bottom][index][help]  */
 268 {
 269     int ret = 0;
 270 
 271     while (dialog_switch_pending)
 272     {
 273         WDialog *h = DIALOG (mc_current->data);
 274         Widget *wh = WIDGET (h);
 275 
 276         dialog_switch_pending = FALSE;
 277         widget_set_state (wh, WST_SUSPENDED, TRUE);
 278         ret = dlg_run (h);
 279         if (widget_get_state (wh, WST_CLOSED))
 280         {
 281             widget_destroy (wh);
 282 
 283             /* return to panels */
 284             if (mc_global.mc_run_mode == MC_RUN_FULL)
 285             {
 286                 mc_current = g_list_find (mc_dialogs, filemanager);
 287                 mc_event_raise (MCEVENT_GROUP_FILEMANAGER, "update_panels", NULL);
 288             }
 289         }
 290     }
 291 
 292     repaint_screen ();
 293 
 294     return ret;
 295 }
 296 
 297 /* --------------------------------------------------------------------------------------------- */
 298 
 299 void
 300 dialog_switch_got_winch (void)
     /* [previous][next][first][last][top][bottom][index][help]  */
 301 {
 302     GList *dlg;
 303 
 304     for (dlg = mc_dialogs; dlg != NULL; dlg = g_list_next (dlg))
 305         if (dlg != mc_current)
 306             GROUP (dlg->data)->winch_pending = TRUE;
 307 }
 308 
 309 /* --------------------------------------------------------------------------------------------- */
 310 
 311 void
 312 dialog_switch_shutdown (void)
     /* [previous][next][first][last][top][bottom][index][help]  */
 313 {
 314     while (mc_dialogs != NULL)
 315     {
 316         WDialog *dlg = DIALOG (mc_dialogs->data);
 317 
 318         dlg_run (dlg);
 319         widget_destroy (WIDGET (dlg));
 320     }
 321 }
 322 
 323 /* --------------------------------------------------------------------------------------------- */
 324 
 325 void
 326 do_refresh (void)
     /* [previous][next][first][last][top][bottom][index][help]  */
 327 {
 328     GList *d = top_dlg;
 329 
 330     if (fast_refresh)
 331     {
 332         if (d != NULL)
 333             widget_draw (WIDGET (d->data));
 334     }
 335     else
 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 
 355 void
 356 repaint_screen (void)
     /* [previous][next][first][last][top][bottom][index][help]  */
 357 {
 358     do_refresh ();
 359     tty_refresh ();
 360 }
 361 
 362 /* --------------------------------------------------------------------------------------------- */
 363 
 364 void
 365 mc_refresh (void)
     /* [previous][next][first][last][top][bottom][index][help]  */
 366 {
 367 #ifdef ENABLE_BACKGROUND
 368     if (mc_global.we_are_background)
 369         return;
 370 #endif /* ENABLE_BACKGROUND */
 371 
 372     if (!tty_got_winch ())
 373         tty_refresh ();
 374     else
 375     {
 376         /* if winch was caugth, we should do not only redraw screen, but
 377            reposition/resize all */
 378         dialog_change_screen_size ();
 379     }
 380 }
 381 
 382 /* --------------------------------------------------------------------------------------------- */
 383 
 384 void
 385 dialog_change_screen_size (void)
     /* [previous][next][first][last][top][bottom][index][help]  */
 386 {
 387     GList *d;
 388 
 389     tty_flush_winch ();
 390     tty_change_screen_size ();
 391 
 392 #ifdef HAVE_SLANG
 393     tty_keypad (TRUE);
 394     tty_nodelay (FALSE);
 395 #endif
 396 
 397     /* Inform all suspending dialogs */
 398     dialog_switch_got_winch ();
 399 
 400     /* Inform all running dialogs from first to last */
 401     for (d = g_list_last (top_dlg); d != NULL; d = g_list_previous (d))
 402         dialog_switch_resize (DIALOG (d->data));
 403 
 404     /* Now, force the redraw */
 405     repaint_screen ();
 406 }
 407 
 408 /* --------------------------------------------------------------------------------------------- */

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