From cd929f11990e39053372da74802a2bd594bf7a46 Mon Sep 17 00:00:00 2001 From: Michael Stapelberg Date: Fri, 12 Feb 2010 13:06:59 +0100 Subject: [PATCH] Bugfix: Correctly do boundary checking/moving to other workspaces when moving floating clients via keyboard (Thanks sasha) --- include/data.h | 6 ++++++ src/floating.c | 25 +++++++++++++++++-------- src/layout.c | 6 +++++- 3 files changed, 28 insertions(+), 9 deletions(-) diff --git a/include/data.h b/include/data.h index 971e908d..8e1a80cc 100644 --- a/include/data.h +++ b/include/data.h @@ -76,6 +76,12 @@ enum { /** * Stores a rectangle, for example the size of a window, the child window etc. * + * Note that x and y can contain signed values in some cases (for example when + * used for the coordinates of a window, which can be set outside of the + * visible area, but not when specifying the position of a workspace for the + * _NET_WM_WORKAREA hint). Not declaring x/y as int32_t saves us a lot of + * typecasts. + * */ struct Rect { uint32_t x, y; diff --git a/src/floating.c b/src/floating.c index 9302b020..bd1a31b8 100644 --- a/src/floating.c +++ b/src/floating.c @@ -411,28 +411,37 @@ void floating_focus_direction(xcb_connection_t *conn, Client *currently_focused, void floating_move(xcb_connection_t *conn, Client *currently_focused, direction_t direction) { LOG("floating move\n"); + Rect destination = currently_focused->rect; + Rect *screen = &(currently_focused->workspace->screen->rect); + switch (direction) { case D_LEFT: - if (currently_focused->rect.x < 10) - return; - currently_focused->rect.x -= 10; + destination.x -= 10; break; case D_RIGHT: - currently_focused->rect.x += 10; + destination.x += 10; break; case D_UP: - if (currently_focused->rect.y < 10) - return; - currently_focused->rect.y -= 10; + destination.y -= 10; break; case D_DOWN: - currently_focused->rect.y += 10; + destination.y += 10; break; /* to make static analyzers happy */ default: break; } + /* Prevent windows from vanishing completely */ + if ((int32_t)(destination.x + destination.width - 5) <= (int32_t)screen->x || + (int32_t)(destination.x + 5) >= (int32_t)(screen->x + screen->width) || + (int32_t)(destination.y + destination.height - 5) <= (int32_t)screen->y || + (int32_t)(destination.y + 5) >= (int32_t)(screen->y + screen->height)) { + DLOG("boundary check failed, not moving\n"); + return; + } + + currently_focused->rect = destination; reposition_client(conn, currently_focused); /* Because reposition_client does not send a faked configure event (only resize does), diff --git a/src/layout.c b/src/layout.c index 388fe7a5..3092c5df 100644 --- a/src/layout.c +++ b/src/layout.c @@ -223,7 +223,9 @@ void reposition_client(xcb_connection_t *conn, Client *client) { return; /* If the client is floating, we need to check if we moved it to a different workspace */ - if (client->workspace->screen == (screen = get_screen_containing(client->rect.x, client->rect.y))) + screen = get_screen_containing(client->rect.x + (client->rect.width / 2), + client->rect.y + (client->rect.height / 2)); + if (client->workspace->screen == screen) return; if (screen == NULL) { @@ -234,6 +236,8 @@ void reposition_client(xcb_connection_t *conn, Client *client) { LOG("Client is on workspace %p with screen %p\n", client->workspace, client->workspace->screen); LOG("but screen at %d, %d is %p\n", client->rect.x, client->rect.y, screen); floating_assign_to_workspace(client, screen->current_workspace); + + set_focus(conn, client, true); } /*