Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- /* TinyWM is written by Nick Welch <[email protected]>, 2005.
- *
- * This software is in the public domain
- * and is provided AS IS, with NO WARRANTY. */
- /* much of tinywm's purpose is to serve as a very basic example of how to do X
- * stuff and/or understand window managers, so i wanted to put comments in the
- * code explaining things, but i really hate wading through code that is
- * over-commented -- and for that matter, tinywm is supposed to be as concise
- * as possible, so having lots of comments just wasn't really fitting for it.
- * i want tinywm.c to be something you can just look at and go "wow, that's
- * it? cool!" so what i did was just copy it over to annotated.c and comment
- * the hell out of it. ahh, but now i have to make every code change twice!
- * oh well. i could always use some sort of script to process the comments out
- * of this and write it to tinywm.c ... nah.
- */
- /* 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>
- #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;
- /* return failure status if we can't connect */
- if(!(dpy = XOpenDisplay(0x0))) return 1;
- /* you'll usually be referencing the root window a lot. this is a somewhat
- * naive approach that will only work on the default screen. most people
- * only have one screen, but not everyone. if you run multi-head without
- * xinerama then you quite possibly have multiple screens. (i'm not sure
- * about vendor-specific implementations, like nvidia's)
- *
- * many, probably most window managers only handle one screen, so in
- * reality this isn't really *that* naive.
- *
- * if you wanted to get the root window of a specific screen you'd use
- * RootWindow(), but the user can also control which screen is our default:
- * if they set $DISPLAY to ":0.foo", then our default screen number is
- * whatever they specify "foo" as.
- */
- 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.
- */
- XGrabKey(dpy, XKeysymToKeycode(dpy, XStringToKeysym("F1")), 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, 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)
- {
- /* 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)
- XUngrabPointer(dpy, CurrentTime);
- }
- }
Advertisement
Add Comment
Please, Sign In to add comment