2006-02-03 18:15:36 +03:00
|
|
|
/*
|
|
|
|
* (C)opyright MMIV-MMVI Anselm R. Garbe <garbeam at gmail dot com>
|
|
|
|
* See LICENSE file for license details.
|
|
|
|
*/
|
|
|
|
|
|
|
|
#include <stdlib.h>
|
2006-02-19 18:21:01 +03:00
|
|
|
#include <string.h>
|
2006-02-03 18:15:36 +03:00
|
|
|
|
|
|
|
#include "wm.h"
|
|
|
|
|
2006-04-03 15:40:34 +04:00
|
|
|
static Vector *
|
2006-04-13 17:35:10 +04:00
|
|
|
vector_of_areas(AreaVector *av)
|
2006-04-03 00:53:56 +04:00
|
|
|
{
|
2006-04-03 15:40:34 +04:00
|
|
|
return (Vector *) av;
|
2006-04-03 00:53:56 +04:00
|
|
|
}
|
|
|
|
|
2006-02-03 18:15:36 +03:00
|
|
|
Area *
|
2006-04-12 12:44:07 +04:00
|
|
|
create_area(View *v)
|
2006-02-03 18:15:36 +03:00
|
|
|
{
|
2006-04-24 19:39:58 +04:00
|
|
|
static unsigned short id = 1;
|
2006-05-04 01:11:14 +04:00
|
|
|
unsigned int w;
|
2006-04-24 19:39:58 +04:00
|
|
|
Area *a = nil;
|
|
|
|
|
|
|
|
if(v->area.size > 1) {
|
|
|
|
if(def.colw)
|
|
|
|
w = def.colw;
|
|
|
|
else
|
|
|
|
w = rect.width / v->area.size - 1;
|
|
|
|
}
|
2006-04-14 14:45:53 +04:00
|
|
|
else
|
2006-04-24 19:39:58 +04:00
|
|
|
w = rect.width;
|
2006-05-04 03:20:32 +04:00
|
|
|
if(w < MIN_COLWIDTH)
|
|
|
|
w = MIN_COLWIDTH;
|
2006-04-24 19:39:58 +04:00
|
|
|
|
2006-04-14 14:45:53 +04:00
|
|
|
if(v->area.size >= 2 && (v->area.size - 1) * MIN_COLWIDTH + w > rect.width)
|
2006-04-14 00:44:31 +04:00
|
|
|
return nil;
|
2006-04-24 19:39:58 +04:00
|
|
|
|
|
|
|
if(v->area.size > 1)
|
|
|
|
scale_view(v, rect.width - w);
|
|
|
|
a = cext_emallocz(sizeof(Area));
|
|
|
|
a->view = v;
|
|
|
|
a->id = id++;
|
|
|
|
a->rect = rect;
|
|
|
|
a->rect.height = rect.height - brect.height;
|
|
|
|
a->mode = def.colmode;
|
|
|
|
a->rect.width = w;
|
|
|
|
cext_vattach(vector_of_areas(&v->area), a);
|
|
|
|
v->sel = v->area.size - 1;
|
|
|
|
return a;
|
2006-02-03 18:15:36 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
destroy_area(Area *a)
|
|
|
|
{
|
2006-03-11 22:50:53 +03:00
|
|
|
unsigned int i;
|
2006-03-23 12:36:51 +03:00
|
|
|
View *v = a->view;
|
2006-05-01 22:53:30 +04:00
|
|
|
if(a->frame.size) {
|
|
|
|
fprintf(stderr, "%s", "wmiiwm: fatal, destroying non-empty area\n");
|
|
|
|
exit(1);
|
|
|
|
}
|
2006-04-03 00:53:56 +04:00
|
|
|
if(a->frame.data)
|
|
|
|
free(a->frame.data);
|
2006-04-12 12:44:07 +04:00
|
|
|
if(v->revert == idx_of_area(a))
|
2006-03-23 12:36:51 +03:00
|
|
|
v->revert = 0;
|
2006-04-03 00:53:56 +04:00
|
|
|
for(i = 0; i < client.size; i++)
|
|
|
|
if(client.data[i]->revert == a)
|
|
|
|
client.data[i]->revert = 0;
|
2006-04-13 17:35:10 +04:00
|
|
|
cext_vdetach(vector_of_areas(&v->area), a);
|
2006-03-23 12:36:51 +03:00
|
|
|
if(v->sel > 1)
|
|
|
|
v->sel--;
|
2006-02-03 18:15:36 +03:00
|
|
|
free(a);
|
|
|
|
}
|
|
|
|
|
|
|
|
int
|
2006-04-12 12:44:07 +04:00
|
|
|
idx_of_area(Area *a)
|
2006-02-03 18:15:36 +03:00
|
|
|
{
|
|
|
|
int i;
|
2006-03-23 12:36:51 +03:00
|
|
|
View *v = a->view;
|
2006-04-03 00:53:56 +04:00
|
|
|
for(i = 0; i < v->area.size; i++)
|
|
|
|
if(v->area.data[i] == a)
|
2006-02-03 18:15:36 +03:00
|
|
|
return i;
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
int
|
2006-04-12 12:44:07 +04:00
|
|
|
idx_of_area_id(View *v, unsigned short id)
|
2006-02-03 18:15:36 +03:00
|
|
|
{
|
|
|
|
int i;
|
2006-04-03 00:53:56 +04:00
|
|
|
for(i = 0; i < v->area.size; i++)
|
|
|
|
if(v->area.data[i]->id == id)
|
2006-02-03 18:15:36 +03:00
|
|
|
return i;
|
|
|
|
return -1;
|
|
|
|
}
|
2006-02-19 18:21:01 +03:00
|
|
|
|
|
|
|
void
|
|
|
|
select_area(Area *a, char *arg)
|
|
|
|
{
|
|
|
|
Area *new;
|
2006-03-23 12:36:51 +03:00
|
|
|
View *v = a->view;
|
2006-04-12 12:44:07 +04:00
|
|
|
int i = idx_of_area(a);
|
2006-03-31 09:57:33 +04:00
|
|
|
|
2006-02-19 18:21:01 +03:00
|
|
|
if(i == -1)
|
|
|
|
return;
|
2006-03-11 22:50:53 +03:00
|
|
|
if(i)
|
2006-03-23 12:36:51 +03:00
|
|
|
v->revert = i;
|
2006-03-31 09:57:33 +04:00
|
|
|
|
2006-03-11 22:37:29 +03:00
|
|
|
if(!strncmp(arg, "toggle", 7)) {
|
|
|
|
if(i)
|
|
|
|
i = 0;
|
2006-04-03 00:53:56 +04:00
|
|
|
else if(v->revert > 0 && v->revert < v->area.size)
|
2006-03-23 12:36:51 +03:00
|
|
|
i = v->revert;
|
2006-03-11 22:37:29 +03:00
|
|
|
else
|
|
|
|
i = 1;
|
|
|
|
} else if(!strncmp(arg, "prev", 5)) {
|
2006-05-09 02:16:12 +04:00
|
|
|
if(i <= 1)
|
|
|
|
return;
|
|
|
|
else
|
|
|
|
i--;
|
2006-02-19 18:21:01 +03:00
|
|
|
} else if(!strncmp(arg, "next", 5)) {
|
2006-05-09 02:16:12 +04:00
|
|
|
if(i + 1 < v->area.size)
|
|
|
|
i++;
|
|
|
|
else
|
|
|
|
return;
|
2006-02-19 18:21:01 +03:00
|
|
|
}
|
|
|
|
else {
|
|
|
|
const char *errstr;
|
2006-04-03 00:53:56 +04:00
|
|
|
i = cext_strtonum(arg, 0, v->area.size - 1, &errstr);
|
2006-02-19 18:21:01 +03:00
|
|
|
if(errstr)
|
|
|
|
return;
|
|
|
|
}
|
2006-04-03 00:53:56 +04:00
|
|
|
new = v->area.data[i];
|
|
|
|
if(new->frame.size)
|
2006-04-26 10:59:55 +04:00
|
|
|
focus_client(new->frame.data[new->sel]->client, True);
|
2006-03-23 12:36:51 +03:00
|
|
|
v->sel = i;
|
2006-04-28 14:37:19 +04:00
|
|
|
draw_clients();
|
2006-02-19 18:21:01 +03:00
|
|
|
}
|
2006-02-24 12:06:02 +03:00
|
|
|
|
|
|
|
void
|
2006-04-12 12:44:07 +04:00
|
|
|
send_to_area(Area *to, Area *from, Client *c)
|
2006-02-24 12:06:02 +03:00
|
|
|
{
|
2006-03-11 22:50:53 +03:00
|
|
|
c->revert = from;
|
2006-04-12 12:44:07 +04:00
|
|
|
detach_from_area(from, c);
|
|
|
|
attach_to_area(to, c);
|
2006-04-26 10:59:55 +04:00
|
|
|
focus_client(c, True);
|
2006-02-24 12:06:02 +03:00
|
|
|
}
|
2006-03-02 12:26:30 +03:00
|
|
|
|
2006-04-07 22:06:59 +04:00
|
|
|
void
|
|
|
|
place_client(Area *a, Client *c)
|
|
|
|
{
|
2006-04-26 01:11:49 +04:00
|
|
|
static unsigned int mx, my;
|
2006-04-10 17:48:27 +04:00
|
|
|
static Bool *field = nil;
|
2006-04-14 11:34:03 +04:00
|
|
|
Bool fit = False;
|
2006-04-26 01:11:49 +04:00
|
|
|
unsigned int i, j, k, x, y, maxx, maxy, dx, dy, cx, cy, diff;
|
2006-04-10 17:48:27 +04:00
|
|
|
XPoint p1 = {0, 0}, p2 = {0, 0};
|
2006-04-07 22:06:59 +04:00
|
|
|
Frame *f = c->frame.data[c->sel];
|
2006-04-10 17:48:27 +04:00
|
|
|
|
2006-04-24 20:23:06 +04:00
|
|
|
if(c->trans)
|
|
|
|
return;
|
|
|
|
if(c->rect.width >= a->rect.width || c->rect.height >= a->rect.height)
|
2006-04-07 22:06:59 +04:00
|
|
|
return;
|
|
|
|
|
2006-04-10 17:48:27 +04:00
|
|
|
if(!field) {
|
|
|
|
mx = rect.width / 8;
|
|
|
|
my = rect.height / 8;
|
|
|
|
field = cext_emallocz(my * mx * sizeof(Bool));
|
|
|
|
}
|
2006-04-07 22:06:59 +04:00
|
|
|
|
2006-04-10 17:48:27 +04:00
|
|
|
for(y = 0; y < my; y++)
|
|
|
|
for(x = 0; x < mx; x++)
|
|
|
|
field[y*mx + x] = True;
|
|
|
|
|
|
|
|
dx = rect.width / mx;
|
|
|
|
dy = rect.height / my;
|
|
|
|
for(k = 0; k < a->frame.size; k++) {
|
2006-04-14 11:34:03 +04:00
|
|
|
Frame *fr = a->frame.data[k];
|
|
|
|
if(fr == f) {
|
|
|
|
cx = f->rect.width / dx;
|
|
|
|
cy = f->rect.height / dy;
|
2006-04-10 17:48:27 +04:00
|
|
|
continue;
|
2006-04-14 11:34:03 +04:00
|
|
|
}
|
2006-04-14 13:50:20 +04:00
|
|
|
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;
|
2006-04-14 13:35:42 +04:00
|
|
|
for(j = y; j < my && j < maxy; j++)
|
|
|
|
for(i = x; i < mx && i < maxx; i++)
|
2006-04-10 17:48:27 +04:00
|
|
|
field[j*mx + i] = False;
|
|
|
|
}
|
|
|
|
|
|
|
|
for(y = 0; y < my; y++)
|
|
|
|
for(x = 0; x < mx; x++) {
|
|
|
|
if(field[y*mx + x]) {
|
2006-04-12 00:33:09 +04:00
|
|
|
for(i = x; (i < mx) && field[y*mx + i]; i++);
|
|
|
|
for(j = y; (j < my) && field[j*mx + x]; j++);
|
2006-04-14 11:34:03 +04:00
|
|
|
if(((i - x) * (j - y) > (p2.x - p1.x) * (p2.y - p1.y))
|
|
|
|
&& (i - x > cx) && (j - y > cy))
|
|
|
|
{
|
|
|
|
fit = True;
|
2006-04-10 17:48:27 +04:00
|
|
|
p1.x = x;
|
|
|
|
p1.y = y;
|
|
|
|
p2.x = i;
|
|
|
|
p2.y = j;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2006-04-14 11:34:03 +04:00
|
|
|
if(fit) {
|
|
|
|
p1.x *= dx;
|
|
|
|
p1.y *= dy;
|
|
|
|
}
|
2006-04-10 17:48:27 +04:00
|
|
|
|
2006-04-14 11:34:03 +04:00
|
|
|
if(fit && (p1.x + f->rect.width < a->rect.x + a->rect.width))
|
2006-04-10 17:48:27 +04:00
|
|
|
f->rect.x = p1.x;
|
2006-04-24 23:21:11 +04:00
|
|
|
else {
|
2006-04-26 01:11:49 +04:00
|
|
|
diff = a->rect.width - f->rect.width;
|
|
|
|
f->rect.x = a->rect.x + (random() % (diff ? diff : 1));
|
2006-04-24 23:21:11 +04:00
|
|
|
}
|
2006-04-10 17:48:27 +04:00
|
|
|
|
2006-04-14 11:34:03 +04:00
|
|
|
if(fit && (p1.y + f->rect.height < a->rect.y + a->rect.height))
|
2006-04-10 17:48:27 +04:00
|
|
|
f->rect.y = p1.y;
|
2006-04-24 23:21:11 +04:00
|
|
|
else {
|
2006-04-26 01:11:49 +04:00
|
|
|
diff = a->rect.height - f->rect.height;
|
|
|
|
f->rect.y = a->rect.y + (random() % (diff ? diff : 1));
|
2006-04-24 23:21:11 +04:00
|
|
|
}
|
2006-04-07 22:06:59 +04:00
|
|
|
}
|
|
|
|
|
2006-03-02 12:26:30 +03:00
|
|
|
void
|
2006-04-12 12:44:07 +04:00
|
|
|
attach_to_area(Area *a, Client *c)
|
2006-03-02 12:26:30 +03:00
|
|
|
{
|
2006-04-24 18:03:37 +04:00
|
|
|
unsigned int h = 0, aidx = idx_of_area(a);
|
|
|
|
Frame *f;
|
2006-03-23 18:12:06 +03:00
|
|
|
|
2006-04-06 19:03:12 +04:00
|
|
|
c->floating = !aidx;
|
2006-04-24 18:54:56 +04:00
|
|
|
if(aidx) {
|
|
|
|
h = a->rect.height / (a->frame.size + 1);
|
|
|
|
if(a->frame.size)
|
2006-04-24 18:03:37 +04:00
|
|
|
scale_column(a, a->rect.height - h);
|
2006-04-06 19:03:12 +04:00
|
|
|
}
|
2006-04-24 18:03:37 +04:00
|
|
|
|
|
|
|
f = create_frame(a, c);
|
|
|
|
|
2006-04-24 18:54:56 +04:00
|
|
|
if(aidx) { /* column */
|
|
|
|
f->rect.height = h;
|
2006-04-24 18:03:37 +04:00
|
|
|
arrange_column(a, False);
|
2006-04-24 18:54:56 +04:00
|
|
|
}
|
2006-04-07 22:06:59 +04:00
|
|
|
else { /* floating */
|
2006-04-10 17:48:27 +04:00
|
|
|
place_client(a, c);
|
2006-03-15 18:00:39 +03:00
|
|
|
resize_client(c, &f->rect, False);
|
2006-04-07 22:06:59 +04:00
|
|
|
}
|
2006-03-02 12:26:30 +03:00
|
|
|
}
|
|
|
|
|
2006-03-02 15:37:52 +03:00
|
|
|
void
|
2006-04-12 12:44:07 +04:00
|
|
|
detach_from_area(Area *a, Client *c)
|
2006-03-02 15:37:52 +03:00
|
|
|
{
|
2006-03-23 12:36:51 +03:00
|
|
|
View *v = a->view;
|
2006-03-07 01:55:47 +03:00
|
|
|
int i;
|
|
|
|
|
2006-04-03 00:53:56 +04:00
|
|
|
for(i = 0; i < c->frame.size; i++)
|
|
|
|
if(c->frame.data[i]->area == a) {
|
2006-04-12 12:44:07 +04:00
|
|
|
destroy_frame(c->frame.data[i]);
|
2006-03-07 01:55:47 +03:00
|
|
|
break;
|
|
|
|
}
|
2006-03-06 19:22:54 +03:00
|
|
|
|
2006-04-12 12:44:07 +04:00
|
|
|
i = idx_of_area(a);
|
2006-04-03 00:53:56 +04:00
|
|
|
if(i && a->frame.size)
|
2006-04-06 19:03:12 +04:00
|
|
|
arrange_column(a, False);
|
2006-03-04 11:23:17 +03:00
|
|
|
else {
|
2006-03-09 14:44:38 +03:00
|
|
|
if(i) {
|
2006-04-03 00:53:56 +04:00
|
|
|
if(v->area.size > 2)
|
2006-03-09 14:44:38 +03:00
|
|
|
destroy_area(a);
|
2006-04-03 00:53:56 +04:00
|
|
|
else if(!a->frame.size && v->area.data[0]->frame.size)
|
2006-03-23 12:36:51 +03:00
|
|
|
v->sel = 0; /* focus floating area if it contains something */
|
2006-04-24 19:19:50 +04:00
|
|
|
arrange_view(v);
|
2006-03-09 14:44:38 +03:00
|
|
|
}
|
2006-04-03 00:53:56 +04:00
|
|
|
else if(!i && !a->frame.size) {
|
2006-03-09 02:27:12 +03:00
|
|
|
if(c->trans) {
|
|
|
|
/* focus area of transient, if possible */
|
2006-04-12 12:44:07 +04:00
|
|
|
Client *cl = client_of_win(c->trans);
|
2006-04-03 00:53:56 +04:00
|
|
|
if(cl && cl->frame.size) {
|
|
|
|
a = cl->frame.data[cl->sel]->area;
|
2006-03-23 12:36:51 +03:00
|
|
|
if(a->view == v)
|
2006-04-12 12:44:07 +04:00
|
|
|
v->sel = idx_of_area(a);
|
2006-03-09 02:27:12 +03:00
|
|
|
}
|
|
|
|
}
|
2006-04-03 00:53:56 +04:00
|
|
|
else if(v->area.data[1]->frame.size)
|
2006-03-23 12:36:51 +03:00
|
|
|
v->sel = 1; /* focus first col as fallback */
|
2006-03-09 02:27:12 +03:00
|
|
|
}
|
2006-03-04 11:23:17 +03:00
|
|
|
}
|
2006-03-02 17:28:55 +03:00
|
|
|
}
|
|
|
|
|
2006-03-06 19:22:54 +03:00
|
|
|
Bool
|
2006-04-12 12:44:07 +04:00
|
|
|
is_of_area(Area *a, Client *c)
|
2006-03-06 19:22:54 +03:00
|
|
|
{
|
|
|
|
unsigned int i;
|
2006-04-03 00:53:56 +04:00
|
|
|
for(i = 0; i < a->frame.size; i++)
|
|
|
|
if(a->frame.data[i]->client == c)
|
2006-03-06 19:22:54 +03:00
|
|
|
return True;
|
|
|
|
return False;
|
|
|
|
}
|
2006-05-08 23:44:56 +04:00
|
|
|
|
|
|
|
Client *
|
|
|
|
sel_client_of_area(Area *a)
|
|
|
|
{
|
|
|
|
if(a) {
|
|
|
|
return (a->frame.size) ? a->frame.data[a->sel]->client : nil;
|
|
|
|
}
|
|
|
|
return nil;
|
|
|
|
}
|