Lisp_Object this_command_keys;
int this_command_key_count;
+/* This vector is used as a buffer to record the events that were actually read
+ by read_key_sequence. */
+Lisp_Object raw_keybuf;
+int raw_keybuf_count;
+
+#define GROW_RAW_KEYBUF \
+if (raw_keybuf_count == XVECTOR (raw_keybuf)->size) \
+ { \
+ int newsize = 2 * XVECTOR (raw_keybuf)->size; \
+ Lisp_Object new; \
+ new = Fmake_vector (make_number (newsize), Qnil); \
+ bcopy (XVECTOR (raw_keybuf)->contents, XVECTOR (new)->contents, \
+ raw_keybuf_count * sizeof (Lisp_Object)); \
+ raw_keybuf = new; \
+ }
+
/* Number of elements of this_command_keys
that precede this key sequence. */
int this_single_command_key_start;
extern struct backtrace *backtrace_list;
+/* If non-nil, the function that implements the display of help.
+ It's called with one argument, the help string to display. */
+
+Lisp_Object Vshow_help_function;
+
/* Nonzero means do menu prompting. */
static int menu_prompting;
int waiting_for_input;
/* True while displaying for echoing. Delays C-g throwing. */
+
static int echoing;
-/* True means we can start echoing at the next input pause
- even though there is something in the echo area. */
-static char *ok_to_echo_at_next_pause;
+/* Non-null means we can start echoing at the next input pause even
+ though there is something in the echo area. */
+
+static struct kboard *ok_to_echo_at_next_pause;
+
+/* The kboard currently echoing, or null for none. Set in echo_now to
+ the kboard echoing. Reset to 0 in cancel_echoing. If non-null,
+ and a current echo area message exists, we know that it comes from
+ echoing. */
+
+static struct kboard *echo_kboard;
/* Nonzero means disregard local maps for the menu bar. */
static int inhibit_local_menu_bar_menus;
/* If not Qnil, a list of objects to be read as subsequent command input. */
Lisp_Object Vunread_command_events;
+/* If not Qnil, a list of objects to be read as subsequent command input
+ including input method processing. */
+Lisp_Object Vunread_input_method_events;
+
+/* If not Qnil, a list of objects to be read as subsequent command input
+ but NOT including input method processing. */
+Lisp_Object Vunread_post_input_method_events;
+
/* If not -1, an event to be read as subsequent command input. */
int unread_command_char;
/* The command being executed by the command loop.
Commands may set this, and the value set will be copied into
current_kboard->Vlast_command instead of the actual command. */
-Lisp_Object this_command;
+Lisp_Object Vthis_command;
+
+/* This is like Vthis_command, except that commands never set it. */
+Lisp_Object real_this_command;
/* The value of point when the last command was executed. */
int last_point_position;
This one takes precedence over ordinary definitions. */
extern Lisp_Object Vkey_translation_map;
+/* If non-nil, this implements the current input method. */
+Lisp_Object Vinput_method_function;
+Lisp_Object Qinput_method_function;
+
+/* When we call Vinput_method_function,
+ this holds the echo area message that was just erased. */
+Lisp_Object Vinput_method_previous_message;
+
/* Non-nil means deactivate the mark at end of this command. */
Lisp_Object Vdeactivate_mark;
Lisp_Object Vdeferred_action_function;
Lisp_Object Qdeferred_action_function;
+Lisp_Object Qinput_method_exit_on_first_char;
+Lisp_Object Qinput_method_use_echo_area;
+
/* File in which we write all commands we read. */
FILE *dribble;
/* 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 volatile struct input_event *kbd_store_ptr;
+static struct input_event * volatile kbd_store_ptr;
/* The above pair of variables forms a "queue empty" flag. When we
enqueue a non-hook event, we increment kbd_store_ptr. When we
Lisp_Object Qdelete_frame;
Lisp_Object Qiconify_frame;
Lisp_Object Qmake_frame_visible;
+Lisp_Object Qhelp_echo;
/* Symbols to denote kinds of events. */
Lisp_Object Qfunction_key;
Lisp_Object Qmouse_click;
#ifdef WINDOWSNT
Lisp_Object Qmouse_wheel;
+Lisp_Object Qlanguage_change;
#endif
Lisp_Object Qdrag_n_drop;
/* Lisp_Object Qmouse_movement; - also an event header */
static int parse_solitary_modifier ();
static void save_getcjmp ();
static void restore_getcjmp ();
+static Lisp_Object apply_modifiers P_ ((int, Lisp_Object));
/* > 0 if we are to echo keystrokes. */
static int echo_keystrokes;
}
echoing = 1;
+ echo_kboard = current_kboard;
message2_nolog (current_kboard->echobuf, strlen (current_kboard->echobuf),
! NILP (current_buffer->enable_multibyte_characters));
-
echoing = 0;
if (waiting_for_input && !NILP (Vquit_flag))
current_kboard->echoptr = current_kboard->echobuf;
current_kboard->echo_after_prompt = -1;
ok_to_echo_at_next_pause = 0;
+ echo_kboard = 0;
}
/* Return the length of the current echo string. */
char *context;
{
Lisp_Object stream;
+ int kill_emacs_p = 0;
Vquit_flag = Qnil;
Vinhibit_quit = Qt;
- echo_area_glyphs = 0;
+ clear_message (1, 0);
/* If the window system or terminal frame hasn't been initialized
yet, or we're not interactive, it's best to dump this message out
to stderr and exit. */
- if (! FRAME_MESSAGE_BUF (selected_frame)
+ if (!selected_frame->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 (selected_frame))
|| noninteractive)
- stream = Qexternal_debugging_output;
+ {
+ stream = Qexternal_debugging_output;
+ kill_emacs_p = 1;
+ }
else
{
Fdiscard_input ();
/* If the window system or terminal frame hasn't been initialized
yet, or we're in -batch mode, this error should cause Emacs to exit. */
- if (! FRAME_MESSAGE_BUF (selected_frame)
- || noninteractive)
+ if (kill_emacs_p)
{
Fterpri (stream);
Fkill_emacs (make_number (-1));
{
if (command_loop_level > 0 || minibuf_level > 0)
{
- return internal_catch (Qexit, command_loop_2, Qnil);
+ Lisp_Object val;
+ val = internal_catch (Qexit, command_loop_2, Qnil);
+ executing_macro = Qnil;
+ return val;
}
else
while (1)
{
internal_catch (Qtop_level, top_level_1, Qnil);
internal_catch (Qtop_level, command_loop_2, Qnil);
+ executing_macro = Qnil;
/* End of file in -batch run causes exit here. */
if (noninteractive)
if (!NILP (Vpost_command_idle_hook) && !NILP (Vrun_hooks))
{
if (NILP (Vunread_command_events)
+ && NILP (Vunread_input_method_events)
+ && NILP (Vunread_post_input_method_events)
&& NILP (Vexecuting_macro)
&& !NILP (sit_for (0, post_command_idle_delay, 0, 1, 1)))
safe_run_hooks (Qpost_command_idle_hook);
}
/* Do this after running Vpost_command_hook, for consistency. */
- current_kboard->Vlast_command = this_command;
- current_kboard->Vreal_last_command = this_command;
+ current_kboard->Vlast_command = Vthis_command;
+ current_kboard->Vreal_last_command = real_this_command;
while (1)
{
+ if (! FRAME_LIVE_P (selected_frame))
+ Fkill_emacs (Qnil);
+
/* Make sure the current window's buffer is selected. */
if (XBUFFER (XWINDOW (selected_window)->buffer) != current_buffer)
set_buffer_internal (XBUFFER (XWINDOW (selected_window)->buffer));
/* If minibuffer on and echo area in use,
wait 2 sec and redraw minibuffer. */
- if (minibuf_level && echo_area_glyphs
+ if (minibuf_level
+ && !NILP (echo_area_buffer[0])
&& EQ (minibuf_window, echo_area_window))
{
/* Bind inhibit-quit to t so that C-g gets read in
before_command_key_count = this_command_key_count;
before_command_echo_length = echo_length ();
- this_command = Qnil;
+ Vthis_command = Qnil;
+ real_this_command = Qnil;
/* Read next key sequence; i gets its length. */
i = read_key_sequence (keybuf, sizeof keybuf / sizeof keybuf[0],
Qnil, 0, 1, 1);
/* A filter may have run while we were reading the input. */
+ if (! FRAME_LIVE_P (selected_frame))
+ Fkill_emacs (Qnil);
if (XBUFFER (XWINDOW (selected_window)->buffer) != current_buffer)
set_buffer_internal (XBUFFER (XWINDOW (selected_window)->buffer));
update the whole window properly. */
if (!NILP (XWINDOW (selected_window)->force_start))
{
+ struct buffer *b;
XWINDOW (selected_window)->force_start = Qnil;
- beg_unchanged = end_unchanged = 0;
+ b = XBUFFER (XWINDOW (selected_window)->buffer);
+ BUF_BEG_UNCHANGED (b) = BUF_END_UNCHANGED (b) = 0;
}
cmd = read_key_sequence_cmd;
/* Execute the command. */
- this_command = cmd;
+ Vthis_command = cmd;
+ real_this_command = cmd;
/* Note that the value cell will never directly contain nil
if the symbol is a local variable. */
if (!NILP (Vpre_command_hook) && !NILP (Vrun_hooks))
safe_run_hooks (Qpre_command_hook);
- if (NILP (this_command))
+ if (NILP (Vthis_command))
{
/* nil means key is undefined. */
bitch_at_user ();
/* Recognize some common commands in common situations and
do them directly. */
- if (EQ (this_command, Qforward_char) && PT < ZV)
+ if (EQ (Vthis_command, Qforward_char) && PT < ZV)
{
struct Lisp_Char_Table *dp
= window_display_table (XWINDOW (selected_window));
no_redisplay = direct_output_forward_char (1);
goto directly_done;
}
- else if (EQ (this_command, Qbackward_char) && PT > BEGV)
+ else if (EQ (Vthis_command, Qbackward_char) && PT > BEGV)
{
struct Lisp_Char_Table *dp
= window_display_table (XWINDOW (selected_window));
no_redisplay = direct_output_forward_char (-1);
goto directly_done;
}
- else if (EQ (this_command, Qself_insert_command)
+ else if (EQ (Vthis_command, Qself_insert_command)
/* Try this optimization only on ascii keystrokes. */
&& INTEGERP (last_command_char))
{
unsigned int c = XINT (last_command_char);
int value;
-
if (NILP (Vexecuting_macro)
&& !EQ (minibuf_window, selected_window))
{
}
nonundocount++;
}
+
lose = ((XFASTINT (XWINDOW (selected_window)->last_modified)
< MODIFF)
|| (XFASTINT (XWINDOW (selected_window)->last_overlay_modified)
|| detect_input_pending ()
|| !NILP (XWINDOW (selected_window)->column_number_displayed)
|| !NILP (Vexecuting_macro));
+
value = internal_self_insert (c, 0);
- if (value)
- lose = 1;
+
if (value == 2)
nonundocount = 0;
- if (!lose
- && (PT == ZV || FETCH_BYTE (PT_BYTE) == '\n'))
- {
- struct Lisp_Char_Table *dp
- = window_display_table (XWINDOW (selected_window));
- int lose = c;
-
- /* Add the offset to the character, for Finsert_char.
- We pass internal_self_insert the unmodified character
- because it itself does this offsetting. */
- if (! NILP (current_buffer->enable_multibyte_characters))
- lose = unibyte_char_to_multibyte (lose);
-
- if (dp)
- {
- Lisp_Object obj;
-
- obj = DISP_CHAR_VECTOR (dp, lose);
- if (NILP (obj))
- {
- /* Do it only for char codes
- that by default display as themselves. */
- if (lose >= 0x20 && lose <= 0x7e)
- no_redisplay = direct_output_for_insert (lose);
- }
- else if (VECTORP (obj)
- && XVECTOR (obj)->size == 1
- && (obj = XVECTOR (obj)->contents[0],
- INTEGERP (obj))
- /* Insist face not specified in glyph. */
- && (XINT (obj) & ((-1) << 8)) == 0)
- no_redisplay
- = direct_output_for_insert (XINT (obj));
- }
- else
- {
- if (lose >= 0x20 && lose <= 0x7e)
- no_redisplay = direct_output_for_insert (lose);
- }
- }
+ /* VALUE == 1 when AFTER-CHANGE functions are
+ installed which is the case most of the time
+ because FONT-LOCK installs one. */
+ if (!lose && !value)
+ no_redisplay = direct_output_for_insert (c);
goto directly_done;
}
}
/* Here for a command that isn't executed directly */
+#ifdef HAVE_X_WINDOWS
+ if (display_busy_cursor_p)
+ {
+ if (inhibit_busy_cursor != 2)
+ inhibit_busy_cursor = 0;
+ if (!inhibit_busy_cursor)
+ Fx_show_busy_cursor ();
+ }
+#endif
+
nonundocount = 0;
if (NILP (current_kboard->Vprefix_arg))
Fundo_boundary ();
- Fcommand_execute (this_command, Qnil, Qnil, Qnil);
+ Fcommand_execute (Vthis_command, Qnil, Qnil, Qnil);
}
directly_done: ;
current_kboard->Vlast_prefix_arg = Vcurrent_prefix_arg;
if (!NILP (Vpost_command_idle_hook) && !NILP (Vrun_hooks))
{
if (NILP (Vunread_command_events)
+ && NILP (Vunread_input_method_events)
+ && NILP (Vunread_post_input_method_events)
&& NILP (Vexecuting_macro)
&& !NILP (sit_for (0, post_command_idle_delay, 0, 1, 1)))
safe_run_hooks (Qpost_command_idle_hook);
then the above doesn't apply. */
if (NILP (current_kboard->Vprefix_arg) || CONSP (last_command_char))
{
- current_kboard->Vlast_command = this_command;
- current_kboard->Vreal_last_command = this_command;
+ current_kboard->Vlast_command = Vthis_command;
+ current_kboard->Vreal_last_command = real_this_command;
cancel_echoing ();
this_command_key_count = 0;
this_single_command_key_start = 0;
MAPS is an array of keymaps; NMAPS is the length of MAPS.
PREV_EVENT is the previous input event, or nil if we are reading
- the first event of a key sequence.
+ the first event of a key sequence (or not reading a key sequence).
+ If PREV_EVENT is t, that is a "magic" value that says
+ not to run input methods, but in other respects to act as if
+ not reading a key sequence.
If USED_MOUSE_MENU is non-null, then we set *USED_MOUSE_MENU to 1
if we used a mouse menu to read the input, or zero otherwise. If
jmp_buf save_jump;
int key_already_recorded = 0;
Lisp_Object tem, save;
+ Lisp_Object previous_echo_area_message;
Lisp_Object also_record;
- struct gcpro gcpro1;
+ int reread;
+ struct gcpro gcpro1, gcpro2;
also_record = Qnil;
before_command_key_count = this_command_key_count;
before_command_echo_length = echo_length ();
c = Qnil;
+ previous_echo_area_message = Qnil;
- GCPRO1 (c);
+ GCPRO2 (c, previous_echo_area_message);
retry:
- if (CONSP (Vunread_command_events))
+ reread = 0;
+ if (CONSP (Vunread_post_input_method_events))
{
- c = XCONS (Vunread_command_events)->car;
- Vunread_command_events = XCONS (Vunread_command_events)->cdr;
+ c = XCONS (Vunread_post_input_method_events)->car;
+ Vunread_post_input_method_events
+ = XCONS (Vunread_post_input_method_events)->cdr;
/* Undo what read_char_x_menu_prompt did when it unread
additional keys returned by Fx_popup_menu. */
&& NILP (XCONS (c)->cdr))
c = XCONS (c)->car;
- if (this_command_key_count == 0)
- goto reread_first;
- else
- goto reread;
+ reread = 1;
+ goto reread_first;
}
if (unread_command_char != -1)
XSETINT (c, unread_command_char);
unread_command_char = -1;
- if (this_command_key_count == 0)
- goto reread_first;
- else
- goto reread;
+ reread = 1;
+ goto reread_first;
+ }
+
+ if (CONSP (Vunread_command_events))
+ {
+ c = XCONS (Vunread_command_events)->car;
+ Vunread_command_events = XCONS (Vunread_command_events)->cdr;
+
+ /* Undo what read_char_x_menu_prompt did when it unread
+ additional keys returned by Fx_popup_menu. */
+ if (CONSP (c)
+ && (SYMBOLP (XCONS (c)->car) || INTEGERP (XCONS (c)->car))
+ && NILP (XCONS (c)->cdr))
+ c = XCONS (c)->car;
+
+ reread = 1;
+ goto reread_for_input_method;
+ }
+
+ if (CONSP (Vunread_input_method_events))
+ {
+ c = XCONS (Vunread_input_method_events)->car;
+ Vunread_input_method_events = XCONS (Vunread_input_method_events)->cdr;
+
+ /* Undo what read_char_x_menu_prompt did when it unread
+ additional keys returned by Fx_popup_menu. */
+ if (CONSP (c)
+ && (SYMBOLP (XCONS (c)->car) || INTEGERP (XCONS (c)->car))
+ && NILP (XCONS (c)->cdr))
+ c = XCONS (c)->car;
+ reread = 1;
+ goto reread_for_input_method;
}
/* If there is no function key translated before
unread_switch_frame = Qnil;
/* This event should make it into this_command_keys, and get echoed
- again, so we go to reread_first, rather than reread. */
+ again, so we do not set `reread'. */
goto reread_first;
}
}
/* Message turns off echoing unless more keystrokes turn it on again. */
- if (echo_area_glyphs && *echo_area_glyphs
- && echo_area_glyphs != current_kboard->echobuf
- && ok_to_echo_at_next_pause != echo_area_glyphs)
+ if (/* There is a current message. */
+ !NILP (echo_area_buffer[0])
+ /* And we're not echoing from this kboard. */
+ && echo_kboard != current_kboard
+ /* And it's either not ok to echo (ok_to_echo == NULL), or the
+ last char echoed was from a different kboard. */
+ && ok_to_echo_at_next_pause != echo_kboard)
cancel_echoing ();
else
/* If already echoing, continue. */
/* If in middle of key sequence and minibuffer not active,
start echoing if enough time elapses. */
- if (minibuf_level == 0 && !current_kboard->immediate_echo
+ if (minibuf_level == 0
+ && !current_kboard->immediate_echo
&& this_command_key_count > 0
&& ! noninteractive
&& echo_keystrokes > 0
- && (echo_area_glyphs == 0 || *echo_area_glyphs == 0
- || ok_to_echo_at_next_pause == echo_area_glyphs))
+ && (/* No message. */
+ NILP (echo_area_buffer[0])
+ /* Or empty message. */
+ || (BUF_BEG (XBUFFER (echo_area_buffer[0]))
+ == BUF_Z (XBUFFER (echo_area_buffer[0])))
+ /* Or already echoing from same kboard. */
+ || (echo_kboard && ok_to_echo_at_next_pause == echo_kboard)
+ /* Or not echoing before and echoing allowed. */
+ || (!echo_kboard && ok_to_echo_at_next_pause)))
{
Lisp_Object tem0;
-
+
/* After a mouse event, start echoing right away.
This is because we are probably about to display a menu,
and we don't want to delay before doing so. */
&& !NILP (prev_event)
&& EVENT_HAS_PARAMETERS (prev_event)
&& !EQ (XCONS (prev_event)->car, Qmenu_bar)
+ && !EQ (XCONS (prev_event)->car, Qtoolbar)
/* Don't bring up a menu if we already have another event. */
&& NILP (Vunread_command_events)
&& unread_command_char < 0)
goto retry;
}
- /* Wipe the echo area. */
- if (echo_area_glyphs)
- safe_run_hooks (Qecho_area_clear_hook);
- echo_area_glyphs = 0;
-
/* Handle things that only apply to characters. */
if (INTEGERP (c))
{
posn = POSN_BUFFER_POSN (EVENT_START (c));
/* Handle menu-bar events:
insert the dummy prefix event `menu-bar'. */
- if (EQ (posn, Qmenu_bar))
+ if (EQ (posn, Qmenu_bar) || EQ (posn, Qtoolbar))
{
/* Change menu-bar to (menu-bar) as the event "position". */
POSN_BUFFER_POSN (EVENT_START (c)) = Fcons (posn, Qnil);
}
}
+ /* Store these characters into recent_keys, the dribble file if any,
+ and the keyboard macro being defined, if any. */
record_char (c);
if (! NILP (also_record))
record_char (also_record);
+ /* Wipe the echo area.
+ But first, if we are about to use an input method,
+ save the echo area contents for it to refer to. */
+ if (INTEGERP (c)
+ && ! NILP (Vinput_method_function)
+ && (unsigned) XINT (c) >= ' '
+ && (unsigned) XINT (c) < 127)
+ {
+ previous_echo_area_message = Fcurrent_message ();
+ Vinput_method_previous_message = previous_echo_area_message;
+ }
+
+ /* Now wipe the echo area. */
+ if (!NILP (echo_area_buffer[0]))
+ safe_run_hooks (Qecho_area_clear_hook);
+ clear_message (1, 0);
+
+ reread_for_input_method:
from_macro:
+ /* Pass this to the input method, if appropriate. */
+ if (INTEGERP (c)
+ && ! NILP (Vinput_method_function)
+ /* Don't run the input method within a key sequence,
+ after the first event of the key sequence. */
+ && NILP (prev_event)
+ && (unsigned) XINT (c) >= ' '
+ && (unsigned) XINT (c) < 127)
+ {
+ Lisp_Object keys;
+ int key_count;
+ struct gcpro gcpro1;
+ int count = specpdl_ptr - specpdl;
+
+ /* Save the echo status. */
+ int saved_immediate_echo = current_kboard->immediate_echo;
+ struct kboard *saved_ok_to_echo = ok_to_echo_at_next_pause;
+ int saved_echo_after_prompt = current_kboard->echo_after_prompt;
+
+ if (before_command_restore_flag)
+ {
+ this_command_key_count = before_command_key_count_1;
+ if (this_command_key_count < this_single_command_key_start)
+ this_single_command_key_start = this_command_key_count;
+ echo_truncate (before_command_echo_length_1);
+ before_command_restore_flag = 0;
+ }
+
+ /* Save the this_command_keys status. */
+ key_count = this_command_key_count;
+
+ if (key_count > 0)
+ keys = Fcopy_sequence (this_command_keys);
+ else
+ keys = Qnil;
+ GCPRO1 (keys);
+
+ /* Clear out this_command_keys. */
+ this_command_key_count = 0;
+
+ /* Now wipe the echo area. */
+ if (!NILP (echo_area_buffer[0]))
+ safe_run_hooks (Qecho_area_clear_hook);
+ clear_message (1, 0);
+ echo_truncate (0);
+
+ /* If we are not reading a key sequence,
+ never use the echo area. */
+ if (maps == 0)
+ {
+ specbind (Qinput_method_use_echo_area, Qt);
+ }
+
+ /* Call the input method. */
+ tem = call1 (Vinput_method_function, c);
+
+ tem = unbind_to (count, tem);
+
+ /* Restore the saved echoing state
+ and this_command_keys state. */
+ this_command_key_count = key_count;
+ if (key_count > 0)
+ this_command_keys = keys;
+
+ cancel_echoing ();
+ ok_to_echo_at_next_pause = saved_ok_to_echo;
+ current_kboard->echo_after_prompt = saved_echo_after_prompt;
+ if (saved_immediate_echo)
+ echo_now ();
+
+ UNGCPRO;
+
+ /* The input method can return no events. */
+ if (! CONSP (tem))
+ {
+ /* Bring back the previous message, if any. */
+ if (! NILP (previous_echo_area_message))
+ message_with_string ("%s", previous_echo_area_message, 0);
+ goto retry;
+ }
+ /* It returned one event or more. */
+ c = XCONS (tem)->car;
+ Vunread_post_input_method_events
+ = nconc2 (XCONS (tem)->cdr, Vunread_post_input_method_events);
+ }
+
reread_first:
- before_command_key_count = this_command_key_count;
- before_command_echo_length = echo_length ();
+ /* Display help if not echoing. */
+ if (CONSP (c)
+ && EQ (XCAR (c), Qhelp_echo))
+ {
+ Lisp_Object msg = XCDR (XCDR (c));
- /* Don't echo mouse motion events. */
- if (echo_keystrokes
- && ! (EVENT_HAS_PARAMETERS (c)
- && EQ (EVENT_HEAD_KIND (EVENT_HEAD (c)), Qmouse_movement)))
+ if (!NILP (Vshow_help_function))
+ call1 (Vshow_help_function, msg);
+ else if (!echoing && !MINI_WINDOW_P (XWINDOW (selected_window)))
+ {
+ if (STRINGP (msg))
+ message3_nolog (msg, XSTRING (msg)->size, STRING_MULTIBYTE (msg));
+ else
+ message (0);
+ }
+
+ goto retry;
+ }
+
+ if (this_command_key_count == 0 || ! reread)
{
- echo_char (c);
+ before_command_key_count = this_command_key_count;
+ before_command_echo_length = echo_length ();
+
+ /* Don't echo mouse motion events. */
+ if (echo_keystrokes
+ && ! (EVENT_HAS_PARAMETERS (c)
+ && EQ (EVENT_HEAD_KIND (EVENT_HEAD (c)), Qmouse_movement)))
+ {
+ echo_char (c);
+ if (! NILP (also_record))
+ echo_char (also_record);
+ /* Once we reread a character, echoing can happen
+ the next time we pause to read a new one. */
+ ok_to_echo_at_next_pause = current_kboard;
+ }
+
+ /* Record this character as part of the current key. */
+ add_command_key (c);
if (! NILP (also_record))
- echo_char (also_record);
- /* Once we reread a character, echoing can happen
- the next time we pause to read a new one. */
- ok_to_echo_at_next_pause = echo_area_glyphs;
+ add_command_key (also_record);
}
- /* Record this character as part of the current key. */
- add_command_key (c);
- if (! NILP (also_record))
- add_command_key (also_record);
-
- /* Re-reading in the middle of a command */
- reread:
last_input_char = c;
num_input_events++;
Lisp_Object c;
{
/* Wipe the echo area. */
- echo_area_glyphs = 0;
+ clear_message (1, 0);
record_char (c);
Discard the event if it would fill the last slot. */
if (kbd_fetch_ptr - 1 != kbd_store_ptr)
{
- volatile struct input_event *sp = kbd_store_ptr;
+ struct input_event *sp = kbd_store_ptr;
sp->kind = event->kind;
if (event->kind == selection_request_event)
{
if (FRAME_LIVE_P (XFRAME (event->frame_or_window)))
x_activate_menubar (XFRAME (event->frame_or_window));
}
+#endif
+#ifdef WINDOWSNT
+ else if (event->kind == language_change_event)
+ {
+ /* Make an event (language-change (FRAME CHARSET LCID)). */
+ obj = Fcons (event->modifiers, Qnil);
+ obj = Fcons (event->code, Qnil);
+ obj = Fcons (event->frame_or_window, obj);
+ obj = Fcons (Qlanguage_change, Fcons (obj, Qnil));
+ kbd_fetch_ptr = event + 1;
+ }
#endif
/* Just discard these, by returning nil.
With MULTI_KBOARD, these events are used as placeholders
mouse events during a popup-menu call. */
else if (event->kind == no_event)
kbd_fetch_ptr = event + 1;
-
+ else if (event->kind == HELP_EVENT)
+ {
+ /* The car of event->frame_or_window is a frame,
+ the cdr is the help to display. */
+ obj = Fcons (Qhelp_echo, event->frame_or_window);
+ kbd_fetch_ptr = event + 1;
+ }
/* If this event is on a different frame, return a switch-frame this
time, and leave the event in the queue for next time. */
else
we're returning is (menu-bar), though; that indicates the
beginning of the menu sequence, and we might as well leave
that as the `event with parameters' for this selection. */
- if (event->kind == menu_bar_event
+ if ((event->kind == menu_bar_event
+ || event->kind == TOOLBAR_EVENT)
&& !(CONSP (obj) && EQ (XCONS (obj)->car, Qmenu_bar))
+ && !(CONSP (obj) && EQ (XCONS (obj)->car, Qtoolbar))
&& used_mouse_menu)
*used_mouse_menu = 1;
#endif
Lisp_Object tem;
int was_locked = single_kboard;
int count = specpdl_ptr - specpdl;
+#ifdef HAVE_WINDOW_SYSTEM
+ int old_inhibit_busy_cursor = inhibit_busy_cursor;
+#endif
/* Mark the timer as triggered to prevent problems if the lisp
code fails to reschedule it right. */
specbind (Qinhibit_quit, Qt);
+#ifdef HAVE_WINDOW_SYSTEM
+ inhibit_busy_cursor = 2;
+#endif
+
call1 (Qtimer_event_handler, chosen_timer);
timers_run++;
+#ifdef HAVE_WINDOW_SYSTEM
+ inhibit_busy_cursor = old_inhibit_busy_cursor;
+#endif
+
unbind_to (count, Qnil);
/* Resume allowing input from any kboard, if that was true before. */
0, 0, /* 0x0E .. 0x0F */
- "shift", /* VK_SHIFT 0x10 */
- "control", /* VK_CONTROL 0x11 */
- "menu", /* VK_MENU 0x12 */
+ 0, /* VK_SHIFT 0x10 */
+ 0, /* VK_CONTROL 0x11 */
+ 0, /* VK_MENU 0x12 */
"pause", /* VK_PAUSE 0x13 */
- "capital", /* VK_CAPITAL 0x14 */
+ "capslock", /* VK_CAPITAL 0x14 */
0, 0, 0, 0, 0, 0, /* 0x15 .. 0x1A */
- 0, /* VK_ESCAPE 0x1B */
+ "escape", /* VK_ESCAPE 0x1B */
0, 0, 0, 0, /* 0x1C .. 0x1F */
"noname", /* VK_NONAME 0xFC */
"pa1", /* VK_PA1 0xFD */
"oem_clear", /* VK_OEM_CLEAR 0xFE */
+ 0 /* 0xFF */
};
#else /* not HAVE_NTGUI */
/* Scroll bar parts. */
Lisp_Object Qabove_handle, Qhandle, Qbelow_handle;
-Lisp_Object Qup, Qdown;
+Lisp_Object Qup, Qdown, Qbottom, Qend_scroll;
+Lisp_Object Qtop;
/* An array of scroll bar parts, indexed by an enum scroll_bar_part value. */
Lisp_Object *scroll_bar_parts[] = {
&Qabove_handle, &Qhandle, &Qbelow_handle,
- &Qup, &Qdown,
+ &Qup, &Qdown, &Qtop, &Qbottom, &Qend_scroll
+};
+
+/* User signal events. */
+Lisp_Object Qusr1_signal, Qusr2_signal;
+
+Lisp_Object *lispy_user_signals[] =
+{
+ &Qusr1_signal, &Qusr2_signal
};
/* 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:
+#ifndef USE_TOOLKIT_SCROLL_BARS
case scroll_bar_click:
+#endif
{
int button = event->code;
int is_double;
FRAME_PTR f = XFRAME (event->frame_or_window);
Lisp_Object window;
Lisp_Object posn;
+ Lisp_Object string_info = Qnil;
int row, column;
/* Ignore mouse events that were made on frame that
if (! FRAME_LIVE_P (f))
return Qnil;
- pixel_to_glyph_coords (f, XINT (event->x), XINT (event->y),
- &column, &row, NULL, 1);
+ /* 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);
#ifndef USE_X_TOOLKIT
/* In the non-toolkit version, clicks on the menu bar
return Qnil;
#endif
+ /* Find the menu bar item under `column'. */
item = Qnil;
items = FRAME_MENU_BAR_ITEMS (f);
for (i = 0; i < XVECTOR (items)->size; i += 4)
}
}
+ /* ELisp manual 2.4b says (x y) are window relative but
+ code says they are frame-relative. */
position
= Fcons (event->frame_or_window,
Fcons (Qmenu_bar,
}
#endif /* not USE_X_TOOLKIT */
- window = window_from_coordinates (f, column, row, &part);
+ /* Set `window' to the window under frame pixel coordinates
+ event->x/event->y. */
+ window = window_from_coordinates (f, XINT (event->x),
+ XINT (event->y), &part, 0);
if (!WINDOWP (window))
{
}
else
{
- int pixcolumn, pixrow;
- column -= WINDOW_LEFT_MARGIN (XWINDOW (window));
- row -= XINT (XWINDOW (window)->top);
- glyph_to_pixel_coords (f, column, row, &pixcolumn, &pixrow);
- XSETINT (event->x, pixcolumn);
- XSETINT (event->y, pixrow);
-
- if (part == 1)
- posn = Qmode_line;
+ /* It's a click in window window at frame coordinates
+ event->x/ event->y. */
+ struct window *w = XWINDOW (window);
+
+ /* Get window relative coordinates. Original code
+ `rounded' this to glyph boundaries. */
+ int wx = FRAME_TO_WINDOW_PIXEL_X (w, XINT (event->x));
+ int wy = FRAME_TO_WINDOW_PIXEL_Y (w, XINT (event->y));
+
+ /* Set event coordinates to window-relative coordinates
+ for constructing the Lisp event below. */
+ XSETINT (event->x, wx);
+ XSETINT (event->y, wy);
+
+ if (part == 1 || part == 3)
+ {
+ /* Mode line or top line. Look for a string under
+ the mouse that may have a `local-map' property. */
+ Lisp_Object string;
+ int charpos;
+
+ posn = part == 1 ? Qmode_line : Qtop_line;
+ string = mode_line_string (w, wx, wy, part == 1, &charpos);
+ if (STRINGP (string))
+ string_info = Fcons (string, make_number (charpos));
+ }
else if (part == 2)
posn = Qvertical_line;
else
- XSETINT (posn,
- buffer_posn_from_coords (XWINDOW (window),
- column, row));
+ XSETINT (posn, buffer_posn_from_coords (w, &wx, &wy));
}
position
Fcons (posn,
Fcons (Fcons (event->x, event->y),
Fcons (make_number (event->timestamp),
- Qnil))));
+ (NILP (string_info)
+ ? Qnil
+ : Fcons (string_info, Qnil))))));
}
+#ifndef USE_TOOLKIT_SCROLL_BARS
else
{
+ /* It's a scrollbar click. */
Lisp_Object window;
Lisp_Object portion_whole;
Lisp_Object part;
Fcons (make_number (event->timestamp),
Fcons (part, Qnil)))));
}
+#endif /* not USE_TOOLKIT_SCROLL_BARS */
start_pos_ptr = &XVECTOR (button_down_location)->contents[button];
}
}
+#if USE_TOOLKIT_SCROLL_BARS
+
+ /* We don't have down and up events if using toolkit scroll bars,
+ so make this always a click event. Store in the `part' of
+ the Lisp event a symbol which maps to the following actions:
+
+ `above_handle' page up
+ `below_handle' page down
+ `up' line up
+ `down' line down
+ `top' top of buffer
+ `bottom' bottom of buffer
+ `handle' thumb has been dragged.
+ `end-scroll' end of interaction with scroll bar
+
+ The incoming input_event contains in its `part' member an
+ index of type `enum scroll_bar_part' which we can use as an
+ index in scroll_bar_parts to get the appropriate symbol. */
+
+ case scroll_bar_click:
+ {
+ Lisp_Object position, head, window, portion_whole, part;
+
+ window = event->frame_or_window;
+ portion_whole = Fcons (event->x, event->y);
+ part = *scroll_bar_parts[(int) event->part];
+
+ position
+ = Fcons (window,
+ Fcons (Qvertical_scroll_bar,
+ Fcons (portion_whole,
+ Fcons (make_number (event->timestamp),
+ Fcons (part, Qnil)))));
+
+ /* Always treat scroll bar events as clicks. */
+ event->modifiers |= click_modifier;
+
+ /* Get the symbol we should use for the mouse click. */
+ head = modify_event_symbol (event->code,
+ event->modifiers,
+ Qmouse_click, Qnil,
+ lispy_mouse_names, &mouse_syms,
+ (sizeof (lispy_mouse_names)
+ / sizeof (lispy_mouse_names[0])));
+ return Fcons (head, Fcons (position, Qnil));
+ }
+
+#endif /* USE_TOOLKIT_SCROLL_BARS */
+
#ifdef WINDOWSNT
case w32_scroll_bar_click:
{
return Qnil;
pixel_to_glyph_coords (f, XINT (event->x), XINT (event->y),
&column, &row, NULL, 1);
- window = window_from_coordinates (f, column, row, &part);
+ window = window_from_coordinates (f, column, row, &part, 0);
if (!WINDOWP (window))
{
posn = Qmode_line;
else if (part == 2)
posn = Qvertical_line;
+ else if (part == 3)
+ posn = Qtop_line;
else
XSETINT (posn,
buffer_posn_from_coords (XWINDOW (window),
return Qnil;
pixel_to_glyph_coords (f, XINT (event->x), XINT (event->y),
&column, &row, NULL, 1);
- window = window_from_coordinates (f, column, row, &part);
+ window = window_from_coordinates (f, column, row, &part, 0);
if (!WINDOWP (window))
{
}
else
{
- int pixcolumn, pixrow;
- column -= XINT (XWINDOW (window)->left);
- row -= XINT (XWINDOW (window)->top);
- glyph_to_pixel_coords (f, column, row, &pixcolumn, &pixrow);
- XSETINT (event->x, pixcolumn);
- XSETINT (event->y, pixrow);
+ /* It's an event in window `window' at frame coordinates
+ event->x/ event->y. */
+ struct window *w = XWINDOW (window);
+
+ /* Get window relative coordinates. */
+ int wx = FRAME_TO_WINDOW_PIXEL_X (w, XINT (event->x));
+ int wy = FRAME_TO_WINDOW_PIXEL_Y (w, XINT (event->y));
+
+ /* Set event coordinates to window-relative coordinates
+ for constructing the Lisp event below. */
+ XSETINT (event->x, wx);
+ XSETINT (event->y, wy);
if (part == 1)
posn = Qmode_line;
else if (part == 2)
posn = Qvertical_line;
+ else if (part == 3)
+ posn = Qtop_line;
else
- XSETINT (posn,
- buffer_posn_from_coords (XWINDOW (window),
- column, row));
+ XSETINT (posn, buffer_posn_from_coords (w, &wx, &wy));
}
{
return XCONS (event->frame_or_window)->cdr;
#endif
+ case TOOLBAR_EVENT:
+ {
+ Lisp_Object key;
+ if (!CONSP (event->frame_or_window))
+ abort ();
+ key = XCDR (event->frame_or_window);
+ if (SYMBOLP (key))
+ key = apply_modifiers (event->modifiers, key);
+ return key;
+ }
+
+ case user_signal:
+ /* A user signal. */
+ return *lispy_user_signals[event->code];
+
/* The 'kind' field of the event is something we don't recognize. */
default:
abort ();
int area;
Lisp_Object window;
Lisp_Object posn;
- int column, row;
if (frame)
- {
- /* It's in a frame; which window on that frame? */
- pixel_to_glyph_coords (frame, XINT (x), XINT (y), &column, &row,
- NULL, 1);
- window = window_from_coordinates (frame, column, row, &area);
- }
+ /* It's in a frame; which window on that frame? */
+ window = window_from_coordinates (frame, XINT (x), XINT (y), &area, 0);
else
window = Qnil;
if (WINDOWP (window))
{
- int pixcolumn, pixrow;
- column -= WINDOW_LEFT_MARGIN (XWINDOW (window));
- row -= XINT (XWINDOW (window)->top);
- glyph_to_pixel_coords (frame, column, row, &pixcolumn, &pixrow);
- XSETINT (x, pixcolumn);
- XSETINT (y, pixrow);
-
+ struct window *w = XWINDOW (window);
+ int hpos, vpos;
+ int wx, wy;
+ int pos;
+
+ /* Get window relative coordinates. */
+ wx = FRAME_TO_WINDOW_PIXEL_X (w, XINT (x));
+ wy = FRAME_TO_WINDOW_PIXEL_Y (w, XINT (y));
+ XSETINT (x, wx);
+ XSETINT (y, wy);
+
if (area == 1)
posn = Qmode_line;
else if (area == 2)
posn = Qvertical_line;
+ else if (area == 3)
+ posn = Qtop_line;
else
- XSETINT (posn,
- buffer_posn_from_coords (XWINDOW (window), column, row));
+ XSETINT (posn, buffer_posn_from_coords (w, &wx, &wy));
}
else if (frame != 0)
{
SYMBOL's Qevent_symbol_element_mask property, and maintains the
Qevent_symbol_elements property. */
-static Lisp_Object
+Lisp_Object
parse_modifiers (symbol)
Lisp_Object symbol;
{
/* Scan one map KEYMAP, accumulating any menu items it defines
in menu_bar_items_vector. */
+static Lisp_Object menu_bar_one_keymap_changed_items;
+
static void
menu_bar_one_keymap (keymap)
Lisp_Object keymap;
{
Lisp_Object tail, item, table;
+ menu_bar_one_keymap_changed_items = Qnil;
+
/* Loop over all keymap entries that have menu strings. */
for (tail = keymap; CONSP (tail); tail = XCONS (tail)->cdr)
{
{
struct gcpro gcpro1;
int i;
+ Lisp_Object tem;
if (EQ (item, Qundefined))
{
if (!i)
return;
+ /* If this keymap has already contributed to this KEY,
+ don't contribute to it a second time. */
+ tem = Fmemq (key, menu_bar_one_keymap_changed_items);
+ if (!NILP (tem))
+ return;
+
+ menu_bar_one_keymap_changed_items
+ = Fcons (key, menu_bar_one_keymap_changed_items);
+
item = XVECTOR (item_properties)->contents[ITEM_PROPERTY_DEF];
/* Find any existing item for this KEY. */
/* Evaluate an expression and return the result (or nil if something
went wrong). Used to evaluate dynamic parts of menu items. */
-static Lisp_Object
+Lisp_Object
menu_item_eval_property (sexpr)
Lisp_Object sexpr;
{
int notreal, inmenubar;
{
Lisp_Object def, tem, item_string, start;
- Lisp_Object cachelist = Qnil;
- Lisp_Object filter = Qnil;
- Lisp_Object keyhint = Qnil;
+ Lisp_Object cachelist;
+ Lisp_Object filter;
+ Lisp_Object keyhint;
int i;
int newcache = 0;
+ cachelist = Qnil;
+ filter = Qnil;
+ keyhint = Qnil;
+
if (!CONSP (item))
return 0;
/* See if this is a separate pane or a submenu. */
def = XVECTOR (item_properties)->contents[ITEM_PROPERTY_DEF];
tem = get_keymap_1 (def, 0, 1);
+ /* For a subkeymap, just record its details and exit. */
if (!NILP (tem))
{
XVECTOR (item_properties)->contents[ITEM_PROPERTY_MAP] = tem;
XVECTOR (item_properties)->contents[ITEM_PROPERTY_DEF] = tem;
return 1;
}
- else if (inmenubar > 0)
- return 0; /* Entries in menu bar must be submenus. */
+ /* At the top level in the menu bar, do likewise for commands also.
+ The menu bar does not display equivalent key bindings anyway.
+ ITEM_PROPERTY_DEF is already set up properly. */
+ if (inmenubar > 0)
+ return 1;
/* This is a command. See if there is an equivalent key binding. */
if (NILP (cachelist))
return 1;
}
+
+
+\f
+/***********************************************************************
+ Tool-bars
+ ***********************************************************************/
+
+/* A vector holding toolbar items while they are parsed in function
+ toolbar_items runs Each item occupies TOOLBAR_ITEM_NSCLOTS
+ elements in the vector. */
+
+static Lisp_Object toolbar_items_vector;
+
+/* A vector holding the result of parse_toolbar_item. Layout is like
+ the one for a single item in toolbar_items_vector. */
+
+static Lisp_Object toolbar_item_properties;
+
+/* Next free index in toolbar_items_vector. */
+
+static int ntoolbar_items;
+
+/* The symbols `toolbar', `toolbar-item', and `:image'. */
+
+extern Lisp_Object Qtoolbar;
+Lisp_Object QCimage;
+
+/* Function prototypes. */
+
+static void init_toolbar_items P_ ((Lisp_Object));
+static void process_toolbar_item P_ ((Lisp_Object, Lisp_Object));
+static int parse_toolbar_item P_ ((Lisp_Object, Lisp_Object));
+static void append_toolbar_item P_ ((void));
+
+
+/* Return a vector of toolbar items for keymaps currently in effect.
+ Reuse vector REUSE if non-nil. Return in *NITEMS the number of
+ toolbar items found. */
+
+Lisp_Object
+toolbar_items (reuse, nitems)
+ Lisp_Object reuse;
+ int *nitems;
+{
+ Lisp_Object *maps;
+ int nmaps, i;
+ Lisp_Object oquit;
+ Lisp_Object *tmaps;
+ extern Lisp_Object Voverriding_local_map_menu_flag;
+ extern Lisp_Object Voverriding_local_map;
+
+ *nitems = 0;
+
+ /* 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
+ quitting while building the menus. We do this instead of
+ specbind because (1) errors will clear it anyway and (2) this
+ avoids risk of specpdl overflow. */
+ oquit = Vinhibit_quit;
+ Vinhibit_quit = Qt;
+
+ /* Initialize toolbar_items_vector and protect it from GC. */
+ init_toolbar_items (reuse);
+
+ /* Build list of keymaps in maps. Set nmaps to the number of maps
+ to process. */
+
+ /* Should overriding-terminal-local-map and overriding-local-map apply? */
+ if (!NILP (Voverriding_local_map_menu_flag))
+ {
+ /* Yes, use them (if non-nil) as well as the global map. */
+ maps = (Lisp_Object *) alloca (3 * sizeof (maps[0]));
+ nmaps = 0;
+ if (!NILP (current_kboard->Voverriding_terminal_local_map))
+ maps[nmaps++] = current_kboard->Voverriding_terminal_local_map;
+ if (!NILP (Voverriding_local_map))
+ maps[nmaps++] = Voverriding_local_map;
+ }
+ else
+ {
+ /* No, so use major and minor mode keymaps. */
+ nmaps = current_minor_maps (NULL, &tmaps);
+ maps = (Lisp_Object *) alloca ((nmaps + 2) * sizeof (maps[0]));
+ bcopy (tmaps, maps, nmaps * sizeof (maps[0]));
+#ifdef USE_TEXT_PROPERTIES
+ maps[nmaps++] = get_local_map (PT, current_buffer);
+#else
+ maps[nmaps++] = current_buffer->keymap;
+#endif
+ }
+
+ /* Add global keymap at the end. */
+ maps[nmaps++] = current_global_map;
+
+ /* Process maps in reverse order and look up in each map the prefix
+ key `toolbar'. */
+ for (i = nmaps - 1; i >= 0; --i)
+ if (!NILP (maps[i]))
+ {
+ Lisp_Object keymap;
+
+ keymap = get_keyelt (access_keymap (maps[i], Qtoolbar, 1, 1), 0);
+ if (!NILP (Fkeymapp (keymap)))
+ {
+ Lisp_Object tail;
+
+ /* KEYMAP is a list `(keymap (KEY . BINDING) ...)'. */
+ for (tail = keymap; CONSP (tail); tail = XCONS (tail)->cdr)
+ {
+ Lisp_Object keydef = XCAR (tail);
+ if (CONSP (keydef))
+ process_toolbar_item (XCAR (keydef), XCDR (keydef));
+ }
+ }
+ }
+
+ Vinhibit_quit = oquit;
+ *nitems = ntoolbar_items / TOOLBAR_ITEM_NSLOTS;
+ return toolbar_items_vector;
+}
+
+
+/* Process the definition of KEY which is DEF. */
+
+static void
+process_toolbar_item (key, def)
+ Lisp_Object key, def;
+{
+ int i;
+ extern Lisp_Object Qundefined;
+ struct gcpro gcpro1, gcpro2;
+
+ /* Protect KEY and DEF from GC because parse_toolbar_item may call
+ eval. */
+ GCPRO2 (key, def);
+
+ if (EQ (def, Qundefined))
+ {
+ /* If a map has an explicit `undefined' as definition,
+ discard any previously made item. */
+ for (i = 0; i < ntoolbar_items; i += TOOLBAR_ITEM_NSLOTS)
+ {
+ Lisp_Object *v = XVECTOR (toolbar_items_vector)->contents + i;
+
+ if (EQ (key, v[TOOLBAR_ITEM_KEY]))
+ {
+ if (ntoolbar_items > i + TOOLBAR_ITEM_NSLOTS)
+ bcopy (v + TOOLBAR_ITEM_NSLOTS, v,
+ ((ntoolbar_items - i - TOOLBAR_ITEM_NSLOTS)
+ * sizeof (Lisp_Object)));
+ ntoolbar_items -= TOOLBAR_ITEM_NSLOTS;
+ break;
+ }
+ }
+ }
+ else if (parse_toolbar_item (key, def))
+ /* Append a new toolbar item to toolbar_items_vector. Accept
+ more than one definition for the same key. */
+ append_toolbar_item ();
+
+ UNGCPRO;
+}
+
+
+/* Parse a toolbar item specification ITEM for key KEY and return the
+ result in toolbar_item_properties. Value is zero if ITEM is
+ invalid.
+
+ ITEM is a list `(menu-item CAPTION BINDING PROPS...)'.
+
+ CAPTION is the caption of the item, If it's not a string, it is
+ evaluated to get a string.
+
+ BINDING is the toolbar item's binding. Toolbar items with keymaps
+ as binding are currently ignored.
+
+ The following properties are recognized:
+
+ - `:enable FORM'.
+
+ FORM is evaluated and specifies whether the toolbar item is enabled
+ or disabled.
+
+ - `:visible FORM'
+
+ FORM is evaluated and specifies whether the toolbar item is visible.
+
+ - `:filter FUNCTION'
+
+ FUNCTION is invoked with one parameter `(quote BINDING)'. Its
+ result is stored as the new binding.
+
+ - `:button (TYPE SELECTED)'
+
+ TYPE must be one of `:radio' or `:toggle'. SELECTED is evaluated
+ and specifies whether the button is selected (pressed) or not.
+
+ - `:image IMAGES'
+
+ IMAGES is either a single image specification or a vector of four
+ image specifications. See enum toolbar_item_images.
+
+ - `:help HELP-STRING'.
+
+ Gives a help string to display for the toolbar item. */
+
+static int
+parse_toolbar_item (key, item)
+ Lisp_Object key, item;
+{
+ /* Access slot with index IDX of vector toolbar_item_properties. */
+#define PROP(IDX) XVECTOR (toolbar_item_properties)->contents[IDX]
+
+ Lisp_Object filter = Qnil;
+ Lisp_Object caption;
+ extern Lisp_Object QCenable, QCvisible, QChelp, QCfilter;
+ extern Lisp_Object QCbutton, QCtoggle, QCradio;
+ int i;
+ struct gcpro gcpro1;
+
+ /* Defininition looks like `(toolbar-item CAPTION BINDING
+ PROPS...)'. Rule out items that aren't lists, don't start with
+ `toolbar-item' or whose rest following `toolbar-item' is not a
+ list. */
+ if (!CONSP (item)
+ || !EQ (XCAR (item), Qmenu_item)
+ || (item = XCDR (item),
+ !CONSP (item)))
+ return 0;
+
+ /* Create toolbar_item_properties vector if necessary. Reset it to
+ defaults. */
+ if (VECTORP (toolbar_item_properties))
+ {
+ for (i = 0; i < TOOLBAR_ITEM_NSLOTS; ++i)
+ PROP (i) = Qnil;
+ }
+ else
+ toolbar_item_properties
+ = Fmake_vector (make_number (TOOLBAR_ITEM_NSLOTS), Qnil);
+
+ /* Set defaults. */
+ PROP (TOOLBAR_ITEM_KEY) = key;
+ PROP (TOOLBAR_ITEM_ENABLED_P) = Qt;
+
+ /* Get the caption of the item. If the caption is not a string,
+ evaluate it to get a string. If we don't get a string, skip this
+ item. */
+ caption = XCAR (item);
+ if (!STRINGP (caption))
+ {
+ caption = menu_item_eval_property (caption);
+ if (!STRINGP (caption))
+ return 0;
+ }
+ PROP (TOOLBAR_ITEM_CAPTION) = caption;
+
+ /* Give up if rest following the caption is not a list. */
+ item = XCDR (item);
+ if (!CONSP (item))
+ return 0;
+
+ /* Store the binding. */
+ PROP (TOOLBAR_ITEM_BINDING) = XCAR (item);
+ item = XCDR (item);
+
+ /* Process the rest of the properties. */
+ for (; CONSP (item) && CONSP (XCDR (item)); item = XCDR (XCDR (item)))
+ {
+ Lisp_Object key, value;
+
+ key = XCAR (item);
+ value = XCAR (XCDR (item));
+
+ if (EQ (key, QCenable))
+ /* `:enable FORM'. */
+ PROP (TOOLBAR_ITEM_ENABLED_P) = value;
+ else if (EQ (key, QCvisible))
+ {
+ /* `:visible FORM'. If got a visible property and that
+ evaluates to nil then ignore this item. */
+ if (NILP (menu_item_eval_property (value)))
+ return 0;
+ }
+ else if (EQ (key, QChelp))
+ /* `:help HELP-STRING'. */
+ PROP (TOOLBAR_ITEM_HELP) = value;
+ else if (EQ (key, QCfilter))
+ /* ':filter FORM'. */
+ filter = value;
+ else if (EQ (key, QCbutton) && CONSP (value))
+ {
+ /* `:button (TYPE . SELECTED)'. */
+ Lisp_Object type, selected;
+
+ type = XCAR (value);
+ selected = XCDR (value);
+ if (EQ (type, QCtoggle) || EQ (type, QCradio))
+ {
+ PROP (TOOLBAR_ITEM_SELECTED_P) = selected;
+ PROP (TOOLBAR_ITEM_TYPE) = type;
+ }
+ }
+ else if (EQ (key, QCimage)
+ && (CONSP (value)
+ || (VECTORP (value) && XVECTOR (value)->size == 4)))
+ /* Value is either a single image specification or a vector
+ of 4 such specifications for the different buttion states. */
+ PROP (TOOLBAR_ITEM_IMAGES) = value;
+ }
+
+ /* If got a filter apply it on binding. */
+ if (!NILP (filter))
+ PROP (TOOLBAR_ITEM_BINDING)
+ = menu_item_eval_property (list2 (filter,
+ list2 (Qquote,
+ PROP (TOOLBAR_ITEM_BINDING))));
+
+ /* See if the binding is a keymap. Give up if it is. */
+ if (!NILP (get_keymap_1 (PROP (TOOLBAR_ITEM_BINDING), 0, 1)))
+ return 0;
+
+ /* Enable or disable selection of item. */
+ if (!EQ (PROP (TOOLBAR_ITEM_ENABLED_P), Qt))
+ PROP (TOOLBAR_ITEM_ENABLED_P)
+ = menu_item_eval_property (PROP (TOOLBAR_ITEM_ENABLED_P));
+
+ /* Handle radio buttons or toggle boxes. */
+ if (!NILP (PROP (TOOLBAR_ITEM_SELECTED_P)))
+ PROP (TOOLBAR_ITEM_SELECTED_P)
+ = menu_item_eval_property (PROP (TOOLBAR_ITEM_SELECTED_P));
+
+ return 1;
+
+#undef PROP
+}
+
+
+/* Initialize Vtoolbar_items. REUSE, if non-nil, is a vector that can
+ be reused. */
+
+static void
+init_toolbar_items (reuse)
+ Lisp_Object reuse;
+{
+ if (VECTORP (reuse))
+ toolbar_items_vector = reuse;
+ else
+ toolbar_items_vector = Fmake_vector (make_number (64), Qnil);
+ ntoolbar_items = 0;
+}
+
+
+/* Append parsed toolbar item properties from toolbar_item_properties */
+
+static void
+append_toolbar_item ()
+{
+ Lisp_Object *to, *from;
+
+ /* Enlarge toolbar_items_vector if necessary. */
+ if (ntoolbar_items + TOOLBAR_ITEM_NSLOTS
+ >= XVECTOR (toolbar_items_vector)->size)
+ {
+ Lisp_Object new_vector;
+ int old_size = XVECTOR (toolbar_items_vector)->size;
+
+ new_vector = Fmake_vector (make_number (2 * old_size), Qnil);
+ bcopy (XVECTOR (toolbar_items_vector)->contents,
+ XVECTOR (new_vector)->contents,
+ old_size * sizeof (Lisp_Object));
+ toolbar_items_vector = new_vector;
+ }
+
+ /* Append entries from toolbar_item_properties to the end of
+ toolbar_items_vector. */
+ to = XVECTOR (toolbar_items_vector)->contents + ntoolbar_items;
+ from = XVECTOR (toolbar_item_properties)->contents;
+ bcopy (from, to, TOOLBAR_ITEM_NSLOTS * sizeof *to);
+ ntoolbar_items += TOOLBAR_ITEM_NSLOTS;
+}
+
+
+
+
\f
/* Read a character using menus based on maps in the array MAPS.
NMAPS is the length of MAPS. Return nil if there are no menus in the maps.
/* If we got to this point via a mouse click,
use a real menu for mouse selection. */
if (EVENT_HAS_PARAMETERS (prev_event)
- && !EQ (XCONS (prev_event)->car, Qmenu_bar))
+ && !EQ (XCONS (prev_event)->car, Qmenu_bar)
+ && !EQ (XCONS (prev_event)->car, Qtoolbar))
{
/* Display the menu and get the selection. */
Lisp_Object *realmaps
int junk;
+ raw_keybuf_count = 0;
+
last_nonmenu_event = Qnil;
delayed_switch_frame = Qnil;
/* read_char returns t when it shows a menu and the user rejects it.
Just return -1. */
if (EQ (key, Qt))
- return -1;
+ {
+ unbind_to (count, Qnil);
+ return -1;
+ }
/* read_char returns -1 at the end of a macro.
Emacs 18 handles this by returning immediately with a
This is to be more consistent with the behavior
of the command_loop_1. */
if (fix_current_buffer)
- if (XBUFFER (XWINDOW (selected_window)->buffer) != current_buffer)
- Fset_buffer (XWINDOW (selected_window)->buffer);
+ {
+ if (! FRAME_LIVE_P (selected_frame))
+ Fkill_emacs (Qnil);
+ if (XBUFFER (XWINDOW (selected_window)->buffer) != current_buffer)
+ Fset_buffer (XWINDOW (selected_window)->buffer);
+ }
orig_local_map = get_local_map (PT, current_buffer);
goto replay_sequence;
replay to get the right keymap. */
if (XINT (key) == quit_char && current_buffer != starting_buffer)
{
+ GROW_RAW_KEYBUF;
+ XVECTOR (raw_keybuf)->contents[raw_keybuf_count++] = key;
keybuf[t++] = key;
mock_input = t;
Vquit_flag = Qnil;
}
Vquit_flag = Qnil;
+
+ if (EVENT_HAS_PARAMETERS (key)
+ && EQ (EVENT_HEAD_KIND (EVENT_HEAD (key)), Qswitch_frame))
+ {
+ /* If we're at the beginning of a key sequence, and the caller
+ says it's okay, go ahead and return this event. If we're
+ in the midst of a key sequence, delay it until the end. */
+ if (t > 0 || !can_return_switch_frame)
+ {
+ delayed_switch_frame = key;
+ goto replay_key;
+ }
+ }
+
+ GROW_RAW_KEYBUF;
+ XVECTOR (raw_keybuf)->contents[raw_keybuf_count++] = key;
}
/* Clicks in non-text areas get prefixed by the symbol
window = POSN_WINDOW (EVENT_START (key));
posn = POSN_BUFFER_POSN (EVENT_START (key));
+
if (CONSP (posn))
{
/* We're looking at the second event of a
&& BUFFERP (XWINDOW (window)->buffer)
&& XBUFFER (XWINDOW (window)->buffer) != current_buffer)
{
+ XVECTOR (raw_keybuf)->contents[raw_keybuf_count++] = key;
keybuf[t] = key;
mock_input = t + 1;
emacsclient). */
record_unwind_protect (Fset_buffer, Fcurrent_buffer ());
+ if (! FRAME_LIVE_P (selected_frame))
+ Fkill_emacs (Qnil);
set_buffer_internal (XBUFFER (XWINDOW (window)->buffer));
orig_local_map = get_local_map (PT, current_buffer);
goto replay_sequence;
}
+
/* For a mouse click, get the local text-property keymap
of the place clicked on, rather than point. */
- if (last_real_key_start == 0 && CONSP (XCONS (key)->cdr)
+ if (last_real_key_start == 0
+ && CONSP (XCONS (key)->cdr)
&& ! localized_local_map)
{
Lisp_Object map_here, start, pos;
localized_local_map = 1;
start = EVENT_START (key);
+
if (CONSP (start) && CONSP (XCONS (start)->cdr))
{
pos = POSN_BUFFER_POSN (start);
keybuf[t] = posn;
keybuf[t+1] = key;
mock_input = t + 2;
-
+
/* Zap the position in key, so we know that we've
expanded it, and don't try to do so again. */
POSN_BUFFER_POSN (EVENT_START (key))
= Fcons (posn, Qnil);
- goto replay_key;
- }
- }
- else if (EQ (kind, Qswitch_frame))
- {
- /* If we're at the beginning of a key sequence, and the caller
- says it's okay, go ahead and return this event. If we're
- in the midst of a key sequence, delay it until the end. */
- if (t > 0 || !can_return_switch_frame)
- {
- delayed_switch_frame = key;
+
+ /* If on a mode line string with a local keymap,
+ reconsider the key sequence with that keymap. */
+ if (CONSP (POSN_STRING (EVENT_START (key))))
+ {
+ Lisp_Object string, pos, map;
+
+ string = POSN_STRING (EVENT_START (key));
+ pos = XCDR (string);
+ string = XCAR (string);
+
+ if (pos >= 0
+ && pos < XSTRING (string)->size
+ && (map = Fget_text_property (pos, Qlocal_map,
+ string),
+ !NILP (map)))
+ {
+ orig_local_map = map;
+ goto replay_sequence;
+ }
+ }
+
goto replay_key;
}
}
posn = POSN_BUFFER_POSN (EVENT_START (key));
/* Handle menu-bar events:
insert the dummy prefix event `menu-bar'. */
- if (EQ (posn, Qmenu_bar))
+ if (EQ (posn, Qmenu_bar) || EQ (posn, Qtoolbar))
{
if (t + 1 >= bufsize)
error ("Key sequence too long");
fkey_next = fkey_map;
fkey_next
- = get_keyelt (access_keymap (fkey_next, key, 1, 0), 0);
+ = get_keyelt (access_keymap (fkey_next, key, 1, 0), 1);
+
+ /* Handle symbol with autoload definition. */
+ if (SYMBOLP (fkey_next) && ! NILP (Ffboundp (fkey_next))
+ && CONSP (XSYMBOL (fkey_next)->function)
+ && EQ (XCONS (XSYMBOL (fkey_next)->function)->car, Qautoload))
+ do_autoload (XSYMBOL (fkey_next)->function,
+ fkey_next);
+
+ /* Handle a symbol whose function definition is a keymap
+ or an array. */
+ if (SYMBOLP (fkey_next) && ! NILP (Ffboundp (fkey_next))
+ && (!NILP (Farrayp (XSYMBOL (fkey_next)->function))
+ || !NILP (Fkeymapp (XSYMBOL (fkey_next)->function))))
+ fkey_next = XSYMBOL (fkey_next)->function;
#if 0 /* I didn't turn this on, because it might cause trouble
for the mapping of return into C-m and tab into C-i. */
fkey_start = fkey_end = t;
fkey_map = Vfunction_key_map;
- /* Do pass the results through key-translation-map. */
- keytran_start = keytran_end = 0;
+ /* Do pass the results through key-translation-map.
+ But don't retranslate what key-translation-map
+ has already translated. */
+ keytran_end = keytran_start;
keytran_map = Vkey_translation_map;
goto replay_sequence;
keytran_next = keytran_map;
keytran_next
- = get_keyelt (access_keymap (keytran_next, key, 1, 0), 0);
+ = get_keyelt (access_keymap (keytran_next, key, 1, 0), 1);
+ /* Handle symbol with autoload definition. */
+ if (SYMBOLP (keytran_next) && ! NILP (Ffboundp (keytran_next))
+ && CONSP (XSYMBOL (keytran_next)->function)
+ && EQ (XCONS (XSYMBOL (keytran_next)->function)->car, Qautoload))
+ do_autoload (XSYMBOL (keytran_next)->function,
+ keytran_next);
+
+ /* Handle a symbol whose function definition is a keymap
+ or an array. */
+ if (SYMBOLP (keytran_next) && ! NILP (Ffboundp (keytran_next))
+ && (!NILP (Farrayp (XSYMBOL (keytran_next)->function))
+ || !NILP (Fkeymapp (XSYMBOL (keytran_next)->function))))
+ keytran_next = XSYMBOL (keytran_next)->function;
+
/* If the key translation map gives a function, not an
- array, then call the function with no args and use
+ array, then call the function with one arg and use
its value instead. */
if (SYMBOLP (keytran_next) && ! NILP (Ffboundp (keytran_next))
&& keytran_end == t)
/* Don't pass the results of key-translation-map
through function-key-map. */
fkey_start = fkey_end = t;
- fkey_map = Vkey_translation_map;
+ fkey_map = Vfunction_key_map;
goto replay_sequence;
}
add_command_key (keybuf[t]);
}
+
+
return t;
}
\n\
`read-key-sequence' checks `function-key-map' for function key\n\
sequences, where they wouldn't conflict with ordinary bindings. See\n\
-`function-key-map' for more details.")
- (prompt, continue_echo, dont_downcase_last, can_return_switch_frame)
+`function-key-map' for more details.\n\
+\n\
+The optional fifth argument COMMAND-LOOP, if non-nil, means\n\
+that this key sequence is being read by something that will\n\
+read commands one after another. It should be nil if the caller\n\
+will read just one key sequence.")
+ (prompt, continue_echo, dont_downcase_last, can_return_switch_frame, command-loop)
#endif
-DEFUN ("read-key-sequence", Fread_key_sequence, Sread_key_sequence, 1, 4, 0,
+DEFUN ("read-key-sequence", Fread_key_sequence, Sread_key_sequence, 1, 5, 0,
0)
- (prompt, continue_echo, dont_downcase_last, can_return_switch_frame)
+ (prompt, continue_echo, dont_downcase_last, can_return_switch_frame,
+ command_loop)
Lisp_Object prompt, continue_echo, dont_downcase_last;
- Lisp_Object can_return_switch_frame;
+ Lisp_Object can_return_switch_frame, command_loop;
{
Lisp_Object keybuf[30];
register int i;
struct gcpro gcpro1, gcpro2;
+ int count = specpdl_ptr - specpdl;
if (!NILP (prompt))
CHECK_STRING (prompt, 0);
QUIT;
+ specbind (Qinput_method_exit_on_first_char,
+ (NILP (command_loop) ? Qt : Qnil));
+ specbind (Qinput_method_use_echo_area,
+ (NILP (command_loop) ? Qt : Qnil));
+
bzero (keybuf, sizeof keybuf);
GCPRO1 (keybuf[0]);
gcpro1.nvars = (sizeof keybuf/sizeof (keybuf[0]));
QUIT;
}
UNGCPRO;
- return make_event_array (i, keybuf);
+ return unbind_to (count, make_event_array (i, keybuf));
}
DEFUN ("read-key-sequence-vector", Fread_key_sequence_vector,
- Sread_key_sequence_vector, 1, 4, 0,
+ Sread_key_sequence_vector, 1, 5, 0,
"Like `read-key-sequence' but always return a vector.")
- (prompt, continue_echo, dont_downcase_last, can_return_switch_frame)
+ (prompt, continue_echo, dont_downcase_last, can_return_switch_frame,
+ command_loop)
Lisp_Object prompt, continue_echo, dont_downcase_last;
- Lisp_Object can_return_switch_frame;
+ Lisp_Object can_return_switch_frame, command_loop;
{
Lisp_Object keybuf[30];
register int i;
struct gcpro gcpro1, gcpro2;
+ int count = specpdl_ptr - specpdl;
if (!NILP (prompt))
CHECK_STRING (prompt, 0);
QUIT;
+ specbind (Qinput_method_exit_on_first_char,
+ (NILP (command_loop) ? Qt : Qnil));
+ specbind (Qinput_method_use_echo_area,
+ (NILP (command_loop) ? Qt : Qnil));
+
bzero (keybuf, sizeof keybuf);
GCPRO1 (keybuf[0]);
gcpro1.nvars = (sizeof keybuf/sizeof (keybuf[0]));
QUIT;
}
UNGCPRO;
- return Fvector (i, keybuf);
+ return unbind_to (count, Fvector (i, keybuf));
}
\f
DEFUN ("command-execute", Fcommand_execute, Scommand_execute, 1, 4, 0,
function = Fintern (function, Qnil);
current_kboard->Vprefix_arg = prefixarg;
- this_command = function;
+ Vthis_command = function;
+ real_this_command = function;
/* If enabled, show which key runs this command. */
if (!NILP (Vsuggest_key_bindings)
Qmouse_movement)))
{
/* But first wait, and skip the message if there is input. */
- if (!NILP (Fsit_for ((NUMBERP (Vsuggest_key_bindings)
- ? Vsuggest_key_bindings : make_number (2)),
- Qnil, Qnil))
+ int delay_time;
+ if (!NILP (echo_area_buffer[0]))
+ /* This command displayed something in the echo area;
+ so wait a few seconds, then display our suggestion message. */
+ delay_time = (NUMBERP (Vsuggest_key_bindings)
+ ? XINT (Vsuggest_key_bindings) : 2);
+ else
+ /* This command left the echo area empty,
+ so display our message immediately. */
+ delay_time = 0;
+
+ if (!NILP (Fsit_for (make_number (delay_time), Qnil, Qnil))
&& ! CONSP (Vunread_command_events))
{
Lisp_Object binding;
char *newmessage;
- char *oldmessage = echo_area_glyphs;
- int oldmessage_len = echo_area_glyphs_length;
- int oldmultibyte = message_enable_multibyte;
+ int message_p = push_message ();
binding = Fkey_description (bindings);
STRING_MULTIBYTE (binding));
if (!NILP (Fsit_for ((NUMBERP (Vsuggest_key_bindings)
? Vsuggest_key_bindings : make_number (2)),
- Qnil, Qnil)))
- message2_nolog (oldmessage, oldmessage_len, oldmultibyte);
+ Qnil, Qnil))
+ && message_p)
+ restore_message ();
+
+ pop_message ();
}
}
get_input_pending (&input_pending, 1);
if (old_timers_run != timers_run && do_display)
- redisplay_preserve_echo_area ();
+ {
+ redisplay_preserve_echo_area ();
+ /* 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. */
+ if (rif)
+ rif->flush_display (NULL);
+ }
return input_pending;
}
+ this_single_command_key_start));
}
+DEFUN ("this-single-command-raw-keys", Fthis_single_command_raw_keys,
+ Sthis_single_command_raw_keys, 0, 0, 0,
+ "Return the raw events that were read for this command.\n\
+Unlike `this-single-command-keys', this function's value\n\
+shows the events before all translations (except for input methods).\n\
+The value is always a vector.")
+ ()
+{
+ return Fvector (raw_keybuf_count,
+ (XVECTOR (raw_keybuf)->contents));
+}
+
DEFUN ("reset-this-command-lengths", Freset_this_command_lengths,
Sreset_this_command_lengths, 0, 0, 0,
"Used for complicated reasons in `universal-argument-other-key'.\n\
before_command_restore_flag = 1;
before_command_key_count_1 = before_command_key_count;
before_command_echo_length_1 = before_command_echo_length;
+ return Qnil;
+}
+
+DEFUN ("clear-this-command-keys", Fclear_this_command_keys,
+ Sclear_this_command_keys, 0, 0, 0,
+ "Clear out the vector that `this-command-keys' returns.")
+ ()
+{
+ this_command_key_count = 0;
+ return Qnil;
}
DEFUN ("recursion-depth", Frecursion_depth, Srecursion_depth, 0, 0, 0,
discard_tty_input ();
- /* Without the cast, GCC complains that this assignment loses the
- volatile qualifier of kbd_store_ptr. Is there anything wrong
- with that? */
- kbd_fetch_ptr = (struct input_event *) kbd_store_ptr;
+ kbd_fetch_ptr = kbd_store_ptr;
Ffillarray (kbd_buffer_frame_or_window, Qnil);
input_pending = 0;
with a window system; but suspend should be disabled in that case. */
get_frame_size (&width, &height);
if (width != old_width || height != old_height)
- change_frame_size (selected_frame, height, width, 0, 0);
+ change_frame_size (selected_frame, height, width, 0, 0, 0);
/* Run suspend-resume-hook. */
if (!NILP (Vrun_hooks))
void
quit_throw_to_read_char ()
{
- quit_error_check ();
sigfree ();
/* Prevent another signal from doing this before we finish. */
clear_waiting_for_input ();
void
syms_of_keyboard ()
{
+ /* Toolbars. */
+ QCimage = intern (":image");
+ staticpro (&QCimage);
+
+ staticpro (&Qhelp_echo);
+ Qhelp_echo = intern ("help-echo");
+
staticpro (&item_properties);
item_properties = Qnil;
+ staticpro (&toolbar_item_properties);
+ toolbar_item_properties = Qnil;
+ staticpro (&toolbar_items_vector);
+ toolbar_items_vector = Qnil;
+
+ staticpro (&real_this_command);
+ real_this_command = Qnil;
+
Qtimer_event_handler = intern ("timer-event-handler");
staticpro (&Qtimer_event_handler);
#ifdef WINDOWSNT
Qmouse_wheel = intern ("mouse-wheel");
staticpro (&Qmouse_wheel);
+ Qlanguage_change = intern ("language-change");
+ staticpro (&Qlanguage_change);
#endif
Qdrag_n_drop = intern ("drag-n-drop");
staticpro (&Qdrag_n_drop);
+ Qusr1_signal = intern ("usr1-signal");
+ staticpro (&Qusr1_signal);
+ Qusr2_signal = intern ("usr2-signal");
+ staticpro (&Qusr2_signal);
+
Qmenu_enable = intern ("menu-enable");
staticpro (&Qmenu_enable);
Qmenu_alias = intern ("menu-alias");
staticpro (&QCenable);
QCvisible = intern (":visible");
staticpro (&QCvisible);
+ QChelp = intern (":help");
+ staticpro (&QChelp);
QCfilter = intern (":filter");
staticpro (&QCfilter);
QCbutton = intern (":button");
staticpro (&Qup);
Qdown = intern ("down");
staticpro (&Qdown);
+ Qtop = intern ("top");
+ staticpro (&Qtop);
+ Qbottom = intern ("bottom");
+ staticpro (&Qbottom);
+ Qend_scroll = intern ("end-scroll");
+ staticpro (&Qend_scroll);
Qevent_kind = intern ("event-kind");
staticpro (&Qevent_kind);
Qpolling_period = intern ("polling-period");
staticpro (&Qpolling_period);
+ Qinput_method_function = intern ("input-method-function");
+ staticpro (&Qinput_method_function);
+
+ Qinput_method_exit_on_first_char = intern ("input-method-exit-on-first-char");
+ staticpro (&Qinput_method_exit_on_first_char);
+ Qinput_method_use_echo_area = intern ("input-method-use-echo-area");
+ staticpro (&Qinput_method_use_echo_area);
+
+ Fset (Qinput_method_exit_on_first_char, Qnil);
+ Fset (Qinput_method_use_echo_area, Qnil);
+
{
struct event_head *p;
this_command_keys = Fmake_vector (make_number (40), Qnil);
staticpro (&this_command_keys);
+ raw_keybuf = Fmake_vector (make_number (30), Qnil);
+ staticpro (&raw_keybuf);
+
Qextended_command_history = intern ("extended-command-history");
Fset (Qextended_command_history, Qnil);
staticpro (&Qextended_command_history);
read_key_sequence_cmd = Qnil;
staticpro (&read_key_sequence_cmd);
+ menu_bar_one_keymap_changed_items = Qnil;
+ staticpro (&menu_bar_one_keymap_changed_items);
+
defsubr (&Sevent_convert_list);
defsubr (&Sread_key_sequence);
defsubr (&Sread_key_sequence_vector);
defsubr (&Sthis_command_keys);
defsubr (&Sthis_command_keys_vector);
defsubr (&Sthis_single_command_keys);
+ defsubr (&Sthis_single_command_raw_keys);
defsubr (&Sreset_this_command_lengths);
+ defsubr (&Sclear_this_command_keys);
defsubr (&Ssuspend_emacs);
defsubr (&Sabort_recursive_edit);
defsubr (&Sexit_recursive_edit);
"Last input event.");
DEFVAR_LISP ("unread-command-events", &Vunread_command_events,
- "List of objects to be read as next command input events.");
+ "List of events to be read as the command input.\n\
+These events are processed first, before actual keyboard input.");
+ Vunread_command_events = Qnil;
DEFVAR_INT ("unread-command-char", &unread_command_char,
"If not -1, an object to be read as next command input event.");
+ DEFVAR_LISP ("unread-post-input-method-events", &Vunread_post_input_method_events,
+ "List of events to be processed as input by input methods.\n\
+These events are processed after `unread-command-events', but\n\
+before actual keyboard input.");
+ Vunread_post_input_method_events = Qnil;
+
+ DEFVAR_LISP ("unread-input-method-events", &Vunread_input_method_events,
+ "List of events to be processed as input by input methods.\n\
+These events are processed after `unread-command-events', but\n\
+before actual keyboard input.");
+ Vunread_input_method_events = Qnil;
+
DEFVAR_LISP ("meta-prefix-char", &meta_prefix_char,
- "Meta-prefix character code. Meta-foo as command input\n\
-turns into this character followed by foo.");
+ "Meta-prefix character code.\n\
+Meta-foo as command input turns into this character followed by foo.");
XSETINT (meta_prefix_char, 033);
DEFVAR_KBOARD ("last-command", Vlast_command,
- "The last command executed. Normally a symbol with a function definition,\n\
-but can be whatever was found in the keymap, or whatever the variable\n\
-`this-command' was set to by that command.\n\
+ "The last command executed.\n\
+Normally a symbol with a function definition, but can be whatever was found\n\
+in the keymap, or whatever the variable `this-command' was set to by that\n\
+command.\n\
\n\
The value `mode-exit' is special; it means that the previous command\n\
read an event that told it to exit, and it did so and unread that event.\n\
DEFVAR_KBOARD ("real-last-command", Vreal_last_command,
"Same as `last-command', but never altered by Lisp code.");
- DEFVAR_LISP ("this-command", &this_command,
+ DEFVAR_LISP ("this-command", &Vthis_command,
"The command now being executed.\n\
The command can set this variable; whatever is put here\n\
will be in `last-command' during the following command.");
- this_command = Qnil;
+ Vthis_command = Qnil;
DEFVAR_INT ("auto-save-interval", &auto_save_interval,
"*Number of keyboard input characters between auto-saves.\n\
Vkeyboard_translate_table = Qnil;
DEFVAR_BOOL ("cannot-suspend", &cannot_suspend,
- "Non-nil means to always spawn a subshell instead of suspending,\n\
-even if the operating system has support for stopping a process.");
+ "Non-nil means to always spawn a subshell instead of suspending.\n\
+\(Even if the operating system has support for stopping a process.\)");
cannot_suspend = 0;
DEFVAR_BOOL ("menu-prompting", &menu_prompting,
DEFVAR_LISP ("pre-command-hook", &Vpre_command_hook,
"Normal hook run before each command is executed.\n\
-Errors running the hook are caught and ignored.");
+If an unhandled error happens in running this hook,\n\
+the hook value is set to nil, since otherwise the error\n\
+might happen repeatedly and make Emacs nonfunctional.");
Vpre_command_hook = Qnil;
DEFVAR_LISP ("post-command-hook", &Vpost_command_hook,
"Normal hook run after each command is executed.\n\
-Errors running the hook are caught and ignored.");
+If an unhandled error happens in running this hook,\n\
+the hook value is set to nil, since otherwise the error\n\
+might happen repeatedly and make Emacs nonfunctional.");
Vpost_command_hook = Qnil;
DEFVAR_LISP ("post-command-idle-hook", &Vpost_command_idle_hook,
DEFVAR_LISP ("timer-idle-list", &Vtimer_idle_list,
"List of active idle-time timers in order of increasing time");
Vtimer_idle_list = Qnil;
+
+ DEFVAR_LISP ("input-method-function", &Vinput_method_function,
+ "If non-nil, the function that implements the current input method.\n\
+It's called with one argument, a printing character that was just read.\n\
+\(That means a character with code 040...0176.)\n\
+Typically this function uses `read-event' to read additional events.\n\
+When it does so, it should first bind `input-method-function' to nil\n\
+so it will not be called recursively.\n\
+\n\
+The function should return a list of zero or more events\n\
+to be used as input. If it wants to put back some events\n\
+to be reconsidered, separately, by the input method,\n\
+it can add them to the beginning of `unread-command-events'.\n\
+\n\
+The input method function can find in `input-method-previous-method'\n\
+the previous echo area message.\n\
+\n\
+The input method function should refer to the variables\n\
+`input-method-use-echo-area' and `input-method-exit-on-first-char'\n\
+for guidance on what to do.");
+ Vinput_method_function = Qnil;
+
+ DEFVAR_LISP ("input-method-previous-message",
+ &Vinput_method_previous_message,
+ "When `input-method-function' is called, hold the previous echo area message.\n\
+This variable exists because `read-event' clears the echo area\n\
+before running the input method. It is nil if there was no message.");
+ Vinput_method_previous_message = Qnil;
+
+ DEFVAR_LISP ("show-help-function", &Vshow_help_function,
+ "If non-nil, the function that implements the display of help.\n\
+It's called with one argument, the help string to display.");
+ Vshow_help_function = Qnil;
}
void