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-2021
   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/filemanager.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/keymap.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, TRUE);
  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->str, 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->fname->len && strncmp (fname, fe->fname->str, 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 =
 378         vfs_path_append_new (view->workdir_vpath, dir->list[*dir_idx].fname->str, (char *) NULL);
 379     mcview_done (view);
 380     mcview_remove_ext_script (view);
 381     mcview_init (view);
 382     if (regex_command_for (view, vfile, "View", &ext_script) == 0)
 383         mcview_load (view, NULL, vfs_path_as_str (vfile), 0, 0, 0);
 384     vfs_path_free (vfile, TRUE);
 385     view->dir = dir;
 386     view->dir_idx = dir_idx;
 387     view->ext_script = ext_script;
 388 
 389     view->dpy_bbar_dirty = FALSE;       /* FIXME */
 390     view->dirty++;
 391 }
 392 
 393 /* --------------------------------------------------------------------------------------------- */
 394 
 395 static void
 396 mcview_load_file_from_history (WView * view)
     /* [previous][next][first][last][top][bottom][index][help]  */
 397 {
 398     char *filename;
 399     int action;
 400 
 401     filename = show_file_history (CONST_WIDGET (view), &action);
 402 
 403     if (filename != NULL && (action == CK_View || action == CK_Enter))
 404     {
 405         mcview_done (view);
 406         mcview_init (view);
 407 
 408         mcview_load (view, NULL, filename, 0, 0, 0);
 409 
 410         view->dpy_bbar_dirty = FALSE;   /* FIXME */
 411         view->dirty++;
 412     }
 413 
 414     g_free (filename);
 415 }
 416 
 417 /* --------------------------------------------------------------------------------------------- */
 418 
 419 static cb_ret_t
 420 mcview_execute_cmd (WView * view, long command)
     /* [previous][next][first][last][top][bottom][index][help]  */
 421 {
 422     int res = MSG_HANDLED;
 423 
 424     switch (command)
 425     {
 426     case CK_Help:
 427         {
 428             ev_help_t event_data = { NULL, "[Internal File Viewer]" };
 429             mc_event_raise (MCEVENT_GROUP_CORE, "help", &event_data);
 430         }
 431         break;
 432     case CK_HexMode:
 433         /* Toggle between hex view and text view */
 434         mcview_toggle_hex_mode (view);
 435         break;
 436     case CK_HexEditMode:
 437         /* Toggle between hexview and hexedit mode */
 438         mcview_toggle_hexedit_mode (view);
 439         break;
 440     case CK_ToggleNavigation:
 441         view->hexview_in_text = !view->hexview_in_text;
 442         view->dirty++;
 443         break;
 444     case CK_LeftQuick:
 445         if (!view->mode_flags.hex)
 446             mcview_move_left (view, 10);
 447         break;
 448     case CK_RightQuick:
 449         if (!view->mode_flags.hex)
 450             mcview_move_right (view, 10);
 451         break;
 452     case CK_Goto:
 453         {
 454             off_t addr;
 455 
 456             if (mcview_dialog_goto (view, &addr))
 457             {
 458                 if (addr >= 0)
 459                     mcview_moveto_offset (view, addr);
 460                 else
 461                 {
 462                     message (D_ERROR, _("Warning"), "%s", _("Invalid value"));
 463                     view->dirty++;
 464                 }
 465             }
 466             break;
 467         }
 468     case CK_Save:
 469         mcview_hexedit_save_changes (view);
 470         break;
 471     case CK_Search:
 472         mcview_search (view, TRUE);
 473         break;
 474     case CK_SearchContinue:
 475         mcview_continue_search_cmd (view);
 476         break;
 477     case CK_SearchForward:
 478         mcview_search_options.backwards = FALSE;
 479         mcview_search (view, TRUE);
 480         break;
 481     case CK_SearchForwardContinue:
 482         mcview_search_options.backwards = FALSE;
 483         mcview_continue_search_cmd (view);
 484         break;
 485     case CK_SearchBackward:
 486         mcview_search_options.backwards = TRUE;
 487         mcview_search (view, TRUE);
 488         break;
 489     case CK_SearchBackwardContinue:
 490         mcview_search_options.backwards = TRUE;
 491         mcview_continue_search_cmd (view);
 492         break;
 493     case CK_SearchOppositeContinue:
 494         {
 495             gboolean direction;
 496 
 497             direction = mcview_search_options.backwards;
 498             mcview_search_options.backwards = !direction;
 499             mcview_continue_search_cmd (view);
 500             mcview_search_options.backwards = direction;
 501         }
 502         break;
 503     case CK_WrapMode:
 504         /* Toggle between wrapped and unwrapped view */
 505         mcview_toggle_wrap_mode (view);
 506         break;
 507     case CK_MagicMode:
 508         mcview_toggle_magic_mode (view);
 509         break;
 510     case CK_NroffMode:
 511         mcview_toggle_nroff_mode (view);
 512         break;
 513     case CK_Home:
 514         mcview_moveto_bol (view);
 515         break;
 516     case CK_End:
 517         mcview_moveto_eol (view);
 518         break;
 519     case CK_Left:
 520         mcview_move_left (view, 1);
 521         break;
 522     case CK_Right:
 523         mcview_move_right (view, 1);
 524         break;
 525     case CK_Up:
 526         mcview_move_up (view, 1);
 527         break;
 528     case CK_Down:
 529         mcview_move_down (view, 1);
 530         break;
 531     case CK_HalfPageUp:
 532         mcview_move_up (view, (view->data_area.height + 1) / 2);
 533         break;
 534     case CK_HalfPageDown:
 535         mcview_move_down (view, (view->data_area.height + 1) / 2);
 536         break;
 537     case CK_PageUp:
 538         mcview_move_up (view, view->data_area.height);
 539         break;
 540     case CK_PageDown:
 541         mcview_move_down (view, view->data_area.height);
 542         break;
 543     case CK_Top:
 544         mcview_moveto_top (view);
 545         break;
 546     case CK_Bottom:
 547         mcview_moveto_bottom (view);
 548         break;
 549     case CK_Shell:
 550         toggle_subshell ();
 551         break;
 552     case CK_Ruler:
 553         mcview_display_toggle_ruler (view);
 554         break;
 555     case CK_Bookmark:
 556         view->dpy_start = view->marks[view->marker];
 557         view->dpy_paragraph_skip_lines = 0;     /* TODO: remember this value in the marker? */
 558         view->dpy_wrap_dirty = TRUE;
 559         view->dirty++;
 560         break;
 561     case CK_BookmarkGoto:
 562         view->marks[view->marker] = view->dpy_start;
 563         break;
 564 #ifdef HAVE_CHARSET
 565     case CK_SelectCodepage:
 566         mcview_select_encoding (view);
 567         view->dirty++;
 568         break;
 569 #endif
 570     case CK_FileNext:
 571     case CK_FilePrev:
 572         /* Does not work in panel mode */
 573         if (!mcview_is_in_panel (view))
 574             mcview_load_next_prev (view, command == CK_FileNext ? 1 : -1);
 575         break;
 576     case CK_History:
 577         mcview_load_file_from_history (view);
 578         break;
 579     case CK_Quit:
 580         if (!mcview_is_in_panel (view))
 581             dlg_stop (DIALOG (WIDGET (view)->owner));
 582         break;
 583     case CK_Cancel:
 584         /* don't close viewer due to SIGINT */
 585         break;
 586     default:
 587         res = MSG_NOT_HANDLED;
 588     }
 589     return res;
 590 }
 591 
 592 /* --------------------------------------------------------------------------------------------- */
 593 
 594 static long
 595 mcview_lookup_key (WView * view, int key)
     /* [previous][next][first][last][top][bottom][index][help]  */
 596 {
 597     if (view->mode_flags.hex)
 598         return keybind_lookup_keymap_command (view->hex_keymap, key);
 599 
 600     return widget_lookup_key (WIDGET (view), key);
 601 }
 602 
 603 /* --------------------------------------------------------------------------------------------- */
 604 /** Both views */
 605 static cb_ret_t
 606 mcview_handle_key (WView * view, int key)
     /* [previous][next][first][last][top][bottom][index][help]  */
 607 {
 608     long command;
 609 
 610 #ifdef HAVE_CHARSET
 611     key = convert_from_input_c (key);
 612 #endif
 613 
 614     if (view->hexedit_mode && view->mode_flags.hex
 615         && mcview_handle_editkey (view, key) == MSG_HANDLED)
 616         return MSG_HANDLED;
 617 
 618     command = mcview_lookup_key (view, key);
 619     if (command != CK_IgnoreKey && mcview_execute_cmd (view, command) == MSG_HANDLED)
 620         return MSG_HANDLED;
 621 
 622 #ifdef MC_ENABLE_DEBUGGING_CODE
 623     if (c == 't')
 624     {                           /* mnemonic: "test" */
 625         mcview_ccache_dump (view);
 626         return MSG_HANDLED;
 627     }
 628 #endif
 629     if (key >= '0' && key <= '9')
 630         view->marker = key - '0';
 631 
 632     /* Key not used */
 633     return MSG_NOT_HANDLED;
 634 }
 635 
 636 
 637 /* --------------------------------------------------------------------------------------------- */
 638 
 639 static inline void
 640 mcview_resize (WView * view)
     /* [previous][next][first][last][top][bottom][index][help]  */
 641 {
 642     view->dpy_wrap_dirty = TRUE;
 643     mcview_compute_areas (view);
 644     mcview_update_bytes_per_line (view);
 645 }
 646 
 647 /* --------------------------------------------------------------------------------------------- */
 648 
 649 static gboolean
 650 mcview_ok_to_quit (WView * view)
     /* [previous][next][first][last][top][bottom][index][help]  */
 651 {
 652     int r;
 653 
 654     if (view->change_list == NULL)
 655         return TRUE;
 656 
 657     if (!mc_global.midnight_shutdown)
 658     {
 659         query_set_sel (2);
 660         r = query_dialog (_("Quit"),
 661                           _("File was modified. Save with exit?"), D_NORMAL, 3,
 662                           _("&Yes"), _("&No"), _("&Cancel quit"));
 663     }
 664     else
 665     {
 666         r = query_dialog (_("Quit"),
 667                           _("Midnight Commander is being shut down.\nSave modified file?"),
 668                           D_NORMAL, 2, _("&Yes"), _("&No"));
 669         /* Esc is No */
 670         if (r == -1)
 671             r = 1;
 672     }
 673 
 674     switch (r)
 675     {
 676     case 0:                    /* Yes */
 677         return mcview_hexedit_save_changes (view) || mc_global.midnight_shutdown;
 678     case 1:                    /* No */
 679         mcview_hexedit_free_change_list (view);
 680         return TRUE;
 681     default:
 682         return FALSE;
 683     }
 684 }
 685 
 686 /* --------------------------------------------------------------------------------------------- */
 687 /*** public functions ****************************************************************************/
 688 /* --------------------------------------------------------------------------------------------- */
 689 
 690 cb_ret_t
 691 mcview_callback (Widget * w, Widget * sender, widget_msg_t msg, int parm, void *data)
     /* [previous][next][first][last][top][bottom][index][help]  */
 692 {
 693     WView *view = (WView *) w;
 694     cb_ret_t i;
 695 
 696     mcview_compute_areas (view);
 697     mcview_update_bytes_per_line (view);
 698 
 699     switch (msg)
 700     {
 701     case MSG_INIT:
 702         if (mcview_is_in_panel (view))
 703             add_hook (&select_file_hook, mcview_hook, view);
 704         else
 705             view->dpy_bbar_dirty = TRUE;
 706         return MSG_HANDLED;
 707 
 708     case MSG_DRAW:
 709         mcview_display (view);
 710         return MSG_HANDLED;
 711 
 712     case MSG_CURSOR:
 713         if (view->mode_flags.hex)
 714             mcview_place_cursor (view);
 715         return MSG_HANDLED;
 716 
 717     case MSG_KEY:
 718         i = mcview_handle_key (view, parm);
 719         mcview_update (view);
 720         return i;
 721 
 722     case MSG_ACTION:
 723         i = mcview_execute_cmd (view, parm);
 724         mcview_update (view);
 725         return i;
 726 
 727     case MSG_FOCUS:
 728         view->dpy_bbar_dirty = TRUE;
 729         /* TODO: get rid of draw here before MSG_DRAW */
 730         mcview_update (view);
 731         return MSG_HANDLED;
 732 
 733     case MSG_RESIZE:
 734         widget_default_callback (w, NULL, MSG_RESIZE, 0, data);
 735         mcview_resize (view);
 736         return MSG_HANDLED;
 737 
 738     case MSG_DESTROY:
 739         if (mcview_is_in_panel (view))
 740         {
 741             delete_hook (&select_file_hook, mcview_hook);
 742 
 743             /*
 744              * In some cases when mc startup is very slow and one panel is in quick vew mode,
 745              * @view is registered in two hook lists at the same time:
 746              *   mcview_callback (MSG_INIT) -> add_hook (&select_file_hook)
 747              *   mcview_hook () -> add_hook (&idle_hook).
 748              * If initialization of file manager is not completed yet, but user switches
 749              * panel mode from qick view to another one (by pressing C-x q), the following
 750              * occurs:
 751              *   view hook is deleted from select_file_hook list via following call chain:
 752              *      create_panel (view_listing) -> widget_replace () ->
 753              *      send_message (MSG_DESTROY) -> mcview_callback (MSG_DESTROY) ->
 754              *      delete_hook (&select_file_hook);
 755              *   @view object is free'd:
 756              *      create_panel (view_listing) -> g_free (old_widget);
 757              *   but @view still is in idle_hook list and tried to be executed:
 758              *      frontend_dlg_run () -> execute_hooks (idle_hook).
 759              * Thus here we have access to free'd @view object. To prevent this, remove view hook
 760              * from idle_hook list.
 761              */
 762             delete_hook (&idle_hook, mcview_hook);
 763 
 764             if (mc_global.midnight_shutdown)
 765                 mcview_ok_to_quit (view);
 766         }
 767         mcview_done (view);
 768         mcview_remove_ext_script (view);
 769         return MSG_HANDLED;
 770 
 771     default:
 772         return widget_default_callback (w, sender, msg, parm, data);
 773     }
 774 }
 775 
 776 /* --------------------------------------------------------------------------------------------- */
 777 
 778 cb_ret_t
 779 mcview_dialog_callback (Widget * w, Widget * sender, widget_msg_t msg, int parm, void *data)
     /* [previous][next][first][last][top][bottom][index][help]  */
 780 {
 781     WDialog *h = DIALOG (w);
 782     WView *view;
 783 
 784     switch (msg)
 785     {
 786     case MSG_ACTION:
 787         /* Handle shortcuts. */
 788 
 789         /* Note: the buttonbar sends messages directly to the the WView, not to
 790          * here, which is why we can pass NULL in the following call. */
 791         return mcview_execute_cmd (NULL, parm);
 792 
 793     case MSG_VALIDATE:
 794         view = (WView *) widget_find_by_type (w, mcview_callback);
 795         /* don't stop the dialog before final decision */
 796         widget_set_state (w, WST_ACTIVE, TRUE);
 797         if (mcview_ok_to_quit (view))
 798             dlg_stop (h);
 799         else
 800             mcview_update (view);
 801         return MSG_HANDLED;
 802 
 803     default:
 804         return dlg_default_callback (w, sender, msg, parm, data);
 805     }
 806 }
 807 
 808 /* --------------------------------------------------------------------------------------------- */

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