55 Commits
1.1 ... sowm2

Author SHA1 Message Date
Dylan Araps
d9f72fdffc big poosh 2020-07-29 11:56:23 +03:00
Dylan Araps
fbf145e5af reduce length of values 2020-07-26 15:30:17 +03:00
Dylan Araps
4a369b4ab2 Reduce length of values 2020-07-26 15:28:44 +03:00
Dylan Araps
37648b9576 minor fixes 2020-07-26 15:25:21 +03:00
Dylan Araps
710659f788 swap em round 2020-07-26 15:19:04 +03:00
Dylan Araps
aae3efc546 shorter null checks 2020-07-26 15:17:58 +03:00
Dylan Araps
16a80214b8 cleanup and minimum window size 2020-07-26 13:31:51 +03:00
Dylan Araps
a9e3490de7 pointer stuff 2020-07-26 13:20:08 +03:00
Dylan Araps
02f08fba01 add initial action 2020-07-21 10:10:39 +03:00
Dylan Araps
c75d34b7b1 more stuff 2020-07-21 10:05:19 +03:00
Dylan Araps
136c30403b add globals for connection/screen 2020-07-21 10:02:14 +03:00
Dylan Araps
d1535393aa move stuff to src 2020-07-21 09:45:29 +03:00
Dylan Araps
0e6e6f469f add initial event functions 2020-07-21 09:26:36 +03:00
Dylan Araps
a047141f91 stuff 2020-07-21 09:20:46 +03:00
Dylan Araps
196e8db5f6 drop prior rewrite 2020-07-21 09:18:56 +03:00
Dylan Araps
b5eca40b64 rewrite 2020-07-21 09:18:05 +03:00
Dylan Araps
3e711082e7 sowm2: Resizing and moving 2020-07-11 14:47:07 +03:00
Dylan Araps
2e4015f988 sowm: Add back LICENSE/README files 2020-07-11 12:16:47 +03:00
Dylan Araps
a743d166fe sowm: Shuffle declarations around 2020-07-11 11:50:54 +03:00
Dylan Araps
5c998e05f4 sowm.h: Drop XCB_LAST_EVENT 2020-07-11 11:46:20 +03:00
Dylan Araps
04b35c3f5e sowm.h: Fix mixed indentation 2020-07-11 11:45:17 +03:00
Dylan Araps
1a4c655b9d 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.
2020-07-11 11:31:30 +03:00
dylan
d327a0978a Merge pull request #89 from zsugabubus/makefile
sowm: fix Makefile dependencies
2020-06-16 12:24:10 +03:00
zsugabubus
0964d47d07 sowm: fix Makefile dependencies
So the binary no longer need to be deleted for a recompilation.
2020-06-16 10:30:13 +02:00
Dylan Araps
6ca1ff91a4 docs: update 2020-05-03 22:14:12 +03:00
Dylan Araps
dabe77272b sowm: revert normal kill 2020-04-25 10:47:50 +03:00
Dylan Araps
ea47780ab0 sowm: Fix normal kill 2020-04-23 08:40:08 +03:00
Dylan Araps
0ed080b99c sowm: small fixes 2020-04-23 08:27:13 +03:00
dylan
7e4466e38e Merge pull request #60 from dylanaraps/kill
sowm: normal window close
2020-04-23 08:21:27 +03:00
Dylan Araps
56bdacaa84 docs: update. Closes #66 and #67 2020-03-30 08:56:41 +03:00
Dylan Araps
e22087856b sowm: Compress window events after compressing all events. 2020-03-11 22:21:41 +02:00
Dylan Araps
f201a467ea sowm: Fix linker errors. Closes #61 2020-02-21 18:08:47 +02:00
Dylan Araps
7821aac0d2 sowm: Fix Makefile 2020-02-20 18:41:45 +02:00
Dylan Araps
a1c80d9b23 sowm: Fix Makefile 2020-02-20 18:40:29 +02:00
Dylan Araps
0df345e1da sowm: Fix compiler warning 2020-02-20 18:37:19 +02:00
Dylan Araps
b5087acaac docs: update 2020-02-20 18:34:57 +02:00
Dylan Araps
3ed647f467 sowm: simpler kill 2020-02-20 18:02:11 +02:00
Dylan Araps
e491a637fe sowm: Changes for easier patching 2020-02-20 16:08:47 +02:00
Dylan Araps
21a35be863 Merge branch 'master' of github.com:dylanaraps/sowm 2020-02-20 16:00:23 +02:00
Dylan Araps
5547cc3a51 sowm: Set minimum resize amount. 2020-02-20 15:59:48 +02:00
dylan
67d323458c Merge pull request #56 from noxgeek/patch-1
Add uninstall to Makefile
2020-02-16 20:02:40 +02:00
noxgeek
0004ff3e18 Add uninstall to Makefile 2020-02-16 18:39:15 +01:00
Dylan Araps
5cc5d25823 Makefile: GNUisms 2020-02-16 13:38:57 +02:00
Dylan Araps
0e8cc9fe86 sowm: Fix errors. Closes #51 2020-01-24 06:40:37 +02:00
Dylan Araps
2c3c353d74 docs: update 2020-01-23 17:03:56 +02:00
Dylan Araps
69f2c71fb7 sowm: proper prototypes 2020-01-23 17:00:26 +02:00
Dylan Araps
a31091472a docs: update 2020-01-23 16:14:22 +02:00
Dylan Araps
1d249a96ef sowm: Add header file 2020-01-23 02:54:13 +02:00
Dylan Araps
f558535e19 docs: update 2020-01-23 02:40:13 +02:00
Dylan Araps
243cab5deb docs: update 2020-01-23 02:39:13 +02:00
Dylan Araps
4f18161758 docs: update 2020-01-23 02:37:32 +02:00
dylan
087e276736 Merge pull request #49 from SeungheonOh/master
Patch: Wheel resize update
2020-01-22 10:57:24 +02:00
Seungheon Oh
c1b252bc6d Patch: Wheel resize update 2020-01-21 15:17:58 -06:00
dylan
4aa7d1a4d6 Merge pull request #48 from SeungheonOh/master
Patch: 2bswm-style fixed
2020-01-21 02:31:16 +02:00
Seungheon Oh
facbfcf061 Patch: 2bswm-style fixed 2020-01-20 13:11:42 -06:00
25 changed files with 478 additions and 1486 deletions

View File

@@ -1,9 +0,0 @@
name: CI
on: [push, pull_request]
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v1
- name: Apply patches.
run: make test

3
.gitignore vendored
View File

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

21
LICENSE Normal file
View File

@@ -0,0 +1,21 @@
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.

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,24 +1,32 @@
CFLAGS+= -std=c99 -Wall -Wextra -pedantic
LDADD+= -lX11
LDFLAGS=
PREFIX?= /usr
BINDIR?= $(PREFIX)/bin
.POSIX:
CC ?= gcc
PREFIX = /usr/local
all: config.h 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.o
$(CC) $(LDFLAGS) -O3 -o $@ $+ $(LDADD)
OBJ = src/event.o src/sowm.o
HDR = src/event.h src/globals.h
install: all
install -Dm 755 sowm $(DESTDIR)$(BINDIR)/sowm
.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
uninstall:
rm -f $(DESTDIR)/bin/sowm
clean:
rm -f sowm *.o
test:
for patch in patches/*.patch; do patch --dry-run -p1 < "$$patch"; done
.PHONY: install uninstall clean

3
README Normal file
View File

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

View File

@@ -1,84 +0,0 @@
# sowm (*Simple 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 / 24kb compiled!*).
- Floating only.
- Fullscreen toggle.
- Window centering.
- Mix of mouse and keyboard workflow.
- Focus with cursor.
- Rounded corners (*[through patch](https://github.com/dylanaraps/sowm/blob/master/patches/sowm-rounded-corners.patch)*)
<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>
## 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**.
## 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

4
design.txt Normal file
View File

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

View File

@@ -1,96 +0,0 @@
diff --git a/config.def.h b/config.def.h
index cae2009..9ad7175 100644
--- a/config.def.h
+++ b/config.def.h
@@ -26,6 +26,26 @@ static struct key keys[] = {
{MOD, XK_p, run, {.com = scrot}},
{MOD, XK_Return, run, {.com = term}},
+ {MOD, XK_h, move, {.com=(char*[]){"move", "left"}, .i=10}},
+ {MOD, XK_j, move, {.com=(char*[]){"move", "down"}, .i=10}},
+ {MOD, XK_k, move, {.com=(char*[]){"move", "up"}, .i=10}},
+ {MOD, XK_l, move, {.com=(char*[]){"move", "right"}, .i=10}},
+ {MOD|ShiftMask, XK_h, move, {.com=(char*[]){"resize", "left"}, .i=10}},
+ {MOD|ShiftMask, XK_j, move, {.com=(char*[]){"resize", "down"}, .i=10}},
+ {MOD|ShiftMask, XK_k, move, {.com=(char*[]){"resize", "up"}, .i=10}},
+ {MOD|ShiftMask, XK_l, move, {.com=(char*[]){"resize", "right"}, .i=10}},
+
+ /*
+ {MOD, XK_h, move_left, {.com = {"move"},.i=10}},
+ {MOD, XK_j, move_down, {.com = {"move"},.i=10}},
+ {MOD, XK_k, move_up, {.com = {"move"},.i=10}},
+ {MOD, XK_l, move_right, {.com = {"move"},.i=10}},
+ {MOD|ShiftMask, XK_h, resize_left, {.com = {"resize"},.i=10}},
+ {MOD|ShiftMask, XK_j, resize_down, {.com = {"resize"},.i=10}},
+ {MOD|ShiftMask, XK_k, resize_up, {.com = {"resize"},.i=10}},
+ {MOD|ShiftMask, XK_l, resize_right, {.com = {"resize"},.i=10}},
+ */
+
{0, XF86XK_AudioLowerVolume, run, {.com = voldown}},
{0, XF86XK_AudioRaiseVolume, run, {.com = volup}},
{0, XF86XK_AudioMute, run, {.com = volmute}},
diff --git a/sowm.c b/sowm.c
index 48222c6..00e2e80 100644
--- a/sowm.c
+++ b/sowm.c
@@ -7,8 +7,9 @@
#include <stdlib.h>
#include <signal.h>
#include <unistd.h>
+#include <stdio.h>
-typedef union {
+typedef struct {
const char** com;
const int i;
const Window w;
@@ -46,6 +47,9 @@ static void win_prev();
static void win_next();
static void win_to_ws(const Arg arg);
static void ws_go(const Arg arg);
+static void apply(int x, int y, int w, int h);
+static void move(const Arg arg);
+
static int xerror() { return 0;}
static client *list = {0}, *ws_list[10] = {0}, *cur;
@@ -77,6 +81,31 @@ static void (*events[LASTEvent])(XEvent *e) = {
XGetGeometry(d, W, &(Window){0}, gx, gy, gw, gh, \
&(unsigned int){0}, &(unsigned int){0})
+void apply(int x,int y,int w,int h) {
+ win_size(cur->w, &wx, &wy, &ww, &wh);
+ XMoveResizeWindow(d, cur->w,
+ wx + x,
+ wy + y,
+ ww + w,
+ wh + h);
+ win_size(cur->w, &wx, &wy, &ww, &wh);
+}
+
+void move(const Arg arg) {
+ if(arg.com[1]=="left") {
+ apply((arg.com[0]=="resize")?arg.i:-arg.i, 0, (arg.com[0]=="resize")?-arg.i:0, 0);
+ }
+ else if(arg.com[1]=="right"){
+ apply((arg.com[0]=="resize")?-arg.i:arg.i, 0, (arg.com[0]=="resize")?arg.i:0, 0);
+ }
+ else if(arg.com[1]=="up"){
+ apply(0, (arg.com[0]=="resize")?arg.i:-arg.i, 0, (arg.com[0]=="resize")?-arg.i:0);
+ }
+ else if(arg.com[1]=="down"){
+ apply(0, (arg.com[0]=="resize")?-arg.i:arg.i, 0, (arg.com[0]=="resize")?arg.i:0);
+ }
+}
+
void win_focus(client *c) {
cur = c;
XSetInputFocus(d, cur->w, RevertToParent, CurrentTime);
@@ -130,6 +159,7 @@ void button_press(XEvent *e) {
}
void button_release() {
+ win_size(cur->w, &wx, &wy, &ww, &wh);
mouse.subwindow = 0;
}

View File

@@ -1,132 +0,0 @@
diff -up a/config.def.h b/config.def.h
--- a/config.def.h 2019-10-17 19:48:23.000000000 +0300
+++ b/config.def.h 2019-10-20 15:12:05.510971991 +0300
@@ -32,16 +32,29 @@ static struct key keys[] = {
{MOD, XK_1, ws_go, {.i = 1}},
{MOD|ShiftMask, XK_1, win_to_ws, {.i = 1}},
+ {MOD|ControlMask,XK_1,ws_toggle, {.i = 1}},
+
{MOD, XK_2, ws_go, {.i = 2}},
{MOD|ShiftMask, XK_2, win_to_ws, {.i = 2}},
+ {MOD|ControlMask,XK_2,ws_toggle, {.i = 2}},
+
{MOD, XK_3, ws_go, {.i = 3}},
{MOD|ShiftMask, XK_3, win_to_ws, {.i = 3}},
+ {MOD|ControlMask,XK_3,ws_toggle, {.i = 3}},
+
{MOD, XK_4, ws_go, {.i = 4}},
{MOD|ShiftMask, XK_4, win_to_ws, {.i = 4}},
+ {MOD|ControlMask,XK_4,ws_toggle, {.i = 4}},
+
{MOD, XK_5, ws_go, {.i = 5}},
{MOD|ShiftMask, XK_5, win_to_ws, {.i = 5}},
+ {MOD|ControlMask,XK_5,ws_toggle, {.i = 5}},
+
{MOD, XK_6, ws_go, {.i = 6}},
{MOD|ShiftMask, XK_6, win_to_ws, {.i = 6}},
+ {MOD|ControlMask,XK_6,ws_toggle, {.i = 6}},
+
+ {MOD, XK_0, ws_toggle_all, {.i = 0}},
};
#endif
Common subdirectories: a/patches and b/patches
Only in b/: sowm-almost-tags-0.3.diff
diff -up a/sowm.c b/sowm.c
--- a/sowm.c 2019-10-17 19:48:23.000000000 +0300
+++ b/sowm.c 2019-10-18 19:02:41.959290919 +0300
@@ -43,11 +43,14 @@ static void win_prev();
static void win_next();
static void win_to_ws(const Arg arg);
static void ws_go(const Arg arg);
+static void ws_toggle(const Arg arg);
+static void ws_toggle_all(const Arg arg);
static int xerror() { return 0;}
static client *list = {0}, *ws_list[10] = {0}, *cur;
static int ws = 1, sw, sh, wx, wy, numlock;
static unsigned int ww, wh;
+static int is_ws_enabled[10] = {0}; /* +1 the amount of ws */
static Display *d;
static XButtonEvent mouse;
@@ -235,24 +238,68 @@ void win_next() {
}
void ws_go(const Arg arg) {
- int tmp = ws;
-
- if (arg.i == ws) return;
-
+ int i;
+
ws_save(ws);
- ws_sel(arg.i);
- for win XMapWindow(d, c->w);
-
- ws_sel(tmp);
-
- for win XUnmapWindow(d, c->w);
+ for (i = 1; i <= 9; i++) {
+ if (i != arg.i) {
+ ws_sel(i);
+ if (list) for win XUnmapWindow(d, c->w);
+ is_ws_enabled[i] = 0;
+ }
+ }
ws_sel(arg.i);
+ if (list) for win XMapWindow(d, c->w);
if (list) win_focus(list); else cur = 0;
}
+void
+ws_toggle(const Arg arg)
+{
+ int i, tmp = -1;
+
+ if (arg.i == ws) {
+ for (i = 1; i <= 9; i++) {
+ if (is_ws_enabled[i] && i != ws) {
+ tmp = i;
+ break;
+ }
+ }
+
+ if (tmp > 0)
+ ws_sel(tmp);
+ else
+ return;
+ }
+
+ tmp = ws;
+
+ ws_sel(arg.i);
+ if (is_ws_enabled[arg.i]) {
+ is_ws_enabled[arg.i] = 0;
+ if (list) for win XUnmapWindow(d, c->w);
+ } else {
+ is_ws_enabled[arg.i] = 1;
+ if (list) for win XMapWindow(d, c->w);
+ }
+ ws_sel(tmp);
+}
+
+void
+ws_toggle_all(const Arg arg)
+{
+ int i, tmp = ws;
+ for (i = 1; i <= 6; i++) {
+ ws_sel(i);
+ if (list) for win XMapWindow(d, c->w);
+ is_ws_enabled[i] = 1;
+ }
+ ws_sel(tmp);
+}
+
void configure_request(XEvent *e) {
XConfigureRequestEvent *ev = &e->xconfigurerequest;

View File

@@ -1,134 +0,0 @@
diff -up a/config.def.h b/config.def.h
--- a/config.def.h 2019-10-28 23:55:17.000000000 +0200
+++ b/config.def.h 2019-11-09 22:30:45.057057111 +0200
@@ -32,16 +32,29 @@ static struct key keys[] = {
{MOD, XK_1, ws_go, {.i = 1}},
{MOD|ShiftMask, XK_1, win_to_ws, {.i = 1}},
+ {MOD|ControlMask,XK_1,ws_toggle, {.i = 1}},
+
{MOD, XK_2, ws_go, {.i = 2}},
{MOD|ShiftMask, XK_2, win_to_ws, {.i = 2}},
+ {MOD|ControlMask,XK_2,ws_toggle, {.i = 2}},
+
{MOD, XK_3, ws_go, {.i = 3}},
{MOD|ShiftMask, XK_3, win_to_ws, {.i = 3}},
+ {MOD|ControlMask,XK_3,ws_toggle, {.i = 3}},
+
{MOD, XK_4, ws_go, {.i = 4}},
{MOD|ShiftMask, XK_4, win_to_ws, {.i = 4}},
+ {MOD|ControlMask,XK_4,ws_toggle, {.i = 4}},
+
{MOD, XK_5, ws_go, {.i = 5}},
{MOD|ShiftMask, XK_5, win_to_ws, {.i = 5}},
+ {MOD|ControlMask,XK_5,ws_toggle, {.i = 5}},
+
{MOD, XK_6, ws_go, {.i = 6}},
{MOD|ShiftMask, XK_6, win_to_ws, {.i = 6}},
+ {MOD|ControlMask,XK_6,ws_toggle, {.i = 6}},
+
+ {MOD, XK_0, ws_toggle_all, {.i = 0}},
};
#endif
Only in b/: config.h
Common subdirectories: a/patches and b/patches
Only in b/: sowm
diff -up a/sowm.c b/sowm.c
--- a/sowm.c 2019-10-28 23:55:17.000000000 +0200
+++ b/sowm.c 2019-11-09 22:34:10.660379162 +0200
@@ -45,11 +45,14 @@ static void win_kill();
static void win_next();
static void win_to_ws(const Arg arg);
static void ws_go(const Arg arg);
+static void ws_toggle(const Arg arg);
+static void ws_toggle_all(const Arg arg);
static int xerror() { return 0;}
static client *list = {0}, *ws_list[10] = {0}, *cur;
static int ws = 1, sw, sh, wx, wy, numlock;
static unsigned int ww, wh;
+static int is_ws_enabled[10] = {0}; /* +1 the amount of ws */
static Display *d;
static XButtonEvent mouse;
@@ -212,24 +215,69 @@ void win_next() {
}
void ws_go(const Arg arg) {
- int tmp = ws;
-
- if (arg.i == ws) return;
+ int i;
ws_save(ws);
- ws_sel(arg.i);
- for win XMapWindow(d, c->w);
-
- ws_sel(tmp);
-
- for win XUnmapWindow(d, c->w);
+ for (i = 1; i <= 9; i++) {
+ if (i != arg.i) {
+ ws_sel(i);
+ if (list) for win XUnmapWindow(d, c->w);
+ is_ws_enabled[i] = 0;
+ }
+ }
ws_sel(arg.i);
+ if (list) for win XMapWindow(d, c->w);
if (list) win_focus(list); else cur = 0;
}
+void
+ws_toggle(const Arg arg)
+{
+ int i, tmp = -1;
+
+ if (arg.i == ws) {
+ for (i = 1; i <= 9; i++) {
+ if (is_ws_enabled[i] && i != ws) {
+ tmp = i;
+ break;
+ }
+ }
+
+ if (tmp > 0)
+ ws_sel(tmp);
+ else
+ return;
+ }
+
+ tmp = ws;
+
+ ws_sel(arg.i);
+ if (is_ws_enabled[arg.i]) {
+ is_ws_enabled[arg.i] = 0;
+ if (list) for win XUnmapWindow(d, c->w);
+ } else {
+ is_ws_enabled[arg.i] = 1;
+ if (list) for win XMapWindow(d, c->w);
+ }
+ ws_sel(tmp);
+}
+
+void
+ws_toggle_all(const Arg arg)
+{
+ int i, tmp = ws;
+ for (i = 1; i <= 6; i++) {
+ ws_sel(i);
+ if (list) for win XMapWindow(d, c->w);
+ is_ws_enabled[i] = 1;
+ }
+ ws_sel(tmp);
+}
+
+
void configure_request(XEvent *e) {
XConfigureRequestEvent *ev = &e->xconfigurerequest;
Only in b/: sowm.o

View File

@@ -1,184 +0,0 @@
diff --git a/config.def.h b/config.def.h
index cae2009..7e422a9 100644
--- a/config.def.h
+++ b/config.def.h
@@ -3,6 +3,9 @@
#define MOD Mod4Mask
+const int handle_bar_thickness = 20;
+const char *handlebar_colour = "#ffffff";
+
const char* menu[] = {"dmenu_run", 0};
const char* term[] = {"st", 0};
const char* scrot[] = {"scr", 0};
diff --git a/sowm.c b/sowm.c
index 48222c6..551c8eb 100644
--- a/sowm.c
+++ b/sowm.c
@@ -55,6 +55,10 @@ static unsigned int ww, wh;
static Display *d;
static XButtonEvent mouse;
+static Window hb = 0;
+static XColor hbc;
+static int hba = 0;
+
static void (*events[LASTEvent])(XEvent *e) = {
[ButtonPress] = button_press,
[ButtonRelease] = button_release,
@@ -77,8 +81,37 @@ static void (*events[LASTEvent])(XEvent *e) = {
XGetGeometry(d, W, &(Window){0}, gx, gy, gw, gh, \
&(unsigned int){0}, &(unsigned int){0})
+void configure_hb_for_window(Window w) {
+ XWindowAttributes wa;
+ XGetWindowAttributes(d, w, &wa);
+ if (!hb) {
+ int s = DefaultScreen(d);
+ hb = XCreateSimpleWindow(d, RootWindow(d, s),
+ wa.x, wa.y - handle_bar_thickness,
+ wa.width + 2*wa.border_width, handle_bar_thickness,
+ 0,
+ hbc.pixel, hbc.pixel);
+ XMapWindow(d, hb);
+ XGrabButton(d, AnyButton, AnyModifier, hb, True,
+ ButtonPressMask|ButtonReleaseMask|PointerMotionMask,
+ GrabModeAsync, GrabModeAsync, 0, 0);
+ } else
+ XMoveResizeWindow(d, hb, wa.x, wa.y - handle_bar_thickness,
+ wa.width, handle_bar_thickness);
+ XRaiseWindow(d, hb);
+}
+
+void destroy_hb(void) {
+ if (!hb) return;
+ XUnmapWindow(d, hb);
+ XDestroyWindow(d, hb);
+ hb = 0;
+}
+
void win_focus(client *c) {
+ if (hba) return;
cur = c;
+ configure_hb_for_window(c->w);
XSetInputFocus(d, cur->w, RevertToParent, CurrentTime);
}
@@ -95,7 +128,22 @@ void notify_enter(XEvent *e) {
}
void notify_motion(XEvent *e) {
- if (!mouse.subwindow || cur->f) return;
+ if (e->xmotion.window == hb) {
+ 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, cur->w,
+ wx + (mouse.button == 1 ? xd : 0),
+ wy + (mouse.button == 1 ? yd : 0),
+ ww + (mouse.button == 3 ? xd : 0),
+ wh + (mouse.button == 3 ? yd : 0));
+
+ configure_hb_for_window(cur->w);
+ }
+
+ if (!mouse.subwindow || mouse.subwindow == hb || cur->f) return;
while(XCheckTypedEvent(d, MotionNotify, e));
@@ -107,6 +155,8 @@ void notify_motion(XEvent *e) {
wy + (mouse.button == 1 ? yd : 0),
ww + (mouse.button == 3 ? xd : 0),
wh + (mouse.button == 3 ? yd : 0));
+
+ if (mouse.subwindow == cur->w) configure_hb_for_window(cur->w);
}
void key_press(XEvent *e) {
@@ -122,6 +172,14 @@ void key_press(XEvent *e) {
}
void button_press(XEvent *e) {
+ if (e->xbutton.window == hb) {
+ mouse = e->xbutton;
+ hba = 1;
+ win_size(cur->w, &wx, &wy, &ww, &wh);
+ XRaiseWindow(d, cur->w);
+ return;
+ }
+
if (!e->xbutton.subwindow) return;
win_size(e->xbutton.subwindow, &wx, &wy, &ww, &wh);
@@ -131,6 +189,7 @@ void button_press(XEvent *e) {
void button_release() {
mouse.subwindow = 0;
+ hba = 0;
}
void win_add(Window w) {
@@ -160,6 +219,8 @@ void win_del(Window w) {
for win if (c->w == w) x = c;
+ if (x == cur) destroy_hb();
+
if (!list || !x) return;
if (x->prev == x) list = 0;
if (list == x) list = x->next;
@@ -180,6 +241,8 @@ void win_center() {
win_size(cur->w, &(int){0}, &(int){0}, &ww, &wh);
XMoveWindow(d, cur->w, (sw - ww) / 2, (sh - wh) / 2);
+
+ configure_hb_for_window(cur->w);
}
void win_fs() {
@@ -188,9 +251,11 @@ void win_fs() {
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
+ destroy_hb();
+ } else {
XMoveResizeWindow(d, cur->w, cur->wx, cur->wy, cur->ww, cur->wh);
+ configure_hb_for_window(cur->w);
+ }
}
void win_to_ws(const Arg arg) {
@@ -207,6 +272,8 @@ void win_to_ws(const Arg arg) {
XUnmapWindow(d, cur->w);
ws_save(tmp);
+ destroy_hb();
+
if (list) win_focus(list);
}
@@ -240,6 +307,8 @@ void ws_go(const Arg arg) {
ws_sel(arg.i);
+ destroy_hb();
+
if (list) win_focus(list); else cur = 0;
}
@@ -303,6 +372,10 @@ int main(void) {
ButtonPressMask|ButtonReleaseMask|PointerMotionMask,
GrabModeAsync, GrabModeAsync, 0, 0);
+ Colormap cm = DefaultColormap(d, s);
+ XParseColor(d, cm, handlebar_colour, &hbc);
+ XAllocColor(d, cm, &hbc);
+
while (1 && !XNextEvent(d, &ev))
if (events[ev.type]) events[ev.type](&ev);
}

View File

@@ -1,40 +0,0 @@
diff --git a/sowm.c b/sowm.c
index 6b9f794..a5bad10 100644
--- a/sowm.c
+++ b/sowm.c
@@ -28,6 +28,7 @@ typedef struct client {
Window w;
} client;
+static void init();
static void button_press(XEvent *e);
static void button_release();
static void configure_request(XEvent *e);
@@ -76,6 +77,18 @@ static void (*events[LASTEvent])(XEvent *e) = {
XGetGeometry(d, W, &(Window){0}, gx, gy, gw, gh, \
&(unsigned int){0}, &(unsigned int){0})
+void init() {
+ Window *child;
+ unsigned int nchild;
+ XQueryTree(d, RootWindow(d, DefaultScreen(d)), &(Window){0},
+ &(Window){0}, &child, &nchild);
+ for(unsigned int i = 0; i < nchild; i++) {
+ XSelectInput(d, child[i], StructureNotifyMask|EnterWindowMask);
+ XMapWindow(d, child[i]);
+ win_add(child[i]);
+ }
+}
+
void win_focus(client *c) {
cur = c;
XSetInputFocus(d, cur->w, RevertToParent, CurrentTime);
@@ -290,6 +303,8 @@ int main(void) {
XSelectInput(d, root, SubstructureRedirectMask);
XDefineCursor(d, root, XCreateFontCursor(d, 68));
+ init();
+
for (unsigned int i=0; i < sizeof(keys)/sizeof(*keys); ++i)
XGrabKey(d, XKeysymToKeycode(d, keys[i].keysym), keys[i].mod,
root, True, GrabModeAsync, GrabModeAsync);

View File

@@ -1,23 +0,0 @@
diff --git a/sowm.c b/sowm.c
index d1b4c2a..49d8af2 100644
--- a/sowm.c
+++ b/sowm.c
@@ -165,7 +165,17 @@ void win_del(Window w) {
}
void win_kill() {
- if (cur) XKillClient(d, cur->w);
+ if (!cur) return;
+
+ XEvent ev = { .type = ClientMessage };
+
+ ev.xclient.window = cur->w;
+ ev.xclient.format = 32;
+ ev.xclient.message_type = XInternAtom(d, "WM_PROTOCOLS", True);
+ ev.xclient.data.l[0] = XInternAtom(d, "WM_DELETE_WINDOW", True);
+ ev.xclient.data.l[1] = CurrentTime;
+
+ XSendEvent(d, cur->w, False, NoEventMask, &ev);
}
void win_center() {

View File

@@ -1,88 +0,0 @@
diff --git a/Makefile b/Makefile
index 8573837..72e9542 100644
--- a/Makefile
+++ b/Makefile
@@ -1,5 +1,5 @@
CFLAGS+= -std=c99 -Wall -Wextra -Wmissing-prototypes -pedantic
-LDADD+= -lX11
+LDADD+= -lX11 -lXinerama
LDFLAGS=
PREFIX?= /usr
BINDIR?= $(PREFIX)/bin
diff --git a/sowm.c b/sowm.c
index 0cc1293..6f858a9 100644
--- a/sowm.c
+++ b/sowm.c
@@ -4,6 +4,7 @@
#include <X11/XF86keysym.h>
#include <X11/keysym.h>
#include <X11/XKBlib.h>
+#include <X11/extensions/Xinerama.h>
#include <stdlib.h>
#include <signal.h>
#include <unistd.h>
@@ -48,7 +49,7 @@ static void ws_go(const Arg arg);
static int xerror() { return 0;}
static client *list = {0}, *ws_list[10] = {0}, *cur;
-static int ws = 1, sw, sh, wx, wy, numlock;
+static int ws = 1, sw, sh, wx, wy, numlock, monitors;
static unsigned int ww, wh;
static Display *d;
@@ -108,6 +109,7 @@ void notify_motion(XEvent *e) {
wy + (mouse.button == 1 ? yd : 0),
ww + (mouse.button == 3 ? xd : 0),
wh + (mouse.button == 3 ? yd : 0));
+ win_size(cur->w, &cur->wx, &cur->wy, &cur->ww, &cur->wh);
}
void key_press(XEvent *e) {
@@ -172,12 +174,35 @@ void win_kill() {
if (cur) XKillClient(d, cur->w);
}
+int multimonitor_center_fs (int fs) {
+ if (!XineramaIsActive(d)) return 1;
+ XineramaScreenInfo *screen_info = XineramaQueryScreens(d, &monitors);
+ for (int i = 0; i < monitors; i++) {
+ if ((cur->wx >= screen_info[i].x_org && cur->wx < screen_info[i].x_org + screen_info[i].width)
+ && (cur->wy >= screen_info[i].y_org && cur->wy < screen_info[i].y_org + screen_info[i].height)) {
+ if (fs)
+ XMoveResizeWindow(d, cur->w,
+ screen_info[i].x_org, screen_info[i].y_org,
+ screen_info[i].width, screen_info[i].height);
+ else
+ XMoveWindow(d, cur->w,
+ screen_info[i].x_org + ((screen_info[i].width - ww) / 2),
+ screen_info[i].y_org + ((screen_info[i].height - wh) / 2));
+ break;
+ }
+ }
+ return 0;
+}
+
void win_center() {
if (!cur) return;
win_size(cur->w, &(int){0}, &(int){0}, &ww, &wh);
- XMoveWindow(d, cur->w, (sw - ww) / 2, (sh - wh) / 2);
+ if (multimonitor_center_fs(0))
+ XMoveWindow(d, cur->w, (sw - ww) / 2, (sh - wh) / 2);
+
+ win_size(cur->w, &cur->wx, &cur->wy, &cur->ww, &cur->wh);
}
void win_fs() {
@@ -185,8 +210,8 @@ void win_fs() {
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);
-
+ if(multimonitor_center_fs(1))
+ XMoveResizeWindow(d, cur->w, 0, 0, sw, sh);
} else
XMoveResizeWindow(d, cur->w, cur->wx, cur->wy, cur->ww, cur->wh);
}

View File

@@ -1,117 +0,0 @@
diff --git a/sowm.c b/sowm.c
index bc14c4e..4ae3a8f 100644
--- a/sowm.c
+++ b/sowm.c
@@ -65,6 +65,9 @@ static void (*events[LASTEvent])(XEvent *e) = {
[MotionNotify] = notify_motion
};
+
+Window WaitingWindow;
+
#include "config.h"
#define win (client *t=0, *c=list; c && t!=list->prev; t=c, c=c->next)
@@ -75,6 +78,23 @@ static void (*events[LASTEvent])(XEvent *e) = {
XGetGeometry(d, W, &(Window){0}, gx, gy, gw, gh, \
&(unsigned int){0}, &(unsigned int){0})
+#define ABS(N) (((N)<0)?-(N):(N))
+
+void draw_outline(int x1, int y1, int x2, int y2) {
+ XClearWindow(d, RootWindow(d, DefaultScreen(d)));
+
+ GC gc = XCreateGC(d, RootWindow(d, DefaultScreen(d)), 0, NULL);
+ if(!gc)return;
+
+ XSetForeground(d, gc, WhitePixel(d, DefaultScreen(d)));
+ XDrawLine(d, RootWindow(d, DefaultScreen(d)), gc, x1, y1, x1, y2);
+ XDrawLine(d, RootWindow(d, DefaultScreen(d)), gc, x1, y1, x2, y1);
+ XDrawLine(d, RootWindow(d, DefaultScreen(d)), gc, x1, y2, x2, y2);
+ XDrawLine(d, RootWindow(d, DefaultScreen(d)), gc, x2, y1, x2, y2);
+ XFreeGC(d, gc);
+ XFlush(d);
+}
+
void win_focus(client *c) {
cur = c;
XSetInputFocus(d, cur->w, RevertToParent, CurrentTime);
@@ -93,7 +113,10 @@ void notify_enter(XEvent *e) {
}
void notify_motion(XEvent *e) {
- if (!mouse.subwindow || cur->f) return;
+ if (!mouse.subwindow || cur->f) {
+ draw_outline(mouse.x_root, mouse.y_root, e->xbutton.x_root, e->xbutton.y_root);
+ return;
+ }
while(XCheckTypedEvent(d, MotionNotify, e));
@@ -116,15 +139,43 @@ void key_press(XEvent *e) {
}
void button_press(XEvent *e) {
- if (!e->xbutton.subwindow) return;
+ mouse = e->xbutton;
+ 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() {
- mouse.subwindow = 0;
+void button_release(XEvent *e) {
+ XClearWindow(d, RootWindow(d, DefaultScreen(d)));
+
+ if(WaitingWindow){
+ XSelectInput(d, WaitingWindow, StructureNotifyMask|EnterWindowMask);
+ win_size(WaitingWindow, &wx, &wy, &ww, &wh);
+ win_add(WaitingWindow);
+ cur = list->prev;
+
+ XMoveResizeWindow(d, cur->w,
+ e->xbutton.x_root > mouse.x_root ? mouse.x_root : e->xbutton.x_root,
+ e->xbutton.y_root > mouse.y_root ? mouse.y_root : e->xbutton.y_root,
+ ABS(mouse.x_root - e->xbutton.x_root),
+ ABS(mouse.y_root - e->xbutton.y_root));
+
+ XMapWindow(d, WaitingWindow);
+ win_focus(list->prev);
+
+ WaitingWindow = 0;
+
+ } else if(!mouse.subwindow && cur) {
+
+ XMoveResizeWindow(d, cur->w,
+ e->xbutton.x_root > mouse.x_root ? mouse.x_root : e->xbutton.x_root,
+ e->xbutton.y_root > mouse.y_root ? mouse.y_root : e->xbutton.y_root,
+ ABS(mouse.x_root - e->xbutton.x_root),
+ ABS(mouse.y_root - e->xbutton.y_root));
+
+ mouse.subwindow = 0;
+ }
}
void win_add(Window w) {
@@ -244,17 +295,7 @@ void configure_request(XEvent *e) {
}
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();
-
- XMapWindow(d, w);
- win_focus(list->prev);
+ WaitingWindow = e->xmaprequest.window;
}
void run(const Arg arg) {

View File

@@ -1,112 +0,0 @@
diff --git a/Makefile b/Makefile
index 8573837..738af94 100644
--- a/Makefile
+++ b/Makefile
@@ -1,5 +1,5 @@
CFLAGS+= -std=c99 -Wall -Wextra -Wmissing-prototypes -pedantic
-LDADD+= -lX11
+LDADD+= -lX11 -lXext
LDFLAGS=
PREFIX?= /usr
BINDIR?= $(PREFIX)/bin
diff --git a/config.def.h b/config.def.h
index aaaf38d..b25dc08 100644
--- a/config.def.h
+++ b/config.def.h
@@ -2,6 +2,7 @@
#define CONFIG_H
#define MOD Mod4Mask
+#define ROUND_CORNERS 20
const char* menu[] = {"dmenu_run", 0};
const char* term[] = {"st", 0};
diff --git a/sowm.c b/sowm.c
index d1b4c2a..56bf509 100644
--- a/sowm.c
+++ b/sowm.c
@@ -4,6 +4,7 @@
#include <X11/XF86keysym.h>
#include <X11/keysym.h>
#include <X11/XKBlib.h>
+#include <X11/extensions/shape.h>
#include <stdlib.h>
#include <signal.h>
#include <unistd.h>
@@ -43,6 +44,7 @@ static void win_del(Window w);
static void win_kill();
static void win_prev();
static void win_next();
+static void win_round_corners(Window w, int rad);
static void win_to_ws(const Arg arg);
static void ws_go(const Arg arg);
static int xerror() { return 0;}
@@ -105,6 +107,9 @@ void notify_motion(XEvent *e) {
wy + (mouse.button == 1 ? yd : 0),
ww + (mouse.button == 3 ? xd : 0),
wh + (mouse.button == 3 ? yd : 0));
+
+ if (mouse.button == 3)
+ win_round_corners(mouse.subwindow, ROUND_CORNERS);
}
void key_press(XEvent *e) {
@@ -185,6 +190,41 @@ void win_fs() {
} else
XMoveResizeWindow(d, cur->w, cur->wx, cur->wy, cur->ww, cur->wh);
+
+ win_round_corners(cur->w, cur->f ? 0 : ROUND_CORNERS);
+}
+
+void win_round_corners(Window w, int rad) {
+ unsigned int ww, wh, dia = 2 * rad;
+
+ win_size(w, &(int){1}, &(int){1}, &ww, &wh);
+
+ if (ww < dia || wh < dia) return;
+
+ Pixmap mask = XCreatePixmap(d, w, ww, wh, 1);
+
+ if (!mask) return;
+
+ XGCValues xgcv;
+ GC shape_gc = XCreateGC(d, mask, 0, &xgcv);
+
+ if (!shape_gc) {
+ XFreePixmap(d, mask);
+ return;
+ }
+
+ XSetForeground(d, shape_gc, 0);
+ XFillRectangle(d, mask, shape_gc, 0, 0, ww, wh);
+ XSetForeground(d, shape_gc, 1);
+ XFillArc(d, mask, shape_gc, 0, 0, dia, dia, 0, 23040);
+ XFillArc(d, mask, shape_gc, ww-dia-1, 0, dia, dia, 0, 23040);
+ XFillArc(d, mask, shape_gc, 0, wh-dia-1, dia, dia, 0, 23040);
+ XFillArc(d, mask, shape_gc, ww-dia-1, wh-dia-1, dia, dia, 0, 23040);
+ XFillRectangle(d, mask, shape_gc, rad, 0, ww-dia, wh);
+ XFillRectangle(d, mask, shape_gc, 0, rad, ww, wh-dia);
+ XShapeCombineMask(d, w, ShapeBounding, 0, 0, mask, ShapeSet);
+ XFreePixmap(d, mask);
+ XFreeGC(d, shape_gc);
}
void win_to_ws(const Arg arg) {
@@ -241,6 +281,8 @@ void configure_request(XEvent *e) {
.sibling = ev->above,
.stack_mode = ev->detail
});
+
+ win_round_corners(ev->window, ROUND_CORNERS);
}
void map_request(XEvent *e) {
@@ -253,6 +295,7 @@ void map_request(XEvent *e) {
if (wx + wy == 0) win_center();
+ win_round_corners(w, ROUND_CORNERS);
XMapWindow(d, w);
win_focus(list->prev);
}

View File

@@ -1,43 +0,0 @@
diff --git a/config.def.h b/config.def.h
index aaaf38d..5a95d71 100644
--- a/config.def.h
+++ b/config.def.h
@@ -2,6 +2,7 @@
#define CONFIG_H
#define MOD Mod4Mask
+#define WheelResizeStep 5
const char* menu[] = {"dmenu_run", 0};
const char* term[] = {"st", 0};
diff --git a/sowm.c b/sowm.c
index bc14c4e..3b95c28 100644
--- a/sowm.c
+++ b/sowm.c
@@ -120,6 +120,17 @@ void button_press(XEvent *e) {
win_size(e->xbutton.subwindow, &wx, &wy, &ww, &wh);
XRaiseWindow(d, e->xbutton.subwindow);
+
+ int sd = 0;
+ if(e->xbutton.button == Button4) sd = WheelResizeStep;
+ else if(e->xbutton.button == Button5) sd = -WheelResizeStep;
+
+ XMoveResizeWindow(d, e->xbutton.subwindow,
+ wx - sd,
+ wy - sd,
+ ww + sd*2,
+ wh + sd*2);
+
mouse = e->xbutton;
}
@@ -285,7 +296,7 @@ int main(void) {
XGrabKey(d, XKeysymToKeycode(d, keys[i].keysym), keys[i].mod,
root, True, GrabModeAsync, GrabModeAsync);
- for (int i=1; i<4; i+=2)
+ for (int i=1; i<6; i++)
XGrabButton(d, i, MOD, root, True,
ButtonPressMask|ButtonReleaseMask|PointerMotionMask,
GrabModeAsync, GrabModeAsync, 0, 0);

326
sowm.c
View File

@@ -1,326 +0,0 @@
// 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>
typedef union {
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;
static void button_press(XEvent *e);
static void button_release();
static void configure_request(XEvent *e);
static void key_press(XEvent *e);
static void map_request(XEvent *e);
static void notify_destroy(XEvent *e);
static void notify_enter(XEvent *e);
static void notify_motion(XEvent *e);
static void run(const Arg arg);
static void win_add(Window w);
static void win_center();
static void win_del(Window w);
static void win_fs();
static void win_kill();
static void win_prev();
static void win_next();
static void win_to_ws(const Arg arg);
static void ws_go(const Arg arg);
static int xerror() { return 0;}
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 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"
#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 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))
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),
ww + (mouse.button == 3 ? xd : 0),
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() {
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() {
if (cur) XKillClient(d, cur->w);
}
void win_center() {
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() {
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() {
if (!cur) return;
XRaiseWindow(d, cur->prev->w);
win_focus(cur->prev);
}
void win_next() {
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();
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 (j=0; j < modmap->max_keypermod; j++)
if (modmap->modifiermap[i * modmap->max_keypermod + j]
== 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);
signal(SIGCHLD, SIG_IGN);
XSetErrorHandler(xerror);
int s = DefaultScreen(d);
Window 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))
if (events[ev.type]) events[ev.type](&ev);
}

125
src/event.c Normal file
View File

@@ -0,0 +1,125 @@
#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);
}
}

12
src/event.h Normal file
View File

@@ -0,0 +1,12 @@
#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 *);

11
src/globals.h Normal file
View File

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

102
src/sowm.c Normal file
View File

@@ -0,0 +1,102 @@
#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 Normal file
View File

@@ -0,0 +1,175 @@
/*
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_ */