Return the path of the deepest accessible child
This commit is contained in:
parent
e826c01208
commit
1bd171cc95
116
xcwd.c
116
xcwd.c
@ -1,4 +1,4 @@
|
|||||||
/* This is xcwd written by Adrien Schildknecht (c) 2013
|
/* This is xcwd written by Adrien Schildknecht (c) 2013-2014
|
||||||
* Email: adrien+dev@schischi.me
|
* Email: adrien+dev@schischi.me
|
||||||
* Feel free to copy and redistribute in terms of the
|
* Feel free to copy and redistribute in terms of the
|
||||||
* BSD license
|
* BSD license
|
||||||
@ -22,19 +22,21 @@
|
|||||||
# include <libutil.h>
|
# include <libutil.h>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#define DEBUG 0
|
//#define DEBUG
|
||||||
|
|
||||||
#define XA_STRING (XInternAtom(dpy, "STRING", 0))
|
#define XA_STRING (XInternAtom(dpy, "STRING", 0))
|
||||||
#define XA_CARDINAL (XInternAtom(dpy, "CARDINAL", 0))
|
#define XA_CARDINAL (XInternAtom(dpy, "CARDINAL", 0))
|
||||||
#define XA_WM_STATE (XInternAtom(dpy, "WM_STATE", 0))
|
#define XA_WM_STATE (XInternAtom(dpy, "WM_STATE", 0))
|
||||||
|
|
||||||
#define LOG(fmt, ...) \
|
#ifdef DEBUG
|
||||||
do { if (DEBUG) fprintf(stderr, fmt, __VA_ARGS__); } while (0)
|
#define LOG(fmt, ...) fprintf(stderr, fmt, __VA_ARGS__)
|
||||||
|
#else
|
||||||
|
#define LOG(fmt, ...) do { } while (0)
|
||||||
|
#endif
|
||||||
|
|
||||||
Display *dpy;
|
Display *dpy;
|
||||||
|
|
||||||
typedef struct processes_s *processes_t;
|
struct proc_list {
|
||||||
struct processes_s {
|
|
||||||
struct proc_s {
|
struct proc_s {
|
||||||
long pid;
|
long pid;
|
||||||
long ppid;
|
long ppid;
|
||||||
@ -46,18 +48,18 @@ struct processes_s {
|
|||||||
size_t n;
|
size_t n;
|
||||||
};
|
};
|
||||||
|
|
||||||
int nameCmp(const void *p1, const void *p2)
|
static int process_name_cmp(const void *p1, const void *p2)
|
||||||
{
|
{
|
||||||
return strcasecmp(((struct proc_s *)p1)->name,
|
return strcasecmp(((struct proc_s *)p1)->name,
|
||||||
((struct proc_s *)p2)->name);
|
((struct proc_s *)p2)->name);
|
||||||
}
|
}
|
||||||
|
|
||||||
int ppidCmp(const void *p1, const void *p2)
|
static int process_ppid_cmp(const void *p1, const void *p2)
|
||||||
{
|
{
|
||||||
return ((struct proc_s *)p1)->ppid - ((struct proc_s *)p2)->ppid;
|
return ((struct proc_s *)p1)->ppid - ((struct proc_s *)p2)->ppid;
|
||||||
}
|
}
|
||||||
|
|
||||||
static Window focusedWindow()
|
static Window focused_window(void)
|
||||||
{
|
{
|
||||||
Atom type;
|
Atom type;
|
||||||
Window focuswin, root, *children;
|
Window focuswin, root, *children;
|
||||||
@ -93,7 +95,7 @@ static Window focusedWindow()
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static long windowPid(Window focuswin)
|
static long pid_of_window(Window win)
|
||||||
{
|
{
|
||||||
Atom nameAtom = XInternAtom(dpy, "_NET_WM_PID", 1);
|
Atom nameAtom = XInternAtom(dpy, "_NET_WM_PID", 1);
|
||||||
Atom type;
|
Atom type;
|
||||||
@ -102,7 +104,7 @@ static long windowPid(Window focuswin)
|
|||||||
unsigned long nitems, after;
|
unsigned long nitems, after;
|
||||||
unsigned char *data;
|
unsigned char *data;
|
||||||
|
|
||||||
status = XGetWindowProperty(dpy, focuswin, nameAtom, 0, 1024, 0,
|
status = XGetWindowProperty(dpy, win, nameAtom, 0, 1024, 0,
|
||||||
XA_CARDINAL, &type, &format, &nitems, &after, &data);
|
XA_CARDINAL, &type, &format, &nitems, &after, &data);
|
||||||
if (status == Success && data) {
|
if (status == Success && data) {
|
||||||
pid = *((long*)data);
|
pid = *((long*)data);
|
||||||
@ -114,7 +116,7 @@ static long windowPid(Window focuswin)
|
|||||||
return pid;
|
return pid;
|
||||||
}
|
}
|
||||||
|
|
||||||
static char* windowStrings(Window focuswin, long unsigned int *size, char* hint)
|
static char* window_strings(Window win, long unsigned int *size, char *hint)
|
||||||
{
|
{
|
||||||
Atom nameAtom = XInternAtom(dpy, hint, 1);
|
Atom nameAtom = XInternAtom(dpy, hint, 1);
|
||||||
Atom type;
|
Atom type;
|
||||||
@ -124,7 +126,7 @@ static char* windowStrings(Window focuswin, long unsigned int *size, char* hint)
|
|||||||
unsigned char *data = 0;
|
unsigned char *data = 0;
|
||||||
char *ret = NULL;
|
char *ret = NULL;
|
||||||
|
|
||||||
if (XGetWindowProperty(dpy, focuswin, nameAtom, 0, 1024, 0, AnyPropertyType,
|
if (XGetWindowProperty(dpy, win, nameAtom, 0, 1024, 0, AnyPropertyType,
|
||||||
&type, &format, size, &after, &data) == Success) {
|
&type, &format, size, &after, &data) == Success) {
|
||||||
if (data) {
|
if (data) {
|
||||||
if (type == XA_STRING) {
|
if (type == XA_STRING) {
|
||||||
@ -144,22 +146,22 @@ static char* windowStrings(Window focuswin, long unsigned int *size, char* hint)
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void freeProcesses(processes_t p)
|
static void processes_free(struct proc_list * p)
|
||||||
{
|
{
|
||||||
free(p->ps);
|
free(p->ps);
|
||||||
free(p);
|
free(p);
|
||||||
}
|
}
|
||||||
|
|
||||||
static processes_t getProcesses(void)
|
static struct proc_list * processes_list(void)
|
||||||
{
|
{
|
||||||
processes_t p = NULL;
|
struct proc_list * p = NULL;
|
||||||
#ifdef LINUX
|
#ifdef LINUX
|
||||||
glob_t globbuf;
|
glob_t globbuf;
|
||||||
unsigned int i, j, k;
|
unsigned int i, j, k;
|
||||||
char line[201] = {0};
|
char line[201] = {0};
|
||||||
|
|
||||||
glob("/proc/[0-9]*", GLOB_NOSORT, NULL, &globbuf);
|
glob("/proc/[0-9]*", GLOB_NOSORT, NULL, &globbuf);
|
||||||
p = malloc(sizeof(struct processes_s));
|
p = malloc(sizeof(struct proc_list));
|
||||||
p->ps = malloc(globbuf.gl_pathc * sizeof(struct proc_s));
|
p->ps = malloc(globbuf.gl_pathc * sizeof(struct proc_s));
|
||||||
|
|
||||||
LOG("Found %zu processes\n", globbuf.gl_pathc);
|
LOG("Found %zu processes\n", globbuf.gl_pathc);
|
||||||
@ -173,7 +175,8 @@ static processes_t getProcesses(void)
|
|||||||
tn = fopen(name, "r");
|
tn = fopen(name, "r");
|
||||||
if (tn == NULL)
|
if (tn == NULL)
|
||||||
continue;
|
continue;
|
||||||
fread(line, 200, 1, tn);
|
if (fread(line, 200, 1, tn) == 0)
|
||||||
|
continue;
|
||||||
p->ps[j].pid = atoi(strtok(line, " "));
|
p->ps[j].pid = atoi(strtok(line, " "));
|
||||||
k = snprintf(p->ps[j].name, 32, "%s", strtok(NULL, " ") + 1);
|
k = snprintf(p->ps[j].name, 32, "%s", strtok(NULL, " ") + 1);
|
||||||
p->ps[j].name[k - 1] = 0;
|
p->ps[j].name[k - 1] = 0;
|
||||||
@ -189,7 +192,7 @@ static processes_t getProcesses(void)
|
|||||||
#endif
|
#endif
|
||||||
#ifdef BSD
|
#ifdef BSD
|
||||||
unsigned int count;
|
unsigned int count;
|
||||||
p = malloc(sizeof(struct processes_s));
|
p = malloc(sizeof(struct proc_list));
|
||||||
struct kinfo_proc *kp;
|
struct kinfo_proc *kp;
|
||||||
size_t len = 0;
|
size_t len = 0;
|
||||||
int name[4] = { CTL_KERN, KERN_PROC, KERN_PROC_PROC, 0 };
|
int name[4] = { CTL_KERN, KERN_PROC, KERN_PROC_PROC, 0 };
|
||||||
@ -225,7 +228,7 @@ static processes_t getProcesses(void)
|
|||||||
return p;
|
return p;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int readPath(struct proc_s *proc)
|
static int read_process_path(struct proc_s *proc)
|
||||||
{
|
{
|
||||||
#ifdef LINUX
|
#ifdef LINUX
|
||||||
char buf[255];
|
char buf[255];
|
||||||
@ -256,35 +259,40 @@ static int readPath(struct proc_s *proc)
|
|||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int cwdOfDeepestChild(processes_t p, long pid)
|
static int child_cwd(struct proc_list * p, struct proc_s *key)
|
||||||
{
|
{
|
||||||
int i;
|
int i;
|
||||||
struct proc_s key = { .pid = pid, .ppid = pid},
|
struct proc_s *res = (struct proc_s *)bsearch(key, p->ps, p->n,
|
||||||
*res = NULL, *lastRes = NULL;
|
sizeof(struct proc_s), process_ppid_cmp);
|
||||||
|
struct proc_s new_key = { .pid = key->ppid };
|
||||||
|
|
||||||
do {
|
if (res == NULL) {
|
||||||
if(res) {
|
LOG("--> %ld pid\n", key->pid);
|
||||||
lastRes = res;
|
return read_process_path(key);
|
||||||
key.ppid = res->pid;
|
|
||||||
}
|
}
|
||||||
res = (struct proc_s *)bsearch(&key, p->ps, p->n,
|
for(i = 0; res != p->ps && (res - i)->ppid == res->ppid; ++i) {
|
||||||
sizeof(struct proc_s), ppidCmp);
|
new_key.ppid = (res - i)->pid;
|
||||||
} while(res);
|
LOG("--> %ld ppid\n", new_key.ppid);
|
||||||
|
if(child_cwd(p, &new_key))
|
||||||
if(!lastRes) {
|
return 1;
|
||||||
return readPath(&key);
|
|
||||||
}
|
}
|
||||||
|
for(i = 1; res != p->ps + p->n && (res + i)->ppid == res->ppid; ++i) {
|
||||||
for(i = 0; lastRes != p->ps && (lastRes - i)->ppid == lastRes->ppid; ++i)
|
new_key.ppid = (res + i)->pid;
|
||||||
if(readPath((lastRes - i)))
|
LOG("--> %ld ppid\n", new_key.ppid);
|
||||||
|
if(child_cwd(p, &new_key))
|
||||||
return 1;
|
return 1;
|
||||||
for(i = 1; lastRes != p->ps + p->n && (lastRes + i)->ppid == lastRes->ppid; ++i)
|
}
|
||||||
if(readPath((lastRes + i)))
|
return read_process_path(key);
|
||||||
return 1;
|
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int getHomeDirectory()
|
static int deepest_child_cwd(struct proc_list * p, long pid)
|
||||||
|
{
|
||||||
|
struct proc_s key = { .pid = pid, .ppid = pid};
|
||||||
|
|
||||||
|
return child_cwd(p, &key);
|
||||||
|
}
|
||||||
|
|
||||||
|
int get_home_dir(void)
|
||||||
{
|
{
|
||||||
LOG("%s", "getenv $HOME...\n");
|
LOG("%s", "getenv $HOME...\n");
|
||||||
fprintf(stdout, "%s\n", getenv("HOME"));
|
fprintf(stdout, "%s\n", getenv("HOME"));
|
||||||
@ -296,32 +304,32 @@ int main(int argc, const char *argv[])
|
|||||||
(void)argc;
|
(void)argc;
|
||||||
(void)argv;
|
(void)argv;
|
||||||
|
|
||||||
processes_t p;
|
struct proc_list * p;
|
||||||
long pid;
|
long pid;
|
||||||
int ret = EXIT_SUCCESS;
|
int ret = EXIT_SUCCESS;
|
||||||
Window w = focusedWindow();
|
Window w = focused_window();
|
||||||
if (w == None)
|
if (w == None)
|
||||||
return getHomeDirectory();
|
return get_home_dir();
|
||||||
|
|
||||||
pid = windowPid(w);
|
pid = pid_of_window(w);
|
||||||
p = getProcesses();
|
p = processes_list();
|
||||||
if(!p)
|
if(!p)
|
||||||
return getHomeDirectory();
|
return get_home_dir();
|
||||||
if(pid != -1)
|
if(pid != -1)
|
||||||
qsort(p->ps, p->n, sizeof(struct proc_s), ppidCmp);
|
qsort(p->ps, p->n, sizeof(struct proc_s), process_ppid_cmp);
|
||||||
else {
|
else {
|
||||||
long unsigned int size;
|
long unsigned int size;
|
||||||
unsigned int i;
|
unsigned int i;
|
||||||
char* strings;
|
char* strings;
|
||||||
struct proc_s *res = NULL, key;
|
struct proc_s *res = NULL, key;
|
||||||
|
|
||||||
qsort(p->ps, p->n, sizeof(struct proc_s), nameCmp);
|
qsort(p->ps, p->n, sizeof(struct proc_s), process_name_cmp);
|
||||||
strings = windowStrings(w, &size, "WM_CLASS");
|
strings = window_strings(w, &size, "WM_CLASS");
|
||||||
for(i = 0; i < size; i += strlen(strings + i) + 1) {
|
for(i = 0; i < size; i += strlen(strings + i) + 1) {
|
||||||
LOG("pidof %s\n", strings + i);
|
LOG("pidof %s\n", strings + i);
|
||||||
strcpy(key.name, strings + i);
|
strcpy(key.name, strings + i);
|
||||||
res = (struct proc_s *)bsearch(&key, p->ps, p->n,
|
res = (struct proc_s *)bsearch(&key, p->ps, p->n,
|
||||||
sizeof(struct proc_s), nameCmp);
|
sizeof(struct proc_s), process_name_cmp);
|
||||||
if(res)
|
if(res)
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -332,9 +340,9 @@ int main(int argc, const char *argv[])
|
|||||||
if (size)
|
if (size)
|
||||||
free(strings);
|
free(strings);
|
||||||
}
|
}
|
||||||
if (pid == -1 || !cwdOfDeepestChild(p, pid))
|
if (pid == -1 || !deepest_child_cwd(p, pid))
|
||||||
ret = getHomeDirectory();
|
ret = get_home_dir();
|
||||||
freeProcesses(p);
|
processes_free(p);
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user