1 /*
2  * Copyright (C) 2005 Fabian Yamaguchi
3  * Copyright (C) 2004-2005 Sasha Vasko
4  * Copyright (C) 1996 Frank Fejes
5  * Copyright (C) 1995 Bo Yang
6  * Copyright (C) 1993 Robert Nation
7  *
8  * This program is free software; you can redistribute it and/or modify
9  * it under the terms of the GNU General Public License as published by
10  * the Free Software Foundation; either version 2 of the License, or
11  * (at your option) any later version.
12  *
13  * This program is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16  * GNU General Public License for more details.
17  *
18  * You should have received a copy of the GNU General Public License
19  * along with this program; if not, write to the Free Software
20  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
21  *
22  */
23 
24 #define LOCAL_DEBUG
25 #include "../../configure.h"
26 
27 #include "asinternals.h"
28 #include "../../libAfterStep/moveresize.h"
29 
30 
31 struct ASWindowGridAuxData {
32 	ASGrid *grid;
33 	long desk;
34 	int min_layer;
35 	Bool frame_only;
36 	int vx, vy;
37 	Bool ignore_avoid_cover;
38 	ASWindow *target;
39 };
40 
41 typedef struct ASFreeRectangleAuxData {
42 	ASVector *list;
43 	long desk;
44 	int min_layer;								/* applies only to non-AvoidCover windows */
45 	int max_layer;								/* applies to all windows - including Avoid Cover */
46 	Bool frame_only;
47 	ASGeometry area;
48 	ASWindow *to_skip;
49 } ASFreeRectangleAuxData;
50 
51 typedef struct ASAvoidCoverAuxData {
52 	ASWindow *new_aswin;
53 	ASWindowBox *aswbox;
54 	ASGeometry *area;
55 } ASAvoidCoverAuxData;
56 
57 
58 /*************************************************************************/
59 /* here we build vector of rectangles, representing one available
60  * space each :
61  */
62 /*************************************************************************/
63 
get_free_rectangles_iter_func(void * data,void * aux_data)64 Bool get_free_rectangles_iter_func (void *data, void *aux_data)
65 {
66 	ASFreeRectangleAuxData *fr_data = (ASFreeRectangleAuxData *) aux_data;
67 	ASWindow *asw = (ASWindow *) data;
68 
69 	if (asw
70 			&& (!IsValidDesk (fr_data->desk)
71 					|| ASWIN_DESK (asw) == fr_data->desk)
72 			&& asw != fr_data->to_skip
73 			&& !ASWIN_GET_FLAGS (asw, AS_Fullscreen | AS_ShortLived)
74 			&& fr_data->max_layer >= ASWIN_LAYER (asw)
75 			&& (ASWIN_HFLAGS (asw, AS_AvoidCover)
76 					|| fr_data->min_layer <= ASWIN_LAYER (asw))) {
77 		int min_vx = fr_data->area.x, max_vx =
78 				fr_data->area.x + fr_data->area.width;
79 		int min_vy = fr_data->area.y, max_vy =
80 				fr_data->area.y + fr_data->area.height;
81 		int x, y;
82 		unsigned int width, height, bw;
83 
84 		if (ASWIN_GET_FLAGS (asw, AS_Iconic)) {
85 			if (asw->icon_canvas != asw->icon_title_canvas
86 					&& asw->icon_title_canvas != NULL) {
87 				get_current_canvas_geometry (asw->icon_title_canvas, &x, &y,
88 																		 &width, &height, &bw);
89 				x += Scr.Vx;
90 				y += Scr.Vy;
91 				if (x + width + bw >= min_vx && x - bw < max_vx
92 						&& y + height + bw >= min_vy && y - bw < max_vy)
93 					subtract_rectangle_from_list (fr_data->list, x - bw, y - bw,
94 																				x + width + bw, y + height + bw);
95 			}
96 			get_current_canvas_geometry (asw->icon_canvas, &x, &y, &width,
97 																	 &height, &bw);
98 		} else
99 			get_current_canvas_geometry (asw->frame_canvas, &x, &y, &width,
100 																	 &height, &bw);
101 		x += Scr.Vx;
102 		y += Scr.Vy;
103 		LOCAL_DEBUG_OUT
104 				("frame_geom = %dx%d%+d%+d, h_limits = %d,%d; v_limits = %d,%d",
105 				 width, height, x - bw, y - bw, min_vx, max_vx, min_vy, max_vy);
106 		if (x + (int)width + (int)bw >= min_vx && x - (int)bw < max_vx
107 				&& y + (int)height + (int)bw >= min_vy && y - (int)bw < max_vy)
108 			subtract_rectangle_from_list (fr_data->list, x - (int)bw,
109 																		y - (int)bw, x + (int)width + (int)bw,
110 																		y + (int)height + (int)bw);
111 	}
112 
113 	return True;
114 }
115 
build_free_space_list(ASWindow * to_skip,ASGeometry * area,int min_layer,int max_layer)116 static ASVector *build_free_space_list (ASWindow * to_skip,
117 																				ASGeometry * area, int min_layer,
118 																				int max_layer)
119 {
120 	ASVector *list = create_asvector (sizeof (XRectangle));
121 	ASFreeRectangleAuxData aux_data;
122 	XRectangle seed_rect;
123 
124 	aux_data.to_skip = to_skip;
125 	aux_data.list = list;
126 	aux_data.desk = Scr.CurrentDesk;
127 	aux_data.min_layer = min_layer;
128 	aux_data.max_layer = max_layer;
129 	aux_data.area = *area;
130 
131 	/* must seed the list with the single rectangle representing the area : */
132 	seed_rect.x = area->x;
133 	seed_rect.y = area->y;
134 	seed_rect.width = area->width;
135 	seed_rect.height = area->height;
136 
137 	append_vector (list, &seed_rect, 1);
138 
139 	iterate_asbidirlist (Scr.Windows->clients, get_free_rectangles_iter_func,
140 											 (void *)&aux_data, NULL, False);
141 
142 #if defined(LOCAL_DEBUG) && !defined(NO_DEBUG_OUTPUT)
143 	print_rectangles_list (list);
144 #endif
145 
146 	return list;
147 }
148 
149 /*************************************************************************
150  * here we build the grid  to facilitate avoid cover and snap-to-grid
151  * while moving resizing window
152  *************************************************************************/
get_aswindow_grid_iter_func(void * data,void * aux_data)153 Bool get_aswindow_grid_iter_func (void *data, void *aux_data)
154 {
155 	ASWindow *asw = (ASWindow *) data;
156 	struct ASWindowGridAuxData *grid_data =
157 			(struct ASWindowGridAuxData *)aux_data;
158 
159 	if (asw
160 			&& (!IsValidDesk (grid_data->desk)
161 					|| ASWIN_DESK (asw) == grid_data->desk)) {
162 		int outer_gravity = Scr.Feel.EdgeAttractionWindow;
163 		int inner_gravity = Scr.Feel.EdgeAttractionWindow;
164 		if (ASWIN_HFLAGS (asw, AS_AvoidCover) && !grid_data->ignore_avoid_cover
165 				&& asw != grid_data->target)
166 			inner_gravity = -1;
167 		else if (inner_gravity == 0
168 						 || grid_data->min_layer > ASWIN_LAYER (asw))
169 			return True;
170 
171 		if (ASWIN_GET_FLAGS (asw, AS_Iconic)) {
172 			add_canvas_grid (grid_data->grid, asw->icon_canvas, outer_gravity,
173 											 inner_gravity, get_flags (Scr.Feel.flags,
174 																								 StickyIcons));
175 			if (asw->icon_canvas != asw->icon_title_canvas)
176 				add_canvas_grid (grid_data->grid, asw->icon_title_canvas,
177 												 outer_gravity, inner_gravity,
178 												 get_flags (Scr.Feel.flags, StickyIcons));
179 		} else {
180 			add_canvas_grid (grid_data->grid, asw->frame_canvas, outer_gravity,
181 											 inner_gravity, ASWIN_GET_FLAGS (asw, AS_Sticky));
182 			if (!grid_data->frame_only)
183 				add_canvas_grid (grid_data->grid, asw->client_canvas,
184 												 outer_gravity / 2, (inner_gravity * 2) / 3,
185 												 ASWIN_GET_FLAGS (asw, AS_Sticky));
186 		}
187 	}
188 	return True;
189 }
190 
make_desktop_grid(int desk,int min_layer,Bool frame_only,ASWindow * target)191 ASGrid *make_desktop_grid (int desk, int min_layer, Bool frame_only,
192 													 ASWindow * target)
193 {
194 	struct ASWindowGridAuxData grid_data;
195 	int resist = Scr.Feel.EdgeResistanceMove;
196 	int attract = Scr.Feel.EdgeAttractionScreen;
197 	int i;
198 	ASVector *free_space_list = NULL;
199 	XRectangle *rects = NULL;
200 	int w = target->status->width;
201 	int h = target->status->height;
202 	ASGeometry area;
203 
204 	grid_data.desk = desk;
205 	grid_data.min_layer = min_layer;
206 	grid_data.frame_only = frame_only;
207 	grid_data.grid = safecalloc (1, sizeof (ASGrid));
208 	grid_data.grid->curr_vx = Scr.Vx;
209 	grid_data.grid->curr_vy = Scr.Vy;
210 	grid_data.ignore_avoid_cover = True;
211 	grid_data.target = target;
212 #if 0
213 	area.x = vx;
214 	area.y = vy;
215 	area.width = Scr.MyDisplayWidth;
216 	area.height = Scr.MyDisplayHeight;
217 #else
218 	area.x = 0;
219 	area.y = 0;
220 	area.width = Scr.VxMax + Scr.MyDisplayWidth;
221 	area.height = Scr.VyMax + Scr.MyDisplayHeight;
222 #endif
223 	/* even though we are not limited to free space - it is best to avoid windows with AvoidCover
224 	 * bit set */
225 	free_space_list =
226 			build_free_space_list (target, &area, AS_LayerHighest,
227 														 AS_LayerHighest);
228 	rects = PVECTOR_HEAD (XRectangle, free_space_list);
229 
230 	i = PVECTOR_USED (free_space_list);
231 	/* now we need to find the biggest rectangle : */
232 	while (--i >= 0)
233 		if (rects[i].width >= w && rects[i].height >= h) {
234 			grid_data.ignore_avoid_cover = False;
235 			break;
236 		}
237 	destroy_asvector (&free_space_list);
238 
239 //    add_canvas_grid( grid_data.grid, Scr.RootCanvas, resist, attract, vx, vy );
240 
241 	add_gridline (grid_data.grid, 0, 0, Scr.MyDisplayWidth, resist, attract,
242 								ASGL_Absolute);
243 	add_gridline (grid_data.grid, Scr.MyDisplayHeight, 0, Scr.MyDisplayWidth,
244 								attract, resist, ASGL_Absolute);
245 	add_gridline (grid_data.grid, 0, 0, Scr.MyDisplayHeight, resist, attract,
246 								ASGL_Absolute | ASGL_Vertical);
247 	add_gridline (grid_data.grid, Scr.MyDisplayWidth, 0, Scr.MyDisplayHeight,
248 								attract, resist, ASGL_Absolute | ASGL_Vertical);
249 
250 	/* add all the window edges for this desktop : */
251 	iterate_asbidirlist (Scr.Windows->clients, get_aswindow_grid_iter_func,
252 											 (void *)&grid_data, NULL, False);
253 
254 #if defined(LOCAL_DEBUG) && !defined(NO_DEBUG_OUTPUT)
255 	print_asgrid (grid_data.grid);
256 #endif
257 
258 	return grid_data.grid;
259 }
260 
setup_aswindow_moveresize(ASWindow * asw,struct ASMoveResizeData * mvrdata)261 void setup_aswindow_moveresize (ASWindow * asw,
262 																struct ASMoveResizeData *mvrdata)
263 {
264 	if (asw->frame_data && asw->tbar) {
265 		if (asw->frame_data->condense_titlebar !=
266 				NO_ALIGN /* && mvrdata->move_only  */ ) {
267 			if (ASWIN_HFLAGS (asw, AS_VerticalTitle))
268 				mvrdata->title_west = asw->tbar->width;
269 			else
270 				mvrdata->title_north = asw->tbar->height;
271 		}
272 	}
273 	raise_scren_panframes (ASDefaultScr);
274 	mvrdata->below_sibling = get_lowest_panframe (ASDefaultScr);
275 	set_moveresize_restrains (mvrdata, asw->hints, asw->status);
276 	mvrdata->grid =
277 			make_desktop_grid (Scr.CurrentDesk, AS_LayerDesktop, False, asw);
278 	Scr.moveresize_in_progress = mvrdata;
279 }
280 
apply_aswindow_moveresize(struct ASMoveResizeData * data)281 void apply_aswindow_moveresize (struct ASMoveResizeData *data)
282 {
283 	ASWindow *asw = window2ASWindow (AS_WIDGET_WINDOW (data->mr));
284 	LOCAL_DEBUG_OUT ("%dx%d%+d%+d", data->curr.width, data->curr.height,
285 									 data->curr.x, data->curr.y);
286 	if (asw && !ASWIN_GET_FLAGS (asw, AS_Dead)) {
287 		int new_width = data->curr.width;
288 		int new_height = data->curr.height;
289 		Bool server_grabbed = False;
290 		if (ASWIN_GET_FLAGS (asw, AS_Shaded)) {
291 			new_width = asw->status->width;
292 			new_height = asw->status->height;
293 #if 0
294 			/* lets only move us as we are in shaded state : */
295 			move_canvas (asw->frame_canvas, data->curr.x, data->curr.y);
296 		} else {
297 			if (data->curr.width != data->last.width ||
298 					data->curr.height != data->last.height) {
299 				int client_width =
300 						data->curr.width - (asw->frame_canvas->width -
301 																asw->client_canvas->width);
302 				int client_height =
303 						data->curr.height - (asw->frame_canvas->height -
304 																 asw->client_canvas->height);
305 				XGrabServer (dpy);
306 				server_grabbed = True;
307 				resize_canvas (asw->client_canvas, client_width, client_height);
308 			}
309 			moveresize_canvas (asw->frame_canvas, data->curr.x, data->curr.y,
310 												 data->curr.width, data->curr.height);
311 			ASSync (False);
312 #endif
313 		}
314 		if (ASWIN_GET_FLAGS (asw, AS_ShapedDecor | AS_Shaped) && (data->curr.width > data->last.width || data->curr.height > data->last.height)) {	/* this greately reduces flickering on resizing of shaped windows : */
315 			XRectangle rect;
316 			rect.x = 0;
317 			rect.y = 0;
318 			moveresize_canvas (asw->frame_canvas, data->curr.x, data->curr.y,
319 												 data->curr.width, data->curr.height);
320 			if (data->curr.width > data->last.width) {
321 				if (get_flags (asw->frame_data->condense_titlebar, ALIGN_LEFT)
322 						&& asw->tbar)
323 					rect.y = asw->tbar->height;
324 				rect.width = data->curr.width - data->last.width;
325 				rect.height = (int)data->last.height - rect.y;
326 				XShapeCombineRectangles (dpy, asw->frame, ShapeBounding,
327 																 data->last.width, 0, &rect, 1, ShapeUnion,
328 																 Unsorted);
329 			}
330 			if (data->curr.height > data->last.height) {
331 				if (get_flags (asw->frame_data->condense_titlebar, ALIGN_RIGHT)
332 						&& asw->tbar)
333 					rect.x = asw->tbar->width;
334 				rect.width = (int)data->curr.width - rect.x;
335 				rect.height = data->curr.height - data->last.height;
336 				XShapeCombineRectangles (dpy, asw->frame, ShapeBounding,
337 																 0, data->last.height, &rect, 1,
338 																 ShapeUnion, Unsorted);
339 			}
340 		}
341 		moveresize_aswindow_wm (asw, data->curr.x, data->curr.y, new_width,
342 														new_height, False);
343 		if (server_grabbed)
344 			XUngrabServer (dpy);
345 	}
346 }
347 
apply_aswindow_move(struct ASMoveResizeData * data)348 void apply_aswindow_move (struct ASMoveResizeData *data)
349 {
350 	ASWindow *asw = window2ASWindow (AS_WIDGET_WINDOW (data->mr));
351 	LOCAL_DEBUG_OUT ("%dx%d%+d%+d", asw->status->width, asw->status->height,
352 									 data->curr.x, data->curr.y);
353 	if (asw && !ASWIN_GET_FLAGS (asw, AS_Dead)) {
354 		/* lets only move us as we maybe in shaded state : */
355 		move_canvas (asw->frame_canvas, data->curr.x, data->curr.y);
356 		ASSync (False);
357 		moveresize_aswindow_wm (asw, data->curr.x, data->curr.y,
358 														asw->status->width, asw->status->height,
359 														False);
360 	}
361 }
362 
complete_aswindow_moveresize(struct ASMoveResizeData * data,Bool cancelled)363 void complete_aswindow_moveresize (struct ASMoveResizeData *data,
364 																	 Bool cancelled)
365 {
366 	ASWindow *asw = window2ASWindow (AS_WIDGET_WINDOW (data->mr));
367 	if (asw && !ASWIN_GET_FLAGS (asw, AS_Dead)) {
368 		if (cancelled) {
369 			SHOW_CHECKPOINT;
370 			LOCAL_DEBUG_OUT ("%dx%d%+d%+d", data->start.width,
371 											 data->start.height, data->start.x, data->start.y);
372 			moveresize_aswindow_wm (asw, data->start.x, data->start.y,
373 															data->start.width, data->start.height,
374 															False);
375 		} else {
376 			SHOW_CHECKPOINT;
377 			LOCAL_DEBUG_OUT ("%dx%d%+d%+d", data->curr.width, data->curr.height,
378 											 data->curr.x, data->curr.y);
379 			moveresize_aswindow_wm (asw, data->curr.x, data->curr.y,
380 															data->curr.width, data->curr.height, False);
381 		}
382 		ASWIN_CLEAR_FLAGS (asw, AS_MoveresizeInProgress);
383 		asw->frame_canvas->root_x = -10000;
384 		asw->frame_canvas->root_y = -10000;
385 		asw->frame_canvas->width = 1;
386 		asw->frame_canvas->height = 1;
387 
388 		on_window_moveresize (asw, asw->frame);
389 		broadcast_config (M_CONFIGURE_WINDOW, asw);
390 	}
391 	Scr.moveresize_in_progress = NULL;
392 }
393 
complete_aswindow_move(struct ASMoveResizeData * data,Bool cancelled)394 void complete_aswindow_move (struct ASMoveResizeData *data, Bool cancelled)
395 {
396 	ASWindow *asw = window2ASWindow (AS_WIDGET_WINDOW (data->mr));
397 	if (asw && !ASWIN_GET_FLAGS (asw, AS_Dead)) {
398 		if (cancelled) {
399 			SHOW_CHECKPOINT;
400 			LOCAL_DEBUG_OUT ("%dx%d%+d%+d", data->start.width,
401 											 data->start.height, data->start.x, data->start.y);
402 			moveresize_aswindow_wm (asw, data->start.x, data->start.y,
403 															data->start.width, data->start.height,
404 															False);
405 		} else {
406 			SHOW_CHECKPOINT;
407 			LOCAL_DEBUG_OUT ("%dx%d%+d%+d", data->start.width,
408 											 data->start.height, data->curr.x, data->curr.y);
409 			moveresize_aswindow_wm (asw, data->curr.x, data->curr.y,
410 															data->start.width, data->start.height,
411 															False);
412 		}
413 
414 		ASWIN_CLEAR_FLAGS (asw, AS_MoveresizeInProgress);
415 		asw->frame_canvas->root_x = -10000;
416 		asw->frame_canvas->root_y = -10000;
417 		on_window_moveresize (asw, asw->frame);
418 		broadcast_config (M_CONFIGURE_WINDOW, asw);
419 	}
420 	Scr.moveresize_in_progress = NULL;
421 }
422 
423 /*************************************************************************/
424 /* placement routines : */
425 /*************************************************************************/
426 static void
apply_placement_result(ASStatusHints * status,XRectangle * anchor,ASHints * hints,ASFlagType flags,int vx,int vy,unsigned int width,unsigned int height)427 apply_placement_result (ASStatusHints * status, XRectangle * anchor,
428 												ASHints * hints, ASFlagType flags, int vx, int vy,
429 												unsigned int width, unsigned int height)
430 {
431 #define apply_placement_result_asw(asw,flags,vx,vy,width,height)  apply_placement_result((asw)->status, &((asw)->anchor), (asw)->hints, flags, vx, vy, width, height )
432 
433 	if (get_flags (flags, XValue)) {
434 		status->x = vx;
435 		if (!get_flags (status->flags, AS_Sticky))
436 			status->x -= status->viewport_x;
437 		else
438 			status->x -= Scr.Vx;
439 	}
440 	if (get_flags (flags, YValue)) {
441 		status->y = vy;
442 		if (!get_flags (status->flags, AS_Sticky))
443 			status->y -= status->viewport_y;
444 		else
445 			status->y -= Scr.Vy;
446 	}
447 	if (get_flags (flags, WidthValue) && width > 0)
448 		status->width = width;
449 
450 	if (get_flags (flags, HeightValue) && height > 0)
451 		status->height = height;
452 
453 	status2anchor (anchor, hints, status, Scr.VxMax + Scr.MyDisplayWidth,
454 								 Scr.VyMax + Scr.MyDisplayHeight);
455 }
456 
457 static int
move_placement_left(ASVector * free_space_list,int x,int y,int w,int h)458 move_placement_left (ASVector * free_space_list, int x, int y, int w,
459 										 int h)
460 {
461 	XRectangle *rects = PVECTOR_HEAD (XRectangle, free_space_list);
462 	int i = PVECTOR_USED (free_space_list);
463 	while (--i >= 0)
464 		if (y >= rects[i].y && y + h <= rects[i].y + (int)rects[i].height
465 				&& rects[i].x < x && rects[i].x + (int)rects[i].width >= x)
466 			x = rects[i].x;
467 	return x;
468 }
469 
470 static int
move_placement_right(ASVector * free_space_list,int x,int y,int w,int h)471 move_placement_right (ASVector * free_space_list, int x, int y, int w,
472 											int h)
473 {
474 	XRectangle *rects = PVECTOR_HEAD (XRectangle, free_space_list);
475 	int i = PVECTOR_USED (free_space_list);
476 	while (--i >= 0)
477 		if (y >= rects[i].y && y + h <= rects[i].y + (int)rects[i].height
478 				&& rects[i].x <= x + w && rects[i].x + (int)rects[i].width > x + w)
479 			x = rects[i].x + (int)rects[i].width - w;
480 	return x;
481 }
482 
483 static int
move_placement_up(ASVector * free_space_list,int x,int y,int w,int h)484 move_placement_up (ASVector * free_space_list, int x, int y, int w, int h)
485 {
486 	XRectangle *rects = PVECTOR_HEAD (XRectangle, free_space_list);
487 	int i = PVECTOR_USED (free_space_list);
488 	while (--i >= 0)
489 		if (x >= rects[i].x && x + w <= rects[i].x + (int)rects[i].width
490 				&& rects[i].y < y && rects[i].y + (int)rects[i].height >= y)
491 			y = rects[i].y;
492 	return y;
493 }
494 
495 static int
move_placement_down(ASVector * free_space_list,int x,int y,int w,int h)496 move_placement_down (ASVector * free_space_list, int x, int y, int w,
497 										 int h)
498 {
499 	XRectangle *rects = PVECTOR_HEAD (XRectangle, free_space_list);
500 	int i = PVECTOR_USED (free_space_list);
501 	while (--i >= 0)
502 		if (x >= rects[i].x && x + w <= rects[i].x + (int)rects[i].width
503 				&& rects[i].y <= y + h
504 				&& rects[i].y + (int)rects[i].height > y + h)
505 			y = rects[i].y + (int)rects[i].height - h;
506 	return y;
507 }
508 
do_smart_placement(ASWindow * asw,ASWindowBox * aswbox,ASGeometry * area)509 static Bool do_smart_placement (ASWindow * asw, ASWindowBox * aswbox,
510 																ASGeometry * area)
511 {
512 	ASVector *free_space_list =
513 			build_free_space_list (asw, area, ASWIN_LAYER (asw),
514 														 AS_LayerHighest);
515 	XRectangle *rects = PVECTOR_HEAD (XRectangle, free_space_list);
516 	int i, selected = -1;
517 	unsigned short w = asw->status->width;
518 	unsigned short h = asw->status->height;
519 	unsigned short dw = w > 100 ? w * 5 / 100 : 5, dh =
520 			h >= 100 ? h * 5 / 100 : 5;
521 	int spacer_x = -1;
522 	int spacer_y = -1;
523 
524 	LOCAL_DEBUG_OUT ("size=%dx%d, delta=%dx%d", w, h, dw, dh);
525 	/* now we have to find the optimal rectangle from the list */
526 	/* pass 1: find rectangle that fits both width and height with margin +- 5% of the window size */
527 	i = PVECTOR_USED (free_space_list);
528 	while (--i >= 0)
529 		if (rects[i].width >= w && rects[i].height >= h &&
530 				rects[i].width - w < dw && rects[i].height - h < dh) {
531 			if (selected >= 0)
532 				if (rects[i].width * rects[i].height >=
533 						rects[selected].width * rects[selected].height)
534 					continue;
535 			selected = i;
536 		}
537 	LOCAL_DEBUG_OUT ("pass1: %d", selected);
538 
539 	if (selected < 0) {
540 		i = PVECTOR_USED (free_space_list);
541 		if (w > 200 && h > 200) {		/* simply find the biggest rectangle that fits  */
542 			while (--i >= 0)
543 				if (rects[i].width >= w && rects[i].height >= h) {
544 					if (selected >= 0)
545 						if (rects[i].width * rects[i].height <=
546 								rects[selected].width * rects[selected].height)
547 							continue;
548 					selected = i;
549 				}
550 			LOCAL_DEBUG_OUT ("pass2a: %d", selected);
551 		} else if (w > h) {					/* try and fit it by the horizontal edge of the screen */
552 			while (--i >= 0)
553 				if (rects[i].width >= w && rects[i].height >= h &&
554 						(rects[i].y < 100
555 						 || rects[i].y + rects[i].height >
556 						 area->y + area->height - 100)) {
557 					selected = i;
558 					if (rects[i].y >= 100)
559 						spacer_y = rects[i].height - h;
560 					break;
561 				}
562 			LOCAL_DEBUG_OUT ("pass2b: %d", selected);
563 		} else {
564 			/* try and fit it by the vertical edge of the screen */
565 			while (--i >= 0)
566 				if (rects[i].width >= w && rects[i].height >= h &&
567 						(rects[i].x < 100
568 						 || rects[i].x + rects[i].width >
569 						 area->x + area->width - 100)) {
570 					selected = i;
571 					if (rects[i].x >= 100)
572 						spacer_x = rects[i].width - w;
573 					break;
574 				}
575 			LOCAL_DEBUG_OUT ("pass2c: %d", selected);
576 		}
577 	}
578 	/* if width < height then swap passes 2 and 3 */
579 	/* pass 2: find rectangle that fits width within margin +- 5% of the window size  and has maximum height
580 	 * left after placement */
581 	if (selected < 0) {
582 		i = PVECTOR_USED (free_space_list);
583 		if (w >= h) {
584 			while (--i >= 0)
585 				if (rects[i].width >= w && rects[i].height >= h
586 						&& rects[i].width - w < dw) {
587 					if (selected >= 0)
588 						if (rects[i].height < rects[selected].height)
589 							continue;
590 					selected = i;
591 				}
592 		} else {
593 			while (--i >= 0)
594 				if (rects[i].width >= w && rects[i].height >= h
595 						&& rects[i].height - h < dh) {
596 					if (selected >= 0)
597 						if (rects[i].width < rects[selected].width)
598 							continue;
599 					selected = i;
600 				}
601 		}
602 	}
603 	LOCAL_DEBUG_OUT ("pass2: %d", selected);
604 	/* pass 3: find rectangle that fits height within margin +- 5% of the window size  and has maximum width
605 	 * left after placement */
606 	if (selected < 0) {
607 		i = PVECTOR_USED (free_space_list);
608 		if (w >= h) {
609 			while (--i >= 0)
610 				if (rects[i].width >= w && rects[i].height >= h
611 						&& rects[i].height - h < dh) {
612 					if (selected >= 0)
613 						if (rects[i].width < rects[selected].width)
614 							continue;
615 					selected = i;
616 				}
617 		} else {
618 			while (--i >= 0)
619 				if (rects[i].width >= w && rects[i].height >= h
620 						&& rects[i].width - w < dw) {
621 					if (selected >= 0)
622 						if (rects[i].height < rects[selected].height)
623 							continue;
624 					selected = i;
625 				}
626 		}
627 	}
628 	LOCAL_DEBUG_OUT ("pass3: %d", selected);
629 	/* pass 4: if width >= height then find rectangle with smallest width difference and largest height difference */
630 	if (selected < 0 && w >= h) {
631 		i = PVECTOR_USED (free_space_list);
632 		while (--i >= 0)
633 			if (rects[i].width >= w && rects[i].height >= h) {
634 				selected = i;
635 				break;
636 			}
637 		while (--i >= 0)
638 			if (rects[i].width >= w && rects[i].height >= h) {
639 				int dw = (rects[i].width > w) ? rects[i].width - w : 1;
640 				int dw_sel =
641 						(rects[selected].width > w) ? rects[selected].width - w : 1;
642 				if (((rects[i].height - h) * Scr.MyDisplayWidth) / dw >
643 						((rects[selected].height - h) * Scr.MyDisplayWidth) / dw_sel)
644 					selected = i;
645 			}
646 	}
647 	LOCAL_DEBUG_OUT ("pass4: %d", selected);
648 	/* pass 5: if width < height then find rectangle with biggest width difference and smallest height difference */
649 	if (selected < 0) {
650 		i = PVECTOR_USED (free_space_list);
651 		while (--i >= 0)
652 			if (rects[i].width >= w && rects[i].height >= h) {
653 				selected = i;
654 				break;
655 			}
656 		while (--i >= 0)
657 			if (rects[i].width >= w && rects[i].height >= h) {
658 				int dh = (rects[i].height > h) ? rects[i].height - h : 1;
659 				int dh_sel =
660 						(rects[selected].height > h) ? rects[selected].height - h : 1;
661 				if (((rects[i].width - w) * Scr.MyDisplayHeight) / dh >
662 						((rects[selected].width - w) * Scr.MyDisplayHeight) / dh_sel)
663 					selected = i;
664 			}
665 	}
666 	LOCAL_DEBUG_OUT ("pass5: %d", selected);
667 
668 	if (selected >= 0) {
669 		int target_x, target_y;
670 		int dx, dy;
671 		int move_left, move_up;
672 		Bool changed;
673 		if (spacer_x < 0) {
674 			spacer_x = 0;
675 			if (rects[selected].width > w) {
676 				int to_right =
677 						(area->x + (int)area->width) - (rects[selected].x +
678 																						(int)rects[selected].width);
679 				if (to_right < rects[selected].x - area->x)
680 					spacer_x = (int)rects[selected].width - (int)w;
681 			}
682 		}
683 		if (spacer_y < 0) {
684 			spacer_y = 0;
685 			if (rects[selected].height > h) {
686 				int to_bottom =
687 						(area->y + (int)area->height) - (rects[selected].y +
688 																						 (int)rects[selected].height);
689 				if (to_bottom < rects[selected].y - area->y)
690 					spacer_y = (int)rects[selected].height - (int)h;
691 			}
692 		}
693 		target_x = rects[selected].x + spacer_x;
694 		target_y = rects[selected].y + spacer_y;
695 
696 		do {
697 			int new_x = target_x, new_y = target_y;
698 			changed = False;
699 			dx = target_x - area->x;
700 			dy = target_y - area->y;
701 
702 			move_left = (dx < area->width - (dx + w));
703 			if (!move_left)
704 				dx = area->width - (dx + w);
705 
706 			move_up = (dy < area->height - (dy + h));
707 			if (!move_up)
708 				dy = area->height - (dy + h);
709 			/* we want to place window as close as possible to the edge of the area */
710 			if (dx > dy) {
711 				if (move_left)
712 					new_x =
713 							move_placement_left (free_space_list, target_x, target_y, w,
714 																	 h);
715 				else
716 					new_x =
717 							move_placement_right (free_space_list, target_x, target_y, w,
718 																		h);
719 				if (dy > 0) {
720 					if (move_up)
721 						new_y =
722 								move_placement_up (free_space_list, target_x, target_y, w,
723 																	 h);
724 					else
725 						new_y =
726 								move_placement_down (free_space_list, target_x, target_y,
727 																		 w, h);
728 				}
729 
730 			} else if (dy > 0) {
731 				if (move_up)
732 					new_y =
733 							move_placement_up (free_space_list, target_x, target_y, w,
734 																 h);
735 				else
736 					new_y =
737 							move_placement_down (free_space_list, target_x, target_y, w,
738 																	 h);
739 				if (dx > 0) {
740 					if (move_left)
741 						new_x =
742 								move_placement_left (free_space_list, target_x, target_y,
743 																		 w, h);
744 					else
745 						new_x =
746 								move_placement_right (free_space_list, target_x, target_y,
747 																			w, h);
748 				}
749 			}
750 			LOCAL_DEBUG_OUT
751 					("move_left = %d, move_up = %d, new = %+d%+d, org = %+d%+d",
752 					 move_left, move_up, new_x, new_y, target_x, target_y);
753 			changed = (target_x != new_x || target_y != new_y);
754 			target_x = new_x;
755 			target_y = new_y;
756 		} while (changed);
757 		apply_placement_result_asw (asw, XValue | YValue, target_x, target_y,
758 																0, 0);
759 		LOCAL_DEBUG_OUT ("success: status(%+d%+d), anchor(%+d,%+d)",
760 										 asw->status->x, asw->status->y, asw->anchor.x,
761 										 asw->anchor.y);
762 	} else {
763 		LOCAL_DEBUG_OUT ("failed%s", "");
764 	}
765 
766 	destroy_asvector (&free_space_list);
767 	return (selected >= 0);
768 }
769 
do_random_placement(ASWindow * asw,ASWindowBox * aswbox,ASGeometry * area,Bool free_space_only)770 static Bool do_random_placement (ASWindow * asw, ASWindowBox * aswbox,
771 																 ASGeometry * area, Bool free_space_only)
772 {
773 	int selected = -1;
774 	unsigned int w = asw->status->width;
775 	unsigned int h = asw->status->height;
776 	static CARD32 rnd32_seed = 345824357;
777 	ASVector *free_space_list = NULL;
778 	XRectangle *rects = NULL;
779 	int i;
780 	long selected_deficiency = 1000000000;
781 
782 #ifndef MY_RND32
783 #define MAX_MY_RND32		0x00ffffffff
784 #ifdef WORD64
785 #define MY_RND32() (rnd32_seed = ((1664525L*rnd32_seed)&MAX_MY_RND32)+1013904223L)
786 #else
787 #define MY_RND32() (rnd32_seed = (1664525L*rnd32_seed)+1013904223L)
788 #endif
789 #endif
790 
791 	if (rnd32_seed == 345824357)
792 		rnd32_seed += time (NULL);
793 
794 	/* even though we are not limited to free space - it is best to avoid windows with AvoidCover
795 	 * bit set */
796 	free_space_list = build_free_space_list (asw, area,
797 																					 free_space_only ?
798 																					 ASWIN_LAYER (asw) :
799 																					 AS_LayerHighest,
800 																					 AS_LayerHighest);
801 	rects = PVECTOR_HEAD (XRectangle, free_space_list);
802 
803 	i = PVECTOR_USED (free_space_list);
804 	while (--i >= 0) {
805 		if (rects[i].width >= w && rects[i].height >= h) {
806 			selected_deficiency = 0;
807 			if (selected >= 0) {
808 				CARD32 r = MY_RND32 ();
809 				if ((r & 0x00000100) == 0)
810 					continue;;
811 
812 			}
813 			selected = i;
814 		} else if (selected_deficiency > 0) {
815 			int deficiency = 0;
816 			if (rects[i].width < w)
817 				deficiency += h * (w - rects[i].width);
818 			if (rects[i].height < h) {
819 				deficiency += w * (h - rects[i].height);
820 				if (rects[i].width < w)
821 					deficiency -= (w - rects[i].width) * (h - rects[i].height);
822 			}
823 #if 0
824 			/* we may use it if we are required to place window, so we can
825 			 * select the largest area available. But ordinarily we should
826 			 * default to manuall placement instead! : */
827 			if (deficiency < selected_deficiency || selected < 0) {
828 				selected = i;
829 				selected_deficiency = deficiency;
830 			}
831 #endif
832 		}
833 	}
834 	if (selected >= 0) {
835 		unsigned int new_x = 0, new_y = 0;
836 		if (rects[selected].width > w) {
837 			new_x = MY_RND32 ();
838 			new_x = (new_x % (rects[selected].width - w));
839 		}
840 
841 		if (rects[selected].height > h) {
842 			new_y = MY_RND32 ();
843 			new_y = (new_y % (rects[selected].height - h));
844 		}
845 		LOCAL_DEBUG_OUT ("rect %dx%d%+d%+d, new_pos = %+d%+d",
846 										 rects[selected].width, rects[selected].height,
847 										 rects[selected].x, rects[selected].y, new_x, new_y);
848 		apply_placement_result_asw (asw, XValue | YValue,
849 																rects[selected].x + new_x,
850 																rects[selected].y + new_y, 0, 0);
851 		LOCAL_DEBUG_OUT ("success: status(%+d%+d), anchor(%+d,%+d)",
852 										 asw->status->x, asw->status->y, asw->anchor.x,
853 										 asw->anchor.y);
854 	} else {
855 		LOCAL_DEBUG_OUT ("failed%s", "");
856 	}
857 
858 	destroy_asvector (&free_space_list);
859 	return (selected >= 0);
860 }
861 
862 static Bool
do_maximized_placement(ASWindow * asw,ASWindowBox * aswbox,ASGeometry * area)863 do_maximized_placement (ASWindow * asw, ASWindowBox * aswbox,
864 												ASGeometry * area)
865 {
866 	int selected = -1;
867 	unsigned int w = asw->status->width;
868 	unsigned int h = asw->status->height;
869 #ifdef HAVE_XINERAMA
870 	unsigned int x = asw->status->x;
871 	unsigned int y = asw->status->y;
872 #endif
873 	ASVector *free_space_list = NULL;
874 	XRectangle *rects = NULL;
875 	int i;
876 
877 	/* even though we are not limited to free space - it is best to avoid windows with AvoidCover
878 	 * bit set */
879 	free_space_list =
880 			build_free_space_list (asw, area, AS_LayerHighest, AS_LayerHighest);
881 	rects = PVECTOR_HEAD (XRectangle, free_space_list);
882 
883 	i = PVECTOR_USED (free_space_list);
884 	/* now we need to find the biggest rectangle : */
885 	while (--i >= 0)
886 		if (rects[i].width >= w && rects[i].height >= h) {
887 			/* if a rect has been selected */
888 			if (selected > 0) {
889 				/* if this rect is smaller than the selected one */
890 				if (rects[i].width * rects[i].height <
891 						rects[selected].width * rects[selected].height)
892 					continue;
893 			}
894 			/* select this rectangle because it's bigger */
895 			selected = i;
896 		}
897 
898 
899 	/* if a rect has NOT been selected */
900 	if (selected < 0) {						/* we simply select the biggest area available : */
901 		i = PVECTOR_USED (free_space_list);
902 		while (--i >= 0) {
903 			if (selected > 0) {
904 				if (rects[i].width * rects[i].height <
905 						rects[selected].width * rects[selected].height)
906 					continue;
907 			}
908 			selected = i;
909 		}
910 	}
911 
912 
913 	if (selected >= 0) {
914 		ASFlagType flags = 0;
915 		int max_width = rects[selected].width;
916 		int max_height = rects[selected].height;
917 
918 #ifdef HAVE_XINERAMA
919 		/* the following block makes sure windows
920 		   are not maximized over multiply heads. */
921 
922 		int i;
923 		XRectangle *s = Scr.xinerama_screens;
924 		int dest_size = -1;
925 		int dest_rect = 0;
926 		int inter_width;
927 		int inter_height;
928 
929 		if (s != NULL) {
930 
931 			/* select the xinerama-screen holding most of the
932 			   window as it is before maximizing it */
933 			for (i = 0; i < Scr.xinerama_screens_num; ++i) {
934 				/* if window is not on this xin-rect at all. */
935 				if ((x < s[i].x && x > s[i].x + s[i].width) ||
936 						(y < s[i].y && y > s[i].y + s[i].height))
937 					continue;
938 
939 				/* window starts left of screen */
940 				if (s[i].x > x)
941 					/* and ends on the screen */
942 					if (s[i].x + s[i].width > x + w)
943 						inter_width = x + w - s[i].x;
944 					else
945 						inter_width = s[i].width;
946 				else if (s[i].x + s[i].width > x + w)
947 					inter_width = s[i].width;
948 				else
949 					inter_width = s[i].x + s[i].width - x;
950 
951 
952 				/* window starts above of screen */
953 				if (s[i].y > y)
954 					/* and ends on the screen */
955 					if (s[i].y + s[i].height > y + h)
956 						inter_height = y + h - s[i].y;
957 					else
958 						inter_height = s[i].height;
959 				else if (s[i].y + s[i].height > y + h)
960 					inter_height = s[i].height;
961 				else
962 					inter_height = s[i].y + s[i].height - y;
963 
964 				if (inter_width * inter_height > dest_size) {
965 					/* I like this rect better than the last. */
966 					dest_rect = i;
967 					dest_size = inter_width * inter_height;
968 				}
969 
970 
971 			}
972 
973 
974 			if (rects[selected].x < s[dest_rect].x)
975 				rects[selected].x = s[dest_rect].x;
976 			if (rects[selected].y < s[dest_rect].y)
977 				rects[selected].y = s[dest_rect].y;
978 			if (max_width > s[dest_rect].width)
979 				max_width = s[dest_rect].width;
980 			if (max_height > s[dest_rect].height)
981 				max_height = s[dest_rect].height;
982 		}
983 #endif													/* XINERAMA */
984 
985 
986 		save_aswindow_anchor (asw, ASWIN_GET_FLAGS (asw, AS_MaximizedX),
987 													ASWIN_GET_FLAGS (asw, AS_MaximizedY));
988 
989 		if (ASWIN_GET_FLAGS (asw, AS_MaximizedX))
990 			set_flags (flags, XValue | WidthValue);
991 		if (ASWIN_GET_FLAGS (asw, AS_MaximizedY))
992 			set_flags (flags, YValue | HeightValue);
993 
994 		if (asw->maximize_ratio_x > 0)
995 			max_width = (asw->maximize_ratio_x * max_width) / 100;
996 		if (asw->maximize_ratio_y > 0)
997 			max_height = (asw->maximize_ratio_y * max_height) / 100;
998 
999 		apply_placement_result_asw (asw, flags, rects[selected].x,
1000 																rects[selected].y, max_width, max_height);
1001 		LOCAL_DEBUG_OUT ("success: status(%+d%+d), anchor(%+d,%+d)",
1002 										 asw->status->x, asw->status->y, asw->anchor.x,
1003 										 asw->anchor.y);
1004 	} else {
1005 		LOCAL_DEBUG_OUT ("failed%s", "");
1006 	}
1007 
1008 	destroy_asvector (&free_space_list);
1009 	return (selected >= 0);
1010 }
1011 
1012 
1013 
do_tile_placement(ASWindow * asw,ASWindowBox * aswbox,ASGeometry * area)1014 static Bool do_tile_placement (ASWindow * asw, ASWindowBox * aswbox,
1015 															 ASGeometry * area)
1016 {
1017 	int selected = -1;
1018 	unsigned short w = asw->status->width;
1019 	unsigned short h = asw->status->height;
1020 	ASVector *free_space_list = NULL;
1021 	XRectangle *rects = NULL;
1022 	int i;
1023 
1024 	free_space_list =
1025 			build_free_space_list (asw, area, ASWIN_LAYER (asw),
1026 														 AS_LayerHighest);
1027 	rects = PVECTOR_HEAD (XRectangle, free_space_list);
1028 
1029 	i = PVECTOR_USED (free_space_list);
1030 	while (--i >= 0)
1031 		if (rects[i].width >= w && rects[i].height >= h) {
1032 			if (selected > 0) {
1033 				if (get_flags (aswbox->flags, ASA_VerticalPriority)) {
1034 					if (get_flags (aswbox->flags, ASA_ReverseOrder)
1035 							|| get_flags (aswbox->flags, ASA_ReverseOrderH)) {
1036 						if (rects[selected].x > rects[i].x)
1037 							continue;
1038 						if (rects[selected].x == rects[i].x
1039 								&& rects[selected].y > rects[i].y)
1040 							continue;
1041 					} else {
1042 						if (rects[selected].x < rects[i].x)
1043 							continue;
1044 						if (rects[selected].x == rects[i].x
1045 								&& rects[selected].y < rects[i].y)
1046 							continue;
1047 					}
1048 				} else if (get_flags (aswbox->flags, ASA_ReverseOrder)
1049 									 || get_flags (aswbox->flags, ASA_ReverseOrderV)) {
1050 					if (rects[selected].y > rects[i].y)
1051 						continue;
1052 					if (rects[selected].y == rects[i].y
1053 							&& rects[selected].x > rects[i].x)
1054 						continue;
1055 				} else {
1056 					if (rects[selected].y < rects[i].y)
1057 						continue;
1058 					if (rects[selected].y == rects[i].y
1059 							&& rects[selected].x < rects[i].x)
1060 						continue;
1061 				}
1062 
1063 			}
1064 			selected = i;
1065 		}
1066 
1067 	if (selected >= 0) {
1068 		int spacer_x = aswbox->x_spacing;
1069 		int spacer_y = aswbox->y_spacing;
1070 		if (rects[selected].width < w + spacer_x)
1071 			spacer_x = rects[selected].width - w;
1072 		if (rects[selected].height < h + spacer_y)
1073 			spacer_y = rects[selected].height - h;
1074 		apply_placement_result_asw (asw, XValue | YValue,
1075 																rects[selected].x + spacer_x,
1076 																rects[selected].y + spacer_y, 0, 0);
1077 		LOCAL_DEBUG_OUT ("success: status(%+d%+d), anchor(%+d,%+d)",
1078 										 asw->status->x, asw->status->y, asw->anchor.x,
1079 										 asw->anchor.y);
1080 	} else {
1081 		LOCAL_DEBUG_OUT ("failed%s", "");
1082 	}
1083 
1084 	destroy_asvector (&free_space_list);
1085 	return (selected >= 0);
1086 }
1087 
do_cascade_placement(ASWindow * asw,ASWindowBox * aswbox,ASGeometry * area)1088 static Bool do_cascade_placement (ASWindow * asw, ASWindowBox * aswbox,
1089 																	ASGeometry * area)
1090 {
1091 	int newpos = aswbox->cascade_pos + 25;
1092 	int x = newpos, y = newpos;
1093 
1094 	if (get_flags (aswbox->flags, ASA_ReverseOrder) ||
1095 			(get_flags (aswbox->flags, ASA_ReverseOrderV) &&
1096 			 get_flags (aswbox->flags, ASA_ReverseOrderH))) {
1097 		x = ((int)(area->width) + area->x) - newpos;
1098 		y = ((int)(area->height) + area->y) - newpos;
1099 	} else if (get_flags (aswbox->flags, ASA_ReverseOrderV)) {
1100 		x = newpos + area->x;
1101 		y = ((int)(area->height) + area->y) - newpos;
1102 	} else if (get_flags (aswbox->flags, ASA_ReverseOrderH)) {
1103 		x = ((int)(area->width) + area->x) - newpos;
1104 		y = newpos + area->y;
1105 	} else {
1106 		x = newpos + area->x;
1107 		y = newpos + area->y;
1108 	}
1109 
1110 	if (x + asw->status->width > area->x + area->width)
1111 		x = (area->x + area->width - asw->status->width);
1112 	if (y + asw->status->height > area->y + area->height)
1113 		y = (area->y + area->height - asw->status->height);
1114 
1115 	asw->status->x = x - asw->status->viewport_x;
1116 	asw->status->y = y - asw->status->viewport_y;
1117 
1118 	aswbox->cascade_pos = newpos;
1119 
1120 	apply_placement_result_asw (asw, XValue | YValue, x, y, 0, 0);
1121 
1122 	return True;
1123 }
1124 
1125 
do_manual_placement(ASWindow * asw,ASWindowBox * aswbox,ASGeometry * area)1126 static Bool do_manual_placement (ASWindow * asw, ASWindowBox * aswbox,
1127 																 ASGeometry * area)
1128 {
1129 	ASMoveResizeData *mvrdata;
1130 	int start_x = 0, start_y = 0;
1131 
1132 	ConfigureNotifyLoop ();
1133 
1134 	ASQueryPointerRootXY (&start_x, &start_y);
1135 	move_canvas (asw->frame_canvas, start_x - 2, start_y - 2);
1136 	handle_canvas_config (asw->frame_canvas);
1137 
1138 /*    moveresize_canvas( asw->frame_canvas, ((int)Scr.MyDisplayWidth - (int)asw->status->width)/2,
1139 										  ((int)Scr.MyDisplayHeight - (int)asw->status->height)/2,
1140 										   asw->status->width, asw->status->height );
1141 	moveresize_canvas( asw->client_canvas, 0, 0, asw->status->width, asw->status->height );
1142 	handle_canvas_config( asw->frame_canvas );
1143  */
1144 	if (asw->status->width * asw->status->height <
1145 			(Scr.Feel.OpaqueMove * Scr.MyDisplayWidth * Scr.MyDisplayHeight) /
1146 			100) {
1147 		LOCAL_DEBUG_OUT ("Mapping client window %lX", asw->client_canvas->w);
1148 		map_canvas_window (asw->client_canvas, True);
1149 		map_canvas_window (asw->frame_canvas, False);
1150 		if (get_desktop_cover_window () != None) {
1151 			Window w[2];
1152 			w[0] = get_desktop_cover_window ();
1153 			w[1] = asw->frame;
1154 			XRaiseWindow (dpy, w[0]);
1155 			XRestackWindows (dpy, w, 2);
1156 			ASSync (False);
1157 		}
1158 	}
1159 	ASSync (False);
1160 	ASWIN_SET_FLAGS (asw, AS_MoveresizeInProgress);
1161 	mvrdata = move_widget_interactively (Scr.RootCanvas,
1162 																			 asw->frame_canvas,
1163 																			 NULL,
1164 																			 apply_aswindow_move,
1165 																			 complete_aswindow_move);
1166 	if (mvrdata) {
1167 		setup_aswindow_moveresize (asw, mvrdata);
1168 		InteractiveMoveLoop ();
1169 	} else
1170 		ASWIN_CLEAR_FLAGS (asw, AS_MoveresizeInProgress);
1171 	/* window may have been destroyed while we were placing it */
1172 	return (ASWIN_GET_FLAGS (asw, AS_Dead) == 0
1173 					&& !get_flags (asw->wm_state_transition, ASWT_TO_WITHDRAWN));
1174 }
1175 
1176 static int
move_to_closest_position(ASWindow * asw,ASGeometry * area,ASStatusHints * status,int * x_inout,int * y_inout,int max_layer)1177 move_to_closest_position (ASWindow * asw, ASGeometry * area,
1178 													ASStatusHints * status, int *x_inout,
1179 													int *y_inout, int max_layer)
1180 {
1181 	int x = *x_inout;
1182 	int y = *y_inout;
1183 	int selected_x = x;
1184 	int selected_y = y;
1185 	int w = status->width;
1186 	int h = status->height;
1187 	int i, selected = -1, selected_factor = 0;;
1188 
1189 	LOCAL_DEBUG_OUT ("current=%dx%d%+d%+d", w, h, x, y);
1190 	/* now we have to find the optimal rectangle from the list */
1191 	ASVector *free_space_list =
1192 			build_free_space_list (asw, area, AS_LayerHighest, max_layer);
1193 	XRectangle *rects = PVECTOR_HEAD (XRectangle, free_space_list);
1194 	i = PVECTOR_USED (free_space_list);
1195 	while (--i >= 0)
1196 		if (rects[i].width >= w && rects[i].height >= h) {
1197 			int new_x = rects[i].x, new_y = rects[i].y;
1198 			int max_x = rects[i].x + rects[i].width - w;
1199 			int max_y = rects[i].y + rects[i].height - h;
1200 			int new_factor;
1201 			if (new_x < x)
1202 				new_x = min (x, max_x);
1203 			if (new_y < y)
1204 				new_y = min (y, max_y);
1205 			new_factor = (x - new_x) * (x - new_x) + (y - new_y) * (y - new_y);
1206 
1207 			if (selected >= 0 && new_factor > selected_factor)
1208 				continue;
1209 			selected_x = new_x;
1210 			selected_y = new_y;
1211 			selected_factor = new_factor;
1212 			selected = i;
1213 		}
1214 	LOCAL_DEBUG_OUT ("selected: %d, %+d%+d", selected, selected_x,
1215 									 selected_y);
1216 	destroy_asvector (&free_space_list);
1217 	*x_inout = selected_x;
1218 	*y_inout = selected_y;
1219 
1220 	return selected;
1221 }
1222 
1223 
1224 static Bool
find_closest_position(ASWindow * asw,ASGeometry * area,ASStatusHints * status,int * closest_x,int * closest_y,int max_layer)1225 find_closest_position (ASWindow * asw, ASGeometry * area,
1226 											 ASStatusHints * status, int *closest_x,
1227 											 int *closest_y, int max_layer)
1228 {
1229 	int selected_x = status->x + Scr.Vx;
1230 	int selected_y = status->y + Scr.Vy;
1231 	/* pass 1: find rectangle that is the closest to current position :  */
1232 	int selected =
1233 			move_to_closest_position (asw, area, status, &selected_x,
1234 																&selected_y, max_layer);
1235 	if (selected >= 0) {
1236 		*closest_x = selected_x;
1237 		*closest_y = selected_y;
1238 	}
1239 	return (selected >= 0);
1240 }
1241 
do_pointer_placement(ASWindow * asw,ASWindowBox * aswbox,ASGeometry * area)1242 static Bool do_pointer_placement (ASWindow * asw, ASWindowBox * aswbox,
1243 																	ASGeometry * area)
1244 {
1245 	int x = area->x, y = area->y;
1246 
1247 	ASQueryPointerRootXY (&x, &y);
1248 
1249 /*fprintf( stderr, "%d: x = %d, y = %d\n", __LINE__, x, y);*/
1250 	x += Scr.Vx - (int)asw->status->width / 2;
1251 	y += Scr.Vy - (int)asw->status->height / 2;
1252 /*fprintf( stderr, "%d: x = %d, y = %d\n", __LINE__, x, y);*/
1253 	if (x < area->x)
1254 		x = area->x;
1255 	else if (x + asw->status->width > area->x + area->width)
1256 		x = (area->x + area->width - asw->status->width);
1257 
1258 	if (y < area->y)
1259 		y = area->y;
1260 	else if (y + asw->status->height > area->y + area->height)
1261 		y = (area->y + area->height - asw->status->height);
1262 
1263 	move_to_closest_position (asw, area, asw->status, &x, &y,
1264 														AS_LayerHighest);
1265 
1266 /*fprintf( stderr, "%d: x = %d, y = %d\n", __LINE__, x, y);*/
1267 	asw->status->x = x - asw->status->viewport_x;
1268 	asw->status->y = y - asw->status->viewport_y;
1269 
1270 	apply_placement_result_asw (asw, XValue | YValue, x, y, 0, 0);
1271 
1272 	return True;
1273 }
1274 
do_closest_placement(ASWindow * asw,ASWindowBox * aswbox,ASGeometry * area)1275 static Bool do_closest_placement (ASWindow * asw, ASWindowBox * aswbox,
1276 																	ASGeometry * area)
1277 {
1278 	int selected_x = 0;
1279 	int selected_y = 0;
1280 
1281 	if (find_closest_position
1282 			(asw, area, asw->status, &selected_x, &selected_y,
1283 			 AS_LayerHighest)) {
1284 		apply_placement_result_asw (asw, XValue | YValue, selected_x,
1285 																selected_y, 0, 0);
1286 		LOCAL_DEBUG_OUT ("success: status(%+d%+d), anchor(%+d,%+d)",
1287 										 asw->status->x, asw->status->y, asw->anchor.x,
1288 										 asw->anchor.y);
1289 		return True;
1290 	} else {
1291 		LOCAL_DEBUG_OUT ("failed%s", "");
1292 	}
1293 
1294 	return False;
1295 }
1296 
1297 static Bool
place_aswindow_in_windowbox(ASWindow * asw,ASWindowBox * aswbox,ASUsePlacementStrategy which,Bool force)1298 place_aswindow_in_windowbox (ASWindow * asw, ASWindowBox * aswbox,
1299 														 ASUsePlacementStrategy which, Bool force)
1300 {
1301 	ASGeometry area;
1302 	Bool res = False;
1303 
1304 	if (ASWIN_GET_FLAGS (asw, AS_Dead)
1305 			|| get_flags (asw->wm_state_transition, ASWT_TO_WITHDRAWN))
1306 		return False;
1307 
1308 	area = aswbox->area;
1309 	if (!get_flags (aswbox->flags, ASA_Virtual)) {
1310 		area.x += Scr.Vx;						/*asw->status->viewport_x ; */
1311 		area.y += Scr.Vy;						/*asw->status->viewport_y ; */
1312 		if (!force) {
1313 			if (area.x >= Scr.VxMax + Scr.MyDisplayWidth)
1314 				return False;
1315 			if (area.y >= Scr.VyMax + Scr.MyDisplayHeight)
1316 				return False;
1317 		}
1318 		if (area.width <= 0)
1319 			area.width = (Scr.VxMax + Scr.MyDisplayWidth) - area.x;
1320 		else if (area.x + area.width > Scr.VxMax + Scr.MyDisplayWidth)
1321 			area.width = Scr.VxMax + Scr.MyDisplayWidth - area.x;
1322 		if (area.height <= 0)
1323 			area.height = (Scr.VyMax + Scr.MyDisplayHeight) - area.y;
1324 		else if (area.y + area.height > Scr.VyMax + Scr.MyDisplayHeight)
1325 			area.height = Scr.VyMax + Scr.MyDisplayHeight - area.y;
1326 	}
1327 	LOCAL_DEBUG_OUT ("placement area is %dx%d%+d%+d", area.width,
1328 									 area.height, area.x, area.y);
1329 
1330 	if (!force) {
1331 		if (get_flags (asw->status->flags, AS_StartViewportX))
1332 			if (asw->status->viewport_x < area.x
1333 					|| asw->status->viewport_x >= area.x + area.width)
1334 				return False;
1335 		if (get_flags (asw->status->flags, AS_StartViewportY))
1336 			if (asw->status->viewport_y < area.y
1337 					|| asw->status->viewport_y >= area.y + area.height)
1338 				return False;
1339 	}
1340 
1341 	if (ASWIN_GET_FLAGS (asw, AS_MaximizedX | AS_MaximizedY))
1342 		return do_maximized_placement (asw, aswbox, &area);
1343 
1344 	if (which == ASP_UseMainStrategy) {
1345 		if (aswbox->main_strategy == ASP_SmartPlacement)
1346 			return do_smart_placement (asw, aswbox, &area);
1347 		else if (aswbox->main_strategy == ASP_RandomPlacement)
1348 			return do_random_placement (asw, aswbox, &area, True);
1349 		else if (aswbox->main_strategy == ASP_Tile)
1350 			return do_tile_placement (asw, aswbox, &area);
1351 		else if (aswbox->main_strategy == ASP_UnderPointer)
1352 			res = do_pointer_placement (asw, aswbox, &area);
1353 		if (force)
1354 			do_tile_placement (asw, aswbox, &area);
1355 	} else {
1356 		if (aswbox->backup_strategy == ASP_RandomPlacement)
1357 			res = do_random_placement (asw, aswbox, &area, False);
1358 		else if (aswbox->backup_strategy == ASP_Cascade)
1359 			res = do_cascade_placement (asw, aswbox, &area);
1360 		else if (aswbox->backup_strategy == ASP_UnderPointer)
1361 			res = do_pointer_placement (asw, aswbox, &area);
1362 
1363 		if (aswbox->backup_strategy == ASP_Manual || (force && !res))
1364 			res = do_manual_placement (asw, aswbox, &area);
1365 	}
1366 	return res;
1367 }
1368 
1369 
place_aswindow(ASWindow * asw)1370 Bool place_aswindow (ASWindow * asw)
1371 {
1372 	/* if window has predefined named windowbox for it - we use only this windowbox
1373 	 * otherwise we use all suitable windowboxes in two passes :
1374 	 *   we first try and apply main strategy to place window in the empty space for each box
1375 	 *   if all fails we apply backup strategy of the default windowbox
1376 	 */
1377 	ASWindowBox *aswbox = NULL;
1378 
1379 	LOCAL_DEBUG_CALLER_OUT ("%p", asw);
1380 	if (AS_ASSERT (asw))
1381 		return False;
1382 
1383 	LOCAL_DEBUG_OUT ("hints(%p),status(%p)", asw->hints, asw->status);
1384 	if (AS_ASSERT (asw->hints) || AS_ASSERT (asw->status))
1385 		return False;
1386 
1387 	LOCAL_DEBUG_OUT ("status->geom(%dx%d%+d%+d), anchor->geom(%dx%d%+d%+d)",
1388 									 asw->status->width, asw->status->height, asw->status->x,
1389 									 asw->status->y, asw->anchor.width, asw->anchor.height,
1390 									 asw->anchor.x, asw->anchor.y);
1391 
1392 	if (asw->hints->windowbox_name) {
1393 		aswbox = find_window_box (&(Scr.Feel), asw->hints->windowbox_name);
1394 		if (aswbox != NULL) {
1395 			if (!place_aswindow_in_windowbox
1396 					(asw, aswbox, ASP_UseMainStrategy, False))
1397 				return place_aswindow_in_windowbox (asw, aswbox,
1398 																						ASP_UseBackupStrategy, True);
1399 			return True;
1400 		}
1401 	}
1402 
1403 	/* search for a window-box if none was specified. */
1404 	if (aswbox == NULL) {
1405 		int i, t;
1406 		ASWindowBox **aswbox_sorted =
1407 				safemalloc (sizeof (ASWindowBox *) * Scr.Feel.window_boxes_num);
1408 		aswbox = &(Scr.Feel.window_boxes[0]);
1409 
1410 		/* the following code will make sure window-boxes which have the
1411 		   virtual-flag set and are not on the current viewport will
1412 		   be considered for placement after all others. */
1413 		t = Scr.Feel.window_boxes_num;
1414 		for (i = 0; i < Scr.Feel.window_boxes_num; ++i) {
1415 			if (get_flags (aswbox[i].flags, ASA_Virtual)
1416 					&& ((asw->status->viewport_x / Scr.MyDisplayWidth
1417 							 != aswbox[i].area.x / Scr.MyDisplayWidth) ||
1418 							(asw->status->viewport_y / Scr.MyDisplayHeight
1419 							 != aswbox[i].area.y / Scr.MyDisplayHeight))
1420 					)
1421 				/* place window-box at the end */
1422 				aswbox_sorted[--t] = &aswbox[i];
1423 			else
1424 				/* place window-box at the front */
1425 				aswbox_sorted[i - Scr.Feel.window_boxes_num + t] = &aswbox[i];
1426 		}
1427 
1428 		for (i = 0; i < Scr.Feel.window_boxes_num; ++i) {
1429 			LOCAL_DEBUG_OUT
1430 					("window_box \"%s\": main_strategy = %d, backup_strategy = %d",
1431 					 aswbox_sorted[i]->name, aswbox_sorted[i]->main_strategy,
1432 					 aswbox_sorted[i]->backup_strategy);
1433 
1434 			if (IsValidDesk (aswbox_sorted[i]->desk)
1435 					&& aswbox_sorted[i]->desk != asw->status->desktop)
1436 				continue;
1437 			if (aswbox_sorted[i]->min_layer > asw->status->layer
1438 					|| aswbox_sorted[i]->max_layer < asw->status->layer)
1439 				continue;
1440 			if (aswbox_sorted[i]->min_width > asw->status->width
1441 					|| (aswbox_sorted[i]->max_width > 0
1442 							&& aswbox_sorted[i]->max_width < asw->status->width))
1443 				continue;
1444 			if (aswbox_sorted[i]->min_height > asw->status->height
1445 					|| (aswbox_sorted[i]->max_height > 0
1446 							&& aswbox_sorted[i]->max_height < asw->status->height))
1447 				continue;
1448 
1449 
1450 			if (ASWIN_GET_FLAGS (asw, AS_MaximizedX | AS_MaximizedY)) {
1451 				int win_x =
1452 						get_flags (aswbox_sorted[i]->flags,
1453 											 ASA_Virtual) ? asw->status->viewport_x : asw->
1454 						status->x;
1455 				int win_y =
1456 						get_flags (aswbox_sorted[i]->flags,
1457 											 ASA_Virtual) ? asw->status->viewport_y : asw->
1458 						status->y;
1459 
1460 
1461 				if (aswbox_sorted[i]->area.x > win_x + (int)(asw->status->width) ||
1462 						aswbox_sorted[i]->area.y > win_y + (int)(asw->status->height)
1463 						|| aswbox_sorted[i]->area.x + (int)aswbox[i].area.width < win_x
1464 						|| aswbox_sorted[i]->area.y + (int)aswbox[i].area.height <
1465 						win_y)
1466 					continue;
1467 			}
1468 
1469 			if (ASWIN_GET_FLAGS (asw, AS_MaximizedX | AS_MaximizedY)) {
1470 				Bool retval =
1471 						place_aswindow_in_windowbox (asw, aswbox_sorted[i],
1472 																				 ASP_UseBackupStrategy, True);
1473 				free (aswbox_sorted);
1474 				return retval;
1475 			} else
1476 					if (place_aswindow_in_windowbox
1477 							(asw, aswbox_sorted[i], ASP_UseMainStrategy, False)) {
1478 				free (aswbox_sorted);
1479 				return True;
1480 			}
1481 		}
1482 		free (aswbox_sorted);
1483 	}
1484 	return place_aswindow_in_windowbox (asw, Scr.Feel.default_window_box,
1485 																			ASP_UseBackupStrategy, True);
1486 }
1487 
avoid_covering_aswin_iter_func(void * data,void * aux_data)1488 Bool avoid_covering_aswin_iter_func (void *data, void *aux_data)
1489 {
1490 	ASWindow *asw = (ASWindow *) data;
1491 	ASAvoidCoverAuxData *ac_aux_data = (ASAvoidCoverAuxData *) aux_data;
1492 	ASWindow *new_aswin = ac_aux_data->new_aswin;
1493 	ASWindowBox *aswbox = ac_aux_data->aswbox;
1494 	ASGeometry *area = ac_aux_data->area;
1495 
1496 	if (asw && ASWIN_DESK (asw) == ASWIN_DESK (new_aswin)
1497 			&& asw != new_aswin) {
1498 		ASStatusHints *n = new_aswin->status;
1499 		ASStatusHints *o = asw->status;
1500 		int dn, ds, dw, de, min_dh;
1501 
1502 		LOCAL_DEBUG_OUT ("comparing to %dx%d%+d%+d, layer = %d",
1503 										 asw->status->width, asw->status->height,
1504 										 asw->status->x, asw->status->y, ASWIN_LAYER (asw));
1505 
1506 		/* we want to move out even lower layer windows so they would not be overlapped by us */
1507 		if ( /*ASWIN_LAYER(asw) < ASWIN_LAYER(new_aswin) || */
1508 				ASWIN_GET_FLAGS (asw, AS_Iconic))
1509 			return True;
1510 
1511 		dw = o->x + (int)o->width - n->x;
1512 		de = (int)(n->x + n->width) - o->x;
1513 		dn = o->y + (int)o->height - n->y;
1514 		ds = (int)(n->y + n->height) - o->y;
1515 		LOCAL_DEBUG_OUT ("deltas : w=%d e=%d s=%d n=%d", dw, de, dn, ds);
1516 		if (dw > 0 && de > 0 && dn > 0 && ds > 0) {
1517 			ASGeometry clip_area = *area;
1518 
1519 			min_dh = min (dw, de);
1520 			if (min_dh < dn && min_dh < ds) {
1521 				if (dw <= de) {					/* better move window westwards */
1522 					clip_area.width = (n->x <= clip_area.x) ? 1 : n->x - clip_area.x;
1523 				} else {								/* better move window eastwards */
1524 
1525 					int d = n->x + (int)n->width - clip_area.x;
1526 					clip_area.x = n->x + n->width;
1527 					clip_area.width =
1528 							(d >= clip_area.width) ? 1 : clip_area.width - d;
1529 				}
1530 			} else if (dn <= ds)			/* better move window southwards */
1531 				clip_area.height = (n->y <= clip_area.y) ? 1 : n->y - clip_area.y;
1532 			else {
1533 				int d = n->y + (int)n->height - clip_area.y;
1534 				clip_area.y = n->y + n->height;
1535 				clip_area.height =
1536 						(d >= clip_area.height) ? 1 : clip_area.height - d;
1537 			}
1538 			LOCAL_DEBUG_OUT ("adjusted area is %dx%d%+d%+d", clip_area.width,
1539 											 clip_area.height, clip_area.x, clip_area.y);
1540 			/* move only affected windows : */
1541 			if (do_closest_placement (asw, aswbox, &clip_area)) {
1542 				anchor2status (asw->status, asw->hints, &(asw->anchor));
1543 				/* now lets actually resize the window : */
1544 				apply_window_status_size (asw, get_orientation_data (asw));
1545 			}
1546 		}
1547 	}
1548 	return True;
1549 }
1550 
do_enforce_avoid_cover(ASWindow * asw)1551 void do_enforce_avoid_cover (ASWindow * asw)
1552 {
1553 	if (asw
1554 			&& ASWIN_HFLAGS (asw,
1555 											 AS_AvoidCover | AS_ShortLived) == AS_AvoidCover) {
1556 		ASWindowBox aswbox;
1557 		ASAvoidCoverAuxData aux_data;
1558 		/* we need to move all the res of the window out of the area occupied by us */
1559 		LOCAL_DEBUG_OUT ("status = %dx%d%+d%+d, layer = %d",
1560 										 asw->status->width, asw->status->height,
1561 										 asw->status->x, asw->status->y, ASWIN_LAYER (asw));
1562 		/* if window has predefined named windowbox for it - we use only this windowbox
1563 		 * otherwise we use all suitable windowboxes in two passes :
1564 		 *   we first try and apply main strategy to place window in the empty space for each box
1565 		 *   if all fails we apply backup strategy of the default windowbox
1566 		 */
1567 		aux_data.new_aswin = asw;
1568 		aux_data.aswbox = &aswbox;
1569 		aswbox.name = mystrdup ("default");
1570 		aswbox.area.x = Scr.Vx;
1571 		aswbox.area.y = Scr.Vy;
1572 		aswbox.area.width = Scr.MyDisplayWidth;
1573 		aswbox.area.height = Scr.MyDisplayHeight;
1574 		aswbox.main_strategy = ASP_Manual;
1575 		aswbox.backup_strategy = ASP_Manual;
1576 		/* we should enforce this one : */
1577 		aswbox.desk = INVALID_DESK;
1578 		aswbox.min_layer = AS_LayerLowest;
1579 		aswbox.max_layer = AS_LayerHighest;
1580 
1581 		aux_data.area = &(aswbox.area);
1582 
1583 		iterate_asbidirlist (Scr.Windows->clients,
1584 												 avoid_covering_aswin_iter_func, (void *)&aux_data,
1585 												 NULL, False);
1586 
1587 		free (aswbox.name);
1588 
1589 	}
1590 }
1591 
delayed_enforce_avoid_cover(void * vdata)1592 void delayed_enforce_avoid_cover (void *vdata)
1593 {
1594 	ASWindow *asw = (ASWindow *) vdata;
1595 	if (asw && asw->magic == MAGIC_ASWINDOW)
1596 		do_enforce_avoid_cover (asw);
1597 }
1598 
enforce_avoid_cover(ASWindow * asw)1599 void enforce_avoid_cover (ASWindow * asw)
1600 {
1601 	/* we do not want to enforce avoid cover right away - clients may want to reposition
1602 	   themselves automatically */
1603 
1604 	if (asw)
1605 		if (ASWIN_HFLAGS (asw, AS_AvoidCover | AS_ShortLived) == AS_AvoidCover) {
1606 /* we don't want to remove by  data as there are other functions associated wit this
1607 *			while( timer_remove_by_data( (void*)asw ) ); */
1608 			timer_new (500, delayed_enforce_avoid_cover, (void *)asw);
1609 		}
1610 }
1611 
1612 
obey_avoid_cover(ASWindow * asw,ASStatusHints * tmp_status,XRectangle * tmp_anchor,int max_layer)1613 void obey_avoid_cover (ASWindow * asw, ASStatusHints * tmp_status,
1614 											 XRectangle * tmp_anchor, int max_layer)
1615 {
1616 	if (asw) {
1617 		ASWindowBox aswbox;
1618 		int selected_x = 0;
1619 		int selected_y = 0;
1620 		int left = Scr.Vx, right = Scr.Vx + Scr.MyDisplayWidth;
1621 		int top = Scr.Vy, bottom = Scr.Vy + Scr.MyDisplayHeight;
1622 
1623 		/* we need to move all the res of the window out of the area occupied by us */
1624 		LOCAL_DEBUG_OUT ("status = %dx%d%+d%+d, layer = %d",
1625 										 asw->status->width, asw->status->height,
1626 										 asw->status->x, asw->status->y, ASWIN_LAYER (asw));
1627 		/* if window has predefined named windowbox for it - we use only this windowbox
1628 		 * otherwise we use all suitable windowboxes in two passes :
1629 		 *   we first try and apply main strategy to place window in the empty space for each box
1630 		 *   if all fails we apply backup strategy of the default windowbox
1631 		 */
1632 		LOCAL_DEBUG_OUT ("max_layer = %d", max_layer);
1633 
1634 		aswbox.name = mystrdup ("default");
1635 		if (!ASWIN_GET_FLAGS (asw, AS_Sticky)) {
1636 			if (asw->status->x < 0)
1637 				left = 0;
1638 			if (asw->status->x + (int)asw->status->width >= Scr.MyDisplayWidth)
1639 				right = Scr.VxMax + Scr.MyDisplayWidth;
1640 			if (asw->status->y < 0)
1641 				top = 0;
1642 			if (asw->status->y + (int)asw->status->height >= Scr.MyDisplayHeight)
1643 				bottom = Scr.VyMax + Scr.MyDisplayHeight;
1644 		}
1645 #if 0
1646 		aswbox.area.x = Scr.Vx;
1647 		aswbox.area.y = Scr.Vy;
1648 		aswbox.area.width = Scr.MyDisplayWidth;
1649 		aswbox.area.height = Scr.MyDisplayHeight;
1650 #else
1651 		aswbox.area.x = left;
1652 		aswbox.area.y = top;
1653 		aswbox.area.width = right - left;
1654 		aswbox.area.height = bottom - top;
1655 #endif
1656 		aswbox.main_strategy = ASP_Manual;
1657 		aswbox.backup_strategy = ASP_Manual;
1658 		/* we should enforce this one : */
1659 		aswbox.desk = INVALID_DESK;
1660 		aswbox.min_layer = AS_LayerLowest;
1661 		aswbox.max_layer = AS_LayerHighest;
1662 
1663 		if (find_closest_position
1664 				(asw, &(aswbox.area), tmp_status, &selected_x, &selected_y,
1665 				 max_layer))
1666 			apply_placement_result (tmp_status, tmp_anchor, asw->hints,
1667 															XValue | YValue, selected_x, selected_y, 0,
1668 															0);
1669 
1670 		free (aswbox.name);
1671 	}
1672 }
1673 
1674 /**************************************************************************
1675  * ************************************************************************
1676  * ************************************************************************
1677  **************************************************************************/
1678 #if 0
1679 /*
1680  * pass 0: do not ignore windows behind the target window's layer
1681  * pass 1: ignore windows behind the target window's layer
1682  */
1683 int
1684 SmartPlacement (ASWindow * t, int *x, int *y, int width, int height,
1685 								int rx, int ry, int rw, int rh, int pass)
1686 {
1687 	int test_x = 0, test_y;
1688 	int loc_ok = 0;
1689 	ASWindow *twin;
1690 	int xb = rx, xmax = rx + rw - width, xs = 1;
1691 	int yb = ry, ymax = ry + rh - height, ys = 1;
1692 
1693 	if (rw < width || rh < height)
1694 		return loc_ok;
1695 
1696 	/* if closer to the right edge than the left, scan from right to left */
1697 	if (Scr.MyDisplayWidth - (rx + rw) < rx) {
1698 		xb = rx + rw - width;
1699 		xs = -1;
1700 	}
1701 
1702 	/* if closer to the bottom edge than the top, scan from bottom to top */
1703 	if (Scr.MyDisplayHeight - (ry + rh) < ry) {
1704 		yb = ry + rh - height;
1705 		ys = -1;
1706 	}
1707 
1708 	for (test_y = yb; ry <= test_y && test_y <= ymax && !loc_ok;
1709 			 test_y += ys)
1710 		for (test_x = xb; rx <= test_x && test_x <= xmax && !loc_ok;
1711 				 test_x += xs) {
1712 			int tx, ty, tw, th;
1713 
1714 			loc_ok = 1;
1715 
1716 			for (twin = Scr.ASRoot.next; twin != NULL && loc_ok;
1717 					 twin = twin->next) {
1718 				/* ignore windows on other desks, and our own window */
1719 				if (ASWIN_DESK (twin) != ASWIN_DESK (t) || twin == t)
1720 					continue;
1721 
1722 				/* ignore non-iconified windows, if we're iconified and not using
1723 				 * StubbornIconPlacement */
1724 				if (!(twin->flags & ICONIFIED) && (t->flags & ICONIFIED) &&
1725 						!(Scr.flags & StubbornIconPlacement))
1726 					continue;
1727 
1728 				/* ignore iconified windows, if we're not iconified and not using
1729 				 * StubbornPlacement */
1730 				if ((twin->flags & ICONIFIED) && !(t->flags & ICONIFIED) &&
1731 						!(Scr.flags & StubbornPlacement))
1732 					continue;
1733 
1734 				/* ignore a window on a lower layer, unless it's an AvoidCover
1735 				 * window or instructed to pay attention to it (ie, pass == 0) */
1736 				if (!(twin->flags & ICONIFIED)
1737 						&& ASWIN_LAYER (twin) < ASWIN_LAYER (t)
1738 						&& !ASWIN_HFLAGS (twin, AS_AvoidCover) && pass)
1739 					continue;
1740 
1741 				get_window_geometry (twin, twin->flags, &tx, &ty, &tw, &th);
1742 				tw += 2 * twin->bw;
1743 				th += 2 * twin->bw;
1744 				if (tx <= test_x + width && tx + tw >= test_x &&
1745 						ty <= test_y + height && ty + th >= test_y) {
1746 					loc_ok = 0;
1747 					if (xs > 0)
1748 						test_x = tx + tw;
1749 					else
1750 						test_x = tx - width;
1751 				}
1752 			}
1753 		}
1754 	if (loc_ok) {
1755 		*x = test_x - xs;
1756 		*y = test_y - ys;
1757 	}
1758 	return loc_ok;
1759 }
1760 
1761 /**************************************************************************
1762  *
1763  * Handles initial placement and sizing of a new window
1764  * Returns False in the event of a lost window.
1765  *
1766  **************************************************************************/
1767 Bool PlaceWindow (ASWindow * tmp_win, unsigned long tflag, int Desk)
1768 {
1769 	int xl = -1, yt = -1, DragWidth, DragHeight;
1770 	extern Bool PPosOverride;
1771 	XRectangle srect = { 0, 0, Scr.MyDisplayWidth, Scr.MyDisplayHeight };
1772 	int x, y;
1773 	unsigned int width, height;
1774 
1775 	y = tmp_win->attr.y;
1776 	x = tmp_win->attr.x;
1777 	width = tmp_win->frame_width;
1778 	height = tmp_win->frame_height;
1779 
1780 #ifdef HAVE_XINERAMA
1781 	if (Scr.xinerama_screens_num > 1) {
1782 		register int i;
1783 		XRectangle *s = Scr.xinerama_screens;
1784 
1785 		for (i = 0; i < Scr.xinerama_screens_num; ++i) {
1786 			/* if window is completely in this xinerama-screen */
1787 			if (s[i].x < x + width && s[i].x + s[i].width > x &&
1788 					s[i].y < y + height && s[i].y + s[i].height > y) {
1789 				srect = s[i];
1790 				break;
1791 			}
1792 		}
1793 	}
1794 #endif													/* XINERAMA */
1795 
1796 
1797 	tmp_win->Desk = InvestigateWindowDesk (tmp_win);
1798 
1799 	/* I think it would be good to switch to the selected desk
1800 	 * whenever a new window pops up, except during initialization */
1801 	if (!PPosOverride && Scr.CurrentDesk != tmp_win->Desk)
1802 		changeDesks (0, tmp_win->Desk);
1803 
1804 	/* Desk has been selected, now pick a location for the window */
1805 	/*
1806 	 *  If
1807 	 *     o  the window is a transient, or
1808 	 *
1809 	 *     o  a USPosition was requested, or
1810 	 *
1811 	 *     o  Prepos flag was given
1812 	 *
1813 	 *   then put the window where requested.
1814 	 *
1815 	 *   If RandomPlacement was specified,
1816 	 *       then place the window in a psuedo-random location
1817 	 */
1818 	if (!ASWIN_HFLAGS (tmp_win, AS_Transient) &&
1819 			!(tmp_win->normal_hints.flags & USPosition) &&
1820 			((Scr.flags & NoPPosition)
1821 			 || !(tmp_win->normal_hints.flags & PPosition)) && !(PPosOverride)
1822 			&& !(tflag & PREPOS_FLAG) && !((tmp_win->wmhints)
1823 																		 && (tmp_win->wmhints->
1824 																				 flags & StateHint)
1825 																		 && (tmp_win->wmhints->initial_state ==
1826 																				 IconicState))) {
1827 		/* Get user's window placement, unless RandomPlacement is specified */
1828 		if (Scr.flags & SMART_PLACEMENT) {
1829 			if (!SmartPlacement (tmp_win, &xl, &yt,
1830 													 tmp_win->frame_width + 2 * tmp_win->bw,
1831 													 tmp_win->frame_height + 2 * tmp_win->bw,
1832 													 srect.x, srect.y, srect.width, srect.height, 0))
1833 				SmartPlacement (tmp_win, &xl, &yt,
1834 												tmp_win->frame_width + 2 * tmp_win->bw,
1835 												tmp_win->frame_height + 2 * tmp_win->bw,
1836 												srect.x, srect.y, srect.width, srect.height, 1);
1837 		}
1838 		if (Scr.flags & RandomPlacement) {
1839 			if (xl < 0) {
1840 				/* place window in a random location */
1841 				if (tmp_win->flags & VERTICAL_TITLE) {
1842 					Scr.randomx += 2 * tmp_win->title_width;
1843 					Scr.randomy += tmp_win->title_width;
1844 				} else {
1845 					Scr.randomx += tmp_win->title_height;
1846 					Scr.randomy += 2 * tmp_win->title_height;
1847 				}
1848 				if (Scr.randomx > srect.x + (srect.width / 2))
1849 					Scr.randomx = srect.x;
1850 				if (Scr.randomy > srect.y + (srect.height / 2))
1851 					Scr.randomy = srect.y;
1852 				xl = Scr.randomx - tmp_win->old_bw;
1853 				yt = Scr.randomy - tmp_win->old_bw;
1854 			}
1855 
1856 			if (xl + tmp_win->frame_width + 2 * tmp_win->bw > srect.width) {
1857 				xl = srect.width - tmp_win->frame_width - 2 * tmp_win->bw;
1858 				Scr.randomx = srect.x;
1859 			}
1860 			if (yt + tmp_win->frame_height + 2 * tmp_win->bw > srect.height) {
1861 				yt = srect.height - tmp_win->frame_height - 2 * tmp_win->bw;
1862 				Scr.randomy = srect.y;
1863 			}
1864 		}
1865 		if (xl < 0) {
1866 			if (GrabEm (POSITION)) {
1867 				/* Grabbed the pointer - continue */
1868 				grab_server ();
1869 				DragWidth = tmp_win->frame_width + 2 * tmp_win->bw;
1870 				DragHeight = tmp_win->frame_height + 2 * tmp_win->bw;
1871 				XMapRaised (dpy, Scr.SizeWindow);
1872 				moveLoop (tmp_win, 0, 0, DragWidth, DragHeight, &xl, &yt, False,
1873 									True);
1874 				XUnmapWindow (dpy, Scr.SizeWindow);
1875 				ungrab_server ();
1876 				UngrabEm ();
1877 			} else {
1878 				/* couldn't grab the pointer - better do something */
1879 				XBell (dpy, Scr.screen);
1880 				xl = 0;
1881 				yt = 0;
1882 			}
1883 		}
1884 		tmp_win->attr.y = yt;
1885 		tmp_win->attr.x = xl;
1886 	} else {
1887 		/* the USPosition was specified, or the window is a transient,
1888 		 * or it starts iconic so let it place itself */
1889 		if (!(tmp_win->normal_hints.flags & USPosition)) {
1890 			if (width <= srect.width) {
1891 				if (x < srect.x)
1892 					x = srect.x;
1893 				else if (x + width > srect.x + srect.width)
1894 					x = srect.x + srect.width - width;
1895 			}
1896 			if (height <= srect.height) {
1897 				if (y < srect.y)
1898 					y = srect.y;
1899 				else if (y + height > srect.y + srect.height)
1900 					y = srect.y + srect.height - height;
1901 			}
1902 			tmp_win->attr.y = y;
1903 			tmp_win->attr.x = x;
1904 		}
1905 	}
1906 	aswindow_set_desk_property (tmp_win, tmp_win->Desk);
1907 	return True;
1908 }
1909 
1910 
1911 #endif
1912