Manual pages: mc • mcdiff • mcedit • mcview

root/src/filemanager/layout.c

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

DEFINITIONS

This source file includes following definitions.
  1. max
  2. check_split
  3. update_split
  4. b_left_right_cback
  5. bplus_cback
  6. bminus_cback
  7. layout_bg_callback
  8. layout_update_visibility
  9. layout_callback
  10. layout_dlg_create
  11. panel_do_cols
  12. restore_into_right_dir_panel
  13. layout_save
  14. layout_restore
  15. layout_change
  16. layout_box
  17. panel_update_cols
  18. setup_panels
  19. panels_split_equal
  20. panels_split_more
  21. panels_split_less
  22. setup_cmdline
  23. use_dash
  24. set_hintbar
  25. rotate_dash
  26. get_nth_panel_name
  27. create_panel
  28. swap_panels
  29. get_panel_type
  30. get_panel_widget
  31. get_current_index
  32. get_other_index
  33. get_other_panel
  34. get_current_type
  35. get_other_type
  36. save_panel_dir
  37. get_panel_dir_for
  38. do_load_prompt
  39. load_prompt
  40. title_path_prepare
  41. update_xterm_title_path
  42. update_terminal_cwd

   1 /*
   2    Panel layout module for the Midnight Commander
   3 
   4    Copyright (C) 1995-2026
   5    Free Software Foundation, Inc.
   6 
   7    Written by:
   8    Janne Kukonlehto, 1995
   9    Miguel de Icaza, 1995
  10    Andrew Borodin <aborodin@vmail.ru>, 2011-2022
  11    Slava Zanko <slavazanko@gmail.com>, 2013
  12    Avi Kelman <patcherton.fixesthings@gmail.com>, 2013
  13 
  14    This file is part of the Midnight Commander.
  15 
  16    The Midnight Commander is free software: you can redistribute it
  17    and/or modify it under the terms of the GNU General Public License as
  18    published by the Free Software Foundation, either version 3 of the License,
  19    or (at your option) any later version.
  20 
  21    The Midnight Commander is distributed in the hope that it will be useful,
  22    but WITHOUT ANY WARRANTY; without even the implied warranty of
  23    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  24    GNU General Public License for more details.
  25 
  26    You should have received a copy of the GNU General Public License
  27    along with this program.  If not, see <https://www.gnu.org/licenses/>.
  28  */
  29 
  30 /** \file layout.c
  31  *  \brief Source: panel layout module
  32  */
  33 
  34 #include <config.h>
  35 
  36 #include <pwd.h>  // for username in xterm title
  37 #include <stdlib.h>
  38 #include <stdio.h>
  39 #include <string.h>
  40 #include <sys/types.h>
  41 #include <unistd.h>
  42 
  43 #include "lib/global.h"
  44 #include "lib/terminal.h"  // strip_ctrl_codes()
  45 #include "lib/tty/tty.h"
  46 #include "lib/skin.h"
  47 #include "lib/tty/key.h"
  48 #include "lib/tty/mouse.h"
  49 #include "lib/mcconfig.h"
  50 #include "lib/vfs/vfs.h"  // vfs_get_cwd ()
  51 #include "lib/strutil.h"
  52 #include "lib/widget.h"
  53 #include "lib/util.h"  // mc_time_elapsed()
  54 
  55 #include "src/consaver/cons.saver.h"
  56 #include "src/viewer/mcviewer.h"  // The view widget
  57 #include "src/setup.h"
  58 #ifdef ENABLE_SUBSHELL
  59 #include "src/subshell/subshell.h"
  60 #endif
  61 
  62 #include "command.h"
  63 #include "filemanager.h"
  64 #include "tree.h"
  65 /* Needed for the extern declarations of integer parameters */
  66 #include "dir.h"
  67 #include "layout.h"
  68 #include "info.h"  // The Info widget
  69 
  70 /*** global variables ****************************************************************************/
  71 
  72 panels_layout_t panels_layout = {
  73     // Set if the panels are split horizontally
  74     .horizontal_split = FALSE,
  75 
  76     // vertical split
  77     .vertical_equal = TRUE,
  78     .left_panel_size = 0,
  79 
  80     // horizontal split
  81     .horizontal_equal = TRUE,
  82     .top_panel_size = 0
  83 };
  84 
  85 /* Controls the display of the rotating dash on the verbose mode */
  86 gboolean nice_rotating_dash = TRUE;
  87 
  88 /* The number of output lines shown (if available) */
  89 int output_lines = 0;
  90 
  91 /* Set to show current working dir in xterm window title */
  92 gboolean xterm_title = TRUE;
  93 
  94 /* Set to show free space on device assigned to current directory */
  95 gboolean free_space = TRUE;
  96 
  97 /* The starting line for the output of the subprogram */
  98 int output_start_y = 0;
  99 
 100 int ok_to_refresh = 1;
 101 
 102 /*** file scope macro definitions ****************************************************************/
 103 
 104 /* The maximum number of views managed by the create_panel routine */
 105 /* Must be at least two (for current and other).  Please note that until */
 106 /* Janne gets around this, we will only manage two of them :-) */
 107 #define MAX_VIEWS 2
 108 
 109 /* Width 12 for a wee Quick (Hex) View */
 110 #define MINWIDTH             12
 111 #define MINHEIGHT            5
 112 
 113 #define B_2LEFT              B_USER
 114 #define B_2RIGHT             (B_USER + 1)
 115 #define B_PLUS               (B_USER + 2)
 116 #define B_MINUS              (B_USER + 3)
 117 
 118 #define LAYOUT_OPTIONS_COUNT G_N_ELEMENTS (check_options)
 119 
 120 /*** file scope type declarations ****************************************************************/
 121 
 122 typedef struct
 123 {
 124     gboolean menubar_visible;
 125     gboolean cmdline_visible;
 126     gboolean keybar_visible;
 127     gboolean hint_visible;
 128     gboolean xterm_title;
 129     gboolean free_space;
 130     int output_lines;
 131 } layout_t;
 132 
 133 /*** forward declarations (file scope functions) *************************************************/
 134 
 135 /*** file scope variables ************************************************************************/
 136 
 137 static struct
 138 {
 139     panel_view_mode_t type;
 140     Widget *widget;
 141     char *last_saved_dir;  // last view_list working directory
 142 } panels[MAX_VIEWS] = {
 143     // init MAX_VIEWS items
 144     { view_listing, NULL, NULL },
 145     { view_listing, NULL, NULL },
 146 };
 147 
 148 static layout_t old_layout;
 149 static panels_layout_t old_panels_layout;
 150 
 151 static gboolean equal_split;
 152 static int _output_lines;
 153 
 154 static int height;
 155 
 156 static WRadio *radio_widget;
 157 
 158 static struct
 159 {
 160     const char *text;
 161     gboolean *variable;
 162     WCheck *widget;
 163 } check_options[] = {
 164     { N_ ("&Equal split"), &equal_split, NULL },
 165     { N_ ("&Menubar visible"), &mc_global.menubar_visible, NULL },
 166     { N_ ("Command &prompt"), &mc_global.cmdline_visible, NULL },
 167     { N_ ("&Keybar visible"), &mc_global.keybar_visible, NULL },
 168     { N_ ("H&intbar visible"), &mc_global.hint_visible, NULL },
 169     { N_ ("&XTerm window title"), &xterm_title, NULL },
 170     { N_ ("&Show free space"), &free_space, NULL },
 171 };
 172 
 173 static const char *output_lines_label = NULL;
 174 static int output_lines_label_len;
 175 
 176 static WButton *bleft_widget, *bright_widget;
 177 
 178 /* --------------------------------------------------------------------------------------------- */
 179 /*** file scope functions ************************************************************************/
 180 /* --------------------------------------------------------------------------------------------- */
 181 
 182 /* don't use max() macro to avoid double call of str_term_width1() in widget width calculation */
 183 #undef max
 184 
 185 static int
 186 max (int a, int b)
     /* [previous][next][first][last][top][bottom][index][help]  */
 187 {
 188     return a > b ? a : b;
 189 }
 190 
 191 /* --------------------------------------------------------------------------------------------- */
 192 
 193 static void
 194 check_split (panels_layout_t *layout)
     /* [previous][next][first][last][top][bottom][index][help]  */
 195 {
 196     if (layout->horizontal_split)
 197     {
 198         if (layout->horizontal_equal)
 199             layout->top_panel_size = height / 2;
 200         else if (layout->top_panel_size < MINHEIGHT)
 201             layout->top_panel_size = MINHEIGHT;
 202         else if (layout->top_panel_size > height - MINHEIGHT)
 203             layout->top_panel_size = height - MINHEIGHT;
 204     }
 205     else
 206     {
 207         int md_cols = CONST_WIDGET (filemanager)->rect.cols;
 208 
 209         if (layout->vertical_equal)
 210             layout->left_panel_size = md_cols / 2;
 211         else if (layout->left_panel_size < MINWIDTH)
 212             layout->left_panel_size = MINWIDTH;
 213         else if (layout->left_panel_size > md_cols - MINWIDTH)
 214             layout->left_panel_size = md_cols - MINWIDTH;
 215     }
 216 }
 217 
 218 /* --------------------------------------------------------------------------------------------- */
 219 
 220 static void
 221 update_split (const WDialog *h)
     /* [previous][next][first][last][top][bottom][index][help]  */
 222 {
 223     /* Check split has to be done before testing if it changed, since
 224        it can change due to calling check_split() as well */
 225     check_split (&panels_layout);
 226 
 227     if (panels_layout.horizontal_split)
 228         check_options[0].widget->state = panels_layout.horizontal_equal;
 229     else
 230         check_options[0].widget->state = panels_layout.vertical_equal;
 231     widget_draw (WIDGET (check_options[0].widget));
 232 
 233     tty_setcolor (check_options[0].widget->state ? CORE_DISABLED_COLOR : DIALOG_NORMAL_COLOR);
 234 
 235     widget_gotoyx (h, 6, 5);
 236     if (panels_layout.horizontal_split)
 237         tty_printf ("%03d", panels_layout.top_panel_size);
 238     else
 239         tty_printf ("%03d", panels_layout.left_panel_size);
 240 
 241     widget_gotoyx (h, 6, 17);
 242     if (panels_layout.horizontal_split)
 243         tty_printf ("%03d", height - panels_layout.top_panel_size);
 244     else
 245         tty_printf ("%03d", CONST_WIDGET (filemanager)->rect.cols - panels_layout.left_panel_size);
 246 
 247     widget_gotoyx (h, 6, 12);
 248     tty_print_char ('=');
 249 }
 250 
 251 /* --------------------------------------------------------------------------------------------- */
 252 
 253 static int
 254 b_left_right_cback (WButton *button, int action)
     /* [previous][next][first][last][top][bottom][index][help]  */
 255 {
 256     (void) action;
 257 
 258     if (button == bright_widget)
 259     {
 260         if (panels_layout.horizontal_split)
 261             panels_layout.top_panel_size++;
 262         else
 263             panels_layout.left_panel_size++;
 264     }
 265     else
 266     {
 267         if (panels_layout.horizontal_split)
 268             panels_layout.top_panel_size--;
 269         else
 270             panels_layout.left_panel_size--;
 271     }
 272 
 273     update_split (DIALOG (WIDGET (button)->owner));
 274     layout_change ();
 275     do_refresh ();
 276     return 0;
 277 }
 278 
 279 /* --------------------------------------------------------------------------------------------- */
 280 
 281 static int
 282 bplus_cback (WButton *button, int action)
     /* [previous][next][first][last][top][bottom][index][help]  */
 283 {
 284     (void) button;
 285     (void) action;
 286 
 287     if (_output_lines < 99)
 288         _output_lines++;
 289     return 0;
 290 }
 291 
 292 /* --------------------------------------------------------------------------------------------- */
 293 
 294 static int
 295 bminus_cback (WButton *button, int action)
     /* [previous][next][first][last][top][bottom][index][help]  */
 296 {
 297     (void) button;
 298     (void) action;
 299 
 300     if (_output_lines > 0)
 301         _output_lines--;
 302     return 0;
 303 }
 304 
 305 /* --------------------------------------------------------------------------------------------- */
 306 
 307 static cb_ret_t
 308 layout_bg_callback (Widget *w, Widget *sender, widget_msg_t msg, int parm, void *data)
     /* [previous][next][first][last][top][bottom][index][help]  */
 309 {
 310     switch (msg)
 311     {
 312     case MSG_DRAW:
 313         frame_callback (w, NULL, MSG_DRAW, 0, NULL);
 314 
 315         old_layout.output_lines = -1;
 316 
 317         update_split (DIALOG (w->owner));
 318 
 319         if (old_layout.output_lines != _output_lines)
 320         {
 321             old_layout.output_lines = _output_lines;
 322             tty_setcolor (mc_global.tty.console_flag != '\0' ? DIALOG_NORMAL_COLOR
 323                                                              : CORE_DISABLED_COLOR);
 324             widget_gotoyx (w, 9, 5);
 325             tty_print_string (output_lines_label);
 326             widget_gotoyx (w, 9, 5 + 3 + output_lines_label_len);
 327             tty_printf ("%02d", _output_lines);
 328         }
 329         return MSG_HANDLED;
 330 
 331     default:
 332         return frame_callback (w, sender, msg, parm, data);
 333     }
 334 }
 335 
 336 /* --------------------------------------------------------------------------------------------- */
 337 /* Sync visibility of the menu bar, command line, key bar, and hint bar with layout options.
 338    Don't call this from setup_panels(): menu bar can be shown temporarily (F9) while hidden. */
 339 
 340 static void
 341 layout_update_visibility (void)
     /* [previous][next][first][last][top][bottom][index][help]  */
 342 {
 343     widget_set_visibility (WIDGET (the_menubar), mc_global.menubar_visible);
 344     widget_set_visibility (WIDGET (the_prompt), mc_global.cmdline_visible);
 345     widget_set_visibility (WIDGET (the_cmdline), mc_global.cmdline_visible);
 346     widget_set_visibility (WIDGET (the_keybar), mc_global.keybar_visible);
 347     widget_set_visibility (WIDGET (the_hint), mc_global.hint_visible);
 348 }
 349 
 350 /* --------------------------------------------------------------------------------------------- */
 351 
 352 static cb_ret_t
 353 layout_callback (Widget *w, Widget *sender, widget_msg_t msg, int parm, void *data)
     /* [previous][next][first][last][top][bottom][index][help]  */
 354 {
 355     WDialog *h = DIALOG (w);
 356 
 357     switch (msg)
 358     {
 359     case MSG_POST_KEY:
 360     {
 361         const Widget *mw = CONST_WIDGET (filemanager);
 362         gboolean _menubar_visible, _cmdline_visible, _keybar_visible, _hint_visible;
 363 
 364         _menubar_visible = check_options[1].widget->state;
 365         _cmdline_visible = check_options[2].widget->state;
 366         _keybar_visible = check_options[3].widget->state;
 367         _hint_visible = check_options[4].widget->state;
 368 
 369         if (mc_global.tty.console_flag == '\0')
 370             height = mw->rect.lines - (_keybar_visible ? 1 : 0) - (_cmdline_visible ? 1 : 0)
 371                 - (_menubar_visible ? 1 : 0) - _output_lines - (_hint_visible ? 1 : 0);
 372         else
 373         {
 374             int minimum;
 375 
 376             if (_output_lines < 0)
 377                 _output_lines = 0;
 378             height = mw->rect.lines - (_keybar_visible ? 1 : 0) - (_cmdline_visible ? 1 : 0)
 379                 - (_menubar_visible ? 1 : 0) - _output_lines - (_hint_visible ? 1 : 0);
 380             minimum = MINHEIGHT * (1 + (panels_layout.horizontal_split ? 1 : 0));
 381             if (height < minimum)
 382             {
 383                 _output_lines -= minimum - height;
 384                 height = minimum;
 385             }
 386         }
 387 
 388         if (old_layout.output_lines != _output_lines)
 389         {
 390             old_layout.output_lines = _output_lines;
 391             tty_setcolor (mc_global.tty.console_flag != '\0' ? DIALOG_NORMAL_COLOR
 392                                                              : CORE_DISABLED_COLOR);
 393             widget_gotoyx (h, 9, 5 + 3 + output_lines_label_len);
 394             tty_printf ("%02d", _output_lines);
 395         }
 396     }
 397         return MSG_HANDLED;
 398 
 399     case MSG_NOTIFY:
 400         if (sender == WIDGET (radio_widget))
 401         {
 402             if ((panels_layout.horizontal_split ? 1 : 0) == radio_widget->sel)
 403                 update_split (h);
 404             else
 405             {
 406                 int eq;
 407 
 408                 panels_layout.horizontal_split = radio_widget->sel != 0;
 409 
 410                 if (panels_layout.horizontal_split)
 411                 {
 412                     eq = panels_layout.horizontal_equal;
 413                     if (eq)
 414                         panels_layout.top_panel_size = height / 2;
 415                 }
 416                 else
 417                 {
 418                     eq = panels_layout.vertical_equal;
 419                     if (eq)
 420                         panels_layout.left_panel_size = CONST_WIDGET (filemanager)->rect.cols / 2;
 421                 }
 422 
 423                 widget_disable (WIDGET (bleft_widget), eq);
 424                 widget_disable (WIDGET (bright_widget), eq);
 425 
 426                 update_split (h);
 427                 layout_change ();
 428                 do_refresh ();
 429             }
 430 
 431             return MSG_HANDLED;
 432         }
 433 
 434         if (sender == WIDGET (check_options[0].widget))
 435         {
 436             gboolean eq;
 437 
 438             if (panels_layout.horizontal_split)
 439             {
 440                 panels_layout.horizontal_equal = check_options[0].widget->state;
 441                 eq = panels_layout.horizontal_equal;
 442             }
 443             else
 444             {
 445                 panels_layout.vertical_equal = check_options[0].widget->state;
 446                 eq = panels_layout.vertical_equal;
 447             }
 448 
 449             widget_disable (WIDGET (bleft_widget), eq);
 450             widget_disable (WIDGET (bright_widget), eq);
 451 
 452             update_split (h);
 453             layout_change ();
 454             do_refresh ();
 455 
 456             return MSG_HANDLED;
 457         }
 458 
 459         {
 460             gboolean ok = TRUE;
 461 
 462             if (sender == WIDGET (check_options[1].widget))
 463                 mc_global.menubar_visible = check_options[1].widget->state;
 464             else if (sender == WIDGET (check_options[2].widget))
 465                 mc_global.cmdline_visible = check_options[2].widget->state;
 466             else if (sender == WIDGET (check_options[3].widget))
 467                 mc_global.keybar_visible = check_options[3].widget->state;
 468             else if (sender == WIDGET (check_options[4].widget))
 469                 mc_global.hint_visible = check_options[4].widget->state;
 470             else if (sender == WIDGET (check_options[5].widget))
 471                 xterm_title = check_options[5].widget->state;
 472             else if (sender == WIDGET (check_options[6].widget))
 473                 free_space = check_options[6].widget->state;
 474             else
 475                 ok = FALSE;
 476 
 477             if (ok)
 478             {
 479                 update_split (h);
 480                 layout_update_visibility ();
 481                 layout_change ();
 482                 do_refresh ();
 483                 return MSG_HANDLED;
 484             }
 485         }
 486 
 487         return MSG_NOT_HANDLED;
 488 
 489     default:
 490         return dlg_default_callback (w, sender, msg, parm, data);
 491     }
 492 }
 493 
 494 /* --------------------------------------------------------------------------------------------- */
 495 
 496 static WDialog *
 497 layout_dlg_create (void)
     /* [previous][next][first][last][top][bottom][index][help]  */
 498 {
 499     WDialog *layout_dlg;
 500     WGroup *g;
 501     int l1 = 0, width;
 502     int b1, b2, b;
 503     size_t i;
 504 
 505     const char *title1 = _ ("Panel split");
 506     const char *title2 = _ ("Console output");
 507     const char *title3 = _ ("Other options");
 508 
 509     const char *s_split_direction[2] = {
 510         _ ("&Vertical"),
 511         _ ("&Horizontal"),
 512     };
 513 
 514     const char *ok_button = _ ("&OK");
 515     const char *cancel_button = _ ("&Cancel");
 516 
 517     output_lines_label = _ ("Output lines:");
 518 
 519 #ifdef ENABLE_NLS
 520     {
 521         static gboolean i18n = FALSE;
 522 
 523         if (!i18n)
 524         {
 525             for (i = 0; i < (size_t) LAYOUT_OPTIONS_COUNT; i++)
 526                 check_options[i].text = _ (check_options[i].text);
 527             i18n = TRUE;
 528         }
 529     }
 530 #endif
 531 
 532     // radiobuttons
 533     i = G_N_ELEMENTS (s_split_direction);
 534     while (i-- != 0)
 535         l1 = max (l1, str_term_width1 (s_split_direction[i]) + 7);
 536     // checkboxes
 537     for (i = 0; i < (size_t) LAYOUT_OPTIONS_COUNT; i++)
 538         l1 = max (l1, str_term_width1 (check_options[i].text) + 7);
 539     // groupboxes
 540     l1 = max (l1, str_term_width1 (title1) + 4);
 541     l1 = max (l1, str_term_width1 (title2) + 4);
 542     l1 = max (l1, str_term_width1 (title3) + 4);
 543     // label + "+"/"-" buttons
 544     output_lines_label_len = str_term_width1 (output_lines_label);
 545     l1 = max (l1, output_lines_label_len + 12);
 546     // buttons
 547     b1 = str_term_width1 (ok_button) + 5;  // default button
 548     b2 = str_term_width1 (cancel_button) + 3;
 549     b = b1 + b2 + 1;
 550     // dialog width
 551     width = max (l1 * 2 + 7, b);
 552 
 553     layout_dlg = dlg_create (TRUE, 0, 0, 15, width, WPOS_CENTER, FALSE, dialog_colors,
 554                              layout_callback, NULL, "[Layout]", _ ("Layout"));
 555     g = GROUP (layout_dlg);
 556 
 557     // draw background
 558     layout_dlg->bg->callback = layout_bg_callback;
 559 
 560 #define XTRACT(i) (*check_options[i].variable != 0), check_options[i].text
 561 
 562     // "Panel split" groupbox
 563     group_add_widget (g, groupbox_new (2, 3, 6, l1, title1));
 564 
 565     radio_widget = radio_new (3, 5, 2, s_split_direction);
 566     radio_widget->sel = panels_layout.horizontal_split ? 1 : 0;
 567     group_add_widget (g, radio_widget);
 568 
 569     check_options[0].widget = check_new (5, 5, XTRACT (0));
 570     group_add_widget (g, check_options[0].widget);
 571 
 572     equal_split = panels_layout.horizontal_split ? panels_layout.horizontal_equal
 573                                                  : panels_layout.vertical_equal;
 574 
 575     bleft_widget = button_new (6, 8, B_2LEFT, NARROW_BUTTON, "&<", b_left_right_cback);
 576     widget_disable (WIDGET (bleft_widget), equal_split);
 577     group_add_widget (g, bleft_widget);
 578 
 579     bright_widget = button_new (6, 14, B_2RIGHT, NARROW_BUTTON, "&>", b_left_right_cback);
 580     widget_disable (WIDGET (bright_widget), equal_split);
 581     group_add_widget (g, bright_widget);
 582 
 583     // "Console output" groupbox
 584     {
 585         widget_state_t disabled;
 586         Widget *w;
 587 
 588         disabled = mc_global.tty.console_flag != '\0' ? 0 : WST_DISABLED;
 589 
 590         w = WIDGET (groupbox_new (8, 3, 3, l1, title2));
 591         w->state |= disabled;
 592         group_add_widget (g, w);
 593 
 594         w = WIDGET (
 595             button_new (9, output_lines_label_len + 5, B_PLUS, NARROW_BUTTON, "&+", bplus_cback));
 596         w->state |= disabled;
 597         group_add_widget (g, w);
 598 
 599         w = WIDGET (button_new (9, output_lines_label_len + 5 + 5, B_MINUS, NARROW_BUTTON, "&-",
 600                                 bminus_cback));
 601         w->state |= disabled;
 602         group_add_widget (g, w);
 603     }
 604 
 605     // "Other options" groupbox
 606     group_add_widget (g, groupbox_new (2, 4 + l1, 9, l1, title3));
 607 
 608     for (i = 1; i < (size_t) LAYOUT_OPTIONS_COUNT; i++)
 609     {
 610         check_options[i].widget = check_new (i + 2, 6 + l1, XTRACT (i));
 611         group_add_widget (g, check_options[i].widget);
 612     }
 613 
 614 #undef XTRACT
 615 
 616     group_add_widget (g, hline_new (11, -1, -1));
 617     // buttons
 618     group_add_widget (g, button_new (12, (width - b) / 2, B_ENTER, DEFPUSH_BUTTON, ok_button, 0));
 619     group_add_widget (
 620         g, button_new (12, (width - b) / 2 + b1 + 1, B_CANCEL, NORMAL_BUTTON, cancel_button, 0));
 621 
 622     widget_select (WIDGET (radio_widget));
 623 
 624     return layout_dlg;
 625 }
 626 
 627 /* --------------------------------------------------------------------------------------------- */
 628 
 629 static void
 630 panel_do_cols (int idx)
     /* [previous][next][first][last][top][bottom][index][help]  */
 631 {
 632     if (get_panel_type (idx) == view_listing)
 633         set_panel_formats (PANEL (panels[idx].widget));
 634     else
 635         panel_update_cols (panels[idx].widget, frame_half);
 636 }
 637 
 638 /* --------------------------------------------------------------------------------------------- */
 639 /** Save current list_view widget directory into panel */
 640 
 641 static Widget *
 642 restore_into_right_dir_panel (int idx, gboolean last_was_panel, const WRect *r)
     /* [previous][next][first][last][top][bottom][index][help]  */
 643 {
 644     WPanel *new_widget;
 645     const char *p_name;
 646 
 647     p_name = get_nth_panel_name (idx);
 648 
 649     if (last_was_panel)
 650     {
 651         vfs_path_t *saved_dir_vpath;
 652 
 653         saved_dir_vpath = vfs_path_from_str (panels[idx].last_saved_dir);
 654         new_widget = panel_sized_with_dir_new (p_name, r, saved_dir_vpath);
 655         vfs_path_free (saved_dir_vpath, TRUE);
 656     }
 657     else
 658         new_widget = panel_sized_new (p_name, r);
 659 
 660     return WIDGET (new_widget);
 661 }
 662 
 663 /* --------------------------------------------------------------------------------------------- */
 664 
 665 static void
 666 layout_save (void)
     /* [previous][next][first][last][top][bottom][index][help]  */
 667 {
 668     old_layout.menubar_visible = mc_global.menubar_visible;
 669     old_layout.cmdline_visible = mc_global.cmdline_visible;
 670     old_layout.keybar_visible = mc_global.keybar_visible;
 671     old_layout.hint_visible = mc_global.hint_visible;
 672     old_layout.xterm_title = xterm_title;
 673     old_layout.free_space = free_space;
 674     old_layout.output_lines = -1;
 675 
 676     _output_lines = output_lines;
 677 
 678     old_panels_layout = panels_layout;
 679 }
 680 
 681 /* --------------------------------------------------------------------------------------------- */
 682 
 683 static void
 684 layout_restore (void)
     /* [previous][next][first][last][top][bottom][index][help]  */
 685 {
 686     mc_global.menubar_visible = old_layout.menubar_visible;
 687     mc_global.cmdline_visible = old_layout.cmdline_visible;
 688     mc_global.keybar_visible = old_layout.keybar_visible;
 689     mc_global.hint_visible = old_layout.hint_visible;
 690     xterm_title = old_layout.xterm_title;
 691     free_space = old_layout.free_space;
 692     output_lines = old_layout.output_lines;
 693 
 694     panels_layout = old_panels_layout;
 695 }
 696 
 697 /* --------------------------------------------------------------------------------------------- */
 698 /*** public functions ****************************************************************************/
 699 /* --------------------------------------------------------------------------------------------- */
 700 
 701 void
 702 layout_change (void)
     /* [previous][next][first][last][top][bottom][index][help]  */
 703 {
 704     setup_panels ();
 705     /* update the main menu, because perhaps there was a change in the way
 706        how the panel are split (horizontal/vertical),
 707        and a change of menu visibility. */
 708     update_menu ();
 709     load_hint (TRUE);
 710 }
 711 
 712 /* --------------------------------------------------------------------------------------------- */
 713 
 714 void
 715 layout_box (void)
     /* [previous][next][first][last][top][bottom][index][help]  */
 716 {
 717     WDialog *layout_dlg;
 718 
 719     layout_save ();
 720 
 721     layout_dlg = layout_dlg_create ();
 722 
 723     if (dlg_run (layout_dlg) == B_ENTER)
 724     {
 725         size_t i;
 726 
 727         for (i = 0; i < (size_t) LAYOUT_OPTIONS_COUNT; i++)
 728             if (check_options[i].widget != NULL)
 729                 *check_options[i].variable = check_options[i].widget->state;
 730 
 731         output_lines = _output_lines;
 732     }
 733     else
 734         layout_restore ();
 735 
 736     widget_destroy (WIDGET (layout_dlg));
 737     layout_update_visibility ();
 738     layout_change ();
 739     do_refresh ();
 740 }
 741 
 742 /* --------------------------------------------------------------------------------------------- */
 743 
 744 void
 745 panel_update_cols (Widget *widget, panel_display_t frame_size)
     /* [previous][next][first][last][top][bottom][index][help]  */
 746 {
 747     const Widget *mw = CONST_WIDGET (filemanager);
 748     int cols, x;
 749 
 750     // don't touch panel if it is not in dialog yet
 751     /* if panel is not in dialog it is not in widgets list
 752        and cannot be compared with get_panel_widget() result */
 753     if (widget->owner == NULL)
 754         return;
 755 
 756     if (panels_layout.horizontal_split)
 757     {
 758         widget->rect.cols = mw->rect.cols;
 759         return;
 760     }
 761 
 762     if (frame_size == frame_full)
 763     {
 764         cols = mw->rect.cols;
 765         x = mw->rect.x;
 766     }
 767     else if (widget == get_panel_widget (0))
 768     {
 769         cols = panels_layout.left_panel_size;
 770         x = mw->rect.x;
 771     }
 772     else
 773     {
 774         cols = mw->rect.cols - panels_layout.left_panel_size;
 775         x = mw->rect.x + panels_layout.left_panel_size;
 776     }
 777 
 778     widget->rect.cols = cols;
 779     widget->rect.x = x;
 780 }
 781 
 782 /* --------------------------------------------------------------------------------------------- */
 783 
 784 void
 785 setup_panels (void)
     /* [previous][next][first][last][top][bottom][index][help]  */
 786 {
 787     /* File manager screen layout:
 788      *
 789      * +---------------------------------------------------------------+
 790      * | Menu bar                                                      |
 791      * +-------------------------------+-------------------------------+
 792      * |                               |                               |
 793      * |                               |                               |
 794      * |                               |                               |
 795      * |                               |                               |
 796      * |         Left panel            |         Right panel           |
 797      * |                               |                               |
 798      * |                               |                               |
 799      * |                               |                               |
 800      * |                               |                               |
 801      * +-------------------------------+-------------------------------+
 802      * | Hint (message) bar                                            |
 803      * +---------------------------------------------------------------+
 804      * |                                                               |
 805      * |                        Console content                        |
 806      * |                                                               |
 807      * +--------+------------------------------------------------------+
 808      * | Prompt | Command line                                         |
 809      * | Key (button) bar                                              |
 810      * +--------+------------------------------------------------------+
 811      */
 812 
 813     Widget *mw = WIDGET (filemanager);
 814     const WRect *r = &CONST_WIDGET (mw)->rect;
 815     int start_y;
 816     gboolean active;
 817     WRect rb;
 818 
 819     active = widget_get_state (mw, WST_ACTIVE);
 820 
 821     // lock the group to avoid many redraws
 822     if (active)
 823         widget_set_state (mw, WST_SUSPENDED, TRUE);
 824 
 825     // initial height of panels
 826     height = r->lines - (mc_global.menubar_visible ? 1 : 0) - (mc_global.hint_visible ? 1 : 0)
 827         - (mc_global.cmdline_visible ? 1 : 0) - (mc_global.keybar_visible ? 1 : 0);
 828 
 829     if (mc_global.tty.console_flag != '\0')
 830     {
 831         int minimum;
 832 
 833         if (output_lines < 0)
 834             output_lines = 0;
 835         else
 836             height -= output_lines;
 837         minimum = MINHEIGHT * (1 + (panels_layout.horizontal_split ? 1 : 0));
 838         if (height < minimum)
 839         {
 840             output_lines -= minimum - height;
 841             height = minimum;
 842         }
 843     }
 844 
 845     rb = *r;
 846     rb.lines = 1;
 847     widget_set_size_rect (WIDGET (the_menubar), &rb);
 848 
 849     check_split (&panels_layout);
 850     start_y = r->y + (mc_global.menubar_visible ? 1 : 0);
 851 
 852     // update columns first...
 853     panel_do_cols (0);
 854     panel_do_cols (1);
 855 
 856     // ...then rows and origin
 857     if (panels_layout.horizontal_split)
 858     {
 859         widget_set_size (panels[0].widget, start_y, r->x, panels_layout.top_panel_size,
 860                          panels[0].widget->rect.cols);
 861         widget_set_size (panels[1].widget, start_y + panels_layout.top_panel_size, r->x,
 862                          height - panels_layout.top_panel_size, panels[1].widget->rect.cols);
 863     }
 864     else
 865     {
 866         widget_set_size (panels[0].widget, start_y, r->x, height, panels[0].widget->rect.cols);
 867         widget_set_size (panels[1].widget, start_y, panels[1].widget->rect.x, height,
 868                          panels[1].widget->rect.cols);
 869     }
 870 
 871     widget_set_size (WIDGET (the_hint), height + start_y, r->x, 1, r->cols);
 872 
 873     // Output window
 874     if (mc_global.tty.console_flag != '\0' && output_lines != 0)
 875     {
 876         unsigned char end_line;
 877 
 878         end_line = r->lines - (mc_global.keybar_visible ? 1 : 0) - 1;
 879         output_start_y = end_line - (mc_global.cmdline_visible ? 1 : 0) - output_lines + 1;
 880         show_console_contents (output_start_y, end_line - output_lines, end_line);
 881     }
 882 
 883     if (mc_global.cmdline_visible)
 884 #ifdef ENABLE_SUBSHELL
 885         if (!mc_global.tty.use_subshell || !do_load_prompt ())
 886 #endif
 887             setup_cmdline ();
 888 
 889     rb = *r;
 890     rb.y = r->lines - 1;
 891     rb.lines = 1;
 892     widget_set_size_rect (WIDGET (the_keybar), &rb);
 893 
 894     update_xterm_title_path ();
 895     update_terminal_cwd ();
 896 
 897     // unlock
 898     if (active)
 899     {
 900         widget_set_state (mw, WST_ACTIVE, TRUE);
 901         widget_draw (mw);
 902     }
 903 }
 904 
 905 /* --------------------------------------------------------------------------------------------- */
 906 
 907 void
 908 panels_split_equal (void)
     /* [previous][next][first][last][top][bottom][index][help]  */
 909 {
 910     if (panels_layout.horizontal_split)
 911         panels_layout.horizontal_equal = TRUE;
 912     else
 913         panels_layout.vertical_equal = TRUE;
 914 
 915     layout_change ();
 916     do_refresh ();
 917 }
 918 
 919 /* --------------------------------------------------------------------------------------------- */
 920 
 921 void
 922 panels_split_more (void)
     /* [previous][next][first][last][top][bottom][index][help]  */
 923 {
 924     if (panels_layout.horizontal_split)
 925     {
 926         panels_layout.horizontal_equal = FALSE;
 927         panels_layout.top_panel_size++;
 928     }
 929     else
 930     {
 931         panels_layout.vertical_equal = FALSE;
 932         panels_layout.left_panel_size++;
 933     }
 934 
 935     layout_change ();
 936 }
 937 
 938 /* --------------------------------------------------------------------------------------------- */
 939 
 940 void
 941 panels_split_less (void)
     /* [previous][next][first][last][top][bottom][index][help]  */
 942 {
 943     if (panels_layout.horizontal_split)
 944     {
 945         panels_layout.horizontal_equal = FALSE;
 946         panels_layout.top_panel_size--;
 947     }
 948     else
 949     {
 950         panels_layout.vertical_equal = FALSE;
 951         panels_layout.left_panel_size--;
 952     }
 953 
 954     layout_change ();
 955 }
 956 
 957 /* --------------------------------------------------------------------------------------------- */
 958 
 959 void
 960 setup_cmdline (void)
     /* [previous][next][first][last][top][bottom][index][help]  */
 961 {
 962     const Widget *mw = CONST_WIDGET (filemanager);
 963     const WRect *r = &mw->rect;
 964     int prompt_width;
 965     int y;
 966 
 967     if (!mc_global.cmdline_visible)
 968         return;
 969 
 970 #ifdef ENABLE_SUBSHELL
 971     if (mc_global.tty.use_subshell)
 972     {
 973         // Workaround: avoid crash on FreeBSD (see ticket #4213 for details)
 974         if (subshell_prompt != NULL)
 975         {
 976             g_free (mc_prompt);
 977             mc_prompt = g_strndup (subshell_prompt->str, subshell_prompt->len);
 978         }
 979 
 980         (void) strip_ctrl_codes (mc_prompt);
 981     }
 982 #endif
 983 
 984     prompt_width = str_term_width1 (mc_prompt);
 985 
 986     // Check for prompts too big
 987     if (r->cols > 8 && prompt_width > r->cols - 8)
 988     {
 989         int prompt_len;
 990 
 991         prompt_width = r->cols - 8;
 992         prompt_len = str_offset_to_pos (mc_prompt, prompt_width);
 993         mc_prompt[prompt_len] = '\0';
 994     }
 995 
 996     y = r->lines - 1 - (mc_global.keybar_visible ? 1 : 0);
 997 
 998     widget_set_size (WIDGET (the_prompt), y, r->x, 1, prompt_width);
 999     label_set_text (the_prompt, mc_prompt);
1000     widget_set_size (WIDGET (the_cmdline), y, r->x + prompt_width, 1, r->cols - prompt_width);
1001 }
1002 
1003 /* --------------------------------------------------------------------------------------------- */
1004 
1005 void
1006 use_dash (gboolean flag)
     /* [previous][next][first][last][top][bottom][index][help]  */
1007 {
1008     if (flag)
1009         ok_to_refresh++;
1010     else
1011         ok_to_refresh--;
1012 }
1013 
1014 /* --------------------------------------------------------------------------------------------- */
1015 
1016 void
1017 set_hintbar (const char *str)
     /* [previous][next][first][last][top][bottom][index][help]  */
1018 {
1019     label_set_text (the_hint, str);
1020     if (ok_to_refresh > 0)
1021         mc_refresh ();
1022 }
1023 
1024 /* --------------------------------------------------------------------------------------------- */
1025 
1026 void
1027 rotate_dash (gboolean show)
     /* [previous][next][first][last][top][bottom][index][help]  */
1028 {
1029     static gint64 timestamp = 0;
1030     // update with 10 FPS rate
1031     static const gint64 delay = G_USEC_PER_SEC / 10;
1032 
1033     const Widget *w = CONST_WIDGET (filemanager);
1034 
1035     if (!nice_rotating_dash || (ok_to_refresh <= 0))
1036         return;
1037 
1038     if (show && !mc_time_elapsed (&timestamp, delay))
1039         return;
1040 
1041     widget_gotoyx (w, mc_global.menubar_visible ? 1 : 0, w->rect.cols - 1);
1042     tty_setcolor (CORE_NORMAL_COLOR);
1043 
1044     if (!show)
1045         tty_print_char (mc_tty_frm[MC_TTY_FRM_DRIGHTTOP]);
1046     else
1047     {
1048         static const char rotating_dash[4] MC_NONSTRING = "|/-\\";
1049         static size_t pos = 0;
1050 
1051         tty_print_char (rotating_dash[pos]);
1052         pos = (pos + 1) % sizeof (rotating_dash);
1053     }
1054 
1055     mc_refresh ();
1056 }
1057 
1058 /* --------------------------------------------------------------------------------------------- */
1059 
1060 const char *
1061 get_nth_panel_name (int num)
     /* [previous][next][first][last][top][bottom][index][help]  */
1062 {
1063     if (num == 0)
1064         return "New Left Panel";
1065 
1066     if (num == 1)
1067         return "New Right Panel";
1068 
1069     {
1070         static char buffer[BUF_SMALL];
1071 
1072         g_snprintf (buffer, sizeof (buffer), "%ith Panel", num);
1073         return buffer;
1074     }
1075 }
1076 
1077 /* --------------------------------------------------------------------------------------------- */
1078 /* I wonder if I should start to use the folding mode than Dugan uses */
1079 /*                                                                     */
1080 /* This is the centralized managing of the panel display types         */
1081 /* This routine takes care of destroying and creating new widgets      */
1082 /* Please note that it could manage MAX_VIEWS, not just left and right */
1083 /* Currently nothing in the code takes advantage of this and has hard- */
1084 /* coded values for two panels only                                    */
1085 
1086 /* Set the num-th panel to the view type: type */
1087 /* This routine also keeps at least one WPanel object in the screen */
1088 /* since a lot of routines depend on the current_panel variable */
1089 
1090 void
1091 create_panel (int num, panel_view_mode_t type)
     /* [previous][next][first][last][top][bottom][index][help]  */
1092 {
1093     WRect r = { 0, 0, 0, 0 };
1094     unsigned int the_other = 0;  // Index to the other panel
1095     Widget *new_widget = NULL, *old_widget = NULL;
1096     panel_view_mode_t old_type = view_listing;
1097 
1098     if (num >= MAX_VIEWS)
1099     {
1100         fprintf (stderr, "Cannot allocate more that %d views\n", MAX_VIEWS);
1101         abort ();
1102     }
1103     // Check that we will have a WPanel * at least
1104     if (type != view_listing)
1105     {
1106         the_other = num == 0 ? 1 : 0;
1107 
1108         if (panels[the_other].type != view_listing)
1109             return;
1110     }
1111 
1112     // Get rid of it
1113     if (panels[num].widget != NULL)
1114     {
1115         Widget *w = panels[num].widget;
1116         WPanel *panel = PANEL (w);
1117 
1118         r = w->rect;
1119         old_widget = w;
1120         old_type = panels[num].type;
1121 
1122         if (old_type == view_listing && panel->frame_size == frame_full && type != view_listing)
1123         {
1124             int md_cols = CONST_WIDGET (filemanager)->rect.cols;
1125 
1126             if (panels_layout.horizontal_split)
1127             {
1128                 r.cols = md_cols;
1129                 r.x = 0;
1130             }
1131             else
1132             {
1133                 r.cols = md_cols - panels_layout.left_panel_size;
1134                 if (num == 1)
1135                     r.x = panels_layout.left_panel_size;
1136             }
1137         }
1138     }
1139 
1140     // Restoring saved path from panels.ini for nonlist panel
1141     // when it's first creation (for example view_info)
1142     if (old_widget == NULL && type != view_listing)
1143         panels[num].last_saved_dir = vfs_get_cwd ();
1144 
1145     switch (type)
1146     {
1147     case view_nothing:
1148     case view_listing:
1149     {
1150         gboolean last_was_panel;
1151 
1152         last_was_panel = old_widget != NULL && get_panel_type (num) != view_listing;
1153         new_widget = restore_into_right_dir_panel (num, last_was_panel, &r);
1154         break;
1155     }
1156 
1157     case view_info:
1158         new_widget = WIDGET (info_new (&r));
1159         break;
1160 
1161     case view_tree:
1162         new_widget = WIDGET (tree_new (&r, TRUE));
1163         break;
1164 
1165     case view_quick:
1166     {
1167         WPanel *the_other_panel;
1168         const char *file_name = "";
1169 
1170         new_widget = WIDGET (mcview_new (&r, TRUE));
1171         the_other_panel = PANEL (panels[the_other].widget);
1172         if (the_other_panel != NULL)
1173         {
1174             const file_entry_t *fe;
1175 
1176             fe = panel_current_entry (the_other_panel);
1177             if (fe != NULL)
1178                 file_name = fe->fname->str;
1179         }
1180 
1181         mcview_load ((WView *) new_widget, 0, file_name, 0, 0, 0);
1182         break;
1183     }
1184 
1185     default:
1186         break;
1187     }
1188 
1189     if (type != view_listing)
1190         // Must save dir, for restoring after change type to
1191         // view_listing
1192         save_panel_dir (num);
1193 
1194     panels[num].type = type;
1195     panels[num].widget = new_widget;
1196 
1197     // We use replace to keep the circular list of the dialog in the
1198     // same state.  Maybe we could just kill it and then replace it
1199     if (old_widget != NULL)
1200     {
1201         // save directory history of panel
1202         if (old_type == view_listing)
1203             history_save (filemanager, old_widget);
1204 
1205         widget_replace (old_widget, new_widget);
1206     }
1207 
1208     if (type == view_listing)
1209     {
1210         WPanel *panel = PANEL (new_widget);
1211 
1212         // if existing panel changed type to view_listing, then load history
1213         if (old_widget != NULL)
1214             history_load (filemanager, new_widget);
1215 
1216         if (num == 0)
1217             left_panel = panel;
1218         else
1219             right_panel = panel;
1220 
1221         // forced update format after set new sizes
1222         set_panel_formats (panel);
1223     }
1224 
1225     if (type == view_tree)
1226         the_tree = (WTree *) new_widget;
1227 
1228     /* Prevent current_panel's value from becoming invalid.
1229      * It's just a quick hack to prevent segfaults. Comment out and
1230      * try following:
1231      * - select left panel
1232      * - invoke menu left/tree
1233      * - as long as you stay in the left panel almost everything that uses
1234      *   current_panel causes segfault, e.g. C-Enter, C-x c, ...
1235      */
1236     if ((type != view_listing) && (current_panel == PANEL (old_widget)))
1237         current_panel = num == 0 ? right_panel : left_panel;
1238 
1239     g_free (old_widget);
1240 }
1241 
1242 /* --------------------------------------------------------------------------------------------- */
1243 /** This routine is deeply sticked to the two panels idea.
1244    What should it do in more panels. ANSWER - don't use it
1245    in any multiple panels environment. */
1246 
1247 void
1248 swap_panels (void)
     /* [previous][next][first][last][top][bottom][index][help]  */
1249 {
1250     WPanel *panel1, *panel2;
1251     Widget *tmp_widget;
1252 
1253     panel1 = PANEL (panels[0].widget);
1254     panel2 = PANEL (panels[1].widget);
1255 
1256     if (panels[0].type == view_listing && panels[1].type == view_listing
1257         && !mc_config_get_bool (mc_global.main_config, CONFIG_PANELS_SECTION, "simple_swap", FALSE))
1258     {
1259         WPanel panel;
1260 
1261 #define panelswap(x)                                                                               \
1262     panel.x = panel1->x;                                                                           \
1263     panel1->x = panel2->x;                                                                         \
1264     panel2->x = panel.x;
1265         // Change content and related stuff
1266         panelswap (dir);
1267         panelswap (cwd_vpath);
1268         panelswap (lwd_vpath);
1269         panelswap (marked);
1270         panelswap (dirs_marked);
1271         panelswap (total);
1272         panelswap (top);
1273         panelswap (current);
1274         panelswap (is_panelized);
1275         panelswap (panelized_descr);
1276         panelswap (dir_stat);
1277 #undef panelswap
1278 
1279         panel1->quick_search.active = FALSE;
1280         panel2->quick_search.active = FALSE;
1281 
1282         if (current_panel == panel1)
1283             current_panel = panel2;
1284         else
1285             current_panel = panel1;
1286 
1287         // if sort options are different -> resort panels
1288         if (memcmp (&panel1->sort_info, &panel2->sort_info, sizeof (dir_sort_options_t)) != 0)
1289         {
1290             panel_re_sort (other_panel);
1291             panel_re_sort (current_panel);
1292         }
1293 
1294         if (widget_is_active (panels[0].widget))
1295             widget_select (panels[1].widget);
1296         else if (widget_is_active (panels[1].widget))
1297             widget_select (panels[0].widget);
1298     }
1299     else
1300     {
1301         WPanel *tmp_panel;
1302         WRect r;
1303         int tmp_type;
1304 
1305         tmp_panel = right_panel;
1306         right_panel = left_panel;
1307         left_panel = tmp_panel;
1308 
1309         if (panels[0].type == view_listing)
1310         {
1311             if (strcmp (panel1->name, get_nth_panel_name (0)) == 0)
1312             {
1313                 g_free (panel1->name);
1314                 panel1->name = g_strdup (get_nth_panel_name (1));
1315             }
1316         }
1317         if (panels[1].type == view_listing)
1318         {
1319             if (strcmp (panel2->name, get_nth_panel_name (1)) == 0)
1320             {
1321                 g_free (panel2->name);
1322                 panel2->name = g_strdup (get_nth_panel_name (0));
1323             }
1324         }
1325 
1326         r = panels[0].widget->rect;
1327         panels[0].widget->rect = panels[1].widget->rect;
1328         panels[1].widget->rect = r;
1329 
1330         tmp_widget = panels[0].widget;
1331         panels[0].widget = panels[1].widget;
1332         panels[1].widget = tmp_widget;
1333         tmp_type = panels[0].type;
1334         panels[0].type = panels[1].type;
1335         panels[1].type = tmp_type;
1336 
1337         // force update formats because of possible changed sizes
1338         if (panels[0].type == view_listing)
1339             set_panel_formats (PANEL (panels[0].widget));
1340         if (panels[1].type == view_listing)
1341             set_panel_formats (PANEL (panels[1].widget));
1342     }
1343 }
1344 
1345 /* --------------------------------------------------------------------------------------------- */
1346 
1347 panel_view_mode_t
1348 get_panel_type (int idx)
     /* [previous][next][first][last][top][bottom][index][help]  */
1349 {
1350     return panels[idx].type;
1351 }
1352 
1353 /* --------------------------------------------------------------------------------------------- */
1354 
1355 Widget *
1356 get_panel_widget (int idx)
     /* [previous][next][first][last][top][bottom][index][help]  */
1357 {
1358     return panels[idx].widget;
1359 }
1360 
1361 /* --------------------------------------------------------------------------------------------- */
1362 
1363 int
1364 get_current_index (void)
     /* [previous][next][first][last][top][bottom][index][help]  */
1365 {
1366     return (panels[0].widget == WIDGET (current_panel) ? 0 : 1);
1367 }
1368 
1369 /* --------------------------------------------------------------------------------------------- */
1370 
1371 int
1372 get_other_index (void)
     /* [previous][next][first][last][top][bottom][index][help]  */
1373 {
1374     return (get_current_index () == 0 ? 1 : 0);
1375 }
1376 
1377 /* --------------------------------------------------------------------------------------------- */
1378 
1379 WPanel *
1380 get_other_panel (void)
     /* [previous][next][first][last][top][bottom][index][help]  */
1381 {
1382     return PANEL (get_panel_widget (get_other_index ()));
1383 }
1384 
1385 /* --------------------------------------------------------------------------------------------- */
1386 /** Returns the view type for the current panel/view */
1387 
1388 panel_view_mode_t
1389 get_current_type (void)
     /* [previous][next][first][last][top][bottom][index][help]  */
1390 {
1391     return (panels[0].widget == WIDGET (current_panel) ? panels[0].type : panels[1].type);
1392 }
1393 
1394 /* --------------------------------------------------------------------------------------------- */
1395 /** Returns the view type of the unselected panel */
1396 
1397 panel_view_mode_t
1398 get_other_type (void)
     /* [previous][next][first][last][top][bottom][index][help]  */
1399 {
1400     return (panels[0].widget == WIDGET (current_panel) ? panels[1].type : panels[0].type);
1401 }
1402 
1403 /* --------------------------------------------------------------------------------------------- */
1404 /** Save current list_view widget directory into panel */
1405 
1406 void
1407 save_panel_dir (int idx)
     /* [previous][next][first][last][top][bottom][index][help]  */
1408 {
1409     panel_view_mode_t type;
1410 
1411     type = get_panel_type (idx);
1412     if (type == view_listing)
1413     {
1414         WPanel *p;
1415 
1416         p = PANEL (get_panel_widget (idx));
1417         if (p != NULL)
1418         {
1419             g_free (panels[idx].last_saved_dir);  // last path no needed
1420             // Because path can be nonlocal
1421             panels[idx].last_saved_dir = g_strdup (vfs_path_as_str (p->cwd_vpath));
1422         }
1423     }
1424 }
1425 
1426 /* --------------------------------------------------------------------------------------------- */
1427 /** Return working dir, if it's view_listing - cwd,
1428    but for other types - last_saved_dir */
1429 
1430 char *
1431 get_panel_dir_for (const WPanel *widget)
     /* [previous][next][first][last][top][bottom][index][help]  */
1432 {
1433     int i;
1434 
1435     for (i = 0; i < MAX_VIEWS; i++)
1436         if (PANEL (get_panel_widget (i)) == widget)
1437             break;
1438 
1439     if (i >= MAX_VIEWS)
1440         return g_strdup (".");
1441 
1442     if (get_panel_type (i) == view_listing)
1443     {
1444         vfs_path_t *cwd_vpath;
1445 
1446         cwd_vpath = PANEL (get_panel_widget (i))->cwd_vpath;
1447         return g_strdup (vfs_path_as_str (cwd_vpath));
1448     }
1449 
1450     return g_strdup (panels[i].last_saved_dir);
1451 }
1452 
1453 /* --------------------------------------------------------------------------------------------- */
1454 
1455 #ifdef ENABLE_SUBSHELL
1456 gboolean
1457 do_load_prompt (void)
     /* [previous][next][first][last][top][bottom][index][help]  */
1458 {
1459     gboolean ret = FALSE;
1460 
1461     if (!read_subshell_prompt ())
1462         return ret;
1463 
1464     // Don't actually change the prompt if it's invisible
1465     if (top_dlg != NULL && DIALOG (top_dlg->data) == filemanager && mc_global.cmdline_visible)
1466     {
1467         setup_cmdline ();
1468 
1469         /* since the prompt has changed, and we are called from one of the
1470          * tty_get_event channels, the prompt updating does not take place
1471          * automatically: force a cursor update and a screen refresh
1472          */
1473         widget_update_cursor (WIDGET (filemanager));
1474         mc_refresh ();
1475         ret = TRUE;
1476     }
1477     update_subshell_prompt = TRUE;
1478     return ret;
1479 }
1480 
1481 /* --------------------------------------------------------------------------------------------- */
1482 
1483 int
1484 load_prompt (int fd, void *unused)
     /* [previous][next][first][last][top][bottom][index][help]  */
1485 {
1486     (void) fd;
1487     (void) unused;
1488 
1489     if (should_read_new_subshell_prompt)
1490         do_load_prompt ();
1491     else
1492         flush_subshell (0, QUIETLY);
1493 
1494     return 0;
1495 }
1496 #endif
1497 
1498 /* --------------------------------------------------------------------------------------------- */
1499 
1500 void
1501 title_path_prepare (char **path, char **login)
     /* [previous][next][first][last][top][bottom][index][help]  */
1502 {
1503     char host[BUF_TINY];
1504     struct passwd *pw = NULL;
1505     int res = 0;
1506 
1507     *path =
1508         vfs_path_to_str_flags (current_panel->cwd_vpath, 0, VPF_STRIP_HOME | VPF_STRIP_PASSWORD);
1509 
1510     res = gethostname (host, sizeof (host));
1511     if (res != 0)
1512         host[0] = '\0';
1513     else
1514         host[sizeof (host) - 1] = '\0';
1515 
1516     pw = getpwuid (getuid ());
1517     if (pw != NULL)
1518         *login = g_strdup_printf ("%s@%s", pw->pw_name, host);
1519     else
1520         *login = g_strdup (host);
1521 }
1522 
1523 /* --------------------------------------------------------------------------------------------- */
1524 
1525 /** Show current directory in the xterm title */
1526 void
1527 update_xterm_title_path (void)
     /* [previous][next][first][last][top][bottom][index][help]  */
1528 {
1529     if (mc_global.tty.xterm_flag && xterm_title)
1530     {
1531         char *p;
1532         char *path;
1533         char *login;
1534 
1535         title_path_prepare (&path, &login);
1536 
1537         p = g_strdup_printf ("mc [%s]:%s", login, path);
1538         g_free (login);
1539         g_free (path);
1540 
1541         fprintf (stdout, ESC_STR "]0;%s" ESC_STR "\\", str_term_form (p));
1542         g_free (p);
1543 
1544         if (!mc_global.tty.alternate_plus_minus)
1545             numeric_keypad_mode ();
1546         (void) fflush (stdout);
1547     }
1548 }
1549 
1550 /* --------------------------------------------------------------------------------------------- */
1551 
1552 /** Tell the current directory to the terminal so it can open new tabs there */
1553 void
1554 update_terminal_cwd (void)
     /* [previous][next][first][last][top][bottom][index][help]  */
1555 {
1556     if (mc_global.tty.xterm_flag && vfs_current_is_local ())
1557     {
1558         const gchar *host;
1559         char *path, *path_uri;
1560 
1561         host = g_get_host_name ();
1562         path = vfs_path_to_str_flags (current_panel->cwd_vpath, 0, VPF_NONE);
1563         path_uri = g_uri_escape_string (path, "/", FALSE);
1564 
1565         fprintf (stdout, ESC_STR "]7;file://%s%s" ESC_STR "\\", host, path_uri);
1566         (void) fflush (stdout);
1567 
1568         g_free (path_uri);
1569         g_free (path);
1570     }
1571 }
1572 
1573 /* --------------------------------------------------------------------------------------------- */

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