From 38546109c98e98b933a6e3a8e29572e29e16c1b1 Mon Sep 17 00:00:00 2001 From: Gary Wong Date: Tue, 1 Sep 2009 22:17:03 -0600 Subject: Add a menu for selecting a window to map and raise. --- ChangeLog | 17 +++++++++++++ actions.c | 87 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++- actions.h | 12 +++++++++ gwm.c | 9 +++---- gwm.h | 3 ++- menu.c | 17 ++++++++----- root.c | 2 +- 7 files changed, 132 insertions(+), 15 deletions(-) diff --git a/ChangeLog b/ChangeLog index bee1e73..aa3ed1f 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,20 @@ +2009-09-01 Gary Wong + + * actions.c (action_map_raise, action_window_list_menu) + (action_exit, window_list_activate): New functions. + * gwm.c (main): Use which_signal -1 to indicate a graceful exit. + + * menu.c (menu_button_release, popup_menu): Remember the window + parameter by resource ID, instead of by pointer. That way, it is + simple to detect whether the window has been destroyed between + creation and activation of the menu. + + * menu.c (menu_enter_notify): Don't try to measure the active item + when nothing is active. + + * menu.c (destroy_menu): Don't free NULL labels. + (popup_menu): Don't strdup() NULL labels. + 2009-09-01 Gary Wong * actions.c (action_iconify_window, action_deiconify_window): New diff --git a/actions.c b/actions.c index f29403e..3e65c09 100644 --- a/actions.c +++ b/actions.c @@ -25,6 +25,7 @@ #include #include +#include #if HAVE_UNISTD_H #include #endif @@ -96,7 +97,9 @@ extern void action_root_menu( struct gwm_window *window, const struct menuitem root_menu[] = { { "Map all icons", action_map_all_icons }, { "Raise lowest window", action_raise_lowest }, - { "xterm", action_start_xterm } + { "xterm", action_start_xterm }, + { NULL }, + { "Exit", action_exit } }; popup_menu( window, ev, sizeof root_menu / sizeof *root_menu, root_menu ); @@ -126,6 +129,25 @@ extern void action_deiconify_window( struct gwm_window *window, iconic_to_normal( window ); } +extern void action_map_raise( struct gwm_window *window, + xcb_generic_event_t *ev, + union callback_param cp ) { + + if( window->type == WINDOW_FRAME ) + window = window->u.frame.child; + + if( window->type == WINDOW_MANAGED ) { + uint32_t n; + + n = XCB_STACK_MODE_ABOVE; + xcb_configure_window( c, window->u.managed.frame->w, + XCB_CONFIG_WINDOW_STACK_MODE, &n ); + + if( window->u.managed.state == STATE_ICONIC ) + iconic_to_normal( window ); + } +} + extern void action_map_all_icons( struct gwm_window *window, xcb_generic_event_t *ev, union callback_param cp ) { @@ -159,4 +181,67 @@ extern void action_window_menu( struct gwm_window *window, window_menu ); } +static void window_list_activate( struct gwm_window *window, + xcb_generic_event_t *ev, + union callback_param cp ) { + + struct gwm_window *window_param; + + if( ( window_param = lookup_window( cp.l ) ) ) { + union callback_param param; + + param.p = NULL; + action_map_raise( window_param, ev, param ); + } +} + +extern void action_window_list_menu( struct gwm_window *window, + xcb_generic_event_t *ev, + union callback_param cp ) { + + int i, num_items; + struct menuitem *items; + + for( i = 0, num_items = 0; i < windows.used; i++ ) + if( windows.values[ i ]->type == WINDOW_MANAGED ) + num_items++; + + items = alloca( num_items * sizeof *items ); + + for( i = 0, num_items = 0; i < windows.used; i++ ) + if( windows.values[ i ]->type == WINDOW_MANAGED ) { + struct gwm_window *managed = windows.values[ i ]; + char *name = managed->u.managed.name ? managed->u.managed.name : + "(Untitled)"; + + if( managed->u.managed.state == STATE_ICONIC ) { + int len = strlen( name ); + char *new = alloca( len + 3 ); + + new[ 0 ] = '['; + strcpy( new + 1, name ); + new[ len + 1 ] = ']'; + new[ len + 2 ] = 0; + + name = new; + } + + items[ num_items ].label = name; + items[ num_items ].action = window_list_activate; + items[ num_items ].cp.l = managed->w; + + num_items++; + } + + popup_menu( window, ev, num_items, items ); +} + +extern void action_exit( struct gwm_window *window, xcb_generic_event_t *ev, + union callback_param cp ) { + + /* FIXME prompt for confirmation of exit */ + + signal_caught = -1; +} + /* FIXME make the current frame bindings (move, resize, close?) actions too */ diff --git a/actions.h b/actions.h index 5abb2c4..7cf498e 100644 --- a/actions.h +++ b/actions.h @@ -21,6 +21,10 @@ extern void action_deiconify_window( struct gwm_window *window, xcb_generic_event_t *ev, union callback_param cp ); +extern void action_map_raise( struct gwm_window *window, + xcb_generic_event_t *ev, + union callback_param cp ); + extern void action_map_all_icons( struct gwm_window *window, xcb_generic_event_t *ev, union callback_param cp ); @@ -32,5 +36,13 @@ extern void action_start_xterm( struct gwm_window *window, extern void action_window_menu( struct gwm_window *window, xcb_generic_event_t *ev, union callback_param cp ); + +extern void action_window_list_menu( struct gwm_window *window, + xcb_generic_event_t *ev, + union callback_param cp ); + +extern void action_exit( struct gwm_window *window, xcb_generic_event_t *ev, + union callback_param cp ); + #endif diff --git a/gwm.c b/gwm.c index daa923f..c770d33 100644 --- a/gwm.c +++ b/gwm.c @@ -147,7 +147,7 @@ static int flag_replace, flag_force; static int flag_debug; #endif -static volatile int signal_caught; +volatile int signal_caught; static void ( *update_window )( struct gwm_window *window ); void ( *window_size )( struct gwm_window *window, int *width, int *height ); @@ -2353,9 +2353,8 @@ static void handle_events( void ) { /* FIXME other features: - make override-redirect windows translucent - - desktop menu & other key/pointer bindings - - when in the window menu, turn all windows translucent - except for the selected item (temporarily raise that one?) + - when in the window menu, turn all windows translucent + except for the selected item (temporarily raise that one?) - root background/cursor? (no; xsetroot for non composite case) - standard colourmaps? (no; xstdcmap does that) - DPMS @@ -2594,7 +2593,7 @@ extern int main( int argc, char *argv[] ) { shutdown_display(); - if( which_signal ) { + if( which_signal > 0 ) { raise( which_signal ); return 1; diff --git a/gwm.h b/gwm.h index d3c9337..94c1226 100644 --- a/gwm.h +++ b/gwm.h @@ -257,7 +257,7 @@ struct gwm_window { struct gwm_window *frame; } button; struct _gwm_menu { - struct gwm_window *window_param; + xcb_window_t window_param; int num_items, active_item; int width; struct gwm_window **items; /* must be free()d */ @@ -286,6 +286,7 @@ extern struct gwm_window *fake_window; /* a window created solely to hold the WM_Sn selections */ extern const char *argv0; +extern volatile int signal_caught; extern FORMAT( printf, 1, 2 ) void warning( char *format, ... ); extern FORMAT( printf, 1, 2 ) NORETURN void fatal( char *format, ... ); diff --git a/menu.c b/menu.c index 3497103..6b1e573 100644 --- a/menu.c +++ b/menu.c @@ -44,7 +44,8 @@ static void destroy_menu( struct gwm_window *menu ) { int i; for( i = 0; i < menu->u.menu.num_items; i++ ) { - free( menu->u.menu.items[ i ]->u.menuitem.label ); + if( menu->u.menu.items[ i ]->u.menuitem.label ) + free( menu->u.menu.items[ i ]->u.menuitem.label ); forget_window( menu->u.menu.items[ i ] ); } @@ -65,7 +66,7 @@ static void menu_button_release( struct gwm_window *window, if( final_release( ev ) ) { if( window->u.menu.active_item >= 0 ) { - window_param = window->u.menu.window_param; + window_param = lookup_window( window->u.menu.window_param ); action = window->u.menu.items[ window->u.menu.active_item ]-> u.menuitem.action; cp = window->u.menu.items[ window->u.menu.active_item ]-> @@ -75,7 +76,7 @@ static void menu_button_release( struct gwm_window *window, destroy_menu( window ); - if( action ) + if( action && window_param ) action( window_param, (xcb_generic_event_t *) ev, cp ); } } @@ -103,8 +104,9 @@ static void menu_enter_notify( struct gwm_window *window, if( child->u.menuitem.label ) window_size( child, &width, &height ); else { - window_size( window->u.menu.items[ window->u.menu.active_item ], - &width, &height ); + if( window->u.menu.active_item >= 0 ) + window_size( window->u.menu.items[ window->u.menu.active_item ], + &width, &height ); i = -1; } @@ -180,7 +182,7 @@ extern void popup_menu( struct gwm_window *window, xcb_generic_event_t *ev, menu = add_window( xcb_generate_id( c ) ); menu->screen = screen; menu->type = WINDOW_MENU; - menu->u.menu.window_param = window; + menu->u.menu.window_param = window->w; menu->u.menu.num_items = num_items; menu->u.menu.active_item = -1; menu->u.menu.items = xmalloc( num_items * sizeof *menu->u.menu.items ); @@ -194,7 +196,8 @@ extern void popup_menu( struct gwm_window *window, xcb_generic_event_t *ev, item->screen = screen; item->type = WINDOW_MENUITEM; item->u.menuitem.menu = menu; - item->u.menuitem.label = strdup( items[ i ].label ); + item->u.menuitem.label = items[ i ].label ? strdup( items[ i ].label ) : + NULL; item->u.menuitem.action = items[ i ].action; item->u.menuitem.cp = items[ i ].cp; window_size( item, widths + i, heights + i ); diff --git a/root.c b/root.c index cf00d8c..16b60b9 100644 --- a/root.c +++ b/root.c @@ -61,7 +61,7 @@ static const struct button_action { } button_actions[] = { /* FIXME This table should be configurable, of course. */ { 1, 0, action_root_menu }, - { 2, 0, action_map_all_icons }, + { 2, 0, action_window_list_menu }, { 3, 0, action_start_xterm } }; -- cgit v1.2.3