5 Commits

Author SHA1 Message Date
Dylan Araps
f4cb48d7af update 2020-10-21 15:36:42 +03:00
dylan
ccb96521c1 Merge pull request #101 from venam/master
Refresh keyboard mapping uppon MappingNotify event
2020-10-02 13:35:12 +03:00
Patrick Louis
5663175d57 Refresh keyboard mapping uppon MappingNotify event
When dynamically switching between layout the keys that are grabbed need
to also be refreshed. This is a fix similar to venam/2bwm@148d832

fixes dylanaraps#100
2020-10-02 11:35:03 +03:00
dylan
95596f43aa Merge pull request #93 from Yul3n/master
Added links to the window managers in the thanks
2020-07-08 12:53:20 +03:00
yul3n
e595bfb365 Added links to the window managers in the thanks 2020-07-08 10:12:36 +02:00
15 changed files with 542 additions and 477 deletions

3
.gitignore vendored
View File

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

21
LICENSE
View File

@@ -1,21 +0,0 @@
The MIT License (MIT)
Copyright (c) 2019-2020 Dylan Araps
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.

33
LICENSE.md Normal file
View File

@@ -0,0 +1,33 @@
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,32 +1,24 @@
.POSIX:
CFLAGS += -std=c99 -Wall -Wextra -pedantic -Wold-style-declaration
CFLAGS += -Wmissing-prototypes -Wno-unused-parameter
PREFIX ?= /usr
BINDIR ?= $(PREFIX)/bin
CC ?= gcc
PREFIX = /usr/local
all: sowm
ALL_WARN = -Wall -Wextra -pedantic -Wmissing-prototypes -Wstrict-prototypes
ALL_CFLAGS = $(CFLAGS) $(CPPFLAGS) -std=c99 $(ALL_WARN)
ALL_LDFLAGS = $(LDFLAGS) $(LIBS) -lxcb
config.h:
cp config.def.h config.h
CC = cc
sowm: sowm.c sowm.h config.h Makefile
$(CC) -O3 $(CFLAGS) -o $@ $< -lX11 $(LDFLAGS)
OBJ = src/event.o src/sowm.o
HDR = src/event.h src/globals.h
.c.o:
$(CC) $(ALL_CFLAGS) -c -o $@ $<
sowm: $(OBJ)
$(CC) $(ALL_CFLAGS) -o $@ $(OBJ) $(ALL_LDFLAGS)
$(OBJ): $(HDR)
install: sowm
mkdir -p $(DESTDIR)/bin
cp sowm $(DESTDIR)/bin/sowm
install: all
install -Dm755 sowm $(DESTDIR)$(BINDIR)/sowm
uninstall:
rm -f $(DESTDIR)/bin/sowm
rm -f $(DESTDIR)$(BINDIR)/sowm
clean:
rm -f sowm *.o
.PHONY: install uninstall clean
.PHONY: all install uninstall clean

3
README
View File

@@ -1,3 +0,0 @@
SOWM (Simple Opinionated Window Manager)
________________________________________________________________________________

98
README.md Normal file
View File

@@ -0,0 +1,98 @@
# 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-6` | desktop swap |
| `MOD4` + `Shift` +`1-6` | 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](https://github.com/venam/2bwm)
- [SmallWM](https://github.com/adamnew123456/SmallWM)
- [berry](https://github.com/JLErvin/berry)
- [catwm](https://github.com/pyknite/catwm)
- [dminiwm](https://github.com/moetunes/dminiwm)
- [dwm](https://dwm.suckless.org)
- [monsterwm](https://github.com/c00kiemon5ter/monsterwm)
- [openbox](https://github.com/danakj/openbox)
- [possum-wm](https://github.com/duckinator/possum-wm)
- [swm](https://github.com/dcat/swm)
- [tinywm](http://incise.org/tinywm.html)

49
config.def.h Normal file
View File

@@ -0,0 +1,49 @@
#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

View File

@@ -1,4 +0,0 @@
keybindings
events
actions
manager

289
sowm.c Normal file
View File

@@ -0,0 +1,289 @@
// sowm - An itsy bitsy floating window manager.
#include <X11/Xlib.h>
#include <X11/XF86keysym.h>
#include <X11/keysym.h>
#include <X11/XKBlib.h>
#include <stdlib.h>
#include <signal.h>
#include <unistd.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;
static Display *d;
static XButtonEvent mouse;
static Window root;
static void (*events[LASTEvent])(XEvent *e) = {
[ButtonPress] = button_press,
[ButtonRelease] = button_release,
[ConfigureRequest] = configure_request,
[KeyPress] = key_press,
[MapRequest] = map_request,
[MappingNotify] = mapping_notify,
[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);
}
void notify_destroy(XEvent *e) {
win_del(e->xdestroywindow.window);
if (list) win_focus(list->prev);
}
void notify_enter(XEvent *e) {
while(XCheckTypedEvent(d, EnterNotify, e));
for win if (c->w == e->xcrossing.window) win_focus(c);
}
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 key_press(XEvent *e) {
KeySym keysym = XkbKeycodeToKeysym(d, e->xkey.keycode, 0, 0);
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);
}
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 button_release(XEvent *e) {
mouse.subwindow = 0;
}
void win_add(Window w) {
client *c;
if (!(c = (client *) calloc(1, sizeof(client))))
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);
}
void win_del(Window w) {
client *x = 0;
for win if (c->w == w) x = c;
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;
free(x);
ws_save(ws);
}
void win_kill(const Arg arg) {
if (cur) XKillClient(d, cur->w);
}
void win_center(const Arg arg) {
if (!cur) return;
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);
}
}
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 mapping_notify(XEvent *e) {
XMappingEvent *ev = &e->xmapping;
if (ev->request == MappingKeyboard || ev->request == MappingModifier) {
XRefreshKeyboardMapping(ev);
input_grab(root);
}
}
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);
XUngrabKey(d, AnyKey, AnyModifier, root);
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);
signal(SIGCHLD, SIG_IGN);
XSetErrorHandler(xerror);
int s = DefaultScreen(d);
root = RootWindow(d, s);
sw = XDisplayWidth(d, s);
sh = XDisplayHeight(d, s);
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);
}

58
sowm.h Normal file
View File

@@ -0,0 +1,58 @@
#include <X11/Xlib.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;
};
typedef struct client {
struct client *next, *prev;
int f, wx, wy;
unsigned int ww, wh;
Window w;
} client;
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 mapping_notify(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);
static int xerror() { return 0; }

View File

@@ -1,125 +0,0 @@
#include <xcb/xcb.h>
#include "globals.h"
#include "event.h"
#define MAX(a, b) ((a) > (b) ? (a) : (b))
static xcb_window_t motion_win;
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 event_button_press(xcb_generic_event_t *ev) {
xcb_button_press_event_t *e = (xcb_button_press_event_t *)ev;
xcb_get_geometry_reply_t *geom;
uint32_t value;
if (!e->child) {
return;
}
motion_win = e->child;
value = XCB_STACK_MODE_ABOVE;
xcb_configure_window(dpy, e->child,
XCB_CONFIG_WINDOW_STACK_MODE, &value);
geom = xcb_get_geometry_reply(dpy,
xcb_get_geometry(dpy, e->child), NULL);
xcb_warp_pointer(dpy, XCB_NONE, e->child, 0, 0, 0, 0,
e->detail != 1 ? geom->width : 1,
e->detail != 1 ? geom->height : 1);
xcb_grab_pointer(dpy, 0, scr->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, scr->root, XCB_NONE,
XCB_CURRENT_TIME);
}
void event_button_release(xcb_generic_event_t *ev) {
(void)(ev);
xcb_ungrab_pointer(dpy, XCB_CURRENT_TIME);
motion_win = 0;
}
/* 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) {
xcb_create_notify_event_t *e = (xcb_create_notify_event_t *)ev;
uint32_t value;
value = XCB_EVENT_MASK_ENTER_WINDOW |
XCB_EVENT_MASK_FOCUS_CHANGE |
XCB_EVENT_MASK_SUBSTRUCTURE_NOTIFY;
xcb_change_window_attributes(dpy, e->window, XCB_CW_EVENT_MASK, &value);
xcb_map_window(dpy, e->window);
xcb_set_input_focus(dpy, XCB_INPUT_FOCUS_POINTER_ROOT,
e->window, XCB_CURRENT_TIME);
}
/* void event_notify_destroy(xcb_generic_event_t *ev) { */
/* } */
void event_notify_enter(xcb_generic_event_t *ev) {
xcb_enter_notify_event_t *e = (xcb_enter_notify_event_t *)ev;
if (!e->event || e->event == scr->root) {
return;
}
xcb_set_input_focus(dpy, XCB_INPUT_FOCUS_POINTER_ROOT,
e->event, XCB_CURRENT_TIME);
}
void event_notify_motion(xcb_generic_event_t *ev) {
xcb_motion_notify_event_t *e = (xcb_motion_notify_event_t *)ev;
xcb_query_pointer_reply_t *ptr;
xcb_get_geometry_reply_t *geom;
uint32_t values[2];
if (!motion_win || motion_win == scr->root) {
return;
}
ptr = xcb_query_pointer_reply(dpy, xcb_query_pointer(dpy, scr->root), 0);
geom = xcb_get_geometry_reply(dpy, xcb_get_geometry(dpy, motion_win), NULL);
/* move */
if (e->state & XCB_BUTTON_MASK_1) {
values[0] = (ptr->root_x + geom->width > scr->width_in_pixels)?
(scr->width_in_pixels - geom->width):ptr->root_x;
values[1] = (ptr->root_y + geom->height > scr->height_in_pixels)?
(scr->height_in_pixels - geom->height):ptr->root_y;
xcb_configure_window(dpy, motion_win,
XCB_CONFIG_WINDOW_X | XCB_CONFIG_WINDOW_Y, values);
/* resize */
} else if (e->state & XCB_BUTTON_MASK_3) {
values[0] = MAX(10, ptr->root_x - geom->x);
values[1] = MAX(10, ptr->root_y - geom->y);
xcb_configure_window(dpy, motion_win,
XCB_CONFIG_WINDOW_WIDTH | XCB_CONFIG_WINDOW_HEIGHT, values);
}
}

View File

@@ -1,12 +0,0 @@
#include <xcb/xcb.h>
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);
extern void (*events[XCB_NO_OPERATION])(xcb_generic_event_t *);

View File

@@ -1,11 +0,0 @@
#include <xcb/xcb.h>
extern xcb_connection_t *dpy;
extern xcb_screen_t *scr;
struct desktop {
xcb_window_t *windows;
int num;
};
extern int current_desktop;

View File

@@ -1,102 +0,0 @@
#include <stdio.h>
#include <stdlib.h>
#include <signal.h>
#include <xcb/xcb.h>
#include "event.h"
#include "vec.h"
#include "globals.h"
#include "config.h"
static void init_wm(void);
static void init_input(void);
static void init_desktops(void);
xcb_connection_t *dpy;
xcb_screen_t *scr;
struct desktop *desktops;
int current_desktop = 0;
static void init_wm() {
uint32_t values;
dpy = xcb_connect(NULL, NULL);
if (xcb_connection_has_error(dpy)) {
printf("error: Failed to start sowm\n");
exit(1);
}
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);
}
values = XCB_EVENT_MASK_SUBSTRUCTURE_NOTIFY;
xcb_change_window_attributes_checked(dpy, scr->root,
XCB_CW_EVENT_MASK, &values);
xcb_flush(dpy);
}
static void init_input() {
xcb_grab_key(dpy, 1, scr->root, SOWM_MOD, XCB_NO_SYMBOL,
XCB_GRAB_MODE_ASYNC, XCB_GRAB_MODE_ASYNC);
xcb_grab_button(dpy, 0, scr->root, XCB_EVENT_MASK_BUTTON_PRESS |
XCB_EVENT_MASK_BUTTON_RELEASE, XCB_GRAB_MODE_ASYNC,
XCB_GRAB_MODE_ASYNC, scr->root, XCB_NONE, 1, SOWM_MOD);
xcb_grab_button(dpy, 0, scr->root, XCB_EVENT_MASK_BUTTON_PRESS |
XCB_EVENT_MASK_BUTTON_RELEASE, XCB_GRAB_MODE_ASYNC,
XCB_GRAB_MODE_ASYNC, scr->root, XCB_NONE, 3, SOWM_MOD);
xcb_flush(dpy);
}
static void init_desktops() {
struct desktop new = {0};
for (int i = 0; i < SOWM_NUM_DESKTOPS; i++) {
new.num = i;
vec_push_back(desktops, new);
}
/* todo finish usage of desktops */
vec_free(desktops);
}
int main(int argc, char **argv) {
xcb_generic_event_t *ev;
unsigned int ev_type;
/* unused */
(void) argc;
(void) argv;
/* we don't want sigchld */
signal(SIGCHLD, SIG_IGN);
init_wm();
init_input();
init_desktops();
while ((ev = xcb_wait_for_event(dpy))) {
ev_type = ev->response_type & ~0x80;
if (events[ev_type]) {
events[ev_type](ev);
xcb_flush(dpy);
}
free(ev);
}
return 0;
}

175
src/vec.h
View File

@@ -1,175 +0,0 @@
/*
This is an implementation of a std::vector like growable array, but in plain
C89 code. The result is a type safe, easy to use, dynamic array that has a
familiar set of operations. Source: https://github.com/eteran/c-vector
The MIT License (MIT)
Copyright (c) 2020 Dylan Araps
Copyright (c) 2015 Evan Teran
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.
*/
#ifndef VEC_H_
#define VEC_H_
#include <assert.h> /* for assert */
#include <stddef.h> /* for size_t */
#include <stdlib.h> /* for malloc/realloc/free */
/**
* @brief vec_set_capacity - For internal use, set capacity variable.
* @param vec - the vector
* @param size - the new capacity to set
* @return void
*/
#define vec_set_capacity(vec, size) \
do { \
if (vec) { \
((size_t *)(vec))[-1] = (size); \
} \
} while (0)
/**
* @brief vec_set_size - For internal use, sets the size variable of the vector
* @param vec - the vector
* @param size - the new capacity to set
* @return void
*/
#define vec_set_size(vec, size) \
do { \
if (vec) { \
((size_t *)(vec))[-2] = (size); \
} \
} while (0)
/**
* @brief vec_capacity - gets the current capacity of the vector
* @param vec - the vector
* @return the capacity as a size_t
*/
#define vec_capacity(vec) ((vec) ? ((size_t *)(vec))[-1] : (size_t)0)
/**
* @brief vec_size - gets the current size of the vector
* @param vec - the vector
* @return the size as a size_t
*/
#define vec_size(vec) ((vec) ? ((size_t *)(vec))[-2] : (size_t)0)
/**
* @brief vec_empty - returns non-zero if the vector is empty
* @param vec - the vector
* @return non-zero if empty, zero if non-empty
*/
#define vec_empty(vec) (vec_size(vec) == 0)
/**
* @brief vec_grow - For internal use, ensure that the vector is >= <count>.
* @param vec - the vector
* @param size - the new capacity to set
* @return void
*/
#define vec_grow(vec, count) \
do { \
const size_t vec__sz = (count) * sizeof(*(vec)) + (sizeof(size_t) * 2); \
if (!(vec)) { \
size_t *vec__p = malloc(vec__sz); \
assert(vec__p); \
(vec) = (void *)(&vec__p[2]); \
vec_set_capacity((vec), (count)); \
vec_set_size((vec), 0); \
} else { \
size_t *vec__p1 = &((size_t *)(vec))[-2]; \
size_t *vec__p2 = realloc(vec__p1, (vec__sz)); \
assert(vec__p2); \
(vec) = (void *)(&vec__p2[2]); \
vec_set_capacity((vec), (count)); \
} \
} while (0)
/**
* @brief vec_pop_back - removes the last element from the vector
* @param vec - the vector
* @return void
*/
#define vec_pop_back(vec) \
do { \
vec_set_size((vec), vec_size(vec) - 1); \
} while (0)
/**
* @brief vec_erase - removes the element at index i from the vector
* @param vec - the vector
* @param i - index of element to remove
* @return void
*/
#define vec_erase(vec, i) \
do { \
if (vec) { \
const size_t vec__sz = vec_size(vec); \
if ((i) < vec__sz) { \
vec_set_size((vec), vec__sz - 1); \
size_t vec__x; \
for (vec__x = (i); vec__x < (vec__sz - 1); ++vec__x) { \
(vec)[vec__x] = (vec)[vec__x + 1]; \
} \
} \
} \
} while (0)
/**
* @brief vec_free - frees all memory associated with the vector
* @param vec - the vector
* @return void
*/
#define vec_free(vec) \
do { \
if (vec) { \
size_t *p1 = &((size_t *)(vec))[-2]; \
free(p1); \
} \
} while (0)
/**
* @brief vec_end - returns an iterator to one past the last element
* @param vec - the vector
* @return a pointer to one past the last element (or NULL)
*/
#define vec_end(vec) ((vec) ? &((vec)[vec_size(vec)]) : NULL)
/**
* @brief vec_push_back - adds an element to the end of the vector
* @param vec - the vector
* @param value - the value to add
* @return void
*/
#define vec_push_back(vec, value) \
do { \
size_t vec__cap = vec_capacity(vec); \
if (vec__cap <= vec_size(vec)) { \
vec_grow((vec), !vec__cap ? vec__cap + 1 : vec__cap * 2); \
} \
vec[vec_size(vec)] = (value); \
vec_set_size((vec), vec_size(vec) + 1); \
} while (0)
#endif /* VEC_H_ */