15
15
namespace waybar ::modules::sway {
16
16
17
17
Window::Window (const std::string& id, const Bar& bar, const Json::Value& config)
18
- : AIconLabel(config, " window" , id, " {title }" , 0 , true ), bar_(bar), windowId_(-1 ) {
18
+ : AIconLabel(config, " window" , id, " {}" , 0 , true ), bar_(bar), windowId_(-1 ) {
19
19
// Icon size
20
20
if (config_[" icon-size" ].isUInt ()) {
21
21
app_icon_size_ = config[" icon-size" ].asUInt ();
@@ -33,6 +33,7 @@ Window::Window(const std::string& id, const Bar& bar, const Json::Value& config)
33
33
ipc_.handleEvent ();
34
34
} catch (const std::exception & e) {
35
35
spdlog::error (" Window: {}" , e.what ());
36
+ spdlog::trace (" Window::Window exception" );
36
37
}
37
38
});
38
39
}
@@ -44,12 +45,13 @@ void Window::onCmd(const struct Ipc::ipc_response& res) {
44
45
std::lock_guard<std::mutex> lock (mutex_);
45
46
auto payload = parser_.parse (res.payload );
46
47
auto output = payload[" output" ].isString () ? payload[" output" ].asString () : " " ;
47
- std::tie (app_nb_, windowId_, window_, app_id_, app_class_, shell_) =
48
+ std::tie (app_nb_, floating_count_, windowId_, window_, app_id_, app_class_, shell_, layout_ ) =
48
49
getFocusedNode (payload[" nodes" ], output);
49
50
updateAppIconName ();
50
51
dp.emit ();
51
52
} catch (const std::exception & e) {
52
53
spdlog::error (" Window: {}" , e.what ());
54
+ spdlog::trace (" Window::onCmd exception" );
53
55
}
54
56
}
55
57
@@ -154,27 +156,52 @@ void Window::updateAppIcon() {
154
156
}
155
157
156
158
auto Window::update () -> void {
157
- if (!old_app_id_.empty ()) {
158
- bar_.window .get_style_context ()->remove_class (old_app_id_);
159
- }
159
+ spdlog::trace (" workspace layout {}, tiled count {}, floating count {}" , layout_, app_nb_,
160
+ floating_count_);
161
+
162
+ int mode = 0 ;
160
163
if (app_nb_ == 0 ) {
161
- bar_.window .get_style_context ()->remove_class (" solo" );
162
- if (!bar_.window .get_style_context ()->has_class (" empty" )) {
163
- bar_.window .get_style_context ()->add_class (" empty" );
164
+ if (floating_count_ == 0 ) {
165
+ mode += 1 ;
166
+ } else {
167
+ mode += 4 ;
164
168
}
165
169
} else if (app_nb_ == 1 ) {
166
- bar_.window .get_style_context ()->remove_class (" empty" );
167
- if (!bar_.window .get_style_context ()->has_class (" solo" )) {
168
- bar_.window .get_style_context ()->add_class (" solo" );
170
+ mode += 2 ;
171
+ } else {
172
+ if (layout_ == " tabbed" ) {
173
+ mode += 8 ;
174
+ } else if (layout_ == " stacked" ) {
175
+ mode += 16 ;
176
+ } else {
177
+ mode += 32 ;
169
178
}
170
179
if (!app_id_.empty () && !bar_.window .get_style_context ()->has_class (app_id_)) {
171
180
bar_.window .get_style_context ()->add_class (app_id_);
172
181
old_app_id_ = app_id_;
173
182
}
174
- } else {
175
- bar_.window .get_style_context ()->remove_class (" solo" );
176
- bar_.window .get_style_context ()->remove_class (" empty" );
177
183
}
184
+
185
+ if (!old_app_id_.empty () && ((mode & 2 ) == 0 || old_app_id_ != app_id_) &&
186
+ bar_.window .get_style_context ()->has_class (old_app_id_)) {
187
+ spdlog::trace (" Removing app_id class: {}" , old_app_id_);
188
+ bar_.window .get_style_context ()->remove_class (old_app_id_);
189
+ old_app_id_ = " " ;
190
+ }
191
+
192
+ setClass (" empty" , ((mode & 1 ) > 0 ));
193
+ setClass (" solo" , ((mode & 2 ) > 0 ));
194
+ setClass (" floating" , ((mode & 4 ) > 0 ));
195
+ setClass (" tabbed" , ((mode & 8 ) > 0 ));
196
+ setClass (" stacked" , ((mode & 16 ) > 0 ));
197
+ setClass (" tiled" , ((mode & 32 ) > 0 ));
198
+
199
+ if ((mode & 2 ) > 0 && !app_id_.empty () && !bar_.window .get_style_context ()->has_class (app_id_)) {
200
+ spdlog::trace (" Adding app_id class: {}" , app_id_);
201
+ bar_.window .get_style_context ()->add_class (app_id_);
202
+ old_app_id_ = app_id_;
203
+ }
204
+
178
205
label_.set_markup (fmt::format (format_, fmt::arg (" title" , rewriteTitle (window_)),
179
206
fmt::arg (" app_id" , app_id_), fmt::arg (" shell" , shell_)));
180
207
if (tooltipEnabled ()) {
@@ -187,78 +214,151 @@ auto Window::update() -> void {
187
214
AIconLabel::update ();
188
215
}
189
216
190
- int leafNodesInWorkspace (const Json::Value& node) {
217
+ void Window::setClass (std::string classname, bool enable) {
218
+ if (enable) {
219
+ if (!bar_.window .get_style_context ()->has_class (classname)) {
220
+ bar_.window .get_style_context ()->add_class (classname);
221
+ }
222
+ } else {
223
+ bar_.window .get_style_context ()->remove_class (classname);
224
+ }
225
+ }
226
+
227
+ std::pair<int , int > leafNodesInWorkspace (const Json::Value& node) {
191
228
auto const & nodes = node[" nodes" ];
192
229
auto const & floating_nodes = node[" floating_nodes" ];
193
230
if (nodes.empty () && floating_nodes.empty ()) {
194
- if (node[" type" ] == " workspace" )
195
- return 0 ;
196
- else
197
- return 1 ;
231
+ if (node[" type" ].asString () == " workspace" )
232
+ return {0 , 0 };
233
+ else if (node[" type" ].asString () == " floating_con" ) {
234
+ return {0 , 1 };
235
+ } else {
236
+ return {1 , 0 };
237
+ }
198
238
}
199
239
int sum = 0 ;
200
- if (!nodes.empty ()) {
201
- for (auto const & node : nodes) sum += leafNodesInWorkspace (node);
240
+ int floating_sum = 0 ;
241
+ for (auto const & node : nodes) {
242
+ std::pair all_leaf_nodes = leafNodesInWorkspace (node);
243
+ sum += all_leaf_nodes.first ;
244
+ floating_sum += all_leaf_nodes.second ;
202
245
}
203
- if (!floating_nodes.empty ()) {
204
- for (auto const & node : floating_nodes) sum += leafNodesInWorkspace (node);
246
+ for (auto const & node : floating_nodes) {
247
+ std::pair all_leaf_nodes = leafNodesInWorkspace (node);
248
+ sum += all_leaf_nodes.first ;
249
+ floating_sum += all_leaf_nodes.second ;
205
250
}
206
- return sum;
251
+ return { sum, floating_sum} ;
207
252
}
208
253
209
- std::tuple<std::size_t , int , std::string, std::string, std::string, std::string> gfnWithWorkspace (
210
- const Json::Value& nodes, std::string& output, const Json::Value& config_, const Bar& bar_,
211
- Json::Value& parentWorkspace) {
254
+ std::tuple<std::size_t , int , int , std::string, std::string, std::string, std::string, std::string>
255
+ gfnWithWorkspace (const Json::Value& nodes, std::string& output, const Json::Value& config_,
256
+ const Bar& bar_, Json::Value& parentWorkspace,
257
+ const Json::Value& immediateParent) {
212
258
for (auto const & node : nodes) {
213
- if (node[" output" ].isString ()) {
214
- output = node[" output" ].asString ();
215
- }
216
- // found node
217
- if (node[" focused" ].asBool () && (node[" type" ] == " con" || node[" type" ] == " floating_con" )) {
218
- if ((!config_[" all-outputs" ].asBool () && output == bar_.output ->name ) ||
219
- config_[" all-outputs" ].asBool ()) {
220
- auto app_id = node[" app_id" ].isString () ? node[" app_id" ].asString ()
221
- : node[" window_properties" ][" instance" ].asString ();
222
- const auto app_class = node[" window_properties" ][" class" ].isString ()
223
- ? node[" window_properties" ][" class" ].asString ()
224
- : " " ;
225
-
226
- const auto shell = node[" shell" ].isString () ? node[" shell" ].asString () : " " ;
227
-
228
- int nb = node.size ();
229
- if (parentWorkspace != 0 ) nb = leafNodesInWorkspace (parentWorkspace);
230
- return {nb, node[" id" ].asInt (), Glib::Markup::escape_text (node[" name" ].asString ()),
231
- app_id, app_class, shell};
259
+ if (node[" type" ].asString () == " output" ) {
260
+ if ((!config_[" all-outputs" ].asBool () || config_[" offscreen-css" ].asBool ()) &&
261
+ (node[" name" ].asString () != bar_.output ->name )) {
262
+ continue ;
263
+ }
264
+ output = node[" name" ].asString ();
265
+ } else if (node[" type" ].asString () == " workspace" ) {
266
+ // needs to be a string comparison, because filterWorkspace is the current_workspace
267
+ if (node[" name" ].asString () != immediateParent[" current_workspace" ].asString ()) {
268
+ continue ;
232
269
}
270
+ if (node[" focused" ].asBool ()) {
271
+ std::pair all_leaf_nodes = leafNodesInWorkspace (node);
272
+ return {all_leaf_nodes.first ,
273
+ all_leaf_nodes.second ,
274
+ node[" id" ].asInt (),
275
+ (((all_leaf_nodes.first > 0 ) || (all_leaf_nodes.second > 0 )) &&
276
+ (config_[" show-focused-workspace-name" ].asBool ()))
277
+ ? node[" name" ].asString ()
278
+ : " " ,
279
+ " " ,
280
+ " " ,
281
+ " " ,
282
+ node[" layout" ].asString ()};
283
+ }
284
+ parentWorkspace = node;
285
+ } else if ((node[" type" ].asString () == " con" || node[" type" ].asString () == " floating_con" ) &&
286
+ (node[" focused" ].asBool ())) {
287
+ // found node
288
+ spdlog::trace (" actual output {}, output found {}, node (focused) found {}" , bar_.output ->name ,
289
+ output, node[" name" ].asString ());
290
+ auto app_id = node[" app_id" ].isString () ? node[" app_id" ].asString ()
291
+ : node[" window_properties" ][" instance" ].asString ();
292
+ const auto app_class = node[" window_properties" ][" class" ].isString ()
293
+ ? node[" window_properties" ][" class" ].asString ()
294
+ : " " ;
295
+ const auto shell = node[" shell" ].isString () ? node[" shell" ].asString () : " " ;
296
+ int nb = node.size ();
297
+ int floating_count = 0 ;
298
+ std::string workspace_layout = " " ;
299
+ if (!parentWorkspace.isNull ()) {
300
+ std::pair all_leaf_nodes = leafNodesInWorkspace (parentWorkspace);
301
+ nb = all_leaf_nodes.first ;
302
+ floating_count = all_leaf_nodes.second ;
303
+ workspace_layout = parentWorkspace[" layout" ].asString ();
304
+ }
305
+ return {nb,
306
+ floating_count,
307
+ node[" id" ].asInt (),
308
+ Glib::Markup::escape_text (node[" name" ].asString ()),
309
+ app_id,
310
+ app_class,
311
+ shell,
312
+ workspace_layout};
233
313
}
314
+
234
315
// iterate
235
- if (node[" type" ] == " workspace" ) parentWorkspace = node;
236
- auto [nb, id, name, app_id, app_class, shell] =
237
- gfnWithWorkspace (node[" nodes" ], output, config_, bar_, parentWorkspace);
238
- if (id > -1 && !name.empty ()) {
239
- return {nb, id, name, app_id, app_class, shell};
240
- }
241
- // Search for floating node
242
- std::tie (nb, id, name, app_id, app_class, shell) =
243
- gfnWithWorkspace (node[" floating_nodes" ], output, config_, bar_, parentWorkspace);
244
- if (id > -1 && !name.empty ()) {
245
- return {nb, id, name, app_id, app_class, shell};
316
+ auto [nb, f, id, name, app_id, app_class, shell, workspace_layout] =
317
+ gfnWithWorkspace (node[" nodes" ], output, config_, bar_, parentWorkspace, node);
318
+ auto [nb2, f2, id2, name2, app_id2, app_class2, shell2, workspace_layout2] =
319
+ gfnWithWorkspace (node[" floating_nodes" ], output, config_, bar_, parentWorkspace, node);
320
+
321
+ // if ((id > 0 || ((id2 < 0 || name2.empty()) && id > -1)) && !name.empty()) {
322
+ if ((id > 0 ) || (id2 < 0 && id > -1 )) {
323
+ return {nb, f, id, name, app_id, app_class, shell, workspace_layout};
324
+ } else if (id2 > 0 && !name2.empty ()) {
325
+ return {nb2, f2, id2, name2, app_id2, app_class, shell2, workspace_layout2};
246
326
}
247
327
}
248
- return {0 , -1 , " " , " " , " " , " " };
328
+
329
+ // this only comes into effect when no focused children are present
330
+ if (config_[" all-outputs" ].asBool () && config_[" offscreen-css" ].asBool () &&
331
+ immediateParent[" type" ].asString () == " workspace" ) {
332
+ std::pair all_leaf_nodes = leafNodesInWorkspace (immediateParent);
333
+ // using an empty string as default ensures that no window depending styles are set due to the
334
+ // checks above for !name.empty()
335
+ return {all_leaf_nodes.first ,
336
+ all_leaf_nodes.second ,
337
+ 0 ,
338
+ (all_leaf_nodes.first > 0 || all_leaf_nodes.second > 0 )
339
+ ? config_[" offscreen-css-text" ].asString ()
340
+ : " " ,
341
+ " " ,
342
+ " " ,
343
+ " " ,
344
+ immediateParent[" layout" ].asString ()};
345
+ }
346
+
347
+ return {0 , 0 , -1 , " " , " " , " " , " " , " " };
249
348
}
250
349
251
- std::tuple<std::size_t , int , std::string, std::string, std::string, std::string>
350
+ std::tuple<std::size_t , int , int , std::string, std::string, std::string, std::string, std::string>
252
351
Window::getFocusedNode (const Json::Value& nodes, std::string& output) {
253
- Json::Value placeholder = 0 ;
254
- return gfnWithWorkspace (nodes, output, config_, bar_, placeholder);
352
+ Json::Value placeholder = Json::Value::null ;
353
+ return gfnWithWorkspace (nodes, output, config_, bar_, placeholder, placeholder );
255
354
}
256
355
257
356
void Window::getTree () {
258
357
try {
259
358
ipc_.sendCmd (IPC_GET_TREE);
260
359
} catch (const std::exception & e) {
261
360
spdlog::error (" Window: {}" , e.what ());
361
+ spdlog::trace (" Window::getTree exception" );
262
362
}
263
363
}
264
364
0 commit comments