wmii/cmd/wm/layout_column.c

400 lines
9.7 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;
struct Acme {
Container columns;
2005-12-09 04:46:59 +03:00
Container frames;
2005-11-18 18:54:58 +03:00
};
struct Column {
2005-12-10 18:38:43 +03:00
Bool refresh;
Container frames;
2005-12-05 01:45:59 +03:00
XRectangle rect;
2005-11-18 18:54:58 +03:00
};
2005-12-05 01:45:59 +03:00
static void init_col(Area * a);
static void deinit_col(Area * a);
static void arrange_col(Area * a);
static Bool attach_col(Area * a, Client * c);
2005-12-11 18:24:52 +03:00
static void detach_col(Area * a, Client * c, Bool unmap);
static void resize_col(Frame *f, XRectangle * new, XPoint * pt);
2005-12-11 01:43:45 +03:00
static void select_col(Frame *f, Bool raise);
static Container *get_frames_col(Area *a);
2005-12-11 01:43:45 +03:00
static Action *get_actions_col(Area *a);
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);
static void destroy_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},
{"destroy", destroy_col},
2005-12-11 01:43:45 +03:00
{0, 0}
};
2005-12-09 04:46:59 +03:00
static Layout lcol = { "col", init_col, deinit_col, arrange_col, attach_col, detach_col,
2005-12-11 01:43:45 +03:00
resize_col, select_col, get_frames_col, get_actions_col };
2005-11-18 18:54:58 +03:00
2005-12-05 01:45:59 +03:00
void init_layout_column()
2005-11-18 18:54:58 +03:00
{
cext_attach_item(&layouts, &lcol);
2005-11-18 18:54:58 +03:00
}
static Column *get_sel_column(Acme *acme)
{
return cext_stack_get_top_item(&acme->columns);
}
2005-11-18 18:54:58 +03:00
static void iter_arrange_column_frame(void *frame, void *height)
2005-11-18 18:54:58 +03:00
{
unsigned int h = *(unsigned int *)height;
Frame *f = frame;
Column *col = f->aux;
if (col->refresh) {
f->rect = col->rect;
f->rect.height = h;
f->rect.y = cext_list_get_item_index(&col->frames, f) * h;
2005-11-18 18:54:58 +03:00
}
resize_frame(f, &f->rect, 0);
2005-11-18 18:54:58 +03:00
}
static void iter_arrange_column(void *column, void *area)
2005-11-18 18:54:58 +03:00
{
Column *col = column;
size_t size = cext_sizeof(&col->frames);
2005-12-10 18:38:43 +03:00
unsigned int height;
if (size) {
height= ((Area *)area)->rect.height / size;
cext_list_iterate(&col->frames, &height, iter_arrange_column_frame);
col->refresh = False;
}
}
2005-11-18 18:54:58 +03:00
static void arrange_col(Area *a)
{
Acme *acme = a->aux;
cext_list_iterate(&acme->columns, a, iter_arrange_column);
2005-11-18 18:54:58 +03:00
}
2005-12-10 18:38:43 +03:00
static void iter_attach_col(void *client, void *area)
2005-11-18 18:54:58 +03:00
{
2005-12-10 18:38:43 +03:00
attach_col(area, client);
}
2005-11-18 18:54:58 +03:00
2005-12-10 18:38:43 +03:00
static void init_col(Area *a)
{
2005-12-10 18:38:43 +03:00
Acme *acme = cext_emallocz(sizeof(Acme));
Column *col = cext_emallocz(sizeof(Column));
a->aux = acme;
col->rect = a->rect;
cext_attach_item(&acme->columns, col);
cext_list_iterate(&a->clients, a, iter_attach_col);
}
2005-12-10 18:38:43 +03:00
static void iter_detach_client(void *client, void *area)
{
2005-12-11 18:24:52 +03:00
Area *a = area;
detach_col(a, (Client *)client, a->page != get_sel_page());
}
static void deinit_col(Area *a)
{
Acme *acme = a->aux;
2005-12-10 18:38:43 +03:00
Column *col;
cext_list_iterate(&a->clients, a, iter_detach_client);
while ((col = get_sel_column(acme)))
{
cext_detach_item(&acme->columns, col);
free(col);
}
2005-11-18 18:54:58 +03:00
free(acme);
a->aux = 0;
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;
2005-12-10 18:38:43 +03:00
Column *col = get_sel_column(acme);
Frame *f = get_sel_frame_of_area(a);
Bool center = False;
/* check for tabbing? */
if (f && (((char *) f->file[F_LOCKED]->content)[0] == '1'))
f = 0;
if (!f) {
f = alloc_frame(&c->rect);
attach_frame_to_area(a, f);
f->aux = col;
cext_attach_item(&acme->frames, f);
cext_attach_item(&col->frames, f);
center = True;
}
attach_client_to_frame(f, c);
2005-12-10 18:38:43 +03:00
if (a->page == get_sel_page())
XMapWindow(dpy, f->win);
if (center)
center_pointer(f);
col->refresh = True;
arrange_col(a);
return True;
2005-11-18 18:54:58 +03:00
}
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);
2005-12-10 18:38:43 +03:00
if (!cext_sizeof(&f->clients)) {
detach_frame_from_area(f);
cext_detach_item(&acme->frames, f);
cext_detach_item(&col->frames, f);
destroy_frame(f);
}
col->refresh = True;
arrange_col(a);
2005-11-18 18:54:58 +03:00
}
2005-12-10 18:38:43 +03:00
static void iter_match_frame_horiz(void *frame, void *rect)
2005-11-18 18:54:58 +03:00
{
2005-12-10 18:38:43 +03:00
Frame *f = frame;
XRectangle *r = rect;
f->rect.x = r->x;
f->rect.width = r->width;
resize_frame(f, &f->rect, nil);
}
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;
Frame *north = 0, *south = 0;
Acme *acme = f->area->aux;
size_t ncol = cext_sizeof(&acme->columns);
size_t nfr = cext_sizeof(&col->frames);
int colidx = cext_list_get_item_index(&acme->columns, col);
int 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);
/* horizontal resize */
2005-11-18 18:54:58 +03:00
if (new->x < f->rect.x) {
2005-12-10 18:38:43 +03:00
if (west && new->x > west->rect.x) {
2005-11-18 18:54:58 +03:00
west->rect.width = new->x - west->rect.x;
col->rect.width += f->rect.x - new->x;
col->rect.x = new->x;
2005-12-10 18:38:43 +03:00
cext_list_iterate(&west->frames, &west->rect, iter_match_frame_horiz);
cext_list_iterate(&col->frames, &col->rect, iter_match_frame_horiz);
2005-11-18 18:54:58 +03:00
}
}
if (new->x + new->width > f->rect.x + f->rect.width) {
2005-12-10 18:38:43 +03:00
if (east && (new->x + new->width < east->rect.x + east->rect.width)) {
2005-11-18 18:54:58 +03:00
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;
2005-12-10 18:38:43 +03:00
cext_list_iterate(&col->frames, &col->rect, iter_match_frame_horiz);
cext_list_iterate(&east->frames, &east->rect, iter_match_frame_horiz);
2005-11-18 18:54:58 +03:00
}
}
2005-12-10 18:38:43 +03:00
/* vertical resize */
2005-11-18 18:54:58 +03:00
if (new->y < f->rect.y) {
2005-12-10 18:38:43 +03:00
if (north && new->y > north->rect.y) {
2005-11-18 18:54:58 +03:00
north->rect.height = new->y - north->rect.y;
2005-12-10 18:38:43 +03:00
f->rect.height += new->y - north->rect.y;
2005-11-18 18:54:58 +03:00
f->rect.y = new->y;
2005-12-10 18:38:43 +03:00
resize_frame(north, &north->rect, nil);
resize_frame(f, &f->rect, nil);
2005-11-18 18:54:58 +03:00
}
}
if (new->y + new->height > f->rect.y + f->rect.height) {
2005-12-10 18:38:43 +03:00
if (south && (new->y + new->height < south->rect.y + south->rect.height)) {
south->rect.height -= new->y + new->height - south->rect.y;
south->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, &south->rect, nil);
2005-11-18 18:54:58 +03:00
}
}
}
2005-12-10 18:38:43 +03:00
static int comp_pointer(void *point, void *column)
{
Column *col = column;
XPoint *pt = point;
return blitz_ispointinrect(pt->x, pt->y, &col->rect);
}
static void drop_moving(Frame *f, XRectangle *new, XPoint *pt)
2005-11-18 18:54:58 +03:00
{
2005-12-05 01:45:59 +03:00
Acme *acme = f->area->aux;
2005-12-10 18:38:43 +03:00
Column *src = f->aux, *tgt = 0;
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
2005-12-10 18:38:43 +03:00
tgt = cext_find_item(&acme->columns, pt, comp_pointer);
2005-11-18 18:54:58 +03:00
2005-12-10 18:38:43 +03:00
if (tgt && tgt != src)
{
cext_detach_item(&src->frames, f);
cext_attach_item(&tgt->frames, f);
f->aux = tgt;
2005-12-10 18:38:43 +03:00
tgt->refresh = src->refresh = True;
cext_stack_top_item(&acme->columns, tgt);
iter_arrange_column(tgt, f->area);
iter_arrange_column(src, f->area);
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-10 18:38:43 +03:00
draw_area(f->area);
2005-11-18 18:54:58 +03:00
}
2005-12-09 04:46:59 +03:00
2005-12-11 01:43:45 +03:00
static void select_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;
Column *col = f->aux;
2005-12-11 02:03:17 +03:00
cext_stack_top_item(&acme->columns, col);
2005-12-11 01:43:45 +03:00
sel_client(cext_stack_get_top_item(&f->clients));
cext_stack_top_item(&col->frames, f);
cext_stack_top_item(&acme->frames, f);
a->file[A_SEL_FRAME]->content = f->file[F_PREFIX]->content;
2005-12-11 17:47:23 +03:00
if (raise)
center_pointer(f);
2005-12-09 04:46:59 +03:00
}
static Container *get_frames_col(Area *a)
{
Acme *acme = a->aux;
return &acme->frames;
}
2005-12-11 01:43:45 +03:00
static Action *get_actions_col(Area *a)
{
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, *old;
f = old = cext_stack_get_top_item(&col->frames);
if (!f || !arg)
return;
if (!strncmp(arg, "prev", 5))
f = cext_list_get_prev_item(&col->frames, f);
else if (!strncmp(arg, "next", 5))
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
2005-12-11 17:47:23 +03:00
f = cext_list_get_item(&col->frames, blitz_strtonum(arg, 0, cext_sizeof(&col->frames) - 1));
if (f && old != f) {
2005-12-11 02:03:17 +03:00
select_col(f, True);
center_pointer(f);
draw_frame(old, nil);
draw_frame(f, nil);
}
}
static void swap_frame(void *obj, char *arg)
{
Area *a = obj;
Acme *acme = a->aux;
Column *col = get_sel_column(acme);
Frame *f = cext_stack_get_top_item(&col->frames);
if (!f || !arg)
return;
}
static void update_column_width(Area *a)
{
Acme *acme = a->aux;
size_t size = cext_sizeof(&acme->columns);
unsigned int i, width = a->rect.width / cext_sizeof(&acme->columns);
for (i = 0; i < size; i++) {
Column *col = cext_list_get_item(&acme->columns, i);
col->refresh = True;
col->rect.x = i * width;
col->rect.width = width;
}
arrange_col(a);
}
static void new_col(void *obj, char *arg)
{
Area *a = obj;
Acme *acme = a->aux;
Column *col = cext_emallocz(sizeof(Column));
cext_attach_item(&acme->columns, col);
update_column_width(a);
}
static void destroy_col(void *obj, char *arg)
{
Area *a = obj;
Acme *acme = a->aux;
Column *col = get_sel_column(acme);
size_t size;
if (cext_sizeof(&acme->columns) > 1) {
while (cext_sizeof(&col->frames)) {
Frame *f = cext_stack_get_top_item(&col->frames);
while ((size = cext_sizeof(&f->clients))) {
detach_col(a, cext_stack_get_top_item(&f->clients), a->page != get_sel_page());
if (size == 1)
break;
}
}
cext_detach_item(&acme->columns, col);
free(col);
update_column_width(a);
}
}