wmii/cmd/wm/layout_column.c

606 lines
15 KiB
C
Raw Normal View History

2005-11-18 18:54:58 +03:00
/*
* (C)opyright MMIV-MMVI Anselm R. Garbe <garbeam at gmail dot com>
2005-11-18 18:54:58 +03:00
* See LICENSE file for license details.
*/
#include <stdlib.h>
#include <string.h>
#include <math.h>
#include "wm.h"
#include "layoutdef.h"
2005-11-18 18:54:58 +03:00
typedef struct Acme Acme;
typedef struct Column Column;
typedef struct Cell Cell;
2005-11-18 18:54:58 +03:00
struct Acme {
2005-12-21 18:18:11 +03:00
Column *sel;
Column *columns;
size_t ncolumns;
Frame *frames;
size_t nframes;
};
struct Cell {
2005-12-21 18:18:11 +03:00
Frame *frame;
Cell *next;
Cell *prev;
Column *column;
2005-11-18 18:54:58 +03:00
};
struct Column {
2005-12-21 18:18:11 +03:00
Cell *sel;
Cell *cells;
size_t ncells;
XRectangle rect;
Column *prev;
Column *next;
2005-11-18 18:54:58 +03:00
};
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);
2005-12-11 01:43:45 +03:00
2005-12-11 02:03:17 +03:00
static void select_frame(void *obj, char *arg);
static void swap_frame(void *obj, char *arg);
static void new_column(void *obj, char *arg);
2005-12-11 02:03:17 +03:00
2005-12-11 01:43:45 +03:00
static Action lcol_acttbl[] = {
2005-12-21 18:18:11 +03:00
{"select", select_frame},
{"swap", swap_frame},
{"new", new_column},
2005-12-21 18:18:11 +03:00
{0, 0}
2005-12-11 01:43:45 +03:00
};
2005-12-21 18:18:11 +03:00
void
init_layout_column()
2005-11-18 18:54:58 +03:00
{
2006-01-12 18:06:50 +03:00
LayoutDef *lp, *l = cext_emallocz(sizeof(LayoutDef));
2005-12-21 18:18:11 +03:00
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;
2005-12-21 18:18:11 +03:00
for(lp = layouts; lp && lp->next; lp = lp->next);
if(lp)
lp->next = l;
else
layouts = l;
2005-11-18 18:54:58 +03:00
}
2005-12-21 18:18:11 +03:00
static void
xarrange_column(Column * column)
2005-11-18 18:54:58 +03:00
{
2005-12-21 18:18:11 +03:00
Cell *cell;
unsigned int i = 0, h = layout_rect.height / column->ncells;
for(cell = column->cells; cell; cell = cell->next) {
2005-12-21 18:18:11 +03:00
Frame *f = cell->frame;
f->rect = column->rect;
2006-01-12 18:06:50 +03:00
f->rect.y = layout_rect.y + i * h;
2005-12-21 18:18:11 +03:00
if(!cell->next)
2006-01-12 18:06:50 +03:00
f->rect.height = layout_rect.height - f->rect.y + layout_rect.y;
2005-12-21 18:18:11 +03:00
else
f->rect.height = h;
resize_frame(f, &f->rect, 0);
i++;
}
}
2005-11-18 18:54:58 +03:00
2005-12-21 18:18:11 +03:00
static void
arrange_column(Layout *l)
{
2006-01-12 18:06:50 +03:00
Acme *acme = l->aux;
Column *column;
for(column = acme->columns; column; column = column->next)
xarrange_column(column);
2005-12-21 18:18:11 +03:00
XSync(dpy, False);
2005-11-18 18:54:58 +03:00
}
2005-12-21 18:18:11 +03:00
static void
init_column(Layout *l, Client * clients)
2005-11-18 18:54:58 +03:00
{
2005-12-21 18:18:11 +03:00
Client *n, *c = clients;
2006-01-12 18:06:50 +03:00
l->aux = cext_emallocz(sizeof(Acme));
2005-12-21 18:18:11 +03:00
while(c) {
n = c->next;
attach_column(l, c);
2005-12-21 18:18:11 +03:00
c = n;
}
}
2005-11-18 18:54:58 +03:00
2005-12-21 18:18:11 +03:00
static void
attach_frame(Layout *l, Column * column, Frame * new)
{
2006-01-12 18:06:50 +03:00
Acme *acme = l->aux;
2005-12-21 18:18:11 +03:00
Cell *c, *cell = cext_emallocz(sizeof(Cell));
Frame *f;
cell->frame = new;
cell->column = column;
2005-12-21 18:18:11 +03:00
new->aux = cell;
for(c = column->cells; c && c->next; c = c->next);
2005-12-21 18:18:11 +03:00
if(!c)
column->cells = cell;
2005-12-21 18:18:11 +03:00
else {
c->next = cell;
cell->prev = c;
}
column->ncells++;
2005-12-21 18:18:11 +03:00
for(f = acme->frames; f && f->next; f = f->next);
if(!f)
acme->frames = new;
else {
f->next = new;
new->prev = f;
}
2006-01-12 18:06:50 +03:00
attach_frame_to_layout(l, new);
2005-12-21 18:18:11 +03:00
acme->nframes++;
}
2005-12-21 18:18:11 +03:00
static void
2006-01-12 18:06:50 +03:00
detach_frame(Layout *l, Frame * old)
{
2006-01-12 18:06:50 +03:00
Acme *acme = l->aux;
2005-12-21 18:18:11 +03:00
Cell *cell = old->aux;
Column *column = cell->column;
2005-12-21 18:18:11 +03:00
if(cell->prev)
cell->prev->next = cell->next;
else
column->cells = cell->next;
2005-12-21 18:18:11 +03:00
if(cell->next)
cell->next->prev = cell->prev;
if(column->sel == cell)
column->sel = column->cells;
2005-12-21 18:18:11 +03:00
free(cell);
column->ncells--;
2005-12-21 18:18:11 +03:00
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;
2005-12-21 18:18:11 +03:00
old->aux = nil;
2006-01-12 18:06:50 +03:00
detach_frame_from_layout(old);
2005-12-21 18:18:11 +03:00
acme->nframes--;
}
2005-12-21 18:18:11 +03:00
static Client *
deinit_column(Layout *l)
{
2006-01-12 18:06:50 +03:00
Acme *acme = l->aux;
2005-12-21 18:18:11 +03:00
Frame *f;
Client *cl, *res = nil, *c = nil;
Column *column = acme->columns;
2005-12-21 18:18:11 +03:00
while((f = acme->frames)) {
while((cl = f->clients)) {
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;
}
}
2006-01-12 18:06:50 +03:00
detach_frame(l, f);
2005-12-21 18:18:11 +03:00
destroy_frame(f);
}
while((column = acme->columns)) {
acme->columns = column->next;
free(column);
2005-12-21 18:18:11 +03:00
}
free(acme);
2006-01-12 18:06:50 +03:00
l->aux = 0;
2005-12-21 18:18:11 +03:00
return res;
2005-11-18 18:54:58 +03:00
}
2005-12-21 18:18:11 +03:00
static Bool
attach_column(Layout *l, Client * c)
2005-11-18 18:54:58 +03:00
{
2006-01-12 18:06:50 +03:00
Acme *acme = l->aux;
Column *column = acme->sel;
2005-12-21 18:18:11 +03:00
Frame *f = nil;
if(!column) {
column = cext_emallocz(sizeof(Column));
column->rect = layout_rect;
acme->columns = acme->sel = column;
2005-12-21 18:18:11 +03:00
acme->ncolumns++;
}
f = alloc_frame(&c->rect);
attach_frame(l, column, f);
2005-12-21 18:18:11 +03:00
attach_client_to_frame(f, c);
xarrange_column(column);
2006-01-12 18:06:50 +03:00
if(l->page == selpage)
2005-12-21 18:18:11 +03:00
XMapWindow(dpy, f->win);
focus_column(l, c, True);
2005-12-21 18:18:11 +03:00
return True;
2005-11-18 18:54:58 +03:00
}
2005-12-21 18:18:11 +03:00
static void
2006-01-12 18:06:50 +03:00
update_column_width(Layout *l)
{
2006-01-12 18:06:50 +03:00
Acme *acme = l->aux;
2005-12-21 18:18:11 +03:00
unsigned int i = 0, width;
Column *column;
2005-12-21 18:18:11 +03:00
if(!acme->ncolumns)
return;
2006-01-12 18:06:50 +03:00
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;
2005-12-21 18:18:11 +03:00
i++;
}
arrange_column(l);
}
2005-12-21 18:18:11 +03:00
static void
detach_column(Layout *l, Client * c, Bool unmap)
2005-11-18 18:54:58 +03:00
{
2006-01-12 18:06:50 +03:00
Acme *acme = l->aux;
2005-12-21 18:18:11 +03:00
Frame *f = c->frame;
Cell *old = f->aux;
Column *column = old->column;
2005-12-21 18:18:11 +03:00
detach_client_from_frame(c, unmap);
if(!f->clients) {
2006-01-12 18:06:50 +03:00
detach_frame(l, f);
2005-12-21 18:18:11 +03:00
destroy_frame(f);
} else
return;
if(column->cells) {
if(column->sel == old)
column->sel = column->cells;
xarrange_column(column);
}
2005-12-21 18:18:11 +03:00
else {
if(acme->sel == column) {
if(column->prev)
acme->sel = column->prev;
2005-12-21 18:18:11 +03:00
else
acme->sel = nil;
}
if(column->prev)
column->prev->next = column->next;
2005-12-21 18:18:11 +03:00
else
acme->columns = column->next;
if(column->next)
column->next->prev = column->prev;
2005-12-21 18:18:11 +03:00
if(!acme->sel)
acme->sel = acme->columns;
acme->ncolumns--;
free(column);
2006-01-12 18:06:50 +03:00
update_column_width(l);
2005-12-21 18:18:11 +03:00
}
2005-11-18 18:54:58 +03:00
}
2005-12-21 18:18:11 +03:00
static void
match_frame_horiz(Column * column, XRectangle * r)
2005-11-18 18:54:58 +03:00
{
2005-12-21 18:18:11 +03:00
Cell *cell;
for(cell = column->cells; cell; cell = cell->next) {
2005-12-21 18:18:11 +03:00
Frame *f = cell->frame;
f->rect.x = r->x;
f->rect.width = r->width;
resize_frame(f, &f->rect, nil);
}
2005-12-10 18:38:43 +03:00
}
2005-11-18 18:54:58 +03:00
2005-12-21 18:18:11 +03:00
static void
drop_resize(Frame * f, XRectangle * new)
2005-12-10 18:38:43 +03:00
{
Column *west = nil, *east = nil, *column = nil;
2005-12-21 18:18:11 +03:00
Cell *north = nil, *south = nil;
Cell *cell = f->aux;
column = cell->column;
west = column->prev;
east = column->next;
2005-12-21 18:18:11 +03:00
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;
2005-12-21 18:18:11 +03:00
match_frame_horiz(west, &west->rect);
match_frame_horiz(column, &column->rect);
2005-12-21 18:18:11 +03:00
}
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);
2005-12-21 18:18:11 +03:00
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);
}
2005-11-18 18:54:58 +03:00
}
2005-12-21 18:18:11 +03:00
static void
drop_moving(Frame * f, XRectangle * new, XPoint * pt)
2005-11-18 18:54:58 +03:00
{
2006-01-12 18:06:50 +03:00
Layout *l = f->layout;
2005-12-21 18:18:11 +03:00
Cell *cell = f->aux;
Column *src = cell->column, *tgt = 0;
2006-01-12 18:06:50 +03:00
Acme *acme = l->aux;
2005-12-21 18:18:11 +03:00
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;
2006-01-12 18:06:50 +03:00
detach_frame(l, f);
attach_frame(l, tgt, f);
xarrange_column(src);
xarrange_column(tgt);
focus_column(l, f->sel, True);
2005-12-21 18:18:11 +03:00
} 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);
2005-12-21 18:18:11 +03:00
}
}
}
2005-11-18 18:54:58 +03:00
}
2005-12-21 18:18:11 +03:00
static void
resize_column(Frame * f, XRectangle * new, XPoint * pt)
2005-11-18 18:54:58 +03:00
{
2005-12-21 18:18:11 +03:00
if((f->rect.width == new->width)
&& (f->rect.height == new->height))
drop_moving(f, new, pt);
else
drop_resize(f, new);
2005-11-18 18:54:58 +03:00
}
2005-12-09 04:46:59 +03:00
2005-12-21 18:18:11 +03:00
static void
focus_column(Layout *l, Client *c, Bool raise)
2005-12-09 04:46:59 +03:00
{
2006-01-12 18:06:50 +03:00
Acme *acme = l->aux;
Cell *cell = c->frame->aux;
2006-01-18 16:42:44 +03:00
Client *old = sel_client();
2005-12-21 18:18:11 +03:00
2006-01-18 16:42:44 +03:00
c->frame->sel = c;
acme->sel = cell->column;
cell->column->sel = cell;
l->file[L_SEL_FRAME]->content = c->frame->file[F_PREFIX]->content;
2006-01-18 16:42:44 +03:00
if(raise)
XWarpPointer(dpy, None, c->win, 0, 0, 0, 0,
c->rect.width / 2, c->rect.height / 2);
2006-01-18 16:42:44 +03:00
focus_client(c, old);
2005-12-09 04:46:59 +03:00
}
2005-12-21 18:18:11 +03:00
static Frame *
frames_column(Layout *l)
{
2006-01-12 18:06:50 +03:00
Acme *acme = l->aux;
2005-12-21 18:18:11 +03:00
return acme->frames;
}
static Client *
sel_column(Layout *l)
2005-12-21 18:18:11 +03:00
{
2006-01-12 18:06:50 +03:00
Acme *acme = l->aux;
Column *column = acme->sel;
if(column && column->sel)
return column->sel->frame->sel;
2005-12-21 18:18:11 +03:00
return nil;
}
2005-12-21 18:18:11 +03:00
static Action *
actions_column(Layout *l)
2005-12-11 01:43:45 +03:00
{
2005-12-21 18:18:11 +03:00
return lcol_acttbl;
}
2005-12-11 02:03:17 +03:00
2005-12-21 18:18:11 +03:00
static void
select_frame(void *obj, char *arg)
2005-12-11 02:03:17 +03:00
{
2006-01-12 18:06:50 +03:00
Layout *l = obj;
Acme *acme = l->aux;
Column *c, *column = acme->sel;
2005-12-21 18:18:11 +03:00
Cell *cell;
if(!column)
2005-12-21 18:18:11 +03:00
return;
cell = column->sel;
2005-12-21 18:18:11 +03:00
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);
2005-12-21 18:18:11 +03:00
} else if(!strncmp(arg, "next", 5)) {
if(cell->next)
cell = cell->next;
else
cell = column->cells;
2005-12-21 18:18:11 +03:00
} else if(!strncmp(arg, "west", 5)) {
if(column->prev)
cell = column->prev->sel;
else {
2005-12-21 18:18:11 +03:00
for(c = acme->columns; c && c->next; c = c->next);
cell = c->sel;
}
2005-12-21 18:18:11 +03:00
} else if(!strncmp(arg, "east", 5)) {
if(column->next)
cell = column->next->sel;
2005-12-21 18:18:11 +03:00
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)
2005-12-21 18:18:11 +03:00
i++;
}
if(cell && cell != column->sel)
focus_column(l, cell->frame->sel, True);
2005-12-11 02:03:17 +03:00
}
2005-12-21 18:18:11 +03:00
static void
swap_frame(void *obj, char *arg)
{
2006-01-12 18:06:50 +03:00
Layout *l = obj;
Acme *acme = l->aux;
Column *west = nil, *east = nil, *column = acme->sel;
Cell *north = nil, *south = nil, *cell = column->sel;
2005-12-21 18:18:11 +03:00
Frame *f;
XRectangle r;
if(!column || !cell || !arg)
2005-12-21 18:18:11 +03:00
return;
west = column->prev;
east = column->next;
2005-12-21 18:18:11 +03:00
north = cell->prev;
south = cell->next;
if(!west)
west = east;
if(!east)
east = west;
2005-12-21 18:18:11 +03:00
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);
2005-12-21 18:18:11 +03:00
} 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) {
2005-12-21 18:18:11 +03:00
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) {
2005-12-21 18:18:11 +03:00
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);
2005-12-21 18:18:11 +03:00
}
}
2005-12-21 18:18:11 +03:00
static void
new_column(void *obj, char *arg)
{
2006-01-12 18:06:50 +03:00
Layout *l = obj;
Acme *acme = l->aux;
Column *c, *new, *column = acme->sel;
2005-12-21 18:18:11 +03:00
Frame *f;
if(!column || column->ncells < 2)
2005-12-21 18:18:11 +03:00
return;
f = column->sel->frame;
2005-12-21 18:18:11 +03:00
for(c = acme->columns; c && c->next; c = c->next);
2005-12-16 19:18:00 +03:00
2005-12-21 18:18:11 +03:00
new = cext_emallocz(sizeof(Column));
2006-01-12 18:06:50 +03:00
new->rect = layout_rect;
2005-12-21 18:18:11 +03:00
new->prev = c;
c->next = new;
acme->ncolumns++;
acme->sel = new;
2005-12-16 19:18:00 +03:00
2006-01-12 18:06:50 +03:00
detach_frame(l, f);
attach_frame(l, new, f);
2005-12-16 19:18:00 +03:00
2006-01-12 18:06:50 +03:00
update_column_width(l);
focus_column(l, f->sel, True);
}