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 = N_ ("Panel split");
 496     const char *title2 = N_ ("Console output");
 497     const char *title3 = N_ ("Other options");
 498 
 499     const char *s_split_direction[2] = {
 500         N_ ("&Vertical"),
 501         N_ ("&Horizontal"),
 502     };
 503 
 504     const char *ok_button = N_ ("&OK");
 505     const char *cancel_button = N_ ("&Cancel");
 506 
 507     output_lines_label = _ ("Output lines:");
 508 
 509 #ifdef ENABLE_NLS
 510     {
 511         static gboolean i18n = FALSE;
 512 
 513         title1 = _ (title1);
 514         title2 = _ (title2);
 515         title3 = _ (title3);
 516 
 517         i = G_N_ELEMENTS (s_split_direction);
 518         while (i-- != 0)
 519             s_split_direction[i] = _ (s_split_direction[i]);
 520 
 521         if (!i18n)
 522         {
 523             for (i = 0; i < (size_t) LAYOUT_OPTIONS_COUNT; i++)
 524                 check_options[i].text = _ (check_options[i].text);
 525             i18n = TRUE;
 526         }
 527 
 528         ok_button = _ (ok_button);
 529         cancel_button = _ (cancel_button);
 530     }
 531 #endif
 532 
 533     // radiobuttons
 534     i = G_N_ELEMENTS (s_split_direction);
 535     while (i-- != 0)
 536         l1 = max (l1, str_term_width1 (s_split_direction[i]) + 7);
 537     // checkboxes
 538     for (i = 0; i < (size_t) LAYOUT_OPTIONS_COUNT; i++)
 539         l1 = max (l1, str_term_width1 (check_options[i].text) + 7);
 540     // groupboxes
 541     l1 = max (l1, str_term_width1 (title1) + 4);
 542     l1 = max (l1, str_term_width1 (title2) + 4);
 543     l1 = max (l1, str_term_width1 (title3) + 4);
 544     // label + "+"/"-" buttons
 545     output_lines_label_len = str_term_width1 (output_lines_label);
 546     l1 = max (l1, output_lines_label_len + 12);
 547     // buttons
 548     b1 = str_term_width1 (ok_button) + 5;  // default button
 549     b2 = str_term_width1 (cancel_button) + 3;
 550     b = b1 + b2 + 1;
 551     // dialog width
 552     width = max (l1 * 2 + 7, b);
 553 
 554     layout_dlg = dlg_create (TRUE, 0, 0, 15, width, WPOS_CENTER, FALSE, dialog_colors,
 555                              layout_callback, NULL, "[Layout]", _ ("Layout"));
 556     g = GROUP (layout_dlg);
 557 
 558     // draw background
 559     layout_dlg->bg->callback = layout_bg_callback;
 560 
 561 #define XTRACT(i) (*check_options[i].variable != 0), check_options[i].text
 562 
 563     // "Panel split" groupbox
 564     group_add_widget (g, groupbox_new (2, 3, 6, l1, title1));
 565 
 566     radio_widget = radio_new (3, 5, 2, s_split_direction);
 567     radio_widget->sel = panels_layout.horizontal_split ? 1 : 0;
 568     group_add_widget (g, radio_widget);
 569 
 570     check_options[0].widget = check_new (5, 5, XTRACT (0));
 571     group_add_widget (g, check_options[0].widget);
 572 
 573     equal_split = panels_layout.horizontal_split ? panels_layout.horizontal_equal
 574                                                  : panels_layout.vertical_equal;
 575 
 576     bleft_widget = button_new (6, 8, B_2LEFT, NARROW_BUTTON, "&<", b_left_right_cback);
 577     widget_disable (WIDGET (bleft_widget), equal_split);
 578     group_add_widget (g, bleft_widget);
 579 
 580     bright_widget = button_new (6, 14, B_2RIGHT, NARROW_BUTTON, "&>", b_left_right_cback);
 581     widget_disable (WIDGET (bright_widget), equal_split);
 582     group_add_widget (g, bright_widget);
 583 
 584     // "Console output" groupbox
 585     {
 586         widget_state_t disabled;
 587         Widget *w;
 588 
 589         disabled = mc_global.tty.console_flag != '\0' ? 0 : WST_DISABLED;
 590 
 591         w = WIDGET (groupbox_new (8, 3, 3, l1, title2));
 592         w->state |= disabled;
 593         group_add_widget (g, w);
 594 
 595         w = WIDGET (
 596             button_new (9, output_lines_label_len + 5, B_PLUS, NARROW_BUTTON, "&+", bplus_cback));
 597         w->state |= disabled;
 598         group_add_widget (g, w);
 599 
 600         w = WIDGET (button_new (9, output_lines_label_len + 5 + 5, B_MINUS, NARROW_BUTTON, "&-",
 601                                 bminus_cback));
 602         w->state |= disabled;
 603         group_add_widget (g, w);
 604     }
 605 
 606     // "Other options" groupbox
 607     group_add_widget (g, groupbox_new (2, 4 + l1, 9, l1, title3));
 608 
 609     for (i = 1; i < (size_t) LAYOUT_OPTIONS_COUNT; i++)
 610     {
 611         check_options[i].widget = check_new (i + 2, 6 + l1, XTRACT (i));
 612         group_add_widget (g, check_options[i].widget);
 613     }
 614 
 615 #undef XTRACT
 616 
 617     group_add_widget (g, hline_new (11, -1, -1));
 618     // buttons
 619     group_add_widget (g, button_new (12, (width - b) / 2, B_ENTER, DEFPUSH_BUTTON, ok_button, 0));
 620     group_add_widget (
 621         g, button_new (12, (width - b) / 2 + b1 + 1, B_CANCEL, NORMAL_BUTTON, cancel_button, 0));
 622 
 623     widget_select (WIDGET (radio_widget));
 624 
 625     return layout_dlg;
 626 }
 627 
 628 /* --------------------------------------------------------------------------------------------- */
 629 
 630 static void
 631 panel_do_cols (int idx)
     /* [previous][next][first][last][top][bottom][index][help]  */
 632 {
 633     if (get_panel_type (idx) == view_listing)
 634         set_panel_formats (PANEL (panels[idx].widget));
 635     else
 636         panel_update_cols (panels[idx].widget, frame_half);
 637 }
 638 
 639 /* --------------------------------------------------------------------------------------------- */
 640 /** Save current list_view widget directory into panel */
 641 
 642 static Widget *
 643 restore_into_right_dir_panel (int idx, gboolean last_was_panel, const WRect *r)
     /* [previous][next][first][last][top][bottom][index][help]  */
 644 {
 645     WPanel *new_widget;
 646     const char *p_name;
 647 
 648     p_name = get_nth_panel_name (idx);
 649 
 650     if (last_was_panel)
 651     {
 652         vfs_path_t *saved_dir_vpath;
 653 
 654         saved_dir_vpath = vfs_path_from_str (panels[idx].last_saved_dir);
 655         new_widget = panel_sized_with_dir_new (p_name, r, saved_dir_vpath);
 656         vfs_path_free (saved_dir_vpath, TRUE);
 657     }
 658     else
 659         new_widget = panel_sized_new (p_name, r);
 660 
 661     return WIDGET (new_widget);
 662 }
 663 
 664 /* --------------------------------------------------------------------------------------------- */
 665 
 666 static void
 667 layout_save (void)
     /* [previous][next][first][last][top][bottom][index][help]  */
 668 {
 669     old_layout.menubar_visible = menubar_visible;
 670     old_layout.command_prompt = command_prompt;
 671     old_layout.keybar_visible = mc_global.keybar_visible;
 672     old_layout.message_visible = mc_global.message_visible;
 673     old_layout.xterm_title = xterm_title;
 674     old_layout.free_space = free_space;
 675     old_layout.output_lines = -1;
 676 
 677     _output_lines = output_lines;
 678 
 679     old_panels_layout = panels_layout;
 680 }
 681 
 682 /* --------------------------------------------------------------------------------------------- */
 683 
 684 static void
 685 layout_restore (void)
     /* [previous][next][first][last][top][bottom][index][help]  */
 686 {
 687     menubar_visible = old_layout.menubar_visible;
 688     command_prompt = old_layout.command_prompt;
 689     mc_global.keybar_visible = old_layout.keybar_visible;
 690     mc_global.message_visible = old_layout.message_visible;
 691     xterm_title = old_layout.xterm_title;
 692     free_space = old_layout.free_space;
 693     output_lines = old_layout.output_lines;
 694 
 695     panels_layout = old_panels_layout;
 696 }
 697 
 698 /* --------------------------------------------------------------------------------------------- */
 699 /*** public functions ****************************************************************************/
 700 /* --------------------------------------------------------------------------------------------- */
 701 
 702 void
 703 layout_change (void)
     /* [previous][next][first][last][top][bottom][index][help]  */
 704 {
 705     setup_panels ();
 706     /* update the main menu, because perhaps there was a change in the way
 707        how the panel are split (horizontal/vertical),
 708        and a change of menu visibility. */
 709     update_menu ();
 710     load_hint (TRUE);
 711 }
 712 
 713 /* --------------------------------------------------------------------------------------------- */
 714 
 715 void
 716 layout_box (void)
     /* [previous][next][first][last][top][bottom][index][help]  */
 717 {
 718     WDialog *layout_dlg;
 719 
 720     layout_save ();
 721 
 722     layout_dlg = layout_dlg_create ();
 723 
 724     if (dlg_run (layout_dlg) == B_ENTER)
 725     {
 726         size_t i;
 727 
 728         for (i = 0; i < (size_t) LAYOUT_OPTIONS_COUNT; i++)
 729             if (check_options[i].widget != NULL)
 730                 *check_options[i].variable = check_options[i].widget->state;
 731 
 732         output_lines = _output_lines;
 733     }
 734     else
 735         layout_restore ();
 736 
 737     widget_destroy (WIDGET (layout_dlg));
 738     layout_change ();
 739     do_refresh ();
 740 }
 741 
 742 /* --------------------------------------------------------------------------------------------- */
 743 
 744 void
 745 panel_update_cols (Widget *widget, panel_display_t frame_size)
     /* [previous][next][first][last][top][bottom][index][help]  */
 746 {
 747     const Widget *mw = CONST_WIDGET (filemanager);
 748     int cols, x;
 749 
 750     // don't touch panel if it is not in dialog yet
 751     /* if panel is not in dialog it is not in widgets list
 752        and cannot be compared with get_panel_widget() result */
 753     if (widget->owner == NULL)
 754         return;
 755 
 756     if (panels_layout.horizontal_split)
 757     {
 758         widget->rect.cols = mw->rect.cols;
 759         return;
 760     }
 761 
 762     if (frame_size == frame_full)
 763     {
 764         cols = mw->rect.cols;
 765         x = mw->rect.x;
 766     }
 767     else if (widget == get_panel_widget (0))
 768     {
 769         cols = panels_layout.left_panel_size;
 770         x = mw->rect.x;
 771     }
 772     else
 773     {
 774         cols = mw->rect.cols - panels_layout.left_panel_size;
 775         x = mw->rect.x + panels_layout.left_panel_size;
 776     }
 777 
 778     widget->rect.cols = cols;
 779     widget->rect.x = x;
 780 }
 781 
 782 /* --------------------------------------------------------------------------------------------- */
 783 
 784 void
 785 setup_panels (void)
     /* [previous][next][first][last][top][bottom][index][help]  */
 786 {
 787     /* File manager screen layout:
 788      *
 789      * +---------------------------------------------------------------+
 790      * | Menu bar                                                      |
 791      * +-------------------------------+-------------------------------+
 792      * |                               |                               |
 793      * |                               |                               |
 794      * |                               |                               |
 795      * |                               |                               |
 796      * |         Left panel            |         Right panel           |
 797      * |                               |                               |
 798      * |                               |                               |
 799      * |                               |                               |
 800      * |                               |                               |
 801      * +-------------------------------+-------------------------------+
 802      * | Hint (message) bar                                            |
 803      * +---------------------------------------------------------------+
 804      * |                                                               |
 805      * |                        Console content                        |
 806      * |                                                               |
 807      * +--------+------------------------------------------------------+
 808      * | Prompt | Command line                                         |
 809      * | Key (button) bar                                              |
 810      * +--------+------------------------------------------------------+
 811      */
 812 
 813     Widget *mw = WIDGET (filemanager);
 814     const WRect *r = &CONST_WIDGET (mw)->rect;
 815     int start_y;
 816     gboolean active;
 817     WRect rb;
 818 
 819     active = widget_get_state (mw, WST_ACTIVE);
 820 
 821     // lock the group to avoid many redraws
 822     if (active)
 823         widget_set_state (mw, WST_SUSPENDED, TRUE);
 824 
 825     // initial height of panels
 826     height = r->lines - (menubar_visible ? 1 : 0) - (mc_global.message_visible ? 1 : 0)
 827         - (command_prompt ? 1 : 0) - (mc_global.keybar_visible ? 1 : 0);
 828 
 829     if (mc_global.tty.console_flag != '\0')
 830     {
 831         int minimum;
 832 
 833         if (output_lines < 0)
 834             output_lines = 0;
 835         else
 836             height -= output_lines;
 837         minimum = MINHEIGHT * (1 + (panels_layout.horizontal_split ? 1 : 0));
 838         if (height < minimum)
 839         {
 840             output_lines -= minimum - height;
 841             height = minimum;
 842         }
 843     }
 844 
 845     rb = *r;
 846     rb.lines = 1;
 847     widget_set_size_rect (WIDGET (the_menubar), &rb);
 848     widget_set_visibility (WIDGET (the_menubar), menubar_visible);
 849 
 850     check_split (&panels_layout);
 851     start_y = r->y + (menubar_visible ? 1 : 0);
 852 
 853     // update columns first...
 854     panel_do_cols (0);
 855     panel_do_cols (1);
 856 
 857     // ...then rows and origin
 858     if (panels_layout.horizontal_split)
 859     {
 860         widget_set_size (panels[0].widget, start_y, r->x, panels_layout.top_panel_size,
 861                          panels[0].widget->rect.cols);
 862         widget_set_size (panels[1].widget, start_y + panels_layout.top_panel_size, r->x,
 863                          height - panels_layout.top_panel_size, panels[1].widget->rect.cols);
 864     }
 865     else
 866     {
 867         widget_set_size (panels[0].widget, start_y, r->x, height, panels[0].widget->rect.cols);
 868         widget_set_size (panels[1].widget, start_y, panels[1].widget->rect.x, height,
 869                          panels[1].widget->rect.cols);
 870     }
 871 
 872     widget_set_size (WIDGET (the_hint), height + start_y, r->x, 1, r->cols);
 873     widget_set_visibility (WIDGET (the_hint), mc_global.message_visible);
 874 
 875     // Output window
 876     if (mc_global.tty.console_flag != '\0' && output_lines != 0)
 877     {
 878         unsigned char end_line;
 879 
 880         end_line = r->lines - (mc_global.keybar_visible ? 1 : 0) - 1;
 881         output_start_y = end_line - (command_prompt ? 1 : 0) - output_lines + 1;
 882         show_console_contents (output_start_y, end_line - output_lines, end_line);
 883     }
 884 
 885     if (command_prompt)
 886     {
 887 #ifdef ENABLE_SUBSHELL
 888         if (!mc_global.tty.use_subshell || !do_load_prompt ())
 889 #endif
 890             setup_cmdline ();
 891     }
 892     else
 893     {
 894         // make invisible
 895         widget_hide (WIDGET (cmdline));
 896         widget_hide (WIDGET (the_prompt));
 897     }
 898 
 899     rb = *r;
 900     rb.y = r->lines - 1;
 901     rb.lines = 1;
 902     widget_set_size_rect (WIDGET (the_bar), &rb);
 903     widget_set_visibility (WIDGET (the_bar), mc_global.keybar_visible);
 904 
 905     update_xterm_title_path ();
 906     update_terminal_cwd ();
 907 
 908     // unlock
 909     if (active)
 910     {
 911         widget_set_state (mw, WST_ACTIVE, TRUE);
 912         widget_draw (mw);
 913     }
 914 }
 915 
 916 /* --------------------------------------------------------------------------------------------- */
 917 
 918 void
 919 panels_split_equal (void)
     /* [previous][next][first][last][top][bottom][index][help]  */
 920 {
 921     if (panels_layout.horizontal_split)
 922         panels_layout.horizontal_equal = TRUE;
 923     else
 924         panels_layout.vertical_equal = TRUE;
 925 
 926     layout_change ();
 927     do_refresh ();
 928 }
 929 
 930 /* --------------------------------------------------------------------------------------------- */
 931 
 932 void
 933 panels_split_more (void)
     /* [previous][next][first][last][top][bottom][index][help]  */
 934 {
 935     if (panels_layout.horizontal_split)
 936     {
 937         panels_layout.horizontal_equal = FALSE;
 938         panels_layout.top_panel_size++;
 939     }
 940     else
 941     {
 942         panels_layout.vertical_equal = FALSE;
 943         panels_layout.left_panel_size++;
 944     }
 945 
 946     layout_change ();
 947 }
 948 
 949 /* --------------------------------------------------------------------------------------------- */
 950 
 951 void
 952 panels_split_less (void)
     /* [previous][next][first][last][top][bottom][index][help]  */
 953 {
 954     if (panels_layout.horizontal_split)
 955     {
 956         panels_layout.horizontal_equal = FALSE;
 957         panels_layout.top_panel_size--;
 958     }
 959     else
 960     {
 961         panels_layout.vertical_equal = FALSE;
 962         panels_layout.left_panel_size--;
 963     }
 964 
 965     layout_change ();
 966 }
 967 
 968 /* --------------------------------------------------------------------------------------------- */
 969 
 970 void
 971 setup_cmdline (void)
     /* [previous][next][first][last][top][bottom][index][help]  */
 972 {
 973     const Widget *mw = CONST_WIDGET (filemanager);
 974     const WRect *r = &mw->rect;
 975     int prompt_width;
 976     int y;
 977     char *tmp_prompt = (char *) mc_prompt;
 978 
 979     if (!command_prompt)
 980         return;
 981 
 982 #ifdef ENABLE_SUBSHELL
 983     if (mc_global.tty.use_subshell)
 984     {
 985         // Workaround: avoid crash on FreeBSD (see ticket #4213 for details)
 986         if (subshell_prompt != NULL)
 987             tmp_prompt = g_string_free (subshell_prompt, FALSE);
 988         else
 989             tmp_prompt = g_strdup (mc_prompt);
 990         (void) strip_ctrl_codes (tmp_prompt);
 991     }
 992 #endif
 993 
 994     prompt_width = str_term_width1 (tmp_prompt);
 995 
 996     // Check for prompts too big
 997     if (r->cols > 8 && prompt_width > r->cols - 8)
 998     {
 999         int prompt_len;
1000 
1001         prompt_width = r->cols - 8;
1002         prompt_len = str_offset_to_pos (tmp_prompt, prompt_width);
1003         tmp_prompt[prompt_len] = '\0';
1004     }
1005 
1006 #ifdef ENABLE_SUBSHELL
1007     if (mc_global.tty.use_subshell)
1008     {
1009         subshell_prompt = g_string_new_take (tmp_prompt);
1010         mc_prompt = subshell_prompt->str;
1011     }
1012 #endif
1013 
1014     y = r->lines - 1 - (mc_global.keybar_visible ? 1 : 0);
1015 
1016     widget_set_size (WIDGET (the_prompt), y, r->x, 1, prompt_width);
1017     label_set_text (the_prompt, mc_prompt);
1018     widget_set_size (WIDGET (cmdline), y, r->x + prompt_width, 1, r->cols - prompt_width);
1019 
1020     widget_show (WIDGET (the_prompt));
1021     widget_show (WIDGET (cmdline));
1022 }
1023 
1024 /* --------------------------------------------------------------------------------------------- */
1025 
1026 void
1027 use_dash (gboolean flag)
     /* [previous][next][first][last][top][bottom][index][help]  */
1028 {
1029     if (flag)
1030         ok_to_refresh++;
1031     else
1032         ok_to_refresh--;
1033 }
1034 
1035 /* --------------------------------------------------------------------------------------------- */
1036 
1037 void
1038 set_hintbar (const char *str)
     /* [previous][next][first][last][top][bottom][index][help]  */
1039 {
1040     label_set_text (the_hint, str);
1041     if (ok_to_refresh > 0)
1042         mc_refresh ();
1043 }
1044 
1045 /* --------------------------------------------------------------------------------------------- */
1046 
1047 void
1048 rotate_dash (gboolean show)
     /* [previous][next][first][last][top][bottom][index][help]  */
1049 {
1050     static gint64 timestamp = 0;
1051     // update with 10 FPS rate
1052     static const gint64 delay = G_USEC_PER_SEC / 10;
1053 
1054     const Widget *w = CONST_WIDGET (filemanager);
1055 
1056     if (!nice_rotating_dash || (ok_to_refresh <= 0))
1057         return;
1058 
1059     if (show && !mc_time_elapsed (&timestamp, delay))
1060         return;
1061 
1062     widget_gotoyx (w, menubar_visible ? 1 : 0, w->rect.cols - 1);
1063     tty_setcolor (NORMAL_COLOR);
1064 
1065     if (!show)
1066         tty_print_alt_char (ACS_URCORNER, FALSE);
1067     else
1068     {
1069         static const char rotating_dash[4] = "|/-\\";
1070         static size_t pos = 0;
1071 
1072         tty_print_char (rotating_dash[pos]);
1073         pos = (pos + 1) % sizeof (rotating_dash);
1074     }
1075 
1076     mc_refresh ();
1077 }
1078 
1079 /* --------------------------------------------------------------------------------------------- */
1080 
1081 const char *
1082 get_nth_panel_name (int num)
     /* [previous][next][first][last][top][bottom][index][help]  */
1083 {
1084     if (num == 0)
1085         return "New Left Panel";
1086 
1087     if (num == 1)
1088         return "New Right Panel";
1089 
1090     {
1091         static char buffer[BUF_SMALL];
1092 
1093         g_snprintf (buffer, sizeof (buffer), "%ith Panel", num);
1094         return buffer;
1095     }
1096 }
1097 
1098 /* --------------------------------------------------------------------------------------------- */
1099 /* I wonder if I should start to use the folding mode than Dugan uses */
1100 /*                                                                     */
1101 /* This is the centralized managing of the panel display types         */
1102 /* This routine takes care of destroying and creating new widgets      */
1103 /* Please note that it could manage MAX_VIEWS, not just left and right */
1104 /* Currently nothing in the code takes advantage of this and has hard- */
1105 /* coded values for two panels only                                    */
1106 
1107 /* Set the num-th panel to the view type: type */
1108 /* This routine also keeps at least one WPanel object in the screen */
1109 /* since a lot of routines depend on the current_panel variable */
1110 
1111 void
1112 create_panel (int num, panel_view_mode_t type)
     /* [previous][next][first][last][top][bottom][index][help]  */
1113 {
1114     WRect r = { 0, 0, 0, 0 };
1115     unsigned int the_other = 0;  // Index to the other panel
1116     Widget *new_widget = NULL, *old_widget = NULL;
1117     panel_view_mode_t old_type = view_listing;
1118 
1119     if (num >= MAX_VIEWS)
1120     {
1121         fprintf (stderr, "Cannot allocate more that %d views\n", MAX_VIEWS);
1122         abort ();
1123     }
1124     // Check that we will have a WPanel * at least
1125     if (type != view_listing)
1126     {
1127         the_other = num == 0 ? 1 : 0;
1128 
1129         if (panels[the_other].type != view_listing)
1130             return;
1131     }
1132 
1133     // Get rid of it
1134     if (panels[num].widget != NULL)
1135     {
1136         Widget *w = panels[num].widget;
1137         WPanel *panel = PANEL (w);
1138 
1139         r = w->rect;
1140         old_widget = w;
1141         old_type = panels[num].type;
1142 
1143         if (old_type == view_listing && panel->frame_size == frame_full && type != view_listing)
1144         {
1145             int md_cols = CONST_WIDGET (filemanager)->rect.cols;
1146 
1147             if (panels_layout.horizontal_split)
1148             {
1149                 r.cols = md_cols;
1150                 r.x = 0;
1151             }
1152             else
1153             {
1154                 r.cols = md_cols - panels_layout.left_panel_size;
1155                 if (num == 1)
1156                     r.x = panels_layout.left_panel_size;
1157             }
1158         }
1159     }
1160 
1161     // Restoring saved path from panels.ini for nonlist panel
1162     // when it's first creation (for example view_info)
1163     if (old_widget == NULL && type != view_listing)
1164         panels[num].last_saved_dir = vfs_get_cwd ();
1165 
1166     switch (type)
1167     {
1168     case view_nothing:
1169     case view_listing:
1170     {
1171         gboolean last_was_panel;
1172 
1173         last_was_panel = old_widget != NULL && get_panel_type (num) != view_listing;
1174         new_widget = restore_into_right_dir_panel (num, last_was_panel, &r);
1175         break;
1176     }
1177 
1178     case view_info:
1179         new_widget = WIDGET (info_new (&r));
1180         break;
1181 
1182     case view_tree:
1183         new_widget = WIDGET (tree_new (&r, TRUE));
1184         break;
1185 
1186     case view_quick:
1187     {
1188         WPanel *the_other_panel;
1189         const char *file_name = "";
1190 
1191         new_widget = WIDGET (mcview_new (&r, TRUE));
1192         the_other_panel = PANEL (panels[the_other].widget);
1193         if (the_other_panel != NULL)
1194         {
1195             const file_entry_t *fe;
1196 
1197             fe = panel_current_entry (the_other_panel);
1198             if (fe != NULL)
1199                 file_name = fe->fname->str;
1200         }
1201 
1202         mcview_load ((WView *) new_widget, 0, file_name, 0, 0, 0);
1203         break;
1204     }
1205 
1206     default:
1207         break;
1208     }
1209 
1210     if (type != view_listing)
1211         // Must save dir, for restoring after change type to
1212         // view_listing
1213         save_panel_dir (num);
1214 
1215     panels[num].type = type;
1216     panels[num].widget = new_widget;
1217 
1218     // We use replace to keep the circular list of the dialog in the
1219     // same state.  Maybe we could just kill it and then replace it
1220     if (old_widget != NULL)
1221     {
1222         if (old_type == view_listing)
1223         {
1224             /* save and write directory history of panel
1225              * ... and other histories of filemanager  */
1226             dlg_save_history (filemanager);
1227         }
1228 
1229         widget_replace (old_widget, new_widget);
1230     }
1231 
1232     if (type == view_listing)
1233     {
1234         WPanel *panel = PANEL (new_widget);
1235 
1236         // if existing panel changed type to view_listing, then load history
1237         if (old_widget != NULL)
1238         {
1239             ev_history_load_save_t event_data = { NULL, new_widget };
1240 
1241             mc_event_raise (filemanager->event_group, MCEVENT_HISTORY_LOAD, &event_data);
1242         }
1243 
1244         if (num == 0)
1245             left_panel = panel;
1246         else
1247             right_panel = panel;
1248 
1249         // forced update format after set new sizes
1250         set_panel_formats (panel);
1251     }
1252 
1253     if (type == view_tree)
1254         the_tree = (WTree *) new_widget;
1255 
1256     /* Prevent current_panel's value from becoming invalid.
1257      * It's just a quick hack to prevent segfaults. Comment out and
1258      * try following:
1259      * - select left panel
1260      * - invoke menu left/tree
1261      * - as long as you stay in the left panel almost everything that uses
1262      *   current_panel causes segfault, e.g. C-Enter, C-x c, ...
1263      */
1264     if ((type != view_listing) && (current_panel == PANEL (old_widget)))
1265         current_panel = num == 0 ? right_panel : left_panel;
1266 
1267     g_free (old_widget);
1268 }
1269 
1270 /* --------------------------------------------------------------------------------------------- */
1271 /** This routine is deeply sticked to the two panels idea.
1272    What should it do in more panels. ANSWER - don't use it
1273    in any multiple panels environment. */
1274 
1275 void
1276 swap_panels (void)
     /* [previous][next][first][last][top][bottom][index][help]  */
1277 {
1278     WPanel *panel1, *panel2;
1279     Widget *tmp_widget;
1280 
1281     panel1 = PANEL (panels[0].widget);
1282     panel2 = PANEL (panels[1].widget);
1283 
1284     if (panels[0].type == view_listing && panels[1].type == view_listing
1285         && !mc_config_get_bool (mc_global.main_config, CONFIG_PANELS_SECTION, "simple_swap", FALSE))
1286     {
1287         WPanel panel;
1288 
1289 #define panelswap(x)                                                                               \
1290     panel.x = panel1->x;                                                                           \
1291     panel1->x = panel2->x;                                                                         \
1292     panel2->x = panel.x;
1293         // Change content and related stuff
1294         panelswap (dir);
1295         panelswap (active);
1296         panelswap (cwd_vpath);
1297         panelswap (lwd_vpath);
1298         panelswap (marked);
1299         panelswap (dirs_marked);
1300         panelswap (total);
1301         panelswap (top);
1302         panelswap (current);
1303         panelswap (is_panelized);
1304         panelswap (panelized_descr);
1305         panelswap (dir_stat);
1306 #undef panelswap
1307 
1308         panel1->quick_search.active = FALSE;
1309         panel2->quick_search.active = FALSE;
1310 
1311         if (current_panel == panel1)
1312             current_panel = panel2;
1313         else
1314             current_panel = panel1;
1315 
1316         // if sort options are different -> resort panels
1317         if (memcmp (&panel1->sort_info, &panel2->sort_info, sizeof (dir_sort_options_t)) != 0)
1318         {
1319             panel_re_sort (other_panel);
1320             panel_re_sort (current_panel);
1321         }
1322 
1323         if (widget_is_active (panels[0].widget))
1324             widget_select (panels[1].widget);
1325         else if (widget_is_active (panels[1].widget))
1326             widget_select (panels[0].widget);
1327     }
1328     else
1329     {
1330         WPanel *tmp_panel;
1331         WRect r;
1332         int tmp_type;
1333 
1334         tmp_panel = right_panel;
1335         right_panel = left_panel;
1336         left_panel = tmp_panel;
1337 
1338         if (panels[0].type == view_listing)
1339         {
1340             if (strcmp (panel1->name, get_nth_panel_name (0)) == 0)
1341             {
1342                 g_free (panel1->name);
1343                 panel1->name = g_strdup (get_nth_panel_name (1));
1344             }
1345         }
1346         if (panels[1].type == view_listing)
1347         {
1348             if (strcmp (panel2->name, get_nth_panel_name (1)) == 0)
1349             {
1350                 g_free (panel2->name);
1351                 panel2->name = g_strdup (get_nth_panel_name (0));
1352             }
1353         }
1354 
1355         r = panels[0].widget->rect;
1356         panels[0].widget->rect = panels[1].widget->rect;
1357         panels[1].widget->rect = r;
1358 
1359         tmp_widget = panels[0].widget;
1360         panels[0].widget = panels[1].widget;
1361         panels[1].widget = tmp_widget;
1362         tmp_type = panels[0].type;
1363         panels[0].type = panels[1].type;
1364         panels[1].type = tmp_type;
1365 
1366         // force update formats because of possible changed sizes
1367         if (panels[0].type == view_listing)
1368             set_panel_formats (PANEL (panels[0].widget));
1369         if (panels[1].type == view_listing)
1370             set_panel_formats (PANEL (panels[1].widget));
1371     }
1372 }
1373 
1374 /* --------------------------------------------------------------------------------------------- */
1375 
1376 panel_view_mode_t
1377 get_panel_type (int idx)
     /* [previous][next][first][last][top][bottom][index][help]  */
1378 {
1379     return panels[idx].type;
1380 }
1381 
1382 /* --------------------------------------------------------------------------------------------- */
1383 
1384 Widget *
1385 get_panel_widget (int idx)
     /* [previous][next][first][last][top][bottom][index][help]  */
1386 {
1387     return panels[idx].widget;
1388 }
1389 
1390 /* --------------------------------------------------------------------------------------------- */
1391 
1392 int
1393 get_current_index (void)
     /* [previous][next][first][last][top][bottom][index][help]  */
1394 {
1395     return (panels[0].widget == WIDGET (current_panel) ? 0 : 1);
1396 }
1397 
1398 /* --------------------------------------------------------------------------------------------- */
1399 
1400 int
1401 get_other_index (void)
     /* [previous][next][first][last][top][bottom][index][help]  */
1402 {
1403     return (get_current_index () == 0 ? 1 : 0);
1404 }
1405 
1406 /* --------------------------------------------------------------------------------------------- */
1407 
1408 WPanel *
1409 get_other_panel (void)
     /* [previous][next][first][last][top][bottom][index][help]  */
1410 {
1411     return PANEL (get_panel_widget (get_other_index ()));
1412 }
1413 
1414 /* --------------------------------------------------------------------------------------------- */
1415 /** Returns the view type for the current panel/view */
1416 
1417 panel_view_mode_t
1418 get_current_type (void)
     /* [previous][next][first][last][top][bottom][index][help]  */
1419 {
1420     return (panels[0].widget == WIDGET (current_panel) ? panels[0].type : panels[1].type);
1421 }
1422 
1423 /* --------------------------------------------------------------------------------------------- */
1424 /** Returns the view type of the unselected panel */
1425 
1426 panel_view_mode_t
1427 get_other_type (void)
     /* [previous][next][first][last][top][bottom][index][help]  */
1428 {
1429     return (panels[0].widget == WIDGET (current_panel) ? panels[1].type : panels[0].type);
1430 }
1431 
1432 /* --------------------------------------------------------------------------------------------- */
1433 /** Save current list_view widget directory into panel */
1434 
1435 void
1436 save_panel_dir (int idx)
     /* [previous][next][first][last][top][bottom][index][help]  */
1437 {
1438     panel_view_mode_t type;
1439 
1440     type = get_panel_type (idx);
1441     if (type == view_listing)
1442     {
1443         WPanel *p;
1444 
1445         p = PANEL (get_panel_widget (idx));
1446         if (p != NULL)
1447         {
1448             g_free (panels[idx].last_saved_dir);  // last path no needed
1449             // Because path can be nonlocal
1450             panels[idx].last_saved_dir = g_strdup (vfs_path_as_str (p->cwd_vpath));
1451         }
1452     }
1453 }
1454 
1455 /* --------------------------------------------------------------------------------------------- */
1456 /** Return working dir, if it's view_listing - cwd,
1457    but for other types - last_saved_dir */
1458 
1459 char *
1460 get_panel_dir_for (const WPanel *widget)
     /* [previous][next][first][last][top][bottom][index][help]  */
1461 {
1462     int i;
1463 
1464     for (i = 0; i < MAX_VIEWS; i++)
1465         if (PANEL (get_panel_widget (i)) == widget)
1466             break;
1467 
1468     if (i >= MAX_VIEWS)
1469         return g_strdup (".");
1470 
1471     if (get_panel_type (i) == view_listing)
1472     {
1473         vfs_path_t *cwd_vpath;
1474 
1475         cwd_vpath = PANEL (get_panel_widget (i))->cwd_vpath;
1476         return g_strdup (vfs_path_as_str (cwd_vpath));
1477     }
1478 
1479     return g_strdup (panels[i].last_saved_dir);
1480 }
1481 
1482 /* --------------------------------------------------------------------------------------------- */
1483 
1484 #ifdef ENABLE_SUBSHELL
1485 gboolean
1486 do_load_prompt (void)
     /* [previous][next][first][last][top][bottom][index][help]  */
1487 {
1488     gboolean ret = FALSE;
1489 
1490     if (!read_subshell_prompt ())
1491         return ret;
1492 
1493     // Don't actually change the prompt if it's invisible
1494     if (top_dlg != NULL && DIALOG (top_dlg->data) == filemanager && command_prompt)
1495     {
1496         setup_cmdline ();
1497 
1498         /* since the prompt has changed, and we are called from one of the
1499          * tty_get_event channels, the prompt updating does not take place
1500          * automatically: force a cursor update and a screen refresh
1501          */
1502         widget_update_cursor (WIDGET (filemanager));
1503         mc_refresh ();
1504         ret = TRUE;
1505     }
1506     update_subshell_prompt = TRUE;
1507     return ret;
1508 }
1509 
1510 /* --------------------------------------------------------------------------------------------- */
1511 
1512 int
1513 load_prompt (int fd, void *unused)
     /* [previous][next][first][last][top][bottom][index][help]  */
1514 {
1515     (void) fd;
1516     (void) unused;
1517 
1518     if (should_read_new_subshell_prompt)
1519         do_load_prompt ();
1520     else
1521         flush_subshell (0, QUIETLY);
1522 
1523     return 0;
1524 }
1525 #endif
1526 
1527 /* --------------------------------------------------------------------------------------------- */
1528 
1529 void
1530 title_path_prepare (char **path, char **login)
     /* [previous][next][first][last][top][bottom][index][help]  */
1531 {
1532     char host[BUF_TINY];
1533     struct passwd *pw = NULL;
1534     int res = 0;
1535 
1536     *path =
1537         vfs_path_to_str_flags (current_panel->cwd_vpath, 0, VPF_STRIP_HOME | VPF_STRIP_PASSWORD);
1538 
1539     res = gethostname (host, sizeof (host));
1540     if (res != 0)
1541         host[0] = '\0';
1542     else
1543         host[sizeof (host) - 1] = '\0';
1544 
1545     pw = getpwuid (getuid ());
1546     if (pw != NULL)
1547         *login = g_strdup_printf ("%s@%s", pw->pw_name, host);
1548     else
1549         *login = g_strdup (host);
1550 }
1551 
1552 /* --------------------------------------------------------------------------------------------- */
1553 
1554 /** Show current directory in the xterm title */
1555 void
1556 update_xterm_title_path (void)
     /* [previous][next][first][last][top][bottom][index][help]  */
1557 {
1558     if (mc_global.tty.xterm_flag && xterm_title)
1559     {
1560         char *p;
1561         char *path;
1562         char *login;
1563 
1564         title_path_prepare (&path, &login);
1565 
1566         p = g_strdup_printf ("mc [%s]:%s", login, path);
1567         g_free (login);
1568         g_free (path);
1569 
1570         fprintf (stdout, ESC_STR "]0;%s" ESC_STR "\\", str_term_form (p));
1571         g_free (p);
1572 
1573         if (!mc_global.tty.alternate_plus_minus)
1574             numeric_keypad_mode ();
1575         (void) fflush (stdout);
1576     }
1577 }
1578 
1579 /* --------------------------------------------------------------------------------------------- */
1580 
1581 /** Tell the current directory to the terminal so it can open new tabs there */
1582 void
1583 update_terminal_cwd (void)
     /* [previous][next][first][last][top][bottom][index][help]  */
1584 {
1585     if (mc_global.tty.xterm_flag && vfs_current_is_local ())
1586     {
1587         const gchar *host;
1588         char *path, *path_uri;
1589 
1590         host = g_get_host_name ();
1591         path = vfs_path_to_str_flags (current_panel->cwd_vpath, 0, VPF_NONE);
1592         path_uri = g_uri_escape_string (path, "/", FALSE);
1593 
1594         fprintf (stdout, ESC_STR "]7;file://%s%s" ESC_STR "\\", host, path_uri);
1595         (void) fflush (stdout);
1596 
1597         g_free (path_uri);
1598         g_free (path);
1599     }
1600 }
1601 
1602 /* --------------------------------------------------------------------------------------------- */

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