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