Add module for keyboard layout
Update list of modules in README Add layout class to sway modules update default config and stylepull/556/head
parent
b9cd51a9cc
commit
87b56a31cb
|
@ -6,7 +6,7 @@
|
||||||
> *Waybar [examples](https://github.com/Alexays/Waybar/wiki/Examples)*
|
> *Waybar [examples](https://github.com/Alexays/Waybar/wiki/Examples)*
|
||||||
|
|
||||||
**Current features**
|
**Current features**
|
||||||
- Sway (Workspaces, Binding mode, Focused window name)
|
- Sway (Workspaces, Binding mode, Focused window name, Keyboard Layout)
|
||||||
- Tray [#21](https://github.com/Alexays/Waybar/issues/21)
|
- Tray [#21](https://github.com/Alexays/Waybar/issues/21)
|
||||||
- Local time
|
- Local time
|
||||||
- Battery
|
- Battery
|
||||||
|
|
|
@ -6,6 +6,7 @@
|
||||||
#include "modules/sway/mode.hpp"
|
#include "modules/sway/mode.hpp"
|
||||||
#include "modules/sway/window.hpp"
|
#include "modules/sway/window.hpp"
|
||||||
#include "modules/sway/workspaces.hpp"
|
#include "modules/sway/workspaces.hpp"
|
||||||
|
#include "modules/sway/layout.hpp"
|
||||||
#endif
|
#endif
|
||||||
#ifndef NO_FILESYSTEM
|
#ifndef NO_FILESYSTEM
|
||||||
#include "modules/battery.hpp"
|
#include "modules/battery.hpp"
|
||||||
|
|
|
@ -0,0 +1,54 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#ifdef FILESYSTEM_EXPERIMENTAL
|
||||||
|
#include <experimental/filesystem>
|
||||||
|
#else
|
||||||
|
#include <filesystem>
|
||||||
|
#endif
|
||||||
|
#include <fmt/format.h>
|
||||||
|
#include <fstream>
|
||||||
|
#include <regex>
|
||||||
|
#include "ALabel.hpp"
|
||||||
|
#include "bar.hpp"
|
||||||
|
#include "client.hpp"
|
||||||
|
#include "modules/sway/ipc/client.hpp"
|
||||||
|
#include "util/json.hpp"
|
||||||
|
#include "util/sleeper_thread.hpp"
|
||||||
|
|
||||||
|
namespace waybar::modules::sway {
|
||||||
|
|
||||||
|
#ifdef FILESYSTEM_EXPERIMENTAL
|
||||||
|
namespace fs = std::experimental::filesystem;
|
||||||
|
#else
|
||||||
|
namespace fs = std::filesystem;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
class Layout : public ALabel, public sigc::trackable {
|
||||||
|
public:
|
||||||
|
Layout(const std::string&, const Json::Value&);
|
||||||
|
~Layout() = default;
|
||||||
|
auto update() -> void;
|
||||||
|
|
||||||
|
private:
|
||||||
|
static inline const fs::path xbk_file_ = "/usr/share/X11/xkb/rules/evdev.xml";
|
||||||
|
|
||||||
|
void onCmd(const struct Ipc::ipc_response&);
|
||||||
|
void onEvent(const struct Ipc::ipc_response&);
|
||||||
|
void worker();
|
||||||
|
void shortName();
|
||||||
|
inline std::string sanitize(const std::string& text) {
|
||||||
|
std::regex specialChars {R"([-[\]{}()*+?.,\^$|#\s])"};
|
||||||
|
return std::regex_replace(text, specialChars, R"(\$&)");
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string layout_;
|
||||||
|
std::string short_description_;
|
||||||
|
std::string short_variant_;
|
||||||
|
util::JsonParser parser_;
|
||||||
|
std::mutex mutex_;
|
||||||
|
|
||||||
|
util::SleeperThread thread_;
|
||||||
|
Ipc ipc_;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace waybar::modules::sway
|
|
@ -105,7 +105,8 @@ if true # find_program('sway', required : false).found()
|
||||||
'src/modules/sway/ipc/client.cpp',
|
'src/modules/sway/ipc/client.cpp',
|
||||||
'src/modules/sway/mode.cpp',
|
'src/modules/sway/mode.cpp',
|
||||||
'src/modules/sway/window.cpp',
|
'src/modules/sway/window.cpp',
|
||||||
'src/modules/sway/workspaces.cpp'
|
'src/modules/sway/workspaces.cpp',
|
||||||
|
'src/modules/sway/layout.cpp'
|
||||||
]
|
]
|
||||||
endif
|
endif
|
||||||
|
|
||||||
|
|
|
@ -6,7 +6,7 @@
|
||||||
// Choose the order of the modules
|
// Choose the order of the modules
|
||||||
"modules-left": ["sway/workspaces", "sway/mode", "custom/media"],
|
"modules-left": ["sway/workspaces", "sway/mode", "custom/media"],
|
||||||
"modules-center": ["sway/window"],
|
"modules-center": ["sway/window"],
|
||||||
"modules-right": ["mpd", "idle_inhibitor", "pulseaudio", "network", "cpu", "memory", "temperature", "backlight", "battery", "battery#bat2", "clock", "tray"],
|
"modules-right": ["sway/layout", "mpd", "idle_inhibitor", "pulseaudio", "network", "cpu", "memory", "temperature", "backlight", "battery", "battery#bat2", "clock", "tray"],
|
||||||
// Modules configuration
|
// Modules configuration
|
||||||
// "sway/workspaces": {
|
// "sway/workspaces": {
|
||||||
// "disable-scroll": true,
|
// "disable-scroll": true,
|
||||||
|
@ -26,6 +26,10 @@
|
||||||
"sway/mode": {
|
"sway/mode": {
|
||||||
"format": "<span style=\"italic\">{}</span>"
|
"format": "<span style=\"italic\">{}</span>"
|
||||||
},
|
},
|
||||||
|
"sway/layout": {
|
||||||
|
"tooltip-format": "{long}",
|
||||||
|
"format": "{short} "
|
||||||
|
},
|
||||||
"mpd": {
|
"mpd": {
|
||||||
"format": "{stateIcon} {consumeIcon}{randomIcon}{repeatIcon}{singleIcon}{artist} - {album} - {title} ({elapsedTime:%M:%S}/{totalTime:%M:%S}) ",
|
"format": "{stateIcon} {consumeIcon}{randomIcon}{repeatIcon}{singleIcon}{artist} - {album} - {title} ({elapsedTime:%M:%S}/{totalTime:%M:%S}) ",
|
||||||
"format-disconnected": "Disconnected ",
|
"format-disconnected": "Disconnected ",
|
||||||
|
|
|
@ -77,6 +77,7 @@ window#waybar.chromium {
|
||||||
#tray,
|
#tray,
|
||||||
#mode,
|
#mode,
|
||||||
#idle_inhibitor,
|
#idle_inhibitor,
|
||||||
|
#layout,
|
||||||
#mpd {
|
#mpd {
|
||||||
padding: 0 10px;
|
padding: 0 10px;
|
||||||
margin: 0 4px;
|
margin: 0 4px;
|
||||||
|
|
|
@ -22,6 +22,9 @@ waybar::AModule* waybar::Factory::makeModule(const std::string& name) const {
|
||||||
if (ref == "sway/window") {
|
if (ref == "sway/window") {
|
||||||
return new waybar::modules::sway::Window(id, bar_, config_[name]);
|
return new waybar::modules::sway::Window(id, bar_, config_[name]);
|
||||||
}
|
}
|
||||||
|
if (ref == "sway/layout") {
|
||||||
|
return new waybar::modules::sway::Layout(id, config_[name]);
|
||||||
|
}
|
||||||
#endif
|
#endif
|
||||||
if (ref == "idle_inhibitor") {
|
if (ref == "idle_inhibitor") {
|
||||||
return new waybar::modules::IdleInhibitor(id, bar_, config_[name]);
|
return new waybar::modules::IdleInhibitor(id, bar_, config_[name]);
|
||||||
|
|
|
@ -0,0 +1,101 @@
|
||||||
|
#include "modules/sway/layout.hpp"
|
||||||
|
#include <spdlog/spdlog.h>
|
||||||
|
|
||||||
|
namespace waybar::modules::sway {
|
||||||
|
|
||||||
|
Layout::Layout(const std::string& id, const Json::Value& config)
|
||||||
|
: ALabel(config, "layout", id, "{}", 0) {
|
||||||
|
ipc_.subscribe(R"(["input"])");
|
||||||
|
ipc_.signal_event.connect(sigc::mem_fun(*this, &Layout::onEvent));
|
||||||
|
ipc_.signal_cmd.connect(sigc::mem_fun(*this, &Layout::onCmd));
|
||||||
|
ipc_.sendCmd(IPC_GET_INPUTS);
|
||||||
|
shortName();
|
||||||
|
// Launch worker
|
||||||
|
worker();
|
||||||
|
dp.emit();
|
||||||
|
}
|
||||||
|
|
||||||
|
void Layout::onEvent(const struct Ipc::ipc_response& res) {
|
||||||
|
try {
|
||||||
|
std::lock_guard<std::mutex> lock(mutex_);
|
||||||
|
auto payload = parser_.parse(res.payload);
|
||||||
|
if (payload["change"] == "xkb_layout") {
|
||||||
|
layout_ = payload["input"]["xkb_active_layout_name"].asString();
|
||||||
|
}
|
||||||
|
dp.emit();
|
||||||
|
} catch (const std::exception& e) {
|
||||||
|
spdlog::error("Layout: {}", e.what());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Layout::onCmd(const struct Ipc::ipc_response &res) {
|
||||||
|
if (res.type == IPC_GET_INPUTS) {
|
||||||
|
try {
|
||||||
|
std::lock_guard<std::mutex> lock(mutex_);
|
||||||
|
auto payload = parser_.parse(res.payload);
|
||||||
|
for (auto keyboard : payload) {
|
||||||
|
if (keyboard["identifier"] == "1:1:AT_Translated_Set_2_keyboard") {
|
||||||
|
layout_ = keyboard["xkb_active_layout_name"].asString();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
dp.emit();
|
||||||
|
} catch (const std::exception& e) {
|
||||||
|
spdlog::error("Layout: {}", e.what());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Layout::worker() {
|
||||||
|
thread_ = [this] {
|
||||||
|
try {
|
||||||
|
ipc_.handleEvent();
|
||||||
|
} catch (const std::exception& e) {
|
||||||
|
spdlog::error("Layout: {}", e.what());
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
auto Layout::update() -> void {
|
||||||
|
shortName();
|
||||||
|
|
||||||
|
if (layout_.empty()) {
|
||||||
|
event_box_.hide();
|
||||||
|
} else {
|
||||||
|
label_.set_markup(fmt::format(format_,
|
||||||
|
fmt::arg("long", layout_),
|
||||||
|
fmt::arg("short", short_description_),
|
||||||
|
fmt::arg("variant", short_variant_)));
|
||||||
|
if (tooltipEnabled()) {
|
||||||
|
if (config_["tooltip-format"].isString()) {
|
||||||
|
auto tooltip_format = config_["tooltip-format"].asString();
|
||||||
|
label_.set_tooltip_text(fmt::format(tooltip_format,
|
||||||
|
fmt::arg("long", layout_),
|
||||||
|
fmt::arg("short", short_description_),
|
||||||
|
fmt::arg("variant", short_variant_)));
|
||||||
|
} else {
|
||||||
|
label_.set_tooltip_text(layout_);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
event_box_.show();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Layout::shortName() {
|
||||||
|
std::string line;
|
||||||
|
std::ifstream file (xbk_file_);
|
||||||
|
std::regex e1 (".*<shortDescription>(.*)</shortDescription>.*");
|
||||||
|
std::regex e2 (".*<name>(.*)</name>.*");
|
||||||
|
|
||||||
|
while (getline(file,line)) {
|
||||||
|
|
||||||
|
if(std::regex_match(line, e1)) {
|
||||||
|
short_description_ = std::regex_replace(line, e1, "$1");
|
||||||
|
} else if(std::regex_match(line, e2)) {
|
||||||
|
short_variant_ = std::regex_replace(line, e2, "$1");
|
||||||
|
} else if(std::regex_match(line, std::regex(".*<description>"+sanitize(layout_)+"</description>.*"))){
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace waybar::modules::sway
|
Loading…
Reference in New Issue