#include #include #include #include extern const char *__progname; #include #include #include #include #include #include "builtins.h" #include "blocktype.h" typedef enum { PIN_INPUT = 1, PIN_OUTPUT, } PINTYPE; typedef struct iopin IOPIN; typedef struct block BLOCK; typedef struct signal SIGNAL; typedef struct menu MENU; typedef struct menuitem MENUITEM; struct menu { int nitems; MENUITEM *items; int width; int height; Window win; MENU *link; unsigned int flags; #define MF_MAPPED 0x00000001 } ; #define MENU_INIT(name) {\ sizeof(menu_##name##_items) / sizeof(menu_##name##_items[0]), \ &menu_##name##_items[0] } struct menuitem { const char *text; int key; void (*impl)(int); int arg; int y; } ; struct iopin { BLOCK *block; PINTYPE pintype; int inx; } ; struct block { BLOCKTYPE *type; SIGNAL **inputs; SIGNAL **outputs; double *params; int x; int y; } ; struct signal { IOPIN *drive; int n_driven; IOPIN **driven; } ; static XrmDatabase db; static const char *defaults = "\ *Foreground: white\n\ *Background: black\n\ *BorderColour: white\n\ *Drop.OKColour: green\n\ *Drop.BadColour: red\n\ *BorderWidth: 1\n\ *Font: fixed\n\ "; static char *displayname; static char *geometryspec; static char *fontname; static char *foreground; static char *background; static char *bordercstr; static char *dropokcstr; static char *dropbadcstr; static char *borderwstr; static char *bordermstr; static char *visualstr; static int synch; static int argc; static char **argv; Display *disp; static Screen *scr; static int scrwidth; static int scrheight; static int depth; static Window rootwin; static Colormap wincmap; static int defcmap; static XVisualInfo visinfo; XFontStruct *font; static int def_font; static XColor fgcolour; static XColor bgcolour; static XColor bdcolour; static XColor dragcolour_r; static XColor dragcolour_g; static int margin; static int borderwidth; static Window topwin; static Window drawwin; static Window menuwin; static Window dragwin; static GC wingc; static GC gc_fg; static GC gc_bg; static GC gc_1bpp_0; static GC gc_1bpp_1; static GC gc_drag; int font_space; int font_endspace; int font_baseline; int font_baselineskip; static int winx; static int winy; static int winw; static int winh; static Cursor nilcurs; static XTextProperty wn_prop; static XTextProperty in_prop; static XSizeHints *normal_hints; static XWMHints *wm_hints; static XClassHint *class_hints; static int (*old_ioerr)(Display *); static int (*old_err)(Display *, XErrorEvent *); static int n_blocktypes; static BLOCKTYPE **blocktypes; static MENU *allmenus; static int menu_maxwidth; static int menu_maxheight; static MENU *curmenu; static void (*block_menu_choice)(int); static char **block_menu_texts; static void (*cancel_it)(void); static int dragging; static int drag_w; static int drag_h; static int drag_xoff; static int drag_yoff; static int drag_curok; static Pixmap drag_pm; static int (*drag_drop)(int, int, int); // forwards static MENU menu_main; static MENU menu_block; static MENU menu_cancel; static char *deconst(const char *s) { char *rv; bcopy(&s,&rv,sizeof(rv)); return(rv); } static void panic(void) { (void)*(volatile char *)0; abort(); } static void saveargv(int ac, char **av) { int i; int nc; char *abuf; argc = ac; argv = (char **) malloc((ac+1)*sizeof(char *)); nc = 1; for (i=0;i 0) { skip --; continue; } if (**av != '-') { fprintf(stderr,"%s: unrecognized argument `%s'\n",__progname,*av); errs ++; continue; } if (0) { needarg:; fprintf(stderr,"%s: %s needs a following argument\n",__progname,*av); errs ++; continue; } #define WANTARG() do { if (++skip >= ac) goto needarg; } while (0) if (!strcmp(*av,"-display")) { WANTARG(); displayname = av[skip]; continue; } if (!strcmp(*av,"-geometry")) { WANTARG(); geometryspec = av[skip]; continue; } if (!strcmp(*av,"-font") || !strcmp(*av,"-fn")) { WANTARG(); fontname = av[skip]; continue; } if (!strcmp(*av,"-foreground") || !strcmp(*av,"-fg")) { WANTARG(); foreground = av[skip]; continue; } if (!strcmp(*av,"-background") || !strcmp(*av,"-bg")) { WANTARG(); background = av[skip]; continue; } if (!strcmp(*av,"-bordercolor") || !strcmp(*av,"-bd")) { WANTARG(); bordercstr = av[skip]; continue; } if (!strcmp(*av,"-borderwidth") || !strcmp(*av,"-bw")) { WANTARG(); borderwstr = av[skip]; continue; } if (!strcmp(*av,"-bordermargin") || !strcmp(*av,"-bm")) { WANTARG(); bordermstr = av[skip]; continue; } if (!strcmp(*av,"-visual")) { WANTARG(); visualstr = av[skip]; continue; } if (!strcmp(*av,"-sync")) { synch = 1; continue; } #undef WANTARG fprintf(stderr,"%s: unrecognized option `%s'\n",__progname,*av); errs ++; } if (errs) exit(1); } static void setup_blocktype(BLOCKTYPE *bt) { n_blocktypes ++; blocktypes = realloc(blocktypes,n_blocktypes*sizeof(*blocktypes)); blocktypes[n_blocktypes-1] = bt; bt->inx = n_blocktypes - 1; } static void setup_blocktypes(void) { n_blocktypes = 0; blocktypes = 0; setup_blocktype(&block_constant); setup_blocktype(&block_amp); setup_blocktype(&block_sum); setup_blocktype(&block_prod); setup_blocktype(&block_cmp); setup_blocktype(&block_noise); setup_blocktype(&block_osc); setup_blocktype(&block_vco); setup_blocktype(&block_ddcosc); setup_blocktype(&block_genosc); setup_blocktype(&block_envelope); setup_blocktype(&block_output); // Poisson envelope // Key } static int find_best_visual(XVisualInfo *vv, int n) { int best; int i; XVisualInfo *v; best = -1; for (i=n-1;i>=0;i--) { v = vv + i; switch (v->class) { case PseudoColor: case DirectColor: break; default: continue; break; } if ( (best < 0) || (vv[i].depth > vv[best].depth) || ( (vv[i].depth == vv[best].depth) && (vv[i].visual == XDefaultVisual(disp,vv[i].screen)) ) ) { best = i; } } if (best < 0) return(0); visinfo = vv[best]; return(1); } static void setup_visual(void) { XVisualInfo *xvi; int nvi; XVisualInfo template; int class; const char *classname; if (! visualstr) { template.screen = XScreenNumberOfScreen(scr); xvi = XGetVisualInfo(disp,VisualScreenMask,&template,&nvi); if (xvi == 0) { fprintf(stderr,"%s: no visuals found?!\n",__progname); exit(1); } if (nvi == 0) { fprintf(stderr,"%s: what? XGetVisualInfo worked but found no visuals?\n",__progname); exit(1); } if (find_best_visual(xvi,nvi)) return; fprintf(stderr,"%s: no usable visual found on this screen\n",__progname); exit(1); } else { #define FOO(c) if (!strcasecmp(visualstr,#c)) { class = c; classname = #c; } else FOO(StaticGray) FOO(StaticColor) FOO(TrueColor) FOO(GrayScale) FOO(PseudoColor) FOO(DirectColor) #undef FOO { unsigned long int id; char *cp; id = strtol(visualstr,&cp,0); if (*cp) { fprintf(stderr,"%s: %s: invalid visual option\n",__progname,visualstr); exit(1); } template.visualid = (VisualID) id; xvi = XGetVisualInfo(disp,VisualIDMask,&template,&nvi); if (xvi == 0) { fprintf(stderr,"%s: no such visual found\n",__progname); exit(1); } if (nvi == 0) { fprintf(stderr,"%s: what? XGetVisualInfo returned non-nil but zero count?\n",__progname); exit(1); } if (xvi->screen != XScreenNumberOfScreen(scr)) { fprintf(stderr,"%s: visual %s is on a different screen\n",__progname,visualstr); exit(1); } if (find_best_visual(xvi,nvi)) return; fprintf(stderr,"%s: visual %s isn't usable (need DirectColor or PseudoColor)\n",__progname,visualstr); exit(1); } switch (class) { case DirectColor: case PseudoColor: break; default: fprintf(stderr,"%s: can't work with %s visuals\n",__progname,classname); exit(1); break; } template.class = class; template.screen = XScreenNumberOfScreen(scr); xvi = XGetVisualInfo(disp,VisualClassMask|VisualScreenMask,&template,&nvi); if (xvi == 0) { fprintf(stderr,"%s: no %s visual found on this screen\n",__progname,classname); exit(1); } if (nvi == 0) { fprintf(stderr,"%s: what? XGetVisualInfo returned non-nil but zero count?\n",__progname); exit(1); } if (find_best_visual(xvi,nvi)) return; fprintf(stderr,"%s: no usable %s visual found on this screen\n",__progname,classname); exit(1); } } static void setup_db(void) { char *str; char *home; char hostname[256]; XrmDatabase db2; db = XrmGetStringDatabase(defaults); str = XResourceManagerString(disp); if (str) { db2 = XrmGetStringDatabase(str); XrmMergeDatabases(db2,&db); } home = getenv("HOME"); if (home) { str = malloc(strlen(home)+1+10+1); sprintf(str,"%s/.Xdefaults",home); db2 = XrmGetFileDatabase(str); if (db2) { XrmMergeDatabases(db2,&db); } free(str); gethostname(&hostname[0],(sizeof(hostname)/sizeof(hostname[0]))-1); hostname[(sizeof(hostname)/sizeof(hostname[0]))-1] = '\0'; str = malloc(strlen(home)+1+11+strlen(&hostname[0])+1); sprintf(str,"%s/.Xdefaults-%s",home,&hostname[0]); db2 = XrmGetFileDatabase(str); if (db2) { XrmMergeDatabases(db2,&db); } free(str); } } static void maybeset(char **strp, char *str) { if (str && !*strp) *strp = str; } static char *get_default_value(const char *name, const char *class) { char *type; XrmValue value; if (XrmGetResource(db,name,class,&type,&value) == False) return(0); return(value.addr); } static void setup_cmap(void) { if (visinfo.visual == XDefaultVisualOfScreen(scr)) { wincmap = XDefaultColormapOfScreen(scr); defcmap = 1; } else { wincmap = XCreateColormap(disp,rootwin,visinfo.visual,AllocNone); defcmap = 0; } } static void setup_colour(XColor *col, unsigned long int pix, char *str, int load) { if (XParseColor(disp,wincmap,str,col) == 0) { fprintf(stderr,"%s: bad colour `%s'\n",__progname,str); exit(1); } col->pixel = pix; col->flags = DoRed | DoGreen | DoBlue; if (load) XStoreColor(disp,wincmap,col); } static void setup_colours(void) { unsigned long int pixels[4]; XAllocColorCells(disp,wincmap,False,0,0,&pixels[0],4); setup_colour(&fgcolour,pixels[0],foreground,1); setup_colour(&bgcolour,pixels[1],background,1); setup_colour(&bdcolour,pixels[2],bordercstr,1); setup_colour(&dragcolour_r,pixels[3],dropbadcstr,0); setup_colour(&dragcolour_g,pixels[3],dropokcstr,0); } static void setup_numbers(void) { if (bordermstr) margin = atoi(bordermstr); if (borderwstr) borderwidth = atoi(borderwstr); } static void setup_font(void) { unsigned long int fontprop; font = XLoadQueryFont(disp,fontname); if (font == 0) { font = XQueryFont(disp,XGContextFromGC(wingc)); if (font == 0) { fprintf(stderr,"%s: can't query the server default font, sorry\n",__progname); exit(1); } fprintf(stderr,"%s: can't load font %s, using server default\n",__progname,fontname); def_font = 1; } else { def_font = 0; } if (XGetFontProperty(font,XA_NORM_SPACE,&fontprop)) { font_space = fontprop; } else { font_space = XTextWidth(font,"0",1); } if (XGetFontProperty(font,XA_END_SPACE,&fontprop)) { font_endspace = fontprop; } else { font_endspace = 1.5 * font_space; } font_baseline = font->ascent; font_baselineskip = font->ascent + font->descent; } static void create_menu_windows(void) { MENU *m; unsigned long int attrmask; XSetWindowAttributes attr; for (m=allmenus;m;m=m->link) { attrmask = 0; attr.background_pixel = bgcolour.pixel; attrmask |= CWBackPixel; attr.backing_store = NotUseful; attrmask |= CWBackingStore; attr.event_mask = ExposureMask; attrmask |= CWEventMask; m->win = XCreateWindow(disp,menuwin,0,0,menu_maxwidth,menu_maxheight,0,depth,InputOutput,visinfo.visual,attrmask,&attr); } } static void setup_windows(void) { int x; int y; int w; int h; int bits; unsigned long int attrmask; XSetWindowAttributes attr; unsigned long int gcvalmask; XGCValues gcval; w = (scrwidth * 2) / 3; h = (scrheight * 2) / 3; x = (scrwidth - w) / 2; y = (scrheight - h) / 2; bits = XParseGeometry(geometryspec,&x,&y,&w,&h); if (bits & XNegative) x = scrwidth + x - w; if (bits & YNegative) y = scrheight + y - h; attrmask = 0; attr.background_pixel = bgcolour.pixel; attrmask |= CWBackPixel; attr.border_pixel = bdcolour.pixel; attrmask |= CWBorderPixel; attr.backing_store = NotUseful; attrmask |= CWBackingStore; attr.event_mask = KeyPressMask | ButtonPressMask | ButtonReleaseMask | PointerMotionMask | PointerMotionHintMask | StructureNotifyMask; attrmask |= CWEventMask; attr.colormap = wincmap; attrmask |= CWColormap; winx = x; winy = y; winw = w; winh = h; w -= 2 * borderwidth; h -= 2 * borderwidth; topwin = XCreateWindow(disp,rootwin,x,y,w,h,borderwidth,depth,InputOutput,visinfo.visual,attrmask,&attr); wn_prop.value = (unsigned char *) deconst("synth"); wn_prop.encoding = XA_STRING; wn_prop.format = 8; wn_prop.nitems = strlen(wn_prop.value); in_prop.value = (unsigned char *) deconst("synth"); in_prop.encoding = XA_STRING; in_prop.format = 8; in_prop.nitems = strlen(in_prop.value); normal_hints = XAllocSizeHints(); normal_hints->flags = PMinSize | PResizeInc; normal_hints->x = x; normal_hints->y = y; normal_hints->flags |= (bits & (XValue|YValue)) ? USPosition : PPosition; normal_hints->width = w; normal_hints->height = h; normal_hints->flags |= (bits & (WidthValue|HeightValue)) ? USSize : PSize; normal_hints->min_width = w; normal_hints->min_height = h; normal_hints->width_inc = 1; normal_hints->height_inc = 1; wm_hints = XAllocWMHints(); wm_hints->flags = InputHint; wm_hints->input = False; class_hints = XAllocClassHint(); class_hints->res_name = deconst("synth"); class_hints->res_class = deconst("Sound"); XSetWMProperties(disp,topwin,&wn_prop,&in_prop,argv,argc,normal_hints,wm_hints,class_hints); gcvalmask = 0; if (! def_font) { gcval.font = font->fid; gcvalmask |= GCFont; } gcval.foreground = fgcolour.pixel; gcvalmask |= GCForeground; gcval.background = bgcolour.pixel; gcvalmask |= GCBackground; wingc = XCreateGC(disp,topwin,gcvalmask,&gcval); attrmask = 0; attr.background_pixel = bgcolour.pixel; attrmask |= CWBackPixel; attr.backing_store = NotUseful; attrmask |= CWBackingStore; attr.event_mask = ExposureMask; attrmask |= CWEventMask; drawwin = XCreateWindow(disp,topwin,0,0,32767,32767,0,depth,InputOutput,visinfo.visual,attrmask,&attr); XMapWindow(disp,drawwin); attrmask = 0; attr.background_pixel = bgcolour.pixel; attrmask |= CWBackPixel; attr.backing_store = NotUseful; attrmask |= CWBackingStore; attr.event_mask = ExposureMask; attrmask |= CWEventMask; menuwin = XCreateWindow(disp,topwin,-1,-1,menu_maxwidth+2,menu_maxheight+2,1,depth,InputOutput,visinfo.visual,attrmask,&attr); XMapWindow(disp,menuwin); create_menu_windows(); attrmask = 0; attr.background_pixel = bgcolour.pixel; attrmask |= CWBackPixel; attr.backing_store = NotUseful; attrmask |= CWBackingStore; dragwin = XCreateWindow(disp,drawwin,0,0,1,1,0,depth,InputOutput,visinfo.visual,attrmask,&attr); XMapRaised(disp,topwin); printf("topwin %lx\n",(unsigned long int)topwin); printf("drawwin %lx\n",(unsigned long int)drawwin); printf("menuwin %lx\n",(unsigned long int)menuwin); printf("dragwin %lx\n",(unsigned long int)dragwin); } static GC setup_gc(Drawable d, unsigned long int pix) { unsigned long int gcvalmask; XGCValues gcval; gcvalmask = 0; if (! def_font) { gcval.font = font->fid; gcvalmask |= GCFont; } gcval.foreground = pix; gcvalmask |= GCForeground; return(XCreateGC(disp,d,gcvalmask,&gcval)); } static void setup_gcs(void) { Pixmap pm; gc_fg = setup_gc(topwin,fgcolour.pixel); gc_bg = setup_gc(topwin,bgcolour.pixel); gc_drag = setup_gc(topwin,dragcolour_r.pixel); pm = XCreatePixmap(disp,topwin,1,1,1); gc_1bpp_0 = setup_gc(pm,0); gc_1bpp_1 = setup_gc(pm,1); XFreePixmap(disp,pm); } static void setup_cursors(void) { Pixmap pm; pm = XCreatePixmap(disp,topwin,1,1,1); XDrawPoint(disp,pm,gc_1bpp_0,0,0); nilcurs = XCreatePixmapCursor(disp,pm,pm,&fgcolour,&bgcolour,0,0); XFreePixmap(disp,pm); XDefineCursor(disp,dragwin,nilcurs); } static int ioerror_handler(Display *d) { return((*old_ioerr)(d)); } static int error_handler(Display *d, XErrorEvent *e) { return((*old_err)(d,e)); } static void setup_error(void) { old_err = XSetErrorHandler(error_handler); old_ioerr = XSetIOErrorHandler(ioerror_handler); } static void redraw_menu(MENU *m) { int inx; MENUITEM *i; for (inx=m->nitems-1;inx>=0;inx--) { i = &m->items[inx]; XDrawString(disp,m->win,gc_fg,0,i->y,i->text,strlen(i->text)); } } static void handle_expose(XExposeEvent *e) { MENU *m; for (m=allmenus;m;m=m->link) { if (e->window == m->win) { if (e->count == 0) redraw_menu(m); return; } } } static void keystroke(unsigned char k) { int i; for (i=curmenu->nitems-1;i>=0;i--) { if (curmenu->items[i].key == k) { (*curmenu->items[i].impl)(curmenu->items[i].arg); return; } } XBell(disp,0); } static void handle_key(XKeyEvent *e, int downp) { char str[64]; int sl; if (! downp) return; sl = XLookupString(e,&str[0],sizeof(str),0,0); if (sl < 1) return; keystroke(str[0]); } static void drag_to(int x, int y) { int ok; XMoveWindow(disp,dragwin,x-drag_xoff,y-drag_yoff); ok = (*drag_drop)(x,y,0); if (ok != drag_curok) { XStoreColor(disp,wincmap,ok?&dragcolour_g:&dragcolour_r); drag_curok = ok; } } static void drag_query(void) { Window ptr_root; Window ptr_child; int ptr_rootx; int ptr_rooty; int ptr_winx; int ptr_winy; unsigned int ptr_mask; switch (XQueryPointer(disp,topwin,&ptr_root,&ptr_child,&ptr_rootx,&ptr_rooty,&ptr_winx,&ptr_winy,&ptr_mask)) { case False: // Left the screen! Do nothing. return; break; case True: break; default: fprintf(stderr,"XQueryPointer returned neither True nor False\n"); exit(1); break; } if (! dragging) return; drag_to(ptr_winx,ptr_winy); } /* * There is a problem here. * * If we get a hint event, we want to ignore all non-hint events * between the hint event and the response carrying the XQueryPointer * response data. The trouble is, Xlib gives us no way to do this. * Not even the X*IfEvent functions help, because a single read() * could return (a) events before the XQueryPointer response, (b) that * response, and (c) events after it, all in the same blob, with no * API that lets us tell the difference between (a) and (c) (and, * indeed, once the response is consumed there may be no difference * left). * * Thus, this is unfixable (well, short of reimplementing Xlib). So, * we ignore the issue and assume that it's "good enough" to just call * XQueryPointer in response to a hint event and ignore the * possibility of non-hint events between the hint event and the * XQueryPointer response. */ static void handle_motion(XMotionEvent *e) { if (e->window != topwin) return; if (e->is_hint) { drag_query(); } else { if (! dragging) return; drag_to(e->x,e->y); } } static void handle_event(XEvent *e) { switch (e->type) { default: break; case Expose: /* XExposeEvent - xexpose */ handle_expose(&e->xexpose); break; case KeyPress: /* XKeyPressedEvent - XKeyEvent - xkey */ handle_key(&e->xkey,1); break; case KeyRelease: /* XKeyReleasedEvent - XKeyEvent - xkey */ handle_key(&e->xkey,0); break; case MotionNotify: /* XPointerMovedEvent - XMotionEvent - xmotion */ handle_motion(&e->xmotion); break; #if 0 case ConfigureNotify: /* XConfigureEvent - xconfigure */ winw = e->xconfigure.width + (2 * e->xconfigure.border_width); winh = e->xconfigure.height + (2 * e->xconfigure.border_width); redisplay(); break; case GraphicsExpose: /* XGraphicsExposeEvent - xgraphicsexpose */ if (e->xexpose.count == 0) { redisplay(); } break; case VisibilityNotify: /* XVisibilityEvent - xvisibility */ if (e->xvisibility.state != VisibilityUnobscured) { obscured(); } break; case DestroyNotify: /* XDestroyWindowEvent - xdestroywindow */ exit(0); break; #endif } } static void run(void) { XEvent e; while (1) { XNextEvent(disp,&e); handle_event(&e); } } static void set_curmenu(MENU *m) { if (! (m->flags & MF_MAPPED)) { XMapWindow(disp,m->win); m->flags |= MF_MAPPED; } XRaiseWindow(disp,m->win); curmenu = m; } static void menu_blank_item(MENUITEM *i) { i->text = ""; i->key = -1; i->impl = 0; } static void block_menu_impl(int inx) { (*block_menu_choice)(inx); } static void block_menu_cancel(int inx __attribute__((__unused__))) { (*block_menu_choice)(-1); } static void create_block_menu(void) { int inx; MENUITEM *i; char *txt; menu_block.nitems = n_blocktypes + 2; menu_block.items = malloc(menu_block.nitems*sizeof(*menu_block.items)); block_menu_texts = malloc(n_blocktypes*sizeof(*block_menu_texts)); for (inx=0;inxkey = 'a' + inx; asprintf(&txt," %c %s ",i->key,blocktypes[inx]->name); block_menu_texts[inx] = txt; i->text = txt; i->impl = &block_menu_impl; i->arg = inx; } menu_blank_item(&menu_block.items[n_blocktypes]); i = &menu_block.items[n_blocktypes+1]; i->text = " ESC cancel "; i->key = '\e'; i->impl = &block_menu_cancel; } static void recreate_block_menu(void) { int inx; for (inx=menu_block.nitems-3;inx>=0;inx--) free(block_menu_texts[inx]); free(menu_block.items); free(block_menu_texts); create_block_menu(); } static void menu_impl_main_Q(int arg __attribute__((__unused__))) { exit(0); } static void pick_block_type(void (*chosen)(int)) { block_menu_choice = chosen; set_curmenu(&menu_block); } static void n_block_drag_cancel(void) { // XXX XXX XXX } static void init_drag(void) { dragging = 0; drag_w = -1; drag_h = -1; drag_pm = None; } static void start_dragging(int w, int h, void (*render)(Drawable, GC, GC), int (*drop)(int, int, int)) { if (dragging) panic(); if ((w != drag_w) || (h != drag_h)) { if (drag_pm != None) XFreePixmap(disp,drag_pm); drag_w = w; drag_h = h; drag_pm = XCreatePixmap(disp,rootwin,w,h,depth); XResizeWindow(disp,dragwin,w,h); } (*render)((Drawable)drag_pm,gc_bg,gc_drag); XSetWindowBackgroundPixmap(disp,dragwin,drag_pm); XClearWindow(disp,dragwin); XMapWindow(disp,dragwin); drag_xoff = w / 2; drag_yoff = h / 2; drag_drop = drop; drag_curok = -1; dragging = 1; drag_query(); } static int n_block_drop(int x, int y, int doit) { (void)x; (void)y; (void)doit; return(x>512); // XXX XXX XXX;;; } static void n_block_type(int choice) { BLOCKDIMS sz; printf("n_block_type: choice = %d\n",choice); if ((choice < 0) || (choice >= n_blocktypes)) { XBell(disp,0); set_curmenu(&menu_main); return; } printf("creating block type %d (%s)\n",choice,blocktypes[choice]->name); sz = (*blocktypes[choice]->size)(); set_curmenu(&menu_cancel); cancel_it = &n_block_drag_cancel; start_dragging(sz.w,sz.h,blocktypes[choice]->render,&n_block_drop); } static void menu_impl_main_n(int arg __attribute__((__unused__))) { if (menu_block.nitems != n_blocktypes+2) recreate_block_menu(); pick_block_type(&n_block_type); } static MENUITEM menu_main_items[] = { { " Q quit ", 'Q', &menu_impl_main_Q }, { " n new block ", 'n', &menu_impl_main_n } }; static MENU menu_main = MENU_INIT(main); static MENU menu_block; static void menu_impl_cancel(int arg __attribute__((__unused__))) { (*cancel_it)(); } static MENUITEM menu_cancel_items[] = { { " ESC cancel ", '\e', &menu_impl_cancel } }; static MENU menu_cancel = MENU_INIT(cancel); static void setup_menu(MENU *m) { int ix; MENUITEM *i; int y; int xte_dir; int xte_asc; int xte_desc; XCharStruct cs; int w; w = 0; y = font_baseline; for (ix=0;ixnitems;ix++) { i = &m->items[ix]; i->y = y; XTextExtents(font,i->text,strlen(i->text),&xte_dir,&xte_asc,&xte_desc,&cs); if (cs.width > w) w = cs.width; y += font_baselineskip; } m->width = w; if (w > menu_maxwidth) menu_maxwidth = w; m->height = m->nitems * font_baselineskip; if (m->height > menu_maxheight) menu_maxheight = m->height; m->flags = 0; m->link = allmenus; allmenus = m; } static void setup_menus(void) { create_block_menu(); menu_maxwidth = 0; menu_maxheight = 0; allmenus = 0; setup_menu(&menu_main); setup_menu(&menu_block); setup_menu(&menu_cancel); } static void init_menu(void) { set_curmenu(&menu_main); } int main(int, char **); int main(int ac, char **av) { saveargv(ac,av); handleargs(ac,av); setup_blocktypes(); setup_error(); disp = XOpenDisplay(displayname); if (disp == 0) { fprintf(stderr,"%s: can't open display\n",__progname); exit(1); } if (synch) XSynchronize(disp,True); scr = XDefaultScreenOfDisplay(disp); setup_visual(); scrwidth = XWidthOfScreen(scr); scrheight = XHeightOfScreen(scr); depth = visinfo.depth; rootwin = XRootWindowOfScreen(scr); setup_db(); maybeset(&geometryspec,get_default_value("synth.geometry","Sound.Geometry")); maybeset(&fontname,get_default_value("synth.font","Sound.Font")); maybeset(&foreground,get_default_value("synth.foreground","Sound.Foreground")); maybeset(&background,get_default_value("synth.background","Sound.Background")); maybeset(&bordercstr,get_default_value("synth.borderColour","Sound.BorderColour")); maybeset(&dropokcstr,get_default_value("synth.drop.okColour","Sound.Drop.OKColour")); maybeset(&dropbadcstr,get_default_value("synth.drop.badColour","Sound.Drop.BadColour")); maybeset(&borderwstr,get_default_value("synth.borderWidth","Sound.BorderWidth")); maybeset(&bordermstr,get_default_value("synth.borderMargin","Sound.BorderMargin")); setup_cmap(); setup_colours(); setup_numbers(); setup_font(); setup_menus(); setup_windows(); setup_gcs(); setup_cursors(); init_menu(); init_drag(); run(); return(0); }