mirror of
https://github.com/0intro/wmii
synced 2024-11-30 01:23:12 +03:00
313 lines
7.1 KiB
C
313 lines
7.1 KiB
C
/* (C)opyright MMIV-MMVI Anselm R. Garbe <garbeam at gmail dot com>
|
|
* See LICENSE file for license details.
|
|
*/
|
|
#include "wmii.h"
|
|
#include <assert.h>
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
#include <math.h>
|
|
|
|
char *
|
|
str_of_column_mode(int mode) {
|
|
switch(mode) {
|
|
case Coldefault: return "default"; break;
|
|
case Colstack: return "stack"; break;
|
|
case Colmax: return "max"; break;
|
|
default: break;
|
|
}
|
|
return nil;
|
|
}
|
|
|
|
int
|
|
column_mode_of_str(char *arg) {
|
|
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
|
|
scale_column(Area *a) {
|
|
Frame *f, **fp;
|
|
uint min_height, yoff, dy;
|
|
uint num_col, num_uncol;
|
|
uint col_h, uncol_h;
|
|
int surplus, i, j;
|
|
|
|
if(!a->frame)
|
|
return;
|
|
|
|
/* This works by comparing heights based on a surplus of their
|
|
* minimum size. We start by subtracting the minimum size, then
|
|
* scale the surplus, and add back the minimum size later. This
|
|
* is based on the size of the client, rather than the frame, so
|
|
* increment gaps can be equalized later */
|
|
/* Frames that can't be accomodated are pushed to the floating layer */
|
|
|
|
min_height = labelh(&def.font);
|
|
col_h = labelh(&def.font);
|
|
uncol_h = min_height + frame_delta_h();
|
|
|
|
num_col = 0;
|
|
num_uncol = 0;
|
|
dy = 0;
|
|
for(f=a->frame; f; f=f->anext)
|
|
if(f->collapsed)
|
|
num_col++;
|
|
else
|
|
num_uncol++;
|
|
|
|
surplus = a->rect.height;
|
|
surplus -= num_col * col_h;
|
|
surplus -= num_uncol * uncol_h;
|
|
if(surplus < 0) {
|
|
i = ceil((float)(-surplus)/(uncol_h - col_h));
|
|
if(i >= num_uncol)
|
|
i = num_uncol - 1;
|
|
num_uncol -= i;
|
|
num_col += i;
|
|
surplus += i * (uncol_h - col_h);
|
|
}
|
|
if(surplus < 0) {
|
|
i = ceil((float)(-surplus)/col_h);
|
|
if(i > num_col)
|
|
i = num_col;
|
|
num_col -= i;
|
|
surplus += i * col_h;
|
|
}
|
|
|
|
i = num_col - 1;
|
|
j = num_uncol - 1;
|
|
for(f=a->frame; f; f=f->anext) {
|
|
if(f == a->sel)
|
|
j++;
|
|
if(!f->collapsed) {
|
|
if(j < 0 && f != a->sel)
|
|
f->collapsed = True;
|
|
else {
|
|
if(f->crect.height <= min_height)
|
|
f->crect.height = 1;
|
|
else
|
|
f->crect.height -= min_height;
|
|
dy += f->crect.height;
|
|
}
|
|
j--;
|
|
}
|
|
}
|
|
for(fp=&a->frame; *fp;) {
|
|
f = *fp;
|
|
if(f == a->sel)
|
|
i++;
|
|
if(f->collapsed) {
|
|
if(i < 0 && f != a->sel) {
|
|
f->collapsed = False;
|
|
send_to_area(f->view->area, f);
|
|
continue;
|
|
}
|
|
i--;
|
|
}
|
|
fp=&f->anext;
|
|
}
|
|
|
|
i = num_uncol;
|
|
for(f=a->frame; f; f=f->anext) {
|
|
f->rect.x = a->rect.x;
|
|
f->rect.width = a->rect.width;
|
|
if(!f->collapsed) {
|
|
i--;
|
|
f->rect.height = (float)f->crect.height / dy * surplus;
|
|
if(!i)
|
|
f->rect.height = surplus;
|
|
f->rect.height += min_height + frame_delta_h();
|
|
match_sizehints(f->client, &f->rect, False, NWEST);
|
|
|
|
dy -= f->crect.height;
|
|
surplus -= f->rect.height - frame_delta_h() - min_height;
|
|
}else
|
|
f->rect.height = labelh(&def.font);
|
|
}
|
|
|
|
yoff = a->rect.y;
|
|
i = num_uncol;
|
|
for(f=a->frame; f; f=f->anext) {
|
|
f->rect.y = yoff;
|
|
f->rect.x = a->rect.x;
|
|
f->rect.width = a->rect.width;
|
|
if(f->collapsed)
|
|
yoff += f->rect.height;
|
|
else{
|
|
i--;
|
|
f->rect.height += surplus / num_uncol;
|
|
if(!i)
|
|
f->rect.height += surplus % num_uncol;
|
|
yoff += f->rect.height;
|
|
}
|
|
}
|
|
}
|
|
|
|
void
|
|
arrange_column(Area *a, Bool dirty) {
|
|
Frame *f;
|
|
|
|
if(a->floating || !a->frame)
|
|
return;
|
|
|
|
switch(a->mode) {
|
|
case Coldefault:
|
|
for(f=a->frame; f; f=f->anext) {
|
|
f->collapsed = False;
|
|
if(dirty)
|
|
f->crect.height = 100;
|
|
}
|
|
break;
|
|
case Colstack:
|
|
for(f=a->frame; f; f=f->anext)
|
|
f->collapsed = (f != a->sel);
|
|
break;
|
|
case Colmax:
|
|
for(f=a->frame; f; f=f->anext) {
|
|
f->collapsed = False;
|
|
f->rect = a->rect;
|
|
}
|
|
goto resize;
|
|
default:
|
|
break;
|
|
}
|
|
scale_column(a);
|
|
resize:
|
|
if(a->view == screen->sel)
|
|
for(f=a->frame; f; f=f->anext)
|
|
resize_client(f->client, &f->rect);
|
|
flush_masked_events(EnterWindowMask);
|
|
}
|
|
|
|
static void
|
|
match_horiz(Area *a, XRectangle *r) {
|
|
Frame *f;
|
|
|
|
for(f=a->frame; f; f=f->anext) {
|
|
f->rect.x = r->x;
|
|
f->rect.width = r->width;
|
|
resize_frame(f, &f->rect);
|
|
}
|
|
}
|
|
|
|
void
|
|
resize_column(Client *c, XRectangle *new) {
|
|
Area *west, *east, *a;
|
|
Frame *north, *south, *f;
|
|
View *v;
|
|
BlitzAlign sticky;
|
|
uint min_height;
|
|
uint min_width;
|
|
|
|
f = c->sel;
|
|
a = f->area;
|
|
v = a->view;
|
|
min_height = 2 * labelh(&def.font);
|
|
min_width = screen->rect.width/NCOL;
|
|
|
|
for(west=v->area->next; west; west=west->next)
|
|
if(west->next == a) break;
|
|
east = a->next;
|
|
for(north=a->frame; north; north=north->anext)
|
|
if(north->anext == f) break;
|
|
south = f->anext;
|
|
/* validate (and trim if necessary) horizontal resize */
|
|
sticky = get_sticky(&f->rect, new);
|
|
if(new->width < min_width) {
|
|
if(sticky & EAST)
|
|
new->x = r_east(&a->rect) - min_width;
|
|
new->width = min_width;
|
|
}
|
|
if(west && !(sticky & WEST)) {
|
|
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;
|
|
}
|
|
} else {
|
|
new->width += new->x - a->rect.x;
|
|
new->x = a->rect.x;
|
|
}
|
|
if(east && !(sticky & EAST)) {
|
|
if(r_east(new) > r_east(&east->rect) - min_width)
|
|
new->width = r_east(&east->rect) - min_width - new->x;
|
|
} else
|
|
new->width = r_east(&a->rect) - new->x;
|
|
if(new->width < min_width)
|
|
goto AfterHorizontal;
|
|
/* horizontal resize */
|
|
sticky = get_sticky(&a->rect, new);
|
|
if(west && !(sticky & WEST)) {
|
|
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 && !(sticky & EAST)) {
|
|
east->rect.width -= r_east(new) - east->rect.x;
|
|
east->rect.x = r_east(new);
|
|
a->rect.width = r_east(new) - 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 */
|
|
sticky = get_sticky(&f->rect, new);
|
|
if(new->height < min_height) {
|
|
if((f->rect.height < min_height) && sticky & (NORTH|SOUTH))
|
|
goto AfterVertical;
|
|
if(sticky & SOUTH)
|
|
new->y = r_south(&f->rect) - min_height;
|
|
new->height = min_height;
|
|
}
|
|
if(north && !(sticky & NORTH))
|
|
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 && !(sticky & SOUTH)) {
|
|
if(r_south(new) > r_south(&south->rect) - min_height)
|
|
new->height = r_south(&south->rect) - min_height - new->y;
|
|
}
|
|
if(new->height < min_height)
|
|
goto AfterVertical;
|
|
/* vertical resize */
|
|
if(north && !(sticky & NORTH)) {
|
|
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);
|
|
}
|
|
if(south && !(sticky & SOUTH)) {
|
|
south->rect.height -= r_south(new) - south->rect.y;
|
|
south->rect.y = r_south(new);
|
|
f->rect.y = new->y;
|
|
f->rect.height = new->height;
|
|
resize_frame(f, &f->rect);
|
|
resize_frame(south, &south->rect);
|
|
}
|
|
AfterVertical:
|
|
//relax_column(a);
|
|
focus_view(screen, v);
|
|
}
|
|
|
|
Area *
|
|
new_column(View *v, Area *pos, uint w) {
|
|
Area *a = create_area(v, pos, w);
|
|
if(!a)
|
|
return nil;
|
|
arrange_view(v);
|
|
return a;
|
|
}
|