/* * This is *not* the Motif WM. I named it before I heard of Motif; the * first m stands for Mouse. */ #include #include #include #include #include #include #include #include #include #include #include #include extern const char *__progname; static XrmDatabase db; static const char *defaults = "\ *Foreground: white\n\ *Background: black\n\ *BorderColor: white\n\ *Font: fixed\n\ *BorderWidth: 2\n\ *BorderMargin: 5\n\ "; static char *displayname; static char *fontname; static char *foreground; static char *background; static char *bordercstr; static char *borderwstr; static char *bordermstr; static int synch = 0; static int nograbs = 0; static int output_log = 0; static const char *resname = "xhello"; static const char *resclass = "XHello"; static char *xrmstr = 0; static int argc; static char **argv; #define MODKEYS (ShiftMask|LockMask|ControlMask|Mod1Mask|Mod2Mask|Mod3Mask|Mod4Mask|Mod5Mask) typedef struct client CLIENT; typedef struct guiclient GUICLIENT; typedef struct cursdef CURSDEF; typedef struct guistate GUISTATE; struct cursdef { char *data; char *mask; int xsize; int ysize; int xhot; int yhot; } ; struct client { CLIENT *link; Window topwin; int kbd_order; int is_mapped; KeySym selkey; Colormap cmap; } ; struct guiclient { CLIENT *c; int gx; char *skstr; int skw; char *name; int nw; Window win; int winx; int winy; int winw; int winh; int winbw; } ; struct guistate { int nc; GUICLIENT **cv; int maxnw; int maxskw; int rowh; Window idwin; Window guiwin; Window markwin; Window marksel; Window markparent; Window clientparent; int markw; int cursor; } ; static char lt_img_data[3*18] = { 0,0,0,254,255,1,254,255,0,6,0,0,6,0,0,6,0,0,6,0,0,6,0,0,6,0,0,6,0,0,6,0,0,6,0,0,6,0,0,6,0,0,6,0,0,6,0,0,2,0,0,0,0,0 }; static char lt_img_mask[3*18] = { 254,255,1,255,255,3,255,255,1,255,255,0,15,0,0,15,0,0,15,0,0,15,0,0,15,0,0,15,0,0,15,0,0,15,0,0,15,0,0,15,0,0,15,0,0,15,0,0,7,0,0,1,0,0 }; static char t_img_data[3*18] = { 0,0,0,254,255,1,254,255,1,6,128,1,6,128,1,2,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 }; static char t_img_mask[3*18] = { 254,255,1,255,255,3,255,255,3,255,255,3,15,192,3,7,128,3,2,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 }; static char rt_img_data[3*18] = { 0,0,0,254,255,1,252,255,1,0,128,1,0,128,1,0,128,1,0,128,1,0,128,1,0,128,1,0,128,1,0,128,1,0,128,1,0,128,1,0,128,1,0,128,1,0,128,1,0,0,1,0,0,0 }; static char rt_img_mask[3*18] = { 254,255,1,255,255,3,254,255,3,252,255,3,0,192,3,0,192,3,0,192,3,0,192,3,0,192,3,0,192,3,0,192,3,0,192,3,0,192,3,0,192,3,0,192,3,0,192,3,0,128,3,1,0,1 }; static char l_img_data[3*18] = { 0,0,0,62,0,0,30,0,0,6,0,0,6,0,0,6,0,0,6,0,0,6,0,0,6,0,0,6,0,0,6,0,0,6,0,0,6,0,0,6,0,0,6,0,0,30,0,0,62,0,0,0,0,0 }; static char l_img_mask[3*18] = { 62,0,0,127,0,0,63,0,0,15,0,0,15,0,0,15,0,0,15,0,0,15,0,0,15,0,0,15,0,0,15,0,0,15,0,0,15,0,0,15,0,0,15,0,0,63,0,0,127,0,0,62,0,0 }; static char c_img_data[3*18] = { 0,0,0,254,255,1,254,255,1,6,128,1,6,128,1,6,128,1,6,128,1,6,128,1,6,128,1,6,128,1,6,128,1,6,128,1,6,128,1,6,128,1,6,128,1,254,255,1,254,255,1,0,0,0 }; static char c_img_mask[3*18] = { 255,255,3,255,255,3,255,255,3,255,255,3,15,192,3,15,192,3,15,192,3,15,192,3,15,192,3,15,192,3,15,192,3,15,192,3,15,192,3,15,192,3,255,255,3,255,255,3,255,255,3,255,255,3 }; static char r_img_data[3*18] = { 0,0,0,0,240,1,0,224,1,0,128,1,0,128,1,0,128,1,0,128,1,0,128,1,0,128,1,0,128,1,0,128,1,0,128,1,0,128,1,0,128,1,0,128,1,0,224,1,0,240,1,0,0,0 }; static char r_img_mask[3*18] = { 0,240,1,0,248,3,0,240,3,0,192,3,0,192,3,0,192,3,0,192,3,0,192,3,0,192,3,0,192,3,0,192,3,0,192,3,0,192,3,0,192,3,0,192,3,0,240,3,0,248,3,0,240,1 }; static char lb_img_data[3*18] = { 0,0,0,2,0,0,6,0,0,6,0,0,6,0,0,6,0,0,6,0,0,6,0,0,6,0,0,6,0,0,6,0,0,6,0,0,6,0,0,6,0,0,6,0,0,254,255,0,254,255,1,0,0,0 }; static char lb_img_mask[3*18] = { 1,0,0,7,0,0,15,0,0,15,0,0,15,0,0,15,0,0,15,0,0,15,0,0,15,0,0,15,0,0,15,0,0,15,0,0,15,0,0,15,0,0,255,255,0,255,255,1,255,255,3,254,255,1 }; static char b_img_data[3*18] = { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,0,1,6,128,1,6,128,1,254,255,1,254,255,1,0,0,0 }; static char b_img_mask[3*18] = { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,0,1,7,128,3,15,192,3,255,255,3,255,255,3,255,255,3,254,255,1 }; static char rb_img_data[3*18] = { 0,0,0,0,0,1,0,128,1,0,128,1,0,128,1,0,128,1,0,128,1,0,128,1,0,128,1,0,128,1,0,128,1,0,128,1,0,128,1,0,128,1,0,128,1,252,255,1,254,255,1,0,0,0 }; static char rb_img_mask[3*18] = { 1,0,1,0,128,3,0,192,3,0,192,3,0,192,3,0,192,3,0,192,3,0,192,3,0,192,3,0,192,3,0,192,3,0,192,3,0,192,3,0,192,3,252,255,3,254,255,3,255,255,3,254,255,1 }; static char nil_img_data[1] = { 0 }; static char nil_img_mask[1] = { 0 }; static CURSDEF cursdefs[3][3] = { { { <_img_data[0], <_img_mask[0], 18, 18, 1, 1 }, { & l_img_data[0], & l_img_mask[0], 18, 18, 1, 8 }, { &lb_img_data[0], &lb_img_mask[0], 18, 18, 1, 16 } }, { { & t_img_data[0], & t_img_mask[0], 18, 18, 8, 1 }, { & c_img_data[0], & c_img_mask[0], 18, 18, 8, 8 }, { & b_img_data[0], & b_img_mask[0], 18, 18, 8, 16 } }, { { &rt_img_data[0], &rt_img_mask[0], 18, 18, 16, 1 }, { & r_img_data[0], & r_img_mask[0], 18, 18, 16, 8 }, { &rb_img_data[0], &rb_img_mask[0], 18, 18, 16, 16 } } }; static Display *disp; static Screen *scr; static int width; static int height; static int depth; static Window rootwin; static GC rootgc; static GC gc; static XFontStruct *font; static int baselineskip; static Window resize_limit; static Cursor nilcursor; static Cursor resize_cursors[3][3]; static Window resize_children[3][3]; static Colormap defcmap; static XColor fgcolour; static XColor bgcolour; static XColor bdcolour; static int borderwidth; static int bordermargin; static CLIENT *clients; static Atom selkey_property; #ifdef XA_WM_PROTOCOLS #define A_WM_PROTOCOLS XA_WM_PROTOCOLS #else static Atom A_WM_PROTOCOLS; #endif #ifdef XA_WM_DELETE_WINDOW #define A_WM_DELETE_WINDOW XA_WM_DELETE_WINDOW #else static Atom A_WM_DELETE_WINDOW; #endif #ifdef XA_WM_NAME #define A_WM_NAME XA_WM_NAME #else static Atom A_WM_NAME; #endif static int selecting; #define SELECT_NONE 0 #define SELECT_SELECT 1 /* give keyboard focus to */ #define SELECT_EXPOSE 2 /* really "select and expose" */ #define SELECT_KEYSET 3 /* set select key of current window */ static GUISTATE gui; static FILE *mywin; static int kbd_max; static int kbd_min; static int have_focus; static int junk_direction; static int junk_ascent; static int junk_descent; #define XTE_JUNK &junk_direction,&junk_ascent,&junk_descent static int (*preverr)(Display *, XErrorEvent *); static int (*prevIOerr)(Display *); static int grabnest = 0; static void handle_event(XEvent *); /* forward */ static void strappend(char **strp, const char *str) { char *new; int oldl; int sl; if (! *strp) { *strp = malloc(1); **strp = '\0'; } oldl = strlen(*strp); sl = strlen(str); new = malloc(oldl+sl+1); bcopy(*strp,new,oldl); bcopy(str,new+oldl,sl); new[oldl+sl] = '\0'; free(*strp); *strp = new; } static void saveargv(int ac, char **av) { int i; int nc; char *abuf; argc = ac; argv = 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,"-font") || !strcmp(*av,"-fn")) { WANTARG(); fontname = av[skip]; continue; } if (!strcmp(*av,"-resname")) { WANTARG(); resname = av[skip]; continue; } if (!strcmp(*av,"-resclass")) { WANTARG(); resclass = av[skip]; continue; } if (!strcmp(*av,"-xrm")) { WANTARG(); strappend(&xrmstr,"\n"); strappend(&xrmstr,av[skip]); continue; } if (!strcmp(*av,"-sync")) { synch = 1; continue; } if (!strcmp(*av,"-log")) { output_log = 1; continue; } if (!strcmp(*av,"-nograb") || !strcmp(*av,"-nograbs")) { nograbs = 1; continue; } #undef WANTARG fprintf(stderr,"%s: unrecognized option `%s'\n",__progname,*av); errs ++; } if (errs) { exit(1); } } static void grabserver(void) { if ((grabnest == 0) && !nograbs) { XGrabServer(disp); } grabnest ++; } static void ungrabserver(void) { if (grabnest <= 0) { fprintf(mywin,"unmatched ungrabserver()\n"); return; } grabnest --; if (grabnest == 0) { XUngrabServer(disp); } } #if 0 static void ungrabserverall(void) { grabnest = 0; XUngrabServer(disp); } #endif static int window_exists(Window w) { Window root; Window parent; Window *children; int nchildren; int rv; int i; XQueryTree(disp,rootwin,&root,&parent,&children,&nchildren); rv = 0; for (i=0;ilink) { if (c->is_mapped && (c->kbd_order > max->kbd_order)) { max = c; } } return(max); } static void reset_selkey(CLIENT *c) { Atom actual_type; int actual_format; unsigned long int nitems; unsigned long int bytes_after; unsigned char *prop; XGetWindowProperty(disp,c->topwin,selkey_property,0,32,False,XA_STRING, &actual_type,&actual_format,&nitems,&bytes_after,&prop); if (actual_type == None) { /* doesn't exist */ c->selkey = NoSymbol; } else if ((actual_type != XA_STRING) || (actual_format != 8)) { /* wrong type or format */ c->selkey = NoSymbol; } else { c->selkey = XStringToKeysym(prop); { const char *skn; skn = XKeysymToString(c->selkey); if (skn == 0) skn = "not defined"; fprintf(mywin,"reset_selkey: name %s selkey %x (%s)\n",prop,(int)c->selkey,skn); } } XFree(prop); } static void reset_colormap(CLIENT *c) { XWindowAttributes attr; XGetWindowAttributes(disp,c->topwin,&attr); c->cmap = attr.colormap; if ((c->cmap != None) && (c == kbd_top())) { XInstallColormap(disp,c->cmap); } } static void new_client(Window w, int kbo) { CLIENT *c; unsigned int chgmask; XSetWindowAttributes chg; if ((w == rootwin) || (w == resize_limit)) return; grabserver(); if (window_exists(w)) { c = malloc(sizeof(CLIENT)); c->link = clients; clients = c; c->topwin = w; c->kbd_order = kbo; c->selkey = NoSymbol; chgmask = 0; chg.event_mask = PropertyChangeMask | ColormapChangeMask; chgmask |= CWEventMask; XChangeWindowAttributes(disp,c->topwin,chgmask,&chg); reset_selkey(c); reset_colormap(c); fprintf(mywin,"new client: window %x\n",(int)w); } ungrabserver(); } static void dead_client(Window w) { CLIENT **cp; CLIENT *c; for (cp=&clients;(c=*cp);cp=&c->link) { if (c->topwin == w) break; } if (c) { *cp = c->link; free(c); fprintf(mywin,"dead client: window %x\n",(int)w); } } static CLIENT *find_client(Window w) { CLIENT *c; for (c=clients;c;c=c->link) if (c->topwin == w) break; return(c); } static void load_clients(void) { Window rwin; Window rpar; Window *children; int nchildren; int i; XQueryTree(disp,rootwin,&rwin,&rpar,&children,&nchildren); clients = 0; kbd_min = 0; kbd_max = 0; for (i=0;iis_mapped = window_is_mapped(c->topwin); } XFree(children); } static Bool focus_interesting_event(Display *d __attribute__((__unused__)), XEvent *e, char *a __attribute__((__unused__))) { return(((e->type==DestroyNotify)||(e->type==UnmapNotify))?True:False); } static void reset_focus(void) { static int inhere = 0; CLIENT *c; Window w; XEvent e; if (inhere) return; grabserver(); inhere = 1; XSync(disp,False); while (XCheckIfEvent(disp,&e,focus_interesting_event,0) == True) { handle_event(&e); } c = kbd_top(); if (c) { w = c->topwin; fprintf(mywin,"giving focus to window %x\n",(int)w); XSetInputFocus(disp,w,RevertToPointerRoot,CurrentTime); if (c->cmap != None) XInstallColormap(disp,c->cmap); } inhere = 0; ungrabserver(); } static void check_focus(void) { Window hasfocus; Window focusroot; int junki1; int junki2; int junki3; int junki4; Window junkwin1; Window junkwin2; unsigned int junkui1; Window *junkwp1; have_focus = 0; XGetInputFocus(disp,&hasfocus,&junki1); if ((hasfocus == PointerRoot) || (hasfocus == None)) { if (XQueryPointer(disp,rootwin,&junkwin1,&junkwin2,&junki1,&junki2,&junki3,&junki4,&junkui1) == True) { reset_focus(); have_focus = 1; } } else { if (XQueryTree(disp,hasfocus,&focusroot,&junkwin1,&junkwp1,&junkui1)) { XFree((char *)junkwp1); have_focus = (focusroot == rootwin); } } } static int err(Display *d, XErrorEvent *ee) { if (ee->request_code == X_SetInputFocus) { char errmsg[256]; XGetErrorText(disp,ee->error_code,&errmsg[0],sizeof(errmsg)); printf("%s: XSetInputFocus: %s\n",__progname,&errmsg[0]); return(0); } return((*preverr)(d,ee)); } static int ioerr(Display *d) { return((*prevIOerr)(d)); } 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_shape(void) { int evbase; int errbase; switch (XShapeQueryExtension(disp,&evbase,&errbase)) { case True: break; case False: fprintf(stderr,"%s: display lacks Shape support\n",__progname); break; default: fprintf(stderr,"%s: XShapeQueryExtension returned impossible result\n",__progname); break; } } static void setup_db(void) { char *str; XrmDatabase db2; db = XrmGetStringDatabase(defaults); str = XResourceManagerString(disp); if (str) { db2 = XrmGetStringDatabase(str); XrmMergeDatabases(db2,&db); } #if defined(XlibSpecificationRelease) && (XlibSpecificationRelease >= 5) str = XScreenResourceString(scr); if (str) { db2 = XrmGetStringDatabase(str); XrmMergeDatabases(db2,&db); } #endif if (xrmstr) { db2 = XrmGetStringDatabase(xrmstr); XrmMergeDatabases(db2,&db); } } static void setup_variables(void) { XSetWindowAttributes attr; unsigned long int attrmask; Pixmap source; Pixmap mask; int i; int j; XCharStruct tb; Pixmap bg; bordermargin = bordermstr ? atoi(bordermstr) : 0; borderwidth = borderwstr ? atoi(borderwstr) : 1; attrmask = 0; resize_limit = XCreateWindow(disp,rootwin,0,0,1,1,0,0,InputOnly,CopyFromParent,attrmask,&attr); for (i=0;i<3;i++) { for (j=0;j<3;j++) { source = XCreatePixmapFromBitmapData(disp,rootwin,cursdefs[i][j].data,cursdefs[i][j].xsize,cursdefs[i][j].ysize,1,0,1); mask = XCreatePixmapFromBitmapData(disp,rootwin,cursdefs[i][j].mask,cursdefs[i][j].xsize,cursdefs[i][j].ysize,1,0,1); resize_cursors[i][j] = XCreatePixmapCursor(disp,source,mask,&fgcolour,&bgcolour,cursdefs[i][j].xhot,cursdefs[i][j].yhot); XFreePixmap(disp,source); XFreePixmap(disp,mask); attrmask = 0; attr.cursor = resize_cursors[i][j]; attrmask |= CWCursor; resize_children[i][j] = XCreateWindow(disp,resize_limit,0,0,1,1,0,0,InputOnly,CopyFromParent,attrmask,&attr); } } XMapSubwindows(disp,resize_limit); attrmask = 0; attrmask |= CWBackPixel; attr.background_pixel = fgcolour.pixel; attrmask |= CWBorderPixel; attr.border_pixel = bdcolour.pixel; attrmask |= CWOverrideRedirect; attr.override_redirect = True; attrmask |= CWSaveUnder; attr.save_under = True; attrmask |= CWEventMask; attr.event_mask = ButtonPressMask | ButtonReleaseMask | PointerMotionMask; attrmask |= CWDontPropagate; attr.do_not_propagate_mask = ButtonPressMask | ButtonReleaseMask | PointerMotionMask; gui.guiwin = XCreateWindow(disp,rootwin,0,0,1,1,borderwidth,0,InputOutput,CopyFromParent,attrmask,&attr); attrmask = 0; attrmask |= CWBackPixel; attr.background_pixel = fgcolour.pixel; attrmask |= CWBorderPixel; attr.border_pixel = bgcolour.pixel; attrmask |= CWOverrideRedirect; attr.override_redirect = True; attrmask |= CWSaveUnder; attr.save_under = True; attrmask |= CWDontPropagate; attr.do_not_propagate_mask = ButtonPressMask | ButtonReleaseMask | PointerMotionMask; gui.idwin = XCreateWindow(disp,rootwin,0,0,width,height,0,0,InputOutput,CopyFromParent,attrmask,&attr); source = XCreatePixmapFromBitmapData(disp,rootwin,nil_img_data,1,1,1,0,1); mask = XCreatePixmapFromBitmapData(disp,rootwin,nil_img_mask,1,1,1,0,1); nilcursor = XCreatePixmapCursor(disp,source,mask,&fgcolour,&bgcolour,0,0); XFreePixmap(disp,source); XFreePixmap(disp,mask); attrmask = 0; attr.event_mask = SubstructureRedirectMask | SubstructureNotifyMask | FocusChangeMask | KeyPressMask; attrmask |= CWEventMask; XChangeWindowAttributes(disp,rootwin,attrmask,&attr); selecting = SELECT_NONE; selkey_property = XInternAtom(disp,"wm_selkey",False); #ifndef XA_WM_PROTOCOLS A_WM_PROTOCOLS = XInternAtom(disp,"WM_PROTOCOLS",False); #endif #ifndef XA_WM_DELETE_WINDOW A_WM_DELETE_WINDOW = XInternAtom(disp,"WM_DELETE_WINDOW",False); #endif #ifndef XA_WM_NAME A_WM_NAME = XInternAtom(disp,"WM_NAME",False); #endif XTextExtents(font,"<",1,XTE_JUNK,&tb); gui.markw = tb.width; attrmask = 0; attrmask |= CWBackPixel; attr.background_pixel = bgcolour.pixel; gui.markparent = XCreateWindow(disp,gui.guiwin,0,0,1,1,0,depth,InputOutput,CopyFromParent,attrmask,&attr); bg = XCreatePixmap(disp,gui.guiwin,gui.markw,baselineskip,depth); XSetForeground(disp,gc,bgcolour.pixel); XFillRectangle(disp,bg,gc,0,0,65535,65535); XSetForeground(disp,gc,fgcolour.pixel); XDrawString(disp,bg,gc,0,font->ascent,"<",1); attrmask = 0; attrmask |= CWBackPixmap; attr.background_pixmap = bg; gui.markwin = XCreateWindow(disp,gui.markparent,-32767,-32767,gui.markw,baselineskip,0,depth,InputOutput,CopyFromParent,attrmask,&attr); XFreePixmap(disp,bg); bg = XCreatePixmap(disp,gui.guiwin,gui.markw,baselineskip,depth); XFillRectangle(disp,bg,gc,0,0,65535,65535); XSetForeground(disp,gc,bgcolour.pixel); XDrawString(disp,bg,gc,0,font->ascent,"<",1); attrmask = 0; attrmask |= CWBackPixmap; attr.background_pixmap = bg; gui.marksel = XCreateWindow(disp,gui.markparent,-32767,-32767,gui.markw,baselineskip,0,depth,InputOutput,CopyFromParent,attrmask,&attr); XFreePixmap(disp,bg); attrmask = 0; attrmask |= CWBackPixel; attr.background_pixel = fgcolour.pixel; gui.clientparent = XCreateWindow(disp,gui.guiwin,0,0,1,1,0,depth,InputOutput,CopyFromParent,attrmask,&attr); XMapSubwindows(disp,gui.markparent); XMapSubwindows(disp,gui.guiwin); } static const char *focusmode(int mode) { static char badbuf[64]; switch (mode) { case NotifyNormal: return("NotifyNormal"); case NotifyWhileGrabbed: return("NotifyWhileGrabbed"); case NotifyGrab: return("NotifyGrab"); case NotifyUngrab: return("NotifyUngrab"); } sprintf(&badbuf[0],"?%d",mode); return(&badbuf[0]); } static const char *focusdetail(int detail) { static char badbuf[64]; switch (detail) { case NotifyAncestor: return("NotifyAncestor"); case NotifyVirtual: return("NotifyVirtual"); case NotifyInferior: return("NotifyInferior"); case NotifyNonlinear: return("NotifyNonlinear"); case NotifyNonlinearVirtual: return("NotifyNonlinearVirtual"); case NotifyPointer: return("NotifyPointer"); case NotifyPointerRoot: return("NotifyPointerRoot"); case NotifyDetailNone: return("NotifyDetailNone"); } sprintf(&badbuf[0],"?%d",detail); return(&badbuf[0]); } static void grab_button(unsigned int b, unsigned int mod) { fprintf(mywin,"XGrabButton: b=%u mod=%x\n",b,mod); XGrabButton(disp,b,mod,rootwin,False,ButtonPressMask|PointerMotionMask,GrabModeSync,GrabModeSync,None,None); } static void setup_gcs(void) { gc = XDefaultGCOfScreen(scr); rootgc = XCreateGC(disp,rootwin,0,0); } static void setup_font(void) { font = XLoadQueryFont(disp,fontname); if (font == 0) { font = XQueryFont(disp,XGContextFromGC(rootgc)); 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); } XSetFont(disp,gc,font->fid); baselineskip = font->ascent + font->descent; } static void setup_colour(const char *str, XColor *col) { if (XParseColor(disp,defcmap,str,col) == 0) { fprintf(stderr,"%s: bad colour `%s'\n",__progname,str); exit(1); } if (XAllocColor(disp,defcmap,col) == 0) { fprintf(stderr,"%s: can't allocate colormap cell for colour `%s'\n",__progname,str); exit(1); } } static void setup_colours(void) { setup_colour(foreground,&fgcolour); setup_colour(background,&bgcolour); setup_colour(bordercstr,&bdcolour); XSetForeground(disp,gc,fgcolour.pixel); XSetBackground(disp,gc,bgcolour.pixel); } static void setup_grabs(void) { KeyCode kc; grab_button(Button1,ShiftMask); grab_button(Button1,ControlMask); grab_button(Button1,ShiftMask|ControlMask); grab_button(Button2,ShiftMask|ControlMask); grab_button(Button3,ControlMask); grab_button(Button3,ShiftMask|ControlMask); kc = XKeysymToKeycode(disp,XK_F7); if (kc != 0) XGrabKey(disp,kc,AnyModifier,rootwin,False,GrabModeAsync,GrabModeSync); kc = XKeysymToKeycode(disp,XK_F8); if (kc != 0) XGrabKey(disp,kc,AnyModifier,rootwin,False,GrabModeAsync,GrabModeSync); } static void wselect(CLIENT *c) { if (c) { c->kbd_order = ++kbd_max; reset_focus(); } else { XSetInputFocus(disp,PointerRoot,RevertToPointerRoot,CurrentTime); } } static void wdeselect(CLIENT *c) { if (c) { c->kbd_order = --kbd_min; reset_focus(); } } static void kset(KeySym ks) { CLIENT *sel; sel = kbd_top(); if (sel) sel->selkey = ks; } static void kselect(KeySym ks, int expose) { CLIENT *sel; if (ks == XK_space) { CLIENT *c; CLIENT *max; max = 0; sel = 0; for (c=clients;c;c=c->link) { if ((max == 0) || (c->kbd_order > max->kbd_order)) { sel = max; max = c; } else if ((sel == 0) || (c->kbd_order > sel->kbd_order)) { sel = c; } } } else { CLIENT *c; CLIENT *max; CLIENT *maxm; CLIENT *minm; max = clients; maxm = 0; minm = 0; for (c=clients;c;c=c->link) { if (c->kbd_order > max->kbd_order) max = c; if (c->selkey != ks) continue; if ((maxm == 0) || (c->kbd_order > maxm->kbd_order)) maxm = c; if ((minm == 0) || (c->kbd_order < minm->kbd_order)) minm = c; } sel = (max->selkey == ks) ? minm : maxm; } if (sel) { wselect(sel); if (expose) { grabserver(); if (window_exists(sel->topwin)) { XRaiseWindow(disp,sel->topwin); } ungrabserver(); } } } static void setlimit(int x1, int y1, int x2, int y2) { int i; int j; unsigned int chgmask; XWindowChanges chg; int subx[4]; int suby[4]; chgmask = 0; chg.x = x1; chgmask |= CWX; chg.y = y1; chgmask |= CWY; chg.width = x2 + 1 - x1; chgmask |= CWWidth; chg.height = y2 + 1 - y1; chgmask |= CWHeight; if (chg.width < 3) chg.width = 3; if (chg.height < 3) chg.height = 3; subx[0] = 0; subx[1] = chg.width / 3; subx[2] = chg.width - subx[1]; subx[3] = chg.width; suby[0] = 0; suby[1] = chg.height / 3; suby[2] = chg.height - suby[1]; suby[3] = chg.height; XConfigureWindow(disp,resize_limit,chgmask,&chg); for (i=0;i<3;i++) { for (j=0;j<3;j++) { chgmask = 0; chg.x = subx[i]; chgmask |= CWX; chg.y = suby[j]; chgmask |= CWY; chg.width = subx[i+1] - subx[i]; chgmask |= CWWidth; chg.height = suby[j+1] - suby[j]; chgmask |= CWHeight; XConfigureWindow(disp,resize_children[i][j],chgmask,&chg); } } } static Bool move_resize_pred(Display *d __attribute__((__unused__)), XEvent *e, char *a __attribute__((__unused__))) { switch (e->type) { case ButtonPress: case MotionNotify: return(True); break; } return(False); } static void move_or_resize(CLIENT *c) { unsigned int junkui; int x1; int x2; int y1; int y2; int ox; int oy; int dx; int dy; unsigned long int gcchange; int grv; int dragging; #define DRAG_L 0x00000001 #define DRAG_R 0x00000002 #define DRAG_T 0x00000004 #define DRAG_B 0x00000008 #define DRAG_ALL (DRAG_L|DRAG_R|DRAG_T|DRAG_B) int lastdrag; int xmin; int ymin; int xmax; int ymax; int xoff; int yoff; unsigned int chgmask; XWindowChanges chg; XGCValues gcvalues; XSegment boxsegs[4]; XWindowAttributes attr; XEvent e; Window junkwin1; Window junkwin2; if (c == 0) return; if (XGetWindowAttributes(disp,c->topwin,&attr) == 0) goto out; if (XQueryPointer(disp,rootwin,&junkwin1,&junkwin2,&ox,&oy,&x1,&y1,&junkui) == False) goto out; x1 = attr.x; y1 = attr.y; x2 = attr.x + attr.width + (attr.border_width * 2) - 1; y2 = attr.y + attr.height + (attr.border_width * 2) - 1; dragging = 0; setlimit(0,0,width,height); XMapRaised(disp,resize_limit); switch (grv=XGrabPointer(disp,rootwin,False,ButtonPressMask|PointerMotionMask|PointerMotionHintMask,GrabModeSync,GrabModeSync,resize_limit,None,CurrentTime)) { default: fprintf(mywin,"XGrabPointer: %d\n",grv); break; case GrabSuccess: break; case GrabNotViewable: fprintf(mywin,"XGrabPointer: GrabNotViewable\n"); break; case AlreadyGrabbed: fprintf(mywin,"XGrabPointer: AlreadyGrabbed\n"); break; case GrabFrozen: fprintf(mywin,"XGrabPointer: GrabFrozen\n"); break; case GrabInvalidTime: fprintf(mywin,"XGrabPointer: GrabInvalidTime\n"); break; } XAllowEvents(disp,AsyncPointer,CurrentTime); gcchange = 0; gcvalues.foreground = ~0; gcchange |= GCForeground; gcvalues.background = 0; gcchange |= GCBackground; gcvalues.function = GXxor; gcchange |= GCFunction; gcvalues.subwindow_mode = IncludeInferiors; gcchange |= GCSubwindowMode; gcvalues.clip_mask = None; gcchange |= GCClipMask; XChangeGC(disp,rootgc,gcchange,&gcvalues); lastdrag = ~0; while (1) { if (dragging != lastdrag) { lastdrag = dragging; XChangeActivePointerGrab(disp,ButtonPressMask|PointerMotionMask|PointerMotionHintMask,dragging?nilcursor:None,CurrentTime); switch (dragging) { case 0: xmin = x1; ymin = y1; xmax = x2; ymax = y2; break; case DRAG_ALL: xmin = xoff; ymin = yoff; xmax = width - (attr.width + (2 * attr.border_width) - xoff); ymax = height - (attr.height + (2 * attr.border_width) - yoff); break; default: xmin = 0; ymin = 0; xmax = width; ymax = height; break; } setlimit(xmin,ymin,xmax,ymax); } if (XCheckIfEvent(disp,&e,move_resize_pred,0) == False) { boxsegs[0].x1 = x1; /* gag - should figure out how to draw a proper closed box */ boxsegs[0].y1 = y1; boxsegs[0].x2 = x1; boxsegs[0].y2 = y2; boxsegs[1].x1 = x1; boxsegs[1].y1 = y1; boxsegs[1].x2 = x2; boxsegs[1].y2 = y1; boxsegs[2].x1 = x2; boxsegs[2].y1 = y2; boxsegs[2].x2 = x1; boxsegs[2].y2 = y2; boxsegs[3].x1 = x2; boxsegs[3].y1 = y2; boxsegs[3].x2 = x2; boxsegs[3].y2 = y1; XDrawSegments(disp,rootwin,rootgc,&boxsegs[0],4); XIfEvent(disp,&e,move_resize_pred,0); XDrawSegments(disp,rootwin,rootgc,&boxsegs[0],4); } switch (e.type) { default: break; case ButtonPress: /* XButtonEvent - xbutton */ switch (e.xbutton.button) { case Button1: if (dragging) { dragging = 0; } else { int xc1; int xc2; int yc1; int yc2; int x; int y; xc1 = (x2 - x1) / 3; xc2 = (x2 - x1) - xc1; yc1 = (y2 - y1) / 3; yc2 = (y2 - y1) - yc1; x = e.xbutton.x_root - x1; y = e.xbutton.y_root - y1; if (x <= xc1) x = 0; else if (x >= xc2) x = 2; else x = 1; if (y <= yc1) y = 0; else if (y >= yc2) y = 2; else y = 1; if ((x == 1) && (y == 1)) { dragging = DRAG_ALL; xoff = e.xbutton.x_root - x1; yoff = e.xbutton.y_root - y1; } else { switch (x) { case 0: dragging |= DRAG_L; x = xmin; break; case 1: x = e.xbutton.x_root; break; case 2: dragging |= DRAG_R; x = xmax; break; } switch (y) { case 0: dragging |= DRAG_T; y = ymin; break; case 1: y = e.xbutton.y_root; break; case 2: dragging |= DRAG_B; y = ymax; break; } XWarpPointer(disp,None,rootwin,0,0,0,0,x,y); ox = x; oy = y; } } break; case Button2: chgmask = 0; chg.x = x1; chgmask |= CWX; chg.y = y1; chgmask |= CWY; chg.width = (x2 + 1 - x1) - (attr.border_width * 2); chgmask |= CWWidth; chg.height = (y2 + 1 - y1) - (attr.border_width * 2); chgmask |= CWHeight; if (chg.width < 1) chg.width = 1; if (chg.height < 1) chg.height = 1; XConfigureWindow(disp,c->topwin,chgmask,&chg); goto out; /* aka break 2 */ break; case Button3: goto out; /* aka break 2 */ break; } break; case MotionNotify: /* XMotionEvent - xmotion */ { Window w1; Window w2; int rx; int ry; int x; int y; unsigned int m; if (XQueryPointer(disp,rootwin,&w1,&w2,&rx,&ry,&x,&y,&m) == True) { dx = x - ox; dy = y - oy; if (dragging & DRAG_L) x1 += dx; if (dragging & DRAG_R) x2 += dx; if (dragging & DRAG_T) y1 += dy; if (dragging & DRAG_B) y2 += dy; if (x1 > x2) { x1 ^= x2; x2 ^= x1; x1 ^= x2; dragging ^= DRAG_L|DRAG_R; } if (y1 > y2) { y1 ^= y2; y2 ^= y1; y1 ^= y2; dragging ^= DRAG_T|DRAG_B; } ox += dx; oy += dy; } } break; } } out:; XUnmapWindow(disp,resize_limit); XUngrabPointer(disp,CurrentTime); } static void set_gui_cursor(int inx) { GUICLIENT *g; int x1; int y1; int x2; int y2; XRectangle rects[4]; if ((inx < 0) || (inx >= gui.nc)) abort(); gui.cursor = inx; g = gui.cv[inx]; XMoveWindow(disp,gui.markwin,bordermargin,bordermargin+(inx*gui.rowh)); XUnmapWindow(disp,gui.idwin); x1 = g->winx; y1 = g->winy; x2 = g->winx + g->winw + (2 * g->winbw); y2 = g->winy + g->winh + (2 * g->winbw); rects[0].x = x1 - 1; rects[0].y = y1 - 1; rects[0].width = (x2 - x1) + 2; rects[0].height = 3; rects[1].x = x1 - 1; rects[1].y = y2 - 1; rects[1].width = (x2 - x1) + 2; rects[1].height = 3; rects[2].x = x1 - 1; rects[2].y = y1 - 1; rects[2].width = 3; rects[2].height = (y2 - y1) + 2; rects[3].x = x2 - 1; rects[3].y = y1 - 1; rects[3].width = 3; rects[3].height = (y2 - y1) + 2; XShapeCombineRectangles(disp,gui.idwin,ShapeBounding,0,0,&rects[0],4,ShapeSet,Unsorted); rects[0].x = x1; rects[0].y = y1; rects[0].width = x2 - x1; rects[0].height = 1; rects[1].x = x1; rects[1].y = y2; rects[1].width = x2 - x1; rects[1].height = 1; rects[2].x = x1; rects[2].y = y1; rects[2].width = 1; rects[2].height = y2 - y1; rects[3].x = x2; rects[3].y = y1; rects[3].width = 1; rects[3].height = y2 - y1; XShapeCombineRectangles(disp,gui.idwin,ShapeClip,0,0,&rects[0],4,ShapeSet,Unsorted); XMapWindow(disp,gui.idwin); } static void run_gui(void) { CLIENT *c; GUICLIENT *g; int i; int j; int k; const char *skn; Window root_root; Window root_parent; Window *root_children; int root_nchildren; XCharStruct tb; int ew; int ww; int h; unsigned long int attrmask; XSetWindowAttributes attr; Pixmap bg; if (! clients) { XBell(disp,0); return; } gui.nc = 0; gui.cv = 0; for (c=clients;c;c=c->link) { if (! c->is_mapped) continue; gui.cv = realloc(gui.cv,(gui.nc+1)*sizeof(GUICLIENT *)); g = malloc(sizeof(GUICLIENT)); g->c = c; fprintf(mywin,"client %p, guiclient %p, as [%d]\n",(void *)c,(void *)g,gui.nc); gui.cv[gui.nc++] = g; } XUnmapWindow(disp,gui.idwin); XUnmapWindow(disp,gui.guiwin); XRaiseWindow(disp,gui.idwin); XRaiseWindow(disp,gui.guiwin); XMoveWindow(disp,gui.markwin,-32767,-32767); XMoveWindow(disp,gui.marksel,-32767,-32767); for (k=gui.nc-1;k>=0;k--) gui.cv[k]->gx = -1; XQueryTree(disp,rootwin,&root_root,&root_parent,&root_children,&root_nchildren); j = 0; for (i=root_nchildren-1;i>=0;i--) { for (k=gui.nc-1;k>=0;k--) { g = gui.cv[k]; if (g->c->topwin == root_children[i]) { g->gx = j++; fprintf(mywin,"child [%d] %#lx matches client %p, gx %d\n",i,(unsigned long int)root_children[i],(void *)g->c,g->gx); break; } } } j = 0; for (i=0;igx >= 0) { if (j != i) gui.cv[j] = gui.cv[i]; j ++; } else { fprintf(mywin,"dropping unfound guiclient %p (win %#lx)\n",(void *)g,(unsigned long int)g->c->topwin); } } while (gui.nc > j) free(gui.cv[--gui.nc]); fprintf(mywin,"# clients = %d\n",gui.nc); if (gui.nc < 1) { free(gui.cv); XBell(disp,0); return; } gui.maxnw = 0; gui.maxskw = 0; for (i=gui.nc-1;i>=0;i--) { Atom actual_type; int actual_format; unsigned long int nitems; unsigned long int bytes_after; unsigned char *prop; Window xtc_junk; Window ggroot_junk; int ggx_junk; int ggy_junk; unsigned int ggd_junk; g = gui.cv[i]; c = g->c; fprintf(mywin,"client %p, window %#lx\n",(void *)c,(unsigned long int)c->topwin); XGetWindowProperty(disp,c->topwin,A_WM_NAME,0,16,False,XA_STRING, &actual_type,&actual_format,&nitems,&bytes_after,&prop); if ((actual_type == None) || (actual_type != XA_STRING) || (actual_format != 8)) { g->name = 0; g->nw = 0; fprintf(mywin," no name\n"); } else { g->name = strdup(prop); XTextExtents(font,g->name,strlen(g->name),XTE_JUNK,&tb); g->nw = tb.width; fprintf(mywin," name %s, width %d\n",g->name,tb.width); if (tb.width > gui.maxnw) gui.maxnw = tb.width; } XFree(prop); g->skstr = 0; g->skw = 0; if (c->selkey != NoSymbol) { skn = XKeysymToString(c->selkey); if (skn) { g->skstr = strdup(skn); XTextExtents(font,skn,strlen(skn),XTE_JUNK,&tb); g->skw = tb.width; if (tb.width > gui.maxskw) gui.maxskw = tb.width; fprintf(mywin," selkey %s, width %d\n",g->skstr,tb.width); } } XTranslateCoordinates(disp,c->topwin,rootwin,0,0,&g->winx,&g->winy,&xtc_junk); XGetGeometry(disp,c->topwin,&ggroot_junk,&ggx_junk,&ggy_junk,&g->winw,&g->winh,&g->winbw,&ggd_junk); } fprintf(mywin,"maxnw %d, maxskw %d\n",gui.maxnw,gui.maxskw); ew = (4 * bordermargin) + borderwidth + gui.maxnw + gui.maxskw; ww = ew + (2 * bordermargin) + borderwidth + gui.markw; h = baselineskip + (2 * bordermargin); gui.rowh = h + borderwidth; for (i=gui.nc-1;i>=0;i--) { g = gui.cv[i]; bg = XCreatePixmap(disp,rootwin,ew,h,depth); XSetForeground(disp,gc,bgcolour.pixel); XFillRectangle(disp,bg,gc,0,0,65535,65535); XSetForeground(disp,gc,fgcolour.pixel); if (g->skstr) XDrawString(disp,bg,gc,bordermargin,bordermargin+font->ascent,g->skstr,strlen(g->skstr)); XFillRectangle(disp,bg,gc,(2*bordermargin)+gui.maxskw,0,borderwidth,65535); if (g->name) XDrawString(disp,bg,gc,(3*bordermargin)+borderwidth+gui.maxskw,bordermargin+font->ascent,g->name,strlen(g->name)); attrmask = 0; attrmask |= CWBackPixmap; attr.background_pixmap = bg; g->win = XCreateWindow(disp,gui.clientparent,0,g->gx*gui.rowh,ew,h,0,depth,InputOutput,CopyFromParent,attrmask,&attr); XFreePixmap(disp,bg); } h = (gui.nc * gui.rowh) - borderwidth; XMoveResizeWindow(disp,gui.clientparent,0,0,ew,h); XMoveResizeWindow(disp,gui.markparent,ew+borderwidth,0,(2*bordermargin)+gui.markw,h); XMoveResizeWindow(disp,gui.guiwin,(width-(ww+(2*borderwidth)))/2,(height-(h+(2*borderwidth)))/2,ww,h); XMapSubwindows(disp,gui.clientparent); XMapWindow(disp,gui.guiwin); set_gui_cursor(0); i = 1; while <"gui"> (1) { XEvent e; if (i) { XAllowEvents(disp,SyncKeyboard,CurrentTime); i = 0; } XNextEvent(disp,&e); switch (e.type) { case KeyPress: fprintf(mywin,"KeyPress event, keycode %d\n",e.xkey.keycode); i = 1; switch (XKeycodeToKeysym(disp,e.xkey.keycode,0)) { case XK_J: case XK_j: if (gui.cursor+1 < gui.nc) set_gui_cursor(gui.cursor+1); break; case XK_K: case XK_k: if (gui.cursor > 0) set_gui_cursor(gui.cursor-1); break; case XK_Escape: break <"gui">; default: XBell(disp,0); break; } break; case KeyRelease: i = 1; break; } } XDestroySubwindows(disp,gui.clientparent); XUnmapWindow(disp,gui.guiwin); XUnmapWindow(disp,gui.idwin); while (gui.nc > 0) free(gui.cv[--gui.nc]); free(gui.cv); } static void handle_event(XEvent *e) { KeySym keysym; unsigned int chgmask; XWindowChanges chg; switch (e->type) { default: break; case DestroyNotify: /* XDestroyWindowEvent - xdestroywindow */ dead_client(e->xdestroywindow.window); if (have_focus) reset_focus(); break; case FocusIn: /* XFocusInEvent - xfocus */ fprintf(mywin,"FocusIn: window %x, mode %s, detail %s\n", (int)e->xfocus.window,focusmode(e->xfocus.mode),focusdetail(e->xfocus.detail)); switch (e->xfocus.detail) { case NotifyPointer: reset_focus(); break; case NotifyNonlinearVirtual: have_focus = 1; break; } break; case FocusOut: /* XFocusOutEvent - xfocus */ fprintf(mywin,"FocusOut: window %x, mode %s, detail %s\n", (int)e->xfocus.window,focusmode(e->xfocus.mode),focusdetail(e->xfocus.detail)); switch (e->xfocus.detail) { case NotifyDetailNone: reset_focus(); break; case NotifyNonlinearVirtual: have_focus = 0; break; } break; case ButtonPress: /* XButtonEvent - xbutton */ fprintf(mywin,"ButtonPress: window %x subwindow %x at (%d,%d) state %x button %d\n",(int)e->xbutton.window,(int)e->xbutton.subwindow,e->xbutton.x,e->xbutton.y,e->xbutton.state,e->xbutton.button); switch (e->xbutton.button) { case Button1: grabserver(); if (window_exists(e->xbutton.subwindow)) { switch (e->xbutton.state & MODKEYS) { case ShiftMask: wselect(find_client(e->xbutton.subwindow)); break; case ControlMask: XLowerWindow(disp,e->xbutton.subwindow); wdeselect(find_client(e->xbutton.subwindow)); break; case ShiftMask|ControlMask: XRaiseWindow(disp,e->xbutton.subwindow); wselect(find_client(e->xbutton.subwindow)); break; } } ungrabserver(); break; case Button2: switch (e->xbutton.state & MODKEYS) { case ShiftMask|ControlMask: grabserver(); if (window_exists(e->xbutton.subwindow)) { XInstallColormap(disp,defcmap); move_or_resize(find_client(e->xbutton.subwindow)); reset_focus(); } ungrabserver(); break; } break; case Button3: if (selecting != SELECT_NONE) { selecting = SELECT_NONE; XUngrabKeyboard(disp,CurrentTime); fprintf(mywin,"Forcible SELECT_NONE\n"); break; } switch (e->xbutton.state & MODKEYS) { case ControlMask: { XEvent se; se.type = ClientMessage; se.xclient.window = e->xbutton.subwindow; se.xclient.message_type = A_WM_PROTOCOLS; se.xclient.format = 32; se.xclient.data.l[0] = A_WM_DELETE_WINDOW; XSendEvent(disp,e->xbutton.subwindow,False,0,&se); } break; case ShiftMask|ControlMask: XKillClient(disp,e->xbutton.subwindow); break; } break; } XUngrabPointer(disp,e->xbutton.time); break; case KeyPress: /* XKeyPressedEvent - XKeyEvent - xkey */ switch (selecting) { int foo(void) { switch (XKeycodeToKeysym(disp,e->xkey.keycode,0)) { case XK_F7: selecting = SELECT_SELECT; fprintf(mywin,"F7 pressed: switching to SELECT_SELECT\n"); if (0) { case XK_F8: selecting = SELECT_EXPOSE; fprintf(mywin,"F8 pressed: switching to SELECT_EXPOSE\n"); } if (0) { case XK_F6: selecting = SELECT_KEYSET; fprintf(mywin,"F6 pressed: switching to SELECT_KEYSET\n"); } XAllowEvents(disp,SyncKeyboard,e->xkey.time); return(1); } return(0); } case SELECT_NONE: switch (XKeycodeToKeysym(disp,e->xkey.keycode,0)) { case XK_F7: if (XGrabKeyboard(disp,rootwin,False,GrabModeAsync,GrabModeSync,e->xkey.time) == GrabSuccess) { XAllowEvents(disp,SyncKeyboard,e->xkey.time); selecting = SELECT_SELECT; fprintf(mywin,"F7 pressed: SELECT_SELECT set\n"); } else { fprintf(mywin,"F7 pressed: XGrabKeyboard failed\n"); } break; case XK_F8: switch (e->xkey.state & (ControlMask|ShiftMask)) { case 0: if (XGrabKeyboard(disp,rootwin,False,GrabModeAsync,GrabModeSync,e->xkey.time) == GrabSuccess) { XAllowEvents(disp,SyncKeyboard,e->xkey.time); selecting = SELECT_EXPOSE; fprintf(mywin,"F8 pressed: SELECT_EXPOSE set\n"); } else { fprintf(mywin,"F8 pressed: XGrabKeyboard failed\n"); } break; case ControlMask|ShiftMask: grabserver(); if (XGrabKeyboard(disp,rootwin,False,GrabModeAsync,GrabModeSync,e->xkey.time) == GrabSuccess) { fprintf(mywin,"Ctl-Shift-F8 pressed: running GUI\n"); run_gui(); XUngrabKeyboard(disp,CurrentTime); } else { fprintf(mywin,"Ctrl-Shift-F8 pressed: XGrabKeyboard failed\n"); } ungrabserver(); break; case ControlMask: fprintf(mywin,"Ctrl-F8 pressed: ignoring\n"); if (0) { case ShiftMask: fprintf(mywin,"Shift-F8 pressed: ignoring\n"); } if (0) { default: fprintf(mywin,"impossibly modified F8 pressed: ignoring\n"); } XBell(disp,0); XUngrabKeyboard(disp,e->xkey.time); break; } break; case XK_F6: if (XGrabKeyboard(disp,rootwin,False,GrabModeAsync,GrabModeSync,e->xkey.time) == GrabSuccess) { XAllowEvents(disp,SyncKeyboard,e->xkey.time); selecting = SELECT_KEYSET; fprintf(mywin,"F6 pressed: SELECT_KEYSET set\n"); } else { fprintf(mywin,"F6 pressed: XGrabKeyboard failed\n"); } break; default: XUngrabKeyboard(disp,e->xkey.time); fprintf(mywin,"other key pressed: no select, keyboard ungrabbed\n"); break; } break; case SELECT_SELECT: if (foo()) break; selecting = SELECT_NONE; keysym = XKeycodeToKeysym(disp,e->xkey.keycode,0); kselect(keysym,0); XUngrabKeyboard(disp,e->xkey.time); fprintf(mywin,"SELECT_SELECT: keyboard ungrabbed\n"); break; case SELECT_EXPOSE: if (foo()) break; selecting = SELECT_NONE; keysym = XKeycodeToKeysym(disp,e->xkey.keycode,0); kselect(keysym,1); XUngrabKeyboard(disp,e->xkey.time); fprintf(mywin,"SELECT_EXPOSE: keyboard ungrabbed\n"); break; case SELECT_KEYSET: if (foo()) break; selecting = SELECT_NONE; keysym = XKeycodeToKeysym(disp,e->xkey.keycode,0); kset(keysym); XUngrabKeyboard(disp,e->xkey.time); fprintf(mywin,"SELECT_KEYSET: keyboard ungrabbed\n"); break; } break; case KeyRelease: /* XKeyPressedEvent - XKeyEvent - xkey */ if (selecting != SELECT_NONE) { XAllowEvents(disp,SyncKeyboard,e->xkey.time); } break; case CirculateRequest: /* XCirculateRequestEvent - xcirculaterequest */ fprintf(mywin,"CirculateRequest: Parent %x, window %x, to %s\n", (int)e->xcirculaterequest.parent,(int)e->xcirculaterequest.window, ((e->xcirculaterequest.place==PlaceOnTop)?"top":"bottom") ); grabserver(); if (window_exists(e->xcirculaterequest.window)) { switch (e->xcirculaterequest.place) { case PlaceOnTop: XRaiseWindow(disp,e->xcirculaterequest.window); break; case PlaceOnBottom: XLowerWindow(disp,e->xcirculaterequest.window); break; } } ungrabserver(); break; case ConfigureRequest: /* XConfigureRequestEvent - xconfigurerequest */ fprintf(mywin, "ConfigureRequest: Parent %x, window %x, to (%d,%d) size (%d,%d) bw %d detail %d\n", (int)e->xconfigurerequest.parent,(int)e->xconfigurerequest.window, e->xconfigurerequest.x,e->xconfigurerequest.y, e->xconfigurerequest.width,e->xconfigurerequest.height, e->xconfigurerequest.border_width,e->xconfigurerequest.detail ); chgmask = e->xconfigurerequest.value_mask; if (chgmask & CWX) chg.x = e->xconfigurerequest.x; if (chgmask & CWY) chg.y = e->xconfigurerequest.y; if (chgmask & CWWidth) chg.width = e->xconfigurerequest.width; if (chgmask & CWHeight) chg.height = e->xconfigurerequest.height; if (chgmask & CWBorderWidth) chg.border_width = e->xconfigurerequest.border_width; if (chgmask & CWSibling) chg.sibling = e->xconfigurerequest.above; if (chgmask & CWStackMode) chg.stack_mode = e->xconfigurerequest.detail; if (chg.width < 1) chgmask &= ~CWWidth; if (chg.height < 1) chgmask &= ~CWHeight; grabserver(); if (window_exists(e->xconfigurerequest.window)) { XConfigureWindow(disp,e->xconfigurerequest.window,chgmask,&chg); } ungrabserver(); break; case MapRequest: /* XMapRequestEvent - xmaprequest */ fprintf(mywin,"MapRequest: parent %x, window %x\n", (int)e->xmaprequest.parent,(int)e->xmaprequest.window); grabserver(); if (window_exists(e->xmaprequest.window)) { CLIENT *c; XMapWindow(disp,e->xmaprequest.window); c = find_client(e->xmaprequest.window); if (c == 0) { new_client(e->xmaprequest.window,--kbd_min); c = find_client(e->xmaprequest.window); } c->is_mapped = 1; } ungrabserver(); break; case MapNotify: fprintf(mywin,"MapNotify: window %x\n",(int)e->xmap.window); if (!e->xmap.override_redirect) { CLIENT *c; c = find_client(e->xmap.window); if (c) c->is_mapped = 1; } break; case UnmapNotify: fprintf(mywin,"UnmapNotify: window %x\n",(int)e->xunmap.window); { CLIENT *c; c = find_client(e->xunmap.window); if (c) c->is_mapped = 0; reset_focus(); } break; case PropertyNotify: /* XPropertyEvent - xproperty */ if (e->xproperty.atom == selkey_property) { CLIENT *c; c = find_client(e->xproperty.window); if (c) { grabserver(); if (window_exists(e->xproperty.window)) reset_selkey(c); ungrabserver(); } } break; case ColormapNotify: /* XColormapEvent - xcolormap */ { CLIENT *c; c = find_client(e->xcolormap.window); if (c) { grabserver(); if (window_exists(e->xcolormap.window)) reset_colormap(c); ungrabserver(); } } break; } } static void setup_mywin(void) { mywin = output_log ? stdout : fopen("/dev/null","w"); setlinebuf(mywin); } int main(int, char **); int main(int ac, char **av) { saveargv(ac,av); handleargs(ac,av); setup_mywin(); fprintf(mywin,"This is mwm.\n"); disp = XOpenDisplay(displayname); if (! disp) { fprintf(stderr,"%s: can't open display\n",__progname); exit(1); } if (synch) XSynchronize(disp,True); setup_shape(); preverr = XSetErrorHandler(err); prevIOerr = XSetIOErrorHandler(ioerr); scr = XDefaultScreenOfDisplay(disp); width = XWidthOfScreen(scr); height = XHeightOfScreen(scr); depth = XPlanesOfScreen(scr); rootwin = XRootWindowOfScreen(scr); defcmap = XDefaultColormapOfScreen(scr); setup_db(); maybeset(&fontname,get_default_value("mwm.font","WM.Font")); maybeset(&foreground,get_default_value("mwm.foreground","WM.Foreground")); maybeset(&background,get_default_value("mwm.background","WM.Background")); maybeset(&bordercstr,get_default_value("mwm.borderColor","WM.BorderColor")); maybeset(&borderwstr,get_default_value("mwm.borderWidth","WM.BorderWidth")); maybeset(&bordermstr,get_default_value("mwm.borderMargin","WM.BorderMargin")); setup_gcs(); setup_font(); setup_colours(); setup_variables(); setup_grabs(); grabserver(); load_clients(); check_focus(); ungrabserver(); while (1) { XEvent e; XNextEvent(disp,&e); handle_event(&e); } }