ATOM_REFS_INIT ("_NET_WM_SYNC_REQUEST", Xatom_net_wm_sync_request)
ATOM_REFS_INIT ("_NET_WM_SYNC_REQUEST_COUNTER", Xatom_net_wm_sync_request_counter)
ATOM_REFS_INIT ("_NET_WM_FRAME_DRAWN", Xatom_net_wm_frame_drawn)
+ ATOM_REFS_INIT ("_NET_WM_FRAME_TIMINGS", Xatom_net_wm_frame_timings)
ATOM_REFS_INIT ("_NET_WM_USER_TIME", Xatom_net_wm_user_time)
ATOM_REFS_INIT ("_NET_WM_USER_TIME_WINDOW", Xatom_net_wm_user_time_window)
ATOM_REFS_INIT ("_NET_CLIENT_LIST_STACKING", Xatom_net_client_list_stacking)
Starting and ending an update
***********************************************************************/
+#if defined HAVE_XSYNC && !defined USE_GTK
+/* Tell the compositing manager to postpone updates of F until a frame
+ has finished drawing. */
+
+static void
+x_sync_update_begin (struct frame *f)
+{
+ XSyncValue value, add;
+ Bool overflow;
+
+ if (FRAME_X_EXTENDED_COUNTER (f) == None)
+ return;
+
+ value = FRAME_X_COUNTER_VALUE (f);
+
+ /* Since a frame is already in progress, there is no point in
+ continuing. */
+ if (XSyncValueLow32 (value) % 2)
+ return;
+
+ /* Since Emacs needs a non-urgent redraw, ensure that value % 4 ==
+ 0. */
+ if (XSyncValueLow32 (value) % 4 == 2)
+ XSyncIntToValue (&add, 3);
+ else
+ XSyncIntToValue (&add, 1);
+
+ XSyncValueAdd (&FRAME_X_COUNTER_VALUE (f),
+ value, add, &overflow);
+
+ if (XSyncValueLow32 (FRAME_X_COUNTER_VALUE (f)) % 4 != 1)
+ emacs_abort ();
+
+ if (overflow)
+ XSyncIntToValue (&FRAME_X_COUNTER_VALUE (f), 1);
+
+ XSyncSetCounter (FRAME_X_DISPLAY (f),
+ FRAME_X_EXTENDED_COUNTER (f),
+ FRAME_X_COUNTER_VALUE (f));
+}
+
+/* Tell the compositing manager that FRAME has been drawn and can be
+ updated. */
+
+static void
+x_sync_update_finish (struct frame *f)
+{
+ XSyncValue value, add;
+ Bool overflow;
+
+ if (FRAME_X_EXTENDED_COUNTER (f) == None)
+ return;
+
+ if (FRAME_X_OUTPUT (f)->ext_sync_end_pending_p)
+ return;
+
+ value = FRAME_X_COUNTER_VALUE (f);
+
+ if (!(XSyncValueLow32 (value) % 2))
+ return;
+
+ XSyncIntToValue (&add, 1);
+ XSyncValueAdd (&FRAME_X_COUNTER_VALUE (f),
+ value, add, &overflow);
+
+ if (overflow)
+ XSyncIntToValue (&FRAME_X_COUNTER_VALUE (f), 0);
+
+ XSyncSetCounter (FRAME_X_DISPLAY (f),
+ FRAME_X_EXTENDED_COUNTER (f),
+ FRAME_X_COUNTER_VALUE (f));
+
+ /* TODO: implement sync fences. */
+}
+#endif
+
/* Start an update of frame F. This function is installed as a hook
for update_begin, i.e. it is called when update_begin is called.
This function is called prior to calls to gui_update_window_begin for
static void
x_update_begin (struct frame *f)
{
+#if defined HAVE_XSYNC && !defined USE_GTK
+ x_sync_update_begin (f);
+#else
/* Nothing to do. */
+#endif
}
/* Draw a vertical window border from (x,y0) to (x,y1) */
#ifdef USE_CAIRO
if (!FRAME_X_DOUBLE_BUFFERED_P (f) && FRAME_CR_CONTEXT (f))
- {
- block_input ();
- cairo_surface_flush (cairo_get_target (FRAME_CR_CONTEXT (f)));
- unblock_input ();
- }
+ cairo_surface_flush (cairo_get_target (FRAME_CR_CONTEXT (f)));
#endif
-#ifndef XFlush
- block_input ();
- XFlush (FRAME_X_DISPLAY (f));
- unblock_input ();
+ /* If double buffering is disabled, finish the update here.
+ Otherwise, finish the update when the back buffer is next
+ displayed. */
+#if defined HAVE_XSYNC && !defined USE_GTK
+#ifdef HAVE_XDBE
+ if (!FRAME_X_DOUBLE_BUFFERED_P (f))
+#endif
+ x_sync_update_finish (f);
#endif
}
if (!buffer_flipping_blocked_p ()
&& FRAME_X_NEED_BUFFER_FLIP (f))
show_back_buffer (f);
+
+#if defined HAVE_XSYNC && !defined USE_GTK
+ if (FRAME_X_DOUBLE_BUFFERED_P (f))
+ x_sync_update_finish (f);
+#endif
#endif
#ifdef HAVE_XSYNC
if (FRAME_X_OUTPUT (f)->ext_sync_end_pending_p
&& FRAME_X_EXTENDED_COUNTER (f) != None)
{
- current = FRAME_X_OUTPUT (f)->current_extended_counter_value;
+ current = FRAME_X_COUNTER_VALUE (f);
if (XSyncValueLow32 (current) % 2)
XSyncIntToValue (&add, 1);
else
XSyncIntToValue (&add, 2);
- XSyncValueAdd (&FRAME_X_OUTPUT (f)->current_extended_counter_value,
+ XSyncValueAdd (&FRAME_X_COUNTER_VALUE (f),
current, add, &overflow_p);
if (overflow_p)
XSyncSetCounter (FRAME_X_DISPLAY (f),
FRAME_X_EXTENDED_COUNTER (f),
- FRAME_X_OUTPUT (f)->current_extended_counter_value);
+ FRAME_X_COUNTER_VALUE (f));
FRAME_X_OUTPUT (f)->ext_sync_end_pending_p = false;
}
}
else if (event->xclient.data.l[4] == 1)
{
- XSyncIntsToValue (&FRAME_X_OUTPUT (f)->current_extended_counter_value,
- event->xclient.data.l[2], event->xclient.data.l[3]);
+ XSyncIntsToValue (&FRAME_X_COUNTER_VALUE (f),
+ event->xclient.data.l[2],
+ event->xclient.data.l[3]);
FRAME_X_OUTPUT (f)->ext_sync_end_pending_p = true;
}
goto done;
}
+#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)
+ goto done;
+#endif
+
xft_settings_event (dpyinfo, event);
f = any;
Xatom_net_wm_state_shaded, Xatom_net_frame_extents, Xatom_net_current_desktop,
Xatom_net_workarea, Xatom_net_wm_opaque_region, Xatom_net_wm_ping,
Xatom_net_wm_sync_request, Xatom_net_wm_sync_request_counter,
- Xatom_net_wm_frame_drawn, Xatom_net_wm_user_time,
+ Xatom_net_wm_frame_drawn, Xatom_net_wm_frame_timings, Xatom_net_wm_user_time,
Xatom_net_wm_user_time_window, Xatom_net_client_list_stacking,
Xatom_net_wm_pid;
#endif
#ifdef HAVE_XSYNC
-#define FRAME_X_BASIC_COUNTER(f) FRAME_X_OUTPUT (f)->basic_frame_counter
-#define FRAME_X_EXTENDED_COUNTER(f) FRAME_X_OUTPUT (f)->extended_frame_counter
+#define FRAME_X_BASIC_COUNTER(f) \
+ FRAME_X_OUTPUT (f)->basic_frame_counter
+#define FRAME_X_EXTENDED_COUNTER(f) \
+ FRAME_X_OUTPUT (f)->extended_frame_counter
+#define FRAME_X_COUNTER_VALUE(f) \
+ FRAME_X_OUTPUT (f)->current_extended_counter_value
#endif
/* This is the Colormap which frame F uses. */