/* * 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 #include "config.h" #include "dat.h" #include "fns.h" #include "patchlevel.h" #ifndef MICROSLEEP_DELAY #define MICROSLEEP_DELAY 100000 #endif void mainloop(int shape_event) { static XEvent ev; static Client* c; static int monitor; 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; /* XRANDR related events; idk what the define for this is */ case 89: if (XRRUpdateConfiguration(&ev)) { fetchmonitorinfo(); monitor = getmonitorbyclient(c); if (monitor < 0 || monitor >= nmonitors) { break; } for (c = clients; c; c = c->next) { monitor = getmonitorbyclient(c); wrangle(c, monitorinfo[monitor]); } } break; case KeyPress: keypress(&ev.xkey); break; case KeyRelease: keyrelease(&ev.xkey); break; case ButtonPress: button(&ev.xbutton); XAllowEvents(dpy, ReplayPointer, ev.xbutton.time); break; case ButtonRelease: XAllowEvents(dpy, ReplayPointer, ev.xbutton.time); 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; XRRMonitorInfo monitor; int m; /* 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) { m = getmonitorbyclient(c); monitor = monitorinfo[m]; 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 && e->width >= monitor.width && e->height >= monitor.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.sibling = None; wc.border_width = c->border; wc.stack_mode = e->detail; XConfigureWindow(dpy, c->parent, e->value_mask, &wc); if (e->value_mask & CWStackMode) { if (c->virt > 0 && c->virt != virt) switch_to(c->virt); if (hidden(c)) { unhidec(c, 1); } 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; XRRMonitorInfo monitor; monitor = monitorinfo[getmonitorbymouse()]; 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; } } if (kbLaunch) { usleep(MICROSLEEP_DELAY); #ifdef CENTERVMAX centerclient(c, monitor, 1); #else centerclient(c, monitor, 0); #endif kbLaunch = 0; } switch (c->state) { case WithdrawnState: if (c->parent == c->screen->root) { if (!manage(c, 0)) return; break; } XReparentWindow(dpy, c->window, c->parent, BORDER, BORDER); 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, *revertc; int m; curtime = CurrentTime; c = getclient(e->window, 0); if (c) { m = getmonitorbyclient(c); switch (c->state) { case IconicState: if (e->send_event) { unhidec(c, 0); withdraw(c); } break; case NormalState: if (c == current) { nofocus(); if (revertc = getclient(getrevert(c), 0)) { top(revertc); active(revertc); } else { shuffleonmonitor(m); } } 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; /* 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 defined(OPACITY) && defined(TRANSPARENTLIST) if (istransparent(c)) { /* We need to set the atom on both the window and its parent */ const Atom alpha_atom = XInternAtom(dpy, "_NET_WM_WINDOW_OPACITY", 0); unsigned long opacity = (unsigned long)OPACITY * 0x1010101; XChangeProperty( dpy, c->window, alpha_atom, XA_CARDINAL, 32, PropModeReplace, (unsigned char*)&opacity, 1); XChangeProperty( dpy, c->parent, alpha_atom, XA_CARDINAL, 32, PropModeReplace, (unsigned char*)&opacity, 1); } #endif } void destroy(Window w) { int i; Client *c, *revertc; Window revert; curtime = CurrentTime; c = getclient(w, 0); if (c == 0) return; revert = getrevert(c); if (numvirtuals > 1) for (i = 0; i < numvirtuals; i++) if (currents[i] == c) currents[i] = 0; rmclient(c); if (!current && (revertc = getclient(revert, 0))) { top(revertc); active(revertc); } /* flush any errors generated by the window's sudden demise */ ignore_badwindow = 1; XSync(dpy, False); ignore_badwindow = 0; } void clientmesg(XClientMessageEvent* e) { Client* c; curtime = CurrentTime; if (e->message_type == exit_rio) { cleanup(); exit(0); } if (e->message_type == restart_rio) { fprintf(stderr, "*** ryudo 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]); } }