gdk_x11_window_set_frame_sync_enabled (window, FALSE);
}
#endif
+
+#if defined HAVE_XSYNC && !defined USE_GTK
+ /* Frame synchronization can't be used in child frames since
+ they are not directly managed by the compositing manager.
+ Re-enabling vsync in former child frames also leads to
+ inconsistent display. In addition, they can only be updated
+ outside of a toplevel frame. */
+ FRAME_X_OUTPUT (f)->use_vsync_p = false;
+ FRAME_X_WAITING_FOR_DRAW (f) = false;
+#endif
unblock_input ();
fset_parent_frame (f, new_value);
}
#ifdef HAVE_XSYNC
- if (dpyinfo->xsync_supported_p)
+ if (dpyinfo->xsync_supported_p
+ /* Frame synchronization isn't supported in child frames. */
+ && NILP (parent_frame)
+ && !f->output_data.x->explicit_parent)
{
#ifndef HAVE_GTK3
XSyncValue initial_value;
((STRINGP (value)
&& !strcmp (SSDATA (value), "extended")) ? 2 : 1));
#endif
+
+#ifndef USE_GTK
+ if (FRAME_X_EXTENDED_COUNTER (f))
+ FRAME_X_OUTPUT (f)->use_vsync_p
+ = x_wm_supports (f, dpyinfo->Xatom_net_wm_frame_drawn);
+#endif
}
#endif
x_menu_show (struct frame *f, int x, int y, int menuflags,
Lisp_Object title, const char **error_name)
{
+#ifdef HAVE_X_WINDOWS
+ Window dummy_window;
+#endif
Window root;
XMenu *menu;
int pane, selidx, lpane, status;
inhibit_garbage_collection ();
#ifdef HAVE_X_WINDOWS
- {
- /* Adjust coordinates to relative to the outer (window manager) window. */
- int left_off, top_off;
+ XTranslateCoordinates (FRAME_X_DISPLAY (f),
- x_real_pos_and_offsets (f, &left_off, NULL, &top_off, NULL,
- NULL, NULL, NULL, NULL, NULL);
+ /* From-window, to-window. */
+ FRAME_X_WINDOW (f),
+ FRAME_DISPLAY_INFO (f)->root_window,
- x += left_off;
- y += top_off;
- }
-#endif /* HAVE_X_WINDOWS */
+ /* From-position, to-position. */
+ x, y, &x, &y,
+ /* Child of win. */
+ &dummy_window);
+#else
+ /* MSDOS without X support. */
x += f->left_pos;
y += f->top_pos;
+#endif
/* Create all the necessary panes and their items. */
maxwidth = maxlines = lines = i = 0;
***********************************************************************/
#if defined HAVE_XSYNC && !defined USE_GTK
+static Bool
+x_sync_is_frame_drawn_event (Display *dpy, XEvent *event,
+ XPointer user_data)
+{
+ struct frame *f;
+ struct x_display_info *dpyinfo;
+
+ f = (struct frame *) user_data;
+ dpyinfo = FRAME_DISPLAY_INFO (f);
+
+ if (event->type == ClientMessage
+ && (event->xclient.message_type
+ == dpyinfo->Xatom_net_wm_frame_drawn)
+ && event->xclient.window == FRAME_OUTER_WINDOW (f))
+ return True;
+
+ return False;
+}
+
+/* Wait for the compositing manager to finish drawing the last frame.
+ If the compositing manager has already drawn everything, do
+ nothing. */
+
+static void
+x_sync_wait_for_frame_drawn_event (struct frame *f)
+{
+ XEvent event;
+
+ if (!FRAME_X_WAITING_FOR_DRAW (f))
+ return;
+
+ /* Wait for the frame drawn message to arrive. */
+ XIfEvent (FRAME_X_DISPLAY (f), &event,
+ x_sync_is_frame_drawn_event, (XPointer) f);
+ FRAME_X_WAITING_FOR_DRAW (f) = false;
+}
+
/* Tell the compositing manager to postpone updates of F until a frame
has finished drawing. */
if (XSyncValueLow32 (value) % 2)
return;
+ /* Wait for a pending frame draw event if the last frame has not yet
+ been drawn if F isn't double buffered. (In double buffered
+ frames, this happens before buffer flipping). */
+
+#ifdef HAVE_XDBE
+ if (!FRAME_X_DOUBLE_BUFFERED_P (f))
+#endif
+ x_sync_wait_for_frame_drawn_event (f);
+
/* Since Emacs needs a non-urgent redraw, ensure that value % 4 ==
0. */
if (XSyncValueLow32 (value) % 4 == 2)
FRAME_X_EXTENDED_COUNTER (f),
FRAME_X_COUNTER_VALUE (f));
- /* TODO: implement sync fences. */
+ /* FIXME: this leads to freezes if the compositing manager crashes
+ in the meantime. */
+ if (FRAME_OUTPUT_DATA (f)->use_vsync_p)
+ FRAME_X_WAITING_FOR_DRAW (f) = true;
+}
+
+/* Handle a _NET_WM_FRAME_DRAWN message from the compositor. */
+
+static void
+x_sync_handle_frame_drawn (struct x_display_info *dpyinfo,
+ XEvent *message, struct frame *f)
+{
+ if (FRAME_OUTER_WINDOW (f) == message->xclient.window)
+ FRAME_X_WAITING_FOR_DRAW (f) = false;
}
#endif
static void
show_back_buffer (struct frame *f)
{
+ XdbeSwapInfo swap_info;
+#ifdef USE_CAIRO
+ cairo_t *cr;
+#endif
+
block_input ();
if (FRAME_X_DOUBLE_BUFFERED_P (f))
{
+#if defined HAVE_XSYNC && !defined USE_GTK
+ /* Wait for drawing of the previous frame to complete before
+ displaying this new frame. */
+ x_sync_wait_for_frame_drawn_event (f);
+#endif
+
#ifdef USE_CAIRO
- cairo_t *cr = FRAME_CR_CONTEXT (f);
+ cr = FRAME_CR_CONTEXT (f);
if (cr)
cairo_surface_flush (cairo_get_target (cr));
#endif
- XdbeSwapInfo swap_info;
memset (&swap_info, 0, sizeof (swap_info));
swap_info.swap_window = FRAME_X_WINDOW (f);
swap_info.swap_action = XdbeCopied;
FRAME_X_COUNTER_VALUE (f));
FRAME_X_OUTPUT (f)->ext_sync_end_pending_p = false;
+
+#ifndef USE_GTK
+ if (FRAME_OUTPUT_DATA (f)->use_vsync_p)
+ FRAME_X_WAITING_FOR_DRAW (f) = true;
+#endif
}
#else
if (FRAME_X_OUTPUT (f)->xg_sync_end_pending_p)
#if defined HAVE_XSYNC && !defined USE_GTK
/* These messages are sent by the compositing manager after a
frame is drawn under extended synchronization. */
- if (event->xclient.message_type == dpyinfo->Xatom_net_wm_frame_drawn
- || event->xclient.message_type == dpyinfo->Xatom_net_wm_frame_timings)
+ if (event->xclient.message_type
+ == dpyinfo->Xatom_net_wm_frame_drawn)
+ {
+ if (any)
+ x_sync_handle_frame_drawn (dpyinfo, (XEvent *) event, any);
+
+ goto done;
+ }
+
+ if (event->xclient.message_type
+ == dpyinfo->Xatom_net_wm_frame_timings)
goto done;
#endif
#endif
#ifdef HAVE_XSYNC
+ /* The "basic frame counter" used for resize synchronization. */
XSyncCounter basic_frame_counter;
+
+ /* The "extended frame counter" used for frame synchronization. */
XSyncCounter extended_frame_counter;
+
+ /* The pending value of the basic counter. */
XSyncValue pending_basic_counter_value;
+
+ /* The current value of the extended counter. */
XSyncValue current_extended_counter_value;
+ /* Whether or not basic resize synchronization is in progress. */
bool_bf sync_end_pending_p : 1;
+
+ /* Whether or not extended resize synchronization is in
+ progress. */
bool_bf ext_sync_end_pending_p : 1;
+
#ifdef HAVE_GTK3
+ /* Whether or not GDK resize synchronization is in progress. */
bool_bf xg_sync_end_pending_p : 1;
#endif
+
+ /* Whether or Emacs is waiting for the compositing manager to draw a
+ frame. */
+ bool_bf waiting_for_frame_p : 1;
+
+#ifndef USE_GTK
+ /* Whether or not Emacs should wait for the compositing manager to
+ draw frames before starting a new frame. */
+ bool_bf use_vsync_p : 1;
+#endif
#endif
/* Relief GCs, colors etc. */
FRAME_X_OUTPUT (f)->basic_frame_counter
#define FRAME_X_EXTENDED_COUNTER(f) \
FRAME_X_OUTPUT (f)->extended_frame_counter
+#define FRAME_X_WAITING_FOR_DRAW(f) \
+ FRAME_X_OUTPUT (f)->waiting_for_frame_p
#define FRAME_X_COUNTER_VALUE(f) \
FRAME_X_OUTPUT (f)->current_extended_counter_value
#endif