1 /*
2 Editor initialisation and callback handler.
3
4 Copyright (C) 1996-2021
5 Free Software Foundation, Inc.
6
7 Written by:
8 Paul Sheer, 1996, 1997
9 Andrew Borodin <aborodin@vmail.ru> 2012, 2013
10
11 This file is part of the Midnight Commander.
12
13 The Midnight Commander is free software: you can redistribute it
14 and/or modify it under the terms of the GNU General Public License as
15 published by the Free Software Foundation, either version 3 of the License,
16 or (at your option) any later version.
17
18 The Midnight Commander is distributed in the hope that it will be useful,
19 but WITHOUT ANY WARRANTY; without even the implied warranty of
20 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 GNU General Public License for more details.
22
23 You should have received a copy of the GNU General Public License
24 along with this program. If not, see <http://www.gnu.org/licenses/>.
25 */
26
27 /** \file
28 * \brief Source: editor initialisation and callback handler
29 * \author Paul Sheer
30 * \date 1996, 1997
31 */
32
33 #include <config.h>
34
35 #include <ctype.h>
36 #include <errno.h>
37 #include <stdlib.h>
38 #include <string.h>
39 #include <sys/types.h>
40 #include <unistd.h>
41
42 #include "lib/global.h"
43
44 #include "lib/tty/tty.h" /* LINES, COLS */
45 #include "lib/tty/key.h" /* is_idle() */
46 #include "lib/tty/color.h" /* tty_setcolor() */
47 #include "lib/skin.h"
48 #include "lib/fileloc.h" /* EDIT_HOME_DIR */
49 #include "lib/strutil.h" /* str_term_trim() */
50 #include "lib/util.h" /* mc_build_filename() */
51 #include "lib/widget.h"
52 #include "lib/mcconfig.h"
53 #include "lib/event.h" /* mc_event_raise() */
54 #ifdef HAVE_CHARSET
55 #include "lib/charsets.h"
56 #endif
57
58 #include "src/keymap.h" /* keybind_lookup_keymap_command() */
59 #include "src/setup.h" /* home_dir */
60 #include "src/execute.h" /* toggle_subshell() */
61 #include "src/filemanager/cmd.h" /* save_setup_cmd() */
62 #include "src/learn.h" /* learn_keys() */
63 #include "src/args.h" /* mcedit_arg_t */
64
65 #include "edit-impl.h"
66 #include "editwidget.h"
67 #include "editmacros.h" /* edit_execute_macro() */
68 #ifdef HAVE_ASPELL
69 #include "spell.h"
70 #endif
71
72 /*** global variables ****************************************************************************/
73
74 char *edit_window_state_char = NULL;
75 char *edit_window_close_char = NULL;
76
77 /*** file scope macro definitions ****************************************************************/
78
79 #define WINDOW_MIN_LINES (2 + 2)
80 #define WINDOW_MIN_COLS (2 + LINE_STATE_WIDTH + 2)
81
82 /*** file scope type declarations ****************************************************************/
83
84 /*** file scope variables ************************************************************************/
85 static unsigned int edit_dlg_init_refcounter = 0;
86
87 /*** file scope functions ************************************************************************/
88
89 static cb_ret_t edit_dialog_callback (Widget * w, Widget * sender, widget_msg_t msg, int parm,
90 void *data);
91
92 /* --------------------------------------------------------------------------------------------- */
93 /**
94 * Init the 'edit' subsystem
95 */
96
97 static void
edit_dlg_init(void)98 edit_dlg_init (void)
99 {
100 edit_dlg_init_refcounter++;
101
102 if (edit_dlg_init_refcounter == 1)
103 {
104 edit_window_state_char = mc_skin_get ("widget-editor", "window-state-char", "*");
105 edit_window_close_char = mc_skin_get ("widget-editor", "window-close-char", "X");
106
107 #ifdef HAVE_ASPELL
108 aspell_init ();
109 #endif
110 }
111 }
112
113 /* --------------------------------------------------------------------------------------------- */
114 /**
115 * Deinit the 'edit' subsystem
116 */
117
118 static void
edit_dlg_deinit(void)119 edit_dlg_deinit (void)
120 {
121 if (edit_dlg_init_refcounter == 1)
122 {
123 g_free (edit_window_state_char);
124 g_free (edit_window_close_char);
125
126 #ifdef HAVE_ASPELL
127 aspell_clean ();
128 #endif
129 }
130
131 if (edit_dlg_init_refcounter != 0)
132 edit_dlg_init_refcounter--;
133 }
134
135 /* --------------------------------------------------------------------------------------------- */
136 /**
137 * Show info about editor
138 */
139
140 static void
edit_about(void)141 edit_about (void)
142 {
143 char *ver;
144
145 ver = g_strdup_printf ("MCEdit %s", mc_global.mc_version);
146
147 {
148 quick_widget_t quick_widgets[] = {
149 /* *INDENT-OFF* */
150 QUICK_LABEL (ver, NULL),
151 QUICK_SEPARATOR (TRUE),
152 QUICK_LABEL (N_("A user friendly text editor\n"
153 "written for the Midnight Commander."), NULL),
154 QUICK_SEPARATOR (FALSE),
155 QUICK_LABEL (N_("Copyright (C) 1996-2021 the Free Software Foundation"), NULL),
156 QUICK_START_BUTTONS (TRUE, TRUE),
157 QUICK_BUTTON (N_("&OK"), B_ENTER, NULL, NULL),
158 QUICK_END
159 /* *INDENT-ON* */
160 };
161
162 quick_dialog_t qdlg = {
163 -1, -1, 40,
164 N_("About"), "[Internal File Editor]",
165 quick_widgets, NULL, NULL
166 };
167
168 quick_widgets[0].pos_flags = WPOS_KEEP_TOP | WPOS_CENTER_HORZ;
169 quick_widgets[2].pos_flags = WPOS_KEEP_TOP | WPOS_CENTER_HORZ;
170 quick_widgets[4].pos_flags = WPOS_KEEP_TOP | WPOS_CENTER_HORZ;
171
172 (void) quick_dialog (&qdlg);
173 }
174
175 g_free (ver);
176 }
177
178 /* --------------------------------------------------------------------------------------------- */
179 /**
180 * Show a help window
181 */
182
183 static void
edit_help(void)184 edit_help (void)
185 {
186 ev_help_t event_data = { NULL, "[Internal File Editor]" };
187 mc_event_raise (MCEVENT_GROUP_CORE, "help", &event_data);
188 }
189
190 /* --------------------------------------------------------------------------------------------- */
191 /**
192 * Restore saved window size.
193 *
194 * @param edit editor object
195 */
196
197 static void
edit_restore_size(WEdit * edit)198 edit_restore_size (WEdit * edit)
199 {
200 Widget *w = WIDGET (edit);
201
202 edit->drag_state = MCEDIT_DRAG_NONE;
203 w->mouse.forced_capture = FALSE;
204 widget_set_size_rect (w, &edit->loc_prev);
205 widget_draw (WIDGET (w->owner));
206 }
207
208 /* --------------------------------------------------------------------------------------------- */
209 /**
210 * Move window by one row or column in any direction.
211 *
212 * @param edit editor object
213 * @param command direction (CK_Up, CK_Down, CK_Left, CK_Right)
214 */
215
216 static void
edit_window_move(WEdit * edit,long command)217 edit_window_move (WEdit * edit, long command)
218 {
219 Widget *w = WIDGET (edit);
220 Widget *wh = WIDGET (w->owner);
221
222 switch (command)
223 {
224 case CK_Up:
225 if (w->y > wh->y + 1) /* menubar */
226 w->y--;
227 break;
228 case CK_Down:
229 if (w->y < wh->y + wh->lines - 2) /* buttonbar */
230 w->y++;
231 break;
232 case CK_Left:
233 if (w->x + w->cols > wh->x)
234 w->x--;
235 break;
236 case CK_Right:
237 if (w->x < wh->x + wh->cols)
238 w->x++;
239 break;
240 default:
241 return;
242 }
243
244 edit->force |= REDRAW_PAGE;
245 widget_draw (WIDGET (w->owner));
246 }
247
248 /* --------------------------------------------------------------------------------------------- */
249 /**
250 * Resize window by one row or column in any direction.
251 *
252 * @param edit editor object
253 * @param command direction (CK_Up, CK_Down, CK_Left, CK_Right)
254 */
255
256 static void
edit_window_resize(WEdit * edit,long command)257 edit_window_resize (WEdit * edit, long command)
258 {
259 Widget *w = WIDGET (edit);
260 Widget *wh = WIDGET (w->owner);
261
262 switch (command)
263 {
264 case CK_Up:
265 if (w->lines > WINDOW_MIN_LINES)
266 w->lines--;
267 break;
268 case CK_Down:
269 if (w->y + w->lines < wh->y + wh->lines - 1) /* buttonbar */
270 w->lines++;
271 break;
272 case CK_Left:
273 if (w->cols > WINDOW_MIN_COLS)
274 w->cols--;
275 break;
276 case CK_Right:
277 if (w->x + w->cols < wh->x + wh->cols)
278 w->cols++;
279 break;
280 default:
281 return;
282 }
283
284 edit->force |= REDRAW_COMPLETELY;
285 widget_draw (WIDGET (w->owner));
286 }
287
288 /* --------------------------------------------------------------------------------------------- */
289 /**
290 * Get hotkey by number.
291 *
292 * @param n number
293 * @return hotkey
294 */
295
296 static unsigned char
get_hotkey(int n)297 get_hotkey (int n)
298 {
299 return (n <= 9) ? '0' + n : 'a' + n - 10;
300 }
301
302 /* --------------------------------------------------------------------------------------------- */
303
304 static void
edit_window_list(const WDialog * h)305 edit_window_list (const WDialog * h)
306 {
307 const WGroup *g = CONST_GROUP (h);
308 const size_t offset = 2; /* skip menu and buttonbar */
309 const size_t dlg_num = g_list_length (g->widgets) - offset;
310 int lines, cols;
311 Listbox *listbox;
312 GList *w;
313 WEdit *selected;
314 int i = 0;
315
316 lines = MIN ((size_t) (LINES * 2 / 3), dlg_num);
317 cols = COLS * 2 / 3;
318
319 listbox = create_listbox_window (lines, cols, _("Open files"), "[Open files]");
320
321 for (w = g->widgets; w != NULL; w = g_list_next (w))
322 if (edit_widget_is_editor (CONST_WIDGET (w->data)))
323 {
324 WEdit *e = (WEdit *) w->data;
325 char *fname;
326
327 if (e->filename_vpath == NULL)
328 fname = g_strdup_printf ("%c [%s]", e->modified ? '*' : ' ', _("NoName"));
329 else
330 fname =
331 g_strdup_printf ("%c%s", e->modified ? '*' : ' ',
332 vfs_path_as_str (e->filename_vpath));
333
334 listbox_add_item (listbox->list, LISTBOX_APPEND_AT_END, get_hotkey (i++),
335 str_term_trim (fname, WIDGET (listbox->list)->cols - 2), e, FALSE);
336 g_free (fname);
337 }
338
339 selected = run_listbox_with_data (listbox, g->current->data);
340 if (selected != NULL)
341 widget_select (WIDGET (selected));
342 }
343
344 /* --------------------------------------------------------------------------------------------- */
345
346 static char *
edit_get_shortcut(long command)347 edit_get_shortcut (long command)
348 {
349 const char *ext_map;
350 const char *shortcut = NULL;
351
352 shortcut = keybind_lookup_keymap_shortcut (editor_map, command);
353 if (shortcut != NULL)
354 return g_strdup (shortcut);
355
356 ext_map = keybind_lookup_keymap_shortcut (editor_map, CK_ExtendedKeyMap);
357 if (ext_map != NULL)
358 shortcut = keybind_lookup_keymap_shortcut (editor_x_map, command);
359 if (shortcut != NULL)
360 return g_strdup_printf ("%s %s", ext_map, shortcut);
361
362 return NULL;
363 }
364
365 /* --------------------------------------------------------------------------------------------- */
366
367 static char *
edit_get_title(const WDialog * h,size_t len)368 edit_get_title (const WDialog * h, size_t len)
369 {
370 const WEdit *edit = find_editor (h);
371 const char *modified = edit->modified ? "(*) " : " ";
372 const char *file_label;
373 char *filename;
374
375 len -= 4;
376
377 if (edit->filename_vpath == NULL)
378 filename = g_strdup (_("[NoName]"));
379 else
380 filename = g_strdup (vfs_path_as_str (edit->filename_vpath));
381
382 file_label = str_term_trim (filename, len - str_term_width1 (_("Edit: ")));
383 g_free (filename);
384
385 return g_strconcat (_("Edit: "), modified, file_label, (char *) NULL);
386 }
387
388 /* --------------------------------------------------------------------------------------------- */
389
390 static cb_ret_t
edit_dialog_command_execute(WDialog * h,long command)391 edit_dialog_command_execute (WDialog * h, long command)
392 {
393 WGroup *g = GROUP (h);
394 Widget *wh = WIDGET (h);
395 cb_ret_t ret = MSG_HANDLED;
396
397 switch (command)
398 {
399 case CK_EditNew:
400 edit_add_window (h, wh->y + 1, wh->x, wh->lines - 2, wh->cols, NULL, 0);
401 break;
402 case CK_EditFile:
403 edit_load_cmd (h);
404 break;
405 case CK_History:
406 edit_load_file_from_history (h);
407 break;
408 case CK_EditSyntaxFile:
409 edit_load_syntax_file (h);
410 break;
411 case CK_EditUserMenu:
412 edit_load_menu_file (h);
413 break;
414 case CK_Close:
415 /* if there are no opened files anymore, close MC editor */
416 if (edit_widget_is_editor (CONST_WIDGET (g->current->data)) &&
417 edit_close_cmd ((WEdit *) g->current->data) && find_editor (h) == NULL)
418 dlg_stop (h);
419 break;
420 case CK_Help:
421 edit_help ();
422 /* edit->force |= REDRAW_COMPLETELY; */
423 break;
424 case CK_Menu:
425 edit_menu_cmd (h);
426 break;
427 case CK_Quit:
428 case CK_Cancel:
429 /* don't close editor due to SIGINT, but stop move/resize window */
430 {
431 Widget *w = WIDGET (g->current->data);
432
433 if (edit_widget_is_editor (w) && ((WEdit *) w)->drag_state != MCEDIT_DRAG_NONE)
434 edit_restore_size ((WEdit *) w);
435 else if (command == CK_Quit)
436 dlg_stop (h);
437 }
438 break;
439 case CK_About:
440 edit_about ();
441 break;
442 case CK_SyntaxOnOff:
443 edit_syntax_onoff_cmd (h);
444 break;
445 case CK_ShowTabTws:
446 edit_show_tabs_tws_cmd (h);
447 break;
448 case CK_ShowMargin:
449 edit_show_margin_cmd (h);
450 break;
451 case CK_ShowNumbers:
452 edit_show_numbers_cmd (h);
453 break;
454 case CK_Refresh:
455 edit_refresh_cmd ();
456 break;
457 case CK_Shell:
458 toggle_subshell ();
459 break;
460 case CK_LearnKeys:
461 learn_keys ();
462 break;
463 case CK_WindowMove:
464 case CK_WindowResize:
465 if (edit_widget_is_editor (CONST_WIDGET (g->current->data)))
466 edit_handle_move_resize ((WEdit *) g->current->data, command);
467 break;
468 case CK_WindowList:
469 edit_window_list (h);
470 break;
471 case CK_WindowNext:
472 group_select_next_widget (g);
473 break;
474 case CK_WindowPrev:
475 group_select_prev_widget (g);
476 break;
477 case CK_Options:
478 edit_options_dialog (h);
479 break;
480 case CK_OptionsSaveMode:
481 edit_save_mode_cmd ();
482 break;
483 case CK_SaveSetup:
484 save_setup_cmd ();
485 break;
486 default:
487 ret = MSG_NOT_HANDLED;
488 break;
489 }
490
491 return ret;
492 }
493
494 /* --------------------------------------------------------------------------------------------- */
495 /*
496 * Translate the keycode into either 'command' or 'char_for_insertion'.
497 * 'command' is one of the editor commands from cmddef.h.
498 */
499
500 static gboolean
edit_translate_key(WEdit * edit,long x_key,int * cmd,int * ch)501 edit_translate_key (WEdit * edit, long x_key, int *cmd, int *ch)
502 {
503 Widget *w = WIDGET (edit);
504 long command = CK_InsertChar;
505 int char_for_insertion = -1;
506
507 /* an ordinary insertable character */
508 if (!w->ext_mode && x_key < 256)
509 {
510 #ifndef HAVE_CHARSET
511 if (is_printable (x_key))
512 {
513 char_for_insertion = x_key;
514 goto fin;
515 }
516 #else
517 int c;
518
519 if (edit->charpoint >= 4)
520 {
521 edit->charpoint = 0;
522 edit->charbuf[edit->charpoint] = '\0';
523 }
524 if (edit->charpoint < 4)
525 {
526 edit->charbuf[edit->charpoint++] = x_key;
527 edit->charbuf[edit->charpoint] = '\0';
528 }
529
530 /* input from 8-bit locale */
531 if (!mc_global.utf8_display)
532 {
533 /* source in 8-bit codeset */
534 c = convert_from_input_c (x_key);
535
536 if (is_printable (c))
537 {
538 if (!edit->utf8)
539 char_for_insertion = c;
540 else
541 char_for_insertion = convert_from_8bit_to_utf_c2 ((char) x_key);
542 goto fin;
543 }
544 }
545 else
546 {
547 /* UTF-8 locale */
548 int res;
549
550 res = str_is_valid_char (edit->charbuf, edit->charpoint);
551 if (res < 0 && res != -2)
552 {
553 edit->charpoint = 0; /* broken multibyte char, skip */
554 goto fin;
555 }
556
557 if (edit->utf8)
558 {
559 /* source in UTF-8 codeset */
560 if (res < 0)
561 {
562 char_for_insertion = x_key;
563 goto fin;
564 }
565
566 edit->charbuf[edit->charpoint] = '\0';
567 edit->charpoint = 0;
568 if (g_unichar_isprint (g_utf8_get_char (edit->charbuf)))
569 {
570 char_for_insertion = x_key;
571 goto fin;
572 }
573 }
574 else
575 {
576 /* 8-bit source */
577 if (res < 0)
578 {
579 /* not finised multibyte input (in meddle multibyte utf-8 char) */
580 goto fin;
581 }
582
583 if (g_unichar_isprint (g_utf8_get_char (edit->charbuf)))
584 {
585 c = convert_from_utf_to_current (edit->charbuf);
586 edit->charbuf[0] = '\0';
587 edit->charpoint = 0;
588 char_for_insertion = c;
589 goto fin;
590 }
591
592 /* unprinteble utf input, skip it */
593 edit->charbuf[0] = '\0';
594 edit->charpoint = 0;
595 }
596 }
597 #endif /* HAVE_CHARSET */
598 }
599
600 /* Commands specific to the key emulation */
601 command = widget_lookup_key (w, x_key);
602 if (command == CK_IgnoreKey)
603 command = CK_InsertChar;
604
605 fin:
606 *cmd = (int) command; /* FIXME */
607 *ch = char_for_insertion;
608
609 return !(command == CK_InsertChar && char_for_insertion == -1);
610 }
611
612
613 /* --------------------------------------------------------------------------------------------- */
614
615 static inline void
edit_quit(WDialog * h)616 edit_quit (WDialog * h)
617 {
618 GList *l;
619 WEdit *e = NULL;
620 GSList *m = NULL;
621 GSList *me;
622
623 /* don't stop the dialog before final decision */
624 widget_set_state (WIDGET (h), WST_ACTIVE, TRUE);
625
626 /* check window state and get modified files */
627 for (l = GROUP (h)->widgets; l != NULL; l = g_list_next (l))
628 if (edit_widget_is_editor (CONST_WIDGET (l->data)))
629 {
630 e = (WEdit *) l->data;
631
632 if (e->drag_state != MCEDIT_DRAG_NONE)
633 {
634 edit_restore_size (e);
635 g_slist_free (m);
636 return;
637 }
638
639 /* create separate list because widget_select()
640 changes the window position in Z order */
641 if (e->modified)
642 m = g_slist_prepend (m, l->data);
643 }
644
645 for (me = m; me != NULL; me = g_slist_next (me))
646 {
647 e = (WEdit *) me->data;
648
649 widget_select (WIDGET (e));
650
651 if (!edit_ok_to_exit (e))
652 break;
653 }
654
655 /* if all files were checked, quit editor */
656 if (me == NULL)
657 dlg_stop (h);
658
659 g_slist_free (m);
660 }
661
662 /* --------------------------------------------------------------------------------------------- */
663
664 static inline void
edit_set_buttonbar(WEdit * edit,WButtonBar * bb)665 edit_set_buttonbar (WEdit * edit, WButtonBar * bb)
666 {
667 Widget *w = WIDGET (edit);
668
669 buttonbar_set_label (bb, 1, Q_ ("ButtonBar|Help"), w->keymap, NULL);
670 buttonbar_set_label (bb, 2, Q_ ("ButtonBar|Save"), w->keymap, w);
671 buttonbar_set_label (bb, 3, Q_ ("ButtonBar|Mark"), w->keymap, w);
672 buttonbar_set_label (bb, 4, Q_ ("ButtonBar|Replac"), w->keymap, w);
673 buttonbar_set_label (bb, 5, Q_ ("ButtonBar|Copy"), w->keymap, w);
674 buttonbar_set_label (bb, 6, Q_ ("ButtonBar|Move"), w->keymap, w);
675 buttonbar_set_label (bb, 7, Q_ ("ButtonBar|Search"), w->keymap, w);
676 buttonbar_set_label (bb, 8, Q_ ("ButtonBar|Delete"), w->keymap, w);
677 buttonbar_set_label (bb, 9, Q_ ("ButtonBar|PullDn"), w->keymap, NULL);
678 buttonbar_set_label (bb, 10, Q_ ("ButtonBar|Quit"), w->keymap, NULL);
679 }
680
681 /* --------------------------------------------------------------------------------------------- */
682
683 static void
edit_total_update(WEdit * edit)684 edit_total_update (WEdit * edit)
685 {
686 edit_find_bracket (edit);
687 edit->force |= REDRAW_COMPLETELY;
688 edit_update_curs_row (edit);
689 edit_update_screen (edit);
690 }
691
692 /* --------------------------------------------------------------------------------------------- */
693
694 static gboolean
edit_update_cursor(WEdit * edit,const mouse_event_t * event)695 edit_update_cursor (WEdit * edit, const mouse_event_t * event)
696 {
697 int x, y;
698 gboolean done;
699
700 x = event->x - (edit->fullscreen ? 0 : 1);
701 y = event->y - (edit->fullscreen ? 0 : 1);
702
703 if (edit->mark2 != -1 && event->msg == MSG_MOUSE_UP)
704 return TRUE; /* don't do anything */
705
706 if (event->msg == MSG_MOUSE_DOWN || event->msg == MSG_MOUSE_UP)
707 edit_push_key_press (edit);
708
709 if (!option_cursor_beyond_eol)
710 edit->prev_col = x - edit->start_col - option_line_state_width;
711 else
712 {
713 long line_len;
714
715 line_len =
716 edit_move_forward3 (edit, edit_buffer_get_current_bol (&edit->buffer), 0,
717 edit_buffer_get_current_eol (&edit->buffer));
718
719 if (x > line_len - 1)
720 {
721 edit->over_col = x - line_len - edit->start_col - option_line_state_width;
722 edit->prev_col = line_len;
723 }
724 else
725 {
726 edit->over_col = 0;
727 edit->prev_col = x - option_line_state_width - edit->start_col;
728 }
729 }
730
731 if (y > edit->curs_row)
732 edit_move_down (edit, y - edit->curs_row, FALSE);
733 else if (y < edit->curs_row)
734 edit_move_up (edit, edit->curs_row - y, FALSE);
735 else
736 edit_move_to_prev_col (edit, edit_buffer_get_current_bol (&edit->buffer));
737
738 if (event->msg == MSG_MOUSE_CLICK)
739 {
740 edit_mark_cmd (edit, TRUE); /* reset */
741 edit->highlight = 0;
742 }
743
744 done = (event->msg != MSG_MOUSE_DRAG);
745 if (done)
746 edit_mark_cmd (edit, FALSE);
747
748 return done;
749 }
750
751 /* --------------------------------------------------------------------------------------------- */
752 /** Callback for the edit dialog */
753
754 static cb_ret_t
edit_dialog_callback(Widget * w,Widget * sender,widget_msg_t msg,int parm,void * data)755 edit_dialog_callback (Widget * w, Widget * sender, widget_msg_t msg, int parm, void *data)
756 {
757 WGroup *g = GROUP (w);
758 WDialog *h = DIALOG (w);
759
760 switch (msg)
761 {
762 case MSG_INIT:
763 edit_dlg_init ();
764 return MSG_HANDLED;
765
766 case MSG_RESIZE:
767 dlg_default_callback (w, NULL, MSG_RESIZE, 0, NULL);
768 menubar_arrange (find_menubar (h));
769 return MSG_HANDLED;
770
771 case MSG_ACTION:
772 {
773 /* Handle shortcuts, menu, and buttonbar. */
774
775 cb_ret_t result;
776
777 result = edit_dialog_command_execute (h, parm);
778
779 /* We forward any commands coming from the menu, and which haven't been
780 handled by the dialog, to the focused WEdit window. */
781 if (result == MSG_NOT_HANDLED && sender == WIDGET (find_menubar (h)))
782 result = send_message (g->current->data, NULL, MSG_ACTION, parm, NULL);
783
784 return result;
785 }
786
787 case MSG_KEY:
788 {
789 Widget *we = WIDGET (g->current->data);
790 cb_ret_t ret = MSG_NOT_HANDLED;
791
792 if (edit_widget_is_editor (we))
793 {
794 gboolean ext_mode;
795 long command;
796
797 /* keep and then extmod flag */
798 ext_mode = we->ext_mode;
799 command = widget_lookup_key (we, parm);
800 we->ext_mode = ext_mode;
801
802 if (command == CK_IgnoreKey)
803 we->ext_mode = FALSE;
804 else
805 {
806 ret = edit_dialog_command_execute (h, command);
807 /* if command was not handled, keep the extended mode
808 for the further key processing */
809 if (ret == MSG_HANDLED)
810 we->ext_mode = FALSE;
811 }
812 }
813
814 /*
815 * Due to the "end of bracket" escape the editor sees input with is_idle() == false
816 * (expects more characters) and hence doesn't yet refresh the screen, but then
817 * no further characters arrive (there's only an "end of bracket" which is swallowed
818 * by tty_get_event()), so you end up with a screen that's not refreshed after pasting.
819 * So let's trigger an IDLE signal.
820 */
821 if (!is_idle ())
822 widget_idle (w, TRUE);
823 return ret;
824 }
825
826 /* hardcoded menu hotkeys (see edit_drop_hotkey_menu) */
827 case MSG_UNHANDLED_KEY:
828 return edit_drop_hotkey_menu (h, parm) ? MSG_HANDLED : MSG_NOT_HANDLED;
829
830 case MSG_VALIDATE:
831 edit_quit (h);
832 return MSG_HANDLED;
833
834 case MSG_DESTROY:
835 edit_dlg_deinit ();
836 return MSG_HANDLED;
837
838 case MSG_IDLE:
839 widget_idle (w, FALSE);
840 return send_message (g->current->data, NULL, MSG_IDLE, 0, NULL);
841
842 default:
843 return dlg_default_callback (w, sender, msg, parm, data);
844 }
845 }
846
847 /* --------------------------------------------------------------------------------------------- */
848
849 /**
850 * Handle mouse events of editor screen.
851 *
852 * @param w Widget object (the editor)
853 * @param msg mouse event message
854 * @param event mouse event data
855 */
856 static void
edit_dialog_mouse_callback(Widget * w,mouse_msg_t msg,mouse_event_t * event)857 edit_dialog_mouse_callback (Widget * w, mouse_msg_t msg, mouse_event_t * event)
858 {
859 gboolean unhandled = TRUE;
860
861 if (msg == MSG_MOUSE_DOWN && event->y == 0)
862 {
863 WGroup *g = GROUP (w);
864 WDialog *h = DIALOG (w);
865 WMenuBar *b;
866
867 b = find_menubar (h);
868
869 if (!widget_get_state (WIDGET (b), WST_FOCUSED))
870 {
871 /* menubar */
872
873 GList *l;
874 GList *top = NULL;
875 int x;
876
877 /* Try find top fullscreen window */
878 for (l = g->widgets; l != NULL; l = g_list_next (l))
879 if (edit_widget_is_editor (CONST_WIDGET (l->data))
880 && ((WEdit *) l->data)->fullscreen)
881 top = l;
882
883 /* Handle fullscreen/close buttons in the top line */
884 x = w->cols - 6;
885
886 if (top != NULL && event->x >= x)
887 {
888 WEdit *e = (WEdit *) top->data;
889
890 if (top != g->current)
891 {
892 /* Window is not active. Activate it */
893 widget_select (WIDGET (e));
894 }
895
896 /* Handle buttons */
897 if (event->x - x <= 2)
898 edit_toggle_fullscreen (e);
899 else
900 send_message (h, NULL, MSG_ACTION, CK_Close, NULL);
901
902 unhandled = FALSE;
903 }
904
905 if (unhandled)
906 menubar_activate (b, drop_menus, -1);
907 }
908 }
909
910 /* Continue handling of unhandled event in window or menu */
911 event->result.abort = unhandled;
912 }
913
914 /* --------------------------------------------------------------------------------------------- */
915
916 static cb_ret_t
edit_dialog_bg_callback(Widget * w,Widget * sender,widget_msg_t msg,int parm,void * data)917 edit_dialog_bg_callback (Widget * w, Widget * sender, widget_msg_t msg, int parm, void *data)
918 {
919 switch (msg)
920 {
921 case MSG_INIT:
922 {
923 Widget *wo = WIDGET (w->owner);
924
925 w->y = wo->y + 1;
926 w->x = wo->x;
927 w->lines = wo->lines - 2;
928 w->cols = wo->cols;
929 w->pos_flags |= WPOS_KEEP_ALL;
930
931 return MSG_HANDLED;
932 }
933
934 default:
935 return background_callback (w, sender, msg, parm, data);
936 }
937 }
938
939 /* --------------------------------------------------------------------------------------------- */
940
941 static cb_ret_t
edit_callback(Widget * w,Widget * sender,widget_msg_t msg,int parm,void * data)942 edit_callback (Widget * w, Widget * sender, widget_msg_t msg, int parm, void *data)
943 {
944 WEdit *e = (WEdit *) w;
945
946 switch (msg)
947 {
948 case MSG_FOCUS:
949 edit_set_buttonbar (e, find_buttonbar (DIALOG (w->owner)));
950 return MSG_HANDLED;
951
952 case MSG_DRAW:
953 e->force |= REDRAW_COMPLETELY;
954 edit_update_screen (e);
955 return MSG_HANDLED;
956
957 case MSG_KEY:
958 {
959 int cmd, ch;
960 cb_ret_t ret = MSG_NOT_HANDLED;
961
962 /* The user may override the access-keys for the menu bar. */
963 if (macro_index == -1 && edit_execute_macro (e, parm))
964 {
965 edit_update_screen (e);
966 ret = MSG_HANDLED;
967 }
968 else if (edit_translate_key (e, parm, &cmd, &ch))
969 {
970 edit_execute_key_command (e, cmd, ch);
971 edit_update_screen (e);
972 ret = MSG_HANDLED;
973 }
974
975 return ret;
976 }
977
978 case MSG_ACTION:
979 /* command from menubar or buttonbar */
980 edit_execute_key_command (e, parm, -1);
981 edit_update_screen (e);
982 return MSG_HANDLED;
983
984 case MSG_CURSOR:
985 {
986 int y, x;
987
988 y = (e->fullscreen ? 0 : 1) + EDIT_TEXT_VERTICAL_OFFSET + e->curs_row;
989 x = (e->fullscreen ? 0 : 1) + EDIT_TEXT_HORIZONTAL_OFFSET + option_line_state_width +
990 e->curs_col + e->start_col + e->over_col;
991
992 widget_gotoyx (w, y, x);
993 return MSG_HANDLED;
994 }
995
996 case MSG_IDLE:
997 edit_update_screen (e);
998 return MSG_HANDLED;
999
1000 case MSG_DESTROY:
1001 edit_clean (e);
1002 return MSG_HANDLED;
1003
1004 default:
1005 return widget_default_callback (w, sender, msg, parm, data);
1006 }
1007 }
1008
1009 /* --------------------------------------------------------------------------------------------- */
1010
1011 /**
1012 * Handle move/resize mouse events.
1013 */
1014 static void
edit_mouse_handle_move_resize(Widget * w,mouse_msg_t msg,mouse_event_t * event)1015 edit_mouse_handle_move_resize (Widget * w, mouse_msg_t msg, mouse_event_t * event)
1016 {
1017 WEdit *edit = (WEdit *) (w);
1018 Widget *h = WIDGET (w->owner);
1019 int global_x, global_y;
1020
1021 if (msg == MSG_MOUSE_UP)
1022 {
1023 /* Exit move/resize mode. */
1024 edit_execute_cmd (edit, CK_Enter, -1);
1025 edit_update_screen (edit); /* Paint the buttonbar over our possibly overlapping frame. */
1026 return;
1027 }
1028
1029 if (msg != MSG_MOUSE_DRAG)
1030 /**
1031 * We ignore any other events. Specifically, MSG_MOUSE_DOWN.
1032 *
1033 * When the move/resize is initiated by the menu, we let the user
1034 * stop it by clicking with the mouse. Which is why we don't want
1035 * a mouse down to affect the window.
1036 */
1037 return;
1038
1039 /* Convert point to global coordinates for easier calculations. */
1040 global_x = event->x + w->x;
1041 global_y = event->y + w->y;
1042
1043 /* Clamp the point to the dialog's client area. */
1044 global_y = CLAMP (global_y, h->y + 1, h->y + h->lines - 2); /* Status line, buttonbar */
1045 global_x = CLAMP (global_x, h->x, h->x + h->cols - 1); /* Currently a no-op, as the dialog has no left/right margins. */
1046
1047 if (edit->drag_state == MCEDIT_DRAG_MOVE)
1048 {
1049 w->y = global_y;
1050 w->x = global_x - edit->drag_state_start;
1051 }
1052 else if (edit->drag_state == MCEDIT_DRAG_RESIZE)
1053 {
1054 w->lines = MAX (WINDOW_MIN_LINES, global_y - w->y + 1);
1055 w->cols = MAX (WINDOW_MIN_COLS, global_x - w->x + 1);
1056 }
1057
1058 edit->force |= REDRAW_COMPLETELY; /* Not really needed as WEdit's MSG_DRAW already does this. */
1059
1060 /* We draw the whole dialog because dragging/resizing exposes area beneath. */
1061 widget_draw (WIDGET (w->owner));
1062 }
1063
1064 /* --------------------------------------------------------------------------------------------- */
1065
1066 /**
1067 * Handle mouse events of editor window
1068 *
1069 * @param w Widget object (the editor window)
1070 * @param msg mouse event message
1071 * @param event mouse event data
1072 */
1073 static void
edit_mouse_callback(Widget * w,mouse_msg_t msg,mouse_event_t * event)1074 edit_mouse_callback (Widget * w, mouse_msg_t msg, mouse_event_t * event)
1075 {
1076 WEdit *edit = (WEdit *) w;
1077 /* buttons' distance from right edge */
1078 int dx = edit->fullscreen ? 0 : 2;
1079 /* location of 'Close' and 'Toggle fullscreen' pictograms */
1080 int close_x, toggle_fullscreen_x;
1081
1082 close_x = (w->cols - 1) - dx - 1;
1083 toggle_fullscreen_x = close_x - 3;
1084
1085 if (edit->drag_state != MCEDIT_DRAG_NONE)
1086 {
1087 /* window is being resized/moved */
1088 edit_mouse_handle_move_resize (w, msg, event);
1089 return;
1090 }
1091
1092 /* If it's the last line on the screen, we abort the event to make the
1093 * system channel it to the overlapping buttonbar instead. We have to do
1094 * this because a WEdit has the WOP_TOP_SELECT flag, which makes it above
1095 * the buttonbar in Z-order. */
1096 if (msg == MSG_MOUSE_DOWN && (event->y + w->y == LINES - 1))
1097 {
1098 event->result.abort = TRUE;
1099 return;
1100 }
1101
1102 switch (msg)
1103 {
1104 case MSG_MOUSE_DOWN:
1105 widget_select (w);
1106 edit_update_curs_row (edit);
1107 edit_update_curs_col (edit);
1108
1109 if (!edit->fullscreen)
1110 {
1111 if (event->y == 0)
1112 {
1113 if (event->x >= close_x - 1 && event->x <= close_x + 1)
1114 ; /* do nothing (see MSG_MOUSE_CLICK) */
1115 else if (event->x >= toggle_fullscreen_x - 1 && event->x <= toggle_fullscreen_x + 1)
1116 ; /* do nothing (see MSG_MOUSE_CLICK) */
1117 else
1118 {
1119 /* start window move */
1120 edit_execute_cmd (edit, CK_WindowMove, -1);
1121 edit_update_screen (edit); /* Paint the buttonbar over our possibly overlapping frame. */
1122 edit->drag_state_start = event->x;
1123 }
1124 break;
1125 }
1126
1127 if (event->y == w->lines - 1 && event->x == w->cols - 1)
1128 {
1129 /* bottom-right corner -- start window resize */
1130 edit_execute_cmd (edit, CK_WindowResize, -1);
1131 break;
1132 }
1133 }
1134
1135 MC_FALLTHROUGH; /* to start/stop text selection */
1136
1137 case MSG_MOUSE_UP:
1138 edit_update_cursor (edit, event);
1139 edit_total_update (edit);
1140 break;
1141
1142 case MSG_MOUSE_CLICK:
1143 if (event->y == 0)
1144 {
1145 if (event->x >= close_x - 1 && event->x <= close_x + 1)
1146 send_message (w->owner, NULL, MSG_ACTION, CK_Close, NULL);
1147 else if (event->x >= toggle_fullscreen_x - 1 && event->x <= toggle_fullscreen_x + 1)
1148 edit_toggle_fullscreen (edit);
1149 else if (!edit->fullscreen && event->count == GPM_DOUBLE)
1150 /* double click on top line (toggle fullscreen) */
1151 edit_toggle_fullscreen (edit);
1152 }
1153 else if (event->count == GPM_DOUBLE)
1154 {
1155 /* double click */
1156 edit_mark_current_word_cmd (edit);
1157 edit_total_update (edit);
1158 }
1159 else if (event->count == GPM_TRIPLE)
1160 {
1161 /* triple click: works in GPM only, not in xterm */
1162 edit_mark_current_line_cmd (edit);
1163 edit_total_update (edit);
1164 }
1165 break;
1166
1167 case MSG_MOUSE_DRAG:
1168 edit_update_cursor (edit, event);
1169 edit_total_update (edit);
1170 break;
1171
1172 case MSG_MOUSE_SCROLL_UP:
1173 edit_move_up (edit, 2, TRUE);
1174 edit_total_update (edit);
1175 break;
1176
1177 case MSG_MOUSE_SCROLL_DOWN:
1178 edit_move_down (edit, 2, TRUE);
1179 edit_total_update (edit);
1180 break;
1181
1182 default:
1183 break;
1184 }
1185 }
1186
1187 /* --------------------------------------------------------------------------------------------- */
1188 /*** public functions ****************************************************************************/
1189 /* --------------------------------------------------------------------------------------------- */
1190 /**
1191 * Edit one file.
1192 *
1193 * @param file_vpath file object
1194 * @param line line number
1195 * @return TRUE if no errors was occurred, FALSE otherwise
1196 */
1197
1198 gboolean
edit_file(const vfs_path_t * file_vpath,long line)1199 edit_file (const vfs_path_t * file_vpath, long line)
1200 {
1201 mcedit_arg_t arg = { (vfs_path_t *) file_vpath, line };
1202 GList *files;
1203 gboolean ok;
1204
1205 files = g_list_prepend (NULL, &arg);
1206 ok = edit_files (files);
1207 g_list_free (files);
1208
1209 return ok;
1210 }
1211
1212 /* --------------------------------------------------------------------------------------------- */
1213
1214 gboolean
edit_files(const GList * files)1215 edit_files (const GList * files)
1216 {
1217 static gboolean made_directory = FALSE;
1218 WDialog *edit_dlg;
1219 WGroup *g;
1220 WMenuBar *menubar;
1221 Widget *w, *wd;
1222 const GList *file;
1223 gboolean ok = FALSE;
1224
1225 if (!made_directory)
1226 {
1227 char *dir;
1228
1229 dir = mc_build_filename (mc_config_get_cache_path (), EDIT_HOME_DIR, (char *) NULL);
1230 made_directory = (mkdir (dir, 0700) != -1 || errno == EEXIST);
1231 g_free (dir);
1232
1233 dir = mc_build_filename (mc_config_get_path (), EDIT_HOME_DIR, (char *) NULL);
1234 made_directory = (mkdir (dir, 0700) != -1 || errno == EEXIST);
1235 g_free (dir);
1236
1237 dir = mc_build_filename (mc_config_get_data_path (), EDIT_HOME_DIR, (char *) NULL);
1238 made_directory = (mkdir (dir, 0700) != -1 || errno == EEXIST);
1239 g_free (dir);
1240 }
1241
1242 /* Create a new dialog and add it widgets to it */
1243 edit_dlg =
1244 dlg_create (FALSE, 0, 0, 1, 1, WPOS_FULLSCREEN, FALSE, NULL, edit_dialog_callback,
1245 edit_dialog_mouse_callback, "[Internal File Editor]", NULL);
1246 wd = WIDGET (edit_dlg);
1247 widget_want_tab (wd, TRUE);
1248 wd->keymap = editor_map;
1249 wd->ext_keymap = editor_x_map;
1250
1251 edit_dlg->get_shortcut = edit_get_shortcut;
1252 edit_dlg->get_title = edit_get_title;
1253
1254 g = GROUP (edit_dlg);
1255
1256 edit_dlg->bg =
1257 WIDGET (background_new
1258 (1, 0, wd->lines - 2, wd->cols, EDITOR_BACKGROUND, ' ', edit_dialog_bg_callback));
1259 group_add_widget (g, edit_dlg->bg);
1260
1261 menubar = menubar_new (NULL);
1262 w = WIDGET (menubar);
1263 group_add_widget_autopos (g, w, w->pos_flags, NULL);
1264 edit_init_menu (menubar);
1265
1266 w = WIDGET (buttonbar_new ());
1267 group_add_widget_autopos (g, w, w->pos_flags, NULL);
1268
1269 for (file = files; file != NULL; file = g_list_next (file))
1270 {
1271 mcedit_arg_t *f = (mcedit_arg_t *) file->data;
1272 gboolean f_ok;
1273
1274 f_ok = edit_add_window (edit_dlg, wd->y + 1, wd->x, wd->lines - 2, wd->cols, f->file_vpath,
1275 f->line_number);
1276 /* at least one file has been opened succefully */
1277 ok = ok || f_ok;
1278 }
1279
1280 if (ok)
1281 dlg_run (edit_dlg);
1282
1283 if (!ok || widget_get_state (wd, WST_CLOSED))
1284 widget_destroy (wd);
1285
1286 return ok;
1287 }
1288
1289 /* --------------------------------------------------------------------------------------------- */
1290
1291 const char *
edit_get_file_name(const WEdit * edit)1292 edit_get_file_name (const WEdit * edit)
1293 {
1294 return vfs_path_as_str (edit->filename_vpath);
1295 }
1296
1297 /* --------------------------------------------------------------------------------------------- */
1298
1299 WEdit *
find_editor(const WDialog * h)1300 find_editor (const WDialog * h)
1301 {
1302 const WGroup *g = CONST_GROUP (h);
1303
1304 if (edit_widget_is_editor (CONST_WIDGET (g->current->data)))
1305 return (WEdit *) g->current->data;
1306 return (WEdit *) widget_find_by_type (CONST_WIDGET (h), edit_callback);
1307 }
1308
1309 /* --------------------------------------------------------------------------------------------- */
1310 /**
1311 * Check if widget is an WEdit class.
1312 *
1313 * @param w probably editor object
1314 * @return TRUE if widget is an WEdit class, FALSE otherwise
1315 */
1316
1317 gboolean
edit_widget_is_editor(const Widget * w)1318 edit_widget_is_editor (const Widget * w)
1319 {
1320 return (w != NULL && w->callback == edit_callback);
1321 }
1322
1323 /* --------------------------------------------------------------------------------------------- */
1324
1325 void
edit_update_screen(WEdit * e)1326 edit_update_screen (WEdit * e)
1327 {
1328 edit_scroll_screen_over_cursor (e);
1329 edit_update_curs_col (e);
1330 edit_status (e, widget_get_state (WIDGET (e), WST_FOCUSED));
1331
1332 /* pop all events for this window for internal handling */
1333 if (!is_idle ())
1334 e->force |= REDRAW_PAGE;
1335 else
1336 {
1337 if ((e->force & REDRAW_COMPLETELY) != 0)
1338 e->force |= REDRAW_PAGE;
1339 edit_render_keypress (e);
1340 }
1341
1342 widget_draw (WIDGET (find_buttonbar (DIALOG (WIDGET (e)->owner))));
1343 }
1344
1345 /* --------------------------------------------------------------------------------------------- */
1346 /**
1347 * Save current window size.
1348 *
1349 * @param edit editor object
1350 */
1351
1352 void
edit_save_size(WEdit * edit)1353 edit_save_size (WEdit * edit)
1354 {
1355 Widget *w = WIDGET (edit);
1356
1357 rect_init (&edit->loc_prev, w->y, w->x, w->lines, w->cols);
1358 }
1359
1360 /* --------------------------------------------------------------------------------------------- */
1361 /**
1362 * Create new editor window and insert it into editor screen.
1363 *
1364 * @param h editor dialog (screen)
1365 * @param y y coordinate
1366 * @param x x coordinate
1367 * @param lines window height
1368 * @param cols window width
1369 * @param f file object
1370 * @param fline line number in file
1371 * @return TRUE if new window was successfully created and inserted into editor screen,
1372 * FALSE otherwise
1373 */
1374
1375 gboolean
edit_add_window(WDialog * h,int y,int x,int lines,int cols,const vfs_path_t * f,long fline)1376 edit_add_window (WDialog * h, int y, int x, int lines, int cols, const vfs_path_t * f, long fline)
1377 {
1378 WEdit *edit;
1379 Widget *w;
1380
1381 edit = edit_init (NULL, y, x, lines, cols, f, fline);
1382 if (edit == NULL)
1383 return FALSE;
1384
1385 w = WIDGET (edit);
1386 w->callback = edit_callback;
1387 w->mouse_callback = edit_mouse_callback;
1388
1389 group_add_widget_autopos (GROUP (h), w, WPOS_KEEP_ALL, NULL);
1390 edit_set_buttonbar (edit, find_buttonbar (h));
1391 widget_draw (WIDGET (h));
1392
1393 return TRUE;
1394 }
1395
1396 /* --------------------------------------------------------------------------------------------- */
1397 /**
1398 * Handle move/resize events.
1399 *
1400 * @param edit editor object
1401 * @param command action id
1402 * @return TRUE if the action was handled, FALSE otherwise
1403 */
1404
1405 gboolean
edit_handle_move_resize(WEdit * edit,long command)1406 edit_handle_move_resize (WEdit * edit, long command)
1407 {
1408 Widget *w = WIDGET (edit);
1409 gboolean ret = FALSE;
1410
1411 if (edit->fullscreen)
1412 {
1413 edit->drag_state = MCEDIT_DRAG_NONE;
1414 w->mouse.forced_capture = FALSE;
1415 return ret;
1416 }
1417
1418 switch (edit->drag_state)
1419 {
1420 case MCEDIT_DRAG_NONE:
1421 /* possible start move/resize */
1422 switch (command)
1423 {
1424 case CK_WindowMove:
1425 edit->drag_state = MCEDIT_DRAG_MOVE;
1426 edit_save_size (edit);
1427 edit_status (edit, TRUE); /* redraw frame and status */
1428 /**
1429 * If a user initiates a move by the menu, not by the mouse, we
1430 * make a subsequent mouse drag pull the frame from its middle.
1431 * (We can instead choose '0' to pull it from the corner.)
1432 */
1433 edit->drag_state_start = w->cols / 2;
1434 ret = TRUE;
1435 break;
1436 case CK_WindowResize:
1437 edit->drag_state = MCEDIT_DRAG_RESIZE;
1438 edit_save_size (edit);
1439 edit_status (edit, TRUE); /* redraw frame and status */
1440 ret = TRUE;
1441 break;
1442 default:
1443 break;
1444 }
1445 break;
1446
1447 case MCEDIT_DRAG_MOVE:
1448 switch (command)
1449 {
1450 case CK_WindowResize:
1451 edit->drag_state = MCEDIT_DRAG_RESIZE;
1452 ret = TRUE;
1453 break;
1454 case CK_Up:
1455 case CK_Down:
1456 case CK_Left:
1457 case CK_Right:
1458 edit_window_move (edit, command);
1459 ret = TRUE;
1460 break;
1461 case CK_Enter:
1462 case CK_WindowMove:
1463 edit->drag_state = MCEDIT_DRAG_NONE;
1464 edit_status (edit, TRUE); /* redraw frame and status */
1465 MC_FALLTHROUGH;
1466 default:
1467 ret = TRUE;
1468 break;
1469 }
1470 break;
1471
1472 case MCEDIT_DRAG_RESIZE:
1473 switch (command)
1474 {
1475 case CK_WindowMove:
1476 edit->drag_state = MCEDIT_DRAG_MOVE;
1477 ret = TRUE;
1478 break;
1479 case CK_Up:
1480 case CK_Down:
1481 case CK_Left:
1482 case CK_Right:
1483 edit_window_resize (edit, command);
1484 ret = TRUE;
1485 break;
1486 case CK_Enter:
1487 case CK_WindowResize:
1488 edit->drag_state = MCEDIT_DRAG_NONE;
1489 edit_status (edit, TRUE); /* redraw frame and status */
1490 MC_FALLTHROUGH;
1491 default:
1492 ret = TRUE;
1493 break;
1494 }
1495 break;
1496
1497 default:
1498 break;
1499 }
1500
1501 /**
1502 * - We let the user stop a resize/move operation by clicking with the
1503 * mouse anywhere. ("clicking" = pressing and releasing a button.)
1504 * - We let the user perform a resize/move operation by a mouse drag
1505 * initiated anywhere.
1506 *
1507 * "Anywhere" means: inside or outside the window. We make this happen
1508 * with the 'forced_capture' flag.
1509 */
1510 w->mouse.forced_capture = (edit->drag_state != MCEDIT_DRAG_NONE);
1511
1512 return ret;
1513 }
1514
1515 /* --------------------------------------------------------------------------------------------- */
1516 /**
1517 * Toggle window fuulscreen mode.
1518 *
1519 * @param edit editor object
1520 */
1521
1522 void
edit_toggle_fullscreen(WEdit * edit)1523 edit_toggle_fullscreen (WEdit * edit)
1524 {
1525 Widget *w = WIDGET (edit);
1526
1527 edit->fullscreen = !edit->fullscreen;
1528 edit->force = REDRAW_COMPLETELY;
1529
1530 if (!edit->fullscreen)
1531 {
1532 edit_restore_size (edit);
1533 /* do not follow screen size on resize */
1534 w->pos_flags = WPOS_KEEP_DEFAULT;
1535 }
1536 else
1537 {
1538 Widget *h = WIDGET (w->owner);
1539
1540 edit_save_size (edit);
1541 widget_set_size (w, h->y + 1, h->x, h->lines - 2, h->cols);
1542 /* follow screen size on resize */
1543 w->pos_flags = WPOS_KEEP_ALL;
1544 edit->force |= REDRAW_PAGE;
1545 edit_update_screen (edit);
1546 }
1547 }
1548
1549 /* --------------------------------------------------------------------------------------------- */
1550