1 // -*- mode: C++; indent-tabs-mode: nil; c-basic-offset: 2; -*-
2 // StackingList.cc for Blackbox - an X11 Window manager
3 // Copyright (c) 2001 - 2005 Sean 'Shaleh' Perry <shaleh@debian.org>
4 // Copyright (c) 1997 - 2000, 2002 - 2005
5 //         Bradley T Hughes <bhughes at trolltech.com>
6 //
7 // Permission is hereby granted, free of charge, to any person obtaining a
8 // copy of this software and associated documentation files (the "Software"),
9 // to deal in the Software without restriction, including without limitation
10 // the rights to use, copy, modify, merge, publish, distribute, sublicense,
11 // and/or sell copies of the Software, and to permit persons to whom the
12 // Software is furnished to do so, subject to the following conditions:
13 //
14 // The above copyright notice and this permission notice shall be included in
15 // all copies or substantial portions of the Software.
16 //
17 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18 // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19 // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
20 // THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21 // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
22 // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
23 // DEALINGS IN THE SOFTWARE.
24 
25 #include "StackingList.hh"
26 #include "Window.hh"
27 
28 #include <Unicode.hh>
29 
30 #include <cassert>
31 #include <cstdio>
32 
33 
34 static StackEntity * const zero = 0;
35 
36 
StackingList(void)37 StackingList::StackingList(void) {
38   desktop = stack.insert(stack.begin(), zero);
39   below = stack.insert(desktop, zero);
40   normal = stack.insert(below, zero);
41   above = stack.insert(normal, zero);
42   fullscreen = stack.insert(above, zero);
43 }
44 
45 
insert(StackEntity * entity)46 StackingList::iterator StackingList::insert(StackEntity *entity) {
47   assert(entity);
48 
49   iterator& it = layer(entity->layer());
50   it = stack.insert(it, entity);
51   return it;
52 }
53 
54 
append(StackEntity * entity)55 StackingList::iterator StackingList::append(StackEntity *entity) {
56   assert(entity);
57 
58   iterator& it = layer(entity->layer());
59   if (!*it) { // empty layer
60     it = stack.insert(it, entity);
61     return it;
62   }
63 
64   // find the end of the layer (the zero pointer)
65   iterator tmp = std::find(it, stack.end(), zero);
66   assert(tmp != stack.end());
67   tmp = stack.insert(tmp, entity);
68   return tmp;
69 }
70 
71 
remove(StackEntity * entity)72 StackingList::iterator StackingList::remove(StackEntity *entity) {
73   assert(entity);
74 
75   iterator& pos = layer(entity->layer());
76   iterator it = std::find(pos, stack.end(), entity);
77   assert(it != stack.end());
78   if (it == pos) ++pos;
79   it = stack.erase(it);
80   assert(stack.size() >= 5);
81   return it;
82 }
83 
84 
layer(Layer which)85 StackingList::iterator& StackingList::layer(Layer which) {
86   switch (which) { // teehee
87   case LayerNormal:
88     return normal;
89   case LayerFullScreen:
90     return fullscreen;
91   case LayerAbove:
92     return above;
93   case LayerBelow:
94     return below;
95   case LayerDesktop:
96     return desktop;
97   }
98 
99   assert(0);
100   return normal;
101 }
102 
103 
changeLayer(StackEntity * entity,Layer new_layer)104 void StackingList::changeLayer(StackEntity *entity, Layer new_layer) {
105   assert(entity);
106 
107   (void) remove(entity);
108   entity->setLayer(new_layer);
109   (void) insert(entity);
110 }
111 
112 
raise(StackEntity * entity)113 StackingList::iterator StackingList::raise(StackEntity *entity) {
114   assert(entity);
115 
116   // find the top of the layer and 'entity'
117   iterator& pos = layer(entity->layer());
118   const iterator send = stack.end();
119   iterator it = std::find(pos, send, entity);
120   assert(it != send);
121 
122   if (it == pos) {
123     // entity is already at the top
124     return pos;
125   }
126 
127   // raise the entity
128   (void) stack.erase(it);
129   return pos = stack.insert(pos, entity);
130 }
131 
132 
lower(StackEntity * entity)133 StackingList::iterator StackingList::lower(StackEntity *entity) {
134   assert(entity);
135 
136   // find the top of the layer and 'entity'
137   iterator& pos = layer(entity->layer());
138   const iterator send = stack.end();
139   iterator it = std::find(pos, send, entity);
140   assert(it != send);
141 
142   iterator next = it;
143   ++next;
144   assert(next != send);
145   if (!(*next)) {
146     // entity is already at the bottom
147     return it;
148   }
149 
150   if (it == pos) {
151     // entity is at the top of the layer, adjust the layer iterator to
152     // the next entity
153     ++pos;
154   }
155   assert((*pos));
156 
157   // lower the entity
158   (void) stack.erase(it);
159   it = std::find(pos, send, zero);
160   assert(it != send);
161   return stack.insert(it, entity);
162 }
163 
164 
front(void) const165 StackEntity *StackingList::front(void) const {
166   assert(stack.size() > 5);
167 
168   if (*fullscreen) return *fullscreen;
169   if (*above) return *above;
170   if (*normal) return *normal;
171   if (*below) return *below;
172   // we do not return desktop entities
173   assert(0);
174 
175   // this point is never reached, but the compiler doesn't know that.
176   return zero;
177 }
178 
179 
back(void) const180 StackEntity *StackingList::back(void) const {
181   assert(stack.size() > 5);
182 
183   const_iterator it = desktop, _end = stack.begin();
184   for (--it; it != _end; --it) {
185     if (*it) return *it;
186   }
187 
188   assert(0);
189   return zero;
190 }
191 
192 
print_entity(StackEntity * entity)193 static void print_entity(StackEntity *entity)
194 {
195   BlackboxWindow *win = dynamic_cast<BlackboxWindow *>(entity);
196   if (win) {
197     fprintf(stderr, "  0x%lx: window 0x%lx %p '%s'\n",
198             win->windowID(), win->clientWindow(), win,
199             bt::toLocale(win->title()).c_str());
200   } else if (entity) {
201     fprintf(stderr, "  0x%lx: %p unknown entity\n",
202             entity->windowID(), entity);
203   } else {
204     fprintf(stderr, "  zero\n");
205   }
206 }
207 
208 
dump(void) const209 void StackingList::dump(void) const {
210   const_iterator it = stack.begin(), _end = stack.end();
211   fprintf(stderr, "Stack:\n");
212   for (; it != _end; ++it)
213     print_entity(*it);
214 
215   fprintf(stderr, "Layers:\n");
216   print_entity(*fullscreen);
217   print_entity(*above);
218   print_entity(*normal);
219   print_entity(*below);
220   print_entity(*desktop);
221 }
222