/* Keyboard and mouse input; editor command loop.
- Copyright (C) 1985,86,87,88,89,93,94,95,96,97 Free Software Foundation, Inc.
+ Copyright (C) 1985,86,87,88,89,93,94,95,96,97,99 Free Software Foundation, Inc.
This file is part of GNU Emacs.
the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
Boston, MA 02111-1307, USA. */
-/* Allow config.h to undefine symbols found here. */
-#include <signal.h>
-
#include <config.h>
+#include <signal.h>
#include <stdio.h>
#include "termchar.h"
#include "termopts.h"
#include "syssignal.h"
#include "systty.h"
+#include <sys/types.h>
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+
/* This is to get the definitions of the XK_ symbols. */
#ifdef HAVE_X_WINDOWS
#include "xterm.h"
#ifdef HAVE_WINDOW_SYSTEM
/* Make all keyboard buffers much bigger when using X windows. */
+#ifdef macintosh
+/* But not too big (local data > 32K error) if on macintosh */
+#define KBD_BUFFER_SIZE 512
+#else
#define KBD_BUFFER_SIZE 4096
+#endif
#else /* No X-windows, character input */
#define KBD_BUFFER_SIZE 256
#endif /* No X-windows */
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;
/* 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. */
()
{
int count = specpdl_ptr - specpdl;
- Lisp_Object val;
command_loop_level++;
update_mode_lines = 1;
char *context;
{
Lisp_Object stream;
+ int kill_emacs_p = 0;
+ struct frame *sf = SELECTED_FRAME ();
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 (!sf->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 (sf))
|| 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)
{
- Lisp_Object val = internal_catch (Qexit, command_loop_2, Qnil);
+ Lisp_Object val;
+ val = internal_catch (Qexit, command_loop_2, Qnil);
executing_macro = Qnil;
return val;
}
Lisp_Object
command_loop_1 ()
{
- Lisp_Object cmd, tem;
- int lose, lose2;
+ Lisp_Object cmd;
+ int lose;
int nonundocount;
Lisp_Object keybuf[30];
int i;
if (!NILP (Vpost_command_hook) && !NILP (Vrun_hooks))
safe_run_hooks (Qpost_command_hook);
+ /* If displaying a message, resize the echo area window to fit
+ that message's size exactly. */
+ if (!NILP (echo_area_buffer[0]))
+ resize_echo_area_axactly ();
+
if (!NILP (Vdeferred_action_list))
call0 (Vdeferred_action_function);
while (1)
{
+ if (! FRAME_LIVE_P (XFRAME (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
code swallows a switch-frame event, we'll fix things up here.
Is this a good idea? */
if (FRAMEP (internal_last_event_frame)
- && XFRAME (internal_last_event_frame) != selected_frame)
+ && !EQ (internal_last_event_frame, selected_frame))
Fselect_frame (internal_last_event_frame, Qnil);
#endif
/* If it has changed current-menubar from previous value,
Qnil, 0, 1, 1);
/* A filter may have run while we were reading the input. */
+ if (! FRAME_LIVE_P (XFRAME (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;
{
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 ();
if (!NILP (Vpost_command_hook) && !NILP (Vrun_hooks))
safe_run_hooks (Qpost_command_hook);
+ /* If displaying a message, resize the echo area window to fit
+ that message's size exactly. */
+ if (!NILP (echo_area_buffer[0]))
+ resize_echo_area_axactly ();
+
if (!NILP (Vdeferred_action_list))
safe_run_hooks (Qdeferred_action_function);
safe_run_hooks (hook)
Lisp_Object hook;
{
- Lisp_Object value;
int count = specpdl_ptr - specpdl;
specbind (Qinhibit_quit, hook);
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 echo_area_message;
+ Lisp_Object previous_echo_area_message;
Lisp_Object also_record;
int reread;
struct gcpro gcpro1, gcpro2;
before_command_key_count = this_command_key_count;
before_command_echo_length = echo_length ();
c = Qnil;
- echo_area_message = Qnil;
+ previous_echo_area_message = Qnil;
- GCPRO2 (c, echo_area_message);
+ GCPRO2 (c, previous_echo_area_message);
retry:
}
/* 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 (_setjmp (local_getcjmp))
{
XSETINT (c, quit_char);
- XSETFRAME (internal_last_event_frame, selected_frame);
+ internal_last_event_frame = selected_frame;
Vlast_event_frame = internal_last_event_frame;
/* If we report the quit char as an event,
don't do so more than once. */
#ifdef MULTI_KBOARD
{
- KBOARD *kb = FRAME_KBOARD (selected_frame);
+ KBOARD *kb = FRAME_KBOARD (XFRAME (selected_frame));
if (kb != current_kboard)
{
Lisp_Object *tailp = &kb->kbd_queue;
/* 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, Qtool_bar)
/* Don't bring up a menu if we already have another event. */
&& NILP (Vunread_command_events)
&& unread_command_char < 0)
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, Qtool_bar))
{
/* Change menu-bar to (menu-bar) as the event "position". */
POSN_BUFFER_POSN (EVENT_START (c)) = Fcons (posn, Qnil);
&& ! NILP (Vinput_method_function)
&& (unsigned) XINT (c) >= ' '
&& (unsigned) XINT (c) < 127)
- Vinput_method_previous_message = echo_area_message = Fcurrent_message ();
+ {
+ previous_echo_area_message = Fcurrent_message ();
+ Vinput_method_previous_message = previous_echo_area_message;
+ }
/* Now wipe the echo area. */
- if (echo_area_glyphs)
+ if (!NILP (echo_area_buffer[0]))
safe_run_hooks (Qecho_area_clear_hook);
- echo_area_glyphs = 0;
+ 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 = this_command_key_count;
- int saved = current_kboard->immediate_echo;
+ int key_count;
struct gcpro gcpro1;
+ int count = specpdl_ptr - specpdl;
- keys = Fcopy_sequence (this_command_keys);
+ /* 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;
- current_kboard->immediate_echo = saved;
+
/* The input method can return no events. */
if (! CONSP (tem))
{
/* Bring back the previous message, if any. */
- if (! NILP (Vinput_method_previous_message))
- message_with_string ("%s", echo_area_message, 0);
- this_command_keys = keys;
- this_command_key_count = key_count;
- cancel_echoing ();
+ if (! NILP (previous_echo_area_message))
+ message_with_string ("%s", previous_echo_area_message, 0);
goto retry;
}
/* It returned one event or more. */
reread_first:
+ /* Display help if not echoing. */
+ if (CONSP (c)
+ && EQ (XCAR (c), Qhelp_echo))
+ {
+ Lisp_Object msg = XCDR (XCDR (c));
+
+ 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)
{
before_command_key_count = this_command_key_count;
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;
+ ok_to_echo_at_next_pause = current_kboard;
}
/* Record this character as part of the current key. */
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)
{
{
register int c;
Lisp_Object obj;
- EMACS_TIME next_timer_delay;
if (noninteractive)
{
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
frame = focus;
if (! EQ (frame, internal_last_event_frame)
- && XFRAME (frame) != selected_frame)
+ && !EQ (frame, selected_frame))
obj = make_lispy_switch_frame (frame);
internal_last_event_frame = frame;
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 == TOOL_BAR_EVENT)
&& !(CONSP (obj) && EQ (XCONS (obj)->car, Qmenu_bar))
+ && !(CONSP (obj) && EQ (XCONS (obj)->car, Qtool_bar))
&& used_mouse_menu)
*used_mouse_menu = 1;
#endif
XSETFRAME (frame, f);
if (! EQ (frame, internal_last_event_frame)
- && XFRAME (frame) != selected_frame)
+ && !EQ (frame, selected_frame))
obj = make_lispy_switch_frame (frame);
internal_last_event_frame = frame;
}
while (CONSP (timers) || CONSP (idle_timers))
{
- int triggertime = EMACS_SECS (now);
Lisp_Object *vector;
Lisp_Object timer, idle_timer;
EMACS_TIME timer_time, idle_timer_time;
{
if (NILP (vector[0]))
{
- 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 : Qheader_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 = Qheader_line;
else
XSETINT (posn,
buffer_posn_from_coords (XWINDOW (window),
FRAME_PTR f;
Lisp_Object window;
Lisp_Object posn;
- Lisp_Object head, position;
Lisp_Object files;
int row, column;
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 = Qheader_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 TOOL_BAR_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 wx, wy;
+
+ /* 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 = Qheader_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;
{
cbuf[0] = dos_keyread ();
nread = 1;
#else
- nread = read (input_fd, cbuf, n_to_read);
+ nread = emacs_read (input_fd, cbuf, n_to_read);
#endif
/* POSIX infers that processes which are not in the session leader's
process group won't get SIGHUP's at logout time. BSDI adheres to
cbuf[i] &= ~0x80;
buf[i].code = cbuf[i];
- XSETFRAME (buf[i].frame_or_window, selected_frame);
+ buf[i].frame_or_window = selected_frame;
}
}
if (i + 4 > XVECTOR (menu_bar_items_vector)->size)
{
Lisp_Object tem;
- int newsize = 2 * i;
tem = Fmake_vector (make_number (2 * i), Qnil);
bcopy (XVECTOR (menu_bar_items_vector)->contents,
XVECTOR (tem)->contents, i * sizeof (Lisp_Object));
/* 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;
+ Lisp_Object tail, item;
+
+ 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. */
if (i + 4 > XVECTOR (menu_bar_items_vector)->size)
{
Lisp_Object tem;
- int newsize = 2 * i;
tem = Fmake_vector (make_number (2 * i), Qnil);
bcopy (XVECTOR (menu_bar_items_vector)->contents,
XVECTOR (tem)->contents, i * sizeof (Lisp_Object));
/* 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;
else if (EQ (tem, QCkeys))
{
tem = XCONS (item)->car;
- if (CONSP (tem) || STRINGP (tem) && NILP (cachelist))
+ if (CONSP (tem) || (STRINGP (tem) && NILP (cachelist)))
XVECTOR (item_properties)->contents[ITEM_PROPERTY_KEYEQ]
= tem;
}
/* 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))
}
/* We had a saved key. Is it still bound to the command? */
else if (NILP (tem)
- || !EQ (tem, def)
- /* If the command is an alias for another
- (such as lmenu.el set it up), check if the
- original command matches the cached command. */
- && !(SYMBOLP (def) && EQ (tem, XSYMBOL (def)->function)))
+ || (!EQ (tem, def)
+ /* If the command is an alias for another
+ (such as lmenu.el set it up), check if the
+ original command matches the cached command. */
+ && !(SYMBOLP (def) && EQ (tem, XSYMBOL (def)->function))))
chkcache = 1; /* Need to recompute key binding. */
if (chkcache)
return 1;
}
+
+
+\f
+/***********************************************************************
+ Tool-bars
+ ***********************************************************************/
+
+/* A vector holding tool bar items while they are parsed in function
+ tool_bar_items runs Each item occupies TOOL_BAR_ITEM_NSCLOTS elements
+ in the vector. */
+
+static Lisp_Object tool_bar_items_vector;
+
+/* A vector holding the result of parse_tool_bar_item. Layout is like
+ the one for a single item in tool_bar_items_vector. */
+
+static Lisp_Object tool_bar_item_properties;
+
+/* Next free index in tool_bar_items_vector. */
+
+static int ntool_bar_items;
+
+/* The symbols `tool-bar', and `:image'. */
+
+extern Lisp_Object Qtool_bar;
+Lisp_Object QCimage;
+
+/* Function prototypes. */
+
+static void init_tool_bar_items P_ ((Lisp_Object));
+static void process_tool_bar_item P_ ((Lisp_Object, Lisp_Object));
+static int parse_tool_bar_item P_ ((Lisp_Object, Lisp_Object));
+static void append_tool_bar_item P_ ((void));
+
+
+/* Return a vector of tool bar items for keymaps currently in effect.
+ Reuse vector REUSE if non-nil. Return in *NITEMS the number of
+ tool bar items found. */
+
+Lisp_Object
+tool_bar_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 tool_bar_items_vector and protect it from GC. */
+ init_tool_bar_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 `tool-bar'. */
+ for (i = nmaps - 1; i >= 0; --i)
+ if (!NILP (maps[i]))
+ {
+ Lisp_Object keymap;
+
+ keymap = get_keyelt (access_keymap (maps[i], Qtool_bar, 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_tool_bar_item (XCAR (keydef), XCDR (keydef));
+ }
+ }
+ }
+
+ Vinhibit_quit = oquit;
+ *nitems = ntool_bar_items / TOOL_BAR_ITEM_NSLOTS;
+ return tool_bar_items_vector;
+}
+
+
+/* Process the definition of KEY which is DEF. */
+
+static void
+process_tool_bar_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_tool_bar_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 < ntool_bar_items; i += TOOL_BAR_ITEM_NSLOTS)
+ {
+ Lisp_Object *v = XVECTOR (tool_bar_items_vector)->contents + i;
+
+ if (EQ (key, v[TOOL_BAR_ITEM_KEY]))
+ {
+ if (ntool_bar_items > i + TOOL_BAR_ITEM_NSLOTS)
+ bcopy (v + TOOL_BAR_ITEM_NSLOTS, v,
+ ((ntool_bar_items - i - TOOL_BAR_ITEM_NSLOTS)
+ * sizeof (Lisp_Object)));
+ ntool_bar_items -= TOOL_BAR_ITEM_NSLOTS;
+ break;
+ }
+ }
+ }
+ else if (parse_tool_bar_item (key, def))
+ /* Append a new tool bar item to tool_bar_items_vector. Accept
+ more than one definition for the same key. */
+ append_tool_bar_item ();
+
+ UNGCPRO;
+}
+
+
+/* Parse a tool bar item specification ITEM for key KEY and return the
+ result in tool_bar_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 tool bar item's binding. Tool-bar items with keymaps
+ as binding are currently ignored.
+
+ The following properties are recognized:
+
+ - `:enable FORM'.
+
+ FORM is evaluated and specifies whether the tool bar item is
+ enabled or disabled.
+
+ - `:visible FORM'
+
+ FORM is evaluated and specifies whether the tool bar 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 tool_bar_item_images.
+
+ - `:help HELP-STRING'.
+
+ Gives a help string to display for the tool bar item. */
+
+static int
+parse_tool_bar_item (key, item)
+ Lisp_Object key, item;
+{
+ /* Access slot with index IDX of vector tool_bar_item_properties. */
+#define PROP(IDX) XVECTOR (tool_bar_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;
+
+ /* Defininition looks like `(tool-bar-item CAPTION BINDING
+ PROPS...)'. Rule out items that aren't lists, don't start with
+ `tool-bar-item' or whose rest following `tool-bar-item' is not a
+ list. */
+ if (!CONSP (item)
+ || !EQ (XCAR (item), Qmenu_item)
+ || (item = XCDR (item),
+ !CONSP (item)))
+ return 0;
+
+ /* Create tool_bar_item_properties vector if necessary. Reset it to
+ defaults. */
+ if (VECTORP (tool_bar_item_properties))
+ {
+ for (i = 0; i < TOOL_BAR_ITEM_NSLOTS; ++i)
+ PROP (i) = Qnil;
+ }
+ else
+ tool_bar_item_properties
+ = Fmake_vector (make_number (TOOL_BAR_ITEM_NSLOTS), Qnil);
+
+ /* Set defaults. */
+ PROP (TOOL_BAR_ITEM_KEY) = key;
+ PROP (TOOL_BAR_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 (TOOL_BAR_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 (TOOL_BAR_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 (TOOL_BAR_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 (TOOL_BAR_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 (TOOL_BAR_ITEM_SELECTED_P) = selected;
+ PROP (TOOL_BAR_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 (TOOL_BAR_ITEM_IMAGES) = value;
+ }
+
+ /* If got a filter apply it on binding. */
+ if (!NILP (filter))
+ PROP (TOOL_BAR_ITEM_BINDING)
+ = menu_item_eval_property (list2 (filter,
+ list2 (Qquote,
+ PROP (TOOL_BAR_ITEM_BINDING))));
+
+ /* See if the binding is a keymap. Give up if it is. */
+ if (!NILP (get_keymap_1 (PROP (TOOL_BAR_ITEM_BINDING), 0, 1)))
+ return 0;
+
+ /* Enable or disable selection of item. */
+ if (!EQ (PROP (TOOL_BAR_ITEM_ENABLED_P), Qt))
+ PROP (TOOL_BAR_ITEM_ENABLED_P)
+ = menu_item_eval_property (PROP (TOOL_BAR_ITEM_ENABLED_P));
+
+ /* Handle radio buttons or toggle boxes. */
+ if (!NILP (PROP (TOOL_BAR_ITEM_SELECTED_P)))
+ PROP (TOOL_BAR_ITEM_SELECTED_P)
+ = menu_item_eval_property (PROP (TOOL_BAR_ITEM_SELECTED_P));
+
+ return 1;
+
+#undef PROP
+}
+
+
+/* Initialize tool_bar_items_vector. REUSE, if non-nil, is a vector
+ that can be reused. */
+
+static void
+init_tool_bar_items (reuse)
+ Lisp_Object reuse;
+{
+ if (VECTORP (reuse))
+ tool_bar_items_vector = reuse;
+ else
+ tool_bar_items_vector = Fmake_vector (make_number (64), Qnil);
+ ntool_bar_items = 0;
+}
+
+
+/* Append parsed tool bar item properties from
+ tool_bar_item_properties */
+
+static void
+append_tool_bar_item ()
+{
+ Lisp_Object *to, *from;
+
+ /* Enlarge tool_bar_items_vector if necessary. */
+ if (ntool_bar_items + TOOL_BAR_ITEM_NSLOTS
+ >= XVECTOR (tool_bar_items_vector)->size)
+ {
+ Lisp_Object new_vector;
+ int old_size = XVECTOR (tool_bar_items_vector)->size;
+
+ new_vector = Fmake_vector (make_number (2 * old_size), Qnil);
+ bcopy (XVECTOR (tool_bar_items_vector)->contents,
+ XVECTOR (new_vector)->contents,
+ old_size * sizeof (Lisp_Object));
+ tool_bar_items_vector = new_vector;
+ }
+
+ /* Append entries from tool_bar_item_properties to the end of
+ tool_bar_items_vector. */
+ to = XVECTOR (tool_bar_items_vector)->contents + ntool_bar_items;
+ from = XVECTOR (tool_bar_item_properties)->contents;
+ bcopy (from, to, TOOL_BAR_ITEM_NSLOTS * sizeof *to);
+ ntool_bar_items += TOOL_BAR_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.
{
int mapno;
register Lisp_Object name;
- Lisp_Object rest, vector;
if (used_mouse_menu)
*used_mouse_menu = 0;
/* 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, Qtool_bar))
{
/* Display the menu and get the selection. */
Lisp_Object *realmaps
int mapno;
register Lisp_Object name;
int nlength;
- int width = FRAME_WIDTH (selected_frame) - 4;
+ int width = FRAME_WIDTH (SELECTED_FRAME ()) - 4;
int idx = -1;
int nobindings = 1;
Lisp_Object rest, vector;
int prev_keytran_start;
int prev_keytran_end;
+#if defined (GOBBLE_FIRST_EVENT)
int junk;
+#endif
raw_keybuf_count = 0;
orig_local_map = get_local_map (PT, current_buffer);
- /* Bind input-method-function so that we can set it to nil
- temporarily after the first input event. */
- specbind (Qinput_method_function, Vinput_method_function);
-
/* We jump here when the key sequence has been thoroughly changed, and
we need to rescan it starting from the beginning. When we jump here,
keybuf[0..mock_input] holds the sequence we should reread. */
/* If not, we should actually read a character. */
else
{
- struct buffer *buf = current_buffer;
-
{
#ifdef MULTI_KBOARD
KBOARD *interrupted_kboard = current_kboard;
- struct frame *interrupted_frame = selected_frame;
+ struct frame *interrupted_frame = SELECTED_FRAME ();
if (setjmp (wrong_kboard_jmpbuf))
{
if (!NILP (delayed_switch_frame))
#endif
key = read_char (NILP (prompt), nmaps, submaps, last_nonmenu_event,
&used_mouse_menu);
-
- /* Turn off input methods after a prefix character. */
- Vinput_method_function = Qnil;
}
/* read_char returns t when it shows a menu and the user rejects it.
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 (XFRAME (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;
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
emacsclient). */
record_unwind_protect (Fset_buffer, Fcurrent_buffer ());
+ if (! FRAME_LIVE_P (XFRAME (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);
+
+ /* 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, Qtool_bar))
{
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;
}
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)
+ (prompt, continue_echo, dont_downcase_last, can_return_switch_frame, command-loop)
#endif
DEFUN ("read-key-sequence", Fread_key_sequence, Sread_key_sequence, 1, 5, 0,
{
Lisp_Object keybuf[30];
register int i;
- struct gcpro gcpro1, gcpro2;
+ struct gcpro gcpro1;
int count = specpdl_ptr - specpdl;
if (!NILP (prompt))
{
Lisp_Object keybuf[30];
register int i;
- struct gcpro gcpro1, gcpro2;
+ struct gcpro gcpro1;
int count = specpdl_ptr - specpdl;
if (!NILP (prompt))
if (sizeof (int) == sizeof (EMACS_INT))
sprintf (buf, "%d ", XINT (XCONS (prefixarg)->car));
else if (sizeof (long) == sizeof (EMACS_INT))
- sprintf (buf, "%ld ", XINT (XCONS (prefixarg)->car));
+ sprintf (buf, "%ld ", (long) XINT (XCONS (prefixarg)->car));
else
abort ();
}
if (sizeof (int) == sizeof (EMACS_INT))
sprintf (buf, "%d ", XINT (prefixarg));
else if (sizeof (long) == sizeof (EMACS_INT))
- sprintf (buf, "%ld ", XINT (prefixarg));
+ sprintf (buf, "%ld ", (long) XINT (prefixarg));
else
abort ();
}
{
/* But first wait, and skip the message if there is input. */
int delay_time;
- if (echo_area_glyphs != 0)
+ 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)
{
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;
}
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;
(stuffstring)
Lisp_Object stuffstring;
{
- Lisp_Object tem;
int count = specpdl_ptr - specpdl;
int old_height, old_width;
int width, height;
- struct gcpro gcpro1, gcpro2;
+ struct gcpro gcpro1;
if (!NILP (stuffstring))
CHECK_STRING (stuffstring, 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))
char c;
/* Must preserve main program's value of errno. */
int old_errno = errno;
+ struct frame *sf = SELECTED_FRAME ();
#if defined (USG) && !defined (POSIX_SIGNALS)
if (!read_socket_hook && NILP (Vwindow_system))
cancel_echoing ();
if (!NILP (Vquit_flag)
- && (FRAME_TERMCAP_P (selected_frame) || FRAME_MSDOS_P (selected_frame)))
+ && (FRAME_TERMCAP_P (sf) || FRAME_MSDOS_P (sf)))
{
/* If SIGINT isn't blocked, don't let us be interrupted by
another SIGINT, it might be harmful due to non-reentrancy
void
quit_throw_to_read_char ()
{
- quit_error_check ();
sigfree ();
/* Prevent another signal from doing this before we finish. */
clear_waiting_for_input ();
#endif
#endif
if (FRAMEP (internal_last_event_frame)
- && XFRAME (internal_last_event_frame) != selected_frame)
+ && !EQ (internal_last_event_frame, selected_frame))
do_switch_frame (make_lispy_switch_frame (internal_last_event_frame),
Qnil, 0);
void
syms_of_keyboard ()
{
+ /* Tool-bars. */
+ QCimage = intern (":image");
+ staticpro (&QCimage);
+
+ staticpro (&Qhelp_echo);
+ Qhelp_echo = intern ("help-echo");
+
staticpro (&item_properties);
item_properties = Qnil;
+ staticpro (&tool_bar_item_properties);
+ tool_bar_item_properties = Qnil;
+ staticpro (&tool_bar_items_vector);
+ tool_bar_items_vector = Qnil;
+
staticpro (&real_this_command);
real_this_command = Qnil;
#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);
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_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);
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\
Vthis_command = Qnil;
DEFVAR_INT ("auto-save-interval", &auto_save_interval,
- "*Number of keyboard input characters between auto-saves.\n\
+ "*Number of input events between auto-saves.\n\
Zero means disable autosaving due to number of characters typed.");
auto_save_interval = 300;
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 ("input-method-previous-message",
&Vinput_method_previous_message,
- "When `input-mehod-function' is called, hold the previous echo area message.\n\
+ "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