#include "disptab.h"
#include "dispextern.h"
#include "keyboard.h"
+#include "syntax.h"
#include "intervals.h"
#include "blockinput.h"
+#include "puresize.h"
#include <setjmp.h>
#include <errno.h>
#ifdef WINDOWSNT
Lisp_Object Qmouse_wheel;
#endif
+Lisp_Object Qdrag_n_drop;
/* Lisp_Object Qmouse_movement; - also an event header */
/* Properties of event headers. */
Lisp_Object Qevent_kind;
Lisp_Object Qevent_symbol_elements;
+/* menu item parts */
+Lisp_Object Qmenu_alias;
Lisp_Object Qmenu_enable;
+Lisp_Object QCenable, QCvisible, QChelp, QCfilter, QCkeys, QCkey_sequence;
+Lisp_Object QCbutton, QCtoggle, QCradio;
+extern Lisp_Object Vdefine_key_rebound_commands;
+extern Lisp_Object Qmenu_item;
/* An event header symbol HEAD may have a property named
Qevent_symbol_element_mask, which is of the form (BASE MODIFIERS);
Lisp_Object Qvertical_scroll_bar;
Lisp_Object Qmenu_bar;
-extern Lisp_Object Qmenu_enable;
-
Lisp_Object recursive_edit_unwind (), command_loop ();
Lisp_Object Fthis_command_keys ();
Lisp_Object Qextended_command_history;
EMACS_TIME timer_check ();
+extern Lisp_Object Vhistory_length;
+
extern char *x_get_keysym_name ();
static void record_menu_key ();
-void swallow_events ();
-
Lisp_Object Qpolling_period;
/* List of absolute timers. Appears in order of next scheduled event. */
extern Lisp_Object Vprint_level, Vprint_length;
-extern nonascii_insert_offset;
-
/* Address (if not 0) of EMACS_TIME to zero out if a SIGIO interrupt
happens. */
EMACS_TIME *input_available_clear_time;
static Lisp_Object modify_event_symbol ();
static Lisp_Object make_lispy_switch_frame ();
static int parse_solitary_modifier ();
+static void save_getcjmp ();
+static void restore_getcjmp ();
/* > 0 if we are to echo keystrokes. */
static int echo_keystrokes;
so that it serves as a prompt for the next character.
Also start echoing. */
+void
echo_prompt (str)
char *str;
{
C can be a character, which is printed prettily ("M-C-x" and all that
jazz), or a symbol, whose name is printed. */
+void
echo_char (c)
Lisp_Object c;
{
else if (SYMBOLP (c))
{
struct Lisp_String *name = XSYMBOL (c)->name;
- if ((ptr - current_kboard->echobuf) + name->size_byte + 4
+ if ((ptr - current_kboard->echobuf) + STRING_BYTES (name) + 4
> ECHOBUFSIZE)
return;
- bcopy (name->data, ptr, name->size_byte);
- ptr += name->size_byte;
+ bcopy (name->data, ptr, STRING_BYTES (name));
+ ptr += STRING_BYTES (name);
}
if (current_kboard->echoptr == current_kboard->echobuf
/* Temporarily add a dash to the end of the echo string if it's not
empty, so that it serves as a mini-prompt for the very next character. */
+void
echo_dash ()
{
if (!current_kboard->immediate_echo
/* Turn off echoing, for the start of a new command. */
+void
cancel_echoing ()
{
current_kboard->immediate_echo = 0;
/* Make an auto save happen as soon as possible at command level. */
+void
force_auto_save_soon ()
{
last_auto_save = - auto_save_interval - 1;
{
struct Lisp_Char_Table *dp
= window_display_table (XWINDOW (selected_window));
- lose = FETCH_BYTE (PT_BYTE);
+ lose = FETCH_CHAR (PT_BYTE);
SET_PT (PT + 1);
if ((dp
? (VECTORP (DISP_CHAR_VECTOR (dp, lose))
struct Lisp_Char_Table *dp
= window_display_table (XWINDOW (selected_window));
SET_PT (PT - 1);
- lose = FETCH_BYTE (PT_BYTE);
+ lose = FETCH_CHAR (PT_BYTE);
if ((dp
? (VECTORP (DISP_CHAR_VECTOR (dp, lose))
? XVECTOR (DISP_CHAR_VECTOR (dp, lose))->size == 1
/* Add the offset to the character, for Finsert_char.
We pass internal_self_insert the unmodified character
because it itself does this offsetting. */
- if (lose >= 0200 && lose <= 0377
- && ! NILP (current_buffer->enable_multibyte_characters))
- lose += nonascii_insert_offset;
+ if (! NILP (current_buffer->enable_multibyte_characters))
+ lose = unibyte_char_to_multibyte (lose);
if (dp)
{
}
directly_done: ;
+ /* Note that the value cell will never directly contain nil
+ if the symbol is a local variable. */
+ if (!NILP (Vpost_command_hook) && !NILP (Vrun_hooks))
+ safe_run_hooks (Qpost_command_hook);
+
+ if (!NILP (Vdeferred_action_list))
+ safe_run_hooks (Qdeferred_action_function);
+
+ if (!NILP (Vpost_command_idle_hook) && !NILP (Vrun_hooks))
+ {
+ if (NILP (Vunread_command_events)
+ && NILP (Vexecuting_macro)
+ && !NILP (sit_for (0, post_command_idle_delay, 0, 1, 1)))
+ safe_run_hooks (Qpost_command_idle_hook);
+ }
+
/* If there is a prefix argument,
1) We don't want Vlast_command to be ``universal-argument''
(that would be dumb), so don't set Vlast_command,
this_single_command_key_start = 0;
}
- /* Note that the value cell will never directly contain nil
- if the symbol is a local variable. */
- if (!NILP (Vpost_command_hook) && !NILP (Vrun_hooks))
- safe_run_hooks (Qpost_command_hook);
-
- if (!NILP (Vdeferred_action_list))
- safe_run_hooks (Qdeferred_action_function);
-
- if (!NILP (Vpost_command_idle_hook) && !NILP (Vrun_hooks))
- {
- if (NILP (Vunread_command_events)
- && NILP (Vexecuting_macro)
- && !NILP (sit_for (0, post_command_idle_delay, 0, 1, 1)))
- safe_run_hooks (Qpost_command_idle_hook);
- }
-
if (!NILP (current_buffer->mark_active) && !NILP (Vrun_hooks))
{
if (!NILP (Vdeactivate_mark) && !NILP (Vtransient_mark_mode))
goto reread_first;
}
+ /* if redisplay was requested */
if (commandflag >= 0)
{
+ /* If there is pending input, process any events which are not
+ user-visible, such as X selection_request events. */
if (input_pending
|| detect_input_pending_run_timers (0))
- swallow_events (0);
+ swallow_events (0); /* may clear input_pending */
- if (!input_pending)
- redisplay ();
+ /* Redisplay if no pending input. */
+ while (!input_pending)
+ {
+ redisplay ();
+
+ if (!input_pending)
+ /* Normal case: no input arrived during redisplay. */
+ break;
+
+ /* Input arrived and pre-empted redisplay.
+ Process any events which are not user-visible. */
+ swallow_events (0);
+ /* If that cleared input_pending, try again to redisplay. */
+ }
}
/* Message turns off echoing unless more keystrokes turn it on again. */
{
putc ('<', dribble);
fwrite (XSYMBOL (dribblee)->name->data, sizeof (char),
- XSYMBOL (dribblee)->name->size_byte,
+ STRING_BYTES (XSYMBOL (dribblee)->name),
dribble);
putc ('>', dribble);
}
in case get_char is called recursively.
See read_process_output. */
+static void
save_getcjmp (temp)
jmp_buf temp;
{
bcopy (getcjmp, temp, sizeof getcjmp);
}
+static void
restore_getcjmp (temp)
jmp_buf temp;
{
#ifdef WINDOWSNT
static Lisp_Object mouse_wheel_syms;
#endif
+static Lisp_Object drag_n_drop_syms;
/* This is a list of keysym codes for special "accent" characters.
It parallels lispy_accent_keys. */
/*
* VK_L* & VK_R* - left and right Alt, Ctrl and Shift virtual keys.
- * Used only as parameters to GetAsyncKeyState() and GetKeyState().
+ * Used only as parameters to GetAsyncKeyState and GetKeyState.
* No other API or message will distinguish left and right keys this way.
*/
/* 0xA0 .. 0xEF */
{
"mouse-wheel"
};
+
#endif /* WINDOWSNT */
+/* drag-n-drop events are generated when a set of selected files are
+ dragged from another application and dropped onto an Emacs window. */
+static char *lispy_drag_n_drop_names[] =
+{
+ "drag-n-drop"
+};
+
/* Scroll bar parts. */
Lisp_Object Qabove_handle, Qhandle, Qbelow_handle;
Lisp_Object Qup, Qdown;
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)))));
+ position
+ = Fcons (window,
+ Fcons (Qvertical_scroll_bar,
+ Fcons (portion_whole,
+ Fcons (make_number (event->timestamp),
+ Fcons (part, Qnil)))));
}
/* Always treat W32 scroll bar events as clicks. */
}
}
#endif /* WINDOWSNT */
+
+ case drag_n_drop:
+ {
+ int part;
+ FRAME_PTR f;
+ Lisp_Object window;
+ Lisp_Object posn;
+ Lisp_Object head, position;
+ Lisp_Object files;
+ int row, column;
+
+ /* The frame_or_window field should be a cons of the frame in
+ which the event occurred and a list of the filenames
+ dropped. */
+ if (! CONSP (event->frame_or_window))
+ abort ();
+
+ f = XFRAME (XCONS (event->frame_or_window)->car);
+ files = XCONS (event->frame_or_window)->cdr;
+
+ /* Ignore mouse events that were made on frames that
+ have been deleted. */
+ if (! FRAME_LIVE_P (f))
+ 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);
+
+ if (!WINDOWP (window))
+ {
+ window = XCONS (event->frame_or_window)->car;
+ posn = Qnil;
+ }
+ 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);
+
+ if (part == 1)
+ posn = Qmode_line;
+ else if (part == 2)
+ posn = Qvertical_line;
+ else
+ XSETINT (posn,
+ buffer_posn_from_coords (XWINDOW (window),
+ column, row));
+ }
+
+ {
+ Lisp_Object head, position;
+
+ position
+ = Fcons (window,
+ Fcons (posn,
+ Fcons (Fcons (event->x, event->y),
+ Fcons (make_number (event->timestamp),
+ Qnil))));
+
+ head = modify_event_symbol (0, event->modifiers,
+ Qdrag_n_drop, Qnil,
+ lispy_drag_n_drop_names,
+ &drag_n_drop_syms, 1);
+ return Fcons (head,
+ Fcons (position,
+ Fcons (files,
+ Qnil)));
+ }
+ }
#endif /* HAVE_MOUSE */
#if defined (USE_X_TOOLKIT) || defined (HAVE_NTGUI)
modifiers = 0;
name = XSYMBOL (symbol)->name;
- for (i = 0; i+2 <= name->size_byte; )
+ for (i = 0; i+2 <= STRING_BYTES (name); )
{
int this_mod_end = 0;
int this_mod = 0;
/* Check there is a dash after the modifier, so that it
really is a modifier. */
- if (this_mod_end >= name->size_byte || name->data[this_mod_end] != '-')
+ if (this_mod_end >= STRING_BYTES (name)
+ || name->data[this_mod_end] != '-')
break;
/* This modifier is real; look for another. */
/* Should we include the `click' modifier? */
if (! (modifiers & (down_modifier | drag_modifier
| double_modifier | triple_modifier))
- && i + 7 == name->size_byte
+ && i + 7 == STRING_BYTES (name)
&& strncmp (name->data + i, "mouse-", 6) == 0
&& ('0' <= name->data[i + 6] && name->data[i + 6] <= '9'))
modifiers |= click_modifier;
Lisp_Object mask;
unmodified = Fintern (make_string (XSYMBOL (symbol)->name->data + end,
- XSYMBOL (symbol)->name->size_byte - end),
+ STRING_BYTES (XSYMBOL (symbol)->name) - end),
Qnil);
if (modifiers & ~(((EMACS_INT)1 << VALBITS) - 1))
new_symbol = apply_modifiers_uncached (modifiers,
XSYMBOL (base)->name->data,
XSYMBOL (base)->name->size,
- XSYMBOL (base)->name->size_byte);
+ STRING_BYTES (XSYMBOL (base)->name));
/* Add the new symbol to the base's cache. */
entry = Fcons (index, new_symbol);
switch (name->data[0])
{
#define SINGLE_LETTER_MOD(BIT) \
- if (name->size_byte == 1) \
+ if (STRING_BYTES (name) == 1) \
return BIT;
#define MULTI_LETTER_MOD(BIT, NAME, LEN) \
- if (LEN == name->size_byte \
+ if (LEN == STRING_BYTES (name) \
&& ! strncmp (name->data, NAME, LEN)) \
return BIT;
#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
- this part standard and returns -1 from read(0) with errno==EIO
+ this part standard and returns -1 from read (0) with errno==EIO
when the control tty is taken away.
Jeffrey Honig <jch@bsdi.com> says this is generally safe. */
if (nread == -1 && errno == EIO)
menu_bar_one_keymap (keymap)
Lisp_Object keymap;
{
- Lisp_Object tail, item, key, binding, item_string, table;
+ Lisp_Object tail, item, table;
/* Loop over all keymap entries that have menu strings. */
for (tail = keymap; CONSP (tail); tail = XCONS (tail)->cdr)
{
item = XCONS (tail)->car;
if (CONSP (item))
- {
- key = XCONS (item)->car;
- binding = XCONS (item)->cdr;
- if (CONSP (binding))
- {
- item_string = XCONS (binding)->car;
- if (STRINGP (item_string))
- menu_bar_item (key, item_string, Fcdr (binding));
- }
- else if (EQ (binding, Qundefined))
- menu_bar_item (key, Qnil, binding);
- }
+ menu_bar_item (XCONS (item)->car, XCONS (item)->cdr);
else if (VECTORP (item))
{
/* Loop over the char values represented in the vector. */
{
Lisp_Object character;
XSETFASTINT (character, c);
- binding = XVECTOR (item)->contents[c];
- if (CONSP (binding))
- {
- item_string = XCONS (binding)->car;
- if (STRINGP (item_string))
- menu_bar_item (key, item_string, Fcdr (binding));
- }
- else if (EQ (binding, Qundefined))
- menu_bar_item (key, Qnil, binding);
+ menu_bar_item (character, XVECTOR (item)->contents[c]);
}
}
}
}
-/* This is used as the handler when calling internal_condition_case_1. */
-
-static Lisp_Object
-menu_bar_item_1 (arg)
- Lisp_Object arg;
-{
- return Qnil;
-}
-
/* Add one item to menu_bar_items_vector, for KEY, ITEM_STRING and DEF.
If there's already an item for KEY, add this DEF to it. */
+Lisp_Object item_properties;
+
static void
-menu_bar_item (key, item_string, def)
- Lisp_Object key, item_string, def;
+menu_bar_item (key, item)
+ Lisp_Object key, item;
{
- Lisp_Object tem;
- Lisp_Object enabled;
+ struct gcpro gcpro1;
int i;
- /* Skip menu-bar equiv keys data. */
- if (CONSP (def) && CONSP (XCONS (def)->car))
- def = XCONS (def)->cdr;
-
- if (EQ (def, Qundefined))
+ if (EQ (item, Qundefined))
{
/* If a map has an explicit `undefined' as definition,
discard any previously made menu bar item. */
return;
}
- /* See if this entry is enabled. */
- enabled = Qt;
-
- if (SYMBOLP (def))
- {
- /* No property, or nil, means enable.
- Otherwise, enable if value is not nil. */
- tem = Fget (def, Qmenu_enable);
- if (!NILP (tem))
- /* (condition-case nil (eval tem)
- (error nil)) */
- enabled = internal_condition_case_1 (Feval, tem, Qerror,
- menu_bar_item_1);
- }
-
- /* Ignore this item if it's not enabled. */
- if (NILP (enabled))
+ GCPRO1 (key); /* Is this necessary? */
+ i = parse_menu_item (item, 0, 1);
+ UNGCPRO;
+ if (!i)
return;
+ item = XVECTOR (item_properties)->contents[ITEM_PROPERTY_DEF];
+
/* Find any existing item for this KEY. */
for (i = 0; i < menu_bar_items_index; i += 4)
if (EQ (key, XVECTOR (menu_bar_items_vector)->contents[i]))
XVECTOR (tem)->contents, i * sizeof (Lisp_Object));
menu_bar_items_vector = tem;
}
+
/* Add this item. */
XVECTOR (menu_bar_items_vector)->contents[i++] = key;
- XVECTOR (menu_bar_items_vector)->contents[i++] = item_string;
- XVECTOR (menu_bar_items_vector)->contents[i++] = Fcons (def, Qnil);
+ XVECTOR (menu_bar_items_vector)->contents[i++]
+ = XVECTOR (item_properties)->contents[ITEM_PROPERTY_NAME];
+ XVECTOR (menu_bar_items_vector)->contents[i++] = Fcons (item, Qnil);
XVECTOR (menu_bar_items_vector)->contents[i++] = make_number (0);
menu_bar_items_index = i;
}
- /* We did find an item for this KEY. Add DEF to its list of maps. */
+ /* We did find an item for this KEY. Add ITEM to its list of maps. */
else
{
Lisp_Object old;
old = XVECTOR (menu_bar_items_vector)->contents[i + 2];
- XVECTOR (menu_bar_items_vector)->contents[i + 2] = Fcons (def, old);
+ XVECTOR (menu_bar_items_vector)->contents[i + 2] = Fcons (item, old);
}
}
+\f
+ /* This is used as the handler when calling menu_item_eval_property. */
+static Lisp_Object
+menu_item_eval_property_1 (arg)
+ Lisp_Object arg;
+{
+ /* If we got a quit from within the menu computation,
+ quit all the way out of it. This takes care of C-] in the debugger. */
+ if (CONSP (arg) && EQ (XCONS (arg)->car, Qquit))
+ Fsignal (Qquit, Qnil);
+
+ return Qnil;
+}
+
+/* Evaluate an expression and return the result (or nil if something
+ went wrong). Used to evaluate dynamic parts of menu items. */
+static Lisp_Object
+menu_item_eval_property (sexpr)
+ Lisp_Object sexpr;
+{
+ Lisp_Object val;
+ val = internal_condition_case_1 (Feval, sexpr, Qerror,
+ menu_item_eval_property_1);
+ return val;
+}
+
+/* This function parses a menu item and leaves the result in the
+ vector item_properties.
+ ITEM is a key binding, a possible menu item.
+ If NOTREAL is nonzero, only check for equivalent key bindings, don't
+ evaluate dynamic expressions in the menu item.
+ INMENUBAR is > 0 when this is considered for an entry in a menu bar
+ top level.
+ INMENUBAR is < 0 when this is considered for an entry in a keyboard menu.
+ parse_menu_item returns true if the item is a menu item and false
+ otherwise. */
+
+int
+parse_menu_item (item, notreal, inmenubar)
+ Lisp_Object item;
+ int notreal, inmenubar;
+{
+ Lisp_Object def, tem, item_string, start;
+ Lisp_Object cachelist = Qnil;
+ Lisp_Object filter = Qnil;
+ Lisp_Object keyhint = Qnil;
+ int i;
+ int newcache = 0;
+
+ if (!CONSP (item))
+ return 0;
+
+ /* Create item_properties vector if necessary. */
+ if (NILP (item_properties))
+ item_properties
+ = Fmake_vector (make_number (ITEM_PROPERTY_ENABLE + 1), Qnil);
+
+ /* Initialize optional entries. */
+ for (i = ITEM_PROPERTY_DEF; i < ITEM_PROPERTY_ENABLE; i++)
+ XVECTOR (item_properties)->contents[i] = Qnil;
+ XVECTOR (item_properties)->contents[ITEM_PROPERTY_ENABLE] = Qt;
+
+ /* Save the item here to protect it from GC. */
+ XVECTOR (item_properties)->contents[ITEM_PROPERTY_ITEM] = item;
+
+ item_string = XCONS (item)->car;
+
+ start = item;
+ item = XCONS (item)->cdr;
+ if (STRINGP (item_string))
+ {
+ /* Old format menu item. */
+ XVECTOR (item_properties)->contents[ITEM_PROPERTY_NAME] = item_string;
+
+ /* Maybe help string. */
+ if (CONSP (item) && STRINGP (XCONS (item)->car))
+ {
+ XVECTOR (item_properties)->contents[ITEM_PROPERTY_HELP]
+ = XCONS (item)->car;
+ start = item;
+ item = XCONS (item)->cdr;
+ }
+
+ /* Maybee key binding cache. */
+ if (CONSP (item) && CONSP (XCONS (item)->car)
+ && (NILP (XCONS (XCONS (item)->car)->car)
+ || VECTORP (XCONS (XCONS (item)->car)->car)))
+ {
+ cachelist = XCONS (item)->car;
+ item = XCONS (item)->cdr;
+ }
+
+ /* This is the real definition--the function to run. */
+ XVECTOR (item_properties)->contents[ITEM_PROPERTY_DEF] = item;
+
+ /* Get enable property, if any. */
+ if (SYMBOLP (item))
+ {
+ tem = Fget (item, Qmenu_enable);
+ if (!NILP (tem))
+ XVECTOR (item_properties)->contents[ITEM_PROPERTY_ENABLE] = tem;
+ }
+ }
+ else if (EQ (item_string, Qmenu_item) && CONSP (item))
+ {
+ /* New format menu item. */
+ XVECTOR (item_properties)->contents[ITEM_PROPERTY_NAME]
+ = XCONS (item)->car;
+ start = XCONS (item)->cdr;
+ if (CONSP (start))
+ {
+ /* We have a real binding. */
+ XVECTOR (item_properties)->contents[ITEM_PROPERTY_DEF]
+ = XCONS (start)->car;
+
+ item = XCONS (start)->cdr;
+ /* Is there a cache list with key equivalences. */
+ if (CONSP (item) && CONSP (XCONS (item)->car))
+ {
+ cachelist = XCONS (item)->car;
+ item = XCONS (item)->cdr;
+ }
+
+ /* Parse properties. */
+ while (CONSP (item) && CONSP (XCONS (item)->cdr))
+ {
+ tem = XCONS (item)->car;
+ item = XCONS (item)->cdr;
+
+ if (EQ (tem, QCenable))
+ XVECTOR (item_properties)->contents[ITEM_PROPERTY_ENABLE]
+ = XCONS (item)->car;
+ else if (EQ (tem, QCvisible) && !notreal)
+ {
+ /* If got a visible property and that evaluates to nil
+ then ignore this item. */
+ tem = menu_item_eval_property (XCONS (item)->car);
+ if (NILP (tem))
+ return 0;
+ }
+ else if (EQ (tem, QChelp))
+ XVECTOR (item_properties)->contents[ITEM_PROPERTY_HELP]
+ = XCONS (item)->car;
+ else if (EQ (tem, QCfilter))
+ filter = item;
+ else if (EQ (tem, QCkey_sequence))
+ {
+ tem = XCONS (item)->car;
+ if (NILP (cachelist)
+ && (SYMBOLP (tem) || STRINGP (tem) || VECTORP (tem)))
+ /* Be GC protected. Set keyhint to item instead of tem. */
+ keyhint = item;
+ }
+ else if (EQ (tem, QCkeys))
+ {
+ tem = XCONS (item)->car;
+ if (CONSP (tem) || STRINGP (tem) && NILP (cachelist))
+ XVECTOR (item_properties)->contents[ITEM_PROPERTY_KEYEQ]
+ = tem;
+ }
+ else if (EQ (tem, QCbutton) && CONSP (XCONS (item)->car))
+ {
+ Lisp_Object type;
+ tem = XCONS (item)->car;
+ type = XCONS (tem)->car;
+ if (EQ (type, QCtoggle) || EQ (type, QCradio))
+ {
+ XVECTOR (item_properties)->contents[ITEM_PROPERTY_SELECTED]
+ = XCONS (tem)->cdr;
+ XVECTOR (item_properties)->contents[ITEM_PROPERTY_TYPE]
+ = type;
+ }
+ }
+ item = XCONS (item)->cdr;
+ }
+ }
+ else if (inmenubar || !NILP (start))
+ return 0;
+ }
+ else
+ return 0; /* not a menu item */
+
+ /* If item string is not a string, evaluate it to get string.
+ If we don't get a string, skip this item. */
+ item_string = XVECTOR (item_properties)->contents[ITEM_PROPERTY_NAME];
+ if (!(STRINGP (item_string) || notreal))
+ {
+ item_string = menu_item_eval_property (item_string);
+ if (!STRINGP (item_string))
+ return 0;
+ XVECTOR (item_properties)->contents[ITEM_PROPERTY_NAME] = item_string;
+ }
+
+ /* If got a filter apply it on definition. */
+ def = XVECTOR (item_properties)->contents[ITEM_PROPERTY_DEF];
+ if (!NILP (filter))
+ {
+ def = menu_item_eval_property (Fcons (XCONS (filter)->car,
+ Fcons (def, Qnil)));
+ XVECTOR (item_properties)->contents[ITEM_PROPERTY_DEF] = def;
+ }
+
+ /* If we got no definition, this item is just unselectable text which
+ is OK in a submenu but not in the menubar. */
+ if (NILP (def))
+ return (inmenubar ? 0 : 1);
+
+ /* Enable or disable selection of item. */
+ tem = XVECTOR (item_properties)->contents[ITEM_PROPERTY_ENABLE];
+ if (!EQ (tem, Qt))
+ {
+ if (notreal)
+ tem = Qt;
+ else
+ tem = menu_item_eval_property (tem);
+ if (inmenubar && NILP (tem))
+ return 0; /* Ignore disabled items in menu bar. */
+ XVECTOR (item_properties)->contents[ITEM_PROPERTY_ENABLE] = 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);
+ 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. */
+
+ /* This is a command. See if there is an equivalent key binding. */
+ if (NILP (cachelist))
+ {
+ /* We have to create a cachelist. */
+ CHECK_IMPURE (start);
+ XCONS (start)->cdr = Fcons (Fcons (Qnil, Qnil), XCONS (start)->cdr);
+ cachelist = XCONS (XCONS (start)->cdr)->car;
+ newcache = 1;
+ tem = XVECTOR (item_properties)->contents[ITEM_PROPERTY_KEYEQ];
+ if (!NILP (keyhint))
+ {
+ XCONS (cachelist)->car = XCONS (keyhint)->car;
+ newcache = 0;
+ }
+ else if (STRINGP (tem))
+ {
+ XCONS (cachelist)->cdr = Fsubstitute_command_keys (tem);
+ XCONS (cachelist)->car = Qt;
+ }
+ }
+ tem = XCONS (cachelist)->car;
+ if (!EQ (tem, Qt))
+ {
+ int chkcache = 0;
+ Lisp_Object prefix;
+
+ if (!NILP (tem))
+ tem = Fkey_binding (tem, Qnil);
+
+ prefix = XVECTOR (item_properties)->contents[ITEM_PROPERTY_KEYEQ];
+ if (CONSP (prefix))
+ {
+ def = XCONS (prefix)->car;
+ prefix = XCONS (prefix)->cdr;
+ }
+ else
+ def = XVECTOR (item_properties)->contents[ITEM_PROPERTY_DEF];
+
+ if (NILP (XCONS (cachelist)->car)) /* Have no saved key. */
+ {
+ if (newcache /* Always check first time. */
+ /* Should we check everything when precomputing key
+ bindings? */
+ /* || notreal */
+ /* If something had no key binding before, don't recheck it
+ because that is too slow--except if we have a list of
+ rebound commands in Vdefine_key_rebound_commands, do
+ recheck any command that appears in that list. */
+ || (CONSP (Vdefine_key_rebound_commands)
+ && !NILP (Fmemq (def, Vdefine_key_rebound_commands))))
+ chkcache = 1;
+ }
+ /* 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)))
+ chkcache = 1; /* Need to recompute key binding. */
+
+ if (chkcache)
+ {
+ /* Recompute equivalent key binding. If the command is an alias
+ for another (such as lmenu.el set it up), see if the original
+ command name has equivalent keys. Otherwise look up the
+ specified command itself. We don't try both, because that
+ makes lmenu menus slow. */
+ if (SYMBOLP (def) && SYMBOLP (XSYMBOL (def)->function)
+ && ! NILP (Fget (def, Qmenu_alias)))
+ def = XSYMBOL (def)->function;
+ tem = Fwhere_is_internal (def, Qnil, Qt, Qnil);
+ XCONS (cachelist)->car = tem;
+ if (NILP (tem))
+ {
+ XCONS (cachelist)->cdr = Qnil;
+ chkcache = 0;
+ }
+ }
+ else if (!NILP (keyhint) && !NILP (XCONS (cachelist)->car))
+ {
+ tem = XCONS (cachelist)->car;
+ chkcache = 1;
+ }
+
+ newcache = chkcache;
+ if (chkcache)
+ {
+ tem = Fkey_description (tem);
+ if (CONSP (prefix))
+ {
+ if (STRINGP (XCONS (prefix)->car))
+ tem = concat2 (XCONS (prefix)->car, tem);
+ if (STRINGP (XCONS (prefix)->cdr))
+ tem = concat2 (tem, XCONS (prefix)->cdr);
+ }
+ XCONS (cachelist)->cdr = tem;
+ }
+ }
+
+ tem = XCONS (cachelist)->cdr;
+ if (newcache && !NILP (tem))
+ {
+ tem = concat3 (build_string (" ("), tem, build_string (")"));
+ XCONS (cachelist)->cdr = tem;
+ }
+
+ /* If we only want to precompute equivalent key bindings, stop here. */
+ if (notreal)
+ return 1;
+
+ /* If we have an equivalent key binding, use that. */
+ XVECTOR (item_properties)->contents[ITEM_PROPERTY_KEYEQ] = tem;
+
+ /* Include this when menu help is implemented.
+ tem = XVECTOR (item_properties)->contents[ITEM_PROPERTY_HELP];
+ if (!(NILP (tem) || STRINGP (tem)))
+ {
+ tem = menu_item_eval_property (tem);
+ if (!STRINGP (tem))
+ tem = Qnil;
+ XVECTOR (item_properties)->contents[ITEM_PROPERTY_HELP] = tem;
+ }
+ */
+
+ /* Handle radio buttons or toggle boxes. */
+ tem = XVECTOR (item_properties)->contents[ITEM_PROPERTY_SELECTED];
+ if (!NILP (tem))
+ XVECTOR (item_properties)->contents[ITEM_PROPERTY_SELECTED]
+ = menu_item_eval_property (tem);
+
+ return 1;
+}
\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.
/* Prompt string always starts with map's prompt, and a space. */
strcpy (menu, XSTRING (name)->data);
- nlength = XSTRING (name)->size_byte;
+ nlength = STRING_BYTES (XSTRING (name));
menu[nlength++] = ':';
menu[nlength++] = ' ';
menu[nlength] = 0;
/* Loop over elements of map. */
while (i < width)
{
- Lisp_Object s, elt;
+ Lisp_Object elt;
/* If reached end of map, start at beginning of next map. */
if (NILP (rest))
else
{
/* An ordinary element. */
- Lisp_Object event;
+ Lisp_Object event, tem;
if (idx < 0)
{
- s = Fcar_safe (Fcdr_safe (elt)); /* alist */
- event = Fcar_safe (elt);
+ event = Fcar_safe (elt); /* alist */
+ elt = Fcdr_safe (elt);
}
else
{
- s = Fcar_safe (elt); /* vector */
- XSETINT (event, idx);
+ XSETINT (event, idx); /* vector */
}
/* Ignore the element if it has no prompt string. */
- if (STRINGP (s) && INTEGERP (event))
+ if (INTEGERP (event) && parse_menu_item (elt, 0, -1))
{
/* 1 if the char to type matches the string. */
int char_matches;
Lisp_Object upcased_event, downcased_event;
Lisp_Object desc;
+ Lisp_Object s
+ = XVECTOR (item_properties)->contents[ITEM_PROPERTY_NAME];
upcased_event = Fupcase (event);
downcased_event = Fdowncase (event);
if (! char_matches)
desc = Fsingle_key_description (event);
+ tem
+ = XVECTOR (item_properties)->contents[ITEM_PROPERTY_KEYEQ];
+ if (!NILP (tem))
+ /* Insert equivalent keybinding. */
+ s = concat2 (s, tem);
+
+ tem
+ = XVECTOR (item_properties)->contents[ITEM_PROPERTY_TYPE];
+ if (EQ (tem, QCradio) || EQ (tem, QCtoggle))
+ {
+ /* Insert button prefix. */
+ Lisp_Object selected
+ = XVECTOR (item_properties)->contents[ITEM_PROPERTY_SELECTED];
+ if (EQ (tem, QCradio))
+ tem = build_string (NILP (selected) ? "(*) " : "( ) ");
+ else
+ tem = build_string (NILP (selected) ? "[X] " : "[ ] ");
+ s = concat2 (tem, s);
+ }
+
+
/* If we have room for the prompt string, add it to this line.
If this is the first on the line, always add it. */
if ((XSTRING (s)->size + i + 2
UNGCPRO;
return make_event_array (i, keybuf);
}
+
+DEFUN ("read-key-sequence-vector", Fread_key_sequence_vector,
+ Sread_key_sequence_vector, 1, 4, 0,
+ "Like `read-key-sequence' but always return a vector.")
+ (prompt, continue_echo, dont_downcase_last, can_return_switch_frame)
+ Lisp_Object prompt, continue_echo, dont_downcase_last;
+ Lisp_Object can_return_switch_frame;
+{
+ Lisp_Object keybuf[30];
+ register int i;
+ struct gcpro gcpro1, gcpro2;
+
+ if (!NILP (prompt))
+ CHECK_STRING (prompt, 0);
+ QUIT;
+
+ bzero (keybuf, sizeof keybuf);
+ GCPRO1 (keybuf[0]);
+ gcpro1.nvars = (sizeof keybuf/sizeof (keybuf[0]));
+
+ if (NILP (continue_echo))
+ {
+ this_command_key_count = 0;
+ this_single_command_key_start = 0;
+ }
+
+ i = read_key_sequence (keybuf, (sizeof keybuf/sizeof (keybuf[0])),
+ prompt, ! NILP (dont_downcase_last),
+ ! NILP (can_return_switch_frame), 0);
+
+ if (i == -1)
+ {
+ Vquit_flag = Qt;
+ QUIT;
+ }
+ UNGCPRO;
+ return Fvector (i, keybuf);
+}
\f
DEFUN ("command-execute", Fcommand_execute, Scommand_execute, 1, 4, 0,
"Execute CMD as an editor command.\n\
other sorts of commands, call-interactively takes care of
this. */
if (!NILP (record_flag))
- Vcommand_history
- = Fcons (Fcons (Qexecute_kbd_macro,
- Fcons (final, Fcons (prefixarg, Qnil))),
- Vcommand_history);
+ {
+ Vcommand_history
+ = Fcons (Fcons (Qexecute_kbd_macro,
+ Fcons (final, Fcons (prefixarg, Qnil))),
+ Vcommand_history);
+
+ /* Don't keep command history around forever. */
+ if (NUMBERP (Vhistory_length) && XINT (Vhistory_length) > 0)
+ {
+ tem = Fnthcdr (Vhistory_length, Vcommand_history);
+ if (CONSP (tem))
+ XCONS (tem)->cdr = Qnil;
+ }
+ }
return Fexecute_kbd_macro (final, prefixarg);
}
+
if (CONSP (final) || SUBRP (final) || COMPILEDP (final))
{
backtrace.next = backtrace_list;
newmessage
= (char *) alloca (XSYMBOL (function)->name->size
- + XSTRING (binding)->size_byte
+ + STRING_BYTES (XSTRING (binding))
+ 100);
sprintf (newmessage, "You can run the command `%s' with %s",
XSYMBOL (function)->name->data,
\f
/* Return nonzero if input events are pending. */
+int
detect_input_pending ()
{
if (!input_pending)
/* Return nonzero if input events are pending, and run any pending timers. */
+int
detect_input_pending_run_timers (do_display)
int do_display;
{
The problem is, kbd_buffer_get_event needs to be fixed to know what
to do in that case. It isn't trivial. */
+int
requeued_events_pending_p ()
{
return (!NILP (Vunread_command_events) || unread_command_char != -1);
XVECTOR (this_command_keys)->contents);
}
+DEFUN ("this-command-keys-vector", Fthis_command_keys_vector, Sthis_command_keys_vector, 0, 0, 0,
+ "Return the key sequence that invoked this command, as a vector.")
+ ()
+{
+ return Fvector (this_command_key_count,
+ XVECTOR (this_command_keys)->contents);
+}
+
DEFUN ("this-single-command-keys", Fthis_single_command_keys,
Sthis_single_command_keys, 0, 0, 0,
"Return the key sequence that invoked this command.\n\
Unlike `this-command-keys', this function's value\n\
does not include prefix arguments.\n\
-The value is a string or a vector.")
+The value is always a vector.")
()
{
- return make_event_array (this_command_key_count
- - this_single_command_key_start,
- (XVECTOR (this_command_keys)->contents
- + this_single_command_key_start));
+ return Fvector (this_command_key_count
+ - this_single_command_key_start,
+ (XVECTOR (this_command_keys)->contents
+ + this_single_command_key_start));
}
DEFUN ("reset-this-command-lengths", Freset_this_command_lengths,
/* sys_suspend can get an error if it tries to fork a subshell
and the system resources aren't available for that. */
record_unwind_protect ((Lisp_Object (*) P_ ((Lisp_Object))) init_sys_modes,
- 0);
+ Qnil);
stuff_buffered_input (stuffstring);
if (cannot_suspend)
sys_subshell ();
register int count;
p = XSTRING (stuffstring)->data;
- count = XSTRING (stuffstring)->size_byte;
+ count = STRING_BYTES (XSTRING (stuffstring));
while (count-- > 0)
stuff_char (*p++);
stuff_char ('\n');
#endif /* BSD_SYSTEM and not BSD4_1 */
}
\f
+void
set_waiting_for_input (time_to_clear)
EMACS_TIME *time_to_clear;
{
then quit right away. */
if (immediate_quit && NILP (Vinhibit_quit))
{
+ struct gl_state_s saved;
+ struct gcpro gcpro1, gcpro2, gcpro3, gcpro4;
+
immediate_quit = 0;
sigfree ();
+ saved = gl_state;
+ GCPRO4 (saved.object, saved.global_code,
+ saved.current_syntax_table, saved.old_prop);
Fsignal (Qquit, Qnil);
+ gl_state = saved;
+ UNGCPRO;
}
else
/* Else request quit when it's safe */
}
#endif
+void
init_keyboard ()
{
/* This is correct before outermost invocation of the editor loop */
&Qmake_frame_visible, "make-frame-visible", &Qmake_frame_visible,
};
+void
syms_of_keyboard ()
{
+ staticpro (&item_properties);
+ item_properties = Qnil;
+
Qtimer_event_handler = intern ("timer-event-handler");
staticpro (&Qtimer_event_handler);
Qmouse_wheel = intern ("mouse-wheel");
staticpro (&Qmouse_wheel);
#endif
+ Qdrag_n_drop = intern ("drag-n-drop");
+ staticpro (&Qdrag_n_drop);
Qmenu_enable = intern ("menu-enable");
staticpro (&Qmenu_enable);
+ Qmenu_alias = intern ("menu-alias");
+ staticpro (&Qmenu_alias);
+ QCenable = intern (":enable");
+ staticpro (&QCenable);
+ QCvisible = intern (":visible");
+ staticpro (&QCvisible);
+ QCfilter = intern (":filter");
+ staticpro (&QCfilter);
+ QCbutton = intern (":button");
+ staticpro (&QCbutton);
+ QCkeys = intern (":keys");
+ staticpro (&QCkeys);
+ QCkey_sequence = intern (":key-sequence");
+ staticpro (&QCkey_sequence);
+ QCtoggle = intern (":toggle");
+ staticpro (&QCtoggle);
+ QCradio = intern (":radio");
+ staticpro (&QCradio);
Qmode_line = intern ("mode-line");
staticpro (&Qmode_line);
#ifdef WINDOWSNT
mouse_wheel_syms = Qnil;
staticpro (&mouse_wheel_syms);
+
+ drag_n_drop_syms = Qnil;
+ staticpro (&drag_n_drop_syms);
#endif
unread_switch_frame = Qnil;
defsubr (&Sevent_convert_list);
defsubr (&Sread_key_sequence);
+ defsubr (&Sread_key_sequence_vector);
defsubr (&Srecursive_edit);
#ifdef HAVE_MOUSE
defsubr (&Strack_mouse);
defsubr (&Scommand_execute);
defsubr (&Srecent_keys);
defsubr (&Sthis_command_keys);
+ defsubr (&Sthis_command_keys_vector);
defsubr (&Sthis_single_command_keys);
defsubr (&Sreset_this_command_lengths);
defsubr (&Ssuspend_emacs);
Vtimer_idle_list = Qnil;
}
+void
keys_of_keyboard ()
{
initial_define_key (global_map, Ctl ('Z'), "suspend-emacs");