]> Dogcows Code - chaz/openbox/blob - openbox/moveresize.c
adds option to have the popup centered above the window instead of centered, and...
[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 gint start_x, start_y, start_cx, start_cy, start_cw, start_ch;
42 static gint 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, gchar *format, gint a, gint b)
76 {
77 gchar *text;
78
79 text = g_strdup_printf(format, a, b);
80 if (config_resize_popup_pos == 1) /* == "Top" */
81 popup_position(popup, SouthGravity,
82 c->frame->area.x
83 + c->frame->area.width/2,
84 c->frame->area.y);
85 else /* == "Center" */
86 popup_position(popup, CenterGravity,
87 c->frame->area.x + c->frame->size.left +
88 c->area.width / 2,
89 c->frame->area.y + c->frame->size.top +
90 c->area.height / 2);
91 popup_show(popup, text);
92 g_free(text);
93 }
94
95 void moveresize_start(ObClient *c, gint x, gint y, guint b, guint32 cnr)
96 {
97 ObCursor cur;
98
99 moving = (cnr == prop_atoms.net_wm_moveresize_move ||
100 cnr == prop_atoms.net_wm_moveresize_move_keyboard);
101
102 if (moveresize_in_progress || !c->frame->visible ||
103 !(moving ?
104 (c->functions & OB_CLIENT_FUNC_MOVE) :
105 (c->functions & OB_CLIENT_FUNC_RESIZE)))
106 return;
107
108 moveresize_client = c;
109 start_cx = c->frame->area.x;
110 start_cy = c->frame->area.y;
111 /* these adjustments for the size_inc make resizing a terminal more
112 friendly. you essentially start the resize in the middle of the
113 increment instead of at 0, so you have to move half an increment
114 either way instead of a full increment one and 1 px the other. and this
115 is one large mother fucking comment. */
116 start_cw = c->area.width + c->size_inc.width / 2;
117 start_ch = c->area.height + c->size_inc.height / 2;
118 start_x = x;
119 start_y = y;
120 corner = cnr;
121 button = b;
122
123 /*
124 have to change start_cx and start_cy if going to do this..
125 if (corner == prop_atoms.net_wm_moveresize_move_keyboard ||
126 corner == prop_atoms.net_wm_moveresize_size_keyboard)
127 XWarpPointer(ob_display, None, c->window, 0, 0, 0, 0,
128 c->area.width / 2, c->area.height / 2);
129 */
130
131 if (moving) {
132 cur_x = start_cx;
133 cur_y = start_cy;
134 } else {
135 cur_x = start_cw;
136 cur_y = start_ch;
137 }
138
139 moveresize_in_progress = TRUE;
140
141 if (corner == prop_atoms.net_wm_moveresize_size_topleft)
142 cur = OB_CURSOR_NORTHWEST;
143 else if (corner == prop_atoms.net_wm_moveresize_size_top)
144 cur = OB_CURSOR_NORTH;
145 else if (corner == prop_atoms.net_wm_moveresize_size_topright)
146 cur = OB_CURSOR_NORTHEAST;
147 else if (corner == prop_atoms.net_wm_moveresize_size_right)
148 cur = OB_CURSOR_EAST;
149 else if (corner == prop_atoms.net_wm_moveresize_size_bottomright)
150 cur = OB_CURSOR_SOUTHEAST;
151 else if (corner == prop_atoms.net_wm_moveresize_size_bottom)
152 cur = OB_CURSOR_SOUTH;
153 else if (corner == prop_atoms.net_wm_moveresize_size_bottomleft)
154 cur = OB_CURSOR_SOUTHWEST;
155 else if (corner == prop_atoms.net_wm_moveresize_size_left)
156 cur = OB_CURSOR_WEST;
157 else if (corner == prop_atoms.net_wm_moveresize_size_keyboard)
158 cur = OB_CURSOR_SOUTHEAST;
159 else if (corner == prop_atoms.net_wm_moveresize_move)
160 cur = OB_CURSOR_MOVE;
161 else if (corner == prop_atoms.net_wm_moveresize_move_keyboard)
162 cur = OB_CURSOR_MOVE;
163 else
164 g_assert_not_reached();
165
166 grab_pointer(TRUE, cur);
167 grab_keyboard(TRUE);
168 }
169
170 void moveresize_end(gboolean cancel)
171 {
172 grab_keyboard(FALSE);
173 grab_pointer(FALSE, OB_CURSOR_NONE);
174
175 popup_hide(popup);
176
177 if (moving) {
178 client_move(moveresize_client,
179 (cancel ? start_cx : cur_x),
180 (cancel ? start_cy : cur_y));
181 } else {
182 client_configure(moveresize_client, lockcorner,
183 moveresize_client->area.x,
184 moveresize_client->area.y,
185 (cancel ? start_cw : cur_x),
186 (cancel ? start_ch : cur_y), TRUE, TRUE);
187 }
188
189 moveresize_in_progress = FALSE;
190 moveresize_client = NULL;
191 }
192
193 static void do_move(gboolean resist)
194 {
195 if (resist)
196 resist_move_windows(moveresize_client, &cur_x, &cur_y);
197 resist_move_monitors(moveresize_client, &cur_x, &cur_y);
198
199 /* get where the client should be */
200 frame_frame_gravity(moveresize_client->frame, &cur_x, &cur_y);
201 client_configure(moveresize_client, OB_CORNER_TOPLEFT, cur_x, cur_y,
202 moveresize_client->area.width,
203 moveresize_client->area.height, TRUE, FALSE);
204 if (config_resize_popup_show == 2) /* == "Always" */
205 popup_coords(moveresize_client, "%d x %d",
206 moveresize_client->frame->area.x,
207 moveresize_client->frame->area.y);
208 }
209
210 static void do_resize(gboolean resist)
211 {
212 /* resist_size_* needs the frame size */
213 cur_x += moveresize_client->frame->size.left +
214 moveresize_client->frame->size.right;
215 cur_y += moveresize_client->frame->size.top +
216 moveresize_client->frame->size.bottom;
217
218 if (resist)
219 resist_size_windows(moveresize_client, &cur_x, &cur_y, lockcorner);
220 resist_size_monitors(moveresize_client, &cur_x, &cur_y, lockcorner);
221
222 cur_x -= moveresize_client->frame->size.left +
223 moveresize_client->frame->size.right;
224 cur_y -= moveresize_client->frame->size.top +
225 moveresize_client->frame->size.bottom;
226
227 client_configure(moveresize_client, lockcorner,
228 moveresize_client->area.x, moveresize_client->area.y,
229 cur_x, cur_y, TRUE, FALSE);
230
231 /* this would be better with a fixed width font ... XXX can do it better
232 if there are 2 text boxes */
233 if (config_resize_popup_show == 2 || /* == "Always" */
234 (config_resize_popup_show == 1 && /* == "Nonpixel" */
235 (moveresize_client->size_inc.width > 1 ||
236 moveresize_client->size_inc.height > 1))
237 )
238 popup_coords(moveresize_client, "%d x %d",
239 moveresize_client->logical_size.width,
240 moveresize_client->logical_size.height);
241 }
242
243 void moveresize_event(XEvent *e)
244 {
245 g_assert(moveresize_in_progress);
246
247 if (e->type == ButtonPress) {
248 if (!button) {
249 start_x = e->xbutton.x_root;
250 start_y = e->xbutton.y_root;
251 button = e->xbutton.button; /* this will end it now */
252 }
253 } else if (e->type == ButtonRelease) {
254 if (!button || e->xbutton.button == button) {
255 moveresize_end(FALSE);
256 }
257 } else if (e->type == MotionNotify) {
258 if (moving) {
259 cur_x = start_cx + e->xmotion.x_root - start_x;
260 cur_y = start_cy + e->xmotion.y_root - start_y;
261 do_move(TRUE);
262 } else {
263 if (corner == prop_atoms.net_wm_moveresize_size_topleft) {
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_BOTTOMRIGHT;
267 } else if (corner == prop_atoms.net_wm_moveresize_size_top) {
268 cur_x = start_cw;
269 cur_y = start_ch - (e->xmotion.y_root - start_y);
270 lockcorner = OB_CORNER_BOTTOMRIGHT;
271 } else if (corner == prop_atoms.net_wm_moveresize_size_topright) {
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_BOTTOMLEFT;
275 } else if (corner == prop_atoms.net_wm_moveresize_size_right) {
276 cur_x = start_cw + (e->xmotion.x_root - start_x);
277 cur_y = start_ch;
278 lockcorner = OB_CORNER_BOTTOMLEFT;
279 } else if (corner ==
280 prop_atoms.net_wm_moveresize_size_bottomright) {
281 cur_x = start_cw + (e->xmotion.x_root - start_x);
282 cur_y = start_ch + (e->xmotion.y_root - start_y);
283 lockcorner = OB_CORNER_TOPLEFT;
284 } else if (corner == prop_atoms.net_wm_moveresize_size_bottom) {
285 cur_x = start_cw;
286 cur_y = start_ch + (e->xmotion.y_root - start_y);
287 lockcorner = OB_CORNER_TOPLEFT;
288 } else if (corner ==
289 prop_atoms.net_wm_moveresize_size_bottomleft) {
290 cur_x = start_cw - (e->xmotion.x_root - start_x);
291 cur_y = start_ch + (e->xmotion.y_root - start_y);
292 lockcorner = OB_CORNER_TOPRIGHT;
293 } else if (corner == prop_atoms.net_wm_moveresize_size_left) {
294 cur_x = start_cw - (e->xmotion.x_root - start_x);
295 cur_y = start_ch;
296 lockcorner = OB_CORNER_TOPRIGHT;
297 } else if (corner == prop_atoms.net_wm_moveresize_size_keyboard) {
298 cur_x = start_cw + (e->xmotion.x_root - start_x);
299 cur_y = start_ch + (e->xmotion.y_root - start_y);
300 lockcorner = OB_CORNER_TOPLEFT;
301 } else
302 g_assert_not_reached();
303
304 do_resize(TRUE);
305 }
306 } else if (e->type == KeyPress) {
307 if (e->xkey.keycode == ob_keycode(OB_KEY_ESCAPE))
308 moveresize_end(TRUE);
309 else if (e->xkey.keycode == ob_keycode(OB_KEY_RETURN))
310 moveresize_end(FALSE);
311 else {
312 if (corner == prop_atoms.net_wm_moveresize_size_keyboard) {
313 gint dx = 0, dy = 0, ox = cur_x, oy = cur_y;
314
315 if (e->xkey.keycode == ob_keycode(OB_KEY_RIGHT))
316 dx = MAX(4, moveresize_client->size_inc.width);
317 else if (e->xkey.keycode == ob_keycode(OB_KEY_LEFT))
318 dx = -MAX(4, moveresize_client->size_inc.width);
319 else if (e->xkey.keycode == ob_keycode(OB_KEY_DOWN))
320 dy = MAX(4, moveresize_client->size_inc.height);
321 else if (e->xkey.keycode == ob_keycode(OB_KEY_UP))
322 dy = -MAX(4, moveresize_client->size_inc.height);
323 else
324 return;
325
326 cur_x += dx;
327 cur_y += dy;
328 XWarpPointer(ob_display, None, None, 0, 0, 0, 0, dx, dy);
329 /* steal the motion events this causes */
330 XSync(ob_display, FALSE);
331 {
332 XEvent ce;
333 while (XCheckTypedEvent(ob_display, MotionNotify, &ce));
334 }
335
336 do_resize(FALSE);
337
338 /* because the cursor moves even though the window does
339 not nessesarily (resistance), this adjusts where the curor
340 thinks it started so that it keeps up with where the window
341 actually is */
342 start_x += dx - (cur_x - ox);
343 start_y += dy - (cur_y - oy);
344 } else if (corner == prop_atoms.net_wm_moveresize_move_keyboard) {
345 gint dx = 0, dy = 0, ox = cur_x, oy = cur_y;
346 gint opx, px, opy, py;
347
348 if (e->xkey.keycode == ob_keycode(OB_KEY_RIGHT))
349 dx = 4;
350 else if (e->xkey.keycode == ob_keycode(OB_KEY_LEFT))
351 dx = -4;
352 else if (e->xkey.keycode == ob_keycode(OB_KEY_DOWN))
353 dy = 4;
354 else if (e->xkey.keycode == ob_keycode(OB_KEY_UP))
355 dy = -4;
356 else
357 return;
358
359 cur_x += dx;
360 cur_y += dy;
361 screen_pointer_pos(&opx, &opy);
362 XWarpPointer(ob_display, None, None, 0, 0, 0, 0, dx, dy);
363 /* steal the motion events this causes */
364 XSync(ob_display, FALSE);
365 {
366 XEvent ce;
367 while (XCheckTypedEvent(ob_display, MotionNotify, &ce));
368 }
369 screen_pointer_pos(&px, &py);
370
371 do_move(FALSE);
372
373 /* because the cursor moves even though the window does
374 not nessesarily (resistance), this adjusts where the curor
375 thinks it started so that it keeps up with where the window
376 actually is */
377 start_x += (px - opx) - (cur_x - ox);
378 start_y += (py - opy) - (cur_y - oy);
379 }
380 }
381 }
382 }
This page took 0.059379 seconds and 5 git commands to generate.