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