pax_global_header00006660000000000000000000000064126507417750014530gustar00rootroot0000000000000052 comment=2300dee3846804966a06fce0bdfddbc031e0e872 9wm-1.3.5/000077500000000000000000000000001265074177500122525ustar00rootroot000000000000009wm-1.3.5/.indent.pro000066400000000000000000000001721265074177500143330ustar00rootroot00000000000000--original --declaration-indentation 2 --indent-level 8 --line-length 132 --no-blank-lines-after-commas --honour-newlines 9wm-1.3.5/9wm.c000066400000000000000000000210751265074177500131370ustar00rootroot00000000000000/* * Copyright (c) 2014 multiple authors, see README for licence details */ #include #include #include #include #include #include #include #include #include #include #include #include "dat.h" #include "fns.h" char *version[] = { "9wm version 1.3.5, Copyright © 2015 multiple authors", 0, }; Display *dpy; ScreenInfo *screens; int initting; XFontStruct *font; int nostalgia; char **myargv; char *termprog; char *shell; Bool shape; int _border = 4; int _inset = 1; int curtime; int debug; int signalled; int num_screens; Atom exit_9wm; Atom restart_9wm; Atom wm_state; Atom wm_change_state; Atom wm_protocols; Atom wm_delete; Atom wm_take_focus; Atom wm_colormaps; Atom wm_moveresize; Atom active_window; Atom utf8_string; Atom _9wm_running; Atom _9wm_hold_mode; char *fontlist[] = { "-*-dejavu sans-bold-r-*-*-14-*-*-*-p-*-*-*", "-adobe-helvetica-bold-r-*-*-14-*-*-*-p-*-*-*", "lucm.latin1.9", "blit", "9x15bold", "lucidasanstypewriter-12", "fixed", "*", 0, }; void sigchld(int signum) { while (0 < waitpid(-1, NULL, WNOHANG)); } void usage(void) { fprintf(stderr, "usage: 9wm [-version] [-nostalgia] [-font fname] [-term prog] [exit|restart]\n"); exit(1); } int main(int argc, char *argv[]) { int i, do_exit, do_restart; char *fname; int shape_event, dummy; myargv = argv; /* for restart */ do_exit = do_restart = 0; font = 0; fname = 0; for (i = 1; i < argc; i++) if (strcmp(argv[i], "-nostalgia") == 0) nostalgia++; else if (strcmp(argv[i], "-debug") == 0) debug++; else if (strcmp(argv[i], "-font") == 0 && i + 1 < argc) { i++; fname = argv[i]; } else if (strcmp(argv[i], "-term") == 0 && i + 1 < argc) termprog = argv[++i]; else if (strcmp(argv[i], "-version") == 0) { fprintf(stderr, "%s\n", version[0]); exit(0); } else if (argv[i][0] == '-') usage(); else break; for (; i < argc; i++) if (strcmp(argv[i], "exit") == 0) do_exit++; else if (strcmp(argv[i], "restart") == 0) do_restart++; else usage(); if (do_exit && do_restart) usage(); shell = (char *) getenv("SHELL"); if (shell == NULL) shell = DEFSHELL; dpy = XOpenDisplay(""); if (dpy == 0) fatal("can't open display"); initting = 1; XSetErrorHandler(handler); if (signal(SIGTERM, sighandler) == SIG_IGN) signal(SIGTERM, SIG_IGN); if (signal(SIGINT, sighandler) == SIG_IGN) signal(SIGINT, SIG_IGN); if (signal(SIGHUP, sighandler) == SIG_IGN) signal(SIGHUP, SIG_IGN); signal(SIGCHLD, sigchld); exit_9wm = XInternAtom(dpy, "9WM_EXIT", False); restart_9wm = XInternAtom(dpy, "9WM_RESTART", False); curtime = -1; /* don't care */ if (do_exit) { sendcmessage(DefaultRootWindow(dpy), exit_9wm, 0L, 1); XSync(dpy, False); exit(0); } if (do_restart) { sendcmessage(DefaultRootWindow(dpy), restart_9wm, 0L, 1); XSync(dpy, False); exit(0); } wm_state = XInternAtom(dpy, "WM_STATE", False); wm_change_state = XInternAtom(dpy, "WM_CHANGE_STATE", False); wm_protocols = XInternAtom(dpy, "WM_PROTOCOLS", False); wm_delete = XInternAtom(dpy, "WM_DELETE_WINDOW", False); wm_take_focus = XInternAtom(dpy, "WM_TAKE_FOCUS", False); wm_colormaps = XInternAtom(dpy, "WM_COLORMAP_WINDOWS", False); wm_moveresize = XInternAtom(dpy, "_NET_WM_MOVERESIZE", False); active_window = XInternAtom(dpy, "_NET_ACTIVE_WINDOW", False); utf8_string = XInternAtom(dpy, "UTF8_STRING", False); _9wm_running = XInternAtom(dpy, "_9WM_RUNNING", False); _9wm_hold_mode = XInternAtom(dpy, "_9WM_HOLD_MODE", False); if (fname != 0) if ((font = XLoadQueryFont(dpy, fname)) == 0) fprintf(stderr, "9wm: warning: can't load font %s\n", fname); if (font == 0) { i = 0; for (;;) { fname = fontlist[i++]; if (fname == 0) { fprintf(stderr, "9wm: warning: can't find a font\n"); break; } font = XLoadQueryFont(dpy, fname); if (font != 0) break; } } if (nostalgia == BLIT) { _border--; _inset--; } #ifdef SHAPE shape = XShapeQueryExtension(dpy, &shape_event, &dummy); #endif num_screens = ScreenCount(dpy); screens = (ScreenInfo *) malloc(sizeof(ScreenInfo) * num_screens); for (i = 0; i < num_screens; i++) initscreen(&screens[i], i); /* * set selection so that 9term knows we're running */ curtime = CurrentTime; XSetSelectionOwner(dpy, _9wm_running, screens[0].menuwin, timestamp()); XSync(dpy, False); initting = 0; nofocus(); for (i = 0; i < num_screens; i++) scanwins(&screens[i]); mainloop(shape_event); return 0; } void initscreen(ScreenInfo * s, int i) { char *ds, *colon, *dot1; unsigned long mask; XGCValues gv; XSetWindowAttributes attr; s->num = i; s->root = RootWindow(dpy, i); s->def_cmap = DefaultColormap(dpy, i); s->min_cmaps = MinCmapsOfScreen(ScreenOfDisplay(dpy, i)); ds = DisplayString(dpy); colon = strrchr(ds, ':'); if (colon && num_screens > 1) { strcpy(s->display, "DISPLAY="); strcat(s->display, ds); colon = s->display + 8 + (colon - ds); /* use version in buf */ dot1 = strchr(colon, '.'); /* first period after colon */ if (!dot1) dot1 = colon + strlen(colon); /* if not there, append */ sprintf(dot1, ".%d", i); } else s->display[0] = '\0'; s->black = BlackPixel(dpy, i); s->white = WhitePixel(dpy, i); gv.foreground = s->black ^ s->white; gv.background = s->white; gv.function = GXxor; gv.line_width = 0; gv.subwindow_mode = IncludeInferiors; mask = GCForeground | GCBackground | GCFunction | GCLineWidth | GCSubwindowMode; if (font != 0) { gv.font = font->fid; mask |= GCFont; } s->gc = XCreateGC(dpy, s->root, mask, &gv); initcurs(s); attr.cursor = s->arrow; attr.event_mask = SubstructureRedirectMask | SubstructureNotifyMask | ColormapChangeMask | ButtonPressMask | ButtonReleaseMask | PropertyChangeMask; mask = CWCursor | CWEventMask; XChangeWindowAttributes(dpy, s->root, mask, &attr); XSync(dpy, False); s->menuwin = XCreateSimpleWindow(dpy, s->root, 0, 0, 1, 1, 1, s->black, s->white); } ScreenInfo * getscreen(Window w) { int i; for (i = 0; i < num_screens; i++) if (screens[i].root == w) return &screens[i]; return 0; } Time timestamp(void) { XEvent ev; if (curtime == CurrentTime) { XChangeProperty(dpy, screens[0].root, _9wm_running, _9wm_running, 8, PropModeAppend, (unsigned char *) "", 0); XMaskEvent(dpy, PropertyChangeMask, &ev); curtime = ev.xproperty.time; } return curtime; } void sendcmessage(Window w, Atom a, long x, int isroot) { XEvent ev; int status; long mask; memset(&ev, 0, sizeof(ev)); ev.xclient.type = ClientMessage; ev.xclient.window = w; ev.xclient.message_type = a; ev.xclient.format = 32; ev.xclient.data.l[0] = x; ev.xclient.data.l[1] = timestamp(); mask = 0L; if (isroot) mask = SubstructureRedirectMask; /* magic! */ status = XSendEvent(dpy, w, False, mask, &ev); if (status == 0) fprintf(stderr, "9wm: sendcmessage failed\n"); } void sendconfig(c) Client *c; { XConfigureEvent ce; ce.type = ConfigureNotify; ce.event = c->window; ce.window = c->window; ce.x = c->x; ce.y = c->y; ce.width = c->dx; ce.height = c->dy; ce.border_width = c->border; ce.above = None; ce.override_redirect = 0; XSendEvent(dpy, c->window, False, StructureNotifyMask, (XEvent *) & ce); } void sighandler(void) { signalled = 1; } void getevent(XEvent * e) { int fd; fd_set rfds; struct timeval t; if (!signalled) { if (QLength(dpy) > 0) { XNextEvent(dpy, e); return; } fd = ConnectionNumber(dpy); FD_ZERO(&rfds); FD_SET(fd, &rfds); t.tv_sec = t.tv_usec = 0; if (select(fd + 1, &rfds, NULL, NULL, &t) == 1) { XNextEvent(dpy, e); return; } XFlush(dpy); do { FD_ZERO(&rfds); FD_SET(fd, &rfds); if (select(fd + 1, &rfds, NULL, NULL, NULL) == 1) { XNextEvent(dpy, e); return; } } while (errno == EINTR); if (!signalled) { perror("9wm: select failed"); exit(1); } } fprintf(stderr, "9wm: exiting on signal\n"); cleanup(); exit(1); } void cleanup(void) { Client *c, *cc[2], *next; XWindowChanges wc; int i; /* * order of un-reparenting determines final stacking order... */ cc[0] = cc[1] = 0; for (c = clients; c; c = next) { next = c->next; i = normal(c); c->next = cc[i]; cc[i] = c; } for (i = 0; i < 2; i++) { for (c = cc[i]; c; c = c->next) { if (!withdrawn(c)) { gravitate(c, 1); XReparentWindow(dpy, c->window, c->screen->root, c->x, c->y); } wc.border_width = c->border; XConfigureWindow(dpy, c->window, CWBorderWidth, &wc); } } XSetInputFocus(dpy, PointerRoot, RevertToPointerRoot, timestamp()); for (i = 0; i < num_screens; i++) cmapnofocus(&screens[i]); XCloseDisplay(dpy); } 9wm-1.3.5/9wm.man000066400000000000000000000052401265074177500134640ustar00rootroot00000000000000.if t .ds 85 8\(12 .if n .ds 85 8-1/2 .TH 9wm 1 .SH NAME 9wm \- \*(85-like Window Manager for X .SH SYNOPSIS .B 9wm [ .B \-grey ] [ .B \-version ] [ .B \-font .I fname ] [ .B \-term .I termprog ] [ .BR exit | restart ] .SH DESCRIPTION .I 9wm is a window manager for X which attempts to emulate the window management policies of Plan 9's .I \*(85 window manager. .PP The .B \-grey option makes the background light grey, as does \*(85. Use this option for maximum authenticity. .B \-font .I fname sets the font in .IR 9wm 's menu to .IR fname , overriding the default. .B \-term .I termprog specifies an alternative program to run when the .I New menu item is selected. .B \-version prints the current version on standard error, then exits. .PP To make .I 9wm exit, you have to run .B "9wm exit" on the command line. There is no ``exit'' menu item. .PP .I 9wm is click-to-type: it has a notion of the current window, which is usually on top, and always has its border darkened. Characters typed at the keyboard go to the current window, and mouse clicks outside the current window are swallowed up by .IR 9wm . To make another window the current one, click on it with button 1. Unlike other X window managers, 9wm implements `mouse focus': mouse events are sent only to the current window. .PP A menu of window operations is available by pressing button 3 outside the current window. The first of these, .IR New , attempts to spawn a .I 9term process (or .I xterm if .I 9term is not available). .PP The next four menu items are .IR Reshape , .IR Move , .IR Delete , and .IR Hide . All of the operations change the cursor into a target, prompting the user to click button 3 on one of the windows to select it for the operation. At this stage, clicking button 1 or 2 will abort the operation. Otherwise, if the operation was .IR Resize , the user is prompted to sweep out the new outline with button 3. If it was .IR Move , the user should keep the button held down after the initial click that selected the window, and drag the window to the right place before releasing. In either case, button 1 or 2 will abort the operation. .PP If the .I Delete operation is selected, the window will be deleted when the button is released. This typically kills the client that owns the window. The .I Hide operation just makes the window invisible. While hidden, the window's name appears on the bottom of the button 3 menu. Selecting that item brings the window back (unhides it). This operation replaces the iconification feature provided by other window managers. .SH BUGS Is not completely compatible with \*(85. .PP There is a currently a compiled-in limit of 32 hidden windows. .SH "SEE ALSO" .IR 9term (1), .IR xterm (1). 9wm-1.3.5/CREDITS000066400000000000000000000003621265074177500132730ustar00rootroot00000000000000People Who've Helped ==================== * Jacob Adams has contributed many patches to further modernize building * Dave Conroy contributed a patch to fix event handling with xforms-toolkit 9wm-1.3.5/LICENSE000066400000000000000000000022041265074177500132550ustar00rootroot00000000000000Licence ======= Copyright © 1994-1996 David Hogan Copyright © 2009 The Estate of David Hogan Copyright © 2014 Neale Pickett Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicence, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 9wm-1.3.5/Makefile000066400000000000000000000005731265074177500137170ustar00rootroot00000000000000CFLAGS += -DSHAPE -Wall -Werror LDLIBS = -lXext -lX11 BIN = $(DESTDIR)/usr/bin/ MANDIR = $(DESTDIR)/usr/share/man/man1 MANSUFFIX = 1 all: 9wm 9wm: 9wm.o event.o manage.o menu.o client.o grab.o cursor.o error.o install: 9wm mkdir -p $(BIN) cp 9wm $(BIN)/9wm install.man: mkdir -p $(MANDIR) cp 9wm.man $(MANDIR)/9wm.$(MANSUFFIX) $(OBJS): $(HFILES) clean: rm -f 9wm *.o 9wm-1.3.5/README000066400000000000000000000074431265074177500131420ustar00rootroot000000000000009wm Version 1.3.4 ================= 9wm is an X11 window manager inspired by the Plan 9 window manager 8½. It provides a very simple and clean user interface. It is click-to-type. It uses the X11 font system (which, unfortunately, means no Unicode support). 9wm does not provide virtual desktops, customization, key bindings, or compositing. It does not allocate any colors, which will be great news if you are stuck in 1993. 9wm is distributed under [an MIT License](LICENSE). Where do I get it? ================== The latest version of 9wm is held at How do I use it? ================ The focused window has a black border. Mouse and keyboard events go to this window. Left click a non-focused window (white border) to focus it. Right-click anywhere other than the focused window, including in any non-focused window, to bring up a menu. All further actions are done with the right mouse button. The menu has options for: * New: launch a new xterm * Reshape: select a window, draw new rectangle for its size * Move: drag a window around * Delete: kill (close) a window * Hide: hide (iconify) a window Beneath the first 5 items are a list of all hidden windows. Middle-click anywhere other than the focused window to run "mm mouse2". It's up to you to write an "mm" program and put it in your path somewhere, if you want to use this for something. I have mine run "google-chrome-stable --show-app-list". What if I find a bug? ===================== Please mail all bug reports to neale@woozle.org, so that I can incorporate fixes into the next release. If you can tell me how to fix it, all the better. Known Problems/Bugs =================== 9wm uses ideas from plan9port's `rio`, but is following a different path and is not exactly the same. In an attempt to avoid ludicrously long window names in the menu, 9wm shortens names with colons and dashes in them. The algorithm works well for most programs I've tried, but is bound to fail with something or other, rendering a near-useless icon name. Windows that provide their own placement information aren't handled well right now. I'm working on it. 9wm has no idea how many monitors you have, nor what their dimensions are. It also can't deal with desktop geometry changes, like plugging in an external monitor. I run "9wm restart" to make it quickly reset its internal state and notice any changes. 9wm doesn't have Unicode support. In particular, if you have a browser page open with non-Latin characters in the name, and you hide that window, you will get a weird name for that window's entry in the list. Doing Unicode in X11 is a horrible mess requiring, among other things, a whole new library for rendering text. I may get to this in the future, but for now, I feel like learning about Wayland is a better use of my effort. Acknowledgements ================ Thanks to the late David Hogan for writing 9wm. Thanks to Rob Pike for writing the original 8-1/2 program (and before that, mux) which inspired the writing of 9wm. Thanks to John Mackin, whose gwm "wool code" for emulating mux was also an inspiration: I used it (and hacked it) until I got too frustrated with gwm's large memory requirements and lack of speed (sorry Colas!), and decided to write a dedicated program. Thanks to Matthew Farrow for writing 9term. A big thanks to Dave Edmondson for adding support for multi-screen displays. The following people helped beta test 9wm: John Mackin Noel Hunt Fred Curtis James Matthew Farrow Danny Yee Arnold Robbins Byron Rakitzis micro@cooper.edu Author ====== 9wm was written by David Hogan (dhog@cs.su.oz.au), a postgraduate student at the Basser Department of Computer Science, University of Sydney David Hogan died in 2003. 9wm is now maintained by Neale Pickett . 9wm-1.3.5/TODO.txt000066400000000000000000000004211265074177500135550ustar00rootroot00000000000000* Don't warp mouse pointer for Move * Update function declarations to modern C (as I touch them) * Urgent hints (c->name = ":: " .. c->name .. " ::") * Bring back placement of xterm launched by "New" (like rio) * How is rio placing Google Hangouts popups in the southeast? 9wm-1.3.5/client.c000066400000000000000000000110161265074177500136730ustar00rootroot00000000000000/* * Copyright (c) 2014 multiple authors, see README for licence details */ #include #include #include #include #include #include #include "dat.h" #include "fns.h" Client *clients; Client *current; void setactive(Client *c, int on) { if (c->parent == c->screen->root) { fprintf(stderr, "9wm: bad parent in setactive; dumping core\n"); abort(); } if (on) { XUngrabButton(dpy, AnyButton, AnyModifier, c->parent); XSetInputFocus(dpy, c->window, RevertToPointerRoot, timestamp()); if (c->proto & Ptakefocus) sendcmessage(c->window, wm_protocols, wm_take_focus, 0); cmapfocus(c); } else XGrabButton(dpy, AnyButton, AnyModifier, c->parent, False, ButtonMask, GrabModeAsync, GrabModeSync, None, None); draw_border(c, on); } void draw_border(Client *c, int active) { XSetWindowBackground(dpy, c->parent, active ? c->screen->black : c->screen->white); XClearWindow(dpy, c->parent); if (c->hold && active) XDrawRectangle(dpy, c->parent, c->screen->gc, INSET, INSET, c->dx + BORDER - INSET, c->dy + BORDER - INSET); } void active(Client *c) { Client *cc; if (c == 0) { fprintf(stderr, "9wm: active(c==0)\n"); return; } if (c == current) return; if (current) { setactive(current, 0); if (current->screen != c->screen) cmapnofocus(current->screen); } setactive(c, 1); for (cc = clients; cc; cc = cc->next) if (cc->revert == c) cc->revert = c->revert; c->revert = current; while (c->revert && !normal(c->revert)) c->revert = c->revert->revert; current = c; #ifdef DEBUG if (debug) dump_revert(); #endif } void nofocus(void) { static Window w = 0; int mask; XSetWindowAttributes attr; Client *c; if (current) { setactive(current, 0); for (c = current->revert; c; c = c->revert) if (normal(c)) { active(c); return; } cmapnofocus(current->screen); /* * if no candidates to revert to, fall through */ } current = 0; if (w == 0) { mask = CWOverrideRedirect; attr.override_redirect = 1; w = XCreateWindow(dpy, screens[0].root, 0, 0, 1, 1, 0, CopyFromParent, InputOnly, CopyFromParent, mask, &attr); XMapWindow(dpy, w); } XSetInputFocus(dpy, w, RevertToPointerRoot, timestamp()); } void top(Client *c) { Client **l, *cc; l = &clients; for (cc = *l; cc; cc = *l) { if (cc == c) { *l = c->next; c->next = clients; clients = c; return; } l = &cc->next; } fprintf(stderr, "9wm: %p not on client list in top()\n", c); } Client * getclient(Window w, int create) { Client *c; if (w == 0 || getscreen(w)) return 0; for (c = clients; c; c = c->next) if (c->window == w || c->parent == w) return c; if (!create) return 0; c = (Client *) malloc(sizeof(Client)); memset(c, 0, sizeof(Client)); c->window = w; /* * c->parent will be set by the caller */ c->parent = None; c->reparenting = 0; c->state = WithdrawnState; c->init = 0; c->cmap = None; c->label = c->class = 0; c->revert = 0; c->is9term = 0; c->hold = 0; c->ncmapwins = 0; c->cmapwins = 0; c->wmcmaps = 0; c->next = clients; clients = c; return c; } void rmclient(Client *c) { Client *cc; for (cc = current; cc && cc->revert; cc = cc->revert) if (cc->revert == c) cc->revert = cc->revert->revert; if (c == clients) clients = c->next; for (cc = clients; cc && cc->next; cc = cc->next) if (cc->next == c) cc->next = cc->next->next; if (hidden(c)) unhidec(c, 0); if (c->parent != c->screen->root) XDestroyWindow(dpy, c->parent); c->parent = c->window = None; /* paranoia */ if (current == c) { current = c->revert; if (current == 0) nofocus(); else { if (current->screen != c->screen) cmapnofocus(c->screen); setactive(current, 1); } } if (c->ncmapwins != 0) { XFree((char *) c->cmapwins); free((char *) c->wmcmaps); } if (c->iconname != 0) XFree((char *) c->iconname); if (c->name != 0) XFree((char *) c->name); if (c->instance != 0) XFree((char *) c->instance); if (c->class != 0) XFree((char *) c->class); memset(c, 0, sizeof(Client)); /* paranoia */ free(c); } #ifdef DEBUG void dump_revert(void) { Client *c; int i; i = 0; for (c = current; c; c = c->revert) { fprintf(stderr, "%s(%x:%d)", c->label ? c->label : "?", c->window, c->state); if (i++ > 100) break; if (c->revert) fprintf(stderr, " -> "); } if (current == 0) fprintf(stderr, "empty"); fprintf(stderr, "\n"); } void dump_clients(void) { Client *c; for (c = clients; c; c = c->next) fprintf(stderr, "w 0x%x parent 0x%x @ (%d, %d)\n", c->window, c->parent, c->x, c->y); } #endif 9wm-1.3.5/cursor.c000066400000000000000000000133651265074177500137430ustar00rootroot00000000000000/* * Copyright (c) 2014 multiple authors, see README for licence details */ #include #include #include #include #include #include "dat.h" #include "fns.h" typedef struct { int width; int hot[2]; unsigned char mask[64]; unsigned char fore[64]; } Cursordata; Cursordata sweep0data = { 16, {7, 7}, {0xC0, 0x03, 0xC0, 0x03, 0xC0, 0x03, 0xC0, 0x03, 0xC0, 0x03, 0xC0, 0x03, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xC0, 0x03, 0xC0, 0x03, 0xC0, 0x03, 0xC0, 0x03, 0xC0, 0x03, 0xC0, 0x03}, {0x00, 0x00, 0x80, 0x01, 0x80, 0x01, 0x80, 0x01, 0x80, 0x01, 0x80, 0x01, 0x80, 0x01, 0xFE, 0x7F, 0xFE, 0x7F, 0x80, 0x01, 0x80, 0x01, 0x80, 0x01, 0x80, 0x01, 0x80, 0x01, 0x80, 0x01, 0x00, 0x00} }; Cursordata boxcursdata = { 16, {7, 7}, {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x1F, 0xF8, 0x1F, 0xF8, 0x1F, 0xF8, 0x1F, 0xF8, 0x1F, 0xF8, 0x1F, 0xF8, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF}, {0x00, 0x00, 0xFE, 0x7F, 0xFE, 0x7F, 0xFE, 0x7F, 0x0E, 0x70, 0x0E, 0x70, 0x0E, 0x70, 0x0E, 0x70, 0x0E, 0x70, 0x0E, 0x70, 0x0E, 0x70, 0x0E, 0x70, 0xFE, 0x7F, 0xFE, 0x7F, 0xFE, 0x7F, 0x00, 0x00} }; Cursordata sightdata = { 16, {7, 7}, {0xF8, 0x1F, 0xFC, 0x3F, 0xFE, 0x7F, 0xDF, 0xFB, 0xCF, 0xF3, 0xC7, 0xE3, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xC7, 0xE3, 0xCF, 0xF3, 0xDF, 0x7B, 0xFE, 0x7F, 0xFC, 0x3F, 0xF8, 0x1F,}, {0x00, 0x00, 0xF0, 0x0F, 0x8C, 0x31, 0x84, 0x21, 0x82, 0x41, 0x82, 0x41, 0x82, 0x41, 0xFE, 0x7F, 0xFE, 0x7F, 0x82, 0x41, 0x82, 0x41, 0x82, 0x41, 0x84, 0x21, 0x8C, 0x31, 0xF0, 0x0F, 0x00, 0x00,} }; Cursordata arrowdata = { 16, {1, 1}, {0xFF, 0x07, 0xFF, 0x07, 0xFF, 0x03, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x01, 0xFF, 0x03, 0xFF, 0x07, 0xE7, 0x0F, 0xC7, 0x1F, 0x83, 0x3F, 0x00, 0x7F, 0x00, 0xFE, 0x00, 0x7C, 0x00, 0x38, 0x00, 0x10,}, {0x00, 0x00, 0xFE, 0x03, 0xFE, 0x00, 0x3E, 0x00, 0x7E, 0x00, 0xFE, 0x00, 0xF6, 0x01, 0xE6, 0x03, 0xC2, 0x07, 0x82, 0x0F, 0x00, 0x1F, 0x00, 0x3E, 0x00, 0x7C, 0x00, 0x38, 0x00, 0x10, 0x00, 0x00,} }; Cursordata whitearrow = { 16, {0, 0}, {0xFF, 0x07, 0xFF, 0x07, 0xFF, 0x03, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x01, 0xFF, 0x03, 0xFF, 0x07, 0xE7, 0x0F, 0xC7, 0x1F, 0x83, 0x3F, 0x00, 0x7F, 0x00, 0xFE, 0x00, 0x7C, 0x00, 0x38, 0x00, 0x10,}, {0xFF, 0x07, 0xFF, 0x07, 0x83, 0x03, 0xC3, 0x00, 0xC3, 0x00, 0x83, 0x01, 0x1B, 0x03, 0x3F, 0x06, 0x67, 0x0C, 0xC7, 0x18, 0x83, 0x31, 0x00, 0x63, 0x00, 0xC6, 0x00, 0x6C, 0x00, 0x38, 0x00, 0x10,} }; Cursordata blittarget = { 18, {8, 8}, {0xe0, 0x1f, 0x00, 0xf0, 0x3f, 0x00, 0xf8, 0x7f, 0x00, 0xfc, 0xff, 0x00, 0xfe, 0xff, 0x01, 0xff, 0xff, 0x03, 0xff, 0xff, 0x03, 0xff, 0xff, 0x03, 0xff, 0xff, 0x03, 0xff, 0xff, 0x03, 0xff, 0xff, 0x03, 0xff, 0xff, 0x03, 0xff, 0xff, 0x03, 0xfe, 0xff, 0x01, 0xfc, 0xff, 0x00, 0xf8, 0x7f, 0x00, 0xf0, 0x3f, 0x00, 0xe0, 0x1f, 0x00}, {0x00, 0x00, 0x00, 0xc0, 0x0f, 0x00, 0xf0, 0x3f, 0x00, 0x38, 0x73, 0x00, 0x8c, 0xc7, 0x00, 0xec, 0xdf, 0x00, 0x66, 0x9b, 0x01, 0x36, 0xb3, 0x01, 0xfe, 0xff, 0x01, 0xfe, 0xff, 0x01, 0x36, 0xb3, 0x01, 0x66, 0x9b, 0x01, 0xec, 0xdf, 0x00, 0x8c, 0xc7, 0x00, 0x38, 0x73, 0x00, 0xf0, 0x3f, 0x00, 0xc0, 0x0f, 0x00, 0x00, 0x00, 0x00} }; Cursordata blitarrow = { 18, {1, 1}, {0xff, 0x0f, 0x00, 0xff, 0x07, 0x00, 0xff, 0x03, 0x00, 0xff, 0x00, 0x00, 0xff, 0x00, 0x00, 0xff, 0x01, 0x00, 0xff, 0x03, 0x00, 0xff, 0x07, 0x00, 0xe7, 0x0f, 0x00, 0xc7, 0x1f, 0x00, 0x87, 0x3f, 0x00, 0x03, 0x7f, 0x00, 0x01, 0xfe, 0x00, 0x00, 0xfc, 0x01, 0x00, 0xf8, 0x03, 0x00, 0xf0, 0x01, 0x00, 0xe0, 0x00, 0x00, 0x40, 0x00}, {0x00, 0x00, 0x00, 0xfe, 0x03, 0x00, 0xfe, 0x00, 0x00, 0x3e, 0x00, 0x00, 0x7e, 0x00, 0x00, 0xfe, 0x00, 0x00, 0xf6, 0x01, 0x00, 0xe6, 0x03, 0x00, 0xc2, 0x07, 0x00, 0x82, 0x0f, 0x00, 0x00, 0x1f, 0x00, 0x00, 0x3e, 0x00, 0x00, 0x7c, 0x00, 0x00, 0xf8, 0x00, 0x00, 0xf0, 0x01, 0x00, 0xe0, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x00} }; Cursordata blitsweep = { 18, {8, 8}, {0xc4, 0xff, 0x03, 0xce, 0xff, 0x03, 0xdf, 0xff, 0x03, 0x3e, 0x80, 0x03, 0x7c, 0x83, 0x03, 0xf8, 0x83, 0x03, 0xf7, 0x83, 0x03, 0xe7, 0x83, 0x03, 0xf7, 0x83, 0x03, 0xf7, 0x83, 0x03, 0x07, 0x80, 0x03, 0x07, 0x80, 0x03, 0x07, 0x80, 0x03, 0x07, 0x80, 0x03, 0x07, 0x80, 0x03, 0xff, 0xff, 0x03, 0xff, 0xff, 0x03, 0xff, 0xff, 0x03}, {0x00, 0x00, 0x00, 0x84, 0xff, 0x01, 0x0e, 0x00, 0x01, 0x1c, 0x00, 0x01, 0x38, 0x00, 0x01, 0x70, 0x01, 0x01, 0xe0, 0x01, 0x01, 0xc2, 0x01, 0x01, 0xe2, 0x01, 0x01, 0x02, 0x00, 0x01, 0x02, 0x00, 0x01, 0x02, 0x00, 0x01, 0x02, 0x00, 0x01, 0x02, 0x00, 0x01, 0x02, 0x00, 0x01, 0x02, 0x00, 0x01, 0xfe, 0xff, 0x01, 0x00, 0x00, 0x00} }; static XColor bl, wh; Cursor getcursor(Cursordata * c, ScreenInfo * s) { Pixmap f, m; f = XCreatePixmapFromBitmapData(dpy, s->root, (char *) c->fore, c->width, c->width, 1, 0, 1); m = XCreatePixmapFromBitmapData(dpy, s->root, (char *) c->mask, c->width, c->width, 1, 0, 1); return XCreatePixmapCursor(dpy, f, m, &bl, &wh, c->hot[0], c->hot[1]); } void initcurs(ScreenInfo * s) { XColor dummy; XAllocNamedColor(dpy, DefaultColormap(dpy, s->num), "black", &bl, &dummy); XAllocNamedColor(dpy, DefaultColormap(dpy, s->num), "white", &wh, &dummy); switch (nostalgia) { case BLIT: s->arrow = getcursor(&blitarrow, s); s->target = getcursor(&blittarget, s); s->sweep0 = getcursor(&blitsweep, s); s->boxcurs = getcursor(&blitsweep, s); break; case V1: s->arrow = getcursor(&arrowdata, s); s->target = getcursor(&sightdata, s); s->sweep0 = getcursor(&sweep0data, s); s->boxcurs = getcursor(&boxcursdata, s); break; default: s->arrow = XCreateFontCursor(dpy, XC_left_ptr); s->target = XCreateFontCursor(dpy, XC_crosshair); s->sweep0 = XCreateFontCursor(dpy, XC_sizing); s->boxcurs = XCreateFontCursor(dpy, XC_dotbox); break; } } 9wm-1.3.5/dat.h000066400000000000000000000051031265074177500131720ustar00rootroot00000000000000/* Copyright (c) 1994-1996 David Hogan, see README for licence details */ #define BORDER _border #define INSET _inset #define MAXHIDDEN 32 #define B3FIXED 5 #define AllButtonMask (Button1Mask|Button2Mask|Button3Mask \ |Button4Mask|Button5Mask) #define ButtonMask (ButtonPressMask|ButtonReleaseMask) #define MenuMask (ButtonMask|ButtonMotionMask|ExposureMask) #define MenuGrabMask (ButtonMask|ButtonMotionMask|StructureNotifyMask) #ifdef Plan9 #define DEFSHELL "/bin/rc" #else #define DEFSHELL "/bin/sh" #endif typedef struct Client Client; typedef struct Menu Menu; typedef struct ScreenInfo ScreenInfo; struct Client { Window window; Window parent; Window trans; Client *next; Client *revert; int x; int y; int dx; int dy; int border; XSizeHints size; int min_dx; int min_dy; int state; int init; int reparenting; int is9term; int hold; int proto; char *label; char *instance; char *class; char *name; char *iconname; Colormap cmap; int ncmapwins; Window *cmapwins; Colormap *wmcmaps; ScreenInfo *screen; }; #define hidden(c) ((c)->state == IconicState) #define withdrawn(c) ((c)->state == WithdrawnState) #define normal(c) ((c)->state == NormalState) /* c->proto */ #define Pdelete 1 #define Ptakefocus 2 struct Menu { char **item; char *(*gen)(); int lasthit; }; struct ScreenInfo { int num; Window root; Window menuwin; Colormap def_cmap; GC gc; unsigned long black; unsigned long white; int min_cmaps; Cursor target; Cursor sweep0; Cursor boxcurs; Cursor arrow; Pixmap root_pixmap; char display[256]; /* arbitrary limit */ }; // Nostalgia options enum { MODERN = 0, V1, BLIT }; /* main.c */ extern Display *dpy; extern ScreenInfo *screens; extern int num_screens; extern int initting; extern XFontStruct *font; extern int nostalgia; extern char **myargv; extern Bool shape; extern char *termprog; extern char *shell; extern char *version[]; extern int _border; extern int _inset; extern int curtime; extern int debug; extern Atom exit_9wm; extern Atom restart_9wm; extern Atom wm_state; extern Atom wm_change_state; extern Atom _9wm_hold_mode; extern Atom wm_protocols; extern Atom wm_delete; extern Atom wm_take_focus; extern Atom wm_colormaps; extern Atom utf8_string; extern Atom wm_moveresize; extern Atom active_window; /* client.c */ extern Client *clients; extern Client *current; /* menu.c */ extern Client *hiddenc[]; extern int numhidden; extern char *b3items[]; extern Menu b3menu; /* error.c */ extern int ignore_badwindow; 9wm-1.3.5/error.c000066400000000000000000000040511265074177500135470ustar00rootroot00000000000000/* * Copyright (c) 2014 multiple authors, see README for licence details */ #include #include #include #include #include #include #include "dat.h" #include "fns.h" int ignore_badwindow; void fatal(char *s) { fprintf(stderr, "9wm: "); perror(s); fprintf(stderr, "\n"); exit(1); } int handler(Display * d, XErrorEvent * e) { char msg[80], req[80], number[80]; if (initting && (e->request_code == X_ChangeWindowAttributes) && (e->error_code == BadAccess)) { fprintf(stderr, "9wm: it looks like there's already a window manager running; 9wm not started\n"); exit(1); } if (ignore_badwindow && (e->error_code == BadWindow || e->error_code == BadColor)) return 0; XGetErrorText(d, e->error_code, msg, sizeof(msg)); sprintf(number, "%d", e->request_code); XGetErrorDatabaseText(d, "XRequest", number, "", req, sizeof(req)); if (req[0] == '\0') sprintf(req, "", e->request_code); fprintf(stderr, "9wm: %s(0x%x): %s\n", req, (int) e->resourceid, msg); if (initting) { fprintf(stderr, "9wm: failure during initialisation; aborting\n"); exit(1); } return 0; } void graberror(char *f, int err) { #ifdef DEBUG /* sick of "bug" reports; grab errors "just happen" */ char *s; switch (err) { case GrabNotViewable: s = "not viewable"; break; case AlreadyGrabbed: s = "already grabbed"; break; case GrabFrozen: s = "grab frozen"; break; case GrabInvalidTime: s = "invalid time"; break; case GrabSuccess: return; default: fprintf(stderr, "9wm: %s: grab error: %d\n", f, err); return; } fprintf(stderr, "9wm: %s: grab error: %s\n", f, s); #endif } #ifdef DEBUG_EV #include "showevent/ShowEvent.c" #endif #ifdef DEBUG void dotrace(char *s, Client * c, XEvent * e) { fprintf(stderr, "9wm: %s: c=0x%x", s, c); if (c) fprintf(stderr, " x %d y %d dx %d dy %d w 0x%x parent 0x%x", c->x, c->y, c->dx, c->dy, c->window, c->parent); #ifdef DEBUG_EV if (e) { fprintf(stderr, "\n\t"); ShowEvent(e); } #endif fprintf(stderr, "\n"); } #endif 9wm-1.3.5/event.c000066400000000000000000000227051265074177500135450ustar00rootroot00000000000000/* * Copyright (c) 2014 multiple authors, see README for licence details */ #include #include #include #include #include #include #include #include #include "dat.h" #include "fns.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, "9wm: unknown ev.type %d\n", ev.type); 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, "9wm: SelectionClear (this should not happen)\n"); break; case SelectionNotify: fprintf(stderr, "9wm: SelectionNotify (this should not happen)\n"); break; case SelectionRequest: fprintf(stderr, "9wm: SelectionRequest (this should not happen)\n"); break; case EnterNotify: enter(&ev.xcrossing); break; case ReparentNotify: reparent(&ev.xreparent); break; case FocusIn: focusin(&ev.xfocus); break; case MotionNotify: case Expose: case FocusOut: case ConfigureNotify: case MapNotify: case MappingNotify: /* * 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) { gravitate(c, 1); 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; gravitate(c, 0); if (e->value_mask & CWStackMode) { if (wc.stack_mode == Above) top(c); else e->value_mask &= ~CWStackMode; } if (c->parent != c->screen->root && c->window == e->window) { wc.x = c->x - BORDER; wc.y = c->y - BORDER; wc.width = c->dx + 2 * (BORDER - 1); wc.height = c->dy + 2 * (BORDER - 1); wc.border_width = 1; wc.sibling = None; wc.stack_mode = e->detail; XConfigureWindow(dpy, c->parent, e->value_mask, &wc); sendconfig(c); } } if (c && c->init) { wc.x = BORDER - 1; wc.y = BORDER - 1; } else { wc.x = e->x; wc.y = e->y; } wc.width = e->width; wc.height = e->height; wc.border_width = 0; wc.sibling = None; wc.stack_mode = Above; e->value_mask &= ~CWStackMode; e->value_mask |= CWBorderWidth; XConfigureWindow(dpy, e->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, "9wm: bad mapreq c %p w %x, rescanning\n", 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, "9wm: 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); setwstate(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) { Client *c; curtime = CurrentTime; c = getclient(w, 0); if (c == 0) return; 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_9wm) { cleanup(); exit(0); } else if (e->message_type == restart_9wm) { fprintf(stderr, "*** 9wm restarting ***\n"); cleanup(); execvp(myargv[0], myargv); perror("9wm: exec failed"); exit(1); } else 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, "9wm: WM_CHANGE_STATE: format %d data %ld w 0x%x\n", e->format, e->data.l[0], (int) e->window); } else if ((e->message_type == wm_moveresize) && (e->data.l[2] == 8)) { Client *c = getclient(e->window, 0); move(c); return; } else if (e->message_type == active_window) { Client *c = getclient(e->window, 0); XMapRaised(dpy, c->parent); top(c); active(c); return; } else { char *name; name = XGetAtomName(dpy, e->message_type); fprintf(stderr, "9wm: unhandled ClientMessage %s (%d), window 0x%x\n", name, (int) e->message_type, (int) e->window); XFree(name); } } 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; /* * 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; } if (a == _9wm_hold_mode) { c->hold = getiprop(c->window, _9wm_hold_mode); if (c == current) draw_border(c, 1); } else if (a == wm_colormaps) { getcmaps(c); if (c == current) cmapfocus(c); } else if (a == wm_protocols) { getproto(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)) { XGetWindowAttributes(dpy, c->window, &attr); 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(e) 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 (e->mode != NotifyGrab || e->detail != NotifyNonlinearVirtual) return; c = getclient(e->window, 0); if (c != 0 && c != current) { /* * someone grabbed the pointer; make them current */ XMapRaised(dpy, c->parent); top(c); active(c); } } 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); } } 9wm-1.3.5/fns.h000066400000000000000000000027271265074177500132210ustar00rootroot00000000000000/* Copyright (c) 1994-1996 David Hogan, see README for licence details */ #ifdef DEBUG #define trace(s, c, e) dotrace((s), (c), (e)) #else #define trace(s, c, e) #endif /* 9wm.c */ void usage(); void initscreen(); ScreenInfo *getscreen(); Time timestamp(); void sendcmessage(); void sendconfig(); void sighandler(); void getevent(); void cleanup(); /* event.c */ void mainloop(); void configurereq(); void mapreq(); void circulatereq(); void unmap(); void newwindow(); void destroy(); void clientmesg(); void cmap(); void property(); void shapenotify(); void enter(); void focusin(); void reparent(); /* manage.c */ int manage(); void scanwins(); void setshape(); void withdraw(); void gravitate(); void cmapfocus(); void cmapnofocus(); void getcmaps(); int _getprop(); char *getprop(); Window getwprop(); int getiprop(); int getwstate(); void setwstate(); void setlabel(); void getproto(); void gettrans(); /* menu.c */ void button(); void spawn(); void reshape(); void move(); void delete(); void hide(); void unhide(); void unhidec(); void renamec(); /* client.c */ void setactive(); void draw_border(); void active(); void nofocus(); void top(); Client *getclient(); void rmclient(); void dump_revert(); void dump_clients(); /* grab.c */ int menuhit(); Client *selectwin(); int sweep(); int drag(); void getmouse(); void setmouse(); /* error.c */ int handler(); void fatal(); void graberror(); void showhints(); void dotrace(); /* cursor.c */ void initcurs(ScreenInfo * s); 9wm-1.3.5/grab.c000066400000000000000000000207771265074177500133460ustar00rootroot00000000000000/* * Copyright (c) 2014 multiple authors, see README for licence details */ #include #include #include #include #include #include "dat.h" #include "fns.h" int nobuttons(XButtonEvent * e) { int state; state = (e->state & AllButtonMask); return (e->type == ButtonRelease) && (state & (state - 1)) == 0; } int grab(Window w, Window constrain, int mask, Cursor curs, int t) { int status; if (t == 0) t = timestamp(); status = XGrabPointer(dpy, w, False, mask, GrabModeAsync, GrabModeAsync, constrain, curs, t); return status; } void ungrab(XButtonEvent * e) { XEvent ev; if (!nobuttons(e)) for (;;) { XMaskEvent(dpy, ButtonMask | ButtonMotionMask, &ev); if (ev.type == MotionNotify) continue; e = &ev.xbutton; if (nobuttons(e)) break; } XUngrabPointer(dpy, e->time); curtime = e->time; } int menuhit(XButtonEvent * e, Menu * m) { XEvent ev; int i, n, cur, old, wide, high, status, drawn, warp; int x, y, dx, dy, xmax, ymax; int tx, ty; ScreenInfo *s; if (font == 0) return -1; s = getscreen(e->root); if (s == 0 || e->window == s->menuwin) /* ugly event mangling */ return -1; dx = 0; for (n = 0; m->item[n]; n++) { wide = XTextWidth(font, m->item[n], strlen(m->item[n])) + 4; if (wide > dx) dx = wide; } wide = dx; cur = m->lasthit; if (cur >= n) cur = n - 1; high = font->ascent + font->descent + 1; dy = n * high; x = e->x - wide / 2; y = e->y - cur * high - high / 2; warp = 0; xmax = DisplayWidth(dpy, s->num); ymax = DisplayHeight(dpy, s->num); if (x < 0) { e->x -= x; x = 0; warp++; } if (x + wide >= xmax) { e->x -= x + wide - xmax; x = xmax - wide; warp++; } if (y < 0) { e->y -= y; y = 0; warp++; } if (y + dy >= ymax) { e->y -= y + dy - ymax; y = ymax - dy; warp++; } if (warp) setmouse(e->x, e->y, s); XMoveResizeWindow(dpy, s->menuwin, x, y, dx, dy); XSelectInput(dpy, s->menuwin, MenuMask); XMapRaised(dpy, s->menuwin); status = grab(s->menuwin, None, MenuGrabMask, None, e->time); if (status != GrabSuccess) { /* * graberror("menuhit", status); */ XUnmapWindow(dpy, s->menuwin); return -1; } drawn = 0; for (;;) { XMaskEvent(dpy, MenuMask, &ev); switch (ev.type) { default: fprintf(stderr, "9wm: menuhit: unknown ev.type %d\n", ev.type); break; case ButtonPress: break; case ButtonRelease: if (ev.xbutton.button != e->button) break; x = ev.xbutton.x; y = ev.xbutton.y; i = y / high; if (cur >= 0 && y >= cur * high - 3 && y < (cur + 1) * high + 3) i = cur; if (x < 0 || x > wide || y < -3) i = -1; else if (i < 0 || i >= n) i = -1; else m->lasthit = i; if (!nobuttons(&ev.xbutton)) i = -1; ungrab(&ev.xbutton); XUnmapWindow(dpy, s->menuwin); return i; case MotionNotify: if (!drawn) break; x = ev.xbutton.x; y = ev.xbutton.y; old = cur; cur = y / high; if (old >= 0 && y >= old * high - 3 && y < (old + 1) * high + 3) cur = old; if (x < 0 || x > wide || y < -3) cur = -1; else if (cur < 0 || cur >= n) cur = -1; if (cur == old) break; if (old >= 0 && old < n) XFillRectangle(dpy, s->menuwin, s->gc, 0, old * high, wide, high); if (cur >= 0 && cur < n) XFillRectangle(dpy, s->menuwin, s->gc, 0, cur * high, wide, high); break; case Expose: XClearWindow(dpy, s->menuwin); for (i = 0; i < n; i++) { char *item = m->item[i]; if (i < 5) { tx = (wide - XTextWidth(font, item, strlen(item))) / 2; } else { tx = 1; } ty = i * high + font->ascent + 1; XDrawString(dpy, s->menuwin, s->gc, tx, ty, item, strlen(item)); } if (cur >= 0 && cur < n) XFillRectangle(dpy, s->menuwin, s->gc, 0, cur * high, wide, high); drawn = 1; } } } Client * selectwin(int release, int *shift, ScreenInfo * s) { XEvent ev; XButtonEvent *e; int status; Window w; Client *c; status = grab(s->root, s->root, ButtonMask, s->target, 0); if (status != GrabSuccess) { graberror("selectwin", status); /* */ return 0; } w = None; for (;;) { XMaskEvent(dpy, ButtonMask, &ev); e = &ev.xbutton; switch (ev.type) { case ButtonPress: if (e->button != Button3) { ungrab(e); return 0; } w = e->subwindow; if (!release) { c = getclient(w, 0); if (c == 0) ungrab(e); if (shift != 0) *shift = (e->state & ShiftMask) != 0; return c; } break; case ButtonRelease: ungrab(e); if (e->button != Button3 || e->subwindow != w) return 0; if (shift != 0) *shift = (e->state & ShiftMask) != 0; return getclient(w, 0); } } } void sweepcalc(Client * c, int x, int y) { int dx, dy, sx, sy; dx = x - c->x; dy = y - c->y; sx = sy = 1; if (dx < 0) { dx = -dx; sx = -1; } if (dy < 0) { dy = -dy; sy = -1; } dx -= 2 * BORDER; dy -= 2 * BORDER; if (!c->is9term) { if (dx < c->min_dx) dx = c->min_dx; if (dy < c->min_dy) dy = c->min_dy; } if (c->size.flags & PResizeInc) { dx = c->min_dx + (dx - c->min_dx) / c->size.width_inc * c->size.width_inc; dy = c->min_dy + (dy - c->min_dy) / c->size.height_inc * c->size.height_inc; } if (c->size.flags & PMaxSize) { if (dx > c->size.max_width) dx = c->size.max_width; if (dy > c->size.max_height) dy = c->size.max_height; } c->dx = sx * (dx + 2 * BORDER); c->dy = sy * (dy + 2 * BORDER); } void dragcalc(Client * c, int x, int y) { c->x = x; c->y = y; } void drawbound(Client * c) { int x, y, dx, dy; ScreenInfo *s; s = c->screen; x = c->x; y = c->y; dx = c->dx; dy = c->dy; if (dx < 0) { x += dx; dx = -dx; } if (dy < 0) { y += dy; dy = -dy; } if (dx <= 2 || dy <= 2) return; XDrawRectangle(dpy, s->root, s->gc, x, y, dx - 1, dy - 1); XDrawRectangle(dpy, s->root, s->gc, x + 1, y + 1, dx - 3, dy - 3); } void misleep(int msec) { struct timeval t; t.tv_sec = msec / 1000; t.tv_usec = (msec % 1000) * 1000; select(0, 0, 0, 0, &t); } int sweepdrag(Client * c, XButtonEvent * e0, void (*recalc) ()) { XEvent ev; int idle; int cx, cy, rx, ry; int ox, oy, odx, ody; XButtonEvent *e; ox = c->x; oy = c->y; odx = c->dx; ody = c->dy; c->x -= BORDER; c->y -= BORDER; c->dx += 2 * BORDER; c->dy += 2 * BORDER; if (e0) { c->x = cx = e0->x; c->y = cy = e0->y; recalc(c, e0->x, e0->y); } else getmouse(&cx, &cy, c->screen); XGrabServer(dpy); drawbound(c); idle = 0; for (;;) { if (XCheckMaskEvent(dpy, ButtonMask, &ev) == 0) { getmouse(&rx, &ry, c->screen); if (rx != cx || ry != cy || ++idle > 300) { drawbound(c); if (rx == cx && ry == cy) { XUngrabServer(dpy); XFlush(dpy); misleep(500); XGrabServer(dpy); idle = 0; } recalc(c, rx, ry); cx = rx; cy = ry; drawbound(c); XFlush(dpy); } misleep(50); continue; } e = &ev.xbutton; switch (ev.type) { case ButtonPress: case ButtonRelease: drawbound(c); ungrab(e); XUngrabServer(dpy); recalc(c, ev.xbutton.x, ev.xbutton.y); if (c->dx < 0) { c->x += c->dx; c->dx = -c->dx; } if (c->dy < 0) { c->y += c->dy; c->dy = -c->dy; } c->x += BORDER; c->y += BORDER; c->dx -= 2 * BORDER; c->dy -= 2 * BORDER; if (c->dx < 4 || c->dy < 4 || c->dx < c->min_dx || c->dy < c->min_dy) goto bad; return 1; } } bad: c->x = ox; c->y = oy; c->dx = odx; c->dy = ody; return 0; } int sweep(Client * c) { XEvent ev; int status; XButtonEvent *e; ScreenInfo *s; s = c->screen; status = grab(s->root, s->root, ButtonMask, s->sweep0, 0); if (status != GrabSuccess) { graberror("sweep", status); /* */ return 0; } XMaskEvent(dpy, ButtonMask, &ev); e = &ev.xbutton; if (e->button != Button3) { ungrab(e); return 0; } if (c->size.flags & (PMinSize | PBaseSize)) setmouse(e->x + c->min_dx, e->y + c->min_dy, s); XChangeActivePointerGrab(dpy, ButtonMask, s->boxcurs, e->time); return sweepdrag(c, e, sweepcalc); } int drag(Client * c) { int status; ScreenInfo *s; s = c->screen; if (c->init) setmouse(c->x - BORDER, c->y - BORDER, s); else { getmouse(&c->x, &c->y, s); /* start at current mouse pos */ c->x += BORDER; c->y += BORDER; } status = grab(s->root, s->root, ButtonMask, s->boxcurs, 0); if (status != GrabSuccess) { graberror("drag", status); /* */ return 0; } return sweepdrag(c, 0, dragcalc); } void getmouse(int *x, int *y, ScreenInfo * s) { Window dw1, dw2; int t1, t2; unsigned int t3; XQueryPointer(dpy, s->root, &dw1, &dw2, x, y, &t1, &t2, &t3); } void setmouse(int x, int y, ScreenInfo * s) { XWarpPointer(dpy, None, s->root, None, None, None, None, x, y); } 9wm-1.3.5/manage.c000066400000000000000000000230551265074177500136530ustar00rootroot00000000000000/* * Copyright (c) 2014 multiple authors, see README for licence details */ #include #include #include #include #include #include #include #include #include "dat.h" #include "fns.h" int manage(Client * c, int mapped) { int fixsize, dohide, doreshape, state; long msize; XClassHint class; XWMHints *hints; trace("manage", c, 0); XSelectInput(dpy, c->window, ColormapChangeMask | EnterWindowMask | PropertyChangeMask | FocusChangeMask); /* * Get loads of hints */ if (XGetClassHint(dpy, c->window, &class) != 0) { /* ``Success'' */ c->instance = class.res_name; c->class = class.res_class; c->is9term = (strcmp(c->class, "9term") == 0); } else { c->instance = 0; c->class = 0; c->is9term = 0; } c->iconname = getprop(c->window, XA_WM_ICON_NAME); c->name = getprop(c->window, XA_WM_NAME); setlabel(c); hints = XGetWMHints(dpy, c->window); if (XGetWMNormalHints(dpy, c->window, &c->size, &msize) == 0 || c->size.flags == 0) c->size.flags = PSize; /* not specified - punt */ getcmaps(c); getproto(c); gettrans(c); if (c->is9term) c->hold = getiprop(c->window, _9wm_hold_mode); /* * Figure out what to do with the window from hints */ if (!getwstate(c->window, &state)) state = hints ? hints->initial_state : NormalState; dohide = (state == IconicState); fixsize = 0; if ((c->size.flags & (USSize | PSize))) fixsize = 1; if ((c->size.flags & (PMinSize | PMaxSize)) == (PMinSize | PMaxSize) && c->size.min_width == c->size.max_width && c->size.min_height == c->size.max_height) fixsize = 1; doreshape = !mapped; if (fixsize) { if (c->size.flags & USPosition) doreshape = 0; if (dohide && (c->size.flags & PPosition)) doreshape = 0; if (c->trans != None) doreshape = 0; } if (c->is9term) fixsize = 0; if (c->size.flags & PBaseSize) { c->min_dx = c->size.base_width; c->min_dy = c->size.base_height; } else if (c->size.flags & PMinSize) { c->min_dx = c->size.min_width; c->min_dy = c->size.min_height; } else if (c->is9term) { c->min_dx = 100; c->min_dy = 50; } else c->min_dx = c->min_dy = 0; if (hints) XFree(hints); /* * Now do it!!! */ if (doreshape) { int xmax = DisplayWidth(dpy, c->screen->num); int ymax = DisplayHeight(dpy, c->screen->num); int x, y; getmouse(&x, &y, c->screen); c->x = x - (c->dx / 2); c->y = y - (c->dy / 2); if (c->x + c->dx > xmax) { c->x = xmax - c->dx; } if (c->x < 0) { c->x = 0; } if (c->y + c->dy > ymax) { c->y = ymax - c->dy; } if (c->y < 0) { c->y = 0; } } gravitate(c, 0); c->parent = XCreateSimpleWindow(dpy, c->screen->root, c->x - BORDER, c->y - BORDER, c->dx + 2 * (BORDER - 1), c->dy + 2 * (BORDER - 1), 1, c->screen->black, c->screen->white); XSelectInput(dpy, c->parent, SubstructureRedirectMask | SubstructureNotifyMask); if (mapped) c->reparenting = 1; if (doreshape && !fixsize) XResizeWindow(dpy, c->window, c->dx, c->dy); XSetWindowBorderWidth(dpy, c->window, 0); XReparentWindow(dpy, c->window, c->parent, BORDER - 1, BORDER - 1); #ifdef SHAPE if (shape) { XShapeSelectInput(dpy, c->window, ShapeNotifyMask); ignore_badwindow = 1; /* magic */ setshape(c); ignore_badwindow = 0; } #endif XAddToSaveSet(dpy, c->window); if (dohide) hide(c); else { XMapWindow(dpy, c->window); XMapWindow(dpy, c->parent); if (nostalgia || doreshape) active(c); else if (c->trans != None && current && current->window == c->trans) active(c); else setactive(c, 0); setwstate(c, NormalState); } if (current && (current != c)) cmapfocus(current); c->init = 1; return 1; } void scanwins(ScreenInfo * s) { unsigned int i, nwins; Client *c; Window dw1, dw2, *wins; XWindowAttributes attr; XQueryTree(dpy, s->root, &dw1, &dw2, &wins, &nwins); for (i = 0; i < nwins; i++) { XGetWindowAttributes(dpy, wins[i], &attr); if (attr.override_redirect || wins[i] == s->menuwin) continue; c = getclient(wins[i], 1); if (c != 0 && c->window == wins[i] && !c->init) { c->x = attr.x; c->y = attr.y; c->dx = attr.width; c->dy = attr.height; c->border = attr.border_width; c->screen = s; c->parent = s->root; if (attr.map_state == IsViewable) manage(c, 1); } } XFree((void *) wins); /* cast is to shut stoopid compiler up */ } void gettrans(Client * c) { Window trans; trans = None; if (XGetTransientForHint(dpy, c->window, &trans) != 0) c->trans = trans; else c->trans = None; } void withdraw(Client * c) { XUnmapWindow(dpy, c->parent); gravitate(c, 1); XReparentWindow(dpy, c->window, c->screen->root, c->x, c->y); gravitate(c, 0); XRemoveFromSaveSet(dpy, c->window); setwstate(c, WithdrawnState); /* * flush any errors */ ignore_badwindow = 1; XSync(dpy, False); ignore_badwindow = 0; } void gravitate(Client * c, int invert) { int gravity, dx, dy, delta; gravity = NorthWestGravity; if (c->size.flags & PWinGravity) gravity = c->size.win_gravity; delta = c->border - BORDER; switch (gravity) { case NorthWestGravity: dx = 0; dy = 0; break; case NorthGravity: dx = delta; dy = 0; break; case NorthEastGravity: dx = 2 * delta; dy = 0; break; case WestGravity: dx = 0; dy = delta; break; case CenterGravity: case StaticGravity: dx = delta; dy = delta; break; case EastGravity: dx = 2 * delta; dy = delta; break; case SouthWestGravity: dx = 0; dy = 2 * delta; break; case SouthGravity: dx = delta; dy = 2 * delta; break; case SouthEastGravity: dx = 2 * delta; dy = 2 * delta; break; default: fprintf(stderr, "9wm: bad window gravity %d for 0x%x\n", gravity, (int) c->window); return; } dx += BORDER; dy += BORDER; if (invert) { dx = -dx; dy = -dy; } c->x += dx; c->y += dy; } static void installcmap(ScreenInfo * s, Colormap cmap) { if (cmap == None) XInstallColormap(dpy, s->def_cmap); else XInstallColormap(dpy, cmap); } void cmapfocus(Client * c) { int i, found; Client *cc; if (c == 0) return; else if (c->ncmapwins != 0) { found = 0; for (i = c->ncmapwins - 1; i >= 0; i--) { installcmap(c->screen, c->wmcmaps[i]); if (c->cmapwins[i] == c->window) found++; } if (!found) installcmap(c->screen, c->cmap); } else if (c->trans != None && (cc = getclient(c->trans, 0)) != 0 && cc->ncmapwins != 0) cmapfocus(cc); else installcmap(c->screen, c->cmap); } void cmapnofocus(ScreenInfo * s) { installcmap(s, None); } void getcmaps(Client * c) { int n, i; Window *cw; XWindowAttributes attr; if (!c->init) { XGetWindowAttributes(dpy, c->window, &attr); c->cmap = attr.colormap; } n = _getprop(c->window, wm_colormaps, XA_WINDOW, 100L, (unsigned char **) &cw); if (c->ncmapwins != 0) { XFree((char *) c->cmapwins); free((char *) c->wmcmaps); } if (n <= 0) { c->ncmapwins = 0; return; } c->ncmapwins = n; c->cmapwins = cw; c->wmcmaps = (Colormap *) malloc(n * sizeof(Colormap)); for (i = 0; i < n; i++) { if (cw[i] == c->window) c->wmcmaps[i] = c->cmap; else { XSelectInput(dpy, cw[i], ColormapChangeMask); XGetWindowAttributes(dpy, cw[i], &attr); c->wmcmaps[i] = attr.colormap; } } } void setlabel(Client * c) { char *label, *p; if (c->iconname != 0) { label = c->iconname; } else if (c->name != 0) { label = c->name; } else if (c->instance != 0) { label = c->instance; } else if (c->class != 0) { label = c->class; } else { label = "no label"; } while ((p = strstr(label, " - "))) { label = p + 3; } if ((p = strchr(label, ':')) != 0) *p = '\0'; for (; *label == ' '; label += 1); c->label = label; } #ifdef SHAPE void setshape(Client * c) { int n, order; XRectangle *rect; /* * don't try to add a border if the window is non-rectangular */ rect = XShapeGetRectangles(dpy, c->window, ShapeBounding, &n, &order); if (n > 1) XShapeCombineShape(dpy, c->parent, ShapeBounding, BORDER - 1, BORDER - 1, c->window, ShapeBounding, ShapeSet); XFree((void *) rect); } #endif int _getprop(Window w, Atom a, Atom type, long len, unsigned char **p) { Atom real_type; int format; unsigned long n, extra; int status; status = XGetWindowProperty(dpy, w, a, 0L, len, False, type, &real_type, &format, &n, &extra, p); if (status != Success || *p == 0) return -1; if (n == 0) XFree((void *) *p); /* * could check real_type, format, extra here... */ return n; } char * getprop(Window w, Atom a) { unsigned char *p; if (_getprop(w, a, utf8_string, 100L, &p) <= 0) { return 0; } return (char *) p; } int get1prop(Window w, Atom a, Atom type) { unsigned char *p; int ret; if (_getprop(w, a, type, 1L, &p) <= 0) { return 0; } ret = (int) (unsigned long int) (*p); XFree((void *) p); return ret; } Window getwprop(Window w, Atom a) { return get1prop(w, a, XA_WINDOW); } int getiprop(Window w, Atom a) { return get1prop(w, a, XA_INTEGER); } void setwstate(Client * c, int state) { long data[2]; data[0] = (long) state; data[1] = (long) None; c->state = state; XChangeProperty(dpy, c->window, wm_state, wm_state, 32, PropModeReplace, (unsigned char *) data, 2); } int getwstate(Window w, int *state) { long *p = 0; if (_getprop(w, wm_state, wm_state, 2L, (unsigned char **) &p) <= 0) return 0; *state = (int) *p; XFree((char *) p); return 1; } void getproto(Client * c) { Atom *p; int i; long n; Window w; w = c->window; c->proto = 0; if ((n = _getprop(w, wm_protocols, XA_ATOM, 20L, (unsigned char **) &p)) <= 0) return; for (i = 0; i < n; i++) if (p[i] == wm_delete) c->proto |= Pdelete; else if (p[i] == wm_take_focus) c->proto |= Ptakefocus; XFree((char *) p); } 9wm-1.3.5/menu.c000066400000000000000000000107751265074177500133740ustar00rootroot00000000000000/* * Copyright (c) 2014 multiple authors, see README for licence details */ #include #include #include #include #include #include #include #include #include #include "dat.h" #include "fns.h" Client *hiddenc[MAXHIDDEN]; int numhidden; char *b3items[B3FIXED + MAXHIDDEN + 1] = { "New", "Reshape", "Move", "Delete", "Hide", 0, }; Menu b3menu = { b3items, }; Menu egg = { version, }; void button(XButtonEvent * e) { int n, shift; Client *c; Window dw; ScreenInfo *s; curtime = e->time; s = getscreen(e->root); if (s == 0) return; c = getclient(e->window, 0); if (c) { e->x += c->x - BORDER + 1; e->y += c->y - BORDER + 1; } else if (e->window != e->root) XTranslateCoordinates(dpy, e->window, s->root, e->x, e->y, &e->x, &e->y, &dw); switch (e->button) { case Button1: if (c) { XMapRaised(dpy, c->parent); top(c); active(c); } return; case Button2: if ((e->state & (ShiftMask | ControlMask)) == (ShiftMask | ControlMask)) { menuhit(e, &egg); } else { spawn(s, "mm mouse2"); } return; default: return; case Button3: break; } if (current && current->screen == s) cmapnofocus(s); switch (n = menuhit(e, &b3menu)) { case 0: /* New */ spawn(s, termprog); break; case 1: /* Reshape */ reshape(selectwin(1, 0, s)); break; case 2: /* Move */ move(selectwin(0, 0, s)); break; case 3: /* Delete */ shift = 0; c = selectwin(1, &shift, s); delete(c, shift); break; case 4: /* Hide */ hide(selectwin(1, 0, s)); break; default: /* unhide window */ unhide(n - B3FIXED, 1); break; case -1: /* nothing */ break; } if (current && current->screen == s) cmapfocus(current); } void spawn(ScreenInfo * s, char *prog) { if (fork() == 0) { close(ConnectionNumber(dpy)); if (s->display[0] != '\0') { putenv(s->display); } if (prog != NULL) { execl(shell, shell, "-c", prog, NULL); fprintf(stderr, "9wm: exec %s", shell); perror(" failed"); } execlp("xterm", "xterm", NULL); perror("9wm: exec xterm failed"); exit(1); } } void reshape(c) Client *c; { int odx, ody; if (c == 0) return; odx = c->dx; ody = c->dy; if (sweep(c) == 0) return; active(c); top(c); XRaiseWindow(dpy, c->parent); XMoveResizeWindow(dpy, c->parent, c->x - BORDER, c->y - BORDER, c->dx + 2 * (BORDER - 1), c->dy + 2 * (BORDER - 1)); if (c->dx == odx && c->dy == ody) sendconfig(c); else XMoveResizeWindow(dpy, c->window, BORDER - 1, BORDER - 1, c->dx, c->dy); } void move(Client *c) { if (c == 0) return; if (drag(c) == 0) return; active(c); top(c); XRaiseWindow(dpy, c->parent); XMoveWindow(dpy, c->parent, c->x - BORDER, c->y - BORDER); sendconfig(c); } void delete(c, shift) Client *c; int shift; { if (c == 0) return; if ((c->proto & Pdelete) && !shift) sendcmessage(c->window, wm_protocols, wm_delete, 0); else XKillClient(dpy, c->window); /* let event clean up */ } void hide(Client * c) { int i; if (c == 0 || numhidden == MAXHIDDEN) return; if (hidden(c)) { fprintf(stderr, "9wm: already hidden: %s\n", c->label); return; } XUnmapWindow(dpy, c->parent); XUnmapWindow(dpy, c->window); setwstate(c, IconicState); if (c == current) nofocus(); for (i = numhidden; i > 0; i -= 1) { hiddenc[i] = hiddenc[i - 1]; b3items[B3FIXED + i] = b3items[B3FIXED + i - 1]; } hiddenc[0] = c; b3items[B3FIXED] = c->label; numhidden++; } void unhide(int n, int map) { Client *c; int i; if (n >= numhidden) { fprintf(stderr, "9wm: unhide: n %d numhidden %d\n", n, numhidden); return; } c = hiddenc[n]; if (!hidden(c)) { fprintf(stderr, "9wm: unhide: not hidden: %s(0x%x)\n", c->label, (int) c->window); return; } if (map) { XMapWindow(dpy, c->window); XMapRaised(dpy, c->parent); setwstate(c, NormalState); active(c); top(c); } numhidden--; for (i = n; i < numhidden; i++) { hiddenc[i] = hiddenc[i + 1]; b3items[B3FIXED + i] = b3items[B3FIXED + i + 1]; } b3items[B3FIXED + numhidden] = 0; } void unhidec(c, map) Client *c; int map; { int i; for (i = 0; i < numhidden; i++) if (c == hiddenc[i]) { unhide(i, map); return; } fprintf(stderr, "9wm: unhidec: not hidden: %s(0x%x)\n", c->label, (int) c->window); } void renamec(c, name) Client *c; char *name; { int i; if (name == 0) name = "???"; c->label = name; if (!hidden(c)) return; for (i = 0; i < numhidden; i++) if (c == hiddenc[i]) { b3items[B3FIXED + i] = name; return; } }