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 (listbox->list, LISTBOX_APPEND_BEFORE, get_hotkey (i++), title, h, FALSE);
 256 
 257         g_free (title);
 258     }
 259 
 260     selected = listbox_run_with_data (listbox, mc_current);
 261     if (selected != NULL)
 262         dialog_switch_goto (selected);
 263 }
 264 
 265 /* --------------------------------------------------------------------------------------------- */
 266 
 267 int
 268 dialog_switch_process_pending (void)
     /* [previous][next][first][last][top][bottom][index][help]  */
 269 {
 270     int ret = 0;
 271 
 272     while (dialog_switch_pending)
 273     {
 274         WDialog *h = DIALOG (mc_current->data);
 275         Widget *wh = WIDGET (h);
 276 
 277         dialog_switch_pending = FALSE;
 278         widget_set_state (wh, WST_SUSPENDED, TRUE);
 279         ret = dlg_run (h);
 280         if (widget_get_state (wh, WST_CLOSED))
 281         {
 282             widget_destroy (wh);
 283 
 284             /* return to panels */
 285             if (mc_global.mc_run_mode == MC_RUN_FULL)
 286             {
 287                 mc_current = g_list_find (mc_dialogs, filemanager);
 288                 mc_event_raise (MCEVENT_GROUP_FILEMANAGER, "update_panels", NULL);
 289             }
 290         }
 291     }
 292 
 293     repaint_screen ();
 294 
 295     return ret;
 296 }
 297 
 298 /* --------------------------------------------------------------------------------------------- */
 299 
 300 void
 301 dialog_switch_got_winch (void)
     /* [previous][next][first][last][top][bottom][index][help]  */
 302 {
 303     GList *dlg;
 304 
 305     for (dlg = mc_dialogs; dlg != NULL; dlg = g_list_next (dlg))
 306         if (dlg != mc_current)
 307             GROUP (dlg->data)->winch_pending = TRUE;
 308 }
 309 
 310 /* --------------------------------------------------------------------------------------------- */
 311 
 312 void
 313 dialog_switch_shutdown (void)
     /* [previous][next][first][last][top][bottom][index][help]  */
 314 {
 315     while (mc_dialogs != NULL)
 316     {
 317         WDialog *dlg = DIALOG (mc_dialogs->data);
 318 
 319         dlg_run (dlg);
 320         widget_destroy (WIDGET (dlg));
 321     }
 322 }
 323 
 324 /* --------------------------------------------------------------------------------------------- */
 325 
 326 void
 327 do_refresh (void)
     /* [previous][next][first][last][top][bottom][index][help]  */
 328 {
 329     GList *d = top_dlg;
 330 
 331     if (fast_refresh)
 332     {
 333         if (d != NULL)
 334             widget_draw (WIDGET (d->data));
 335     }
 336     else
 337     {
 338         /* Search first fullscreen dialog */
 339         for (; d != NULL; d = g_list_next (d))
 340             if ((WIDGET (d->data)->pos_flags & WPOS_FULLSCREEN) != 0)
 341                 break;
 342 
 343         /* when small dialog (i.e. error message) is created first,
 344            there is no fullscreen dialog in the stack */
 345         if (d == NULL)
 346             d = g_list_last (top_dlg);
 347 
 348         /* back to top dialog */
 349         for (; d != NULL; d = g_list_previous (d))
 350             widget_draw (WIDGET (d->data));
 351     }
 352 }
 353 
 354 /* --------------------------------------------------------------------------------------------- */
 355 
 356 void
 357 repaint_screen (void)
     /* [previous][next][first][last][top][bottom][index][help]  */
 358 {
 359     do_refresh ();
 360     tty_refresh ();
 361 }
 362 
 363 /* --------------------------------------------------------------------------------------------- */
 364 
 365 void
 366 mc_refresh (void)
     /* [previous][next][first][last][top][bottom][index][help]  */
 367 {
 368 #ifdef ENABLE_BACKGROUND
 369     if (mc_global.we_are_background)
 370         return;
 371 #endif /* ENABLE_BACKGROUND */
 372 
 373     if (!tty_got_winch ())
 374         tty_refresh ();
 375     else
 376     {
 377         /* if winch was caugth, we should do not only redraw screen, but
 378            reposition/resize all */
 379         dialog_change_screen_size ();
 380     }
 381 }
 382 
 383 /* --------------------------------------------------------------------------------------------- */
 384 
 385 void
 386 dialog_change_screen_size (void)
     /* [previous][next][first][last][top][bottom][index][help]  */
 387 {
 388     GList *d;
 389 
 390     tty_flush_winch ();
 391     tty_change_screen_size ();
 392 
 393 #ifdef HAVE_SLANG
 394     tty_keypad (TRUE);
 395     tty_nodelay (FALSE);
 396 #endif
 397 
 398     /* Inform all suspending dialogs */
 399     dialog_switch_got_winch ();
 400 
 401     /* Inform all running dialogs from first to last */
 402     for (d = g_list_last (top_dlg); d != NULL; d = g_list_previous (d))
 403         dialog_switch_resize (DIALOG (d->data));
 404 
 405     /* Now, force the redraw */
 406     repaint_screen ();
 407 }
 408 
 409 /* --------------------------------------------------------------------------------------------- */

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