#include #include #include #include #include #include #include #include #ifdef HAVE_X11_EXTENSIONS_SHAPE_H #include #endif #ifdef AMIGAOS #include #endif #ifdef HAVE_FCNTL_H #include #endif #include #include #include #include #include #ifdef HAVE_SYS_TIME_H #include #endif #ifdef HAVE_SYS_SELECT_H #include #endif #ifdef HAVE_SYS_TYPES_H #include #endif #ifdef HAVE_UNISTD_H #include #endif #ifdef USE_FONTSETS #include #endif #include "drawinfo.h" #include "screen.h" #include "icon.h" #include "client.h" #include "prefs.h" #include "module.h" #include "icc.h" #include "libami.h" #ifdef AMIGAOS #include extern struct Library *XLibBase; struct timeval { long tv_sec; long tv_usec; }; #define fd_set XTransFdset #undef FD_ZERO #undef FD_SET #define FD_ZERO XTransFdZero #define FD_SET XTransFdSet #define select XTransSelect #endif #define HYSTERESIS 5 typedef struct _DragIcon { Icon *icon; Window w; Pixmap pm; int x, y; } DragIcon; Display *dpy = NULL; char *progname; Cursor wm_curs; int signalled=0, forcemoving=0; Client *activeclient=NULL, *dragclient=NULL, *resizeclient=NULL; Client *rubberclient=NULL, *clickclient=NULL, *doubleclient=NULL; Scrn *boundingscr=NULL; Window boundingwin=None; DragIcon *dragiconlist=NULL; int numdragicons=0; Window clickwindow=None; int rubberx, rubbery, rubberh, rubberw, rubberx0, rubbery0, olddragx, olddragy; Time last_icon_click=0, last_double=0; int initting=0; static int ignore_badwindow=0; int dblClickTime=1500; XContext client_context, screen_context, icon_context, menu_context, vroot_context; Scrn *dragscreen=NULL, *menuactive=NULL; static int d_offset=0; static fd_set master_fd_set; static int max_fd=0; char *free_screentitle=NULL; char *x_server=NULL; int shape_event_base, shape_error_base, shape_extn=0; int server_grabs=0; unsigned int meta_mask, switch_mask; static char **main_argv; extern Scrn *mbdclick, *mbdscr; extern void reparent(Client *); extern void redraw(Client *, Window); extern void redrawclient(Client *); extern void redrawmenubar(Scrn *, Window); extern void gadgetclicked(Client *c, Window w, XEvent *e); extern void gadgetunclicked(Client *c, XEvent *e); extern void gadgetaborted(Client *c); extern void clickenter(void); extern void clickleave(void); extern void menu_on(void); extern void menu_off(void); extern void menubar_enter(Window); extern void menubar_leave(Window); extern void *getitembyhotkey(KeySym); extern void menuaction(void *); extern Scrn *getscreenbyroot(Window); extern void assimilate(Window, int, int); extern void deselect_all_icons(Scrn *); extern void reparenticon(Icon *, Scrn *, int, int); extern void handle_client_message(Client *, XClientMessageEvent *); extern void handle_module_input(fd_set *); extern int dispatch_event_to_broker(XEvent *, unsigned long, struct module *); extern XEvent *mkcmessage(Window w, Atom a, long x); extern void reshape_frame(Client *c); extern void read_rc_file(char *filename, int manage_all); extern void init_modules(); extern void flushmodules(); extern void raiselowerclient(Client *, int); #ifndef AMIGAOS void restart_amiwm() { flushmodules(); flushclients(); XFlush(dpy); XCloseDisplay(dpy); execvp(main_argv[0], main_argv); } #endif int handler(Display *d, XErrorEvent *e) { if (initting && (e->request_code == X_ChangeWindowAttributes) && (e->error_code == BadAccess)) { fprintf(stderr, "%s: Another window manager is already running. Not started.\n", progname); exit(1); } if (ignore_badwindow && (e->error_code == BadWindow || e->error_code == BadColor)) return 0; if ((e->error_code == BadMatch && e->request_code == X_ChangeSaveSet) || (e->error_code == BadWindow && e->request_code == X_ChangeProperty) || (e->error_code == BadWindow && e->request_code == X_GetProperty) || (e->error_code == BadWindow && e->request_code == X_GetWindowAttributes) || (e->error_code == BadWindow && e->request_code == X_ChangeWindowAttributes) || (e->error_code == BadDrawable && e->request_code == X_GetGeometry) || (e->error_code == BadWindow && e->request_code == X_SendEvent)) return 0; XmuPrintDefaultErrorMessage(d, e, stderr); if (initting) { fprintf(stderr, "%s: failure during initialisation; aborting\n", progname); exit(1); } return 0; } static struct coevent { struct coevent *next; struct timeval when; void (*what)(void *); void *with; } *eventlist=NULL; #define FIXUPTV(tv) { \ while((tv).tv_usec<0) { (tv).tv_usec+=1000000; (tv).tv_sec--; } \ while((tv).tv_usec>=1000000) { (tv).tv_usec-=1000000; (tv).tv_sec++; } \ } void remove_call_out(void (*what)(void *), void *with) { struct coevent *ee, **e=&eventlist; while(*e && ((*e)->what != what || (*e)->with != with)) e=&(*e)->next; if((ee=*e)) { *e=(*e)->next; free(ee); } } #ifdef BSD_STYLE_GETTIMEOFDAY #define GETTIMEOFDAY(tp) gettimeofday(tp, NULL) #else #define GETTIMEOFDAY(tp) gettimeofday(tp) #endif void call_out(int howlong_s, int howlong_u, void (*what)(void *), void *with) { struct coevent *ce=malloc(sizeof(struct coevent)); if(ce) { struct coevent **e=&eventlist; GETTIMEOFDAY(&ce->when); ce->when.tv_sec+=howlong_s; ce->when.tv_usec+=howlong_u; FIXUPTV(ce->when); ce->what=what; ce->with=with; while(*e && ((*e)->when.tv_secwhen.tv_sec || ((*e)->when.tv_sec==ce->when.tv_sec && (*e)->when.tv_usec<=ce->when.tv_usec))) e=&(*e)->next; ce->next=*e; *e=ce; } } static void call_call_out() { struct timeval now; struct coevent *e; GETTIMEOFDAY(&now); FIXUPTV(now); while((e=eventlist) && (e->when.tv_secwhen.tv_sec==now.tv_sec && e->when.tv_usec<=now.tv_usec))) { eventlist=e->next; (e->what)(e->with); free(e); } } static void fill_in_call_out(struct timeval *tv) { GETTIMEOFDAY(tv); tv->tv_sec=eventlist->when.tv_sec-tv->tv_sec; tv->tv_usec=eventlist->when.tv_usec-tv->tv_usec; FIXUPTV(*tv); if(tv->tv_sec<0) tv->tv_sec = tv->tv_usec = 0; } void add_fd_to_set(int fd) { FD_SET(fd, &master_fd_set); if(fd>=max_fd) max_fd=fd+1; } void remove_fd_from_set(int fd) { FD_CLR(fd, &master_fd_set); } void lookup_keysyms(Display *dpy, unsigned int *meta_mask, unsigned int *switch_mask) { int i,j,k,maxsym,mincode,maxcode; XModifierKeymap *map=XGetModifierMapping(dpy); KeySym *kp, *kmap; unsigned int alt_mask = 0; *meta_mask=0, *switch_mask=0; XDisplayKeycodes(dpy, &mincode, &maxcode); kmap=XGetKeyboardMapping(dpy, mincode, maxcode-mincode+1, &maxsym); for(i=3; i<8; i++) for(j=0; jmax_keypermod; j++) if(map->modifiermap[i*map->max_keypermod+j] >= mincode) for(kp=kmap+(map->modifiermap[i*map->max_keypermod+j]-mincode)*maxsym, k=0; ktitle=s->deftitle; XClearWindow(dpy, s->menubar); redrawmenubar(s, s->menubar); if(free_screentitle) { free(free_screentitle); free_screentitle=NULL; } } void wberror(Scrn *s, char *message) { remove_call_out((void(*)(void *))restorescreentitle, s); (scr=s)->title=message; XClearWindow(dpy, s->menubar); redrawmenubar(s, s->menubar); XBell(dpy, 100); call_out(2, 0, (void(*)(void *))restorescreentitle, s); } void setfocus(Window w) { if(w == None && prefs.focus != FOC_CLICKTOTYPE) w = PointerRoot; XSetInputFocus(dpy, w, (prefs.focus==FOC_CLICKTOTYPE? RevertToNone:RevertToPointerRoot), CurrentTime); } static void update_clock(void *dontcare); void grab_server() { if(!server_grabs++) XGrabServer(dpy); } void ungrab_server() { if(!--server_grabs) { XUngrabServer(dpy); if(prefs.titlebarclock) { remove_call_out(update_clock, NULL); update_clock(NULL); } } } void drawrubber() { if(rubberclient) XDrawRectangle(dpy, rubberclient->scr->back, rubberclient->scr->rubbergc, rubberx, rubbery, rubberw-1, rubberh-1); else if(boundingwin) { const char dash_list[] = { 6 }; int x=rubberx, y=rubbery, w=rubberw, h=rubberh; if(w<0) { x+=w; w=-w; } if(h<0) { y+=h; h=-h; } if(w>=HYSTERESIS || h>=HYSTERESIS) { XSetDashes(dpy, boundingscr->rubbergc, d_offset, dash_list, sizeof(dash_list)); XSetLineAttributes(dpy, boundingscr->rubbergc, 0, LineOnOffDash, CapButt, JoinMiter); XDrawRectangle(dpy, boundingwin, boundingscr->rubbergc, x, y, w, h); XSetLineAttributes(dpy, boundingscr->rubbergc, 0, LineSolid, CapButt, JoinMiter); } } } static void move_dashes(void *dontcare) { call_out(0, 50000, move_dashes, dontcare); drawrubber(); if((--d_offset)<0) d_offset=11; drawrubber(); } void endrubber() { if(rubberclient) { if((!prefs.opaquemove||dragclient==NULL) && (!prefs.opaqueresize||resizeclient==NULL)) drawrubber(); rubberclient=NULL; } else if(boundingwin) { if((!prefs.opaquemove||dragclient==NULL) && (!prefs.opaqueresize||resizeclient==NULL)) drawrubber(); boundingwin=None; } } void initrubber(int x0, int y0, Client *c) { endrubber(); rubberx=c->x; rubbery=c->y; rubberw=c->pwidth; rubberh=c->pheight; rubberx0=x0; rubbery0=y0; rubberclient=c; } void abortrubber() { if(rubberclient) { endrubber(); dragclient=resizeclient=NULL; ungrab_server(); XUngrabPointer(dpy, CurrentTime); } else if(boundingwin) { endrubber(); boundingwin=None; boundingscr=NULL; ungrab_server(); XUngrabPointer(dpy, CurrentTime); } } void startbounding(Scrn *s, Window w, XEvent *e) { last_icon_click=e->xbutton.time; boundingscr=s; boundingwin=w; XGrabPointer(dpy, w, False, Button1MotionMask|ButtonPressMask| ButtonReleaseMask, GrabModeAsync, GrabModeAsync, s->back, None, CurrentTime); grab_server(); rubberx=e->xbutton.x; rubbery=e->xbutton.y; rubberx0=e->xbutton.x_root; rubbery0=e->xbutton.y_root; rubberw=0; rubberh=0; drawrubber(); call_out(0, 0, move_dashes, NULL); } void endbounding(XEvent *e) { Icon *i; int bx, by; Window cc; if(boundingscr) { remove_call_out(move_dashes, NULL); endrubber(); if(!(e->xbutton.state & ShiftMask)) deselect_all_icons(boundingscr); if(rubberw<0) { rubberx+=rubberw; rubberw=-rubberw; } if(rubberh<0) { rubbery+=rubberh; rubberh=-rubberh; } if(rubberw>=HYSTERESIS || rubberh>=HYSTERESIS) for(i=boundingscr->icons; i; i=i->next) if(i->window && i->mapped && XTranslateCoordinates(dpy, i->parent, scr->back, i->x, i->y, &bx, &by, &cc) && bxwidth>rubberx && by+i->height>rubbery) selecticon(i); boundingscr=NULL; ungrab_server(); XUngrabPointer(dpy, CurrentTime); } } void startdragging(Client *c, XEvent *e) { scr=c->scr; dragclient=c; XGrabPointer(dpy, c->drag, False, Button1MotionMask|ButtonPressMask| ButtonReleaseMask, GrabModeAsync, GrabModeAsync, scr->back, None, CurrentTime); if(!prefs.opaquemove) grab_server(); initrubber(e->xbutton.x_root, e->xbutton.y_root, c); rubberx0-=rubberx; rubbery0-=rubbery; if(!forcemoving) { if(rubberx+rubberw>scr->width) rubberx=scr->width-rubberw; if(rubbery+rubberh>scr->height) rubbery=scr->height-rubberh; if(rubberx<0) rubberx=0; if(rubbery<0) rubbery=0; } if(!prefs.opaquemove) drawrubber(); } void startscreendragging(Scrn *s, XEvent *e) { dragscreen=s; XGrabPointer(dpy, s->menubar, False, Button1MotionMask|ButtonPressMask| ButtonReleaseMask, GrabModeAsync, GrabModeAsync, s->root, None, CurrentTime); olddragy=rubbery=s->y; rubbery0=e->xbutton.y_root-rubbery; } void endscreendragging() { Scrn *s; if((s=dragscreen)) { #ifndef ASSIMILATE_WINDOWS scrsendconfig(dragscreen); #endif dragscreen=NULL; XUngrabPointer(dpy, CurrentTime); } } void abortscreendragging() { if(dragscreen) { XMoveWindow(dpy, dragscreen->back, -dragscreen->bw, (dragscreen->y=olddragy)-dragscreen->bw); endscreendragging(); } } void aborticondragging() { if(numdragicons) { int i; for(i=0; iscr, "Icon can't be moved into this window"); aborticondragging(); } void endicondragging(XEvent *e) { int i; Client *c; int wx, wy; Window ch; scr=get_front_scr(); for(;;) { if(scr->root == e->xbutton.root && e->xbutton.y_root>=scr->y) break; if((scr=scr->behind)==get_front_scr()) { badicondrop(); return; } } if (!scr->deftitle) { badicondrop(); return; } if(XTranslateCoordinates(dpy, scr->root, scr->back, e->xbutton.x_root, e->xbutton.y_root, &wx, &wy, &ch) && ch!=None) { if(XFindContext(dpy, ch, client_context, (XPointer*)&c) || c->scr != scr || c->state != NormalState) c = NULL; } else c = NULL; if(c) { if(c->module) { extern Atom amiwm_appwindowmsg; XTranslateCoordinates(dpy, scr->back, c->window, -4, -4, &wx, &wy, &ch); for(i=0; iwindow, amiwm_appwindowmsg, dragiconlist[i].icon->window); e->xclient.data.l[2] = dragiconlist[i].x+wx; e->xclient.data.l[3] = dragiconlist[i].y+wy; dispatch_event_to_broker(e, 0, c->module); } aborticondragging(); } else badicondrop(); return; } for(i=0; imapped=0; for(i=0; iscr!=scr) reparenticon(dragiconlist[i].icon, scr, dragiconlist[i].x-4, dragiconlist[i].y-4-scr->y); else XMoveWindow(dpy, dragiconlist[i].icon->window, dragiconlist[i].icon->x = dragiconlist[i].x-4, dragiconlist[i].icon->y = dragiconlist[i].y-4-scr->y); dragiconlist[i].icon->mapped=1; adjusticon(dragiconlist[i].icon); } aborticondragging(); } void starticondragging(Scrn *scr, XEvent *e) { XWindowAttributes xwa; XSetWindowAttributes xswa; Icon *i; Window ww; aborticondragging(); for(i=scr->firstselected; i; i=i->nextselected) numdragicons++; if(!numdragicons) return; if(!(dragiconlist=calloc(numdragicons, sizeof(DragIcon)))) { numdragicons=0; XBell(dpy, 100); return; } for(numdragicons=0, i=scr->firstselected; i; i=i->nextselected) { dragiconlist[numdragicons].icon = i; XGetWindowAttributes(dpy, i->window, &xwa); if(i->parent!=scr->back) XTranslateCoordinates(dpy, i->parent, scr->back, xwa.x, xwa.y, &xwa.x, &xwa.y, &ww); dragiconlist[numdragicons].x = xwa.x+4; dragiconlist[numdragicons].y = xwa.y+4+scr->y; xswa.save_under=True; xswa.override_redirect=True; if(i->innerwin) { XGetWindowAttributes(dpy, i->innerwin, &xwa); xswa.background_pixmap = dragiconlist[numdragicons].pm = XCreatePixmap(dpy, i->innerwin, xwa.width, xwa.height, xwa.depth); XCopyArea(dpy, i->innerwin, dragiconlist[numdragicons].pm, scr->gc, 0, 0, xwa.width, xwa.height, 0, 0); } else { if(i->secondpm) { xswa.background_pixmap = i->secondpm; XGetGeometry(dpy, i->secondpm, &xwa.root, &xwa.x, &xwa.y, (unsigned int *)&xwa.width, (unsigned int *)&xwa.height, (unsigned int *)&xwa.border_width, (unsigned int *)&xwa.depth); } else if(i->iconpm) { xswa.background_pixmap = i->iconpm; XGetGeometry(dpy, i->iconpm, &xwa.root, &xwa.x, &xwa.y, (unsigned int *)&xwa.width, (unsigned int *)&xwa.height, (unsigned int *)&xwa.border_width, (unsigned int *)&xwa.depth); } if(xwa.depth!=scr->depth) { dragiconlist[numdragicons].pm = XCreatePixmap(dpy, i->window, xwa.width, xwa.height, scr->depth); XSetForeground(dpy, scr->gc, scr->dri.dri_Pens[SHADOWPEN]); XSetBackground(dpy, scr->gc, scr->dri.dri_Pens[BACKGROUNDPEN]); XCopyPlane(dpy, xswa.background_pixmap, dragiconlist[numdragicons].pm, scr->gc, 0, 0, xwa.width, xwa.height, 0, 0, 1); xswa.background_pixmap = dragiconlist[numdragicons].pm; xwa.depth = scr->depth; } } xswa.colormap=xwa.colormap; dragiconlist[numdragicons].w = XCreateWindow(dpy, scr->root, dragiconlist[numdragicons].x, dragiconlist[numdragicons].y, xwa.width, xwa.height, 0, xwa.depth, xwa.class, xwa.visual, CWBackPixmap|CWOverrideRedirect|CWSaveUnder|CWColormap, &xswa); #ifdef HAVE_XSHAPE if(shape_extn) { if(i->innerwin) { int bShaped, xbs, ybs, cShaped, xcs, ycs; unsigned int wbs, hbs, wcs, hcs; XShapeQueryExtents(dpy, i->innerwin, &bShaped, &xbs, &ybs, &wbs, &hbs, &cShaped, &xcs, &ycs, &wcs, &hcs); if(bShaped) XShapeCombineShape(dpy, dragiconlist[numdragicons].w, ShapeBounding, 0, 0, i->innerwin, ShapeBounding, ShapeSet); } else if(i->maskpm) { XShapeCombineMask(dpy, dragiconlist[numdragicons].w, ShapeBounding, 0, 0, i->maskpm, ShapeSet); } } #endif XMapRaised(dpy, dragiconlist[numdragicons].w); numdragicons++; } XGrabPointer(dpy, scr->back, False, Button1MotionMask|ButtonPressMask| ButtonReleaseMask, GrabModeAsync, GrabModeAsync, scr->root, None, CurrentTime); olddragx = rubberx0 = e->xbutton.x_root; olddragy = rubbery0 = e->xbutton.y_root; } void enddragging() { if(dragclient) { Client *c=dragclient; endrubber(); if(rubbery<=-(c->scr->bh)) rubbery=1-(c->scr->bh); XMoveWindow(dpy, c->parent, c->x=rubberx, c->y=rubbery); dragclient=NULL; if(!prefs.opaquemove) ungrab_server(); XUngrabPointer(dpy, CurrentTime); sendconfig(c); } } void do_icon_double_click(Scrn *scr) { extern Atom amiwm_appiconmsg; Icon *i, *next; Client *c; for(i=scr->firstselected; i; i=next) { next=i->nextselected; if(i->module) { dispatch_event_to_broker(mkcmessage(i->window, amiwm_appiconmsg, 0), 0, i->module); } else { if(i->labelwin) XUnmapWindow(dpy, i->labelwin); if(i->window) XUnmapWindow(dpy, i->window); i->mapped=0; deselecticon(i); if((c=(i->client))) { XMapWindow(dpy, c->window); if(c->parent!=c->scr->root && !c->fullscreen) XMapRaised(dpy, c->parent); setclientstate(c, NormalState); } } } } void startresizing(Client *c, XEvent *e) { resizeclient=c; XGrabPointer(dpy, c->resize, False, Button1MotionMask|ButtonPressMask| ButtonReleaseMask, GrabModeAsync, GrabModeAsync, c->scr->back, None, CurrentTime); if(!prefs.opaqueresize) grab_server(); initrubber(e->xbutton.x_root, e->xbutton.y_root, c); rubberx0-=rubberw; rubbery0-=rubberh; if(!prefs.opaqueresize) drawrubber(); } void endresizing() { extern void resizeclientwindow(Client *c, int, int); if(resizeclient) { Client *c=resizeclient; endrubber(); if(!prefs.opaqueresize) ungrab_server(); resizeclientwindow(c, rubberw, rubberh); resizeclient=NULL; XUngrabPointer(dpy, CurrentTime); } } void abortfocus() { if(activeclient) { activeclient->active=False; redrawclient(activeclient); if(prefs.focus==FOC_CLICKTOTYPE) XGrabButton(dpy, Button1, AnyModifier, activeclient->parent, True, ButtonPressMask, GrabModeSync, GrabModeAsync, None, wm_curs); activeclient = NULL; } setfocus(None); } RETSIGTYPE sighandler(int sig) { signalled=1; signal(sig, SIG_IGN); } static void instcmap(Colormap c) { XInstallColormap(dpy, (c == None) ? scr->cmap : c); } void internal_broker(XEvent *e) { /* * XXX this is one of the things that the code in module.c * is abusing to overload display with some numeric * values. Surely there's a better way to do this? */ uintptr_t event_loc=(uintptr_t)e->xany.display; e->xany.display=dpy; if(event_loc==1) { XSendEvent(dpy, e->xany.window, False, 0, e); } else switch(e->type) { case MappingNotify: if(e->xmapping.request==MappingKeyboard || e->xmapping.request==MappingModifier) XRefreshKeyboardMapping(&e->xmapping); lookup_keysyms(dpy, &meta_mask, &switch_mask); break; case KeyPress: if(e->xkey.state & meta_mask) { KeySym ks=XLookupKeysym(&e->xkey, ((e->xkey.state & ShiftMask)?1:0)+ ((e->xkey.state & switch_mask)?2:0)); void *item; if((item=getitembyhotkey(ks))) menuaction(item); } break; } } static void update_clock(void *dontcare) { Scrn *scr; if(server_grabs) return; call_out(prefs.titleclockinterval, 0, update_clock, dontcare); scr = get_front_scr(); do { redrawmenubar(scr, scr->menubar); scr=scr->behind; } while(scr != get_front_scr()); } void cleanup() { extern void free_prefs(); struct coevent *e; flushmodules(); flushclients(); scr = get_front_scr(); while(scr) closescreen(); free_prefs(); if(dpy) { XSetInputFocus(dpy, PointerRoot, RevertToPointerRoot, CurrentTime); XFlush(dpy); XCloseDisplay(dpy); } while((e = eventlist)) { eventlist = e->next; free(e); } if(x_server) free(x_server); } int main(int argc, char *argv[]) { int x_fd, sc; static Argtype array[3]; struct RDArgs *ra; #ifdef USE_FONTSETS setlocale(LC_CTYPE, ""); setlocale(LC_TIME, ""); #endif main_argv=argv; progname=argv[0]; atexit(cleanup); memset(array, 0, sizeof(array)); initargs(argc, argv); if(!(ra=ReadArgs((UBYTE *)"RCFILE,DISPLAY/K,SINGLE/S", (LONG *)array, NULL))) { PrintFault(IoErr(), (UBYTE *)progname); exit(1); } x_server = strdup(XDisplayName(array[1].ptr)); XrmInitialize(); if(!(dpy = XOpenDisplay(array[1].ptr))) { fprintf(stderr, "%s: cannot connect to X server %s\n", progname, x_server); FreeArgs(ra); exit(1); } if(array[1].ptr) { char *env=malloc(strlen((char *)array[1].ptr)+10); sprintf(env, "DISPLAY=%s", (char *)array[1].ptr); putenv(env); } client_context = XUniqueContext(); screen_context = XUniqueContext(); icon_context = XUniqueContext(); menu_context = XUniqueContext(); vroot_context = XUniqueContext(); wm_curs=XCreateFontCursor(dpy, XC_top_left_arrow); FD_ZERO(&master_fd_set); x_fd=ConnectionNumber(dpy); FD_SET(x_fd, &master_fd_set); max_fd=x_fd+1; initting = 1; XSetErrorHandler(handler); #ifdef HAVE_XSHAPE if(XShapeQueryExtension(dpy, &shape_event_base, &shape_error_base)) shape_extn = 1; #endif XSelectInput(dpy, DefaultRootWindow(dpy), SubstructureRedirectMask); XSync(dpy, False); XSelectInput(dpy, DefaultRootWindow(dpy), NoEventMask); init_modules(); read_rc_file(array[0].ptr, !array[2].num); if( prefs.titleclockinterval < 1 ) prefs.titleclockinterval = 1; FreeArgs(ra); if (signal(SIGTERM, sighandler) == SIG_IGN) signal(SIGTERM, SIG_IGN); if (signal(SIGINT, sighandler) == SIG_IGN) signal(SIGINT, SIG_IGN); #ifdef SIGHUP if (signal(SIGHUP, sighandler) == SIG_IGN) signal(SIGHUP, SIG_IGN); #endif init_atoms(); #ifndef AMIGAOS if((fcntl(ConnectionNumber(dpy), F_SETFD, 1)) == -1) fprintf(stderr, "%s: child cannot disinherit TCP fd\n", progname); #endif lookup_keysyms(dpy, &meta_mask, &switch_mask); for(sc=0; sc0) { Client *c; Icon *i; int motionx, motiony; XNextEvent(dpy, &event); if(!XFindContext(dpy, event.xany.window, client_context, (XPointer*)&c)) { scr=c->scr; } else { c = NULL; if(XFindContext(dpy, event.xany.window, screen_context, (XPointer*)&scr)) scr = get_front_scr(); } if(XFindContext(dpy, event.xany.window, icon_context, (XPointer*)&i)) i=NULL; else scr=i->scr; switch(event.type) { case Expose: if(!event.xexpose.count) { if((rubberclient || boundingscr)&&!prefs.opaquemove &&!prefs.opaqueresize) drawrubber(); if(c) redraw(c, event.xexpose.window); else if(i) redrawicon(i, event.xexpose.window); else if(scr) redrawmenubar(scr, event.xexpose.window); if((rubberclient || boundingscr)&&!prefs.opaquemove) drawrubber(); } break; case CreateNotify: if(!XFindContext(dpy, event.xcreatewindow.window, client_context, (XPointer *)&c)) { break; } if(!event.xcreatewindow.override_redirect) { if(!(scr=getscreenbyroot(event.xcreatewindow.parent))) scr = get_front_scr(); createclient(event.xcreatewindow.window); } #ifdef ASSIMILATE_WINDOWS else if(XFindContext(dpy, event.xcreatewindow.window, screen_context, (XPointer*)&scr) && (scr=getscreenbyroot(event.xcreatewindow.parent))) { XGetWindowAttributes(dpy, event.xcreatewindow.window, &attr); assimilate(event.xcreatewindow.window, attr.x, attr.y); } #endif break; case DestroyNotify: if(!XFindContext(dpy, event.xdestroywindow.window, client_context, (XPointer*)&c)) { ignore_badwindow = 1; rmclient(c); XSync(dpy, False); ignore_badwindow = 0; } else if(!XFindContext(dpy, event.xdestroywindow.window, icon_context, (XPointer*)&i)) { ignore_badwindow = 1; if(i->client) i->client->icon=NULL; rmicon(i); XSync(dpy, False); ignore_badwindow = 0; } else if(event.xdestroywindow.window) XDeleteContext(dpy, event.xdestroywindow.window, screen_context); break; case UnmapNotify: if(c && c->active && (event.xunmap.window==c->parent) && !(c->fullscreen && c->state == NormalState)) { c->active=False; activeclient = NULL; redrawclient(c); if(prefs.focus == FOC_CLICKTOTYPE) XGrabButton(dpy, Button1, AnyModifier, c->parent, True, ButtonPressMask, GrabModeSync, GrabModeAsync, None, wm_curs); if(!menuactive) setfocus(None); } if(c && (event.xunmap.window==c->window)) { if((!c->reparenting) && c->parent != c->scr->root) { Icon *i=c->icon; XUnmapWindow(dpy, c->parent); if(i) { if(i->labelwin) XUnmapWindow(dpy, i->labelwin); if(i->window) XUnmapWindow(dpy, i->window); i->mapped=0; deselecticon(i); } setclientstate(c, WithdrawnState); } c->reparenting = 0; } break; case ConfigureNotify: if((!XFindContext(dpy, event.xconfigure.window, icon_context, (XPointer *)&i)) && event.xconfigure.window == i->window){ i->x=event.xconfigure.x; i->y=event.xconfigure.y; i->width=event.xconfigure.width; i->height=event.xconfigure.height; if(i->labelwin) { XWindowChanges xwc; xwc.x=i->x+(i->width>>1)-(i->labelwidth>>1); xwc.y=i->y+i->height+1; xwc.sibling=i->window; xwc.stack_mode=Below; XConfigureWindow(dpy, i->labelwin, CWX|CWY|CWSibling|CWStackMode, &xwc); } } break; case ReparentNotify: if((!XFindContext(dpy, event.xreparent.window, icon_context, (XPointer *)&i)) && event.xreparent.window == i->window){ i->parent=event.xreparent.parent; i->x=event.xreparent.x; i->y=event.xreparent.y; if(i->labelwin) { XWindowChanges xwc; XReparentWindow(dpy, i->labelwin, i->parent, i->x+(i->width>>1)-(i->labelwidth>>1), i->y+i->height+1); xwc.sibling=i->window; xwc.stack_mode=Below; XConfigureWindow(dpy, i->labelwin, CWSibling|CWStackMode, &xwc); } } break; case CirculateNotify: case GravityNotify: case NoExpose: case GraphicsExpose: break; case ClientMessage: if(c) handle_client_message(c, &event.xclient); break; case ColormapNotify: if(event.xcolormap.new && c) if(c->colormap!=event.xcolormap.colormap) { c->colormap=event.xcolormap.colormap; if(c->active) instcmap(c->colormap); } break; case ConfigureRequest: if(XFindContext(dpy, event.xconfigurerequest.window, client_context, (XPointer*)&c)) c = NULL; if(c && event.xconfigurerequest.window==c->window && c->parent!=c->scr->root) { extern void resizeclientwindow(Client *c, int, int); if(event.xconfigurerequest.value_mask&CWBorderWidth) c->old_bw=event.xconfigurerequest.border_width; resizeclientwindow(c, (event.xconfigurerequest.value_mask&CWWidth)? event.xconfigurerequest.width+c->framewidth:c->pwidth, (event.xconfigurerequest.value_mask&CWHeight)? event.xconfigurerequest.height+c->frameheight:c->pheight); if((event.xconfigurerequest.value_mask&(CWX|CWY)) && c->state==WithdrawnState) XMoveWindow(dpy, c->parent, c->x=((event.xconfigurerequest.value_mask&CWX)? event.xconfigurerequest.x:c->x), c->y=((event.xconfigurerequest.value_mask&CWY)? event.xconfigurerequest.y:c->y)); } else { if(!XFindContext(dpy, event.xconfigurerequest.window, screen_context, (XPointer *)&scr)) if((event.xconfigurerequest.y-=scr->y)<0) event.xconfigurerequest.y=0; XConfigureWindow(dpy, event.xconfigurerequest.window, event.xconfigurerequest.value_mask, (XWindowChanges *)&event.xconfigurerequest.x); } break; case CirculateRequest: if(XFindContext(dpy, event.xcirculaterequest.window, client_context, (XPointer*)&c)) if(event.xcirculaterequest.place==PlaceOnTop) XRaiseWindow(dpy, event.xcirculaterequest.window); else { Client *c2; Window r,p,*children; unsigned int nchildren; if(XQueryTree(dpy, scr->back, &r, &p, &children, &nchildren)) { int n; for(n=0; nparent) break; if(nparent==c->scr->root && (xwmh=XGetWMHints(dpy, c->window))) { if(c->state==WithdrawnState && (xwmh->flags&StateHint) && xwmh->initial_state==IconicState) c->state=IconicState; XFree(xwmh); } switch(c->state) { case WithdrawnState: if(c->parent == c->scr->root) reparent(c); case NormalState: XMapWindow(dpy, c->window); if (!c->fullscreen) XMapRaised(dpy, c->parent); setclientstate(c, NormalState); break; case IconicState: if(c->parent == c->scr->root) reparent(c); if(!(c->icon)) createicon(c); adjusticon(c->icon); XMapWindow(dpy, c->icon->window); if(c->icon->labelwidth) XMapWindow(dpy, c->icon->labelwin); c->icon->mapped=1; setclientstate(c, IconicState); break; } } break; case MapNotify: if(prefs.focus == FOC_CLICKTOTYPE && c && event.xmap.window == c->parent && c->parent != c->scr->root && (!c->active)) { if(activeclient) { XGrabButton(dpy, Button1, AnyModifier, activeclient->parent, True, ButtonPressMask, GrabModeSync, GrabModeAsync, None, wm_curs); activeclient->active=False; redrawclient(activeclient); } c->active=True; activeclient = c; XUngrabButton(dpy, Button1, AnyModifier, c->parent); redrawclient(c); setfocus(c->window); } break; case EnterNotify: if(menuactive) { scr=menuactive; menubar_enter(event.xcrossing.window); } else if(clickwindow && event.xcrossing.window == clickwindow) clickenter(); else if(c) { if((!c->active) && (c->state==NormalState) && prefs.focus!=FOC_CLICKTOTYPE) { if(activeclient) { activeclient->active=False; redrawclient(activeclient); } setfocus(c->window); c->active=True; activeclient = c; redrawclient(c); if(prefs.autoraise && c->parent!=c->scr->root) XRaiseWindow(dpy, c->parent); } if(event.xcrossing.window==c->window) instcmap(c->colormap); } break; case LeaveNotify: if(menuactive) { scr=menuactive; menubar_leave(event.xcrossing.window); } else if(clickwindow && event.xcrossing.window == clickwindow) clickleave(); else if(c) { if(c->active && event.xcrossing.window==c->parent && event.xcrossing.detail!=NotifyInferior && prefs.focus == FOC_FOLLOWMOUSE) { if(!menuactive) setfocus(None); c->active=False; activeclient = NULL; instcmap(None); redrawclient(c); } else if(event.xcrossing.window==c->window && event.xcrossing.detail!=NotifyInferior && event.xcrossing.mode==NotifyNormal) instcmap(None); } break; case ButtonPress: if(!rubberclient && !boundingscr && clickwindow==None && !dragiconlist && event.xbutton.button==Button1 && !dragscreen && !menuactive) if(c) { if((!c->active) && prefs.focus==FOC_CLICKTOTYPE && (c->state==NormalState)) { if(activeclient) { activeclient->active=False; redrawclient(activeclient); XGrabButton(dpy, Button1, AnyModifier, activeclient->parent, True, ButtonPressMask, GrabModeSync, GrabModeAsync, None, wm_curs); } setfocus(c->window); c->active=True; activeclient = c; redrawclient(c); XUngrabButton(dpy, Button1, AnyModifier, c->parent); if(prefs.autoraise && c->parent!=c->scr->root) XRaiseWindow(dpy, c->parent); } if(event.xbutton.window!=c->depth && event.xbutton.window!=c->window) { if(c==doubleclient && (event.xbutton.time-last_double)< dblClickTime) { XRaiseWindow(dpy, c->parent); } else { doubleclient=c; last_double=event.xbutton.time; } } if(event.xbutton.window==c->drag) { forcemoving=(prefs.forcemove==FM_ALWAYS) || (event.xbutton.state & ShiftMask); startdragging(c, &event); } else if(event.xbutton.window==c->resize) startresizing(c, &event); else if(event.xbutton.window==c->window || event.xbutton.window==c->parent) ; else gadgetclicked(c, event.xbutton.window, &event); } else if(i && event.xbutton.window==i->window) { abortfocus(); if(i->selected && (event.xbutton.time-last_icon_click)scr); } else { if(!(event.xbutton.state & ShiftMask)) deselect_all_icons(i->scr); last_icon_click=event.xbutton.time; selecticon(i); starticondragging(i->scr, &event); } } else if(scr&&event.xbutton.window==scr->menubardepth) { clickwindow=scr->menubardepth; mbdclick=mbdscr=scr; redrawmenubar(scr, scr->menubardepth); } else if(scr&&event.xbutton.window==scr->menubar && scr->back!=scr->root) { startscreendragging(scr, &event); } else if(scr&&scr->back==event.xbutton.window) { abortfocus(); startbounding(scr, scr->back, &event); } else ; else if(event.xbutton.button==3) { if(rubberclient || boundingscr) abortrubber(); else if(scr&&(scr==mbdscr)&&clickwindow==scr->menubardepth) { mbdclick=NULL; clickwindow=None; redrawmenubar(scr, scr->menubardepth); } else if(clickclient) gadgetaborted(clickclient); else if(dragiconlist) aborticondragging(); else if(dragscreen) abortscreendragging(); else if(scr&&!menuactive) { menu_on(); menuactive=scr; } } if(prefs.focus == FOC_CLICKTOTYPE && !menuactive) { XSync(dpy,0); XAllowEvents(dpy,ReplayPointer,CurrentTime); XSync(dpy,0); } break; case ButtonRelease: if(event.xbutton.button==Button1) { if(rubberclient) { if(dragclient) enddragging(); else if(resizeclient) endresizing(); } else if(boundingwin) endbounding(&event); else if(clickclient) gadgetunclicked(clickclient, &event); else if(dragiconlist) { endicondragging(&event); } else if(dragscreen) endscreendragging(); else if((scr=mbdscr)&& clickwindow==scr->menubardepth) { if(mbdclick) { mbdclick=NULL; redrawmenubar(scr, scr->menubardepth); screentoback(); } clickwindow=None; } } else if(event.xbutton.button==Button3 && (scr=menuactive)) { menu_off(); menuactive=NULL; } break; case MotionNotify: do { motionx=event.xmotion.x_root; motiony=event.xmotion.y_root; } while(XCheckTypedEvent(dpy, MotionNotify, &event)); if(dragclient) { scr=dragclient->scr; if(!prefs.opaquemove) drawrubber(); rubberx=motionx-rubberx0; rubbery=motiony-rubbery0; if(!forcemoving) { if(prefs.forcemove==FM_AUTO && (rubberx+rubberw-scr->width>(rubberw>>2) || rubbery+rubberh-scr->height>(rubberh>>2) || -rubberx>(rubberw>>2)|| -rubbery>(rubberh>>2))) forcemoving=1; else { if(rubberx+rubberw>scr->width) rubberx=scr->width-rubberw; if(rubbery+rubberh>scr->height) rubbery=scr->height-rubberh; if(rubberx<0) rubberx=0; if(rubbery<0) rubbery=0; } } if(prefs.opaquemove) { if(rubbery<=-(c->scr->bh)) rubbery=1-(c->scr->bh); XMoveWindow(dpy, c->parent, c->x=rubberx, c->y=rubbery); } else { drawrubber(); } } else if(resizeclient) { int rw=rubberw, rh=rubberh; scr=resizeclient->scr; if(resizeclient->sizehints->width_inc) { rw=motionx-rubberx0-resizeclient->sizehints->base_width- resizeclient->framewidth; rw-=rw%resizeclient->sizehints->width_inc; rw+=resizeclient->sizehints->base_width; if(rw>resizeclient->sizehints->max_width) rw=resizeclient->sizehints->max_width; if(rwsizehints->min_width) rw=resizeclient->sizehints->min_width; rw+=resizeclient->framewidth; } if(resizeclient->sizehints->height_inc) { rh=motiony-rubbery0-resizeclient->sizehints->base_height- resizeclient->frameheight; rh-=rh%resizeclient->sizehints->height_inc; rh+=resizeclient->sizehints->base_height; if(rh>resizeclient->sizehints->max_height) rh=resizeclient->sizehints->max_height; if(rhsizehints->min_height) rh=resizeclient->sizehints->min_height; rh+=resizeclient->frameheight; } if(rw!=rubberw || rh!=rubberh) { if(prefs.opaqueresize) { Client *c = resizeclient; extern void resizeclientwindow(Client *c, int, int); rubberw=rw; rubberh=rh; resizeclientwindow(c, rubberw, rubberh); } else { drawrubber(); rubberw=rw; rubberh=rh; drawrubber(); } } } else if(dragiconlist) { int i; for(i=0; i=dragscreen->height) rubbery=dragscreen->height-1; XMoveWindow(dpy, dragscreen->back, -dragscreen->bw, (dragscreen->y=rubbery)-dragscreen->bw); } else if(boundingscr) { drawrubber(); rubberw=motionx-rubberx0; rubberh=motiony-rubbery0; drawrubber(); } break; case KeyPress: if(!dispatch_event_to_broker(&event, KeyPressMask, modules)) internal_broker(&event); break; case KeyRelease: if(!dispatch_event_to_broker(&event, KeyPressMask, modules)) internal_broker(&event); break; case MappingNotify: if(!dispatch_event_to_broker(&event, 0, modules)) internal_broker(&event); break; case PropertyNotify: if(event.xproperty.atom != None && c && event.xproperty.window==c->window && XGetGeometry(dpy, c->window, &dummy_root, &dummy_x, &dummy_y, &dummy_w, &dummy_h, &dummy_bw, &dummy_d)) propertychange(c, event.xproperty.atom); break; case FocusOut: /* Ignore */ break; case FocusIn: if(event.xfocus.detail == NotifyDetailNone && prefs.focus == FOC_CLICKTOTYPE && (scr = getscreenbyroot(event.xfocus.window))) { Window w; int rt; XGetInputFocus(dpy, &w, &rt); if(w == None) setfocus(scr->inputbox); } break; default: #ifdef HAVE_XSHAPE if(shape_extn && event.type == shape_event_base + ShapeNotify) { XShapeEvent *s = (XShapeEvent *) &event; if(c && s->kind == ShapeBounding) { c->shaped = s->shaped; reshape_frame(c); } break; } #endif fprintf(stderr, "%s: got unexpected event type %d.\n", progname, event.type); } } if(signalled) break; rfds = master_fd_set; t.tv_sec = t.tv_usec = 0; if (select(max_fd, &rfds, NULL, NULL, &t) > 0) { handle_module_input(&rfds); if(FD_ISSET(x_fd, &rfds)) XPeekEvent(dpy, &event); continue; } if(signalled) break; XFlush(dpy); rfds = master_fd_set; if(eventlist) fill_in_call_out(&t); if(select(max_fd, &rfds, NULL, NULL, (eventlist? &t:NULL))<0) { if (errno != EINTR) { perror("select"); break; } } else { call_call_out(); handle_module_input(&rfds); if(FD_ISSET(x_fd, &rfds)) XPeekEvent(dpy, &event); } } if(prefs.titlebarclock) remove_call_out(update_clock, NULL); if(signalled) fprintf(stderr, "%s: exiting on signal\n", progname); exit(signalled? 0:1); }