Don't attempt to load non-existent characters.
[gwm.git] / actions.c
blob84d1413b76679402200a3db9e029a1d00a40fc81
1 /*
2 * actions.c
4 * Part of gwm, the Gratuitous Window Manager,
5 * by Gary Wong, <gtw@gnu.org>.
7 * Copyright (C) 2009 Gary Wong
9 * This program is free software: you can redistribute it and/or modify
10 * it under the terms of version 3 of the GNU General Public License as
11 * published by the Free Software Foundation.
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
18 * You should have received a copy of the GNU General Public License
19 * along with this program. If not, see <http://www.gnu.org/licenses/>.
21 * $Id$
24 #include <config.h>
26 #include <stdarg.h>
27 #include <stdlib.h>
28 #include <string.h>
29 #if HAVE_UNISTD_H
30 #include <unistd.h>
31 #endif
32 #include <xcb/xcb.h>
34 #include "gwm.h"
36 #include "actions.h"
37 #include "frame.h"
38 #include "managed.h"
39 #include "menu.h"
40 #include "window-table.h"
42 static void external_command( char *name, ... ) {
44 if( !fork() ) {
45 va_list val;
46 int n;
47 char **args;
49 va_start( val, name );
50 for( n = 0; va_arg( val, char * ); n++ )
52 va_end( val );
54 args = alloca( ( n + 2 ) * sizeof *args );
56 args[ 0 ] = name;
58 va_start( val, name );
59 n = 1;
60 while( ( args[ n++ ] = va_arg( val, char * ) ) )
62 va_end( val );
64 setpgid( 0, 0 );
66 execvp( name, args );
68 _exit( 1 );
72 extern void action_raise_lowest( struct gwm_window *window,
73 xcb_generic_event_t *ev,
74 union callback_param cp ) {
76 xcb_circulate_window( c, XCB_CIRCULATE_RAISE_LOWEST,
77 screens[ window->screen ]->root );
80 extern void action_stack_opposite( struct gwm_window *window,
81 xcb_generic_event_t *ev,
82 union callback_param cp ) {
84 if( window->type == WINDOW_FRAME ) {
85 uint32_t n = XCB_STACK_MODE_OPPOSITE;
87 xcb_configure_window( c, window->w, XCB_CONFIG_WINDOW_STACK_MODE,
88 &n );
92 extern void action_root_menu( struct gwm_window *window,
93 xcb_generic_event_t *ev,
94 union callback_param cp ) {
96 /* FIXME this should be configurable, of course */
97 const struct menuitem root_menu[] = {
98 { "Map all icons", action_map_all_icons },
99 { "Raise lowest window", action_raise_lowest },
100 { "xterm", action_start_xterm },
101 { NULL },
102 { "Exit", action_exit }
105 popup_menu( window, ev, sizeof root_menu / sizeof *root_menu, root_menu );
108 extern void action_iconify_window( struct gwm_window *window,
109 xcb_generic_event_t *ev,
110 union callback_param cp ) {
112 if( window->type == WINDOW_FRAME )
113 window = window->u.frame.child;
115 if( window->type == WINDOW_MANAGED &&
116 window->u.managed.state == STATE_NORMAL )
117 normal_to_iconic( window );
120 extern void action_deiconify_window( struct gwm_window *window,
121 xcb_generic_event_t *ev,
122 union callback_param cp ) {
124 if( window->type == WINDOW_FRAME )
125 window = window->u.frame.child;
127 if( window->type == WINDOW_MANAGED &&
128 window->u.managed.state == STATE_ICONIC )
129 iconic_to_normal( window );
132 extern void action_map_raise( struct gwm_window *window,
133 xcb_generic_event_t *ev,
134 union callback_param cp ) {
136 if( window->type == WINDOW_FRAME )
137 window = window->u.frame.child;
139 if( window->type == WINDOW_MANAGED ) {
140 uint32_t n;
142 n = XCB_STACK_MODE_ABOVE;
143 xcb_configure_window( c, window->u.managed.frame->w,
144 XCB_CONFIG_WINDOW_STACK_MODE, &n );
146 if( window->u.managed.state == STATE_ICONIC )
147 iconic_to_normal( window );
151 extern void action_map_all_icons( struct gwm_window *window,
152 xcb_generic_event_t *ev,
153 union callback_param cp ) {
155 int i;
157 for( i = 0; i < windows.used; i++ )
158 if( windows.values[ i ]->type == WINDOW_MANAGED &&
159 windows.values[ i ]->u.managed.state == STATE_ICONIC )
160 iconic_to_normal( windows.values[ i ] );
163 extern void action_start_xterm( struct gwm_window *window,
164 xcb_generic_event_t *ev,
165 union callback_param cp ) {
167 external_command( "xterm", NULL );
170 extern void action_window_menu( struct gwm_window *window,
171 xcb_generic_event_t *ev,
172 union callback_param cp ) {
174 /* FIXME this should be configurable, of course */
175 const struct menuitem window_menu[] = {
176 { "Iconify", action_iconify_window },
177 { "Raise/lower", action_stack_opposite }
180 popup_menu( window, ev, sizeof window_menu / sizeof *window_menu,
181 window_menu );
184 static xcb_window_t place_holder;
185 static int window_was_iconic;
187 static void window_list_activate( struct gwm_window *window,
188 xcb_generic_event_t *ev,
189 union callback_param cp ) {
191 if( place_holder ) {
192 xcb_destroy_window( c, place_holder );
193 place_holder = XCB_NONE;
197 static void window_list_enter( struct gwm_window *window,
198 xcb_generic_event_t *ev,
199 union callback_param cp ) {
201 struct gwm_window *client;
203 if( ( client = lookup_window( cp.l ) ) ) {
204 uint32_t values[ 2 ];
206 /* Introduce another (unmapped and otherwise unused) window into the
207 stack to mark the original position of the client in the stacking
208 order. This might seem ugly, but an alternative scheme to
209 allow us to track the stacking order synchronously ourselves
210 would require another round trip to the server, which would be
211 worse. */
212 place_holder = xcb_generate_id( c );
213 xcb_create_window( c, 0, place_holder, screens[ client->screen ]->root,
214 0, 0, 1, 1, 0, XCB_WINDOW_CLASS_INPUT_ONLY,
215 screens[ client->screen ]->root_visual, 0, NULL );
216 values[ 0 ] = client->u.managed.frame->w;
217 values[ 1 ] = XCB_STACK_MODE_BELOW;
218 xcb_configure_window( c, place_holder, XCB_CONFIG_WINDOW_SIBLING |
219 XCB_CONFIG_WINDOW_STACK_MODE, values );
221 if( ( window_was_iconic = client->u.managed.state == STATE_ICONIC ) )
222 iconic_to_normal( client );
224 /* Raise the client window to immediately below the menu. */
225 values[ 0 ] = pointer_demux; /* the menu */
226 values[ 1 ] = XCB_STACK_MODE_BELOW;
227 xcb_configure_window( c, client->u.managed.frame->w,
228 XCB_CONFIG_WINDOW_SIBLING |
229 XCB_CONFIG_WINDOW_STACK_MODE, values );
231 if( focus_frame != client->u.managed.frame ) {
232 deactivate_focus_frame();
234 focus_frame = client->u.managed.frame;
236 activate_focus_frame( event_time( ev ) );
241 static void window_list_leave( struct gwm_window *window,
242 xcb_generic_event_t *ev,
243 union callback_param cp ) {
245 struct gwm_window *client;
247 if( ( client = lookup_window( cp.l ) ) ) {
248 uint32_t values[ 2 ];
250 values[ 0 ] = place_holder;
251 values[ 1 ] = XCB_STACK_MODE_ABOVE;
252 xcb_configure_window( c, client->u.managed.frame->w,
253 XCB_CONFIG_WINDOW_SIBLING |
254 XCB_CONFIG_WINDOW_STACK_MODE, values );
256 if( window_was_iconic )
257 normal_to_iconic( client );
260 if( place_holder ) {
261 xcb_destroy_window( c, place_holder );
262 place_holder = XCB_NONE;
266 extern void action_window_list_menu( struct gwm_window *window,
267 xcb_generic_event_t *ev,
268 union callback_param cp ) {
270 int i, num_items;
272 struct menuitem *items;
274 for( i = 0, num_items = 0; i < num_screens; i++ ) {
275 xcb_window_t w = screens[ i ]->root | STACK_END;
277 if( i )
278 num_items++;
280 do {
281 struct gwm_window *window = lookup_window( w );
282 xcb_window_t next =
283 stack_lookup( &window_stack, w )->lower_window;
285 if( window && window->type == WINDOW_FRAME )
286 num_items++;
288 w = next;
289 } while( w != ( screens[ i ]->root | STACK_END ) );
292 items = alloca( num_items * sizeof *items );
294 for( i = 0, num_items = 0; i < num_screens; i++ ) {
295 xcb_window_t w = screens[ i ]->root | STACK_END;
297 if( i ) {
298 items[ num_items ].label = NULL;
300 num_items++;
303 do {
304 struct gwm_window *window = lookup_window( w );
305 xcb_window_t next =
306 stack_lookup( &window_stack, w )->lower_window;
308 if( window && window->type == WINDOW_FRAME ) {
309 struct gwm_window *managed = window->u.frame.child;
310 char *name = managed->u.managed.name ?
311 managed->u.managed.name : "(Untitled)";
313 if( managed->u.managed.state == STATE_ICONIC ) {
314 int len = strlen( name );
315 char *new = alloca( len + 3 );
317 new[ 0 ] = '[';
318 strcpy( new + 1, name );
319 new[ len + 1 ] = ']';
320 new[ len + 2 ] = 0;
322 name = new;
325 items[ num_items ].label = name;
326 items[ num_items ].action = window_list_activate;
327 items[ num_items ].enter_action = window_list_enter;
328 items[ num_items ].leave_action = window_list_leave;
329 items[ num_items ].cp.l = managed->w;
330 items[ num_items ].icon = managed->w;
332 num_items++;
335 w = next;
336 } while( w != ( screens[ i ]->root | STACK_END ) );
339 popup_menu( window, ev, num_items, items );
342 extern void action_exit( struct gwm_window *window, xcb_generic_event_t *ev,
343 union callback_param cp ) {
345 /* FIXME prompt for confirmation of exit */
347 signal_caught = -1;
350 /* FIXME make the current frame bindings (move, resize, close?) actions too */