1 /* placement.c - window and icon placement on screen
3 * Window Maker window manager
5 * Copyright (c) 1997, 1998 Alfredo K. Kojima
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 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
30 #include "WindowMaker.h"
37 #include "application.h"
41 extern WPreferences wPreferences
;
44 #define X_ORIGIN wPreferences.window_place_origin.x
45 #define Y_ORIGIN wPreferences.window_place_origin.y
49 * interactive window placement is in moveres.c
53 InteractivePlaceWindow(WWindow
*wwin
, int *x_ret
, int *y_ret
);
57 PlaceIcon(WScreen
*scr
, int *x_ret
, int *y_ret
)
61 int left_margin
, right_margin
;
65 right_margin
= scr
->scr_width
;
67 if (scr
->dock
->on_right_side
)
68 right_margin
-= wPreferences
.icon_size
+ DOCK_EXTRA_SPACE
;
70 left_margin
+= wPreferences
.icon_size
+ DOCK_EXTRA_SPACE
;
75 y1
= y2
-wPreferences
.icon_size
*2;
76 x2
= left_margin
+wPreferences
.icon_size
;
79 wcore
= scr
->stacking_list
[0];
84 if (x2
>=right_margin
+wPreferences
.icon_size
) {
86 x2
= left_margin
+wPreferences
.icon_size
*2;
87 y1
-= wPreferences
.icon_size
;
88 y2
-= wPreferences
.icon_size
;
89 if (y2
<wPreferences
.icon_size
) {
90 /* what's this guy doing!? */
98 parent
= (void*) wcore
->descriptor
.parent
;
100 /* if it is an application icon */
101 if (wcore
->descriptor
.parent_type
== WCLASS_APPICON
) {
102 icon_x
= ((WAppIcon
*)parent
)->x_pos
;
103 icon_y
= ((WAppIcon
*)parent
)->y_pos
;
104 } else if (wcore
->descriptor
.parent_type
== WCLASS_MINIWINDOW
&&
105 (((WIcon
*)parent
)->owner
->frame
->workspace
==scr
->current_workspace
106 || ((WIcon
*)parent
)->owner
->window_flags
.omnipresent
107 || wPreferences
.sticky_icons
)) {
108 icon_x
= ((WIcon
*)parent
)->owner
->icon_x
;
109 icon_y
= ((WIcon
*)parent
)->owner
->icon_y
;
111 wcore
= wcore
->stacking
->under
;
114 wcore
= wcore
->stacking
->under
;
116 /* test if place is taken */
117 if (icon_y
>y1
&& icon_y
<y2
) {
118 if (icon_x
<x2
&& icon_x
>=x1
) {
119 x2
= icon_x
+wPreferences
.icon_size
*2;
120 x1
= icon_x
+wPreferences
.icon_size
;
121 /* this place can't be used */
122 wcore
= scr
->stacking_list
[0];
133 *y_ret
= y2
-wPreferences
.icon_size
;
138 * Returns True if it is an icon and is in this workspace.
141 iconPosition(WCoreWindow
*wcore
, int sx1
, int sy1
, int sx2
, int sy2
,
142 int workspace
, int *retX
, int *retY
)
147 parent
= wcore
->descriptor
.parent
;
149 /* if it is an application icon */
150 if (wcore
->descriptor
.parent_type
== WCLASS_APPICON
) {
151 *retX
= ((WAppIcon
*)parent
)->x_pos
;
152 *retY
= ((WAppIcon
*)parent
)->y_pos
;
155 } else if (wcore
->descriptor
.parent_type
== WCLASS_MINIWINDOW
&&
156 (((WIcon
*)parent
)->owner
->frame
->workspace
==workspace
157 || ((WIcon
*)parent
)->owner
->window_flags
.omnipresent
158 || wPreferences
.sticky_icons
)) {
160 *retX
= ((WIcon
*)parent
)->owner
->icon_x
;
161 *retY
= ((WIcon
*)parent
)->owner
->icon_y
;
167 * Check if it is inside the screen.
170 if (*retX
< sx1
-wPreferences
.icon_size
)
172 else if (*retX
> sx2
)
175 if (*retY
< sy1
-wPreferences
.icon_size
)
177 else if (*retY
> sy2
)
188 PlaceIcon(WScreen
*scr
, int *x_ret
, int *y_ret
)
190 int pf
; /* primary axis */
191 int sf
; /* secondary axis */
197 int sx1
, sx2
, sy1
, sy2
; /* screen boundary */
202 int isize
= wPreferences
.icon_size
;
206 * Find out screen boundaries.
210 sx2
= scr
->scr_width
;
211 sy2
= scr
->scr_height
;
213 if (scr
->dock
->on_right_side
)
214 sx2
-= isize
+ DOCK_EXTRA_SPACE
;
216 sx1
+= isize
+ DOCK_EXTRA_SPACE
;
219 sw
= isize
* (scr
->scr_width
/isize
);
220 sh
= isize
* (scr
->scr_height
/isize
);
221 fullW
= (sx2
-sx1
)/isize
;
222 fullH
= (sy2
-sy1
)/isize
;
224 /* icon yard boundaries */
225 if (wPreferences
.icon_yard
& IY_VERT
) {
232 if (wPreferences
.icon_yard
& IY_RIGHT
) {
239 if (wPreferences
.icon_yard
& IY_TOP
) {
248 * Create a map with the occupied slots. 1 means the slot is used
249 * or at least partially used.
250 * The slot usage can be optimized by only marking fully used slots
251 * or slots that have most of it covered.
252 * Space usage is worse than the fvwm algorithm (used in the old version)
253 * but complexity is much better (faster) than it.
255 map
= wmalloc((sw
+2) * (sh
+2));
256 memset(map
, 0, (sw
+2) * (sh
+2));
258 #define INDEX(x,y) (((y)+1)*(sw+2) + (x) + 1)
260 obj
= scr
->stacking_list
[0];
264 if (iconPosition(obj
, sx1
, sy1
, sx2
, sy2
, scr
->current_workspace
,
266 int xdi
, ydi
; /* rounded down */
267 int xui
, yui
; /* rounded up */
271 xui
= (x
+isize
/2)/isize
;
272 yui
= (y
+isize
/2)/isize
;
273 map
[INDEX(xdi
,ydi
)] = 1;
274 map
[INDEX(xdi
,yui
)] = 1;
275 map
[INDEX(xui
,ydi
)] = 1;
276 map
[INDEX(xui
,yui
)] = 1;
278 obj
= obj
->stacking
->under
;
288 * Look for an empty slot
290 for (si
=0; si
<sf
; si
++) {
291 for (pi
=0; pi
<pf
; pi
++) {
292 if (wPreferences
.icon_yard
& IY_VERT
) {
293 x
= xo
+ xs
*(si
*isize
);
294 y
= yo
+ ys
*(pi
*isize
);
296 x
= xo
+ xs
*(pi
*isize
);
297 y
= yo
+ ys
*(si
*isize
);
299 if (!map
[INDEX(x
/isize
, y
/isize
)]) {
317 smartPlaceWindow(WWindow
*wwin
, int *x_ret
, int *y_ret
,
318 unsigned int width
, unsigned int height
)
320 WScreen
*scr
= wwin
->screen_ptr
;
321 int test_x
= 0, test_y
= Y_ORIGIN
;
322 int loc_ok
= False
, tw
,tx
,ty
,th
;
324 WWindow
*test_window
;
328 extra_height
= wwin
->frame
->top_width
+ wwin
->frame
->bottom_width
+ 2;
330 extra_height
= 24; /* random value */
332 swidth
= scr
->scr_width
;
334 if (scr
->dock
&& !scr
->dock
->lowered
) {
335 if (scr
->dock
->on_right_side
)
336 swidth
-= wPreferences
.icon_size
+ DOCK_EXTRA_SPACE
;
337 else if (X_ORIGIN
< wPreferences
.icon_size
+ DOCK_EXTRA_SPACE
)
338 sx
+= wPreferences
.icon_size
+ DOCK_EXTRA_SPACE
- X_ORIGIN
;
341 /* this was based on fvwm2's smart placement */
343 height
+= extra_height
;
345 while (((test_y
+ height
) < (scr
->scr_height
)) && (!loc_ok
)) {
349 while (((test_x
+ width
) < swidth
) && (!loc_ok
)) {
352 test_window
= scr
->focused_window
;
354 while ((test_window
!= (WWindow
*) 0) && (loc_ok
== True
)) {
356 tw
= test_window
->client
.width
;
357 if (test_window
->flags
.shaded
)
358 th
= test_window
->frame
->top_width
;
360 th
= test_window
->client
.height
+extra_height
;
361 tx
= test_window
->frame_x
;
362 ty
= test_window
->frame_y
;
364 if((tx
<(test_x
+width
))&&((tx
+ tw
) > test_x
)&&
365 (ty
<(test_y
+height
))&&((ty
+ th
)>test_y
)&&
366 (test_window
->flags
.mapped
||
367 (test_window
->flags
.shaded
&&
368 !(test_window
->flags
.miniaturized
||
369 test_window
->flags
.hidden
)))) {
373 test_window
= test_window
->next
;
376 test_window
= scr
->focused_window
;
378 while ((test_window
!= (WWindow
*) 0) && (loc_ok
== True
)) {
380 tw
= test_window
->client
.width
;
381 if (test_window
->flags
.shaded
)
382 th
= test_window
->frame
->top_width
;
384 th
= test_window
->client
.height
+extra_height
;
385 tx
= test_window
->frame_x
;
386 ty
= test_window
->frame_y
;
388 if((tx
<(test_x
+width
))&&((tx
+ tw
) > test_x
)&&
389 (ty
<(test_y
+height
))&&((ty
+ th
)>test_y
)&&
390 (test_window
->flags
.mapped
||
391 (test_window
->flags
.shaded
&&
392 !(test_window
->flags
.miniaturized
||
393 test_window
->flags
.hidden
)))) {
397 test_window
= test_window
->prev
;
399 if (loc_ok
== True
) {
404 test_x
+= PLACETEST_HSTEP
;
406 test_y
+= PLACETEST_VSTEP
;
412 /* Alfredo, shouldn't the cascade placement follow the !dock->lowered flag
413 * like smart placement?
414 * I didn't knew your intention about this, so I did not coded it, but it is
415 * quite simple to do, if you think it should. -Dan
418 cascadeWindow(WScreen
*scr
, WWindow
*wwin
, int *x_ret
, int *y_ret
,
419 unsigned int width
, unsigned int height
, int h
)
421 unsigned int extra_height
;
424 extra_height
= wwin
->frame
->top_width
+ wwin
->frame
->bottom_width
;
426 extra_height
= 24; /* random value */
428 *x_ret
= h
* scr
->cascade_index
+ X_ORIGIN
;
429 *y_ret
= h
* scr
->cascade_index
+ Y_ORIGIN
;
430 height
+= extra_height
;
432 if (width
+ *x_ret
> scr
->scr_width
|| height
+ *y_ret
> scr
->scr_height
) {
433 scr
->cascade_index
= 0;
434 *x_ret
= h
*scr
->cascade_index
+ X_ORIGIN
;
435 *y_ret
= h
*scr
->cascade_index
+ Y_ORIGIN
;
441 PlaceWindow(WWindow
*wwin
, int *x_ret
, int *y_ret
,
442 unsigned width
, unsigned height
)
444 WScreen
*scr
= wwin
->screen_ptr
;
445 int h
= scr
->title_font
->height
+TITLEBAR_EXTRA_HEIGHT
;
447 switch (wPreferences
.window_placement
) {
449 InteractivePlaceWindow(wwin
, x_ret
, y_ret
);
453 if (smartPlaceWindow(wwin
, x_ret
, y_ret
, width
, height
))
455 /* there isn't a break here, because if we fail, it should fall
456 through to cascade placement, as people who want tiling want
457 automagicness aren't going to want to place their window */
460 if (wPreferences
.window_placement
== WPM_SMART
)
461 scr
->cascade_index
++;
463 cascadeWindow(scr
, wwin
, x_ret
, y_ret
, width
, height
, h
);
465 if (wPreferences
.window_placement
== WPM_CASCADE
)
466 scr
->cascade_index
++;
468 if (scr
->dock
&& !scr
->dock
->lowered
) {
471 x2
= *x_ret
+ wwin
->client
.width
;
472 if (scr
->dock
->on_right_side
473 && x2
> scr
->scr_width
- wPreferences
.icon_size
-
475 *x_ret
= scr
->scr_width
- wwin
->client
.width
476 - wPreferences
.icon_size
- DOCK_EXTRA_SPACE
;
477 else if (!scr
->dock
->on_right_side
&&
478 X_ORIGIN
< wPreferences
.icon_size
+ DOCK_EXTRA_SPACE
)
479 *x_ret
+= wPreferences
.icon_size
+ DOCK_EXTRA_SPACE
- X_ORIGIN
;
487 w
= (scr
->scr_width
-wwin
->client
.width
);
488 h
= (scr
->scr_height
-wwin
->client
.height
);
493 if (scr
->dock
&& !scr
->dock
->lowered
) {
496 x2
= *x_ret
+ wwin
->client
.width
;
497 if (scr
->dock
->on_right_side
498 && x2
> scr
->scr_width
- wPreferences
.icon_size
-
500 *x_ret
= scr
->scr_width
- wwin
->client
.width
501 - wPreferences
.icon_size
- DOCK_EXTRA_SPACE
;
502 else if (!scr
->dock
->on_right_side
503 && *x_ret
< wPreferences
.icon_size
)
504 *x_ret
= wPreferences
.icon_size
+ DOCK_EXTRA_SPACE
;
511 puts("Invalid window placement!!!");
519 else if (*x_ret
+ wwin
->client
.width
> scr
->scr_width
)
520 *x_ret
= scr
->scr_width
- wwin
->client
.width
;
524 else if (*y_ret
+ wwin
->client
.height
> scr
->scr_height
)
525 *y_ret
= scr
->scr_height
- wwin
->client
.height
;