feat: add xorg backend (#1)

* Xorg backend

* Xorg backend hotfix

* xorg.c: issues fixed; ukb.c: xorg backend added

* \t replacement

* ukb.c fromatting improved

* ukb.c typo fix

* fix: include order

---------

Co-authored-by: mrsobakin <68982655+mrsobakin@users.noreply.github.com>
This commit is contained in:
zxcry 2025-04-08 18:06:01 +03:00 committed by GitHub
parent 9b34bfc435
commit 4bbcfb2f10
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
2 changed files with 126 additions and 1 deletions

124
src/backends/xorg.c Normal file
View file

@ -0,0 +1,124 @@
#include <stdbool.h>
#include <string.h>
#include <X11/XKBlib.h>
#include <X11/Xlib.h>
#include "ukb.h"
#include "../utils.h"
static char current_layout[128] = {0};
static Display *x_display = 0;
static ukb_err_t update_current_layout() {
XkbStateRec xkb_state;
if (XkbGetState(x_display, XkbUseCoreKbd, &xkb_state) != Success) {
UKB_ERR("Failed to get keyboard state.");
}
XkbDescPtr desc_ptr = XkbGetKeyboard(x_display, XkbAllComponentsMask, XkbUseCoreKbd);
if (!desc_ptr) {
UKB_ERR("Failed to get keyboard description.");
}
if (!desc_ptr->names) {
UKB_ERR("Failed to get keyboard names.");
}
Status error_get_controls = XkbGetControls(x_display, XkbAllComponentsMask, desc_ptr);
if (error_get_controls != Success || !desc_ptr->ctrls) {
UKB_ERR("Failed to get keyboard controls.");
}
int num_groups = desc_ptr->ctrls->num_groups;
if (xkbState.group >= num_groups) {
UKB_ERR("Group index out of range.");
}
char *name_ptr = XGetAtomName(x_display, desc_ptr->names->groups[xkb_state.group]);
if (!name_ptr) {
UKB_ERR("Failed to get group name.");
}
if (strncmp(current_layout, name_ptr, sizeof(current_layout)) != 0) {
strncpy(current_layout, name_ptr, sizeof(current_layout) - 1);
}
XkbFreeKeyboard(desc_ptr, 0, True);
XFree(name_ptr);
UKB_OK();
}
static ukb_err_t xorg_wait_event() {
Bool bret = XkbSelectEventDetails(x_display, XkbUseCoreKbd, XkbStateNotify, XkbAllStateComponentsMask, XkbGroupStateMask);
if (!bret) {
UKB_ERR("XkbSelectEventDetails failed")
}
XEvent event;
int iret = XNextEvent(x_display, &event);
if (!iret) {
UKB_ERR("XNextEvent failed");
}
UKB_OK();
}
static ukb_err_t xorg_listen_loop(ukb_layout_cb_t cb) {
while(1) {
UKB_PROPAGATE(xorg_wait_event());
UKB_PROPAGATE(update_current_layout());
cb(current_layout);
}
UKB_OK();
}
static int xorg_open_display() {
int event_code;
int error_return;
int major = XkbMajorVersion;
int minor = XkbMinorVersion;
int reason_return;
x_display = XkbOpenDisplay(NULL, &event_code, &error_return, &major, &minor, &reason_return);
return reason_return;
}
/********************************* BACKEND ***********************************/
static bool xorg_can_use(void) {
int reason_return = xorg_open_display();
XCloseDisplay(x_display);
return reason_return == XkbOD_Success;
}
static ukb_err_t xorg_listen(ukb_layout_cb_t cb) {
int reason_return = xorg_open_display();
switch (reason_return) {
case XkbOD_Success:
break;
case XkbOD_BadLibraryVersion:
UKB_ERR("Bad XKB library version.");
case XkbOD_ConnectionRefused:
UKB_ERR("Connection to X server refused.");
case XkbOD_BadServerVersion:
UKB_ERR("Bad X11 server version.");
case XkbOD_NonXkbServer:
UKB_ERR("XKB not present.");
default:
UKB_ERR("XKB refused to open the display.");
}
ukb_err_t err = xorg_listen_loop(cb);
XCloseDisplay(x_display);
return err;
}
const ukb_backend_t ukb_backend_xorg = {
.name = "xorg",
.can_use = xorg_can_use,
.listen = xorg_listen,
};

View file

@ -12,7 +12,8 @@
/********************************* BACKENDS **********************************/
#define UKB_BACKENDS(M) \
M(ukb_backend_sway)
M(ukb_backend_sway) \
M(ukb_backend_xorg)
/*****************************************************************************/