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