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