124 Commits
0.2 ... 1.1

Author SHA1 Message Date
Dylan Araps
e0d0415d06 Fix keybinds issue. Closes #15.
This is rather verbose and I personally find it disgusting but
it's required to make key bindings behave.

A big thank you to DWM and other window managers for saving me
a crippling headache.

This increases the code an amount doesn't it?
2020-01-20 01:45:57 +02:00
Dylan Araps
ec79ff991a docs: update 2020-01-17 15:05:24 +02:00
dylan
5675787b03 Merge pull request #46 from SeungheonOh/master
Patch: init windows
2020-01-17 11:23:59 +02:00
Seungheon Oh
e3306e109b Patch: init windows 2020-01-16 15:21:11 -06:00
dylan
893b45b2de Merge pull request #43 from SeungheonOh/master
Fix: issue #42: Workspaces(Shiftmask) + Scary warnings
2020-01-15 10:01:37 +02:00
Seungheon Oh
1cce61e186 Fix: disabled 'missing-prototypes' warning 2020-01-14 15:28:19 -06:00
Seungheon Oh
66336521ed Fix: Shift mask now being recognized 2020-01-14 15:16:06 -06:00
dylan
85ee7ec48e Merge pull request #41 from SeungheonOh/master
New Patch: 2bswm style
2020-01-13 06:05:15 +00:00
Seungheon Oh
307001f472 2bswm style 2020-01-12 16:47:23 -06:00
dylan
d9b0c72fc9 Merge pull request #39 from Leon-Plickat/master
Fix #31
2019-12-25 08:53:22 +00:00
Leon Plickat
a199d34a45 Fix #31 2019-12-25 04:57:26 +01:00
dylan
13f874ead7 Merge pull request #38 from AnusReaper/fix-patches
Updated patches to conform with new changes
2019-12-18 12:05:47 +00:00
Dylan Araps
09a514cd5e sowm: Enable missing prototypes warning and define win_prev. 2019-12-18 11:41:21 +00:00
Dylan Araps
8ee3294adf Merge branch 'master' of github.com:dylanaraps/sowm 2019-12-18 11:30:21 +00:00
AnusReaper
bac7f781b6 Updated patches 2019-12-18 10:26:45 +00:00
dylan
623f4d8bc1 Merge pull request #36 from kiedtl/patch-1
add win_prev() function for focusing previous window
2019-12-16 09:49:36 +00:00
Kiëd Llaentenn
dcaf873fec add win_prev() 2019-12-15 18:53:52 -05:00
dylan
aaabcb8049 Merge pull request #34 from SeungheonOh/master
README.md: Instruction for applying multiple patches/Patch: Wheel for window resizing.
2019-12-15 09:26:46 +00:00
Seungheon Oh
3efaa6decc Patch: Bug fix 2019-12-14 23:16:33 -06:00
Seungheon Oh
1d37651391 Patch: Wheel for resizing window 2019-12-14 22:41:15 -06:00
Seungheon Oh
62959ded52 README.md: Instruction for applying multiple patches 2019-12-14 21:58:12 -06:00
dylan
5423c9172b Merge pull request #32 from SeungheonOh/master
New Patch: Rectangular style window launcher/mover + README.md
2019-12-14 09:32:37 +00:00
Seungheon Oh
8acd15de63 README.md: Installation 4th step for applying patch 2019-12-14 02:00:37 -06:00
Seungheon Oh
f7fd37e326 Patch: Rectangle style window launcher/mover 2019-12-14 01:56:48 -06:00
dylan
6d6889e3cf Merge pull request #30 from Leon-Plickat/master
Add handlebar patch
2019-11-28 02:17:01 +02:00
Leon Plickat
8ff3eee874 Style 2019-11-28 00:47:39 +01:00
Leon Plickat
0b7a277b22 Add handlebar patch 2019-11-27 13:53:12 +01:00
Dylan Araps
124ec67579 Merge branch 'master' of github.com:dylanaraps/sowm 2019-11-25 23:12:21 +00:00
Dylan Araps
93135664c2 sowm: Another possible fix for key bug 2019-11-25 23:12:05 +00:00
dylan
3e4010a0ca Merge pull request #28 from Leon-Plickat/master
Add patch which provides primitive multimonitor functionality
2019-11-25 19:01:50 +02:00
Leon Plickat
6b12178131 Double bug fix
Fixes bug where loop would continue even after window is configured.
Fixes bug where the window origins instead of window center is the
relevant coordinates for determining on which monitor a window is
displayed.
2019-11-25 17:54:27 +01:00
Leon Plickat
9a634e6134 Style 2019-11-25 17:20:49 +01:00
Dylan Araps
275488384a sowm: Run CI on pull requests 2019-11-25 14:50:51 +00:00
Dylan Araps
9a206d6c9d sowm: Test patches in CI. 2019-11-25 14:36:48 +00:00
Dylan Araps
51a96547ef sowm: Test patches in CI. 2019-11-25 14:35:50 +00:00
Dylan Araps
1fb75817aa sowm: prevent fullscreen windows from being moved or resized. 2019-11-25 14:30:34 +00:00
Dylan Araps
df34385548 sowm: revert key change 2019-11-25 14:30:00 +00:00
Leon Plickat
c6ff8d06a0 Simplify multimonitor_center_fs() 2019-11-25 13:52:55 +01:00
Leon Plickat
4dd50e6f4f Remove coords_in_box() 2019-11-25 13:47:20 +01:00
Leon Plickat
4867928d57 Monitor iterating now in its own function 2019-11-25 13:37:04 +01:00
Leon Plickat
afa8b1871f Make number_of_monitors global 2019-11-25 13:22:44 +01:00
Leon Plickat
216e462841 Simply coords_in_box() 2019-11-25 13:12:06 +01:00
Leon Plickat
425ae0f698 Style
Whitespace
2019-11-25 13:02:21 +01:00
Leon Plickat
8f1b7c28df Remove dependency on stdbool.h 2019-11-25 09:50:53 +01:00
Leon Plickat
818480983f Check center of window instead of origin.
Checking on what monitor the center of a window is, is more intuitive.
2019-11-25 04:58:46 +01:00
Leon Plickat
b7b08941d5 Add patch which provides primitive multimonitor functionality
With this patch, center and fullscreen will work as expected when using
multiple outputs.
2019-11-24 22:39:47 +01:00
Dylan Araps
d37d04ef32 Merge branch 'master' of github.com:dylanaraps/sowm 2019-11-24 14:24:28 +00:00
Dylan Araps
2292f86d7f sowm: potential fix for key bug 2019-11-24 14:24:13 +00:00
dylan
31bf57b69a Merge pull request #24 from eti0/patch-1
fix EWMH typo
2019-11-14 17:45:28 +02:00
eti
d79361b13e fix EWMH typo 2019-11-14 16:11:30 +01:00
dylan
7921a93eef Merge pull request #23 from tjtf2/master
update tj's tags patch
2019-11-09 22:51:43 +02:00
Timothy Joseph
a5853ab69a update tj's patch 2019-11-09 22:45:52 +02:00
Dylan Araps
e4965417f7 patches: rebase kill patch 2019-10-28 21:55:17 +00:00
Dylan Araps
bc9a9b14a5 patches: rebase rounded corners 2019-10-28 21:52:28 +00:00
Dylan Araps
421f79c47b sowm: rebase rounded corners 2019-10-25 22:42:26 +03:00
Dylan Araps
cb03ac9664 sowm: revert ungrab key change 2019-10-25 22:37:47 +03:00
Dylan Araps
5b012c10be sowm: attempt to fix key issue 2019-10-25 02:23:19 +03:00
Dylan Araps
35b12c7969 sowm: swap to new keycode to keysym func 2019-10-24 23:33:41 +03:00
Dylan Araps
e9df9ac570 docs: update 2019-10-20 23:39:12 +03:00
Dylan Araps
f14acc3b68 Merge branch 'master' of github.com:dylanaraps/sowm 2019-10-20 23:39:05 +03:00
Dylan Araps
117b04d4a6 sowm: fix workspace issue 2019-10-20 23:34:29 +03:00
dylan
0d4af0e4fa Merge pull request #14 from tjtf2/master
patches: added tj's tags patch
2019-10-20 14:09:17 +00:00
Timothy Joseph
43c7194066 patches: added tj's patch 2019-10-20 15:18:46 +03:00
Dylan Araps
144c153844 sowm: check mod first. 2019-10-19 23:29:21 +03:00
Dylan Araps
2d1e5c2654 sowm: clean up 2019-10-19 17:23:26 +03:00
Dylan Araps
d70ecee07d sowm: clean up 2019-10-19 13:40:28 +03:00
Dylan Araps
fa3c276ce6 sowm: remove now pointless checks 2019-10-19 13:24:17 +03:00
Dylan Araps
7316c149b8 sowm: use Window for window and not int 2019-10-19 10:55:21 +03:00
Dylan Araps
589bb768d9 sowm: fix current 2019-10-19 10:27:18 +03:00
Dylan Araps
84119dd331 sowm: simpler button release 2019-10-19 08:17:17 +03:00
Dylan Araps
5c075a359a sowm: simpler center 2019-10-19 08:14:03 +03:00
Dylan Araps
b48c9b6add sowm: remove root global 2019-10-19 07:49:26 +03:00
Dylan Araps
a4293a63a7 sowm: send client to focus func directly 2019-10-19 00:54:06 +03:00
Dylan Araps
e60a3bcb30 docs: update 2019-10-19 00:31:21 +03:00
Dylan Araps
4ed0c0919f sowm: track current window 2019-10-19 00:30:59 +03:00
Dylan Araps
d6b7a98586 docs: update 2019-10-19 00:18:27 +03:00
Dylan Araps
3f66256197 sowm: simpler alt tab 2019-10-19 00:18:03 +03:00
Dylan Araps
7fe47aefc1 sowm: swap to circular doubly linked list 2019-10-19 00:16:19 +03:00
Dylan Araps
0fa485eb7b docs: update 2019-10-18 20:12:59 +03:00
Dylan Araps
d1e8ee5e67 sowm: more broken (for now) 2019-10-18 19:55:26 +03:00
Dylan Araps
ef61316b5f sowm: we circular now (we also a little broken too) 2019-10-18 17:40:04 +03:00
Dylan Araps
116ebcfc74 docs: update 2019-10-18 13:55:50 +03:00
Dylan Araps
493302d38b sowm: simpler window add 2019-10-18 13:45:02 +03:00
Dylan Araps
f10cec8509 sowm: formatting 2019-10-18 13:05:25 +03:00
Dylan Araps
02b10e8585 sowm: track current client to simplify linked list implementation. 2019-10-18 12:43:09 +03:00
Dylan Araps
8917b6ddb2 sowm: revert oops 2019-10-18 12:32:36 +03:00
Dylan Araps
522defba1e sowm: simpler del 2019-10-18 12:05:13 +03:00
Dylan Araps
e0bd38091a sowm: fix crashes with cur 2019-10-18 11:42:57 +03:00
Dylan Araps
68257b329d sowm: track current window 2019-10-18 11:31:28 +03:00
Dylan Araps
009f1cd017 sowm: clean up 2019-10-17 21:12:41 +03:00
Dylan Araps
b0a8d244e0 patches: rebase 2019-10-17 19:48:23 +03:00
Dylan Araps
cd03f2e3d1 patches: optimize rounded corners further. 2019-10-17 19:47:34 +03:00
Dylan Araps
9353c2be35 patches: rebase 2019-10-17 19:43:06 +03:00
Dylan Araps
cada809f65 sowm: use simpler structure for storing workspaces. 2019-10-17 18:45:47 +03:00
Dylan Araps
0ae4e7918f sowm: move tiny tiny functions to macros. 2019-10-17 18:10:22 +03:00
Dylan Araps
1248c93bcd sowm: clean up 2019-10-17 17:02:42 +03:00
Dylan Araps
ec1f32020e sowm: removed comments for now. Will be added back in a better format. 2019-10-17 15:44:49 +03:00
Dylan Araps
f098fde9cd sowm: Shorter math for window centering. 2019-10-17 15:41:19 +03:00
Dylan Araps
518bb08dc0 sowm: None is just 0 and it's shorter 2019-10-17 15:11:14 +03:00
Dylan Araps
7a995a4970 sowm: skip setting unneeded variables. 2019-10-17 14:28:17 +03:00
Dylan Araps
c4d0b2ee8c sowm: clean up 2019-10-17 14:24:33 +03:00
Dylan Araps
ce819bd126 sowm: subscribe to even less events 2019-10-17 13:43:05 +03:00
Dylan Araps
fa90c629df docs: update 2019-10-17 13:22:28 +03:00
Dylan Araps
fa5526c842 sowm: Don't force window location when the window wants to be put elsewhere. 2019-10-17 11:26:31 +03:00
Dylan Araps
c1f3193b0f Merge branch 'master' of github.com:dylanaraps/sowm 2019-10-17 09:40:41 +03:00
Dylan Araps
3662ca427d sowm: turns out we can't pass 0 as an error handler. :P 2019-10-17 09:40:24 +03:00
Dylan Araps
fdcf245866 docs: update 2019-10-17 09:16:32 +03:00
Dylan Araps
60d88980fb sowm: subscribe to less window events! 2019-10-17 09:16:22 +03:00
Dylan Araps
4af0d54147 sowm: remove unneeded function 2019-10-17 09:03:03 +03:00
Dylan Araps
8e3c9da820 sowm: Remove unneeded call to ws_go on start 2019-10-17 08:53:59 +03:00
Dylan Araps
de4a08ace0 sowm: avoid branch and variable. 2019-10-17 08:39:40 +03:00
Dylan Araps
669ca21407 sowm: simpler window geometry 2019-10-16 17:25:40 +03:00
Dylan Araps
a5503f8159 sowm: avoid global and remove uneeded initial value. 2019-10-16 15:50:10 +03:00
Dylan Araps
42e126009f sowm: void unneeded variable 2019-10-16 15:46:09 +03:00
Dylan Araps
72a0f32dd4 docs: update 2019-10-16 15:22:28 +03:00
Dylan Araps
fa96cc7b18 sowm: reduce scope of client 2019-10-16 14:15:34 +03:00
Dylan Araps
f36c78d9bb sowm: move two overly simple functions to macros. 2019-10-16 13:21:36 +03:00
Dylan Araps
d6de000725 docs: update 2019-10-16 12:50:18 +03:00
Dylan Araps
2c17908a78 docs: update 2019-10-16 11:50:38 +03:00
Dylan Araps
5161ad72f8 docs: update 2019-10-16 11:45:27 +03:00
Dylan Araps
43025432ac sowm: intialize cursor buttons using loop to remove duplicate code 2019-10-16 11:44:59 +03:00
Dylan Araps
8bdffcacda docs: update 2019-10-16 09:19:56 +03:00
Dylan Araps
446ad2e02c sowm: Use modifier from config for mouse controls. 2019-10-16 09:17:46 +03:00
Dylan Araps
19e3078aea docs: update 2019-10-16 09:16:11 +03:00
15 changed files with 1045 additions and 464 deletions

9
.github/workflows/main.yml vendored Normal file
View File

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

View File

@@ -1,4 +1,4 @@
CFLAGS+= -std=c99 -Wall -Wextra -pedantic -Wno-deprecated-declarations
CFLAGS+= -std=c99 -Wall -Wextra -pedantic
LDADD+= -lX11
LDFLAGS=
PREFIX?= /usr
@@ -19,3 +19,6 @@ install: all
clean:
rm -f sowm *.o
test:
for patch in patches/*.patch; do patch --dry-run -p1 < "$$patch"; done

View File

@@ -1,8 +1,8 @@
# sowm
# 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 (*270~ sloc / 24kb compiled!*).
An itsy bitsy floating window manager (*220~ sloc / 24kb compiled!*).
- Floating only.
- Fullscreen toggle.
@@ -15,10 +15,9 @@ An itsy bitsy floating window manager (*270~ sloc / 24kb compiled!*).
- Alt-Tab window focusing.
- All windows die on exit.
- No borders.
- No bar support.
- No ICCCM.
- No EMWH.
- 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
@@ -66,6 +65,8 @@ An itsy bitsy floating window manager (*270~ sloc / 24kb compiled!*).
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

View File

@@ -15,9 +15,11 @@ const char* colors[] = {"bud", "/home/goldie/Pictures/Wallpapers", 0};
static struct key keys[] = {
{MOD, XK_q, win_kill, {0}},
{MOD, XK_c, win_center, {.w = 0}},
{MOD, XK_c, win_center, {0}},
{MOD, XK_f, win_fs, {0}},
{Mod1Mask, XK_Tab, win_next, {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}},

View File

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

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

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

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

40
patches/sowm-init.patch Normal file
View File

@@ -0,0 +1,40 @@
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 +1,23 @@
diff --git a/sowm.c b/sowm.c
index 0d74d4b..ff70968 100644
index d1b4c2a..49d8af2 100644
--- a/sowm.c
+++ b/sowm.c
@@ -326,7 +326,17 @@ void win_del(Window w) {
"Shoot first and don't ask questions later?.."
*/
@@ -165,7 +165,17 @@ void win_del(Window w) {
}
void win_kill() {
- if (win_current() != root) XKillClient(d, cur);
+ if (win_current() == root) return;
- if (cur) XKillClient(d, cur->w);
+ if (!cur) return;
+
+ XEvent ev = { .type = ClientMessage };
+
+ ev.xclient.window = cur;
+ 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, False, NoEventMask, &ev);
+ XSendEvent(d, cur->w, False, NoEventMask, &ev);
}
/*
void win_center() {

View File

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

@@ -0,0 +1,117 @@
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,83 +1,68 @@
diff --git a/Makefile b/Makefile
index 2549d3a..04c2222 100644
index 8573837..738af94 100644
--- a/Makefile
+++ b/Makefile
@@ -1,5 +1,5 @@
CFLAGS+= -std=c99 -Wall -Wextra -pedantic -Wno-deprecated-declarations
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 864c9a7..1525894 100644
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 b9e8867..4c0b3fa 100644
index d1b4c2a..56bf509 100644
--- a/sowm.c
+++ b/sowm.c
@@ -3,6 +3,7 @@
#include <X11/Xlib.h>
@@ -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>
@@ -59,6 +59,7 @@ static void win_del(Window w);
static void win_fs();
@@ -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 void ws_save(int i);
@@ -179,6 +179,9 @@ void notify_motion(XEvent *e) {
attr.y + (mouse.button == 1 ? yd : 0),
attr.width + (mouse.button == 3 ? xd : 0),
attr.height + (mouse.button == 3 ? yd : 0));
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);
}
/*
@@ -367,9 +367,58 @@ void win_fs() {
} else
XMoveResizeWindow(d, cur, c->a.x, c->a.y, c->a.width, c->a.height);
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, c->f ? 0 : ROUND_CORNERS);
}
}
+/*
+ Round the corners of the desired window.
+ win_round_corners(cur->w, cur->f ? 0 : ROUND_CORNERS);
+}
+
+ This isn't included in the actual source as it
+ requires the 'shape' extension to Xorg and I'd
+ like to keep the original source simple.
+
+ This is very similar to the rounded corners
+ implementations in the 'dwm' and 'openbox'
+ patches.
+*/
+void win_round_corners(Window w, int rad) {
+ XWindowAttributes attr2;
+ XGetWindowAttributes(d, w, &attr2);
+ unsigned int ww, wh, dia = 2 * rad;
+
+ int dia = 2 * rad;
+ int ww = attr2.width;
+ int wh = attr2.height;
+ win_size(w, &(int){1}, &(int){1}, &ww, &wh);
+
+ if (ww < dia || wh < dia) return;
+
@@ -105,16 +90,23 @@ index b9e8867..4c0b3fa 100644
+ XShapeCombineMask(d, w, ShapeBounding, 0, 0, mask, ShapeSet);
+ XFreePixmap(d, mask);
+ XFreeGC(d, shape_gc);
+ }
+
/*
This function simply moves the focused window to
the desired desktop.
@@ -511,6 +511,7 @@ void map_request(XEvent *e) {
win_center((Arg){.i = w});
XMapWindow(d, w);
+ win_round_corners(w, ROUND_CORNERS);
FOC(w);
win_add(w);
}
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

@@ -0,0 +1,43 @@
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);

526
sowm.c
View File

@@ -3,23 +3,11 @@
#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>
/*
This iterates over the current desktop's
window list and is inserted where needed.
*/
#define WIN (c=list;c;c=c->next)
/*
This sets focus to the given window. It
could very well be a function but I feel
it belongs here.
*/
#define FOC(W) XSetInputFocus(d, W, RevertToParent, CurrentTime);
typedef union {
const char** com;
const int i;
@@ -33,21 +21,16 @@ struct key {
const Arg arg;
};
typedef struct client client;
struct client{
client *next, *prev;
typedef struct client {
struct client *next, *prev;
int f, wx, wy;
unsigned int ww, wh;
Window w;
XWindowAttributes a;
int f;
};
typedef struct desktop desktop;
struct desktop{client *list;};
} client;
static void button_press(XEvent *e);
static void button_release();
static void configure_request(XEvent *e);
static void key_grab();
static void key_press(XEvent *e);
static void map_request(XEvent *e);
static void notify_destroy(XEvent *e);
@@ -55,31 +38,23 @@ 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(const Arg arg);
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 void ws_save(int i);
static void ws_sel(int i);
static int xerror() { return 0;}
static client *list = {0};
static desktop ws_list[10];
static int ws = 1, sh, sw, s;
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 Window root, cur;
static XButtonEvent mouse;
static XWindowAttributes attr;
static Display *d;
static XButtonEvent mouse;
#include "config.h"
/*
The list of events to subscribe to and the paired functions
to call on an event.
*/
static void (*events[LASTEvent])(XEvent *e) = {
[ButtonPress] = button_press,
[ButtonRelease] = button_release,
@@ -91,353 +66,165 @@ static void (*events[LASTEvent])(XEvent *e) = {
[MotionNotify] = notify_motion
};
/*
'sowm' doesn't keep track of the currently focused window
and instead grabs window under the cursor when needed.
#include "config.h"
This is a super lazy way of handling current focus, however
it aligns perfectly with mouse-follows-focus.
#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]
Logic below will select a real window if this function
returns the 'root' window.
#define win_size(W, gx, gy, gw, gh) \
XGetGeometry(d, W, &(Window){0}, gx, gy, gw, gh, \
&(unsigned int){0}, &(unsigned int){0})
This function returns the current window while at the same
time defining a global variable to contain its value. This
allows for stupidily simple usage.
// Taken from DWM. Many thanks. https://git.suckless.org/dwm
#define mod_clean(mask) (mask & ~(numlock|LockMask) & \
(ShiftMask|ControlMask|Mod1Mask|Mod2Mask|Mod3Mask|Mod4Mask|Mod5Mask))
Example: if (win_current() != root) XKillClient(d, cur);
The value can be used as function output and then
the same value can be used as a variable directly afterwards.
*/
Window win_current() {
XGetInputFocus(d, &cur, (int[]){1});
return cur;
void win_focus(client *c) {
cur = c;
XSetInputFocus(d, cur->w, RevertToParent, CurrentTime);
}
/*
When a window is destroyed it is first removed from the
current desktop's window list and finally focus is shifted.
Focus goes to the window under the cursor if it is *not*
the root window. If it is the root window, focus goes to
the first window in the desktop.
*/
void notify_destroy(XEvent *e) {
win_del(e->xdestroywindow.window);
if (list) FOC(win_current() == root ? list->w : cur);
if (list) win_focus(list->prev);
}
/*
When the mouse enters or leaves a window this function
handles which window shall be focused next.
The while loop firstly compresses all 'EnterNotify'
events down to only the latest which is an optimization
when focus changes very quickly (e.g a desktop focus).
There's no use in computing each and every event as we
only really care about the newest one.
Focus is only then changed if the mouse has entered a
window which is *not* the root window.
*/
void notify_enter(XEvent *e) {
while(XCheckTypedEvent(d, EnterNotify, e));
if (e->xcrossing.window != root) FOC(e->xcrossing.window)
for win if (c->w == e->xcrossing.window) win_focus(c);
}
/*
When the mouse is moved and the paired modifier is
pressed this function handles a window move or a window
resize.
'mouse' is defined on a modifier+mouse press and then
discarded on a modifier+mouse release.
The while loop firstly compresses all 'MotionNotify'
events down to only the latest which is an optimization
when motion happens very quickly.
There's no use in computing each and every event as we
only really care about the newest one.
The window is then moved or resized.
*/
void notify_motion(XEvent *e) {
if (mouse.subwindow == None) return;
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;
while(XCheckTypedEvent(d, MotionNotify, e));
XMoveResizeWindow(d, mouse.subwindow,
attr.x + (mouse.button == 1 ? xd : 0),
attr.y + (mouse.button == 1 ? yd : 0),
attr.width + (mouse.button == 3 ? xd : 0),
attr.height + (mouse.button == 3 ? yd : 0));
wx + (mouse.button == 1 ? xd : 0),
wy + (mouse.button == 1 ? yd : 0),
ww + (mouse.button == 3 ? xd : 0),
wh + (mouse.button == 3 ? yd : 0));
}
/*
This function initializes all key bindings defined in 'config.h'.
Simple stuff, nothing fancy or different from other window
managers happens here.
*/
void key_grab() {
KeyCode code;
for (unsigned int i=0; i < sizeof(keys)/sizeof(*keys); ++i)
if ((code = XKeysymToKeycode(d, keys[i].keysym)))
XGrabKey(d, code, keys[i].mod, root,
True, GrabModeAsync, GrabModeAsync);
}
/*
This function fires on a key press and checks to see if there
is a matching and defined key binding. If there is a match the
function bound to the key is executed.
The deprecated 'XKeycodeToKeysym' is used as the replacement
requires an additional include and I want to keep them to a
minimum.
I highly doubt this deprecated function goes away any time soon
and worst case, I simply update this code. Win-win.
*/
void key_press(XEvent *e) {
KeySym keysym = XKeycodeToKeysym(d, e->xkey.keycode, 0);
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 && keys[i].mod == e->xkey.state)
if (keys[i].keysym == keysym &&
mod_clean(keys[i].mod) == mod_clean(e->xkey.state))
keys[i].function(keys[i].arg);
}
/*
On a mouse button press the window below the cursor's
attributes are stored, the window is raised and the 'mouse'
global is set.
Setting the 'mouse' global tells the motion handling function
that it should operate on the window as the user desires a move
or resize.
*/
void button_press(XEvent *e) {
if (e->xbutton.subwindow == None) return;
if (!e->xbutton.subwindow) return;
XGetWindowAttributes(d, e->xbutton.subwindow, &attr);
win_size(e->xbutton.subwindow, &wx, &wy, &ww, &wh);
XRaiseWindow(d, e->xbutton.subwindow);
mouse = e->xbutton;
}
/*
On a mouse button release we simply unset the 'mouse' global
as all of this mouse pointer nonsense is done.
We also reset the current window's fullscreen state as it is
no longer at 0,0+[screen_width]X[screen_height].
*/
void button_release() {
client *c;
for WIN if (c->w == mouse.subwindow) c->f = 0;
mouse.subwindow = None;
mouse.subwindow = 0;
}
/*
This function is called whenever a window is mapped to the
screen or moved to another desktop.
Memory is allocated for the new window and the current
desktop's window list is updated.
*/
void win_add(Window w) {
client *c, *t;
client *c;
if (!(c = (client *)calloc(1, sizeof(client))))
if (!(c = (client *) calloc(1, sizeof(client))))
exit(1);
if (!list) {
c->next = c->prev = 0;
c->w = w;
list = c;
c->w = w;
if (list) {
list->prev->next = c;
c->prev = list->prev;
list->prev = c;
c->next = list;
} else {
for (t=list;t->next;t=t->next);
c->next = 0;
c->prev = t;
c->w = w;
t->next = c;
list = c;
list->prev = list->next = list;
}
ws_save(ws);
}
/*
This function is called whenever a window is destoyed
or moved to another desktop.
Memory is freed and the current desktop's window list
is updated.
*/
void win_del(Window w) {
client *c;
client *x = 0;
for WIN if (c->w == w) {
if (!c->prev && !c->next) {
free(list);
list = 0;
ws_save(ws);
return;
}
for win if (c->w == w) x = c;
if (!c->prev) {
list = c->next;
c->next->prev = 0;
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;
} else if (!c->next) {
c->prev->next = 0;
} else {
c->prev->next = c->next;
c->next->prev = c->prev;
}
free(c);
ws_save(ws);
return;
}
free(x);
ws_save(ws);
}
/*
This function is called from a key binding to
close the currently focused window.
This differs from other window managers as we skip
the questions and go straight to the killing of
the window.
When I want to close a window I'm not asking, I
want the window closed and so it should immediately
close.
"Shoot first and don't ask questions later?.."
*/
void win_kill() {
if (win_current() != root) XKillClient(d, cur);
if (cur) XKillClient(d, cur->w);
}
/*
This function simply centers the window passed as
an argument. If the argument is '0', use the
currently focused window.
*/
void win_center(const Arg arg) {
Window w = arg.w ? arg.w : win_current();
void win_center() {
if (!cur) return;
XGetWindowAttributes(d, w, &attr);
win_size(cur->w, &(int){0}, &(int){0}, &ww, &wh);
XMoveWindow(d, w, sw / 2 - attr.width / 2,
sh / 2 - attr.height / 2);
XMoveWindow(d, cur->w, (sw - ww) / 2, (sh - wh) / 2);
}
/*
This function toggles the fullscreen state for the
window passed as an argument.
The window's data stucture holds an integer which
is set to '0' for False and '1' for True.
When a window is set to fullscreen it is simply
resized to fit the screen and the prior size and
positioning is stored so it can be restored when
the window is un-fullscreened.
*/
void win_fs() {
client *c;
if (!cur) return;
win_current();
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);
for WIN if (c->w == cur) {
if ((c->f = c->f == 0 ? 1 : 0)) {
XGetWindowAttributes(d, cur, &c->a);
XMoveResizeWindow(d, cur, 0, 0, sw, sh);
} else
XMoveResizeWindow(d, cur, c->a.x, c->a.y, c->a.width, c->a.height);
}
} else
XMoveResizeWindow(d, cur->w, cur->wx, cur->wy, cur->ww, cur->wh);
}
/*
This function simply moves the focused window to
the desired desktop.
It firstly adds the window to the destination
desktop's window list and secondly deletes it
from the current desktop's window list.
The window is then unmapped from the screen and
the focus is shifted to the first window in the
list.
*/
void win_to_ws(const Arg arg) {
int tmp = ws;
win_current();
if (arg.i == tmp) return;
ws_sel(arg.i);
win_add(cur);
win_add(cur->w);
ws_save(arg.i);
ws_sel(tmp);
win_del(cur);
XUnmapWindow(d, cur);
win_del(cur->w);
XUnmapWindow(d, cur->w);
ws_save(tmp);
if (list) FOC(list->w);
if (list) win_focus(list);
}
/*
This function focuses the next window in the
current desktop's window list.
void win_prev() {
if (!cur) return;
If the end of the window list is reached it
wraps back around to the start of the list.
XRaiseWindow(d, cur->prev->w);
win_focus(cur->prev);
}
The newly focused window is then raised to
the top of the stack.
*/
void win_next() {
win_current();
client *c;
if (!cur) return;
if (list) {
for WIN if (c->w == cur) break;
c = c->next ? c->next : list;
FOC(c->w);
XRaiseWindow(d, c->w);
}
XRaiseWindow(d, cur->next->w);
win_focus(cur->next);
}
/*
This function changes the focus to another desktop.
To make this operation invisible the destination
desktop's windows are mapped first and the previous
desktop's windows are then unmapped afterwards.
Finally, focus is shifted to the first window on the
destination desktop's window list.
*/
void ws_go(const Arg arg) {
client *c;
int tmp = ws;
if (arg.i == ws) return;
@@ -445,82 +232,44 @@ void ws_go(const Arg arg) {
ws_save(ws);
ws_sel(arg.i);
if (list) for WIN XMapWindow(d, c->w);
for win XMapWindow(d, c->w);
ws_sel(tmp);
if (list) for WIN XUnmapWindow(d, c->w);
for win XUnmapWindow(d, c->w);
ws_sel(arg.i);
if (list) FOC(list->w);
if (list) win_focus(list); else cur = 0;
}
/*
This function saves the current desktop's window list.
Simple, nothing to see here.
*/
void ws_save(int i) {
ws_list[i].list = list;
}
/*
This function restores a saved desktop's window list.
Simple, nothing to see here.
*/
void ws_sel(int i) {
list = ws_list[i].list;
ws = i;
}
/*
This function allows a window to request a size,
position and other attributes.
This is required so programs like Firefox or MPV
are able to display and function correctly.
*/
void configure_request(XEvent *e) {
XConfigureRequestEvent *ev = &e->xconfigurerequest;
XWindowChanges wc;
wc.x = ev->x;
wc.y = ev->y;
wc.width = ev->width;
wc.height = ev->height;
wc.sibling = ev->above;
wc.stack_mode = ev->detail;
XConfigureWindow(d, ev->window, ev->value_mask, &wc);
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
});
}
/*
This function is executed whenever a window is mapped to
the screen.
The window is centered, mapped to the screen, focused and
finally added to the current desktop's window list.
'XSelectInput' is called to subscribe to various events
related to the window. For example, this is used to get
focus-follows-cursor to work.
*/
void map_request(XEvent *e) {
Window w = e->xmaprequest.window;
XSelectInput(d, w, PropertyChangeMask|StructureNotifyMask|
EnterWindowMask|FocusChangeMask);
win_center((Arg){.i = w});
XMapWindow(d, w);
FOC(w);
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);
}
/*
This function is executed by keybindings to run the
specified program. Simple enough.
*/
void run(const Arg arg) {
if (fork()) return;
if (d) close(ConnectionNumber(d));
@@ -529,58 +278,49 @@ void run(const Arg arg) {
execvp((char*)arg.com[0], (char**)arg.com);
}
/*
This window manager ignores all Xorg related errors.
void input_grab(Window root) {
unsigned int i, j, modifiers[] = {0, LockMask, numlock, numlock|LockMask};
XModifierKeymap *modmap = XGetModifierMapping(d);
KeyCode code;
The window manager either crashes (due to Xorg or
itself) or it continues on its merry way.
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);
The only errors which are handled are failed memory
allocations or a failure to open the display on start.
*/
int xerror() { return 0; }
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);
/*
Initialize the window manager by registering all
keybindings, setting some globals and starting the
event loop.
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);
There's no 'XClosDisplay' or clean up as the only way
to exit this window manager is to kill the process.
XFreeModifiermap(modmap);
}
This fires up Xorg's internal clean up which covers
everything allocated and executed here. It's free!
*/
int main(void) {
XEvent ev;
if (!(d = XOpenDisplay(0x0))) return 0;
if (!(d = XOpenDisplay(0))) exit(1);
signal(SIGCHLD, SIG_IGN);
XSetErrorHandler(xerror);
s = DefaultScreen(d);
root = RootWindow(d, s);
sw = XDisplayWidth(d, s);
sh = XDisplayHeight(d, s);
key_grab();
ws_go((Arg){.i = 1});
XSelectInput(d, root, SubstructureNotifyMask|
SubstructureRedirectMask|EnterWindowMask|LeaveWindowMask);
XGrabButton(d, 1, Mod4Mask, root, True,
ButtonPressMask|ButtonReleaseMask|PointerMotionMask,
GrabModeAsync, GrabModeAsync, None, None);
XGrabButton(d, 3, Mod4Mask, root, True,
ButtonPressMask|ButtonReleaseMask|PointerMotionMask,
GrabModeAsync, GrabModeAsync, None, None);
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))
while (1 && !XNextEvent(d, &ev))
if (events[ev.type]) events[ev.type](&ev);
}