]> icculus.org git repositories - mikachu/openbox.git/blob - src/Workspace.cc
make work without --enable-xinerama
[mikachu/openbox.git] / src / Workspace.cc
1 // -*- mode: C++; indent-tabs-mode: nil; c-basic-offset: 2; -*-
2 // Workspace.cc for Blackbox - an X11 Window manager
3 // Copyright (c) 2001 - 2002 Sean 'Shaleh' Perry <shaleh@debian.org>
4 // Copyright (c) 1997 - 2000 Brad Hughes (bhughes@tcac.net)
5 //
6 // Permission is hereby granted, free of charge, to any person obtaining a
7 // copy of this software and associated documentation files (the "Software"),
8 // to deal in the Software without restriction, including without limitation
9 // the rights to use, copy, modify, merge, publish, distribute, sublicense,
10 // and/or sell copies of the Software, and to permit persons to whom the
11 // Software is furnished to do so, subject to the following conditions:
12 //
13 // The above copyright notice and this permission notice shall be included in
14 // all copies or substantial portions of the Software.
15 //
16 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
19 // THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
21 // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
22 // DEALINGS IN THE SOFTWARE.
23
24 #ifdef    HAVE_CONFIG_H
25 #  include "../config.h"
26 #endif // HAVE_CONFIG_H
27
28 extern "C" {
29 #include <X11/Xlib.h>
30 #include <X11/Xatom.h>
31
32 #ifdef    HAVE_STDIO_H
33 #  include <stdio.h>
34 #endif // HAVE_STDIO_H
35
36 #ifdef HAVE_STRING_H
37 #  include <string.h>
38 #endif // HAVE_STRING_H
39 }
40
41 #include <assert.h>
42
43 #include <functional>
44 #include <string>
45
46 using std::string;
47
48 #include "i18n.hh"
49 #include "blackbox.hh"
50 #include "Clientmenu.hh"
51 #include "Netizen.hh"
52 #include "Screen.hh"
53 #include "Toolbar.hh"
54 #include "Util.hh"
55 #include "Window.hh"
56 #include "Workspace.hh"
57 #include "Windowmenu.hh"
58 #include "XAtom.hh"
59
60
61 Workspace::Workspace(BScreen *scrn, unsigned int i) {
62   screen = scrn;
63   xatom = screen->getBlackbox()->getXAtom();
64
65   cascade_x = cascade_y = 32;
66
67   id = i;
68
69   clientmenu = new Clientmenu(this);
70
71   lastfocus = (BlackboxWindow *) 0;
72
73   readName();
74 }
75
76
77 void Workspace::addWindow(BlackboxWindow *w, bool place) {
78   assert(w != 0);
79
80   if (place) placeWindow(w);
81
82   stackingList.push_front(w);
83     
84   if (w->isNormal()) {
85     w->setWorkspace(id);
86     w->setWindowNumber(windowList.size());
87
88     windowList.push_back(w);
89
90     clientmenu->insert(w->getTitle());
91     clientmenu->update();
92
93     screen->updateNetizenWindowAdd(w->getClientWindow(), id);
94
95     if (id != screen->getCurrentWorkspaceID() &&
96         screen->doFocusNew()) {
97       /*
98          not on the focused workspace, so the window is not going to get focus
99          but if the user wants new windows focused, then it should get focus
100          when this workspace does become focused.
101       */
102       lastfocus = w;
103     }
104   }
105
106   if (! w->isDesktop())
107     raiseWindow(w);
108   else
109     lowerWindow(w);
110 }
111
112
113 void Workspace::removeWindow(BlackboxWindow *w) {
114   assert(w != 0);
115
116   stackingList.remove(w);
117
118   // pass focus to the next appropriate window
119   if ((w->isFocused() || w == lastfocus) &&
120       ! screen->getBlackbox()->doShutdown()) {
121     focusFallback(w);
122
123     // if the window is sticky, then it needs to be removed on all other
124     // workspaces too!
125     if (w->isStuck()) {
126       for (unsigned int i = 0; i < screen->getWorkspaceCount(); ++i)
127         if (i != id)
128           screen->getWorkspace(i)->focusFallback(w);
129     }
130   }
131
132   if (! w->isNormal()) return;
133
134   windowList.remove(w);
135   clientmenu->remove(w->getWindowNumber());
136   clientmenu->update();
137
138   screen->updateNetizenWindowDel(w->getClientWindow());
139
140   BlackboxWindowList::iterator it = windowList.begin();
141   const BlackboxWindowList::iterator end = windowList.end();
142   unsigned int i = 0;
143   for (; it != end; ++it, ++i)
144     (*it)->setWindowNumber(i);
145
146   if (i == 0)
147     cascade_x = cascade_y = 32;
148 }
149
150
151 void Workspace::focusFallback(const BlackboxWindow *old_window) {
152   BlackboxWindow *newfocus = 0;
153
154   if (id == screen->getCurrentWorkspaceID()) {
155     // The window is on the visible workspace.
156
157     // if it's a transient, then try to focus its parent
158     if (old_window && old_window->isTransient()) {
159       newfocus = old_window->getTransientFor();
160
161       if (! newfocus ||
162           newfocus->isIconic() ||                  // do not focus icons
163           newfocus->getWorkspaceNumber() != id ||  // or other workspaces
164           ! newfocus->setInputFocus())
165         newfocus = 0;
166     }
167
168     if (! newfocus) {
169       BlackboxWindowList::iterator it = stackingList.begin(),
170                                   end = stackingList.end();
171       for (; it != end; ++it) {
172         BlackboxWindow *tmp = *it;
173         if (tmp && tmp->isNormal() && tmp->setInputFocus()) {
174           // we found our new focus target
175           newfocus = tmp;
176           break;
177         }
178       }
179     }
180
181     screen->getBlackbox()->setFocusedWindow(newfocus);
182   } else {
183     // The window is not on the visible workspace.
184
185     if (old_window && lastfocus == old_window) {
186       // The window was the last-focus target, so we need to replace it.
187       BlackboxWindow *win = (BlackboxWindow*) 0;
188       if (! stackingList.empty())
189         win = stackingList.front();
190       setLastFocusedWindow(win);
191     }
192   }
193 }
194
195
196 void Workspace::showAll(void) {
197   BlackboxWindowList::iterator it = stackingList.begin();
198   const BlackboxWindowList::iterator end = stackingList.end();
199   for (; it != end; ++it) {
200     BlackboxWindow *bw = *it;
201     if (! bw->isStuck())
202       bw->show();
203   }
204 }
205
206
207 void Workspace::hideAll(void) {
208   // withdraw in reverse order to minimize the number of Expose events
209   BlackboxWindowList::reverse_iterator it = stackingList.rbegin();
210   const BlackboxWindowList::reverse_iterator end = stackingList.rend();
211   while (it != end) {
212     BlackboxWindow *bw = *it;
213     ++it; // withdraw removes the current item from the list so we need the next
214           // iterator before that happens
215     if (! bw->isStuck())
216       bw->withdraw();
217   }
218 }
219
220
221 void Workspace::removeAll(void) {
222   while (! windowList.empty())
223     windowList.front()->iconify();
224 }
225
226
227 /*
228  * returns the number of transients for win, plus the number of transients
229  * associated with each transient of win
230  */
231 static int countTransients(const BlackboxWindow * const win) {
232   int ret = win->getTransients().size();
233   if (ret > 0) {
234     BlackboxWindowList::const_iterator it, end = win->getTransients().end();
235     for (it = win->getTransients().begin(); it != end; ++it) {
236       ret += countTransients(*it);
237     }
238   }
239   return ret;
240 }
241
242
243 /*
244  * puts the transients of win into the stack. windows are stacked above
245  * the window before it in the stackvector being iterated, meaning
246  * stack[0] is on bottom, stack[1] is above stack[0], stack[2] is above
247  * stack[1], etc...
248  */
249 void Workspace::raiseTransients(const BlackboxWindow * const win,
250                                 StackVector::iterator &stack) {
251   if (win->getTransients().size() == 0) return; // nothing to do
252
253   // put win's transients in the stack
254   BlackboxWindowList::const_iterator it, end = win->getTransients().end();
255   for (it = win->getTransients().begin(); it != end; ++it) {
256     *stack++ = (*it)->getFrameWindow();
257     screen->updateNetizenWindowRaise((*it)->getClientWindow());
258
259     if (! (*it)->isIconic()) {
260       Workspace *wkspc = screen->getWorkspace((*it)->getWorkspaceNumber());
261       wkspc->stackingList.remove((*it));
262       wkspc->stackingList.push_front((*it));
263     }
264   }
265
266   // put transients of win's transients in the stack
267   for (it = win->getTransients().begin(); it != end; ++it) {
268     raiseTransients(*it, stack);
269   }
270 }
271
272
273 void Workspace::lowerTransients(const BlackboxWindow * const win,
274                                 StackVector::iterator &stack) {
275   if (win->getTransients().size() == 0) return; // nothing to do
276
277   // put transients of win's transients in the stack
278   BlackboxWindowList::const_reverse_iterator it,
279     end = win->getTransients().rend();
280   for (it = win->getTransients().rbegin(); it != end; ++it) {
281     lowerTransients(*it, stack);
282   }
283
284   // put win's transients in the stack
285   for (it = win->getTransients().rbegin(); it != end; ++it) {
286     *stack++ = (*it)->getFrameWindow();
287     screen->updateNetizenWindowLower((*it)->getClientWindow());
288
289     if (! (*it)->isIconic()) {
290       Workspace *wkspc = screen->getWorkspace((*it)->getWorkspaceNumber());
291       wkspc->stackingList.remove((*it));
292       wkspc->stackingList.push_back((*it));
293     }
294   }
295 }
296
297
298 void Workspace::raiseWindow(BlackboxWindow *w) {
299   BlackboxWindow *win = w;
300
301   if (win->isDesktop()) return;
302
303   // walk up the transient_for's to the window that is not a transient
304   while (win->isTransient() && ! win->isDesktop()) {
305     if (! win->getTransientFor()) break;
306     win = win->getTransientFor();
307   }
308
309   // get the total window count (win and all transients)
310   unsigned int i = 1 + countTransients(win);
311
312   // stack the window with all transients above
313   StackVector stack_vector(i);
314   StackVector::iterator stack = stack_vector.begin();
315
316   *(stack++) = win->getFrameWindow();
317   screen->updateNetizenWindowRaise(win->getClientWindow());
318   if (! (win->isIconic() || win->isDesktop())) {
319     Workspace *wkspc = screen->getWorkspace(win->getWorkspaceNumber());
320     wkspc->stackingList.remove(win);
321     wkspc->stackingList.push_front(win);
322   }
323
324   raiseTransients(win, stack);
325
326   screen->raiseWindows(&stack_vector[0], stack_vector.size());
327 }
328
329
330 void Workspace::lowerWindow(BlackboxWindow *w) {
331   BlackboxWindow *win = w;
332
333   // walk up the transient_for's to the window that is not a transient
334   while (win->isTransient() && ! win->isDesktop()) {
335     if (! win->getTransientFor()) break;
336     win = win->getTransientFor();
337   }
338
339   // get the total window count (win and all transients)
340   unsigned int i = 1 + countTransients(win);
341
342   // stack the window with all transients above
343   StackVector stack_vector(i);
344   StackVector::iterator stack = stack_vector.begin();
345
346   lowerTransients(win, stack);
347
348   *(stack++) = win->getFrameWindow();
349   screen->updateNetizenWindowLower(win->getClientWindow());
350   if (! (win->isIconic() || win->isDesktop())) {
351     Workspace *wkspc = screen->getWorkspace(win->getWorkspaceNumber());
352     wkspc->stackingList.remove(win);
353     wkspc->stackingList.push_back(win);
354   }
355
356   screen->lowerWindows(&stack_vector[0], stack_vector.size());
357 }
358
359
360 void Workspace::reconfigure(void) {
361   clientmenu->reconfigure();
362   std::for_each(windowList.begin(), windowList.end(),
363                 std::mem_fun(&BlackboxWindow::reconfigure));
364 }
365
366
367 BlackboxWindow *Workspace::getWindow(unsigned int index) {
368   if (index < windowList.size()) {
369     BlackboxWindowList::iterator it = windowList.begin();
370     for(; index > 0; --index, ++it); /* increment to index */
371     return *it;
372   }
373   return 0;
374 }
375
376
377 BlackboxWindow*
378 Workspace::getNextWindowInList(BlackboxWindow *w) {
379   BlackboxWindowList::iterator it = std::find(windowList.begin(),
380                                               windowList.end(),
381                                               w);
382   assert(it != windowList.end());   // window must be in list
383   ++it;                             // next window
384   if (it == windowList.end())
385     return windowList.front();      // if we walked off the end, wrap around
386
387   return *it;
388 }
389
390
391 BlackboxWindow* Workspace::getPrevWindowInList(BlackboxWindow *w) {
392   BlackboxWindowList::iterator it = std::find(windowList.begin(),
393                                               windowList.end(),
394                                               w);
395   assert(it != windowList.end()); // window must be in list
396   if (it == windowList.begin())
397     return windowList.back();     // if we walked of the front, wrap around
398
399   return *(--it);
400 }
401
402
403 BlackboxWindow* Workspace::getTopWindowOnStack(void) const {
404   return stackingList.front();
405 }
406
407
408 void Workspace::sendWindowList(Netizen &n) {
409   BlackboxWindowList::iterator it = windowList.begin(),
410     end = windowList.end();
411   for(; it != end; ++it)
412     n.sendWindowAdd((*it)->getClientWindow(), getID());
413 }
414
415
416 unsigned int Workspace::getCount(void) const {
417   return windowList.size();
418 }
419
420
421 void Workspace::appendStackOrder(BlackboxWindowList &stack_order) const {
422   BlackboxWindowList::const_reverse_iterator it = stackingList.rbegin();
423   const BlackboxWindowList::const_reverse_iterator end = stackingList.rend();
424   for (; it != end; ++it)
425     if ((*it)->isNormal())
426       stack_order.push_back(*it);
427 }
428   
429
430 bool Workspace::isCurrent(void) const {
431   return (id == screen->getCurrentWorkspaceID());
432 }
433
434
435 bool Workspace::isLastWindow(const BlackboxWindow* const w) const {
436   return (w == windowList.back());
437 }
438
439
440 void Workspace::setCurrent(void) {
441   screen->changeWorkspaceID(id);
442 }
443
444
445 void Workspace::readName(void) {
446   XAtom::StringVect namesList;
447   unsigned long numnames = id + 1;
448     
449   // attempt to get from the _NET_WM_DESKTOP_NAMES property
450   if (xatom->getValue(screen->getRootWindow(), XAtom::net_desktop_names,
451                       XAtom::utf8, numnames, namesList) &&
452       namesList.size() > id) {
453     name = namesList[id];
454   
455     clientmenu->setLabel(name);
456     clientmenu->update();
457   } else {
458     /*
459        Use a default name. This doesn't actually change the class. That will
460        happen after the setName changes the root property, and that change
461        makes its way back to this function.
462     */
463     string tmp =i18n(WorkspaceSet, WorkspaceDefaultNameFormat,
464                      "Workspace %d");
465     assert(tmp.length() < 32);
466     char default_name[32];
467     sprintf(default_name, tmp.c_str(), id + 1);
468     
469     setName(default_name);  // save this into the _NET_WM_DESKTOP_NAMES property
470   }
471 }
472
473
474 void Workspace::setName(const string& new_name) {
475   // set the _NET_WM_DESKTOP_NAMES property with the new name
476   XAtom::StringVect namesList;
477   unsigned long numnames = (unsigned) -1;
478   if (xatom->getValue(screen->getRootWindow(), XAtom::net_desktop_names,
479                       XAtom::utf8, numnames, namesList) &&
480       namesList.size() > id)
481     namesList[id] = new_name;
482   else
483     namesList.push_back(new_name);
484
485   xatom->setValue(screen->getRootWindow(), XAtom::net_desktop_names,
486                   XAtom::utf8, namesList);
487 }
488
489
490 /*
491  * Calculate free space available for window placement.
492  */
493 typedef std::vector<Rect> rectList;
494
495 static rectList calcSpace(const Rect &win, const rectList &spaces) {
496   Rect isect, extra;
497   rectList result;
498   rectList::const_iterator siter, end = spaces.end();
499   for (siter = spaces.begin(); siter != end; ++siter) {
500     const Rect &curr = *siter;
501
502     if(! win.intersects(curr)) {
503       result.push_back(curr);
504       continue;
505     }
506
507     /* Use an intersection of win and curr to determine the space around
508      * curr that we can use.
509      *
510      * NOTE: the spaces calculated can overlap.
511      */
512     isect = curr & win;
513
514     // left
515     extra.setCoords(curr.left(), curr.top(),
516                     isect.left() - 1, curr.bottom());
517     if (extra.valid()) result.push_back(extra);
518
519     // top
520     extra.setCoords(curr.left(), curr.top(),
521                     curr.right(), isect.top() - 1);
522     if (extra.valid()) result.push_back(extra);
523
524     // right
525     extra.setCoords(isect.right() + 1, curr.top(),
526                     curr.right(), curr.bottom());
527     if (extra.valid()) result.push_back(extra);
528
529     // bottom
530     extra.setCoords(curr.left(), isect.bottom() + 1,
531                     curr.right(), curr.bottom());
532     if (extra.valid()) result.push_back(extra);
533   }
534   return result;
535 }
536
537
538 static bool rowRLBT(const Rect &first, const Rect &second) {
539   if (first.bottom() == second.bottom())
540     return first.right() > second.right();
541   return first.bottom() > second.bottom();
542 }
543
544 static bool rowRLTB(const Rect &first, const Rect &second) {
545   if (first.y() == second.y())
546     return first.right() > second.right();
547   return first.y() < second.y();
548 }
549
550 static bool rowLRBT(const Rect &first, const Rect &second) {
551   if (first.bottom() == second.bottom())
552     return first.x() < second.x();
553   return first.bottom() > second.bottom();
554 }
555
556 static bool rowLRTB(const Rect &first, const Rect &second) {
557   if (first.y() == second.y())
558     return first.x() < second.x();
559   return first.y() < second.y();
560 }
561
562 static bool colLRTB(const Rect &first, const Rect &second) {
563   if (first.x() == second.x())
564     return first.y() < second.y();
565   return first.x() < second.x();
566 }
567
568 static bool colLRBT(const Rect &first, const Rect &second) {
569   if (first.x() == second.x())
570     return first.bottom() > second.bottom();
571   return first.x() < second.x();
572 }
573
574 static bool colRLTB(const Rect &first, const Rect &second) {
575   if (first.right() == second.right())
576     return first.y() < second.y();
577   return first.right() > second.right();
578 }
579
580 static bool colRLBT(const Rect &first, const Rect &second) {
581   if (first.right() == second.right())
582     return first.bottom() > second.bottom();
583   return first.right() > second.right();
584 }
585
586
587 bool Workspace::smartPlacement(Rect& win, const Rect& availableArea) {
588   rectList spaces;
589   spaces.push_back(availableArea); //initially the entire screen is free
590
591   //Find Free Spaces
592   BlackboxWindowList::const_iterator wit = windowList.begin(),
593     end = windowList.end();
594   Rect tmp;
595   for (; wit != end; ++wit) {
596     const BlackboxWindow* const curr = *wit;
597
598     if (curr->isShaded() && screen->getPlaceIgnoreShaded()) continue;
599     if (curr->isMaximizedFull() && screen->getPlaceIgnoreMaximized()) continue;
600
601     tmp.setRect(curr->frameRect().x(), curr->frameRect().y(),
602                 curr->frameRect().width() + screen->getBorderWidth(),
603                 curr->frameRect().height() + screen->getBorderWidth());
604
605     spaces = calcSpace(tmp, spaces);
606   }
607
608   if (screen->getPlacementPolicy() == BScreen::RowSmartPlacement) {
609     if(screen->getRowPlacementDirection() == BScreen::LeftRight) {
610       if(screen->getColPlacementDirection() == BScreen::TopBottom)
611         std::sort(spaces.begin(), spaces.end(), rowLRTB);
612       else
613         std::sort(spaces.begin(), spaces.end(), rowLRBT);
614     } else {
615       if(screen->getColPlacementDirection() == BScreen::TopBottom)
616         std::sort(spaces.begin(), spaces.end(), rowRLTB);
617       else
618         std::sort(spaces.begin(), spaces.end(), rowRLBT);
619     }
620   } else {
621     if(screen->getColPlacementDirection() == BScreen::TopBottom) {
622       if(screen->getRowPlacementDirection() == BScreen::LeftRight)
623         std::sort(spaces.begin(), spaces.end(), colLRTB);
624       else
625         std::sort(spaces.begin(), spaces.end(), colRLTB);
626     } else {
627       if(screen->getRowPlacementDirection() == BScreen::LeftRight)
628         std::sort(spaces.begin(), spaces.end(), colLRBT);
629       else
630         std::sort(spaces.begin(), spaces.end(), colRLBT);
631     }
632   }
633
634   rectList::const_iterator sit = spaces.begin(), spaces_end = spaces.end();
635   for(; sit != spaces_end; ++sit) {
636     if (sit->width() >= win.width() && sit->height() >= win.height())
637       break;
638   }
639
640   if (sit == spaces_end)
641     return False;
642
643   //set new position based on the empty space found
644   const Rect& where = *sit;
645   win.setX(where.x());
646   win.setY(where.y());
647
648   // adjust the location() based on left/right and top/bottom placement
649   if (screen->getPlacementPolicy() == BScreen::RowSmartPlacement) {
650     if (screen->getRowPlacementDirection() == BScreen::RightLeft)
651       win.setX(where.right() - win.width());
652     if (screen->getColPlacementDirection() == BScreen::BottomTop)
653       win.setY(where.bottom() - win.height());
654   } else {
655     if (screen->getColPlacementDirection() == BScreen::BottomTop)
656       win.setY(win.y() + where.height() - win.height());
657     if (screen->getRowPlacementDirection() == BScreen::RightLeft)
658       win.setX(win.x() + where.width() - win.width());
659   }
660   return True;
661 }
662
663
664 bool Workspace::underMousePlacement(Rect &win, const Rect &availableArea) {
665   int x, y, rx, ry;
666   Window c, r;
667   unsigned int m;
668   XQueryPointer(screen->getBlackbox()->getXDisplay(), screen->getRootWindow(),
669                 &r, &c, &rx, &ry, &x, &y, &m);
670   x = rx - win.width() / 2;
671   y = ry - win.height() / 2;
672
673   if (x < availableArea.x())
674     x = availableArea.x();
675   if (y < availableArea.y())
676     y = availableArea.y();
677   if (x + win.width() > availableArea.x() + availableArea.width())
678     x = availableArea.x() + availableArea.width() - win.width();
679   if (y + win.height() > availableArea.y() + availableArea.height())
680     y = availableArea.y() + availableArea.height() - win.height();
681
682   win.setX(x);
683   win.setY(y);
684
685   return True;
686 }
687
688
689 bool Workspace::cascadePlacement(Rect &win, const Rect &availableArea) {
690   if ((cascade_x > static_cast<signed>(availableArea.width() / 2)) ||
691       (cascade_y > static_cast<signed>(availableArea.height() / 2)))
692     cascade_x = cascade_y = 32;
693
694   if (cascade_x == 32) {
695     cascade_x += availableArea.x();
696     cascade_y += availableArea.y();
697   }
698
699   win.setPos(cascade_x, cascade_y);
700
701   return True;
702 }
703
704
705 void Workspace::placeWindow(BlackboxWindow *win) {
706   Rect availableArea(screen->availableArea()),
707     new_win(availableArea.x(), availableArea.y(),
708             win->frameRect().width(), win->frameRect().height());
709   bool placed = False;
710
711   switch (screen->getPlacementPolicy()) {
712   case BScreen::RowSmartPlacement:
713   case BScreen::ColSmartPlacement:
714     placed = smartPlacement(new_win, availableArea);
715     break;
716   case BScreen::UnderMousePlacement:
717   case BScreen::ClickMousePlacement:
718     placed = underMousePlacement(new_win, availableArea);
719   default:
720     break; // handled below
721   } // switch
722
723   if (placed == False) {
724     cascadePlacement(new_win, availableArea);
725     cascade_x += win->getTitleHeight() + (screen->getBorderWidth() * 2);
726     cascade_y += win->getTitleHeight() + (screen->getBorderWidth() * 2);
727   }
728
729   if (new_win.right() > availableArea.right())
730     new_win.setX(availableArea.left());
731   if (new_win.bottom() > availableArea.bottom())
732     new_win.setY(availableArea.top());
733   win->configure(new_win.x(), new_win.y(), new_win.width(), new_win.height());
734 }