268 lines
9 KiB
C++
268 lines
9 KiB
C++
// 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.
|
|
|
|
#include "ScreenPlacement.hh"
|
|
|
|
#include "RowSmartPlacement.hh"
|
|
#include "MinOverlapPlacement.hh"
|
|
#include "UnderMousePlacement.hh"
|
|
#include "ColSmartPlacement.hh"
|
|
#include "CascadePlacement.hh"
|
|
|
|
#include "Screen.hh"
|
|
#include "Window.hh"
|
|
|
|
#include "FbTk/Menu.hh"
|
|
|
|
#include <iostream>
|
|
#include <exception>
|
|
#ifdef HAVE_CSTRING
|
|
#include <cstring>
|
|
#else
|
|
#include <string.h>
|
|
#endif
|
|
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(), ROWMINOVERLAPPLACEMENT,
|
|
screen.name()+".windowPlacement",
|
|
screen.altName()+".WindowPlacement"),
|
|
m_old_policy(ROWSMARTPLACEMENT),
|
|
m_strategy(0),
|
|
m_screen(screen)
|
|
{
|
|
}
|
|
|
|
bool ScreenPlacement::placeWindow(const FluxboxWindow &win, int head,
|
|
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_strategy.get()) {
|
|
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 ROWMINOVERLAPPLACEMENT:
|
|
case COLMINOVERLAPPLACEMENT:
|
|
m_strategy.reset(new MinOverlapPlacement(*m_placement_policy));
|
|
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_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(win, head, 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(win, head, place_x, place_y);
|
|
}
|
|
|
|
|
|
|
|
int win_w = win.normalWidth() + win.fbWindow().borderWidth()*2 + win.widthOffset(),
|
|
win_h = win.normalHeight() + win.fbWindow().borderWidth()*2 + win.heightOffset();
|
|
|
|
// make sure the window is inside our screen(head) area
|
|
if (place_x + win_w - win.xOffset() > head_right)
|
|
place_x = head_left + (head_right - head_left - win_w) / 2 +
|
|
win.xOffset();
|
|
if (place_y + win_h - win.yOffset() > head_bot)
|
|
place_y = head_top + (head_bot - head_top - win_h) / 2 + win.yOffset();
|
|
|
|
return true;
|
|
}
|
|
|
|
bool ScreenPlacement::placeAndShowMenu(FbTk::Menu& menu, int x, int y, bool respect_struts) {
|
|
|
|
int head = m_screen.getHead(x, y);
|
|
|
|
menu.setScreen(m_screen.getHeadX(head),
|
|
m_screen.getHeadY(head),
|
|
m_screen.getHeadWidth(head),
|
|
m_screen.getHeadHeight(head));
|
|
|
|
menu.updateMenu(); // recalculate the size
|
|
|
|
x = x - (menu.width() / 2);
|
|
if (menu.isTitleVisible())
|
|
y = y - (menu.titleWindow().height() / 2);
|
|
|
|
// adjust (x, y) to fit on the screen
|
|
if (!respect_struts) {
|
|
|
|
int bw = 2 * menu.fbwindow().borderWidth();
|
|
std::pair<int, int> pos = m_screen.clampToHead(head, x, y, menu.width() + bw, menu.height() + bw);
|
|
x = pos.first;
|
|
y = pos.second;
|
|
|
|
} else { // do not cover toolbar if no title
|
|
|
|
int top = static_cast<signed>(m_screen.maxTop(head));
|
|
int bottom = static_cast<signed>(m_screen.maxBottom(head));
|
|
int left = static_cast<signed>(m_screen.maxLeft(head));
|
|
int right = static_cast<signed>(m_screen.maxRight(head));
|
|
|
|
if (y < top)
|
|
y = top;
|
|
else if (y + static_cast<signed>(menu.height()) >= bottom)
|
|
y = bottom - menu.height() - 1 - menu.fbwindow().borderWidth();
|
|
|
|
if (x < left)
|
|
x = left;
|
|
else if (x + static_cast<signed>(menu.width()) >= right)
|
|
x = right - static_cast<int>(menu.width()) - 1;
|
|
}
|
|
|
|
menu.move(x, y);
|
|
menu.show();
|
|
menu.grabInputFocus();
|
|
}
|
|
|
|
////////////////////// Placement Resources
|
|
namespace FbTk {
|
|
|
|
template <>
|
|
std::string FbTk::Resource<ScreenPlacement::PlacementPolicy>::getString() const {
|
|
switch (*(*this)) {
|
|
case ScreenPlacement::ROWSMARTPLACEMENT:
|
|
return "RowSmartPlacement";
|
|
case ScreenPlacement::COLSMARTPLACEMENT:
|
|
return "ColSmartPlacement";
|
|
case ScreenPlacement::ROWMINOVERLAPPLACEMENT:
|
|
return "RowMinOverlapPlacement";
|
|
case ScreenPlacement::COLMINOVERLAPPLACEMENT:
|
|
return "ColMinOverlapPlacement";
|
|
case ScreenPlacement::UNDERMOUSEPLACEMENT:
|
|
return "UnderMousePlacement";
|
|
case ScreenPlacement::CASCADEPLACEMENT:
|
|
return "CascadePlacement";
|
|
}
|
|
|
|
return "RowSmartPlacement";
|
|
}
|
|
|
|
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("RowMinOverlapPlacement", str) == 0)
|
|
*(*this) = ScreenPlacement::ROWMINOVERLAPPLACEMENT;
|
|
else if (strcasecmp("ColMinOverlapPlacement", str) == 0)
|
|
*(*this) = ScreenPlacement::COLMINOVERLAPPLACEMENT;
|
|
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::RowDirection>::getString() const {
|
|
switch (*(*this)) {
|
|
case ScreenPlacement::LEFTRIGHT:
|
|
return "LeftToRight";
|
|
case ScreenPlacement::RIGHTLEFT:
|
|
return "RightToLeft";
|
|
}
|
|
|
|
return "LeftToRight";
|
|
}
|
|
|
|
|
|
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::ColumnDirection>::getString() const {
|
|
switch (*(*this)) {
|
|
case ScreenPlacement::TOPBOTTOM:
|
|
return "TopToBottom";
|
|
case ScreenPlacement::BOTTOMTOP:
|
|
return "BottomToTop";
|
|
}
|
|
|
|
return "TopToBottom";
|
|
}
|
|
|
|
|
|
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();
|
|
}
|
|
|
|
} // end namespace FbTk
|