//
// Viewport.cc for pekwm
// Copyright (C) 2003-2004 Claes Nasten <pekdon{@}pekdon{.}net>
//
// This program is licensed under the GNU GPL.
// See the LICENSE file for more information.
//
#include "../config.h"
#include "Viewport.hh"
#include "Atoms.hh"
#include "Config.hh"
#include "PScreen.hh"
#include "PWinObj.hh"
#include "PDecor.hh"
#include "ScreenResources.hh"
#include "Workspaces.hh"
#ifdef DEBUG
#include <iostream>
using std::cerr;
using std::endl;
#endif // DEBUG
using std::list;
//! @brief Viewport constructor
Viewport::Viewport(uint ws, const std::list<PWinObj*> &wo_list) :
_ws(ws), _wo_list(wo_list),
_x(0), _y(0), _cols(1), _rows(1)
{
_scr = PScreen::instance();
// init viewport
reload();
}
//! @brief Viewport destructor
Viewport::~Viewport(void)
{
}
//! @brief Moves the viewport to x y, optionally warping the pointer
//! @param x X position to move to
//! @param y Y position to move to
//! @param warp Wheter or not to warp the pointer, defaults to false
//! @param wx Mouse warp x position, defaults to 0
//! @param wy Mouse warp y position, defaults to 0
bool
Viewport::move(int x, int y, bool warp, int wx, int wy)
{
// validate position
if (x < 0)
x = 0;
else if (x > _x_max)
x = _x_max;
if (y < 0)
y = 0;
else if (y > _y_max)
y = _y_max;
// if the position has changed, let's move all frames
if ((_x != x) || (_y != y)) {
// calculate relative offset
int d_x = _x - x;
int d_y = _y - y;
_x = x;
_y = y;
// Update _NET_DESKTOP_VIEWPORT
hintSetViewport();
if (warp == true)
XWarpPointer(_scr->getDpy(), None, _scr->getRoot(), 0, 0, 0, 0, wx, wy);
list<PWinObj*>::const_iterator it = _wo_list.begin();
for (; it != _wo_list.end(); ++it) {
if (((*it)->getWorkspace() == _ws) && ((*it)->isSticky() != true)) {
(*it)->move((*it)->getX() + d_x, (*it)->getY() + d_y);
// FIXME: This won't send any configure requests to the client,
// should we overload the Frame::move or add a special case?
}
}
return true;
}
return false;
}
//! @brief Moves the viewport in direction dir, optionally warping the pointer
//! @param dir Direction to move
//! @param warp Wheter or not to warp the pointer, defaults to true
bool
Viewport::moveDirection(DirectionType dir, bool warp)
{
int n_x = _x, n_y = _y;
int warp_x, warp_y;
uint warp_d = Config::instance()->getScreenEdgeSize() * 2;
if (warp_d == 0)
warp_d = 2;
_scr->getMousePosition(warp_x, warp_y);
switch (dir) {
case DIRECTION_UP:
n_y -= _v_height;
if (n_y < 0) {
warp_y = _v_height + n_y;
} else {
warp_y = _v_height - warp_d;
}
break;
case DIRECTION_DOWN:
n_y += _v_height;
if (n_y > _y_max) {
warp_y = _v_height + _y - _y_max;
} else {
warp_y = warp_d;
}
break;
case DIRECTION_LEFT:
n_x -= _v_width;
if (n_x < 0) {
warp_x = _v_width + n_x;
} else {
warp_x = _v_width - warp_d;
}
break;
case DIRECTION_RIGHT:
n_x += _v_width;
if (n_x > _x_max) {
warp_x = _v_width + _x - _x_max;
} else {
warp_x = warp_d;
}
break;
default:
// Do nothing
break;
};
return (move(n_x, n_y, warp, warp_x, warp_y));
}
//! @brief Initiates moving of the viewport starting at x y
void
Viewport::moveDrag(int x, int y)
{
int status =
_scr->grabPointer(_scr->getRoot(), ButtonMotionMask|ButtonReleaseMask,
ScreenResources::instance()->getCursor(ScreenResources::CURSOR_MOVE));
if (status != true)
return;
// apply virtual desktop offset
x -= _x;
y -= _y;
bool exit = false;
XEvent ev;
while (exit != true) {
XMaskEvent(_scr->getDpy(), ButtonReleaseMask|ButtonMotionMask, &ev);
switch (ev.type) {
case MotionNotify:
move(ev.xmotion.x_root - x, ev.xmotion.y_root - y);
break;
case ButtonRelease:
exit = true;
break;
default:
// Do nothing
break;
}
}
_scr->ungrabPointer();
}
//! @brief Moves the viewport to the column and row making the wo visible
//! @param wo PWinObj to make visible
bool
Viewport::moveToWO(PWinObj *wo)
{
// make sure it is possible to move to the WO
makeWOInsideVirtual(wo);
return (move(getCol(wo) * _v_width, getRow(wo) * _v_height));
}
//! @brief Moves the viewport x_off and y_off pixels from current position
void
Viewport::scroll(int x_off, int y_off)
{
move(_x + x_off, _y + y_off);
}
//! @brief Moves the viewport to column col and row row
void
Viewport::gotoColRow(uint col, uint row)
{
move(col * _v_width, row * _v_height);
}
//! @brief Updates the viewport related hints
void
Viewport::hintsUpdate(void)
{
hintSetViewport();
hintSetGeometry();
hintSetWorkarea();
}
//! @brief Updates the _NET_DESKTOP_VIEWPORT hint
void
Viewport::hintSetViewport(void)
{
AtomUtil::setPosition(_scr->getRoot(),
EwmhAtoms::instance()->getAtom(NET_DESKTOP_VIEWPORT),
_x, _y);
}
//! @brief Updates the _NET_DESKTOP_GEOMETRY hint
void
Viewport::hintSetGeometry(void)
{
AtomUtil::setPosition(_scr->getRoot(),
EwmhAtoms::instance()->getAtom(NET_DESKTOP_GEOMETRY),
_width, _height);
}
//! @brief Updates the _NET_WORKAREA hint
void
Viewport::hintSetWorkarea(void)
{
int x, y;
uint width, height;
// FIXME: Expected behaviour?
x = _x + _scr->getStrut()->left;
y = _y + _scr->getStrut()->top;
width = _v_width - x - _scr->getStrut()->right;
height = _v_height - y - _scr->getStrut()->bottom;
CARD32 workarea[] = { x, y, width, height };
XChangeProperty(_scr->getDpy(), _scr->getRoot(),
EwmhAtoms::instance()->getAtom(NET_WORKAREA),
XA_CARDINAL, 32, PropModeReplace, (uchar *) workarea, 4);
}
#ifdef HAVE_XRANDR
//! @brief Refetches the root-window size and takes appropriate actions.
void
Viewport::updateGeometry(void)
{
reload();
}
#endif // HAVE_XRANDR
//! @brief Reloads confiuration
void
Viewport::reload(void)
{
_cols = Config::instance()->getViewportCols();
_rows = Config::instance()->getViewportRows();
// setup boundaries
_v_width = _scr->getWidth();
_v_height = _scr->getHeight();
_width = _cols * _v_width;
_height = _rows * _v_height;
_x_max = _width - _v_width;
_y_max = _height - _v_height;
makeAllInsideVirtual();
hintsUpdate(); // make sure workarea is up to date
}
//! @brief Makes sure all PWinObjs are inside the real screen
void
Viewport::makeAllInsideReal(void)
{
list<PWinObj*>::const_iterator it = _wo_list.begin();
for (; it != _wo_list.end(); ++it) {
if (((*it)->getType() == PWinObj::WO_FRAME) &&
((*it)->getWorkspace() == _ws)) {
makeWOInsideReal(*it);
}
}
}
//! @brief Make sure all PWinObjs are inside the virtual screen
void
Viewport::makeAllInsideVirtual(void)
{
list<PWinObj*>::const_iterator it = _wo_list.begin();
for (; it != _wo_list.end(); ++it) {
if (((*it)->getType() == PWinObj::WO_FRAME) &&
((*it)->getWorkspace() == _ws)) {
makeWOInsideVirtual(*it);
}
}
}
//! @brief Make sure wo is inside the real screen
//! @param wo PWinObj to make inside real screen
void
Viewport::makeWOInsideReal(PWinObj *wo)
{
// NOTE: passing false to move, we don't want to corrupt
// _PEKWM_FRAME_VPOS hint with invalid position information
// fix horizontal
if (wo->getRX() < 0) {
wo->move(0, wo->getY(), false);
} else if (wo->getX() > signed(_v_width)) {
wo->move(_v_width - wo->getWidth(), wo->getY(), false);
}
// fix vertical
if (wo->getBY() < 0) {
wo->move(wo->getX(), 0, false);
} else if (wo->getY() > signed(_v_height)) {
wo->move(wo->getX(), _v_height - wo->getHeight(), false);
}
}
//! @brief Make sure wo is inside the virtual screen
//! @param wo PWinObj to make inside virtual screen
void
Viewport::makeWOInsideVirtual(PWinObj *wo)
{
// fix horizontal
if ((wo->getRX() + _x) < 0) {
wo->move(0, wo->getY());
wo->moveVirtual(wo->getX() + _x, wo->getY() + _y);
} else if ((wo->getX() + _x) > signed(_width)) {
wo->move(_width - _x - wo->getWidth(), wo->getY());
wo->moveVirtual(wo->getX() + _x, wo->getY() + _y);
}
// fix vertical
if ((wo->getBY() + _y) < 0) {
wo->move(wo->getX(), 0);
wo->moveVirtual(wo->getX() + _x, wo->getY() + _y);
} else if ((wo->getY() + _y) > signed(_height)) {
wo->move(wo->getX(), _height - _y - wo->getHeight());
wo->moveVirtual(wo->getX() + _x, wo->getY() + _y);
}
}
syntax highlighted by Code2HTML, v. 0.9.1