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

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