Improve XLib-XInput error handling
This commit is contained in:
parent
56b65b8449
commit
00bacdec3e
@ -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
|
|
||||||
|
|
@ -6,8 +6,6 @@
|
|||||||
* https://github.com/anko/xkbcat
|
* https://github.com/anko/xkbcat
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#define _GNU_SOURCE
|
|
||||||
|
|
||||||
#include "devnodes.h"
|
#include "devnodes.h"
|
||||||
|
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
@ -18,6 +16,7 @@
|
|||||||
|
|
||||||
#include <X11/extensions/XInput2.h>
|
#include <X11/extensions/XInput2.h>
|
||||||
#include <X11/Xatom.h>
|
#include <X11/Xatom.h>
|
||||||
|
#include <X11/Xlib.h>
|
||||||
|
|
||||||
|
|
||||||
char* get_property_xi2(Display* dpy, int deviceid, Atom property, const char* property_name)
|
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");
|
char* devnode = get_property_xi2(disp, current_slave->deviceid, props[nprops], "Device Node");
|
||||||
if (current_slave->name != NULL && devnode != NULL)
|
if (current_slave->name != NULL && devnode != NULL)
|
||||||
{
|
{
|
||||||
int success = add_slaveinfo(slaves, current_slave->name, devnode);
|
int err = add_slaveinfo(slaves, current_slave->name, devnode);
|
||||||
if (success != 0)
|
if (err)
|
||||||
fail = true;
|
fail = true;
|
||||||
}
|
}
|
||||||
free(devnode);
|
free(devnode);
|
||||||
@ -103,6 +102,7 @@ XSlaves* build_slave_info(Display* disp)
|
|||||||
if (fail)
|
if (fail)
|
||||||
{
|
{
|
||||||
free_xslaves(slaves);
|
free_xslaves(slaves);
|
||||||
|
slaves = NULL;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -116,73 +116,48 @@ int is_xinput2_available(Display* disp)
|
|||||||
int xiOpcode;
|
int xiOpcode;
|
||||||
int queryEvent, queryError;
|
int queryEvent, queryError;
|
||||||
if (! XQueryExtension(disp, "XInputExtension", &xiOpcode, &queryEvent, &queryError))
|
if (! XQueryExtension(disp, "XInputExtension", &xiOpcode, &queryEvent, &queryError))
|
||||||
{
|
return XINPUTEXTUNAVAIL;
|
||||||
fprintf(stderr, "XInput extension not available\n");
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
int major = 2, minor = 0;
|
int major = 2, minor = 0;
|
||||||
int queryResult = XIQueryVersion(disp, &major, &minor);
|
int queryResult = XIQueryVersion(disp, &major, &minor);
|
||||||
if (queryResult == BadRequest)
|
if (queryResult == BadRequest)
|
||||||
{
|
return XINPUT20UNAVAIL;
|
||||||
fprintf(stderr, "XInput 2.0 support required (got %d.%d)\n", major, minor);
|
|
||||||
return -2;
|
|
||||||
}
|
|
||||||
else if (queryResult != Success)
|
else if (queryResult != Success)
|
||||||
{
|
return XINPUTQUERYVERSIONFAILED;
|
||||||
fprintf(stderr, "XIQueryVersion failed\n");
|
|
||||||
return -3;
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
Display* connect_to_x(const char* xDisplayName)
|
Display* connect_to_x(const char* xDisplayName, int* error)
|
||||||
{
|
{
|
||||||
Display* disp = XOpenDisplay(xDisplayName);
|
Display* disp = XOpenDisplay(xDisplayName);
|
||||||
if (NULL == disp)
|
if (disp == NULL)
|
||||||
{
|
{
|
||||||
fprintf(stderr, "Cannot open X display '%s'\n", xDisplayName);
|
*error = BADDISPLAY;
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (is_xinput2_available(disp) != 0)
|
int err = is_xinput2_available(disp);
|
||||||
|
if (err)
|
||||||
{
|
{
|
||||||
XCloseDisplay(disp);
|
XCloseDisplay(disp);
|
||||||
|
*error = err;
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
return disp;
|
return disp;
|
||||||
}
|
}
|
||||||
|
|
||||||
XSlaves* get_slave_info()
|
XSlaves* get_slave_info(const char* xDisplayName, int* error)
|
||||||
{
|
{
|
||||||
char* xDisplayName = getenv("DISPLAY");
|
Display* disp = connect_to_x(xDisplayName, error);
|
||||||
if (xDisplayName == NULL)
|
if (*error)
|
||||||
{
|
return NULL;
|
||||||
fprintf(stderr, "DISPLAY environment variable not found\n");
|
|
||||||
exit(1);
|
|
||||||
}
|
|
||||||
|
|
||||||
Display* disp = connect_to_x(xDisplayName);
|
|
||||||
if (disp == NULL)
|
|
||||||
exit(1);
|
|
||||||
|
|
||||||
XSlaves* s = build_slave_info(disp);
|
XSlaves* s = build_slave_info(disp);
|
||||||
|
if (s == NULL)
|
||||||
|
*error = XSLAVEINFOQUERYFAILED;
|
||||||
|
|
||||||
XCloseDisplay(disp);
|
XCloseDisplay(disp);
|
||||||
return s;
|
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);
|
|
||||||
// }
|
|
||||||
|
@ -3,4 +3,11 @@
|
|||||||
#include "xslaves.h"
|
#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);
|
||||||
|
@ -1,16 +0,0 @@
|
|||||||
#include "devnodes.h"
|
|
||||||
#include "xslaves.h"
|
|
||||||
|
|
||||||
#include <stdio.h>
|
|
||||||
|
|
||||||
|
|
||||||
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);
|
|
||||||
}
|
|
@ -10,6 +10,8 @@ import (
|
|||||||
"fmt"
|
"fmt"
|
||||||
"unsafe"
|
"unsafe"
|
||||||
"regexp"
|
"regexp"
|
||||||
|
"errors"
|
||||||
|
"os"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
@ -39,7 +41,15 @@ func Print() {
|
|||||||
|
|
||||||
|
|
||||||
func GetXSlaveInfo() ([]C.XSlaveInfo, func()) {
|
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))
|
arr := (*[1 << 30]C.XSlaveInfo)(unsafe.Pointer(xslaves.slaves))
|
||||||
slice := arr[:xslaves.length:xslaves.length]
|
slice := arr[:xslaves.length:xslaves.length]
|
||||||
freeMethod := func() {
|
freeMethod := func() {
|
||||||
@ -49,3 +59,33 @@ func GetXSlaveInfo() ([]C.XSlaveInfo, func()) {
|
|||||||
return slice, freeMethod
|
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)
|
||||||
|
}
|
||||||
|
@ -45,11 +45,18 @@ int add_slaveinfo(XSlaves* slaves, char* name, char* dev_node)
|
|||||||
XSlaveInfo si = new_slave_info();
|
XSlaveInfo si = new_slave_info();
|
||||||
si.name = strdup(name);
|
si.name = strdup(name);
|
||||||
si.dev_node = strdup(dev_node);
|
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)
|
if (slaves->length < slaves->capacity)
|
||||||
{
|
{
|
||||||
slaves->slaves[slaves->length] = si;
|
slaves->slaves[slaves->length] = si;
|
||||||
slaves->length++;
|
slaves->length++;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
return -1;
|
return XSLAVESFULL;
|
||||||
}
|
}
|
||||||
|
@ -3,6 +3,10 @@
|
|||||||
#include <stddef.h>
|
#include <stddef.h>
|
||||||
|
|
||||||
|
|
||||||
|
#define MALLOCFAIL -1
|
||||||
|
#define XSLAVESFULL -2
|
||||||
|
|
||||||
|
|
||||||
typedef struct XSlaveInfo
|
typedef struct XSlaveInfo
|
||||||
{
|
{
|
||||||
char* name;
|
char* name;
|
||||||
|
Loading…
Reference in New Issue
Block a user