diff --git a/xdg/get-x-slave-devnodes/Makefile b/xdg/get-x-slave-devnodes/Makefile index 78b1927..eb9dfb8 100644 --- a/xdg/get-x-slave-devnodes/Makefile +++ b/xdg/get-x-slave-devnodes/Makefile @@ -1,5 +1,5 @@ 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: rm -f get-x-slave-devnodes diff --git a/xdg/get-x-slave-devnodes/get-x-slave-devnodes.c b/xdg/get-x-slave-devnodes/get-x-slave-devnodes.c index fabb304..a0ea294 100644 --- a/xdg/get-x-slave-devnodes/get-x-slave-devnodes.c +++ b/xdg/get-x-slave-devnodes/get-x-slave-devnodes.c @@ -6,6 +6,8 @@ * https://github.com/anko/xkbcat */ +#define _GNU_SOURCE + #include #include #include @@ -28,7 +30,7 @@ char* get_property_xi2(Display* dpy, int deviceid, Atom property, const char* pr char* ret = NULL; name = XGetAtomName(dpy, property); - int interested_in_property = (strcmp(name, property_name) == 0); + bool interested_in_property = (strcmp(name, property_name) == 0); XFree(name); if (!interested_in_property) return ret; @@ -51,22 +53,18 @@ char* get_property_xi2(Display* dpy, int deviceid, Atom property, const char* pr } int len = strlen((char*)ptr); - ret = (char*)malloc(len+1); - strcpy(ret, (const char*)ptr); + ret = strdup((const char*)ptr); - j += len; /* The loop's j++ jumps over the - terminating 0 */ - ptr += len; /* ptr += size below jumps over - the terminating 0 */ + j += len; // The loop's j++ jumps over the terminating 0 + ptr += len; // ptr += size below jumps over the terminating 0 break; + default: // Unknown type done = True; break; } - ptr += act_format/8; - if (done == True) break; } @@ -75,65 +73,145 @@ char* get_property_xi2(Display* dpy, int deviceid, Atom property, const char* pr return ret; } - -void assert_xinput2(Display* disp) +int is_xinput2_available(Display* disp) { int xiOpcode; - { // Test for XInput 2 extension - int queryEvent, queryError; - if (! XQueryExtension(disp, "XInputExtension", &xiOpcode, &queryEvent, &queryError)) - { - fprintf(stderr, "X Input extension not available\n"); - exit(2); - } + int queryEvent, queryError; + if (! XQueryExtension(disp, "XInputExtension", &xiOpcode, &queryEvent, &queryError)) + { + fprintf(stderr, "XInput extension not available\n"); + return -1; } - { // Request XInput 2.0, to guard against changes in future versions - int major = 2, minor = 0; - int queryResult = XIQueryVersion(disp, &major, &minor); - if (queryResult == BadRequest) - { - fprintf(stderr, "Need XI 2.0 support (got %d.%d)\n", major, minor); - exit(3); - } - else if (queryResult != Success) - { - fprintf(stderr, "XIQueryVersion failed!\n"); - exit(4); - } + + 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; + } + else if (queryResult != Success) + { + fprintf(stderr, "XIQueryVersion failed\n"); + 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++; } } - -void print_device_nodes(Display* disp) +int append_as_line(char** dst, char* line) { - XIDeviceInfo* all_slaves; - XIDeviceInfo* current_slave; - int num_slaves; + uint len_newstr = strlen(line) + 2; + if (*dst != NULL) + 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++) { - current_slave = &all_slaves[i]; - + XIDeviceInfo* current_slave = &all_slaves[i]; int nprops; - Atom* props; - props = XIListProperties(disp, current_slave->deviceid, &nprops); - if (!nprops) - printf("Device '%s' does not report any properties.\n", current_slave->name); + Atom* props = XIListProperties(disp, current_slave->deviceid, &nprops); - while(nprops--) + while(nprops-- && !fail) { - char* property = get_property_xi2(disp, current_slave->deviceid, props[nprops], "Device Node"); - if (property != NULL) + char* devnode = get_property_xi2(disp, current_slave->deviceid, props[nprops], "Device Node"); + if (current_slave->name != NULL && devnode != NULL) { - printf("%s=%s\n", current_slave->name, property); - free(property); + int append_slave_success = append_as_line(&slaveinfo.slave_names, current_slave->name); + 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); - } + if (fail) + { + free_slave_info(slaveinfo); + break; + } + } 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"); if (xDisplayName == NULL) { - printf("DISPLAY environment variable not found\n"); + fprintf(stderr, "DISPLAY environment variable not found\n"); exit(1); } - // Connect to X display - Display* disp = XOpenDisplay(xDisplayName); - if (NULL == disp) + Display* disp = connect_to_x(xDisplayName); + if (disp == NULL) + exit(1); + + SlaveInfo si = get_slave_info(disp); + if (!is_empty_slave_info(si)) { - fprintf(stderr, "Cannot open X display '%s'\n", xDisplayName); - exit(1); + printf("%s", si.slave_names); + printf("%s", si.dev_nodes); } - assert_xinput2(disp); - print_device_nodes(disp); + free_slave_info(si); + XCloseDisplay(disp); exit(0); }