2 * usage: .../gui-plan [<windowid>]
5 * off <segname>[/[<movfeat>]
6 * [i]on <segname>[[/<movfeat>] <movpos>]
7 * [i]det <segname>[[/<movfeat>] <movpos>]
19 #include "../layout/plan-data-format.h"
24 typedef struct SegmovfeatState SegmovfeatState;
25 struct SegmovfeatState {
26 SegmovfeatState *next;
27 int invert, det, posn, x, y, width, height, redraw_needed;
29 Pixmap (*posns)[2/*i*/][2/*det*/];
34 static SegmovfeatState **state, *states_head;
36 static oop_source_sys *sys_events;
38 static int redraw_needed_count, expose_count;
40 static void diex(const char *fn, const char *w) __attribute__((noreturn));
41 static void diex(const char *fn, const char *w) {
42 die("Xlib call failed: %s%s%s%s", fn,
43 (w)?" (":"", (w), (w)?")":"");
46 #define XCALL(f,w,al) do{ \
51 static void diexpm(const char *fn, const char *w, int xpmst)
52 __attribute__((noreturn));
53 static void diexpm(const char *fn, const char *w, int xpmst) {
54 die("Xpm call failed: %s%s%s%s: %s", fn,
55 (w)?" (":"", (w), (w)?")":"", XpmGetErrorString(xpmst));
58 #define XPMCALL(f,w,al) do{ \
60 xpmcall_xpmst= ((f) al); \
61 if (xpmcall_xpmst != XpmSuccess) \
62 diexpm(#f, (w), xpmcall_xpmst); \
65 void vbadcmd(ParseState *ps, const char *fmt, va_list al) {
66 fprintf(stderr,"gui-plan: incorrect input: ");
67 vfprintf(stderr,fmt,al);
72 static void *stdin_iferr(oop_source *evts, oop_read *stdin_read,
73 oop_rd_event evt, const char *errmsg, int errnoval,
74 const char *data, size_t recsz, void *cl_v) {
75 die("read stdin: %s", oop_rd_errmsg(stdin_read, evt,
76 errnoval, OOP_RD_STYLE_GETLINE));
80 static int lstrpdbsearch(const char *str, int l,
82 const void *items, int n_items,
84 int min, maxe, try, cmp;
91 if (min >= maxe) badcmd(0,"unknown %s",what);
92 try= min + (maxe - min) / 2;
93 try_item= (const char*)items + itemsz * try;
94 try_name= *(const char *const *)try_item;
95 cmp= lstrstrcmp(str, l, try_name ? try_name : "");
97 if (cmp < 0) maxe= try;
102 static void *some_exception(oop_source *evts, int fd,
103 oop_event evt, void *cl_v) {
104 die("poll exception on fd %d",fd);
107 static int range_overlap(int x1, int width1, int x2, int width2) {
108 /* works for y's and heights too, obviously. */
112 if (rhs1 <= x2 || rhs2 <= x1) return 0;
116 static void xlib_expose(XExposeEvent *ev) {
119 expose_count= ev->count;
120 if (!ev->width || !ev->height) return;
122 for (fs= states_head;
125 if (fs->redraw_needed)
127 if (!range_overlap(fs->x, fs->width,
128 ev->x, ev->width)) continue;
129 if (!range_overlap(fs->y, fs->height,
130 ev->y, ev->height)) continue;
131 fs->redraw_needed= 1;
132 redraw_needed_count++;
136 static void redraw(SegmovfeatState *fs) {
139 if (fs->redraw_needed) {
140 fs->redraw_needed= 0;
141 redraw_needed_count--;
143 if (fs->invert < 0) {
144 XCALL( XFillRectangle, "redraw",
147 fs->width, fs->height) );
149 src= fs->posns[fs->posn][fs->invert][fs->det];
150 XCALL( XCopyArea, "redraw",
152 0,0, fs->width, fs->height,
157 static void redraw_as_needed(void) {
160 for (fs= states_head;
163 if (fs->redraw_needed)
165 assert(!redraw_needed_count);
168 static Bool evpredicate_always(Display *d, XEvent *ev, XPointer a) {
172 static void xlib_process(void) {
177 xst= XCheckIfEvent(d,&ev,evpredicate_always,0);
179 if (!redraw_needed_count || expose_count)
186 case Expose: xlib_expose(&ev.xexpose); break;
187 case NoExpose: break;
188 default: die("unrequested event type %d\n",ev.type);
193 static void *xlib_readable(oop_source *evts, int fd,
194 oop_event evt, void *cl_v) {
199 static void *stdin_ifok(oop_source *evts, oop_read *cl_read,
200 oop_rd_event evt, const char *errmsg, int errnoval,
201 const char *data, size_t recsz, void *cl_v) {
202 const char *slash, *movfeatname;
204 int invert, det, segment_ix, movfeat_ix, lmovfeatname;
206 const PlanSegmentData *segment_d;
207 const PlanSegmovfeatData *movfeat_d;
210 if (evt == OOP_RD_EOF)
213 if (evt != OOP_RD_OK)
214 return stdin_iferr(evts,cl_read,evt,errmsg,errnoval,data,recsz,cl_v);
220 if (!thiswordstrcmp(&ps,"off")) {
224 invert= (ps.thisword[0]=='i');
225 if (invert) { ps.thisword++; ps.lthisword--; }
226 det= (!thiswordstrcmp(&ps,"on") ? 0 :
227 !thiswordstrcmp(&ps,"det") ? 1 :
228 (badcmd(&ps,"unknown command"),-1));
231 slash= memchr(ps.thisword, '/', ps.lthisword);
233 movfeatname= slash + 1;
234 lmovfeatname= (ps.thisword + ps.lthisword) - movfeatname;
235 ps.lthisword= slash - ps.thisword;
240 segment_ix= lstrpdbsearch(ps.thisword, ps.lthisword,
241 "segment", ui_plan_data.segments,
242 ui_plan_data.n_segments, sizeof(*segment_d));
243 segment_d= &ui_plan_data.segments[segment_ix];
245 movfeat_ix= lstrpdbsearch(movfeatname, lmovfeatname,
246 "movfeat", segment_d->movfeats,
247 segment_d->n_movfeats, sizeof(*movfeat_d));
248 movfeat_d= &segment_d->movfeats[movfeat_ix];
251 if (invert<0) badcmd(0,"off may not take movfeatpos");
252 ps_neednumber(&ps, &posn, 0, movfeat_d->n_posns-1, "movfeatpos");
254 if (invert>=0 && movfeat_d->n_posns > 1) badcmd(0,"movfeatpos needed");
260 fs= &state[segment_ix][movfeat_ix];
271 int main(int argc, const char *const *argv) {
272 static XpmColorSymbol coloursymbols[2]= {
273 { (char*)"space", 0, 0 },
274 { (char*)"mark", 0, 1 }
281 XpmAttributes mattribs;
282 XWindowAttributes wattribs;
283 XColor background_colour;
284 int segment_ix, movfeat_ix, posn, invert, det, oor;
286 const PlanSegmentData *segment_d;
287 const PlanSegmovfeatData *movfeat_d;
290 d= XOpenDisplay(0); if (!d) die("XOpenDisplay failed");
292 if ((arg= *++argv)) {
295 if (!strcmp(arg,"--sizes")) {
296 printf("%d\n%d\n", ui_plan_data.xsz, ui_plan_data.ysz);
297 if (ferror(stdout) || fflush(stdout)) diee("print stdout");
301 if (arg[0]=='-') die("invalid option(s)");
303 errno=0; w= strtoul(arg,&ep,0);
304 if (errno || ep==arg || *ep) die("bad windowid");
306 w= XCreateSimpleWindow(d, DefaultRootWindow(d),
307 0,0, ui_plan_data.xsz, ui_plan_data.ysz,
309 if (w == None) diex("XCreateSimpleWindow", "initial");
312 XCALL( XGetWindowAttributes, 0, (d,w,&wattribs) );
314 XPMCALL( XpmCreatePixmapFromData, "background",
315 (d,w, (char**)ui_plan_data.background, &bg_pixmap,0,0) );
317 XCALL( XSetWindowBackgroundPixmap, 0, (d,w,bg_pixmap) );
318 XCALL( XFreePixmap, "background", (d,bg_pixmap) );
320 XCALL( XAllocNamedColor, "background",
321 (d, wattribs.colormap, ui_plan_colour_off,
322 &background_colour, &background_colour) );
324 state= mmalloc(sizeof(*state) * ui_plan_data.n_segments);
325 for (segment_ix= 0, segment_d= ui_plan_data.segments;
326 segment_ix < ui_plan_data.n_segments;
327 segment_ix++, segment_d++) {
328 state[segment_ix]= fs=
329 mmalloc(sizeof(**state) * segment_d->n_movfeats);
330 for (movfeat_ix= 0, movfeat_d= segment_d->movfeats;
331 movfeat_ix < segment_d->n_movfeats;
332 movfeat_ix++, movfeat_d++, fs++) {
333 fs->next= states_head; states_head= fs;
335 fs->det= fs->posn= 0;
338 fs->redraw_needed= 0;
339 mattribs.valuemask= XpmDepth | XpmColorSymbols;
341 mattribs.colorsymbols= coloursymbols;
342 mattribs.numsymbols= sizeof(coloursymbols) / sizeof(*coloursymbols);
343 XPMCALL( XpmCreatePixmapFromData, "mask",
344 (d,w, (char**)movfeat_d->off, &mask,0, &mattribs) );
345 fs->width= mattribs.width;
346 fs->height= mattribs.height;
348 gcv.clip_x_origin= fs->x;
349 gcv.clip_y_origin= fs->y;
351 gcv.foreground= background_colour.pixel;
352 fs->gc= XCreateGC(d,w,
353 GCClipXOrigin | GCClipYOrigin
354 | GCClipMask | GCForeground,
356 XCALL( XFreePixmap, "mask", (d,mask) );
358 fs->posns= mmalloc(sizeof(*fs->posns)*movfeat_d->n_posns);
359 for (posn= 0; posn < movfeat_d->n_posns; posn++)
360 for (invert=0; invert<2; invert++)
361 for (det=0; det<2; det++) {
362 XPMCALL( XpmCreatePixmapFromData, "main",
364 (char**)(movfeat_d->posns[posn].a[invert][det]),
365 &fs->posns[posn][invert][det],
371 sys_events= oop_sys_new(); if (!sys_events) diee("oop_sys_new");
372 events= oop_sys_source(sys_events); assert(events);
374 rd= oop_rd_new_fd(events, 0, 0,0);
375 if (!rd) diee("oop_rd_new_fd");
376 oor= oop_rd_read(rd, OOP_RD_STYLE_GETLINE, 1024,
379 if (oor) diee("oop_rd_read");
381 events->on_fd(events, 0, OOP_EXCEPTION, some_exception, 0);
382 events->on_fd(events, ConnectionNumber(d), OOP_READ, xlib_readable, 0);
383 events->on_fd(events, ConnectionNumber(d), OOP_EXCEPTION, some_exception, 0);
385 XCALL( XSelectInput, 0, (d,w, ExposureMask) );
388 XCALL( XClearArea, "initial", (d,w, 0,0,0,0, True) );
390 XCALL( XMapWindow, 0, (d,w) );
395 oop_sys_run(sys_events);