Files
Waybar/include/modules/keyboard_state.hpp
Tobias Brox 13469a8847 fix(keyboard-state): fix segfault on device hotplug
The keyboard-state module crashes with SIGSEGV in libinput_device_ref
when a new input device appears in /dev/input/.

Three bugs fixed:

1. Missing NULL check: tryAddDevice() calls libinput_path_add_device()
   which returns NULL on failure, then immediately passes the result to
   libinput_device_ref() without checking.  On laptops, virtual input
   devices (power buttons, lid switch, etc.) appear and disappear in
   /dev/input/ triggering the hotplug handler; if libinput can't open
   one of these, the NULL return causes the segfault.

2. Missing cleanup on device removal: The IN_DELETE handler erased
   devices from the map without calling libinput_path_remove_device(),
   leaving dangling pointers in the libinput context.

3. Thread safety: libinput_devices_ was accessed from 3 threads
   (main/GTK, libinput_thread_, hotplug_thread_) without any mutex.

Fixes #4851

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-12 11:57:23 +01:00

52 lines
1.1 KiB
C++

#pragma once
#include <fmt/chrono.h>
#include <gtkmm/label.h>
#include <mutex>
#include <set>
#include <unordered_map>
#include "AModule.hpp"
#include "bar.hpp"
#include "util/sleeper_thread.hpp"
extern "C" {
#include <libevdev/libevdev.h>
#include <libinput.h>
}
namespace waybar::modules {
class KeyboardState : public AModule {
public:
KeyboardState(const std::string&, const waybar::Bar&, const Json::Value&);
virtual ~KeyboardState();
auto update() -> void override;
private:
auto tryAddDevice(const std::string&) -> void;
Gtk::Box box_;
Gtk::Label numlock_label_;
Gtk::Label capslock_label_;
Gtk::Label scrolllock_label_;
std::string numlock_format_;
std::string capslock_format_;
std::string scrolllock_format_;
const std::chrono::seconds interval_;
std::string icon_locked_;
std::string icon_unlocked_;
std::string devices_path_;
struct libinput* libinput_;
std::unordered_map<std::string, struct libinput_device*> libinput_devices_;
std::mutex devices_mutex_; // protects libinput_devices_
std::set<int> binding_keys;
util::SleeperThread libinput_thread_, hotplug_thread_;
};
} // namespace waybar::modules