Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Yet another swaybar ipc implementation #1244

Merged
merged 23 commits into from
Dec 1, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
23 commits
Select commit Hold shift + click to select a range
285a264
feat(util): SafeSignal class for cross-thread signals with arguments
alebastr Dec 29, 2020
8a0e76c
fix(util): avoid creating temporary functor for each event
alebastr Oct 20, 2020
79883db
feat(util): optimize SafeSignal for events from the main thread
alebastr Dec 29, 2020
3e2197a
test(util): add tests for SafeSignal
alebastr Dec 29, 2020
03a641e
feat(bar): support swaybar `mode` for configuring window
alebastr Sep 15, 2021
bc13453
feat(swaybar-ipc): handle mode update
alebastr Sep 15, 2021
ebdeb86
feat(swaybar-ipc): handle visibility_by_modifier update
alebastr Oct 20, 2020
6d2ba7a
feat(bar): store modes as a map of presets
alebastr Nov 20, 2021
ae88d7d
feat(bar): use "default" mode to store global options
alebastr Nov 20, 2021
87b43c2
feat(bar): attach CSS class `mode-{mode}` to window when setting mode
alebastr Nov 20, 2021
23e5181
feat(swaybar-ipc): add swaybar IPC client
alebastr Oct 20, 2020
5baffbf
doc: document swaybar ipc options, `ipc` and `id`
alebastr Nov 20, 2021
452dcaa
feat(client): store bar_id argument
alebastr Nov 20, 2021
52361ed
refactor(bar): make setVisible switch between "default" and "invisibl…
alebastr Nov 21, 2021
5905078
doc: document `mode` option of the bar config
alebastr Nov 20, 2021
6bfb674
fix(swaybar-ipc): better logs
alebastr Nov 22, 2021
2290fe1
fix(bar): handle ipc connection errors.
alebastr Nov 23, 2021
8fe42eb
doc: update `exclusive` and `passthrough` defaults
alebastr Nov 24, 2021
b4e1967
ci: increase FreeBSD VM memory to 2048MB
alebastr Nov 24, 2021
4b5dc1b
test: count copies and moves done by SafeSignal
alebastr Nov 28, 2021
cf5ddb2
fix(swaybar-ipc): avoid unnecessary copy of struct swaybar_config
alebastr Nov 28, 2021
b6d0a4b
feat(bar): allow customization of bar modes
alebastr Nov 28, 2021
05f7727
Merge branch 'master' into swaybar-ipc
Alexays Dec 1, 2021
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .github/workflows/freebsd.yml
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ jobs:
- name: Test in FreeBSD VM
uses: vmactions/freebsd-vm@v0.1.5 # aka FreeBSD 13.0
with:
mem: 2048
usesh: true
prepare: |
export CPPFLAGS=-isystem/usr/local/include LDFLAGS=-L/usr/local/lib # sndio
Expand Down
41 changes: 37 additions & 4 deletions include/bar.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,9 @@
#include <gtkmm/window.h>
#include <json/json.h>

#include <memory>
#include <vector>

#include "AModule.hpp"
#include "xdg-output-unstable-v1-client-protocol.h"

Expand Down Expand Up @@ -36,6 +39,19 @@ struct bar_margins {
int left = 0;
};

struct bar_mode {
bar_layer layer;
bool exclusive;
bool passthrough;
bool visible;
};

#ifdef HAVE_SWAY
namespace modules::sway {
class BarIpcClient;
}
#endif // HAVE_SWAY

class BarSurface {
protected:
BarSurface() = default;
Expand All @@ -54,38 +70,55 @@ class BarSurface {

class Bar {
public:
using bar_mode_map = std::map<std::string_view, struct bar_mode>;
static const bar_mode_map PRESET_MODES;
static const std::string_view MODE_DEFAULT;
static const std::string_view MODE_INVISIBLE;

Bar(struct waybar_output *w_output, const Json::Value &);
Bar(const Bar &) = delete;
~Bar() = default;
~Bar();

void setMode(const std::string_view &);
void setVisible(bool visible);
void toggle();
void handleSignal(int);

struct waybar_output *output;
Json::Value config;
struct wl_surface * surface;
bool exclusive = true;
struct wl_surface *surface;
bool visible = true;
bool vertical = false;
Gtk::Window window;

#ifdef HAVE_SWAY
std::string bar_id;
#endif

private:
void onMap(GdkEventAny *);
auto setupWidgets() -> void;
void getModules(const Factory &, const std::string &, Gtk::Box*);
void setupAltFormatKeyForModule(const std::string &module_name);
void setupAltFormatKeyForModuleList(const char *module_list_name);
void setMode(const bar_mode &);

/* Copy initial set of modes to allow customization */
bar_mode_map configured_modes = PRESET_MODES;
std::string last_mode_{MODE_DEFAULT};

std::unique_ptr<BarSurface> surface_impl_;
bar_layer layer_;
Gtk::Box left_;
Gtk::Box center_;
Gtk::Box right_;
Gtk::Box box_;
std::vector<std::unique_ptr<waybar::AModule>> modules_left_;
std::vector<std::unique_ptr<waybar::AModule>> modules_center_;
std::vector<std::unique_ptr<waybar::AModule>> modules_right_;
#ifdef HAVE_SWAY
using BarIpcClient = modules::sway::BarIpcClient;
std::unique_ptr<BarIpcClient> _ipc_client;
#endif
std::vector<std::unique_ptr<waybar::AModule>> modules_all_;
};

Expand Down
1 change: 1 addition & 0 deletions include/client.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ class Client {
struct zwp_idle_inhibit_manager_v1 *idle_inhibit_manager = nullptr;
std::vector<std::unique_ptr<Bar>> bars;
Config config;
std::string bar_id;

private:
Client() = default;
Expand Down
49 changes: 49 additions & 0 deletions include/modules/sway/bar.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
#pragma once
#include <string>

#include "modules/sway/ipc/client.hpp"
#include "util/SafeSignal.hpp"
#include "util/json.hpp"

namespace waybar {

class Bar;

namespace modules::sway {

/*
* Supported subset of i3/sway IPC barconfig object
*/
struct swaybar_config {
std::string id;
std::string mode;
std::string hidden_state;
};

/**
* swaybar IPC client
*/
class BarIpcClient {
public:
BarIpcClient(waybar::Bar& bar);

private:
void onInitialConfig(const struct Ipc::ipc_response& res);
void onIpcEvent(const struct Ipc::ipc_response&);
void onConfigUpdate(const swaybar_config& config);
void onVisibilityUpdate(bool visible_by_modifier);
void update();

Bar& bar_;
util::JsonParser parser_;
Ipc ipc_;

swaybar_config bar_config_;
bool visible_by_modifier_ = false;

SafeSignal<bool> signal_visible_;
SafeSignal<swaybar_config> signal_config_;
};

} // namespace modules::sway
} // namespace waybar
75 changes: 75 additions & 0 deletions include/util/SafeSignal.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
#pragma once

#include <glibmm/dispatcher.h>
#include <sigc++/signal.h>

#include <functional>
#include <mutex>
#include <queue>
#include <thread>
#include <tuple>
#include <type_traits>
#include <utility>

namespace waybar {

/**
* Thread-safe signal wrapper.
* Uses Glib::Dispatcher to pass events to another thread and locked queue to pass the arguments.
*/
template <typename... Args>
struct SafeSignal : sigc::signal<void(std::decay_t<Args>...)> {
public:
SafeSignal() { dp_.connect(sigc::mem_fun(*this, &SafeSignal::handle_event)); }

template <typename... EmitArgs>
void emit(EmitArgs&&... args) {
if (main_tid_ == std::this_thread::get_id()) {
/*
* Bypass the queue if the method is called the main thread.
* Ensures that events emitted from the main thread are processed synchronously and saves a
* few CPU cycles on locking/queuing.
* As a downside, this makes main thread events prioritized over the other threads and
* disrupts chronological order.
*/
signal_t::emit(std::forward<EmitArgs>(args)...);
} else {
{
std::unique_lock lock(mutex_);
queue_.emplace(std::forward<EmitArgs>(args)...);
}
dp_.emit();
}
}

template <typename... EmitArgs>
inline void operator()(EmitArgs&&... args) {
emit(std::forward<EmitArgs>(args)...);
}

protected:
using signal_t = sigc::signal<void(std::decay_t<Args>...)>;
using slot_t = decltype(std::declval<signal_t>().make_slot());
using arg_tuple_t = std::tuple<std::decay_t<Args>...>;
// ensure that unwrapped methods are not accessible
using signal_t::emit_reverse;
using signal_t::make_slot;

void handle_event() {
for (std::unique_lock lock(mutex_); !queue_.empty(); lock.lock()) {
auto args = queue_.front();
queue_.pop();
lock.unlock();
std::apply(cached_fn_, args);
}
}

Glib::Dispatcher dp_;
std::mutex mutex_;
std::queue<arg_tuple_t> queue_;
const std::thread::id main_tid_ = std::this_thread::get_id();
// cache functor for signal emission to avoid recreating it on each event
const slot_t cached_fn_ = make_slot();
};

} // namespace waybar
19 changes: 17 additions & 2 deletions man/waybar.5.scd.in
Original file line number Diff line number Diff line change
Expand Up @@ -72,14 +72,19 @@ Also a minimal example configuration can be found on the at the bottom of this m
typeof: string ++
Optional name added as a CSS class, for styling multiple waybars.

*mode* ++
typeof: string ++
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*. ++
Note: *hide* and *invisible* modes may be not as useful without Sway IPC.

*exclusive* ++
typeof: bool ++
default: *true* unless the layer is set to *overlay* ++
default: *true* ++
Option to request an exclusive zone from the compositor. Disable this to allow drawing application windows underneath or on top of the bar.

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

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

*ipc* ++
typeof: bool ++
default: false ++
Option to subscribe to the Sway IPC bar configuration and visibility events and control waybar with *swaymsg bar* commands. ++
Requires *bar_id* value from sway configuration to be either passed with the *-b* commandline argument or specified with the *id* option.

*id* ++
typeof: string ++
*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.

*include* ++
typeof: string|array ++
Paths to additional configuration files.
Expand Down
1 change: 1 addition & 0 deletions meson.build
Original file line number Diff line number Diff line change
Expand Up @@ -178,6 +178,7 @@ endif
add_project_arguments('-DHAVE_SWAY', language: 'cpp')
src_files += [
'src/modules/sway/ipc/client.cpp',
'src/modules/sway/bar.cpp',
'src/modules/sway/mode.cpp',
'src/modules/sway/language.cpp',
'src/modules/sway/window.cpp',
Expand Down
Loading