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