]>
Dogcows Code - chaz/openbox/blob - openbox/place.c
e2d6b4bac6f94eab4b318a443467589d6a19d1dd
1 /* -*- indent-tabs-mode: nil; tab-width: 4; c-basic-offset: 4; -*-
3 place.c for the Openbox window manager
4 Copyright (c) 2003 Ben Jansens
6 This program is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 2 of the License, or
9 (at your option) any later version.
11 This program is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
16 See the COPYING file for a copy of the GNU General Public License.
26 static Rect
* pick_head(ObClient
*c
)
28 /* try direct parent first */
29 if (c
->transient_for
&& c
->transient_for
!= OB_TRAN_GROUP
) {
30 return screen_area_monitor(c
->desktop
,
31 client_monitor(c
->transient_for
));
34 /* more than one guy in his group (more than just him) */
35 if (c
->group
&& c
->group
->members
->next
) {
38 /* try on the client's desktop */
39 for (it
= c
->group
->members
; it
; it
= g_slist_next(it
)) {
40 ObClient
*itc
= it
->data
;
42 (itc
->desktop
== c
->desktop
||
43 itc
->desktop
== DESKTOP_ALL
|| c
->desktop
== DESKTOP_ALL
))
44 return screen_area_monitor(c
->desktop
,
45 client_monitor(it
->data
));
48 /* try on all desktops */
49 for (it
= c
->group
->members
; it
; it
= g_slist_next(it
)) {
50 ObClient
*itc
= it
->data
;
52 return screen_area_monitor(c
->desktop
,
53 client_monitor(it
->data
));
60 static gboolean
place_random(ObClient
*client
, gint
*x
, gint
*y
)
65 area
= pick_head(client
);
67 area
= screen_area_monitor(client
->desktop
,
68 g_random_int_range(0, screen_num_monitors
));
72 r
= area
->x
+ area
->width
- client
->frame
->area
.width
;
73 b
= area
->y
+ area
->height
- client
->frame
->area
.height
;
75 if (r
> l
) *x
= g_random_int_range(l
, r
+ 1);
77 if (b
> t
) *y
= g_random_int_range(t
, b
+ 1);
83 static GSList
* area_add(GSList
*list
, Rect
*a
)
85 Rect
*r
= g_new(Rect
, 1);
87 return g_slist_prepend(list
, r
);
90 static GSList
* area_remove(GSList
*list
, Rect
*a
)
93 GSList
*result
= NULL
;
95 for (sit
= list
; sit
; sit
= g_slist_next(sit
)) {
98 if (!RECT_INTERSECTS_RECT(*r
, *a
)) {
99 result
= g_slist_prepend(result
, r
);
100 r
= NULL
; /* dont free it */
104 /* Use an intersection of a and r to determine the space
105 around r that we can use.
107 NOTE: the spaces calculated can overlap.
110 RECT_SET_INTERSECTION(isect
, *r
, *a
);
112 if (RECT_LEFT(isect
) > RECT_LEFT(*r
)) {
113 RECT_SET(extra
, r
->x
, r
->y
,
114 RECT_LEFT(isect
) - r
->x
, r
->height
);
115 result
= area_add(result
, &extra
);
118 if (RECT_TOP(isect
) > RECT_TOP(*r
)) {
119 RECT_SET(extra
, r
->x
, r
->y
,
120 r
->width
, RECT_TOP(isect
) - r
->y
+ 1);
121 result
= area_add(result
, &extra
);
124 if (RECT_RIGHT(isect
) < RECT_RIGHT(*r
)) {
125 RECT_SET(extra
, RECT_RIGHT(isect
) + 1, r
->y
,
126 RECT_RIGHT(*r
) - RECT_RIGHT(isect
), r
->height
);
127 result
= area_add(result
, &extra
);
130 if (RECT_BOTTOM(isect
) < RECT_BOTTOM(*r
)) {
131 RECT_SET(extra
, r
->x
, RECT_BOTTOM(isect
) + 1,
132 r
->width
, RECT_BOTTOM(*r
) - RECT_BOTTOM(isect
));
133 result
= area_add(result
, &extra
);
143 static gint
area_cmp(gconstpointer p1
, gconstpointer p2
, gpointer data
)
146 const Rect
*a1
= p1
, *a2
= p2
;
148 return MIN((a1
->width
- carea
->width
), (a1
->height
- carea
->height
)) -
149 MIN((a2
->width
- carea
->width
), (a2
->height
- carea
->height
));
159 #define SMART_IGNORE(placer, c) \
160 (placer == c || c->shaded || !client_normal(c) || \
161 (c->desktop != DESKTOP_ALL && \
162 c->desktop != (placer->desktop == DESKTOP_ALL ? \
163 screen_desktop : placer->desktop)))
165 static gboolean
place_smart(ObClient
*client
, gint
*x
, gint
*y
,
169 gboolean ret
= FALSE
;
170 GSList
*spaces
= NULL
, *sit
;
173 for (i
= 0; i
< screen_num_monitors
; ++i
)
174 spaces
= area_add(spaces
, screen_area_monitor(client
->desktop
, i
));
176 if (type
== SMART_FULL
|| type
== SMART_FOCUSED
) {
179 list
= focus_order
[client
->desktop
== DESKTOP_ALL
?
180 screen_desktop
: client
->desktop
];
182 for (it
= list
; it
; it
= g_list_next(it
)) {
183 ObClient
*c
= it
->data
;
185 if (!SMART_IGNORE(client
, c
)) {
186 spaces
= area_remove(spaces
, &c
->frame
->area
);
187 if (type
== SMART_FOCUSED
)
191 } else if (type
== SMART_GROUP
) {
195 for (sit
= client
->group
->members
; sit
; sit
= g_slist_next(sit
)) {
196 ObClient
*c
= sit
->data
;
197 if (!SMART_IGNORE(client
, c
))
198 spaces
= area_remove(spaces
, &c
->frame
->area
);
201 g_assert_not_reached();
203 spaces
= g_slist_sort_with_data(spaces
, area_cmp
, &client
->frame
->area
);
205 for (sit
= spaces
; sit
; sit
= g_slist_next(sit
)) {
209 if (r
->width
>= client
->frame
->area
.width
&&
210 r
->height
>= client
->frame
->area
.height
) {
212 if (type
!= SMART_FULL
) {
213 *x
= r
->x
+ (r
->width
- client
->frame
->area
.width
) / 2;
214 *y
= r
->y
+ (r
->height
- client
->frame
->area
.height
) / 2;
224 g_slist_free(spaces
);
229 static gboolean
place_under_mouse(ObClient
*client
, gint
*x
, gint
*y
)
236 screen_pointer_pos(&px
, &py
);
238 for (i
= 0; i
< screen_num_monitors
; ++i
) {
239 area
= screen_area_monitor(client
->desktop
, i
);
240 if (RECT_CONTAINS(*area
, px
, py
))
243 if (i
== screen_num_monitors
)
244 area
= screen_area_monitor(client
->desktop
, 0);
248 r
= area
->x
+ area
->width
- client
->frame
->area
.width
;
249 b
= area
->y
+ area
->height
- client
->frame
->area
.height
;
251 *x
= px
- client
->area
.width
/ 2 - client
->frame
->size
.left
;
252 *x
= MIN(MAX(*x
, l
), r
);
253 *y
= py
- client
->area
.height
/ 2 - client
->frame
->size
.top
;
254 *y
= MIN(MAX(*y
, t
), b
);
259 static gboolean
place_transient(ObClient
*client
, gint
*x
, gint
*y
)
261 if (client
->transient_for
) {
262 if (client
->transient_for
!= OB_TRAN_GROUP
) {
263 ObClient
*c
= client
;
264 ObClient
*p
= client
->transient_for
;
265 *x
= (p
->frame
->area
.width
- c
->frame
->area
.width
) / 2 +
267 *y
= (p
->frame
->area
.height
- c
->frame
->area
.height
) / 2 +
272 gboolean first
= TRUE
;
274 for (it
= client
->group
->members
; it
; it
= it
->next
) {
275 ObClient
*m
= it
->data
;
276 if (!(m
== client
|| m
->transient_for
)) {
278 l
= RECT_LEFT(m
->frame
->area
);
279 t
= RECT_TOP(m
->frame
->area
);
280 r
= RECT_RIGHT(m
->frame
->area
);
281 b
= RECT_BOTTOM(m
->frame
->area
);
284 l
= MIN(l
, RECT_LEFT(m
->frame
->area
));
285 t
= MIN(t
, RECT_TOP(m
->frame
->area
));
286 r
= MAX(r
, RECT_RIGHT(m
->frame
->area
));
287 b
= MAX(b
, RECT_BOTTOM(m
->frame
->area
));
292 *x
= ((r
+ 1 - l
) - client
->frame
->area
.width
) / 2 + l
;
293 *y
= ((b
+ 1 - t
) - client
->frame
->area
.height
) / 2 + t
;
301 static gboolean
place_dialog(ObClient
*client
, gint
*x
, gint
*y
)
303 /* center parentless dialogs on the screen */
304 if (client
->type
== OB_CLIENT_TYPE_DIALOG
) {
307 area
= pick_head(client
);
309 area
= screen_area_monitor(client
->desktop
, 0);
311 *x
= (area
->width
- client
->frame
->area
.width
) / 2 + area
->x
;
312 *y
= (area
->height
- client
->frame
->area
.height
) / 2 + area
->y
;
318 void place_client(ObClient
*client
, gint
*x
, gint
*y
)
320 if (client
->positioned
)
322 if (place_transient(client
, x
, y
) ||
323 place_dialog(client
, x
, y
) ||
324 place_smart(client
, x
, y
, SMART_FULL
) ||
325 place_smart(client
, x
, y
, SMART_GROUP
) ||
326 place_smart(client
, x
, y
, SMART_FOCUSED
) ||
327 (config_focus_follow
?
328 place_under_mouse(client
, x
, y
) :
329 place_random(client
, x
, y
)))
331 /* get where the client should be */
332 frame_frame_gravity(client
->frame
, x
, y
);
334 g_assert_not_reached(); /* the last one better succeed */
This page took 0.050383 seconds and 4 git commands to generate.