Manual pages: mcmcdiffmceditmcview

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

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