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