X-Git-Url: https://code.delx.au/gnu-emacs/blobdiff_plain/016b9ec0c84124bc7754014c447fb08ae2f2df47..1087305574fd61256d66eb0c995f8bb74bd91afe:/src/xterm.c diff --git a/src/xterm.c b/src/xterm.c index c1970cc433..5756378bd3 100644 --- a/src/xterm.c +++ b/src/xterm.c @@ -22,10 +22,12 @@ along with GNU Emacs. If not, see . */ #include #include +#ifdef USE_CAIRO +#include +#endif #include "lisp.h" #include "blockinput.h" -#include "syssignal.h" /* This may include sys/types.h, and that somehow loses if this is not done before the other system files. */ @@ -55,12 +57,9 @@ along with GNU Emacs. If not, see . */ #include #include #include -/* Caused redefinition of DBL_DIG on Netbsd; seems not to be needed. */ -/* #include */ - -#include "charset.h" #include "character.h" #include "coding.h" +#include "composite.h" #include "frame.h" #include "dispextern.h" #include "fontset.h" @@ -68,17 +67,12 @@ along with GNU Emacs. If not, see . */ #include "termopts.h" #include "termchar.h" #include "emacs-icon.h" -#include "disptab.h" #include "buffer.h" #include "window.h" #include "keyboard.h" -#include "intervals.h" -#include "process.h" #include "atimer.h" -#include "keymap.h" #include "font.h" #include "xsettings.h" -#include "xgselect.h" #include "sysselect.h" #include "menu.h" @@ -211,34 +205,16 @@ enum xembed_message XEMBED_ACTIVATE_ACCELERATOR = 14 }; +static void x_free_cr_resources (struct frame *); static bool x_alloc_nearest_color_1 (Display *, Colormap, XColor *); -static void x_set_window_size_1 (struct frame *, bool, int, int); static void x_raise_frame (struct frame *); static void x_lower_frame (struct frame *); -static const XColor *x_color_cells (Display *, int *); static int x_io_error_quitter (Display *); static struct terminal *x_create_terminal (struct x_display_info *); -static void x_update_end (struct frame *); -static void XTframe_up_to_date (struct frame *); -static void x_clear_area1 (Display *, Window, int, int, int, int, int); -static void x_clear_frame (struct frame *); -static _Noreturn void x_ins_del_lines (struct frame *, int, int); -static void frame_highlight (struct frame *); -static void frame_unhighlight (struct frame *); -static void x_new_focus_frame (struct x_display_info *, struct frame *); -static void x_focus_changed (int, int, struct x_display_info *, - struct frame *, struct input_event *); -static void XTframe_rehighlight (struct frame *); static void x_frame_rehighlight (struct x_display_info *); -static void x_draw_hollow_cursor (struct window *, struct glyph_row *); -static void x_draw_bar_cursor (struct window *, struct glyph_row *, int, - enum text_cursor_kinds); static void x_clip_to_row (struct window *, struct glyph_row *, enum glyph_row_area, GC); -static void x_flush (struct frame *f); -static void x_update_begin (struct frame *); -static void x_update_window_begin (struct window *); static struct scroll_bar *x_window_to_scroll_bar (Display *, Window, int); static void x_scroll_bar_report_motion (struct frame **, Lisp_Object *, enum scroll_bar_part *, @@ -258,9 +234,6 @@ static int handle_one_xevent (struct x_display_info *, #if ! (defined USE_X_TOOLKIT || defined USE_MOTIF) static int x_dispatch_event (XEvent *, Display *); #endif -/* Don't declare this _Noreturn because we want no - interference with debugging failing X calls. */ -static void x_connection_closed (Display *, const char *); static void x_wm_set_window_state (struct frame *, int); static void x_wm_set_icon_pixmap (struct frame *, ptrdiff_t); static void x_initialize (void); @@ -326,21 +299,7 @@ record_event (char *locus, int type) #endif -static void x_prepare_for_xlibdraw (struct frame *); -static void x_set_clip_rectangles (struct frame *, GC, XRectangle *, int); -static void x_reset_clip_rectangles (struct frame *, GC); -static void x_fill_rectangle (struct frame *, GC, int, int, int, int); -static void x_draw_rectangle (struct frame *, GC, int, int, int, int); -static void x_fill_trapezoid_for_relief (struct frame *, GC, int, int, - int, int, int); -static void x_clear_window (struct frame *); - #ifdef USE_CAIRO -static struct x_gc_ext_data *x_gc_get_ext_data (struct frame *, GC, int); -static void x_extension_initialize (struct x_display_info *); -static cairo_status_t x_cr_accumulate_data (void *, - const unsigned char *, - unsigned int); #define FRAME_CR_CONTEXT(f) ((f)->output_data.x->cr_context) #define FRAME_CR_SURFACE(f) ((f)->output_data.x->cr_surface) @@ -571,7 +530,7 @@ x_cr_draw_frame (cairo_t *cr, struct frame *f) width = FRAME_PIXEL_WIDTH (f); height = FRAME_PIXEL_HEIGHT (f); - x_prepare_for_xlibdraw (f); + x_free_cr_resources (f); FRAME_CR_CONTEXT (f) = cr; x_clear_area (f, 0, 0, width, height); expose_frame (f, 0, 0, width, height); @@ -584,7 +543,7 @@ x_cr_accumulate_data (void *closure, const unsigned char *data, { Lisp_Object *acc = (Lisp_Object *) closure; - *acc = Fcons (make_unibyte_string (data, length), *acc); + *acc = Fcons (make_unibyte_string ((char const *) data, length), *acc); return CAIRO_STATUS_SUCCESS; } @@ -607,7 +566,7 @@ x_cr_export_frames (Lisp_Object frames, cairo_surface_type_t surface_type) cairo_t *cr; int width, height; void (*surface_set_size_func) (cairo_surface_t *, double, double) = NULL; - Lisp_Object acc = Qnil, args[2]; + Lisp_Object acc = Qnil; int count = SPECPDL_INDEX (); Fredisplay (Qt); @@ -659,7 +618,7 @@ x_cr_export_frames (Lisp_Object frames, cairo_surface_type_t surface_type) QUIT; block_input (); - x_prepare_for_xlibdraw (f); + x_free_cr_resources (f); FRAME_CR_CONTEXT (f) = cr; x_clear_area (f, 0, 0, width, height); expose_frame (f, 0, 0, width, height); @@ -691,15 +650,13 @@ x_cr_export_frames (Lisp_Object frames, cairo_surface_type_t surface_type) #endif unbind_to (count, Qnil); - args[0] = intern ("concat"); - args[1] = Fnreverse (acc); - return Fapply (2, args); + return CALLN (Fapply, intern ("concat"), Fnreverse (acc)); } #endif /* USE_CAIRO */ static void -x_prepare_for_xlibdraw (struct frame *f) +x_free_cr_resources (struct frame *f) { #ifdef USE_CAIRO if (f == NULL) @@ -707,7 +664,7 @@ x_prepare_for_xlibdraw (struct frame *f) Lisp_Object rest, frame; FOR_EACH_FRAME (rest, frame) if (FRAME_X_P (XFRAME (frame))) - x_prepare_for_xlibdraw (XFRAME (frame)); + x_free_cr_resources (XFRAME (frame)); } else { @@ -824,6 +781,48 @@ x_fill_trapezoid_for_relief (struct frame *f, GC gc, int x, int y, x_end_cr_clip (f); } +enum corners + { + CORNER_BOTTOM_RIGHT, /* 0 -> pi/2 */ + CORNER_BOTTOM_LEFT, /* pi/2 -> pi */ + CORNER_TOP_LEFT, /* pi -> 3pi/2 */ + CORNER_TOP_RIGHT, /* 3pi/2 -> 2pi */ + CORNER_LAST + }; + +static void +x_erase_corners_for_relief (struct frame *f, GC gc, int x, int y, + int width, int height, + double radius, double margin, int corners) +{ + cairo_t *cr; + int i; + + cr = x_begin_cr_clip (f, gc); + x_set_cr_source_with_gc_background (f, gc); + for (i = 0; i < CORNER_LAST; i++) + if (corners & (1 << i)) + { + double xm, ym, xc, yc; + + if (i == CORNER_TOP_LEFT || i == CORNER_BOTTOM_LEFT) + xm = x - margin, xc = xm + radius; + else + xm = x + width + margin, xc = xm - radius; + if (i == CORNER_TOP_LEFT || i == CORNER_TOP_RIGHT) + ym = y - margin, yc = ym + radius; + else + ym = y + height + margin, yc = ym - radius; + + cairo_move_to (cr, xm, ym); + cairo_arc (cr, xc, yc, radius, i * M_PI_2, (i + 1) * M_PI_2); + } + cairo_clip (cr); + cairo_rectangle (cr, x, y, width, height); + cairo_fill (cr); + x_end_cr_clip (f); +} + static void x_draw_horizontal_wave (struct frame *f, GC gc, int x, int y, int width, int height, int wave_length) @@ -993,6 +992,10 @@ static void x_update_begin (struct frame *f) { #ifdef USE_CAIRO + if (! NILP (tip_frame) && XFRAME (tip_frame) == f + && ! FRAME_VISIBLE_P (f)) + return; + if (! FRAME_CR_SURFACE (f)) { int width, height; @@ -1710,6 +1713,11 @@ x_draw_glyph_string_background (struct glyph_string *s, bool force_p) s->background_filled_p = true; } else if (FONT_HEIGHT (s->font) < s->height - 2 * box_line_width + /* When xdisp.c ignores FONT_HEIGHT, we cannot trust + font dimensions, since the actual glyphs might be + much smaller. So in that case we always clear the + rectangle with background color. */ + || FONT_TOO_HIGH (s->font) || s->font_not_found_p || s->extends_to_end_of_line_p || force_p) @@ -1906,7 +1914,7 @@ x_draw_glyphless_glyph_string_foreground (struct glyph_string *s) { sprintf (buf, "%0*X", glyph->u.glyphless.ch < 0x10000 ? 4 : 6, - glyph->u.glyphless.ch); + glyph->u.glyphless.ch + 0u); str = buf; } @@ -1999,9 +2007,9 @@ x_alloc_lighter_color_for_widget (Widget widget, Display *display, Colormap cmap static XtConvertArgRec cvt_string_to_pixel_args[] = { - {XtWidgetBaseOffset, (XtPointer) XtOffset (Widget, core.screen), + {XtWidgetBaseOffset, (XtPointer) offsetof (WidgetRec, core.screen), sizeof (Screen *)}, - {XtWidgetBaseOffset, (XtPointer) XtOffset (Widget, core.colormap), + {XtWidgetBaseOffset, (XtPointer) offsetof (WidgetRec, core.colormap), sizeof (Colormap)} }; @@ -2077,7 +2085,7 @@ cvt_string_to_pixel (Display *dpy, XrmValue *args, Cardinal *nargs, params[0] = color_name; XtAppWarningMsg (XtDisplayToApplicationContext (dpy), "badValue", "cvt_string_to_pixel", - "XtToolkitError", "Invalid color `%s'", + "XtToolkitError", "Invalid color '%s'", params, &nparams); return False; } @@ -2180,6 +2188,50 @@ x_query_colors (struct frame *f, XColor *colors, int ncolors) { struct x_display_info *dpyinfo = FRAME_DISPLAY_INFO (f); + if (dpyinfo->red_bits > 0) + { + /* For TrueColor displays, we can decompose the RGB value + directly. */ + int i; + unsigned int rmult, gmult, bmult; + unsigned int rmask, gmask, bmask; + + rmask = (1 << dpyinfo->red_bits) - 1; + gmask = (1 << dpyinfo->green_bits) - 1; + bmask = (1 << dpyinfo->blue_bits) - 1; + /* If we're widening, for example, 8 bits in the pixel value to + 16 bits for the separate-color representation, we want to + extrapolate the lower bits based on those bits available -- + in other words, we'd like 0xff to become 0xffff instead of + the 0xff00 we'd get by just zero-filling the lower bits. + + We generate a 32-bit scaled-up value and shift it, in case + the bit count doesn't divide 16 evenly (e.g., when dealing + with a 3-3-2 bit RGB display), to get more of the lower bits + correct. + + Should we cache the multipliers in dpyinfo? Maybe + special-case the 8-8-8 common case? */ + rmult = 0xffffffff / rmask; + gmult = 0xffffffff / gmask; + bmult = 0xffffffff / bmask; + + for (i = 0; i < ncolors; ++i) + { + unsigned int r, g, b; + unsigned long pixel = colors[i].pixel; + + r = (pixel >> dpyinfo->red_offset) & rmask; + g = (pixel >> dpyinfo->green_offset) & gmask; + b = (pixel >> dpyinfo->blue_offset) & bmask; + + colors[i].red = (r * rmult) >> 16; + colors[i].green = (g * gmult) >> 16; + colors[i].blue = (b * bmult) >> 16; + } + return; + } + if (dpyinfo->color_cells) { int i; @@ -2190,9 +2242,10 @@ x_query_colors (struct frame *f, XColor *colors, int ncolors) eassert (dpyinfo->color_cells[pixel].pixel == pixel); colors[i] = dpyinfo->color_cells[pixel]; } + return; } - else - XQueryColors (FRAME_X_DISPLAY (f), FRAME_X_COLORMAP (f), colors, ncolors); + + XQueryColors (FRAME_X_DISPLAY (f), FRAME_X_COLORMAP (f), colors, ncolors); } @@ -2206,6 +2259,51 @@ x_query_color (struct frame *f, XColor *color) } +/* On frame F, translate the color name to RGB values. Use cached + information, if possible. + + Note that there is currently no way to clean old entries out of the + cache. However, it is limited to names in the server's database, + and names we've actually looked up; list-colors-display is probably + the most color-intensive case we're likely to hit. */ + +Status x_parse_color (struct frame *f, const char *color_name, + XColor *color) +{ + Display *dpy = FRAME_X_DISPLAY (f); + Colormap cmap = FRAME_X_COLORMAP (f); + struct color_name_cache_entry *cache_entry; + + if (color_name[0] == '#') + { + /* The hex form is parsed directly by XParseColor without + talking to the X server. No need for caching. */ + return XParseColor (dpy, cmap, color_name, color); + } + + for (cache_entry = FRAME_DISPLAY_INFO (f)->color_names; cache_entry; + cache_entry = cache_entry->next) + { + if (!xstrcasecmp(cache_entry->name, color_name)) + { + *color = cache_entry->rgb; + return 1; + } + } + + if (XParseColor (dpy, cmap, color_name, color) == 0) + /* No caching of negative results, currently. */ + return 0; + + cache_entry = xzalloc (sizeof *cache_entry); + cache_entry->rgb = *color; + cache_entry->name = xstrdup (color_name); + cache_entry->next = FRAME_DISPLAY_INFO (f)->color_names; + FRAME_DISPLAY_INFO (f)->color_names = cache_entry; + return 1; +} + + /* Allocate the color COLOR->pixel on DISPLAY, colormap CMAP. If an exact match can't be allocated, try the nearest color available. Value is true if successful. Set *COLOR to the color @@ -2278,15 +2376,27 @@ x_alloc_nearest_color_1 (Display *dpy, Colormap cmap, XColor *color) } -/* Allocate the color COLOR->pixel on frame F, colormap CMAP. If an - exact match can't be allocated, try the nearest color available. - Value is true if successful. Set *COLOR to the color - allocated. */ +/* Allocate the color COLOR->pixel on frame F, colormap CMAP, after + gamma correction. If an exact match can't be allocated, try the + nearest color available. Value is true if successful. Set *COLOR + to the color allocated. */ bool x_alloc_nearest_color (struct frame *f, Colormap cmap, XColor *color) { + struct x_display_info *dpyinfo = FRAME_DISPLAY_INFO (f); + gamma_correct (f, color); + + if (dpyinfo->red_bits > 0) + { + color->pixel = x_make_truecolor_pixel (dpyinfo, + color->red, + color->green, + color->blue); + return true; + } + return x_alloc_nearest_color_1 (FRAME_X_DISPLAY (f), cmap, color); } @@ -2300,8 +2410,16 @@ x_copy_color (struct frame *f, unsigned long pixel) { XColor color; + /* If display has an immutable color map, freeing colors is not + necessary and some servers don't allow it. Since we won't free a + color once we've allocated it, we don't need to re-allocate it to + maintain the server's reference count. */ + if (!x_mutable_colormap (FRAME_X_VISUAL (f))) + return pixel; + color.pixel = pixel; block_input (); + /* The color could still be found in the color_cells array. */ x_query_color (f, &color); XAllocColor (FRAME_X_DISPLAY (f), FRAME_X_COLORMAP (f), &color); unblock_input (); @@ -2505,6 +2623,7 @@ x_draw_relief_rect (struct frame *f, { #ifdef USE_CAIRO GC top_left_gc, bottom_right_gc; + int corners = 0; if (raised_p) { @@ -2521,11 +2640,23 @@ x_draw_relief_rect (struct frame *f, x_set_clip_rectangles (f, bottom_right_gc, clip_rect, 1); if (left_p) - x_fill_rectangle (f, top_left_gc, left_x, top_y, - width, bottom_y + 1 - top_y); + { + x_fill_rectangle (f, top_left_gc, left_x, top_y, + width, bottom_y + 1 - top_y); + if (top_p) + corners |= 1 << CORNER_TOP_LEFT; + if (bot_p) + corners |= 1 << CORNER_BOTTOM_LEFT; + } if (right_p) - x_fill_rectangle (f, bottom_right_gc, right_x + 1 - width, top_y, - width, bottom_y + 1 - top_y); + { + x_fill_rectangle (f, bottom_right_gc, right_x + 1 - width, top_y, + width, bottom_y + 1 - top_y); + if (top_p) + corners |= 1 << CORNER_TOP_RIGHT; + if (bot_p) + corners |= 1 << CORNER_BOTTOM_RIGHT; + } if (top_p) { if (!right_p) @@ -2545,6 +2676,20 @@ x_draw_relief_rect (struct frame *f, left_x, bottom_y + 1 - width, right_x + 1 - left_x, width, 0); } + if (left_p && width != 1) + x_fill_rectangle (f, bottom_right_gc, left_x, top_y, + 1, bottom_y + 1 - top_y); + if (top_p && width != 1) + x_fill_rectangle (f, bottom_right_gc, left_x, top_y, + right_x + 1 - left_x, 1); + if (corners) + { + XSetBackground (FRAME_X_DISPLAY (f), top_left_gc, + FRAME_BACKGROUND_PIXEL (f)); + x_erase_corners_for_relief (f, top_left_gc, left_x, top_y, + right_x - left_x + 1, bottom_y - top_y + 1, + 6, 1, corners); + } x_reset_clip_rectangles (f, top_left_gc); x_reset_clip_rectangles (f, bottom_right_gc); @@ -3091,6 +3236,7 @@ x_draw_image_glyph_string (struct glyph_string *s) } /* Draw the foreground. */ +#ifdef USE_CAIRO if (s->img->cr_data) { cairo_t *cr = x_begin_cr_clip (s->f, s->gc); @@ -3106,7 +3252,9 @@ x_draw_image_glyph_string (struct glyph_string *s) cairo_fill (cr); x_end_cr_clip (s->f); } - else if (pixmap != None) + else +#endif + if (pixmap != None) { x_draw_image_foreground_1 (s, pixmap); x_set_glyph_string_clipping (s); @@ -3585,7 +3733,9 @@ x_draw_glyph_string (struct glyph_string *s) static void x_shift_glyphs_for_insert (struct frame *f, int x, int y, int width, int height, int shift_by) { - x_prepare_for_xlibdraw (f); +/* 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), f->output_data.x->normal_gc, x, y, width, height, @@ -4833,7 +4983,7 @@ XTmouse_position (struct frame **fp, int insist, Lisp_Object *bar_window, if (x_had_errors_p (FRAME_X_DISPLAY (*fp))) f1 = 0; - x_uncatch_errors (); + x_uncatch_errors_after_check (); /* If not, is it one of our scroll bars? */ if (! f1) @@ -5356,6 +5506,8 @@ xg_scroll_callback (GtkRange *range, ? scroll_bar_after_handle : scroll_bar_below_handle); bar->dragging = -1; break; + default: + break; } if (part != scroll_bar_nowhere) @@ -6355,7 +6507,7 @@ x_scroll_bar_set_handle (struct scroll_bar *bar, int start, int end, x_clear_area1 (FRAME_X_DISPLAY (f), w, VERTICAL_SCROLL_BAR_LEFT_BORDER, VERTICAL_SCROLL_BAR_TOP_BORDER, - inside_width, start); + inside_width, start, False); /* Change to proper foreground color if one is specified. */ if (f->output_data.x->scroll_bar_foreground_pixel != -1) @@ -6363,7 +6515,7 @@ x_scroll_bar_set_handle (struct scroll_bar *bar, int start, int end, f->output_data.x->scroll_bar_foreground_pixel); /* Draw the handle itself. */ - x_fill_rectangle (f, gc, + XFillRectangle (FRAME_X_DISPLAY (f), w, gc, /* x, y, width, height */ VERTICAL_SCROLL_BAR_LEFT_BORDER, VERTICAL_SCROLL_BAR_TOP_BORDER + start, @@ -6380,7 +6532,7 @@ x_scroll_bar_set_handle (struct scroll_bar *bar, int start, int end, x_clear_area1 (FRAME_X_DISPLAY (f), w, VERTICAL_SCROLL_BAR_LEFT_BORDER, VERTICAL_SCROLL_BAR_TOP_BORDER + end, - inside_width, inside_height - end); + inside_width, inside_height - end, False); } unblock_input (); @@ -6614,8 +6766,7 @@ XTset_horizontal_scroll_bar (struct window *w, int portion, int whole, int posit int area_height = WINDOW_CONFIG_SCROLL_BAR_HEIGHT (w); int rest = area_height - height; if (rest > 0 && width > 0) - x_clear_area (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f), - left, top, width, rest); + x_clear_area (f, left, top, width, rest); } /* Move/size the scroll bar window. */ @@ -6839,7 +6990,7 @@ x_scroll_bar_expose (struct scroll_bar *bar, const XEvent *event) f->output_data.x->scroll_bar_foreground_pixel); /* Draw a one-pixel border just inside the edges of the scroll bar. */ - x_draw_rectangle (f, gc, + XDrawRectangle (FRAME_X_DISPLAY (f), w, gc, /* x, y, width, height */ 0, 0, bar->width - 1, bar->height - 1); @@ -7308,10 +7459,7 @@ handle_one_xevent (struct x_display_info *dpyinfo, const XEvent *event, int *finish, struct input_event *hold_quit) { - union { - struct input_event ie; - struct selection_input_event sie; - } inev; + union buffered_input_event inev; int count = 0; int do_help = 0; ptrdiff_t nbytes = 0; @@ -7323,6 +7471,8 @@ handle_one_xevent (struct x_display_info *dpyinfo, says that a portable program can't use this, but Stephen Gildea assures me that letting the compiler initialize it to zeros will work okay. */ static XComposeStatus compose_status; + XEvent configureEvent; + XEvent next_event; USE_SAFE_ALLOCA; @@ -7383,9 +7533,6 @@ handle_one_xevent (struct x_display_info *dpyinfo, the only valid choice. */ RevertToParent, event->xclient.data.l[1]); - /* This is needed to detect the error - if there is an error. */ - XSync (d, False); x_uncatch_errors (); } /* Not certain about handling scroll bars here */ @@ -7539,7 +7686,7 @@ handle_one_xevent (struct x_display_info *dpyinfo, { const XSelectionClearEvent *eventp = &event->xselectionclear; - inev.ie.kind = SELECTION_CLEAR_EVENT; + inev.sie.kind = SELECTION_CLEAR_EVENT; SELECTION_EVENT_DPYINFO (&inev.sie) = dpyinfo; SELECTION_EVENT_SELECTION (&inev.sie) = eventp->selection; SELECTION_EVENT_TIME (&inev.sie) = eventp->time; @@ -7555,7 +7702,7 @@ handle_one_xevent (struct x_display_info *dpyinfo, { const XSelectionRequestEvent *eventp = &event->xselectionrequest; - inev.ie.kind = SELECTION_REQUEST_EVENT; + inev.sie.kind = SELECTION_REQUEST_EVENT; SELECTION_EVENT_DPYINFO (&inev.sie) = dpyinfo; SELECTION_EVENT_REQUESTOR (&inev.sie) = eventp->requestor; SELECTION_EVENT_SELECTION (&inev.sie) = eventp->selection; @@ -7623,7 +7770,7 @@ handle_one_xevent (struct x_display_info *dpyinfo, } else { -#if defined (USE_GTK) && ! defined (HAVE_GTK3) && ! defined (USE_CAIRO) +#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, @@ -7720,11 +7867,6 @@ handle_one_xevent (struct x_display_info *dpyinfo, goto OTHER; case MapNotify: - if (event->xmap.window == tip_window) - /* The tooltip has been drawn already. Avoid - the SET_FRAME_GARBAGED below. */ - goto OTHER; - /* We use x_top_window_to_frame because map events can come for sub-windows and they don't mean that the frame is visible. */ @@ -7771,17 +7913,18 @@ handle_one_xevent (struct x_display_info *dpyinfo, f = any; -#if ! defined (USE_GTK) /* If mouse-highlight is an integer, input clears out mouse highlighting. */ if (!hlinfo->mouse_face_hidden && INTEGERP (Vmouse_highlight) +#if ! defined (USE_GTK) && (f == 0 - || !EQ (f->tool_bar_window, hlinfo->mouse_face_window))) + || !EQ (f->tool_bar_window, hlinfo->mouse_face_window)) +#endif + ) { clear_mouse_face (hlinfo); hlinfo->mouse_face_hidden = true; } -#endif #if defined USE_MOTIF && defined USE_TOOLKIT_SCROLL_BARS if (f == 0) @@ -8070,7 +8213,7 @@ handle_one_xevent (struct x_display_info *dpyinfo, ? ASCII_KEYSTROKE_EVENT : MULTIBYTE_CHAR_KEYSTROKE_EVENT); inev.ie.code = ch; - kbd_buffer_store_event_hold (&inev.ie, hold_quit); + kbd_buffer_store_buffered_event (&inev, hold_quit); } count += nchars; @@ -8239,29 +8382,74 @@ handle_one_xevent (struct x_display_info *dpyinfo, } case ConfigureNotify: - f = x_top_window_to_frame (dpyinfo, event->xconfigure.window); + /* An opaque move can generate a stream of events as the window + is dragged around. If the connection round trip time isn't + really short, they may come faster than we can respond to + them, given the multiple queries we can do to check window + manager state, translate coordinates, etc. + + So if this ConfigureNotify is immediately followed by another + for the same window, use the info from the latest update, and + consider the events all handled. */ + /* Opaque resize may be trickier; ConfigureNotify events are + mixed with Expose events for multiple windows. */ + configureEvent = *event; + while (XPending (dpyinfo->display)) + { + XNextEvent (dpyinfo->display, &next_event); + if (next_event.type != ConfigureNotify + || next_event.xconfigure.window != event->xconfigure.window + /* Skipping events with different sizes can lead to a + mispositioned mode line at initial window creation. + Only drop window motion events for now. */ + || next_event.xconfigure.width != event->xconfigure.width + || next_event.xconfigure.height != event->xconfigure.height) + { + XPutBackEvent (dpyinfo->display, &next_event); + break; + } + else + configureEvent = next_event; + } + f = x_top_window_to_frame (dpyinfo, configureEvent.xconfigure.window); #ifdef USE_CAIRO if (f) x_cr_destroy_surface (f); #endif #ifdef USE_GTK if (!f && (f = any) - && event->xconfigure.window == FRAME_X_WINDOW (f)) + && configureEvent.xconfigure.window == FRAME_X_WINDOW (f)) { - xg_frame_resized (f, event->xconfigure.width, - event->xconfigure.height); + xg_frame_resized (f, configureEvent.xconfigure.width, + configureEvent.xconfigure.height); +#ifdef USE_CAIRO x_cr_destroy_surface (f); +#endif f = 0; } #endif if (f) { - x_net_wm_state (f, event->xconfigure.window); + x_net_wm_state (f, configureEvent.xconfigure.window); + +#ifdef USE_X_TOOLKIT + /* Tip frames are pure X window, set size for them. */ + if (! NILP (tip_frame) && XFRAME (tip_frame) == f) + { + if (FRAME_PIXEL_HEIGHT (f) != configureEvent.xconfigure.height + || FRAME_PIXEL_WIDTH (f) != configureEvent.xconfigure.width) + SET_FRAME_GARBAGED (f); + FRAME_PIXEL_HEIGHT (f) = configureEvent.xconfigure.height; + FRAME_PIXEL_WIDTH (f) = configureEvent.xconfigure.width; + } +#endif #ifndef USE_X_TOOLKIT #ifndef USE_GTK - int width = FRAME_PIXEL_TO_TEXT_WIDTH (f, event->xconfigure.width); - int height = FRAME_PIXEL_TO_TEXT_HEIGHT (f, event->xconfigure.height); + int width = + FRAME_PIXEL_TO_TEXT_WIDTH (f, configureEvent.xconfigure.width); + int height = + FRAME_PIXEL_TO_TEXT_HEIGHT (f, configureEvent.xconfigure.height); /* In the toolkit version, change_frame_size is called by the code that handles resizing @@ -8272,8 +8460,8 @@ handle_one_xevent (struct x_display_info *dpyinfo, to check the pixel dimensions as well. */ if (width != FRAME_TEXT_WIDTH (f) || height != FRAME_TEXT_HEIGHT (f) - || event->xconfigure.width != FRAME_PIXEL_WIDTH (f) - || event->xconfigure.height != FRAME_PIXEL_HEIGHT (f)) + || configureEvent.xconfigure.width != FRAME_PIXEL_WIDTH (f) + || configureEvent.xconfigure.height != FRAME_PIXEL_HEIGHT (f)) { change_frame_size (f, width, height, false, true, false, true); x_clear_under_internal_border (f); @@ -8473,7 +8661,7 @@ handle_one_xevent (struct x_display_info *dpyinfo, done: if (inev.ie.kind != NO_EVENT) { - kbd_buffer_store_event_hold (&inev.ie, hold_quit); + kbd_buffer_store_buffered_event (&inev, hold_quit); count++; } @@ -9026,6 +9214,8 @@ x_text_icon (struct frame *f, const char *icon_name) struct x_error_message_stack { char string[X_ERROR_MESSAGE_SIZE]; Display *dpy; + x_special_error_handler handler; + void *handler_data; struct x_error_message_stack *prev; }; static struct x_error_message_stack *x_error_message; @@ -9040,6 +9230,9 @@ x_error_catcher (Display *display, XErrorEvent *event) XGetErrorText (display, event->error_code, x_error_message->string, X_ERROR_MESSAGE_SIZE); + if (x_error_message->handler) + x_error_message->handler (display, event, x_error_message->string, + x_error_message->handler_data); } /* Begin trapping X errors for display DPY. Actually we trap X errors @@ -9053,10 +9246,14 @@ x_error_catcher (Display *display, XErrorEvent *event) Calling x_check_errors signals an Emacs error if an X error has occurred since the last call to x_catch_errors or x_check_errors. - Calling x_uncatch_errors resumes the normal error handling. */ + Calling x_uncatch_errors resumes the normal error handling. + Calling x_uncatch_errors_after_check is similar, but skips an XSync + to the server, and should be used only immediately after + x_had_errors_p or x_check_errors. */ void -x_catch_errors (Display *dpy) +x_catch_errors_with_handler (Display *dpy, x_special_error_handler handler, + void *handler_data) { struct x_error_message_stack *data = xmalloc (sizeof *data); @@ -9065,10 +9262,37 @@ x_catch_errors (Display *dpy) data->dpy = dpy; data->string[0] = 0; + data->handler = handler; + data->handler_data = handler_data; data->prev = x_error_message; x_error_message = data; } +void +x_catch_errors (Display *dpy) +{ + x_catch_errors_with_handler (dpy, NULL, NULL); +} + +/* Undo the last x_catch_errors call. + DPY should be the display that was passed to x_catch_errors. + + This version should be used only if the immediately preceding + X-protocol-related thing was x_check_errors or x_had_error_p, both + of which issue XSync calls, so we don't need to re-sync here. */ + +void +x_uncatch_errors_after_check (void) +{ + struct x_error_message_stack *tmp; + + block_input (); + tmp = x_error_message; + x_error_message = x_error_message->prev; + xfree (tmp); + unblock_input (); +} + /* Undo the last x_catch_errors call. DPY should be the display that was passed to x_catch_errors. */ @@ -9163,7 +9387,7 @@ static char *error_msg; the text of an error message that lead to the connection loss. */ static void -x_connection_closed (Display *dpy, const char *error_message) +x_connection_closed (Display *dpy, const char *error_message, bool ioerror) { struct x_display_info *dpyinfo = x_display_info_for_display (dpy); Lisp_Object frame, tail; @@ -9182,6 +9406,7 @@ x_connection_closed (Display *dpy, const char *error_message) dpyinfo->reference_count++; dpyinfo->terminal->reference_count++; } + if (ioerror) dpyinfo->display = 0; /* First delete frames whose mini-buffers are on frames that are on the dead display. */ @@ -9319,7 +9544,7 @@ x_error_quitter (Display *display, XErrorEvent *event) XGetErrorText (display, event->error_code, buf, sizeof (buf)); sprintf (buf1, "X protocol error: %s on protocol request %d", buf, event->request_code); - x_connection_closed (display, buf1); + x_connection_closed (display, buf1, false); } @@ -9332,9 +9557,9 @@ x_io_error_quitter (Display *display) { char buf[256]; - snprintf (buf, sizeof buf, "Connection lost to X server `%s'", + snprintf (buf, sizeof buf, "Connection lost to X server '%s'", DisplayString (display)); - x_connection_closed (display, buf); + x_connection_closed (display, buf, true); return 0; } @@ -9349,7 +9574,11 @@ Lisp_Object x_new_font (struct frame *f, Lisp_Object font_object, int fontset) { struct font *font = XFONT_OBJECT (font_object); - int unit; + int unit, font_ascent, font_descent; +#ifndef USE_X_TOOLKIT + int old_menu_bar_height = FRAME_MENU_BAR_HEIGHT (f); + Lisp_Object fullscreen; +#endif if (fontset < 0) fontset = fontset_from_font (font_object); @@ -9362,7 +9591,8 @@ x_new_font (struct frame *f, Lisp_Object font_object, int fontset) FRAME_FONT (f) = font; FRAME_BASELINE_OFFSET (f) = font->baseline_offset; FRAME_COLUMN_WIDTH (f) = font->average_width; - FRAME_LINE_HEIGHT (f) = FONT_HEIGHT (font); + get_font_ascent_descent (font, &font_ascent, &font_descent); + FRAME_LINE_HEIGHT (f) = font_ascent + font_descent; #ifndef USE_X_TOOLKIT FRAME_MENU_BAR_HEIGHT (f) = FRAME_MENU_BAR_LINES (f) * FRAME_LINE_HEIGHT (f); @@ -9385,9 +9615,25 @@ x_new_font (struct frame *f, Lisp_Object font_object, int fontset) doing it because it's done in Fx_show_tip, and it leads to problems because the tip frame has no widget. */ if (NILP (tip_frame) || XFRAME (tip_frame) != f) + { adjust_frame_size (f, FRAME_COLS (f) * FRAME_COLUMN_WIDTH (f), FRAME_LINES (f) * FRAME_LINE_HEIGHT (f), 3, false, Qfont); +#ifndef USE_X_TOOLKIT + if (FRAME_MENU_BAR_HEIGHT (f) != old_menu_bar_height + && !f->after_make_frame + && (EQ (frame_inhibit_implied_resize, Qt) + || (CONSP (frame_inhibit_implied_resize) + && NILP (Fmemq (Qfont, frame_inhibit_implied_resize)))) + && (NILP (fullscreen = get_frame_param (f, Qfullscreen)) + || EQ (fullscreen, Qfullwidth))) + /* If the menu bar height changes, try to keep text height + constant. */ + adjust_frame_size + (f, -1, FRAME_TEXT_HEIGHT (f) + FRAME_MENU_BAR_HEIGHT (f) + - old_menu_bar_height, 1, false, Qfont); +#endif /* USE_X_TOOLKIT */ + } } #ifdef HAVE_X_I18N @@ -9723,8 +9969,8 @@ x_set_offset (struct frame *f, register int xoff, register int yoff, int change_ Specification/Extended Window Manager Hints at http://freedesktop.org/wiki/Specifications/wm-spec. */ -static bool -wm_supports (struct frame *f, Atom want_atom) +bool +x_wm_supports (struct frame *f, Atom want_atom) { Atom actual_type; unsigned long actual_size, bytes_remaining; @@ -9760,10 +10006,9 @@ wm_supports (struct frame *f, Atom want_atom) /* Check if window exists. */ XSelectInput (dpy, wmcheck_window, StructureNotifyMask); - x_sync (f); if (x_had_errors_p (dpy)) { - x_uncatch_errors (); + x_uncatch_errors_after_check (); unblock_input (); return false; } @@ -9917,7 +10162,7 @@ static bool do_ewmh_fullscreen (struct frame *f) { struct x_display_info *dpyinfo = FRAME_DISPLAY_INFO (f); - bool have_net_atom = wm_supports (f, dpyinfo->Xatom_net_wm_state); + bool have_net_atom = x_wm_supports (f, dpyinfo->Xatom_net_wm_state); int cur; bool dummy; @@ -9926,7 +10171,7 @@ do_ewmh_fullscreen (struct frame *f) /* Some window managers don't say they support _NET_WM_STATE, but they do say they support _NET_WM_STATE_FULLSCREEN. Try that also. */ if (!have_net_atom) - have_net_atom = wm_supports (f, dpyinfo->Xatom_net_wm_state_fullscreen); + have_net_atom = x_wm_supports (f, dpyinfo->Xatom_net_wm_state_fullscreen); if (have_net_atom && cur != f->want_fullscreen) { @@ -10096,6 +10341,8 @@ x_handle_net_wm_state (struct frame *f, const XPropertyEvent *event) static void x_check_fullscreen (struct frame *f) { + Lisp_Object lval = Qnil; + if (do_ewmh_fullscreen (f)) return; @@ -10114,22 +10361,34 @@ x_check_fullscreen (struct frame *f) switch (f->want_fullscreen) { /* No difference between these two when there is no WM */ - case FULLSCREEN_BOTH: case FULLSCREEN_MAXIMIZED: + lval = Qmaximized; + width = x_display_pixel_width (dpyinfo); + height = x_display_pixel_height (dpyinfo); + break; + case FULLSCREEN_BOTH: + lval = Qfullboth; width = x_display_pixel_width (dpyinfo); height = x_display_pixel_height (dpyinfo); break; case FULLSCREEN_WIDTH: + lval = Qfullwidth; width = x_display_pixel_width (dpyinfo); height = height + FRAME_MENUBAR_HEIGHT (f); break; case FULLSCREEN_HEIGHT: + lval = Qfullheight; height = x_display_pixel_height (dpyinfo); + break; + default: + emacs_abort (); } frame_size_history_add (f, Qx_check_fullscreen, width, height, Qnil); + x_wm_set_size_hint (f, 0, false); + XResizeWindow (FRAME_X_DISPLAY (f), FRAME_OUTER_WINDOW (f), width, height); @@ -10142,6 +10401,10 @@ x_check_fullscreen (struct frame *f) x_sync (f); } } + + /* `x_net_wm_state' might have reset the fullscreen frame parameter, + restore it. */ + store_frame_param (f, Qfullscreen, lval); } /* This function is called by x_set_offset to determine whether the window @@ -10302,7 +10565,7 @@ x_set_window_size_1 (struct frame *f, bool change_gravity, if (EQ (fullscreen, Qfullwidth) && width == FRAME_TEXT_WIDTH (f)) { frame_size_history_add - (f, Qxg_frame_set_char_size_1, width, height, + (f, Qx_set_window_size_1, width, height, list2 (make_number (old_height), make_number (pixelheight + FRAME_MENUBAR_HEIGHT (f)))); @@ -10312,7 +10575,7 @@ x_set_window_size_1 (struct frame *f, bool change_gravity, else if (EQ (fullscreen, Qfullheight) && height == FRAME_TEXT_HEIGHT (f)) { frame_size_history_add - (f, Qxg_frame_set_char_size_2, width, height, + (f, Qx_set_window_size_2, width, height, list2 (make_number (old_width), make_number (pixelwidth))); XResizeWindow (FRAME_X_DISPLAY (f), FRAME_OUTER_WINDOW (f), @@ -10322,10 +10585,11 @@ x_set_window_size_1 (struct frame *f, bool change_gravity, else { frame_size_history_add - (f, Qxg_frame_set_char_size_3, width, height, - list2 (make_number (pixelwidth + FRAME_TOOLBAR_WIDTH (f)), + (f, Qx_set_window_size_3, width, height, + list3 (make_number (pixelwidth + FRAME_TOOLBAR_WIDTH (f)), make_number (pixelheight + FRAME_TOOLBAR_HEIGHT (f) - + FRAME_MENUBAR_HEIGHT (f)))); + + FRAME_MENUBAR_HEIGHT (f)), + make_number (FRAME_MENUBAR_HEIGHT (f)))); XResizeWindow (FRAME_X_DISPLAY (f), FRAME_OUTER_WINDOW (f), pixelwidth, pixelheight + FRAME_MENUBAR_HEIGHT (f)); @@ -10441,8 +10705,6 @@ x_set_window_size (struct frame *f, bool change_gravity, cancel_mouse_face (f); unblock_input (); - - do_pending_window_change (false); } /* Move the mouse to position pixel PIX_X, PIX_Y relative to frame F. */ @@ -10505,7 +10767,7 @@ x_ewmh_activate_frame (struct frame *f) struct x_display_info *dpyinfo = FRAME_DISPLAY_INFO (f); - if (FRAME_VISIBLE_P (f) && wm_supports (f, dpyinfo->Xatom_net_active_window)) + if (FRAME_VISIBLE_P (f) && x_wm_supports (f, dpyinfo->Xatom_net_active_window)) { Lisp_Object frame; XSETFRAME (frame, f); @@ -10949,7 +11211,7 @@ x_free_frame_resources (struct frame *f) free_frame_xic (f); #endif - x_prepare_for_xlibdraw (f); + x_free_cr_resources (f); #ifdef USE_X_TOOLKIT if (f->output_data.x->widget) { @@ -11097,8 +11359,8 @@ x_wm_set_size_hint (struct frame *f, long flags, bool user_position) size_hints.x = f->left_pos; size_hints.y = f->top_pos; - size_hints.height = FRAME_PIXEL_HEIGHT (f); size_hints.width = FRAME_PIXEL_WIDTH (f); + size_hints.height = FRAME_PIXEL_HEIGHT (f); size_hints.width_inc = frame_resize_pixelwise ? 1 : FRAME_COLUMN_WIDTH (f); size_hints.height_inc = frame_resize_pixelwise ? 1 : FRAME_LINE_HEIGHT (f); @@ -11111,34 +11373,21 @@ x_wm_set_size_hint (struct frame *f, long flags, bool user_position) /* Calculate the base and minimum sizes. */ { int base_width, base_height; - int min_rows = 0, min_cols = 0; base_width = FRAME_TEXT_COLS_TO_PIXEL_WIDTH (f, 0); base_height = FRAME_TEXT_LINES_TO_PIXEL_HEIGHT (f, 0); - if (frame_resize_pixelwise) - /* Needed to prevent a bad protocol error crash when making the - frame size very small. */ - { - min_cols = 2 * min_cols; - min_rows = 2 * min_rows; - } - /* The window manager uses the base width hints to calculate the current number of rows and columns in the frame while resizing; min_width and min_height aren't useful for this purpose, since they might not give the dimensions for a - zero-row, zero-column frame. - - We use the base_width and base_height members if we have - them; otherwise, we set the min_width and min_height members - to the size for a zero x zero frame. */ + zero-row, zero-column frame. */ size_hints.flags |= PBaseSize; size_hints.base_width = base_width; size_hints.base_height = base_height + FRAME_MENUBAR_HEIGHT (f); - size_hints.min_width = base_width + min_cols * FRAME_COLUMN_WIDTH (f); - size_hints.min_height = base_height + min_rows * FRAME_LINE_HEIGHT (f); + size_hints.min_width = base_width; + size_hints.min_height = base_height; } /* If we don't need the old flags, we don't need the old hint at all. */ @@ -11399,7 +11648,10 @@ get_bits_and_offset (unsigned long mask, int *bits, int *offset) bool x_display_ok (const char *display) { + /* XOpenDisplay fails if it gets a signal. Block SIGIO which may arrive. */ + unrequest_sigio (); Display *dpy = XOpenDisplay (display); + request_sigio (); if (!dpy) return false; XCloseDisplay (dpy); @@ -11521,7 +11773,6 @@ x_term_init (Lisp_Object display_name, char *xrm_option, char *resource_name) struct terminal *terminal; struct x_display_info *dpyinfo; XrmDatabase xrdb; - ptrdiff_t lim; block_input (); @@ -11579,7 +11830,9 @@ x_term_init (Lisp_Object display_name, char *xrm_option, char *resource_name) /* gtk_init does set_locale. Fix locale before and after. */ fixup_locale (); + unrequest_sigio (); /* See comment in x_display_ok. */ gtk_init (&argc, &argv2); + request_sigio (); fixup_locale (); g_log_remove_handler ("GLib", id); @@ -11629,10 +11882,12 @@ x_term_init (Lisp_Object display_name, char *xrm_option, char *resource_name) argv[argc++] = xrm_option; } turn_on_atimers (false); + unrequest_sigio (); /* See comment in x_display_ok. */ dpy = XtOpenDisplay (Xt_app_con, SSDATA (display_name), resource_name, EMACS_CLASS, emacs_options, XtNumber (emacs_options), &argc, argv); + request_sigio (); turn_on_atimers (true); #ifdef HAVE_X11XTR6 @@ -11643,7 +11898,9 @@ x_term_init (Lisp_Object display_name, char *xrm_option, char *resource_name) #else /* not USE_X_TOOLKIT */ XSetLocaleModifiers (""); + unrequest_sigio (); // See comment in x_display_ok. dpy = XOpenDisplay (SSDATA (display_name)); + request_sigio (); #endif /* not USE_X_TOOLKIT */ #endif /* not USE_GTK*/ @@ -11676,13 +11933,6 @@ x_term_init (Lisp_Object display_name, char *xrm_option, char *resource_name) { char *vendor = ServerVendor (dpy); - /* Protect terminal from GC before removing it from the - list of terminals. */ - struct gcpro gcpro1; - Lisp_Object gcpro_term; - XSETTERMINAL (gcpro_term, terminal); - GCPRO1 (gcpro_term); - /* Temporarily hide the partially initialized terminal. */ terminal_list = terminal->next_terminal; unblock_input (); @@ -11693,7 +11943,6 @@ x_term_init (Lisp_Object display_name, char *xrm_option, char *resource_name) block_input (); terminal->next_terminal = terminal_list; terminal_list = terminal; - UNGCPRO; } /* Don't let the initial kboard remain current longer than necessary. @@ -11713,6 +11962,10 @@ x_term_init (Lisp_Object display_name, char *xrm_option, char *resource_name) dpyinfo->display = dpy; dpyinfo->connection = ConnectionNumber (dpyinfo->display); + /* http://lists.gnu.org/archive/html/emacs-devel/2015-11/msg00194.html */ + dpyinfo->smallest_font_height = 1; + dpyinfo->smallest_char_width = 1; + /* Set the name of the terminal. */ terminal->name = xlispstrdup (display_name); @@ -11720,13 +11973,13 @@ x_term_init (Lisp_Object display_name, char *xrm_option, char *resource_name) XSetAfterFunction (x_current_display, x_trace_wire); #endif - lim = min (PTRDIFF_MAX, SIZE_MAX) - sizeof "@"; Lisp_Object system_name = Fsystem_name (); - if (lim - SBYTES (Vinvocation_name) < SBYTES (system_name)) + ptrdiff_t nbytes; + if (INT_ADD_WRAPV (SBYTES (Vinvocation_name), SBYTES (system_name) + 2, + &nbytes)) memory_full (SIZE_MAX); dpyinfo->x_id = ++x_display_id; - dpyinfo->x_id_name = xmalloc (SBYTES (Vinvocation_name) - + SBYTES (system_name) + 2); + dpyinfo->x_id_name = xmalloc (nbytes); char *nametail = lispstpcpy (dpyinfo->x_id_name, Vinvocation_name); *nametail++ = '@'; lispstpcpy (nametail, system_name); @@ -12043,6 +12296,7 @@ static void x_delete_display (struct x_display_info *dpyinfo) { struct terminal *t; + struct color_name_cache_entry *color_entry, *next_color_entry; /* Close all frames and delete the generic struct terminal for this X display. */ @@ -12072,6 +12326,15 @@ x_delete_display (struct x_display_info *dpyinfo) tail->next = tail->next->next; } + for (color_entry = dpyinfo->color_names; + color_entry; + color_entry = next_color_entry) + { + next_color_entry = color_entry->next; + xfree (color_entry->name); + xfree (color_entry); + } + xfree (dpyinfo->x_id_name); xfree (dpyinfo->x_dnd_atoms); xfree (dpyinfo->color_cells); @@ -12156,7 +12419,7 @@ static struct redisplay_interface x_redisplay_interface = x_draw_window_cursor, x_draw_vertical_window_border, x_draw_window_divider, - x_shift_glyphs_for_insert, + x_shift_glyphs_for_insert, /* Never called; see comment in function. */ x_show_hourglass, x_hide_hourglass }; @@ -12457,9 +12720,11 @@ default is nil, which is the same as `super'. */); DEFVAR_BOOL ("x-frame-normalize-before-maximize", x_frame_normalize_before_maximize, doc: /* Non-nil means normalize frame before maximizing. -If this variable is t, Emacs asks the window manager to give the frame -intermediately its normal size whenever changing from a full-height or -full-width state to the fully maximized one and vice versa. +If this variable is t, Emacs first asks the window manager to give the +frame its normal size, and only then the final state, whenever changing +from a full-height, full-width or full-both state to the maximized one +or when changing from the maximized to the full-height or full-width +state. Set this variable only if your window manager cannot handle the transition between the various maximization states. */);