add the kdetrayproxy tool
authorDana Jansens <danakj@orodu.net>
Fri, 1 Aug 2003 05:00:23 +0000 (05:00 +0000)
committerDana Jansens <danakj@orodu.net>
Fri, 1 Aug 2003 05:00:23 +0000 (05:00 +0000)
Makefile.am
tools/kdetrayproxy/.cvsignore [new file with mode: 0644]
tools/kdetrayproxy/Makefile [new file with mode: 0644]
tools/kdetrayproxy/kdetrayproxy.c [new file with mode: 0644]

index f84dc6f..6ab3dc2 100644 (file)
@@ -22,7 +22,8 @@ lib_LTLIBRARIES = \
        parser/libobparser.la
 
 bin_PROGRAMS = \
-       kernel/openbox
+       kernel/openbox \
+       tools/kdetrayproxy/kdetrayproxy
 
 plugin_LTLIBRARIES = \
        plugins/resistance/resistance.la \
@@ -354,6 +355,16 @@ tools_obconf_obconf_SOURCES = \
        tools/obconf/main.c
 
 
+## kdetrayproxy ##
+
+tools_kdetrayproxy_kdetrayproxy_CPPFLAGS = \
+       $(X_CFLAGS)
+tools_kdetrayproxy_kdetrayproxy_LDADD = \
+       $(X_LIBS)
+tools_kdetrayproxy_kdetrayproxy_SOURCES = \
+       tools/kdetrayproxy/kdetrayproxy.c
+
+
 ## themes ##
 
 dist_theme_DATA = \
diff --git a/tools/kdetrayproxy/.cvsignore b/tools/kdetrayproxy/.cvsignore
new file mode 100644 (file)
index 0000000..3e53acd
--- /dev/null
@@ -0,0 +1,4 @@
+.deps
+.dirstamp
+.libs
+kdetrayproxy
diff --git a/tools/kdetrayproxy/Makefile b/tools/kdetrayproxy/Makefile
new file mode 100644 (file)
index 0000000..cfc4653
--- /dev/null
@@ -0,0 +1,4 @@
+all clean install:
+       $(MAKE) -C ../.. -$(MAKEFLAGS) $@
+
+.PHONY: all clean install
diff --git a/tools/kdetrayproxy/kdetrayproxy.c b/tools/kdetrayproxy/kdetrayproxy.c
new file mode 100644 (file)
index 0000000..31a4d97
--- /dev/null
@@ -0,0 +1,220 @@
+#include <X11/Xlib.h>
+#include <X11/Xatom.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/select.h>
+#include <unistd.h>
+
+typedef struct IList {
+    Window win;
+    int ignore_unmaps;
+
+    struct IList *next;
+} IList;
+
+Display *display;
+Window root;
+Atom winhint;
+Atom roothint;
+int xfd;
+IList *list;
+
+void init();
+void eventloop();
+void handleevent(XEvent *e);
+void addicon(Window win);
+void removeicon(Window win, int unmap);
+int issystray(Atom *a, int n);
+void updatehint();
+Window findclient(Window win);
+int ignore_errors(Display *d, XErrorEvent *e);
+void wait_time(unsigned int t);
+
+int main()
+{
+    init();
+    updatehint();
+    eventloop();
+    return 0;
+}
+
+void init()
+{
+    display = XOpenDisplay(NULL);
+    if (!display) {
+        fprintf(stderr, "Could not open display\n");
+        exit(EXIT_FAILURE);
+    }
+
+    xfd = ConnectionNumber(display);
+
+    root = RootWindowOfScreen(DefaultScreenOfDisplay(display));
+
+    winhint = XInternAtom(display, "_KDE_NET_WM_SYSTEM_TRAY_WINDOW_FOR", 0);
+    roothint = XInternAtom(display, "_KDE_NET_SYSTEM_TRAY_WINDOWS", 0);
+
+    XSelectInput(display, root, SubstructureNotifyMask);
+}
+
+void eventloop()
+{
+    XEvent e;
+    fd_set set;
+
+    while (1) {
+        int event = False;
+        while (XPending(display)) {
+            event = True;
+            XNextEvent(display, &e);
+            handleevent(&e);
+        }
+        if (!event) {
+            FD_ZERO(&set);
+            FD_SET(xfd, &set);
+            select(xfd + 1, &set, NULL, NULL, NULL);
+        }
+    }
+}
+
+void handleevent(XEvent *e)
+{
+    switch (e->type) {
+    case MapNotify:
+    {
+        Atom *a;
+        int n;
+        Window w;
+
+        w = findclient(e->xmap.window);
+        if (w) {
+            a = XListProperties(display, w, &n);
+            if (issystray(a, n))
+                addicon(w);
+            XFree(a);
+        }
+        break;
+    }
+    case UnmapNotify:
+        removeicon(e->xunmap.window, True);
+        break;
+    case DestroyNotify:
+        removeicon(e->xdestroywindow.window, False);
+        break;
+    }
+}
+
+int ignore_errors(Display *d, XErrorEvent *e)
+{
+    (void)d; (void)e;
+    return 1;
+}
+
+void addicon(Window win)
+{
+    IList *it;
+
+    for (it = list; it; it = it->next)
+        if (it->win == win) return; /* duplicate */
+
+    it = list;
+    list = malloc(sizeof(IList));
+    list->win = win;
+    list->ignore_unmaps = 2;
+    list->next = it;
+
+    XSelectInput(display, win, StructureNotifyMask);
+    /* if i set the root hint too fast the dock app can fuck itself up */
+    wait_time(1000000 / 8);
+    updatehint();
+}
+
+void removeicon(Window win, int unmap)
+{
+    IList *it, *last = NULL;
+    void *old;
+
+    for (it = list; it; last = it, it = it->next)
+        if (it->win == win) {
+            if (it->ignore_unmaps && unmap) {
+                it->ignore_unmaps--;
+                return;
+            }
+
+            if (!last)
+                list = it->next;
+            else
+                last->next = it->next;
+
+            XSync(display, False);
+            old = XSetErrorHandler(ignore_errors);
+            XSelectInput(display, win, NoEventMask);
+            XSync(display, False);
+            XSetErrorHandler(old);
+            free(it);
+
+            updatehint();
+        }
+}
+
+int issystray(Atom *a, int n)
+{
+    int i, r = False;
+
+    for (i = 0; i < n; ++i) { 
+        if (a[i] == winhint) {
+            r = True;
+            break;
+        }
+    }
+    return r;
+}
+
+void updatehint()
+{
+    IList *it;
+    int *wins, n, i;
+
+    for (it = list, n = 0; it; it = it->next, ++n) ;
+    if (n) {
+        wins = malloc(sizeof(int) * n);
+        for (it = list, i = 0; it; it = it->next, ++i)
+            wins[i] = it->win;
+    }
+    XChangeProperty(display, root, roothint, XA_WINDOW, 32, PropModeReplace,
+                    (unsigned char*) wins, n);
+}
+
+Window findclient(Window win)
+{
+  Window r, *children;
+  unsigned int n, i;
+  Atom state = XInternAtom(display, "WM_STATE", True);
+  Atom ret_type;
+  int ret_format;
+  unsigned long ret_items, ret_bytesleft;
+  unsigned long *prop_return;
+
+  XQueryTree(display, win, &r, &r, &children, &n);
+  for (i = 0; i < n; ++i) {
+    Window w = findclient(children[i]);
+    if (w) return w;
+  }
+
+  /* try me */
+  XGetWindowProperty(display, win, state, 0, 1,
+                    False, state, &ret_type, &ret_format,
+                    &ret_items, &ret_bytesleft,
+                    (unsigned char**) &prop_return); 
+  if (ret_type == None || ret_items < 1)
+    return None;
+  return win; /* found it! */
+}
+
+void wait_time(unsigned int t)
+{
+    struct timeval time;
+    time.tv_sec = 0;
+    time.tv_usec = t;
+    select(1, NULL, NULL, NULL, &time);
+}