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