summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorKeith Packard <keithp@keithp.com>2013-07-26 18:46:45 -0700
committerKeith Packard <keithp@keithp.com>2020-03-29 13:47:09 -0700
commit3f2af30bd94ea3012bc1d1bde82f7c9a1c4dea27 (patch)
tree7373ec89b489d2edfe0c8c1a329cac12c932ea1e
parent46dac260d384e034aaabd576d9b818d39f4821c6 (diff)
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 <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 <keithp@keithp.com>
-rw-r--r--Eyes.c168
-rw-r--r--Eyes.h2
-rw-r--r--EyesP.h15
-rw-r--r--Makefile.am4
-rw-r--r--configure.ac6
-rw-r--r--xeyes.c8
6 files changed, 197 insertions, 6 deletions
diff --git a/Eyes.c b/Eyes.c
index a9f2618..6b51d00 100644
--- a/Eyes.c
+++ b/Eyes.c
@@ -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),
@@ -77,6 +80,10 @@ static XtResource resources[] = {
{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
diff --git a/Eyes.h b/Eyes.h
index 5170356..6bac782 100644
--- a/Eyes.h
+++ b/Eyes.h
@@ -35,6 +35,8 @@
#define XtNrender "render"
#define XtNdistance "distance"
+#define XtNpresent "present"
+
enum EyesPart {
PART_CLEAR = -1,
diff --git a/EyesP.h b/EyesP.h
index 159d7f3..29fe8a3 100644
--- a/EyesP.h
+++ b/EyesP.h
@@ -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
@@ -31,9 +38,17 @@ typedef struct {
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;
diff --git a/Makefile.am b/Makefile.am
index 9889544..fe14b6d 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -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 \
diff --git a/configure.ac b/configure.ac
index 031692e..3171978 100644
--- a/configure.ac
+++ b/configure.ac
@@ -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])
diff --git a/xeyes.c b/xeyes.c
index c2f3a73..1c1f4b7 100644
--- a/xeyes.c
+++ b/xeyes.c
@@ -57,6 +57,10 @@ usage(void)
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"},
};