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

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