add a slit to the kernel
authorDana Jansens <danakj@orodu.net>
Sat, 10 May 2003 20:52:32 +0000 (20:52 +0000)
committerDana Jansens <danakj@orodu.net>
Sat, 10 May 2003 20:52:32 +0000 (20:52 +0000)
openbox/Makefile.am
openbox/client.c
openbox/event.c
openbox/frame.c
openbox/openbox.c
openbox/screen.c
openbox/slit.c [new file with mode: 0644]
openbox/slit.h [new file with mode: 0644]

index 8e027dd..e860580 100644 (file)
@@ -26,12 +26,13 @@ openbox3_SOURCES=parse.tab.c parse.lex.c action.c client.c config.c \
                  extensions.c focus.c frame.c grab.c menu.c menu_render.c \
                  openbox.c framerender.c parse.c plugin.c prop.c screen.c \
                  stacking.c dispatch.c event.c group.c timer.c xerror.c \
-                 moveresize.c startup.c popup.c
+                 moveresize.c startup.c popup.c slit.c
 
 noinst_HEADERS=action.h client.h config.h dispatch.h event.h extensions.h \
                focus.h frame.h framerender.h geom.h gettext.h grab.h group.h \
                menu.h openbox.h parse.h parse.tab.h plugin.h prop.h screen.h \
-               stacking.h timer.h xerror.h moveresize.h startup.h popup.h
+               stacking.h timer.h xerror.h moveresize.h startup.h popup.h \
+               slit.h
 
 # kill the implicit .c.y rule
 %.c: %.y
index dd25e4d..29a20ad 100644 (file)
@@ -1,4 +1,5 @@
 #include "client.h"
+#include "slit.h"
 #include "startup.h"
 #include "screen.h"
 #include "moveresize.h"
@@ -176,7 +177,7 @@ void client_manage(Window window)
     XEvent e;
     XWindowAttributes attrib;
     XSetWindowAttributes attrib_set;
-/*    XWMHints *wmhint; */
+    XWMHints *wmhint;
 
     grab_server(TRUE);
 
@@ -197,18 +198,18 @@ void client_manage(Window window)
        return; /* don't manage it */
     }
   
-/*    /\* is the window a docking app *\/
+    /* is the window a docking app */
     if ((wmhint = XGetWMHints(ob_display, window))) {
        if ((wmhint->flags & StateHint) &&
            wmhint->initial_state == WithdrawnState) {
-           /\* XXX: make dock apps work! *\/
+            slit_add(window, wmhint, &attrib);
             grab_server(FALSE);
            XFree(wmhint);
            return;
        }
        XFree(wmhint);
     }
-*/
+
     g_message("Managing window: %lx", window);
 
     /* choose the events we want to receive on the CLIENT window */
index 02ead5b..c96583d 100644 (file)
@@ -1,4 +1,5 @@
 #include "openbox.h"
+#include "slit.h"
 #include "client.h"
 #include "xerror.h"
 #include "prop.h"
@@ -23,6 +24,7 @@
 
 static void event_process(XEvent *e);
 static void event_handle_root(XEvent *e);
+static void event_handle_slitapp(SlitApp *app, XEvent *e);
 static void event_handle_client(Client *c, XEvent *e);
 static void event_handle_menu(Menu *menu, XEvent *e);
 
@@ -373,12 +375,14 @@ static gboolean event_ignore(XEvent *e, Client *client)
 static void event_process(XEvent *e)
 {
     Window window;
-    Client *client;
+    Client *client = NULL;
+    SlitApp *slitapp = NULL;
     Menu *menu = NULL;
 
     window = event_get_window(e);
     if (!(client = g_hash_table_lookup(client_map, &window)))
-        menu = g_hash_table_lookup(menu_map, &window);
+        if (!(slitapp = g_hash_table_lookup(slit_map, &window)))
+            menu = g_hash_table_lookup(menu_map, &window);
 
     event_set_lasttime(e);
     event_hack_mods(e);
@@ -391,6 +395,8 @@ static void event_process(XEvent *e)
         return;
     } else if (client)
        event_handle_client(client, e);
+    else if (slitapp)
+       event_handle_slitapp(slitapp, e);
     else if (window == ob_root)
        event_handle_root(e);
     else if (e->type == MapRequest)
@@ -901,3 +907,22 @@ static void event_handle_menu(Menu *menu, XEvent *e)
        }
     }
 }
+
+static void event_handle_slitapp(SlitApp *app, XEvent *e)
+{
+    switch (e->type) {
+    case UnmapNotify:
+       if (app->ignore_unmaps) {
+           app->ignore_unmaps--;
+           break;
+       }
+       slit_remove(app, TRUE);
+       break;
+    case DestroyNotify:
+       slit_remove(app, FALSE);
+       break;
+    case ReparentNotify:
+       slit_remove(app, FALSE);
+       break;
+    }
+}
index f344f9e..d714b69 100644 (file)
@@ -456,8 +456,12 @@ void frame_release_client(Frame *self, Client *client)
     if (XCheckTypedWindowEvent(ob_display, client->window,
                               ReparentNotify, &ev)) {
        XPutBackEvent(ob_display, &ev);
+
        /* re-map the window since the unmanaging process unmaps it */
-       XMapWindow(ob_display, client->window);
+
+        /* XXX ... um no it doesnt it unmaps its parent, the window itself
+           retains its mapped state, no?! XXX
+           XMapWindow(ob_display, client->window); */
     } else {
        /* according to the ICCCM - if the client doesn't reparent itself,
           then we will reparent the window to root for them */
index 8c599c4..4792396 100644 (file)
@@ -1,4 +1,5 @@
 #include "openbox.h"
+#include "slit.h"
 #include "event.h"
 #include "menu.h"
 #include "client.h"
@@ -191,6 +192,7 @@ int main(int argc, char **argv)
        screen_startup();
         group_startup();
        client_startup();
+        slit_startup();
 
         /* call startup for all the plugins */
         plugin_startall();
@@ -203,9 +205,11 @@ int main(int argc, char **argv)
            event_loop();
        ob_state = State_Exiting;
 
+        slit_remove_all();
        client_unmanage_all();
 
         plugin_shutdown(); /* calls all the plugins' shutdown functions */
+        slit_shutdown();
        client_shutdown();
         group_shutdown();
        screen_shutdown();
index 04bc21c..b43be92 100644 (file)
@@ -1,4 +1,5 @@
 #include "openbox.h"
+#include "slit.h"
 #include "prop.h"
 #include "startup.h"
 #include "config.h"
@@ -218,6 +219,7 @@ void screen_resize(int w, int h)
     if (ob_state == State_Starting)
        return;
 
+    slit_configure_all();
     screen_update_struts();
 
     for (it = client_list; it; it = it->next)
diff --git a/openbox/slit.c b/openbox/slit.c
new file mode 100644 (file)
index 0000000..1ed32a2
--- /dev/null
@@ -0,0 +1,260 @@
+#include "slit.h"
+#include "screen.h"
+#include "openbox.h"
+#include "render/theme.h"
+#include "render/render.h"
+
+#ifdef HAVE_LIMITS_H
+#  include <limits.h>
+#endif
+
+#define SLITAPP_EVENT_MASK (StructureNotifyMask)
+
+struct Slit {
+    Window frame;
+
+    /* user-requested position stuff */
+    SlitPosition pos;
+    int gravity;
+    int user_x, user_y;
+
+    /* actual position (when not auto-hidden) */
+    int x, y;
+    int w, h;
+
+    gboolean horz;
+
+    Appearance *a_frame;
+
+    GList *slit_apps;
+};
+
+GHashTable *slit_map = NULL;
+
+static Slit *slit;
+static int nslits;
+
+static void slit_configure(Slit *self);
+
+void slit_startup()
+{
+    XSetWindowAttributes attrib;
+    int i;
+
+    slit_map = g_hash_table_new(g_int_hash, g_int_equal);
+
+    nslits = 1;
+    slit = g_new0(struct Slit, nslits);
+
+    for (i = 0; i < nslits; ++i) {
+        slit[i].horz = TRUE;
+
+        attrib.override_redirect = True;
+        slit[i].frame = XCreateWindow(ob_display, ob_root, 0, 0, 1, 1, 0,
+                                      render_depth, InputOutput, render_visual,
+                                      CWOverrideRedirect, &attrib);
+        slit[i].a_frame = appearance_copy(theme_a_unfocused_title);
+        XSetWindowBorder(ob_display, slit[i].frame, theme_b_color->pixel);
+        XSetWindowBorderWidth(ob_display, slit[i].frame, theme_bwidth);
+    }
+}
+
+void slit_shutdown()
+{
+    int i;
+
+    for (i = 0; i < nslits; ++i) {
+        XDestroyWindow(ob_display, slit[i].frame);
+        appearance_free(slit[i].a_frame);
+    }
+}
+
+void slit_add(Window win, XWMHints *wmhints, XWindowAttributes *attrib)
+{
+    Slit *s;
+    SlitApp *app;
+
+    /* XXX pick a slit */
+    s = &slit[0];
+
+    app = g_new0(SlitApp, 1);
+    app->slit = s;
+    app->win = win;
+    app->icon_win = (wmhints->flags & IconWindowHint) ?
+        wmhints->icon_window : win;
+    
+    app->w = attrib->width;
+    app->h = attrib->height;
+
+    s->slit_apps = g_list_append(s->slit_apps, app);
+    slit_configure(s);
+    XReparentWindow(ob_display, app->icon_win, s->frame, app->x, app->y);
+
+    /*
+      This is the same case as in frame.c for client windows. When Openbox is
+      starting, the window is already mapped so we see unmap events occur for
+      it. There are 2 unmap events generated that we see, one with the 'event'
+      member set the root window, and one set to the client, but both get
+      handled and need to be ignored.
+    */
+    if (ob_state == State_Starting)
+       app->ignore_unmaps += 2;
+
+    if (app->win != app->icon_win)
+        XMoveWindow(ob_display, app->win, 100, 100);
+    XMapWindow(ob_display, app->icon_win);
+    XSync(ob_display, False);
+
+    /* specify that if we exit, the window should not be destroyed and should
+       be reparented back to root automatically */
+    XChangeSaveSet(ob_display, app->icon_win, SetModeInsert);
+    XSelectInput(ob_display, app->icon_win, SLITAPP_EVENT_MASK);
+
+    g_hash_table_insert(slit_map, &app->icon_win, app);
+
+    g_message("Managed Slit App: 0x%lx", app->icon_win);
+}
+
+void slit_remove_all()
+{
+    int i;
+
+    for (i = 0; i < nslits; ++i)
+        while (slit[i].slit_apps)
+            slit_remove(slit[i].slit_apps->data, TRUE);
+}
+
+void slit_remove(SlitApp *app, gboolean reparent)
+{
+    XSelectInput(ob_display, app->icon_win, NoEventMask);
+    /* remove the window from our save set */
+    XChangeSaveSet(ob_display, app->icon_win, SetModeDelete);
+    XSync(ob_display, False);
+
+    g_hash_table_remove(slit_map, &app->icon_win);
+
+    if (reparent)
+       XReparentWindow(ob_display, app->icon_win, ob_root, app->x, app->y);
+
+    app->slit->slit_apps = g_list_remove(app->slit->slit_apps, app);
+    slit_configure(app->slit);
+
+    g_message("Unmanaged Slit App: 0x%lx", app->icon_win);
+
+    g_free(app);
+}
+
+void slit_configure_all()
+{
+    int i; for (i = 0; i < nslits; ++i) slit_configure(&slit[i]);
+}
+
+static void slit_configure(Slit *self)
+{
+    GList *it;
+    int spot;
+
+    self->w = self->h = spot = 0;
+
+    for (it = self->slit_apps; it; it = it->next) {
+        struct SlitApp *app = it->data;
+        if (self->horz) {
+            app->x = spot;
+            app->y = 0;
+            self->w += app->w;
+            self->h = MAX(self->h, app->h);
+            spot += app->w;
+        } else {
+            app->x = 0;
+            app->y = spot;
+            self->w = MAX(self->h, app->w);
+            self->h += app->h;
+            spot += app->h;
+        }
+
+        XMoveWindow(ob_display, app->icon_win, app->x, app->y);
+    }
+
+    /* used for calculating offsets */
+    self->w += theme_bwidth * 2;
+    self->h += theme_bwidth * 2;
+
+    switch (self->pos) {
+    case SlitPos_Floating:
+        /* calculate position */
+        self->x = self->user_x;
+        self->y = self->user_y;
+
+        switch(self->gravity) {
+        case NorthGravity:
+        case CenterGravity:
+        case SouthGravity:
+            self->x -= self->w / 2;
+            break;
+        case NorthEastGravity:
+        case EastGravity:
+        case SouthEastGravity:
+            self->x -= self->w;
+            break;
+        }
+        switch(self->gravity) {
+        case WestGravity:
+        case CenterGravity:
+        case EastGravity:
+            self->y -= self->h / 2;
+            break;
+        case SouthWestGravity:
+        case SouthGravity:
+        case SouthEastGravity:
+            self->y -= self->h;
+            break;
+        }
+        break;
+    case SlitPos_TopLeft:
+        self->x = 0;
+        self->y = 0;
+        break;
+    case SlitPos_Top:
+        self->x = (screen_physical_size.width - self->w) / 2;
+        self->y = 0;
+        break;
+    case SlitPos_TopRight:
+        self->x = screen_physical_size.width - self->w;
+        self->y = 0;
+        break;
+    case SlitPos_Left:
+        self->x = 0;
+        self->y = (screen_physical_size.height - self->h) / 2;
+        break;
+    case SlitPos_Right:
+        self->x = screen_physical_size.width - self->w;
+        self->y = (screen_physical_size.height - self->h) / 2;
+        break;
+    case SlitPos_BottomLeft:
+        self->x = 0;
+        self->y = screen_physical_size.height - self->h;
+        break;
+    case SlitPos_Bottom:
+        self->x = (screen_physical_size.width - self->w) / 2;
+        self->y = screen_physical_size.height - self->h;
+        break;
+    case SlitPos_BottomRight:
+        self->x = screen_physical_size.width - self->w;
+        self->y = screen_physical_size.height - self->h;
+        break;
+    }
+
+    /* not used for actually sizing shit */
+    self->w -= theme_bwidth * 2;
+    self->h -= theme_bwidth * 2;
+
+    if (self->w > 0 && self->h > 0) {
+        RECT_SET(self->a_frame->area, 0, 0, self->w, self->h);
+        XMoveResizeWindow(ob_display, self->frame,
+                          self->x, self->y, self->w, self->h);
+
+        paint(self->frame, self->a_frame);
+        XMapWindow(ob_display, self->frame);
+    } else
+        XUnmapWindow(ob_display, self->frame);
+}
diff --git a/openbox/slit.h b/openbox/slit.h
new file mode 100644 (file)
index 0000000..f3fce18
--- /dev/null
@@ -0,0 +1,46 @@
+#ifndef __slit_h
+#define __slit_h
+
+#include <glib.h>
+#include <X11/Xlib.h>
+#include <X11/Xutil.h>
+
+typedef struct Slit Slit;
+
+typedef struct SlitApp {
+    int ignore_unmaps;
+
+    Slit *slit;
+    Window icon_win;
+    Window win;
+    int x;
+    int y;
+    int w;
+    int h;
+} SlitApp;
+
+typedef enum {
+    SlitPos_Floating,
+    SlitPos_TopLeft,
+    SlitPos_Top,
+    SlitPos_TopRight,
+    SlitPos_Right,
+    SlitPos_BottomRight,
+    SlitPos_Bottom,
+    SlitPos_BottomLeft,
+    SlitPos_Left
+} SlitPosition;
+
+extern GHashTable *slit_map;
+
+void slit_startup();
+void slit_shutdown();
+
+void slit_configure_all();
+
+void slit_add(Window win, XWMHints *wmhints, XWindowAttributes *attrib);
+
+void slit_remove_all();
+void slit_remove(SlitApp *app, gboolean reparent);
+
+#endif