meta: Rewrite sowm and swap to XCB.

This was my first real C project and it shows. Learning C is quite
fun and I still have a long way to go. This next rewrite should be
less of a hot-mess than the original Xlib version.

Notable mistakes:

- while (1 && ...)
- for win (spastic pre-processor stuff)
- no proper tracking of client sizes/positions.
- lazy window focus model.
- almost code-golfed code-base.
- circular-doubly-linked-list for clients.

The following changes mark the initial commit for the rewrite.
The window manager works but does not yet do enough for it to be
usable. Clients, keybindings, a configuration file, etc, etc do
not yet exist. Baby steps.
This commit is contained in:
Dylan Araps 2020-07-11 11:31:30 +03:00
parent d327a0978a
commit 1a4c655b9d
No known key found for this signature in database
GPG Key ID: 46D62DD9F1DE636E
7 changed files with 180 additions and 477 deletions

1
.gitignore vendored
View File

@ -1,3 +1,4 @@
sowm
sowm.o
config.h
.ccls-cache

View File

@ -1,33 +0,0 @@
MIT/X Consortium License
- © 2019- Dylan Araps <dylan.araps@gmail.com>
- © 2006-2011 Anselm R Garbe <anselm@garbe.us>
- © 2007-2011 Peter Hartlich <sgkkr at hartlich dot com>
- © 2010-2011 Connor Lane Smith <cls@lubutu.com>
- © 2006-2009 Jukka Salmi <jukka at salmi dot ch>
- © 2007-2009 Premysl Hruby <dfenze at gmail dot com>
- © 2007-2009 Szabolcs Nagy <nszabolcs at gmail dot com>
- © 2007-2009 Christof Musik <christof at sendfax dot de>
- © 2009 Mate Nagy <mnagy at port70 dot net>
- © 2007-2008 Enno Gottox Boland <gottox at s01 dot de>
- © 2008 Martin Hurton <martin dot hurton at gmail dot com>
- © 2008 Neale Pickett <neale dot woozle dot org>
- © 2006-2007 Sander van Dijk <a dot h dot vandijk at gmail dot com>
Permission is hereby granted, free of charge, to any person obtaining a
copy of this software and associated documentation files (the "Software"),
to deal in the Software without restriction, including without limitation
the rights to use, copy, modify, merge, publish, distribute, sublicense,
and/or sell copies of the Software, and to permit persons to whom the
Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
DEALINGS IN THE SOFTWARE.

View File

@ -1,22 +1,24 @@
CFLAGS += -std=c99 -Wall -Wextra -pedantic -Wold-style-declaration
CFLAGS += -Wmissing-prototypes -Wno-unused-parameter
PREFIX ?= /usr
BINDIR ?= $(PREFIX)/bin
CC ?= gcc
.POSIX:
PREFIX = /usr/local
ALL_WARN = -Wall -Wextra -pedantic -Wmissing-prototypes -Wstrict-prototypes
ALL_CFLAGS = $(CFLAGS) $(CPPFLAGS) -std=c99 $(ALL_WARN)
ALL_LDFLAGS = $(LDFLAGS) -lxcb
CC = cc
all: sowm
config.h:
cp config.def.h config.h
sowm: sowm.c sowm.h config.h Makefile
$(CC) -O3 $(CFLAGS) -o $@ $< -lX11 $(LDFLAGS)
sowm: sowm.c Makefile
$(CC) -O3 $(ALL_CFLAGS) -o $@ $< $(ALL_LDFLAGS)
install: all
install -Dm755 sowm $(DESTDIR)$(BINDIR)/sowm
mkdir -p $(DESTDIR)/bin
cp sowm $(DESTDIR)/bin/sowm
uninstall:
rm -f $(DESTDIR)$(BINDIR)/sowm
rm -f $(DESTDIR)/bin/sowm
clean:
rm -f sowm *.o

View File

@ -1,98 +0,0 @@
# sowm (*~~Simple~~ Shitty Opinionated Window Manager*)
<a href="https://user-images.githubusercontent.com/6799467/66687576-9747c200-ec72-11e9-947d-5b96753eab03.jpg"><img src="https://user-images.githubusercontent.com/6799467/66687576-9747c200-ec72-11e9-947d-5b96753eab03.jpg" width="43%" align="right"></a>
An itsy bitsy floating window manager (*220~ sloc!*).
- Floating only.
- Fullscreen toggle.
- Window centering.
- Mix of mouse and keyboard workflow.
- Focus with cursor.
- Rounded corners (*[through patch](https://github.com/dylanaraps/sowm/pull/58)*)
- Titlebars (*[through patch](https://github.com/dylanaraps/sowm/pull/57)*)
<a href="https://user-images.githubusercontent.com/6799467/66687814-8cd9f800-ec73-11e9-97b8-6ae77876bd1b.jpg"><img src="https://user-images.githubusercontent.com/6799467/66687814-8cd9f800-ec73-11e9-97b8-6ae77876bd1b.jpg" width="43%" align="right"></a>
- Alt-Tab window focusing.
- All windows die on exit.
- No window borders.
- [No ICCCM](https://web.archive.org/web/20190617214524/https://raw.githubusercontent.com/kfish/xsel/1a1c5edf0dc129055f7764c666da2dd468df6016/rant.txt).
- No EWMH.
- etc etc etc
<br>
Patches available here: https://github.com/dylanaraps/sowm/pulls
## Default Keybindings
**Window Management**
| combo | action |
| -------------------------- | -----------------------|
| `Mouse` | focus under cursor |
| `MOD4` + `Left Mouse` | move window |
| `MOD4` + `Right Mouse` | resize window |
| `MOD4` + `f` | maximize toggle |
| `MOD4` + `c` | center window |
| `MOD4` + `q` | kill window |
| `MOD4` + `1-9` | desktop swap |
| `MOD4` + `Shift` +`1-9` | send window to desktop |
| `MOD1` + `TAB` (*alt-tab*) | focus cycle |
**Programs**
| combo | action | program |
| ------------------------ | ---------------- | -------------- |
| `MOD4` + `Return` | terminal | `st` |
| `MOD4` + `d` | dmenu | `dmenu_run` |
| `MOD4` + `p` | scrot | `scr` |
| `MOD4` + `w` | wallpaper cycler | `bud` |
| `XF86_AudioLowerVolume` | volume down | `amixer` |
| `XF86_AudioRaiseVolume` | volume up | `amixer` |
| `XF86_AudioMute` | volume toggle | `amixer` |
| `XF86_MonBrightnessUp` | brightness up | `bri` |
| `XF86_MonBrightnessDown` | brightness down | `bri` |
## Dependencies
- `xlib` (*usually `libX11`*).
## Installation
1) Copy `config.def.h` to `config.h` and modify it to suit your needs.
2) Run `make` to build `sowm`.
3) Copy it to your path or run `make install`.
- `DESTDIR` and `PREFIX` are supported.
4) (Optional) Apply patch with `git apply patches/patch-name`
- In case of applying multiple patches, it has to be done **manually**.
If you are using GDM, save the following to `/usr/share/xsessions/sowm.desktop`. It is still recommended to start `sowm` from `.xinitrc` or through
[your own xinit implementation](https://github.com/dylanaraps/bin/blob/dfd9a9ff4555efb1cc966f8473339f37d13698ba/x).
```
[Desktop Entry]
Name=sowm
Comment=This session runs sowm as desktop manager
Exec=sowm
Type=Application
```
## Thanks
- 2bwm
- SmallWM
- berry
- catwm
- dminiwm
- dwm
- monsterwm
- openbox
- possumwm
- swm
- tinywm

View File

@ -1,49 +0,0 @@
#ifndef CONFIG_H
#define CONFIG_H
#define MOD Mod4Mask
const char* menu[] = {"dmenu_run", 0};
const char* term[] = {"st", 0};
const char* scrot[] = {"scr", 0};
const char* briup[] = {"bri", "10", "+", 0};
const char* bridown[] = {"bri", "10", "-", 0};
const char* voldown[] = {"amixer", "sset", "Master", "5%-", 0};
const char* volup[] = {"amixer", "sset", "Master", "5%+", 0};
const char* volmute[] = {"amixer", "sset", "Master", "toggle", 0};
const char* colors[] = {"bud", "/home/goldie/Pictures/Wallpapers", 0};
static struct key keys[] = {
{MOD, XK_q, win_kill, {0}},
{MOD, XK_c, win_center, {0}},
{MOD, XK_f, win_fs, {0}},
{Mod1Mask, XK_Tab, win_next, {0}},
{Mod1Mask|ShiftMask, XK_Tab, win_prev, {0}},
{MOD, XK_d, run, {.com = menu}},
{MOD, XK_w, run, {.com = colors}},
{MOD, XK_p, run, {.com = scrot}},
{MOD, XK_Return, run, {.com = term}},
{0, XF86XK_AudioLowerVolume, run, {.com = voldown}},
{0, XF86XK_AudioRaiseVolume, run, {.com = volup}},
{0, XF86XK_AudioMute, run, {.com = volmute}},
{0, XF86XK_MonBrightnessUp, run, {.com = briup}},
{0, XF86XK_MonBrightnessDown, run, {.com = bridown}},
{MOD, XK_1, ws_go, {.i = 1}},
{MOD|ShiftMask, XK_1, win_to_ws, {.i = 1}},
{MOD, XK_2, ws_go, {.i = 2}},
{MOD|ShiftMask, XK_2, win_to_ws, {.i = 2}},
{MOD, XK_3, ws_go, {.i = 3}},
{MOD|ShiftMask, XK_3, win_to_ws, {.i = 3}},
{MOD, XK_4, ws_go, {.i = 4}},
{MOD|ShiftMask, XK_4, win_to_ws, {.i = 4}},
{MOD, XK_5, ws_go, {.i = 5}},
{MOD|ShiftMask, XK_5, win_to_ws, {.i = 5}},
{MOD, XK_6, ws_go, {.i = 6}},
{MOD|ShiftMask, XK_6, win_to_ws, {.i = 6}},
};
#endif

356
sowm.c
View File

@ -1,277 +1,167 @@
// sowm - An itsy bitsy floating window manager.
#include <X11/Xlib.h>
#include <X11/XF86keysym.h>
#include <X11/keysym.h>
#include <X11/XKBlib.h>
#define _POSIX_C_SOURCE 200809L
#include <stdio.h>
#include <stdlib.h>
#include <signal.h>
#include <unistd.h>
#include <xcb/xcb.h>
#include "sowm.h"
static client *list = {0}, *ws_list[10] = {0}, *cur;
static int ws = 1, sw, sh, wx, wy, numlock = 0;
static unsigned int ww, wh;
void event_button_press(xcb_generic_event_t *ev) {
xcb_button_press_event_t *e = (xcb_button_press_event_t *)ev;
static Display *d;
static XButtonEvent mouse;
static Window root;
ev_vals[0] = XCB_STACK_MODE_ABOVE;
xcb_configure_window(dpy, e->child, XCB_CONFIG_WINDOW_STACK_MODE, ev_vals);
static void (*events[LASTEvent])(XEvent *e) = {
[ButtonPress] = button_press,
[ButtonRelease] = button_release,
[ConfigureRequest] = configure_request,
[KeyPress] = key_press,
[MapRequest] = map_request,
[DestroyNotify] = notify_destroy,
[EnterNotify] = notify_enter,
[MotionNotify] = notify_motion
};
#include "config.h"
void win_focus(client *c) {
cur = c;
XSetInputFocus(d, cur->w, RevertToParent, CurrentTime);
xcb_grab_pointer(dpy, 0, root, XCB_EVENT_MASK_BUTTON_RELEASE |
XCB_EVENT_MASK_BUTTON_MOTION | XCB_EVENT_MASK_POINTER_MOTION_HINT,
XCB_GRAB_MODE_ASYNC, XCB_GRAB_MODE_ASYNC, root, XCB_NONE,
XCB_CURRENT_TIME);
}
void notify_destroy(XEvent *e) {
win_del(e->xdestroywindow.window);
if (list) win_focus(list->prev);
void event_button_release(xcb_generic_event_t *ev) {
xcb_ungrab_pointer(dpy, XCB_CURRENT_TIME);
}
void notify_enter(XEvent *e) {
while(XCheckTypedEvent(d, EnterNotify, e));
void event_configure_request(xcb_generic_event_t *ev) {
xcb_configure_request_event_t *e = (xcb_configure_request_event_t *)ev;
uint32_t values[7];
int8_t i = -1;
for win if (c->w == e->xcrossing.window) win_focus(c);
if (e->value_mask & XCB_CONFIG_WINDOW_X) {
e->value_mask |= XCB_CONFIG_WINDOW_X;
values[++i] = e->x;
}
if (e->value_mask & XCB_CONFIG_WINDOW_Y) {
e->value_mask |= XCB_CONFIG_WINDOW_Y;
values[++i] = e->y;
}
if (e->value_mask & XCB_CONFIG_WINDOW_WIDTH) {
e->value_mask |= XCB_CONFIG_WINDOW_WIDTH;
values[++i] = e->width;
}
if (e->value_mask & XCB_CONFIG_WINDOW_HEIGHT) {
e->value_mask |= XCB_CONFIG_WINDOW_HEIGHT;
values[++i] = e->height;
}
if (e->value_mask & XCB_CONFIG_WINDOW_SIBLING) {
e->value_mask |= XCB_CONFIG_WINDOW_SIBLING;
values[++i] = e->sibling;
}
if (e->value_mask & XCB_CONFIG_WINDOW_STACK_MODE) {
e->value_mask |= XCB_CONFIG_WINDOW_STACK_MODE;
values[++i] = e->stack_mode;
}
if (i != -1) {
xcb_configure_window(dpy, e->window, e->value_mask, values);
xcb_flush(dpy);
}
}
void notify_motion(XEvent *e) {
if (!mouse.subwindow || cur->f) return;
while(XCheckTypedEvent(d, MotionNotify, e));
int xd = e->xbutton.x_root - mouse.x_root;
int yd = e->xbutton.y_root - mouse.y_root;
XMoveResizeWindow(d, mouse.subwindow,
wx + (mouse.button == 1 ? xd : 0),
wy + (mouse.button == 1 ? yd : 0),
MAX(1, ww + (mouse.button == 3 ? xd : 0)),
MAX(1, wh + (mouse.button == 3 ? yd : 0)));
void event_key_press(xcb_generic_event_t *ev) {
xcb_key_press_event_t *e = (xcb_key_press_event_t *)ev;
}
void key_press(XEvent *e) {
KeySym keysym = XkbKeycodeToKeysym(d, e->xkey.keycode, 0, 0);
void event_notify_create(xcb_generic_event_t *ev) {
xcb_create_notify_event_t *e = (xcb_create_notify_event_t *)ev;
for (unsigned int i=0; i < sizeof(keys)/sizeof(*keys); ++i)
if (keys[i].keysym == keysym &&
mod_clean(keys[i].mod) == mod_clean(e->xkey.state))
keys[i].function(keys[i].arg);
ev_vals[0] = XCB_EVENT_MASK_ENTER_WINDOW | XCB_EVENT_MASK_FOCUS_CHANGE;
ev_vals[1] = XCB_EVENT_MASK_SUBSTRUCTURE_NOTIFY;
xcb_change_window_attributes(dpy, e->window, XCB_CW_EVENT_MASK, ev_vals);
xcb_map_window(dpy, e->window);
xcb_set_input_focus(dpy, XCB_INPUT_FOCUS_PARENT,
e->window, XCB_CURRENT_TIME);
}
void button_press(XEvent *e) {
if (!e->xbutton.subwindow) return;
win_size(e->xbutton.subwindow, &wx, &wy, &ww, &wh);
XRaiseWindow(d, e->xbutton.subwindow);
mouse = e->xbutton;
void event_notify_destroy(xcb_generic_event_t *ev) {
xcb_destroy_notify_event_t *e = (xcb_destroy_notify_event_t *)ev;
}
void button_release(XEvent *e) {
mouse.subwindow = 0;
void event_notify_enter(xcb_generic_event_t *ev) {
xcb_enter_notify_event_t *e = (xcb_enter_notify_event_t *)ev;
xcb_set_input_focus(dpy, XCB_INPUT_FOCUS_PARENT,
e->event, XCB_CURRENT_TIME);
}
void win_add(Window w) {
client *c;
void event_notify_motion(xcb_generic_event_t *ev) {
xcb_motion_notify_event_t *e = (xcb_motion_notify_event_t *)ev;
}
if (!(c = (client *) calloc(1, sizeof(client))))
void win_add(xcb_window_t win) {
}
void init_wm(void) {
dpy = xcb_connect(NULL, NULL);
if (xcb_connection_has_error(dpy)) {
printf("error: Failed to start sowm\n");
exit(1);
c->w = w;
if (list) {
list->prev->next = c;
c->prev = list->prev;
list->prev = c;
c->next = list;
} else {
list = c;
list->prev = list->next = list;
}
ws_save(ws);
scr = xcb_setup_roots_iterator(xcb_get_setup(dpy)).data;
if (!scr) {
printf("error: Failed to assign screen number\n");
xcb_disconnect(dpy);
exit(1);
}
root = scr->root;
ev_vals[0] = XCB_EVENT_MASK_SUBSTRUCTURE_NOTIFY;
xcb_change_window_attributes_checked(dpy, root, XCB_CW_EVENT_MASK, ev_vals);
xcb_flush(dpy);
}
void win_del(Window w) {
client *x = 0;
void init_input(void) {
xcb_grab_key(dpy, 1, root, XCB_MOD_MASK_4, XCB_NO_SYMBOL,
XCB_GRAB_MODE_ASYNC, XCB_GRAB_MODE_ASYNC);
for win if (c->w == w) x = c;
xcb_grab_button(dpy, 0, root, XCB_EVENT_MASK_BUTTON_PRESS |
XCB_EVENT_MASK_BUTTON_RELEASE, XCB_GRAB_MODE_ASYNC,
XCB_GRAB_MODE_ASYNC, root, XCB_NONE, 1, XCB_MOD_MASK_4);
if (!list || !x) return;
if (x->prev == x) list = 0;
if (list == x) list = x->next;
if (x->next) x->next->prev = x->prev;
if (x->prev) x->prev->next = x->next;
xcb_grab_button(dpy, 0, root, XCB_EVENT_MASK_BUTTON_PRESS |
XCB_EVENT_MASK_BUTTON_RELEASE, XCB_GRAB_MODE_ASYNC,
XCB_GRAB_MODE_ASYNC, root, XCB_NONE, 3, XCB_MOD_MASK_4);
free(x);
ws_save(ws);
xcb_flush(dpy);
}
void win_kill(const Arg arg) {
if (cur) XKillClient(d, cur->w);
}
void run_loop(void) {
xcb_generic_event_t *ev;
void win_center(const Arg arg) {
if (!cur) return;
for (;;) {
ev = xcb_wait_for_event(dpy);
win_size(cur->w, &(int){0}, &(int){0}, &ww, &wh);
XMoveWindow(d, cur->w, (sw - ww) / 2, (sh - wh) / 2);
}
void win_fs(const Arg arg) {
if (!cur) return;
if ((cur->f = cur->f ? 0 : 1)) {
win_size(cur->w, &cur->wx, &cur->wy, &cur->ww, &cur->wh);
XMoveResizeWindow(d, cur->w, 0, 0, sw, sh);
} else {
XMoveResizeWindow(d, cur->w, cur->wx, cur->wy, cur->ww, cur->wh);
if (events[EVENT_MASK(ev->response_type)]) {
events[EVENT_MASK(ev->response_type)](ev);
xcb_flush(dpy);
}
free(ev);
}
}
void win_to_ws(const Arg arg) {
int tmp = ws;
if (arg.i == tmp) return;
ws_sel(arg.i);
win_add(cur->w);
ws_save(arg.i);
ws_sel(tmp);
win_del(cur->w);
XUnmapWindow(d, cur->w);
ws_save(tmp);
if (list) win_focus(list);
}
void win_prev(const Arg arg) {
if (!cur) return;
XRaiseWindow(d, cur->prev->w);
win_focus(cur->prev);
}
void win_next(const Arg arg) {
if (!cur) return;
XRaiseWindow(d, cur->next->w);
win_focus(cur->next);
}
void ws_go(const Arg arg) {
int tmp = ws;
if (arg.i == ws) return;
ws_save(ws);
ws_sel(arg.i);
for win XMapWindow(d, c->w);
ws_sel(tmp);
for win XUnmapWindow(d, c->w);
ws_sel(arg.i);
if (list) win_focus(list); else cur = 0;
}
void configure_request(XEvent *e) {
XConfigureRequestEvent *ev = &e->xconfigurerequest;
XConfigureWindow(d, ev->window, ev->value_mask, &(XWindowChanges) {
.x = ev->x,
.y = ev->y,
.width = ev->width,
.height = ev->height,
.sibling = ev->above,
.stack_mode = ev->detail
});
}
void map_request(XEvent *e) {
Window w = e->xmaprequest.window;
XSelectInput(d, w, StructureNotifyMask|EnterWindowMask);
win_size(w, &wx, &wy, &ww, &wh);
win_add(w);
cur = list->prev;
if (wx + wy == 0) win_center((Arg){0});
XMapWindow(d, w);
win_focus(list->prev);
}
void run(const Arg arg) {
if (fork()) return;
if (d) close(ConnectionNumber(d));
setsid();
execvp((char*)arg.com[0], (char**)arg.com);
}
void input_grab(Window root) {
unsigned int i, j, modifiers[] = {0, LockMask, numlock, numlock|LockMask};
XModifierKeymap *modmap = XGetModifierMapping(d);
KeyCode code;
for (i = 0; i < 8; i++)
for (int k = 0; k < modmap->max_keypermod; k++)
if (modmap->modifiermap[i * modmap->max_keypermod + k]
== XKeysymToKeycode(d, 0xff7f))
numlock = (1 << i);
for (i = 0; i < sizeof(keys)/sizeof(*keys); i++)
if ((code = XKeysymToKeycode(d, keys[i].keysym)))
for (j = 0; j < sizeof(modifiers)/sizeof(*modifiers); j++)
XGrabKey(d, code, keys[i].mod | modifiers[j], root,
True, GrabModeAsync, GrabModeAsync);
for (i = 1; i < 4; i += 2)
for (j = 0; j < sizeof(modifiers)/sizeof(*modifiers); j++)
XGrabButton(d, i, MOD | modifiers[j], root, True,
ButtonPressMask|ButtonReleaseMask|PointerMotionMask,
GrabModeAsync, GrabModeAsync, 0, 0);
XFreeModifiermap(modmap);
}
int main(void) {
XEvent ev;
if (!(d = XOpenDisplay(0))) exit(1);
int main(int argc, char *argv[]) {
/* unused */
(void) argc;
(void) argv;
/* we don't want sigchld */
signal(SIGCHLD, SIG_IGN);
XSetErrorHandler(xerror);
int s = DefaultScreen(d);
root = RootWindow(d, s);
sw = XDisplayWidth(d, s);
sh = XDisplayHeight(d, s);
init_wm();
init_input();
run_loop();
XSelectInput(d, root, SubstructureRedirectMask);
XDefineCursor(d, root, XCreateFontCursor(d, 68));
input_grab(root);
while (1 && !XNextEvent(d, &ev)) // 1 && will forever be here.
if (events[ev.type]) events[ev.type](&ev);
return 0;
}

94
sowm.h
View File

@ -1,57 +1,47 @@
#include <X11/Xlib.h>
#define _POSIX_C_SOURCE 200809L
#include <xcb/xcb.h>
#define win (client *t=0, *c=list; c && t!=list->prev; t=c, c=c->next)
#define ws_save(W) ws_list[W] = list
#define ws_sel(W) list = ws_list[ws = W]
#define MAX(a, b) ((a) > (b) ? (a) : (b))
#define win_size(W, gx, gy, gw, gh) \
XGetGeometry(d, W, &(Window){0}, gx, gy, gw, gh, \
&(unsigned int){0}, &(unsigned int){0})
// Taken from DWM. Many thanks. https://git.suckless.org/dwm
#define mod_clean(mask) (mask & ~(numlock|LockMask) & \
(ShiftMask|ControlMask|Mod1Mask|Mod2Mask|Mod3Mask|Mod4Mask|Mod5Mask))
typedef struct {
const char** com;
const int i;
const Window w;
} Arg;
struct key {
unsigned int mod;
KeySym keysym;
void (*function)(const Arg arg);
const Arg arg;
struct wconf {
int16_t x;
int16_t y;
uint16_t width;
uint16_t height;
uint8_t stack_mode;
xcb_window_t sibling;
};
typedef struct client {
struct client *next, *prev;
int f, wx, wy;
unsigned int ww, wh;
Window w;
} client;
xcb_connection_t *dpy;
xcb_screen_t *scr;
xcb_drawable_t root;
void button_press(XEvent *e);
void button_release(XEvent *e);
void configure_request(XEvent *e);
void input_grab(Window root);
void key_press(XEvent *e);
void map_request(XEvent *e);
void notify_destroy(XEvent *e);
void notify_enter(XEvent *e);
void notify_motion(XEvent *e);
void run(const Arg arg);
void win_add(Window w);
void win_center(const Arg arg);
void win_del(Window w);
void win_fs(const Arg arg);
void win_focus(client *c);
void win_kill(const Arg arg);
void win_prev(const Arg arg);
void win_next(const Arg arg);
void win_to_ws(const Arg arg);
void ws_go(const Arg arg);
uint32_t ev_vals[3];
static int xerror() { return 0; }
/* xcb event with the largest value */
#define XCB_LAST_EVENT XCB_GET_MODIFIER_MAPPING
#define EVENT_MASK(e) (((e) & ~0x80))
void init_wm(void);
void init_input(void);
void run_loop(void);
void event_button_press(xcb_generic_event_t *ev);
void event_button_release(xcb_generic_event_t *ev);
void event_configure_request(xcb_generic_event_t *ev);
void event_key_press(xcb_generic_event_t *ev);
void event_notify_create(xcb_generic_event_t *ev);
void event_notify_destroy(xcb_generic_event_t *ev);
void event_notify_enter(xcb_generic_event_t *ev);
void event_notify_motion(xcb_generic_event_t *ev);
void (*events[XCB_NO_OPERATION])(xcb_generic_event_t *) = {
[XCB_BUTTON_PRESS] = event_button_press,
[XCB_BUTTON_RELEASE] = event_button_release,
[XCB_CONFIGURE_REQUEST] = event_configure_request,
[XCB_KEY_PRESS] = event_key_press,
[XCB_CREATE_NOTIFY] = event_notify_create,
[XCB_DESTROY_NOTIFY] = event_notify_destroy,
[XCB_ENTER_NOTIFY] = event_notify_enter,
[XCB_MOTION_NOTIFY] = event_notify_motion
};
void win_add(xcb_window_t win);