diff --git a/include/floating.h b/include/floating.h index a4f8619a..b0c0b7cc 100644 --- a/include/floating.h +++ b/include/floating.h @@ -11,6 +11,12 @@ #ifndef _FLOATING_H #define _FLOATING_H +/** Callback for dragging */ +typedef void(*callback_t)(Rect*, uint32_t, uint32_t); + +/** On which border was the dragging initiated? */ +typedef enum { BORDER_LEFT, BORDER_RIGHT, BORDER_TOP, BORDER_BOTTOM} border_t; + /** * Enters floating mode for the given client. * Correctly takes care of the position/size (separately stored for tiling/floating mode) @@ -67,4 +73,15 @@ void floating_move(xcb_connection_t *conn, Client *currently_focused, direction_ */ void floating_toggle_hide(xcb_connection_t *conn, Workspace *workspace); +/** + * This function grabs your pointer and lets you drag stuff around (borders). + * Every time you move your mouse, an XCB_MOTION_NOTIFY event will be received + * and the given callback will be called with the parameters specified (client, + * border on which the click originally was), the original rect of the client, + * the event and the new coordinates (x, y). + * + */ +void drag_pointer(xcb_connection_t *conn, Client *client, xcb_button_press_event_t *event, + xcb_window_t confine_to, border_t border, callback_t callback); + #endif diff --git a/src/floating.c b/src/floating.c index 6e5bec52..5deda47a 100644 --- a/src/floating.c +++ b/src/floating.c @@ -25,15 +25,7 @@ #include "debug.h" #include "layout.h" #include "client.h" - -/* On which border was the dragging initiated? */ -typedef enum { BORDER_LEFT, BORDER_RIGHT, BORDER_TOP, BORDER_BOTTOM} border_t; -/* Callback for dragging */ -typedef void(*callback_t)(Rect*, uint32_t, uint32_t); - -/* Forward definitions */ -static void drag_pointer(xcb_connection_t *conn, Client *client, xcb_button_press_event_t *event, - border_t border, callback_t callback); +#include "floating.h" /* * Toggles floating mode for the given client. @@ -238,7 +230,7 @@ int floating_border_click(xcb_connection_t *conn, Client *client, xcb_button_pre LOG("border = %d\n", border); - drag_pointer(conn, client, event, border, resize_callback); + drag_pointer(conn, client, event, XCB_NONE, border, resize_callback); return 1; } @@ -264,7 +256,7 @@ void floating_drag_window(xcb_connection_t *conn, Client *client, xcb_button_pre } - drag_pointer(conn, client, event, BORDER_TOP /* irrelevant */, drag_window_callback); + drag_pointer(conn, client, event, XCB_NONE, BORDER_TOP /* irrelevant */, drag_window_callback); } /* @@ -275,12 +267,13 @@ void floating_drag_window(xcb_connection_t *conn, Client *client, xcb_button_pre * the event and the new coordinates (x, y). * */ -static void drag_pointer(xcb_connection_t *conn, Client *client, xcb_button_press_event_t *event, - border_t border, callback_t callback) { +void drag_pointer(xcb_connection_t *conn, Client *client, xcb_button_press_event_t *event, + xcb_window_t confine_to, border_t border, callback_t callback) { xcb_window_t root = xcb_setup_roots_iterator(xcb_get_setup(conn)).data->root; uint32_t new_x, new_y; Rect old_rect; - memcpy(&old_rect, &(client->rect), sizeof(Rect)); + if (client != NULL) + memcpy(&old_rect, &(client->rect), sizeof(Rect)); /* Grab the pointer */ /* TODO: returncode */ @@ -290,7 +283,7 @@ static void drag_pointer(xcb_connection_t *conn, Client *client, xcb_button_pres XCB_EVENT_MASK_BUTTON_RELEASE | XCB_EVENT_MASK_POINTER_MOTION, /* which events to let through */ XCB_GRAB_MODE_ASYNC, /* pointer events should continue as normal */ XCB_GRAB_MODE_ASYNC, /* keyboard mode */ - XCB_NONE, /* confine_to = in which window should the cursor stay */ + confine_to, /* confine_to = in which window should the cursor stay */ XCB_NONE, /* don’t display a special cursor */ XCB_CURRENT_TIME); diff --git a/src/resize.c b/src/resize.c index 7a20061c..3a639e2e 100644 --- a/src/resize.c +++ b/src/resize.c @@ -26,6 +26,7 @@ #include "layout.h" #include "xinerama.h" #include "config.h" +#include "floating.h" /* * Renders the resize window between the first/second container and resizes @@ -35,7 +36,6 @@ int resize_graphical_handler(xcb_connection_t *conn, Workspace *ws, int first, int second, resize_orientation_t orientation, xcb_button_press_event_t *event) { int new_position; - xcb_window_t root = xcb_setup_roots_iterator(xcb_get_setup(conn)).data->root; xcb_screen_t *root_screen = xcb_setup_roots_iterator(xcb_get_setup(conn)).data; i3Screen *screen = get_screen_containing(event->root_x, event->root_y); if (screen == NULL) { @@ -91,59 +91,32 @@ int resize_graphical_handler(xcb_connection_t *conn, Workspace *ws, int first, i xcb_circulate_window(conn, XCB_CIRCULATE_RAISE_LOWEST, helpwin); - xcb_grab_pointer(conn, false, root, XCB_EVENT_MASK_BUTTON_RELEASE | XCB_EVENT_MASK_POINTER_MOTION, - XCB_GRAB_MODE_ASYNC, XCB_GRAB_MODE_ASYNC, grabwin, XCB_NONE, XCB_CURRENT_TIME); - xcb_flush(conn); - xcb_generic_event_t *inside_event; - /* I’ve always wanted to have my own eventhandler… */ - while ((inside_event = xcb_wait_for_event(conn))) { - /* Same as get_event_handler in xcb */ - int nr = inside_event->response_type; - if (nr == 0) { - /* An error occured */ - handle_event(NULL, conn, inside_event); - free(inside_event); - continue; + void resize_callback(Rect *old_rect, uint32_t new_x, uint32_t new_y) { + LOG("new x = %d, y = %d\n", new_x, new_y); + if (orientation == O_VERTICAL) { + /* Check if the new coordinates are within screen boundaries */ + if (new_x > (screen->rect.x + screen->rect.width) || + new_x < screen->rect.x) + return; + + values[0] = new_position = new_x; + xcb_configure_window(conn, helpwin, XCB_CONFIG_WINDOW_X, values); + } else { + if (new_y > (screen->rect.y + screen->rect.height) || + new_y < screen->rect.y) + return; + + values[0] = new_position = new_y; + xcb_configure_window(conn, helpwin, XCB_CONFIG_WINDOW_Y, values); } - assert(nr < 256); - nr &= XCB_EVENT_RESPONSE_TYPE_MASK; - assert(nr >= 2); - /* Check if we need to escape this loop */ - if (nr == XCB_BUTTON_RELEASE) - break; - - switch (nr) { - case XCB_MOTION_NOTIFY: { - xcb_motion_notify_event_t *motion_event = (xcb_motion_notify_event_t*)inside_event; - if (orientation == O_VERTICAL) { - if (motion_event->root_x < (screen->rect.x + screen->rect.width) && - motion_event->root_x > screen->rect.x) { - values[0] = new_position = ((xcb_motion_notify_event_t*)inside_event)->root_x; - xcb_configure_window(conn, helpwin, XCB_CONFIG_WINDOW_X, values); - } else { - LOG("Ignoring new position\n"); - } - } else { - values[0] = new_position = ((xcb_motion_notify_event_t*)inside_event)->root_y; - xcb_configure_window(conn, helpwin, XCB_CONFIG_WINDOW_Y, values); - } - - xcb_flush(conn); - break; - } - default: - LOG("Passing to original handler\n"); - /* Use original handler */ - xcb_event_handle(&evenths, inside_event); - break; - } - free(inside_event); + xcb_flush(conn); } - xcb_ungrab_pointer(conn, XCB_CURRENT_TIME); + drag_pointer(conn, NULL, event, grabwin, BORDER_TOP, resize_callback); + xcb_destroy_window(conn, helpwin); xcb_destroy_window(conn, grabwin); xcb_flush(conn);