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