X-Git-Url: http://git.hcoop.net/bpt/emacs.git/blobdiff_plain/9628b8878f46b2b7eeeb4f272d20f2e64de19f4a..da8e11156a5a22f6e4cdab41b4b797aaee10bd6e:/src/keyboard.c diff --git a/src/keyboard.c b/src/keyboard.c index 069c605dc6..b6f1dfa071 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,03 + 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. @@ -23,13 +23,12 @@ Boston, MA 02111-1307, USA. */ #include #include #include "lisp.h" -#include "systty.h" /* This must be included befor termchar.h. */ #include "termchar.h" #include "termopts.h" +#include "frame.h" #include "termhooks.h" #include "macros.h" #include "keyboard.h" -#include "frame.h" #include "window.h" #include "commands.h" #include "buffer.h" @@ -461,11 +460,6 @@ FILE *dribble; /* Nonzero if input is available. */ int input_pending; -/* 1 if should obey 0200 bit in input chars as "Meta", 2 if should - keep 0200 bit in input chars. 0 to ignore the 0200 bit. */ - -int meta_key; - /* Non-zero means force key bindings update in parse_menu_item. */ int update_menu_bindings; @@ -476,36 +470,6 @@ extern char *pending_malloc_warning; static struct input_event kbd_buffer[KBD_BUFFER_SIZE]; -/* Vector to GCPRO the Lisp objects referenced from kbd_buffer. - - The interrupt-level event handlers will never enqueue an event on a - frame which is not in Vframe_list, and once an event is dequeued, - internal_last_event_frame or the event itself points to the frame. - So that's all fine. - - But while the event is sitting in the queue, it's completely - unprotected. Suppose the user types one command which will run for - a while and then delete a frame, and then types another event at - the frame that will be deleted, before the command gets around to - it. Suppose there are no references to this frame elsewhere in - Emacs, and a GC occurs before the second event is dequeued. Now we - have an event referring to a freed frame, which will crash Emacs - when it is dequeued. - - Similar things happen when an event on a scroll bar is enqueued; the - window may be deleted while the event is in the queue. - - So, we use this vector to protect the Lisp_Objects in the event - queue. That way, they'll be dequeued as dead frames or windows, - but still valid Lisp objects. - - If kbd_buffer[i].kind != NO_EVENT, then - - AREF (kbd_buffer_gcpro, 2 * i) == kbd_buffer[i].frame_or_window. - AREF (kbd_buffer_gcpro, 2 * i + 1) == kbd_buffer[i].arg. */ - -static Lisp_Object kbd_buffer_gcpro; - /* Pointer to next available character in kbd_buffer. If kbd_fetch_ptr == kbd_store_ptr, the buffer is empty. This may be kbd_buffer + KBD_BUFFER_SIZE, meaning that the @@ -584,7 +548,7 @@ Lisp_Object Qvertical_scroll_bar; Lisp_Object Qmenu_bar; extern Lisp_Object Qleft_margin, Qright_margin; extern Lisp_Object Qleft_fringe, Qright_fringe; -extern Lisp_Object Qimage; +extern Lisp_Object QCmap; Lisp_Object recursive_edit_unwind (), command_loop (); Lisp_Object Fthis_command_keys (); @@ -622,9 +586,6 @@ int interrupt_input; /* Nonzero while interrupts are temporarily deferred during redisplay. */ int interrupts_deferred; -/* Nonzero means use ^S/^Q for flow control. */ -int flow_control; - /* Allow m- file to inhibit use of FIONREAD. */ #ifdef BROKEN_FIONREAD #undef FIONREAD @@ -701,6 +662,7 @@ static Lisp_Object apply_modifiers P_ ((int, Lisp_Object)); static void clear_event P_ ((struct input_event *)); static void any_kboard_state P_ ((void)); static SIGTYPE interrupt_signal P_ ((int signalnum)); +static void handle_interrupt P_ ((void)); /* Nonzero means don't try to suspend even if the operating system seems to support it. */ @@ -1211,9 +1173,7 @@ cmd_error_internal (data, context) if (!sf->glyphs_initialized_p /* This is the case of the frame dumped with Emacs, when we're running under a window system. */ - || (!NILP (Vwindow_system) - && !inhibit_window_system - && FRAME_TERMCAP_P (sf)) + || FRAME_INITIAL_P (sf) || noninteractive) { stream = Qexternal_debugging_output; @@ -2072,7 +2032,10 @@ void start_polling () { #ifdef POLL_FOR_INPUT - if (read_socket_hook && !interrupt_input) + /* XXX This condition was (read_socket_hook && !interrupt_input), + but read_socket_hook is not global anymore. Let's pretend that + it's always set. */ + if (!interrupt_input) { /* Turn alarm handling on unconditionally. It might have been turned off in process.c. */ @@ -2106,7 +2069,10 @@ int input_polling_used () { #ifdef POLL_FOR_INPUT - return read_socket_hook && !interrupt_input; + /* XXX This condition was (read_socket_hook && !interrupt_input), + but read_socket_hook is not global anymore. Let's pretend that + it's always set. */ + return !interrupt_input; #else return 0; #endif @@ -2118,7 +2084,10 @@ void stop_polling () { #ifdef POLL_FOR_INPUT - if (read_socket_hook && !interrupt_input) + /* XXX This condition was (read_socket_hook && !interrupt_input), + but read_socket_hook is not global anymore. Let's pretend that + it's always set. */ + if (!interrupt_input) ++poll_suppress_count; #endif } @@ -2940,13 +2909,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); @@ -3605,7 +3574,7 @@ kbd_buffer_store_event (event) } last_event_timestamp = event->timestamp; - interrupt_signal (0 /* dummy */); + handle_interrupt (); return; } @@ -3631,7 +3600,6 @@ kbd_buffer_store_event (event) Discard the event if it would fill the last slot. */ if (kbd_fetch_ptr - 1 != kbd_store_ptr) { - int idx; #if 0 /* The SELECTION_REQUEST_EVENT case looks bogus, and it's error prone to assign individual members for other events, in case @@ -3661,9 +3629,6 @@ kbd_buffer_store_event (event) *kbd_store_ptr = *event; #endif - idx = 2 * (kbd_store_ptr - kbd_buffer); - ASET (kbd_buffer_gcpro, idx, event->frame_or_window); - ASET (kbd_buffer_gcpro, idx + 1, event->arg); ++kbd_store_ptr; } } @@ -3779,9 +3744,6 @@ static INLINE void clear_event (event) struct input_event *event; { - int idx = 2 * (event - kbd_buffer); - ASET (kbd_buffer_gcpro, idx, Qnil); - ASET (kbd_buffer_gcpro, idx + 1, Qnil); event->kind = NO_EVENT; } @@ -4088,7 +4050,8 @@ kbd_buffer_get_event (kbp, used_mouse_menu) If there is no valid info, it does not store anything so x remains nil. */ x = Qnil; - (*mouse_position_hook) (&f, 0, &bar_window, &part, &x, &y, &time); + if (f && FRAME_DISPLAY (f)->mouse_position_hook) /* XXX Can f or mouse_position_hook be NULL here? */ + (*FRAME_DISPLAY (f)->mouse_position_hook) (&f, 0, &bar_window, &part, &x, &y, &time); obj = Qnil; @@ -4979,9 +4942,11 @@ make_lispy_position (f, x, y, time) { /* It's a click in window window at frame coordinates (x,y) */ struct window *w = XWINDOW (window); - Lisp_Object object = Qnil; + Lisp_Object string_info = Qnil; int textpos = -1, rx = -1, ry = -1; int dx = -1, dy = -1; + int width = -1, height = -1; + Lisp_Object object = Qnil; /* Set event coordinates to window-relative coordinates for constructing the Lisp event below. */ @@ -4997,9 +4962,10 @@ make_lispy_position (f, x, y, time) posn = part == ON_MODE_LINE ? Qmode_line : Qheader_line; rx = wx, ry = wy; - string = mode_line_string (w, &rx, &ry, &dx, &dy, part, &charpos); + string = mode_line_string (w, part, &rx, &ry, &charpos, + &object, &dx, &dy, &width, &height); if (STRINGP (string)) - object = Fcons (string, make_number (charpos)); + string_info = Fcons (string, make_number (charpos)); if (w == XWINDOW (selected_window)) textpos = PT; else @@ -5010,6 +4976,7 @@ make_lispy_position (f, x, y, time) posn = Qvertical_line; wx = -1; dx = 0; + width = 1; } else if (part == ON_LEFT_MARGIN || part == ON_RIGHT_MARGIN) { @@ -5018,9 +4985,10 @@ make_lispy_position (f, x, y, time) posn = (part == ON_LEFT_MARGIN) ? Qleft_margin : Qright_margin; rx = wx, ry = wy; - string = marginal_area_string (w, &rx, &ry, &dx, &dy, part, &charpos); + string = marginal_area_string (w, part, &rx, &ry, &charpos, + &object, &dx, &dy, &width, &height); if (STRINGP (string)) - object = Fcons (string, make_number (charpos)); + string_info = Fcons (string, make_number (charpos)); } else if (part == ON_LEFT_FRINGE || part == ON_RIGHT_FRINGE) { @@ -5039,35 +5007,60 @@ make_lispy_position (f, x, y, time) if (textpos < 0) { - Lisp_Object string; + Lisp_Object string2, object2 = Qnil; struct display_pos p; int dx2, dy2; + int width2, height2; wx = max (WINDOW_LEFT_MARGIN_WIDTH (w), wx); - buffer_posn_from_coords (w, &wx, &wy, &dx2, &dy2, &string, &p); + string2 = buffer_posn_from_coords (w, &wx, &wy, &p, + &object2, &dx2, &dy2, + &width2, &height2); textpos = CHARPOS (p.pos); if (rx < 0) rx = wx; if (ry < 0) ry = wy; if (dx < 0) dx = dx2; if (dy < 0) dy = dy2; + if (width < 0) width = width2; + if (height < 0) height = height2; if (NILP (posn)) { posn = make_number (textpos); - if (STRINGP (string)) - object = Fcons (string, - make_number (CHARPOS (p.string_pos))); - else if (CONSP (string) && EQ (XCAR (string), Qimage)) - object = string; + if (STRINGP (string2)) + string_info = Fcons (string2, + make_number (CHARPOS (p.string_pos))); } + if (NILP (object)) + object = object2; } +#ifdef HAVE_WINDOW_SYSTEM + if (IMAGEP (object)) + { + Lisp_Object image_map, hotspot; + if ((image_map = Fplist_get (XCDR (object), QCmap), + !NILP (image_map)) + && (hotspot = find_hot_spot (image_map, dx, dy), + CONSP (hotspot)) + && (hotspot = XCDR (hotspot), CONSP (hotspot))) + posn = XCAR (hotspot); + } +#endif + + /* Object info */ extra_info = Fcons (object, + Fcons (Fcons (make_number (dx), + make_number (dy)), + Fcons (Fcons (make_number (width), + make_number (height)), + Qnil))); + + /* String info */ + extra_info = Fcons (string_info, Fcons (make_number (textpos), Fcons (Fcons (make_number (rx), make_number (ry)), - Fcons (Fcons (make_number (dx), - make_number (dy)), - Qnil)))); + extra_info))); } else if (f != 0) { @@ -6460,7 +6453,7 @@ get_filtered_input_pending (addr, do_timers_now, filter_events) /* If input is being read as it arrives, and we have none, there is none. */ if (*addr > 0 || (interrupt_input && ! interrupts_deferred)) return; - + /* Try to read some input and see how much we get. */ gobble_input (0); *addr = (!NILP (Vquit_flag) @@ -6499,7 +6492,10 @@ gobble_input (expected) } else #ifdef POLL_FOR_INPUT - if (read_socket_hook && !interrupt_input && poll_suppress_count == 0) + /* XXX This condition was (read_socket_hook && !interrupt_input), + but read_socket_hook is not global anymore. Let's pretend that + it's always set. */ + if (!interrupt_input && poll_suppress_count == 0) { SIGMASKTYPE mask; mask = sigblock (sigmask (SIGALRM)); @@ -6578,174 +6574,227 @@ read_avail_input (expected) { struct input_event buf[KBD_BUFFER_SIZE]; register int i; - int nread; - + struct display *d; + int nread = 0; + 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) (buf, KBD_BUFFER_SIZE, expected); - else + d = display_list; + while (d) + { + struct display *next = d->next_display; + + if (d->read_socket_hook) + /* No need for FIONREAD or fcntl; just say don't wait. */ + nread = (*d->read_socket_hook) (d, buf, KBD_BUFFER_SIZE, expected); + + if (nread == -2) + { + /* The display device terminated; it should be closed. */ + + /* Kill Emacs if this was our last display. */ + if (! display_list->next_display) + kill (getpid (), SIGHUP); + + /* XXX Is calling delete_display safe here? It calls Fdelete_frame. */ + if (d->delete_display_hook) + (*d->delete_display_hook) (d); + else + delete_display (d); + } + else if (nread > 0) + { + /* We've got input. */ + break; + } + + d = next; + } + + /* Scan the chars for C-g and store them in kbd_buffer. */ + for (i = 0; i < nread; i++) { - /* Using KBD_BUFFER_SIZE - 1 here avoids reading more than - the kbd_buffer can really hold. That may prevent loss - of characters on some systems when input is stuffed at us. */ - unsigned char cbuf[KBD_BUFFER_SIZE - 1]; - int n_to_read; + kbd_buffer_store_event (&buf[i]); + /* Don't look at input that follows a C-g too closely. + This reduces lossage due to autorepeat on C-g. */ + if (buf[i].kind == ASCII_KEYSTROKE_EVENT + && buf[i].code == quit_char) + break; + } + + return nread; +} + +/* This is the tty way of reading available input. + Note that each terminal device has its own `struct display' object, + and so this function is called once for each individual termcap + display. The first parameter indicates which device to read from. */ + +int +tty_read_avail_input (struct display *display, + struct input_event *buf, + int numchars, int expected) +{ + /* Using KBD_BUFFER_SIZE - 1 here avoids reading more than + the kbd_buffer can really hold. That may prevent loss + of characters on some systems when input is stuffed at us. */ + unsigned char cbuf[KBD_BUFFER_SIZE - 1]; + int n_to_read, i; + struct tty_display_info *tty = display->display_info.tty; + Lisp_Object frame; + int nread = 0; + + if (display->type != output_termcap) + abort (); + + /* XXX I think the following code should be moved to separate + functions in system-dependent files. */ #ifdef WINDOWSNT - return 0; + return 0; #else /* not WINDOWSNT */ #ifdef MSDOS - n_to_read = dos_keysns (); - if (n_to_read == 0) - return 0; - - cbuf[0] = dos_keyread (); - nread = 1; - + n_to_read = dos_keysns (); + if (n_to_read == 0) + return 0; + + cbuf[0] = dos_keyread (); + nread = 1; + #else /* not MSDOS */ - struct tty_output *tty; - nread = 0; - - /* Try to read from each available tty, until one succeeds. */ - for (tty = tty_list; tty && !nread; tty = tty->next) { + if (! tty->term_initted) + return 0; - /* Determine how many characters we should *try* to read. */ + /* Determine how many characters we should *try* to read. */ #ifdef FIONREAD - /* Find out how much input is available. */ - if (ioctl (fileno (TTY_INPUT (tty)), FIONREAD, &n_to_read) < 0) - { - /* Formerly simply reported no input, but that sometimes led to - a failure of Emacs to terminate. - SIGHUP seems appropriate if we can't reach the terminal. */ - /* ??? 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. */ - if (! noninteractive) - { - if (! tty_list->next) - kill (getpid (), SIGHUP); /* This was the last terminal. */ - else - n_to_read = 0; /* XXX tty should be closed here. */ - } - else - { - n_to_read = 0; - } - } - if (n_to_read == 0) - continue; - if (n_to_read > sizeof cbuf) - n_to_read = sizeof cbuf; + /* Find out how much input is available. */ + if (ioctl (fileno (TTY_INPUT (tty)), FIONREAD, &n_to_read) < 0) + { + if (! noninteractive) + return -2; /* Close this display. */ + 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) || defined(CYGWIN) - /* Read some input if available, but don't wait. */ - n_to_read = sizeof cbuf; - fcntl (fileno (TTY_INPUT (tty)), F_SETFL, O_NDELAY); + /* Read some input if available, but don't wait. */ + n_to_read = sizeof cbuf; + fcntl (fileno (TTY_INPUT (tty)), F_SETFL, O_NDELAY); #else - you lose; + you lose; #endif #endif - - /* Now read; for one reason or another, this will not block. - NREAD is set to the number of chars read. */ - do - { - nread = emacs_read (fileno (TTY_INPUT (tty)), cbuf, n_to_read); - /* POSIX infers that processes which are not in the session leader's - process group won't get SIGHUP's at logout time. BSDI adheres to - this part standard and returns -1 from read (0) with errno==EIO - when the control tty is taken away. - Jeffrey Honig says this is generally safe. */ - if (nread == -1 && errno == EIO) - { - if (! tty_list->next) - kill (0, SIGHUP); /* This was the last terminal. */ - else - ; /* XXX tty should be closed here. */ - } + + /* Now read; for one reason or another, this will not block. + NREAD is set to the number of chars read. */ + do + { + nread = emacs_read (fileno (TTY_INPUT (tty)), cbuf, n_to_read); + /* POSIX infers that processes which are not in the session leader's + process group won't get SIGHUP's at logout time. BSDI adheres to + this part standard and returns -1 from read (0) with errno==EIO + when the control tty is taken away. + Jeffrey Honig says this is generally safe. */ + if (nread == -1 && errno == EIO) + { + return -2; /* Close this display. */ + } #if defined (AIX) && (! defined (aix386) && defined (_BSD)) - /* The kernel sometimes fails to deliver SIGHUP for ptys. - This looks incorrect, but it isn't, because _BSD causes - O_NDELAY to be defined in fcntl.h as O_NONBLOCK, - and that causes a value other than 0 when there is no input. */ - if (nread == 0) - { - if (! tty_list->next) - kill (0, SIGHUP); /* This was the last terminal. */ - else - ; /* XXX tty should be closed here. */ - } + /* The kernel sometimes fails to deliver SIGHUP for ptys. + This looks incorrect, but it isn't, because _BSD causes + O_NDELAY to be defined in fcntl.h as O_NONBLOCK, + and that causes a value other than 0 when there is no input. */ + if (nread == 0) + { + return -2; /* Close this display. */ + } #endif - } - while ( - /* We used to retry the read if it was interrupted. - But this does the wrong thing when O_NDELAY causes - an EAGAIN error. Does anybody know of a situation - where a retry is actually needed? */ + } + while ( + /* We used to retry the read if it was interrupted. + But this does the wrong thing when O_NDELAY causes + an EAGAIN error. Does anybody know of a situation + where a retry is actually needed? */ #if 0 - nread < 0 && (errno == EAGAIN + nread < 0 && (errno == EAGAIN #ifdef EFAULT - || errno == EFAULT + || errno == EFAULT #endif #ifdef EBADSLT - || errno == EBADSLT + || errno == EBADSLT #endif - ) + ) #else - 0 + 0 #endif - ); - + ); + #ifndef FIONREAD #if defined (USG) || defined (DGUX) || defined (CYGWIN) - fcntl (fileno (TTY_INPUT (tty)), F_SETFL, 0); + fcntl (fileno (TTY_INPUT (tty)), F_SETFL, 0); #endif /* USG or DGUX or CYGWIN */ #endif /* no FIONREAD */ - - } /* for each tty */ - - if (! nread) - return 0; - + + if (nread <= 0) + return nread; + #endif /* not MSDOS */ #endif /* not WINDOWSNT */ - - /* XXX Select frame corresponding to the tty. */ - - for (i = 0; i < nread; i++) - { - buf[i].kind = ASCII_KEYSTROKE_EVENT; - buf[i].modifiers = 0; - if (meta_key == 1 && (cbuf[i] & 0x80)) - buf[i].modifiers = meta_modifier; - if (meta_key != 2) - cbuf[i] &= ~0x80; - - buf[i].code = cbuf[i]; - buf[i].frame_or_window = selected_frame; - buf[i].arg = Qnil; - } - } - - /* Scan the chars for C-g and store them in kbd_buffer. */ + + /* Select the frame corresponding to the active tty. Note that the + value of selected_frame is not reliable here, redisplay tends to + temporarily change it. */ + frame = tty->top_frame; + for (i = 0; i < nread; i++) { - kbd_buffer_store_event (&buf[i]); - /* Don't look at input that follows a C-g too closely. - This reduces lossage due to autorepeat on C-g. */ - if (buf[i].kind == ASCII_KEYSTROKE_EVENT - && buf[i].code == quit_char) - break; + buf[i].kind = ASCII_KEYSTROKE_EVENT; + buf[i].modifiers = 0; + if (tty->meta_key == 1 && (cbuf[i] & 0x80)) + buf[i].modifiers = meta_modifier; + if (tty->meta_key != 2) + cbuf[i] &= ~0x80; + + buf[i].code = cbuf[i]; + buf[i].frame_or_window = frame; + buf[i].arg = Qnil; } return nread; } + #endif /* not VMS */ +void +handle_async_input () +{ +#ifdef BSD4_1 + extern int select_alarmed; +#endif + interrupt_input_pending = 0; + + while (1) + { + int nread; + nread = read_avail_input (1); + /* -1 means it's not ok to read the input now. + UNBLOCK_INPUT will read it later; now, avoid infinite loop. + 0 means there was no keyboard input available. */ + if (nread <= 0) + break; + +#ifdef BSD4_1 + select_alarmed = 1; /* Force the select emulator back to life */ +#endif + } +} + #ifdef SIGIO /* for entire page */ /* Note SIGIO has been undef'd if FIONREAD is missing. */ @@ -6755,9 +6804,6 @@ input_available_signal (signo) { /* Must preserve main program's value of errno. */ int old_errno = errno; -#ifdef BSD4_1 - extern int select_alarmed; -#endif #if defined (USG) && !defined (POSIX_SIGNALS) /* USG systems forget handlers when they are used; @@ -6772,20 +6818,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 (); @@ -6804,7 +6841,7 @@ void reinvoke_input_signal () { #ifdef SIGIO - kill (getpid (), SIGIO); + handle_async_input (); #endif } @@ -8867,7 +8904,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) @@ -8925,7 +8962,7 @@ read_key_sequence (keybuf, bufsize, prompt, dont_downcase_last, localized_local_map = 1; start = EVENT_START (key); - if (CONSP (start) && CONSP (XCDR (start))) + if (CONSP (start) && POSN_INBUFFER_P (start)) { pos = POSN_BUFFER_POSN (start); if (INTEGERP (pos) @@ -9035,7 +9072,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)) @@ -9047,8 +9084,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; @@ -9843,8 +9880,12 @@ detect_input_pending_run_timers (do_display) from an idle timer function. The symptom of the bug is that the cursor sometimes doesn't become visible until the next X event is processed. --gerd. */ - if (rif) - rif->flush_display (NULL); + { + Lisp_Object tail, frame; + FOR_EACH_FRAME (tail, frame) + if (FRAME_RIF (XFRAME (frame))) + FRAME_RIF (XFRAME (frame))->flush_display (XFRAME (frame)); + } } return input_pending; @@ -10060,7 +10101,6 @@ Also end any kbd macro being defined. */) discard_tty_input (); kbd_fetch_ptr = kbd_store_ptr; - Ffillarray (kbd_buffer_gcpro, Qnil); input_pending = 0; return Qnil; @@ -10098,12 +10138,12 @@ On such systems, Emacs starts a subshell instead of suspending. */) call1 (Vrun_hooks, intern ("suspend-hook")); GCPRO1 (stuffstring); - get_tty_size (CURTTY (), &old_width, &old_height); + get_tty_size (fileno (TTY_INPUT (CURTTY ())), &old_width, &old_height); reset_all_sys_modes (); /* sys_suspend can get an error if it tries to fork a subshell and the system resources aren't available for that. */ record_unwind_protect ((Lisp_Object (*) P_ ((Lisp_Object))) init_sys_modes, - Qnil); + (Lisp_Object)CURTTY()); /* XXX */ stuff_buffered_input (stuffstring); if (cannot_suspend) sys_subshell (); @@ -10114,7 +10154,7 @@ On such systems, Emacs starts a subshell instead of suspending. */) /* Check if terminal/window size has changed. Note that this is not useful when we are running directly with a window system; but suspend should be disabled in that case. */ - get_tty_size (CURTTY (), &width, &height); + get_tty_size (fileno (TTY_INPUT (CURTTY ())), &width, &height); if (width != old_width || height != old_height) change_frame_size (SELECTED_FRAME (), height, width, 0, 0, 0); @@ -10154,17 +10194,13 @@ stuff_buffered_input (stuffstring) 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); + clear_event (kbd_fetch_ptr); } input_pending = 0; @@ -10178,10 +10214,10 @@ set_waiting_for_input (time_to_clear) { input_available_clear_time = time_to_clear; - /* Tell interrupt_signal to throw back to read_char, */ + /* Tell handle_interrupt to throw back to read_char, */ waiting_for_input = 1; - /* If interrupt_signal was called before and buffered a C-g, + /* If handle_interrupt was called before and buffered a C-g, make it run again now, to avoid timing error. */ if (!NILP (Vquit_flag)) quit_throw_to_read_char (); @@ -10190,45 +10226,76 @@ set_waiting_for_input (time_to_clear) void clear_waiting_for_input () { - /* Tell interrupt_signal not to throw back to read_char, */ + /* Tell handle_interrupt not to throw back to read_char, */ waiting_for_input = 0; input_available_clear_time = 0; } -/* 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. +/* The SIGINT handler. - If `waiting_for_input' is non zero, then unless `echoing' is - nonzero, immediately throw back to read_char. - - Otherwise it sets the Lisp variable quit-flag not-nil. This causes - eval to throw, when it gets a chance. If quit-flag is already - non-nil, it stops the job right away. */ + If we have a frame on the controlling tty, the SIGINT was generated + by C-g, so we call handle_interrupt. Otherwise, the handler kills + Emacs. */ static SIGTYPE interrupt_signal (signalnum) /* If we don't have an argument, */ int signalnum; /* some compilers complain in signal calls. */ { - char c; /* Must preserve main program's value of errno. */ int old_errno = errno; - struct frame *sf = SELECTED_FRAME (); + struct display *display; #if defined (USG) && !defined (POSIX_SIGNALS) - if (!read_socket_hook && NILP (Vwindow_system)) + /* USG systems forget handlers when they are used; + must reestablish each time */ + signal (SIGINT, interrupt_signal); + signal (SIGQUIT, interrupt_signal); +#endif /* USG */ + + /* See if we have a display on our controlling terminal. */ + display = get_named_tty_display (NULL); + if (!display) { - /* USG systems forget handlers when they are used; - must reestablish each time */ - signal (SIGINT, interrupt_signal); - signal (SIGQUIT, interrupt_signal); + /* If there are no frames there, let's pretend that we are a + well-behaving UN*X program and quit. */ + Fkill_emacs (Qnil); } -#endif /* USG */ + else + { + /* Otherwise, the SIGINT was probably generated by C-g. */ + + /* Set internal_last_event_frame to the top frame of the + controlling tty, if we have a frame there. We disable the + interrupt key on secondary ttys, so the SIGINT must have come + from the controlling tty. */ + internal_last_event_frame = display->display_info.tty->top_frame; + + handle_interrupt (); + } + + errno = old_errno; +} + +/* This routine is called at interrupt level in response to C-g. + + It is called from the SIGINT handler or kbd_buffer_store_event. + + If `waiting_for_input' is non zero, then unless `echoing' is + nonzero, immediately throw back to read_char. + + Otherwise it sets the Lisp variable quit-flag not-nil. This causes + eval to throw, when it gets a chance. If quit-flag is already + non-nil, it stops the job right away. */ + +static void +handle_interrupt () +{ + char c; + struct frame *sf = SELECTED_FRAME (); cancel_echoing (); + /* XXX This code needs to be revised for multi-tty support. */ if (!NILP (Vquit_flag) && (FRAME_TERMCAP_P (sf) || FRAME_MSDOS_P (sf))) { @@ -10345,9 +10412,7 @@ interrupt_signal (signalnum) /* If we don't have an argument, */ } if (waiting_for_input && !echoing) - quit_throw_to_read_char (); - - errno = old_errno; + quit_throw_to_read_char (); } /* Handle a C-g by making read_char return C-g. */ @@ -10394,6 +10459,11 @@ See also `current-input-mode'. */) (interrupt, flow, meta, quit) Lisp_Object interrupt, flow, meta, quit; { + /* XXX This function needs to be revised for multi-device support. + Currently it compiles fine, but its semantics are wrong. It sets + global parameters (e.g. interrupt_input) based on only the + current frame's device. */ + if (!NILP (quit) && (!INTEGERP (quit) || XINT (quit) < 0 || XINT (quit) > 0400)) error ("set-input-mode: QUIT must be an ASCII character"); @@ -10409,7 +10479,7 @@ See also `current-input-mode'. */) #ifdef SIGIO /* Note SIGIO has been undef'd if FIONREAD is missing. */ - if (read_socket_hook) + if (FRAME_DISPLAY (SELECTED_FRAME ())->read_socket_hook) { /* When using X, don't give the user a real choice, because we haven't implemented the mechanisms to support it. */ @@ -10430,16 +10500,21 @@ See also `current-input-mode'. */) interrupt_input = 1; #endif - flow_control = !NILP (flow); - if (NILP (meta)) - meta_key = 0; - else if (EQ (meta, Qt)) - meta_key = 1; - else - meta_key = 2; + if (FRAME_TERMCAP_P (XFRAME (selected_frame))) + { + struct tty_display_info *tty = CURTTY (); + tty->flow_control = !NILP (flow); + if (NILP (meta)) + tty->meta_key = 0; + else if (EQ (meta, Qt)) + tty->meta_key = 1; + else + tty->meta_key = 2; + } + if (!NILP (quit)) /* Don't let this value be out of range. */ - quit_char = XINT (quit) & (meta_key ? 0377 : 0177); + quit_char = XINT (quit) & (NILP (meta) ? 0177 : 0377); #ifndef DOS_NT init_all_sys_modes (); @@ -10469,10 +10544,21 @@ The elements of this list correspond to the arguments of () { Lisp_Object val[4]; - + struct frame *sf = XFRAME (selected_frame); + val[0] = interrupt_input ? Qt : Qnil; - val[1] = flow_control ? Qt : Qnil; - val[2] = meta_key == 2 ? make_number (0) : meta_key == 1 ? Qt : Qnil; + if (FRAME_TERMCAP_P (sf)) + { + val[1] = FRAME_TTY (sf)->flow_control ? Qt : Qnil; + val[2] = FRAME_TTY (sf)->meta_key == 2 + ? make_number (0) + : CURTTY ()->meta_key == 1 ? Qt : Qnil; + } + else + { + val[1] = Qnil; + val[2] = Qt; + } XSETFASTINT (val[3], quit_char); return Flist (sizeof (val) / sizeof (val[0]), val); @@ -10564,7 +10650,6 @@ init_keyboard () recent_keys_index = 0; kbd_fetch_ptr = kbd_buffer; kbd_store_ptr = kbd_buffer; - kbd_buffer_gcpro = Fmake_vector (make_number (2 * KBD_BUFFER_SIZE), Qnil); #ifdef HAVE_MOUSE do_mouse_tracking = Qnil; #endif @@ -10581,8 +10666,14 @@ init_keyboard () wipe_kboard (current_kboard); init_kboard (current_kboard); - if (!noninteractive && !read_socket_hook && NILP (Vwindow_system)) + if (!noninteractive) { + /* Before multi-tty support, these handlers used to be installed + only if the current session was a tty session. Now an Emacs + session may have multiple display types, so we always handle + SIGINT. There is special code in interrupt_signal to exit + Emacs on SIGINT when there are no termcap frames on the + controlling terminal. */ signal (SIGINT, interrupt_signal); #if defined (HAVE_TERMIO) || defined (HAVE_TERMIOS) /* For systems with SysV TERMIO, C-g is set up for both SIGINT and @@ -10855,9 +10946,6 @@ syms_of_keyboard () Fset (Qextended_command_history, Qnil); staticpro (&Qextended_command_history); - kbd_buffer_gcpro = Fmake_vector (make_number (2 * KBD_BUFFER_SIZE), Qnil); - staticpro (&kbd_buffer_gcpro); - accent_key_syms = Qnil; staticpro (&accent_key_syms);