/* 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.
#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. */
#include <fcntl.h>
#include <errno.h>
#include <sys/stat.h>
-/* Caused redefinition of DBL_DIG on Netbsd; seems not to be needed. */
-/* #include <sys/param.h> */
-
-#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"
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);
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);
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);
return CALLN (Fapply, intern ("concat"), Fnreverse (acc));
{
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;
#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));
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 evently (e.g., when dealing
+ 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.
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;
/* 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)
{
XClearArea (dpy, window, x, y, width, height, exposures);
}
-
void
x_clear_area (struct frame *f, int x, int y, int width, int height)
{
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)
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;
}
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
#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
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);
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. */
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;
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
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);
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. */
{
struct font *font = XFONT_OBJECT (font_object);
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);
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
XSelectInput (dpy, wmcheck_window, StructureNotifyMask);
if (x_had_errors_p (dpy))
{
- x_uncatch_errors ();
+ x_uncatch_errors_after_check ();
unblock_input ();
return false;
}
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)
*sticky = true;
}
+#ifdef USE_XCB
+ free (prop);
+#else
if (tmp_data) XFree (tmp_data);
+#endif
+
unblock_input ();
return ! is_hidden;
}
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))));
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),
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));
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);
/* 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. */
struct terminal *terminal;
struct x_display_info *dpyinfo;
XrmDatabase xrdb;
- ptrdiff_t lim;
+#ifdef USE_XCB
+ xcb_connection_t *xcb_conn;
+#endif
block_input ();
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);
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);
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);