├── LICENSE ├── Makefile ├── README.md └── wind.c /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2020 SeungheonOh 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | CFLAGS+= -Wall -Wextra -pedantic 2 | LDADD+= -lX11 -lXext 3 | LDFLAGS= 4 | PREFIX?= /usr 5 | BINDIR?= $(PREFIX)/bin 6 | 7 | CC ?= gcc 8 | 9 | all: wind 10 | 11 | wind: wind.o 12 | $(CC) $(LDFLAGS) -O3 -o $@ $+ $(LDADD) 13 | 14 | install: all 15 | install -Dm 755 wind $(DESTDIR)$(BINDIR)/wind 16 | 17 | uninstall: 18 | rm $(BINDIR)/wind 19 | 20 | clean: 21 | rm -f wind *.o 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Wind 2 | Wind (Wind is not dummy) :) 3 | A sub-150-loc X11 window manager, that works without any dumb dumb stuff. 4 | 5 | # Features 6 | - Simple drag to move 7 | - Simple drag to resize 8 | - Wheel for all sides size increments/decrement 9 | - Cool outline style drag move 10 | - Readable code(kind of) 11 | 12 | # Installation 13 | Xlib is the only dependency 14 | ``` 15 | make 16 | make install 17 | ``` 18 | 19 | # Keymaps? 20 | Nah, speration of WM and hotkey daemon give user a very clear seperation and more managable configuration. 21 | 22 | [Sxhkd](https://github.com/baskerville/sxhkd) is simple, and you don't have to deal with some dumb stuffs, just like Wind. 23 | 24 | # Thanks 25 | [sowm](https://github.com/dylanaraps/sowm) by dylanaraps 26 | 27 | [catwm](https://github.com/pyknite/catwm) by pyknite 28 | -------------------------------------------------------------------------------- /wind.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | #define ABS(N) (((N)<0)?-(N):(N)) 7 | #define MAX(x,y) ((x)<(y)?(y):(x)) 8 | #define MIN(x,y) ((x)>(y)?(y):(x)) 9 | 10 | typedef struct client { 11 | Window window; 12 | int x, y; 13 | unsigned int width, height; 14 | } client; 15 | 16 | Display *d; 17 | int s; 18 | Window root; 19 | client current; 20 | XButtonEvent mouse; 21 | 22 | void outline(int x, int y, unsigned int width, unsigned int height) { 23 | static int X, Y, W, H; // previous outline 24 | GC gc = XCreateGC(d, root, GCFunction|GCLineWidth, &(XGCValues){.function = GXinvert, .line_width=3}); 25 | if(!gc) return; 26 | XSetForeground(d, gc, WhitePixel(d, s)); 27 | XDrawRectangle(d, root, gc, X, Y, W, H); 28 | XDrawRectangle(d, root, gc, x, y, width, height); 29 | XFreeGC(d, gc); 30 | XFlush(d); 31 | X = x; 32 | Y = y; 33 | W = width; 34 | H = height; 35 | } 36 | 37 | void init(){ 38 | Window *child; 39 | unsigned int nchild; 40 | XQueryTree(d, root, &(Window){0}, 41 | &(Window){0}, &child, &nchild); 42 | 43 | for(unsigned int i = 0; i < nchild; i++) { 44 | XSelectInput(d, child[i], EnterWindowMask|LeaveWindowMask|SubstructureNotifyMask); 45 | XMapWindow(d, child[i]); 46 | } 47 | } 48 | 49 | client get_client(Window win){ 50 | client c; 51 | 52 | XGetGeometry(d, win, &(Window){0}, 53 | &c.x, &c.y, &c.width, &c.height, 54 | &(unsigned int){0}, &(unsigned int){0}); 55 | 56 | c.window = win; 57 | return c; 58 | } 59 | 60 | void btn_press(XEvent *e){ 61 | mouse = e->xbutton; 62 | 63 | if(!e->xbutton.subwindow) return; 64 | current = get_client(e->xbutton.subwindow); 65 | XRaiseWindow(d, current.window); 66 | 67 | int sd = 0; // Wheel resize 68 | if(e->xbutton.button == 4) sd = 5; 69 | else if(e->xbutton.button == 5) sd = -5; 70 | 71 | XMoveResizeWindow(d, current.window, 72 | current.x - sd, current.y - sd, 73 | current.width + sd*2, current.height + sd*2); 74 | } 75 | 76 | void btn_release(XEvent *e){ 77 | outline(0, 0, 0, 0); 78 | XDefineCursor(d, root, XCreateFontCursor(d, 68)); 79 | if(!current.window || mouse.subwindow)return; 80 | XMoveResizeWindow(d, current.window, 81 | MIN(mouse.x_root, e->xbutton.x_root), MIN(mouse.y_root, e->xbutton.y_root), 82 | ABS(e->xbutton.x_root - mouse.x_root), ABS(e->xbutton.y_root - mouse.y_root)); 83 | 84 | current = (client){0}; 85 | mouse = (XButtonEvent){0}; 86 | } 87 | 88 | void config_request(XEvent *e){ 89 | XConfigureRequestEvent *ev = &e->xconfigurerequest; 90 | XConfigureWindow(d, ev->window, ev->value_mask, &(XWindowChanges){ 91 | .x = ev->x, .y = ev->y, 92 | .width = ev->width, .height = ev->height, 93 | .sibling = ev->above, .stack_mode = ev->detail 94 | }); 95 | } 96 | 97 | void map_request(XEvent *e){ 98 | int x = 0, y = 0; 99 | if(!XQueryPointer(d, root, &(Window){0}, &(Window){0}, &x, &y, &(int){0}, &(int){0}, &(unsigned int){0})) return; 100 | Window win = e->xmaprequest.window; 101 | XSelectInput(d, win, EnterWindowMask|LeaveWindowMask|SubstructureNotifyMask); 102 | current = get_client(win); 103 | XMoveWindow(d, win, x - current.width/2, y - current.height/2); 104 | XMapWindow(d, win); 105 | XSetWindowBorder(d, win, WhitePixel(d, s)); 106 | XConfigureWindow(d, win, CWBorderWidth, &(XWindowChanges){.border_width = 2}); 107 | XSetInputFocus(d, e->xcrossing.window, RevertToParent, CurrentTime); 108 | } 109 | 110 | void enter_notify(XEvent *e){ 111 | if(e->xcrossing.window) 112 | XSetInputFocus(d, e->xcrossing.window, RevertToParent, CurrentTime); 113 | } 114 | 115 | void motion_notify(XEvent *e) { 116 | int xd = e->xbutton.x_root - mouse.x_root; 117 | int yd = e->xbutton.y_root - mouse.y_root; 118 | 119 | if(!current.window || !mouse.subwindow){ 120 | XDefineCursor(d, root, XCreateFontCursor(d, 34)); 121 | outline(MIN(mouse.x_root, e->xbutton.x_root), MIN(mouse.y_root, e->xbutton.y_root), 122 | ABS(xd), ABS(yd)); 123 | return; 124 | } 125 | 126 | XMoveResizeWindow(d, current.window, 127 | current.x + (mouse.button == 1 ? xd : 0), 128 | current.y + (mouse.button == 1 ? yd : 0), 129 | current.width + (mouse.button == 3 ? xd : 0), 130 | current.height + (mouse.button == 3 ? yd : 0)); 131 | } 132 | 133 | int xerror(){ return 0; } 134 | 135 | static void (*event_handler[LASTEvent])(XEvent *e) = { 136 | [ButtonPress] = btn_press, 137 | [ButtonRelease] = btn_release, 138 | [ConfigureRequest] = config_request, 139 | [MapRequest] = map_request, 140 | [EnterNotify] = enter_notify, 141 | [MotionNotify] = motion_notify 142 | }; 143 | 144 | int main() { 145 | if(!(d = XOpenDisplay(0))) exit(1); 146 | s = DefaultScreen(d); 147 | root = RootWindow(d, s); 148 | 149 | signal(SIGCHLD, SIG_IGN); 150 | XSetErrorHandler(xerror); 151 | 152 | XSelectInput(d, root, SubstructureRedirectMask); 153 | XDefineCursor(d, root, XCreateFontCursor(d, 68)); 154 | 155 | init(); 156 | 157 | for(int i = 1; i < 7; i++) 158 | XGrabButton(d, i, Mod4Mask , DefaultRootWindow(d), True, 159 | ButtonPressMask|ButtonReleaseMask|PointerMotionMask, 160 | GrabModeAsync, GrabModeAsync, 0, 0); 161 | 162 | XEvent ev; 163 | while(!XNextEvent(d, &ev)) 164 | if(event_handler[ev.type])event_handler[ev.type](&ev); 165 | } 166 | 167 | --------------------------------------------------------------------------------