X-Git-Url: http://git.hcoop.net/bpt/emacs.git/blobdiff_plain/45de137aed5987e2fc90ccc0fe498360e40e6119..d95ebe75a0471e700cfddecb68329f9970c128c4:/src/keyboard.c diff --git a/src/keyboard.c b/src/keyboard.c index 6148a2510b..1aca012776 100644 --- a/src/keyboard.c +++ b/src/keyboard.c @@ -1,6 +1,7 @@ /* 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, 2006 Free Software Foundation, Inc. This file is part of GNU Emacs. @@ -16,8 +17,8 @@ GNU General Public License for more details. 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 #include @@ -45,6 +46,9 @@ Boston, MA 02111-1307, USA. */ #include #include +#ifdef HAVE_GTK_AND_PTHREAD +#include +#endif #ifdef MSDOS #include "msdos.h" #include @@ -62,6 +66,10 @@ Boston, MA 02111-1307, USA. */ #include #endif +#ifdef HAVE_FCNTL_H +#include +#endif + /* This is to get the definitions of the XK_ symbols. */ #ifdef HAVE_X_WINDOWS #include "xterm.h" @@ -117,6 +125,8 @@ struct backtrace 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 @@ -129,8 +139,8 @@ KBOARD the_only_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 */ @@ -371,12 +381,15 @@ Lisp_Object real_this_command; command is stored in this-original-command. It is nil otherwise. */ Lisp_Object Vthis_original_command; -/* The value of point when the last command was executed. */ +/* The value of point when the last command was started. */ int last_point_position; /* The buffer that was current when the last command was started. */ Lisp_Object last_point_position_buffer; +/* The window that was selected when the last command was started. */ +Lisp_Object last_point_position_window; + /* The frame in which the last input event occurred, or Qmacro if the last event came from a macro. We use this to determine when to generate switch-frame events. This may be cleared by functions @@ -441,11 +454,6 @@ Lisp_Object Qecho_area_clear_hook; 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. */ @@ -469,46 +477,12 @@ int input_pending; int meta_key; -/* Non-zero means force key bindings update in parse_menu_item. */ - -int update_menu_bindings; - extern char *pending_malloc_warning; /* Circular buffer for pre-read keyboard input. */ 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 @@ -544,14 +518,21 @@ Lisp_Object Qmake_frame_visible; 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; Lisp_Object Qsave_session; +#ifdef MAC_OS +Lisp_Object Qmac_apple_event; +#endif /* Lisp_Object Qmouse_movement; - also an event header */ @@ -587,7 +568,7 @@ Lisp_Object Qvertical_scroll_bar; Lisp_Object Qmenu_bar; extern Lisp_Object Qleft_margin, Qright_margin; extern Lisp_Object Qleft_fringe, Qright_fringe; -extern Lisp_Object Qimage; +extern Lisp_Object QCmap; Lisp_Object recursive_edit_unwind (), command_loop (); Lisp_Object Fthis_command_keys (); @@ -635,7 +616,7 @@ int flow_control; /* 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 @@ -668,17 +649,25 @@ static EMACS_TIME timer_idleness_start_time; static EMACS_TIME timer_last_idleness_start_time; +/* If non-nil, events produced by disabled menu items and tool-bar + buttons are not ignored. Help functions bind this to allow help on + those items and buttons. */ +Lisp_Object Venable_disabled_menus_and_buttons; + /* 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 (); @@ -704,11 +693,16 @@ static Lisp_Object apply_modifiers P_ ((int, Lisp_Object)); 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; + /* 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. */ @@ -801,6 +795,8 @@ echo_char (c) else echo_string = concat2 (echo_string, build_string (" ")); } + else if (STRINGP (echo_string)) + echo_string = concat2 (echo_string, build_string (" ")); current_kboard->echo_string = concat2 (echo_string, make_string (buffer, ptr - buffer)); @@ -828,6 +824,21 @@ echo_dash () == 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, @@ -1019,13 +1030,18 @@ DEFUN ("recursive-edit", Frecursive_edit, Srecursive_edit, 0, 0, "", 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; @@ -1095,6 +1111,19 @@ single_kboard_state () #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. */ @@ -1149,21 +1178,21 @@ cmd_error (data) 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 (); @@ -1181,7 +1210,8 @@ cmd_error (data) 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); @@ -1263,15 +1293,19 @@ command_loop () { 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) @@ -1324,6 +1358,12 @@ DEFUN ("top-level", Ftop_level, Stop_level, 0, 0, "", 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); } @@ -1365,6 +1405,7 @@ cancel_hourglass_unwind (arg) Lisp_Object arg; { cancel_hourglass (); + return Qnil; } #endif @@ -1377,7 +1418,7 @@ command_loop_1 () Lisp_Object keybuf[30]; int i; int no_direct; - int prev_modiff; + int prev_modiff = 0; struct buffer *prev_buffer = NULL; #ifdef MULTI_KBOARD int was_locked = single_kboard; @@ -1410,21 +1451,9 @@ command_loop_1 () 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; - /* Do this after running Vpost_command_hook, for consistency. */ current_kboard->Vlast_command = Vthis_command; current_kboard->Vreal_last_command = real_this_command; @@ -1488,7 +1517,7 @@ command_loop_1 () 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. */ @@ -1501,6 +1530,7 @@ command_loop_1 () 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], @@ -1546,11 +1576,11 @@ command_loop_1 () } 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. */ } @@ -1561,6 +1591,7 @@ command_loop_1 () prev_buffer = current_buffer; prev_modiff = MODIFF; last_point_position = PT; + last_point_position_window = selected_window; XSETBUFFER (last_point_position_buffer, prev_buffer); /* By default, we adjust point to a boundary of a region that @@ -1596,7 +1627,10 @@ command_loop_1 () 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; @@ -1646,7 +1680,7 @@ command_loop_1 () && 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; } @@ -1681,7 +1715,7 @@ command_loop_1 () && 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; } @@ -1694,7 +1728,7 @@ command_loop_1 () = 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) @@ -1716,7 +1750,7 @@ command_loop_1 () || !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); @@ -1744,7 +1778,7 @@ command_loop_1 () int scount = SPECPDL_INDEX (); if (display_hourglass_p - && NILP (Vexecuting_macro)) + && NILP (Vexecuting_kbd_macro)) { record_unwind_protect (cancel_hourglass_unwind, Qnil); start_hourglass (); @@ -1762,7 +1796,7 @@ command_loop_1 () 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 } @@ -1783,16 +1817,6 @@ command_loop_1 () 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, @@ -1818,6 +1842,14 @@ command_loop_1 () 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'. */ @@ -1900,10 +1932,13 @@ adjust_point_for_property (last_pt, modified) ? 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; @@ -1958,7 +1993,12 @@ adjust_point_for_property (last_pt, modified) : (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) @@ -2063,7 +2103,11 @@ poll_for_input (timer) 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 */ @@ -2206,12 +2250,16 @@ make_ctrl_char (c) 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). + + If HELP is nil, that means clear the previous help echo. - 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 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. @@ -2256,6 +2304,11 @@ show_help_echo (help, window, object, pos, ok_to_overwrite_keystroke_echo) 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)) @@ -2353,7 +2406,6 @@ read_char (commandflag, nmaps, maps, prev_event, used_mouse_menu) 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; @@ -2435,7 +2487,7 @@ read_char (commandflag, nmaps, maps, prev_event, used_mouse_menu) 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 @@ -2452,19 +2504,19 @@ read_char (commandflag, nmaps, maps, prev_event, used_mouse_menu) /* 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; } @@ -2573,6 +2625,9 @@ read_char (commandflag, nmaps, maps, prev_event, used_mouse_menu) 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; @@ -2860,9 +2915,6 @@ read_char (commandflag, nmaps, maps, prev_event, used_mouse_menu) 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; @@ -2902,7 +2954,7 @@ read_char (commandflag, nmaps, maps, prev_event, used_mouse_menu) 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) @@ -2943,13 +2995,13 @@ read_char (commandflag, nmaps, maps, prev_event, used_mouse_menu) { 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); @@ -3007,6 +3059,7 @@ read_char (commandflag, nmaps, maps, prev_event, used_mouse_menu) /* 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 @@ -3061,6 +3114,7 @@ read_char (commandflag, nmaps, maps, prev_event, used_mouse_menu) 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 (); @@ -3101,7 +3155,7 @@ read_char (commandflag, nmaps, maps, prev_event, used_mouse_menu) 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; } @@ -3402,10 +3456,11 @@ tracking_off (old_value) 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; @@ -3457,20 +3512,21 @@ some_mouse_moved () /* 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; @@ -3478,20 +3534,34 @@ readable_filtered_events (do_timers_now, filter_events) ? 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) @@ -3509,15 +3579,6 @@ readable_filtered_events (do_timers_now, filter_events) 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; @@ -3543,15 +3604,41 @@ event_to_kboard (event) } #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; @@ -3593,6 +3680,12 @@ kbd_buffer_store_event (event) } #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 @@ -3622,7 +3715,9 @@ kbd_buffer_store_event (event) 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) @@ -3634,40 +3729,44 @@ kbd_buffer_store_event (event) 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; } } @@ -3685,24 +3784,22 @@ kbd_buffer_store_event (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); } @@ -3782,9 +3879,6 @@ static INLINE void 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; } @@ -3843,10 +3937,7 @@ kbd_buffer_get_event (kbp, used_mouse_menu) 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. */ @@ -3890,7 +3981,8 @@ kbd_buffer_get_event (kbp, used_mouse_menu) /* 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; @@ -3901,7 +3993,7 @@ kbd_buffer_get_event (kbp, used_mouse_menu) 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. */ @@ -3909,22 +4001,6 @@ kbd_buffer_get_event (kbp, used_mouse_menu) #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) { @@ -3934,7 +4010,7 @@ kbd_buffer_get_event (kbp, used_mouse_menu) kbd_fetch_ptr = event + 1; } #endif -#if defined (HAVE_X11) || defined (HAVE_NTGUI) +#if defined (HAVE_X11) || defined (HAVE_NTGUI) || defined (MAC_OS) else if (event->kind == ICONIFY_EVENT) { /* Make an event (iconify-frame (FRAME)). */ @@ -3966,13 +4042,16 @@ kbd_buffer_get_event (kbp, used_mouse_menu) 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; } @@ -4151,7 +4230,8 @@ swallow_events (do_display) /* 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; @@ -4162,25 +4242,7 @@ swallow_events (do_display) 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. */ @@ -4192,7 +4254,7 @@ swallow_events (do_display) } 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); @@ -4201,7 +4263,7 @@ swallow_events (do_display) /* 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; @@ -4229,12 +4291,23 @@ timer_start_idle () /* 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; @@ -4982,16 +5055,22 @@ make_lispy_position (f, x, y, time) { /* 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. */ XSETINT (*x, wx); XSETINT (*y, wy); - if (part == ON_MODE_LINE || part == ON_HEADER_LINE) + if (part == ON_TEXT) + { + wx += WINDOW_LEFT_MARGIN_WIDTH (w); + } + else if (part == ON_MODE_LINE || part == ON_HEADER_LINE) { /* Mode line or header line. Look for a string under the mouse that may have a `local-map' property. */ @@ -5000,9 +5079,10 @@ make_lispy_position (f, x, y, time) 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 @@ -5013,64 +5093,107 @@ make_lispy_position (f, x, y, time) 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)); + string_info = Fcons (string, make_number (charpos)); + if (part == ON_LEFT_MARGIN) + wx = 0; + else + wx = window_box_right_offset (w, TEXT_AREA) - 1; + } + else if (part == ON_LEFT_FRINGE) + { + posn = Qleft_fringe; + rx = 0; + dx = wx; + wx = (WINDOW_HAS_FRINGES_OUTSIDE_MARGINS (w) + ? 0 + : window_box_width (w, LEFT_MARGIN_AREA)); + dx -= wx; } - else if (part == ON_LEFT_FRINGE || part == ON_RIGHT_FRINGE) + else if (part == ON_RIGHT_FRINGE) { - posn = (part == ON_LEFT_FRINGE) ? Qleft_fringe : Qright_fringe; + posn = Qright_fringe; rx = 0; dx = wx; - if (part == ON_RIGHT_FRINGE) - dx -= (window_box_width (w, LEFT_MARGIN_AREA) - + window_box_width (w, TEXT_AREA) - + (WINDOW_HAS_FRINGES_OUTSIDE_MARGINS (w) - ? window_box_width (w, RIGHT_MARGIN_AREA) - : 0)); - else if (!WINDOW_HAS_FRINGES_OUTSIDE_MARGINS (w)) - dx -= window_box_width (w, LEFT_MARGIN_AREA); + wx = (window_box_width (w, LEFT_MARGIN_AREA) + + window_box_width (w, TEXT_AREA) + + (WINDOW_HAS_FRINGES_OUTSIDE_MARGINS (w) + ? window_box_width (w, RIGHT_MARGIN_AREA) + : 0)); + dx -= wx; + } + else + { + /* Note: We have no special posn for part == ON_SCROLL_BAR. */ + wx = max (WINDOW_LEFT_MARGIN_WIDTH (w), wx); } if (textpos < 0) { - Lisp_Object string; + Lisp_Object string2, object2 = Qnil; struct display_pos p; int dx2, dy2; - wx = max (WINDOW_LEFT_MARGIN_WIDTH (w), wx); - buffer_posn_from_coords (w, &wx, &wy, &dx2, &dy2, &string, &p); + int width2, height2; + 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))); - else if (CONSP (string) && EQ (XCAR (string), Qimage)) - object = string; + 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) { @@ -5416,13 +5539,23 @@ make_lispy_event (event) if (CONSP (down) && INTEGERP (XCAR (down)) && INTEGERP (XCDR (down))) { - xdiff = XFASTINT (event->x) - XFASTINT (XCAR (down)); - ydiff = XFASTINT (event->y) - XFASTINT (XCDR (down)); + xdiff = XINT (event->x) - XINT (XCAR (down)); + ydiff = XINT (event->y) - XINT (XCDR (down)); } if (xdiff < double_click_fuzz && xdiff > - double_click_fuzz - && ydiff < double_click_fuzz - && ydiff > - double_click_fuzz) + && ydiff < double_click_fuzz && ydiff > - double_click_fuzz + /* Maybe the mouse has moved a lot, caused scrolling, and + eventually ended up at the same screen position (but + not buffer position) in which case it is a drag, not + a click. */ + /* FIXME: OTOH if the buffer position has changed + because of a timer or process filter rather than + because of mouse movement, it should be considered as + a click. But mouse-drag-region completely ignores + this case and it hasn't caused any real problem, so + it's probably OK to ignore it as well. */ + && EQ (Fcar (Fcdr (start_pos)), Fcar (Fcdr (position)))) /* Mouse hasn't moved (much). */ event->modifiers |= click_modifier; else @@ -5475,7 +5608,7 @@ make_lispy_event (event) { Lisp_Object position; Lisp_Object head; - + /* Build the position as appropriate for this mouse click. */ struct frame *f = XFRAME (event->frame_or_window); @@ -5683,14 +5816,8 @@ make_lispy_event (event) Lisp_Object head, position; Lisp_Object files; - /* The frame_or_window field should be a cons of the frame in - which the event occurred and a list of the filenames - dropped. */ - if (! CONSP (event->frame_or_window)) - abort (); - - f = XFRAME (XCAR (event->frame_or_window)); - files = XCDR (event->frame_or_window); + f = XFRAME (event->frame_or_window); + files = event->arg; /* Ignore mouse events that were made on frames that have been deleted. */ @@ -5745,6 +5872,20 @@ make_lispy_event (event) case SAVE_SESSION_EVENT: return Qsave_session; +#ifdef MAC_OS + case MAC_APPLE_EVENT: + { + Lisp_Object spec[2]; + + spec[0] = event->x; + spec[1] = event->y; + return Fcons (Qmac_apple_event, + Fcons (Fvector (2, spec), + Fcons (mac_make_lispy_event_code (event->code), + Qnil))); + } +#endif + /* The 'kind' field of the event is something we don't recognize. */ default: abort (); @@ -6218,12 +6359,8 @@ modify_event_symbol (symbol_num, modifiers, symbol_kind, name_alist_or_stem, { 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]) @@ -6447,18 +6584,20 @@ lucid_event_type_list_p (object) 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)) @@ -6466,23 +6605,7 @@ get_filtered_input_pending (addr, do_timers_now, filter_events) /* 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. */ @@ -6579,16 +6702,26 @@ static int 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 @@ -6689,34 +6822,57 @@ read_avail_input (expected) #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 */ +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. */ @@ -6726,10 +6882,6 @@ input_available_signal (signo) { /* 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 */ @@ -6740,23 +6892,18 @@ input_available_signal (signo) 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 (); @@ -6775,7 +6922,7 @@ void reinvoke_input_signal () { #ifdef SIGIO - kill (getpid (), SIGIO); + handle_async_input (); #endif } @@ -6817,8 +6964,6 @@ menu_bar_items (old) 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 @@ -6834,8 +6979,6 @@ menu_bar_items (old) 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 @@ -6939,7 +7082,6 @@ menu_bar_items (old) menu_bar_items_index = i; Vinhibit_quit = oquit; - UNGCPRO; return menu_bar_items_vector; } @@ -7134,7 +7276,9 @@ parse_menu_item (item, notreal, inmenubar) if (SYMBOLP (item)) { tem = Fget (item, Qmenu_enable); - if (!NILP (tem)) + if (!NILP (Venable_disabled_menus_and_buttons)) + AREF (item_properties, ITEM_PROPERTY_ENABLE) = Qt; + else if (!NILP (tem)) AREF (item_properties, ITEM_PROPERTY_ENABLE) = tem; } } @@ -7163,7 +7307,12 @@ parse_menu_item (item, notreal, inmenubar) item = XCDR (item); if (EQ (tem, QCenable)) - AREF (item_properties, ITEM_PROPERTY_ENABLE) = XCAR (item); + { + if (!NILP (Venable_disabled_menus_and_buttons)) + AREF (item_properties, ITEM_PROPERTY_ENABLE) = Qt; + else + AREF (item_properties, ITEM_PROPERTY_ENABLE) = XCAR (item); + } else if (EQ (tem, QCvisible) && !notreal) { /* If got a visible property and that evaluates to nil @@ -7307,9 +7456,7 @@ parse_menu_item (item, notreal, inmenubar) else def = AREF (item_properties, ITEM_PROPERTY_DEF); - if (!update_menu_bindings) - chkcache = 0; - else if (NILP (XCAR (cachelist))) /* Have no saved key. */ + if (NILP (XCAR (cachelist))) /* Have no saved key. */ { if (newcache /* Always check first time. */ /* Should we check everything when precomputing key @@ -7359,7 +7506,7 @@ parse_menu_item (item, notreal, inmenubar) newcache = chkcache; if (chkcache) { - tem = Fkey_description (tem); + tem = Fkey_description (tem, Qnil); if (CONSP (prefix)) { if (STRINGP (XCAR (prefix))) @@ -7434,7 +7581,7 @@ Lisp_Object QCimage; /* Function prototypes. */ static void init_tool_bar_items P_ ((Lisp_Object)); -static void process_tool_bar_item P_ ((Lisp_Object, Lisp_Object)); +static void process_tool_bar_item P_ ((Lisp_Object, Lisp_Object, Lisp_Object, void*)); static int parse_tool_bar_item P_ ((Lisp_Object, Lisp_Object)); static void append_tool_bar_item P_ ((void)); @@ -7512,17 +7659,7 @@ tool_bar_items (reuse, nitems) keymap = get_keymap (access_keymap (maps[i], Qtool_bar, 1, 0, 1), 0, 1); if (CONSP (keymap)) - { - Lisp_Object tail; - - /* KEYMAP is a list `(keymap (KEY . BINDING) ...)'. */ - for (tail = keymap; CONSP (tail); tail = XCDR (tail)) - { - Lisp_Object keydef = XCAR (tail); - if (CONSP (keydef)) - process_tool_bar_item (XCAR (keydef), XCDR (keydef)); - } - } + map_keymap (keymap, process_tool_bar_item, Qnil, NULL, 1); } Vinhibit_quit = oquit; @@ -7534,8 +7671,9 @@ tool_bar_items (reuse, nitems) /* Process the definition of KEY which is DEF. */ static void -process_tool_bar_item (key, def) - Lisp_Object key, def; +process_tool_bar_item (key, def, data, args) + Lisp_Object key, def, data; + void *args; { int i; extern Lisp_Object Qundefined; @@ -7685,8 +7823,13 @@ parse_tool_bar_item (key, item) value = XCAR (XCDR (item)); if (EQ (key, QCenable)) - /* `:enable FORM'. */ - PROP (TOOL_BAR_ITEM_ENABLED_P) = value; + { + /* `:enable FORM'. */ + if (!NILP (Venable_disabled_menus_and_buttons)) + PROP (TOOL_BAR_ITEM_ENABLED_P) = Qt; + else + PROP (TOOL_BAR_ITEM_ENABLED_P) = value; + } else if (EQ (key, QCvisible)) { /* `:visible FORM'. If got a visible property and that @@ -8233,7 +8376,7 @@ access_keymap_keyremap (map, key, prompt, do_funcall) int do_funcall; { Lisp_Object next; - + next = access_keymap (map, key, 1, 0, 1); /* Handle symbol with autoload definition. */ @@ -8248,7 +8391,7 @@ access_keymap_keyremap (map, key, prompt, do_funcall) && (!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. */ @@ -8749,14 +8892,7 @@ read_key_sequence (keybuf, bufsize, prompt, dont_downcase_last, 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 @@ -8838,7 +8974,7 @@ read_key_sequence (keybuf, bufsize, prompt, dont_downcase_last, 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) @@ -8896,7 +9032,7 @@ read_key_sequence (keybuf, bufsize, prompt, dont_downcase_last, 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) @@ -9006,7 +9142,7 @@ read_key_sequence (keybuf, bufsize, prompt, dont_downcase_last, { 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)) @@ -9018,8 +9154,8 @@ read_key_sequence (keybuf, bufsize, prompt, dont_downcase_last, /* 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; @@ -9262,7 +9398,7 @@ read_key_sequence (keybuf, bufsize, prompt, dont_downcase_last, /* Adjust the function-key-map counters. */ fkey.end += diff; fkey.start += diff; - + goto replay_sequence; } } @@ -9343,6 +9479,7 @@ read_key_sequence (keybuf, bufsize, prompt, dont_downcase_last, /* Don't downcase the last character if the caller says don't. Don't downcase it if the result is undefined, either. */ if ((dont_downcase_last || first_binding >= nmaps) + && t > 0 && t - 1 == original_uppercase_position) keybuf[t - 1] = original_uppercase; @@ -9564,15 +9701,15 @@ a special event, so ignore the prefix argument and don't clear it. */) 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); } } while (1) { - final = Findirect_function (cmd); + final = Findirect_function (cmd, Qnil); if (CONSP (final) && (tem = Fcar (final), EQ (tem, Qautoload))) { @@ -9618,6 +9755,7 @@ a special event, so ignore the prefix argument and don't clear it. */) backtrace.args = &cmd; backtrace.nargs = 1; backtrace.evalargs = 0; + backtrace.debug_on_exit = 0; tem = Fcall_interactively (cmd, record_flag, keys); @@ -9641,6 +9779,15 @@ DEFUN ("execute-extended-command", Fexecute_extended_command, Sexecute_extended_ 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); @@ -9654,23 +9801,9 @@ DEFUN ("execute-extended-command", Fexecute_extended_command, Sexecute_extended_ 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 @@ -9686,6 +9819,10 @@ DEFUN ("execute-extended-command", Fexecute_extended_command, Sexecute_extended_ 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"); @@ -9721,7 +9858,7 @@ DEFUN ("execute-extended-command", Fexecute_extended_command, Sexecute_extended_ /* 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); @@ -9758,7 +9895,7 @@ DEFUN ("execute-extended-command", Fexecute_extended_command, Sexecute_extended_ 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)) @@ -9795,6 +9932,18 @@ detect_input_pending () 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 @@ -9804,7 +9953,7 @@ detect_input_pending_run_timers (do_display) 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) { @@ -9832,7 +9981,7 @@ clear_input_pending () } /* 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. */ @@ -9853,7 +10002,9 @@ if there is a doubt, the value is t. */) 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; } @@ -10031,7 +10182,6 @@ Also end any kbd macro being defined. */) discard_tty_input (); kbd_fetch_ptr = kbd_store_ptr; - Ffillarray (kbd_buffer_gcpro, Qnil); input_pending = 0; return Qnil; @@ -10101,9 +10251,7 @@ void 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)) @@ -10119,25 +10267,23 @@ stuff_buffered_input (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 */ } void @@ -10195,6 +10341,7 @@ interrupt_signal (signalnum) /* If we don't have an argument, */ } #endif /* USG */ + SIGNAL_THREAD_CHECK (signalnum); cancel_echoing (); if (!NILP (Vquit_flag) @@ -10446,6 +10593,81 @@ The elements of this list correspond to the arguments of 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, (XINT (x) + + WINDOW_LEFT_EDGE_X (w) + + (NILP (whole) + ? window_box_left_offset (w, TEXT_AREA) + : 0))); + 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; + + if (NILP (window)) + window = selected_window; + + tem = Fpos_visible_in_window_p (pos, window, Qt); + if (!NILP (tem)) + { + Lisp_Object x = XCAR (tem); + Lisp_Object y = XCAR (XCDR (tem)); + + /* Point invisible due to hscrolling? */ + if (XINT (x) < 0) + return Qnil; + tem = Fposn_at_x_y (x, y, window, Qnil); + } + + return tem; +} + /* * Set up a new kboard object with reasonable initial values. @@ -10532,7 +10754,6 @@ init_keyboard () 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 @@ -10588,11 +10809,6 @@ init_keyboard () poll_suppress_count = 1; start_polling (); #endif - -#ifdef MAC_OSX - /* At least provide an escape route since C-g doesn't work. */ - signal (SIGINT, interrupt_signal); -#endif } /* This type's only use is in syms_of_keyboard, to initialize the @@ -10645,8 +10861,8 @@ syms_of_keyboard () 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); @@ -10669,9 +10885,6 @@ syms_of_keyboard () 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); @@ -10682,7 +10895,7 @@ syms_of_keyboard () 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 @@ -10690,7 +10903,12 @@ syms_of_keyboard () staticpro (&Qdrag_n_drop); Qsave_session = intern ("save-session"); - staticpro(&Qsave_session); + staticpro (&Qsave_session); + +#ifdef MAC_OS + Qmac_apple_event = intern ("mac-apple-event"); + staticpro (&Qmac_apple_event); +#endif Qusr1_signal = intern ("usr1-signal"); staticpro (&Qusr1_signal); @@ -10729,6 +10947,11 @@ syms_of_keyboard () 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"); @@ -10777,6 +11000,7 @@ syms_of_keyboard () Fset (Qinput_method_use_echo_area, Qnil); last_point_position_buffer = Qnil; + last_point_position_window = Qnil; { struct event_head *p; @@ -10823,9 +11047,6 @@ syms_of_keyboard () 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); @@ -10847,6 +11068,9 @@ syms_of_keyboard () 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); @@ -10873,6 +11097,8 @@ syms_of_keyboard () 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. */); @@ -11043,11 +11269,13 @@ Useful to set before you dump a modified Emacs. */); 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'. */); @@ -11111,21 +11339,12 @@ the hook value is set to nil, since otherwise the error 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, @@ -11142,13 +11361,15 @@ The elements of the list are event types that may have menu bar bindings. */); 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, @@ -11233,8 +11454,8 @@ It's called with one argument, the help string to display. */); 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. */); @@ -11249,16 +11470,24 @@ suppressed only after special commands that set `disable-point-adjustment' (which see) to non-nil. */); Vglobal_disable_point_adjustment = Qnil; - DEFVAR_BOOL ("update-menu-bindings", &update_menu_bindings, - doc: /* Non-nil means updating menu bindings is allowed. -A value of nil means menu bindings should not be updated. -Used during Emacs' startup. */); - update_menu_bindings = 1; - DEFVAR_LISP ("minibuffer-message-timeout", &Vminibuffer_message_timeout, 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; + + DEFVAR_LISP ("enable-disabled-menus-and-buttons", + &Venable_disabled_menus_and_buttons, + doc: /* If non-nil, don't ignore events produced by disabled menu items and tool-bar. + +Help functions bind this to allow help on disabled menu items +and tool-bar buttons. */); + Venable_disabled_menus_and_buttons = Qnil; } void @@ -11272,14 +11501,33 @@ keys_of_keyboard () 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", @@ -11317,8 +11565,12 @@ mark_kboards () { 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); }