wmii/area.c

416 lines
8.0 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>
* See LICENSE file for license details.
*/
2006-10-20 12:07:55 +04:00
#include "wmii.h"
2006-10-12 18:10:57 +04:00
#include <assert.h>
#include <stdlib.h>
2006-06-08 12:54:19 +04:00
#include <stdio.h>
#include <string.h>
static void place_client(Area *a, Client *c);
static int
max(int a, int b) {
if(a > b)
return a;
return b;
}
Client *
2006-10-12 18:10:57 +04:00
sel_client_of_area(Area *a) {
2007-02-06 05:56:03 +03:00
if(a && a->sel)
return a->sel->client;
return nil;
2006-06-25 17:16:03 +04:00
}
Area *
2006-10-12 18:10:57 +04:00
create_area(View *v, Area *pos, unsigned int w) {
static unsigned short id = 1;
unsigned int area_num, col_num, i;
2007-02-05 08:41:13 +03:00
unsigned int min_width;
Area *a, **p;
2007-02-05 08:41:13 +03:00
min_width = screen->rect.width/NCOL;
p = pos ? &pos->next : &v->area;
2006-06-08 12:54:19 +04:00
area_num = 0;
2007-02-05 08:41:13 +03:00
i = 0;
2007-02-06 05:56:03 +03:00
for(a = v->area; a != *p; a = a->next)
2007-02-05 08:41:13 +03:00
area_num++, i++;
for(; a; a = a->next) area_num++;
col_num = max((area_num - 1), 0);
if(!w) {
if(area_num)
w = screen->rect.width / (col_num + 1);
else
w = screen->rect.width;
}
if(w < min_width)
w = min_width;
2007-02-07 04:47:03 +03:00
if(col_num && (col_num * min_width + w) > screen->rect.width)
2007-02-05 05:02:05 +03:00
return nil;
if(i)
scale_view(v, screen->rect.width - w);
2007-02-05 08:41:13 +03:00
2006-10-12 18:10:57 +04:00
a = ixp_emallocz(sizeof(Area));
a->view = v;
a->id = id++;
a->rect = screen->rect;
a->rect.height = screen->rect.height - screen->brect.height;
a->mode = def.colmode;
a->rect.width = w;
2007-02-05 05:02:05 +03:00
a->frame = nil;
a->sel = nil;
2006-06-08 12:54:19 +04:00
a->next = *p;
*p = a;
2007-02-05 08:41:13 +03:00
if(i)
write_event("CreateColumn %d\n", i);
focus_area(a);
return a;
}
void
2006-10-12 18:10:57 +04:00
destroy_area(Area *a) {
2006-06-08 12:54:19 +04:00
Client *c;
Area *ta;
2007-02-07 04:47:03 +03:00
View *v;
unsigned int i;
2007-02-07 04:47:03 +03:00
v = a->view;
2006-10-12 18:10:57 +04:00
assert(!a->frame && "wmiiwm: fatal, destroying non-empty area");
2006-06-08 12:54:19 +04:00
if(v->revert == a)
2007-02-05 05:02:05 +03:00
v->revert = nil;
2006-06-08 12:54:19 +04:00
for(c=client; c; c=c->next)
if(c->revert == a)
2007-02-05 05:02:05 +03:00
c->revert = nil;
2007-02-07 04:47:03 +03:00
i = 1;
for(ta=v->area; ta; ta=ta->next)
if(ta->next == a) break;
else i++;
if(ta) {
ta->next = a->next;
if(ta->floating && ta->next)
ta = ta->next;
if(v->sel == a)
focus_area(ta);
2006-06-08 12:54:19 +04:00
}
if(i) write_event("DestroyColumn %d\n", i);
2006-06-08 12:54:19 +04:00
free(a);
}
void
send_to_area(Area *to, Area *from, Frame *f) {
assert(to->view == f->view);
if(to->floating != from->floating) {
XRectangle temp = f->revert;
f->revert = f->rect;
f->rect = temp;
}
f->client->revert = from;
detach_from_area(from, f);
attach_to_area(to, f, True);
}
void
attach_to_area(Area *a, Frame *f, Bool send) {
unsigned int h, n_frame;
Frame *ft;
Client *c;
View *v;
v = a->view;
c = f->client;
h = 0;
n_frame = 1;
for(ft=a->frame; ft; ft=ft->anext)
n_frame++;
c->floating = a->floating;
if(!a->floating) {
h = a->rect.height / n_frame;
if(a->frame)
scale_column(a, a->rect.height - h);
}
if(!send && !a->floating) { /* column */
unsigned int w = newcolw_of_view(v);
if(v->area->next->frame && w) {
a = new_column(v, a, w);
arrange_view(v);
}
}
f->area = a;
if(a->sel)
insert_frame(nil, f, False);
else
insert_frame(a->sel, f, False);
if(!c->floating) /* column */
f->rect.height = h;
else /* floating */
place_client(a, c);
if(!a->floating)
arrange_column(a, False);
focus_client(f->client, False);
update_client_grab(f->client);
}
void
detach_from_area(Area *a, Frame *f) {
Frame *pr;
Client *c;
View *v;
Area *ta;
unsigned int i;
v = a->view;
c = f->client;
for(pr = a->frame; pr; pr = pr->anext)
if(pr->anext == f) break;
remove_frame(f);
if(a->sel == f)
a->sel = pr;
if(a->sel == nil)
a->sel = a->frame;
if(!a->floating) {
if(a->frame)
arrange_column(a, False);
else {
i = 0;
for(ta=v->area; ta && ta != a; ta=ta->next)
i++;
if(v->area->next->next)
destroy_area(a);
else if(!a->frame && v->area->frame)
/* focus floating area if it contains something */
focus_area(v->area);
arrange_view(v);
}
}
else if(!a->frame) {
if(c->trans) {
/* focus area of transient, if possible */
Client *cl = client_of_win(c->trans);
if(cl && cl->frame) {
a = cl->sel->area;
if(a->view == v)
focus_area(a);
}
}
else if(v->area->next->frame)
focus_area(v->area->next);
}
}
static void
2006-10-12 18:10:57 +04:00
place_client(Area *a, Client *c) {
static unsigned int mx, my;
2007-02-07 04:47:03 +03:00
static Bool *field;
BlitzAlign align;
XPoint p1 = {0, 0};
XPoint p2 = {0, 0};
XRectangle *rects;
2007-02-07 04:47:03 +03:00
Frame *f, *fr;
Bool fit;
unsigned int i, j, x, y, dx, dy, cx, cy, maxx, maxy, diff, num;
int snap;
snap = screen->rect.height / 66;
num = 0;
fit = False;
align = CENTER;
field = nil;
2007-02-07 04:47:03 +03:00
f = c->sel;
if(c->trans)
return;
if(c->rect.width >= a->rect.width
|| c->rect.height >= a->rect.height
|| c->size.flags & USPosition
|| c->size.flags & PPosition)
return;
rects = rects_of_view(a->view, &num);
if(!field) {
mx = screen->rect.width / 8;
my = screen->rect.height / 8;
2006-10-12 18:10:57 +04:00
field = ixp_emallocz(my * mx * sizeof(Bool));
}
for(y = 0; y < my; y++)
for(x = 0; x < mx; x++)
field[y*mx + x] = True;
dx = screen->rect.width / mx;
dy = screen->rect.height / my;
for(fr=a->frame; fr; fr=fr->anext) {
if(fr == f) {
cx = f->rect.width / dx;
cy = f->rect.height / dy;
continue;
}
if(fr->rect.x < 0)
x = 0;
else
x = fr->rect.x / dx;
if(fr->rect.y < 0)
y = 0;
else
y = fr->rect.y / dy;
maxx = (fr->rect.x + fr->rect.width) / dx;
maxy = (fr->rect.y + fr->rect.height) / dy;
for(j = y; j < my && j < maxy; j++)
for(i = x; i < mx && i < maxx; i++)
field[j*mx + i] = False;
}
for(y = 0; y < my; y++)
for(x = 0; x < mx; x++) {
if(field[y*mx + x]) {
for(i = x; (i < mx) && field[y*mx + i]; i++);
for(j = y; (j < my) && field[j*mx + x]; j++);
if(((i - x) * (j - y) > (p2.x - p1.x) * (p2.y - p1.y))
&& (i - x > cx) && (j - y > cy))
{
fit = True;
p1.x = x;
p1.y = y;
p2.x = i;
p2.y = j;
}
}
}
if(fit) {
p1.x *= dx;
p1.y *= dy;
}
if(fit && (p1.x + f->rect.width < a->rect.x + a->rect.width))
f->rect.x = p1.x;
else {
diff = a->rect.width - f->rect.width;
f->rect.x = a->rect.x + (random() % (diff ? diff : 1));
}
if(fit && (p1.y + f->rect.height < a->rect.y + a->rect.height))
f->rect.y = p1.y;
else {
diff = a->rect.height - f->rect.height;
f->rect.y = a->rect.y + (random() % (diff ? diff : 1));
}
snap_rect(rects, num, &f->rect, &align, snap);
if(rects)
free(rects);
}
2006-06-25 17:16:03 +04:00
void
focus_area(Area *a) {
Frame *f;
2007-02-07 04:47:03 +03:00
View *v;
Area *old_a;
int i;
2006-06-25 17:16:03 +04:00
2007-02-07 04:47:03 +03:00
v = a->view;
f = a->sel;
old_a = v->sel;
2007-02-07 04:47:03 +03:00
/* XXX: Replace this with an assert later */
if(a == old_a)
return;
2007-02-07 04:47:03 +03:00
v->sel = a;
if(v != screen->sel)
return;
if(f)
XSetInputFocus(blz.dpy, f->client->win, RevertToPointerRoot, CurrentTime);
else
XSetInputFocus(blz.dpy, blz.root, RevertToPointerRoot, CurrentTime);
if(f) {
update_frame_widget_colors(f);
draw_frame(f);
2006-06-25 17:16:03 +04:00
}
if(old_a) {
if(old_a->sel) {
update_frame_widget_colors(old_a->sel);
draw_frame(old_a->sel);
2006-06-25 17:16:03 +04:00
}
if(a->floating != old_a->floating)
v->revert = old_a;
2006-06-25 17:16:03 +04:00
}
2007-02-10 05:29:21 +03:00
2006-06-25 17:16:03 +04:00
if(a != old_a) {
2007-02-07 04:47:03 +03:00
i = 0;
for(a = v->area; a != v->sel; a = a->next)
2007-02-07 04:47:03 +03:00
i++;
if(i)
write_event("ColumnFocus %d\n", i);
else
write_event("FocusFloating\n");
2006-06-25 17:16:03 +04:00
}
}
2006-06-20 02:25:49 +04:00
char *
2006-10-12 18:10:57 +04:00
select_area(Area *a, char *arg) {
Area *new;
2006-06-08 12:54:19 +04:00
unsigned int i;
2006-06-20 02:25:49 +04:00
Frame *p, *f;
View *v;
static char Ebadvalue[] = "bad value";
2006-06-20 02:25:49 +04:00
v = a->view;
f = a->sel;
if(!strncmp(arg, "toggle", 7)) {
if(!a->floating)
2006-06-08 12:54:19 +04:00
new = v->area;
else if(v->revert)
2006-06-08 12:54:19 +04:00
new = v->revert;
else
2006-06-08 12:54:19 +04:00
new = v->area->next;
2006-06-20 02:25:49 +04:00
} else if(!strncmp(arg, "left", 5)) {
if(a->floating)
2006-06-20 02:25:49 +04:00
return Ebadvalue;
2007-02-07 20:08:25 +03:00
for(new=v->area->next; new->next; new=new->next)
if(new->next == a) break;
2006-06-20 02:25:49 +04:00
} else if(!strncmp(arg, "right", 5)) {
if(a->floating)
2006-06-20 02:25:49 +04:00
return Ebadvalue;
2007-02-07 20:08:25 +03:00
new = a->next ? a->next : v->area->next;
}
else if(!strncmp(arg, "up", 3)) {
if(!f)
return Ebadvalue;
2006-06-20 02:25:49 +04:00
for(p=a->frame; p->anext; p=p->anext)
if(p->anext == f) break;
goto focus_client;
}
else if(!strncmp(arg, "down", 5)) {
if(!f)
return Ebadvalue;
p = f->anext ? f->anext : a->frame;
goto focus_client;
}
else {
if(sscanf(arg, "%d", &i) != 1)
2006-06-20 02:25:49 +04:00
return Ebadvalue;
2007-02-07 04:47:03 +03:00
for(new=view->area; i && new->next; new=new->next)
i--;
}
focus_area(new);
2007-02-05 05:02:05 +03:00
return nil;
focus_client:
frame_to_top(p);
focus_client(p->client, True);
if(v == screen->sel)
restack_view(v);
flush_masked_events(EnterWindowMask);
return nil;
}