1 #include "stack.h"
2 
3 #include <X11/Xlib.h>
4 #include <string>
5 
6 #include "client.h"
7 #include "ewmh.h"
8 #include "globals.h"
9 #include "utils.h"
10 
11 using std::function;
12 using std::string;
13 using std::stringstream;
14 using std::vector;
15 
16 const std::array<const char*, LAYER_COUNT>g_layer_names =
17     ArrayInitializer<const char*, LAYER_COUNT>({
18      { LAYER_FOCUS       , "Focus-Layer"                },
19      { LAYER_FULLSCREEN  , "Fullscreen-Layer"           },
20      { LAYER_FLOATING    , "Floating-Layer"             },
21      { LAYER_NORMAL      , "Tiling-Layer"               },
22      { LAYER_FRAMES      , "Frame Layer"                },
23 }).a;
24 
25 
~Stack()26 Stack::~Stack() {
27     for (int i = 0; i < LAYER_COUNT; i++) {
28         if (!layers_[i].empty()) {
29             HSDebug("Warning: %s of stack %p was not empty on destroy\n",
30                     g_layer_names[i], (void*)this);
31         }
32     }
33 }
34 
Slice()35 Slice::Slice() {
36     layers.insert(LAYER_NORMAL);
37 }
38 
makeWindowSlice(Window window)39 Slice* Slice::makeWindowSlice(Window window) {
40     auto s = new Slice();
41     s->type = Type::WindowSlice;
42     s->data.window = window;
43     return s;
44 }
45 
makeFrameSlice(Window window)46 Slice* Slice::makeFrameSlice(Window window) {
47     auto s = Slice::makeWindowSlice(window);
48     s->layers.clear();
49     s->layers.insert(LAYER_FRAMES);
50     return s;
51 }
52 
53 
makeClientSlice(Client * client)54 Slice* Slice::makeClientSlice(Client* client) {
55     auto s = new Slice();
56     s->type = Type::ClientSlice;
57     s->data.client = client;
58     if (client->floating_()) {
59         s->layers.clear();
60         s->layers.insert(LAYER_FLOATING);
61     }
62     return s;
63 }
64 
highestLayer() const65 HSLayer Slice::highestLayer() const {
66     if (layers.empty()) {
67         return LAYER_COUNT;
68     } else {
69         return *(layers.begin());
70     }
71 }
72 
insertSlice(Slice * elem)73 void Stack::insertSlice(Slice* elem) {
74     for (auto layer : elem->layers) {
75         layers_[layer].insert(elem);
76     }
77     dirty = true;
78 }
79 
removeSlice(Slice * elem)80 void Stack::removeSlice(Slice* elem) {
81     for (auto layer : elem->layers) {
82         layers_[layer].remove(elem);
83     }
84     dirty = true;
85 }
86 
getLabel()87 string Slice::getLabel() {
88     stringstream label;
89     switch (type) {
90         case Type::WindowSlice:
91             label << "Window " << WindowID(data.window).str();
92             break;
93         case Type::ClientSlice:
94             label << "Client " << WindowID(data.client->x11Window()).str()
95                   << " \"" << data.client->title_() << "\"";
96             break;
97         default: ;
98     }
99     return label.str();
100 }
101 
102 //! helper function for Stack::toWindowBuf() for a given Slice and layer. The
103 //other parameters are as for Stack::toWindowBuf()
extractWindowsFromSlice(bool real_clients,HSLayer layer,function<void (Window)> yield)104 void Slice::extractWindowsFromSlice(bool real_clients, HSLayer layer,
105                                 function<void(Window)> yield) {
106     if (highestLayer() != layer) {
107         /** slice only is added to its highest layer.
108          * just skip it if the slice is not shown on this data->layer */
109         return;
110     }
111     switch (type) {
112         case Type::ClientSlice:
113             if (real_clients) {
114                 yield(data.client->x11Window());
115             } else {
116                 yield(data.client->decorationWindow());
117             }
118             break;
119         case Type::WindowSlice:
120             if (!real_clients) {
121                 yield(data.window);
122             }
123             break;
124     }
125 }
126 
127 //! return the stack of windows by successive calls to the given yield
128 //function. The stack is returned from top to bottom, i.e. the topmost element
129 //is the first element added to the stack.
extractWindows(bool real_clients,function<void (Window)> yield)130 void Stack::extractWindows(bool real_clients, function<void(Window)> yield) {
131     for (int i = 0; i < LAYER_COUNT; i++) {
132         for (auto slice : layers_[i]) {
133             slice->extractWindowsFromSlice(real_clients, (HSLayer)i, yield);
134         }
135     }
136 }
137 
raiseSlice(Slice * slice)138 void Stack::raiseSlice(Slice* slice) {
139     for (auto layer : slice->layers) {
140         layers_[layer].raise(slice);
141     }
142     dirty = true;
143 }
144 
145 //! insert the slice to the given layer. if 'insertOnTop' is set, insert at the top
146 //! otherwise insert at the bottom of the layer
sliceAddLayer(Slice * slice,HSLayer layer,bool insertOnTop)147 void Stack::sliceAddLayer(Slice* slice, HSLayer layer, bool insertOnTop) {
148     if (slice->layers.count(layer) != 0) {
149         /* nothing to do */
150         return;
151     }
152 
153     slice->layers.insert(layer);
154     layers_[layer].insert(slice, insertOnTop);
155     dirty = true;
156 }
157 
sliceRemoveLayer(Slice * slice,HSLayer layer)158 void Stack::sliceRemoveLayer(Slice* slice, HSLayer layer) {
159     /* remove slice from layer in the stack */
160     layers_[layer].remove(slice);
161     dirty = true;
162 
163     if (slice->layers.count(layer) == 0) {
164         return;
165     }
166 
167     slice->layers.erase(layer);
168 }
169 
isLayerEmpty(HSLayer layer)170 bool Stack::isLayerEmpty(HSLayer layer) {
171     return layers_[layer].empty();
172 }
173 
clearLayer(HSLayer layer)174 void Stack::clearLayer(HSLayer layer) {
175     while (!isLayerEmpty(layer)) {
176         sliceRemoveLayer(*layers_[layer].begin(), layer);
177         dirty = true;
178     }
179 }
180 
181