diff --git a/Makefile b/Makefile index 2a543b0..19107c5 100644 --- a/Makefile +++ b/Makefile @@ -2,10 +2,10 @@ all: config.h ntwm CC=gcc -CFLAGS=-Iinclude -Iconfig +CFLAGS=-Iinclude -Iconfig -Wno-pointer-to-int-cast LIBS=-lX11 -lXrandr -FLAGS=-Os -pipe -s -ansi -pedantic +FLAGS=-Os -s -pipe -ansi -pedantic DEBUGFLAGS=-Og -Wall -pipe -g -ansi -pedantic SOURCES=ntwm.c diff --git a/README.md b/README.md index 984f3e5..997aa05 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ ![ntwm](https://github.com/Cubified/ntwm/blob/master/images/ntwm.png) -# ntwm v1.2.5 +# ntwm v1.2.6 A tiny, frameless, keyboard-driven tiling window manager with multimonitor support. @@ -18,8 +18,8 @@ All of the following window managers have multimonitor support. | ntwm | 19kb | |------|-------| -| dwm | 33kb | | 2bwm | 36kb | +| dwm | 46kb | | i3 | 343kb | *(Note: these values are approximate and may be subject to change)* @@ -146,10 +146,33 @@ By default, ntwm supports the following tiling modes (with more coming): To edit the order in which these modes are selected, adjust the `modes` variable in `config.h`. +However, if you'd like to shrink the size of the output binary, you may remove support for additional modes by removing the corresponding `ENABLE_*` preprocessor definition. + +### Logging + +To further decrease filesize, ntwm supports compilation without `stdio.h`, resulting in a save of approximately 4kb. To enable this, define `LOGGING_NO_STDIO` in `config.h`. + +### Memory Usage + +With v1.2.6, ntwm now supports user-configurable memory usage through the `MAX_MONITORS`, `MAX_WINDOWS`, and `MAX_BARS` directives - ensuring ntwm will use exactly the amount of memory required to hold the given amounts of each. + +Tune these to your system, but ensure they are not overly constraining - exceeding them will invoke unwanted behavior. + +### Towards an Even Smaller Binary + +In no particular order: +- Run [sstrip](http://www.muppetlabs.com/~breadbox/software/elfkickers.html) (19kb -> 17kb) +- Compile with [musl](https://www.musl-libc.org) or [dietlibc](https://www.fefe.de/dietlibc) (requires Xlib and any other userland X applications to be compiled from source) +- Compile a 32-bit binary (requires 32-bit Xlib) + --- ## Changelog +### v1.2.6 +- Replace linked list implementation with `libspool.h`, increasing filesize but treating memory more responsibly and executing more quickly +- Allow for the disabling of certain tiling modes, decreasing filesize + ### v1.2.5 - Add support for two types of client message (`NET_WM_STATE_ABOVE` and `NET_WM_STATE_FULLSCREEN`) with more to come - Add global "above" window which supersedes per-monitor fullscreen @@ -158,6 +181,7 @@ To edit the order in which these modes are selected, adjust the `modes` variable - Move all Xlib utility functions into `x.h` - Move files into appropriate folders, cleaning up the appearance of the repository - Add `above_enabled` check to avoid X error +- Add support for logging without `stdio.h` (error messages are somewhat less specific, but still useful) ### v1.2.0 - Add support for pre-mapped windows being tiled, thereby greatly improving the `reset` command @@ -225,8 +249,8 @@ To edit the order in which these modes are selected, adjust the `modes` variable ## To-Do -- Investigate and resolve any remaining memory leaks -- Fix flickering upon dragging chromium tabs +- Clean up tiling functionality +- Fix support for dual bars - Fix incongruency between client-toggled and window manager-wide fullscreen ## What Will (Likely) Never be Implemented diff --git a/config/config.def.h b/config/config.def.h index 8f262ef..3aacde9 100644 --- a/config/config.def.h +++ b/config/config.def.h @@ -2,15 +2,19 @@ * config.h: ntwm configuration */ -#define VER "1.2.5" +#define VER "1.2.6" #define GAPS 50 #define STACK_RATIO 0.3 #define DIALOG_RATIO 0.7 #define MULTIHEAD /* multimonitor support */ -#define LOGGING /* startup/shutdown logging */ +/*#define LOGGING_NO_STDIO*/ /* avoid including stdio.h for error/info logging (decreases filesize) */ #define MASK Mod1Mask #define SHIFT ShiftMask +#define MAX_MONITORS 2 /* memory fine-tuning options - ntwm will use no more memory than is specified here */ +#define MAX_WINDOWS 16 +#define MAX_BARS 2 + #define TERMCMD "xterm" char *autostartcmd = "true"; @@ -53,6 +57,11 @@ const key keys[] = { typedef void (*func)(); +#define ENABLE_GRID +#define ENABLE_DUALSTACK +#define ENABLE_FIBONACCI +#define ENABLE_BOTTOMSTACK + static void tile_grid(); static void tile_dualstack(); static void tile_fibonacci(); diff --git a/include/events.h b/include/events.h index 63fe8d1..00cde6c 100644 --- a/include/events.h +++ b/include/events.h @@ -26,11 +26,10 @@ void map_request(XEvent *e){ if((wintype == window_normal || wintype == window_utility) && !x_is_child(ev->window)){ - node *list = find_monitor()->windows; + pool *list = find_monitor()->windows; - if(list_find(list, NULL, ev->window) == NULL){ - node *n = list_push(list); - n->data_noptr = ev->window; + if(pool_find((void*)ev->window, list) == -1){ + pool_push((void*)ev->window, list); tile(); @@ -95,14 +94,14 @@ void configure_request(XEvent *e){ */ void unmap_notify(XEvent *e){ XUnmapEvent *ev = &e->xunmap; - node *list = find_monitor()->windows; - node *elem = list_find(list,NULL,ev->window); + pool *list = find_monitor()->windows; + int ind = pool_find((void*)ev->window, list); last_call = "unmap"; if(focused == ev->window){ - if(list->size > 1){ - cycle_windows(list,focused,0); + if((unsigned int)~list->avail > 0){ + cycle_windows(list, focused, 0); } else { focused = 0; } @@ -113,16 +112,16 @@ void unmap_notify(XEvent *e){ above = 0; } - if(elem != NULL){ - list_pop(list,elem); - tile(); + if(ind > -1){ + pool_pop(ind, list); } else { - node *bar = list_find(bars,NULL,ev->window); - if(bar != NULL){ - multihead_delbar(bar->data_noptr); - tile(); + int p; + if((p = pool_find((void*)ev->window, bars)) > -1){ + multihead_delbar(p); } } + + tile(); } /* @@ -157,10 +156,10 @@ void key_press(XEvent *e){ toggle_fullscreen(current_monitor, focused); break; case cmd_next: - cycle_monitors(focused, 1); + cycle_monitors(focused, DIR_RIGHT); break; case cmd_prev: - cycle_monitors(focused, 0); + cycle_monitors(focused, DIR_LEFT); break; case cmd_mode: next_mode(); @@ -175,7 +174,11 @@ void key_press(XEvent *e){ reset(map_request); break; default: +#ifdef LOGGING_NO_STDIO + error("Unrecognized command in config."); +#else error("Unrecognized command \"%s\" in config.", keys[i].func); +#endif break; } } diff --git a/include/libspool.h b/include/libspool.h new file mode 100644 index 0000000..dd8612e --- /dev/null +++ b/include/libspool.h @@ -0,0 +1,235 @@ +/* + * libspool.h: a small memory pool implementation + * + * Credits to https://graphics.stanford.edu/~seander/bithacks.html + * for clever bit manipulation tricks + */ + +#ifndef __LIBSPOOL_H +#define __LIBSPOOL_H + +#include + +#define flip_bit(n, b) (n ^= pow2(b)) + +#define pool_get(i, p) (p->pool[i]) +#define pool_astype(i, t) (*(t*)i) +#define pool_first(p) lsb(p->avail^0xFFFF) +#define pool_foreach(p) int ind;for(ind=pool_first(p);p->avail<0xFFFF&&indsize;ind=next_unset_bit(p->avail,ind)) +#define pool_foreach_nodecl(p) for(ind=pool_first(p);p->avail<0xFFFF&&indsize;ind=next_unset_bit(p->avail,ind)) /* If ANSI/C99/C11 compliance is necessary */ + +#define DIR_LEFT 0 +#define DIR_RIGHT 1 + +typedef struct pool { + int ind; /* Index of first available slot (least significant bit) */ + int size; /* Maximum size of the memory pool */ + int avail; /* Integer holding all available slots */ + void **pool; /* Pool itself */ +} pool; + +static int pow2(int n); +static int lsb(int n); +static int bits_set(int n); +static int set_all(int size); +static int next_unset_bit(int n, int start); + +static pool *pool_init(); +static void pool_push(void *data, pool *p); +/* pool_pop(int ind, pool *p); - Defined as macro*/ +static int pool_adj(int ind, int dir, pool *p); +static int pool_find(void *data, pool *p); +static int pool_check(int ind, pool *p); +static int pool_count(pool *p); +static void pool_free(pool *p); + +/* + * Finds powers of 2 by lookup table + */ +int pow2(int n){ + int powers[] = { 1, 2, 4, 8, 16, 32, 64, 128, 256, 512, 1024, 2048, 4096, 8192, 16384, 32768, 65536 }; + + return powers[n]; +} + +/* + * Finds the least significant bit in + * an integer + */ +int lsb(int n){ + float f; + + if(n == 0){ + return -1; + } + + f = (float)(n & -n); + return (*(int *)&f >> 23) - 0x7f; +} + +/* + * Returns the number of bits set + * to one in an integer by use of + * lookup table + */ +int bits_set(int n){ + static const unsigned char BitsSetTable256[256] = { +# define B2(n) n, n+1, n+1, n+2 +# define B4(n) B2(n), B2(n+1), B2(n+1), B2(n+2) +# define B6(n) B4(n), B4(n+1), B4(n+1), B4(n+2) + B6(0), B6(1), B6(1), B6(2) + }; + + return (BitsSetTable256[n & 0xff] + + BitsSetTable256[(n >> 8) & 0xff] + + BitsSetTable256[(n >> 16) & 0xff] + + BitsSetTable256[n >> 24]); +} + +/* + * Returns an integer with all bits + * to the right of a given value + * set to 1 + */ +int set_all(int size){ + return (1 << size) - 1; +} + +/* + * Returns the position of the next bit + * equal to zero moving right-to-left + * from a given starting point + */ +int next_unset_bit(int n, int start){ + unsigned int flip = ~n; + flip >>= start+1; + return lsb(flip)+start+1; +} + +/***/ + +/* + * Initializes a new memory pool by allocating + * a block of preset size, removing continued + * calls to malloc() which slow execution + */ +pool *pool_init(int size){ + pool *p = malloc(sizeof(pool)); + p->ind = 0; + p->size = size; + p->avail = set_all(size); + p->pool = malloc(sizeof(void*)*size); + + return p; +} + +/* + * Pushes a given pointer to the pool and + * moves the index of the nearest + * available block (overwriting + * old entries if enabled) + */ +void pool_push(void *data, pool *p){ + if(p->ind == -1){ + error("Out of memory."); + return; + } + + flip_bit(p->avail, p->ind); + p->pool[p->ind] = data; + p->ind = lsb(p->avail); +} + +/* + * Frees a pool item simply by + * flagging it for overwriting + */ +#define pool_pop(i, p) flip_bit(p->avail, i);p->ind=i + +/* + * Returns the index of the next + * filled slot in the given + * direction (left/right), + * wrapping if necessary + */ +int pool_adj(int pos, int dir, pool *p){ + int out = pos, + cnt = 0, + hit = 0; + + flip_bit(p->avail, pos); + + if(dir == DIR_LEFT){ + while(cnt < p->size){ + if(pool_check(out, p) == 0){ + hit = 1; + break; + } + out--; + cnt++; + + if(out < 0){ + out = p->size-1; + } + } + } else { + while(cnt < p->size){ + if(pool_check(out, p) == 0){ + hit = 1; + break; + } + out++; + cnt++; + + if(out >= p->size){ + out = 0; + } + } + } + + flip_bit(p->avail, pos); + + return (hit ? out : -1); +} + +/* + * Finds an item in the pool + * based on its data, + * returning -1 if + * not found + */ +int pool_find(void *data, pool *p){ + pool_foreach(p){ + if(pool_get(ind, p) == data){ + return ind; + } + } + return -1; +} + +/* + * Returns 1 if a given slot is + * available + */ +int pool_check(int ind, pool *p){ + return (p->avail & (1<size - bits_set(p->avail); +} + +/* + * Frees a pool and its associated + * arrays + */ +void pool_free(pool *p){ + free(p->pool); + free(p); +} + +#endif diff --git a/include/list.h b/include/list.h deleted file mode 100644 index ebf0cb8..0000000 --- a/include/list.h +++ /dev/null @@ -1,181 +0,0 @@ -/* - * list.h: linked list implementation - */ - -#ifndef __LIST_H -#define __LIST_H - -typedef struct node { - void *data; - unsigned int data_noptr; - int size; - struct node *next; - struct node *prev; - struct node *end; -} node; - -#define list_foreach(root) node *itr;for(itr=root;itr!=NULL;itr=itr->next) -#define list_foreach_noroot(root) node *itr;for(itr=root->next;itr!=NULL;itr=itr->next) -/* - * (For ANSI compliance) - */ -#define list_foreach_nodecl(root) for(itr=root;itr!=NULL;itr=itr->next) -#define list_foreach_noroot_nodecl(root) for(itr=root->next;itr!=NULL;itr=itr->next) - -#define list_foreach_reverse(root) node *itr;for(itr=root->end;itr!=NULL;itr=itr->prev) -#define list_foreach_reverse_noroot(root) node *itr;for(itr=root->end;itr!=root;itr=itr->prev) - -static node *node_create(); - -static node *list_init(); -static node *list_push(node *root); -static node *list_find(node *root, void *data, unsigned int data_noptr); -static node *list_get(node *root, int index); - -static void list_pop(node *root, node *elem); -static void list_free(node *root); - -static int list_sizeof(node *root); - -/* - * Creates a new node (not to be used - * in the majority of cases) - */ -node *node_create(){ - node *elem = malloc(sizeof(node)); - - return elem; -} - -/* - * Creates (and returns) a new root node - */ -node *list_init(){ - node *root = node_create(); - root->data = NULL; - root->data_noptr = 0; - root->size = 0; - root->next = NULL; - root->prev = NULL; - root->end = NULL; - - return root; -} - -/* - * Creates (and returns) a new node which - * has been inserted after the root node - */ -node *list_push(node *root){ - node *elem = node_create(); - - elem->size = 0; - elem->next = NULL; - elem->prev = root->end; - elem->end = NULL; - - if(root->end != NULL){ - root->end->next = elem; - } - root->end = elem; - - if(root->next == NULL){ - root->next = elem; - elem->prev = root; - } - - root->size++; - - return elem; -} - -/* - * Finds a node based on given data, - * returns NULL if not found - */ -node *list_find(node *root, void *data, unsigned int data_noptr){ - int found = 0; - - list_foreach(root){ - if((data != NULL && - itr->data == data) || - (data_noptr != 0 && - itr->data_noptr == data_noptr) - ){ - found = 1; - break; - } - } - if(found){ - return itr; - } - return NULL; -} - -/* - * Gets a node at a specified position - * in the list (root is at index 0) - */ -node *list_get(node *root, int index){ - int cnt = 0; - list_foreach(root){ - if(cnt == index){ - break; - } - cnt++; - } - return itr; -} - -/* - * Deletes a node from the list (does - * nothing if not found) - */ -void list_pop(node *root, node *elem){ - elem->prev->next = elem->next; - - if(elem->next != NULL){ - elem->next->prev = elem->prev; - } - - if(root->end == elem){ - if(elem->next == NULL){ - root->end = elem->prev; - } else { - root->end = elem->next; - } - } - - free(elem); - - root->size--; -} - -/* - * Frees an entire list - */ -void list_free(node *root){ - /* - list_foreach_noroot(root){ - if(itr->prev != NULL){ - free(itr->prev); - } - } - free(itr);*/ - - list_foreach_reverse(root){ - if(itr->next != NULL){ - free(itr->next); - } - } -} - -/* - * Returns the number of nodes in - * a list (not including root) - */ -int list_sizeof(node *root){ - return root->size; -} - -#endif diff --git a/include/logging.h b/include/logging.h index e764109..57382dc 100644 --- a/include/logging.h +++ b/include/logging.h @@ -5,11 +5,13 @@ #ifndef __LOGGING_H #define __LOGGING_H -#ifdef LOGGING +#ifndef LOGGING_NO_STDIO #include #include #endif +#define STDOUT 1 + #define ANSI_COLOR_RED "\x1b[31m" #define ANSI_COLOR_GREEN "\x1b[32m" #define ANSI_COLOR_YELLOW "\x1b[33m" @@ -18,12 +20,31 @@ #define ANSI_COLOR_CYAN "\x1b[36m" #define ANSI_COLOR_RESET "\x1b[0m" -static void info(const char *str, ...); -static void error(const char *str, ...); -static void debug(const char *str, ...); +static int len(char *str); +static void print(char *str); +static void info(char *str, ...); +static void error(char *str, ...); +static void debug(char *str, ...); + +int len(char *str){ + int o; + char *c; + for(c=str,o=0;*c;c++,o++){} + return o; +} + +void print(char *str){ + write(STDOUT, str, len(str)); +} + +/***/ -void info(const char *str, ...){ -#ifdef LOGGING +void info(char *str, ...){ +#ifdef LOGGING_NO_STDIO + print(ANSI_COLOR_CYAN "=> "); + print(str); + print(ANSI_COLOR_RESET "\n"); +#else va_list args; va_start(args,str); @@ -34,8 +55,12 @@ void info(const char *str, ...){ #endif } -void error(const char *str, ...){ -#ifdef LOGGING +void error(char *str, ...){ +#ifdef LOGGING_NO_STDIO + print(ANSI_COLOR_RED "==> Error: "); + print(str); + print(ANSI_COLOR_RESET "\n"); +#else va_list args; va_start(args,str); @@ -46,8 +71,12 @@ void error(const char *str, ...){ #endif } -void debug(const char *str, ...){ -#ifdef LOGGING +void debug(char *str, ...){ +#ifdef LOGGING_NO_STDIO + print(ANSI_COLOR_GREEN "=> Debug: "); + print(str); + print(ANSI_COLOR_RESET "\n"); +#else va_list args; va_start(args,str); diff --git a/include/modes.h b/include/modes.h index bf6d779..f99b5fd 100644 --- a/include/modes.h +++ b/include/modes.h @@ -36,6 +36,8 @@ * example of this). */ +#ifdef ENABLE_GRID + /* * ___________ * | M | 2 | @@ -50,12 +52,12 @@ void tile_grid(monitor *m){ col_number, row_number, x, y, w, h, - gaps; + gaps, + ind; Window win; - node *list = m->windows; - node *itr; - - clients_count = list_sizeof(list); + pool *list = m->windows; + + clients_count = pool_count(list); if(clients_count == 0){ return; } @@ -76,7 +78,7 @@ void tile_grid(monitor *m){ row_number = 0; i = 0; - list_foreach_noroot_nodecl(list){ + pool_foreach_nodecl(list){ if(i / rows + 1 > cols - clients_count % cols){ rows = clients_count / cols + 1; } @@ -86,7 +88,7 @@ void tile_grid(monitor *m){ w = col_width - gaps; h = (col_height / rows) - gaps; - win = itr->data_noptr; + win = (Window)pool_get(ind, list); if(m->fullscreen_enabled && m->fullscreen == win && @@ -96,7 +98,7 @@ void tile_grid(monitor *m){ w = m->width; h = m->height; - XRaiseWindow(dpy,win); + XRaiseWindow(dpy, win); } x_move_resize( @@ -113,6 +115,10 @@ void tile_grid(monitor *m){ } } +#endif + +#ifdef ENABLE_DUALSTACK + /* * ___________ * | 2| | 1| @@ -121,8 +127,8 @@ void tile_grid(monitor *m){ * |__|_____|__| */ void tile_dualstack(monitor *m){ - node *list = m->windows; - int len = list_sizeof(list); + pool *list = m->windows; + int len = pool_count(list); int gaps = (m->gaps_enabled ? GAPS : 0); int cols = (len >= 3 ? 3 : len); @@ -161,14 +167,14 @@ void tile_dualstack(monitor *m){ Window win; - node *itr; + int ind; if(len == 0){ return; } - list_foreach_noroot_nodecl(list){ - win = itr->data_noptr; + pool_foreach_nodecl(list){ + win = (Window)pool_get(ind, list); switch(current_col){ case 0: @@ -189,7 +195,7 @@ void tile_dualstack(monitor *m){ break; } break; - case 1: + case 1: /* This is really horrible */ x = m->x + (m->width - subcol_width); y = m->y + (subcol_height_right * (current_row_right)) + (current_row_right > 0 ? 0 : gaps); width = subcol_width - gaps; @@ -213,7 +219,7 @@ void tile_dualstack(monitor *m){ width = m->width; height = m->height; - XRaiseWindow(dpy,win); + XRaiseWindow(dpy, win); } x_move_resize( @@ -230,6 +236,10 @@ void tile_dualstack(monitor *m){ } } +#endif + +#ifdef ENABLE_FIBONACCI + /* * ___________ * | | 1 | @@ -241,13 +251,16 @@ void tile_dualstack(monitor *m){ void tile_fibonacci(monitor *m){ int gaps = (m->gaps_enabled ? GAPS : 0); - int ind = 0, - x = gaps, + int x = gaps, y = gaps, w = m->width - 2 * gaps, h = m->height - 2 * gaps; - list_foreach_noroot(m->windows){ + Window win; + + pool_foreach(m->windows){ + win = (Window)pool_get(ind, m->windows); + if(ind % 2){ h = h / 2 - gaps / 2; } else { @@ -263,26 +276,28 @@ void tile_fibonacci(monitor *m){ } if(m->fullscreen_enabled && - m->fullscreen == itr->data_noptr && + m->fullscreen == win && !above_enabled){ x = 0; y = 0; w = m->width; h = m->height; - XRaiseWindow(dpy,itr->data_noptr); + XRaiseWindow(dpy, win); } x_move_resize( - itr->data_noptr, + win, x + m->x, y + m->y, w, h ); - - ind++; } } +#endif + +#ifdef TILE_BOTTOMSTACK + /* * ----------- * | M | @@ -292,16 +307,22 @@ void tile_fibonacci(monitor *m){ * |___________| */ void tile_bottomstack(monitor *m){ + pool *list = m->windows; + int x, y, w, h; int gaps = (m->gaps_enabled ? GAPS : 0), indx = 0; - int subcol_height = (m->windows->size > 1 ? m->height * STACK_RATIO : 0); - int subcol_width = (m->windows->size > 1 ? m->width / (m->windows->size - 1) : 0); + int subcol_height = (pool_count(list) > 0 ? m->height * STACK_RATIO : 0); + int subcol_width = (pool_count(list) > 0 ? m->width / (pool_count(list) - 1) : 0); + + Window win; + + pool_foreach(list){ + win = (Window)pool_get(ind, list); - list_foreach_noroot(m->windows){ if(indx == 0){ x = m->x + gaps; y = m->y + gaps; @@ -315,18 +336,18 @@ void tile_bottomstack(monitor *m){ } if(m->fullscreen_enabled && - m->fullscreen == itr->data_noptr && + m->fullscreen == win && !above_enabled){ x = m->x; y = m->y; w = m->width; h = m->height; - XRaiseWindow(dpy,itr->data_noptr); + XRaiseWindow(dpy, win); } x_move_resize( - itr->data_noptr, + win, x, y, w, h ); @@ -336,3 +357,5 @@ void tile_bottomstack(monitor *m){ } #endif + +#endif diff --git a/include/multihead.h b/include/multihead.h index 0a5dbad..586665d 100644 --- a/include/multihead.h +++ b/include/multihead.h @@ -6,7 +6,7 @@ #define __MULTIHEAD_H typedef struct monitor { - node *windows; + pool *windows; int width; int height; int x; @@ -23,7 +23,7 @@ static void multihead_resize(); static monitor *find_monitor(); static void multihead_addbar(Window win); -static void multihead_delbar(Window win); +static void multihead_delbar(int pos); static int multihead_isbar(Window win); static monitor *monitor_atpos(int x, int y); @@ -37,16 +37,15 @@ void multihead_setup(){ int i; XRRScreenResources *screen_resources = XRRGetScreenResources(dpy, root); - monitors = list_init(); + monitors = pool_init(MAX_MONITORS); for(i=0;incrtc;i++){ XRRCrtcInfo *crtc_info = XRRGetCrtcInfo(dpy, screen_resources, screen_resources->crtcs[i]); if(crtc_info->width > 0){ monitor *mon = malloc(sizeof(monitor)); - node *n = list_push(monitors); - mon->windows = list_init(); + mon->windows = pool_init(MAX_WINDOWS); mon->width = crtc_info->width; mon->height = crtc_info->height; mon->x = crtc_info->x; @@ -56,7 +55,7 @@ void multihead_setup(){ mon->fullscreen_enabled = 0; mon->fullscreen = 0; - n->data = mon; + pool_push(mon, monitors); } XRRFreeCrtcInfo(crtc_info); @@ -80,16 +79,17 @@ void multihead_setup(){ * monitor struct */ void multihead_free(){ - list_foreach(monitors){ - monitor *m = (monitor*)itr->data; - if(m != NULL && m->windows != NULL){ - list_free(m->windows); - } - } if(monitors != NULL && bars != NULL){ - list_free(monitors); - list_free(bars); + pool_foreach(monitors){ + monitor *m = pool_get(ind, monitors); + if(m != NULL && m->windows != NULL){ + pool_free(m->windows); + } + free(m); + } + pool_free(monitors); + pool_free(bars); } } @@ -103,8 +103,8 @@ void multihead_resize(){ XRRCrtcInfo *crtc_info; monitor *m; int i = 0; - list_foreach_noroot(monitors){ - m = itr->data; + pool_foreach(monitors){ + m = pool_get(ind, monitors); crtc_info = XRRGetCrtcInfo(dpy, screen_resources, screen_resources->crtcs[i]); m->width = crtc_info->width; m->height = crtc_info->height; @@ -151,9 +151,11 @@ monitor *find_monitor(){ * the display in X */ void multihead_setup(){ - monitors = list_init(); - monitor *monitor = malloc(sizeof(monitor)); - monitor->windows = list_init(); + monitor *monitor; + + monitors = pool_init(1); + monitor = malloc(sizeof(monitor)); + monitor->windows = pool_init(MAX_WINDOWS); monitor->width = XWidthOfScreen(screen); monitor->height = XHeightOfScreen(screen); monitor->x = 0; @@ -164,8 +166,7 @@ void multihead_setup(){ monitor->fullscreen = 0; rr_event_base = -1; rr_error_base = -1; - node *n = list_push(monitors); - n->data = monitor; + pool_push(monitor, monitors); } /* @@ -173,14 +174,12 @@ void multihead_setup(){ * the windows it holds */ void multihead_free(){ - list_foreach_noroot(monitors){ - monitor *m = (monitor*)itr->data; - if(m != NULL && m->windows != NULL){ - list_free(m->windows); - } + if(monitors != NULL && + bars != NULL){ + pool_free(pool_get(0, monitors)); + pool_free(monitors); + pool_free(bars); } - list_free(monitors); - list_free(bars); } /* @@ -190,12 +189,9 @@ void multihead_free(){ * Xrandr */ void multihead_resize(){ - monitor *m; - list_foreach_noroot(monitors){ - m = (monitor*)itr->data; - m->width = XWidthOfScreen(screen); - m->height = XHeightOfScreen(screen); - } + monitor *m = pool_get(0, monitors); + m->width = XWidthOfScreen(screen); + m->height = XHeightOfScreen(screen); } /* @@ -203,7 +199,7 @@ void multihead_resize(){ * monitor */ monitor *find_monitor(){ - return list_get(monitors,1)->data; + return pool_get(0, monitors); } #endif @@ -222,7 +218,6 @@ void multihead_addbar(Window win){ borderwidth, depth; monitor *m; - node *newbar; XGetGeometry( dpy, @@ -232,15 +227,9 @@ void multihead_addbar(Window win){ &w, &h, &borderwidth, &depth - ); + ); m = monitor_atpos(x, y); - - newbar = list_push(bars); - newbar->data = malloc(sizeof(int)); - *(int*)newbar->data = h; - newbar->data_noptr = win; - m->height -= h; /* @@ -251,30 +240,23 @@ void multihead_addbar(Window win){ */ if(y <= (m->height+m->y) / 2){ m->y += h; - /* - * Misuse of this member - * to store this - * information - */ - newbar->size = 1; } + + pool_push((void*)win, bars); } /* * Does the opposite of * multihead_addbar() */ -void multihead_delbar(Window win){ - monitor *m = find_monitor(); - - node *bar = list_find(bars, NULL, win); - if(bar != NULL){ - m->height += *(int*)bar->data; - if(bar->size){ - m->y -= *(int*)bar->data; - } - list_pop(bars, bar); - } +void multihead_delbar(int pos){ + pool_pop(pos, bars); + + multihead_resize(); + + /* + * TODO: Flesh out + */ } /* @@ -285,7 +267,7 @@ void multihead_delbar(Window win){ * tile_existing()) */ int multihead_isbar(Window win){ - return (list_find(bars, NULL, win) != NULL); + return (pool_find((void*)win, bars) > -1); } /* @@ -295,10 +277,10 @@ int multihead_isbar(Window win){ monitor *monitor_atpos(int x, int y){ int mon_x, mon_y, mon_w, mon_h; - monitor *m = monitors->next->data; + monitor *m = pool_get(0, monitors); - list_foreach_noroot(monitors){ - m = (monitor*)itr->data; + pool_foreach(monitors){ + m = pool_get(ind, monitors); mon_x = m->x; mon_y = m->y; mon_w = m->width; diff --git a/include/tiling.h b/include/tiling.h index 0814d15..bcfc6aa 100644 --- a/include/tiling.h +++ b/include/tiling.h @@ -10,7 +10,7 @@ static void toggle_gaps(monitor *current_monitor); static void toggle_fullscreen(monitor *current_monitor, Window win); static void toggle_above(Window win); static void cycle_monitors(Window win, int dir); -static void cycle_windows(node *windows, Window current, int dir); +static void cycle_windows(pool *windows, Window current, int dir); static void next_mode(); static void center_window(Window win); static void reset(func map_req); @@ -23,8 +23,8 @@ static void tile_existing(func map_req); */ void tile(){ monitor *m; - list_foreach_noroot(monitors){ - m = itr->data; + pool_foreach(monitors){ + m = pool_get(ind, monitors); if(above_enabled && m->fullscreen_enabled){ m->fullscreen_enabled = 2; @@ -73,39 +73,27 @@ void toggle_above(Window win){ * or next available monitor */ void cycle_monitors(Window win, int dir){ - if(x_valid_window(focused)){ - monitor *current_mon = monitors->next->data, - *next_mon = monitors->next->data; - node *elem = current_mon->windows->next, - *new_elem, - *itr; - for( - itr=(dir ? monitors->next : monitors->end); - itr!=NULL; - itr=(dir ? itr->next : itr->prev) - ){ - current_mon = itr->data; - elem = list_find(current_mon->windows,NULL,win); - if(elem != NULL && elem->data_noptr == win){ - if(itr->next != NULL){ - next_mon = itr->next->data; - } else { - next_mon = monitors->next->data; - } + if(x_valid_window(win)){ + int v = -1, + p = 0; + monitor *m = pool_get(0, monitors); + pool_foreach(monitors){ + m = pool_get(ind, monitors); + if((p = pool_find((void*)win, m->windows)) > -1){ break; } } - if(current_mon != NULL && - next_mon != NULL && - elem != NULL){ - list_pop(current_mon->windows,elem); - new_elem = list_push(next_mon->windows); - new_elem->data_noptr = win; + v = pool_adj(p, dir, monitors); + if(v != -1){ + pool_pop(p, m->windows); + + m = pool_get(v, monitors); + pool_push((void*)win, m->windows); x_set_cursorpos( - next_mon->x + (next_mon->width / 2), - next_mon->y + (next_mon->height / 2) + m->x + (m->width / 2), + m->y + (m->height / 2) ); tile(); @@ -117,31 +105,13 @@ void cycle_monitors(Window win, int dir){ * Focuses the previous/next window * in a monitor's list */ -void cycle_windows(node *windows, Window current, int dir){ - node *elem = NULL; - list_foreach_noroot(windows){ - if(itr->data_noptr == current){ - elem = itr; - break; - } - } - - if(elem != NULL){ - switch(dir){ - case 0: - if(elem->prev == windows){ - x_set_focused(windows->end->data_noptr); - } else { - x_set_focused(elem->prev->data_noptr); - } - break; - case 1: - if(elem->next == NULL){ - x_set_focused(windows->next->data_noptr); - } else { - x_set_focused(elem->next->data_noptr); - } - break; +void cycle_windows(pool *windows, Window current, int dir){ + int v = -1, + ind = pool_find((void*)current, windows); + if(ind != -1){ + v = pool_adj(ind, dir, windows); + if(v != -1){ + x_set_focused((Window)pool_get(v, windows)); } } } @@ -180,12 +150,12 @@ void center_window(Window win){ * a "ghost window" */ void reset(func map_req){ - list_foreach_noroot(monitors){ - monitor *m = (monitor*)itr->data; + pool_foreach(monitors){ + monitor *m = pool_get(ind, monitors); if(m != NULL && m->windows != NULL){ - list_free(m->windows); + pool_free(m->windows); } - m->windows = list_init(); + m->windows = pool_init(MAX_WINDOWS); } /* diff --git a/include/util.h b/include/util.h index c59ba21..0ad3ce4 100644 --- a/include/util.h +++ b/include/util.h @@ -7,11 +7,7 @@ #define LENGTH(x) (sizeof(x)/sizeof(x[0])) -static void quit(); static void spawn(char *cmd); -static int round_float(float n); -static int closest_even(int n); -static int closest_odd(int n); static int hash_str(char *str); /* @@ -19,9 +15,7 @@ static int hash_str(char *str); * flipping the running * boolean */ -void quit(){ - running = 0; -} +#define quit() (running = 0) /* * Forks a child process, @@ -50,27 +44,21 @@ void spawn(char *cmd){ * Rounds a float to * the nearest int */ -int round_float(float n){ - return (int)(n < 0 ? n - 0.5 : n + 0.5); -} +#define round_float(n) ((int)(n < 0 ? n - 0.5 : n + 0.5)) /* * Finds the closest * even number to * an integer n */ -int closest_even(int n){ - return (n % 2 == 0 ? n : n - 1); -} +#define closest_even(n) (n % 2 == 0 ? n : n - 1) /* * Finds the closest * odd number to * an integer n */ -int closest_odd(int n){ - return (n % 2 ? n : n - 1); -} +#define closest_odd(n) (n % 2 ? n : n - 1) /* * "Hashes" a string to diff --git a/include/x.h b/include/x.h index 4806d7f..59def01 100644 --- a/include/x.h +++ b/include/x.h @@ -64,7 +64,7 @@ void x_init(){ screen = DefaultScreenOfDisplay(dpy); focused = 0; above = 0; - bars = list_init(); + bars = pool_init(MAX_BARS); XSetErrorHandler(&on_x_error); @@ -122,7 +122,7 @@ void x_kill_focused(){ if(x_valid_window(focused)){ int success = x_send_event(focused, atoms[atom_delete]); - XUnmapWindow(dpy,focused); + XUnmapWindow(dpy, focused); if(!success){ XGrabServer(dpy); @@ -263,14 +263,15 @@ void x_query_window(Window win, int *x, int *y, unsigned int *w, unsigned int *h * to a given window */ int x_send_event(Window win, Atom atom){ - int protocols_count; + int protocols_count = 0, + exists = 0; Atom *protocols; XEvent evt; - int exists = 0; - XGetWMProtocols(dpy, win, &protocols, &protocols_count); + protocols_count--; + while(!exists){ exists = (protocols[protocols_count] == atom); protocols_count--; @@ -304,7 +305,11 @@ int on_x_error(Display *dpy, XErrorEvent *e){ quit(); } } else { +#ifdef LOGGING_NO_STDIO + error(last_call); +#else error("%s (error code %i)", last_call, e->error_code); +#endif } last_err = e->error_code; return 0; diff --git a/ntwm.c b/ntwm.c index 22d3ede..5e76d4f 100644 --- a/ntwm.c +++ b/ntwm.c @@ -15,7 +15,7 @@ #include "config.h" #include "logging.h" -#include "list.h" +#include "libspool.h" int running = 1; int has_thrown = 0; @@ -38,8 +38,8 @@ Window root; Window above; Atom atoms[8]; -node *monitors; -node *bars; +pool *monitors; +pool *bars; #include "util.h" #include "x.h"