]> Dogcows Code - chaz/openbox/blob - src/Workspace.cc
xinerama support for window placement
[chaz/openbox] / 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) {
588 rectList spaces;
589
590 //initially the entire screen is free
591 #ifdef XINERAMA
592 if (screen->isXineramaActive() &&
593 screen->getBlackbox()->doXineramaPlacement()) {
594 RectList availableAreas = screen->allAvailableAreas();
595 assert(availableAreas.size() > 0);
596 RectList::iterator it, end = availableAreas.end();
597
598 for (it = availableAreas.begin(); it != end; ++it)
599 spaces.push_back(*it);
600 } else
601 #endif // XINERAMA
602 spaces.push_back(screen->availableArea());
603
604 //Find Free Spaces
605 BlackboxWindowList::const_iterator wit = windowList.begin(),
606 end = windowList.end();
607 Rect tmp;
608 for (; wit != end; ++wit) {
609 const BlackboxWindow* const curr = *wit;
610
611 if (curr->isShaded() && screen->getPlaceIgnoreShaded()) continue;
612 if (curr->isMaximizedFull() && screen->getPlaceIgnoreMaximized()) continue;
613
614 tmp.setRect(curr->frameRect().x(), curr->frameRect().y(),
615 curr->frameRect().width() + screen->getBorderWidth(),
616 curr->frameRect().height() + screen->getBorderWidth());
617
618 spaces = calcSpace(tmp, spaces);
619 }
620
621 if (screen->getPlacementPolicy() == BScreen::RowSmartPlacement) {
622 if(screen->getRowPlacementDirection() == BScreen::LeftRight) {
623 if(screen->getColPlacementDirection() == BScreen::TopBottom)
624 std::sort(spaces.begin(), spaces.end(), rowLRTB);
625 else
626 std::sort(spaces.begin(), spaces.end(), rowLRBT);
627 } else {
628 if(screen->getColPlacementDirection() == BScreen::TopBottom)
629 std::sort(spaces.begin(), spaces.end(), rowRLTB);
630 else
631 std::sort(spaces.begin(), spaces.end(), rowRLBT);
632 }
633 } else {
634 if(screen->getColPlacementDirection() == BScreen::TopBottom) {
635 if(screen->getRowPlacementDirection() == BScreen::LeftRight)
636 std::sort(spaces.begin(), spaces.end(), colLRTB);
637 else
638 std::sort(spaces.begin(), spaces.end(), colRLTB);
639 } else {
640 if(screen->getRowPlacementDirection() == BScreen::LeftRight)
641 std::sort(spaces.begin(), spaces.end(), colLRBT);
642 else
643 std::sort(spaces.begin(), spaces.end(), colRLBT);
644 }
645 }
646
647 rectList::const_iterator sit = spaces.begin(), spaces_end = spaces.end();
648 for(; sit != spaces_end; ++sit) {
649 if (sit->width() >= win.width() && sit->height() >= win.height())
650 break;
651 }
652
653 if (sit == spaces_end)
654 return False;
655
656 //set new position based on the empty space found
657 const Rect& where = *sit;
658 win.setX(where.x());
659 win.setY(where.y());
660
661 // adjust the location() based on left/right and top/bottom placement
662 if (screen->getPlacementPolicy() == BScreen::RowSmartPlacement) {
663 if (screen->getRowPlacementDirection() == BScreen::RightLeft)
664 win.setX(where.right() - win.width());
665 if (screen->getColPlacementDirection() == BScreen::BottomTop)
666 win.setY(where.bottom() - win.height());
667 } else {
668 if (screen->getColPlacementDirection() == BScreen::BottomTop)
669 win.setY(win.y() + where.height() - win.height());
670 if (screen->getRowPlacementDirection() == BScreen::RightLeft)
671 win.setX(win.x() + where.width() - win.width());
672 }
673 return True;
674 }
675
676
677 bool Workspace::underMousePlacement(Rect &win) {
678 int x, y, rx, ry;
679 Window c, r;
680 unsigned int m;
681 XQueryPointer(screen->getBlackbox()->getXDisplay(), screen->getRootWindow(),
682 &r, &c, &rx, &ry, &x, &y, &m);
683
684 Rect area;
685 #ifdef XINERAMA
686 if (screen->isXineramaActive() &&
687 screen->getBlackbox()->doXineramaPlacement()) {
688 RectList availableAreas = screen->allAvailableAreas();
689 assert(availableAreas.size() > 0);
690 RectList::iterator it, end = availableAreas.end();
691
692 for (it = availableAreas.begin(); it != end; ++it)
693 if (it->contains(rx, ry)) break;
694 assert(it != end); // the mouse isn't inside an area?
695 area = *it;
696 } else
697 #endif // XINERAMA
698 area = screen->availableArea();
699
700 x = rx - win.width() / 2;
701 y = ry - win.height() / 2;
702
703 if (x < area.x())
704 x = area.x();
705 if (y < area.y())
706 y = area.y();
707 if (x + win.width() > area.x() + area.width())
708 x = area.x() + area.width() - win.width();
709 if (y + win.height() > area.y() + area.height())
710 y = area.y() + area.height() - win.height();
711
712 win.setX(x);
713 win.setY(y);
714
715 return True;
716 }
717
718
719 bool Workspace::cascadePlacement(Rect &win) {
720 const Rect &availableArea = screen->availableArea();
721
722 if ((cascade_x > static_cast<signed>(availableArea.width() / 2)) ||
723 (cascade_y > static_cast<signed>(availableArea.height() / 2)))
724 cascade_x = cascade_y = 32;
725
726 if (cascade_x == 32) {
727 cascade_x += availableArea.x();
728 cascade_y += availableArea.y();
729 }
730
731 win.setPos(cascade_x, cascade_y);
732
733 return True;
734 }
735
736
737 void Workspace::placeWindow(BlackboxWindow *win) {
738 Rect new_win(0, 0, win->frameRect().width(), win->frameRect().height());
739 bool placed = False;
740
741 switch (screen->getPlacementPolicy()) {
742 case BScreen::RowSmartPlacement:
743 case BScreen::ColSmartPlacement:
744 placed = smartPlacement(new_win);
745 break;
746 case BScreen::UnderMousePlacement:
747 case BScreen::ClickMousePlacement:
748 placed = underMousePlacement(new_win);
749 default:
750 break; // handled below
751 } // switch
752
753 if (placed == False) {
754 cascadePlacement(new_win);
755 cascade_x += win->getTitleHeight() + (screen->getBorderWidth() * 2);
756 cascade_y += win->getTitleHeight() + (screen->getBorderWidth() * 2);
757 }
758
759 // make sure the placement was valid
760 assert(screen->availableArea().contains(new_win));
761
762 win->configure(new_win.x(), new_win.y(), new_win.width(), new_win.height());
763 }
This page took 0.071646 seconds and 5 git commands to generate.