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