Suppport _NET_WM_MOVERESIZE completely
Patch status: superseded
Patch by Lukas K
Long description:
fixes #1432 This patch supersedes the previous one regarding _NET_WM_MOVERESIZE. It adds support for resizing windows using _NET_WM_MOVERESIZE_SIZE and fixes the number of supported atoms added to the root window.
To apply this patch, use:
curl http://cr.i3wm.org/patch/704/raw.patch | git am
b/include/atoms.xmacro
24 |
@@ -1,6 +1,7 @@ |
25 |
xmacro(_NET_SUPPORTED) |
26 |
xmacro(_NET_SUPPORTING_WM_CHECK) |
27 |
xmacro(_NET_WM_NAME) |
28 |
+xmacro(_NET_WM_MOVERESIZE) |
29 |
xmacro(_NET_WM_STATE_FULLSCREEN) |
30 |
xmacro(_NET_WM_STATE_DEMANDS_ATTENTION) |
31 |
xmacro(_NET_WM_STATE_MODAL) |
b/include/floating.h
36 |
@@ -96,7 +96,7 @@ void floating_drag_window(Con *con, const xcb_button_press_event_t *event); |
37 |
* Calls the drag_pointer function with the resize_window callback |
38 |
* |
39 |
*/ |
40 |
-void floating_resize_window(Con *con, const bool proportional, const xcb_button_press_event_t *event); |
41 |
+void floating_resize_window(Con *con, const bool proportional, const xcb_button_press_event_t *event, border_t force_corner); |
42 |
|
43 |
/** |
44 |
* Called when a floating window is created or resized. |
b/include/xcursor.h
49 |
@@ -19,6 +19,10 @@ enum xcursor_cursor_t { |
50 |
XCURSOR_CURSOR_TOP_RIGHT_CORNER, |
51 |
XCURSOR_CURSOR_BOTTOM_LEFT_CORNER, |
52 |
XCURSOR_CURSOR_BOTTOM_RIGHT_CORNER, |
53 |
+ XCURSOR_CURSOR_TOP_SIDE, |
54 |
+ XCURSOR_CURSOR_RIGHT_SIDE, |
55 |
+ XCURSOR_CURSOR_BOTTOM_SIDE, |
56 |
+ XCURSOR_CURSOR_LEFT_SIDE, |
57 |
XCURSOR_CURSOR_WATCH, |
58 |
XCURSOR_CURSOR_MOVE, |
59 |
XCURSOR_CURSOR_MAX |
b/src/click.c
64 |
@@ -266,7 +266,7 @@ static int route_click(Con *con, xcb_button_press_event_t *event, const bool mod |
65 |
* also try resizing (tiling) if it was a click on the top */ |
66 |
if (mod_pressed && event->detail == XCB_BUTTON_INDEX_3) { |
67 |
DLOG("floating resize due to floatingmodifier\n"); |
68 |
- floating_resize_window(floatingcon, proportional, event); |
69 |
+ floating_resize_window(floatingcon, proportional, event, 0); |
70 |
return 1; |
71 |
} |
72 |
|
73 |
@@ -279,13 +279,13 @@ static int route_click(Con *con, xcb_button_press_event_t *event, const bool mod |
74 |
|
75 |
if (dest == CLICK_DECORATION && event->detail == XCB_BUTTON_INDEX_3) { |
76 |
DLOG("floating resize due to decoration right click\n"); |
77 |
- floating_resize_window(floatingcon, proportional, event); |
78 |
+ floating_resize_window(floatingcon, proportional, event, 0); |
79 |
return 1; |
80 |
} |
81 |
|
82 |
if (dest == CLICK_BORDER) { |
83 |
DLOG("floating resize due to border click\n"); |
84 |
- floating_resize_window(floatingcon, proportional, event); |
85 |
+ floating_resize_window(floatingcon, proportional, event, 0); |
86 |
return 1; |
87 |
} |
88 |
|
b/src/ewmh.c
93 |
@@ -234,5 +234,6 @@ void ewmh_setup_hints(void) { |
94 |
/* I’m not entirely sure if we need to keep _NET_WM_NAME on root. */ |
95 |
xcb_change_property(conn, XCB_PROP_MODE_REPLACE, root, A__NET_WM_NAME, A_UTF8_STRING, 8, strlen("i3"), "i3"); |
96 |
|
97 |
- xcb_change_property(conn, XCB_PROP_MODE_REPLACE, root, A__NET_SUPPORTED, XCB_ATOM_ATOM, 32, 23, supported_atoms); |
98 |
+ /* only send the first 24 atoms (last one is _NET_CLOSE_WINDOW) increment that number when adding supported atoms */ |
99 |
+ xcb_change_property(conn, XCB_PROP_MODE_REPLACE, root, A__NET_SUPPORTED, XCB_ATOM_ATOM, 32, 24, supported_atoms); |
100 |
} |
b/src/floating.c
105 |
@@ -488,8 +488,8 @@ DRAGGING_CB(resize_window_callback) { |
106 |
|
107 |
int32_t dest_x = con->rect.x; |
108 |
int32_t dest_y = con->rect.y; |
109 |
- uint32_t dest_width; |
110 |
- uint32_t dest_height; |
111 |
+ uint32_t dest_width = old_rect->width; |
112 |
+ uint32_t dest_height = old_rect->height; |
113 |
|
114 |
double ratio = (double)old_rect->width / old_rect->height; |
115 |
|
116 |
@@ -497,12 +497,12 @@ DRAGGING_CB(resize_window_callback) { |
117 |
* taking into account in which corner the client was grabbed */ |
118 |
if (corner & BORDER_LEFT) |
119 |
dest_width = old_rect->width - (new_x - event->root_x); |
120 |
- else |
121 |
+ else if (corner & BORDER_RIGHT) |
122 |
dest_width = old_rect->width + (new_x - event->root_x); |
123 |
|
124 |
if (corner & BORDER_TOP) |
125 |
dest_height = old_rect->height - (new_y - event->root_y); |
126 |
- else |
127 |
+ else if (corner & BORDER_BOTTOM) |
128 |
dest_height = old_rect->height + (new_y - event->root_y); |
129 |
|
130 |
/* User wants to keep proportions, so we may have to adjust our values */ |
131 |
@@ -540,26 +540,41 @@ DRAGGING_CB(resize_window_callback) { |
132 |
* |
133 |
*/ |
134 |
void floating_resize_window(Con *con, const bool proportional, |
135 |
- const xcb_button_press_event_t *event) { |
136 |
+ const xcb_button_press_event_t *event, |
137 |
+ border_t force_corner) { |
138 |
DLOG("floating_resize_window\n"); |
139 |
|
140 |
/* corner saves the nearest corner to the original click. It contains |
141 |
* a bitmask of the nearest borders (BORDER_LEFT, BORDER_RIGHT, …) */ |
142 |
border_t corner = 0; |
143 |
+ int cursor = 0; |
144 |
+ if(force_corner == 0) { |
145 |
+ if (event->event_x <= (int16_t)(con->rect.width / 2)) |
146 |
+ corner |= BORDER_LEFT; |
147 |
+ else |
148 |
+ corner |= BORDER_RIGHT; |
149 |
|
150 |
- if (event->event_x <= (int16_t)(con->rect.width / 2)) |
151 |
- corner |= BORDER_LEFT; |
152 |
- else |
153 |
- corner |= BORDER_RIGHT; |
154 |
+ if (event->event_y <= (int16_t)(con->rect.height / 2)) |
155 |
+ corner |= BORDER_TOP; |
156 |
+ else |
157 |
+ corner |= BORDER_BOTTOM; |
158 |
+ } |
159 |
+ else { |
160 |
+ corner = force_corner; |
161 |
+ } |
162 |
|
163 |
- int cursor = 0; |
164 |
- if (event->event_y <= (int16_t)(con->rect.height / 2)) { |
165 |
- corner |= BORDER_TOP; |
166 |
+ if(corner == BORDER_TOP) |
167 |
+ cursor = XCURSOR_CURSOR_TOP_SIDE; |
168 |
+ else if(corner == BORDER_RIGHT) |
169 |
+ cursor = XCURSOR_CURSOR_RIGHT_SIDE; |
170 |
+ else if(corner == BORDER_BOTTOM) |
171 |
+ cursor = XCURSOR_CURSOR_BOTTOM_SIDE; |
172 |
+ else if(corner == BORDER_LEFT) |
173 |
+ cursor = XCURSOR_CURSOR_LEFT_SIDE; |
174 |
+ else if(corner & BORDER_TOP) |
175 |
cursor = (corner & BORDER_LEFT) ? XCURSOR_CURSOR_TOP_LEFT_CORNER : XCURSOR_CURSOR_TOP_RIGHT_CORNER; |
176 |
- } else { |
177 |
- corner |= BORDER_BOTTOM; |
178 |
+ else if(corner & BORDER_BOTTOM) |
179 |
cursor = (corner & BORDER_LEFT) ? XCURSOR_CURSOR_BOTTOM_LEFT_CORNER : XCURSOR_CURSOR_BOTTOM_RIGHT_CORNER; |
180 |
- } |
181 |
|
182 |
struct resize_window_callback_params params = {corner, proportional, event}; |
183 |
|
b/src/handlers.c
188 |
@@ -651,6 +651,20 @@ static void handle_expose_event(xcb_expose_event_t *event) { |
189 |
return; |
190 |
} |
191 |
|
192 |
+ |
193 |
+#define _NET_WM_MOVERESIZE_SIZE_TOPLEFT 0 |
194 |
+#define _NET_WM_MOVERESIZE_SIZE_TOP 1 |
195 |
+#define _NET_WM_MOVERESIZE_SIZE_TOPRIGHT 2 |
196 |
+#define _NET_WM_MOVERESIZE_SIZE_RIGHT 3 |
197 |
+#define _NET_WM_MOVERESIZE_SIZE_BOTTOMRIGHT 4 |
198 |
+#define _NET_WM_MOVERESIZE_SIZE_BOTTOM 5 |
199 |
+#define _NET_WM_MOVERESIZE_SIZE_BOTTOMLEFT 6 |
200 |
+#define _NET_WM_MOVERESIZE_SIZE_LEFT 7 |
201 |
+#define _NET_WM_MOVERESIZE_MOVE 8 /* movement only */ |
202 |
+#define _NET_WM_MOVERESIZE_SIZE_KEYBOARD 9 /* size via keyboard */ |
203 |
+#define _NET_WM_MOVERESIZE_MOVE_KEYBOARD 10 /* move via keyboard */ |
204 |
+#define _NET_WM_MOVERESIZE_CANCEL 11 /* cancel operation */ |
205 |
+ |
206 |
/* |
207 |
* Handle client messages (EWMH) |
208 |
* |
209 |
@@ -856,6 +870,53 @@ static void handle_client_message(xcb_client_message_event_t *event) { |
210 |
} else { |
211 |
DLOG("Couldn't find con for _NET_CLOSE_WINDOW request. (window = %d)\n", event->window); |
212 |
} |
213 |
+ } |
214 |
+ else if (event->type == A__NET_WM_MOVERESIZE) { |
215 |
+ /* |
216 |
+ * Client-side decorated Gtk3 windows emit this signal when being |
217 |
+ * dragged by their GtkHeaderBar |
218 |
+ */ |
219 |
+ Con *con = con_by_window_id(event->window); |
220 |
+ if (con && con_is_floating(con)) { |
221 |
+ DLOG("Handling _NET_WM_MOVERESIZE request (con = %p)\n", con); |
222 |
+ uint32_t direction = event->data.data32[2]; |
223 |
+ uint32_t x_root = event->data.data32[0]; |
224 |
+ uint32_t y_root = event->data.data32[1]; |
225 |
+ /* construct fake xcb_button_press_event_t */ |
226 |
+ xcb_button_press_event_t fake = { |
227 |
+ .root_x = x_root, |
228 |
+ .root_y = y_root |
229 |
+ }; |
230 |
+ if(direction == _NET_WM_MOVERESIZE_MOVE) { |
231 |
+ floating_drag_window(con->parent, &fake); |
232 |
+ |
233 |
+ } else if(direction >= _NET_WM_MOVERESIZE_SIZE_TOPLEFT && direction <= _NET_WM_MOVERESIZE_SIZE_LEFT) { |
234 |
+ border_t border=0; |
235 |
+ if(direction == _NET_WM_MOVERESIZE_SIZE_TOP || |
236 |
+ direction == _NET_WM_MOVERESIZE_SIZE_TOPLEFT || |
237 |
+ direction == _NET_WM_MOVERESIZE_SIZE_TOPRIGHT) |
238 |
+ border |= BORDER_TOP; |
239 |
+ if(direction == _NET_WM_MOVERESIZE_SIZE_RIGHT || |
240 |
+ direction == _NET_WM_MOVERESIZE_SIZE_TOPRIGHT || |
241 |
+ direction == _NET_WM_MOVERESIZE_SIZE_BOTTOMRIGHT) |
242 |
+ border |= BORDER_RIGHT; |
243 |
+ if(direction == _NET_WM_MOVERESIZE_SIZE_BOTTOM || |
244 |
+ direction == _NET_WM_MOVERESIZE_SIZE_BOTTOMLEFT || |
245 |
+ direction == _NET_WM_MOVERESIZE_SIZE_BOTTOMRIGHT) |
246 |
+ border |= BORDER_BOTTOM; |
247 |
+ if(direction == _NET_WM_MOVERESIZE_SIZE_LEFT || |
248 |
+ direction == _NET_WM_MOVERESIZE_SIZE_TOPLEFT || |
249 |
+ direction == _NET_WM_MOVERESIZE_SIZE_TOPRIGHT) |
250 |
+ border |= BORDER_RIGHT; |
251 |
+ |
252 |
+ floating_resize_window(con->parent, FALSE, &fake, border); |
253 |
+ } else { |
254 |
+ DLOG("_NET_WM_MOVERESIZE direction %d not implemented\n", direction); |
255 |
+ } |
256 |
+ |
257 |
+ } else { |
258 |
+ DLOG("Couldn't find con for _NET_WM_MOVERESIZE request. or con not floating (window = %d)\n", event->window); |
259 |
+ } |
260 |
} else { |
261 |
DLOG("unhandled clientmessage\n"); |
262 |
return; |
b/src/xcursor.c
267 |
@@ -44,6 +44,10 @@ void xcursor_load_cursors(void) { |
268 |
LOAD_CURSOR(XCURSOR_CURSOR_TOP_RIGHT_CORNER, "top_right_corner"); |
269 |
LOAD_CURSOR(XCURSOR_CURSOR_BOTTOM_LEFT_CORNER, "bottom_left_corner"); |
270 |
LOAD_CURSOR(XCURSOR_CURSOR_BOTTOM_RIGHT_CORNER, "bottom_right_corner"); |
271 |
+ LOAD_CURSOR(XCURSOR_CURSOR_TOP_SIDE, "top_side"); |
272 |
+ LOAD_CURSOR(XCURSOR_CURSOR_RIGHT_SIDE, "right_side"); |
273 |
+ LOAD_CURSOR(XCURSOR_CURSOR_BOTTOM_SIDE, "bottom_side"); |
274 |
+ LOAD_CURSOR(XCURSOR_CURSOR_LEFT_SIDE, "left_side"); |
275 |
#undef LOAD_CURSOR |
276 |
} |
277 |
|