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)
 145         {
 146             /* FIXME: is it possible that history->data == NULL? */
 147             view->last_search_string = (gchar *) history->data;
 148             history->data = NULL;
 149             history = g_list_first (history);
 150             g_list_free_full (history, g_free);
 151 
 152             if (mcview_search_init (view))
 153             {
 154                 mcview_search (view, FALSE);
 155                 return;
 156             }
 157 
 158             /* found, but cannot init search */
 159             MC_PTR_FREE (view->last_search_string);
 160         }
 161 
 162         /* if not... then ask for an expression */
 163         mcview_search (view, TRUE);
 164     }
 165 }
 166 
 167 /* --------------------------------------------------------------------------------------------- */
 168 
 169 static void
 170 mcview_hook (void *v)
     /* [previous][next][first][last][top][bottom][index][help]  */
 171 {
 172     WView *view = (WView *) v;
 173     WPanel *panel;
 174 
 175     /* If the user is busy typing, wait until he finishes to update the
 176        screen */
 177     if (!is_idle ())
 178     {
 179         if (!hook_present (idle_hook, mcview_hook))
 180             add_hook (&idle_hook, mcview_hook, v);
 181         return;
 182     }
 183 
 184     delete_hook (&idle_hook, mcview_hook);
 185 
 186     if (get_current_type () == view_listing)
 187         panel = current_panel;
 188     else if (get_other_type () == view_listing)
 189         panel = other_panel;
 190     else
 191         return;
 192 
 193     mcview_done (view);
 194     mcview_init (view);
 195     mcview_load (view, 0, panel->dir.list[panel->selected].fname->str, 0, 0, 0);
 196     mcview_display (view);
 197 }
 198 
 199 /* --------------------------------------------------------------------------------------------- */
 200 
 201 static cb_ret_t
 202 mcview_handle_editkey (WView * view, int key)
     /* [previous][next][first][last][top][bottom][index][help]  */
 203 {
 204     struct hexedit_change_node *node;
 205     int byte_val = -1;
 206 
 207     /* Has there been a change at this position? */
 208     node = view->change_list;
 209     while ((node != NULL) && (node->offset != view->hex_cursor))
 210         node = node->next;
 211 
 212     if (!view->hexview_in_text)
 213     {
 214         /* Hex editing */
 215         unsigned int hexvalue = 0;
 216 
 217         if (key >= '0' && key <= '9')
 218             hexvalue = 0 + (key - '0');
 219         else if (key >= 'A' && key <= 'F')
 220             hexvalue = 10 + (key - 'A');
 221         else if (key >= 'a' && key <= 'f')
 222             hexvalue = 10 + (key - 'a');
 223         else
 224             return MSG_NOT_HANDLED;
 225 
 226         if (node != NULL)
 227             byte_val = node->value;
 228         else
 229             mcview_get_byte (view, view->hex_cursor, &byte_val);
 230 
 231         if (view->hexedit_lownibble)
 232             byte_val = (byte_val & 0xf0) | (hexvalue);
 233         else
 234             byte_val = (byte_val & 0x0f) | (hexvalue << 4);
 235     }
 236     else
 237     {
 238         /* Text editing */
 239         if (key < 256 && key != '\t')
 240             byte_val = key;
 241         else
 242             return MSG_NOT_HANDLED;
 243     }
 244 
 245     if ((view->filename_vpath != NULL)
 246         && (*(vfs_path_get_last_path_str (view->filename_vpath)) != '\0')
 247         && (view->change_list == NULL))
 248         view->locked = lock_file (view->filename_vpath);
 249 
 250     if (node == NULL)
 251     {
 252         node = g_new (struct hexedit_change_node, 1);
 253         node->offset = view->hex_cursor;
 254         node->value = byte_val;
 255         mcview_enqueue_change (&view->change_list, node);
 256     }
 257     else
 258         node->value = byte_val;
 259 
 260     view->dirty++;
 261     mcview_move_right (view, 1);
 262 
 263     return MSG_HANDLED;
 264 }
 265 
 266 /* --------------------------------------------------------------------------------------------- */
 267 
 268 static void
 269 mcview_load_next_prev_init (WView * view)
     /* [previous][next][first][last][top][bottom][index][help]  */
 270 {
 271     if (mc_global.mc_run_mode != MC_RUN_VIEWER)
 272     {
 273         /* get file list from current panel. Update it each time */
 274         view->dir = &current_panel->dir;
 275         view->dir_idx = &current_panel->selected;
 276     }
 277     else if (view->dir == NULL)
 278     {
 279         /* Run from command line */
 280         /* Run 1st time. Load/get directory */
 281 
 282         /* TODO: check mtime of directory to reload it */
 283 
 284         dir_sort_options_t sort_op = { FALSE, TRUE, FALSE };
 285 
 286         /* load directory where requested file is */
 287         view->dir = g_new0 (dir_list, 1);
 288         view->dir_idx = g_new (int, 1);
 289 
 290         if (dir_list_load
 291             (view->dir, view->workdir_vpath, (GCompareFunc) sort_name, &sort_op, NULL))
 292         {
 293             const char *fname;
 294             size_t fname_len;
 295             int i;
 296 
 297             fname = x_basename (vfs_path_as_str (view->filename_vpath));
 298             fname_len = strlen (fname);
 299 
 300             /* search current file in the list */
 301             for (i = 0; i != view->dir->len; i++)
 302             {
 303                 const file_entry_t *fe = &view->dir->list[i];
 304 
 305                 if (fname_len == fe->fname->len && strncmp (fname, fe->fname->str, fname_len) == 0)
 306                     break;
 307             }
 308 
 309             *view->dir_idx = i;
 310         }
 311         else
 312         {
 313             message (D_ERROR, MSG_ERROR, _("Cannot read directory contents"));
 314             MC_PTR_FREE (view->dir);
 315             MC_PTR_FREE (view->dir_idx);
 316         }
 317     }
 318 }
 319 
 320 /* --------------------------------------------------------------------------------------------- */
 321 
 322 static void
 323 mcview_scan_for_file (WView * view, int direction)
     /* [previous][next][first][last][top][bottom][index][help]  */
 324 {
 325     int i;
 326 
 327     for (i = *view->dir_idx + direction; i != *view->dir_idx; i += direction)
 328     {
 329         if (i < 0)
 330             i = view->dir->len - 1;
 331         if (i == view->dir->len)
 332             i = 0;
 333         if (!S_ISDIR (view->dir->list[i].st.st_mode))
 334             break;
 335     }
 336 
 337     *view->dir_idx = i;
 338 }
 339 
 340 /* --------------------------------------------------------------------------------------------- */
 341 
 342 static void
 343 mcview_load_next_prev (WView * view, int direction)
     /* [previous][next][first][last][top][bottom][index][help]  */
 344 {
 345     dir_list *dir;
 346     int *dir_idx;
 347     vfs_path_t *vfile;
 348     vfs_path_t *ext_script = NULL;
 349 
 350     mcview_load_next_prev_init (view);
 351     mcview_scan_for_file (view, direction);
 352 
 353     /* reinit view */
 354     dir = view->dir;
 355     dir_idx = view->dir_idx;
 356     view->dir = NULL;
 357     view->dir_idx = NULL;
 358     vfile =
 359         vfs_path_append_new (view->workdir_vpath, dir->list[*dir_idx].fname->str, (char *) NULL);
 360     mcview_done (view);
 361     mcview_remove_ext_script (view);
 362     mcview_init (view);
 363     if (regex_command_for (view, vfile, "View", &ext_script) == 0)
 364         mcview_load (view, NULL, vfs_path_as_str (vfile), 0, 0, 0);
 365     vfs_path_free (vfile, TRUE);
 366     view->dir = dir;
 367     view->dir_idx = dir_idx;
 368     view->ext_script = ext_script;
 369 
 370     view->dpy_bbar_dirty = FALSE;       /* FIXME */
 371     view->dirty++;
 372 }
 373 
 374 /* --------------------------------------------------------------------------------------------- */
 375 
 376 static void
 377 mcview_load_file_from_history (WView * view)
     /* [previous][next][first][last][top][bottom][index][help]  */
 378 {
 379     char *filename;
 380     int action;
 381 
 382     filename = show_file_history (CONST_WIDGET (view), &action);
 383 
 384     if (filename != NULL && (action == CK_View || action == CK_Enter))
 385     {
 386         mcview_done (view);
 387         mcview_init (view);
 388 
 389         mcview_load (view, NULL, filename, 0, 0, 0);
 390 
 391         view->dpy_bbar_dirty = FALSE;   /* FIXME */
 392         view->dirty++;
 393     }
 394 
 395     g_free (filename);
 396 }
 397 
 398 /* --------------------------------------------------------------------------------------------- */
 399 
 400 static cb_ret_t
 401 mcview_execute_cmd (WView * view, long command)
     /* [previous][next][first][last][top][bottom][index][help]  */
 402 {
 403     int res = MSG_HANDLED;
 404 
 405     switch (command)
 406     {
 407     case CK_Help:
 408         {
 409             ev_help_t event_data = { NULL, "[Internal File Viewer]" };
 410             mc_event_raise (MCEVENT_GROUP_CORE, "help", &event_data);
 411         }
 412         break;
 413     case CK_HexMode:
 414         /* Toggle between hex view and text view */
 415         mcview_toggle_hex_mode (view);
 416         break;
 417     case CK_HexEditMode:
 418         /* Toggle between hexview and hexedit mode */
 419         mcview_toggle_hexedit_mode (view);
 420         break;
 421     case CK_ToggleNavigation:
 422         view->hexview_in_text = !view->hexview_in_text;
 423         view->dirty++;
 424         break;
 425     case CK_LeftQuick:
 426         if (!view->mode_flags.hex)
 427             mcview_move_left (view, 10);
 428         break;
 429     case CK_RightQuick:
 430         if (!view->mode_flags.hex)
 431             mcview_move_right (view, 10);
 432         break;
 433     case CK_Goto:
 434         {
 435             off_t addr;
 436 
 437             if (mcview_dialog_goto (view, &addr))
 438             {
 439                 if (addr >= 0)
 440                     mcview_moveto_offset (view, addr);
 441                 else
 442                 {
 443                     message (D_ERROR, _("Warning"), "%s", _("Invalid value"));
 444                     view->dirty++;
 445                 }
 446             }
 447             break;
 448         }
 449     case CK_Save:
 450         mcview_hexedit_save_changes (view);
 451         break;
 452     case CK_Search:
 453         mcview_search (view, TRUE);
 454         break;
 455     case CK_SearchContinue:
 456         mcview_continue_search_cmd (view);
 457         break;
 458     case CK_SearchForward:
 459         mcview_search_options.backwards = FALSE;
 460         mcview_search (view, TRUE);
 461         break;
 462     case CK_SearchForwardContinue:
 463         mcview_search_options.backwards = FALSE;
 464         mcview_continue_search_cmd (view);
 465         break;
 466     case CK_SearchBackward:
 467         mcview_search_options.backwards = TRUE;
 468         mcview_search (view, TRUE);
 469         break;
 470     case CK_SearchBackwardContinue:
 471         mcview_search_options.backwards = TRUE;
 472         mcview_continue_search_cmd (view);
 473         break;
 474     case CK_SearchOppositeContinue:
 475         {
 476             gboolean direction;
 477 
 478             direction = mcview_search_options.backwards;
 479             mcview_search_options.backwards = !direction;
 480             mcview_continue_search_cmd (view);
 481             mcview_search_options.backwards = direction;
 482         }
 483         break;
 484     case CK_WrapMode:
 485         /* Toggle between wrapped and unwrapped view */
 486         mcview_toggle_wrap_mode (view);
 487         break;
 488     case CK_MagicMode:
 489         mcview_toggle_magic_mode (view);
 490         break;
 491     case CK_NroffMode:
 492         mcview_toggle_nroff_mode (view);
 493         break;
 494     case CK_Home:
 495         mcview_moveto_bol (view);
 496         break;
 497     case CK_End:
 498         mcview_moveto_eol (view);
 499         break;
 500     case CK_Left:
 501         mcview_move_left (view, 1);
 502         break;
 503     case CK_Right:
 504         mcview_move_right (view, 1);
 505         break;
 506     case CK_Up:
 507         mcview_move_up (view, 1);
 508         break;
 509     case CK_Down:
 510         mcview_move_down (view, 1);
 511         break;
 512     case CK_HalfPageUp:
 513         mcview_move_up (view, (view->data_area.height + 1) / 2);
 514         break;
 515     case CK_HalfPageDown:
 516         mcview_move_down (view, (view->data_area.height + 1) / 2);
 517         break;
 518     case CK_PageUp:
 519         mcview_move_up (view, view->data_area.height);
 520         break;
 521     case CK_PageDown:
 522         mcview_move_down (view, view->data_area.height);
 523         break;
 524     case CK_Top:
 525         mcview_moveto_top (view);
 526         break;
 527     case CK_Bottom:
 528         mcview_moveto_bottom (view);
 529         break;
 530     case CK_Shell:
 531         toggle_subshell ();
 532         break;
 533     case CK_Ruler:
 534         mcview_display_toggle_ruler (view);
 535         break;
 536     case CK_Bookmark:
 537         view->dpy_start = view->marks[view->marker];
 538         view->dpy_paragraph_skip_lines = 0;     /* TODO: remember this value in the marker? */
 539         view->dpy_wrap_dirty = TRUE;
 540         view->dirty++;
 541         break;
 542     case CK_BookmarkGoto:
 543         view->marks[view->marker] = view->dpy_start;
 544         break;
 545 #ifdef HAVE_CHARSET
 546     case CK_SelectCodepage:
 547         mcview_select_encoding (view);
 548         view->dirty++;
 549         break;
 550 #endif
 551     case CK_FileNext:
 552     case CK_FilePrev:
 553         /* Does not work in panel mode */
 554         if (!mcview_is_in_panel (view))
 555             mcview_load_next_prev (view, command == CK_FileNext ? 1 : -1);
 556         break;
 557     case CK_History:
 558         mcview_load_file_from_history (view);
 559         break;
 560     case CK_Quit:
 561         if (!mcview_is_in_panel (view))
 562             dlg_stop (DIALOG (WIDGET (view)->owner));
 563         break;
 564     case CK_Cancel:
 565         /* don't close viewer due to SIGINT */
 566         break;
 567     default:
 568         res = MSG_NOT_HANDLED;
 569     }
 570     return res;
 571 }
 572 
 573 /* --------------------------------------------------------------------------------------------- */
 574 
 575 static long
 576 mcview_lookup_key (WView * view, int key)
     /* [previous][next][first][last][top][bottom][index][help]  */
 577 {
 578     if (view->mode_flags.hex)
 579         return keybind_lookup_keymap_command (view->hex_keymap, key);
 580 
 581     return widget_lookup_key (WIDGET (view), key);
 582 }
 583 
 584 /* --------------------------------------------------------------------------------------------- */
 585 /** Both views */
 586 static cb_ret_t
 587 mcview_handle_key (WView * view, int key)
     /* [previous][next][first][last][top][bottom][index][help]  */
 588 {
 589     long command;
 590 
 591 #ifdef HAVE_CHARSET
 592     key = convert_from_input_c (key);
 593 #endif
 594 
 595     if (view->hexedit_mode && view->mode_flags.hex
 596         && mcview_handle_editkey (view, key) == MSG_HANDLED)
 597         return MSG_HANDLED;
 598 
 599     command = mcview_lookup_key (view, key);
 600     if (command != CK_IgnoreKey && mcview_execute_cmd (view, command) == MSG_HANDLED)
 601         return MSG_HANDLED;
 602 
 603 #ifdef MC_ENABLE_DEBUGGING_CODE
 604     if (c == 't')
 605     {                           /* mnemonic: "test" */
 606         mcview_ccache_dump (view);
 607         return MSG_HANDLED;
 608     }
 609 #endif
 610     if (key >= '0' && key <= '9')
 611         view->marker = key - '0';
 612 
 613     /* Key not used */
 614     return MSG_NOT_HANDLED;
 615 }
 616 
 617 
 618 /* --------------------------------------------------------------------------------------------- */
 619 
 620 static inline void
 621 mcview_resize (WView * view)
     /* [previous][next][first][last][top][bottom][index][help]  */
 622 {
 623     view->dpy_wrap_dirty = TRUE;
 624     mcview_compute_areas (view);
 625     mcview_update_bytes_per_line (view);
 626 }
 627 
 628 /* --------------------------------------------------------------------------------------------- */
 629 
 630 static gboolean
 631 mcview_ok_to_quit (WView * view)
     /* [previous][next][first][last][top][bottom][index][help]  */
 632 {
 633     int r;
 634 
 635     if (view->change_list == NULL)
 636         return TRUE;
 637 
 638     if (!mc_global.midnight_shutdown)
 639     {
 640         query_set_sel (2);
 641         r = query_dialog (_("Quit"),
 642                           _("File was modified. Save with exit?"), D_NORMAL, 3,
 643                           _("&Yes"), _("&No"), _("&Cancel quit"));
 644     }
 645     else
 646     {
 647         r = query_dialog (_("Quit"),
 648                           _("Midnight Commander is being shut down.\nSave modified file?"),
 649                           D_NORMAL, 2, _("&Yes"), _("&No"));
 650         /* Esc is No */
 651         if (r == -1)
 652             r = 1;
 653     }
 654 
 655     switch (r)
 656     {
 657     case 0:                    /* Yes */
 658         return mcview_hexedit_save_changes (view) || mc_global.midnight_shutdown;
 659     case 1:                    /* No */
 660         mcview_hexedit_free_change_list (view);
 661         return TRUE;
 662     default:
 663         return FALSE;
 664     }
 665 }
 666 
 667 /* --------------------------------------------------------------------------------------------- */
 668 /*** public functions ****************************************************************************/
 669 /* --------------------------------------------------------------------------------------------- */
 670 
 671 cb_ret_t
 672 mcview_callback (Widget * w, Widget * sender, widget_msg_t msg, int parm, void *data)
     /* [previous][next][first][last][top][bottom][index][help]  */
 673 {
 674     WView *view = (WView *) w;
 675     cb_ret_t i;
 676 
 677     mcview_compute_areas (view);
 678     mcview_update_bytes_per_line (view);
 679 
 680     switch (msg)
 681     {
 682     case MSG_INIT:
 683         if (mcview_is_in_panel (view))
 684             add_hook (&select_file_hook, mcview_hook, view);
 685         else
 686             view->dpy_bbar_dirty = TRUE;
 687         return MSG_HANDLED;
 688 
 689     case MSG_DRAW:
 690         mcview_display (view);
 691         return MSG_HANDLED;
 692 
 693     case MSG_CURSOR:
 694         if (view->mode_flags.hex)
 695             mcview_place_cursor (view);
 696         return MSG_HANDLED;
 697 
 698     case MSG_KEY:
 699         i = mcview_handle_key (view, parm);
 700         mcview_update (view);
 701         return i;
 702 
 703     case MSG_ACTION:
 704         i = mcview_execute_cmd (view, parm);
 705         mcview_update (view);
 706         return i;
 707 
 708     case MSG_FOCUS:
 709         view->dpy_bbar_dirty = TRUE;
 710         /* TODO: get rid of draw here before MSG_DRAW */
 711         mcview_update (view);
 712         return MSG_HANDLED;
 713 
 714     case MSG_RESIZE:
 715         widget_default_callback (w, NULL, MSG_RESIZE, 0, data);
 716         mcview_resize (view);
 717         return MSG_HANDLED;
 718 
 719     case MSG_DESTROY:
 720         if (mcview_is_in_panel (view))
 721         {
 722             delete_hook (&select_file_hook, mcview_hook);
 723 
 724             /*
 725              * In some cases when mc startup is very slow and one panel is in quick vew mode,
 726              * @view is registered in two hook lists at the same time:
 727              *   mcview_callback (MSG_INIT) -> add_hook (&select_file_hook)
 728              *   mcview_hook () -> add_hook (&idle_hook).
 729              * If initialization of file manager is not completed yet, but user switches
 730              * panel mode from qick view to another one (by pressing C-x q), the following
 731              * occurs:
 732              *   view hook is deleted from select_file_hook list via following call chain:
 733              *      create_panel (view_listing) -> widget_replace () ->
 734              *      send_message (MSG_DESTROY) -> mcview_callback (MSG_DESTROY) ->
 735              *      delete_hook (&select_file_hook);
 736              *   @view object is free'd:
 737              *      create_panel (view_listing) -> g_free (old_widget);
 738              *   but @view still is in idle_hook list and tried to be executed:
 739              *      frontend_dlg_run () -> execute_hooks (idle_hook).
 740              * Thus here we have access to free'd @view object. To prevent this, remove view hook
 741              * from idle_hook list.
 742              */
 743             delete_hook (&idle_hook, mcview_hook);
 744 
 745             if (mc_global.midnight_shutdown)
 746                 mcview_ok_to_quit (view);
 747         }
 748         mcview_done (view);
 749         mcview_remove_ext_script (view);
 750         return MSG_HANDLED;
 751 
 752     default:
 753         return widget_default_callback (w, sender, msg, parm, data);
 754     }
 755 }
 756 
 757 /* --------------------------------------------------------------------------------------------- */
 758 
 759 cb_ret_t
 760 mcview_dialog_callback (Widget * w, Widget * sender, widget_msg_t msg, int parm, void *data)
     /* [previous][next][first][last][top][bottom][index][help]  */
 761 {
 762     WDialog *h = DIALOG (w);
 763     WView *view;
 764 
 765     switch (msg)
 766     {
 767     case MSG_ACTION:
 768         /* Handle shortcuts. */
 769 
 770         /* Note: the buttonbar sends messages directly to the the WView, not to
 771          * here, which is why we can pass NULL in the following call. */
 772         return mcview_execute_cmd (NULL, parm);
 773 
 774     case MSG_VALIDATE:
 775         view = (WView *) widget_find_by_type (w, mcview_callback);
 776         /* don't stop the dialog before final decision */
 777         widget_set_state (w, WST_ACTIVE, TRUE);
 778         if (mcview_ok_to_quit (view))
 779             dlg_stop (h);
 780         else
 781             mcview_update (view);
 782         return MSG_HANDLED;
 783 
 784     default:
 785         return dlg_default_callback (w, sender, msg, parm, data);
 786     }
 787 }
 788 
 789 /* --------------------------------------------------------------------------------------------- */

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