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 |
|