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

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