fluxbox/src/FbTk/XLayer.cc

392 lines
12 KiB
C++
Raw Normal View History

2003-01-16 12:41:27 +00:00
// XLayer.cc for FbTk - fluxbox toolkit
2006-02-16 06:53:05 +00:00
// Copyright (c) 2003 - 2006 Henrik Kinnunen (fluxgen at fluxbox dot org)
2003-01-16 12:41:27 +00:00
// and Simon Bowden (rathnor at users.sourceforge.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.
2004-11-19 11:37:27 +00:00
// $Id$
2003-01-16 12:41:27 +00:00
#include "XLayer.hh"
#include "XLayerItem.hh"
#include "App.hh"
#include <iostream>
using std::find;
2003-01-16 12:41:27 +00:00
using namespace FbTk;
#ifdef DEBUG
using std::cerr;
using std::endl;
#endif // DEBUG
2003-01-16 12:41:27 +00:00
XLayer::XLayer(MultLayers &manager, int layernum):
m_manager(manager), m_layernum(layernum) {
}
XLayer::~XLayer() {
2003-02-03 13:45:23 +00:00
2003-01-16 12:41:27 +00:00
}
void XLayer::restack() {
if (!m_manager.isUpdatable())
return;
2003-02-03 13:45:23 +00:00
int num_windows = countWindows();
// each LayerItem can contain several windows
iterator it = itemList().begin();
iterator it_end = itemList().end();
2003-02-03 13:45:23 +00:00
Window *winlist = new Window[num_windows];
size_t j=0;
2003-02-09 14:11:14 +00:00
// add all the windows from each item
for (; it != it_end; ++it) {
2003-02-09 14:11:14 +00:00
XLayerItem::Windows::const_iterator wit = (*it)->getWindows().begin();
XLayerItem::Windows::const_iterator wit_end = (*it)->getWindows().end();
for (; wit != wit_end; ++wit) {
if ((*wit)->window())
winlist[j++] = (*wit)->window();
2003-02-09 14:11:14 +00:00
}
2003-01-16 12:41:27 +00:00
}
XRestackWindows(FbTk::App::instance()->display(), winlist, j);
2003-01-16 12:41:27 +00:00
delete [] winlist;
2003-02-09 14:11:14 +00:00
2003-01-16 12:41:27 +00:00
}
int XLayer::countWindows() {
2003-02-03 13:45:23 +00:00
int num_windows = 0;
iterator it = itemList().begin();
iterator it_end = itemList().end();
for (; it != it_end; ++it) {
2003-02-09 14:11:14 +00:00
num_windows += (*it)->numWindows();
}
2003-02-03 13:45:23 +00:00
return num_windows;
}
2003-02-09 14:11:14 +00:00
// Stack all windows associated with 'item' below the 'above' item
2003-01-16 12:41:27 +00:00
void XLayer::stackBelowItem(XLayerItem *item, XLayerItem *above) {
if (!m_manager.isUpdatable())
return;
2003-02-03 13:45:23 +00:00
// if there are no windows provided for above us,
// then we must restack the entire layer
// we can't do XRaiseWindow because a restack then causes OverrideRedirect
// windows to get pushed to the bottom
2003-01-16 12:41:27 +00:00
if (!above) { // must need to go right to top
restack();
return;
2003-01-16 12:41:27 +00:00
}
Window *winlist;
size_t winnum = 1, size = item->numWindows()+1;
// We do have a window to stack below
// so we put it on top, and fill the rest of the array with the ones to go below it.
winlist = new Window[size];
// assume that above's window exists
winlist[0] = above->getWindows().back()->window();
2003-02-09 14:11:14 +00:00
// fill the rest of the array
XLayerItem::Windows::iterator it = item->getWindows().begin();
XLayerItem::Windows::iterator it_end = item->getWindows().end();
for (; it != it_end; ++it) {
if ((*it)->window())
winlist[winnum++] = (*it)->window();
}
2003-02-09 14:11:14 +00:00
// stack the windows
XRestackWindows(FbTk::App::instance()->display(), winlist, winnum);
2003-01-16 12:41:27 +00:00
delete [] winlist;
2003-01-16 12:41:27 +00:00
}
// We can't just use Restack here, because it won't do anything if they're
// already in the same relative order excluding other windows
2006-03-20 11:31:24 +00:00
void XLayer::alignItem(XLayerItem &item) {
if (itemList().front() == &item) {
stackBelowItem(&item, m_manager.getLowestItemAboveLayer(m_layernum));
return;
}
// Note: some other things effectively assume that the window list is
2006-03-20 11:31:24 +00:00
// sorted from highest to lowest
// get our item
iterator myit = find(itemList().begin(), itemList().end(), &item);
iterator it = myit;
2006-03-20 11:31:24 +00:00
// go to the one above it in our layer (top is front, so we decrement)
--it;
// keep going until we find one that is currently visible to the user
while (it != itemList().begin() && !(*it)->visible())
--it;
if (it == itemList().begin() && !(*it)->visible())
// reached front item, but it wasn't visible, therefore it was already raised
stackBelowItem(&item, m_manager.getLowestItemAboveLayer(m_layernum));
else
stackBelowItem(&item, *it);
2006-03-20 11:31:24 +00:00
}
2003-01-16 12:41:27 +00:00
XLayer::iterator XLayer::insert(XLayerItem &item, unsigned int pos) {
#ifdef DEBUG
2003-02-09 14:11:14 +00:00
// at this point we don't support insertions into a layer other than at the top
if (pos != 0)
2003-01-16 12:41:27 +00:00
cerr<<__FILE__<<"("<<__LINE__<<"): Insert using non-zero position not valid in XLayer"<<endl;
#endif // DEBUG
2003-01-16 12:41:27 +00:00
itemList().push_front(&item);
// restack below next window up
stackBelowItem(&item, m_manager.getLowestItemAboveLayer(m_layernum));
return itemList().begin();
}
2003-02-09 14:11:14 +00:00
void XLayer::remove(XLayerItem &item) {
2003-02-03 13:45:23 +00:00
iterator it = itemList().begin();
iterator it_end = itemList().end();
for (; it != it_end; ++it) {
2003-02-09 14:11:14 +00:00
if (*it == &item) {
2003-02-03 13:45:23 +00:00
itemList().erase(it);
2003-02-09 14:11:14 +00:00
break;
}
2003-02-03 13:45:23 +00:00
}
2003-01-16 12:41:27 +00:00
}
2006-12-22 05:44:42 +00:00
#ifdef NOT_USED
2003-01-16 12:41:27 +00:00
void XLayer::cycleUp() {
// need to find highest visible window, and move it to bottom
iterator it = itemList().begin();
iterator it_end = itemList().end();
while (it != it_end && !(*it)->visible())
2003-02-03 13:45:23 +00:00
++it;
2003-01-16 12:41:27 +00:00
// if there is something to do
2003-02-03 13:45:23 +00:00
if (it != it_end)
2003-01-16 12:41:27 +00:00
lower(**it);
2003-02-03 13:45:23 +00:00
2003-01-16 12:41:27 +00:00
}
void XLayer::cycleDown() {
2003-02-09 14:11:14 +00:00
// need to find lowest visible window, and move it to top
// so use a reverse iterator, and the same logic as cycleUp()
2003-01-16 12:41:27 +00:00
reverse_iterator it = itemList().rbegin();
reverse_iterator it_end = itemList().rend();
while (it != it_end && !(*it)->visible())
2003-02-03 13:45:23 +00:00
++it;
2003-01-16 12:41:27 +00:00
// if there is something to do
2003-02-03 13:45:23 +00:00
if (it != it_end)
2003-01-16 12:41:27 +00:00
raise(**it);
2003-01-16 12:41:27 +00:00
}
void XLayer::stepUp(XLayerItem &item) {
// need to find next visible window upwards, and put it above that
if (&item == itemList().front())
2003-02-03 13:45:23 +00:00
return; // nothing to do
2003-01-16 12:41:27 +00:00
// TODO: is there a better way of doing this?
2003-02-09 14:11:14 +00:00
// get our item
iterator myit = find(itemList().begin(), itemList().end(), &item);
2003-02-09 14:11:14 +00:00
iterator it = myit;
2003-02-09 14:11:14 +00:00
// go to the one above it in our layer (top is front, so we decrement)
--it;
// keep going until we find one that is currently visible to the user
while (it != itemList().begin() && !(*it)->visible())
2003-02-03 13:45:23 +00:00
--it;
2003-02-09 14:11:14 +00:00
if (it == itemList().begin() && !(*it)->visible()) {
2003-01-16 12:41:27 +00:00
// reached front item, but it wasn't visible, therefore it was already raised
} else {
// it is the next visible item down, we need to be above it.
2003-02-09 14:11:14 +00:00
// remove that item from the list and add it back to before it (the one we want to go above)
itemList().erase(myit);
itemList().insert(it, &item);
// if we've reached the top of the layer, we need to stack below the next one up
if (it == itemList().begin()) {
2003-01-16 12:41:27 +00:00
stackBelowItem(&item, m_manager.getLowestItemAboveLayer(m_layernum));
} else {
// otherwise go up one in this layer (i.e. above the one we want to go above)
2003-02-09 14:11:14 +00:00
--it;
// and stack below that.
2003-01-16 12:41:27 +00:00
stackBelowItem(&item, *it);
}
}
}
void XLayer::stepDown(XLayerItem &item) {
// need to find next visible window down, and put it below that
2003-02-09 14:11:14 +00:00
// if we're already the bottom of the layer
if (&item == itemList().back())
2003-02-03 13:45:23 +00:00
return; // nothing to do
2003-01-16 12:41:27 +00:00
2003-02-09 14:11:14 +00:00
// get our position
2006-12-22 05:44:42 +00:00
iterator it = find(itemList().begin(), itemList().end(), &item);
2003-02-09 14:11:14 +00:00
// go one below it (top is front, so we must increment)
2003-01-16 12:41:27 +00:00
it++;
iterator it_end = itemList().end();
2003-02-09 14:11:14 +00:00
// keep going down until we find a visible one
while (it != it_end && !(*it)->visible())
2003-02-09 14:11:14 +00:00
it++;
2003-01-16 12:41:27 +00:00
2003-02-09 14:11:14 +00:00
// if we didn't reach the end, then stack below the
// item that we found.
2003-02-03 13:45:23 +00:00
if (it != it_end)
2003-01-16 12:41:27 +00:00
stackBelowItem(&item, *it);
2003-02-09 14:11:14 +00:00
// if we did reach the end, then there are no visible windows, so we don't do anything
2003-01-16 12:41:27 +00:00
}
2006-12-22 05:44:42 +00:00
#endif // NOT_USED
2003-01-16 12:41:27 +00:00
void XLayer::raise(XLayerItem &item) {
// assume it is already in this layer
2003-02-03 13:45:23 +00:00
if (&item == itemList().front())
2003-01-16 12:41:27 +00:00
return; // nothing to do
iterator it = find(itemList().begin(), itemList().end(), &item);
2003-02-09 14:11:14 +00:00
if (it != itemList().end())
itemList().erase(it);
else {
2003-04-15 23:20:31 +00:00
#ifdef DEBUG
2003-02-09 14:11:14 +00:00
cerr<<__FILE__<<"("<<__LINE__<<"): WARNING: raise on item not in layer["<<m_layernum<<"]"<<endl;
2003-04-15 23:20:31 +00:00
#endif // DEBUG
2003-02-09 14:11:14 +00:00
return;
}
2003-01-16 12:41:27 +00:00
itemList().push_front(&item);
stackBelowItem(&item, m_manager.getLowestItemAboveLayer(m_layernum));
2003-01-16 12:41:27 +00:00
}
void XLayer::tempRaise(XLayerItem &item) {
// assume it is already in this layer
if (&item == itemList().front())
return; // nothing to do
iterator it = find(itemList().begin(), itemList().end(), &item);
2003-04-15 23:20:31 +00:00
if (it == itemList().end()) {
#ifdef DEBUG
cerr<<__FILE__<<"("<<__LINE__<<"): WARNING: raise on item not in layer["<<m_layernum<<"]"<<endl;
2003-04-15 23:20:31 +00:00
#endif // DEBUG
return;
}
// don't add it back to the top
stackBelowItem(&item, m_manager.getLowestItemAboveLayer(m_layernum));
}
2003-01-16 12:41:27 +00:00
void XLayer::lower(XLayerItem &item) {
// assume already in this layer
2003-02-09 14:11:14 +00:00
// is it already the lowest?
if (&item == itemList().back())
2003-01-16 12:41:27 +00:00
return; // nothing to do
iterator it = find(itemList().begin(), itemList().end(), &item);
2003-02-09 14:11:14 +00:00
if (it != itemList().end())
// remove this item
itemList().erase(it);
#ifdef DEBUG
else {
cerr<<__FILE__<<"("<<__LINE__<<"): WARNING: lower on item not in layer"<<endl;
return;
}
#endif // DEBUG
// add it to the bottom
2003-01-16 12:41:27 +00:00
itemList().push_back(&item);
2003-02-09 14:11:14 +00:00
// find the item we need to stack below
// start at the end
it = itemList().end();
// go up one so we have an object (which must exist, since at least this item is in the layer)
2003-01-16 12:41:27 +00:00
it--;
2003-02-09 14:11:14 +00:00
// go down another one
// must exist, otherwise our item must == itemList().back()
it--;
2003-02-09 14:11:14 +00:00
// and restack our window below that one.
stackBelowItem(&item, *it);
2003-02-09 14:11:14 +00:00
}
void XLayer::raiseLayer(XLayerItem &item) {
m_manager.raiseLayer(item);
}
void XLayer::lowerLayer(XLayerItem &item) {
m_manager.lowerLayer(item);
2003-01-16 12:41:27 +00:00
}
2003-02-09 14:11:14 +00:00
void XLayer::moveToLayer(XLayerItem &item, int layernum) {
m_manager.moveToLayer(item, layernum);
}
2003-01-16 12:41:27 +00:00
XLayerItem *XLayer::getLowestItem() {
if (itemList().empty())
2003-02-03 13:45:23 +00:00
return 0;
else
2003-02-03 13:45:23 +00:00
return itemList().back();
2003-01-16 12:41:27 +00:00
}
XLayerItem *XLayer::getItemBelow(XLayerItem &item) {
2003-02-09 14:11:14 +00:00
// get our iterator
iterator it = find(itemList().begin(), itemList().end(), &item);
2003-02-09 14:11:14 +00:00
// go one lower
it++;
2003-02-09 14:11:14 +00:00
// if one lower is the end, there is no item below, otherwise we've got it
2003-02-03 13:45:23 +00:00
if (it == itemList().end())
return 0;
2003-02-03 13:45:23 +00:00
else
return *it;
2003-02-09 14:11:14 +00:00
}
XLayerItem *XLayer::getItemAbove(XLayerItem &item) {
// get our iterator
iterator it = find(itemList().begin(), itemList().end(), &item);
2003-02-09 14:11:14 +00:00
// if this is the beginning (top-most item), do nothing, otherwise give the next one up
2003-02-09 14:11:14 +00:00
// the list (which must be there since we aren't the beginning)
if (it == itemList().begin())
return 0;
else
2003-02-09 14:11:14 +00:00
return *(--it);
}