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>]
16 #include <sys/types.h>
17 #include <sys/socket.h>
22 #include <X11/Xproto.h>
24 typedef int ErrorCode;
28 #include "../layout/plan-data-format.h"
29 #include "../layout/layout-data.h"
35 #define NSEGMENTS (ui_plan_data.n_segments)
37 typedef struct MaskState MaskState;
39 int x, y, width, height;
43 typedef struct PosnState PosnState;
45 int x, y, width, height;
51 unsigned on:1, inv:1, det:1, trainown:2, updated_tmp:1,
52 resolution_problem:1; /* for multiplexer client only */
55 typedef struct SegmovfeatState SegmovfeatState;
56 struct SegmovfeatState {
57 SegmovfeatState *next;
59 unsigned redraw_needed:1;
62 PosnState (*posns)[2/*i*/][2/*det*/];
63 /* posns[n_posns]=unknown if n_posns>1 */
67 const char *progname= "gui-plan";
69 typedef struct TrainState TrainState;
73 SegFlags flags; /* used by multiplexer client */
78 static SegState *state;
79 static SegmovfeatState *states_head;
80 static StartupState stastate;
82 static oop_source_sys *sys_events;
84 static int redraw_needed_count, expose_count;
85 static Pixmap bg_pixmap;
86 static unsigned long train_pixel, owned_pixel;
88 static const char *stastate_names[]= DEFINE_STASTATE_DATA;
90 static const char *badcmdreport_data;
91 static size_t badcmdreport_recsz;
93 void die_hook(void) { }
94 void die_vprintf_hook(const char *fmt, va_list al) { }
96 static void xlib_process(void);
98 static void diex(const char *fn, const char *w) __attribute__((noreturn));
99 static void diex(const char *fn, const char *w) {
100 die("Xlib call failed: %s%s%s%s", fn,
101 (w)?" (":"", (w), (w)?")":"");
104 #define XCALL(f,w,al) do{ \
109 static void diexpm(const char *fn, const char *w, int xpmst)
110 __attribute__((noreturn));
111 static void diexpm(const char *fn, const char *w, int xpmst) {
112 die("Xpm call failed: %s%s%s%s: %s", fn,
113 (w)?" (":"", (w), (w)?")":"", XpmGetErrorString(xpmst));
116 #define XPMCALL(f,w,al) do{ \
118 xpmcall_xpmst= ((f) al); \
119 if (xpmcall_xpmst != XpmSuccess) \
120 diexpm(#f, (w), xpmcall_xpmst); \
123 static void die_graphicsexpose(const XEvent *ev) {
124 die("GraphicsExpose %lx(%s) x=%d y=%d w=%d h=%d count=%d"
126 (unsigned long)ev->xgraphicsexpose.drawable,
127 ev->xgraphicsexpose.drawable==win ? "w" : "?",
128 ev->xgraphicsexpose.x,
129 ev->xgraphicsexpose.y,
130 ev->xgraphicsexpose.width,
131 ev->xgraphicsexpose.height,
132 ev->xgraphicsexpose.count,
133 ev->xgraphicsexpose.major_code,
134 ev->xgraphicsexpose.major_code==X_CopyArea ? "CA" :
135 ev->xgraphicsexpose.major_code==X_CopyPlane ? "CP" : "?");
138 /*---------- input handling ----------*/
142 void (*on_eof)(void);
143 void (*on_input_line)(ParseState *ps);
144 int (*on_badcmd)(void);
147 static const InputStream *instream;
149 static void *input_iferr(oop_source *evts, oop_read *stdin_read,
150 oop_rd_event evt, const char *errmsg, int errnoval,
151 const char *data, size_t recsz, void *u_v) {
153 emsg= oop_rd_errmsg(stdin_read, evt, errnoval, OOP_RD_STYLE_GETLINE);
154 die("%s: %s", instream->name, emsg);
157 static void *input_ifok(oop_source *evts, oop_read *cl_read,
158 oop_rd_event evt, const char *errmsg, int errnoval,
159 const char *data, size_t recsz, void *u_v) {
162 if (evt == OOP_RD_EOF) {
166 if (evt != OOP_RD_OK) {
167 input_iferr(evts,cl_read,evt,errmsg,errnoval,data,recsz,0);
171 badcmdreport_data= data;
172 badcmdreport_recsz= recsz;
175 instream->on_input_line(&ps);
180 static void *some_exception(oop_source *evts, int fd,
181 oop_event evt, void *name_v) {
182 const char *name= name_v;
183 die("poll exception on %s (fd %d)",name,fd);
186 int vbadcmd(ParseState *ps, const char *fmt, va_list al) {
187 fprintf(stderr,"gui-plan: incorrect input: `%.*s': ",
188 (int)badcmdreport_recsz, badcmdreport_data);
189 vfprintf(stderr,fmt,al);
191 return instream->on_badcmd();
194 static int lstrpdbsearch(const char *str, int l,
196 const void *items, int n_items,
198 int min, maxe, try, cmp;
199 const void *try_item;
200 const char *try_name;
205 if (min >= maxe) { badcmd(0,"unknown %s `%.*s'",what,l,str); return -1; }
206 try= min + (maxe - min) / 2;
207 try_item= (const char*)items + itemsz * try;
208 try_name= *(const char *const *)try_item;
209 cmp= lstrstrcmp(str, l, try_name ? try_name : "");
210 if (!cmp) return try;
211 if (cmp < 0) maxe= try;
216 static int lstrpdbsearch_movfeat(const char *str, int l,
217 const PlanSegmentData *sd) {
218 return lstrpdbsearch(str, l, "movfeat", sd->movfeats, sd->n_movfeats,
219 sizeof(*sd->movfeats));
221 static int lstrpdbsearch_segment(const char *str, int l) {
222 return lstrpdbsearch(str, l, "segment",
223 ui_plan_data.segments, ui_plan_data.n_segments,
224 sizeof(*ui_plan_data.segments));
227 /*---------- drawing etc. ----------*/
229 static int range_overlap(int x1, int width1, int x2, int width2) {
230 /* works for y's and heights too, obviously. */
234 if (rhs1 <= x2 || rhs2 <= x1) return 0;
238 static void redraw_mark(SegmovfeatState *fs) {
239 if (fs->redraw_needed) return;
240 fs->redraw_needed= 1;
241 redraw_needed_count++;
244 static void xlib_expose(XExposeEvent *ev) {
247 expose_count= ev->count;
248 if (!ev->width || !ev->height) return;
250 for (fs= states_head;
253 if (!range_overlap(fs->whole.x, fs->whole.width,
254 ev->x, ev->width)) continue;
255 if (!range_overlap(fs->whole.y, fs->whole.height,
256 ev->y, ev->height)) continue;
261 static void copyarea(const char *what,
262 Drawable src, GC gc, int src_x, int src_y,
263 int w, int h, int dest_x, int dest_y) {
264 XCALL( XCopyArea, what,
265 (disp, src, win, gc, src_x,src_y, w,h, dest_x,dest_y) );
268 // if (XCheckTypedEvent(disp,GraphicsExpose,&ev))
269 // die_graphicsexpose(&ev);
272 static void redraw(SegmovfeatState *fs) {
276 if (fs->redraw_needed) {
277 fs->redraw_needed= 0;
278 redraw_needed_count--;
281 copyarea("redraw", bg_pixmap, fs->whole.gc,
282 fs->whole.x, fs->whole.y,
283 fs->whole.width, fs->whole.height,
284 fs->whole.x, fs->whole.y);
287 src= &fs->posns[fs->posn][fs->flags.inv][fs->flags.det];
288 copyarea("redraw-on", src->pm, fs->whole.gc,
289 0,0, src->width, src->height,
292 if (fs->flags.trainown && src && src->edge.x >= 0) {
293 gcv.foreground= fs->flags.trainown>1 ? train_pixel : owned_pixel;
294 XCALL( XChangeGC, "train/own",
295 (disp, src->edge.gc, GCForeground, &gcv) );
296 XCALL( XFillRectangle, "train/own",
297 (disp, win, src->edge.gc,
298 src->edge.x, src->edge.y,
299 src->edge.width, src->edge.height) );
303 static void redraw_as_needed(void) {
306 for (fs= states_head;
309 if (fs->redraw_needed)
311 assert(!redraw_needed_count);
314 static Bool evpredicate_always(Display *d, XEvent *ev, XPointer a) {
318 static void xlib_process(void) {
323 xst= XCheckIfEvent(disp,&ev,evpredicate_always,0);
325 if (!redraw_needed_count || expose_count)
332 case Expose: xlib_expose(&ev.xexpose); break;
333 case NoExpose: break;
334 case MappingNotify: break;
335 case GraphicsExpose: die_graphicsexpose(&ev);
336 default: die("unrequested event type %d\n",ev.type);
341 static void *xlib_readable(oop_source *evts, int fd,
342 oop_event evt, void *cl_v) {
347 static int thiswordeatonechar(ParseState *ps, int c) {
348 if (ps->thisword[0] == c) {
349 ps->thisword++; ps->lthisword--;
355 static void loadmask(MaskState *out, const PlanPixmapDataRef *ppd,
356 XGCValues *gcv, long gcv_mask) {
357 static XpmColorSymbol coloursymbols[2]= {
358 { (char*)"space", 0, 0 },
359 { (char*)"mark", 0, 1 }
362 XpmAttributes mattribs;
367 mattribs.valuemask= XpmDepth | XpmColorSymbols;
369 mattribs.colorsymbols= coloursymbols;
370 mattribs.numsymbols= sizeof(coloursymbols) / sizeof(*coloursymbols);
371 XPMCALL( XpmCreatePixmapFromData, "mask",
372 (disp,win, (char**)ppd->d, &pm,0, &mattribs) );
373 out->width= mattribs.width;
374 out->height= mattribs.height;
376 gcv->clip_x_origin= out->x;
377 gcv->clip_y_origin= out->y;
379 out->gc= XCreateGC(disp,win,
380 gcv_mask | GCClipXOrigin | GCClipYOrigin | GCClipMask,
382 XCALL( XFreePixmap, "mask", (disp,pm) );
385 /*---------- stdin input handling ----------*/
387 static void stdin_eof(void) { exit(0); }
388 static int stdin_badcmd(void) { exit(8); }
390 static void stdin_input_line(ParseState *ps) {
391 const char *slash, *movfeatname;
392 int invert, det, trainown, segment_ix, movfeat_ix, lmovfeatname;
394 const PlanSegmentData *segment_d;
395 const PlanSegmovfeatData *movfeat_d;
400 if (!thiswordstrcmp(ps,"off")) {
406 thiswordeatonechar(ps,'t') ? 2 :
407 thiswordeatonechar(ps,'f') ? 1 : 0;
408 invert= thiswordeatonechar(ps,'i');
409 det= (!thiswordstrcmp(ps,"on") ? 0 :
410 !thiswordstrcmp(ps,"det") ? 1 :
411 (badcmd(ps,"unknown command"),-1));
414 slash= memchr(ps->thisword, '/', ps->lthisword);
416 movfeatname= slash + 1;
417 lmovfeatname= (ps->thisword + ps->lthisword) - movfeatname;
418 ps->lthisword= slash - ps->thisword;
423 segment_ix= lstrpdbsearch_segment(ps->thisword,ps->lthisword);
424 segment_d= &ui_plan_data.segments[segment_ix];
426 movfeat_ix= lstrpdbsearch_movfeat(movfeatname, lmovfeatname, segment_d);
427 movfeat_d= &segment_d->movfeats[movfeat_ix];
430 if (invert<0) badcmd(0,"off may not take movfeatpos");
431 ps_neednumber(ps, &posn, 0, movfeat_d->n_posns-1, "movfeatpos");
433 if (invert>=0 && movfeat_d->n_posns > 1) {
434 posn= movfeat_d->n_posns;
442 fs= &state[segment_ix].mfs[movfeat_ix];
445 fs->flags.inv= invert;
451 fs->flags.trainown= trainown;
457 static const InputStream stdin_is= {
458 "stdin", stdin_eof, stdin_input_line, stdin_badcmd
461 /*---------- multiplexer client ----------*/
463 static OutBufferChain sock= { (char*)"multiplexer socket", -1 };
465 static void sockvprintf(const char *fmt, va_list al)
466 __attribute__((format(printf,1,0)));
467 static void sockprintf(const char *fmt, ...)
468 __attribute__((format(printf,1,2)));
470 static void sockvprintf(const char *fmt, va_list al) {
471 ovprintf(&sock,fmt,al);
473 static void sockprintf(const char *fmt, ...) {
480 static int sock_clientconnect(const char *node, const char *service) {
481 struct addrinfo *aires, *try, hints;
482 char niaddrbuf[256], niportbuf[64];
485 memset(&hints,0,sizeof(hints));
486 hints.ai_family= PF_UNSPEC;
487 hints.ai_socktype= SOCK_STREAM;
488 r= getaddrinfo(node,service,&hints,&aires);
489 if (r) die("getaddrinfo node `%s' service `%s' failed: %s\n",
490 node,service,gai_strerror(r));
492 for (try=aires; try; try=try->ai_next) {
493 assert(try->ai_socktype == SOCK_STREAM);
495 r= getnameinfo(try->ai_addr, try->ai_addrlen,
496 niaddrbuf, sizeof(niaddrbuf),
497 niportbuf, sizeof(niportbuf),
498 NI_NUMERICHOST|NI_NUMERICSERV);
501 printf("trying %s,%s... ",niaddrbuf,niportbuf);
504 sock= socket(try->ai_family, SOCK_STREAM, try->ai_protocol);
506 printf("couldn't create socket: %s\n",strerror(errno));
510 r= connect(sock, try->ai_addr, try->ai_addrlen);
512 printf("connected\n");
516 printf("connect failed: %s\n",strerror(errno));
523 static void sock_eof(void) { die("EOF on multiplexer connection"); }
524 static int sock_badcmd(void) { return -1; }
526 /*---------- multiplexer protocol ----------*/
529 struct { struct TrainState *next, *back; } others;
534 static struct { TrainState *head, *tail; } trains;
536 #define FOR_S for (s=0; s<NSEGMENTS; s++)
538 static void mx_clear_updated(void) {
541 state[s].flags.updated_tmp= 0;
544 static void mx_redraw_feat(int s, int f) {
545 SegState *ss= &state[s];
546 SegmovfeatState *fs= &ss->mfs[f];
547 fs->flags= ss->flags;
548 fs->flags.on= stastate > Sta_Off && poweron;
549 if (stastate==Sta_Resolving)
550 fs->flags.trainown= ss->flags.resolution_problem ? 2 : 0;
554 static void mx_redraw_seg(int s) {
556 assert(!!state[s].flags.trainown == !!state[s].owner);
557 for (f=0; f < ui_plan_data.segments[s].n_movfeats; f++)
561 static void mx_redraw_all(void) {
567 static int ps_needsegment(ParseState *ps) {
568 int r= ps_needword(ps); if (r) return -1;
569 return lstrpdbsearch_segment(ps->thisword,ps->lthisword);
572 static void si_detect(ParseState *ps) {
576 s= ps_needsegment(ps); if (s<0) return;
577 r= ps_neednumber(ps,&dl,0,1,"detection flag"); if (r) return;
578 state[s].flags.det= dl;
582 static void si_polarity(ParseState *ps) {
587 if (*ps->remain++ != '<') { badcmd(ps,"missing <"); return; }
589 end= strchr(ps->remain,'>');
590 if (!end) { badcmd(ps,"missing >"); return; }
592 while (ps->remain < end) {
593 delim= memchr(ps->remain, ',', end - ps->remain);
594 if (!delim) delim= end;
596 ps->thisword= ps->remain;
597 ps->lthisword= delim - ps->remain;
600 s= lstrpdbsearch_segment(ps->thisword,ps->lthisword); if (s<0) continue;
601 state[s].flags.updated_tmp= 1;
604 if (state[s].flags.inv == state[s].flags.updated_tmp)
606 state[s].flags.inv= state[s].flags.updated_tmp;
611 static void si_movpos(ParseState *ps) {
613 s= ps_needsegment(ps); if (s<0) return;
614 r= ps_needword(ps); if (r) return;
615 if (thiswordstrcmp(ps,"position")) { badcmd(ps,"weird movpos"); return; }
617 r= ps_needword(ps); if (r) return;
618 if (!thiswordstrcmp(ps,"?")) {
620 for (f=0; f < ui_plan_data.segments[s].n_movfeats; f++)
621 state[s].mfs[f].posn= ui_plan_data.segments[s].movfeats[f].n_posns;
626 const char *feat= ps->thisword;
627 const char *endword= ps->thisword + ps->lthisword;
628 while (feat < endword) {
631 featl < ps->lthisword && CTYPE(isalpha, feat[featl]);
635 errno=0; unsigned long pos= strtoul(feat+featl,&ep,10);
637 if (!featl || errno || ep==feat+featl || ep > endword) {
638 badcmd(ps,"bad movfeatpos `%.*s'", (int)(endword - feat), feat);
642 f= lstrpdbsearch_movfeat(feat, featl, &ui_plan_data.segments[s]);
645 if (pos >= ui_plan_data.segments[s].movfeats[f].n_posns)
646 { badcmd(ps,"out of range movfeat %.*s%lu", featl,feat, pos); }
648 state[s].mfs[f].posn= pos;
655 static void si_on(ParseState *ps) {
660 static void si_off(ParseState *ps) {
665 static void si_train(ParseState *ps) {
672 r= ps_needword(ps); /* <train> */ if (r) return;
674 /* atomise the train name */
675 for (train=trains.head;
677 train= train->others.next)
678 if (!thiswordstrcmp(ps,train->name))
681 train= mmalloc(sizeof(*train));
682 train->name= mmalloc(ps->lthisword+1);
683 memcpy(train->name,ps->thisword,ps->lthisword);
684 train->name[ps->lthisword]= 0;
685 DLIST2_APPEND(trains,train,others);
688 r= ps_needword(ps); if (r) return;
689 if (thiswordstrcmp(ps,"has")) { badcmd(ps,"weird train"); return; }
690 while (ps_word(ps) >= 0) {
691 sl= strcspn(ps->thisword, "/.!*~#+");
692 if (sl > ps->lthisword) sl= ps->lthisword;
694 if (*seg=='-') { seg++; sl--; }
695 s= lstrpdbsearch_segment(seg,sl); if (s<0) continue;
696 lastchar= ps->thisword[ps->lthisword-1];
697 state[s].owner= train;
698 state[s].flags.updated_tmp= 1;
699 state[s].flags.trainown= 1 + (lastchar=='!' || lastchar=='*');
702 if (state[s].flags.updated_tmp) {
704 } else if (state[s].owner==train) {
706 state[s].flags.trainown= 0;
712 typedef struct MuxEventInfo MuxEventInfo;
713 typedef void MuxEventFn(ParseState *ps);
715 struct MuxEventInfo {
716 const char *prefix; /* 0: sentinel */
717 const char *remainpat; /* 0: no pattern in select needed */
718 MuxEventFn *fn; /* 0: just ignore matching messages */
720 static const MuxEventInfo muxeventinfos[];
722 static void si_stastate(ParseState *ps) {
724 const char *const *new_stastate;
726 new_stastate= some_needword_lookup(ps, stastate_names, "stastate");
727 stastate= new_stastate ? new_stastate - stastate_names : 0;
730 state[s].flags.resolution_problem= 0;
732 if (stastate <= Sta_Resolving) {
734 state[s].flags.det= 0;
735 state[s].flags.trainown= 0;
742 static void mx_resolution_problem(int s) {
743 state[s].flags.resolution_problem= 1;
746 static void si_resolution_inexplicable(ParseState *ps) {
748 s= ps_needsegment(ps); if (s<0) return;
749 mx_resolution_problem(s);
751 static void si_resolution_mispositioned(ParseState *ps) {
753 r= ps_needword(ps); /* head|tail */ if (r) return;
754 r= ps_needword(ps); /* <train> */ if (r) return;
755 s= ps_needsegment(ps); if (s<0) return;
756 mx_resolution_problem(s);
759 static void si_connected(ParseState *ps) {
760 const MuxEventInfo *mxi;
764 sockprintf("select-replay");
765 for (mxi=muxeventinfos; mxi->prefix; mxi++) {
769 for (p=mxi->prefix; (c=*p); p++) {
775 sockprintf("%s",mxi->remainpat);
777 sockprintf(" ~|*\n");
779 /* set the fixed moveable features */
780 const SegmentInfo *segi;
781 const MovFeatInfo *mfi;
782 const PlanSegmentData *planseg;
783 const PlanSegmovfeatData *planfeat;
786 for (segn=0; segn<info_nsegments; segn++) {
787 segi= &info_segments[segn];
788 if (!segi->n_fixedmovfeats) continue;
789 for (s=0; s<NSEGMENTS; s++)
790 if (!strcmp(segi->pname, (planseg=&ui_plan_data.segments[s])->segname))
792 die("layout data segment %s not found\n",segi->pname);
794 for (mfn=0, mfi= segi->movfeats + segi->n_movfeats;
795 mfn < segi->n_fixedmovfeats;
797 for (f=1; f<planseg->n_movfeats; f++)
798 if (!strcmp(mfi->pname, (planfeat=&planseg->movfeats[f])->movfeatname))
800 die("layout data movfeat %s/%s not found\n",segi->pname,mfi->pname);
802 state[s].mfs[f].posn= mfi->posns;
803 if (debug) fprintf(debug,"fixed %s/%s=%d\n",
804 segi->pname,mfi->pname,mfi->posns);
809 static void si_fatal(ParseState *ps) {
810 die("multiplexer reports problem: %.*s\n",
811 (int)badcmdreport_recsz, badcmdreport_data);
813 static void si_ack(ParseState *ps) {
814 ps_needword(ps); /* command */
815 ps_needword(ps); /* status */
816 if (thiswordstrcmp(ps,"ok")) si_fatal(0);
819 static const MuxEventInfo muxeventinfos[]= {
820 { "?detect", "", si_detect },
821 { "?picio out polarity", "", si_polarity },
822 { "?movpos", "_*_position", si_movpos },
823 { "?picio out on", "", si_on },
824 { "?picio out off", "", si_off },
825 { "?train", "_*_has", si_train },
827 { "?stastate", "", si_stastate },
829 { "?resolution inexplicable", "", si_resolution_inexplicable },
830 { "?resolution mispositioned", "", si_resolution_mispositioned },
832 { "=connected", "", si_connected },
833 { "=permission", "", 0 },
835 { "+executing", 0, 0 },
836 { "+ack", 0, si_ack },
837 { "+nak", 0, si_fatal },
838 { "=failed", 0, si_fatal },
839 { "=denied", 0, si_fatal },
843 static void sock_input_line(ParseState *ps) {
844 const MuxEventInfo *mxi;
845 const char *got, *expected;
847 if (!ps->remain || !ps->remain[0])
849 ps->thisword= ps->remain;
850 for (mxi=muxeventinfos; mxi->prefix; mxi++) {
852 expected= mxi->prefix;
853 l= ps->lthisword= strlen(expected);
854 if (*expected=='?') { got++; expected++; l--; }
855 if (memcmp(got, expected, l)) continue;
856 if (!got[l] || got[l]==' ') goto found;
860 if (!mxi->fn) return;
862 if ((c= *ps->remain)) { assert(c==' '); ps->remain++; }
863 if (debug) fprintf(debug,"calling <%s> with <%.*s|%s>\n",
864 mxi->prefix, ps->lthisword,ps->thisword, ps->remain);
868 static const InputStream sock_is= {
869 "multiplexer connection",
875 /*---------- main program including much of the initialisation ----------*/
877 int main(int argc, const char *const *argv) {
880 XpmAttributes mattribs;
881 XWindowAttributes wattribs;
882 int segment_ix, movfeat_ix, posn, invert, det, oor, infd;
887 const PlanSegmentData *segment_d;
888 const PlanSegmovfeatData *movfeat_d;
891 sys_events= oop_sys_new(); if (!sys_events) diee("oop_sys_new");
892 events= oop_sys_source(sys_events); assert(events);
894 while ((arg= *++argv)) {
895 if (!strcmp(arg,"--sizes")) {
896 printf("%d\n%d\n", ui_plan_data.xsz, ui_plan_data.ysz);
897 if (ferror(stdout) || fflush(stdout)) diee("print stdout");
899 } else if (!strcmp(arg,"--debug")) {
901 } else if (arg[0]=='@') {
905 comma= strchr(node,',');
910 service= STR(TRAINMX_PORT);
912 sock.fd= sock_clientconnect(node,service);
913 if (sock.fd<0) die("unable to connect to multiplexer");
915 if (comma) *comma= ',';
916 } else if (arg[0]=='-') {
917 die("invalid option(s)");
919 errno=0; wspec= strtoul(arg,&ep,0);
920 if (errno || ep==arg || *ep || wspec==None) die("bad windowid");
924 disp= XOpenDisplay(0); if (!disp) die("XOpenDisplay failed");
927 win= XCreateSimpleWindow(disp, DefaultRootWindow(disp),
928 0,0, ui_plan_data.xsz, ui_plan_data.ysz,
930 if (win == None) diex("XCreateSimpleWindow", "initial");
935 XCALL( XGetWindowAttributes, 0, (disp,win,&wattribs) );
937 XPMCALL( XpmCreatePixmapFromData, "background",
938 (disp,win, (char**)ui_plan_data.background, &bg_pixmap,0,0) );
940 XCALL( XSetWindowBackgroundPixmap, 0, (disp,win,bg_pixmap) );
942 XCALL( XAllocNamedColor, "white",
943 (disp, wattribs.colormap, "#ffffff",
945 train_pixel= colour.pixel;
947 XCALL( XAllocNamedColor, "owned",
948 (disp, wattribs.colormap, "#a0a0a0",
950 owned_pixel= colour.pixel;
952 state= mmalloc(sizeof(*state) * NSEGMENTS);
953 for (segment_ix= 0, segment_d= ui_plan_data.segments;
954 segment_ix < ui_plan_data.n_segments;
955 segment_ix++, segment_d++) {
956 state[segment_ix].flags.on= 0;
957 state[segment_ix].flags.inv= 0;
958 state[segment_ix].flags.det= 0;
959 state[segment_ix].flags.trainown= 0;
960 state[segment_ix].flags.updated_tmp= 0;
961 state[segment_ix].owner= 0;
962 state[segment_ix].mfs= fs=
963 mmalloc(sizeof(*state[segment_ix].mfs) * segment_d->n_movfeats);
964 for (movfeat_ix= 0, movfeat_d= segment_d->movfeats;
965 movfeat_ix < segment_d->n_movfeats;
966 movfeat_ix++, movfeat_d++, fs++) {
967 fs->next= states_head; states_head= fs;
968 fs->flags= state[segment_ix].flags;
969 fs->posn= movfeat_d->n_posns;
970 if (fs->posn==1) fs->posn= 0;
971 fs->redraw_needed= 0;
973 loadmask(&fs->whole, &movfeat_d->mask, &gcv, 0);
975 fs->posns= mmalloc(sizeof(*fs->posns)*(fs->posn+1));
976 for (posn= 0; posn <= fs->posn; posn++)
977 for (invert=0; invert<2; invert++)
978 for (det=0; det<2; det++) {
979 PosnState *ps= &fs->posns[posn][invert][det];
980 const PlanPixmapOnData *ppod=
981 posn < movfeat_d->n_posns
982 ? &movfeat_d->posns[posn] : 0;
983 const PlanPixmapDataRef *ppdr= ppod
984 ? &ppod->on[invert][det]
985 : &movfeat_d->unknown[invert][det];
988 mattribs.valuemask= 0;
989 XPMCALL( XpmCreatePixmapFromData, "main",
994 ps->width= mattribs.width;
995 ps->height= mattribs.height;
997 loadmask(&ps->edge, &ppod->pedge, &gcv, 0);
1008 instream= &stdin_is;
1014 events->on_fd(events, infd, OOP_EXCEPTION, some_exception,
1015 (void*)instream->name);
1017 rd= oop_rd_new_fd(events, infd, 0,0);
1018 if (!rd) diee("oop_rd_new_fd");
1020 oor= oop_rd_read(rd, OOP_RD_STYLE_GETLINE, 1024,
1021 input_ifok,0, input_iferr,0);
1022 if (oor) diee("oop_rd_read");
1024 int fd= ConnectionNumber(disp);
1025 events->on_fd(events, fd, OOP_READ, xlib_readable, 0);
1026 events->on_fd(events, fd, OOP_EXCEPTION, some_exception,
1027 (void*)"xserver connection");
1029 XCALL( XSelectInput, 0, (disp,win, ExposureMask) );
1032 XCALL( XClearArea, "initial", (disp,win, 0,0,0,0, True) );
1034 XCALL( XMapWindow, 0, (disp,win) );
1039 oop_sys_run(sys_events);