sowm

An itsy bitsy floating window manager (220~ sloc!).
git clone git://mfeller.io/sowm.git
Log | Files | Refs | README | LICENSE

sowm.c (7234B)


      1 // sowm - An itsy bitsy floating window manager.
      2 
      3 #include <X11/Xlib.h>
      4 #include <X11/XF86keysym.h>
      5 #include <X11/keysym.h>
      6 #include <X11/XKBlib.h>
      7 #include <stdlib.h>
      8 #include <signal.h>
      9 #include <unistd.h>
     10 
     11 #include "sowm.h"
     12 
     13 static client       *list = {0}, *ws_list[10] = {0}, *cur;
     14 static int          ws = 1, sw, sh, wx, wy, numlock = 0;
     15 static unsigned int ww, wh;
     16 
     17 static Display      *d;
     18 static XButtonEvent mouse;
     19 static Window       root;
     20 
     21 static void (*events[LASTEvent])(XEvent *e) = {
     22     [ButtonPress]      = button_press,
     23     [ButtonRelease]    = button_release,
     24     [ConfigureRequest] = configure_request,
     25     [KeyPress]         = key_press,
     26     [MapRequest]       = map_request,
     27     [DestroyNotify]    = notify_destroy,
     28     [EnterNotify]      = notify_enter,
     29     [MotionNotify]     = notify_motion
     30 };
     31 
     32 #include "config.h"
     33 
     34 void win_focus(client *c) {
     35     cur = c;
     36     XSetInputFocus(d, cur->w, RevertToParent, CurrentTime);
     37 }
     38 
     39 void win_move(const Arg arg) {
     40 	int r = arg.com[0][0] == 'r';
     41 	char m = arg.com[1][0];
     42 
     43 	win_size(cur->w, &wx, &wy, &ww, &wh);
     44 
     45 	XMoveResizeWindow(d, cur->w, \
     46 		wx + (r ? 0 : m == 'e' ?  arg.i : m == 'w' ? -arg.i : 0),
     47 		wy + (r ? 0 : m == 'n' ? -arg.i : m == 's' ?  arg.i : 0),
     48 		MAX(10, ww + (r ? m == 'e' ?  arg.i : m == 'w' ? -arg.i : 0 : 0)),
     49 		MAX(10, wh + (r ? m == 'n' ? -arg.i : m == 's' ?  arg.i : 0 : 0)));
     50 }
     51 
     52 void notify_destroy(XEvent *e) {
     53     win_del(e->xdestroywindow.window);
     54 
     55     if (list) win_focus(list->prev);
     56 }
     57 
     58 void notify_enter(XEvent *e) {
     59     while(XCheckTypedEvent(d, EnterNotify, e));
     60 
     61     for win if (c->w == e->xcrossing.window) win_focus(c);
     62 }
     63 
     64 void notify_motion(XEvent *e) {
     65     if (!mouse.subwindow || cur->f) return;
     66 
     67     while(XCheckTypedEvent(d, MotionNotify, e));
     68     while(XCheckTypedWindowEvent(d, mouse.subwindow, MotionNotify, e));
     69 
     70     int xd = e->xbutton.x_root - mouse.x_root;
     71     int yd = e->xbutton.y_root - mouse.y_root;
     72 
     73     XMoveResizeWindow(d, mouse.subwindow,
     74         wx + (mouse.button == 1 ? xd : 0),
     75         wy + (mouse.button == 1 ? yd : 0),
     76         MAX(1, ww + (mouse.button == 3 ? xd : 0)),
     77         MAX(1, wh + (mouse.button == 3 ? yd : 0)));
     78 }
     79 
     80 void key_press(XEvent *e) {
     81     KeySym keysym = XkbKeycodeToKeysym(d, e->xkey.keycode, 0, 0);
     82 
     83     for (unsigned int i=0; i < sizeof(keys)/sizeof(*keys); ++i)
     84         if (keys[i].keysym == keysym &&
     85             mod_clean(keys[i].mod) == mod_clean(e->xkey.state))
     86             keys[i].function(keys[i].arg);
     87 }
     88 
     89 void button_press(XEvent *e) {
     90     if (!e->xbutton.subwindow) return;
     91 
     92     win_size(e->xbutton.subwindow, &wx, &wy, &ww, &wh);
     93     XRaiseWindow(d, e->xbutton.subwindow);
     94     mouse = e->xbutton;
     95 }
     96 
     97 void button_release(XEvent *e) {
     98     mouse.subwindow = 0;
     99 }
    100 
    101 void win_add(Window w) {
    102     client *c;
    103     XWindowChanges wc;
    104 
    105     if (!(c = (client *) calloc(1, sizeof(client))))
    106         exit(1);
    107 
    108     c->w = w;
    109 
    110     wc.border_width = BorderWidth;
    111     XConfigureWindow(d, w, (1<<4), &wc);
    112     XSetWindowBorder(d, w, BorderColor);
    113 
    114     if (list) {
    115         list->prev->next = c;
    116         c->prev          = list->prev;
    117         list->prev       = c;
    118         c->next          = list;
    119 
    120     } else {
    121         list = c;
    122         list->prev = list->next = list;
    123     }
    124 
    125     ws_save(ws);
    126 }
    127 
    128 void win_del(Window w) {
    129     client *x = 0;
    130 
    131     for win if (c->w == w) x = c;
    132 
    133     if (!list || !x)  return;
    134     if (x->prev == x) list = 0;
    135     if (list == x)    list = x->next;
    136     if (x->next)      x->next->prev = x->prev;
    137     if (x->prev)      x->prev->next = x->next;
    138 
    139     free(x);
    140     ws_save(ws);
    141 }
    142 
    143 void win_kill(const Arg arg) {
    144     if (cur) XKillClient(d, cur->w);
    145 }
    146 
    147 void win_center(const Arg arg) {
    148     if (!cur) return;
    149 
    150     win_size(cur->w, &(int){0}, &(int){0}, &ww, &wh);
    151     XMoveWindow(d, cur->w, (sw - ww) / 2, (sh - wh) / 2);
    152 }
    153 
    154 void win_fs(const Arg arg) {
    155     if (!cur) return;
    156 
    157     if ((cur->f = cur->f ? 0 : 1)) {
    158         win_size(cur->w, &cur->wx, &cur->wy, &cur->ww, &cur->wh);
    159         XMoveResizeWindow(d, cur->w, -BorderWidth, -BorderWidth, sw, sh);
    160 
    161     } else {
    162         XMoveResizeWindow(d, cur->w, cur->wx, cur->wy, cur->ww, cur->wh);
    163     }
    164 }
    165 
    166 void win_to_ws(const Arg arg) {
    167     int tmp = ws;
    168 
    169     if (arg.i == tmp) return;
    170 
    171     ws_sel(arg.i);
    172     win_add(cur->w);
    173     ws_save(arg.i);
    174 
    175     ws_sel(tmp);
    176     win_del(cur->w);
    177     XUnmapWindow(d, cur->w);
    178     ws_save(tmp);
    179 
    180     if (list) win_focus(list);
    181 }
    182 
    183 void win_prev(const Arg arg) {
    184     if (!cur) return;
    185 
    186     XRaiseWindow(d, cur->prev->w);
    187     win_focus(cur->prev);
    188 }
    189 
    190 void win_next(const Arg arg) {
    191     if (!cur) return;
    192 
    193     XRaiseWindow(d, cur->next->w);
    194     win_focus(cur->next);
    195 }
    196 
    197 void ws_go(const Arg arg) {
    198     int tmp = ws;
    199 
    200     if (arg.i == ws) return;
    201 
    202     ws_save(ws);
    203     ws_sel(arg.i);
    204 
    205     for win XMapWindow(d, c->w);
    206 
    207     ws_sel(tmp);
    208 
    209     for win XUnmapWindow(d, c->w);
    210 
    211     ws_sel(arg.i);
    212 
    213     if (list) win_focus(list); else cur = 0;
    214 }
    215 
    216 void configure_request(XEvent *e) {
    217     XConfigureRequestEvent *ev = &e->xconfigurerequest;
    218 
    219     XConfigureWindow(d, ev->window, ev->value_mask, &(XWindowChanges) {
    220         .x          = ev->x,
    221         .y          = ev->y,
    222         .width      = ev->width,
    223         .height     = ev->height,
    224         .sibling    = ev->above,
    225         .stack_mode = ev->detail
    226     });
    227 }
    228 
    229 void map_request(XEvent *e) {
    230     Window w = e->xmaprequest.window;
    231 
    232     XSelectInput(d, w, StructureNotifyMask|EnterWindowMask);
    233     win_size(w, &wx, &wy, &ww, &wh);
    234     win_add(w);
    235     cur = list->prev;
    236 
    237     if (wx + wy == 0) win_center((Arg){0});
    238 
    239     XMapWindow(d, w);
    240     win_focus(list->prev);
    241 }
    242 
    243 void run(const Arg arg) {
    244     if (fork()) return;
    245     if (d) close(ConnectionNumber(d));
    246 
    247     setsid();
    248     execvp((char*)arg.com[0], (char**)arg.com);
    249 }
    250 
    251 void input_grab(Window root) {
    252     unsigned int i, j, modifiers[] = {0, LockMask, numlock, numlock|LockMask};
    253     XModifierKeymap *modmap = XGetModifierMapping(d);
    254     KeyCode code;
    255 
    256     for (i = 0; i < 8; i++)
    257         for (int k = 0; k < modmap->max_keypermod; k++)
    258             if (modmap->modifiermap[i * modmap->max_keypermod + k]
    259                 == XKeysymToKeycode(d, 0xff7f))
    260                 numlock = (1 << i);
    261 
    262     for (i = 0; i < sizeof(keys)/sizeof(*keys); i++)
    263         if ((code = XKeysymToKeycode(d, keys[i].keysym)))
    264             for (j = 0; j < sizeof(modifiers)/sizeof(*modifiers); j++)
    265                 XGrabKey(d, code, keys[i].mod | modifiers[j], root,
    266                         True, GrabModeAsync, GrabModeAsync);
    267 
    268     for (i = 1; i < 4; i += 2)
    269         for (j = 0; j < sizeof(modifiers)/sizeof(*modifiers); j++)
    270             XGrabButton(d, i, MOD | modifiers[j], root, True,
    271                 ButtonPressMask|ButtonReleaseMask|PointerMotionMask,
    272                 GrabModeAsync, GrabModeAsync, 0, 0);
    273 
    274     XFreeModifiermap(modmap);
    275 }
    276 
    277 int main(void) {
    278     XEvent ev;
    279 
    280     if (!(d = XOpenDisplay(0))) exit(1);
    281 
    282     signal(SIGCHLD, SIG_IGN);
    283     XSetErrorHandler(xerror);
    284 
    285     int s = DefaultScreen(d);
    286     root  = RootWindow(d, s);
    287     sw    = XDisplayWidth(d, s);
    288     sh    = XDisplayHeight(d, s);
    289 
    290     XSelectInput(d,  root, SubstructureRedirectMask);
    291     XDefineCursor(d, root, XCreateFontCursor(d, 68));
    292     input_grab(root);
    293 
    294     while (1 && !XNextEvent(d, &ev))
    295         if (events[ev.type]) events[ev.type](&ev);
    296 }