summaryrefslogtreecommitdiff
path: root/app/xeyes/Eyes.c
diff options
context:
space:
mode:
Diffstat (limited to 'app/xeyes/Eyes.c')
-rw-r--r--app/xeyes/Eyes.c313
1 files changed, 284 insertions, 29 deletions
diff --git a/app/xeyes/Eyes.c b/app/xeyes/Eyes.c
index a9f261885..aa54b1cfa 100644
--- a/app/xeyes/Eyes.c
+++ b/app/xeyes/Eyes.c
@@ -48,36 +48,40 @@ from the X Consortium.
# include <X11/extensions/shape.h>
# include <X11/Xlibint.h>
# include <stdlib.h>
-
-#if (defined(SVR4) || defined(SYSV) && defined(i386))
-extern double hypot(double, double);
-#endif
+# include <X11/extensions/XInput2.h>
#define offset(field) XtOffsetOf(EyesRec, eyes.field)
#define goffset(field) XtOffsetOf(WidgetRec, core.field)
static XtResource resources[] = {
- {XtNwidth, XtCWidth, XtRDimension, sizeof(Dimension),
+ {(char *) XtNwidth, (char *) XtCWidth, XtRDimension, sizeof(Dimension),
goffset(width), XtRImmediate, (XtPointer) 150},
- {XtNheight, XtCHeight, XtRDimension, sizeof(Dimension),
+ {(char *) XtNheight, (char *) XtCHeight, XtRDimension, sizeof(Dimension),
goffset(height), XtRImmediate, (XtPointer) 100},
- {XtNforeground, XtCForeground, XtRPixel, sizeof(Pixel),
- offset(pixel[PART_PUPIL]), XtRString, XtDefaultForeground},
- {XtNoutline, XtCForeground, XtRPixel, sizeof(Pixel),
- offset(pixel[PART_OUTLINE]), XtRString, XtDefaultForeground},
- {XtNcenterColor, XtCBackground, XtRPixel, sizeof (Pixel),
- offset(pixel[PART_CENTER]), XtRString, XtDefaultBackground},
- {XtNreverseVideo, XtCReverseVideo, XtRBoolean, sizeof (Boolean),
+ {(char *) XtNforeground, (char *) XtCForeground, XtRPixel, sizeof(Pixel),
+ offset(pixel[PART_PUPIL]), XtRString, (char *) XtDefaultForeground},
+ {(char *) XtNbackgroundPixmap, (char *) XtCPixmap, XtRPixmap, sizeof(Pixmap),
+ XtOffsetOf(CoreRec,core.background_pixmap),
+ XtRImmediate, (XtPointer)None},
+ {(char *) XtNoutline, (char *) XtCForeground, XtRPixel, sizeof(Pixel),
+ offset(pixel[PART_OUTLINE]), XtRString, (char *) XtDefaultForeground},
+ {(char *) XtNcenterColor, (char *) XtCBackground, XtRPixel, sizeof (Pixel),
+ offset(pixel[PART_CENTER]), XtRString, (char *) XtDefaultBackground},
+ {(char *) XtNreverseVideo, (char *) XtCReverseVideo, XtRBoolean, sizeof (Boolean),
offset (reverse_video), XtRImmediate, (XtPointer) FALSE},
- {XtNbackingStore, XtCBackingStore, XtRBackingStore, sizeof (int),
- offset (backing_store), XtRString, "default"},
- {XtNshapeWindow, XtCShapeWindow, XtRBoolean, sizeof (Boolean),
+ {(char *) XtNbackingStore, (char *) XtCBackingStore, (char *) XtRBackingStore, sizeof (int),
+ offset (backing_store), XtRString, (char *) "default"},
+ {(char *) XtNshapeWindow, (char *) XtCShapeWindow, XtRBoolean, sizeof (Boolean),
offset (shape_window), XtRImmediate, (XtPointer) TRUE},
#ifdef XRENDER
- {XtNrender, XtCBoolean, XtRBoolean, sizeof(Boolean),
+ {(char *) XtNrender, (char *) XtCBoolean, XtRBoolean, sizeof(Boolean),
offset(render), XtRImmediate, (XtPointer) TRUE },
#endif
- {XtNdistance, XtCBoolean, XtRBoolean, sizeof(Boolean),
+#ifdef PRESENT
+ {(char *) XtNpresent, (char *) XtCBoolean, XtRBoolean, sizeof(Boolean),
+ offset(present), XtRImmediate, (XtPointer) TRUE },
+#endif
+ {(char *) XtNdistance, (char *) XtCBoolean, XtRBoolean, sizeof(Boolean),
offset(distance), XtRImmediate, (XtPointer) FALSE },
};
@@ -113,6 +117,218 @@ 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) {
+
+ 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);
+}
+
+struct root_listen_list {
+ struct root_listen_list *next;
+ Widget widget;
+};
+
+static struct root_listen_list *root_listen_list;
+
+static Boolean xi2_dispatcher(XEvent *event) {
+ struct root_listen_list *rll;
+ Boolean was_dispatched = False;
+
+ for (rll = root_listen_list; rll; rll = rll->next) {
+ if (XtDisplay(rll->widget) == event->xany.display) {
+ XtDispatchEventToWidget(rll->widget, event);
+ was_dispatched = True;
+ }
+ }
+ return was_dispatched;
+}
+
+static void select_xi2_events(Widget w)
+{
+ XIEventMask evmasks[1];
+ unsigned char mask1[(XI_LASTEVENT + 7)/8];
+
+ memset(mask1, 0, sizeof(mask1));
+
+ /* select for button and key events from all master devices */
+ XISetMask(mask1, XI_RawMotion);
+
+ evmasks[0].deviceid = XIAllMasterDevices;
+ evmasks[0].mask_len = sizeof(mask1);
+ evmasks[0].mask = mask1;
+
+ XISelectEvents(XtDisplay(w),
+ RootWindowOfScreen(XtScreen(w)),
+ evmasks, 1);
+ XtSetEventDispatcher(XtDisplay(w),
+ GenericEvent,
+ xi2_dispatcher);
+}
+
+static Boolean xi2_add_root_listener(Widget widget)
+{
+ struct root_listen_list *rll = malloc (sizeof (struct root_listen_list));
+
+ if (!rll)
+ return False;
+ rll->widget = widget;
+ rll->next = root_listen_list;
+ if (!root_listen_list)
+ select_xi2_events(widget);
+ root_listen_list = rll;
+ XtInsertEventTypeHandler(widget, GenericEvent, NULL, EyesGeneric, NULL, XtListHead);
+ return True;
+}
+
+static void xi2_remove_root_listener(Widget widget)
+{
+ struct root_listen_list *rll, **prev;
+
+ for (prev = &root_listen_list; (rll = *prev) != NULL; prev = &rll->next) {
+ if (rll->widget == widget) {
+ *prev = rll->next;
+ free(rll);
+ break;
+ }
+ }
+}
+
+/* Return 1 if XI2 is available, 0 otherwise */
+static int has_xi2(Display *dpy)
+{
+ int major, minor;
+ int rc;
+
+ /* We need at least XI 2.0 */
+ major = 2;
+ minor = 0;
+
+ rc = XIQueryVersion(dpy, &major, &minor);
+ if (rc == BadRequest) {
+ return 0;
+ } else if (rc != Success) {
+ return 0;
+ }
+ return 1;
+}
+
+
/* ARGSUSED */
static void Initialize (
Widget greq,
@@ -182,6 +398,8 @@ static void Initialize (
w->eyes.shape_mask = 0;
w->eyes.gc[PART_SHAPE] = NULL;
+ w->eyes.has_xi2 = has_xi2(XtDisplay(w));
+
#ifdef XRENDER
for (i = 0; i < PART_SHAPE; i ++) {
XColor c;
@@ -197,6 +415,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 +436,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 +498,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 +629,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 +669,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 +684,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)
@@ -482,9 +717,11 @@ static void draw_it (
if (XtIsRealized((Widget)w)) {
draw_it_core(w);
}
- w->eyes.interval_id =
- XtAppAddTimeOut(XtWidgetToApplicationContext((Widget) w),
- delays[w->eyes.update], draw_it, (XtPointer)w);
+ if (!w->eyes.has_xi2) {
+ w->eyes.interval_id =
+ XtAppAddTimeOut(XtWidgetToApplicationContext((Widget) w),
+ delays[w->eyes.update], draw_it, (XtPointer)w);
+ }
} /* draw_it */
static void Resize (Widget gw)
@@ -497,12 +734,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 +787,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
@@ -558,9 +808,13 @@ static void Realize (
XtCreateWindow( gw, (unsigned)InputOutput, (Visual *)CopyFromParent,
*valueMask, attrs );
Resize (gw);
- w->eyes.interval_id =
- XtAppAddTimeOut(XtWidgetToApplicationContext(gw),
- delays[w->eyes.update], draw_it, (XtPointer)gw);
+
+ if (w->eyes.has_xi2)
+ xi2_add_root_listener(gw);
+ else
+ w->eyes.interval_id =
+ XtAppAddTimeOut(XtWidgetToApplicationContext(gw),
+ delays[w->eyes.update], draw_it, (XtPointer)gw);
}
static void Destroy (Widget gw)
@@ -572,6 +826,7 @@ static void Destroy (Widget gw)
XtRemoveTimeOut (w->eyes.interval_id);
for (i = 0; i < PART_MAX; i ++)
XtReleaseGC(gw, w->eyes.gc[i]);
+ xi2_remove_root_listener(gw);
#ifdef XRENDER
if (w->eyes.picture)
XRenderFreePicture (XtDisplay(w), w->eyes.picture);
@@ -608,7 +863,7 @@ static Boolean SetValues (
EyesClassRec eyesClassRec = {
{ /* core fields */
/* superclass */ &widgetClassRec,
- /* class_name */ "Eyes",
+ /* class_name */ (char *) "Eyes",
/* size */ sizeof(EyesRec),
/* class_initialize */ ClassInitialize,
/* class_part_initialize */ NULL,