rewrote the movetoedge code so it works with both types of edges (to edge and from...
authorDana Jansens <danakj@orodu.net>
Thu, 28 Jun 2007 05:18:01 +0000 (05:18 +0000)
committerDana Jansens <danakj@orodu.net>
Thu, 28 Jun 2007 05:18:01 +0000 (05:18 +0000)
openbox/actions/growtoedge.c
openbox/actions/movetofromedge.c
openbox/client.c
openbox/client.h
openbox/moveresize.c

index 5d4647f..a5b24e3 100644 (file)
@@ -74,11 +74,13 @@ static gboolean run_func(ObActionsData *data, gpointer options)
         width = c->area.width + c->frame->size.left + c->frame->size.right;
         height = c->area.height + c->frame->size.top + c->frame->size.bottom;
 
+#if 0
+        dest = client_directional_edge_search(c, o->dir);
+
         switch(o->dir) {
         case OB_DIRECTION_NORTH:
             if (c->shaded) break; /* don't allow vertical resize if shaded */
 
-            dest = client_directional_edge_search(c, o->dir, FALSE);
             if (a->y == y)
                 height = height / 2;
             else {
@@ -87,7 +89,6 @@ static gboolean run_func(ObActionsData *data, gpointer options)
             }
             break;
         case OB_DIRECTION_WEST:
-            dest = client_directional_edge_search(c, o->dir, FALSE);
             if (a->x == x)
                 width = width / 2;
             else {
@@ -98,7 +99,6 @@ static gboolean run_func(ObActionsData *data, gpointer options)
         case OB_DIRECTION_SOUTH:
             if (c->shaded) break; /* don't allow vertical resize if shaded */
 
-            dest = client_directional_edge_search(c, o->dir, FALSE);
             if (a->y + a->height == y + c->frame->area.height) {
                 height = c->frame->area.height / 2;
                 y = a->y + a->height - height;
@@ -108,7 +108,6 @@ static gboolean run_func(ObActionsData *data, gpointer options)
             height -= (height - c->frame->area.height) % c->size_inc.height;
             break;
         case OB_DIRECTION_EAST:
-            dest = client_directional_edge_search(c, o->dir, FALSE);
             if (a->x + a->width == x + c->frame->area.width) {
                 width = c->frame->area.width / 2;
                 x = a->x + a->width - width;
@@ -129,6 +128,7 @@ static gboolean run_func(ObActionsData *data, gpointer options)
         client_move_resize(c, x, y, width, height);
         actions_client_move(data, TRUE);
 
+#endif
         g_free(a);
     }
 
index 72a89c1..8db4509 100644 (file)
@@ -6,24 +6,16 @@
 
 typedef struct {
     ObDirection dir;
-    gboolean hang;
 } Options;
 
 static gpointer setup_func(ObParseInst *i, xmlDocPtr doc, xmlNodePtr node);
-static gpointer setup_to_func(ObParseInst *i, xmlDocPtr doc, xmlNodePtr node);
-static gpointer setup_from_func(ObParseInst *i,xmlDocPtr doc, xmlNodePtr node);
 static void     free_func(gpointer options);
 static gboolean run_func(ObActionsData *data, gpointer options);
 
 void action_movetofromedge_startup()
 {
     actions_register("MoveToEdge",
-                     setup_to_func,
-                     free_func,
-                     run_func,
-                     NULL, NULL);
-    actions_register("MoveFromEdge",
-                     setup_from_func,
+                     setup_func,
                      free_func,
                      run_func,
                      NULL, NULL);
@@ -57,20 +49,6 @@ static gpointer setup_func(ObParseInst *i, xmlDocPtr doc, xmlNodePtr node)
     return o;
 }
 
-static gpointer setup_to_func(ObParseInst *i, xmlDocPtr doc, xmlNodePtr node)
-{
-    Options *o = setup_func(i, doc, node);
-    o->hang = FALSE;
-    return o;
-}
-
-static gpointer setup_from_func(ObParseInst *i, xmlDocPtr doc, xmlNodePtr node)
-{
-    Options *o = setup_func(i, doc, node);
-    o->hang = TRUE;
-    return o;
-}
-
 static void free_func(gpointer options)
 {
     Options *o = options;
@@ -85,40 +63,13 @@ static gboolean run_func(ObActionsData *data, gpointer options)
 
     if (data->client) {
         gint x, y;
-        ObClient *c = data->client;
 
-        x = c->frame->area.x;
-        y = c->frame->area.y;
-    
-        switch(o->dir) {
-        case OB_DIRECTION_NORTH:
-            y = client_directional_edge_search(c, OB_DIRECTION_NORTH,
-                                               o->hang)
-                - (o->hang ? c->frame->area.height : 0);
-            break;
-        case OB_DIRECTION_WEST:
-            x = client_directional_edge_search(c, OB_DIRECTION_WEST,
-                                               o->hang)
-                - (o->hang ? c->frame->area.width : 0);
-            break;
-        case OB_DIRECTION_SOUTH:
-            y = client_directional_edge_search(c, OB_DIRECTION_SOUTH,
-                                               o->hang)
-                - (o->hang ? 0 : c->frame->area.height);
-            break;
-        case OB_DIRECTION_EAST:
-            x = client_directional_edge_search(c, OB_DIRECTION_EAST,
-                                               o->hang)
-                - (o->hang ? 0 : c->frame->area.width);
-            break;
-        default:
-            g_assert_not_reached();
+        client_find_move_directional(data->client, o->dir, &x, &y);
+        if (x != data->client->area.x || y != data->client->area.y) {
+            actions_client_move(data, FALSE);
+            client_move(data->client, x, y);
+            actions_client_move(data, TRUE);
         }
-        frame_frame_gravity(c->frame, &x, &y);
-
-        actions_client_move(data, FALSE);
-        client_move(c, x, y);
-        actions_client_move(data, TRUE);
     }
 
     return FALSE;
index e58cc75..9cbbaf6 100644 (file)
@@ -3883,179 +3883,161 @@ ObClient *client_search_transient(ObClient *self, ObClient *search)
             if (cur->iconic)                                                  \
                 continue;
 
-#define HIT_EDGE(my_edge_start, my_edge_end, his_edge_start, his_edge_end) \
-            if ((his_edge_start >= my_edge_start && \
-                 his_edge_start <= my_edge_end) ||  \
-                (my_edge_start >= his_edge_start && \
-                 my_edge_start <= his_edge_end))    \
-                dest = his_offset;
-
-/* finds the nearest edge in the given direction from the current client
- * note to self: the edge is the -frame- edge (the actual one), not the
- * client edge.
- */
-gint client_directional_edge_search(ObClient *c, ObDirection dir, gboolean hang)
+void client_find_move_directional(ObClient *self, ObDirection dir,
+                                  gint *x, gint *y)
 {
-    gint dest, monitor_dest;
-    gint my_edge_start, my_edge_end, my_offset;
+    gint dest, edge, my_edge_start, my_edge_size, my_pos;
     GList *it;
     Rect *a, *mon;
     
-    if(!client_list)
-        return -1;
+    *x = self->frame->area.x;
+    *y = self->frame->area.y;
 
-    a = screen_area(c->desktop, SCREEN_AREA_ALL_MONITORS, &c->frame->area);
-    mon = screen_area(c->desktop, SCREEN_AREA_ONE_MONITOR, &c->frame->area);
+    a = screen_area(self->desktop, SCREEN_AREA_ALL_MONITORS,
+                    &self->frame->area);
+    mon = screen_area(self->desktop, SCREEN_AREA_ONE_MONITOR,
+                      &self->frame->area);
 
     switch(dir) {
     case OB_DIRECTION_NORTH:
-        my_edge_start = c->frame->area.x;
-        my_edge_end = c->frame->area.x + c->frame->area.width;
-        my_offset = c->frame->area.y + (hang ? c->frame->area.height : 0);
-        
-        /* default: top of screen */
-        dest = a->y + (hang ? c->frame->area.height : 0);
-        monitor_dest = mon->y + (hang ? c->frame->area.height : 0);
-        /* if the monitor edge comes before the screen edge, */
-        /* use that as the destination instead. (For xinerama) */
-        if (monitor_dest != dest && my_offset > monitor_dest)
-            dest = monitor_dest; 
-
-        for(it = client_list; it && my_offset != dest; it = g_list_next(it)) {
-            gint his_edge_start, his_edge_end, his_offset;
-            ObClient *cur = it->data;
-
-            WANT_EDGE(cur, c)
-
-            his_edge_start = cur->frame->area.x;
-            his_edge_end = cur->frame->area.x + cur->frame->area.width;
-            his_offset = cur->frame->area.y + 
-                         (hang ? 0 : cur->frame->area.height);
-
-            if(his_offset + 1 > my_offset)
-                continue;
-
-            if(his_offset < dest)
-                continue;
+    case OB_DIRECTION_SOUTH:
+        my_edge_start = RECT_LEFT(self->frame->area);
+        my_edge_size = self->frame->area.width;
+        my_pos = RECT_TOP(self->frame->area);
+        break;
+    case OB_DIRECTION_EAST:
+    case OB_DIRECTION_WEST:
+        my_edge_start = RECT_TOP(self->frame->area);
+        my_edge_size = self->frame->area.height;
+        my_pos = RECT_LEFT(self->frame->area);
+        break;
+    default:
+        g_assert_not_reached();
+    }
 
-            HIT_EDGE(my_edge_start, my_edge_end, his_edge_start, his_edge_end)
-        }
+    switch(dir) {
+    case OB_DIRECTION_NORTH:
+        if (RECT_TOP(self->frame->area) > RECT_TOP(*mon))
+            edge = RECT_TOP(*mon);
+        else
+            edge = RECT_TOP(*a);
         break;
     case OB_DIRECTION_SOUTH:
-        my_edge_start = c->frame->area.x;
-        my_edge_end = c->frame->area.x + c->frame->area.width;
-        my_offset = c->frame->area.y + (hang ? 0 : c->frame->area.height);
-
-        /* default: bottom of screen */
-        dest = a->y + a->height - (hang ? c->frame->area.height : 0);
-        monitor_dest = mon->y + mon->height -
-                       (hang ? c->frame->area.height : 0);
-        /* if the monitor edge comes before the screen edge, */
-        /* use that as the destination instead. (For xinerama) */
-        if (monitor_dest != dest && my_offset < monitor_dest)
-            dest = monitor_dest; 
+        if (RECT_BOTTOM(self->frame->area) < RECT_BOTTOM(*mon))
+            edge = RECT_BOTTOM(*mon) - self->frame->area.height;
+        else
+            edge = RECT_BOTTOM(*a) - self->frame->area.height;
+        break;
+    case OB_DIRECTION_EAST:
+        if (RECT_RIGHT(self->frame->area) < RECT_RIGHT(*mon))
+            edge = RECT_RIGHT(*mon) - self->frame->area.width;
+        else
+            edge = RECT_RIGHT(*a) - self->frame->area.width;
+        break;
+    case OB_DIRECTION_WEST:
+        if (RECT_LEFT(self->frame->area) > RECT_LEFT(*mon))
+            edge = RECT_LEFT(*mon);
+        else
+            edge = RECT_LEFT(*a);
+        break;
+    default:
+        g_assert_not_reached();
+    }
+    /* default to the far edge, then narrow it down */
+    dest = edge;
 
-        for(it = client_list; it && my_offset != dest; it = g_list_next(it)) {
-            gint his_edge_start, his_edge_end, his_offset;
-            ObClient *cur = it->data;
+    for(it = client_list; it && dest != my_pos; it = g_list_next(it)) {
+        ObClient *cur = it->data;
+        gint edge_start, edge_size, head, tail;
+        gboolean skip_head = FALSE, skip_tail = FALSE;
 
-            WANT_EDGE(cur, c)
+        WANT_EDGE(cur, self); /* skip windows to not bump into */
 
-            his_edge_start = cur->frame->area.x;
-            his_edge_end = cur->frame->area.x + cur->frame->area.width;
-            his_offset = cur->frame->area.y +
-                         (hang ? cur->frame->area.height : 0);
+        switch(dir) {
+        case OB_DIRECTION_NORTH:
+        case OB_DIRECTION_SOUTH:
+            edge_start = cur->frame->area.x;
+            edge_size = cur->frame->area.width;
+            break;
+        case OB_DIRECTION_EAST:
+        case OB_DIRECTION_WEST:
+            edge_start = cur->frame->area.y;
+            edge_size = cur->frame->area.height;
+            break;
+        default:
+            g_assert_not_reached();
+        }
 
+        /* do we collide with this window? */
+        if (!RANGES_INTERSECT(my_edge_start, my_edge_size,
+                              edge_start, edge_size))
+            continue;
 
-            if(his_offset - 1 < my_offset)
-                continue;
-            
-            if(his_offset > dest)
-                continue;
+        switch(dir) {
+        case OB_DIRECTION_NORTH:
+        case OB_DIRECTION_SOUTH:
+            head = RECT_TOP(cur->frame->area) - self->frame->area.height;
+            tail = RECT_BOTTOM(cur->frame->area) + 1;
+            break;
+        case OB_DIRECTION_EAST:
+        case OB_DIRECTION_WEST:
+            head = RECT_LEFT(cur->frame->area) - self->frame->area.width;
+            tail = RECT_RIGHT(cur->frame->area) + 1;
+            break;
+        default:
+            g_assert_not_reached();
+        }
 
-            HIT_EDGE(my_edge_start, my_edge_end, his_edge_start, his_edge_end)
+        switch(dir) {
+        case OB_DIRECTION_NORTH:
+        case OB_DIRECTION_WEST:
+            if (my_pos <= head)
+                skip_head = TRUE;
+            if (my_pos <= tail)
+                skip_tail = TRUE;
+            if (head < edge)
+                skip_head = TRUE;
+            if (tail < edge)
+                skip_tail = TRUE;
+            break;
+        case OB_DIRECTION_SOUTH:
+        case OB_DIRECTION_EAST:
+            if (my_pos >= head)
+                skip_head = TRUE;
+            if (my_pos >= tail)
+                skip_tail = TRUE;
+            if (head > edge)
+                skip_head = TRUE;
+            if (tail > edge)
+                skip_tail = TRUE;
+            break;
+        default:
+            g_assert_not_reached();
         }
-        break;
-    case OB_DIRECTION_WEST:
-        my_edge_start = c->frame->area.y;
-        my_edge_end = c->frame->area.y + c->frame->area.height;
-        my_offset = c->frame->area.x + (hang ? c->frame->area.width : 0);
-
-        /* default: leftmost egde of screen */
-        dest = a->x + (hang ? c->frame->area.width : 0);
-        monitor_dest = mon->x + (hang ? c->frame->area.width : 0);
-        /* if the monitor edge comes before the screen edge, */
-        /* use that as the destination instead. (For xinerama) */
-        if (monitor_dest != dest && my_offset > monitor_dest)
-            dest = monitor_dest;            
-
-        for(it = client_list; it && my_offset != dest; it = g_list_next(it)) {
-            gint his_edge_start, his_edge_end, his_offset;
-            ObClient *cur = it->data;
-
-            WANT_EDGE(cur, c)
-
-            his_edge_start = cur->frame->area.y;
-            his_edge_end = cur->frame->area.y + cur->frame->area.height;
-            his_offset = cur->frame->area.x +
-                         (hang ? 0 : cur->frame->area.width);
-
-            if(his_offset + 1 > my_offset)
-                continue;
 
-            if(his_offset < dest)
-                continue;
+        if (!skip_head)
+            dest = head;
+        else if (!skip_tail)
+            dest = tail;
+    }
 
-            HIT_EDGE(my_edge_start, my_edge_end, his_edge_start, his_edge_end)
-        }
-       break;
+    switch(dir) {
+    case OB_DIRECTION_NORTH:
+    case OB_DIRECTION_SOUTH:
+        *y = dest;
+        break;
+    case OB_DIRECTION_WEST:
     case OB_DIRECTION_EAST:
-        my_edge_start = c->frame->area.y;
-        my_edge_end = c->frame->area.y + c->frame->area.height;
-        my_offset = c->frame->area.x + (hang ? 0 : c->frame->area.width);
-        
-        /* default: rightmost edge of screen */
-        dest = a->x + a->width - (hang ? c->frame->area.width : 0);
-        monitor_dest = mon->x + mon->width -
-                       (hang ? c->frame->area.width : 0);
-        /* if the monitor edge comes before the screen edge, */
-        /* use that as the destination instead. (For xinerama) */
-        if (monitor_dest != dest && my_offset < monitor_dest)
-            dest = monitor_dest;            
-
-        for(it = client_list; it && my_offset != dest; it = g_list_next(it)) {
-            gint his_edge_start, his_edge_end, his_offset;
-            ObClient *cur = it->data;
-
-            WANT_EDGE(cur, c)
-
-            his_edge_start = cur->frame->area.y;
-            his_edge_end = cur->frame->area.y + cur->frame->area.height;
-            his_offset = cur->frame->area.x +
-                         (hang ? cur->frame->area.width : 0);
-
-            if(his_offset - 1 < my_offset)
-                continue;
-            
-            if(his_offset > dest)
-                continue;
-
-            HIT_EDGE(my_edge_start, my_edge_end, his_edge_start, his_edge_end)
-        }
+        *x = dest;
         break;
-    case OB_DIRECTION_NORTHEAST:
-    case OB_DIRECTION_SOUTHEAST:
-    case OB_DIRECTION_NORTHWEST:
-    case OB_DIRECTION_SOUTHWEST:
-        /* not implemented */
     default:
         g_assert_not_reached();
-        dest = 0; /* suppress warning */
     }
 
     g_free(a);
     g_free(mon);
-    return dest;
+
+    frame_frame_gravity(self->frame, x, y);
 }
 
 ObClient* client_under_pointer()
index bb78345..fcfb28b 100644 (file)
@@ -455,6 +455,11 @@ gboolean client_find_onscreen(ObClient *self, gint *x, gint *y, gint w, gint h,
 */
 void client_move_onscreen(ObClient *self, gboolean rude);
 
+/*! dir is either North, South, East or West. It can't be, for example,
+  Northwest */
+void client_find_move_directional(ObClient *self, ObDirection dir,
+                                  gint *x, gint *y);
+
 /*! Fullscreen's or unfullscreen's the client window
   @param fs true if the window should be made fullscreen; false if it should
             be returned to normal state.
@@ -684,9 +689,6 @@ ObClient *client_search_parent(ObClient *self, ObClient *search);
   NULL is returned if the given search is not a transient of the client. */
 ObClient *client_search_transient(ObClient *self, ObClient *search);
 
-/*! Return the closest edge in the given direction */
-gint client_directional_edge_search(ObClient *c, ObDirection dir, gboolean hang);
-
 /*! Set a client window to be above/below other clients.
   @layer < 0 indicates the client should be placed below other clients.<br />
          = 0 indicates the client should be placed with other clients.<br />
index 05c5f59..19bed57 100644 (file)
@@ -26,6 +26,7 @@
 #include "openbox.h"
 #include "resist.h"
 #include "mainloop.h"
+#include "modkeys.h"
 #include "popup.h"
 #include "moveresize.h"
 #include "config.h"
@@ -39,7 +40,7 @@
 #include <glib.h>
 
 /* how far windows move and resize with the keyboard arrows */
-#define KEY_DIST 4
+#define KEY_DIST 8
 
 gboolean moveresize_in_progress = FALSE;
 ObClient *moveresize_client = NULL;
@@ -434,7 +435,7 @@ static gboolean edge_warp_delay_func(gpointer data)
 
 static void do_edge_warp(gint x, gint y)
 {
-    guint i, d;
+    guint i;
     ObDirection dir;
 
     if (!config_mouse_screenedgetime) return;
@@ -597,15 +598,41 @@ gboolean moveresize_event(XEvent *e)
             } else if (corner == prop_atoms.net_wm_moveresize_move_keyboard) {
                 gint dx = 0, dy = 0, ox = cur_x, oy = cur_y;
                 gint opx, px, opy, py;
-
-                if (e->xkey.keycode == ob_keycode(OB_KEY_RIGHT))
-                    dx = KEY_DIST;
-                else if (e->xkey.keycode == ob_keycode(OB_KEY_LEFT))
-                    dx = -KEY_DIST;
-                else if (e->xkey.keycode == ob_keycode(OB_KEY_DOWN))
-                    dy = KEY_DIST;
-                else /* if (e->xkey.keycode == ob_keycode(OB_KEY_UP)) */
-                    dy = -KEY_DIST;
+                gint dist = KEY_DIST;
+
+                /* shift means jump to edge */
+                if (e->xkey.state & modkeys_key_to_mask(OB_MODKEY_KEY_SHIFT)) {
+                    gint x, y;
+                    ObDirection dir;
+
+                    if (e->xkey.keycode == ob_keycode(OB_KEY_RIGHT))
+                        dir = OB_DIRECTION_EAST;
+                    else if (e->xkey.keycode == ob_keycode(OB_KEY_LEFT))
+                        dir = OB_DIRECTION_WEST;
+                    else if (e->xkey.keycode == ob_keycode(OB_KEY_DOWN))
+                        dir = OB_DIRECTION_SOUTH;
+                    else /* if (e->xkey.keycode == ob_keycode(OB_KEY_UP)) */
+                        dir = OB_DIRECTION_NORTH;
+
+                    client_find_move_directional(moveresize_client, dir,
+                                                 &x, &y);
+                    dx = x - moveresize_client->area.x;
+                    dy = y - moveresize_client->area.y;
+                } else {
+                    /* control means fine grained */
+                    if (e->xkey.state &
+                        modkeys_key_to_mask(OB_MODKEY_KEY_CONTROL))
+                        dist = 1;
+
+                    if (e->xkey.keycode == ob_keycode(OB_KEY_RIGHT))
+                        dx = dist;
+                    else if (e->xkey.keycode == ob_keycode(OB_KEY_LEFT))
+                        dx = -dist;
+                    else if (e->xkey.keycode == ob_keycode(OB_KEY_DOWN))
+                        dy = dist;
+                    else /* if (e->xkey.keycode == ob_keycode(OB_KEY_UP)) */
+                        dy = -dist;
+                }
 
                 cur_x += dx;
                 cur_y += dy;