All pastes #1368107 Raw Edit

focus.c

public c v1 · immutable
#1368107 ·published 2009-03-22 16:10 UTC
rendered paste body
#include <X11/Xlib.h>#include <X11/Xatom.h>#include <unistd.h>#include <stdlib.h>#include <stdio.h>#include <string.h>#include <errno.h>// Globals, yay!Window rootWindow = None;Atom atomClassName = 0;Atom atomPID = 0;// Resolves a PID to an executable, using /procchar *resolvePID(long lPID) {	// If we've reached this function, we're not on OS X	// It's fairly safe to assume that we have /proc	char szPath[1024];	char *szExePath = malloc(sizeof(char)*1024);;	int iChars = 0;		snprintf(szPath, 1023, "/proc/%ld/exe", lPID);		iChars = readlink(szPath, szExePath, 1023);	if(iChars == -1) {		free(szExePath);		return NULL;	}	else	{		szExePath[iChars] = '\0';		return szExePath;	}}// Returns the direct parent of a windowWindow getParentWindow(Display *dpy, Window child) {	Window rootWindow;	Window parentWindow;	Window *childWindows;	unsigned int iChildCount;		XQueryTree(dpy, child, &rootWindow, &parentWindow, &childWindows, &iChildCount);	if(iChildCount != 0)		XFree(childWindows);	return parentWindow;}// Look up the executable's PID, then resolve that to an executable// This should really also check the WM_CLIENT_MACHINE property// as per http://standards.freedesktop.org/wm-spec/wm-spec-1.4.html#id2552250// but I can't be arsed. If you're spending all your time focused on// dbus-daemon, this is why.char *getWindowExecutableByPID(Display *dpy, Window queryWindow) {	Atom outType;	int outFmt;	unsigned long outItems;	unsigned long outBytes;	long *outPID;	long PID;		Window currentWindow = queryWindow;		while((currentWindow != None) && (currentWindow != rootWindow)) {		int success = XGetWindowProperty(dpy, currentWindow, atomPID,										 0, 1, False, XA_CARDINAL,										 &outType, &outFmt, &outItems,										&outBytes, (unsigned char **)&outPID);		if(success == Success && outType != None)		{			PID = *outPID;			XFree(outPID);			return resolvePID(PID);		}		currentWindow = getParentWindow(dpy, currentWindow);	}	return NULL;}// Try to use the WM_CLASS property as executable name (dodgy)char *getWindowExecutableByClassName(Display *dpy, Window queryWindow) {	Atom outType;	int outFmt;	unsigned long outItems;	unsigned long outBytes;	unsigned char *outClassName;	char *szClassName = NULL;		Window currentWindow = queryWindow;		while((currentWindow != None) && (currentWindow != rootWindow)) {		int success = XGetWindowProperty(dpy, currentWindow, atomClassName,										 0, 1024, False, XA_STRING,										 &outType, &outFmt, &outItems,										&outBytes, &outClassName);		if(success == Success && outType != None)		{			szClassName = strdup((const char *)outClassName);			XFree(outClassName);			return szClassName;		}		currentWindow = getParentWindow(dpy, currentWindow);	}	return NULL;	}// Try several methods of finding the executablechar *getWindowExecutable(Display *dpy, Window queryWindow) {	char *executable = NULL;	// There's no libproc or procfs on macs.#ifndef __APPLE__	executable = getWindowExecutableByPID(dpy, queryWindow);#endif	if(!executable)		executable = getWindowExecutableByClassName(dpy, queryWindow);	if(!executable)		executable = strdup("None");	return executable;}char *getFocusWindow(Display *dpy){		Window focus;	int revert;		// Find the focus window	XGetInputFocus(dpy, &focus, &revert);		// If nothing has focus, return "None"	if(focus == None || focus == rootWindow)		return strdup("None");	else		return getWindowExecutable(dpy, focus);}int main(int argc, char **argv) {	Display *pDisplay = NULL;	FILE *pLog = NULL;	float flIntervalMult = 1.0;	int iInterval = 1000000;	char *szPrevFocus = NULL;	long lPrevFocusPeriod = 0;	long lRewindPosition = 0;		if(argc != 3) {		printf("%s [interval in seconds] [logfile]\n", argv[0]);		exit(1);	}		if(sscanf(argv[1], "%f", &flIntervalMult) != 1)	{		printf("Usage: %s [interval in seconds] [logfile]\n", argv[0]);		exit(1);	}		// Init XLib	pDisplay = XOpenDisplay(NULL);	rootWindow = XDefaultRootWindow(pDisplay);	atomPID = XInternAtom(pDisplay, "_NET_WM_PID", False);	atomClassName = XInternAtom(pDisplay, "WM_CLASS", False);		// Set up defaults	szPrevFocus = strdup("");	iInterval *= flIntervalMult;		// And open our log file	pLog = fopen(argv[2], "w+");	if(pLog == NULL) {		printf("Could not open %s for writing: %s\n", argv[2], strerror(errno));		exit(1);	}		// Print the file header (consists solely of a version specifier, \t, and interval in microseconds)	fprintf(pLog, "FOCUSLOG1\t%d\n", iInterval);		while(1) {		char *szCurrFocus = getFocusWindow(pDisplay);				// Check whether focus has changed		if(strcmp(szPrevFocus, szCurrFocus) != 0) {			// If so, move on to the new line, and print our current focus			fprintf(pLog, "\n%s\t", szCurrFocus);			// Store where to rewind to, to print the period			lRewindPosition = ftell(pLog);			// Then print 1 to ensure it's logged even if only 1 interval passes			fprintf(pLog, "1");			// Reset the period			lPrevFocusPeriod = 1L;			// And free and replace the old focus name			free(szPrevFocus);			szPrevFocus = szCurrFocus;		}		else		{			// If it hasn't, free the new focus			free(szCurrFocus);			// Rewind to the insertion position			fseek(pLog, lRewindPosition, SEEK_SET);			// And print the new period			lPrevFocusPeriod++;			fprintf(pLog, "%ld", lPrevFocusPeriod);		}		// And sleep for a while		usleep(iInterval);	}}