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_callback
  9. layout_dlg_create
  10. panel_do_cols
  11. restore_into_right_dir_panel
  12. layout_save
  13. layout_restore
  14. layout_change
  15. layout_box
  16. panel_update_cols
  17. setup_panels
  18. panels_split_equal
  19. panels_split_more
  20. panels_split_less
  21. setup_cmdline
  22. use_dash
  23. set_hintbar
  24. rotate_dash
  25. get_nth_panel_name
  26. create_panel
  27. swap_panels
  28. get_panel_type
  29. get_panel_widget
  30. get_current_index
  31. get_other_index
  32. get_other_panel
  33. get_current_type
  34. get_other_type
  35. save_panel_dir
  36. get_panel_dir_for
  37. do_load_prompt
  38. load_prompt
  39. title_path_prepare
  40. update_xterm_title_path
  41. update_terminal_cwd

   1 /*
   2    Panel layout module for the Midnight Commander
   3 
   4    Copyright (C) 1995-2025
   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/tty/tty.h"
  45 #include "lib/skin.h"
  46 #include "lib/tty/key.h"
  47 #include "lib/tty/mouse.h"
  48 #include "lib/mcconfig.h"
  49 #include "lib/vfs/vfs.h"  // vfs_get_cwd ()
  50 #include "lib/strutil.h"
  51 #include "lib/widget.h"
  52 #include "lib/event.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 if the command prompt is to be displayed */
  92 gboolean command_prompt = TRUE;
  93 
  94 /* Set if the main menu is visible */
  95 gboolean menubar_visible = TRUE;
  96 
  97 /* Set to show current working dir in xterm window title */
  98 gboolean xterm_title = TRUE;
  99 
 100 /* Set to show free space on device assigned to current directory */
 101 gboolean free_space = TRUE;
 102 
 103 /* The starting line for the output of the subprogram */
 104 int output_start_y = 0;
 105 
 106 int ok_to_refresh = 1;
 107 
 108 /*** file scope macro definitions ****************************************************************/
 109 
 110 /* The maximum number of views managed by the create_panel routine */
 111 /* Must be at least two (for current and other).  Please note that until */
 112 /* Janne gets around this, we will only manage two of them :-) */
 113 #define MAX_VIEWS 2
 114 
 115 /* Width 12 for a wee Quick (Hex) View */
 116 #define MINWIDTH             12
 117 #define MINHEIGHT            5
 118 
 119 #define B_2LEFT              B_USER
 120 #define B_2RIGHT             (B_USER + 1)
 121 #define B_PLUS               (B_USER + 2)
 122 #define B_MINUS              (B_USER + 3)
 123 
 124 #define LAYOUT_OPTIONS_COUNT G_N_ELEMENTS (check_options)
 125 
 126 /*** file scope type declarations ****************************************************************/
 127 
 128 typedef struct
 129 {
 130     gboolean menubar_visible;
 131     gboolean command_prompt;
 132     gboolean keybar_visible;
 133     gboolean message_visible;
 134     gboolean xterm_title;
 135     gboolean free_space;
 136     int output_lines;
 137 } layout_t;
 138 
 139 /*** forward declarations (file scope functions) *************************************************/
 140 
 141 /*** file scope variables ************************************************************************/
 142 
 143 static struct
 144 {
 145     panel_view_mode_t type;
 146     Widget *widget;
 147     char *last_saved_dir;  // last view_list working directory
 148 } panels[MAX_VIEWS] = {
 149     // init MAX_VIEWS items
 150     { view_listing, NULL, NULL },
 151     { view_listing, NULL, NULL },
 152 };
 153 
 154 static layout_t old_layout;
 155 static panels_layout_t old_panels_layout;
 156 
 157 static gboolean equal_split;
 158 static int _output_lines;
 159 
 160 static int height;
 161 
 162 static WRadio *radio_widget;
 163 
 164 static struct
 165 {
 166     const char *text;
 167     gboolean *variable;
 168     WCheck *widget;
 169 } check_options[] = {
 170     { N_ ("&Equal split"), &equal_split, NULL },
 171     { N_ ("&Menubar visible"), &menubar_visible, NULL },
 172     { N_ ("Command &prompt"), &command_prompt, NULL },
 173     { N_ ("&Keybar visible"), &mc_global.keybar_visible, NULL },
 174     { N_ ("H&intbar visible"), &mc_global.message_visible, NULL },
 175     { N_ ("&XTerm window title"), &xterm_title, NULL },
 176     { N_ ("&Show free space"), &free_space, NULL },
 177 };
 178 
 179 static const char *output_lines_label = NULL;
 180 static int output_lines_label_len;
 181 
 182 static WButton *bleft_widget, *bright_widget;
 183 
 184 /* --------------------------------------------------------------------------------------------- */
 185 /*** file scope functions ************************************************************************/
 186 /* --------------------------------------------------------------------------------------------- */
 187 
 188 /* don't use max() macro to avoid double call of str_term_width1() in widget width calculation */
 189 #undef max
 190 
 191 static int
 192 max (int a, int b)
     /* [previous][next][first][last][top][bottom][index][help]  */
 193 {
 194     return a > b ? a : b;
 195 }
 196 
 197 /* --------------------------------------------------------------------------------------------- */
 198 
 199 static void
 200 check_split (panels_layout_t *layout)
     /* [previous][next][first][last][top][bottom][index][help]  */
 201 {
 202     if (layout->horizontal_split)
 203     {
 204         if (layout->horizontal_equal)
 205             layout->top_panel_size = height / 2;
 206         else if (layout->top_panel_size < MINHEIGHT)
 207             layout->top_panel_size = MINHEIGHT;
 208         else if (layout->top_panel_size > height - MINHEIGHT)
 209             layout->top_panel_size = height - MINHEIGHT;
 210     }
 211     else
 212     {
 213         int md_cols = CONST_WIDGET (filemanager)->rect.cols;
 214 
 215         if (layout->vertical_equal)
 216             layout->left_panel_size = md_cols / 2;
 217         else if (layout->left_panel_size < MINWIDTH)
 218             layout->left_panel_size = MINWIDTH;
 219         else if (layout->left_panel_size > md_cols - MINWIDTH)
 220             layout->left_panel_size = md_cols - MINWIDTH;
 221     }
 222 }
 223 
 224 /* --------------------------------------------------------------------------------------------- */
 225 
 226 static void
 227 update_split (const WDialog *h)
     /* [previous][next][first][last][top][bottom][index][help]  */
 228 {
 229     /* Check split has to be done before testing if it changed, since
 230        it can change due to calling check_split() as well */
 231     check_split (&panels_layout);
 232 
 233     if (panels_layout.horizontal_split)
 234         check_options[0].widget->state = panels_layout.horizontal_equal;
 235     else
 236         check_options[0].widget->state = panels_layout.vertical_equal;
 237     widget_draw (WIDGET (check_options[0].widget));
 238 
 239     tty_setcolor (check_options[0].widget->state ? DISABLED_COLOR : COLOR_NORMAL);
 240 
 241     widget_gotoyx (h, 6, 5);
 242     if (panels_layout.horizontal_split)
 243         tty_printf ("%03d", panels_layout.top_panel_size);
 244     else
 245         tty_printf ("%03d", panels_layout.left_panel_size);
 246 
 247     widget_gotoyx (h, 6, 17);
 248     if (panels_layout.horizontal_split)
 249         tty_printf ("%03d", height - panels_layout.top_panel_size);
 250     else
 251         tty_printf ("%03d", CONST_WIDGET (filemanager)->rect.cols - panels_layout.left_panel_size);
 252 
 253     widget_gotoyx (h, 6, 12);
 254     tty_print_char ('=');
 255 }
 256 
 257 /* --------------------------------------------------------------------------------------------- */
 258 
 259 static int
 260 b_left_right_cback (WButton *button, int action)
     /* [previous][next][first][last][top][bottom][index][help]  */
 261 {
 262     (void) action;
 263 
 264     if (button == bright_widget)
 265     {
 266         if (panels_layout.horizontal_split)
 267             panels_layout.top_panel_size++;
 268         else
 269             panels_layout.left_panel_size++;
 270     }
 271     else
 272     {
 273         if (panels_layout.horizontal_split)
 274             panels_layout.top_panel_size--;
 275         else
 276             panels_layout.left_panel_size--;
 277     }
 278 
 279     update_split (DIALOG (WIDGET (button)->owner));
 280     layout_change ();
 281     do_refresh ();
 282     return 0;
 283 }
 284 
 285 /* --------------------------------------------------------------------------------------------- */
 286 
 287 static int
 288 bplus_cback (WButton *button, int action)
     /* [previous][next][first][last][top][bottom][index][help]  */
 289 {
 290     (void) button;
 291     (void) action;
 292 
 293     if (_output_lines < 99)
 294         _output_lines++;
 295     return 0;
 296 }
 297 
 298 /* --------------------------------------------------------------------------------------------- */
 299 
 300 static int
 301 bminus_cback (WButton *button, int action)
     /* [previous][next][first][last][top][bottom][index][help]  */
 302 {
 303     (void) button;
 304     (void) action;
 305 
 306     if (_output_lines > 0)
 307         _output_lines--;
 308     return 0;
 309 }
 310 
 311 /* --------------------------------------------------------------------------------------------- */
 312 
 313 static cb_ret_t
 314 layout_bg_callback (Widget *w, Widget *sender, widget_msg_t msg, int parm, void *data)
     /* [previous][next][first][last][top][bottom][index][help]  */
 315 {
 316     switch (msg)
 317     {
 318     case MSG_DRAW:
 319         frame_callback (w, NULL, MSG_DRAW, 0, NULL);
 320 
 321         old_layout.output_lines = -1;
 322 
 323         update_split (DIALOG (w->owner));
 324 
 325         if (old_layout.output_lines != _output_lines)
 326         {
 327             old_layout.output_lines = _output_lines;
 328             tty_setcolor (mc_global.tty.console_flag != '\0' ? COLOR_NORMAL : DISABLED_COLOR);
 329             widget_gotoyx (w, 9, 5);
 330             tty_print_string (output_lines_label);
 331             widget_gotoyx (w, 9, 5 + 3 + output_lines_label_len);
 332             tty_printf ("%02d", _output_lines);
 333         }
 334         return MSG_HANDLED;
 335 
 336     default:
 337         return frame_callback (w, sender, msg, parm, data);
 338     }
 339 }
 340 
 341 /* --------------------------------------------------------------------------------------------- */
 342 
 343 static cb_ret_t
 344 layout_callback (Widget *w, Widget *sender, widget_msg_t msg, int parm, void *data)
     /* [previous][next][first][last][top][bottom][index][help]  */
 345 {
 346     WDialog *h = DIALOG (w);
 347 
 348     switch (msg)
 349     {
 350     case MSG_POST_KEY:
 351     {
 352         const Widget *mw = CONST_WIDGET (filemanager);
 353         gboolean _menubar_visible, _command_prompt, _keybar_visible, _message_visible;
 354 
 355         _menubar_visible = check_options[1].widget->state;
 356         _command_prompt = check_options[2].widget->state;
 357         _keybar_visible = check_options[3].widget->state;
 358         _message_visible = check_options[4].widget->state;
 359 
 360         if (mc_global.tty.console_flag == '\0')
 361             height = mw->rect.lines - (_keybar_visible ? 1 : 0) - (_command_prompt ? 1 : 0)
 362                 - (_menubar_visible ? 1 : 0) - _output_lines - (_message_visible ? 1 : 0);
 363         else
 364         {
 365             int minimum;
 366 
 367             if (_output_lines < 0)
 368                 _output_lines = 0;
 369             height = mw->rect.lines - (_keybar_visible ? 1 : 0) - (_command_prompt ? 1 : 0)
 370                 - (_menubar_visible ? 1 : 0) - _output_lines - (_message_visible ? 1 : 0);
 371             minimum = MINHEIGHT * (1 + (panels_layout.horizontal_split ? 1 : 0));
 372             if (height < minimum)
 373             {
 374                 _output_lines -= minimum - height;
 375                 height = minimum;
 376             }
 377         }
 378 
 379         if (old_layout.output_lines != _output_lines)
 380         {
 381             old_layout.output_lines = _output_lines;
 382             tty_setcolor (mc_global.tty.console_flag != '\0' ? COLOR_NORMAL : DISABLED_COLOR);
 383             widget_gotoyx (h, 9, 5 + 3 + output_lines_label_len);
 384             tty_printf ("%02d", _output_lines);
 385         }
 386     }
 387         return MSG_HANDLED;
 388 
 389     case MSG_NOTIFY:
 390         if (sender == WIDGET (radio_widget))
 391         {
 392             if ((panels_layout.horizontal_split ? 1 : 0) == radio_widget->sel)
 393                 update_split (h);
 394             else
 395             {
 396                 int eq;
 397 
 398                 panels_layout.horizontal_split = radio_widget->sel != 0;
 399 
 400                 if (panels_layout.horizontal_split)
 401                 {
 402                     eq = panels_layout.horizontal_equal;
 403                     if (eq)
 404                         panels_layout.top_panel_size = height / 2;
 405                 }
 406                 else
 407                 {
 408                     eq = panels_layout.vertical_equal;
 409                     if (eq)
 410                         panels_layout.left_panel_size = CONST_WIDGET (filemanager)->rect.cols / 2;
 411                 }
 412 
 413                 widget_disable (WIDGET (bleft_widget), eq);
 414                 widget_disable (WIDGET (bright_widget), eq);
 415 
 416                 update_split (h);
 417                 layout_change ();
 418                 do_refresh ();
 419             }
 420 
 421             return MSG_HANDLED;
 422         }
 423 
 424         if (sender == WIDGET (check_options[0].widget))
 425         {
 426             gboolean eq;
 427 
 428             if (panels_layout.horizontal_split)
 429             {
 430                 panels_layout.horizontal_equal = check_options[0].widget->state;
 431                 eq = panels_layout.horizontal_equal;
 432             }
 433             else
 434             {
 435                 panels_layout.vertical_equal = check_options[0].widget->state;
 436                 eq = panels_layout.vertical_equal;
 437             }
 438 
 439             widget_disable (WIDGET (bleft_widget), eq);
 440             widget_disable (WIDGET (bright_widget), eq);
 441 
 442             update_split (h);
 443             layout_change ();
 444             do_refresh ();
 445 
 446             return MSG_HANDLED;
 447         }
 448 
 449         {
 450             gboolean ok = TRUE;
 451 
 452             if (sender == WIDGET (check_options[1].widget))
 453                 menubar_visible = check_options[1].widget->state;
 454             else if (sender == WIDGET (check_options[2].widget))
 455                 command_prompt = check_options[2].widget->state;
 456             else if (sender == WIDGET (check_options[3].widget))
 457                 mc_global.keybar_visible = check_options[3].widget->state;
 458             else if (sender == WIDGET (check_options[4].widget))
 459                 mc_global.message_visible = check_options[4].widget->state;
 460             else if (sender == WIDGET (check_options[5].widget))
 461                 xterm_title = check_options[5].widget->state;
 462             else if (sender == WIDGET (check_options[6].widget))
 463                 free_space = check_options[6].widget->state;
 464             else
 465                 ok = FALSE;
 466 
 467             if (ok)
 468             {
 469                 update_split (h);
 470                 layout_change ();
 471                 do_refresh ();
 472                 return MSG_HANDLED;
 473             }
 474         }
 475 
 476         return MSG_NOT_HANDLED;
 477 
 478     default:
 479         return dlg_default_callback (w, sender, msg, parm, data);
 480     }
 481 }
 482 
 483 /* --------------------------------------------------------------------------------------------- */
 484 
 485 static WDialog *
 486 layout_dlg_create (void)
     /* [previous][next][first][last][top][bottom][index][help]  */
 487 {
 488     WDialog *layout_dlg;
 489     WGroup *g;
 490     int l1 = 0, width;
 491     int b1, b2, b;
 492     size_t i;
 493 
 494     const char *title1 = N_ ("Panel split");
 495     const char *title2 = N_ ("Console output");
 496     const char *title3 = N_ ("Other options");
 497 
 498     const char *s_split_direction[2] = {
 499         N_ ("&Vertical"),
 500         N_ ("&Horizontal"),
 501     };
 502 
 503     const char *ok_button = N_ ("&OK");
 504     const char *cancel_button = N_ ("&Cancel");
 505 
 506     output_lines_label = _ ("Output lines:");
 507 
 508 #ifdef ENABLE_NLS
 509     {
 510         static gboolean i18n = FALSE;
 511 
 512         title1 = _ (title1);
 513         title2 = _ (title2);
 514         title3 = _ (title3);
 515 
 516         i = G_N_ELEMENTS (s_split_direction);
 517         while (i-- != 0)
 518             s_split_direction[i] = _ (s_split_direction[i]);
 519 
 520         if (!i18n)
 521         {
 522             for (i = 0; i < (size_t) LAYOUT_OPTIONS_COUNT; i++)
 523                 check_options[i].text = _ (check_options[i].text);
 524             i18n = TRUE;
 525         }
 526 
 527         ok_button = _ (ok_button);
 528         cancel_button = _ (cancel_button);
 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 = menubar_visible;
 669     old_layout.command_prompt = command_prompt;
 670     old_layout.keybar_visible = mc_global.keybar_visible;
 671     old_layout.message_visible = mc_global.message_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     menubar_visible = old_layout.menubar_visible;
 687     command_prompt = old_layout.command_prompt;
 688     mc_global.keybar_visible = old_layout.keybar_visible;
 689     mc_global.message_visible = old_layout.message_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_change ();
 738     do_refresh ();
 739 }
 740 
 741 /* --------------------------------------------------------------------------------------------- */
 742 
 743 void
 744 panel_update_cols (Widget *widget, panel_display_t frame_size)
     /* [previous][next][first][last][top][bottom][index][help]  */
 745 {
 746     const Widget *mw = CONST_WIDGET (filemanager);
 747     int cols, x;
 748 
 749     // don't touch panel if it is not in dialog yet
 750     /* if panel is not in dialog it is not in widgets list
 751        and cannot be compared with get_panel_widget() result */
 752     if (widget->owner == NULL)
 753         return;
 754 
 755     if (panels_layout.horizontal_split)
 756     {
 757         widget->rect.cols = mw->rect.cols;
 758         return;
 759     }
 760 
 761     if (frame_size == frame_full)
 762     {
 763         cols = mw->rect.cols;
 764         x = mw->rect.x;
 765     }
 766     else if (widget == get_panel_widget (0))
 767     {
 768         cols = panels_layout.left_panel_size;
 769         x = mw->rect.x;
 770     }
 771     else
 772     {
 773         cols = mw->rect.cols - panels_layout.left_panel_size;
 774         x = mw->rect.x + panels_layout.left_panel_size;
 775     }
 776 
 777     widget->rect.cols = cols;
 778     widget->rect.x = x;
 779 }
 780 
 781 /* --------------------------------------------------------------------------------------------- */
 782 
 783 void
 784 setup_panels (void)
     /* [previous][next][first][last][top][bottom][index][help]  */
 785 {
 786     /* File manager screen layout:
 787      *
 788      * +---------------------------------------------------------------+
 789      * | Menu bar                                                      |
 790      * +-------------------------------+-------------------------------+
 791      * |                               |                               |
 792      * |                               |                               |
 793      * |                               |                               |
 794      * |                               |                               |
 795      * |         Left panel            |         Right panel           |
 796      * |                               |                               |
 797      * |                               |                               |
 798      * |                               |                               |
 799      * |                               |                               |
 800      * +-------------------------------+-------------------------------+
 801      * | Hint (message) bar                                            |
 802      * +---------------------------------------------------------------+
 803      * |                                                               |
 804      * |                        Console content                        |
 805      * |                                                               |
 806      * +--------+------------------------------------------------------+
 807      * | Prompt | Command line                                         |
 808      * | Key (button) bar                                              |
 809      * +--------+------------------------------------------------------+
 810      */
 811 
 812     Widget *mw = WIDGET (filemanager);
 813     const WRect *r = &CONST_WIDGET (mw)->rect;
 814     int start_y;
 815     gboolean active;
 816     WRect rb;
 817 
 818     active = widget_get_state (mw, WST_ACTIVE);
 819 
 820     // lock the group to avoid many redraws
 821     if (active)
 822         widget_set_state (mw, WST_SUSPENDED, TRUE);
 823 
 824     // initial height of panels
 825     height = r->lines - (menubar_visible ? 1 : 0) - (mc_global.message_visible ? 1 : 0)
 826         - (command_prompt ? 1 : 0) - (mc_global.keybar_visible ? 1 : 0);
 827 
 828     if (mc_global.tty.console_flag != '\0')
 829     {
 830         int minimum;
 831 
 832         if (output_lines < 0)
 833             output_lines = 0;
 834         else
 835             height -= output_lines;
 836         minimum = MINHEIGHT * (1 + (panels_layout.horizontal_split ? 1 : 0));
 837         if (height < minimum)
 838         {
 839             output_lines -= minimum - height;
 840             height = minimum;
 841         }
 842     }
 843 
 844     rb = *r;
 845     rb.lines = 1;
 846     widget_set_size_rect (WIDGET (the_menubar), &rb);
 847     widget_set_visibility (WIDGET (the_menubar), menubar_visible);
 848 
 849     check_split (&panels_layout);
 850     start_y = r->y + (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     widget_set_visibility (WIDGET (the_hint), mc_global.message_visible);
 873 
 874     // Output window
 875     if (mc_global.tty.console_flag != '\0' && output_lines != 0)
 876     {
 877         unsigned char end_line;
 878 
 879         end_line = r->lines - (mc_global.keybar_visible ? 1 : 0) - 1;
 880         output_start_y = end_line - (command_prompt ? 1 : 0) - output_lines + 1;
 881         show_console_contents (output_start_y, end_line - output_lines, end_line);
 882     }
 883 
 884     if (command_prompt)
 885     {
 886 #ifdef ENABLE_SUBSHELL
 887         if (!mc_global.tty.use_subshell || !do_load_prompt ())
 888 #endif
 889             setup_cmdline ();
 890     }
 891     else
 892     {
 893         // make invisible
 894         widget_hide (WIDGET (cmdline));
 895         widget_hide (WIDGET (the_prompt));
 896     }
 897 
 898     rb = *r;
 899     rb.y = r->lines - 1;
 900     rb.lines = 1;
 901     widget_set_size_rect (WIDGET (the_bar), &rb);
 902     widget_set_visibility (WIDGET (the_bar), mc_global.keybar_visible);
 903 
 904     update_xterm_title_path ();
 905     update_terminal_cwd ();
 906 
 907     // unlock
 908     if (active)
 909     {
 910         widget_set_state (mw, WST_ACTIVE, TRUE);
 911         widget_draw (mw);
 912     }
 913 }
 914 
 915 /* --------------------------------------------------------------------------------------------- */
 916 
 917 void
 918 panels_split_equal (void)
     /* [previous][next][first][last][top][bottom][index][help]  */
 919 {
 920     if (panels_layout.horizontal_split)
 921         panels_layout.horizontal_equal = TRUE;
 922     else
 923         panels_layout.vertical_equal = TRUE;
 924 
 925     layout_change ();
 926     do_refresh ();
 927 }
 928 
 929 /* --------------------------------------------------------------------------------------------- */
 930 
 931 void
 932 panels_split_more (void)
     /* [previous][next][first][last][top][bottom][index][help]  */
 933 {
 934     if (panels_layout.horizontal_split)
 935     {
 936         panels_layout.horizontal_equal = FALSE;
 937         panels_layout.top_panel_size++;
 938     }
 939     else
 940     {
 941         panels_layout.vertical_equal = FALSE;
 942         panels_layout.left_panel_size++;
 943     }
 944 
 945     layout_change ();
 946 }
 947 
 948 /* --------------------------------------------------------------------------------------------- */
 949 
 950 void
 951 panels_split_less (void)
     /* [previous][next][first][last][top][bottom][index][help]  */
 952 {
 953     if (panels_layout.horizontal_split)
 954     {
 955         panels_layout.horizontal_equal = FALSE;
 956         panels_layout.top_panel_size--;
 957     }
 958     else
 959     {
 960         panels_layout.vertical_equal = FALSE;
 961         panels_layout.left_panel_size--;
 962     }
 963 
 964     layout_change ();
 965 }
 966 
 967 /* --------------------------------------------------------------------------------------------- */
 968 
 969 void
 970 setup_cmdline (void)
     /* [previous][next][first][last][top][bottom][index][help]  */
 971 {
 972     const Widget *mw = CONST_WIDGET (filemanager);
 973     const WRect *r = &mw->rect;
 974     int prompt_width;
 975     int y;
 976     char *tmp_prompt = (char *) mc_prompt;
 977 
 978     if (!command_prompt)
 979         return;
 980 
 981 #ifdef ENABLE_SUBSHELL
 982     if (mc_global.tty.use_subshell)
 983     {
 984         // Workaround: avoid crash on FreeBSD (see ticket #4213 for details)
 985         if (subshell_prompt != NULL)
 986             tmp_prompt = g_string_free (subshell_prompt, FALSE);
 987         else
 988             tmp_prompt = g_strdup (mc_prompt);
 989         (void) strip_ctrl_codes (tmp_prompt);
 990     }
 991 #endif
 992 
 993     prompt_width = str_term_width1 (tmp_prompt);
 994 
 995     // Check for prompts too big
 996     if (r->cols > 8 && prompt_width > r->cols - 8)
 997     {
 998         int prompt_len;
 999 
1000         prompt_width = r->cols - 8;
1001         prompt_len = str_offset_to_pos (tmp_prompt, prompt_width);
1002         tmp_prompt[prompt_len] = '\0';
1003     }
1004 
1005 #ifdef ENABLE_SUBSHELL
1006     if (mc_global.tty.use_subshell)
1007     {
1008         subshell_prompt = g_string_new_take (tmp_prompt);
1009         mc_prompt = subshell_prompt->str;
1010     }
1011 #endif
1012 
1013     y = r->lines - 1 - (mc_global.keybar_visible ? 1 : 0);
1014 
1015     widget_set_size (WIDGET (the_prompt), y, r->x, 1, prompt_width);
1016     label_set_text (the_prompt, mc_prompt);
1017     widget_set_size (WIDGET (cmdline), y, r->x + prompt_width, 1, r->cols - prompt_width);
1018 
1019     widget_show (WIDGET (the_prompt));
1020     widget_show (WIDGET (cmdline));
1021 }
1022 
1023 /* --------------------------------------------------------------------------------------------- */
1024 
1025 void
1026 use_dash (gboolean flag)
     /* [previous][next][first][last][top][bottom][index][help]  */
1027 {
1028     if (flag)
1029         ok_to_refresh++;
1030     else
1031         ok_to_refresh--;
1032 }
1033 
1034 /* --------------------------------------------------------------------------------------------- */
1035 
1036 void
1037 set_hintbar (const char *str)
     /* [previous][next][first][last][top][bottom][index][help]  */
1038 {
1039     label_set_text (the_hint, str);
1040     if (ok_to_refresh > 0)
1041         mc_refresh ();
1042 }
1043 
1044 /* --------------------------------------------------------------------------------------------- */
1045 
1046 void
1047 rotate_dash (gboolean show)
     /* [previous][next][first][last][top][bottom][index][help]  */
1048 {
1049     static gint64 timestamp = 0;
1050     // update with 10 FPS rate
1051     static const gint64 delay = G_USEC_PER_SEC / 10;
1052 
1053     const Widget *w = CONST_WIDGET (filemanager);
1054 
1055     if (!nice_rotating_dash || (ok_to_refresh <= 0))
1056         return;
1057 
1058     if (show && !mc_time_elapsed (&timestamp, delay))
1059         return;
1060 
1061     widget_gotoyx (w, menubar_visible ? 1 : 0, w->rect.cols - 1);
1062     tty_setcolor (NORMAL_COLOR);
1063 
1064     if (!show)
1065         tty_print_alt_char (ACS_URCORNER, FALSE);
1066     else
1067     {
1068         static const char rotating_dash[4] = "|/-\\";
1069         static size_t pos = 0;
1070 
1071         tty_print_char (rotating_dash[pos]);
1072         pos = (pos + 1) % sizeof (rotating_dash);
1073     }
1074 
1075     mc_refresh ();
1076 }
1077 
1078 /* --------------------------------------------------------------------------------------------- */
1079 
1080 const char *
1081 get_nth_panel_name (int num)
     /* [previous][next][first][last][top][bottom][index][help]  */
1082 {
1083     if (num == 0)
1084         return "New Left Panel";
1085 
1086     if (num == 1)
1087         return "New Right Panel";
1088 
1089     {
1090         static char buffer[BUF_SMALL];
1091 
1092         g_snprintf (buffer, sizeof (buffer), "%ith Panel", num);
1093         return buffer;
1094     }
1095 }
1096 
1097 /* --------------------------------------------------------------------------------------------- */
1098 /* I wonder if I should start to use the folding mode than Dugan uses */
1099 /*                                                                     */
1100 /* This is the centralized managing of the panel display types         */
1101 /* This routine takes care of destroying and creating new widgets      */
1102 /* Please note that it could manage MAX_VIEWS, not just left and right */
1103 /* Currently nothing in the code takes advantage of this and has hard- */
1104 /* coded values for two panels only                                    */
1105 
1106 /* Set the num-th panel to the view type: type */
1107 /* This routine also keeps at least one WPanel object in the screen */
1108 /* since a lot of routines depend on the current_panel variable */
1109 
1110 void
1111 create_panel (int num, panel_view_mode_t type)
     /* [previous][next][first][last][top][bottom][index][help]  */
1112 {
1113     WRect r = { 0, 0, 0, 0 };
1114     unsigned int the_other = 0;  // Index to the other panel
1115     Widget *new_widget = NULL, *old_widget = NULL;
1116     panel_view_mode_t old_type = view_listing;
1117 
1118     if (num >= MAX_VIEWS)
1119     {
1120         fprintf (stderr, "Cannot allocate more that %d views\n", MAX_VIEWS);
1121         abort ();
1122     }
1123     // Check that we will have a WPanel * at least
1124     if (type != view_listing)
1125     {
1126         the_other = num == 0 ? 1 : 0;
1127 
1128         if (panels[the_other].type != view_listing)
1129             return;
1130     }
1131 
1132     // Get rid of it
1133     if (panels[num].widget != NULL)
1134     {
1135         Widget *w = panels[num].widget;
1136         WPanel *panel = PANEL (w);
1137 
1138         r = w->rect;
1139         old_widget = w;
1140         old_type = panels[num].type;
1141 
1142         if (old_type == view_listing && panel->frame_size == frame_full && type != view_listing)
1143         {
1144             int md_cols = CONST_WIDGET (filemanager)->rect.cols;
1145 
1146             if (panels_layout.horizontal_split)
1147             {
1148                 r.cols = md_cols;
1149                 r.x = 0;
1150             }
1151             else
1152             {
1153                 r.cols = md_cols - panels_layout.left_panel_size;
1154                 if (num == 1)
1155                     r.x = panels_layout.left_panel_size;
1156             }
1157         }
1158     }
1159 
1160     // Restoring saved path from panels.ini for nonlist panel
1161     // when it's first creation (for example view_info)
1162     if (old_widget == NULL && type != view_listing)
1163         panels[num].last_saved_dir = vfs_get_cwd ();
1164 
1165     switch (type)
1166     {
1167     case view_nothing:
1168     case view_listing:
1169     {
1170         gboolean last_was_panel;
1171 
1172         last_was_panel = old_widget != NULL && get_panel_type (num) != view_listing;
1173         new_widget = restore_into_right_dir_panel (num, last_was_panel, &r);
1174         break;
1175     }
1176 
1177     case view_info:
1178         new_widget = WIDGET (info_new (&r));
1179         break;
1180 
1181     case view_tree:
1182         new_widget = WIDGET (tree_new (&r, TRUE));
1183         break;
1184 
1185     case view_quick:
1186     {
1187         WPanel *the_other_panel;
1188         const char *file_name = "";
1189 
1190         new_widget = WIDGET (mcview_new (&r, TRUE));
1191         the_other_panel = PANEL (panels[the_other].widget);
1192         if (the_other_panel != NULL)
1193         {
1194             const file_entry_t *fe;
1195 
1196             fe = panel_current_entry (the_other_panel);
1197             if (fe != NULL)
1198                 file_name = fe->fname->str;
1199         }
1200 
1201         mcview_load ((WView *) new_widget, 0, file_name, 0, 0, 0);
1202         break;
1203     }
1204 
1205     default:
1206         break;
1207     }
1208 
1209     if (type != view_listing)
1210         // Must save dir, for restoring after change type to
1211         // view_listing
1212         save_panel_dir (num);
1213 
1214     panels[num].type = type;
1215     panels[num].widget = new_widget;
1216 
1217     // We use replace to keep the circular list of the dialog in the
1218     // same state.  Maybe we could just kill it and then replace it
1219     if (old_widget != NULL)
1220     {
1221         if (old_type == view_listing)
1222         {
1223             /* save and write directory history of panel
1224              * ... and other histories of filemanager  */
1225             dlg_save_history (filemanager);
1226         }
1227 
1228         widget_replace (old_widget, new_widget);
1229     }
1230 
1231     if (type == view_listing)
1232     {
1233         WPanel *panel = PANEL (new_widget);
1234 
1235         // if existing panel changed type to view_listing, then load history
1236         if (old_widget != NULL)
1237         {
1238             ev_history_load_save_t event_data = { NULL, new_widget };
1239 
1240             mc_event_raise (filemanager->event_group, MCEVENT_HISTORY_LOAD, &event_data);
1241         }
1242 
1243         if (num == 0)
1244             left_panel = panel;
1245         else
1246             right_panel = panel;
1247 
1248         // forced update format after set new sizes
1249         set_panel_formats (panel);
1250     }
1251 
1252     if (type == view_tree)
1253         the_tree = (WTree *) new_widget;
1254 
1255     /* Prevent current_panel's value from becoming invalid.
1256      * It's just a quick hack to prevent segfaults. Comment out and
1257      * try following:
1258      * - select left panel
1259      * - invoke menu left/tree
1260      * - as long as you stay in the left panel almost everything that uses
1261      *   current_panel causes segfault, e.g. C-Enter, C-x c, ...
1262      */
1263     if ((type != view_listing) && (current_panel == PANEL (old_widget)))
1264         current_panel = num == 0 ? right_panel : left_panel;
1265 
1266     g_free (old_widget);
1267 }
1268 
1269 /* --------------------------------------------------------------------------------------------- */
1270 /** This routine is deeply sticked to the two panels idea.
1271    What should it do in more panels. ANSWER - don't use it
1272    in any multiple panels environment. */
1273 
1274 void
1275 swap_panels (void)
     /* [previous][next][first][last][top][bottom][index][help]  */
1276 {
1277     WPanel *panel1, *panel2;
1278     Widget *tmp_widget;
1279 
1280     panel1 = PANEL (panels[0].widget);
1281     panel2 = PANEL (panels[1].widget);
1282 
1283     if (panels[0].type == view_listing && panels[1].type == view_listing
1284         && !mc_config_get_bool (mc_global.main_config, CONFIG_PANELS_SECTION, "simple_swap", FALSE))
1285     {
1286         WPanel panel;
1287 
1288 #define panelswap(x)                                                                               \
1289     panel.x = panel1->x;                                                                           \
1290     panel1->x = panel2->x;                                                                         \
1291     panel2->x = panel.x;
1292         // Change content and related stuff
1293         panelswap (dir);
1294         panelswap (active);
1295         panelswap (cwd_vpath);
1296         panelswap (lwd_vpath);
1297         panelswap (marked);
1298         panelswap (dirs_marked);
1299         panelswap (total);
1300         panelswap (top);
1301         panelswap (current);
1302         panelswap (is_panelized);
1303         panelswap (panelized_descr);
1304         panelswap (dir_stat);
1305 #undef panelswap
1306 
1307         panel1->quick_search.active = FALSE;
1308         panel2->quick_search.active = FALSE;
1309 
1310         if (current_panel == panel1)
1311             current_panel = panel2;
1312         else
1313             current_panel = panel1;
1314 
1315         // if sort options are different -> resort panels
1316         if (memcmp (&panel1->sort_info, &panel2->sort_info, sizeof (dir_sort_options_t)) != 0)
1317         {
1318             panel_re_sort (other_panel);
1319             panel_re_sort (current_panel);
1320         }
1321 
1322         if (widget_is_active (panels[0].widget))
1323             widget_select (panels[1].widget);
1324         else if (widget_is_active (panels[1].widget))
1325             widget_select (panels[0].widget);
1326     }
1327     else
1328     {
1329         WPanel *tmp_panel;
1330         WRect r;
1331         int tmp_type;
1332 
1333         tmp_panel = right_panel;
1334         right_panel = left_panel;
1335         left_panel = tmp_panel;
1336 
1337         if (panels[0].type == view_listing)
1338         {
1339             if (strcmp (panel1->name, get_nth_panel_name (0)) == 0)
1340             {
1341                 g_free (panel1->name);
1342                 panel1->name = g_strdup (get_nth_panel_name (1));
1343             }
1344         }
1345         if (panels[1].type == view_listing)
1346         {
1347             if (strcmp (panel2->name, get_nth_panel_name (1)) == 0)
1348             {
1349                 g_free (panel2->name);
1350                 panel2->name = g_strdup (get_nth_panel_name (0));
1351             }
1352         }
1353 
1354         r = panels[0].widget->rect;
1355         panels[0].widget->rect = panels[1].widget->rect;
1356         panels[1].widget->rect = r;
1357 
1358         tmp_widget = panels[0].widget;
1359         panels[0].widget = panels[1].widget;
1360         panels[1].widget = tmp_widget;
1361         tmp_type = panels[0].type;
1362         panels[0].type = panels[1].type;
1363         panels[1].type = tmp_type;
1364 
1365         // force update formats because of possible changed sizes
1366         if (panels[0].type == view_listing)
1367             set_panel_formats (PANEL (panels[0].widget));
1368         if (panels[1].type == view_listing)
1369             set_panel_formats (PANEL (panels[1].widget));
1370     }
1371 }
1372 
1373 /* --------------------------------------------------------------------------------------------- */
1374 
1375 panel_view_mode_t
1376 get_panel_type (int idx)
     /* [previous][next][first][last][top][bottom][index][help]  */
1377 {
1378     return panels[idx].type;
1379 }
1380 
1381 /* --------------------------------------------------------------------------------------------- */
1382 
1383 Widget *
1384 get_panel_widget (int idx)
     /* [previous][next][first][last][top][bottom][index][help]  */
1385 {
1386     return panels[idx].widget;
1387 }
1388 
1389 /* --------------------------------------------------------------------------------------------- */
1390 
1391 int
1392 get_current_index (void)
     /* [previous][next][first][last][top][bottom][index][help]  */
1393 {
1394     return (panels[0].widget == WIDGET (current_panel) ? 0 : 1);
1395 }
1396 
1397 /* --------------------------------------------------------------------------------------------- */
1398 
1399 int
1400 get_other_index (void)
     /* [previous][next][first][last][top][bottom][index][help]  */
1401 {
1402     return (get_current_index () == 0 ? 1 : 0);
1403 }
1404 
1405 /* --------------------------------------------------------------------------------------------- */
1406 
1407 WPanel *
1408 get_other_panel (void)
     /* [previous][next][first][last][top][bottom][index][help]  */
1409 {
1410     return PANEL (get_panel_widget (get_other_index ()));
1411 }
1412 
1413 /* --------------------------------------------------------------------------------------------- */
1414 /** Returns the view type for the current panel/view */
1415 
1416 panel_view_mode_t
1417 get_current_type (void)
     /* [previous][next][first][last][top][bottom][index][help]  */
1418 {
1419     return (panels[0].widget == WIDGET (current_panel) ? panels[0].type : panels[1].type);
1420 }
1421 
1422 /* --------------------------------------------------------------------------------------------- */
1423 /** Returns the view type of the unselected panel */
1424 
1425 panel_view_mode_t
1426 get_other_type (void)
     /* [previous][next][first][last][top][bottom][index][help]  */
1427 {
1428     return (panels[0].widget == WIDGET (current_panel) ? panels[1].type : panels[0].type);
1429 }
1430 
1431 /* --------------------------------------------------------------------------------------------- */
1432 /** Save current list_view widget directory into panel */
1433 
1434 void
1435 save_panel_dir (int idx)
     /* [previous][next][first][last][top][bottom][index][help]  */
1436 {
1437     panel_view_mode_t type;
1438 
1439     type = get_panel_type (idx);
1440     if (type == view_listing)
1441     {
1442         WPanel *p;
1443 
1444         p = PANEL (get_panel_widget (idx));
1445         if (p != NULL)
1446         {
1447             g_free (panels[idx].last_saved_dir);  // last path no needed
1448             // Because path can be nonlocal
1449             panels[idx].last_saved_dir = g_strdup (vfs_path_as_str (p->cwd_vpath));
1450         }
1451     }
1452 }
1453 
1454 /* --------------------------------------------------------------------------------------------- */
1455 /** Return working dir, if it's view_listing - cwd,
1456    but for other types - last_saved_dir */
1457 
1458 char *
1459 get_panel_dir_for (const WPanel *widget)
     /* [previous][next][first][last][top][bottom][index][help]  */
1460 {
1461     int i;
1462 
1463     for (i = 0; i < MAX_VIEWS; i++)
1464         if (PANEL (get_panel_widget (i)) == widget)
1465             break;
1466 
1467     if (i >= MAX_VIEWS)
1468         return g_strdup (".");
1469 
1470     if (get_panel_type (i) == view_listing)
1471     {
1472         vfs_path_t *cwd_vpath;
1473 
1474         cwd_vpath = PANEL (get_panel_widget (i))->cwd_vpath;
1475         return g_strdup (vfs_path_as_str (cwd_vpath));
1476     }
1477 
1478     return g_strdup (panels[i].last_saved_dir);
1479 }
1480 
1481 /* --------------------------------------------------------------------------------------------- */
1482 
1483 #ifdef ENABLE_SUBSHELL
1484 gboolean
1485 do_load_prompt (void)
     /* [previous][next][first][last][top][bottom][index][help]  */
1486 {
1487     gboolean ret = FALSE;
1488 
1489     if (!read_subshell_prompt ())
1490         return ret;
1491 
1492     // Don't actually change the prompt if it's invisible
1493     if (top_dlg != NULL && DIALOG (top_dlg->data) == filemanager && command_prompt)
1494     {
1495         setup_cmdline ();
1496 
1497         /* since the prompt has changed, and we are called from one of the
1498          * tty_get_event channels, the prompt updating does not take place
1499          * automatically: force a cursor update and a screen refresh
1500          */
1501         widget_update_cursor (WIDGET (filemanager));
1502         mc_refresh ();
1503         ret = TRUE;
1504     }
1505     update_subshell_prompt = TRUE;
1506     return ret;
1507 }
1508 
1509 /* --------------------------------------------------------------------------------------------- */
1510 
1511 int
1512 load_prompt (int fd, void *unused)
     /* [previous][next][first][last][top][bottom][index][help]  */
1513 {
1514     (void) fd;
1515     (void) unused;
1516 
1517     if (should_read_new_subshell_prompt)
1518         do_load_prompt ();
1519     else
1520         flush_subshell (0, QUIETLY);
1521 
1522     return 0;
1523 }
1524 #endif
1525 
1526 /* --------------------------------------------------------------------------------------------- */
1527 
1528 void
1529 title_path_prepare (char **path, char **login)
     /* [previous][next][first][last][top][bottom][index][help]  */
1530 {
1531     char host[BUF_TINY];
1532     struct passwd *pw = NULL;
1533     int res = 0;
1534 
1535     *path =
1536         vfs_path_to_str_flags (current_panel->cwd_vpath, 0, VPF_STRIP_HOME | VPF_STRIP_PASSWORD);
1537 
1538     res = gethostname (host, sizeof (host));
1539     if (res != 0)
1540         host[0] = '\0';
1541     else
1542         host[sizeof (host) - 1] = '\0';
1543 
1544     pw = getpwuid (getuid ());
1545     if (pw != NULL)
1546         *login = g_strdup_printf ("%s@%s", pw->pw_name, host);
1547     else
1548         *login = g_strdup (host);
1549 }
1550 
1551 /* --------------------------------------------------------------------------------------------- */
1552 
1553 /** Show current directory in the xterm title */
1554 void
1555 update_xterm_title_path (void)
     /* [previous][next][first][last][top][bottom][index][help]  */
1556 {
1557     if (mc_global.tty.xterm_flag && xterm_title)
1558     {
1559         char *p;
1560         char *path;
1561         char *login;
1562 
1563         title_path_prepare (&path, &login);
1564 
1565         p = g_strdup_printf ("mc [%s]:%s", login, path);
1566         g_free (login);
1567         g_free (path);
1568 
1569         fprintf (stdout, ESC_STR "]0;%s" ESC_STR "\\", str_term_form (p));
1570         g_free (p);
1571 
1572         if (!mc_global.tty.alternate_plus_minus)
1573             numeric_keypad_mode ();
1574         (void) fflush (stdout);
1575     }
1576 }
1577 
1578 /* --------------------------------------------------------------------------------------------- */
1579 
1580 /** Tell the current directory to the terminal so it can open new tabs there */
1581 void
1582 update_terminal_cwd (void)
     /* [previous][next][first][last][top][bottom][index][help]  */
1583 {
1584     if (mc_global.tty.xterm_flag && vfs_current_is_local ())
1585     {
1586         const gchar *host;
1587         char *path, *path_uri;
1588 
1589         host = g_get_host_name ();
1590         path = vfs_path_to_str_flags (current_panel->cwd_vpath, 0, VPF_NONE);
1591         path_uri = g_uri_escape_string (path, "/", FALSE);
1592 
1593         fprintf (stdout, ESC_STR "]7;file://%s%s" ESC_STR "\\", host, path_uri);
1594         (void) fflush (stdout);
1595 
1596         g_free (path_uri);
1597         g_free (path);
1598     }
1599 }
1600 
1601 /* --------------------------------------------------------------------------------------------- */

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