2 * usage: .../gui-plan [<windowid>]
5 * off <segname>[/[<movfeat>]
6 * [t|f][i]on <segname>[[/<movfeat>] <movpos>]
7 * [t|f][i]det <segname>[[/<movfeat>] <movpos>]
19 #include "../layout/plan-data-format.h"
24 typedef struct MaskState MaskState;
26 int x, y, width, height;
30 typedef struct PosnState PosnState;
32 int x, y, width, height;
37 typedef struct SegmovfeatState SegmovfeatState;
38 struct SegmovfeatState {
39 SegmovfeatState *next;
40 int invert, det, trainown, posn, redraw_needed;
42 PosnState (*posns)[2/*i*/][2/*det*/];
43 /* posns[n_posns]=unknown if n_posns>1 */
47 const char *progname= "gui-plan";
49 static SegmovfeatState **state, *states_head;
51 static oop_source_sys *sys_events;
53 static int redraw_needed_count, expose_count;
54 static Pixmap bg_pixmap;
55 static unsigned long train_pixel, owned_pixel;
57 static const char *badcmdreport_data;
58 static size_t badcmdreport_recsz;
60 void die_hook(void) { }
61 void die_vprintf_hook(const char *fmt, va_list al) { }
63 static void diex(const char *fn, const char *w) __attribute__((noreturn));
64 static void diex(const char *fn, const char *w) {
65 die("Xlib call failed: %s%s%s%s", fn,
66 (w)?" (":"", (w), (w)?")":"");
69 #define XCALL(f,w,al) do{ \
74 static void diexpm(const char *fn, const char *w, int xpmst)
75 __attribute__((noreturn));
76 static void diexpm(const char *fn, const char *w, int xpmst) {
77 die("Xpm call failed: %s%s%s%s: %s", fn,
78 (w)?" (":"", (w), (w)?")":"", XpmGetErrorString(xpmst));
81 #define XPMCALL(f,w,al) do{ \
83 xpmcall_xpmst= ((f) al); \
84 if (xpmcall_xpmst != XpmSuccess) \
85 diexpm(#f, (w), xpmcall_xpmst); \
88 void vbadcmd(ParseState *ps, const char *fmt, va_list al) {
89 fprintf(stderr,"gui-plan: incorrect input: `%.*s': ",
90 (int)badcmdreport_recsz, badcmdreport_data);
91 vfprintf(stderr,fmt,al);
96 static void *stdin_iferr(oop_source *evts, oop_read *stdin_read,
97 oop_rd_event evt, const char *errmsg, int errnoval,
98 const char *data, size_t recsz, void *cl_v) {
99 die("read stdin: %s", oop_rd_errmsg(stdin_read, evt,
100 errnoval, OOP_RD_STYLE_GETLINE));
104 static int lstrpdbsearch(const char *str, int l,
106 const void *items, int n_items,
108 int min, maxe, try, cmp;
109 const void *try_item;
110 const char *try_name;
115 if (min >= maxe) badcmd(0,"unknown %s `%.*s'",what,l,str);
116 try= min + (maxe - min) / 2;
117 try_item= (const char*)items + itemsz * try;
118 try_name= *(const char *const *)try_item;
119 cmp= lstrstrcmp(str, l, try_name ? try_name : "");
120 if (!cmp) return try;
121 if (cmp < 0) maxe= try;
126 static void *some_exception(oop_source *evts, int fd,
127 oop_event evt, void *cl_v) {
128 die("poll exception on fd %d",fd);
131 static int range_overlap(int x1, int width1, int x2, int width2) {
132 /* works for y's and heights too, obviously. */
136 if (rhs1 <= x2 || rhs2 <= x1) return 0;
140 static void xlib_expose(XExposeEvent *ev) {
143 expose_count= ev->count;
144 if (!ev->width || !ev->height) return;
146 for (fs= states_head;
149 if (fs->redraw_needed)
151 if (!range_overlap(fs->whole.x, fs->whole.width,
152 ev->x, ev->width)) continue;
153 if (!range_overlap(fs->whole.y, fs->whole.height,
154 ev->y, ev->height)) continue;
155 fs->redraw_needed= 1;
156 redraw_needed_count++;
160 static void redraw(SegmovfeatState *fs) {
164 if (fs->redraw_needed) {
165 fs->redraw_needed= 0;
166 redraw_needed_count--;
169 XCALL( XCopyArea, "redraw",
170 (d, bg_pixmap, w, fs->whole.gc,
171 fs->whole.x, fs->whole.y,
172 fs->whole.width, fs->whole.height,
173 fs->whole.x, fs->whole.y) );
174 if (fs->invert >= 0) {
175 src= &fs->posns[fs->posn][fs->invert][fs->det];
176 XCALL( XCopyArea, "redraw",
177 (d, src->pm, w, fs->whole.gc,
178 0,0, src->width, src->height,
181 if (fs->trainown && src && src->edge.x >= 0) {
182 gcv.foreground= fs->trainown>1 ? train_pixel : owned_pixel;
183 XCALL( XChangeGC, "train/own",
184 (d, src->edge.gc, GCForeground, &gcv) );
185 XCALL( XFillRectangle, "train/own",
187 src->edge.x, src->edge.y,
188 src->edge.width, src->edge.height) );
192 static void redraw_as_needed(void) {
195 for (fs= states_head;
198 if (fs->redraw_needed)
200 assert(!redraw_needed_count);
203 static Bool evpredicate_always(Display *d, XEvent *ev, XPointer a) {
207 static void xlib_process(void) {
212 xst= XCheckIfEvent(d,&ev,evpredicate_always,0);
214 if (!redraw_needed_count || expose_count)
221 case Expose: xlib_expose(&ev.xexpose); break;
222 case NoExpose: break;
223 default: die("unrequested event type %d\n",ev.type);
228 static void *xlib_readable(oop_source *evts, int fd,
229 oop_event evt, void *cl_v) {
234 static int thiswordeatonechar(ParseState *ps, int c) {
235 if (ps->thisword[0] == c) {
236 ps->thisword++; ps->lthisword--;
242 static void *stdin_ifok(oop_source *evts, oop_read *cl_read,
243 oop_rd_event evt, const char *errmsg, int errnoval,
244 const char *data, size_t recsz, void *cl_v) {
245 const char *slash, *movfeatname;
247 int invert, det, trainown, segment_ix, movfeat_ix, lmovfeatname;
249 const PlanSegmentData *segment_d;
250 const PlanSegmovfeatData *movfeat_d;
253 if (evt == OOP_RD_EOF)
256 if (evt != OOP_RD_OK)
257 return stdin_iferr(evts,cl_read,evt,errmsg,errnoval,data,recsz,cl_v);
259 badcmdreport_data= data;
260 badcmdreport_recsz= recsz;
266 if (!thiswordstrcmp(&ps,"off")) {
272 thiswordeatonechar(&ps,'t') ? 2 :
273 thiswordeatonechar(&ps,'f') ? 1 : 0;
274 invert= thiswordeatonechar(&ps,'i');
275 det= (!thiswordstrcmp(&ps,"on") ? 0 :
276 !thiswordstrcmp(&ps,"det") ? 1 :
277 (badcmd(&ps,"unknown command"),-1));
280 slash= memchr(ps.thisword, '/', ps.lthisword);
282 movfeatname= slash + 1;
283 lmovfeatname= (ps.thisword + ps.lthisword) - movfeatname;
284 ps.lthisword= slash - ps.thisword;
289 segment_ix= lstrpdbsearch(ps.thisword, ps.lthisword,
290 "segment", ui_plan_data.segments,
291 ui_plan_data.n_segments, sizeof(*segment_d));
292 segment_d= &ui_plan_data.segments[segment_ix];
294 movfeat_ix= lstrpdbsearch(movfeatname, lmovfeatname,
295 "movfeat", segment_d->movfeats,
296 segment_d->n_movfeats, sizeof(*movfeat_d));
297 movfeat_d= &segment_d->movfeats[movfeat_ix];
300 if (invert<0) badcmd(0,"off may not take movfeatpos");
301 ps_neednumber(&ps, &posn, 0, movfeat_d->n_posns-1, "movfeatpos");
303 if (invert>=0 && movfeat_d->n_posns > 1) {
304 posn= movfeat_d->n_posns;
312 fs= &state[segment_ix][movfeat_ix];
315 fs->trainown= trainown;
324 static void loadmask(MaskState *out, const PlanPixmapDataRef *ppd,
325 XGCValues *gcv, long gcv_mask) {
326 static XpmColorSymbol coloursymbols[2]= {
327 { (char*)"space", 0, 0 },
328 { (char*)"mark", 0, 1 }
331 XpmAttributes mattribs;
336 mattribs.valuemask= XpmDepth | XpmColorSymbols;
338 mattribs.colorsymbols= coloursymbols;
339 mattribs.numsymbols= sizeof(coloursymbols) / sizeof(*coloursymbols);
340 XPMCALL( XpmCreatePixmapFromData, "mask",
341 (d,w, (char**)ppd->d, &pm,0, &mattribs) );
342 out->width= mattribs.width;
343 out->height= mattribs.height;
345 gcv->clip_x_origin= out->x;
346 gcv->clip_y_origin= out->y;
348 out->gc= XCreateGC(d,w,
349 gcv_mask | GCClipXOrigin | GCClipYOrigin | GCClipMask,
351 XCALL( XFreePixmap, "mask", (d,pm) );
354 int main(int argc, const char *const *argv) {
357 XpmAttributes mattribs;
358 XWindowAttributes wattribs;
359 int segment_ix, movfeat_ix, posn, invert, det, oor;
363 const PlanSegmentData *segment_d;
364 const PlanSegmovfeatData *movfeat_d;
366 d= XOpenDisplay(0); if (!d) die("XOpenDisplay failed");
368 if ((arg= *++argv)) {
371 if (!strcmp(arg,"--sizes")) {
372 printf("%d\n%d\n", ui_plan_data.xsz, ui_plan_data.ysz);
373 if (ferror(stdout) || fflush(stdout)) diee("print stdout");
377 if (arg[0]=='-') die("invalid option(s)");
379 errno=0; w= strtoul(arg,&ep,0);
380 if (errno || ep==arg || *ep) die("bad windowid");
382 w= XCreateSimpleWindow(d, DefaultRootWindow(d),
383 0,0, ui_plan_data.xsz, ui_plan_data.ysz,
385 if (w == None) diex("XCreateSimpleWindow", "initial");
388 XCALL( XGetWindowAttributes, 0, (d,w,&wattribs) );
390 XPMCALL( XpmCreatePixmapFromData, "background",
391 (d,w, (char**)ui_plan_data.background, &bg_pixmap,0,0) );
393 XCALL( XSetWindowBackgroundPixmap, 0, (d,w,bg_pixmap) );
395 XCALL( XAllocNamedColor, "white",
396 (d, wattribs.colormap, "#ffffff",
398 train_pixel= colour.pixel;
400 XCALL( XAllocNamedColor, "owned",
401 (d, wattribs.colormap, "#a0a0a0",
403 owned_pixel= colour.pixel;
405 state= mmalloc(sizeof(*state) * ui_plan_data.n_segments);
406 for (segment_ix= 0, segment_d= ui_plan_data.segments;
407 segment_ix < ui_plan_data.n_segments;
408 segment_ix++, segment_d++) {
409 state[segment_ix]= fs=
410 mmalloc(sizeof(**state) * segment_d->n_movfeats);
411 for (movfeat_ix= 0, movfeat_d= segment_d->movfeats;
412 movfeat_ix < segment_d->n_movfeats;
413 movfeat_ix++, movfeat_d++, fs++) {
414 fs->next= states_head; states_head= fs;
418 fs->posn= movfeat_d->n_posns;
419 if (fs->posn==1) fs->posn= 0;
420 fs->redraw_needed= 0;
422 loadmask(&fs->whole, &movfeat_d->mask, &gcv, 0);
424 fs->posns= mmalloc(sizeof(*fs->posns)*(fs->posn+1));
425 for (posn= 0; posn <= fs->posn; posn++)
426 for (invert=0; invert<2; invert++)
427 for (det=0; det<2; det++) {
428 PosnState *ps= &fs->posns[posn][invert][det];
429 const PlanPixmapOnData *ppod=
430 posn < movfeat_d->n_posns
431 ? &movfeat_d->posns[posn] : 0;
432 const PlanPixmapDataRef *ppdr= ppod
433 ? &ppod->on[invert][det]
434 : &movfeat_d->unknown[invert][det];
437 mattribs.valuemask= 0;
438 XPMCALL( XpmCreatePixmapFromData, "main",
443 ps->width= mattribs.width;
444 ps->height= mattribs.height;
446 loadmask(&ps->edge, &ppod->pedge, &gcv, 0);
455 sys_events= oop_sys_new(); if (!sys_events) diee("oop_sys_new");
456 events= oop_sys_source(sys_events); assert(events);
458 rd= oop_rd_new_fd(events, 0, 0,0);
459 if (!rd) diee("oop_rd_new_fd");
460 oor= oop_rd_read(rd, OOP_RD_STYLE_GETLINE, 1024,
463 if (oor) diee("oop_rd_read");
465 events->on_fd(events, 0, OOP_EXCEPTION, some_exception, 0);
466 events->on_fd(events, ConnectionNumber(d), OOP_READ, xlib_readable, 0);
467 events->on_fd(events, ConnectionNumber(d), OOP_EXCEPTION, some_exception, 0);
469 XCALL( XSelectInput, 0, (d,w, ExposureMask) );
472 XCALL( XClearArea, "initial", (d,w, 0,0,0,0, True) );
474 XCALL( XMapWindow, 0, (d,w) );
479 oop_sys_run(sys_events);