root/src/viewer/actions_cmd.c

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

DEFINITIONS

This source file includes following definitions.
  1. mcview_remove_ext_script
  2. mcview_search
  3. mcview_continue_search_cmd
  4. mcview_hook
  5. mcview_handle_editkey
  6. mcview_load_next_prev_init
  7. mcview_scan_for_file
  8. mcview_load_next_prev
  9. mcview_load_file_from_history
  10. mcview_execute_cmd
  11. mcview_lookup_key
  12. mcview_handle_key
  13. mcview_resize
  14. mcview_ok_to_quit
  15. mcview_callback
  16. mcview_dialog_callback

   1 /*
   2    Internal file viewer for the Midnight Commander
   3    Callback function for some actions (hotkeys, menu)
   4 
   5    Copyright (C) 1994-2020
   6    Free Software Foundation, Inc.
   7 
   8    Written by:
   9    Miguel de Icaza, 1994, 1995, 1998
  10    Janne Kukonlehto, 1994, 1995
  11    Jakub Jelinek, 1995
  12    Joseph M. Hinkle, 1996
  13    Norbert Warmuth, 1997
  14    Pavel Machek, 1998
  15    Roland Illig <roland.illig@gmx.de>, 2004, 2005
  16    Slava Zanko <slavazanko@google.com>, 2009, 2013
  17    Andrew Borodin <aborodin@vmail.ru>, 2009, 2013
  18    Ilia Maslakov <il.smind@gmail.com>, 2009
  19 
  20    This file is part of the Midnight Commander.
  21 
  22    The Midnight Commander is free software: you can redistribute it
  23    and/or modify it under the terms of the GNU General Public License as
  24    published by the Free Software Foundation, either version 3 of the License,
  25    or (at your option) any later version.
  26 
  27    The Midnight Commander is distributed in the hope that it will be useful,
  28    but WITHOUT ANY WARRANTY; without even the implied warranty of
  29    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  30    GNU General Public License for more details.
  31 
  32    You should have received a copy of the GNU General Public License
  33    along with this program.  If not, see <http://www.gnu.org/licenses/>.
  34  */
  35 
  36 /*
  37    The functions in this section can be bound to hotkeys. They are all
  38    of the same type (taking a pointer to WView as parameter and
  39    returning void). TODO: In the not-too-distant future, these commands
  40    will become fully configurable, like they already are in the
  41    internal editor. By convention, all the function names end in
  42    "_cmd".
  43  */
  44 
  45 #include <config.h>
  46 
  47 #include <errno.h>
  48 #include <stdlib.h>
  49 
  50 #include "lib/global.h"
  51 
  52 #include "lib/tty/tty.h"
  53 #include "lib/tty/key.h"        /* is_idle() */
  54 #include "lib/lock.h"           /* lock_file() */
  55 #include "lib/util.h"
  56 #include "lib/widget.h"
  57 #ifdef HAVE_CHARSET
  58 #include "lib/charsets.h"
  59 #endif
  60 #include "lib/event.h"          /* mc_event_raise() */
  61 #include "lib/mcconfig.h"       /* mc_config_history_get() */
  62 
  63 #include "src/filemanager/layout.h"
  64 #include "src/filemanager/midnight.h"   /* current_panel */
  65 #include "src/filemanager/ext.h"        /* regex_command_for() */
  66 
  67 #include "src/history.h"
  68 #include "src/file_history.h"   /* show_file_history() */
  69 #include "src/execute.h"
  70 #include "src/keybind-defaults.h"
  71 
  72 #include "internal.h"
  73 
  74 /*** global variables ****************************************************************************/
  75 
  76 /*** file scope macro definitions ****************************************************************/
  77 
  78 /*** file scope type declarations ****************************************************************/
  79 
  80 /*** file scope variables ************************************************************************/
  81 
  82 /* --------------------------------------------------------------------------------------------- */
  83 /*** file scope functions ************************************************************************/
  84 /* --------------------------------------------------------------------------------------------- */
  85 
  86 static void
  87 mcview_remove_ext_script (WView * view)
     /* [previous][next][first][last][top][bottom][index][help]  */
  88 {
  89     if (view->ext_script != NULL)
  90     {
  91         mc_unlink (view->ext_script);
  92         vfs_path_free (view->ext_script);
  93         view->ext_script = NULL;
  94     }
  95 }
  96 
  97 /* --------------------------------------------------------------------------------------------- */
  98 
  99 /* Both views */
 100 static void
 101 mcview_search (WView * view, gboolean start_search)
     /* [previous][next][first][last][top][bottom][index][help]  */
 102 {
 103     off_t want_search_start = view->search_start;
 104 
 105     if (start_search)
 106     {
 107         if (mcview_dialog_search (view))
 108         {
 109             if (view->mode_flags.hex)
 110                 want_search_start = view->hex_cursor;
 111 
 112             mcview_do_search (view, want_search_start);
 113         }
 114     }
 115     else
 116     {
 117         if (view->mode_flags.hex)
 118         {
 119             if (!mcview_search_options.backwards)
 120                 want_search_start = view->hex_cursor + 1;
 121             else if (view->hex_cursor > 0)
 122                 want_search_start = view->hex_cursor - 1;
 123             else
 124                 want_search_start = 0;
 125         }
 126 
 127         mcview_do_search (view, want_search_start);
 128     }
 129 }
 130 
 131 /* --------------------------------------------------------------------------------------------- */
 132 
 133 static void
 134 mcview_continue_search_cmd (WView * view)
     /* [previous][next][first][last][top][bottom][index][help]  */
 135 {
 136     if (view->last_search_string != NULL)
 137         mcview_search (view, FALSE);
 138     else
 139     {
 140         /* find last search string in history */
 141         GList *history;
 142 
 143         history = mc_config_history_get (MC_HISTORY_SHARED_SEARCH);
 144         if (history != NULL && history->data != NULL)
 145         {
 146             view->last_search_string = (gchar *) g_strdup (history->data);
 147             history = g_list_first (history);
 148             g_list_free_full (history, g_free);
 149 
 150 #ifdef HAVE_CHARSET
 151             view->search = mc_search_new (view->last_search_string, cp_source);
 152 #else
 153             view->search = mc_search_new (view->last_search_string, NULL);
 154 #endif
 155             view->search_nroff_seq = mcview_nroff_seq_new (view);
 156 
 157             if (view->search == NULL)
 158             {
 159                 /* if not... then ask for an expression */
 160                 MC_PTR_FREE (view->last_search_string);
 161                 mcview_search (view, TRUE);
 162             }
 163             else
 164             {
 165                 view->search->search_type = mcview_search_options.type;
 166 #ifdef HAVE_CHARSET
 167                 view->search->is_all_charsets = mcview_search_options.all_codepages;
 168 #endif
 169                 view->search->is_case_sensitive = mcview_search_options.case_sens;
 170                 view->search->whole_words = mcview_search_options.whole_words;
 171                 view->search->search_fn = mcview_search_cmd_callback;
 172                 view->search->update_fn = mcview_search_update_cmd_callback;
 173 
 174                 mcview_search (view, FALSE);
 175             }
 176         }
 177         else
 178         {
 179             /* if not... then ask for an expression */
 180             MC_PTR_FREE (view->last_search_string);
 181             mcview_search (view, TRUE);
 182         }
 183     }
 184 }
 185 
 186 /* --------------------------------------------------------------------------------------------- */
 187 
 188 static void
 189 mcview_hook (void *v)
     /* [previous][next][first][last][top][bottom][index][help]  */
 190 {
 191     WView *view = (WView *) v;
 192     WPanel *panel;
 193 
 194     /* If the user is busy typing, wait until he finishes to update the
 195        screen */
 196     if (!is_idle ())
 197     {
 198         if (!hook_present (idle_hook, mcview_hook))
 199             add_hook (&idle_hook, mcview_hook, v);
 200         return;
 201     }
 202 
 203     delete_hook (&idle_hook, mcview_hook);
 204 
 205     if (get_current_type () == view_listing)
 206         panel = current_panel;
 207     else if (get_other_type () == view_listing)
 208         panel = other_panel;
 209     else
 210         return;
 211 
 212     mcview_done (view);
 213     mcview_init (view);
 214     mcview_load (view, 0, panel->dir.list[panel->selected].fname, 0, 0, 0);
 215     mcview_display (view);
 216 }
 217 
 218 /* --------------------------------------------------------------------------------------------- */
 219 
 220 static cb_ret_t
 221 mcview_handle_editkey (WView * view, int key)
     /* [previous][next][first][last][top][bottom][index][help]  */
 222 {
 223     struct hexedit_change_node *node;
 224     int byte_val = -1;
 225 
 226     /* Has there been a change at this position? */
 227     node = view->change_list;
 228     while ((node != NULL) && (node->offset != view->hex_cursor))
 229         node = node->next;
 230 
 231     if (!view->hexview_in_text)
 232     {
 233         /* Hex editing */
 234         unsigned int hexvalue = 0;
 235 
 236         if (key >= '0' && key <= '9')
 237             hexvalue = 0 + (key - '0');
 238         else if (key >= 'A' && key <= 'F')
 239             hexvalue = 10 + (key - 'A');
 240         else if (key >= 'a' && key <= 'f')
 241             hexvalue = 10 + (key - 'a');
 242         else
 243             return MSG_NOT_HANDLED;
 244 
 245         if (node != NULL)
 246             byte_val = node->value;
 247         else
 248             mcview_get_byte (view, view->hex_cursor, &byte_val);
 249 
 250         if (view->hexedit_lownibble)
 251             byte_val = (byte_val & 0xf0) | (hexvalue);
 252         else
 253             byte_val = (byte_val & 0x0f) | (hexvalue << 4);
 254     }
 255     else
 256     {
 257         /* Text editing */
 258         if (key < 256 && key != '\t')
 259             byte_val = key;
 260         else
 261             return MSG_NOT_HANDLED;
 262     }
 263 
 264     if ((view->filename_vpath != NULL)
 265         && (*(vfs_path_get_last_path_str (view->filename_vpath)) != '\0')
 266         && (view->change_list == NULL))
 267         view->locked = lock_file (view->filename_vpath);
 268 
 269     if (node == NULL)
 270     {
 271         node = g_new (struct hexedit_change_node, 1);
 272         node->offset = view->hex_cursor;
 273         node->value = byte_val;
 274         mcview_enqueue_change (&view->change_list, node);
 275     }
 276     else
 277         node->value = byte_val;
 278 
 279     view->dirty++;
 280     mcview_move_right (view, 1);
 281 
 282     return MSG_HANDLED;
 283 }
 284 
 285 /* --------------------------------------------------------------------------------------------- */
 286 
 287 static void
 288 mcview_load_next_prev_init (WView * view)
     /* [previous][next][first][last][top][bottom][index][help]  */
 289 {
 290     if (mc_global.mc_run_mode != MC_RUN_VIEWER)
 291     {
 292         /* get file list from current panel. Update it each time */
 293         view->dir = &current_panel->dir;
 294         view->dir_idx = &current_panel->selected;
 295     }
 296     else if (view->dir == NULL)
 297     {
 298         /* Run from command line */
 299         /* Run 1st time. Load/get directory */
 300 
 301         /* TODO: check mtime of directory to reload it */
 302 
 303         dir_sort_options_t sort_op = { FALSE, TRUE, FALSE };
 304 
 305         /* load directory where requested file is */
 306         view->dir = g_new0 (dir_list, 1);
 307         view->dir_idx = g_new (int, 1);
 308 
 309         if (dir_list_load
 310             (view->dir, view->workdir_vpath, (GCompareFunc) sort_name, &sort_op, NULL))
 311         {
 312             const char *fname;
 313             size_t fname_len;
 314             int i;
 315 
 316             fname = x_basename (vfs_path_as_str (view->filename_vpath));
 317             fname_len = strlen (fname);
 318 
 319             /* search current file in the list */
 320             for (i = 0; i != view->dir->len; i++)
 321             {
 322                 const file_entry_t *fe = &view->dir->list[i];
 323 
 324                 if (fname_len == fe->fnamelen && strncmp (fname, fe->fname, fname_len) == 0)
 325                     break;
 326             }
 327 
 328             *view->dir_idx = i;
 329         }
 330         else
 331         {
 332             message (D_ERROR, MSG_ERROR, _("Cannot read directory contents"));
 333             MC_PTR_FREE (view->dir);
 334             MC_PTR_FREE (view->dir_idx);
 335         }
 336     }
 337 }
 338 
 339 /* --------------------------------------------------------------------------------------------- */
 340 
 341 static void
 342 mcview_scan_for_file (WView * view, int direction)
     /* [previous][next][first][last][top][bottom][index][help]  */
 343 {
 344     int i;
 345 
 346     for (i = *view->dir_idx + direction; i != *view->dir_idx; i += direction)
 347     {
 348         if (i < 0)
 349             i = view->dir->len - 1;
 350         if (i == view->dir->len)
 351             i = 0;
 352         if (!S_ISDIR (view->dir->list[i].st.st_mode))
 353             break;
 354     }
 355 
 356     *view->dir_idx = i;
 357 }
 358 
 359 /* --------------------------------------------------------------------------------------------- */
 360 
 361 static void
 362 mcview_load_next_prev (WView * view, int direction)
     /* [previous][next][first][last][top][bottom][index][help]  */
 363 {
 364     dir_list *dir;
 365     int *dir_idx;
 366     vfs_path_t *vfile;
 367     vfs_path_t *ext_script = NULL;
 368 
 369     mcview_load_next_prev_init (view);
 370     mcview_scan_for_file (view, direction);
 371 
 372     /* reinit view */
 373     dir = view->dir;
 374     dir_idx = view->dir_idx;
 375     view->dir = NULL;
 376     view->dir_idx = NULL;
 377     vfile = vfs_path_append_new (view->workdir_vpath, dir->list[*dir_idx].fname, (char *) NULL);
 378     mcview_done (view);
 379     mcview_remove_ext_script (view);
 380     mcview_init (view);
 381     if (regex_command_for (view, vfile, "View", &ext_script) == 0)
 382         mcview_load (view, NULL, vfs_path_as_str (vfile), 0, 0, 0);
 383     vfs_path_free (vfile);
 384     view->dir = dir;
 385     view->dir_idx = dir_idx;
 386     view->ext_script = ext_script;
 387 
 388     view->dpy_bbar_dirty = FALSE;       /* FIXME */
 389     view->dirty++;
 390 }
 391 
 392 /* --------------------------------------------------------------------------------------------- */
 393 
 394 static void
 395 mcview_load_file_from_history (WView * view)
     /* [previous][next][first][last][top][bottom][index][help]  */
 396 {
 397     char *filename;
 398     int action;
 399 
 400     filename = show_file_history (CONST_WIDGET (view), &action);
 401 
 402     if (filename != NULL && (action == CK_View || action == CK_Enter))
 403     {
 404         mcview_done (view);
 405         mcview_init (view);
 406 
 407         mcview_load (view, NULL, filename, 0, 0, 0);
 408 
 409         view->dpy_bbar_dirty = FALSE;   /* FIXME */
 410         view->dirty++;
 411     }
 412 
 413     g_free (filename);
 414 }
 415 
 416 /* --------------------------------------------------------------------------------------------- */
 417 
 418 static cb_ret_t
 419 mcview_execute_cmd (WView * view, long command)
     /* [previous][next][first][last][top][bottom][index][help]  */
 420 {
 421     int res = MSG_HANDLED;
 422 
 423     switch (command)
 424     {
 425     case CK_Help:
 426         {
 427             ev_help_t event_data = { NULL, "[Internal File Viewer]" };
 428             mc_event_raise (MCEVENT_GROUP_CORE, "help", &event_data);
 429         }
 430         break;
 431     case CK_HexMode:
 432         /* Toggle between hex view and text view */
 433         mcview_toggle_hex_mode (view);
 434         break;
 435     case CK_HexEditMode:
 436         /* Toggle between hexview and hexedit mode */
 437         mcview_toggle_hexedit_mode (view);
 438         break;
 439     case CK_ToggleNavigation:
 440         view->hexview_in_text = !view->hexview_in_text;
 441         view->dirty++;
 442         break;
 443     case CK_LeftQuick:
 444         if (!view->mode_flags.hex)
 445             mcview_move_left (view, 10);
 446         break;
 447     case CK_RightQuick:
 448         if (!view->mode_flags.hex)
 449             mcview_move_right (view, 10);
 450         break;
 451     case CK_Goto:
 452         {
 453             off_t addr;
 454 
 455             if (mcview_dialog_goto (view, &addr))
 456             {
 457                 if (addr >= 0)
 458                     mcview_moveto_offset (view, addr);
 459                 else
 460                 {
 461                     message (D_ERROR, _("Warning"), "%s", _("Invalid value"));
 462                     view->dirty++;
 463                 }
 464             }
 465             break;
 466         }
 467     case CK_Save:
 468         mcview_hexedit_save_changes (view);
 469         break;
 470     case CK_Search:
 471         mcview_search (view, TRUE);
 472         break;
 473     case CK_SearchContinue:
 474         mcview_continue_search_cmd (view);
 475         break;
 476     case CK_SearchForward:
 477         mcview_search_options.backwards = FALSE;
 478         mcview_search (view, TRUE);
 479         break;
 480     case CK_SearchForwardContinue:
 481         mcview_search_options.backwards = FALSE;
 482         mcview_continue_search_cmd (view);
 483         break;
 484     case CK_SearchBackward:
 485         mcview_search_options.backwards = TRUE;
 486         mcview_search (view, TRUE);
 487         break;
 488     case CK_SearchBackwardContinue:
 489         mcview_search_options.backwards = TRUE;
 490         mcview_continue_search_cmd (view);
 491         break;
 492     case CK_SearchOppositeContinue:
 493         {
 494             gboolean direction;
 495 
 496             direction = mcview_search_options.backwards;
 497             mcview_search_options.backwards = !direction;
 498             mcview_continue_search_cmd (view);
 499             mcview_search_options.backwards = direction;
 500         }
 501         break;
 502     case CK_WrapMode:
 503         /* Toggle between wrapped and unwrapped view */
 504         mcview_toggle_wrap_mode (view);
 505         break;
 506     case CK_MagicMode:
 507         mcview_toggle_magic_mode (view);
 508         break;
 509     case CK_NroffMode:
 510         mcview_toggle_nroff_mode (view);
 511         break;
 512     case CK_Home:
 513         mcview_moveto_bol (view);
 514         break;
 515     case CK_End:
 516         mcview_moveto_eol (view);
 517         break;
 518     case CK_Left:
 519         mcview_move_left (view, 1);
 520         break;
 521     case CK_Right:
 522         mcview_move_right (view, 1);
 523         break;
 524     case CK_Up:
 525         mcview_move_up (view, 1);
 526         break;
 527     case CK_Down:
 528         mcview_move_down (view, 1);
 529         break;
 530     case CK_HalfPageUp:
 531         mcview_move_up (view, (view->data_area.height + 1) / 2);
 532         break;
 533     case CK_HalfPageDown:
 534         mcview_move_down (view, (view->data_area.height + 1) / 2);
 535         break;
 536     case CK_PageUp:
 537         mcview_move_up (view, view->data_area.height);
 538         break;
 539     case CK_PageDown:
 540         mcview_move_down (view, view->data_area.height);
 541         break;
 542     case CK_Top:
 543         mcview_moveto_top (view);
 544         break;
 545     case CK_Bottom:
 546         mcview_moveto_bottom (view);
 547         break;
 548     case CK_Shell:
 549         toggle_subshell ();
 550         break;
 551     case CK_Ruler:
 552         mcview_display_toggle_ruler (view);
 553         break;
 554     case CK_Bookmark:
 555         view->dpy_start = view->marks[view->marker];
 556         view->dpy_paragraph_skip_lines = 0;     /* TODO: remember this value in the marker? */
 557         view->dpy_wrap_dirty = TRUE;
 558         view->dirty++;
 559         break;
 560     case CK_BookmarkGoto:
 561         view->marks[view->marker] = view->dpy_start;
 562         break;
 563 #ifdef HAVE_CHARSET
 564     case CK_SelectCodepage:
 565         mcview_select_encoding (view);
 566         view->dirty++;
 567         break;
 568 #endif
 569     case CK_FileNext:
 570     case CK_FilePrev:
 571         /* Does not work in panel mode */
 572         if (!mcview_is_in_panel (view))
 573             mcview_load_next_prev (view, command == CK_FileNext ? 1 : -1);
 574         break;
 575     case CK_History:
 576         mcview_load_file_from_history (view);
 577         break;
 578     case CK_Quit:
 579         if (!mcview_is_in_panel (view))
 580             dlg_stop (DIALOG (WIDGET (view)->owner));
 581         break;
 582     case CK_Cancel:
 583         /* don't close viewer due to SIGINT */
 584         break;
 585     default:
 586         res = MSG_NOT_HANDLED;
 587     }
 588     return res;
 589 }
 590 
 591 /* --------------------------------------------------------------------------------------------- */
 592 
 593 static long
 594 mcview_lookup_key (WView * view, int key)
     /* [previous][next][first][last][top][bottom][index][help]  */
 595 {
 596     if (view->mode_flags.hex)
 597         return keybind_lookup_keymap_command (view->hex_keymap, key);
 598 
 599     return widget_lookup_key (WIDGET (view), key);
 600 }
 601 
 602 /* --------------------------------------------------------------------------------------------- */
 603 /** Both views */
 604 static cb_ret_t
 605 mcview_handle_key (WView * view, int key)
     /* [previous][next][first][last][top][bottom][index][help]  */
 606 {
 607     long command;
 608 
 609 #ifdef HAVE_CHARSET
 610     key = convert_from_input_c (key);
 611 #endif
 612 
 613     if (view->hexedit_mode && view->mode_flags.hex
 614         && mcview_handle_editkey (view, key) == MSG_HANDLED)
 615         return MSG_HANDLED;
 616 
 617     command = mcview_lookup_key (view, key);
 618     if (command != CK_IgnoreKey && mcview_execute_cmd (view, command) == MSG_HANDLED)
 619         return MSG_HANDLED;
 620 
 621 #ifdef MC_ENABLE_DEBUGGING_CODE
 622     if (c == 't')
 623     {                           /* mnemonic: "test" */
 624         mcview_ccache_dump (view);
 625         return MSG_HANDLED;
 626     }
 627 #endif
 628     if (key >= '0' && key <= '9')
 629         view->marker = key - '0';
 630 
 631     /* Key not used */
 632     return MSG_NOT_HANDLED;
 633 }
 634 
 635 
 636 /* --------------------------------------------------------------------------------------------- */
 637 
 638 static inline void
 639 mcview_resize (WView * view)
     /* [previous][next][first][last][top][bottom][index][help]  */
 640 {
 641     view->dpy_wrap_dirty = TRUE;
 642     mcview_compute_areas (view);
 643     mcview_update_bytes_per_line (view);
 644 }
 645 
 646 /* --------------------------------------------------------------------------------------------- */
 647 
 648 static gboolean
 649 mcview_ok_to_quit (WView * view)
     /* [previous][next][first][last][top][bottom][index][help]  */
 650 {
 651     int r;
 652 
 653     if (view->change_list == NULL)
 654         return TRUE;
 655 
 656     if (!mc_global.midnight_shutdown)
 657     {
 658         query_set_sel (2);
 659         r = query_dialog (_("Quit"),
 660                           _("File was modified. Save with exit?"), D_NORMAL, 3,
 661                           _("&Yes"), _("&No"), _("&Cancel quit"));
 662     }
 663     else
 664     {
 665         r = query_dialog (_("Quit"),
 666                           _("Midnight Commander is being shut down.\nSave modified file?"),
 667                           D_NORMAL, 2, _("&Yes"), _("&No"));
 668         /* Esc is No */
 669         if (r == -1)
 670             r = 1;
 671     }
 672 
 673     switch (r)
 674     {
 675     case 0:                    /* Yes */
 676         return mcview_hexedit_save_changes (view) || mc_global.midnight_shutdown;
 677     case 1:                    /* No */
 678         mcview_hexedit_free_change_list (view);
 679         return TRUE;
 680     default:
 681         return FALSE;
 682     }
 683 }
 684 
 685 /* --------------------------------------------------------------------------------------------- */
 686 /*** public functions ****************************************************************************/
 687 /* --------------------------------------------------------------------------------------------- */
 688 
 689 cb_ret_t
 690 mcview_callback (Widget * w, Widget * sender, widget_msg_t msg, int parm, void *data)
     /* [previous][next][first][last][top][bottom][index][help]  */
 691 {
 692     WView *view = (WView *) w;
 693     cb_ret_t i;
 694 
 695     mcview_compute_areas (view);
 696     mcview_update_bytes_per_line (view);
 697 
 698     switch (msg)
 699     {
 700     case MSG_INIT:
 701         if (mcview_is_in_panel (view))
 702             add_hook (&select_file_hook, mcview_hook, view);
 703         else
 704             view->dpy_bbar_dirty = TRUE;
 705         return MSG_HANDLED;
 706 
 707     case MSG_DRAW:
 708         mcview_display (view);
 709         return MSG_HANDLED;
 710 
 711     case MSG_CURSOR:
 712         if (view->mode_flags.hex)
 713             mcview_place_cursor (view);
 714         return MSG_HANDLED;
 715 
 716     case MSG_KEY:
 717         i = mcview_handle_key (view, parm);
 718         mcview_update (view);
 719         return i;
 720 
 721     case MSG_ACTION:
 722         i = mcview_execute_cmd (view, parm);
 723         mcview_update (view);
 724         return i;
 725 
 726     case MSG_FOCUS:
 727         view->dpy_bbar_dirty = TRUE;
 728         /* TODO: get rid of draw here before MSG_DRAW */
 729         mcview_update (view);
 730         return MSG_HANDLED;
 731 
 732     case MSG_RESIZE:
 733         widget_default_callback (w, NULL, MSG_RESIZE, 0, data);
 734         mcview_resize (view);
 735         return MSG_HANDLED;
 736 
 737     case MSG_DESTROY:
 738         if (mcview_is_in_panel (view))
 739         {
 740             delete_hook (&select_file_hook, mcview_hook);
 741 
 742             /*
 743              * In some cases when mc startup is very slow and one panel is in quick vew mode,
 744              * @view is registered in two hook lists at the same time:
 745              *   mcview_callback (MSG_INIT) -> add_hook (&select_file_hook)
 746              *   mcview_hook () -> add_hook (&idle_hook).
 747              * If initialization of file manager is not completed yet, but user switches
 748              * panel mode from qick view to another one (by pressing C-x q), the following
 749              * occurs:
 750              *   view hook is deleted from select_file_hook list via following call chain:
 751              *      create_panel (view_listing) -> widget_replace () ->
 752              *      send_message (MSG_DESTROY) -> mcview_callback (MSG_DESTROY) ->
 753              *      delete_hook (&select_file_hook);
 754              *   @view object is free'd:
 755              *      create_panel (view_listing) -> g_free (old_widget);
 756              *   but @view still is in idle_hook list and tried to be executed:
 757              *      frontend_dlg_run () -> execute_hooks (idle_hook).
 758              * Thus here we have access to free'd @view object. To prevent this, remove view hook
 759              * from idle_hook list.
 760              */
 761             delete_hook (&idle_hook, mcview_hook);
 762 
 763             if (mc_global.midnight_shutdown)
 764                 mcview_ok_to_quit (view);
 765         }
 766         mcview_done (view);
 767         mcview_remove_ext_script (view);
 768         return MSG_HANDLED;
 769 
 770     default:
 771         return widget_default_callback (w, sender, msg, parm, data);
 772     }
 773 }
 774 
 775 /* --------------------------------------------------------------------------------------------- */
 776 
 777 cb_ret_t
 778 mcview_dialog_callback (Widget * w, Widget * sender, widget_msg_t msg, int parm, void *data)
     /* [previous][next][first][last][top][bottom][index][help]  */
 779 {
 780     WDialog *h = DIALOG (w);
 781     WView *view;
 782 
 783     switch (msg)
 784     {
 785     case MSG_ACTION:
 786         /* Handle shortcuts. */
 787 
 788         /* Note: the buttonbar sends messages directly to the the WView, not to
 789          * here, which is why we can pass NULL in the following call. */
 790         return mcview_execute_cmd (NULL, parm);
 791 
 792     case MSG_VALIDATE:
 793         view = (WView *) widget_find_by_type (w, mcview_callback);
 794         /* don't stop the dialog before final decision */
 795         widget_set_state (w, WST_ACTIVE, TRUE);
 796         if (mcview_ok_to_quit (view))
 797             dlg_stop (h);
 798         else
 799             mcview_update (view);
 800         return MSG_HANDLED;
 801 
 802     default:
 803         return dlg_default_callback (w, sender, msg, parm, data);
 804     }
 805 }
 806 
 807 /* --------------------------------------------------------------------------------------------- */

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