/* * Copyright (c) 2019 Derek Stevens, 2005 Rus Cox, 1994-1996 David Hogan * see README for licence details */ #include #include #include #include #include #include #include #include #include #include "dat.h" #include "fns.h" #include "patchlevel.h" #include "config.h" void mainloop(int shape_event) { XEvent ev; for(;;){ getevent(&ev); #ifdef DEBUG_EV if(debug){ ShowEvent(&ev); printf("\n"); } #endif switch (ev.type){ default: #ifdef SHAPE if(shape && ev.type == shape_event) shapenotify((XShapeEvent *)&ev); else #endif fprintf(stderr, "ryudo: unknown ev.type %d\n", ev.type); break; case KeyPress: keypress(&ev.xkey); break; case KeyRelease: keyrelease(&ev.xkey); break; case ButtonPress: button(&ev.xbutton); break; case ButtonRelease: break; case MapRequest: mapreq(&ev.xmaprequest); break; case ConfigureRequest: configurereq(&ev.xconfigurerequest); break; case CirculateRequest: circulatereq(&ev.xcirculaterequest); break; case UnmapNotify: unmap(&ev.xunmap); break; case CreateNotify: newwindow(&ev.xcreatewindow); break; case DestroyNotify: destroy(ev.xdestroywindow.window); break; case ClientMessage: clientmesg(&ev.xclient); break; case ColormapNotify: cmap(&ev.xcolormap); break; case PropertyNotify: property(&ev.xproperty); break; case SelectionClear: fprintf(stderr, "ryudo: SelectionClear (this should not happen)\n"); break; case SelectionNotify: fprintf(stderr, "ryudo: SelectionNotify (this should not happen)\n"); break; case SelectionRequest: fprintf(stderr, "ryudo: SelectionRequest (this should not happen)\n"); break; case EnterNotify: enter(&ev.xcrossing); break; case LeaveNotify: leave(&ev.xcrossing); break; case ReparentNotify: reparent(&ev.xreparent); break; case FocusIn: focusin(&ev.xfocus); break; case MotionNotify: motionnotify(&ev.xmotion); break; case Expose: case NoExpose: case FocusOut: case ConfigureNotify: case MapNotify: case MappingNotify: case GraphicsExpose: /* not interested */ trace("ignore", 0, &ev); break; } } } void configurereq(XConfigureRequestEvent *e) { XWindowChanges wc; Client *c; /* we don't set curtime as nothing here uses it */ c = getclient(e->window, 0); trace("configurereq", c, e); e->value_mask &= ~CWSibling; if(c){ if(e->value_mask & CWX) c->x = e->x; if(e->value_mask & CWY) c->y = e->y; if(e->value_mask & CWWidth) c->dx = e->width; if(e->value_mask & CWHeight) c->dy = e->height; if(e->value_mask & CWBorderWidth) c->border = e->border_width; if(c->dx >= c->screen->width && c->dy >= c->screen->height) c->border = 0; else c->border = BORDER; if(e->value_mask & CWStackMode){ if(e->detail == Above) top(c); else e->value_mask &= ~CWStackMode; } e->value_mask |= CWX|CWY|CWHeight|CWWidth; if(c->parent != c->screen->root && c->window == e->window){ wc.x = c->x - c->border; wc.y = c->y - c->border; wc.width = c->dx+c->border+c->border; wc.height = c->dy+c->border+c->border; wc.border_width = 1; wc.sibling = None; wc.stack_mode = e->detail; XConfigureWindow(dpy, c->parent, e->value_mask, &wc); if(e->value_mask & CWStackMode){ top(c); active(c); } } } if(c && c->parent != c->screen->root){ wc.x = c->border; wc.y = c->border; }else { wc.x = c->x; wc.y = c->y; } wc.width = c->dx; wc.height = c->dy; wc.border_width = 0; wc.sibling = None; wc.stack_mode = Above; e->value_mask &= ~CWStackMode; e->value_mask |= CWBorderWidth; XConfigureWindow(dpy, c->window, e->value_mask, &wc); } void mapreq(XMapRequestEvent *e) { Client *c; int i; curtime = CurrentTime; c = getclient(e->window, 0); trace("mapreq", c, e); if(c == 0 || c->window != e->window){ /* workaround for stupid NCDware */ fprintf(stderr, "ryudo: bad mapreq c %p w %x, rescanning\n", (void*)c, (int)e->window); for(i = 0; i < num_screens; i++) scanwins(&screens[i]); c = getclient(e->window, 0); if(c == 0 || c->window != e->window){ fprintf(stderr, "ryudo: window not found after rescan\n"); return; } } switch (c->state){ case WithdrawnState: if(c->parent == c->screen->root){ if(!manage(c, 0)) return; break; } XReparentWindow(dpy, c->window, c->parent, BORDER-1, BORDER-1); XAddToSaveSet(dpy, c->window); /* fall through... */ case NormalState: XMapWindow(dpy, c->window); XMapRaised(dpy, c->parent); top(c); setstate(c, NormalState); if(c->trans != None && current && c->trans == current->window) active(c); break; case IconicState: unhidec(c, 1); break; } } void unmap(XUnmapEvent *e) { Client *c; curtime = CurrentTime; c = getclient(e->window, 0); if(c){ switch (c->state){ case IconicState: if(e->send_event){ unhidec(c, 0); withdraw(c); } break; case NormalState: if(c == current) nofocus(); if(!c->reparenting) withdraw(c); break; } c->reparenting = 0; } } void circulatereq(XCirculateRequestEvent *e) { fprintf(stderr, "It must be the warlock Krill!\n"); /* ☺ */ } void newwindow(XCreateWindowEvent *e) { Client *c; ScreenInfo *s; static XWindowAttributes ra; XGetWindowAttributes(dpy, DefaultRootWindow(dpy), &ra); /* we don't set curtime as nothing here uses it */ if(e->override_redirect) return; c = getclient(e->window, 1); if(c && c->window == e->window && (s = getscreen(e->parent))){ c->x = e->x; c->y = e->y; c->dx = e->width; c->dy = e->height; c->border = e->border_width; c->screen = s; if(c->parent == None) c->parent = c->screen->root; } if (kbLaunch) { usleep(100000); quickreshape(c, ra.width/5, ra.height/5, 3*ra.width/5, 3*ra.height/5); kbLaunch = 0; } } void destroy(Window w) { int i; Client *c; curtime = CurrentTime; c = getclient(w, 0); if(c == 0) return; if(numvirtuals > 1) for(i=0; imessage_type == exit_rio){ cleanup(); exit(0); } if(e->message_type == restart_rio){ fprintf(stderr, "*** rio restarting ***\n"); cleanup(); execvp(myargv[0], myargv); perror("ryudo: exec failed"); exit(1); } if(e->message_type == wm_protocols) return; if(e->message_type == wm_change_state){ c = getclient(e->window, 0); if(e->format == 32 && e->data.l[0] == IconicState && c != 0){ if(normal(c)) hide(c); } else fprintf(stderr, "ryudo: WM_CHANGE_STATE: format %d data %d w 0x%x\n", (int)e->format, (int)e->data.l[0], (int)e->window); return; } if(e->message_type == wm_state){ // c = getclient(e->window, 0); // if(e->format == 32 && e->data.l[1] == wm_state_fullscreen){ // }else fprintf(stderr, "ryudo: WM_STATE: format %d data %d %d w 0x%x\n", (int)e->format, (int)e->data.l[0], (int)e->data.l[1], (int)e->window); return; } fprintf(stderr, "ryudo: strange ClientMessage, type 0x%x window 0x%x\n", (int)e->message_type, (int)e->window); } void cmap(XColormapEvent *e) { Client *c; int i; /* we don't set curtime as nothing here uses it */ if(e->new){ c = getclient(e->window, 0); if(c){ c->cmap = e->colormap; if(c == current) cmapfocus(c); } else for(c = clients; c; c = c->next){ for(i = 0; i < c->ncmapwins; i++) if(c->cmapwins[i] == e->window){ c->wmcmaps[i] = e->colormap; if(c == current) cmapfocus(c); return; } } } } void property(XPropertyEvent *e) { Atom a; int delete; Client *c; long msize; /* we don't set curtime as nothing here uses it */ a = e->atom; delete = (e->state == PropertyDelete); c = getclient(e->window, 0); if(c == 0) return; switch (a){ case XA_WM_ICON_NAME: if(c->iconname != 0) XFree((char*) c->iconname); c->iconname = delete ? 0 : getprop(c->window, a); setlabel(c); renamec(c, c->label); return; case XA_WM_NAME: if(c->name != 0) XFree((char*) c->name); c->name = delete ? 0 : getprop(c->window, a); setlabel(c); renamec(c, c->label); return; case XA_WM_TRANSIENT_FOR: gettrans(c); return; case XA_WM_HINTS: case XA_WM_SIZE_HINTS: case XA_WM_ZOOM_HINTS: /* placeholders to not forget. ignore for now. -Axel */ return; case XA_WM_NORMAL_HINTS: if(XGetWMNormalHints(dpy, c->window, &c->size, &msize) == 0 || c->size.flags == 0) c->size.flags = PSize; /* not specified - punt */ return; } if(a == _rio_hold_mode){ c->hold = getiprop(c->window, _rio_hold_mode); if(c == current) draw_border(c, 1); } else if(a == wm_colormaps){ getcmaps(c); if(c == current) cmapfocus(c); } } void reparent(XReparentEvent *e) { Client *c; XWindowAttributes attr; ScreenInfo *s; /* we don't set curtime as nothing here uses it */ if(!getscreen(e->event) || e->override_redirect) return; if((s = getscreen(e->parent)) != 0){ c = getclient(e->window, 1); if(c != 0 && (c->dx == 0 || c->dy == 0)){ /* flush any errors */ ignore_badwindow = 1; XGetWindowAttributes(dpy, c->window, &attr); XSync(dpy, False); ignore_badwindow = 0; c->x = attr.x; c->y = attr.y; c->dx = attr.width; c->dy = attr.height; c->border = attr.border_width; c->screen = s; if(c->parent == None) c->parent = c->screen->root; } } else { c = getclient(e->window, 0); if(c != 0 && (c->parent == c->screen->root || withdrawn(c))) rmclient(c); } } #ifdef SHAPE void shapenotify(XShapeEvent *e) { Client *c; /* we don't set curtime as nothing here uses it */ c = getclient(e->window, 0); if(c == 0) return; setshape(c); } #endif void enter(XCrossingEvent *e) { Client *c; curtime = e->time; if(!ffm) if(e->mode != NotifyGrab || e->detail != NotifyNonlinearVirtual) return; c = getclient(e->window, 0); if(c != 0 && c != current){ /* someone grabbed the pointer; make them current */ if(!ffm) XMapRaised(dpy, c->parent); top(c); active(c); } } void leave(XCrossingEvent *e) { Client *c; c = getclient(e->window, 0); if(c) XUndefineCursor(dpy, c->parent); /* XDefineCursor(dpy, c->parent, c->screen->arrow); */ } void focusin(XFocusChangeEvent *e) { Client *c; curtime = CurrentTime; if(e->detail != NotifyNonlinearVirtual) return; c = getclient(e->window, 0); if(c != 0 && c->window == e->window && c != current){ #ifdef AUTOSTICK if (isautostick(c)){ #endif /* someone grabbed keyboard or seized focus; make them current */ XMapRaised(dpy, c->parent); top(c); active(c); #ifdef AUTOSTICK } #endif } } BorderOrient borderorient(Client *c, int x, int y) { if(x <= BORDER){ if(y <= CORNER){ if(debug) fprintf(stderr, "topleft\n"); return BorderWNW; } if(y >= (c->dy + 2*BORDER) - CORNER){ if(debug) fprintf(stderr, "botleft\n"); return BorderWSW; } if(y > CORNER && y < (c->dy + 2*BORDER) - CORNER){ if(debug) fprintf(stderr, "left\n"); return BorderW; } } else if(x <= CORNER){ if(y <= BORDER){ if(debug) fprintf(stderr, "topleft\n"); return BorderNNW; } if (y >= (c->dy + BORDER)){ if(debug) fprintf(stderr, "botleft\n"); return BorderSSW; } } else if(x >= (c->dx + BORDER)){ if(y <= CORNER){ if(debug) fprintf(stderr, "topright\n"); return BorderENE; } if(y >= (c->dy + 2*BORDER) - CORNER){ if(debug) fprintf(stderr, "botright\n"); return BorderESE; } if(y > CORNER && y < (c->dy + 2*BORDER) - CORNER){ if(debug) fprintf(stderr, "right\n"); return BorderE; } } else if(x >= (c->dx + 2*BORDER) - CORNER){ if(y <= BORDER){ if(debug) fprintf(stderr, "topright\n"); return BorderNNE; } if (y >= (c->dy + BORDER)){ if(debug) fprintf(stderr, "botright\n"); return BorderSSE; } } else if(x > CORNER && x < (c->dx + 2*BORDER) - CORNER){ if(y <= BORDER){ if(debug) fprintf(stderr, "top\n"); return BorderN; } if(y >= (c->dy + BORDER)){ if(debug) fprintf(stderr, "bot\n"); return BorderS; } } return BorderUnknown; } void motionnotify(XMotionEvent *e) { Client *c; BorderOrient bl; c = getclient(e->window, 0); if(c){ bl = borderorient(c, e->x, e->y); if(bl == BorderUnknown) XUndefineCursor(dpy, c->parent); else XDefineCursor(dpy, c->parent, c->screen->bordcurs[bl]); } }