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