~shiny/tools

49a690f44802e6fdf0c3c3872bd8008692c0c030 — Thomas Spurden 9 years ago df0dfd8
Tool to print a line when a RandR monitor is added or removed.
1 files changed, 161 insertions(+), 0 deletions(-)

A randr_tail.c
A randr_tail.c => randr_tail.c +161 -0
@@ 0,0 1,161 @@
#if 0
# Copyright (c) 2014, Thomas Spurden <thomas@spurden.name>
# 
# Permission to use, copy, modify, and/or distribute this software for any
# purpose with or without fee is hereby granted, provided that the above
# copyright notice and this permission notice appear in all copies.
# 
# THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
# OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.

# Print a line to stdout whenever a XRandR diplay is plugged or unplugged
# The line will be of the form:
# + OUTPUTNAME
# for plug, and
# - OUTPUTNAME
# for unplug

# This file can be read by either GNU Make or a C99 compiler.
# Easy way to compile is: make -f thisfile output
# Which will produce a binary called output.

# Dependencies: X11 with XRandR

! := $(lastword $(MAKEFILE_LIST))
%: $!
	$(CC) -pedantic -Wall -O2 -std=c99 -lX11 -lXrandr -o $@ -xc $!

define program
#endif

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <X11/Xlib.h>
#include <X11/extensions/Xrandr.h>

static int error_handler(void) 
{
	exit(EXIT_FAILURE);
}

char* strdup(char const* in)
{
	size_t len = strlen(in);
	if(len > 256) {
		return NULL;
	}
	char* to = malloc(len + 1);
	strncpy(to, in, len);
	to[len] = '\0';
	return to;
}

char* connected_outputs[16] = {0};

int set_connected(char const* name, int con)
{
	char** inspos = NULL;
	for(unsigned int i = 0; i < sizeof(connected_outputs) / sizeof(connected_outputs[0]); i += 1) {
		if(connected_outputs[i]) {
			if(strcmp(connected_outputs[i], name) == 0) {
				if(con) {
					return 1;
				} else {
					free(connected_outputs[i]);
					connected_outputs[i] = 0;
					return 1;
				}
			}
		} else {
			inspos = &connected_outputs[i];
		}
	}
	if(con && inspos) {
		*inspos = strdup(name);
		return (*inspos)? 0 : -1;
	}

	return -1;
}

int main(int argc, char **argv) 
{
	XEvent ev;
	Display *dpy;
	int eventBase, errorBase;

	dpy = XOpenDisplay(NULL);

	if(dpy == NULL) {
		fprintf(stderr, "Could not open X11 display\n");
		exit(EXIT_FAILURE);
	}

	if(!XRRQueryExtension(dpy, &eventBase, &errorBase)) {
		fprintf(stderr, "Could not query the XRandR extension\n");
		exit(EXIT_FAILURE);
	}

	{
		XRRScreenResources* res = XRRGetScreenResources(dpy, DefaultRootWindow(dpy));
		for(int i = 0; i < res->noutput; i += 1) {
			XRROutputInfo* info = XRRGetOutputInfo(dpy, res, res->outputs[i]);
			set_connected(info->name, info->connection == 0);
			XRRFreeOutputInfo(info);

		}
		XRRFreeScreenResources(res);
	}

	XRRSelectInput(dpy, DefaultRootWindow(dpy), RROutputChangeNotifyMask);
	XSync(dpy, False);
	XSetIOErrorHandler((XIOErrorHandler) error_handler);
	while(1) {
		if(!XNextEvent(dpy, &ev)) {
			if(ev.type != eventBase + RRNotify_OutputChange) {
				continue;
			}

			XRROutputChangeNotifyEvent* change = (XRROutputChangeNotifyEvent*)&ev;
			XRRScreenResources* resources = XRRGetScreenResources(change->display, change->window);
			if(resources == NULL) {
				fprintf(stderr, "Could not get screen resources\n");
				continue;
			}

			XRROutputInfo* info = XRRGetOutputInfo(change->display, resources, change->output);
			if(info == NULL) {
				XRRFreeScreenResources(resources);
				fprintf(stderr, "Could not get output info\n");
				continue;
			}

			if(info->connection == 0) {
				if(set_connected(info->name, 1) == 0) {
					printf("+ %s\n", info->name);
					fflush(stdout);
				}
			}
			else {
				if(set_connected(info->name, 0) == 1) {
					printf("- %s\n", info->name);
					fflush(stdout);
				}
			}

			XRRFreeScreenResources(resources);
			XRRFreeOutputInfo(info);
		}
	}
	return EXIT_SUCCESS;
}

#if 0
endef
#endif