root/src/editor/editwidget.c

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

DEFINITIONS

This source file includes following definitions.
  1. edit_dlg_init
  2. edit_dlg_deinit
  3. edit_about
  4. edit_help
  5. edit_restore_size
  6. edit_window_move
  7. edit_window_resize
  8. get_hotkey
  9. edit_window_list
  10. edit_get_shortcut
  11. edit_get_title
  12. edit_dialog_command_execute
  13. edit_translate_key
  14. edit_quit
  15. edit_set_buttonbar
  16. edit_total_update
  17. edit_update_cursor
  18. edit_dialog_callback
  19. edit_dialog_mouse_callback
  20. edit_dialog_bg_callback
  21. edit_callback
  22. edit_mouse_handle_move_resize
  23. edit_mouse_callback
  24. edit_file
  25. edit_files
  26. edit_get_file_name
  27. find_editor
  28. edit_widget_is_editor
  29. edit_update_screen
  30. edit_save_size
  31. edit_add_window
  32. edit_handle_move_resize
  33. edit_toggle_fullscreen

   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
  98 edit_dlg_init (void)
     /* [previous][next][first][last][top][bottom][index][help]  */
  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
 119 edit_dlg_deinit (void)
     /* [previous][next][first][last][top][bottom][index][help]  */
 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
 141 edit_about (void)
     /* [previous][next][first][last][top][bottom][index][help]  */
 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
 184 edit_help (void)
     /* [previous][next][first][last][top][bottom][index][help]  */
 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
 198 edit_restore_size (WEdit * edit)
     /* [previous][next][first][last][top][bottom][index][help]  */
 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
 217 edit_window_move (WEdit * edit, long command)
     /* [previous][next][first][last][top][bottom][index][help]  */
 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
 257 edit_window_resize (WEdit * edit, long command)
     /* [previous][next][first][last][top][bottom][index][help]  */
 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
 297 get_hotkey (int n)
     /* [previous][next][first][last][top][bottom][index][help]  */
 298 {
 299     return (n <= 9) ? '0' + n : 'a' + n - 10;
 300 }
 301 
 302 /* --------------------------------------------------------------------------------------------- */
 303 
 304 static void
 305 edit_window_list (const WDialog * h)
     /* [previous][next][first][last][top][bottom][index][help]  */
 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 *
 347 edit_get_shortcut (long command)
     /* [previous][next][first][last][top][bottom][index][help]  */
 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 *
 368 edit_get_title (const WDialog * h, size_t len)
     /* [previous][next][first][last][top][bottom][index][help]  */
 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
 391 edit_dialog_command_execute (WDialog * h, long command)
     /* [previous][next][first][last][top][bottom][index][help]  */
 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
 501 edit_translate_key (WEdit * edit, long x_key, int *cmd, int *ch)
     /* [previous][next][first][last][top][bottom][index][help]  */
 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
 616 edit_quit (WDialog * h)
     /* [previous][next][first][last][top][bottom][index][help]  */
 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
 665 edit_set_buttonbar (WEdit * edit, WButtonBar * bb)
     /* [previous][next][first][last][top][bottom][index][help]  */
 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
 684 edit_total_update (WEdit * edit)
     /* [previous][next][first][last][top][bottom][index][help]  */
 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
 695 edit_update_cursor (WEdit * edit, const mouse_event_t * event)
     /* [previous][next][first][last][top][bottom][index][help]  */
 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
 755 edit_dialog_callback (Widget * w, Widget * sender, widget_msg_t msg, int parm, void *data)
     /* [previous][next][first][last][top][bottom][index][help]  */
 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
 857 edit_dialog_mouse_callback (Widget * w, mouse_msg_t msg, mouse_event_t * event)
     /* [previous][next][first][last][top][bottom][index][help]  */
 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
 917 edit_dialog_bg_callback (Widget * w, Widget * sender, widget_msg_t msg, int parm, void *data)
     /* [previous][next][first][last][top][bottom][index][help]  */
 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
 942 edit_callback (Widget * w, Widget * sender, widget_msg_t msg, int parm, void *data)
     /* [previous][next][first][last][top][bottom][index][help]  */
 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
1015 edit_mouse_handle_move_resize (Widget * w, mouse_msg_t msg, mouse_event_t * event)
     /* [previous][next][first][last][top][bottom][index][help]  */
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
1074 edit_mouse_callback (Widget * w, mouse_msg_t msg, mouse_event_t * event)
     /* [previous][next][first][last][top][bottom][index][help]  */
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
1199 edit_file (const vfs_path_t * file_vpath, long line)
     /* [previous][next][first][last][top][bottom][index][help]  */
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
1215 edit_files (const GList * files)
     /* [previous][next][first][last][top][bottom][index][help]  */
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 *
1292 edit_get_file_name (const WEdit * edit)
     /* [previous][next][first][last][top][bottom][index][help]  */
1293 {
1294     return vfs_path_as_str (edit->filename_vpath);
1295 }
1296 
1297 /* --------------------------------------------------------------------------------------------- */
1298 
1299 WEdit *
1300 find_editor (const WDialog * h)
     /* [previous][next][first][last][top][bottom][index][help]  */
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
1318 edit_widget_is_editor (const Widget * w)
     /* [previous][next][first][last][top][bottom][index][help]  */
1319 {
1320     return (w != NULL && w->callback == edit_callback);
1321 }
1322 
1323 /* --------------------------------------------------------------------------------------------- */
1324 
1325 void
1326 edit_update_screen (WEdit * e)
     /* [previous][next][first][last][top][bottom][index][help]  */
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
1353 edit_save_size (WEdit * edit)
     /* [previous][next][first][last][top][bottom][index][help]  */
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
1376 edit_add_window (WDialog * h, int y, int x, int lines, int cols, const vfs_path_t * f, long fline)
     /* [previous][next][first][last][top][bottom][index][help]  */
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
1406 edit_handle_move_resize (WEdit * edit, long command)
     /* [previous][next][first][last][top][bottom][index][help]  */
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
1523 edit_toggle_fullscreen (WEdit * edit)
     /* [previous][next][first][last][top][bottom][index][help]  */
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 /* --------------------------------------------------------------------------------------------- */

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