/* Terminal control module for terminals described by TERMCAP
- Copyright (C) 1985-1987, 1993-1995, 1998, 2000-2013 Free Software
+ Copyright (C) 1985-1987, 1993-1995, 1998, 2000-2014 Free Software
Foundation, Inc.
This file is part of GNU Emacs.
static int max_frame_cols;
+static Lisp_Object Qtty_mode_set_strings;
+static Lisp_Object Qtty_mode_reset_strings;
+
\f
#ifdef HAVE_GPM
/* Set up termcap modes for Emacs. */
+static void
+tty_send_additional_strings (struct terminal *terminal, Lisp_Object sym)
+{
+ Lisp_Object lisp_terminal;
+ Lisp_Object extra_codes;
+ struct tty_display_info *tty = terminal->display_info.tty;
+
+ XSETTERMINAL (lisp_terminal, terminal);
+ for (extra_codes = Fterminal_parameter (lisp_terminal, sym);
+ CONSP (extra_codes);
+ extra_codes = XCDR (extra_codes))
+ {
+ Lisp_Object string = XCAR (extra_codes);
+ if (STRINGP (string))
+ {
+ fwrite (SDATA (string), 1, SBYTES (string), tty->output);
+ if (tty->termscript)
+ fwrite (SDATA (string), 1, SBYTES (string), tty->termscript);
+ }
+ }
+}
+
static void
tty_set_terminal_modes (struct terminal *terminal)
{
OUTPUT_IF (tty, visible_cursor ? tty->TS_cursor_visible : tty->TS_cursor_normal);
OUTPUT_IF (tty, tty->TS_keypad_mode);
losecursor (tty);
+ tty_send_additional_strings (terminal, Qtty_mode_set_strings);
fflush (tty->output);
}
}
if (tty->output)
{
+ tty_send_additional_strings (terminal, Qtty_mode_reset_strings);
tty_turn_off_highlight (tty);
tty_turn_off_insert (tty);
OUTPUT_IF (tty, tty->TS_end_keypad_mode);
tty_show_cursor (tty);
tty_turn_off_insert (tty);
tty_background_highlight (tty);
+ fflush (tty->output);
}
/* The implementation of set_terminal_window for termcap frames. */
sequence, and return a pointer to that byte sequence. */
unsigned char *
-encode_terminal_code (struct glyph *src, int src_len, struct coding_system *coding)
+encode_terminal_code (struct glyph *src, int src_len,
+ struct coding_system *coding)
{
struct glyph *src_end = src + src_len;
unsigned char *buf;
if (!KEYMAPP (KVAR (kboard, Vinput_decode_map)))
kset_input_decode_map (kboard, Fmake_sparse_keymap (Qnil));
- for (i = 0; i < (sizeof (keys) / sizeof (keys[0])); i++)
+ for (i = 0; i < ARRAYELTS (keys); i++)
{
char *sequence = tgetstr (keys[i].cap, address);
if (sequence)
CONDITIONAL_REASSIGN ("kD", "kI", "insert");
/* if there's no key_end keycap, map key_ll to 'end' keysym */
CONDITIONAL_REASSIGN ("@7", "kH", "end");
-
- /* IBM has their own non-standard dialect of terminfo.
- If the standard name isn't found, try the IBM name. */
- CONDITIONAL_REASSIGN ("kB", "KO", "backtab");
- CONDITIONAL_REASSIGN ("@4", "kJ", "execute"); /* actually "action" */
- CONDITIONAL_REASSIGN ("@4", "kc", "execute"); /* actually "command" */
- CONDITIONAL_REASSIGN ("%7", "ki", "menu");
- CONDITIONAL_REASSIGN ("@7", "kw", "end");
- CONDITIONAL_REASSIGN ("F1", "k<", "f11");
- CONDITIONAL_REASSIGN ("F2", "k>", "f12");
- CONDITIONAL_REASSIGN ("%1", "kq", "help");
- CONDITIONAL_REASSIGN ("*6", "kU", "select");
#undef CONDITIONAL_REASSIGN
}
acronym = XCDR (acronym);
buf[0] = '[';
str = STRINGP (acronym) ? SSDATA (acronym) : "";
- for (len = 0; len < 6 && str[len] && ASCII_BYTE_P (str[len]); len++)
+ for (len = 0; len < 6 && str[len] && ASCII_CHAR_P (str[len]); len++)
buf[1 + len] = str[len];
buf[1 + len] = ']';
len += 2;
turn_on_face (struct frame *f, int face_id)
{
struct face *face = FACE_FROM_ID (f, face_id);
- long fg = face->foreground;
- long bg = face->background;
+ unsigned long fg = face->foreground;
+ unsigned long bg = face->background;
struct tty_display_info *tty = FRAME_TTY (f);
- /* Do this first because TS_end_standout_mode may be the same
+ /* Use reverse video if the face specifies that.
+ Do this first because TS_end_standout_mode may be the same
as TS_exit_attribute_mode, which turns all appearances off. */
- if (MAY_USE_WITH_COLORS_P (tty, NC_REVERSE))
- {
- if (tty->TN_max_colors > 0)
- {
- if (fg >= 0 && bg >= 0)
- {
- /* If the terminal supports colors, we can set them
- below without using reverse video. The face's fg
- and bg colors are set as they should appear on
- the screen, i.e. they take the inverse-video'ness
- of the face already into account. */
- }
- else if (inverse_video)
- {
- if (fg == FACE_TTY_DEFAULT_FG_COLOR
- || bg == FACE_TTY_DEFAULT_BG_COLOR)
- tty_toggle_highlight (tty);
- }
- else
- {
- if (fg == FACE_TTY_DEFAULT_BG_COLOR
- || bg == FACE_TTY_DEFAULT_FG_COLOR)
- tty_toggle_highlight (tty);
- }
- }
- else
- {
- /* If we can't display colors, use reverse video
- if the face specifies that. */
- if (inverse_video)
- {
- if (fg == FACE_TTY_DEFAULT_FG_COLOR
- || bg == FACE_TTY_DEFAULT_BG_COLOR)
- tty_toggle_highlight (tty);
- }
- else
- {
- if (fg == FACE_TTY_DEFAULT_BG_COLOR
- || bg == FACE_TTY_DEFAULT_FG_COLOR)
- tty_toggle_highlight (tty);
- }
- }
- }
+ if (MAY_USE_WITH_COLORS_P (tty, NC_REVERSE)
+ && (inverse_video
+ ? fg == FACE_TTY_DEFAULT_FG_COLOR || bg == FACE_TTY_DEFAULT_BG_COLOR
+ : fg == FACE_TTY_DEFAULT_BG_COLOR || bg == FACE_TTY_DEFAULT_FG_COLOR))
+ tty_toggle_highlight (tty);
if (face->tty_bold_p && MAY_USE_WITH_COLORS_P (tty, NC_BOLD))
OUTPUT1_IF (tty, tty->TS_enter_bold_mode);
char *p;
ts = tty->standout_mode ? tty->TS_set_background : tty->TS_set_foreground;
- if (fg >= 0 && ts)
+ if (face_tty_specified_color (fg) && ts)
{
p = tparam (ts, NULL, 0, fg, 0, 0, 0);
OUTPUT (tty, p);
}
ts = tty->standout_mode ? tty->TS_set_foreground : tty->TS_set_background;
- if (bg >= 0 && ts)
+ if (face_tty_specified_color (bg) && ts)
{
p = tparam (ts, NULL, 0, bg, 0, 0, 0);
OUTPUT (tty, p);
/* Return true if the terminal on frame F supports all of the
- capabilities in CAPS simultaneously, with foreground and background
- colors FG and BG. */
+ capabilities in CAPS simultaneously. */
bool
-tty_capable_p (struct tty_display_info *tty, unsigned int caps,
- unsigned long fg, unsigned long bg)
+tty_capable_p (struct tty_display_info *tty, unsigned int caps)
{
#define TTY_CAPABLE_P_TRY(tty, cap, TS, NC_bit) \
if ((caps & (cap)) && (!(TS) || !MAY_USE_WITH_COLORS_P(tty, NC_bit))) \
if (save)
{
- xfree (default_orig_pair);
- default_orig_pair = tty->TS_orig_pair ? xstrdup (tty->TS_orig_pair) : NULL;
-
- xfree (default_set_foreground);
- default_set_foreground = tty->TS_set_foreground ? xstrdup (tty->TS_set_foreground)
- : NULL;
-
- xfree (default_set_background);
- default_set_background = tty->TS_set_background ? xstrdup (tty->TS_set_background)
- : NULL;
-
+ dupstring (&default_orig_pair, tty->TS_orig_pair);
+ dupstring (&default_set_foreground, tty->TS_set_foreground);
+ dupstring (&default_set_background, tty->TS_set_background);
default_max_colors = tty->TN_max_colors;
default_max_pairs = tty->TN_max_pairs;
default_no_color_video = tty->TN_no_color_video;
was suspended. */
get_tty_size (fileno (t->display_info.tty->input), &width, &height);
if (width != old_width || height != old_height)
- change_frame_size (f, height, width, 0, 0, 0);
+ change_frame_size (f, width, height, 0, 0, 0, 0);
SET_FRAME_VISIBLE (XFRAME (t->display_info.tty->top_frame), 1);
}
Menus
***********************************************************************/
-#if defined (HAVE_MENUS) && !defined (MSDOS)
+#if !defined (MSDOS)
/* TTY menu implementation and main ideas are borrowed from msdos.c.
However, unlike on MSDOS, where the menu text is drawn directly to
the display video memory, on a TTY we use display_string (see
display_tty_menu_item in xdisp.c) to put the glyphs produced from
- the menu items directly into the frame's 'desired_matrix' glyph
- matrix, and then call update_frame_with_menu to deliver the results
- to the glass. The previous contents of the screen, in the form of
- the current_matrix, is stashed away, and used to restore screen
+ the menu items into the frame's 'desired_matrix' glyph matrix, and
+ then call update_frame_with_menu to deliver the results to the
+ glass. The previous contents of the screen, in the form of the
+ current_matrix, is stashed away, and used to restore screen
contents when the menu selection changes or when the final
selection is made and the menu should be popped down.
{
if (pane == menu->panenumber[i])
return menu->submenu[i];
- if ((try = tty_menu_search_pane (menu->submenu[i], pane)))
+ try = tty_menu_search_pane (menu->submenu[i], pane);
+ if (try)
return try;
}
return (tty_menu *) 0;
}
}
-/* Display MENU at (X,Y) using FACES. */
+/* Display MENU at (X,Y) using FACES, starting with FIRST_ITEM
+ (zero-based). */
static void
tty_menu_display (tty_menu *menu, int x, int y, int pn, int *faces,
- int mx, int my, int disp_help)
+ int mx, int my, int first_item, bool disp_help)
{
int i, face, width, enabled, mousehere, row, col;
struct frame *sf = SELECTED_FRAME ();
struct tty_display_info *tty = FRAME_TTY (sf);
+ /* Don't try to display more menu items than the console can display
+ using the available screen lines. Exclude the echo area line, as
+ it will be overwritten by the help-echo anyway. */
+ int max_items = min (menu->count - first_item, FRAME_LINES (sf) - 1 - y);
menu_help_message = NULL;
width = menu->width;
col = cursorX (tty);
row = cursorY (tty);
- for (i = 0; i < menu->count; i++)
+ for (i = 0; i < max_items; i++)
{
int max_width = width + 2; /* +2 for padding blanks on each side */
+ int j = i + first_item;
- cursor_to (sf, y + i, x);
- if (menu->submenu[i])
+ if (menu->submenu[j])
max_width += 2; /* for displaying " >" after the item */
enabled
- = (!menu->submenu[i] && menu->panenumber[i]) || (menu->submenu[i]);
+ = (!menu->submenu[j] && menu->panenumber[j]) || (menu->submenu[j]);
mousehere = (y + i == my && x <= mx && mx < x + max_width);
face = faces[enabled + mousehere * 2];
/* Display the menu help string for the i-th menu item even if
code does. */
if (disp_help && enabled + mousehere * 2 >= 2)
{
- menu_help_message = menu->help_text[i];
+ menu_help_message = menu->help_text[j];
menu_help_paneno = pn - 1;
- menu_help_itemno = i;
+ menu_help_itemno = j;
}
- display_tty_menu_item (menu->text[i], max_width, face, x, y + i,
- menu->submenu[i] != NULL);
+ /* Take note of the coordinates of the active menu item, to
+ display the cursor there. */
+ if (mousehere)
+ {
+ row = y + i;
+ col = x;
+ }
+ display_tty_menu_item (menu->text[j], max_width, face, x, y + i,
+ menu->submenu[j] != NULL);
}
- update_frame_with_menu (sf);
- cursor_to (sf, row, col);
+ update_frame_with_menu (sf, row, col);
}
/* --------------------------- X Menu emulation ---------------------- */
/* Create a new item in a menu pane. */
-static int
+static bool
tty_menu_add_selection (tty_menu *menu, int pane,
- char *txt, int enable, char const *help_text)
+ char *txt, bool enable, char const *help_text)
{
int len;
unsigned char *p;
if (pane)
- if (!(menu = tty_menu_search_pane (menu, pane)))
- return TTYM_FAILURE;
+ {
+ menu = tty_menu_search_pane (menu, pane);
+ if (! menu)
+ return 0;
+ }
tty_menu_make_room (menu);
menu->submenu[menu->count] = (tty_menu *) 0;
menu->text[menu->count] = txt;
if (len > menu->width)
menu->width = len;
- return TTYM_SUCCESS;
+ return 1;
}
/* Decide where the menu would be placed if requested at (X,Y). */
/* Make sure every row is enabled, or else update_frame will not
redraw them. (Rows that are identical to what is already on
screen will not be redrawn anyway.) */
- to->enabled_p = 1;
+ to->enabled_p = true;
to->hash = from->hash;
- if (from->used[LEFT_MARGIN_AREA])
- {
- nbytes = from->used[LEFT_MARGIN_AREA] * sizeof (struct glyph);
- to->glyphs[LEFT_MARGIN_AREA] = xmalloc (nbytes);
- memcpy (to->glyphs[LEFT_MARGIN_AREA],
- from->glyphs[LEFT_MARGIN_AREA], nbytes);
- to->used[LEFT_MARGIN_AREA] = from->used[LEFT_MARGIN_AREA];
- }
- if (from->used[RIGHT_MARGIN_AREA])
- {
- nbytes = from->used[RIGHT_MARGIN_AREA] * sizeof (struct glyph);
- to->glyphs[RIGHT_MARGIN_AREA] = xmalloc (nbytes);
- memcpy (to->glyphs[RIGHT_MARGIN_AREA],
- from->glyphs[RIGHT_MARGIN_AREA], nbytes);
- to->used[RIGHT_MARGIN_AREA] = from->used[RIGHT_MARGIN_AREA];
- }
}
return saved;
to->used[TEXT_AREA] = from->used[TEXT_AREA];
to->enabled_p = from->enabled_p;
to->hash = from->hash;
- nbytes = from->used[LEFT_MARGIN_AREA] * sizeof (struct glyph);
- if (nbytes)
- {
- eassert (to->glyphs[LEFT_MARGIN_AREA] != from->glyphs[LEFT_MARGIN_AREA]);
- memcpy (to->glyphs[LEFT_MARGIN_AREA],
- from->glyphs[LEFT_MARGIN_AREA], nbytes);
- to->used[LEFT_MARGIN_AREA] = from->used[LEFT_MARGIN_AREA];
- }
- else
- to->used[LEFT_MARGIN_AREA] = 0;
- nbytes = from->used[RIGHT_MARGIN_AREA] * sizeof (struct glyph);
- if (nbytes)
- {
- eassert (to->glyphs[RIGHT_MARGIN_AREA] != from->glyphs[RIGHT_MARGIN_AREA]);
- memcpy (to->glyphs[RIGHT_MARGIN_AREA],
- from->glyphs[RIGHT_MARGIN_AREA], nbytes);
- to->used[RIGHT_MARGIN_AREA] = from->used[RIGHT_MARGIN_AREA];
- }
- else
- to->used[RIGHT_MARGIN_AREA] = 0;
}
}
int i;
if (!saved)
- return; /* already freed */
+ return; /* Already freed! */
for (i = 0; i < saved->nrows; ++i)
{
struct glyph_row *from = saved->rows + i;
xfree (from->glyphs[TEXT_AREA]);
- if (from->used[LEFT_MARGIN_AREA])
- xfree (from->glyphs[LEFT_MARGIN_AREA]);
- if (from->used[RIGHT_MARGIN_AREA])
- xfree (from->glyphs[RIGHT_MARGIN_AREA]);
}
xfree (saved->rows);
screen_update (struct frame *f, struct glyph_matrix *mtx)
{
restore_desired_matrix (f, mtx);
- update_frame_with_menu (f);
+ update_frame_with_menu (f, -1, -1);
}
-/* Read user input and return X and Y coordinates where that input
- puts us. We only consider mouse movement and click events and
- keyboard movement commands; the rest are ignored.
+typedef enum {
+ MI_QUIT_MENU = -1,
+ MI_CONTINUE = 0,
+ MI_ITEM_SELECTED = 1,
+ MI_NEXT_ITEM = 2,
+ MI_PREV_ITEM = 3,
+ MI_SCROLL_FORWARD = 4,
+ MI_SCROLL_BACK = 5
+} mi_result;
- Value is -1 if C-g was pressed, 1 if an item was selected, 2 or 3
- if we need to move to the next or previous menu-bar menu, zero
- otherwise. */
-static int
+/* Read user input and return X and Y coordinates where that input
+ puts us. We only consider mouse movement and click events, and
+ keyboard movement commands; the rest are ignored. */
+static mi_result
read_menu_input (struct frame *sf, int *x, int *y, int min_y, int max_y,
bool *first_time)
{
else
{
Lisp_Object cmd;
- int usable_input = 1;
- int st = 0;
+ bool usable_input = 1;
+ mi_result st = MI_CONTINUE;
struct tty_display_info *tty = FRAME_TTY (sf);
Lisp_Object saved_mouse_tracking = do_mouse_tracking;
tty->showing_menu = 0;
do_mouse_tracking = saved_mouse_tracking;
- if (EQ (cmd, Qt) || EQ (cmd, Qtty_menu_exit))
- return -1;
+ if (EQ (cmd, Qt) || EQ (cmd, Qtty_menu_exit)
+ /* If some input switched frames under our feet, exit the
+ menu, since the menu faces are no longer valid, and the
+ menu is no longer relevant anyway. */
+ || sf != SELECTED_FRAME ())
+ return MI_QUIT_MENU;
if (EQ (cmd, Qtty_menu_mouse_movement))
mouse_get_xy (x, y);
else if (EQ (cmd, Qtty_menu_next_menu))
{
usable_input = 0;
- st = 2;
+ st = MI_NEXT_ITEM;
}
else if (EQ (cmd, Qtty_menu_prev_menu))
{
usable_input = 0;
- st = 3;
+ st = MI_PREV_ITEM;
}
else if (EQ (cmd, Qtty_menu_next_item))
{
if (*y < max_y)
*y += 1;
+ else
+ st = MI_SCROLL_FORWARD;
}
else if (EQ (cmd, Qtty_menu_prev_item))
{
if (*y > min_y)
*y -= 1;
+ else
+ st = MI_SCROLL_BACK;
}
else if (EQ (cmd, Qtty_menu_select))
- st = 1;
+ st = MI_ITEM_SELECTED;
else if (!EQ (cmd, Qtty_menu_ignore))
usable_input = 0;
if (usable_input)
sf->mouse_moved = 1;
return st;
}
- return 0;
+ return MI_CONTINUE;
}
/* Display menu, wait for user's response, and return that response. */
tty_menu_activate (tty_menu *menu, int *pane, int *selidx,
int x0, int y0, char **txt,
void (*help_callback)(char const *, int, int),
- int kbd_navigation)
+ bool kbd_navigation)
{
struct tty_menu_state *state;
- int statecount, x, y, i, leave, onepane;
+ int statecount, x, y, i;
+ bool leave, onepane;
int result IF_LINT (= 0);
- int title_faces[4]; /* face to display the menu title */
+ int title_faces[4]; /* Face to display the menu title. */
int faces[4], buffers_num_deleted = 0;
struct frame *sf = SELECTED_FRAME ();
struct tty_display_info *tty = FRAME_TTY (sf);
bool first_time;
Lisp_Object selectface;
+ int first_item = 0;
+ int col, row;
/* Don't allow non-positive x0 and y0, lest the menu will wrap
around the display. */
/* Force update of the current frame, so that the desired and the
current matrices are identical. */
- update_frame_with_menu (sf);
+ update_frame_with_menu (sf, -1, -1);
state[0].menu = menu;
state[0].screen_behind = save_and_enable_current_matrix (sf);
want to interpret them as zero-based column and row coordinates,
and also because we want the first item of the menu, not its
title, to appear at x0,y0. */
- tty_menu_display (menu, x0 - 1, y0 - 1, 1, title_faces, x0 - 1, y0 - 1, 0);
+ tty_menu_display (menu, x0 - 1, y0 - 1, 1, title_faces, x0 - 1, y0 - 1, 0, 0);
/* Turn off the cursor. Otherwise it shows through the menu
panes, which is ugly. */
+ col = cursorX (tty);
+ row = cursorY (tty);
tty_hide_cursor (tty);
+
if (buffers_num_deleted)
menu->text[0][7] = ' ';
- if ((onepane = menu->count == 1 && menu->submenu[0]))
+ onepane = menu->count == 1 && menu->submenu[0];
+ if (onepane)
{
menu->width = menu->submenu[0]->width;
state[0].menu = menu->submenu[0];
leave = 0;
while (!leave)
{
- int input_status;
- int min_y = state[0].y, max_y = min_y + state[0].menu->count - 1;
+ mi_result input_status;
+ int min_y = state[0].y;
+ int max_y = min (min_y + state[0].menu->count, FRAME_LINES (sf) - 1) - 1;
input_status = read_menu_input (sf, &x, &y, min_y, max_y, &first_time);
if (input_status)
{
leave = 1;
- if (input_status == -1)
+ switch (input_status)
{
+ case MI_QUIT_MENU:
/* Remove the last help-echo, so that it doesn't
re-appear after "Quit". */
show_help_echo (Qnil, Qnil, Qnil, Qnil);
result = TTYM_NO_SELECT;
- }
- else if (input_status == 2)
- {
+ break;
+ case MI_NEXT_ITEM:
if (kbd_navigation)
result = TTYM_NEXT;
else
leave = 0;
- }
- else if (input_status == 3)
- {
+ break;
+ case MI_PREV_ITEM:
if (kbd_navigation)
result = TTYM_PREV;
else
leave = 0;
+ break;
+ case MI_SCROLL_FORWARD:
+ if (y - min_y == state[0].menu->count - 1 - first_item)
+ {
+ y = min_y;
+ first_item = 0;
+ }
+ else
+ first_item++;
+ leave = 0;
+ break;
+ case MI_SCROLL_BACK:
+ if (first_item == 0)
+ {
+ y = max_y;
+ first_item = state[0].menu->count - 1 - (y - min_y);
+ }
+ else
+ first_item--;
+ leave = 0;
+ break;
+ default:
+ /* MI_ITEM_SELECTED is handled below, so nothing to do. */
+ break;
}
}
- if (sf->mouse_moved && input_status != -1)
+ if (sf->mouse_moved && input_status != MI_QUIT_MENU)
{
sf->mouse_moved = 0;
result = TTYM_IA_SELECT;
for (i = 0; i < statecount; i++)
if (state[i].x <= x && x < state[i].x + state[i].menu->width + 2)
{
- int dy = y - state[i].y;
+ int dy = y - state[i].y + first_item;
if (0 <= dy && dy < state[i].menu->count)
{
if (!state[i].menu->submenu[dy])
have been opened. That does not include an open and
active submenu. */
if (i != statecount - 2
- || state[i].menu->submenu[dy] != state[i+1].menu)
+ || state[i].menu->submenu[dy] != state[i + 1].menu)
while (i != statecount - 1)
{
statecount--;
state[i].x,
state[i].y,
state[i].pane,
- faces, x, y, 1);
+ faces, x, y, first_item, 1);
state[statecount].menu = state[i].menu->submenu[dy];
state[statecount].pane = state[i].menu->panenumber[dy];
state[statecount].screen_behind
state[statecount - 1].x,
state[statecount - 1].y,
state[statecount - 1].pane,
- faces, x, y, 1);
- tty_hide_cursor (tty);
- fflush (tty->output);
+ faces, x, y, first_item, 1);
+ /* The call to display help-echo below will move the cursor,
+ so remember its current position as computed by
+ tty_menu_display. */
+ col = cursorX (tty);
+ row = cursorY (tty);
}
/* Display the help-echo message for the currently-selected menu
{
help_callback (menu_help_message,
menu_help_paneno, menu_help_itemno);
- tty_hide_cursor (tty);
- fflush (tty->output);
+ /* Move the cursor to the beginning of the current menu
+ item, so that screen readers and other accessibility aids
+ know where the active region is. */
+ cursor_to (sf, row, col);
prev_menu_help_message = menu_help_message;
}
+ /* Both tty_menu_display and help_callback invoke update_end,
+ which calls tty_show_cursor. Re-hide it, so it doesn't show
+ through the menus. */
+ tty_hide_cursor (tty);
+ fflush (tty->output);
}
sf->mouse_moved = 0;
screen_update (sf, state[0].screen_behind);
while (statecount--)
free_saved_screen (state[statecount].screen_behind);
- tty_show_cursor (tty); /* turn cursor back on */
+ tty_show_cursor (tty); /* Turn cursor back on. */
fflush (tty->output);
/* Clean up any mouse events that are waiting inside Emacs event queue.
Lisp_Object pane_name;
Lisp_Object menu_object;
- first_item = XVECTOR (menu_items)->u.contents;
+ first_item = XVECTOR (menu_items)->contents;
if (EQ (first_item[0], Qt))
pane_name = first_item[MENU_ITEMS_PANE_NAME];
else if (EQ (first_item[0], Qquote))
break;
i += 4;
}
- i -= 4; /* went one too far */
+ i -= 4; /* Went one too far! */
}
return i;
}
if (i < last_i)
*x = XINT (AREF (items, i + 4 + 3));
else
- *x = 0; /* wrap around to the first item */
+ *x = 0; /* Wrap around to the first item. */
}
else if (prev_x < 0)
{
}
}
+/* WINDOWSNT uses this as menu_show_hook, see w32console.c. */
Lisp_Object
-tty_menu_show (struct frame *f, int x, int y, int for_click, int keymaps,
- Lisp_Object title, int kbd_navigation, const char **error_name)
+tty_menu_show (struct frame *f, int x, int y, int menuflags,
+ Lisp_Object title, const char **error_name)
{
tty_menu *menu;
int pane, selidx, lpane, status;
int dispwidth, dispheight;
int i, j, lines, maxlines;
int maxwidth;
- ptrdiff_t specpdl_count = SPECPDL_INDEX ();
+ ptrdiff_t specpdl_count;
- if (! FRAME_TERMCAP_P (f))
- emacs_abort ();
+ eassert (FRAME_TERMCAP_P (f));
*error_name = 0;
if (menu_items_n_panes == 0)
return Qnil;
}
- /* Don't GC while we prepare and show the menu, because we give the
- menu functions pointers to the contents of strings. */
- inhibit_garbage_collection ();
+ dynwind_begin ();
+
+ /* Avoid crashes if, e.g., another client will connect while we
+ are in a menu. */
+ temporarily_switch_to_single_kboard (f);
/* Adjust coordinates to be root-window-relative. */
item_x = x += f->left_pos;
prefix = AREF (menu_items, i + MENU_ITEMS_PANE_PREFIX);
pane_string = (NILP (pane_name)
? "" : SSDATA (pane_name));
- if (keymaps && !NILP (prefix))
+ if ((menuflags & MENU_KEYMAPS) && !NILP (prefix))
pane_string++;
lpane = tty_menu_add_pane (menu, pane_string);
{
tty_menu_destroy (menu);
*error_name = "Can't create pane";
- return Qnil;
+ entry = Qnil;
+ goto tty_menu_end;
}
i += MENU_ITEMS_PANE_LENGTH;
if (!NILP (descrip))
{
- /* if alloca is fast, use that to make the space,
+ /* If alloca is fast, use that to make the space,
to reduce gc needs. */
item_data = (char *) alloca (maxwidth + SBYTES (descrip) + 1);
memcpy (item_data, SSDATA (item_name), SBYTES (item_name));
item_data = SSDATA (item_name);
if (lpane == TTYM_FAILURE
- || (tty_menu_add_selection (menu, lpane, item_data,
- !NILP (enable), help_string)
- == TTYM_FAILURE))
+ || (! tty_menu_add_selection (menu, lpane, item_data,
+ !NILP (enable), help_string)))
{
tty_menu_destroy (menu);
*error_name = "Can't add selection to menu";
- return Qnil;
+ entry = Qnil;
+ goto tty_menu_end;
}
i += MENU_ITEMS_ITEM_LENGTH;
lines++;
x = max (x, 1);
y = max (y, 1);
tty_menu_locate (menu, x, y, &ulx, &uly, &width, &height);
- if (ulx+width > dispwidth)
+ if (ulx + width > dispwidth)
{
x -= (ulx + width) - dispwidth;
ulx = dispwidth - width;
}
- if (uly+height > dispheight)
+ if (uly + height > dispheight)
{
y -= (uly + height) - dispheight;
uly = dispheight - height;
}
- if (FRAME_HAS_MINIBUF_P (f) && uly+height > dispheight - 2)
+ if (FRAME_HAS_MINIBUF_P (f) && uly + height > dispheight - 2)
{
/* Move the menu away of the echo area, to avoid overwriting the
menu with help echo messages or vice versa. */
/* If position was not given by a mouse click, adjust so upper left
corner of the menu as a whole ends up at given coordinates. This
is what x-popup-menu says in its documentation. */
- x += width/2;
- y += 1.5*height/(maxlines+2);
+ x += width / 2;
+ y += 1.5 * height / (maxlines + 2);
}
#endif
specbind (Qoverriding_terminal_local_map,
Fsymbol_value (Qtty_menu_navigation_map));
status = tty_menu_activate (menu, &pane, &selidx, x, y, &datap,
- tty_menu_help_callback, kbd_navigation);
+ tty_menu_help_callback,
+ menuflags & MENU_KBD_NAVIGATION);
entry = pane_prefix = Qnil;
switch (status)
{
entry
= AREF (menu_items, i + MENU_ITEMS_ITEM_VALUE);
- if (keymaps != 0)
+ if (menuflags & MENU_KEYMAPS)
{
entry = Fcons (entry, Qnil);
if (!NILP (pane_prefix))
case TTYM_IA_SELECT:
break;
case TTYM_NO_SELECT:
+ /* If the selected frame was changed while we displayed a menu,
+ throw to top level in order to undo any temporary settings
+ made by TTY menu code. */
+ if (f != SELECTED_FRAME ())
+ Ftop_level ();
/* Make "Cancel" equivalent to C-g unless FOR_CLICK (which means
the menu was invoked with a mouse event as POSITION). */
- if (! for_click)
+ if (!(menuflags & MENU_FOR_CLICK))
Fsignal (Qquit, Qnil);
break;
}
- unbind_to (specpdl_count, Qnil);
+ tty_menu_end:
+ dynwind_end ();
return entry;
}
-#endif /* HAVE_MENUS && !MSDOS */
+#endif /* !MSDOS */
\f
#ifndef MSDOS
***********************************************************************/
/* Initialize the tty-dependent part of frame F. The frame must
- already have its device initialized. */
+ already have its device initialized. */
void
create_tty_output (struct frame *f)
f->output_data.tty = t;
}
-/* Delete frame F's face cache, and its tty-dependent part. */
+/* Delete frame F's face cache, and its tty-dependent part. */
static void
tty_free_frame_resources (struct frame *f)
{
eassert (FRAME_TERMCAP_P (f));
-
- if (FRAME_FACE_CACHE (f))
- free_frame_faces (f);
-
+ free_frame_faces (f);
xfree (f->output_data.tty);
}
#else /* MSDOS */
-/* Delete frame F's face cache. */
+/* Delete frame F's face cache. */
static void
tty_free_frame_resources (struct frame *f)
{
eassert (FRAME_TERMCAP_P (f) || FRAME_MSDOS_P (f));
-
- if (FRAME_FACE_CACHE (f))
- free_frame_faces (f);
+ free_frame_faces (f);
}
#endif /* MSDOS */
\f
terminal->frame_rehighlight_hook = 0;
terminal->frame_raise_lower_hook = 0;
terminal->fullscreen_hook = 0;
+ terminal->menu_show_hook = 0;
terminal->set_vertical_scroll_bar_hook = 0;
terminal->condemn_scroll_bars_hook = 0;
terminal->redeem_scroll_bar_hook = 0;
static void
set_tty_hooks (struct terminal *terminal)
{
- terminal->rif = 0; /* ttys don't support window-based redisplay. */
-
terminal->cursor_to_hook = &tty_cursor_to;
terminal->raw_cursor_to_hook = &tty_raw_cursor_to;
-
terminal->clear_to_end_hook = &tty_clear_to_end;
terminal->clear_frame_hook = &tty_clear_frame;
terminal->clear_end_of_line_hook = &tty_clear_end_of_line;
-
terminal->ins_del_lines_hook = &tty_ins_del_lines;
-
terminal->insert_glyphs_hook = &tty_insert_glyphs;
terminal->write_glyphs_hook = &tty_write_glyphs;
terminal->delete_glyphs_hook = &tty_delete_glyphs;
-
terminal->ring_bell_hook = &tty_ring_bell;
-
terminal->reset_terminal_modes_hook = &tty_reset_terminal_modes;
terminal->set_terminal_modes_hook = &tty_set_terminal_modes;
- terminal->update_begin_hook = 0; /* Not needed. */
terminal->update_end_hook = &tty_update_end;
+ terminal->menu_show_hook = &tty_menu_show;
terminal->set_terminal_window_hook = &tty_set_terminal_window;
-
- terminal->mouse_position_hook = 0; /* Not needed. */
- terminal->frame_rehighlight_hook = 0; /* Not needed. */
- terminal->frame_raise_lower_hook = 0; /* Not needed. */
-
- terminal->set_vertical_scroll_bar_hook = 0; /* Not needed. */
- terminal->condemn_scroll_bars_hook = 0; /* Not needed. */
- terminal->redeem_scroll_bar_hook = 0; /* Not needed. */
- terminal->judge_scroll_bars_hook = 0; /* Not needed. */
-
terminal->read_socket_hook = &tty_read_avail_input; /* keyboard.c */
- terminal->frame_up_to_date_hook = 0; /* Not needed. */
-
terminal->delete_frame_hook = &tty_free_frame_resources;
terminal->delete_terminal_hook = &delete_tty;
+ /* Other hooks are NULL by default. */
}
/* If FD is the controlling terminal, drop it. */
/* setsid failed, presumably because Emacs is already a process
group leader. Fall back on the obsolescent way to dissociate
a controlling tty. */
- block_tty_out_signal ();
+ sigset_t oldset;
+ block_tty_out_signal (&oldset);
ioctl (fd, TIOCNOTTY, 0);
- unblock_tty_out_signal ();
+ unblock_tty_out_signal (&oldset);
#endif
}
}
int status;
struct tty_display_info *tty = NULL;
struct terminal *terminal = NULL;
+ sigset_t oldset;
bool ctty = false; /* True if asked to open controlling tty. */
if (!terminal_type)
if (terminal)
return terminal;
- terminal = create_terminal ();
+ terminal = create_terminal (output_termcap, NULL);
#ifdef MSDOS
if (been_here > 0)
maybe_fatal (0, 0, "Attempt to create another terminal %s", "",
tty->next = tty_list;
tty_list = tty;
- terminal->type = output_termcap;
terminal->display_info.tty = tty;
tty->terminal = terminal;
open a frame on the same terminal. */
int flags = O_RDWR | O_NOCTTY | (ctty ? 0 : O_IGNORE_CTTY);
int fd = emacs_open (name, flags, 0);
- tty->input = tty->output = fd < 0 || ! isatty (fd) ? 0 : fdopen (fd, "w+");
+ tty->input = tty->output =
+ ((fd < 0 || ! isatty (fd))
+ ? NULL
+ : fdopen (fd, "w+"));
if (! tty->input)
{
char const *diagnostic
- = tty->input ? "Not a tty device: %s" : "Could not open file: %s";
+ = (fd < 0) ? "Could not open file: %s" : "Not a tty device: %s";
emacs_close (fd);
maybe_fatal (must_succeed, terminal, diagnostic, diagnostic, name);
}
/* On some systems, tgetent tries to access the controlling
terminal. */
- block_tty_out_signal ();
+ block_tty_out_signal (&oldset);
status = tgetent (tty->termcap_term_buffer, terminal_type);
if (tty->termcap_term_buffer[TERMCAP_BUFFER_SIZE - 1])
emacs_abort ();
- unblock_tty_out_signal ();
+ unblock_tty_out_signal (&oldset);
if (status < 0)
{
/* Since we make MagicWrap terminals look like AutoWrap, we need to have
the former flag imply the latter. */
AutoWrap (tty) = MagicWrap (tty) || tgetflag ("am");
- terminal->memory_below_frame = tgetflag ("db");
+ tty->memory_below_frame = tgetflag ("db");
tty->TF_hazeltine = tgetflag ("hz");
- terminal->must_write_spaces = tgetflag ("in");
+ tty->must_write_spaces = tgetflag ("in");
tty->meta_key = tgetflag ("km") || tgetflag ("MT");
tty->TF_insmode_motion = tgetflag ("mi");
tty->TF_standout_motion = tgetflag ("ms");
tty->specified_window = height;
FRAME_VERTICAL_SCROLL_BAR_TYPE (f) = vertical_scroll_bar_none;
- terminal->char_ins_del_ok = 1;
+ tty->char_ins_del_ok = 1;
baud_rate = 19200;
}
#else /* MSDOS */
get_tty_size (fileno (tty->input), &width, &height);
FrameCols (tty) = width;
FrameRows (tty) = height;
- terminal->char_ins_del_ok = 0;
+ tty->char_ins_del_ok = 0;
init_baud_rate (fileno (tty->input));
}
#endif /* MSDOS */
tty->delete_in_insert_mode = 1;
UseTabs (tty) = 0;
- terminal->scroll_region_ok = 0;
+ tty->scroll_region_ok = 0;
/* Seems to insert lines when it's not supposed to, messing up the
display. In doing a trace, it didn't seem to be called much, so I
don't think we're losing anything by turning it off. */
- terminal->line_ins_del_ok = 0;
+ tty->line_ins_del_ok = 0;
tty->TN_max_colors = 16; /* Must be non-zero for tty-display-color-p. */
#endif /* DOS_NT */
UseTabs (tty) = tabs_safe_p (fileno (tty->input)) && TabWidth (tty) == 8;
- terminal->scroll_region_ok
+ tty->scroll_region_ok
= (tty->Wcm->cm_abs
&& (tty->TS_set_window || tty->TS_set_scroll_region || tty->TS_set_scroll_region_1));
- terminal->line_ins_del_ok
+ tty->line_ins_del_ok
= (((tty->TS_ins_line || tty->TS_ins_multi_lines)
&& (tty->TS_del_line || tty->TS_del_multi_lines))
- || (terminal->scroll_region_ok
+ || (tty->scroll_region_ok
&& tty->TS_fwd_scroll && tty->TS_rev_scroll));
- terminal->char_ins_del_ok
+ tty->char_ins_del_ok
= ((tty->TS_ins_char || tty->TS_insert_mode
|| tty->TS_pad_inserted_char || tty->TS_ins_multi_chars)
&& (tty->TS_del_char || tty->TS_del_multi_chars));
- terminal->fast_clear_end_of_line = tty->TS_clr_line != 0;
-
init_baud_rate (fileno (tty->input));
#endif /* not DOS_NT */
void
syms_of_term (void)
{
+#include "term.x"
+
DEFVAR_BOOL ("system-uses-terminfo", system_uses_terminfo,
doc: /* Non-nil means the system uses terminfo rather than termcap.
This variable can be used by terminal emulator packages. */);
bigger, or it may make it blink, or it may do nothing at all. */);
visible_cursor = 1;
- defsubr (&Stty_display_color_p);
- defsubr (&Stty_display_color_cells);
- defsubr (&Stty_no_underline);
- defsubr (&Stty_type);
- defsubr (&Scontrolling_tty_p);
- defsubr (&Stty_top_frame);
- defsubr (&Ssuspend_tty);
- defsubr (&Sresume_tty);
-#ifdef HAVE_GPM
- defsubr (&Sgpm_mouse_start);
- defsubr (&Sgpm_mouse_stop);
-#endif /* HAVE_GPM */
-
#ifndef DOS_NT
default_orig_pair = NULL;
default_set_foreground = NULL;
encode_terminal_src = NULL;
encode_terminal_dst = NULL;
+ DEFSYM (Qtty_mode_set_strings, "tty-mode-set-strings");
+ DEFSYM (Qtty_mode_reset_strings, "tty-mode-reset-strings");
+
+#ifndef MSDOS
DEFSYM (Qtty_menu_next_item, "tty-menu-next-item");
DEFSYM (Qtty_menu_prev_item, "tty-menu-prev-item");
DEFSYM (Qtty_menu_next_menu, "tty-menu-next-menu");
DEFSYM (Qtty_menu_exit, "tty-menu-exit");
DEFSYM (Qtty_menu_mouse_movement, "tty-menu-mouse-movement");
DEFSYM (Qtty_menu_navigation_map, "tty-menu-navigation-map");
+#endif
}