add shit that i made in the last week!
authorDana Jansens <danakj@orodu.net>
Fri, 9 May 2003 19:58:08 +0000 (19:58 +0000)
committerDana Jansens <danakj@orodu.net>
Fri, 9 May 2003 19:58:08 +0000 (19:58 +0000)
openbox/openbox.c
openbox/popup.c [new file with mode: 0644]
openbox/popup.h [new file with mode: 0644]
tools/Makefile.am [new file with mode: 0644]
tools/slit/Makefile.am [new file with mode: 0644]
tools/slit/slit.c [new file with mode: 0644]

index 304d52c..8c599c4 100644 (file)
@@ -271,7 +271,8 @@ void signal_handler(const ObEvent *e, void *data)
 
     case SIGFPE:
     case SIGSEGV:
-       g_error("Caught signal %d. Aborting and dumping core.", s);
+       g_message("Caught signal %d. Aborting and dumping core.", s);
+        abort();
     }
 }
 
diff --git a/openbox/popup.c b/openbox/popup.c
new file mode 100644 (file)
index 0000000..f20aa00
--- /dev/null
@@ -0,0 +1,215 @@
+#include "openbox.h"
+#include "frame.h"
+#include "render/render.h"
+#include "render/theme.h"
+
+typedef struct Popup {
+    gboolean hasicon;
+    Window bg;
+    Window icon;
+    Window text;
+    Appearance *a_bg;
+    Appearance *a_icon;
+    Appearance *a_text;
+    int gravity;
+    int x;
+    int y;
+    int w;
+    int h;
+} Popup;
+
+Popup *popup_new(gboolean hasicon)
+{
+    Popup *self = g_new(Popup, 1);
+    self->hasicon = hasicon;
+    self->bg = None;
+    self->a_text = NULL;
+    self->gravity = NorthWestGravity;
+    self->x = self->y = self->w = self->h = 0;
+    return self;
+}
+
+void popup_free(Popup *self)
+{
+    if (self->bg) {
+        XDestroyWindow(ob_display, self->bg);
+        XDestroyWindow(ob_display, self->text);
+        XDestroyWindow(ob_display, self->icon);
+        appearance_free(self->a_bg);
+        if (self->hasicon)
+            appearance_free(self->a_icon);
+    }
+    if (self->a_text)
+        appearance_free(self->a_text);
+    g_free(self);
+}
+
+void popup_position(Popup *self, int gravity, int x, int y)
+{
+    self->gravity = gravity;
+    self->x = x;
+    self->y = y;
+}
+
+void popup_size(Popup *self, int w, int h)
+{
+    self->w = w;
+    self->h = h;
+}
+
+void popup_size_to_string(Popup *self, char *text)
+{
+    int textw, texth;
+    int iconw;
+
+    if (!self->a_text)
+        self->a_text = appearance_copy(theme_app_hilite_label);
+
+    self->a_text->texture[0].data.text.string = text;
+    appearance_minsize(self->a_text, &textw, &texth);
+    textw += theme_bevel * 2;
+    texth += theme_bevel * 2;
+
+    self->h = texth + theme_bevel * 2;
+    iconw = (self->hasicon ? texth : 0);
+    self->w = textw + iconw + theme_bevel * 3;
+}
+
+void popup_show(Popup *self, char *text, Icon *icon)
+{
+    XSetWindowAttributes attrib;
+    int x, y, w, h;
+    int textw, texth;
+    int iconw;
+
+    /* create the shit if needed */
+    if (!self->bg) {
+        attrib.override_redirect = True;
+        self->bg = XCreateWindow(ob_display, ob_root,
+                                 0, 0, 1, 1, 0, render_depth, InputOutput,
+                                 render_visual, CWOverrideRedirect, &attrib);
+
+        XSetWindowBorderWidth(ob_display, self->bg, theme_bwidth);
+        XSetWindowBorder(ob_display, self->bg, theme_b_color->pixel);
+
+        self->text = XCreateWindow(ob_display, self->bg,
+                                   0, 0, 1, 1, 0, render_depth, InputOutput,
+                                   render_visual, 0, NULL);
+        if (self->hasicon)
+            self->icon = XCreateWindow(ob_display, self->bg,
+                                       0, 0, 1, 1, 0,
+                                       render_depth, InputOutput,
+                                       render_visual, 0, NULL);
+
+        XMapWindow(ob_display, self->text);
+        XMapWindow(ob_display, self->icon);
+
+        self->a_bg = appearance_copy(theme_app_hilite_bg);
+        if (self->hasicon)
+            self->a_icon = appearance_copy(theme_app_icon);
+    }
+    if (!self->a_text)
+        self->a_text = appearance_copy(theme_app_hilite_label);
+
+    /* set up the textures */
+    self->a_text->texture[0].data.text.string = text;
+    if (self->hasicon) {
+        if (icon) {
+            self->a_icon->texture[0].type = RGBA;
+            self->a_icon->texture[0].data.rgba.width = icon->width;
+            self->a_icon->texture[0].data.rgba.height = icon->height;
+            self->a_icon->texture[0].data.rgba.data = icon->data;
+        } else
+            self->a_icon->texture[0].type = NoTexture;
+    }
+
+    /* measure the shit out */
+    appearance_minsize(self->a_text, &textw, &texth);
+    textw += theme_bevel * 2;
+    texth += theme_bevel * 2;
+
+    /* set the sizes up and reget the text sizes from the calculated
+       outer sizes */
+    if (self->h) {
+        h = self->h;
+        texth = h - (theme_bevel * 2);
+    } else
+        h = texth + theme_bevel * 2;
+    iconw = (self->hasicon ? texth : 0);
+    if (self->w) {
+        w = self->w;
+        textw = w - (iconw + theme_bevel * 3);
+    } else
+        w = textw + iconw + theme_bevel * 3;
+    /* sanity checks to avoid crashes! */
+    if (w < 1) w = 1;
+    if (h < 1) h = 1;
+    if (textw < 1) textw = 1;
+    if (texth < 1) texth = 1;
+
+    /* set up the x coord */
+    x = self->x;
+    switch (self->gravity) {
+    case NorthGravity:
+    case CenterGravity:
+    case SouthGravity:
+        x -= w / 2;
+        break;
+    case NorthEastGravity:
+    case EastGravity:
+    case SouthEastGravity:
+        x -= w;
+        break;
+    }
+
+    /* set up the y coord */
+    y = self->y;
+    switch (self->gravity) {
+    case WestGravity:
+    case CenterGravity:
+    case EastGravity:
+        y -= h / 2;
+        break;
+    case SouthWestGravity:
+    case SouthGravity:
+    case SouthEastGravity:
+        y -= h;
+        break;
+    }
+
+    /* set the windows/appearances up */
+    RECT_SET(self->a_bg->area, 0, 0, w, h);
+    XMoveResizeWindow(ob_display, self->bg, x, y, w, h);
+
+    RECT_SET(self->a_text->area, 0, 0, textw, texth); 
+    RECT_SET(self->a_text->texture[0].position, theme_bevel, theme_bevel,
+             textw - theme_bevel * 2, texth - theme_bevel * 2);
+    self->a_text->surface.data.planar.parent = self->a_bg;
+    self->a_text->surface.data.planar.parentx = iconw + theme_bevel * 2;
+    self->a_text->surface.data.planar.parenty = theme_bevel;
+    XMoveResizeWindow(ob_display, self->text,
+                      iconw + theme_bevel * 2, theme_bevel, textw, texth);
+
+    if (self->hasicon) {
+        if (iconw < 1) iconw = 1; /* sanity check for crashes */
+        RECT_SET(self->a_icon->area, 0, 0, iconw, texth);
+        RECT_SET(self->a_icon->texture[0].position, 0, 0, iconw, texth);
+        self->a_icon->surface.data.planar.parent = self->a_bg;
+        self->a_icon->surface.data.planar.parentx = theme_bevel;
+        self->a_icon->surface.data.planar.parenty = theme_bevel;
+        XMoveResizeWindow(ob_display, self->icon,
+                          theme_bevel, theme_bevel, iconw, texth);
+    }
+
+    paint(self->bg, self->a_bg);
+    paint(self->text, self->a_text);
+    if (self->hasicon)
+        paint(self->icon, self->a_icon);
+
+    XMapWindow(ob_display, self->bg);
+}
+
+void popup_hide(Popup *self)
+{
+    XUnmapWindow(ob_display, self->bg);
+}
diff --git a/openbox/popup.h b/openbox/popup.h
new file mode 100644 (file)
index 0000000..f26bedd
--- /dev/null
@@ -0,0 +1,25 @@
+#ifndef __popup_h
+#define __popup_h
+
+#include "frame.h"
+
+typedef struct Popup Popup;
+
+Popup *popup_new(gboolean hasicon);
+void popup_free(Popup *self);
+
+/*! Position the popup. The gravity rules are not the same X uses for windows,
+  instead of the position being the top-left of the window, the gravity
+  specifies which corner of the popup will be placed at the given coords.
+  Static and Forget gravity are equivilent to NorthWest.
+*/
+void popup_position(Popup *self, int gravity, int x, int y);
+/*! Set the sizes for the popup. When set to 0, the size will be based on
+  the text size. */
+void popup_size(Popup *self, int w, int h);
+void popup_size_to_string(Popup *self, char *text);
+
+void popup_show(Popup *self, char *text, Icon *icon);
+void popup_hide(Popup *self);
+
+#endif
diff --git a/tools/Makefile.am b/tools/Makefile.am
new file mode 100644 (file)
index 0000000..a66187c
--- /dev/null
@@ -0,0 +1 @@
+SUBDIRS = slit
diff --git a/tools/slit/Makefile.am b/tools/slit/Makefile.am
new file mode 100644 (file)
index 0000000..b9aa505
--- /dev/null
@@ -0,0 +1,17 @@
+rcdir=$(datadir)/openbox
+
+INCLUDES=-I../..
+
+CPPFLAGS=$(X_CFLAGS) $(XFT_CFLAGS) $(GLIB_CFLAGS) @CPPFLAGS@ \
+         -DRCDIR=\"$(rcdir)\" \
+         -DG_LOG_DOMAIN=\"ObSlit\"
+LIBS=$(X_LIBS) $(XFT_LIBS) $(GLIB_LIBS) @LIBS@ @LIBINTL@
+
+bin_PROGRAMS=obslit
+
+obslit_LDADD=-lobrender -L../../render
+obslit_SOURCES=slit.c
+MAINTAINERCLEANFILES=Makefile.in
+
+distclean-local:
+       $(RM) *\~ *.orig *.rej .\#*
diff --git a/tools/slit/slit.c b/tools/slit/slit.c
new file mode 100644 (file)
index 0000000..28d9303
--- /dev/null
@@ -0,0 +1,634 @@
+#include "render/render.h"
+#include "render/theme.h"
+
+#include <X11/Xlib.h>
+#include <stdlib.h>
+#include <glib.h>
+#ifdef HAVE_SIGNAL_H
+#  include <signal.h>
+#endif
+#ifdef HAVE_SYS_SELECT_H
+#  include <sys/select.h>
+#endif
+
+#define TITLE_EVENT_MASK (ButtonPressMask | ButtonReleaseMask | \
+                          ButtonMotionMask)
+#define ROOT_EVENT_MASK (PropertyChangeMask | StructureNotifyMask | \
+                         SubstructureNotifyMask)
+#define SLITAPP_EVENT_MASK (StructureNotifyMask)
+
+Display *ob_display;
+Window ob_root;
+int ob_screen;
+
+static struct Slit {
+    Window frame;
+    Window title;
+
+    /* user-requested position stuff */
+    int gravity;
+    int user_x, user_y;
+
+    /* actual position (when not auto-hidden) */
+    int x, y;
+    int w, h;
+
+    gboolean horz;
+
+    Appearance *a_frame;
+    Appearance *a_title;
+
+    GList *slit_apps;
+} *slit;
+static int nslits;
+
+struct SlitApp {
+    Window icon_win;
+    Window win;
+    int x;
+    int y;
+    int w;
+    int h;
+};
+
+static Atom atom_atom;
+static Atom atom_card;
+static Atom atom_theme;
+static Atom atom_type;
+static Atom atom_type_dock;
+static Atom atom_desktop;
+static Atom atom_state;
+static Atom atom_strut;
+
+static gboolean quit = FALSE;
+static gboolean reconfig = FALSE;
+
+void slit_read_theme();
+void slit_configure();
+void event_handle(XEvent *e);
+void slit_add_existing();
+void slit_add_app(Window win);
+void slit_remove_app(struct Slit *slit, struct SlitApp *app,gboolean reparent);
+
+void sighandler(int signal)
+{
+    if (signal == SIGUSR1) 
+        reconfig =TRUE;
+    else
+        quit = TRUE;
+}
+
+int xerrorhandler(Display *d, XErrorEvent *e)
+{
+    char errtxt[128];
+    XGetErrorText(d, e->error_code, errtxt, 127);
+    g_error("X Error: %s", errtxt);
+    return 0;
+}
+
+int main()
+{
+    int i;
+    guint desk = 0xffffffff;
+    XEvent e;
+    XSetWindowAttributes attrib;
+    struct sigaction action;
+    sigset_t sigset;
+    int xfd;
+    fd_set selset;
+
+    /* set up signal handler */
+    sigemptyset(&sigset);
+    action.sa_handler = sighandler;
+    action.sa_mask = sigset;
+    action.sa_flags = SA_NOCLDSTOP;
+    sigaction(SIGUSR1, &action, (struct sigaction *) NULL);
+    sigaction(SIGPIPE, &action, (struct sigaction *) NULL);
+    sigaction(SIGSEGV, &action, (struct sigaction *) NULL);
+    sigaction(SIGFPE, &action, (struct sigaction *) NULL);
+    sigaction(SIGTERM, &action, (struct sigaction *) NULL);
+    sigaction(SIGINT, &action, (struct sigaction *) NULL);
+    sigaction(SIGHUP, &action, (struct sigaction *) NULL);
+
+    ob_display = XOpenDisplay(NULL);
+    ob_screen = DefaultScreen(ob_display);
+    ob_root = RootWindow(ob_display, ob_screen);
+
+   XSetErrorHandler(xerrorhandler);
+
+    render_startup();
+    theme_startup();
+
+    atom_atom = XInternAtom(ob_display, "ATOM", False);
+    atom_card = XInternAtom(ob_display, "CARDINAL", False);
+    atom_theme = XInternAtom(ob_display, "_OPENBOX_THEME", False);
+    atom_type = XInternAtom(ob_display, "_NET_WM_WINDOW_TYPE", False);
+    atom_type_dock = XInternAtom(ob_display, "_NET_WM_WINDOW_TYPE_DOCK",False);
+    atom_desktop =XInternAtom(ob_display, "_NET_WM_DESKTOP", False);
+    atom_state = XInternAtom(ob_display, "WM_STATE", False);
+    atom_strut = XInternAtom(ob_display, "_NET_WM_STRUT", False);
+
+    nslits = 1;
+    slit = g_new0(struct Slit, nslits);
+
+    for (i = 0; i < nslits; ++i) {
+        slit[i].horz = TRUE;
+
+        slit[i].frame = XCreateWindow(ob_display, ob_root, 0, 0, 1, 1, 0,
+                                      render_depth, InputOutput, render_visual,
+                                      0, NULL);
+        attrib.event_mask = TITLE_EVENT_MASK;
+        slit[i].title = XCreateWindow(ob_display, slit[i].frame, 0, 0, 1, 1, 0,
+                                      render_depth, InputOutput, render_visual,
+                                      CWEventMask, &attrib);
+        XMapWindow(ob_display, slit[i].title);
+
+        XChangeProperty(ob_display, slit[i].frame, atom_type, atom_atom,
+                        32, PropModeReplace, (guchar*)&atom_type_dock, 1);
+
+        XChangeProperty(ob_display, slit[i].frame, atom_desktop, atom_card,
+                        32, PropModeReplace, (guchar*)&desk, 1);
+    }
+
+    slit_read_theme();
+
+    XSelectInput(ob_display, ob_root, ROOT_EVENT_MASK);
+
+    slit_add_existing();
+
+    xfd = ConnectionNumber(ob_display);
+    FD_ZERO(&selset);
+    FD_SET(xfd, &selset);
+    while (!quit) {
+        gboolean hadevent = FALSE;
+        while (XPending(ob_display)) {
+            XNextEvent(ob_display, &e);
+            event_handle(&e);
+            hadevent = TRUE;
+        }
+        if (!hadevent) {
+            if (reconfig)
+                slit_read_theme();
+
+            if (!quit)
+                select(xfd + 1, &selset, NULL, NULL, NULL);
+        }
+    }
+
+    for (i = 0; i < nslits; ++i) {
+        while (slit[i].slit_apps)
+            slit_remove_app(&slit[i], slit[i].slit_apps->data, TRUE);
+
+        XDestroyWindow(ob_display, slit[i].title);
+        XDestroyWindow(ob_display, slit[i].frame);
+
+        appearance_free(slit[i].a_frame);
+        appearance_free(slit[i].a_title);
+    }
+
+    theme_shutdown();
+    render_shutdown();
+    XCloseDisplay(ob_display);
+    return 0;
+}
+
+Window find_client(Window win)
+{
+  Window r, *children;
+  unsigned int n, i;
+  Atom ret_type;
+  int ret_format;
+  unsigned long ret_items, ret_bytesleft;
+  unsigned long *prop_return;
+
+  XQueryTree(ob_display, win, &r, &r, &children, &n);
+  for (i = 0; i < n; ++i) {
+    Window w = find_client(children[i]);
+    if (w) return w;
+  }
+
+  /* try me */
+  XGetWindowProperty(ob_display, win, atom_state, 0, 1,
+                    False, atom_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 event_handle(XEvent *e)
+{
+    int i;
+    Window win;
+    static guint button = 0;
+    int sw, sh;
+    int xpos, ypos;
+    int x, y, g;
+
+    switch (e->type) {
+    case ButtonPress:
+        if (!button) {
+            button = e->xbutton.button;
+        }
+        break;
+    case ButtonRelease:
+        if (button == e->xbutton.button)
+            button = 0;
+        break;
+    case MotionNotify:
+        if (button == 1) {
+            for (i = 0; i < nslits; ++i)
+                if (slit[i].title == e->xmotion.window) {
+                    /* pick a corner and move it */
+                    sw = WidthOfScreen(ScreenOfDisplay(ob_display, ob_screen));
+                    sh = HeightOfScreen(ScreenOfDisplay(ob_display,ob_screen));
+
+                    if (e->xmotion.x_root < sw / 3) /* left edge */
+                        xpos = 0;
+                    else if (e->xmotion.x_root < sw / 3 * 2) /* middle */
+                        xpos = 1;
+                    else /* right edge */
+                        xpos = 2;
+                    if (e->xmotion.y_root < sh / 3) /* top edge */
+                        ypos = 0;
+                    else if (e->xmotion.y_root < sh / 3 * 2) /* middle */
+                        ypos = 1;
+                    else /* bottom edge */
+                        ypos = 2;
+
+                    if (xpos == 1 && ypos == 1)
+                        return; /* cant go in middle middle */
+
+                    if (xpos == 0) {
+                        if (ypos == 0) {
+                            x = 0;
+                            y = 0;
+                            g = NorthWestGravity;
+                        } else if (ypos == 1) {
+                            x = 0;
+                            y = sh / 2;
+                            g = WestGravity;
+                        } else {
+                            x = 0;
+                            y = sh;
+                            g = SouthWestGravity;
+                        }
+                    } else if (xpos == 1) {
+                        if (ypos == 0) {
+                            x = sw / 2;
+                            y = 0;
+                            g = NorthGravity;
+                        } else {
+                            x = sw / 2;
+                            y = sh;
+                            g = SouthGravity;
+                        }
+                    } else {
+                        if (ypos == 0) {
+                            x = sw;
+                            y = 0;
+                            g = NorthEastGravity;
+                        } else if (ypos == 1) {
+                            x = sw;
+                            y = sh / 2;
+                            g = EastGravity;
+                        } else {
+                            x = sw;
+                            y = sh;
+                            g = SouthEastGravity;
+                        }
+                    }
+                    if (x != slit[i].x || y != slit[i].y ||
+                        g != slit[i].gravity) {
+                        slit[i].user_x = x;
+                        slit[i].user_y = y;
+                        slit[i].gravity = g;
+                        slit_configure();
+                    }
+                }
+        }
+        break;
+    case PropertyNotify:
+        g_message("PropertyNotify on 0x%lx", e->xproperty.window);
+        if (e->xproperty.window == ob_root) {
+            if (e->xproperty.atom == atom_theme)
+                slit_read_theme();
+        }
+        break;
+    case ConfigureNotify:
+        g_message("ConfigureNotify on 0x%lx", e->xconfigure.window);
+        if (e->xconfigure.window == ob_root) {
+            slit_configure();
+            return;
+        }
+
+        /* an owned slitapp? */
+        for (i = 0; i < nslits; ++i) {
+            GList *it;
+
+            for (it = slit[i].slit_apps; it; it = it->next) {
+                struct SlitApp *app = it->data;
+                if (e->xconfigure.window == app->icon_win) {
+                    if (app->w != e->xconfigure.width ||
+                        app->h != e->xconfigure.height) {
+                        g_message("w %d h %d w %d h %d",
+                                  app->w, e->xconfigure.width,
+                                  app->h, e->xconfigure.height);
+                        app->w = e->xconfigure.width;
+                        app->h = e->xconfigure.height;
+                        slit_configure();
+                    }
+                    return;
+                }
+            }
+        }
+        break;
+    case MapNotify:
+        g_message("MapNotify on 0x%lx", e->xmap.window);
+
+        win = find_client(e->xmap.window);
+        if (!win) return;
+
+        for (i = 0; i < nslits; ++i)
+            if (win == slit[i].frame)
+                return;
+
+        slit_add_app(win);
+        break;
+    case UnmapNotify:
+        g_message("UnmapNotify on 0x%lx", e->xunmap.window);
+        for (i = 0; i < nslits; ++i) {
+            GList *it;
+
+            for (it = slit[i].slit_apps; it; it = it->next) {
+                struct SlitApp *app = it->data;
+                if (e->xunmap.window == app->icon_win) {
+                    gboolean r;
+                    XEvent e;
+
+                    r = !XCheckTypedWindowEvent(ob_display, app->icon_win,
+                                                DestroyNotify, &e);
+                    if (r) {
+                        if (XCheckTypedWindowEvent(ob_display, app->icon_win,
+                                                   ReparentNotify, &e)) {
+                            XPutBackEvent(ob_display, &e);
+                            r = FALSE;
+                        }
+                    }
+                    slit_remove_app(&slit[i], app, r);
+                    break;
+                }
+            }
+        }
+        break;
+    case ReparentNotify:
+        g_message("ReparentNotify on 0x%lx", e->xdestroywindow.window);
+        for (i = 0; i < nslits; ++i) {
+            GList *it;
+
+            for (it = slit[i].slit_apps; it; it = it->next) {
+                struct SlitApp *app = it->data;
+                if (e->xdestroywindow.window == app->icon_win) {
+                    slit_remove_app(&slit[i], app, FALSE);
+                    break;
+                }
+            }
+        }
+    case DestroyNotify:
+        g_message("DestroyNotify on 0x%lx", e->xdestroywindow.window);
+        for (i = 0; i < nslits; ++i) {
+            GList *it;
+
+            for (it = slit[i].slit_apps; it; it = it->next) {
+                struct SlitApp *app = it->data;
+                if (e->xdestroywindow.window == app->icon_win) {
+                    slit_remove_app(&slit[i], app, FALSE);
+                    break;
+                }
+            }
+        }
+        break;
+    }
+}
+
+void slit_add_existing()
+{
+    unsigned int i, nchild;
+    int j;
+    Window w, *children;
+    XWindowAttributes attrib;
+
+    XQueryTree(ob_display, ob_root, &w, &w, &children, &nchild);
+
+    for (i = 0; i < nchild; ++i) {
+        for (j = 0; j < nslits; ++j)
+            if (children[i] == slit[j].frame)
+                continue;
+        if (children[i] == None)
+            continue;
+        if ((children[i] = find_client(children[i])) == None)
+            continue;
+       if (XGetWindowAttributes(ob_display, children[i], &attrib)) {
+           if (attrib.override_redirect) continue;
+
+            slit_add_app(children[i]);
+       }
+    }
+    XFree(children);
+}
+
+void slit_add_app(Window win)
+{
+    int i;
+    XWMHints *h;
+    XWindowAttributes attrib;
+    struct Slit *s;
+
+    s = &slit[0];
+
+    if ((h = XGetWMHints(ob_display, win))) {
+        if (h->flags & StateHint && h->initial_state == WithdrawnState) {
+            struct SlitApp *app = g_new(struct SlitApp, 1);
+
+            app->win = win;
+            app->icon_win = (h->flags & IconWindowHint) ?
+                h->icon_window : win;
+
+            XFree(h);
+
+            for (i = 0; i < nslits; ++i) {
+                GList *it;
+                for (it = slit[i].slit_apps; it; it = it->next)
+                    if (app->icon_win ==
+                        ((struct SlitApp*)it->data)->icon_win)
+                        /* already managed! */
+                        return;
+            }
+
+            if (XGetWindowAttributes(ob_display, app->icon_win, &attrib)) {
+                app->w = attrib.width;
+                app->h = attrib.height;
+            } else {
+                g_free(app);
+                app = NULL;
+            }
+
+            if (app) {
+                s->slit_apps = g_list_append(s->slit_apps, app);
+                slit_configure();
+                XReparentWindow(ob_display, app->icon_win,
+                                s->frame, app->x, app->y);
+/*                if (app->win != app->icon_win)
+                  XUnmapWindow(ob_display, app->win);*/
+                XSync(ob_display, False);
+                XSelectInput(ob_display, app->icon_win,
+                             SLITAPP_EVENT_MASK);
+            }
+            g_message("Managed: 0x%lx", app->icon_win);
+        } else
+            XFree(h);
+    }
+}
+
+void slit_remove_app(struct Slit *slit, struct SlitApp *app, gboolean reparent)
+{
+
+    XSelectInput(ob_display, app->icon_win, NoEventMask);
+    XSync(ob_display, False);
+    if (reparent) {
+        g_message("reparenting");
+/*        if (app->win != app->icon_win)
+          XMapWindow(ob_display, app->win);*/
+        XReparentWindow(ob_display, app->icon_win, ob_root, 0, 0);
+    }
+
+    g_free(app);
+    slit->slit_apps = g_list_remove(slit->slit_apps, app);
+    slit_configure();
+}
+
+void slit_read_theme()
+{
+    XTextProperty prop;
+    int i;
+    char *theme = NULL;
+
+    if (XGetTextProperty(ob_display, ob_root, &prop,
+                         XInternAtom(ob_display, "_OPENBOX_THEME", False))) {
+        theme = theme_load((char*)prop.value);
+        XFree(prop.value);
+    } else
+        theme = theme_load(NULL);
+    g_free(theme);
+    if (!theme) exit(EXIT_FAILURE);
+
+    for (i = 0; i < nslits; ++i) {
+        appearance_free(slit[i].a_frame);
+        appearance_free(slit[i].a_title);
+
+        slit[i].a_frame = appearance_copy(theme_a_unfocused_title);
+        slit[i].a_title = appearance_copy(theme_a_unfocused_title);
+
+        XSetWindowBorder(ob_display, slit[i].frame, theme_b_color->pixel);
+        XSetWindowBorderWidth(ob_display, slit[i].frame, theme_bwidth);
+        XSetWindowBorder(ob_display, slit[i].frame, BlackPixel(ob_display, ob_screen));
+        XSetWindowBorderWidth(ob_display, slit[i].frame, 30);
+    }
+
+    slit_configure();
+}
+
+void slit_configure()
+{
+    int i;
+    int titleh;
+    GList *it;
+    int spot;
+
+    titleh = 4;
+
+    for (i = 0; i < nslits; ++i) {
+        if (slit[i].horz) {
+            slit[i].w = titleh;
+            slit[i].h = 0;
+        } else {
+            slit[i].w = 0;
+            slit[i].h = titleh;
+        }
+        spot = titleh;
+
+        for (it = slit[i].slit_apps; it; it = it->next) {
+            struct SlitApp *app = it->data;
+            if (slit[i].horz) {
+                g_message("%d", spot);
+                app->x = spot;
+                app->y = 0;
+                slit[i].w += app->w;
+                slit[i].h = MAX(slit[i].h, app->h);
+                spot += app->w;
+            } else {
+                app->x = 0;
+                app->y = spot;
+                slit[i].w = MAX(slit[i].h, app->w);
+                slit[i].h += app->h;
+                spot += app->h;
+            }
+
+            XMoveWindow(ob_display, app->icon_win, app->x, app->y);
+        }
+
+        /* calculate position */
+        slit[i].x = slit[i].user_x;
+        slit[i].y = slit[i].user_y;
+
+        switch(slit[i].gravity) {
+        case NorthGravity:
+        case CenterGravity:
+        case SouthGravity:
+            slit[i].x -= slit[i].w / 2;
+            break;
+        case NorthEastGravity:
+        case EastGravity:
+        case SouthEastGravity:
+            slit[i].x -= slit[i].w;
+            break;
+        }
+        switch(slit[i].gravity) {
+        case WestGravity:
+        case CenterGravity:
+        case EastGravity:
+            slit[i].y -= slit[i].h / 2;
+            break;
+        case SouthWestGravity:
+        case SouthGravity:
+        case SouthEastGravity:
+            slit[i].y -= slit[i].h;
+            break;
+        }
+
+        if (slit[i].w > 0 && slit[i].h > 0) {
+            RECT_SET(slit[i].a_frame->area, 0, 0, slit[i].w, slit[i].h);
+            XMoveResizeWindow(ob_display, slit[i].frame,
+                              slit[i].x - theme_bwidth,
+                              slit[i].y - theme_bwidth,
+                              slit[i].w, slit[i].h);
+
+            if (slit[i].horz) {
+                RECT_SET(slit[i].a_title->area, 0, 0, titleh, slit[i].h);
+                XMoveResizeWindow(ob_display, slit[i].title, 0, 0,
+                                  titleh, slit[i].h);
+            } else {
+                RECT_SET(slit[i].a_title->area, 0, 0, slit[i].w, titleh);
+                XMoveResizeWindow(ob_display, slit[i].title, 0, 0,
+                                  slit[i].w, titleh);
+            }
+
+            paint(slit[i].frame, slit[i].a_frame);
+            paint(slit[i].title, slit[i].a_title);
+            XMapWindow(ob_display, slit[i].frame);
+        } else
+            XUnmapWindow(ob_display, slit[i].frame);
+    }
+}