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