i3 - improved tiling WM


Support _NET_WM_MOVERESIZE

Patch status: needinfo

Patch by Lukas K

Long description:

Add support for the _NET_WM_MOVERESIZE client message. This message
enables clients to initiate window moving or resizing. Toolkits like
Gtk3 use this message when the user drags a client-side decorated window
by its title bar. When Gtk detects that the window manager does not
support this client message, it uses a slow fallback implementation.

fixes #1432

To apply this patch, use:
curl http://cr.i3wm.org/patch/707/raw.patch | git am

b/include/atoms.xmacro

22
@@ -1,6 +1,7 @@
23
 xmacro(_NET_SUPPORTED)
24
 xmacro(_NET_SUPPORTING_WM_CHECK)
25
 xmacro(_NET_WM_NAME)
26
+xmacro(_NET_WM_MOVERESIZE)
27
 xmacro(_NET_WM_STATE_FULLSCREEN)
28
 xmacro(_NET_WM_STATE_DEMANDS_ATTENTION)
29
 xmacro(_NET_WM_STATE_MODAL)

b/src/ewmh.c

34
@@ -234,5 +234,6 @@ void ewmh_setup_hints(void) {
35
     /* I’m not entirely sure if we need to keep _NET_WM_NAME on root. */
36
     xcb_change_property(conn, XCB_PROP_MODE_REPLACE, root, A__NET_WM_NAME, A_UTF8_STRING, 8, strlen("i3"), "i3");
37
 
38
-    xcb_change_property(conn, XCB_PROP_MODE_REPLACE, root, A__NET_SUPPORTED, XCB_ATOM_ATOM, 32, 23, supported_atoms);
39
+    /* only send the first 24 atoms (last one is _NET_CLOSE_WINDOW) increment that number when adding supported atoms */
40
+    xcb_change_property(conn, XCB_PROP_MODE_REPLACE, root, A__NET_SUPPORTED, XCB_ATOM_ATOM, 32, 24, supported_atoms);
41
 }

b/src/handlers.c

46
@@ -651,6 +651,19 @@ static void handle_expose_event(xcb_expose_event_t *event) {
47
     return;
48
 }
49
 
50
+#define _NET_WM_MOVERESIZE_SIZE_TOPLEFT      0
51
+#define _NET_WM_MOVERESIZE_SIZE_TOP          1
52
+#define _NET_WM_MOVERESIZE_SIZE_TOPRIGHT     2
53
+#define _NET_WM_MOVERESIZE_SIZE_RIGHT        3
54
+#define _NET_WM_MOVERESIZE_SIZE_BOTTOMRIGHT  4
55
+#define _NET_WM_MOVERESIZE_SIZE_BOTTOM       5
56
+#define _NET_WM_MOVERESIZE_SIZE_BOTTOMLEFT   6
57
+#define _NET_WM_MOVERESIZE_SIZE_LEFT         7
58
+#define _NET_WM_MOVERESIZE_MOVE              8   /* movement only */
59
+#define _NET_WM_MOVERESIZE_SIZE_KEYBOARD     9   /* size via keyboard */
60
+#define _NET_WM_MOVERESIZE_MOVE_KEYBOARD    10   /* move via keyboard */
61
+#define _NET_WM_MOVERESIZE_CANCEL           11   /* cancel operation */
62
+
63
 /*
64
  * Handle client messages (EWMH)
65
  *
66
@@ -856,6 +869,35 @@ static void handle_client_message(xcb_client_message_event_t *event) {
67
         } else {
68
             DLOG("Couldn't find con for _NET_CLOSE_WINDOW request. (window = %d)\n", event->window);
69
         }
70
+    } else if (event->type == A__NET_WM_MOVERESIZE) {
71
+        /*
72
+         * Client-side decorated Gtk3 windows emit this signal when being
73
+         * dragged by their GtkHeaderBar
74
+         */
75
+         Con *con = con_by_window_id(event->window);
76
+         if (con && con_is_floating(con)) {
77
+             DLOG("Handling _NET_WM_MOVERESIZE request (con = %p)\n", con);
78
+             uint32_t direction = event->data.data32[2];
79
+             uint32_t x_root = event->data.data32[0];
80
+             uint32_t y_root = event->data.data32[1];
81
+             /* construct fake xcb_button_press_event_t */
82
+             xcb_button_press_event_t fake = {
83
+                 .root_x = x_root,
84
+                 .root_y = y_root,
85
+                 .event_x = x_root-(con->rect.x),
86
+                 .event_y = y_root-(con->rect.y)
87
+             };
88
+             if(direction == _NET_WM_MOVERESIZE_MOVE) {
89
+                 floating_drag_window(con->parent, &fake);
90
+             } else if(direction >= _NET_WM_MOVERESIZE_SIZE_TOPLEFT && direction <= _NET_WM_MOVERESIZE_SIZE_LEFT) {
91
+                 floating_resize_window(con->parent, FALSE, &fake);
92
+             } else {
93
+                DLOG("_NET_WM_MOVERESIZE direction %d not implemented\n", direction);
94
+             }
95
+
96
+         } else {
97
+             DLOG("Couldn't find con for _NET_WM_MOVERESIZE request. or con not floating (window = %d)\n", event->window);
98
+         }
99
     } else {
100
         DLOG("unhandled clientmessage\n");
101
         return;