new method for loading menu files etc
[mikachu/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 "dispatch.h"
8 #include "openbox.h"
9 #include "resist.h"
10 #include "popup.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 void moveresize_startup()
35 {
36     XSetWindowAttributes attrib;
37
38     popup = popup_new(FALSE);
39     popup_size_to_string(popup, "W:  0000  W:  0000");
40
41     attrib.save_under = True;
42 }
43
44 void moveresize_shutdown()
45 {
46     popup_free(popup);
47     popup = NULL;
48 }
49
50 static void popup_coords(char *format, int a, int b)
51 {
52     char *text;
53     Rect *area;
54
55     text = g_strdup_printf(format, a, b);
56     area = screen_physical_area_monitor(0);
57     popup_position(popup, NorthWestGravity,
58                    POPUP_X + area->x, POPUP_Y + area->y);
59     popup_show(popup, text, NULL);
60     g_free(text);
61 }
62
63 void moveresize_start(ObClient *c, int x, int y, guint b, guint32 cnr)
64 {
65     ObCursor cur;
66
67     g_assert(!moveresize_in_progress);
68
69     moveresize_client = c;
70     start_cx = c->frame->area.x;
71     start_cy = c->frame->area.y;
72     start_cw = c->area.width;
73     start_ch = c->area.height;
74     start_x = x;
75     start_y = y;
76     corner = cnr;
77     button = b;
78
79     /*
80       have to change start_cx and start_cy if going to do this..
81     if (corner == prop_atoms.net_wm_moveresize_move_keyboard ||
82         corner == prop_atoms.net_wm_moveresize_size_keyboard)
83         XWarpPointer(ob_display, None, c->window, 0, 0, 0, 0,
84                      c->area.width / 2, c->area.height / 2);
85     */
86
87     if (corner == prop_atoms.net_wm_moveresize_move ||
88         corner == prop_atoms.net_wm_moveresize_move_keyboard) {
89         cur_x = start_cx;
90         cur_y = start_cy;
91         moving = TRUE;
92     } else {
93         cur_x = start_cw;
94         cur_y = start_ch;
95         moving = FALSE;
96     }
97
98     moveresize_in_progress = TRUE;
99
100     if (corner == prop_atoms.net_wm_moveresize_size_topleft)
101         cur = OB_CURSOR_NORTHWEST;
102     else if (corner == prop_atoms.net_wm_moveresize_size_top)
103         cur = OB_CURSOR_NORTH;
104     else if (corner == prop_atoms.net_wm_moveresize_size_topright)
105         cur = OB_CURSOR_NORTHEAST;
106     else if (corner == prop_atoms.net_wm_moveresize_size_right)
107         cur = OB_CURSOR_EAST;
108     else if (corner == prop_atoms.net_wm_moveresize_size_bottomright)
109         cur = OB_CURSOR_SOUTHEAST;
110     else if (corner == prop_atoms.net_wm_moveresize_size_bottom)
111         cur = OB_CURSOR_SOUTH;
112     else if (corner == prop_atoms.net_wm_moveresize_size_bottomleft)
113         cur = OB_CURSOR_SOUTHWEST;
114     else if (corner == prop_atoms.net_wm_moveresize_size_left)
115         cur = OB_CURSOR_WEST;
116     else if (corner == prop_atoms.net_wm_moveresize_size_keyboard)
117         cur = OB_CURSOR_SOUTHEAST;
118     else if (corner == prop_atoms.net_wm_moveresize_move)
119         cur = OB_CURSOR_MOVE;
120     else if (corner == prop_atoms.net_wm_moveresize_move_keyboard)
121         cur = OB_CURSOR_MOVE;
122     else
123         g_assert_not_reached();
124
125     grab_pointer(TRUE, cur);
126     grab_keyboard(TRUE);
127 }
128
129 void moveresize_end(gboolean cancel)
130 {
131     grab_keyboard(FALSE);
132     grab_pointer(FALSE, None);
133
134     popup_hide(popup);
135
136     if (moving) {
137         client_configure(moveresize_client, OB_CORNER_TOPLEFT,
138                          (cancel ? start_cx : cur_x),
139                          (cancel ? start_cy : cur_y),
140                          start_cw, start_ch, TRUE, TRUE);
141     } else {
142         client_configure(moveresize_client, lockcorner,
143                          moveresize_client->area.x,
144                          moveresize_client->area.y,
145                          (cancel ? start_cw : cur_x),
146                          (cancel ? start_ch : cur_y), TRUE, TRUE);
147     }
148
149     moveresize_in_progress = FALSE;
150     moveresize_client = NULL;
151 }
152
153 static void do_move(gboolean resist)
154 {
155     Rect *a;
156
157     if (resist)
158         resist_move(moveresize_client, &cur_x, &cur_y);
159
160     dispatch_move(moveresize_client, &cur_x, &cur_y);
161
162     /* get where the client should be */
163     frame_frame_gravity(moveresize_client->frame, &cur_x, &cur_y);
164     client_configure(moveresize_client, OB_CORNER_TOPLEFT, cur_x, cur_y,
165                      start_cw, start_ch, TRUE, FALSE);
166
167     /* this would be better with a fixed width font ... XXX can do it better
168        if there are 2 text boxes */
169     a = screen_area(screen_desktop);
170     popup_coords("X:  %4d  Y:  %4d",
171                  moveresize_client->frame->area.x - a->x,
172                  moveresize_client->frame->area.y - a->y);
173 }
174
175 static void do_resize(gboolean resist)
176 {
177     /* dispatch_resize needs the frame size */
178     cur_x += moveresize_client->frame->size.left +
179         moveresize_client->frame->size.right;
180     cur_y += moveresize_client->frame->size.top +
181         moveresize_client->frame->size.bottom;
182
183     if (resist)
184         resist_size(moveresize_client, &cur_x, &cur_y, lockcorner);
185
186     dispatch_resize(moveresize_client, &cur_x, &cur_y, lockcorner);
187
188     cur_x -= moveresize_client->frame->size.left +
189         moveresize_client->frame->size.right;
190     cur_y -= moveresize_client->frame->size.top +
191         moveresize_client->frame->size.bottom;
192     
193     client_configure(moveresize_client, lockcorner, 
194                      moveresize_client->area.x, moveresize_client->area.y,
195                      cur_x, cur_y, TRUE, FALSE);
196
197     /* this would be better with a fixed width font ... XXX can do it better
198        if there are 2 text boxes */
199     popup_coords("W:  %4d  H:  %4d", moveresize_client->logical_size.width,
200                  moveresize_client->logical_size.height);
201 }
202
203 void moveresize_event(XEvent *e)
204 {
205     g_assert(moveresize_in_progress);
206
207     if (e->type == ButtonPress) {
208         if (!button) {
209             start_x = e->xbutton.x_root;
210             start_y = e->xbutton.y_root;
211             button = e->xbutton.button; /* this will end it now */
212         }
213     } else if (e->type == ButtonRelease) {
214         if (!button || e->xbutton.button == button) {
215             moveresize_end(FALSE);
216         }
217     } else if (e->type == MotionNotify) {
218         if (moving) {
219             cur_x = start_cx + e->xmotion.x_root - start_x;
220             cur_y = start_cy + e->xmotion.y_root - start_y;
221             do_move(TRUE);
222         } else {
223             if (corner == prop_atoms.net_wm_moveresize_size_topleft) {
224                 cur_x = start_cw - (e->xmotion.x_root - start_x);
225                 cur_y = start_ch - (e->xmotion.y_root - start_y);
226                 lockcorner = OB_CORNER_BOTTOMRIGHT;
227             } else if (corner == prop_atoms.net_wm_moveresize_size_top) {
228                 cur_x = start_cw;
229                 cur_y = start_ch - (e->xmotion.y_root - start_y);
230                 lockcorner = OB_CORNER_BOTTOMRIGHT;
231             } else if (corner == prop_atoms.net_wm_moveresize_size_topright) {
232                 cur_x = start_cw + (e->xmotion.x_root - start_x);
233                 cur_y = start_ch - (e->xmotion.y_root - start_y);
234                 lockcorner = OB_CORNER_BOTTOMLEFT;
235             } else if (corner == prop_atoms.net_wm_moveresize_size_right) { 
236                 cur_x = start_cw + (e->xmotion.x_root - start_x);
237                 cur_y = start_ch;
238                 lockcorner = OB_CORNER_BOTTOMLEFT;
239             } else if (corner ==
240                        prop_atoms.net_wm_moveresize_size_bottomright) {
241                 cur_x = start_cw + (e->xmotion.x_root - start_x);
242                 cur_y = start_ch + (e->xmotion.y_root - start_y);
243                 lockcorner = OB_CORNER_TOPLEFT;
244             } else if (corner == prop_atoms.net_wm_moveresize_size_bottom) {
245                 cur_x = start_cw;
246                 cur_y = start_ch + (e->xmotion.y_root - start_y);
247                 lockcorner = OB_CORNER_TOPLEFT;
248             } else if (corner ==
249                        prop_atoms.net_wm_moveresize_size_bottomleft) {
250                 cur_x = start_cw - (e->xmotion.x_root - start_x);
251                 cur_y = start_ch + (e->xmotion.y_root - start_y);
252                 lockcorner = OB_CORNER_TOPRIGHT;
253             } else if (corner == prop_atoms.net_wm_moveresize_size_left) {
254                 cur_x = start_cw - (e->xmotion.x_root - start_x);
255                 cur_y = start_ch;
256                 lockcorner = OB_CORNER_TOPRIGHT;
257             } else if (corner == prop_atoms.net_wm_moveresize_size_keyboard) {
258                 cur_x = start_cw + (e->xmotion.x_root - start_x);
259                 cur_y = start_ch + (e->xmotion.y_root - start_y);
260                 lockcorner = OB_CORNER_TOPLEFT;
261             } else
262                 g_assert_not_reached();
263
264             do_resize(TRUE);
265         }
266     } else if (e->type == KeyPress) {
267         if (e->xkey.keycode == ob_keycode(OB_KEY_ESCAPE))
268             moveresize_end(TRUE);
269         else if (e->xkey.keycode == ob_keycode(OB_KEY_RETURN))
270             moveresize_end(FALSE);
271         else {
272             if (corner == prop_atoms.net_wm_moveresize_size_keyboard) {
273                 int dx = 0, dy = 0;
274
275                 if (e->xkey.keycode == ob_keycode(OB_KEY_RIGHT))
276                     dx = MAX(4, moveresize_client->size_inc.width);
277                 else if (e->xkey.keycode == ob_keycode(OB_KEY_LEFT))
278                     dx = -MAX(4, moveresize_client->size_inc.width);
279                 else if (e->xkey.keycode == ob_keycode(OB_KEY_DOWN))
280                     dy = MAX(4, moveresize_client->size_inc.height);
281                 else if (e->xkey.keycode == ob_keycode(OB_KEY_UP))
282                     dy = -MAX(4, moveresize_client->size_inc.height);
283                 else
284                     return;
285
286                 cur_x += dx;
287                 cur_y += dy;
288                 XWarpPointer(ob_display, None, None, 0, 0, 0, 0, dx, dy);
289
290                 do_resize(FALSE);
291             } else if (corner == prop_atoms.net_wm_moveresize_move_keyboard) {
292                 int dx = 0, dy = 0;
293
294                 if (e->xkey.keycode == ob_keycode(OB_KEY_RIGHT))
295                     dx = 4;
296                 else if (e->xkey.keycode == ob_keycode(OB_KEY_LEFT))
297                     dx = -4;
298                 else if (e->xkey.keycode == ob_keycode(OB_KEY_DOWN))
299                     dy = 4;
300                 else if (e->xkey.keycode == ob_keycode(OB_KEY_UP))
301                     dy = -4;
302                 else
303                     return;
304
305                 cur_x += dx;
306                 cur_y += dy;
307                 XWarpPointer(ob_display, None, None, 0, 0, 0, 0, dx, dy);
308
309                 do_move(FALSE);
310             }
311         }
312     }
313 }