Skip to content

Commit d41a60d

Browse files
authored
Merge pull request #1244 from alebastr/swaybar-ipc
Yet another swaybar ipc implementation
2 parents 9bc6fae + 05f7727 commit d41a60d

File tree

13 files changed

+623
-43
lines changed

13 files changed

+623
-43
lines changed

.github/workflows/freebsd.yml

+1
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ jobs:
1313
- name: Test in FreeBSD VM
1414
uses: vmactions/freebsd-vm@v0.1.5 # aka FreeBSD 13.0
1515
with:
16+
mem: 2048
1617
usesh: true
1718
prepare: |
1819
export CPPFLAGS=-isystem/usr/local/include LDFLAGS=-L/usr/local/lib # sndio

include/bar.hpp

+37-4
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,9 @@
88
#include <gtkmm/window.h>
99
#include <json/json.h>
1010

11+
#include <memory>
12+
#include <vector>
13+
1114
#include "AModule.hpp"
1215
#include "xdg-output-unstable-v1-client-protocol.h"
1316

@@ -36,6 +39,19 @@ struct bar_margins {
3639
int left = 0;
3740
};
3841

42+
struct bar_mode {
43+
bar_layer layer;
44+
bool exclusive;
45+
bool passthrough;
46+
bool visible;
47+
};
48+
49+
#ifdef HAVE_SWAY
50+
namespace modules::sway {
51+
class BarIpcClient;
52+
}
53+
#endif // HAVE_SWAY
54+
3955
class BarSurface {
4056
protected:
4157
BarSurface() = default;
@@ -54,38 +70,55 @@ class BarSurface {
5470

5571
class Bar {
5672
public:
73+
using bar_mode_map = std::map<std::string_view, struct bar_mode>;
74+
static const bar_mode_map PRESET_MODES;
75+
static const std::string_view MODE_DEFAULT;
76+
static const std::string_view MODE_INVISIBLE;
77+
5778
Bar(struct waybar_output *w_output, const Json::Value &);
5879
Bar(const Bar &) = delete;
59-
~Bar() = default;
80+
~Bar();
6081

82+
void setMode(const std::string_view &);
6183
void setVisible(bool visible);
6284
void toggle();
6385
void handleSignal(int);
6486

6587
struct waybar_output *output;
6688
Json::Value config;
67-
struct wl_surface * surface;
68-
bool exclusive = true;
89+
struct wl_surface *surface;
6990
bool visible = true;
7091
bool vertical = false;
7192
Gtk::Window window;
7293

94+
#ifdef HAVE_SWAY
95+
std::string bar_id;
96+
#endif
97+
7398
private:
7499
void onMap(GdkEventAny *);
75100
auto setupWidgets() -> void;
76101
void getModules(const Factory &, const std::string &, Gtk::Box*);
77102
void setupAltFormatKeyForModule(const std::string &module_name);
78103
void setupAltFormatKeyForModuleList(const char *module_list_name);
104+
void setMode(const bar_mode &);
105+
106+
/* Copy initial set of modes to allow customization */
107+
bar_mode_map configured_modes = PRESET_MODES;
108+
std::string last_mode_{MODE_DEFAULT};
79109

80110
std::unique_ptr<BarSurface> surface_impl_;
81-
bar_layer layer_;
82111
Gtk::Box left_;
83112
Gtk::Box center_;
84113
Gtk::Box right_;
85114
Gtk::Box box_;
86115
std::vector<std::unique_ptr<waybar::AModule>> modules_left_;
87116
std::vector<std::unique_ptr<waybar::AModule>> modules_center_;
88117
std::vector<std::unique_ptr<waybar::AModule>> modules_right_;
118+
#ifdef HAVE_SWAY
119+
using BarIpcClient = modules::sway::BarIpcClient;
120+
std::unique_ptr<BarIpcClient> _ipc_client;
121+
#endif
89122
std::vector<std::unique_ptr<waybar::AModule>> modules_all_;
90123
};
91124

include/client.hpp

+1
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@ class Client {
2929
struct zwp_idle_inhibit_manager_v1 *idle_inhibit_manager = nullptr;
3030
std::vector<std::unique_ptr<Bar>> bars;
3131
Config config;
32+
std::string bar_id;
3233

3334
private:
3435
Client() = default;

include/modules/sway/bar.hpp

+49
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
#pragma once
2+
#include <string>
3+
4+
#include "modules/sway/ipc/client.hpp"
5+
#include "util/SafeSignal.hpp"
6+
#include "util/json.hpp"
7+
8+
namespace waybar {
9+
10+
class Bar;
11+
12+
namespace modules::sway {
13+
14+
/*
15+
* Supported subset of i3/sway IPC barconfig object
16+
*/
17+
struct swaybar_config {
18+
std::string id;
19+
std::string mode;
20+
std::string hidden_state;
21+
};
22+
23+
/**
24+
* swaybar IPC client
25+
*/
26+
class BarIpcClient {
27+
public:
28+
BarIpcClient(waybar::Bar& bar);
29+
30+
private:
31+
void onInitialConfig(const struct Ipc::ipc_response& res);
32+
void onIpcEvent(const struct Ipc::ipc_response&);
33+
void onConfigUpdate(const swaybar_config& config);
34+
void onVisibilityUpdate(bool visible_by_modifier);
35+
void update();
36+
37+
Bar& bar_;
38+
util::JsonParser parser_;
39+
Ipc ipc_;
40+
41+
swaybar_config bar_config_;
42+
bool visible_by_modifier_ = false;
43+
44+
SafeSignal<bool> signal_visible_;
45+
SafeSignal<swaybar_config> signal_config_;
46+
};
47+
48+
} // namespace modules::sway
49+
} // namespace waybar

include/util/SafeSignal.hpp

+75
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,75 @@
1+
#pragma once
2+
3+
#include <glibmm/dispatcher.h>
4+
#include <sigc++/signal.h>
5+
6+
#include <functional>
7+
#include <mutex>
8+
#include <queue>
9+
#include <thread>
10+
#include <tuple>
11+
#include <type_traits>
12+
#include <utility>
13+
14+
namespace waybar {
15+
16+
/**
17+
* Thread-safe signal wrapper.
18+
* Uses Glib::Dispatcher to pass events to another thread and locked queue to pass the arguments.
19+
*/
20+
template <typename... Args>
21+
struct SafeSignal : sigc::signal<void(std::decay_t<Args>...)> {
22+
public:
23+
SafeSignal() { dp_.connect(sigc::mem_fun(*this, &SafeSignal::handle_event)); }
24+
25+
template <typename... EmitArgs>
26+
void emit(EmitArgs&&... args) {
27+
if (main_tid_ == std::this_thread::get_id()) {
28+
/*
29+
* Bypass the queue if the method is called the main thread.
30+
* Ensures that events emitted from the main thread are processed synchronously and saves a
31+
* few CPU cycles on locking/queuing.
32+
* As a downside, this makes main thread events prioritized over the other threads and
33+
* disrupts chronological order.
34+
*/
35+
signal_t::emit(std::forward<EmitArgs>(args)...);
36+
} else {
37+
{
38+
std::unique_lock lock(mutex_);
39+
queue_.emplace(std::forward<EmitArgs>(args)...);
40+
}
41+
dp_.emit();
42+
}
43+
}
44+
45+
template <typename... EmitArgs>
46+
inline void operator()(EmitArgs&&... args) {
47+
emit(std::forward<EmitArgs>(args)...);
48+
}
49+
50+
protected:
51+
using signal_t = sigc::signal<void(std::decay_t<Args>...)>;
52+
using slot_t = decltype(std::declval<signal_t>().make_slot());
53+
using arg_tuple_t = std::tuple<std::decay_t<Args>...>;
54+
// ensure that unwrapped methods are not accessible
55+
using signal_t::emit_reverse;
56+
using signal_t::make_slot;
57+
58+
void handle_event() {
59+
for (std::unique_lock lock(mutex_); !queue_.empty(); lock.lock()) {
60+
auto args = queue_.front();
61+
queue_.pop();
62+
lock.unlock();
63+
std::apply(cached_fn_, args);
64+
}
65+
}
66+
67+
Glib::Dispatcher dp_;
68+
std::mutex mutex_;
69+
std::queue<arg_tuple_t> queue_;
70+
const std::thread::id main_tid_ = std::this_thread::get_id();
71+
// cache functor for signal emission to avoid recreating it on each event
72+
const slot_t cached_fn_ = make_slot();
73+
};
74+
75+
} // namespace waybar

man/waybar.5.scd.in

+17-2
Original file line numberDiff line numberDiff line change
@@ -72,14 +72,19 @@ Also a minimal example configuration can be found on the at the bottom of this m
7272
typeof: string ++
7373
Optional name added as a CSS class, for styling multiple waybars.
7474

75+
*mode* ++
76+
typeof: string ++
77+
Selects one of the preconfigured display modes. This is an equivalent of the sway-bar(5) *mode* command and supports the same values: *dock*, *hide*, *invisible*, *overlay*. ++
78+
Note: *hide* and *invisible* modes may be not as useful without Sway IPC.
79+
7580
*exclusive* ++
7681
typeof: bool ++
77-
default: *true* unless the layer is set to *overlay* ++
82+
default: *true* ++
7883
Option to request an exclusive zone from the compositor. Disable this to allow drawing application windows underneath or on top of the bar.
7984

8085
*passthrough* ++
8186
typeof: bool ++
82-
default: *false* unless the layer is set to *overlay* ++
87+
default: *false* ++
8388
Option to pass any pointer events to the window under the bar.
8489
Intended to be used with either *top* or *overlay* layers and without exclusive zone.
8590

@@ -89,6 +94,16 @@ Also a minimal example configuration can be found on the at the bottom of this m
8994
Option to disable the use of gtk-layer-shell for popups.
9095
Only functional if compiled with gtk-layer-shell support.
9196

97+
*ipc* ++
98+
typeof: bool ++
99+
default: false ++
100+
Option to subscribe to the Sway IPC bar configuration and visibility events and control waybar with *swaymsg bar* commands. ++
101+
Requires *bar_id* value from sway configuration to be either passed with the *-b* commandline argument or specified with the *id* option.
102+
103+
*id* ++
104+
typeof: string ++
105+
*bar_id* for the Sway IPC. Use this if you need to override the value passed with the *-b bar_id* commandline argument for the specific bar instance.
106+
92107
*include* ++
93108
typeof: string|array ++
94109
Paths to additional configuration files.

meson.build

+1
Original file line numberDiff line numberDiff line change
@@ -178,6 +178,7 @@ endif
178178
add_project_arguments('-DHAVE_SWAY', language: 'cpp')
179179
src_files += [
180180
'src/modules/sway/ipc/client.cpp',
181+
'src/modules/sway/bar.cpp',
181182
'src/modules/sway/mode.cpp',
182183
'src/modules/sway/language.cpp',
183184
'src/modules/sway/window.cpp',

0 commit comments

Comments
 (0)