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 "layout.h"
|
|
|
|
|
|
|
|
#include <cext.h>
|
|
|
|
|
|
|
|
typedef struct Acme Acme;
|
|
|
|
typedef struct Column Column;
|
|
|
|
|
|
|
|
struct Acme {
|
2005-12-05 01:45:59 +03:00
|
|
|
int sel;
|
|
|
|
Column **column;
|
2005-11-18 18:54:58 +03:00
|
|
|
};
|
|
|
|
|
|
|
|
struct Column {
|
2005-12-05 01:45:59 +03:00
|
|
|
int sel;
|
|
|
|
int refresh;
|
2005-12-05 04:50:02 +03:00
|
|
|
Frame **frame;
|
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 void attach_col(Area * a, Client * c);
|
|
|
|
static void detach_col(Area * a, Client * c, int unmapped, int destroyed);
|
|
|
|
static void resize_col(Frame * f, XRectangle * new, XPoint * pt);
|
2005-11-22 14:49:19 +03:00
|
|
|
|
2005-12-05 04:09:27 +03:00
|
|
|
static Layout lcol = { "col", init_col, deinit_col, arrange_col, attach_col, detach_col, resize_col };
|
2005-11-18 18:54:58 +03:00
|
|
|
|
2005-12-05 01:45:59 +03:00
|
|
|
static Column zero_column = { 0 };
|
|
|
|
static Acme zero_acme = { 0 };
|
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
|
|
|
{
|
2005-12-05 04:09:27 +03:00
|
|
|
layouts = (Layout **) attach_item_end((void **) layouts, &lcol, sizeof(Layout *));
|
2005-11-18 18:54:58 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2005-12-05 01:45:59 +03:00
|
|
|
static void arrange_column(Area * a, Column * col)
|
2005-11-18 18:54:58 +03:00
|
|
|
{
|
2005-12-05 01:45:59 +03:00
|
|
|
int i;
|
2005-12-05 04:50:02 +03:00
|
|
|
int n = count_items((void **) col->frame);
|
2005-12-05 01:45:59 +03:00
|
|
|
unsigned int height = a->rect.height / n;
|
2005-12-05 04:50:02 +03:00
|
|
|
for (i = 0; col->frame && col->frame[i]; i++) {
|
2005-11-18 18:54:58 +03:00
|
|
|
if (col->refresh) {
|
2005-12-05 04:50:02 +03:00
|
|
|
col->frame[i]->rect = col->rect;
|
|
|
|
col->frame[i]->rect.height = height;
|
|
|
|
col->frame[i]->rect.y = i * height;
|
2005-11-18 18:54:58 +03:00
|
|
|
}
|
2005-12-05 04:50:02 +03:00
|
|
|
resize_frame(col->frame[i], &col->frame[i]->rect, 0, 1);
|
2005-11-18 18:54:58 +03:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2005-12-05 01:45:59 +03:00
|
|
|
static void arrange_col(Area * a)
|
2005-11-18 18:54:58 +03:00
|
|
|
{
|
2005-12-05 01:45:59 +03:00
|
|
|
Acme *acme = a->aux;
|
|
|
|
int i;
|
2005-11-18 18:54:58 +03:00
|
|
|
|
|
|
|
if (!acme) {
|
|
|
|
fprintf(stderr, "%s", "wmiiwm: fatal, page has no layout\n");
|
|
|
|
exit(1);
|
|
|
|
}
|
|
|
|
for (i = 0; acme->column && acme->column[i]; i++)
|
2005-11-22 14:49:19 +03:00
|
|
|
arrange_column(a, acme->column[i]);
|
2005-11-18 18:54:58 +03:00
|
|
|
}
|
|
|
|
|
2005-12-05 01:45:59 +03:00
|
|
|
static void init_col(Area * a)
|
2005-11-18 18:54:58 +03:00
|
|
|
{
|
2005-12-05 01:45:59 +03:00
|
|
|
Acme *acme = emalloc(sizeof(Acme));
|
|
|
|
int i, j, n, cols = 1;
|
|
|
|
unsigned int width = 1;
|
|
|
|
Column *col;
|
2005-11-18 18:54:58 +03:00
|
|
|
|
|
|
|
*acme = zero_acme;
|
2005-11-22 14:49:19 +03:00
|
|
|
a->aux = acme;
|
2005-11-18 18:54:58 +03:00
|
|
|
|
|
|
|
/* processing argv */
|
2005-11-22 14:49:19 +03:00
|
|
|
/*
|
2005-12-05 01:45:59 +03:00
|
|
|
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
|
|
|
|
2005-11-22 14:49:19 +03:00
|
|
|
width = a->rect.width / cols;
|
2005-11-18 18:54:58 +03:00
|
|
|
acme->column = emalloc((cols + 1) * sizeof(Column *));
|
|
|
|
for (i = 0; i < cols; i++) {
|
|
|
|
acme->column[i] = emalloc(sizeof(Column));
|
|
|
|
*acme->column[i] = zero_column;
|
2005-11-22 14:49:19 +03:00
|
|
|
acme->column[i]->rect = a->rect;
|
2005-11-18 18:54:58 +03:00
|
|
|
acme->column[i]->rect.x = i * width;
|
|
|
|
acme->column[i]->rect.width = width;
|
|
|
|
acme->column[i]->refresh = 1;
|
|
|
|
}
|
2005-12-05 01:45:59 +03:00
|
|
|
acme->column[cols] = 0; /* null termination of array */
|
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
|
|
|
*/
|
2005-12-05 04:50:02 +03:00
|
|
|
n = count_items((void **) client);
|
2005-11-18 18:54:58 +03:00
|
|
|
if (n > cols) {
|
|
|
|
/* 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];
|
2005-12-05 04:50:02 +03:00
|
|
|
col->frame = 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++;
|
|
|
|
}
|
|
|
|
}
|
2005-11-23 14:53:24 +03:00
|
|
|
arrange_col(a);
|
2005-11-18 18:54:58 +03:00
|
|
|
}
|
|
|
|
|
2005-12-05 01:45:59 +03:00
|
|
|
static void deinit_col(Area * a)
|
2005-11-18 18:54:58 +03:00
|
|
|
{
|
2005-12-05 01:45:59 +03:00
|
|
|
Acme *acme = a->aux;
|
|
|
|
int i;
|
2005-11-18 18:54:58 +03:00
|
|
|
|
|
|
|
for (i = 0; acme->column && acme->column[i]; i++) {
|
2005-12-05 01:45:59 +03:00
|
|
|
Column *col = acme->column[i];
|
|
|
|
int j;
|
2005-12-05 04:50:02 +03:00
|
|
|
for (j = 0; col->frame && col->frame[j]; j++) {
|
|
|
|
Frame *f = col->frame[j];
|
|
|
|
while (f->client && f->client[0])
|
|
|
|
detach_client_from_frame(f->client[0], 0, 0);
|
2005-11-23 14:53:24 +03:00
|
|
|
detach_frame_from_area(f, 1);
|
2005-12-03 20:02:39 +03:00
|
|
|
destroy_frame(f);
|
2005-11-18 18:54:58 +03:00
|
|
|
}
|
2005-12-05 04:50:02 +03:00
|
|
|
free(col->frame);
|
2005-11-18 18:54:58 +03:00
|
|
|
}
|
|
|
|
free(acme->column);
|
|
|
|
free(acme);
|
2005-11-23 14:53:24 +03:00
|
|
|
a->aux = 0;
|
2005-11-18 18:54:58 +03:00
|
|
|
}
|
|
|
|
|
2005-12-05 01:45:59 +03:00
|
|
|
static void 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 = acme->column[acme->sel];
|
2005-12-05 22:38:03 +03:00
|
|
|
f = alloc_frame(&c->rect);
|
2005-12-05 04:52:26 +03:00
|
|
|
col->frame = (Frame **) attach_item_end((void **) col->frame, f, sizeof(Frame *));
|
2005-11-18 18:54:58 +03:00
|
|
|
f->aux = col;
|
|
|
|
col->refresh = 1;
|
2005-11-23 14:53:24 +03:00
|
|
|
attach_frame_to_area(a, f);
|
|
|
|
attach_client_to_frame(f, c);
|
2005-11-18 18:54:58 +03:00
|
|
|
|
2005-11-23 14:53:24 +03:00
|
|
|
arrange_col(a);
|
2005-11-18 18:54:58 +03:00
|
|
|
}
|
|
|
|
|
2005-12-05 01:45:59 +03:00
|
|
|
static void detach_col(Area * a, Client * c, int unmapped, int destroyed)
|
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
|
|
|
|
|
|
|
if (!col)
|
2005-12-05 01:45:59 +03:00
|
|
|
return; /* client was not attached, maybe exit(1) in
|
|
|
|
* such case */
|
2005-12-05 04:52:26 +03:00
|
|
|
col->frame = (Frame **) detach_item((void **) col->frame, c->frame, sizeof(Frame *));
|
2005-11-18 18:54:58 +03:00
|
|
|
col->refresh = 1;
|
|
|
|
detach_client_from_frame(c, unmapped, destroyed);
|
2005-11-23 14:53:24 +03:00
|
|
|
detach_frame_from_area(f, 1);
|
2005-12-03 20:02:39 +03:00
|
|
|
destroy_frame(f);
|
2005-11-18 18:54:58 +03:00
|
|
|
|
2005-11-23 14:53:24 +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
|
|
|
{
|
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, 1);
|
|
|
|
}
|
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, 1);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
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, 1);
|
|
|
|
}
|
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, 1);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
/* 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, 1);
|
|
|
|
resize_frame(f, &f->rect, 0, 1);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
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, 1);
|
|
|
|
resize_frame(south, &south->rect, 0, 1);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
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
|
|
|
{
|
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;
|
2005-11-18 18:54:58 +03:00
|
|
|
resize_frame(f, &f->rect, 0, 1);
|
|
|
|
resize_frame(fp, &fp->rect, 0, 1);
|
|
|
|
}
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
/* detach, attach and change order in target column */
|
2005-12-05 04:50:02 +03:00
|
|
|
src->frame = (Frame **) detach_item((void **) src->frame,
|
2005-12-05 01:45:59 +03:00
|
|
|
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;
|
2005-11-23 14:53:24 +03:00
|
|
|
arrange_column(f->area, tgt);
|
2005-11-18 18:54:58 +03:00
|
|
|
|
|
|
|
/* TODO: implement a better target placing strategy */
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2005-12-05 01:45:59 +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);
|
|
|
|
}
|