]> Dogcows Code - chaz/openbox/blob - openbox/moveresize.c
dont start a move/resize on clients that cant do it
[chaz/openbox] / openbox / moveresize.c
1 /* -*- indent-tabs-mode: nil; tab-width: 4; c-basic-offset: 4; -*-
2
3 moveresize.c for the Openbox window manager
4 Copyright (c) 2003 Ben Jansens
5
6 This program is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 2 of the License, or
9 (at your option) any later version.
10
11 This program is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
15
16 See the COPYING file for a copy of the GNU General Public License.
17 */
18
19 #include "grab.h"
20 #include "framerender.h"
21 #include "screen.h"
22 #include "prop.h"
23 #include "client.h"
24 #include "frame.h"
25 #include "openbox.h"
26 #include "resist.h"
27 #include "popup.h"
28 #include "moveresize.h"
29 #include "config.h"
30 #include "render/render.h"
31 #include "render/theme.h"
32
33 #include <X11/Xlib.h>
34 #include <glib.h>
35
36 gboolean moveresize_in_progress = FALSE;
37 ObClient *moveresize_client = NULL;
38
39 static gboolean moving = FALSE; /* TRUE - moving, FALSE - resizing */
40
41 static int start_x, start_y, start_cx, start_cy, start_cw, start_ch;
42 static int cur_x, cur_y;
43 static guint button;
44 static guint32 corner;
45 static ObCorner lockcorner;
46
47 static ObPopup *popup = NULL;
48
49 static void client_dest(ObClient *client, gpointer data)
50 {
51 if (moveresize_client == client)
52 moveresize_end(TRUE);
53 }
54
55 void moveresize_startup(gboolean reconfig)
56 {
57 popup = popup_new(FALSE);
58
59 if (!reconfig)
60 client_add_destructor(client_dest, NULL);
61 }
62
63 void moveresize_shutdown(gboolean reconfig)
64 {
65 if (!reconfig) {
66 if (moveresize_in_progress)
67 moveresize_end(FALSE);
68 client_remove_destructor(client_dest);
69 }
70
71 popup_free(popup);
72 popup = NULL;
73 }
74
75 static void popup_coords(ObClient *c, char *format, int a, int b)
76 {
77 char *text;
78
79 text = g_strdup_printf(format, a, b);
80 popup_position(popup, CenterGravity,
81 c->frame->area.x + c->frame->size.left +
82 c->area.width / 2,
83 c->frame->area.y + c->frame->size.top +
84 c->area.height / 2);
85 popup_show(popup, text);
86 g_free(text);
87 }
88
89 void moveresize_start(ObClient *c, int x, int y, guint b, guint32 cnr)
90 {
91 ObCursor cur;
92
93 moving = (cnr == prop_atoms.net_wm_moveresize_move ||
94 cnr == prop_atoms.net_wm_moveresize_move_keyboard);
95
96 if (moveresize_in_progress || !c->frame->visible ||
97 !(moving ?
98 (c->functions & OB_CLIENT_FUNC_MOVE) :
99 (c->functions & OB_CLIENT_FUNC_RESIZE)))
100 return;
101
102 moveresize_client = c;
103 start_cx = c->frame->area.x;
104 start_cy = c->frame->area.y;
105 /* these adjustments for the size_inc make resizing a terminal more
106 friendly. you essentially start the resize in the middle of the
107 increment instead of at 0, so you have to move half an increment
108 either way instead of a full increment one and 1 px the other. and this
109 is one large mother fucking comment. */
110 start_cw = c->area.width + c->size_inc.width / 2;
111 start_ch = c->area.height + c->size_inc.height / 2;
112 start_x = x;
113 start_y = y;
114 corner = cnr;
115 button = b;
116
117 /*
118 have to change start_cx and start_cy if going to do this..
119 if (corner == prop_atoms.net_wm_moveresize_move_keyboard ||
120 corner == prop_atoms.net_wm_moveresize_size_keyboard)
121 XWarpPointer(ob_display, None, c->window, 0, 0, 0, 0,
122 c->area.width / 2, c->area.height / 2);
123 */
124
125 if (moving) {
126 cur_x = start_cx;
127 cur_y = start_cy;
128 } else {
129 cur_x = start_cw;
130 cur_y = start_ch;
131 }
132
133 moveresize_in_progress = TRUE;
134
135 if (corner == prop_atoms.net_wm_moveresize_size_topleft)
136 cur = OB_CURSOR_NORTHWEST;
137 else if (corner == prop_atoms.net_wm_moveresize_size_top)
138 cur = OB_CURSOR_NORTH;
139 else if (corner == prop_atoms.net_wm_moveresize_size_topright)
140 cur = OB_CURSOR_NORTHEAST;
141 else if (corner == prop_atoms.net_wm_moveresize_size_right)
142 cur = OB_CURSOR_EAST;
143 else if (corner == prop_atoms.net_wm_moveresize_size_bottomright)
144 cur = OB_CURSOR_SOUTHEAST;
145 else if (corner == prop_atoms.net_wm_moveresize_size_bottom)
146 cur = OB_CURSOR_SOUTH;
147 else if (corner == prop_atoms.net_wm_moveresize_size_bottomleft)
148 cur = OB_CURSOR_SOUTHWEST;
149 else if (corner == prop_atoms.net_wm_moveresize_size_left)
150 cur = OB_CURSOR_WEST;
151 else if (corner == prop_atoms.net_wm_moveresize_size_keyboard)
152 cur = OB_CURSOR_SOUTHEAST;
153 else if (corner == prop_atoms.net_wm_moveresize_move)
154 cur = OB_CURSOR_MOVE;
155 else if (corner == prop_atoms.net_wm_moveresize_move_keyboard)
156 cur = OB_CURSOR_MOVE;
157 else
158 g_assert_not_reached();
159
160 grab_pointer(TRUE, cur);
161 grab_keyboard(TRUE);
162 }
163
164 void moveresize_end(gboolean cancel)
165 {
166 grab_keyboard(FALSE);
167 grab_pointer(FALSE, OB_CURSOR_NONE);
168
169 popup_hide(popup);
170
171 if (moving) {
172 client_move(moveresize_client,
173 (cancel ? start_cx : cur_x),
174 (cancel ? start_cy : cur_y));
175 } else {
176 client_configure(moveresize_client, lockcorner,
177 moveresize_client->area.x,
178 moveresize_client->area.y,
179 (cancel ? start_cw : cur_x),
180 (cancel ? start_ch : cur_y), TRUE, TRUE);
181 }
182
183 moveresize_in_progress = FALSE;
184 moveresize_client = NULL;
185 }
186
187 static void do_move(gboolean resist)
188 {
189 if (resist)
190 resist_move_windows(moveresize_client, &cur_x, &cur_y);
191 resist_move_monitors(moveresize_client, &cur_x, &cur_y);
192
193 /* get where the client should be */
194 frame_frame_gravity(moveresize_client->frame, &cur_x, &cur_y);
195 client_configure(moveresize_client, OB_CORNER_TOPLEFT, cur_x, cur_y,
196 moveresize_client->area.width,
197 moveresize_client->area.height, TRUE, FALSE);
198 }
199
200 static void do_resize(gboolean resist)
201 {
202 /* resist_size_* needs the frame size */
203 cur_x += moveresize_client->frame->size.left +
204 moveresize_client->frame->size.right;
205 cur_y += moveresize_client->frame->size.top +
206 moveresize_client->frame->size.bottom;
207
208 if (resist)
209 resist_size_windows(moveresize_client, &cur_x, &cur_y, lockcorner);
210 resist_size_monitors(moveresize_client, &cur_x, &cur_y, lockcorner);
211
212 cur_x -= moveresize_client->frame->size.left +
213 moveresize_client->frame->size.right;
214 cur_y -= moveresize_client->frame->size.top +
215 moveresize_client->frame->size.bottom;
216
217 client_configure(moveresize_client, lockcorner,
218 moveresize_client->area.x, moveresize_client->area.y,
219 cur_x, cur_y, TRUE, FALSE);
220
221 /* this would be better with a fixed width font ... XXX can do it better
222 if there are 2 text boxes */
223 if (moveresize_client->size_inc.width > 1 ||
224 moveresize_client->size_inc.height > 1)
225 popup_coords(moveresize_client, "%d x %d",
226 moveresize_client->logical_size.width,
227 moveresize_client->logical_size.height);
228 }
229
230 void moveresize_event(XEvent *e)
231 {
232 g_assert(moveresize_in_progress);
233
234 if (e->type == ButtonPress) {
235 if (!button) {
236 start_x = e->xbutton.x_root;
237 start_y = e->xbutton.y_root;
238 button = e->xbutton.button; /* this will end it now */
239 }
240 } else if (e->type == ButtonRelease) {
241 if (!button || e->xbutton.button == button) {
242 moveresize_end(FALSE);
243 }
244 } else if (e->type == MotionNotify) {
245 if (moving) {
246 cur_x = start_cx + e->xmotion.x_root - start_x;
247 cur_y = start_cy + e->xmotion.y_root - start_y;
248 do_move(TRUE);
249 } else {
250 if (corner == prop_atoms.net_wm_moveresize_size_topleft) {
251 cur_x = start_cw - (e->xmotion.x_root - start_x);
252 cur_y = start_ch - (e->xmotion.y_root - start_y);
253 lockcorner = OB_CORNER_BOTTOMRIGHT;
254 } else if (corner == prop_atoms.net_wm_moveresize_size_top) {
255 cur_x = start_cw;
256 cur_y = start_ch - (e->xmotion.y_root - start_y);
257 lockcorner = OB_CORNER_BOTTOMRIGHT;
258 } else if (corner == prop_atoms.net_wm_moveresize_size_topright) {
259 cur_x = start_cw + (e->xmotion.x_root - start_x);
260 cur_y = start_ch - (e->xmotion.y_root - start_y);
261 lockcorner = OB_CORNER_BOTTOMLEFT;
262 } else if (corner == prop_atoms.net_wm_moveresize_size_right) {
263 cur_x = start_cw + (e->xmotion.x_root - start_x);
264 cur_y = start_ch;
265 lockcorner = OB_CORNER_BOTTOMLEFT;
266 } else if (corner ==
267 prop_atoms.net_wm_moveresize_size_bottomright) {
268 cur_x = start_cw + (e->xmotion.x_root - start_x);
269 cur_y = start_ch + (e->xmotion.y_root - start_y);
270 lockcorner = OB_CORNER_TOPLEFT;
271 } else if (corner == prop_atoms.net_wm_moveresize_size_bottom) {
272 cur_x = start_cw;
273 cur_y = start_ch + (e->xmotion.y_root - start_y);
274 lockcorner = OB_CORNER_TOPLEFT;
275 } else if (corner ==
276 prop_atoms.net_wm_moveresize_size_bottomleft) {
277 cur_x = start_cw - (e->xmotion.x_root - start_x);
278 cur_y = start_ch + (e->xmotion.y_root - start_y);
279 lockcorner = OB_CORNER_TOPRIGHT;
280 } else if (corner == prop_atoms.net_wm_moveresize_size_left) {
281 cur_x = start_cw - (e->xmotion.x_root - start_x);
282 cur_y = start_ch;
283 lockcorner = OB_CORNER_TOPRIGHT;
284 } else if (corner == prop_atoms.net_wm_moveresize_size_keyboard) {
285 cur_x = start_cw + (e->xmotion.x_root - start_x);
286 cur_y = start_ch + (e->xmotion.y_root - start_y);
287 lockcorner = OB_CORNER_TOPLEFT;
288 } else
289 g_assert_not_reached();
290
291 do_resize(TRUE);
292 }
293 } else if (e->type == KeyPress) {
294 if (e->xkey.keycode == ob_keycode(OB_KEY_ESCAPE))
295 moveresize_end(TRUE);
296 else if (e->xkey.keycode == ob_keycode(OB_KEY_RETURN))
297 moveresize_end(FALSE);
298 else {
299 if (corner == prop_atoms.net_wm_moveresize_size_keyboard) {
300 int dx = 0, dy = 0, ox = cur_x, oy = cur_y;
301
302 if (e->xkey.keycode == ob_keycode(OB_KEY_RIGHT))
303 dx = MAX(4, moveresize_client->size_inc.width);
304 else if (e->xkey.keycode == ob_keycode(OB_KEY_LEFT))
305 dx = -MAX(4, moveresize_client->size_inc.width);
306 else if (e->xkey.keycode == ob_keycode(OB_KEY_DOWN))
307 dy = MAX(4, moveresize_client->size_inc.height);
308 else if (e->xkey.keycode == ob_keycode(OB_KEY_UP))
309 dy = -MAX(4, moveresize_client->size_inc.height);
310 else
311 return;
312
313 cur_x += dx;
314 cur_y += dy;
315 XWarpPointer(ob_display, None, None, 0, 0, 0, 0, dx, dy);
316 /* steal the motion events this causes */
317 XSync(ob_display, FALSE);
318 {
319 XEvent ce;
320 while (XCheckTypedEvent(ob_display, MotionNotify, &ce));
321 }
322
323 do_resize(FALSE);
324
325 /* because the cursor moves even though the window does
326 not nessesarily (resistance), this adjusts where the curor
327 thinks it started so that it keeps up with where the window
328 actually is */
329 start_x += dx - (cur_x - ox);
330 start_y += dy - (cur_y - oy);
331 } else if (corner == prop_atoms.net_wm_moveresize_move_keyboard) {
332 int dx = 0, dy = 0, ox = cur_x, oy = cur_y;
333 int opx, px, opy, py;
334
335 if (e->xkey.keycode == ob_keycode(OB_KEY_RIGHT))
336 dx = 4;
337 else if (e->xkey.keycode == ob_keycode(OB_KEY_LEFT))
338 dx = -4;
339 else if (e->xkey.keycode == ob_keycode(OB_KEY_DOWN))
340 dy = 4;
341 else if (e->xkey.keycode == ob_keycode(OB_KEY_UP))
342 dy = -4;
343 else
344 return;
345
346 cur_x += dx;
347 cur_y += dy;
348 screen_pointer_pos(&opx, &opy);
349 XWarpPointer(ob_display, None, None, 0, 0, 0, 0, dx, dy);
350 /* steal the motion events this causes */
351 XSync(ob_display, FALSE);
352 {
353 XEvent ce;
354 while (XCheckTypedEvent(ob_display, MotionNotify, &ce));
355 }
356 screen_pointer_pos(&px, &py);
357
358 do_move(FALSE);
359
360 /* because the cursor moves even though the window does
361 not nessesarily (resistance), this adjusts where the curor
362 thinks it started so that it keeps up with where the window
363 actually is */
364 start_x += (px - opx) - (cur_x - ox);
365 start_y += (py - opy) - (cur_y - oy);
366 }
367 }
368 }
369 }
This page took 0.049571 seconds and 5 git commands to generate.