Skip to content

Commit

Permalink
modules: Keyboard Layout
Browse files Browse the repository at this point in the history
This patch adds a new module to show the current keyboard layout.

Signed-off-by: Harish Krupo <harishkrupo@gmail.com>
  • Loading branch information
harishkrupo committed Nov 7, 2018
1 parent 5930a8e commit bee1a34
Show file tree
Hide file tree
Showing 11 changed files with 177 additions and 2 deletions.
2 changes: 2 additions & 0 deletions include/IModule.hpp
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
#pragma once

#include <gtkmm.h>
#include <wayland-client.h>

namespace waybar {

Expand All @@ -9,6 +10,7 @@ class IModule {
virtual ~IModule() = default;
virtual auto update() -> void = 0;
virtual operator Gtk::Widget &() = 0;
virtual void handleSeat(struct wl_seat*, uint32_t) {};
Glib::Dispatcher dp; // Hmmm Maybe I should create an abstract class ?
};

Expand Down
1 change: 1 addition & 0 deletions include/bar.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ class Bar {
Bar(const Bar&) = delete;

auto toggle() -> void;
void handleSeat(struct wl_seat*, uint32_t);

const Client& client;
Gtk::Window window;
Expand Down
2 changes: 2 additions & 0 deletions include/client.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,8 @@ class Client {
uint32_t name, const char *interface, uint32_t version);
static void handleGlobalRemove(void *data,
struct wl_registry *registry, uint32_t name);
static void seatName(void *data, struct wl_seat *wl_seat, const char *name) {}
static void seatCapabilities(void *data, struct wl_seat *wl_seat, uint32_t caps);
};

}
1 change: 1 addition & 0 deletions include/factory.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
#ifdef HAVE_LIBPULSE
#include "modules/pulseaudio.hpp"
#endif
#include "modules/kbdlayout.hpp"
#include "modules/custom.hpp"

namespace waybar {
Expand Down
44 changes: 44 additions & 0 deletions include/modules/kbdlayout.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
#pragma once

#include <fmt/format.h>
#include <algorithm>
#include "ALabel.hpp"
#include <xkbcommon/xkbcommon.h>
#include <wayland-client.h>
#include <sys/mman.h>

namespace waybar::modules {

class KbdLayout : public ALabel {
public:
KbdLayout(const Json::Value&);
~KbdLayout();
auto update() -> void;
void handleSeat(struct wl_seat* seat, uint32_t caps);
struct wl_keyboard *wl_kbd_ = nullptr;
struct xkb_context *xkb_ctx_ = nullptr;
struct xkb_keymap *keymap_ = nullptr;
struct xkb_state *xkb_state_ = nullptr;
uint32_t current_group_ = 0;

private:

static void kbdKeymap(void *data, struct wl_keyboard *wl_kbd, uint32_t format,
int fd, uint32_t size);
static void kbdEnter(void *data, struct wl_keyboard *wl_kbd, uint32_t serial,
struct wl_surface *surf, struct wl_array *keys) {}
static void kbdLeave(void *data, struct wl_keyboard *wl_kbd, uint32_t serial, struct wl_surface *surf) {}

static void kbdKey(void *data, struct wl_keyboard *wl_kbd, uint32_t serial, uint32_t time,
uint32_t key, uint32_t state) {}

static void kbdModifiers(void *data, struct wl_keyboard *wl_kbd, uint32_t serial,
uint32_t mods_depressed, uint32_t mods_latched,
uint32_t mods_locked, uint32_t group);

static void kbdRepeatInfo(void *data, struct wl_keyboard *wl_kbd, int32_t rate,
int32_t delay) {}
std::string layout_ = "EN";
};

} // namespace waybar::modules
5 changes: 4 additions & 1 deletion meson.build
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ sigcpp = dependency('sigc++-2.0')
libnl = dependency('libnl-3.0', required: get_option('libnl'))
libnlgen = dependency('libnl-genl-3.0', required: get_option('libnl'))
libpulse = dependency('libpulse', required: get_option('pulseaudio'))
xkbcommon = dependency('xkbcommon')

src_files = files(
'src/factory.cpp',
Expand All @@ -48,6 +49,7 @@ src_files = files(
'src/modules/clock.cpp',
'src/modules/custom.cpp',
'src/modules/cpu.cpp',
'src/modules/kbdlayout.cpp',
'src/main.cpp',
'src/bar.cpp',
'src/client.cpp'
Expand Down Expand Up @@ -109,7 +111,8 @@ executable(
giounix,
libnl,
libnlgen,
libpulse
libpulse,
xkbcommon
],
include_directories: [include_directories('include')],
install: true,
Expand Down
7 changes: 6 additions & 1 deletion resources/style.css
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ window#waybar {
border-bottom: 3px solid white;
}

#clock, #battery, #cpu, #memory, #network, #pulseaudio, #custom-spotify, #tray, #mode {
#clock, #battery, #cpu, #memory, #network, #pulseaudio, #custom-spotify, #tray, #mode, kbdlayout {
padding: 0 10px;
margin: 0 5px;
}
Expand Down Expand Up @@ -100,3 +100,8 @@ window#waybar {
#tray {
background-color: #2980b9;
}

#kbdlayout {
background: #1f4d96;
color: white;
}
15 changes: 15 additions & 0 deletions src/bar.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -144,6 +144,21 @@ auto waybar::Bar::toggle() -> void
wl_surface_commit(surface);
}

void waybar::Bar::handleSeat(struct wl_seat* seat, uint32_t caps) {
zwlr_layer_surface_v1_get_keyboard_modifiers(layer_surface, 1, seat);
wl_surface_commit(surface);

for (auto it = modules_left_.begin(); it != modules_left_.end(); ++it) {
(*it)->handleSeat(seat, caps);
}
for (auto it = modules_center_.begin(); it != modules_center_.end(); ++it) {
(*it)->handleSeat(seat, caps);
}
for (auto it = modules_right_.begin(); it != modules_right_.end(); ++it) {
(*it)->handleSeat(seat, caps);
}
}

auto waybar::Bar::setupConfig() -> void
{
std::ifstream file(client.config_file);
Expand Down
12 changes: 12 additions & 0 deletions src/client.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,13 @@ waybar::Client::Client(int argc, char* argv[])

}

void waybar::Client::seatCapabilities(void *data, struct wl_seat *wl_seat, uint32_t caps) {
auto o = static_cast<waybar::Client *>(data);
for (auto it = o->bars.begin(); it != o->bars.end(); ++it) {
(*it)->handleSeat(wl_seat, caps);
}
}

void waybar::Client::handleGlobal(void *data, struct wl_registry *registry,
uint32_t name, const char *interface, uint32_t version)
{
Expand All @@ -58,8 +65,13 @@ void waybar::Client::handleGlobal(void *data, struct wl_registry *registry,
o->bars.emplace_back(std::make_unique<Bar>(*o, std::move(output), name));
}
} else if (strcmp(interface, wl_seat_interface.name) == 0) {
static const struct wl_seat_listener seat_listener = {
seatCapabilities,
seatName
};
o->seat = static_cast<struct wl_seat *>(wl_registry_bind(registry, name,
&wl_seat_interface, version));
wl_seat_add_listener(o->seat, &seat_listener, o);
} else if (strcmp(interface, zxdg_output_manager_v1_interface.name) == 0
&& version >= ZXDG_OUTPUT_V1_NAME_SINCE_VERSION) {
o->xdg_output_manager = static_cast<struct zxdg_output_manager_v1 *>(
Expand Down
3 changes: 3 additions & 0 deletions src/factory.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,9 @@ waybar::IModule* waybar::Factory::makeModule(const std::string &name) const
return new waybar::modules::Pulseaudio(config_[name]);
}
#endif
if (ref == "kbdlayout") {
return new waybar::modules::KbdLayout(config_[name]);
}
if (ref.compare(0, 7, "custom/") == 0 && ref.size() > 7) {
return new waybar::modules::Custom(ref.substr(7), config_[name]);
}
Expand Down
87 changes: 87 additions & 0 deletions src/modules/kbdlayout.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
#include "modules/kbdlayout.hpp"

waybar::modules::KbdLayout::KbdLayout(const Json::Value &config)
: ALabel(config, "{layout}"), current_group_(0) {
label_.set_name("kbdlayout");
enum xkb_context_flags ctx_flags = static_cast<enum xkb_context_flags>(XKB_CONTEXT_NO_DEFAULT_INCLUDES | XKB_CONTEXT_NO_ENVIRONMENT_NAMES);
xkb_ctx_ = xkb_context_new(ctx_flags);
}

waybar::modules::KbdLayout::~KbdLayout() {
xkb_context_unref(xkb_ctx_);
}

void waybar::modules::KbdLayout::handleSeat(struct wl_seat* seat, uint32_t caps) {
static const struct wl_keyboard_listener kbd_listener = {
kbdKeymap,
kbdEnter,
kbdLeave,
kbdKey,
kbdModifiers,
kbdRepeatInfo
};

if (!wl_kbd_ && (caps & WL_SEAT_CAPABILITY_KEYBOARD)) {
wl_kbd_ = wl_seat_get_keyboard(seat);
wl_keyboard_add_listener(wl_kbd_, &kbd_listener, this);
} else if (wl_kbd_ && !(caps & WL_SEAT_CAPABILITY_KEYBOARD)) {
wl_keyboard_destroy(wl_kbd_);
wl_kbd_ = NULL;
xkb_keymap_unref(keymap_);
keymap_ = NULL;
}
}

auto waybar::modules::KbdLayout::update() -> void
{
auto format = format_;

xkb_keycode_t keycode = 38;
xkb_layout_index_t layout = xkb_state_key_get_layout(xkb_state_, keycode);
layout_ = xkb_keymap_layout_get_name(keymap_, layout);

label_.set_label(fmt::format(format, fmt::arg("layout", layout_)));
}

void waybar::modules::KbdLayout::kbdKeymap(void *data, struct wl_keyboard *wl_kbd, uint32_t format, int fd, uint32_t size) {
auto o = static_cast<waybar::modules::KbdLayout *>(data);
void *buf;

buf = mmap(NULL, size, PROT_READ, MAP_PRIVATE, fd, 0);
if (buf == MAP_FAILED) {
printf("Failed to mmap keymap: %d\n", errno);
close(fd);
return;
}

o->keymap_ = xkb_keymap_new_from_buffer(o->xkb_ctx_, static_cast<const char*>(buf), size - 1,
XKB_KEYMAP_FORMAT_TEXT_V1, static_cast<enum xkb_keymap_compile_flags>(0));
munmap(buf, size);
close(fd);
if (!o->keymap_) {
printf("Failed to compile keymap!\n");
return;
}

o->xkb_state_ = xkb_state_new(o->keymap_);
if (!o->xkb_state_) {
printf("Failed to create XKB state!\n");
return;
}

o->dp.emit();
}

void waybar::modules::KbdLayout::kbdModifiers(void *data, struct wl_keyboard *wl_kbd, uint32_t serial,
uint32_t mods_depressed, uint32_t mods_latched,
uint32_t mods_locked, uint32_t group) {

auto o = static_cast<waybar::modules::KbdLayout *>(data);

xkb_state_update_mask(o->xkb_state_, mods_depressed, mods_latched,
mods_locked, 0, 0, group);
if (o->current_group_ != group) {
o->current_group_ = group;
o->dp.emit();
}
}

0 comments on commit bee1a34

Please sign in to comment.