X-Git-Url: http://git.hcoop.net/bpt/emacs.git/blobdiff_plain/85e7f4776aa861a7e1fe994a787987ea923a6936..d95ebe75a0471e700cfddecb68329f9970c128c4:/src/keyboard.c diff --git a/src/keyboard.c b/src/keyboard.c index f5ca087227..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,04 - 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 @@ -65,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" @@ -376,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 @@ -446,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. */ @@ -474,10 +477,6 @@ 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. */ @@ -519,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 */ @@ -643,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 (); @@ -781,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)); @@ -811,16 +827,16 @@ echo_dash () /* 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; + 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) - 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); + 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; + if (XINT (last_char) == '-' && XINT (prev_char) != ' ') + return; } /* Put a dash at the end of the buffer temporarily, @@ -1014,7 +1030,7 @@ 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. */) () { @@ -1162,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 (); @@ -1277,7 +1293,7 @@ command_loop () { Lisp_Object val; val = internal_catch (Qexit, command_loop_2, Qnil); - executing_macro = Qnil; + executing_kbd_macro = Qnil; return val; } else @@ -1289,7 +1305,7 @@ command_loop () 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) @@ -1402,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; @@ -1435,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; @@ -1513,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. */ @@ -1526,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], @@ -1571,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. */ } @@ -1586,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 @@ -1674,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; } @@ -1709,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; } @@ -1722,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) @@ -1744,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); @@ -1772,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 (); @@ -1790,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 } @@ -1811,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, @@ -1936,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; @@ -2104,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 */ @@ -2247,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). - 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. @@ -2297,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)) @@ -2475,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 @@ -2492,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; } @@ -2613,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; @@ -3441,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; @@ -3496,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; @@ -3517,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) @@ -3548,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; @@ -3988,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)). */ @@ -4020,11 +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->frame_or_window, Qnil); +#endif obj = Fcons (Qlanguage_change, Fcons (obj, Qnil)); kbd_fetch_ptr = event + 1; } @@ -4227,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); @@ -5039,7 +5066,11 @@ make_lispy_position (f, x, y, time) 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. */ @@ -5075,20 +5106,37 @@ make_lispy_position (f, x, y, time) &object, &dx, &dy, &width, &height); if (STRINGP (string)) 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 || part == ON_RIGHT_FRINGE) + else if (part == ON_LEFT_FRINGE) { - posn = (part == ON_LEFT_FRINGE) ? Qleft_fringe : Qright_fringe; + posn = Qleft_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_HAS_FRINGES_OUTSIDE_MARGINS (w) + ? 0 + : window_box_width (w, LEFT_MARGIN_AREA)); + dx -= wx; + } + else if (part == ON_RIGHT_FRINGE) + { + posn = Qright_fringe; + rx = 0; + dx = wx; + 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) @@ -5097,7 +5145,6 @@ make_lispy_position (f, x, y, time) struct display_pos p; int dx2, dy2; int width2, height2; - wx = max (WINDOW_LEFT_MARGIN_WIDTH (w), wx); string2 = buffer_posn_from_coords (w, &wx, &wy, &p, &object2, &dx2, &dy2, &width2, &height2); @@ -5492,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 @@ -5759,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. */ @@ -5821,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 (); @@ -6519,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)) @@ -6538,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. */ @@ -6841,14 +6892,16 @@ input_available_signal (signo) sigisheld (SIGIO); #endif - if (input_available_clear_time) - EMACS_SET_SECS_USECS (*input_available_clear_time, 0, 0); - #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); + +#ifndef SYNC_INPUT handle_async_input (); #endif @@ -6911,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 @@ -6928,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 @@ -7033,7 +7082,6 @@ menu_bar_items (old) menu_bar_items_index = i; Vinhibit_quit = oquit; - UNGCPRO; return menu_bar_items_vector; } @@ -7228,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; } } @@ -7257,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 @@ -7401,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 @@ -7528,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)); @@ -7606,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; @@ -7628,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; @@ -7779,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 @@ -9430,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; @@ -9659,7 +9709,7 @@ a special event, so ignore the prefix argument and don't clear it. */) while (1) { - final = Findirect_function (cmd); + final = Findirect_function (cmd, Qnil); if (CONSP (final) && (tem = Fcar (final), EQ (tem, Qautoload))) { @@ -9729,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); @@ -9760,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"); @@ -9795,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); @@ -9869,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 @@ -9878,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) { @@ -9927,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; } @@ -10516,18 +10593,23 @@ 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, 3, 0, +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. +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) - Lisp_Object x, y, frame_or_window; + (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; @@ -10538,8 +10620,11 @@ The `posn-' functions access elements of such lists. */) CHECK_LIVE_WINDOW (frame_or_window); w = XWINDOW (frame_or_window); - XSETINT (x, (WINDOW_TO_FRAME_PIXEL_X (w, XINT (x)) - + window_box_left_offset (w, TEXT_AREA))); + 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; } @@ -10565,9 +10650,21 @@ The `posn-' functions access elements of such lists. */) { Lisp_Object tem; + if (NILP (window)) + window = selected_window; + tem = Fpos_visible_in_window_p (pos, window, Qt); if (!NILP (tem)) - tem = Fposn_at_x_y (XCAR (tem), XCAR (XCDR (tem)), window); + { + 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; } @@ -10712,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 @@ -10793,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); @@ -10806,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 @@ -10814,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); @@ -10853,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"); @@ -10901,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; @@ -10968,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); @@ -11236,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, @@ -11267,14 +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 overrides `overriding-local-map'. +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, @@ -11375,12 +11470,6 @@ 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. */); @@ -11391,6 +11480,14 @@ If the value is not a number, such messages don't time out. */); 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 @@ -11404,10 +11501,29 @@ 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.