1 /*
2 * Copyright (C) 2000-2007 Carsten Haitzler, Geoff Harrison and various contributors
3 * Copyright (C) 2004-2020 Kim Woelders
4 *
5 * Permission is hereby granted, free of charge, to any person obtaining a copy
6 * of this software and associated documentation files (the "Software"), to
7 * deal in the Software without restriction, including without limitation the
8 * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
9 * sell copies of the Software, and to permit persons to whom the Software is
10 * furnished to do so, subject to the following conditions:
11 *
12 * The above copyright notice and this permission notice shall be included in
13 * all copies of the Software, its documentation and marketing & publicity
14 * materials, and acknowledgment shall be given in the documentation, materials
15 * and software packages that this Software was used.
16 *
17 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
20 * THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
21 * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
22 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
23 */
24 #include "E.h"
25 #include "desktops.h"
26 #include "ewins.h"
27 #include "groups.h"
28 #include "screen.h"
29 #include "slide.h"
30
31 #define DEBUG_ARRANGE 0
32
33 typedef struct {
34 void *data;
35 int x, y, w, h;
36 int p;
37 } RectBox;
38
39 typedef struct {
40 int x, y;
41 int p, q;
42 } RectInfo;
43
44 static int
ArrangeAddToList(int * array,int current_size,int value)45 ArrangeAddToList(int *array, int current_size, int value)
46 {
47 int i, j;
48
49 if (current_size >= 2 &&
50 (value <= array[0] || value >= array[current_size - 1]))
51 return current_size;
52
53 for (i = 0; i < current_size; i++)
54 {
55 if (value < array[i])
56 {
57 for (j = current_size; j > i; j--)
58 array[j] = array[j - 1];
59 array[i] = value;
60 return current_size + 1;
61 }
62 else if (value == array[i])
63 return current_size;
64 }
65 array[current_size] = value;
66 return current_size + 1;
67 }
68
69 static void
ArrangeMakeXYArrays(int tx1,int tx2,int ty1,int ty2,int fitw,int fith,const RectBox * sorted,int num_sorted,int * xarray,int * nx,int * yarray,int * ny)70 ArrangeMakeXYArrays(int tx1, int tx2, int ty1, int ty2, int fitw, int fith,
71 const RectBox * sorted, int num_sorted,
72 int *xarray, int *nx, int *yarray, int *ny)
73 {
74 int j, x1, x2, y1, y2;
75 int xsize, ysize;
76
77 xsize = 0;
78 ysize = 0;
79
80 /* put all the sorted rects into the xy arrays */
81 xsize = ArrangeAddToList(xarray, xsize, tx1);
82 xsize = ArrangeAddToList(xarray, xsize, tx2);
83 xsize = ArrangeAddToList(xarray, xsize, tx2 - fitw);
84 ysize = ArrangeAddToList(yarray, ysize, ty1);
85 ysize = ArrangeAddToList(yarray, ysize, ty2);
86 ysize = ArrangeAddToList(yarray, ysize, ty2 - fith);
87
88 for (j = 0; j < num_sorted; j++)
89 {
90 x1 = sorted[j].x;
91 x2 = x1 + sorted[j].w;
92 xsize = ArrangeAddToList(xarray, xsize, x1);
93 xsize = ArrangeAddToList(xarray, xsize, x2);
94 xsize = ArrangeAddToList(xarray, xsize, x1 - fitw);
95 xsize = ArrangeAddToList(xarray, xsize, x2 - fitw);
96 y1 = sorted[j].y;
97 y2 = y1 + sorted[j].h;
98 ysize = ArrangeAddToList(yarray, ysize, y1);
99 ysize = ArrangeAddToList(yarray, ysize, y2);
100 ysize = ArrangeAddToList(yarray, ysize, y1 - fith);
101 ysize = ArrangeAddToList(yarray, ysize, y2 - fith);
102 }
103 #if DEBUG_ARRANGE
104 for (j = 0; j < xsize; j++)
105 Eprintf("xarray[%d] = %d\n", j, xarray[j]);
106 for (j = 0; j < ysize; j++)
107 Eprintf("yarray[%d] = %d\n", j, yarray[j]);
108 #endif
109
110 *nx = xsize;
111 *ny = ysize;
112 }
113
114 #define Filled(x,y) (filled[(y * (xsize - 1)) + x])
115
116 static void
ArrangeMakeFillLists(const RectBox * sorted,int num_sorted,int * xarray,int xsize,int * yarray,int ysize,unsigned char * filled)117 ArrangeMakeFillLists(const RectBox * sorted, int num_sorted,
118 int *xarray, int xsize, int *yarray, int ysize,
119 unsigned char *filled)
120 {
121 int j, x1, x2, y1, y2, k, y, x;
122
123 /* fill the allocation array */
124 for (j = 0; j < (xsize - 1) * (ysize - 1); filled[j++] = 0)
125 ;
126 for (j = 0; j < num_sorted; j++)
127 {
128 if (sorted[j].x + sorted[j].w <= xarray[0] ||
129 sorted[j].x >= xarray[xsize - 1])
130 continue;
131 if (sorted[j].y + sorted[j].h <= yarray[0] ||
132 sorted[j].y >= yarray[ysize - 1])
133 continue;
134 x1 = -1;
135 x2 = -1;
136 y1 = -1;
137 y2 = -1;
138 for (k = 0; k < xsize - 1; k++)
139 if (sorted[j].x <= xarray[k])
140 {
141 x1 = x2 = k;
142 break;
143 }
144 for (k++; k < xsize - 1; k++)
145 if (sorted[j].x + sorted[j].w > xarray[k])
146 x2 = k;
147 for (k = 0; k < ysize - 1; k++)
148 if (sorted[j].y <= yarray[k])
149 {
150 y1 = y2 = k;
151 break;
152 }
153 for (k++; k < ysize - 1; k++)
154 if (sorted[j].y + sorted[j].h > yarray[k])
155 y2 = k;
156 #if DEBUG_ARRANGE
157 Eprintf("Fill %4d,%4d %4dx%4d: (%2d)%4d->(%2d)%4d,(%2d)%4d->(%2d)%4d\n",
158 sorted[j].x, sorted[j].y, sorted[j].w, sorted[j].h,
159 x1, xarray[x1], x2, xarray[x2], y1, yarray[y1], y2, yarray[y2]);
160 #endif
161 if ((x1 >= 0) && (x2 >= 0) && (y1 >= 0) && (y2 >= 0))
162 {
163 for (y = y1; y <= y2; y++)
164 {
165 for (x = x1; x <= x2; x++)
166 {
167 Filled(x, y) += sorted[j].p;
168 }
169 }
170 }
171 }
172
173 #if DEBUG_ARRANGE
174 Eprintf("Filled[%2d,%2d] =\n", xsize, ysize);
175 for (k = 0; k < ysize - 1; k++)
176 {
177 for (j = 0; j < xsize - 1; j++)
178 printf(" %2d", Filled(j, k));
179 printf("\n");
180 }
181 #endif
182 }
183
184 static void
ArrangeFindSpace(const int * xarray,int xsize,const int * yarray,int ysize,unsigned char * filled,RectInfo * spaces,int * ns,int wx,int wy,int ww,int wh)185 ArrangeFindSpace(const int *xarray, int xsize, const int *yarray, int ysize,
186 unsigned char *filled, RectInfo * spaces, int *ns,
187 int wx, int wy, int ww, int wh)
188 {
189 int i, j, w, h, fw, fh, z1, z2;
190 int cost, desk;
191 int num_spaces = *ns;
192
193 if (wx < xarray[0] || (wx != xarray[0] && wx + ww > xarray[xsize - 1]))
194 return;
195 if (wy < yarray[0] || (wy != yarray[0] && wy + wh > yarray[ysize - 1]))
196 return;
197
198 cost = desk = 0;
199 fh = wh;
200 #if DEBUG_ARRANGE > 1
201 Eprintf("Check-A %d,%d %dx%d\n", wx, wy, ww, wh);
202 #endif
203 for (j = 0; j < ysize - 1; j++)
204 {
205 z2 = yarray[j + 1];
206 if (z2 <= wy)
207 continue;
208
209 z1 = wy > yarray[j] ? wy : yarray[j];
210 z2 = wy + wh < z2 ? wy + wh : z2;
211 h = z2 - z1;
212 fw = ww;
213 for (i = 0; i < xsize - 1; i++)
214 {
215 z2 = xarray[i + 1];
216 if (z2 <= wx)
217 continue;
218
219 z1 = wx > xarray[i] ? wx : xarray[i];
220 z2 = wx + ww < z2 ? wx + ww : z2;
221 w = z2 - z1;
222 #if DEBUG_ARRANGE > 1
223 Eprintf("Add [%d,%d] %3dx%3d: %2d\n", i, j, w, h, Filled(i, j));
224 #endif
225 if (Filled(i, j) == 0)
226 desk += w * h;
227 else
228 cost += w * h * Filled(i, j);
229 fw -= w;
230 if (fw <= 0)
231 break;
232 }
233 fh -= h;
234 if (fh <= 0)
235 break;
236 }
237
238 #if DEBUG_ARRANGE
239 Eprintf("Check %4d,%4d %3dx%3d cost=%d desk=%d\n", wx, wy, ww, wh,
240 cost, desk);
241 #endif
242 spaces[num_spaces].x = wx;
243 spaces[num_spaces].y = wy;
244 spaces[num_spaces].p = cost;
245 spaces[num_spaces].q = desk;
246 num_spaces++;
247 *ns = num_spaces;
248 }
249
250 static void
ArrangeFindSpaces(const int * xarray,int xsize,const int * yarray,int ysize,unsigned char * filled,RectInfo * spaces,int max_spaces,int * ns,RectBox * fit)251 ArrangeFindSpaces(const int *xarray, int xsize, const int *yarray, int ysize,
252 unsigned char *filled, RectInfo * spaces, int max_spaces,
253 int *ns, RectBox * fit)
254 {
255 int ix, iy, fx, fy, fw, fh;
256
257 /* create list of all "spaces" */
258 *ns = 0;
259 fw = fit->w;
260 fh = fit->h;
261 for (iy = 0; iy < ysize; iy++)
262 {
263 fy = yarray[iy];
264
265 for (ix = 0; ix < xsize; ix++)
266 {
267 fx = xarray[ix];
268
269 ArrangeFindSpace(xarray, xsize, yarray, ysize, filled, spaces, ns,
270 fx, fy, fw, fh);
271 if (*ns >= max_spaces)
272 goto done;
273 }
274 }
275
276 done:
277 ;
278 }
279
280 static void
ArrangeSwapList(RectBox * list,int a,int b)281 ArrangeSwapList(RectBox * list, int a, int b)
282 {
283 RectBox bb;
284
285 bb.data = list[a].data;
286 bb.x = list[a].x;
287 bb.y = list[a].y;
288 bb.w = list[a].w;
289 bb.h = list[a].h;
290 list[a].data = list[b].data;
291 list[a].x = list[b].x;
292 list[a].y = list[b].y;
293 list[a].w = list[b].w;
294 list[a].h = list[b].h;
295 list[b].data = bb.data;
296 list[b].x = bb.x;
297 list[b].y = bb.y;
298 list[b].w = bb.w;
299 list[b].h = bb.h;
300 }
301
302 static void
ArrangeRects(const RectBox * fixed,int fixed_count,RectBox * floating,int floating_count,RectBox * sorted,int startx,int starty,int width,int height,int policy,char initial_window)303 ArrangeRects(const RectBox * fixed, int fixed_count, RectBox * floating,
304 int floating_count, RectBox * sorted, int startx, int starty,
305 int width, int height, int policy, char initial_window)
306 {
307 int num_sorted;
308 int tx1, ty1, tx2, ty2;
309 int xsize = 0, ysize = 0;
310 int *xarray, *yarray;
311 int i, j, k;
312 unsigned char *filled;
313 RectInfo *spaces;
314 int num_spaces, alloc_spaces;
315 int sort;
316 int a1, a2;
317
318 tx1 = startx;
319 ty1 = starty;
320 tx2 = startx + width;
321 ty2 = starty + height;
322 if (initial_window)
323 {
324 int xx1, yy1, xx2, yy2;
325
326 ScreenGetAvailableAreaByPointer(&xx1, &yy1, &xx2, &yy2,
327 Conf.place.ignore_struts);
328 xx2 += xx1;
329 yy2 += yy1;
330 if (tx1 < xx1)
331 tx1 = xx1;
332 if (tx2 > xx2)
333 tx2 = xx2;
334 if (ty1 < yy1)
335 ty1 = yy1;
336 if (ty2 > yy2)
337 ty2 = yy2;
338 }
339 #if DEBUG_ARRANGE
340 Eprintf("Target area %d,%d -> %d,%d\n", tx1, ty1, tx2, ty2);
341 #endif
342
343 switch (policy)
344 {
345 case ARRANGE_VERBATIM:
346 break;
347 case ARRANGE_BY_SIZE:
348 sort = 0;
349 while (!sort)
350 {
351 sort = 1;
352 for (i = 0; i < floating_count - 1; i++)
353 {
354 a1 = floating[i].w * floating[i].h;
355 a2 = floating[i + 1].w * floating[i + 1].h;
356 if (a2 > a1)
357 {
358 sort = 0;
359 ArrangeSwapList(floating, i, i + 1);
360 }
361 }
362 }
363 break;
364 case ARRANGE_BY_POSITION:
365 sort = 0;
366 while (!sort)
367 {
368 sort = 1;
369 for (i = 0; i < floating_count - 1; i++)
370 {
371 a1 = floating[i].x + floating[i].y;
372 a2 = (floating[i + 1].x + (floating[i + 1].w >> 1)) +
373 (floating[i + 1].y + (floating[i + 1].h >> 1));
374 if (a2 < a1)
375 {
376 sort = 0;
377 ArrangeSwapList(floating, i, i + 1);
378 }
379 }
380 }
381 break;
382 default:
383 break;
384 }
385
386 /* for every floating rect in order, "fit" it into the sorted list */
387 i = ((fixed_count + floating_count) * 4) + 2;
388 xarray = EMALLOC(int, i);
389 yarray = EMALLOC(int, i);
390
391 filled = NULL;
392 spaces = NULL;
393 alloc_spaces = 0;
394
395 if (!xarray || !yarray)
396 goto done;
397
398 /* copy "fixed" rects into the sorted list */
399 if (fixed)
400 memcpy(sorted, fixed, fixed_count * sizeof(RectBox));
401 num_sorted = fixed_count;
402
403 /* go through each floating rect in order and "fit" it in */
404 for (i = 0; i < floating_count; i++)
405 {
406 ArrangeMakeXYArrays(tx1, tx2, ty1, ty2, floating[i].w, floating[i].h,
407 sorted, num_sorted, xarray, &xsize, yarray, &ysize);
408 num_spaces = xsize * ysize;
409 if (num_spaces <= 0)
410 continue;
411
412 if (alloc_spaces < num_spaces)
413 {
414 unsigned char *ptr_f;
415 RectInfo *ptr_s;
416
417 ptr_f = EREALLOC(unsigned char, filled, num_spaces);
418
419 if (ptr_f)
420 filled = ptr_f;
421 ptr_s = EREALLOC(RectInfo, spaces, num_spaces);
422 if (ptr_s)
423 spaces = ptr_s;
424 if (!ptr_f || !ptr_s)
425 goto done;
426 alloc_spaces = num_spaces;
427 }
428 ArrangeMakeFillLists(sorted, num_sorted,
429 xarray, xsize, yarray, ysize, filled);
430
431 /* create list of all "spaces" */
432 ArrangeFindSpaces(xarray, xsize, yarray, ysize, filled,
433 spaces, alloc_spaces, &num_spaces, floating + i);
434 if (num_spaces <= 0)
435 continue;
436
437 /* find the first space that fits */
438 k = 0;
439 sort = 0x7fffffff; /* NB! Break at 0 == free space */
440 for (j = 0; j < num_spaces; j++)
441 {
442 a1 = spaces[j].p - spaces[j].q * 4;
443 if (a1 >= sort)
444 continue;
445 sort = a1;
446 k = j;
447 if (spaces[j].p == 0)
448 break;
449 }
450 if (spaces[k].q == 0 && Conf.place.center_if_desk_full)
451 {
452 sorted[num_sorted].x = (tx1 + tx2 - floating[i].w) / 2;
453 sorted[num_sorted].y = (ty1 + ty2 - floating[i].h) / 2;
454 }
455 else
456 {
457 sorted[num_sorted].x = spaces[k].x;
458 sorted[num_sorted].y = spaces[k].y;
459 }
460 sorted[num_sorted].data = floating[i].data;
461 sorted[num_sorted].w = floating[i].w;
462 sorted[num_sorted].h = floating[i].h;
463 sorted[num_sorted].p = floating[i].p;
464 num_sorted++;
465 }
466
467 #if DEBUG_ARRANGE
468 for (i = 0; i < num_sorted; i++)
469 Eprintf("Sorted: x,y=%4d,%4d wxh=%3dx%3d p=%2d: %s\n",
470 sorted[i].x, sorted[i].y, sorted[i].w, sorted[i].h, sorted[i].p,
471 (sorted[i].data) ? EobjGetName((EObj *) sorted[i].data) : "?");
472 #endif
473
474 done:
475 /* free up memory */
476 Efree(xarray);
477 Efree(yarray);
478 Efree(filled);
479 Efree(spaces);
480 }
481
482 void
SnapEwin(EWin * ewin,int dx,int dy,int * new_dx,int * new_dy)483 SnapEwin(EWin * ewin, int dx, int dy, int *new_dx, int *new_dy)
484 {
485 EWin *const *lst1;
486 EWin **lst, **gwins;
487 int gnum, num, i, j, screen_snap_dist, odx, ody;
488 static char last_res = 0;
489 int top_bound, bottom_bound, left_bound, right_bound, w, h;
490
491 if (!ewin)
492 return;
493
494 if (!Conf.snap.enable)
495 {
496 *new_dx = dx;
497 *new_dy = dy;
498 return;
499 }
500
501 ScreenGetGeometry(ewin->shape_x, ewin->shape_y,
502 &left_bound, &top_bound, &w, &h);
503 right_bound = left_bound + w;
504 bottom_bound = top_bound + h;
505 screen_snap_dist = Mode.constrained ? (w + h) : Conf.snap.screen_snap_dist;
506
507 lst1 = EwinListOrderGet(&num);
508 if (!lst1)
509 return;
510
511 lst = EMALLOC(EWin *, num);
512 if (!lst)
513 return;
514 memcpy(lst, lst1, num * sizeof(EWin *));
515
516 gwins = ListWinGroupMembersForEwin(ewin, GROUP_ACTION_MOVE, Mode.nogroup
517 || Mode.move.swap, &gnum);
518 if (gwins)
519 {
520 for (i = 0; i < gnum; i++)
521 {
522 for (j = 0; j < num; j++)
523 {
524 if ((lst[j] == gwins[i]) || (lst[j] == ewin))
525 lst[j] = NULL;
526 }
527 }
528 Efree(gwins);
529 }
530
531 odx = dx;
532 ody = dy;
533 if (dx < 0)
534 {
535 if (IN_BELOW(ewin->shape_x + dx, left_bound, screen_snap_dist)
536 && (ewin->shape_x >= left_bound))
537 {
538 dx = left_bound - ewin->shape_x;
539 }
540 else
541 {
542 for (i = 0; i < num; i++)
543 {
544 if (!lst[i])
545 continue;
546
547 if ((EoGetDesk(ewin) == EoGetDesk(lst[i]) ||
548 EoIsSticky(lst[i])) && !(EoIsFloating(lst[i])) &&
549 !lst[i]->state.iconified && !lst[i]->props.ignorearrange)
550 {
551 if (IN_BELOW
552 (ewin->shape_x + dx,
553 EoGetX(lst[i]) + EoGetW(lst[i]) - 1,
554 Conf.snap.edge_snap_dist)
555 && SPANS_COMMON(ewin->shape_y, EoGetH(ewin),
556 EoGetY(lst[i]), EoGetH(lst[i]))
557 && (ewin->shape_x >=
558 (EoGetX(lst[i]) + EoGetW(lst[i]))))
559 {
560 dx =
561 (EoGetX(lst[i]) + EoGetW(lst[i])) -
562 ewin->shape_x;
563 break;
564 }
565 }
566 }
567 }
568 if ((ewin->req_x - ewin->shape_x) > 0)
569 dx = 0;
570 }
571 else if (dx > 0)
572 {
573 if (IN_ABOVE
574 (ewin->shape_x + EoGetW(ewin) + dx, right_bound, screen_snap_dist)
575 && ((ewin->shape_x + EoGetW(ewin)) <= right_bound))
576 {
577 dx = right_bound - (ewin->shape_x + EoGetW(ewin));
578 }
579 else
580 {
581 for (i = 0; i < num; i++)
582 {
583 if (!lst[i])
584 continue;
585
586 if ((EoGetDesk(ewin) == EoGetDesk(lst[i]) ||
587 EoIsSticky(lst[i])) && !(EoIsFloating(lst[i])) &&
588 !lst[i]->state.iconified && !lst[i]->props.ignorearrange)
589 {
590 if (IN_ABOVE
591 (ewin->shape_x + EoGetW(ewin) + dx - 1,
592 EoGetX(lst[i]), Conf.snap.edge_snap_dist)
593 && SPANS_COMMON(ewin->shape_y, EoGetH(ewin),
594 EoGetY(lst[i]), EoGetH(lst[i]))
595 && ((ewin->shape_x + EoGetW(ewin)) <=
596 EoGetX(lst[i])))
597 {
598 dx =
599 EoGetX(lst[i]) - (ewin->shape_x + EoGetW(ewin));
600 break;
601 }
602 }
603 }
604 }
605 if ((ewin->req_x - ewin->shape_x) < 0)
606 dx = 0;
607 }
608
609 if (dy < 0)
610 {
611 if (IN_BELOW(ewin->shape_y + dy, top_bound, screen_snap_dist)
612 && (ewin->shape_y >= top_bound))
613 {
614 dy = top_bound - ewin->shape_y;
615 }
616 else
617 {
618 for (i = 0; i < num; i++)
619 {
620 if (!lst[i])
621 continue;
622
623 if ((EoGetDesk(ewin) == EoGetDesk(lst[i]) ||
624 EoIsSticky(lst[i])) && !(EoIsFloating(lst[i])) &&
625 !lst[i]->state.iconified && !lst[i]->props.ignorearrange)
626 {
627 if (IN_BELOW
628 (ewin->shape_y + dy,
629 EoGetY(lst[i]) + EoGetH(lst[i]) - 1,
630 Conf.snap.edge_snap_dist)
631 && SPANS_COMMON(ewin->shape_x, EoGetW(ewin),
632 EoGetX(lst[i]), EoGetW(lst[i]))
633 && (ewin->shape_y >=
634 (EoGetY(lst[i]) + EoGetH(lst[i]))))
635 {
636 dy =
637 (EoGetY(lst[i]) + EoGetH(lst[i])) -
638 ewin->shape_y;
639 break;
640 }
641 }
642 }
643 }
644 if ((ewin->req_y - ewin->shape_y) > 0)
645 dy = 0;
646 }
647 else if (dy > 0)
648 {
649 if (IN_ABOVE
650 (ewin->shape_y + EoGetH(ewin) + dy, bottom_bound,
651 screen_snap_dist)
652 && ((ewin->shape_y + EoGetH(ewin)) <= bottom_bound))
653 {
654 dy = bottom_bound - (ewin->shape_y + EoGetH(ewin));
655 }
656 else
657 {
658 for (i = 0; i < num; i++)
659 {
660 if (!lst[i])
661 continue;
662
663 if ((EoGetDesk(ewin) == EoGetDesk(lst[i]) ||
664 EoIsSticky(lst[i])) && !(EoIsFloating(lst[i])) &&
665 !lst[i]->state.iconified && !lst[i]->props.ignorearrange)
666 {
667 if (IN_ABOVE
668 (ewin->shape_y + EoGetH(ewin) + dy - 1,
669 EoGetY(lst[i]), Conf.snap.edge_snap_dist)
670 && SPANS_COMMON(ewin->shape_x, EoGetW(ewin),
671 EoGetX(lst[i]), EoGetW(lst[i]))
672 && ((ewin->shape_y + EoGetH(ewin)) <=
673 EoGetY(lst[i])))
674 {
675 dy =
676 EoGetY(lst[i]) - (ewin->shape_y + EoGetH(ewin));
677 break;
678 }
679 }
680 }
681 }
682 if ((ewin->req_y - ewin->shape_y) < 0)
683 dy = 0;
684 }
685
686 Efree(lst);
687
688 if ((odx != dx) || (ody != dy))
689 {
690 if (!last_res)
691 {
692 /* SoundPlay(SOUND_MOVE_RESIST); */
693 last_res = 1;
694 }
695 }
696 else
697 {
698 last_res = 0;
699 }
700 *new_dx = dx;
701 *new_dy = dy;
702 }
703
704 void
ArrangeEwin(EWin * ewin)705 ArrangeEwin(EWin * ewin)
706 {
707 int x, y;
708
709 ArrangeEwinXY(ewin, &x, &y);
710 EwinMove(ewin, x, y, 0);
711 }
712
713 void
ArrangeEwinCentered(EWin * ewin)714 ArrangeEwinCentered(EWin * ewin)
715 {
716 int x, y;
717
718 ArrangeEwinCenteredXY(ewin, &x, &y);
719 EwinMove(ewin, x, y, 0);
720 }
721
722 static void
ArrangeGetRectList(RectBox ** pfixed,int * nfixed,RectBox ** pfloating,int * nfloating,EWin * ewin)723 ArrangeGetRectList(RectBox ** pfixed, int *nfixed, RectBox ** pfloating,
724 int *nfloating, EWin * ewin)
725 {
726 RectBox *rb, *fixed, *floating;
727 int x, y, w, h, i, nfix, nflt, num;
728 EObj *const *lst, *eo;
729 Desk *dsk;
730
731 fixed = floating = NULL;
732 nfix = nflt = 0;
733
734 lst = EobjListStackGet(&num);
735 if (!lst)
736 goto done;
737
738 fixed = EMALLOC(RectBox, num);
739 if (!fixed)
740 goto done;
741
742 dsk = (ewin) ? EoGetDesk(ewin) : DesksGetCurrent();
743
744 for (i = 0; i < num; i++)
745 {
746 rb = fixed + nfix;
747 eo = lst[i];
748
749 if (!eo->shown)
750 continue;
751
752 if (eo->type == EOBJ_TYPE_EWIN)
753 {
754 EWin *ew = (EWin *) eo;
755
756 if (ew == ewin)
757 continue;
758 if (eo->desk != dsk)
759 continue;
760
761 if (ew->props.ignorearrange || EoGetLayer(ew) == 0)
762 continue;
763
764 if (pfloating)
765 {
766 int ax, ay;
767
768 DeskGetArea(EoGetDesk(ew), &ax, &ay);
769
770 if (!EoIsSticky(ew) && !EoIsFloating(ew) &&
771 ew->area_x == ax && ew->area_y == ay)
772 {
773 floating = EREALLOC(RectBox, floating, nflt + 1);
774 rb = floating + nflt++;
775 rb->data = ew;
776 rb->x = EoGetX(ew);
777 rb->y = EoGetY(ew);
778 rb->w = EoGetW(ew);
779 rb->h = EoGetH(ew);
780 rb->p = EoGetLayer(ew);
781 #if DEBUG_ARRANGE
782 Eprintf("Add float: x,y=%4d,%4d wxh=%3dx%3d p=%2d: %s\n",
783 rb->x, rb->y, rb->w, rb->h, rb->p,
784 EobjGetName(eo));
785 #endif
786 continue;
787 }
788 }
789
790 rb->data = ew;
791
792 if (ew->props.never_use_area)
793 rb->p = 100;
794 else
795 rb->p = EoGetLayer(ew);
796 }
797 else if (eo->type == EOBJ_TYPE_BUTTON)
798 {
799 if (!eo->sticky && eo->desk != dsk)
800 continue;
801
802 rb->data = NULL;
803 rb->p = (eo->sticky) ? 1 : 0;
804 }
805 else
806 {
807 continue;
808 }
809
810 x = EobjGetX(eo);
811 y = EobjGetY(eo);
812 w = EobjGetW(eo);
813 h = EobjGetH(eo);
814
815 if (x < 0)
816 {
817 w += x;
818 x = 0;
819 }
820 if ((x + w) > WinGetW(VROOT))
821 w = WinGetW(VROOT) - x;
822
823 if (y < 0)
824 {
825 h += y;
826 y = 0;
827 }
828 if ((y + h) > WinGetH(VROOT))
829 h = WinGetH(VROOT) - y;
830
831 if ((w <= 0) || (h <= 0))
832 continue;
833
834 rb->x = x;
835 rb->y = y;
836 rb->w = w;
837 rb->h = h;
838 #if DEBUG_ARRANGE
839 Eprintf("Add fixed: x,y=%4d,%4d wxh=%3dx%3d p=%2d: %s\n", rb->x, rb->y,
840 rb->w, rb->h, rb->p, EobjGetName(eo));
841 #endif
842
843 nfix++;
844 }
845
846 done:
847 #if DEBUG_ARRANGE
848 Eprintf("Fixed: %p/%d Floating: %p/%d\n", fixed, nfix, floating, nflt);
849 #endif
850 *pfixed = fixed;
851 *nfixed = nfix;
852 if (pfloating)
853 *pfloating = floating;
854 if (nfloating)
855 *nfloating = nflt;
856 }
857
858 void
ArrangeEwinXY(EWin * ewin,int * px,int * py)859 ArrangeEwinXY(EWin * ewin, int *px, int *py)
860 {
861 int i, num;
862 RectBox *fixed, *ret, newrect;
863
864 *px = *py = 0;
865
866 if (!ewin)
867 return;
868
869 EwinListGetAll(&num);
870 if (num <= 1)
871 {
872 ArrangeEwinCenteredXY(ewin, px, py);
873 return;
874 }
875
876 fixed = NULL;
877 ArrangeGetRectList(&fixed, &num, NULL, NULL, ewin);
878
879 newrect.data = ewin;
880 newrect.x = 0;
881 newrect.y = 0;
882 newrect.w = EoGetW(ewin);
883 newrect.h = EoGetH(ewin);
884 newrect.p = EoGetLayer(ewin);
885
886 ret = ECALLOC(RectBox, num + 1);
887 if (!ret)
888 goto done;
889
890 ArrangeRects(fixed, num, &newrect, 1, ret, 0, 0,
891 WinGetW(VROOT), WinGetH(VROOT), ARRANGE_BY_SIZE, 1);
892
893 for (i = 0; i < num + 1; i++)
894 {
895 if (ret[i].data == ewin)
896 {
897 *px = ret[i].x;
898 *py = ret[i].y;
899 break;
900 }
901 }
902
903 done:
904 Efree(ret);
905 Efree(fixed);
906 }
907
908 void
ArrangeEwinCenteredXY(EWin * ewin,int * px,int * py)909 ArrangeEwinCenteredXY(EWin * ewin, int *px, int *py)
910 {
911 int x, y, w, h;
912
913 ScreenGetAvailableAreaByPointer(&x, &y, &w, &h, Conf.place.ignore_struts);
914 *px = (w - EoGetW(ewin)) / 2 + x;
915 *py = (h - EoGetH(ewin)) / 2 + y;
916 }
917
918 void
ArrangeEwinCenteredOn(EWin * ewin,int x,int y,int w,int h,int * px,int * py)919 ArrangeEwinCenteredOn(EWin * ewin, int x, int y, int w, int h, int *px, int *py)
920 {
921 int sx, sy, sw, sh;
922
923 x += (w - EoGetW(ewin)) / 2;
924 y += (h - EoGetH(ewin)) / 2;
925
926 ScreenGetAvailableArea(x, y, &sx, &sy, &sw, &sh, Conf.place.ignore_struts);
927
928 /* keep it all on this screen if possible */
929 x = MIN(x, sx + sw - EoGetW(ewin));
930 y = MIN(y, sy + sh - EoGetH(ewin));
931 x = MAX(x, sx);
932 y = MAX(y, sy);
933
934 *px = x;
935 *py = y;
936 }
937
938 void
ArrangeEwins(const char * params)939 ArrangeEwins(const char *params)
940 {
941 const char *type;
942 int method;
943 int i, nfix, nflt, num;
944 RectBox *fixed, *ret, *floating;
945 EWin *const *lst, *ewin;
946
947 type = params;
948 method = ARRANGE_BY_SIZE;
949
950 if (params)
951 {
952 if (!strcmp("order", type))
953 {
954 method = ARRANGE_VERBATIM;
955 }
956 else if (!strcmp("place", type))
957 {
958 method = ARRANGE_BY_POSITION;
959 }
960 }
961
962 fixed = floating = ret = NULL;
963
964 lst = EwinListGetAll(&num);
965 if (!lst)
966 goto done;
967
968 ArrangeGetRectList(&fixed, &nfix, &floating, &nflt, NULL);
969
970 ret = ECALLOC(RectBox, nflt + nfix);
971 if (!ret)
972 goto done;
973
974 ArrangeRects(fixed, nfix, floating, nflt, ret, 0, 0,
975 WinGetW(VROOT), WinGetH(VROOT), method, 1);
976
977 for (i = nfix; i < nflt + nfix; i++)
978 {
979 if (!ret[i].data)
980 continue;
981
982 ewin = (EWin *) ret[i].data;
983 if ((EoGetX(ewin) == ret[i].x) && (EoGetY(ewin) == ret[i].y))
984 continue;
985
986 if (Conf.place.cleanupslide)
987 EwinSlideTo(ewin, EoGetX(ewin), EoGetY(ewin),
988 ret[i].x, ret[i].y, Conf.place.slidespeedcleanup,
989 Conf.place.slidemode, 0);
990 else
991 EwinMove(ewin, ret[i].x, ret[i].y, 0);
992 }
993
994 done:
995 Efree(fixed);
996 Efree(ret);
997 Efree(floating);
998 }
999