add comment about the new code in moveresize for size increment windows
[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 #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     client_configure(moveresize_client, OB_CORNER_TOPLEFT, cur_x, cur_y,
178                      start_cw, start_ch, TRUE, FALSE);
179
180     /* this would be better with a fixed width font ... XXX can do it better
181        if there are 2 text boxes */
182     a = screen_area(screen_desktop);
183     popup_coords("X:  %4d  Y:  %4d",
184                  moveresize_client->frame->area.x - a->x,
185                  moveresize_client->frame->area.y - a->y);
186 }
187
188 static void do_resize(gboolean resist)
189 {
190     /* resist_size_* needs the frame size */
191     cur_x += moveresize_client->frame->size.left +
192         moveresize_client->frame->size.right;
193     cur_y += moveresize_client->frame->size.top +
194         moveresize_client->frame->size.bottom;
195
196     if (resist)
197         resist_size_windows(moveresize_client, &cur_x, &cur_y, lockcorner);
198     resist_size_monitors(moveresize_client, &cur_x, &cur_y, lockcorner);
199
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     client_configure(moveresize_client, lockcorner, 
206                      moveresize_client->area.x, moveresize_client->area.y,
207                      cur_x, cur_y, TRUE, FALSE);
208
209     /* this would be better with a fixed width font ... XXX can do it better
210        if there are 2 text boxes */
211     popup_coords("W:  %4d  H:  %4d", moveresize_client->logical_size.width,
212                  moveresize_client->logical_size.height);
213 }
214
215 void moveresize_event(XEvent *e)
216 {
217     g_assert(moveresize_in_progress);
218
219     if (e->type == ButtonPress) {
220         if (!button) {
221             start_x = e->xbutton.x_root;
222             start_y = e->xbutton.y_root;
223             button = e->xbutton.button; /* this will end it now */
224         }
225     } else if (e->type == ButtonRelease) {
226         if (!button || e->xbutton.button == button) {
227             moveresize_end(FALSE);
228         }
229     } else if (e->type == MotionNotify) {
230         if (moving) {
231             cur_x = start_cx + e->xmotion.x_root - start_x;
232             cur_y = start_cy + e->xmotion.y_root - start_y;
233             do_move(TRUE);
234         } else {
235             if (corner == prop_atoms.net_wm_moveresize_size_topleft) {
236                 cur_x = start_cw - (e->xmotion.x_root - start_x);
237                 cur_y = start_ch - (e->xmotion.y_root - start_y);
238                 lockcorner = OB_CORNER_BOTTOMRIGHT;
239             } else if (corner == prop_atoms.net_wm_moveresize_size_top) {
240                 cur_x = start_cw;
241                 cur_y = start_ch - (e->xmotion.y_root - start_y);
242                 lockcorner = OB_CORNER_BOTTOMRIGHT;
243             } else if (corner == prop_atoms.net_wm_moveresize_size_topright) {
244                 cur_x = start_cw + (e->xmotion.x_root - start_x);
245                 cur_y = start_ch - (e->xmotion.y_root - start_y);
246                 lockcorner = OB_CORNER_BOTTOMLEFT;
247             } else if (corner == prop_atoms.net_wm_moveresize_size_right) { 
248                 cur_x = start_cw + (e->xmotion.x_root - start_x);
249                 cur_y = start_ch;
250                 lockcorner = OB_CORNER_BOTTOMLEFT;
251             } else if (corner ==
252                        prop_atoms.net_wm_moveresize_size_bottomright) {
253                 cur_x = start_cw + (e->xmotion.x_root - start_x);
254                 cur_y = start_ch + (e->xmotion.y_root - start_y);
255                 lockcorner = OB_CORNER_TOPLEFT;
256             } else if (corner == prop_atoms.net_wm_moveresize_size_bottom) {
257                 cur_x = start_cw;
258                 cur_y = start_ch + (e->xmotion.y_root - start_y);
259                 lockcorner = OB_CORNER_TOPLEFT;
260             } else if (corner ==
261                        prop_atoms.net_wm_moveresize_size_bottomleft) {
262                 cur_x = start_cw - (e->xmotion.x_root - start_x);
263                 cur_y = start_ch + (e->xmotion.y_root - start_y);
264                 lockcorner = OB_CORNER_TOPRIGHT;
265             } else if (corner == prop_atoms.net_wm_moveresize_size_left) {
266                 cur_x = start_cw - (e->xmotion.x_root - start_x);
267                 cur_y = start_ch;
268                 lockcorner = OB_CORNER_TOPRIGHT;
269             } else if (corner == prop_atoms.net_wm_moveresize_size_keyboard) {
270                 cur_x = start_cw + (e->xmotion.x_root - start_x);
271                 cur_y = start_ch + (e->xmotion.y_root - start_y);
272                 lockcorner = OB_CORNER_TOPLEFT;
273             } else
274                 g_assert_not_reached();
275
276             do_resize(TRUE);
277         }
278     } else if (e->type == KeyPress) {
279         if (e->xkey.keycode == ob_keycode(OB_KEY_ESCAPE))
280             moveresize_end(TRUE);
281         else if (e->xkey.keycode == ob_keycode(OB_KEY_RETURN))
282             moveresize_end(FALSE);
283         else {
284             if (corner == prop_atoms.net_wm_moveresize_size_keyboard) {
285                 int dx = 0, dy = 0;
286
287                 if (e->xkey.keycode == ob_keycode(OB_KEY_RIGHT))
288                     dx = MAX(4, moveresize_client->size_inc.width);
289                 else if (e->xkey.keycode == ob_keycode(OB_KEY_LEFT))
290                     dx = -MAX(4, moveresize_client->size_inc.width);
291                 else if (e->xkey.keycode == ob_keycode(OB_KEY_DOWN))
292                     dy = MAX(4, moveresize_client->size_inc.height);
293                 else if (e->xkey.keycode == ob_keycode(OB_KEY_UP))
294                     dy = -MAX(4, moveresize_client->size_inc.height);
295                 else
296                     return;
297
298                 cur_x += dx;
299                 cur_y += dy;
300                 XWarpPointer(ob_display, None, None, 0, 0, 0, 0, dx, dy);
301
302                 do_resize(FALSE);
303             } else if (corner == prop_atoms.net_wm_moveresize_move_keyboard) {
304                 int dx = 0, dy = 0;
305
306                 if (e->xkey.keycode == ob_keycode(OB_KEY_RIGHT))
307                     dx = 4;
308                 else if (e->xkey.keycode == ob_keycode(OB_KEY_LEFT))
309                     dx = -4;
310                 else if (e->xkey.keycode == ob_keycode(OB_KEY_DOWN))
311                     dy = 4;
312                 else if (e->xkey.keycode == ob_keycode(OB_KEY_UP))
313                     dy = -4;
314                 else
315                     return;
316
317                 cur_x += dx;
318                 cur_y += dy;
319                 XWarpPointer(ob_display, None, None, 0, 0, 0, 0, dx, dy);
320
321                 do_move(FALSE);
322             }
323         }
324     }
325 }