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)*
|
||||
|
||||
**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)
|
||||
- Local time
|
||||
- Battery
|
||||
|
|
|
@ -6,6 +6,7 @@
|
|||
#include "modules/sway/mode.hpp"
|
||||
#include "modules/sway/window.hpp"
|
||||
#include "modules/sway/workspaces.hpp"
|
||||
#include "modules/sway/layout.hpp"
|
||||
#endif
|
||||
#ifndef NO_FILESYSTEM
|
||||
#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/mode.cpp',
|
||||
'src/modules/sway/window.cpp',
|
||||
'src/modules/sway/workspaces.cpp'
|
||||
'src/modules/sway/workspaces.cpp',
|
||||
'src/modules/sway/layout.cpp'
|
||||
]
|
||||
endif
|
||||
|
||||
|
|
|
@ -6,7 +6,7 @@
|
|||
// Choose the order of the modules
|
||||
"modules-left": ["sway/workspaces", "sway/mode", "custom/media"],
|
||||
"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
|
||||
// "sway/workspaces": {
|
||||
// "disable-scroll": true,
|
||||
|
@ -26,6 +26,10 @@
|
|||
"sway/mode": {
|
||||
"format": "<span style=\"italic\">{}</span>"
|
||||
},
|
||||
"sway/layout": {
|
||||
"tooltip-format": "{long}",
|
||||
"format": "{short} "
|
||||
},
|
||||
"mpd": {
|
||||
"format": "{stateIcon} {consumeIcon}{randomIcon}{repeatIcon}{singleIcon}{artist} - {album} - {title} ({elapsedTime:%M:%S}/{totalTime:%M:%S}) ",
|
||||
"format-disconnected": "Disconnected ",
|
||||
|
|
|
@ -77,6 +77,7 @@ window#waybar.chromium {
|
|||
#tray,
|
||||
#mode,
|
||||
#idle_inhibitor,
|
||||
#layout,
|
||||
#mpd {
|
||||
padding: 0 10px;
|
||||
margin: 0 4px;
|
||||
|
|
|
@ -22,6 +22,9 @@ waybar::AModule* waybar::Factory::makeModule(const std::string& name) const {
|
|||
if (ref == "sway/window") {
|
||||
return new waybar::modules::sway::Window(id, bar_, config_[name]);
|
||||
}
|
||||
if (ref == "sway/layout") {
|
||||
return new waybar::modules::sway::Layout(id, config_[name]);
|
||||
}
|
||||
#endif
|
||||
if (ref == "idle_inhibitor") {
|
||||
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