/* Keyboard and mouse input; editor command loop.
- Copyright (C) 1985,86,87,88,89,93,94,95,96,97,99,2000,01,02,03
- Free Software Foundation, Inc.
+ Copyright (C) 1985, 1986, 1987, 1988, 1989, 1993, 1994, 1995,
+ 1996, 1997, 1999, 2000, 2001, 2002, 2003, 2004,
+ 2005 Free Software Foundation, Inc.
This file is part of GNU Emacs.
You should have received a copy of the GNU General Public License
along with GNU Emacs; see the file COPYING. If not, write to
-the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
-Boston, MA 02111-1307, USA. */
+the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+Boston, MA 02110-1301, USA. */
#include <config.h>
#include <signal.h>
#include <setjmp.h>
#include <errno.h>
+#ifdef HAVE_GTK_AND_PTHREAD
+#include <pthread.h>
+#endif
#ifdef MSDOS
#include "msdos.h"
#include <time.h>
#include <unistd.h>
#endif
+#ifdef HAVE_FCNTL_H
+#include <fcntl.h>
+#endif
+
/* This is to get the definitions of the XK_ symbols. */
#ifdef HAVE_X_WINDOWS
#include "xterm.h"
args points to slot holding list of
unevalled args */
char evalargs;
+ /* Nonzero means call value of debugger when done with this operation. */
+ char debug_on_exit;
};
#ifdef MULTI_KBOARD
#endif
/* Non-nil disable property on a command means
- do not execute it; call disabled-command-hook's value instead. */
-Lisp_Object Qdisabled, Qdisabled_command_hook;
+ do not execute it; call disabled-command-function's value instead. */
+Lisp_Object Qdisabled, Qdisabled_command_function;
#define NUM_RECENT_KEYS (100)
int recent_keys_index; /* Index for storing next element into recent_keys */
Lisp_Object Qpre_command_hook, Vpre_command_hook;
Lisp_Object Qpost_command_hook, Vpost_command_hook;
Lisp_Object Qcommand_hook_internal, Vcommand_hook_internal;
-/* Hook run after a command if there's no more input soon. */
-Lisp_Object Qpost_command_idle_hook, Vpost_command_idle_hook;
-
-/* Delay time in microseconds before running post-command-idle-hook. */
-EMACS_INT post_command_idle_delay;
/* List of deferred actions to be performed at a later time.
The precise format isn't relevant here; we just check whether it is nil. */
static struct input_event kbd_buffer[KBD_BUFFER_SIZE];
-/* Vector to GCPRO the Lisp objects referenced from kbd_buffer.
-
- The interrupt-level event handlers will never enqueue an event on a
- frame which is not in Vframe_list, and once an event is dequeued,
- internal_last_event_frame or the event itself points to the frame.
- So that's all fine.
-
- But while the event is sitting in the queue, it's completely
- unprotected. Suppose the user types one command which will run for
- a while and then delete a frame, and then types another event at
- the frame that will be deleted, before the command gets around to
- it. Suppose there are no references to this frame elsewhere in
- Emacs, and a GC occurs before the second event is dequeued. Now we
- have an event referring to a freed frame, which will crash Emacs
- when it is dequeued.
-
- Similar things happen when an event on a scroll bar is enqueued; the
- window may be deleted while the event is in the queue.
-
- So, we use this vector to protect the Lisp_Objects in the event
- queue. That way, they'll be dequeued as dead frames or windows,
- but still valid Lisp objects.
-
- If kbd_buffer[i].kind != NO_EVENT, then
-
- AREF (kbd_buffer_gcpro, 2 * i) == kbd_buffer[i].frame_or_window.
- AREF (kbd_buffer_gcpro, 2 * i + 1) == kbd_buffer[i].arg. */
-
-static Lisp_Object kbd_buffer_gcpro;
-
/* Pointer to next available character in kbd_buffer.
If kbd_fetch_ptr == kbd_store_ptr, the buffer is empty.
This may be kbd_buffer + KBD_BUFFER_SIZE, meaning that the
Lisp_Object Qselect_window;
Lisp_Object Qhelp_echo;
+#ifdef HAVE_MOUSE
+Lisp_Object Qmouse_fixup_help_message;
+#endif
+
/* Symbols to denote kinds of events. */
Lisp_Object Qfunction_key;
Lisp_Object Qmouse_click;
-#ifdef WINDOWSNT
+#if defined (WINDOWSNT) || defined (MAC_OS)
Lisp_Object Qlanguage_change;
#endif
Lisp_Object Qdrag_n_drop;
/* We are unable to use interrupts if FIONREAD is not available,
so flush SIGIO so we won't try. */
-#ifndef FIONREAD
+#if !defined (FIONREAD)
#ifdef SIGIO
#undef SIGIO
#endif
\f
/* Global variable declarations. */
+/* Flags for readable_events. */
+#define READABLE_EVENTS_DO_TIMERS_NOW (1 << 0)
+#define READABLE_EVENTS_FILTER_EVENTS (1 << 1)
+#define READABLE_EVENTS_IGNORE_SQUEEZABLES (1 << 2)
+
/* Function for init_keyboard to call with no args (if nonzero). */
void (*keyboard_init_hook) ();
static int read_avail_input P_ ((int));
static void get_input_pending P_ ((int *, int));
-static void get_filtered_input_pending P_ ((int *, int, int));
static int readable_events P_ ((int));
-static int readable_filtered_events P_ ((int, int));
static Lisp_Object read_char_x_menu_prompt P_ ((int, Lisp_Object *,
Lisp_Object, int *));
static Lisp_Object read_char_x_menu_prompt ();
static void clear_event P_ ((struct input_event *));
static void any_kboard_state P_ ((void));
static SIGTYPE interrupt_signal P_ ((int signalnum));
+static void timer_start_idle P_ ((void));
+static void timer_stop_idle P_ ((void));
+static void timer_resume_idle P_ ((void));
/* Nonzero means don't try to suspend even if the operating system seems
to support it. */
static int cannot_suspend;
+extern Lisp_Object Qidentity, Qonly;
+\f
/* Install the string STR as the beginning of the string of echoing,
so that it serves as a prompt for the next character.
Also start echoing. */
== SCHARS (current_kboard->echo_string))
return;
+ /* Do nothing if we have already put a dash at the end. */
+ if (SCHARS (current_kboard->echo_string) > 1)
+ {
+ Lisp_Object last_char, prev_char, idx;
+
+ idx = make_number (SCHARS (current_kboard->echo_string) - 2);
+ prev_char = Faref (current_kboard->echo_string, idx);
+
+ idx = make_number (SCHARS (current_kboard->echo_string) - 1);
+ last_char = Faref (current_kboard->echo_string, idx);
+
+ if (XINT (last_char) == '-' && XINT (prev_char) != ' ')
+ return;
+ }
+
/* Put a dash at the end of the buffer temporarily,
but make it go away when the next character is added. */
current_kboard->echo_string = concat2 (current_kboard->echo_string,
doc: /* Invoke the editor command loop recursively.
To get out of the recursive edit, a command can do `(throw 'exit nil)';
that tells this function to return.
-Alternately, `(throw 'exit t)' makes this function signal an error.
+Alternatively, `(throw 'exit t)' makes this function signal an error.
This function is called by the editor initialization to begin editing. */)
()
{
int count = SPECPDL_INDEX ();
Lisp_Object buffer;
+ /* If we enter while input is blocked, don't lock up here.
+ This may happen through the debugger during redisplay. */
+ if (INPUT_BLOCKED_P)
+ return Qnil;
+
command_loop_level++;
update_mode_lines = 1;
#endif
}
+/* If we're in single_kboard state for kboard KBOARD,
+ get out of it. */
+
+void
+not_single_kboard_state (kboard)
+ KBOARD *kboard;
+{
+#ifdef MULTI_KBOARD
+ if (kboard == current_kboard)
+ single_kboard = 0;
+#endif
+}
+
/* Maintain a stack of kboards, so other parts of Emacs
can switch temporarily to the kboard of a given frame
and then revert to the previous status. */
cancel_hourglass ();
#endif
- if (!NILP (executing_macro))
+ if (!NILP (executing_kbd_macro))
{
- if (executing_macro_iterations == 1)
+ if (executing_kbd_macro_iterations == 1)
sprintf (macroerror, "After 1 kbd macro iteration: ");
else
sprintf (macroerror, "After %d kbd macro iterations: ",
- executing_macro_iterations);
+ executing_kbd_macro_iterations);
}
else
*macroerror = 0;
Vstandard_output = Qt;
Vstandard_input = Qt;
- Vexecuting_macro = Qnil;
- executing_macro = Qnil;
+ Vexecuting_kbd_macro = Qnil;
+ executing_kbd_macro = Qnil;
current_kboard->Vprefix_arg = Qnil;
current_kboard->Vlast_prefix_arg = Qnil;
cancel_echoing ();
Vinhibit_quit = Qnil;
#ifdef MULTI_KBOARD
- any_kboard_state ();
+ if (command_loop_level == 0 && minibuf_level == 0)
+ any_kboard_state ();
#endif
return make_number (0);
{
Lisp_Object val;
val = internal_catch (Qexit, command_loop_2, Qnil);
- executing_macro = Qnil;
+ executing_kbd_macro = Qnil;
return val;
}
else
while (1)
{
internal_catch (Qtop_level, top_level_1, Qnil);
+ /* Reset single_kboard in case top-level set it while
+ evaluating an -f option, or we are stuck there for some
+ other reason. */
+ any_kboard_state ();
internal_catch (Qtop_level, command_loop_2, Qnil);
- executing_macro = Qnil;
+ executing_kbd_macro = Qnil;
/* End of file in -batch run causes exit here. */
if (noninteractive)
if (display_hourglass_p)
cancel_hourglass ();
#endif
+
+ /* Unblock input if we enter with input blocked. This may happen if
+ redisplay traps e.g. during tool-bar update with input blocked. */
+ while (INPUT_BLOCKED_P)
+ UNBLOCK_INPUT;
+
return Fthrow (Qtop_level, Qnil);
}
Lisp_Object arg;
{
cancel_hourglass ();
+ return Qnil;
}
#endif
resize_echo_area_exactly ();
if (!NILP (Vdeferred_action_list))
- call0 (Vdeferred_action_function);
-
- if (!NILP (Vpost_command_idle_hook) && !NILP (Vrun_hooks))
- {
- if (NILP (Vunread_command_events)
- && NILP (Vunread_input_method_events)
- && NILP (Vunread_post_input_method_events)
- && NILP (Vexecuting_macro)
- && !NILP (sit_for (0, post_command_idle_delay, 0, 1, 1)))
- safe_run_hooks (Qpost_command_idle_hook);
- }
+ safe_run_hooks (Qdeferred_action_function);
}
Vmemory_full = Qnil;
Is this a good idea? */
if (FRAMEP (internal_last_event_frame)
&& !EQ (internal_last_event_frame, selected_frame))
- Fselect_frame (internal_last_event_frame, Qnil);
+ Fselect_frame (internal_last_event_frame);
#endif
/* If it has changed current-menubar from previous value,
really recompute the menubar from the value. */
Vthis_command = Qnil;
real_this_command = Qnil;
+ Vthis_original_command = Qnil;
/* Read next key sequence; i gets its length. */
i = read_key_sequence (keybuf, sizeof keybuf / sizeof keybuf[0],
}
cmd = read_key_sequence_cmd;
- if (!NILP (Vexecuting_macro))
+ if (!NILP (Vexecuting_kbd_macro))
{
if (!NILP (Vquit_flag))
{
- Vexecuting_macro = Qt;
+ Vexecuting_kbd_macro = Qt;
QUIT; /* Make some noise. */
/* Will return since macro now empty. */
}
if (NILP (Vthis_command))
{
/* nil means key is undefined. */
+ Lisp_Object keys = Fvector (i, keybuf);
+ keys = Fkey_description (keys, Qnil);
bitch_at_user ();
+ message_with_string ("%s is undefined", keys, 0);
current_kboard->defining_kbd_macro = Qnil;
update_mode_lines = 1;
current_kboard->Vprefix_arg = Qnil;
&& EQ (current_buffer->selective_display, Qnil)
&& !detect_input_pending ()
&& NILP (XWINDOW (selected_window)->column_number_displayed)
- && NILP (Vexecuting_macro))
+ && NILP (Vexecuting_kbd_macro))
direct_output_forward_char (1);
goto directly_done;
}
&& EQ (current_buffer->selective_display, Qnil)
&& !detect_input_pending ()
&& NILP (XWINDOW (selected_window)->column_number_displayed)
- && NILP (Vexecuting_macro))
+ && NILP (Vexecuting_kbd_macro))
direct_output_forward_char (-1);
goto directly_done;
}
= translate_char (Vtranslation_table_for_input,
XFASTINT (last_command_char), 0, 0, 0);
int value;
- if (NILP (Vexecuting_macro)
+ if (NILP (Vexecuting_kbd_macro)
&& !EQ (minibuf_window, selected_window))
{
if (!nonundocount || nonundocount >= 20)
|| !EQ (current_buffer->selective_display, Qnil)
|| detect_input_pending ()
|| !NILP (XWINDOW (selected_window)->column_number_displayed)
- || !NILP (Vexecuting_macro));
+ || !NILP (Vexecuting_kbd_macro));
value = internal_self_insert (c, 0);
int scount = SPECPDL_INDEX ();
if (display_hourglass_p
- && NILP (Vexecuting_macro))
+ && NILP (Vexecuting_kbd_macro))
{
record_unwind_protect (cancel_hourglass_unwind, Qnil);
start_hourglass ();
hourglass cursor anyway.
But don't cancel the hourglass within a macro
just because a command in the macro finishes. */
- if (NILP (Vexecuting_macro))
+ if (NILP (Vexecuting_kbd_macro))
unbind_to (scount, Qnil);
#endif
}
if (!NILP (Vdeferred_action_list))
safe_run_hooks (Qdeferred_action_function);
- if (!NILP (Vpost_command_idle_hook) && !NILP (Vrun_hooks))
- {
- if (NILP (Vunread_command_events)
- && NILP (Vunread_input_method_events)
- && NILP (Vunread_post_input_method_events)
- && NILP (Vexecuting_macro)
- && !NILP (sit_for (0, post_command_idle_delay, 0, 1, 1)))
- safe_run_hooks (Qpost_command_idle_hook);
- }
-
/* If there is a prefix argument,
1) We don't want Vlast_command to be ``universal-argument''
(that would be dumb), so don't set Vlast_command,
if (!NILP (current_buffer->mark_active) && !NILP (Vrun_hooks))
{
+ /* Setting transient-mark-mode to `only' is a way of
+ turning it on for just one command. */
+
+ if (EQ (Vtransient_mark_mode, Qidentity))
+ Vtransient_mark_mode = Qnil;
+ if (EQ (Vtransient_mark_mode, Qonly))
+ Vtransient_mark_mode = Qidentity;
+
if (!NILP (Vdeactivate_mark) && !NILP (Vtransient_mark_mode))
{
/* We could also call `deactivate'mark'. */
? get_property_and_range (PT, Qdisplay, &val, &beg, &end, Qnil)
: (beg = OVERLAY_POSITION (OVERLAY_START (overlay)),
end = OVERLAY_POSITION (OVERLAY_END (overlay))))
- && beg < PT) /* && end > PT <- It's always the case. */
+ && (beg < PT /* && end > PT <- It's always the case. */
+ || (beg <= PT && STRINGP (val) && SCHARS (val) == 0)))
{
xassert (end > PT);
- SET_PT (PT < last_pt ? beg : end);
+ SET_PT (PT < last_pt
+ ? (STRINGP (val) && SCHARS (val) == 0 ? beg - 1 : beg)
+ : end);
check_composition = check_invisible = 1;
}
check_display = 0;
: (PT < last_pt ? beg : end));
check_composition = check_display = 1;
}
+#if 0 /* This assertion isn't correct, because SET_PT may end up setting
+ the point to something other than its argument, due to
+ point-motion hooks, intangibility, etc. */
xassert (PT == beg || PT == end);
+#endif
+
/* Pretend the area doesn't exist if the buffer is not
modified. */
if (!modified && !ellipsis && beg < end)
struct atimer *timer;
{
if (poll_suppress_count == 0)
+#ifdef SYNC_INPUT
+ interrupt_input_pending = 1;
+#else
poll_for_input_1 ();
+#endif
}
#endif /* POLL_FOR_INPUT */
return c;
}
-/* Display help echo in the echo area.
+/* Display the help-echo property of the character after the mouse pointer.
+ Either show it in the echo area, or call show-help-function to display
+ it by other means (maybe in a tooltip).
- HELP a string means display that string, HELP nil means clear the
- help echo. If HELP is a function, call it with OBJECT and POS as
- arguments; the function should return a help string or nil for
- none. For all other types of HELP evaluate it to obtain a string.
+ If HELP is nil, that means clear the previous help echo.
+
+ If HELP is a string, display that string. If HELP is a function,
+ call it with OBJECT and POS as arguments; the function should
+ return a help string or nil for none. For all other types of HELP,
+ evaluate it to obtain a string.
WINDOW is the window in which the help was generated, if any.
It is nil if not in a window.
return;
}
+#ifdef HAVE_MOUSE
+ if (!noninteractive && STRINGP (help))
+ help = call1 (Qmouse_fixup_help_message, help);
+#endif
+
if (STRINGP (help) || NILP (help))
{
if (!NILP (Vshow_help_function))
volatile Lisp_Object also_record;
volatile int reread;
struct gcpro gcpro1, gcpro2;
- EMACS_TIME last_idle_start;
int polling_stopped_here = 0;
also_record = Qnil;
this_command_key_count_reset = 0;
- if (!NILP (Vexecuting_macro))
+ if (!NILP (Vexecuting_kbd_macro))
{
/* We set this to Qmacro; since that's not a frame, nobody will
try to switch frames on us, and the selected window will
/* Exit the macro if we are at the end.
Also, some things replace the macro with t
to force an early exit. */
- if (EQ (Vexecuting_macro, Qt)
- || executing_macro_index >= XFASTINT (Flength (Vexecuting_macro)))
+ if (EQ (Vexecuting_kbd_macro, Qt)
+ || executing_kbd_macro_index >= XFASTINT (Flength (Vexecuting_kbd_macro)))
{
XSETINT (c, -1);
goto exit;
}
- c = Faref (Vexecuting_macro, make_number (executing_macro_index));
- if (STRINGP (Vexecuting_macro)
- && (XINT (c) & 0x80))
+ c = Faref (Vexecuting_kbd_macro, make_number (executing_kbd_macro_index));
+ if (STRINGP (Vexecuting_kbd_macro)
+ && (XINT (c) & 0x80) && (XUINT (c) <= 0xff))
XSETFASTINT (c, CHAR_META | (XINT (c) & ~0x80));
- executing_macro_index++;
+ executing_kbd_macro_index++;
goto from_macro;
}
if (_setjmp (local_getcjmp))
{
+ /* We must have saved the outer value of getcjmp here,
+ so restore it now. */
+ restore_getcjmp (save_jump);
XSETINT (c, quit_char);
internal_last_event_frame = selected_frame;
Vlast_event_frame = internal_last_event_frame;
non_reread:
- /* Record the last idle start time so that we can reset it
- should the next event read be a help-echo. */
- last_idle_start = timer_idleness_start_time;
timer_stop_idle ();
RESUME_POLLING;
prevents automatic window selection (under
mouse_autoselect_window from acting as a real input event, for
example banishing the mouse under mouse-avoidance-mode. */
- timer_idleness_start_time = last_idle_start;
+ timer_resume_idle ();
/* Resume allowing input from any kboard, if that was true before. */
if (!was_locked)
{
Lisp_Object posn;
- posn = POSN_BUFFER_POSN (EVENT_START (c));
+ posn = POSN_POSN (EVENT_START (c));
/* Handle menu-bar events:
insert the dummy prefix event `menu-bar'. */
if (EQ (posn, Qmenu_bar) || EQ (posn, Qtool_bar))
{
/* Change menu-bar to (menu-bar) as the event "position". */
- POSN_BUFFER_SET_POSN (EVENT_START (c), Fcons (posn, Qnil));
+ POSN_SET_POSN (EVENT_START (c), Fcons (posn, Qnil));
also_record = c;
Vunread_command_events = Fcons (c, Vunread_command_events);
/* Save the echo status. */
int saved_immediate_echo = current_kboard->immediate_echo;
struct kboard *saved_ok_to_echo = ok_to_echo_at_next_pause;
+ Lisp_Object saved_echo_string = current_kboard->echo_string;
int saved_echo_after_prompt = current_kboard->echo_after_prompt;
#if 0
cancel_echoing ();
ok_to_echo_at_next_pause = saved_ok_to_echo;
+ current_kboard->echo_string = saved_echo_string;
current_kboard->echo_after_prompt = saved_echo_after_prompt;
if (saved_immediate_echo)
echo_now ();
show_help_echo (help, window, object, position, 0);
/* We stopped being idle for this event; undo that. */
- timer_idleness_start_time = last_idle_start;
+ timer_resume_idle ();
goto retry;
}
input has been processed. If the only input available was
the sort that we have just disabled, then we need to call
redisplay. */
- if (!readable_events (1))
+ if (!readable_events (READABLE_EVENTS_DO_TIMERS_NOW))
{
redisplay_preserve_echo_area (6);
- get_input_pending (&input_pending, 1);
+ get_input_pending (&input_pending,
+ READABLE_EVENTS_DO_TIMERS_NOW);
}
}
return Qnil;
/* Return true iff there are any events in the queue that read-char
would return. If this returns false, a read-char would block. */
static int
-readable_filtered_events (do_timers_now, filter_events)
- int do_timers_now;
- int filter_events;
+readable_events (flags)
+ int flags;
{
- if (do_timers_now)
- timer_check (do_timers_now);
+ if (flags & READABLE_EVENTS_DO_TIMERS_NOW)
+ timer_check (1);
- /* If the buffer contains only FOCUS_IN_EVENT events,
- and FILTER_EVENTS is nonzero, report it as empty. */
+ /* If the buffer contains only FOCUS_IN_EVENT events, and
+ READABLE_EVENTS_FILTER_EVENTS is set, report it as empty. */
if (kbd_fetch_ptr != kbd_store_ptr)
{
- int have_live_event = 1;
-
- if (filter_events)
+ if (flags & (READABLE_EVENTS_FILTER_EVENTS
+#ifdef USE_TOOLKIT_SCROLL_BARS
+ | READABLE_EVENTS_IGNORE_SQUEEZABLES
+#endif
+ ))
{
struct input_event *event;
? kbd_fetch_ptr
: kbd_buffer);
- while (have_live_event && event->kind == FOCUS_IN_EVENT)
- {
- event++;
+ do
+ {
+ if (!(
+#ifdef USE_TOOLKIT_SCROLL_BARS
+ (flags & READABLE_EVENTS_FILTER_EVENTS) &&
+#endif
+ event->kind == FOCUS_IN_EVENT)
+#ifdef USE_TOOLKIT_SCROLL_BARS
+ && !((flags & READABLE_EVENTS_IGNORE_SQUEEZABLES)
+ && event->kind == SCROLL_BAR_CLICK_EVENT
+ && event->part == scroll_bar_handle
+ && event->modifiers == 0)
+#endif
+ )
+ return 1;
+ event++;
if (event == kbd_buffer + KBD_BUFFER_SIZE)
event = kbd_buffer;
- if (event == kbd_store_ptr)
- have_live_event = 0;
- }
+ }
+ while (event != kbd_store_ptr);
}
- if (have_live_event) return 1;
+ else
+ return 1;
}
#ifdef HAVE_MOUSE
- if (!NILP (do_mouse_tracking) && some_mouse_moved ())
+ if (!(flags & READABLE_EVENTS_IGNORE_SQUEEZABLES)
+ && !NILP (do_mouse_tracking) && some_mouse_moved ())
return 1;
#endif
if (single_kboard)
return 0;
}
-/* Return true iff there are any events in the queue that read-char
- would return. If this returns false, a read-char would block. */
-static int
-readable_events (do_timers_now)
- int do_timers_now;
-{
- return readable_filtered_events (do_timers_now, 0);
-}
-
/* Set this for debugging, to have a way to get out */
int stop_character;
}
#endif
+
+Lisp_Object Vthrow_on_input;
+
/* Store an event obtained at interrupt level into kbd_buffer, fifo */
void
kbd_buffer_store_event (event)
register struct input_event *event;
+{
+ kbd_buffer_store_event_hold (event, 0);
+}
+
+/* Store EVENT obtained at interrupt level into kbd_buffer, fifo.
+
+ If HOLD_QUIT is 0, just stuff EVENT into the fifo.
+ Else, if HOLD_QUIT.kind != NO_EVENT, discard EVENT.
+ Else, if EVENT is a quit event, store the quit event
+ in HOLD_QUIT, and return (thus ignoring further events).
+
+ This is used in read_avail_input to postpone the processing
+ of the quit event until all subsequent input events have been
+ parsed (and discarded).
+ */
+
+void
+kbd_buffer_store_event_hold (event, hold_quit)
+ register struct input_event *event;
+ struct input_event *hold_quit;
{
if (event->kind == NO_EVENT)
abort ();
+ if (hold_quit && hold_quit->kind != NO_EVENT)
+ return;
+
if (event->kind == ASCII_KEYSTROKE_EVENT)
{
register int c = event->code & 0377;
}
#endif
+ if (hold_quit)
+ {
+ bcopy (event, (char *) hold_quit, sizeof (*event));
+ return;
+ }
+
/* If this results in a quit_char being returned to Emacs as
input, set Vlast_event_frame properly. If this doesn't
get returned to Emacs as an event, the next event read
Just ignore the second one. */
else if (event->kind == BUFFER_SWITCH_EVENT
&& kbd_fetch_ptr != kbd_store_ptr
- && kbd_store_ptr->kind == BUFFER_SWITCH_EVENT)
+ && ((kbd_store_ptr == kbd_buffer
+ ? kbd_buffer + KBD_BUFFER_SIZE - 1
+ : kbd_store_ptr - 1)->kind) == BUFFER_SWITCH_EVENT)
return;
if (kbd_store_ptr - kbd_buffer == KBD_BUFFER_SIZE)
Discard the event if it would fill the last slot. */
if (kbd_fetch_ptr - 1 != kbd_store_ptr)
{
- int idx;
+ *kbd_store_ptr = *event;
+ ++kbd_store_ptr;
+ }
-#if 0 /* The SELECTION_REQUEST_EVENT case looks bogus, and it's error
- prone to assign individual members for other events, in case
- the input_event structure is changed. --2000-07-13, gerd. */
- struct input_event *sp = kbd_store_ptr;
- sp->kind = event->kind;
- if (event->kind == SELECTION_REQUEST_EVENT)
+ /* If we're inside while-no-input, and this event qualifies
+ as input, set quit-flag to cause an interrupt. */
+ if (!NILP (Vthrow_on_input)
+ && event->kind != FOCUS_IN_EVENT
+ && event->kind != HELP_EVENT
+ && event->kind != DEICONIFY_EVENT)
+ {
+ Vquit_flag = Vthrow_on_input;
+ /* If we're inside a function that wants immediate quits,
+ do it now. */
+ if (immediate_quit && NILP (Vinhibit_quit))
{
- /* We must not use the ordinary copying code for this case,
- since `part' is an enum and copying it might not copy enough
- in this case. */
- bcopy (event, (char *) sp, sizeof (*event));
+ immediate_quit = 0;
+ sigfree ();
+ QUIT;
}
- else
+ }
+}
- {
- sp->code = event->code;
- sp->part = event->part;
- sp->frame_or_window = event->frame_or_window;
- sp->arg = event->arg;
- sp->modifiers = event->modifiers;
- sp->x = event->x;
- sp->y = event->y;
- sp->timestamp = event->timestamp;
- }
-#else
- *kbd_store_ptr = *event;
-#endif
- idx = 2 * (kbd_store_ptr - kbd_buffer);
- ASET (kbd_buffer_gcpro, idx, event->frame_or_window);
- ASET (kbd_buffer_gcpro, idx + 1, event->arg);
- ++kbd_store_ptr;
+/* Put an input event back in the head of the event queue. */
+
+void
+kbd_buffer_unget_event (event)
+ register struct input_event *event;
+{
+ if (kbd_fetch_ptr == kbd_buffer)
+ kbd_fetch_ptr = kbd_buffer + KBD_BUFFER_SIZE;
+
+ /* Don't let the very last slot in the buffer become full, */
+ if (kbd_fetch_ptr - 1 != kbd_store_ptr)
+ {
+ --kbd_fetch_ptr;
+ *kbd_fetch_ptr = *event;
}
}
Value is the number of input_events generated. */
-int
-gen_help_event (bufp, size, help, frame, window, object, pos)
- struct input_event *bufp;
- int size;
+void
+gen_help_event (help, frame, window, object, pos)
Lisp_Object help, frame, object, window;
int pos;
{
- if (size >= 1)
- {
- bufp->kind = HELP_EVENT;
- bufp->frame_or_window = frame;
- bufp->arg = object;
- bufp->x = WINDOWP (window) ? window : frame;
- bufp->y = help;
- bufp->code = pos;
- return 1;
- }
- return 0;
+ struct input_event event;
+
+ EVENT_INIT (event);
+
+ event.kind = HELP_EVENT;
+ event.frame_or_window = frame;
+ event.arg = object;
+ event.x = WINDOWP (window) ? window : frame;
+ event.y = help;
+ event.code = pos;
+ kbd_buffer_store_event (&event);
}
clear_event (event)
struct input_event *event;
{
- int idx = 2 * (event - kbd_buffer);
- ASET (kbd_buffer_gcpro, idx, Qnil);
- ASET (kbd_buffer_gcpro, idx + 1, Qnil);
event->kind = NO_EVENT;
}
break;
#endif
{
- Lisp_Object minus_one;
-
- XSETINT (minus_one, -1);
- wait_reading_process_input (0, 0, minus_one, 1);
+ wait_reading_process_output (0, 0, -1, 1, Qnil, NULL, 0);
if (!interrupt_input && kbd_fetch_ptr == kbd_store_ptr)
/* Pass 1 for EXPECT since we just waited to have input. */
/* These two kinds of events get special handling
and don't actually appear to the command loop.
We return nil for them. */
- if (event->kind == SELECTION_REQUEST_EVENT)
+ if (event->kind == SELECTION_REQUEST_EVENT
+ || event->kind == SELECTION_CLEAR_EVENT)
{
#ifdef HAVE_X11
struct input_event copy;
copy = *event;
kbd_fetch_ptr = event + 1;
input_pending = readable_events (0);
- x_handle_selection_request (©);
+ x_handle_selection_event (©);
#else
/* We're getting selection request events, but we don't have
a window system. */
#endif
}
- else if (event->kind == SELECTION_CLEAR_EVENT)
- {
-#ifdef HAVE_X11
- struct input_event copy;
-
- /* Remove it from the buffer before processing it. */
- copy = *event;
- kbd_fetch_ptr = event + 1;
- input_pending = readable_events (0);
- x_handle_selection_clear (©);
-#else
- /* We're getting selection request events, but we don't have
- a window system. */
- abort ();
-#endif
- }
#if defined (HAVE_X11) || defined (HAVE_NTGUI) || defined (MAC_OS)
else if (event->kind == DELETE_WINDOW_EVENT)
{
x_activate_menubar (XFRAME (event->frame_or_window));
}
#endif
-#ifdef WINDOWSNT
+#if defined (WINDOWSNT) || defined (MAC_OS)
else if (event->kind == LANGUAGE_CHANGE_EVENT)
{
+#ifdef MAC_OS
+ /* Make an event (language-change (KEY_SCRIPT)). */
+ obj = Fcons (make_number (event->code), Qnil);
+#else
/* Make an event (language-change (FRAME CHARSET LCID)). */
- obj = Fcons (event->modifiers, Qnil);
- obj = Fcons (event->code, obj);
- obj = Fcons (event->frame_or_window, obj);
+ obj = Fcons (event->frame_or_window, Qnil);
+#endif
obj = Fcons (Qlanguage_change, Fcons (obj, Qnil));
kbd_fetch_ptr = event + 1;
}
/* These two kinds of events get special handling
and don't actually appear to the command loop. */
- if (event->kind == SELECTION_REQUEST_EVENT)
+ if (event->kind == SELECTION_REQUEST_EVENT
+ || event->kind == SELECTION_CLEAR_EVENT)
{
#ifdef HAVE_X11
struct input_event copy;
copy = *event;
kbd_fetch_ptr = event + 1;
input_pending = readable_events (0);
- x_handle_selection_request (©);
-#else
- /* We're getting selection request events, but we don't have
- a window system. */
- abort ();
-#endif
- }
-
- else if (event->kind == SELECTION_CLEAR_EVENT)
- {
-#ifdef HAVE_X11
- struct input_event copy;
-
- /* Remove it from the buffer before processing it, */
- copy = *event;
-
- kbd_fetch_ptr = event + 1;
- input_pending = readable_events (0);
- x_handle_selection_clear (©);
+ x_handle_selection_event (©);
#else
/* We're getting selection request events, but we don't have
a window system. */
}
old_timers_run = timers_run;
- get_input_pending (&input_pending, 1);
+ get_input_pending (&input_pending, READABLE_EVENTS_DO_TIMERS_NOW);
if (timers_run != old_timers_run && do_display)
redisplay_preserve_echo_area (7);
/* Record the start of when Emacs is idle,
for the sake of running idle-time timers. */
-void
+static void
timer_start_idle ()
{
Lisp_Object timers;
/* Record that Emacs is no longer idle, so stop running idle-time timers. */
-void
+static void
timer_stop_idle ()
{
EMACS_SET_SECS_USECS (timer_idleness_start_time, -1, -1);
}
+/* Resume idle timer from last idle start time. */
+
+static void
+timer_resume_idle ()
+{
+ if (! EMACS_TIME_NEG_P (timer_idleness_start_time))
+ return;
+
+ timer_idleness_start_time = timer_last_idleness_start_time;
+}
+
/* This is only for debugging. */
struct input_event last_timer_event;
{
/* It's a click in window window at frame coordinates (x,y) */
struct window *w = XWINDOW (window);
- Lisp_Object object = Qnil;
+ Lisp_Object string_info = Qnil;
int textpos = -1, rx = -1, ry = -1;
int dx = -1, dy = -1;
+ int width = -1, height = -1;
+ Lisp_Object object = Qnil;
/* Set event coordinates to window-relative coordinates
for constructing the Lisp event below. */
posn = part == ON_MODE_LINE ? Qmode_line : Qheader_line;
rx = wx, ry = wy;
- string = mode_line_string (w, &rx, &ry, &dx, &dy, part, &charpos);
+ string = mode_line_string (w, part, &rx, &ry, &charpos,
+ &object, &dx, &dy, &width, &height);
if (STRINGP (string))
- object = Fcons (string, make_number (charpos));
+ string_info = Fcons (string, make_number (charpos));
if (w == XWINDOW (selected_window))
textpos = PT;
else
posn = Qvertical_line;
wx = -1;
dx = 0;
+ width = 1;
}
else if (part == ON_LEFT_MARGIN || part == ON_RIGHT_MARGIN)
{
Lisp_Object string;
int charpos;
-
+
posn = (part == ON_LEFT_MARGIN) ? Qleft_margin : Qright_margin;
rx = wx, ry = wy;
- string = marginal_area_string (w, &rx, &ry, &dx, &dy, part, &charpos);
+ string = marginal_area_string (w, part, &rx, &ry, &charpos,
+ &object, &dx, &dy, &width, &height);
if (STRINGP (string))
- object = Fcons (string, make_number (charpos));
-#ifdef HAVE_WINDOW_SYSTEM
- else if (IMAGEP (string))
- {
- Lisp_Object image_map, hotspot;
- object = string;
- if ((image_map = Fplist_get (XCDR (object), QCmap),
- !NILP (image_map))
- && (hotspot = find_hot_spot (image_map, dx, dy),
- CONSP (hotspot))
- && (hotspot = XCDR (hotspot), CONSP (hotspot)))
- posn = XCAR (hotspot);
- }
-#endif
+ string_info = Fcons (string, make_number (charpos));
}
else if (part == ON_LEFT_FRINGE || part == ON_RIGHT_FRINGE)
{
if (textpos < 0)
{
- Lisp_Object string;
+ Lisp_Object string2, object2 = Qnil;
struct display_pos p;
int dx2, dy2;
+ int width2, height2;
wx = max (WINDOW_LEFT_MARGIN_WIDTH (w), wx);
- buffer_posn_from_coords (w, &wx, &wy, &dx2, &dy2, &string, &p);
+ string2 = buffer_posn_from_coords (w, &wx, &wy, &p,
+ &object2, &dx2, &dy2,
+ &width2, &height2);
textpos = CHARPOS (p.pos);
if (rx < 0) rx = wx;
if (ry < 0) ry = wy;
if (dx < 0) dx = dx2;
if (dy < 0) dy = dy2;
+ if (width < 0) width = width2;
+ if (height < 0) height = height2;
if (NILP (posn))
{
posn = make_number (textpos);
- if (STRINGP (string))
- object = Fcons (string,
- make_number (CHARPOS (p.string_pos)));
-#ifdef HAVE_WINDOW_SYSTEM
- else if (IMAGEP (string))
- {
- Lisp_Object image_map, hotspot;
- object = string;
- if ((image_map = Fplist_get (XCDR (object), QCmap),
- !NILP (image_map))
- && (hotspot = find_hot_spot (image_map, dx, dy),
- CONSP (hotspot))
- && (hotspot = XCDR (hotspot), CONSP (hotspot)))
- posn = XCAR (hotspot);
- }
-#endif
+ if (STRINGP (string2))
+ string_info = Fcons (string2,
+ make_number (CHARPOS (p.string_pos)));
}
+ if (NILP (object))
+ object = object2;
+ }
+
+#ifdef HAVE_WINDOW_SYSTEM
+ if (IMAGEP (object))
+ {
+ Lisp_Object image_map, hotspot;
+ if ((image_map = Fplist_get (XCDR (object), QCmap),
+ !NILP (image_map))
+ && (hotspot = find_hot_spot (image_map, dx, dy),
+ CONSP (hotspot))
+ && (hotspot = XCDR (hotspot), CONSP (hotspot)))
+ posn = XCAR (hotspot);
}
+#endif
+ /* Object info */
extra_info = Fcons (object,
+ Fcons (Fcons (make_number (dx),
+ make_number (dy)),
+ Fcons (Fcons (make_number (width),
+ make_number (height)),
+ Qnil)));
+
+ /* String info */
+ extra_info = Fcons (string_info,
Fcons (make_number (textpos),
Fcons (Fcons (make_number (rx),
make_number (ry)),
- Fcons (Fcons (make_number (dx),
- make_number (dy)),
- Qnil))));
+ extra_info)));
}
else if (f != 0)
{
{
Lisp_Object position;
Lisp_Object head;
-
+
/* Build the position as appropriate for this mouse click. */
struct frame *f = XFRAME (event->frame_or_window);
{
int len = SBYTES (name_alist_or_stem);
char *buf = (char *) alloca (len + 50);
- if (sizeof (int) == sizeof (EMACS_INT))
- sprintf (buf, "%s-%d", SDATA (name_alist_or_stem),
- XINT (symbol_int) + 1);
- else if (sizeof (long) == sizeof (EMACS_INT))
- sprintf (buf, "%s-%ld", SDATA (name_alist_or_stem),
- XINT (symbol_int) + 1);
+ sprintf (buf, "%s-%ld", SDATA (name_alist_or_stem),
+ (long) XINT (symbol_int) + 1);
value = intern (buf);
}
else if (name_table != 0 && name_table[symbol_num])
but works even if FIONREAD does not exist.
(In fact, this may actually read some input.)
- If DO_TIMERS_NOW is nonzero, actually run timer events that are ripe.
- If FILTER_EVENTS is nonzero, ignore internal events (FOCUS_IN_EVENT). */
+ If READABLE_EVENTS_DO_TIMERS_NOW is set in FLAGS, actually run
+ timer events that are ripe.
+ If READABLE_EVENTS_FILTER_EVENTS is set in FLAGS, ignore internal
+ events (FOCUS_IN_EVENT).
+ If READABLE_EVENTS_IGNORE_SQUEEZABLES is set in FLAGS, ignore mouse
+ movements and toolkit scroll bar thumb drags. */
static void
-get_filtered_input_pending (addr, do_timers_now, filter_events)
+get_input_pending (addr, flags)
int *addr;
- int do_timers_now;
- int filter_events;
+ int flags;
{
/* First of all, have we already counted some input? */
- *addr = (!NILP (Vquit_flag)
- || readable_filtered_events (do_timers_now, filter_events));
+ *addr = (!NILP (Vquit_flag) || readable_events (flags));
/* If input is being read as it arrives, and we have none, there is none. */
if (*addr > 0 || (interrupt_input && ! interrupts_deferred))
/* Try to read some input and see how much we get. */
gobble_input (0);
- *addr = (!NILP (Vquit_flag)
- || readable_filtered_events (do_timers_now, filter_events));
-}
-
-/* Store into *addr a value nonzero if terminal input chars are available.
- Serves the purpose of ioctl (0, FIONREAD, addr)
- but works even if FIONREAD does not exist.
- (In fact, this may actually read some input.)
-
- If DO_TIMERS_NOW is nonzero, actually run timer events that are ripe. */
-
-static void
-get_input_pending (addr, do_timers_now)
- int *addr;
- int do_timers_now;
-{
- get_filtered_input_pending (addr, do_timers_now, 0);
+ *addr = (!NILP (Vquit_flag) || readable_events (flags));
}
/* Interface to read_avail_input, blocking SIGIO or SIGALRM if necessary. */
read_avail_input (expected)
int expected;
{
- struct input_event buf[KBD_BUFFER_SIZE];
register int i;
- int nread;
-
- for (i = 0; i < KBD_BUFFER_SIZE; i++)
- EVENT_INIT (buf[i]);
+ int nread = 0;
if (read_socket_hook)
- /* No need for FIONREAD or fcntl; just say don't wait. */
- nread = (*read_socket_hook) (input_fd, buf, KBD_BUFFER_SIZE, expected);
+ {
+ int nr;
+ struct input_event hold_quit;
+
+ EVENT_INIT (hold_quit);
+ hold_quit.kind = NO_EVENT;
+
+ /* No need for FIONREAD or fcntl; just say don't wait. */
+ while (nr = (*read_socket_hook) (input_fd, expected, &hold_quit), nr > 0)
+ {
+ nread += nr;
+ expected = 0;
+ }
+ if (hold_quit.kind != NO_EVENT)
+ kbd_buffer_store_event (&hold_quit);
+ }
else
{
/* Using KBD_BUFFER_SIZE - 1 here avoids reading more than
#endif /* no FIONREAD */
for (i = 0; i < nread; i++)
{
- buf[i].kind = ASCII_KEYSTROKE_EVENT;
- buf[i].modifiers = 0;
+ struct input_event buf;
+ EVENT_INIT (buf);
+ buf.kind = ASCII_KEYSTROKE_EVENT;
+ buf.modifiers = 0;
if (meta_key == 1 && (cbuf[i] & 0x80))
- buf[i].modifiers = meta_modifier;
+ buf.modifiers = meta_modifier;
if (meta_key != 2)
cbuf[i] &= ~0x80;
- buf[i].code = cbuf[i];
- buf[i].frame_or_window = selected_frame;
- buf[i].arg = Qnil;
- }
- }
+ buf.code = cbuf[i];
+ buf.frame_or_window = selected_frame;
+ buf.arg = Qnil;
- /* Scan the chars for C-g and store them in kbd_buffer. */
- for (i = 0; i < nread; i++)
- {
- kbd_buffer_store_event (&buf[i]);
- /* Don't look at input that follows a C-g too closely.
- This reduces lossage due to autorepeat on C-g. */
- if (buf[i].kind == ASCII_KEYSTROKE_EVENT
- && buf[i].code == quit_char)
- break;
+ kbd_buffer_store_event (&buf);
+ /* Don't look at input that follows a C-g too closely.
+ This reduces lossage due to autorepeat on C-g. */
+ if (buf.kind == ASCII_KEYSTROKE_EVENT
+ && buf.code == quit_char)
+ break;
+ }
}
return nread;
}
#endif /* not VMS */
\f
+void
+handle_async_input ()
+{
+#ifdef BSD4_1
+ extern int select_alarmed;
+#endif
+
+ interrupt_input_pending = 0;
+
+ while (1)
+ {
+ int nread;
+ nread = read_avail_input (1);
+ /* -1 means it's not ok to read the input now.
+ UNBLOCK_INPUT will read it later; now, avoid infinite loop.
+ 0 means there was no keyboard input available. */
+ if (nread <= 0)
+ break;
+
+#ifdef BSD4_1
+ select_alarmed = 1; /* Force the select emulator back to life */
+#endif
+ }
+}
+
#ifdef SIGIO /* for entire page */
/* Note SIGIO has been undef'd if FIONREAD is missing. */
{
/* Must preserve main program's value of errno. */
int old_errno = errno;
-#ifdef BSD4_1
- extern int select_alarmed;
-#endif
-
#if defined (USG) && !defined (POSIX_SIGNALS)
/* USG systems forget handlers when they are used;
must reestablish each time */
sigisheld (SIGIO);
#endif
+#ifdef SYNC_INPUT
+ interrupt_input_pending = 1;
+#else
+ SIGNAL_THREAD_CHECK (signo);
+#endif
+
if (input_available_clear_time)
EMACS_SET_SECS_USECS (*input_available_clear_time, 0, 0);
- while (1)
- {
- int nread;
- nread = read_avail_input (1);
- /* -1 means it's not ok to read the input now.
- UNBLOCK_INPUT will read it later; now, avoid infinite loop.
- 0 means there was no keyboard input available. */
- if (nread <= 0)
- break;
-
-#ifdef BSD4_1
- select_alarmed = 1; /* Force the select emulator back to life */
+#ifndef SYNC_INPUT
+ handle_async_input ();
#endif
- }
#ifdef BSD4_1
sigfree ();
reinvoke_input_signal ()
{
#ifdef SIGIO
- kill (getpid (), SIGIO);
+ handle_async_input ();
#endif
}
int i;
- struct gcpro gcpro1;
-
/* In order to build the menus, we need to call the keymap
accessors. They all call QUIT. But this function is called
during redisplay, during which a quit is fatal. So inhibit
menu_bar_items_vector = Fmake_vector (make_number (24), Qnil);
menu_bar_items_index = 0;
- GCPRO1 (menu_bar_items_vector);
-
/* Build our list of keymaps.
If we recognize a function key and replace its escape sequence in
keybuf with its symbol, or if the sequence starts with a mouse
menu_bar_items_index = i;
Vinhibit_quit = oquit;
- UNGCPRO;
return menu_bar_items_vector;
}
\f
newcache = chkcache;
if (chkcache)
{
- tem = Fkey_description (tem);
+ tem = Fkey_description (tem, Qnil);
if (CONSP (prefix))
{
if (STRINGP (XCAR (prefix)))
int do_funcall;
{
Lisp_Object next;
-
+
next = access_keymap (map, key, 1, 0, 1);
/* Handle symbol with autoload definition. */
&& (!NILP (Farrayp (XSYMBOL (next)->function))
|| KEYMAPP (XSYMBOL (next)->function)))
next = XSYMBOL (next)->function;
-
+
/* If the keymap gives a function, not an
array, then call the function with one arg and use
its value instead. */
keymap may have changed, so replay the sequence. */
if (BUFFERP (key))
{
- EMACS_TIME initial_idleness_start_time;
- EMACS_SET_SECS_USECS (initial_idleness_start_time,
- EMACS_SECS (timer_last_idleness_start_time),
- EMACS_USECS (timer_last_idleness_start_time));
-
- /* Resume idle state, using the same start-time as before. */
- timer_start_idle ();
- timer_idleness_start_time = initial_idleness_start_time;
+ timer_resume_idle ();
mock_input = t;
/* Reset the current buffer from the selected window
Lisp_Object window, posn;
window = POSN_WINDOW (EVENT_START (key));
- posn = POSN_BUFFER_POSN (EVENT_START (key));
+ posn = POSN_POSN (EVENT_START (key));
if (CONSP (posn)
|| (!NILP (fake_prefixed_keys)
localized_local_map = 1;
start = EVENT_START (key);
- if (CONSP (start) && CONSP (XCDR (start)))
+ if (CONSP (start) && POSN_INBUFFER_P (start))
{
pos = POSN_BUFFER_POSN (start);
if (INTEGERP (pos)
{
Lisp_Object posn;
- posn = POSN_BUFFER_POSN (EVENT_START (key));
+ posn = POSN_POSN (EVENT_START (key));
/* Handle menu-bar events:
insert the dummy prefix event `menu-bar'. */
if (EQ (posn, Qmenu_bar) || EQ (posn, Qtool_bar))
/* Zap the position in key, so we know that we've
expanded it, and don't try to do so again. */
- POSN_BUFFER_SET_POSN (EVENT_START (key),
- Fcons (posn, Qnil));
+ POSN_SET_POSN (EVENT_START (key),
+ Fcons (posn, Qnil));
mock_input = t + 2;
goto replay_sequence;
/* Adjust the function-key-map counters. */
fkey.end += diff;
fkey.start += diff;
-
+
goto replay_sequence;
}
}
tem = Fget (cmd, Qdisabled);
if (!NILP (tem) && !NILP (Vrun_hooks))
{
- tem = Fsymbol_value (Qdisabled_command_hook);
+ tem = Fsymbol_value (Qdisabled_command_function);
if (!NILP (tem))
- return call1 (Vrun_hooks, Qdisabled_command_hook);
+ return call1 (Vrun_hooks, Qdisabled_command_function);
}
}
backtrace.args = &cmd;
backtrace.nargs = 1;
backtrace.evalargs = 0;
+ backtrace.debug_on_exit = 0;
tem = Fcall_interactively (cmd, record_flag, keys);
Lisp_Object saved_keys, saved_last_point_position_buffer;
Lisp_Object bindings, value;
struct gcpro gcpro1, gcpro2, gcpro3;
+#ifdef HAVE_X_WINDOWS
+ /* The call to Fcompleting_read wil start and cancel the hourglass,
+ but if the hourglass was already scheduled, this means that no
+ hourglass will be shown for the actual M-x command itself.
+ So we restart it if it is already scheduled. Note that checking
+ hourglass_shown_p is not enough, normally the hourglass is not shown,
+ just scheduled to be shown. */
+ int hstarted = hourglass_started ();
+#endif
saved_keys = Fvector (this_command_key_count,
XVECTOR (this_command_keys)->contents);
else if (CONSP (prefixarg) && XINT (XCAR (prefixarg)) == 4)
strcpy (buf, "C-u ");
else if (CONSP (prefixarg) && INTEGERP (XCAR (prefixarg)))
- {
- if (sizeof (int) == sizeof (EMACS_INT))
- sprintf (buf, "%d ", XINT (XCAR (prefixarg)));
- else if (sizeof (long) == sizeof (EMACS_INT))
- sprintf (buf, "%ld ", (long) XINT (XCAR (prefixarg)));
- else
- abort ();
- }
+ sprintf (buf, "%ld ", (long) XINT (XCAR (prefixarg)));
else if (INTEGERP (prefixarg))
- {
- if (sizeof (int) == sizeof (EMACS_INT))
- sprintf (buf, "%d ", XINT (prefixarg));
- else if (sizeof (long) == sizeof (EMACS_INT))
- sprintf (buf, "%ld ", (long) XINT (prefixarg));
- else
- abort ();
- }
+ sprintf (buf, "%ld ", (long) XINT (prefixarg));
/* This isn't strictly correct if execute-extended-command
is bound to anything else. Perhaps it should use
Qt, Qnil, Qextended_command_history, Qnil,
Qnil);
+#ifdef HAVE_X_WINDOWS
+ if (hstarted) start_hourglass ();
+#endif
+
if (STRINGP (function) && SCHARS (function) == 0)
error ("No command name given");
/* If enabled, show which key runs this command. */
if (!NILP (Vsuggest_key_bindings)
- && NILP (Vexecuting_macro)
+ && NILP (Vexecuting_kbd_macro)
&& SYMBOLP (function))
bindings = Fwhere_is_internal (function, Voverriding_local_map,
Qt, Qnil, Qnil);
int count = SPECPDL_INDEX ();
record_unwind_protect (pop_message_unwind, Qnil);
- binding = Fkey_description (bindings);
+ binding = Fkey_description (bindings, Qnil);
newmessage
= (char *) alloca (SCHARS (SYMBOL_NAME (function))
return input_pending;
}
+/* Return nonzero if input events other than mouse movements are
+ pending. */
+
+int
+detect_input_pending_ignore_squeezables ()
+{
+ if (!input_pending)
+ get_input_pending (&input_pending, READABLE_EVENTS_IGNORE_SQUEEZABLES);
+
+ return input_pending;
+}
+
/* Return nonzero if input events are pending, and run any pending timers. */
int
int old_timers_run = timers_run;
if (!input_pending)
- get_input_pending (&input_pending, 1);
+ get_input_pending (&input_pending, READABLE_EVENTS_DO_TIMERS_NOW);
if (old_timers_run != timers_run && do_display)
{
}
/* Return nonzero if there are pending requeued events.
- This isn't used yet. The hope is to make wait_reading_process_input
+ This isn't used yet. The hope is to make wait_reading_process_output
call it, and return if it runs Lisp code that unreads something.
The problem is, kbd_buffer_get_event needs to be fixed to know what
to do in that case. It isn't trivial. */
if (!NILP (Vunread_command_events) || unread_command_char != -1)
return (Qt);
- get_filtered_input_pending (&input_pending, 1, 1);
+ get_input_pending (&input_pending,
+ READABLE_EVENTS_DO_TIMERS_NOW
+ | READABLE_EVENTS_FILTER_EVENTS);
return input_pending > 0 ? Qt : Qnil;
}
discard_tty_input ();
kbd_fetch_ptr = kbd_store_ptr;
- Ffillarray (kbd_buffer_gcpro, Qnil);
input_pending = 0;
return Qnil;
stuff_buffered_input (stuffstring)
Lisp_Object stuffstring;
{
-/* stuff_char works only in BSD, versions 4.2 and up. */
-#ifdef BSD_SYSTEM
-#ifndef BSD4_1
+#ifdef SIGTSTP /* stuff_char is defined if SIGTSTP. */
register unsigned char *p;
if (STRINGP (stuffstring))
/* Anything we have read ahead, put back for the shell to read. */
/* ?? What should this do when we have multiple keyboards??
- Should we ignore anything that was typed in at the "wrong" kboard? */
+ Should we ignore anything that was typed in at the "wrong" kboard?
+
+ rms: we should stuff everything back into the kboard
+ it came from. */
for (; kbd_fetch_ptr != kbd_store_ptr; kbd_fetch_ptr++)
{
- int idx;
if (kbd_fetch_ptr == kbd_buffer + KBD_BUFFER_SIZE)
kbd_fetch_ptr = kbd_buffer;
if (kbd_fetch_ptr->kind == ASCII_KEYSTROKE_EVENT)
stuff_char (kbd_fetch_ptr->code);
- kbd_fetch_ptr->kind = NO_EVENT;
- idx = 2 * (kbd_fetch_ptr - kbd_buffer);
- ASET (kbd_buffer_gcpro, idx, Qnil);
- ASET (kbd_buffer_gcpro, idx + 1, Qnil);
+ clear_event (kbd_fetch_ptr);
}
input_pending = 0;
-#endif
-#endif /* BSD_SYSTEM and not BSD4_1 */
+#endif /* SIGTSTP */
}
\f
void
}
#endif /* USG */
+ SIGNAL_THREAD_CHECK (signalnum);
cancel_echoing ();
if (!NILP (Vquit_flag)
return Flist (sizeof (val) / sizeof (val[0]), val);
}
+DEFUN ("posn-at-x-y", Fposn_at_x_y, Sposn_at_x_y, 2, 4, 0,
+ doc: /* Return position information for pixel coordinates X and Y.
+By default, X and Y are relative to text area of the selected window.
+Optional third arg FRAME-OR-WINDOW non-nil specifies frame or window.
+If optional fourth arg WHOLE is non-nil, X is relative to the left
+edge of the window.
+
+The return value is similar to a mouse click position:
+ (WINDOW AREA-OR-POS (X . Y) TIMESTAMP OBJECT POS (COL . ROW)
+ IMAGE (DX . DY) (WIDTH . HEIGHT))
+The `posn-' functions access elements of such lists. */)
+ (x, y, frame_or_window, whole)
+ Lisp_Object x, y, frame_or_window, whole;
+{
+ CHECK_NATNUM (x);
+ CHECK_NATNUM (y);
+
+ if (NILP (frame_or_window))
+ frame_or_window = selected_window;
+
+ if (WINDOWP (frame_or_window))
+ {
+ struct window *w;
+
+ CHECK_LIVE_WINDOW (frame_or_window);
+
+ w = XWINDOW (frame_or_window);
+ XSETINT (x, (WINDOW_TO_FRAME_PIXEL_X (w, XINT (x))
+ + (NILP (whole)
+ ? window_box_left_offset (w, TEXT_AREA)
+ : - (WINDOW_LEFT_SCROLL_BAR_COLS (w)
+ * WINDOW_FRAME_COLUMN_WIDTH (w)))));
+ XSETINT (y, WINDOW_TO_FRAME_PIXEL_Y (w, XINT (y)));
+ frame_or_window = w->frame;
+ }
+
+ CHECK_LIVE_FRAME (frame_or_window);
+
+ return make_lispy_position (XFRAME (frame_or_window), &x, &y, 0);
+}
+
+DEFUN ("posn-at-point", Fposn_at_point, Sposn_at_point, 0, 2, 0,
+ doc: /* Return position information for buffer POS in WINDOW.
+POS defaults to point in WINDOW; WINDOW defaults to the selected window.
+
+Return nil if position is not visible in window. Otherwise,
+the return value is similar to that returned by `event-start' for
+a mouse click at the upper left corner of the glyph corresponding
+to the given buffer position:
+ (WINDOW AREA-OR-POS (X . Y) TIMESTAMP OBJECT POS (COL . ROW)
+ IMAGE (DX . DY) (WIDTH . HEIGHT))
+The `posn-' functions access elements of such lists. */)
+ (pos, window)
+ Lisp_Object pos, window;
+{
+ Lisp_Object tem;
+
+ tem = Fpos_visible_in_window_p (pos, window, Qt);
+ if (!NILP (tem))
+ tem = Fposn_at_x_y (XCAR (tem), XCAR (XCDR (tem)), window, Qnil);
+ return tem;
+}
+
\f
/*
* Set up a new kboard object with reasonable initial values.
recent_keys_index = 0;
kbd_fetch_ptr = kbd_buffer;
kbd_store_ptr = kbd_buffer;
- kbd_buffer_gcpro = Fmake_vector (make_number (2 * KBD_BUFFER_SIZE), Qnil);
#ifdef HAVE_MOUSE
do_mouse_tracking = Qnil;
#endif
Qtimer_event_handler = intern ("timer-event-handler");
staticpro (&Qtimer_event_handler);
- Qdisabled_command_hook = intern ("disabled-command-hook");
- staticpro (&Qdisabled_command_hook);
+ Qdisabled_command_function = intern ("disabled-command-function");
+ staticpro (&Qdisabled_command_function);
Qself_insert_command = intern ("self-insert-command");
staticpro (&Qself_insert_command);
Qpost_command_hook = intern ("post-command-hook");
staticpro (&Qpost_command_hook);
- Qpost_command_idle_hook = intern ("post-command-idle-hook");
- staticpro (&Qpost_command_idle_hook);
-
Qdeferred_action_function = intern ("deferred-action-function");
staticpro (&Qdeferred_action_function);
staticpro (&Qfunction_key);
Qmouse_click = intern ("mouse-click");
staticpro (&Qmouse_click);
-#ifdef WINDOWSNT
+#if defined (WINDOWSNT) || defined (MAC_OS)
Qlanguage_change = intern ("language-change");
staticpro (&Qlanguage_change);
#endif
staticpro (&Qdrag_n_drop);
Qsave_session = intern ("save-session");
- staticpro(&Qsave_session);
+ staticpro (&Qsave_session);
Qusr1_signal = intern ("usr1-signal");
staticpro (&Qusr1_signal);
Qmenu_bar = intern ("menu-bar");
staticpro (&Qmenu_bar);
+#ifdef HAVE_MOUSE
+ Qmouse_fixup_help_message = intern ("mouse-fixup-help-message");
+ staticpro (&Qmouse_fixup_help_message);
+#endif
+
Qabove_handle = intern ("above-handle");
staticpro (&Qabove_handle);
Qhandle = intern ("handle");
Fset (Qextended_command_history, Qnil);
staticpro (&Qextended_command_history);
- kbd_buffer_gcpro = Fmake_vector (make_number (2 * KBD_BUFFER_SIZE), Qnil);
- staticpro (&kbd_buffer_gcpro);
-
accent_key_syms = Qnil;
staticpro (&accent_key_syms);
menu_bar_one_keymap_changed_items = Qnil;
staticpro (&menu_bar_one_keymap_changed_items);
+ menu_bar_items_vector = Qnil;
+ staticpro (&menu_bar_items_vector);
+
defsubr (&Sevent_convert_list);
defsubr (&Sread_key_sequence);
defsubr (&Sread_key_sequence_vector);
defsubr (&Sset_input_mode);
defsubr (&Scurrent_input_mode);
defsubr (&Sexecute_extended_command);
+ defsubr (&Sposn_at_point);
+ defsubr (&Sposn_at_x_y);
DEFVAR_LISP ("last-command-char", &last_command_char,
doc: /* Last input event that was part of a command. */);
DEFVAR_LISP ("keyboard-translate-table", &Vkeyboard_translate_table,
doc: /* Translate table for keyboard input, or nil.
-Each character is looked up in this string and the contents used instead.
-The value may be a string, a vector, or a char-table.
-If it is a string or vector of length N,
-character codes N and up are untranslated.
-In a vector or a char-table, an element which is nil means "no translation".
+If non-nil, the value should be a char-table. Each character read
+from the keyboard is looked up in this char-table. If the value found
+there is non-nil, then it is used instead of the actual input character.
+
+The value can also be a string or vector, but this is considered obsolete.
+If it is a string or vector of length N, character codes N and up are left
+untranslated. In a vector, an element which is nil means "no translation".
This is applied to the characters supplied to input methods, not their
output. See also `translation-table-for-input'. */);
might happen repeatedly and make Emacs nonfunctional. */);
Vpost_command_hook = Qnil;
- DEFVAR_LISP ("post-command-idle-hook", &Vpost_command_idle_hook,
- doc: /* Normal hook run after each command is executed, if idle.
-Errors running the hook are caught and ignored. */);
- Vpost_command_idle_hook = Qnil;
-
- DEFVAR_INT ("post-command-idle-delay", &post_command_idle_delay,
- doc: /* Delay time before running `post-command-idle-hook'.
-This is measured in microseconds. */);
- post_command_idle_delay = 100000;
-
#if 0
DEFVAR_LISP ("echo-area-clear-hook", ...,
doc: /* Normal hook run when clearing the echo area. */);
#endif
Qecho_area_clear_hook = intern ("echo-area-clear-hook");
+ staticpro (&Qecho_area_clear_hook);
SET_SYMBOL_VALUE (Qecho_area_clear_hook, Qnil);
DEFVAR_LISP ("lucid-menu-bar-dirty-flag", &Vlucid_menu_bar_dirty_flag,
doc: /* Per-terminal keymap that overrides all other local keymaps.
If this variable is non-nil, it is used as a keymap instead of the
buffer's local map, and the minor mode keymaps and text property keymaps.
+It also replaces `overriding-local-map'.
+
This variable is intended to let commands such as `universal-argument'
set up a different keymap for reading the next command. */);
DEFVAR_LISP ("overriding-local-map", &Voverriding_local_map,
doc: /* Keymap that overrides all other local keymaps.
-If this variable is non-nil, it is used as a keymap instead of the
-buffer's local map, and the minor mode keymaps and text property keymaps. */);
+If this variable is non-nil, it is used as a keymap--replacing the
+buffer's local map, the minor mode keymaps, and char property keymaps. */);
Voverriding_local_map = Qnil;
DEFVAR_LISP ("overriding-local-map-menu-flag", &Voverriding_local_map_menu_flag,
After a command is executed, if point is moved into a region that has
special properties (e.g. composition, display), we adjust point to
-the boundary of the region. But, several special commands sets this
-variable to non-nil, then we suppress the point adjustment.
+the boundary of the region. But, when a command sets this variable to
+non-nil, we suppress the point adjustment.
This variable is set to nil before reading a command, and is checked
just after executing the command. */);
doc: /* *How long to display an echo-area message when the minibuffer is active.
If the value is not a number, such messages don't time out. */);
Vminibuffer_message_timeout = make_number (2);
+
+ DEFVAR_LISP ("throw-on-input", &Vthrow_on_input,
+ doc: /* If non-nil, any keyboard input throws to this symbol.
+The value of that variable is passed to `quit-flag' and later causes a
+peculiar kind of quitting. */);
+ Vthrow_on_input = Qnil;
}
void
initial_define_lispy_key (Vspecial_event_map, "delete-frame",
"handle-delete-frame");
+ /* Here we used to use `ignore-event' which would simple set prefix-arg to
+ current-prefix-arg, as is done in `handle-switch-frame'.
+ But `handle-switch-frame is not run from the special-map.
+ Commands from that map are run in a special way that automatically
+ preserves the prefix-arg. Restoring the prefix arg here is not just
+ redundant but harmful:
+ - C-u C-x v =
+ - current-prefix-arg is set to non-nil, prefix-arg is set to nil.
+ - after the first prompt, the exit-minibuffer-hook is run which may
+ iconify a frame and thus push a `iconify-frame' event.
+ - after running exit-minibuffer-hook, current-prefix-arg is
+ restored to the non-nil value it had before the prompt.
+ - we enter the second prompt.
+ current-prefix-arg is non-nil, prefix-arg is nil.
+ - before running the first real event, we run the special iconify-frame
+ event, but we pass the `special' arg to execute-command so
+ current-prefix-arg and prefix-arg are left untouched.
+ - here we foolishly copy the non-nil current-prefix-arg to prefix-arg.
+ - the next key event will have a spuriously non-nil current-prefix-arg. */
initial_define_lispy_key (Vspecial_event_map, "iconify-frame",
- "ignore-event");
+ "ignore");
initial_define_lispy_key (Vspecial_event_map, "make-frame-visible",
- "ignore-event");
+ "ignore");
/* Handling it at such a low-level causes read_key_sequence to get
* confused because it doesn't realize that the current_buffer was
* changed by read_char.
- *
+ *
* initial_define_lispy_key (Vspecial_event_map, "select-window",
* "handle-select-window"); */
initial_define_lispy_key (Vspecial_event_map, "save-session",
{
if (event == kbd_buffer + KBD_BUFFER_SIZE)
event = kbd_buffer;
- mark_object (event->x);
- mark_object (event->y);
+ if (event->kind != SELECTION_REQUEST_EVENT
+ && event->kind != SELECTION_CLEAR_EVENT)
+ {
+ mark_object (event->x);
+ mark_object (event->y);
+ }
mark_object (event->frame_or_window);
mark_object (event->arg);
}