]>
Dogcows Code - chaz/openbox/blob - openbox/place.c
6bcfe9d8df0d107bdf07424d7ab8f0e93cd3622f
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-2007 Dana 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.
28 static void add_choice(guint
*choice
, guint mychoice
)
31 for (i
= 0; i
< screen_num_monitors
; ++i
) {
32 if (choice
[i
] == mychoice
)
34 else if (choice
[i
] == screen_num_monitors
) {
41 static Rect
*pick_pointer_head(ObClient
*c
)
46 screen_pointer_pos(&px
, &py
);
48 for (i
= 0; i
< screen_num_monitors
; ++i
) {
49 Rect
*monitor
= screen_physical_area_monitor(i
);
50 gboolean contain
= RECT_CONTAINS(*monitor
, px
, py
);
53 return screen_area_monitor(c
->desktop
, i
, NULL
);
55 g_assert_not_reached();
58 /*! Pick a monitor to place a window on. */
59 static Rect
**pick_head(ObClient
*c
)
67 area
= g_new(Rect
*, screen_num_monitors
);
68 choice
= g_new(guint
, screen_num_monitors
);
69 for (i
= 0; i
< screen_num_monitors
; ++i
)
70 choice
[i
] = screen_num_monitors
; /* make them all invalid to start */
72 /* try direct parent first */
73 if ((p
= client_direct_parent(c
))) {
74 add_choice(choice
, client_monitor(p
));
75 ob_debug("placement adding choice %d for parent\n",
79 /* more than one window in its group (more than just this window) */
80 if (client_has_group_siblings(c
)) {
83 /* try on the client's desktop */
84 for (it
= c
->group
->members
; it
; it
= g_slist_next(it
)) {
85 ObClient
*itc
= it
->data
;
87 (itc
->desktop
== c
->desktop
||
88 itc
->desktop
== DESKTOP_ALL
|| c
->desktop
== DESKTOP_ALL
))
90 add_choice(choice
, client_monitor(it
->data
));
91 ob_debug("placement adding choice %d for group sibling\n",
92 client_monitor(it
->data
));
96 /* try on all desktops */
97 for (it
= c
->group
->members
; it
; it
= g_slist_next(it
)) {
98 ObClient
*itc
= it
->data
;
100 add_choice(choice
, client_monitor(it
->data
));
101 ob_debug("placement adding choice %d for group sibling on "
102 "another desktop\n", client_monitor(it
->data
));
108 add_choice(choice
, client_monitor(focus_client
));
109 ob_debug("placement adding choice %d for focused window\n",
110 client_monitor(focus_client
));
113 screen_pointer_pos(&px
, &py
);
115 for (i
= 0; i
< screen_num_monitors
; i
++) {
116 Rect
*monitor
= screen_physical_area_monitor(i
);
117 gboolean contain
= RECT_CONTAINS(*monitor
, px
, py
);
120 add_choice(choice
, i
);
121 ob_debug("placement adding choice %d for mouse pointer\n", i
);
126 /* add any leftover choices */
127 for (i
= 0; i
< screen_num_monitors
; ++i
)
128 add_choice(choice
, i
);
130 for (i
= 0; i
< screen_num_monitors
; ++i
)
131 area
[i
] = screen_area_monitor(c
->desktop
, choice
[i
], NULL
);
136 static gboolean
place_random(ObClient
*client
, gint
*x
, gint
*y
)
142 areas
= pick_head(client
);
143 i
= g_random_int_range(0, screen_num_monitors
);
147 r
= areas
[i
]->x
+ areas
[i
]->width
- client
->frame
->area
.width
;
148 b
= areas
[i
]->y
+ areas
[i
]->height
- client
->frame
->area
.height
;
150 if (r
> l
) *x
= g_random_int_range(l
, r
+ 1);
151 else *x
= areas
[i
]->x
;
152 if (b
> t
) *y
= g_random_int_range(t
, b
+ 1);
153 else *y
= areas
[i
]->y
;
155 for (i
= 0; i
< screen_num_monitors
; ++i
)
162 static GSList
* area_add(GSList
*list
, Rect
*a
)
164 Rect
*r
= g_new(Rect
, 1);
166 return g_slist_prepend(list
, r
);
169 static GSList
* area_remove(GSList
*list
, Rect
*a
)
172 GSList
*result
= NULL
;
174 for (sit
= list
; sit
; sit
= g_slist_next(sit
)) {
177 if (!RECT_INTERSECTS_RECT(*r
, *a
)) {
178 result
= g_slist_prepend(result
, r
);
179 r
= NULL
; /* dont free it */
183 /* Use an intersection of a and r to determine the space
184 around r that we can use.
186 NOTE: the spaces calculated can overlap.
189 RECT_SET_INTERSECTION(isect
, *r
, *a
);
191 if (RECT_LEFT(isect
) > RECT_LEFT(*r
)) {
192 RECT_SET(extra
, r
->x
, r
->y
,
193 RECT_LEFT(isect
) - r
->x
, r
->height
);
194 result
= area_add(result
, &extra
);
197 if (RECT_TOP(isect
) > RECT_TOP(*r
)) {
198 RECT_SET(extra
, r
->x
, r
->y
,
199 r
->width
, RECT_TOP(isect
) - r
->y
+ 1);
200 result
= area_add(result
, &extra
);
203 if (RECT_RIGHT(isect
) < RECT_RIGHT(*r
)) {
204 RECT_SET(extra
, RECT_RIGHT(isect
) + 1, r
->y
,
205 RECT_RIGHT(*r
) - RECT_RIGHT(isect
), r
->height
);
206 result
= area_add(result
, &extra
);
209 if (RECT_BOTTOM(isect
) < RECT_BOTTOM(*r
)) {
210 RECT_SET(extra
, r
->x
, RECT_BOTTOM(isect
) + 1,
211 r
->width
, RECT_BOTTOM(*r
) - RECT_BOTTOM(isect
));
212 result
= area_add(result
, &extra
);
223 IGNORE_FULLSCREEN
= 1 << 0,
224 IGNORE_MAXIMIZED
= 1 << 1,
225 IGNORE_MENUTOOL
= 1 << 2,
226 /*IGNORE_SHADED = 1 << 3,*/
227 IGNORE_NONGROUP
= 1 << 3,
228 IGNORE_BELOW
= 1 << 4,
229 IGNORE_NONFOCUS
= 1 << 5,
233 static gboolean
place_nooverlap(ObClient
*c
, gint
*x
, gint
*y
)
239 GSList
*spaces
= NULL
, *sit
, *maxit
;
242 areas
= pick_head(c
);
247 /* try ignoring different things to find empty space */
248 for (ignore
= 0; ignore
< IGNORE_END
&& !ret
; ignore
= (ignore
<< 1) + 1) {
251 /* try all monitors in order of preference */
252 for (i
= 0; i
< screen_num_monitors
&& !ret
; ++i
) {
255 /* add the whole monitor */
256 spaces
= area_add(spaces
, areas
[i
]);
258 /* go thru all the windows */
259 for (it
= client_list
; it
; it
= g_list_next(it
)) {
260 ObClient
*test
= it
->data
;
262 /* should we ignore this client? */
263 if (screen_showing_desktop
) continue;
264 if (c
== test
) continue;
265 if (test
->iconic
) continue;
266 if (c
->desktop
!= DESKTOP_ALL
) {
267 if (test
->desktop
!= c
->desktop
&&
268 test
->desktop
!= DESKTOP_ALL
) continue;
270 if (test
->desktop
!= screen_desktop
&&
271 test
->desktop
!= DESKTOP_ALL
) continue;
273 if (test
->type
== OB_CLIENT_TYPE_SPLASH
||
274 test
->type
== OB_CLIENT_TYPE_DESKTOP
) continue;
277 if ((ignore
& IGNORE_FULLSCREEN
) &&
278 test
->fullscreen
) continue;
279 if ((ignore
& IGNORE_MAXIMIZED
) &&
280 test
->max_horz
&& test
->max_vert
) continue;
281 if ((ignore
& IGNORE_MENUTOOL
) &&
282 (test
->type
== OB_CLIENT_TYPE_MENU
||
283 test
->type
== OB_CLIENT_TYPE_TOOLBAR
) &&
284 client_has_parent(c
)) continue;
286 if ((ignore & IGNORE_SHADED) &&
287 test->shaded) continue;
289 if ((ignore
& IGNORE_NONGROUP
) &&
290 client_has_group_siblings(c
) &&
291 test
->group
!= c
->group
) continue;
292 if ((ignore
& IGNORE_BELOW
) &&
293 test
->layer
< c
->layer
) continue;
294 if ((ignore
& IGNORE_NONFOCUS
) &&
295 focus_client
!= test
) continue;
297 /* don't ignore this window, so remove it from the available
299 spaces
= area_remove(spaces
, &test
->frame
->area
);
302 for (sit
= spaces
; sit
; sit
= g_slist_next(sit
)) {
305 if (r
->width
>= c
->frame
->area
.width
&&
306 r
->height
>= c
->frame
->area
.height
&&
315 Rect
*r
= maxit
->data
;
317 /* center it in the area */
318 *x
= r
->x
+ (r
->width
- c
->frame
->area
.width
) / 2;
319 *y
= r
->y
+ (r
->height
- c
->frame
->area
.height
) / 2;
324 g_free(spaces
->data
);
325 spaces
= g_slist_delete_link(spaces
, spaces
);
330 for (i
= 0; i
< screen_num_monitors
; ++i
)
336 static gboolean
place_under_mouse(ObClient
*client
, gint
*x
, gint
*y
)
342 if (!screen_pointer_pos(&px
, &py
))
344 area
= pick_pointer_head(client
);
348 r
= area
->x
+ area
->width
- client
->frame
->area
.width
;
349 b
= area
->y
+ area
->height
- client
->frame
->area
.height
;
351 *x
= px
- client
->area
.width
/ 2 - client
->frame
->size
.left
;
352 *x
= MIN(MAX(*x
, l
), r
);
353 *y
= py
- client
->area
.height
/ 2 - client
->frame
->size
.top
;
354 *y
= MIN(MAX(*y
, t
), b
);
359 static gboolean
place_per_app_setting(ObClient
*client
, gint
*x
, gint
*y
,
360 ObAppSettings
*settings
)
364 if (!settings
|| (settings
&& !settings
->pos_given
))
367 /* Find which head the pointer is on */
368 if (settings
->monitor
== 0)
369 screen
= pick_pointer_head(client
);
370 else if (settings
->monitor
> 0 &&
371 (guint
)settings
->monitor
<= screen_num_monitors
)
372 screen
= screen_area_monitor(client
->desktop
,
373 (guint
)settings
->monitor
- 1, NULL
);
378 areas
= pick_head(client
);
381 for (i
= 0; i
< screen_num_monitors
; ++i
)
386 if (settings
->center_x
)
387 *x
= screen
->x
+ screen
->width
/ 2 - client
->area
.width
/ 2;
388 else if (settings
->opposite_x
)
389 *x
= screen
->x
+ screen
->width
- client
->frame
->area
.width
-
390 settings
->position
.x
;
392 *x
= screen
->x
+ settings
->position
.x
;
394 if (settings
->center_y
)
395 *y
= screen
->y
+ screen
->height
/ 2 - client
->area
.height
/ 2;
396 else if (settings
->opposite_y
)
397 *y
= screen
->y
+ screen
->height
- client
->frame
->area
.height
-
398 settings
->position
.y
;
400 *y
= screen
->y
+ settings
->position
.y
;
405 static gboolean
place_transient_splash(ObClient
*client
, gint
*x
, gint
*y
)
407 if (client
->type
== OB_CLIENT_TYPE_DIALOG
) {
409 gboolean first
= TRUE
;
411 for (it
= client
->parents
; it
; it
= g_slist_next(it
)) {
412 ObClient
*m
= it
->data
;
415 l
= RECT_LEFT(m
->frame
->area
);
416 t
= RECT_TOP(m
->frame
->area
);
417 r
= RECT_RIGHT(m
->frame
->area
);
418 b
= RECT_BOTTOM(m
->frame
->area
);
421 l
= MIN(l
, RECT_LEFT(m
->frame
->area
));
422 t
= MIN(t
, RECT_TOP(m
->frame
->area
));
423 r
= MAX(r
, RECT_RIGHT(m
->frame
->area
));
424 b
= MAX(b
, RECT_BOTTOM(m
->frame
->area
));
428 *x
= ((r
+ 1 - l
) - client
->frame
->area
.width
) / 2 + l
;
429 *y
= ((b
+ 1 - t
) - client
->frame
->area
.height
) / 2 + t
;
435 if (client
->type
== OB_CLIENT_TYPE_DIALOG
||
436 client
->type
== OB_CLIENT_TYPE_SPLASH
)
441 areas
= pick_head(client
);
443 *x
= (areas
[0]->width
- client
->frame
->area
.width
) / 2 + areas
[0]->x
;
444 *y
= (areas
[0]->height
- client
->frame
->area
.height
) / 2 + areas
[0]->y
;
446 for (i
= 0; i
< screen_num_monitors
; ++i
)
455 /* Return TRUE if we want client.c to enforce on-screen-keeping */
456 gboolean
place_client(ObClient
*client
, gint
*x
, gint
*y
,
457 ObAppSettings
*settings
)
461 if (client
->positioned
)
464 /* try a number of methods */
465 ret
= place_transient_splash(client
, x
, y
) ||
466 place_per_app_setting(client
, x
, y
, settings
) ||
467 (config_place_policy
== OB_PLACE_POLICY_MOUSE
&&
468 place_under_mouse(client
, x
, y
)) ||
469 place_nooverlap(client
, x
, y
) ||
470 place_under_mouse(client
, x
, y
) ||
471 place_random(client
, x
, y
);
474 /* get where the client should be */
475 frame_frame_gravity(client
->frame
, x
, y
,
476 client
->area
.width
, client
->area
.height
);
This page took 0.053099 seconds and 4 git commands to generate.