* direntry.c: Use g_strlcpy instead strncpy for fix buffer overrun
[midnight-commander.git] / src / layout.c
blobc1d19a254c9258c1daee6c98ee1d940fa90eed0f
1 /* Panel layout module for the Midnight Commander
2 Copyright (C) 1995 the Free Software Foundation
4 Written: 1995 Janne Kukonlehto
5 1995 Miguel de Icaza
7 This program is free software; you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation; either version 2 of the License, or
10 (at your option) any later version.
12 This program is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License for more details.
17 You should have received a copy of the GNU General Public License
18 along with this program; if not, write to the Free Software
19 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
22 #include <config.h>
23 #include <stdarg.h>
24 #include <stdio.h>
25 #include <string.h>
26 #include <sys/types.h>
27 #include <sys/stat.h>
28 #if HAVE_TERMIOS_H
29 # include <termios.h>
30 #endif
32 * If TIOCGWINSZ supported, make it available here, because window-
33 * resizing code depends on it...
35 #ifdef HAVE_SYS_IOCTL_H
36 # include <sys/ioctl.h>
37 #endif
38 #ifdef HAVE_UNISTD_H
39 # include <unistd.h>
40 #endif
41 #include <signal.h>
43 #include "global.h"
44 #include "tty.h" /* COLS */
45 #include "win.h"
46 #include "color.h"
47 #include "key.h"
48 #include "dialog.h"
49 #include "widget.h"
50 #include "command.h"
51 #include "profile.h" /* For sync_profiles() */
52 #include "mouse.h"
53 #define WANT_WIDGETS
54 #include "main.h"
55 #include "subshell.h" /* For use_subshell and resize_subshell() */
56 #include "tree.h"
57 #include "menu.h"
59 /* Needed for the extern declarations of integer parameters */
60 #include "dir.h"
61 #include "panel.h" /* The Panel widget */
62 #include "cons.saver.h"
63 #include "layout.h"
64 #include "info.h" /* The Info widget */
65 #include "view.h" /* The view widget */
67 #define WANT_WIDGETS
68 #include "setup.h" /* For save_setup() */
70 /* Controls the display of the rotating dash on the verbose mode */
71 int nice_rotating_dash = 1;
73 /* If set, then we have to call the layout_change routine from main */
74 static int layout_do_change = 0;
76 /* Set if the panels are split horizontally */
77 int horizontal_split = 0;
79 /* Set if the window has changed it's size */
80 int winch_flag = 0;
82 /* Set if the split is the same */
83 int equal_split = 1;
85 /* First panel size if the panel are not split equally */
86 int first_panel_size = 0;
88 /* The number of output lines shown (if available) */
89 int output_lines = 0;
91 /* Set if the command prompt is to be displayed */
92 int command_prompt = 1;
94 /* Set if the nice and useful keybar is visible */
95 int keybar_visible = 1;
97 /* Set if the nice message (hint) bar is visible */
98 int message_visible = 1;
100 /* Set to show current working dir in xterm window title */
101 int xterm_title = 1;
103 /* The starting line for the output of the subprogram */
104 int output_start_y = 0;
106 /* The maximum number of views managed by the set_display_type routine */
107 /* Must be at least two (for current and other). Please note that until */
108 /* Janne gets around this, we will only manage two of them :-) */
109 #define MAX_VIEWS 2
111 static struct {
112 int type;
113 Widget *widget;
114 } panels [MAX_VIEWS];
116 /* These variables are used to avoid updating the information unless */
117 /* we need it */
118 static int old_first_panel_size;
119 static int old_horizontal_split;
120 static int old_output_lines;
122 /* Internal variables */
123 static int _horizontal_split;
124 static int _equal_split;
125 static int _first_panel_size;
126 static int _menubar_visible;
127 static int _output_lines;
128 static int _command_prompt;
129 static int _keybar_visible;
130 static int _message_visible;
131 static int _xterm_title;
132 static int _permission_mode;
133 static int _filetype_mode;
135 static int height;
137 /* Width 12 for a wee Quick (Hex) View */
138 #define MINWIDTH 12
139 #define MINHEIGHT 5
141 #define BY 12
143 #define B_2LEFT B_USER
144 #define B_2RIGHT (B_USER + 1)
145 #define B_PLUS (B_USER + 2)
146 #define B_MINUS (B_USER + 3)
148 static Dlg_head *layout_dlg;
150 static const char *s_split_direction [2] = {
151 N_("&Vertical"),
152 N_("&Horizontal")
155 static WRadio *radio_widget;
157 static struct {
158 const char *text;
159 int *variable;
160 WCheck *widget;
161 } check_options [] = {
162 { N_("&Xterm window title"), &xterm_title, 0 },
163 { N_("h&Intbar visible"), &message_visible, 0 },
164 { N_("&Keybar visible"), &keybar_visible, 0 },
165 { N_("command &Prompt"), &command_prompt, 0 },
166 { N_("show &Mini status"), &show_mini_info, 0 },
167 { N_("menu&Bar visible"), &menubar_visible, 0 },
168 { N_("&Equal split"), &equal_split, 0 },
169 { N_("pe&Rmissions"), &permission_mode, 0 },
170 { N_("&File types"), &filetype_mode, 0 },
171 { 0, 0, 0 }
174 static int first_width, second_width;
175 static char *output_lines_label;
177 static WButton *bleft_widget, *bright_widget;
179 /* Declarations for static functions */
180 static void low_level_change_screen_size (void);
182 static void _check_split (void)
184 if (_horizontal_split){
185 if (_equal_split)
186 _first_panel_size = height / 2;
187 else if (_first_panel_size < MINHEIGHT)
188 _first_panel_size = MINHEIGHT;
189 else if (_first_panel_size > height - MINHEIGHT)
190 _first_panel_size = height - MINHEIGHT;
191 } else {
192 if (_equal_split)
193 _first_panel_size = COLS / 2;
194 else if (_first_panel_size < MINWIDTH)
195 _first_panel_size = MINWIDTH;
196 else if (_first_panel_size > COLS - MINWIDTH)
197 _first_panel_size = COLS - MINWIDTH;
201 static void update_split (void)
203 /* Check split has to be done before testing if it changed, since
204 it can change due to calling _check_split() as well*/
205 _check_split ();
207 /* To avoid setting the cursor to the wrong place */
208 if ((old_first_panel_size == _first_panel_size) &&
209 (old_horizontal_split == _horizontal_split)){
210 return;
213 old_first_panel_size = _first_panel_size;
214 old_horizontal_split = _horizontal_split;
216 attrset (COLOR_NORMAL);
217 dlg_move (layout_dlg, 6, 6);
218 printw ("%03d", _first_panel_size);
219 dlg_move (layout_dlg, 6, 18);
220 if (_horizontal_split)
221 printw ("%03d", height - _first_panel_size);
222 else
223 printw ("%03d", COLS - _first_panel_size);
226 static int b2left_cback (int action)
228 if (_equal_split){
229 /* Turn equal split off */
230 _equal_split = 0;
231 check_options [6].widget->state = check_options [6].widget->state & ~C_BOOL;
232 dlg_select_widget (layout_dlg, check_options [6].widget);
233 dlg_select_widget (layout_dlg, bleft_widget);
235 _first_panel_size++;
236 return 0;
239 static int b2right_cback (int action)
241 if (_equal_split){
242 /* Turn equal split off */
243 _equal_split = 0;
244 check_options [6].widget->state = check_options [6].widget->state & ~C_BOOL;
245 dlg_select_widget (layout_dlg, check_options [6].widget);
246 dlg_select_widget (layout_dlg, bright_widget);
248 _first_panel_size--;
249 return 0;
252 static int bplus_cback (int action)
254 if (_output_lines < 99)
255 _output_lines++;
256 return 0;
259 static int bminus_cback (int action)
261 if (_output_lines > 0)
262 _output_lines--;
263 return 0;
266 static cb_ret_t
267 layout_callback (struct Dlg_head *h, dlg_msg_t msg, int parm)
269 switch (msg) {
270 case DLG_DRAW:
271 /*When repainting the whole dialog (e.g. with C-l) we have to
272 update everything*/
273 common_dialog_repaint (h);
275 old_first_panel_size = -1;
276 old_horizontal_split = -1;
277 old_output_lines = -1;
279 attrset (COLOR_HOT_NORMAL);
280 update_split ();
281 dlg_move (h, 6, 13);
282 addch ('=');
283 if (console_flag){
284 if (old_output_lines != _output_lines){
285 old_output_lines = _output_lines;
286 attrset (COLOR_NORMAL);
287 dlg_move (h, 9, 16 + first_width);
288 addstr (output_lines_label);
289 dlg_move (h, 9, 10 + first_width);
290 printw ("%02d", _output_lines);
293 return MSG_HANDLED;
295 case DLG_POST_KEY:
296 _filetype_mode = check_options [8].widget->state & C_BOOL;
297 _permission_mode = check_options [7].widget->state & C_BOOL;
298 _equal_split = check_options [6].widget->state & C_BOOL;
299 _menubar_visible = check_options [5].widget->state & C_BOOL;
300 _command_prompt = check_options [4].widget->state & C_BOOL;
301 _keybar_visible = check_options [2].widget->state & C_BOOL;
302 _message_visible = check_options [1].widget->state & C_BOOL;
303 _xterm_title = check_options [0].widget->state & C_BOOL;
304 if (console_flag){
305 int minimum;
306 if (_output_lines < 0)
307 _output_lines = 0;
308 height = LINES - _keybar_visible - _command_prompt -
309 _menubar_visible - _output_lines - _message_visible;
310 minimum = MINHEIGHT * (1 + _horizontal_split);
311 if (height < minimum){
312 _output_lines -= minimum - height;
313 height = minimum;
315 } else {
316 height = LINES - _keybar_visible - _command_prompt -
317 _menubar_visible - _output_lines - _message_visible;
319 if (_horizontal_split != radio_widget->sel){
320 _horizontal_split = radio_widget->sel;
321 if (_horizontal_split)
322 _first_panel_size = height / 2;
323 else
324 _first_panel_size = COLS / 2;
326 update_split ();
327 if (console_flag){
328 if (old_output_lines != _output_lines){
329 old_output_lines = _output_lines;
330 attrset (COLOR_NORMAL);
331 dlg_move (h, 9, 10 + first_width);
332 printw ("%02d", _output_lines);
335 return MSG_HANDLED;
337 default:
338 return default_dlg_callback (h, msg, parm);
342 static void
343 init_layout (void)
345 static int i18n_layt_flag = 0;
346 static int b1, b2, b3;
347 int i = sizeof (s_split_direction) / sizeof (char *);
348 char *ok_button = _("&OK");
349 char *cancel_button = _("&Cancel");
350 char *save_button = _("&Save");
351 static char *title1, *title2, *title3;
353 if (!i18n_layt_flag) {
354 register int l1;
356 first_width = 19; /* length of line with '<' '>' buttons */
358 title1 = _(" Panel split ");
359 title2 = _(" Highlight... ");
360 title3 = _(" Other options ");
361 output_lines_label = _("output lines");
363 while (i--) {
364 s_split_direction[i] = _(s_split_direction[i]);
365 l1 = strlen (s_split_direction[i]) + 7;
366 if (l1 > first_width)
367 first_width = l1;
370 for (i = 0; i <= 8; i++) {
371 check_options[i].text = _(check_options[i].text);
372 l1 = strlen (check_options[i].text) + 7;
373 if (l1 > first_width)
374 first_width = l1;
377 l1 = strlen (title1) + 1;
378 if (l1 > first_width)
379 first_width = l1;
381 l1 = strlen (title2) + 1;
382 if (l1 > first_width)
383 first_width = l1;
386 second_width = strlen (title3) + 1;
387 for (i = 0; i < 6; i++) {
388 check_options[i].text = _(check_options[i].text);
389 l1 = strlen (check_options[i].text) + 7;
390 if (l1 > second_width)
391 second_width = l1;
393 if (console_flag) {
394 l1 = strlen (output_lines_label) + 13;
395 if (l1 > second_width)
396 second_width = l1;
400 * alex@bcs.zp.ua:
401 * To be completely correct, one need to check if the title
402 * does not exceed dialog length and total length of 3 buttons
403 * allows their placement in one row. But assuming this dialog
404 * is wide enough, I don't include such a tests.
406 * Now the last thing to do - properly space buttons...
408 l1 = 11 + strlen (ok_button) /* 14 - all brackets and inner space */
409 +strlen (save_button) /* notice: it is 3 char less because */
410 +strlen (cancel_button); /* of '&' char in button text */
412 i = (first_width + second_width - l1) / 4;
413 b1 = 5 + i;
414 b2 = b1 + strlen (ok_button) + i + 6;
415 b3 = b2 + strlen (save_button) + i + 4;
417 i18n_layt_flag = 1;
420 layout_dlg =
421 create_dlg (0, 0, 15, first_width + second_width + 9,
422 dialog_colors, layout_callback, "[Layout]",
423 _("Layout"), DLG_CENTER | DLG_REVERSE);
425 add_widget (layout_dlg, groupbox_new (4, 2, first_width, 6, title1));
426 add_widget (layout_dlg, groupbox_new (4, 8, first_width, 4, title2));
427 add_widget (layout_dlg,
428 groupbox_new (5 + first_width, 2, second_width, 10,
429 title3));
431 add_widget (layout_dlg,
432 button_new (BY, b3, B_CANCEL, NORMAL_BUTTON, cancel_button,
433 0));
434 add_widget (layout_dlg,
435 button_new (BY, b2, B_EXIT, NORMAL_BUTTON, save_button,
436 0));
437 add_widget (layout_dlg,
438 button_new (BY, b1, B_ENTER, DEFPUSH_BUTTON, ok_button,
439 0));
440 if (console_flag) {
441 add_widget (layout_dlg,
442 button_new (9, 12 + first_width, B_MINUS,
443 NARROW_BUTTON, "&-", bminus_cback));
444 add_widget (layout_dlg,
445 button_new (9, 7 + first_width, B_PLUS, NARROW_BUTTON,
446 "&+", bplus_cback));
448 #define XTRACT(i) *check_options[i].variable, check_options[i].text
450 for (i = 0; i < 6; i++) {
451 check_options[i].widget =
452 check_new (8 - i, 7 + first_width, XTRACT (i));
453 add_widget (layout_dlg, check_options[i].widget);
455 check_options[8].widget = check_new (10, 6, XTRACT (8));
456 add_widget (layout_dlg, check_options[8].widget);
457 check_options[7].widget = check_new (9, 6, XTRACT (7));
458 add_widget (layout_dlg, check_options[7].widget);
460 _filetype_mode = filetype_mode;
461 _permission_mode = permission_mode;
462 _equal_split = equal_split;
463 _menubar_visible = menubar_visible;
464 _command_prompt = command_prompt;
465 _keybar_visible = keybar_visible;
466 _message_visible = message_visible;
467 _xterm_title = xterm_title;
468 bright_widget =
469 button_new (6, 15, B_2RIGHT, NARROW_BUTTON, "&>", b2right_cback);
470 add_widget (layout_dlg, bright_widget);
471 bleft_widget =
472 button_new (6, 9, B_2LEFT, NARROW_BUTTON, "&<", b2left_cback);
473 add_widget (layout_dlg, bleft_widget);
474 check_options[6].widget = check_new (5, 6, XTRACT (6));
475 old_first_panel_size = -1;
476 old_horizontal_split = -1;
477 old_output_lines = -1;
479 _first_panel_size = first_panel_size;
480 _output_lines = output_lines;
481 add_widget (layout_dlg, check_options[6].widget);
482 radio_widget = radio_new (3, 6, 2, s_split_direction, 1);
483 add_widget (layout_dlg, radio_widget);
484 radio_widget->sel = horizontal_split;
487 static void
488 layout_change (void)
490 setup_panels ();
491 layout_do_change = 0;
492 /* re-init the menu, because perhaps there was a change in the way
493 how the panel are split (horizontal/vertical). */
494 done_menu ();
495 init_menu ();
496 menubar_arrange (the_menubar);
499 void layout_cmd (void)
501 int result;
502 int i;
504 init_layout ();
505 run_dlg (layout_dlg);
506 result = layout_dlg->ret_value;
508 if (result == B_ENTER || result == B_EXIT){
509 for (i = 0; check_options [i].text; i++)
510 if (check_options [i].widget)
511 *check_options [i].variable = check_options [i].widget->state & C_BOOL;
512 horizontal_split = radio_widget->sel;
513 first_panel_size = _first_panel_size;
514 output_lines = _output_lines;
515 layout_do_change = 1;
517 if (result == B_EXIT){
518 save_layout ();
519 sync_profiles ();
522 destroy_dlg (layout_dlg);
523 if (layout_do_change)
524 layout_change ();
527 static void check_split (void)
529 if (horizontal_split){
530 if (equal_split)
531 first_panel_size = height / 2;
532 else if (first_panel_size < MINHEIGHT)
533 first_panel_size = MINHEIGHT;
534 else if (first_panel_size > height - MINHEIGHT)
535 first_panel_size = height - MINHEIGHT;
536 } else {
537 if (equal_split)
538 first_panel_size = COLS / 2;
539 else if (first_panel_size < MINWIDTH)
540 first_panel_size = MINWIDTH;
541 else if (first_panel_size > COLS - MINWIDTH)
542 first_panel_size = COLS - MINWIDTH;
546 #ifdef HAVE_SLANG
547 void
548 init_curses ()
550 #ifndef HAS_ACS_AS_PCCHARS
551 if (force_ugly_line_drawing)
552 SLtt_Has_Alt_Charset = 0;
553 #endif
554 SLsmg_init_smg ();
555 do_enter_ca_mode ();
556 init_colors ();
557 keypad (stdscr, TRUE);
558 nodelay (stdscr, FALSE);
560 #else
561 static const struct {
562 int acscode;
563 int character;
564 } acs_approx [] = {
565 { 'q', '-' }, /* ACS_HLINE */
566 { 'x', '|' }, /* ACS_VLINE */
567 { 'l', '+' }, /* ACS_ULCORNER */
568 { 'k', '+' }, /* ACS_URCORNER */
569 { 'm', '+' }, /* ACS_LLCORNER */
570 { 'j', '+' }, /* ACS_LRCORNER */
571 { 'a', '#' }, /* ACS_CKBOARD */
572 { 'u', '+' }, /* ACS_RTEE */
573 { 't', '+' }, /* ACS_LTEE */
574 { 'w', '+' }, /* ACS_TTEE */
575 { 'v', '+' }, /* ACS_BTEE */
576 { 'n', '+' }, /* ACS_PLUS */
577 { 0, 0 } };
579 void init_curses (void)
581 int i;
582 initscr();
583 #ifdef HAVE_ESCDELAY
585 * If ncurses exports the ESCDELAY variable, it should be set to
586 * a low value, or you'll experience a delay in processing escape
587 * sequences that are recognized by mc (e.g. Esc-Esc). On the other
588 * hand, making ESCDELAY too small can result in some sequences
589 * (e.g. cursor arrows) being reported as separate keys under heavy
590 * processor load, and this can be a problem if mc hasn't learned
591 * them in the "Learn Keys" dialog. The value is in milliseconds.
593 ESCDELAY = 200;
594 #endif /* HAVE_ESCDELAY */
595 do_enter_ca_mode ();
596 mc_raw_mode ();
597 noecho ();
598 keypad (stdscr, TRUE);
599 nodelay (stdscr, FALSE);
600 init_colors ();
601 if (force_ugly_line_drawing) {
602 for (i = 0; acs_approx[i].acscode != 0; i++) {
603 acs_map[acs_approx[i].acscode] = acs_approx[i].character;
607 #endif /* ! HAVE_SLANG */
609 void
610 clr_scr (void)
612 standend ();
613 dlg_erase (midnight_dlg);
614 mc_refresh ();
615 doupdate ();
618 void
619 done_screen ()
621 if (!(quit & SUBSHELL_EXIT))
622 clr_scr ();
623 reset_shell_mode ();
624 mc_noraw_mode ();
625 keypad (stdscr, FALSE);
626 done_colors ();
629 static void
630 panel_do_cols (int index)
632 if (get_display_type (index) == view_listing)
633 set_panel_formats ((WPanel *) panels [index].widget);
634 else {
635 panel_update_cols (panels [index].widget, frame_half);
637 /* In case of an Hex Quick View must review line length */
638 if (get_display_type (index) == view_quick)
639 view_update_bytes_per_line ((WView *) panels [index].widget);
643 void
644 setup_panels (void)
646 int start_y;
647 int promptl; /* the prompt len */
649 if (console_flag) {
650 int minimum;
651 if (output_lines < 0)
652 output_lines = 0;
653 height =
654 LINES - keybar_visible - command_prompt - menubar_visible -
655 output_lines - message_visible;
656 minimum = MINHEIGHT * (1 + horizontal_split);
657 if (height < minimum) {
658 output_lines -= minimum - height;
659 height = minimum;
661 } else {
662 height =
663 LINES - menubar_visible - command_prompt - keybar_visible -
664 message_visible;
666 check_split ();
667 start_y = menubar_visible;
669 /* The column computing is defered until panel_do_cols */
670 if (horizontal_split) {
671 widget_set_size (panels[0].widget, start_y, 0, first_panel_size,
674 widget_set_size (panels[1].widget, start_y + first_panel_size, 0,
675 height - first_panel_size, 0);
676 } else {
677 int first_x = first_panel_size;
679 widget_set_size (panels[0].widget, start_y, 0, height, 0);
681 widget_set_size (panels[1].widget, start_y, first_x, height, 0);
684 panel_do_cols (0);
685 panel_do_cols (1);
687 promptl = strlen (prompt);
689 widget_set_size (&the_menubar->widget, 0, 0, 1, COLS);
691 if (command_prompt) {
692 widget_set_size (&cmdline->widget, LINES - 1 - keybar_visible,
693 promptl, 1,
694 COLS - promptl - (keybar_visible ? 0 : 1));
695 winput_set_origin (cmdline, promptl,
696 COLS - promptl - (keybar_visible ? 0 : 1));
697 widget_set_size (&the_prompt->widget, LINES - 1 - keybar_visible,
698 0, 1, promptl);
699 } else {
700 widget_set_size (&cmdline->widget, 0, 0, 0, 0);
701 winput_set_origin (cmdline, 0, 0);
702 widget_set_size (&the_prompt->widget, LINES, COLS, 0, 0);
705 widget_set_size (&the_bar->widget, LINES - 1, 0, keybar_visible, COLS);
706 the_bar->visible = keybar_visible;
708 /* Output window */
709 if (console_flag && output_lines) {
710 output_start_y =
711 LINES - command_prompt - keybar_visible - output_lines;
712 show_console_contents (output_start_y,
713 LINES - output_lines - keybar_visible - 1,
714 LINES - keybar_visible - 1);
716 if (message_visible) {
717 widget_set_size (&the_hint->widget, height + start_y, 0, 1, COLS);
718 set_hintbar (""); /* clean up the line */
719 } else
720 widget_set_size (&the_hint->widget, 0, 0, 0, 0);
722 load_hint (1);
723 update_xterm_title_path ();
726 void flag_winch (int dummy)
728 #ifndef USE_NCURSES /* don't do malloc in a signal handler */
729 low_level_change_screen_size ();
730 #endif
731 winch_flag = 1;
734 static void
735 low_level_change_screen_size (void)
737 #if defined(HAVE_SLANG) || NCURSES_VERSION_MAJOR >= 4
738 #if defined TIOCGWINSZ
739 struct winsize winsz;
741 winsz.ws_col = winsz.ws_row = 0;
742 /* Ioctl on the STDIN_FILENO */
743 ioctl (0, TIOCGWINSZ, &winsz);
744 if (winsz.ws_col && winsz.ws_row){
745 #if defined(NCURSES_VERSION) && defined(HAVE_RESIZETERM)
746 resizeterm(winsz.ws_row, winsz.ws_col);
747 clearok(stdscr,TRUE); /* sigwinch's should use a semaphore! */
748 #else
749 COLS = winsz.ws_col;
750 LINES = winsz.ws_row;
751 #endif
752 #ifdef HAVE_SUBSHELL_SUPPORT
753 resize_subshell ();
754 #endif
756 #endif /* TIOCGWINSZ */
757 #endif /* defined(HAVE_SLANG) || NCURSES_VERSION_MAJOR >= 4 */
760 void
761 change_screen_size (void)
763 #if defined(HAVE_SLANG) || NCURSES_VERSION_MAJOR >= 4
764 #if defined TIOCGWINSZ
766 #ifndef NCURSES_VERSION
767 mc_noraw_mode ();
768 endwin ();
769 #endif
770 low_level_change_screen_size ();
771 check_split ();
772 #ifndef NCURSES_VERSION
773 /* XSI Curses spec states that portable applications shall not invoke
774 * initscr() more than once. This kludge could be done within the scope
775 * of the specification by using endwin followed by a refresh (in fact,
776 * more than one curses implementation does this); it is guaranteed to work
777 * only with slang.
779 init_curses ();
780 #endif
781 setup_panels ();
783 /* Inform currently running dialog */
784 (*current_dlg->callback) (current_dlg, DLG_RESIZE, 0);
786 #ifdef RESIZABLE_MENUBAR
787 menubar_arrange (the_menubar);
788 #endif
790 /* Now, force the redraw */
791 do_refresh ();
792 touchwin (stdscr);
793 #endif /* TIOCGWINSZ */
794 #endif /* defined(HAVE_SLANG) || NCURSES_VERSION_MAJOR >= 4 */
795 winch_flag = 0;
798 static int ok_to_refresh = 1;
800 void use_dash (int flag)
802 if (flag)
803 ok_to_refresh++;
804 else
805 ok_to_refresh--;
808 void set_hintbar(char *str)
810 label_set_text (the_hint, str);
811 if (ok_to_refresh > 0)
812 refresh();
815 void print_vfs_message (const char *msg, ...)
817 va_list ap;
818 char str [128];
820 va_start (ap, msg);
822 g_vsnprintf (str, sizeof (str), msg, ap);
823 va_end (ap);
825 if (midnight_shutdown)
826 return;
828 if (!message_visible || !the_hint || !the_hint->widget.parent) {
829 int col, row;
831 if (!nice_rotating_dash || (ok_to_refresh <= 0))
832 return;
834 /* Preserve current cursor position */
835 getyx (stdscr, row, col);
837 move (0, 0);
838 attrset (NORMAL_COLOR);
839 printw ("%-*s", COLS-1, str);
841 /* Restore cursor position */
842 move(row, col);
843 mc_refresh ();
844 return;
847 if (message_visible) {
848 set_hintbar(str);
852 void rotate_dash (void)
854 static const char rotating_dash [] = "|/-\\";
855 static size_t pos = 0;
857 if (!nice_rotating_dash || (ok_to_refresh <= 0))
858 return;
860 if (pos >= sizeof (rotating_dash)-1)
861 pos = 0;
862 move (0, COLS-1);
863 attrset (NORMAL_COLOR);
864 addch (rotating_dash [pos]);
865 mc_refresh ();
866 pos++;
869 char *get_nth_panel_name (int num)
871 static char buffer [BUF_SMALL];
873 if (!num)
874 return "New Left Panel";
875 else if (num == 1)
876 return "New Right Panel";
877 else {
878 g_snprintf (buffer, sizeof (buffer), "%ith Panel", num);
879 return buffer;
883 /* I wonder if I should start to use the folding mode than Dugan uses */
884 /* */
885 /* This is the centralized managing of the panel display types */
886 /* This routine takes care of destroying and creating new widgets */
887 /* Please note that it could manage MAX_VIEWS, not just left and right */
888 /* Currently nothing in the code takes advantage of this and has hard- */
889 /* coded values for two panels only */
891 /* Set the num-th panel to the view type: type */
892 /* This routine also keeps at least one WPanel object in the screen */
893 /* since a lot of routines depend on the current_panel variable */
894 void set_display_type (int num, int type)
896 int x, y, cols, lines;
897 int the_other; /* Index to the other panel */
898 char *file_name = 0; /* For Quick view */
899 Widget *new_widget, *old_widget;
900 WPanel *the_other_panel;
902 x = y = cols = lines = 0;
903 old_widget = 0;
904 if (num >= MAX_VIEWS){
905 fprintf (stderr, "Cannot allocate more that %d views\n", MAX_VIEWS);
906 abort ();
909 /* Check that we will have a WPanel * at least */
910 the_other = 0;
911 if (type != view_listing){
912 the_other = num == 0 ? 1 : 0;
914 if (panels [the_other].type != view_listing)
915 return;
919 /* Get rid of it */
920 if (panels [num].widget){
921 Widget *w = panels [num].widget;
922 WPanel *panel = (WPanel *) panels [num].widget;
924 x = w->x;
925 y = w->y;
926 cols = w->cols;
927 lines = w->lines;
928 old_widget = panels [num].widget;
930 if (panels [num].type == view_listing){
931 if (panel->frame_size == frame_full && type != view_listing){
932 cols = COLS - first_panel_size;
933 if (num == 1)
934 x = first_panel_size;
939 new_widget = 0;
941 switch (type){
942 case view_listing:
943 new_widget = (Widget *) panel_new (get_nth_panel_name (num));
944 break;
946 case view_info:
947 new_widget = (Widget *) info_new ();
949 break;
951 case view_tree:
952 new_widget = (Widget *) tree_new (1, 0, 0, 0, 0);
953 break;
955 case view_quick:
956 new_widget = (Widget *) view_new (0, 0, 0, 0, 1);
957 the_other_panel = (WPanel *) panels [the_other].widget;
958 if (the_other_panel)
959 file_name =
960 the_other_panel->dir.list[the_other_panel->selected].fname;
961 else
962 file_name = "";
964 view_init ((WView *) new_widget, 0, file_name, 0);
965 break;
967 panels [num].type = type;
968 panels [num].widget = (Widget *) new_widget;
970 /* We set the same size the old widget had */
971 widget_set_size ((Widget *) new_widget, y, x, lines, cols);
973 /* We use replace to keep the circular list of the dialog in the */
974 /* same state. Maybe we could just kill it and then replace it */
975 if (midnight_dlg && old_widget){
976 dlg_replace_widget (midnight_dlg, old_widget, panels [num].widget);
978 if (type == view_listing){
979 if (num == 0)
980 left_panel = (WPanel *) new_widget;
981 else
982 right_panel = (WPanel *) new_widget;
985 if (type == view_tree)
986 the_tree = (WTree *) new_widget;
988 /* Prevent current_panel's value from becoming invalid.
989 * It's just a quick hack to prevent segfaults. Comment out and
990 * try following:
991 * - select left panel
992 * - invoke menue left/tree
993 * - as long as you stay in the left panel almost everything that uses
994 * current_panel causes segfault, e.g. C-Enter, C-x c, ...
997 if (type != view_listing)
998 if (current_panel == (WPanel *) old_widget)
999 current_panel = num == 0 ? right_panel : left_panel;
1002 /* This routine is deeply sticked to the two panels idea.
1003 What should it do in more panels. ANSWER - don't use it
1004 in any multiple panels environment. */
1005 void swap_panels ()
1007 Widget tmp;
1008 Widget *tmp_widget;
1009 WPanel panel;
1010 WPanel *panel1, *panel2;
1011 int tmp_type;
1013 #define panelswap(x) panel. x = panel1-> x; panel1-> x = panel2-> x; panel2-> x = panel. x;
1015 #define panelswapstr(e) strcpy (panel. e, panel1-> e); \
1016 strcpy (panel1-> e, panel2-> e); \
1017 strcpy (panel2-> e, panel. e);
1018 panel1 = (WPanel *) panels [0].widget;
1019 panel2 = (WPanel *) panels [1].widget;
1020 if (panels [0].type == view_listing && panels [1].type == view_listing) {
1021 /* Change everything except format/sort/panel_name etc. */
1022 panelswap (dir);
1023 panelswap (active);
1024 panelswapstr (cwd);
1025 panelswapstr (lwd);
1026 panelswap (count);
1027 panelswap (marked);
1028 panelswap (dirs_marked);
1029 panelswap (total);
1030 panelswap (top_file);
1031 panelswap (selected);
1032 panelswap (is_panelized);
1033 panelswap (dir_stat);
1035 panel1->searching = 0;
1036 panel2->searching = 0;
1037 if (current_panel == panel1)
1038 current_panel = panel2;
1039 else
1040 current_panel = panel1;
1042 if (dlg_widget_active (panels[0].widget))
1043 dlg_select_widget (midnight_dlg, (void *) panels [1].widget);
1044 else if (dlg_widget_active (panels[1].widget))
1045 dlg_select_widget (midnight_dlg, (void *) panels [0].widget);
1046 } else {
1047 WPanel *tmp_panel;
1049 tmp_panel=right_panel;
1050 right_panel=left_panel;
1051 left_panel=tmp_panel;
1053 if (panels [0].type == view_listing) {
1054 if (!strcmp (panel1->panel_name, get_nth_panel_name (0))) {
1055 g_free (panel1->panel_name);
1056 panel1->panel_name = g_strdup (get_nth_panel_name (1));
1059 if (panels [1].type == view_listing) {
1060 if (!strcmp (panel2->panel_name, get_nth_panel_name (1))) {
1061 g_free (panel2->panel_name);
1062 panel2->panel_name = g_strdup (get_nth_panel_name (0));
1066 tmp.x = panels [0].widget->x;
1067 tmp.y = panels [0].widget->y;
1068 tmp.cols = panels [0].widget->cols;
1069 tmp.lines = panels [0].widget->lines;
1071 panels [0].widget->x = panels [1].widget->x;
1072 panels [0].widget->y = panels [1].widget->y;
1073 panels [0].widget->cols = panels [1].widget->cols;
1074 panels [0].widget->lines = panels [1].widget->lines;
1076 panels [1].widget->x = tmp.x;
1077 panels [1].widget->y = tmp.y;
1078 panels [1].widget->cols = tmp.cols;
1079 panels [1].widget->lines = tmp.lines;
1081 tmp_widget = panels [0].widget;
1082 panels [0].widget = panels [1].widget;
1083 panels [1].widget = tmp_widget;
1084 tmp_type = panels [0].type;
1085 panels [0].type = panels [1].type;
1086 panels [1].type = tmp_type;
1090 int get_display_type (int index)
1092 return panels [index].type;
1095 struct Widget *
1096 get_panel_widget (int index)
1098 return panels[index].widget;
1101 int get_current_index (void)
1103 if (panels [0].widget == ((Widget *) current_panel))
1104 return 0;
1105 else
1106 return 1;
1109 int get_other_index (void)
1111 return !get_current_index ();
1114 struct WPanel *
1115 get_other_panel (void)
1117 return (struct WPanel *) get_panel_widget (get_other_index ());
1120 /* Returns the view type for the current panel/view */
1121 int get_current_type (void)
1123 if (panels [0].widget == (Widget *) current_panel)
1124 return panels [0].type;
1125 else
1126 return panels [1].type;
1129 /* Returns the view type of the unselected panel */
1130 int get_other_type (void)
1132 if (panels [0].widget == (Widget *) current_panel)
1133 return panels [1].type;
1134 else
1135 return panels [0].type;