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