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 }