X-Git-Url: http://git.hcoop.net/bpt/emacs.git/blobdiff_plain/ab1959fcbaf8c87bc39b2e98a7511348709ae1fe..b65c1b44897ddae92eca834f60f11008aee94247:/src/keyboard.c diff --git a/src/keyboard.c b/src/keyboard.c index 1f2227f419..d6a743489a 100644 --- a/src/keyboard.c +++ b/src/keyboard.c @@ -1,5 +1,5 @@ /* Keyboard and mouse input; editor command loop. - Copyright (C) 1985,86,87,88,89,93,94,95,96,97,99, 2000, 01, 02 + Copyright (C) 1985,86,87,88,89,93,94,95,96,97,99,2000,01,02,03,04 Free Software Foundation, Inc. This file is part of GNU Emacs. @@ -145,6 +145,10 @@ Lisp_Object recent_keys; /* A vector, holding the last 100 keystrokes */ Lisp_Object this_command_keys; int this_command_key_count; +/* 1 after calling Freset_this_command_lengths. + Usually it is 0. */ +int this_command_key_count_reset; + /* This vector is used as a buffer to record the events that were actually read by read_key_sequence. */ Lisp_Object raw_keybuf; @@ -169,13 +173,6 @@ int this_single_command_key_start; before this command was read. */ static int before_command_key_count; static int before_command_echo_length; -/* Values of before_command_key_count and before_command_echo_length - saved by reset-this-command-lengths. */ -static int before_command_key_count_1; -static int before_command_echo_length_1; -/* Flag set by reset-this-command-lengths, - saying to reset the lengths when add_command_key is called. */ -static int before_command_restore_flag; extern int minbuf_level; @@ -412,7 +409,7 @@ Lisp_Object Vecho_keystrokes; /* Form to evaluate (if non-nil) when Emacs is started. */ Lisp_Object Vtop_level; -/* User-supplied string to translate input characters through. */ +/* User-supplied table to translate input characters. */ Lisp_Object Vkeyboard_translate_table; /* Keymap mapping ASCII function key sequences onto their preferred forms. */ @@ -550,9 +547,6 @@ Lisp_Object Qhelp_echo; /* Symbols to denote kinds of events. */ Lisp_Object Qfunction_key; Lisp_Object Qmouse_click; -#if defined(WINDOWSNT) || defined(MAC_OSX) -Lisp_Object Qmouse_wheel; -#endif #ifdef WINDOWSNT Lisp_Object Qlanguage_change; #endif @@ -592,17 +586,20 @@ Lisp_Object Qvertical_line; 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 QCmap; Lisp_Object recursive_edit_unwind (), command_loop (); Lisp_Object Fthis_command_keys (); Lisp_Object Qextended_command_history; EMACS_TIME timer_check (); -extern Lisp_Object Vhistory_length; +extern Lisp_Object Vhistory_length, Vtranslation_table_for_input; extern char *x_get_keysym_name (); static void record_menu_key (); +static int echo_length (); Lisp_Object Qpolling_period; @@ -706,6 +703,7 @@ static void restore_getcjmp P_ ((jmp_buf)); 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)); /* Nonzero means don't try to suspend even if the operating system seems to support it. */ @@ -740,7 +738,7 @@ echo_char (c) Lisp_Object echo_string; echo_string = current_kboard->echo_string; - + /* If someone has passed us a composite event, use its head symbol. */ c = EVENT_HEAD (c); @@ -752,7 +750,7 @@ echo_char (c) { Lisp_Object name = SYMBOL_NAME (c); int nbytes = SBYTES (name); - + if (size - (ptr - buffer) < nbytes) { int offset = ptr - buffer; @@ -770,7 +768,7 @@ echo_char (c) { const char *text = " (Type ? for further options)"; int len = strlen (text); - + if (size - (ptr - buffer) < len) { int offset = ptr - buffer; @@ -786,14 +784,19 @@ echo_char (c) /* Replace a dash from echo_dash with a space, otherwise add a space at the end as a separator between keys. */ if (STRINGP (echo_string) - && SCHARS (echo_string) > 0) + && SCHARS (echo_string) > 1) { - Lisp_Object last_char, idx; + Lisp_Object last_char, prev_char, idx; + + idx = make_number (SCHARS (echo_string) - 2); + prev_char = Faref (echo_string, idx); idx = make_number (SCHARS (echo_string) - 1); last_char = Faref (echo_string, idx); - if (XINT (last_char) == '-') + /* We test PREV_CHAR to make sure this isn't the echoing + of a minus-sign. */ + if (XINT (last_char) == '-' && XINT (prev_char) != ' ') Faset (echo_string, idx, make_number (' ')); else echo_string = concat2 (echo_string, build_string (" ")); @@ -819,12 +822,12 @@ echo_dash () if (!current_kboard->immediate_echo && SCHARS (current_kboard->echo_string) == 0) return; - + /* Do nothing if we just printed a prompt. */ if (current_kboard->echo_after_prompt == SCHARS (current_kboard->echo_string)) 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, @@ -846,11 +849,26 @@ echo_now () for (i = 0; i < this_command_key_count; i++) { Lisp_Object c; + + /* Set before_command_echo_length to the value that would + have been saved before the start of this subcommand in + command_loop_1, if we had already been echoing then. */ + if (i == this_single_command_key_start) + before_command_echo_length = echo_length (); + c = XVECTOR (this_command_keys)->contents[i]; if (! (EVENT_HAS_PARAMETERS (c) && EQ (EVENT_HEAD_KIND (EVENT_HEAD (c)), Qmouse_movement))) echo_char (c); } + + /* Set before_command_echo_length to the value that would + have been saved before the start of this subcommand in + command_loop_1, if we had already been echoing then. */ + if (this_command_key_count == this_single_command_key_start) + before_command_echo_length = echo_length (); + + /* Put a dash at the end to invite the user to type more. */ echo_dash (); } @@ -912,6 +930,8 @@ static void add_command_key (key) Lisp_Object key; { +#if 0 /* Not needed after we made Freset_this_command_lengths + do the job immediately. */ /* If reset-this-command-length was called recently, obey it now. See the doc string of that function for an explanation of why. */ if (before_command_restore_flag) @@ -922,6 +942,7 @@ add_command_key (key) echo_truncate (before_command_echo_length_1); before_command_restore_flag = 0; } +#endif if (this_command_key_count >= ASIZE (this_command_keys)) this_command_keys = larger_vector (this_command_keys, @@ -1031,12 +1052,12 @@ recursive_edit_unwind (info) { if (BUFFERP (XCAR (info))) Fset_buffer (XCAR (info)); - + if (NILP (XCDR (info))) any_kboard_state (); else single_kboard_state (); - + command_loop_level--; update_mode_lines = 1; return Qnil; @@ -1213,7 +1234,7 @@ cmd_error_internal (data, context) since they are asyncronous. */ if (EQ (XCAR (data), Qquit)) Vsignaling_function = Qnil; - + print_error_message (data, stream, context, Vsignaling_function); Vsignaling_function = Qnil; @@ -1334,7 +1355,18 @@ DEFUN ("abort-recursive-edit", Fabort_recursive_edit, Sabort_recursive_edit, 0, static int read_key_sequence P_ ((Lisp_Object *, int, Lisp_Object, int, int, int)); void safe_run_hooks P_ ((Lisp_Object)); -static void adjust_point_for_property P_ ((int)); +static void adjust_point_for_property P_ ((int, int)); + +/* Cancel hourglass from protect_unwind. + ARG is not used. */ +#ifdef HAVE_X_WINDOWS +static Lisp_Object +cancel_hourglass_unwind (arg) + Lisp_Object arg; +{ + cancel_hourglass (); +} +#endif Lisp_Object command_loop_1 () @@ -1350,6 +1382,7 @@ command_loop_1 () #ifdef MULTI_KBOARD int was_locked = single_kboard; #endif + int already_adjusted; current_kboard->Vprefix_arg = Qnil; current_kboard->Vlast_prefix_arg = Qnil; @@ -1359,6 +1392,7 @@ command_loop_1 () nonundocount = 0; this_command_key_count = 0; + this_command_key_count_reset = 0; this_single_command_key_start = 0; if (NILP (Vmemory_full)) @@ -1491,6 +1525,7 @@ command_loop_1 () { cancel_echoing (); this_command_key_count = 0; + this_command_key_count_reset = 0; this_single_command_key_start = 0; goto finalize; } @@ -1543,7 +1578,7 @@ command_loop_1 () if (SYMBOLP (cmd)) { Lisp_Object cmd1; - if (cmd1 = Fremap_command (cmd), !NILP (cmd1)) + if (cmd1 = Fcommand_remapping (cmd), !NILP (cmd1)) cmd = cmd1; } @@ -1555,7 +1590,9 @@ command_loop_1 () if the symbol is a local variable. */ if (!NILP (Vpre_command_hook) && !NILP (Vrun_hooks)) safe_run_hooks (Qpre_command_hook); - + + already_adjusted = 0; + if (NILP (Vthis_command)) { /* nil means key is undefined. */ @@ -1579,12 +1616,23 @@ command_loop_1 () = window_display_table (XWINDOW (selected_window)); lose = FETCH_CHAR (PT_BYTE); SET_PT (PT + 1); - if ((dp - ? (VECTORP (DISP_CHAR_VECTOR (dp, lose)) - ? XVECTOR (DISP_CHAR_VECTOR (dp, lose))->size == 1 - : (NILP (DISP_CHAR_VECTOR (dp, lose)) - && (lose >= 0x20 && lose < 0x7f))) - : (lose >= 0x20 && lose < 0x7f)) + if (! NILP (Vpost_command_hook)) + /* Put this before calling adjust_point_for_property + so it will only get called once in any case. */ + goto directly_done; + if (current_buffer == prev_buffer + && last_point_position != PT + && NILP (Vdisable_point_adjustment) + && NILP (Vglobal_disable_point_adjustment)) + adjust_point_for_property (last_point_position, 0); + already_adjusted = 1; + if (PT == last_point_position + 1 + && (dp + ? (VECTORP (DISP_CHAR_VECTOR (dp, lose)) + ? XVECTOR (DISP_CHAR_VECTOR (dp, lose))->size == 1 + : (NILP (DISP_CHAR_VECTOR (dp, lose)) + && (lose >= 0x20 && lose < 0x7f))) + : (lose >= 0x20 && lose < 0x7f)) /* To extract the case of continuation on wide-column characters. */ && (WIDTH_BY_CHAR_HEAD (FETCH_BYTE (PT_BYTE)) == 1) @@ -1608,12 +1656,21 @@ command_loop_1 () = window_display_table (XWINDOW (selected_window)); SET_PT (PT - 1); lose = FETCH_CHAR (PT_BYTE); - if ((dp - ? (VECTORP (DISP_CHAR_VECTOR (dp, lose)) - ? XVECTOR (DISP_CHAR_VECTOR (dp, lose))->size == 1 - : (NILP (DISP_CHAR_VECTOR (dp, lose)) - && (lose >= 0x20 && lose < 0x7f))) - : (lose >= 0x20 && lose < 0x7f)) + if (! NILP (Vpost_command_hook)) + goto directly_done; + if (current_buffer == prev_buffer + && last_point_position != PT + && NILP (Vdisable_point_adjustment) + && NILP (Vglobal_disable_point_adjustment)) + adjust_point_for_property (last_point_position, 0); + already_adjusted = 1; + if (PT == last_point_position - 1 + && (dp + ? (VECTORP (DISP_CHAR_VECTOR (dp, lose)) + ? XVECTOR (DISP_CHAR_VECTOR (dp, lose))->size == 1 + : (NILP (DISP_CHAR_VECTOR (dp, lose)) + && (lose >= 0x20 && lose < 0x7f))) + : (lose >= 0x20 && lose < 0x7f)) && (XFASTINT (XWINDOW (selected_window)->last_modified) >= MODIFF) && (XFASTINT (XWINDOW (selected_window)->last_overlay_modified) @@ -1629,10 +1686,13 @@ command_loop_1 () goto directly_done; } else if (EQ (Vthis_command, Qself_insert_command) - /* Try this optimization only on ascii keystrokes. */ - && INTEGERP (last_command_char)) + /* Try this optimization only on char keystrokes. */ + && NATNUMP (last_command_char) + && CHAR_VALID_P (XFASTINT (last_command_char), 0)) { - unsigned int c = XINT (last_command_char); + unsigned int c + = translate_char (Vtranslation_table_for_input, + XFASTINT (last_command_char), 0, 0, 0); int value; if (NILP (Vexecuting_macro) && !EQ (minibuf_window, selected_window)) @@ -1644,7 +1704,7 @@ command_loop_1 () } nonundocount++; } - + lose = ((XFASTINT (XWINDOW (selected_window)->last_modified) < MODIFF) || (XFASTINT (XWINDOW (selected_window)->last_overlay_modified) @@ -1657,12 +1717,17 @@ command_loop_1 () || detect_input_pending () || !NILP (XWINDOW (selected_window)->column_number_displayed) || !NILP (Vexecuting_macro)); - + value = internal_self_insert (c, 0); if (value == 2) nonundocount = 0; + if (! NILP (Vpost_command_hook)) + /* Put this before calling adjust_point_for_property + so it will only get called once in any case. */ + goto directly_done; + /* VALUE == 1 when AFTER-CHANGE functions are installed which is the case most of the time because FONT-LOCK installs one. */ @@ -1674,16 +1739,22 @@ command_loop_1 () /* Here for a command that isn't executed directly */ + { #ifdef HAVE_X_WINDOWS - if (display_hourglass_p - && NILP (Vexecuting_macro)) - start_hourglass (); + int scount = SPECPDL_INDEX (); + + if (display_hourglass_p + && NILP (Vexecuting_macro)) + { + record_unwind_protect (cancel_hourglass_unwind, Qnil); + start_hourglass (); + } #endif - nonundocount = 0; - if (NILP (current_kboard->Vprefix_arg)) - Fundo_boundary (); - Fcommand_execute (Vthis_command, Qnil, Qnil, Qnil); + nonundocount = 0; + if (NILP (current_kboard->Vprefix_arg)) + Fundo_boundary (); + Fcommand_execute (Vthis_command, Qnil, Qnil, Qnil); #ifdef HAVE_X_WINDOWS /* Do not check display_hourglass_p here, because @@ -1692,8 +1763,9 @@ command_loop_1 () But don't cancel the hourglass within a macro just because a command in the macro finishes. */ if (NILP (Vexecuting_macro)) - cancel_hourglass (); + unbind_to (scount, Qnil); #endif + } } directly_done: ; current_kboard->Vlast_prefix_arg = Vcurrent_prefix_arg; @@ -1740,6 +1812,7 @@ command_loop_1 () current_kboard->Vreal_last_command = real_this_command; cancel_echoing (); this_command_key_count = 0; + this_command_key_count_reset = 0; this_single_command_key_start = 0; } @@ -1765,8 +1838,9 @@ command_loop_1 () if (current_buffer == prev_buffer && last_point_position != PT && NILP (Vdisable_point_adjustment) - && NILP (Vglobal_disable_point_adjustment)) - adjust_point_for_property (last_point_position); + && NILP (Vglobal_disable_point_adjustment) + && !already_adjusted) + adjust_point_for_property (last_point_position, MODIFF != prev_modiff); /* Install chars successfully executed in kbd macro. */ @@ -1785,47 +1859,131 @@ extern Lisp_Object Qcomposition, Qdisplay; /* Adjust point to a boundary of a region that has such a property that should be treated intangible. For the moment, we check - `composition' and `display' property. LAST_PT is the last position - of point. */ + `composition', `display' and `invisible' properties. + LAST_PT is the last position of point. */ + +extern Lisp_Object Qafter_string, Qbefore_string; +extern Lisp_Object get_pos_property P_ ((Lisp_Object, Lisp_Object, Lisp_Object)); static void -adjust_point_for_property (last_pt) +adjust_point_for_property (last_pt, modified) int last_pt; + int modified; { - int start, end; - Lisp_Object val; - int check_composition = 1, check_display = 1; + int beg, end; + Lisp_Object val, overlay, tmp; + int check_composition = 1, check_display = 1, check_invisible = 1; + int orig_pt = PT; - while (check_composition || check_display) + /* FIXME: cycling is probably not necessary because these properties + can't be usefully combined anyway. */ + while (check_composition || check_display || check_invisible) { if (check_composition && PT > BEGV && PT < ZV - && get_property_and_range (PT, Qcomposition, &val, &start, &end, Qnil) - && COMPOSITION_VALID_P (start, end, val) - && start < PT && end > PT - && (last_pt <= start || last_pt >= end)) + && get_property_and_range (PT, Qcomposition, &val, &beg, &end, Qnil) + && COMPOSITION_VALID_P (beg, end, val) + && beg < PT /* && end > PT <- It's always the case. */ + && (last_pt <= beg || last_pt >= end)) { - if (PT < last_pt) - SET_PT (start); - else - SET_PT (end); - check_display = 1; + xassert (end > PT); + SET_PT (PT < last_pt ? beg : end); + check_display = check_invisible = 1; } check_composition = 0; if (check_display && PT > BEGV && PT < ZV - && get_property_and_range (PT, Qdisplay, &val, &start, &end, Qnil) + && !NILP (val = get_char_property_and_overlay + (make_number (PT), Qdisplay, Qnil, &overlay)) && display_prop_intangible_p (val) - && start < PT && end > PT - && (last_pt <= start || last_pt >= end)) + && (!OVERLAYP (overlay) + ? 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. */ { - if (PT < last_pt) - SET_PT (start); - else - SET_PT (end); - check_composition = 1; + xassert (end > PT); + SET_PT (PT < last_pt ? beg : end); + check_composition = check_invisible = 1; } check_display = 0; + if (check_invisible && PT > BEGV && PT < ZV) + { + int inv, ellipsis = 0; + beg = end = PT; + + /* Find boundaries `beg' and `end' of the invisible area, if any. */ + while (end < ZV + && !NILP (val = get_char_property_and_overlay + (make_number (end), Qinvisible, Qnil, &overlay)) + && (inv = TEXT_PROP_MEANS_INVISIBLE (val))) + { + ellipsis = ellipsis || inv > 1 + || (OVERLAYP (overlay) + && (!NILP (Foverlay_get (overlay, Qafter_string)) + || !NILP (Foverlay_get (overlay, Qbefore_string)))); + tmp = Fnext_single_char_property_change + (make_number (end), Qinvisible, Qnil, Qnil); + end = NATNUMP (tmp) ? XFASTINT (tmp) : ZV; + } + while (beg > BEGV + && !NILP (val = get_char_property_and_overlay + (make_number (beg - 1), Qinvisible, Qnil, &overlay)) + && (inv = TEXT_PROP_MEANS_INVISIBLE (val))) + { + ellipsis = ellipsis || inv > 1 + || (OVERLAYP (overlay) + && (!NILP (Foverlay_get (overlay, Qafter_string)) + || !NILP (Foverlay_get (overlay, Qbefore_string)))); + tmp = Fprevious_single_char_property_change + (make_number (beg), Qinvisible, Qnil, Qnil); + beg = NATNUMP (tmp) ? XFASTINT (tmp) : BEGV; + } + + /* Move away from the inside area. */ + if (beg < PT && end > PT) + { + SET_PT ((orig_pt == PT && (last_pt < beg || last_pt > end)) + /* We haven't moved yet (so we don't need to fear + infinite-looping) and we were outside the range + before (so either end of the range still corresponds + to a move in the right direction): pretend we moved + less than we actually did, so that we still have + more freedom below in choosing which end of the range + to go to. */ + ? (orig_pt = -1, PT < last_pt ? end : beg) + /* We either have moved already or the last point + was already in the range: we don't get to choose + which end of the range we have to go to. */ + : (PT < last_pt ? beg : end)); + check_composition = check_display = 1; + } + xassert (PT == beg || PT == end); + /* Pretend the area doesn't exist if the buffer is not + modified. */ + if (!modified && !ellipsis && beg < end) + { + if (last_pt == beg && PT == end && end < ZV) + (check_composition = check_display = 1, SET_PT (end + 1)); + else if (last_pt == end && PT == beg && beg > BEGV) + (check_composition = check_display = 1, SET_PT (beg - 1)); + else if (PT == ((PT < last_pt) ? beg : end)) + /* We've already moved as far as we can. Trying to go + to the other end would mean moving backwards and thus + could lead to an infinite loop. */ + ; + else if (val = get_pos_property (make_number (PT), + Qinvisible, Qnil), + TEXT_PROP_MEANS_INVISIBLE (val) + && (val = get_pos_property + (make_number (PT == beg ? end : beg), + Qinvisible, Qnil), + !TEXT_PROP_MEANS_INVISIBLE (val))) + (check_composition = check_display = 1, + SET_PT (PT == beg ? end : beg)); + } + } + check_invisible = 0; } } @@ -1844,6 +2002,11 @@ static Lisp_Object safe_run_hooks_error (data) Lisp_Object data; { + Lisp_Object args[3]; + args[0] = build_string ("Error in %s: %s"); + args[1] = Vinhibit_quit; + args[2] = data; + Fmessage (3, args); return Fset (Vinhibit_quit, Qnil); } @@ -1917,7 +2080,7 @@ start_polling () /* Turn alarm handling on unconditionally. It might have been turned off in process.c. */ turn_on_atimers (1); - + /* If poll timer doesn't exist, are we need one with a different interval, start a new one. */ if (poll_timer == NULL @@ -1927,7 +2090,7 @@ start_polling () if (poll_timer) cancel_atimer (poll_timer); - + EMACS_SET_SECS_USECS (interval, polling_period, 0); poll_timer = start_atimer (ATIMER_CONTINUOUS, interval, poll_for_input, NULL); @@ -2088,7 +2251,7 @@ show_help_echo (help, window, object, pos, ok_to_overwrite_keystroke_echo) } else help = safe_eval (help); - + if (!STRINGP (help)) return; } @@ -2111,7 +2274,7 @@ show_help_echo (help, window, object, pos, ok_to_overwrite_keystroke_echo) if (!help_echo_showing_p) Vpre_help_message = current_message (); - + specbind (Qmessage_truncate_lines, Qt); message3_nolog (help, SBYTES (help), STRING_MULTIBYTE (help)); @@ -2127,7 +2290,7 @@ show_help_echo (help, window, object, pos, ok_to_overwrite_keystroke_echo) else message (0); } - + help_echo_showing_p = STRINGP (help); } } @@ -2144,6 +2307,14 @@ static void record_char (); static jmp_buf wrong_kboard_jmpbuf; #endif +#define STOP_POLLING \ +do { if (! polling_stopped_here) stop_polling (); \ + polling_stopped_here = 1; } while (0) + +#define RESUME_POLLING \ +do { if (polling_stopped_here) start_polling (); \ + polling_stopped_here = 0; } while (0) + /* read a character from the keyboard; call the redisplay if needed */ /* commandflag 0 means do not do auto-saving, but do do redisplay. -1 means do not do redisplay, but do do autosaving. @@ -2183,11 +2354,14 @@ read_char (commandflag, nmaps, maps, prev_event, used_mouse_menu) volatile int reread; struct gcpro gcpro1, gcpro2; EMACS_TIME last_idle_start; + int polling_stopped_here = 0; also_record = Qnil; +#if 0 /* This was commented out as part of fixing echo for C-u left. */ before_command_key_count = this_command_key_count; before_command_echo_length = echo_length (); +#endif c = Qnil; previous_echo_area_message = Qnil; @@ -2233,13 +2407,13 @@ read_char (commandflag, nmaps, maps, prev_event, used_mouse_menu) && EQ (XCDR (c), Qdisabled) && (SYMBOLP (XCAR (c)) || INTEGERP (XCAR (c)))) c = XCAR (c); - + /* If the queued event is something that used the mouse, set used_mouse_menu accordingly. */ if (used_mouse_menu && (EQ (c, Qtool_bar) || EQ (c, Qmenu_bar))) *used_mouse_menu = 1; - + reread = 1; goto reread_for_input_method; } @@ -2259,9 +2433,7 @@ read_char (commandflag, nmaps, maps, prev_event, used_mouse_menu) goto reread_for_input_method; } - /* If there is no function key translated before - reset-this-command-lengths takes effect, forget about it. */ - before_command_restore_flag = 0; + this_command_key_count_reset = 0; if (!NILP (Vexecuting_macro)) { @@ -2284,7 +2456,7 @@ read_char (commandflag, nmaps, maps, prev_event, used_mouse_menu) || executing_macro_index >= XFASTINT (Flength (Vexecuting_macro))) { XSETINT (c, -1); - RETURN_UNGCPRO (c); + goto exit; } c = Faref (Vexecuting_macro, make_number (executing_macro_index)); @@ -2336,7 +2508,7 @@ read_char (commandflag, nmaps, maps, prev_event, used_mouse_menu) } /* Message turns off echoing unless more keystrokes turn it on again. - + The code in 20.x for the condition was 1. echo_area_glyphs && *echo_area_glyphs @@ -2344,10 +2516,10 @@ read_char (commandflag, nmaps, maps, prev_event, used_mouse_menu) 3. && ok_to_echo_at_next_pause != echo_area_glyphs (1) means there's a current message displayed - + (2) means it's not the message from echoing from the current kboard. - + (3) There's only one place in 20.x where ok_to_echo_at_next_pause is set to a non-null value. This is done in read_char and it is set to echo_area_glyphs after a call to echo_char. That means @@ -2359,7 +2531,7 @@ read_char (commandflag, nmaps, maps, prev_event, used_mouse_menu) must be either null, or the current message isn't from echoing at all, or it's from echoing from a different kboard than the current one. */ - + if (/* There currently is something in the echo area. */ !NILP (echo_area_buffer[0]) && (/* And it's either not from echoing. */ @@ -2371,7 +2543,7 @@ read_char (commandflag, nmaps, maps, prev_event, used_mouse_menu) cancel_echoing (); else echo_dash (); - + /* Try reading a character via menu prompting in the minibuf. Try this before the sit-for, because the sit-for would do the wrong thing if we are supposed to do @@ -2446,7 +2618,7 @@ read_char (commandflag, nmaps, maps, prev_event, used_mouse_menu) /* If in middle of key sequence and minibuffer not active, start echoing if enough time elapses. */ - if (minibuf_level == 0 + if (minibuf_level == 0 && !current_kboard->immediate_echo && this_command_key_count > 0 && ! noninteractive @@ -2463,7 +2635,7 @@ read_char (commandflag, nmaps, maps, prev_event, used_mouse_menu) || (!echo_kboard && ok_to_echo_at_next_pause))) { Lisp_Object tem0; - + /* After a mouse event, start echoing right away. This is because we are probably about to display a menu, and we don't want to delay before doing so. */ @@ -2516,7 +2688,7 @@ read_char (commandflag, nmaps, maps, prev_event, used_mouse_menu) /* Now that we have read an event, Emacs is not idle. */ timer_stop_idle (); - RETURN_UNGCPRO (c); + goto exit; } /* Maybe autosave and/or garbage collect due to idleness. */ @@ -2623,7 +2795,7 @@ read_char (commandflag, nmaps, maps, prev_event, used_mouse_menu) wrong_kboard: - stop_polling (); + STOP_POLLING; /* Finally, we read from the main queue, and if that gives us something we can't use yet, we put it on the @@ -2692,7 +2864,7 @@ read_char (commandflag, nmaps, maps, prev_event, used_mouse_menu) should the next event read be a help-echo. */ last_idle_start = timer_idleness_start_time; timer_stop_idle (); - start_polling (); + RESUME_POLLING; if (NILP (c)) { @@ -2709,7 +2881,7 @@ read_char (commandflag, nmaps, maps, prev_event, used_mouse_menu) so don't show them to the user. Also, don't record a key if we already did. */ if (BUFFERP (c) || key_already_recorded) - RETURN_UNGCPRO (c); + goto exit; /* Process special events within read_char and loop around to read another event. */ @@ -2744,14 +2916,14 @@ read_char (commandflag, nmaps, maps, prev_event, used_mouse_menu) { /* If kbd_buffer_get_event gave us an EOF, return that. */ if (XINT (c) == -1) - RETURN_UNGCPRO (c); + goto exit; if ((STRINGP (Vkeyboard_translate_table) && SCHARS (Vkeyboard_translate_table) > (unsigned) XFASTINT (c)) || (VECTORP (Vkeyboard_translate_table) && XVECTOR (Vkeyboard_translate_table)->size > (unsigned) XFASTINT (c)) || (CHAR_TABLE_P (Vkeyboard_translate_table) - && CHAR_TABLE_ORDINARY_SLOTS > (unsigned) XFASTINT (c))) + && CHAR_VALID_P (XINT (c), 0))) { Lisp_Object d; d = Faref (Vkeyboard_translate_table, c); @@ -2771,13 +2943,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); @@ -2827,8 +2999,8 @@ read_char (commandflag, nmaps, maps, prev_event, used_mouse_menu) && (unsigned) XINT (c) != 127 && (unsigned) XINT (c) < 256) { - Lisp_Object keys; - int key_count; + Lisp_Object keys; + int key_count, key_count_reset; struct gcpro gcpro1; int count = SPECPDL_INDEX (); @@ -2837,6 +3009,7 @@ read_char (commandflag, nmaps, maps, prev_event, used_mouse_menu) struct kboard *saved_ok_to_echo = ok_to_echo_at_next_pause; int saved_echo_after_prompt = current_kboard->echo_after_prompt; +#if 0 if (before_command_restore_flag) { this_command_key_count = before_command_key_count_1; @@ -2845,9 +3018,11 @@ read_char (commandflag, nmaps, maps, prev_event, used_mouse_menu) echo_truncate (before_command_echo_length_1); before_command_restore_flag = 0; } +#endif /* Save the this_command_keys status. */ key_count = this_command_key_count; + key_count_reset = this_command_key_count_reset; if (key_count > 0) keys = Fcopy_sequence (this_command_keys); @@ -2857,6 +3032,7 @@ read_char (commandflag, nmaps, maps, prev_event, used_mouse_menu) /* Clear out this_command_keys. */ this_command_key_count = 0; + this_command_key_count_reset = 0; /* Now wipe the echo area. */ if (!NILP (echo_area_buffer[0])) @@ -2879,6 +3055,7 @@ read_char (commandflag, nmaps, maps, prev_event, used_mouse_menu) /* Restore the saved echoing state and this_command_keys state. */ this_command_key_count = key_count; + this_command_key_count_reset = key_count_reset; if (key_count > 0) this_command_keys = keys; @@ -2927,11 +3104,10 @@ read_char (commandflag, nmaps, maps, prev_event, used_mouse_menu) timer_idleness_start_time = last_idle_start; goto retry; } - - if (this_command_key_count == 0 || ! reread) + + if (! reread || this_command_key_count == 0 + || this_command_key_count_reset) { - before_command_key_count = this_command_key_count; - before_command_echo_length = echo_length (); /* Don't echo mouse motion events. */ if ((FLOATP (Vecho_keystrokes) || INTEGERP (Vecho_keystrokes)) @@ -2986,6 +3162,8 @@ read_char (commandflag, nmaps, maps, prev_event, used_mouse_menu) } } + exit: + RESUME_POLLING; RETURN_UNGCPRO (c); } @@ -3001,8 +3179,10 @@ record_menu_key (c) record_char (c); +#if 0 before_command_key_count = this_command_key_count; before_command_echo_length = echo_length (); +#endif /* Don't echo mouse motion events. */ if ((FLOATP (Vecho_keystrokes) || INTEGERP (Vecho_keystrokes)) @@ -3057,19 +3237,19 @@ record_char (c) Lisp_Object ev1, ev2, ev3; int ix1, ix2, ix3; - + if ((ix1 = recent_keys_index - 1) < 0) ix1 = NUM_RECENT_KEYS - 1; ev1 = AREF (recent_keys, ix1); - + if ((ix2 = ix1 - 1) < 0) ix2 = NUM_RECENT_KEYS - 1; ev2 = AREF (recent_keys, ix2); - + if ((ix3 = ix2 - 1) < 0) ix3 = NUM_RECENT_KEYS - 1; ev3 = AREF (recent_keys, ix3); - + if (EQ (XCAR (c), Qhelp_echo)) { /* Don't record `help-echo' in recent_keys unless it shows some help @@ -3140,7 +3320,7 @@ record_char (c) } num_nonmacro_input_events++; - + /* Write c to the dribble file. If c is a lispy event, write the event's symbol to the dribble file, in . Bleaugh. If you, dear reader, have a better idea, you've got the source. :-) */ @@ -3385,7 +3565,6 @@ kbd_buffer_store_event (event) if (c == quit_char) { - static SIGTYPE interrupt_signal P_ ((int)); #ifdef MULTI_KBOARD KBOARD *kb; struct input_event *sp; @@ -3456,7 +3635,7 @@ kbd_buffer_store_event (event) if (kbd_fetch_ptr - 1 != kbd_store_ptr) { int idx; - + #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. */ @@ -3557,6 +3736,7 @@ discard_mouse_events () sp = kbd_buffer; if (sp->kind == MOUSE_CLICK_EVENT + || sp->kind == WHEEL_EVENT #ifdef WINDOWSNT || sp->kind == W32_SCROLL_BAR_CLICK_EVENT #endif @@ -3580,7 +3760,7 @@ kbd_buffer_events_waiting (discard) int discard; { struct input_event *sp; - + for (sp = kbd_fetch_ptr; sp != kbd_store_ptr && sp->kind == NO_EVENT; ++sp) @@ -3776,7 +3956,8 @@ kbd_buffer_get_event (kbp, used_mouse_menu) XSETBUFFER (obj, current_buffer); kbd_fetch_ptr = event + 1; } -#if defined (USE_X_TOOLKIT) || defined (HAVE_NTGUI) || defined (MAC_OS) +#if defined (USE_X_TOOLKIT) || defined (HAVE_NTGUI) || defined (MAC_OS) \ + || defined (USE_GTK) else if (event->kind == MENU_BAR_ACTIVATE_EVENT) { kbd_fetch_ptr = event + 1; @@ -3844,14 +4025,6 @@ kbd_buffer_get_event (kbp, used_mouse_menu) && !EQ (frame, selected_frame)) obj = make_lispy_switch_frame (frame); internal_last_event_frame = frame; - kbd_fetch_ptr = event + 1; - } - else if (event->kind == SELECT_WINDOW_EVENT) - { - /* Make an event (select-window (WINDOW)). */ - obj = Fcons (event->frame_or_window, Qnil); - obj = Fcons (Qselect_window, Fcons (obj, Qnil)); - kbd_fetch_ptr = event + 1; } else @@ -3882,8 +4055,9 @@ kbd_buffer_get_event (kbp, used_mouse_menu) if (NILP (obj)) { obj = make_lispy_event (event); - -#if defined (USE_X_TOOLKIT) || defined (HAVE_NTGUI) || defined(MAC_OS) + +#if defined (USE_X_TOOLKIT) || defined (HAVE_NTGUI) || defined(MAC_OS) \ + || defined (USE_GTK) /* If this was a menu selection, then set the flag to inhibit writing to last_nonmenu_event. Don't do this if the event we're returning is (menu-bar), though; that indicates the @@ -4212,7 +4386,7 @@ timer_check (do_it_now) difference = idle_timer_difference; } vector = XVECTOR (chosen_timer)->contents; - + /* If timer is ripe, run it if it hasn't been run. */ if (EMACS_TIME_NEG_P (difference) || (EMACS_SECS (difference) == 0 @@ -4229,7 +4403,7 @@ timer_check (do_it_now) vector[0] = Qt; specbind (Qinhibit_quit, Qt); - + call1 (Qtimer_event_handler, chosen_timer); Vdeactivate_mark = old_deactivate_mark; timers_run++; @@ -4262,9 +4436,7 @@ timer_check (do_it_now) static Lisp_Object accent_key_syms; static Lisp_Object func_key_syms; static Lisp_Object mouse_syms; -#if defined(WINDOWSNT) || defined(MAC_OSX) -static Lisp_Object mouse_wheel_syms; -#endif +static Lisp_Object wheel_syms; static Lisp_Object drag_n_drop_syms; /* This is a list of keysym codes for special "accent" characters. @@ -4337,6 +4509,41 @@ static int lispy_accent_codes[] = #else 0, #endif +#ifdef XK_dead_abovering + XK_dead_abovering, +#else + 0, +#endif +#ifdef XK_dead_iota + XK_dead_iota, +#else + 0, +#endif +#ifdef XK_dead_belowdot + XK_dead_belowdot, +#else + 0, +#endif +#ifdef XK_dead_voiced_sound + XK_dead_voiced_sound, +#else + 0, +#endif +#ifdef XK_dead_semivoiced_sound + XK_dead_semivoiced_sound, +#else + 0, +#endif +#ifdef XK_dead_hook + XK_dead_hook, +#else + 0, +#endif +#ifdef XK_dead_horn + XK_dead_horn, +#else + 0, +#endif }; /* This is a list of Lisp names for special "accent" characters. @@ -4357,6 +4564,13 @@ static char *lispy_accent_keys[] = "dead-caron", "dead-doubleacute", "dead-abovedot", + "dead-abovering", + "dead-iota", + "dead-belowdot", + "dead-voiced-sound", + "dead-semivoiced-sound", + "dead-hook", + "dead-horn", }; #ifdef HAVE_NTGUI @@ -4365,36 +4579,36 @@ static char *lispy_accent_keys[] = char *lispy_function_keys[] = { 0, /* 0 */ - + 0, /* VK_LBUTTON 0x01 */ 0, /* VK_RBUTTON 0x02 */ "cancel", /* VK_CANCEL 0x03 */ 0, /* VK_MBUTTON 0x04 */ - + 0, 0, 0, /* 0x05 .. 0x07 */ - + "backspace", /* VK_BACK 0x08 */ "tab", /* VK_TAB 0x09 */ - + 0, 0, /* 0x0A .. 0x0B */ - + "clear", /* VK_CLEAR 0x0C */ "return", /* VK_RETURN 0x0D */ - + 0, 0, /* 0x0E .. 0x0F */ - + 0, /* VK_SHIFT 0x10 */ 0, /* VK_CONTROL 0x11 */ 0, /* VK_MENU 0x12 */ "pause", /* VK_PAUSE 0x13 */ "capslock", /* VK_CAPITAL 0x14 */ - + 0, 0, 0, 0, 0, 0, /* 0x15 .. 0x1A */ - + "escape", /* VK_ESCAPE 0x1B */ - + 0, 0, 0, 0, /* 0x1C .. 0x1F */ - + 0, /* VK_SPACE 0x20 */ "prior", /* VK_PRIOR 0x21 */ "next", /* VK_NEXT 0x22 */ @@ -4411,25 +4625,25 @@ char *lispy_function_keys[] = "insert", /* VK_INSERT 0x2D */ "delete", /* VK_DELETE 0x2E */ "help", /* VK_HELP 0x2F */ - + /* VK_0 thru VK_9 are the same as ASCII '0' thru '9' (0x30 - 0x39) */ - + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - + 0, 0, 0, 0, 0, 0, 0, /* 0x3A .. 0x40 */ - + /* VK_A thru VK_Z are the same as ASCII 'A' thru 'Z' (0x41 - 0x5A) */ - - 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, + + 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - + "lwindow", /* VK_LWIN 0x5B */ "rwindow", /* VK_RWIN 0x5C */ "apps", /* VK_APPS 0x5D */ - + 0, 0, /* 0x5E .. 0x5F */ - + "kp-0", /* VK_NUMPAD0 0x60 */ "kp-1", /* VK_NUMPAD1 0x61 */ "kp-2", /* VK_NUMPAD2 0x62 */ @@ -4470,13 +4684,13 @@ char *lispy_function_keys[] = "f22", /* VK_F22 0x85 */ "f23", /* VK_F23 0x86 */ "f24", /* VK_F24 0x87 */ - + 0, 0, 0, 0, /* 0x88 .. 0x8B */ 0, 0, 0, 0, /* 0x8C .. 0x8F */ - + "kp-numlock", /* VK_NUMLOCK 0x90 */ "scroll", /* VK_SCROLL 0x91 */ - + "kp-space", /* VK_NUMPAD_CLEAR 0x92 */ "kp-enter", /* VK_NUMPAD_ENTER 0x93 */ "kp-prior", /* VK_NUMPAD_PRIOR 0x94 */ @@ -4498,17 +4712,17 @@ char *lispy_function_keys[] = * No other API or message will distinguish left and right keys this way. */ /* 0xA0 .. 0xEF */ - + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - + /* 0xF0 .. 0xF5 */ - + 0, 0, 0, 0, 0, 0, - + "attn", /* VK_ATTN 0xF6 */ "crsel", /* VK_CRSEL 0xF7 */ "exsel", /* VK_EXSEL 0xF8 */ @@ -4523,6 +4737,10 @@ char *lispy_function_keys[] = #else /* not HAVE_NTGUI */ +/* This should be dealt with in XTread_socket now, and that doesn't + depend on the client system having the Kana syms defined. See also + the XK_kana_A case below. */ +#if 0 #ifdef XK_kana_A static char *lispy_kana_keys[] = { @@ -4537,7 +4755,7 @@ static char *lispy_kana_keys[] = 0,0,0,0,0,0,0,0,0,0,0,0,0,0,"overline",0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 0x480 .. 0x48f */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 0x490 .. 0x49f */ - 0, "kana-fullstop", "kana-openingbracket", "kana-closingbracket", + 0, "kana-fullstop", "kana-openingbracket", "kana-closingbracket", "kana-comma", "kana-conjunctive", "kana-WO", "kana-a", "kana-i", "kana-u", "kana-e", "kana-o", "kana-ya", "kana-yu", "kana-yo", "kana-tsu", @@ -4557,6 +4775,7 @@ static char *lispy_kana_keys[] = 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 0x4f0 .. 0x4ff */ }; #endif /* XK_kana_A */ +#endif /* 0 */ #define FUNCTION_KEY_OFFSET 0xff00 @@ -4655,9 +4874,9 @@ static char *iso_lispy_function_keys[] = 0, 0, 0, 0, 0, 0, 0, 0, /* 0xfe10 */ 0, 0, 0, 0, 0, 0, 0, 0, /* 0xfe18 */ "iso-lefttab", /* 0xfe20 */ - "iso-move-line-up", "iso-move-line-down", - "iso-partial-line-up", "iso-partial-line-down", - "iso-partial-space-left", "iso-partial-space-right", + "iso-move-line-up", "iso-move-line-down", + "iso-partial-line-up", "iso-partial-line-down", + "iso-partial-space-left", "iso-partial-space-right", "iso-set-margin-left", "iso-set-margin-right", /* 0xffe27, 28 */ "iso-release-margin-left", "iso-release-margin-right", "iso-release-both-margins", @@ -4671,21 +4890,11 @@ static char *iso_lispy_function_keys[] = Lisp_Object Vlispy_mouse_stem; -#if defined(WINDOWSNT) || defined(MAC_OSX) -/* mouse-wheel events are generated by the wheel on devices such as - the MS Intellimouse. The wheel sits in between the left and right - mouse buttons, and is typically used to scroll or zoom the window - underneath the pointer. mouse-wheel events specify the object on - which they operate, and a delta corresponding to the amount and - direction that the wheel is rotated. Clicking the mouse-wheel - generates a mouse-2 event. */ -static char *lispy_mouse_wheel_names[] = -{ - "mouse-wheel" +static char *lispy_wheel_names[] = +{ + "wheel-up", "wheel-down" }; -#endif /* WINDOWSNT */ - /* drag-n-drop events are generated when a set of selected files are dragged from another application and dropped onto an Emacs window. */ static char *lispy_drag_n_drop_names[] = @@ -4748,6 +4957,169 @@ EMACS_INT double_click_fuzz; int double_click_count; +/* Return position of a mouse click or wheel event */ + +static Lisp_Object +make_lispy_position (f, x, y, time) + struct frame *f; + Lisp_Object *x, *y; + unsigned long time; +{ + Lisp_Object window; + enum window_part part; + Lisp_Object posn = Qnil; + Lisp_Object extra_info = Qnil; + int wx, wy; + + /* Set `window' to the window under frame pixel coordinates (x,y) */ + if (f) + window = window_from_coordinates (f, XINT (*x), XINT (*y), + &part, &wx, &wy, 0); + else + window = Qnil; + + if (WINDOWP (window)) + { + /* It's a click in window window at frame coordinates (x,y) */ + struct window *w = XWINDOW (window); + 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) + { + /* Mode line or header line. Look for a string under + the mouse that may have a `local-map' property. */ + Lisp_Object string; + int charpos; + + posn = part == ON_MODE_LINE ? Qmode_line : Qheader_line; + rx = wx, ry = wy; + string = mode_line_string (w, part, &rx, &ry, &charpos, + &object, &dx, &dy, &width, &height); + if (STRINGP (string)) + string_info = Fcons (string, make_number (charpos)); + if (w == XWINDOW (selected_window)) + textpos = PT; + else + textpos = XMARKER (w->pointm)->charpos; + } + else if (part == ON_VERTICAL_BORDER) + { + 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, part, &rx, &ry, &charpos, + &object, &dx, &dy, &width, &height); + if (STRINGP (string)) + string_info = Fcons (string, make_number (charpos)); + } + else if (part == ON_LEFT_FRINGE || part == ON_RIGHT_FRINGE) + { + posn = (part == ON_LEFT_FRINGE) ? Qleft_fringe : 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); + } + + if (textpos < 0) + { + Lisp_Object string2, object2 = Qnil; + 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); + 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 (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)), + extra_info))); + } + else if (f != 0) + { + XSETFRAME (window, f); + } + else + { + window = Qnil; + XSETFASTINT (*x, 0); + XSETFASTINT (*y, 0); + } + + return Fcons (window, + Fcons (posn, + Fcons (Fcons (*x, *y), + Fcons (make_number (time), + extra_info)))); +} + /* Given a struct input_event, build the lisp event which represents it. If EVENT is 0, build a mouse movement event from the mouse movement buffer, which should have a movement event in it. @@ -4792,8 +5164,17 @@ make_lispy_event (event) case MULTIBYTE_CHAR_KEYSTROKE_EVENT: { Lisp_Object lispy_c; + int c = event->code; - XSETFASTINT (lispy_c, event->code); + /* Add in the other modifier bits. We took care of ctrl_modifier + just above, and the shift key was taken care of by the X code, + and applied to control characters by make_ctrl_char. */ + c |= (event->modifiers + & (meta_modifier | alt_modifier + | hyper_modifier | super_modifier | ctrl_modifier)); + /* What about the `shift' modifier ? */ + button_down_time = 0; + XSETFASTINT (lispy_c, c); return lispy_c; } @@ -4811,6 +5192,7 @@ make_lispy_event (event) (sizeof (lispy_accent_keys) / sizeof (lispy_accent_keys[0]))); +#if 0 #ifdef XK_kana_A if (event->code >= 0x400 && event->code < 0x500) return modify_event_symbol (event->code - 0x400, @@ -4820,6 +5202,7 @@ make_lispy_event (event) (sizeof (lispy_kana_keys) / sizeof (lispy_kana_keys[0]))); #endif /* XK_kana_A */ +#endif /* 0 */ #ifdef ISO_FUNCTION_KEY_OFFSET if (event->code < FUNCTION_KEY_OFFSET @@ -4871,24 +5254,23 @@ make_lispy_event (event) Lisp_Object position; Lisp_Object *start_pos_ptr; Lisp_Object start_pos; - Lisp_Object window; position = Qnil; /* Build the position as appropriate for this mouse click. */ if (event->kind == MOUSE_CLICK_EVENT) { - int part; struct frame *f = XFRAME (event->frame_or_window); - Lisp_Object posn; - Lisp_Object string_info = Qnil; +#if ! defined (USE_X_TOOLKIT) && ! defined (USE_GTK) int row, column; +#endif /* Ignore mouse events that were made on frame that have been deleted. */ if (! FRAME_LIVE_P (f)) return Qnil; +#if ! defined (USE_X_TOOLKIT) && ! defined (USE_GTK) /* EVENT->x and EVENT->y are frame-relative pixel coordinates at this place. Under old redisplay, COLUMN and ROW are set to frame relative glyph coordinates @@ -4897,7 +5279,6 @@ make_lispy_event (event) pixel_to_glyph_coords (f, XINT (event->x), XINT (event->y), &column, &row, NULL, 1); -#ifndef USE_X_TOOLKIT /* In the non-toolkit version, clicks on the menu bar are ordinary button events in the event buffer. Distinguish them, and invoke the menu. @@ -4949,83 +5330,16 @@ make_lispy_event (event) return Fcons (item, Fcons (position, Qnil)); } -#endif /* not USE_X_TOOLKIT */ - - /* Set `window' to the window under frame pixel coordinates - event->x/event->y. */ - window = window_from_coordinates (f, XINT (event->x), - XINT (event->y), &part, 0); - - if (!WINDOWP (window)) - { - window = event->frame_or_window; - posn = Qnil; - } - else - { - /* It's a click in window window at frame coordinates - event->x/ event->y. */ - struct window *w = XWINDOW (window); - - /* Get window relative coordinates. Original code - `rounded' this to glyph boundaries. */ - int wx = FRAME_TO_WINDOW_PIXEL_X (w, XINT (event->x)); - int wy = FRAME_TO_WINDOW_PIXEL_Y (w, XINT (event->y)); - - /* Set event coordinates to window-relative coordinates - for constructing the Lisp event below. */ - XSETINT (event->x, wx); - XSETINT (event->y, wy); +#endif /* not USE_X_TOOLKIT && not USE_GTK */ - if (part == 1 || part == 3) - { - /* Mode line or header line. Look for a string under - the mouse that may have a `local-map' property. */ - Lisp_Object string; - int charpos; - - posn = part == 1 ? Qmode_line : Qheader_line; - string = mode_line_string (w, wx, wy, part == 1, &charpos); - if (STRINGP (string)) - string_info = Fcons (string, make_number (charpos)); - } - else if (part == 2) - posn = Qvertical_line; - else if (part == 6 || part == 7) - { - int charpos; - Lisp_Object object = marginal_area_string (w, wx, wy, part, - &charpos); - posn = (part == 6) ? Qleft_margin : Qright_margin; - if (STRINGP (object)) - string_info = Fcons (object, make_number (charpos)); - } - else - { - Lisp_Object object; - struct display_pos p; - buffer_posn_from_coords (w, &wx, &wy, &object, &p); - posn = make_number (CHARPOS (p.pos)); - if (STRINGP (object)) - string_info - = Fcons (object, - make_number (CHARPOS (p.string_pos))); - } - } - - position - = Fcons (window, - Fcons (posn, - Fcons (Fcons (event->x, event->y), - Fcons (make_number (event->timestamp), - (NILP (string_info) - ? Qnil - : Fcons (string_info, Qnil)))))); + position = make_lispy_position (f, &event->x, &event->y, + event->timestamp); } #ifndef USE_TOOLKIT_SCROLL_BARS else { /* It's a scrollbar click. */ + Lisp_Object window; Lisp_Object portion_whole; Lisp_Object part; @@ -5048,7 +5362,7 @@ make_lispy_event (event) button + 1, Qnil); mouse_syms = larger_vector (mouse_syms, button + 1, Qnil); } - + start_pos_ptr = &AREF (button_down_location, button); start_pos = *start_pos_ptr; *start_pos_ptr = Qnil; @@ -5081,7 +5395,7 @@ make_lispy_event (event) && ((int)(event->timestamp - button_down_time) < XINT (Vdouble_click_time))))); } - + last_mouse_button = button; last_mouse_x = XINT (event->x); last_mouse_y = XINT (event->y); @@ -5146,7 +5460,7 @@ make_lispy_event (event) button_down_time = 0; event->modifiers |= drag_modifier; } - + /* Don't check is_double; treat this as multiple if the down-event was multiple. */ if (double_click_count > 1) @@ -5187,6 +5501,113 @@ make_lispy_event (event) } } + case WHEEL_EVENT: + { + Lisp_Object position; + Lisp_Object head; + + /* Build the position as appropriate for this mouse click. */ + struct frame *f = XFRAME (event->frame_or_window); + + /* Ignore wheel events that were made on frame that have been + deleted. */ + if (! FRAME_LIVE_P (f)) + return Qnil; + + position = make_lispy_position (f, &event->x, &event->y, + event->timestamp); + + /* Set double or triple modifiers to indicate the wheel speed. */ + { + /* On window-system frames, use the value of + double-click-fuzz as is. On other frames, interpret it + as a multiple of 1/8 characters. */ + struct frame *f; + int fuzz; + int is_double; + + if (WINDOWP (event->frame_or_window)) + f = XFRAME (XWINDOW (event->frame_or_window)->frame); + else if (FRAMEP (event->frame_or_window)) + f = XFRAME (event->frame_or_window); + else + abort (); + + if (FRAME_WINDOW_P (f)) + fuzz = double_click_fuzz; + else + fuzz = double_click_fuzz / 8; + + is_double = (last_mouse_button < 0 + && (abs (XINT (event->x) - last_mouse_x) <= fuzz) + && (abs (XINT (event->y) - last_mouse_y) <= fuzz) + && button_down_time != 0 + && (EQ (Vdouble_click_time, Qt) + || (INTEGERP (Vdouble_click_time) + && ((int)(event->timestamp - button_down_time) + < XINT (Vdouble_click_time))))); + if (is_double) + { + double_click_count++; + event->modifiers |= ((double_click_count > 2) + ? triple_modifier + : double_modifier); + } + else + { + double_click_count = 1; + event->modifiers |= click_modifier; + } + + button_down_time = event->timestamp; + /* Use a negative value to distinguish wheel from mouse button. */ + last_mouse_button = -1; + last_mouse_x = XINT (event->x); + last_mouse_y = XINT (event->y); + } + + { + int symbol_num; + + if (event->modifiers & up_modifier) + { + /* Emit a wheel-up event. */ + event->modifiers &= ~up_modifier; + symbol_num = 0; + } + else if (event->modifiers & down_modifier) + { + /* Emit a wheel-down event. */ + event->modifiers &= ~down_modifier; + symbol_num = 1; + } + else + /* Every wheel event should either have the down_modifier or + the up_modifier set. */ + abort (); + + /* Get the symbol we should use for the wheel event. */ + head = modify_event_symbol (symbol_num, + event->modifiers, + Qmouse_click, + Qnil, + lispy_wheel_names, + &wheel_syms, + ASIZE (wheel_syms)); + } + + if (event->modifiers & (double_modifier | triple_modifier)) + return Fcons (head, + Fcons (position, + Fcons (make_number (double_click_count), + Qnil))); + else + return Fcons (head, + Fcons (position, + Qnil)); + } + + #ifdef USE_TOOLKIT_SCROLL_BARS /* We don't have down and up events if using toolkit scroll bars, @@ -5205,7 +5626,7 @@ make_lispy_event (event) The incoming input_event contains in its `part' member an index of type `enum scroll_bar_part' which we can use as an index in scroll_bar_parts to get the appropriate symbol. */ - + case SCROLL_BAR_CLICK_EVENT: { Lisp_Object position, head, window, portion_whole, part; @@ -5225,16 +5646,19 @@ make_lispy_event (event) event->modifiers |= click_modifier; event->modifiers &= ~up_modifier; + if (event->code >= ASIZE (mouse_syms)) + mouse_syms = larger_vector (mouse_syms, event->code + 1, Qnil); + /* Get the symbol we should use for the mouse click. */ head = modify_event_symbol (event->code, event->modifiers, - Qmouse_click, + Qmouse_click, Vlispy_mouse_stem, NULL, &mouse_syms, XVECTOR (mouse_syms)->size); return Fcons (head, Fcons (position, Qnil)); } - + #endif /* USE_TOOLKIT_SCROLL_BARS */ #ifdef WINDOWSNT @@ -5272,7 +5696,7 @@ make_lispy_event (event) head = modify_event_symbol (button, event->modifiers, - Qmouse_click, + Qmouse_click, Vlispy_mouse_stem, NULL, &mouse_syms, XVECTOR (mouse_syms)->size); @@ -5282,86 +5706,11 @@ make_lispy_event (event) } } #endif /* WINDOWSNT */ -#if defined(WINDOWSNT) || defined(MAC_OSX) - case MOUSE_WHEEL_EVENT: - { - int part; - FRAME_PTR f = XFRAME (event->frame_or_window); - Lisp_Object window; - Lisp_Object posn; - Lisp_Object head, position; - int row, column; - - /* Ignore mouse events that were made on frame that - have been deleted. */ - if (! FRAME_LIVE_P (f)) - return Qnil; - pixel_to_glyph_coords (f, XINT (event->x), XINT (event->y), - &column, &row, NULL, 1); - window = window_from_coordinates (f, XINT (event->x), - XINT (event->y), &part, 0); - - if (!WINDOWP (window)) - { - window = event->frame_or_window; - posn = Qnil; - } - else - { - int pixcolumn, pixrow; - column -= XINT (XWINDOW (window)->left); - row -= XINT (XWINDOW (window)->top); - glyph_to_pixel_coords (XWINDOW(window), column, row, - &pixcolumn, &pixrow); - XSETINT (event->x, pixcolumn); - XSETINT (event->y, pixrow); - - if (part == 1) - posn = Qmode_line; - else if (part == 2) - posn = Qvertical_line; - else if (part == 3) - posn = Qheader_line; - else - { - Lisp_Object object; - struct display_pos p; - buffer_posn_from_coords (XWINDOW (window), &column, &row, - &object, &p); - posn = make_number (CHARPOS (p.pos)); - } - } - - { - Lisp_Object head, position; - - position - = Fcons (window, - Fcons (posn, - Fcons (Fcons (event->x, event->y), - Fcons (make_number (event->timestamp), - Qnil)))); - - head = modify_event_symbol (0, event->modifiers, - Qmouse_wheel, Qnil, - lispy_mouse_wheel_names, - &mouse_wheel_syms, 1); - return Fcons (head, - Fcons (position, - /* Insert 1 here so event-click-count works. */ - Fcons (make_number (1), - Fcons (make_number (event->code), - Qnil)))); - } - } -#endif /* WINDOWSNT || MAC_OSX */ case DRAG_N_DROP_EVENT: { - int part; FRAME_PTR f; - Lisp_Object window; - Lisp_Object posn; + Lisp_Object head, position; Lisp_Object files; /* The frame_or_window field should be a cons of the frame in @@ -5378,67 +5727,22 @@ make_lispy_event (event) if (! FRAME_LIVE_P (f)) return Qnil; - window = window_from_coordinates (f, XINT (event->x), - XINT (event->y), &part, 0); - - if (!WINDOWP (window)) - { - window = XCAR (event->frame_or_window); - posn = Qnil; - } - else - { - /* It's an event in window `window' at frame coordinates - event->x/ event->y. */ - struct window *w = XWINDOW (window); - - /* Get window relative coordinates. */ - int wx = FRAME_TO_WINDOW_PIXEL_X (w, XINT (event->x)); - int wy = FRAME_TO_WINDOW_PIXEL_Y (w, XINT (event->y)); - - /* Set event coordinates to window-relative coordinates - for constructing the Lisp event below. */ - XSETINT (event->x, wx); - XSETINT (event->y, wy); - - if (part == 1) - posn = Qmode_line; - else if (part == 2) - posn = Qvertical_line; - else if (part == 3) - posn = Qheader_line; - else - { - Lisp_Object object; - struct display_pos p; - buffer_posn_from_coords (w, &wx, &wy, &object, &p); - posn = make_number (CHARPOS (p.pos)); - } - } - - { - Lisp_Object head, position; - - position - = Fcons (window, - Fcons (posn, - Fcons (Fcons (event->x, event->y), - Fcons (make_number (event->timestamp), - Qnil)))); - - head = modify_event_symbol (0, event->modifiers, - Qdrag_n_drop, Qnil, - lispy_drag_n_drop_names, - &drag_n_drop_syms, 1); - return Fcons (head, - Fcons (position, - Fcons (files, - Qnil))); - } + position = make_lispy_position (f, &event->x, &event->y, + event->timestamp); + + head = modify_event_symbol (0, event->modifiers, + Qdrag_n_drop, Qnil, + lispy_drag_n_drop_names, + &drag_n_drop_syms, 1); + return Fcons (head, + Fcons (position, + Fcons (files, + Qnil))); } #endif /* HAVE_MOUSE */ -#if defined (USE_X_TOOLKIT) || defined (HAVE_NTGUI) || defined (MAC_OS) +#if defined (USE_X_TOOLKIT) || defined (HAVE_NTGUI) || defined (MAC_OS) \ + || defined (USE_GTK) case MENU_BAR_EVENT: if (EQ (event->arg, event->frame_or_window)) /* This is the prefix key. We translate this to @@ -5448,6 +5752,12 @@ make_lispy_event (event) return event->arg; #endif + case SELECT_WINDOW_EVENT: + /* Make an event (select-window (WINDOW)). */ + return Fcons (Qselect_window, + Fcons (Fcons (event->frame_or_window, Qnil), + Qnil)); + case TOOL_BAR_EVENT: if (EQ (event->arg, event->frame_or_window)) /* This is the prefix key. We translate this to @@ -5461,10 +5771,10 @@ make_lispy_event (event) case USER_SIGNAL_EVENT: /* A user signal. */ return *lispy_user_signals[event->code]; - + case SAVE_SESSION_EVENT: return Qsave_session; - + /* The 'kind' field of the event is something we don't recognize. */ default: abort (); @@ -5500,60 +5810,12 @@ make_lispy_movement (frame, bar_window, part, x, y, time) /* Or is it an ordinary mouse movement? */ else { - int area; - Lisp_Object window; - Lisp_Object posn; - - if (frame) - /* It's in a frame; which window on that frame? */ - window = window_from_coordinates (frame, XINT (x), XINT (y), &area, 0); - else - window = Qnil; + Lisp_Object position; - if (WINDOWP (window)) - { - struct window *w = XWINDOW (window); - int wx, wy; - - /* Get window relative coordinates. */ - wx = FRAME_TO_WINDOW_PIXEL_X (w, XINT (x)); - wy = FRAME_TO_WINDOW_PIXEL_Y (w, XINT (y)); - XSETINT (x, wx); - XSETINT (y, wy); - - if (area == 1) - posn = Qmode_line; - else if (area == 2) - posn = Qvertical_line; - else if (area == 3) - posn = Qheader_line; - else - { - Lisp_Object object; - struct display_pos p; - buffer_posn_from_coords (w, &wx, &wy, &object, &p); - posn = make_number (CHARPOS (p.pos)); - } - } - else if (frame != 0) - { - XSETFRAME (window, frame); - posn = Qnil; - } - else - { - window = Qnil; - posn = Qnil; - XSETFASTINT (x, 0); - XSETFASTINT (y, 0); - } + position = make_lispy_position (frame, &x, &y, time); return Fcons (Qmouse_movement, - Fcons (Fcons (window, - Fcons (posn, - Fcons (Fcons (x, y), - Fcons (make_number (time), - Qnil)))), + Fcons (position, Qnil)); } } @@ -5631,6 +5893,26 @@ parse_modifiers_uncached (symbol, modifier_end) break; #undef SINGLE_LETTER_MOD + +#define MULTI_LETTER_MOD(BIT, NAME, LEN) \ + if (i + LEN + 1 <= SBYTES (name) \ + && ! strncmp (SDATA (name) + i, NAME, LEN)) \ + { \ + this_mod_end = i + LEN; \ + this_mod = BIT; \ + } + + case 'd': + MULTI_LETTER_MOD (drag_modifier, "drag", 4); + MULTI_LETTER_MOD (down_modifier, "down", 4); + MULTI_LETTER_MOD (double_modifier, "double", 6); + break; + + case 't': + MULTI_LETTER_MOD (triple_modifier, "triple", 6); + break; +#undef MULTI_LETTER_MOD + } /* If we found no modifier, stop looking for them. */ @@ -5771,7 +6053,7 @@ parse_modifiers (symbol) SBYTES (SYMBOL_NAME (symbol)) - end), Qnil); - if (modifiers & ~VALMASK) + if (modifiers & ~INTMASK) abort (); XSETFASTINT (mask, modifiers); elements = Fcons (unmodified, Fcons (mask, Qnil)); @@ -5808,7 +6090,7 @@ apply_modifiers (modifiers, base) Lisp_Object cache, index, entry, new_symbol; /* Mask out upper bits. We don't know where this value's been. */ - modifiers &= VALMASK; + modifiers &= INTMASK; /* The click modifier never figures into cache indices. */ cache = Fget (base, Qmodifier_cache); @@ -5829,12 +6111,15 @@ apply_modifiers (modifiers, base) entry = Fcons (index, new_symbol); Fput (base, Qmodifier_cache, Fcons (entry, cache)); - /* We have the parsing info now for free, so add it to the caches. */ - XSETFASTINT (index, modifiers); - Fput (new_symbol, Qevent_symbol_element_mask, - Fcons (base, Fcons (index, Qnil))); - Fput (new_symbol, Qevent_symbol_elements, - Fcons (base, lispy_modifier_list (modifiers))); + /* We have the parsing info now for free, so we could add it to + the caches: + XSETFASTINT (index, modifiers); + Fput (new_symbol, Qevent_symbol_element_mask, + Fcons (base, Fcons (index, Qnil))); + Fput (new_symbol, Qevent_symbol_elements, + Fcons (base, lispy_modifier_list (modifiers))); + Sadly, this is only correct if `base' is indeed a base event, + which is not necessarily the case. -stef */ } /* Make sure this symbol is of the same kind as BASE. @@ -5963,8 +6248,12 @@ 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); - sprintf (buf, "%s-%d", SDATA (name_alist_or_stem), - XINT (symbol_int) + 1); + 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); value = intern (buf); } else if (name_table != 0 && name_table[symbol_num]) @@ -6265,6 +6554,7 @@ record_asynch_buffer_change () { struct input_event event; Lisp_Object tem; + EVENT_INIT (event); event.kind = BUFFER_SWITCH_EVENT; event.frame_or_window = Qnil; @@ -6323,6 +6613,9 @@ read_avail_input (expected) register int i; int nread; + for (i = 0; i < KBD_BUFFER_SIZE; i++) + EVENT_INIT (buf[i]); + 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); @@ -6352,13 +6645,18 @@ read_avail_input (expected) /* ??? Is it really right to send the signal just to this process rather than to the whole process group? Perhaps on systems with FIONREAD Emacs is alone in its group. */ - kill (getpid (), SIGHUP); + { + if (! noninteractive) + kill (getpid (), SIGHUP); + else + n_to_read = 0; + } if (n_to_read == 0) return 0; if (n_to_read > sizeof cbuf) n_to_read = sizeof cbuf; #else /* no FIONREAD */ -#if defined (USG) || defined (DGUX) +#if defined (USG) || defined (DGUX) || defined(CYGWIN) /* Read some input if available, but don't wait. */ n_to_read = sizeof cbuf; fcntl (input_fd, F_SETFL, O_NDELAY); @@ -6415,9 +6713,9 @@ read_avail_input (expected) ); #ifndef FIONREAD -#if defined (USG) || defined (DGUX) +#if defined (USG) || defined (DGUX) || defined (CYGWIN) fcntl (input_fd, F_SETFL, 0); -#endif /* USG or DGUX */ +#endif /* USG or DGUX or CYGWIN */ #endif /* no FIONREAD */ for (i = 0; i < nread; i++) { @@ -6449,18 +6747,39 @@ read_avail_input (expected) } #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. */ -SIGTYPE +static SIGTYPE input_available_signal (signo) int 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; @@ -6475,20 +6794,11 @@ input_available_signal (signo) 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 */ +#ifdef SYNC_INPUT + interrupt_input_pending = 1; +#else + handle_async_input (); #endif - } #ifdef BSD4_1 sigfree (); @@ -6507,14 +6817,14 @@ void reinvoke_input_signal () { #ifdef SIGIO - kill (getpid (), SIGIO); + handle_async_input (); #endif } -static void menu_bar_item P_ ((Lisp_Object, Lisp_Object)); -static void menu_bar_one_keymap P_ ((Lisp_Object)); +static void menu_bar_item P_ ((Lisp_Object, Lisp_Object, Lisp_Object, void*)); +static Lisp_Object menu_bar_one_keymap_changed_items; /* These variables hold the vector under construction within menu_bar_items and its subroutines, and the current index @@ -6618,7 +6928,10 @@ menu_bar_items (old) def = get_keymap (access_keymap (maps[mapno], Qmenu_bar, 1, 0, 1), 0, 1); if (CONSP (def)) - menu_bar_one_keymap (def); + { + menu_bar_one_keymap_changed_items = Qnil; + map_keymap (def, menu_bar_item, Qnil, NULL, 1); + } } /* Move to the end those items that should be at the end. */ @@ -6672,48 +6985,15 @@ menu_bar_items (old) return menu_bar_items_vector; } -/* Scan one map KEYMAP, accumulating any menu items it defines - in menu_bar_items_vector. */ - -static Lisp_Object menu_bar_one_keymap_changed_items; - -static void -menu_bar_one_keymap (keymap) - Lisp_Object keymap; -{ - Lisp_Object tail, item; - - menu_bar_one_keymap_changed_items = Qnil; - - /* Loop over all keymap entries that have menu strings. */ - for (tail = keymap; CONSP (tail); tail = XCDR (tail)) - { - item = XCAR (tail); - if (CONSP (item)) - menu_bar_item (XCAR (item), XCDR (item)); - else if (VECTORP (item)) - { - /* Loop over the char values represented in the vector. */ - int len = XVECTOR (item)->size; - int c; - for (c = 0; c < len; c++) - { - Lisp_Object character; - XSETFASTINT (character, c); - menu_bar_item (character, XVECTOR (item)->contents[c]); - } - } - } -} - /* Add one item to menu_bar_items_vector, for KEY, ITEM_STRING and DEF. If there's already an item for KEY, add this DEF to it. */ Lisp_Object item_properties; static void -menu_bar_item (key, item) - Lisp_Object key, item; +menu_bar_item (key, item, dummy1, dummy2) + Lisp_Object key, item, dummy1; + void *dummy2; { struct gcpro gcpro1; int i; @@ -6786,7 +7066,10 @@ menu_bar_item (key, item) { Lisp_Object old; old = XVECTOR (menu_bar_items_vector)->contents[i + 2]; - XVECTOR (menu_bar_items_vector)->contents[i + 2] = Fcons (item, old); + /* If the new and the old items are not both keymaps, + the lookup will only find `item'. */ + item = Fcons (item, KEYMAPP (item) && KEYMAPP (XCAR (old)) ? old : Qnil); + XVECTOR (menu_bar_items_vector)->contents[i + 2] = item; } } @@ -6803,7 +7086,7 @@ menu_item_eval_property_1 (arg) return Qnil; } -/* Evaluate an expression and return the result (or nil if something +/* Evaluate an expression and return the result (or nil if something went wrong). Used to evaluate dynamic parts of menu items. */ Lisp_Object menu_item_eval_property (sexpr) @@ -6856,7 +7139,7 @@ parse_menu_item (item, notreal, inmenubar) for (i = ITEM_PROPERTY_DEF; i < ITEM_PROPERTY_ENABLE; i++) AREF (item_properties, i) = Qnil; AREF (item_properties, ITEM_PROPERTY_ENABLE) = Qt; - + /* Save the item here to protect it from GC. */ AREF (item_properties, ITEM_PROPERTY_ITEM) = item; @@ -6876,7 +7159,7 @@ parse_menu_item (item, notreal, inmenubar) start = item; item = XCDR (item); } - + /* Maybe key binding cache. */ if (CONSP (item) && CONSP (XCAR (item)) && (NILP (XCAR (XCAR (item))) @@ -6885,7 +7168,7 @@ parse_menu_item (item, notreal, inmenubar) cachelist = XCAR (item); item = XCDR (item); } - + /* This is the real definition--the function to run. */ AREF (item_properties, ITEM_PROPERTY_DEF) = item; @@ -6981,7 +7264,7 @@ parse_menu_item (item, notreal, inmenubar) return 0; AREF (item_properties, ITEM_PROPERTY_NAME) = item_string; } - + /* If got a filter apply it on definition. */ def = AREF (item_properties, ITEM_PROPERTY_DEF); if (!NILP (filter)) @@ -7009,7 +7292,7 @@ parse_menu_item (item, notreal, inmenubar) is OK in a submenu but not in the menubar. */ if (NILP (def)) return (inmenubar ? 0 : 1); - + /* See if this is a separate pane or a submenu. */ def = AREF (item_properties, ITEM_PROPERTY_DEF); tem = get_keymap (def, 0, 1); @@ -7020,7 +7303,7 @@ parse_menu_item (item, notreal, inmenubar) AREF (item_properties, ITEM_PROPERTY_DEF) = tem; return 1; } - + /* At the top level in the menu bar, do likewise for commands also. The menu bar does not display equivalent key bindings anyway. ITEM_PROPERTY_DEF is already set up properly. */ @@ -7047,7 +7330,7 @@ parse_menu_item (item, notreal, inmenubar) XSETCAR (cachelist, Qt); } } - + tem = XCAR (cachelist); if (!EQ (tem, Qt)) { @@ -7155,7 +7438,7 @@ parse_menu_item (item, notreal, inmenubar) } */ - /* Handle radio buttons or toggle boxes. */ + /* Handle radio buttons or toggle boxes. */ tem = AREF (item_properties, ITEM_PROPERTY_SELECTED); if (!NILP (tem)) AREF (item_properties, ITEM_PROPERTY_SELECTED) @@ -7222,13 +7505,13 @@ tool_bar_items (reuse, nitems) avoids risk of specpdl overflow. */ oquit = Vinhibit_quit; Vinhibit_quit = Qt; - + /* Initialize tool_bar_items_vector and protect it from GC. */ init_tool_bar_items (reuse); /* Build list of keymaps in maps. Set nmaps to the number of maps to process. */ - + /* Should overriding-terminal-local-map and overriding-local-map apply? */ if (!NILP (Voverriding_local_map_menu_flag)) { @@ -7273,7 +7556,7 @@ tool_bar_items (reuse, nitems) if (CONSP (keymap)) { Lisp_Object tail; - + /* KEYMAP is a list `(keymap (KEY . BINDING) ...)'. */ for (tail = keymap; CONSP (tail); tail = XCDR (tail)) { @@ -7311,7 +7594,7 @@ process_tool_bar_item (key, def) for (i = 0; i < ntool_bar_items; i += TOOL_BAR_ITEM_NSLOTS) { Lisp_Object *v = XVECTOR (tool_bar_items_vector)->contents + i; - + if (EQ (key, v[TOOL_BAR_ITEM_KEY])) { if (ntool_bar_items > i + TOOL_BAR_ITEM_NSLOTS) @@ -7337,41 +7620,41 @@ process_tool_bar_item (key, def) invalid. ITEM is a list `(menu-item CAPTION BINDING PROPS...)'. - + CAPTION is the caption of the item, If it's not a string, it is evaluated to get a string. - + BINDING is the tool bar item's binding. Tool-bar items with keymaps as binding are currently ignored. The following properties are recognized: - `:enable FORM'. - + FORM is evaluated and specifies whether the tool bar item is enabled or disabled. - + - `:visible FORM' - + FORM is evaluated and specifies whether the tool bar item is visible. - + - `:filter FUNCTION' FUNCTION is invoked with one parameter `(quote BINDING)'. Its result is stored as the new binding. - + - `:button (TYPE SELECTED)' TYPE must be one of `:radio' or `:toggle'. SELECTED is evaluated and specifies whether the button is selected (pressed) or not. - + - `:image IMAGES' IMAGES is either a single image specification or a vector of four image specifications. See enum tool_bar_item_images. - + - `:help HELP-STRING'. - + Gives a help string to display for the tool bar item. */ static int @@ -7405,11 +7688,11 @@ parse_tool_bar_item (key, item) else tool_bar_item_properties = Fmake_vector (make_number (TOOL_BAR_ITEM_NSLOTS), Qnil); - + /* Set defaults. */ PROP (TOOL_BAR_ITEM_KEY) = key; PROP (TOOL_BAR_ITEM_ENABLED_P) = Qt; - + /* Get the caption of the item. If the caption is not a string, evaluate it to get a string. If we don't get a string, skip this item. */ @@ -7496,13 +7779,13 @@ parse_tool_bar_item (key, item) PROP (TOOL_BAR_ITEM_ENABLED_P) = menu_item_eval_property (PROP (TOOL_BAR_ITEM_ENABLED_P)); - /* Handle radio buttons or toggle boxes. */ + /* Handle radio buttons or toggle boxes. */ if (!NILP (PROP (TOOL_BAR_ITEM_SELECTED_P))) PROP (TOOL_BAR_ITEM_SELECTED_P) = menu_item_eval_property (PROP (TOOL_BAR_ITEM_SELECTED_P)); return 1; - + #undef PROP } @@ -7529,7 +7812,7 @@ static void append_tool_bar_item () { Lisp_Object *to, *from; - + /* Enlarge tool_bar_items_vector if necessary. */ if (ntool_bar_items + TOOL_BAR_ITEM_NSLOTS >= XVECTOR (tool_bar_items_vector)->size) @@ -7584,7 +7867,7 @@ read_char_x_menu_prompt (nmaps, maps, prev_event, used_mouse_menu) int *used_mouse_menu; { int mapno; - register Lisp_Object name; + register Lisp_Object name = Qnil; if (used_mouse_menu) *used_mouse_menu = 0; @@ -7686,7 +7969,8 @@ read_char_minibuf_menu_prompt (commandflag, nmaps, maps) int mapno; register Lisp_Object name; int nlength; - int width = FRAME_WIDTH (SELECTED_FRAME ()) - 4; + /* FIXME: Use the minibuffer's frame width. */ + int width = FRAME_COLS (SELECTED_FRAME ()) - 4; int idx = -1; int nobindings = 1; Lisp_Object rest, vector; @@ -7830,7 +8114,7 @@ read_char_minibuf_menu_prompt (commandflag, nmaps, maps) tem = build_string (NILP (selected) ? "[X] " : "[ ] "); s = concat2 (tem, s); } - + /* If we have room for the prompt string, add it to this line. If this is the first on the line, always add it. */ @@ -7893,7 +8177,7 @@ read_char_minibuf_menu_prompt (commandflag, nmaps, maps) } /* Prompt with that and read response. */ - message2_nolog (menu, strlen (menu), + message2_nolog (menu, strlen (menu), ! NILP (current_buffer->enable_multibyte_characters)); /* Make believe its not a keyboard macro in case the help char @@ -7948,20 +8232,13 @@ follow_key (key, nmaps, current, defs, next) int nmaps; { int i, first_binding; - int did_meta = 0; first_binding = nmaps; for (i = nmaps - 1; i >= 0; i--) { if (! NILP (current[i])) { - Lisp_Object map; - if (did_meta) - map = defs[i]; - else - map = current[i]; - - defs[i] = access_keymap (map, key, 1, 0, 1); + defs[i] = access_keymap (current[i], key, 1, 0, 1); if (! NILP (defs[i])) first_binding = i; } @@ -7977,6 +8254,128 @@ follow_key (key, nmaps, current, defs, next) return first_binding; } +/* Structure used to keep track of partial application of key remapping + such as Vfunction_key_map and Vkey_translation_map. */ +typedef struct keyremap +{ + Lisp_Object map, parent; + int start, end; +} keyremap; + +/* Lookup KEY in MAP. + MAP is a keymap mapping keys to key vectors or functions. + If the mapping is a function and DO_FUNCTION is non-zero, then + the function is called with PROMPT as parameter and its return + value is used as the return value of this function (after checking + that it is indeed a vector). */ + +static Lisp_Object +access_keymap_keyremap (map, key, prompt, do_funcall) + Lisp_Object map, key, prompt; + int do_funcall; +{ + Lisp_Object next; + + next = access_keymap (map, key, 1, 0, 1); + + /* Handle symbol with autoload definition. */ + if (SYMBOLP (next) && !NILP (Ffboundp (next)) + && CONSP (XSYMBOL (next)->function) + && EQ (XCAR (XSYMBOL (next)->function), Qautoload)) + do_autoload (XSYMBOL (next)->function, next); + + /* Handle a symbol whose function definition is a keymap + or an array. */ + if (SYMBOLP (next) && !NILP (Ffboundp (next)) + && (!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. */ + if (SYMBOLP (next) && !NILP (Ffboundp (next)) && do_funcall) + { + Lisp_Object tem; + tem = next; + + next = call1 (next, prompt); + /* If the function returned something invalid, + barf--don't ignore it. + (To ignore it safely, we would need to gcpro a bunch of + other variables.) */ + if (! (VECTORP (next) || STRINGP (next))) + error ("Function %s returns invalid key sequence", tem); + } + return next; +} + +/* Do one step of the key remapping used for function-key-map and + key-translation-map: + KEYBUF is the buffer holding the input events. + BUFSIZE is its maximum size. + FKEY is a pointer to the keyremap structure to use. + INPUT is the index of the last element in KEYBUF. + DOIT if non-zero says that the remapping can actually take place. + DIFF is used to return the number of keys added/removed by the remapping. + PARENT is the root of the keymap. + PROMPT is the prompt to use if the remapping happens through a function. + The return value is non-zero if the remapping actually took place. */ + +static int +keyremap_step (keybuf, bufsize, fkey, input, doit, diff, prompt) + Lisp_Object *keybuf, prompt; + keyremap *fkey; + int input, doit, *diff, bufsize; +{ + Lisp_Object next, key; + + key = keybuf[fkey->end++]; + next = access_keymap_keyremap (fkey->map, key, prompt, doit); + + /* If keybuf[fkey->start..fkey->end] is bound in the + map and we're in a position to do the key remapping, replace it with + the binding and restart with fkey->start at the end. */ + if ((VECTORP (next) || STRINGP (next)) && doit) + { + int len = XFASTINT (Flength (next)); + int i; + + *diff = len - (fkey->end - fkey->start); + + if (input + *diff >= bufsize) + error ("Key sequence too long"); + + /* Shift the keys that follow fkey->end. */ + if (*diff < 0) + for (i = fkey->end; i < input; i++) + keybuf[i + *diff] = keybuf[i]; + else if (*diff > 0) + for (i = input - 1; i >= fkey->end; i--) + keybuf[i + *diff] = keybuf[i]; + /* Overwrite the old keys with the new ones. */ + for (i = 0; i < len; i++) + keybuf[fkey->start + i] + = Faref (next, make_number (i)); + + fkey->start = fkey->end += *diff; + fkey->map = fkey->parent; + + return 1; + } + + fkey->map = get_keymap (next, 0, 1); + + /* If we no longer have a bound suffix, try a new position for + fkey->start. */ + if (!CONSP (fkey->map)) + { + fkey->end = ++fkey->start; + fkey->map = fkey->parent; + } + return 0; +} + /* Read a sequence of keys that ends with a non prefix character, storing it in KEYBUF, a buffer of size BUFSIZE. Prompt with PROMPT. @@ -8064,7 +8463,7 @@ read_key_sequence (keybuf, bufsize, prompt, dont_downcase_last, defs[i] is non-nil. */ volatile int first_binding; /* Index of the first key that has no binding. - It is useless to try fkey_start larger than that. */ + It is useless to try fkey.start larger than that. */ volatile int first_unbound; /* If t < mock_input, then KEYBUF[t] should be read as the next @@ -8083,22 +8482,21 @@ read_key_sequence (keybuf, bufsize, prompt, dont_downcase_last, volatile int mock_input = 0; /* If the sequence is unbound in submaps[], then - keybuf[fkey_start..fkey_end-1] is a prefix in Vfunction_key_map, - and fkey_map is its binding. + keybuf[fkey.start..fkey.end-1] is a prefix in Vfunction_key_map, + and fkey.map is its binding. These might be > t, indicating that all function key scanning should hold off until t reaches them. We do this when we've just recognized a function key, to avoid searching for the function key's again in Vfunction_key_map. */ - volatile int fkey_start = 0, fkey_end = 0; - volatile Lisp_Object fkey_map; + volatile keyremap fkey; /* Likewise, for key_translation_map. */ - volatile int keytran_start = 0, keytran_end = 0; - volatile Lisp_Object keytran_map; + volatile keyremap keytran; - /* If we receive a ``switch-frame'' event in the middle of a key sequence, - we put it off for later. While we're reading, we keep the event here. */ + /* If we receive a `switch-frame' or `select-window' event in the middle of + a key sequence, we put it off for later. + While we're reading, we keep the event here. */ volatile Lisp_Object delayed_switch_frame; /* See the comment below... */ @@ -8129,16 +8527,11 @@ read_key_sequence (keybuf, bufsize, prompt, dont_downcase_last, last_nonmenu_event = Qnil; delayed_switch_frame = Qnil; - fkey_map = Vfunction_key_map; - keytran_map = Vkey_translation_map; - - /* If there is no function-key-map, turn off function key scanning. */ - if (!KEYMAPP (Vfunction_key_map)) - fkey_start = fkey_end = bufsize + 1; - - /* If there is no key-translation-map, turn off scanning. */ - if (!KEYMAPP (Vkey_translation_map)) - keytran_start = keytran_end = bufsize + 1; + fkey.map = fkey.parent = Vfunction_key_map; + keytran.map = keytran.parent = Vkey_translation_map; + /* If there is no translation-map, turn off scanning. */ + fkey.start = fkey.end = KEYMAPP (fkey.map) ? 0 : bufsize + 1; + keytran.start = keytran.end = KEYMAPP (keytran.map) ? 0 : bufsize + 1; if (INTERACTIVE) { @@ -8248,15 +8641,15 @@ read_key_sequence (keybuf, bufsize, prompt, dont_downcase_last, /* If the best binding for the current key sequence is a keymap, or we may be looking at a function key's escape sequence, keep on reading. */ - while ((first_binding < nmaps && ! NILP (submaps[first_binding])) - || (first_binding >= nmaps && fkey_start < t) - || (first_binding >= nmaps && keytran_start < t) + while (first_binding < nmaps + /* Keep reading as long as there's a prefix binding. */ + ? !NILP (submaps[first_binding]) /* Don't return in the middle of a possible function key sequence, if the only bindings we found were via case conversion. Thus, if ESC O a has a function-key-map translation and ESC o has a binding, don't return after ESC O, so that we can translate ESC O plus the next character. */ - ) + : (fkey.start < t || keytran.start < t)) { Lisp_Object key; int used_mouse_menu = 0; @@ -8274,10 +8667,13 @@ read_key_sequence (keybuf, bufsize, prompt, dont_downcase_last, just one key. */ volatile int echo_local_start, keys_local_start, local_first_binding; + eassert (fkey.end == t || (fkey.end > t && fkey.end <= mock_input)); + eassert (fkey.start <= fkey.end); + eassert (keytran.start <= keytran.end); /* key-translation-map is applied *after* function-key-map. */ - eassert (keytran_end <= fkey_start); + eassert (keytran.end <= fkey.start); - if (first_unbound < fkey_start && first_unbound < keytran_start) + if (first_unbound < fkey.start && first_unbound < keytran.start) { /* The prefix upto first_unbound has no binding and has no translation left to do either, so we know it's unbound. If we don't stop now, we risk staying here indefinitely @@ -8287,10 +8683,10 @@ read_key_sequence (keybuf, bufsize, prompt, dont_downcase_last, for (i = first_unbound + 1; i < t; i++) keybuf[i - first_unbound - 1] = keybuf[i]; mock_input = t - first_unbound - 1; - fkey_end = fkey_start -= first_unbound + 1; - fkey_map = Vfunction_key_map; - keytran_end = keytran_start -= first_unbound + 1; - keytran_map = Vkey_translation_map; + fkey.end = fkey.start -= first_unbound + 1; + fkey.map = fkey.parent; + keytran.end = keytran.start -= first_unbound + 1; + keytran.map = keytran.parent; goto replay_sequence; } @@ -8442,6 +8838,7 @@ read_key_sequence (keybuf, bufsize, prompt, dont_downcase_last, Vquit_flag = Qnil; if (EVENT_HAS_PARAMETERS (key) + /* Either a `switch-frame' or a `select-window' event. */ && EQ (EVENT_HEAD_KIND (EVENT_HEAD (key)), Qswitch_frame)) { /* If we're at the beginning of a key sequence, and the caller @@ -8475,6 +8872,7 @@ read_key_sequence (keybuf, bufsize, prompt, dont_downcase_last, if (EVENT_HAS_PARAMETERS (key)) { Lisp_Object kind; + Lisp_Object string; kind = EVENT_HEAD_KIND (EVENT_HEAD (key)); if (EQ (kind, Qmouse_click)) @@ -8482,7 +8880,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) @@ -8528,7 +8926,7 @@ read_key_sequence (keybuf, bufsize, prompt, dont_downcase_last, orig_keymap = get_local_map (PT, current_buffer, Qkeymap); goto replay_sequence; } - + /* For a mouse click, get the local text-property keymap of the place clicked on, rather than point. */ if (last_real_key_start == 0 @@ -8539,8 +8937,8 @@ 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) @@ -8578,7 +8976,7 @@ read_key_sequence (keybuf, bufsize, prompt, dont_downcase_last, { if (t + 1 >= bufsize) error ("Key sequence too long"); - + keybuf[t] = posn; keybuf[t + 1] = key; mock_input = t + 2; @@ -8591,11 +8989,11 @@ read_key_sequence (keybuf, bufsize, prompt, dont_downcase_last, /* If on a mode line string with a local keymap, reconsider the key sequence with that keymap. */ - if (CONSP (POSN_STRING (EVENT_START (key)))) + if (string = POSN_STRING (EVENT_START (key)), + (CONSP (string) && STRINGP (XCAR (string)))) { - Lisp_Object string, pos, map, map2; + Lisp_Object pos, map, map2; - string = POSN_STRING (EVENT_START (key)); pos = XCDR (string); string = XCAR (string); if (XINT (pos) >= 0 @@ -8614,16 +9012,16 @@ read_key_sequence (keybuf, bufsize, prompt, dont_downcase_last, goto replay_key; } - else if (CONSP (POSN_STRING (EVENT_START (key))) - && NILP (from_string)) + else if (NILP (from_string) + && (string = POSN_STRING (EVENT_START (key)), + (CONSP (string) && STRINGP (XCAR (string))))) { /* For a click on a string, i.e. overlay string or a string displayed via the `display' property, consider `local-map' and `keymap' properties of that string. */ - Lisp_Object string, pos, map, map2; + Lisp_Object pos, map, map2; - string = POSN_STRING (EVENT_START (key)); pos = XCDR (string); string = XCAR (string); if (XINT (pos) >= 0 @@ -8650,7 +9048,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)) @@ -8662,8 +9060,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; @@ -8693,15 +9091,15 @@ read_key_sequence (keybuf, bufsize, prompt, dont_downcase_last, /* This is needed for the following scenario: event 0: a down-event that gets dropped by calling replay_key. event 1: some normal prefix like C-h. - After event 0, first_unbound is 0, after event 1 fkey_start - and keytran_start are both 1, so when we see that C-h is bound, + After event 0, first_unbound is 0, after event 1 fkey.start + and keytran.start are both 1, so when we see that C-h is bound, we need to update first_unbound. */ first_unbound = max (t + 1, first_unbound); else { Lisp_Object head; - - /* Remember the position to put an upper bound on fkey_start. */ + + /* Remember the position to put an upper bound on fkey.start. */ first_unbound = min (t, first_unbound); head = EVENT_HEAD (key); @@ -8782,6 +9180,27 @@ read_key_sequence (keybuf, bufsize, prompt, dont_downcase_last, xterm-mouse-mode. -stef Isn't this just the most wonderful code ever? */ + + /* If mock_input > t + 1, the above simplification + will actually end up dropping keys on the floor. + This is probably OK for now, but even + if mock_input <= t + 1, we need to adjust fkey + and keytran. + Typical case [header-line down-mouse-N]: + mock_input = 2, t = 1, fkey.end = 1, + last_real_key_start = 0. */ + if (fkey.end > last_real_key_start) + { + fkey.end = fkey.start + = min (last_real_key_start, fkey.start); + fkey.map = fkey.parent; + if (keytran.end > last_real_key_start) + { + keytran.end = keytran.start + = min (last_real_key_start, keytran.start); + keytran.map = keytran.parent; + } + } if (t == last_real_key_start) { mock_input = 0; @@ -8840,224 +9259,62 @@ read_key_sequence (keybuf, bufsize, prompt, dont_downcase_last, to go over the sequence before we return (since we keep the invariant that keytran.end <= fkey.start). */ { - if (fkey_start < t) - (fkey_start = fkey_end = t, fkey_map = Vfunction_key_map); + if (fkey.start < t) + (fkey.start = fkey.end = t, fkey.map = fkey.parent); } else /* If the sequence is unbound, see if we can hang a function key off the end of it. */ - { - Lisp_Object fkey_next; - - /* Continue scan from fkey_end until we find a bound suffix. - If we fail, increment fkey_start and start over from there. */ - while (fkey_end < t) - { - Lisp_Object key; - - key = keybuf[fkey_end++]; - fkey_next = access_keymap (fkey_map, key, 1, 0, 1); - - /* Handle symbol with autoload definition. */ - if (SYMBOLP (fkey_next) && ! NILP (Ffboundp (fkey_next)) - && CONSP (XSYMBOL (fkey_next)->function) - && EQ (XCAR (XSYMBOL (fkey_next)->function), Qautoload)) - do_autoload (XSYMBOL (fkey_next)->function, - fkey_next); - - /* Handle a symbol whose function definition is a keymap - or an array. */ - if (SYMBOLP (fkey_next) && ! NILP (Ffboundp (fkey_next)) - && (!NILP (Farrayp (XSYMBOL (fkey_next)->function)) - || KEYMAPP (XSYMBOL (fkey_next)->function))) - fkey_next = XSYMBOL (fkey_next)->function; - -#if 0 /* I didn't turn this on, because it might cause trouble - for the mapping of return into C-m and tab into C-i. */ - /* Optionally don't map function keys into other things. - This enables the user to redefine kp- keys easily. */ - if (SYMBOLP (key) && !NILP (Vinhibit_function_key_mapping)) - fkey_next = Qnil; -#endif - - /* If the function key map gives a function, not an - array, then call the function with no args and use - its value instead. */ - if (SYMBOLP (fkey_next) && ! NILP (Ffboundp (fkey_next)) - /* If there's a binding (i.e. first_binding >= nmaps) - we don't want to apply this function-key-mapping. */ - && fkey_end == t && first_binding >= nmaps) - { - struct gcpro gcpro1, gcpro2, gcpro3; - Lisp_Object tem; - tem = fkey_next; - - GCPRO3 (fkey_map, keytran_map, delayed_switch_frame); - fkey_next = call1 (fkey_next, prompt); - UNGCPRO; - /* If the function returned something invalid, - barf--don't ignore it. - (To ignore it safely, we would need to gcpro a bunch of - other variables.) */ - if (! (VECTORP (fkey_next) || STRINGP (fkey_next))) - error ("Function in key-translation-map returns invalid key sequence"); - } - - /* If keybuf[fkey_start..fkey_end] is bound in the - function key map and it's a suffix of the current - sequence (i.e. fkey_end == t), replace it with - the binding and restart with fkey_start at the end. */ - if ((VECTORP (fkey_next) || STRINGP (fkey_next)) - /* If there's a binding (i.e. first_binding >= nmaps) - we don't want to apply this function-key-mapping. */ - && fkey_end == t && first_binding >= nmaps) - { - int len = XFASTINT (Flength (fkey_next)); - - t = fkey_start + len; - if (t >= bufsize) - error ("Key sequence too long"); - - if (VECTORP (fkey_next)) - bcopy (XVECTOR (fkey_next)->contents, - keybuf + fkey_start, - (t - fkey_start) * sizeof (keybuf[0])); - else if (STRINGP (fkey_next)) - { - int i; - - for (i = 0; i < len; i++) - XSETFASTINT (keybuf[fkey_start + i], - SREF (fkey_next, i)); - } - - mock_input = t; - fkey_start = fkey_end = t; - fkey_map = Vfunction_key_map; - - /* Do pass the results through key-translation-map. - But don't retranslate what key-translation-map - has already translated. */ - keytran_end = keytran_start; - keytran_map = Vkey_translation_map; - - goto replay_sequence; - } - - fkey_map = get_keymap (fkey_next, 0, 1); - - /* If we no longer have a bound suffix, try a new positions for - fkey_start. */ - if (!CONSP (fkey_map)) - { - fkey_end = ++fkey_start; - fkey_map = Vfunction_key_map; - } - } - } - - /* Look for this sequence in key-translation-map. */ - { - Lisp_Object keytran_next; - - /* Scan from keytran_end until we find a bound suffix. */ - while (keytran_end < fkey_start) + /* Continue scan from fkey.end until we find a bound suffix. */ + while (fkey.end < t) { - Lisp_Object key; - - key = keybuf[keytran_end++]; - keytran_next - = access_keymap (keytran_map, key, 1, 0, 1); - - /* Handle symbol with autoload definition. */ - if (SYMBOLP (keytran_next) && ! NILP (Ffboundp (keytran_next)) - && CONSP (XSYMBOL (keytran_next)->function) - && EQ (XCAR (XSYMBOL (keytran_next)->function), Qautoload)) - do_autoload (XSYMBOL (keytran_next)->function, - keytran_next); - - /* Handle a symbol whose function definition is a keymap - or an array. */ - if (SYMBOLP (keytran_next) && ! NILP (Ffboundp (keytran_next)) - && (!NILP (Farrayp (XSYMBOL (keytran_next)->function)) - || KEYMAPP (XSYMBOL (keytran_next)->function))) - keytran_next = XSYMBOL (keytran_next)->function; - - /* If the key translation map gives a function, not an - array, then call the function with one arg and use - its value instead. */ - if (SYMBOLP (keytran_next) && ! NILP (Ffboundp (keytran_next))) - { - struct gcpro gcpro1, gcpro2, gcpro3; - Lisp_Object tem; - tem = keytran_next; - - GCPRO3 (fkey_map, keytran_map, delayed_switch_frame); - keytran_next = call1 (keytran_next, prompt); - UNGCPRO; - /* If the function returned something invalid, - barf--don't ignore it. - (To ignore it safely, we would need to gcpro a bunch of - other variables.) */ - if (! (VECTORP (keytran_next) || STRINGP (keytran_next))) - error ("Function in key-translation-map returns invalid key sequence"); - } - - /* If keybuf[keytran_start..keytran_end] is bound in the - key translation map and it's a suffix of the current - sequence (i.e. keytran_end == t), replace it with - the binding and restart with keytran_start at the end. */ - if ((VECTORP (keytran_next) || STRINGP (keytran_next))) + struct gcpro gcpro1, gcpro2, gcpro3; + int done, diff; + + GCPRO3 (fkey.map, keytran.map, delayed_switch_frame); + done = keyremap_step (keybuf, bufsize, &fkey, + max (t, mock_input), + /* If there's a binding (i.e. + first_binding >= nmaps) we don't want + to apply this function-key-mapping. */ + fkey.end + 1 == t && first_binding >= nmaps, + &diff, prompt); + UNGCPRO; + if (done) { - int len = XFASTINT (Flength (keytran_next)); - int i, diff = len - (keytran_end - keytran_start); - - mock_input = max (t, mock_input); - if (mock_input + diff >= bufsize) - error ("Key sequence too long"); - - /* Shift the keys that are after keytran_end. */ - if (diff < 0) - for (i = keytran_end; i < mock_input; i++) - keybuf[i + diff] = keybuf[i]; - else if (diff > 0) - for (i = mock_input - 1; i >= keytran_end; i--) - keybuf[i + diff] = keybuf[i]; - /* Replace the keys between keytran_start and keytran_end - with those from keytran_next. */ - for (i = 0; i < len; i++) - keybuf[keytran_start + i] - = Faref (keytran_next, make_number (i)); - - mock_input += diff; - keytran_start = keytran_end += diff; - keytran_map = Vkey_translation_map; - - /* Adjust the function-key-map counters. */ - fkey_start += diff; - fkey_end += diff; - + mock_input = diff + max (t, mock_input); goto replay_sequence; } + } - keytran_map = get_keymap (keytran_next, 0, 1); + /* Look for this sequence in key-translation-map. + Scan from keytran.end until we find a bound suffix. */ + while (keytran.end < fkey.start) + { + struct gcpro gcpro1, gcpro2, gcpro3; + int done, diff; - /* If we no longer have a bound suffix, try a new positions for - keytran_start. */ - if (!CONSP (keytran_map)) - { - keytran_end = ++keytran_start; - keytran_map = Vkey_translation_map; - } - } - } + GCPRO3 (fkey.map, keytran.map, delayed_switch_frame); + done = keyremap_step (keybuf, bufsize, &keytran, max (t, mock_input), + 1, &diff, prompt); + UNGCPRO; + if (done) + { + mock_input = diff + max (t, mock_input); + /* Adjust the function-key-map counters. */ + fkey.end += diff; + fkey.start += diff; + + goto replay_sequence; + } + } /* If KEY is not defined in any of the keymaps, and cannot be part of a function key or translation, and is an upper case letter use the corresponding lower-case letter instead. */ if (first_binding >= nmaps - && fkey_start >= t && keytran_start >= t + && fkey.start >= t && keytran.start >= t && INTEGERP (key) && ((((XINT (key) & 0x3ffff) < XCHAR_TABLE (current_buffer->downcase_table)->size) @@ -9088,7 +9345,7 @@ read_key_sequence (keybuf, bufsize, prompt, dont_downcase_last, and is a shifted function key, use the corresponding unshifted function key instead. */ if (first_binding >= nmaps - && fkey_start >= t && keytran_start >= t + && fkey.start >= t && keytran.start >= t && SYMBOLP (key)) { Lisp_Object breakdown; @@ -9109,6 +9366,8 @@ read_key_sequence (keybuf, bufsize, prompt, dont_downcase_last, keybuf[t - 1] = new_key; mock_input = max (t, mock_input); + fkey.start = fkey.end = KEYMAPP (fkey.map) ? 0 : bufsize + 1; + keytran.start = keytran.end = KEYMAPP (keytran.map) ? 0 : bufsize + 1; goto replay_sequence; } @@ -9146,7 +9405,7 @@ read_key_sequence (keybuf, bufsize, prompt, dont_downcase_last, add_command_key (keybuf[t]); } - + UNGCPRO; return t; @@ -9225,6 +9484,7 @@ will read just one key sequence. */) if (NILP (continue_echo)) { this_command_key_count = 0; + this_command_key_count_reset = 0; this_single_command_key_start = 0; } @@ -9284,6 +9544,7 @@ DEFUN ("read-key-sequence-vector", Fread_key_sequence_vector, if (NILP (continue_echo)) { this_command_key_count = 0; + this_command_key_count_reset = 0; this_single_command_key_start = 0; } @@ -9477,6 +9738,7 @@ DEFUN ("execute-extended-command", Fexecute_extended_command, Sexecute_extended_ int i; this_command_key_count = 0; + this_command_key_count_reset = 0; this_single_command_key_start = 0; keys = XVECTOR (saved_keys)->contents; @@ -9537,7 +9799,7 @@ DEFUN ("execute-extended-command", Fexecute_extended_command, Sexecute_extended_ int message_p = push_message (); int count = SPECPDL_INDEX (); - record_unwind_protect (push_message_unwind, Qnil); + record_unwind_protect (pop_message_unwind, Qnil); binding = Fkey_description (bindings); newmessage @@ -9712,22 +9974,28 @@ The value is always a vector. */) DEFUN ("reset-this-command-lengths", Freset_this_command_lengths, Sreset_this_command_lengths, 0, 0, 0, - doc: /* Used for complicated reasons in `universal-argument-other-key'. + doc: /* Make the unread events replace the last command and echo. +Used in `universal-argument-other-key'. `universal-argument-other-key' rereads the event just typed. It then gets translated through `function-key-map'. -The translated event gets included in the echo area and in -the value of `this-command-keys' in addition to the raw original event. -That is not right. - -Calling this function directs the translated event to replace -the original event, so that only one version of the event actually -appears in the echo area and in the value of `this-command-keys'. */) +The translated event has to replace the real events, +both in the value of (this-command-keys) and in echoing. +To achieve this, `universal-argument-other-key' calls +`reset-this-command-lengths', which discards the record of reading +these events the first time. */) () { - before_command_restore_flag = 1; - before_command_key_count_1 = before_command_key_count; - before_command_echo_length_1 = before_command_echo_length; + this_command_key_count = before_command_key_count; + if (this_command_key_count < this_single_command_key_start) + this_single_command_key_start = this_command_key_count; + + echo_truncate (before_command_echo_length); + + /* Cause whatever we put into unread-command-events + to echo as if it were being freshly read from the keyboard. */ + this_command_key_count_reset = 1; + return Qnil; } @@ -9740,8 +10008,9 @@ KEEP-RECORD is non-nil. */) Lisp_Object keep_record; { int i; - + this_command_key_count = 0; + this_command_key_count_reset = 0; if (NILP (keep_record)) { @@ -9786,10 +10055,16 @@ If FILE is nil, close any open dribble file. */) DEFUN ("discard-input", Fdiscard_input, Sdiscard_input, 0, 0, 0, doc: /* Discard the contents of the terminal input buffer. -Also cancel any kbd macro being defined. */) +Also end any kbd macro being defined. */) () { - current_kboard->defining_kbd_macro = Qnil; + if (!NILP (current_kboard->defining_kbd_macro)) + { + /* Discard the last command from the macro. */ + Fcancel_kbd_macro_events (); + end_kbd_macro (); + } + update_mode_lines++; Vunread_command_events = Qnil; @@ -9883,25 +10158,25 @@ stuff_buffered_input (stuffstring) stuff_char (*p++); stuff_char ('\n'); } - + /* 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? */ 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); } - + input_pending = 0; #endif #endif /* BSD_SYSTEM and not BSD4_1 */ @@ -9931,7 +10206,7 @@ clear_waiting_for_input () } /* This routine is called at interrupt level in response to C-g. - + If interrupt_input, this is the handler for SIGINT. Otherwise, it is called from kbd_buffer_store_event, in handling SIGIO or SIGTINT. @@ -9943,7 +10218,7 @@ clear_waiting_for_input () eval to throw, when it gets a chance. If quit-flag is already non-nil, it stops the job right away. */ -SIGTYPE +static SIGTYPE interrupt_signal (signalnum) /* If we don't have an argument, */ int signalnum; /* some compilers complain in signal calls. */ { @@ -10021,7 +10296,7 @@ interrupt_signal (signalnum) /* If we don't have an argument, */ } while (c != '\n') c = getchar (); } - else + else { /* During GC, it must be safe to reenable quitting again. */ Vinhibit_quit = Qnil; @@ -10263,7 +10538,7 @@ delete_kboard (kb) KBOARD *kb; { KBOARD **kbp; - + for (kbp = &all_kboards; *kbp != kb; kbp = &(*kbp)->next_kboard) if (*kbp == NULL) abort (); @@ -10278,7 +10553,7 @@ delete_kboard (kb) if (current_kboard == kb) abort (); } - + wipe_kboard (kb); xfree (kb); } @@ -10355,6 +10630,11 @@ 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 @@ -10372,7 +10652,9 @@ struct event_head head_table[] = { {&Qdelete_frame, "delete-frame", &Qdelete_frame}, {&Qiconify_frame, "iconify-frame", &Qiconify_frame}, {&Qmake_frame_visible, "make-frame-visible", &Qmake_frame_visible}, - {&Qselect_window, "select-window", &Qselect_window} + /* `select-window' should be handled just like `switch-frame' + in read_key_sequence. */ + {&Qselect_window, "select-window", &Qswitch_frame} }; void @@ -10380,7 +10662,7 @@ syms_of_keyboard () { Vpre_help_message = Qnil; staticpro (&Vpre_help_message); - + Vlispy_mouse_stem = build_string ("mouse"); staticpro (&Vlispy_mouse_stem); @@ -10442,10 +10724,6 @@ syms_of_keyboard () staticpro (&Qfunction_key); Qmouse_click = intern ("mouse-click"); staticpro (&Qmouse_click); -#if defined(WINDOWSNT) || defined(MAC_OSX) - Qmouse_wheel = intern ("mouse-wheel"); - staticpro (&Qmouse_wheel); -#endif #ifdef WINDOWSNT Qlanguage_change = intern ("language-change"); staticpro (&Qlanguage_change); @@ -10455,7 +10733,7 @@ syms_of_keyboard () Qsave_session = intern ("save-session"); staticpro(&Qsave_session); - + Qusr1_signal = intern ("usr1-signal"); staticpro (&Qusr1_signal); Qusr2_signal = intern ("usr2-signal"); @@ -10560,6 +10838,8 @@ syms_of_keyboard () staticpro (&button_down_location); mouse_syms = Fmake_vector (make_number (1), Qnil); staticpro (&mouse_syms); + wheel_syms = Fmake_vector (make_number (2), Qnil); + staticpro (&wheel_syms); { int i; @@ -10594,12 +10874,8 @@ syms_of_keyboard () func_key_syms = Qnil; staticpro (&func_key_syms); -#if defined(WINDOWSNT) || defined(MAC_OSX) - mouse_wheel_syms = Qnil; - staticpro (&mouse_wheel_syms); drag_n_drop_syms = Qnil; staticpro (&drag_n_drop_syms); -#endif unread_switch_frame = Qnil; staticpro (&unread_switch_frame); @@ -10707,9 +10983,10 @@ will be in `last-command' during the following command. */); Vthis_command = Qnil; DEFVAR_LISP ("this-original-command", &Vthis_original_command, - doc: /* If non-nil, the original command bound to the current key sequence. -The value of `this-command' is the result of looking up the original -command in the active keymaps. */); + doc: /* The command bound to the current key sequence before remapping. +It equals `this-command' if the original command was not remapped through +any of the active keymaps. Otherwise, the value of `this-command' is the +result of looking up the original command in the active keymaps. */); Vthis_original_command = Qnil; DEFVAR_INT ("auto-save-interval", &auto_save_interval, @@ -10753,7 +11030,7 @@ instead of pixels. This variable is also the threshold for motion of the mouse to count as a drag. */); double_click_fuzz = 3; - + DEFVAR_BOOL ("inhibit-local-menu-bar-menus", &inhibit_local_menu_bar_menus, doc: /* *Non-nil means inhibit local map menu bar menus. */); inhibit_local_menu_bar_menus = 0; @@ -10812,7 +11089,10 @@ 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". */); +In a vector or a char-table, 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'. */); Vkeyboard_translate_table = Qnil; DEFVAR_BOOL ("cannot-suspend", &cannot_suspend, @@ -11038,8 +11318,54 @@ keys_of_keyboard () "ignore-event"); initial_define_lispy_key (Vspecial_event_map, "make-frame-visible", "ignore-event"); - initial_define_lispy_key (Vspecial_event_map, "select-window", - "handle-select-window"); + /* 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", "handle-save-session"); } + +/* Mark the pointers in the kboard objects. + Called by the Fgarbage_collector. */ +void +mark_kboards () +{ + KBOARD *kb; + Lisp_Object *p; + for (kb = all_kboards; kb; kb = kb->next_kboard) + { + if (kb->kbd_macro_buffer) + for (p = kb->kbd_macro_buffer; p < kb->kbd_macro_ptr; p++) + mark_object (*p); + mark_object (kb->Voverriding_terminal_local_map); + mark_object (kb->Vlast_command); + mark_object (kb->Vreal_last_command); + mark_object (kb->Vprefix_arg); + mark_object (kb->Vlast_prefix_arg); + mark_object (kb->kbd_queue); + mark_object (kb->defining_kbd_macro); + mark_object (kb->Vlast_kbd_macro); + mark_object (kb->Vsystem_key_alist); + mark_object (kb->system_key_syms); + mark_object (kb->Vdefault_minibuffer_frame); + mark_object (kb->echo_string); + } + { + struct input_event *event; + for (event = kbd_fetch_ptr; event != kbd_store_ptr; event++) + { + if (event == kbd_buffer + KBD_BUFFER_SIZE) + event = kbd_buffer; + mark_object (event->x); + mark_object (event->y); + mark_object (event->frame_or_window); + mark_object (event->arg); + } + } +} + +/* arch-tag: 774e34d7-6d31-42f3-8397-e079a4e4c9ca + (do not change this comment) */