136 lines
4.3 KiB
C
136 lines
4.3 KiB
C
#include "client.h"
|
|
#include "group.h"
|
|
#include "screen.h"
|
|
#include "frame.h"
|
|
|
|
static Rect* pick_head(ObClient *c)
|
|
{
|
|
/* try direct parent first */
|
|
if (c->transient_for && c->transient_for != OB_TRAN_GROUP) {
|
|
return screen_area_monitor(c->desktop,
|
|
client_monitor(c->transient_for));
|
|
}
|
|
|
|
/* more than one guy in his group (more than just him) */
|
|
if (c->group && c->group->members->next) {
|
|
GSList *it;
|
|
|
|
/* try on the client's desktop */
|
|
for (it = c->group->members; it; it = g_slist_next(it)) {
|
|
ObClient *itc = it->data;
|
|
if (itc != c &&
|
|
(itc->desktop == c->desktop ||
|
|
itc->desktop == DESKTOP_ALL || c->desktop == DESKTOP_ALL))
|
|
return screen_area_monitor(c->desktop,
|
|
client_monitor(it->data));
|
|
}
|
|
|
|
/* try on all desktops */
|
|
for (it = c->group->members; it; it = g_slist_next(it)) {
|
|
ObClient *itc = it->data;
|
|
if (itc != c)
|
|
return screen_area_monitor(c->desktop,
|
|
client_monitor(it->data));
|
|
}
|
|
}
|
|
|
|
return NULL;
|
|
}
|
|
|
|
static gboolean place_random(ObClient *client, gint *x, gint *y)
|
|
{
|
|
int l, r, t, b;
|
|
Rect *area;
|
|
|
|
area = pick_head(client);
|
|
if (!area)
|
|
area = screen_area_monitor(client->desktop,
|
|
g_random_int_range(0, screen_num_monitors));
|
|
|
|
l = area->x;
|
|
t = area->y;
|
|
r = area->x + area->width - client->frame->area.width;
|
|
b = area->y + area->height - client->frame->area.height;
|
|
|
|
if (r > l) *x = g_random_int_range(l, r + 1);
|
|
else *x = 0;
|
|
if (b > t) *y = g_random_int_range(t, b + 1);
|
|
else *y = 0;
|
|
|
|
/* get where the client should be */
|
|
frame_frame_gravity(client->frame, x, y);
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
static gboolean place_transient(ObClient *client, gint *x, gint *y)
|
|
{
|
|
if (client->transient_for) {
|
|
if (client->transient_for != OB_TRAN_GROUP) {
|
|
ObClient *c = client;
|
|
ObClient *p = client->transient_for;
|
|
*x = (p->frame->area.width - c->frame->area.width) / 2 +
|
|
p->frame->area.x;
|
|
*y = (p->frame->area.height - c->frame->area.height) / 2 +
|
|
p->frame->area.y;
|
|
return TRUE;
|
|
} else {
|
|
GSList *it;
|
|
gboolean first = TRUE;
|
|
int l, r, t, b;
|
|
for (it = client->group->members; it; it = it->next) {
|
|
ObClient *m = it->data;
|
|
if (!(m == client || m->transient_for)) {
|
|
if (first) {
|
|
l = m->frame->area.x;
|
|
t = m->frame->area.y;
|
|
r = m->frame->area.x + m->frame->area.width - 1;
|
|
b = m->frame->area.y + m->frame->area.height - 1;
|
|
first = FALSE;
|
|
} else {
|
|
l = MIN(l, m->frame->area.x);
|
|
t = MIN(t, m->frame->area.y);
|
|
r = MAX(r, m->frame->area.x +m->frame->area.width - 1);
|
|
b = MAX(b, m->frame->area.y +m->frame->area.height -1);
|
|
}
|
|
}
|
|
}
|
|
if (!first) {
|
|
*x = ((r + 1 - l) - client->frame->area.width) / 2 + l;
|
|
*y = ((b + 1 - t) - client->frame->area.height) / 2 + t;
|
|
return TRUE;
|
|
}
|
|
}
|
|
}
|
|
return FALSE;
|
|
}
|
|
|
|
static gboolean place_dialog(ObClient *client, gint *x, gint *y)
|
|
{
|
|
/* center parentless dialogs on the screen */
|
|
if (client->type == OB_CLIENT_TYPE_DIALOG) {
|
|
Rect *area;
|
|
|
|
area = pick_head(client);
|
|
if (!area)
|
|
area = screen_area_monitor(client->desktop, 0);
|
|
|
|
*x = (area->width - client->frame->area.width) / 2 + area->x;
|
|
*y = (area->height - client->frame->area.height) / 2 + area->y;
|
|
return TRUE;
|
|
}
|
|
return FALSE;
|
|
}
|
|
|
|
void place_client(ObClient *client, gint *x, gint *y)
|
|
{
|
|
if (client->positioned)
|
|
return;
|
|
if (place_transient(client, x, y))
|
|
return;
|
|
if (place_dialog(client, x, y))
|
|
return;
|
|
if (place_random(client, x, y))
|
|
return;
|
|
g_assert_not_reached(); /* the last one better succeed */
|
|
}
|