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

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