2 * Copyright (C) 2000-2007 Carsten Haitzler, Geoff Harrison and various contributors
3 * Copyright (C) 2004-2008 Kim Woelders
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:
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.
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.
30 #define DEBUG_ARRANGE 0
44 ArrangeAddToList(int *array, int current_size, int value)
48 if (current_size >= 2 &&
49 (value <= array[0] || value >= array[current_size - 1]))
52 for (i = 0; i < current_size; i++)
56 for (j = current_size; j > i; j--)
57 array[j] = array[j - 1];
59 return current_size + 1;
61 else if (value == array[i])
64 array[current_size] = value;
65 return current_size + 1;
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)
73 int j, x1, x2, y1, y2;
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);
87 for (j = 0; j < num_sorted; j++)
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);
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);
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]);
113 #define Filled(x,y) (filled[(y * (xsize - 1)) + x])
116 ArrangeMakeFillLists(const RectBox * sorted, int num_sorted,
117 int *xarray, int xsize, int *yarray, int ysize,
118 unsigned char *filled)
120 int j, x1, x2, y1, y2, k, y, x;
122 /* fill the allocation array */
123 for (j = 0; j < (xsize - 1) * (ysize - 1); filled[j++] = 0)
125 for (j = 0; j < num_sorted; j++)
131 for (k = 0; k < xsize - 1; k++)
132 if (sorted[j].x == xarray[k])
137 for (k++; k < xsize - 1; k++)
138 if (sorted[j].x + sorted[j].w > xarray[k])
140 for (k = 0; k < ysize - 1; k++)
141 if (sorted[j].y == yarray[k])
146 for (k++; k < ysize - 1; k++)
147 if (sorted[j].y + sorted[j].h > yarray[k])
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]);
154 if ((x1 >= 0) && (x2 >= 0) && (y1 >= 0) && (y2 >= 0))
156 for (y = y1; y <= y2; y++)
158 for (x = x1; x <= x2; x++)
160 Filled(x, y) += sorted[j].p;
167 Eprintf("Filled[%2d,%2d] =\n", xsize, ysize);
168 for (k = 0; k < ysize - 1; k++)
170 for (j = 0; j < xsize - 1; j++)
171 printf(" %2d", Filled(j, k));
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)
182 int i, j, w, h, fw, fh, z1, z2;
184 int num_spaces = *ns;
186 if (wx < xarray[0] || (wx != xarray[0] && wx + ww > xarray[xsize - 1]))
188 if (wy < yarray[0] || (wy != yarray[0] && wy + wh > yarray[ysize - 1]))
193 #if DEBUG_ARRANGE > 1
194 Eprintf("Check-A %d,%d %dx%d\n", wx, wy, ww, wh);
196 for (j = 0; j < ysize - 1; j++)
202 z1 = wy > yarray[j] ? wy : yarray[j];
203 z2 = wy + wh < z2 ? wy + wh : z2;
206 for (i = 0; i < xsize - 1; i++)
212 z1 = wx > xarray[i] ? wx : xarray[i];
213 z2 = wx + ww < z2 ? wx + ww : z2;
215 #if DEBUG_ARRANGE > 1
216 Eprintf("Add [%d,%d] %3dx%3d: %2d\n", i, j, w, h, Filled(i, j));
218 if (Filled(i, j) == 0)
221 cost += w * h * Filled(i, j);
232 Eprintf("Check %4d,%4d %3dx%3d cost=%d desk=%d\n", wx, wy, ww, wh,
235 spaces[num_spaces].x = wx;
236 spaces[num_spaces].y = wy;
237 spaces[num_spaces].p = cost;
238 spaces[num_spaces].q = desk;
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)
248 int ix, iy, fx, fy, fw, fh;
250 /* create list of all "spaces" */
254 for (iy = 0; iy < ysize; iy++)
258 for (ix = 0; ix < xsize; ix++)
262 ArrangeFindSpace(xarray, xsize, yarray, ysize, filled, spaces, ns,
264 if (*ns >= max_spaces)
274 ArrangeSwapList(RectBox * list, int a, int b)
278 bb.data = list[a].data;
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;
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)
301 int tx1, ty1, tx2, ty2;
302 int xsize = 0, ysize = 0;
303 int *xarray, *yarray;
305 unsigned char *filled;
307 int num_spaces, alloc_spaces;
313 tx2 = startx + width;
314 ty2 = starty + height;
317 int xx1, yy1, xx2, yy2;
319 ScreenGetAvailableAreaByPointer(&xx1, &yy1, &xx2, &yy2);
332 Eprintf("Target area %d,%d -> %d,%d\n", tx1, ty1, tx2, ty2);
337 case ARRANGE_VERBATIM:
339 case ARRANGE_BY_SIZE:
344 for (i = 0; i < floating_count - 1; i++)
346 a1 = floating[i].w * floating[i].h;
347 a2 = floating[i + 1].w * floating[i + 1].h;
351 ArrangeSwapList(floating, i, i + 1);
356 case ARRANGE_BY_POSITION:
361 for (i = 0; i < floating_count - 1; i++)
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));
369 ArrangeSwapList(floating, i, i + 1);
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);
387 if (!xarray || !yarray)
390 /* copy "fixed" rects into the sorted list */
391 memcpy(sorted, fixed, fixed_count * sizeof(RectBox));
392 num_sorted = fixed_count;
394 /* go through each floating rect in order and "fit" it in */
395 for (i = 0; i < floating_count; i++)
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)
402 unsigned char *ptr_f;
405 ptr_f = EREALLOC(unsigned char, filled, num_spaces);
409 ptr_s = EREALLOC(RectInfo, spaces, num_spaces);
412 if (!ptr_f || !ptr_s)
414 alloc_spaces = num_spaces;
416 ArrangeMakeFillLists(sorted, num_sorted,
417 xarray, xsize, yarray, ysize, filled);
419 /* create list of all "spaces" */
420 ArrangeFindSpaces(xarray, xsize, yarray, ysize, filled,
421 spaces, alloc_spaces, &num_spaces, floating + i);
423 /* find the first space that fits */
425 sort = 0x7fffffff; /* NB! Break at 0 == free space */
426 for (j = 0; j < num_spaces; j++)
428 a1 = spaces[j].p - spaces[j].q * 4;
436 if (spaces[k].q == 0 && Conf.place.center_if_desk_full)
438 sorted[num_sorted].x = (tx1 + tx2 - floating[i].w) / 2;
439 sorted[num_sorted].y = (ty1 + ty2 - floating[i].h) / 2;
443 sorted[num_sorted].x = spaces[k].x;
444 sorted[num_sorted].y = spaces[k].y;
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;
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) : "?");
469 SnapEwin(EWin * ewin, int dx, int dy, int *new_dx, int *new_dy)
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;
480 if (!Conf.snap.enable)
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;
494 lst1 = EwinListOrderGet(&num);
497 lst = EMALLOC(EWin *, num);
500 memcpy(lst, lst1, num * sizeof(EWin *));
502 gwins = ListWinGroupMembersForEwin(ewin, GROUP_ACTION_MOVE, Mode.nogroup
503 || Mode.move.swap, &gnum);
506 for (i = 0; i < gnum; i++)
508 for (j = 0; j < num; j++)
510 if ((lst[j] == gwins[i]) || (lst[j] == ewin))
521 if (IN_BELOW(ewin->shape_x + dx, left_bound, screen_snap_dist)
522 && (ewin->shape_x >= left_bound))
524 dx = left_bound - ewin->shape_x;
528 for (i = 0; i < num; i++)
533 if ((EoGetDesk(ewin) == EoGetDesk(lst[i]) ||
534 EoIsSticky(lst[i])) && !(EoIsFloating(lst[i])) &&
535 !lst[i]->state.iconified && !lst[i]->props.ignorearrange)
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]))
544 (EoGetX(lst[i]) + EoGetW(lst[i]))))
547 (EoGetX(lst[i]) + EoGetW(lst[i])) -
554 if ((ewin->req_x - ewin->shape_x) > 0)
560 (ewin->shape_x + EoGetW(ewin) + dx, right_bound, screen_snap_dist)
561 && ((ewin->shape_x + EoGetW(ewin)) <= right_bound))
563 dx = right_bound - (ewin->shape_x + EoGetW(ewin));
567 for (i = 0; i < num; i++)
572 if ((EoGetDesk(ewin) == EoGetDesk(lst[i]) ||
573 EoIsSticky(lst[i])) && !(EoIsFloating(lst[i])) &&
574 !lst[i]->state.iconified && !lst[i]->props.ignorearrange)
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)) <=
585 EoGetX(lst[i]) - (ewin->shape_x + EoGetW(ewin));
591 if ((ewin->req_x - ewin->shape_x) < 0)
597 if (IN_BELOW(ewin->shape_y + dy, top_bound, screen_snap_dist)
598 && (ewin->shape_y >= top_bound))
600 dy = top_bound - ewin->shape_y;
604 for (i = 0; i < num; i++)
609 if ((EoGetDesk(ewin) == EoGetDesk(lst[i]) ||
610 EoIsSticky(lst[i])) && !(EoIsFloating(lst[i])) &&
611 !lst[i]->state.iconified && !lst[i]->props.ignorearrange)
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]))
620 (EoGetY(lst[i]) + EoGetH(lst[i]))))
623 (EoGetY(lst[i]) + EoGetH(lst[i])) -
630 if ((ewin->req_y - ewin->shape_y) > 0)
636 (ewin->shape_y + EoGetH(ewin) + dy, bottom_bound,
638 && ((ewin->shape_y + EoGetH(ewin)) <= bottom_bound))
640 dy = bottom_bound - (ewin->shape_y + EoGetH(ewin));
644 for (i = 0; i < num; i++)
649 if ((EoGetDesk(ewin) == EoGetDesk(lst[i]) ||
650 EoIsSticky(lst[i])) && !(EoIsFloating(lst[i])) &&
651 !lst[i]->state.iconified && !lst[i]->props.ignorearrange)
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)) <=
662 EoGetY(lst[i]) - (ewin->shape_y + EoGetH(ewin));
668 if ((ewin->req_y - ewin->shape_y) < 0)
674 if ((odx != dx) || (ody != dy))
678 /* SoundPlay(SOUND_MOVE_RESIST); */
691 ArrangeEwin(EWin * ewin)
695 ArrangeEwinXY(ewin, &x, &y);
696 EwinMove(ewin, x, y);
700 ArrangeEwinCentered(EWin * ewin)
704 ArrangeEwinCenteredXY(ewin, &x, &y);
705 EwinMove(ewin, x, y);
709 ArrangeGetRectList(RectBox ** pfixed, int *nfixed, RectBox ** pfloating,
710 int *nfloating, EWin * ewin)
712 RectBox *rb, *fixed, *floating;
713 int x, y, w, h, i, nfix, nflt, num;
714 EObj *const *lst, *eo;
717 fixed = floating = NULL;
720 lst = EobjListStackGet(&num);
724 fixed = EMALLOC(RectBox, num);
729 dsk = (ewin) ? EoGetDesk(ewin) : DesksGetCurrent();
731 for (i = 0; i < num; i++)
739 if (eo->type == EOBJ_TYPE_EWIN)
741 EWin *ew = (EWin *) eo;
748 if (ew->props.ignorearrange || EoGetLayer(ew) == 0)
755 DeskGetArea(EoGetDesk(ew), &ax, &ay);
757 if (!EoIsSticky(ew) && !EoIsFloating(ew) &&
758 ew->area_x == ax && ew->area_y == ay)
760 floating = EREALLOC(RectBox, floating, nflt + 1);
761 rb = floating + nflt++;
767 rb->p = EoGetLayer(ew);
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,
779 if (ew->props.never_use_area)
782 rb->p = EoGetLayer(ew);
784 else if (eo->type == EOBJ_TYPE_BUTTON)
786 if (!eo->sticky && eo->desk != dsk)
790 rb->p = (eo->sticky) ? 1 : 0;
807 if ((x + w) > WinGetW(VROOT))
808 w = WinGetW(VROOT) - x;
815 if ((y + h) > WinGetH(VROOT))
816 h = WinGetH(VROOT) - y;
818 if ((w <= 0) || (h <= 0))
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));
835 Eprintf("Fixed: %p/%d Floating: %p/%d\n", fixed, nfix, floating, nflt);
840 *pfloating = floating;
846 ArrangeEwinXY(EWin * ewin, int *px, int *py)
850 RectBox *fixed, *ret, newrect;
855 lst = EwinListGetAll(&num);
858 ArrangeEwinCenteredXY(ewin, px, py);
862 ArrangeGetRectList(&fixed, &num, NULL, NULL, ewin);
867 newrect.w = EoGetW(ewin);
868 newrect.h = EoGetH(ewin);
869 newrect.p = EoGetLayer(ewin);
871 ret = ECALLOC(RectBox, num + 1);
872 ArrangeRects(fixed, num, &newrect, 1, ret, 0, 0,
873 WinGetW(VROOT), WinGetH(VROOT), ARRANGE_BY_SIZE, 1);
875 for (i = 0; i < num + 1; i++)
877 if (ret[i].data == ewin)
889 ArrangeEwinCenteredXY(EWin * ewin, int *px, int *py)
893 ScreenGetAvailableAreaByPointer(&x, &y, &w, &h);
894 *px = (w - EoGetW(ewin)) / 2 + x;
895 *py = (h - EoGetH(ewin)) / 2 + y;
899 ArrangeEwins(const char *params)
903 int i, nfix, nflt, num;
904 RectBox *fixed, *ret, *floating;
905 EWin *const *lst, *ewin;
908 method = ARRANGE_BY_SIZE;
912 if (!strcmp("order", type))
914 method = ARRANGE_VERBATIM;
916 else if (!strcmp("place", type))
918 method = ARRANGE_BY_POSITION;
922 lst = EwinListGetAll(&num);
926 ArrangeGetRectList(&fixed, &nfix, &floating, &nflt, NULL);
928 ret = ECALLOC(RectBox, nflt + nfix);
929 ArrangeRects(fixed, nfix, floating, nflt, ret, 0, 0,
930 WinGetW(VROOT), WinGetH(VROOT), method, 1);
932 for (i = nfix; i < nflt + nfix; i++)
937 ewin = (EWin *) ret[i].data;
938 if ((EoGetX(ewin) == ret[i].x) && (EoGetY(ewin) == ret[i].y))
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);
946 EwinMove(ewin, ret[i].x, ret[i].y);