openbox/src/Workspace.cc

826 lines
24 KiB
C++
Raw Normal View History

// -*- mode: C++; indent-tabs-mode: nil; c-basic-offset: 2; -*-
// Workspace.cc for Blackbox - an X11 Window manager
// Copyright (c) 2001 - 2002 Sean 'Shaleh' Perry <shaleh@debian.org>
2002-04-11 03:20:38 +00:00
// Copyright (c) 1997 - 2000 Brad Hughes (bhughes@tcac.net)
//
// Permission is hereby granted, free of charge, to any person obtaining a
// copy of this software and associated documentation files (the "Software"),
// to deal in the Software without restriction, including without limitation
// the rights to use, copy, modify, merge, publish, distribute, sublicense,
// and/or sell copies of the Software, and to permit persons to whom the
// Software is furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE.
#ifdef HAVE_CONFIG_H
# include "../config.h"
#endif // HAVE_CONFIG_H
extern "C" {
#include <X11/Xlib.h>
#include <X11/Xatom.h>
#ifdef HAVE_STDIO_H
# include <stdio.h>
#endif // HAVE_STDIO_H
#ifdef HAVE_STRING_H
# include <string.h>
#endif // HAVE_STRING_H
}
2002-06-01 17:54:32 +00:00
#include <assert.h>
#include <functional>
#include <string>
2002-04-11 03:20:38 +00:00
using std::string;
2002-04-11 03:20:38 +00:00
#include "i18n.hh"
#include "blackbox.hh"
#include "Clientmenu.hh"
#include "Font.hh"
#include "Netizen.hh"
#include "Screen.hh"
#include "Toolbar.hh"
#include "Util.hh"
#include "Window.hh"
#include "Workspace.hh"
#include "Windowmenu.hh"
#include "XAtom.hh"
2002-04-11 03:20:38 +00:00
Workspace::Workspace(BScreen *scrn, unsigned int i) {
screen = scrn;
xatom = screen->getBlackbox()->getXAtom();
2002-04-11 03:20:38 +00:00
cascade_x = cascade_y = 0;
#ifdef XINERAMA
cascade_region = 0;
#endif // XINERAMA
2002-04-11 03:20:38 +00:00
id = i;
2002-04-11 03:20:38 +00:00
clientmenu = new Clientmenu(this);
lastfocus = (BlackboxWindow *) 0;
readName();
2002-04-11 03:20:38 +00:00
}
void Workspace::addWindow(BlackboxWindow *w, bool place, bool sticky) {
assert(w != 0);
2002-04-11 03:20:38 +00:00
if (place) placeWindow(w);
stackingList.push_front(w);
if (! sticky)
w->setWorkspace(id);
if (! w->isNormal()) {
if (! sticky) {
// just give it some number, else bad things happen as it is assumed to
// not be on a workspace
w->setWindowNumber(0);
}
} else {
if (! sticky)
w->setWindowNumber(windowList.size());
2002-04-11 03:20:38 +00:00
windowList.push_back(w);
2002-04-11 03:20:38 +00:00
clientmenu->insert(w->getTitle());
clientmenu->update();
if (! sticky)
screen->updateNetizenWindowAdd(w->getClientWindow(), id);
if (screen->doFocusNew() || (w->isTransient() && w->getTransientFor() &&
w->getTransientFor()->isFocused())) {
if (id != screen->getCurrentWorkspaceID()) {
/*
not on the focused workspace, so the window is not going to get focus
but if the user wants new windows focused, then it should get focus
when this workspace does become focused.
*/
lastfocus = w;
}
}
}
2002-04-11 03:20:38 +00:00
if (! w->isDesktop())
raiseWindow(w);
else
lowerWindow(w);
2002-04-11 03:20:38 +00:00
}
void Workspace::removeWindow(BlackboxWindow *w, bool sticky) {
assert(w != 0);
2002-04-11 03:20:38 +00:00
stackingList.remove(w);
2002-04-11 03:20:38 +00:00
2002-06-21 01:06:29 +00:00
// pass focus to the next appropriate window
if ((w->isFocused() || w == lastfocus) &&
! screen->getBlackbox()->doShutdown()) {
2002-07-14 18:45:46 +00:00
focusFallback(w);
}
if (! w->isNormal()) return;
BlackboxWindowList::iterator it, end = windowList.end();
int i;
for (i = 0, it = windowList.begin(); it != end; ++it, ++i)
if (*it == w)
break;
assert(it != end);
windowList.erase(it);
clientmenu->remove(i);
2002-04-11 03:20:38 +00:00
clientmenu->update();
if (! sticky) {
screen->updateNetizenWindowDel(w->getClientWindow());
2002-04-11 03:20:38 +00:00
BlackboxWindowList::iterator it = windowList.begin();
const BlackboxWindowList::iterator end = windowList.end();
unsigned int i = 0;
for (; it != end; ++it, ++i)
(*it)->setWindowNumber(i);
}
2002-04-11 03:20:38 +00:00
if (i == 0) {
cascade_x = cascade_y = 0;
#ifdef XINERAMA
cascade_region = 0;
#endif // XINERAMA
}
}
2002-07-10 22:24:48 +00:00
void Workspace::focusFallback(const BlackboxWindow *old_window) {
BlackboxWindow *newfocus = 0;
2002-07-14 18:45:46 +00:00
if (id == screen->getCurrentWorkspaceID()) {
// The window is on the visible workspace.
2002-07-10 22:24:48 +00:00
2002-07-14 18:45:46 +00:00
// if it's a transient, then try to focus its parent
if (old_window && old_window->isTransient()) {
newfocus = old_window->getTransientFor();
if (! newfocus ||
newfocus->isIconic() || // do not focus icons
newfocus->getWorkspaceNumber() != id || // or other workspaces
! newfocus->setInputFocus())
newfocus = 0;
}
2002-07-10 22:24:48 +00:00
2002-07-14 18:45:46 +00:00
if (! newfocus) {
BlackboxWindowList::iterator it = stackingList.begin(),
end = stackingList.end();
for (; it != end; ++it) {
BlackboxWindow *tmp = *it;
if (tmp && tmp->isNormal() && tmp->setInputFocus()) {
2002-07-14 18:45:46 +00:00
// we found our new focus target
newfocus = tmp;
break;
}
2002-07-10 22:24:48 +00:00
}
}
2002-07-14 18:45:46 +00:00
screen->getBlackbox()->setFocusedWindow(newfocus);
} else {
// The window is not on the visible workspace.
if (old_window && lastfocus == old_window) {
// The window was the last-focus target, so we need to replace it.
BlackboxWindow *win = (BlackboxWindow*) 0;
if (! stackingList.empty())
win = stackingList.front();
setLastFocusedWindow(win);
}
}
2002-07-10 22:24:48 +00:00
}
void Workspace::setFocused(const BlackboxWindow *w, bool focused) {
BlackboxWindowList::iterator it, end = windowList.end();
int i;
for (i = 0, it = windowList.begin(); it != end; ++it, ++i)
if (*it == w)
break;
// if its == end, then a window thats not in the windowList
// got focused, such as a !isNormal() window.
if (it != end)
clientmenu->setItemSelected(i, focused);
}
void Workspace::removeAll(void) {
while (! windowList.empty())
windowList.front()->iconify();
}
2002-04-11 03:20:38 +00:00
void Workspace::showAll(void) {
BlackboxWindowList::iterator it = stackingList.begin();
const BlackboxWindowList::iterator end = stackingList.end();
for (; it != end; ++it) {
BlackboxWindow *bw = *it;
// not normal windows cant focus from mouse enters anyways, so we dont
// need to unmap/remap them on workspace changes
if (! bw->isStuck() || bw->isNormal())
bw->show();
}
}
void Workspace::hideAll(void) {
// withdraw in reverse order to minimize the number of Expose events
BlackboxWindowList lst(stackingList.rbegin(), stackingList.rend());
BlackboxWindowList::iterator it = lst.begin();
const BlackboxWindowList::iterator end = lst.end();
for (; it != end; ++it) {
BlackboxWindow *bw = *it;
// not normal windows cant focus from mouse enters anyways, so we dont
// need to unmap/remap them on workspace changes
if (! bw->isStuck() || bw->isNormal())
bw->withdraw();
}
}
2002-04-11 03:20:38 +00:00
/*
* returns the number of transients for win, plus the number of transients
* associated with each transient of win
*/
2002-08-07 00:24:58 +00:00
static unsigned int countTransients(const BlackboxWindow * const win) {
BlackboxWindowList transients = win->getTransients();
if (transients.empty()) return 0;
unsigned int ret = transients.size();
BlackboxWindowList::const_iterator it = transients.begin(),
end = transients.end();
for (; it != end; ++it)
ret += countTransients(*it);
return ret;
}
/*
* puts the transients of win into the stack. windows are stacked above
* the window before it in the stackvector being iterated, meaning
* stack[0] is on bottom, stack[1] is above stack[0], stack[2] is above
* stack[1], etc...
*/
void Workspace::raiseTransients(const BlackboxWindow * const win,
StackVector::iterator &stack) {
2002-08-07 00:24:58 +00:00
if (win->getTransients().empty()) return; // nothing to do
// put win's transients in the stack
BlackboxWindowList::const_iterator it, end = win->getTransients().end();
for (it = win->getTransients().begin(); it != end; ++it) {
2002-08-07 00:24:58 +00:00
BlackboxWindow *w = *it;
*stack++ = w->getFrameWindow();
screen->updateNetizenWindowRaise(w->getClientWindow());
if (! w->isIconic()) {
Workspace *wkspc = screen->getWorkspace(w->getWorkspaceNumber());
wkspc->stackingList.remove(w);
wkspc->stackingList.push_front(w);
}
}
2002-04-11 03:20:38 +00:00
// put transients of win's transients in the stack
2002-08-07 00:24:58 +00:00
for (it = win->getTransients().begin(); it != end; ++it)
raiseTransients(*it, stack);
}
2002-04-11 03:20:38 +00:00
void Workspace::lowerTransients(const BlackboxWindow * const win,
StackVector::iterator &stack) {
2002-08-07 00:24:58 +00:00
if (win->getTransients().empty()) return; // nothing to do
2002-04-11 03:20:38 +00:00
// put transients of win's transients in the stack
BlackboxWindowList::const_reverse_iterator it,
end = win->getTransients().rend();
2002-08-07 00:24:58 +00:00
for (it = win->getTransients().rbegin(); it != end; ++it)
lowerTransients(*it, stack);
2002-04-11 03:20:38 +00:00
// put win's transients in the stack
for (it = win->getTransients().rbegin(); it != end; ++it) {
2002-08-07 00:24:58 +00:00
BlackboxWindow *w = *it;
*stack++ = w->getFrameWindow();
screen->updateNetizenWindowLower(w->getClientWindow());
if (! w->isIconic()) {
Workspace *wkspc = screen->getWorkspace(w->getWorkspaceNumber());
wkspc->stackingList.remove(w);
wkspc->stackingList.push_back(w);
}
2002-04-11 03:20:38 +00:00
}
}
void Workspace::raiseWindow(BlackboxWindow *w) {
BlackboxWindow *win = w;
if (win->isDesktop()) return;
// walk up the transient_for's to the window that is not a transient
2002-08-07 00:24:58 +00:00
while (win->isTransient() && win->getTransientFor())
win = win->getTransientFor();
2002-04-11 03:20:38 +00:00
// get the total window count (win and all transients)
unsigned int i = 1 + countTransients(win);
2002-04-11 03:20:38 +00:00
// stack the window with all transients above
StackVector stack_vector(i);
StackVector::iterator stack = stack_vector.begin();
2002-04-11 03:20:38 +00:00
*(stack++) = win->getFrameWindow();
screen->updateNetizenWindowRaise(win->getClientWindow());
if (! (win->isIconic() || win->isDesktop())) {
Workspace *wkspc = screen->getWorkspace(win->getWorkspaceNumber());
wkspc->stackingList.remove(win);
wkspc->stackingList.push_front(win);
2002-04-11 03:20:38 +00:00
}
raiseTransients(win, stack);
2002-04-11 03:20:38 +00:00
screen->raiseWindows(&stack_vector[0], stack_vector.size());
}
2002-04-11 03:20:38 +00:00
void Workspace::lowerWindow(BlackboxWindow *w) {
BlackboxWindow *win = w;
2002-04-11 03:20:38 +00:00
// walk up the transient_for's to the window that is not a transient
2002-08-07 00:24:58 +00:00
while (win->isTransient() && win->getTransientFor())
2002-04-11 03:20:38 +00:00
win = win->getTransientFor();
// get the total window count (win and all transients)
unsigned int i = 1 + countTransients(win);
// stack the window with all transients above
StackVector stack_vector(i);
StackVector::iterator stack = stack_vector.begin();
2002-04-11 03:20:38 +00:00
lowerTransients(win, stack);
2002-04-11 03:20:38 +00:00
*(stack++) = win->getFrameWindow();
screen->updateNetizenWindowLower(win->getClientWindow());
if (! (win->isIconic() || win->isDesktop())) {
Workspace *wkspc = screen->getWorkspace(win->getWorkspaceNumber());
wkspc->stackingList.remove(win);
wkspc->stackingList.push_back(win);
}
2002-04-11 03:20:38 +00:00
screen->lowerWindows(&stack_vector[0], stack_vector.size());
2002-04-11 03:20:38 +00:00
}
void Workspace::reconfigure(void) {
clientmenu->reconfigure();
std::for_each(windowList.begin(), windowList.end(),
std::mem_fun(&BlackboxWindow::reconfigure));
}
2002-04-11 03:20:38 +00:00
BlackboxWindow *Workspace::getWindow(unsigned int index) {
if (index < windowList.size()) {
BlackboxWindowList::iterator it = windowList.begin();
2002-08-07 00:24:58 +00:00
while (index-- > 0) // increment to index
++it;
return *it;
}
2002-08-07 00:24:58 +00:00
return 0;
2002-04-11 03:20:38 +00:00
}
BlackboxWindow*
Workspace::getNextWindowInList(BlackboxWindow *w) {
BlackboxWindowList::iterator it = std::find(windowList.begin(),
windowList.end(),
w);
assert(it != windowList.end()); // window must be in list
++it; // next window
if (it == windowList.end())
return windowList.front(); // if we walked off the end, wrap around
return *it;
2002-04-11 03:20:38 +00:00
}
BlackboxWindow* Workspace::getPrevWindowInList(BlackboxWindow *w) {
BlackboxWindowList::iterator it = std::find(windowList.begin(),
windowList.end(),
w);
assert(it != windowList.end()); // window must be in list
if (it == windowList.begin())
return windowList.back(); // if we walked of the front, wrap around
return *(--it);
2002-04-11 03:20:38 +00:00
}
BlackboxWindow* Workspace::getTopWindowOnStack(void) const {
2002-08-07 00:24:58 +00:00
assert(! stackingList.empty());
return stackingList.front();
2002-04-11 03:20:38 +00:00
}
void Workspace::sendWindowList(Netizen &n) {
BlackboxWindowList::iterator it = windowList.begin(),
end = windowList.end();
for(; it != end; ++it)
n.sendWindowAdd((*it)->getClientWindow(), getID());
}
unsigned int Workspace::getCount(void) const {
return windowList.size();
}
void Workspace::appendStackOrder(BlackboxWindowList &stack_order) const {
BlackboxWindowList::const_reverse_iterator it = stackingList.rbegin();
const BlackboxWindowList::const_reverse_iterator end = stackingList.rend();
for (; it != end; ++it)
2002-07-16 22:01:17 +00:00
if ((*it)->isNormal())
stack_order.push_back(*it);
}
2002-08-07 00:24:58 +00:00
bool Workspace::isCurrent(void) const {
return (id == screen->getCurrentWorkspaceID());
2002-04-11 03:20:38 +00:00
}
bool Workspace::isLastWindow(const BlackboxWindow* const w) const {
return (w == windowList.back());
}
void Workspace::setCurrent(void) {
screen->changeWorkspaceID(id);
}
2002-04-11 03:20:38 +00:00
void Workspace::readName(void) {
XAtom::StringVect namesList;
unsigned long numnames = id + 1;
// attempt to get from the _NET_WM_DESKTOP_NAMES property
if (xatom->getValue(screen->getRootWindow(), XAtom::net_desktop_names,
XAtom::utf8, numnames, namesList) &&
namesList.size() > id) {
name = namesList[id];
clientmenu->setLabel(name);
clientmenu->update();
2002-04-11 03:20:38 +00:00
} else {
/*
Use a default name. This doesn't actually change the class. That will
happen after the setName changes the root property, and that change
makes its way back to this function.
*/
string tmp =i18n(WorkspaceSet, WorkspaceDefaultNameFormat,
"Workspace %d");
assert(tmp.length() < 32);
char default_name[32];
sprintf(default_name, tmp.c_str(), id + 1);
setName(default_name); // save this into the _NET_WM_DESKTOP_NAMES property
}
}
void Workspace::setName(const string& new_name) {
// set the _NET_WM_DESKTOP_NAMES property with the new name
XAtom::StringVect namesList;
unsigned long numnames = (unsigned) -1;
if (xatom->getValue(screen->getRootWindow(), XAtom::net_desktop_names,
XAtom::utf8, numnames, namesList) &&
namesList.size() > id)
namesList[id] = new_name;
else
namesList.push_back(new_name);
xatom->setValue(screen->getRootWindow(), XAtom::net_desktop_names,
XAtom::utf8, namesList);
2002-04-11 03:20:38 +00:00
}
/*
* Calculate free space available for window placement.
*/
Workspace::rectList Workspace::calcSpace(const Rect &win,
const rectList &spaces) const {
Rect isect, extra;
rectList result;
rectList::const_iterator siter, end = spaces.end();
for (siter = spaces.begin(); siter != end; ++siter) {
const Rect &curr = *siter;
if(! win.intersects(curr)) {
result.push_back(curr);
continue;
}
/* Use an intersection of win and curr to determine the space around
* curr that we can use.
*
* NOTE: the spaces calculated can overlap.
*/
isect = curr & win;
// left
extra.setCoords(curr.left(), curr.top(),
isect.left() - screen->getSnapOffset(), curr.bottom());
if (extra.valid()) result.push_back(extra);
// top
extra.setCoords(curr.left(), curr.top(),
curr.right(), isect.top() - screen->getSnapOffset());
if (extra.valid()) result.push_back(extra);
// right
extra.setCoords(isect.right() + screen->getSnapOffset(), curr.top(),
curr.right(), curr.bottom());
if (extra.valid()) result.push_back(extra);
// bottom
extra.setCoords(curr.left(), isect.bottom() + screen->getSnapOffset(),
curr.right(), curr.bottom());
if (extra.valid()) result.push_back(extra);
}
return result;
}
static bool rowRLBT(const Rect &first, const Rect &second) {
if (first.bottom() == second.bottom())
return first.right() > second.right();
return first.bottom() > second.bottom();
}
static bool rowRLTB(const Rect &first, const Rect &second) {
if (first.y() == second.y())
return first.right() > second.right();
return first.y() < second.y();
}
static bool rowLRBT(const Rect &first, const Rect &second) {
if (first.bottom() == second.bottom())
return first.x() < second.x();
return first.bottom() > second.bottom();
}
static bool rowLRTB(const Rect &first, const Rect &second) {
if (first.y() == second.y())
return first.x() < second.x();
return first.y() < second.y();
}
static bool colLRTB(const Rect &first, const Rect &second) {
if (first.x() == second.x())
return first.y() < second.y();
return first.x() < second.x();
}
static bool colLRBT(const Rect &first, const Rect &second) {
if (first.x() == second.x())
return first.bottom() > second.bottom();
return first.x() < second.x();
}
static bool colRLTB(const Rect &first, const Rect &second) {
if (first.right() == second.right())
return first.y() < second.y();
return first.right() > second.right();
}
static bool colRLBT(const Rect &first, const Rect &second) {
if (first.right() == second.right())
return first.bottom() > second.bottom();
return first.right() > second.right();
}
2002-07-22 04:29:40 +00:00
bool Workspace::smartPlacement(Rect& win) {
rectList spaces;
2002-07-22 04:29:40 +00:00
//initially the entire screen is free
#ifdef XINERAMA
if (screen->isXineramaActive() &&
screen->getBlackbox()->doXineramaPlacement()) {
RectList availableAreas = screen->allAvailableAreas();
RectList::iterator it, end = availableAreas.end();
for (it = availableAreas.begin(); it != end; ++it)
spaces.push_back(*it);
} else
#endif // XINERAMA
spaces.push_back(screen->availableArea());
//Find Free Spaces
2002-05-30 04:35:22 +00:00
BlackboxWindowList::const_iterator wit = windowList.begin(),
end = windowList.end();
Rect tmp;
for (; wit != end; ++wit) {
const BlackboxWindow* const curr = *wit;
2002-05-30 04:35:22 +00:00
// watch for shaded windows and full-maxed windows
if (curr->isShaded()) {
if (screen->getPlaceIgnoreShaded()) continue;
} else if (curr->isMaximizedFull()) {
if (screen->getPlaceIgnoreMaximized()) continue;
}
2002-05-30 04:35:22 +00:00
tmp.setRect(curr->frameRect().x(), curr->frameRect().y(),
curr->frameRect().width() + screen->getBorderWidth(),
curr->frameRect().height() + screen->getBorderWidth());
spaces = calcSpace(tmp, spaces);
}
if (screen->getPlacementPolicy() == BScreen::RowSmartPlacement) {
if(screen->getRowPlacementDirection() == BScreen::LeftRight) {
if(screen->getColPlacementDirection() == BScreen::TopBottom)
2002-06-01 17:54:32 +00:00
std::sort(spaces.begin(), spaces.end(), rowLRTB);
else
2002-06-01 17:54:32 +00:00
std::sort(spaces.begin(), spaces.end(), rowLRBT);
} else {
if(screen->getColPlacementDirection() == BScreen::TopBottom)
2002-06-01 17:54:32 +00:00
std::sort(spaces.begin(), spaces.end(), rowRLTB);
else
2002-06-01 17:54:32 +00:00
std::sort(spaces.begin(), spaces.end(), rowRLBT);
}
} else {
if(screen->getColPlacementDirection() == BScreen::TopBottom) {
if(screen->getRowPlacementDirection() == BScreen::LeftRight)
2002-06-01 17:54:32 +00:00
std::sort(spaces.begin(), spaces.end(), colLRTB);
else
2002-06-01 17:54:32 +00:00
std::sort(spaces.begin(), spaces.end(), colRLTB);
} else {
if(screen->getRowPlacementDirection() == BScreen::LeftRight)
2002-06-01 17:54:32 +00:00
std::sort(spaces.begin(), spaces.end(), colLRBT);
else
2002-06-01 17:54:32 +00:00
std::sort(spaces.begin(), spaces.end(), colRLBT);
}
}
rectList::const_iterator sit = spaces.begin(), spaces_end = spaces.end();
for(; sit != spaces_end; ++sit) {
if (sit->width() >= win.width() && sit->height() >= win.height())
break;
}
if (sit == spaces_end)
return False;
//set new position based on the empty space found
const Rect& where = *sit;
win.setX(where.x());
win.setY(where.y());
// adjust the location() based on left/right and top/bottom placement
if (screen->getPlacementPolicy() == BScreen::RowSmartPlacement) {
if (screen->getRowPlacementDirection() == BScreen::RightLeft)
win.setX(where.right() - win.width());
if (screen->getColPlacementDirection() == BScreen::BottomTop)
win.setY(where.bottom() - win.height());
} else {
if (screen->getColPlacementDirection() == BScreen::BottomTop)
win.setY(win.y() + where.height() - win.height());
if (screen->getRowPlacementDirection() == BScreen::RightLeft)
win.setX(win.x() + where.width() - win.width());
}
return True;
}
2002-07-22 06:11:33 +00:00
bool Workspace::underMousePlacement(Rect &win) {
int x, y, rx, ry;
Window c, r;
unsigned int m;
XQueryPointer(screen->getBlackbox()->getXDisplay(), screen->getRootWindow(),
&r, &c, &rx, &ry, &x, &y, &m);
2002-07-22 04:29:40 +00:00
Rect area;
#ifdef XINERAMA
if (screen->isXineramaActive() &&
screen->getBlackbox()->doXineramaPlacement()) {
RectList availableAreas = screen->allAvailableAreas();
RectList::iterator it, end = availableAreas.end();
for (it = availableAreas.begin(); it != end; ++it)
if (it->contains(rx, ry)) break;
assert(it != end); // the mouse isn't inside an area?
area = *it;
} else
#endif // XINERAMA
area = screen->availableArea();
x = rx - win.width() / 2;
y = ry - win.height() / 2;
2002-07-22 04:29:40 +00:00
if (x < area.x())
x = area.x();
if (y < area.y())
y = area.y();
if (x + win.width() > area.x() + area.width())
x = area.x() + area.width() - win.width();
if (y + win.height() > area.y() + area.height())
y = area.y() + area.height() - win.height();
win.setX(x);
win.setY(y);
return True;
}
bool Workspace::cascadePlacement(Rect &win, const int offset) {
Rect area;
#ifdef XINERAMA
if (screen->isXineramaActive() &&
screen->getBlackbox()->doXineramaPlacement()) {
area = screen->allAvailableAreas()[cascade_region];
} else
#endif // XINERAMA
area = screen->availableArea();
2002-07-22 04:29:40 +00:00
if ((static_cast<signed>(cascade_x + win.width()) > area.right() + 1) ||
(static_cast<signed>(cascade_y + win.height()) > area.bottom() + 1)) {
cascade_x = cascade_y = 0;
#ifdef XINERAMA
if (screen->isXineramaActive() &&
screen->getBlackbox()->doXineramaPlacement()) {
// go to the next xinerama region, and use its area
if (++cascade_region >= screen->allAvailableAreas().size())
cascade_region = 0;
area = screen->allAvailableAreas()[cascade_region];
}
#endif // XINERAMA
}
if (cascade_x == 0) {
cascade_x = area.x() + offset;
cascade_y = area.y() + offset;
}
win.setPos(cascade_x, cascade_y);
cascade_x += offset;
cascade_y += offset;
return True;
}
void Workspace::placeWindow(BlackboxWindow *win) {
2002-07-22 04:29:40 +00:00
Rect new_win(0, 0, win->frameRect().width(), win->frameRect().height());
bool placed = False;
switch (screen->getPlacementPolicy()) {
case BScreen::RowSmartPlacement:
case BScreen::ColSmartPlacement:
2002-07-22 04:29:40 +00:00
placed = smartPlacement(new_win);
2002-04-28 00:11:19 +00:00
break;
case BScreen::UnderMousePlacement:
2002-07-16 05:00:09 +00:00
case BScreen::ClickMousePlacement:
2002-07-22 04:29:40 +00:00
placed = underMousePlacement(new_win);
default:
break; // handled below
2002-04-11 03:20:38 +00:00
} // switch
if (placed == False)
cascadePlacement(new_win, (win->getTitleHeight() +
screen->getBorderWidth() * 2));
if (new_win.right() > screen->availableArea().right())
new_win.setX(screen->availableArea().left());
if (new_win.bottom() > screen->availableArea().bottom())
new_win.setY(screen->availableArea().top());
2002-07-22 04:29:40 +00:00
win->configure(new_win.x(), new_win.y(), new_win.width(), new_win.height());
}