1a1d141d5Smrg/* 2a1d141d5Smrg 3a1d141d5SmrgCopyright (c) 1991 X Consortium 43bee1c92SmrgCopyright (c) 2023 q3k 5a1d141d5Smrg 6a1d141d5SmrgPermission is hereby granted, free of charge, to any person obtaining 7a1d141d5Smrga copy of this software and associated documentation files (the 8a1d141d5Smrg"Software"), to deal in the Software without restriction, including 9a1d141d5Smrgwithout limitation the rights to use, copy, modify, merge, publish, 10a1d141d5Smrgdistribute, sublicense, and/or sell copies of the Software, and to 11a1d141d5Smrgpermit persons to whom the Software is furnished to do so, subject to 12a1d141d5Smrgthe following conditions: 13a1d141d5Smrg 14a1d141d5SmrgThe above copyright notice and this permission notice shall be included 15a1d141d5Smrgin all copies or substantial portions of the Software. 16a1d141d5Smrg 17a1d141d5SmrgTHE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 18a1d141d5SmrgOR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 19a1d141d5SmrgMERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 20a1d141d5SmrgIN NO EVENT SHALL THE X CONSORTIUM BE LIABLE FOR ANY CLAIM, DAMAGES OR 21a1d141d5SmrgOTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, 22a1d141d5SmrgARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 23a1d141d5SmrgOTHER DEALINGS IN THE SOFTWARE. 24a1d141d5Smrg 25a1d141d5SmrgExcept as contained in this notice, the name of the X Consortium shall 26a1d141d5Smrgnot be used in advertising or otherwise to promote the sale, use or 27a1d141d5Smrgother dealings in this Software without prior written authorization 28a1d141d5Smrgfrom the X Consortium. 29a1d141d5Smrg 30a1d141d5Smrg*/ 31a1d141d5Smrg 32a1d141d5Smrg/* 33a1d141d5Smrg * Eyes.c 34a1d141d5Smrg * 35a1d141d5Smrg * a widget which follows the mouse around 36a1d141d5Smrg */ 37a1d141d5Smrg 382ddb6cf1Smrg#ifdef HAVE_CONFIG_H 392ddb6cf1Smrg# include "config.h" 402ddb6cf1Smrg#endif 412ddb6cf1Smrg 42a1d141d5Smrg# include <X11/Xos.h> 43a1d141d5Smrg# include <stdio.h> 44a1d141d5Smrg# include <X11/IntrinsicP.h> 45a1d141d5Smrg# include <X11/StringDefs.h> 46a1d141d5Smrg# include <X11/Xmu/Converters.h> 47a1d141d5Smrg# include "EyesP.h" 48a1d141d5Smrg# include <math.h> 49a1d141d5Smrg# include <X11/extensions/shape.h> 502ddb6cf1Smrg# include <X11/Xlibint.h> 512ddb6cf1Smrg# include <stdlib.h> 5226df5c7cSmrg# include <X11/extensions/XInput2.h> 533bee1c92Smrg# include <assert.h> 54a1d141d5Smrg 55a1d141d5Smrg#define offset(field) XtOffsetOf(EyesRec, eyes.field) 56a1d141d5Smrg#define goffset(field) XtOffsetOf(WidgetRec, core.field) 57a1d141d5Smrg 58a1d141d5Smrgstatic XtResource resources[] = { 5926df5c7cSmrg {(char *) XtNwidth, (char *) XtCWidth, XtRDimension, sizeof(Dimension), 60a1d141d5Smrg goffset(width), XtRImmediate, (XtPointer) 150}, 6126df5c7cSmrg {(char *) XtNheight, (char *) XtCHeight, XtRDimension, sizeof(Dimension), 62a1d141d5Smrg goffset(height), XtRImmediate, (XtPointer) 100}, 6326df5c7cSmrg {(char *) XtNforeground, (char *) XtCForeground, XtRPixel, sizeof(Pixel), 6426df5c7cSmrg offset(pixel[PART_PUPIL]), XtRString, (char *) XtDefaultForeground}, 6526df5c7cSmrg {(char *) XtNbackgroundPixmap, (char *) XtCPixmap, XtRPixmap, sizeof(Pixmap), 6626df5c7cSmrg XtOffsetOf(CoreRec,core.background_pixmap), 6726df5c7cSmrg XtRImmediate, (XtPointer)None}, 6826df5c7cSmrg {(char *) XtNoutline, (char *) XtCForeground, XtRPixel, sizeof(Pixel), 6926df5c7cSmrg offset(pixel[PART_OUTLINE]), XtRString, (char *) XtDefaultForeground}, 7026df5c7cSmrg {(char *) XtNcenterColor, (char *) XtCBackground, XtRPixel, sizeof (Pixel), 7126df5c7cSmrg offset(pixel[PART_CENTER]), XtRString, (char *) XtDefaultBackground}, 7226df5c7cSmrg {(char *) XtNreverseVideo, (char *) XtCReverseVideo, XtRBoolean, sizeof (Boolean), 73a1d141d5Smrg offset (reverse_video), XtRImmediate, (XtPointer) FALSE}, 7426df5c7cSmrg {(char *) XtNbackingStore, (char *) XtCBackingStore, (char *) XtRBackingStore, sizeof (int), 7526df5c7cSmrg offset (backing_store), XtRString, (char *) "default"}, 7626df5c7cSmrg {(char *) XtNshapeWindow, (char *) XtCShapeWindow, XtRBoolean, sizeof (Boolean), 77a1d141d5Smrg offset (shape_window), XtRImmediate, (XtPointer) TRUE}, 782ddb6cf1Smrg#ifdef XRENDER 7926df5c7cSmrg {(char *) XtNrender, (char *) XtCBoolean, XtRBoolean, sizeof(Boolean), 802ddb6cf1Smrg offset(render), XtRImmediate, (XtPointer) TRUE }, 812ddb6cf1Smrg#endif 8226df5c7cSmrg#ifdef PRESENT 8326df5c7cSmrg {(char *) XtNpresent, (char *) XtCBoolean, XtRBoolean, sizeof(Boolean), 8426df5c7cSmrg offset(present), XtRImmediate, (XtPointer) TRUE }, 8526df5c7cSmrg#endif 8626df5c7cSmrg {(char *) XtNdistance, (char *) XtCBoolean, XtRBoolean, sizeof(Boolean), 872ddb6cf1Smrg offset(distance), XtRImmediate, (XtPointer) FALSE }, 883bee1c92Smrg {(char *) XtNbiblicallyAccurate, (char *) XtCBoolean, XtRBoolean, sizeof(Boolean), 893bee1c92Smrg offset(biblically_accurate), XtRImmediate, (XtPointer) FALSE }, 90a1d141d5Smrg}; 91a1d141d5Smrg 92a1d141d5Smrg#undef offset 93a1d141d5Smrg#undef goffset 94a1d141d5Smrg 95a1d141d5Smrg# define EYE_OFFSET (0.1) /* padding between eyes */ 96a1d141d5Smrg# define EYE_THICK (0.175) /* thickness of eye rim */ 972ddb6cf1Smrg# define BALL_DIAM (0.3) 982ddb6cf1Smrg# define BALL_PAD (0.175) 992ddb6cf1Smrg# define EYE_DIAM (2.0 - (EYE_THICK + EYE_OFFSET) * 2) 1002ddb6cf1Smrg# define BALL_DIST ((EYE_DIAM - BALL_DIAM) / 2.0 - BALL_PAD) 101a1d141d5Smrg 1022ddb6cf1Smrg# define TPOINT_NONE (-1000) /* special value meaning "not yet set" */ 103a1d141d5Smrg# define TPointEqual(a, b) ((a).x == (b).x && (a).y == (b).y) 104a1d141d5Smrg# define XPointEqual(a, b) ((a).x == (b).x && (a).y == (b).y) 1052ddb6cf1Smrg# define AngleBetween(A, A0, A1) (A0 <= A1 ? A0 <= A && A <= A1 : \ 1062ddb6cf1Smrg A0 <= A || A <= A1) 107a1d141d5Smrg 108a1d141d5Smrgstatic int delays[] = { 50, 100, 200, 400, 0 }; 109a1d141d5Smrg 1103bee1c92Smrgstatic EyeLayout layout_standard[] = { 1113bee1c92Smrg { .x = 0.0, .y = 0.0, }, 1123bee1c92Smrg { .x = 2.0, .y = 0.0, }, 1133bee1c92Smrg}; 1143bee1c92Smrg 1153bee1c92Smrgstatic EyeLayout layout_biblical[] = { 1163bee1c92Smrg { .x = 0.0+0.75, .y = 0.0, }, 1173bee1c92Smrg { .x = 1.5+0.75, .y = 0.0, }, 1183bee1c92Smrg { .x = 3.0+0.75, .y = 0.0, }, 1193bee1c92Smrg 1203bee1c92Smrg { .x = 0.0+0.00, .y = 1.4, }, 1213bee1c92Smrg { .x = 1.5+0.00, .y = 1.4, }, 1223bee1c92Smrg { .x = 3.0+0.00, .y = 1.4, }, 1233bee1c92Smrg { .x = 4.5+0.00, .y = 1.4, }, 1243bee1c92Smrg 1253bee1c92Smrg { .x = 0.0+0.75, .y = 2.8, }, 1263bee1c92Smrg { .x = 1.5+0.75, .y = 2.8, }, 1273bee1c92Smrg { .x = 3.0+0.75, .y = 2.8, }, 1283bee1c92Smrg}; 1293bee1c92Smrg 1303bee1c92Smrgstatic EyeConfiguration *EyesConfigure(Boolean biblically_accurate) 1313bee1c92Smrg{ 1323bee1c92Smrg EyeConfiguration *c = calloc(sizeof(EyeConfiguration), 1); 1333bee1c92Smrg assert(c != NULL); 1343bee1c92Smrg 1353bee1c92Smrg if (biblically_accurate) { 1363bee1c92Smrg c->eyes = layout_biblical; 1373bee1c92Smrg c->count = sizeof(layout_biblical) / sizeof(EyeLayout); 1383bee1c92Smrg } else { 1393bee1c92Smrg c->eyes = layout_standard; 1403bee1c92Smrg c->count = sizeof(layout_standard) / sizeof(EyeLayout); 1413bee1c92Smrg } 1423bee1c92Smrg 1433bee1c92Smrg // Calculate the bounding box of the eyes. 1443bee1c92Smrg c->w_min_x = c->eyes[0].x; 1453bee1c92Smrg c->w_max_x = c->eyes[0].x; 1463bee1c92Smrg c->w_min_y = c->eyes[0].y; 1473bee1c92Smrg c->w_max_y = c->eyes[0].y; 1483bee1c92Smrg 1493bee1c92Smrg for (int i = 0; i < c->count; i++) { 1503bee1c92Smrg EyeLayout *l = &c->eyes[i]; 1513bee1c92Smrg if (l->x > c->w_max_x) { 1523bee1c92Smrg c->w_max_x = l->x; 1533bee1c92Smrg } 1543bee1c92Smrg if (l->x < c->w_min_x) { 1553bee1c92Smrg c->w_min_x = l->x; 1563bee1c92Smrg } 1573bee1c92Smrg if (l->y > c->w_max_y) { 1583bee1c92Smrg c->w_max_y = l->y; 1593bee1c92Smrg } 1603bee1c92Smrg if (l->y < c->w_min_y) { 1613bee1c92Smrg c->w_min_y = l->y; 1623bee1c92Smrg } 1633bee1c92Smrg } 1643bee1c92Smrg 1653bee1c92Smrg // Add half size of eye (2.0) minus padding to each edge. 1663bee1c92Smrg c->w_min_x -= (1.0 - EYE_OFFSET); 1673bee1c92Smrg c->w_max_x += (1.0 - EYE_OFFSET); 1683bee1c92Smrg c->w_min_y -= (1.0 - EYE_OFFSET); 1693bee1c92Smrg c->w_max_y += (1.0 - EYE_OFFSET); 1703bee1c92Smrg return c; 1713bee1c92Smrg} 1723bee1c92Smrg 173a1d141d5Smrgstatic void ClassInitialize(void) 174a1d141d5Smrg{ 175a1d141d5Smrg XtAddConverter( XtRString, XtRBackingStore, XmuCvtStringToBackingStore, 176a1d141d5Smrg NULL, 0 ); 177a1d141d5Smrg} 178a1d141d5Smrg 179a1d141d5SmrgWidgetClass eyesWidgetClass = (WidgetClass) &eyesClassRec; 180a1d141d5Smrg 18126df5c7cSmrg#ifdef PRESENT 18226df5c7cSmrgstatic void CheckPresent(EyesWidget w) { 18326df5c7cSmrg const xcb_query_extension_reply_t *xfixes_ext_reply; 18426df5c7cSmrg const xcb_query_extension_reply_t *damage_ext_reply; 18526df5c7cSmrg const xcb_query_extension_reply_t *present_ext_reply; 18626df5c7cSmrg xcb_xfixes_query_version_cookie_t xfixes_cookie; 18726df5c7cSmrg xcb_xfixes_query_version_reply_t *xfixes_reply; 18826df5c7cSmrg xcb_damage_query_version_cookie_t damage_cookie; 18926df5c7cSmrg xcb_damage_query_version_reply_t *damage_reply; 19026df5c7cSmrg xcb_present_query_version_cookie_t present_cookie; 19126df5c7cSmrg xcb_present_query_version_reply_t *present_reply; 19226df5c7cSmrg 19326df5c7cSmrg if (!w->eyes.present) 19426df5c7cSmrg return; 19526df5c7cSmrg 19626df5c7cSmrg xcb_prefetch_extension_data(xt_xcb(w), &xcb_xfixes_id); 19726df5c7cSmrg xcb_prefetch_extension_data(xt_xcb(w), &xcb_damage_id); 19826df5c7cSmrg xcb_prefetch_extension_data(xt_xcb(w), &xcb_present_id); 19926df5c7cSmrg 20026df5c7cSmrg xfixes_ext_reply = xcb_get_extension_data(xt_xcb(w), &xcb_xfixes_id); 20126df5c7cSmrg damage_ext_reply = xcb_get_extension_data(xt_xcb(w), &xcb_damage_id); 20226df5c7cSmrg present_ext_reply = xcb_get_extension_data(xt_xcb(w), &xcb_present_id); 20326df5c7cSmrg if (xfixes_ext_reply == NULL || !xfixes_ext_reply->present 20426df5c7cSmrg || damage_ext_reply == NULL || !damage_ext_reply->present 20526df5c7cSmrg || present_ext_reply == NULL || !present_ext_reply->present) 20626df5c7cSmrg { 20726df5c7cSmrg w->eyes.present = FALSE; 20826df5c7cSmrg } 20926df5c7cSmrg 21026df5c7cSmrg if (!w->eyes.present) 21126df5c7cSmrg return; 21226df5c7cSmrg 21326df5c7cSmrg /* Now tell the server which versions of the extensions we support */ 21426df5c7cSmrg xfixes_cookie = xcb_xfixes_query_version(xt_xcb(w), 21526df5c7cSmrg XCB_XFIXES_MAJOR_VERSION, 21626df5c7cSmrg XCB_XFIXES_MINOR_VERSION); 21726df5c7cSmrg 21826df5c7cSmrg damage_cookie = xcb_damage_query_version(xt_xcb(w), 21926df5c7cSmrg XCB_DAMAGE_MAJOR_VERSION, 22026df5c7cSmrg XCB_DAMAGE_MINOR_VERSION); 22126df5c7cSmrg 22226df5c7cSmrg present_cookie = xcb_present_query_version(xt_xcb(w), 22326df5c7cSmrg XCB_PRESENT_MAJOR_VERSION, 22426df5c7cSmrg XCB_PRESENT_MINOR_VERSION); 22526df5c7cSmrg 22626df5c7cSmrg xfixes_reply = xcb_xfixes_query_version_reply(xt_xcb(w), 22726df5c7cSmrg xfixes_cookie, 22826df5c7cSmrg NULL); 22926df5c7cSmrg free(xfixes_reply); 23026df5c7cSmrg 23126df5c7cSmrg damage_reply = xcb_damage_query_version_reply(xt_xcb(w), 23226df5c7cSmrg damage_cookie, 23326df5c7cSmrg NULL); 23426df5c7cSmrg free(damage_reply); 23526df5c7cSmrg 23626df5c7cSmrg present_reply = xcb_present_query_version_reply(xt_xcb(w), 23726df5c7cSmrg present_cookie, 23826df5c7cSmrg NULL); 23926df5c7cSmrg free(present_reply); 24026df5c7cSmrg} 24126df5c7cSmrg 24226df5c7cSmrgstatic void MakePresentData(EyesWidget w) { 24326df5c7cSmrg 24426df5c7cSmrg if (!w->eyes.present) 24526df5c7cSmrg return; 24626df5c7cSmrg 24726df5c7cSmrg if (!w->eyes.back_buffer) { 24826df5c7cSmrg xcb_create_pixmap(xt_xcb(w), 24926df5c7cSmrg w->core.depth, 25026df5c7cSmrg w->eyes.back_buffer = xcb_generate_id(xt_xcb(w)), 25126df5c7cSmrg XtWindow(w), 25226df5c7cSmrg w->core.width, 25326df5c7cSmrg w->core.height); 25426df5c7cSmrg } 25526df5c7cSmrg if (!w->eyes.back_damage) { 25626df5c7cSmrg xcb_damage_create(xt_xcb(w), 25726df5c7cSmrg w->eyes.back_damage = xcb_generate_id(xt_xcb(w)), 25826df5c7cSmrg w->eyes.back_buffer, 25926df5c7cSmrg XCB_DAMAGE_REPORT_LEVEL_NON_EMPTY); 26026df5c7cSmrg xcb_xfixes_create_region(xt_xcb(w), 26126df5c7cSmrg w->eyes.back_region = xcb_generate_id(xt_xcb(w)), 26226df5c7cSmrg 0, NULL); 26326df5c7cSmrg } 26426df5c7cSmrg} 26526df5c7cSmrg 26626df5c7cSmrgstatic void UpdatePresent(EyesWidget w) { 26726df5c7cSmrg if (w->eyes.back_buffer) { 26826df5c7cSmrg xcb_damage_subtract(xt_xcb(w), 26926df5c7cSmrg w->eyes.back_damage, 27026df5c7cSmrg None, 27126df5c7cSmrg w->eyes.back_region); 27226df5c7cSmrg xcb_present_pixmap(xt_xcb(w), 27326df5c7cSmrg XtWindow(w), 27426df5c7cSmrg w->eyes.back_buffer, 27526df5c7cSmrg 0, 27626df5c7cSmrg None, 27726df5c7cSmrg w->eyes.back_region, 27826df5c7cSmrg 0, 0, 27926df5c7cSmrg None, 28026df5c7cSmrg None, 28126df5c7cSmrg None, 28226df5c7cSmrg 0, 28326df5c7cSmrg 0, 1, 0, 28426df5c7cSmrg 0, NULL); 28526df5c7cSmrg } 28626df5c7cSmrg} 28726df5c7cSmrg 28826df5c7cSmrg#endif 28926df5c7cSmrg 29026df5c7cSmrg#ifdef PRESENT 29126df5c7cSmrg#define EyesDrawable(w) (w->eyes.back_buffer ? w->eyes.back_buffer : XtWindow(w)) 29226df5c7cSmrg#else 29326df5c7cSmrg#define EyesDrawable(w) XtWindow(w) 29426df5c7cSmrg#endif 29526df5c7cSmrg 29626df5c7cSmrgstatic void draw_it_core(EyesWidget w); 29726df5c7cSmrg 29826df5c7cSmrgstatic void EyesGeneric(Widget w, XtPointer closure, XEvent *event, Boolean *continue_to_dispatch) 29926df5c7cSmrg{ 30026df5c7cSmrg draw_it_core((EyesWidget) w); 30126df5c7cSmrg} 30226df5c7cSmrg 30326df5c7cSmrgstruct root_listen_list { 30426df5c7cSmrg struct root_listen_list *next; 30526df5c7cSmrg Widget widget; 30626df5c7cSmrg}; 30726df5c7cSmrg 30826df5c7cSmrgstatic struct root_listen_list *root_listen_list; 30926df5c7cSmrg 31026df5c7cSmrgstatic Boolean xi2_dispatcher(XEvent *event) { 31126df5c7cSmrg struct root_listen_list *rll; 31226df5c7cSmrg Boolean was_dispatched = False; 31326df5c7cSmrg 31426df5c7cSmrg for (rll = root_listen_list; rll; rll = rll->next) { 31526df5c7cSmrg if (XtDisplay(rll->widget) == event->xany.display) { 31626df5c7cSmrg XtDispatchEventToWidget(rll->widget, event); 31726df5c7cSmrg was_dispatched = True; 31826df5c7cSmrg } 31926df5c7cSmrg } 32026df5c7cSmrg return was_dispatched; 32126df5c7cSmrg} 32226df5c7cSmrg 32326df5c7cSmrgstatic void select_xi2_events(Widget w) 32426df5c7cSmrg{ 32526df5c7cSmrg XIEventMask evmasks[1]; 32626df5c7cSmrg unsigned char mask1[(XI_LASTEVENT + 7)/8]; 32726df5c7cSmrg 32826df5c7cSmrg memset(mask1, 0, sizeof(mask1)); 32926df5c7cSmrg 33026df5c7cSmrg /* select for button and key events from all master devices */ 33126df5c7cSmrg XISetMask(mask1, XI_RawMotion); 33226df5c7cSmrg 33326df5c7cSmrg evmasks[0].deviceid = XIAllMasterDevices; 33426df5c7cSmrg evmasks[0].mask_len = sizeof(mask1); 33526df5c7cSmrg evmasks[0].mask = mask1; 33626df5c7cSmrg 33726df5c7cSmrg XISelectEvents(XtDisplay(w), 33826df5c7cSmrg RootWindowOfScreen(XtScreen(w)), 33926df5c7cSmrg evmasks, 1); 34026df5c7cSmrg XtSetEventDispatcher(XtDisplay(w), 34126df5c7cSmrg GenericEvent, 34226df5c7cSmrg xi2_dispatcher); 34326df5c7cSmrg} 34426df5c7cSmrg 34526df5c7cSmrgstatic Boolean xi2_add_root_listener(Widget widget) 34626df5c7cSmrg{ 34726df5c7cSmrg struct root_listen_list *rll = malloc (sizeof (struct root_listen_list)); 34826df5c7cSmrg 34926df5c7cSmrg if (!rll) 35026df5c7cSmrg return False; 35126df5c7cSmrg rll->widget = widget; 35226df5c7cSmrg rll->next = root_listen_list; 35326df5c7cSmrg if (!root_listen_list) 35426df5c7cSmrg select_xi2_events(widget); 35526df5c7cSmrg root_listen_list = rll; 35626df5c7cSmrg XtInsertEventTypeHandler(widget, GenericEvent, NULL, EyesGeneric, NULL, XtListHead); 35726df5c7cSmrg return True; 35826df5c7cSmrg} 35926df5c7cSmrg 36026df5c7cSmrgstatic void xi2_remove_root_listener(Widget widget) 36126df5c7cSmrg{ 36226df5c7cSmrg struct root_listen_list *rll, **prev; 36326df5c7cSmrg 36426df5c7cSmrg for (prev = &root_listen_list; (rll = *prev) != NULL; prev = &rll->next) { 36526df5c7cSmrg if (rll->widget == widget) { 36626df5c7cSmrg *prev = rll->next; 36726df5c7cSmrg free(rll); 36826df5c7cSmrg break; 36926df5c7cSmrg } 37026df5c7cSmrg } 37126df5c7cSmrg} 37226df5c7cSmrg 37326df5c7cSmrg/* Return 1 if XI2 is available, 0 otherwise */ 37426df5c7cSmrgstatic int has_xi2(Display *dpy) 37526df5c7cSmrg{ 37626df5c7cSmrg int major, minor; 37726df5c7cSmrg int rc; 37826df5c7cSmrg 37926df5c7cSmrg /* We need at least XI 2.0 */ 38026df5c7cSmrg major = 2; 38126df5c7cSmrg minor = 0; 38226df5c7cSmrg 38326df5c7cSmrg rc = XIQueryVersion(dpy, &major, &minor); 38426df5c7cSmrg if (rc == BadRequest) { 38526df5c7cSmrg return 0; 38626df5c7cSmrg } else if (rc != Success) { 38726df5c7cSmrg return 0; 38826df5c7cSmrg } 38926df5c7cSmrg return 1; 39026df5c7cSmrg} 39126df5c7cSmrg 39226df5c7cSmrg 393a1d141d5Smrg/* ARGSUSED */ 394a1d141d5Smrgstatic void Initialize ( 395a1d141d5Smrg Widget greq, 396a1d141d5Smrg Widget gnew, 397a1d141d5Smrg ArgList args, 398a1d141d5Smrg Cardinal *num_args) 399a1d141d5Smrg{ 400a1d141d5Smrg EyesWidget w = (EyesWidget)gnew; 401a1d141d5Smrg XtGCMask valuemask; 402a1d141d5Smrg XGCValues myXGCV; 403a1d141d5Smrg int shape_event_base, shape_error_base; 4042ddb6cf1Smrg#ifdef XRENDER 4052ddb6cf1Smrg enum EyesPart i; 4062ddb6cf1Smrg#endif 407a1d141d5Smrg 4083bee1c92Smrg EyeConfiguration *config = EyesConfigure(w->eyes.biblically_accurate); 4093bee1c92Smrg TPoint *pupils = calloc(sizeof(TPoint), config->count); 4103bee1c92Smrg assert(pupils != NULL); 4113bee1c92Smrg for (int j = 0; j < config->count; j++) { 4123bee1c92Smrg pupils[j].x = TPOINT_NONE; 4133bee1c92Smrg pupils[j].y = TPOINT_NONE; 4143bee1c92Smrg } 4153bee1c92Smrg w->eyes.configuration = config; 4163bee1c92Smrg w->eyes.pupils = pupils; 4173bee1c92Smrg 4183bee1c92Smrg 419a1d141d5Smrg /* 420a1d141d5Smrg * set the colors if reverse video; these are the colors used: 421a1d141d5Smrg * 422a1d141d5Smrg * background - paper white 423a1d141d5Smrg * foreground - text, ticks black 424a1d141d5Smrg * border - border black (foreground) 425a1d141d5Smrg * 4262ddb6cf1Smrg * This doesn't completely work since the parent has already made up a 427a1d141d5Smrg * border. Sigh. 428a1d141d5Smrg */ 429a1d141d5Smrg if (w->eyes.reverse_video) { 4302ddb6cf1Smrg Pixel fg = w->eyes.pixel[PART_PUPIL]; 431a1d141d5Smrg Pixel bg = w->core.background_pixel; 432a1d141d5Smrg 433a1d141d5Smrg if (w->core.border_pixel == fg) 434a1d141d5Smrg w->core.border_pixel = bg; 4352ddb6cf1Smrg if (w->eyes.pixel[PART_OUTLINE] == fg) 4362ddb6cf1Smrg w->eyes.pixel[PART_OUTLINE] = bg; 4372ddb6cf1Smrg if (w->eyes.pixel[PART_CENTER] == bg) 4382ddb6cf1Smrg w->eyes.pixel[PART_CENTER] = fg; 4392ddb6cf1Smrg w->eyes.pixel[PART_PUPIL] = bg; 440a1d141d5Smrg w->core.background_pixel = fg; 441a1d141d5Smrg } 442a1d141d5Smrg 4432ddb6cf1Smrg myXGCV.foreground = w->eyes.pixel[PART_PUPIL]; 444a1d141d5Smrg myXGCV.background = w->core.background_pixel; 445a1d141d5Smrg valuemask = GCForeground | GCBackground; 4462ddb6cf1Smrg w->eyes.gc[PART_PUPIL] = XtGetGC(gnew, valuemask, &myXGCV); 447a1d141d5Smrg 4482ddb6cf1Smrg myXGCV.foreground = w->eyes.pixel[PART_OUTLINE]; 449a1d141d5Smrg valuemask = GCForeground | GCBackground; 4502ddb6cf1Smrg w->eyes.gc[PART_OUTLINE] = XtGetGC(gnew, valuemask, &myXGCV); 451a1d141d5Smrg 4522ddb6cf1Smrg myXGCV.foreground = w->eyes.pixel[PART_CENTER]; 4532ddb6cf1Smrg myXGCV.background = w->eyes.pixel[PART_PUPIL]; 454a1d141d5Smrg valuemask = GCForeground | GCBackground; 4552ddb6cf1Smrg w->eyes.gc[PART_CENTER] = XtGetGC(gnew, valuemask, &myXGCV); 456a1d141d5Smrg 457a1d141d5Smrg w->eyes.update = 0; 458a1d141d5Smrg /* wait for Realize to add the timeout */ 459a1d141d5Smrg w->eyes.interval_id = 0; 460a1d141d5Smrg 4612ddb6cf1Smrg w->eyes.mouse.x = w->eyes.mouse.y = TPOINT_NONE; 462a1d141d5Smrg 463a1d141d5Smrg if (w->eyes.shape_window && !XShapeQueryExtension (XtDisplay (w), 464a1d141d5Smrg &shape_event_base, 465a1d141d5Smrg &shape_error_base)) 466a1d141d5Smrg w->eyes.shape_window = False; 467a1d141d5Smrg w->eyes.shape_mask = 0; 4682ddb6cf1Smrg w->eyes.gc[PART_SHAPE] = NULL; 4692ddb6cf1Smrg 47026df5c7cSmrg w->eyes.has_xi2 = has_xi2(XtDisplay(w)); 47126df5c7cSmrg 4722ddb6cf1Smrg#ifdef XRENDER 4732ddb6cf1Smrg for (i = 0; i < PART_SHAPE; i ++) { 4742ddb6cf1Smrg XColor c; 4752ddb6cf1Smrg XRenderColor rc; 4762ddb6cf1Smrg 4772ddb6cf1Smrg c.pixel = w->eyes.pixel[i]; 4782ddb6cf1Smrg XQueryColor(XtDisplay (w), w->core.colormap, &c); 4792ddb6cf1Smrg 4802ddb6cf1Smrg rc.red = c.red; 4812ddb6cf1Smrg rc.green = c.green; 4822ddb6cf1Smrg rc.blue = c.blue; 4832ddb6cf1Smrg rc.alpha = -1; 4842ddb6cf1Smrg w->eyes.fill[i] = XRenderCreateSolidFill(XtDisplay (w), &rc); 4852ddb6cf1Smrg } 4862ddb6cf1Smrg#endif 48726df5c7cSmrg#ifdef PRESENT 48826df5c7cSmrg w->eyes.back_buffer = None; 48926df5c7cSmrg w->eyes.back_damage = None; 49026df5c7cSmrg CheckPresent(w); 49126df5c7cSmrg#endif 492a1d141d5Smrg} 493a1d141d5Smrg 4942ddb6cf1Smrgstatic void 4952ddb6cf1SmrgdrawEllipse(EyesWidget w, enum EyesPart part, 4962ddb6cf1Smrg double centerx, double centery, 4972ddb6cf1Smrg double oldx, double oldy, 4982ddb6cf1Smrg double diam) 499a1d141d5Smrg{ 5002ddb6cf1Smrg const TRectangle tpos = { 5012ddb6cf1Smrg centerx - diam/2.0, 5022ddb6cf1Smrg centery - diam/2.0, 5032ddb6cf1Smrg diam, diam }; 5042ddb6cf1Smrg TRectangle pos; 5052ddb6cf1Smrg Trectangle(&w->eyes.t, &tpos, &pos); 5062ddb6cf1Smrg 5072ddb6cf1Smrg if (part == PART_CLEAR) { 50826df5c7cSmrg XFillRectangle(XtDisplay(w), EyesDrawable(w), 5092ddb6cf1Smrg w->eyes.gc[PART_CENTER], 5102ddb6cf1Smrg (int)pos.x, (int)pos.y, 5112ddb6cf1Smrg (int)pos.width+2, (int)pos.height+2); 5122ddb6cf1Smrg return; 5132ddb6cf1Smrg } 5142ddb6cf1Smrg#ifdef XRENDER 5152ddb6cf1Smrg if (w->eyes.render && part != PART_SHAPE && (!w->eyes.shape_window || 5162ddb6cf1Smrg part != PART_OUTLINE) && 5172ddb6cf1Smrg w->eyes.picture) { 5182ddb6cf1Smrg int n, i; 5192ddb6cf1Smrg double hd, c, s, sx, sy, x, y, px, py; 5202ddb6cf1Smrg XPointDouble *p; 5212ddb6cf1Smrg 5222ddb6cf1Smrg pos.x = pos.x + pos.width/2.0; 5232ddb6cf1Smrg pos.y = pos.y + pos.height/2.0; 5242ddb6cf1Smrg 5252ddb6cf1Smrg /* determine number of segments to draw */ 5262ddb6cf1Smrg hd = hypot(pos.width, pos.height)/2; 5272ddb6cf1Smrg n = (M_PI / acos(hd/(hd+1.0))) + 0.5; 5282ddb6cf1Smrg if (n < 2) n = 2; 5292ddb6cf1Smrg 5302ddb6cf1Smrg c = cos(M_PI/n); 5312ddb6cf1Smrg s = sin(M_PI/n); 5322ddb6cf1Smrg sx = -(pos.width*s)/pos.height; 5332ddb6cf1Smrg sy = (pos.height*s)/pos.width; 5342ddb6cf1Smrg 5352ddb6cf1Smrg n *= 2; 5362ddb6cf1Smrg p = Xmalloc(sizeof(*p)*n); 5372ddb6cf1Smrg if (!p) 5382ddb6cf1Smrg return; 5392ddb6cf1Smrg x = 0; 5402ddb6cf1Smrg y = pos.height/2.0; 5412ddb6cf1Smrg for (i = 0; i < n; i ++) 5422ddb6cf1Smrg { 5432ddb6cf1Smrg p[i].x = x + pos.x; 5442ddb6cf1Smrg p[i].y = y + pos.y; 5452ddb6cf1Smrg px = x; 5462ddb6cf1Smrg py = y; 5472ddb6cf1Smrg x = c*px + sx*py; 5482ddb6cf1Smrg y = c*py + sy*px; 549a1d141d5Smrg } 5502ddb6cf1Smrg 5512ddb6cf1Smrg if (oldx != TPOINT_NONE || oldy != TPOINT_NONE) 5522ddb6cf1Smrg drawEllipse(w, PART_CLEAR, oldx, oldy, 5532ddb6cf1Smrg TPOINT_NONE, TPOINT_NONE, diam); 5542ddb6cf1Smrg 5552ddb6cf1Smrg XRenderCompositeDoublePoly(XtDisplay(w), PictOpOver, 5562ddb6cf1Smrg w->eyes.fill[part], w->eyes.picture, 5572ddb6cf1Smrg XRenderFindStandardFormat(XtDisplay(w), 5582ddb6cf1Smrg PictStandardA8), 5592ddb6cf1Smrg 0, 0, 0, 0, p, n, 0); 5602ddb6cf1Smrg 5612ddb6cf1Smrg Xfree(p); 5622ddb6cf1Smrg return; 5632ddb6cf1Smrg } 5642ddb6cf1Smrg#endif 5652ddb6cf1Smrg if (oldx != TPOINT_NONE || oldy != TPOINT_NONE) 5662ddb6cf1Smrg drawEllipse(w, PART_CLEAR, oldx, oldy, 5672ddb6cf1Smrg TPOINT_NONE, TPOINT_NONE, diam); 5682ddb6cf1Smrg 5692ddb6cf1Smrg XFillArc(XtDisplay(w), 57026df5c7cSmrg part == PART_SHAPE ? w->eyes.shape_mask : EyesDrawable(w), 5712ddb6cf1Smrg w->eyes.gc[part], 5722ddb6cf1Smrg (int)(pos.x + 0.5), (int)(pos.y + 0.5), 5732ddb6cf1Smrg (int)(pos.width + 0.0), (int)(pos.height + 0.0), 5742ddb6cf1Smrg 90*64, 360*64); 5752ddb6cf1Smrg} 5762ddb6cf1Smrg 5772ddb6cf1Smrg 5782ddb6cf1Smrgstatic void 5792ddb6cf1SmrgeyeLiner(EyesWidget w, 5802ddb6cf1Smrg Boolean draw, 5812ddb6cf1Smrg int num) 5822ddb6cf1Smrg{ 5833bee1c92Smrg EyeLayout *l = &w->eyes.configuration->eyes[num]; 5842ddb6cf1Smrg drawEllipse(w, draw ? PART_OUTLINE : PART_SHAPE, 5853bee1c92Smrg l->x, l->y, 5862ddb6cf1Smrg TPOINT_NONE, TPOINT_NONE, 5872ddb6cf1Smrg EYE_DIAM + 2.0*EYE_THICK); 5882ddb6cf1Smrg if (draw) { 5893bee1c92Smrg drawEllipse(w, PART_CENTER, l->x, l->y, 5902ddb6cf1Smrg TPOINT_NONE, TPOINT_NONE, 5912ddb6cf1Smrg EYE_DIAM); 5922ddb6cf1Smrg } 593a1d141d5Smrg} 594a1d141d5Smrg 595a1d141d5Smrgstatic TPoint computePupil ( 5963bee1c92Smrg EyeLayout *layout, 5972ddb6cf1Smrg TPoint mouse, 5982ddb6cf1Smrg const TRectangle *screen) 599a1d141d5Smrg{ 600a1d141d5Smrg double cx, cy; 601a1d141d5Smrg double dist; 602a1d141d5Smrg double angle; 603a1d141d5Smrg double dx, dy; 604a1d141d5Smrg double cosa, sina; 605a1d141d5Smrg TPoint ret; 606a1d141d5Smrg 6073bee1c92Smrg cx = layout->x; dx = mouse.x - cx; 6083bee1c92Smrg cy = layout->y; dy = mouse.y - cy; 6092ddb6cf1Smrg if (dx == 0 && dy == 0); 6102ddb6cf1Smrg else { 611a1d141d5Smrg angle = atan2 ((double) dy, (double) dx); 612a1d141d5Smrg cosa = cos (angle); 613a1d141d5Smrg sina = sin (angle); 6142ddb6cf1Smrg dist = BALL_DIST; 6152ddb6cf1Smrg if (screen) 6162ddb6cf1Smrg { 6172ddb6cf1Smrg /* use distance mapping */ 6182ddb6cf1Smrg double x0, y0, x1, y1; 6192ddb6cf1Smrg double a[4]; 6202ddb6cf1Smrg x0 = screen->x - cx; 6212ddb6cf1Smrg y0 = screen->y - cy; 6222ddb6cf1Smrg x1 = x0 + screen->width; 6232ddb6cf1Smrg y1 = y0 + screen->height; 6242ddb6cf1Smrg a[0] = atan2(y0, x0); 6252ddb6cf1Smrg a[1] = atan2(y1, x0); 6262ddb6cf1Smrg a[2] = atan2(y1, x1); 6272ddb6cf1Smrg a[3] = atan2(y0, x1); 6282ddb6cf1Smrg if (AngleBetween(angle, a[0], a[1])) 6292ddb6cf1Smrg { 6302ddb6cf1Smrg /* left */ 6312ddb6cf1Smrg dist *= dx / x0; 6322ddb6cf1Smrg } 6332ddb6cf1Smrg else if (AngleBetween(angle, a[1], a[2])) 6342ddb6cf1Smrg { 6352ddb6cf1Smrg /* bottom */ 6362ddb6cf1Smrg dist *= dy / y1; 6372ddb6cf1Smrg } 6382ddb6cf1Smrg else if (AngleBetween(angle, a[2], a[3])) 6392ddb6cf1Smrg { 6402ddb6cf1Smrg /* right */ 6412ddb6cf1Smrg dist *= dx / x1; 6422ddb6cf1Smrg } 6432ddb6cf1Smrg else if (AngleBetween(angle, a[3], a[0])) 6442ddb6cf1Smrg { 6452ddb6cf1Smrg /* top */ 6462ddb6cf1Smrg dist *= dy / y0; 6472ddb6cf1Smrg } 6482ddb6cf1Smrg if (dist > BALL_DIST) 6492ddb6cf1Smrg dist = BALL_DIST; 6502ddb6cf1Smrg } 651a1d141d5Smrg if (dist > hypot ((double) dx, (double) dy)) { 6522ddb6cf1Smrg cx += dx; 6532ddb6cf1Smrg cy += dy; 654a1d141d5Smrg } else { 6552ddb6cf1Smrg cx += dist * cosa; 6562ddb6cf1Smrg cy += dist * sina; 657a1d141d5Smrg } 658a1d141d5Smrg } 659a1d141d5Smrg ret.x = cx; 660a1d141d5Smrg ret.y = cy; 661a1d141d5Smrg return ret; 662a1d141d5Smrg} 663a1d141d5Smrg 664a1d141d5Smrgstatic void computePupils ( 6652ddb6cf1Smrg EyesWidget w, 666a1d141d5Smrg TPoint mouse, 6673bee1c92Smrg TPoint *pupils) 668a1d141d5Smrg{ 6692ddb6cf1Smrg TRectangle screen, *sp = NULL; 6702ddb6cf1Smrg if (w->eyes.distance) { 6712ddb6cf1Smrg Window r, cw; 6722ddb6cf1Smrg int x, y; 6732ddb6cf1Smrg r = RootWindowOfScreen(w->core.screen); 6742ddb6cf1Smrg XTranslateCoordinates(XtDisplay(w), XtWindow(w), r, 0, 0, &x, &y, &cw); 6752ddb6cf1Smrg screen.x = Tx(-x, -y, &w->eyes.t); 6762ddb6cf1Smrg screen.y = Ty(-x, -y, &w->eyes.t); 6772ddb6cf1Smrg screen.width = Twidth (w->core.screen->width, w->core.screen->height, 6782ddb6cf1Smrg &w->eyes.t); 6792ddb6cf1Smrg screen.height = Theight(w->core.screen->width, w->core.screen->height, 6802ddb6cf1Smrg &w->eyes.t); 6812ddb6cf1Smrg sp = &screen; 6822ddb6cf1Smrg } 6833bee1c92Smrg for (int i = 0; i < w->eyes.configuration->count; i++) { 6843bee1c92Smrg pupils[i] = computePupil(&w->eyes.configuration->eyes[i], mouse, sp); 6853bee1c92Smrg } 686a1d141d5Smrg} 687a1d141d5Smrg 6882ddb6cf1Smrgstatic void 6892ddb6cf1SmrgeyeBall(EyesWidget w, 6902ddb6cf1Smrg Boolean draw, 6912ddb6cf1Smrg TPoint *old, 6922ddb6cf1Smrg int num) 693a1d141d5Smrg{ 6943bee1c92Smrg //printf("eyeBall(_, %d, %p, %d)\n", draw, old, num); 6952ddb6cf1Smrg drawEllipse(w, draw ? PART_PUPIL : PART_CLEAR, 6963bee1c92Smrg w->eyes.pupils[num].x, w->eyes.pupils[num].y, 6972ddb6cf1Smrg old ? old->x : TPOINT_NONE, old ? old->y : TPOINT_NONE, 6982ddb6cf1Smrg BALL_DIAM); 699a1d141d5Smrg} 700a1d141d5Smrg 701a1d141d5Smrgstatic void repaint_window (EyesWidget w) 702a1d141d5Smrg{ 703a1d141d5Smrg if (XtIsRealized ((Widget) w)) { 70426df5c7cSmrg#ifdef PRESENT 70526df5c7cSmrg MakePresentData(w); 70626df5c7cSmrg#endif 7073bee1c92Smrg for (int i = 0; i < w->eyes.configuration->count; i++) { 7083bee1c92Smrg eyeLiner (w, TRUE, i); 7093bee1c92Smrg } 7103bee1c92Smrg computePupils (w, w->eyes.mouse, w->eyes.pupils); 7113bee1c92Smrg for (int i = 0; i < w->eyes.configuration->count; i++) { 7123bee1c92Smrg eyeBall (w, TRUE, NULL, i); 7133bee1c92Smrg } 71426df5c7cSmrg#ifdef PRESENT 71526df5c7cSmrg UpdatePresent(w); 71626df5c7cSmrg#endif 717a1d141d5Smrg } 718a1d141d5Smrg} 719a1d141d5Smrg 7202ddb6cf1Smrgstatic void 7212ddb6cf1SmrgdrawEye(EyesWidget w, TPoint newpupil, int num) 7222ddb6cf1Smrg{ 7232ddb6cf1Smrg XPoint xnewpupil, xpupil; 7242ddb6cf1Smrg 7253bee1c92Smrg xpupil.x = Xx(w->eyes.pupils[num].x, w->eyes.pupils[num].y, &w->eyes.t); 7263bee1c92Smrg xpupil.y = Xy(w->eyes.pupils[num].x, w->eyes.pupils[num].y, &w->eyes.t); 7272ddb6cf1Smrg xnewpupil.x = Xx(newpupil.x, newpupil.y, &w->eyes.t); 7282ddb6cf1Smrg xnewpupil.y = Xy(newpupil.x, newpupil.y, &w->eyes.t); 7292ddb6cf1Smrg if ( 7302ddb6cf1Smrg#ifdef XRENDER 7313bee1c92Smrg w->eyes.picture ? !TPointEqual(w->eyes.pupils[num], newpupil) : 7322ddb6cf1Smrg#endif 7332ddb6cf1Smrg !XPointEqual(xpupil, xnewpupil)) { 7343bee1c92Smrg TPoint oldpupil = w->eyes.pupils[num]; 7353bee1c92Smrg w->eyes.pupils[num] = newpupil; 7362ddb6cf1Smrg eyeBall (w, TRUE, &oldpupil, num); 7372ddb6cf1Smrg } 7382ddb6cf1Smrg} 7392ddb6cf1Smrg 7402ddb6cf1Smrgstatic void 7412ddb6cf1SmrgdrawEyes(EyesWidget w, TPoint mouse) 7422ddb6cf1Smrg{ 7432ddb6cf1Smrg int num; 7443bee1c92Smrg TPoint newpupils[w->eyes.configuration->count]; 7452ddb6cf1Smrg 74626df5c7cSmrg#ifdef PRESENT 74726df5c7cSmrg MakePresentData(w); 74826df5c7cSmrg#endif 7492ddb6cf1Smrg if (TPointEqual (mouse, w->eyes.mouse)) { 7502ddb6cf1Smrg if (delays[w->eyes.update + 1] != 0) 7512ddb6cf1Smrg ++w->eyes.update; 7522ddb6cf1Smrg return; 7532ddb6cf1Smrg } 7543bee1c92Smrg computePupils (w, mouse, newpupils); 7553bee1c92Smrg for (num = 0; num < w->eyes.configuration->count; num++) { 7563bee1c92Smrg drawEye(w, newpupils[num], num); 7572ddb6cf1Smrg } 7582ddb6cf1Smrg 7592ddb6cf1Smrg w->eyes.mouse = mouse; 7602ddb6cf1Smrg w->eyes.update = 0; 76126df5c7cSmrg#ifdef PRESENT 76226df5c7cSmrg UpdatePresent(w); 76326df5c7cSmrg#endif 7642ddb6cf1Smrg} 7652ddb6cf1Smrg 7662ddb6cf1Smrgstatic void draw_it_core(EyesWidget w) 7672ddb6cf1Smrg{ 7682ddb6cf1Smrg Window rep_root, rep_child; 7692ddb6cf1Smrg int rep_rootx, rep_rooty; 7702ddb6cf1Smrg unsigned int rep_mask; 7712ddb6cf1Smrg int dx, dy; 7722ddb6cf1Smrg TPoint mouse; 7732ddb6cf1Smrg Display *dpy = XtDisplay (w); 7742ddb6cf1Smrg Window win = XtWindow (w); 7752ddb6cf1Smrg 7762ddb6cf1Smrg XQueryPointer (dpy, win, &rep_root, &rep_child, 7772ddb6cf1Smrg &rep_rootx, &rep_rooty, &dx, &dy, &rep_mask); 7782ddb6cf1Smrg mouse.x = Tx(dx, dy, &w->eyes.t); 7792ddb6cf1Smrg mouse.y = Ty(dx, dy, &w->eyes.t); 7802ddb6cf1Smrg 7812ddb6cf1Smrg drawEyes(w, mouse); 7822ddb6cf1Smrg} 7832ddb6cf1Smrg 784a1d141d5Smrg/* ARGSUSED */ 785a1d141d5Smrgstatic void draw_it ( 786a1d141d5Smrg XtPointer client_data, 787a1d141d5Smrg XtIntervalId *id) /* unused */ 788a1d141d5Smrg{ 789a1d141d5Smrg EyesWidget w = (EyesWidget)client_data; 790a1d141d5Smrg 791a1d141d5Smrg if (XtIsRealized((Widget)w)) { 7922ddb6cf1Smrg draw_it_core(w); 793a1d141d5Smrg } 79426df5c7cSmrg if (!w->eyes.has_xi2) { 79526df5c7cSmrg w->eyes.interval_id = 79626df5c7cSmrg XtAppAddTimeOut(XtWidgetToApplicationContext((Widget) w), 79726df5c7cSmrg delays[w->eyes.update], draw_it, (XtPointer)w); 79826df5c7cSmrg } 799a1d141d5Smrg} /* draw_it */ 800a1d141d5Smrg 801a1d141d5Smrgstatic void Resize (Widget gw) 802a1d141d5Smrg{ 803a1d141d5Smrg EyesWidget w = (EyesWidget) gw; 804a1d141d5Smrg XGCValues xgcv; 805a1d141d5Smrg Widget parent; 8062ddb6cf1Smrg Display *dpy = XtDisplay (w); 807a1d141d5Smrg int x, y; 808a1d141d5Smrg 809a1d141d5Smrg if (XtIsRealized (gw)) 810a1d141d5Smrg { 811a1d141d5Smrg SetTransform (&w->eyes.t, 812a1d141d5Smrg 0, w->core.width, 813a1d141d5Smrg w->core.height, 0, 8143bee1c92Smrg w->eyes.configuration->w_min_x, 8153bee1c92Smrg w->eyes.configuration->w_max_x, 8163bee1c92Smrg w->eyes.configuration->w_min_y, 8173bee1c92Smrg w->eyes.configuration->w_max_y); 81826df5c7cSmrg#ifdef PRESENT 81926df5c7cSmrg if (w->eyes.back_buffer) { 82026df5c7cSmrg xcb_free_pixmap(xt_xcb(w), 82126df5c7cSmrg w->eyes.back_buffer); 82226df5c7cSmrg w->eyes.back_buffer = None; 82326df5c7cSmrg xcb_damage_destroy(xt_xcb(w), 82426df5c7cSmrg w->eyes.back_damage); 82526df5c7cSmrg w->eyes.back_damage = None; 82626df5c7cSmrg } 82726df5c7cSmrg MakePresentData(w); 82826df5c7cSmrg#endif 82926df5c7cSmrg if (EyesDrawable(w) == XtWindow(w)) 83026df5c7cSmrg XClearWindow (dpy, XtWindow (w)); 83126df5c7cSmrg 8322ddb6cf1Smrg#ifdef XRENDER 8332ddb6cf1Smrg if (w->eyes.picture) { 8342ddb6cf1Smrg XRenderFreePicture(dpy, w->eyes.picture); 8352ddb6cf1Smrg w->eyes.picture = 0; 8362ddb6cf1Smrg } 8372ddb6cf1Smrg#endif 838a1d141d5Smrg if (w->eyes.shape_window) { 8392ddb6cf1Smrg w->eyes.shape_mask = XCreatePixmap (dpy, XtWindow (w), 840a1d141d5Smrg w->core.width, w->core.height, 1); 8412ddb6cf1Smrg if (!w->eyes.gc[PART_SHAPE]) 8422ddb6cf1Smrg w->eyes.gc[PART_SHAPE] = XCreateGC (dpy, w->eyes.shape_mask, 8432ddb6cf1Smrg 0, &xgcv); 8442ddb6cf1Smrg XSetForeground (dpy, w->eyes.gc[PART_SHAPE], 0); 8452ddb6cf1Smrg XFillRectangle (dpy, w->eyes.shape_mask, w->eyes.gc[PART_SHAPE], 8462ddb6cf1Smrg 0, 0, w->core.width, w->core.height); 8472ddb6cf1Smrg XSetForeground (dpy, w->eyes.gc[PART_SHAPE], 1); 8483bee1c92Smrg for (int i = 0; i < w->eyes.configuration->count; i++) { 8493bee1c92Smrg eyeLiner (w, FALSE, i); 8503bee1c92Smrg } 851a1d141d5Smrg x = y = 0; 852a1d141d5Smrg for (parent = (Widget) w; XtParent (parent); parent = XtParent (parent)) { 853a1d141d5Smrg x += parent->core.x + parent->core.border_width; 854a1d141d5Smrg x += parent->core.y + parent->core.border_width; 855a1d141d5Smrg } 856a1d141d5Smrg XShapeCombineMask (XtDisplay (parent), XtWindow (parent), ShapeBounding, 857a1d141d5Smrg x, y, w->eyes.shape_mask, ShapeSet); 8582ddb6cf1Smrg XFreePixmap (dpy, w->eyes.shape_mask); 859a1d141d5Smrg } 8602ddb6cf1Smrg#ifdef XRENDER 8612ddb6cf1Smrg if (w->eyes.render) { 8622ddb6cf1Smrg XRenderPictureAttributes pa; 8632ddb6cf1Smrg XRenderPictFormat *pf; 8642ddb6cf1Smrg pf = XRenderFindVisualFormat(dpy, 8652ddb6cf1Smrg DefaultVisualOfScreen(w->core.screen)); 8662ddb6cf1Smrg if (pf) 86726df5c7cSmrg w->eyes.picture = XRenderCreatePicture(dpy, EyesDrawable (w), 8682ddb6cf1Smrg pf, 0, &pa); 8692ddb6cf1Smrg } 8702ddb6cf1Smrg#endif 871a1d141d5Smrg } 872a1d141d5Smrg} 873a1d141d5Smrg 874a1d141d5Smrgstatic void Realize ( 875a1d141d5Smrg Widget gw, 876a1d141d5Smrg XtValueMask *valueMask, 877a1d141d5Smrg XSetWindowAttributes *attrs) 878a1d141d5Smrg{ 879a1d141d5Smrg EyesWidget w = (EyesWidget)gw; 880a1d141d5Smrg 881a1d141d5Smrg if (w->eyes.backing_store != Always + WhenMapped + NotUseful) { 882a1d141d5Smrg attrs->backing_store = w->eyes.backing_store; 883a1d141d5Smrg *valueMask |= CWBackingStore; 884a1d141d5Smrg } 885a1d141d5Smrg XtCreateWindow( gw, (unsigned)InputOutput, (Visual *)CopyFromParent, 886a1d141d5Smrg *valueMask, attrs ); 887a1d141d5Smrg Resize (gw); 88826df5c7cSmrg 88926df5c7cSmrg if (w->eyes.has_xi2) 89026df5c7cSmrg xi2_add_root_listener(gw); 89126df5c7cSmrg else 89226df5c7cSmrg w->eyes.interval_id = 89326df5c7cSmrg XtAppAddTimeOut(XtWidgetToApplicationContext(gw), 89426df5c7cSmrg delays[w->eyes.update], draw_it, (XtPointer)gw); 895a1d141d5Smrg} 896a1d141d5Smrg 897a1d141d5Smrgstatic void Destroy (Widget gw) 898a1d141d5Smrg{ 899a1d141d5Smrg EyesWidget w = (EyesWidget)gw; 9002ddb6cf1Smrg int i; 901a1d141d5Smrg 902a1d141d5Smrg if (w->eyes.interval_id) 903a1d141d5Smrg XtRemoveTimeOut (w->eyes.interval_id); 9042ddb6cf1Smrg for (i = 0; i < PART_MAX; i ++) 9052ddb6cf1Smrg XtReleaseGC(gw, w->eyes.gc[i]); 90626df5c7cSmrg xi2_remove_root_listener(gw); 9072ddb6cf1Smrg#ifdef XRENDER 9082ddb6cf1Smrg if (w->eyes.picture) 9092ddb6cf1Smrg XRenderFreePicture (XtDisplay(w), w->eyes.picture); 9102ddb6cf1Smrg#endif 911a1d141d5Smrg} 912a1d141d5Smrg 913a1d141d5Smrg/* ARGSUSED */ 914a1d141d5Smrgstatic void Redisplay( 915a1d141d5Smrg Widget gw, 916a1d141d5Smrg XEvent *event, 917a1d141d5Smrg Region region) 918a1d141d5Smrg{ 919a1d141d5Smrg EyesWidget w; 920a1d141d5Smrg 921a1d141d5Smrg w = (EyesWidget) gw; 9223bee1c92Smrg for (int i = 0; i < w->eyes.configuration->count; i++) { 9233bee1c92Smrg w->eyes.pupils[i].x = TPOINT_NONE; 9243bee1c92Smrg w->eyes.pupils[i].y = TPOINT_NONE; 9253bee1c92Smrg } 926a1d141d5Smrg (void) repaint_window ((EyesWidget)gw); 927a1d141d5Smrg} 928a1d141d5Smrg 929a1d141d5Smrg/* ARGSUSED */ 930a1d141d5Smrgstatic Boolean SetValues ( 931a1d141d5Smrg Widget current, 932a1d141d5Smrg Widget request, 933a1d141d5Smrg Widget new, 934a1d141d5Smrg ArgList args, 935a1d141d5Smrg Cardinal *num_args) 936a1d141d5Smrg{ 937a1d141d5Smrg return( FALSE ); 938a1d141d5Smrg} 939a1d141d5Smrg 940a1d141d5SmrgEyesClassRec eyesClassRec = { 941a1d141d5Smrg { /* core fields */ 942a1d141d5Smrg /* superclass */ &widgetClassRec, 94326df5c7cSmrg /* class_name */ (char *) "Eyes", 944a1d141d5Smrg /* size */ sizeof(EyesRec), 945a1d141d5Smrg /* class_initialize */ ClassInitialize, 946a1d141d5Smrg /* class_part_initialize */ NULL, 947a1d141d5Smrg /* class_inited */ FALSE, 948a1d141d5Smrg /* initialize */ Initialize, 949a1d141d5Smrg /* initialize_hook */ NULL, 950a1d141d5Smrg /* realize */ Realize, 951a1d141d5Smrg /* actions */ NULL, 952a1d141d5Smrg /* num_actions */ 0, 953a1d141d5Smrg /* resources */ resources, 954a1d141d5Smrg /* num_resources */ XtNumber(resources), 955a1d141d5Smrg /* xrm_class */ NULLQUARK, 956a1d141d5Smrg /* compress_motion */ TRUE, 957a1d141d5Smrg /* compress_exposure */ TRUE, 958a1d141d5Smrg /* compress_enterleave */ TRUE, 959a1d141d5Smrg /* visible_interest */ FALSE, 960a1d141d5Smrg /* destroy */ Destroy, 961a1d141d5Smrg /* resize */ Resize, 962a1d141d5Smrg /* expose */ Redisplay, 963a1d141d5Smrg /* set_values */ SetValues, 964a1d141d5Smrg /* set_values_hook */ NULL, 965a1d141d5Smrg /* set_values_almost */ NULL, 966a1d141d5Smrg /* get_values_hook */ NULL, 967a1d141d5Smrg /* accept_focus */ NULL, 968a1d141d5Smrg /* version */ XtVersion, 969a1d141d5Smrg /* callback_private */ NULL, 970a1d141d5Smrg /* tm_table */ NULL, 971a1d141d5Smrg /* query_geometry */ XtInheritQueryGeometry, 972a1d141d5Smrg } 973a1d141d5Smrg}; 974