#include <stdio.h>
#include <ctype.h>
#include <string.h>
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif
#include "termchar.h"
#include "termopts.h"
#include "lisp.h"
+#include "buffer.h"
+#include "character.h"
#include "charset.h"
#include "coding.h"
+#include "composite.h"
#include "keyboard.h"
#include "frame.h"
#include "disptab.h"
#include "window.h"
#include "keymap.h"
#include "blockinput.h"
+#include "intervals.h"
/* For now, don't try to include termcap.h. On some systems,
configure finds a non-standard termcap.h that the main build
#ifdef HAVE_GPM
#include <sys/fcntl.h>
-#include "buffer.h"
/* Nonzero means mouse is enabled on Linux console. */
int term_gpm = 0;
static int mouse_face_beg_row, mouse_face_beg_col;
static int mouse_face_end_row, mouse_face_end_col;
static int mouse_face_past_end;
-static Lisp_Object mouse_face_window;
+static Lisp_Object Qmouse_face_window;
static int mouse_face_face_id;
-/* FRAME and X, Y position of mouse when last checked for
- highlighting. X and Y can be negative or out of range for the frame. */
-struct frame *mouse_face_mouse_frame;
-int mouse_face_mouse_x, mouse_face_mouse_y;
-
static int pos_x, pos_y;
static int last_mouse_x, last_mouse_y;
#endif /* HAVE_GPM */
}
}
\f
-/* Buffer to store the source and result of code conversion for terminal. */
-static unsigned char *encode_terminal_buf;
-/* Allocated size of the above buffer. */
-static int encode_terminal_bufsize;
+/* Buffers to store the source and result of code conversion for terminal. */
+static unsigned char *encode_terminal_src;
+static unsigned char *encode_terminal_dst;
+/* Allocated sizes of the above buffers. */
+static int encode_terminal_src_size;
+static int encode_terminal_dst_size;
/* Encode SRC_LEN glyphs starting at SRC to terminal output codes.
Set CODING->produced to the byte-length of the resulting byte
int nchars, nbytes, required;
register int tlen = GLYPH_TABLE_LENGTH;
register Lisp_Object *tbase = GLYPH_TABLE_BASE;
+ Lisp_Object charset_list;
/* Allocate sufficient size of buffer to store all characters in
multibyte-form. But, it may be enlarged on demand if
- Vglyph_table contains a string. */
+ Vglyph_table contains a string or a composite glyph is
+ encountered. */
required = MAX_MULTIBYTE_LENGTH * src_len;
- if (encode_terminal_bufsize < required)
+ if (encode_terminal_src_size < required)
{
- if (encode_terminal_bufsize == 0)
- encode_terminal_buf = xmalloc (required);
+ if (encode_terminal_src_size == 0)
+ encode_terminal_src = xmalloc (required);
else
- encode_terminal_buf = xrealloc (encode_terminal_buf, required);
- encode_terminal_bufsize = required;
+ encode_terminal_src = xrealloc (encode_terminal_src, required);
+ encode_terminal_src_size = required;
}
- buf = encode_terminal_buf;
+ charset_list = coding_charset_list (coding);
+
+ buf = encode_terminal_src;
nchars = 0;
while (src < src_end)
{
+ if (src->type == COMPOSITE_GLYPH)
+ {
+ struct composition *cmp = composition_table[src->u.cmp_id];
+ int i;
+
+ nbytes = buf - encode_terminal_src;
+ required = MAX_MULTIBYTE_LENGTH * cmp->glyph_len;
+
+ if (encode_terminal_src_size < nbytes + required)
+ {
+ encode_terminal_src_size = nbytes + required;
+ encode_terminal_src = xrealloc (encode_terminal_src,
+ encode_terminal_src_size);
+ buf = encode_terminal_src + nbytes;
+ }
+
+ for (i = 0; i < cmp->glyph_len; i++)
+ {
+ int c = COMPOSITION_GLYPH (cmp, i);
+
+ if (! char_charset (c, charset_list, NULL))
+ break;
+ buf += CHAR_STRING (c, buf);
+ nchars++;
+ }
+ if (i == 0)
+ {
+ /* The first character of the composition is not encodable. */
+ *buf++ = '?';
+ nchars++;
+ }
+ }
/* We must skip glyphs to be padded for a wide character. */
- if (! CHAR_GLYPH_PADDING_P (*src))
+ else if (! CHAR_GLYPH_PADDING_P (*src))
{
+ int c;
+ Lisp_Object string;
+
+ string = Qnil;
g = GLYPH_FROM_CHAR_GLYPH (src[0]);
if (g < 0 || g >= tlen)
{
/* This glyph doesn't has an entry in Vglyph_table. */
- if (CHAR_VALID_P (src->u.ch, 0))
- buf += CHAR_STRING (src->u.ch, buf);
- else
- *buf++ = SPACEGLYPH;
- nchars++;
+ c = src->u.ch;
}
else
{
GLYPH_FOLLOW_ALIASES (tbase, tlen, g);
if (GLYPH_SIMPLE_P (tbase, tlen, g))
- {
- int c = FAST_GLYPH_CHAR (g);
+ /* We set the multi-byte form of a character in G
+ (that should be an ASCII character) at WORKBUF. */
+ c = FAST_GLYPH_CHAR (g);
+ else
+ /* We have a string in Vglyph_table. */
+ string = tbase[g];
+ }
- if (CHAR_VALID_P (c, 0))
- buf += CHAR_STRING (c, buf);
- else
- *buf++ = SPACEGLYPH;
+ if (NILP (string))
+ {
+ nbytes = buf - encode_terminal_src;
+ if (encode_terminal_src_size < nbytes + MAX_MULTIBYTE_LENGTH)
+ {
+ encode_terminal_src_size = nbytes + MAX_MULTIBYTE_LENGTH;
+ encode_terminal_src = xrealloc (encode_terminal_src,
+ encode_terminal_src_size);
+ buf = encode_terminal_src + nbytes;
+ }
+ if (char_charset (c, charset_list, NULL))
+ {
+ /* Store the multibyte form of C at BUF. */
+ buf += CHAR_STRING (c, buf);
nchars++;
}
else
{
- /* We have a string in Vglyph_table. */
- Lisp_Object string;
-
- string = tbase[g];
- if (! STRING_MULTIBYTE (string))
- string = string_to_multibyte (string);
- nbytes = buf - encode_terminal_buf;
- if (encode_terminal_bufsize < nbytes + SBYTES (string))
+ /* C is not encodable. */
+ *buf++ = '?';
+ nchars++;
+ while (src + 1 < src_end && CHAR_GLYPH_PADDING_P (src[1]))
{
- encode_terminal_bufsize = nbytes + SBYTES (string);
- encode_terminal_buf = xrealloc (encode_terminal_buf,
- encode_terminal_bufsize);
- buf = encode_terminal_buf + nbytes;
+ *buf++ = '?';
+ nchars++;
+ src++;
}
- bcopy (SDATA (string), buf, SBYTES (string));
- buf += SBYTES (string);
- nchars += SCHARS (string);
}
}
+ else
+ {
+ unsigned char *p = SDATA (string), *pend = p + SBYTES (string);
+
+ if (! STRING_MULTIBYTE (string))
+ string = string_to_multibyte (string);
+ nbytes = buf - encode_terminal_src;
+ if (encode_terminal_src_size < nbytes + SBYTES (string))
+ {
+ encode_terminal_src_size = nbytes + SBYTES (string);
+ encode_terminal_src = xrealloc (encode_terminal_src,
+ encode_terminal_src_size);
+ buf = encode_terminal_src + nbytes;
+ }
+ bcopy (SDATA (string), buf, SBYTES (string));
+ buf += SBYTES (string);
+ nchars += SCHARS (string);
+ }
}
src++;
}
- nbytes = buf - encode_terminal_buf;
- coding->src_multibyte = 1;
- coding->dst_multibyte = 0;
- if (SYMBOLP (coding->pre_write_conversion)
- && ! NILP (Ffboundp (coding->pre_write_conversion)))
+ if (nchars == 0)
{
- run_pre_write_conversin_on_c_str (&encode_terminal_buf,
- &encode_terminal_bufsize,
- nchars, nbytes, coding);
- nchars = coding->produced_char;
- nbytes = coding->produced;
+ coding->produced = 0;
+ return NULL;
}
- required = nbytes + encoding_buffer_size (coding, nbytes);
- if (encode_terminal_bufsize < required)
+
+ nbytes = buf - encode_terminal_src;
+ coding->source = encode_terminal_src;
+ if (encode_terminal_dst_size == 0)
{
- encode_terminal_bufsize = required;
- encode_terminal_buf = xrealloc (encode_terminal_buf, required);
+ encode_terminal_dst_size = encode_terminal_src_size;
+ encode_terminal_dst = xmalloc (encode_terminal_dst_size);
}
+ coding->destination = encode_terminal_dst;
+ coding->dst_bytes = encode_terminal_dst_size;
+ encode_coding_object (coding, Qnil, 0, 0, nchars, nbytes, Qnil);
+ /* coding->destination may have been reallocated. */
+ encode_terminal_dst = coding->destination;
+ encode_terminal_dst_size = coding->dst_bytes;
- encode_coding (coding, encode_terminal_buf, encode_terminal_buf + nbytes,
- nbytes, encode_terminal_bufsize - nbytes);
- return encode_terminal_buf + nbytes;
+ return (encode_terminal_dst);
}
+
void
write_glyphs (string, len)
register struct glyph *string;
register int len;
{
+ int produced, consumed;
struct frame *sf = XFRAME (selected_frame);
struct frame *f = updating_frame ? updating_frame : sf;
unsigned char *conversion_buffer;
#ifdef static
#define append_glyph append_glyph_term
#define produce_stretch_glyph produce_stretch_glyph_term
+#define append_composite_glyph append_composite_glyph_term
+#define produce_composite_glyph produce_composite_glyph_term
#endif
static void append_glyph P_ ((struct it *));
static void produce_stretch_glyph P_ ((struct it *));
-
+static void append_composite_glyph P_ ((struct it *));
+static void produce_composite_glyph P_ ((struct it *));
/* Append glyphs to IT's glyph_row. Called from produce_glyphs for
terminal frames if IT->glyph_row != NULL. IT->char_to_display is
struct it *it;
{
/* If a hook is installed, let it do the work. */
+
+ /* Nothing but characters are supported on terminal frames. */
xassert (it->what == IT_CHARACTER
|| it->what == IT_COMPOSITION
|| it->what == IT_STRETCH);
goto done;
}
- /* Nothing but characters are supported on terminal frames. For a
- composition sequence, it->c is the first character of the
- sequence. */
- xassert (it->what == IT_CHARACTER
- || it->what == IT_COMPOSITION);
+ if (it->what == IT_COMPOSITION)
+ {
+ produce_composite_glyph (it);
+ goto done;
+ }
/* Maybe translate single-byte characters to multibyte. */
it->char_to_display = it->c;
it->pixel_width = nspaces;
it->nglyphs = nspaces;
}
- else if (SINGLE_BYTE_CHAR_P (it->c))
+ else if (CHAR_BYTE8_P (it->c))
{
if (unibyte_display_via_language_environment
- && (it->c >= 0240
- || !NILP (Vnonascii_translation_table)))
+ && (it->c >= 0240))
{
- int charset;
-
it->char_to_display = unibyte_char_to_multibyte (it->c);
- charset = CHAR_CHARSET (it->char_to_display);
- it->pixel_width = CHARSET_WIDTH (charset);
+ it->pixel_width = CHAR_WIDTH (it->char_to_display);
it->nglyphs = it->pixel_width;
if (it->glyph_row)
append_glyph (it);
}
else
{
- /* Coming here means that it->c is from display table, thus we
- must send the code as is to the terminal. Although there's
- no way to know how many columns it occupies on a screen, it
- is a good assumption that a single byte code has 1-column
- width. */
+ /* Coming here means that it->c is from display table, thus
+ we must send the raw 8-bit byte as is to the terminal.
+ Although there's no way to know how many columns it
+ occupies on a screen, it is a good assumption that a
+ single byte code has 1-column width. */
it->pixel_width = it->nglyphs = 1;
if (it->glyph_row)
append_glyph (it);
}
else
{
- /* A multi-byte character. The display width is fixed for all
- characters of the set. Some of the glyphs may have to be
- ignored because they are already displayed in a continued
- line. */
- int charset = CHAR_CHARSET (it->c);
-
- it->pixel_width = CHARSET_WIDTH (charset);
+ it->pixel_width = CHAR_WIDTH (it->c);
it->nglyphs = it->pixel_width;
if (it->glyph_row)
}
+/* Append glyphs to IT's glyph_row for the composition IT->cmp_id.
+ Called from produce_composite_glyph for terminal frames if
+ IT->glyph_row != NULL. IT->face_id contains the character's
+ face. */
+
+static void
+append_composite_glyph (it)
+ struct it *it;
+{
+ struct glyph *glyph;
+
+ xassert (it->glyph_row);
+ glyph = it->glyph_row->glyphs[it->area] + it->glyph_row->used[it->area];
+ if (glyph < it->glyph_row->glyphs[1 + it->area])
+ {
+ glyph->type = COMPOSITE_GLYPH;
+ glyph->pixel_width = it->pixel_width;
+ glyph->u.cmp_id = it->cmp_id;
+ glyph->face_id = it->face_id;
+ glyph->padding_p = 0;
+ glyph->charpos = CHARPOS (it->position);
+ glyph->object = it->object;
+
+ ++it->glyph_row->used[it->area];
+ ++glyph;
+ }
+}
+
+
+/* Produce a composite glyph for iterator IT. IT->cmp_id is the ID of
+ the composition. We simply produces components of the composition
+ assuming that that the terminal has a capability to layout/render
+ it correctly. */
+
+static void
+produce_composite_glyph (it)
+ struct it *it;
+{
+ struct composition *cmp = composition_table[it->cmp_id];
+ int c;
+
+ xassert (cmp->glyph_len > 0);
+ c = COMPOSITION_GLYPH (cmp, 0);
+ it->pixel_width = CHAR_WIDTH (it->c);
+ it->nglyphs = 1;
+
+ if (it->glyph_row)
+ append_composite_glyph (it);
+}
+
+
/* Get information about special display element WHAT in an
environment described by IT. WHAT is one of IT_TRUNCATION or
IT_CONTINUATION. Maybe produce glyphs for WHAT if IT has a
***********************************************************************/
#ifdef HAVE_GPM
+void
+term_mouse_moveto (int x, int y)
+{
+ /* TODO: how to set mouse position?
+ const char *name;
+ int fd;
+ name = (const char *) ttyname (0);
+ fd = open (name, O_WRONLY);
+ SOME_FUNCTION (x, y, fd);
+ close (fd);
+ last_mouse_x = x;
+ last_mouse_y = y; */
+}
+
static void
term_show_mouse_face (enum draw_glyphs_face draw)
{
- struct window *w = XWINDOW (mouse_face_window);
+ struct window *w = XWINDOW (Qmouse_face_window);
int save_x, save_y;
- int i, j;
+ int i;
if (/* If window is in the process of being destroyed, don't bother
to do anything. */
static void
term_clear_mouse_face ()
{
- if (!NILP (mouse_face_window))
+ if (!NILP (Qmouse_face_window))
term_show_mouse_face (DRAW_NORMAL_TEXT);
mouse_face_beg_row = mouse_face_beg_col = -1;
mouse_face_end_row = mouse_face_end_col = -1;
- mouse_face_window = Qnil;
+ Qmouse_face_window = Qnil;
}
/* Find the glyph matrix position of buffer position POS in window W.
|| !f->glyphs_initialized_p)
return;
- mouse_face_mouse_x = x;
- mouse_face_mouse_y = y;
- mouse_face_mouse_frame = f;
-
/* Which window is that in? */
window = window_from_coordinates (f, x, y, &part, &x, &y, 0);
if (!WINDOWP (window))
return;
- if (!EQ (window, mouse_face_window))
+ if (!EQ (window, Qmouse_face_window))
term_clear_mouse_face ();
w = XWINDOW (window);
{
extern Lisp_Object Qmouse_face;
Lisp_Object mouse_face, overlay, position, *overlay_vec;
- int noverlays, obegv, ozv;;
+ int noverlays, obegv, ozv;
struct buffer *obuf;
/* If we get an out-of-range value, return now; avoid an error. */
noverlays = sort_overlays (overlay_vec, noverlays, w);
/* Check mouse-face highlighting. */
- if (!(EQ (window, mouse_face_window)
+ if (!(EQ (window, Qmouse_face_window)
&& y >= mouse_face_beg_row
&& y <= mouse_face_end_row
&& (y > mouse_face_beg_row
= !fast_find_position (w, XFASTINT (after),
&mouse_face_end_col,
&mouse_face_end_row);
- mouse_face_window = window;
+ Qmouse_face_window = window;
mouse_face_face_id
= face_at_buffer_position (w, pos, 0, 0,
= !fast_find_position (w, XFASTINT (after),
&mouse_face_end_col,
&mouse_face_end_row);
- mouse_face_window = window;
+ Qmouse_face_window = window;
mouse_face_face_id
= face_at_buffer_position (w, pos, 0, 0,
if (event->x != last_mouse_x || event->y != last_mouse_y)
{
frame->mouse_moved = 1;
- term_mouse_highlight (frame, event->x - 1, event->y - 1);
+ term_mouse_highlight (frame, event->x, event->y);
/* Remember which glyph we're now on. */
last_mouse_x = event->x;
last_mouse_y = event->y;
Set *time to the time the mouse was at the returned position.
- This should clear mouse_moved until the next motion
- event arrives.
-
- NOT CURRENTLY INVOKED: see mouse_position_hook below. */
+ This clears mouse_moved until the next motion
+ event arrives. */
static void
term_mouse_position (FRAME_PTR *fp, int insist, Lisp_Object *bar_window,
enum scroll_bar_part *part, Lisp_Object *x,
Lisp_Object *y, unsigned long *time)
{
- Gpm_Event event;
struct timeval now;
- int i;
-
- BLOCK_INPUT;
*fp = SELECTED_FRAME ();
+ (*fp)->mouse_moved = 0;
*bar_window = Qnil;
*part = 0;
- i = Gpm_GetSnapshot (&event);
-
- XSETINT (*x, event.x);
- XSETINT (*y, event.y);
+ XSETINT (*x, last_mouse_x);
+ XSETINT (*y, last_mouse_y);
gettimeofday(&now, 0);
*time = (now.tv_sec * 1000) + (now.tv_usec / 1000);
-
- UNBLOCK_INPUT;
}
/* Prepare a mouse-event in *RESULT for placement in the input queue.
if (event->type & GPM_DRAG)
result->modifiers |= drag_modifier;
- if (!(event->type & (GPM_MOVE|GPM_DRAG))) {
+ if (!(event->type & (GPM_MOVE | GPM_DRAG))) {
/* 1 << KG_SHIFT */
if (event->modifiers & (1 << 0))
result->modifiers |= meta_modifier;
}
- XSETINT (result->x, event->x - 1);
- XSETINT (result->y, event->y - 1);
+ XSETINT (result->x, event->x);
+ XSETINT (result->y, event->y);
XSETFRAME (result->frame_or_window, f);
result->arg = Qnil;
return Qnil;
handle_one_term_event (Gpm_Event *event, struct input_event* hold_quit)
{
struct frame *f = SELECTED_FRAME ();
- int i, j, fd;
+ int fd;
struct input_event ie;
int do_help = 0;
int count = 0;
ie.kind = NO_EVENT;
ie.arg = Qnil;
- if (event->type & GPM_MOVE) {
+ if (event->type & (GPM_MOVE | GPM_DRAG)) {
unsigned char buf[6 * sizeof (short)];
unsigned short *arg = (unsigned short *) buf + 1;
const char *name;
/* Display mouse pointer */
buf[sizeof(short) - 1] = 2; /* set selection */
- arg[0] = arg[2] = (unsigned short) event->x;
- arg[1] = arg[3] = (unsigned short) event->y;
+ arg[0] = arg[2] = (unsigned short) event->x + gpm_zerobased;
+ arg[1] = arg[3] = (unsigned short) event->y + gpm_zerobased;
arg[4] = (unsigned short) 3;
- name = (const char *) ttyname (0);
+ name = ttyname (0);
fd = open (name, O_WRONLY);
ioctl (fd, TIOCLINUX, buf + sizeof (short) - 1);
- close(fd);
+ close (fd);
- term_mouse_movement (f, event);
+ if (!term_mouse_movement (f, event))
+ help_echo_string = previous_help_echo_string;
/* If the contents of the global variable help_echo_string
has changed, generate a HELP_EVENT. */
else {
f->mouse_moved = 0;
term_mouse_click (&ie, event, f);
- //kbd_buffer_store_event_hold (&ie, hold_quit);
}
done:
connection.defaultMask = ~GPM_HARD;
connection.maxMod = ~0;
connection.minMod = 0;
+ gpm_zerobased = 1;
if (Gpm_Open (&connection, 0) < 0)
return Qnil;
int status;
struct frame *sf = XFRAME (selected_frame);
- encode_terminal_bufsize = 0;
+ encode_terminal_src_size = 0;
+ encode_terminal_dst_size = 0;
#ifdef HAVE_GPM
- /* TODO: Can't get Gpm_Snapshot in term_mouse_position to work: test with
- (mouse-position). Also set-mouse-position won't work as is. */
- /* mouse_position_hook = term_mouse_position; */
-
- mouse_face_window = Qnil;
+ mouse_position_hook = term_mouse_position;
+ Qmouse_face_window = Qnil;
#endif
#ifdef WINDOWSNT
#ifdef HAVE_GPM
defsubr (&Sterm_open_connection);
defsubr (&Sterm_close_connection);
+
+ staticpro (&Qmouse_face_window);
#endif /* HAVE_GPM */
fullscreen_hook = NULL;