Mercurial > emacs
changeset 25022:3ea84b15b5e6
(read_char): Use message3_nolog to show help-echo.
(make_lispy_event) <TOOLBAR_EVENT>: Apply modifiers.
(kbd_store_ptr): Declare it as a volatile pointer
instead of a pointer to a volatile input_event.
(kbd_buffer_store_event): Remove volatile modifier from
declaration of local variable `sp'.
(Fdiscard_input): Don't cast when assigning kbd_store_ptr
to kbd_fetch_ptr.
(make_lispy_event): Handle mouse on top lines.
(make_lispy_movement): Ditto.
(read_char): Rename local variable echo_area_message
because it shadows the global one.
(cmd_error_internal): Set echo_areA_message.
(command_loop_1): Test echo_areA_message.
(read_char): Ditto.
(record_menu_key): Set echo_area_message to nil.
(Fexecute_extended_command): Test echo_area_message.
(Fexecute_extended_command): Handle echo_area_message.
(toolbar_items): Call access_keymap with third
parameter 1, so that we don't get inherited toolbar item
definitions.
Ditto.
(kbd_buffer_get_event): Set flag to prevent recording
TOOLBAR_EVENT events in last_nonmenu_event.
(timer_check): Inhibit busy cursor around calls to
timer-event-handler. This busy cursor tends to be anoying if
fontifying stealthily.
(command_loop_1): Display busy cursor.
(Vshow_help_function): New.
(read_char): Use it.
(make_lispy_event): Add string and string position
info to mouse-click events.
(read_key_sequence): Handle `local-map' property of mode line
strings.
(Qend_scroll): New.
(scroll_bar_parts): Add it.
(scroll_bar_parts): Add Qtop and Qbottom.
(syms_of_keyboard): Add Qbottom.
(make_lispy_event): Handle scroll_bar_click
differently when using toolkit scroll bars.
(cmd_error_internal): Bug fix.
(syms_of_keyboard): Staticpro toolbar_item_properties
and toolbar_items_vectors.
(Qhelp_echo): New symbol.
(read_char): Handle `toolbar' and `help_echo' events.
(kbd_buffer_get_event): Handle HELP_ECHO input event.
(make_lispy_event): Handle TOOLBAR_EVENT.
(toolbar_items): New.
(process_toolbar_item): New.
(PROP): New.
(init_toolbar_items): New.
(append_toolbar_item): New.
(read_char_x_menu_prompt): Handle `toolbar' event.
(read_key_sequence): Ditto.
(syms_of_keyboard): Intern `:help'.
(toolbar_items): New.
(process_toolbar_item): New.
(parse_toolbar_item): New.
(init_toolbar_items): New.
(append_toolbar_item): New.
(detect_input_pending_run_timers): Likewise.
(detect_input_pending_run_timers): Call gobble_input
after redisplaying.
(clear_waiting_for_input): Return void.
(record_asynch_buffer_change): Return void.
(stop_polling): Return void.
(start_polling): Ditto.
(cmd_error_internal): Write to stderr if selected
frame is Vterminal_frame under X. This is the case when a font
cannot be loaded when Emacs starts. Replace test for
FRAME_MESSAGE_BUF with test for glyphs_initialized_p.
(quit_throw_to_read_char): Ditto.
(make_lispy_event): mouse clicks; don't do frame
glyph position calculations.
(make_lispy_movement): Use buffer_posn_from_coords and window
relative coordinates.
(make_lispy_event): For mouse clicks, use
x_y_to_hpos_vpos.
(make_lispy_event): Use BUFFER_POSN_FROM_COORDS
with window relative pixel coordinates. Use GLYPH_TO_PIXEL_-
COORDS mit new arguments.
(make_lispy_event): WINDOW_FROM_COORDINATES with
pixel coords.
(make_lispy_movement): Same.
(interrupt_signal): Cursor_to with 4 params.
(command_loop_1): Call DIRECT_OUTPUT_FOR_INSERT
for any character.
author | Gerd Moellmann <gerd@gnu.org> |
---|---|
date | Wed, 21 Jul 1999 21:43:52 +0000 |
parents | 7a31786a0335 |
children | 6e3de2f65704 |
files | src/keyboard.c |
diffstat | 1 files changed, 717 insertions(+), 122 deletions(-) [+] |
line wrap: on
line diff
--- a/src/keyboard.c Wed Jul 21 21:43:52 1999 +0000 +++ b/src/keyboard.c Wed Jul 21 21:43:52 1999 +0000 @@ -166,6 +166,11 @@ 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; @@ -459,7 +464,7 @@ /* 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 @@ -482,6 +487,7 @@ 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; @@ -600,6 +606,7 @@ 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; @@ -1014,17 +1021,27 @@ char *context; { Lisp_Object stream; + int kill_emacs_p = 0; Vquit_flag = Qnil; Vinhibit_quit = Qt; echo_area_glyphs = 0; + echo_area_message = Qnil; /* If the window system or terminal frame hasn't been initialized yet, or we're not interactive, it's best to dump this message out to stderr and exit. */ - if (! FRAME_MESSAGE_BUF (selected_frame) + if (!selected_frame->glyphs_initialized_p + /* This is the case of the frame dumped with Emacs, when we're + running under a window system. */ + || (!NILP (Vwindow_system) + && !inhibit_window_system + && !FRAME_WINDOW_P (selected_frame)) || noninteractive) - stream = Qexternal_debugging_output; + { + stream = Qexternal_debugging_output; + kill_emacs_p = 1; + } else { Fdiscard_input (); @@ -1039,8 +1056,7 @@ /* 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)); @@ -1222,7 +1238,8 @@ /* If minibuffer on and echo area in use, wait 2 sec and redraw minibuffer. */ - if (minibuf_level && echo_area_glyphs + if (minibuf_level + && (echo_area_glyphs || STRINGP (echo_area_message)) && EQ (minibuf_window, echo_area_window)) { /* Bind inhibit-quit to t so that C-g gets read in @@ -1421,7 +1438,6 @@ { unsigned int c = XINT (last_command_char); int value; - if (NILP (Vexecuting_macro) && !EQ (minibuf_window, selected_window)) { @@ -1432,6 +1448,7 @@ } nonundocount++; } + lose = ((XFASTINT (XWINDOW (selected_window)->last_modified) < MODIFF) || (XFASTINT (XWINDOW (selected_window)->last_overlay_modified) @@ -1444,58 +1461,33 @@ || 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 (); @@ -1810,7 +1802,7 @@ 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; @@ -1820,9 +1812,9 @@ before_command_key_count = this_command_key_count; before_command_echo_length = echo_length (); c = Qnil; - echo_area_message = Qnil; - - GCPRO2 (c, echo_area_message); + previous_echo_area_message = Qnil; + + GCPRO2 (c, previous_echo_area_message); retry: @@ -1958,10 +1950,13 @@ } /* Message turns off echoing unless more keystrokes turn it on again. */ - if (echo_area_glyphs && *echo_area_glyphs + if (echo_area_glyphs + && *echo_area_glyphs && echo_area_glyphs != current_kboard->echobuf && ok_to_echo_at_next_pause != echo_area_glyphs) cancel_echoing (); + else if (STRINGP (echo_area_message)) + cancel_echoing (); else /* If already echoing, continue. */ echo_dash (); @@ -2034,10 +2029,12 @@ /* 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 + && !STRINGP (echo_area_message) && (echo_area_glyphs == 0 || *echo_area_glyphs == 0 || ok_to_echo_at_next_pause == echo_area_glyphs)) { @@ -2081,6 +2078,7 @@ && !NILP (prev_event) && EVENT_HAS_PARAMETERS (prev_event) && !EQ (XCONS (prev_event)->car, Qmenu_bar) + && !EQ (XCONS (prev_event)->car, Qtoolbar) /* Don't bring up a menu if we already have another event. */ && NILP (Vunread_command_events) && unread_command_char < 0) @@ -2333,7 +2331,7 @@ posn = POSN_BUFFER_POSN (EVENT_START (c)); /* Handle menu-bar events: insert the dummy prefix event `menu-bar'. */ - if (EQ (posn, Qmenu_bar)) + if (EQ (posn, Qmenu_bar) || EQ (posn, Qtoolbar)) { /* Change menu-bar to (menu-bar) as the event "position". */ POSN_BUFFER_POSN (EVENT_START (c)) = Fcons (posn, Qnil); @@ -2357,12 +2355,16 @@ && ! 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 (echo_area_glyphs || STRINGP (echo_area_message)) safe_run_hooks (Qecho_area_clear_hook); echo_area_glyphs = 0; + echo_area_message = Qnil; reread_for_input_method: from_macro: @@ -2407,9 +2409,10 @@ this_command_key_count = 0; /* Now wipe the echo area. */ - if (echo_area_glyphs) + if (echo_area_glyphs || STRINGP (echo_area_message)) safe_run_hooks (Qecho_area_clear_hook); echo_area_glyphs = 0; + echo_area_message = Qnil; echo_truncate (0); /* If we are not reading a key sequence, @@ -2442,8 +2445,8 @@ if (! CONSP (tem)) { /* Bring back the previous message, if any. */ - if (! NILP (echo_area_message)) - message_with_string ("%s", echo_area_message, 0); + if (! NILP (previous_echo_area_message)) + message_with_string ("%s", previous_echo_area_message, 0); goto retry; } /* It returned one event or more. */ @@ -2454,6 +2457,25 @@ 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; @@ -2523,6 +2545,7 @@ { /* Wipe the echo area. */ echo_area_glyphs = 0; + echo_area_message = Qnil; record_char (c); @@ -2855,7 +2878,7 @@ 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) { @@ -3100,7 +3123,13 @@ 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 @@ -3135,8 +3164,10 @@ we're returning is (menu-bar), though; that indicates the beginning of the menu sequence, and we might as well leave that as the `event with parameters' for this selection. */ - if (event->kind == menu_bar_event + if ((event->kind == menu_bar_event + || event->kind == TOOLBAR_EVENT) && !(CONSP (obj) && EQ (XCONS (obj)->car, Qmenu_bar)) + && !(CONSP (obj) && EQ (XCONS (obj)->car, Qtoolbar)) && used_mouse_menu) *used_mouse_menu = 1; #endif @@ -3471,6 +3502,9 @@ 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. */ @@ -3478,9 +3512,17 @@ 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. */ @@ -3946,12 +3988,13 @@ /* 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. */ @@ -4095,7 +4138,9 @@ /* 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; @@ -4113,6 +4158,7 @@ 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 @@ -4120,8 +4166,13 @@ 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 @@ -4146,6 +4197,7 @@ 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) @@ -4163,6 +4215,8 @@ } } + /* 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, @@ -4174,7 +4228,10 @@ } #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)) { @@ -4183,21 +4240,36 @@ } else { - int pixcolumn, pixrow; - column -= WINDOW_LEFT_MARGIN (XWINDOW (window)); - row -= XINT (XWINDOW (window)->top); - glyph_to_pixel_coords (f, column, row, &pixcolumn, &pixrow); - XSETINT (event->x, pixcolumn); - XSETINT (event->y, pixrow); - - if (part == 1) - posn = Qmode_line; + /* It's a click in window window at frame coordinates + event->x/ event->y. */ + struct window *w = XWINDOW (window); + + /* Get window relative coordinates. Original code + `rounded' this to glyph boundaries. */ + int wx = FRAME_TO_WINDOW_PIXEL_X (w, XINT (event->x)); + int wy = FRAME_TO_WINDOW_PIXEL_Y (w, XINT (event->y)); + + /* Set event coordinates to window-relative coordinates + for constructing the Lisp event below. */ + XSETINT (event->x, wx); + XSETINT (event->y, wy); + + if (part == 1 || part == 3) + { + /* Mode line or top line. Look for a string under + the mouse that may have a `local-map' property. */ + Lisp_Object string; + int charpos; + + posn = part == 1 ? Qmode_line : Qtop_line; + string = mode_line_string (w, wx, wy, part == 1, &charpos); + if (STRINGP (string)) + string_info = Fcons (string, make_number (charpos)); + } else if (part == 2) posn = Qvertical_line; else - XSETINT (posn, - buffer_posn_from_coords (XWINDOW (window), - column, row)); + XSETINT (posn, buffer_posn_from_coords (w, &wx, &wy)); } position @@ -4205,10 +4277,14 @@ 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; @@ -4224,6 +4300,7 @@ Fcons (make_number (event->timestamp), Fcons (part, Qnil))))); } +#endif /* not USE_TOOLKIT_SCROLL_BARS */ start_pos_ptr = &XVECTOR (button_down_location)->contents[button]; @@ -4335,6 +4412,55 @@ } } +#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: { @@ -4397,7 +4523,7 @@ 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)) { @@ -4417,6 +4543,8 @@ posn = Qmode_line; else if (part == 2) posn = Qvertical_line; + else if (part == 3) + posn = Qtop_line; else XSETINT (posn, buffer_posn_from_coords (XWINDOW (window), @@ -4470,7 +4598,7 @@ 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)) { @@ -4479,21 +4607,27 @@ } else { - int pixcolumn, pixrow; - column -= XINT (XWINDOW (window)->left); - row -= XINT (XWINDOW (window)->top); - glyph_to_pixel_coords (f, column, row, &pixcolumn, &pixrow); - XSETINT (event->x, pixcolumn); - XSETINT (event->y, pixrow); + /* It's an event in window `window' at frame coordinates + event->x/ event->y. */ + struct window *w = XWINDOW (window); + + /* Get window relative coordinates. */ + int wx = FRAME_TO_WINDOW_PIXEL_X (w, XINT (event->x)); + int wy = FRAME_TO_WINDOW_PIXEL_Y (w, XINT (event->y)); + + /* Set event coordinates to window-relative coordinates + for constructing the Lisp event below. */ + XSETINT (event->x, wx); + XSETINT (event->y, wy); if (part == 1) posn = Qmode_line; else if (part == 2) posn = Qvertical_line; + else if (part == 3) + posn = Qtop_line; else - XSETINT (posn, - buffer_posn_from_coords (XWINDOW (window), - column, row)); + XSETINT (posn, buffer_posn_from_coords (w, &wx, &wy)); } { @@ -4526,6 +4660,17 @@ return XCONS (event->frame_or_window)->cdr; #endif + case TOOLBAR_EVENT: + { + Lisp_Object key; + if (!CONSP (event->frame_or_window)) + abort (); + key = XCDR (event->frame_or_window); + if (SYMBOLP (key)) + key = apply_modifiers (event->modifiers, key); + return key; + } + case user_signal: /* A user signal. */ return *lispy_user_signals[event->code]; @@ -4568,34 +4713,34 @@ int area; Lisp_Object window; Lisp_Object posn; - int column, row; if (frame) - { - /* It's in a frame; which window on that frame? */ - pixel_to_glyph_coords (frame, XINT (x), XINT (y), &column, &row, - NULL, 1); - window = window_from_coordinates (frame, column, row, &area); - } + /* It's in a frame; which window on that frame? */ + window = window_from_coordinates (frame, XINT (x), XINT (y), &area, 0); else window = Qnil; if (WINDOWP (window)) { - int pixcolumn, pixrow; - column -= WINDOW_LEFT_MARGIN (XWINDOW (window)); - row -= XINT (XWINDOW (window)->top); - glyph_to_pixel_coords (frame, column, row, &pixcolumn, &pixrow); - XSETINT (x, pixcolumn); - XSETINT (y, pixrow); - + struct window *w = XWINDOW (window); + int hpos, vpos; + int wx, wy; + int pos; + + /* Get window relative coordinates. */ + wx = FRAME_TO_WINDOW_PIXEL_X (w, XINT (x)); + wy = FRAME_TO_WINDOW_PIXEL_Y (w, XINT (y)); + XSETINT (x, wx); + XSETINT (y, wy); + if (area == 1) posn = Qmode_line; else if (area == 2) posn = Qvertical_line; + else if (area == 3) + posn = Qtop_line; else - XSETINT (posn, - buffer_posn_from_coords (XWINDOW (window), column, row)); + XSETINT (posn, buffer_posn_from_coords (w, &wx, &wy)); } else if (frame != 0) { @@ -5846,7 +5991,7 @@ /* 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; { @@ -6206,6 +6351,392 @@ return 1; } + + + +/*********************************************************************** + Tool-bars + ***********************************************************************/ + +/* A vector holding toolbar items while they are parsed in function + toolbar_items runs Each item occupies TOOLBAR_ITEM_NSCLOTS + elements in the vector. */ + +static Lisp_Object toolbar_items_vector; + +/* A vector holding the result of parse_toolbar_item. Layout is like + the one for a single item in toolbar_items_vector. */ + +static Lisp_Object toolbar_item_properties; + +/* Next free index in toolbar_items_vector. */ + +static int ntoolbar_items; + +/* The symbols `toolbar', `toolbar-item', and `:image'. */ + +extern Lisp_Object Qtoolbar; +Lisp_Object QCimage; + +/* Function prototypes. */ + +static void init_toolbar_items P_ ((Lisp_Object)); +static void process_toolbar_item P_ ((Lisp_Object, Lisp_Object)); +static int parse_toolbar_item P_ ((Lisp_Object, Lisp_Object)); +static void append_toolbar_item P_ ((void)); + + +/* Return a vector of toolbar items for keymaps currently in effect. + Reuse vector REUSE if non-nil. Return in *NITEMS the number of + toolbar items found. */ + +Lisp_Object +toolbar_items (reuse, nitems) + Lisp_Object reuse; + int *nitems; +{ + Lisp_Object *maps; + int nmaps, i; + Lisp_Object oquit; + Lisp_Object *tmaps; + extern Lisp_Object Voverriding_local_map_menu_flag; + extern Lisp_Object Voverriding_local_map; + + *nitems = 0; + + /* In order to build the menus, we need to call the keymap + accessors. They all call QUIT. But this function is called + during redisplay, during which a quit is fatal. So inhibit + quitting while building the menus. We do this instead of + specbind because (1) errors will clear it anyway and (2) this + avoids risk of specpdl overflow. */ + oquit = Vinhibit_quit; + Vinhibit_quit = Qt; + + /* Initialize toolbar_items_vector and protect it from GC. */ + init_toolbar_items (reuse); + + /* Build list of keymaps in maps. Set nmaps to the number of maps + to process. */ + + /* Should overriding-terminal-local-map and overriding-local-map apply? */ + if (!NILP (Voverriding_local_map_menu_flag)) + { + /* Yes, use them (if non-nil) as well as the global map. */ + maps = (Lisp_Object *) alloca (3 * sizeof (maps[0])); + nmaps = 0; + if (!NILP (current_kboard->Voverriding_terminal_local_map)) + maps[nmaps++] = current_kboard->Voverriding_terminal_local_map; + if (!NILP (Voverriding_local_map)) + maps[nmaps++] = Voverriding_local_map; + } + else + { + /* No, so use major and minor mode keymaps. */ + nmaps = current_minor_maps (NULL, &tmaps); + maps = (Lisp_Object *) alloca ((nmaps + 2) * sizeof (maps[0])); + bcopy (tmaps, maps, nmaps * sizeof (maps[0])); +#ifdef USE_TEXT_PROPERTIES + maps[nmaps++] = get_local_map (PT, current_buffer); +#else + maps[nmaps++] = current_buffer->keymap; +#endif + } + + /* Add global keymap at the end. */ + maps[nmaps++] = current_global_map; + + /* Process maps in reverse order and look up in each map the prefix + key `toolbar'. */ + for (i = nmaps - 1; i >= 0; --i) + if (!NILP (maps[i])) + { + Lisp_Object keymap; + + keymap = get_keyelt (access_keymap (maps[i], Qtoolbar, 1, 1), 0); + if (!NILP (Fkeymapp (keymap))) + { + Lisp_Object tail; + + /* KEYMAP is a list `(keymap (KEY . BINDING) ...)'. */ + for (tail = keymap; CONSP (tail); tail = XCONS (tail)->cdr) + { + Lisp_Object keydef = XCAR (tail); + if (CONSP (keydef)) + process_toolbar_item (XCAR (keydef), XCDR (keydef)); + } + } + } + + Vinhibit_quit = oquit; + *nitems = ntoolbar_items / TOOLBAR_ITEM_NSLOTS; + return toolbar_items_vector; +} + + +/* Process the definition of KEY which is DEF. */ + +static void +process_toolbar_item (key, def) + Lisp_Object key, def; +{ + int i; + extern Lisp_Object Qundefined; + struct gcpro gcpro1, gcpro2; + + /* Protect KEY and DEF from GC because parse_toolbar_item may call + eval. */ + GCPRO2 (key, def); + + if (EQ (def, Qundefined)) + { + /* If a map has an explicit `undefined' as definition, + discard any previously made item. */ + for (i = 0; i < ntoolbar_items; i += TOOLBAR_ITEM_NSLOTS) + { + Lisp_Object *v = XVECTOR (toolbar_items_vector)->contents + i; + + if (EQ (key, v[TOOLBAR_ITEM_KEY])) + { + if (ntoolbar_items > i + TOOLBAR_ITEM_NSLOTS) + bcopy (v + TOOLBAR_ITEM_NSLOTS, v, + ((ntoolbar_items - i - TOOLBAR_ITEM_NSLOTS) + * sizeof (Lisp_Object))); + ntoolbar_items -= TOOLBAR_ITEM_NSLOTS; + break; + } + } + } + else if (parse_toolbar_item (key, def)) + /* Append a new toolbar item to toolbar_items_vector. Accept + more than one definition for the same key. */ + append_toolbar_item (); + + UNGCPRO; +} + + +/* Parse a toolbar item specification ITEM for key KEY and return the + result in toolbar_item_properties. Value is zero if ITEM is + invalid. + + ITEM is a list `(menu-item CAPTION BINDING PROPS...)'. + + CAPTION is the caption of the item, If it's not a string, it is + evaluated to get a string. + + BINDING is the toolbar item's binding. Toolbar items with keymaps + as binding are currently ignored. + + The following properties are recognized: + + - `:enable FORM'. + + FORM is evaluated and specifies whether the toolbar item is enabled + or disabled. + + - `:visible FORM' + + FORM is evaluated and specifies whether the toolbar item is visible. + + - `:filter FUNCTION' + + FUNCTION is invoked with one parameter `(quote BINDING)'. Its + result is stored as the new binding. + + - `:button (TYPE SELECTED)' + + TYPE must be one of `:radio' or `:toggle'. SELECTED is evaluated + and specifies whether the button is selected (pressed) or not. + + - `:image IMAGES' + + IMAGES is either a single image specification or a vector of four + image specifications. See enum toolbar_item_images. + + - `:help HELP-STRING'. + + Gives a help string to display for the toolbar item. */ + +static int +parse_toolbar_item (key, item) + Lisp_Object key, item; +{ + /* Access slot with index IDX of vector toolbar_item_properties. */ +#define PROP(IDX) XVECTOR (toolbar_item_properties)->contents[IDX] + + Lisp_Object filter = Qnil; + Lisp_Object caption; + extern Lisp_Object QCenable, QCvisible, QChelp, QCfilter; + extern Lisp_Object QCbutton, QCtoggle, QCradio; + int i; + struct gcpro gcpro1; + + /* Defininition looks like `(toolbar-item CAPTION BINDING + PROPS...)'. Rule out items that aren't lists, don't start with + `toolbar-item' or whose rest following `toolbar-item' is not a + list. */ + if (!CONSP (item) + || !EQ (XCAR (item), Qmenu_item) + || (item = XCDR (item), + !CONSP (item))) + return 0; + + /* Create toolbar_item_properties vector if necessary. Reset it to + defaults. */ + if (VECTORP (toolbar_item_properties)) + { + for (i = 0; i < TOOLBAR_ITEM_NSLOTS; ++i) + PROP (i) = Qnil; + } + else + toolbar_item_properties + = Fmake_vector (make_number (TOOLBAR_ITEM_NSLOTS), Qnil); + + /* Set defaults. */ + PROP (TOOLBAR_ITEM_KEY) = key; + PROP (TOOLBAR_ITEM_ENABLED_P) = Qt; + + /* Get the caption of the item. If the caption is not a string, + evaluate it to get a string. If we don't get a string, skip this + item. */ + caption = XCAR (item); + if (!STRINGP (caption)) + { + caption = menu_item_eval_property (caption); + if (!STRINGP (caption)) + return 0; + } + PROP (TOOLBAR_ITEM_CAPTION) = caption; + + /* Give up if rest following the caption is not a list. */ + item = XCDR (item); + if (!CONSP (item)) + return 0; + + /* Store the binding. */ + PROP (TOOLBAR_ITEM_BINDING) = XCAR (item); + item = XCDR (item); + + /* Process the rest of the properties. */ + for (; CONSP (item) && CONSP (XCDR (item)); item = XCDR (XCDR (item))) + { + Lisp_Object key, value; + + key = XCAR (item); + value = XCAR (XCDR (item)); + + if (EQ (key, QCenable)) + /* `:enable FORM'. */ + PROP (TOOLBAR_ITEM_ENABLED_P) = value; + else if (EQ (key, QCvisible)) + { + /* `:visible FORM'. If got a visible property and that + evaluates to nil then ignore this item. */ + if (NILP (menu_item_eval_property (value))) + return 0; + } + else if (EQ (key, QChelp)) + /* `:help HELP-STRING'. */ + PROP (TOOLBAR_ITEM_HELP) = value; + else if (EQ (key, QCfilter)) + /* ':filter FORM'. */ + filter = value; + else if (EQ (key, QCbutton) && CONSP (value)) + { + /* `:button (TYPE . SELECTED)'. */ + Lisp_Object type, selected; + + type = XCAR (value); + selected = XCDR (value); + if (EQ (type, QCtoggle) || EQ (type, QCradio)) + { + PROP (TOOLBAR_ITEM_SELECTED_P) = selected; + PROP (TOOLBAR_ITEM_TYPE) = type; + } + } + else if (EQ (key, QCimage) + && (CONSP (value) + || (VECTORP (value) && XVECTOR (value)->size == 4))) + /* Value is either a single image specification or a vector + of 4 such specifications for the different buttion states. */ + PROP (TOOLBAR_ITEM_IMAGES) = value; + } + + /* If got a filter apply it on binding. */ + if (!NILP (filter)) + PROP (TOOLBAR_ITEM_BINDING) + = menu_item_eval_property (list2 (filter, + list2 (Qquote, + PROP (TOOLBAR_ITEM_BINDING)))); + + /* See if the binding is a keymap. Give up if it is. */ + if (!NILP (get_keymap_1 (PROP (TOOLBAR_ITEM_BINDING), 0, 1))) + return 0; + + /* Enable or disable selection of item. */ + if (!EQ (PROP (TOOLBAR_ITEM_ENABLED_P), Qt)) + PROP (TOOLBAR_ITEM_ENABLED_P) + = menu_item_eval_property (PROP (TOOLBAR_ITEM_ENABLED_P)); + + /* Handle radio buttons or toggle boxes. */ + if (!NILP (PROP (TOOLBAR_ITEM_SELECTED_P))) + PROP (TOOLBAR_ITEM_SELECTED_P) + = menu_item_eval_property (PROP (TOOLBAR_ITEM_SELECTED_P)); + + return 1; + +#undef PROP +} + + +/* Initialize Vtoolbar_items. REUSE, if non-nil, is a vector that can + be reused. */ + +static void +init_toolbar_items (reuse) + Lisp_Object reuse; +{ + if (VECTORP (reuse)) + toolbar_items_vector = reuse; + else + toolbar_items_vector = Fmake_vector (make_number (64), Qnil); + ntoolbar_items = 0; +} + + +/* Append parsed toolbar item properties from toolbar_item_properties */ + +static void +append_toolbar_item () +{ + Lisp_Object *to, *from; + + /* Enlarge toolbar_items_vector if necessary. */ + if (ntoolbar_items + TOOLBAR_ITEM_NSLOTS + >= XVECTOR (toolbar_items_vector)->size) + { + Lisp_Object new_vector; + int old_size = XVECTOR (toolbar_items_vector)->size; + + new_vector = Fmake_vector (make_number (2 * old_size), Qnil); + bcopy (XVECTOR (toolbar_items_vector)->contents, + XVECTOR (new_vector)->contents, + old_size * sizeof (Lisp_Object)); + toolbar_items_vector = new_vector; + } + + /* Append entries from toolbar_item_properties to the end of + toolbar_items_vector. */ + to = XVECTOR (toolbar_items_vector)->contents + ntoolbar_items; + from = XVECTOR (toolbar_item_properties)->contents; + bcopy (from, to, TOOLBAR_ITEM_NSLOTS * sizeof *to); + ntoolbar_items += TOOLBAR_ITEM_NSLOTS; +} + + + + /* 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. @@ -6269,7 +6800,8 @@ /* If we got to this point via a mouse click, use a real menu for mouse selection. */ if (EVENT_HAS_PARAMETERS (prev_event) - && !EQ (XCONS (prev_event)->car, Qmenu_bar)) + && !EQ (XCONS (prev_event)->car, Qmenu_bar) + && !EQ (XCONS (prev_event)->car, Qtoolbar)) { /* Display the menu and get the selection. */ Lisp_Object *realmaps @@ -7114,6 +7646,7 @@ 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 @@ -7154,15 +7687,18 @@ 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); @@ -7191,11 +7727,33 @@ 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; } } @@ -7208,7 +7766,7 @@ posn = POSN_BUFFER_POSN (EVENT_START (key)); /* Handle menu-bar events: insert the dummy prefix event `menu-bar'. */ - if (EQ (posn, Qmenu_bar)) + if (EQ (posn, Qmenu_bar) || EQ (posn, Qtoolbar)) { if (t + 1 >= bufsize) error ("Key sequence too long"); @@ -8085,7 +8643,7 @@ { /* But first wait, and skip the message if there is input. */ int delay_time; - if (echo_area_glyphs != 0) + if (echo_area_glyphs != 0 || STRINGP (echo_area_message)) /* This command displayed something in the echo area; so wait a few seconds, then display our suggestion message. */ delay_time = (NUMBERP (Vsuggest_key_bindings) @@ -8101,6 +8659,7 @@ Lisp_Object binding; char *newmessage; char *oldmessage = echo_area_glyphs; + Lisp_Object oldmessage_string = echo_area_message; int oldmessage_len = echo_area_glyphs_length; int oldmultibyte = message_enable_multibyte; @@ -8119,7 +8678,13 @@ if (!NILP (Fsit_for ((NUMBERP (Vsuggest_key_bindings) ? Vsuggest_key_bindings : make_number (2)), Qnil, Qnil))) - message2_nolog (oldmessage, oldmessage_len, oldmultibyte); + { + if (STRINGP (oldmessage_string)) + message3_nolog (oldmessage_string, oldmessage_len, + oldmultibyte); + else + message2_nolog (oldmessage, oldmessage_len, oldmultibyte); + } } } @@ -8190,7 +8755,16 @@ 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; } @@ -8369,10 +8943,7 @@ 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; @@ -8658,7 +9229,6 @@ void quit_throw_to_read_char () { - quit_error_check (); sigfree (); /* Prevent another signal from doing this before we finish. */ clear_waiting_for_input (); @@ -8936,9 +9506,21 @@ void syms_of_keyboard () { + /* Toolbars. */ + QCimage = intern (":image"); + staticpro (&QCimage); + + staticpro (&Qhelp_echo); + Qhelp_echo = intern ("help-echo"); + staticpro (&item_properties); item_properties = Qnil; + staticpro (&toolbar_item_properties); + toolbar_item_properties = Qnil; + staticpro (&toolbar_items_vector); + toolbar_items_vector = Qnil; + staticpro (&real_this_command); real_this_command = Qnil; @@ -9004,6 +9586,8 @@ staticpro (&QCenable); QCvisible = intern (":visible"); staticpro (&QCvisible); + QChelp = intern (":help"); + staticpro (&QChelp); QCfilter = intern (":filter"); staticpro (&QCfilter); QCbutton = intern (":button"); @@ -9036,6 +9620,12 @@ 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); @@ -9493,6 +10083,11 @@ 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