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