diff options
Diffstat (limited to 'src/xterm.c')
-rw-r--r-- | src/xterm.c | 404 |
1 files changed, 271 insertions, 133 deletions
diff --git a/src/xterm.c b/src/xterm.c index 213a527d55d..67bd13a042f 100644 --- a/src/xterm.c +++ b/src/xterm.c @@ -22,6 +22,7 @@ along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>. */ #include <config.h> #include <stdio.h> +#include <stdlib.h> #ifdef USE_CAIRO #include <math.h> #endif @@ -44,6 +45,10 @@ along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>. */ #include <X11/extensions/Xrender.h> #endif +#ifdef HAVE_XDBE +#include <X11/extensions/Xdbe.h> +#endif + /* Load sys/types.h if not already loaded. In some systems loading it twice is suicidal. */ #ifndef makedev @@ -95,10 +100,6 @@ along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>. */ #endif #ifdef USE_X_TOOLKIT -#if !defined (NO_EDITRES) -#define HACK_EDITRES -extern void _XEditResCheckMessages (Widget, XtPointer, XEvent *, Boolean *); -#endif /* not NO_EDITRES */ /* Include toolkit specific headers for the scroll bar widget. */ @@ -363,7 +364,7 @@ x_begin_cr_clip (struct frame *f, GC gc) { cairo_surface_t *surface; surface = cairo_xlib_surface_create (FRAME_X_DISPLAY (f), - FRAME_X_WINDOW (f), + FRAME_X_DRAWABLE (f), FRAME_DISPLAY_INFO (f)->visual, FRAME_PIXEL_WIDTH (f), FRAME_PIXEL_HEIGHT (f)); @@ -725,7 +726,7 @@ x_fill_rectangle (struct frame *f, GC gc, int x, int y, int width, int height) cairo_fill (cr); x_end_cr_clip (f); #else - XFillRectangle (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f), + XFillRectangle (FRAME_X_DISPLAY (f), FRAME_X_DRAWABLE (f), gc, x, y, width, height); #endif } @@ -743,7 +744,7 @@ x_draw_rectangle (struct frame *f, GC gc, int x, int y, int width, int height) cairo_stroke (cr); x_end_cr_clip (f); #else - XDrawRectangle (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f), + XDrawRectangle (FRAME_X_DISPLAY (f), FRAME_X_DRAWABLE (f), gc, x, y, width, height); #endif } @@ -759,7 +760,10 @@ x_clear_window (struct frame *f) cairo_paint (cr); x_end_cr_clip (f); #else - XClearWindow (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f)); + if (FRAME_X_DOUBLE_BUFFERED_P (f)) + x_clear_area (f, 0, 0, FRAME_PIXEL_WIDTH (f), FRAME_PIXEL_HEIGHT (f)); + else + XClearWindow (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f)); #endif } @@ -1062,7 +1066,7 @@ x_draw_vertical_window_border (struct window *w, int x, int y0, int y1) struct frame *f = XFRAME (WINDOW_FRAME (w)); struct face *face; - face = FACE_FROM_ID (f, VERTICAL_BORDER_FACE_ID); + face = FACE_FROM_ID_OR_NULL (f, VERTICAL_BORDER_FACE_ID); if (face) XSetForeground (FRAME_X_DISPLAY (f), f->output_data.x->normal_gc, face->foreground); @@ -1070,7 +1074,7 @@ x_draw_vertical_window_border (struct window *w, int x, int y0, int y1) #ifdef USE_CAIRO x_fill_rectangle (f, f->output_data.x->normal_gc, x, y0, 1, y1 - y0); #else - XDrawLine (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f), + XDrawLine (FRAME_X_DISPLAY (f), FRAME_X_DRAWABLE (f), f->output_data.x->normal_gc, x, y0, x, y1); #endif } @@ -1081,9 +1085,11 @@ static void x_draw_window_divider (struct window *w, int x0, int x1, int y0, int y1) { struct frame *f = XFRAME (WINDOW_FRAME (w)); - struct face *face = FACE_FROM_ID (f, WINDOW_DIVIDER_FACE_ID); - struct face *face_first = FACE_FROM_ID (f, WINDOW_DIVIDER_FIRST_PIXEL_FACE_ID); - struct face *face_last = FACE_FROM_ID (f, WINDOW_DIVIDER_LAST_PIXEL_FACE_ID); + struct face *face = FACE_FROM_ID_OR_NULL (f, WINDOW_DIVIDER_FACE_ID); + struct face *face_first + = FACE_FROM_ID_OR_NULL (f, WINDOW_DIVIDER_FIRST_PIXEL_FACE_ID); + struct face *face_last + = FACE_FROM_ID_OR_NULL (f, WINDOW_DIVIDER_LAST_PIXEL_FACE_ID); unsigned long color = face ? face->foreground : FRAME_FOREGROUND_PIXEL (f); unsigned long color_first = (face_first ? face_first->foreground @@ -1176,6 +1182,41 @@ x_update_window_end (struct window *w, bool cursor_on_p, } } +/* Show the frame back buffer. If frame is double-buffered, + atomically publish to the user's screen graphics updates made since + the last call to show_back_buffer. */ +static void +show_back_buffer (struct frame *f) +{ + block_input (); + if (FRAME_X_DOUBLE_BUFFERED_P (f)) + { +#ifdef HAVE_XDBE + XdbeSwapInfo swap_info; + memset (&swap_info, 0, sizeof (swap_info)); + swap_info.swap_window = FRAME_X_WINDOW (f); + swap_info.swap_action = XdbeCopied; + XdbeSwapBuffers (FRAME_X_DISPLAY (f), &swap_info, 1); +#else + eassert (!"should have back-buffer only with XDBE"); +#endif + } + FRAME_X_NEED_BUFFER_FLIP (f) = false; + unblock_input (); +} + +/* Updates back buffer and flushes changes to display. Called from + minibuf read code. Note that we display the back buffer even if + buffer flipping is blocked. */ +static void +x_flip_and_flush (struct frame *f) +{ + block_input (); + if (FRAME_X_NEED_BUFFER_FLIP (f)) + show_back_buffer (f); + x_flush (f); + unblock_input (); +} /* End update of frame F. This function is installed as a hook in update_end. */ @@ -1208,7 +1249,7 @@ x_update_end (struct frame *f) if (! FRAME_EXTERNAL_MENU_BAR (f)) height += FRAME_MENU_BAR_HEIGHT (f); surface = cairo_xlib_surface_create (FRAME_X_DISPLAY (f), - FRAME_X_WINDOW (f), + FRAME_X_DRAWABLE (f), FRAME_DISPLAY_INFO (f)->visual, width, height); @@ -1221,7 +1262,7 @@ x_update_end (struct frame *f) cairo_destroy (cr); unblock_input (); } -#endif /* USE_CAIRO */ +#endif #ifndef XFlush block_input (); @@ -1230,17 +1271,26 @@ x_update_end (struct frame *f) #endif } - /* This function is called from various places in xdisp.c whenever a complete update has been performed. */ static void XTframe_up_to_date (struct frame *f) { - if (FRAME_X_P (f)) - FRAME_MOUSE_UPDATE (f); + eassert (FRAME_X_P (f)); + block_input (); + FRAME_MOUSE_UPDATE (f); + if (!buffer_flipping_blocked_p () && FRAME_X_NEED_BUFFER_FLIP (f)) + show_back_buffer (f); + unblock_input (); } +static void +XTbuffer_flipping_unblocked_hook (struct frame *f) +{ + if (FRAME_X_NEED_BUFFER_FLIP (f)) + show_back_buffer (f); +} /* Clear under internal border if any (GTK has its own version). */ #ifndef USE_GTK @@ -1355,7 +1405,7 @@ x_draw_fringe_bitmap (struct window *w, struct glyph_row *row, struct draw_fring #else /* not USE_CAIRO */ if (p->which) { - Window window = FRAME_X_WINDOW (f); + Drawable drawable = FRAME_X_DRAWABLE (f); char *bits; Pixmap pixmap, clipmask = (Pixmap) 0; int depth = DefaultDepthOfScreen (FRAME_X_SCREEN (f)); @@ -1368,7 +1418,7 @@ x_draw_fringe_bitmap (struct window *w, struct glyph_row *row, struct draw_fring /* Draw the bitmap. I believe these small pixmaps can be cached by the server. */ - pixmap = XCreatePixmapFromBitmapData (display, window, bits, p->wd, p->h, + pixmap = XCreatePixmapFromBitmapData (display, drawable, bits, p->wd, p->h, (p->cursor_p ? (p->overlay_p ? face->background : f->output_data.x->cursor_pixel) @@ -1387,7 +1437,7 @@ x_draw_fringe_bitmap (struct window *w, struct glyph_row *row, struct draw_fring XChangeGC (display, gc, GCClipMask | GCClipXOrigin | GCClipYOrigin, &gcv); } - XCopyArea (display, pixmap, window, gc, 0, 0, + XCopyArea (display, pixmap, drawable, gc, 0, 0, p->wd, p->h, p->x, p->y); XFreePixmap (display, pixmap); @@ -1488,7 +1538,7 @@ x_set_cursor_gc (struct glyph_string *s) mask, &xgcv); else FRAME_DISPLAY_INFO (s->f)->scratch_cursor_gc - = XCreateGC (s->display, s->window, mask, &xgcv); + = XCreateGC (s->display, FRAME_X_DRAWABLE (s->f), mask, &xgcv); s->gc = FRAME_DISPLAY_INFO (s->f)->scratch_cursor_gc; } @@ -1505,7 +1555,7 @@ x_set_mouse_face_gc (struct glyph_string *s) /* What face has to be used last for the mouse face? */ face_id = MOUSE_HL_INFO (s->f)->mouse_face_face_id; - face = FACE_FROM_ID (s->f, face_id); + face = FACE_FROM_ID_OR_NULL (s->f, face_id); if (face == NULL) face = FACE_FROM_ID (s->f, MOUSE_FACE_ID); @@ -1535,7 +1585,7 @@ x_set_mouse_face_gc (struct glyph_string *s) mask, &xgcv); else FRAME_DISPLAY_INFO (s->f)->scratch_cursor_gc - = XCreateGC (s->display, s->window, mask, &xgcv); + = XCreateGC (s->display, FRAME_X_DRAWABLE (s->f), mask, &xgcv); s->gc = FRAME_DISPLAY_INFO (s->f)->scratch_cursor_gc; @@ -2156,6 +2206,7 @@ static const XColor * x_color_cells (Display *dpy, int *ncells) { struct x_display_info *dpyinfo = x_display_info_for_display (dpy); + eassume (dpyinfo); if (dpyinfo->color_cells == NULL) { @@ -2352,17 +2403,19 @@ x_alloc_nearest_color_1 (Display *dpy, Colormap cmap, XColor *color) equal to a cached pixel color recorded earlier, there was a change in the colormap, so clear the color cache. */ struct x_display_info *dpyinfo = x_display_info_for_display (dpy); - XColor *cached_color; + eassume (dpyinfo); - if (dpyinfo->color_cells - && (cached_color = &dpyinfo->color_cells[color->pixel], - (cached_color->red != color->red - || cached_color->blue != color->blue - || cached_color->green != color->green))) + if (dpyinfo->color_cells) { - xfree (dpyinfo->color_cells); - dpyinfo->color_cells = NULL; - dpyinfo->ncolor_cells = 0; + XColor *cached_color = &dpyinfo->color_cells[color->pixel]; + if (cached_color->red != color->red + || cached_color->blue != color->blue + || cached_color->green != color->green) + { + xfree (dpyinfo->color_cells); + dpyinfo->color_cells = NULL; + dpyinfo->ncolor_cells = 0; + } } } @@ -2563,7 +2616,7 @@ x_setup_relief_color (struct frame *f, struct relief *relief, double factor, { xgcv.stipple = dpyinfo->gray; mask |= GCStipple; - relief->gc = XCreateGC (dpy, FRAME_X_WINDOW (f), mask, &xgcv); + relief->gc = XCreateGC (dpy, FRAME_X_DRAWABLE (f), mask, &xgcv); } else XChangeGC (dpy, relief->gc, mask, &xgcv); @@ -2694,7 +2747,7 @@ x_draw_relief_rect (struct frame *f, x_reset_clip_rectangles (f, bottom_right_gc); #else Display *dpy = FRAME_X_DISPLAY (f); - Window window = FRAME_X_WINDOW (f); + Drawable drawable = FRAME_X_DRAWABLE (f); int i; GC gc; @@ -2713,12 +2766,12 @@ x_draw_relief_rect (struct frame *f, if (top_p) { if (width == 1) - XDrawLine (dpy, window, gc, + XDrawLine (dpy, drawable, gc, left_x + left_p, top_y, right_x + !right_p, top_y); for (i = 1; i < width; ++i) - XDrawLine (dpy, window, gc, + XDrawLine (dpy, drawable, gc, left_x + i * left_p, top_y + i, right_x + 1 - i * right_p, top_y + i); } @@ -2727,13 +2780,13 @@ x_draw_relief_rect (struct frame *f, if (left_p) { if (width == 1) - XDrawLine (dpy, window, gc, left_x, top_y + 1, left_x, bottom_y); + XDrawLine (dpy, drawable, gc, left_x, top_y + 1, left_x, bottom_y); - XClearArea (dpy, window, left_x, top_y, 1, 1, False); - XClearArea (dpy, window, left_x, bottom_y, 1, 1, False); + x_clear_area(f, left_x, top_y, 1, 1); + x_clear_area(f, left_x, bottom_y, 1, 1); for (i = (width > 1 ? 1 : 0); i < width; ++i) - XDrawLine (dpy, window, gc, + XDrawLine (dpy, drawable, gc, left_x + i, top_y + (i + 1) * top_p, left_x + i, bottom_y + 1 - (i + 1) * bot_p); } @@ -2749,23 +2802,23 @@ x_draw_relief_rect (struct frame *f, { /* Outermost top line. */ if (top_p) - XDrawLine (dpy, window, gc, + XDrawLine (dpy, drawable, gc, left_x + left_p, top_y, right_x + !right_p, top_y); /* Outermost left line. */ if (left_p) - XDrawLine (dpy, window, gc, left_x, top_y + 1, left_x, bottom_y); + XDrawLine (dpy, drawable, gc, left_x, top_y + 1, left_x, bottom_y); } /* Bottom. */ if (bot_p) { - XDrawLine (dpy, window, gc, + XDrawLine (dpy, drawable, gc, left_x + left_p, bottom_y, right_x + !right_p, bottom_y); for (i = 1; i < width; ++i) - XDrawLine (dpy, window, gc, + XDrawLine (dpy, drawable, gc, left_x + i * left_p, bottom_y - i, right_x + 1 - i * right_p, bottom_y - i); } @@ -2773,10 +2826,10 @@ x_draw_relief_rect (struct frame *f, /* Right. */ if (right_p) { - XClearArea (dpy, window, right_x, top_y, 1, 1, False); - XClearArea (dpy, window, right_x, bottom_y, 1, 1, False); + x_clear_area(f, right_x, top_y, 1, 1); + x_clear_area(f, right_x, bottom_y, 1, 1); for (i = 0; i < width; ++i) - XDrawLine (dpy, window, gc, + XDrawLine (dpy, drawable, gc, right_x - i, top_y + (i + 1) * top_p, right_x - i, bottom_y + 1 - (i + 1) * bot_p); } @@ -2928,7 +2981,8 @@ x_draw_image_foreground (struct glyph_string *s) 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, + XCopyArea (s->display, s->img->pixmap, + FRAME_X_DRAWABLE (s->f), s->gc, s->slice.x + r.x - x, s->slice.y + r.y - y, r.width, r.height, r.x, r.y); } @@ -2942,7 +2996,8 @@ x_draw_image_foreground (struct glyph_string *s) 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, + XCopyArea (s->display, s->img->pixmap, + FRAME_X_DRAWABLE (s->f), s->gc, s->slice.x + r.x - x, s->slice.y + r.y - y, r.width, r.height, r.x, r.y); @@ -3182,7 +3237,7 @@ x_draw_image_glyph_string (struct glyph_string *s) int depth = DefaultDepthOfScreen (screen); /* Create a pixmap as large as the glyph string. */ - pixmap = XCreatePixmap (s->display, s->window, + pixmap = XCreatePixmap (s->display, FRAME_X_DRAWABLE (s->f), s->background_width, s->height, depth); @@ -3257,7 +3312,7 @@ x_draw_image_glyph_string (struct glyph_string *s) { x_draw_image_foreground_1 (s, pixmap); x_set_glyph_string_clipping (s); - XCopyArea (s->display, pixmap, s->window, s->gc, + XCopyArea (s->display, pixmap, FRAME_X_DRAWABLE (s->f), s->gc, 0, 0, s->background_width, s->height, s->x, s->y); XFreePixmap (s->display, pixmap); } @@ -3436,7 +3491,7 @@ x_draw_underwave (struct glyph_string *s) while (x1 <= xmax) { - XDrawLine (s->display, s->window, s->gc, x1, y1, x2, y2); + XDrawLine (s->display, FRAME_X_DRAWABLE (s->f), s->gc, x1, y1, x2, y2); x1 = x2, y1 = y2; x2 += dx, y2 = y0 + odd*dy; odd = !odd; @@ -3739,7 +3794,7 @@ x_shift_glyphs_for_insert (struct frame *f, int x, int y, int width, int height, /* Never called on a GUI frame, see http://lists.gnu.org/archive/html/emacs-devel/2015-05/msg00456.html */ - XCopyArea (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f), FRAME_X_WINDOW (f), + XCopyArea (FRAME_X_DISPLAY (f), FRAME_X_DRAWABLE (f), FRAME_X_DRAWABLE (f), f->output_data.x->normal_gc, x, y, width, height, x + shift_by, y); @@ -3780,8 +3835,14 @@ x_clear_area (struct frame *f, int x, int y, int width, int height) cairo_fill (cr); x_end_cr_clip (f); #else - x_clear_area1 (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f), - x, y, width, height, False); + if (FRAME_X_DOUBLE_BUFFERED_P (f)) + XFillRectangle (FRAME_X_DISPLAY (f), + FRAME_X_DRAWABLE (f), + f->output_data.x->reverse_gc, + x, y, width, height); + else + x_clear_area1 (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f), + x, y, width, height, False); #endif } @@ -3797,19 +3858,13 @@ x_clear_frame (struct frame *f) block_input (); + font_drop_xrender_surfaces (f); x_clear_window (f); /* We have to clear the scroll bars. If we have changed colors or something like that, then they should be notified. */ x_scroll_bar_clear (f); -#if defined (USE_GTK) && defined (USE_TOOLKIT_SCROLL_BARS) - /* Make sure scroll bars are redrawn. As they aren't redrawn by - redisplay, do it here. */ - if (FRAME_GTK_WIDGET (f)) - gtk_widget_queue_draw (FRAME_GTK_WIDGET (f)); -#endif - XFlush (FRAME_X_DISPLAY (f)); unblock_input (); @@ -4107,7 +4162,7 @@ x_scroll_run (struct window *w, struct run *run) SET_FRAME_GARBAGED (f); #else XCopyArea (FRAME_X_DISPLAY (f), - FRAME_X_WINDOW (f), FRAME_X_WINDOW (f), + FRAME_X_DRAWABLE (f), FRAME_X_DRAWABLE (f), f->output_data.x->normal_gc, x, from_y, width, height, @@ -4646,12 +4701,15 @@ x_find_modifier_meanings (struct x_display_info *dpyinfo) int x_x_to_emacs_modifiers (struct x_display_info *dpyinfo, int state) { + int mod_ctrl = ctrl_modifier; int mod_meta = meta_modifier; int mod_alt = alt_modifier; int mod_hyper = hyper_modifier; int mod_super = super_modifier; Lisp_Object tem; + tem = Fget (Vx_ctrl_keysym, Qmodifier_value); + if (INTEGERP (tem)) mod_ctrl = XINT (tem) & INT_MAX; tem = Fget (Vx_alt_keysym, Qmodifier_value); if (INTEGERP (tem)) mod_alt = XINT (tem) & INT_MAX; tem = Fget (Vx_meta_keysym, Qmodifier_value); @@ -4662,7 +4720,7 @@ x_x_to_emacs_modifiers (struct x_display_info *dpyinfo, int state) if (INTEGERP (tem)) mod_super = XINT (tem) & INT_MAX; return ( ((state & (ShiftMask | dpyinfo->shift_lock_mask)) ? shift_modifier : 0) - | ((state & ControlMask) ? ctrl_modifier : 0) + | ((state & ControlMask) ? mod_ctrl : 0) | ((state & dpyinfo->meta_mod_mask) ? mod_meta : 0) | ((state & dpyinfo->alt_mod_mask) ? mod_alt : 0) | ((state & dpyinfo->super_mod_mask) ? mod_super : 0) @@ -4672,6 +4730,7 @@ x_x_to_emacs_modifiers (struct x_display_info *dpyinfo, int state) static int x_emacs_to_x_modifiers (struct x_display_info *dpyinfo, EMACS_INT state) { + EMACS_INT mod_ctrl = ctrl_modifier; EMACS_INT mod_meta = meta_modifier; EMACS_INT mod_alt = alt_modifier; EMACS_INT mod_hyper = hyper_modifier; @@ -4679,6 +4738,8 @@ x_emacs_to_x_modifiers (struct x_display_info *dpyinfo, EMACS_INT state) Lisp_Object tem; + tem = Fget (Vx_ctrl_keysym, Qmodifier_value); + if (INTEGERP (tem)) mod_ctrl = XINT (tem); tem = Fget (Vx_alt_keysym, Qmodifier_value); if (INTEGERP (tem)) mod_alt = XINT (tem); tem = Fget (Vx_meta_keysym, Qmodifier_value); @@ -4693,7 +4754,7 @@ x_emacs_to_x_modifiers (struct x_display_info *dpyinfo, EMACS_INT state) | ((state & mod_super) ? dpyinfo->super_mod_mask : 0) | ((state & mod_hyper) ? dpyinfo->hyper_mod_mask : 0) | ((state & shift_modifier) ? ShiftMask : 0) - | ((state & ctrl_modifier) ? ControlMask : 0) + | ((state & mod_ctrl) ? ControlMask : 0) | ((state & mod_meta) ? dpyinfo->meta_mod_mask : 0)); } @@ -5244,9 +5305,8 @@ x_send_scroll_bar_event (Lisp_Object window, enum scroll_bar_part part, struct window *w = XWINDOW (window); struct frame *f = XFRAME (w->frame); intptr_t iw = (intptr_t) w; - enum { BITS_PER_INTPTR = CHAR_BIT * sizeof iw }; - verify (BITS_PER_INTPTR <= 64); - int sign_shift = BITS_PER_INTPTR - 32; + verify (INTPTR_WIDTH <= 64); + int sign_shift = INTPTR_WIDTH - 32; block_input (); @@ -7447,6 +7507,26 @@ x_net_wm_state (struct frame *f, Window window) /** store_frame_param (f, Qsticky, sticky ? Qt : Qnil); **/ } +/* Flip back buffers on any frames with undrawn content. */ +static void +flush_dirty_back_buffers (void) +{ + block_input (); + Lisp_Object tail, frame; + FOR_EACH_FRAME (tail, frame) + { + struct frame *f = XFRAME (frame); + if (FRAME_LIVE_P (f) && + FRAME_X_P (f) && + FRAME_X_WINDOW (f) && + !FRAME_GARBAGED_P (f) && + !buffer_flipping_blocked_p () && + FRAME_X_NEED_BUFFER_FLIP (f)) + show_back_buffer (f); + } + unblock_input (); +} + /* Handles the XEvent EVENT on display DPYINFO. *FINISH is X_EVENT_GOTO_OUT if caller should stop reading events. @@ -7605,7 +7685,7 @@ handle_one_xevent (struct x_display_info *dpyinfo, goto done; } -#ifdef HACK_EDITRES +#ifdef X_TOOLKIT_EDITRES if (event->xclient.message_type == dpyinfo->Xatom_editres) { f = any; @@ -7614,7 +7694,7 @@ handle_one_xevent (struct x_display_info *dpyinfo, NULL, (XEvent *) event, NULL); goto done; } -#endif /* HACK_EDITRES */ +#endif /* X_TOOLKIT_EDITRES */ if (event->xclient.message_type == dpyinfo->Xatom_DONE || event->xclient.message_type == dpyinfo->Xatom_PAGE) @@ -7765,23 +7845,49 @@ handle_one_xevent (struct x_display_info *dpyinfo, { if (!FRAME_VISIBLE_P (f)) { + block_input (); SET_FRAME_VISIBLE (f, 1); SET_FRAME_ICONIFIED (f, false); + if (FRAME_X_DOUBLE_BUFFERED_P (f)) + font_drop_xrender_surfaces (f); f->output_data.x->has_been_visible = true; SET_FRAME_GARBAGED (f); + unblock_input (); } - else - { + else if (FRAME_GARBAGED_P (f)) + { #ifdef USE_GTK - /* This seems to be needed for GTK 2.6 and later, see - http://debbugs.gnu.org/cgi/bugreport.cgi?bug=15398. */ - x_clear_area (f, - event->xexpose.x, event->xexpose.y, - event->xexpose.width, event->xexpose.height); + /* Go around the back buffer and manually clear the + window the first time we show it. This way, we avoid + showing users the sanity-defying horror of whatever + GtkWindow is rendering beneath us. We've garbaged + the frame, so we'll redraw the whole thing on next + redisplay anyway. Yuck. */ + x_clear_area1 ( + FRAME_X_DISPLAY (f), + FRAME_X_WINDOW (f), + event->xexpose.x, event->xexpose.y, + event->xexpose.width, event->xexpose.height, + 0); +#endif + } + + + if (!FRAME_GARBAGED_P (f)) + { +#ifdef USE_GTK + /* This seems to be needed for GTK 2.6 and later, see + http://debbugs.gnu.org/cgi/bugreport.cgi?bug=15398. */ + x_clear_area (f, + event->xexpose.x, event->xexpose.y, + event->xexpose.width, event->xexpose.height); #endif - expose_frame (f, event->xexpose.x, event->xexpose.y, + expose_frame (f, event->xexpose.x, event->xexpose.y, event->xexpose.width, event->xexpose.height); - } + } + + if (!FRAME_GARBAGED_P (f)) + show_back_buffer (f); } else { @@ -7821,10 +7927,13 @@ handle_one_xevent (struct x_display_info *dpyinfo, available. */ f = x_window_to_frame (dpyinfo, event->xgraphicsexpose.drawable); if (f) - expose_frame (f, event->xgraphicsexpose.x, - event->xgraphicsexpose.y, - event->xgraphicsexpose.width, - event->xgraphicsexpose.height); + { + expose_frame (f, event->xgraphicsexpose.x, + event->xgraphicsexpose.y, + event->xgraphicsexpose.width, + event->xgraphicsexpose.height); + show_back_buffer (f); + } #ifdef USE_X_TOOLKIT else goto OTHER; @@ -7895,16 +8004,6 @@ handle_one_xevent (struct x_display_info *dpyinfo, /* Force a redisplay sooner or later to update the frame titles in case this is the second frame. */ record_asynch_buffer_change (); - -#ifdef USE_GTK - /* xg_frame_resized does the wrong thing with Gtk+ 3.20.3 or later. - For earlier Gtk+ versions it is unclear whether - xg_frame_resized is useful, so leave it in for now. - See Bug#23144. */ -# if ! GTK_CHECK_VERSION (3, 20, 3) - xg_frame_resized (f, -1, -1); -# endif -#endif } goto OTHER; @@ -8419,7 +8518,17 @@ handle_one_xevent (struct x_display_info *dpyinfo, else configureEvent = next_event; } + f = x_top_window_to_frame (dpyinfo, configureEvent.xconfigure.window); + /* Unfortunately, we need to call font_drop_xrender_surfaces for + _all_ ConfigureNotify events, otherwise we miss some and + flicker. Don't try to optimize these calls by looking only + for size changes: that's not sufficient. We miss some + surface invalidations and flicker. */ + block_input (); + if (f && FRAME_X_DOUBLE_BUFFERED_P (f)) + font_drop_xrender_surfaces (f); + unblock_input (); #ifdef USE_CAIRO if (f) x_cr_destroy_surface (f); #endif @@ -8428,6 +8537,10 @@ handle_one_xevent (struct x_display_info *dpyinfo, && (f = any) && configureEvent.xconfigure.window == FRAME_X_WINDOW (f)) { + block_input (); + if (FRAME_X_DOUBLE_BUFFERED_P (f)) + font_drop_xrender_surfaces (f); + unblock_input (); xg_frame_resized (f, configureEvent.xconfigure.width, configureEvent.xconfigure.height); #ifdef USE_CAIRO @@ -8438,7 +8551,8 @@ handle_one_xevent (struct x_display_info *dpyinfo, #endif if (f) { - x_net_wm_state (f, configureEvent.xconfigure.window); + + x_net_wm_state (f, configureEvent.xconfigure.window); #ifdef USE_X_TOOLKIT /* Tip frames are pure X window, set size for them. */ @@ -8446,7 +8560,9 @@ handle_one_xevent (struct x_display_info *dpyinfo, { if (FRAME_PIXEL_HEIGHT (f) != configureEvent.xconfigure.height || FRAME_PIXEL_WIDTH (f) != configureEvent.xconfigure.width) - SET_FRAME_GARBAGED (f); + { + SET_FRAME_GARBAGED (f); + } FRAME_PIXEL_HEIGHT (f) = configureEvent.xconfigure.height; FRAME_PIXEL_WIDTH (f) = configureEvent.xconfigure.width; } @@ -8472,8 +8588,8 @@ handle_one_xevent (struct x_display_info *dpyinfo, || configureEvent.xconfigure.height != FRAME_PIXEL_HEIGHT (f)) { change_frame_size (f, width, height, false, true, false, true); - x_clear_under_internal_border (f); - SET_FRAME_GARBAGED (f); + x_clear_under_internal_border (f); + SET_FRAME_GARBAGED (f); cancel_mouse_face (f); } #endif /* not USE_GTK */ @@ -8697,6 +8813,9 @@ handle_one_xevent (struct x_display_info *dpyinfo, count++; } + /* Sometimes event processing draws to the frame outside redisplay. + To ensure that these changes become visible, draw them here. */ + flush_dirty_back_buffers (); SAFE_FREE (); return count; } @@ -8889,7 +9008,7 @@ x_draw_hollow_cursor (struct window *w, struct glyph_row *row) if (dpyinfo->scratch_cursor_gc) XChangeGC (dpy, dpyinfo->scratch_cursor_gc, GCForeground, &xgcv); else - dpyinfo->scratch_cursor_gc = XCreateGC (dpy, FRAME_X_WINDOW (f), + dpyinfo->scratch_cursor_gc = XCreateGC (dpy, FRAME_X_DRAWABLE (f), GCForeground, &xgcv); gc = dpyinfo->scratch_cursor_gc; @@ -8946,7 +9065,7 @@ x_draw_bar_cursor (struct window *w, struct glyph_row *row, int width, enum text else { Display *dpy = FRAME_X_DISPLAY (f); - Window window = FRAME_X_WINDOW (f); + Drawable drawable = FRAME_X_DRAWABLE (f); GC gc = FRAME_DISPLAY_INFO (f)->scratch_cursor_gc; unsigned long mask = GCForeground | GCBackground | GCGraphicsExposures; struct face *face = FACE_FROM_ID (f, cursor_glyph->face_id); @@ -8967,7 +9086,7 @@ x_draw_bar_cursor (struct window *w, struct glyph_row *row, int width, enum text XChangeGC (dpy, gc, mask, &xgcv); else { - gc = XCreateGC (dpy, window, mask, &xgcv); + gc = XCreateGC (dpy, drawable, mask, &xgcv); FRAME_DISPLAY_INFO (f)->scratch_cursor_gc = gc; } @@ -9037,11 +9156,6 @@ static void x_clear_frame_area (struct frame *f, int x, int y, int width, int height) { x_clear_area (f, x, y, width, height); -#ifdef USE_GTK - /* Must queue a redraw, because scroll bars might have been cleared. */ - if (FRAME_GTK_WIDGET (f)) - gtk_widget_queue_draw (FRAME_GTK_WIDGET (f)); -#endif } @@ -9398,7 +9512,7 @@ static char *error_msg; /* Handle the loss of connection to display DPY. ERROR_MESSAGE is the text of an error message that lead to the connection loss. */ -static void +static _Noreturn void x_connection_closed (Display *dpy, const char *error_message, bool ioerror) { struct x_display_info *dpyinfo = x_display_info_for_display (dpy); @@ -9496,9 +9610,6 @@ For details, see etc/PROBLEMS.\n", unbind_to (idx, Qnil); clear_waiting_for_input (); - /* Tell GCC not to suggest attribute 'noreturn' for this function. */ - IF_LINT (if (! terminal_list) return; ) - /* Here, we absolutely have to use a non-local exit (e.g. signal, throw, longjmp), because returning from this function would get us back into Xlib's code which will directly call `exit'. */ @@ -9564,7 +9675,7 @@ x_error_quitter (Display *display, XErrorEvent *event) 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. */ -static int +static _Noreturn int x_io_error_quitter (Display *display) { char buf[256]; @@ -9572,7 +9683,7 @@ x_io_error_quitter (Display *display) snprintf (buf, sizeof buf, "Connection lost to X server '%s'", DisplayString (display)); x_connection_closed (display, buf, true); - return 0; + assume (false); } /* Changing the font of the frame. */ @@ -10901,9 +11012,9 @@ x_make_frame_visible (struct frame *f) if (! FRAME_VISIBLE_P (f)) { - /* We test FRAME_GARBAGED_P here to make sure we don't - call x_set_offset a second time - if we get to x_make_frame_visible a second time + /* We test asked_for_visible here to make sure we don't + call x_set_offset a second time + if we get to x_make_frame_visible a second time before the window gets really visible. */ if (! FRAME_ICONIFIED_P (f) && ! FRAME_X_EMBEDDED_P (f) @@ -10947,6 +11058,8 @@ x_make_frame_visible (struct frame *f) will set it when they are handled. */ bool previously_visible = f->output_data.x->has_been_visible; + XSETFRAME (frame, f); + original_left = f->left_pos; original_top = f->top_pos; @@ -10993,8 +11106,6 @@ x_make_frame_visible (struct frame *f) unblock_input (); } - XSETFRAME (frame, f); - /* Process X events until a MapNotify event has been seen. */ while (!FRAME_VISIBLE_P (f)) { @@ -11239,6 +11350,7 @@ x_free_frame_resources (struct frame *f) font-driver (e.g. xft) access a window while finishing a face. */ free_frame_faces (f); + tear_down_x_back_buffer (f); if (f->output_data.x->icon_desc) XDestroyWindow (FRAME_X_DISPLAY (f), f->output_data.x->icon_desc); @@ -11270,7 +11382,7 @@ x_free_frame_resources (struct frame *f) /* Tooltips don't have widgets, only a simple X window, even if we are using a toolkit. */ else if (FRAME_X_WINDOW (f)) - XDestroyWindow (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f)); + XDestroyWindow (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f)); free_frame_menubar (f); @@ -11282,8 +11394,9 @@ x_free_frame_resources (struct frame *f) xg_free_frame_widgets (f); #endif /* USE_GTK */ + tear_down_x_back_buffer (f); if (FRAME_X_WINDOW (f)) - XDestroyWindow (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f)); + XDestroyWindow (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f)); #endif /* !USE_X_TOOLKIT */ unload_color (f, FRAME_FOREGROUND_PIXEL (f)); @@ -12123,7 +12236,15 @@ x_term_init (Lisp_Object display_name, char *xrm_option, char *resource_name) } else dpyinfo->cmap = XCreateColormap (dpyinfo->display, dpyinfo->root_window, - dpyinfo->visual, AllocNone); + dpyinfo->visual, AllocNone); + +#ifdef HAVE_XDBE + dpyinfo->supports_xdbe = false; + int xdbe_major; + int xdbe_minor; + if (XdbeQueryExtension (dpyinfo->display, &xdbe_major, &xdbe_minor)) + dpyinfo->supports_xdbe = true; +#endif #ifdef HAVE_XFT { @@ -12474,7 +12595,7 @@ static struct redisplay_interface x_redisplay_interface = x_after_update_window_line, x_update_window_begin, x_update_window_end, - x_flush, + x_flip_and_flush, x_clear_window_mouse_face, x_get_glyph_overhangs, x_fix_overlapping_area, @@ -12604,6 +12725,7 @@ x_create_terminal (struct x_display_info *dpyinfo) terminal->update_end_hook = x_update_end; terminal->read_socket_hook = XTread_socket; terminal->frame_up_to_date_hook = XTframe_up_to_date; + terminal->buffer_flipping_unblocked_hook = XTbuffer_flipping_unblocked_hook; terminal->mouse_position_hook = XTmouse_position; terminal->frame_rehighlight_hook = XTframe_rehighlight; terminal->frame_raise_lower_hook = XTframe_raise_lower; @@ -12640,6 +12762,13 @@ x_initialize (void) /* Try to use interrupt input; if we can't, then start polling. */ Fset_input_interrupt_mode (Qt); +#if THREADS_ENABLED + /* This must be called before any other Xlib routines. */ + if (XInitThreads () == 0) + fprintf (stderr, + "Warning: An error occurred initializing X11 thread support!\n"); +#endif + #ifdef USE_X_TOOLKIT XtToolkitInitialize (); @@ -12747,6 +12876,8 @@ With MS Windows or Nextstep, the value is t. */); #endif DEFSYM (Qmodifier_value, "modifier-value"); + DEFSYM (Qctrl, "ctrl"); + Fput (Qctrl, Qmodifier_value, make_number (ctrl_modifier)); DEFSYM (Qalt, "alt"); Fput (Qalt, Qmodifier_value, make_number (alt_modifier)); DEFSYM (Qhyper, "hyper"); @@ -12756,32 +12887,39 @@ With MS Windows or Nextstep, the value is t. */); DEFSYM (Qsuper, "super"); Fput (Qsuper, Qmodifier_value, make_number (super_modifier)); + DEFVAR_LISP ("x-ctrl-keysym", Vx_ctrl_keysym, + doc: /* Which keys Emacs uses for the ctrl modifier. +This should be one of the symbols `ctrl', `alt', `hyper', `meta', +`super'. For example, `ctrl' means use the Ctrl_L and Ctrl_R keysyms. +The default is nil, which is the same as `ctrl'. */); + Vx_ctrl_keysym = Qnil; + DEFVAR_LISP ("x-alt-keysym", Vx_alt_keysym, doc: /* Which keys Emacs uses for the alt modifier. -This should be one of the symbols `alt', `hyper', `meta', `super'. -For example, `alt' means use the Alt_L and Alt_R keysyms. The default -is nil, which is the same as `alt'. */); +This should be one of the symbols `ctrl', `alt', `hyper', `meta', +`super'. For example, `alt' means use the Alt_L and Alt_R keysyms. +The default is nil, which is the same as `alt'. */); Vx_alt_keysym = Qnil; DEFVAR_LISP ("x-hyper-keysym", Vx_hyper_keysym, doc: /* Which keys Emacs uses for the hyper modifier. -This should be one of the symbols `alt', `hyper', `meta', `super'. -For example, `hyper' means use the Hyper_L and Hyper_R keysyms. The -default is nil, which is the same as `hyper'. */); +This should be one of the symbols `ctrl', `alt', `hyper', `meta', +`super'. For example, `hyper' means use the Hyper_L and Hyper_R +keysyms. The default is nil, which is the same as `hyper'. */); Vx_hyper_keysym = Qnil; DEFVAR_LISP ("x-meta-keysym", Vx_meta_keysym, doc: /* Which keys Emacs uses for the meta modifier. -This should be one of the symbols `alt', `hyper', `meta', `super'. -For example, `meta' means use the Meta_L and Meta_R keysyms. The -default is nil, which is the same as `meta'. */); +This should be one of the symbols `ctrl', `alt', `hyper', `meta', +`super'. For example, `meta' means use the Meta_L and Meta_R keysyms. +The default is nil, which is the same as `meta'. */); Vx_meta_keysym = Qnil; DEFVAR_LISP ("x-super-keysym", Vx_super_keysym, doc: /* Which keys Emacs uses for the super modifier. -This should be one of the symbols `alt', `hyper', `meta', `super'. -For example, `super' means use the Super_L and Super_R keysyms. The -default is nil, which is the same as `super'. */); +This should be one of the symbols `ctrl', `alt', `hyper', `meta', +`super'. For example, `super' means use the Super_L and Super_R +keysyms. The default is nil, which is the same as `super'. */); Vx_super_keysym = Qnil; DEFVAR_LISP ("x-keysym-table", Vx_keysym_table, |