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

add module wayfire/window, wayfire/workspaces #3863

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
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
122 changes: 122 additions & 0 deletions include/modules/wayfire/backend.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,122 @@
#pragma once

#include <json/json.h>
#include <unistd.h>

#include <functional>
#include <list>
#include <memory>
#include <mutex>
#include <optional>
#include <string>
#include <unordered_map>
#include <utility>

namespace waybar::modules::wayfire {

using EventHandler = std::function<void(const std::string& event)>;

struct State {
/*
┌───────────┐ ┌───────────┐
│ output #1 │ │ output #2 │
└─────┬─────┘ └─────┬─────┘
└─┐ └─────┐─ ─ ─ ─ ─ ─ ─ ─ ┐
┌───────┴───────┐ ┌───────┴──────┐ ┌───────┴───────┐
│ wset #1 │ │ wset #2 │ │ wset #3 │
│┌────────────┐ │ │┌────────────┐│ │┌────────────┐ │
││ workspaces │ │ ││ workspaces ││ ││ workspaces │ │
│└─┬──────────┘ │ │└────────────┘│ │└─┬──────────┘ │
│ │ ┌─────────┐│ └──────────────┘ │ │ ┌─────────┐│
│ ├─┤ view #1 ││ │ └─┤ view #3 ││
│ │ └─────────┘│ │ └─────────┘│
│ │ ┌─────────┐│ └───────────────┘
│ └─┤ view #2 ││
│ └─────────┘│
└───────────────┘
*/

struct Output {
size_t id;
size_t w, h;
size_t wset_idx;
};

struct Workspace {
size_t num_views;
size_t num_sticky_views;
};

struct Wset {
std::optional<std::reference_wrapper<Output>> output;
std::vector<Workspace> wss;
size_t ws_w, ws_h, ws_x, ws_y;
size_t focused_view_id;

auto ws_idx() const { return ws_w * ws_y + ws_x; }
auto count_ws(const Json::Value& pos) -> Workspace&;
auto locate_ws(const Json::Value& geo) -> Workspace&;
auto locate_ws(const Json::Value& geo) const -> const Workspace&;
};

std::unordered_map<std::string, Output> outputs;
std::unordered_map<size_t, Wset> wsets;
std::unordered_map<size_t, Json::Value> views;
std::string focused_output_name;
size_t maybe_empty_focus_wset_idx = {};
size_t vswitch_sticky_view_id = {};
bool new_output_detected = {};
bool vswitching = {};

auto update_view(const Json::Value& view) -> void;
};

struct Sock {
int fd;

Sock(int fd) : fd{fd} {}
~Sock() { close(fd); }
Sock(const Sock&) = delete;
auto operator=(const Sock&) = delete;
Sock(Sock&& rhs) noexcept {
fd = rhs.fd;
rhs.fd = -1;
}
auto& operator=(Sock&& rhs) noexcept {
fd = rhs.fd;
rhs.fd = -1;
return *this;
}
};

class IPC {
static std::weak_ptr<IPC> instance;
Json::CharReaderBuilder reader_builder;
Json::StreamWriterBuilder writer_builder;
std::list<std::pair<std::string, std::reference_wrapper<const EventHandler>>> handlers;
std::mutex handlers_mutex;
State state;
std::mutex state_mutex;

IPC() { start(); }

static auto connect() -> Sock;
auto receive(Sock& sock) -> Json::Value;
auto start() -> void;
auto root_event_handler(const std::string& event, const Json::Value& data) -> void;
auto update_state_handler(const std::string& event, const Json::Value& data) -> void;

public:
static auto get_instance() -> std::shared_ptr<IPC>;
auto send(const std::string& method, Json::Value&& data) -> Json::Value;
auto register_handler(const std::string& event, const EventHandler& handler) -> void;
auto unregister_handler(EventHandler& handler) -> void;

auto lock_state() -> std::lock_guard<std::mutex> { return std::lock_guard{state_mutex}; }
auto& get_outputs() const { return state.outputs; }
auto& get_wsets() const { return state.wsets; }
auto& get_views() const { return state.views; }
auto& get_focused_output_name() const { return state.focused_output_name; }
};

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

#include "AAppIconLabel.hpp"
#include "bar.hpp"
#include "modules/wayfire/backend.hpp"

namespace waybar::modules::wayfire {

class Window : public AAppIconLabel {
std::shared_ptr<IPC> ipc;
EventHandler handler;

const Bar& bar_;
std::string old_app_id_;

public:
Window(const std::string& id, const Bar& bar, const Json::Value& config);
~Window() override;

auto update() -> void override;
auto update_icon_label() -> void;
};

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

#include <gtkmm/button.h>
#include <json/json.h>

#include <memory>
#include <vector>

#include "AModule.hpp"
#include "bar.hpp"
#include "modules/wayfire/backend.hpp"

namespace waybar::modules::wayfire {

class Workspaces : public AModule {
std::shared_ptr<IPC> ipc;
EventHandler handler;

const Bar& bar_;
Gtk::Box box_;
std::vector<Gtk::Button> buttons_;

auto handleScroll(GdkEventScroll* e) -> bool override;
auto update() -> void override;
auto update_box() -> void;

public:
Workspaces(const std::string& id, const Bar& bar, const Json::Value& config);
~Workspaces() override;
};

} // namespace waybar::modules::wayfire
82 changes: 82 additions & 0 deletions man/waybar-wayfire-window.5.scd
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
waybar-wayfire-window(5)

# NAME

waybar - wayfire window module

# DESCRIPTION

The *window* module displays the title of the currently focused window in wayfire.

# CONFIGURATION

Addressed by *wayfire/window*

*format*: ++
typeof: string ++
default: {title} ++
The format, how information should be displayed. On {} the current window title is displayed.

*rewrite*: ++
typeof: object ++
Rules to rewrite window title. See *rewrite rules*.

*icon*: ++
typeof: bool ++
default: false ++
Option to hide the application icon.

*icon-size*: ++
typeof: integer ++
default: 24 ++
Option to change the size of the application icon.

*expand*: ++
typeof: bool ++
default: false ++
Enables this module to consume all left over space dynamically.

# FORMAT REPLACEMENTS

See the output of "wayfire msg windows" for examples

*{title}*: The current title of the focused window.

*{app_id}*: The current app ID of the focused window.

# REWRITE RULES

*rewrite* is an object where keys are regular expressions and values are
rewrite rules if the expression matches. Rules may contain references to
captures of the expression.

Regular expression and replacement follow ECMA-script rules.

If no expression matches, the title is left unchanged.

Invalid expressions (e.g., mismatched parentheses) are skipped.

# EXAMPLES

```
"wayfire/window": {
"format": "{}",
"rewrite": {
"(.*) - Mozilla Firefox": "🌎 $1",
"(.*) - zsh": "> [$1]"
}
}
```

# STYLE

- *#window*
- *window#waybar.empty #window* When no windows are on the workspace

The following classes are applied to the entire Waybar rather than just the
window widget:

- *window#waybar.empty* When no windows are in the workspace
- *window#waybar.solo* When only one window is on the workspace
- *window#waybar.<app-id>* Where *app-id* is the app ID of the only window on
the workspace
86 changes: 86 additions & 0 deletions man/waybar-wayfire-workspaces.5.scd
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
waybar-wayfire-workspaces(5)

# NAME

waybar - wayfire workspaces module

# DESCRIPTION

The *workspaces* module displays the currently used workspaces in wayfire.

# CONFIGURATION

Addressed by *wayfire/workspaces*

*format*: ++
typeof: string ++
default: {value} ++
The format, how information should be displayed.

*format-icons*: ++
typeof: array ++
Based on the workspace name, index and state, the corresponding icon gets selected. See *icons*.

*disable-click*: ++
typeof: bool ++
default: false ++
If set to false, you can click to change workspace. If set to true this behaviour is disabled.

*disable-markup*: ++
typeof: bool ++
default: false ++
If set to true, button label will escape pango markup.

*current-only*: ++
typeof: bool ++
default: false ++
If set to true, only the active or focused workspace will be shown.

*on-update*: ++
typeof: string ++
Command to execute when the module is updated.

*expand*: ++
typeof: bool ++
default: false ++
Enables this module to consume all left over space dynamically.

# FORMAT REPLACEMENTS

*{icon}*: Icon, as defined in *format-icons*.

*{index}*: Index of the workspace on its output.

*{output}*: Output where the workspace is located.

# ICONS

Additional to workspace name matching, the following *format-icons* can be set.

- *default*: Will be shown, when no string matches are found.
- *focused*: Will be shown, when workspace is focused.

# EXAMPLES

```
"wayfire/workspaces": {
"format": "{icon}",
"format-icons": {
"1": "",
"2": "",
"3": "",
"4": "",
"5": "",
"focused": "",
"default": ""
}
}
```

# Style

- *#workspaces button*
- *#workspaces button.focused*: The single focused workspace.
- *#workspaces button.empty*: The workspace is empty.
- *#workspaces button.current_output*: The workspace is from the same output as
the bar that it is displayed on.
9 changes: 9 additions & 0 deletions meson.build
Original file line number Diff line number Diff line change
Expand Up @@ -333,6 +333,15 @@ if get_option('niri')
)
endif

if true
add_project_arguments('-DHAVE_WAYFIRE', language: 'cpp')
src_files += files(
'src/modules/wayfire/backend.cpp',
'src/modules/wayfire/window.cpp',
'src/modules/wayfire/workspaces.cpp',
)
endif

if libnl.found() and libnlgen.found()
add_project_arguments('-DHAVE_LIBNL', language: 'cpp')
src_files += files('src/modules/network.cpp')
Expand Down
12 changes: 12 additions & 0 deletions src/factory.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,10 @@
#include "modules/niri/window.hpp"
#include "modules/niri/workspaces.hpp"
#endif
#ifdef HAVE_WAYFIRE
#include "modules/wayfire/window.hpp"
#include "modules/wayfire/workspaces.hpp"
#endif
#if defined(__FreeBSD__) || defined(__linux__)
#include "modules/battery.hpp"
#endif
Expand Down Expand Up @@ -221,6 +225,14 @@ waybar::AModule* waybar::Factory::makeModule(const std::string& name,
if (ref == "niri/workspaces") {
return new waybar::modules::niri::Workspaces(id, bar_, config_[name]);
}
#endif
#ifdef HAVE_WAYFIRE
if (ref == "wayfire/window") {
return new waybar::modules::wayfire::Window(id, bar_, config_[name]);
}
if (ref == "wayfire/workspaces") {
return new waybar::modules::wayfire::Workspaces(id, bar_, config_[name]);
}
#endif
if (ref == "idle_inhibitor") {
return new waybar::modules::IdleInhibitor(id, bar_, config_[name]);
Expand Down
Loading