static ptrdiff_t before_command_key_count;
static ptrdiff_t before_command_echo_length;
+#ifdef HAVE_STACK_OVERFLOW_HANDLING
+
+/* For longjmp to recover from C stack overflow. */
+sigjmp_buf return_to_command_loop;
+
+/* Message displayed by Vtop_level when recovering from C stack overflow. */
+static Lisp_Object recover_top_level_message;
+
+#endif /* HAVE_STACK_OVERFLOW_HANDLING */
+
+/* Message normally displayed by Vtop_level. */
+static Lisp_Object regular_top_level_message;
+
/* For longjmp to where kbd input is being done. */
static sys_jmp_buf getcjmp;
'volatile' here. */
Lisp_Object internal_last_event_frame;
-static Lisp_Object Qx_set_selection, Qhandle_switch_frame;
+static Lisp_Object Qgui_set_selection, Qhandle_switch_frame;
static Lisp_Object Qhandle_select_window;
Lisp_Object QPRIMARY;
Lisp_Object Qundefined;
static Lisp_Object Qtimer_event_handler;
-/* read_key_sequence stores here the command definition of the
+/* `read_key_sequence' stores here the command definition of the
key sequence that it reads. */
static Lisp_Object read_key_sequence_cmd;
static Lisp_Object read_key_sequence_remapped;
Lisp_Object Qmode_line;
Lisp_Object Qvertical_line;
Lisp_Object Qright_divider, Qbottom_divider;
-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;
-struct timespec timer_check (void);
static void echo_now (void);
static ptrdiff_t echo_length (void);
/* Nonzero while interrupts are temporarily deferred during redisplay. */
bool interrupts_deferred;
-/* If we support a window system, turn on the code to poll periodically
- to detect C-g. It isn't actually used when doing interrupt input. */
-#ifdef HAVE_WINDOW_SYSTEM
-#define POLL_FOR_INPUT
-#endif
-
/* The time when Emacs started being idle. */
static struct timespec timer_idleness_start_time;
static void
echo_add_key (Lisp_Object c)
{
- int size = KEY_DESCRIPTION_SIZE + 100;
- char *buffer = alloca (size);
+ char initbuf[KEY_DESCRIPTION_SIZE + 100];
+ ptrdiff_t size = sizeof initbuf;
+ char *buffer = initbuf;
char *ptr = buffer;
Lisp_Object echo_string;
+ USE_SAFE_ALLOCA;
echo_string = KVAR (current_kboard, echo_string);
else if (SYMBOLP (c))
{
Lisp_Object name = SYMBOL_NAME (c);
- int nbytes = SBYTES (name);
+ ptrdiff_t nbytes = SBYTES (name);
if (size - (ptr - buffer) < nbytes)
{
- int offset = ptr - buffer;
+ ptrdiff_t offset = ptr - buffer;
size = max (2 * size, size + nbytes);
- buffer = alloca (size);
+ buffer = SAFE_ALLOCA (size);
ptr = buffer + offset;
}
if ((NILP (echo_string) || SCHARS (echo_string) == 0)
&& help_char_p (c))
{
- const char *text = " (Type ? for further options)";
- int len = strlen (text);
+ static const char text[] = " (Type ? for further options)";
+ int len = sizeof text - 1;
if (size - (ptr - buffer) < len)
{
- int offset = ptr - buffer;
+ ptrdiff_t offset = ptr - buffer;
size += len;
- buffer = alloca (size);
+ buffer = SAFE_ALLOCA (size);
ptr = buffer + offset;
}
/* Replace a dash from echo_dash with a space, otherwise add a space
at the end as a separator between keys. */
+ AUTO_STRING (space, " ");
if (STRINGP (echo_string) && SCHARS (echo_string) > 1)
{
Lisp_Object last_char, prev_char, idx;
if (XINT (last_char) == '-' && XINT (prev_char) != ' ')
Faset (echo_string, idx, make_number (' '));
else
- echo_string = concat2 (echo_string, build_string (" "));
+ echo_string = concat2 (echo_string, space);
}
else if (STRINGP (echo_string) && SCHARS (echo_string) > 0)
- echo_string = concat2 (echo_string, build_string (" "));
+ echo_string = concat2 (echo_string, space);
kset_echo_string
(current_kboard,
concat2 (echo_string, make_string (buffer, ptr - buffer)));
+ SAFE_FREE ();
}
/* Add C to the echo string, if echoing is going on. C can be a
/* Put a dash at the end of the buffer temporarily,
but make it go away when the next character is added. */
- kset_echo_string
- (current_kboard,
- concat2 (KVAR (current_kboard, echo_string), build_string ("-")));
+ AUTO_STRING (dash, "-");
+ kset_echo_string (current_kboard,
+ concat2 (KVAR (current_kboard, echo_string), dash));
echo_now ();
}
{
print_error_message (data, Qexternal_debugging_output,
SSDATA (context), signal);
- Fterpri (Qexternal_debugging_output);
+ Fterpri (Qexternal_debugging_output, Qnil);
Fkill_emacs (make_number (-1));
}
else
Lisp_Object
command_loop (void)
{
+#ifdef HAVE_STACK_OVERFLOW_HANDLING
+ /* At least on GNU/Linux, saving signal mask is important here. */
+ if (sigsetjmp (return_to_command_loop, 1) != 0)
+ {
+ /* Comes here from handle_sigsegv, see sysdep.c. */
+ init_eval ();
+ Vinternal__top_level_message = recover_top_level_message;
+ }
+ else
+ Vinternal__top_level_message = regular_top_level_message;
+#endif /* HAVE_STACK_OVERFLOW_HANDLING */
if (command_loop_level > 0 || minibuf_level > 0)
{
Lisp_Object val;
xsignal1 (Quser_error, build_string (msg));
}
-_Noreturn
+/* _Noreturn will be added to prototype by make-docfile. */
DEFUN ("exit-recursive-edit", Fexit_recursive_edit, Sexit_recursive_edit, 0, 0, "",
doc: /* Exit from the innermost recursive edit or minibuffer. */)
(void)
user_error ("No recursive edit is in progress");
}
-_Noreturn
+/* _Noreturn will be added to prototype by make-docfile. */
DEFUN ("abort-recursive-edit", Fabort_recursive_edit, Sabort_recursive_edit, 0, 0, "",
doc: /* Abort the command that requested this recursive edit or minibuffer input. */)
(void)
}
}
-DEFUN ("track-mouse", Ftrack_mouse, Strack_mouse, 0, UNEVALLED, 0,
- doc: /* Evaluate BODY with mouse movement events enabled.
-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...) */)
- (Lisp_Object args)
+DEFUN ("internal--track-mouse", Ftrack_mouse, Strack_mouse, 1, 1, 0,
+ doc: /* Call BODYFUN with mouse movement events enabled. */)
+ (Lisp_Object bodyfun)
{
ptrdiff_t count = SPECPDL_INDEX ();
Lisp_Object val;
do_mouse_tracking = Qt;
- val = Fprogn (args);
+ val = call0 (bodyfun);
return unbind_to (count, val);
}
If ignore_mouse_drag_p is non-zero, ignore (implicit) mouse movement
after resizing the tool-bar window. */
-#if !defined HAVE_WINDOW_SYSTEM || defined USE_GTK || defined HAVE_NS
-static
-#endif
bool ignore_mouse_drag_p;
static struct frame *
static int read_key_sequence (Lisp_Object *, int, Lisp_Object,
bool, bool, bool, bool);
-void safe_run_hooks (Lisp_Object);
static void adjust_point_for_property (ptrdiff_t, bool);
/* The last boundary auto-added to buffer-undo-list. */
Lisp_Object last_undo_boundary;
-extern Lisp_Object Qregion_extract_function;
-
/* FIXME: This is wrong rather than test window-system, we should call
a new set-selection, which will then dispatch to x-set-selection, or
tty-set-selection, or w32-set-selection, ... */
Vthis_command_keys_shift_translated = Qnil;
/* Read next key sequence; i gets its length. */
- i = read_key_sequence (keybuf, sizeof keybuf / sizeof keybuf[0],
+ i = read_key_sequence (keybuf, ARRAYELTS (keybuf),
Qnil, 0, 1, 1, 0);
/* A filter may have run while we were reading the input. */
/* Execute the command. */
+ {
+ total_keys += total_keys < NUM_RECENT_KEYS;
+ ASET (recent_keys, recent_keys_index,
+ Fcons (Qnil, cmd));
+ if (++recent_keys_index >= NUM_RECENT_KEYS)
+ recent_keys_index = 0;
+ }
Vthis_command = cmd;
Vreal_this_command = cmd;
safe_run_hooks (Qpre_command_hook);
= call1 (Fsymbol_value (Qregion_extract_function), Qnil);
if (XINT (Flength (txt)) > 0)
/* Don't set empty selections. */
- call2 (Qx_set_selection, QPRIMARY, txt);
+ call2 (Qgui_set_selection, QPRIMARY, txt);
}
if (current_buffer != prev_buffer || MODIFF != prev_modiff)
menus. */
specbind (Qecho_keystrokes, make_number (0));
- i = read_key_sequence (keybuf, sizeof keybuf / sizeof keybuf[0],
+ i = read_key_sequence (keybuf, ARRAYELTS (keybuf),
Qnil, 0, 1, 1, 1);
unbind_to (count, Qnil);
}
}
-/* Subroutine for safe_run_hooks: run the hook HOOK. */
+/* Subroutine for safe_run_hooks: run the hook, which is ARGS[1]. */
static Lisp_Object
-safe_run_hooks_1 (void)
+safe_run_hooks_1 (ptrdiff_t nargs, Lisp_Object *args)
{
- eassert (CONSP (Vinhibit_quit));
- return call0 (XCDR (Vinhibit_quit));
+ eassert (nargs == 2);
+ return call0 (args[1]);
}
/* Subroutine for safe_run_hooks: handle an error by clearing out the function
from the hook. */
static Lisp_Object
-safe_run_hooks_error (Lisp_Object error_data)
+safe_run_hooks_error (Lisp_Object error, ptrdiff_t nargs, Lisp_Object *args)
{
- Lisp_Object hook
- = CONSP (Vinhibit_quit) ? XCAR (Vinhibit_quit) : Vinhibit_quit;
- Lisp_Object fun = CONSP (Vinhibit_quit) ? XCDR (Vinhibit_quit) : Qnil;
- Lisp_Object args[4];
- args[0] = build_string ("Error in %s (%S): %S");
- args[1] = hook;
- args[2] = fun;
- args[3] = error_data;
- Fmessage (4, args);
+ eassert (nargs == 2);
+ AUTO_STRING (format, "Error in %s (%S): %S");
+ Lisp_Object hook = args[0];
+ Lisp_Object fun = args[1];
+ Fmessage (4, (Lisp_Object []) {format, hook, fun, error});
+
if (SYMBOLP (hook))
{
Lisp_Object val;
static Lisp_Object
safe_run_hook_funcall (ptrdiff_t nargs, Lisp_Object *args)
{
- eassert (nargs == 1);
- if (CONSP (Vinhibit_quit))
- XSETCDR (Vinhibit_quit, args[0]);
- else
- Vinhibit_quit = Fcons (Vinhibit_quit, args[0]);
+ Lisp_Object iargs[2];
- internal_condition_case (safe_run_hooks_1, Qt, safe_run_hooks_error);
+ eassert (nargs == 2);
+ /* Yes, run_hook_with_args works this way. */
+ iargs[0] = args[1];
+ iargs[1] = args[0];
+ internal_condition_case_n (safe_run_hooks_1, 2, iargs,
+ Qt, safe_run_hooks_error);
return Qnil;
}
void
safe_run_hooks (Lisp_Object hook)
{
- /* FIXME: our `internal_condition_case' does not provide any way to pass data
- to its body or to its handlers other than via globals such as
- dynamically-bound variables ;-) */
+ Lisp_Object args[2];
+ struct gcpro gcpro1;
ptrdiff_t count = SPECPDL_INDEX ();
- specbind (Qinhibit_quit, hook);
- run_hook_with_args (1, &hook, safe_run_hook_funcall);
+ args[0] = hook;
+ args[1] = hook;
+ GCPRO1 (hook);
+ specbind (Qinhibit_quit, Qt);
+ run_hook_with_args (2, args, safe_run_hook_funcall);
unbind_to (count, Qnil);
+ UNGCPRO;
}
\f
\f
/* Apply the control modifier to CHARACTER. */
-#ifndef HAVE_NTGUI
-static
-#endif
int
make_ctrl_char (int c)
{
/* Save the upper bits here. */
int upper = c & ~0177;
- if (! ASCII_BYTE_P (c))
+ if (! ASCII_CHAR_P (c))
return c |= ctrl_modifier;
c &= 0177;
bool *used_mouse_menu)
{
#define MAX_ENCODED_BYTES 16
+#ifndef WINDOWSNT
Lisp_Object events[MAX_ENCODED_BYTES];
int n = 0;
+#endif
while (true)
{
Lisp_Object nextevt
{ /* An encoded byte sequence, let's try to decode it. */
struct coding_system *coding
= TERMINAL_KEYBOARD_CODING (terminal);
- unsigned char *src = alloca (n);
+ unsigned char src[MAX_ENCODED_BYTES];
+ unsigned char dest[MAX_ENCODED_BYTES * MAX_MULTIBYTE_LENGTH];
int i;
for (i = 0; i < n; i++)
src[i] = XINT (events[i]);
if (meta_key != 2)
for (i = 0; i < n; i++)
src[i] &= ~0x80;
- coding->destination = alloca (n * 4);
- coding->dst_bytes = n * 4;
+ coding->destination = dest;
+ coding->dst_bytes = sizeof dest;
decode_coding_c_string (coding, src, n, Qnil);
eassert (coding->produced_char <= n);
if (coding->produced_char == 0)
}
}
+static bool
+echo_keystrokes_p (void)
+{
+ return (FLOATP (Vecho_keystrokes) ? XFLOAT_DATA (Vecho_keystrokes) > 0.0
+ : INTEGERP (Vecho_keystrokes) ? XINT (Vecho_keystrokes) > 0 : false);
+}
+
/* 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.
retry:
- reread = 0;
if (CONSP (Vunread_post_input_method_events))
{
c = XCAR (Vunread_post_input_method_events);
&& NILP (XCDR (c)))
c = XCAR (c);
- reread = 1;
+ reread = true;
goto reread_first;
}
+ else
+ reread = false;
+
if (CONSP (Vunread_command_events))
{
c = XCAR (Vunread_command_events);
Vunread_command_events = XCDR (Vunread_command_events);
- reread = 1;
-
/* Undo what sit-for did when it unread additional keys
inside universal-argument. */
- if (CONSP (c)
- && EQ (XCAR (c), Qt))
- {
- reread = 0;
- c = XCDR (c);
- }
+ if (CONSP (c) && EQ (XCAR (c), Qt))
+ c = XCDR (c);
+ else
+ reread = true;
/* Undo what read_char_x_menu_prompt did when it unread
additional keys returned by Fx_popup_menu. */
&& (SYMBOLP (XCAR (c)) || INTEGERP (XCAR (c)))
&& NILP (XCDR (c)))
c = XCAR (c);
- reread = 1;
+ reread = true;
goto reread_for_input_method;
}
/* We must have saved the outer value of getcjmp here,
so restore it now. */
restore_getcjmp (save_jump);
+ pthread_sigmask (SIG_SETMASK, &empty_mask, 0);
unbind_to (jmpcount, Qnil);
XSETINT (c, quit_char);
internal_last_event_frame = selected_frame;
&& !current_kboard->immediate_echo
&& this_command_key_count > 0
&& ! noninteractive
- && (FLOATP (Vecho_keystrokes) || INTEGERP (Vecho_keystrokes))
- && NILP (Fzerop (Vecho_keystrokes))
+ && echo_keystrokes_p ()
&& (/* No message. */
NILP (echo_area_buffer[0])
/* Or empty message. */
{
c = XCAR (Vunread_command_events);
Vunread_command_events = XCDR (Vunread_command_events);
+
+ if (CONSP (c) && EQ (XCAR (c), Qt))
+ c = XCDR (c);
+ else
+ reread = true;
}
/* Read something from current KBOARD's side queue, if possible. */
{
c = read_decoded_event_from_main_queue (end_time, local_getcjmp,
prev_event, used_mouse_menu);
- if (NILP(c) && end_time &&
- timespec_cmp (*end_time, current_timespec ()) <= 0)
+ if (NILP (c) && end_time
+ && timespec_cmp (*end_time, current_timespec ()) <= 0)
{
goto exit;
}
{
/* Don't echo mouse motion events. */
- if ((FLOATP (Vecho_keystrokes) || INTEGERP (Vecho_keystrokes))
- && NILP (Fzerop (Vecho_keystrokes))
+ if (echo_keystrokes_p ()
&& ! (EVENT_HAS_PARAMETERS (c)
&& EQ (EVENT_HEAD_KIND (EVENT_HEAD (c)), Qmouse_movement)))
{
#endif
/* Don't echo mouse motion events. */
- if ((FLOATP (Vecho_keystrokes) || INTEGERP (Vecho_keystrokes))
- && NILP (Fzerop (Vecho_keystrokes)))
+ if (echo_keystrokes_p ())
{
echo_char (c);
event->kind == FOCUS_IN_EVENT)
#ifdef USE_TOOLKIT_SCROLL_BARS
&& !((flags & READABLE_EVENTS_IGNORE_SQUEEZABLES)
- && event->kind == SCROLL_BAR_CLICK_EVENT
+ && (event->kind == SCROLL_BAR_CLICK_EVENT
+ || event->kind == HORIZONTAL_SCROLL_BAR_CLICK_EVENT)
&& event->part == scroll_bar_handle
&& event->modifiers == 0)
#endif
- )
+ && !((flags & READABLE_EVENTS_FILTER_EVENTS)
+ && event->kind == BUFFER_SWITCH_EVENT))
return 1;
event++;
if (event == kbd_buffer + KBD_BUFFER_SIZE)
}
}
+/* Limit help event positions to this range, to avoid overflow problems. */
+#define INPUT_EVENT_POS_MAX \
+ ((ptrdiff_t) min (PTRDIFF_MAX, min (TYPE_MAXIMUM (Time) / 2, \
+ MOST_POSITIVE_FIXNUM)))
+#define INPUT_EVENT_POS_MIN (-1 - INPUT_EVENT_POS_MAX)
+
+/* Return a Time that encodes position POS. POS must be in range. */
+
+static Time
+position_to_Time (ptrdiff_t pos)
+{
+ eassert (INPUT_EVENT_POS_MIN <= pos && pos <= INPUT_EVENT_POS_MAX);
+ return pos;
+}
+
+/* Return the position that ENCODED_POS encodes.
+ Avoid signed integer overflow. */
+
+static ptrdiff_t
+Time_to_position (Time encoded_pos)
+{
+ if (encoded_pos <= INPUT_EVENT_POS_MAX)
+ return encoded_pos;
+ Time encoded_pos_min = INPUT_EVENT_POS_MIN;
+ eassert (encoded_pos_min <= encoded_pos);
+ ptrdiff_t notpos = -1 - encoded_pos;
+ return -1 - notpos;
+}
/* Generate a HELP_EVENT input_event and store it in the keyboard
buffer.
{
struct input_event event;
- EVENT_INIT (event);
-
event.kind = HELP_EVENT;
event.frame_or_window = frame;
event.arg = object;
event.x = WINDOWP (window) ? window : frame;
event.y = help;
- event.code = pos;
+ event.timestamp = position_to_Time (pos);
kbd_buffer_store_event (&event);
}
event.arg = Qnil;
event.x = Qnil;
event.y = help;
- event.code = 0;
+ event.timestamp = 0;
kbd_buffer_store_event (&event);
}
#ifdef HAVE_GPM
|| sp->kind == GPM_CLICK_EVENT
#endif
- || sp->kind == SCROLL_BAR_CLICK_EVENT)
+ || sp->kind == SCROLL_BAR_CLICK_EVENT
+ || sp->kind == HORIZONTAL_SCROLL_BAR_CLICK_EVENT)
{
sp->kind = NO_EVENT;
}
frame = event->frame_or_window;
object = event->arg;
- position = make_number (event->code);
+ position = make_number (Time_to_position (event->timestamp));
window = event->x;
help = event->y;
clear_event (event);
vector = XVECTOR (timer)->contents;
if (! NILP (vector[0]))
return 0;
+ if (! INTEGERP (vector[2]))
+ return false;
- return decode_time_components (vector[1], vector[2], vector[3], vector[8],
- result, 0);
+ struct lisp_time t;
+ if (! decode_time_components (vector[1], vector[2], vector[3], vector[8],
+ &t, 0))
+ return false;
+ *result = lisp_to_timespec (t);
+ return timespec_valid_p (*result);
}
/* Scroll bar parts. */
static Lisp_Object Qabove_handle, Qhandle, Qbelow_handle;
-Lisp_Object Qup, Qdown, Qbottom;
+static Lisp_Object Qbefore_handle, Qhorizontal_handle, Qafter_handle;
+Lisp_Object Qup, Qdown, Qtop, Qbottom;
+static Lisp_Object Qleftmost, Qrightmost;
static Lisp_Object Qend_scroll;
-Lisp_Object Qtop;
static Lisp_Object Qratio;
-/* An array of scroll bar parts, indexed by an enum scroll_bar_part value. */
+/* An array of scroll bar parts, indexed by an enum scroll_bar_part value.
+ Note that Qnil corresponds to scroll_bar_nowhere and should not appear
+ in Lisp events. */
static Lisp_Object *const scroll_bar_parts[] = {
- &Qabove_handle, &Qhandle, &Qbelow_handle,
- &Qup, &Qdown, &Qtop, &Qbottom, &Qend_scroll, &Qratio
+ &Qnil, &Qabove_handle, &Qhandle, &Qbelow_handle,
+ &Qup, &Qdown, &Qtop, &Qbottom, &Qend_scroll, &Qratio,
+ &Qbefore_handle, &Qhorizontal_handle, &Qafter_handle,
+ &Qleft, &Qright, &Qleftmost, &Qrightmost, &Qend_scroll, &Qratio
};
/* A vector, indexed by button number, giving the down-going location
/* It's a click in window WINDOW at frame coordinates (X,Y) */
struct window *w = XWINDOW (window);
Lisp_Object string_info = Qnil;
- ptrdiff_t textpos = -1;
+ ptrdiff_t textpos = 0;
int col = -1, row = -1;
int dx = -1, dy = -1;
int width = -1, height = -1;
&object, &dx, &dy, &width, &height);
if (STRINGP (string))
string_info = Fcons (string, make_number (charpos));
- textpos = (w == XWINDOW (selected_window)
- && current_buffer == XBUFFER (w->contents))
- ? PT : marker_position (w->pointm);
+ textpos = -1;
xret = wx;
yret = wy;
&object, &dx, &dy, &width, &height);
if (STRINGP (string))
string_info = Fcons (string, make_number (charpos));
+ xret = wx;
yret = wy - WINDOW_HEADER_LINE_HEIGHT (w);
}
else if (part == ON_LEFT_FRINGE)
{
posn = Qleft_fringe;
col = 0;
+ xret = wx;
dx = wx
- (WINDOW_HAS_FRINGES_OUTSIDE_MARGINS (w)
? 0 : window_box_width (w, LEFT_MARGIN_AREA));
{
posn = Qright_fringe;
col = 0;
+ xret = wx;
dx = wx
- window_box_width (w, LEFT_MARGIN_AREA)
- window_box_width (w, TEXT_AREA)
posn = Qvertical_line;
width = 1;
dx = 0;
+ xret = wx;
+ dy = yret = wy;
+ }
+ else if (part == ON_VERTICAL_SCROLL_BAR)
+ {
+ posn = Qvertical_scroll_bar;
+ width = WINDOW_SCROLL_BAR_AREA_WIDTH (w);
+ dx = xret = wx;
+ dy = yret = wy;
+ }
+ else if (part == ON_HORIZONTAL_SCROLL_BAR)
+ {
+ posn = Qhorizontal_scroll_bar;
+ width = WINDOW_SCROLL_BAR_AREA_HEIGHT (w);
+ dx = xret = wx;
dy = yret = wy;
}
- /* Nothing special for part == ON_SCROLL_BAR. */
else if (part == ON_RIGHT_DIVIDER)
{
posn = Qright_divider;
/* For clicks in the text area, fringes, or margins, call
buffer_posn_from_coords to extract TEXTPOS, the buffer
position nearest to the click. */
- if (textpos < 0)
+ if (!textpos)
{
Lisp_Object string2, object2 = Qnil;
struct display_pos p;
}
#endif
- /* Object info */
+ /* Object info. */
extra_info
= list3 (object,
Fcons (make_number (dx), make_number (dy)),
Fcons (make_number (width), make_number (height)));
- /* String info */
+ /* String info. */
extra_info = Fcons (string_info,
- Fcons (make_number (textpos),
+ Fcons (textpos < 0 ? Qnil : make_number (textpos),
Fcons (Fcons (make_number (col),
make_number (row)),
extra_info)));
}
else if (f != 0)
- XSETFRAME (window, f);
+ {
+ /* Return mouse pixel coordinates here. */
+ XSETFRAME (window, f);
+ xret = XINT (x);
+ yret = XINT (y);
+ }
else
window = Qnil;
#endif
}
+/* Build the part of Lisp event which represents scroll bar state from
+ EV. TYPE is one of Qvertical_scroll_bar or Qhorizontal_scroll_bar. */
+
+static Lisp_Object
+make_scroll_bar_position (struct input_event *ev, Lisp_Object type)
+{
+ return list5 (ev->frame_or_window, type, Fcons (ev->x, ev->y),
+ make_number (ev->timestamp), *scroll_bar_parts[ev->part]);
+}
+
/* 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.
case NON_ASCII_KEYSTROKE_EVENT:
button_down_time = 0;
- for (i = 0; i < sizeof (lispy_accent_codes) / sizeof (int); i++)
+ for (i = 0; i < ARRAYELTS (lispy_accent_codes); i++)
if (event->code == lispy_accent_codes[i])
return modify_event_symbol (i,
event->modifiers,
Qfunction_key, Qnil,
lispy_accent_keys, &accent_key_syms,
- (sizeof (lispy_accent_keys)
- / sizeof (lispy_accent_keys[0])));
+ ARRAYELTS (lispy_accent_keys));
#if 0
#ifdef XK_kana_A
event->modifiers & ~shift_modifier,
Qfunction_key, Qnil,
lispy_kana_keys, &func_key_syms,
- (sizeof (lispy_kana_keys)
- / sizeof (lispy_kana_keys[0])));
+ ARRAYELTS (lispy_kana_keys));
#endif /* XK_kana_A */
#endif /* 0 */
event->modifiers,
Qfunction_key, Qnil,
iso_lispy_function_keys, &func_key_syms,
- (sizeof (iso_lispy_function_keys)
- / sizeof (iso_lispy_function_keys[0])));
+ ARRAYELTS (iso_lispy_function_keys));
#endif
- /* Handle system-specific or unknown keysyms. */
- if (event->code & (1 << 28)
- || event->code - FUNCTION_KEY_OFFSET < 0
- || (event->code - FUNCTION_KEY_OFFSET
- >= sizeof lispy_function_keys / sizeof *lispy_function_keys)
- || !lispy_function_keys[event->code - FUNCTION_KEY_OFFSET])
- {
- /* We need to use an alist rather than a vector as the cache
- since we can't make a vector long enough. */
- if (NILP (KVAR (current_kboard, system_key_syms)))
- kset_system_key_syms (current_kboard, Fcons (Qnil, Qnil));
- return modify_event_symbol (event->code,
- event->modifiers,
- Qfunction_key,
- KVAR (current_kboard, Vsystem_key_alist),
- 0, &KVAR (current_kboard, system_key_syms),
- PTRDIFF_MAX);
- }
-
- return modify_event_symbol (event->code - FUNCTION_KEY_OFFSET,
+ if ((FUNCTION_KEY_OFFSET <= event->code
+ && (event->code
+ < FUNCTION_KEY_OFFSET + ARRAYELTS (lispy_function_keys)))
+ && lispy_function_keys[event->code - FUNCTION_KEY_OFFSET])
+ return modify_event_symbol (event->code - FUNCTION_KEY_OFFSET,
+ event->modifiers,
+ Qfunction_key, Qnil,
+ lispy_function_keys, &func_key_syms,
+ ARRAYELTS (lispy_function_keys));
+
+ /* Handle system-specific or unknown keysyms.
+ We need to use an alist rather than a vector as the cache
+ since we can't make a vector long enough. */
+ if (NILP (KVAR (current_kboard, system_key_syms)))
+ kset_system_key_syms (current_kboard, Fcons (Qnil, Qnil));
+ return modify_event_symbol (event->code,
event->modifiers,
- Qfunction_key, Qnil,
- lispy_function_keys, &func_key_syms,
- (sizeof (lispy_function_keys)
- / sizeof (lispy_function_keys[0])));
+ Qfunction_key,
+ KVAR (current_kboard, Vsystem_key_alist),
+ 0, &KVAR (current_kboard, system_key_syms),
+ PTRDIFF_MAX);
#ifdef HAVE_NTGUI
case MULTIMEDIA_KEY_EVENT:
- if (event->code < (sizeof (lispy_multimedia_keys)
- / sizeof (lispy_multimedia_keys[0]))
+ if (event->code < ARRAYELTS (lispy_multimedia_keys)
&& event->code > 0 && lispy_multimedia_keys[event->code])
{
return modify_event_symbol (event->code, event->modifiers,
Qfunction_key, Qnil,
lispy_multimedia_keys, &func_key_syms,
- (sizeof (lispy_multimedia_keys)
- / sizeof (lispy_multimedia_keys[0])));
+ ARRAYELTS (lispy_multimedia_keys));
}
return Qnil;
#endif
#endif
#ifndef USE_TOOLKIT_SCROLL_BARS
case SCROLL_BAR_CLICK_EVENT:
+ case HORIZONTAL_SCROLL_BAR_CLICK_EVENT:
#endif
{
int button = event->code;
}
#ifndef USE_TOOLKIT_SCROLL_BARS
else
- {
- /* It's a scrollbar click. */
- Lisp_Object window;
- Lisp_Object portion_whole;
- Lisp_Object part;
-
- window = event->frame_or_window;
- portion_whole = Fcons (event->x, event->y);
- part = *scroll_bar_parts[(int) event->part];
-
- position = list5 (window, Qvertical_scroll_bar,
- portion_whole, make_number (event->timestamp),
- part);
- }
+ /* It's a scrollbar click. */
+ position = make_scroll_bar_position (event, Qvertical_scroll_bar);
#endif /* not USE_TOOLKIT_SCROLL_BARS */
if (button >= ASIZE (button_down_location))
case SCROLL_BAR_CLICK_EVENT:
{
- Lisp_Object position, head, window, portion_whole, part;
+ Lisp_Object position, head;
+
+ position = make_scroll_bar_position (event, Qvertical_scroll_bar);
- window = event->frame_or_window;
- portion_whole = Fcons (event->x, event->y);
- part = *scroll_bar_parts[(int) event->part];
+ /* Always treat scroll bar events as clicks. */
+ event->modifiers |= click_modifier;
+ event->modifiers &= ~up_modifier;
- position = list5 (window, Qvertical_scroll_bar, portion_whole,
- make_number (event->timestamp), part);
+ if (event->code >= ASIZE (mouse_syms))
+ mouse_syms = larger_vector (mouse_syms,
+ event->code - ASIZE (mouse_syms) + 1,
+ -1);
+
+ /* Get the symbol we should use for the mouse click. */
+ head = modify_event_symbol (event->code,
+ event->modifiers,
+ Qmouse_click,
+ Vlispy_mouse_stem,
+ NULL, &mouse_syms,
+ ASIZE (mouse_syms));
+ return list2 (head, position);
+ }
+
+ case HORIZONTAL_SCROLL_BAR_CLICK_EVENT:
+ {
+ Lisp_Object position, head;
+
+ position = make_scroll_bar_position (event, Qhorizontal_scroll_bar);
/* Always treat scroll bar events as clicks. */
event->modifiers |= click_modifier;
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, "alt", "super", "hyper", "shift", "control", "meta"
};
-#define NUM_MOD_NAMES (sizeof (modifier_names) / sizeof (modifier_names[0]))
+#define NUM_MOD_NAMES ARRAYELTS (modifier_names)
static Lisp_Object modifier_symbols;
}
}
+ /* If there was no error, make sure the pointer
+ is visible for all frames on this terminal. */
+ if (nr >= 0)
+ {
+ Lisp_Object tail, frame;
+
+ FOR_EACH_FRAME (tail, frame)
+ {
+ struct frame *f = XFRAME (frame);
+ if (FRAME_TERMINAL (f) == t)
+ frame_make_pointer_visible (f);
+ }
+ }
+
if (hold_quit.kind != NO_EVENT)
kbd_buffer_store_event (&hold_quit);
}
if (err && !nread)
nread = -1;
- frame_make_pointer_visible ();
-
return nread;
}
}
\f
-static void menu_bar_item (Lisp_Object, Lisp_Object, Lisp_Object, void*);
+static void menu_bar_item (Lisp_Object, Lisp_Object, Lisp_Object, void *);
static Lisp_Object menu_bar_one_keymap_changed_items;
/* These variables hold the vector under construction within
static int menu_bar_items_index;
-static const char* separator_names[] = {
+static const char *separator_names[] = {
"space",
"no-line",
"single-line",
in the current keymaps, or nil where it is not a prefix. */
Lisp_Object *maps;
+ Lisp_Object mapsbuf[3];
Lisp_Object def, tail;
ptrdiff_t mapno;
Lisp_Object oquit;
+ USE_SAFE_ALLOCA;
+
/* In order to build the menus, we need to call the keymap
accessors. They all call QUIT. But this function is called
during redisplay, during which a quit is fatal. So inhibit
&& !NILP (Voverriding_local_map))
{
/* Yes, use them (if non-nil) as well as the global map. */
- maps = alloca (3 * sizeof (maps[0]));
+ maps = mapsbuf;
nmaps = 0;
if (!NILP (KVAR (current_kboard, Voverriding_terminal_local_map)))
maps[nmaps++] = KVAR (current_kboard, Voverriding_terminal_local_map);
Lisp_Object tem;
ptrdiff_t nminor;
nminor = current_minor_maps (NULL, &tmaps);
- maps = alloca ((nminor + 4) * sizeof *maps);
+ SAFE_NALLOCA (maps, 1, nminor + 4);
nmaps = 0;
tem = KVAR (current_kboard, Voverriding_terminal_local_map);
if (!NILP (tem) && !NILP (Voverriding_local_map_menu_flag))
{
int i = menu_bar_items_index;
if (i + 4 > ASIZE (menu_bar_items_vector))
- menu_bar_items_vector =
- larger_vector (menu_bar_items_vector, 4, -1);
+ menu_bar_items_vector
+ = larger_vector (menu_bar_items_vector, 4, -1);
/* Add this item. */
ASET (menu_bar_items_vector, i, Qnil); i++;
ASET (menu_bar_items_vector, i, Qnil); i++;
}
Vinhibit_quit = oquit;
+ SAFE_FREE ();
return menu_bar_items_vector;
}
\f
{ /* This is a command. See if there is an equivalent key binding. */
Lisp_Object keyeq = AREF (item_properties, ITEM_PROPERTY_KEYEQ);
+ AUTO_STRING (space_space, " ");
/* The previous code preferred :key-sequence to :keys, so we
preserve this behavior. */
if (STRINGP (keyeq) && !CONSP (keyhint))
- keyeq = concat2 (build_string (" "), Fsubstitute_command_keys (keyeq));
+ keyeq = concat2 (space_space, Fsubstitute_command_keys (keyeq));
else
{
Lisp_Object prefix = keyeq;
if (STRINGP (XCDR (prefix)))
tem = concat2 (tem, XCDR (prefix));
}
- keyeq = concat2 (build_string (" "), tem);
- /* keyeq = concat3(build_string(" ("),tem,build_string(")")); */
+ keyeq = concat2 (space_space, tem);
}
else
keyeq = Qnil;
/* Function prototypes. */
static void init_tool_bar_items (Lisp_Object);
-static void process_tool_bar_item (Lisp_Object, Lisp_Object, Lisp_Object, void*);
+static void process_tool_bar_item (Lisp_Object, Lisp_Object, Lisp_Object,
+ void *);
static bool parse_tool_bar_item (Lisp_Object, Lisp_Object);
static void append_tool_bar_item (void);
tool_bar_items (Lisp_Object reuse, int *nitems)
{
Lisp_Object *maps;
+ Lisp_Object mapsbuf[3];
ptrdiff_t nmaps, i;
Lisp_Object oquit;
Lisp_Object *tmaps;
+ USE_SAFE_ALLOCA;
*nitems = 0;
&& !NILP (Voverriding_local_map))
{
/* Yes, use them (if non-nil) as well as the global map. */
- maps = alloca (3 * sizeof *maps);
+ maps = mapsbuf;
nmaps = 0;
if (!NILP (KVAR (current_kboard, Voverriding_terminal_local_map)))
maps[nmaps++] = KVAR (current_kboard, Voverriding_terminal_local_map);
Lisp_Object tem;
ptrdiff_t nminor;
nminor = current_minor_maps (NULL, &tmaps);
- maps = alloca ((nminor + 4) * sizeof *maps);
+ SAFE_NALLOCA (maps, 1, nminor + 4);
nmaps = 0;
tem = KVAR (current_kboard, Voverriding_terminal_local_map);
if (!NILP (tem) && !NILP (Voverriding_local_map_menu_flag))
Vinhibit_quit = oquit;
*nitems = ntool_bar_items / TOOL_BAR_ITEM_NSLOTS;
+ SAFE_FREE ();
return tool_bar_items_vector;
}
read_char_minibuf_menu_prompt (int commandflag,
Lisp_Object map)
{
- register Lisp_Object name;
+ Lisp_Object name;
ptrdiff_t nlength;
/* FIXME: Use the minibuffer's frame width. */
ptrdiff_t width = FRAME_COLS (SELECTED_FRAME ()) - 4;
/* Insert button prefix. */
Lisp_Object selected
= AREF (item_properties, ITEM_PROPERTY_SELECTED);
+ AUTO_STRING (radio_yes, "(*) ");
+ AUTO_STRING (radio_no , "( ) ");
+ AUTO_STRING (check_yes, "[X] ");
+ AUTO_STRING (check_no , "[ ] ");
if (EQ (tem, QCradio))
- tem = build_string (NILP (selected) ? "(*) " : "( ) ");
+ tem = NILP (selected) ? radio_yes : radio_no;
else
- tem = build_string (NILP (selected) ? "[X] " : "[ ] ");
+ tem = NILP (selected) ? check_yes : check_no;
s = concat2 (tem, s);
}
echo_now ();
}
else if (cursor_in_echo_area
- && (FLOATP (Vecho_keystrokes) || INTEGERP (Vecho_keystrokes))
- && NILP (Fzerop (Vecho_keystrokes)))
+ && echo_keystrokes_p ())
/* This doesn't put in a dash if the echo buffer is empty, so
you don't always see a dash hanging out in the minibuffer. */
echo_dash ();
{
key = keybuf[t];
add_command_key (key);
- if ((FLOATP (Vecho_keystrokes) || INTEGERP (Vecho_keystrokes))
- && NILP (Fzerop (Vecho_keystrokes))
+ if (echo_keystrokes_p ()
&& current_kboard->immediate_echo)
{
echo_add_key (key);
Better ideas? */
for (; t < mock_input; t++)
{
- if ((FLOATP (Vecho_keystrokes) || INTEGERP (Vecho_keystrokes))
- && NILP (Fzerop (Vecho_keystrokes)))
+ if (echo_keystrokes_p ())
echo_char (keybuf[t]);
add_command_key (keybuf[t]);
}
memset (keybuf, 0, sizeof keybuf);
GCPRO1 (keybuf[0]);
- gcpro1.nvars = (sizeof keybuf / sizeof (keybuf[0]));
+ gcpro1.nvars = ARRAYELTS (keybuf);
if (NILP (continue_echo))
{
cancel_hourglass ();
#endif
- i = read_key_sequence (keybuf, (sizeof keybuf / sizeof (keybuf[0])),
+ i = read_key_sequence (keybuf, ARRAYELTS (keybuf),
prompt, ! NILP (dont_downcase_last),
! NILP (can_return_switch_frame), 0, 0);
? Qt : Qnil);
}
-DEFUN ("recent-keys", Frecent_keys, Srecent_keys, 0, 0, 0,
- doc: /* Return vector of last 300 events, not counting those from keyboard macros. */)
- (void)
+DEFUN ("recent-keys", Frecent_keys, Srecent_keys, 0, 1, 0,
+ doc: /* Return vector of last few events, not counting those from keyboard macros.
+If INCLUDE-CMDS is non-nil, include the commands that were run,
+represented as events of the form (nil . COMMAND). */)
+ (Lisp_Object include_cmds)
{
- Lisp_Object *keys = XVECTOR (recent_keys)->contents;
- Lisp_Object val;
+ bool cmds = !NILP (include_cmds);
- if (total_keys < NUM_RECENT_KEYS)
- return Fvector (total_keys, keys);
+ if (!total_keys
+ || (cmds && total_keys < NUM_RECENT_KEYS))
+ return Fvector (total_keys,
+ XVECTOR (recent_keys)->contents);
else
{
- val = Fvector (NUM_RECENT_KEYS, keys);
- vcopy (val, 0, keys + recent_keys_index,
- NUM_RECENT_KEYS - recent_keys_index);
- vcopy (val, NUM_RECENT_KEYS - recent_keys_index,
- keys, recent_keys_index);
- return val;
+ Lisp_Object es = Qnil;
+ int i = (total_keys < NUM_RECENT_KEYS
+ ? 0 : recent_keys_index);
+ eassert (recent_keys_index < NUM_RECENT_KEYS);
+ do
+ {
+ Lisp_Object e = AREF (recent_keys, i);
+ if (cmds || !CONSP (e) || !NILP (XCAR (e)))
+ es = Fcons (e, es);
+ if (++i >= NUM_RECENT_KEYS)
+ i = 0;
+ } while (i != recent_keys_index);
+ es = Fnreverse (es);
+ return Fvconcat (1, &es);
}
}
with a window system; but suspend should be disabled in that case. */
get_tty_size (fileno (CURTTY ()->input), &width, &height);
if (width != old_width || height != old_height)
- change_frame_size (SELECTED_FRAME (), width, height, 0, 0, 0, 0);
+ change_frame_size (SELECTED_FRAME (), width,
+ height - FRAME_MENU_BAR_LINES (SELECTED_FRAME ()),
+ 0, 0, 0, 0);
/* Run suspend-resume-hook. */
hook = intern ("suspend-resume-hook");
handle_interrupt_signal (int sig)
{
/* See if we have an active terminal on our controlling tty. */
- struct terminal *terminal = get_named_tty ("/dev/tty");
+ struct terminal *terminal = get_named_terminal ("/dev/tty");
if (!terminal)
{
/* If there are no frames there, let's pretend that we are a
cancel_echoing ();
/* XXX This code needs to be revised for multi-tty support. */
- if (!NILP (Vquit_flag) && get_named_tty ("/dev/tty"))
+ if (!NILP (Vquit_flag) && get_named_terminal ("/dev/tty"))
{
if (! in_signal_handler)
{
See also `current-input-mode'. */)
(Lisp_Object flow, Lisp_Object terminal)
{
- struct terminal *t = get_terminal (terminal, 1);
+ struct terminal *t = decode_tty_terminal (terminal);
struct tty_display_info *tty;
- if (t == NULL || (t->type != output_termcap && t->type != output_msdos_raw))
+
+ if (!t)
return Qnil;
tty = t->display_info.tty;
See also `current-input-mode'. */)
(Lisp_Object meta, Lisp_Object terminal)
{
- struct terminal *t = get_terminal (terminal, 1);
+ struct terminal *t = decode_tty_terminal (terminal);
struct tty_display_info *tty;
int new_meta;
- if (t == NULL || (t->type != output_termcap && t->type != output_msdos_raw))
+ if (!t)
return Qnil;
tty = t->display_info.tty;
See also `current-input-mode'. */)
(Lisp_Object quit)
{
- struct terminal *t = get_named_tty ("/dev/tty");
+ struct terminal *t = get_named_terminal ("/dev/tty");
struct tty_display_info *tty;
- if (t == NULL || (t->type != output_termcap && t->type != output_msdos_raw))
+
+ if (!t)
return Qnil;
tty = t->display_info.tty;
}
XSETFASTINT (val[3], quit_char);
- return Flist (sizeof (val) / sizeof (val[0]), val);
+ return Flist (ARRAYELTS (val), val);
}
DEFUN ("posn-at-x-y", Fposn_at_x_y, Sposn_at_x_y, 2, 4, 0,
Vlispy_mouse_stem = build_pure_c_string ("mouse");
staticpro (&Vlispy_mouse_stem);
+ regular_top_level_message = build_pure_c_string ("Back to top level");
+#ifdef HAVE_STACK_OVERFLOW_HANDLING
+ recover_top_level_message
+ = build_pure_c_string ("Re-entering top level after C stack overflow");
+#endif
+ DEFVAR_LISP ("internal--top-level-message", Vinternal__top_level_message,
+ doc: /* Message displayed by `normal-top-level'. */);
+ Vinternal__top_level_message = regular_top_level_message;
+
/* Tool-bars. */
DEFSYM (QCimage, ":image");
DEFSYM (Qhelp_echo, "help-echo");
DEFSYM (Qmode_line, "mode-line");
DEFSYM (Qvertical_line, "vertical-line");
- DEFSYM (Qvertical_scroll_bar, "vertical-scroll-bar");
DEFSYM (Qmenu_bar, "menu-bar");
DEFSYM (Qright_divider, "right-divider");
DEFSYM (Qbottom_divider, "bottom-divider");
DEFSYM (Qbottom, "bottom");
DEFSYM (Qend_scroll, "end-scroll");
DEFSYM (Qratio, "ratio");
+ DEFSYM (Qbefore_handle, "before-handle");
+ DEFSYM (Qhorizontal_handle, "horizontal-handle");
+ DEFSYM (Qafter_handle, "after-handle");
+ DEFSYM (Qleft, "left");
+ DEFSYM (Qright, "right");
+ DEFSYM (Qleftmost, "leftmost");
+ DEFSYM (Qrightmost, "rightmost");
DEFSYM (Qevent_kind, "event-kind");
DEFSYM (Qevent_symbol_elements, "event-symbol-elements");
DEFSYM (Qpolling_period, "polling-period");
- DEFSYM (Qx_set_selection, "x-set-selection");
+ DEFSYM (Qgui_set_selection, "gui-set-selection");
DEFSYM (QPRIMARY, "PRIMARY");
DEFSYM (Qhandle_switch_frame, "handle-switch-frame");
DEFSYM (Qhandle_select_window, "handle-select-window");
{
int i;
- int len = sizeof (head_table) / sizeof (head_table[0]);
+ int len = ARRAYELTS (head_table);
for (i = 0; i < len; i++)
{
staticpro (&button_down_location);
mouse_syms = Fmake_vector (make_number (5), Qnil);
staticpro (&mouse_syms);
- wheel_syms = Fmake_vector (make_number (sizeof (lispy_wheel_names)
- / sizeof (lispy_wheel_names[0])),
+ wheel_syms = Fmake_vector (make_number (ARRAYELTS (lispy_wheel_names)),
Qnil);
staticpro (&wheel_syms);
{
int i;
- int len = sizeof (modifier_names) / sizeof (modifier_names[0]);
+ int len = ARRAYELTS (modifier_names);
modifier_symbols = Fmake_vector (make_number (len), Qnil);
for (i = 0; i < len; i++)
Buffer modification stores t in this variable. */);
Vdeactivate_mark = Qnil;
DEFSYM (Qdeactivate_mark, "deactivate-mark");
+ Fmake_variable_buffer_local (Qdeactivate_mark);
DEFVAR_LISP ("pre-command-hook", Vpre_command_hook,
doc: /* Normal hook run before each command is executed.