diff --git a/xdg/xinput_devnodes/Makefile b/xdg/xinput_devnodes/Makefile deleted file mode 100644 index a806a65..0000000 --- a/xdg/xinput_devnodes/Makefile +++ /dev/null @@ -1,5 +0,0 @@ -main: main.c - $(CC) -O2 --std=gnu99 -pedantic -Wall main.c xslaves.c devnodes.c -o devnodes -lX11 -lXi -clean: - rm -f devnodes - diff --git a/xdg/xinput_devnodes/devnodes.c b/xdg/xinput_devnodes/devnodes.c index 9a1948b..f40e46f 100644 --- a/xdg/xinput_devnodes/devnodes.c +++ b/xdg/xinput_devnodes/devnodes.c @@ -1,13 +1,11 @@ /* - * Loosely based on a mix of: - * - xorg-xinput - * https://github.com/freedesktop/xorg-xinput/blob/master/src/property.c::print_property_xi2 - * - xkbcat - * https://github.com/anko/xkbcat +* Loosely based on a mix of: +* - xorg-xinput +* https://github.com/freedesktop/xorg-xinput/blob/master/src/property.c::print_property_xi2 +* - xkbcat +* https://github.com/anko/xkbcat */ -#define _GNU_SOURCE - #include "devnodes.h" #include @@ -18,6 +16,7 @@ #include #include +#include char* get_property_xi2(Display* dpy, int deviceid, Atom property, const char* property_name) @@ -93,8 +92,8 @@ XSlaves* build_slave_info(Display* disp) char* devnode = get_property_xi2(disp, current_slave->deviceid, props[nprops], "Device Node"); if (current_slave->name != NULL && devnode != NULL) { - int success = add_slaveinfo(slaves, current_slave->name, devnode); - if (success != 0) + int err = add_slaveinfo(slaves, current_slave->name, devnode); + if (err) fail = true; } free(devnode); @@ -103,6 +102,7 @@ XSlaves* build_slave_info(Display* disp) if (fail) { free_xslaves(slaves); + slaves = NULL; break; } @@ -116,73 +116,48 @@ int is_xinput2_available(Display* disp) int xiOpcode; int queryEvent, queryError; if (! XQueryExtension(disp, "XInputExtension", &xiOpcode, &queryEvent, &queryError)) - { - fprintf(stderr, "XInput extension not available\n"); - return -1; - } + return XINPUTEXTUNAVAIL; int major = 2, minor = 0; int queryResult = XIQueryVersion(disp, &major, &minor); if (queryResult == BadRequest) - { - fprintf(stderr, "XInput 2.0 support required (got %d.%d)\n", major, minor); - return -2; - } + return XINPUT20UNAVAIL; else if (queryResult != Success) - { - fprintf(stderr, "XIQueryVersion failed\n"); - return -3; - } + return XINPUTQUERYVERSIONFAILED; return 0; } -Display* connect_to_x(const char* xDisplayName) +Display* connect_to_x(const char* xDisplayName, int* error) { Display* disp = XOpenDisplay(xDisplayName); - if (NULL == disp) + if (disp == NULL) { - fprintf(stderr, "Cannot open X display '%s'\n", xDisplayName); + *error = BADDISPLAY; return NULL; } - if (is_xinput2_available(disp) != 0) + int err = is_xinput2_available(disp); + if (err) { XCloseDisplay(disp); + *error = err; return NULL; } return disp; } -XSlaves* get_slave_info() +XSlaves* get_slave_info(const char* xDisplayName, int* error) { - char* xDisplayName = getenv("DISPLAY"); - if (xDisplayName == NULL) - { - fprintf(stderr, "DISPLAY environment variable not found\n"); - exit(1); - } - - Display* disp = connect_to_x(xDisplayName); - if (disp == NULL) - exit(1); + Display* disp = connect_to_x(xDisplayName, error); + if (*error) + return NULL; XSlaves* s = build_slave_info(disp); + if (s == NULL) + *error = XSLAVEINFOQUERYFAILED; + XCloseDisplay(disp); return s; } - - -// int main(int argc, char * argv[]) -// { -// XSlaves* s = get_slave_info(); -// for (int i = 0; i < s->length; i++) -// { -// XSlaveInfo si = s->slaves[i]; -// printf("Name: %s\n", si.name); -// printf("Node: %s\n", si.dev_node); -// printf("\n"); -// } -// free_xslaves(s); -// } diff --git a/xdg/xinput_devnodes/devnodes.h b/xdg/xinput_devnodes/devnodes.h index 8cde8aa..21eaa3a 100644 --- a/xdg/xinput_devnodes/devnodes.h +++ b/xdg/xinput_devnodes/devnodes.h @@ -3,4 +3,11 @@ #include "xslaves.h" -XSlaves* get_slave_info(); +#define BADDISPLAY -3 +#define XINPUTEXTUNAVAIL -4 +#define XINPUT20UNAVAIL -5 +#define XINPUTQUERYVERSIONFAILED -6 +#define XSLAVEINFOQUERYFAILED -7 + + +XSlaves* get_slave_info(const char* xDisplayName, int* error); diff --git a/xdg/xinput_devnodes/main.c b/xdg/xinput_devnodes/main.c deleted file mode 100644 index d70ebb8..0000000 --- a/xdg/xinput_devnodes/main.c +++ /dev/null @@ -1,16 +0,0 @@ -#include "devnodes.h" -#include "xslaves.h" - -#include - - -int main(int argc, char** argv) { - XSlaves* xs = get_slave_info(); - for (int i=0; i < xs->length; i++) - { - XSlaveInfo si = xs->slaves[i]; - printf("%s = %s\n", si.name, si.dev_node); - } - - free_xslaves(xs); -} diff --git a/xdg/xinput_devnodes/xinput_devnodes.go b/xdg/xinput_devnodes/xinput_devnodes.go index 3bad466..a82402b 100644 --- a/xdg/xinput_devnodes/xinput_devnodes.go +++ b/xdg/xinput_devnodes/xinput_devnodes.go @@ -10,6 +10,8 @@ import ( "fmt" "unsafe" "regexp" + "errors" + "os" ) @@ -39,7 +41,15 @@ func Print() { func GetXSlaveInfo() ([]C.XSlaveInfo, func()) { - xslaves := C.get_slave_info() + xDisplayName := C.CString(tryGetXDisplay()) + defer C.free(unsafe.Pointer(xDisplayName)) + + var error C.int + xslaves := C.get_slave_info(xDisplayName, &error) + if (error != C.int(0)) { + panic(convertErrorIntToGoError(error)) + } + arr := (*[1 << 30]C.XSlaveInfo)(unsafe.Pointer(xslaves.slaves)) slice := arr[:xslaves.length:xslaves.length] freeMethod := func() { @@ -49,3 +59,33 @@ func GetXSlaveInfo() ([]C.XSlaveInfo, func()) { return slice, freeMethod } +func tryGetXDisplay() string { + display := os.Getenv("DISPLAY") + if display == "" { + panic(errors.New("DISPLAY envvar not set")) + } + return display +} + +func convertErrorIntToGoError(err C.int) error { + errorMsg := "" + switch err { + case C.MALLOCFAIL: + errorMsg = "Memory allocation failed" + case C.XSLAVESFULL: + errorMsg = "XSlaves full" + case C.BADDISPLAY: + errorMsg = "Failed to open X display" + case C.XINPUTEXTUNAVAIL: + errorMsg = "XInput extension unavailable" + case C.XINPUT20UNAVAIL: + errorMsg = "XInput extension is not 2.0" + case C.XINPUTQUERYVERSIONFAILED: + errorMsg = "Failed to query XInput extension version" + case C.XSLAVEINFOQUERYFAILED: + errorMsg = "Failed to query XInput slaves" + default: + errorMsg = fmt.Sprintf("Unknown error from devnodes.h: %v", err) + } + return errors.New(errorMsg) +} diff --git a/xdg/xinput_devnodes/xslaves.c b/xdg/xinput_devnodes/xslaves.c index a833332..c6f2cb0 100644 --- a/xdg/xinput_devnodes/xslaves.c +++ b/xdg/xinput_devnodes/xslaves.c @@ -45,11 +45,18 @@ int add_slaveinfo(XSlaves* slaves, char* name, char* dev_node) XSlaveInfo si = new_slave_info(); si.name = strdup(name); si.dev_node = strdup(dev_node); + if (si.name == NULL || si.dev_node == NULL) + { + free(si.name); + free(si.dev_node); + return MALLOCFAIL; + } + if (slaves->length < slaves->capacity) { slaves->slaves[slaves->length] = si; slaves->length++; return 0; } - return -1; + return XSLAVESFULL; } diff --git a/xdg/xinput_devnodes/xslaves.h b/xdg/xinput_devnodes/xslaves.h index 7075bd6..6bcc0ec 100644 --- a/xdg/xinput_devnodes/xslaves.h +++ b/xdg/xinput_devnodes/xslaves.h @@ -3,6 +3,10 @@ #include +#define MALLOCFAIL -1 +#define XSLAVESFULL -2 + + typedef struct XSlaveInfo { char* name;