]> icculus.org git repositories - dana/openbox.git/blob - openbox/action.c
add the layer action
[dana/openbox.git] / openbox / action.c
1 /* -*- indent-tabs-mode: nil; tab-width: 4; c-basic-offset: 4; -*-
2
3    action.c for the Openbox window manager
4    Copyright (c) 2006        Mikael Magnusson
5    Copyright (c) 2003-2007   Dana Jansens
6
7    This program is free software; you can redistribute it and/or modify
8    it under the terms of the GNU General Public License as published by
9    the Free Software Foundation; either version 2 of the License, or
10    (at your option) any later version.
11
12    This program is distributed in the hope that it will be useful,
13    but WITHOUT ANY WARRANTY; without even the implied warranty of
14    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15    GNU General Public License for more details.
16
17    See the COPYING file for a copy of the GNU General Public License.
18 */
19
20 #include "debug.h"
21 #include "client.h"
22 #include "focus.h"
23 #include "focus_cycle.h"
24 #include "moveresize.h"
25 #include "menu.h"
26 #include "prop.h"
27 #include "stacking.h"
28 #include "screen.h"
29 #include "action.h"
30 #include "openbox.h"
31 #include "grab.h"
32 #include "keyboard.h"
33 #include "event.h"
34 #include "dock.h"
35 #include "config.h"
36 #include "mainloop.h"
37 #include "startupnotify.h"
38 #include "gettext.h"
39
40 #include <glib.h>
41
42
43
44
45 void setup_action_movefromedge_north(ObAction **a, ObUserAction uact)
46 {
47     (*a)->data.diraction.any.client_action = OB_CLIENT_ACTION_ALWAYS;
48     (*a)->data.diraction.direction = OB_DIRECTION_NORTH;
49     (*a)->data.diraction.hang = TRUE;
50 }
51
52 void setup_action_movefromedge_south(ObAction **a, ObUserAction uact)
53 {
54     (*a)->data.diraction.any.client_action = OB_CLIENT_ACTION_ALWAYS;
55     (*a)->data.diraction.direction = OB_DIRECTION_SOUTH;
56     (*a)->data.diraction.hang = TRUE;
57 }
58
59 void setup_action_movefromedge_east(ObAction **a, ObUserAction uact)
60 {
61     (*a)->data.diraction.any.client_action = OB_CLIENT_ACTION_ALWAYS;
62     (*a)->data.diraction.direction = OB_DIRECTION_EAST;
63     (*a)->data.diraction.hang = TRUE;
64 }
65
66 void setup_action_movefromedge_west(ObAction **a, ObUserAction uact)
67 {
68     (*a)->data.diraction.any.client_action = OB_CLIENT_ACTION_ALWAYS;
69     (*a)->data.diraction.direction = OB_DIRECTION_WEST;
70     (*a)->data.diraction.hang = TRUE;
71 }
72
73 void setup_action_movetoedge_north(ObAction **a, ObUserAction uact)
74 {
75     (*a)->data.diraction.any.client_action = OB_CLIENT_ACTION_ALWAYS;
76     (*a)->data.diraction.direction = OB_DIRECTION_NORTH;
77     (*a)->data.diraction.hang = FALSE;
78 }
79
80 void setup_action_movetoedge_south(ObAction **a, ObUserAction uact)
81 {
82     (*a)->data.diraction.any.client_action = OB_CLIENT_ACTION_ALWAYS;
83     (*a)->data.diraction.direction = OB_DIRECTION_SOUTH;
84     (*a)->data.diraction.hang = FALSE;
85 }
86
87 void setup_action_movetoedge_east(ObAction **a, ObUserAction uact)
88 {
89     (*a)->data.diraction.any.client_action = OB_CLIENT_ACTION_ALWAYS;
90     (*a)->data.diraction.direction = OB_DIRECTION_EAST;
91     (*a)->data.diraction.hang = FALSE;
92 }
93
94 void setup_action_movetoedge_west(ObAction **a, ObUserAction uact)
95 {
96     (*a)->data.diraction.any.client_action = OB_CLIENT_ACTION_ALWAYS;
97     (*a)->data.diraction.direction = OB_DIRECTION_WEST;
98     (*a)->data.diraction.hang = FALSE;
99 }
100
101 void setup_action_growtoedge_north(ObAction **a, ObUserAction uact)
102 {
103     (*a)->data.diraction.any.client_action = OB_CLIENT_ACTION_ALWAYS;
104     (*a)->data.diraction.direction = OB_DIRECTION_NORTH;
105 }
106
107 void setup_action_growtoedge_south(ObAction **a, ObUserAction uact)
108 {
109     (*a)->data.diraction.any.client_action = OB_CLIENT_ACTION_ALWAYS;
110     (*a)->data.diraction.direction = OB_DIRECTION_SOUTH;
111 }
112
113 void setup_action_growtoedge_east(ObAction **a, ObUserAction uact)
114 {
115     (*a)->data.diraction.any.client_action = OB_CLIENT_ACTION_ALWAYS;
116     (*a)->data.diraction.direction = OB_DIRECTION_EAST;
117 }
118
119 void setup_action_growtoedge_west(ObAction **a, ObUserAction uact)
120 {
121     (*a)->data.diraction.any.client_action = OB_CLIENT_ACTION_ALWAYS;
122     (*a)->data.diraction.direction = OB_DIRECTION_WEST;
123 }
124
125 void setup_action_top_layer(ObAction **a, ObUserAction uact)
126 {
127     (*a)->data.layer.any.client_action = OB_CLIENT_ACTION_ALWAYS;
128     (*a)->data.layer.layer = 1;
129 }
130
131 void setup_action_normal_layer(ObAction **a, ObUserAction uact)
132 {
133     (*a)->data.layer.any.client_action = OB_CLIENT_ACTION_ALWAYS;
134     (*a)->data.layer.layer = 0;
135 }
136
137 void setup_action_bottom_layer(ObAction **a, ObUserAction uact)
138 {
139     (*a)->data.layer.any.client_action = OB_CLIENT_ACTION_ALWAYS;
140     (*a)->data.layer.layer = -1;
141 }
142
143 void setup_client_action(ObAction **a, ObUserAction uact)
144 {
145     (*a)->data.any.client_action = OB_CLIENT_ACTION_ALWAYS;
146 }
147
148 ActionString actionstrings[] =
149 {
150     {
151         "shadelower",
152         action_shadelower,
153         setup_client_action
154     },
155     {
156         "unshaderaise",
157         action_unshaderaise,
158         setup_client_action
159     },
160     {
161         "sendtotoplayer",
162         action_send_to_layer,
163         setup_action_top_layer
164     },
165     {
166         "togglealwaysontop",
167         action_toggle_layer,
168         setup_action_top_layer
169     },
170     {
171         "sendtonormallayer",
172         action_send_to_layer,
173         setup_action_normal_layer
174     },
175     {
176         "sendtobottomlayer",
177         action_send_to_layer,
178         setup_action_bottom_layer
179     },
180     {
181         "togglealwaysonbottom",
182         action_toggle_layer,
183         setup_action_bottom_layer
184     },
185     {
186         "movefromedgenorth",
187         action_movetoedge,
188         setup_action_movefromedge_north
189     },
190     {
191         "movefromedgesouth",
192         action_movetoedge,
193         setup_action_movefromedge_south
194     },
195     {
196         "movefromedgewest",
197         action_movetoedge,
198         setup_action_movefromedge_west
199     },
200     {
201         "movefromedgeeast",
202         action_movetoedge,
203         setup_action_movefromedge_east
204     },
205     {
206         "movetoedgenorth",
207         action_movetoedge,
208         setup_action_movetoedge_north
209     },
210     {
211         "movetoedgesouth",
212         action_movetoedge,
213         setup_action_movetoedge_south
214     },
215     {
216         "movetoedgewest",
217         action_movetoedge,
218         setup_action_movetoedge_west
219     },
220     {
221         "movetoedgeeast",
222         action_movetoedge,
223         setup_action_movetoedge_east
224     },
225     {
226         "growtoedgenorth",
227         action_growtoedge,
228         setup_action_growtoedge_north
229     },
230     {
231         "growtoedgesouth",
232         action_growtoedge,
233         setup_action_growtoedge_south
234     },
235     {
236         "growtoedgewest",
237         action_growtoedge,
238         setup_action_growtoedge_west
239     },
240     {
241         "growtoedgeeast",
242         action_growtoedge,
243         setup_action_growtoedge_east
244     },
245     {
246         NULL,
247         NULL,
248         NULL
249     }
250 };
251
252 void action_unshaderaise(union ActionData *data)
253 {
254     if (data->client.any.c->shaded)
255         action_unshade(data);
256     else
257         action_raise(data);
258 }
259
260 void action_shadelower(union ActionData *data)
261 {
262     if (data->client.any.c->shaded)
263         action_lower(data);
264     else
265         action_shade(data);
266 }
267
268 void action_movetoedge(union ActionData *data)
269 {
270     gint x, y;
271     ObClient *c = data->diraction.any.c;
272
273     x = c->frame->area.x;
274     y = c->frame->area.y;
275     
276     switch(data->diraction.direction) {
277     case OB_DIRECTION_NORTH:
278         y = client_directional_edge_search(c, OB_DIRECTION_NORTH,
279                                            data->diraction.hang)
280             - (data->diraction.hang ? c->frame->area.height : 0);
281         break;
282     case OB_DIRECTION_WEST:
283         x = client_directional_edge_search(c, OB_DIRECTION_WEST,
284                                            data->diraction.hang)
285             - (data->diraction.hang ? c->frame->area.width : 0);
286         break;
287     case OB_DIRECTION_SOUTH:
288         y = client_directional_edge_search(c, OB_DIRECTION_SOUTH,
289                                            data->diraction.hang)
290             - (data->diraction.hang ? 0 : c->frame->area.height);
291         break;
292     case OB_DIRECTION_EAST:
293         x = client_directional_edge_search(c, OB_DIRECTION_EAST,
294                                            data->diraction.hang)
295             - (data->diraction.hang ? 0 : c->frame->area.width);
296         break;
297     default:
298         g_assert_not_reached();
299     }
300     frame_frame_gravity(c->frame, &x, &y, c->area.width, c->area.height);
301     client_action_start(data);
302     client_move(c, x, y);
303     client_action_end(data, FALSE);
304 }
305
306 void action_growtoedge(union ActionData *data)
307 {
308     gint x, y, width, height, dest;
309     ObClient *c = data->diraction.any.c;
310     Rect *a;
311
312     a = screen_area(c->desktop, SCREEN_AREA_ALL_MONITORS, &c->frame->area);
313     x = c->frame->area.x;
314     y = c->frame->area.y;
315     /* get the unshaded frame's dimensions..if it is shaded */
316     width = c->area.width + c->frame->size.left + c->frame->size.right;
317     height = c->area.height + c->frame->size.top + c->frame->size.bottom;
318
319     switch(data->diraction.direction) {
320     case OB_DIRECTION_NORTH:
321         if (c->shaded) break; /* don't allow vertical resize if shaded */
322
323         dest = client_directional_edge_search(c, OB_DIRECTION_NORTH, FALSE);
324         if (a->y == y)
325             height = height / 2;
326         else {
327             height = c->frame->area.y + height - dest;
328             y = dest;
329         }
330         break;
331     case OB_DIRECTION_WEST:
332         dest = client_directional_edge_search(c, OB_DIRECTION_WEST, FALSE);
333         if (a->x == x)
334             width = width / 2;
335         else {
336             width = c->frame->area.x + width - dest;
337             x = dest;
338         }
339         break;
340     case OB_DIRECTION_SOUTH:
341         if (c->shaded) break; /* don't allow vertical resize if shaded */
342
343         dest = client_directional_edge_search(c, OB_DIRECTION_SOUTH, FALSE);
344         if (a->y + a->height == y + c->frame->area.height) {
345             height = c->frame->area.height / 2;
346             y = a->y + a->height - height;
347         } else
348             height = dest - c->frame->area.y;
349         y += (height - c->frame->area.height) % c->size_inc.height;
350         height -= (height - c->frame->area.height) % c->size_inc.height;
351         break;
352     case OB_DIRECTION_EAST:
353         dest = client_directional_edge_search(c, OB_DIRECTION_EAST, FALSE);
354         if (a->x + a->width == x + c->frame->area.width) {
355             width = c->frame->area.width / 2;
356             x = a->x + a->width - width;
357         } else
358             width = dest - c->frame->area.x;
359         x += (width - c->frame->area.width) % c->size_inc.width;
360         width -= (width - c->frame->area.width) % c->size_inc.width;
361         break;
362     default:
363         g_assert_not_reached();
364     }
365     width -= c->frame->size.left + c->frame->size.right;
366     height -= c->frame->size.top + c->frame->size.bottom;
367     frame_frame_gravity(c->frame, &x, &y, width, height);
368     client_action_start(data);
369     client_move_resize(c, x, y, width, height);
370     client_action_end(data, FALSE);
371     g_free(a);
372 }
373
374 void action_send_to_layer(union ActionData *data)
375 {
376     client_set_layer(data->layer.any.c, data->layer.layer);
377 }
378
379 void action_toggle_layer(union ActionData *data)
380 {
381     ObClient *c = data->layer.any.c;
382
383     client_action_start(data);
384     client_action_end(data, config_focus_under_mouse);
385 }
386