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