X-Git-Url: http://git.hcoop.net/bpt/emacs.git/blobdiff_plain/d04103a1003598b33a5e1248be47f6c427e09466..04c9dde8afc535589a1a4803b45b346325e353e7:/src/xterm.c diff --git a/src/xterm.c b/src/xterm.c index 97553147bb..609ffefcbb 100644 --- a/src/xterm.c +++ b/src/xterm.c @@ -1,6 +1,6 @@ /* X Communication module for terminals which understand the X protocol. - Copyright (C) 1989, 93, 94, 95, 96, 97, 98, 1999, 2000, 01, 02, 2003 - Free Software Foundation, Inc. + Copyright (C) 1989, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, + 2002, 2003, 2004, 2005 Free Software Foundation, Inc. This file is part of GNU Emacs. @@ -131,6 +131,7 @@ extern void _XEditResCheckMessages (); #include #include #define ARROW_SCROLLBAR +#define XAW_ARROW_SCROLLBARS #include #else /* !HAVE_XAW3D */ #include @@ -216,6 +217,17 @@ static String Xt_default_resources[] = {0}; 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) @@ -286,7 +298,7 @@ extern Lisp_Object Vcommand_line_args, Vsystem_name; extern Lisp_Object Vx_no_window_manager; -extern Lisp_Object Qface, Qmouse_face, Qeql; +extern Lisp_Object Qeql; extern int errno; @@ -335,39 +347,30 @@ static void x_clear_frame P_ ((void)); 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 *)); static void x_draw_bar_cursor P_ ((struct window *, struct glyph_row *, int, enum text_cursor_kinds)); -static void x_clip_to_row P_ ((struct window *, struct glyph_row *, GC)); +static void x_clip_to_row P_ ((struct window *, struct glyph_row *, int, GC)); static void x_flush P_ ((struct frame *f)); static void x_update_begin P_ ((struct frame *)); static void x_update_window_begin P_ ((struct window *)); static void x_after_update_window_line P_ ((struct glyph_row *)); -static struct scroll_bar *x_window_to_scroll_bar P_ ((Window)); +static struct scroll_bar *x_window_to_scroll_bar P_ ((Display *, Window)); static void x_scroll_bar_report_motion P_ ((struct frame **, Lisp_Object *, enum scroll_bar_part *, Lisp_Object *, Lisp_Object *, 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. */ @@ -568,7 +571,9 @@ x_update_window_end (w, cursor_on_p, mouse_face_overwritten_p) output_cursor.vpos, output_cursor.x, output_cursor.y); - x_draw_vertical_border (w); + if (draw_window_fringes (w, 1)) + x_draw_vertical_border (w); + UNBLOCK_INPUT; } @@ -648,11 +653,7 @@ x_after_update_window_line (desired_row) 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 @@ -696,11 +697,26 @@ x_draw_fringe_bitmap (w, row, p) 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, -1, gc); + row->y = oldY; + row->visible_height = oldVH; + } + else + x_clip_to_row (w, row, -1, 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 @@ -718,20 +734,49 @@ x_draw_fringe_bitmap (w, row, p) 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); @@ -935,7 +980,8 @@ static void x_draw_image_foreground_1 P_ ((struct glyph_string *, Pixmap)); 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 *)); @@ -1973,9 +2019,10 @@ x_setup_relief_colors (s) 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); @@ -1990,10 +2037,11 @@ x_draw_relief_rect (f, left_x, top_y, right_x, bottom_y, width, 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) @@ -2009,10 +2057,11 @@ x_draw_relief_rect (f, left_x, top_y, right_x, bottom_y, width, 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) @@ -2078,15 +2127,9 @@ x_draw_glyph_string_box (s) struct glyph *last_glyph; XRectangle clip_rect; - last_x = window_box_right (s->w, s->area); - if (s->row->full_width_p - && !s->w->pseudo_window_p) - { - last_x += WINDOW_RIGHT_SCROLL_BAR_AREA_WIDTH (s->w); - if (s->area != RIGHT_MARGIN_AREA - || WINDOW_HAS_FRINGES_OUTSIDE_MARGINS (s->w)) - last_x += WINDOW_RIGHT_FRINGE_WIDTH (s->w); - } + last_x = ((s->row->full_width_p && !s->w->pseudo_window_p) + ? WINDOW_RIGHT_EDGE_X (s->w) + : window_box_right (s->w, s->area)); /* The glyph that may have a right box line. */ last_glyph = (s->cmp || s->img @@ -2120,7 +2163,7 @@ x_draw_glyph_string_box (s) { 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); } } @@ -2131,21 +2174,22 @@ static void 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) { @@ -2170,11 +2214,12 @@ x_draw_image_foreground (s) 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 { @@ -2183,11 +2228,12 @@ x_draw_image_foreground (s) 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 @@ -2199,15 +2245,17 @@ x_draw_image_foreground (s) { 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); } @@ -2219,21 +2267,22 @@ x_draw_image_relief (s) { 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) @@ -2249,12 +2298,17 @@ x_draw_image_relief (s) 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); } @@ -2265,21 +2319,22 @@ x_draw_image_foreground_1 (s, pixmap) 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) { @@ -2295,19 +2350,21 @@ x_draw_image_foreground_1 (s, 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 @@ -2320,14 +2377,15 @@ x_draw_image_foreground_1 (s, pixmap) 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); } @@ -2369,33 +2427,28 @@ static void 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 @@ -2434,7 +2487,19 @@ x_draw_image_glyph_string (s) } } 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; } @@ -2752,10 +2817,6 @@ x_clear_frame () XFlush (FRAME_X_DISPLAY (f)); -#ifdef USE_GTK - xg_frame_cleared (f); -#endif - UNBLOCK_INPUT; } @@ -3123,20 +3184,16 @@ x_new_focus_frame (dpyinfo, frame) /* 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) @@ -3146,17 +3203,12 @@ x_focus_changed (type, state, dpyinfo, frame, bufp, numchars) /* 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; } } @@ -3182,57 +3234,51 @@ x_focus_changed (type, state, dpyinfo, frame, bufp, numchars) 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) { case EnterNotify: case LeaveNotify: - if (event->xcrossing.detail != NotifyInferior - && event->xcrossing.focus - && ! (frame->output_data.x->focus_state & FOCUS_EXPLICIT)) - nr_events = x_focus_changed ((event->type == EnterNotify - ? FocusIn : FocusOut), - FOCUS_IMPLICIT, - dpyinfo, - frame, - bufp, - numchars); + { + struct frame *focus_frame = dpyinfo->x_focus_event_frame; + int focus_state + = focus_frame ? focus_frame->output_data.x->focus_state : 0; + + if (event->xcrossing.detail != NotifyInferior + && event->xcrossing.focus + && ! (focus_state & FOCUS_EXPLICIT)) + 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; } @@ -3326,12 +3372,14 @@ x_find_modifier_meanings (dpyinfo) Alt keysyms are on. */ { int row, col; /* The row and column in the modifier table. */ + int found_alt_or_meta; for (row = 3; row < 8; row++) + { + found_alt_or_meta = 0; for (col = 0; col < mods->max_keypermod; col++) { - KeyCode code - = mods->modifiermap[(row * mods->max_keypermod) + col]; + KeyCode code = mods->modifiermap[(row * mods->max_keypermod) + col]; /* Zeroes are used for filler. Skip them. */ if (code == 0) @@ -3349,33 +3397,44 @@ x_find_modifier_meanings (dpyinfo) { case XK_Meta_L: case XK_Meta_R: + found_alt_or_meta = 1; dpyinfo->meta_mod_mask |= (1 << row); break; case XK_Alt_L: case XK_Alt_R: + found_alt_or_meta = 1; dpyinfo->alt_mod_mask |= (1 << row); break; case XK_Hyper_L: case XK_Hyper_R: - dpyinfo->hyper_mod_mask |= (1 << row); + if (!found_alt_or_meta) + dpyinfo->hyper_mod_mask |= (1 << row); + code_col = syms_per_code; + col = mods->max_keypermod; break; case XK_Super_L: case XK_Super_R: - dpyinfo->super_mod_mask |= (1 << row); + if (!found_alt_or_meta) + dpyinfo->super_mod_mask |= (1 << row); + code_col = syms_per_code; + col = mods->max_keypermod; break; case XK_Shift_Lock: /* Ignore this if it's not on the lock modifier. */ - if ((1 << row) == LockMask) + if (!found_alt_or_meta && ((1 << row) == LockMask)) dpyinfo->shift_lock_mask = LockMask; + code_col = syms_per_code; + col = mods->max_keypermod; break; } } } } + } } /* If we couldn't find any meta keys, accept any alt keys as meta keys. */ @@ -3577,35 +3636,39 @@ glyph_rect (f, x, y, rect) 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; } @@ -3770,7 +3833,9 @@ XTmouse_position (fp, insist, bar_window, part, x, y, time) /* If not, is it one of our scroll bars? */ if (! f1) { - struct scroll_bar *bar = x_window_to_scroll_bar (win); + struct scroll_bar *bar; + + bar = x_window_to_scroll_bar (FRAME_X_DISPLAY (*fp), win); if (bar) { @@ -3841,19 +3906,21 @@ XTmouse_position (fp, insist, bar_window, part, x, y, time) /* Scroll bar support. */ -/* Given an X window ID, find the struct scroll_bar which manages it. +/* Given an X window ID and a DISPLAY, find the struct scroll_bar which + manages it. This can be called in GC, so we have to make sure to strip off mark bits. */ static struct scroll_bar * -x_window_to_scroll_bar (window_id) +x_window_to_scroll_bar (display, window_id) + Display *display; Window window_id; { Lisp_Object tail; -#ifdef USE_GTK - window_id = (Window) xg_get_scroll_id_for_window (window_id); -#endif /* USE_GTK */ +#if defined (USE_GTK) && defined (USE_TOOLKIT_SCROLL_BARS) + window_id = (Window) xg_get_scroll_id_for_window (display, window_id); +#endif /* USE_GTK && USE_TOOLKIT_SCROLL_BARS */ for (tail = Vframe_list; XGCTYPE (tail) == Lisp_Cons; @@ -3876,7 +3943,8 @@ x_window_to_scroll_bar (window_id) condemned = Qnil, ! GC_NILP (bar)); bar = XSCROLL_BAR (bar)->next) - if (SCROLL_BAR_X_WINDOW (XSCROLL_BAR (bar)) == window_id) + if (SCROLL_BAR_X_WINDOW (XSCROLL_BAR (bar)) == window_id && + FRAME_X_DISPLAY (XFRAME (frame)) == display) return XSCROLL_BAR (bar); } @@ -4209,8 +4277,6 @@ xg_scroll_callback (widget, data) int part = -1, whole = 0, portion = 0; GtkAdjustment *adj = GTK_ADJUSTMENT (gtk_range_get_adjustment (widget)); - if (xg_ignore_gtk_scrollbar) return; - position = gtk_adjustment_get_value (adj); p = g_object_get_data (G_OBJECT (widget), XG_LAST_SB_DATA); @@ -4224,6 +4290,8 @@ xg_scroll_callback (widget, data) previous = *p; *p = position; + if (xg_ignore_gtk_scrollbar) return; + diff = (int) (position - previous); if (diff == (int) adj->step_increment) @@ -4783,9 +4851,7 @@ x_scroll_bar_create (w, top, left, width, height) top, left + VERTICAL_SCROLL_BAR_WIDTH_TRIM, width - VERTICAL_SCROLL_BAR_WIDTH_TRIM * 2, - max (height, 1), - left, - width); + max (height, 1)); xg_show_scroll_bar (SCROLL_BAR_X_WINDOW (bar)); #else /* not USE_GTK */ Widget scroll_bar = SCROLL_BAR_X_WIDGET (FRAME_X_DISPLAY (f), bar); @@ -4980,9 +5046,15 @@ XTset_vertical_scroll_bar (w, portion, whole, position) /* Compute the left edge of the scroll bar. */ #ifdef USE_TOOLKIT_SCROLL_BARS if (WINDOW_HAS_VERTICAL_SCROLL_BAR_ON_RIGHT (w)) - sb_left = left + width - sb_width - (width - sb_width) / 2; + sb_left = (left + + (WINDOW_RIGHTMOST_P (w) + ? width - sb_width - (width - sb_width) / 2 + : 0)); else - sb_left = left + (width - sb_width) / 2; + sb_left = (left + + (WINDOW_LEFTMOST_P (w) + ? (width - sb_width) / 2 + : width - sb_width)); #else if (WINDOW_HAS_VERTICAL_SCROLL_BAR_ON_RIGHT (w)) sb_left = left + width - sb_width; @@ -5023,32 +5095,29 @@ XTset_vertical_scroll_bar (w, portion, whole, position) #ifdef USE_TOOLKIT_SCROLL_BARS -#ifdef USE_GTK - if (mask) - xg_update_scrollbar_pos (f, - SCROLL_BAR_X_WINDOW (bar), - top, - sb_left + VERTICAL_SCROLL_BAR_WIDTH_TRIM, - sb_width - VERTICAL_SCROLL_BAR_WIDTH_TRIM * 2, - max (height, 1), - left, - width); -#else /* not USE_GTK */ - - /* Since toolkit scroll bars are smaller than the space reserved - for them on the frame, we have to clear "under" them. */ - if (width > 0 && height > 0) - x_clear_area (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f), - left, top, width, height, False); /* Move/size the scroll bar widget. */ if (mask) + { + /* Since toolkit scroll bars are smaller than the space reserved + for them on the frame, we have to clear "under" them. */ + if (width > 0 && height > 0) + x_clear_area (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f), + left, top, width, height, False); +#ifdef USE_GTK + xg_update_scrollbar_pos (f, + SCROLL_BAR_X_WINDOW (bar), + top, + sb_left + VERTICAL_SCROLL_BAR_WIDTH_TRIM, + sb_width - VERTICAL_SCROLL_BAR_WIDTH_TRIM *2, + max (height, 1)); +#else /* not USE_GTK */ XtConfigureWidget (SCROLL_BAR_X_WIDGET (FRAME_X_DISPLAY (f), bar), sb_left + VERTICAL_SCROLL_BAR_WIDTH_TRIM, top, sb_width - VERTICAL_SCROLL_BAR_WIDTH_TRIM * 2, max (height, 1), 0); - #endif /* not USE_GTK */ + } #else /* not USE_TOOLKIT_SCROLL_BARS */ /* Clear areas not covered by the scroll bar because of @@ -5500,73 +5569,6 @@ x_scroll_bar_clear (f) } -/* Define a queue to save up SelectionRequest events for later handling. */ - -struct selection_event_queue - { - XEvent event; - struct selection_event_queue *next; - }; - -static struct selection_event_queue *queue; - -/* Nonzero means queue up certain events--don't process them yet. */ - -static int x_queue_selection_requests; - -/* Queue up an X event *EVENT, to be processed later. */ - -static void -x_queue_event (f, event) - FRAME_PTR f; - XEvent *event; -{ - struct selection_event_queue *queue_tmp - = (struct selection_event_queue *) xmalloc (sizeof (struct selection_event_queue)); - - if (queue_tmp != NULL) - { - queue_tmp->event = *event; - queue_tmp->next = queue; - queue = queue_tmp; - } -} - -/* Take all the queued events and put them back - so that they get processed afresh. */ - -static void -x_unqueue_events (display) - Display *display; -{ - while (queue != NULL) - { - struct selection_event_queue *queue_tmp = queue; - XPutBackEvent (display, &queue_tmp->event); - queue = queue_tmp->next; - xfree ((char *)queue_tmp); - } -} - -/* Start queuing SelectionRequest events. */ - -void -x_start_queuing_selection_requests (display) - Display *display; -{ - x_queue_selection_requests++; -} - -/* Stop queuing SelectionRequest events. */ - -void -x_stop_queuing_selection_requests (display) - Display *display; -{ - x_queue_selection_requests--; - x_unqueue_events (display); -} - /* The main X event-reading loop - XTread_socket. */ #if 0 @@ -5593,6 +5595,11 @@ static XComposeStatus compose_status; 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. */ @@ -5612,15 +5619,8 @@ static struct x_display_info *next_noop_dpyinfo; 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.ie.kind = MENU_BAR_ACTIVATE_EVENT; \ + XSETFRAME (inev.ie.frame_or_window, f); \ } \ while (0) @@ -5662,41 +5662,47 @@ x_filter_event (dpyinfo, event) #endif #ifdef USE_GTK -static struct x_display_info *current_dpyinfo; -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; GdkEvent *ev; gpointer data; { - XEvent *xev = (XEvent*)gxev; + XEvent *xev = (XEvent *) gxev; - if (current_numcharsp) + if (current_count >= 0) { + struct x_display_info *dpyinfo; + + dpyinfo = x_display_info_for_display (xev->xany.display); + #ifdef HAVE_X_I18N /* Filter events for the current X input method. GTK calls XFilterEvent but not for key press and release, so we do it here. */ if (xev->type == KeyPress || xev->type == KeyRelease) - if (x_filter_event (current_dpyinfo, xev)) + if (dpyinfo && x_filter_event (dpyinfo, xev)) return GDK_FILTER_REMOVE; #endif - current_count += handle_one_xevent (current_dpyinfo, - xev, - current_bufp, - current_numcharsp, - ¤t_finish); + + if (! dpyinfo) + current_finish = X_EVENT_NORMAL; + else + { + current_count += + handle_one_xevent (dpyinfo, xev, ¤t_finish, + current_hold_quit); + } } else - current_finish = x_dispatch_event (xev, GDK_DISPLAY ()); + current_finish = x_dispatch_event (xev, xev->xany.display); if (current_finish == X_EVENT_GOTO_OUT || current_finish == X_EVENT_DROP) return GDK_FILTER_REMOVE; @@ -5712,28 +5718,32 @@ event_handler_gdk (gxev, ev, data) *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; { + union { + struct input_event ie; + struct selection_input_event sie; + } 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.ie); + inev.ie.kind = NO_EVENT; + inev.ie.arg = Qnil; + switch (event.type) { case ClientMessage: @@ -5788,8 +5798,10 @@ handle_one_xevent (dpyinfo, eventp, bufp_r, numcharsp, finish) } /* 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 @@ -5800,11 +5812,9 @@ handle_one_xevent (dpyinfo, eventp, bufp_r, numcharsp, finish) /* 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); @@ -5819,41 +5829,36 @@ handle_one_xevent (dpyinfo, eventp, bufp_r, numcharsp, finish) 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.ie.kind = DELETE_WINDOW_EVENT; + XSETFRAME (inev.ie.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]; @@ -5863,45 +5868,55 @@ handle_one_xevent (dpyinfo, eventp, bufp_r, numcharsp, finish) 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.ie); + *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.ie)) + *finish = X_EVENT_DROP; } break; @@ -5921,19 +5936,11 @@ handle_one_xevent (dpyinfo, eventp, bufp_r, numcharsp, finish) { 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.ie.kind = SELECTION_CLEAR_EVENT; + SELECTION_EVENT_DISPLAY (&inev.sie) = eventp->display; + SELECTION_EVENT_SELECTION (&inev.sie) = eventp->selection; + SELECTION_EVENT_TIME (&inev.sie) = eventp->time; + inev.ie.frame_or_window = Qnil; } break; @@ -5942,31 +5949,19 @@ handle_one_xevent (dpyinfo, eventp, bufp_r, numcharsp, finish) if (!x_window_to_frame (dpyinfo, event.xselectionrequest.owner)) goto OTHER; #endif /* USE_X_TOOLKIT */ - if (x_queue_selection_requests) - x_queue_event (x_window_to_frame (dpyinfo, event.xselectionrequest.owner), - &event); - else - { + { 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.ie.kind = SELECTION_REQUEST_EVENT; + SELECTION_EVENT_DISPLAY (&inev.sie) = eventp->display; + SELECTION_EVENT_REQUESTOR (&inev.sie) = eventp->requestor; + SELECTION_EVENT_SELECTION (&inev.sie) = eventp->selection; + SELECTION_EVENT_TARGET (&inev.sie) = eventp->target; + SELECTION_EVENT_PROPERTY (&inev.sie) = eventp->property; + SELECTION_EVENT_TIME (&inev.sie) = eventp->time; + inev.ie.frame_or_window = Qnil; + } break; case PropertyNotify: @@ -5995,7 +5990,6 @@ handle_one_xevent (dpyinfo, eventp, bufp_r, numcharsp, finish) FRAME_X_DISPLAY_INFO (f)->wm_type = X_WMTYPE_UNKNOWN; } goto OTHER; - break; case Expose: f = x_window_to_frame (dpyinfo, event.xexpose.window); @@ -6003,6 +5997,14 @@ handle_one_xevent (dpyinfo, eventp, bufp_r, numcharsp, finish) { x_check_fullscreen (f); +#ifdef USE_GTK + /* This seems to be needed for GTK 2.6. */ + x_clear_area (event.xexpose.display, + event.xexpose.window, + event.xexpose.x, event.xexpose.y, + event.xexpose.width, event.xexpose.height, + FALSE); +#endif if (f->async_visible == 0) { f->async_visible = 1; @@ -6036,7 +6038,8 @@ handle_one_xevent (dpyinfo, eventp, bufp_r, numcharsp, finish) /* Dispatch event to the widget. */ goto OTHER; #else /* not USE_TOOLKIT_SCROLL_BARS */ - bar = x_window_to_scroll_bar (event.xexpose.window); + bar = x_window_to_scroll_bar (event.xexpose.display, + event.xexpose.window); if (bar) x_scroll_bar_expose (bar, &event); @@ -6096,12 +6099,8 @@ handle_one_xevent (dpyinfo, eventp, bufp_r, numcharsp, finish) { f->async_iconified = 1; - bufp->kind = ICONIFY_EVENT; - XSETFRAME (bufp->frame_or_window, f); - bufp->arg = Qnil; - bufp++; - count++; - numchars--; + inev.ie.kind = ICONIFY_EVENT; + XSETFRAME (inev.ie.frame_or_window, f); } } goto OTHER; @@ -6118,7 +6117,7 @@ handle_one_xevent (dpyinfo, eventp, bufp_r, numcharsp, finish) f = x_top_window_to_frame (dpyinfo, event.xmap.window); if (f) { - /* wait_reading_process_input will notice this and update + /* wait_reading_process_output will notice this and update the frame's display structures. If we where iconified, we should not set garbaged, because that stops redrawing on Expose events. This looks @@ -6133,12 +6132,8 @@ handle_one_xevent (dpyinfo, eventp, bufp_r, numcharsp, finish) if (f->iconified) { - bufp->kind = DEICONIFY_EVENT; - XSETFRAME (bufp->frame_or_window, f); - bufp->arg = Qnil; - bufp++; - count++; - numchars--; + inev.ie.kind = DEICONIFY_EVENT; + XSETFRAME (inev.ie.frame_or_window, f); } else if (! NILP (Vframe_list) && ! NILP (XCDR (Vframe_list))) @@ -6151,6 +6146,8 @@ handle_one_xevent (dpyinfo, eventp, bufp_r, numcharsp, finish) 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 ()) @@ -6161,8 +6158,8 @@ handle_one_xevent (dpyinfo, eventp, bufp_r, numcharsp, finish) 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 @@ -6199,6 +6196,15 @@ handle_one_xevent (dpyinfo, eventp, bufp_r, numcharsp, finish) 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), @@ -6285,51 +6291,44 @@ handle_one_xevent (dpyinfo, eventp, bufp_r, numcharsp, finish) &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.ie.frame_or_window, f); + inev.ie.modifiers + = x_x_to_emacs_modifiers (FRAME_X_DISPLAY_INFO (f), modifiers); + inev.ie.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.ie.kind = ASCII_KEYSTROKE_EVENT; + inev.ie.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.ie.kind = (SINGLE_BYTE_CHAR_P (XFASTINT (c)) + ? ASCII_KEYSTROKE_EVENT + : MULTIBYTE_CHAR_KEYSTROKE_EVENT); + inev.ie.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 @@ -6410,104 +6409,80 @@ handle_one_xevent (dpyinfo, eventp, bufp_r, numcharsp, finish) <= 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.ie.kind = NON_ASCII_KEYSTROKE_EVENT; + inev.ie.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; + + /* 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++) + { + STORE_KEYSYM_FOR_DEBUG (copy_bufptr[i]); + } - /* 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++; - } + { + /* 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; + } - count += nchars; - numchars -= nchars; + /* 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.ie.kind = (SINGLE_BYTE_CHAR_P (c) + ? ASCII_KEYSTROKE_EVENT + : MULTIBYTE_CHAR_KEYSTROKE_EVENT); + inev.ie.code = c; + kbd_buffer_store_event_hold (&inev.ie, hold_quit); + } - if (keysym == NoSymbol) - break; - } - else - abort (); - } - else - abort (); + /* Previous code updated count by nchars rather than nbytes, + but that seems bogus to me. ++kfs */ + count += nbytes; + + inev.ie.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 @@ -6528,63 +6503,41 @@ handle_one_xevent (dpyinfo, eventp, bufp_r, numcharsp, finish) #endif case EnterNotify: - { - int n; + x_detect_focus_change (dpyinfo, &event, &inev.ie); - 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.ie); 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.ie); f = x_top_window_to_frame (dpyinfo, event.xcrossing.window); if (f) @@ -6602,31 +6555,12 @@ handle_one_xevent (dpyinfo, eventp, bufp_r, numcharsp, finish) 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.ie); goto OTHER; case MotionNotify: @@ -6662,15 +6596,12 @@ handle_one_xevent (dpyinfo, eventp, bufp_r, numcharsp, finish) /* Window will be selected only when it is not selected now and last mouse movement event was not in it. Minibuffer window will be selected iff it is active. */ - if (WINDOWP(window) + 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.ie.kind = SELECT_WINDOW_EVENT; + inev.ie.frame_or_window = window; } last_window=window; @@ -6681,7 +6612,8 @@ handle_one_xevent (dpyinfo, eventp, bufp_r, numcharsp, finish) { #ifndef USE_TOOLKIT_SCROLL_BARS struct scroll_bar *bar - = x_window_to_scroll_bar (event.xmotion.window); + = x_window_to_scroll_bar (event.xmotion.display, + event.xmotion.window); if (bar) x_scroll_bar_note_movement (bar, &event); @@ -6696,22 +6628,7 @@ handle_one_xevent (dpyinfo, eventp, bufp_r, numcharsp, finish) 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; } @@ -6795,10 +6712,8 @@ handle_one_xevent (dpyinfo, eventp, bufp_r, numcharsp, finish) { /* 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 @@ -6838,25 +6753,40 @@ handle_one_xevent (dpyinfo, eventp, bufp_r, numcharsp, finish) #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.ie, &event, f); + } + if (event.type == ButtonRelease) + ignore_next_mouse_click_timeout = 0; + } + else + construct_mouse_click (&inev.ie, &event, f); + } } } else { struct scroll_bar *bar - = x_window_to_scroll_bar (event.xbutton.window); + = x_window_to_scroll_bar (event.xbutton.display, + event.xbutton.window); #ifdef USE_TOOLKIT_SCROLL_BARS /* Make the "Ctrl-Mouse-2 splits window" work for toolkit 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.ie); *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.ie); #endif /* not USE_TOOLKIT_SCROLL_BARS */ } @@ -6877,14 +6807,6 @@ handle_one_xevent (dpyinfo, eventp, bufp_r, numcharsp, finish) 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, @@ -6971,16 +6893,38 @@ handle_one_xevent (dpyinfo, eventp, bufp_r, numcharsp, finish) break; } - goto ret; + done: + if (inev.ie.kind != NO_EVENT) + { + kbd_buffer_store_event_hold (&inev.ie, 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; } @@ -6996,30 +6940,12 @@ x_dispatch_event (event, display) 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; - - for (dpyinfo = x_display_list; dpyinfo; dpyinfo = dpyinfo->next) - if (dpyinfo->display == display) - break; + 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; } @@ -7029,19 +6955,16 @@ x_dispatch_event (event, display) 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; @@ -7060,9 +6983,6 @@ XTread_socket (sd, bufp, numchars, expected) /* 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. @@ -7104,35 +7024,21 @@ XTread_socket (sd, bufp, numchars, expected) } #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 -#ifdef USE_GTK - /* For GTK we must use the GTK event loop. But XEvents gets passed - to our filter function above, and then to the big event switch. - We use a bunch of globals to communicate with our filter function, - that is kind of ugly, but it works. */ - current_dpyinfo = dpyinfo; - - while (gtk_events_pending ()) - { - current_count = count; - current_numcharsp = &numchars; - current_bufp = &bufp; - - gtk_main_iteration (); - - count = current_count; - current_bufp = 0; - current_numcharsp = 0; - - if (current_finish == X_EVENT_GOTO_OUT) - goto out; - } - -#else /* not USE_GTK */ +#ifndef USE_GTK while (XPending (dpyinfo->display)) { int finish; @@ -7146,18 +7052,40 @@ XTread_socket (sd, bufp, numchars, expected) #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; } -#endif /* USE_GTK */ +#endif /* not USE_GTK */ } +#ifdef USE_GTK + + /* For GTK we must use the GTK event loop. But XEvents gets passed + to our filter function above, and then to the big event switch. + We use a bunch of globals to communicate with our filter function, + that is kind of ugly, but it works. + + There is no way to do one display at the time, GTK just does events + from all displays. */ + + while (gtk_events_pending ()) + { + current_count = count; + current_hold_quit = hold_quit; + + gtk_main_iteration (); + + count = current_count; + current_count = -1; + current_hold_quit = 0; + + if (current_finish == X_EVENT_GOTO_OUT) + break; + } +#endif /* USE_GTK */ + out:; /* On some systems, an X bug causes Emacs to get no more events @@ -7191,8 +7119,9 @@ XTread_socket (sd, bufp, numchars, expected) pending_autoraise_frame = 0; } - UNBLOCK_INPUT; --handling_signal; + UNBLOCK_INPUT; + return count; } @@ -7211,19 +7140,20 @@ XTread_socket (sd, bufp, numchars, expected) mode lines must be clipped to the whole window. */ static void -x_clip_to_row (w, row, gc) +x_clip_to_row (w, row, area, gc) struct window *w; struct glyph_row *row; + int area; GC gc; { struct frame *f = XFRAME (WINDOW_FRAME (w)); XRectangle clip_rect; - int window_y, window_width; + int window_x, window_y, window_width; - window_box (w, -1, 0, &window_y, &window_width, 0); + window_box (w, area, &window_x, &window_y, &window_width, 0); - clip_rect.x = WINDOW_TO_FRAME_PIXEL_X (w, 0); - clip_rect.y = WINDOW_TO_FRAME_PIXEL_Y (w, row->y); + clip_rect.x = window_x; + clip_rect.y = WINDOW_TO_FRAME_PIXEL_Y (w, max (0, row->y)); clip_rect.y = max (clip_rect.y, window_y); clip_rect.width = window_width; clip_rect.height = row->visible_height; @@ -7247,28 +7177,16 @@ x_draw_hollow_cursor (w, row) 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); if (cursor_glyph == NULL) return; - /* Compute the width of the rectangle to draw. If on a stretch - glyph, and `x-stretch-block-cursor' is nil, don't draw a - rectangle as wide as the glyph, but use a canonical character - width instead. */ - wd = cursor_glyph->pixel_width - 1; - if (cursor_glyph->type == STRETCH_GLYPH - && !x_stretch_cursor_p) - wd = min (FRAME_COLUMN_WIDTH (f), wd); - w->phys_cursor_width = wd; + /* Compute frame-relative coordinates for phys cursor. */ + x = WINDOW_TEXT_TO_FRAME_PIXEL_X (w, w->phys_cursor.x); + y = get_phys_cursor_geometry (w, row, cursor_glyph, &h); + wd = w->phys_cursor_width; /* The foreground of cursor_gc is typically the same as the normal background color, which can cause the cursor box to be invisible. */ @@ -7281,7 +7199,7 @@ x_draw_hollow_cursor (w, row) gc = dpyinfo->scratch_cursor_gc; /* Set clipping, draw the rectangle, and reset clipping again. */ - x_clip_to_row (w, row, gc); + x_clip_to_row (w, row, TEXT_AREA, gc); XDrawRectangle (dpy, FRAME_X_WINDOW (f), gc, x, y, wd, h); XSetClipMask (dpy, gc, None); } @@ -7353,7 +7271,7 @@ x_draw_bar_cursor (w, row, width, kind) width = min (cursor_glyph->pixel_width, width); w->phys_cursor_width = width; - x_clip_to_row (w, row, gc); + x_clip_to_row (w, row, TEXT_AREA, gc); if (kind == BAR_CURSOR) XFillRectangle (dpy, window, gc, @@ -7413,6 +7331,13 @@ x_draw_window_cursor (w, glyph_row, x, y, cursor_type, cursor_width, on_p, activ 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: @@ -7475,13 +7400,13 @@ x_bitmap_icon (f, file) if (STRINGP (file)) { #ifdef USE_GTK - /* Use gtk_window_set_icon_from_file() if available, + /* Use gtk_window_set_icon_from_file () if available, It's not restricted to bitmaps */ - if (xg_set_icon(f, file)) + if (xg_set_icon (f, file)) return 0; #endif /* USE_GTK */ bitmap_id = x_create_bitmap_from_file (f, file); - x_create_bitmap_mask(f, bitmap_id); + x_create_bitmap_mask (f, bitmap_id); } else { @@ -7491,7 +7416,7 @@ x_bitmap_icon (f, file) FRAME_X_DISPLAY_INFO (f)->icon_bitmap_id = x_create_bitmap_from_data (f, gnu_bits, gnu_width, gnu_height); - x_create_bitmap_mask(f, FRAME_X_DISPLAY_INFO (f)->icon_bitmap_id); + x_create_bitmap_mask (f, FRAME_X_DISPLAY_INFO (f)->icon_bitmap_id); } /* The first time we create the GNU bitmap and mask, @@ -7604,11 +7529,17 @@ static Lisp_Object x_catch_errors_unwind (old_val) Lisp_Object old_val; { - Lisp_Object first; + Lisp_Object first = XCAR (old_val); + Display *dpy = XSAVE_VALUE (first)->pointer; - first = XCAR (old_val); - - XSync (XSAVE_VALUE (first)->pointer, False); + /* The display may have been closed before this function is called. + Check if it is still open before calling XSync. */ + if (x_display_info_for_display (dpy) != 0) + { + BLOCK_INPUT; + XSync (dpy, False); + UNBLOCK_INPUT; + } x_error_message_string = XCDR (old_val); return Qnil; @@ -7760,6 +7691,11 @@ x_connection_closed (dpy, error_message) } #endif +#ifdef USE_GTK + if (dpyinfo) + xg_display_close (dpyinfo->display); +#endif + /* Indicate that this display is dead. */ if (dpyinfo) dpyinfo->display = 0; @@ -7814,12 +7750,41 @@ x_connection_closed (dpy, error_message) error ("%s", error_msg); } +/* We specifically use it before defining it, so that gcc doesn't inline it, + otherwise gdb doesn't know how to properly put a breakpoint on it. */ +static void x_error_quitter (Display *display, XErrorEvent *error); + +/* This is the first-level handler for X protocol errors. + It calls x_error_quitter or x_error_catcher. */ + +static int +x_error_handler (display, error) + Display *display; + XErrorEvent *error; +{ + if (! NILP (x_error_message_string)) + x_error_catcher (display, error); + else + x_error_quitter (display, error); + return 0; +} /* This is the usual handler for X protocol errors. It kills all frames on the display that we got the error for. If that was the only one, it prints an error message and kills Emacs. */ -static void +/* .gdbinit puts a breakpoint here, so make sure it is not inlined. */ + +#if __GNUC__ >= 3 /* On GCC 3.0 we might get a warning. */ +#define NO_INLINE __attribute__((noinline)) +#else +#define NO_INLINE +#endif + +/* On older GCC versions, just putting x_error_quitter + after x_error_handler prevents inlining into the former. */ + +static void NO_INLINE x_error_quitter (display, error) Display *display; XErrorEvent *error; @@ -7836,21 +7801,6 @@ x_error_quitter (display, error) } -/* This is the first-level handler for X protocol errors. - It calls x_error_quitter or x_error_catcher. */ - -static int -x_error_handler (display, error) - Display *display; - XErrorEvent *error; -{ - if (! NILP (x_error_message_string)) - x_error_catcher (display, error); - else - x_error_quitter (display, error); - return 0; -} - /* This is the handler for X IO errors, always. It kills all frames on the display that we lost touch with. If that was the only one, it prints an error message and kills Emacs. */ @@ -7888,7 +7838,8 @@ x_new_font (f, fontname) FRAME_BASELINE_OFFSET (f) = fontp->baseline_offset; FRAME_FONTSET (f) = -1; - FRAME_COLUMN_WIDTH (f) = FONT_WIDTH (FRAME_FONT (f)); + FRAME_COLUMN_WIDTH (f) = fontp->average_width; + FRAME_SPACE_WIDTH (f) = fontp->space_width; FRAME_LINE_HEIGHT (f) = FONT_HEIGHT (FRAME_FONT (f)); compute_fringe_widths (f, 1); @@ -7996,11 +7947,7 @@ xim_destroy_callback (xim, client_data, call_data) if (FRAME_X_DISPLAY_INFO (f) == dpyinfo) { FRAME_XIC (f) = NULL; - if (FRAME_XIC_FONTSET (f)) - { - XFreeFontSet (FRAME_X_DISPLAY (f), FRAME_XIC_FONTSET (f)); - FRAME_XIC_FONTSET (f) = NULL; - } + xic_free_xfontset (f); } } @@ -8193,70 +8140,19 @@ void 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 - 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; - } - /* 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 - - FRAME_PIXEL_WIDTH (f) - + f->left_pos); + - FRAME_PIXEL_WIDTH (f) + f->left_pos); { int height = FRAME_PIXEL_HEIGHT (f); @@ -8278,11 +8174,7 @@ x_calc_absolute_position (f) #endif if (flags & YNegative) - f->top_pos = (FRAME_X_DISPLAY_INFO (f)->height - - 2 * f->border_width - - win_y - - height - + f->top_pos); + f->top_pos = (FRAME_X_DISPLAY_INFO (f)->height - height + f->top_pos); } /* The left_pos and top_pos @@ -8317,24 +8209,13 @@ x_set_offset (f, xoff, yoff, change_gravity) 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 @@ -8409,7 +8290,9 @@ x_check_expected_move (f) FRAME_X_OUTPUT (f)->move_offset_left = expect_left - f->left_pos; FRAME_X_OUTPUT (f)->move_offset_top = expect_top - f->top_pos; - x_set_offset (f, expect_left, expect_top, 1); + f->left_pos = expect_left; + f->top_pos = expect_top; + x_set_offset (f, expect_left, expect_top, 0); } else if (FRAME_X_DISPLAY_INFO (f)->wm_type == X_WMTYPE_UNKNOWN) FRAME_X_DISPLAY_INFO (f)->wm_type = X_WMTYPE_B; @@ -9442,11 +9325,11 @@ x_list_fonts (f, pattern, size, maxnames) Display *dpy = dpyinfo->display; int try_XLoadQueryFont = 0; int count; - int allow_scalable_fonts_p = 0; + int allow_auto_scaled_font = 0; if (size < 0) { - allow_scalable_fonts_p = 1; + allow_auto_scaled_font = 1; size = 0; } @@ -9469,7 +9352,7 @@ x_list_fonts (f, pattern, size, maxnames) ((((PATTERN . MAXNAMES) . SCALABLE) (FONTNAME . WIDTH) ...) ...) */ tem = XCDR (dpyinfo->name_list_element); key = Fcons (Fcons (pattern, make_number (maxnames)), - allow_scalable_fonts_p ? Qt : Qnil); + allow_auto_scaled_font ? Qt : Qnil); list = Fassoc (key, tem); if (!NILP (list)) { @@ -9575,25 +9458,28 @@ x_list_fonts (f, pattern, size, maxnames) { int width = 0; char *p = names[i]; - int average_width = -1, dashes = 0; + int average_width = -1, resx = 0, dashes = 0; /* Count the number of dashes in NAMES[I]. If there are - 14 dashes, and the field value following 12th dash - (AVERAGE_WIDTH) is 0, this is a auto-scaled font which - is usually too ugly to be used for editing. Let's - ignore it. */ + 14 dashes, the field value following 9th dash + (RESOLUTION_X) is nonzero, and the field value + following 12th dash (AVERAGE_WIDTH) is 0, this is a + auto-scaled font which is usually too ugly to be used + for editing. Let's ignore it. */ while (*p) if (*p++ == '-') { dashes++; if (dashes == 7) /* PIXEL_SIZE field */ width = atoi (p); + else if (dashes == 9) + resx = atoi (p); else if (dashes == 12) /* AVERAGE_WIDTH field */ average_width = atoi (p); } - if (allow_scalable_fonts_p - || dashes < 14 || average_width != 0) + if (allow_auto_scaled_font + || dashes < 14 || average_width != 0 || resx == 0) { tem = build_string (names[i]); if (NILP (Fassoc (tem, list))) @@ -9897,6 +9783,43 @@ x_load_font (f, fontname, size) fontp->name = (char *) xmalloc (strlen (fontname) + 1); bcopy (fontname, fontp->name, strlen (fontname) + 1); + if (font->min_bounds.width == font->max_bounds.width) + { + /* Fixed width font. */ + fontp->average_width = fontp->space_width = font->min_bounds.width; + } + else + { + XChar2b char2b; + XCharStruct *pcm; + + char2b.byte1 = 0x00, char2b.byte2 = 0x20; + pcm = x_per_char_metric (font, &char2b, 0); + if (pcm) + fontp->space_width = pcm->width; + else + fontp->space_width = FONT_WIDTH (font); + + fontp->average_width + = (XGetFontProperty (font, dpyinfo->Xatom_AVERAGE_WIDTH, &value) + ? (long) value / 10 : 0); + if (fontp->average_width < 0) + fontp->average_width = - fontp->average_width; + if (fontp->average_width == 0) + { + if (pcm) + { + int width = pcm->width; + for (char2b.byte2 = 33; char2b.byte2 <= 126; char2b.byte2++) + if ((pcm = x_per_char_metric (font, &char2b, 0)) != NULL) + width += pcm->width; + fontp->average_width = width / 95; + } + else + fontp->average_width = FONT_WIDTH (font); + } + } + /* Try to get the full name of FONT. Put it in FULL_NAME. */ full_name = 0; if (XGetFontProperty (font, XA_FONT, &value)) @@ -10201,60 +10124,65 @@ x_term_init (display_name, xrm_option, resource_name) char **argv2 = argv; GdkAtom atom; - /* GTK 2.0 can only handle one display, GTK 2.2 can handle more - than one, but this remains to be implemented. */ - if (x_initialized > 1) - error ("Sorry, the GTK port can only handle one display."); - ++x_initialized; - - for (argc = 0; argc < NUM_ARGV; ++argc) - argv[argc] = 0; + if (x_initialized++ > 1) + { + /* Opening another display. If xg_display_open returns less + than zero, we are probably on GTK 2.0, which can only handle + one display. GTK 2.2 or later can handle more than one. */ + if (xg_display_open (SDATA (display_name), &dpy) < 0) + error ("Sorry, this version of GTK can only handle one display"); + } + else + { + for (argc = 0; argc < NUM_ARGV; ++argc) + argv[argc] = 0; - argc = 0; - argv[argc++] = initial_argv[0]; + argc = 0; + argv[argc++] = initial_argv[0]; - if (! NILP (display_name)) - { - argv[argc++] = "--display"; - argv[argc++] = SDATA (display_name); - } + if (! NILP (display_name)) + { + argv[argc++] = "--display"; + argv[argc++] = SDATA (display_name); + } - argv[argc++] = "--name"; - argv[argc++] = resource_name; + argv[argc++] = "--name"; + argv[argc++] = resource_name; #ifdef HAVE_X11R5 - XSetLocaleModifiers (""); + XSetLocaleModifiers (""); #endif - gtk_init (&argc, &argv2); + gtk_init (&argc, &argv2); - /* gtk_init does set_locale. We must fix locale after calling it. */ - fixup_locale (); - xg_initialize (); + /* gtk_init does set_locale. We must fix locale after calling it. */ + fixup_locale (); + xg_initialize (); - dpy = GDK_DISPLAY (); + dpy = GDK_DISPLAY (); - /* NULL window -> events for all windows go to our function */ - gdk_window_add_filter (NULL, event_handler_gdk, NULL); + /* NULL window -> events for all windows go to our function */ + gdk_window_add_filter (NULL, event_handler_gdk, NULL); - /* Load our own gtkrc if it exists. */ - { - struct gcpro gcpro1, gcpro2; - char *file = "~/.emacs.d/gtkrc"; - Lisp_Object s, abs_file; + /* Load our own gtkrc if it exists. */ + { + struct gcpro gcpro1, gcpro2; + char *file = "~/.emacs.d/gtkrc"; + Lisp_Object s, abs_file; - GCPRO2 (s, abs_file); - s = make_string (file, strlen (file)); - abs_file = Fexpand_file_name(s, Qnil); + GCPRO2 (s, abs_file); + s = make_string (file, strlen (file)); + abs_file = Fexpand_file_name (s, Qnil); - if (! NILP (abs_file) && !NILP (Ffile_readable_p (abs_file))) - gtk_rc_parse (SDATA (abs_file)); + if (! NILP (abs_file) && !NILP (Ffile_readable_p (abs_file))) + gtk_rc_parse (SDATA (abs_file)); - UNGCPRO; - } + UNGCPRO; + } - XSetErrorHandler (x_error_handler); - XSetIOErrorHandler (x_io_error_quitter); + XSetErrorHandler (x_error_handler); + XSetIOErrorHandler (x_io_error_quitter); + } } #else /* not USE_GTK */ #ifdef USE_X_TOOLKIT @@ -10375,6 +10303,11 @@ x_term_init (display_name, xrm_option, resource_name) x_find_modifier_meanings (dpyinfo); /* Get the scroll bar cursor. */ +#ifdef USE_GTK + /* We must create a GTK cursor, it is required for GTK widgets. */ + dpyinfo->xg_cursor = xg_create_default_cursor (dpyinfo->display); +#endif /* USE_GTK */ + dpyinfo->vertical_scroll_bar_cursor = XCreateFontCursor (dpyinfo->display, XC_sb_v_double_arrow); @@ -10436,7 +10369,7 @@ x_term_init (display_name, xrm_option, resource_name) 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)) { @@ -10461,10 +10394,12 @@ x_term_init (display_name, xrm_option, resource_name) int screen_number = XScreenNumberOfScreen (dpyinfo->screen); double pixels = DisplayHeight (dpyinfo->display, screen_number); double mm = DisplayHeightMM (dpyinfo->display, screen_number); - dpyinfo->resy = pixels * 25.4 / mm; + /* Mac OS X 10.3's Xserver sometimes reports 0.0mm. */ + dpyinfo->resy = (mm < 1) ? 100 : pixels * 25.4 / mm; pixels = DisplayWidth (dpyinfo->display, screen_number); + /* Mac OS X 10.3's Xserver sometimes reports 0.0mm. */ mm = DisplayWidthMM (dpyinfo->display, screen_number); - dpyinfo->resx = pixels * 25.4 / mm; + dpyinfo->resx = (mm < 1) ? 100 : pixels * 25.4 / mm; } dpyinfo->Xatom_wm_protocols @@ -10512,6 +10447,8 @@ x_term_init (display_name, xrm_option, resource_name) /* For properties of font. */ dpyinfo->Xatom_PIXEL_SIZE = XInternAtom (dpyinfo->display, "PIXEL_SIZE", False); + dpyinfo->Xatom_AVERAGE_WIDTH + = XInternAtom (dpyinfo->display, "AVERAGE_WIDTH", False); dpyinfo->Xatom_MULE_BASELINE_OFFSET = XInternAtom (dpyinfo->display, "_MULE_BASELINE_OFFSET", False); dpyinfo->Xatom_MULE_RELATIVE_COMPOSE @@ -10766,7 +10703,7 @@ static struct redisplay_interface x_redisplay_interface = x_update_window_end, x_cursor_to, x_flush, -#ifndef XFlush +#ifdef XFlush x_flush, #else 0, /* flush_display_optional */ @@ -10775,6 +10712,8 @@ static struct redisplay_interface x_redisplay_interface = 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, @@ -10821,6 +10760,11 @@ x_initialize () 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); @@ -10904,6 +10848,16 @@ UNDERLINE_POSITION font properties, for example 7x13 on XFree prior 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.