Skip to content

Commit

Permalink
add module wayfire/window, wayfire/workspaces
Browse files Browse the repository at this point in the history
  • Loading branch information
yamader committed Jan 3, 2025
1 parent ac08b75 commit d7e4a7d
Show file tree
Hide file tree
Showing 10 changed files with 1,072 additions and 0 deletions.
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

0 comments on commit d7e4a7d

Please sign in to comment.