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_handle_key
  12. mcview_resize
  13. mcview_ok_to_quit
  14. mcview_callback
  15. 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-2019
   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 (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 /** Both views */
 593 static cb_ret_t
 594 mcview_handle_key (WView * view, int key)
     /* [previous][next][first][last][top][bottom][index][help]  */
 595 {
 596     long command;
 597 
 598 #ifdef HAVE_CHARSET
 599     key = convert_from_input_c (key);
 600 #endif
 601 
 602     if (view->mode_flags.hex)
 603     {
 604         if (view->hexedit_mode && (mcview_handle_editkey (view, key) == MSG_HANDLED))
 605             return MSG_HANDLED;
 606 
 607         command = keybind_lookup_keymap_command (viewer_hex_map, key);
 608         if ((command != CK_IgnoreKey) && (mcview_execute_cmd (view, command) == MSG_HANDLED))
 609             return MSG_HANDLED;
 610     }
 611 
 612     command = keybind_lookup_keymap_command (viewer_map, key);
 613     if ((command != CK_IgnoreKey) && (mcview_execute_cmd (view, command) == MSG_HANDLED))
 614         return MSG_HANDLED;
 615 
 616 #ifdef MC_ENABLE_DEBUGGING_CODE
 617     if (c == 't')
 618     {                           /* mnemonic: "test" */
 619         mcview_ccache_dump (view);
 620         return MSG_HANDLED;
 621     }
 622 #endif
 623     if (key >= '0' && key <= '9')
 624         view->marker = key - '0';
 625 
 626     /* Key not used */
 627     return MSG_NOT_HANDLED;
 628 }
 629 
 630 
 631 /* --------------------------------------------------------------------------------------------- */
 632 
 633 static inline void
 634 mcview_resize (WView * view)
     /* [previous][next][first][last][top][bottom][index][help]  */
 635 {
 636     view->dpy_wrap_dirty = TRUE;
 637     mcview_compute_areas (view);
 638     mcview_update_bytes_per_line (view);
 639 }
 640 
 641 /* --------------------------------------------------------------------------------------------- */
 642 
 643 static gboolean
 644 mcview_ok_to_quit (WView * view)
     /* [previous][next][first][last][top][bottom][index][help]  */
 645 {
 646     int r;
 647 
 648     if (view->change_list == NULL)
 649         return TRUE;
 650 
 651     if (!mc_global.midnight_shutdown)
 652     {
 653         query_set_sel (2);
 654         r = query_dialog (_("Quit"),
 655                           _("File was modified. Save with exit?"), D_NORMAL, 3,
 656                           _("&Yes"), _("&No"), _("&Cancel quit"));
 657     }
 658     else
 659     {
 660         r = query_dialog (_("Quit"),
 661                           _("Midnight Commander is being shut down.\nSave modified file?"),
 662                           D_NORMAL, 2, _("&Yes"), _("&No"));
 663         /* Esc is No */
 664         if (r == -1)
 665             r = 1;
 666     }
 667 
 668     switch (r)
 669     {
 670     case 0:                    /* Yes */
 671         return mcview_hexedit_save_changes (view) || mc_global.midnight_shutdown;
 672     case 1:                    /* No */
 673         mcview_hexedit_free_change_list (view);
 674         return TRUE;
 675     default:
 676         return FALSE;
 677     }
 678 }
 679 
 680 /* --------------------------------------------------------------------------------------------- */
 681 /*** public functions ****************************************************************************/
 682 /* --------------------------------------------------------------------------------------------- */
 683 
 684 cb_ret_t
 685 mcview_callback (Widget * w, Widget * sender, widget_msg_t msg, int parm, void *data)
     /* [previous][next][first][last][top][bottom][index][help]  */
 686 {
 687     WView *view = (WView *) w;
 688     cb_ret_t i;
 689 
 690     mcview_compute_areas (view);
 691     mcview_update_bytes_per_line (view);
 692 
 693     switch (msg)
 694     {
 695     case MSG_INIT:
 696         if (mcview_is_in_panel (view))
 697             add_hook (&select_file_hook, mcview_hook, view);
 698         else
 699             view->dpy_bbar_dirty = TRUE;
 700         return MSG_HANDLED;
 701 
 702     case MSG_DRAW:
 703         mcview_display (view);
 704         return MSG_HANDLED;
 705 
 706     case MSG_CURSOR:
 707         if (view->mode_flags.hex)
 708             mcview_place_cursor (view);
 709         return MSG_HANDLED;
 710 
 711     case MSG_KEY:
 712         i = mcview_handle_key (view, parm);
 713         mcview_update (view);
 714         return i;
 715 
 716     case MSG_ACTION:
 717         i = mcview_execute_cmd (view, parm);
 718         mcview_update (view);
 719         return i;
 720 
 721     case MSG_FOCUS:
 722         view->dpy_bbar_dirty = TRUE;
 723         /* TODO: get rid of draw here before MSG_DRAW */
 724         mcview_update (view);
 725         return MSG_HANDLED;
 726 
 727     case MSG_RESIZE:
 728         mcview_resize (view);
 729         return MSG_HANDLED;
 730 
 731     case MSG_DESTROY:
 732         if (mcview_is_in_panel (view))
 733         {
 734             delete_hook (&select_file_hook, mcview_hook);
 735 
 736             /*
 737              * In some cases when mc startup is very slow and one panel is in quick vew mode,
 738              * @view is registered in two hook lists at the same time:
 739              *   mcview_callback (MSG_INIT) -> add_hook (&select_file_hook)
 740              *   mcview_hook () -> add_hook (&idle_hook).
 741              * If initialization of file manager is not completed yet, but user switches
 742              * panel mode from qick view to another one (by pressing C-x q), the following
 743              * occurs:
 744              *   view hook is deleted from select_file_hook list via following call chain:
 745              *      create_panel (view_listing) -> widget_replace () ->
 746              *      send_message (MSG_DESTROY) -> mcview_callback (MSG_DESTROY) ->
 747              *      delete_hook (&select_file_hook);
 748              *   @view object is free'd:
 749              *      create_panel (view_listing) -> g_free (old_widget);
 750              *   but @view still is in idle_hook list and tried to be executed:
 751              *      frontend_dlg_run () -> execute_hooks (idle_hook).
 752              * Thus here we have access to free'd @view object. To prevent this, remove view hook
 753              * from idle_hook list.
 754              */
 755             delete_hook (&idle_hook, mcview_hook);
 756 
 757             if (mc_global.midnight_shutdown)
 758                 mcview_ok_to_quit (view);
 759         }
 760         mcview_done (view);
 761         mcview_remove_ext_script (view);
 762         return MSG_HANDLED;
 763 
 764     default:
 765         return widget_default_callback (w, sender, msg, parm, data);
 766     }
 767 }
 768 
 769 /* --------------------------------------------------------------------------------------------- */
 770 
 771 cb_ret_t
 772 mcview_dialog_callback (Widget * w, Widget * sender, widget_msg_t msg, int parm, void *data)
     /* [previous][next][first][last][top][bottom][index][help]  */
 773 {
 774     WDialog *h = DIALOG (w);
 775     WView *view;
 776 
 777     switch (msg)
 778     {
 779     case MSG_ACTION:
 780         /* Handle shortcuts. */
 781 
 782         /* Note: the buttonbar sends messages directly to the the WView, not to
 783          * here, which is why we can pass NULL in the following call. */
 784         return mcview_execute_cmd (NULL, parm);
 785 
 786     case MSG_VALIDATE:
 787         view = (WView *) find_widget_type (h, mcview_callback);
 788         /* don't stop the dialog before final decision */
 789         widget_set_state (WIDGET (h), WST_ACTIVE, TRUE);
 790         if (mcview_ok_to_quit (view))
 791             dlg_stop (h);
 792         else
 793             mcview_update (view);
 794         return MSG_HANDLED;
 795 
 796     default:
 797         return dlg_default_callback (w, sender, msg, parm, data);
 798     }
 799 }
 800 
 801 /* --------------------------------------------------------------------------------------------- */

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