]> Dogcows Code - chaz/openbox/blob - src/workspace.cc
rename, remove bullshit. ya
[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 "blackbox.hh"
49 #include "clientmenu.hh"
50 #include "font.hh"
51 #include "netizen.hh"
52 #include "screen.hh"
53 #include "toolbar.hh"
54 #include "util.hh"
55 #include "window.hh"
56 #include "workspace.hh"
57 #include "windowmenu.hh"
58 #include "xatom.hh"
59
60
61 Workspace::Workspace(BScreen *scrn, unsigned int i) {
62 screen = scrn;
63 xatom = screen->getBlackbox()->getXAtom();
64
65 cascade_x = cascade_y = 0;
66 #ifdef XINERAMA
67 cascade_region = 0;
68 #endif // XINERAMA
69
70 id = i;
71
72 clientmenu = new Clientmenu(this);
73
74 lastfocus = (BlackboxWindow *) 0;
75
76 readName();
77 }
78
79
80 void Workspace::addWindow(BlackboxWindow *w, bool place, bool sticky) {
81 assert(w != 0);
82
83 if (place) placeWindow(w);
84
85 stackingList.push_front(w);
86
87 if (! sticky)
88 w->setWorkspace(id);
89
90 if (! w->isNormal()) {
91 if (! sticky) {
92 // just give it some number, else bad things happen as it is assumed to
93 // not be on a workspace
94 w->setWindowNumber(0);
95 }
96 } else {
97 if (! sticky)
98 w->setWindowNumber(windowList.size());
99
100 windowList.push_back(w);
101
102 clientmenu->insert(w->getTitle());
103 clientmenu->update();
104
105 if (! sticky)
106 screen->updateNetizenWindowAdd(w->getClientWindow(), id);
107
108 if (screen->doFocusNew() || (w->isTransient() && w->getTransientFor() &&
109 w->getTransientFor()->isFocused())) {
110 if (id != screen->getCurrentWorkspaceID()) {
111 /*
112 not on the focused workspace, so the window is not going to get focus
113 but if the user wants new windows focused, then it should get focus
114 when this workspace does become focused.
115 */
116 lastfocus = w;
117 }
118 }
119 }
120
121 if (! w->isDesktop())
122 raiseWindow(w);
123 else
124 lowerWindow(w);
125 }
126
127
128 void Workspace::removeWindow(BlackboxWindow *w, bool sticky) {
129 assert(w != 0);
130
131 stackingList.remove(w);
132
133 // pass focus to the next appropriate window
134 if ((w->isFocused() || w == lastfocus) &&
135 ! screen->getBlackbox()->doShutdown()) {
136 focusFallback(w);
137 }
138
139 if (! w->isNormal()) return;
140
141 BlackboxWindowList::iterator it, end = windowList.end();
142 int i;
143 for (i = 0, it = windowList.begin(); it != end; ++it, ++i)
144 if (*it == w)
145 break;
146 assert(it != end);
147
148 windowList.erase(it);
149 clientmenu->remove(i);
150 clientmenu->update();
151
152 if (! sticky) {
153 screen->updateNetizenWindowDel(w->getClientWindow());
154
155 BlackboxWindowList::iterator it = windowList.begin();
156 const BlackboxWindowList::iterator end = windowList.end();
157 unsigned int i = 0;
158 for (; it != end; ++it, ++i)
159 (*it)->setWindowNumber(i);
160 }
161
162 if (i == 0) {
163 cascade_x = cascade_y = 0;
164 #ifdef XINERAMA
165 cascade_region = 0;
166 #endif // XINERAMA
167 }
168 }
169
170
171 void Workspace::focusFallback(const BlackboxWindow *old_window) {
172 BlackboxWindow *newfocus = 0;
173
174 if (id == screen->getCurrentWorkspaceID()) {
175 // The window is on the visible workspace.
176
177 // if it's a transient, then try to focus its parent
178 if (old_window && old_window->isTransient()) {
179 newfocus = old_window->getTransientFor();
180
181 if (! newfocus ||
182 newfocus->isIconic() || // do not focus icons
183 newfocus->getWorkspaceNumber() != id || // or other workspaces
184 ! newfocus->setInputFocus())
185 newfocus = 0;
186 }
187
188 if (! newfocus) {
189 BlackboxWindowList::iterator it = stackingList.begin(),
190 end = stackingList.end();
191 for (; it != end; ++it) {
192 BlackboxWindow *tmp = *it;
193 if (tmp && tmp->isNormal() && tmp->setInputFocus()) {
194 // we found our new focus target
195 newfocus = tmp;
196 break;
197 }
198 }
199 }
200
201 screen->getBlackbox()->setFocusedWindow(newfocus);
202 } else {
203 // The window is not on the visible workspace.
204
205 if (old_window && lastfocus == old_window) {
206 // The window was the last-focus target, so we need to replace it.
207 BlackboxWindow *win = (BlackboxWindow*) 0;
208 if (! stackingList.empty())
209 win = stackingList.front();
210 setLastFocusedWindow(win);
211 }
212 }
213 }
214
215
216 void Workspace::setFocused(const BlackboxWindow *w, bool focused) {
217 BlackboxWindowList::iterator it, end = windowList.end();
218 int i;
219 for (i = 0, it = windowList.begin(); it != end; ++it, ++i)
220 if (*it == w)
221 break;
222 // if its == end, then a window thats not in the windowList
223 // got focused, such as a !isNormal() window.
224 if (it != end)
225 clientmenu->setItemSelected(i, focused);
226 }
227
228
229 void Workspace::removeAll(void) {
230 while (! windowList.empty())
231 windowList.front()->iconify();
232 }
233
234 void Workspace::showAll(void) {
235 BlackboxWindowList::iterator it = stackingList.begin();
236 const BlackboxWindowList::iterator end = stackingList.end();
237 for (; it != end; ++it) {
238 BlackboxWindow *bw = *it;
239 // sticky windows arent unmapped on a workspace change so we don't have ot
240 // map them, but sometimes on a restart, another app can unmap our sticky
241 // windows, so we map on startup always
242 if (! bw->isStuck() || screen->getBlackbox()->isStartup())
243 bw->show();
244 }
245 }
246
247
248 void Workspace::hideAll(void) {
249 // withdraw in reverse order to minimize the number of Expose events
250
251 BlackboxWindowList lst(stackingList.rbegin(), stackingList.rend());
252
253 BlackboxWindowList::iterator it = lst.begin();
254 const BlackboxWindowList::iterator end = lst.end();
255 for (; it != end; ++it) {
256 BlackboxWindow *bw = *it;
257 // don't hide sticky windows, or they'll end up flickering on a workspace
258 // change
259 if (! bw->isStuck())
260 bw->withdraw();
261 }
262 }
263
264
265
266 /*
267 * returns the number of transients for win, plus the number of transients
268 * associated with each transient of win
269 */
270 static unsigned int countTransients(const BlackboxWindow * const win) {
271 BlackboxWindowList transients = win->getTransients();
272 if (transients.empty()) return 0;
273
274 unsigned int ret = transients.size();
275 BlackboxWindowList::const_iterator it = transients.begin(),
276 end = transients.end();
277 for (; it != end; ++it)
278 ret += countTransients(*it);
279
280 return ret;
281 }
282
283
284 /*
285 * puts the transients of win into the stack. windows are stacked above
286 * the window before it in the stackvector being iterated, meaning
287 * stack[0] is on bottom, stack[1] is above stack[0], stack[2] is above
288 * stack[1], etc...
289 */
290 void Workspace::raiseTransients(const BlackboxWindow * const win,
291 StackVector::iterator &stack) {
292 if (win->getTransients().empty()) return; // nothing to do
293
294 // put win's transients in the stack
295 BlackboxWindowList::const_iterator it, end = win->getTransients().end();
296 for (it = win->getTransients().begin(); it != end; ++it) {
297 BlackboxWindow *w = *it;
298 *stack++ = w->getFrameWindow();
299 screen->updateNetizenWindowRaise(w->getClientWindow());
300
301 if (! w->isIconic()) {
302 Workspace *wkspc = screen->getWorkspace(w->getWorkspaceNumber());
303 wkspc->stackingList.remove(w);
304 wkspc->stackingList.push_front(w);
305 }
306 }
307
308 // put transients of win's transients in the stack
309 for (it = win->getTransients().begin(); it != end; ++it)
310 raiseTransients(*it, stack);
311 }
312
313
314 void Workspace::lowerTransients(const BlackboxWindow * const win,
315 StackVector::iterator &stack) {
316 if (win->getTransients().empty()) return; // nothing to do
317
318 // put transients of win's transients in the stack
319 BlackboxWindowList::const_reverse_iterator it,
320 end = win->getTransients().rend();
321 for (it = win->getTransients().rbegin(); it != end; ++it)
322 lowerTransients(*it, stack);
323
324 // put win's transients in the stack
325 for (it = win->getTransients().rbegin(); it != end; ++it) {
326 BlackboxWindow *w = *it;
327 *stack++ = w->getFrameWindow();
328 screen->updateNetizenWindowLower(w->getClientWindow());
329
330 if (! w->isIconic()) {
331 Workspace *wkspc = screen->getWorkspace(w->getWorkspaceNumber());
332 wkspc->stackingList.remove(w);
333 wkspc->stackingList.push_back(w);
334 }
335 }
336 }
337
338
339 void Workspace::raiseWindow(BlackboxWindow *w) {
340 BlackboxWindow *win = w;
341
342 if (win->isDesktop()) return;
343
344 // walk up the transient_for's to the window that is not a transient
345 while (win->isTransient() && win->getTransientFor())
346 win = win->getTransientFor();
347
348 // get the total window count (win and all transients)
349 unsigned int i = 1 + countTransients(win);
350
351 // stack the window with all transients above
352 StackVector stack_vector(i);
353 StackVector::iterator stack = stack_vector.begin();
354
355 *(stack++) = win->getFrameWindow();
356 screen->updateNetizenWindowRaise(win->getClientWindow());
357 if (! (win->isIconic() || win->isDesktop())) {
358 Workspace *wkspc = screen->getWorkspace(win->getWorkspaceNumber());
359 wkspc->stackingList.remove(win);
360 wkspc->stackingList.push_front(win);
361 }
362
363 raiseTransients(win, stack);
364
365 screen->raiseWindows(&stack_vector[0], stack_vector.size());
366 }
367
368
369 void Workspace::lowerWindow(BlackboxWindow *w) {
370 BlackboxWindow *win = w;
371
372 // walk up the transient_for's to the window that is not a transient
373 while (win->isTransient() && win->getTransientFor())
374 win = win->getTransientFor();
375
376 // get the total window count (win and all transients)
377 unsigned int i = 1 + countTransients(win);
378
379 // stack the window with all transients above
380 StackVector stack_vector(i);
381 StackVector::iterator stack = stack_vector.begin();
382
383 lowerTransients(win, stack);
384
385 *(stack++) = win->getFrameWindow();
386 screen->updateNetizenWindowLower(win->getClientWindow());
387 if (! (win->isIconic() || win->isDesktop())) {
388 Workspace *wkspc = screen->getWorkspace(win->getWorkspaceNumber());
389 wkspc->stackingList.remove(win);
390 wkspc->stackingList.push_back(win);
391 }
392
393 screen->lowerWindows(&stack_vector[0], stack_vector.size());
394 }
395
396
397 void Workspace::reconfigure(void) {
398 clientmenu->reconfigure();
399 std::for_each(windowList.begin(), windowList.end(),
400 std::mem_fun(&BlackboxWindow::reconfigure));
401 }
402
403
404 BlackboxWindow *Workspace::getWindow(unsigned int index) {
405 if (index < windowList.size()) {
406 BlackboxWindowList::iterator it = windowList.begin();
407 while (index-- > 0) // increment to index
408 ++it;
409 return *it;
410 }
411
412 return 0;
413 }
414
415
416 BlackboxWindow*
417 Workspace::getNextWindowInList(BlackboxWindow *w) {
418 BlackboxWindowList::iterator it = std::find(windowList.begin(),
419 windowList.end(),
420 w);
421 assert(it != windowList.end()); // window must be in list
422 ++it; // next window
423 if (it == windowList.end())
424 return windowList.front(); // if we walked off the end, wrap around
425
426 return *it;
427 }
428
429
430 BlackboxWindow* Workspace::getPrevWindowInList(BlackboxWindow *w) {
431 BlackboxWindowList::iterator it = std::find(windowList.begin(),
432 windowList.end(),
433 w);
434 assert(it != windowList.end()); // window must be in list
435 if (it == windowList.begin())
436 return windowList.back(); // if we walked of the front, wrap around
437
438 return *(--it);
439 }
440
441
442 BlackboxWindow* Workspace::getTopWindowOnStack(void) const {
443 assert(! stackingList.empty());
444 return stackingList.front();
445 }
446
447
448 void Workspace::sendWindowList(Netizen &n) {
449 BlackboxWindowList::iterator it = windowList.begin(),
450 end = windowList.end();
451 for(; it != end; ++it)
452 n.sendWindowAdd((*it)->getClientWindow(), getID());
453 }
454
455
456 unsigned int Workspace::getCount(void) const {
457 return windowList.size();
458 }
459
460
461 void Workspace::appendStackOrder(BlackboxWindowList &stack_order) const {
462 BlackboxWindowList::const_reverse_iterator it = stackingList.rbegin();
463 const BlackboxWindowList::const_reverse_iterator end = stackingList.rend();
464 for (; it != end; ++it)
465 // don't add desktop wnidows, or sticky windows more than once
466 if (! ( (*it)->isDesktop() ||
467 ((*it)->isStuck() && id != screen->getCurrentWorkspaceID())))
468 stack_order.push_back(*it);
469 }
470
471
472 bool Workspace::isCurrent(void) const {
473 return (id == screen->getCurrentWorkspaceID());
474 }
475
476
477 bool Workspace::isLastWindow(const BlackboxWindow* const w) const {
478 return (w == windowList.back());
479 }
480
481
482 void Workspace::setCurrent(void) {
483 screen->changeWorkspaceID(id);
484 }
485
486
487 void Workspace::readName(void) {
488 XAtom::StringVect namesList;
489 unsigned long numnames = id + 1;
490
491 // attempt to get from the _NET_WM_DESKTOP_NAMES property
492 if (xatom->getValue(screen->getRootWindow(), XAtom::net_desktop_names,
493 XAtom::utf8, numnames, namesList) &&
494 namesList.size() > id) {
495 name = namesList[id];
496
497 clientmenu->setLabel(name);
498 clientmenu->update();
499 } else {
500 /*
501 Use a default name. This doesn't actually change the class. That will
502 happen after the setName changes the root property, and that change
503 makes its way back to this function.
504 */
505 string tmp =i18n(WorkspaceSet, WorkspaceDefaultNameFormat,
506 "Workspace %d");
507 assert(tmp.length() < 32);
508 char default_name[32];
509 sprintf(default_name, tmp.c_str(), id + 1);
510
511 setName(default_name); // save this into the _NET_WM_DESKTOP_NAMES property
512 }
513 }
514
515
516 void Workspace::setName(const string& new_name) {
517 // set the _NET_WM_DESKTOP_NAMES property with the new name
518 XAtom::StringVect namesList;
519 unsigned long numnames = (unsigned) -1;
520 if (xatom->getValue(screen->getRootWindow(), XAtom::net_desktop_names,
521 XAtom::utf8, numnames, namesList) &&
522 namesList.size() > id)
523 namesList[id] = new_name;
524 else
525 namesList.push_back(new_name);
526
527 xatom->setValue(screen->getRootWindow(), XAtom::net_desktop_names,
528 XAtom::utf8, namesList);
529 }
530
531
532 /*
533 * Calculate free space available for window placement.
534 */
535 Workspace::rectList Workspace::calcSpace(const Rect &win,
536 const rectList &spaces) const {
537 Rect isect, extra;
538 rectList result;
539 rectList::const_iterator siter, end = spaces.end();
540 for (siter = spaces.begin(); siter != end; ++siter) {
541 const Rect &curr = *siter;
542
543 if(! win.intersects(curr)) {
544 result.push_back(curr);
545 continue;
546 }
547
548 /* Use an intersection of win and curr to determine the space around
549 * curr that we can use.
550 *
551 * NOTE: the spaces calculated can overlap.
552 */
553 isect = curr & win;
554
555 // left
556 extra.setCoords(curr.left(), curr.top(),
557 isect.left() - screen->getSnapOffset(), curr.bottom());
558 if (extra.valid()) result.push_back(extra);
559
560 // top
561 extra.setCoords(curr.left(), curr.top(),
562 curr.right(), isect.top() - screen->getSnapOffset());
563 if (extra.valid()) result.push_back(extra);
564
565 // right
566 extra.setCoords(isect.right() + screen->getSnapOffset(), curr.top(),
567 curr.right(), curr.bottom());
568 if (extra.valid()) result.push_back(extra);
569
570 // bottom
571 extra.setCoords(curr.left(), isect.bottom() + screen->getSnapOffset(),
572 curr.right(), curr.bottom());
573 if (extra.valid()) result.push_back(extra);
574 }
575 return result;
576 }
577
578
579 static bool rowRLBT(const Rect &first, const Rect &second) {
580 if (first.bottom() == second.bottom())
581 return first.right() > second.right();
582 return first.bottom() > second.bottom();
583 }
584
585 static bool rowRLTB(const Rect &first, const Rect &second) {
586 if (first.y() == second.y())
587 return first.right() > second.right();
588 return first.y() < second.y();
589 }
590
591 static bool rowLRBT(const Rect &first, const Rect &second) {
592 if (first.bottom() == second.bottom())
593 return first.x() < second.x();
594 return first.bottom() > second.bottom();
595 }
596
597 static bool rowLRTB(const Rect &first, const Rect &second) {
598 if (first.y() == second.y())
599 return first.x() < second.x();
600 return first.y() < second.y();
601 }
602
603 static bool colLRTB(const Rect &first, const Rect &second) {
604 if (first.x() == second.x())
605 return first.y() < second.y();
606 return first.x() < second.x();
607 }
608
609 static bool colLRBT(const Rect &first, const Rect &second) {
610 if (first.x() == second.x())
611 return first.bottom() > second.bottom();
612 return first.x() < second.x();
613 }
614
615 static bool colRLTB(const Rect &first, const Rect &second) {
616 if (first.right() == second.right())
617 return first.y() < second.y();
618 return first.right() > second.right();
619 }
620
621 static bool colRLBT(const Rect &first, const Rect &second) {
622 if (first.right() == second.right())
623 return first.bottom() > second.bottom();
624 return first.right() > second.right();
625 }
626
627
628 bool Workspace::smartPlacement(Rect& win) {
629 rectList spaces;
630
631 //initially the entire screen is free
632 #ifdef XINERAMA
633 if (screen->isXineramaActive() &&
634 screen->getBlackbox()->doXineramaPlacement()) {
635 RectList availableAreas = screen->allAvailableAreas();
636 RectList::iterator it, end = availableAreas.end();
637
638 for (it = availableAreas.begin(); it != end; ++it) {
639 Rect r = *it;
640 r.setRect(r.x() + screen->getSnapOffset(),
641 r.y() + screen->getSnapOffset(),
642 r.width() - screen->getSnapOffset(),
643 r.height() - screen->getSnapOffset());
644 spaces.push_back(*it);
645 }
646 } else
647 #endif // XINERAMA
648 {
649 Rect r = screen->availableArea();
650 r.setRect(r.x() + screen->getSnapOffset(),
651 r.y() + screen->getSnapOffset(),
652 r.width() - screen->getSnapOffset(),
653 r.height() - screen->getSnapOffset());
654 spaces.push_back(r);
655 }
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.070351 seconds and 4 git commands to generate.