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