Improve hacky XLib code
This commit is contained in:
		@@ -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
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -6,6 +6,8 @@
 | 
			
		||||
 *     https://github.com/anko/xkbcat
 | 
			
		||||
*/
 | 
			
		||||
 | 
			
		||||
#define _GNU_SOURCE
 | 
			
		||||
 | 
			
		||||
#include <string.h>
 | 
			
		||||
#include <stdio.h>
 | 
			
		||||
#include <stdlib.h>
 | 
			
		||||
@@ -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);
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user