diff options
Diffstat (limited to 'src/FbTk/XLayer.cc')
-rw-r--r-- | src/FbTk/XLayer.cc | 371 |
1 files changed, 371 insertions, 0 deletions
diff --git a/src/FbTk/XLayer.cc b/src/FbTk/XLayer.cc new file mode 100644 index 0000000..8164444 --- /dev/null +++ b/src/FbTk/XLayer.cc | |||
@@ -0,0 +1,371 @@ | |||
1 | // XLayer.cc for FbTk - fluxbox toolkit | ||
2 | // Copyright (c) 2003 Henrik Kinnunen (fluxgen at users.sourceforge.net) | ||
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 | // $Id: XLayer.cc,v 1.9 2003/07/20 18:05:40 rathnor Exp $ | ||
24 | |||
25 | #include "XLayer.hh" | ||
26 | #include "XLayerItem.hh" | ||
27 | #include "App.hh" | ||
28 | |||
29 | #include <iostream> | ||
30 | using namespace std; | ||
31 | using namespace FbTk; | ||
32 | |||
33 | XLayer::XLayer(MultLayers &manager, int layernum): | ||
34 | m_manager(manager), m_layernum(layernum) { | ||
35 | } | ||
36 | |||
37 | XLayer::~XLayer() { | ||
38 | |||
39 | } | ||
40 | |||
41 | void XLayer::restack() { | ||
42 | if (!m_manager.isUpdatable()) | ||
43 | return; | ||
44 | |||
45 | int num_windows = countWindows(); | ||
46 | |||
47 | // each LayerItem can contain several windows | ||
48 | iterator it = itemList().begin(); | ||
49 | iterator it_end = itemList().end(); | ||
50 | it = itemList().begin(); | ||
51 | it_end = itemList().end(); | ||
52 | Window *winlist = new Window[num_windows]; | ||
53 | size_t j=0; | ||
54 | |||
55 | // add all the windows from each item | ||
56 | for (size_t i=0; it != it_end; ++it, i++) { | ||
57 | XLayerItem::Windows::const_iterator wit = (*it)->getWindows().begin(); | ||
58 | XLayerItem::Windows::const_iterator wit_end = (*it)->getWindows().end(); | ||
59 | for (; wit != wit_end; ++wit) { | ||
60 | if ((*wit)->window()) | ||
61 | winlist[j++] = (*wit)->window(); | ||
62 | } | ||
63 | } | ||
64 | |||
65 | XRestackWindows(FbTk::App::instance()->display(), winlist, j); | ||
66 | |||
67 | delete [] winlist; | ||
68 | |||
69 | } | ||
70 | |||
71 | int XLayer::countWindows() { | ||
72 | int num_windows = 0; | ||
73 | iterator it = itemList().begin(); | ||
74 | iterator it_end = itemList().end(); | ||
75 | for (size_t i=0; it != it_end; ++it, i++) { | ||
76 | num_windows += (*it)->numWindows(); | ||
77 | } | ||
78 | return num_windows; | ||
79 | } | ||
80 | |||
81 | |||
82 | // Stack all windows associated with 'item' below the 'above' item | ||
83 | void XLayer::stackBelowItem(XLayerItem *item, XLayerItem *above) { | ||
84 | if (!m_manager.isUpdatable()) | ||
85 | return; | ||
86 | |||
87 | Window *winlist; | ||
88 | size_t winnum, size, num = item->numWindows(); | ||
89 | |||
90 | // if there are no windows provided for above us, | ||
91 | // then we must have to go right to the top of the stack | ||
92 | if (!above) { // must need to go right to top | ||
93 | if (item->getWindows().front()->window()) | ||
94 | XRaiseWindow(FbTk::App::instance()->display(), item->getWindows().front()->window()); | ||
95 | |||
96 | // if this XLayerItem has more than one window, | ||
97 | // then we'll stack the rest in under the front one too | ||
98 | // our size needs to be the number of windows in the group, since there isn't one above. | ||
99 | if (num > 1) { | ||
100 | winnum = 0; | ||
101 | // stack relative to top one (just raised) | ||
102 | size = num; | ||
103 | winlist = new Window[size]; | ||
104 | } else { | ||
105 | // we've raised the window, nothing else to do | ||
106 | return; | ||
107 | } | ||
108 | } else { | ||
109 | // We do have a window to stack below | ||
110 | |||
111 | // so we put it on top, and fill the rest of the array with the ones to go below it. | ||
112 | winnum = 1; | ||
113 | size = num+1; | ||
114 | winlist = new Window[size]; | ||
115 | // assume that above's window exists | ||
116 | winlist[0] = above->getWindows().back()->window(); | ||
117 | } | ||
118 | |||
119 | // fill the rest of the array | ||
120 | XLayerItem::Windows::iterator it = item->getWindows().begin(); | ||
121 | XLayerItem::Windows::iterator it_end = item->getWindows().end(); | ||
122 | for (; it != it_end; ++it) { | ||
123 | if ((*it)->window()) | ||
124 | winlist[winnum++] = (*it)->window(); | ||
125 | } | ||
126 | |||
127 | // stack the windows | ||
128 | XRestackWindows(FbTk::App::instance()->display(), winlist, winnum); | ||
129 | |||
130 | delete [] winlist; | ||
131 | |||
132 | } | ||
133 | |||
134 | XLayer::iterator XLayer::insert(XLayerItem &item, unsigned int pos) { | ||
135 | #ifdef DEBUG | ||
136 | // at this point we don't support insertions into a layer other than at the top | ||
137 | if (pos != 0) | ||
138 | cerr<<__FILE__<<"("<<__LINE__<<"): Insert using non-zero position not valid in XLayer"<<endl; | ||
139 | #endif // DEBUG | ||
140 | |||
141 | itemList().push_front(&item); | ||
142 | // restack below next window up | ||
143 | stackBelowItem(&item, m_manager.getLowestItemAboveLayer(m_layernum)); | ||
144 | return itemList().begin(); | ||
145 | } | ||
146 | |||
147 | void XLayer::remove(XLayerItem &item) { | ||
148 | iterator it = itemList().begin(); | ||
149 | iterator it_end = itemList().end(); | ||
150 | for (; it != it_end; ++it) { | ||
151 | if (*it == &item) { | ||
152 | itemList().erase(it); | ||
153 | break; | ||
154 | } | ||
155 | } | ||
156 | } | ||
157 | |||
158 | void XLayer::cycleUp() { | ||
159 | // need to find highest visible window, and move it to bottom | ||
160 | iterator it = itemList().begin(); | ||
161 | iterator it_end = itemList().end(); | ||
162 | while (it != it_end && !(*it)->visible()) | ||
163 | ++it; | ||
164 | |||
165 | // if there is something to do | ||
166 | if (it != it_end) | ||
167 | lower(**it); | ||
168 | |||
169 | } | ||
170 | |||
171 | void XLayer::cycleDown() { | ||
172 | // need to find lowest visible window, and move it to top | ||
173 | // so use a reverse iterator, and the same logic as cycleUp() | ||
174 | reverse_iterator it = itemList().rbegin(); | ||
175 | reverse_iterator it_end = itemList().rend(); | ||
176 | while (it != it_end && !(*it)->visible()) | ||
177 | ++it; | ||
178 | |||
179 | // if there is something to do | ||
180 | if (it != it_end) | ||
181 | raise(**it); | ||
182 | |||
183 | } | ||
184 | |||
185 | void XLayer::stepUp(XLayerItem &item) { | ||
186 | // need to find next visible window upwards, and put it above that | ||
187 | |||
188 | if (&item == itemList().front()) | ||
189 | return; // nothing to do | ||
190 | |||
191 | // TODO: is there a better way of doing this? | ||
192 | |||
193 | // get our item | ||
194 | iterator myit = std::find(itemList().begin(), itemList().end(), &item); | ||
195 | iterator it = myit; | ||
196 | |||
197 | // go to the one above it in our layer (top is front, so we decrement) | ||
198 | --it; | ||
199 | |||
200 | // keep going until we find one that is currently visible to the user | ||
201 | while (it != itemList().begin() && !(*it)->visible()) | ||
202 | --it; | ||
203 | |||
204 | if (it == itemList().begin() && !(*it)->visible()) { | ||
205 | // reached front item, but it wasn't visible, therefore it was already raised | ||
206 | } else { | ||
207 | // it is the next visible item down, we need to be above it. | ||
208 | // remove that item from the list and add it back to before it (the one we want to go above) | ||
209 | |||
210 | itemList().erase(myit); | ||
211 | itemList().insert(it, &item); | ||
212 | |||
213 | // if we've reached the top of the layer, we need to stack below the next one up | ||
214 | if (it == itemList().begin()) { | ||
215 | stackBelowItem(&item, m_manager.getLowestItemAboveLayer(m_layernum)); | ||
216 | } else { | ||
217 | // otherwise go up one in this layer (i.e. above the one we want to go above) | ||
218 | --it; | ||
219 | // and stack below that. | ||
220 | stackBelowItem(&item, *it); | ||
221 | } | ||
222 | } | ||
223 | } | ||
224 | |||
225 | void XLayer::stepDown(XLayerItem &item) { | ||
226 | // need to find next visible window down, and put it below that | ||
227 | |||
228 | // if we're already the bottom of the layer | ||
229 | if (&item == itemList().back()) | ||
230 | return; // nothing to do | ||
231 | |||
232 | // get our position | ||
233 | iterator myit = std::find(itemList().begin(), itemList().end(), &item); | ||
234 | iterator it = myit; | ||
235 | |||
236 | // go one below it (top is front, so we must increment) | ||
237 | it++; | ||
238 | iterator it_end = itemList().end(); | ||
239 | |||
240 | // keep going down until we find a visible one | ||
241 | while (it != it_end && !(*it)->visible()) | ||
242 | it++; | ||
243 | |||
244 | // if we didn't reach the end, then stack below the | ||
245 | // item that we found. | ||
246 | if (it != it_end) | ||
247 | stackBelowItem(&item, *it); | ||
248 | // if we did reach the end, then there are no visible windows, so we don't do anything | ||
249 | } | ||
250 | |||
251 | void XLayer::raise(XLayerItem &item) { | ||
252 | // assume it is already in this layer | ||
253 | |||
254 | if (&item == itemList().front()) | ||
255 | return; // nothing to do | ||
256 | |||
257 | iterator it = std::find(itemList().begin(), itemList().end(), &item); | ||
258 | if (it != itemList().end()) | ||
259 | itemList().erase(it); | ||
260 | else { | ||
261 | #ifdef DEBUG | ||
262 | cerr<<__FILE__<<"("<<__LINE__<<"): WARNING: raise on item not in layer["<<m_layernum<<"]"<<endl; | ||
263 | #endif // DEBUG | ||
264 | return; | ||
265 | } | ||
266 | |||
267 | itemList().push_front(&item); | ||
268 | stackBelowItem(&item, m_manager.getLowestItemAboveLayer(m_layernum)); | ||
269 | |||
270 | } | ||
271 | |||
272 | void XLayer::tempRaise(XLayerItem &item) { | ||
273 | // assume it is already in this layer | ||
274 | |||
275 | if (&item == itemList().front()) | ||
276 | return; // nothing to do | ||
277 | |||
278 | iterator it = std::find(itemList().begin(), itemList().end(), &item); | ||
279 | if (it == itemList().end()) { | ||
280 | #ifdef DEBUG | ||
281 | cerr<<__FILE__<<"("<<__LINE__<<"): WARNING: raise on item not in layer["<<m_layernum<<"]"<<endl; | ||
282 | #endif // DEBUG | ||
283 | return; | ||
284 | } | ||
285 | |||
286 | // don't add it back to the top | ||
287 | stackBelowItem(&item, m_manager.getLowestItemAboveLayer(m_layernum)); | ||
288 | |||
289 | } | ||
290 | |||
291 | void XLayer::lower(XLayerItem &item) { | ||
292 | // assume already in this layer | ||
293 | |||
294 | // is it already the lowest? | ||
295 | if (&item == itemList().back()) | ||
296 | return; // nothing to do | ||
297 | |||
298 | iterator it = std::find(itemList().begin(), itemList().end(), &item); | ||
299 | if (it != itemList().end()) | ||
300 | // remove this item | ||
301 | itemList().erase(it); | ||
302 | #ifdef DEBUG | ||
303 | else { | ||
304 | cerr<<__FILE__<<"("<<__LINE__<<"): WARNING: lower on item not in layer"<<endl; | ||
305 | return; | ||
306 | } | ||
307 | #endif // DEBUG | ||
308 | |||
309 | // add it to the bottom | ||
310 | itemList().push_back(&item); | ||
311 | |||
312 | // find the item we need to stack below | ||
313 | // start at the end | ||
314 | it = itemList().end(); | ||
315 | |||
316 | // go up one so we have an object (which must exist, since at least this item is in the layer) | ||
317 | it--; | ||
318 | |||
319 | // go down another one | ||
320 | // must exist, otherwise our item must == itemList().back() | ||
321 | it--; | ||
322 | |||
323 | // and restack our window below that one. | ||
324 | stackBelowItem(&item, *it); | ||
325 | } | ||
326 | |||
327 | void XLayer::raiseLayer(XLayerItem &item) { | ||
328 | m_manager.raiseLayer(item); | ||
329 | } | ||
330 | |||
331 | void XLayer::lowerLayer(XLayerItem &item) { | ||
332 | m_manager.lowerLayer(item); | ||
333 | } | ||
334 | |||
335 | void XLayer::moveToLayer(XLayerItem &item, int layernum) { | ||
336 | m_manager.moveToLayer(item, layernum); | ||
337 | } | ||
338 | |||
339 | |||
340 | XLayerItem *XLayer::getLowestItem() { | ||
341 | if (itemList().empty()) | ||
342 | return 0; | ||
343 | else | ||
344 | return itemList().back(); | ||
345 | } | ||
346 | |||
347 | XLayerItem *XLayer::getItemBelow(XLayerItem &item) { | ||
348 | // get our iterator | ||
349 | iterator it = std::find(itemList().begin(), itemList().end(), &item); | ||
350 | |||
351 | // go one lower | ||
352 | it++; | ||
353 | |||
354 | // if one lower is the end, there is no item below, otherwise we've got it | ||
355 | if (it == itemList().end()) | ||
356 | return 0; | ||
357 | else | ||
358 | return *it; | ||
359 | } | ||
360 | |||
361 | XLayerItem *XLayer::getItemAbove(XLayerItem &item) { | ||
362 | // get our iterator | ||
363 | iterator it = std::find(itemList().begin(), itemList().end(), &item); | ||
364 | |||
365 | // if this is the beginning (top-most item), do nothing, otherwise give the next one up | ||
366 | // the list (which must be there since we aren't the beginning) | ||
367 | if (it == itemList().begin()) | ||
368 | return 0; | ||
369 | else | ||
370 | return *(--it); | ||
371 | } | ||