first commit

This commit is contained in:
Adrien Schildknecht 2013-04-24 21:05:53 +02:00
commit 913c08b9ac
5 changed files with 318 additions and 0 deletions

27
LICENSE Normal file
View File

@ -0,0 +1,27 @@
Copyright © 2013, Adrien Schildknecht
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
* Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
* Neither the name of the copyright holder nor the names of
contributors may be used to endorse or promote products derived from
this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY Adrien Schildknecht ''AS IS'' AND ANY
EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL Adrien Schildknecht BE LIABLE FOR ANY
DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

24
Makefile Normal file
View File

@ -0,0 +1,24 @@
CFILES=xcwd.c
CC=gcc
CFLAGS=-Wall -Werror -std=gnu89 #-DDEBUG -g
LDFLAGS=-lX11
EXE="xcwd"
O=${CFILES:.c=.o}
prefix=/usr/
${EXE}: clean ${O}
${CC} ${CFLAGS} ${LDFLAGS} -o $@ ${O}
.SUFFIXES: .c .o
.c.o:
${CC} ${CFLAGS} -c $<
clean:
rm -vf *.o
distclean: clean
rm -vf ${EXE}
install: ${EXE}
install -m 0755 ${EXE} $(prefix)/bin

17
README.md Normal file
View File

@ -0,0 +1,17 @@
xcwd - X current working directory
==================================
xcwd is a simple tool which print the current working directory of the
currently focused window.
The main goal is to launch applications directly into the same directory
as the focused applications. This is especially useful if you want to open
a new terminal for debugging or compiling purpose.
Requirements
------------
- libX11-dev
Running xwcd
------------
Simply invoke the 'xcwd' command.
You probably want to use it this way:
``urxvt -cd `xcwd` ``

12
TODO Normal file
View File

@ -0,0 +1,12 @@
TODO
====
Features
--------
check the WM_CLIENT_MACHINE property
multi-monitor ?
Bugs
----
xcwd is unable to get the properties of a gtk window.

238
xcwd.c Normal file
View File

@ -0,0 +1,238 @@
/* This is fcwd written by Adrien Schildknecht (c) 2013
* Email: adrien+dev@schischi.me
* Feel free to copy and redistribute in terms of the
* BSD license
*/
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <glob.h>
#include <sys/stat.h>
#include <X11/Xlib.h>
#define XA_STRING (XInternAtom(dpy, "STRING", 0))
Display *dpy;
typedef struct processes_s *processes_t;
struct processes_s {
struct proc_s {
long pid;
long ppid;
char name[32];
} *ps;
size_t n;
};
int nameCmp(const void *p1, const void *p2)
{
return strcasecmp(((struct proc_s *)p1)->name,
((struct proc_s *)p2)->name);
}
int ppidCmp(const void *p1, const void *p2)
{
return ((struct proc_s *)p1)->ppid - ((struct proc_s *)p2)->ppid;
}
static Window focusedWindow()
{
Window focuswin;
int focusrevert;
dpy = XOpenDisplay (NULL);
if (!dpy)
exit (1);
XGetInputFocus (dpy, &focuswin, &focusrevert);
#ifdef DEBUG
fprintf(stderr, "Window ID = %lu\n", focuswin);
#endif
return focuswin;
}
static long windowPid(Window focuswin)
{
Atom nameAtom = XInternAtom(dpy, "_NET_WM_PID", 1);
Atom cardinalAtom = XInternAtom(dpy, "CARDINAL", 0);
Atom type;
int format;
long pid = -1;
unsigned long nitems, after;
unsigned char *data = 0;
if (XGetWindowProperty(dpy, focuswin, nameAtom, 0, 1024, 0, cardinalAtom,
&type, &format, &nitems, &after, &data) == Success) {
if (data) {
pid = *((long*)data);
XFree(data);
}
}
#ifdef DEBUG
if(pid == -1)
fprintf(stderr, "_NET_WM_PID not found\n");
else
fprintf(stderr, "_NET_WM_PID = %lu\n", pid);
#endif
return pid;
}
static char* windowStrings(Window focuswin, size_t *size, char* hint)
{
Atom nameAtom = XInternAtom(dpy, hint, 1);
Atom type;
int format;
int i;
unsigned long after;
unsigned char *data = 0;
char *ret = NULL;
if (XGetWindowProperty(dpy, focuswin, nameAtom, 0, 1024, 0, AnyPropertyType,
&type, &format, size, &after, &data) == Success) {
if (data) {
if(type == XA_STRING) {
ret = malloc(sizeof(char) * *size);
#ifdef DEBUG
fprintf(stderr, "%s = ", hint);
#endif
for(i = 0; i < *size; ++i) {
#ifdef DEBUG
fprintf(stderr, "%c", data[i] == 0 ? ' ' : data[i]);
#endif
ret[i] = data[i];
}
#ifdef DEBUG
fprintf(stderr, "\n");
#endif
}
XFree(data);
}
#ifdef DEBUG
else
fprintf(stderr, "%s not found\n", hint);
#endif
}
return ret;
}
static void freeProcesses(processes_t p)
{
free(p->ps);
free(p);
}
static processes_t getProcesses(void)
{
glob_t globbuf;
unsigned int i, j;
processes_t p;
glob("/proc/[0-9]*", GLOB_NOSORT, NULL, &globbuf);
p = malloc(sizeof(struct processes_s));
p->ps = malloc(globbuf.gl_pathc * sizeof(struct proc_s));
#ifdef DEBUG
fprintf(stderr, "Found %ld processes\n", globbuf.gl_pathc);
#endif
for (i = j = 0; i < globbuf.gl_pathc; i++) {
char name[32];
FILE *tn;
(void)globbuf.gl_pathv[globbuf.gl_pathc - i - 1];
snprintf(name, sizeof(name), "%s%s",
globbuf.gl_pathv[globbuf.gl_pathc - i - 1], "/stat");
tn = fopen(name, "r");
if (tn == NULL)
continue;
fscanf(tn, "%ld (%32[^)] %*3c %ld", &p->ps[j].pid, p->ps[j].name,
&p->ps[j].ppid);
#ifdef DEBUG
fprintf(stderr, "\t%-20s\tpid=%6ld\tppid=%6ld\n", p->ps[j].name,
p->ps[j].pid, p->ps[j].ppid);
#endif
fclose(tn);
j++;
}
p->n = j;
globfree(&globbuf);
return p;
}
static long lastChild(processes_t p, long pid)
{
struct proc_s key, *res;
do {
key.ppid = pid;
res = (struct proc_s *)bsearch(&key, p->ps, p->n,
sizeof(struct proc_s), ppidCmp);
pid = res ? res->pid : -1;
}while(pid != -1);
return key.ppid;
}
static void readPath(long pid)
{
char buf[255];
char path[64];
snprintf(path, sizeof(path), "/proc/%ld/cwd", pid);
#ifdef DEBUG
fprintf(stderr, "Read %s\n", path);
#endif
readlink(path, buf, 255);
fprintf(stdout, "%s\n", buf);
}
int main(int argc, const char *argv[])
{
processes_t p;
Window w = focusedWindow();
long pid;
pid = windowPid(w);
p = getProcesses();
if(pid != -1) { // WM_NET_PID
qsort(p->ps, p->n, sizeof(struct proc_s), ppidCmp);
}
else {
size_t size;
char* strings;
int i;
struct proc_s *res = NULL, key;
qsort(p->ps, p->n, sizeof(struct proc_s), nameCmp);
strings = windowStrings(w, &size, "WM_CLASS");
for(i = 0; i < size; i += strlen(strings + i) + 1) {
#ifdef DEBUG
fprintf(stderr, "pidof %s\n", strings + i);
#endif
strcpy(key.name, strings + i);
res = (struct proc_s *)bsearch(&key, p->ps, p->n,
sizeof(struct proc_s), nameCmp);
if(res)
break;
}
if(res) {
pid = res->pid;
#ifdef DEBUG
fprintf(stderr, "Found %s (%ld)\n", res->name, res->pid);
#endif
}
if(size != 0)
free(strings);
}
if(pid != -1) {
pid = lastChild(p, pid);
readPath(pid);
}
else {
#ifdef DEBUG
fprintf(stderr, "getenv $HOME...\n");
#endif
fprintf(stdout, "%s\n", getenv("HOME"));
}
freeProcesses(p);
return EXIT_SUCCESS;
}