diff options
Diffstat (limited to 'app/xeyes/Eyes.c')
-rw-r--r-- | app/xeyes/Eyes.c | 313 |
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, |