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