Commit 3f2af30b authored by Keith Packard's avatar Keith Packard
Browse files

Add support for the 'Present' extension. [v3]



This makes updating the eyes nicely vblank synchronized.

v2:
	Ensure extensions exist before calling query_version

	These calls add calls to xcb_get_extension_data before calling
	query_version calls, as those calls will mark the connection
	with an error if made against an X server without the
	extension present.
Suggested-by: Uli Schlachter's avatarUli Schlachter <psychon@znc.in>

v3:
	check the 'present' field in the return from
	xcb_get_extension_data; the xcb_get_extension_data call will
	always succeed (save for out of memory), the only way to tell
	if the extension is supported in the target X server is to
	test the 'present' field in the query extension reply value.
Signed-off-by: Keith Packard's avatarKeith Packard <keithp@keithp.com>
parent 46dac260
......@@ -63,6 +63,9 @@ static XtResource resources[] = {
goffset(height), XtRImmediate, (XtPointer) 100},
{XtNforeground, XtCForeground, XtRPixel, sizeof(Pixel),
offset(pixel[PART_PUPIL]), XtRString, XtDefaultForeground},
{XtNbackgroundPixmap, XtCPixmap, XtRPixmap, sizeof(Pixmap),
XtOffsetOf(CoreRec,core.background_pixmap),
XtRImmediate, (XtPointer)None},
{XtNoutline, XtCForeground, XtRPixel, sizeof(Pixel),
offset(pixel[PART_OUTLINE]), XtRString, XtDefaultForeground},
{XtNcenterColor, XtCBackground, XtRPixel, sizeof (Pixel),
......@@ -76,6 +79,10 @@ static XtResource resources[] = {
#ifdef XRENDER
{XtNrender, XtCBoolean, XtRBoolean, sizeof(Boolean),
offset(render), XtRImmediate, (XtPointer) TRUE },
#endif
#ifdef PRESENT
{XtNpresent, XtCBoolean, XtRBoolean, sizeof(Boolean),
offset(present), XtRImmediate, (XtPointer) TRUE },
#endif
{XtNdistance, XtCBoolean, XtRBoolean, sizeof(Boolean),
offset(distance), XtRImmediate, (XtPointer) FALSE },
......@@ -113,6 +120,129 @@ static void ClassInitialize(void)
WidgetClass eyesWidgetClass = (WidgetClass) &eyesClassRec;
#ifdef PRESENT
static void CheckPresent(EyesWidget w) {
const xcb_query_extension_reply_t *xfixes_ext_reply;
const xcb_query_extension_reply_t *damage_ext_reply;
const xcb_query_extension_reply_t *present_ext_reply;
xcb_xfixes_query_version_cookie_t xfixes_cookie;
xcb_xfixes_query_version_reply_t *xfixes_reply;
xcb_damage_query_version_cookie_t damage_cookie;
xcb_damage_query_version_reply_t *damage_reply;
xcb_present_query_version_cookie_t present_cookie;
xcb_present_query_version_reply_t *present_reply;
if (!w->eyes.present)
return;
xcb_prefetch_extension_data(xt_xcb(w), &xcb_xfixes_id);
xcb_prefetch_extension_data(xt_xcb(w), &xcb_damage_id);
xcb_prefetch_extension_data(xt_xcb(w), &xcb_present_id);
xfixes_ext_reply = xcb_get_extension_data(xt_xcb(w), &xcb_xfixes_id);
damage_ext_reply = xcb_get_extension_data(xt_xcb(w), &xcb_damage_id);
present_ext_reply = xcb_get_extension_data(xt_xcb(w), &xcb_present_id);
if (xfixes_ext_reply == NULL || !xfixes_ext_reply->present
|| damage_ext_reply == NULL || !damage_ext_reply->present
|| present_ext_reply == NULL || !present_ext_reply->present)
{
w->eyes.present = FALSE;
}
if (!w->eyes.present)
return;
/* Now tell the server which versions of the extensions we support */
xfixes_cookie = xcb_xfixes_query_version(xt_xcb(w),
XCB_XFIXES_MAJOR_VERSION,
XCB_XFIXES_MINOR_VERSION);
damage_cookie = xcb_damage_query_version(xt_xcb(w),
XCB_DAMAGE_MAJOR_VERSION,
XCB_DAMAGE_MINOR_VERSION);
present_cookie = xcb_present_query_version(xt_xcb(w),
XCB_PRESENT_MAJOR_VERSION,
XCB_PRESENT_MINOR_VERSION);
xfixes_reply = xcb_xfixes_query_version_reply(xt_xcb(w),
xfixes_cookie,
NULL);
free(xfixes_reply);
damage_reply = xcb_damage_query_version_reply(xt_xcb(w),
damage_cookie,
NULL);
free(damage_reply);
present_reply = xcb_present_query_version_reply(xt_xcb(w),
present_cookie,
NULL);
free(present_reply);
}
static void MakePresentData(EyesWidget w) {
xcb_generic_event_t *ev;
if (!w->eyes.present)
return;
if (!w->eyes.back_buffer) {
xcb_create_pixmap(xt_xcb(w),
w->core.depth,
w->eyes.back_buffer = xcb_generate_id(xt_xcb(w)),
XtWindow(w),
w->core.width,
w->core.height);
}
if (!w->eyes.back_damage) {
xcb_damage_create(xt_xcb(w),
w->eyes.back_damage = xcb_generate_id(xt_xcb(w)),
w->eyes.back_buffer,
XCB_DAMAGE_REPORT_LEVEL_NON_EMPTY);
xcb_xfixes_create_region(xt_xcb(w),
w->eyes.back_region = xcb_generate_id(xt_xcb(w)),
0, NULL);
}
}
static void UpdatePresent(EyesWidget w) {
if (w->eyes.back_buffer) {
xcb_damage_subtract(xt_xcb(w),
w->eyes.back_damage,
None,
w->eyes.back_region);
xcb_present_pixmap(xt_xcb(w),
XtWindow(w),
w->eyes.back_buffer,
0,
None,
w->eyes.back_region,
0, 0,
None,
None,
None,
0,
0, 1, 0,
0, NULL);
}
}
#endif
#ifdef PRESENT
#define EyesDrawable(w) (w->eyes.back_buffer ? w->eyes.back_buffer : XtWindow(w))
#else
#define EyesDrawable(w) XtWindow(w)
#endif
static void draw_it_core(EyesWidget w);
static void EyesGeneric(Widget w, XtPointer closure, XEvent *event, Boolean *continue_to_dispatch)
{
draw_it_core((EyesWidget) w);
}
/* ARGSUSED */
static void Initialize (
Widget greq,
......@@ -197,6 +327,11 @@ static void Initialize (
w->eyes.fill[i] = XRenderCreateSolidFill(XtDisplay (w), &rc);
}
#endif
#ifdef PRESENT
w->eyes.back_buffer = None;
w->eyes.back_damage = None;
CheckPresent(w);
#endif
}
static void
......@@ -213,7 +348,7 @@ drawEllipse(EyesWidget w, enum EyesPart part,
Trectangle(&w->eyes.t, &tpos, &pos);
if (part == PART_CLEAR) {
XFillRectangle(XtDisplay(w), XtWindow(w),
XFillRectangle(XtDisplay(w), EyesDrawable(w),
w->eyes.gc[PART_CENTER],
(int)pos.x, (int)pos.y,
(int)pos.width+2, (int)pos.height+2);
......@@ -275,7 +410,7 @@ drawEllipse(EyesWidget w, enum EyesPart part,
TPOINT_NONE, TPOINT_NONE, diam);
XFillArc(XtDisplay(w),
part == PART_SHAPE ? w->eyes.shape_mask : XtWindow(w),
part == PART_SHAPE ? w->eyes.shape_mask : EyesDrawable(w),
w->eyes.gc[part],
(int)(pos.x + 0.5), (int)(pos.y + 0.5),
(int)(pos.width + 0.0), (int)(pos.height + 0.0),
......@@ -406,11 +541,17 @@ eyeBall(EyesWidget w,
static void repaint_window (EyesWidget w)
{
if (XtIsRealized ((Widget) w)) {
#ifdef PRESENT
MakePresentData(w);
#endif
eyeLiner (w, TRUE, 0);
eyeLiner (w, TRUE, 1);
computePupils (w, w->eyes.mouse, w->eyes.pupil);
eyeBall (w, TRUE, NULL, 0);
eyeBall (w, TRUE, NULL, 1);
#ifdef PRESENT
UpdatePresent(w);
#endif
}
}
......@@ -440,6 +581,9 @@ drawEyes(EyesWidget w, TPoint mouse)
TPoint newpupil[2];
int num;
#ifdef PRESENT
MakePresentData(w);
#endif
if (TPointEqual (mouse, w->eyes.mouse)) {
if (delays[w->eyes.update + 1] != 0)
++w->eyes.update;
......@@ -452,6 +596,9 @@ drawEyes(EyesWidget w, TPoint mouse)
w->eyes.mouse = mouse;
w->eyes.update = 0;
#ifdef PRESENT
UpdatePresent(w);
#endif
}
static void draw_it_core(EyesWidget w)
......@@ -497,12 +644,25 @@ static void Resize (Widget gw)
if (XtIsRealized (gw))
{
XClearWindow (dpy, XtWindow (w));
SetTransform (&w->eyes.t,
0, w->core.width,
w->core.height, 0,
W_MIN_X, W_MAX_X,
W_MIN_Y, W_MAX_Y);
#ifdef PRESENT
if (w->eyes.back_buffer) {
xcb_free_pixmap(xt_xcb(w),
w->eyes.back_buffer);
w->eyes.back_buffer = None;
xcb_damage_destroy(xt_xcb(w),
w->eyes.back_damage);
w->eyes.back_damage = None;
}
MakePresentData(w);
#endif
if (EyesDrawable(w) == XtWindow(w))
XClearWindow (dpy, XtWindow (w));
#ifdef XRENDER
if (w->eyes.picture) {
XRenderFreePicture(dpy, w->eyes.picture);
......@@ -537,7 +697,7 @@ static void Resize (Widget gw)
pf = XRenderFindVisualFormat(dpy,
DefaultVisualOfScreen(w->core.screen));
if (pf)
w->eyes.picture = XRenderCreatePicture(dpy, XtWindow (w),
w->eyes.picture = XRenderCreatePicture(dpy, EyesDrawable (w),
pf, 0, &pa);
}
#endif
......
......@@ -35,6 +35,8 @@
#define XtNrender "render"
#define XtNdistance "distance"
#define XtNpresent "present"
enum EyesPart {
PART_CLEAR = -1,
......
......@@ -8,6 +8,13 @@
#include <X11/extensions/Xrender.h>
#endif
#include "transform.h"
#ifdef PRESENT
#include <X11/Xlib-xcb.h>
#include <xcb/xcb.h>
#include <xcb/present.h>
#include <xcb/xfixes.h>
#include <xcb/damage.h>
#endif
#define SEG_BUFF_SIZE 128
......@@ -30,10 +37,18 @@ typedef struct {
Boolean render;
Picture picture;
Picture fill[PART_SHAPE];
#endif
#ifdef PRESENT
Pixmap back_buffer;
xcb_damage_damage_t back_damage;
xcb_xfixes_region_t back_region;
Boolean present;
#endif
Boolean distance;
} EyesPart;
#define xt_xcb(w) (XGetXCBConnection(XtDisplay(w)))
/* Full instance record declaration */
typedef struct _EyesRec {
CorePart core;
......
......@@ -22,8 +22,8 @@
SUBDIRS = man
bin_PROGRAMS = xeyes
AM_CFLAGS = $(XEYES_CFLAGS) $(XRENDER_CFLAGS) $(CWARNFLAGS)
xeyes_LDADD = $(XEYES_LIBS) $(XRENDER_LIBS) -lm
AM_CFLAGS = $(XEYES_CFLAGS) $(XRENDER_CFLAGS) $(PRESENT_CFLAGS) $(CWARNFLAGS)
xeyes_LDADD = $(XEYES_LIBS) $(XRENDER_LIBS) $(PRESENT_LIBS) -lm
xeyes_SOURCES = \
Eyes.c \
......
......@@ -47,6 +47,12 @@ if test x$use_xrender != xno ; then
AC_DEFINE([XRENDER],1,[Define to use X Render Extension])
fi
AC_ARG_WITH(present, AS_HELP_STRING([--with-present],[Use Present for updates (Default is AUTO)]),use_present="$withval",use_present="try")
if test x$use_present != xno ; then
PKG_CHECK_MODULES(PRESENT, [x11-xcb xcb-present >= 1.9 xcb-xfixes xcb-damage])
AC_DEFINE([PRESENT],1,[Define to use X Present Extension])
fi
AC_CONFIG_FILES([
Makefile
man/Makefile])
......
......@@ -56,6 +56,10 @@ usage(void)
#ifdef XRENDER
fprintf(stderr,
" [-render | +render]\n");
#endif
#ifdef PRESENT
fprintf(stderr,
" [-present | +present]\n");
#endif
exit(1);
}
......@@ -73,6 +77,10 @@ static XrmOptionDescRec options[] = {
{"-render", "*eyes.render", XrmoptionNoArg, "TRUE"},
{"+render", "*eyes.render", XrmoptionNoArg, "FALSE"},
#endif
#ifdef PRESENT
{"-present", "*eyes.present", XrmoptionNoArg, "TRUE"},
{"+present", "*eyes.present", XrmoptionNoArg, "FALSE"},
#endif
{"-distance", "*eyes.distance", XrmoptionNoArg, "TRUE"},
};
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment