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 niri/workspaces, niri/window, niri/language #3551

Merged
merged 4 commits into from
Sep 13, 2024
Merged
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
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
- Sway (Workspaces, Binding mode, Focused window name)
- River (Mapping mode, Tags, Focused window name)
- Hyprland (Window Icons, Workspaces, Focused window name)
- Niri (Workspaces, Focused window name, Language)
- DWL (Tags, Focused window name) [requires dwl ipc patch](https://github.com/djpohly/dwl/wiki/ipc)
- Tray [#21](https://github.com/Alexays/Waybar/issues/21)
- Local time
Expand Down
52 changes: 52 additions & 0 deletions include/modules/niri/backend.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
#pragma once

#include <list>
#include <mutex>
#include <string>
#include <utility>

#include "util/json.hpp"

namespace waybar::modules::niri {

class EventHandler {
public:
virtual void onEvent(const Json::Value& ev) = 0;
virtual ~EventHandler() = default;
};

class IPC {
public:
IPC() { startIPC(); }

void registerForIPC(const std::string& ev, EventHandler* ev_handler);
void unregisterForIPC(EventHandler* handler);

static Json::Value send(const Json::Value& request);

// The data members are only safe to access while dataMutex_ is locked.
std::lock_guard<std::mutex> lockData() { return std::lock_guard(dataMutex_); }
const std::vector<Json::Value> &workspaces() const { return workspaces_; }
const std::vector<Json::Value> &windows() const { return windows_; }
const std::vector<std::string> &keyboardLayoutNames() const { return keyboardLayoutNames_; }
unsigned keyboardLayoutCurrent() const { return keyboardLayoutCurrent_; }

private:
void startIPC();
static int connectToSocket();
void parseIPC(const std::string&);

std::mutex dataMutex_;
std::vector<Json::Value> workspaces_;
std::vector<Json::Value> windows_;
std::vector<std::string> keyboardLayoutNames_;
unsigned keyboardLayoutCurrent_;

util::JsonParser parser_;
std::mutex callbackMutex_;
std::list<std::pair<std::string, EventHandler*>> callbacks_;
};

inline std::unique_ptr<IPC> gIPC;

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

#include <string>

#include "ALabel.hpp"
#include "bar.hpp"
#include "modules/niri/backend.hpp"

namespace waybar::modules::niri {

class Language : public ALabel, public EventHandler {
public:
Language(const std::string&, const Bar&, const Json::Value&);
~Language() override;
void update() override;

private:
void updateFromIPC();
void onEvent(const Json::Value &ev) override;
void doUpdate();

struct Layout {
std::string full_name;
std::string short_name;
std::string variant;
std::string short_description;
};

static Layout getLayout(const std::string &fullName);

std::mutex mutex_;
const Bar &bar_;

std::vector<Layout> layouts_;
unsigned current_idx_;
};

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

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

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

namespace waybar::modules::niri {

class Window : public AAppIconLabel, public EventHandler {
public:
Window(const std::string &, const Bar &, const Json::Value &);
~Window() override;
void update() override;

private:
void onEvent(const Json::Value &ev) override;
void doUpdate();
void setClass(const std::string &className, bool enable);

const Bar &bar_;

std::string oldAppId_;
};

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

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

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

namespace waybar::modules::niri {

class Workspaces : public AModule, public EventHandler {
public:
Workspaces(const std::string &, const Bar &, const Json::Value &);
~Workspaces() override;
void update() override;

private:
void onEvent(const Json::Value &ev) override;
void doUpdate();
Gtk::Button &addButton(const Json::Value &ws);
std::string getIcon(const std::string &value, const Json::Value &ws);

const Bar &bar_;
Gtk::Box box_;
// Map from niri workspace id to button.
std::unordered_map<uint64_t, Gtk::Button> buttons_;
};

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

# NAME

waybar - niri language module

# DESCRIPTION

The *language* module displays the currently selected language in niri.

# CONFIGURATION

Addressed by *niri/language*

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

*format-<lang>* ++
typeof: string++
Provide an alternative name to display per language where <lang> is the language of your choosing. Can be passed multiple times with multiple languages as shown by the example below.

*menu*: ++
typeof: string ++
Action that popups the menu.

*menu-file*: ++
typeof: string ++
Location of the menu descriptor file. There need to be an element of type GtkMenu with id *menu*

*menu-actions*: ++
typeof: array ++
The actions corresponding to the buttons of the menu.

# FORMAT REPLACEMENTS

*{short}*: Short name of layout (e.g. "us"). Equals to {}.

*{shortDescription}*: Short description of layout (e.g. "en").

*{long}*: Long name of layout (e.g. "English (Dvorak)").

*{variant}*: Variant of layout (e.g. "dvorak").

# EXAMPLES

```
"niri/language": {
"format": "Lang: {long}"
"format-en": "AMERICA, HELL YEAH!"
"format-tr": "As bayrakları"
}
```

# STYLE

- *#language*
81 changes: 81 additions & 0 deletions man/waybar-niri-window.5.scd
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
waybar-niri-window(5)

# NAME

waybar - niri window module

# DESCRIPTION

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

# CONFIGURATION

Addressed by *niri/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*.

*separate-outputs*: ++
typeof: bool ++
Show the active window of the monitor the bar belongs to, instead of the focused window.

*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.

# FORMAT REPLACEMENTS

See the output of "niri 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

```
"niri/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
97 changes: 97 additions & 0 deletions man/waybar-niri-workspaces.5.scd
Original file line number Diff line number Diff line change
@@ -0,0 +1,97 @@
waybar-niri-workspaces(5)

# NAME

waybar - niri workspaces module

# DESCRIPTION

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

# CONFIGURATION

Addressed by *niri/workspaces*

*all-outputs*: ++
typeof: bool ++
default: false ++
If set to false, workspaces will only be shown on the output they are on. If set to true all workspaces will be shown on every output.

*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.

# FORMAT REPLACEMENTS

*{value}*: Name of the workspace, or index for unnamed workspaces,
as defined by niri.

*{name}*: Name of the workspace for named workspaces.

*{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.
- *active*: Will be shown, when workspace is active on its output.

# EXAMPLES

```
"niri/workspaces": {
"format": "{icon}",
"format-icons": {
// Named workspaces
// (you need to configure them in niri)
"browser": "",
"discord": "",
"chat": "<b></b>",

// Icons by state
"active": "",
"default": ""
}
}
```

# Style

- *#workspaces button*
- *#workspaces button.focused*: The single focused workspace.
- *#workspaces button.active*: The workspace is active (visible) on its output.
- *#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.
- *#workspaces button#niri-workspace-<name>*: Workspaces named this, or index
for unnamed workspaces.
Loading
Loading