/* X Communication module for terminals which understand the X protocol.
- Copyright (C) 1989, 93, 94, 95, 96, 97, 98, 1999, 2000, 01, 02, 2003
+ Copyright (C) 1989, 93, 94, 95, 96, 97, 98, 1999, 2000,01,02,03,04
Free Software Foundation, Inc.
This file is part of GNU Emacs.
/* #include <sys/param.h> */
#include "charset.h"
+#include "character.h"
#include "coding.h"
#include "ccl.h"
#include "frame.h"
static int toolkit_scroll_bar_interaction;
+/* Non-zero means to not move point as a result of clicking on a
+ frame to focus it (when focus-follows-mouse is nil). */
+
+int x_mouse_click_focus_ignore_position;
+
+/* Non-zero timeout value means ignore next mouse click if it arrives
+ before that timeout elapses (i.e. as part of the same sequence of
+ events resulting from clicking on a frame to select it). */
+
+static unsigned long ignore_next_mouse_click_timeout;
+
/* Mouse movement.
Formerly, we used PointerMotionHintMask (in standard_event_mask)
extern Lisp_Object Vx_no_window_manager;
-extern Lisp_Object Qface, Qmouse_face, Qeql;
+extern Lisp_Object Qeql;
extern int errno;
static void frame_highlight P_ ((struct frame *));
static void frame_unhighlight P_ ((struct frame *));
static void x_new_focus_frame P_ ((struct x_display_info *, struct frame *));
-static int x_focus_changed P_ ((int,
- int,
- struct x_display_info *,
- struct frame *,
- struct input_event *,
- int));
-static int x_detect_focus_change P_ ((struct x_display_info *,
- XEvent *,
- struct input_event *,
- int));
+static void x_focus_changed P_ ((int, int, struct x_display_info *,
+ struct frame *, struct input_event *));
+static void x_detect_focus_change P_ ((struct x_display_info *,
+ XEvent *, struct input_event *));
static void XTframe_rehighlight P_ ((struct frame *));
static void x_frame_rehighlight P_ ((struct x_display_info *));
static void x_draw_hollow_cursor P_ ((struct window *, struct glyph_row *));
unsigned long *));
static void x_check_fullscreen P_ ((struct frame *));
static void x_check_expected_move P_ ((struct frame *));
-static int handle_one_xevent P_ ((struct x_display_info *,
- XEvent *,
- struct input_event **,
- int *,
- int *));
+static int handle_one_xevent P_ ((struct x_display_info *, XEvent *,
+ int *, struct input_event *));
/* Flush display of frame F, or of all frames if F is null. */
output_cursor.x, output_cursor.y);
x_draw_vertical_border (w);
+
+ draw_window_fringes (w);
+
UNBLOCK_INPUT;
}
xassert (w);
if (!desired_row->mode_line_p && !w->pseudo_window_p)
- {
- BLOCK_INPUT;
- draw_row_fringe_bitmaps (w, desired_row);
- UNBLOCK_INPUT;
- }
+ desired_row->redraw_fringe_bitmaps_p = 1;
/* When a window has disappeared, make sure that no rest of
full-width rows stays visible in the internal border. Could
Window window = FRAME_X_WINDOW (f);
GC gc = f->output_data.x->normal_gc;
struct face *face = p->face;
+ int rowY;
/* Must clip because of partially visible lines. */
- x_clip_to_row (w, row, gc);
+ rowY = WINDOW_TO_FRAME_PIXEL_Y (w, row->y);
+ if (p->y < rowY)
+ {
+ /* Adjust position of "bottom aligned" bitmap on partially
+ visible last row. */
+ int oldY = row->y;
+ int oldVH = row->visible_height;
+ row->visible_height = p->h;
+ row->y -= rowY - p->y;
+ x_clip_to_row (w, row, gc);
+ row->y = oldY;
+ row->visible_height = oldVH;
+ }
+ else
+ x_clip_to_row (w, row, gc);
- if (p->bx >= 0)
+ if (p->bx >= 0 && !p->overlay_p)
{
/* In case the same realized face is used for fringes and
for something displayed in the text (e.g. face `region' on
XSetForeground (display, face->gc, face->foreground);
}
- if (p->which != NO_FRINGE_BITMAP)
+ if (p->which)
{
- unsigned char *bits = fringe_bitmaps[p->which].bits + p->dh;
- Pixmap pixmap;
+ unsigned char *bits;
+ Pixmap pixmap, clipmask = (Pixmap) 0;
int depth = DefaultDepthOfScreen (FRAME_X_SCREEN (f));
+ XGCValues gcv;
+
+ if (p->wd > 8)
+ bits = (unsigned char *)(p->bits + p->dh);
+ else
+ bits = (unsigned char *)p->bits + p->dh;
/* Draw the bitmap. I believe these small pixmaps can be cached
by the server. */
pixmap = XCreatePixmapFromBitmapData (display, window, bits, p->wd, p->h,
- face->foreground,
+ (p->cursor_p
+ ? (p->overlay_p ? face->background
+ : f->output_data.x->cursor_pixel)
+ : face->foreground),
face->background, depth);
+
+ if (p->overlay_p)
+ {
+ clipmask = XCreatePixmapFromBitmapData (display,
+ FRAME_X_DISPLAY_INFO (f)->root_window,
+ bits, p->wd, p->h,
+ 1, 0, 1);
+ gcv.clip_mask = clipmask;
+ gcv.clip_x_origin = p->x;
+ gcv.clip_y_origin = p->y;
+ XChangeGC (display, gc, GCClipMask | GCClipXOrigin | GCClipYOrigin, &gcv);
+ }
+
XCopyArea (display, pixmap, window, gc, 0, 0,
p->wd, p->h, p->x, p->y);
XFreePixmap (display, pixmap);
+
+ if (p->overlay_p)
+ {
+ gcv.clip_mask = (Pixmap) 0;
+ XChangeGC (display, gc, GCClipMask, &gcv);
+ XFreePixmap (display, clipmask);
+ }
}
XSetClipMask (display, gc, None);
/* Function prototypes of this page. */
-static int x_encode_char P_ ((int, XChar2b *, struct font_info *, int *));
+static int x_encode_char P_ ((int, XChar2b *, struct font_info *,
+ struct charset *, int *));
/* Get metrics of character CHAR2B in FONT. Value is null if CHAR2B
the two-byte form of C. Encoding is returned in *CHAR2B. */
static int
-x_encode_char (c, char2b, font_info, two_byte_p)
+x_encode_char (c, char2b, font_info, charset, two_byte_p)
int c;
XChar2b *char2b;
struct font_info *font_info;
+ struct charset *charset;
int *two_byte_p;
{
- int charset = CHAR_CHARSET (c);
XFontStruct *font = font_info->font;
/* FONT_INFO may define a scheme by which to encode byte1 and byte2.
if (CHARSET_DIMENSION (charset) == 1)
{
- ccl->reg[0] = charset;
+ ccl->reg[0] = CHARSET_ID (charset);
ccl->reg[1] = char2b->byte2;
ccl->reg[2] = -1;
}
else
{
- ccl->reg[0] = charset;
+ ccl->reg[0] = CHARSET_ID (charset);
ccl->reg[1] = char2b->byte1;
ccl->reg[2] = char2b->byte2;
}
- ccl_driver (ccl, NULL, NULL, 0, 0, NULL);
+ ccl_driver (ccl, NULL, NULL, 0, 0, Qnil);
/* We assume that MSBs are appropriately set/reset by CCL
program. */
if (font->max_byte1 == 0) /* 1-byte font */
- char2b->byte1 = 0, char2b->byte2 = ccl->reg[1];
+ STORE_XCHAR2B (char2b, 0, ccl->reg[1]);
else
- char2b->byte1 = ccl->reg[1], char2b->byte2 = ccl->reg[2];
+ STORE_XCHAR2B (char2b, ccl->reg[1], ccl->reg[2]);
}
- else if (font_info->encoding[charset])
+ else if (font_info->encoding_type)
{
/* Fixed encoding scheme. See fontset.h for the meaning of the
encoding numbers. */
- int enc = font_info->encoding[charset];
+ unsigned char enc = font_info->encoding_type;
if ((enc == 1 || enc == 2)
&& CHARSET_DIMENSION (charset) == 2)
static void x_clear_glyph_string_rect P_ ((struct glyph_string *, int,
int, int, int));
static void x_draw_relief_rect P_ ((struct frame *, int, int, int, int,
- int, int, int, int, XRectangle *));
+ int, int, int, int, int, int,
+ XRectangle *));
static void x_draw_box_rect P_ ((struct glyph_string *, int, int, int, int,
int, int, int, XRectangle *));
face = FACE_FROM_ID (s->f, MOUSE_FACE_ID);
if (s->first_glyph->type == CHAR_GLYPH)
- face_id = FACE_FOR_CHAR (s->f, face, s->first_glyph->u.ch);
+ face_id = FACE_FOR_CHAR (s->f, face, s->first_glyph->u.ch, -1, Qnil);
else
- face_id = FACE_FOR_CHAR (s->f, face, 0);
+ face_id = FACE_FOR_CHAR (s->f, face, 0, -1, Qnil);
s->face = FACE_FROM_ID (s->f, face_id);
PREPARE_FACE_FOR_DISPLAY (s->f, s->face);
/* RIF:
- Compute left and right overhang of glyph string S. If S is a glyph
- string for a composition, assume overhangs don't exist. */
+ Compute left and right overhang of glyph string S. */
static void
x_compute_glyph_string_overhangs (s)
s->right_overhang = cs.rbearing > cs.width ? cs.rbearing - cs.width : 0;
s->left_overhang = cs.lbearing < 0 ? -cs.lbearing : 0;
}
+ else if (s->cmp)
+ {
+ s->right_overhang = s->cmp->rbearing - s->cmp->pixel_width;
+ s->left_overhang = - s->cmp->lbearing;
+ }
}
static void
x_draw_relief_rect (f, left_x, top_y, right_x, bottom_y, width,
- raised_p, left_p, right_p, clip_rect)
+ raised_p, top_p, bot_p, left_p, right_p, clip_rect)
struct frame *f;
- int left_x, top_y, right_x, bottom_y, width, left_p, right_p, raised_p;
+ int left_x, top_y, right_x, bottom_y, width;
+ int top_p, bot_p, left_p, right_p, raised_p;
XRectangle *clip_rect;
{
Display *dpy = FRAME_X_DISPLAY (f);
XSetClipRectangles (dpy, gc, 0, 0, clip_rect, 1, Unsorted);
/* Top. */
- for (i = 0; i < width; ++i)
- XDrawLine (dpy, window, gc,
- left_x + i * left_p, top_y + i,
- right_x + 1 - i * right_p, top_y + i);
+ if (top_p)
+ for (i = 0; i < width; ++i)
+ XDrawLine (dpy, window, gc,
+ left_x + i * left_p, top_y + i,
+ right_x + 1 - i * right_p, top_y + i);
/* Left. */
if (left_p)
XSetClipRectangles (dpy, gc, 0, 0, clip_rect, 1, Unsorted);
/* Bottom. */
- for (i = 0; i < width; ++i)
- XDrawLine (dpy, window, gc,
- left_x + i * left_p, bottom_y - i,
- right_x + 1 - i * right_p, bottom_y - i);
+ if (bot_p)
+ for (i = 0; i < width; ++i)
+ XDrawLine (dpy, window, gc,
+ left_x + i * left_p, bottom_y - i,
+ right_x + 1 - i * right_p, bottom_y - i);
/* Right. */
if (right_p)
{
x_setup_relief_colors (s);
x_draw_relief_rect (s->f, left_x, top_y, right_x, bottom_y,
- width, raised_p, left_p, right_p, &clip_rect);
+ width, raised_p, 1, 1, left_p, right_p, &clip_rect);
}
}
x_draw_image_foreground (s)
struct glyph_string *s;
{
- int x;
- int y = s->ybase - image_ascent (s->img, s->face);
+ int x = s->x;
+ int y = s->ybase - image_ascent (s->img, s->face, &s->slice);
/* If first glyph of S has a left box line, start drawing it to the
right of that line. */
if (s->face->box != FACE_NO_BOX
- && s->first_glyph->left_box_line_p)
- x = s->x + abs (s->face->box_line_width);
- else
- x = s->x;
+ && s->first_glyph->left_box_line_p
+ && s->slice.x == 0)
+ x += abs (s->face->box_line_width);
/* If there is a margin around the image, adjust x- and y-position
by that margin. */
- x += s->img->hmargin;
- y += s->img->vmargin;
+ if (s->slice.x == 0)
+ x += s->img->hmargin;
+ if (s->slice.y == 0)
+ y += s->img->vmargin;
if (s->img->pixmap)
{
get_glyph_string_clip_rect (s, &clip_rect);
image_rect.x = x;
image_rect.y = y;
- image_rect.width = s->img->width;
- image_rect.height = s->img->height;
+ image_rect.width = s->slice.width;
+ image_rect.height = s->slice.height;
if (x_intersect_rectangles (&clip_rect, &image_rect, &r))
XCopyArea (s->display, s->img->pixmap, s->window, s->gc,
- r.x - x, r.y - y, r.width, r.height, r.x, r.y);
+ s->slice.x + r.x - x, s->slice.y + r.y - y,
+ r.width, r.height, r.x, r.y);
}
else
{
get_glyph_string_clip_rect (s, &clip_rect);
image_rect.x = x;
image_rect.y = y;
- image_rect.width = s->img->width;
- image_rect.height = s->img->height;
+ image_rect.width = s->slice.width;
+ image_rect.height = s->slice.height;
if (x_intersect_rectangles (&clip_rect, &image_rect, &r))
XCopyArea (s->display, s->img->pixmap, s->window, s->gc,
- r.x - x, r.y - y, r.width, r.height, r.x, r.y);
+ s->slice.x + r.x - x, s->slice.y + r.y - y,
+ r.width, r.height, r.x, r.y);
/* When the image has a mask, we can expect that at
least part of a mouse highlight or a block cursor will
{
int r = s->img->relief;
if (r < 0) r = -r;
- XDrawRectangle (s->display, s->window, s->gc, x - r, y - r,
- s->img->width + r*2 - 1, s->img->height + r*2 - 1);
+ XDrawRectangle (s->display, s->window, s->gc,
+ x - r, y - r,
+ s->slice.width + r*2 - 1,
+ s->slice.height + r*2 - 1);
}
}
}
else
/* Draw a rectangle if image could not be loaded. */
XDrawRectangle (s->display, s->window, s->gc, x, y,
- s->img->width - 1, s->img->height - 1);
+ s->slice.width - 1, s->slice.height - 1);
}
{
int x0, y0, x1, y1, thick, raised_p;
XRectangle r;
- int x;
- int y = s->ybase - image_ascent (s->img, s->face);
+ int x = s->x;
+ int y = s->ybase - image_ascent (s->img, s->face, &s->slice);
/* If first glyph of S has a left box line, start drawing it to the
right of that line. */
if (s->face->box != FACE_NO_BOX
- && s->first_glyph->left_box_line_p)
- x = s->x + abs (s->face->box_line_width);
- else
- x = s->x;
+ && s->first_glyph->left_box_line_p
+ && s->slice.x == 0)
+ x += abs (s->face->box_line_width);
/* If there is a margin around the image, adjust x- and y-position
by that margin. */
- x += s->img->hmargin;
- y += s->img->vmargin;
+ if (s->slice.x == 0)
+ x += s->img->hmargin;
+ if (s->slice.y == 0)
+ y += s->img->vmargin;
if (s->hl == DRAW_IMAGE_SUNKEN
|| s->hl == DRAW_IMAGE_RAISED)
x0 = x - thick;
y0 = y - thick;
- x1 = x + s->img->width + thick - 1;
- y1 = y + s->img->height + thick - 1;
+ x1 = x + s->slice.width + thick - 1;
+ y1 = y + s->slice.height + thick - 1;
x_setup_relief_colors (s);
get_glyph_string_clip_rect (s, &r);
- x_draw_relief_rect (s->f, x0, y0, x1, y1, thick, raised_p, 1, 1, &r);
+ x_draw_relief_rect (s->f, x0, y0, x1, y1, thick, raised_p,
+ s->slice.y == 0,
+ s->slice.y + s->slice.height == s->img->height,
+ s->slice.x == 0,
+ s->slice.x + s->slice.width == s->img->width,
+ &r);
}
struct glyph_string *s;
Pixmap pixmap;
{
- int x;
- int y = s->ybase - s->y - image_ascent (s->img, s->face);
+ int x = 0;
+ int y = s->ybase - s->y - image_ascent (s->img, s->face, &s->slice);
/* If first glyph of S has a left box line, start drawing it to the
right of that line. */
if (s->face->box != FACE_NO_BOX
- && s->first_glyph->left_box_line_p)
- x = abs (s->face->box_line_width);
- else
- x = 0;
+ && s->first_glyph->left_box_line_p
+ && s->slice.x == 0)
+ x += abs (s->face->box_line_width);
/* If there is a margin around the image, adjust x- and y-position
by that margin. */
- x += s->img->hmargin;
- y += s->img->vmargin;
+ if (s->slice.x == 0)
+ x += s->img->hmargin;
+ if (s->slice.y == 0)
+ y += s->img->vmargin;
if (s->img->pixmap)
{
XGCValues xgcv;
xgcv.clip_mask = s->img->mask;
- xgcv.clip_x_origin = x;
- xgcv.clip_y_origin = y;
+ xgcv.clip_x_origin = x - s->slice.x;
+ xgcv.clip_y_origin = y - s->slice.y;
xgcv.function = GXcopy;
XChangeGC (s->display, s->gc, mask, &xgcv);
XCopyArea (s->display, s->img->pixmap, pixmap, s->gc,
- 0, 0, s->img->width, s->img->height, x, y);
+ s->slice.x, s->slice.y,
+ s->slice.width, s->slice.height, x, y);
XSetClipMask (s->display, s->gc, None);
}
else
{
XCopyArea (s->display, s->img->pixmap, pixmap, s->gc,
- 0, 0, s->img->width, s->img->height, x, y);
+ s->slice.x, s->slice.y,
+ s->slice.width, s->slice.height, x, y);
/* When the image has a mask, we can expect that at
least part of a mouse highlight or a block cursor will
int r = s->img->relief;
if (r < 0) r = -r;
XDrawRectangle (s->display, s->window, s->gc, x - r, y - r,
- s->img->width + r*2 - 1, s->img->height + r*2 - 1);
+ s->slice.width + r*2 - 1,
+ s->slice.height + r*2 - 1);
}
}
}
else
/* Draw a rectangle if image could not be loaded. */
XDrawRectangle (s->display, pixmap, s->gc, x, y,
- s->img->width - 1, s->img->height - 1);
+ s->slice.width - 1, s->slice.height - 1);
}
x_draw_image_glyph_string (s)
struct glyph_string *s;
{
- int x, y;
int box_line_hwidth = abs (s->face->box_line_width);
int box_line_vwidth = max (s->face->box_line_width, 0);
int height;
Pixmap pixmap = None;
- height = s->height - 2 * box_line_vwidth;
-
+ height = s->height;
+ if (s->slice.y == 0)
+ height -= box_line_vwidth;
+ if (s->slice.y + s->slice.height >= s->img->height)
+ height -= box_line_vwidth;
/* Fill background with face under the image. Do it only if row is
taller than image or if image has a clip mask to reduce
flickering. */
s->stippled_p = s->face->stipple != 0;
- if (height > s->img->height
+ if (height > s->slice.height
|| s->img->hmargin
|| s->img->vmargin
|| s->img->mask
|| s->img->pixmap == 0
|| s->width != s->background_width)
{
- if (box_line_hwidth && s->first_glyph->left_box_line_p)
- x = s->x + box_line_hwidth;
- else
- x = s->x;
-
- y = s->y + box_line_vwidth;
-
if (s->img->mask)
{
/* Create a pixmap as large as the glyph string. Fill it
}
}
else
- x_draw_glyph_string_bg_rect (s, x, y, s->background_width, height);
+ {
+ int x = s->x;
+ int y = s->y;
+
+ if (s->first_glyph->left_box_line_p
+ && s->slice.x == 0)
+ x += box_line_hwidth;
+
+ if (s->slice.y == 0)
+ y += box_line_vwidth;
+
+ x_draw_glyph_string_bg_rect (s, x, y, s->background_width, height);
+ }
s->background_filled_p = 1;
}
/* Handle FocusIn and FocusOut state changes for FRAME.
If FRAME has focus and there exists more than one frame, puts
- a FOCUS_IN_EVENT into BUFP.
- Returns number of events inserted into BUFP. */
+ a FOCUS_IN_EVENT into *BUFP. */
-static int
-x_focus_changed (type, state, dpyinfo, frame, bufp, numchars)
+static void
+x_focus_changed (type, state, dpyinfo, frame, bufp)
int type;
int state;
struct x_display_info *dpyinfo;
struct frame *frame;
struct input_event *bufp;
- int numchars;
{
- int nr_events = 0;
-
if (type == FocusIn)
{
if (dpyinfo->x_focus_event_frame != frame)
/* Don't stop displaying the initial startup message
for a switch-frame event we don't need. */
- if (numchars > 0
- && GC_NILP (Vterminal_frame)
+ if (GC_NILP (Vterminal_frame)
&& GC_CONSP (Vframe_list)
&& !GC_NILP (XCDR (Vframe_list)))
{
bufp->kind = FOCUS_IN_EVENT;
XSETFRAME (bufp->frame_or_window, frame);
- bufp->arg = Qnil;
- ++bufp;
- numchars--;
- ++nr_events;
}
}
XUnsetICFocus (FRAME_XIC (frame));
#endif
}
-
- return nr_events;
}
/* The focus may have changed. Figure out if it is a real focus change,
by checking both FocusIn/Out and Enter/LeaveNotify events.
- Returns number of events inserted into BUFP. */
+ Returns FOCUS_IN_EVENT event in *BUFP. */
-static int
-x_detect_focus_change (dpyinfo, event, bufp, numchars)
+static void
+x_detect_focus_change (dpyinfo, event, bufp)
struct x_display_info *dpyinfo;
XEvent *event;
struct input_event *bufp;
- int numchars;
{
struct frame *frame;
- int nr_events = 0;
frame = x_any_window_to_frame (dpyinfo, event->xany.window);
- if (! frame) return nr_events;
+ if (! frame)
+ return;
switch (event->type)
{
if (event->xcrossing.detail != NotifyInferior
&& event->xcrossing.focus
&& ! (focus_state & FOCUS_EXPLICIT))
- nr_events = x_focus_changed ((event->type == EnterNotify
- ? FocusIn : FocusOut),
- FOCUS_IMPLICIT,
- dpyinfo,
- frame,
- bufp,
- numchars);
+ x_focus_changed ((event->type == EnterNotify ? FocusIn : FocusOut),
+ FOCUS_IMPLICIT,
+ dpyinfo, frame, bufp);
}
break;
case FocusIn:
case FocusOut:
- nr_events = x_focus_changed (event->type,
- (event->xfocus.detail == NotifyPointer
- ? FOCUS_IMPLICIT : FOCUS_EXPLICIT),
- dpyinfo,
- frame,
- bufp,
- numchars);
+ x_focus_changed (event->type,
+ (event->xfocus.detail == NotifyPointer ?
+ FOCUS_IMPLICIT : FOCUS_EXPLICIT),
+ dpyinfo, frame, bufp);
break;
}
-
- return nr_events;
}
XRectangle *rect;
{
Lisp_Object window;
- int found = 0;
+ struct window *w;
+ struct glyph_row *r, *end_row;
window = window_from_coordinates (f, x, y, 0, &x, &y, 0);
- if (!NILP (window))
- {
- struct window *w = XWINDOW (window);
- struct glyph_row *r = MATRIX_FIRST_TEXT_ROW (w->current_matrix);
- struct glyph_row *end = r + w->current_matrix->nrows - 1;
+ if (NILP (window))
+ return 0;
- for (; !found && r < end && r->enabled_p; ++r)
- if (r->y >= y)
- {
- struct glyph *g = r->glyphs[TEXT_AREA];
- struct glyph *end = g + r->used[TEXT_AREA];
- int gx;
+ w = XWINDOW (window);
+ r = MATRIX_FIRST_TEXT_ROW (w->current_matrix);
+ end_row = r + w->current_matrix->nrows - 1;
- for (gx = r->x; !found && g < end; gx += g->pixel_width, ++g)
- if (gx >= x)
- {
- rect->width = g->pixel_width;
- rect->height = r->height;
- rect->x = WINDOW_TO_FRAME_PIXEL_X (w, gx);
- rect->y = WINDOW_TO_FRAME_PIXEL_Y (w, r->y);
- found = 1;
- }
- }
+ for (; r < end_row && r->enabled_p; ++r)
+ {
+ if (r->y >= y)
+ {
+ struct glyph *g = r->glyphs[TEXT_AREA];
+ struct glyph *end = g + r->used[TEXT_AREA];
+ int gx = r->x;
+ while (g < end && gx < x)
+ gx += g->pixel_width, ++g;
+ if (g < end)
+ {
+ rect->width = g->pixel_width;
+ rect->height = r->height;
+ rect->x = WINDOW_TO_FRAME_PIXEL_X (w, gx);
+ rect->y = WINDOW_TO_FRAME_PIXEL_Y (w, r->y);
+ return 1;
+ }
+ break;
+ }
}
- return found;
+ return 0;
}
static int temp_index;
static short temp_buffer[100];
+#define STORE_KEYSYM_FOR_DEBUG(keysym) \
+ if (temp_index == sizeof temp_buffer / sizeof (short)) \
+ temp_index = 0; \
+ temp_buffer[temp_index++] = (keysym)
+
/* Set this to nonzero to fake an "X I/O error"
on a particular display. */
f->output_data.x->saved_menu_event \
= (XEvent *) xmalloc (sizeof (XEvent)); \
bcopy (&event, f->output_data.x->saved_menu_event, size); \
- if (numchars >= 1) \
- { \
- bufp->kind = MENU_BAR_ACTIVATE_EVENT; \
- XSETFRAME (bufp->frame_or_window, f); \
- bufp->arg = Qnil; \
- bufp++; \
- count++; \
- numchars--; \
- } \
+ inev.kind = MENU_BAR_ACTIVATE_EVENT; \
+ XSETFRAME (inev.frame_or_window, f); \
} \
while (0)
#endif
#ifdef USE_GTK
-static struct input_event **current_bufp;
-static int *current_numcharsp;
static int current_count;
static int current_finish;
+static struct input_event *current_hold_quit;
/* This is the filter function invoked by the GTK event loop.
It is invoked before the XEvent is translated to a GdkEvent,
- so we have a chanse to act on the event before GTK. */
+ so we have a chance to act on the event before GTK. */
static GdkFilterReturn
event_handler_gdk (gxev, ev, data)
GdkXEvent *gxev;
{
XEvent *xev = (XEvent *) gxev;
- if (current_numcharsp)
+ if (current_count >= 0)
{
struct x_display_info *dpyinfo;
if (! dpyinfo)
current_finish = X_EVENT_NORMAL;
else
- current_count += handle_one_xevent (dpyinfo,
- xev,
- current_bufp,
- current_numcharsp,
- ¤t_finish);
+ {
+ current_count +=
+ handle_one_xevent (dpyinfo, xev, ¤t_finish,
+ current_hold_quit);
+ }
}
else
current_finish = x_dispatch_event (xev, xev->xany.display);
*FINISH is zero if caller should continue reading events.
*FINISH is X_EVENT_DROP if event should not be passed to the toolkit.
- Events representing keys are stored in buffer *BUFP_R,
- which can hold up to *NUMCHARSP characters.
We return the number of characters stored into the buffer. */
static int
-handle_one_xevent (dpyinfo, eventp, bufp_r, numcharsp, finish)
+handle_one_xevent (dpyinfo, eventp, finish, hold_quit)
struct x_display_info *dpyinfo;
XEvent *eventp;
- /* register */ struct input_event **bufp_r;
- /* register */ int *numcharsp;
int *finish;
+ struct input_event *hold_quit;
{
+ struct input_event inev;
int count = 0;
+ int do_help = 0;
int nbytes = 0;
struct frame *f;
struct coding_system coding;
- struct input_event *bufp = *bufp_r;
- int numchars = *numcharsp;
XEvent event = *eventp;
*finish = X_EVENT_NORMAL;
+ EVENT_INIT (inev);
+ inev.kind = NO_EVENT;
+ inev.arg = Qnil;
+
switch (event.type)
{
case ClientMessage:
}
/* Not certain about handling scroll bars here */
#endif /* 0 */
+ goto done;
}
- else if (event.xclient.data.l[0]
+
+ if (event.xclient.data.l[0]
== dpyinfo->Xatom_wm_save_yourself)
{
/* Save state modify the WM_COMMAND property to
/* If we have a session manager, don't set this.
KDE will then start two Emacsen, one for the
session manager and one for this. */
- if (numchars > 0
#ifdef HAVE_X_SM
- && ! x_session_have_connection ()
+ if (! x_session_have_connection ())
#endif
- )
{
f = x_top_window_to_frame (dpyinfo,
event.xclient.window);
event.xclient.window,
0, 0);
}
+ goto done;
}
- else if (event.xclient.data.l[0]
- == dpyinfo->Xatom_wm_delete_window)
+
+ if (event.xclient.data.l[0]
+ == dpyinfo->Xatom_wm_delete_window)
{
- struct frame *f
- = x_any_window_to_frame (dpyinfo,
+ f = x_any_window_to_frame (dpyinfo,
event.xclient.window);
+ if (!f)
+ goto OTHER; /* May be a dialog that is to be removed */
- if (f)
- {
- if (numchars == 0)
- abort ();
-
- bufp->kind = DELETE_WINDOW_EVENT;
- XSETFRAME (bufp->frame_or_window, f);
- bufp->arg = Qnil;
- bufp++;
-
- count += 1;
- numchars -= 1;
- }
- else
- goto OTHER; /* May be a dialog that is to be removed */
+ inev.kind = DELETE_WINDOW_EVENT;
+ XSETFRAME (inev.frame_or_window, f);
+ goto done;
}
+
+ goto done;
}
- else if (event.xclient.message_type
+
+ if (event.xclient.message_type
== dpyinfo->Xatom_wm_configure_denied)
{
+ goto done;
}
- else if (event.xclient.message_type
- == dpyinfo->Xatom_wm_window_moved)
+
+ if (event.xclient.message_type
+ == dpyinfo->Xatom_wm_window_moved)
{
int new_x, new_y;
- struct frame *f
- = x_window_to_frame (dpyinfo, event.xclient.window);
+ f = x_window_to_frame (dpyinfo, event.xclient.window);
new_x = event.xclient.data.s[0];
new_y = event.xclient.data.s[1];
f->left_pos = new_x;
f->top_pos = new_y;
}
+ goto done;
}
+
#ifdef HACK_EDITRES
- else if (event.xclient.message_type
- == dpyinfo->Xatom_editres)
+ if (event.xclient.message_type
+ == dpyinfo->Xatom_editres)
{
- struct frame *f
- = x_any_window_to_frame (dpyinfo, event.xclient.window);
+ f = x_any_window_to_frame (dpyinfo, event.xclient.window);
_XEditResCheckMessages (f->output_data.x->widget, NULL,
&event, NULL);
+ goto done;
}
#endif /* HACK_EDITRES */
- else if ((event.xclient.message_type
- == dpyinfo->Xatom_DONE)
- || (event.xclient.message_type
- == dpyinfo->Xatom_PAGE))
+
+ if ((event.xclient.message_type
+ == dpyinfo->Xatom_DONE)
+ || (event.xclient.message_type
+ == dpyinfo->Xatom_PAGE))
{
/* Ghostview job completed. Kill it. We could
reply with "Next" if we received "Page", but we
currently never do because we are interested in
images, only, which should have 1 page. */
Pixmap pixmap = (Pixmap) event.xclient.data.l[1];
- struct frame *f
- = x_window_to_frame (dpyinfo, event.xclient.window);
+ f = x_window_to_frame (dpyinfo, event.xclient.window);
x_kill_gs_process (pixmap, f);
expose_frame (f, 0, 0, 0, 0);
+ goto done;
}
+
#ifdef USE_TOOLKIT_SCROLL_BARS
/* Scroll bar callbacks send a ClientMessage from which
we construct an input_event. */
- else if (event.xclient.message_type
- == dpyinfo->Xatom_Scrollbar)
+ if (event.xclient.message_type
+ == dpyinfo->Xatom_Scrollbar)
{
- x_scroll_bar_to_input_event (&event, bufp);
- ++bufp, ++count, --numchars;
- goto out;
+ x_scroll_bar_to_input_event (&event, &inev);
+ *finish = X_EVENT_GOTO_OUT;
+ goto done;
}
#endif /* USE_TOOLKIT_SCROLL_BARS */
- else
- goto OTHER;
+
+ f = x_any_window_to_frame (dpyinfo, event.xclient.window);
+
+ if (!f)
+ goto OTHER;
+
+ if (x_handle_dnd_message (f, &event.xclient, dpyinfo, &inev))
+ *finish = X_EVENT_DROP;
}
break;
{
XSelectionClearEvent *eventp = (XSelectionClearEvent *) &event;
- if (numchars == 0)
- abort ();
-
- bufp->kind = SELECTION_CLEAR_EVENT;
- SELECTION_EVENT_DISPLAY (bufp) = eventp->display;
- SELECTION_EVENT_SELECTION (bufp) = eventp->selection;
- SELECTION_EVENT_TIME (bufp) = eventp->time;
- bufp->frame_or_window = Qnil;
- bufp->arg = Qnil;
- bufp++;
-
- count += 1;
- numchars -= 1;
+ inev.kind = SELECTION_CLEAR_EVENT;
+ SELECTION_EVENT_DISPLAY (&inev) = eventp->display;
+ SELECTION_EVENT_SELECTION (&inev) = eventp->selection;
+ SELECTION_EVENT_TIME (&inev) = eventp->time;
+ inev.frame_or_window = Qnil;
}
break;
XSelectionRequestEvent *eventp
= (XSelectionRequestEvent *) &event;
- if (numchars == 0)
- abort ();
-
- bufp->kind = SELECTION_REQUEST_EVENT;
- SELECTION_EVENT_DISPLAY (bufp) = eventp->display;
- SELECTION_EVENT_REQUESTOR (bufp) = eventp->requestor;
- SELECTION_EVENT_SELECTION (bufp) = eventp->selection;
- SELECTION_EVENT_TARGET (bufp) = eventp->target;
- SELECTION_EVENT_PROPERTY (bufp) = eventp->property;
- SELECTION_EVENT_TIME (bufp) = eventp->time;
- bufp->frame_or_window = Qnil;
- bufp->arg = Qnil;
- bufp++;
-
- count += 1;
- numchars -= 1;
+ inev.kind = SELECTION_REQUEST_EVENT;
+ SELECTION_EVENT_DISPLAY (&inev) = eventp->display;
+ SELECTION_EVENT_REQUESTOR (&inev) = eventp->requestor;
+ SELECTION_EVENT_SELECTION (&inev) = eventp->selection;
+ SELECTION_EVENT_TARGET (&inev) = eventp->target;
+ SELECTION_EVENT_PROPERTY (&inev) = eventp->property;
+ SELECTION_EVENT_TIME (&inev) = eventp->time;
+ inev.frame_or_window = Qnil;
}
break;
FRAME_X_DISPLAY_INFO (f)->wm_type = X_WMTYPE_UNKNOWN;
}
goto OTHER;
- break;
case Expose:
f = x_window_to_frame (dpyinfo, event.xexpose.window);
{
f->async_iconified = 1;
- bufp->kind = ICONIFY_EVENT;
- XSETFRAME (bufp->frame_or_window, f);
- bufp->arg = Qnil;
- bufp++;
- count++;
- numchars--;
+ inev.kind = ICONIFY_EVENT;
+ XSETFRAME (inev.frame_or_window, f);
}
}
goto OTHER;
if (f->iconified)
{
- bufp->kind = DEICONIFY_EVENT;
- XSETFRAME (bufp->frame_or_window, f);
- bufp->arg = Qnil;
- bufp++;
- count++;
- numchars--;
+ inev.kind = DEICONIFY_EVENT;
+ XSETFRAME (inev.frame_or_window, f);
}
else if (! NILP (Vframe_list)
&& ! NILP (XCDR (Vframe_list)))
case KeyPress:
+ ignore_next_mouse_click_timeout = 0;
+
#if defined (USE_X_TOOLKIT) || defined (USE_GTK)
/* Dispatch KeyPress events when in menu. */
if (popup_activated ())
if (!dpyinfo->mouse_face_hidden && INTEGERP (Vmouse_highlight))
{
- dpyinfo->mouse_face_hidden = 1;
clear_mouse_face (dpyinfo);
+ dpyinfo->mouse_face_hidden = 1;
}
#if defined USE_MOTIF && defined USE_TOOLKIT_SCROLL_BARS
int copy_bufsiz = sizeof (copy_buffer);
int modifiers;
Lisp_Object coding_system = Qlatin_1;
+ Lisp_Object c;
+
+#ifdef USE_GTK
+ /* Don't pass keys to GTK. A Tab will shift focus to the
+ tool bar in GTK 2.4. Keys will still go to menus and
+ dialogs because in that case popup_activated is TRUE
+ (see above). */
+ *finish = X_EVENT_DROP;
+#endif
event.xkey.state
|= x_emacs_to_x_modifiers (FRAME_X_DISPLAY_INFO (f),
&compose_status);
#endif
+ /* If not using XIM/XIC, and a compose sequence is in progress,
+ we break here. Otherwise, chars_matched is always 0. */
+ if (compose_status.chars_matched > 0 && nbytes == 0)
+ break;
+
orig_keysym = keysym;
- if (numchars > 1)
- {
- Lisp_Object c;
+ /* Common for all keysym input events. */
+ XSETFRAME (inev.frame_or_window, f);
+ inev.modifiers
+ = x_x_to_emacs_modifiers (FRAME_X_DISPLAY_INFO (f), modifiers);
+ inev.timestamp = event.xkey.time;
- /* First deal with keysyms which have defined
- translations to characters. */
- if (keysym >= 32 && keysym < 128)
- /* Avoid explicitly decoding each ASCII character. */
- {
- bufp->kind = ASCII_KEYSTROKE_EVENT;
- bufp->code = keysym;
- XSETFRAME (bufp->frame_or_window, f);
- bufp->arg = Qnil;
- bufp->modifiers
- = x_x_to_emacs_modifiers (FRAME_X_DISPLAY_INFO (f),
- modifiers);
- bufp->timestamp = event.xkey.time;
- bufp++;
- count++;
- numchars--;
- }
- /* Now non-ASCII. */
- else if (HASH_TABLE_P (Vx_keysym_table)
- && (NATNUMP (c = Fgethash (make_number (keysym),
- Vx_keysym_table,
- Qnil))))
- {
- bufp->kind = (SINGLE_BYTE_CHAR_P (XFASTINT (c))
- ? ASCII_KEYSTROKE_EVENT
- : MULTIBYTE_CHAR_KEYSTROKE_EVENT);
- bufp->code = XFASTINT (c);
- XSETFRAME (bufp->frame_or_window, f);
- bufp->arg = Qnil;
- bufp->modifiers
- = x_x_to_emacs_modifiers (FRAME_X_DISPLAY_INFO (f),
- modifiers);
- bufp->timestamp = event.xkey.time;
- bufp++;
- count++;
- numchars--;
- }
- /* Random non-modifier sorts of keysyms. */
- else if (((keysym >= XK_BackSpace && keysym <= XK_Escape)
+ /* First deal with keysyms which have defined
+ translations to characters. */
+ if (keysym >= 32 && keysym < 128)
+ /* Avoid explicitly decoding each ASCII character. */
+ {
+ inev.kind = ASCII_KEYSTROKE_EVENT;
+ inev.code = keysym;
+ goto done_keysym;
+ }
+
+ /* Now non-ASCII. */
+ if (HASH_TABLE_P (Vx_keysym_table)
+ && (NATNUMP (c = Fgethash (make_number (keysym),
+ Vx_keysym_table,
+ Qnil))))
+ {
+ inev.kind = (SINGLE_BYTE_CHAR_P (XFASTINT (c))
+ ? ASCII_KEYSTROKE_EVENT
+ : MULTIBYTE_CHAR_KEYSTROKE_EVENT);
+ inev.code = XFASTINT (c);
+ goto done_keysym;
+ }
+
+ /* Random non-modifier sorts of keysyms. */
+ if (((keysym >= XK_BackSpace && keysym <= XK_Escape)
|| keysym == XK_Delete
#ifdef XK_ISO_Left_Tab
|| (keysym >= XK_ISO_Left_Tab
<= XK_ISO_Last_Group_Lock)
#endif
))
- {
- if (temp_index == sizeof temp_buffer / sizeof (short))
- temp_index = 0;
- temp_buffer[temp_index++] = keysym;
- /* make_lispy_event will convert this to a symbolic
- key. */
- bufp->kind = NON_ASCII_KEYSTROKE_EVENT;
- bufp->code = keysym;
- XSETFRAME (bufp->frame_or_window, f);
- bufp->arg = Qnil;
- bufp->modifiers
- = x_x_to_emacs_modifiers (FRAME_X_DISPLAY_INFO (f),
- modifiers);
- bufp->timestamp = event.xkey.time;
- bufp++;
- count++;
- numchars--;
- }
- else if (numchars > nbytes)
- { /* Raw bytes, not keysym. */
- register int i;
- register int c;
- int nchars, len;
-
- /* The input should be decoded with `coding_system'
- which depends on which X*LookupString function
- we used just above and the locale. */
- setup_coding_system (coding_system, &coding);
- coding.src_multibyte = 0;
- coding.dst_multibyte = 1;
- /* The input is converted to events, thus we can't
- handle composition. Anyway, there's no XIM that
- gives us composition information. */
- coding.composing = COMPOSITION_DISABLED;
-
- for (i = 0; i < nbytes; i++)
- {
- if (temp_index == (sizeof temp_buffer
- / sizeof (short)))
- temp_index = 0;
- temp_buffer[temp_index++] = copy_bufptr[i];
- }
+ {
+ STORE_KEYSYM_FOR_DEBUG (keysym);
+ /* make_lispy_event will convert this to a symbolic
+ key. */
+ inev.kind = NON_ASCII_KEYSTROKE_EVENT;
+ inev.code = keysym;
+ goto done_keysym;
+ }
- {
- /* Decode the input data. */
- int require;
- unsigned char *p;
-
- require = decoding_buffer_size (&coding, nbytes);
- p = (unsigned char *) alloca (require);
- coding.mode |= CODING_MODE_LAST_BLOCK;
- /* We explicitly disable composition
- handling because key data should
- not contain any composition
- sequence. */
- coding.composing = COMPOSITION_DISABLED;
- decode_coding (&coding, copy_bufptr, p,
- nbytes, require);
- nbytes = coding.produced;
- nchars = coding.produced_char;
- copy_bufptr = p;
- }
+ { /* Raw bytes, not keysym. */
+ register int i;
+ register int c;
+ int nchars, len;
- /* Convert the input data to a sequence of
- character events. */
- for (i = 0; i < nbytes; i += len)
- {
- if (nchars == nbytes)
- c = copy_bufptr[i], len = 1;
- else
- c = STRING_CHAR_AND_LENGTH (copy_bufptr + i,
- nbytes - i, len);
-
- bufp->kind = (SINGLE_BYTE_CHAR_P (c)
- ? ASCII_KEYSTROKE_EVENT
- : MULTIBYTE_CHAR_KEYSTROKE_EVENT);
- bufp->code = c;
- XSETFRAME (bufp->frame_or_window, f);
- bufp->arg = Qnil;
- bufp->modifiers
- = x_x_to_emacs_modifiers (FRAME_X_DISPLAY_INFO (f),
- modifiers);
- bufp->timestamp = event.xkey.time;
- bufp++;
- }
+ for (i = 0, nchars = 0; i < nbytes; i++)
+ {
+ if (ASCII_BYTE_P (copy_bufptr[i]))
+ nchars++;
+ STORE_KEYSYM_FOR_DEBUG (copy_bufptr[i]);
+ }
- count += nchars;
- numchars -= nchars;
+ if (nchars < nbytes)
+ {
+ /* Decode the input data. */
+ int require;
+ unsigned char *p;
+
+ /* The input should be decoded with `coding_system'
+ which depends on which X*LookupString function
+ we used just above and the locale. */
+ setup_coding_system (coding_system, &coding);
+ coding.src_multibyte = 0;
+ coding.dst_multibyte = 1;
+ /* The input is converted to events, thus we can't
+ handle composition. Anyway, there's no XIM that
+ gives us composition information. */
+ coding.common_flags &= ~CODING_ANNOTATION_MASK;
+
+ require = MAX_MULTIBYTE_LENGTH * nbytes;
+ coding.destination = alloca (require);
+ coding.dst_bytes = require;
+ coding.mode |= CODING_MODE_LAST_BLOCK;
+ decode_coding_c_string (&coding, copy_bufptr, nbytes, Qnil);
+ nbytes = coding.produced;
+ nchars = coding.produced_char;
+ copy_bufptr = coding.destination;
+ }
- if (keysym == NoSymbol)
- break;
- }
- else
- abort ();
- }
- else
- abort ();
+ /* Convert the input data to a sequence of
+ character events. */
+ for (i = 0; i < nbytes; i += len)
+ {
+ if (nchars == nbytes)
+ c = copy_bufptr[i], len = 1;
+ else
+ c = STRING_CHAR_AND_LENGTH (copy_bufptr + i,
+ nbytes - i, len);
+ inev.kind = (SINGLE_BYTE_CHAR_P (c)
+ ? ASCII_KEYSTROKE_EVENT
+ : MULTIBYTE_CHAR_KEYSTROKE_EVENT);
+ inev.code = c;
+ kbd_buffer_store_event_hold (&inev, hold_quit);
+ }
+
+ /* Previous code updated count by nchars rather than nbytes,
+ but that seems bogus to me. ++kfs */
+ count += nbytes;
+
+ inev.kind = NO_EVENT; /* Already stored above. */
+
+ if (keysym == NoSymbol)
+ break;
+ }
}
+ done_keysym:
#ifdef HAVE_X_I18N
/* Don't dispatch this event since XtDispatchEvent calls
XFilterEvent, and two calls in a row may freeze the
#endif
case EnterNotify:
- {
- int n;
+ x_detect_focus_change (dpyinfo, &event, &inev);
- n = x_detect_focus_change (dpyinfo, &event, bufp, numchars);
- if (n > 0)
- {
- bufp += n, count += n, numchars -= n;
- }
+ f = x_any_window_to_frame (dpyinfo, event.xcrossing.window);
- f = x_any_window_to_frame (dpyinfo, event.xcrossing.window);
+ if (f && x_mouse_click_focus_ignore_position)
+ ignore_next_mouse_click_timeout = event.xmotion.time + 200;
#if 0
- if (event.xcrossing.focus)
- {
- /* Avoid nasty pop/raise loops. */
- if (f && (!(f->auto_raise)
- || !(f->auto_lower)
- || (event.xcrossing.time - enter_timestamp) > 500))
- {
- x_new_focus_frame (dpyinfo, f);
- enter_timestamp = event.xcrossing.time;
- }
- }
- else if (f == dpyinfo->x_focus_frame)
- x_new_focus_frame (dpyinfo, 0);
+ if (event.xcrossing.focus)
+ {
+ /* Avoid nasty pop/raise loops. */
+ if (f && (!(f->auto_raise)
+ || !(f->auto_lower)
+ || (event.xcrossing.time - enter_timestamp) > 500))
+ {
+ x_new_focus_frame (dpyinfo, f);
+ enter_timestamp = event.xcrossing.time;
+ }
+ }
+ else if (f == dpyinfo->x_focus_frame)
+ x_new_focus_frame (dpyinfo, 0);
#endif
- /* EnterNotify counts as mouse movement,
- so update things that depend on mouse position. */
- if (f && !f->output_data.x->hourglass_p)
- note_mouse_movement (f, &event.xmotion);
- goto OTHER;
- }
+ /* EnterNotify counts as mouse movement,
+ so update things that depend on mouse position. */
+ if (f && !f->output_data.x->hourglass_p)
+ note_mouse_movement (f, &event.xmotion);
+ goto OTHER;
case FocusIn:
- {
- int n;
-
- n = x_detect_focus_change (dpyinfo, &event, bufp, numchars);
- if (n > 0)
- {
- bufp += n, count += n, numchars -= n;
- }
- }
-
+ x_detect_focus_change (dpyinfo, &event, &inev);
goto OTHER;
case LeaveNotify:
- {
- int n;
-
- n = x_detect_focus_change (dpyinfo, &event, bufp, numchars);
- if (n > 0)
- {
- bufp += n, count += n, numchars -= n;
- }
- }
+ x_detect_focus_change (dpyinfo, &event, &inev);
f = x_top_window_to_frame (dpyinfo, event.xcrossing.window);
if (f)
Otherwise, the startup message is cleared when
the mouse leaves the frame. */
if (any_help_event_p)
- {
- Lisp_Object frame;
- int n;
-
- XSETFRAME (frame, f);
- help_echo_string = Qnil;
- n = gen_help_event (bufp, numchars,
- Qnil, frame, Qnil, Qnil, 0);
- bufp += n, count += n, numchars -= n;
- }
-
+ do_help = -1;
}
goto OTHER;
case FocusOut:
- {
- int n;
-
- n = x_detect_focus_change (dpyinfo, &event, bufp, numchars);
- if (n > 0)
- {
- bufp += n, count += n, numchars -= n;
- }
- }
-
+ x_detect_focus_change (dpyinfo, &event, &inev);
goto OTHER;
case MotionNotify:
will be selected iff it is active. */
if (WINDOWP (window)
&& !EQ (window, last_window)
- && !EQ (window, selected_window)
- && numchars > 0)
+ && !EQ (window, selected_window))
{
- bufp->kind = SELECT_WINDOW_EVENT;
- bufp->frame_or_window = window;
- bufp->arg = Qnil;
- ++bufp, ++count, --numchars;
+ inev.kind = SELECT_WINDOW_EVENT;
+ inev.frame_or_window = window;
}
last_window=window;
has changed, generate a HELP_EVENT. */
if (!NILP (help_echo_string)
|| !NILP (previous_help_echo_string))
- {
- Lisp_Object frame;
- int n;
-
- if (f)
- XSETFRAME (frame, f);
- else
- frame = Qnil;
-
- any_help_event_p = 1;
- n = gen_help_event (bufp, numchars, help_echo_string, frame,
- help_echo_window, help_echo_object,
- help_echo_pos);
- bufp += n, count += n, numchars -= n;
- }
-
+ do_help = 1;
goto OTHER;
}
{
/* If we decide we want to generate an event to be seen
by the rest of Emacs, we put it here. */
- struct input_event emacs_event;
int tool_bar_p = 0;
- emacs_event.kind = NO_EVENT;
bzero (&compose_status, sizeof (compose_status));
if (dpyinfo->grabbed
#if defined (USE_X_TOOLKIT) || defined (USE_GTK)
if (! popup_activated ())
#endif
- construct_mouse_click (&emacs_event, &event, f);
+ {
+ if (ignore_next_mouse_click_timeout)
+ {
+ if (event.type == ButtonPress
+ && (int)(event.xbutton.time - ignore_next_mouse_click_timeout) > 0)
+ {
+ ignore_next_mouse_click_timeout = 0;
+ construct_mouse_click (&inev, &event, f);
+ }
+ if (event.type == ButtonRelease)
+ ignore_next_mouse_click_timeout = 0;
+ }
+ else
+ construct_mouse_click (&inev, &event, f);
+ }
}
}
else
scroll bars. */
if (bar && event.xbutton.state & ControlMask)
{
- x_scroll_bar_handle_click (bar, &event, &emacs_event);
+ x_scroll_bar_handle_click (bar, &event, &inev);
*finish = X_EVENT_DROP;
}
#else /* not USE_TOOLKIT_SCROLL_BARS */
if (bar)
- x_scroll_bar_handle_click (bar, &event, &emacs_event);
+ x_scroll_bar_handle_click (bar, &event, &inev);
#endif /* not USE_TOOLKIT_SCROLL_BARS */
}
else
dpyinfo->grabbed &= ~(1 << event.xbutton.button);
- if (numchars >= 1 && emacs_event.kind != NO_EVENT)
- {
- bcopy (&emacs_event, bufp, sizeof (struct input_event));
- bufp++;
- count++;
- numchars--;
- }
-
#if defined (USE_X_TOOLKIT) || defined (USE_GTK)
f = x_menubar_window_to_frame (dpyinfo, event.xbutton.window);
/* For a down-event in the menu bar,
break;
}
- goto ret;
+ done:
+ if (inev.kind != NO_EVENT)
+ {
+ kbd_buffer_store_event_hold (&inev, hold_quit);
+ count++;
+ }
- out:
- *finish = X_EVENT_GOTO_OUT;
+ if (do_help
+ && !(hold_quit && hold_quit->kind != NO_EVENT))
+ {
+ Lisp_Object frame;
- ret:
- *bufp_r = bufp;
- *numcharsp = numchars;
- *eventp = event;
+ if (f)
+ XSETFRAME (frame, f);
+ else
+ frame = Qnil;
+ if (do_help > 0)
+ {
+ any_help_event_p = 1;
+ gen_help_event (help_echo_string, frame, help_echo_window,
+ help_echo_object, help_echo_pos);
+ }
+ else
+ {
+ help_echo_string = Qnil;
+ gen_help_event (Qnil, frame, Qnil, Qnil, 0);
+ }
+ count++;
+ }
+
+ *eventp = event;
return count;
}
Display *display;
{
struct x_display_info *dpyinfo;
- struct input_event bufp[10];
- struct input_event *bufpp;
- int numchars = 10;
int finish = X_EVENT_NORMAL;
- for (bufpp = bufp; bufpp != bufp + 10; bufpp++)
- EVENT_INIT (*bufpp);
- bufpp = bufp;
-
dpyinfo = x_display_info_for_display (display);
if (dpyinfo)
- {
- int i, events;
- events = handle_one_xevent (dpyinfo,
- event,
- &bufpp,
- &numchars,
- &finish);
- for (i = 0; i < events; ++i)
- kbd_buffer_store_event (&bufp[i]);
- }
+ handle_one_xevent (dpyinfo, event, &finish, 0);
return finish;
}
This routine is called by the SIGIO handler.
We return as soon as there are no more events to be read.
- Events representing keys are stored in buffer BUFP,
- which can hold up to NUMCHARS characters.
We return the number of characters stored into the buffer,
thus pretending to be `read'.
EXPECTED is nonzero if the caller knows input is available. */
static int
-XTread_socket (sd, bufp, numchars, expected)
+XTread_socket (sd, expected, hold_quit)
register int sd;
- /* register */ struct input_event *bufp;
- /* register */ int numchars;
int expected;
+ struct input_event *hold_quit;
{
int count = 0;
XEvent event;
/* So people can tell when we have read the available input. */
input_signal_count++;
- if (numchars <= 0)
- abort (); /* Don't think this happens. */
-
++handling_signal;
/* Find the display we are supposed to read input for.
}
#ifdef HAVE_X_SM
- BLOCK_INPUT;
- count += x_session_check_input (bufp, &numchars);
- UNBLOCK_INPUT;
+ {
+ struct input_event inev;
+ BLOCK_INPUT;
+ /* We don't need to EVENT_INIT (inev) here, as
+ x_session_check_input copies an entire input_event. */
+ if (x_session_check_input (&inev))
+ {
+ kbd_buffer_store_event_hold (&inev, hold_quit);
+ count++;
+ }
+ UNBLOCK_INPUT;
+ }
#endif
#ifndef USE_GTK
#endif
event_found = 1;
- count += handle_one_xevent (dpyinfo,
- &event,
- &bufp,
- &numchars,
- &finish);
+ count += handle_one_xevent (dpyinfo, &event, &finish, hold_quit);
if (finish == X_EVENT_GOTO_OUT)
goto out;
while (gtk_events_pending ())
{
current_count = count;
- current_numcharsp = &numchars;
- current_bufp = &bufp;
+ current_hold_quit = hold_quit;
gtk_main_iteration ();
count = current_count;
- current_bufp = 0;
- current_numcharsp = 0;
+ current_count = -1;
+ current_hold_quit = 0;
if (current_finish == X_EVENT_GOTO_OUT)
break;
pending_autoraise_frame = 0;
}
- UNBLOCK_INPUT;
--handling_signal;
+ UNBLOCK_INPUT;
+
return count;
}
struct glyph *cursor_glyph;
GC gc;
- /* Compute frame-relative coordinates from window-relative
- coordinates. */
- x = WINDOW_TEXT_TO_FRAME_PIXEL_X (w, w->phys_cursor.x);
- y = (WINDOW_TO_FRAME_PIXEL_Y (w, w->phys_cursor.y)
- + row->ascent - w->phys_cursor_ascent);
- h = row->height - 1;
-
/* Get the glyph the cursor is on. If we can't tell because
the current matrix is invalid or such, give up. */
cursor_glyph = get_phys_cursor_glyph (w);
wd = min (FRAME_COLUMN_WIDTH (f), wd);
w->phys_cursor_width = wd;
+ /* Compute frame-relative coordinates from window-relative
+ coordinates. */
+ x = WINDOW_TEXT_TO_FRAME_PIXEL_X (w, w->phys_cursor.x);
+ y = WINDOW_TO_FRAME_PIXEL_Y (w, w->phys_cursor.y);
+
+ /* Compute the proper height and ascent of the rectangle, based
+ on the actual glyph. Using the full height of the row looks
+ bad when there are tall images on that row. */
+ h = max (min (FRAME_LINE_HEIGHT (f), row->height),
+ cursor_glyph->ascent + cursor_glyph->descent);
+ if (h < row->height)
+ y += row->ascent /* - w->phys_cursor_ascent */ + cursor_glyph->descent - h;
+ h--;
+
/* The foreground of cursor_gc is typically the same as the normal
background color, which can cause the cursor box to be invisible. */
xgcv.foreground = f->output_data.x->cursor_pixel;
w->phys_cursor_type = cursor_type;
w->phys_cursor_on_p = 1;
+ if (glyph_row->exact_window_width_line_p
+ && w->phys_cursor.hpos >= glyph_row->used[TEXT_AREA])
+ {
+ glyph_row->cursor_in_fringe_p = 1;
+ draw_fringe_bitmap (w, glyph_row, 0);
+ }
+ else
switch (cursor_type)
{
case HOLLOW_BOX_CURSOR:
register char *fontname;
{
struct font_info *fontp
- = FS_LOAD_FONT (f, 0, fontname, -1);
+ = FS_LOAD_FONT (f, fontname);
if (!fontp)
return Qnil;
+ if (FRAME_FONT (f) == (XFontStruct *) (fontp->font))
+ /* This font is already set in frame F. There's nothing more to
+ do. */
+ return build_string (fontp->full_name);
+
FRAME_FONT (f) = (XFontStruct *) (fontp->font);
FRAME_BASELINE_OFFSET (f) = fontp->baseline_offset;
FRAME_FONTSET (f) = -1;
return build_string (fontp->full_name);
}
-/* Give frame F the fontset named FONTSETNAME as its default font, and
- return the full name of that fontset. FONTSETNAME may be a wildcard
- pattern; in that case, we choose some fontset that fits the pattern.
- The return value shows which fontset we chose. */
+/* Give frame F the fontset named FONTSETNAME as its default fontset,
+ and return the full name of that fontset. FONTSETNAME may be a
+ wildcard pattern; in that case, we choose some fontset that fits
+ the pattern. FONTSETNAME may be a font name for ASCII characters;
+ in that case, we create a fontset from that font name.
+
+ The return value shows which fontset we chose.
+ If FONTSETNAME specifies the default fontset, return Qt.
+ If an ASCII font in the specified fontset can't be loaded, return
+ Qnil. */
Lisp_Object
x_new_fontset (f, fontsetname)
struct frame *f;
- char *fontsetname;
+ Lisp_Object fontsetname;
{
- int fontset = fs_query_fontset (build_string (fontsetname), 0);
+ int fontset = fs_query_fontset (fontsetname, 0);
Lisp_Object result;
- if (fontset < 0)
- return Qnil;
-
- if (FRAME_FONTSET (f) == fontset)
+ if (fontset > 0 && f->output_data.x->fontset == fontset)
/* This fontset is already set in frame F. There's nothing more
to do. */
return fontset_name (fontset);
+ else if (fontset == 0)
+ /* The default fontset can't be the default font. */
+ return Qt;
- result = x_new_font (f, (SDATA (fontset_ascii (fontset))));
+ if (fontset > 0)
+ result = x_new_font (f, (SDATA (fontset_ascii (fontset))));
+ else
+ result = x_new_font (f, SDATA (fontsetname));
if (!STRINGP (result))
/* Can't load ASCII font. */
return Qnil;
+ if (fontset < 0)
+ fontset = new_fontset_from_font_name (result);
+
/* Since x_new_font doesn't update any fontset information, do it now. */
FRAME_FONTSET (f) = fontset;
xic_set_xfontset (f, SDATA (fontset_ascii (fontset)));
#endif
- return build_string (fontsetname);
+ return fontset_name (fontset);
}
\f
x_calc_absolute_position (f)
struct frame *f;
{
- Window child;
int win_x = 0, win_y = 0;
int flags = f->size_hint_flags;
- int this_window;
/* We have nothing to do if the current position
is already for the top-left corner. */
if (! ((flags & XNegative) || (flags & YNegative)))
return;
- this_window = FRAME_OUTER_WINDOW (f);
-
- /* Find the position of the outside upper-left corner of
+ /* Find the offsets of the outside upper-left corner of
the inner window, with respect to the outer window.
But do this only if we will need the results. */
if (f->output_data.x->parent_desc != FRAME_X_DISPLAY_INFO (f)->root_window)
- {
- int count;
-
- BLOCK_INPUT;
- count = x_catch_errors (FRAME_X_DISPLAY (f));
- while (1)
- {
- x_clear_errors (FRAME_X_DISPLAY (f));
- XTranslateCoordinates (FRAME_X_DISPLAY (f),
-
- /* From-window, to-window. */
- this_window,
- f->output_data.x->parent_desc,
-
- /* From-position, to-position. */
- 0, 0, &win_x, &win_y,
-
- /* Child of win. */
- &child);
- if (x_had_errors_p (FRAME_X_DISPLAY (f)))
- {
- Window newroot, newparent = 0xdeadbeef;
- Window *newchildren;
- unsigned int nchildren;
-
- if (! XQueryTree (FRAME_X_DISPLAY (f), this_window, &newroot,
- &newparent, &newchildren, &nchildren))
- break;
-
- XFree ((char *) newchildren);
-
- f->output_data.x->parent_desc = newparent;
- }
- else
- break;
- }
-
- x_uncatch_errors (FRAME_X_DISPLAY (f), count);
- UNBLOCK_INPUT;
- }
+ /* This is to get *_pixels_outer_diff. */
+ x_real_positions (f, &win_x, &win_y);
/* Treat negative positions as relative to the leftmost bottommost
position that fits on the screen. */
if (flags & XNegative)
f->left_pos = (FRAME_X_DISPLAY_INFO (f)->width
- - 2 * f->border_width - win_x
+ - 2 * FRAME_X_OUTPUT (f)->x_pixels_outer_diff
- FRAME_PIXEL_WIDTH (f)
+ f->left_pos);
if (flags & YNegative)
f->top_pos = (FRAME_X_DISPLAY_INFO (f)->height
- - 2 * f->border_width
- - win_y
+ - FRAME_X_OUTPUT (f)->y_pixels_outer_diff
+
+ /* Assume the window manager decorations are the same size on
+ three sides, i.e. left, right and bottom. This is to
+ compensate for the bottom part. */
+ - FRAME_X_OUTPUT (f)->x_pixels_outer_diff
- height
+ f->top_pos);
}
f->win_gravity = NorthWestGravity;
}
x_calc_absolute_position (f);
-
+
BLOCK_INPUT;
x_wm_set_size_hint (f, (long) 0, 0);
modified_left = f->left_pos;
modified_top = f->top_pos;
-#if 0 /* Running on psilocin (Debian), and displaying on the NCD X-terminal,
- this seems to be unnecessary and incorrect. rms, 4/17/97. */
- /* It is a mystery why we need to add the border_width here
- when the frame is already visible, but experiment says we do. */
- if (change_gravity != 0)
- {
- modified_left += f->border_width;
- modified_top += f->border_width;
- }
-#endif
-
if (FRAME_X_DISPLAY_INFO (f)->wm_type == X_WMTYPE_A)
{
/* Some WMs (twm, wmaker at least) has an offset that is smaller
If SIZE is > 0, it is the size (maximum bounds width) of fonts
to be listed.
- SIZE < 0 means include scalable fonts.
+ SIZE < 0 means include auto scaled fonts.
Frame F null means we have not yet created any frame on X, and
consult the first display in x_display_list. MAXNAMES sets a limit
bzero (fontp, sizeof (*fontp));
fontp->font = font;
fontp->font_idx = i;
+ fontp->charset = -1; /* fs_load_font sets it. */
fontp->name = (char *) xmalloc (strlen (fontname) + 1);
bcopy (fontname, fontp->name, strlen (fontname) + 1);
the font code-points (0:0x20..0x7F, 1:0xA0..0xFF), or
(0:0x2020..0x7F7F, 1:0xA0A0..0xFFFF, 3:0x20A0..0x7FFF,
2:0xA020..0xFF7F). For the moment, we don't know which charset
- uses this font. So, we set information in fontp->encoding[1]
+ uses this font. So, we set information in fontp->encoding_type
which is never used by any charset. If mapping can't be
decided, set FONT_ENCODING_NOT_DECIDED. */
- fontp->encoding[1]
+ fontp->encoding_type
= (font->max_byte1 == 0
/* 1-byte font */
? (font->min_char_or_byte2 < 0x80
}
+/* Return a char-table whose elements are t if the font FONT_INFO
+ contains a glyph for the corresponding character, and nil if
+ not. */
+
+Lisp_Object
+x_get_font_repertory (f, font_info)
+ FRAME_PTR f;
+ struct font_info *font_info;
+{
+ XFontStruct *font = (XFontStruct *) font_info->font;
+ Lisp_Object table;
+ int min_byte1, max_byte1, min_byte2, max_byte2;
+ int c;
+ struct charset *charset = CHARSET_FROM_ID (font_info->charset);
+ int offset = CHARSET_OFFSET (charset);
+
+ table = Fmake_char_table (Qnil, Qnil);
+
+ min_byte1 = font->min_byte1;
+ max_byte1 = font->max_byte1;
+ min_byte2 = font->min_char_or_byte2;
+ max_byte2 = font->max_char_or_byte2;
+ if (min_byte1 == 0 && max_byte1 == 0)
+ {
+ if (! font->per_char || font->all_chars_exist == True)
+ {
+ if (offset >= 0)
+ char_table_set_range (table, offset + min_byte2,
+ offset + max_byte2, Qt);
+ else
+ for (; min_byte2 <= max_byte2; min_byte2++)
+ {
+ c = DECODE_CHAR (charset, min_byte2);
+ CHAR_TABLE_SET (table, c, Qt);
+ }
+ }
+ else
+ {
+ XCharStruct *pcm = font->per_char;
+ int from = -1;
+ int i;
+
+ for (i = min_byte2; i <= max_byte2; i++, pcm++)
+ {
+ if (pcm->width == 0 && pcm->rbearing == pcm->lbearing)
+ {
+ if (from >= 0)
+ {
+ if (offset >= 0)
+ char_table_set_range (table, offset + from,
+ offset + i - 1, Qt);
+ else
+ for (; from < i; from++)
+ {
+ c = DECODE_CHAR (charset, from);
+ CHAR_TABLE_SET (table, c, Qt);
+ }
+ from = -1;
+ }
+ }
+ else if (from < 0)
+ from = i;
+ }
+ if (from >= 0)
+ {
+ if (offset >= 0)
+ char_table_set_range (table, offset + from, offset + i - 1,
+ Qt);
+ else
+ for (; from < i; from++)
+ {
+ c = DECODE_CHAR (charset, from);
+ CHAR_TABLE_SET (table, c, Qt);
+ }
+ }
+ }
+ }
+ else
+ {
+ if (! font->per_char || font->all_chars_exist == True)
+ {
+ int i, j;
+
+ if (offset >= 0)
+ for (i = min_byte1; i <= max_byte1; i++)
+ char_table_set_range
+ (table, offset + ((i << 8) | min_byte2),
+ offset + ((i << 8) | max_byte2), Qt);
+ else
+ for (i = min_byte1; i <= max_byte1; i++)
+ for (j = min_byte2; j <= max_byte2; j++)
+ {
+ unsigned code = (i << 8) | j;
+ c = DECODE_CHAR (charset, code);
+ CHAR_TABLE_SET (table, c, Qt);
+ }
+ }
+ else
+ {
+ XCharStruct *pcm = font->per_char;
+ int i;
+
+ for (i = min_byte1; i <= max_byte1; i++)
+ {
+ int from = -1;
+ int j;
+
+ for (j = min_byte2; j <= max_byte2; j++, pcm++)
+ {
+ if (pcm->width == 0 && pcm->rbearing == pcm->lbearing)
+ {
+ if (from >= 0)
+ {
+ if (offset >= 0)
+ char_table_set_range
+ (table, offset + ((i << 8) | from),
+ offset + ((i << 8) | (j - 1)), Qt);
+ else
+ {
+ for (; from < j; from++)
+ {
+ unsigned code = (i << 8) | from;
+ c = ENCODE_CHAR (charset, code);
+ CHAR_TABLE_SET (table, c, Qt);
+ }
+ }
+ from = -1;
+ }
+ }
+ else if (from < 0)
+ from = j;
+ }
+ if (from >= 0)
+ {
+ if (offset >= 0)
+ char_table_set_range
+ (table, offset + ((i << 8) | from),
+ offset + ((i << 8) | (j - 1)), Qt);
+ else
+ {
+ for (; from < j; from++)
+ {
+ unsigned code = (i << 8) | from;
+ c = DECODE_CHAR (charset, code);
+ CHAR_TABLE_SET (table, c, Qt);
+ }
+ }
+ }
+ }
+ }
+ }
+
+ return table;
+}
\f
/***********************************************************************
Initialization
get_bits_and_offset (dpyinfo->visual->green_mask,
&dpyinfo->green_bits, &dpyinfo->green_offset);
}
-
+
/* See if a private colormap is requested. */
if (dpyinfo->visual == DefaultVisualOfScreen (dpyinfo->screen))
{
x_get_glyph_overhangs,
x_fix_overlapping_area,
x_draw_fringe_bitmap,
+ 0, /* define_fringe_bitmap */
+ 0, /* destroy_fringe_bitmap */
x_per_char_metric,
x_encode_char,
x_compute_glyph_string_overhangs,
x_noop_count = 0;
last_tool_bar_item = -1;
any_help_event_p = 0;
+ ignore_next_mouse_click_timeout = 0;
+
+#ifdef USE_GTK
+ current_count = -1;
+#endif
/* Try to use interrupt input; if we can't, then start polling. */
Fset_input_mode (Qt, Qnil, Qt, Qnil);
staticpro (&Qvendor_specific_keysyms);
Qvendor_specific_keysyms = intern ("vendor-specific-keysyms");
- staticpro (&Qutf_8);
- Qutf_8 = intern ("utf-8");
staticpro (&Qlatin_1);
Qlatin_1 = intern ("latin-1");
to 4.1, set this to nil. */);
x_use_underline_position_properties = 1;
+ DEFVAR_BOOL ("x-mouse-click-focus-ignore-position",
+ &x_mouse_click_focus_ignore_position,
+ doc: /* Non-nil means that a mouse click to focus a frame does not move point.
+This variable is only used when the window manager requires that you
+click on a frame to select it (give it focus). In that case, a value
+of nil, means that the selected window and cursor position changes to
+reflect the mouse click position, while a non-nil value means that the
+selected window or cursor position is preserved. */);
+ x_mouse_click_focus_ignore_position = 0;
+
DEFVAR_LISP ("x-toolkit-scroll-bars", &Vx_toolkit_scroll_bars,
doc: /* What X toolkit scroll bars Emacs uses.
A value of nil means Emacs doesn't use X toolkit scroll bars.