]> Dogcows Code - chaz/openbox/blob - src/Workspace.cc
sync with blackbox
[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::removeAll(void) {
226 while (! windowList.empty())
227 windowList.front()->iconify();
228 }
229
230
231 /*
232 * returns the number of transients for win, plus the number of transients
233 * associated with each transient of win
234 */
235 static unsigned int countTransients(const BlackboxWindow * const win) {
236 BlackboxWindowList transients = win->getTransients();
237 if (transients.empty()) return 0;
238
239 unsigned int ret = transients.size();
240 BlackboxWindowList::const_iterator it = transients.begin(),
241 end = transients.end();
242 for (; it != end; ++it)
243 ret += countTransients(*it);
244
245 return ret;
246 }
247
248
249 /*
250 * puts the transients of win into the stack. windows are stacked above
251 * the window before it in the stackvector being iterated, meaning
252 * stack[0] is on bottom, stack[1] is above stack[0], stack[2] is above
253 * stack[1], etc...
254 */
255 void Workspace::raiseTransients(const BlackboxWindow * const win,
256 StackVector::iterator &stack) {
257 if (win->getTransients().empty()) return; // nothing to do
258
259 // put win's transients in the stack
260 BlackboxWindowList::const_iterator it, end = win->getTransients().end();
261 for (it = win->getTransients().begin(); it != end; ++it) {
262 BlackboxWindow *w = *it;
263 *stack++ = w->getFrameWindow();
264 screen->updateNetizenWindowRaise(w->getClientWindow());
265
266 if (! w->isIconic()) {
267 Workspace *wkspc = screen->getWorkspace(w->getWorkspaceNumber());
268 wkspc->stackingList.remove(w);
269 wkspc->stackingList.push_front(w);
270 }
271 }
272
273 // put transients of win's transients in the stack
274 for (it = win->getTransients().begin(); it != end; ++it)
275 raiseTransients(*it, stack);
276 }
277
278
279 void Workspace::lowerTransients(const BlackboxWindow * const win,
280 StackVector::iterator &stack) {
281 if (win->getTransients().empty()) return; // nothing to do
282
283 // put transients of win's transients in the stack
284 BlackboxWindowList::const_reverse_iterator it,
285 end = win->getTransients().rend();
286 for (it = win->getTransients().rbegin(); it != end; ++it)
287 lowerTransients(*it, stack);
288
289 // put win's transients in the stack
290 for (it = win->getTransients().rbegin(); it != end; ++it) {
291 BlackboxWindow *w = *it;
292 *stack++ = w->getFrameWindow();
293 screen->updateNetizenWindowLower(w->getClientWindow());
294
295 if (! w->isIconic()) {
296 Workspace *wkspc = screen->getWorkspace(w->getWorkspaceNumber());
297 wkspc->stackingList.remove(w);
298 wkspc->stackingList.push_back(w);
299 }
300 }
301 }
302
303
304 void Workspace::raiseWindow(BlackboxWindow *w) {
305 BlackboxWindow *win = w;
306
307 if (win->isDesktop()) return;
308
309 // walk up the transient_for's to the window that is not a transient
310 while (win->isTransient() && win->getTransientFor())
311 win = win->getTransientFor();
312
313 // get the total window count (win and all transients)
314 unsigned int i = 1 + countTransients(win);
315
316 // stack the window with all transients above
317 StackVector stack_vector(i);
318 StackVector::iterator stack = stack_vector.begin();
319
320 *(stack++) = win->getFrameWindow();
321 screen->updateNetizenWindowRaise(win->getClientWindow());
322 if (! (win->isIconic() || win->isDesktop())) {
323 Workspace *wkspc = screen->getWorkspace(win->getWorkspaceNumber());
324 wkspc->stackingList.remove(win);
325 wkspc->stackingList.push_front(win);
326 }
327
328 raiseTransients(win, stack);
329
330 screen->raiseWindows(&stack_vector[0], stack_vector.size());
331 }
332
333
334 void Workspace::lowerWindow(BlackboxWindow *w) {
335 BlackboxWindow *win = w;
336
337 // walk up the transient_for's to the window that is not a transient
338 while (win->isTransient() && win->getTransientFor())
339 win = win->getTransientFor();
340
341 // get the total window count (win and all transients)
342 unsigned int i = 1 + countTransients(win);
343
344 // stack the window with all transients above
345 StackVector stack_vector(i);
346 StackVector::iterator stack = stack_vector.begin();
347
348 lowerTransients(win, stack);
349
350 *(stack++) = win->getFrameWindow();
351 screen->updateNetizenWindowLower(win->getClientWindow());
352 if (! (win->isIconic() || win->isDesktop())) {
353 Workspace *wkspc = screen->getWorkspace(win->getWorkspaceNumber());
354 wkspc->stackingList.remove(win);
355 wkspc->stackingList.push_back(win);
356 }
357
358 screen->lowerWindows(&stack_vector[0], stack_vector.size());
359 }
360
361
362 void Workspace::reconfigure(void) {
363 clientmenu->reconfigure();
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 void Workspace::sendWindowList(Netizen &n) {
414 BlackboxWindowList::iterator it = windowList.begin(),
415 end = windowList.end();
416 for(; it != end; ++it)
417 n.sendWindowAdd((*it)->getClientWindow(), getID());
418 }
419
420
421 unsigned int Workspace::getCount(void) const {
422 return windowList.size();
423 }
424
425
426 void Workspace::appendStackOrder(BlackboxWindowList &stack_order) const {
427 BlackboxWindowList::const_reverse_iterator it = stackingList.rbegin();
428 const BlackboxWindowList::const_reverse_iterator end = stackingList.rend();
429 for (; it != end; ++it)
430 if ((*it)->isNormal())
431 stack_order.push_back(*it);
432 }
433
434
435 void Workspace::hide(void) {
436 BlackboxWindow *focused = screen->getBlackbox()->getFocusedWindow();
437 if (focused && focused->getScreen() == screen) {
438 assert(focused->isStuck() || focused->getWorkspaceNumber() == id);
439
440 lastfocus = focused;
441 } else {
442 // if no window had focus, no need to store a last focus
443 lastfocus = (BlackboxWindow *) 0;
444 }
445
446 // when we switch workspaces, unfocus whatever was focused
447 screen->getBlackbox()->setFocusedWindow((BlackboxWindow *) 0);
448
449 // withdraw windows in reverse order to minimize the number of Expose events
450
451 BlackboxWindowList::reverse_iterator it = stackingList.rbegin();
452 const BlackboxWindowList::reverse_iterator end = stackingList.rend();
453 for (; it != end; ++it) {
454 BlackboxWindow *bw = *it;
455 // not normal windows cant focus from mouse enters anyways, so we dont
456 // need to unmap/remap them on workspace changes
457 if (! bw->isStuck() || bw->isNormal())
458 bw->withdraw();
459 }
460 }
461
462
463 void Workspace::show(void) {
464 std::for_each(stackingList.begin(), stackingList.end(),
465 std::mem_fun(&BlackboxWindow::show));
466
467 XSync(screen->getBlackbox()->getXDisplay(), False);
468
469 if (screen->doFocusLast()) {
470 if (! screen->isSloppyFocus() && ! lastfocus && ! stackingList.empty())
471 lastfocus = stackingList.front();
472
473 if (lastfocus)
474 lastfocus->setInputFocus();
475 }
476 }
477
478
479 bool Workspace::isCurrent(void) const {
480 return (id == screen->getCurrentWorkspaceID());
481 }
482
483
484 bool Workspace::isLastWindow(const BlackboxWindow* const w) const {
485 return (w == windowList.back());
486 }
487
488
489 void Workspace::setCurrent(void) {
490 screen->changeWorkspaceID(id);
491 }
492
493
494 void Workspace::readName(void) {
495 XAtom::StringVect namesList;
496 unsigned long numnames = id + 1;
497
498 // attempt to get from the _NET_WM_DESKTOP_NAMES property
499 if (xatom->getValue(screen->getRootWindow(), XAtom::net_desktop_names,
500 XAtom::utf8, numnames, namesList) &&
501 namesList.size() > id) {
502 name = namesList[id];
503
504 clientmenu->setLabel(name);
505 clientmenu->update();
506 } else {
507 /*
508 Use a default name. This doesn't actually change the class. That will
509 happen after the setName changes the root property, and that change
510 makes its way back to this function.
511 */
512 string tmp =i18n(WorkspaceSet, WorkspaceDefaultNameFormat,
513 "Workspace %d");
514 assert(tmp.length() < 32);
515 char default_name[32];
516 sprintf(default_name, tmp.c_str(), id + 1);
517
518 setName(default_name); // save this into the _NET_WM_DESKTOP_NAMES property
519 }
520 }
521
522
523 void Workspace::setName(const string& new_name) {
524 // set the _NET_WM_DESKTOP_NAMES property with the new name
525 XAtom::StringVect namesList;
526 unsigned long numnames = (unsigned) -1;
527 if (xatom->getValue(screen->getRootWindow(), XAtom::net_desktop_names,
528 XAtom::utf8, numnames, namesList) &&
529 namesList.size() > id)
530 namesList[id] = new_name;
531 else
532 namesList.push_back(new_name);
533
534 xatom->setValue(screen->getRootWindow(), XAtom::net_desktop_names,
535 XAtom::utf8, namesList);
536 }
537
538
539 /*
540 * Calculate free space available for window placement.
541 */
542 typedef std::vector<Rect> rectList;
543
544 static rectList calcSpace(const Rect &win, const rectList &spaces) {
545 Rect isect, extra;
546 rectList result;
547 rectList::const_iterator siter, end = spaces.end();
548 for (siter = spaces.begin(); siter != end; ++siter) {
549 const Rect &curr = *siter;
550
551 if(! win.intersects(curr)) {
552 result.push_back(curr);
553 continue;
554 }
555
556 /* Use an intersection of win and curr to determine the space around
557 * curr that we can use.
558 *
559 * NOTE: the spaces calculated can overlap.
560 */
561 isect = curr & win;
562
563 // left
564 extra.setCoords(curr.left(), curr.top(),
565 isect.left() - 1, curr.bottom());
566 if (extra.valid()) result.push_back(extra);
567
568 // top
569 extra.setCoords(curr.left(), curr.top(),
570 curr.right(), isect.top() - 1);
571 if (extra.valid()) result.push_back(extra);
572
573 // right
574 extra.setCoords(isect.right() + 1, curr.top(),
575 curr.right(), curr.bottom());
576 if (extra.valid()) result.push_back(extra);
577
578 // bottom
579 extra.setCoords(curr.left(), isect.bottom() + 1,
580 curr.right(), curr.bottom());
581 if (extra.valid()) result.push_back(extra);
582 }
583 return result;
584 }
585
586
587 static bool rowRLBT(const Rect &first, const Rect &second) {
588 if (first.bottom() == second.bottom())
589 return first.right() > second.right();
590 return first.bottom() > second.bottom();
591 }
592
593 static bool rowRLTB(const Rect &first, const Rect &second) {
594 if (first.y() == second.y())
595 return first.right() > second.right();
596 return first.y() < second.y();
597 }
598
599 static bool rowLRBT(const Rect &first, const Rect &second) {
600 if (first.bottom() == second.bottom())
601 return first.x() < second.x();
602 return first.bottom() > second.bottom();
603 }
604
605 static bool rowLRTB(const Rect &first, const Rect &second) {
606 if (first.y() == second.y())
607 return first.x() < second.x();
608 return first.y() < second.y();
609 }
610
611 static bool colLRTB(const Rect &first, const Rect &second) {
612 if (first.x() == second.x())
613 return first.y() < second.y();
614 return first.x() < second.x();
615 }
616
617 static bool colLRBT(const Rect &first, const Rect &second) {
618 if (first.x() == second.x())
619 return first.bottom() > second.bottom();
620 return first.x() < second.x();
621 }
622
623 static bool colRLTB(const Rect &first, const Rect &second) {
624 if (first.right() == second.right())
625 return first.y() < second.y();
626 return first.right() > second.right();
627 }
628
629 static bool colRLBT(const Rect &first, const Rect &second) {
630 if (first.right() == second.right())
631 return first.bottom() > second.bottom();
632 return first.right() > second.right();
633 }
634
635
636 bool Workspace::smartPlacement(Rect& win) {
637 rectList spaces;
638
639 //initially the entire screen is free
640 #ifdef XINERAMA
641 if (screen->isXineramaActive() &&
642 screen->getBlackbox()->doXineramaPlacement()) {
643 RectList availableAreas = screen->allAvailableAreas();
644 RectList::iterator it, end = availableAreas.end();
645
646 for (it = availableAreas.begin(); it != end; ++it)
647 spaces.push_back(*it);
648 } else
649 #endif // XINERAMA
650 spaces.push_back(screen->availableArea());
651
652 //Find Free Spaces
653 BlackboxWindowList::const_iterator wit = windowList.begin(),
654 end = windowList.end();
655 Rect tmp;
656 for (; wit != end; ++wit) {
657 const BlackboxWindow* const curr = *wit;
658
659 // watch for shaded windows and full-maxed windows
660 if (curr->isShaded()) {
661 if (screen->getPlaceIgnoreShaded()) continue;
662 } else if (curr->isMaximizedFull()) {
663 if (screen->getPlaceIgnoreMaximized()) continue;
664 }
665
666 tmp.setRect(curr->frameRect().x(), curr->frameRect().y(),
667 curr->frameRect().width() + screen->getBorderWidth(),
668 curr->frameRect().height() + screen->getBorderWidth());
669
670 spaces = calcSpace(tmp, spaces);
671 }
672
673 if (screen->getPlacementPolicy() == BScreen::RowSmartPlacement) {
674 if(screen->getRowPlacementDirection() == BScreen::LeftRight) {
675 if(screen->getColPlacementDirection() == BScreen::TopBottom)
676 std::sort(spaces.begin(), spaces.end(), rowLRTB);
677 else
678 std::sort(spaces.begin(), spaces.end(), rowLRBT);
679 } else {
680 if(screen->getColPlacementDirection() == BScreen::TopBottom)
681 std::sort(spaces.begin(), spaces.end(), rowRLTB);
682 else
683 std::sort(spaces.begin(), spaces.end(), rowRLBT);
684 }
685 } else {
686 if(screen->getColPlacementDirection() == BScreen::TopBottom) {
687 if(screen->getRowPlacementDirection() == BScreen::LeftRight)
688 std::sort(spaces.begin(), spaces.end(), colLRTB);
689 else
690 std::sort(spaces.begin(), spaces.end(), colRLTB);
691 } else {
692 if(screen->getRowPlacementDirection() == BScreen::LeftRight)
693 std::sort(spaces.begin(), spaces.end(), colLRBT);
694 else
695 std::sort(spaces.begin(), spaces.end(), colRLBT);
696 }
697 }
698
699 rectList::const_iterator sit = spaces.begin(), spaces_end = spaces.end();
700 for(; sit != spaces_end; ++sit) {
701 if (sit->width() >= win.width() && sit->height() >= win.height())
702 break;
703 }
704
705 if (sit == spaces_end)
706 return False;
707
708 //set new position based on the empty space found
709 const Rect& where = *sit;
710 win.setX(where.x());
711 win.setY(where.y());
712
713 // adjust the location() based on left/right and top/bottom placement
714 if (screen->getPlacementPolicy() == BScreen::RowSmartPlacement) {
715 if (screen->getRowPlacementDirection() == BScreen::RightLeft)
716 win.setX(where.right() - win.width());
717 if (screen->getColPlacementDirection() == BScreen::BottomTop)
718 win.setY(where.bottom() - win.height());
719 } else {
720 if (screen->getColPlacementDirection() == BScreen::BottomTop)
721 win.setY(win.y() + where.height() - win.height());
722 if (screen->getRowPlacementDirection() == BScreen::RightLeft)
723 win.setX(win.x() + where.width() - win.width());
724 }
725 return True;
726 }
727
728
729 bool Workspace::underMousePlacement(Rect &win) {
730 int x, y, rx, ry;
731 Window c, r;
732 unsigned int m;
733 XQueryPointer(screen->getBlackbox()->getXDisplay(), screen->getRootWindow(),
734 &r, &c, &rx, &ry, &x, &y, &m);
735
736 Rect area;
737 #ifdef XINERAMA
738 if (screen->isXineramaActive() &&
739 screen->getBlackbox()->doXineramaPlacement()) {
740 RectList availableAreas = screen->allAvailableAreas();
741 RectList::iterator it, end = availableAreas.end();
742
743 for (it = availableAreas.begin(); it != end; ++it)
744 if (it->contains(rx, ry)) break;
745 assert(it != end); // the mouse isn't inside an area?
746 area = *it;
747 } else
748 #endif // XINERAMA
749 area = screen->availableArea();
750
751 x = rx - win.width() / 2;
752 y = ry - win.height() / 2;
753
754 if (x < area.x())
755 x = area.x();
756 if (y < area.y())
757 y = area.y();
758 if (x + win.width() > area.x() + area.width())
759 x = area.x() + area.width() - win.width();
760 if (y + win.height() > area.y() + area.height())
761 y = area.y() + area.height() - win.height();
762
763 win.setX(x);
764 win.setY(y);
765
766 return True;
767 }
768
769
770 bool Workspace::cascadePlacement(Rect &win, const int offset) {
771 Rect area;
772
773 #ifdef XINERAMA
774 if (screen->isXineramaActive() &&
775 screen->getBlackbox()->doXineramaPlacement()) {
776 area = screen->allAvailableAreas()[cascade_region];
777 } else
778 #endif // XINERAMA
779 area = screen->availableArea();
780
781 if ((static_cast<signed>(cascade_x + win.width()) > area.right() + 1) ||
782 (static_cast<signed>(cascade_y + win.height()) > area.bottom() + 1)) {
783 cascade_x = cascade_y = 0;
784 #ifdef XINERAMA
785 if (screen->isXineramaActive() &&
786 screen->getBlackbox()->doXineramaPlacement()) {
787 // go to the next xinerama region, and use its area
788 if (++cascade_region >= screen->allAvailableAreas().size())
789 cascade_region = 0;
790 area = screen->allAvailableAreas()[cascade_region];
791 }
792 #endif // XINERAMA
793 }
794
795 if (cascade_x == 0) {
796 cascade_x = area.x() + offset;
797 cascade_y = area.y() + offset;
798 }
799
800 win.setPos(cascade_x, cascade_y);
801
802 cascade_x += offset;
803 cascade_y += offset;
804
805 return True;
806 }
807
808
809 void Workspace::placeWindow(BlackboxWindow *win) {
810 Rect new_win(0, 0, win->frameRect().width(), win->frameRect().height());
811 bool placed = False;
812
813 switch (screen->getPlacementPolicy()) {
814 case BScreen::RowSmartPlacement:
815 case BScreen::ColSmartPlacement:
816 placed = smartPlacement(new_win);
817 break;
818 case BScreen::UnderMousePlacement:
819 case BScreen::ClickMousePlacement:
820 placed = underMousePlacement(new_win);
821 default:
822 break; // handled below
823 } // switch
824
825 if (placed == False)
826 cascadePlacement(new_win, (win->getTitleHeight() +
827 screen->getBorderWidth() * 2));
828
829 if (new_win.right() > screen->availableArea().right())
830 new_win.setX(screen->availableArea().left());
831 if (new_win.bottom() > screen->availableArea().bottom())
832 new_win.setY(screen->availableArea().top());
833
834 win->configure(new_win.x(), new_win.y(), new_win.width(), new_win.height());
835 }
This page took 0.078199 seconds and 5 git commands to generate.