aboutsummaryrefslogtreecommitdiff
path: root/src/FbTk/Layer.cc
diff options
context:
space:
mode:
Diffstat (limited to 'src/FbTk/Layer.cc')
-rw-r--r--src/FbTk/Layer.cc310
1 files changed, 310 insertions, 0 deletions
diff --git a/src/FbTk/Layer.cc b/src/FbTk/Layer.cc
new file mode 100644
index 0000000..d3c6615
--- /dev/null
+++ b/src/FbTk/Layer.cc
@@ -0,0 +1,310 @@
1// Layer.cc for FbTk - fluxbox toolkit
2// Copyright (c) 2003 - 2006 Henrik Kinnunen (fluxgen at fluxbox dot org)
3// and Simon Bowden (rathnor at users.sourceforge.net)
4//
5// Permission is hereby granted, free of charge, to any person obtaining a
6// copy of this software and associated documentation files (the "Software"),
7// to deal in the Software without restriction, including without limitation
8// the rights to use, copy, modify, merge, publish, distribute, sublicense,
9// and/or sell copies of the Software, and to permit persons to whom the
10// Software is furnished to do so, subject to the following conditions:
11//
12// The above copyright notice and this permission notice shall be included in
13// all copies or substantial portions of the Software.
14//
15// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
18// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
20// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
21// DEALINGS IN THE SOFTWARE.
22
23#include "Layer.hh"
24#include "LayerItem.hh"
25#include "App.hh"
26#include "FbWindow.hh"
27#include "MultLayers.hh"
28
29#include <iostream>
30#include <algorithm>
31#include <numeric>
32
33using namespace FbTk;
34
35#ifdef DEBUG
36using std::cerr;
37using std::endl;
38#endif // DEBUG
39
40namespace {
41
42int sum_windows(int nr, LayerItem* item) {
43 return nr + item->numWindows();
44}
45
46int count_windows(const FbTk::Layer::ItemList& items) {
47 return std::accumulate(items.begin(), items.end(), 0, sum_windows);
48}
49
50
51void extract_windows_to_stack(const LayerItem::Windows& windows, std::vector<Window>& stack) {
52 LayerItem::Windows::const_iterator i = windows.begin();
53 LayerItem::Windows::const_iterator end = windows.end();
54 for (; i != end; ++i) {
55 Window w = (*i)->window();
56 if (w)
57 stack.push_back(w);
58 }
59}
60
61void extract_windows_to_stack(const FbTk::Layer::ItemList& items, LayerItem* temp_raised, std::vector<Window>& stack) {
62
63 if (temp_raised) { // add windows that go on top
64 extract_windows_to_stack(temp_raised->getWindows(), stack);
65 }
66
67 FbTk::Layer::ItemList::const_iterator it = items.begin();
68 FbTk::Layer::ItemList::const_iterator it_end = items.end();
69 for (; it != it_end; ++it) { // add all the windows from each other item
70 if (*it == temp_raised) {
71 continue;
72 }
73 extract_windows_to_stack((*it)->getWindows(), stack);
74 }
75}
76
77void restack(const FbTk::Layer::ItemList& items, LayerItem* temp_raised) {
78
79 std::vector<Window> stack;
80 extract_windows_to_stack(items, temp_raised, stack);
81
82 if (!stack.empty())
83 XRestackWindows(FbTk::App::instance()->display(), &stack[0], stack.size());
84}
85
86} // end of anonymous namespace
87
88
89void Layer::restack(const std::vector<Layer*>& layers) {
90
91 std::vector<Window> stack;
92 std::vector<Layer*>::const_iterator l;
93 for (l = layers.begin(); l != layers.end(); ++l) {
94 extract_windows_to_stack((*l)->itemList(), 0, stack);
95 }
96
97 if (!stack.empty())
98 XRestackWindows(FbTk::App::instance()->display(), &stack[0], stack.size());
99}
100
101Layer::Layer(MultLayers &manager, int layernum):
102 m_manager(manager), m_layernum(layernum), m_needs_restack(false) {
103}
104
105Layer::~Layer() {
106
107}
108
109void Layer::restack() {
110 if (m_manager.isUpdatable()) {
111 ::restack(itemList(), 0);
112 m_needs_restack = false;
113 }
114}
115
116void Layer::restackAndTempRaise(LayerItem &item) {
117 ::restack(itemList(), &item);
118}
119
120int Layer::countWindows() {
121 return ::count_windows(itemList());
122}
123
124
125// Stack all windows associated with 'item' below the 'above' item
126void Layer::stackBelowItem(LayerItem &item, LayerItem *above) {
127 if (!m_manager.isUpdatable())
128 return;
129
130 // if there are no windows provided for above us,
131 // then we must restack the entire layer
132 // we can't do XRaiseWindow because a restack then causes OverrideRedirect
133 // windows to get pushed to the bottom
134 if (!above || m_needs_restack) { // must need to go right to top
135 restack();
136 return;
137 }
138
139 std::vector<Window> stack;
140
141 // We do have a window to stack below
142 // so we put it on top, and fill the rest of the array with the ones to go below it.
143 // assume that above's window exists
144 stack.push_back(above->getWindows().back()->window());
145
146 // fill the rest of the array
147 extract_windows_to_stack(item.getWindows(), stack);
148
149 XRestackWindows(FbTk::App::instance()->display(), &stack[0], stack.size());
150}
151
152// We can't just use Restack here, because it won't do anything if they're
153// already in the same relative order excluding other windows
154void Layer::alignItem(LayerItem &item) {
155 if (itemList().front() == &item) {
156 stackBelowItem(item, m_manager.getLowestItemAboveLayer(m_layernum));
157 return;
158 }
159
160 // Note: some other things effectively assume that the window list is
161 // sorted from highest to lowest
162 // get our item
163 iterator myit = std::find(itemList().begin(), itemList().end(), &item);
164 iterator it = myit;
165
166 // go to the one above it in our layer (top is front, so we decrement)
167 --it;
168
169 // keep going until we find one that is currently visible to the user
170 while (it != itemList().begin() && !(*it)->visible())
171 --it;
172
173 if (it == itemList().begin() && !(*it)->visible())
174 // reached front item, but it wasn't visible, therefore it was already raised
175 stackBelowItem(item, m_manager.getLowestItemAboveLayer(m_layernum));
176 else
177 stackBelowItem(item, *it);
178
179}
180
181Layer::iterator Layer::insert(LayerItem &item, unsigned int pos) {
182#ifdef DEBUG
183 // at this point we don't support insertions into a layer other than at the top
184 if (pos != 0)
185 cerr<<__FILE__<<"("<<__LINE__<<"): Insert using non-zero position not valid in Layer"<<endl;
186#endif // DEBUG
187
188 itemList().push_front(&item);
189 // restack below next window up
190 stackBelowItem(item, m_manager.getLowestItemAboveLayer(m_layernum));
191 return itemList().begin();
192}
193
194void Layer::remove(LayerItem &item) {
195 iterator it = itemList().begin();
196 iterator it_end = itemList().end();
197 for (; it != it_end; ++it) {
198 if (*it == &item) {
199 itemList().erase(it);
200 break;
201 }
202 }
203}
204
205void Layer::raise(LayerItem &item) {
206 // assume it is already in this layer
207
208 if (&item == itemList().front()) {
209 if (m_needs_restack)
210 restack();
211 return; // nothing to do
212 }
213
214
215 iterator it = std::find(itemList().begin(), itemList().end(), &item);
216 if (it != itemList().end())
217 itemList().erase(it);
218 else {
219#ifdef DEBUG
220 cerr<<__FILE__<<"("<<__LINE__<<"): WARNING: raise on item not in layer["<<m_layernum<<"]"<<endl;
221#endif // DEBUG
222 return;
223 }
224
225 itemList().push_front(&item);
226 stackBelowItem(item, m_manager.getLowestItemAboveLayer(m_layernum));
227
228}
229
230void Layer::tempRaise(LayerItem &item) {
231 // assume it is already in this layer
232
233 if (!m_needs_restack && &item == itemList().front())
234 return; // nothing to do
235
236 iterator it = std::find(itemList().begin(), itemList().end(), &item);
237 if (it == itemList().end()) {
238#ifdef DEBUG
239 cerr<<__FILE__<<"("<<__LINE__<<"): WARNING: raise on item not in layer["<<m_layernum<<"]"<<endl;
240#endif // DEBUG
241 return;
242 }
243
244 if (m_needs_restack)
245 restackAndTempRaise(item);
246 else
247 stackBelowItem(item, m_manager.getLowestItemAboveLayer(m_layernum));
248
249 m_needs_restack = true;
250}
251
252void Layer::lower(LayerItem &item) {
253 // assume already in this layer
254
255 // is it already the lowest?
256 if (&item == itemList().back()) {
257 if (m_needs_restack)
258 restack();
259 return; // nothing to do
260 }
261
262 iterator it = std::find(itemList().begin(), itemList().end(), &item);
263 if (it != itemList().end())
264 // remove this item
265 itemList().erase(it);
266#ifdef DEBUG
267 else {
268 cerr<<__FILE__<<"("<<__LINE__<<"): WARNING: lower on item not in layer"<<endl;
269 return;
270 }
271#endif // DEBUG
272
273 // add it to the bottom
274 itemList().push_back(&item);
275
276 // find the item we need to stack below
277 // start at the end
278 it = itemList().end();
279
280 // go up one so we have an object (which must exist, since at least this item is in the layer)
281 it--;
282
283 // go down another one
284 // must exist, otherwise our item must == itemList().back()
285 it--;
286
287 // and restack our window below that one.
288 stackBelowItem(item, *it);
289}
290
291void Layer::raiseLayer(LayerItem &item) {
292 m_manager.raiseLayer(item);
293}
294
295void Layer::lowerLayer(LayerItem &item) {
296 m_manager.lowerLayer(item);
297}
298
299void Layer::moveToLayer(LayerItem &item, int layernum) {
300 m_manager.moveToLayer(item, layernum);
301}
302
303
304LayerItem *Layer::getLowestItem() {
305 if (itemList().empty())
306 return 0;
307 else
308 return itemList().back();
309}
310