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
,
54 unsigned width
, unsigned height
);
58 * Returns True if it is an icon and is in this workspace.
61 iconPosition(WCoreWindow
*wcore
, int sx1
, int sy1
, int sx2
, int sy2
,
62 int workspace
, int *retX
, int *retY
)
67 parent
= wcore
->descriptor
.parent
;
69 /* if it is an application icon */
70 if (wcore
->descriptor
.parent_type
== WCLASS_APPICON
) {
71 *retX
= ((WAppIcon
*)parent
)->x_pos
;
72 *retY
= ((WAppIcon
*)parent
)->y_pos
;
75 } else if (wcore
->descriptor
.parent_type
== WCLASS_MINIWINDOW
&&
76 (((WIcon
*)parent
)->owner
->frame
->workspace
==workspace
77 || ((WIcon
*)parent
)->owner
->window_flags
.omnipresent
78 || wPreferences
.sticky_icons
)
79 && !((WIcon
*)parent
)->owner
->flags
.hidden
) {
81 *retX
= ((WIcon
*)parent
)->owner
->icon_x
;
82 *retY
= ((WIcon
*)parent
)->owner
->icon_y
;
88 * Check if it is inside the screen.
91 if (*retX
< sx1
-wPreferences
.icon_size
)
96 if (*retY
< sy1
-wPreferences
.icon_size
)
109 PlaceIcon(WScreen
*scr
, int *x_ret
, int *y_ret
)
111 int pf
; /* primary axis */
112 int sf
; /* secondary axis */
118 int sx1
, sx2
, sy1
, sy2
; /* screen boundary */
123 int isize
= wPreferences
.icon_size
;
128 * Find out screen boundaries.
132 sx2
= scr
->scr_width
;
133 sy2
= scr
->scr_height
;
135 if (scr
->dock
->on_right_side
)
136 sx2
-= isize
+ DOCK_EXTRA_SPACE
;
138 sx1
+= isize
+ DOCK_EXTRA_SPACE
;
141 sw
= isize
* (scr
->scr_width
/isize
);
142 sh
= isize
* (scr
->scr_height
/isize
);
143 fullW
= (sx2
-sx1
)/isize
;
144 fullH
= (sy2
-sy1
)/isize
;
146 /* icon yard boundaries */
147 if (wPreferences
.icon_yard
& IY_VERT
) {
154 if (wPreferences
.icon_yard
& IY_RIGHT
) {
161 if (wPreferences
.icon_yard
& IY_TOP
) {
170 * Create a map with the occupied slots. 1 means the slot is used
171 * or at least partially used.
172 * The slot usage can be optimized by only marking fully used slots
173 * or slots that have most of it covered.
174 * Space usage is worse than the fvwm algorithm (used in the old version)
175 * but complexity is much better (faster) than it.
177 map
= wmalloc((sw
+2) * (sh
+2));
178 memset(map
, 0, (sw
+2) * (sh
+2));
180 #define INDEX(x,y) (((y)+1)*(sw+2) + (x) + 1)
182 for (level
= WMNormalLevel
; level
>= WMDesktopLevel
; level
--) {
183 obj
= scr
->stacking_list
[level
];
188 if (iconPosition(obj
, sx1
, sy1
, sx2
, sy2
, scr
->current_workspace
,
190 int xdi
, ydi
; /* rounded down */
191 int xui
, yui
; /* rounded up */
195 xui
= (x
+isize
/2)/isize
;
196 yui
= (y
+isize
/2)/isize
;
197 map
[INDEX(xdi
,ydi
)] = 1;
198 map
[INDEX(xdi
,yui
)] = 1;
199 map
[INDEX(xui
,ydi
)] = 1;
200 map
[INDEX(xui
,yui
)] = 1;
202 obj
= obj
->stacking
->under
;
212 * Look for an empty slot
214 for (si
=0; si
<sf
; si
++) {
215 for (pi
=0; pi
<pf
; pi
++) {
216 if (wPreferences
.icon_yard
& IY_VERT
) {
217 x
= xo
+ xs
*(si
*isize
);
218 y
= yo
+ ys
*(pi
*isize
);
220 x
= xo
+ xs
*(pi
*isize
);
221 y
= yo
+ ys
*(si
*isize
);
223 if (!map
[INDEX(x
/isize
, y
/isize
)]) {
241 smartPlaceWindow(WWindow
*wwin
, int *x_ret
, int *y_ret
,
242 unsigned int width
, unsigned int height
)
244 WScreen
*scr
= wwin
->screen_ptr
;
245 int test_x
= 0, test_y
= Y_ORIGIN
;
246 int loc_ok
= False
, tw
,tx
,ty
,th
;
248 WWindow
*test_window
;
252 extra_height
= wwin
->frame
->top_width
+ wwin
->frame
->bottom_width
+ 2;
254 extra_height
= 24; /* random value */
256 swidth
= scr
->scr_width
;
258 if (scr
->dock
&& !scr
->dock
->lowered
) {
259 if (scr
->dock
->on_right_side
)
260 swidth
-= wPreferences
.icon_size
+ DOCK_EXTRA_SPACE
;
261 else if (X_ORIGIN
< wPreferences
.icon_size
+ DOCK_EXTRA_SPACE
)
262 sx
+= wPreferences
.icon_size
+ DOCK_EXTRA_SPACE
- X_ORIGIN
;
265 /* this was based on fvwm2's smart placement */
267 height
+= extra_height
;
269 while (((test_y
+ height
) < (scr
->scr_height
)) && (!loc_ok
)) {
273 while (((test_x
+ width
) < swidth
) && (!loc_ok
)) {
276 test_window
= scr
->focused_window
;
278 while ((test_window
!= (WWindow
*) 0) && (loc_ok
== True
)) {
280 tw
= test_window
->client
.width
;
281 if (test_window
->flags
.shaded
)
282 th
= test_window
->frame
->top_width
;
284 th
= test_window
->client
.height
+extra_height
;
285 tx
= test_window
->frame_x
;
286 ty
= test_window
->frame_y
;
288 if((tx
<(test_x
+width
))&&((tx
+ tw
) > test_x
)&&
289 (ty
<(test_y
+height
))&&((ty
+ th
)>test_y
)&&
290 (test_window
->flags
.mapped
||
291 (test_window
->flags
.shaded
&&
292 !(test_window
->flags
.miniaturized
||
293 test_window
->flags
.hidden
)))) {
297 test_window
= test_window
->next
;
300 test_window
= scr
->focused_window
;
302 while ((test_window
!= (WWindow
*) 0) && (loc_ok
== True
)) {
304 tw
= test_window
->client
.width
;
305 if (test_window
->flags
.shaded
)
306 th
= test_window
->frame
->top_width
;
308 th
= test_window
->client
.height
+extra_height
;
309 tx
= test_window
->frame_x
;
310 ty
= test_window
->frame_y
;
312 if((tx
<(test_x
+width
))&&((tx
+ tw
) > test_x
)&&
313 (ty
<(test_y
+height
))&&((ty
+ th
)>test_y
)&&
314 (test_window
->flags
.mapped
||
315 (test_window
->flags
.shaded
&&
316 !(test_window
->flags
.miniaturized
||
317 test_window
->flags
.hidden
)))) {
321 test_window
= test_window
->prev
;
323 if (loc_ok
== True
) {
328 test_x
+= PLACETEST_HSTEP
;
330 test_y
+= PLACETEST_VSTEP
;
337 cascadeWindow(WScreen
*scr
, WWindow
*wwin
, int *x_ret
, int *y_ret
,
338 unsigned int width
, unsigned int height
, int h
)
340 unsigned int extra_height
;
341 unsigned int scr_width
;
344 scr_width
= scr
->scr_width
;
345 if (scr
->dock
&& !scr
->dock
->lowered
) {
346 if (scr
->dock
->on_right_side
) {
347 scr_width
-= wPreferences
.icon_size
;
349 xoffset
= wPreferences
.icon_size
;
354 extra_height
= wwin
->frame
->top_width
+ wwin
->frame
->bottom_width
;
356 extra_height
= 24; /* random value */
358 *x_ret
= h
* scr
->cascade_index
+ X_ORIGIN
;
359 *y_ret
= h
* scr
->cascade_index
+ Y_ORIGIN
;
360 height
+= extra_height
;
362 if (width
+ *x_ret
> scr_width
|| height
+ *y_ret
> scr
->scr_height
) {
363 scr
->cascade_index
= 0;
364 *x_ret
= h
*scr
->cascade_index
+ X_ORIGIN
;
365 *y_ret
= h
*scr
->cascade_index
+ Y_ORIGIN
;
371 PlaceWindow(WWindow
*wwin
, int *x_ret
, int *y_ret
,
372 unsigned width
, unsigned height
)
374 WScreen
*scr
= wwin
->screen_ptr
;
375 int h
= scr
->title_font
->height
+TITLEBAR_EXTRA_HEIGHT
;
377 switch (wPreferences
.window_placement
) {
379 InteractivePlaceWindow(wwin
, x_ret
, y_ret
, width
, height
);
383 if (smartPlaceWindow(wwin
, x_ret
, y_ret
, width
, height
))
385 /* there isn't a break here, because if we fail, it should fall
386 through to cascade placement, as people who want tiling want
387 automagicness aren't going to want to place their window */
390 if (wPreferences
.window_placement
== WPM_SMART
)
391 scr
->cascade_index
++;
393 cascadeWindow(scr
, wwin
, x_ret
, y_ret
, width
, height
, h
);
395 if (wPreferences
.window_placement
== WPM_CASCADE
)
396 scr
->cascade_index
++;
398 if (scr
->dock
&& !scr
->dock
->lowered
) {
402 if (scr
->dock
->on_right_side
403 && x2
> scr
->scr_width
- wPreferences
.icon_size
-
405 *x_ret
= scr
->scr_width
- width
406 - wPreferences
.icon_size
- DOCK_EXTRA_SPACE
;
407 else if (!scr
->dock
->on_right_side
&&
408 X_ORIGIN
< wPreferences
.icon_size
+ DOCK_EXTRA_SPACE
)
409 *x_ret
+= wPreferences
.icon_size
+ DOCK_EXTRA_SPACE
- X_ORIGIN
;
417 w
= (scr
->scr_width
- width
);
418 h
= (scr
->scr_height
- height
);
423 if (scr
->dock
&& !scr
->dock
->lowered
) {
427 if (scr
->dock
->on_right_side
428 && x2
> scr
->scr_width
- wPreferences
.icon_size
-
430 *x_ret
= scr
->scr_width
- width
431 - wPreferences
.icon_size
- DOCK_EXTRA_SPACE
;
432 else if (!scr
->dock
->on_right_side
433 && *x_ret
< wPreferences
.icon_size
)
434 *x_ret
= wPreferences
.icon_size
+ DOCK_EXTRA_SPACE
;
441 puts("Invalid window placement!!!");
449 else if (*x_ret
+ width
> scr
->scr_width
)
450 *x_ret
= scr
->scr_width
- width
;
454 else if (*y_ret
+ height
> scr
->scr_height
)
455 *y_ret
= scr
->scr_height
- height
;