#include <config.h>
-#define BLOCKINPUT_INLINE EXTERN_INLINE
-#define KEYBOARD_INLINE EXTERN_INLINE
-
#include "sysstdio.h"
#include "lisp.h"
KBOARD *initial_kboard;
KBOARD *current_kboard;
-KBOARD *all_kboards;
+static KBOARD *all_kboards;
/* True in the single-kboard state, false in the any-kboard state. */
static bool single_kboard;
'volatile' here. */
Lisp_Object internal_last_event_frame;
-/* The timestamp of the last input event we received from the X server.
- X Windows wants this for selection ownership. */
-Time last_event_timestamp;
-
static Lisp_Object Qx_set_selection, Qhandle_switch_frame;
static Lisp_Object Qhandle_select_window;
Lisp_Object QPRIMARY;
static Lisp_Object Qvertical_scroll_bar;
Lisp_Object Qmenu_bar;
+static Lisp_Object Qecho_keystrokes;
+
static void recursive_edit_unwind (Lisp_Object buffer);
static Lisp_Object command_loop (void);
static Lisp_Object Qcommand_execute;
Lisp_Object *, ptrdiff_t);
static Lisp_Object make_lispy_switch_frame (Lisp_Object);
static Lisp_Object make_lispy_focus_in (Lisp_Object);
+#ifdef HAVE_WINDOW_SYSTEM
static Lisp_Object make_lispy_focus_out (Lisp_Object);
+#endif /* HAVE_WINDOW_SYSTEM */
static bool help_char_p (Lisp_Object);
static void save_getcjmp (sys_jmp_buf);
static void restore_getcjmp (sys_jmp_buf);
sans error-handling encapsulation. */
static int read_key_sequence (Lisp_Object *, int, Lisp_Object,
- bool, bool, bool);
+ bool, bool, bool, bool);
void safe_run_hooks (Lisp_Object);
static void adjust_point_for_property (ptrdiff_t, bool);
/* Read next key sequence; i gets its length. */
i = read_key_sequence (keybuf, sizeof keybuf / sizeof keybuf[0],
- Qnil, 0, 1, 1);
+ Qnil, 0, 1, 1, 0);
/* A filter may have run while we were reading the input. */
if (! FRAME_LIVE_P (XFRAME (selected_frame)))
}
}
+Lisp_Object
+read_menu_command (void)
+{
+ Lisp_Object keybuf[30];
+ ptrdiff_t count = SPECPDL_INDEX ();
+ int i;
+
+ /* We don't want to echo the keystrokes while navigating the
+ menus. */
+ specbind (Qecho_keystrokes, make_number (0));
+
+ i = read_key_sequence (keybuf, sizeof keybuf / sizeof keybuf[0],
+ Qnil, 0, 1, 1, 1);
+
+ unbind_to (count, Qnil);
+
+ if (! FRAME_LIVE_P (XFRAME (selected_frame)))
+ Fkill_emacs (Qnil);
+ if (i == 0 || i == -1)
+ return Qt;
+
+ return read_key_sequence_cmd;
+}
+
/* Adjust point to a boundary of a region that has such a property
that should be treated intangible. For the moment, we check
`composition', `display' and `invisible' properties.
\f
/* Apply the control modifier to CHARACTER. */
+#ifndef WINDOWSNT
+static
+#endif
int
make_ctrl_char (int c)
{
/* Read a character from the keyboard; call the redisplay if needed. */
/* commandflag 0 means do not autosave, but do redisplay.
-1 means do not redisplay, but do autosave.
+ -2 means do neither.
1 means do both. */
/* The arguments MAP is for menu prompting. MAP is a keymap.
if (/* There currently is something in the echo area. */
!NILP (echo_area_buffer[0])
- && (/* And it's either not from echoing. */
- !EQ (echo_area_buffer[0], echo_message_buffer)
- /* Or it's an echo from a different kboard. */
- || echo_kboard != current_kboard
+ && (/* It's an echo from a different kboard. */
+ echo_kboard != current_kboard
/* Or we explicitly allow overwriting whatever there is. */
|| ok_to_echo_at_next_pause == NULL))
cancel_echoing ();
/* Maybe auto save due to number of keystrokes. */
- if (commandflag != 0
+ if (commandflag != 0 && commandflag != -2
&& auto_save_interval > 0
&& num_nonmacro_input_events - last_auto_save > max (auto_save_interval, 20)
&& !detect_input_pending_run_timers (0))
9 at 200k, 11 at 300k, and 12 at 500k. It is 15 at 1 meg. */
/* Auto save if enough time goes by without input. */
- if (commandflag != 0
+ if (commandflag != 0 && commandflag != -2
&& num_nonmacro_input_events > last_auto_save
&& INTEGERP (Vauto_save_timeout)
&& XINT (Vauto_save_timeout) > 0)
RETURN_UNGCPRO (c);
}
+#ifdef HAVE_MENUS
+
/* Record a key that came from a mouse menu.
Record it for echoing, for this-command-keys, and so on. */
num_input_events++;
}
+#endif /* HAVE_MENUS */
+
/* Return true if should recognize C as "the help character". */
static bool
Vlast_event_frame = focus;
}
- last_event_timestamp = event->timestamp;
-
handle_interrupt (0);
return;
}
}
}
else
- wait_reading_process_output (0, 0, -1, 1, Qnil, NULL, 0);
+ {
+ bool do_display = true;
+
+ if (FRAME_TERMCAP_P (SELECTED_FRAME ()))
+ {
+ struct tty_display_info *tty = CURTTY ();
+
+ /* When this TTY is displaying a menu, we must prevent
+ any redisplay, because we modify the frame's glyph
+ matrix behind the back of the display engine. */
+ if (tty->showing_menu)
+ do_display = false;
+ }
+
+ wait_reading_process_output (0, 0, -1, do_display, Qnil, NULL, 0);
+ }
if (!interrupt_input && kbd_fetch_ptr == kbd_store_ptr)
gobble_input ();
? kbd_fetch_ptr
: kbd_buffer);
- last_event_timestamp = event->timestamp;
-
*kbp = event_to_kboard (event);
if (*kbp == 0)
*kbp = current_kboard; /* Better than returning null ptr? */
else
kbd_fetch_ptr++;
- /* X wants last_event_timestamp for selection ownership. */
- last_event_timestamp = copy.timestamp;
input_pending = readable_events (0);
x_handle_selection_event (©);
#else
if (! (VECTORP (timer) && ASIZE (timer) == 9))
return 0;
- vector = XVECTOR (timer)->contents;
+ vector = XVECTOR (timer)->u.contents;
if (! NILP (vector[0]))
return 0;
extra_info))));
}
+/* Return non-zero if F is a GUI frame that uses some toolkit-managed
+ menu bar. This really means that Emacs draws and manages the menu
+ bar as part of its normal display, and therefore can compute its
+ geometry. */
+static bool
+toolkit_menubar_in_use (struct frame *f)
+{
+#if defined (USE_X_TOOLKIT) || defined (USE_GTK) || defined (HAVE_NS) || defined (HAVE_NTGUI)
+ return !(!FRAME_WINDOW_P (f));
+#else
+ return false;
+#endif
+}
+
/* 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.
/* A mouse click. Figure out where it is, decide whether it's
a press, click or drag, and build the appropriate structure. */
case MOUSE_CLICK_EVENT:
+#ifdef HAVE_GPM
+ case GPM_CLICK_EVENT:
+#endif
#ifndef USE_TOOLKIT_SCROLL_BARS
case SCROLL_BAR_CLICK_EVENT:
#endif
position = Qnil;
/* Build the position as appropriate for this mouse click. */
- if (event->kind == MOUSE_CLICK_EVENT)
+ if (event->kind == MOUSE_CLICK_EVENT
+#ifdef HAVE_GPM
+ || event->kind == GPM_CLICK_EVENT
+#endif
+ )
{
struct frame *f = XFRAME (event->frame_or_window);
-#if ! defined (USE_X_TOOLKIT) && ! defined (USE_GTK) && ! defined (HAVE_NS)
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) && ! defined (HAVE_NS)
/* 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
which are then used to determine whether this click is
in a menu (non-toolkit version). */
- pixel_to_glyph_coords (f, XINT (event->x), XINT (event->y),
- &column, &row, NULL, 1);
-
- /* In the non-toolkit version, clicks on the menu bar
- are ordinary button events in the event buffer.
- Distinguish them, and invoke the menu.
-
- (In the toolkit version, the toolkit handles the menu bar
- and Emacs doesn't know about it until after the user
- makes a selection.) */
- if (row >= 0 && row < FRAME_MENU_BAR_LINES (f)
- && (event->modifiers & down_modifier))
+ if (!toolkit_menubar_in_use (f))
{
- Lisp_Object items, item;
-
- /* Find the menu bar item under `column'. */
- item = Qnil;
- items = FRAME_MENU_BAR_ITEMS (f);
- for (i = 0; i < ASIZE (items); i += 4)
+ pixel_to_glyph_coords (f, XINT (event->x), XINT (event->y),
+ &column, &row, NULL, 1);
+
+ /* In the non-toolkit version, clicks on the menu bar
+ are ordinary button events in the event buffer.
+ Distinguish them, and invoke the menu.
+
+ (In the toolkit version, the toolkit handles the
+ menu bar and Emacs doesn't know about it until
+ after the user makes a selection.) */
+ if (row >= 0 && row < FRAME_MENU_BAR_LINES (f)
+ && (event->modifiers & down_modifier))
{
- Lisp_Object pos, string;
- string = AREF (items, i + 1);
- pos = AREF (items, i + 3);
- if (NILP (string))
- break;
- if (column >= XINT (pos)
- && column < XINT (pos) + SCHARS (string))
+ Lisp_Object items, item;
+
+ /* Find the menu bar item under `column'. */
+ item = Qnil;
+ items = FRAME_MENU_BAR_ITEMS (f);
+ for (i = 0; i < ASIZE (items); i += 4)
{
- item = AREF (items, i);
- break;
+ Lisp_Object pos, string;
+ string = AREF (items, i + 1);
+ pos = AREF (items, i + 3);
+ if (NILP (string))
+ break;
+ if (column >= XINT (pos)
+ && column < XINT (pos) + SCHARS (string))
+ {
+ item = AREF (items, i);
+ break;
+ }
}
- }
- /* ELisp manual 2.4b says (x y) are window relative but
- code says they are frame-relative. */
- position = list4 (event->frame_or_window,
- Qmenu_bar,
- Fcons (event->x, event->y),
- make_number (event->timestamp));
+ /* ELisp manual 2.4b says (x y) are window
+ relative but code says they are
+ frame-relative. */
+ position = list4 (event->frame_or_window,
+ Qmenu_bar,
+ Fcons (event->x, event->y),
+ make_number (event->timestamp));
- return list2 (item, position);
+ return list2 (item, position);
+ }
}
-#endif /* not USE_X_TOOLKIT && not USE_GTK && not HAVE_NS */
position = make_lispy_position (f, event->x, event->y,
event->timestamp);
case CONFIG_CHANGED_EVENT:
return list3 (Qconfig_changed_event,
event->arg, event->frame_or_window);
-#ifdef HAVE_GPM
- case GPM_CLICK_EVENT:
- {
- struct frame *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))
- {
- ptrdiff_t incr = button - ASIZE (button_down_location) + 1;
- button_down_location = larger_vector (button_down_location,
- incr, -1);
- mouse_syms = larger_vector (mouse_syms, incr, -1);
- }
-
- start_pos_ptr = aref_addr (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,
- ASIZE (mouse_syms));
-
- if (event->modifiers & drag_modifier)
- return list3 (head, start_pos, position);
- else if (event->modifiers & double_modifier)
- return list3 (head, position, make_number (2));
- else if (event->modifiers & triple_modifier)
- return list3 (head, position, make_number (3));
- else
- return list2 (head, position);
- }
-#endif /* HAVE_GPM */
/* The 'kind' field of the event is something we don't recognize. */
default:
{
return list2 (Qfocus_in, frame);
}
+
+#ifdef HAVE_WINDOW_SYSTEM
+
static Lisp_Object
make_lispy_focus_out (Lisp_Object frame)
{
return list2 (Qfocus_out, frame);
}
-\f
+
+#endif /* HAVE_WINDOW_SYSTEM */
+
/* Manipulating modifiers. */
/* Parse the name of SYMBOL, and return the set of modifiers it contains.
}
/* Undo any number of BLOCK_INPUT calls down to level LEVEL,
- and also (if the level is now 0) reinvoke any pending signal. */
+ and reinvoke any pending signal if the level is now 0 and
+ a fatal error is not already in progress. */
void
unblock_input_to (int level)
interrupt_input_blocked = level;
if (level == 0)
{
- if (pending_signals)
+ if (pending_signals && !fatal_error_in_progress)
process_pending_signals ();
}
else if (level < 0)
discard any previously made item. */
for (i = 0; i < ntool_bar_items; i += TOOL_BAR_ITEM_NSLOTS)
{
- Lisp_Object *v = XVECTOR (tool_bar_items_vector)->contents + i;
+ Lisp_Object *v = XVECTOR (tool_bar_items_vector)->u.contents + i;
if (EQ (key, v[TOOL_BAR_ITEM_KEY]))
{
/* Append entries from tool_bar_item_properties to the end of
tool_bar_items_vector. */
vcopy (tool_bar_items_vector, ntool_bar_items,
- XVECTOR (tool_bar_item_properties)->contents, TOOL_BAR_ITEM_NSLOTS);
+ XVECTOR (tool_bar_item_properties)->u.contents, TOOL_BAR_ITEM_NSLOTS);
ntool_bar_items += TOOL_BAR_ITEM_NSLOTS;
}
Echo starting immediately unless `prompt' is 0.
+ If PREVENT_REDISPLAY is non-zero, avoid redisplay by calling
+ read_char with a suitable COMMANDFLAG argument.
+
Where a key sequence ends depends on the currently active keymaps.
These include any minor mode keymaps active in the current buffer,
the current buffer's local map, and the global map.
static int
read_key_sequence (Lisp_Object *keybuf, int bufsize, Lisp_Object prompt,
bool dont_downcase_last, bool can_return_switch_frame,
- bool fix_current_buffer)
+ bool fix_current_buffer, bool prevent_redisplay)
{
ptrdiff_t count = SPECPDL_INDEX ();
{
if (!NILP (prompt))
{
- /* Install the string STR as the beginning of the string of
- echoing, so that it serves as a prompt for the next
+ /* Install the string PROMPT as the beginning of the string
+ of echoing, so that it serves as a prompt for the next
character. */
kset_echo_string (current_kboard, prompt);
current_kboard->echo_after_prompt = SCHARS (prompt);
{
KBOARD *interrupted_kboard = current_kboard;
struct frame *interrupted_frame = SELECTED_FRAME ();
- key = read_char (NILP (prompt),
+ /* Calling read_char with COMMANDFLAG = -2 avoids
+ redisplay in read_char and its subroutines. */
+ key = read_char (prevent_redisplay ? -2 : NILP (prompt),
current_binding, last_nonmenu_event,
&used_mouse_menu, NULL);
if ((INTEGERP (key) && XINT (key) == -2) /* wrong_kboard_jmpbuf */
i = read_key_sequence (keybuf, (sizeof keybuf / sizeof (keybuf[0])),
prompt, ! NILP (dont_downcase_last),
- ! NILP (can_return_switch_frame), 0);
+ ! NILP (can_return_switch_frame), 0, 0);
#if 0 /* The following is fine for code reading a key sequence and
then proceeding with a lengthy computation, but it's not good
get_input_pending (READABLE_EVENTS_DO_TIMERS_NOW);
if (old_timers_run != timers_run && do_display)
- {
- redisplay_preserve_echo_area (8);
- /* The following fixes a bug when using lazy-lock with
- lazy-lock-defer-on-the-fly set to t, i.e. when fontifying
- 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. */
- {
- Lisp_Object tail, frame;
- FOR_EACH_FRAME (tail, frame)
- if (FRAME_RIF (XFRAME (frame)))
- FRAME_RIF (XFRAME (frame))->flush_display (XFRAME (frame));
- }
- }
+ redisplay_preserve_echo_area (8);
return input_pending;
}
return (!NILP (Vunread_command_events));
}
-
-DEFUN ("input-pending-p", Finput_pending_p, Sinput_pending_p, 0, 0, 0,
+DEFUN ("input-pending-p", Finput_pending_p, Sinput_pending_p, 0, 1, 0,
doc: /* Return t if command input is currently available with no wait.
Actually, the value is nil only if we can be sure that no input is available;
-if there is a doubt, the value is t. */)
- (void)
+if there is a doubt, the value is t.
+
+If CHECK-TIMERS is non-nil, timers that are ready to run will do so. */)
+ (Lisp_Object check_timers)
{
if (!NILP (Vunread_command_events)
|| !NILP (Vunread_post_input_method_events)
/* Process non-user-visible events (Bug#10195). */
process_special_events ();
- return (get_input_pending (READABLE_EVENTS_DO_TIMERS_NOW
+ return (get_input_pending ((NILP (check_timers)
+ ? 0 : READABLE_EVENTS_DO_TIMERS_NOW)
| READABLE_EVENTS_FILTER_EVENTS)
? Qt : Qnil);
}
doc: /* Return vector of last 300 events, not counting those from keyboard macros. */)
(void)
{
- Lisp_Object *keys = XVECTOR (recent_keys)->contents;
+ Lisp_Object *keys = XVECTOR (recent_keys)->u.contents;
Lisp_Object val;
if (total_keys < NUM_RECENT_KEYS)
(void)
{
return make_event_array (this_command_key_count,
- XVECTOR (this_command_keys)->contents);
+ XVECTOR (this_command_keys)->u.contents);
}
DEFUN ("this-command-keys-vector", Fthis_command_keys_vector, Sthis_command_keys_vector, 0, 0, 0,
(void)
{
return Fvector (this_command_key_count,
- XVECTOR (this_command_keys)->contents);
+ XVECTOR (this_command_keys)->u.contents);
}
DEFUN ("this-single-command-keys", Fthis_single_command_keys,
{
return Fvector (this_command_key_count
- this_single_command_key_start,
- (XVECTOR (this_command_keys)->contents
+ (XVECTOR (this_command_keys)->u.contents
+ this_single_command_key_start));
}
The value is always a vector. */)
(void)
{
- return Fvector (raw_keybuf_count,
- (XVECTOR (raw_keybuf)->contents));
+ return Fvector (raw_keybuf_count, XVECTOR (raw_keybuf)->u.contents);
}
DEFUN ("reset-this-command-lengths", Freset_this_command_lengths,
return tem;
}
-\f
-/*
- * Set up a new kboard object with reasonable initial values.
- */
-void
-init_kboard (KBOARD *kb)
+/* Set up a new kboard object with reasonable initial values.
+ TYPE is a window system for which this keyboard is used. */
+
+static void
+init_kboard (KBOARD *kb, Lisp_Object type)
{
kset_overriding_terminal_local_map (kb, Qnil);
kset_last_command (kb, Qnil);
kb->reference_count = 0;
kset_system_key_alist (kb, Qnil);
kset_system_key_syms (kb, Qnil);
- kset_window_system (kb, Qt); /* Unset. */
+ kset_window_system (kb, type);
kset_input_decode_map (kb, Fmake_sparse_keymap (Qnil));
kset_local_function_key_map (kb, Fmake_sparse_keymap (Qnil));
Fset_keymap_parent (KVAR (kb, Vlocal_function_key_map), Vfunction_key_map);
kset_default_minibuffer_frame (kb, Qnil);
}
+/* Allocate and basically initialize keyboard
+ object to use with window system TYPE. */
+
+KBOARD *
+allocate_kboard (Lisp_Object type)
+{
+ KBOARD *kb = xmalloc (sizeof *kb);
+
+ init_kboard (kb, type);
+ kb->next_kboard = all_kboards;
+ all_kboards = kb;
+ return kb;
+}
+
/*
* Destroy the contents of a kboard object, but not the object itself.
* We use this just before deleting it, or if we're going to initialize
current_kboard = initial_kboard;
/* Re-initialize the keyboard again. */
wipe_kboard (current_kboard);
- init_kboard (current_kboard);
/* A value of nil for Vwindow_system normally means a tty, but we also use
it for the initial terminal since there is no window system there. */
- kset_window_system (current_kboard, Qnil);
+ init_kboard (current_kboard, Qnil);
if (!noninteractive)
{
DEFSYM (Qhelp_form_show, "help-form-show");
+ DEFSYM (Qecho_keystrokes, "echo-keystrokes");
+
Fset (Qinput_method_exit_on_first_char, Qnil);
Fset (Qinput_method_use_echo_area, Qnil);
variable are `sigusr1' and `sigusr2'. */);
Vdebug_on_event = intern_c_string ("sigusr2");
- /* Create the initial keyboard. */
- initial_kboard = xmalloc (sizeof *initial_kboard);
- init_kboard (initial_kboard);
- /* Vwindow_system is left at t for now. */
- initial_kboard->next_kboard = all_kboards;
- all_kboards = initial_kboard;
+ /* Create the initial keyboard. Qt means 'unset'. */
+ initial_kboard = allocate_kboard (Qt);
}
void