wmii/column.c

312 lines
8.1 KiB
C
Raw Normal View History

2006-10-12 18:10:57 +04:00
/* (C)opyright MMIV-MMVI Anselm R. Garbe <garbeam at gmail dot com>
2006-04-12 12:44:07 +04:00
* See LICENSE file for license details.
*/
2006-10-20 12:07:55 +04:00
#include "wmii.h"
2006-04-12 12:44:07 +04:00
#include <stdlib.h>
#include <string.h>
char *
2006-10-12 18:10:57 +04:00
str_of_column_mode(int mode) {
2006-04-12 12:44:07 +04:00
switch(mode) {
case Coldefault: return "default"; break;
case Colstack: return "stack"; break;
case Colmax: return "max"; break;
default: break;
}
2007-02-05 05:02:05 +03:00
return nil;
2006-04-12 12:44:07 +04:00
}
int
2006-10-12 18:10:57 +04:00
column_mode_of_str(char *arg) {
2006-04-12 12:44:07 +04:00
if(!strncmp("default", arg, 8))
return Coldefault;
if(!strncmp("stack", arg, 6))
return Colstack;
if(!strncmp("max", arg, 4))
return Colmax;
return -1;
}
static void
2006-10-12 18:10:57 +04:00
relax_column(Area *a) {
2006-06-08 12:54:19 +04:00
unsigned int frame_size, yoff, h;
Frame *f;
int hdiff;
2006-04-12 12:44:07 +04:00
Bool fallthrough = False;
2006-06-08 12:54:19 +04:00
if(!a->frame)
2006-04-12 12:44:07 +04:00
return;
frame_size = 0;
for(f=a->frame; f; f=f->anext)
frame_size++;
2006-04-12 12:44:07 +04:00
switch(a->mode) {
case Coldefault:
2006-06-08 12:54:19 +04:00
h = a->rect.height / frame_size;
2006-10-12 18:12:22 +04:00
if(h < 2 * labelh(&def.font))
2006-04-12 12:44:07 +04:00
fallthrough = True;
break;
case Colstack:
2006-10-12 18:12:22 +04:00
h = a->rect.height - (frame_size - 1) * labelh(&def.font);
if(h < 3 * labelh(&def.font))
2006-04-12 12:44:07 +04:00
fallthrough = True;
default:
yoff = a->rect.y;
2006-04-12 12:44:07 +04:00
break;
}
if(fallthrough) {
2006-06-08 12:54:19 +04:00
for(f=a->frame; f; f=f->anext) {
2006-04-12 12:44:07 +04:00
f->rect.x = a->rect.x + (a->rect.width - f->rect.width) / 2;
f->rect.y = a->rect.y + (a->rect.height - f->rect.height) / 2;
}
return;
}
/* some relaxing from potential increment gaps */
h = 0;
2006-06-08 12:54:19 +04:00
for(f=a->frame; f; f=f->anext) {
2006-04-12 12:44:07 +04:00
if(a->mode == Colmax) {
if(h < f->rect.height)
h = f->rect.height;
}
else
h += f->rect.height;
}
hdiff = a->rect.height - h;
if((a->mode == Coldefault) && (hdiff > 0)) {
int hx;
for(hx = 1; hx < hdiff; hx++)
2006-06-08 12:54:19 +04:00
for(f=a->frame; f && (hx < hdiff); f=f->anext) {
unsigned int tmp = f->rect.height;
f->rect.height += hx;
match_sizehints(f->client, &f->rect, f->area->floating, NORTH|EAST);
hdiff -= (f->rect.height - tmp);
}
2006-04-12 12:44:07 +04:00
}
if(hdiff < 0)
hdiff = 0;
2006-06-08 12:54:19 +04:00
hdiff /= frame_size;
2006-04-12 12:44:07 +04:00
yoff = a->rect.y + hdiff / 2;
2006-06-08 12:54:19 +04:00
for(f=a->frame; f; f=f->anext) {
2006-04-12 12:44:07 +04:00
f->rect.y = yoff;
if(a->mode != Colmax || f == a->sel) {
f->rect.x = a->rect.x + (a->rect.width - f->rect.width) / 2;
2006-04-12 12:44:07 +04:00
yoff = f->rect.y + f->rect.height + hdiff;
}
if(a->mode != Colstack || f == a->sel)
match_sizehints(f->client, &f->rect, f->area->floating, NORTH|EAST);
2006-04-12 12:44:07 +04:00
}
}
void
2006-10-12 18:10:57 +04:00
scale_column(Area *a, float h) {
2006-06-08 12:54:19 +04:00
unsigned int yoff, frame_size = 0;
Frame *f;
2006-10-12 18:12:22 +04:00
unsigned int min_height = 2 * labelh(&def.font);
2006-04-24 18:03:37 +04:00
float scale, dy = 0;
int hdiff;
2006-04-24 18:03:37 +04:00
2006-06-08 12:54:19 +04:00
if(!a->frame)
2006-04-24 18:03:37 +04:00
return;
2006-06-08 12:54:19 +04:00
for(f=a->frame; f; f=f->anext, frame_size++)
dy += f->rect.height;
2006-04-24 18:03:37 +04:00
scale = h / dy;
2006-05-04 00:25:33 +04:00
yoff = 0;
2006-06-08 12:54:19 +04:00
for(f=a->frame; f; f=f->anext) {
2006-04-24 18:03:37 +04:00
f->rect.height *= scale;
2006-06-08 12:54:19 +04:00
if(!f->anext)
2006-05-04 01:26:21 +04:00
f->rect.height = h - yoff;
yoff += f->rect.height;
2006-04-24 18:03:37 +04:00
}
/* min_height can only be respected when there is enough space; the caller should guarantee this */
2006-06-08 12:54:19 +04:00
if(frame_size * min_height > h)
return;
2006-05-04 01:26:21 +04:00
yoff = 0;
for(f=a->frame, frame_size--; f; f=f->anext, frame_size--) {
if(f->rect.height < min_height)
f->rect.height = min_height;
2006-06-08 12:54:19 +04:00
else if((hdiff = yoff + f->rect.height - h + frame_size * min_height) > 0)
f->rect.height -= hdiff;
2006-06-08 12:54:19 +04:00
if(!f->anext)
f->rect.height = h - yoff;
yoff += f->rect.height;
}
2006-04-24 18:03:37 +04:00
}
void
2006-10-12 18:10:57 +04:00
arrange_column(Area *a, Bool dirty) {
2006-06-08 12:54:19 +04:00
Frame *f;
unsigned int num_frames = 0, yoff = a->rect.y, h;
2006-10-12 18:12:22 +04:00
unsigned int min_height = 2 * labelh(&def.font);
2006-04-12 12:44:07 +04:00
if(a->floating || !a->frame)
2006-04-12 12:44:07 +04:00
return;
for(f=a->frame; f; f=f->anext)
num_frames++;
2006-04-12 12:44:07 +04:00
switch(a->mode) {
case Coldefault:
2006-06-08 12:54:19 +04:00
h = a->rect.height / num_frames;
if(h < min_height)
2006-04-12 12:44:07 +04:00
goto Fallthrough;
if(dirty) {
2006-06-08 12:54:19 +04:00
for(f=a->frame; f; f=f->anext)
f->rect.height = h;
2006-04-12 12:44:07 +04:00
}
2006-04-24 18:03:37 +04:00
scale_column(a, a->rect.height);
2006-06-08 12:54:19 +04:00
for(f=a->frame; f; f=f->anext) {
f->rect.x = a->rect.x;
f->rect.y = yoff;
f->rect.width = a->rect.width;
yoff += f->rect.height;
match_sizehints(f->client, &f->rect, f->area->floating, NORTH|EAST);
}
2006-04-12 12:44:07 +04:00
break;
case Colstack:
2006-10-12 18:12:22 +04:00
h = a->rect.height - (num_frames - 1) * labelh(&def.font);
if(h < 3 * labelh(&def.font))
2006-04-12 12:44:07 +04:00
goto Fallthrough;
2006-06-08 12:54:19 +04:00
for(f=a->frame; f; f=f->anext) {
2006-04-12 12:44:07 +04:00
f->rect = a->rect;
f->rect.y = yoff;
2006-06-08 12:54:19 +04:00
if(f == a->sel)
2006-04-12 12:44:07 +04:00
f->rect.height = h;
else
2006-10-12 18:12:22 +04:00
f->rect.height = labelh(&def.font);
2006-04-12 12:44:07 +04:00
yoff += f->rect.height;
}
break;
Fallthrough:
case Colmax:
2006-06-08 12:54:19 +04:00
for(f=a->frame; f; f=f->anext) {
2006-04-12 12:44:07 +04:00
f->rect = a->rect;
if(f != a->sel) f->rect.x = screen->rect.width * 2;
match_sizehints(f->client, &f->rect, f->area->floating, NORTH|EAST);
2006-04-12 12:44:07 +04:00
}
break;
default:
break;
}
relax_column(a);
flush_masked_events(EnterWindowMask);
2006-04-12 12:44:07 +04:00
}
static void
2006-10-12 18:10:57 +04:00
match_horiz(Area *a, XRectangle *r) {
2006-06-08 12:54:19 +04:00
Frame *f;
2006-04-12 12:44:07 +04:00
2006-06-08 12:54:19 +04:00
for(f=a->frame; f; f=f->anext) {
2006-04-12 12:44:07 +04:00
f->rect.x = r->x;
f->rect.width = r->width;
resize_frame(f, &f->rect);
2006-04-12 12:44:07 +04:00
}
}
static void
2006-10-12 18:10:57 +04:00
drop_resize(Frame *f, XRectangle *new) {
2007-02-05 05:02:05 +03:00
Area *west = nil, *east = nil, *a = f->area;
2006-04-12 12:44:07 +04:00
View *v = a->view;
2007-02-05 05:02:05 +03:00
Frame *north = nil, *south = nil;
2006-10-12 18:12:22 +04:00
unsigned int min_height = 2 * labelh(&def.font);
unsigned int min_width = screen->rect.width/NCOL;
2006-04-12 12:44:07 +04:00
2006-06-08 12:54:19 +04:00
for(west=v->area->next; west && west->next != a; west=west->next);
2006-04-12 12:44:07 +04:00
/* first managed area is indexed 1, thus (i > 1) ? ... */
east = a->next;
2006-06-08 12:54:19 +04:00
for(north=a->frame; north && north->anext != f; north=north->anext);
south = f->anext;
2006-04-12 12:44:07 +04:00
/* validate (and trim if necessary) horizontal resize */
if(new->width < min_width) {
2006-04-12 12:44:07 +04:00
if(new->x + new->width == f->rect.x + f->rect.width)
new->x = a->rect.x + a->rect.width - min_width;
new->width = min_width;
2006-04-12 12:44:07 +04:00
}
if(west && (new->x != f->rect.x)) {
if(new->x < 0 || new->x < (west->rect.x + min_width)) {
new->width -= (west->rect.x + min_width) - new->x;
new->x = west->rect.x + min_width;
2006-04-12 12:44:07 +04:00
}
} else {
new->width += new->x - a->rect.x;
new->x = a->rect.x;
}
if(east && (new->x + new->width != f->rect.x + f->rect.width)) {
if((new->x + new->width) > (east->rect.x + east->rect.width - min_width))
new->width = (east->rect.x + east->rect.width - min_width) - new->x;
2006-04-12 12:44:07 +04:00
} else
new->width = (a->rect.x + a->rect.width) - new->x;
if(new->width < min_width)
2006-04-12 12:44:07 +04:00
goto AfterHorizontal;
/* horizontal resize */
if(west && (new->x != a->rect.x)) {
west->rect.width = new->x - west->rect.x;
a->rect.width += a->rect.x - new->x;
a->rect.x = new->x;
match_horiz(a, &a->rect);
match_horiz(west, &west->rect);
relax_column(west);
}
if(east && (new->x + new->width != a->rect.x + a->rect.width)) {
east->rect.width -= new->x + new->width - east->rect.x;
east->rect.x = new->x + new->width;
a->rect.width = (new->x + new->width) - a->rect.x;
match_horiz(a, &a->rect);
match_horiz(east, &east->rect);
relax_column(east);
}
AfterHorizontal:
/* skip vertical resize unless the column is in equal mode */
if(a->mode != Coldefault)
goto AfterVertical;
/* validate (and trim if necessary) vertical resize */
if(new->height < min_height) {
if(f->rect.height < min_height
&& (new->y == f->rect.y || new->y + new->height == f->rect.y + f->rect.height))
goto AfterVertical;
if(new->y + new->height == f->rect.y + f->rect.height)
new->y = f->rect.y + f->rect.height - min_height;
new->height = min_height;
}
if(north && (new->y != f->rect.y))
if(new->y < 0 || new->y < (north->rect.y + min_height)) {
new->height -= (north->rect.y + min_height) - new->y;
new->y = north->rect.y + min_height;
}
if(south && (new->y + new->height != f->rect.y + f->rect.height)) {
if((new->y + new->height) > (south->rect.y + south->rect.height - min_height))
new->height = (south->rect.y + south->rect.height - min_height) - new->y;
}
if(new->height < min_height)
goto AfterVertical;
/* vertical resize */
if(north && (new->y != f->rect.y)) {
north->rect.height = new->y - north->rect.y;
f->rect.height += f->rect.y - new->y;
f->rect.y = new->y;
resize_frame(north, &north->rect);
resize_frame(f, &f->rect);
2006-04-12 12:44:07 +04:00
}
if(south && (new->y + new->height != f->rect.y + f->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);
resize_frame(south, &south->rect);
2006-04-12 12:44:07 +04:00
}
AfterVertical:
relax_column(a);
focus_view(screen, v);
2006-04-12 12:44:07 +04:00
}
void
2007-02-05 09:00:42 +03:00
resize_column(Client *c, XRectangle *r) {
drop_resize(c->sel, r);
2006-04-12 12:44:07 +04:00
}
Area *
2006-06-08 12:54:19 +04:00
new_column(View *v, Area *pos, unsigned int w) {
Area *a = create_area(v, pos, w);
if(!a)
2007-02-05 05:02:05 +03:00
return nil;
2006-04-24 19:19:50 +04:00
arrange_view(v);
return a;
}