Maximus: Tiled Maximization
[wmaker-crm.git] / src / placement.c
Commit [+]AuthorDateLineData
9d2e6ef9 scottc1998-09-29 22:36:29 +00001/* placement.c - window and icon placement on screen
6830b057 dan2004-10-12 21:28:27 +00002 *
9af1c6c4 dan1998-10-21 14:43:47 +00003 * Window Maker window manager
6830b057 dan2004-10-12 21:28:27 +00004 *
4153e2fd dan2003-01-16 23:30:45 +00005 * Copyright (c) 1997-2003 Alfredo K. Kojima
6830b057 dan2004-10-12 21:28:27 +00006 *
9d2e6ef9 scottc1998-09-29 22:36:29 +00007 * 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.
11 *
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.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
6830b057 dan2004-10-12 21:28:27 +000019 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
9d2e6ef9 scottc1998-09-29 22:36:29 +000020 * USA.
21 */
22
23#include "wconfig.h"
24
25#include <X11/Xlib.h>
26#include <stdlib.h>
27#include <stdio.h>
28#include <string.h>
3c046182 kojima1999-09-16 02:58:56 +000029#include <limits.h>
9d2e6ef9 scottc1998-09-29 22:36:29 +000030
31#include "WindowMaker.h"
32#include "wcore.h"
33#include "framewin.h"
34#include "window.h"
35#include "icon.h"
daeb6d67 kojima1999-04-30 23:31:00 +000036#include "appicon.h"
9d2e6ef9 scottc1998-09-29 22:36:29 +000037#include "actions.h"
38#include "funcs.h"
39#include "application.h"
40#include "appicon.h"
41#include "dock.h"
a10214a5 kojima2002-11-28 22:04:07 +000042#include "xinerama.h"
9d2e6ef9 scottc1998-09-29 22:36:29 +000043
44extern WPreferences wPreferences;
45
620a280d kojima2004-10-22 23:39:11 +000046#define X_ORIGIN WMAX(usableArea.x1,\
6830b057 dan2004-10-12 21:28:27 +000047 wPreferences.window_place_origin.x)
0261c326 dan1999-01-06 15:22:33 +000048
620a280d kojima2004-10-22 23:39:11 +000049#define Y_ORIGIN WMAX(usableArea.y1,\
6830b057 dan2004-10-12 21:28:27 +000050 wPreferences.window_place_origin.y)
9d2e6ef9 scottc1998-09-29 22:36:29 +000051
34be9d78
CM
Carlos R. Mafra2009-08-29 18:46:05 +020052/* interactive window placement is in moveres.c */
53extern void InteractivePlaceWindow(WWindow *wwin, int *x_ret, int *y_ret,
54 unsigned width, unsigned height);
9d2e6ef9 scottc1998-09-29 22:36:29 +000055
34be9d78 Carlos R. Mafra2009-08-29 18:46:05 +020056/* Returns True if it is an icon and is in this workspace */
9d2e6ef9 scottc1998-09-29 22:36:29 +000057static Bool
34be9d78
CM
Carlos R. Mafra2009-08-29 18:46:05 +020058iconPosition(WCoreWindow *wcore, int sx1, int sy1, int sx2, int sy2,
59 int workspace, int *retX, int *retY)
9d2e6ef9 scottc1998-09-29 22:36:29 +000060{
688a56e8
CM
Carlos R. Mafra2009-08-20 00:59:40 +020061 void *parent;
62 int ok = 0;
63
64 parent = wcore->descriptor.parent;
65
66 /* if it is an application icon */
67 if (wcore->descriptor.parent_type == WCLASS_APPICON && !((WAppIcon *) parent)->docked) {
68 *retX = ((WAppIcon *) parent)->x_pos;
69 *retY = ((WAppIcon *) parent)->y_pos;
70
71 ok = 1;
72 } else if (wcore->descriptor.parent_type == WCLASS_MINIWINDOW &&
73 (((WIcon *) parent)->owner->frame->workspace == workspace
74 || IS_OMNIPRESENT(((WIcon *) parent)->owner)
75 || wPreferences.sticky_icons)
76 && ((WIcon *) parent)->mapped) {
77
78 *retX = ((WIcon *) parent)->owner->icon_x;
79 *retY = ((WIcon *) parent)->owner->icon_y;
80
81 ok = 1;
82 } else if (wcore->descriptor.parent_type == WCLASS_WINDOW
83 && ((WWindow *) parent)->flags.icon_moved
84 && (((WWindow *) parent)->frame->workspace == workspace || IS_OMNIPRESENT((WWindow *) parent)
85 || wPreferences.sticky_icons)) {
86 *retX = ((WWindow *) parent)->icon_x;
87 *retY = ((WWindow *) parent)->icon_y;
88
89 ok = 1;
90 }
91
34be9d78 Carlos R. Mafra2009-08-29 18:46:05 +020092 /* Check if it is inside the screen */
688a56e8
CM
Carlos R. Mafra2009-08-20 00:59:40 +020093 if (ok) {
94 if (*retX < sx1 - wPreferences.icon_size)
95 ok = 0;
96 else if (*retX > sx2)
97 ok = 0;
98
99 if (*retY < sy1 - wPreferences.icon_size)
100 ok = 0;
101 else if (*retY > sy2)
102 ok = 0;
103 }
104
105 return ok;
9d2e6ef9 scottc1998-09-29 22:36:29 +0000106}
107
34be9d78 Carlos R. Mafra2009-08-29 18:46:05 +0200108void PlaceIcon(WScreen *scr, int *x_ret, int *y_ret, int head)
9d2e6ef9 scottc1998-09-29 22:36:29 +0000109{
688a56e8
CM
Carlos R. Mafra2009-08-20 00:59:40 +0200110 int pf; /* primary axis */
111 int sf; /* secondary axis */
112 int fullW;
113 int fullH;
114 char *map;
115 int pi, si;
116 WCoreWindow *obj;
117 int sx1, sx2, sy1, sy2; /* screen boundary */
118 int sw, sh;
119 int xo, yo;
120 int xs, ys;
121 int x, y;
122 int isize = wPreferences.icon_size;
123 int done = 0;
124 WMBagIterator iter;
125 WArea area = wGetUsableAreaForHead(scr, head, NULL, False);
126
127 /* Find out screen boundaries. */
128
129 /* Allows each head to have miniwindows */
688a56e8
CM
Carlos R. Mafra2009-08-20 00:59:40 +0200130 sx1 = area.x1;
131 sy1 = area.y1;
132 sx2 = area.x2;
133 sy2 = area.y2;
134 sw = sx2 - sx1;
135 sh = sy2 - sy1;
a10214a5 kojima2002-11-28 22:04:07 +0000136
27a396d7 dan2003-06-06 04:11:00 +0000137#if 0
688a56e8
CM
Carlos R. Mafra2009-08-20 00:59:40 +0200138 if (scr->dock) {
139 if (scr->dock->on_right_side)
140 sx2 -= isize + DOCK_EXTRA_SPACE;
141 else
142 sx1 += isize + DOCK_EXTRA_SPACE;
143 }
27a396d7 dan2003-06-06 04:11:00 +0000144#endif
9d2e6ef9 scottc1998-09-29 22:36:29 +0000145
688a56e8
CM
Carlos R. Mafra2009-08-20 00:59:40 +0200146 sw = isize * (sw / isize);
147 sh = isize * (sh / isize);
148 fullW = (sx2 - sx1) / isize;
149 fullH = (sy2 - sy1) / isize;
150
151 /* icon yard boundaries */
152 if (wPreferences.icon_yard & IY_VERT) {
153 pf = fullH;
154 sf = fullW;
155 } else {
156 pf = fullW;
157 sf = fullH;
158 }
159 if (wPreferences.icon_yard & IY_RIGHT) {
160 xo = sx2 - isize;
161 xs = -1;
162 } else {
163 xo = sx1;
164 xs = 1;
165 }
166 if (wPreferences.icon_yard & IY_TOP) {
167 yo = sy1;
168 ys = 1;
169 } else {
170 yo = sy2 - isize;
171 ys = -1;
172 }
173
174 /*
175 * Create a map with the occupied slots. 1 means the slot is used
176 * or at least partially used.
177 * The slot usage can be optimized by only marking fully used slots
178 * or slots that have most of it covered.
179 * Space usage is worse than the fvwm algorithm (used in the old version)
180 * but complexity is much better (faster) than it.
181 */
182 map = wmalloc((sw + 2) * (sh + 2));
183 memset(map, 0, (sw + 2) * (sh + 2));
9d2e6ef9 scottc1998-09-29 22:36:29 +0000184
185#define INDEX(x,y) (((y)+1)*(sw+2) + (x) + 1)
186
688a56e8
CM
Carlos R. Mafra2009-08-20 00:59:40 +0200187 WM_ETARETI_BAG(scr->stacking_list, obj, iter) {
188
189 while (obj) {
190 int x, y;
191
192 if (iconPosition(obj, sx1, sy1, sx2, sy2, scr->current_workspace, &x, &y)) {
193 int xdi, ydi; /* rounded down */
194 int xui, yui; /* rounded up */
195
196 xdi = x / isize;
197 ydi = y / isize;
198 xui = (x + isize / 2) / isize;
199 yui = (y + isize / 2) / isize;
200 map[INDEX(xdi, ydi)] = 1;
201 map[INDEX(xdi, yui)] = 1;
202 map[INDEX(xui, ydi)] = 1;
203 map[INDEX(xui, yui)] = 1;
204 }
205 obj = obj->stacking->under;
206 }
207 }
34be9d78 Carlos R. Mafra2009-08-29 18:46:05 +0200208 /* Default position */
688a56e8
CM
Carlos R. Mafra2009-08-20 00:59:40 +0200209 *x_ret = 0;
210 *y_ret = 0;
211
34be9d78 Carlos R. Mafra2009-08-29 18:46:05 +0200212 /* Look for an empty slot */
688a56e8
CM
Carlos R. Mafra2009-08-20 00:59:40 +0200213 for (si = 0; si < sf; si++) {
214 for (pi = 0; pi < pf; pi++) {
215 if (wPreferences.icon_yard & IY_VERT) {
216 x = xo + xs * (si * isize);
217 y = yo + ys * (pi * isize);
218 } else {
219 x = xo + xs * (pi * isize);
220 y = yo + ys * (si * isize);
221 }
222 if (!map[INDEX(x / isize, y / isize)]) {
223 *x_ret = x;
224 *y_ret = y;
225 done = 1;
226 break;
227 }
228 }
229 if (done)
230 break;
231 }
232
233 wfree(map);
9d2e6ef9 scottc1998-09-29 22:36:29 +0000234}
235
34be9d78 Carlos R. Mafra2009-08-29 18:46:05 +0200236/* Computes the intersecting length of two line sections */
cf62d159 Carlos R. Mafra2009-09-02 01:37:47 +0200237int calcIntersectionLength(int p1, int l1, int p2, int l2)
3c046182 kojima1999-09-16 02:58:56 +0000238{
688a56e8
CM
Carlos R. Mafra2009-08-20 00:59:40 +0200239 int isect;
240 int tmp;
241
242 if (p1 > p2) {
243 tmp = p1;
244 p1 = p2;
245 p2 = tmp;
246 tmp = l1;
247 l1 = l2;
248 l2 = tmp;
249 }
250
251 if (p1 + l1 < p2)
252 isect = 0;
253 else if (p2 + l2 < p1 + l1)
254 isect = l2;
255 else
256 isect = p1 + l1 - p2;
257
258 return isect;
3c046182 kojima1999-09-16 02:58:56 +0000259}
260
34be9d78 Carlos R. Mafra2009-08-29 18:46:05 +0200261/* Computes the intersecting area of two rectangles */
688a56e8 Carlos R. Mafra2009-08-20 00:59:40 +0200262int calcIntersectionArea(int x1, int y1, int w1, int h1, int x2, int y2, int w2, int h2)
3c046182 kojima1999-09-16 02:58:56 +0000263{
688a56e8
CM
Carlos R. Mafra2009-08-20 00:59:40 +0200264 return calcIntersectionLength(x1, w1, x2, w2)
265 * calcIntersectionLength(y1, h1, y2, h2);
3c046182 kojima1999-09-16 02:58:56 +0000266}
267
34be9d78 Carlos R. Mafra2009-08-29 18:46:05 +0200268static int calcSumOfCoveredAreas(WWindow *wwin, int x, int y, int w, int h)
3c046182 kojima1999-09-16 02:58:56 +0000269{
688a56e8
CM
Carlos R. Mafra2009-08-20 00:59:40 +0200270 int sum_isect = 0;
271 WWindow *test_window;
272 int tw, tx, ty, th;
273
274 test_window = wwin->screen_ptr->focused_window;
275 for (; test_window != NULL && test_window->prev != NULL;)
276 test_window = test_window->prev;
277
278 for (; test_window != NULL; test_window = test_window->next) {
279 if (test_window->frame->core->stacking->window_level < WMNormalLevel) {
280 continue;
281 }
3c046182 kojima1999-09-16 02:58:56 +0000282#if 0
688a56e8
CM
Carlos R. Mafra2009-08-20 00:59:40 +0200283 tw = test_window->client.width;
284 if (test_window->flags.shaded)
285 th = test_window->frame->top_width;
286 else
287 th = test_window->client.height + extra_height;
3c046182 kojima1999-09-16 02:58:56 +0000288#else
688a56e8
CM
Carlos R. Mafra2009-08-20 00:59:40 +0200289 tw = test_window->frame->core->width;
290 th = test_window->frame->core->height;
3c046182 kojima1999-09-16 02:58:56 +0000291#endif
688a56e8
CM
Carlos R. Mafra2009-08-20 00:59:40 +0200292 tx = test_window->frame_x;
293 ty = test_window->frame_y;
294
95a576bd
DD
Daniel D├ęchelotte2006-03-05 19:42:57 +0100295 if (test_window->flags.mapped || (test_window->flags.shaded &&
296 test_window->frame->workspace == wwin->screen_ptr->current_workspace &&
688a56e8
CM
Carlos R. Mafra2009-08-20 00:59:40 +0200297 !(test_window->flags.miniaturized || test_window->flags.hidden))) {
298 sum_isect += calcIntersectionArea(tx, ty, tw, th, x, y, w, h);
299 }
300 }
3c046182 kojima1999-09-16 02:58:56 +0000301
688a56e8
CM
Carlos R. Mafra2009-08-20 00:59:40 +0200302 return sum_isect;
303}
3c046182 kojima1999-09-16 02:58:56 +0000304
2f87d01a
CM
Carlos R. Mafra2009-08-28 16:44:54 +0200305static void set_width_height(WWindow *wwin, unsigned int *width, unsigned int *height)
306{
307 if (wwin->frame) {
308 *height += wwin->frame->top_width + wwin->frame->bottom_width;
309 } else {
310 if (HAS_TITLEBAR(wwin))
328251c6 Carlos R. Mafra2009-08-28 20:59:47 +0200311 *height += TITLEBAR_HEIGHT;
2f87d01a
CM
Carlos R. Mafra2009-08-28 16:44:54 +0200312 if (HAS_RESIZEBAR(wwin))
313 *height += RESIZEBAR_HEIGHT;
314 }
315 if (HAS_BORDER(wwin)) {
316 *height += 2 * FRAME_BORDER_WIDTH;
317 *width += 2 * FRAME_BORDER_WIDTH;
318 }
319}
320
3c046182 kojima1999-09-16 02:58:56 +0000321static void
34be9d78
CM
Carlos R. Mafra2009-08-29 18:46:05 +0200322smartPlaceWindow(WWindow *wwin, int *x_ret, int *y_ret, unsigned int width,
323 unsigned int height, WArea usableArea)
9d2e6ef9 scottc1998-09-29 22:36:29 +0000324{
688a56e8
CM
Carlos R. Mafra2009-08-20 00:59:40 +0200325 int test_x = 0, test_y = Y_ORIGIN;
326 int from_x, to_x, from_y, to_y;
327 int sx;
328 int min_isect, min_isect_x, min_isect_y;
329 int sum_isect;
330
2f87d01a Carlos R. Mafra2009-08-28 16:44:54 +0200331 set_width_height(wwin, &width, &height);
688a56e8 Carlos R. Mafra2009-08-20 00:59:40 +0200332
2f87d01a Carlos R. Mafra2009-08-28 16:44:54 +0200333 sx = X_ORIGIN;
688a56e8
CM
Carlos R. Mafra2009-08-20 00:59:40 +0200334 min_isect = INT_MAX;
335 min_isect_x = sx;
336 min_isect_y = test_y;
337
338 while (((test_y + height) < usableArea.y2)) {
339 test_x = sx;
340 while ((test_x + width) < usableArea.x2) {
341 sum_isect = calcSumOfCoveredAreas(wwin, test_x, test_y, width, height);
342
343 if (sum_isect < min_isect) {
344 min_isect = sum_isect;
345 min_isect_x = test_x;
346 min_isect_y = test_y;
347 }
348
349 test_x += PLACETEST_HSTEP;
350 }
351 test_y += PLACETEST_VSTEP;
352 }
353
354 from_x = min_isect_x - PLACETEST_HSTEP + 1;
355 from_x = WMAX(from_x, X_ORIGIN);
356 to_x = min_isect_x + PLACETEST_HSTEP;
357 if (to_x + width > usableArea.x2)
358 to_x = usableArea.x2 - width;
359
360 from_y = min_isect_y - PLACETEST_VSTEP + 1;
361 from_y = WMAX(from_y, Y_ORIGIN);
362 to_y = min_isect_y + PLACETEST_VSTEP;
363 if (to_y + height > usableArea.y2)
364 to_y = usableArea.y2 - height;
365
366 for (test_x = from_x; test_x < to_x; test_x++) {
367 for (test_y = from_y; test_y < to_y; test_y++) {
368 sum_isect = calcSumOfCoveredAreas(wwin, test_x, test_y, width, height);
369
370 if (sum_isect < min_isect) {
371 min_isect = sum_isect;
372 min_isect_x = test_x;
373 min_isect_y = test_y;
374 }
375 }
376 }
377
378 *x_ret = min_isect_x;
379 *y_ret = min_isect_y;
9d2e6ef9 scottc1998-09-29 22:36:29 +0000380}
381
ac64e68f dan1999-09-17 16:18:37 +0000382static Bool
34be9d78 Carlos R. Mafra2009-08-29 18:46:05 +0200383autoPlaceWindow(WWindow *wwin, int *x_ret, int *y_ret,
688a56e8 Carlos R. Mafra2009-08-20 00:59:40 +0200384 unsigned int width, unsigned int height, int tryCount, WArea usableArea)
ac64e68f dan1999-09-17 16:18:37 +0000385{
688a56e8
CM
Carlos R. Mafra2009-08-20 00:59:40 +0200386 WScreen *scr = wwin->screen_ptr;
387 int test_x = 0, test_y = Y_ORIGIN;
388 int loc_ok = False, tw, tx, ty, th;
389 int swidth, sx;
390 WWindow *test_window;
391
2f87d01a Carlos R. Mafra2009-08-28 16:44:54 +0200392 set_width_height(wwin, &width, &height);
688a56e8
CM
Carlos R. Mafra2009-08-20 00:59:40 +0200393 swidth = usableArea.x2 - usableArea.x1;
394 sx = X_ORIGIN;
395
396 /* this was based on fvwm2's smart placement */
688a56e8
CM
Carlos R. Mafra2009-08-20 00:59:40 +0200397 while (((test_y + height) < (usableArea.y2 - usableArea.y1)) && !loc_ok) {
398 test_x = sx;
399
400 while (((test_x + width) < swidth) && (!loc_ok)) {
401
402 loc_ok = True;
403 test_window = scr->focused_window;
404
405 while ((test_window != NULL) && (loc_ok == True)) {
406
407 if (test_window->frame->core->stacking->window_level
408 < WMNormalLevel && tryCount > 0) {
409 test_window = test_window->next;
410 continue;
411 }
ac64e68f dan1999-09-17 16:18:37 +0000412#if 0
688a56e8
CM
Carlos R. Mafra2009-08-20 00:59:40 +0200413 tw = test_window->client.width;
414 if (test_window->flags.shaded)
415 th = test_window->frame->top_width;
416 else
417 th = test_window->client.height + extra_height;
ac64e68f dan1999-09-17 16:18:37 +0000418#else
688a56e8
CM
Carlos R. Mafra2009-08-20 00:59:40 +0200419 tw = test_window->frame->core->width;
420 th = test_window->frame->core->height;
ac64e68f dan1999-09-17 16:18:37 +0000421#endif
688a56e8
CM
Carlos R. Mafra2009-08-20 00:59:40 +0200422 tx = test_window->frame_x;
423 ty = test_window->frame_y;
424
425 if ((tx < (test_x + width)) && ((tx + tw) > test_x) &&
426 (ty < (test_y + height)) && ((ty + th) > test_y) &&
427 (test_window->flags.mapped ||
428 (test_window->flags.shaded &&
429 test_window->frame->workspace == scr->current_workspace &&
430 !(test_window->flags.miniaturized || test_window->flags.hidden)))) {
431
432 loc_ok = False;
433 }
434 test_window = test_window->next;
435 }
436
437 test_window = scr->focused_window;
438
439 while ((test_window != NULL) && (loc_ok == True)) {
440
441 if (test_window->frame->core->stacking->window_level
442 < WMNormalLevel && tryCount > 0) {
443 test_window = test_window->prev;
444 continue;
445 }
ac64e68f dan1999-09-17 16:18:37 +0000446#if 0
688a56e8
CM
Carlos R. Mafra2009-08-20 00:59:40 +0200447 tw = test_window->client.width;
448 if (test_window->flags.shaded)
449 th = test_window->frame->top_width;
450 else
451 th = test_window->client.height + extra_height;
ac64e68f dan1999-09-17 16:18:37 +0000452#else
688a56e8
CM
Carlos R. Mafra2009-08-20 00:59:40 +0200453 tw = test_window->frame->core->width;
454 th = test_window->frame->core->height;
ac64e68f dan1999-09-17 16:18:37 +0000455#endif
688a56e8
CM
Carlos R. Mafra2009-08-20 00:59:40 +0200456 tx = test_window->frame_x;
457 ty = test_window->frame_y;
458
459 if ((tx < (test_x + width)) && ((tx + tw) > test_x) &&
460 (ty < (test_y + height)) && ((ty + th) > test_y) &&
461 (test_window->flags.mapped ||
462 (test_window->flags.shaded &&
463 test_window->frame->workspace == scr->current_workspace &&
464 !(test_window->flags.miniaturized || test_window->flags.hidden)))) {
465
466 loc_ok = False;
467 }
468 test_window = test_window->prev;
469 }
470 if (loc_ok == True) {
471 *x_ret = test_x;
472 *y_ret = test_y;
473 break;
474 }
475 test_x += PLACETEST_HSTEP;
476 }
477 test_y += PLACETEST_VSTEP;
478 }
479
480 return loc_ok;
ac64e68f dan1999-09-17 16:18:37 +0000481}
482
6830b057 dan2004-10-12 21:28:27 +0000483static void
34be9d78 Carlos R. Mafra2009-08-29 18:46:05 +0200484cascadeWindow(WScreen *scr, WWindow *wwin, int *x_ret, int *y_ret,
688a56e8 Carlos R. Mafra2009-08-20 00:59:40 +0200485 unsigned int width, unsigned int height, int h, WArea usableArea)
9d2e6ef9 scottc1998-09-29 22:36:29 +0000486{
2f87d01a Carlos R. Mafra2009-08-28 16:44:54 +0200487 set_width_height(wwin, &width, &height);
688a56e8
CM
Carlos R. Mafra2009-08-20 00:59:40 +0200488
489 *x_ret = h * scr->cascade_index + X_ORIGIN;
490 *y_ret = h * scr->cascade_index + Y_ORIGIN;
491
492 if (width + *x_ret > usableArea.x2 || height + *y_ret > usableArea.y2) {
493 scr->cascade_index = 0;
494 *x_ret = X_ORIGIN;
495 *y_ret = Y_ORIGIN;
496 }
9d2e6ef9 scottc1998-09-29 22:36:29 +0000497}
498
a10214a5 kojima2002-11-28 22:04:07 +0000499static void
34be9d78 Carlos R. Mafra2009-08-29 18:46:05 +0200500randomPlaceWindow(WScreen *scr, WWindow *wwin, int *x_ret, int *y_ret,
688a56e8 Carlos R. Mafra2009-08-20 00:59:40 +0200501 unsigned int width, unsigned int height, WArea usableArea)
a10214a5 kojima2002-11-28 22:04:07 +0000502{
688a56e8
CM
Carlos R. Mafra2009-08-20 00:59:40 +0200503 int w, h;
504
2f87d01a Carlos R. Mafra2009-08-28 16:44:54 +0200505 set_width_height(wwin, &width, &height);
688a56e8
CM
Carlos R. Mafra2009-08-20 00:59:40 +0200506
507 w = ((usableArea.x2 - X_ORIGIN) - width);
508 h = ((usableArea.y2 - Y_ORIGIN) - height);
509 if (w < 1)
510 w = 1;
511 if (h < 1)
512 h = 1;
513 *x_ret = X_ORIGIN + rand() % w;
514 *y_ret = Y_ORIGIN + rand() % h;
a10214a5 kojima2002-11-28 22:04:07 +0000515}
516
34be9d78 Carlos R. Mafra2009-08-29 18:46:05 +0200517void PlaceWindow(WWindow *wwin, int *x_ret, int *y_ret, unsigned width, unsigned height)
9d2e6ef9 scottc1998-09-29 22:36:29 +0000518{
688a56e8 Carlos R. Mafra2009-08-20 00:59:40 +0200519 WScreen *scr = wwin->screen_ptr;
34be9d78
CM
Carlos R. Mafra2009-08-29 18:46:05 +0200520 int h = WMFontHeight(scr->title_font)
521 + (wPreferences.window_title_clearance + TITLEBAR_EXTEND_SPACE) * 2;
522 WArea usableArea = wGetUsableAreaForHead(scr, wGetHeadForPointerLocation(scr),
688a56e8
CM
Carlos R. Mafra2009-08-20 00:59:40 +0200523 NULL, True);
524
525 switch (wPreferences.window_placement) {
526 case WPM_MANUAL:
527 InteractivePlaceWindow(wwin, x_ret, y_ret, width, height);
528 break;
529
530 case WPM_SMART:
531 smartPlaceWindow(wwin, x_ret, y_ret, width, height, usableArea);
532 break;
533
534 case WPM_AUTO:
535 if (autoPlaceWindow(wwin, x_ret, y_ret, width, height, 0, usableArea)) {
536 break;
537 } else if (autoPlaceWindow(wwin, x_ret, y_ret, width, height, 1, usableArea)) {
538 break;
539 }
540 /* there isn't a break here, because if we fail, it should fall
541 through to cascade placement, as people who want tiling want
542 automagicness aren't going to want to place their window */
543
544 case WPM_CASCADE:
545 if (wPreferences.window_placement == WPM_AUTO)
546 scr->cascade_index++;
547
548 cascadeWindow(scr, wwin, x_ret, y_ret, width, height, h, usableArea);
549
550 if (wPreferences.window_placement == WPM_CASCADE)
551 scr->cascade_index++;
552 break;
553
554 case WPM_RANDOM:
555 randomPlaceWindow(scr, wwin, x_ret, y_ret, width, height, usableArea);
556 break;
9d2e6ef9 scottc1998-09-29 22:36:29 +0000557
a10214a5 kojima2002-11-28 22:04:07 +0000558#ifdef DEBUG
688a56e8
CM
Carlos R. Mafra2009-08-20 00:59:40 +0200559 default:
560 puts("Invalid window placement!!!");
561 *x_ret = 0;
562 *y_ret = 0;
9d2e6ef9 scottc1998-09-29 22:36:29 +0000563#endif
688a56e8
CM
Carlos R. Mafra2009-08-20 00:59:40 +0200564 }
565
566 /*
567 * clip to usableArea instead of full screen
568 * this will also take dock/clip etc.. into account
569 * aswell as being xinerama friendly
570 */
571 if (*x_ret + width > usableArea.x2)
572 *x_ret = usableArea.x2 - width;
573 if (*x_ret < usableArea.x1)
574 *x_ret = usableArea.x1;
575
576 if (*y_ret + height > usableArea.y2)
577 *y_ret = usableArea.y2 - height;
578 if (*y_ret < usableArea.y1)
579 *y_ret = usableArea.y1;
9d2e6ef9 scottc1998-09-29 22:36:29 +0000580}