| /* Copyright (c) 1994-1996 David Hogan, see README for licence details */ |
| #include <stdio.h> |
| #include <stdlib.h> |
| #include <X11/X.h> |
| #include <X11/Xos.h> |
| #include <X11/Xlib.h> |
| #include <X11/Xutil.h> |
| #include <X11/Xatom.h> |
| #include <X11/extensions/shape.h> |
| #include "dat.h" |
| #include "fns.h" |
| #include "patchlevel.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, "rio: 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, "rio: SelectionClear (this should not happen)\n"); |
| break; |
| case SelectionNotify: |
| fprintf(stderr, "rio: SelectionNotify (this should not happen)\n"); |
| break; |
| case SelectionRequest: |
| fprintf(stderr, "rio: 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, "rio: 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, "rio: 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; |
| |
| /* 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; |
| } |
| } |
| |
| void |
| destroy(Window w) |
| { |
| int i; |
| Client *c; |
| |
| curtime = CurrentTime; |
| c = getclient(w, 0); |
| if(c == 0) |
| return; |
| |
| if(numvirtuals > 1) |
| for(i=0; i<numvirtuals; i++) |
| if(currents[i] == c) |
| currents[i] = 0; |
| |
| rmclient(c); |
| |
| /* 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, "*** rio restarting ***\n"); |
| cleanup(); |
| execvp(myargv[0], myargv); |
| perror("rio: 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, "rio: 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, "rio: 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, "rio: 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){ |
| /* someone grabbed keyboard or seized focus; make them current */ |
| XMapRaised(dpy, c->parent); |
| top(c); |
| active(c); |
| } |
| } |
| |
| 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]); |
| } |
| } |