wmii/cmd/wm/layout_column.c

387 lines
9.1 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 {
2005-12-05 01:45:59 +03:00
int sel;
Container columns;
2005-12-09 04:46:59 +03:00
Container frames;
2005-11-18 18:54:58 +03:00
};
struct Column {
2005-12-05 01:45:59 +03:00
int sel;
int 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-06 00:22:24 +03:00
static void detach_col(Area * a, Client * c);
2005-12-05 01:45:59 +03:00
static void resize_col(Frame * f, XRectangle * new, XPoint * pt);
2005-12-09 04:46:59 +03:00
static Container *get_frames_col(Area *a);
static void aux_col(Area *a, char *aux);
2005-12-09 04:46:59 +03:00
static Layout lcol = { "col", init_col, deinit_col, arrange_col, attach_col, detach_col,
resize_col, get_frames_col, aux_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);
unsigned int height = ((Area *)area)->rect.height / size;
cext_list_iterate(&col->frames, &height, iter_arrange_column_frame);
}
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
}
static void init_col(Area *a)
2005-11-18 18:54:58 +03:00
{
Acme *acme = cext_emallocz(sizeof(Acme));
int i, cols = 1;
unsigned int width;
//size_t size;
2005-12-05 01:45:59 +03:00
Column *col;
2005-11-18 18:54:58 +03:00
a->aux = acme;
2005-11-18 18:54:58 +03:00
/* processing argv */
/*
for (i = 1; (i < argc) && (argv[i][0] == '-'); i++) {
switch (argv[i][1]) {
case 'c':
cols = _strtonum(argv[++i], 0, 32);
if (cols < 1)
cols = 1;
break;
}
}
*/
2005-11-18 18:54:58 +03:00
width = a->rect.width / cols;
2005-11-18 18:54:58 +03:00
for (i = 0; i < cols; i++) {
col = cext_emallocz(sizeof(Column));
col->rect = a->rect;
col->rect.x = i * width;
col->rect.width = width;
col->refresh = 1;
cext_attach_item(&acme->columns, col);
2005-11-18 18:54:58 +03:00
}
/*
2005-12-05 04:50:02 +03:00
* Frame attaching strategy works as follows: 1. If more client than
2005-11-18 18:54:58 +03:00
* column exist, then each column gets one client, except eastmost
2005-12-05 04:50:02 +03:00
* column, which gets all remaining client. 2. If lesser client
2005-11-18 18:54:58 +03:00
* than column exist, than filling begins from eastmost to westmost
2005-12-05 04:50:02 +03:00
* column until no more client exist.
2005-11-18 18:54:58 +03:00
*/
#if 0
size = cext_sizeof(&a->clients);
if (size > cols) {
2005-11-18 18:54:58 +03:00
/* 1st. case */
j = 0;
for (i = 0; i < (cols - 1); i++) {
col = acme->column[i];
2005-12-05 22:38:03 +03:00
col->frame = (Frame **) attach_item_end((void **) col->frame, alloc_frame(&client[i]->rect), sizeof(Frame *));
2005-12-05 04:50:02 +03:00
col->frame[0]->aux = col;
attach_frame_to_area(a, col->frame[0]);
attach_client_to_frame(col->frame[0], client[j]);
2005-11-18 18:54:58 +03:00
j++;
}
col = acme->column[cols - 1];
col->frame = cext_emalloc((n - j + 1) * sizeof(Frame *));
2005-11-18 18:54:58 +03:00
for (i = 0; i + j < n; i++) {
2005-12-05 22:38:03 +03:00
col->frame[i] = alloc_frame(&client[j + i]->rect);
2005-12-05 04:50:02 +03:00
col->frame[i]->aux = col;
attach_frame_to_area(a, col->frame[i]);
attach_client_to_frame(col->frame[i], client[j + i]);
2005-11-18 18:54:58 +03:00
}
2005-12-05 04:50:02 +03:00
col->frame[i] = 0;
2005-11-18 18:54:58 +03:00
} else {
/* 2nd case */
j = 0;
for (i = cols - 1; j < n; i--) {
col = acme->column[i];
2005-12-05 22:38:03 +03:00
col->frame = (Frame **) attach_item_end((void **) col->frame, alloc_frame(&client[i]->rect), sizeof(Frame *));
2005-12-05 04:50:02 +03:00
col->frame[0]->aux = col;
attach_frame_to_area(a, col->frame[0]);
attach_client_to_frame(col->frame[0], client[j]);
2005-11-18 18:54:58 +03:00
j++;
}
}
arrange_col(a);
#endif
2005-11-18 18:54:58 +03:00
}
static void iter_detach_client(void *client, void *aux)
2005-11-18 18:54:58 +03:00
{
Client *c = client;
detach_client_from_frame(c);
}
2005-11-18 18:54:58 +03:00
static void iter_detach_frame(void *frame, void *aux)
{
Frame *f = frame;
cext_list_iterate(&f->clients, nil, iter_detach_client);
}
static void iter_deinit_col(void *column, void *aux)
{
Column *col = column;
cext_list_iterate(&col->frames, nil, iter_detach_frame);
}
static void deinit_col(Area *a)
{
Acme *acme = a->aux;
cext_list_iterate(&acme->columns, nil, iter_deinit_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;
Column *col;
Frame *f;
2005-11-18 18:54:58 +03:00
col = get_sel_column(acme);
2005-12-05 22:38:03 +03:00
f = alloc_frame(&c->rect);
cext_attach_item(&col->frames, f);
2005-11-18 18:54:58 +03:00
f->aux = col;
col->refresh = 1;
attach_frame_to_area(a, f);
attach_client_to_frame(f, c);
arrange_col(a);
return True;
2005-11-18 18:54:58 +03:00
}
static void detach_col(Area *a, Client *c)
2005-11-18 18:54:58 +03:00
{
2005-12-05 01:45:59 +03:00
Frame *f = c->frame;
Column *col = f->aux;
2005-11-18 18:54:58 +03:00
cext_detach_item(&col->frames, f);
2005-11-18 18:54:58 +03:00
col->refresh = 1;
detach_client_from_frame(c);
detach_frame_from_area(f);
2005-12-03 20:02:39 +03:00
destroy_frame(f);
2005-11-18 18:54:58 +03:00
arrange_col(a);
2005-11-18 18:54:58 +03:00
}
2005-12-05 01:45:59 +03:00
static void drop_resize(Frame * f, XRectangle * new)
2005-11-18 18:54:58 +03:00
{
#if 0
2005-12-05 01:45:59 +03:00
Column *col = f->aux;
Acme *acme = f->area->aux;
int i, idx, n = 0;
2005-11-18 18:54:58 +03:00
if (!col) {
fprintf(stderr, "%s",
2005-12-05 01:45:59 +03:00
"wmii: fatal: frame has no associated column\n");
2005-11-18 18:54:58 +03:00
exit(1);
}
for (i = 0; acme->column && acme->column[i]; i++) {
if (acme->column[i] == col)
idx = i;
n++;
}
/* horizontal resizals are */
if (new->x < f->rect.x) {
if (idx && new->x > acme->column[idx - 1]->rect.x) {
2005-12-05 01:45:59 +03:00
Column *west = acme->column[idx - 1];
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-05 04:50:02 +03:00
for (i = 0; west->frame && west->frame[i]; i++) {
Frame *f = west->frame[i];
2005-11-18 18:54:58 +03:00
f->rect.x = west->rect.x;
f->rect.width = west->rect.width;
resize_frame(f, &f->rect, 0);
2005-11-18 18:54:58 +03:00
}
2005-12-05 04:50:02 +03:00
for (i = 0; col->frame && col->frame[i]; i++) {
Frame *f = col->frame[i];
2005-11-18 18:54:58 +03:00
f->rect.x = col->rect.x;
f->rect.width = col->rect.width;
resize_frame(f, &f->rect, 0);
2005-11-18 18:54:58 +03:00
}
}
}
if (new->x + new->width > f->rect.x + f->rect.width) {
if ((idx + 1 < n) &&
2005-12-05 01:45:59 +03:00
(new->x + new->width < acme->column[idx + 1]->rect.x
+ acme->column[idx + 1]->rect.width)) {
Column *east = acme->column[idx + 1];
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-05 04:50:02 +03:00
for (i = 0; col->frame && col->frame[i]; i++) {
Frame *f = col->frame[i];
2005-11-18 18:54:58 +03:00
f->rect.x = col->rect.x;
f->rect.width = col->rect.width;
resize_frame(f, &f->rect, 0);
2005-11-18 18:54:58 +03:00
}
2005-12-05 04:50:02 +03:00
for (i = 0; east->frame && east->frame[i]; i++) {
Frame *f = east->frame[i];
2005-11-18 18:54:58 +03:00
f->rect.x = east->rect.x;
f->rect.width = east->rect.width;
resize_frame(f, &f->rect, 0);
2005-11-18 18:54:58 +03:00
}
}
}
/* vertical stuff */
n = 0;
2005-12-05 04:50:02 +03:00
for (i = 0; col->frame && col->frame[i]; i++) {
if (col->frame[i] == f)
2005-11-18 18:54:58 +03:00
idx = i;
n++;
}
if (new->y < f->rect.y) {
2005-12-05 04:50:02 +03:00
if (idx && new->y > col->frame[idx - 1]->rect.y) {
Frame *north = col->frame[idx - 1];
2005-11-18 18:54:58 +03:00
north->rect.height = new->y - north->rect.y;
f->rect.width += new->y - north->rect.y;
f->rect.y = new->y;
resize_frame(north, &north->rect, 0);
resize_frame(f, &f->rect, 0);
2005-11-18 18:54:58 +03:00
}
}
if (new->y + new->height > f->rect.y + f->rect.height) {
if ((idx + 1 < n) &&
2005-12-05 04:50:02 +03:00
(new->y + new->height < col->frame[idx + 1]->rect.y
+ col->frame[idx + 1]->rect.height)) {
Frame *south = col->frame[idx + 1];
2005-11-18 18:54:58 +03:00
south->rect.width -= new->x + new->width - south->rect.x;
south->rect.x = new->x + new->width;
f->rect.x = new->x;
f->rect.width = new->width;
resize_frame(f, &f->rect, 0);
resize_frame(south, &south->rect, 0);
2005-11-18 18:54:58 +03:00
}
}
#endif
2005-11-18 18:54:58 +03:00
}
2005-12-05 01:45:59 +03:00
static void _drop_move(Frame * f, XRectangle * new, XPoint * pt)
2005-11-18 18:54:58 +03:00
{
#if 0
2005-12-05 01:45:59 +03:00
Column *tgt = 0, *src = f->aux;
Acme *acme = f->area->aux;
int i;
2005-11-18 18:54:58 +03:00
if (!src) {
fprintf(stderr, "%s",
2005-12-05 01:45:59 +03:00
"wmii: fatal: frame has no associated column\n");
2005-11-18 18:54:58 +03:00
exit(1);
}
for (i = 0; acme->column && acme->column[i]; i++) {
2005-12-05 01:45:59 +03:00
Column *colp = acme->column[i];
2005-11-18 18:54:58 +03:00
if (blitz_ispointinrect(pt->x, pt->y, &colp->rect)) {
tgt = colp;
break;
}
}
/* use pointer as fixpoint */
if (tgt == src) {
/* only change order within column */
2005-12-05 04:50:02 +03:00
for (i = 0; tgt->frame && tgt->frame[i]; i++) {
Frame *fp = tgt->frame[i];
2005-11-18 18:54:58 +03:00
if (blitz_ispointinrect(pt->x, pt->y, &fp->rect)) {
if (fp == f)
2005-12-05 01:45:59 +03:00
return; /* just ignore */
2005-11-18 18:54:58 +03:00
else {
2005-12-05 04:50:02 +03:00
int idxf = index_item((void **) tgt->frame, f);
int idxfp = index_item((void **) tgt->frame, fp);
2005-12-05 01:45:59 +03:00
Frame *tmpf = f;
XRectangle tmpr = f->rect;
2005-11-18 18:54:58 +03:00
f->rect = fp->rect;
fp->rect = tmpr;
2005-12-05 04:50:02 +03:00
tgt->frame[idxf] = tgt->frame[idxfp];
tgt->frame[idxfp] = tmpf;
resize_frame(f, &f->rect, 0);
resize_frame(fp, &fp->rect, 0);
2005-11-18 18:54:58 +03:00
}
return;
}
}
} else {
/* detach, attach and change order in target column */
2005-12-06 00:22:24 +03:00
src->frame = (Frame **) detach_item((void **) src->frame, f, sizeof(Frame *));
2005-12-05 04:50:02 +03:00
tgt->frame =
(Frame **) attach_item_end((void **) tgt->frame, f,
2005-12-05 01:45:59 +03:00
sizeof(Frame *));
2005-11-18 18:54:58 +03:00
tgt->refresh = 1;
iter_arrange_column(tgt, f->area);
2005-11-18 18:54:58 +03:00
/* TODO: implement a better target placing strategy */
}
#endif
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-11-18 18:54:58 +03:00
_drop_move(f, new, pt);
else
drop_resize(f, new);
}
2005-12-09 04:46:59 +03:00
static Container *get_frames_col(Area *a)
{
Acme *acme = a->aux;
return &acme->frames;
}
static void aux_col(Area *a, char *aux)
{
}