/* * Multi-mterm front end. * * Manages multiple mterms in a single window-manager window. * * The effect is rather like window(1), only the interface is natively * X instead of termcap-based. * * We set up a container window and manage multiple mterm instances * within it. Each mterm instance is run with -blanket and * -keystroke-fd, -blanket to make it fit a window we manage within * the container window and -keystroke-fd so we can get keystrokes to * it properly. */ #include #include #include #include #include extern const char *__progname; static const char *displayarg = 0; static const char *fontarg = 0; static const char *geometryarg = 0; static const char *fgarg = "white"; static const char *bgarg = "black"; static const char *bcarg = "white"; static const char *bwarg = "1"; static const char *bmarg = "1"; typedef struct callonce CALLONCE; typedef struct geom GEOM; typedef struct col COL; typedef struct em EM; struct em { EM *flink; EM *blink; int x; int y; int w; int h; LX_XID win; LX_XID kswin; pid_t kid; int ksfd; AIO_OQ ksoq; } ; struct col { const char *str; LX_RGB rgb; unsigned int pix; int good; } ; struct geom { unsigned int x; unsigned int y; int w; int h; unsigned int flags; #define GF_POS 0x00000001 #define GF_X_NEG 0x00000002 #define GF_Y_NEG 0x00000004 } ; struct callonce { void (*fn)(void *); void *arg; int id; } ; static LX_CONN *xc; static int scrno; static LX_XID root; static int depth; static LX_XID visual; static LX_XID cmap; static LX_XID fontid; static LX_FONTINFO *fontinfo; static LX_SGC gc; static LX_SGC gc1; static COL fg_col; static COL bg_col; static COL bc_col; static int ncpend; static int colid; static EM *ems; static LX_XID contwin; static GEOM geom; static int bordermargin; static int borderwidth; static int charwidth; static int baselineskip; static LX_XID cursor; static unsigned int scrw; static unsigned int scrh; static void handleargs(int ac, char **av) { int skip; int errs; skip = 0; errs = 0; for (ac--,av++;ac;ac--,av++) { if (skip > 0) { skip --; continue; } if (**av != '-') { fprintf(stderr,"%s: stray argument `%s'\n",__progname,*av); errs = 1; continue; } if (0) { needarg:; fprintf(stderr,"%s: %s needs a following argument\n",__progname,*av); errs = 1; continue; } #define WANTARG() do { if (++skip >= ac) goto needarg; } while (0) if (!strcmp(*av,"-display")) { WANTARG(); displayarg = av[skip]; continue; } if (!strcmp(*av,"-geometry")) { WANTARG(); geometryarg = av[skip]; continue; } if (!strcmp(*av,"-font")) { WANTARG(); fontarg = av[skip]; continue; } if (!strcmp(*av,"-fg") || !strcmp(*av,"-foreground")) { WANTARG(); fgarg = av[skip]; continue; } if (!strcmp(*av,"-bg") || !strcmp(*av,"-background")) { WANTARG(); bgarg = av[skip]; continue; } if (!strcmp(*av,"-bc") || !strcmp(*av,"-bordercolour") || !strcmp(*av,"-bordercolor")) { WANTARG(); bcarg = av[skip]; continue; } if (!strcmp(*av,"-bw") || !strcmp(*av,"-borderwidth")) { WANTARG(); bwarg = av[skip]; continue; } if (!strcmp(*av,"-bm") || !strcmp(*av,"-bordermargin")) { WANTARG(); bmarg = av[skip]; continue; } #undef WANTARG fprintf(stderr,"%s: unrecognized option `%s'\n",__progname,*av); errs = 1; } if (errs) exit(1); } static void setup_preopen(void) { borderwidth = atoi(bwarg); if (borderwidth < 0) borderwidth = 0; bordermargin = atoi(bmarg); if (bordermargin < 0) bordermargin = 0; } static int call_once_call(void *cov) { CALLONCE *co; void (*fn)(void *); void *arg; co = cov; fn = co->fn; arg = co->arg; aio_remove_block(co->id); free(co); (*fn)(arg); return(AIO_BLOCK_LOOP); } static void call_once(void (*fn)(void *), void *arg) { CALLONCE *co; co = malloc(sizeof(CALLONCE)); co->fn = fn; co->arg = arg; co->id = aio_add_block(&call_once_call,co); } static GEOM parse_geometry(const char *arg) { int v[4]; char c[2][2]; int n1; int n2; n1 = -1; n2 = -1; sscanf(arg,"%dx%d%1[+-]%d%1[+-]%d %n%*c%n",&v[0],&v[1],&c[0][0],&v[2],&c[1][0],&v[3],&n1,&n2); if (n2 >= 0) { fprintf(stderr,"%s: geometry spec has trailing junk: %s\n",__progname,arg); exit(1); } if (n1 >= 0) { if ((v[0] <= 0) || (v[1] <= 0)) { fprintf(stderr,"%s: geometry spec has nonpositive width or height: %s\n",__progname,arg); exit(1); } return((GEOM){.w=v[0],.h=v[1],.x=v[2],.y=v[3],.flags=GF_POS|((c[0][0]=='-')?GF_X_NEG:0)|((c[1][0]=='-')?GF_Y_NEG:0)}); } sscanf(arg,"%dx%d %n%*c%n",&v[0],&v[1],&n1,&n2); if (n2 >= 0) { fprintf(stderr,"%s: geometry spec has trailing junk: %s\n",__progname,arg); exit(1); } if (n1 >= 0) { if ((v[0] <= 0) || (v[1] <= 0)) { fprintf(stderr,"%s: geometry spec has nonpositive width or height: %s\n",__progname,arg); exit(1); } return((GEOM){.w=v[0],.h=v[1],.x=0,.y=0,.flags=0}); } fprintf(stderr,"%s: can't parse geometry spec: %s\n",__progname,arg); exit(1); } static int startup_step3(void *arg __attribute__((__unused__))) { int x; int y; int iw; int ih; int ow; int oh; LX_XID pm_d; LX_RECTANGLE r; if (ncpend > 0) return(AIO_BLOCK_NIL); aio_remove_block(colid); if (!fg_col.good || !bg_col.good || !bc_col.good) exit(1); ems = 0; baselineskip = fontinfo->maxbounds.ascent + fontinfo->maxbounds.descent; charwidth = fontinfo->maxbounds.width; pm_d = lx_CreatePixmap(xc,root,1,3,baselineskip+2); lx_ChangeSGC_va(xc,gc1,LX_GCV_Foreground(0),LX_GCV_END); r.x = 0; r.y = 0; r.w = 3; r.h = baselineskip + 2; lx_PolyFillRectangle(xc,pm_d,lx_SGC_GC(xc,gc1),1,&r); lx_ChangeSGC_va(xc,gc1,LX_GCV_Foreground(1),LX_GCV_END); r.x = 1; r.y = 1; r.w = 1; r.h = baselineskip; lx_PolyFillRectangle(xc,pm_d,lx_SGC_GC(xc,gc1),1,&r); cursor = lx_CreateCursor_rgb(xc,pm_d,LX_PIXMAP_None,fg_col.rgb,bg_col.rgb,1,(baselineskip/2)+1); lx_FreePixmap(xc,pm_d); iw = (geom.w * charwidth) + (2 * bordermargin); ih = (geom.h * baselineskip) + (2 * bordermargin); ow = iw + (2 * borderwidth); oh = ih + (2 * borderwidth); if (geom.flags & GF_POS) { x = (geom.flags & GF_X_NEG) ? scrw - (ow + geom.x) : geom.x; y = (geom.flags & GF_Y_NEG) ? scrh - (oh + geom.y) : geom.y; } else { x = (scrw - ow) / 2; y = (scrh - oh) / 2; } contwin = lx_CreateWindow_va(xc,root,x,y,iw,ih,borderwidth,depth,LX_WCLASS_InputOutput,visual, LX_CWV_BackPixel(bg_col.pix), LX_CWV_BorderPixel(bc_col.pix), LX_CWV_EventMask(LX_EM_StructureNotify), LX_CWV_Colormap(cmap), LX_CWV_Cursor(cursor), LX_CWV_END); lx_MapWindow(xc,contwin); return(0); } static void startup_step2(void *arg __attribute__((__unused__))) { colid = aio_add_block(&startup_step3,0); } static void handle_event(LX_CONN *c, LX_EVENT *e) { if (c != xc) abort(); switch (e->type) { case LX_EV_ConfigureNotify: printf("ConfigureNotify: "); if (e->u.ConfigureNotify.window != contwin) { printf("[*** win=%lx] ",(unsigned long int)e->u.ConfigureNotify.window); } printf( "%dx%d+%d+%d, bw %d\n", e->u.ConfigureNotify.w, e->u.ConfigureNotify.h, e->u.ConfigureNotify.x, e->u.ConfigureNotify.y, e->u.ConfigureNotify.borderwidth ); break; default: printf("Event type %d\n",(int)e->type); break; } } static void startup_got_colour(void *cv) { COL *c; c = cv; printf("Colour: %s -> %04x,%04x,%04x, pixel %lx\n",c->str,c->rgb.r,c->rgb.g,c->rgb.b,(unsigned long int)c->pix); ncpend --; } static void startup_alloc_colour(void *cv) { COL *c; c = cv; if (c->good) { lx_op_callback(lx_AllocColor(xc,cmap,c->rgb.r,c->rgb.g,c->rgb.b,&c->pix,&c->rgb.r,&c->rgb.g,&c->rgb.b),&startup_got_colour,c,0); } else { printf("Colour: %s -> fail\n",c->str); ncpend --; } } static void setup_colour(COL *c, const char *s) { c->str = s; lx_op_callback(lx_lookup_color_rgb(xc,cmap,s,-1,&c->rgb,&c->good),&startup_alloc_colour,c,0); ncpend ++; } static void startup_step1(LX_CONN *newxc, void *arg __attribute__((__unused__))) { LX_XID pm1; xc = newxc; lx_set_event_handler(xc,&handle_event); scrno = lx_default_screen(xc); root = lx_root(xc,scrno); depth = lx_root_depth(xc,scrno); visual = lx_root_visual(xc,scrno); cmap = lx_root_colormap(xc,scrno); scrw = lx_root_width(xc,scrno); scrh = lx_root_height(xc,scrno); if (! geometryarg) geometryarg = "80x24"; geom = parse_geometry(geometryarg); if (fontarg) { fontid = lx_OpenFont(xc,fontarg); gc = lx_CreateSGC_va(xc,root,LX_GCV_Font(fontid),LX_GCV_END); } else { gc = lx_CreateSGC_va(xc,root,LX_GCV_END); fontid = lx_SGC_GC(xc,gc); } pm1 = lx_CreatePixmap(xc,root,1,1,1); gc1 = lx_CreateSGC_va(xc,pm1,LX_GCV_END); lx_SGC_GC(xc,gc1); lx_FreePixmap(xc,pm1); ncpend = 0; setup_colour(&fg_col,fgarg); setup_colour(&bg_col,bgarg); setup_colour(&bc_col,bcarg); lx_op_callback(lx_QueryFont(xc,fontid,&fontinfo),&startup_step2,0,0); } int main(int, char **); int main(int ac, char **av) { handleargs(ac,av); setup_preopen(); aio_poll_init(); lx_open(displayarg,0,&startup_step1,0,0,0); aio_event_loop(); (void)&call_once; return(1); }