diff options
author | Gary Wong <gtw@gnu.org> | 2009-08-31 15:26:01 -0600 |
---|---|---|
committer | Gary Wong <gtw@gnu.org> | 2009-08-31 15:26:01 -0600 |
commit | 69b03632ad36228490e30e79852f8b922fb22c74 (patch) | |
tree | af4e2529c470e812db3a0f3be86a0a8703fb9a1e | |
parent | 49b9141e117ff21451619399cee6b18d653c619c (diff) |
Make frame decorations optional (selected by _MOTIF_WM_HINTS property).
-rw-r--r-- | ChangeLog | 18 | ||||
-rw-r--r-- | actions.c | 1 | ||||
-rw-r--r-- | decorate-core.c | 1 | ||||
-rw-r--r-- | decorate-render.c | 1 | ||||
-rw-r--r-- | frame.c | 78 | ||||
-rw-r--r-- | frame.h | 5 | ||||
-rw-r--r-- | gwm.c | 47 | ||||
-rw-r--r-- | gwm.h | 14 | ||||
-rw-r--r-- | managed.c | 142 | ||||
-rw-r--r-- | managed.h | 2 | ||||
-rw-r--r-- | root.c | 1 |
11 files changed, 252 insertions, 58 deletions
@@ -1,5 +1,19 @@ 2009-08-31 Gary Wong <gtw@gnu.org> + * frame.c (frame_t, frame_xb): Make window decorations optional. + (frame_blr): New function. + (frame_b, frame_l, frame_r): Invoke frame_blr(). + (deactivate_focus_frame): Moved from gwm.c. + (frame_button_press, frame_enter_notify): Make window decorations + optional. + * gwm.c (start_managing_window): Likewise. + (setup_display): Add _MOTIF_WM_HINTS property. + * managed.c (managed_property_change): Handle _MOTIF_WM_HINTS property. + (match_managed_shape): Retrieve _MOTIF_WM_HINTS when a client + window is no longer bounding shaped. + +2009-08-31 Gary Wong <gtw@gnu.org> + * button.c (button_size, button_xb): New functions. All references to former constants updated. * frame.c (frame_t, frame_b, frame_l, frame_r, frame_xb): New @@ -36,7 +50,7 @@ (managed_property_notify): Use async_get_property. * gwm.c (start_managing_window): Initialise net_wm_name. (setup_display): Add _NET_WM_NAME property. - + 2009-08-28 Gary Wong <gtw@gnu.org> * frame.c (recalc_size): Initialise feedback->u.feedback. @@ -57,7 +71,7 @@ to (FcChar8 *). 2009-08-28 Gary Wong <gtw@gnu.org> - + * gwm.c (shutdown_display): Reparent the windows in strict stacking order. @@ -33,6 +33,7 @@ #include "gwm.h" #include "actions.h" +#include "frame.h" #include "window-table.h" static void external_command( char *name, ... ) { diff --git a/decorate-core.c b/decorate-core.c index c3c3b73..52f5837 100644 --- a/decorate-core.c +++ b/decorate-core.c @@ -33,6 +33,7 @@ #include "button.h" #include "decorate-core.h" +#include "frame.h" #define FONT_SIZE 12 #define STRING2(x) #x diff --git a/decorate-render.c b/decorate-render.c index b30f25a..b844973 100644 --- a/decorate-render.c +++ b/decorate-render.c @@ -38,6 +38,7 @@ #include "button.h" #include "decorate-render.h" +#include "frame.h" enum style_id { STYLE_TITLE, STYLE_MENU, NUM_STYLES @@ -43,37 +43,57 @@ extern int frame_t( struct gwm_window *window, int include_x_border ) { + int base, border; + assert( window->type == WINDOW_FRAME ); + + if( window->u.frame.decoration & DEC_BORDER ) { + base = FRAME_BORDER_WIDTH; + border = FRAME_X_BORDER; + } else + base = border = 0; + + if( window->u.frame.decoration & DEC_TITLE ) + base = FRAME_TITLE_HEIGHT; - return FRAME_TITLE_HEIGHT + ( include_x_border ? FRAME_X_BORDER : 0 ); + return base + ( include_x_border ? border : 0 ); } -extern int frame_b( struct gwm_window *window, int include_x_border ) { +static int frame_blr( struct gwm_window *window, int include_x_border ) { - assert( window->type == WINDOW_FRAME ); + int base, border; - return FRAME_BORDER_WIDTH + ( include_x_border ? FRAME_X_BORDER : 0 ); + assert( window->type == WINDOW_FRAME ); + + if( window->u.frame.decoration & DEC_BORDER ) { + base = FRAME_BORDER_WIDTH; + border = FRAME_X_BORDER; + } else + base = border = 0; + + return base + ( include_x_border ? border : 0 ); +} + +extern int frame_b( struct gwm_window *window, int include_x_border ) { + + return frame_blr( window, include_x_border ); } extern int frame_l( struct gwm_window *window, int include_x_border ) { - assert( window->type == WINDOW_FRAME ); - - return FRAME_BORDER_WIDTH + ( include_x_border ? FRAME_X_BORDER : 0 ); + return frame_blr( window, include_x_border ); } extern int frame_r( struct gwm_window *window, int include_x_border ) { - assert( window->type == WINDOW_FRAME ); - - return FRAME_BORDER_WIDTH + ( include_x_border ? FRAME_X_BORDER : 0 ); + return frame_blr( window, include_x_border ); } extern int frame_xb( struct gwm_window *window ) { assert( window->type == WINDOW_FRAME ); - return FRAME_X_BORDER; + return window->u.frame.decoration & DEC_BORDER ? FRAME_X_BORDER : 0; } extern void translate_child_to_frame( struct gwm_window *frame, @@ -292,6 +312,26 @@ extern void apply_size_constraints( struct gwm_window *window, int *width, } } +struct gwm_window *focus_frame; + +extern void deactivate_focus_frame( void ) { + + uint32_t n; + + if( !focus_frame ) + return; + + if( focus_frame->u.frame.decoration & ( DEC_TITLE | DEC_BORDER ) ) { + n = gwm_screens[ focus_frame->screen ].pixels[ COL_FRAME_INACTIVE ]; + xcb_change_window_attributes( c, focus_frame->w, XCB_CW_BACK_PIXEL, + &n ); + } + + if( focus_frame->u.frame.decoration & DEC_TITLE ) + queue_window_update( focus_frame, 0, 0, focus_frame->u.frame.width, + focus_frame->u.frame.height, FALSE ); +} + static enum _window_operation { OP_NONE, OP_MOVE, OP_RESIZE } window_op; @@ -695,7 +735,8 @@ static void frame_button_press( struct gwm_window *window, return; window_op = ( ev->detail > 1 ) == - ( ev->event_y < frame_t( window, FALSE ) ) ? OP_RESIZE : OP_MOVE; + ( ( window->u.frame.decoration & DEC_TITLE ) && + ev->event_y < frame_t( window, FALSE ) ) ? OP_RESIZE : OP_MOVE; init_x = ev->root_x; init_y = ev->root_y; @@ -827,11 +868,14 @@ static void frame_enter_notify( struct gwm_window *window, focus_frame = window; - n = gwm_screens[ window->screen ].pixels[ COL_FRAME_ACTIVE ]; - xcb_change_window_attributes( c, window->w, XCB_CW_BACK_PIXEL, &n ); - - queue_window_update( window, 0, 0, window->u.frame.width, - window->u.frame.height, FALSE ); + if( window->u.frame.decoration & ( DEC_TITLE | DEC_BORDER ) ) { + n = gwm_screens[ window->screen ].pixels[ COL_FRAME_ACTIVE ]; + xcb_change_window_attributes( c, window->w, XCB_CW_BACK_PIXEL, &n ); + } + + if( window->u.frame.decoration & DEC_TITLE ) + queue_window_update( window, 0, 0, window->u.frame.width, + window->u.frame.height, FALSE ); /* FIXME Defer all this focus stuff in case of multiple enter/leave notifies. */ @@ -1,6 +1,9 @@ #ifndef FRAME_H #define FRAME_H +extern struct gwm_window *focus_frame; /* the WINDOW_FRAME which has the + focus, if any */ + extern int frame_t( struct gwm_window *window, int include_x_border ); extern int frame_b( struct gwm_window *window, int include_x_border ); extern int frame_l( struct gwm_window *window, int include_x_border ); @@ -20,6 +23,8 @@ extern void translate_frame_to_child( struct gwm_window *frame, extern void apply_size_constraints( struct gwm_window *window, int *width, int *height ); +extern void deactivate_focus_frame( void ); + extern void synthetic_configure_notify( struct gwm_window *window ); extern event_handler frame_handlers[], childless_handlers[]; @@ -89,6 +89,7 @@ xcb_atom_t atoms[ NUM_ATOMS ]; static const char *atom_names[ NUM_ATOMS ] = { "COMPOUND_TEXT", "MANAGER", + "_MOTIF_WM_HINTS", "_NET_WM_NAME", "UTF8_STRING", "VERSION", @@ -137,7 +138,7 @@ xcb_render_directformat_t dfmt_rgba8, dfmt_a8; xcb_cursor_t cursors[ NUM_CURSORS ]; -struct gwm_window *fake_window, *focus_frame; +struct gwm_window *fake_window; const char *argv0; static int flag_replace, flag_force; @@ -1063,14 +1064,19 @@ static void start_managing_window( struct gwm_window *window, window->u.managed.name = NULL; window->u.managed.net_wm_name = 0; window->u.managed.state = STATE_WITHDRAWN; +#if USE_SHAPE + window->u.managed.shaped = have_extension[ EXT_SHAPE ] && shape && + shape->bounding_shaped; +#endif frame->screen = window->screen; frame->type = WINDOW_FRAME; frame->u.frame.child = window; frame->u.frame.button = button; + frame->u.frame.decoration = DEC_DEFAULT; button->screen = window->screen; button->type = WINDOW_BUTTON; button->u.button.frame = frame; - + for( i = 0; i < NUM_PROPS; i++ ) managed_property_change( window, i, props[ i ] ); @@ -1121,8 +1127,9 @@ static void start_managing_window( struct gwm_window *window, xcb_create_window( c, XCB_COPY_FROM_PARENT, frame->w, geom->root, frame->u.frame.x, frame->u.frame.y, - frame->u.frame.width, frame->u.frame.height, 1, - XCB_WINDOW_CLASS_INPUT_OUTPUT, XCB_COPY_FROM_PARENT, + frame->u.frame.width, frame->u.frame.height, + frame_xb( frame ), XCB_WINDOW_CLASS_INPUT_OUTPUT, + XCB_COPY_FROM_PARENT, XCB_CW_BACK_PIXEL | XCB_CW_BORDER_PIXEL | XCB_CW_BIT_GRAVITY | XCB_CW_OVERRIDE_REDIRECT | XCB_CW_EVENT_MASK, values ); @@ -1145,8 +1152,9 @@ static void start_managing_window( struct gwm_window *window, XCB_EVENT_MASK_ENTER_WINDOW | XCB_EVENT_MASK_LEAVE_WINDOW, XCB_GRAB_MODE_ASYNC, XCB_GRAB_MODE_ASYNC, XCB_NONE, XCB_NONE, XCB_BUTTON_INDEX_ANY, 0x8000 ); - - xcb_map_window( c, button->w ); + + if( frame->u.frame.decoration & DEC_TITLE ) + xcb_map_window( c, button->w ); xcb_change_save_set( c, XCB_SET_MODE_INSERT, w ); @@ -1163,6 +1171,7 @@ static void start_managing_window( struct gwm_window *window, xcb_reparent_window( c, w, frame->w, frame_l( frame, FALSE ), frame_t( frame, FALSE ) ); + if( !map_request ) { values[ 0 ] = XCB_EVENT_MASK_STRUCTURE_NOTIFY | XCB_EVENT_MASK_PROPERTY_CHANGE | @@ -1178,8 +1187,8 @@ static void start_managing_window( struct gwm_window *window, } #if USE_SHAPE - if( have_extension[ EXT_SHAPE ] && shape && shape->bounding_shaped ) - match_managed_shape( window, TRUE ); + if( window->u.managed.shaped ) + match_managed_shape( window ); #endif /* Tell the client we've relocated their window with respect to the @@ -1415,20 +1424,6 @@ extern void iconic_to_normal( struct gwm_window *window ) { xcb_map_window( c, window->u.managed.frame->w ); } -extern void deactivate_focus_frame( void ) { - - uint32_t n; - - if( !focus_frame ) - return; - - n = gwm_screens[ focus_frame->screen ].pixels[ COL_FRAME_INACTIVE ]; - xcb_change_window_attributes( c, focus_frame->w, XCB_CW_BACK_PIXEL, &n ); - - queue_window_update( focus_frame, 0, 0, focus_frame->u.frame.width, - focus_frame->u.frame.height, FALSE ); -} - extern void generic_expose( struct gwm_window *window, xcb_expose_event_t *ev ) { @@ -1683,11 +1678,8 @@ static void setup_display( void ) { free( r ); } - /* FIXME Also monitor EWMH client window properties: - _MOTIF_WM_HINTS, to see what decoration clients want - _NET_WM_NAME, UTF-8 in preference to WM_NAME - _NET_WM_ICON, ARGB icon(s) - and set _NET_FRAME_EXTENTS. */ + /* FIXME Also monitor _NET_WM_ICON and set _NET_FRAME_EXTENTS. */ + prop_atoms[ PROP__MOTIF_WM_HINTS ] = atoms[ ATOM__MOTIF_WM_HINTS ]; prop_atoms[ PROP__NET_WM_NAME ] = atoms[ ATOM__NET_WM_NAME ]; prop_atoms[ PROP_WM_COLORMAP_WINDOWS ] = atoms[ ATOM_WM_COLORMAP_WINDOWS ]; prop_atoms[ PROP_WM_HINTS ] = WM_HINTS; @@ -1695,6 +1687,7 @@ static void setup_display( void ) { prop_atoms[ PROP_WM_NORMAL_HINTS ] = WM_NORMAL_HINTS; prop_atoms[ PROP_WM_PROTOCOLS ] = atoms[ ATOM_WM_PROTOCOLS ]; + prop_types[ PROP__MOTIF_WM_HINTS ] = atoms[ ATOM__MOTIF_WM_HINTS ]; prop_types[ PROP__NET_WM_NAME ] = atoms[ ATOM_UTF8_STRING ]; prop_types[ PROP_WM_COLORMAP_WINDOWS ] = WINDOW; prop_types[ PROP_WM_HINTS ] = WM_HINTS; @@ -65,6 +65,7 @@ enum x_atom { enum gwm_atom { ATOM_COMPOUND_TEXT, ATOM_MANAGER, + ATOM__MOTIF_WM_HINTS, ATOM__NET_WM_NAME, ATOM_UTF8_STRING, ATOM_VERSION, @@ -81,6 +82,7 @@ enum gwm_atom { extern xcb_atom_t atoms[ NUM_ATOMS ]; enum gwm_property_type { + PROP__MOTIF_WM_HINTS, PROP__NET_WM_NAME, PROP_WM_COLORMAP_WINDOWS, PROP_WM_HINTS, @@ -186,6 +188,10 @@ extern xcb_cursor_t cursors[ NUM_CURSORS ]; #define STATE_NORMAL 1 #define STATE_ICONIC 3 +#define DEC_BORDER 0x1 +#define DEC_TITLE 0x2 +#define DEC_DEFAULT ( DEC_BORDER | DEC_TITLE ) + struct gwm_window { xcb_window_t w; int screen; @@ -200,6 +206,9 @@ struct gwm_window { struct gwm_window *frame; uint16_t border_width; xcb_colormap_t cmap; +#if USE_SHAPE + int shaped; +#endif /* from WM_COLORMAP_WINDOWS: */ xcb_window_t cmap_window; /* from WM_HINTS: */ @@ -219,6 +228,7 @@ struct gwm_window { struct _gwm_frame { struct gwm_window *child, *button; int x, y, width, height; + int decoration; /* see DEC_* above */ } frame; struct _gwm_button { struct gwm_window *frame; @@ -237,8 +247,6 @@ struct gwm_window { extern struct gwm_window *fake_window; /* a window created solely to hold the WM_Sn selections */ -extern struct gwm_window *focus_frame; /* the WINDOW_FRAME which has the - focus, if any */ extern const char *argv0; @@ -305,8 +313,6 @@ extern void install_window_colormap( int screen, struct gwm_window *window, extern void generic_expose( struct gwm_window *window, xcb_expose_event_t *ev ); -extern void deactivate_focus_frame( void ); - extern void iconic_to_normal( struct gwm_window *window ); extern void manage_window( xcb_window_t w, int map_request ); @@ -117,6 +117,16 @@ static void async_get_property( struct gwm_window *window, handle_managed_get_property, cp ); } +#define MOTIF_WM_HINTS_DECORATIONS 0x2 + +#define MOTIF_WM_HINTS_FLAGS_OFF 0 +#define MOTIF_WM_HINTS_DECORATIONS_OFF 2 +#define MOTIF_WM_HINTS_MIN_SIZE 3 /* ignore hint properties smaller than this */ + +#define MOTIF_WM_HINTS_DEC_ALL 0x1 +#define MOTIF_WM_HINTS_DEC_BORDER 0x2 +#define MOTIF_WM_HINTS_DEC_TITLE 0x8 + #define WM_HINTS_INPUT 0x1 #define WM_HINTS_STATE 0x2 @@ -152,11 +162,120 @@ extern void managed_property_change( struct gwm_window *window, int prop, int i; struct xcb_screen_t *screen; int value_len; - + int old_decoration; + assert( window->type == WINDOW_MANAGED ); switch( prop ) { + case PROP__MOTIF_WM_HINTS: + /* _MOTIF_WM_HINTS property. */ + old_decoration = window->u.managed.frame->u.frame.decoration; + + window->u.managed.frame->u.frame.decoration = DEC_DEFAULT; + + if( p->format == 32 && p->value_len >= MOTIF_WM_HINTS_MIN_SIZE ) { + p32 = xcb_get_property_value( p ); + + if( p32[ MOTIF_WM_HINTS_FLAGS_OFF ] & + MOTIF_WM_HINTS_DECORATIONS ) { + if( p32[ MOTIF_WM_HINTS_DECORATIONS_OFF ] & + MOTIF_WM_HINTS_DEC_ALL ) { + window->u.managed.frame->u.frame.decoration = + DEC_BORDER | DEC_TITLE; + + if( p32[ MOTIF_WM_HINTS_DECORATIONS_OFF ] & + MOTIF_WM_HINTS_DEC_BORDER ) + window->u.managed.frame->u.frame.decoration &= + ~DEC_BORDER; + + if( p32[ MOTIF_WM_HINTS_DECORATIONS_OFF ] & + MOTIF_WM_HINTS_DEC_TITLE ) + window->u.managed.frame->u.frame.decoration &= + ~DEC_TITLE; + } else { + window->u.managed.frame->u.frame.decoration = 0; + + if( p32[ MOTIF_WM_HINTS_DECORATIONS_OFF ] & + MOTIF_WM_HINTS_DEC_BORDER ) + window->u.managed.frame->u.frame.decoration |= + DEC_BORDER; + + if( p32[ MOTIF_WM_HINTS_DECORATIONS_OFF ] & + MOTIF_WM_HINTS_DEC_TITLE ) + window->u.managed.frame->u.frame.decoration |= + DEC_TITLE; + } + } + } + +#if USE_SHAPE + if( window->u.managed.shaped ) + /* Never apply borders to shaped windows. */ + window->u.managed.frame->u.frame.decoration &= ~DEC_BORDER; +#endif + + if( window->u.managed.state == STATE_NORMAL && + window->u.managed.frame->u.frame.decoration != old_decoration ) { + int new_decoration = window->u.managed.frame->u.frame.decoration; + int x, y, width, height; + uint32_t n[ 5 ]; + + window->u.managed.frame->u.frame.decoration = old_decoration; + + translate_frame_to_child( window->u.managed.frame, &x, &y, + window->u.managed.frame->u.frame.x, + window->u.managed.frame->u.frame.y, + window->u.managed.border_width, + window->u.managed.win_gravity ); + + window->u.managed.frame->u.frame.decoration = new_decoration; + + translate_child_to_frame( window->u.managed.frame, &x, &y, + &width, &height, x, y, + window->u.managed.frame->u.frame.width - + frame_l( window->u.managed.frame, + FALSE ) - + frame_r( window->u.managed.frame, + FALSE ), + window->u.managed.frame->u.frame.height - + frame_t( window->u.managed.frame, + FALSE ) - + frame_b( window->u.managed.frame, + FALSE ), + window->u.managed.border_width, + window->u.managed.win_gravity ); + + if( new_decoration & DEC_TITLE ) + xcb_map_window( c, + window->u.managed.frame->u.frame.button->w ); + else + xcb_unmap_window( c, + window->u.managed.frame->u.frame.button->w ); + + n[ 0 ] = frame_l( window->u.managed.frame, FALSE ); + n[ 1 ] = frame_l( window->u.managed.frame, FALSE ); + xcb_configure_window( c, window->w, XCB_CONFIG_WINDOW_X | + XCB_CONFIG_WINDOW_Y, n ); + + n[ 0 ] = x; + n[ 1 ] = y; + n[ 2 ] = width; + n[ 3 ] = height; + n[ 4 ] = frame_xb( window->u.managed.frame ); + /* We'll also notify the client of any changes, in the + ConfigureNotify handler for the event we expect to receive in + response to this request. */ + xcb_configure_window( c, window->u.managed.frame->w, + XCB_CONFIG_WINDOW_X | XCB_CONFIG_WINDOW_Y | + XCB_CONFIG_WINDOW_WIDTH | + XCB_CONFIG_WINDOW_HEIGHT | + XCB_CONFIG_WINDOW_BORDER_WIDTH, n ); + } + + break; + case PROP__NET_WM_NAME: + /* _NET_WM_NAME property (see EMWH "Application Window Properties". */ if( window->u.managed.name ) free( window->u.managed.name ); @@ -167,7 +286,8 @@ extern void managed_property_change( struct gwm_window *window, int prop, window->u.managed.name[ p->value_len ] = 0; window->u.managed.net_wm_name = 1; - if( window->u.managed.state == STATE_NORMAL ) + if( window->u.managed.state == STATE_NORMAL && + ( window->u.managed.frame->u.frame.decoration & DEC_TITLE ) ) queue_window_update( window->u.managed.frame, 0, 0, window->u.managed.frame->u.frame.width, frame_t( window->u.managed.frame, FALSE ), @@ -243,7 +363,8 @@ extern void managed_property_change( struct gwm_window *window, int prop, else window->u.managed.name = NULL; - if( window->u.managed.state == STATE_NORMAL ) + if( window->u.managed.state == STATE_NORMAL && + ( window->u.managed.frame->u.frame.decoration & DEC_TITLE ) ) queue_window_update( window->u.managed.frame, 0, 0, window->u.managed.frame->u.frame.width, frame_t( window->u.managed.frame, FALSE ), @@ -474,9 +595,9 @@ static void managed_colormap_notify( struct gwm_window *window, } #if USE_SHAPE -extern void match_managed_shape( struct gwm_window *window, int shaped ) { +extern void match_managed_shape( struct gwm_window *window ) { - if( shaped ) { + if( window->u.managed.shaped ) { xcb_rectangle_t rect; rect.x = rect.y = 0; @@ -498,8 +619,15 @@ extern void match_managed_shape( struct gwm_window *window, int shaped ) { static void managed_shape_notify( struct gwm_window *window, xcb_shape_notify_event_t *ev ) { - if( ev->shape_kind == XCB_SHAPE_SK_BOUNDING ) - match_managed_shape( window, ev->shaped ); + if( ev->shape_kind == XCB_SHAPE_SK_BOUNDING ) { + if( window->u.managed.shaped != ev->shaped && + !( window->u.managed.shaped = ev->shaped ) ) + /* The client is no longer shaped. Retrieve its original + _MOTIF_WM_HINTS, since we might now want to apply a border. */ + async_get_property( window, PROP__MOTIF_WM_HINTS ); + + match_managed_shape( window ); + } } #endif @@ -2,7 +2,7 @@ #define MANAGED_H #if USE_SHAPE -extern void match_managed_shape( struct gwm_window *window, int shaped ); +extern void match_managed_shape( struct gwm_window *window ); #endif extern void managed_property_change( struct gwm_window *window, int prop, @@ -28,6 +28,7 @@ #include "gwm.h" #include "actions.h" +#include "frame.h" #include "keyboard.h" #include "managed.h" #include "root.h" |