diff options
Diffstat (limited to 'src/cmd/rio')
-rw-r--r-- | src/cmd/rio/9wm.man | 118 | ||||
-rw-r--r-- | src/cmd/rio/README | 203 | ||||
-rw-r--r-- | src/cmd/rio/client.c | 242 | ||||
-rw-r--r-- | src/cmd/rio/color.c | 44 | ||||
-rw-r--r-- | src/cmd/rio/cursor.c | 368 | ||||
-rw-r--r-- | src/cmd/rio/dat.h | 148 | ||||
-rw-r--r-- | src/cmd/rio/error.c | 98 | ||||
-rw-r--r-- | src/cmd/rio/event.c | 465 | ||||
-rw-r--r-- | src/cmd/rio/fns.h | 96 | ||||
-rw-r--r-- | src/cmd/rio/grab.c | 498 | ||||
-rw-r--r-- | src/cmd/rio/main.c | 437 | ||||
-rw-r--r-- | src/cmd/rio/manage.c | 482 | ||||
-rw-r--r-- | src/cmd/rio/menu.c | 258 | ||||
-rw-r--r-- | src/cmd/rio/patchlevel.h | 1 |
14 files changed, 3458 insertions, 0 deletions
diff --git a/src/cmd/rio/9wm.man b/src/cmd/rio/9wm.man new file mode 100644 index 00000000..23aa06af --- /dev/null +++ b/src/cmd/rio/9wm.man @@ -0,0 +1,118 @@ +.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). +The new +.I 9term +will request that its outline be swept using button 3 +of the mouse, by changing the cursor. +.RI ( xterm +defaults to a fixed size, and thus wants to be dragged; pressing +button 3 places it.) +.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). diff --git a/src/cmd/rio/README b/src/cmd/rio/README new file mode 100644 index 00000000..bece6c32 --- /dev/null +++ b/src/cmd/rio/README @@ -0,0 +1,203 @@ +This is David Hogan's 9wm updated to behave more like +Plan 9's rio. Since I cannot get approval for the changes +and I'd prefer not to resort to patches, I have renamed it "rio". + +Current incompatibilities that would be nice to fix: + +- Rio uses X11 fonts for the menu, and there aren't any good ones! +I'm tempted to hard-code the Plan 9 default font bitmap. + +- The command-line options should be made more like Plan 9. + +- Should work out a protocol between 9term and rio so that: + * 9term can tell rio to blue its border during hold mode + * rio can tell 9term to fade its text when it loses focus + * rio can tell 9term to unfade its text when it regains focus + +- Should change window focus on b2/b3 clicks and then + pass along the click event to the now-focused window. + +- Should change 9term to redirect b3 clicks to rio so that rio + can put up the usual b3 menu. + +The original README is below. + +- russ cox +rsc@swtch.com +20 march 2004 + + + 9wm Version 1.2 + Copyright 1994-1996 David Hogan. + +What is 9wm? +============ + +9wm is an X window manager which attempts to emulate the Plan 9 window +manager 8-1/2 as far as possible within the constraints imposed by X. +It provides a simple yet comfortable user interface, without garish +decorations or title-bars. Or icons. And it's click-to-type. This +will not appeal to everybody, but if you're not put off yet then read +on. (And don't knock it until you've tried it.) + +One major difference between 9wm and 8-1/2 is that the latter provides +windows of text with a typescript interface, and doesn't need to run a +separate program to emulate a terminal. 9wm, as an X window manager, +does require a separate program. For better 8-1/2 emulation, you should +obtain Matthew Farrow's "9term" program (ftp://ftp.cs.su.oz.au/matty/unicode), +version 1.6 or later (earlier versions don't cooperate with 9wm in +implementing "hold mode"). Of course, you can run xterm under 9wm as well. + +What is 9wm not? +================ + +9wm is not a virtual window manager. It is not customisable to any +great extent. It is not large and unwieldy, and doesn't use the X +toolkit. Requests to make it any of these things will be silently +ignored (or flamed if I have had a bad day :-) If you want tvtwm +or mwm, you know where to get them... + +Where do I get it? +================== + +The latest version of 9wm is held at ftp://ftp.cs.su.oz.au/dhog/9wm + +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 (http://www.cs.su.oz.au/~dhog/). + +Licence +======= + + 9wm is free software, and is Copyright (c) 1994-1996 by David Hogan. + Permission is granted to all sentient beings to use this software, + to make copies of it, and to distribute those copies, provided + that: + + (1) the copyright and licence notices are left intact + (2) the recipients are aware that it is free software + (3) any unapproved changes in functionality are either + (i) only distributed as patches + or (ii) distributed as a new program which is not called 9wm + and whose documentation gives credit where it is due + (4) the author is not held responsible for any defects + or shortcomings in the software, or damages caused by it. + + There is no warranty for this software. Have a nice day. + +How do I compile/install it? +============================ + +Assuming your system is correctly configured, you should only need to +run xmkmf to generate the Makefile, and then run make or make install. +make install.man should copy the manpage (9wm.man) to the appropriate +directory. + +If the make fails, complaining that the function _XShapeQueryExtension +does not exist, try removing the "-DSHAPE" from the Imakefile, and +run xmkmf and make again. + +If you don't have imake, or it is misconfigured, or you would prefer +not to use it, try copying the file "Makefile.no-imake" to "Makefile", +then edit the definitions in this Makefile to suit your system. This +may require defining suitable compilation flags for your system +(normally imake does this for you). For instance, on AIX you must +include "-DBSD_INCLUDES" in CFLAGS. + +How do I use it? +================ + +See the manual page for details. You should probably read the +man page for 9term as well. + +What if I find a bug? +===================== + +Please mail all bug reports to 9wm-bugs@plan9.cs.su.oz.au, 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 tries hard to emulate 8-1/2, but isn't 100% compatible. If +you are an experienced 8-1/2 user, please be patient with it. + +One intentional difference between 9wm and 8-1/2 is in the behaviour +of the menu when the last hidden item is unhidden. Under 8-1/2, when +the menu is next used, it pops up with "New" selected. Under 9wm, +the (new) last menu item will be selected. This is a feature. It +may be confusing if you frequently switch between 9wm and 8-1/2. +If you don't like this feature, email me for the one line fix. + +There have been some problems encountered when resizing 9term on +some platforms. This turns out to be a problem in 9term (actually +in libXg, to be precise). Newer versions of 9term should be +immune to this, see matty@cs.su.oz.au if your 9term needs fixing. + +Some client programs do weird things. One of these is Frame Maker. +It appears that if it has a modal dialog on the screen, then if any +of its windows are current, all keypresses are redirected to the +modal dialog. This is not 9wm's fault -- Frame Maker is doing this. + +Programs like Netscape Navigator like to put riddiculously long +icon name properties on their windows, of the form "Netscape: blah blah". +There is no way that I know of to stop netscape from doing this. For this +reason, 9wm truncates labels at the first colon it finds. This keeps the +button 3 menu from becoming excessively wide. Note that with same +applications, you can use an iconName resource to set the label; this +works well for "xman", whose default icon name of "Manual Browser" +is a tad too long. + +See Also +======== + +http://www.cs.su.oz.au/~dhog/ + The 9wm Home Page + +ftp://ftp.cs.su.oz.au/matty/unicode/ + for source to 9term (get README first) + +ftp://plan9.att.com/plan9/unixsrc/sam/ + for source && info on Rob Pike's editor "sam" + +ftp://rtfm.mit.edu/pub/usenet/news.answers/unix-faq/shell/rc + for information on a publically available implementation + of the Plan 9 shell "rc" for unix (or look in comp.unix.shell). + +ftp://viz.tamu.edu/pub/rc + for source to the abovementioned implementation of rc. + +http://plan9.att.com/plan9/ +http://plan9.att.com/magic/man2html/1/8%c2%bd + for information on Plan 9 (including the 8-1/2 manual entry) + +Acknowledgements +================ + +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 diff --git a/src/cmd/rio/client.c b/src/cmd/rio/client.c new file mode 100644 index 00000000..9e346558 --- /dev/null +++ b/src/cmd/rio/client.c @@ -0,0 +1,242 @@ +/* Copyright (c) 1994-1996 David Hogan, see README for licence details */ +#include <stdio.h> +#include <X11/X.h> +#include <X11/Xlib.h> +#include <X11/Xutil.h> +#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) +{ + unsigned long pixel; + + if(active){ + if(c->hold) + pixel = c->screen->activeholdborder; + else + pixel = c->screen->activeborder; + }else{ + if(c->hold) + pixel = c->screen->inactiveholdborder; + else + pixel = c->screen->inactiveborder; + } + + XSetWindowBackground(dpy, c->parent, pixel); + XClearWindow(dpy, c->parent); +} + +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: %x 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 diff --git a/src/cmd/rio/color.c b/src/cmd/rio/color.c new file mode 100644 index 00000000..8c534660 --- /dev/null +++ b/src/cmd/rio/color.c @@ -0,0 +1,44 @@ +/* Copyright (c) 2004 Russ Cox, see README for licence details */ +#include <stdio.h> +#include <signal.h> +#include <X11/X.h> +#include <X11/Xlib.h> +#include <X11/Xutil.h> +#include "dat.h" +#include "fns.h" + +unsigned long +colorpixel(Display *dpy, int depth, ulong rgb) +{ + int r, g, b; + + r = rgb>>16; + g = (rgb>>8)&0xFF; + b = rgb&0xFF; + + switch(depth){ + case 1: + case 2: + case 4: + case 8: + default: + /* not going to waste color map entries */ + if(rgb == 0xFFFFFF) + return WhitePixel(dpy, DefaultScreen(dpy)); + return BlackPixel(dpy, DefaultScreen(dpy)); + case 15: + r >>= 3; + g >>= 3; + b >>= 3; + return (r<<10) | (g<<5) | b; + case 16: + r >>= 3; + g >>= 2; + b >>= 3; + return (r<<11) | (g<<5) | b; + case 24: + case 32: + return rgb; + } +} + diff --git a/src/cmd/rio/cursor.c b/src/cmd/rio/cursor.c new file mode 100644 index 00000000..f28906f7 --- /dev/null +++ b/src/cmd/rio/cursor.c @@ -0,0 +1,368 @@ +/* Copyright (c) 1994-1996 David Hogan, see README for licence details */ +#include <stdio.h> +#include <X11/X.h> +#include <X11/Xlib.h> +#include <X11/Xutil.h> +#include "dat.h" +#include "fns.h" + +typedef struct { + int width; + int hot[2]; + unsigned char mask[64]; + unsigned char fore[64]; +} Cursordata; + +Cursordata bigarrow = { + 16, + {0, 0}, + { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x7F, 0xFF, 0x3F, + 0xFF, 0x0F, 0xFF, 0x0F, 0xFF, 0x1F, 0xFF, 0x3F, + 0xFF, 0x7F, 0xFF, 0xFF, 0xFF, 0x7F, 0xFF, 0x3F, + 0xCF, 0x1F, 0x8F, 0x0F, 0x07, 0x07, 0x03, 0x02, + }, + { 0x00, 0x00, 0xFE, 0x7F, 0xFE, 0x3F, 0xFE, 0x0F, + 0xFE, 0x07, 0xFE, 0x07, 0xFE, 0x0F, 0xFE, 0x1F, + 0xFE, 0x3F, 0xFE, 0x7F, 0xFE, 0x3F, 0xCE, 0x1F, + 0x86, 0x0F, 0x06, 0x07, 0x02, 0x02, 0x00, 0x00, + }, +}; + +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} +}; + +/* + * Grey tile pattern for root background + */ + +#define grey_width 4 +#define grey_height 2 +static char grey_bits[] = { + 0x01, 0x04, +}; + +static XColor bl, wh; + +Cursor +getcursor(c, s) +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(s) +ScreenInfo *s; +{ + XColor dummy; + + XAllocNamedColor(dpy, DefaultColormap(dpy, s->num), + "black", &bl, &dummy); + XAllocNamedColor(dpy, DefaultColormap(dpy, s->num), + "white", &wh, &dummy); + + if (nostalgia) { + s->arrow = getcursor(&blitarrow, s); + s->target = getcursor(&blittarget, s); + s->sweep0 = getcursor(&blitsweep, s); + s->boxcurs = getcursor(&blitsweep, s); + } + else { + s->arrow = getcursor(&bigarrow, s); + s->target = getcursor(&sightdata, s); + s->sweep0 = getcursor(&sweep0data, s); + s->boxcurs = getcursor(&boxcursdata, s); + } + + s->root_pixmap = XCreatePixmapFromBitmapData(dpy, + s->root, grey_bits, grey_width, grey_height, + s->black, s->white, DefaultDepth(dpy, s->num)); +} + + +/* RIO + +Cursor crosscursor = { + {-7, -7}, + {0x03, 0xC0, 0x03, 0xC0, 0x03, 0xC0, 0x03, 0xC0, + 0x03, 0xC0, 0x03, 0xC0, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0x03, 0xC0, 0x03, 0xC0, + 0x03, 0xC0, 0x03, 0xC0, 0x03, 0xC0, 0x03, 0xC0, }, + {0x00, 0x00, 0x01, 0x80, 0x01, 0x80, 0x01, 0x80, + 0x01, 0x80, 0x01, 0x80, 0x01, 0x80, 0x7F, 0xFE, + 0x7F, 0xFE, 0x01, 0x80, 0x01, 0x80, 0x01, 0x80, + 0x01, 0x80, 0x01, 0x80, 0x01, 0x80, 0x00, 0x00, } +}; + +Cursor boxcursor = { + {-7, -7}, + {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xF8, 0x1F, 0xF8, 0x1F, 0xF8, 0x1F, + 0xF8, 0x1F, 0xF8, 0x1F, 0xF8, 0x1F, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, }, + {0x00, 0x00, 0x7F, 0xFE, 0x7F, 0xFE, 0x7F, 0xFE, + 0x70, 0x0E, 0x70, 0x0E, 0x70, 0x0E, 0x70, 0x0E, + 0x70, 0x0E, 0x70, 0x0E, 0x70, 0x0E, 0x70, 0x0E, + 0x7F, 0xFE, 0x7F, 0xFE, 0x7F, 0xFE, 0x00, 0x00, } +}; + +Cursor sightcursor = { + {-7, -7}, + {0x1F, 0xF8, 0x3F, 0xFC, 0x7F, 0xFE, 0xFB, 0xDF, + 0xF3, 0xCF, 0xE3, 0xC7, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xE3, 0xC7, 0xF3, 0xCF, + 0x7B, 0xDF, 0x7F, 0xFE, 0x3F, 0xFC, 0x1F, 0xF8, }, + {0x00, 0x00, 0x0F, 0xF0, 0x31, 0x8C, 0x21, 0x84, + 0x41, 0x82, 0x41, 0x82, 0x41, 0x82, 0x7F, 0xFE, + 0x7F, 0xFE, 0x41, 0x82, 0x41, 0x82, 0x41, 0x82, + 0x21, 0x84, 0x31, 0x8C, 0x0F, 0xF0, 0x00, 0x00, } +}; + +Cursor whitearrow = { + {0, 0}, + {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFE, 0xFF, 0xFC, + 0xFF, 0xF0, 0xFF, 0xF0, 0xFF, 0xF8, 0xFF, 0xFC, + 0xFF, 0xFE, 0xFF, 0xFF, 0xFF, 0xFE, 0xFF, 0xFC, + 0xF3, 0xF8, 0xF1, 0xF0, 0xE0, 0xE0, 0xC0, 0x40, }, + {0xFF, 0xFF, 0xFF, 0xFF, 0xC0, 0x06, 0xC0, 0x1C, + 0xC0, 0x30, 0xC0, 0x30, 0xC0, 0x38, 0xC0, 0x1C, + 0xC0, 0x0E, 0xC0, 0x07, 0xCE, 0x0E, 0xDF, 0x1C, + 0xD3, 0xB8, 0xF1, 0xF0, 0xE0, 0xE0, 0xC0, 0x40, } +}; + +Cursor query = { + {-7,-7}, + {0x0f, 0xf0, 0x1f, 0xf8, 0x3f, 0xfc, 0x7f, 0xfe, + 0x7c, 0x7e, 0x78, 0x7e, 0x00, 0xfc, 0x01, 0xf8, + 0x03, 0xf0, 0x07, 0xe0, 0x07, 0xc0, 0x07, 0xc0, + 0x07, 0xc0, 0x07, 0xc0, 0x07, 0xc0, 0x07, 0xc0, }, + {0x00, 0x00, 0x0f, 0xf0, 0x1f, 0xf8, 0x3c, 0x3c, + 0x38, 0x1c, 0x00, 0x3c, 0x00, 0x78, 0x00, 0xf0, + 0x01, 0xe0, 0x03, 0xc0, 0x03, 0x80, 0x03, 0x80, + 0x00, 0x00, 0x03, 0x80, 0x03, 0x80, 0x00, 0x00, } +}; + +Cursor tl = { + {-4, -4}, + {0xfe, 0x00, 0x82, 0x00, 0x8c, 0x00, 0x87, 0xff, + 0xa0, 0x01, 0xb0, 0x01, 0xd0, 0x01, 0x11, 0xff, + 0x11, 0x00, 0x11, 0x00, 0x11, 0x00, 0x11, 0x00, + 0x11, 0x00, 0x11, 0x00, 0x11, 0x00, 0x1f, 0x00, }, + {0x00, 0x00, 0x7c, 0x00, 0x70, 0x00, 0x78, 0x00, + 0x5f, 0xfe, 0x4f, 0xfe, 0x0f, 0xfe, 0x0e, 0x00, + 0x0e, 0x00, 0x0e, 0x00, 0x0e, 0x00, 0x0e, 0x00, + 0x0e, 0x00, 0x0e, 0x00, 0x0e, 0x00, 0x00, 0x00, } +}; + +Cursor t = { + {-7, -8}, + {0x00, 0x00, 0x00, 0x00, 0x03, 0x80, 0x06, 0xc0, + 0x1c, 0x70, 0x10, 0x10, 0x0c, 0x60, 0xfc, 0x7f, + 0x80, 0x01, 0x80, 0x01, 0x80, 0x01, 0xff, 0xff, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, }, + {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, + 0x03, 0x80, 0x0f, 0xe0, 0x03, 0x80, 0x03, 0x80, + 0x7f, 0xfe, 0x7f, 0xfe, 0x7f, 0xfe, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, } +}; + +Cursor tr = { + {-11, -4}, + {0x00, 0x7f, 0x00, 0x41, 0x00, 0x31, 0xff, 0xe1, + 0x80, 0x05, 0x80, 0x0d, 0x80, 0x0b, 0xff, 0x88, + 0x00, 0x88, 0x0, 0x88, 0x00, 0x88, 0x00, 0x88, + 0x00, 0x88, 0x00, 0x88, 0x00, 0x88, 0x00, 0xf8, }, + {0x00, 0x00, 0x00, 0x3e, 0x00, 0x0e, 0x00, 0x1e, + 0x7f, 0xfa, 0x7f, 0xf2, 0x7f, 0xf0, 0x00, 0x70, + 0x00, 0x70, 0x00, 0x70, 0x00, 0x70, 0x00, 0x70, + 0x00, 0x70, 0x00, 0x70, 0x00, 0x70, 0x00, 0x00, } +}; + +Cursor r = { + {-8, -7}, + {0x07, 0xc0, 0x04, 0x40, 0x04, 0x40, 0x04, 0x58, + 0x04, 0x68, 0x04, 0x6c, 0x04, 0x06, 0x04, 0x02, + 0x04, 0x06, 0x04, 0x6c, 0x04, 0x68, 0x04, 0x58, + 0x04, 0x40, 0x04, 0x40, 0x04, 0x40, 0x07, 0xc0, }, + {0x00, 0x00, 0x03, 0x80, 0x03, 0x80, 0x03, 0x80, + 0x03, 0x90, 0x03, 0x90, 0x03, 0xf8, 0x03, 0xfc, + 0x03, 0xf8, 0x03, 0x90, 0x03, 0x90, 0x03, 0x80, + 0x03, 0x80, 0x03, 0x80, 0x03, 0x80, 0x00, 0x00, } +}; + +Cursor br = { + {-11, -11}, + {0x00, 0xf8, 0x00, 0x88, 0x00, 0x88, 0x00, 0x88, + 0x00, 0x88, 0x00, 0x88, 0x00, 0x88, 0x00, 0x88, + 0xff, 0x88, 0x80, 0x0b, 0x80, 0x0d, 0x80, 0x05, + 0xff, 0xe1, 0x00, 0x31, 0x00, 0x41, 0x00, 0x7f, }, + {0x00, 0x00, 0x00, 0x70, 0x00, 0x70, 0x00, 0x70, + 0x0, 0x70, 0x00, 0x70, 0x00, 0x70, 0x00, 0x70, + 0x00, 0x70, 0x7f, 0xf0, 0x7f, 0xf2, 0x7f, 0xfa, + 0x00, 0x1e, 0x00, 0x0e, 0x00, 0x3e, 0x00, 0x00, } +}; + +Cursor b = { + {-7, -7}, + {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xff, 0xff, 0x80, 0x01, 0x80, 0x01, 0x80, 0x01, + 0xfc, 0x7f, 0x0c, 0x60, 0x10, 0x10, 0x1c, 0x70, + 0x06, 0xc0, 0x03, 0x80, 0x00, 0x00, 0x00, 0x00, }, + {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x7f, 0xfe, 0x7f, 0xfe, 0x7f, 0xfe, + 0x03, 0x80, 0x03, 0x80, 0x0f, 0xe0, 0x03, 0x80, + 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, } +}; + +Cursor bl = { + {-4, -11}, + {0x1f, 0x00, 0x11, 0x00, 0x11, 0x00, 0x11, 0x00, + 0x11, 0x00, 0x11, 0x00, 0x11, 0x00, 0x11, 0x00, + 0x11, 0xff, 0xd0, 0x01, 0xb0, 0x01, 0xa0, 0x01, + 0x87, 0xff, 0x8c, 0x00, 0x82, 0x00, 0xfe, 0x00, }, + {0x00, 0x00, 0x0e, 0x00, 0x0e, 0x00, 0x0e, 0x00, + 0x0e, 0x00, 0x0e, 0x00, 0x0e, 0x00, 0x0e, 0x00, + 0x0e, 0x00, 0x0f, 0xfe, 0x4f, 0xfe, 0x5f, 0xfe, + 0x78, 0x00, 0x70, 0x00, 0x7c, 0x00, 0x00, 0x0, } +}; + +Cursor l = { + {-7, -7}, + {0x03, 0xe0, 0x02, 0x20, 0x02, 0x20, 0x1a, 0x20, + 0x16, 0x20, 0x36, 0x20, 0x60, 0x20, 0x40, 0x20, + 0x60, 0x20, 0x36, 0x20, 0x16, 0x20, 0x1a, 0x20, + 0x02, 0x20, 0x02, 0x20, 0x02, 0x20, 0x03, 0xe0, }, + {0x00, 0x00, 0x01, 0xc0, 0x01, 0xc0, 0x01, 0xc0, + 0x09, 0xc0, 0x09, 0xc0, 0x1f, 0xc0, 0x3f, 0xc0, + 0x1f, 0xc0, 0x09, 0xc0, 0x09, 0xc0, 0x01, 0xc0, + 0x01, 0xc0, 0x01, 0xc0, 0x01, 0xc0, 0x00, 0x00, } +}; + +Cursor *corners[9] = { + &tl, &t, &tr, + &l, nil, &r, + &bl, &b, &br, +}; + +*/ diff --git a/src/cmd/rio/dat.h b/src/cmd/rio/dat.h new file mode 100644 index 00000000..ac5ee155 --- /dev/null +++ b/src/cmd/rio/dat.h @@ -0,0 +1,148 @@ +/* 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; + int depth; + int width; + int height; + Window root; + Window menuwin; + Window sweepwin; + Colormap def_cmap; + GC gc; + GC gccopy; + GC gcred; + GC gcsweep; + GC gcmenubg; + GC gcmenubgs; + GC gcmenufg; + GC gcmenufgs; + unsigned long black; + unsigned long white; + unsigned long activeholdborder; + unsigned long inactiveholdborder; + unsigned long activeborder; + unsigned long inactiveborder; + unsigned long red; + Pixmap bkup[2]; + int min_cmaps; + Cursor target; + Cursor sweep0; + Cursor boxcurs; + Cursor arrow; + Pixmap root_pixmap; + char display[256]; /* arbitrary limit */ +}; + +/* 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 int solidsweep; + +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; + +/* 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; diff --git a/src/cmd/rio/error.c b/src/cmd/rio/error.c new file mode 100644 index 00000000..731da9fc --- /dev/null +++ b/src/cmd/rio/error.c @@ -0,0 +1,98 @@ +/* Copyright (c) 1994-1996 David Hogan, see README for licence details */ +#include <stdio.h> +#include <X11/X.h> +#include <X11/Xlib.h> +#include <X11/Xutil.h> +#include <X11/Xproto.h> +#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, "<request-code-%d>", e->request_code); + + fprintf(stderr, "9wm: %s(0x%x): %s\n", req, 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 diff --git a/src/cmd/rio/event.c b/src/cmd/rio/event.c new file mode 100644 index 00000000..1b27e85a --- /dev/null +++ b/src/cmd/rio/event.c @@ -0,0 +1,465 @@ +/* Copyright (c) 1994-1996 David Hogan, see README for licence details */ +#include <stdio.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, "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 NoExpose: + 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; + wc.height = c->dy+2*BORDER; + 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; + wc.y = BORDER; + } + 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 %x w %x, rescanning\n", + c, 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); + 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) +{ + 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); + } + if (e->message_type == restart_9wm) { + fprintf(stderr, "*** 9wm restarting ***\n"); + cleanup(); + execvp(myargv[0], myargv); + perror("9wm: exec failed"); + exit(1); + } + 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 %d w 0x%x\n", + e->format, e->data.l[0], e->window); + return; + } + fprintf(stderr, "9wm: strange ClientMessage, type 0x%x window 0x%x\n", + e->message_type, 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; + + /* 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); + } +} + +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(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); + } +} diff --git a/src/cmd/rio/fns.h b/src/cmd/rio/fns.h new file mode 100644 index 00000000..bfb9df88 --- /dev/null +++ b/src/cmd/rio/fns.h @@ -0,0 +1,96 @@ +/* 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 + +/* color.c */ +unsigned long colorpixel(Display*, int, unsigned long); + +/* main.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 getstate(); +void setstate(); +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(); diff --git a/src/cmd/rio/grab.c b/src/cmd/rio/grab.c new file mode 100644 index 00000000..233233d8 --- /dev/null +++ b/src/cmd/rio/grab.c @@ -0,0 +1,498 @@ +/* Copyright (c) 1994-1996 David Hogan, see README for licence details */ +#include <stdio.h> +#include <X11/X.h> +#include <X11/Xos.h> +#include <X11/Xlib.h> +#include <X11/Xutil.h> +#include "dat.h" +#include "fns.h" + +int +nobuttons(XButtonEvent *e) /* Einstuerzende */ +{ + 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; +} + +static void +drawstring(Display *dpy, ScreenInfo *s, Menu *m, int wide, int high, int i, int selected) +{ + int tx, ty; + + tx = (wide - XTextWidth(font, m->item[i], strlen(m->item[i])))/2; + ty = i*high + font->ascent + 1; + XFillRectangle(dpy, s->menuwin, selected ? s->gcmenubgs : s->gcmenubg, 0, i*high, wide, high); + XDrawString(dpy, s->menuwin, selected ? s->gcmenufgs : s->gcmenufg, tx, ty, m->item[i], strlen(m->item[i])); +} + +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) + drawstring(dpy, s, m, wide, high, old, 0); + if (cur >= 0 && cur < n) + drawstring(dpy, s, m, wide, high, cur, 1); + break; + case Expose: + XClearWindow(dpy, s->menuwin); + for (i = 0; i < n; i++) + drawstring(dpy, s, m, wide, high, i, cur==i); + 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; +} + +static void +xcopy(int fwd, Display *dpy, Drawable src, Drawable dst, GC gc, int x, int y, int dx, int dy, int x1, int y1) +{ + if(fwd) + XCopyArea(dpy, src, dst, gc, x, y, dx, dy, x1, y1); + else + XCopyArea(dpy, dst, src, gc, x1, y1, dx, dy, x, y); +} + +void +drawbound(Client *c, int drawing) +{ + 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; + + if(solidsweep){ + if(drawing == -1){ + XUnmapWindow(dpy, s->sweepwin); + return; + } + + x += BORDER; + y += BORDER; + dx -= 2*BORDER; + dy -= 2*BORDER; + + if(drawing){ + XMoveResizeWindow(dpy, s->sweepwin, x, y, dx, dy); + XSelectInput(dpy, s->sweepwin, MenuMask); + XMapRaised(dpy, s->sweepwin); + } + return; + } + + if(drawing == -1) + return; + + xcopy(drawing, dpy, s->root, s->bkup[0], s->gccopy, x, y, dx, BORDER, 0, 0); + xcopy(drawing, dpy, s->root, s->bkup[0], s->gccopy, x, y+dy-BORDER, dx, BORDER, dx, 0); + xcopy(drawing, dpy, s->root, s->bkup[1], s->gccopy, x, y, BORDER, dy, 0, 0); + xcopy(drawing, dpy, s->root, s->bkup[1], s->gccopy, x+dx-BORDER, y, BORDER, dy, 0, dy); + + if(drawing){ + XFillRectangle(dpy, s->root, s->gcred, x, y, dx, BORDER); + XFillRectangle(dpy, s->root, s->gcred, x, y+dy-BORDER, dx, BORDER); + XFillRectangle(dpy, s->root, s->gcred, x, y, BORDER, dy); + XFillRectangle(dpy, s->root, s->gcred, x+dx-BORDER, y, BORDER, dy); + } +} + +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)(Client*, int, int)) +{ + 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, 1); + idle = 0; + for (;;) { + if (XCheckMaskEvent(dpy, ButtonMask, &ev) == 0) { + getmouse(&rx, &ry, c->screen); + if (rx != cx || ry != cy || ++idle > 300) { + drawbound(c, 0); + 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, 1); + XFlush(dpy); + } + misleep(50); + continue; + } + e = &ev.xbutton; + switch (ev.type) { + case ButtonPress: + case ButtonRelease: + drawbound(c, 0); + ungrab(e); + XUngrabServer(dpy); + if (e->button != Button3 && c->init) + goto bad; + 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; + drawbound(c, -1); + 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); +} diff --git a/src/cmd/rio/main.c b/src/cmd/rio/main.c new file mode 100644 index 00000000..d9bec822 --- /dev/null +++ b/src/cmd/rio/main.c @@ -0,0 +1,437 @@ +/* Copyright (c) 1994-1996 David Hogan, see README for licence details */ +#include <stdio.h> +#include <signal.h> +#include <errno.h> +#include <X11/X.h> +#include <X11/Xos.h> +#include <X11/Xlib.h> +#include <X11/Xutil.h> +#include <X11/Xatom.h> +#include "dat.h" +#include "fns.h" +#include "patchlevel.h" + +char *version[] = +{ + "rio version 1.0, Copyright (c) 1994-1996 David Hogan, (c) 2004 Russ Cox", 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; +int solidsweep = 0; + +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 _9wm_running; +Atom _9wm_hold_mode; + +char *fontlist[] = { + "lucm.latin1.9", + "blit", + "lucidasanstypewriter-bold-10", + "9x15bold", + "fixed", + "*", + 0, +}; + +void +usage(void) +{ + fprintf(stderr, "usage: rio [-grey] [-version] [-font fname] [-term prog] [exit|restart]\n"); + exit(1); +} + +int +main(int argc, char *argv[]) +{ + int i, background, do_exit, do_restart; + char *fname; + int shape_event, dummy; + + myargv = argv; /* for restart */ + + do_exit = do_restart = 0; + background = 1; + font = 0; + fname = 0; + for (i = 1; i < argc; i++) + if (strcmp(argv[i], "-nostalgia") == 0) + nostalgia++; + else if (strcmp(argv[i], "-grey") == 0) + background = 1; + 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", version[0]); + if (PATCHLEVEL > 0) + fprintf(stderr, "; patch level %d", PATCHLEVEL); + fprintf(stderr, "\n"); + 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); + + 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); + _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) { + _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, background); + + /* 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); +} + +void +initscreen(ScreenInfo *s, int i, int background) +{ + 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)); + s->depth = DefaultDepth(dpy, i); + + ds = DisplayString(dpy); + colon = rindex(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 = index(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->activeholdborder = colorpixel(dpy, s->depth, 0x000099); + s->inactiveholdborder = colorpixel(dpy, s->depth, 0x005DBB); + s->activeborder = colorpixel(dpy, s->depth ,0x55AAAA); + s->inactiveborder = colorpixel(dpy, s->depth, 0x9EEEEE); + s->red = colorpixel(dpy, s->depth, 0xDD0000); + s->black = BlackPixel(dpy, i); + s->white = WhitePixel(dpy, i); + s->width = WidthOfScreen(ScreenOfDisplay(dpy, i)); + s->height = HeightOfScreen(ScreenOfDisplay(dpy, i)); + s->bkup[0] = XCreatePixmap(dpy, s->root, 2*s->width, BORDER, DefaultDepth(dpy, i)); + s->bkup[1] = XCreatePixmap(dpy, s->root, BORDER, 2*s->height, DefaultDepth(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); + + gv.function = GXcopy; + s->gccopy = XCreateGC(dpy, s->root, mask, &gv); + + gv.foreground = s->red; + s->gcred = XCreateGC(dpy, s->root, mask, &gv); + + gv.foreground = colorpixel(dpy, s->depth, 0xEEEEEE); + s->gcsweep = XCreateGC(dpy, s->root, mask, &gv); + + gv.foreground = colorpixel(dpy, s->depth, 0xE9FFE9); + s->gcmenubg = XCreateGC(dpy, s->root, mask, &gv); + + gv.foreground = colorpixel(dpy, s->depth, 0x448844); + s->gcmenubgs = XCreateGC(dpy, s->root, mask, &gv); + + gv.foreground = s->black; + gv.background = colorpixel(dpy, s->depth, 0xE9FFE9); + s->gcmenufg = XCreateGC(dpy, s->root, mask, &gv); + + gv.foreground = colorpixel(dpy, s->depth, 0xE9FFE9); + gv.background = colorpixel(dpy, s->depth, 0x448844); + s->gcmenufgs = 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); + + if (background) { +/* + XSetWindowBackgroundPixmap(dpy, s->root, s->root_pixmap); + XClearWindow(dpy, s->root); +*/ + system("xsetroot -solid grey30"); + } + s->menuwin = XCreateSimpleWindow(dpy, s->root, 0, 0, 1, 1, 2, colorpixel(dpy, s->depth, 0xAAFFAA), colorpixel(dpy, s->depth, 0xE9FFE9)); + s->sweepwin = XCreateSimpleWindow(dpy, s->root, 0, 0, 1, 1, 4, s->red, colorpixel(dpy, s->depth, 0xEEEEEE)); +} + +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(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); + FD_SET(fd, &rfds); + if (select(fd+1, &rfds, NULL, NULL, NULL) == 1) { + XNextEvent(dpy, e); + return; + } + if (errno != EINTR || !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); +} diff --git a/src/cmd/rio/manage.c b/src/cmd/rio/manage.c new file mode 100644 index 00000000..3384daf2 --- /dev/null +++ b/src/cmd/rio/manage.c @@ -0,0 +1,482 @@ +/* Copyright (c) 1994-1996 David Hogan, see README for licence details */ +#include <stdio.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" + +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 (!getstate(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) { + if (current && current->screen == c->screen) + cmapnofocus(c->screen); + if (!c->is9term && c->x==0 && c->y==0) { + static int nwin; + + c->x = 20*nwin+BORDER; + c->y = 20*nwin+BORDER; + nwin++; + nwin %= 10; + } + + if (c->is9term && !(fixsize ? drag(c) : sweep(c))) { + XKillClient(dpy, c->window); + rmclient(c); + if (current && current->screen == c->screen) + cmapfocus(current); + return 0; + } + } + else + gravitate(c, 0); + + c->parent = XCreateSimpleWindow(dpy, c->screen->root, + c->x - BORDER, c->y - BORDER, + c->dx + 2*BORDER, c->dy + 2*BORDER, + 0, 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, BORDER); +#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); + XUnmapWindow(dpy, c->screen->sweepwin); + if (nostalgia || doreshape) + active(c); + else if (c->trans != None && current && current->window == c->trans) + active(c); + else + setactive(c, 0); + setstate(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); + setstate(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, 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"; + if ((p = index(label, ':')) != 0) + *p = '\0'; + 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, BORDER, + 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, XA_STRING, 100L, &p) <= 0) + return 0; + return (char *)p; +} + +int +get1prop(Window w, Atom a, Atom type) +{ + char **p, *x; + + if (_getprop(w, a, type, 1L, (unsigned char**)&p) <= 0) + return 0; + x = *p; + XFree((void*) p); + return (int)x; +} + +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 +setstate(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 +getstate(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); +} diff --git a/src/cmd/rio/menu.c b/src/cmd/rio/menu.c new file mode 100644 index 00000000..54453954 --- /dev/null +++ b/src/cmd/rio/menu.c @@ -0,0 +1,258 @@ +/* Copyright (c) 1994-1996 David Hogan, see README for licence details */ +#include <stdio.h> +#include <signal.h> +#include <X11/X.h> +#include <X11/Xlib.h> +#include <X11/Xutil.h> +#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; + e->y += c->y - BORDER; + } + 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); + return; + default: + return; + case Button3: + break; + } + + if (current && current->screen == s) + cmapnofocus(s); + switch (n = menuhit(e, &b3menu)) { + case 0: /* New */ + spawn(s); + 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) +{ + /* + * ugly dance to avoid leaving zombies. Could use SIGCHLD, + * but it's not very portable. + */ + if (fork() == 0) { + if (fork() == 0) { + close(ConnectionNumber(dpy)); + if (s->display[0] != '\0') + putenv(s->display); + if (termprog != NULL) { + execl(shell, shell, "-c", termprog, 0); + fprintf(stderr, "9wm: exec %s", shell); + perror(" failed"); + } + execlp("9term", "9term", "-w", 0); + execlp("xterm", "xterm", "-ut", 0); + perror("9wm: exec 9term/xterm failed"); + exit(1); + } + exit(0); + } + wait((int *) 0); +} + +void +reshape(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, c->dy+2*BORDER); + if (c->dx == odx && c->dy == ody) + sendconfig(c); + else + XMoveResizeWindow(dpy, c->window, BORDER, BORDER, 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(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) +{ + 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); + setstate(c, IconicState); + if (c == current) + nofocus(); + hiddenc[numhidden] = c; + b3items[B3FIXED+numhidden] = c->label; + numhidden++; + b3items[B3FIXED+numhidden] = 0; +} + +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, c->window); + return; + } + + if (map) { + XMapWindow(dpy, c->window); + XMapRaised(dpy, c->parent); + setstate(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(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, c->window); +} + +void +renamec(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; + } +} diff --git a/src/cmd/rio/patchlevel.h b/src/cmd/rio/patchlevel.h new file mode 100644 index 00000000..935ec354 --- /dev/null +++ b/src/cmd/rio/patchlevel.h @@ -0,0 +1 @@ +#define PATCHLEVEL 0 |