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"
43 extern WPreferences wPreferences
;
46 #define X_ORIGIN(scr) WMAX((scr)->totalUsableArea.x1,\
47 wPreferences.window_place_origin.x)
49 #define Y_ORIGIN(scr) WMAX((scr)->totalUsableArea.y1,\
50 wPreferences.window_place_origin.y)
54 * interactive window placement is in moveres.c
58 InteractivePlaceWindow(WWindow
*wwin
, int *x_ret
, int *y_ret
,
59 unsigned width
, unsigned height
);
63 * Returns True if it is an icon and is in this workspace.
66 iconPosition(WCoreWindow
*wcore
, int sx1
, int sy1
, int sx2
, int sy2
,
67 int workspace
, int *retX
, int *retY
)
72 parent
= wcore
->descriptor
.parent
;
74 /* if it is an application icon */
75 if (wcore
->descriptor
.parent_type
== WCLASS_APPICON
) {
76 *retX
= ((WAppIcon
*)parent
)->x_pos
;
77 *retY
= ((WAppIcon
*)parent
)->y_pos
;
80 } else if (wcore
->descriptor
.parent_type
== WCLASS_MINIWINDOW
&&
81 (((WIcon
*)parent
)->owner
->frame
->workspace
== workspace
82 || IS_OMNIPRESENT(((WIcon
*)parent
)->owner
)
83 || wPreferences
.sticky_icons
)
84 && ((WIcon
*)parent
)->mapped
85 && (!((WIcon
*)parent
)->owner
->flags
.hidden
86 || wcore
->screen_ptr
->flags
.startup
)) {
88 *retX
= ((WIcon
*)parent
)->owner
->icon_x
;
89 *retY
= ((WIcon
*)parent
)->owner
->icon_y
;
92 } else if (wcore
->descriptor
.parent_type
== WCLASS_WINDOW
93 && (((WWindow
*)parent
)->flags
.icon_moved
94 || ((WWindow
*)parent
)->flags
.hidden
)
95 && (((WWindow
*)parent
)->frame
->workspace
== workspace
96 || IS_OMNIPRESENT((WWindow
*)parent
)
97 || wPreferences
.sticky_icons
)) {
98 *retX
= ((WWindow
*)parent
)->icon_x
;
99 *retY
= ((WWindow
*)parent
)->icon_y
;
106 * Check if it is inside the screen.
109 if (*retX
< sx1
-wPreferences
.icon_size
)
111 else if (*retX
> sx2
)
114 if (*retY
< sy1
-wPreferences
.icon_size
)
116 else if (*retY
> sy2
)
127 PlaceIcon(WScreen
*scr
, int *x_ret
, int *y_ret
)
129 int pf
; /* primary axis */
130 int sf
; /* secondary axis */
136 int sx1
, sx2
, sy1
, sy2
; /* screen boundary */
141 int isize
= wPreferences
.icon_size
;
146 * Find out screen boundaries.
150 sx2
= scr
->scr_width
;
151 sy2
= scr
->scr_height
;
153 if (scr
->dock
->on_right_side
)
154 sx2
-= isize
+ DOCK_EXTRA_SPACE
;
156 sx1
+= isize
+ DOCK_EXTRA_SPACE
;
159 sw
= isize
* (scr
->scr_width
/isize
);
160 sh
= isize
* (scr
->scr_height
/isize
);
161 fullW
= (sx2
-sx1
)/isize
;
162 fullH
= (sy2
-sy1
)/isize
;
164 /* icon yard boundaries */
165 if (wPreferences
.icon_yard
& IY_VERT
) {
172 if (wPreferences
.icon_yard
& IY_RIGHT
) {
179 if (wPreferences
.icon_yard
& IY_TOP
) {
188 * Create a map with the occupied slots. 1 means the slot is used
189 * or at least partially used.
190 * The slot usage can be optimized by only marking fully used slots
191 * or slots that have most of it covered.
192 * Space usage is worse than the fvwm algorithm (used in the old version)
193 * but complexity is much better (faster) than it.
195 map
= wmalloc((sw
+2) * (sh
+2));
196 memset(map
, 0, (sw
+2) * (sh
+2));
198 #define INDEX(x,y) (((y)+1)*(sw+2) + (x) + 1)
200 for (level
= MAX_WINDOW_LEVELS
-1; level
>= WMDesktopLevel
; level
--) {
201 obj
= scr
->stacking_list
[level
];
206 if (iconPosition(obj
, sx1
, sy1
, sx2
, sy2
, scr
->current_workspace
,
208 int xdi
, ydi
; /* rounded down */
209 int xui
, yui
; /* rounded up */
213 xui
= (x
+isize
/2)/isize
;
214 yui
= (y
+isize
/2)/isize
;
215 map
[INDEX(xdi
,ydi
)] = 1;
216 map
[INDEX(xdi
,yui
)] = 1;
217 map
[INDEX(xui
,ydi
)] = 1;
218 map
[INDEX(xui
,yui
)] = 1;
220 obj
= obj
->stacking
->under
;
230 * Look for an empty slot
232 for (si
=0; si
<sf
; si
++) {
233 for (pi
=0; pi
<pf
; pi
++) {
234 if (wPreferences
.icon_yard
& IY_VERT
) {
235 x
= xo
+ xs
*(si
*isize
);
236 y
= yo
+ ys
*(pi
*isize
);
238 x
= xo
+ xs
*(pi
*isize
);
239 y
= yo
+ ys
*(si
*isize
);
241 if (!map
[INDEX(x
/isize
, y
/isize
)]) {
257 smartPlaceWindow(WWindow
*wwin
, int *x_ret
, int *y_ret
,
258 unsigned int width
, unsigned int height
, int tryCount
)
260 WScreen
*scr
= wwin
->screen_ptr
;
261 int test_x
= 0, test_y
= Y_ORIGIN(scr
);
262 int loc_ok
= False
, tw
,tx
,ty
,th
;
264 WWindow
*test_window
;
266 WArea usableArea
= scr
->totalUsableArea
;
269 extra_height
= wwin
->frame
->top_width
+ wwin
->frame
->bottom_width
+ 2;
271 extra_height
= 24; /* random value */
273 swidth
= usableArea
.x2
-usableArea
.x1
;
276 /* this was based on fvwm2's smart placement */
278 height
+= extra_height
;
280 while (((test_y
+ height
) < (scr
->scr_height
)) && (!loc_ok
)) {
284 while (((test_x
+ width
) < swidth
) && (!loc_ok
)) {
287 test_window
= scr
->focused_window
;
289 while ((test_window
!= NULL
) && (loc_ok
== True
)) {
291 if (test_window
->frame
->core
->stacking
->window_level
292 < WMNormalLevel
&& tryCount
> 0) {
293 test_window
= test_window
->next
;
297 tw
= test_window
->client
.width
;
298 if (test_window
->flags
.shaded
)
299 th
= test_window
->frame
->top_width
;
301 th
= test_window
->client
.height
+ extra_height
;
303 tw
= test_window
->frame
->core
->width
;
304 th
= test_window
->frame
->core
->height
;
306 tx
= test_window
->frame_x
;
307 ty
= test_window
->frame_y
;
309 if ((tx
< (test_x
+ width
)) && ((tx
+ tw
) > test_x
) &&
310 (ty
< (test_y
+ height
)) && ((ty
+ th
) > test_y
) &&
311 (test_window
->flags
.mapped
||
312 (test_window
->flags
.shaded
&&
313 !(test_window
->flags
.miniaturized
||
314 test_window
->flags
.hidden
)))) {
318 test_window
= test_window
->next
;
321 test_window
= scr
->focused_window
;
323 while ((test_window
!= NULL
) && (loc_ok
== True
)) {
325 if (test_window
->frame
->core
->stacking
->window_level
326 < WMNormalLevel
&& tryCount
> 0) {
327 test_window
= test_window
->prev
;
331 tw
= test_window
->client
.width
;
332 if (test_window
->flags
.shaded
)
333 th
= test_window
->frame
->top_width
;
335 th
= test_window
->client
.height
+ extra_height
;
337 tw
= test_window
->frame
->core
->width
;
338 th
= test_window
->frame
->core
->height
;
340 tx
= test_window
->frame_x
;
341 ty
= test_window
->frame_y
;
343 if ((tx
< (test_x
+ width
)) && ((tx
+ tw
) > test_x
) &&
344 (ty
< (test_y
+ height
)) && ((ty
+ th
) > test_y
) &&
345 (test_window
->flags
.mapped
||
346 (test_window
->flags
.shaded
&&
347 !(test_window
->flags
.miniaturized
||
348 test_window
->flags
.hidden
)))) {
352 test_window
= test_window
->prev
;
354 if (loc_ok
== True
) {
359 test_x
+= PLACETEST_HSTEP
;
361 test_y
+= PLACETEST_VSTEP
;
369 cascadeWindow(WScreen
*scr
, WWindow
*wwin
, int *x_ret
, int *y_ret
,
370 unsigned int width
, unsigned int height
, int h
)
372 unsigned int extra_height
;
373 WArea usableArea
= scr
->totalUsableArea
;
376 extra_height
= wwin
->frame
->top_width
+ wwin
->frame
->bottom_width
;
378 extra_height
= 24; /* random value */
380 *x_ret
= h
* scr
->cascade_index
+ X_ORIGIN(scr
);
381 *y_ret
= h
* scr
->cascade_index
+ Y_ORIGIN(scr
);
382 height
+= extra_height
;
384 if (width
+ *x_ret
> usableArea
.x2
|| height
+ *y_ret
> usableArea
.y2
) {
385 scr
->cascade_index
= 0;
386 *x_ret
= X_ORIGIN(scr
);
387 *y_ret
= Y_ORIGIN(scr
);
393 PlaceWindow(WWindow
*wwin
, int *x_ret
, int *y_ret
,
394 unsigned width
, unsigned height
)
396 WScreen
*scr
= wwin
->screen_ptr
;
397 int h
= scr
->title_font
->height
+TITLEBAR_EXTRA_HEIGHT
;
399 switch (wPreferences
.window_placement
) {
401 InteractivePlaceWindow(wwin
, x_ret
, y_ret
, width
, height
);
405 if (smartPlaceWindow(wwin
, x_ret
, y_ret
, width
, height
, 0)) {
407 } else if (smartPlaceWindow(wwin
, x_ret
, y_ret
, width
, height
, 1)) {
410 /* there isn't a break here, because if we fail, it should fall
411 through to cascade placement, as people who want tiling want
412 automagicness aren't going to want to place their window */
415 if (wPreferences
.window_placement
== WPM_SMART
)
416 scr
->cascade_index
++;
418 cascadeWindow(scr
, wwin
, x_ret
, y_ret
, width
, height
, h
);
420 if (wPreferences
.window_placement
== WPM_CASCADE
)
421 scr
->cascade_index
++;
426 int w
, h
, extra_height
;
427 WArea usableArea
= scr
->totalUsableArea
;
430 extra_height
= wwin
->frame
->top_width
+ wwin
->frame
->bottom_width
+ 2;
432 extra_height
= 24; /* random value */
434 w
= ((usableArea
.x2
-X_ORIGIN(scr
)) - width
);
435 h
= ((usableArea
.y2
-Y_ORIGIN(scr
)) - height
- extra_height
);
438 *x_ret
= X_ORIGIN(scr
) + rand()%w
;
439 *y_ret
= Y_ORIGIN(scr
) + rand()%h
;
445 puts("Invalid window placement!!!");
451 if (*x_ret
+ width
> scr
->scr_width
)
452 *x_ret
= scr
->scr_width
- width
;
456 if (*y_ret
+ height
> scr
->scr_height
)
457 *y_ret
= scr
->scr_height
- height
;