Commit 284f4730 authored by Jim Blandy's avatar Jim Blandy
Browse files

Initial revision

parent 6bbbd9b0
/* Keyboard and mouse input; editor command loop.
Copyright (C) 1985, 1986, 1987, 1988, 1989 Free Software Foundation, Inc.
This file is part of GNU Emacs.
GNU Emacs is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 1, or (at your option)
any later version.
GNU Emacs is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with GNU Emacs; see the file COPYING. If not, write to
the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
/* Allow config.h to undefine symbols found here. */
#include <signal.h>
#include "config.h"
#include <stdio.h>
#undef NULL
#include "termchar.h"
#include "termopts.h"
#include "lisp.h"
#include "termhooks.h"
#include "macros.h"
#include "screen.h"
#include "window.h"
#include "commands.h"
#include "buffer.h"
#include "disptab.h"
#include "keyboard.h"
#include <setjmp.h>
#include <errno.h>
#include "emacssignal.h"
extern int errno;
/* Get FIONREAD, if it is available. */
#ifdef USG
#include <termio.h>
#include <fcntl.h>
#else /* not USG */
#ifndef VMS
#include <sys/ioctl.h>
#endif /* not VMS */
#endif /* not USG */
/* UNIPLUS systems may have FIONREAD. */
#ifdef UNIPLUS
#include <sys.ioctl.h>
#endif
#ifdef HAVE_X_WINDOWS
extern Lisp_Object Vmouse_grabbed;
/* Make all keyboard buffers much bigger when using X windows. */
#define KBD_BUFFER_SIZE 4096
#else /* No X-windows, character input */
#define KBD_BUFFER_SIZE 256
#endif /* No X-windows */
/* Following definition copied from eval.c */
struct backtrace
{
struct backtrace *next;
Lisp_Object *function;
Lisp_Object *args; /* Points to vector of args. */
int nargs; /* length of vector. If nargs is UNEVALLED,
args points to slot holding list of
unevalled args */
char evalargs;
};
/* Non-nil disable property on a command means
do not execute it; call disabled-command-hook's value instead. */
Lisp_Object Qdisabled, Vdisabled_command_hook;
#define NUM_RECENT_KEYS (100)
int recent_keys_index; /* Index for storing next element into recent_keys */
int total_keys; /* Total number of elements stored into recent_keys */
Lisp_Object recent_keys[NUM_RECENT_KEYS]; /* Holds last 100 keystrokes */
/* Buffer holding the key that invoked the current command. */
Lisp_Object *this_command_keys;
int this_command_key_count; /* Size in use. */
int this_command_keys_size; /* Size allocated. */
extern int minbuf_level;
extern struct backtrace *backtrace_list;
/* Nonzero means do menu prompting. */
static int menu_prompting;
/* Character to see next line of menu prompt. */
static Lisp_Object menu_prompt_more_char;
/* For longjmp to where kbd input is being done. */
static jmp_buf getcjmp;
/* True while doing kbd input. */
int waiting_for_input;
/* True while displaying for echoing. Delays C-g throwing. */
static int echoing;
/* Nonzero means C-G should cause immediate error-signal. */
int immediate_quit;
/* Character to recognize as the help char. */
Lisp_Object help_char;
/* Form to execute when help char is typed. */
Lisp_Object Vhelp_form;
/* Character that causes a quit. Normally C-g.
If we are running on an ordinary terminal, this must be an ordinary
ASCII char, since we want to make it our interrupt character.
If we are not running on an ordinary terminal, it still needs to be
an ordinary ASCII char. This character needs to be recognized in
the input interrupt handler. At this point, the keystroke is
represented as a struct input_event, while the desired quit
character is specified as a lispy event. The mapping from struct
input_events to lispy events cannot run in an interrupt handler,
and the reverse mapping is difficult for anything but ASCII
keystrokes.
FOR THESE ELABORATE AND UNSATISFYING REASONS, quit_char must be an
ASCII character. */
int quit_char;
extern Lisp_Object current_global_map;
extern int minibuf_level;
/* Current depth in recursive edits. */
int command_loop_level;
/* Total number of times command_loop has read a key sequence. */
int num_input_keys;
/* Last input character read as a command. */
Lisp_Object last_command_char;
/* Last input character read for any purpose. */
Lisp_Object last_input_char;
/* If not Qnil, an object to be read as the next command input. */
Lisp_Object unread_command_char;
/* Char to use as prefix when a meta character is typed in.
This is bound on entry to minibuffer in case ESC is changed there. */
Lisp_Object meta_prefix_char;
/* Last size recorded for a current buffer which is not a minibuffer. */
static int last_non_minibuf_size;
/* Number of idle seconds before an auto-save. */
static Lisp_Object Vauto_save_timeout;
/* Total number of times read_char has returned. */
int num_input_chars;
/* Auto-save automatically when this many characters have been typed
since the last time. */
static int auto_save_interval;
/* Value of num_input_chars as of last auto save. */
int last_auto_save;
/* Last command executed by the editor command loop, not counting
commands that set the prefix argument. */
Lisp_Object last_command;
/* The command being executed by the command loop.
Commands may set this, and the value set will be copied into last_command
instead of the actual command. */
Lisp_Object this_command;
#ifndef HAVE_X11
/* Window of last mouse click. */
extern Lisp_Object Vmouse_window;
/* List containing details of last mouse click. */
extern Lisp_Object Vmouse_event;
#endif /* defined HAVE_X11 */
/* Hook to call on each mouse event after running its definition. */
Lisp_Object Vmouse_event_function;
/* Hook to call when mouse leaves screen. */
Lisp_Object Vmouse_left_hook;
/* Hook to call when a screen is mapped. */
Lisp_Object Vmap_screen_hook;
/* Hook to call when a screen is unmapped. */
Lisp_Object Vunmap_screen_hook;
/* Handler for non-grabbed (no keys depressed) mouse motion. */
Lisp_Object Vmouse_motion_handler;
/* The screen in which the last input event occurred.
command_loop_1 will select this screen before running the
command bound to an event sequence, and read_key_sequence will
toss the existing prefix if the user starts typing at a
new screen. */
Lisp_Object Vlast_event_screen;
/* X Windows wants this for selection ownership. */
unsigned long last_event_timestamp;
Lisp_Object Qself_insert_command;
Lisp_Object Qforward_char;
Lisp_Object Qbackward_char;
/* read_key_sequence stores here the command definition of the
key sequence that it reads. */
Lisp_Object read_key_sequence_cmd;
/* Form to evaluate (if non-nil) when Emacs is started. */
Lisp_Object Vtop_level;
/* User-supplied string to translate input characters through. */
Lisp_Object Vkeyboard_translate_table;
/* Keymap mapping ASCII function key sequences onto their preferred forms. */
extern Lisp_Object Vfunction_key_map;
/* File in which we write all commands we read. */
FILE *dribble;
/* Nonzero if input is available. */
int input_pending;
/* Nonzero if should obey 0200 bit in input chars as "Meta". */
int meta_key;
extern char *pending_malloc_warning;
/* Circular buffer for pre-read keyboard input. */
static struct input_event kbd_buffer[KBD_BUFFER_SIZE];
/* 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 the
next available char is in kbd_buffer[0]. */
static struct input_event *kbd_fetch_ptr;
/* Pointer to next place to store character in kbd_buffer. This
may be kbd_buffer + KBD_BUFFER_SIZE, meaning that the next
character should go in kbd_buffer[0]. */
static struct input_event *kbd_store_ptr;
/* The above pair of variables forms a "queue empty" flag. When we
enqueue a non-hook event, we increment kbd_write_count. When we
dequeue a non-hook event, we increment kbd_read_count. We say that
there is input available iff the two counters are equal.
Why not just have a flag set and cleared by the enqueuing and
dequeuing functions? Such a flag could be screwed up by interrupts
at inopportune times. */
/* If this flag is non-zero, mouse movement events will appear in the
input stream. If is zero, mouse movement will be ignored. */
int do_mouse_tracking;
/* The window system handling code should set this if the mouse has
moved since the last call to the mouse_position_hook. Calling that
hook should clear this. Code assumes that if this is set, it can
call mouse_position_hook to get the promised position, so don't set
it unless you're prepared to substantiate the claim! */
int mouse_moved;
/* True iff there is an event in kbd_buffer, or if mouse tracking is
enabled and there is a new mouse position in the mouse movement
buffer. Note that if this is false, that doesn't mean that there
is readable input; all the events in the queue might be button-up
events, and do_mouse_tracking might be off. */
#define EVENT_QUEUES_EMPTY \
((kbd_fetch_ptr == kbd_store_ptr) && (!do_mouse_tracking || !mouse_moved))
/* Symbols to head events. */
Lisp_Object Qmouse_movement;
Lisp_Object Qvscrollbar_part;
Lisp_Object Qvslider_part;
Lisp_Object Qvthumbup_part;
Lisp_Object Qvthumbdown_part;
Lisp_Object Qhscrollbar_part;
Lisp_Object Qhslider_part;
Lisp_Object Qhthumbleft_part;
Lisp_Object Qhthumbright_part;
/* Symbols to denote kinds of events. */
Lisp_Object Qfunction_key;
Lisp_Object Qmouse_click;
/* Lisp_Object Qmouse_movement; - also an event header */
Lisp_Object Qscrollbar_click;
/* Properties of event headers. */
Lisp_Object Qevent_kind;
Lisp_Object Qevent_unmodified;
/* Symbols to use for non-text mouse positions. */
Lisp_Object Qmode_line;
Lisp_Object Qvertical_split;
/* Address (if not 0) of word to zero out if a SIGIO interrupt happens. */
long *input_available_clear_word;
/* Nonzero means use SIGIO interrupts; zero means use CBREAK mode.
Default is 1 if INTERRUPT_INPUT is defined. */
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;
#ifndef BSD4_1
#define sigfree() sigsetmask (SIGEMPTYMASK)
#define sigholdx(sig) sigsetmask (sigmask (sig))
#define sigblockx(sig) sigblock (sigmask (sig))
#define sigunblockx(sig) sigblock (SIGEMPTYMASK)
#define sigpausex(sig) sigpause (0)
#endif /* not BSD4_1 */
#ifdef BSD4_1
#define SIGIO SIGTINT
/* sigfree and sigholdx are in sysdep.c */
#define sigblockx(sig) sighold (sig)
#define sigunblockx(sig) sigrelse (sig)
#define sigpausex(sig) sigpause (sig)
#endif /* BSD4_1 */
/* Allow m- file to inhibit use of FIONREAD. */
#ifdef BROKEN_FIONREAD
#undef FIONREAD
#endif
/* We are unable to use interrupts if FIONREAD is not available,
so flush SIGIO so we won't try. */
#ifndef FIONREAD
#ifdef SIGIO
#undef SIGIO
#endif
#endif
/* If we support X Windows, and won't get an interrupt when input
arrives from the server, poll periodically so we can detect C-g. */
#ifdef HAVE_X_WINDOWS
#ifndef SIGIO
#define POLL_FOR_INPUT
#endif
#endif
/* Global variable declarations. */
/* Function for init_keyboard to call with no args (if nonzero). */
void (*keyboard_init_hook) ();
static int read_avail_input ();
static void get_input_pending ();
/* > 0 if we are to echo keystrokes. */
static int echo_keystrokes;
/* Nonzero means echo each character as typed. */
static int immediate_echo;
/* The text we're echoing in the modeline - partial key sequences,
usually. '\0'-terminated. */
static char echobuf[100];
/* Where to append more text to echobuf if we want to. */
static char *echoptr;
#define min(a,b) ((a)<(b)?(a):(b))
#define max(a,b) ((a)>(b)?(a):(b))
/* Install the string STR as the beginning of the string of echoing,
so that it serves as a prompt for the next character.
Also start echoing. */
echo_prompt (str)
char *str;
{
int len = strlen (str);
if (len > sizeof echobuf - 4)
len = sizeof echobuf - 4;
bcopy (str, echobuf, len + 1);
echoptr = echobuf + len;
echo ();
}
/* Add C to the echo string, if echoing is going on.
C can be a character, which is printed prettily ("M-C-x" and all that
jazz), or a symbol, whose name is printed. */
echo_char (c)
Lisp_Object c;
{
extern char *push_key_description ();
if (immediate_echo)
{
char *ptr = echoptr;
if (ptr != echobuf)
*ptr++ = ' ';
/* If someone has passed us a composite event, use its head symbol. */
if (EVENT_HAS_PARAMETERS (c))
c = EVENT_HEAD (c);
if (XTYPE (c) == Lisp_Int)
{
if (ptr - echobuf > sizeof echobuf - 6)
return;
ptr = push_key_description (c, ptr);
}
else if (XTYPE (c) == Lisp_Symbol)
{
struct Lisp_String *name = XSYMBOL (c)->name;
if (((ptr - echobuf) + name->size + 4) > sizeof echobuf)
return;
bcopy (name->data, ptr, name->size);
ptr += name->size;
}
if (echoptr == echobuf && c == help_char)
{
strcpy (ptr, " (Type ? for further options)");
ptr += strlen (ptr);
}
*ptr = 0;
echoptr = ptr;
echo ();
}
}
/* Temporarily add a dash to the end of the echo string if it's not
empty, so that it serves as a mini-prompt for the very next character. */
echo_dash ()
{
if (!immediate_echo && echoptr == echobuf)
return;
/* Put a dash at the end of the buffer temporarily,
but make it go away when the next character is added. */
echoptr[0] = '-';
echoptr[1] = 0;
echo ();
}
/* Display the current echo string, and begin echoing if not already
doing so. */
echo ()
{
if (!immediate_echo)
{
int i;
immediate_echo = 1;
for (i = 0; i < this_command_key_count; i++)
echo_char (this_command_keys[i]);
echo_dash ();
}
echoing = 1;
message1 (echobuf);
echoing = 0;
if (waiting_for_input && !NILP (Vquit_flag))
quit_throw_to_read_char ();
}
/* Turn off echoing, for the start of a new command. */
cancel_echoing ()
{
immediate_echo = 0;
echoptr = echobuf;
}
/* Return the length of the current echo string. */
static int
echo_length ()
{
return echoptr - echobuf;
}
/* Truncate the current echo message to its first LEN chars.
This and echo_char get used by read_key_sequence when the user
switches screens while entering a key sequence. */
static void
echo_truncate (len)
int len;
{
echobuf[len] = '\0';
echoptr = echobuf + strlen (echobuf);
}
/* Functions for manipulating this_command_keys. */
static void
add_command_key (key)
Lisp_Object key;
{
if (this_command_key_count == this_command_keys_size)
{
this_command_keys_size *= 2;
this_command_keys
= (Lisp_Object *) xrealloc (this_command_keys,
(this_command_keys_size
* sizeof (Lisp_Object)));
}
this_command_keys[this_command_key_count++] = key;
}
Lisp_Object
recursive_edit_1 ()
{
int count = specpdl_ptr - specpdl;
Lisp_Object val;
if (command_loop_level > 0)
{
specbind (Qstandard_output, Qt);
specbind (Qstandard_input, Qt);
}
val = command_loop ();
if (EQ (val, Qt))
Fsignal (Qquit, Qnil);
unbind_to (count);
return Qnil;
}
/* When an auto-save happens, record the "time", and don't do again soon. */
record_auto_save ()
{
last_auto_save = num_input_chars;
}
Lisp_Object recursive_edit_unwind (), command_loop ();
DEFUN ("recursive-edit", Frecursive_edit, Srecursive_edit, 0, 0, "",
"Invoke the editor command loop recursively.\n\
To get out of the recursive edit, a command can do `(throw 'exit nil)';\n\
that tells this function to return.\n\
Alternately, `(throw 'exit t)' makes this function signal an error.\n\
This function is called by the editor initialization to begin editing.")
()
{
int count = specpdl_ptr - specpdl;
Lisp_Object val;
command_loop_level++;
update_mode_lines = 1;
record_unwind_protect (recursive_edit_unwind,
(command_loop_level
&& current_buffer != XBUFFER (XWINDOW (selected_window)->buffer))
? Fcurrent_buffer ()
: Qnil);
recursive_edit_1 ();
return unbind_to (count, Qnil);
}
Lisp_Object
recursive_edit_unwind (buffer)
Lisp_Object buffer;
{
if (!NILP (buffer))
Fset_buffer (buffer);
command_loop_level--;
update_mode_lines = 1;
return Qnil;
}
Lisp_Object
cmd_error (data)
Lisp_Object data;
{
Lisp_Object errmsg, tail, errname, file_error;
Lisp_Object stream;
struct gcpro gcpro1;
int i;
Vquit_flag = Qnil;
Vinhibit_quit = Qt;
Vstandard_output = Qt;
Vstandard_input = Qt;
Vexecuting_macro = Qnil;
echo_area_glyphs = 0;
/* If the window system or terminal screen hasn't been initialized
yet, or we're not interactive, it's best to dump this message out
to stderr and exit. */
if (! SCREEN_MESSAGE_BUF (selected_screen)
|| noninteractive)
stream = Qexternal_debugging_output;
else
{
Fdiscard_input ();
bitch_at_user ();
stream = Qt;
}
errname = Fcar (data);
if (EQ (errname, Qerror))
{
data = Fcdr (data);
if (!CONSP (data)) data = Qnil;
errmsg = Fcar (data);
file_error = Qnil;
}
else
{
errmsg = Fget (errname, Qerror_message);
file_error = Fmemq (Qfile_error,
Fget (errname, Qerror_conditions));
}
/* Print an error message including the data items.
This is done by printing it into a scratch buffer
and then making a copy of the text in the buffer. */
if (!CONSP (data)) data = Qnil;
tail = Fcdr (data);
GCPRO1 (tail);
/* For file-error, make error message by concatenating
all the data items. They are all strings. */
if (!NILP (file_error) && !NILP (tail))
errmsg = XCONS (tail)->car, tail = XCONS (tail)->cdr;
if (XTYPE (errmsg) == Lisp_String)
Fprinc (errmsg, stream);
else
write_string_1 ("peculiar error", -1, stream);
for (i = 0; CONSP (tail); tail = Fcdr (tail), i++)
{
write_string_1 (i ? ", " : ": ", 2, stream);