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