/* Keyboard and mouse input; editor command loop.
Copyright (C) 1985, 1986, 1987, 1988, 1989, 1993, 1994, 1995,
1996, 1997, 1999, 2000, 2001, 2002, 2003, 2004,
- 2005, 2006 Free Software Foundation, Inc.
+ 2005, 2006, 2007 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 2, or (at your option)
+the Free Software Foundation; either version 3, or (at your option)
any later version.
GNU Emacs is distributed in the hope that it will be useful,
/* Variables for blockinput.h: */
/* Non-zero if interrupt input is blocked right now. */
-int interrupt_input_blocked;
+volatile int interrupt_input_blocked;
/* Nonzero means an input interrupt has arrived
during the current critical section. */
#define KBD_BUFFER_SIZE 4096
#endif /* No X-windows */
-#define abs(x) ((x) >= 0 ? (x) : -(x))
-
/* Following definition copied from eval.c */
struct backtrace
do not execute it; call disabled-command-function's value instead. */
Lisp_Object Qdisabled, Qdisabled_command_function;
-#define NUM_RECENT_KEYS (100)
+#define NUM_RECENT_KEYS (300)
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; /* A vector, holding the last 100 keystrokes */
+Lisp_Object recent_keys; /* Vector holds the last NUM_RECENT_KEYS keystrokes */
/* Vector holding the key sequence that invoked the current command.
It is reused for each command, and it may be longer than the current
/* The above pair of variables forms a "queue empty" flag. When we
enqueue a non-hook event, we increment kbd_store_ptr. When we
dequeue a non-hook event, we increment kbd_fetch_ptr. We say that
- there is input available iff the two pointers are not equal.
+ there is input available if the two pointers are not 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
Lisp_Object Qselect_window;
Lisp_Object Qhelp_echo;
-#ifdef HAVE_MOUSE
+#if defined (HAVE_MOUSE) || defined (HAVE_GPM)
Lisp_Object Qmouse_fixup_help_message;
#endif
static Lisp_Object read_char_minibuf_menu_prompt P_ ((int, int,
Lisp_Object *));
static Lisp_Object make_lispy_event P_ ((struct input_event *));
-#ifdef HAVE_MOUSE
+#if defined (HAVE_MOUSE) || defined (HAVE_GPM)
static Lisp_Object make_lispy_movement P_ ((struct frame *, Lisp_Object,
enum scroll_bar_part,
Lisp_Object, Lisp_Object,
static void restore_getcjmp P_ ((jmp_buf));
static Lisp_Object apply_modifiers P_ ((int, Lisp_Object));
static void clear_event P_ ((struct input_event *));
+#ifdef MULTI_KBOARD
static Lisp_Object restore_kboard_configuration P_ ((Lisp_Object));
+#endif
static SIGTYPE interrupt_signal P_ ((int signalnum));
static void handle_interrupt P_ ((void));
static void timer_start_idle P_ ((void));
}
#endif
+#ifdef MULTI_KBOARD
static Lisp_Object
restore_kboard_configuration (was_locked)
Lisp_Object was_locked;
}
return Qnil;
}
+#endif
+
\f
/* Handle errors that are not handled at inner levels
by printing an error message and returning to the editor command loop. */
/* Use user's specified output function if any. */
if (!NILP (Vcommand_error_function))
call3 (Vcommand_error_function, data,
- build_string (context ? context : ""),
+ context ? build_string (context) : empty_unibyte_string,
Vsignaling_function);
/* If the window system or terminal frame hasn't been initialized
yet, or we're not interactive, write the message to stderr and exit. */
return Qnil;
}
\f
-#ifdef HAVE_MOUSE
+#if defined (HAVE_MOUSE) || defined (HAVE_GPM)
/* Restore mouse tracking enablement. See Ftrack_mouse for the only use
of this function. */
Within a `track-mouse' form, mouse motion generates input events that
you can read with `read-event'.
Normally, mouse motion is ignored.
-usage: (track-mouse BODY ...) */)
+usage: (track-mouse BODY...) */)
(args)
Lisp_Object args;
{
return 0;
}
-#endif /* HAVE_MOUSE */
+#endif /* HAVE_MOUSE || HAVE_GPM */
\f
/* This is the actual command reading loop,
sans error-handling encapsulation. */
}
}
-#ifdef C_ALLOCA
- alloca (0); /* Cause a garbage collection now */
- /* Since we can free the most stuff here. */
-#endif /* C_ALLOCA */
-
#if 0
/* Select the frame that the last event came from. Usually,
switch-frame events will take care of this, but if some lisp
if (SYMBOLP (cmd))
{
Lisp_Object cmd1;
- if (cmd1 = Fcommand_remapping (cmd, Qnil), !NILP (cmd1))
+ if (cmd1 = Fcommand_remapping (cmd, Qnil, Qnil), !NILP (cmd1))
cmd = cmd1;
}
return;
}
-#ifdef HAVE_MOUSE
+#if defined (HAVE_MOUSE) || defined (HAVE_GPM)
if (!noninteractive && STRINGP (help))
{
/* The mouse-fixup-help-message Lisp function can call
static Lisp_Object kbd_buffer_get_event ();
static void record_char ();
+static Lisp_Object help_form_saved_window_configs;
+static Lisp_Object
+read_char_help_form_unwind (arg)
+{
+ Lisp_Object window_config = XCAR (help_form_saved_window_configs);
+ help_form_saved_window_configs = XCDR (help_form_saved_window_configs);
+ if (!NILP (window_config))
+ Fset_window_configuration (window_config);
+ return Qnil;
+}
+
#define STOP_POLLING \
do { if (! polling_stopped_here) stop_polling (); \
polling_stopped_here = 1; } while (0)
Lisp_Object tem0;
count = SPECPDL_INDEX ();
- record_unwind_protect (Fset_window_configuration,
- Fcurrent_window_configuration (Qnil));
+ help_form_saved_window_configs
+ = Fcons (Fcurrent_window_configuration (Qnil),
+ help_form_saved_window_configs);
+ record_unwind_protect (read_char_help_form_unwind, Qnil);
tem0 = Feval (Vhelp_form);
if (STRINGP (tem0))
cancel_echoing ();
do
- c = read_char (0, 0, 0, Qnil, 0, NULL);
+ {
+ c = read_char (0, 0, 0, Qnil, 0, NULL);
+ if (EVENT_HAS_PARAMETERS (c)
+ && EQ (EVENT_HEAD_KIND (EVENT_HEAD (c)), Qmouse_click))
+ XSETCAR (help_form_saved_window_configs, Qnil);
+ }
while (BUFFERP (c));
/* Remove the help from the frame */
unbind_to (count, Qnil);
If you, dear reader, have a better idea, you've got the source. :-) */
if (dribble)
{
+ BLOCK_INPUT;
if (INTEGERP (c))
{
if (XUINT (c) < 0x100)
}
fflush (dribble);
+ UNBLOCK_INPUT;
}
}
kbd_buffer_store_event places events in kbd_buffer, and
kbd_buffer_get_event retrieves them. */
-/* Return true iff there are any events in the queue that read-char
+/* Return true if there are any events in the queue that read-char
would return. If this returns false, a read-char would block. */
static int
readable_events (flags)
return 1;
}
-#ifdef HAVE_MOUSE
+#if defined (HAVE_MOUSE) || defined (HAVE_GPM)
if (!(flags & READABLE_EVENTS_IGNORE_SQUEEZABLES)
&& !NILP (do_mouse_tracking) && some_mouse_moved ())
return 1;
if (sp->kind == MOUSE_CLICK_EVENT
|| sp->kind == WHEEL_EVENT
+ || sp->kind == HORIZ_WHEEL_EVENT
#ifdef WINDOWSNT
|| sp->kind == W32_SCROLL_BAR_CLICK_EVENT
+#endif
+#ifdef HAVE_GPM
+ || sp->kind == GPM_CLICK_EVENT
#endif
|| sp->kind == SCROLL_BAR_CLICK_EVENT)
{
{
if (kbd_fetch_ptr != kbd_store_ptr)
break;
-#ifdef HAVE_MOUSE
+#if defined (HAVE_MOUSE) || defined (HAVE_GPM)
if (!NILP (do_mouse_tracking) && some_mouse_moved ())
break;
#endif
#endif /* SIGIO */
if (kbd_fetch_ptr != kbd_store_ptr)
break;
-#ifdef HAVE_MOUSE
+#if defined (HAVE_MOUSE) || defined (HAVE_GPM)
if (!NILP (do_mouse_tracking) && some_mouse_moved ())
break;
#endif
}
}
}
-#ifdef HAVE_MOUSE
+#if defined (HAVE_MOUSE) || defined (HAVE_GPM)
/* Try generating a mouse motion event. */
else if (!NILP (do_mouse_tracking) && some_mouse_moved ())
{
if (!NILP (x) && NILP (obj))
obj = make_lispy_movement (f, bar_window, part, x, y, time);
}
-#endif /* HAVE_MOUSE */
+#endif /* HAVE_MOUSE || HAVE GPM */
else
/* We were promised by the above while loop that there was
something for us to read! */
static char *lispy_wheel_names[] =
{
- "wheel-up", "wheel-down"
+ "wheel-up", "wheel-down", "wheel-left", "wheel-right"
};
/* drag-n-drop events are generated when a set of selected files are
}
case WHEEL_EVENT:
+ case HORIZ_WHEEL_EVENT:
{
Lisp_Object position;
Lisp_Object head;
the up_modifier set. */
abort ();
+ if (event->kind == HORIZ_WHEEL_EVENT)
+ symbol_num += 2;
+
/* Get the symbol we should use for the wheel event. */
head = modify_event_symbol (symbol_num,
event->modifiers,
}
#endif
+#ifdef HAVE_GPM
+ case GPM_CLICK_EVENT:
+ {
+ FRAME_PTR f = XFRAME (event->frame_or_window);
+ Lisp_Object head, position;
+ Lisp_Object *start_pos_ptr;
+ Lisp_Object start_pos;
+ int button = event->code;
+
+ if (button >= ASIZE (button_down_location))
+ {
+ button_down_location = larger_vector (button_down_location,
+ 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;
+
+ position = make_lispy_position (f, &event->x, &event->y,
+ event->timestamp);
+
+ if (event->modifiers & down_modifier)
+ *start_pos_ptr = Fcopy_alist (position);
+ else if (event->modifiers & (up_modifier | drag_modifier))
+ {
+ if (!CONSP (start_pos))
+ return Qnil;
+ event->modifiers &= ~up_modifier;
+ }
+
+ head = modify_event_symbol (button,
+ event->modifiers,
+ Qmouse_click, Vlispy_mouse_stem,
+ NULL,
+ &mouse_syms,
+ XVECTOR (mouse_syms)->size);
+
+ if (event->modifiers & drag_modifier)
+ return Fcons (head,
+ Fcons (start_pos,
+ Fcons (position,
+ Qnil)));
+ else if (event->modifiers & double_modifier)
+ return Fcons (head,
+ Fcons (position,
+ Fcons (make_number (2),
+ Qnil)));
+ else if (event->modifiers & triple_modifier)
+ return Fcons (head,
+ Fcons (position,
+ Fcons (make_number (3),
+ Qnil)));
+ else
+ return Fcons (head,
+ Fcons (position,
+ Qnil));
+ }
+#endif /* HAVE_GPM */
+
/* The 'kind' field of the event is something we don't recognize. */
default:
abort ();
}
}
-#ifdef HAVE_MOUSE
+#if defined(HAVE_MOUSE) || defined(HAVE_GPM)
static Lisp_Object
make_lispy_movement (frame, bar_window, part, x, y, time)
}
}
-#endif /* HAVE_MOUSE */
+#endif /* HAVE_MOUSE || HAVE GPM */
/* Construct a switch frame event. */
static Lisp_Object
struct tty_display_info *tty = terminal->display_info.tty;
int nread = 0;
- if (terminal->deleted) /* Don't read from a deleted terminal. */
+ if (!terminal->name) /* Don't read from a dead terminal. */
return;
if (terminal->type != output_termcap)
if (! tty->input)
return 0; /* The terminal is suspended. */
- /* Determine how many characters we should *try* to read. */
+#ifdef HAVE_GPM
+ if (gpm_tty == tty)
+ {
+ Gpm_Event event;
+ struct input_event hold_quit;
+ int gpm;
+
+ EVENT_INIT (hold_quit);
+ hold_quit.kind = NO_EVENT;
+
+ while (gpm = Gpm_GetEvent (&event), gpm == 1) {
+ nread += handle_one_term_event (tty, &event, &hold_quit);
+ }
+ if (hold_quit.kind != NO_EVENT)
+ kbd_buffer_store_event (&hold_quit);
+ if (nread)
+ return nread;
+ }
+#endif /* HAVE_GPM */
+
+/* Determine how many characters we should *try* to read. */
#ifdef FIONREAD
/* Find out how much input is available. */
if (ioctl (fileno (tty->input), FIONREAD, &n_to_read) < 0)
static int ntool_bar_items;
-/* The symbols `tool-bar', and `:image'. */
+/* The symbols `tool-bar', `:image' and `:rtl'. */
extern Lisp_Object Qtool_bar;
Lisp_Object QCimage;
+Lisp_Object Qrtl;
/* Function prototypes. */
/* Value is either a single image specification or a vector
of 4 such specifications for the different button states. */
PROP (TOOL_BAR_ITEM_IMAGES) = value;
+ else if (EQ (key, Qrtl))
+ /* ':rtl STRING' */
+ PROP (TOOL_BAR_ITEM_RTL_IMAGE) = value;
}
/* If got a filter apply it on binding. */
of the place where a mouse click occurred. */
volatile int localized_local_map = 0;
- /* The index in defs[] of the first keymap that has a binding for
+ /* The index in submaps[] of the first keymap that has a binding for
this key sequence. In other words, the lowest i such that
- defs[i] is non-nil. */
+ submaps[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. */
{
pos = POSN_BUFFER_POSN (start);
if (INTEGERP (pos)
- && XINT (pos) >= BEG && XINT (pos) <= Z)
+ && XINT (pos) >= BEGV
+ && XINT (pos) <= ZV)
{
map_here = get_local_map (XINT (pos),
current_buffer, Qlocal_map);
if (!NILP (map) || !NILP (map2))
{
from_string = string;
+ keybuf[t++] = key;
+ mock_input = t;
goto replay_sequence;
}
}
}
DEFUN ("recent-keys", Frecent_keys, Srecent_keys, 0, 0, 0,
- doc: /* Return vector of last 100 events, not counting those from keyboard macros. */)
+ doc: /* Return vector of last 300 events, not counting those from keyboard macros. */)
()
{
Lisp_Object *keys = XVECTOR (recent_keys)->contents;
doc: /* Return the key sequence that invoked this command.
However, if the command has called `read-key-sequence', it returns
the last key sequence that has been read.
-The value is a string or a vector. */)
+The value is a string or a vector.
+
+See also `this-command-keys-vector'. */)
()
{
return make_event_array (this_command_key_count,
DEFUN ("this-command-keys-vector", Fthis_command_keys_vector, Sthis_command_keys_vector, 0, 0, 0,
doc: /* Return the key sequence that invoked this command, as a vector.
However, if the command has called `read-key-sequence', it returns
-the last key sequence that has been read. */)
+the last key sequence that has been read.
+
+See also `this-command-keys'. */)
()
{
return Fvector (this_command_key_count,
{
if (dribble)
{
+ BLOCK_INPUT;
fclose (dribble);
+ UNBLOCK_INPUT;
dribble = 0;
}
if (!NILP (file))
Fset_input_interrupt_mode (interrupt);
Fset_output_flow_control (flow, Qnil);
Fset_input_meta_mode (meta, Qnil);
- Fset_quit_char (quit);
+ if (!NILP (quit))
+ Fset_quit_char (quit);
return Qnil;
}
recent_keys_index = 0;
kbd_fetch_ptr = kbd_buffer;
kbd_store_ptr = kbd_buffer;
-#ifdef HAVE_MOUSE
+#if defined (HAVE_MOUSE) || defined (HAVE_GPM)
do_mouse_tracking = Qnil;
#endif
input_pending = 0;
+ interrupt_input_blocked = 0;
+ interrupt_input_pending = 0;
/* This means that command_loop_1 won't try to select anything the first
time through. */
staticpro (&Qhelp_echo);
Qhelp_echo = intern ("help-echo");
+ staticpro (&Qrtl);
+ Qrtl = intern (":rtl");
+
staticpro (&item_properties);
item_properties = Qnil;
Qmenu_bar = intern ("menu-bar");
staticpro (&Qmenu_bar);
-#ifdef HAVE_MOUSE
+#if defined (HAVE_MOUSE) || defined (HAVE_GPM)
Qmouse_fixup_help_message = intern ("mouse-fixup-help-message");
staticpro (&Qmouse_fixup_help_message);
#endif
staticpro (&button_down_location);
mouse_syms = Fmake_vector (make_number (1), Qnil);
staticpro (&mouse_syms);
- wheel_syms = Fmake_vector (make_number (2), Qnil);
+ wheel_syms = Fmake_vector (make_number (4), Qnil);
staticpro (&wheel_syms);
{
menu_bar_items_vector = Qnil;
staticpro (&menu_bar_items_vector);
+ help_form_saved_window_configs = Qnil;
+ staticpro (&help_form_saved_window_configs);
+
defsubr (&Scurrent_idle_time);
defsubr (&Sevent_convert_list);
defsubr (&Sread_key_sequence);
defsubr (&Sread_key_sequence_vector);
defsubr (&Srecursive_edit);
-#ifdef HAVE_MOUSE
+#if defined (HAVE_MOUSE) || defined (HAVE_GPM)
defsubr (&Strack_mouse);
#endif
defsubr (&Sinput_pending_p);
DEFVAR_LISP ("unread-post-input-method-events", &Vunread_post_input_method_events,
doc: /* List of events to be processed as input by input methods.
These events are processed before `unread-command-events'
-and actual keyboard input without given to `input-method-function'. */);
+and actual keyboard input, but are not given to `input-method-function'. */);
Vunread_post_input_method_events = Qnil;
DEFVAR_LISP ("unread-input-method-events", &Vunread_input_method_events,