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