-
-
Notifications
You must be signed in to change notification settings - Fork 3
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
0 parents
commit 6485c30
Showing
5 changed files
with
261 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
possum |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
TinyWM is written by Nick Welch <mack@incise.org>, 2005. | ||
|
||
This software is in the public domain | ||
and is provided AS IS, with NO WARRANTY. | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,9 @@ | ||
PREFIX?=/usr | ||
CFLAGS?=-Os -pedantic -Wall | ||
|
||
all: | ||
$(CC) $(CFLAGS) -I$(PREFIX)/include -L$(PREFIX)/lib -lX11 -o possum possum.c | ||
|
||
clean: | ||
rm -f possum | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,47 @@ | ||
TinyWM is written by Nick Welch <mack@incise.org>, 2005. | ||
|
||
TinyWM is a ridiculously tiny window manager implemented in nearly as few lines | ||
of C as possible, without being obfuscated or entirely useless. It allows you | ||
to move, resize, focus (sloppy), and raise windows -- that's it! TinyWM's main | ||
purpose is to serve as a quick example of some window manager programming | ||
basics. | ||
|
||
Files: | ||
|
||
Makefile: highly advanced build system | ||
tinywm.c: the code | ||
annotated.c: same, but with tons of rambling comments about everything | ||
tinywm.py: a python version (requires CVS python-xlib due to a bug) | ||
|
||
Usage: | ||
|
||
Focus follows pointer. | ||
Alt+Button1, drag: interactive window move | ||
Alt+Button3, drag: interactive window resize | ||
Alt+F1: raise focused window | ||
|
||
Misc: | ||
|
||
A fella by the name of Trent Buck made a lisp version: | ||
|
||
http://twb.ath.cx/~twb/src/misc/tinywm.lisp | ||
|
||
I have started a wiki about window manager development, although I'm not sure | ||
the subject is popular enough for the wiki to keep from dying a horrible | ||
death. In any case, it is here: | ||
|
||
http://riters.com/WMDev/ | ||
|
||
Another very small window manager is failsafewm. Originally I started | ||
hacking on it, as there was quite a bit of stuff in it that I thought was | ||
unneeded, and I wound up rewriting it from scratch, with just the bare | ||
necessities -- that's TinyWM. | ||
|
||
http://freshmeat.net/projects/failsafewm/ | ||
|
||
Yet another small -- but in comparison, big -- window manager is aewm. It's | ||
a good example for learning about window management, and the fact that so | ||
many WMs have spawned from it is proof. | ||
|
||
http://www.red-bean.com/~decklin/aewm/ | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,199 @@ | ||
/* possum is copyright Nick Markwell, 2009. | ||
* Based on TinyWM by Nick Welch <mack@incise.org> | ||
* and is provided AS IS, with NO WARRANTY. */ | ||
|
||
/* most X stuff will be included with Xlib.h, but a few things require other | ||
* headers, like Xmd.h, keysym.h, etc. | ||
*/ | ||
#include <X11/Xlib.h> | ||
#include <stdlib.h> | ||
#include <string.h> | ||
#include <stdio.h> | ||
|
||
/* Yay for a macro that lets you use KEYCODE("key") to generate the definition... | ||
* KEYCODE("F1") | ||
* -> | ||
* KeyCode kc_F1 = XKeysymToKeycode(dpy, XStringToKeysym("F1")); | ||
*/ | ||
#define KEYCODE(NAME) KeyCode kc_##NAME = XKeysymToKeycode(dpy, XStringToKeysym( #NAME )); | ||
#define KEYGRAB(NAME) XGrabKey(dpy, kc_##NAME, Mod1Mask, root, True, GrabModeAsync, GrabModeAsync); | ||
|
||
#define MAX(a, b) ((a) > (b) ? (a) : (b)) | ||
|
||
int main() | ||
{ | ||
Display * dpy; | ||
Window root; | ||
XWindowAttributes attr; | ||
|
||
/* we use this to save the pointer's state at the beginning of the | ||
* move/resize. | ||
*/ | ||
XButtonEvent start; | ||
|
||
XEvent ev; | ||
|
||
/* Get $DISPLAY from the environment */ | ||
char *display_str = getenv("DISPLAY"); | ||
|
||
/* If $DISPLAY wasn't defined, use :0.0 */ | ||
if ( !strcmp("", display_str) ) display_str = ":0.0"; | ||
|
||
/* return failure status if we can't connect */ | ||
if(!(dpy = XOpenDisplay(display_str))) return 1; | ||
|
||
root = DefaultRootWindow(dpy); | ||
|
||
/* you could also include keysym.h and use the XK_F1 constant instead of | ||
* the call to XStringToKeysym, but this method is more "dynamic." imagine | ||
* you have config files which specify key bindings. instead of parsing | ||
* the key names and having a huge table or whatever to map strings to XK_* | ||
* constants, you can just take the user-specified string and hand it off | ||
* to XStringToKeysym. XStringToKeysym will give you back the appropriate | ||
* keysym or tell you if it's an invalid key name. | ||
* | ||
* a keysym is basically a platform-independent numeric representation of a | ||
* key, like "F1", "a", "b", "L", "5", "Shift", etc. a keycode is a | ||
* numeric representation of a key on the keyboard sent by the keyboard | ||
* driver (or something along those lines -- i'm no hardware/driver expert) | ||
* to X. so we never want to hard-code keycodes, because they can and will | ||
* differ between systems. | ||
*/ | ||
KEYCODE(F1) | ||
KEYCODE(F2) | ||
KEYCODE(F3) | ||
KEYCODE(F4) | ||
KEYCODE(F5) | ||
KEYCODE(F6) | ||
KEYCODE(F7) | ||
KEYCODE(F8) | ||
KEYCODE(F9) | ||
KEYCODE(F10) | ||
KEYCODE(F11) | ||
KEYCODE(F12) | ||
KEYCODE(Enter) | ||
KEYGRAB(F1) | ||
KEYGRAB(F2) | ||
KEYGRAB(F3) | ||
KEYGRAB(F4) | ||
KEYGRAB(F5) | ||
KEYGRAB(F6) | ||
KEYGRAB(F7) | ||
KEYGRAB(F8) | ||
KEYGRAB(F9) | ||
KEYGRAB(F10) | ||
KEYGRAB(F11) | ||
KEYGRAB(F12) | ||
KEYGRAB(Enter) | ||
/*XGrabKey(dpy, kc_Enter, Mod1Mask, root, True, GrabModeAsync, GrabModeAsync);*/ | ||
|
||
/* XGrabKey and XGrabButton are basically ways of saying "when this | ||
* combination of modifiers and key/button is pressed, send me the events." | ||
* so we can safely assume that we'll receive Alt+F1 events, Alt+Button1 | ||
* events, and Alt+Button3 events, but no others. You can either do | ||
* individual grabs like these for key/mouse combinations, or you can use | ||
* XSelectInput with KeyPressMask/ButtonPressMask/etc to catch all events | ||
* of those types and filter them as you receive them. | ||
*/ | ||
XGrabButton(dpy, 1, Mod1Mask, root, True, ButtonPressMask, GrabModeAsync, | ||
GrabModeAsync, None, None); | ||
XGrabButton(dpy, 2, Mod1Mask, root, True, ButtonPressMask, GrabModeAsync, | ||
GrabModeAsync, None, None); | ||
XGrabButton(dpy, 3, Mod1Mask, root, True, ButtonPressMask, GrabModeAsync, | ||
GrabModeAsync, None, None); | ||
|
||
for(;;) | ||
{ | ||
/* this is the most basic way of looping through X events; you can be | ||
* more flexible by using XPending(), or ConnectionNumber() along with | ||
* select() (or poll() or whatever floats your boat). | ||
*/ | ||
XNextEvent(dpy, &ev); | ||
|
||
/* this is our keybinding for raising windows. as i saw someone | ||
* mention on the ratpoison wiki, it is pretty stupid; however, i | ||
* wanted to fit some sort of keyboard binding in here somewhere, and | ||
* this was the best fit for it. | ||
* | ||
* i was a little confused about .window vs. .subwindow for a while, | ||
* but a little RTFMing took care of that. our passive grabs above | ||
* grabbed on the root window, so since we're only interested in events | ||
* for its child windows, we look at .subwindow. when subwindow | ||
* None, that means that the window the event happened in was the same | ||
* window that was grabbed on -- in this case, the root window. | ||
*/ | ||
if(ev.type == KeyPress && ev.xkey.subwindow != None) | ||
XRaiseWindow(dpy, ev.xkey.subwindow); | ||
else if(ev.type == ButtonPress && ev.xbutton.subwindow != None) | ||
{ | ||
fprintf(stderr, "BUTTON DOWN!!!!!\n"); | ||
/* Raise the window */ | ||
XRaiseWindow(dpy, ev.xbutton.subwindow); | ||
|
||
/* now we take command of the pointer, looking for motion and | ||
* button release events. | ||
*/ | ||
XGrabPointer(dpy, ev.xbutton.subwindow, True, | ||
PointerMotionMask|ButtonReleaseMask, GrabModeAsync, | ||
GrabModeAsync, None, None, CurrentTime); | ||
|
||
/* we "remember" the position of the pointer at the beginning of | ||
* our move/resize, and the size/position of the window. that way, | ||
* when the pointer moves, we can compare it to our initial data | ||
* and move/resize accordingly. | ||
*/ | ||
XGetWindowAttributes(dpy, ev.xbutton.subwindow, &attr); | ||
start = ev.xbutton; | ||
} | ||
/* the only way we'd receive a motion notify event is if we already did | ||
* a pointer grab and we're in move/resize mode, so we assume that. */ | ||
else if(ev.type == MotionNotify) | ||
{ | ||
int xdiff, ydiff; | ||
|
||
/* here we "compress" motion notify events. if there are 10 of | ||
* them waiting, it makes no sense to look at any of them but the | ||
* most recent. in some cases -- if the window is really big or | ||
* things are just acting slowly in general -- failing to do this | ||
* can result in a lot of "drag lag." | ||
* | ||
* for window managers with things like desktop switching, it can | ||
* also be useful to compress EnterNotify events, so that you don't | ||
* get "focus flicker" as windows shuffle around underneath the | ||
* pointer. | ||
*/ | ||
while(XCheckTypedEvent(dpy, MotionNotify, &ev)); | ||
|
||
/* now we use the stuff we saved at the beginning of the | ||
* move/resize and compare it to the pointer's current position to | ||
* determine what the window's new size or position should be. | ||
* | ||
* if the initial button press was button 1, then we're moving. | ||
* otherwise it was 3 and we're resizing. | ||
* | ||
* we also make sure not to go negative with the window's | ||
* dimensions, resulting in "wrapping" which will make our window | ||
* something ridiculous like 65000 pixels wide (often accompanied | ||
* by lots of swapping and slowdown). | ||
* | ||
* even worse is if we get "lucky" and hit a width or height of | ||
* exactly zero, triggering an X error. so we specify a minimum | ||
* width/height of 1 pixel. | ||
*/ | ||
xdiff = ev.xbutton.x_root - start.x_root; | ||
ydiff = ev.xbutton.y_root - start.y_root; | ||
XMoveResizeWindow(dpy, ev.xmotion.window, | ||
attr.x + (start.button==1 ? xdiff : 0), | ||
attr.y + (start.button==1 ? ydiff : 0), | ||
MAX(1, attr.width + (start.button==3 ? xdiff : 0)), | ||
MAX(1, attr.height + (start.button==3 ? ydiff : 0))); | ||
} | ||
/* like motion notifies, the only way we'll receive a button release is | ||
* during a move/resize, due to our pointer grab. this ends the | ||
* move/resize. | ||
*/ | ||
else if(ev.type == ButtonRelease) | ||
if ( ev.xbutton.subwindow != None ) | ||
XUngrabPointer(dpy, CurrentTime); | ||
} | ||
} |