Improve hacky XLib code
This commit is contained in:
parent
bae3b95b6c
commit
86ed0f7989
@ -1,5 +1,5 @@
|
|||||||
get-x-slave-devnodes: get-x-slave-devnodes.c
|
get-x-slave-devnodes: get-x-slave-devnodes.c
|
||||||
$(CC) -O2 --std=c99 -pedantic -Wall get-x-slave-devnodes.c -o get-x-slave-devnodes -lX11 -lXi
|
$(CC) -O2 --std=gnu99 -pedantic -Wall get-x-slave-devnodes.c -o get-x-slave-devnodes -lX11 -lXi
|
||||||
clean:
|
clean:
|
||||||
rm -f get-x-slave-devnodes
|
rm -f get-x-slave-devnodes
|
||||||
|
|
||||||
|
@ -6,6 +6,8 @@
|
|||||||
* https://github.com/anko/xkbcat
|
* https://github.com/anko/xkbcat
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
#define _GNU_SOURCE
|
||||||
|
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
@ -28,7 +30,7 @@ char* get_property_xi2(Display* dpy, int deviceid, Atom property, const char* pr
|
|||||||
char* ret = NULL;
|
char* ret = NULL;
|
||||||
|
|
||||||
name = XGetAtomName(dpy, property);
|
name = XGetAtomName(dpy, property);
|
||||||
int interested_in_property = (strcmp(name, property_name) == 0);
|
bool interested_in_property = (strcmp(name, property_name) == 0);
|
||||||
XFree(name);
|
XFree(name);
|
||||||
if (!interested_in_property)
|
if (!interested_in_property)
|
||||||
return ret;
|
return ret;
|
||||||
@ -51,22 +53,18 @@ char* get_property_xi2(Display* dpy, int deviceid, Atom property, const char* pr
|
|||||||
}
|
}
|
||||||
|
|
||||||
int len = strlen((char*)ptr);
|
int len = strlen((char*)ptr);
|
||||||
ret = (char*)malloc(len+1);
|
ret = strdup((const char*)ptr);
|
||||||
strcpy(ret, (const char*)ptr);
|
|
||||||
|
|
||||||
j += len; /* The loop's j++ jumps over the
|
j += len; // The loop's j++ jumps over the terminating 0
|
||||||
terminating 0 */
|
ptr += len; // ptr += size below jumps over the terminating 0
|
||||||
ptr += len; /* ptr += size below jumps over
|
|
||||||
the terminating 0 */
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
// Unknown type
|
// Unknown type
|
||||||
done = True;
|
done = True;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
ptr += act_format/8;
|
ptr += act_format/8;
|
||||||
|
|
||||||
if (done == True)
|
if (done == True)
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -75,65 +73,145 @@ char* get_property_xi2(Display* dpy, int deviceid, Atom property, const char* pr
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int is_xinput2_available(Display* disp)
|
||||||
void assert_xinput2(Display* disp)
|
|
||||||
{
|
{
|
||||||
int xiOpcode;
|
int xiOpcode;
|
||||||
{ // Test for XInput 2 extension
|
int queryEvent, queryError;
|
||||||
int queryEvent, queryError;
|
if (! XQueryExtension(disp, "XInputExtension", &xiOpcode, &queryEvent, &queryError))
|
||||||
if (! XQueryExtension(disp, "XInputExtension", &xiOpcode, &queryEvent, &queryError))
|
{
|
||||||
{
|
fprintf(stderr, "XInput extension not available\n");
|
||||||
fprintf(stderr, "X Input extension not available\n");
|
return -1;
|
||||||
exit(2);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
{ // Request XInput 2.0, to guard against changes in future versions
|
|
||||||
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)
|
||||||
{
|
{
|
||||||
fprintf(stderr, "Need XI 2.0 support (got %d.%d)\n", major, minor);
|
fprintf(stderr, "XInput 2.0 support required (got %d.%d)\n", major, minor);
|
||||||
exit(3);
|
return -2;
|
||||||
}
|
}
|
||||||
else if (queryResult != Success)
|
else if (queryResult != Success)
|
||||||
{
|
{
|
||||||
fprintf(stderr, "XIQueryVersion failed!\n");
|
fprintf(stderr, "XIQueryVersion failed\n");
|
||||||
exit(4);
|
return -3;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
typedef struct SlaveInfo
|
||||||
|
{
|
||||||
|
char* slave_names;
|
||||||
|
char* dev_nodes;
|
||||||
|
} SlaveInfo;
|
||||||
|
|
||||||
|
SlaveInfo new_slave_info()
|
||||||
|
{
|
||||||
|
SlaveInfo si;
|
||||||
|
si.slave_names = NULL;
|
||||||
|
si.dev_nodes = NULL;
|
||||||
|
return si;
|
||||||
|
}
|
||||||
|
|
||||||
|
void free_slave_info(SlaveInfo si)
|
||||||
|
{
|
||||||
|
free(si.slave_names);
|
||||||
|
free(si.dev_nodes);
|
||||||
|
si.slave_names = NULL;
|
||||||
|
si.dev_nodes = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool is_empty_slave_info(SlaveInfo si)
|
||||||
|
{
|
||||||
|
return (si.slave_names == NULL || si.dev_nodes == NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
void replace(char* str, char old, char new)
|
||||||
|
{
|
||||||
|
int i = 0;
|
||||||
|
while (str[i] != '\0')
|
||||||
|
{
|
||||||
|
if (str[i] == old)
|
||||||
|
str[i] = new;
|
||||||
|
i++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int append_as_line(char** dst, char* line)
|
||||||
void print_device_nodes(Display* disp)
|
|
||||||
{
|
{
|
||||||
XIDeviceInfo* all_slaves;
|
uint len_newstr = strlen(line) + 2;
|
||||||
XIDeviceInfo* current_slave;
|
if (*dst != NULL)
|
||||||
int num_slaves;
|
len_newstr += strlen(*dst);
|
||||||
|
|
||||||
|
char* newstr = (char*)malloc(len_newstr);
|
||||||
|
if (newstr == NULL)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
newstr[0] = '\0';
|
||||||
|
replace(line, '\n', ' ');
|
||||||
|
if (*dst != NULL)
|
||||||
|
strcat(newstr, *dst);
|
||||||
|
strcat(newstr, line);
|
||||||
|
strcat(newstr, "\n");
|
||||||
|
|
||||||
|
free(*dst);
|
||||||
|
*dst = newstr;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
SlaveInfo get_slave_info(Display* disp)
|
||||||
|
{
|
||||||
|
int num_slaves;
|
||||||
|
XIDeviceInfo* all_slaves = XIQueryDevice(disp, XIAllDevices, &num_slaves);
|
||||||
|
SlaveInfo slaveinfo = new_slave_info();
|
||||||
|
bool fail = false;
|
||||||
|
|
||||||
all_slaves = XIQueryDevice(disp, XIAllDevices, &num_slaves);
|
|
||||||
for (int i = 0; i < num_slaves; i++)
|
for (int i = 0; i < num_slaves; i++)
|
||||||
{
|
{
|
||||||
current_slave = &all_slaves[i];
|
XIDeviceInfo* current_slave = &all_slaves[i];
|
||||||
|
|
||||||
int nprops;
|
int nprops;
|
||||||
Atom* props;
|
Atom* props = XIListProperties(disp, current_slave->deviceid, &nprops);
|
||||||
props = XIListProperties(disp, current_slave->deviceid, &nprops);
|
|
||||||
if (!nprops)
|
|
||||||
printf("Device '%s' does not report any properties.\n", current_slave->name);
|
|
||||||
|
|
||||||
while(nprops--)
|
while(nprops-- && !fail)
|
||||||
{
|
{
|
||||||
char* property = 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 (property != NULL)
|
if (current_slave->name != NULL && devnode != NULL)
|
||||||
{
|
{
|
||||||
printf("%s=%s\n", current_slave->name, property);
|
int append_slave_success = append_as_line(&slaveinfo.slave_names, current_slave->name);
|
||||||
free(property);
|
int append_devnode_success = append_as_line(&slaveinfo.dev_nodes, devnode);
|
||||||
|
if (append_slave_success != 0 || append_devnode_success != 0)
|
||||||
|
fail = true;
|
||||||
}
|
}
|
||||||
|
free(devnode);
|
||||||
}
|
}
|
||||||
XFree(props);
|
XFree(props);
|
||||||
}
|
if (fail)
|
||||||
|
{
|
||||||
|
free_slave_info(slaveinfo);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
XIFreeDeviceInfo(all_slaves);
|
XIFreeDeviceInfo(all_slaves);
|
||||||
|
return slaveinfo;
|
||||||
|
}
|
||||||
|
|
||||||
|
Display* connect_to_x(const char* xDisplayName)
|
||||||
|
{
|
||||||
|
Display* disp = XOpenDisplay(xDisplayName);
|
||||||
|
if (NULL == disp)
|
||||||
|
{
|
||||||
|
fprintf(stderr, "Cannot open X display '%s'\n", xDisplayName);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (is_xinput2_available(disp) != 0)
|
||||||
|
{
|
||||||
|
XCloseDisplay(disp);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
return disp;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -142,19 +220,22 @@ int main(int argc, char * argv[])
|
|||||||
char* xDisplayName = getenv("DISPLAY");
|
char* xDisplayName = getenv("DISPLAY");
|
||||||
if (xDisplayName == NULL)
|
if (xDisplayName == NULL)
|
||||||
{
|
{
|
||||||
printf("DISPLAY environment variable not found\n");
|
fprintf(stderr, "DISPLAY environment variable not found\n");
|
||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Connect to X display
|
Display* disp = connect_to_x(xDisplayName);
|
||||||
Display* disp = XOpenDisplay(xDisplayName);
|
if (disp == NULL)
|
||||||
if (NULL == disp)
|
exit(1);
|
||||||
|
|
||||||
|
SlaveInfo si = get_slave_info(disp);
|
||||||
|
if (!is_empty_slave_info(si))
|
||||||
{
|
{
|
||||||
fprintf(stderr, "Cannot open X display '%s'\n", xDisplayName);
|
printf("%s", si.slave_names);
|
||||||
exit(1);
|
printf("%s", si.dev_nodes);
|
||||||
}
|
}
|
||||||
assert_xinput2(disp);
|
|
||||||
|
|
||||||
print_device_nodes(disp);
|
free_slave_info(si);
|
||||||
|
XCloseDisplay(disp);
|
||||||
exit(0);
|
exit(0);
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user