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