wmii

git clone git://oldgit.suckless.org/wmii/
Log | Files | Refs | README | LICENSE

commit e6caefcd581927b0cbdc497a64b8d66e2f643afb
parent b5f71fd3c72b5d8dc5518a3c68d6920019e36bc6
Author: Anselm R. Garbe <garbeam@wmii.de>
Date:   Wed, 25 Jan 2006 19:39:08 +0200

began structural changes, don't pull yet


Diffstat:
cmd/wm/Makefile | 24++++++++++++++++++------
cmd/wm/Makefile.wm | 27---------------------------
cmd/wm/client.c | 482++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-----
cmd/wm/column.c | 634+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
cmd/wm/event.c | 2+-
cmd/wm/frame.c | 384-------------------------------------------------------------------------------
cmd/wm/layout_column.c | 634-------------------------------------------------------------------------------
cmd/wm/mklayout.sh | 12------------
cmd/wm/mouse.c | 2+-
cmd/wm/page.c | 18++++--------------
cmd/wm/wm.c | 315++++++++++++++++++++++++++++++++-----------------------------------------------
cmd/wm/wm.h | 202+++++++++++++++++++++++++++++--------------------------------------------------
doc/RELEASE | 10+++++-----
13 files changed, 1321 insertions(+), 1425 deletions(-)

diff --git a/cmd/wm/Makefile b/cmd/wm/Makefile @@ -3,13 +3,25 @@ include ../../config.mk -all: layoutdef.c - @${MAKE} -f Makefile.wm - @echo built core wm +CFLAGS += -I../../liblitz -I../../libixp -I../../libwmii \ + -I../../libcext +LDFLAGS += -L../../liblitz -llitz -L../../libixp -lixp \ + -L../../libwmii -lwmii -L../../libcext -lcext +# Solaris +# LDFLAGS += -lsocket -layoutdef.c: - @echo SH mklayout.sh - @sh mklayout.sh +SRC = wm.c client.c event.c mouse.c page.c column.c +OBJ = ${SRC:.c=.o} + +all: wmiiwm + +.c.o: + @echo CC $< + @${CC} -c ${CFLAGS} $< + +wmiiwm: ${OBJ} + @echo LD $@ + @${CC} -o $@ ${OBJ} ${LDFLAGS} clean: rm -f wmiiwm *.o layoutdef.* diff --git a/cmd/wm/Makefile.wm b/cmd/wm/Makefile.wm @@ -1,27 +0,0 @@ -# wm - window manager improved 2 -# (C)opyright MMIV-MMVI Anselm R. Garbe - -include ../../config.mk - -CFLAGS += -I../../liblitz -I../../libixp -I../../libwmii \ - -I../../libcext -LDFLAGS += -L../../liblitz -llitz -L../../libixp -lixp \ - -L../../libwmii -lwmii -L../../libcext -lcext -# Solaris -# LDFLAGS += -lsocket - -SRC = wm.c client.c event.c mouse.c frame.c page.c layoutdef.c layout.c - -include layoutdef.mk - -OBJ = ${SRC:.c=.o} - -all: wmiiwm - -.c.o: - @echo CC $< - @${CC} -c ${CFLAGS} $< - -wmiiwm: ${OBJ} - @echo LD $@ - @${CC} -o $@ ${OBJ} ${LDFLAGS} diff --git a/cmd/wm/client.c b/cmd/wm/client.c @@ -10,18 +10,95 @@ #include "wm.h" +static void handle_before_read_client(IXPServer * s, File * file); +static void handle_after_write_client(IXPServer * s, File * file); + Client * -alloc_client(Window w) +alloc_client(Window w, XWindowAttributes *wa) { XTextProperty name; Client *c = (Client *) cext_emallocz(sizeof(Client)); + XSetWindowAttributes fwa; + size_t i; + static int id = 1; + char buf[MAX_BUF]; + int bw, th; + long msize; + /* client itself */ c->win = w; + c->rect.x = wa->x; + c->rect.y = wa->y; + c->border = wa->border_width; + c->rect.width = wa->width + 2 * c->border; + c->rect.height = wa->height + 2 * c->border; + XSetWindowBorderWidth(dpy, c->win, 0); + c->proto = win_proto(c->win); + XGetTransientForHint(dpy, c->win, &c->trans); + if(!XGetWMNormalHints(dpy, c->win, &c->size, &msize) || !c->size.flags) + c->size.flags = PSize; + XAddToSaveSet(dpy, c->win); XGetWMName(dpy, c->win, &name); if(name.value) { cext_strlcpy(c->name, (char *)name.value, sizeof(c->name)); free(name.value); } + + snprintf(buf, MAX_BUF, "/detached/%d", id); + c->file[C_PREFIX] = ixp_create(ixps, buf); + snprintf(buf, MAX_BUF, "/detached/%d/name", id); + c->file[C_NAME] = ixp_create(ixps, buf); + c->file[C_NAME]->before_read = handle_before_read_client; + snprintf(buf, MAX_BUF, "/detached/%d/border", id); + c->file[C_BORDER] = + wmii_create_ixpfile(ixps, buf, def[WM_BORDER]->content); + c->file[C_BORDER]->after_write = handle_after_write_client; + snprintf(buf, MAX_BUF, "/detached/%d/tab", id); + c->file[C_TAB] = wmii_create_ixpfile(ixps, buf, def[WM_TAB]->content); + c->file[C_TAB]->after_write = handle_after_write_client; + snprintf(buf, MAX_BUF, "/detached/%d/handleinc", id); + c->file[C_HANDLE_INC] = + wmii_create_ixpfile(ixps, buf, def[WM_HANDLE_INC]->content); + c->file[C_HANDLE_INC]->after_write = handle_after_write_client; + snprintf(buf, MAX_BUF, "/detached/%d/geometry", id); + c->file[C_GEOMETRY] = ixp_create(ixps, buf); + c->file[C_GEOMETRY]->before_read = handle_before_read_client; + c->file[C_GEOMETRY]->after_write = handle_after_write_client; + id++; + + /* client.frame */ + fwa.override_redirect = 1; + fwa.background_pixmap = ParentRelative; + fwa.event_mask = SubstructureRedirectMask | ExposureMask | ButtonPressMask | PointerMotionMask; + + bw = border_width(c); + th = tab_height(c); + c->frame.rect.width += 2 * bw; + c->frame.rect.height += bw + (th ? th : bw); + c->frame.win = XCreateWindow(dpy, root, c->frame.rect.x, c->frame.rect.y, + c->frame.rect.width, c->frame.rect.height, 0, + DefaultDepth(dpy, screen), CopyFromParent, DefaultVisual(dpy, screen), + CWOverrideRedirect | CWBackPixmap | CWEventMask, &fwa); + c->frame.cursor = normal_cursor; + XDefineCursor(dpy, c->frame.win, c->frame.cursor); + c->frame.gc = XCreateGC(dpy, c->frame.win, 0, 0); + XSync(dpy, False); + + if(!clients) { + clientssz = 2; + clients = cext_emallocz(sizeof(Client *) * clientssz); + } + for(i = 0; (i < clientssz) && clients[i]; i++); + if(i >= clientssz) { + Client **tmp = clients; + clientssz *= 2; + clients = cext_emallocz(sizeof(Client *) * clientssz); + for(i = 0; tmp[i]; i++) + clients[i] = tmp[i]; + free(tmp); + } + clients[i] = c; + return c; } @@ -135,23 +212,6 @@ close_client(Client * c) } void -init_client(Client * c, XWindowAttributes * wa) -{ - long msize; - c->rect.x = wa->x; - c->rect.y = wa->y; - c->border = wa->border_width; - c->rect.width = wa->width + 2 * c->border; - c->rect.height = wa->height + 2 * c->border; - XSetWindowBorderWidth(dpy, c->win, 0); - c->proto = win_proto(c->win); - XGetTransientForHint(dpy, c->win, &c->trans); - if(!XGetWMNormalHints(dpy, c->win, &c->size, &msize) || !c->size.flags) - c->size.flags = PSize; - XAddToSaveSet(dpy, c->win); -} - -void handle_client_property(Client * c, XPropertyEvent * e) { XTextProperty name; @@ -196,7 +256,7 @@ destroy_client(Client * c) void draw_client(Client *c) { - Frame *f = c->frame; + Client *f = c->frame; unsigned int tabh = tab_height(f); Draw d = { 0 }; @@ -213,13 +273,13 @@ draw_client(Client *c) d.font = font; if(f == sel_frame()) { - d.bg = blitz_loadcolor(dpy, screen_num, def[WM_SEL_BG_COLOR]->content); - d.fg = blitz_loadcolor(dpy, screen_num, def[WM_SEL_FG_COLOR]->content); - d.border = blitz_loadcolor(dpy, screen_num, def[WM_SEL_BORDER_COLOR]->content); + d.bg = blitz_loadcolor(dpy, screen, def[WM_SEL_BG_COLOR]->content); + d.fg = blitz_loadcolor(dpy, screen, def[WM_SEL_FG_COLOR]->content); + d.border = blitz_loadcolor(dpy, screen, def[WM_SEL_BORDER_COLOR]->content); } else { - d.bg = blitz_loadcolor(dpy, screen_num, def[WM_NORM_BG_COLOR]->content); - d.fg = blitz_loadcolor(dpy, screen_num, def[WM_NORM_FG_COLOR]->content); - d.border = blitz_loadcolor(dpy, screen_num, def[WM_NORM_BORDER_COLOR]->content); + d.bg = blitz_loadcolor(dpy, screen, def[WM_NORM_BG_COLOR]->content); + d.fg = blitz_loadcolor(dpy, screen, def[WM_NORM_FG_COLOR]->content); + d.border = blitz_loadcolor(dpy, screen, def[WM_NORM_BORDER_COLOR]->content); } blitz_drawlabel(dpy, &d); XSync(dpy, False); @@ -310,7 +370,7 @@ attach_client(Client * c) void detach_client(Client * c, Bool unmap) { - Frame *f = c->frame; + Client *f = c->frame; Layout *l = f ? f->layout : nil; if(l) l->def->detach(l, c, unmap); @@ -362,3 +422,373 @@ attach_detached(Client * c) detached = c; ndetached++; } + + + +Client * +alloc_frame(XRectangle * r) +{ + XSetWindowAttributes wa; + static int id = 1; + char buf[MAX_BUF]; + Client *f = (Client *) cext_emallocz(sizeof(Client)); + int bw, th; + + f->rect = *r; + f->cursor = normal_cursor; + + snprintf(buf, MAX_BUF, "/detached/%d", id); + f->file[F_PREFIX] = ixp_create(ixps, buf); + snprintf(buf, MAX_BUF, "/detached/%d/name", id); + f->file[F_NAME] = ixp_create(ixps, buf); + f->file[F_NAME]->before_read = handle_before_read_frame; + snprintf(buf, MAX_BUF, "/detached/%d/border", id); + f->file[F_BORDER] = + wmii_create_ixpfile(ixps, buf, def[WM_BORDER]->content); + f->file[F_BORDER]->after_write = handle_after_write_frame; + snprintf(buf, MAX_BUF, "/detached/%d/tab", id); + f->file[F_TAB] = wmii_create_ixpfile(ixps, buf, def[WM_TAB]->content); + f->file[F_TAB]->after_write = handle_after_write_frame; + snprintf(buf, MAX_BUF, "/detached/%d/handleinc", id); + f->file[F_HANDLE_INC] = + wmii_create_ixpfile(ixps, buf, def[WM_HANDLE_INC]->content); + f->file[F_HANDLE_INC]->after_write = handle_after_write_frame; + snprintf(buf, MAX_BUF, "/detached/%d/geometry", id); + f->file[F_GEOMETRY] = ixp_create(ixps, buf); + f->file[F_GEOMETRY]->before_read = handle_before_read_frame; + f->file[F_GEOMETRY]->after_write = handle_after_write_frame; + id++; + + wa.override_redirect = 1; + wa.background_pixmap = ParentRelative; + wa.event_mask = SubstructureRedirectMask | ExposureMask | ButtonPressMask | PointerMotionMask; + + bw = border_width(c); + th = tab_height(c); + c->frame.rect.width += 2 * bw; + c->frame.rect.height += bw + (th ? th : bw); + c->frame.win = XCreateWindow(dpy, root, c->frame.rect.x, c->frame.rect.y, + c->frame.rect.width, c->frame.rect.height, 0, + DefaultDepth(dpy, screen), CopyFromParent, DefaultVisual(dpy, screen), + CWOverrideRedirect | CWBackPixmap | CWEventMask, &wa); + c->frame.cursor = normal_cursor; + XDefineCursor(dpy, c->frame.win, c->frame.cursor); + c->frame.gc = XCreateGC(dpy, c->frame.win, 0, 0); + XSync(dpy, False); + return f; +} + +Client * +win_to_frame(Window w) +{ + Page *p; + for(p = pages; p; p = p->next) { + Client *f; + if(p->managed->def) + for(f = p->managed->def->frames(p->managed); f; f = f->next) + if(f->win == w) + return f; + for(f = p->floating->def->frames(p->floating); f; f = f->next) + if(f->win == w) + return f; + } + return nil; +} + +void +destroy_frame(Client * f) +{ + XFreeGC(dpy, f->gc); + XDestroyWindow(dpy, f->win); + ixp_remove_file(ixps, f->file[F_PREFIX]); + free(f); +} + +unsigned int +tab_height(Client * f) +{ + if(blitz_strtonum(f->file[F_TAB]->content, 0, 1)) + return font->ascent + font->descent + 4; + return 0; +} + +unsigned int +border_width(Client * f) +{ + if(blitz_strtonum(f->file[F_BORDER]->content, 0, 1)) + return BORDER_WIDTH; + return 0; +} + +static void +check_dimensions(Client * f, unsigned int tabh, unsigned int bw) +{ + Client *c = sel_client(); + if(!c) + return; + + if(c->size.flags & PMinSize) { + if(f->rect.width - 2 * bw < c->size.min_width) { + f->rect.width = c->size.min_width + 2 * bw; + } + if(f->rect.height - bw - (tabh ? tabh : bw) < c->size.min_height) { + f->rect.height = c->size.min_height + bw + (tabh ? tabh : bw); + } + } + if(c->size.flags & PMaxSize) { + if(f->rect.width - 2 * bw > c->size.max_width) { + f->rect.width = c->size.max_width + 2 * bw; + } + if(f->rect.height - bw - (tabh ? tabh : bw) > c->size.max_height) { + f->rect.height = c->size.max_height + bw + (tabh ? tabh : bw); + } + } +} + +static void +resize_incremental(Client * f, unsigned int tabh, unsigned int bw) +{ + Client *c = f->sel; + if(!c) + return; + /* increment stuff, see chapter 4.1.2.3 of the ICCCM Manual */ + if(c->size.flags & PResizeInc) { + int base_width = 0, base_height = 0; + + if(c->size.flags & PBaseSize) { + base_width = c->size.base_width; + base_height = c->size.base_height; + } else if(c->size.flags & PMinSize) { + /* base_{width,height} default to min_{width,height} */ + base_width = c->size.min_width; + base_height = c->size.min_height; + } + /* client_width = base_width + i * c->size.width_inc for an integer i */ + f->rect.width -= + (f->rect.width - 2 * bw - base_width) % c->size.width_inc; + f->rect.height -= + (f->rect.height - bw - (tabh ? tabh : bw) - + base_height) % c->size.height_inc; + } +} + +void +resize_frame(Client * f, XRectangle * r, XPoint * pt) +{ + Layout *l = f->layout; + unsigned int tabh = tab_height(f); + unsigned int bw = border_width(f); + Client *c = f->client; + + l->def->resize(f, r, pt); + + /* resize if client requests special size */ + check_dimensions(f, tabh, bw); + + if(f->file[F_HANDLE_INC]->content + && ((char *) f->file[F_HANDLE_INC]->content)[0] == '1') + resize_incremental(f, tabh, bw); + + XMoveResizeWindow(dpy, f->win, f->rect.x, f->rect.y, f->rect.width, + f->rect.height); + + if(f->client) { + c->rect.x = bw; + c->rect.y = tabh ? tabh : bw; + c->rect.width = c->frame->rect.width - 2 * bw; + c->rect.height = c->frame->rect.height - bw - (tabh ? tabh : bw); + XMoveResizeWindow(dpy, c->win, c->rect.x, c->rect.y, c->rect.width, + c->rect.height); + configure_client(c); + } +} + +/** + * Assumes following file: + * + * ./sel-style/text-font "<value>" + * ./sel-style/text-size "<int>" + * ./sel-style/text-color "#RRGGBBAA" + * ./sel-style/bg-color "#RRGGBBAA" + * ./sel-style/border-color "#RRGGBBAA [#RRGGBBAA [#RRGGBBAA [#RRGGBBAA]]]" + * ./norm-style/text-font "<value>" + * ./norm-style/text-size "<int>" + * ./norm-style/text-color "#RRGGBBAA" + * ./norm-style/bg-color "#RRGGBBAA" + * ./norm-style/border-color "#RRGGBBAA [#RRGGBBAA [#RRGGBBAA [#RRGGBBAA]]]" + */ +void +draw_frame(Client * f) +{ + Draw d = { 0 }; + int bw = border_width(f); + XRectangle notch; + if(bw) { + notch.x = bw; + notch.y = bw; + notch.width = f->rect.width - 2 * bw; + notch.height = f->rect.height - 2 * bw; + d.drawable = f->win; + d.font = font; + d.gc = f->gc; + + /* define ground plate (i = 0) */ + if(f == sel_frame()) { + d.bg = blitz_loadcolor(dpy, screen, def[WM_SEL_BG_COLOR]->content); + d.fg = blitz_loadcolor(dpy, screen, def[WM_SEL_FG_COLOR]->content); + d.border = blitz_loadcolor(dpy, screen, def[WM_SEL_BORDER_COLOR]->content); + } else { + d.bg = blitz_loadcolor(dpy, screen, def[WM_NORM_BG_COLOR]->content); + d.fg = blitz_loadcolor(dpy, screen, def[WM_NORM_FG_COLOR]->content); + d.border = blitz_loadcolor(dpy, screen, def[WM_NORM_BORDER_COLOR]->content); + } + d.rect = f->rect; + d.rect.x = d.rect.y = 0; + d.notch = &notch; + + blitz_drawlabel(dpy, &d); + } + draw_client(f->client); + XSync(dpy, False); +} + +void +handle_frame_buttonpress(XButtonEvent * e, Client * f) +{ + Align align; + int bindex; + Layout *l = sel_layout(); + if(l != f->layout) + focus_layout(f->layout); + l = f->layout; + l->def->focus(l, f->client, False); + if(e->button == Button1) { + align = cursor_to_align(f->cursor); + if(align == CENTER) + mouse_move(f); + else + mouse_resize(f, align); + return; + } + bindex = WM_EVENT_B2PRESS - 2 + e->button; + /* frame mouse handling */ + if(def[bindex]->content) + wmii_spawn(dpy, def[bindex]->content); +} + +void +attach_client_to_frame(Client * f, Client * c) +{ + f->client = c; + c->frame = f; + resize_frame(f, &f->rect, 0); + reparent_client(c, f->win, c->rect.x, c->rect.y); + map_client(c); +} + +void +detach_client_from_frame(Client * c, Bool unmap) +{ + Client *f = c->frame; + + c->frame = nil; + if(f->sel == c) + f->sel = nil; + + f->client = nil; + + if(!c->destroyed) { + if(!unmap) { + attach_detached(c); + unmap_client(c); + } + c->rect.x = f->rect.x; + c->rect.y = f->rect.y; + reparent_client(c, root, c->rect.x, c->rect.y); + } +} + +static Client * +handle_before_read_frames(IXPServer *s, File *file, Layout *l) +{ + Client *f; + char buf[32]; + if(!l->def) + return nil; + for(f = l->def->frames(l); f; f = f->next) { + if(file == f->file[F_GEOMETRY]) { + snprintf(buf, sizeof(buf), "%d %d %d %d", f->rect.x, f->rect.y, + f->rect.width, f->rect.height); + if(file->content) + free(file->content); + file->content = cext_estrdup(buf); + file->size = strlen(buf); + return f; + } + else if(file == f->file[F_NAME]) { + if(file->content) + free(file->content); + if(f->sel && f->sel->name) { + file->content = cext_estrdup(f->sel->name); + file->size = strlen(f->sel->name); + } + else { + file->content = nil; + file->size = 0; + } + return f; + } + } + return nil; +} + +static void +handle_before_read_frame(IXPServer * s, File * file) +{ + Page *p; + for(p = pages; p; p = p->next) { + if(handle_before_read_frames(s, file, p->managed) + || handle_before_read_frames(s, file, p->floating)) + return; + } +} + +static Client * +handle_after_write_frames(IXPServer *s, File *file, Layout *l) +{ + Client *f; + for(f = l->def->frames(l); f; f = f->next) { + if(file == f->file[F_TAB] || file == f->file[F_BORDER] + || file == f->file[F_HANDLE_INC]) { + f->layout->def->arrange(f->layout); + return f; + } else if(file == f->file[F_GEOMETRY]) { + char *geom = f->file[F_GEOMETRY]->content; + if(geom && strrchr(geom, ' ')) { + XRectangle frect = f->rect; + blitz_strtorect(&rect, &frect, geom); + resize_frame(f, &frect, 0); + } + return f; + } + } + return nil; +} + +static void +handle_after_write_frame(IXPServer * s, File * file) +{ + Page *p; + for(p = pages; p; p = p->next) { + if(handle_after_write_frames(s, file, p->managed) + || handle_after_write_frames(s, file, p->floating)) + return; + } +} + +Client * +sel_frame() +{ + Client *c = sel_client(); + return c ? c->frame : nil; +} diff --git a/cmd/wm/column.c b/cmd/wm/column.c @@ -0,0 +1,634 @@ +/* + * (C)opyright MMIV-MMVI Anselm R. Garbe <garbeam at gmail dot com> + * See LICENSE file for license details. + */ + +#include <stdlib.h> +#include <string.h> +#include <math.h> + +#include "wm.h" +#include "layoutdef.h" + +typedef struct Acme Acme; +typedef struct Column Column; +typedef struct Cell Cell; + +struct Acme { + Column *sel; + Column *columns; + size_t ncolumns; + Frame *frames; + size_t nframes; +}; + +struct Cell { + Frame *frame; + Cell *next; + Cell *prev; + Column *column; +}; + +struct Column { + Cell *sel; + Cell *cells; + size_t ncells; + XRectangle rect; + Column *prev; + Column *next; +}; + +static void init_column(Layout *l, Client * clients); +static Client *deinit_column(Layout *l); +static void arrange_column(Layout *l); +static Bool attach_column(Layout *l, Client * c); +static void detach_column(Layout *l, Client * c, Bool unmap); +static void resize_column(Frame * f, XRectangle * new, XPoint * pt); +static void focus_column(Layout *l, Client *c, Bool raise); +static Frame *frames_column(Layout *l); +static Client *sel_column(Layout *l); +static Action *actions_column(Layout *l); + +static void select_frame(void *obj, char *arg); +static void max_frame(void *obj, char *arg); +static void swap_frame(void *obj, char *arg); +static void new_column(void *obj, char *arg); + +static Action lcol_acttbl[] = { + {"select", select_frame}, + {"swap", swap_frame}, + {"new", new_column}, + {"max", max_frame}, + {0, 0} +}; + +void +init_layout_column() +{ + LayoutDef *lp, *l = cext_emallocz(sizeof(LayoutDef)); + l->name = "column"; + l->init = init_column; + l->deinit = deinit_column; + l->arrange = arrange_column; + l->attach = attach_column; + l->detach = detach_column; + l->resize = resize_column; + l->focus = focus_column; + l->frames = frames_column; + l->sel = sel_column; + l->actions = actions_column; + + for(lp = layouts; lp && lp->next; lp = lp->next); + if(lp) + lp->next = l; + else + layouts = l; +} + +static void +xarrange_column(Column * column) +{ + Cell *cell; + unsigned int i = 0, h = layout_rect.height / column->ncells; + for(cell = column->cells; cell; cell = cell->next) { + Frame *f = cell->frame; + f->rect = column->rect; + f->rect.y = layout_rect.y + i * h; + if(!cell->next) + f->rect.height = layout_rect.height - f->rect.y + layout_rect.y; + else + f->rect.height = h; + resize_frame(f, &f->rect, 0); + i++; + } +} + +static void +arrange_column(Layout *l) +{ + Acme *acme = l->aux; + Column *column; + for(column = acme->columns; column; column = column->next) + xarrange_column(column); + XSync(dpy, False); +} + +static void +init_column(Layout *l, Client * clients) +{ + Client *n, *c = clients; + + l->aux = cext_emallocz(sizeof(Acme)); + while(c) { + n = c->next; + attach_column(l, c); + c = n; + } +} + +static void +attach_frame(Layout *l, Column * column, Frame * new) +{ + Acme *acme = l->aux; + Cell *c, *cell = cext_emallocz(sizeof(Cell)); + Frame *f; + + cell->frame = new; + cell->column = column; + new->aux = cell; + for(c = column->cells; c && c->next; c = c->next); + if(!c) + column->cells = cell; + else { + c->next = cell; + cell->prev = c; + } + column->ncells++; + + for(f = acme->frames; f && f->next; f = f->next); + if(!f) + acme->frames = new; + else { + f->next = new; + new->prev = f; + } + attach_frame_to_layout(l, new); + acme->nframes++; +} + +static void +detach_frame(Layout *l, Frame * old) +{ + Acme *acme = l->aux; + Cell *cell = old->aux; + Column *column = cell->column; + + if(cell->prev) + cell->prev->next = cell->next; + else + column->cells = cell->next; + if(cell->next) + cell->next->prev = cell->prev; + + if(column->sel == cell) + column->sel = column->cells; + + free(cell); + column->ncells--; + + if(old->prev) + old->prev->next = old->next; + else + acme->frames = old->next; + if(old->next) + old->next->prev = old->prev; + old->prev = old->next = nil; + old->aux = nil; + detach_frame_from_layout(old); + acme->nframes--; +} + +static Client * +deinit_column(Layout *l) +{ + Acme *acme = l->aux; + Frame *f; + Client *cl, *res = nil, *c = nil; + Column *column = acme->columns; + + while((f = acme->frames)) { + cl = f->client; + detach_client_from_frame(cl, False); + cl->prev = cl->next = 0; + if(!c) + res = c = cl; + else { + c->next = cl; + cl->prev = c; + c = cl; + } + detach_frame(l, f); + destroy_frame(f); + } + while((column = acme->columns)) { + acme->columns = column->next; + free(column); + } + free(acme); + l->aux = 0; + return res; +} + +static Bool +attach_column(Layout *l, Client * c) +{ + Acme *acme = l->aux; + Column *column = acme->sel; + Frame *f = nil; + + if(!column) { + column = cext_emallocz(sizeof(Column)); + column->rect = layout_rect; + acme->columns = acme->sel = column; + acme->ncolumns++; + } + + f = alloc_frame(&c->rect); + attach_frame(l, column, f); + attach_client_to_frame(f, c); + xarrange_column(column); + if(l->page == selpage) + XMapWindow(dpy, f->win); + focus_column(l, c, True); + return True; +} + +static void +update_column_width(Layout *l) +{ + Acme *acme = l->aux; + unsigned int i = 0, width; + Column *column; + + if(!acme->ncolumns) + return; + + width = layout_rect.width / acme->ncolumns; + for(column = acme->columns; column; column = column->next) { + column->rect = layout_rect; + column->rect.x = i * width; + column->rect.width = width; + i++; + } + arrange_column(l); +} + +static void +detach_column(Layout *l, Client * c, Bool unmap) +{ + Acme *acme = l->aux; + Frame *f = c->frame; + Cell *old = f->aux; + Column *column = old->column; + + detach_client_from_frame(c, unmap); + detach_frame(l, f); + destroy_frame(f); + if(column->cells) { + if(column->sel == old) + column->sel = column->cells; + xarrange_column(column); + } + else { + if(acme->sel == column) { + if(column->prev) + acme->sel = column->prev; + else + acme->sel = nil; + } + if(column->prev) + column->prev->next = column->next; + else + acme->columns = column->next; + if(column->next) + column->next->prev = column->prev; + if(!acme->sel) + acme->sel = acme->columns; + acme->ncolumns--; + free(column); + update_column_width(l); + } +} + +static void +match_frame_horiz(Column * column, XRectangle * r) +{ + Cell *cell; + for(cell = column->cells; cell; cell = cell->next) { + Frame *f = cell->frame; + f->rect.x = r->x; + f->rect.width = r->width; + resize_frame(f, &f->rect, nil); + } +} + +static void +drop_resize(Frame * f, XRectangle * new) +{ + Column *west = nil, *east = nil, *column = nil; + Cell *north = nil, *south = nil; + Cell *cell = f->aux; + + column = cell->column; + west = column->prev; + east = column->next; + north = cell->prev; + south = cell->next; + + /* horizontal resize */ + if(west && (new->x != f->rect.x)) { + west->rect.width = new->x - west->rect.x; + column->rect.width += f->rect.x - new->x; + column->rect.x = new->x; + match_frame_horiz(west, &west->rect); + match_frame_horiz(column, &column->rect); + } + if(east && (new->x + new->width != f->rect.x + f->rect.width)) { + east->rect.width -= new->x + new->width - east->rect.x; + east->rect.x = new->x + new->width; + column->rect.x = new->x; + column->rect.width = new->width; + match_frame_horiz(column, &column->rect); + match_frame_horiz(east, &east->rect); + } + + /* vertical resize */ + if(north && (new->y != f->rect.y)) { + north->frame->rect.height = new->y - north->frame->rect.y; + f->rect.height += f->rect.y - new->y; + f->rect.y = new->y; + resize_frame(north->frame, &north->frame->rect, nil); + resize_frame(f, &f->rect, nil); + } + if(south && (new->y + new->height != f->rect.y + f->rect.height)) { + south->frame->rect.height -= + new->y + new->height - south->frame->rect.y; + south->frame->rect.y = new->y + new->height; + f->rect.y = new->y; + f->rect.height = new->height; + resize_frame(f, &f->rect, nil); + resize_frame(south->frame, &south->frame->rect, nil); + } +} + +static void +drop_moving(Frame * f, XRectangle * new, XPoint * pt) +{ + Layout *l = f->layout; + Cell *cell = f->aux; + Column *src = cell->column, *tgt = 0; + Acme *acme = l->aux; + + if(!pt) + return; + + for(tgt = acme->columns; + tgt && !blitz_ispointinrect(pt->x, pt->y, &tgt->rect); + tgt = tgt->next); + if(tgt) { + if(tgt != src) { + if(src->ncells < 2) + return; + detach_frame(l, f); + attach_frame(l, tgt, f); + xarrange_column(src); + xarrange_column(tgt); + focus_column(l, f->sel, True); + } else { + Cell *c; + for(c = src->cells; + c && !blitz_ispointinrect(pt->x, pt->y, &c->frame->rect); + c = c->next); + if(c && c != cell) { + Frame *tmp = c->frame; + c->frame = f; + cell->frame = tmp; + xarrange_column(src); + focus_column(l, f->sel, True); + } + } + } +} + +static void +resize_column(Frame * f, XRectangle * new, XPoint * pt) +{ + if((f->rect.width == new->width) + && (f->rect.height == new->height)) + drop_moving(f, new, pt); + else + drop_resize(f, new); +} + +static void +focus_column(Layout *l, Client *c, Bool raise) +{ + Acme *acme = l->aux; + Cell *cell = c->frame->aux; + Client *old = sel_client(); + + c->frame->sel = c; + acme->sel = cell->column; + cell->column->sel = cell; + l->file[L_SEL_FRAME]->content = c->frame->file[F_PREFIX]->content; + + if(raise) + XWarpPointer(dpy, None, c->win, 0, 0, 0, 0, + c->rect.width / 2, c->rect.height / 2); + + focus_client(c, old); +} + +static Frame * +frames_column(Layout *l) +{ + Acme *acme = l->aux; + return acme->frames; +} + +static Client * +sel_column(Layout *l) +{ + Acme *acme = l->aux; + Column *column = acme->sel; + + if(column && column->sel) + return column->sel->frame->sel; + return nil; +} + +static Action * +actions_column(Layout *l) +{ + return lcol_acttbl; +} + +static void +max_frame(void *obj, char *arg) +{ + Layout *l = obj; + Acme *acme = l->aux; + Column *c = acme->sel; + Cell *cell; + Frame *f; + + if(!c) + return; + + cell = c->sel; + if(!cell) + return; + + f = cell->frame; + if(f->maximized) { + f->rect = f->old; + resize_frame(f, &f->old, nil); + f->maximized = False; + } + else { + f->old = f->rect; + f->rect = c->rect; + XRaiseWindow(dpy, f->win); + resize_frame(f, &c->rect, nil); + f->maximized = True; + } +} + +static void +select_frame(void *obj, char *arg) +{ + Layout *l = obj; + Acme *acme = l->aux; + Column *c, *column = acme->sel; + Cell *cell; + + if(!column) + return; + + cell = column->sel; + if(!cell || !arg) + return; + if(!strncmp(arg, "prev", 5)) { + if(cell->prev) + cell = cell->prev; + else + for(cell = column->cells; cell && cell->next; cell = cell->next); + } else if(!strncmp(arg, "next", 5)) { + if(cell->next) + cell = cell->next; + else + cell = column->cells; + } else if(!strncmp(arg, "west", 5)) { + if(column->prev) + cell = column->prev->sel; + else { + for(c = acme->columns; c && c->next; c = c->next); + cell = c->sel; + } + } else if(!strncmp(arg, "east", 5)) { + if(column->next) + cell = column->next->sel; + else + cell = acme->columns->sel; + } else { + unsigned int i = 0, idx = blitz_strtonum(arg, 0, column->ncells - 1); + for(cell = column->cells; cell && i != idx; cell = cell->next) + i++; + } + if(cell && cell != column->sel) + focus_column(l, cell->frame->sel, True); +} + +static void +swap_frame(void *obj, char *arg) +{ + Layout *l = obj; + Acme *acme = l->aux; + Column *west = nil, *east = nil, *column = acme->sel; + Cell *north = nil, *south = nil, *cell = column->sel; + Frame *f; + XRectangle r; + + if(!column || !cell || !arg) + return; + + west = column->prev; + east = column->next; + north = cell->prev; + south = cell->next; + + if(!west) + west = east; + if(!east) + east = west; + + if(!strncmp(arg, "north", 6) && north) { + r = north->frame->rect; + north->frame->rect = cell->frame->rect; + cell->frame->rect = r; + f = north->frame; + north->frame = cell->frame; + cell->frame = f; + cell->frame->aux = cell; + north->frame->aux = north; + resize_frame(cell->frame, &cell->frame->rect, nil); + resize_frame(north->frame, &north->frame->rect, nil); + focus_column(l, cell->frame->sel, True); + } else if(!strncmp(arg, "south", 6) && south) { + r = south->frame->rect; + south->frame->rect = cell->frame->rect; + cell->frame->rect = r; + f = south->frame; + south->frame = cell->frame; + cell->frame = f; + cell->frame->aux = cell; + south->frame->aux = south; + resize_frame(cell->frame, &cell->frame->rect, nil); + resize_frame(south->frame, &south->frame->rect, nil); + focus_column(l, cell->frame->sel, True); + } else if(!strncmp(arg, "west", 5) && west && column->ncells && west->ncells) { + Cell *other = west->sel; + r = other->frame->rect; + other->frame->rect = cell->frame->rect; + cell->frame->rect = r; + f = other->frame; + other->frame = cell->frame; + cell->frame = f; + other->frame->aux = other; + cell->frame->aux = cell; + resize_frame(cell->frame, &cell->frame->rect, nil); + resize_frame(other->frame, &other->frame->rect, nil); + focus_column(l, other->frame->sel, True); + } else if(!strncmp(arg, "east", 5) && east && column->ncells && east->ncells) { + Cell *other = east->sel; + r = other->frame->rect; + other->frame->rect = cell->frame->rect; + cell->frame->rect = r; + f = other->frame; + other->frame = cell->frame; + cell->frame = f; + other->frame->aux = other; + cell->frame->aux = cell; + resize_frame(cell->frame, &cell->frame->rect, nil); + resize_frame(other->frame, &other->frame->rect, nil); + focus_column(l, other->frame->sel, True); + } +} + +static void +new_column(void *obj, char *arg) +{ + Layout *l = obj; + Acme *acme = l->aux; + Column *c, *new, *column = acme->sel; + Frame *f; + + if(!column || column->ncells < 2) + return; + + f = column->sel->frame; + for(c = acme->columns; c && c->next; c = c->next); + + new = cext_emallocz(sizeof(Column)); + new->rect = layout_rect; + new->prev = c; + c->next = new; + acme->ncolumns++; + acme->sel = new; + + detach_frame(l, f); + attach_frame(l, new, f); + + update_column_width(l); + focus_column(l, f->sel, True); +} diff --git a/cmd/wm/event.c b/cmd/wm/event.c @@ -208,7 +208,7 @@ handle_maprequest(XEvent * e) /* attach heuristic support */ if(attachqueue && (attachqueue->page != selpage)) { - AttachQueue *r = attachqueue; + MapQueue *r = attachqueue; focus_page(r->page); attachqueue = attachqueue->next; free(r); diff --git a/cmd/wm/frame.c b/cmd/wm/frame.c @@ -1,384 +0,0 @@ -/* - * (C)opyright MMIV-MMVI Anselm R. Garbe <garbeam at gmail dot com> - * See LICENSE file for license details. - */ - -#include <assert.h> -#include <math.h> -#include <stdlib.h> -#include <string.h> - -#include "wm.h" - -static void handle_after_write_frame(IXPServer * s, File * file); -static void handle_before_read_frame(IXPServer * s, File * file); - -Frame * -alloc_frame(XRectangle * r) -{ - XSetWindowAttributes wa; - static int id = 1; - char buf[MAX_BUF]; - Frame *f = (Frame *) cext_emallocz(sizeof(Frame)); - int bw, th; - - f->rect = *r; - f->cursor = normal_cursor; - - snprintf(buf, MAX_BUF, "/detached/%d", id); - f->file[F_PREFIX] = ixp_create(ixps, buf); - snprintf(buf, MAX_BUF, "/detached/%d/name", id); - f->file[F_NAME] = ixp_create(ixps, buf); - f->file[F_NAME]->before_read = handle_before_read_frame; - snprintf(buf, MAX_BUF, "/detached/%d/border", id); - f->file[F_BORDER] = - wmii_create_ixpfile(ixps, buf, def[WM_BORDER]->content); - f->file[F_BORDER]->after_write = handle_after_write_frame; - snprintf(buf, MAX_BUF, "/detached/%d/tab", id); - f->file[F_TAB] = wmii_create_ixpfile(ixps, buf, def[WM_TAB]->content); - f->file[F_TAB]->after_write = handle_after_write_frame; - snprintf(buf, MAX_BUF, "/detached/%d/handleinc", id); - f->file[F_HANDLE_INC] = - wmii_create_ixpfile(ixps, buf, def[WM_HANDLE_INC]->content); - f->file[F_HANDLE_INC]->after_write = handle_after_write_frame; - snprintf(buf, MAX_BUF, "/detached/%d/geometry", id); - f->file[F_GEOMETRY] = ixp_create(ixps, buf); - f->file[F_GEOMETRY]->before_read = handle_before_read_frame; - f->file[F_GEOMETRY]->after_write = handle_after_write_frame; - id++; - - wa.override_redirect = 1; - wa.background_pixmap = ParentRelative; - wa.event_mask = - SubstructureRedirectMask | ExposureMask | ButtonPressMask | - PointerMotionMask; - - bw = border_width(f); - th = tab_height(f); - f->rect.width += 2 * bw; - f->rect.height += bw + (th ? th : bw); - f->win = XCreateWindow(dpy, root, f->rect.x, f->rect.y, f->rect.width, - f->rect.height, 0, DefaultDepth(dpy, screen_num), - CopyFromParent, DefaultVisual(dpy, screen_num), - CWOverrideRedirect | CWBackPixmap | CWEventMask, - &wa); - XDefineCursor(dpy, f->win, f->cursor); - f->gc = XCreateGC(dpy, f->win, 0, 0); - XSync(dpy, False); - return f; -} - -Frame * -win_to_frame(Window w) -{ - Page *p; - for(p = pages; p; p = p->next) { - Frame *f; - if(p->managed->def) - for(f = p->managed->def->frames(p->managed); f; f = f->next) - if(f->win == w) - return f; - for(f = p->floating->def->frames(p->floating); f; f = f->next) - if(f->win == w) - return f; - } - return nil; -} - -void -destroy_frame(Frame * f) -{ - XFreeGC(dpy, f->gc); - XDestroyWindow(dpy, f->win); - ixp_remove_file(ixps, f->file[F_PREFIX]); - free(f); -} - -unsigned int -tab_height(Frame * f) -{ - if(blitz_strtonum(f->file[F_TAB]->content, 0, 1)) - return font->ascent + font->descent + 4; - return 0; -} - -unsigned int -border_width(Frame * f) -{ - if(blitz_strtonum(f->file[F_BORDER]->content, 0, 1)) - return BORDER_WIDTH; - return 0; -} - -static void -check_dimensions(Frame * f, unsigned int tabh, unsigned int bw) -{ - Client *c = sel_client(); - if(!c) - return; - - if(c->size.flags & PMinSize) { - if(f->rect.width - 2 * bw < c->size.min_width) { - f->rect.width = c->size.min_width + 2 * bw; - } - if(f->rect.height - bw - (tabh ? tabh : bw) < c->size.min_height) { - f->rect.height = c->size.min_height + bw + (tabh ? tabh : bw); - } - } - if(c->size.flags & PMaxSize) { - if(f->rect.width - 2 * bw > c->size.max_width) { - f->rect.width = c->size.max_width + 2 * bw; - } - if(f->rect.height - bw - (tabh ? tabh : bw) > c->size.max_height) { - f->rect.height = c->size.max_height + bw + (tabh ? tabh : bw); - } - } -} - -static void -resize_incremental(Frame * f, unsigned int tabh, unsigned int bw) -{ - Client *c = f->sel; - if(!c) - return; - /* increment stuff, see chapter 4.1.2.3 of the ICCCM Manual */ - if(c->size.flags & PResizeInc) { - int base_width = 0, base_height = 0; - - if(c->size.flags & PBaseSize) { - base_width = c->size.base_width; - base_height = c->size.base_height; - } else if(c->size.flags & PMinSize) { - /* base_{width,height} default to min_{width,height} */ - base_width = c->size.min_width; - base_height = c->size.min_height; - } - /* client_width = base_width + i * c->size.width_inc for an integer i */ - f->rect.width -= - (f->rect.width - 2 * bw - base_width) % c->size.width_inc; - f->rect.height -= - (f->rect.height - bw - (tabh ? tabh : bw) - - base_height) % c->size.height_inc; - } -} - -void -resize_frame(Frame * f, XRectangle * r, XPoint * pt) -{ - Layout *l = f->layout; - unsigned int tabh = tab_height(f); - unsigned int bw = border_width(f); - Client *c = f->client; - - l->def->resize(f, r, pt); - - /* resize if client requests special size */ - check_dimensions(f, tabh, bw); - - if(f->file[F_HANDLE_INC]->content - && ((char *) f->file[F_HANDLE_INC]->content)[0] == '1') - resize_incremental(f, tabh, bw); - - XMoveResizeWindow(dpy, f->win, f->rect.x, f->rect.y, f->rect.width, - f->rect.height); - - if(f->client) { - c->rect.x = bw; - c->rect.y = tabh ? tabh : bw; - c->rect.width = c->frame->rect.width - 2 * bw; - c->rect.height = c->frame->rect.height - bw - (tabh ? tabh : bw); - XMoveResizeWindow(dpy, c->win, c->rect.x, c->rect.y, c->rect.width, - c->rect.height); - configure_client(c); - } -} - -/** - * Assumes following file: - * - * ./sel-style/text-font "<value>" - * ./sel-style/text-size "<int>" - * ./sel-style/text-color "#RRGGBBAA" - * ./sel-style/bg-color "#RRGGBBAA" - * ./sel-style/border-color "#RRGGBBAA [#RRGGBBAA [#RRGGBBAA [#RRGGBBAA]]]" - * ./norm-style/text-font "<value>" - * ./norm-style/text-size "<int>" - * ./norm-style/text-color "#RRGGBBAA" - * ./norm-style/bg-color "#RRGGBBAA" - * ./norm-style/border-color "#RRGGBBAA [#RRGGBBAA [#RRGGBBAA [#RRGGBBAA]]]" - */ -void -draw_frame(Frame * f) -{ - Draw d = { 0 }; - int bw = border_width(f); - XRectangle notch; - if(bw) { - notch.x = bw; - notch.y = bw; - notch.width = f->rect.width - 2 * bw; - notch.height = f->rect.height - 2 * bw; - d.drawable = f->win; - d.font = font; - d.gc = f->gc; - - /* define ground plate (i = 0) */ - if(f == sel_frame()) { - d.bg = blitz_loadcolor(dpy, screen_num, def[WM_SEL_BG_COLOR]->content); - d.fg = blitz_loadcolor(dpy, screen_num, def[WM_SEL_FG_COLOR]->content); - d.border = blitz_loadcolor(dpy, screen_num, def[WM_SEL_BORDER_COLOR]->content); - } else { - d.bg = blitz_loadcolor(dpy, screen_num, def[WM_NORM_BG_COLOR]->content); - d.fg = blitz_loadcolor(dpy, screen_num, def[WM_NORM_FG_COLOR]->content); - d.border = blitz_loadcolor(dpy, screen_num, def[WM_NORM_BORDER_COLOR]->content); - } - d.rect = f->rect; - d.rect.x = d.rect.y = 0; - d.notch = &notch; - - blitz_drawlabel(dpy, &d); - } - draw_client(f->client); - XSync(dpy, False); -} - -void -handle_frame_buttonpress(XButtonEvent * e, Frame * f) -{ - Align align; - int bindex; - Layout *l = sel_layout(); - if(l != f->layout) - focus_layout(f->layout); - l = f->layout; - l->def->focus(l, f->client, False); - if(e->button == Button1) { - align = cursor_to_align(f->cursor); - if(align == CENTER) - mouse_move(f); - else - mouse_resize(f, align); - return; - } - bindex = WM_EVENT_B2PRESS - 2 + e->button; - /* frame mouse handling */ - if(def[bindex]->content) - wmii_spawn(dpy, def[bindex]->content); -} - -void -attach_client_to_frame(Frame * f, Client * c) -{ - f->client = c; - c->frame = f; - resize_frame(f, &f->rect, 0); - reparent_client(c, f->win, c->rect.x, c->rect.y); - map_client(c); -} - -void -detach_client_from_frame(Client * c, Bool unmap) -{ - Frame *f = c->frame; - - c->frame = nil; - if(f->sel == c) - f->sel = nil; - - f->client = nil; - - if(!c->destroyed) { - if(!unmap) { - attach_detached(c); - unmap_client(c); - } - c->rect.x = f->rect.x; - c->rect.y = f->rect.y; - reparent_client(c, root, c->rect.x, c->rect.y); - } -} - -static Frame * -handle_before_read_frames(IXPServer *s, File *file, Layout *l) -{ - Frame *f; - char buf[32]; - if(!l->def) - return nil; - for(f = l->def->frames(l); f; f = f->next) { - if(file == f->file[F_GEOMETRY]) { - snprintf(buf, sizeof(buf), "%d %d %d %d", f->rect.x, f->rect.y, - f->rect.width, f->rect.height); - if(file->content) - free(file->content); - file->content = cext_estrdup(buf); - file->size = strlen(buf); - return f; - } - else if(file == f->file[F_NAME]) { - if(file->content) - free(file->content); - if(f->sel && f->sel->name) { - file->content = cext_estrdup(f->sel->name); - file->size = strlen(f->sel->name); - } - else { - file->content = nil; - file->size = 0; - } - return f; - } - } - return nil; -} - -static void -handle_before_read_frame(IXPServer * s, File * file) -{ - Page *p; - for(p = pages; p; p = p->next) { - if(handle_before_read_frames(s, file, p->managed) - || handle_before_read_frames(s, file, p->floating)) - return; - } -} - -static Frame * -handle_after_write_frames(IXPServer *s, File *file, Layout *l) -{ - Frame *f; - for(f = l->def->frames(l); f; f = f->next) { - if(file == f->file[F_TAB] || file == f->file[F_BORDER] - || file == f->file[F_HANDLE_INC]) { - f->layout->def->arrange(f->layout); - return f; - } else if(file == f->file[F_GEOMETRY]) { - char *geom = f->file[F_GEOMETRY]->content; - if(geom && strrchr(geom, ' ')) { - XRectangle frect = f->rect; - blitz_strtorect(&rect, &frect, geom); - resize_frame(f, &frect, 0); - } - return f; - } - } - return nil; -} - -static void -handle_after_write_frame(IXPServer * s, File * file) -{ - Page *p; - for(p = pages; p; p = p->next) { - if(handle_after_write_frames(s, file, p->managed) - || handle_after_write_frames(s, file, p->floating)) - return; - } -} - -Frame * -sel_frame() -{ - Client *c = sel_client(); - return c ? c->frame : nil; -} diff --git a/cmd/wm/layout_column.c b/cmd/wm/layout_column.c @@ -1,634 +0,0 @@ -/* - * (C)opyright MMIV-MMVI Anselm R. Garbe <garbeam at gmail dot com> - * See LICENSE file for license details. - */ - -#include <stdlib.h> -#include <string.h> -#include <math.h> - -#include "wm.h" -#include "layoutdef.h" - -typedef struct Acme Acme; -typedef struct Column Column; -typedef struct Cell Cell; - -struct Acme { - Column *sel; - Column *columns; - size_t ncolumns; - Frame *frames; - size_t nframes; -}; - -struct Cell { - Frame *frame; - Cell *next; - Cell *prev; - Column *column; -}; - -struct Column { - Cell *sel; - Cell *cells; - size_t ncells; - XRectangle rect; - Column *prev; - Column *next; -}; - -static void init_column(Layout *l, Client * clients); -static Client *deinit_column(Layout *l); -static void arrange_column(Layout *l); -static Bool attach_column(Layout *l, Client * c); -static void detach_column(Layout *l, Client * c, Bool unmap); -static void resize_column(Frame * f, XRectangle * new, XPoint * pt); -static void focus_column(Layout *l, Client *c, Bool raise); -static Frame *frames_column(Layout *l); -static Client *sel_column(Layout *l); -static Action *actions_column(Layout *l); - -static void select_frame(void *obj, char *arg); -static void max_frame(void *obj, char *arg); -static void swap_frame(void *obj, char *arg); -static void new_column(void *obj, char *arg); - -static Action lcol_acttbl[] = { - {"select", select_frame}, - {"swap", swap_frame}, - {"new", new_column}, - {"max", max_frame}, - {0, 0} -}; - -void -init_layout_column() -{ - LayoutDef *lp, *l = cext_emallocz(sizeof(LayoutDef)); - l->name = "column"; - l->init = init_column; - l->deinit = deinit_column; - l->arrange = arrange_column; - l->attach = attach_column; - l->detach = detach_column; - l->resize = resize_column; - l->focus = focus_column; - l->frames = frames_column; - l->sel = sel_column; - l->actions = actions_column; - - for(lp = layouts; lp && lp->next; lp = lp->next); - if(lp) - lp->next = l; - else - layouts = l; -} - -static void -xarrange_column(Column * column) -{ - Cell *cell; - unsigned int i = 0, h = layout_rect.height / column->ncells; - for(cell = column->cells; cell; cell = cell->next) { - Frame *f = cell->frame; - f->rect = column->rect; - f->rect.y = layout_rect.y + i * h; - if(!cell->next) - f->rect.height = layout_rect.height - f->rect.y + layout_rect.y; - else - f->rect.height = h; - resize_frame(f, &f->rect, 0); - i++; - } -} - -static void -arrange_column(Layout *l) -{ - Acme *acme = l->aux; - Column *column; - for(column = acme->columns; column; column = column->next) - xarrange_column(column); - XSync(dpy, False); -} - -static void -init_column(Layout *l, Client * clients) -{ - Client *n, *c = clients; - - l->aux = cext_emallocz(sizeof(Acme)); - while(c) { - n = c->next; - attach_column(l, c); - c = n; - } -} - -static void -attach_frame(Layout *l, Column * column, Frame * new) -{ - Acme *acme = l->aux; - Cell *c, *cell = cext_emallocz(sizeof(Cell)); - Frame *f; - - cell->frame = new; - cell->column = column; - new->aux = cell; - for(c = column->cells; c && c->next; c = c->next); - if(!c) - column->cells = cell; - else { - c->next = cell; - cell->prev = c; - } - column->ncells++; - - for(f = acme->frames; f && f->next; f = f->next); - if(!f) - acme->frames = new; - else { - f->next = new; - new->prev = f; - } - attach_frame_to_layout(l, new); - acme->nframes++; -} - -static void -detach_frame(Layout *l, Frame * old) -{ - Acme *acme = l->aux; - Cell *cell = old->aux; - Column *column = cell->column; - - if(cell->prev) - cell->prev->next = cell->next; - else - column->cells = cell->next; - if(cell->next) - cell->next->prev = cell->prev; - - if(column->sel == cell) - column->sel = column->cells; - - free(cell); - column->ncells--; - - if(old->prev) - old->prev->next = old->next; - else - acme->frames = old->next; - if(old->next) - old->next->prev = old->prev; - old->prev = old->next = nil; - old->aux = nil; - detach_frame_from_layout(old); - acme->nframes--; -} - -static Client * -deinit_column(Layout *l) -{ - Acme *acme = l->aux; - Frame *f; - Client *cl, *res = nil, *c = nil; - Column *column = acme->columns; - - while((f = acme->frames)) { - cl = f->client; - detach_client_from_frame(cl, False); - cl->prev = cl->next = 0; - if(!c) - res = c = cl; - else { - c->next = cl; - cl->prev = c; - c = cl; - } - detach_frame(l, f); - destroy_frame(f); - } - while((column = acme->columns)) { - acme->columns = column->next; - free(column); - } - free(acme); - l->aux = 0; - return res; -} - -static Bool -attach_column(Layout *l, Client * c) -{ - Acme *acme = l->aux; - Column *column = acme->sel; - Frame *f = nil; - - if(!column) { - column = cext_emallocz(sizeof(Column)); - column->rect = layout_rect; - acme->columns = acme->sel = column; - acme->ncolumns++; - } - - f = alloc_frame(&c->rect); - attach_frame(l, column, f); - attach_client_to_frame(f, c); - xarrange_column(column); - if(l->page == selpage) - XMapWindow(dpy, f->win); - focus_column(l, c, True); - return True; -} - -static void -update_column_width(Layout *l) -{ - Acme *acme = l->aux; - unsigned int i = 0, width; - Column *column; - - if(!acme->ncolumns) - return; - - width = layout_rect.width / acme->ncolumns; - for(column = acme->columns; column; column = column->next) { - column->rect = layout_rect; - column->rect.x = i * width; - column->rect.width = width; - i++; - } - arrange_column(l); -} - -static void -detach_column(Layout *l, Client * c, Bool unmap) -{ - Acme *acme = l->aux; - Frame *f = c->frame; - Cell *old = f->aux; - Column *column = old->column; - - detach_client_from_frame(c, unmap); - detach_frame(l, f); - destroy_frame(f); - if(column->cells) { - if(column->sel == old) - column->sel = column->cells; - xarrange_column(column); - } - else { - if(acme->sel == column) { - if(column->prev) - acme->sel = column->prev; - else - acme->sel = nil; - } - if(column->prev) - column->prev->next = column->next; - else - acme->columns = column->next; - if(column->next) - column->next->prev = column->prev; - if(!acme->sel) - acme->sel = acme->columns; - acme->ncolumns--; - free(column); - update_column_width(l); - } -} - -static void -match_frame_horiz(Column * column, XRectangle * r) -{ - Cell *cell; - for(cell = column->cells; cell; cell = cell->next) { - Frame *f = cell->frame; - f->rect.x = r->x; - f->rect.width = r->width; - resize_frame(f, &f->rect, nil); - } -} - -static void -drop_resize(Frame * f, XRectangle * new) -{ - Column *west = nil, *east = nil, *column = nil; - Cell *north = nil, *south = nil; - Cell *cell = f->aux; - - column = cell->column; - west = column->prev; - east = column->next; - north = cell->prev; - south = cell->next; - - /* horizontal resize */ - if(west && (new->x != f->rect.x)) { - west->rect.width = new->x - west->rect.x; - column->rect.width += f->rect.x - new->x; - column->rect.x = new->x; - match_frame_horiz(west, &west->rect); - match_frame_horiz(column, &column->rect); - } - if(east && (new->x + new->width != f->rect.x + f->rect.width)) { - east->rect.width -= new->x + new->width - east->rect.x; - east->rect.x = new->x + new->width; - column->rect.x = new->x; - column->rect.width = new->width; - match_frame_horiz(column, &column->rect); - match_frame_horiz(east, &east->rect); - } - - /* vertical resize */ - if(north && (new->y != f->rect.y)) { - north->frame->rect.height = new->y - north->frame->rect.y; - f->rect.height += f->rect.y - new->y; - f->rect.y = new->y; - resize_frame(north->frame, &north->frame->rect, nil); - resize_frame(f, &f->rect, nil); - } - if(south && (new->y + new->height != f->rect.y + f->rect.height)) { - south->frame->rect.height -= - new->y + new->height - south->frame->rect.y; - south->frame->rect.y = new->y + new->height; - f->rect.y = new->y; - f->rect.height = new->height; - resize_frame(f, &f->rect, nil); - resize_frame(south->frame, &south->frame->rect, nil); - } -} - -static void -drop_moving(Frame * f, XRectangle * new, XPoint * pt) -{ - Layout *l = f->layout; - Cell *cell = f->aux; - Column *src = cell->column, *tgt = 0; - Acme *acme = l->aux; - - if(!pt) - return; - - for(tgt = acme->columns; - tgt && !blitz_ispointinrect(pt->x, pt->y, &tgt->rect); - tgt = tgt->next); - if(tgt) { - if(tgt != src) { - if(src->ncells < 2) - return; - detach_frame(l, f); - attach_frame(l, tgt, f); - xarrange_column(src); - xarrange_column(tgt); - focus_column(l, f->sel, True); - } else { - Cell *c; - for(c = src->cells; - c && !blitz_ispointinrect(pt->x, pt->y, &c->frame->rect); - c = c->next); - if(c && c != cell) { - Frame *tmp = c->frame; - c->frame = f; - cell->frame = tmp; - xarrange_column(src); - focus_column(l, f->sel, True); - } - } - } -} - -static void -resize_column(Frame * f, XRectangle * new, XPoint * pt) -{ - if((f->rect.width == new->width) - && (f->rect.height == new->height)) - drop_moving(f, new, pt); - else - drop_resize(f, new); -} - -static void -focus_column(Layout *l, Client *c, Bool raise) -{ - Acme *acme = l->aux; - Cell *cell = c->frame->aux; - Client *old = sel_client(); - - c->frame->sel = c; - acme->sel = cell->column; - cell->column->sel = cell; - l->file[L_SEL_FRAME]->content = c->frame->file[F_PREFIX]->content; - - if(raise) - XWarpPointer(dpy, None, c->win, 0, 0, 0, 0, - c->rect.width / 2, c->rect.height / 2); - - focus_client(c, old); -} - -static Frame * -frames_column(Layout *l) -{ - Acme *acme = l->aux; - return acme->frames; -} - -static Client * -sel_column(Layout *l) -{ - Acme *acme = l->aux; - Column *column = acme->sel; - - if(column && column->sel) - return column->sel->frame->sel; - return nil; -} - -static Action * -actions_column(Layout *l) -{ - return lcol_acttbl; -} - -static void -max_frame(void *obj, char *arg) -{ - Layout *l = obj; - Acme *acme = l->aux; - Column *c = acme->sel; - Cell *cell; - Frame *f; - - if(!c) - return; - - cell = c->sel; - if(!cell) - return; - - f = cell->frame; - if(f->maximized) { - f->rect = f->old; - resize_frame(f, &f->old, nil); - f->maximized = False; - } - else { - f->old = f->rect; - f->rect = c->rect; - XRaiseWindow(dpy, f->win); - resize_frame(f, &c->rect, nil); - f->maximized = True; - } -} - -static void -select_frame(void *obj, char *arg) -{ - Layout *l = obj; - Acme *acme = l->aux; - Column *c, *column = acme->sel; - Cell *cell; - - if(!column) - return; - - cell = column->sel; - if(!cell || !arg) - return; - if(!strncmp(arg, "prev", 5)) { - if(cell->prev) - cell = cell->prev; - else - for(cell = column->cells; cell && cell->next; cell = cell->next); - } else if(!strncmp(arg, "next", 5)) { - if(cell->next) - cell = cell->next; - else - cell = column->cells; - } else if(!strncmp(arg, "west", 5)) { - if(column->prev) - cell = column->prev->sel; - else { - for(c = acme->columns; c && c->next; c = c->next); - cell = c->sel; - } - } else if(!strncmp(arg, "east", 5)) { - if(column->next) - cell = column->next->sel; - else - cell = acme->columns->sel; - } else { - unsigned int i = 0, idx = blitz_strtonum(arg, 0, column->ncells - 1); - for(cell = column->cells; cell && i != idx; cell = cell->next) - i++; - } - if(cell && cell != column->sel) - focus_column(l, cell->frame->sel, True); -} - -static void -swap_frame(void *obj, char *arg) -{ - Layout *l = obj; - Acme *acme = l->aux; - Column *west = nil, *east = nil, *column = acme->sel; - Cell *north = nil, *south = nil, *cell = column->sel; - Frame *f; - XRectangle r; - - if(!column || !cell || !arg) - return; - - west = column->prev; - east = column->next; - north = cell->prev; - south = cell->next; - - if(!west) - west = east; - if(!east) - east = west; - - if(!strncmp(arg, "north", 6) && north) { - r = north->frame->rect; - north->frame->rect = cell->frame->rect; - cell->frame->rect = r; - f = north->frame; - north->frame = cell->frame; - cell->frame = f; - cell->frame->aux = cell; - north->frame->aux = north; - resize_frame(cell->frame, &cell->frame->rect, nil); - resize_frame(north->frame, &north->frame->rect, nil); - focus_column(l, cell->frame->sel, True); - } else if(!strncmp(arg, "south", 6) && south) { - r = south->frame->rect; - south->frame->rect = cell->frame->rect; - cell->frame->rect = r; - f = south->frame; - south->frame = cell->frame; - cell->frame = f; - cell->frame->aux = cell; - south->frame->aux = south; - resize_frame(cell->frame, &cell->frame->rect, nil); - resize_frame(south->frame, &south->frame->rect, nil); - focus_column(l, cell->frame->sel, True); - } else if(!strncmp(arg, "west", 5) && west && column->ncells && west->ncells) { - Cell *other = west->sel; - r = other->frame->rect; - other->frame->rect = cell->frame->rect; - cell->frame->rect = r; - f = other->frame; - other->frame = cell->frame; - cell->frame = f; - other->frame->aux = other; - cell->frame->aux = cell; - resize_frame(cell->frame, &cell->frame->rect, nil); - resize_frame(other->frame, &other->frame->rect, nil); - focus_column(l, other->frame->sel, True); - } else if(!strncmp(arg, "east", 5) && east && column->ncells && east->ncells) { - Cell *other = east->sel; - r = other->frame->rect; - other->frame->rect = cell->frame->rect; - cell->frame->rect = r; - f = other->frame; - other->frame = cell->frame; - cell->frame = f; - other->frame->aux = other; - cell->frame->aux = cell; - resize_frame(cell->frame, &cell->frame->rect, nil); - resize_frame(other->frame, &other->frame->rect, nil); - focus_column(l, other->frame->sel, True); - } -} - -static void -new_column(void *obj, char *arg) -{ - Layout *l = obj; - Acme *acme = l->aux; - Column *c, *new, *column = acme->sel; - Frame *f; - - if(!column || column->ncells < 2) - return; - - f = column->sel->frame; - for(c = acme->columns; c && c->next; c = c->next); - - new = cext_emallocz(sizeof(Column)); - new->rect = layout_rect; - new->prev = c; - c->next = new; - acme->ncolumns++; - acme->sel = new; - - detach_frame(l, f); - attach_frame(l, new, f); - - update_column_width(l); - focus_column(l, f->sel, True); -} diff --git a/cmd/wm/mklayout.sh b/cmd/wm/mklayout.sh @@ -1,12 +0,0 @@ -#!/bin/sh -rm -f layoutdef.h layoutdef.c layout.mk -echo "#include \"layoutdef.h\"" > layoutdef.c -echo "#include \"wm.h\"" >> layoutdef.c -echo "void init_layouts() {" >> layoutdef.c -for i in `ls layout_*.c`; do - FUNC="`echo \`basename $i\` | sed 's/\.c//g'`" - echo "void init_$FUNC();" >> layoutdef.h - echo " init_$FUNC();" >> layoutdef.c; - echo "SRC += $i" >>layoutdef.mk -done -echo "}" >> layoutdef.c diff --git a/cmd/wm/mouse.c b/cmd/wm/mouse.c @@ -290,7 +290,7 @@ draw_pseudo_border(XRectangle * r) pseudo.y += 2; pseudo.width -= 4; pseudo.height -= 4; - XDrawRectangles(dpy, root, xorgc, &pseudo, 1); + XDrawRectangles(dpy, root, gc_xor, &pseudo, 1); XSync(dpy, False); } diff --git a/cmd/wm/page.c b/cmd/wm/page.c @@ -72,7 +72,7 @@ destroy_page(Page * p) return; Page *newselpage; - AttachQueue *o, *n; + MapQueue *o, *n; while(attachqueue && (attachqueue->page == p)) { n = attachqueue->next; @@ -235,13 +235,13 @@ handle_after_write_page(IXPServer * s, File * file) static void xexec(void *obj, char *arg) { - AttachQueue *r; + MapQueue *r; if(!attachqueue) - r = attachqueue = cext_emallocz(sizeof(AttachQueue)); + r = attachqueue = cext_emallocz(sizeof(MapQueue)); else { for(r = attachqueue; r && r->next; r = r->next); - r->next = cext_emallocz(sizeof(AttachQueue)); + r->next = cext_emallocz(sizeof(MapQueue)); r = r->next; } r->page = obj; @@ -258,13 +258,3 @@ toggle_layout(void *obj, char *arg) else focus_layout(p->managed); } - -Page * -pageat(unsigned int idx) -{ - unsigned int i = 0; - Page *p; - for(p = pages; p && i != idx; p = p->next) - i++; - return p; -} diff --git a/cmd/wm/wm.c b/cmd/wm/wm.c @@ -116,73 +116,69 @@ scale_rect(XRectangle * from_dim, XRectangle * to_dim, } static void -draw_pager_layout(Layout *l, Draw * d) -{ - Frame *f; - Frame *sel = sel_frame(); - if(!l->def) - return; - for(f = l->def->frames(l); f; f = f->next) { - if(f == sel) { - d->bg = blitz_loadcolor(dpy, screen_num, def[WM_SEL_BG_COLOR]->content); - d->fg = blitz_loadcolor(dpy, screen_num, def[WM_SEL_FG_COLOR]->content); - d->border = blitz_loadcolor(dpy, screen_num, def[WM_SEL_BORDER_COLOR]->content); - } else { - d->bg = blitz_loadcolor(dpy, screen_num, def[WM_NORM_BG_COLOR]->content); - d->fg = blitz_loadcolor(dpy, screen_num, def[WM_NORM_FG_COLOR]->content); - d->border = blitz_loadcolor(dpy, screen_num, def[WM_NORM_BORDER_COLOR]->content); - } - d->data = f->sel->name; - scale_rect(&rect, &initial_rect, &f->rect, &d->rect); - blitz_drawlabel(dpy, d); - XSync(dpy, False); /* do not clear upwards */ +draw_pager_client(Client *c, Draw *d) +{ + if(c == sel_client()) { + d->bg = blitz_loadcolor(dpy, screen, def[WM_SEL_BG_COLOR]->content); + d->fg = blitz_loadcolor(dpy, screen, def[WM_SEL_FG_COLOR]->content); + d->border = blitz_loadcolor(dpy, screen, def[WM_SEL_BORDER_COLOR]->content); + } else { + d->bg = blitz_loadcolor(dpy, screen, def[WM_NORM_BG_COLOR]->content); + d->fg = blitz_loadcolor(dpy, screen, def[WM_NORM_FG_COLOR]->content); + d->border = blitz_loadcolor(dpy, screen, def[WM_NORM_BORDER_COLOR]->content); } + d->data = c->name; + scale_rect(&rect, &initial_rect, &c->frame.rect, &d->rect); + blitz_drawlabel(dpy, d); + XSync(dpy, False); /* do not clear upwards */ } static void -draw_pager_page(Page * p, Draw * d) +draw_pager_page(size_t idx, Draw *d) { - unsigned int idx = 1; + size_t i, j; char name[4]; initial_rect = d->rect; - Page *page; - if(p == selpage) { - d->bg = blitz_loadcolor(dpy, screen_num, def[WM_SEL_BG_COLOR]->content); - d->fg = blitz_loadcolor(dpy, screen_num, def[WM_SEL_FG_COLOR]->content); - d->border = blitz_loadcolor(dpy, screen_num, def[WM_SEL_BORDER_COLOR]->content); + if(idx == sel_page) { + d->bg = blitz_loadcolor(dpy, screen, def[WM_SEL_BG_COLOR]->content); + d->fg = blitz_loadcolor(dpy, screen, def[WM_SEL_FG_COLOR]->content); + d->border = blitz_loadcolor(dpy, screen, def[WM_SEL_BORDER_COLOR]->content); } else { - d->bg = blitz_loadcolor(dpy, screen_num, def[WM_NORM_BG_COLOR]->content); - d->fg = blitz_loadcolor(dpy, screen_num, def[WM_NORM_FG_COLOR]->content); - d->border = blitz_loadcolor(dpy, screen_num, def[WM_NORM_BORDER_COLOR]->content); + d->bg = blitz_loadcolor(dpy, screen, def[WM_NORM_BG_COLOR]->content); + d->fg = blitz_loadcolor(dpy, screen, def[WM_NORM_FG_COLOR]->content); + d->border = blitz_loadcolor(dpy, screen, def[WM_NORM_BORDER_COLOR]->content); } - for(page = pages; page && page != p; page = page->next) - idx++; - snprintf(name, sizeof(name), "%d", idx); + snprintf(name, sizeof(name), "%d", idx + 1); d->data = name; blitz_drawlabel(dpy, d); XSync(dpy, False); - if(p->managed) - draw_pager_layout(p->managed, d); - draw_pager_layout(p->floating, d); + + for(i = 0; (i < pages[idx]->managedsz) && pages[idx]->managed[i]; i++) { + Column *col = pages[idx]->managed[i]; + for(j = 0; (i < col->clientssz) && col->clients[j]; j++) + draw_pager_client(col->clients[j], d); + } + for(i = 0; (i < pages[idx]->floatingsz) && pages[idx]->floating[i]; i++) + draw_pager_client(pages[idx]->floating[i], d); } static void draw_pager() { Draw d = { 0 }; - unsigned int ic, ir, tw, th, rows, cols; + unsigned int i, ic, ir, tw, th, rows, cols; int dx; - Page *p; - blitz_getbasegeometry(npages, &cols, &rows); + for(i = 0; (i < pagessz) && pages[i]; i++); + blitz_getbasegeometry(i, &cols, &rows); dx = (cols - 1) * GAP; /* GAPpx space */ tw = (rect.width - dx) / cols; th = ((double) tw / rect.width) * rect.height; d.drawable = transient; - d.gc = transient_gc; + d.gc = gc_transient; d.font = font; - p = pages; + i = 0; for(ir = 0; ir < rows; ir++) { for(ic = 0; ic < cols; ic++) { d.rect.x = ic * tw + (ic * GAP); @@ -192,28 +188,27 @@ draw_pager() else d.rect.y = ir * (rect.height - th) / (rows - 1); d.rect.height = th; - draw_pager_page(p, &d); - if(!p->next) + draw_pager_page(i++, &d); + if(!pages[i]) return; - p = p->next; } } } -static Page * +static int xy_to_pager_page(int x, int y) { - unsigned int ic, ir, tw, th, rows, cols; + unsigned int i, ic, ir, tw, th, rows, cols; int dx; XRectangle r; - Page *p; - blitz_getbasegeometry(npages, &cols, &rows); + for(i = 0; (i < pagessz) && pages[i]; i++); + blitz_getbasegeometry(i, &cols, &rows); dx = (cols - 1) * GAP; /* GAPpx space */ tw = (rect.width - dx) / cols; th = ((double) tw / rect.width) * rect.height; - p = pages; + i = 0; for(ir = 0; ir < rows; ir++) { for(ic = 0; ic < cols; ic++) { r.x = ic * tw + (ic * GAP); @@ -224,13 +219,13 @@ xy_to_pager_page(int x, int y) r.y = ir * (rect.height - th) / (rows - 1); r.height = th; if(blitz_ispointinrect(x, y, &r)) - return p; - if(!p->next) - return nil; - p = p->next; + return i; + i++; + if(!pages[i]) + return -1; } } - return nil; + return -1; } static int @@ -253,10 +248,13 @@ pager(void *obj, char *arg) { XEvent ev; int i; + size_t j; if(!pages) return; + for(j = 0; (j < pagessz) && pages[j]; j++); + XClearWindow(dpy, transient); XMapRaised(dpy, transient); draw_pager(); @@ -282,8 +280,8 @@ pager(void *obj, char *arg) case KeyPress: XUnmapWindow(dpy, transient); if((i = handle_kpress(&ev.xkey)) != -1) - if(i < npages) - focus_page(pageat(i)); + if(i < j) + focus_page(i); XUngrabKeyboard(dpy, CurrentTime); XUngrabPointer(dpy, CurrentTime /* ev.xbutton.time */ ); return; @@ -303,12 +301,12 @@ pager(void *obj, char *arg) static void map_detached_clients() { - unsigned int ic, ir, tw, th, rows, cols; + unsigned int i, ic, ir, tw, th, rows, cols; int dx, dy; - Client *c = detached; XRectangle cr; - blitz_getbasegeometry(ndetached, &cols, &rows); + for(i = 0; detached && detached[i]; i++); + blitz_getbasegeometry(i, &cols, &rows); if(!cols) cols = 1; if(!rows) @@ -318,21 +316,21 @@ map_detached_clients() tw = (rect.width - dx) / cols; th = (rect.height - dy) / rows; + i = 0; for(ir = 0; ir < rows; ir++) { for(ic = 0; ic < cols; ic++) { - if(!c) + if(!detached[i++]) return; cr.x = ic * tw + (ic * GAP); cr.y = ir * th + (ir * GAP); cr.width = tw; cr.height = th; - XMoveResizeWindow(dpy, c->win, cr.x, cr.y, cr.width, cr.height); - configure_client(c); - map_client(c); - grab_client(c, AnyModifier, Button1); - XRaiseWindow(dpy, c->win); + XMoveResizeWindow(dpy, detached[i]->win, cr.x, cr.y, cr.width, cr.height); + configure_client(detached[i]); + map_client(detached[i]); + grab_client(detached[i], AnyModifier, Button1); + XRaiseWindow(dpy, detached[i]->win); XSync(dpy, False); - c = c->next; } } } @@ -342,9 +340,11 @@ detached_clients(void *obj, char *arg) { XEvent ev; int n; - Client *c = detached; + size_t i, nc; + Client *c; - if(!c) + for(nc = 0; detached && detached[nc]; nc++); + if(!nc) return; XClearWindow(dpy, transient); XMapRaised(dpy, transient); @@ -362,12 +362,12 @@ detached_clients(void *obj, char *arg) switch (ev.type) { case KeyPress: XUnmapWindow(dpy, transient); - for(c = detached; c; c = c->next) - unmap_client(c); + for(i = 0; detached[i]; i++) + unmap_client(detached[i]); if((n = handle_kpress(&ev.xkey)) != -1) { - if((c = clientat(detached, n))) { - detach_detached(c); - attach_client(c); + if(n < nc) { + detach_detached(detached[n]); + attach_client(detached[n]); } } XUngrabKeyboard(dpy, CurrentTime); @@ -375,8 +375,8 @@ detached_clients(void *obj, char *arg) break; case ButtonPress: XUnmapWindow(dpy, transient); - for(c = detached; c; c = c->next) - unmap_client(c); + for(i = 0; detached[i]; i++) + unmap_client(detached[i]); if((ev.xbutton.button == Button1) && (c = win_to_client(ev.xbutton.window))) { detach_detached(c); @@ -400,7 +400,7 @@ xclose_client(void *obj, char *arg) static void xattach_client(void *obj, char *arg) { - Client *c = detached; + Client *c = detached ? detached[0] : nil; if(c) { detach_detached(c); attach_client(c); @@ -418,34 +418,32 @@ xdetach_client(void *obj, char *arg) static void xselect_page(void *obj, char *arg) { - Page *p = selpage; - if(!p || !arg) + size_t np; + + for(np = 0; (np < pagessz) && pages[np]; np++); + if(!np || !arg) return; if(!strncmp(arg, "prev", 5)) { - if(p->prev) - p = p->prev; - else - for(p = pages; p && p->next; p = p->next); + if(sel_page > 0) + for(sel_page = 0; pages[sel_page]; sel_page++); + sel_page--; } else if(!strncmp(arg, "next", 5)) { - if(p->next) - p = p->next; - else - p = pages; - } else { - int idx = blitz_strtonum(arg, 0, pageid); - if(idx) - idx--; + if(pages[sel_page + 1]) + sel_page++; else - idx = 9; - p = pageat(idx); + sel_page = 0; + } else { + int idx = blitz_strtonum(arg, 0, np); + if(idx < np) + sel_page = idx; } - focus_page(p); + focus_page(sel_page); } static void xdestroy_page(void *obj, char *arg) { - destroy_page(selpage); + destroy_page(sel_page); } static void @@ -457,24 +455,12 @@ new_page(void *obj, char *arg) Client * win_to_client(Window w) { - Page *p; - Client *c; - for(c = detached; c; c = c->next) - if(c->win == w) - return c; - for(p = pages; p; p = p->next) { - Frame *f; - if(p->managed->def) - for(f = p->managed->def->frames(p->managed); f; f = f->next) { - if(f->client->win == w) - return f->client; - } - for(f = p->floating->def->frames(p->floating); f; f = f->next) { - if(f->client->win == w) - return f->client; - } - } - return nil; + size_t i; + + for(i = 0; clients && clients[i]; i++) + if(clients[i]->win == w) + return clients[i]; + return nil; } void @@ -495,8 +481,7 @@ scan_wins() || XGetTransientForHint(dpy, wins[i], &d1)) continue; if(wa.map_state == IsViewable) { - c = alloc_client(wins[i]); - init_client(c, &wa); + c = alloc_client(wins[i], &wa); attach_client(c); c->ignore_unmap++; /* was viewable already */ } @@ -563,31 +548,6 @@ win_state(Window w) return res; } -static void -update_pages() -{ - Page *p; - - for(p = pages; p; p = p->next) { - p->floating->def->arrange(p->floating); - p->managed->def->arrange(p->managed); - } -} - -void -handle_before_read(IXPServer * s, File * f) -{ - char buf[64]; - if(f == def[WM_MANAGED_GEOMETRY]) { - snprintf(buf, 64, "%d %d %d %d", layout_rect.x, layout_rect.y, - layout_rect.width, layout_rect.height); - if(f->content) - free(f->content); - f->content = cext_estrdup(buf); - f->size = strlen(buf); - } -} - void handle_after_write(IXPServer * s, File * f) { @@ -595,22 +555,15 @@ handle_after_write(IXPServer * s, File * f) run_action(f, 0, wm_acttbl); else if(f == def[WM_TRANS_COLOR]) { unsigned long col[1]; - col[0] = xorcolor.pixel; - XFreeColors(dpy, DefaultColormap(dpy, screen_num), col, 1, 0); - XAllocNamedColor(dpy, DefaultColormap(dpy, screen_num), + col[0] = color_xor.pixel; + XFreeColors(dpy, DefaultColormap(dpy, screen), col, 1, 0); + XAllocNamedColor(dpy, DefaultColormap(dpy, screen), def[WM_TRANS_COLOR]->content, - &xorcolor, &xorcolor); - XSetForeground(dpy, xorgc, xorcolor.pixel); + &color_xor, &color_xor); + XSetForeground(dpy, gc_xor, color_xor.pixel); } else if(f == def[WM_FONT]) { XFreeFont(dpy, font); font = blitz_getfont(dpy, def[WM_FONT]->content); - } else if(f == def[WM_MANAGED_GEOMETRY]) { - char *geom = def[WM_MANAGED_GEOMETRY]->content; - if(geom && strrchr(geom, ' ')) { - layout_rect = rect; - blitz_strtorect(&rect, &layout_rect, geom); - update_pages(); - } } check_event(0); } @@ -653,11 +606,7 @@ init_default() wmii_create_ixpfile(ixps, "/default/transcolor", BLITZ_SEL_FG_COLOR); def[WM_TRANS_COLOR]->after_write = handle_after_write; - def[WM_MANAGED_GEOMETRY] = - wmii_create_ixpfile(ixps, "/default/geometry", - BLITZ_SEL_FG_COLOR); - def[WM_MANAGED_GEOMETRY]->after_write = handle_after_write; - def[WM_MANAGED_GEOMETRY]->before_read = handle_before_read; + def[WM_MANAGED_GEOMETRY] = wmii_create_ixpfile(ixps, "/default/geometry", BLITZ_SEL_FG_COLOR); def[WM_SEL_BG_COLOR] = wmii_create_ixpfile(ixps, "/default/sstyle/bgcolor", BLITZ_SEL_BG_COLOR); @@ -673,17 +622,14 @@ init_default() def[WM_NORM_FG_COLOR] = wmii_create_ixpfile(ixps, "/default/nstyle/fgcolor", BLITZ_NORM_FG_COLOR); - def[WM_NORM_BORDER_COLOR] = - wmii_create_ixpfile(ixps, "/default/nstyle/bordercolor", + def[WM_NORM_BORDER_COLOR] = wmii_create_ixpfile(ixps, "/default/nstyle/bordercolor", BLITZ_NORM_BORDER_COLOR); def[WM_FONT] = wmii_create_ixpfile(ixps, "/default/font", BLITZ_FONT); def[WM_FONT]->after_write = handle_after_write; def[WM_SNAP_VALUE] = wmii_create_ixpfile(ixps, "/default/snapvalue", "20"); /* 0..1000 */ def[WM_BORDER] = wmii_create_ixpfile(ixps, "/default/border", "1"); def[WM_TAB] = wmii_create_ixpfile(ixps, "/default/tab", "1"); - def[WM_HANDLE_INC] = - wmii_create_ixpfile(ixps, "/default/handleinc", "1"); - def[WM_LAYOUT] = wmii_create_ixpfile(ixps, "/default/layout", LAYOUT); + def[WM_HANDLE_INC] = wmii_create_ixpfile(ixps, "/default/handleinc", "1"); def[WM_SEL_PAGE] = ixp_create(ixps, "/sel"); def[WM_EVENT_PAGE_UPDATE] = ixp_create(ixps, "/event/pageupdate"); def[WM_EVENT_CLIENT_UPDATE] = ixp_create(ixps, "/event/clientupdate"); @@ -700,34 +646,33 @@ init_screen() XGCValues gcv; XSetWindowAttributes wa; - XAllocNamedColor(dpy, DefaultColormap(dpy, screen_num), - def[WM_TRANS_COLOR]->content, &xorcolor, &xorcolor); + XAllocNamedColor(dpy, DefaultColormap(dpy, screen), + def[WM_TRANS_COLOR]->content, &color_xor, &color_xor); gcv.subwindow_mode = IncludeInferiors; gcv.function = GXxor; - gcv.foreground = xorcolor.pixel; + gcv.foreground = color_xor.pixel; gcv.line_width = 4; gcv.plane_mask = AllPlanes; gcv.graphics_exposures = False; - xorgc = XCreateGC(dpy, root, GCForeground | GCGraphicsExposures + gc_xor = XCreateGC(dpy, root, GCForeground | GCGraphicsExposures | GCFunction | GCSubwindowMode | GCLineWidth | GCPlaneMask, &gcv); rect.x = rect.y = 0; - rect.width = DisplayWidth(dpy, screen_num); - rect.height = DisplayHeight(dpy, screen_num); - layout_rect = rect; + rect.width = DisplayWidth(dpy, screen); + rect.height = DisplayHeight(dpy, screen); wa.override_redirect = 1; wa.background_pixmap = ParentRelative; wa.event_mask = ExposureMask | ButtonPressMask; transient = XCreateWindow(dpy, root, 0, 0, rect.width, rect.height, 0, - DefaultDepth(dpy, screen_num), CopyFromParent, - DefaultVisual(dpy, screen_num), + DefaultDepth(dpy, screen), CopyFromParent, + DefaultVisual(dpy, screen), CWOverrideRedirect | CWBackPixmap | CWEventMask, &wa); XSync(dpy, False); - transient_gc = XCreateGC(dpy, transient, 0, 0); + gc_transient = XCreateGC(dpy, transient, 0, 0); XDefineCursor(dpy, transient, normal_cursor); XDefineCursor(dpy, root, normal_cursor); } @@ -771,14 +716,12 @@ startup_error_handler(Display * dpy, XErrorEvent * error) static void cleanup() { - Page *p; - for(p = pages; p; p = p->next) { - Frame *f; - for(f = p->managed->def->frames(p->managed); f; f = f->next) - detach_client_from_frame(f->client, False); - for(f = p->floating->def->frames(p->floating); f; f = f->next) - detach_client_from_frame(f->client, False); - } + size_t i; + Client *c; + for(i = 0; clients && clients[i]; i++) { + c = clients[i]; + reparent_client(c, root, c->frame.rect.x + c->rect.x, c->frame.rect.y + c->rect.y); + } XSetInputFocus(dpy, PointerRoot, RevertToPointerRoot, CurrentTime); XSync(dpy, False); } @@ -818,8 +761,8 @@ main(int argc, char *argv[]) fprintf(stderr, "%s", "wmiiwm: cannot open display\n"); exit(1); } - screen_num = DefaultScreen(dpy); - root = RootWindow(dpy, screen_num); + screen = DefaultScreen(dpy); + root = RootWindow(dpy, screen); /* check if another WM is already running */ other_wm_running = 0; @@ -850,20 +793,18 @@ main(int argc, char *argv[]) } def[WM_CTL]->after_write = handle_after_write; - pages = selpage = nil; - ndetached = npages = 0; - pageid = 1; - detached = nil; - layouts = nil; + detachedsz = pagessz = clientssz = sel_page = 0; + pages = nil; + clients = detached = nil; attachqueue = nil; + init_atoms(); init_cursors(); init_default(); font = blitz_getfont(dpy, def[WM_FONT]->content); wmii_init_lock_modifiers(dpy, &valid_mask, &num_lock_mask); init_screen(); - init_layouts(); scan_wins(); /* main event loop */ diff --git a/cmd/wm/wm.h b/cmd/wm/wm.h @@ -13,32 +13,24 @@ enum { P_PREFIX, P_NAME, - P_LAYOUT_PREFIX, - P_SEL_LAYOUT, - P_LAYOUT_NAME, + P_MANAGED_PREFIX, + P_FLOATING_PREFIX, + P_SEL_PREFIX, + P_SEL_MANAGED_CLIENT, + P_SEL_FLOATING_CLIENT, P_CTL, P_LAST }; -/* array indexes of layout file pointers */ -enum { - L_PREFIX, - L_FRAME_PREFIX, - L_SEL_FRAME, - L_NAME, - L_CTL, - L_LAST -}; - /* array indexes of frame file pointers */ enum { - F_PREFIX, - F_NAME, - F_GEOMETRY, - F_BORDER, - F_TAB, - F_HANDLE_INC, - F_LAST + C_PREFIX, + C_NAME, + C_GEOMETRY, + C_BORDER, + C_TAB, + C_HANDLE_INC, + C_LAST }; /* array indexes of wm file pointers */ @@ -58,7 +50,6 @@ enum { WM_HANDLE_INC, WM_SNAP_VALUE, WM_SEL_PAGE, - WM_LAYOUT, WM_EVENT_PAGE_UPDATE, WM_EVENT_CLIENT_UPDATE, WM_EVENT_B1PRESS, @@ -81,110 +72,80 @@ enum { #define PROTO_DEL 1 #define BORDER_WIDTH 3 -#define LAYOUT "column" -#define LAYOUT_FLOAT "float" #define GAP 5 #define ROOT_MASK SubstructureRedirectMask #define CLIENT_MASK (StructureNotifyMask | PropertyChangeMask) +typedef struct MapQueue MapQueue; +typedef struct Column Column; typedef struct Page Page; -typedef struct AttachQueue AttachQueue; -typedef struct LayoutDef LayoutDef; -typedef struct Layout Layout; -typedef struct Frame Frame; typedef struct Client Client; -struct AttachQueue { +struct MapQueue { Page *page; - AttachQueue *next; -}; - -struct Page { - Layout *managed; - Layout *floating; - Layout *sel; - File *file[P_LAST]; - Page *next; - Page *prev; - size_t index; + MapQueue *next; }; -struct LayoutDef { - char *name; - void (*init) (Layout *, Client *); /* called when layout is initialized */ - Client *(*deinit) (Layout *); /* called when layout is uninitialized */ - void (*arrange) (Layout *); /* called when layout is resized */ - Bool(*attach) (Layout *, Client *); /* called on attach */ - void (*detach) (Layout *, Client *, Bool unmap); /* called on detach */ - void (*resize) (Frame *, XRectangle *, XPoint *); /* called after resize */ - void (*focus) (Layout *, Client *, Bool raise); /* focussing a client */ - Frame *(*frames) (Layout *); /* called for drawing */ - Client *(*sel) (Layout *); /* returns selected client */ - Action *(*actions) (Layout *); /* local action table */ - LayoutDef *next; +struct Column { + Client **clients; + size_t clientssz; + size_t sel; }; -struct Layout { - Page *page; - LayoutDef *def; - void *aux; /* auxillary pointer */ - File *file[L_LAST]; -}; - -struct Frame { - Layout *layout; - Window win; - Client *sel; - Client *client; - Bool maximized; - XRectangle old; - GC gc; - XRectangle rect; - Cursor cursor; - void *aux; /* auxillary pointer */ - File *file[F_LAST]; - Frame *next; - Frame *prev; +struct Page { + Client **floating; + Column **managed; + size_t floatingsz; + size_t managedsz; + size_t sel_float; + size_t sel_managed; + Bool is_managed; + XRectangle rect_managed; + File *file[P_LAST]; }; struct Client { + char name[256]; int proto; unsigned int border; unsigned int ignore_unmap; - char name[256]; Bool destroyed; + Bool maximized; Window win; Window trans; XRectangle rect; XSizeHints size; - Frame *frame; - Client *next; - Client *prev; + struct Frame { + Window win; + XRectangle rect; + XRectangle revert; + GC gc; + Cursor cursor; + } frame; + File *file[C_LAST]; }; - /* global variables */ -Page *pages; -Page *selpage; -AttachQueue *attachqueue; -size_t npages; -int pageid; -Client *detached; -size_t ndetached; -LayoutDef *layouts; +Page **pages; +size_t pagessz; +size_t sel_page; +MapQueue *attachqueue; +Client **detached; +size_t detachedsz; +Client **clients; +size_t clientssz; Display *dpy; IXPServer *ixps; -int screen_num; +int screen; Window root; -Window transient; +Window transient; /* pager / attach */ XRectangle rect; -XRectangle layout_rect; XFontStruct *font; -XColor xorcolor; -GC xorgc; -GC transient_gc; +XColor color_xor; +GC gc_xor; +GC gc_transient; Atom wm_state; /* TODO: Maybe replace with wm_atoms[WM_ATOM_COUNT]? */ Atom wm_change_state; @@ -213,8 +174,7 @@ unsigned int valid_mask, num_lock_mask; /* client.c */ -Client *alloc_client(Window w); -void init_client(Client * c, XWindowAttributes * wa); +Client *alloc_client(Window w, XWindowAttributes *wa); void destroy_client(Client * c); void configure_client(Client * c); void handle_client_property(Client * c, XPropertyEvent * e); @@ -233,52 +193,38 @@ Client *clientat(Client * clients, size_t idx); void detach_detached(Client * c); void attach_detached(Client * c); void focus_client(Client *new, Client *old); - -/* frame.c */ -Frame *win_to_frame(Window w); -Frame *alloc_frame(XRectangle * r); -void destroy_frame(Frame * f); -void resize_frame(Frame * f, XRectangle * r, XPoint * pt); -void draw_frame(Frame * f); -void handle_frame_buttonpress(XButtonEvent * e, Frame * f); -void attach_client_to_frame(Frame * f, Client * c); +Client *win_to_frame(Window w); +Client *alloc_frame(XRectangle * r); +void destroy_frame(Client * f); +void resize_frame(Client * f, XRectangle * r, XPoint * pt); +void draw_frame(Client * f); +void handle_frame_buttonpress(XButtonEvent * e, Client * f); +void attach_client_to_frame(Client * f, Client * c); void detach_client_from_frame(Client * client, Bool unmap); -unsigned int tab_height(Frame * f); -unsigned int border_width(Frame * f); -Frame *sel_frame(); +unsigned int tab_height(Client * f); +unsigned int border_width(Client * f); +Client *sel_frame(); /* event.c */ void init_event_hander(); void check_event(Connection * c); /* mouse.c */ -void mouse_resize(Frame * f, Align align); -void mouse_move(Frame * f); -Cursor cursor_for_motion(Frame * f, int x, int y); +void mouse_resize(Client * f, Align align); +void mouse_move(Client * f); +Cursor cursor_for_motion(Client * f, int x, int y); Align cursor_to_align(Cursor cursor); Align xy_to_align(XRectangle * rect, int x, int y); -void drop_move(Frame * f, XRectangle * new, XPoint * pt); +void drop_move(Client * f, XRectangle * new, XPoint * pt); /* page.c */ -Page *pageat(unsigned int idx); -Page *alloc_page(); -void destroy_page(Page * p); -void focus_page(Page * p); +size_t alloc_page(); +void destroy_page(size_t idx); +void focus_page(size_t idx); XRectangle *rectangles(unsigned int *num); -/* layout.c */ -Layout *alloc_layout(Page * p, char *layout); -void destroy_layout(Layout *l); -void focus_layout(Layout *l); -void unmap_layout(Layout *l); -void map_layout(Layout *l, Bool raise); -Layout *sel_layout(); -void attach_frame_to_layout(Layout *l, Frame * f); -void detach_frame_from_layout(Frame * f); -LayoutDef *match_layout_def(char *name); - -/* layoutdef.c */ -void init_layouts(); +/* column.c */ +void arrange_column(Page *p); /* wm.c */ void invoke_wm_event(File * f); @@ -288,5 +234,5 @@ Client *win_to_client(Window w); int win_proto(Window w); int win_state(Window w); void handle_after_write(IXPServer * s, File * f); -void detach(Frame * f, int client_destroyed); +void detach(Client * f, int client_destroyed); void set_client_state(Client * c, int state); diff --git a/doc/RELEASE b/doc/RELEASE @@ -1,11 +1,11 @@ -Abbadon +Abbadon (9base-2) Amare Andariel Andon ArchDean Beth Bethanel -Boyd * (2) +Boyd (wmii-2) Camael Charon Duma @@ -36,9 +36,9 @@ Sandalphon Sophia Sunya Thanatos -Tothiel * (wmii-2.5, 9base-1) +Tothiel (wmii-2.5) Ultimus Maximus -Uriel * (1) +Uriel (wmii-1) Yhprum Zaphkiel -Zadkiel * (1.1) +Zadkiel (wmii-1.1)