moved placement strategies to different PlacementStrategy classes

This commit is contained in:
fluxgen 2006-02-19 11:11:22 +00:00
parent d099e7673a
commit b772fd969f
15 changed files with 905 additions and 366 deletions

75
src/CascadePlacement.cc Normal file
View file

@ -0,0 +1,75 @@
// CascadePlacement.cc
// Copyright (c) 2006 Fluxbox Team (fluxgen at fluxbox dot org)
//
// 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.
// $Id$
#include "CascadePlacement.hh"
#include "Window.hh"
#include "Screen.hh"
CascadePlacement::CascadePlacement(const BScreen &screen) {
// +1 ?
m_cascade_x = new int[screen.numHeads() + 1];
m_cascade_y = new int[screen.numHeads() + 1];
for (int i=0; i < screen.numHeads() + 1; i++) {
m_cascade_x[i] = 32 + screen.getHeadX(i);
m_cascade_y[i] = 32 + screen.getHeadY(i);
}
}
CascadePlacement::~CascadePlacement() {
delete [] m_cascade_x;
delete [] m_cascade_y;
}
bool CascadePlacement::placeWindow(const std::vector<FluxboxWindow *> &windowlist,
const FluxboxWindow &win,
int &place_x, int &place_y) {
int head = (signed) win.screen().getCurrHead();
int head_left = (signed) win.screen().maxLeft(head);
int head_right = (signed) win.screen().maxRight(head);
int head_top = (signed) win.screen().maxTop(head);
int head_bot = (signed) win.screen().maxBottom(head);
if ((m_cascade_x[head] > ((head_left + head_right) / 2)) ||
(m_cascade_y[head] > ((head_top + head_bot) / 2))) {
m_cascade_x[head] = head_left + 32;
m_cascade_y[head] = head_top + 32;
}
place_x = m_cascade_x[head];
place_y = m_cascade_y[head];
// just one borderwidth, so they can share a borderwidth (looks better)
int titlebar_height =
win.titlebarHeight() + win.fbWindow().borderWidth();
if (titlebar_height < 4) // make sure it is not insignificant
titlebar_height = 32;
m_cascade_x[head] += titlebar_height;
m_cascade_y[head] += titlebar_height;
return true;
}

45
src/CascadePlacement.hh Normal file
View file

@ -0,0 +1,45 @@
// CascadePlacement.hh
// Copyright (c) 2006 Fluxbox Team (fluxgen at fluxbox dot org)
//
// 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.
// $Id$
#ifndef CASCADEPLACEMENT_HH
#define CASCADEPLACEMENT_HH
#include "PlacementStrategy.hh"
#include "FbTk/NotCopyable.hh"
class BScreen;
class CascadePlacement: public PlacementStrategy,
private FbTk::NotCopyable {
public:
explicit CascadePlacement(const BScreen &screen);
~CascadePlacement();
bool placeWindow(const std::vector<FluxboxWindow *> &windowlist,
const FluxboxWindow &window,
int &place_x, int &place_y);
private:
int *m_cascade_x; ///< need a cascade for each head (Xinerama)
int *m_cascade_y; ///< need a cascade for each head (Xinerama)
};
#endif // CASCADEPLACEMENT_HH

136
src/ColSmartPlacement.cc Normal file
View file

@ -0,0 +1,136 @@
// ColSmartPlacement.cc
// Copyright (c) 2006 Fluxbox Team (fluxgen at fluxbox dot org)
//
// 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.
// $Id$
#include "ColSmartPlacement.hh"
#include "Screen.hh"
#include "ScreenPlacement.hh"
#include "Window.hh"
bool ColSmartPlacement::placeWindow(const std::vector<FluxboxWindow *> &windowlist,
const FluxboxWindow &win,
int &place_x, int &place_y) {
// xinerama head constraints
int head = (signed) win.screen().getCurrHead();
int head_left = (signed) win.screen().maxLeft(head);
int head_right = (signed) win.screen().maxRight(head);
int head_top = (signed) win.screen().maxTop(head);
int head_bot = (signed) win.screen().maxBottom(head);
bool placed = false;
int next_x, next_y;
const ScreenPlacement &screen_placement =
dynamic_cast<const ScreenPlacement &>(win.screen().placementStrategy());
bool top_bot = screen_placement.colDirection() == ScreenPlacement::TOPBOTTOM;
bool left_right = screen_placement.rowDirection() == ScreenPlacement::LEFTRIGHT;
int test_x;
int win_w = win.width() + win.fbWindow().borderWidth()*2;
int win_h = win.height() + win.fbWindow().borderWidth()*2;
if (left_right)
test_x = head_left;
else
test_x = head_right - win_w;
int change_y = 1;
if (screen_placement.colDirection() == ScreenPlacement::BOTTOMTOP)
change_y = -1;
while (!placed &&
(left_right ? test_x + win_w <= head_right
: test_x >= head_left)) {
if (left_right)
next_x = head_right; // it will get shrunk
else
next_x = head_left-1;
int test_y;
if (top_bot)
test_y = head_top;
else
test_y = head_bot - win_h;
while (!placed &&
(top_bot ? test_y + win_h <= head_bot
: test_y >= head_top)) {
placed = true;
next_y = test_y + change_y;
std::vector<FluxboxWindow *>::const_iterator it =
windowlist.begin();
std::vector<FluxboxWindow *>::const_iterator it_end =
windowlist.end();
for (; it != it_end && placed; ++it) {
int curr_x = (*it)->x();
int curr_y = (*it)->y();
int curr_w = (*it)->width() + (*it)->fbWindow().borderWidth()*2;
int curr_h = (*it)->height() + (*it)->fbWindow().borderWidth()*2;
if (curr_x < test_x + win_w &&
curr_x + curr_w > test_x &&
curr_y < test_y + win_h &&
curr_y + curr_h > test_y) {
// this window is in the way
placed = false;
// we find the next y that we can go to (a window will be in the way
// all the way to its bottom)
if (top_bot) {
if (curr_y + curr_h > next_y)
next_y = curr_y + curr_h;
} else {
if (curr_y - win_h < next_y)
next_y = curr_y - win_h;
}
// but we can only go to the nearest x, since that is where the
// next time current windows in the way will change
if (left_right) {
if (curr_x + curr_w < next_x)
next_x = curr_x + curr_w;
} else {
if (curr_x - win_w > next_x)
next_x = curr_x - win_w;
}
}
}
if (placed) {
place_x = test_x;
place_y = test_y;
}
test_y = next_y;
} // end while
test_x = next_x;
} // end while
return placed;
}

36
src/ColSmartPlacement.hh Normal file
View file

@ -0,0 +1,36 @@
// ColSmartPlacement.hh
// Copyright (c) 2006 Fluxbox Team (fluxgen at fluxbox dot org)
//
// 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.
// $Id$
#ifndef COLSMARTPLACEMENT_HH
#define COLSMARTPLACEMENT_HH
#include "PlacementStrategy.hh"
class ColSmartPlacement: public PlacementStrategy {
public:
bool placeWindow(const std::vector<FluxboxWindow *> &windowlist,
const FluxboxWindow &win,
int &place_x, int &place_y);
};
#endif // COLSMARTPLACEMENT_HH

View file

@ -128,6 +128,11 @@ fluxbox_SOURCES = AtomHandler.hh ArrowButton.hh ArrowButton.cc \
Resources.cc \
WindowCmd.hh WindowCmd.cc \
FocusControl.hh FocusControl.cc \
CascadePlacement.hh CascadePlacement.cc \
ColSmartPlacement.hh ColSmartPlacement.cc \
RowSmartPlacement.hh RowSmartPlacement.cc \
ScreenPlacement.hh ScreenPlacement.cc \
UnderMousePlacement.hh UnderMousePlacement.cc \
${newwmspec_SOURCE} ${gnome_SOURCE} \
${REMEMBER_SOURCE} ${TOOLBAR_SOURCE}

155
src/RowSmartPlacement.cc Normal file
View file

@ -0,0 +1,155 @@
// RowSmartPlacement.cc
// Copyright (c) 2006 Fluxbox Team (fluxgen at fluxbox dot org)
//
// 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.
// $Id$
#include "RowSmartPlacement.hh"
#include "Window.hh"
#include "Screen.hh"
#include "ScreenPlacement.hh"
bool RowSmartPlacement::placeWindow(const std::vector<FluxboxWindow *> &windowlist,
const FluxboxWindow &win,
int &place_x, int &place_y) {
bool placed = false;
int next_x, next_y;
// view (screen + head) constraints
int head = (signed) win.screen().getCurrHead();
int head_left = (signed) win.screen().maxLeft(head);
int head_right = (signed) win.screen().maxRight(head);
int head_top = (signed) win.screen().maxTop(head);
int head_bot = (signed) win.screen().maxBottom(head);
const ScreenPlacement &screen_placement =
dynamic_cast<const ScreenPlacement &>(win.screen().placementStrategy());
bool top_bot =
screen_placement.colDirection() == ScreenPlacement::TOPBOTTOM;
bool left_right =
screen_placement.rowDirection() == ScreenPlacement::LEFTRIGHT;
int change_x = 1, change_y = 1;
if (screen_placement.colDirection() == ScreenPlacement::BOTTOMTOP)
change_y = -1;
if (screen_placement.rowDirection() == ScreenPlacement::RIGHTLEFT)
change_x = -1;
int win_h = win.height() + win.fbWindow().borderWidth()*2;
int win_w = win.width() + win.fbWindow().borderWidth()*2;
int test_y;
if (top_bot)
test_y = head_top;
else
test_y = head_bot - win_h;
while (!placed &&
(top_bot ? test_y + win_h <= head_bot
: test_y >= head_top)) {
int test_x;
if (left_right)
test_x = head_left;
else
test_x = head_right - win_w;
// The trick here is that we set it to the furthest away one,
// then the code brings it back down to the safest one that
// we can go to (i.e. the next untested area)
if (top_bot)
next_y = head_bot; // will be shrunk
else
next_y = head_top-1;
while (!placed &&
(left_right ? test_x + win_w <= head_right
: test_x >= head_left)) {
placed = true;
next_x = test_x + change_x;
std::vector<FluxboxWindow *>::const_iterator win_it =
windowlist.begin();
std::vector<FluxboxWindow *>::const_iterator win_it_end =
windowlist.end();
for (; win_it != win_it_end && placed; ++win_it) {
FluxboxWindow &window = **win_it;
int curr_x = window.x();
int curr_y = window.y();
int curr_w = window.width() + window.fbWindow().borderWidth()*2;
int curr_h = window.height() + window.fbWindow().borderWidth()*2;
if (curr_x < test_x + win_w &&
curr_x + curr_w > test_x &&
curr_y < test_y + win_h &&
curr_y + curr_h > test_y) {
// this window is in the way
placed = false;
// we find the next x that we can go to (a window will be in the way
// all the way to its far side)
if (left_right) {
if (curr_x + curr_w > next_x)
next_x = curr_x + curr_w;
} else {
if (curr_x - win_w < next_x)
next_x = curr_x - win_w;
}
// but we can only go to the nearest y, since that is where the
// next time current windows in the way will change
if (top_bot) {
if (curr_y + curr_h < next_y)
next_y = curr_y + curr_h;
} else {
if (curr_y - win_h > next_y)
next_y = curr_y - win_h;
}
}
}
if (placed) {
place_x = test_x;
place_y = test_y;
break;
}
test_x = next_x;
} // end while
test_y = next_y;
} // end while
return placed;
}

37
src/RowSmartPlacement.hh Normal file
View file

@ -0,0 +1,37 @@
// RowSmartPlacement.hh
// Copyright (c) 2006 Fluxbox Team (fluxgen at fluxbox dot org)
//
// 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.
// $Id$
#ifndef ROWSMARTPLACEMENT_HH
#define ROWSMARTPLACEMENT_HH
#include "PlacementStrategy.hh"
class RowSmartPlacement: public PlacementStrategy {
public:
bool placeWindow(const std::vector<FluxboxWindow *> &windowlist,
const FluxboxWindow &win,
int &place_x, int &place_y);
};
#endif // ROWSMARTPLACEMENT_HH

View file

@ -33,6 +33,7 @@
#include "Netizen.hh"
#include "FocusControl.hh"
#include "ScreenPlacement.hh"
// themes
#include "FbWinFrameTheme.hh"
@ -184,9 +185,7 @@ BScreen::ScreenResource::ScreenResource(FbTk::ResourceManager &rm,
menu_delay(rm, 0, scrname + ".menuDelay", altscrname+".MenuDelay"),
menu_delay_close(rm, 0, scrname + ".menuDelayClose", altscrname+".MenuDelayClose"),
menu_mode(rm, FbTk::MenuTheme::DELAY_OPEN, scrname+".menuMode", altscrname+".MenuMode"),
placement_policy(rm, ROWSMARTPLACEMENT, scrname+".windowPlacement", altscrname+".WindowPlacement"),
row_direction(rm, LEFTRIGHT, scrname+".rowPlacementDirection", altscrname+".RowPlacementDirection"),
col_direction(rm, TOPBOTTOM, scrname+".colPlacementDirection", altscrname+".ColPlacementDirection"),
gc_line_width(rm, 1, scrname+".overlay.lineWidth", altscrname+".Overlay.LineWidth"),
gc_line_style(rm,
FbTk::GContext::LINESOLID,
@ -238,6 +237,7 @@ BScreen::BScreen(FbTk::ResourceManager &rm,
m_name(screenname),
m_altname(altscreenname),
m_focus_control(new FocusControl(*this)),
m_placement_strategy(new ScreenPlacement(*this)),
m_xinerama_headinfo(0),
m_shutdown(false) {
@ -446,7 +446,10 @@ BScreen::~BScreen() {
// TODO fluxgen: check if this is the right place
delete [] m_head_areas;
delete m_focus_control;
delete m_placement_strategy;
}
void BScreen::initWindows() {

View file

@ -30,6 +30,7 @@
#include "FbRootWindow.hh"
#include "MenuTheme.hh"
#include "PlacementStrategy.hh"
#include "FbTk/Resource.hh"
#include "FbTk/Subject.hh"
@ -63,6 +64,7 @@ class Strut;
class Slit;
class HeadArea;
class FocusControl;
class PlacementStrategy;
namespace FbTk {
class Menu;
@ -90,15 +92,6 @@ public:
QUADRANTRESIZE,
DEFAULTRESIZE = BOTTOMRESIZE };
enum PlacementPolicy {
ROWSMARTPLACEMENT,
COLSMARTPLACEMENT,
CASCADEPLACEMENT,
UNDERMOUSEPLACEMENT
};
enum RowDirection { LEFTRIGHT, RIGHTLEFT};
enum ColumnDirection { TOPBOTTOM, BOTTOMTOP};
typedef std::vector<FluxboxWindow *> Icons;
@ -218,10 +211,7 @@ public:
/// hide all windowmenus except the given one (if given)
void hideWindowMenus(const FluxboxWindow* except= 0);
inline PlacementPolicy getPlacementPolicy() const { return *resource.placement_policy; }
inline int getEdgeSnapThreshold() const { return *resource.edge_snap_threshold; }
inline RowDirection getRowPlacementDirection() const { return *resource.row_direction; }
inline ColumnDirection getColPlacementDirection() const { return *resource.col_direction; }
void setRootColormapInstalled(bool r) { root_colormap_installed = r; }
void saveRootCommand(std::string rootcmd) { *resource.rootcommand = rootcmd; }
@ -249,7 +239,9 @@ public:
const std::string &altName() const { return m_altname; }
bool isShuttingdown() const { return m_shutdown; }
PlacementStrategy &placementStrategy() { return *m_placement_strategy; }
const PlacementStrategy &placementStrategy() const { return *m_placement_strategy; }
int addWorkspace();
int removeLastWorkspace();
// scroll workspaces
@ -442,9 +434,7 @@ private:
FbTk::Resource<int> workspaces, edge_snap_threshold, focused_alpha,
unfocused_alpha, menu_alpha, menu_delay, menu_delay_close;
FbTk::Resource<FbTk::MenuTheme::MenuMode> menu_mode;
FbTk::Resource<PlacementPolicy> placement_policy;
FbTk::Resource<RowDirection> row_direction;
FbTk::Resource<ColumnDirection> col_direction;
FbTk::Resource<int> gc_line_width;
FbTk::Resource<FbTk::GContext::LineStyle> gc_line_style;
FbTk::Resource<FbTk::GContext::JoinStyle> gc_join_style;
@ -458,6 +448,7 @@ private:
const std::string m_name, m_altname;
FocusControl *m_focus_control;
PlacementStrategy *m_placement_strategy;
// This is a map of windows to clients for clients that had a left
// window set, but that window wasn't present at the time

207
src/ScreenPlacement.cc Normal file
View file

@ -0,0 +1,207 @@
// ScreenPlacement.cc
// Copyright (c) 2006 Fluxbox Team (fluxgen at fluxbox dot org)
//
// 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.
// $Id$
#include "ScreenPlacement.hh"
#include "RowSmartPlacement.hh"
#include "UnderMousePlacement.hh"
#include "ColSmartPlacement.hh"
#include "CascadePlacement.hh"
#include "Screen.hh"
#include "Window.hh"
#include <iostream>
#include <exception>
using std::cerr;
using std::endl;
ScreenPlacement::ScreenPlacement(BScreen &screen):
m_row_direction(screen.resourceManager(), LEFTRIGHT,
screen.name()+".rowPlacementDirection",
screen.altName()+".RowPlacementDirection"),
m_col_direction(screen.resourceManager(), TOPBOTTOM,
screen.name()+".colPlacementDirection",
screen.altName()+".ColPlacementDirection"),
m_placement_policy(screen.resourceManager(), ROWSMARTPLACEMENT,
screen.name()+".windowPlacement",
screen.altName()+".WindowPlacement"),
m_old_policy(*m_placement_policy),
m_strategy(new RowSmartPlacement())
{
}
bool ScreenPlacement::placeWindow(const std::vector<FluxboxWindow *> &windowlist,
const FluxboxWindow &win,
int &place_x, int &place_y) {
// check the resource placement and see if has changed
// and if so update the strategy
if (m_old_policy != *m_placement_policy) {
m_old_policy = *m_placement_policy;
switch (*m_placement_policy) {
case ROWSMARTPLACEMENT:
m_strategy.reset(new RowSmartPlacement());
break;
case COLSMARTPLACEMENT:
m_strategy.reset(new ColSmartPlacement());
break;
case CASCADEPLACEMENT:
m_strategy.reset(new CascadePlacement(win.screen()));
break;
case UNDERMOUSEPLACEMENT:
m_strategy.reset(new UnderMousePlacement());
break;
}
}
// view (screen + head) constraints
int head = (signed) win.screen().getCurrHead();
int head_left = (signed) win.screen().maxLeft(head);
int head_right = (signed) win.screen().maxRight(head);
int head_top = (signed) win.screen().maxTop(head);
int head_bot = (signed) win.screen().maxBottom(head);
// start placement, top left corner
place_x = head_left;
place_y = head_top;
bool placed = false;
try {
placed = m_strategy->placeWindow(windowlist,
win,
place_x, place_y);
} catch (std::bad_cast cast) {
// This should not happen.
// If for some reason we change the PlacementStrategy in Screen
// from ScreenPlacement to something else then we might get
// bad_cast from some placement strategies.
cerr<<"Failed to place window: "<<cast.what()<<endl;
}
if (!placed) {
// Create fallback strategy, when we need it the first time
// This strategy must succeed!
if (m_fallback_strategy.get() == 0)
m_fallback_strategy.reset(new CascadePlacement(win.screen()));
m_fallback_strategy->placeWindow(windowlist,
win,
place_x, place_y);
}
int win_w = win.width() + win.fbWindow().borderWidth()*2,
win_h = win.height() + win.fbWindow().borderWidth()*2;
// make sure the window is inside our screen(head) area
if (place_x + win_w > head_right)
place_x = (head_right - win_w) / 2;
if (place_y + win_h > head_bot)
place_y = (head_bot - win_h) / 2;
return true;
}
////////////////////// Placement Resources
template <>
void FbTk::Resource<ScreenPlacement::PlacementPolicy>::setFromString(const char *str) {
if (strcasecmp("RowSmartPlacement", str) == 0)
*(*this) = ScreenPlacement::ROWSMARTPLACEMENT;
else if (strcasecmp("ColSmartPlacement", str) == 0)
*(*this) = ScreenPlacement::COLSMARTPLACEMENT;
else if (strcasecmp("UnderMousePlacement", str) == 0)
*(*this) = ScreenPlacement::UNDERMOUSEPLACEMENT;
else if (strcasecmp("CascadePlacement", str) == 0)
*(*this) = ScreenPlacement::CASCADEPLACEMENT;
else
setDefaultValue();
}
template <>
std::string FbTk::Resource<ScreenPlacement::PlacementPolicy>::getString() const {
switch (*(*this)) {
case ScreenPlacement::ROWSMARTPLACEMENT:
return "RowSmartPlacement";
case ScreenPlacement::COLSMARTPLACEMENT:
return "ColSmartPlacement";
case ScreenPlacement::UNDERMOUSEPLACEMENT:
return "UnderMousePlacement";
case ScreenPlacement::CASCADEPLACEMENT:
return "CascadePlacement";
}
return "RowSmartPlacement";
}
template <>
void FbTk::Resource<ScreenPlacement::RowDirection>::setFromString(const char *str) {
if (strcasecmp("LeftToRight", str) == 0)
*(*this) = ScreenPlacement::LEFTRIGHT;
else if (strcasecmp("RightToLeft", str) == 0)
*(*this) = ScreenPlacement::RIGHTLEFT;
else
setDefaultValue();
}
template <>
std::string FbTk::Resource<ScreenPlacement::RowDirection>::getString() const {
switch (*(*this)) {
case ScreenPlacement::LEFTRIGHT:
return "LeftToRight";
case ScreenPlacement::RIGHTLEFT:
return "RightToLeft";
}
return "LeftToRight";
}
template <>
void FbTk::Resource<ScreenPlacement::ColumnDirection>::setFromString(const char *str) {
if (strcasecmp("TopToBottom", str) == 0)
*(*this) = ScreenPlacement::TOPBOTTOM;
else if (strcasecmp("BottomToTop", str) == 0)
*(*this) = ScreenPlacement::BOTTOMTOP;
else
setDefaultValue();
}
template <>
std::string FbTk::Resource<ScreenPlacement::ColumnDirection>::getString() const {
switch (*(*this)) {
case ScreenPlacement::TOPBOTTOM:
return "TopToBottom";
case ScreenPlacement::BOTTOMTOP:
return "BottomToTop";
}
return "TopToBottom";
}

77
src/ScreenPlacement.hh Normal file
View file

@ -0,0 +1,77 @@
// ScreenPlacement.hh
// Copyright (c) 2006 Fluxbox Team (fluxgen at fluxbox dot org)
//
// 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.
// $Id$
#ifndef SCREENPLACEMENT_HH
#define SCREENPLACEMENT_HH
#include "PlacementStrategy.hh"
#include "FbTk/Resource.hh"
class BScreen;
/**
* Main class for strategy handling
* This is a bridge between screen and
* the real placement strategy (rowcol, undermouse etc)
* The placeWindow function in this class is guaranteed to succeed.
* It holds a pointer to the real placement strategy which is
* called upon placeWindow, it also holds the placement resources
*/
class ScreenPlacement: public PlacementStrategy {
public:
enum PlacementPolicy {
ROWSMARTPLACEMENT,
COLSMARTPLACEMENT,
CASCADEPLACEMENT,
UNDERMOUSEPLACEMENT
};
enum RowDirection {
LEFTRIGHT, ///< from left to right
RIGHTLEFT ///< from right to left
};
enum ColumnDirection {
TOPBOTTOM, ///< from top to bottom
BOTTOMTOP ///< from bottom to top
};
explicit ScreenPlacement(BScreen &screen);
/// placeWindow is guaranteed to succeed, ignore return value
/// @return true
bool placeWindow(const std::vector<FluxboxWindow *> &windowlist,
const FluxboxWindow &window,
int &place_x, int &place_y);
RowDirection rowDirection() const { return *m_row_direction; }
ColumnDirection colDirection() const { return *m_col_direction; }
private:
FbTk::Resource<RowDirection> m_row_direction; ///< row direction resource
FbTk::Resource<ColumnDirection> m_col_direction; ///< column direction resource
FbTk::Resource<PlacementPolicy> m_placement_policy; ///< placement policy resource
PlacementPolicy m_old_policy; ///< holds old policy, used to determine if resources has changed
std::auto_ptr<PlacementStrategy> m_strategy; ///< main strategy
std::auto_ptr<PlacementStrategy> m_fallback_strategy; ///< a fallback strategy if the main strategy fails
};
#endif // SCREENPLACEMENT_HH

View file

@ -29,82 +29,6 @@
#include <string>
using namespace std;
template <>
void FbTk::Resource<BScreen::PlacementPolicy>::setFromString(const char *str) {
if (strcasecmp("RowSmartPlacement", str) == 0)
*(*this) = BScreen::ROWSMARTPLACEMENT;
else if (strcasecmp("ColSmartPlacement", str) == 0)
*(*this) = BScreen::COLSMARTPLACEMENT;
else if (strcasecmp("UnderMousePlacement", str) == 0)
*(*this) = BScreen::UNDERMOUSEPLACEMENT;
else if (strcasecmp("CascadePlacement", str) == 0)
*(*this) = BScreen::CASCADEPLACEMENT;
else
setDefaultValue();
}
template <>
string FbTk::Resource<BScreen::PlacementPolicy>::getString() const {
switch (*(*this)) {
case BScreen::ROWSMARTPLACEMENT:
return "RowSmartPlacement";
case BScreen::COLSMARTPLACEMENT:
return "ColSmartPlacement";
case BScreen::UNDERMOUSEPLACEMENT:
return "UnderMousePlacement";
case BScreen::CASCADEPLACEMENT:
return "CascadePlacement";
}
return "RowSmartPlacement";
}
template <>
void FbTk::Resource<BScreen::RowDirection>::setFromString(const char *str) {
if (strcasecmp("LeftToRight", str) == 0)
*(*this) = BScreen::LEFTRIGHT;
else if (strcasecmp("RightToLeft", str) == 0)
*(*this) = BScreen::RIGHTLEFT;
else
setDefaultValue();
}
template <>
string FbTk::Resource<BScreen::RowDirection>::getString() const {
switch (*(*this)) {
case BScreen::LEFTRIGHT:
return "LeftToRight";
case BScreen::RIGHTLEFT:
return "RightToLeft";
}
return "LeftToRight";
}
template <>
void FbTk::Resource<BScreen::ColumnDirection>::setFromString(const char *str) {
if (strcasecmp("TopToBottom", str) == 0)
*(*this) = BScreen::TOPBOTTOM;
else if (strcasecmp("BottomToTop", str) == 0)
*(*this) = BScreen::BOTTOMTOP;
else
setDefaultValue();
}
template <>
string FbTk::Resource<BScreen::ColumnDirection>::getString() const {
switch (*(*this)) {
case BScreen::TOPBOTTOM:
return "TopToBottom";
case BScreen::BOTTOMTOP:
return "BottomToTop";
}
return "TopToBottom";
}
template <>
string FbTk::Resource<FbTk::MenuTheme::MenuMode>::getString() const {

View file

@ -0,0 +1,75 @@
// UnderMousePlacement.cc
// Copyright (c) 2006 Fluxbox Team (fluxgen at fluxbox dot org)
//
// 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.
// $Id$
#include "UnderMousePlacement.hh"
#include "FbTk/App.hh"
#include "Screen.hh"
#include "Window.hh"
bool UnderMousePlacement::placeWindow(const std::vector<FluxboxWindow *> &list,
const FluxboxWindow &win,
int &place_x, int &place_y) {
int root_x, root_y, ignore_i;
unsigned int ignore_ui;
Window ignore_w;
XQueryPointer(FbTk::App::instance()->display(),
win.screen().rootWindow().window(), &ignore_w,
&ignore_w, &root_x, &root_y,
&ignore_i, &ignore_i, &ignore_ui);
// 2*border = border on each side of the screen
int win_w = win.width() + win.fbWindow().borderWidth()*2,
win_h = win.height() + win.fbWindow().borderWidth()*2;
int test_x = root_x - (win_w / 2);
int test_y = root_y - (win_h / 2);
// keep the window inside the screen
int head = (signed) win.screen().getCurrHead();
int head_left = (signed) win.screen().maxLeft(head);
int head_right = (signed) win.screen().maxRight(head);
int head_top = (signed) win.screen().maxTop(head);
int head_bot = (signed) win.screen().maxBottom(head);
if (test_x < head_left)
test_x = head_left;
if (test_x + win_w > head_right)
test_x = head_right - win_w;
if (test_y < head_top)
test_y = head_top;
if (test_y + win_h > head_bot)
test_y = head_bot - win_h;
place_x = test_x;
place_y = test_y;
return true;
}

View file

@ -0,0 +1,36 @@
// UnderMousePlacement.hh
// Copyright (c) 2006 Fluxbox Team (fluxgen at fluxbox dot org)
//
// 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.
// $Id$
#ifndef UNDERMOUSEPLACEMENT_HH
#define UNDERMOUSEPLACEMENT_HH
#include "PlacementStrategy.hh"
class UnderMousePlacement: public PlacementStrategy {
public:
bool placeWindow(const std::vector<FluxboxWindow *> &windowlist,
const FluxboxWindow &win,
int &place_x, int &place_y);
};
#endif // UNDERMOUSEPLACEMENT_HH

View file

@ -33,6 +33,7 @@
#include "FbWinFrame.hh"
#include "WindowCmd.hh"
#include "FocusControl.hh"
#include "PlacementStrategy.hh"
#include "FbTk/I18n.hh"
#include "FbTk/MenuItem.hh"
@ -140,21 +141,13 @@ Workspace::Workspace(BScreen &scrn, FbTk::MultLayers &layermanager,
m_name(name),
m_id(id) {
m_cascade_x = new int[scrn.numHeads() + 1];
m_cascade_y = new int[scrn.numHeads() + 1];
for (int i=0; i < scrn.numHeads()+1; i++) {
m_cascade_x[i] = 32 + scrn.getHeadX(i);
m_cascade_y[i] = 32 + scrn.getHeadY(i);
}
menu().setInternalMenu();
setName(name);
}
Workspace::~Workspace() {
delete [] m_cascade_x;
delete [] m_cascade_y;
}
void Workspace::setLastFocusedWindow(FluxboxWindow *win) {
@ -427,268 +420,12 @@ void Workspace::updateClientmenu() {
}
void Workspace::placeWindow(FluxboxWindow &win) {
bool placed = false;
// restrictions
int head = (signed) screen().getCurrHead();
int head_left = (signed) screen().maxLeft(head);
int head_right = (signed) screen().maxRight(head);
int head_top = (signed) screen().maxTop(head);
int head_bot = (signed) screen().maxBottom(head);
int place_x = head_left, place_y = head_top, change_x = 1, change_y = 1;
if (screen().getColPlacementDirection() == BScreen::BOTTOMTOP)
change_y = -1;
if (screen().getRowPlacementDirection() == BScreen::RIGHTLEFT)
change_x = -1;
int win_w = win.width() + win.fbWindow().borderWidth()*2,
win_h = win.height() + win.fbWindow().borderWidth()*2;
int test_x, test_y, curr_x, curr_y, curr_w, curr_h;
switch (screen().getPlacementPolicy()) {
case BScreen::UNDERMOUSEPLACEMENT: {
int root_x, root_y, ignore_i;
unsigned int ignore_ui;
Window ignore_w;
XQueryPointer(FbTk::App::instance()->display(),
screen().rootWindow().window(), &ignore_w,
&ignore_w, &root_x, &root_y,
&ignore_i, &ignore_i, &ignore_ui);
test_x = root_x - (win_w / 2);
test_y = root_y - (win_h / 2);
// keep the window inside the screen
if (test_x < head_left)
test_x = head_left;
if (test_x + win_w > head_right)
test_x = head_right - win_w;
if (test_y < head_top)
test_y = head_top;
if (test_y + win_h > head_bot)
test_y = head_bot - win_h;
place_x = test_x;
place_y = test_y;
placed = true;
break;
} // end case UNDERMOUSEPLACEMENT
case BScreen::ROWSMARTPLACEMENT: {
int next_x, next_y;
bool top_bot = screen().getColPlacementDirection() == BScreen::TOPBOTTOM;
bool left_right = screen().getRowPlacementDirection() == BScreen::LEFTRIGHT;
if (top_bot)
test_y = head_top;
else
test_y = head_bot - win_h;
while (!placed &&
(top_bot ? test_y + win_h <= head_bot
: test_y >= head_top)) {
if (left_right)
test_x = head_left;
else
test_x = head_right - win_w;
// The trick here is that we set it to the furthest away one,
// then the code brings it back down to the safest one that
// we can go to (i.e. the next untested area)
if (top_bot)
next_y = head_bot; // will be shrunk
else
next_y = head_top-1;
while (!placed &&
(left_right ? test_x + win_w <= head_right
: test_x >= head_left)) {
placed = true;
next_x = test_x + change_x;
Windows::iterator win_it = m_windowlist.begin();
const Windows::iterator win_it_end = m_windowlist.end();
for (; win_it != win_it_end && placed; ++win_it) {
FluxboxWindow &window = **win_it;
curr_x = window.x();
curr_y = window.y();
curr_w = window.width() + window.fbWindow().borderWidth()*2;
curr_h = window.height() + window.fbWindow().borderWidth()*2;
if (curr_x < test_x + win_w &&
curr_x + curr_w > test_x &&
curr_y < test_y + win_h &&
curr_y + curr_h > test_y) {
// this window is in the way
placed = false;
// we find the next x that we can go to (a window will be in the way
// all the way to its far side)
if (left_right) {
if (curr_x + curr_w > next_x)
next_x = curr_x + curr_w;
} else {
if (curr_x - win_w < next_x)
next_x = curr_x - win_w;
}
// but we can only go to the nearest y, since that is where the
// next time current windows in the way will change
if (top_bot) {
if (curr_y + curr_h < next_y)
next_y = curr_y + curr_h;
} else {
if (curr_y - win_h > next_y)
next_y = curr_y - win_h;
}
}
}
if (placed) {
place_x = test_x;
place_y = test_y;
break;
}
test_x = next_x;
} // end while
test_y = next_y;
} // end while
break;
} // end case ROWSMARTPLACEMENT
case BScreen::COLSMARTPLACEMENT: {
int next_x, next_y;
bool top_bot = screen().getColPlacementDirection() == BScreen::TOPBOTTOM;
bool left_right = screen().getRowPlacementDirection() == BScreen::LEFTRIGHT;
if (left_right)
test_x = head_left;
else
test_x = head_right - win_w;
while (!placed &&
(left_right ? test_x + win_w <= head_right
: test_x >= head_left)) {
if (left_right)
next_x = head_right; // it will get shrunk
else
next_x = head_left-1;
if (top_bot)
test_y = head_top;
else
test_y = head_bot - win_h;
while (!placed &&
(top_bot ? test_y + win_h <= head_bot
: test_y >= head_top)) {
placed = True;
next_y = test_y + change_y;
Windows::iterator it = m_windowlist.begin();
Windows::iterator it_end = m_windowlist.end();
for (; it != it_end && placed; ++it) {
curr_x = (*it)->x();
curr_y = (*it)->y();
curr_w = (*it)->width() + (*it)->fbWindow().borderWidth()*2;
curr_h = (*it)->height() + (*it)->fbWindow().borderWidth()*2;
if (curr_x < test_x + win_w &&
curr_x + curr_w > test_x &&
curr_y < test_y + win_h &&
curr_y + curr_h > test_y) {
// this window is in the way
placed = False;
// we find the next y that we can go to (a window will be in the way
// all the way to its bottom)
if (top_bot) {
if (curr_y + curr_h > next_y)
next_y = curr_y + curr_h;
} else {
if (curr_y - win_h < next_y)
next_y = curr_y - win_h;
}
// but we can only go to the nearest x, since that is where the
// next time current windows in the way will change
if (left_right) {
if (curr_x + curr_w < next_x)
next_x = curr_x + curr_w;
} else {
if (curr_x - win_w > next_x)
next_x = curr_x - win_w;
}
}
}
if (placed) {
place_x = test_x;
place_y = test_y;
}
test_y = next_y;
} // end while
test_x = next_x;
} // end while
break;
} // end COLSMARTPLACEMENT
}
// cascade placement or smart placement failed
if (! placed) {
if ((m_cascade_x[head] > ((head_left + head_right) / 2)) ||
(m_cascade_y[head] > ((head_top + head_bot) / 2))) {
m_cascade_x[head] = head_left + 32;
m_cascade_y[head] = head_top + 32;
}
place_x = m_cascade_x[head];
place_y = m_cascade_y[head];
// just one borderwidth, so they can share a borderwidth (looks better)
int titlebar_height = win.titlebarHeight() + win.fbWindow().borderWidth();
if (titlebar_height < 4) // make sure it is not insignificant
titlebar_height = 32;
m_cascade_x[head] += titlebar_height;
m_cascade_y[head] += titlebar_height;
}
if (place_x + win_w > head_right)
place_x = (head_right - win_w) / 2;
if (place_y + win_h > head_bot)
place_y = (head_bot - win_h) / 2;
int place_x, place_y;
// we ignore the return value,
// the screen placement strategy is guaranteed to succeed.
screen().placementStrategy().placeWindow(m_windowlist,
win,
place_x, place_y);
win.moveResize(place_x, place_y, win.width(), win.height());
}