From: Stefan Monnier Date: Sat, 29 Mar 2008 01:46:10 +0000 (+0000) Subject: * keyboard.c (pending_funcalls): New var. X-Git-Tag: emacs-pretest-23.0.90~6810 X-Git-Url: http://git.eshelyaron.com/gitweb/?a=commitdiff_plain;h=58555d8187f3425f69e57316cfcd296f8fe08433;p=emacs.git * keyboard.c (pending_funcalls): New var. (timer_check): Run it. (syms_of_keyboard): Initialize it. * terminal.c (Qrun_hook_with_args, Qdelete_terminal_functions) (Vdelete_terminal_functions): New vars. (syms_of_terminal): Initialize them. (Fdelete_terminal): Run delete-terminal-functions. * xdisp.c (safe_eval): Rewrite. (safe_call2): New fun. * frame.c (Qdelete_frame_functions): New var. (syms_of_frame): Initialize it. (Fdelete_frame): Use it and use safe_call2 and pending_funcalls. * lisp.h (safe_call2, pending_funcalls): Declare. --- diff --git a/etc/NEWS b/etc/NEWS index 236823fa2df..285b7428b2c 100644 --- a/etc/NEWS +++ b/etc/NEWS @@ -614,6 +614,7 @@ for the list of extra keys that are available. * Incompatible Lisp Changes in Emacs 23.1 ++++ ** The multibyteness of process filters is determined by the coding-system used for decoding. The functions `process-filter-multibyte-p' and `set-process-filter-multibyte' are obsolete. @@ -664,6 +665,8 @@ functions and variables (formerly used for Tamil script). * Lisp Changes in Emacs 23.1 +** When deleting a terminal, run the special hook `delete-terminal-functions'. + ** The `read-shell-command' function does what its name says, with completion. It uses the minibuffer-local-shell-command-map for that. diff --git a/src/ChangeLog b/src/ChangeLog index 391ea05e7aa..33c1b324e97 100644 --- a/src/ChangeLog +++ b/src/ChangeLog @@ -1,3 +1,19 @@ +2008-03-29 Stefan Monnier + + * keyboard.c (pending_funcalls): New var. + (timer_check): Run it. + (syms_of_keyboard): Initialize it. + * terminal.c (Qrun_hook_with_args, Qdelete_terminal_functions) + (Vdelete_terminal_functions): New vars. + (syms_of_terminal): Initialize them. + (Fdelete_terminal): Run delete-terminal-functions. + * xdisp.c (safe_eval): Rewrite. + (safe_call2): New fun. + * frame.c (Qdelete_frame_functions): New var. + (syms_of_frame): Initialize it. + (Fdelete_frame): Use it and use safe_call2 and pending_funcalls. + * lisp.h (safe_call2, pending_funcalls): Declare. + 2008-03-28 Andreas Schwab * indent.c (Fmove_to_column): Move declaration before statements. diff --git a/src/frame.c b/src/frame.c index 35d00e51552..81b91924d2f 100644 --- a/src/frame.c +++ b/src/frame.c @@ -129,7 +129,7 @@ Lisp_Object Vdefault_frame_alist; Lisp_Object Vdefault_frame_scroll_bars; Lisp_Object Vmouse_position_function; Lisp_Object Vmouse_highlight; -Lisp_Object Vdelete_frame_functions; +static Lisp_Object Vdelete_frame_functions, Qdelete_frame_functions; int focus_follows_mouse; @@ -1334,6 +1334,8 @@ delete_frame_handler (Lisp_Object arg) return Qnil; } +extern Lisp_Object Qrun_hook_with_args; + DEFUN ("delete-frame", Fdelete_frame, Sdelete_frame, 0, 2, "", doc: /* Delete FRAME, permanently eliminating it from use. If omitted, FRAME defaults to the selected frame. @@ -1410,21 +1412,14 @@ But FORCE inhibits this too. */) unless FORCE is `noelisp' or frame is a tooltip. FORCE is set to `noelisp' when handling a disconnect from the terminal, so we don't dare call Lisp code. */ - if (!NILP (Vrun_hooks) && !EQ (force, Qnoelisp) - && NILP (Fframe_parameter (frame, intern ("tooltip")))) - { - Lisp_Object args[2]; - struct gcpro gcpro1, gcpro2; - - /* Don't let a rogue function in `delete-frame-functions' - prevent the frame deletion. */ - GCPRO2 (args[0], args[1]); - args[0] = intern ("delete-frame-functions"); - args[1] = frame; - internal_condition_case_2 (Frun_hook_with_args, 2, args, - Qt, delete_frame_handler); - UNGCPRO; - } + if (NILP (Vrun_hooks) || !NILP (Fframe_parameter (frame, intern ("tooltip")))) + ; + if (EQ (force, Qnoelisp)) + pending_funcalls + = Fcons (list3 (Qrun_hook_with_args, Qdelete_frame_functions, frame), + pending_funcalls); + else + safe_call2 (Qrun_hook_with_args, Qdelete_frame_functions, frame); /* The hook may sometimes (indirectly) cause the frame to be deleted. */ if (! FRAME_LIVE_P (f)) @@ -4526,13 +4521,13 @@ when the mouse is over clickable text. */); The functions are run with one arg, the frame to be deleted. See `delete-frame'. -Note that functions in this list may be called twice on the same -frame. In the second invocation, the frame is already deleted, and -the function should do nothing. (You can use `frame-live-p' to check -for this.) This wrinkle happens when an earlier function in -`delete-frame-functions' (indirectly) calls `delete-frame' -recursively. */); +Note that functions in this list may be called just before the frame is +actually deleted, or some time later (or even both when an earlier function +in `delete-frame-functions' (indirectly) calls `delete-frame' +recursively). */); Vdelete_frame_functions = Qnil; + Qdelete_frame_functions = intern ("delete-frame-functions"); + staticpro (&Qdelete_frame_functions); DEFVAR_KBOARD ("default-minibuffer-frame", Vdefault_minibuffer_frame, doc: /* Minibufferless frames use this frame's minibuffer. diff --git a/src/keyboard.c b/src/keyboard.c index cdcf4c6b608..a930fe74289 100644 --- a/src/keyboard.c +++ b/src/keyboard.c @@ -4505,6 +4505,13 @@ timer_resume_idle () /* This is only for debugging. */ struct input_event last_timer_event; +/* List of elisp functions to call, delayed because they were generated in + a context where Elisp could not be safely run (e.g. redisplay, signal, + ...). Each lement has the form (FUN . ARGS). */ +Lisp_Object pending_funcalls; + +extern Lisp_Object Qapply; + /* Check whether a timer has fired. To prevent larger problems we simply disregard elements that are not proper timers. Do not make a circular timer list for the time being. @@ -4541,6 +4548,14 @@ timer_check (do_it_now) chosen_timer = Qnil; GCPRO3 (timers, idle_timers, chosen_timer); + /* First run the code that was delayed. */ + while (CONSP (pending_funcalls)) + { + Lisp_Object funcall = XCAR (pending_funcalls); + pending_funcalls = XCDR (pending_funcalls); + safe_call2 (Qapply, XCAR (funcall), XCDR (funcall)); + } + if (CONSP (timers) || CONSP (idle_timers)) { EMACS_GET_TIME (now); @@ -11726,6 +11741,8 @@ struct event_head head_table[] = { void syms_of_keyboard () { + pending_funcalls = Qnil; + Vpre_help_message = Qnil; staticpro (&Vpre_help_message); diff --git a/src/lisp.h b/src/lisp.h index 333b6a2a92f..c9a33307bc4 100644 --- a/src/lisp.h +++ b/src/lisp.h @@ -2776,6 +2776,7 @@ EXFUN (Ffetch_bytecode, 1); extern void init_eval_once P_ ((void)); extern Lisp_Object safe_call P_ ((int, Lisp_Object *)); extern Lisp_Object safe_call1 P_ ((Lisp_Object, Lisp_Object)); +extern Lisp_Object safe_call2 (Lisp_Object, Lisp_Object, Lisp_Object); extern void init_eval P_ ((void)); extern void syms_of_eval P_ ((void)); @@ -3025,6 +3026,7 @@ EXFUN (Fset_output_flow_control, 2); EXFUN (Fset_input_meta_mode, 2); EXFUN (Fset_quit_char, 1); EXFUN (Fset_input_mode, 4); +extern Lisp_Object pending_funcalls; extern int detect_input_pending P_ ((void)); extern int detect_input_pending_ignore_squeezables P_ ((void)); extern int detect_input_pending_run_timers P_ ((int)); diff --git a/src/terminal.c b/src/terminal.c index bbc2fd74c2e..6a7cd37929c 100644 --- a/src/terminal.c +++ b/src/terminal.c @@ -295,6 +295,10 @@ delete_terminal (struct terminal *terminal) #endif } +Lisp_Object Qrun_hook_with_args; +static Lisp_Object Qdelete_terminal_functions; +static Lisp_Object Vdelete_terminal_functions; + DEFUN ("delete-terminal", Fdelete_terminal, Sdelete_terminal, 0, 2, 0, doc: /* Delete TERMINAL by deleting all frames on it and closing the terminal. TERMINAL may be a terminal id, a frame, or nil (meaning the selected @@ -320,6 +324,16 @@ but if the second argument FORCE is non-nil, you may do so. */) error ("Attempt to delete the sole active display terminal"); } + if (NILP (Vrun_hooks)) + ; + else if (EQ (force, Qnoelisp)) + pending_funcalls + = Fcons (list3 (Qrun_hook_with_args, + Qdelete_terminal_functions, terminal), + pending_funcalls); + else + safe_call2 (Qrun_hook_with_args, Qdelete_terminal_functions, terminal); + if (t->delete_terminal_hook) (*t->delete_terminal_hook) (t); else @@ -552,6 +566,17 @@ syms_of_terminal () The function should accept no arguments. */); Vring_bell_function = Qnil; + DEFVAR_LISP ("delete-terminal-functions", &Vdelete_terminal_functions, + doc: /* Special hook run when a terminal is deleted. +Each function is called with argument, the terminal. +This may be called just before actually deleting the terminal, +or some time later. */); + Vdelete_terminal_functions = Qnil; + Qdelete_terminal_functions = intern ("delete-terminal-functions"); + staticpro (&Qdelete_terminal_functions); + Qrun_hook_with_args = intern ("run-hook-with-args"); + staticpro (&Qrun_hook_with_args); + defsubr (&Sdelete_terminal); defsubr (&Sframe_terminal); defsubr (&Sterminal_live_p); diff --git a/src/xdisp.c b/src/xdisp.c index 70db580bb0d..073d6a79068 100644 --- a/src/xdisp.c +++ b/src/xdisp.c @@ -2316,33 +2316,6 @@ safe_eval_handler (arg) /* Evaluate SEXPR and return the result, or nil if something went wrong. Prevent redisplay during the evaluation. */ -Lisp_Object -safe_eval (sexpr) - Lisp_Object sexpr; -{ - Lisp_Object val; - - if (inhibit_eval_during_redisplay) - val = Qnil; - else - { - int count = SPECPDL_INDEX (); - struct gcpro gcpro1; - - GCPRO1 (sexpr); - specbind (Qinhibit_redisplay, Qt); - /* Use Qt to ensure debugger does not run, - so there is no possibility of wanting to redisplay. */ - val = internal_condition_case_1 (Feval, sexpr, Qt, - safe_eval_handler); - UNGCPRO; - val = unbind_to (count, val); - } - - return val; -} - - /* Call function ARGS[0] with arguments ARGS[1] to ARGS[NARGS - 1]. Return the result, or nil if something went wrong. Prevent redisplay during the evaluation. */ @@ -2389,6 +2362,27 @@ safe_call1 (fn, arg) return safe_call (2, args); } +static Lisp_Object Qeval; + +Lisp_Object +safe_eval (Lisp_Object sexpr) +{ + return safe_call1 (Qeval, sexpr); +} + +/* Call function FN with one argument ARG. + Return the result, or nil if something went wrong. */ + +Lisp_Object +safe_call2 (Lisp_Object fn, Lisp_Object arg1, Lisp_Object arg2) +{ + Lisp_Object args[3]; + args[0] = fn; + args[1] = arg1; + args[2] = arg2; + return safe_call (3, args); +} + /*********************************************************************** @@ -8634,7 +8628,7 @@ current_message () { Lisp_Object msg; - if (NILP (echo_area_buffer[0])) + if (!BUFFERP (echo_area_buffer[0])) msg = Qnil; else { @@ -24359,6 +24353,9 @@ syms_of_xdisp () staticpro (&Qinhibit_point_motion_hooks); Qinhibit_point_motion_hooks = intern ("inhibit-point-motion-hooks"); + Qeval = intern ("eval"); + staticpro (&Qeval); + QCdata = intern (":data"); staticpro (&QCdata); Qdisplay = intern ("display"); diff --git a/src/xterm.c b/src/xterm.c index f8ef761c5f5..147e492e7d5 100644 --- a/src/xterm.c +++ b/src/xterm.c @@ -8144,7 +8144,11 @@ x_connection_closed (dpy, error_message) /* We have just closed all frames on this display. */ abort (); - x_delete_display (dpyinfo); + { + Lisp_Object tmp; + XSETTERMINAL (tmp, dpyinfo->terminal); + Fdelete_terminal (tmp, Qnoelisp); + } } x_uncatch_errors (); @@ -8165,10 +8169,9 @@ x_connection_closed (dpy, error_message) unbind_to (index, Qnil); clear_waiting_for_input (); - /* FIXME: This is an asynchronous interrupt w.r.t elisp, so signalling an - error might not be the best thing to do. I'd vote for creating an - elisp event and stuffing it in the queue so people can bind to it via - the global map. --Stef */ + /* Here, we absolutely have to use a non-local exit (e.g. signal, throw, + longjmp), because returning from this function would get us back into + Xlib's code which will directly call `exit'. */ error ("%s", error_msg); }