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)
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:
13 // The above copyright notice and this permission notice shall be included in
14 // all copies or substantial portions of the Software.
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.
25 # include "../config.h"
26 #endif // HAVE_CONFIG_H
30 #include <X11/Xatom.h>
34 #endif // HAVE_STDIO_H
38 #endif // HAVE_STRING_H
49 #include "blackbox.hh"
50 #include "Clientmenu.hh"
57 #include "Workspace.hh"
58 #include "Windowmenu.hh"
62 Workspace::Workspace(BScreen
*scrn
, unsigned int i
) {
64 xatom
= screen
->getBlackbox()->getXAtom();
66 cascade_x
= cascade_y
= 0;
73 clientmenu
= new Clientmenu(this);
75 lastfocus
= (BlackboxWindow
*) 0;
81 void Workspace::addWindow(BlackboxWindow
*w
, bool place
, bool sticky
) {
84 if (place
) placeWindow(w
);
86 stackingList
.push_front(w
);
91 if (! w
->isNormal()) {
93 // just give it some number, else bad things happen as it is assumed to
94 // not be on a workspace
95 w
->setWindowNumber(0);
99 w
->setWindowNumber(windowList
.size());
101 windowList
.push_back(w
);
103 clientmenu
->insert(w
->getTitle());
104 clientmenu
->update();
107 screen
->updateNetizenWindowAdd(w
->getClientWindow(), id
);
109 if (screen
->doFocusNew() || (w
->isTransient() && w
->getTransientFor() &&
110 w
->getTransientFor()->isFocused())) {
111 if (id
!= screen
->getCurrentWorkspaceID()) {
113 not on the focused workspace, so the window is not going to get focus
114 but if the user wants new windows focused, then it should get focus
115 when this workspace does become focused.
122 if (! w
->isDesktop())
129 void Workspace::removeWindow(BlackboxWindow
*w
, bool sticky
) {
132 stackingList
.remove(w
);
134 // pass focus to the next appropriate window
135 if ((w
->isFocused() || w
== lastfocus
) &&
136 ! screen
->getBlackbox()->doShutdown()) {
140 if (! w
->isNormal()) return;
142 BlackboxWindowList::iterator it
, end
= windowList
.end();
144 for (i
= 0, it
= windowList
.begin(); it
!= end
; ++it
, ++i
)
149 windowList
.erase(it
);
150 clientmenu
->remove(i
);
151 clientmenu
->update();
154 screen
->updateNetizenWindowDel(w
->getClientWindow());
156 BlackboxWindowList::iterator it
= windowList
.begin();
157 const BlackboxWindowList::iterator end
= windowList
.end();
159 for (; it
!= end
; ++it
, ++i
)
160 (*it
)->setWindowNumber(i
);
164 cascade_x
= cascade_y
= 0;
172 void Workspace::focusFallback(const BlackboxWindow
*old_window
) {
173 BlackboxWindow
*newfocus
= 0;
175 if (id
== screen
->getCurrentWorkspaceID()) {
176 // The window is on the visible workspace.
178 // if it's a transient, then try to focus its parent
179 if (old_window
&& old_window
->isTransient()) {
180 newfocus
= old_window
->getTransientFor();
183 newfocus
->isIconic() || // do not focus icons
184 newfocus
->getWorkspaceNumber() != id
|| // or other workspaces
185 ! newfocus
->setInputFocus())
190 BlackboxWindowList::iterator it
= stackingList
.begin(),
191 end
= stackingList
.end();
192 for (; it
!= end
; ++it
) {
193 BlackboxWindow
*tmp
= *it
;
194 if (tmp
&& tmp
->isNormal() && tmp
->setInputFocus()) {
195 // we found our new focus target
202 screen
->getBlackbox()->setFocusedWindow(newfocus
);
204 // The window is not on the visible workspace.
206 if (old_window
&& lastfocus
== old_window
) {
207 // The window was the last-focus target, so we need to replace it.
208 BlackboxWindow
*win
= (BlackboxWindow
*) 0;
209 if (! stackingList
.empty())
210 win
= stackingList
.front();
211 setLastFocusedWindow(win
);
217 void Workspace::setFocused(const BlackboxWindow
*w
, bool focused
) {
218 BlackboxWindowList::iterator it
, end
= windowList
.end();
220 for (i
= 0, it
= windowList
.begin(); it
!= end
; ++it
, ++i
)
223 // if its == end, then a window thats not in the windowList
224 // got focused, such as a !isNormal() window.
226 clientmenu
->setItemSelected(i
, focused
);
230 void Workspace::removeAll(void) {
231 while (! windowList
.empty())
232 windowList
.front()->iconify();
235 void Workspace::showAll(void) {
236 BlackboxWindowList::iterator it
= stackingList
.begin();
237 const BlackboxWindowList::iterator end
= stackingList
.end();
238 for (; it
!= end
; ++it
) {
239 BlackboxWindow
*bw
= *it
;
240 // sticky windows arent unmapped on a workspace change so we don't have ot
241 // map them, but sometimes on a restart, another app can unmap our sticky
242 // windows, so we map on startup always
243 if (! bw
->isStuck() || screen
->getBlackbox()->isStartup())
249 void Workspace::hideAll(void) {
250 // withdraw in reverse order to minimize the number of Expose events
252 BlackboxWindowList
lst(stackingList
.rbegin(), stackingList
.rend());
254 BlackboxWindowList::iterator it
= lst
.begin();
255 const BlackboxWindowList::iterator end
= lst
.end();
256 for (; it
!= end
; ++it
) {
257 BlackboxWindow
*bw
= *it
;
258 // don't hide sticky windows, or they'll end up flickering on a workspace
268 * returns the number of transients for win, plus the number of transients
269 * associated with each transient of win
271 static unsigned int countTransients(const BlackboxWindow
* const win
) {
272 BlackboxWindowList transients
= win
->getTransients();
273 if (transients
.empty()) return 0;
275 unsigned int ret
= transients
.size();
276 BlackboxWindowList::const_iterator it
= transients
.begin(),
277 end
= transients
.end();
278 for (; it
!= end
; ++it
)
279 ret
+= countTransients(*it
);
286 * puts the transients of win into the stack. windows are stacked above
287 * the window before it in the stackvector being iterated, meaning
288 * stack[0] is on bottom, stack[1] is above stack[0], stack[2] is above
291 void Workspace::raiseTransients(const BlackboxWindow
* const win
,
292 StackVector::iterator
&stack
) {
293 if (win
->getTransients().empty()) return; // nothing to do
295 // put win's transients in the stack
296 BlackboxWindowList::const_iterator it
, end
= win
->getTransients().end();
297 for (it
= win
->getTransients().begin(); it
!= end
; ++it
) {
298 BlackboxWindow
*w
= *it
;
299 *stack
++ = w
->getFrameWindow();
300 screen
->updateNetizenWindowRaise(w
->getClientWindow());
302 if (! w
->isIconic()) {
303 Workspace
*wkspc
= screen
->getWorkspace(w
->getWorkspaceNumber());
304 wkspc
->stackingList
.remove(w
);
305 wkspc
->stackingList
.push_front(w
);
309 // put transients of win's transients in the stack
310 for (it
= win
->getTransients().begin(); it
!= end
; ++it
)
311 raiseTransients(*it
, stack
);
315 void Workspace::lowerTransients(const BlackboxWindow
* const win
,
316 StackVector::iterator
&stack
) {
317 if (win
->getTransients().empty()) return; // nothing to do
319 // put transients of win's transients in the stack
320 BlackboxWindowList::const_reverse_iterator it
,
321 end
= win
->getTransients().rend();
322 for (it
= win
->getTransients().rbegin(); it
!= end
; ++it
)
323 lowerTransients(*it
, stack
);
325 // put win's transients in the stack
326 for (it
= win
->getTransients().rbegin(); it
!= end
; ++it
) {
327 BlackboxWindow
*w
= *it
;
328 *stack
++ = w
->getFrameWindow();
329 screen
->updateNetizenWindowLower(w
->getClientWindow());
331 if (! w
->isIconic()) {
332 Workspace
*wkspc
= screen
->getWorkspace(w
->getWorkspaceNumber());
333 wkspc
->stackingList
.remove(w
);
334 wkspc
->stackingList
.push_back(w
);
340 void Workspace::raiseWindow(BlackboxWindow
*w
) {
341 BlackboxWindow
*win
= w
;
343 if (win
->isDesktop()) return;
345 // walk up the transient_for's to the window that is not a transient
346 while (win
->isTransient() && win
->getTransientFor())
347 win
= win
->getTransientFor();
349 // get the total window count (win and all transients)
350 unsigned int i
= 1 + countTransients(win
);
352 // stack the window with all transients above
353 StackVector
stack_vector(i
);
354 StackVector::iterator stack
= stack_vector
.begin();
356 *(stack
++) = win
->getFrameWindow();
357 screen
->updateNetizenWindowRaise(win
->getClientWindow());
358 if (! (win
->isIconic() || win
->isDesktop())) {
359 Workspace
*wkspc
= screen
->getWorkspace(win
->getWorkspaceNumber());
360 wkspc
->stackingList
.remove(win
);
361 wkspc
->stackingList
.push_front(win
);
364 raiseTransients(win
, stack
);
366 screen
->raiseWindows(&stack_vector
[0], stack_vector
.size());
370 void Workspace::lowerWindow(BlackboxWindow
*w
) {
371 BlackboxWindow
*win
= w
;
373 // walk up the transient_for's to the window that is not a transient
374 while (win
->isTransient() && win
->getTransientFor())
375 win
= win
->getTransientFor();
377 // get the total window count (win and all transients)
378 unsigned int i
= 1 + countTransients(win
);
380 // stack the window with all transients above
381 StackVector
stack_vector(i
);
382 StackVector::iterator stack
= stack_vector
.begin();
384 lowerTransients(win
, stack
);
386 *(stack
++) = win
->getFrameWindow();
387 screen
->updateNetizenWindowLower(win
->getClientWindow());
388 if (! (win
->isIconic() || win
->isDesktop())) {
389 Workspace
*wkspc
= screen
->getWorkspace(win
->getWorkspaceNumber());
390 wkspc
->stackingList
.remove(win
);
391 wkspc
->stackingList
.push_back(win
);
394 screen
->lowerWindows(&stack_vector
[0], stack_vector
.size());
398 void Workspace::reconfigure(void) {
399 clientmenu
->reconfigure();
400 std::for_each(windowList
.begin(), windowList
.end(),
401 std::mem_fun(&BlackboxWindow::reconfigure
));
405 BlackboxWindow
*Workspace::getWindow(unsigned int index
) {
406 if (index
< windowList
.size()) {
407 BlackboxWindowList::iterator it
= windowList
.begin();
408 while (index
-- > 0) // increment to index
418 Workspace::getNextWindowInList(BlackboxWindow
*w
) {
419 BlackboxWindowList::iterator it
= std::find(windowList
.begin(),
422 assert(it
!= windowList
.end()); // window must be in list
424 if (it
== windowList
.end())
425 return windowList
.front(); // if we walked off the end, wrap around
431 BlackboxWindow
* Workspace::getPrevWindowInList(BlackboxWindow
*w
) {
432 BlackboxWindowList::iterator it
= std::find(windowList
.begin(),
435 assert(it
!= windowList
.end()); // window must be in list
436 if (it
== windowList
.begin())
437 return windowList
.back(); // if we walked of the front, wrap around
443 BlackboxWindow
* Workspace::getTopWindowOnStack(void) const {
444 assert(! stackingList
.empty());
445 return stackingList
.front();
449 void Workspace::sendWindowList(Netizen
&n
) {
450 BlackboxWindowList::iterator it
= windowList
.begin(),
451 end
= windowList
.end();
452 for(; it
!= end
; ++it
)
453 n
.sendWindowAdd((*it
)->getClientWindow(), getID());
457 unsigned int Workspace::getCount(void) const {
458 return windowList
.size();
462 void Workspace::appendStackOrder(BlackboxWindowList
&stack_order
) const {
463 BlackboxWindowList::const_reverse_iterator it
= stackingList
.rbegin();
464 const BlackboxWindowList::const_reverse_iterator end
= stackingList
.rend();
465 for (; it
!= end
; ++it
)
466 // don't add desktop wnidows, or sticky windows more than once
467 if (! ( (*it
)->isDesktop() ||
468 ((*it
)->isStuck() && id
!= screen
->getCurrentWorkspaceID())))
469 stack_order
.push_back(*it
);
473 bool Workspace::isCurrent(void) const {
474 return (id
== screen
->getCurrentWorkspaceID());
478 bool Workspace::isLastWindow(const BlackboxWindow
* const w
) const {
479 return (w
== windowList
.back());
483 void Workspace::setCurrent(void) {
484 screen
->changeWorkspaceID(id
);
488 void Workspace::readName(void) {
489 XAtom::StringVect namesList
;
490 unsigned long numnames
= id
+ 1;
492 // attempt to get from the _NET_WM_DESKTOP_NAMES property
493 if (xatom
->getValue(screen
->getRootWindow(), XAtom::net_desktop_names
,
494 XAtom::utf8
, numnames
, namesList
) &&
495 namesList
.size() > id
) {
496 name
= namesList
[id
];
498 clientmenu
->setLabel(name
);
499 clientmenu
->update();
502 Use a default name. This doesn't actually change the class. That will
503 happen after the setName changes the root property, and that change
504 makes its way back to this function.
506 string tmp
=i18n(WorkspaceSet
, WorkspaceDefaultNameFormat
,
508 assert(tmp
.length() < 32);
509 char default_name
[32];
510 sprintf(default_name
, tmp
.c_str(), id
+ 1);
512 setName(default_name
); // save this into the _NET_WM_DESKTOP_NAMES property
517 void Workspace::setName(const string
& new_name
) {
518 // set the _NET_WM_DESKTOP_NAMES property with the new name
519 XAtom::StringVect namesList
;
520 unsigned long numnames
= (unsigned) -1;
521 if (xatom
->getValue(screen
->getRootWindow(), XAtom::net_desktop_names
,
522 XAtom::utf8
, numnames
, namesList
) &&
523 namesList
.size() > id
)
524 namesList
[id
] = new_name
;
526 namesList
.push_back(new_name
);
528 xatom
->setValue(screen
->getRootWindow(), XAtom::net_desktop_names
,
529 XAtom::utf8
, namesList
);
534 * Calculate free space available for window placement.
536 Workspace::rectList
Workspace::calcSpace(const Rect
&win
,
537 const rectList
&spaces
) const {
540 rectList::const_iterator siter
, end
= spaces
.end();
541 for (siter
= spaces
.begin(); siter
!= end
; ++siter
) {
542 const Rect
&curr
= *siter
;
544 if(! win
.intersects(curr
)) {
545 result
.push_back(curr
);
549 /* Use an intersection of win and curr to determine the space around
550 * curr that we can use.
552 * NOTE: the spaces calculated can overlap.
557 extra
.setCoords(curr
.left(), curr
.top(),
558 isect
.left() - screen
->getSnapOffset(), curr
.bottom());
559 if (extra
.valid()) result
.push_back(extra
);
562 extra
.setCoords(curr
.left(), curr
.top(),
563 curr
.right(), isect
.top() - screen
->getSnapOffset());
564 if (extra
.valid()) result
.push_back(extra
);
567 extra
.setCoords(isect
.right() + screen
->getSnapOffset(), curr
.top(),
568 curr
.right(), curr
.bottom());
569 if (extra
.valid()) result
.push_back(extra
);
572 extra
.setCoords(curr
.left(), isect
.bottom() + screen
->getSnapOffset(),
573 curr
.right(), curr
.bottom());
574 if (extra
.valid()) result
.push_back(extra
);
580 static bool rowRLBT(const Rect
&first
, const Rect
&second
) {
581 if (first
.bottom() == second
.bottom())
582 return first
.right() > second
.right();
583 return first
.bottom() > second
.bottom();
586 static bool rowRLTB(const Rect
&first
, const Rect
&second
) {
587 if (first
.y() == second
.y())
588 return first
.right() > second
.right();
589 return first
.y() < second
.y();
592 static bool rowLRBT(const Rect
&first
, const Rect
&second
) {
593 if (first
.bottom() == second
.bottom())
594 return first
.x() < second
.x();
595 return first
.bottom() > second
.bottom();
598 static bool rowLRTB(const Rect
&first
, const Rect
&second
) {
599 if (first
.y() == second
.y())
600 return first
.x() < second
.x();
601 return first
.y() < second
.y();
604 static bool colLRTB(const Rect
&first
, const Rect
&second
) {
605 if (first
.x() == second
.x())
606 return first
.y() < second
.y();
607 return first
.x() < second
.x();
610 static bool colLRBT(const Rect
&first
, const Rect
&second
) {
611 if (first
.x() == second
.x())
612 return first
.bottom() > second
.bottom();
613 return first
.x() < second
.x();
616 static bool colRLTB(const Rect
&first
, const Rect
&second
) {
617 if (first
.right() == second
.right())
618 return first
.y() < second
.y();
619 return first
.right() > second
.right();
622 static bool colRLBT(const Rect
&first
, const Rect
&second
) {
623 if (first
.right() == second
.right())
624 return first
.bottom() > second
.bottom();
625 return first
.right() > second
.right();
629 bool Workspace::smartPlacement(Rect
& win
) {
632 //initially the entire screen is free
634 if (screen
->isXineramaActive() &&
635 screen
->getBlackbox()->doXineramaPlacement()) {
636 RectList availableAreas
= screen
->allAvailableAreas();
637 RectList::iterator it
, end
= availableAreas
.end();
639 for (it
= availableAreas
.begin(); it
!= end
; ++it
)
640 spaces
.push_back(*it
);
643 spaces
.push_back(screen
->availableArea());
646 BlackboxWindowList::const_iterator wit
= windowList
.begin(),
647 end
= windowList
.end();
649 for (; wit
!= end
; ++wit
) {
650 const BlackboxWindow
* const curr
= *wit
;
652 // watch for shaded windows and full-maxed windows
653 if (curr
->isShaded()) {
654 if (screen
->getPlaceIgnoreShaded()) continue;
655 } else if (curr
->isMaximizedFull()) {
656 if (screen
->getPlaceIgnoreMaximized()) continue;
659 tmp
.setRect(curr
->frameRect().x(), curr
->frameRect().y(),
660 curr
->frameRect().width() + screen
->getBorderWidth(),
661 curr
->frameRect().height() + screen
->getBorderWidth());
663 spaces
= calcSpace(tmp
, spaces
);
666 if (screen
->getPlacementPolicy() == BScreen::RowSmartPlacement
) {
667 if(screen
->getRowPlacementDirection() == BScreen::LeftRight
) {
668 if(screen
->getColPlacementDirection() == BScreen::TopBottom
)
669 std::sort(spaces
.begin(), spaces
.end(), rowLRTB
);
671 std::sort(spaces
.begin(), spaces
.end(), rowLRBT
);
673 if(screen
->getColPlacementDirection() == BScreen::TopBottom
)
674 std::sort(spaces
.begin(), spaces
.end(), rowRLTB
);
676 std::sort(spaces
.begin(), spaces
.end(), rowRLBT
);
679 if(screen
->getColPlacementDirection() == BScreen::TopBottom
) {
680 if(screen
->getRowPlacementDirection() == BScreen::LeftRight
)
681 std::sort(spaces
.begin(), spaces
.end(), colLRTB
);
683 std::sort(spaces
.begin(), spaces
.end(), colRLTB
);
685 if(screen
->getRowPlacementDirection() == BScreen::LeftRight
)
686 std::sort(spaces
.begin(), spaces
.end(), colLRBT
);
688 std::sort(spaces
.begin(), spaces
.end(), colRLBT
);
692 rectList::const_iterator sit
= spaces
.begin(), spaces_end
= spaces
.end();
693 for(; sit
!= spaces_end
; ++sit
) {
694 if (sit
->width() >= win
.width() && sit
->height() >= win
.height())
698 if (sit
== spaces_end
)
701 //set new position based on the empty space found
702 const Rect
& where
= *sit
;
706 // adjust the location() based on left/right and top/bottom placement
707 if (screen
->getPlacementPolicy() == BScreen::RowSmartPlacement
) {
708 if (screen
->getRowPlacementDirection() == BScreen::RightLeft
)
709 win
.setX(where
.right() - win
.width());
710 if (screen
->getColPlacementDirection() == BScreen::BottomTop
)
711 win
.setY(where
.bottom() - win
.height());
713 if (screen
->getColPlacementDirection() == BScreen::BottomTop
)
714 win
.setY(win
.y() + where
.height() - win
.height());
715 if (screen
->getRowPlacementDirection() == BScreen::RightLeft
)
716 win
.setX(win
.x() + where
.width() - win
.width());
722 bool Workspace::underMousePlacement(Rect
&win
) {
726 XQueryPointer(screen
->getBlackbox()->getXDisplay(), screen
->getRootWindow(),
727 &r
, &c
, &rx
, &ry
, &x
, &y
, &m
);
731 if (screen
->isXineramaActive() &&
732 screen
->getBlackbox()->doXineramaPlacement()) {
733 RectList availableAreas
= screen
->allAvailableAreas();
734 RectList::iterator it
, end
= availableAreas
.end();
736 for (it
= availableAreas
.begin(); it
!= end
; ++it
)
737 if (it
->contains(rx
, ry
)) break;
738 assert(it
!= end
); // the mouse isn't inside an area?
742 area
= screen
->availableArea();
744 x
= rx
- win
.width() / 2;
745 y
= ry
- win
.height() / 2;
751 if (x
+ win
.width() > area
.x() + area
.width())
752 x
= area
.x() + area
.width() - win
.width();
753 if (y
+ win
.height() > area
.y() + area
.height())
754 y
= area
.y() + area
.height() - win
.height();
763 bool Workspace::cascadePlacement(Rect
&win
, const int offset
) {
767 if (screen
->isXineramaActive() &&
768 screen
->getBlackbox()->doXineramaPlacement()) {
769 area
= screen
->allAvailableAreas()[cascade_region
];
772 area
= screen
->availableArea();
774 if ((static_cast<signed>(cascade_x
+ win
.width()) > area
.right() + 1) ||
775 (static_cast<signed>(cascade_y
+ win
.height()) > area
.bottom() + 1)) {
776 cascade_x
= cascade_y
= 0;
778 if (screen
->isXineramaActive() &&
779 screen
->getBlackbox()->doXineramaPlacement()) {
780 // go to the next xinerama region, and use its area
781 if (++cascade_region
>= screen
->allAvailableAreas().size())
783 area
= screen
->allAvailableAreas()[cascade_region
];
788 if (cascade_x
== 0) {
789 cascade_x
= area
.x() + offset
;
790 cascade_y
= area
.y() + offset
;
793 win
.setPos(cascade_x
, cascade_y
);
802 void Workspace::placeWindow(BlackboxWindow
*win
) {
803 Rect
new_win(0, 0, win
->frameRect().width(), win
->frameRect().height());
806 switch (screen
->getPlacementPolicy()) {
807 case BScreen::RowSmartPlacement
:
808 case BScreen::ColSmartPlacement
:
809 placed
= smartPlacement(new_win
);
811 case BScreen::UnderMousePlacement
:
812 case BScreen::ClickMousePlacement
:
813 placed
= underMousePlacement(new_win
);
815 break; // handled below
819 cascadePlacement(new_win
, (win
->getTitleHeight() +
820 screen
->getBorderWidth() * 2));
822 if (new_win
.right() > screen
->availableArea().right())
823 new_win
.setX(screen
->availableArea().left());
824 if (new_win
.bottom() > screen
->availableArea().bottom())
825 new_win
.setY(screen
->availableArea().top());
827 win
->configure(new_win
.x(), new_win
.y(), new_win
.width(), new_win
.height());