Manual pages: mcmcdiffmceditmcview

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

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