#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)
*/
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
#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.
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;
}
}
- drag_pointer(conn, client, event, BORDER_TOP /* irrelevant */, drag_window_callback);
+ drag_pointer(conn, client, event, XCB_NONE, BORDER_TOP /* irrelevant */, drag_window_callback);
}
/*
* 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 */
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);
#include "layout.h"
#include "xinerama.h"
#include "config.h"
+#include "floating.h"
/*
* Renders the resize window between the first/second container and resizes
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) {
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;
- }
- 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;
+ 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);
}
- 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);