]> Dogcows Code - chaz/openbox/blobdiff - openbox/slit.c
grab button events on the slit so they dont go through to root
[chaz/openbox] / openbox / slit.c
index 1ed32a24e56c784a2e4986e9d30cb2eb20341238..a5d8be3b6666188845ef4fc0d8658f112b3f6502 100644 (file)
@@ -1,13 +1,13 @@
 #include "slit.h"
 #include "screen.h"
+#include "grab.h"
+#include "timer.h"
 #include "openbox.h"
 #include "render/theme.h"
 #include "render/render.h"
 
-#ifdef HAVE_LIMITS_H
-#  include <limits.h>
-#endif
-
+#define SLIT_EVENT_MASK (ButtonPressMask | ButtonReleaseMask | \
+                         EnterWindowMask | LeaveWindowMask)
 #define SLITAPP_EVENT_MASK (StructureNotifyMask)
 
 struct Slit {
@@ -23,17 +23,24 @@ struct Slit {
     int w, h;
 
     gboolean horz;
+    gboolean hide;
+    gboolean hidden;
 
     Appearance *a_frame;
 
+    Timer *hide_timer;
+
     GList *slit_apps;
 };
 
 GHashTable *slit_map = NULL;
+GHashTable *slit_app_map = NULL;
 
 static Slit *slit;
 static int nslits;
 
+static guint slit_hide_timeout = 3000; /* XXX make a config option */
+
 static void slit_configure(Slit *self);
 
 void slit_startup()
@@ -42,20 +49,28 @@ void slit_startup()
     int i;
 
     slit_map = g_hash_table_new(g_int_hash, g_int_equal);
+    slit_app_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;
+        slit[i].horz = FALSE;
+        slit[i].hide = FALSE;
+        slit[i].hidden = TRUE;
+        slit[i].pos = SlitPos_TopRight;
 
+        attrib.event_mask = SLIT_EVENT_MASK;
         attrib.override_redirect = True;
         slit[i].frame = XCreateWindow(ob_display, ob_root, 0, 0, 1, 1, 0,
                                       render_depth, InputOutput, render_visual,
-                                      CWOverrideRedirect, &attrib);
+                                      CWOverrideRedirect | CWEventMask,
+                                      &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);
+
+        g_hash_table_insert(slit_map, &slit[i].frame, &slit[i]);
     }
 }
 
@@ -66,13 +81,17 @@ void slit_shutdown()
     for (i = 0; i < nslits; ++i) {
         XDestroyWindow(ob_display, slit[i].frame);
         appearance_free(slit[i].a_frame);
+        g_hash_table_remove(slit_map, &slit[i].frame);
     }
+    g_hash_table_destroy(slit_app_map);
+    g_hash_table_destroy(slit_map);
 }
 
-void slit_add(Window win, XWMHints *wmhints, XWindowAttributes *attrib)
+void slit_add(Window win, XWMHints *wmhints)
 {
     Slit *s;
     SlitApp *app;
+    XWindowAttributes attrib;
 
     /* XXX pick a slit */
     s = &slit[0];
@@ -83,13 +102,17 @@ void slit_add(Window win, XWMHints *wmhints, XWindowAttributes *attrib)
     app->icon_win = (wmhints->flags & IconWindowHint) ?
         wmhints->icon_window : win;
     
-    app->w = attrib->width;
-    app->h = attrib->height;
+    if (XGetWindowAttributes(ob_display, app->icon_win, &attrib)) {
+        app->w = attrib.width;
+        app->h = attrib.height;
+    } else {
+        app->w = app->h = 64;
+    }
 
     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);
 
+    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
@@ -100,8 +123,11 @@ void slit_add(Window win, XWMHints *wmhints, XWindowAttributes *attrib)
     if (ob_state == State_Starting)
        app->ignore_unmaps += 2;
 
-    if (app->win != app->icon_win)
-        XMoveWindow(ob_display, app->win, 100, 100);
+    if (app->win != app->icon_win) {
+        /* have to map it so that it can be re-managed on a restart */
+        XMoveWindow(ob_display, app->win, -1000, -1000);
+        XMapWindow(ob_display, app->win);
+    }
     XMapWindow(ob_display, app->icon_win);
     XSync(ob_display, False);
 
@@ -110,7 +136,10 @@ void slit_add(Window win, XWMHints *wmhints, XWindowAttributes *attrib)
     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);
+    grab_button_full(2, 0, app->icon_win, ButtonMotionMask, GrabModeAsync,
+                     ob_cursors.move);
+
+    g_hash_table_insert(slit_app_map, &app->icon_win, app);
 
     g_message("Managed Slit App: 0x%lx", app->icon_win);
 }
@@ -126,12 +155,13 @@ void slit_remove_all()
 
 void slit_remove(SlitApp *app, gboolean reparent)
 {
+    ungrab_button(2, 0, app->icon_win);
     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);
+    g_hash_table_remove(slit_app_map, &app->icon_win);
 
     if (reparent)
        XReparentWindow(ob_display, app->icon_win, ob_root, app->x, app->y);
@@ -167,7 +197,7 @@ static void slit_configure(Slit *self)
         } else {
             app->x = 0;
             app->y = spot;
-            self->w = MAX(self->h, app->w);
+            self->w = MAX(self->w, app->w);
             self->h += app->h;
             spot += app->h;
         }
@@ -179,71 +209,123 @@ static void slit_configure(Slit *self)
     self->w += theme_bwidth * 2;
     self->h += theme_bwidth * 2;
 
+    /* calculate position */
     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;
+        self->gravity = NorthWestGravity;
         break;
     case SlitPos_Top:
-        self->x = (screen_physical_size.width - self->w) / 2;
+        self->x = screen_physical_size.width / 2;
         self->y = 0;
+        self->gravity = NorthGravity;
         break;
     case SlitPos_TopRight:
-        self->x = screen_physical_size.width - self->w;
+        self->x = screen_physical_size.width;
         self->y = 0;
+        self->gravity = NorthEastGravity;
         break;
     case SlitPos_Left:
         self->x = 0;
-        self->y = (screen_physical_size.height - self->h) / 2;
+        self->y = screen_physical_size.height / 2;
+        self->gravity = WestGravity;
         break;
     case SlitPos_Right:
-        self->x = screen_physical_size.width - self->w;
-        self->y = (screen_physical_size.height - self->h) / 2;
+        self->x = screen_physical_size.width;
+        self->y = screen_physical_size.height / 2;
+        self->gravity = EastGravity;
         break;
     case SlitPos_BottomLeft:
         self->x = 0;
-        self->y = screen_physical_size.height - self->h;
+        self->y = screen_physical_size.height;
+        self->gravity = SouthWestGravity;
         break;
     case SlitPos_Bottom:
-        self->x = (screen_physical_size.width - self->w) / 2;
-        self->y = screen_physical_size.height - self->h;
+        self->x = screen_physical_size.width / 2;
+        self->y = screen_physical_size.height;
+        self->gravity = SouthGravity;
         break;
     case SlitPos_BottomRight:
-        self->x = screen_physical_size.width - self->w;
-        self->y = screen_physical_size.height - self->h;
+        self->x = screen_physical_size.width;
+        self->y = screen_physical_size.height;
+        self->gravity = SouthEastGravity;
+        break;
+    }
+
+    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;
     }
 
+    if (self->hide && self->hidden) {
+        g_message("hidden");
+        switch (self->pos) {
+        case SlitPos_Floating:
+            break;
+        case SlitPos_TopLeft:
+            if (self->horz)
+                self->y -= self->h - theme_bwidth;
+            else
+                self->x -= self->w - theme_bwidth;
+            break;
+        case SlitPos_Top:
+            self->y -= self->h - theme_bwidth;
+            break;
+        case SlitPos_TopRight:
+            if (self->horz)
+                self->y -= self->h - theme_bwidth;
+            else
+                self->x += self->w - theme_bwidth;
+            break;
+        case SlitPos_Left:
+            self->x -= self->w - theme_bwidth;
+            break;
+        case SlitPos_Right:
+            self->x += self->w - theme_bwidth;
+            break;
+        case SlitPos_BottomLeft:
+            if (self->horz)
+                self->y += self->h - theme_bwidth;
+            else
+                self->x -= self->w - theme_bwidth;
+            break;
+        case SlitPos_Bottom:
+            self->y += self->h - theme_bwidth;
+            break;
+        case SlitPos_BottomRight:
+            if (self->horz)
+                self->y += self->h - theme_bwidth;
+            else
+                self->x += self->w - theme_bwidth;
+            break;
+        }    
+    }
+
     /* not used for actually sizing shit */
     self->w -= theme_bwidth * 2;
     self->h -= theme_bwidth * 2;
@@ -257,4 +339,105 @@ static void slit_configure(Slit *self)
         XMapWindow(ob_display, self->frame);
     } else
         XUnmapWindow(ob_display, self->frame);
+
+    /* but they are useful outside of this function! */
+    self->w += theme_bwidth * 2;
+    self->h += theme_bwidth * 2;
+}
+
+void slit_app_configure(SlitApp *app, int w, int h)
+{
+    app->w = w;
+    app->h = h;
+    slit_configure(app->slit);
+}
+
+void slit_app_drag(SlitApp *app, XMotionEvent *e)
+{
+    Slit *src, *dest = NULL;
+    SlitApp *over = NULL;
+    GList *it;
+    int i;
+    int x, y;
+    gboolean after;
+
+    src = app->slit;
+    x = e->x_root;
+    y = e->y_root;
+
+    /* which slit are we on top of? */
+    for (i = 0; i < nslits; ++i)
+        if (x >= slit[i].x &&
+            y >= slit[i].y &&
+            x < slit[i].x + slit[i].w &&
+            y < slit[i].y + slit[i].h) {
+            dest = &slit[i];
+            break;
+        }
+    if (!dest) return;
+
+    x -= dest->x;
+    y -= dest->y;
+
+    /* which slit app are we on top of? */
+    for (it = dest->slit_apps; it; it = it->next) {
+        over = it->data;
+        if (dest->horz) {
+            if (x >= over->x && x < over->x + over->w)
+                break;
+        } else {
+            if (y >= over->y && y < over->y + over->h)
+                break;
+        }
+    }
+    if (!it || app == over) return;
+
+    x -= over->x;
+    y -= over->y;
+
+    if (dest->horz)
+        after = (x > over->w / 2);
+    else
+        after = (y > over->h / 2);
+
+    /* remove before doing the it->next! */
+    src->slit_apps = g_list_remove(src->slit_apps, app);
+    if (src != dest) slit_configure(src);
+
+    if (after) it = it->next;
+
+    dest->slit_apps = g_list_insert_before(dest->slit_apps, it, app);
+    slit_configure(dest);
+}
+
+static void hide_timeout(Slit *self)
+{
+    /* dont repeat */
+    timer_stop(self->hide_timer);
+    self->hide_timer = NULL;
+
+    /* hide */
+    self->hidden = TRUE;
+    slit_configure(self);
+}
+
+void slit_hide(Slit *self, gboolean hide)
+{
+    if (self->hidden == hide || !self->hide)
+        return;
+    if (!hide) {
+        /* show */
+        self->hidden = FALSE;
+        slit_configure(self);
+
+        /* if was hiding, stop it */
+        if (self->hide_timer) {
+            timer_stop(self->hide_timer);
+            self->hide_timer = NULL;
+        }
+    } else {
+        g_assert(!self->hide_timer);
+        self->hide_timer = timer_start(slit_hide_timeout * 1000,
+                                       (TimeoutHandler)hide_timeout, self);
+    }
 }
This page took 0.029027 seconds and 4 git commands to generate.