Skip to content

Commit

Permalink
Merge pull request #1244 from alebastr/swaybar-ipc
Browse files Browse the repository at this point in the history
Yet another swaybar ipc implementation
  • Loading branch information
Alexays authored Dec 1, 2021
2 parents 9bc6fae + 05f7727 commit d41a60d
Show file tree
Hide file tree
Showing 13 changed files with 623 additions and 43 deletions.
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/[email protected] # 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

0 comments on commit d41a60d

Please sign in to comment.