wmii/cmd/wm/layout_column.c

581 lines
12 KiB
C
Raw Normal View History

2005-11-18 18:54:58 +03:00
/*
* (C)opyright MMIV-MMV 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"
2005-11-18 18:54:58 +03:00
typedef struct Acme Acme;
typedef struct Column Column;
typedef struct ColFrame ColFrame;
2005-11-18 18:54:58 +03:00
struct Acme {
Column *sel;
Column *columns;
size_t ncolumns;
Frame *frames;
size_t nframes;
};
struct ColFrame {
Frame *frame;
ColFrame *next;
ColFrame *prev;
Column *col;
2005-11-18 18:54:58 +03:00
};
struct Column {
ColFrame *sel;
ColFrame *frames;
size_t nframes;
2005-12-05 01:45:59 +03:00
XRectangle rect;
Column *prev;
Column *next;
2005-11-18 18:54:58 +03:00
};
static void init_col(Area *a, Client *clients);
static Client *deinit_col(Area *a);
static void arrange_col(Area *a);
static Bool attach_col(Area *a, Client *c);
static void detach_col(Area *a, Client *c, Bool unmap);
static void resize_col(Frame *f, XRectangle *new, XPoint *pt);
static void focus_col(Frame *f, Bool raise);
static Frame *frames_col(Area *a);
static Frame *sel_col(Area *a);
static Action *actions_col(Area *a);
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_col(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-11 02:03:17 +03:00
{"select", select_frame},
{"swap", swap_frame},
{"new", new_col},
2005-12-11 01:43:45 +03:00
{0, 0}
};
2005-12-05 01:45:59 +03:00
void init_layout_column()
2005-11-18 18:54:58 +03:00
{
Layout *lp, *l = cext_emallocz(sizeof(Layout));
l->name = "column";
l->init = init_col;
l->deinit = deinit_col;
l->arrange = arrange_col;
l->attach = attach_col;
l->detach = detach_col;
l->resize = resize_col;
l->focus = focus_col;
l->frames = frames_col;
l->sel = sel_col;
l->actions = actions_col;
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
}
static void arrange_column(Column *col)
2005-11-18 18:54:58 +03:00
{
ColFrame *cf;
unsigned int i = 0, h = area_rect.height / col->nframes;
for (cf = col->frames; cf; cf = cf->next) {
Frame *f = cf->frame;
f->rect = col->rect;
f->rect.y = area_rect.y + i * h;
if (!cf->next)
f->rect.height = area_rect.height - f->rect.y + area_rect.y;
else
f->rect.height = h;
resize_frame(f, &f->rect, 0);
i++;
2005-12-10 18:38:43 +03:00
}
}
2005-11-18 18:54:58 +03:00
static void arrange_col(Area *a)
{
Acme *acme = a->aux;
Column *col;
for (col = acme->columns; col; col = col->next)
arrange_column(col);
2005-12-12 19:04:40 +03:00
XSync(dpy, False);
2005-11-18 18:54:58 +03:00
}
static void init_col(Area *a, Client *clients)
2005-11-18 18:54:58 +03:00
{
Client *n, *c = clients;
a->aux = cext_emallocz(sizeof(Acme));
while (c) {
n = c->next;
attach_col(a, c);
c = n;
}
}
2005-11-18 18:54:58 +03:00
static void attach_frame(Area *a, Column *col, Frame *f)
{
Acme *acme = a->aux;
ColFrame *c, *cf = cext_emallocz(sizeof(ColFrame));
Frame *fr;
cf->frame = f;
cf->col = col;
f->aux = cf;
for (c = col->frames; c && c->next; c = c->next);
if (!c)
col->frames = cf;
else {
c->next = cf;
cf->prev = c;
}
col->sel = cf;
col->nframes++;
for (fr = acme->frames; fr && fr->next; fr = fr->next);
if (!fr)
acme->frames = f;
else {
fr->next = f;
f->prev = fr;
}
attach_frame_to_area(a, f);
acme->nframes++;
}
static void detach_frame(Area *a, Frame *f)
{
Acme *acme = a->aux;
ColFrame *cf = f->aux;
Column *col = cf->col;
if (col->sel == cf) {
if (cf->prev)
col->sel = cf->prev;
else
col->sel = nil;
}
if (cf->prev)
cf->prev->next = cf->next;
else
col->frames = cf->next;
if (cf->next)
cf->next->prev = cf->prev;
if (!col->sel)
col->sel = col->frames;
free(cf);
col->nframes--;
if (f->prev)
f->prev->next = f->next;
else
acme->frames = f->next;
if (f->next)
f->next->prev = f->prev;
f->aux = nil;
detach_frame_from_area(f);
acme->nframes--;
}
static Client *deinit_col(Area *a)
{
Acme *acme = a->aux;
Frame *f;
Client *cl, *res = nil, *c = nil;
Column *col = acme->columns;
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;
}
}
detach_frame(a, f);
destroy_frame(f);
}
while ((col = acme->columns)) {
acme->columns = col->next;
2005-12-10 18:38:43 +03:00
free(col);
}
2005-11-18 18:54:58 +03:00
free(acme);
a->aux = 0;
return res;
2005-11-18 18:54:58 +03:00
}
static Bool attach_col(Area *a, Client *c)
2005-11-18 18:54:58 +03:00
{
2005-12-05 01:45:59 +03:00
Acme *acme = a->aux;
Column *col = acme->sel;
Frame *f = nil;
if (col && col->sel)
f = col->sel->frame;
2005-12-10 18:38:43 +03:00
if (!col) {
col = cext_emallocz(sizeof(Column));
col->rect = area_rect;
acme->columns = acme->sel = col;
acme->ncolumns++;
}
2005-12-10 18:38:43 +03:00
/* check for tabbing? */
if (f && (((char *) f->file[F_LOCKED]->content)[0] == '1'))
f = 0;
if (!f) {
f = alloc_frame(&c->rect);
attach_frame(a, col, f);
2005-12-10 18:38:43 +03:00
}
attach_client_to_frame(f, c);
arrange_column(col);
if (a->page == selpage)
2005-12-10 18:38:43 +03:00
XMapWindow(dpy, f->win);
focus_col(f, True);
return True;
2005-11-18 18:54:58 +03:00
}
static void update_column_width(Area *a)
{
Acme *acme = a->aux;
unsigned int i = 0, width;
Column *col;
if (!acme->ncolumns)
return;
width = area_rect.width / acme->ncolumns;
for (col = acme->columns; col; col = col->next) {
col->rect = area_rect;
col->rect.x = i * width;
col->rect.width = width;
i++;
}
arrange_col(a);
}
2005-12-11 18:24:52 +03:00
static void detach_col(Area *a, Client *c, Bool unmap)
2005-11-18 18:54:58 +03:00
{
2005-12-10 18:38:43 +03:00
Acme *acme = a->aux;
2005-12-05 01:45:59 +03:00
Frame *f = c->frame;
Column *col = f->aux;
2005-11-18 18:54:58 +03:00
2005-12-11 18:24:52 +03:00
detach_client_from_frame(c, unmap);
if (!f->clients) {
detach_frame(a, f);
2005-12-10 18:38:43 +03:00
destroy_frame(f);
}
else return;
if (col->frames)
arrange_column(col);
else {
if (acme->sel == col) {
if (col->prev)
acme->sel = col->prev;
else
acme->sel = nil;
}
if (col->prev)
col->prev->next = col->next;
else
acme->columns = col->next;
if (col->next)
col->next->prev = col->prev;
if (!acme->sel)
acme->sel = acme->columns;
acme->ncolumns--;
free(col);
update_column_width(a);
}
2005-11-18 18:54:58 +03:00
}
static void match_frame_horiz(Column *col, XRectangle *r)
2005-11-18 18:54:58 +03:00
{
ColFrame *cf;
for (cf = col->frames; cf; cf = cf->next) {
Frame *f = cf->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-10 18:38:43 +03:00
static void drop_resize(Frame *f, XRectangle *new)
{
Column *west = 0, *east = 0, *col = f->aux;
ColFrame *north = 0, *south = 0;
ColFrame *cf = f->aux;
2005-12-10 18:38:43 +03:00
west = col->prev;
east = col->next;
north = cf->prev;
south = cf->next;
2005-12-10 18:38:43 +03:00
/* horizontal resize */
if (west && (new->x != f->rect.x)) {
west->rect.width = new->x - west->rect.x;
col->rect.width += f->rect.x - new->x;
col->rect.x = new->x;
match_frame_horiz(west, &west->rect);
match_frame_horiz(col, &col->rect);
2005-11-18 18:54:58 +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;
col->rect.x = new->x;
col->rect.width = new->width;
match_frame_horiz(col, &col->rect);
match_frame_horiz(east, &east->rect);
2005-11-18 18:54:58 +03:00
}
2005-12-10 18:38:43 +03:00
/* 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);
2005-11-18 18:54:58 +03:00
}
2005-12-15 02:23:31 +03:00
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-10 18:38:43 +03:00
static void drop_moving(Frame *f, XRectangle *new, XPoint *pt)
2005-11-18 18:54:58 +03:00
{
Area *a = f->area;
ColFrame *fcf = f->aux;
Column *src = fcf->col, *tgt = 0;
Acme *acme = a->aux;
2005-11-18 18:54:58 +03:00
2005-12-10 18:38:43 +03:00
if (!pt)
return;
2005-11-18 18:54:58 +03:00
for (tgt = acme->columns; tgt && !blitz_ispointinrect(pt->x, pt->y, &tgt->rect); tgt = tgt->next);
if (tgt) {
if (tgt != src) {
if (src->nframes < 2)
return;
detach_frame(a, f);
attach_frame(a, tgt, f);
arrange_column(src);
arrange_column(tgt);
focus_col(f, True);
}
else {
ColFrame *cf;
for (cf = src->frames; cf && !blitz_ispointinrect(pt->x, pt->y, &cf->frame->rect); cf = cf->next);
if (cf && cf != fcf) {
Frame *tmp = cf->frame;
cf->frame = f;
fcf->frame = tmp;
arrange_column(src);
focus_col(f, True);
}
}
2005-11-18 18:54:58 +03:00
}
}
static void resize_col(Frame *f, XRectangle *new, XPoint *pt)
2005-11-18 18:54:58 +03:00
{
if ((f->rect.width == new->width)
2005-12-05 01:45:59 +03:00
&& (f->rect.height == new->height))
2005-12-10 18:38:43 +03:00
drop_moving(f, new, pt);
2005-11-18 18:54:58 +03:00
else
drop_resize(f, new);
}
2005-12-09 04:46:59 +03:00
static void focus_col(Frame *f, Bool raise)
2005-12-09 04:46:59 +03:00
{
2005-12-11 01:43:45 +03:00
Area *a = f->area;
Acme *acme = a->aux;
ColFrame *old, *fcf = f->aux;
Column *col = fcf->col;
old = col->sel;
acme->sel = col;
col->sel = fcf;
sel_client(f->sel);
2005-12-11 01:43:45 +03:00
a->file[A_SEL_FRAME]->content = f->file[F_PREFIX]->content;
2005-12-11 17:47:23 +03:00
if (raise)
center_pointer(f);
if (old && old != fcf)
draw_frame(old->frame);
draw_frame(f);
2005-12-09 04:46:59 +03:00
}
static Frame *frames_col(Area *a)
{
Acme *acme = a->aux;
return acme->frames;
}
static Frame *sel_col(Area *a) {
Acme *acme = a->aux;
Column *col = acme->sel;
if (col && col->sel)
return col->sel->frame;
return nil;
}
static Action *actions_col(Area *a)
2005-12-11 01:43:45 +03:00
{
return lcol_acttbl;
}
2005-12-11 02:03:17 +03:00
static void select_frame(void *obj, char *arg)
{
Area *a = obj;
Acme *acme = a->aux;
Column *col = get_sel_column(acme);
Frame *f;
2005-12-11 02:03:17 +03:00
2005-12-13 22:06:07 +03:00
if (!col)
return;
f = cext_stack_get_top_item(&col->frames);
2005-12-11 02:03:17 +03:00
if (!f || !arg)
return;
if (!strncmp(arg, "prev", 5))
f = cext_list_get_prev_item(&acme->frames, f);
2005-12-11 02:03:17 +03:00
else if (!strncmp(arg, "next", 5))
f = cext_list_get_next_item(&acme->frames, f);
else if (!strncmp(arg, "north", 6))
f = cext_list_get_next_item(&col->frames, f);
else if (!strncmp(arg, "south", 6))
2005-12-11 02:03:17 +03:00
f = cext_list_get_next_item(&col->frames, f);
else if (!strncmp(arg, "west", 5)) {
col = cext_list_get_prev_item(&acme->columns, col);
cext_stack_top_item(&acme->columns, col);
f = cext_stack_get_top_item(&col->frames);
}
else if (!strncmp(arg, "east", 5)) {
col = cext_list_get_next_item(&acme->columns, col);
cext_stack_top_item(&acme->columns, col);
f = cext_stack_get_top_item(&col->frames);
}
2005-12-11 02:03:17 +03:00
else
f = cext_list_get_item(&col->frames, blitz_strtonum(arg, 0, cext_sizeof_container(&col->frames) - 1));
focus_col(f, True);
2005-12-11 02:03:17 +03:00
}
static void swap_frame(void *obj, char *arg)
{
Area *a = obj;
Acme *acme = a->aux;
Column *west = 0, *east = 0, *col = get_sel_column(acme);
2005-12-13 22:06:07 +03:00
Frame *north = 0, *south = 0, *f;
2005-12-13 21:58:05 +03:00
XRectangle r;
size_t ncol, nfr;
int colidx, fidx;
2005-12-13 22:06:07 +03:00
if (!col)
return;
f = cext_stack_get_top_item(&col->frames);
if (!f || !arg)
return;
ncol = cext_sizeof_container(&acme->columns);
nfr = cext_sizeof_container(&col->frames);
colidx = cext_list_get_item_index(&acme->columns, col);
fidx = cext_list_get_item_index(&col->frames, f);
if (colidx > 0)
west = cext_list_get_item(&acme->columns, colidx - 1);
if (colidx + 1 < ncol)
east = cext_list_get_item(&acme->columns, colidx + 1);
if (fidx > 0)
north = cext_list_get_item(&col->frames, fidx - 1);
if (fidx + 1 < nfr)
south = cext_list_get_item(&col->frames, fidx + 1);
if (!strncmp(arg, "north", 6) && north) {
2005-12-13 21:58:05 +03:00
r = north->rect;
north->rect = f->rect;
f->rect = r;
cext_swap_items(&col->frames, f, north);
2005-12-13 21:58:05 +03:00
resize_frame(f, &f->rect, nil);
resize_frame(north, &north->rect, nil);
focus_col(f, True);
}
else if (!strncmp(arg, "south", 6) && south) {
2005-12-13 21:58:05 +03:00
r = south->rect;
south->rect = f->rect;
f->rect = r;
cext_swap_items(&col->frames, f, south);
2005-12-13 21:58:05 +03:00
resize_frame(f, &f->rect, nil);
resize_frame(south, &south->rect, nil);
focus_col(f, True);
}
else if (!strncmp(arg, "west", 5) && west && (ncol > 1)) {
Frame *other = cext_stack_get_top_item(&west->frames);
2005-12-13 21:58:05 +03:00
r = other->rect;
other->rect = f->rect;
f->rect = r;
cext_detach_item(&col->frames, f);
cext_detach_item(&west->frames, other);
cext_attach_item(&west->frames, f);
cext_attach_item(&col->frames, other);
f->aux = west;
other->aux = col;
2005-12-13 21:58:05 +03:00
resize_frame(f, &f->rect, nil);
resize_frame(other, &other->rect, nil);
focus_col(f, True);
}
else if (!strncmp(arg, "east", 5) && east && (ncol > 1)) {
Frame *other = cext_stack_get_top_item(&east->frames);
2005-12-13 21:58:05 +03:00
r = other->rect;
other->rect = f->rect;
f->rect = r;
cext_detach_item(&col->frames, f);
cext_detach_item(&east->frames, other);
cext_attach_item(&east->frames, f);
cext_attach_item(&col->frames, other);
f->aux = east;
other->aux = col;
2005-12-13 21:58:05 +03:00
resize_frame(f, &f->rect, nil);
resize_frame(other, &other->rect, nil);
focus_col(f, True);
}
}
static void new_col(void *obj, char *arg)
{
Area *a = obj;
Acme *acme = a->aux;
Column *col = get_sel_column(acme);
2005-12-13 22:06:07 +03:00
Frame *f;
2005-12-13 22:06:07 +03:00
if (!col || (cext_sizeof_container(&col->frames) < 2))
return;
2005-12-13 22:06:07 +03:00
f = cext_stack_get_top_item(&col->frames);
cext_detach_item(&col->frames, f);
f->aux = col = cext_emallocz(sizeof(Column));
cext_attach_item(&col->frames, f);
cext_attach_item(&acme->columns, col);
update_column_width(a);
focus_col(f, True);
}