]> Dogcows Code - chaz/openbox/blob - src/Workspace.cc
Fix send to menu, having deleted workspaces in it.
[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 }
114
115 if (! w->isDesktop())
116 raiseWindow(w);
117 else
118 lowerWindow(w);
119 }
120
121
122 void Workspace::removeWindow(BlackboxWindow *w, bool sticky) {
123 assert(w != 0);
124
125 stackingList.remove(w);
126
127 // pass focus to the next appropriate window
128 if ((w->isFocused() || w == lastfocus) &&
129 ! screen->getBlackbox()->doShutdown()) {
130 focusFallback(w);
131 }
132
133 if (! w->isNormal()) return;
134
135 BlackboxWindowList::iterator it, end = windowList.end();
136 int i;
137 for (i = 0, it = windowList.begin(); it != end; ++it, ++i)
138 if (*it == w)
139 break;
140 assert(it != end);
141
142 windowList.erase(it);
143 clientmenu->remove(i);
144 clientmenu->update();
145
146 if (! sticky) {
147 screen->updateNetizenWindowDel(w->getClientWindow());
148
149 BlackboxWindowList::iterator it = windowList.begin();
150 const BlackboxWindowList::iterator end = windowList.end();
151 unsigned int i = 0;
152 for (; it != end; ++it, ++i)
153 (*it)->setWindowNumber(i);
154 }
155
156 if (i == 0) {
157 cascade_x = cascade_y = 0;
158 #ifdef XINERAMA
159 cascade_region = 0;
160 #endif // XINERAMA
161 }
162 }
163
164
165 void Workspace::focusFallback(const BlackboxWindow *old_window) {
166 BlackboxWindow *newfocus = 0;
167
168 if (id == screen->getCurrentWorkspaceID()) {
169 // The window is on the visible workspace.
170
171 // if it's a transient, then try to focus its parent
172 if (old_window && old_window->isTransient()) {
173 newfocus = old_window->getTransientFor();
174
175 if (! newfocus ||
176 newfocus->isIconic() || // do not focus icons
177 newfocus->getWorkspaceNumber() != id || // or other workspaces
178 ! newfocus->setInputFocus())
179 newfocus = 0;
180 }
181
182 if (! newfocus) {
183 BlackboxWindowList::iterator it = stackingList.begin(),
184 end = stackingList.end();
185 for (; it != end; ++it) {
186 BlackboxWindow *tmp = *it;
187 if (tmp && tmp->isNormal() && tmp->setInputFocus()) {
188 // we found our new focus target
189 newfocus = tmp;
190 break;
191 }
192 }
193 }
194
195 screen->getBlackbox()->setFocusedWindow(newfocus);
196 } else {
197 // The window is not on the visible workspace.
198
199 if (old_window && lastfocus == old_window) {
200 // The window was the last-focus target, so we need to replace it.
201 BlackboxWindow *win = (BlackboxWindow*) 0;
202 if (! stackingList.empty())
203 win = stackingList.front();
204 setLastFocusedWindow(win);
205 }
206 }
207 }
208
209
210 void Workspace::setFocused(const BlackboxWindow *w, bool focused) {
211 BlackboxWindowList::iterator it, end = windowList.end();
212 int i;
213 for (i = 0, it = windowList.begin(); it != end; ++it, ++i)
214 if (*it == w)
215 break;
216 // if its == end, then a window thats not in the windowList
217 // got focused, such as a !isNormal() window.
218 if (it != end)
219 clientmenu->setItemSelected(i, focused);
220 }
221
222
223 void Workspace::removeAll(void) {
224 while (! windowList.empty())
225 windowList.front()->iconify();
226 }
227
228 void Workspace::showAll(void) {
229 BlackboxWindowList::iterator it = stackingList.begin();
230 const BlackboxWindowList::iterator end = stackingList.end();
231 for (; it != end; ++it) {
232 BlackboxWindow *bw = *it;
233 // not normal windows cant focus from mouse enters anyways, so we dont
234 // need to unmap/remap them on workspace changes
235 if (! bw->isStuck() || bw->isNormal())
236 bw->show();
237 }
238 }
239
240
241 void Workspace::hideAll(void) {
242 // withdraw in reverse order to minimize the number of Expose events
243
244 BlackboxWindowList lst(stackingList.rbegin(), stackingList.rend());
245
246 BlackboxWindowList::iterator it = lst.begin();
247 const BlackboxWindowList::iterator end = lst.end();
248 for (; it != end; ++it) {
249 BlackboxWindow *bw = *it;
250 // not normal windows cant focus from mouse enters anyways, so we dont
251 // need to unmap/remap them on workspace changes
252 if (! bw->isStuck() || bw->isNormal())
253 bw->withdraw();
254 }
255 }
256
257
258
259 /*
260 * returns the number of transients for win, plus the number of transients
261 * associated with each transient of win
262 */
263 static unsigned int countTransients(const BlackboxWindow * const win) {
264 BlackboxWindowList transients = win->getTransients();
265 if (transients.empty()) return 0;
266
267 unsigned int ret = transients.size();
268 BlackboxWindowList::const_iterator it = transients.begin(),
269 end = transients.end();
270 for (; it != end; ++it)
271 ret += countTransients(*it);
272
273 return ret;
274 }
275
276
277 /*
278 * puts the transients of win into the stack. windows are stacked above
279 * the window before it in the stackvector being iterated, meaning
280 * stack[0] is on bottom, stack[1] is above stack[0], stack[2] is above
281 * stack[1], etc...
282 */
283 void Workspace::raiseTransients(const BlackboxWindow * const win,
284 StackVector::iterator &stack) {
285 if (win->getTransients().empty()) return; // nothing to do
286
287 // put win's transients in the stack
288 BlackboxWindowList::const_iterator it, end = win->getTransients().end();
289 for (it = win->getTransients().begin(); it != end; ++it) {
290 BlackboxWindow *w = *it;
291 *stack++ = w->getFrameWindow();
292 screen->updateNetizenWindowRaise(w->getClientWindow());
293
294 if (! w->isIconic()) {
295 Workspace *wkspc = screen->getWorkspace(w->getWorkspaceNumber());
296 wkspc->stackingList.remove(w);
297 wkspc->stackingList.push_front(w);
298 }
299 }
300
301 // put transients of win's transients in the stack
302 for (it = win->getTransients().begin(); it != end; ++it)
303 raiseTransients(*it, stack);
304 }
305
306
307 void Workspace::lowerTransients(const BlackboxWindow * const win,
308 StackVector::iterator &stack) {
309 if (win->getTransients().empty()) return; // nothing to do
310
311 // put transients of win's transients in the stack
312 BlackboxWindowList::const_reverse_iterator it,
313 end = win->getTransients().rend();
314 for (it = win->getTransients().rbegin(); it != end; ++it)
315 lowerTransients(*it, stack);
316
317 // put win's transients in the stack
318 for (it = win->getTransients().rbegin(); it != end; ++it) {
319 BlackboxWindow *w = *it;
320 *stack++ = w->getFrameWindow();
321 screen->updateNetizenWindowLower(w->getClientWindow());
322
323 if (! w->isIconic()) {
324 Workspace *wkspc = screen->getWorkspace(w->getWorkspaceNumber());
325 wkspc->stackingList.remove(w);
326 wkspc->stackingList.push_back(w);
327 }
328 }
329 }
330
331
332 void Workspace::raiseWindow(BlackboxWindow *w) {
333 BlackboxWindow *win = w;
334
335 if (win->isDesktop()) return;
336
337 // walk up the transient_for's to the window that is not a transient
338 while (win->isTransient() && win->getTransientFor())
339 win = win->getTransientFor();
340
341 // get the total window count (win and all transients)
342 unsigned int i = 1 + countTransients(win);
343
344 // stack the window with all transients above
345 StackVector stack_vector(i);
346 StackVector::iterator stack = stack_vector.begin();
347
348 *(stack++) = win->getFrameWindow();
349 screen->updateNetizenWindowRaise(win->getClientWindow());
350 if (! (win->isIconic() || win->isDesktop())) {
351 Workspace *wkspc = screen->getWorkspace(win->getWorkspaceNumber());
352 wkspc->stackingList.remove(win);
353 wkspc->stackingList.push_front(win);
354 }
355
356 raiseTransients(win, stack);
357
358 screen->raiseWindows(&stack_vector[0], stack_vector.size());
359 }
360
361
362 void Workspace::lowerWindow(BlackboxWindow *w) {
363 BlackboxWindow *win = w;
364
365 // walk up the transient_for's to the window that is not a transient
366 while (win->isTransient() && win->getTransientFor())
367 win = win->getTransientFor();
368
369 // get the total window count (win and all transients)
370 unsigned int i = 1 + countTransients(win);
371
372 // stack the window with all transients above
373 StackVector stack_vector(i);
374 StackVector::iterator stack = stack_vector.begin();
375
376 lowerTransients(win, stack);
377
378 *(stack++) = win->getFrameWindow();
379 screen->updateNetizenWindowLower(win->getClientWindow());
380 if (! (win->isIconic() || win->isDesktop())) {
381 Workspace *wkspc = screen->getWorkspace(win->getWorkspaceNumber());
382 wkspc->stackingList.remove(win);
383 wkspc->stackingList.push_back(win);
384 }
385
386 screen->lowerWindows(&stack_vector[0], stack_vector.size());
387 }
388
389
390 void Workspace::reconfigure(void) {
391 clientmenu->reconfigure();
392 std::for_each(windowList.begin(), windowList.end(),
393 std::mem_fun(&BlackboxWindow::reconfigure));
394 }
395
396
397 BlackboxWindow *Workspace::getWindow(unsigned int index) {
398 if (index < windowList.size()) {
399 BlackboxWindowList::iterator it = windowList.begin();
400 while (index-- > 0) // increment to index
401 ++it;
402 return *it;
403 }
404
405 return 0;
406 }
407
408
409 BlackboxWindow*
410 Workspace::getNextWindowInList(BlackboxWindow *w) {
411 BlackboxWindowList::iterator it = std::find(windowList.begin(),
412 windowList.end(),
413 w);
414 assert(it != windowList.end()); // window must be in list
415 ++it; // next window
416 if (it == windowList.end())
417 return windowList.front(); // if we walked off the end, wrap around
418
419 return *it;
420 }
421
422
423 BlackboxWindow* Workspace::getPrevWindowInList(BlackboxWindow *w) {
424 BlackboxWindowList::iterator it = std::find(windowList.begin(),
425 windowList.end(),
426 w);
427 assert(it != windowList.end()); // window must be in list
428 if (it == windowList.begin())
429 return windowList.back(); // if we walked of the front, wrap around
430
431 return *(--it);
432 }
433
434
435 BlackboxWindow* Workspace::getTopWindowOnStack(void) const {
436 assert(! stackingList.empty());
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.080151 seconds and 4 git commands to generate.