diff options
-rw-r--r-- | Makefile | 18 | ||||
-rw-r--r-- | README.md | 182 | ||||
-rw-r--r-- | src/config | 4 | ||||
-rw-r--r-- | src/defs.h | 7 | ||||
-rw-r--r-- | src/sxwm.c | 58 |
5 files changed, 242 insertions, 27 deletions
@@ -6,6 +6,7 @@ SRC_DIR = src SRC = $(wildcard $(SRC_DIR)/*.c) OBJ = $(SRC:.c=.o) BIN = sxwm +PREFIX = /usr/local all: $(BIN) @@ -15,7 +16,20 @@ $(BIN): $(OBJ) $(SRC_DIR)/%.o: $(SRC_DIR)/%.c $(CC) $(CFLAGS) -c -o $@ $< -c: +clean: rm -f $(SRC_DIR)/*.o $(BIN) -.PHONY: all c +install: all + @echo "Installing $(BIN) to $(DESTDIR)$(PREFIX)/bin..." + @mkdir -p $(DESTDIR)$(PREFIX)/bin + @install -m 755 $(BIN) $(DESTDIR)$(PREFIX)/bin/$(BIN) + @echo "Installation complete." + +uninstall: + @echo "Uninstalling $(BIN) from $(DESTDIR)$(PREFIX)/bin..." + @rm -f $(DESTDIR)$(PREFIX)/bin/$(BIN) + @echo "Uninstallation complete." + +clean-install: clean install + +.PHONY: all clean install uninstall clean-install @@ -1,21 +1,161 @@ -MIT License - -Copyright (c) Abhinav Prasai 2025 - -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. +# sxwm (*The (truly) Simple Xorg Window Manager*) +Performance greater than DWM, and easier to config than i3wm + +<a href="https://user-images.githubusercontent.com/username/sxwm-screen1.jpg"><img src="https://user-images.githubusercontent.com/username/sxwm-screen1.jpg" width="45%" align="right"></a> + +Here we have a **minimal**, **tiling**, and **configurable** window manager. + +- **Tiling & Floating**: Seamlessly switch between layouts. +- **Workspaces**: Workspaces work with your bar. +- **Bars work too**: BAR BAR BAR?! Why not try [sxbar](https://github.com/uint23/sxbar) +- **Lightweight**: Single C file plus a small header and config. +- **Easy Config**: All settings in `config`. +- **SUPER Fast**: Sometimes **2M** sometimes **4M**, idk but still destroys DWM +- **BEST WM**: Basically DWM on roids (and without the elitism). + +<br> + +<a href="TODO"><img src="TODO" width="45%" align="right"></a> + +- **Master-Stack**: Use the DWM native and super productive layout. +- **Keyboard-driven**: Full coverage via `MOD` + keys. +- **Mouse Support**: Focus under cursor, move & resize with modifiers. +- **Zero Dependencies**: Only requires `libX11`. +- **Compiles on a Toaster**: As long as it has a decently modern compiler. + +<br clear="right"> + +--- + +## Default Configuration + +All options reside in `config` (which is just a header-file) with clear comments. +Keybindings are also easy to understand and quick to implement. +No more bindsym or... *\*shudders\** C code... +```c +CMD(terminal, "st"); +CMD(browser, "firefox"); + +static const Binding binds[] = +{ +/*————< MODIFIER(S) >< KEY >—————< FUNCTION >——*/ + +/*———————< Here are your functions calls >————— — */ + + CALL(MOD|SHIFT, e, quit), + CALL(MOD|SHIFT, q, close_focused), + + CALL(MOD, j, focus_next), + CALL(MOD, k, focus_prev), + + CALL(MOD|SHIFT, j, move_master_next), + CALL(MOD|SHIFT, k, move_master_prev), + + CALL(MOD, equal, inc_gaps), + CALL(MOD, minus, dec_gaps), + + CALL(MOD, space, toggle_floating), + CALL(MOD|SHIFT, space, toggle_floating_global), + ..... +``` + +--- + +## Default Keybindings + +**Window Management** + +| Combo | Action | +| ---------------------------- | ------------------------- | +| `Mouse` | Focus under cursor | +| `MOD` + `Left Mouse` | Move window by mouse | +| `MOD` + `Right Mouse` | Resize window by mouse | +| `MOD` + `j` / `k` | Focus next / previous | +| `MOD` + `Shift` + `j` / `k` | Move in master stack | +| `MOD` + `Space` | Toggle floating | +| `MOD` + `Shift` + `Space` | Toggle all floating | +| `MOD` + `=` / `-` | Inc/Dec gaps | +| `MOD` + `f` | Fullscreen toggle | +| `MOD` + `c` | Center window | +| `MOD` + `q` | Close focused window | +| `MOD` + `1-9` | Switch workspace 1–9 | +| `MOD` + `Shift` + `1-9` | Move window to WS 1–9 | + +**Programs** + +| Combo | Action | Programs (by default) | +| -------------------- | ---------- | --------- | +| `MOD` + `Return` | Terminal | `st` | +| `MOD` + `b` | Browser | `firefox` | + +--- + +## 📦 Dependencies + +- `libX11` (Xorg client library) +- GCC / Clang & Make + +--- + +## 🧰 Makefile Targets + +Below are the available `make` targets for streamlining common tasks: + +| Target | Description | +| ---------------- | ------------------------------------------------------------------- | +| `make` or `make all` | Compile the source files into the `sxwm` binary. | +| `make clean` | Remove object files (`*.o`) and build artifacts. | +| `make install` | Install `sxwm` to `$(PREFIX)/bin` (default `/usr/local/bin`). | +| `make uninstall` | Remove the installed binary from `$(PREFIX)/bin`. | +| `make clean-install` | Runs `make clean` then `make install`. | + +> You can override the install directory by specifying `PREFIX` or `DESTDIR`, for example: +> ```sh +> make install PREFIX=$HOME/.local +> ``` + +--- + +## 🚀 Installation + +1. **Clone repository** + + ```bash + git clone https://github.com/username/sxwm.git + cd sxwm + ``` + +2. **Build** + + ```bash + make + ``` + +3. **Install** (optional) + + ```bash + sudo make install PREFIX=/usr/local + ``` + +4. **Run** + + Add to `~/.xinitrc`: + ```sh + exec sxwm + ``` + +--- + +## 🙏 Thanks & Inspiration + +- [dwm](https://dwm.suckless.org) +- [i3](https://i3wm.org) +- [sowm](https://github.com/dylanaraps/sowm) +- [2bwm](https://github.com/venam/2bwm) +- [tinywm](http://incise.org/tinywm.html) + +--- + +<p align="center"> + <em>Contributions welcome! Open issues or submit PRs.</em> +</p> @@ -98,7 +98,6 @@ CMD(terminal, "st"); CMD(browser, "firefox"); - /* * ———————————————< Bindings >————————————————* * @@ -179,6 +178,8 @@ static const Binding binds[] = CALL(MOD, space, toggle_floating), CALL(MOD|SHIFT, space, toggle_floating_global), + CALL(MOD|SHIFT, f, toggle_fullscreen), + /*—————< Here are your executable functions >—————*/ BIND(MOD, Return, terminal), @@ -212,4 +213,5 @@ static const Binding binds[] = CALL(MOD, 9, change_ws9), CALL(MOD|SHIFT, 9, moveto_ws9), + }; @@ -3,9 +3,12 @@ #ifndef DEFS_H #define DEFS_H -#include <stdint.h> #include <X11/Xlib.h> +#define uint unsigned int +#define ulong unsigned long +#define u_char unsigned char + #define SXWM_VERSION "sxwm ver. 0.1.5" #define SXWM_AUTHOR "(C) Abhinav Prasai 2025" #define SXWM_LICINFO "See LICENSE for more info" @@ -83,7 +86,9 @@ typedef struct { typedef struct Client{ Window win; uint x, y, h, w; + uint orig_x, orig_y, orig_w, orig_h; Bool floating; + Bool fullscreen; struct Client *next; } Client; @@ -59,6 +59,7 @@ static void spawn(const char **cmd); static void tile(void); static void toggle_floating(void); static void toggle_floating_global(void); +static void toggle_fullscreen(void); static void update_borders(void); static int xerr(Display *dpy, XErrorEvent *ee); static void xev_case(XEvent *xev); @@ -122,7 +123,8 @@ add_client(Window w) c->y = wa.y; c->w = wa.width; c->h = wa.height; - c->floating = 0; + c->floating = False; + c->fullscreen = False; if (global_floating) { XSetWindowBorder(dpy, c->win, border_foc_col); @@ -504,6 +506,12 @@ move_to_workspace(uint ws) if (!focused || ws >= NUM_WORKSPACES || ws == current_ws) return; + if (focused->fullscreen) { + focused->fullscreen = False; + XMoveResizeWindow(dpy, focused->win, focused->orig_x, focused->orig_y, focused->orig_w, focused->orig_h); + XSetWindowBorderWidth(dpy, focused->win, BORDER_WIDTH); + } + /* remove from current list */ Client **pp = &workspaces[current_ws]; while (*pp && *pp != focused) pp = &(*pp)->next; @@ -702,9 +710,13 @@ tile(void) { uint total_windows = 0; Client *head = workspaces[current_ws]; - for (Client *c = head; c; c = c->next) + for (Client *c = head; c; c = c->next) { + if (c->fullscreen) + return; + if (!c->floating) ++total_windows; + } if (total_windows == 0) return; @@ -777,7 +789,13 @@ static void toggle_floating(void) { if (!focused) return; + focused->floating = !focused->floating; + if (focused->fullscreen) { + focused->fullscreen = False; + tile(); + XSetWindowBorderWidth(dpy, focused->win, BORDER_WIDTH); + } if (focused->floating) { XWindowAttributes wa; @@ -847,6 +865,41 @@ toggle_floating_global(void) } static void +toggle_fullscreen(void) +{ + if (!focused) + return; + + if (focused->floating) + focused->floating = False; + + focused->fullscreen = !focused->fullscreen; + + if (focused->fullscreen) { + XWindowAttributes wa; + XGetWindowAttributes(dpy, focused->win, &wa); + focused->orig_x = wa.x; + focused->orig_y = wa.y; + focused->orig_w = wa.width; + focused->orig_h = wa.height; + + uint fs_x = 0; + uint fs_y = 0; + uint fs_w = scr_width; + uint fs_h = scr_height; + + XSetWindowBorderWidth(dpy, focused->win, 0); + XMoveResizeWindow(dpy, focused->win, fs_x, fs_y, fs_w, fs_h); + XRaiseWindow(dpy, focused->win); // Ensure it's on top + } else { + XMoveResizeWindow(dpy, focused->win, focused->orig_x, focused->orig_y, focused->orig_w, focused->orig_h); + XSetWindowBorderWidth(dpy, focused->win, BORDER_WIDTH); + tile(); + update_borders(); + } +} + +static void update_borders(void) { for (Client *c = workspaces[current_ws]; c; c = c->next) { @@ -889,6 +942,7 @@ change_workspace(uint ws) static int xerr(Display *dpy, XErrorEvent *ee) { + /* TODO MAKE IT BETTER */ if (ee->error_code == BadWindow || ee->error_code == BadDrawable || (ee->request_code == X_ConfigureWindow && ee->error_code == BadMatch) |