├── .gitignore ├── test.sh ├── src ├── config.h ├── util.h ├── wm.h ├── util.c ├── binding.h ├── wayland.h ├── screen.h ├── wayland.c ├── wm.c ├── screen.c ├── binding.c ├── window.h ├── config.c └── window.c ├── LICENSE ├── Makefile ├── defconfig └── README.md /.gitignore: -------------------------------------------------------------------------------- 1 | wm 2 | *.o 3 | 4 | -------------------------------------------------------------------------------- /test.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | swc-launch -t /dev/tty8 -- ./wm -d 4 | 5 | -------------------------------------------------------------------------------- /src/config.h: -------------------------------------------------------------------------------- 1 | #ifndef CONFIG_H 2 | #define CONFIG_H 3 | 4 | #include 5 | #include 6 | 7 | /* 8 | * Load the config file and initiate the parsing. 9 | */ 10 | void load_config(char *); 11 | 12 | /* 13 | * Take the already opened FILE, read it line by line and parse it. 14 | */ 15 | void parse_config(FILE *); 16 | 17 | /* 18 | * Trigger a manual config reload. 19 | */ 20 | void reload_config(void *, uint32_t, uint32_t, uint32_t); 21 | 22 | #endif 23 | 24 | -------------------------------------------------------------------------------- /src/util.h: -------------------------------------------------------------------------------- 1 | #ifndef UTIL_H 2 | #define UTIL_H 3 | 4 | #include 5 | 6 | /* 7 | * Print a pretty formatted debug message if debugging is enabled. 8 | */ 9 | void debug(char *); 10 | 11 | /* 12 | * Print a pretty formatted warning message. 13 | */ 14 | void warn(char *); 15 | 16 | /* 17 | * Print a pretty formatted error message and then kill everything. 18 | */ 19 | void die(char *); 20 | 21 | /* 22 | * Spawn an arbitrary command. 23 | */ 24 | void spawn(void *, uint32_t, uint32_t, uint32_t); 25 | 26 | #endif 27 | 28 | -------------------------------------------------------------------------------- /src/wm.h: -------------------------------------------------------------------------------- 1 | #ifndef WM_H 2 | #define WM_H 3 | 4 | #include 5 | 6 | #define VERSION "0.2a" 7 | 8 | /* 9 | * Hold the complete global state, the Wayland connection, active 10 | * screens and windows. 11 | */ 12 | struct wm { 13 | bool running; 14 | 15 | char *config; 16 | 17 | bool debug; 18 | int borderwidth; 19 | unsigned int bordercolor; 20 | int margins; 21 | 22 | struct wl_connection *wl_connection; 23 | struct screen *active_screen; 24 | struct window *active_window; 25 | } wm; 26 | 27 | /* 28 | * Exit gracefully. 29 | */ 30 | void quit(void *, uint32_t, uint32_t, uint32_t); 31 | 32 | #endif 33 | 34 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2015, Robin 'sulami' Schroer 2 | 3 | Permission to use, copy, modify, and/or distribute this software for any 4 | purpose with or without fee is hereby granted, provided that the above 5 | copyright notice and this permission notice appear in all copies. 6 | 7 | THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 8 | WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 9 | MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 10 | ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 11 | WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 12 | ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 13 | OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 14 | 15 | -------------------------------------------------------------------------------- /src/util.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | #include "wm.h" 7 | 8 | void 9 | debug(char *msg) 10 | { 11 | if (!wm.debug) 12 | return; 13 | 14 | fprintf(stdout, "DEBUG: %s.\n", msg); 15 | } 16 | 17 | void 18 | warn(char *warn) 19 | { 20 | fprintf(stderr, "WARNING: %s.\n", warn); 21 | } 22 | 23 | void 24 | die(char *err) 25 | { 26 | fprintf(stderr, "ERROR: %s.\n", err); 27 | exit(EXIT_FAILURE); 28 | } 29 | 30 | void 31 | spawn(void *data, uint32_t time, uint32_t value, uint32_t state) 32 | { 33 | char *command[] = { data, NULL }; 34 | 35 | if (state != WL_KEYBOARD_KEY_STATE_PRESSED) 36 | return; 37 | 38 | if (fork() == 0) { 39 | printf("starting %s\n", command[0]); 40 | execvp(command[0], command); 41 | exit(EXIT_SUCCESS); 42 | } 43 | } 44 | 45 | -------------------------------------------------------------------------------- /src/binding.h: -------------------------------------------------------------------------------- 1 | #ifndef BINDING_H 2 | #define BINDING_H 3 | 4 | /* 5 | * Register a new move bind with swc/Wayland. Takes the key and 6 | * coordinates. 7 | */ 8 | void add_move_bind(int, int, int); 9 | 10 | /* 11 | * Register a resize bind, takes the key and dimensions. 12 | */ 13 | void add_resize_bind(int, int, int); 14 | 15 | /* 16 | * Register a warp bind. Works just like adding move binds. 17 | */ 18 | void add_warp_bind(int, int, int); 19 | 20 | /* 21 | * Register a focus bind. Takes the key and the direction to switch in, 22 | * usually -1 or 1. 23 | */ 24 | void add_focus_bind(int, int); 25 | 26 | /* 27 | * Register a spawn bind. Takes the command to run. 28 | */ 29 | void add_spawn_bind(int, char *); 30 | 31 | /* 32 | * Register a config reload bind. 33 | */ 34 | void add_reload_bind(int); 35 | 36 | /* 37 | * Register a quit bind. 38 | */ 39 | void add_quit_bind(int); 40 | 41 | #endif 42 | 43 | -------------------------------------------------------------------------------- /src/wayland.h: -------------------------------------------------------------------------------- 1 | #ifndef WAYLAND_H 2 | #define WAYLAND_H 3 | 4 | #include 5 | 6 | #include "screen.h" 7 | #include "window.h" 8 | 9 | /* 10 | * Use swc to initialize a Wayland connection. 11 | */ 12 | struct wl_connection *wayland_init(); 13 | 14 | /* 15 | * Start the Wayland event loop after we have loaded the config and 16 | * added all the binds. 17 | */ 18 | void wayland_run(struct wl_connection *); 19 | 20 | /* 21 | * Terminate an existing Wayland connection by destroying the display. 22 | */ 23 | void wayland_exit(struct wl_connection *); 24 | 25 | /* 26 | * Swc manager to point to required callbacks. 27 | */ 28 | static const struct swc_manager manager = { 29 | &new_screen, 30 | &new_window, 31 | }; 32 | 33 | /* 34 | * Connection struct to keep all wayland-specific stuff in one place. 35 | */ 36 | struct wl_connection { 37 | struct wl_display *display; 38 | struct wl_event_loop *event_loop; 39 | }; 40 | 41 | #endif 42 | 43 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | PROJECT = wm 2 | 3 | DEBUG = 0 4 | 5 | PREFIX ?= /usr/local 6 | BINDIR ?= $(PREFIX)/bin 7 | 8 | CC = gcc 9 | CFLAGS += -std=c99 -pedantic -Wall -Wextra -Werror \ 10 | -Wimplicit-function-declaration -Wno-main -Wno-uninitialized \ 11 | -Wno-unused-parameter 12 | LDFLAGS += -lwayland-server -lswc -lX11 13 | 14 | SRCDIR = src 15 | SRC = $(SRCDIR)/$(PROJECT).c 16 | OBJ = binding.o config.o screen.o util.o wayland.o window.o 17 | 18 | ifeq ($(DEBUG),0) 19 | CFLAGS += -O2 20 | else 21 | CFLAGS += -g 22 | LDFLAGS += -g 23 | endif 24 | 25 | all: $(PROJECT) 26 | 27 | %.o: $(SRCDIR)/%.c $(SRCDIR)/%.h 28 | @echo \ CC $< 29 | @$(CC) $(CFLAGS) -c $< 30 | 31 | $(PROJECT): $(SRC) $(OBJ) $(SRCDIR)/$(PROJECT).h 32 | @echo \ CC $< 33 | @$(CC) $(SRC) $(OBJ) $(CFLAGS) $(LDFLAGS) -o $(PROJECT) 34 | 35 | clean: 36 | @echo \ RM $(PROJECT) 37 | @rm -f $(PROJECT) *.o 38 | 39 | install: all 40 | @echo \ IN $(DESTDIR)$(BINDIR)/$(PROJECT) 41 | @install -Dm755 $(PROJECT) $(DESTDIR)$(BINDIR)/$(PROJECT) 42 | 43 | uninstall: 44 | @echo \ RM $(DESTDIR)$(BINDIR)/$(PROJECT) 45 | @rm -f $(DESTDIR)$(BINDIR)/$(PROJECT) 46 | 47 | .PHONY: clean install uninstall 48 | 49 | -------------------------------------------------------------------------------- /defconfig: -------------------------------------------------------------------------------- 1 | # WM config 2 | # Lines starting with '#' and blank lines are ignored. 3 | 4 | # Set the borders and margins 5 | set margins 20 6 | set borderwidth 4 7 | # The border color setting supports hexadecimal colors with or without 8 | # '0x'-prefix, ARGB is supported in addition to RGB, but without 9 | # effect yet. 10 | set bordercolor abcdef 11 | 12 | # Move the active window relatively by 10 pixels. 13 | bind h move -10 0 14 | bind j move 0 10 15 | bind k move 0 -10 16 | bind l move 10 0 17 | 18 | # Resize the active window by 10 pixels. 19 | bind u resize -10 0 20 | bind i resize 0 10 21 | bind o resize 0 -10 22 | bind p resize 10 0 23 | 24 | # Warp the active window to the 9 preset positions on the screen. 25 | bind q warp -1 -1 26 | bind w warp 0 -1 27 | bind e warp 1 -1 28 | bind a warp -1 0 29 | bind s warp 0 0 30 | bind d warp 1 0 31 | bind z warp -1 1 32 | bind x warp 0 1 33 | bind c warp 1 1 34 | 35 | # Spawn a terminal. 36 | bind t spawn /home/sulami/build/st/st 37 | 38 | # Reload/-parse this config file. 39 | bind r reload 40 | 41 | # Quit. 42 | bind p quit 43 | 44 | # Cycle the focus in either direction. 45 | bind n focus +1 46 | bind m focus -1 47 | 48 | -------------------------------------------------------------------------------- /src/screen.h: -------------------------------------------------------------------------------- 1 | #ifndef SCREEN_H 2 | #define SCREEN_H 3 | 4 | #include "window.h" 5 | 6 | /* 7 | * Internal representation of a screen. 8 | */ 9 | struct screen { 10 | unsigned int num_windows; 11 | struct swc_screen *swc; 12 | struct wl_list windows; 13 | }; 14 | 15 | /* 16 | * Callback for adding new screens via swc. 17 | */ 18 | void new_screen(struct swc_screen *); 19 | 20 | /* 21 | * Handle a change in screen dimensions, e.g. docks. 22 | */ 23 | void screen_usable_geometry_changed(void *); 24 | 25 | /* 26 | * Change the active screen. 27 | */ 28 | void screen_entered(void *); 29 | 30 | /* 31 | * Add a new window to a screen, add it to the list, map it. 32 | */ 33 | void screen_add_window(struct screen *, struct window *); 34 | 35 | /* 36 | * Remove a window from a screen and the list, unmap it. 37 | */ 38 | void screen_remove_window(struct screen *, struct window *); 39 | 40 | /* 41 | * Used to bind the screen handling functions. 42 | */ 43 | static const struct swc_screen_handler screen_handler = { 44 | .usable_geometry_changed = &screen_usable_geometry_changed, 45 | .entered = &screen_entered, 46 | }; 47 | 48 | /* 49 | * Helper function to get the geometry of a screen. 50 | */ 51 | struct swc_rectangle *get_screen_geometry(struct screen *); 52 | 53 | #endif 54 | 55 | -------------------------------------------------------------------------------- /src/wayland.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include "util.h" 4 | #include "wayland.h" 5 | #include "window.h" 6 | 7 | struct wl_connection * 8 | wayland_init() 9 | { 10 | debug("Connecting to Wayland"); 11 | struct wl_connection *conn = malloc(sizeof(struct wl_connection)); 12 | if (!conn) 13 | die("Failed to allocate connection struct"); 14 | 15 | debug("Creating display"); 16 | conn->display = wl_display_create(); 17 | if (!conn->display) 18 | die("Failed to create a Wayland display"); 19 | 20 | debug("Adding socket"); 21 | if (wl_display_add_socket(conn->display, NULL) != 0) 22 | die("Failed to add a socket to the Wayland connection"); 23 | 24 | debug("Initializing swc"); 25 | if (!swc_initialize(conn->display, NULL, &manager)) 26 | die("Failed to initialize swc"); 27 | 28 | return conn; 29 | } 30 | 31 | void 32 | wayland_run(struct wl_connection *conn) 33 | { 34 | debug("Getting event loop"); 35 | conn->event_loop = wl_display_get_event_loop(conn->display); 36 | 37 | debug("Starting Wayland display"); 38 | wl_display_run(conn->display); 39 | } 40 | 41 | void 42 | wayland_exit(struct wl_connection *conn) 43 | { 44 | debug("Terminating Wayland display"); 45 | wl_display_terminate(conn->display); 46 | debug("Destroying Wayland display"); 47 | wl_display_destroy(conn->display); 48 | } 49 | 50 | -------------------------------------------------------------------------------- /src/wm.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | 7 | #include "config.h" 8 | #include "util.h" 9 | #include "wayland.h" 10 | #include "wm.h" 11 | 12 | int 13 | main(int argc, char *argv[]) 14 | { 15 | int opt; 16 | 17 | wm.debug = false; 18 | wm.margins = 0; 19 | wm.borderwidth = 1; 20 | wm.bordercolor = 0xffffffff; 21 | 22 | while((opt = getopt(argc, argv, "c:dhv")) != -1) { 23 | switch (opt) { 24 | case 'c': 25 | wm.config = optarg; 26 | break; 27 | case 'd': 28 | wm.debug = true; 29 | debug("Enabled debug output"); 30 | break; 31 | case 'h': 32 | puts("TBD"); 33 | exit(EXIT_SUCCESS); 34 | case 'v': 35 | printf("%s %s\n", argv[0], VERSION); 36 | exit(EXIT_SUCCESS); 37 | default: 38 | fprintf(stderr, "Usage: %s [-dhv] [-c config]\n", 39 | argv[0]); 40 | exit(EXIT_FAILURE); 41 | } 42 | } 43 | 44 | wm.wl_connection = wayland_init(); 45 | 46 | /* Load the default config if no custom one has been loaded */ 47 | if (!wm.config) { 48 | char *conf = getenv("XDG_CONFIG_HOME"); 49 | strcat(conf, "/.wmrc"); 50 | wm.config = conf; 51 | } 52 | 53 | load_config(wm.config); 54 | 55 | wayland_run(wm.wl_connection); 56 | 57 | wayland_exit(wm.wl_connection); 58 | 59 | return EXIT_SUCCESS; 60 | } 61 | 62 | void 63 | quit(void *data, uint32_t time, uint32_t value, uint32_t state) 64 | { 65 | exit(EXIT_SUCCESS); 66 | } 67 | 68 | -------------------------------------------------------------------------------- /src/screen.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include "util.h" 4 | #include "wayland.h" 5 | #include "wm.h" 6 | 7 | void 8 | new_screen(struct swc_screen *swc) 9 | { 10 | debug("Adding new screen"); 11 | struct screen *screen = malloc(sizeof(struct screen)); 12 | if (!screen) 13 | die("Failed to allocate screen"); 14 | 15 | screen->swc = swc; 16 | screen->num_windows = 0; 17 | wl_list_init(&screen->windows); 18 | swc_screen_set_handler(swc, &screen_handler, screen); 19 | wm.active_screen = screen; 20 | } 21 | 22 | void 23 | screen_usable_geometry_changed(void *data) 24 | { 25 | debug("Screen geometry changed"); 26 | struct screen *screen = data; 27 | 28 | if (screen) {} /* FIXME shut up the compiler */ 29 | /* 30 | * TODO 31 | * - perhaps rearrange windows 32 | */ 33 | } 34 | 35 | void 36 | screen_entered(void *data) 37 | { 38 | debug("Screen entered"); 39 | struct screen *screen = data; 40 | 41 | wm.active_screen = screen; 42 | } 43 | 44 | void 45 | screen_add_window(struct screen *screen, struct window *window) 46 | { 47 | debug("Window added to screen"); 48 | window->screen = screen; 49 | wl_list_insert(&screen->windows, &window->link); 50 | screen->num_windows += 1; 51 | swc_window_show(window->swc); 52 | } 53 | 54 | void 55 | screen_remove_window(struct screen *screen, struct window *window) 56 | { 57 | debug("Window removed from screen"); 58 | window->screen = NULL; 59 | wl_list_remove(&window->link); 60 | screen->num_windows -= 1; 61 | swc_window_hide(window->swc); 62 | } 63 | 64 | struct swc_rectangle * 65 | get_screen_geometry(struct screen *screen) 66 | { 67 | return &screen->swc->usable_geometry; 68 | } 69 | 70 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | WM 2 | == 3 | 4 | Still need a name. And a catchphrase. 5 | 6 | Features 7 | -------- 8 | 9 | None yet. 10 | 11 | Building 12 | -------- 13 | 14 | You will need the following: 15 | 16 | - Wayland 17 | - [swc][0] ~~(also on the [AUR][a0])~~ I added something crucial to swc in my 18 | own fork, so you will need mine unless my changes get merged into mainline 19 | swc. 20 | - [wld][1] (also on the [AUR][a1]) 21 | - libdrm 22 | - libevdev 23 | - libxkbcommon 24 | - libinput 25 | - libudev 26 | - xlib (for parsing keys) 27 | - libxcb (for XWayland) 28 | - xcb-util-wm (for XWayland) 29 | - pixman 30 | - Linux >= 3.12 31 | 32 | [0]: https://github.com/sulami/swc 33 | [1]: https://github.com/michaelforney/wld 34 | [a0]: https://aur.archlinux.org/packages/swc-git/ 35 | [a1]: https://aur.archlinux.org/packages/wld-git/ 36 | 37 | After building and installing swc, run 38 | 39 | ``` 40 | make clean && make 41 | ``` 42 | 43 | to build wm. 44 | 45 | Usage 46 | ----- 47 | 48 | None yet. 49 | 50 | Todo 51 | ---- 52 | 53 | - [x] Bind the swc stuff 54 | - [x] Produce a working Wayland display that can handle windows 55 | - [x] Parse keybinds and commands from a config file 56 | - [x] Window movement 57 | - [x] Window warping 58 | - [x] Spawning 59 | - [x] Focus changing 60 | - [x] Resizing 61 | - [ ] Grouping stuff 62 | - [ ] Monitor stuff 63 | - [x] Reloading settings 64 | - [x] Quitting 65 | - [ ] Custom modifiers instead of using Mod4 for everything 66 | - [ ] Configurable Mouse actions 67 | - [ ] Window groups 68 | - [ ] Monitors 69 | - [x] Settings 70 | - [x] Custom borders 71 | - [x] Custom margins 72 | - [ ] All sorts of bugfixing, NULL-checking, etc. 73 | - [ ] A manpage and other proper end-user documentation 74 | 75 | Contributing 76 | ------------ 77 | 78 | The codebase is following [OpenBSD's KNF][obsd]. 79 | 80 | [obsd]: http://www.openbsd.org/cgi-bin/man.cgi/OpenBSD-current/man9/style.9 81 | 82 | Acknowledgements 83 | ---------------- 84 | 85 | Obviously huge thanks to [Michael Forney][mf] for building swc. 86 | 87 | [mf]: https://github.com/michaelforney 88 | 89 | -------------------------------------------------------------------------------- /src/binding.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | #include "config.h" 6 | #include "window.h" 7 | #include "wm.h" 8 | #include "util.h" 9 | 10 | void 11 | add_move_bind(int key, int x, int y) 12 | { 13 | struct movement_set *ms = malloc(sizeof(struct movement_set)); 14 | if (!ms) { 15 | warn("Failed to allocate memory for move bind"); 16 | return; 17 | } 18 | 19 | ms->x = x; 20 | ms->y = y; 21 | 22 | swc_add_binding(SWC_BINDING_KEY, SWC_MOD_LOGO, key, &window_move, ms); 23 | } 24 | 25 | void 26 | add_resize_bind(int key, int w, int h) 27 | { 28 | struct resize_set *rs = malloc(sizeof(struct resize_set)); 29 | if (!rs) { 30 | warn("Failed to allocate memory for resize bind"); 31 | return; 32 | } 33 | 34 | rs->w = w; 35 | rs->h = h; 36 | 37 | swc_add_binding(SWC_BINDING_KEY, SWC_MOD_LOGO, key, &window_resize, rs); 38 | } 39 | 40 | void 41 | add_warp_bind(int key, int x, int y) 42 | { 43 | struct warp_set *ws = malloc(sizeof(struct warp_set)); 44 | if (!ws){ 45 | warn("Failed to allocate memory for warp bind"); 46 | return; 47 | } 48 | 49 | ws->x = x; 50 | ws->y = y; 51 | 52 | swc_add_binding(SWC_BINDING_KEY, SWC_MOD_LOGO, key, &window_warp, ws); 53 | } 54 | 55 | void 56 | add_spawn_bind(int key, char *cmd) 57 | { 58 | char *command = malloc(sizeof(char) * strlen(cmd) + 1); 59 | if (!command) { 60 | warn("Failed to allocate memory for spawn bind"); 61 | return; 62 | } 63 | 64 | strcpy(command, cmd); 65 | 66 | swc_add_binding(SWC_BINDING_KEY, SWC_MOD_LOGO, key, &spawn, command); 67 | } 68 | 69 | void 70 | add_focus_bind(int key, int direction) 71 | { 72 | int *dir = malloc(sizeof(int)); 73 | if (!dir) { 74 | warn("Failed to allocate memory for focus bind"); 75 | return; 76 | } 77 | 78 | swc_add_binding(SWC_BINDING_KEY, SWC_MOD_LOGO, key, 79 | &window_change_focus, dir); 80 | } 81 | 82 | void 83 | add_reload_bind(int key) 84 | { 85 | swc_add_binding(SWC_BINDING_KEY, SWC_MOD_LOGO, key, &reload_config, 86 | NULL); 87 | } 88 | 89 | void 90 | add_quit_bind(int key) 91 | { 92 | swc_add_binding(SWC_BINDING_KEY, SWC_MOD_LOGO, key, &quit, NULL); 93 | } 94 | 95 | -------------------------------------------------------------------------------- /src/window.h: -------------------------------------------------------------------------------- 1 | #ifndef WINDOW_H 2 | #define WINDOW_H 3 | 4 | /* 5 | * Internal representation of a window. 6 | */ 7 | struct window { 8 | struct swc_window *swc; 9 | struct screen *screen; 10 | struct wl_list link; 11 | }; 12 | 13 | /* 14 | * Callback for adding new windows via swc. 15 | */ 16 | void new_window(struct swc_window *); 17 | 18 | /* 19 | * Show the window passed if hidden. 20 | */ 21 | void show_window(struct window *); 22 | 23 | /* 24 | * Hide the window passed if shown. 25 | */ 26 | void hide_window(struct window *); 27 | 28 | /* 29 | * Set the window position. 30 | */ 31 | void set_window_position(struct window *, int32_t, int32_t); 32 | 33 | /* 34 | * Set the window size. 35 | */ 36 | void set_window_size(struct window *, uint32_t, uint32_t); 37 | 38 | /* 39 | * Get the geometry of a window. 40 | */ 41 | struct swc_rectangle *get_window_geometry(struct window *); 42 | 43 | /* 44 | * Set the geometry of a window. This combines setting position and 45 | * size. 46 | */ 47 | void set_window_geometry(struct window *, struct swc_rectangle *); 48 | 49 | /* 50 | * Set the color and width of the border of a window. 51 | */ 52 | void set_window_border(struct window *, uint32_t, int); 53 | 54 | /* 55 | * Change the focused window, handle borders. 56 | */ 57 | void focus_window(struct window *); 58 | 59 | /* 60 | * Focus a window and set it to fullscreen. 61 | */ 62 | void fullscreen_winodw(struct window *); 63 | 64 | /* 65 | * Callback for entering windows, essentially focus them. 66 | */ 67 | void window_entered(void *); 68 | 69 | /* 70 | * Begin interactive move of a window. 71 | */ 72 | void begin_move(struct window *); 73 | 74 | /* 75 | * End interactive move of a window. 76 | */ 77 | void end_move(struct window *); 78 | 79 | /* 80 | * Begin interactive resize of a window. 81 | */ 82 | void begin_resize(struct window *); 83 | 84 | /* 85 | * End interactive resize of a window. 86 | */ 87 | void end_resize(struct window *); 88 | 89 | /* 90 | * Callback for destroying windows. Trigger removal from screen, free 91 | * the window structure. 92 | */ 93 | void window_destroy(void *); 94 | 95 | /* 96 | * Hold window callbacks. 97 | */ 98 | static const struct swc_window_handler window_handler = { 99 | .destroy = &window_destroy, 100 | .entered = &window_entered, 101 | }; 102 | 103 | /* 104 | * A simple struct for window_move() to package both coordinates in one 105 | * pointer. 106 | */ 107 | struct movement_set { 108 | int x; 109 | int y; 110 | }; 111 | 112 | /* 113 | * Move the active window relativ to its current position. To be used 114 | * as a swc binding with a movement_set struct pointer as first 115 | * argument, hence the fancy arguments. 116 | */ 117 | void window_move(void *, uint32_t, uint32_t, uint32_t); 118 | 119 | /* 120 | * This struct holds the information passed to window_resize(). It is 121 | * essentially identical to movement_set, but will be kept seperately 122 | * in case something changes in the future. 123 | */ 124 | struct resize_set { 125 | int w; 126 | int h; 127 | }; 128 | 129 | /* 130 | * Resize the active window. Changes only the width/height, and not 131 | * the position, so the top-left edge should stay in place when using 132 | * this. 133 | */ 134 | void window_resize(void *, uint32_t, uint32_t, uint32_t); 135 | 136 | /* 137 | * A simple struct for window_warp() to package the position to warp to 138 | * in one pointer. The structure here is: 139 | * x/y < 0 : left/top 140 | * x/y == 0 : center 141 | * x/y > 0 : right/bottom 142 | */ 143 | struct warp_set { 144 | int x; 145 | int y; 146 | }; 147 | 148 | /* 149 | * Move the active window to a screen edge dictated by the warp_set 150 | * pointer that should be passed as the first argument. 151 | */ 152 | void window_warp(void *, uint32_t, uint32_t, uint32_t); 153 | 154 | /* 155 | * Change the window focus either forwards or backwards, depending on 156 | * the data passed. 157 | */ 158 | void window_change_focus(void *, uint32_t, uint32_t, uint32_t); 159 | 160 | #endif 161 | 162 | -------------------------------------------------------------------------------- /src/config.c: -------------------------------------------------------------------------------- 1 | #define _DEFAULT_SOURCE 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | 11 | #include "binding.h" 12 | #include "config.h" 13 | #include "wm.h" 14 | #include "util.h" 15 | 16 | void 17 | parse_config(FILE *file) 18 | { 19 | char line[256]; 20 | 21 | while(fgets(line, sizeof(line), file)) { 22 | char *cmd = strtok(line, " \t"); 23 | if (cmd[0] == '#' || cmd[0] == '\n') 24 | continue; 25 | 26 | if (!strcmp(cmd, "bind")) { 27 | char *key = strtok(NULL, " \t\n"); 28 | char *cmd = strtok(NULL, " \t\n"); 29 | if (!key || !cmd) { 30 | warn("Failed to register keybind"); 31 | continue; 32 | } 33 | 34 | int ks = XStringToKeysym(key); 35 | if (!ks) { 36 | warn("Unknown key in config"); 37 | continue; 38 | } 39 | 40 | if (!strcmp(cmd, "spawn")) { 41 | char *prog = strtok(NULL, " \t\n"); 42 | if (!prog) { 43 | warn("Failed to register spawn bind"); 44 | continue; 45 | } 46 | 47 | add_spawn_bind(ks, prog); 48 | } else if (!strcmp(cmd, "move")) { 49 | char *cx = strtok(NULL, " \t\n"); 50 | char *cy = strtok(NULL, " \t\n"); 51 | 52 | if (!cx || !cy) { 53 | warn("Failed to register move bind"); 54 | continue; 55 | } 56 | 57 | int x = strtol(cx, NULL, 10); 58 | int y = strtol(cy, NULL, 10); 59 | 60 | add_move_bind(ks, x, y); 61 | } else if (!strcmp(cmd, "resize")) { 62 | char *cw = strtok(NULL, " \t\n"); 63 | char *ch = strtok(NULL, " \t\n"); 64 | 65 | if (!cw || !ch) { 66 | warn("Failed to register resize bind"); 67 | continue; 68 | } 69 | 70 | int w = strtol(cw, NULL, 10); 71 | int h = strtol(ch, NULL, 10); 72 | 73 | add_resize_bind(ks, w, h); 74 | } else if (!strcmp(cmd, "warp")) { 75 | char *cx = strtok(NULL, " \t\n"); 76 | char *cy = strtok(NULL, " \t\n"); 77 | 78 | if (!cx || !cy) { 79 | warn("Failed to register spawn bind"); 80 | continue; 81 | } 82 | 83 | int x = strtol(cx, NULL, 10); 84 | int y = strtol(cy, NULL, 10); 85 | 86 | add_warp_bind(ks, x, y); 87 | } else if (!strcmp(cmd, "focus")) { 88 | char *cd = strtok(NULL, " \t\n"); 89 | 90 | if (!cd) { 91 | warn("Failed to register focus bind"); 92 | continue; 93 | } 94 | 95 | int d = strtol(cd, NULL, 10); 96 | add_focus_bind(ks, d); 97 | } else if (!strcmp(cmd, "reload")) { 98 | add_reload_bind(ks); 99 | } else if (!strcmp(cmd, "quit")) { 100 | add_quit_bind(ks); 101 | } else { 102 | warn("Unknown command in config"); 103 | continue; 104 | } 105 | 106 | debug("Binding registered"); 107 | } else if (!strcmp(cmd, "set")) { 108 | char *setting = strtok(NULL, " \t\n"); 109 | char *value = strtok(NULL, " \t\n"); 110 | if (!setting || !value) { 111 | warn("Failed to register setting"); 112 | continue; 113 | } 114 | 115 | if (!strcmp(setting, "borderwidth")) { 116 | int b = strtol(value, NULL, 10); 117 | if (!b) { 118 | warn("Failed to register border width"); 119 | continue; 120 | } 121 | wm.borderwidth = b; 122 | } else if (!strcmp(setting, "bordercolor")) { 123 | int c = strtol(value, NULL, 16); 124 | if (!c) { 125 | warn("Failed to register border color"); 126 | continue; 127 | } 128 | wm.bordercolor = c; 129 | } else if (!strcmp(setting, "margins")) { 130 | int m = strtol(value, NULL, 10); 131 | if (!m) { 132 | warn("Failed to register margins"); 133 | continue; 134 | } 135 | wm.margins = m; 136 | } else { 137 | warn("Unknown setting in config"); 138 | continue; 139 | } 140 | 141 | debug("Setting registered"); 142 | } else { 143 | warn("Found unknown command in config"); 144 | } 145 | } 146 | } 147 | 148 | void 149 | load_config(char *path) 150 | { 151 | FILE *file; 152 | 153 | debug("Loading config file"); 154 | 155 | file = fopen(path, "r"); 156 | if (!file) { 157 | warn("Could not load config file"); 158 | return; 159 | } 160 | 161 | parse_config(file); 162 | 163 | debug("Loaded config file"); 164 | 165 | fclose(file); 166 | } 167 | 168 | void 169 | reload_config(void *data, uint32_t time, uint32_t value, uint32_t state) 170 | { 171 | load_config(wm.config); 172 | } 173 | 174 | -------------------------------------------------------------------------------- /src/window.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | #include "screen.h" 5 | #include "util.h" 6 | #include "window.h" 7 | #include "wm.h" 8 | 9 | void 10 | new_window(struct swc_window *swc) 11 | { 12 | debug("Adding new window"); 13 | struct window *window = malloc(sizeof(struct window)); 14 | if (!window) 15 | die("Failed to allocate window"); 16 | 17 | window->swc = swc; 18 | window->screen = NULL; 19 | 20 | swc_window_set_handler(swc, &window_handler, window); 21 | swc_window_set_stacked(window->swc); /* TODO other modes? */ 22 | screen_add_window(wm.active_screen, window); 23 | focus_window(window); 24 | } 25 | 26 | void 27 | focus_window(struct window *window) 28 | { 29 | debug("Switching window focus"); 30 | if (window) { 31 | swc_window_focus(window->swc); 32 | set_window_border(window, wm.bordercolor, wm.borderwidth); 33 | } else { 34 | swc_window_focus(NULL); 35 | } 36 | 37 | wm.active_window = window; 38 | } 39 | 40 | void 41 | fullscreen_winodw(struct window *window) 42 | { 43 | debug("Fullscreening window"); 44 | focus_window(window); 45 | swc_window_set_fullscreen(window->swc, window->screen->swc); 46 | } 47 | 48 | void 49 | show_window(struct window *window) 50 | { 51 | debug("Showing window"); 52 | swc_window_show(window->swc); 53 | } 54 | 55 | void 56 | hide_window(struct window *window) 57 | { 58 | debug("Hiding window"); 59 | swc_window_hide(window->swc); 60 | } 61 | 62 | void 63 | set_window_position(struct window *window, int32_t x, int32_t y) 64 | { 65 | debug("Setting window position"); 66 | swc_window_set_position(window->swc, x, y); 67 | } 68 | 69 | void 70 | set_window_size(struct window *window, uint32_t width, uint32_t height) 71 | { 72 | debug("Setting window size"); 73 | swc_window_set_size(window->swc, width, height); 74 | } 75 | 76 | struct swc_rectangle * 77 | get_window_geometry(struct window *window) 78 | { 79 | debug("Getting window geometry"); 80 | return swc_window_get_geometry(window->swc); 81 | } 82 | 83 | void 84 | set_window_geometry(struct window *window, struct swc_rectangle *geometry) 85 | { 86 | debug("Setting window geometry"); 87 | swc_window_set_geometry(window->swc, geometry); 88 | } 89 | 90 | void 91 | set_window_border(struct window *window, uint32_t color, int width) 92 | { 93 | debug("Setting window border"); 94 | swc_window_set_border(window->swc, color, width); 95 | } 96 | 97 | void 98 | window_entered(void *data) 99 | { 100 | debug("Window entered"); 101 | struct window *window = data; 102 | 103 | focus_window(window); 104 | } 105 | 106 | void 107 | window_destroy(void *data) 108 | { 109 | debug("Window destroyed"); 110 | struct window *window = data; 111 | 112 | /* TODO change focus? */ 113 | 114 | screen_remove_window(window->screen, window); 115 | free(window); 116 | } 117 | 118 | void 119 | begin_move(struct window *window) 120 | { 121 | debug("Beginning interactive window move"); 122 | swc_window_begin_move(window->swc); 123 | } 124 | 125 | void 126 | end_move(struct window *window) 127 | { 128 | debug("Ending interactive window move"); 129 | swc_window_end_move(window->swc); 130 | } 131 | 132 | void 133 | begin_resize(struct window *window) 134 | { 135 | debug("Beginning interactive window resize"); 136 | swc_window_begin_resize(window->swc, SWC_WINDOW_EDGE_AUTO); 137 | } 138 | 139 | void 140 | end_resize(struct window *window) 141 | { 142 | debug("Ending interactive window resize"); 143 | swc_window_end_resize(window->swc); 144 | } 145 | 146 | void 147 | window_move(void *data, uint32_t time, uint32_t value, uint32_t state) 148 | { 149 | debug("Moving window"); 150 | 151 | struct movement_set *ms = (struct movement_set *)data; 152 | struct window *win = wm.active_window; 153 | struct swc_rectangle *geo = get_window_geometry(win); 154 | 155 | set_window_position(win, geo->x + ms->x, geo->y + ms->y); 156 | } 157 | 158 | void 159 | window_resize(void *data, uint32_t time, uint32_t value, uint32_t state) 160 | { 161 | debug("Resizing window"); 162 | 163 | struct resize_set *rs = (struct resize_set *)data; 164 | struct window *win = wm.active_window; 165 | struct swc_rectangle *geo = get_window_geometry(win); 166 | 167 | set_window_size(win, geo->width + rs->w, geo->height + rs->h); 168 | } 169 | 170 | void 171 | window_warp(void *data, uint32_t time, uint32_t value, uint32_t state) 172 | { 173 | debug("Warping window"); 174 | 175 | int x, y; 176 | 177 | struct warp_set *ws = (struct warp_set *)data; 178 | struct window *win = wm.active_window; 179 | struct swc_rectangle *wingeo = get_window_geometry(win); 180 | struct screen *scr = win->screen; 181 | struct swc_rectangle *scrgeo = get_screen_geometry(scr); 182 | 183 | if (ws->x < 0) 184 | x = wm.margins; 185 | else if (ws->x > 0) 186 | x = scrgeo->width - wingeo->width - wm.margins; 187 | else 188 | x = scrgeo->width / 2 - wingeo->width / 2; 189 | 190 | if (ws->y < 0) 191 | y = wm.margins; 192 | else if (ws->y > 0) 193 | y = scrgeo->height - wingeo->height - wm.margins; 194 | else 195 | y = scrgeo->height / 2 - wingeo->height / 2; 196 | 197 | set_window_position(win, x, y); 198 | } 199 | 200 | void 201 | window_change_focus(void *data, uint32_t time, uint32_t value, uint32_t state) 202 | { 203 | debug("Changing focus"); 204 | 205 | struct window *win = wm.active_window; 206 | 207 | if (*(int *)data > 0) { 208 | win = wl_container_of(win->link.next, win, link); 209 | } else { 210 | win = wl_container_of(win->link.prev, win, link); 211 | } 212 | 213 | focus_window(win); 214 | } 215 | 216 | --------------------------------------------------------------------------------