]> icculus.org git repositories - mikachu/openbox.git/blob - openbox/moveresize.c
add internal popups n shit to the stacking list.
[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 "dispatch.h"
7 #include "openbox.h"
8 #include "popup.h"
9 #include "render/render.h"
10 #include "render/theme.h"
11
12 #include <X11/Xlib.h>
13 #include <glib.h>
14
15 gboolean moveresize_in_progress = FALSE;
16 Client *moveresize_client = NULL;
17
18 static gboolean moving = FALSE; /* TRUE - moving, FALSE - resizing */
19
20 static int start_x, start_y, start_cx, start_cy, start_cw, start_ch;
21 static int cur_x, cur_y;
22 static guint button;
23 static guint32 corner;
24 static Corner lockcorner;
25
26 static guint button_return, button_escape, button_left, button_right,
27     button_up, button_down;
28
29 static Popup *popup = NULL;
30 static InternalWindow opaque_window = { { Window_Internal }, None };
31 static GC opaque_gc = None;
32 static gboolean first_draw = FALSE;
33
34 #define POPUP_X (10)
35 #define POPUP_Y (10)
36
37 gboolean config_opaque_move = FALSE;
38 gboolean config_opaque_resize = FALSE;
39
40 void moveresize_startup()
41 {
42     XSetWindowAttributes attrib;
43     XGCValues gcv;
44
45     button_return = XKeysymToKeycode(ob_display, XStringToKeysym("Return"));
46     button_escape = XKeysymToKeycode(ob_display, XStringToKeysym("Escape"));
47     button_left = XKeysymToKeycode(ob_display, XStringToKeysym("Left"));
48     button_right = XKeysymToKeycode(ob_display, XStringToKeysym("Right"));
49     button_up = XKeysymToKeycode(ob_display, XStringToKeysym("Up"));
50     button_down = XKeysymToKeycode(ob_display, XStringToKeysym("Down"));
51
52     popup = popup_new(FALSE);
53     popup_size_to_string(popup, "W:  0000  W:  0000");
54     popup_position(popup, NorthWestGravity, POPUP_X, POPUP_Y);
55
56     attrib.save_under = True;
57     opaque_window.win = XCreateWindow(ob_display, ob_root, 0, 0, 1, 1, 0,
58                                       render_depth, InputOutput, render_visual,
59                                       CWSaveUnder, &attrib);
60     stacking_add(&opaque_window);
61     stacking_raise(INTERNAL_AS_WINDOW(&opaque_window));
62
63     /* a GC to invert stuff */
64     gcv.function = GXxor;
65     gcv.line_width = theme_bwidth;
66     gcv.foreground = (WhitePixel(ob_display, ob_screen) ^
67                       BlackPixel(ob_display, ob_screen));
68     opaque_gc = XCreateGC(ob_display, opaque_window.win,
69                           GCFunction | GCForeground | GCLineWidth, &gcv);
70 }
71
72 void moveresize_shutdown()
73 {
74     popup_free(popup);
75     popup = NULL;
76     stacking_remove(&opaque_window);
77     XFreeGC(ob_display, opaque_gc);
78     XDestroyWindow(ob_display, opaque_window.win);
79 }
80
81 static void popup_coords(char *format, int a, int b)
82 {
83     char *text;
84
85     text = g_strdup_printf(format, a, b);
86     popup_show(popup, text, NULL);
87     g_free(text);
88 }
89
90 void moveresize_start(Client *c, int x, int y, guint b, guint32 cnr)
91 {
92     Cursor cur;
93
94     g_assert(!moveresize_in_progress);
95
96     moveresize_client = c;
97     start_cx = c->frame->area.x;
98     start_cy = c->frame->area.y;
99     start_cw = c->area.width;
100     start_ch = c->area.height;
101     start_x = x;
102     start_y = y;
103     if (corner == prop_atoms.net_wm_moveresize_move_keyboard ||
104         corner == prop_atoms.net_wm_moveresize_size_keyboard)
105         button = 0; /* mouse can't end it without being pressed first */
106     else
107         button = b;
108     corner = cnr;
109
110     if (corner == prop_atoms.net_wm_moveresize_move ||
111         corner == prop_atoms.net_wm_moveresize_move_keyboard) {
112         cur_x = start_cx;
113         cur_y = start_cy;
114         moving = TRUE;
115     } else {
116         cur_x = start_cw;
117         cur_y = start_ch;
118         moving = FALSE;
119     }
120
121     moveresize_in_progress = TRUE;
122
123     if (corner == prop_atoms.net_wm_moveresize_size_topleft)
124         cur = ob_cursors.tl;
125     else if (corner == prop_atoms.net_wm_moveresize_size_top)
126         cur = ob_cursors.t;
127     else if (corner == prop_atoms.net_wm_moveresize_size_topright)
128         cur = ob_cursors.tr;
129     else if (corner == prop_atoms.net_wm_moveresize_size_right)
130         cur = ob_cursors.r;
131     else if (corner == prop_atoms.net_wm_moveresize_size_bottomright)
132         cur = ob_cursors.br;
133     else if (corner == prop_atoms.net_wm_moveresize_size_bottom)
134         cur = ob_cursors.b;
135     else if (corner == prop_atoms.net_wm_moveresize_size_bottomleft)
136         cur = ob_cursors.bl;
137     else if (corner == prop_atoms.net_wm_moveresize_size_left)
138         cur = ob_cursors.l;
139     else if (corner == prop_atoms.net_wm_moveresize_size_keyboard)
140         cur = ob_cursors.br;
141     else if (corner == prop_atoms.net_wm_moveresize_move)
142         cur = ob_cursors.move;
143     else if (corner == prop_atoms.net_wm_moveresize_move_keyboard)
144         cur = ob_cursors.move;
145     else
146         g_assert_not_reached();
147
148     grab_pointer(TRUE, cur);
149     grab_keyboard(TRUE);
150
151     XResizeWindow(ob_display, opaque_window.win, screen_physical_size.width,
152                   screen_physical_size.height);
153     stacking_raise(INTERNAL_AS_WINDOW(&opaque_window));
154     if (corner == prop_atoms.net_wm_moveresize_move ||
155         corner == prop_atoms.net_wm_moveresize_move_keyboard) {
156         if (!config_opaque_move)
157             XMapWindow(ob_display, opaque_window.win);
158     } else {
159         if (!config_opaque_resize)
160             XMapWindow(ob_display, opaque_window.win);
161     }
162     first_draw = TRUE;
163 }
164
165 void moveresize_end(gboolean cancel)
166 {
167     XUnmapWindow(ob_display, opaque_window.win);
168
169     grab_keyboard(FALSE);
170     grab_pointer(FALSE, None);
171
172     popup_hide(popup);
173
174     if (moving) {
175         client_configure(moveresize_client, Corner_TopLeft,
176                          (cancel ? start_cx : cur_x),
177                          (cancel ? start_cy : cur_y),
178                          start_cw, start_ch, TRUE, TRUE);
179     } else {
180         client_configure(moveresize_client, lockcorner,
181                          moveresize_client->area.x,
182                          moveresize_client->area.y,
183                          (cancel ? start_cw : cur_x),
184                          (cancel ? start_ch : cur_y), TRUE, TRUE);
185     }
186
187     moveresize_in_progress = FALSE;
188     moveresize_client = NULL;
189 }
190
191 static void do_move()
192 {
193     int oldx, oldy, oldw, oldh;
194
195     dispatch_move(moveresize_client, &cur_x, &cur_y);
196
197     oldx = moveresize_client->frame->area.x;
198     oldy = moveresize_client->frame->area.y;
199     oldw = moveresize_client->frame->area.width;
200     oldh = moveresize_client->frame->area.height;
201     /* get where the client should be */
202     frame_frame_gravity(moveresize_client->frame, &cur_x, &cur_y);
203     client_configure(moveresize_client, Corner_TopLeft, cur_x, cur_y,
204                      start_cw, start_ch, TRUE, FALSE);
205     /* draw the new one */
206     if (!config_opaque_move)
207         XDrawRectangle(ob_display, opaque_window.win, opaque_gc,
208                        moveresize_client->frame->area.x,
209                        moveresize_client->frame->area.y,
210                        moveresize_client->frame->area.width - 1,
211                        moveresize_client->frame->area.height - 1);
212     /* erase the old one */
213     if (!config_opaque_move && !first_draw)
214         XDrawRectangle(ob_display, opaque_window.win, opaque_gc,
215                        oldx, oldy, oldw - 1, oldh - 1);
216     first_draw = FALSE;
217
218     /* this would be better with a fixed width font ... XXX can do it better
219        if there are 2 text boxes */
220     popup_coords("X:  %4d  Y:  %4d", moveresize_client->frame->area.x,
221                  moveresize_client->frame->area.y);
222 }
223
224 static void do_resize()
225 {
226     int oldx, oldy, oldw, oldh;
227
228     /* dispatch_resize needs the frame size */
229     cur_x += moveresize_client->frame->size.left +
230         moveresize_client->frame->size.right;
231     cur_y += moveresize_client->frame->size.top +
232         moveresize_client->frame->size.bottom;
233
234     dispatch_resize(moveresize_client, &cur_x, &cur_y, lockcorner);
235
236     cur_x -= moveresize_client->frame->size.left +
237         moveresize_client->frame->size.right;
238     cur_y -= moveresize_client->frame->size.top +
239         moveresize_client->frame->size.bottom;
240     
241     oldx = moveresize_client->frame->area.x;
242     oldy = moveresize_client->frame->area.y;
243     oldw = moveresize_client->frame->area.width;
244     oldh = moveresize_client->frame->area.height;
245     client_configure(moveresize_client, lockcorner, 
246                      moveresize_client->area.x, moveresize_client->area.y,
247                      cur_x, cur_y, TRUE, FALSE);
248     /* draw the new one */
249     if (!config_opaque_resize)
250         XDrawRectangle(ob_display, opaque_window.win, opaque_gc,
251                        moveresize_client->frame->area.x,
252                        moveresize_client->frame->area.y,
253                        moveresize_client->frame->area.width - 1,
254                        moveresize_client->frame->area.height - 1);
255     /* erase the old one */
256     if (!config_opaque_resize && !first_draw)
257         XDrawRectangle(ob_display, opaque_window.win, opaque_gc,
258                        oldx, oldy, oldw - 1, oldh - 1);
259     first_draw = FALSE;
260
261     /* this would be better with a fixed width font ... XXX can do it better
262        if there are 2 text boxes */
263     popup_coords("W:  %4d  H:  %4d", moveresize_client->logical_size.width,
264                  moveresize_client->logical_size.height);
265 }
266
267 void moveresize_event(XEvent *e)
268 {
269     g_assert(moveresize_in_progress);
270
271     if (e->type == ButtonPress) {
272         if (!button) {
273             start_x = e->xbutton.x_root;
274             start_y = e->xbutton.y_root;
275             button = e->xbutton.button; /* this will end it now */
276         }
277     } else if (e->type == ButtonRelease) {
278         if (!button || e->xbutton.button == button) {
279             moveresize_end(FALSE);
280         }
281     } else if (e->type == MotionNotify) {
282         if (moving) {
283             cur_x = start_cx + e->xmotion.x_root - start_x;
284             cur_y = start_cy + e->xmotion.y_root - start_y;
285             do_move();
286         } else {
287             if (corner == prop_atoms.net_wm_moveresize_size_topleft) {
288                 cur_x = start_cw - (e->xmotion.x_root - start_x);
289                 cur_y = start_ch - (e->xmotion.y_root - start_y);
290                 lockcorner = Corner_BottomRight;
291             } else if (corner == prop_atoms.net_wm_moveresize_size_top) {
292                 cur_x = start_cw;
293                 cur_y = start_ch - (e->xmotion.y_root - start_y);
294                 lockcorner = Corner_BottomRight;
295             } else if (corner == prop_atoms.net_wm_moveresize_size_topright) {
296                 cur_x = start_cw + (e->xmotion.x_root - start_x);
297                 cur_y = start_ch - (e->xmotion.y_root - start_y);
298                 lockcorner = Corner_BottomLeft;
299             } else if (corner == prop_atoms.net_wm_moveresize_size_right) { 
300                 cur_x = start_cw + (e->xmotion.x_root - start_x);
301                 cur_y = start_ch;
302                 lockcorner = Corner_BottomLeft;
303             } else if (corner ==
304                        prop_atoms.net_wm_moveresize_size_bottomright) {
305                 cur_x = start_cw + (e->xmotion.x_root - start_x);
306                 cur_y = start_ch + (e->xmotion.y_root - start_y);
307                 lockcorner = Corner_TopLeft;
308             } else if (corner == prop_atoms.net_wm_moveresize_size_bottom) {
309                 cur_x = start_cw;
310                 cur_y = start_ch + (e->xmotion.y_root - start_y);
311                 lockcorner = Corner_TopLeft;
312             } else if (corner ==
313                        prop_atoms.net_wm_moveresize_size_bottomleft) {
314                 cur_x = start_cw - (e->xmotion.x_root - start_x);
315                 cur_y = start_ch + (e->xmotion.y_root - start_y);
316                 lockcorner = Corner_TopRight;
317             } else if (corner == prop_atoms.net_wm_moveresize_size_left) {
318                 cur_x = start_cw - (e->xmotion.x_root - start_x);
319                 cur_y = start_ch;
320                 lockcorner = Corner_TopRight;
321             } else if (corner == prop_atoms.net_wm_moveresize_size_keyboard) {
322                 cur_x = start_cw + (e->xmotion.x_root - start_x);
323                 cur_y = start_ch + (e->xmotion.y_root - start_y);
324                 lockcorner = Corner_TopLeft;
325             } else
326                 g_assert_not_reached();
327
328             do_resize();
329         }
330     } else if (e->type == KeyPress) {
331         if (e->xkey.keycode == button_escape)
332             moveresize_end(TRUE);
333         else if (e->xkey.keycode == button_return)
334             moveresize_end(FALSE);
335         else {
336             if (corner == prop_atoms.net_wm_moveresize_size_keyboard) {
337                 if (e->xkey.keycode == button_right)
338                     cur_x += MAX(4, moveresize_client->size_inc.width);
339                 else if (e->xkey.keycode == button_left)
340                     cur_x -= MAX(4, moveresize_client->size_inc.width);
341                 else if (e->xkey.keycode == button_down)
342                     cur_y += MAX(4, moveresize_client->size_inc.height);
343                 else if (e->xkey.keycode == button_up)
344                     cur_y -= MAX(4, moveresize_client->size_inc.height);
345                 else
346                     return;
347                 do_resize();
348             } else if (corner == prop_atoms.net_wm_moveresize_move_keyboard) {
349                 if (e->xkey.keycode == button_right)
350                     cur_x += 4;
351                 else if (e->xkey.keycode == button_left)
352                     cur_x -= 4;
353                 else if (e->xkey.keycode == button_down)
354                     cur_y += 4;
355                 else if (e->xkey.keycode == button_up)
356                     cur_y -= 4;
357                 else
358                     return;
359                 do_move();
360             }
361         }
362     }
363 }