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 
 978     if (!command_prompt)
 979         return;
 980 
 981 #ifdef ENABLE_SUBSHELL
 982     if (mc_global.tty.use_subshell)
 983     {
 984         // Workaround: avoid crash on FreeBSD (see ticket #4213 for details)
 985         if (subshell_prompt != NULL)
 986         {
 987             g_free (mc_prompt);
 988             mc_prompt = g_strndup (subshell_prompt->str, subshell_prompt->len);
 989         }
 990 
 991         (void) strip_ctrl_codes (mc_prompt);
 992     }
 993 #endif
 994 
 995     prompt_width = str_term_width1 (mc_prompt);
 996 
 997     // Check for prompts too big
 998     if (r->cols > 8 && prompt_width > r->cols - 8)
 999     {
1000         int prompt_len;
1001 
1002         prompt_width = r->cols - 8;
1003         prompt_len = str_offset_to_pos (mc_prompt, prompt_width);
1004         mc_prompt[prompt_len] = '\0';
1005     }
1006 
1007     y = r->lines - 1 - (mc_global.keybar_visible ? 1 : 0);
1008 
1009     widget_set_size (WIDGET (the_prompt), y, r->x, 1, prompt_width);
1010     label_set_text (the_prompt, mc_prompt);
1011     widget_set_size (WIDGET (cmdline), y, r->x + prompt_width, 1, r->cols - prompt_width);
1012 
1013     widget_show (WIDGET (the_prompt));
1014     widget_show (WIDGET (cmdline));
1015 }
1016 
1017 /* --------------------------------------------------------------------------------------------- */
1018 
1019 void
1020 use_dash (gboolean flag)
     /* [previous][next][first][last][top][bottom][index][help]  */
1021 {
1022     if (flag)
1023         ok_to_refresh++;
1024     else
1025         ok_to_refresh--;
1026 }
1027 
1028 /* --------------------------------------------------------------------------------------------- */
1029 
1030 void
1031 set_hintbar (const char *str)
     /* [previous][next][first][last][top][bottom][index][help]  */
1032 {
1033     label_set_text (the_hint, str);
1034     if (ok_to_refresh > 0)
1035         mc_refresh ();
1036 }
1037 
1038 /* --------------------------------------------------------------------------------------------- */
1039 
1040 void
1041 rotate_dash (gboolean show)
     /* [previous][next][first][last][top][bottom][index][help]  */
1042 {
1043     static gint64 timestamp = 0;
1044     // update with 10 FPS rate
1045     static const gint64 delay = G_USEC_PER_SEC / 10;
1046 
1047     const Widget *w = CONST_WIDGET (filemanager);
1048 
1049     if (!nice_rotating_dash || (ok_to_refresh <= 0))
1050         return;
1051 
1052     if (show && !mc_time_elapsed (&timestamp, delay))
1053         return;
1054 
1055     widget_gotoyx (w, menubar_visible ? 1 : 0, w->rect.cols - 1);
1056     tty_setcolor (NORMAL_COLOR);
1057 
1058     if (!show)
1059         tty_print_alt_char (ACS_URCORNER, FALSE);
1060     else
1061     {
1062         static const char rotating_dash[4] MC_NONSTRING = "|/-\\";
1063         static size_t pos = 0;
1064 
1065         tty_print_char (rotating_dash[pos]);
1066         pos = (pos + 1) % sizeof (rotating_dash);
1067     }
1068 
1069     mc_refresh ();
1070 }
1071 
1072 /* --------------------------------------------------------------------------------------------- */
1073 
1074 const char *
1075 get_nth_panel_name (int num)
     /* [previous][next][first][last][top][bottom][index][help]  */
1076 {
1077     if (num == 0)
1078         return "New Left Panel";
1079 
1080     if (num == 1)
1081         return "New Right Panel";
1082 
1083     {
1084         static char buffer[BUF_SMALL];
1085 
1086         g_snprintf (buffer, sizeof (buffer), "%ith Panel", num);
1087         return buffer;
1088     }
1089 }
1090 
1091 /* --------------------------------------------------------------------------------------------- */
1092 /* I wonder if I should start to use the folding mode than Dugan uses */
1093 /*                                                                     */
1094 /* This is the centralized managing of the panel display types         */
1095 /* This routine takes care of destroying and creating new widgets      */
1096 /* Please note that it could manage MAX_VIEWS, not just left and right */
1097 /* Currently nothing in the code takes advantage of this and has hard- */
1098 /* coded values for two panels only                                    */
1099 
1100 /* Set the num-th panel to the view type: type */
1101 /* This routine also keeps at least one WPanel object in the screen */
1102 /* since a lot of routines depend on the current_panel variable */
1103 
1104 void
1105 create_panel (int num, panel_view_mode_t type)
     /* [previous][next][first][last][top][bottom][index][help]  */
1106 {
1107     WRect r = { 0, 0, 0, 0 };
1108     unsigned int the_other = 0;  // Index to the other panel
1109     Widget *new_widget = NULL, *old_widget = NULL;
1110     panel_view_mode_t old_type = view_listing;
1111 
1112     if (num >= MAX_VIEWS)
1113     {
1114         fprintf (stderr, "Cannot allocate more that %d views\n", MAX_VIEWS);
1115         abort ();
1116     }
1117     // Check that we will have a WPanel * at least
1118     if (type != view_listing)
1119     {
1120         the_other = num == 0 ? 1 : 0;
1121 
1122         if (panels[the_other].type != view_listing)
1123             return;
1124     }
1125 
1126     // Get rid of it
1127     if (panels[num].widget != NULL)
1128     {
1129         Widget *w = panels[num].widget;
1130         WPanel *panel = PANEL (w);
1131 
1132         r = w->rect;
1133         old_widget = w;
1134         old_type = panels[num].type;
1135 
1136         if (old_type == view_listing && panel->frame_size == frame_full && type != view_listing)
1137         {
1138             int md_cols = CONST_WIDGET (filemanager)->rect.cols;
1139 
1140             if (panels_layout.horizontal_split)
1141             {
1142                 r.cols = md_cols;
1143                 r.x = 0;
1144             }
1145             else
1146             {
1147                 r.cols = md_cols - panels_layout.left_panel_size;
1148                 if (num == 1)
1149                     r.x = panels_layout.left_panel_size;
1150             }
1151         }
1152     }
1153 
1154     // Restoring saved path from panels.ini for nonlist panel
1155     // when it's first creation (for example view_info)
1156     if (old_widget == NULL && type != view_listing)
1157         panels[num].last_saved_dir = vfs_get_cwd ();
1158 
1159     switch (type)
1160     {
1161     case view_nothing:
1162     case view_listing:
1163     {
1164         gboolean last_was_panel;
1165 
1166         last_was_panel = old_widget != NULL && get_panel_type (num) != view_listing;
1167         new_widget = restore_into_right_dir_panel (num, last_was_panel, &r);
1168         break;
1169     }
1170 
1171     case view_info:
1172         new_widget = WIDGET (info_new (&r));
1173         break;
1174 
1175     case view_tree:
1176         new_widget = WIDGET (tree_new (&r, TRUE));
1177         break;
1178 
1179     case view_quick:
1180     {
1181         WPanel *the_other_panel;
1182         const char *file_name = "";
1183 
1184         new_widget = WIDGET (mcview_new (&r, TRUE));
1185         the_other_panel = PANEL (panels[the_other].widget);
1186         if (the_other_panel != NULL)
1187         {
1188             const file_entry_t *fe;
1189 
1190             fe = panel_current_entry (the_other_panel);
1191             if (fe != NULL)
1192                 file_name = fe->fname->str;
1193         }
1194 
1195         mcview_load ((WView *) new_widget, 0, file_name, 0, 0, 0);
1196         break;
1197     }
1198 
1199     default:
1200         break;
1201     }
1202 
1203     if (type != view_listing)
1204         // Must save dir, for restoring after change type to
1205         // view_listing
1206         save_panel_dir (num);
1207 
1208     panels[num].type = type;
1209     panels[num].widget = new_widget;
1210 
1211     // We use replace to keep the circular list of the dialog in the
1212     // same state.  Maybe we could just kill it and then replace it
1213     if (old_widget != NULL)
1214     {
1215         if (old_type == view_listing)
1216         {
1217             /* save and write directory history of panel
1218              * ... and other histories of filemanager  */
1219             dlg_save_history (filemanager);
1220         }
1221 
1222         widget_replace (old_widget, new_widget);
1223     }
1224 
1225     if (type == view_listing)
1226     {
1227         WPanel *panel = PANEL (new_widget);
1228 
1229         // if existing panel changed type to view_listing, then load history
1230         if (old_widget != NULL)
1231         {
1232             ev_history_load_save_t event_data = { NULL, new_widget };
1233 
1234             mc_event_raise (filemanager->event_group, MCEVENT_HISTORY_LOAD, &event_data);
1235         }
1236 
1237         if (num == 0)
1238             left_panel = panel;
1239         else
1240             right_panel = panel;
1241 
1242         // forced update format after set new sizes
1243         set_panel_formats (panel);
1244     }
1245 
1246     if (type == view_tree)
1247         the_tree = (WTree *) new_widget;
1248 
1249     /* Prevent current_panel's value from becoming invalid.
1250      * It's just a quick hack to prevent segfaults. Comment out and
1251      * try following:
1252      * - select left panel
1253      * - invoke menu left/tree
1254      * - as long as you stay in the left panel almost everything that uses
1255      *   current_panel causes segfault, e.g. C-Enter, C-x c, ...
1256      */
1257     if ((type != view_listing) && (current_panel == PANEL (old_widget)))
1258         current_panel = num == 0 ? right_panel : left_panel;
1259 
1260     g_free (old_widget);
1261 }
1262 
1263 /* --------------------------------------------------------------------------------------------- */
1264 /** This routine is deeply sticked to the two panels idea.
1265    What should it do in more panels. ANSWER - don't use it
1266    in any multiple panels environment. */
1267 
1268 void
1269 swap_panels (void)
     /* [previous][next][first][last][top][bottom][index][help]  */
1270 {
1271     WPanel *panel1, *panel2;
1272     Widget *tmp_widget;
1273 
1274     panel1 = PANEL (panels[0].widget);
1275     panel2 = PANEL (panels[1].widget);
1276 
1277     if (panels[0].type == view_listing && panels[1].type == view_listing
1278         && !mc_config_get_bool (mc_global.main_config, CONFIG_PANELS_SECTION, "simple_swap", FALSE))
1279     {
1280         WPanel panel;
1281 
1282 #define panelswap(x)                                                                               \
1283     panel.x = panel1->x;                                                                           \
1284     panel1->x = panel2->x;                                                                         \
1285     panel2->x = panel.x;
1286         // Change content and related stuff
1287         panelswap (dir);
1288         panelswap (active);
1289         panelswap (cwd_vpath);
1290         panelswap (lwd_vpath);
1291         panelswap (marked);
1292         panelswap (dirs_marked);
1293         panelswap (total);
1294         panelswap (top);
1295         panelswap (current);
1296         panelswap (is_panelized);
1297         panelswap (panelized_descr);
1298         panelswap (dir_stat);
1299 #undef panelswap
1300 
1301         panel1->quick_search.active = FALSE;
1302         panel2->quick_search.active = FALSE;
1303 
1304         if (current_panel == panel1)
1305             current_panel = panel2;
1306         else
1307             current_panel = panel1;
1308 
1309         // if sort options are different -> resort panels
1310         if (memcmp (&panel1->sort_info, &panel2->sort_info, sizeof (dir_sort_options_t)) != 0)
1311         {
1312             panel_re_sort (other_panel);
1313             panel_re_sort (current_panel);
1314         }
1315 
1316         if (widget_is_active (panels[0].widget))
1317             widget_select (panels[1].widget);
1318         else if (widget_is_active (panels[1].widget))
1319             widget_select (panels[0].widget);
1320     }
1321     else
1322     {
1323         WPanel *tmp_panel;
1324         WRect r;
1325         int tmp_type;
1326 
1327         tmp_panel = right_panel;
1328         right_panel = left_panel;
1329         left_panel = tmp_panel;
1330 
1331         if (panels[0].type == view_listing)
1332         {
1333             if (strcmp (panel1->name, get_nth_panel_name (0)) == 0)
1334             {
1335                 g_free (panel1->name);
1336                 panel1->name = g_strdup (get_nth_panel_name (1));
1337             }
1338         }
1339         if (panels[1].type == view_listing)
1340         {
1341             if (strcmp (panel2->name, get_nth_panel_name (1)) == 0)
1342             {
1343                 g_free (panel2->name);
1344                 panel2->name = g_strdup (get_nth_panel_name (0));
1345             }
1346         }
1347 
1348         r = panels[0].widget->rect;
1349         panels[0].widget->rect = panels[1].widget->rect;
1350         panels[1].widget->rect = r;
1351 
1352         tmp_widget = panels[0].widget;
1353         panels[0].widget = panels[1].widget;
1354         panels[1].widget = tmp_widget;
1355         tmp_type = panels[0].type;
1356         panels[0].type = panels[1].type;
1357         panels[1].type = tmp_type;
1358 
1359         // force update formats because of possible changed sizes
1360         if (panels[0].type == view_listing)
1361             set_panel_formats (PANEL (panels[0].widget));
1362         if (panels[1].type == view_listing)
1363             set_panel_formats (PANEL (panels[1].widget));
1364     }
1365 }
1366 
1367 /* --------------------------------------------------------------------------------------------- */
1368 
1369 panel_view_mode_t
1370 get_panel_type (int idx)
     /* [previous][next][first][last][top][bottom][index][help]  */
1371 {
1372     return panels[idx].type;
1373 }
1374 
1375 /* --------------------------------------------------------------------------------------------- */
1376 
1377 Widget *
1378 get_panel_widget (int idx)
     /* [previous][next][first][last][top][bottom][index][help]  */
1379 {
1380     return panels[idx].widget;
1381 }
1382 
1383 /* --------------------------------------------------------------------------------------------- */
1384 
1385 int
1386 get_current_index (void)
     /* [previous][next][first][last][top][bottom][index][help]  */
1387 {
1388     return (panels[0].widget == WIDGET (current_panel) ? 0 : 1);
1389 }
1390 
1391 /* --------------------------------------------------------------------------------------------- */
1392 
1393 int
1394 get_other_index (void)
     /* [previous][next][first][last][top][bottom][index][help]  */
1395 {
1396     return (get_current_index () == 0 ? 1 : 0);
1397 }
1398 
1399 /* --------------------------------------------------------------------------------------------- */
1400 
1401 WPanel *
1402 get_other_panel (void)
     /* [previous][next][first][last][top][bottom][index][help]  */
1403 {
1404     return PANEL (get_panel_widget (get_other_index ()));
1405 }
1406 
1407 /* --------------------------------------------------------------------------------------------- */
1408 /** Returns the view type for the current panel/view */
1409 
1410 panel_view_mode_t
1411 get_current_type (void)
     /* [previous][next][first][last][top][bottom][index][help]  */
1412 {
1413     return (panels[0].widget == WIDGET (current_panel) ? panels[0].type : panels[1].type);
1414 }
1415 
1416 /* --------------------------------------------------------------------------------------------- */
1417 /** Returns the view type of the unselected panel */
1418 
1419 panel_view_mode_t
1420 get_other_type (void)
     /* [previous][next][first][last][top][bottom][index][help]  */
1421 {
1422     return (panels[0].widget == WIDGET (current_panel) ? panels[1].type : panels[0].type);
1423 }
1424 
1425 /* --------------------------------------------------------------------------------------------- */
1426 /** Save current list_view widget directory into panel */
1427 
1428 void
1429 save_panel_dir (int idx)
     /* [previous][next][first][last][top][bottom][index][help]  */
1430 {
1431     panel_view_mode_t type;
1432 
1433     type = get_panel_type (idx);
1434     if (type == view_listing)
1435     {
1436         WPanel *p;
1437 
1438         p = PANEL (get_panel_widget (idx));
1439         if (p != NULL)
1440         {
1441             g_free (panels[idx].last_saved_dir);  // last path no needed
1442             // Because path can be nonlocal
1443             panels[idx].last_saved_dir = g_strdup (vfs_path_as_str (p->cwd_vpath));
1444         }
1445     }
1446 }
1447 
1448 /* --------------------------------------------------------------------------------------------- */
1449 /** Return working dir, if it's view_listing - cwd,
1450    but for other types - last_saved_dir */
1451 
1452 char *
1453 get_panel_dir_for (const WPanel *widget)
     /* [previous][next][first][last][top][bottom][index][help]  */
1454 {
1455     int i;
1456 
1457     for (i = 0; i < MAX_VIEWS; i++)
1458         if (PANEL (get_panel_widget (i)) == widget)
1459             break;
1460 
1461     if (i >= MAX_VIEWS)
1462         return g_strdup (".");
1463 
1464     if (get_panel_type (i) == view_listing)
1465     {
1466         vfs_path_t *cwd_vpath;
1467 
1468         cwd_vpath = PANEL (get_panel_widget (i))->cwd_vpath;
1469         return g_strdup (vfs_path_as_str (cwd_vpath));
1470     }
1471 
1472     return g_strdup (panels[i].last_saved_dir);
1473 }
1474 
1475 /* --------------------------------------------------------------------------------------------- */
1476 
1477 #ifdef ENABLE_SUBSHELL
1478 gboolean
1479 do_load_prompt (void)
     /* [previous][next][first][last][top][bottom][index][help]  */
1480 {
1481     gboolean ret = FALSE;
1482 
1483     if (!read_subshell_prompt ())
1484         return ret;
1485 
1486     // Don't actually change the prompt if it's invisible
1487     if (top_dlg != NULL && DIALOG (top_dlg->data) == filemanager && command_prompt)
1488     {
1489         setup_cmdline ();
1490 
1491         /* since the prompt has changed, and we are called from one of the
1492          * tty_get_event channels, the prompt updating does not take place
1493          * automatically: force a cursor update and a screen refresh
1494          */
1495         widget_update_cursor (WIDGET (filemanager));
1496         mc_refresh ();
1497         ret = TRUE;
1498     }
1499     update_subshell_prompt = TRUE;
1500     return ret;
1501 }
1502 
1503 /* --------------------------------------------------------------------------------------------- */
1504 
1505 int
1506 load_prompt (int fd, void *unused)
     /* [previous][next][first][last][top][bottom][index][help]  */
1507 {
1508     (void) fd;
1509     (void) unused;
1510 
1511     if (should_read_new_subshell_prompt)
1512         do_load_prompt ();
1513     else
1514         flush_subshell (0, QUIETLY);
1515 
1516     return 0;
1517 }
1518 #endif
1519 
1520 /* --------------------------------------------------------------------------------------------- */
1521 
1522 void
1523 title_path_prepare (char **path, char **login)
     /* [previous][next][first][last][top][bottom][index][help]  */
1524 {
1525     char host[BUF_TINY];
1526     struct passwd *pw = NULL;
1527     int res = 0;
1528 
1529     *path =
1530         vfs_path_to_str_flags (current_panel->cwd_vpath, 0, VPF_STRIP_HOME | VPF_STRIP_PASSWORD);
1531 
1532     res = gethostname (host, sizeof (host));
1533     if (res != 0)
1534         host[0] = '\0';
1535     else
1536         host[sizeof (host) - 1] = '\0';
1537 
1538     pw = getpwuid (getuid ());
1539     if (pw != NULL)
1540         *login = g_strdup_printf ("%s@%s", pw->pw_name, host);
1541     else
1542         *login = g_strdup (host);
1543 }
1544 
1545 /* --------------------------------------------------------------------------------------------- */
1546 
1547 /** Show current directory in the xterm title */
1548 void
1549 update_xterm_title_path (void)
     /* [previous][next][first][last][top][bottom][index][help]  */
1550 {
1551     if (mc_global.tty.xterm_flag && xterm_title)
1552     {
1553         char *p;
1554         char *path;
1555         char *login;
1556 
1557         title_path_prepare (&path, &login);
1558 
1559         p = g_strdup_printf ("mc [%s]:%s", login, path);
1560         g_free (login);
1561         g_free (path);
1562 
1563         fprintf (stdout, ESC_STR "]0;%s" ESC_STR "\\", str_term_form (p));
1564         g_free (p);
1565 
1566         if (!mc_global.tty.alternate_plus_minus)
1567             numeric_keypad_mode ();
1568         (void) fflush (stdout);
1569     }
1570 }
1571 
1572 /* --------------------------------------------------------------------------------------------- */
1573 
1574 /** Tell the current directory to the terminal so it can open new tabs there */
1575 void
1576 update_terminal_cwd (void)
     /* [previous][next][first][last][top][bottom][index][help]  */
1577 {
1578     if (mc_global.tty.xterm_flag && vfs_current_is_local ())
1579     {
1580         const gchar *host;
1581         char *path, *path_uri;
1582 
1583         host = g_get_host_name ();
1584         path = vfs_path_to_str_flags (current_panel->cwd_vpath, 0, VPF_NONE);
1585         path_uri = g_uri_escape_string (path, "/", FALSE);
1586 
1587         fprintf (stdout, ESC_STR "]7;file://%s%s" ESC_STR "\\", host, path_uri);
1588         (void) fflush (stdout);
1589 
1590         g_free (path_uri);
1591         g_free (path);
1592     }
1593 }
1594 
1595 /* --------------------------------------------------------------------------------------------- */

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