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_callback
  21. edit_mouse_handle_move_resize
  22. edit_mouse_callback
  23. edit_file
  24. edit_files
  25. edit_get_file_name
  26. find_editor
  27. edit_widget_is_editor
  28. edit_update_screen
  29. edit_save_size
  30. edit_add_window
  31. edit_handle_move_resize
  32. edit_toggle_fullscreen

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

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