diff --git a/openbox/actions/growtoedge.c b/openbox/actions/growtoedge.c
index 5d4647f7..a5b24e37 100644
--- a/openbox/actions/growtoedge.c
+++ b/openbox/actions/growtoedge.c
@@ -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);
}
diff --git a/openbox/actions/movetofromedge.c b/openbox/actions/movetofromedge.c
index 72a89c1c..8db45097 100644
--- a/openbox/actions/movetofromedge.c
+++ b/openbox/actions/movetofromedge.c
@@ -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;
diff --git a/openbox/client.c b/openbox/client.c
index e58cc753..9cbbaf61 100644
--- a/openbox/client.c
+++ b/openbox/client.c
@@ -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;
-
- HIT_EDGE(my_edge_start, my_edge_end, his_edge_start, his_edge_end)
- }
- 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;
-
- 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 ? cur->frame->area.height : 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)
- }
+ 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_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;
-
- HIT_EDGE(my_edge_start, my_edge_end, his_edge_start, his_edge_end)
- }
- break;
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)
- }
+ 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();
+ }
+
+ 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:
+ 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 && 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, self); /* skip windows to not bump into */
+
+ 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;
+
+ 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();
+ }
+
+ 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();
+ }
+
+ if (!skip_head)
+ dest = head;
+ else if (!skip_tail)
+ dest = tail;
+ }
+
+ switch(dir) {
+ case OB_DIRECTION_NORTH:
+ case OB_DIRECTION_SOUTH:
+ *y = dest;
+ break;
+ case OB_DIRECTION_WEST:
+ case OB_DIRECTION_EAST:
+ *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()
diff --git a/openbox/client.h b/openbox/client.h
index bb783458..fcfb28b8 100644
--- a/openbox/client.h
+++ b/openbox/client.h
@@ -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.
= 0 indicates the client should be placed with other clients.
diff --git a/openbox/moveresize.c b/openbox/moveresize.c
index 05c5f596..19bed579 100644
--- a/openbox/moveresize.c
+++ b/openbox/moveresize.c
@@ -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
/* 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;
+ gint dist = KEY_DIST;
- 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;
+ /* 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;