]>
Dogcows Code - chaz/openbox/blob - openbox/place.c
1 /* -*- indent-tabs-mode: nil; tab-width: 4; c-basic-offset: 4; -*-
3 place.c for the Openbox window manager
4 Copyright (c) 2006 Mikael Magnusson
5 Copyright (c) 2003 Ben Jansens
7 This program is free software; you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation; either version 2 of the License, or
10 (at your option) any later version.
12 This program is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License for more details.
17 See the COPYING file for a copy of the GNU General Public License.
27 static Rect
* pick_head(ObClient
*c
)
29 /* try direct parent first */
30 if (c
->transient_for
&& c
->transient_for
!= OB_TRAN_GROUP
) {
31 return screen_area_monitor(c
->desktop
,
32 client_monitor(c
->transient_for
));
35 /* more than one guy in his group (more than just him) */
36 if (client_has_group_siblings(c
)) {
39 /* try on the client's desktop */
40 for (it
= c
->group
->members
; it
; it
= g_slist_next(it
)) {
41 ObClient
*itc
= it
->data
;
43 (itc
->desktop
== c
->desktop
||
44 itc
->desktop
== DESKTOP_ALL
|| c
->desktop
== DESKTOP_ALL
))
45 return screen_area_monitor(c
->desktop
,
46 client_monitor(it
->data
));
49 /* try on all desktops */
50 for (it
= c
->group
->members
; it
; it
= g_slist_next(it
)) {
51 ObClient
*itc
= it
->data
;
53 return screen_area_monitor(c
->desktop
,
54 client_monitor(it
->data
));
61 static gboolean
place_random(ObClient
*client
, gint
*x
, gint
*y
)
66 area
= pick_head(client
);
68 area
= screen_area_monitor(client
->desktop
,
69 g_random_int_range(0, screen_num_monitors
));
73 r
= area
->x
+ area
->width
- client
->frame
->area
.width
;
74 b
= area
->y
+ area
->height
- client
->frame
->area
.height
;
76 if (r
> l
) *x
= g_random_int_range(l
, r
+ 1);
78 if (b
> t
) *y
= g_random_int_range(t
, b
+ 1);
84 static GSList
* area_add(GSList
*list
, Rect
*a
)
86 Rect
*r
= g_new(Rect
, 1);
88 return g_slist_prepend(list
, r
);
91 static GSList
* area_remove(GSList
*list
, Rect
*a
)
94 GSList
*result
= NULL
;
96 for (sit
= list
; sit
; sit
= g_slist_next(sit
)) {
99 if (!RECT_INTERSECTS_RECT(*r
, *a
)) {
100 result
= g_slist_prepend(result
, r
);
101 r
= NULL
; /* dont free it */
105 /* Use an intersection of a and r to determine the space
106 around r that we can use.
108 NOTE: the spaces calculated can overlap.
111 RECT_SET_INTERSECTION(isect
, *r
, *a
);
113 if (RECT_LEFT(isect
) > RECT_LEFT(*r
)) {
114 RECT_SET(extra
, r
->x
, r
->y
,
115 RECT_LEFT(isect
) - r
->x
, r
->height
);
116 result
= area_add(result
, &extra
);
119 if (RECT_TOP(isect
) > RECT_TOP(*r
)) {
120 RECT_SET(extra
, r
->x
, r
->y
,
121 r
->width
, RECT_TOP(isect
) - r
->y
+ 1);
122 result
= area_add(result
, &extra
);
125 if (RECT_RIGHT(isect
) < RECT_RIGHT(*r
)) {
126 RECT_SET(extra
, RECT_RIGHT(isect
) + 1, r
->y
,
127 RECT_RIGHT(*r
) - RECT_RIGHT(isect
), r
->height
);
128 result
= area_add(result
, &extra
);
131 if (RECT_BOTTOM(isect
) < RECT_BOTTOM(*r
)) {
132 RECT_SET(extra
, r
->x
, RECT_BOTTOM(isect
) + 1,
133 r
->width
, RECT_BOTTOM(*r
) - RECT_BOTTOM(isect
));
134 result
= area_add(result
, &extra
);
144 static gint
area_cmp(gconstpointer p1
, gconstpointer p2
, gpointer data
)
147 Rect
*carea
= &c
->frame
->area
;
148 const Rect
*a1
= p1
, *a2
= p2
;
149 gboolean diffhead
= FALSE
;
153 for (i
= 0; i
< screen_num_monitors
; ++i
) {
154 a
= screen_physical_area_monitor(i
);
155 if (RECT_CONTAINS(*a
, a1
->x
, a1
->y
) &&
156 !RECT_CONTAINS(*a
, a2
->x
, a2
->y
))
163 /* has to be more than me in the group */
164 if (diffhead
&& client_has_group_siblings(c
)) {
168 /* find how many clients in the group are on each monitor, use the
169 monitor with the most in it */
170 num
= g_new0(guint
, screen_num_monitors
);
171 for (it
= c
->group
->members
; it
; it
= g_slist_next(it
))
173 ++num
[client_monitor(it
->data
)];
175 for (i
= 1; i
< screen_num_monitors
; ++i
)
176 if (num
[i
] > num
[most
])
181 a
= screen_physical_area_monitor(most
);
182 if (RECT_CONTAINS(*a
, a1
->x
, a1
->y
))
184 if (RECT_CONTAINS(*a
, a2
->x
, a2
->y
))
188 return MIN((a1
->width
- carea
->width
), (a1
->height
- carea
->height
)) -
189 MIN((a2
->width
- carea
->width
), (a2
->height
- carea
->height
));
199 #define SMART_IGNORE(placer, c) \
200 (placer == c || !c->frame->visible || c->shaded || !client_normal(c) || \
201 (c->desktop != DESKTOP_ALL && \
202 c->desktop != (placer->desktop == DESKTOP_ALL ? \
203 screen_desktop : placer->desktop)))
205 static gboolean
place_smart(ObClient
*client
, gint
*x
, gint
*y
,
209 gboolean ret
= FALSE
;
210 GSList
*spaces
= NULL
, *sit
;
213 for (i
= 0; i
< screen_num_monitors
; ++i
)
214 spaces
= area_add(spaces
, screen_area_monitor(client
->desktop
, i
));
216 /* stay out from under windows in higher layers */
217 for (it
= stacking_list
; it
; it
= g_list_next(it
)) {
220 if (WINDOW_IS_CLIENT(it
->data
)) {
227 if (c
->layer
> client
->layer
) {
228 if (!SMART_IGNORE(client
, c
))
229 spaces
= area_remove(spaces
, &c
->frame
->area
);
234 if (client
->type
== OB_CLIENT_TYPE_NORMAL
) {
235 if (type
== SMART_FULL
|| type
== SMART_FOCUSED
) {
236 gboolean found_foc
= FALSE
, stop
= FALSE
;
240 list
= focus_order
[client
->desktop
== DESKTOP_ALL
?
241 screen_desktop
: client
->desktop
];
242 foc
= list
? list
->data
: NULL
;
244 for (; it
&& !stop
; it
= g_list_next(it
)) {
247 if (WINDOW_IS_CLIENT(it
->data
)) {
254 if (!SMART_IGNORE(client
, c
)) {
255 if (type
== SMART_FOCUSED
)
259 spaces
= area_remove(spaces
, &c
->frame
->area
);
265 } else if (type
== SMART_GROUP
) {
266 /* has to be more than me in the group */
267 if (!client_has_group_siblings(client
))
270 for (sit
= client
->group
->members
; sit
; sit
= g_slist_next(sit
)) {
271 ObClient
*c
= sit
->data
;
272 if (!SMART_IGNORE(client
, c
))
273 spaces
= area_remove(spaces
, &c
->frame
->area
);
276 g_assert_not_reached();
279 spaces
= g_slist_sort_with_data(spaces
, area_cmp
, client
);
281 for (sit
= spaces
; sit
; sit
= g_slist_next(sit
)) {
285 if (r
->width
>= client
->frame
->area
.width
&&
286 r
->height
>= client
->frame
->area
.height
) {
288 if (client
->type
== OB_CLIENT_TYPE_DIALOG
||
291 *x
= r
->x
+ (r
->width
- client
->frame
->area
.width
) / 2;
292 *y
= r
->y
+ (r
->height
- client
->frame
->area
.height
) / 2;
302 g_slist_free(spaces
);
307 static gboolean
place_under_mouse(ObClient
*client
, gint
*x
, gint
*y
)
314 screen_pointer_pos(&px
, &py
);
316 for (i
= 0; i
< screen_num_monitors
; ++i
) {
317 area
= screen_area_monitor(client
->desktop
, i
);
318 if (RECT_CONTAINS(*area
, px
, py
))
321 if (i
== screen_num_monitors
)
322 area
= screen_area_monitor(client
->desktop
, 0);
326 r
= area
->x
+ area
->width
- client
->frame
->area
.width
;
327 b
= area
->y
+ area
->height
- client
->frame
->area
.height
;
329 *x
= px
- client
->area
.width
/ 2 - client
->frame
->size
.left
;
330 *x
= MIN(MAX(*x
, l
), r
);
331 *y
= py
- client
->area
.height
/ 2 - client
->frame
->size
.top
;
332 *y
= MIN(MAX(*y
, t
), b
);
337 static gboolean
place_per_app_setting(ObClient
*client
, gint
*x
, gint
*y
,
338 ObAppSettings
*settings
)
343 if (!settings
|| (settings
&& !settings
->pos_given
))
346 /* Find which head the pointer is on */
347 if (settings
->head
== -1 && screen_num_monitors
> 1) {
348 screen_pointer_pos(&px
, &py
);
350 for (i
= 0; i
< screen_num_monitors
; i
++) {
351 screen
= screen_area_monitor(client
->desktop
, i
);
352 if (RECT_CONTAINS(*screen
, px
, py
))
356 if (i
== screen_num_monitors
)
357 screen
= screen_area_monitor(client
->desktop
, 0);
360 screen
= screen_area_monitor(client
->desktop
, settings
->head
);
362 if (settings
->center_x
)
363 *x
= screen
->x
+ screen
->width
/ 2 - client
->area
.width
/ 2;
365 *x
= screen
->x
+ settings
->position
.x
;
367 if (settings
->center_y
)
368 *y
= screen
->y
+ screen
->height
/ 2 - client
->area
.height
/ 2;
370 *y
= screen
->y
+ settings
->position
.y
;
375 static gboolean
place_transient(ObClient
*client
, gint
*x
, gint
*y
)
377 if (client
->transient_for
) {
378 if (client
->transient_for
!= OB_TRAN_GROUP
) {
379 ObClient
*c
= client
;
380 ObClient
*p
= client
->transient_for
;
381 *x
= (p
->frame
->area
.width
- c
->frame
->area
.width
) / 2 +
383 *y
= (p
->frame
->area
.height
- c
->frame
->area
.height
) / 2 +
388 gboolean first
= TRUE
;
390 for (it
= client
->group
->members
; it
; it
= g_slist_next(it
)) {
391 ObClient
*m
= it
->data
;
392 if (!(m
== client
|| m
->transient_for
)) {
394 l
= RECT_LEFT(m
->frame
->area
);
395 t
= RECT_TOP(m
->frame
->area
);
396 r
= RECT_RIGHT(m
->frame
->area
);
397 b
= RECT_BOTTOM(m
->frame
->area
);
400 l
= MIN(l
, RECT_LEFT(m
->frame
->area
));
401 t
= MIN(t
, RECT_TOP(m
->frame
->area
));
402 r
= MAX(r
, RECT_RIGHT(m
->frame
->area
));
403 b
= MAX(b
, RECT_BOTTOM(m
->frame
->area
));
408 *x
= ((r
+ 1 - l
) - client
->frame
->area
.width
) / 2 + l
;
409 *y
= ((b
+ 1 - t
) - client
->frame
->area
.height
) / 2 + t
;
417 /* Return TRUE if we want client.c to enforce on-screen-keeping */
418 gboolean
place_client(ObClient
*client
, gint
*x
, gint
*y
,
419 ObAppSettings
*settings
)
421 gboolean ret
= FALSE
;
422 if (client
->positioned
)
424 if (place_transient(client
, x
, y
))
427 place_per_app_setting(client
, x
, y
, settings
) ||
428 ((config_place_policy
== OB_PLACE_POLICY_MOUSE
) ?
429 place_under_mouse(client
, x
, y
) :
430 place_smart(client
, x
, y
, SMART_FULL
) ||
431 place_smart(client
, x
, y
, SMART_GROUP
) ||
432 place_smart(client
, x
, y
, SMART_FOCUSED
) ||
433 place_random(client
, x
, y
))))
434 g_assert_not_reached(); /* the last one better succeed */
435 /* get where the client should be */
436 frame_frame_gravity(client
->frame
, x
, y
);
This page took 0.052672 seconds and 4 git commands to generate.