X-Git-Url: https://code.delx.au/gnu-emacs/blobdiff_plain/dcf18b5c84fc9704bb2d1cfd01519710f105d126..3d82a8ee4bd392ae536c8c3640140d1d0f594f44:/src/xterm.c diff --git a/src/xterm.c b/src/xterm.c index 691ede58b4..1f71afd7f7 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, 1993-2015 Free Software Foundation, Inc. +Copyright (C) 1989, 1993-2016 Free Software Foundation, Inc. This file is part of GNU Emacs. @@ -28,7 +28,6 @@ along with GNU Emacs. If not, see . */ #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. */ @@ -58,30 +57,23 @@ 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 "xwidget.h" #include "fontset.h" #include "termhooks.h" #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" @@ -552,7 +544,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; } @@ -575,10 +567,11 @@ 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); + specbind (Qredisplay_dont_pause, Qt); + redisplay_preserve_echo_area (31); f = XFRAME (XCAR (frames)); frames = XCDR (frames); @@ -620,24 +613,18 @@ x_cr_export_frames (Lisp_Object frames, cairo_surface_type_t surface_type) cr = cairo_create (surface); cairo_surface_destroy (surface); record_unwind_protect (x_cr_destroy, make_save_ptr (cr)); - unblock_input (); while (1) { - QUIT; - - block_input (); 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); FRAME_CR_CONTEXT (f) = NULL; - unblock_input (); if (NILP (frames)) break; - block_input (); cairo_surface_show_page (surface); f = XFRAME (XCAR (frames)); frames = XCDR (frames); @@ -645,23 +632,24 @@ x_cr_export_frames (Lisp_Object frames, cairo_surface_type_t surface_type) height = FRAME_PIXEL_HEIGHT (f); if (surface_set_size_func) (*surface_set_size_func) (surface, width, height); + unblock_input (); + QUIT; + block_input (); } #ifdef CAIRO_HAS_PNG_FUNCTIONS if (surface_type == CAIRO_SURFACE_TYPE_IMAGE) { - block_input (); cairo_surface_flush (surface); cairo_surface_write_to_png_stream (surface, x_cr_accumulate_data, &acc); - unblock_input (); } #endif + unblock_input (); + 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 */ @@ -1325,7 +1313,6 @@ x_draw_fringe_bitmap (struct window *w, struct glyph_row *row, struct draw_fring { struct frame *f = XFRAME (WINDOW_FRAME (w)); Display *display = FRAME_X_DISPLAY (f); - Window window = FRAME_X_WINDOW (f); GC gc = f->output_data.x->normal_gc; struct face *face = p->face; @@ -1368,6 +1355,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); char *bits; Pixmap pixmap, clipmask = (Pixmap) 0; int depth = DefaultDepthOfScreen (FRAME_X_SCREEN (f)); @@ -1724,6 +1712,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) @@ -2194,6 +2187,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; @@ -2204,9 +2241,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); } @@ -2220,6 +2258,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 @@ -2292,15 +2375,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); } @@ -2314,8 +2409,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 (); @@ -3409,6 +3512,10 @@ x_draw_glyph_string (struct glyph_string *s) x_draw_image_glyph_string (s); break; + case XWIDGET_GLYPH: + x_draw_xwidget_glyph_string (s); + break; + case STRETCH_GLYPH: x_draw_stretch_glyph_string (s); break; @@ -3651,7 +3758,7 @@ x_delete_glyphs (struct frame *f, register int n) /* Like XClearArea, but check that WIDTH and HEIGHT are reasonable. If they are <= 0, this is probably an error. */ -static void +static ATTRIBUTE_UNUSED void x_clear_area1 (Display *dpy, Window window, int x, int y, int width, int height, int exposures) { @@ -3659,7 +3766,6 @@ x_clear_area1 (Display *dpy, Window window, XClearArea (dpy, window, x, y, width, height, exposures); } - void x_clear_area (struct frame *f, int x, int y, int width, int height) { @@ -4879,7 +4985,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) @@ -5402,6 +5508,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) @@ -7353,10 +7461,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; @@ -7368,6 +7473,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; @@ -7428,9 +7535,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 */ @@ -7584,7 +7688,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; @@ -7600,7 +7704,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; @@ -8111,7 +8215,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; @@ -8280,17 +8384,46 @@ 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 @@ -8299,24 +8432,26 @@ handle_one_xevent (struct x_display_info *dpyinfo, #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) != event->xconfigure.height - || FRAME_PIXEL_WIDTH (f) != event->xconfigure.width) + if (FRAME_PIXEL_HEIGHT (f) != configureEvent.xconfigure.height + || FRAME_PIXEL_WIDTH (f) != configureEvent.xconfigure.width) SET_FRAME_GARBAGED (f); - FRAME_PIXEL_HEIGHT (f) = event->xconfigure.height; - FRAME_PIXEL_WIDTH (f) = event->xconfigure.width; + 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 @@ -8327,8 +8462,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); @@ -8528,7 +8663,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++; } @@ -8789,6 +8924,10 @@ x_draw_bar_cursor (struct window *w, struct glyph_row *row, int width, enum text if (cursor_glyph == NULL) return; + /* Experimental avoidance of cursor on xwidget. */ + if (cursor_glyph->type == XWIDGET_GLYPH) + return; + /* If on an image, draw like a normal cursor. That's usually better visible than drawing a bar, esp. if the image is large so that the bar might not be in the window. */ @@ -9081,6 +9220,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; @@ -9095,6 +9236,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 @@ -9108,10 +9252,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); @@ -9120,10 +9268,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. */ @@ -9405,7 +9580,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); @@ -9418,7 +9597,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); @@ -9441,9 +9621,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 @@ -9779,8 +9975,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; @@ -9816,10 +10012,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; } @@ -9907,39 +10102,69 @@ get_current_wm_state (struct frame *f, int *size_state, bool *sticky) { - Atom actual_type; - unsigned long actual_size, bytes_remaining; - int i, rc, actual_format; + unsigned long actual_size; + int i; bool is_hidden = false; struct x_display_info *dpyinfo = FRAME_DISPLAY_INFO (f); long max_len = 65536; + Atom target_type = XA_ATOM; + /* If XCB is available, we can avoid three XSync calls. */ +#ifdef USE_XCB + xcb_get_property_cookie_t prop_cookie; + xcb_get_property_reply_t *prop; + xcb_atom_t *reply_data; +#else Display *dpy = FRAME_X_DISPLAY (f); + unsigned long bytes_remaining; + int rc, actual_format; + Atom actual_type; unsigned char *tmp_data = NULL; - Atom target_type = XA_ATOM; + Atom *reply_data; +#endif *sticky = false; *size_state = FULLSCREEN_NONE; block_input (); + +#ifdef USE_XCB + prop_cookie = xcb_get_property (dpyinfo->xcb_connection, 0, window, + dpyinfo->Xatom_net_wm_state, + target_type, 0, max_len); + prop = xcb_get_property_reply (dpyinfo->xcb_connection, prop_cookie, NULL); + if (prop && prop->type == target_type) + { + int actual_bytes = xcb_get_property_value_length (prop); + eassume (0 <= actual_bytes); + actual_size = actual_bytes / sizeof *reply_data; + reply_data = xcb_get_property_value (prop); + } + else + { + actual_size = 0; + is_hidden = FRAME_ICONIFIED_P (f); + } +#else x_catch_errors (dpy); rc = XGetWindowProperty (dpy, window, dpyinfo->Xatom_net_wm_state, 0, max_len, False, target_type, &actual_type, &actual_format, &actual_size, &bytes_remaining, &tmp_data); - if (rc != Success || actual_type != target_type || x_had_errors_p (dpy)) + if (rc == Success && actual_type == target_type && ! x_had_errors_p (dpy)) + reply_data = (Atom *) tmp_data; + else { - if (tmp_data) XFree (tmp_data); - x_uncatch_errors (); - unblock_input (); - return !FRAME_ICONIFIED_P (f); + actual_size = 0; + is_hidden = FRAME_ICONIFIED_P (f); } x_uncatch_errors (); +#endif for (i = 0; i < actual_size; ++i) { - Atom a = ((Atom*)tmp_data)[i]; + Atom a = reply_data[i]; if (a == dpyinfo->Xatom_net_wm_state_hidden) is_hidden = true; else if (a == dpyinfo->Xatom_net_wm_state_maximized_horz) @@ -9962,7 +10187,12 @@ get_current_wm_state (struct frame *f, *sticky = true; } +#ifdef USE_XCB + free (prop); +#else if (tmp_data) XFree (tmp_data); +#endif + unblock_input (); return ! is_hidden; } @@ -9973,7 +10203,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; @@ -9982,7 +10212,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) { @@ -10152,6 +10382,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; @@ -10170,22 +10402,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); @@ -10198,6 +10442,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 @@ -10358,7 +10606,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)))); @@ -10368,7 +10616,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), @@ -10378,10 +10626,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)); @@ -10497,8 +10746,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. */ @@ -10561,7 +10808,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); @@ -11153,8 +11400,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); @@ -11167,34 +11414,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. */ @@ -11580,7 +11814,9 @@ 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; +#ifdef USE_XCB + xcb_connection_t *xcb_conn; +#endif block_input (); @@ -11719,6 +11955,25 @@ x_term_init (Lisp_Object display_name, char *xrm_option, char *resource_name) return 0; } +#ifdef USE_XCB + xcb_conn = XGetXCBConnection (dpy); + if (xcb_conn == 0) + { +#ifdef USE_GTK + xg_display_close (dpy); +#else +#ifdef USE_X_TOOLKIT + XtCloseDisplay (dpy); +#else + XCloseDisplay (dpy); +#endif +#endif /* ! USE_GTK */ + + unblock_input (); + return 0; + } +#endif + /* We have definitely succeeded. Record the new connection. */ dpyinfo = xzalloc (sizeof *dpyinfo); @@ -11741,13 +11996,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 (); @@ -11758,7 +12006,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. @@ -11777,6 +12024,13 @@ x_term_init (Lisp_Object display_name, char *xrm_option, char *resource_name) dpyinfo->name_list_element = Fcons (display_name, Qnil); dpyinfo->display = dpy; dpyinfo->connection = ConnectionNumber (dpyinfo->display); +#ifdef USE_XCB + dpyinfo->xcb_connection = xcb_conn; +#endif + + /* 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); @@ -11785,13 +12039,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); @@ -12108,6 +12362,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. */ @@ -12137,6 +12392,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);