fix up support for moveresize. make keyboard grabs Async so that i can hit escape...
[dana/openbox.git] / openbox / moveresize.c
1 #include "grab.h"
2 #include "framerender.h"
3 #include "prop.h"
4 #include "client.h"
5 #include "dispatch.h"
6 #include "openbox.h"
7
8 #include <X11/Xlib.h>
9 #include <glib.h>
10
11 gboolean moveresize_in_progress = FALSE;
12 static gboolean moving = FALSE; /* TRUE - moving, FALSE - resizing */
13
14 static Window coords = None;
15 static int start_x, start_y, start_cx, start_cy, start_cw, start_ch;
16 static int cur_x, cur_y;
17 static Client *client;
18 static guint button;
19 static guint32 corner;
20 static Corner lockcorner;
21
22 static guint button_return, button_escape, button_left, button_right,
23     button_up, button_down;
24
25 #define POPUP_X (10)
26 #define POPUP_Y (10)
27
28 void moveresize_startup()
29 {
30     button_return = XKeysymToKeycode(ob_display, XStringToKeysym("Return"));
31     button_escape = XKeysymToKeycode(ob_display, XStringToKeysym("Escape"));
32     button_left = XKeysymToKeycode(ob_display, XStringToKeysym("Left"));
33     button_right = XKeysymToKeycode(ob_display, XStringToKeysym("Right"));
34     button_up = XKeysymToKeycode(ob_display, XStringToKeysym("Up"));
35     button_down = XKeysymToKeycode(ob_display, XStringToKeysym("Down"));
36 }
37
38 static void popup_coords(char *format, int a, int b)
39 {
40     XSetWindowAttributes attrib;
41     Size s;
42     char *text;
43
44     if (coords == None) {
45         attrib.override_redirect = TRUE;
46         coords = XCreateWindow(ob_display, ob_root,
47                                0, 0, 1, 1, 0, render_depth, InputOutput,
48                                render_visual, CWOverrideRedirect, &attrib);
49         g_assert(coords != None);
50
51         XMapWindow(ob_display, coords);
52     }
53
54     text = g_strdup_printf(format, a, b);
55     framerender_size_popup_label(text, &s);
56     XMoveResizeWindow(ob_display, coords,
57                       POPUP_X, POPUP_Y, s.width, s.height);
58     framerender_popup_label(coords, &s, text);
59     g_free(text);
60 }
61
62 void moveresize_start(Client *c, int x, int y, guint b, guint32 cnr)
63 {
64     Cursor cur;
65
66     g_assert(!moveresize_in_progress);
67
68     client = c;
69     start_cx = c->frame->area.x;
70     start_cy = c->frame->area.y;
71     start_cw = c->area.width;
72     start_ch = c->area.height;
73     start_x = x;
74     start_y = y;
75     if (corner == prop_atoms.net_wm_moveresize_move_keyboard ||
76         corner == prop_atoms.net_wm_moveresize_size_keyboard)
77         button = 0; /* mouse can't end it without being pressed first */
78     else
79         button = b;
80     corner = cnr;
81
82     if (corner == prop_atoms.net_wm_moveresize_move ||
83         corner == prop_atoms.net_wm_moveresize_move_keyboard) {
84         cur_x = start_cx;
85         cur_y = start_cy;
86         moving = TRUE;
87     } else {
88         cur_x = start_cw;
89         cur_y = start_ch;
90         moving = FALSE;
91     }
92
93     moveresize_in_progress = TRUE;
94
95     if (corner == prop_atoms.net_wm_moveresize_size_topleft)
96         cur = ob_cursors.tl;
97     else if (corner == prop_atoms.net_wm_moveresize_size_top)
98         cur = ob_cursors.tl;
99     else if (corner == prop_atoms.net_wm_moveresize_size_topright)
100         cur = ob_cursors.tr;
101     else if (corner == prop_atoms.net_wm_moveresize_size_right)
102         cur = ob_cursors.tr;
103     else if (corner == prop_atoms.net_wm_moveresize_size_bottomright)
104         cur = ob_cursors.br;
105     else if (corner == prop_atoms.net_wm_moveresize_size_bottom)
106         cur = ob_cursors.br;
107     else if (corner == prop_atoms.net_wm_moveresize_size_bottomleft)
108         cur = ob_cursors.bl;
109     else if (corner == prop_atoms.net_wm_moveresize_size_left)
110         cur = ob_cursors.bl;
111     else if (corner == prop_atoms.net_wm_moveresize_size_keyboard)
112         cur = ob_cursors.br;
113     else if (corner == prop_atoms.net_wm_moveresize_move)
114         cur = ob_cursors.move;
115     else if (corner == prop_atoms.net_wm_moveresize_move_keyboard)
116         cur = ob_cursors.move;
117     else
118         g_assert_not_reached();
119
120     grab_pointer(TRUE, cur);
121     grab_keyboard(TRUE);
122 }
123
124 static void end_moveresize(gboolean cancel)
125 {
126     grab_keyboard(FALSE);
127     grab_pointer(FALSE, None);
128
129     XDestroyWindow(ob_display, coords);
130     coords = None;
131
132     moveresize_in_progress = FALSE;
133
134     if (moving) {
135         client_configure(client, Corner_TopLeft, (cancel ? start_cx : cur_x),
136                          (cancel ? start_cy : cur_y),
137                          start_cw, start_ch, TRUE, TRUE);
138     } else {
139         client_configure(client, lockcorner, client->area.x,
140                          client->area.y, (cancel ? start_cw : cur_x),
141                          (cancel ? start_ch : cur_y), TRUE, TRUE);
142     }
143 }
144
145 static void do_move()
146 {
147     dispatch_move(client, &cur_x, &cur_y);
148
149     popup_coords("X:  %d  Y:  %d", cur_x, cur_y);
150
151     /* get where the client should be */
152     frame_frame_gravity(client->frame, &cur_x, &cur_y);
153     client_configure(client, Corner_TopLeft, cur_x, cur_y,
154                      start_cw, start_ch, TRUE, FALSE);
155 }
156
157 static void do_resize()
158 {
159     /* dispatch_resize needs the frame size */
160     cur_x += client->frame->size.left + client->frame->size.right;
161     cur_y += client->frame->size.top + client->frame->size.bottom;
162
163     dispatch_resize(client, &cur_x, &cur_y, lockcorner);
164
165     cur_x -= client->frame->size.left + client->frame->size.right;
166     cur_y -= client->frame->size.top + client->frame->size.bottom;
167     
168     client_configure(client, lockcorner, client->area.x,
169                      client->area.y, cur_x, cur_y, TRUE, FALSE);
170
171     popup_coords("W:  %d  H:  %d", client->logical_size.width,
172                  client->logical_size.height);
173 }
174
175 void moveresize_event(XEvent *e)
176 {
177     g_assert(moveresize_in_progress);
178
179     if (e->type == ButtonPress) {
180         if (!button) {
181             start_x = e->xbutton.x_root;
182             start_y = e->xbutton.y_root;
183             button = e->xbutton.button; /* this will end it now */
184         }
185     } else if (e->type == ButtonRelease) {
186         if (e->xbutton.button == button) {
187             end_moveresize(FALSE);
188         }
189     } else if (e->type == MotionNotify) {
190         if (moving) {
191             cur_x = start_cx + e->xmotion.x_root - start_x;
192             cur_y = start_cy + e->xmotion.y_root - start_y;
193             do_move();
194         } else {
195             if (corner == prop_atoms.net_wm_moveresize_size_topleft) {
196                 cur_x = start_cw - (e->xmotion.x_root - start_x);
197                 cur_y = start_ch - (e->xmotion.y_root - start_y);
198                 lockcorner = Corner_BottomRight;
199             } else if (corner == prop_atoms.net_wm_moveresize_size_top) {
200                 cur_x = start_cw;
201                 cur_y = start_ch - (e->xmotion.y_root - start_y);
202                 lockcorner = Corner_BottomRight;
203             } else if (corner == prop_atoms.net_wm_moveresize_size_topright) {
204                 cur_x = start_cw + (e->xmotion.x_root - start_x);
205                 cur_y = start_ch - (e->xmotion.y_root - start_y);
206                 lockcorner = Corner_BottomLeft;
207             } else if (corner == prop_atoms.net_wm_moveresize_size_right) { 
208                 cur_x = start_cw + (e->xmotion.x_root - start_x);
209                 cur_y = start_ch;
210                 lockcorner = Corner_BottomLeft;
211             } else if (corner ==
212                        prop_atoms.net_wm_moveresize_size_bottomright) {
213                 cur_x = start_cw + (e->xmotion.x_root - start_x);
214                 cur_y = start_ch + (e->xmotion.y_root - start_y);
215                 lockcorner = Corner_TopLeft;
216             } else if (corner == prop_atoms.net_wm_moveresize_size_bottom) {
217                 cur_x = start_cw;
218                 cur_y = start_ch + (e->xmotion.y_root - start_y);
219                 lockcorner = Corner_TopLeft;
220             } else if (corner ==
221                        prop_atoms.net_wm_moveresize_size_bottomleft) {
222                 cur_x = start_cw - (e->xmotion.x_root - start_x);
223                 cur_y = start_ch + (e->xmotion.y_root - start_y);
224                 lockcorner = Corner_TopRight;
225             } else if (corner == prop_atoms.net_wm_moveresize_size_left) {
226                 cur_x = start_cw - (e->xmotion.x_root - start_x);
227                 cur_y = start_ch;
228                 lockcorner = Corner_TopRight;
229             } else if (corner == prop_atoms.net_wm_moveresize_size_keyboard) {
230                 cur_x = start_cw + (e->xmotion.x_root - start_x);
231                 cur_y = start_ch + (e->xmotion.y_root - start_y);
232                 lockcorner = Corner_TopLeft;
233             } else
234                 g_assert_not_reached();
235
236             do_resize();
237         }
238     } else if (e->type == KeyPress) {
239         if (e->xkey.keycode == button_escape)
240             end_moveresize(TRUE);
241         else if (e->xkey.keycode == button_return)
242             end_moveresize(FALSE);
243         else {
244             if (corner == prop_atoms.net_wm_moveresize_size_keyboard) {
245                 if (e->xkey.keycode == button_right)
246                     cur_x += MAX(4, client->size_inc.width);
247                 else if (e->xkey.keycode == button_left)
248                     cur_x -= MAX(4, client->size_inc.width);
249                 else if (e->xkey.keycode == button_down)
250                     cur_y += MAX(4, client->size_inc.height);
251                 else if (e->xkey.keycode == button_up)
252                     cur_y -= MAX(4, client->size_inc.height);
253                 else
254                     return;
255                 do_resize();
256             } else if (corner == prop_atoms.net_wm_moveresize_move_keyboard) {
257                 if (e->xkey.keycode == button_right)
258                     cur_x += 4;
259                 else if (e->xkey.keycode == button_left)
260                     cur_x -= 4;
261                 else if (e->xkey.keycode == button_down)
262                     cur_y += 4;
263                 else if (e->xkey.keycode == button_up)
264                     cur_y -= 4;
265                 else
266                     return;
267                 do_move();
268             }
269         }
270     }
271 }