first commit

This commit is contained in:
Iris Lightshard 2019-12-02 13:23:00 -05:00
commit 794fc2bc71
Signed by: Iris Lightshard
GPG key ID: 3B7FBC22144E6398
31 changed files with 7883 additions and 0 deletions

2
.gitignore vendored Normal file
View file

@ -0,0 +1,2 @@
*.o
ryudo

258
README.md Executable file
View file

@ -0,0 +1,258 @@
# [[ RYUDO ]]
## the minimalist floatiling window manager that flows
-- Derek Stevens <drkste@zoho.com> 2019 --
### About
Ryudo is a fork of Russ Cox's Rio, itself a fork of David Hogan's 9wm.
The primary additions I've made are:
- URxvt is detected as a proper terminal program for sweeping out new windows
- URxvt is the default terminal emulator (still tries 9term and then xterm if no dice)
- Customizable colors, borders, fonts, and keybinds in config.h
- Default keybindings:
+ New Terminal: Super+Slash
+ Destroy: Super+D
+ Iconify: Super+I
+ Maximize: Super+M
+ moVe: Super+V
+ Reshape: Super+R
+ Snap Left: Super+H
+ Snap Right: Super+L
+ Snap Top: Super+K
+ Snap Bottom: Super+J
+ Snap Top-Left: Super+Q
+ Snap Bottom-Left: Super+W
+ Snap Bottom-Right: Super+O
+ Snap Top-Right: Super+P
+ Snap Floating-Center: Super+C
+ Virtual Desk++: Super+Right
+ Virtual Desk--: Super+Left
The name "Ryudo" is a nod to "Rio" and a Japanese word for "flow."
Using Ryudo should feel very natural -- you can do things with keyboard or
mouse depending on the situation. Terminal launching can be done with mouse
using the popup menu, or using the keyboar, which will spawn a terminal
window centered taking up 9/25 of the screen (3/5 width, 3/5 height).
### Dependencies, Building, Installation
Being forked from Rio, Ryudo requires **plan9port**, **Xlib**, and **Xt**.
Make it with **mk ryudo** and then copy the resulting executable **ryudo** to
somewhere in your **PATH**
If you try to install it with **mk install** it will probably install
to **$PLAN9/bin/** under the name **rio**. This is less than ideal but I'm
not a master of mk, so my protocol is to use a mk target **ryudo** which
builds the program as **o.rio**, then calls **ryudomagic.sh** to rename
the program.
If you have trouble building, you might need to edit the **mkfile** at line 2
to point to the proper location of your plan9port's **mkwsysrules.sh**.
### Bugs and Caveats
Of the bugs and caveats not already mentioned in Rio's readme:
- Rendering of windows with RGBA surfaces is bound to RGB space (xshove and transset can be leveraged to get transparent terminals if you want it)
- Since maximization doesn't use the EWM Hint for maximization, programs like Firefox will remember their window size as the maximized size and probably start offset so they aren't completely onscreen. There is probably a rule we can put in newwindow() to mitigate this, but it's not super important.
- Probably more!
### Legacy
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:
- 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
- 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.
Axel Belinfante contributed the code to handle border grabbing
for resize and various other improvements.
The original README is below.
- russ cox
rsc@swtch.com
30 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

285
client.c Executable file
View file

@ -0,0 +1,285 @@
/* Copyright (c) 1994-1996 David Hogan, see README for licence details */
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.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)
{
/* dbg("setactive client %x %d", c->window, c->on); */
if(c->parent == c->screen->root)
return;
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, 1);
cmapfocus(c);
}else{
if(c->proto & Plosefocus)
sendcmessage(c->window, wm_protocols, wm_lose_focus, 0, 1);
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;
}
if(debug) fprintf(stderr, "draw_border %p pixel %ld active %d hold %d\n", (void*)c, pixel, active, c->hold);
XSetWindowBackground(dpy, c->parent, pixel);
XClearWindow(dpy, c->parent);
}
void
active(Client *c)
{
Client *cc;
if(c == 0){
fprintf(stderr, "ryudo: 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/*|CWColormap*/;
attr.override_redirect = 1;
/* attr.colormap = screens[0].def_cmap;*/
w = XCreateWindow(dpy, screens[0].root, 0, 0, 1, 1, 0,
0 /*screens[0].depth*/, InputOnly, screens[0].vis, 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, "rio: %p not on client list in top()\n", (void*)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;
c->virt = virt;
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 : "?", (int)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", (int)c->window, (int)c->parent, c->x, c->y);
}
#endif
void
shuffle(int up)
{
Client **l, *c;
if(clients == 0 || clients->next == 0)
return;
if(!up){
c = 0;
/*for(c=clients; c->next; c=c->next) */
/* ; */
for(l=&clients; (*l)->next; l=&(*l)->next)
if ((*l)->state == 1)
c = *l;
if (c == 0)
return;
XMapRaised(dpy, c->parent);
top(c);
active(c);
}else{
c = clients;
for(l=&clients; *l; l=&(*l)->next)
;
clients = c->next;
*l = c;
c->next = 0;
XLowerWindow(dpy, c->window);
}
/* XMapRaised(dpy, clients->parent); */
/* top(clients); */
/* active(clients); */
}

45
color.c Executable file
View file

@ -0,0 +1,45 @@
/* 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, ScreenInfo *s, int depth, unsigned long rgb, unsigned long def)
{
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 */
return def;
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:
/* try to find byte order */
if(s->vis->red_mask & 0xff)
return (r) | (g<<8) | (b<<16); /* OK on Sun */
return rgb;
}
}

39
config.h Executable file
View file

@ -0,0 +1,39 @@
#define SHOLDCOL 0xC8C8C8
#define HOLDCOL 0x444444
#define SBORDERCOL 0x1F9B92
#define BORDERCOL 0x000000
#define GHOSTCOL 0x797979
#define BORDER 4
#define MENUBORDER 0
#define MBORDERCOL 0x000000
#define MENUFGCOL 0x797979
#define MENUBGCOL 0x000000
#define SMENUFGCOL 0x000000
#define SMENUBGCOL 0x797979
#define SHORTCUTMOD Mod4Mask
#define MODBITS (1<<6)
#define MAX_KEY XK_m
#define ICON_KEY XK_i
#define MOVE_KEY XK_v
#define RESIZE_KEY XK_r
#define DESTROY_KEY XK_d
#define SNAPLEFT_KEY XK_h
#define SNAPRIGHT_KEY XK_l
#define SNAPTOP_KEY XK_k
#define SNAPBOTTOM_KEY XK_j
#define SNAPTOPLEFT_KEY XK_q
#define SNAPBOTTOMLEFT_KEY XK_w
#define SNAPBOTTOMRIGHT_KEY XK_o
#define SNAPTOPRIGHT_KEY XK_p
#define SNAPCENTER_KEY XK_c
#define NEXTVIRT_KEY XK_Right
#define PREVVIRT_KEY XK_Left
#define LAUNCH_KEY XK_slash

381
cursor.c Executable file
View file

@ -0,0 +1,381 @@
/* 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, s->depth);
s->bordcurs[BorderN] = XCreateFontCursor(dpy, 138);
s->bordcurs[BorderNNE] = XCreateFontCursor(dpy, 136);
s->bordcurs[BorderENE] = s->bordcurs[BorderNNE] ;
s->bordcurs[BorderE] = XCreateFontCursor(dpy, 96);
s->bordcurs[BorderESE] = XCreateFontCursor(dpy, 14);
s->bordcurs[BorderSSE] = s->bordcurs[BorderESE];
s->bordcurs[BorderS] = XCreateFontCursor(dpy, 16);
s->bordcurs[BorderSSW] = XCreateFontCursor(dpy, 12);
s->bordcurs[BorderWSW] = s->bordcurs[BorderSSW];
s->bordcurs[BorderW] = XCreateFontCursor(dpy, 70);
s->bordcurs[BorderWNW] = XCreateFontCursor(dpy, 134);
s->bordcurs[BorderNNW] = s->bordcurs[BorderWNW];
}
/* 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
};
*/

191
dat.h Executable file
View file

@ -0,0 +1,191 @@
/* Copyright (c) 1994-1996 David Hogan, see README for licence details */
#ifndef BORDER
#define BORDER _border
#endif
#define CORNER _corner
#define INSET _inset
#define MAXHIDDEN 128
#define B3FIXED 5
#define NUMVIRTUALS 12
#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;
int virt;
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
#define Plosefocus 4
struct Menu {
char **item;
char *(*gen)();
int lasthit;
};
enum BorderOrient {
BorderUnknown = 0, /* we depend on this!*/
BorderN,
BorderNNE,
BorderENE,
BorderE,
BorderESE,
BorderSSE,
BorderS,
BorderSSW,
BorderWSW,
BorderW,
BorderWNW,
BorderNNW,
NBorder
};
typedef enum BorderOrient BorderOrient;
struct ScreenInfo {
int num;
int depth;
Visual *vis;
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;
Cursor bordcurs[NBorder];
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 _corner;
extern int _inset;
extern int curtime;
extern int debug;
extern int solidsweep;
extern int numvirtuals;
extern int scrolling;
extern int ffm; /* focus follows mouse */
extern Atom exit_rio;
extern Atom restart_rio;
extern Atom wm_state;
extern Atom wm_change_state;
extern Atom _rio_hold_mode;
extern Atom wm_protocols;
extern Atom wm_delete;
extern Atom wm_take_focus;
extern Atom wm_lose_focus;
extern Atom wm_colormaps;
extern Atom wm_state_fullscreen;
extern Atom wm_state;
/* client.c */
extern Client *clients;
extern Client *current;
extern Client *currents[];
/* menu.c */
extern Client *hiddenc[];
extern int numhidden;
extern char *b2items[];
extern Menu b2menu;
extern char *b3items[];
extern Menu b3menu;
extern int virt;
/* manage.c */
extern int isNew;
/* error.c */
extern int ignore_badwindow;
/* key.c and event.c share this */
extern int kbLaunch;

102
error.c Executable file
View file

@ -0,0 +1,102 @@
/* Copyright (c) 1994-1996 David Hogan, see README for licence details */
#include <stdio.h>
#include <stdlib.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, "ryudo: ");
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, "ryudo: it looks like there's already a window manager running; ryudo 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>", (int)e->request_code);
fprintf(stderr, "ryudo: %s(0x%x): %s\n", req, (int)e->resourceid, msg);
if(initting){
fprintf(stderr, "ryudo: 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, "ryudo: %s: grab error: %d\n", f, err);
return;
}
fprintf(stderr, "ryudo: %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)
{
if(debug == 0)
return;
setbuf(stdout, 0);
fprintf(stderr, "ryudo: %s: c=%p", s, (void*)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, (int)c->window, (int)c->parent);
#ifdef DEBUG_EV
if(e){
fprintf(stderr, "\n\t");
ShowEvent(e);
}
#endif
fprintf(stderr, "\n");
}
#endif

619
event.c Executable file
View file

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

118
fns.h Executable file
View file

@ -0,0 +1,118 @@
/* 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
#define setstate setstaterio
/* color.c */
unsigned long colorpixel(Display*, ScreenInfo*, int, unsigned long, 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 leave();
void focusin();
void reparent();
void motionnotify();
BorderOrient borderorient();
/* 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();
/* key.c */
void keypress();
void keyrelease();
void keysetup();
void quickreshape();
/* menu.c */
void button();
void spawn();
void reshape();
void move();
void delete();
void hide();
void unhide();
void unhidec();
void renamec();
void button2();
void initb2menu();
void switch_to();
void switch_to_c();
/* client.c */
void setactive();
void draw_border();
void active();
void nofocus();
void top();
Client *getclient();
void rmclient();
void dump_revert();
void dump_clients();
void shuffle(int);
/* grab.c */
int menuhit();
Client *selectwin();
int sweep();
int drag();
int pull();
void getmouse();
void setmouse();
/* error.c */
int handler();
void fatal();
void graberror();
void showhints();
void dotrace();
/* cursor.c */
void initcurs();
void ShowEvent(XEvent*);

675
grab.c Executable file
View file

@ -0,0 +1,675 @@
/* 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;
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, "ryudo: 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);
}
}
}
int
sweepcalc(Client *c, int x, int y, BorderOrient bl, int ignored)
{
int dx, dy, sx, sy;
dx = x - c->x;
dy = y - c->y;
sx = sy = 1;
x += dx;
if(dx < 0){
dx = -dx;
sx = -1;
}
y += dy;
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);
return ignored;
}
int
dragcalc(Client *c, int x, int y, BorderOrient bl, int ignored)
{
c->x += x;
c->y += y;
return ignored;
}
int
pullcalc(Client *c, int x, int y, BorderOrient bl, int init)
{
int dx, dy, sx, sy, px, py, spx, spy, rdx, rdy, xoff, yoff, xcorn, ycorn;
px = c->x;
py = c->y;
dx = c->dx;
dy = c->dy;
sx = sy = 1;
spx = spy = 0;
xoff = yoff = 0;
xcorn = ycorn = 0;
switch(bl){
case BorderN:
py = y;
dy = (c->y + c->dy) - y;
spy = 1;
yoff = y - c->y;
break;
case BorderS:
dy = y - c->y;
yoff = (c->y + c->dy) - y;
break;
case BorderE:
dx = x - c->x;
xoff = (c->x + c->dx) - x;
break;
case BorderW:
px = x;
dx = (c->x + c->dx) - x;
spx = 1;
xoff = x - c->x;
break;
case BorderNNW:
case BorderWNW:
px = x;
dx = (c->x + c->dx) - x;
spx = 1;
py = y;
dy = (c->y + c->dy) - y;
spy = 1;
xoff = x - c->x;
yoff = y - c->y;
break;
case BorderNNE:
case BorderENE:
dx = x - c->x;
py = y;
dy = (c->y + c->dy) - y;
spy = 1;
xoff = (c->x + c->dx) - x;
yoff = y - c->y;
break;
case BorderSSE:
case BorderESE:
dx = x - c->x;
dy = y - c->y;
xoff = (c->x + c->dx) - x;
yoff = (c->y + c->dy) - y;
break;
case BorderSSW:
case BorderWSW:
px = x;
dx = (c->x + c->dx) - x;
spx = 1;
dy = y - c->y;
xoff = x - c->x;
yoff = (c->y + c->dy) - y;
break;
default:
break;
}
switch(bl){
case BorderNNW:
case BorderNNE:
case BorderSSW:
case BorderSSE:
xcorn = 1;
break;
case BorderWNW:
case BorderENE:
case BorderWSW:
case BorderESE:
ycorn = 1;
break;
}
if(!init
|| xoff < 0 || (xcorn && xoff > CORNER) || (!xcorn && xoff > BORDER)
|| yoff < 0 || (ycorn && yoff > CORNER) || (!ycorn && yoff > BORDER)){
xoff = 0;
yoff = 0;
init = 0;
}
if(debug) fprintf(stderr, "c %dx%d+%d+%d m +%d+%d r %dx%d+%d+%d sp (%d,%d) bl %d\n",
c->dx, c->dy, c->x, c->y, x, y, dx, dy, px, py, spx, spy, bl);
if(dx < 0){
dx = -dx;
sx = -1;
}
if(dy < 0){
dy = -dy;
sy = -1;
}
/* remember requested size;
* after applying size hints we may have to correct position
*/
rdx = sx*dx;
rdy = sy*dy;
/* apply size hints */
dx -= (2*BORDER - xoff);
dy -= (2*BORDER - yoff);
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;
}
/* set size and position */
c->dx = sx*(dx + 2*BORDER );
c->dy = sy*(dy + 2*BORDER );
c->x = px;
c->y = py;
/* compensate position for size changed due to size hints */
if(spx)
c->x -= c->dx - rdx;
if(spy)
c->y -= c->dy - rdy;
return init;
}
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;
if(debug) fprintf(stderr, "drawbound %d %dx%d+%d+%d\n", drawing, c->dx, c->dy, c->x, c->y);
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, int but, XButtonEvent *e0, BorderOrient bl, int (*recalc)(Client*, int, int, BorderOrient, int))
{
XEvent ev;
int idle;
int cx, cy, rx, ry;
int ox, oy, odx, ody;
XButtonEvent *e;
int notmoved;
notmoved = 1;
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(bl != BorderUnknown || e0 == 0)
getmouse(&cx, &cy, c->screen);
else
getmouse(&c->x, &c->y, c->screen);
XGrabServer(dpy);
if(bl != BorderUnknown){
notmoved = recalc(c, cx, cy, bl, notmoved);
}
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;
}
if(e0 || bl != BorderUnknown)
notmoved = recalc(c, rx, ry, bl, notmoved);
else
notmoved = recalc(c, rx-cx, ry-cy, bl, notmoved);
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 != but && c->init)
goto bad;
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:
if(debug) fprintf(stderr, "sweepdrag bad\n");
c->x = ox;
c->y = oy;
c->dx = odx;
c->dy = ody;
drawbound(c, -1);
return 0;
}
int
sweep(Client *c, int but, XButtonEvent *ignored)
{
XEvent ev;
int status;
XButtonEvent *e;
ScreenInfo *s;
s = c->screen;
c->dx = 0;
c->dy = 0;
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 != but){
ungrab(e);
return 0;
}
XChangeActivePointerGrab(dpy, ButtonMask, s->boxcurs, e->time);
return sweepdrag(c, but, e, BorderUnknown, sweepcalc);
}
int
pull(Client *c, int but, XButtonEvent *e)
{
int status;
ScreenInfo *s;
BorderOrient bl;
bl = borderorient(c, e->x, e->y);
/* assert(bl > BorderUnknown && bl < NBorder); */
s = c->screen;
status = grab(s->root, s->root, ButtonMask, s->bordcurs[bl], 0);
if(status != GrabSuccess){
graberror("pull", status); /* */
return 0;
}
return sweepdrag(c, but, 0, bl, pullcalc);
}
int
drag(Client *c, int but)
{
int status;
ScreenInfo *s;
s = c->screen;
status = grab(s->root, s->root, ButtonMask, s->boxcurs, 0);
if(status != GrabSuccess){
graberror("drag", status); /* */
return 0;
}
return sweepdrag(c, but, 0, BorderUnknown, 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);
if(debug) fprintf(stderr, "getmouse: %d %d\n", *x, *y);
}
void
setmouse(int x, int y, ScreenInfo *s)
{
XWarpPointer(dpy, None, s->root, None, None, None, None, x, y);
}

210
key.c Executable file
View file

@ -0,0 +1,210 @@
/*
* Copyright (c) 2019 Derek Stevens, 2005 Russ Cox, 1994-1996 David Hogan
* see README for license details
*/
#include <stdio.h>
#include <stdlib.h>
#include <signal.h>
#include <X11/X.h>
#include <X11/Xos.h>
#include <X11/Xlib.h>
#include <X11/Xutil.h>
#include <X11/Xatom.h>
#include <X11/keysym.h>
#include <X11/extensions/shape.h>
#include "config.h"
#include "dat.h"
#include "fns.h"
#include "patchlevel.h"
enum
{
GrabAltTab,
GrabAltAny
};
/*static int tabcode = 0x17; */
/*static int altcode = 0x40; */
/*static int pgupcode = 0x63; */
/*static int pgdowncode = 0x69; */
static void alttab(int shift);
void quickreshape(Client*c, int x, int y, int dx, int dy);
void
keysetup(void)
{
int i;
int tabcode = XKeysymToKeycode(dpy, XK_Tab);
int dcode = XKeysymToKeycode(dpy, DESTROY_KEY);
int icode = XKeysymToKeycode(dpy, ICON_KEY);
int mcode = XKeysymToKeycode(dpy, MAX_KEY);
int vcode = XKeysymToKeycode(dpy, MOVE_KEY);
int rcode = XKeysymToKeycode(dpy, RESIZE_KEY);
int hcode = XKeysymToKeycode(dpy, SNAPLEFT_KEY);
int lcode = XKeysymToKeycode(dpy, SNAPRIGHT_KEY);
int jcode = XKeysymToKeycode(dpy, SNAPBOTTOM_KEY);
int kcode = XKeysymToKeycode(dpy, SNAPTOP_KEY);
int qcode = XKeysymToKeycode(dpy, SNAPTOPLEFT_KEY);
int wcode = XKeysymToKeycode(dpy, SNAPBOTTOMLEFT_KEY);
int ocode = XKeysymToKeycode(dpy, SNAPBOTTOMRIGHT_KEY);
int pcode = XKeysymToKeycode(dpy, SNAPTOPRIGHT_KEY);
int ccode = XKeysymToKeycode(dpy, SNAPCENTER_KEY);
int slcode = XKeysymToKeycode(dpy, LAUNCH_KEY);
int rightcode = XKeysymToKeycode(dpy, NEXTVIRT_KEY);
int leftcode = XKeysymToKeycode(dpy, PREVVIRT_KEY);
for(i=0; i<num_screens; i++){
XGrabKey(dpy, tabcode, Mod1Mask, screens[i].root, 0, GrabModeSync, GrabModeAsync);
XGrabKey(dpy, dcode, SHORTCUTMOD, screens[i].root, 0, GrabModeSync, GrabModeAsync);
XGrabKey(dpy, icode, SHORTCUTMOD, screens[i].root, 0, GrabModeSync, GrabModeAsync);
XGrabKey(dpy, rcode, SHORTCUTMOD, screens[i].root, 0, GrabModeSync, GrabModeAsync);
XGrabKey(dpy, vcode, SHORTCUTMOD, screens[i].root, 0, GrabModeSync, GrabModeAsync);
XGrabKey(dpy, mcode, SHORTCUTMOD, screens[i].root, 0, GrabModeSync, GrabModeAsync);
XGrabKey(dpy, hcode, SHORTCUTMOD, screens[i].root, 0, GrabModeSync, GrabModeAsync);
XGrabKey(dpy, lcode, SHORTCUTMOD, screens[i].root, 0, GrabModeSync, GrabModeAsync);
XGrabKey(dpy, jcode, SHORTCUTMOD, screens[i].root, 0, GrabModeSync, GrabModeAsync);
XGrabKey(dpy, kcode, SHORTCUTMOD, screens[i].root, 0, GrabModeSync, GrabModeAsync);
XGrabKey(dpy, qcode, SHORTCUTMOD, screens[i].root, 0, GrabModeSync, GrabModeAsync);
XGrabKey(dpy, wcode, SHORTCUTMOD, screens[i].root, 0, GrabModeSync, GrabModeAsync);
XGrabKey(dpy, ocode, SHORTCUTMOD, screens[i].root, 0, GrabModeSync, GrabModeAsync);
XGrabKey(dpy, pcode, SHORTCUTMOD, screens[i].root, 0, GrabModeSync, GrabModeAsync);
XGrabKey(dpy, ccode, SHORTCUTMOD, screens[i].root, 0, GrabModeSync, GrabModeAsync);
XGrabKey(dpy, leftcode, SHORTCUTMOD, screens[i].root, 0, GrabModeSync, GrabModeAsync);
XGrabKey(dpy, rightcode, SHORTCUTMOD, screens[i].root, 0, GrabModeSync, GrabModeAsync);
XGrabKey(dpy, slcode, SHORTCUTMOD, screens[i].root, 0, GrabModeSync, GrabModeAsync);
XGrabKey(dpy, tabcode, Mod1Mask|ShiftMask, screens[i].root, 0, GrabModeSync, GrabModeAsync);
/* XGrabKey(dpy, pgupcode, Mod1Mask, screens[i].root, 0, GrabModeSync, GrabModeAsync); */
/* XGrabKey(dpy, pgdowncode, Mod1Mask, screens[i].root, 0, GrabModeSync, GrabModeAsync); */
/* XGrabKey(dpy, altcode, 0, screens[i].root, 0, GrabModeSync, GrabModeAsync); */
}
}
void
keypress(XKeyEvent *e)
{
/*
* process key press here
*/
int tabcode = XKeysymToKeycode(dpy, XK_Tab);
int dcode = XKeysymToKeycode(dpy, DESTROY_KEY);
int icode = XKeysymToKeycode(dpy, ICON_KEY);
int mcode = XKeysymToKeycode(dpy, MAX_KEY);
int vcode = XKeysymToKeycode(dpy, MOVE_KEY);
int rcode = XKeysymToKeycode(dpy, RESIZE_KEY);
int slcode = XKeysymToKeycode(dpy, LAUNCH_KEY);
int hcode = XKeysymToKeycode(dpy, SNAPLEFT_KEY);
int lcode = XKeysymToKeycode(dpy, SNAPRIGHT_KEY);
int jcode = XKeysymToKeycode(dpy, SNAPBOTTOM_KEY);
int kcode = XKeysymToKeycode(dpy, SNAPTOP_KEY);
int qcode = XKeysymToKeycode(dpy, SNAPTOPLEFT_KEY);
int wcode = XKeysymToKeycode(dpy, SNAPBOTTOMLEFT_KEY);
int ocode = XKeysymToKeycode(dpy, SNAPBOTTOMRIGHT_KEY);
int pcode = XKeysymToKeycode(dpy, SNAPTOPRIGHT_KEY);
int ccode = XKeysymToKeycode(dpy, SNAPCENTER_KEY);
int rightcode = XKeysymToKeycode(dpy, NEXTVIRT_KEY);
int leftcode = XKeysymToKeycode(dpy, PREVVIRT_KEY);
XWindowAttributes ra;
XGetWindowAttributes(dpy, DefaultRootWindow(dpy), &ra);
/* alt tab */
if(e->keycode == tabcode && (e->state&Mod1Mask) == (1<<3))
alttab(e->state&ShiftMask);
/* basic wm functionality */
if(e->keycode == dcode && (e->state&SHORTCUTMOD) == (MODBITS))
delete(current, 0);
if(e->keycode == icode && (e->state&SHORTCUTMOD) == (MODBITS))
hide(current);
if (e->keycode == vcode && (e->state&SHORTCUTMOD) == (MODBITS))
move(current, Button3);
if (e->keycode == rcode && (e->state&SHORTCUTMOD) == (MODBITS))
reshape(current, Button3, sweep, 0);
if (e->keycode == mcode && (e->state&SHORTCUTMOD) == (MODBITS))
quickreshape(current, 0, 0, ra.width, ra.height);
/* half snap */
if (e->keycode == hcode && (e->state&SHORTCUTMOD) == (MODBITS))
quickreshape(current, 0, 0, ra.width/2, ra.height);
if (e->keycode == lcode && (e->state&SHORTCUTMOD) == (MODBITS))
quickreshape(current, ra.width/2, 0, ra.width/2, ra.height);
if (e->keycode == jcode && (e->state&SHORTCUTMOD) == (MODBITS))
quickreshape(current, 0, ra.height/2, ra.width, ra.height/2);
if (e->keycode == kcode && (e->state&SHORTCUTMOD) == (MODBITS))
quickreshape(current, 0, 0, ra.width, ra.height/2);
/* quarter snap */
if (e->keycode == qcode && (e->state&SHORTCUTMOD) == (MODBITS))
quickreshape(current, 0, 0, ra.width/2, ra.height/2);
if (e->keycode == wcode && (e->state&SHORTCUTMOD) == (MODBITS))
quickreshape(current, 0, ra.height/2, ra.width/2, ra.height/2);
if (e->keycode == ocode && (e->state&SHORTCUTMOD) == (MODBITS))
quickreshape(current, ra.width/2, ra.height/2, ra.width/2, ra.height/2);
if (e->keycode == pcode && (e->state&SHORTCUTMOD) == (MODBITS))
quickreshape(current, ra.width/2, 0, ra.width/2, ra.height/2);
/* center snap */
if (e->keycode == ccode && (e->state&SHORTCUTMOD) == (MODBITS))
quickreshape(current, ra.width/5, ra.height/5, 3*ra.width/5, 3*ra.height/5);
/* launch */
if (e->keycode == slcode && (e->state&SHORTCUTMOD) == (MODBITS)){
kbLaunch = 1;
if(fork() == 0){
close(ConnectionNumber(dpy));
if(dpy != '\0')
putenv(dpy);
signal(SIGINT, SIG_DFL);
signal(SIGTERM, SIG_DFL);
signal(SIGHUP, SIG_DFL);
if(termprog != NULL){
execl(shell, shell, "-c", termprog, (char*)0);
fprintf(stderr, "ryudo: exec %s", shell);
perror(" failed");
}
execlp("urxvt", "urxvt", (char*)0);
execlp("9term", "9term", scrolling ? "-ws" : "-w", (char*)0);
execlp("xterm", "xterm", "-ut", (char*)0);
perror("ryudo: exec 9term/xterm failed");
}
}
/* switch virts */
if (e->keycode == rightcode && (e->state&SHORTCUTMOD) == (MODBITS))
if (numvirtuals > 1 && virt < numvirtuals - 1)
switch_to(virt + 1);
if (e->keycode == leftcode && (e->state&SHORTCUTMOD) == (MODBITS))
if (numvirtuals >1 && virt > 0)
switch_to(virt - 1);
XAllowEvents(dpy, SyncKeyboard, e->time);
}
void
keyrelease(XKeyEvent *e)
{
XAllowEvents(dpy, SyncKeyboard, e->time);
}
void
quickreshape(Client *c, int x, int y, int dx, int dy)
{
XMoveResizeWindow(dpy, c->parent, x,y, dx, dy);
c->x = x + BORDER;
c->y = y + BORDER;
c->dx = dx-2*BORDER;
c->dy = dy-2*BORDER;
XMoveResizeWindow(dpy, c->window, BORDER, BORDER, c->dx, c->dy);
sendconfig(c);
}
static void
alttab(int shift)
{
shuffle(shift);
/* fprintf(stderr, "%sTab\n", shift ? "Back" : ""); */
}

544
main.c Executable file
View file

@ -0,0 +1,544 @@
/* Copyright (c) 1994-1996 David Hogan, see README for licence details */
#include <stdio.h>
#include <signal.h>
#include <errno.h>
#include <stdlib.h>
#include <unistd.h>
#include <X11/X.h>
#include <X11/Xos.h>
#include <X11/Xlib.h>
#include <X11/Xutil.h>
#include <X11/Xatom.h>
#ifdef SHAPE
#include <X11/extensions/shape.h>
#endif
#include "config.h"
#include "dat.h"
#include "fns.h"
#include "patchlevel.h"
char *version[] =
{
"ryudo version 0.1, Copyright (c) 1994-1996 David Hogan, (c) 2004 Russ Cox, (c) 2019 Derek Stevens", 0
};
Display *dpy;
ScreenInfo *screens;
int initting;
XFontStruct *font;
int nostalgia;
char **myargv;
char *termprog;
char *shell;
Bool shape;
int _border = 4;
int _corner = 25;
int _inset = 1;
int curtime;
int debug;
int signalled;
int scrolling;
int num_screens;
int solidsweep = 0;
int numvirtuals = 0;
int ffm = 0;
int kbLaunch = 0;
Atom exit_rio;
Atom restart_rio;
Atom wm_state;
Atom wm_change_state;
Atom wm_protocols;
Atom wm_delete;
Atom wm_take_focus;
Atom wm_lose_focus;
Atom wm_colormaps;
Atom _rio_running;
Atom _rio_hold_mode;
Atom wm_state_fullscreen;
Atom wm_state;
char *fontlist[] = {
"*-lucidatypewriter-medium-*-12-*-75-*",
"lucm.latin1.9",
"blit",
"*-lucidatypewriter-bold-*-14-*-75-*",
"9x15bold",
"fixed",
"*",
0
};
void
usage(void)
{
fprintf(stderr, "usage: ryudo [-grey] [-font fname] [-s] [-term prog] [-version] [-virtuals num] [exit|restart]\n");
exit(1);
}
int
main(int argc, char *argv[])
{
int i, background, do_exit, do_restart;
char *fname;
int shape_event;
#ifdef SHAPE
int dummy;
#endif
shape_event = 0;
myargv = argv; /* for restart */
do_exit = do_restart = 0;
background = 0;
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], "-ffm") == 0)
ffm++;
*/
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], "-virtuals") == 0 && i+1<argc){
numvirtuals = atoi(argv[++i]);
if(numvirtuals < 0 || numvirtuals > 12){
fprintf(stderr, "ryudo: wrong number of virtual displays, defaulting to 4\n");
numvirtuals = 4;
}
} 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(strcmp(argv[i], "-s") == 0){
scrolling = 1;
}
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_rio = XInternAtom(dpy, "9WM_EXIT", False);
restart_rio = XInternAtom(dpy, "9WM_RESTART", False);
curtime = -1; /* don't care */
if(do_exit){
sendcmessage(DefaultRootWindow(dpy), exit_rio, 0L, 1, 1);
XSync(dpy, False);
exit(0);
}
if(do_restart){
sendcmessage(DefaultRootWindow(dpy), restart_rio, 0L, 1, 1);
XSync(dpy, False);
exit(0);
}
if(0) XSynchronize(dpy, True);
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_lose_focus = XInternAtom(dpy, "_9WM_LOSE_FOCUS", False);
wm_colormaps = XInternAtom(dpy, "WM_COLORMAP_WINDOWS", False);
_rio_running = XInternAtom(dpy, "_9WM_RUNNING", False);
_rio_hold_mode = XInternAtom(dpy, "_9WM_HOLD_MODE", False);
wm_state = XInternAtom(dpy, "_NET_WM_STATE", False);
wm_state_fullscreen = XInternAtom(dpy, "_NET_WM_STATE_FULLSCREEN", False);
if(fname != 0)
if((font = XLoadQueryFont(dpy, fname)) == 0)
fprintf(stderr, "ryudo: warning: can't load font %s\n", fname);
if(font == 0){
i = 0;
for(;;){
fname = fontlist[i++];
if(fname == 0){
fprintf(stderr, "ryudo: 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);
initb2menu(numvirtuals);
/* set selection so that 9term knows we're running */
curtime = CurrentTime;
XSetSelectionOwner(dpy, _rio_running, screens[0].menuwin, timestamp());
XSync(dpy, False);
initting = 0;
nofocus();
for(i = 0; i < num_screens; i++)
scanwins(&screens[i]);
keysetup();
mainloop(shape_event);
return 0;
}
void
initscreen(ScreenInfo *s, int i, int background)
{
char *ds, *colon, *dot1;
unsigned long mask;
unsigned long gmask;
XGCValues gv;
XSetWindowAttributes attr;
XVisualInfo xvi;
XSetWindowAttributes attrs;
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);
/*
* Figure out underlying screen format.
*/
if(XMatchVisualInfo(dpy, i, 16, TrueColor, &xvi)
|| XMatchVisualInfo(dpy, i, 16, DirectColor, &xvi)){
s->vis = xvi.visual;
s->depth = 16;
}
else
if(XMatchVisualInfo(dpy, i, 15, TrueColor, &xvi)
|| XMatchVisualInfo(dpy, i, 15, DirectColor, &xvi)){
s->vis = xvi.visual;
s->depth = 15;
}
else
if(XMatchVisualInfo(dpy, i, 24, TrueColor, &xvi)
|| XMatchVisualInfo(dpy, i, 24, DirectColor, &xvi)){
s->vis = xvi.visual;
s->depth = 24;
}
else
if(XMatchVisualInfo(dpy, i, 8, PseudoColor, &xvi)
|| XMatchVisualInfo(dpy, i, 8, StaticColor, &xvi)){
s->vis = xvi.visual;
s->depth = 8;
}
else{
s->depth = DefaultDepth(dpy, i);
if(s->depth != 8){
fprintf(stderr, "can't understand depth %d screen", s->depth);
exit(1);
}
s->vis = DefaultVisual(dpy, i);
}
if(DefaultDepth(dpy, i) != s->depth){
s->def_cmap = XCreateColormap(dpy, s->root, s->vis, AllocNone);
}
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->black = BlackPixel(dpy, i);
s->white = WhitePixel(dpy, i);
s->activeholdborder = colorpixel(dpy, s, s->depth, SHOLDCOL, s->white);
s->inactiveholdborder = colorpixel(dpy, s, s->depth, HOLDCOL, s->black);
s->activeborder = colorpixel(dpy, s, s->depth, SBORDERCOL, s->black);
s->inactiveborder = colorpixel(dpy, s, s->depth, BORDERCOL, s->white);
s->red = colorpixel(dpy, s, s->depth, GHOSTCOL, s->white);
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;
gmask = GCForeground | GCBackground | GCFunction | GCLineWidth
| GCSubwindowMode;
if(font != 0){
gv.font = font->fid;
gmask |= GCFont;
}
s->gc = XCreateGC(dpy, s->root, gmask, &gv);
gv.function = GXcopy;
s->gccopy = XCreateGC(dpy, s->root, gmask, &gv);
gv.foreground = s->red;
s->gcred = XCreateGC(dpy, s->root, gmask, &gv);
gv.foreground = colorpixel(dpy, s, s->depth, 0xEEEEEE, s->black);
s->gcsweep = XCreateGC(dpy, s->root, gmask, &gv);
initcurs(s);
attr.cursor = s->arrow;
attr.event_mask = SubstructureRedirectMask
| SubstructureNotifyMask | ColormapChangeMask
| ButtonPressMask | ButtonReleaseMask | PropertyChangeMask
| KeyPressMask | EnterWindowMask;
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);
} else
system("xsetroot -solid grey30");
attrs.border_pixel = colorpixel(dpy, s, s->depth, MBORDERCOL, s->black);
attrs.background_pixel = colorpixel(dpy, s, s->depth, MENUBGCOL, s->white);
attrs.colormap = s->def_cmap;
s->menuwin = XCreateWindow(dpy, s->root, 0, 0, 1, 1, MENUBORDER,
s->depth,
CopyFromParent,
s->vis,
CWBackPixel | CWBorderPixel | CWColormap,
&attrs
);
gv.foreground = colorpixel(dpy, s, s->depth, MENUBGCOL, s->black);
s->gcmenubg = XCreateGC(dpy, s->menuwin, gmask, &gv);
gv.foreground = colorpixel(dpy, s, s->depth, SMENUBGCOL, s->white);
s->gcmenubgs = XCreateGC(dpy, s->menuwin, gmask, &gv);
gv.foreground = colorpixel(dpy, s, s->depth, MENUFGCOL, s->white);
gv.background = colorpixel(dpy, s, s->depth, MENUBGCOL, s->black);
s->gcmenufg = XCreateGC(dpy, s->menuwin, gmask, &gv);
gv.foreground = colorpixel(dpy, s, s->depth, SMENUFGCOL, s->white);
gv.background = colorpixel(dpy, s, s->depth, SMENUBGCOL, s->black);
s->gcmenufgs = XCreateGC(dpy, s->menuwin, gmask, &gv);
attrs.border_pixel = s->red;
attrs.background_pixel = colorpixel(dpy, s, s->depth, 0xEEEEEE, s->black);
attrs.colormap = s->def_cmap;
s->sweepwin = XCreateWindow(dpy, s->root, 0, 0, 1, 1, 4,
s->depth,
CopyFromParent,
s->vis,
CWBackPixel | CWBorderPixel | CWColormap,
&attrs
);
}
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, _rio_running, _rio_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, int usemask)
{
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 = 0;
if(usemask){
mask |= KeyPressMask; /* seems to be necessary */
if(isroot)
mask |= SubstructureRedirectMask; /* magic! */
else
mask |= ExposureMask; /* not really correct but so be it */
}
status = XSendEvent(dpy, w, False, mask, &ev);
if(status == 0)
fprintf(stderr, "ryudo: 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("ryudo: select failed");
exit(1);
}
}
fprintf(stderr, "ryudo: 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)){
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);
}

476
manage.c Executable file
View file

@ -0,0 +1,476 @@
/*
* Window management.
*/
/*
* Copyright (c) 2019 Derek Stevens, 2005 Russ Cox, 1994-1996 David Hogan
* see README for licence details
*/
#include <stdio.h>
#include <stdlib.h>
#include <inttypes.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 isNew;
int
manage(Client *c, int mapped)
{
int fixsize, dohide, doreshape, state;
long msize;
XClassHint class;
XWMHints *hints;
XSetWindowAttributes attrs;
trace("manage", c, 0);
XSelectInput(dpy, c->window, ColormapChangeMask | EnterWindowMask | PropertyChangeMask | FocusChangeMask | KeyPressMask);
/* Get loads of hints */
if(XGetClassHint(dpy, c->window, &class) != 0){ /* ``Success'' */
c->instance = class.res_name;
c->class = class.res_class;
c->is9term = 0;
if(isNew){
c->is9term = strstr(c->class, "term") || strstr(c->class, "Term") || strstr (c->class, "urxvt") || strstr (c->class, "URxvt");
isNew = 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, _rio_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(0) fprintf(stderr, "in doreshape is9term=%d fixsize=%d, x=%d, y=%d, min_dx=%d, min_dy=%d, dx=%d, dy=%d\n",
c->is9term, fixsize, c->x, c->y, c->min_dx, c->min_dy, c->dx, c->dy);
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, Button3) : sweep(c, Button3))){
XKillClient(dpy, c->window);
rmclient(c);
if(current && current->screen == c->screen)
cmapfocus(current);
return 0;
}
}
attrs.border_pixel = c->screen->black;
attrs.background_pixel = c->screen->white;
attrs.colormap = c->screen->def_cmap;
c->parent = XCreateWindow(dpy, c->screen->root,
c->x - BORDER, c->y - BORDER,
c->dx + 2*BORDER, c->dy + 2*BORDER,
0,
c->screen->depth,
CopyFromParent,
c->screen->vis,
CWBackPixel | CWBorderPixel | CWColormap,
&attrs);
XSelectInput(dpy, c->parent, SubstructureRedirectMask | SubstructureNotifyMask|ButtonPressMask| PointerMotionMask|LeaveWindowMask|KeyPressMask);
if(mapped)
c->reparenting = 1;
if(doreshape && !fixsize)
XResizeWindow(dpy, c->window, c->dx, c->dy);
XSetWindowBorderWidth(dpy, c->window, 0);
/*
* To have something more than only a big white or black border
* XXX should replace this by a pattern in the white or black
* such that we can see the border also if all our
* windows are black and/or white
* (black (or white) border around black (or white) window
* is not very helpful.
*/
if(c->screen->depth <= 8){
XSetWindowBorderWidth(dpy, c->parent, 1);
}
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;
/*
* If we swept the window, let's send a resize event to the
* guy who just got resized. It's not clear whether the apps
* should notice their new size via other means. Try as I might,
* I can't find a way to have them notice during initdraw, so
* I solve the problem this way instead. -rsc
*/
if(c->is9term)
sendconfig(c);
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);
XReparentWindow(dpy, c->window, c->screen->root, c->x, c->y);
XRemoveFromSaveSet(dpy, c->window);
setstate(c, WithdrawnState);
/* flush any errors */
ignore_badwindow = 1;
XSync(dpy, False);
ignore_badwindow = 0;
}
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){
ignore_badwindow = 1;
XGetWindowAttributes(dpy, c->window, &attr);
c->cmap = attr.colormap;
XSync(dpy, False);
ignore_badwindow = 0;
}
n = _getprop(c->window, wm_colormaps, XA_WINDOW, 100L, (void*)&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 {
/* flush any errors (e.g., caused by mozilla tabs) */
ignore_badwindow = 1;
XSelectInput(dpy, cw[i], ColormapChangeMask);
XGetWindowAttributes(dpy, cw[i], &attr);
c->wmcmaps[i] = attr.colormap;
XSync(dpy, False);
ignore_badwindow = 0;
}
}
}
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, (void*)&p) <= 0)
return 0;
x = *p;
XFree((void*) p);
return (int)(uintptr_t)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, (void*)&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, (void*)&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;
else if(p[i] == wm_lose_focus)
c->proto |= Plosefocus;
XFree((char *) p);
}

427
menu.c Executable file
View file

@ -0,0 +1,427 @@
/*
* Pop-up menus.
*/
/* Copyright (c) 1994-1996 David Hogan, see README for licence details */
#define _SVID_SOURCE 1 /* putenv in glibc */
#define _DEFAULT_SOURCE 1
#include <stdio.h>
#include <signal.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
#include <sys/wait.h>
#include <X11/X.h>
#include <X11/Xlib.h>
#include <X11/Xutil.h>
#include "dat.h"
#include "fns.h"
Client *hiddenc[MAXHIDDEN];
int numhidden;
int virt;
int reversehide = 1;
Client * currents[NUMVIRTUALS] =
{
NULL, NULL, NULL, NULL
};
char *b2items[NUMVIRTUALS+1] =
{
"One",
"Two",
"Three",
"Four",
"Five",
"Six",
"Seven",
"Eight",
"Nine",
"Ten",
"Eleven",
"Twelve",
0
};
Menu b2menu =
{
b2items
};
char *b3items[B3FIXED+MAXHIDDEN+1] =
{
"New",
"Reshape",
"Move",
"Delete",
"Hide",
0
};
enum
{
New,
Reshape,
Move,
Delete,
Hide
};
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){
if(debug) fprintf(stderr, "but: e x=%d y=%d c x=%d y=%d dx=%d dy=%d BORDR %d\n",
e->x, e->y, c->x, c->y, c->dx, c->dy, BORDER);
if(borderorient(c, e->x, e->y) != BorderUnknown){
switch (e->button){
case Button1:
case Button2:
reshape(c, e->button, pull, e);
return;
case Button3:
move(c, Button3);
return;
default:
return;
}
}
e->x += c->x - BORDER;
e->y += c->y - BORDER;
} else if(e->window != e->root){
if(debug) fprintf(stderr, "but no client: e x=%d y=%d\n",
e->x, e->y);
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(c){
XMapRaised(dpy, c->parent);
active(c);
XAllowEvents (dpy, ReplayPointer, curtime);
} else if((e->state&(ShiftMask|ControlMask))==(ShiftMask|ControlMask)){
menuhit(e, &egg);
} else if(numvirtuals > 1 && (n = menuhit(e, &b2menu)) > -1)
button2(n);
return;
case Button3:
break;
case Button4:
/* scroll up changes to previous virtual screen */
if(!c && e->type == ButtonPress)
if(numvirtuals > 1 && virt > 0)
switch_to(virt - 1);
return;
case Button5:
/* scroll down changes to next virtual screen */
if(!c && e->type == ButtonPress)
if(numvirtuals > 1 && virt < numvirtuals - 1)
switch_to(virt + 1);
return;
default:
return;
}
if(current && current->screen == s)
cmapnofocus(s);
switch (n = menuhit(e, &b3menu)){
case New:
spawn(s);
break;
case Reshape:
reshape(selectwin(1, 0, s), Button3, sweep, 0);
break;
case Move:
move(selectwin(0, 0, s), Button3);
break;
case Delete:
shift = 0;
c = selectwin(1, &shift, s);
delete(c, shift);
break;
case 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 cause sweeping for terminals.
* the very next window created will require sweeping.
* hope it's created by the program we're about to
* exec!
*/
isNew = 1;
/*
* 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);
signal(SIGINT, SIG_DFL);
signal(SIGTERM, SIG_DFL);
signal(SIGHUP, SIG_DFL);
if(termprog != NULL){
execl(shell, shell, "-c", termprog, (char*)0);
fprintf(stderr, "ryudo: exec %s", shell);
perror(" failed");
}
execlp("urxvt", "urxvt", (char*)0);
execlp("9term", "9term", scrolling ? "-ws" : "-w", (char*)0);
execlp("xterm", "xterm", "-ut", (char*)0);
perror("ryudo: exec 9term/xterm failed");
exit(1);
}
exit(0);
}
wait((int *) 0);
}
void
reshape(Client *c, int but, int (*fn)(Client*, int, XButtonEvent *), XButtonEvent *e)
{
int odx, ody;
if(c == 0)
return;
odx = c->dx;
ody = c->dy;
if(fn(c, but, e) == 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, int but)
{
if(c == 0)
return;
if(drag(c, but) == 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, 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, "ryudo: already hidden: %s\n", c->label);
return;
}
XUnmapWindow(dpy, c->parent);
XUnmapWindow(dpy, c->window);
setstate(c, IconicState);
if(c == current)
nofocus();
if(reversehide){
memmove(hiddenc+1, hiddenc, numhidden*sizeof hiddenc[0]);
memmove(b3items+B3FIXED+1, b3items+B3FIXED, numhidden*sizeof b3items[0]);
hiddenc[0] = c;
b3items[B3FIXED] = c->label;
}else{
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, "ryudo: unhide: n %d numhidden %d\n", n, numhidden);
return;
}
c = hiddenc[n];
if(!hidden(c)){
fprintf(stderr, "ryudo: unhide: not hidden: %s(0x%x)\n",
c->label, (int)c->window);
return;
}
c->virt = virt;
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, "ryudo: unhidec: not hidden: %s(0x%x)\n",
c->label, (int)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;
}
}
void
button2(int n)
{
switch_to(n);
if(current)
cmapfocus(current);
}
void
switch_to_c(int n, Client *c)
{
if(c == 0)
return;
if(c->next)
switch_to_c(n, c->next);
if(c->parent == DefaultRootWindow(dpy))
return;
if(c->virt != virt && c->state == NormalState){
XUnmapWindow(dpy, c->parent);
XUnmapWindow(dpy, c->window);
setstate(c, IconicState);
if(c == current)
nofocus();
} else if(c->virt == virt && c->state == IconicState){
int i;
for(i = 0; i < numhidden; i++)
if(c == hiddenc[i])
break;
if(i == numhidden){
XMapWindow(dpy, c->window);
XMapWindow(dpy, c->parent);
setstate(c, NormalState);
if(currents[virt] == c)
active(c);
}
}
}
void
switch_to(int n)
{
if(n == virt)
return;
currents[virt] = current;
virt = n;
/* redundant when called from a menu switch
* but needed for scroll-button switches
*/
b2menu.lasthit = n;
switch_to_c(n, clients);
current = currents[virt];
}
void
initb2menu(int n)
{
b2items[n] = 0;
}

45
mkfile Executable file
View file

@ -0,0 +1,45 @@
<$PLAN9/src/mkhdr
<|sh /usr/lib/plan9/src/cmd/devdraw/mkwsysrules.sh # for X11
RIOFILES=\
client.$O\
color.$O\
cursor.$O\
error.$O\
event.$O\
grab.$O\
key.$O\
main.$O\
manage.$O\
menu.$O\
CFLAGS=$CFLAGS -DDEBUG
HFILES=dat.h fns.h
TARG=rio xshove
# need to add lib64 when it exists (on x86-64), but
# Darwin complains about the nonexistant directory
# Bug in mk? "$L64 -lXext" gobbles the space, so
# add trailing slash.
L64=`[ -d $X11/lib64 ] && echo 64; echo`
LDFLAGS=-L$X11/lib$L64/ -lXext -lX11 $LDFLAGS
<|sh mkriorules.sh
$O.rio: $RIOFILES
CFLAGS=$CFLAGS -DSHAPE -DDEBUG_EV -DDEBUG
$O.xevents: xevents.$O printevent.$O
$LD -o $target $prereq $LDFLAGS
xevents.$O printevent.$O: printevent.h
error.$O: showevent/ShowEvent.c
$O.xshove: xshove.$O
$LD -o $O.xshove xshove.$O -lX11 $LDFLAGS
ryudo: $O.rio
sh ryudomagic.sh

8
mkriorules.sh Executable file
View file

@ -0,0 +1,8 @@
if [ "x$WSYSTYPE" != xx11 ]; then
echo 'default:V: all'
echo
echo 'all install clean nuke:'
echo ' # WSYSTYPE is not x11, and ryudo is only for x11'
exit 0
fi
cat $PLAN9/src/mkmany

1
patchlevel.h Executable file
View file

@ -0,0 +1 @@
#define PATCHLEVEL 0

986
printevent.c Executable file
View file

@ -0,0 +1,986 @@
/*
* Original code posted to comp.sources.x
* Modifications by Russ Cox <rsc@swtch.com>.
*/
/*
Path: uunet!wyse!mikew
From: mikew@wyse.wyse.com (Mike Wexler)
Newsgroups: comp.sources.x
Subject: v02i056: subroutine to print events in human readable form, Part01/01
Message-ID: <1935@wyse.wyse.com>
Date: 22 Dec 88 19:28:25 GMT
Organization: Wyse Technology, San Jose
Lines: 1093
Approved: mikew@wyse.com
Submitted-by: richsun!darkstar!ken
Posting-number: Volume 2, Issue 56
Archive-name: showevent/part01
There are times during debugging when it would be real useful to be able to
print the fields of an event in a human readable form. Too many times I found
myself scrounging around in section 8 of the Xlib manual looking for the valid
fields for the events I wanted to see, then adding printf's to display the
numeric values of the fields, and then scanning through X.h trying to decode
the cryptic detail and state fields. After playing with xev, I decided to
write a couple of standard functions that I could keep in a library and call
on whenever I needed a little debugging verbosity. The first function,
GetType(), is useful for returning the string representation of the type of
an event. The second function, ShowEvent(), is used to display all the fields
of an event in a readable format. The functions are not complicated, in fact,
they are mind-numbingly boring - but that's just the point nobody wants to
spend the time writing functions like this, they just want to have them when
they need them.
A simple, sample program is included which does little else but to demonstrate
the use of these two functions. These functions have saved me many an hour
during debugging and I hope you find some benefit to these. If you have any
comments, suggestions, improvements, or if you find any blithering errors you
can get it touch with me at the following location:
ken@richsun.UUCP
*/
#include <stdio.h>
#include <X11/Intrinsic.h>
#include <X11/Xproto.h>
#include "printevent.h"
static char* sep = " ";
/******************************************************************************/
/**** Miscellaneous routines to convert values to their string equivalents ****/
/******************************************************************************/
/* Returns the string equivalent of a boolean parameter */
static char*
TorF(int bool)
{
switch (bool) {
case True:
return ("True");
case False:
return ("False");
default:
return ("?");
}
}
/* Returns the string equivalent of a property notify state */
static char*
PropertyState(int state)
{
switch (state) {
case PropertyNewValue:
return ("PropertyNewValue");
case PropertyDelete:
return ("PropertyDelete");
default:
return ("?");
}
}
/* Returns the string equivalent of a visibility notify state */
static char*
VisibilityState(int state)
{
switch (state) {
case VisibilityUnobscured:
return ("VisibilityUnobscured");
case VisibilityPartiallyObscured:
return ("VisibilityPartiallyObscured");
case VisibilityFullyObscured:
return ("VisibilityFullyObscured");
default:
return ("?");
}
}
/* Returns the string equivalent of a timestamp */
static char*
ServerTime(Time time)
{
unsigned long msec;
unsigned long sec;
unsigned long min;
unsigned long hr;
unsigned long day;
static char buffer[32];
msec = time % 1000;
time /= 1000;
sec = time % 60;
time /= 60;
min = time % 60;
time /= 60;
hr = time % 24;
time /= 24;
day = time;
if(0)
sprintf(buffer, "%lu day%s %02lu:%02lu:%02lu.%03lu",
day, day == 1 ? "" : "(s)", hr, min, sec, msec);
sprintf(buffer, "%lud%luh%lum%lu.%03lds", day, hr, min, sec, msec);
return (buffer);
}
/* Simple structure to ease the interpretation of masks */
typedef struct MaskType MaskType;
struct MaskType
{
unsigned int value;
char *string;
};
/* Returns the string equivalent of a mask of buttons and/or modifier keys */
static char*
ButtonAndOrModifierState(unsigned int state)
{
static char buffer[256];
static MaskType masks[] = {
{Button1Mask, "Button1Mask"},
{Button2Mask, "Button2Mask"},
{Button3Mask, "Button3Mask"},
{Button4Mask, "Button4Mask"},
{Button5Mask, "Button5Mask"},
{ShiftMask, "ShiftMask"},
{LockMask, "LockMask"},
{ControlMask, "ControlMask"},
{Mod1Mask, "Mod1Mask"},
{Mod2Mask, "Mod2Mask"},
{Mod3Mask, "Mod3Mask"},
{Mod4Mask, "Mod4Mask"},
{Mod5Mask, "Mod5Mask"},
};
int num_masks = sizeof(masks) / sizeof(MaskType);
int i;
Boolean first = True;
buffer[0] = 0;
for (i = 0; i < num_masks; i++)
if (state & masks[i].value)
if (first) {
first = False;
strcpy(buffer, masks[i].string);
} else {
strcat(buffer, " | ");
strcat(buffer, masks[i].string);
}
return (buffer);
}
/* Returns the string equivalent of a mask of configure window values */
static char*
ConfigureValueMask(unsigned int valuemask)
{
static char buffer[256];
static MaskType masks[] = {
{CWX, "CWX"},
{CWY, "CWY"},
{CWWidth, "CWWidth"},
{CWHeight, "CWHeight"},
{CWBorderWidth, "CWBorderWidth"},
{CWSibling, "CWSibling"},
{CWStackMode, "CWStackMode"},
};
int num_masks = sizeof(masks) / sizeof(MaskType);
int i;
Boolean first = True;
buffer[0] = 0;
for (i = 0; i < num_masks; i++)
if (valuemask & masks[i].value)
if (first) {
first = False;
strcpy(buffer, masks[i].string);
} else {
strcat(buffer, " | ");
strcat(buffer, masks[i].string);
}
return (buffer);
}
/* Returns the string equivalent of a motion hint */
static char*
IsHint(char is_hint)
{
switch (is_hint) {
case NotifyNormal:
return ("NotifyNormal");
case NotifyHint:
return ("NotifyHint");
default:
return ("?");
}
}
/* Returns the string equivalent of an id or the value "None" */
static char*
MaybeNone(int value)
{
static char buffer[16];
if (value == None)
return ("None");
else {
sprintf(buffer, "0x%x", value);
return (buffer);
}
}
/* Returns the string equivalent of a colormap state */
static char*
ColormapState(int state)
{
switch (state) {
case ColormapInstalled:
return ("ColormapInstalled");
case ColormapUninstalled:
return ("ColormapUninstalled");
default:
return ("?");
}
}
/* Returns the string equivalent of a crossing detail */
static char*
CrossingDetail(int detail)
{
switch (detail) {
case NotifyAncestor:
return ("NotifyAncestor");
case NotifyInferior:
return ("NotifyInferior");
case NotifyVirtual:
return ("NotifyVirtual");
case NotifyNonlinear:
return ("NotifyNonlinear");
case NotifyNonlinearVirtual:
return ("NotifyNonlinearVirtual");
default:
return ("?");
}
}
/* Returns the string equivalent of a focus change detail */
static char*
FocusChangeDetail(int detail)
{
switch (detail) {
case NotifyAncestor:
return ("NotifyAncestor");
case NotifyInferior:
return ("NotifyInferior");
case NotifyVirtual:
return ("NotifyVirtual");
case NotifyNonlinear:
return ("NotifyNonlinear");
case NotifyNonlinearVirtual:
return ("NotifyNonlinearVirtual");
case NotifyPointer:
return ("NotifyPointer");
case NotifyPointerRoot:
return ("NotifyPointerRoot");
case NotifyDetailNone:
return ("NotifyDetailNone");
default:
return ("?");
}
}
/* Returns the string equivalent of a configure detail */
static char*
ConfigureDetail(int detail)
{
switch (detail) {
case Above:
return ("Above");
case Below:
return ("Below");
case TopIf:
return ("TopIf");
case BottomIf:
return ("BottomIf");
case Opposite:
return ("Opposite");
default:
return ("?");
}
}
/* Returns the string equivalent of a grab mode */
static char*
GrabMode(int mode)
{
switch (mode) {
case NotifyNormal:
return ("NotifyNormal");
case NotifyGrab:
return ("NotifyGrab");
case NotifyUngrab:
return ("NotifyUngrab");
case NotifyWhileGrabbed:
return ("NotifyWhileGrabbed");
default:
return ("?");
}
}
/* Returns the string equivalent of a mapping request */
static char*
MappingRequest(int request)
{
switch (request) {
case MappingModifier:
return ("MappingModifier");
case MappingKeyboard:
return ("MappingKeyboard");
case MappingPointer:
return ("MappingPointer");
default:
return ("?");
}
}
/* Returns the string equivalent of a stacking order place */
static char*
Place(int place)
{
switch (place) {
case PlaceOnTop:
return ("PlaceOnTop");
case PlaceOnBottom:
return ("PlaceOnBottom");
default:
return ("?");
}
}
/* Returns the string equivalent of a major code */
static char*
MajorCode(int code)
{
static char buffer[32];
switch (code) {
case X_CopyArea:
return ("X_CopyArea");
case X_CopyPlane:
return ("X_CopyPlane");
default:
sprintf(buffer, "0x%x", code);
return (buffer);
}
}
/* Returns the string equivalent the keycode contained in the key event */
static char*
Keycode(XKeyEvent *ev)
{
static char buffer[256];
KeySym keysym_str;
char *keysym_name;
char string[256];
XLookupString(ev, string, 64, &keysym_str, NULL);
if (keysym_str == NoSymbol)
keysym_name = "NoSymbol";
else if (!(keysym_name = XKeysymToString(keysym_str)))
keysym_name = "(no name)";
sprintf(buffer, "%u (keysym 0x%x \"%s\")",
(int)ev->keycode, (int)keysym_str, keysym_name);
return (buffer);
}
/* Returns the string equivalent of an atom or "None"*/
static char*
AtomName(Display *dpy, Atom atom)
{
static char buffer[256];
char *atom_name;
if (atom == None)
return ("None");
atom_name = XGetAtomName(dpy, atom);
strncpy(buffer, atom_name, 256);
XFree(atom_name);
return (buffer);
}
/******************************************************************************/
/**** Routines to print out readable values for the field of various events ***/
/******************************************************************************/
static void
VerbMotion(XMotionEvent *ev)
{
printf("window=0x%x%s", (int)ev->window, sep);
printf("root=0x%x%s", (int)ev->root, sep);
printf("subwindow=0x%x%s", (int)ev->subwindow, sep);
printf("time=%s%s", ServerTime(ev->time), sep);
printf("x=%d y=%d%s", ev->x, ev->y, sep);
printf("x_root=%d y_root=%d%s", ev->x_root, ev->y_root, sep);
printf("state=%s%s", ButtonAndOrModifierState(ev->state), sep);
printf("is_hint=%s%s", IsHint(ev->is_hint), sep);
printf("same_screen=%s\n", TorF(ev->same_screen));
}
static void
VerbButton(XButtonEvent *ev)
{
printf("window=0x%x%s", (int)ev->window, sep);
printf("root=0x%x%s", (int)ev->root, sep);
printf("subwindow=0x%x%s", (int)ev->subwindow, sep);
printf("time=%s%s", ServerTime(ev->time), sep);
printf("x=%d y=%d%s", ev->x, ev->y, sep);
printf("x_root=%d y_root=%d%s", ev->x_root, ev->y_root, sep);
printf("state=%s%s", ButtonAndOrModifierState(ev->state), sep);
printf("button=%s%s", ButtonAndOrModifierState(ev->button), sep);
printf("same_screen=%s\n", TorF(ev->same_screen));
}
static void
VerbColormap(XColormapEvent *ev)
{
printf("window=0x%x%s", (int)ev->window, sep);
printf("colormap=%s%s", MaybeNone(ev->colormap), sep);
printf("new=%s%s", TorF(ev->new), sep);
printf("state=%s\n", ColormapState(ev->state));
}
static void
VerbCrossing(XCrossingEvent *ev)
{
printf("window=0x%x%s", (int)ev->window, sep);
printf("root=0x%x%s", (int)ev->root, sep);
printf("subwindow=0x%x%s", (int)ev->subwindow, sep);
printf("time=%s%s", ServerTime(ev->time), sep);
printf("x=%d y=%d%s", ev->x, ev->y, sep);
printf("x_root=%d y_root=%d%s", ev->x_root, ev->y_root, sep);
printf("mode=%s%s", GrabMode(ev->mode), sep);
printf("detail=%s%s", CrossingDetail(ev->detail), sep);
printf("same_screen=%s%s", TorF(ev->same_screen), sep);
printf("focus=%s%s", TorF(ev->focus), sep);
printf("state=%s\n", ButtonAndOrModifierState(ev->state));
}
static void
VerbExpose(XExposeEvent *ev)
{
printf("window=0x%x%s", (int)ev->window, sep);
printf("x=%d y=%d%s", ev->x, ev->y, sep);
printf("width=%d height=%d%s", ev->width, ev->height, sep);
printf("count=%d\n", ev->count);
}
static void
VerbGraphicsExpose(XGraphicsExposeEvent *ev)
{
printf("drawable=0x%x%s", (int)ev->drawable, sep);
printf("x=%d y=%d%s", ev->x, ev->y, sep);
printf("width=%d height=%d%s", ev->width, ev->height, sep);
printf("major_code=%s%s", MajorCode(ev->major_code), sep);
printf("minor_code=%d\n", ev->minor_code);
}
static void
VerbNoExpose(XNoExposeEvent *ev)
{
printf("drawable=0x%x%s", (int)ev->drawable, sep);
printf("major_code=%s%s", MajorCode(ev->major_code), sep);
printf("minor_code=%d\n", ev->minor_code);
}
static void
VerbFocus(XFocusChangeEvent *ev)
{
printf("window=0x%x%s", (int)ev->window, sep);
printf("mode=%s%s", GrabMode(ev->mode), sep);
printf("detail=%s\n", FocusChangeDetail(ev->detail));
}
static void
VerbKeymap(XKeymapEvent *ev)
{
int i;
printf("window=0x%x%s", (int)ev->window, sep);
printf("key_vector=");
for (i = 0; i < 32; i++)
printf("%02x", ev->key_vector[i]);
printf("\n");
}
static void
VerbKey(XKeyEvent *ev)
{
printf("window=0x%x%s", (int)ev->window, sep);
printf("root=0x%x%s", (int)ev->root, sep);
if(ev->subwindow)
printf("subwindow=0x%x%s", (int)ev->subwindow, sep);
printf("time=%s%s", ServerTime(ev->time), sep);
printf("[%d,%d]%s", ev->x, ev->y, sep);
printf("root=[%d,%d]%s", ev->x_root, ev->y_root, sep);
if(ev->state)
printf("state=%s%s", ButtonAndOrModifierState(ev->state), sep);
printf("keycode=%s%s", Keycode(ev), sep);
if(!ev->same_screen)
printf("!same_screen", TorF(ev->same_screen));
printf("\n");
return;
printf("window=0x%x%s", (int)ev->window, sep);
printf("root=0x%x%s", (int)ev->root, sep);
printf("subwindow=0x%x%s", (int)ev->subwindow, sep);
printf("time=%s%s", ServerTime(ev->time), sep);
printf("x=%d y=%d%s", ev->x, ev->y, sep);
printf("x_root=%d y_root=%d%s", ev->x_root, ev->y_root, sep);
printf("state=%s%s", ButtonAndOrModifierState(ev->state), sep);
printf("keycode=%s%s", Keycode(ev), sep);
printf("same_screen=%s\n", TorF(ev->same_screen));
}
static void
VerbProperty(XPropertyEvent *ev)
{
printf("window=0x%x%s", (int)ev->window, sep);
printf("atom=%s%s", AtomName(ev->display, ev->atom), sep);
printf("time=%s%s", ServerTime(ev->time), sep);
printf("state=%s\n", PropertyState(ev->state));
}
static void
VerbResizeRequest(XResizeRequestEvent *ev)
{
printf("window=0x%x%s", (int)ev->window, sep);
printf("width=%d height=%d\n", ev->width, ev->height);
}
static void
VerbCirculate(XCirculateEvent *ev)
{
printf("event=0x%x%s", (int)ev->event, sep);
printf("window=0x%x%s", (int)ev->window, sep);
printf("place=%s\n", Place(ev->place));
}
static void
VerbConfigure(XConfigureEvent *ev)
{
printf("event=0x%x%s", (int)ev->event, sep);
printf("window=0x%x%s", (int)ev->window, sep);
printf("x=%d y=%d%s", ev->x, ev->y, sep);
printf("width=%d height=%d%s", ev->width, ev->height, sep);
printf("border_width=%d%s", ev->border_width, sep);
printf("above=%s%s", MaybeNone(ev->above), sep);
printf("override_redirect=%s\n", TorF(ev->override_redirect));
}
static void
VerbCreateWindow(XCreateWindowEvent *ev)
{
printf("parent=0x%x%s", (int)ev->parent, sep);
printf("window=0x%x%s", (int)ev->window, sep);
printf("x=%d y=%d%s", ev->x, ev->y, sep);
printf("width=%d height=%d%s", ev->width, ev->height, sep);
printf("border_width=%d%s", ev->border_width, sep);
printf("override_redirect=%s\n", TorF(ev->override_redirect));
}
static void
VerbDestroyWindow(XDestroyWindowEvent *ev)
{
printf("event=0x%x%s", (int)ev->event, sep);
printf("window=0x%x\n", (int)ev->window);
}
static void
VerbGravity(XGravityEvent *ev)
{
printf("event=0x%x%s", (int)ev->event, sep);
printf("window=0x%x%s", (int)ev->window, sep);
printf("x=%d y=%d\n", ev->x, ev->y);
}
static void
VerbMap(XMapEvent *ev)
{
printf("event=0x%x%s", (int)ev->event, sep);
printf("window=0x%x%s", (int)ev->window, sep);
printf("override_redirect=%s\n", TorF(ev->override_redirect));
}
static void
VerbReparent(XReparentEvent *ev)
{
printf("event=0x%x%s", (int)ev->event, sep);
printf("window=0x%x%s", (int)ev->window, sep);
printf("parent=0x%x%s", (int)ev->parent, sep);
printf("x=%d y=%d%s", ev->x, ev->y, sep);
printf("override_redirect=%s\n", TorF(ev->override_redirect));
}
static void
VerbUnmap(XUnmapEvent *ev)
{
printf("event=0x%x%s", (int)ev->event, sep);
printf("window=0x%x%s", (int)ev->window, sep);
printf("from_configure=%s\n", TorF(ev->from_configure));
}
static void
VerbCirculateRequest(XCirculateRequestEvent *ev)
{
printf("parent=0x%x%s", (int)ev->parent, sep);
printf("window=0x%x%s", (int)ev->window, sep);
printf("place=%s\n", Place(ev->place));
}
static void
VerbConfigureRequest(XConfigureRequestEvent *ev)
{
printf("parent=0x%x%s", (int)ev->parent, sep);
printf("window=0x%x%s", (int)ev->window, sep);
printf("x=%d y=%d%s", ev->x, ev->y, sep);
printf("width=%d height=%d%s", ev->width, ev->height, sep);
printf("border_width=%d%s", ev->border_width, sep);
printf("above=%s%s", MaybeNone(ev->above), sep);
printf("detail=%s%s", ConfigureDetail(ev->detail), sep);
printf("value_mask=%s\n", ConfigureValueMask(ev->value_mask));
}
static void
VerbMapRequest(XMapRequestEvent *ev)
{
printf("parent=0x%x%s", (int)ev->parent, sep);
printf("window=0x%x\n", (int)ev->window);
}
static void
VerbClient(XClientMessageEvent *ev)
{
int i;
printf("window=0x%x%s", (int)ev->window, sep);
printf("message_type=%s%s", AtomName(ev->display, ev->message_type), sep);
printf("format=%d\n", ev->format);
printf("data (shown as longs)=");
for (i = 0; i < 5; i++)
printf(" 0x%08lx", ev->data.l[i]);
printf("\n");
}
static void
VerbMapping(XMappingEvent *ev)
{
printf("window=0x%x%s", (int)ev->window, sep);
printf("request=%s%s", MappingRequest(ev->request), sep);
printf("first_keycode=0x%x%s", ev->first_keycode, sep);
printf("count=0x%x\n", ev->count);
}
static void
VerbSelectionClear(XSelectionClearEvent *ev)
{
printf("window=0x%x%s", (int)ev->window, sep);
printf("selection=%s%s", AtomName(ev->display, ev->selection), sep);
printf("time=%s\n", ServerTime(ev->time));
}
static void
VerbSelection(XSelectionEvent *ev)
{
printf("requestor=0x%x%s", (int)ev->requestor, sep);
printf("selection=%s%s", AtomName(ev->display, ev->selection), sep);
printf("target=%s%s", AtomName(ev->display, ev->target), sep);
printf("property=%s%s", AtomName(ev->display, ev->property), sep);
printf("time=%s\n", ServerTime(ev->time));
}
static void
VerbSelectionRequest(XSelectionRequestEvent *ev)
{
printf("owner=0x%x%s", (int)ev->owner, sep);
printf("requestor=0x%x%s", (int)ev->requestor, sep);
printf("selection=%s%s", AtomName(ev->display, ev->selection), sep);
printf("target=%s%s", AtomName(ev->display, ev->target), sep);
printf("property=%s%s", AtomName(ev->display, ev->property), sep);
printf("time=%s\n", ServerTime(ev->time));
}
static void
VerbVisibility(XVisibilityEvent *ev)
{
printf("window=0x%x%s", (int)ev->window, sep);
printf("state=%s\n", VisibilityState(ev->state));
}
/******************************************************************************/
/************ Return the string representation for type of an event ***********/
/******************************************************************************/
char *eventtype(XEvent *ev)
{
static char buffer[20];
switch (ev->type) {
case KeyPress:
return ("KeyPress");
case KeyRelease:
return ("KeyRelease");
case ButtonPress:
return ("ButtonPress");
case ButtonRelease:
return ("ButtonRelease");
case MotionNotify:
return ("MotionNotify");
case EnterNotify:
return ("EnterNotify");
case LeaveNotify:
return ("LeaveNotify");
case FocusIn:
return ("FocusIn");
case FocusOut:
return ("FocusOut");
case KeymapNotify:
return ("KeymapNotify");
case Expose:
return ("Expose");
case GraphicsExpose:
return ("GraphicsExpose");
case NoExpose:
return ("NoExpose");
case VisibilityNotify:
return ("VisibilityNotify");
case CreateNotify:
return ("CreateNotify");
case DestroyNotify:
return ("DestroyNotify");
case UnmapNotify:
return ("UnmapNotify");
case MapNotify:
return ("MapNotify");
case MapRequest:
return ("MapRequest");
case ReparentNotify:
return ("ReparentNotify");
case ConfigureNotify:
return ("ConfigureNotify");
case ConfigureRequest:
return ("ConfigureRequest");
case GravityNotify:
return ("GravityNotify");
case ResizeRequest:
return ("ResizeRequest");
case CirculateNotify:
return ("CirculateNotify");
case CirculateRequest:
return ("CirculateRequest");
case PropertyNotify:
return ("PropertyNotify");
case SelectionClear:
return ("SelectionClear");
case SelectionRequest:
return ("SelectionRequest");
case SelectionNotify:
return ("SelectionNotify");
case ColormapNotify:
return ("ColormapNotify");
case ClientMessage:
return ("ClientMessage");
case MappingNotify:
return ("MappingNotify");
}
sprintf(buffer, "%d", ev->type);
return buffer;
}
/******************************************************************************/
/**************** Print the values of all fields for any event ****************/
/******************************************************************************/
void printevent(XEvent *e)
{
XAnyEvent *ev = (void*)e;
printf("%3ld %-20s ", ev->serial, eventtype(e));
if(ev->send_event)
printf("(sendevent) ");
if(0){
printf("type=%s%s", eventtype(e), sep);
printf("serial=%lu%s", ev->serial, sep);
printf("send_event=%s%s", TorF(ev->send_event), sep);
printf("display=0x%p%s", ev->display, sep);
}
switch (ev->type) {
case MotionNotify:
VerbMotion((void*)ev);
break;
case ButtonPress:
case ButtonRelease:
VerbButton((void*)ev);
break;
case ColormapNotify:
VerbColormap((void*)ev);
break;
case EnterNotify:
case LeaveNotify:
VerbCrossing((void*)ev);
break;
case Expose:
VerbExpose((void*)ev);
break;
case GraphicsExpose:
VerbGraphicsExpose((void*)ev);
break;
case NoExpose:
VerbNoExpose((void*)ev);
break;
case FocusIn:
case FocusOut:
VerbFocus((void*)ev);
break;
case KeymapNotify:
VerbKeymap((void*)ev);
break;
case KeyPress:
case KeyRelease:
VerbKey((void*)ev);
break;
case PropertyNotify:
VerbProperty((void*)ev);
break;
case ResizeRequest:
VerbResizeRequest((void*)ev);
break;
case CirculateNotify:
VerbCirculate((void*)ev);
break;
case ConfigureNotify:
VerbConfigure((void*)ev);
break;
case CreateNotify:
VerbCreateWindow((void*)ev);
break;
case DestroyNotify:
VerbDestroyWindow((void*)ev);
break;
case GravityNotify:
VerbGravity((void*)ev);
break;
case MapNotify:
VerbMap((void*)ev);
break;
case ReparentNotify:
VerbReparent((void*)ev);
break;
case UnmapNotify:
VerbUnmap((void*)ev);
break;
case CirculateRequest:
VerbCirculateRequest((void*)ev);
break;
case ConfigureRequest:
VerbConfigureRequest((void*)ev);
break;
case MapRequest:
VerbMapRequest((void*)ev);
break;
case ClientMessage:
VerbClient((void*)ev);
break;
case MappingNotify:
VerbMapping((void*)ev);
break;
case SelectionClear:
VerbSelectionClear((void*)ev);
break;
case SelectionNotify:
VerbSelection((void*)ev);
break;
case SelectionRequest:
VerbSelectionRequest((void*)ev);
break;
case VisibilityNotify:
VerbVisibility((void*)ev);
break;
}
}

2
printevent.h Executable file
View file

@ -0,0 +1,2 @@
char *eventtype(XEvent*);
void printevent(XEvent*);

4
rio.c Executable file
View file

@ -0,0 +1,4 @@
// nothing to see here, but OS X Lion nm complains
// about object files with nothing
int something_to_quiet_lion_nm = 1;

1
ryudomagic.sh Executable file
View file

@ -0,0 +1 @@
mv $O.rio ryudo

13
showevent/Makefile Executable file
View file

@ -0,0 +1,13 @@
CFLAGS = -g
INCLUDE = -I/global/include
LFLAGS = -L/global/lib
OBJS = ShowEvent.o sample.o
LIBS = -lX11
all: sample
.c.o:
$(CC) $(INCLUDE) $(CFLAGS) -c $<
sample: $(OBJS)
$(CC) $(LFLAGS) $(OBJS) $(LIBS) -o sample

888
showevent/ShowEvent.c Executable file
View file

@ -0,0 +1,888 @@
#include <X11/Intrinsic.h>
#include <X11/Xproto.h>
Boolean use_separate_lines = True;
static char *sep;
/******************************************************************************/
/**** Miscellaneous routines to convert values to their string equivalents ****/
/******************************************************************************/
/* Returns the string equivalent of a boolean parameter */
static char *TorF(bool)
int bool;
{
switch (bool) {
case True:
return ("True");
case False:
return ("False");
default:
return ("?");
}
}
/* Returns the string equivalent of a property notify state */
static char *PropertyState(state)
int state;
{
switch (state) {
case PropertyNewValue:
return ("PropertyNewValue");
case PropertyDelete:
return ("PropertyDelete");
default:
return ("?");
}
}
/* Returns the string equivalent of a visibility notify state */
static char *VisibilityState(state)
int state;
{
switch (state) {
case VisibilityUnobscured:
return ("VisibilityUnobscured");
case VisibilityPartiallyObscured:
return ("VisibilityPartiallyObscured");
case VisibilityFullyObscured:
return ("VisibilityFullyObscured");
default:
return ("?");
}
}
/* Returns the string equivalent of a timestamp */
static char *ServerTime(time)
Time time;
{
unsigned long msec;
unsigned long sec;
unsigned long min;
unsigned long hr;
unsigned long day;
static char buffer[32];
msec = time % 1000;
time /= 1000;
sec = time % 60;
time /= 60;
min = time % 60;
time /= 60;
hr = time % 24;
time /= 24;
day = time;
sprintf(buffer, "%ld day%s %02ld:%02ld:%02ld.%03ld",
day, day == 1 ? "" : "(s)", hr, min, sec, msec);
return (buffer);
}
/* Simple structure to ease the interpretation of masks */
typedef struct _MaskType {
unsigned int value;
char *string;
} MaskType;
/* Returns the string equivalent of a mask of buttons and/or modifier keys */
static char *ButtonAndOrModifierState(state)
unsigned int state;
{
static char buffer[256];
static MaskType masks[] = {
{Button1Mask, "Button1Mask"},
{Button2Mask, "Button2Mask"},
{Button3Mask, "Button3Mask"},
{Button4Mask, "Button4Mask"},
{Button5Mask, "Button5Mask"},
{ShiftMask, "ShiftMask"},
{LockMask, "LockMask"},
{ControlMask, "ControlMask"},
{Mod1Mask, "Mod1Mask"},
{Mod2Mask, "Mod2Mask"},
{Mod3Mask, "Mod3Mask"},
{Mod4Mask, "Mod4Mask"},
{Mod5Mask, "Mod5Mask"},
};
int num_masks = sizeof(masks) / sizeof(MaskType);
int i;
Boolean first = True;
buffer[0] = 0;
for (i = 0; i < num_masks; i++)
if (state & masks[i].value)
if (first) {
first = False;
strcpy(buffer, masks[i].string);
} else {
strcat(buffer, " | ");
strcat(buffer, masks[i].string);
}
return (buffer);
}
/* Returns the string equivalent of a mask of configure window values */
static char *ConfigureValueMask(valuemask)
unsigned int valuemask;
{
static char buffer[256];
static MaskType masks[] = {
{CWX, "CWX"},
{CWY, "CWY"},
{CWWidth, "CWWidth"},
{CWHeight, "CWHeight"},
{CWBorderWidth, "CWBorderWidth"},
{CWSibling, "CWSibling"},
{CWStackMode, "CWStackMode"},
};
int num_masks = sizeof(masks) / sizeof(MaskType);
int i;
Boolean first = True;
buffer[0] = 0;
for (i = 0; i < num_masks; i++)
if (valuemask & masks[i].value)
if (first) {
first = False;
strcpy(buffer, masks[i].string);
} else {
strcat(buffer, " | ");
strcat(buffer, masks[i].string);
}
return (buffer);
}
/* Returns the string equivalent of a motion hint */
static char *IsHint(is_hint)
char is_hint;
{
switch (is_hint) {
case NotifyNormal:
return ("NotifyNormal");
case NotifyHint:
return ("NotifyHint");
default:
return ("?");
}
}
/* Returns the string equivalent of an id or the value "None" */
static char *MaybeNone(value)
int value;
{
static char buffer[16];
if (value == None)
return ("None");
else {
sprintf(buffer, "0x%x", value);
return (buffer);
}
}
/* Returns the string equivalent of a colormap state */
static char *ColormapState(state)
int state;
{
switch (state) {
case ColormapInstalled:
return ("ColormapInstalled");
case ColormapUninstalled:
return ("ColormapUninstalled");
default:
return ("?");
}
}
/* Returns the string equivalent of a crossing detail */
static char *CrossingDetail(detail)
int detail;
{
switch (detail) {
case NotifyAncestor:
return ("NotifyAncestor");
case NotifyInferior:
return ("NotifyInferior");
case NotifyVirtual:
return ("NotifyVirtual");
case NotifyNonlinear:
return ("NotifyNonlinear");
case NotifyNonlinearVirtual:
return ("NotifyNonlinearVirtual");
default:
return ("?");
}
}
/* Returns the string equivalent of a focus change detail */
static char *FocusChangeDetail(detail)
int detail;
{
switch (detail) {
case NotifyAncestor:
return ("NotifyAncestor");
case NotifyInferior:
return ("NotifyInferior");
case NotifyVirtual:
return ("NotifyVirtual");
case NotifyNonlinear:
return ("NotifyNonlinear");
case NotifyNonlinearVirtual:
return ("NotifyNonlinearVirtual");
case NotifyPointer:
return ("NotifyPointer");
case NotifyPointerRoot:
return ("NotifyPointerRoot");
case NotifyDetailNone:
return ("NotifyDetailNone");
default:
return ("?");
}
}
/* Returns the string equivalent of a configure detail */
static char *ConfigureDetail(detail)
int detail;
{
switch (detail) {
case Above:
return ("Above");
case Below:
return ("Below");
case TopIf:
return ("TopIf");
case BottomIf:
return ("BottomIf");
case Opposite:
return ("Opposite");
default:
return ("?");
}
}
/* Returns the string equivalent of a grab mode */
static char *GrabMode(mode)
int mode;
{
switch (mode) {
case NotifyNormal:
return ("NotifyNormal");
case NotifyGrab:
return ("NotifyGrab");
case NotifyUngrab:
return ("NotifyUngrab");
case NotifyWhileGrabbed:
return ("NotifyWhileGrabbed");
default:
return ("?");
}
}
/* Returns the string equivalent of a mapping request */
static char *MappingRequest(request)
int request;
{
switch (request) {
case MappingModifier:
return ("MappingModifier");
case MappingKeyboard:
return ("MappingKeyboard");
case MappingPointer:
return ("MappingPointer");
default:
return ("?");
}
}
/* Returns the string equivalent of a stacking order place */
static char *Place(place)
int place;
{
switch (place) {
case PlaceOnTop:
return ("PlaceOnTop");
case PlaceOnBottom:
return ("PlaceOnBottom");
default:
return ("?");
}
}
/* Returns the string equivalent of a major code */
static char *MajorCode(code)
int code;
{
static char buffer[32];
switch (code) {
case X_CopyArea:
return ("X_CopyArea");
case X_CopyPlane:
return ("X_CopyPlane");
default:
sprintf(buffer, "0x%x", code);
return (buffer);
}
}
/* Returns the string equivalent the keycode contained in the key event */
static char *Keycode(ev)
XKeyEvent *ev;
{
static char buffer[256];
KeySym keysym_str;
char *keysym_name;
char string[256];
XLookupString(ev, string, 64, &keysym_str, NULL);
if (keysym_str == NoSymbol)
keysym_name = "NoSymbol";
else if (!(keysym_name = XKeysymToString(keysym_str)))
keysym_name = "(no name)";
sprintf(buffer, "%u (keysym 0x%x \"%s\")",
ev->keycode, (unsigned)keysym_str, keysym_name);
return (buffer);
}
/* Returns the string equivalent of an atom or "None"*/
static char *AtomName(Display *dpy, Atom atom)
{
static char buffer[256];
char *atom_name;
if (atom == None)
return ("None");
atom_name = XGetAtomName(dpy, atom);
strncpy(buffer, atom_name, 256);
XFree(atom_name);
return (buffer);
}
/******************************************************************************/
/**** Routines to print out readable values for the field of various events ***/
/******************************************************************************/
static void VerbMotion(XMotionEvent *ev)
{
printf("window=0x%x%s", (unsigned)ev->window, sep);
printf("root=0x%x%s", (unsigned)ev->root, sep);
printf("subwindow=0x%x%s", (unsigned)ev->subwindow, sep);
printf("time=%s%s", ServerTime(ev->time), sep);
printf("x=%d y=%d%s", ev->x, ev->y, sep);
printf("x_root=%d y_root=%d%s", ev->x_root, ev->y_root, sep);
printf("state=%s%s", ButtonAndOrModifierState(ev->state), sep);
printf("is_hint=%s%s", IsHint(ev->is_hint), sep);
printf("same_screen=%s\n", TorF(ev->same_screen));
}
static void VerbButton(XButtonEvent *ev)
{
printf("window=0x%x%s", (unsigned)ev->window, sep);
printf("root=0x%x%s", (unsigned)ev->root, sep);
printf("subwindow=0x%x%s", (unsigned)ev->subwindow, sep);
printf("time=%s%s", ServerTime(ev->time), sep);
printf("x=%d y=%d%s", ev->x, ev->y, sep);
printf("x_root=%d y_root=%d%s", ev->x_root, ev->y_root, sep);
printf("state=%s%s", ButtonAndOrModifierState(ev->state), sep);
printf("button=%s%s", ButtonAndOrModifierState(ev->button), sep);
printf("same_screen=%s\n", TorF(ev->same_screen));
}
static void VerbColormap(XColormapEvent *ev)
{
printf("window=0x%x%s", (unsigned)ev->window, sep);
printf("colormap=%s%s", MaybeNone(ev->colormap), sep);
printf("new=%s%s", TorF(ev->new), sep);
printf("state=%s\n", ColormapState(ev->state));
}
static void VerbCrossing(XCrossingEvent *ev)
{
printf("window=0x%x%s", (unsigned)ev->window, sep);
printf("root=0x%x%s", (unsigned)ev->root, sep);
printf("subwindow=0x%x%s", (unsigned)ev->subwindow, sep);
printf("time=%s%s", ServerTime(ev->time), sep);
printf("x=%d y=%d%s", ev->x, ev->y, sep);
printf("x_root=%d y_root=%d%s", ev->x_root, ev->y_root, sep);
printf("mode=%s%s", GrabMode(ev->mode), sep);
printf("detail=%s%s", CrossingDetail(ev->detail), sep);
printf("same_screen=%s%s", TorF(ev->same_screen), sep);
printf("focus=%s%s", TorF(ev->focus), sep);
printf("state=%s\n", ButtonAndOrModifierState(ev->state));
}
static void VerbExpose(XExposeEvent *ev)
{
printf("window=0x%x%s", (unsigned)ev->window, sep);
printf("x=%d y=%d%s", ev->x, ev->y, sep);
printf("width=%d height=%d%s", ev->width, ev->height, sep);
printf("count=%d\n", ev->count);
}
static void VerbGraphicsExpose(XGraphicsExposeEvent *ev)
{
printf("drawable=0x%x%s", (unsigned)ev->drawable, sep);
printf("x=%d y=%d%s", ev->x, ev->y, sep);
printf("width=%d height=%d%s", ev->width, ev->height, sep);
printf("major_code=%s%s", MajorCode(ev->major_code), sep);
printf("minor_code=%d\n", ev->minor_code);
}
static void VerbNoExpose(XNoExposeEvent *ev)
{
printf("drawable=0x%x%s", (unsigned)ev->drawable, sep);
printf("major_code=%s%s", MajorCode(ev->major_code), sep);
printf("minor_code=%d\n", ev->minor_code);
}
static void VerbFocus(XFocusChangeEvent *ev)
{
printf("window=0x%x%s", (unsigned)ev->window, sep);
printf("mode=%s%s", GrabMode(ev->mode), sep);
printf("detail=%s\n", FocusChangeDetail(ev->detail));
}
static void VerbKeymap(XKeymapEvent *ev)
{
int i;
printf("window=0x%x%s", (unsigned)ev->window, sep);
printf("key_vector=");
for (i = 0; i < 32; i++)
printf("%02x", ev->key_vector[i]);
printf("\n");
}
static void VerbKey(XKeyEvent *ev)
{
printf("window=0x%x%s", (unsigned)ev->window, sep);
printf("root=0x%x%s", (unsigned)ev->root, sep);
printf("subwindow=0x%x%s", (unsigned)ev->subwindow, sep);
printf("time=%s%s", ServerTime(ev->time), sep);
printf("x=%d y=%d%s", ev->x, ev->y, sep);
printf("x_root=%d y_root=%d%s", ev->x_root, ev->y_root, sep);
printf("state=%s%s", ButtonAndOrModifierState(ev->state), sep);
printf("keycode=%s%s", Keycode(ev), sep);
printf("same_screen=%s\n", TorF(ev->same_screen));
}
static void VerbProperty(XPropertyEvent *ev)
{
printf("window=0x%x%s", (unsigned)ev->window, sep);
printf("atom=%s%s", AtomName(ev->display, ev->atom), sep);
printf("time=%s%s", ServerTime(ev->time), sep);
printf("state=%s\n", PropertyState(ev->state));
}
static void VerbResizeRequest(XResizeRequestEvent *ev)
{
printf("window=0x%x%s", (unsigned)ev->window, sep);
printf("width=%d height=%d\n", ev->width, ev->height);
}
static void VerbCirculate(XCirculateEvent *ev)
{
printf("event=0x%x%s", (unsigned)ev->event, sep);
printf("window=0x%x%s", (unsigned)ev->window, sep);
printf("place=%s\n", Place(ev->place));
}
static void VerbConfigure(XConfigureEvent *ev)
{
printf("event=0x%x%s", (unsigned)ev->event, sep);
printf("window=0x%x%s", (unsigned)ev->window, sep);
printf("x=%d y=%d%s", ev->x, ev->y, sep);
printf("width=%d height=%d%s", ev->width, ev->height, sep);
printf("border_width=%d%s", ev->border_width, sep);
printf("above=%s%s", MaybeNone(ev->above), sep);
printf("override_redirect=%s\n", TorF(ev->override_redirect));
}
static void VerbCreateWindow(XCreateWindowEvent *ev)
{
printf("parent=0x%x%s", (unsigned)ev->parent, sep);
printf("window=0x%x%s", (unsigned)ev->window, sep);
printf("x=%d y=%d%s", ev->x, ev->y, sep);
printf("width=%d height=%d%s", ev->width, ev->height, sep);
printf("border_width=%d%s", ev->border_width, sep);
printf("override_redirect=%s\n", TorF(ev->override_redirect));
}
static void VerbDestroyWindow(XDestroyWindowEvent *ev)
{
printf("event=0x%x%s", (unsigned)ev->event, sep);
printf("window=0x%x\n", (unsigned)ev->window);
}
static void VerbGravity(XGravityEvent *ev)
{
printf("event=0x%x%s", (unsigned)ev->event, sep);
printf("window=0x%x%s", (unsigned)ev->window, sep);
printf("x=%d y=%d\n", ev->x, ev->y);
}
static void VerbMap(XMapEvent *ev)
{
printf("event=0x%x%s", (unsigned)ev->event, sep);
printf("window=0x%x%s", (unsigned)ev->window, sep);
printf("override_redirect=%s\n", TorF(ev->override_redirect));
}
static void VerbReparent(XReparentEvent *ev)
{
printf("event=0x%x%s", (unsigned)ev->event, sep);
printf("window=0x%x%s", (unsigned)ev->window, sep);
printf("parent=0x%x%s", (unsigned)ev->parent, sep);
printf("x=%d y=%d%s", ev->x, ev->y, sep);
printf("override_redirect=%s\n", TorF(ev->override_redirect));
}
static void VerbUnmap(XUnmapEvent *ev)
{
printf("event=0x%x%s", (unsigned)ev->event, sep);
printf("window=0x%x%s", (unsigned)ev->window, sep);
printf("from_configure=%s\n", TorF(ev->from_configure));
}
static void VerbCirculateRequest(XCirculateRequestEvent *ev)
{
printf("parent=0x%x%s", (unsigned)ev->parent, sep);
printf("window=0x%x%s", (unsigned)ev->window, sep);
printf("place=%s\n", Place(ev->place));
}
static void VerbConfigureRequest(XConfigureRequestEvent *ev)
{
printf("parent=0x%x%s", (unsigned)ev->parent, sep);
printf("window=0x%x%s", (unsigned)ev->window, sep);
printf("x=%d y=%d%s", ev->x, ev->y, sep);
printf("width=%d height=%d%s", ev->width, ev->height, sep);
printf("border_width=%d%s", ev->border_width, sep);
printf("above=%s%s", MaybeNone(ev->above), sep);
printf("detail=%s%s", ConfigureDetail(ev->detail), sep);
printf("value_mask=%s\n", ConfigureValueMask(ev->value_mask));
}
static void VerbMapRequest(XMapRequestEvent *ev)
{
printf("parent=0x%x%s", (unsigned)ev->parent, sep);
printf("window=0x%x\n", (unsigned)ev->window);
}
static void VerbClient(XClientMessageEvent *ev)
{
int i;
printf("window=0x%x%s", (unsigned)ev->window, sep);
printf("message_type=%s%s", AtomName(ev->display, ev->message_type), sep);
printf("format=%d\n", ev->format);
printf("data (shown as longs)=");
for (i = 0; i < 5; i++)
printf(" 0x%08lx", ev->data.l[i]);
printf("\n");
}
static void VerbMapping(XMappingEvent *ev)
{
printf("window=0x%x%s", (unsigned)ev->window, sep);
printf("request=%s%s", MappingRequest(ev->request), sep);
printf("first_keycode=0x%x%s", ev->first_keycode, sep);
printf("count=0x%x\n", ev->count);
}
static void VerbSelectionClear(XSelectionClearEvent *ev)
{
printf("window=0x%x%s", (unsigned)ev->window, sep);
printf("selection=%s%s", AtomName(ev->display, ev->selection), sep);
printf("time=%s\n", ServerTime(ev->time));
}
static void VerbSelection(XSelectionEvent *ev)
{
printf("requestor=0x%x%s", (unsigned)ev->requestor, sep);
printf("selection=%s%s", AtomName(ev->display, ev->selection), sep);
printf("target=%s%s", AtomName(ev->display, ev->target), sep);
printf("property=%s%s", AtomName(ev->display, ev->property), sep);
printf("time=%s\n", ServerTime(ev->time));
}
static void VerbSelectionRequest(XSelectionRequestEvent *ev)
{
printf("owner=0x%x%s", (unsigned)ev->owner, sep);
printf("requestor=0x%x%s", (unsigned)ev->requestor, sep);
printf("selection=%s%s", AtomName(ev->display, ev->selection), sep);
printf("target=%s%s", AtomName(ev->display, ev->target), sep);
printf("property=%s%s", AtomName(ev->display, ev->property), sep);
printf("time=%s\n", ServerTime(ev->time));
}
static void VerbVisibility(XVisibilityEvent *ev)
{
printf("window=0x%x%s", (unsigned)ev->window, sep);
printf("state=%s\n", VisibilityState(ev->state));
}
/******************************************************************************/
/************ Return the string representation for type of an event ***********/
/******************************************************************************/
char *GetType(ev)
XEvent *ev;
{
switch (ev->type) {
case KeyPress:
return ("KeyPress");
case KeyRelease:
return ("KeyRelease");
case ButtonPress:
return ("ButtonPress");
case ButtonRelease:
return ("ButtonRelease");
case MotionNotify:
return ("MotionNotify");
case EnterNotify:
return ("EnterNotify");
case LeaveNotify:
return ("LeaveNotify");
case FocusIn:
return ("FocusIn");
case FocusOut:
return ("FocusOut");
case KeymapNotify:
return ("KeymapNotify");
case Expose:
return ("Expose");
case GraphicsExpose:
return ("GraphicsExpose");
case NoExpose:
return ("NoExpose");
case VisibilityNotify:
return ("VisibilityNotify");
case CreateNotify:
return ("CreateNotify");
case DestroyNotify:
return ("DestroyNotify");
case UnmapNotify:
return ("UnmapNotify");
case MapNotify:
return ("MapNotify");
case MapRequest:
return ("MapRequest");
case ReparentNotify:
return ("ReparentNotify");
case ConfigureNotify:
return ("ConfigureNotify");
case ConfigureRequest:
return ("ConfigureRequest");
case GravityNotify:
return ("GravityNotify");
case ResizeRequest:
return ("ResizeRequest");
case CirculateNotify:
return ("CirculateNotify");
case CirculateRequest:
return ("CirculateRequest");
case PropertyNotify:
return ("PropertyNotify");
case SelectionClear:
return ("SelectionClear");
case SelectionRequest:
return ("SelectionRequest");
case SelectionNotify:
return ("SelectionNotify");
case ColormapNotify:
return ("ColormapNotify");
case ClientMessage:
return ("ClientMessage");
case MappingNotify:
return ("MappingNotify");
}
return "???";
}
/******************************************************************************/
/**************** Print the values of all fields for any event ****************/
/******************************************************************************/
void ShowEvent(XEvent *eev)
{
XAnyEvent *ev = (XAnyEvent*)eev;
/* determine which field separator to use */
if (use_separate_lines)
sep = "\n";
else
sep = " ";
printf("type=%s%s", GetType((XEvent*)ev), sep);
printf("serial=%ld%s", ev->serial, sep);
printf("send_event=%s%s", TorF(ev->send_event), sep);
printf("display=0x%p%s", ev->display, sep);
switch (ev->type) {
case MotionNotify:
VerbMotion((void*)ev);
break;
case ButtonPress:
case ButtonRelease:
VerbButton((void*)ev);
break;
case ColormapNotify:
VerbColormap((void*)ev);
break;
case EnterNotify:
case LeaveNotify:
VerbCrossing((void*)ev);
break;
case Expose:
VerbExpose((void*)ev);
break;
case GraphicsExpose:
VerbGraphicsExpose((void*)ev);
break;
case NoExpose:
VerbNoExpose((void*)ev);
break;
case FocusIn:
case FocusOut:
VerbFocus((void*)ev);
break;
case KeymapNotify:
VerbKeymap((void*)ev);
break;
case KeyPress:
case KeyRelease:
VerbKey((void*)ev);
break;
case PropertyNotify:
VerbProperty((void*)ev);
break;
case ResizeRequest:
VerbResizeRequest((void*)ev);
break;
case CirculateNotify:
VerbCirculate((void*)ev);
break;
case ConfigureNotify:
VerbConfigure((void*)ev);
break;
case CreateNotify:
VerbCreateWindow((void*)ev);
break;
case DestroyNotify:
VerbDestroyWindow((void*)ev);
break;
case GravityNotify:
VerbGravity((void*)ev);
break;
case MapNotify:
VerbMap((void*)ev);
break;
case ReparentNotify:
VerbReparent((void*)ev);
break;
case UnmapNotify:
VerbUnmap((void*)ev);
break;
case CirculateRequest:
VerbCirculateRequest((void*)ev);
break;
case ConfigureRequest:
VerbConfigureRequest((void*)ev);
break;
case MapRequest:
VerbMapRequest((void*)ev);
break;
case ClientMessage:
VerbClient((void*)ev);
break;
case MappingNotify:
VerbMapping((void*)ev);
break;
case SelectionClear:
VerbSelectionClear((void*)ev);
break;
case SelectionNotify:
VerbSelection((void*)ev);
break;
case SelectionRequest:
VerbSelectionRequest((void*)ev);
break;
case VisibilityNotify:
VerbVisibility((void*)ev);
break;
}
}

20
showevent/ShowEvent.man Executable file
View file

@ -0,0 +1,20 @@
.TH ShowEvent 3X11 "December 1988"
.SH NAME
.B ShowEvent \- display the fields of an event
.br
.B GetType - get a string representation of an event type
.SH SYNOPSIS
.B void ShowEvent(event)
.br
.B XEvent *event;
.PP
.B char *GetType(event)
.br
.B XEvent *event;
.SH DESCRIPTION
ShowEvent displays the fields of the specified event in a readable form.
.PP
GetType returns the string representation of the specified event type.

1103
showevent/part01 Executable file

File diff suppressed because it is too large Load diff

1
showevent/patchlevel.h Executable file
View file

@ -0,0 +1 @@
#define PATCHLEVEL 0

28
showevent/readme Executable file
View file

@ -0,0 +1,28 @@
I have edited this code to work on modern compilers.
Russ Cox
---
There are times during debugging when it would be real useful to be able to
print the fields of an event in a human readable form. Too many times I found
myself scrounging around in section 8 of the Xlib manual looking for the valid
fields for the events I wanted to see, then adding printf's to display the
numeric values of the fields, and then scanning through X.h trying to decode
the cryptic detail and state fields. After playing with xev, I decided to
write a couple of standard functions that I could keep in a library and call
on whenever I needed a little debugging verbosity. The first function,
GetType(), is useful for returning the string representation of the type of
an event. The second function, ShowEvent(), is used to display all the fields
of an event in a readable format. The functions are not complicated, in fact,
they are mind-numbingly boring - but that's just the point nobody wants to
spend the time writing functions like this, they just want to have them when
they need them.
A simple, sample program is included which does little else but to demonstrate
the use of these two functions. These functions have saved me many an hour
during debugging and I hope you find some benefit to these. If you have any
comments, suggestions, improvements, or if you find any blithering errors you
can get it touch with me at the following location:
ken@richsun.UUCP

48
showevent/sample.c Executable file
View file

@ -0,0 +1,48 @@
#include <X11/Intrinsic.h>
/*
* Disclaimer: No I don't actually code like this but this is a simple,
* "Quick-n-Dirty", plain, vanilla, "No ups, No extras" piece of code.
*/
main(argc, argv)
int argc;
char **argv;
{
Display *dpy;
int screen;
Window window;
XEvent event;
extern Boolean use_separate_lines;
if (!(dpy = XOpenDisplay(""))) {
printf("Failed to open display...\n");
exit(1);
}
screen = DefaultScreen(dpy);
window = XCreateSimpleWindow(dpy, RootWindow(dpy, screen), 100, 100,
300, 200, 2, BlackPixel(dpy, screen), WhitePixel(dpy, screen));
XSelectInput(dpy, window, KeyPressMask | KeyReleaseMask | ButtonPressMask |
ButtonReleaseMask | EnterWindowMask | LeaveWindowMask |
PointerMotionMask | PointerMotionHintMask | Button1MotionMask |
Button2MotionMask | Button3MotionMask | Button4MotionMask |
Button5MotionMask | ButtonMotionMask | KeymapStateMask |
ExposureMask | VisibilityChangeMask | StructureNotifyMask |
SubstructureNotifyMask | SubstructureRedirectMask | FocusChangeMask |
PropertyChangeMask | ColormapChangeMask | OwnerGrabButtonMask);
XMapWindow(dpy, window);
/* set this to false to make ShowEvent take up less vertival space */
use_separate_lines = True;
while (1) {
XNextEvent(dpy, &event);
printf("Detail of %s event:\n", GetType(&event));
ShowEvent(&event);
printf("\n\n");
}
}

45
xevents.c Executable file
View file

@ -0,0 +1,45 @@
/*
* Original code posted to comp.sources.x (see printevent.c).
* Modifications by Russ Cox <rsc@swtch.com>.
*/
#include <stdio.h>
#include <stdlib.h>
#include <X11/Intrinsic.h>
#include "printevent.h"
int
main(int argc, char **argv)
{
int screen;
Display *dpy;
Window window;
XEvent event;
if (!(dpy = XOpenDisplay(""))) {
printf("Failed to open display...\n");
exit(1);
}
screen = DefaultScreen(dpy);
window = XCreateSimpleWindow(dpy, RootWindow(dpy, screen), 100, 100,
300, 200, 2, BlackPixel(dpy, screen), WhitePixel(dpy, screen));
XSelectInput(dpy, window, KeyPressMask | KeyReleaseMask | ButtonPressMask |
ButtonReleaseMask | EnterWindowMask | LeaveWindowMask |
PointerMotionMask | PointerMotionHintMask | Button1MotionMask |
Button2MotionMask | Button3MotionMask | Button4MotionMask |
Button5MotionMask | ButtonMotionMask | KeymapStateMask |
ExposureMask | VisibilityChangeMask | StructureNotifyMask |
SubstructureNotifyMask | SubstructureRedirectMask | FocusChangeMask |
PropertyChangeMask | ColormapChangeMask | OwnerGrabButtonMask);
XMapWindow(dpy, window);
for(;;){
XNextEvent(dpy, &event);
printevent(&event);
}
}

318
xshove.c Executable file
View file

@ -0,0 +1,318 @@
#include <u.h>
#include <X11/X.h>
#include <X11/Xatom.h>
#include <X11/Xlib.h>
#include <X11/Xutil.h>
#include <libc.h>
#include <ctype.h>
AUTOLIB(X11);
typedef struct Rectangle Rectangle;
struct Rectangle
{
struct {
int x;
int y;
} min, max;
};
#define Dx(r) ((r).max.x - (r).min.x)
#define Dy(r) ((r).max.y - (r).min.y)
typedef struct Win Win;
struct Win
{
Window xw;
int x;
int y;
int dx;
int dy;
char *class;
char *instance;
char *name;
char *iconname;
};
Display *dpy;
Window root;
Win *w;
int nw;
void getinfo(void);
void listwindows(void);
int parsewinsize(char*, Rectangle*, int*, int*, int*);
void shove(char*, char*);
void
usage(void)
{
fprint(2, "usage: xshove [window rectangle]\n");
exits("usage");
}
void
main(int argc, char **argv)
{
int screen;
screen = 0;
ARGBEGIN{
case 's':
screen = atoi(EARGF(usage()));
break;
default:
usage();
break;
}ARGEND
dpy = XOpenDisplay("");
if(dpy == nil)
sysfatal("open display: %r");
root = RootWindow(dpy, screen);
getinfo();
if(argc == 0){
listwindows();
exits(0);
}
if(argc != 2)
usage();
shove(argv[0], argv[1]);
exits(0);
}
char*
getproperty(Window w, Atom a)
{
uchar *p;
int fmt;
Atom type;
ulong n, dummy;
n = 100;
p = nil;
XGetWindowProperty(dpy, w, a, 0, 100L, 0,
AnyPropertyType, &type, &fmt,
&n, &dummy, &p);
if(p == nil || *p == 0)
return nil;
return strdup((char*)p);
}
Window
findname(Window w)
{
int i;
uint nxwin;
Window dw1, dw2, *xwin;
if(getproperty(w, XA_WM_NAME))
return w;
if(!XQueryTree(dpy, w, &dw1, &dw2, &xwin, &nxwin))
return 0;
for(i=0; i<nxwin; i++)
if((w = findname(xwin[i])) != 0)
return w;
return 0;
}
void
getinfo(void)
{
int i;
uint nxwin;
Window dw1, dw2, *xwin;
XClassHint class;
XWindowAttributes attr;
if(!XQueryTree(dpy, root, &dw1, &dw2, &xwin, &nxwin))
return;
w = mallocz(nxwin*sizeof w[0], 1);
if(w == 0)
sysfatal("malloc: %r");
Win *ww = w;
for(i=0; i<nxwin; i++){
memset(&attr, 0, sizeof attr);
xwin[i] = findname(xwin[i]);
if(xwin[i] == 0)
continue;
XGetWindowAttributes(dpy, xwin[i], &attr);
if(attr.width <= 0 || attr.override_redirect || attr.map_state != IsViewable)
continue;
ww->xw = xwin[i];
ww->x = attr.x;
ww->y = attr.y;
ww->dx = attr.width;
ww->dy = attr.height;
XTranslateCoordinates(dpy, ww->xw, root, 0, 0, &ww->x, &ww->y, &dw1);
if(XGetClassHint(dpy, ww->xw, &class)){
ww->class = strdup(class.res_class);
ww->instance = strdup(class.res_name);
}
ww->iconname = getproperty(ww->xw, XA_WM_ICON_NAME);
ww->name = getproperty(ww->xw, XA_WM_NAME);
ww++;
}
nw = ww - w;
}
void
listwindows(void)
{
int i;
for(i=0; i<nw; i++){
Win *ww = &w[i];
char rect[50];
snprint(rect, sizeof rect, "%d,%d,%d,%d", ww->x, ww->y, ww->x+ww->dx, ww->y+ww->dy);
print("%08x %-20s %-10s %s\n",
(uint)ww->xw,
rect,
ww->instance,
ww->class);
}
}
void
shove(char *name, char *geom)
{
int i;
int isdelta, havemin, havesize;
int old, new;
Rectangle r;
if(parsewinsize(geom, &r, &isdelta, &havemin, &havesize) < 0)
sysfatal("bad window spec: %s", name);
old = 0;
new = 1;
if(isdelta){
old = 1;
new = isdelta;
}
for(i=0; i<nw; i++){
Win *ww = &w[i];
if(ww->instance && strstr(ww->instance, name)
|| ww->class && strstr(ww->class, name)){
int value_mask;
XWindowChanges e;
memset(&e, 0, sizeof e);
if(havemin){
e.x = old*ww->x + new*r.min.x;
e.y = old*ww->y + new*r.min.y;
}else{
e.x = ww->x;
e.y = ww->y;
}
if(havesize){
e.width = old*ww->dx + new*Dx(r);
e.height = old*ww->dy + new*Dy(r);
}else{
e.width = ww->dx;
e.height = ww->dy;
}
value_mask = CWX | CWY | CWWidth | CWHeight;
XConfigureWindow(dpy, ww->xw, value_mask, &e);
XFlush(dpy);
}
}
}
int
parsewinsize(char *s, Rectangle *r, int *isdelta, int *havemin, int *havesize)
{
char c, *os;
int i, j, k, l;
os = s;
if(*s == '-'){
s++;
*isdelta = -1;
}else if(*s == '+'){
s++;
*isdelta = 1;
}else
*isdelta = 0;
*havemin = 0;
*havesize = 0;
memset(r, 0, sizeof *r);
if(!isdigit((uchar)*s))
goto oops;
i = strtol(s, &s, 0);
if(*s == 'x'){
s++;
if(!isdigit((uchar)*s))
goto oops;
j = strtol(s, &s, 0);
r->max.x = i;
r->max.y = j;
*havesize = 1;
if(*s == 0)
return 0;
if(*s != '@')
goto oops;
s++;
if(!isdigit((uchar)*s))
goto oops;
i = strtol(s, &s, 0);
if(*s != ',' && *s != ' ')
goto oops;
s++;
if(!isdigit((uchar)*s))
goto oops;
j = strtol(s, &s, 0);
if(*s != 0)
goto oops;
r->min.x += i;
r->max.x += i;
r->min.y += j;
r->max.y += j;
*havesize = 1;
*havemin = 1;
return 0;
}
c = *s;
if(c != ' ' && c != ',')
goto oops;
s++;
if(!isdigit((uchar)*s))
goto oops;
j = strtol(s, &s, 0);
if(*s == 0){
r->min.x = i;
r->min.y = j;
*havemin = 1;
return 0;
}
if(*s != c)
goto oops;
s++;
if(!isdigit((uchar)*s))
goto oops;
k = strtol(s, &s, 0);
if(*s != c)
goto oops;
s++;
if(!isdigit((uchar)*s))
goto oops;
l = strtol(s, &s, 0);
if(*s != 0)
goto oops;
r->min.x = i;
r->min.y = j;
r->max.x = k;
r->max.y = l;
*havemin = 1;
*havesize = 1;
return 0;
oops:
werrstr("bad syntax in window size '%s'", os);
return -1;
}