diff options
Diffstat (limited to 'frame.c')
-rw-r--r-- | frame.c | 334 |
1 files changed, 300 insertions, 34 deletions
@@ -35,6 +35,263 @@ #define EDGE_RESIST 8 +#define FRAME_X_BORDER 1 /* X border added to all four sides of frame */ +#define FRAME_BORDER_WIDTH 2 /* pixels added to left, right and bottom; + includes padding but excludes X border */ +#define FRAME_TITLE_HEIGHT 16 /* pixels added to top; includes title + bar but excludes X border */ + +extern int frame_t( struct gwm_window *window, int include_x_border ) { + + assert( window->type == WINDOW_FRAME ); + + return FRAME_TITLE_HEIGHT + ( include_x_border ? FRAME_X_BORDER : 0 ); +} + +extern int frame_b( struct gwm_window *window, int include_x_border ) { + + assert( window->type == WINDOW_FRAME ); + + return FRAME_BORDER_WIDTH + ( include_x_border ? FRAME_X_BORDER : 0 ); +} + +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 ); +} + +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 ); +} + +extern int frame_xb( struct gwm_window *window ) { + + assert( window->type == WINDOW_FRAME ); + + return FRAME_X_BORDER; +} + +extern void translate_child_to_frame( struct gwm_window *frame, + int *fx, int *fy, int *fwidth, + int *fheight, int cx, int cy, + int cwidth, int cheight, + int cborder, int win_gravity ) { + + *fwidth = cwidth + frame_l( frame, FALSE ) + frame_r( frame, FALSE ); + *fheight = cheight + frame_t( frame, FALSE ) + frame_b( frame, FALSE ); + + switch( win_gravity ) { + case XCB_GRAVITY_NORTH_WEST: + case XCB_GRAVITY_WEST: + case XCB_GRAVITY_SOUTH_WEST: + default: + *fx = cx; + break; + + case XCB_GRAVITY_NORTH: + case XCB_GRAVITY_CENTER: + case XCB_GRAVITY_SOUTH: + *fx = cx + cborder - ( ( frame_l( frame, TRUE ) + + frame_r( frame, TRUE ) ) >> 1 ); + break; + + case XCB_GRAVITY_NORTH_EAST: + case XCB_GRAVITY_EAST: + case XCB_GRAVITY_SOUTH_EAST: + *fx = cx + ( cborder << 1 ) - frame_l( frame, TRUE ) - + frame_r( frame, TRUE ); + break; + + case XCB_GRAVITY_STATIC: + *fx = cx + cborder - frame_l( frame, TRUE ); + } + + switch( win_gravity ) { + case XCB_GRAVITY_NORTH_WEST: + case XCB_GRAVITY_NORTH: + case XCB_GRAVITY_NORTH_EAST: + default: + *fy = cy; + break; + + case XCB_GRAVITY_WEST: + case XCB_GRAVITY_CENTER: + case XCB_GRAVITY_EAST: + *fy = cy + cborder - ( ( frame_t( frame, TRUE ) + + frame_b( frame, TRUE ) ) >> 1 ); + break; + + case XCB_GRAVITY_SOUTH_WEST: + case XCB_GRAVITY_SOUTH: + case XCB_GRAVITY_SOUTH_EAST: + *fy = cy + ( cborder << 1 ) - frame_t( frame, TRUE ) - + frame_b( frame, TRUE ); + break; + + case XCB_GRAVITY_STATIC: + *fy = cy + cborder - frame_t( frame, TRUE ); + break; + } +} + +extern void translate_frame_to_child( struct gwm_window *frame, + int *cx, int *cy, int fx, int fy, + int cborder, int win_gravity ) { + + switch( win_gravity ) { + case XCB_GRAVITY_NORTH_WEST: + case XCB_GRAVITY_WEST: + case XCB_GRAVITY_SOUTH_WEST: + default: + *cx = fx; + break; + + case XCB_GRAVITY_NORTH: + case XCB_GRAVITY_CENTER: + case XCB_GRAVITY_SOUTH: + *cx = fx - cborder + ( ( frame_l( frame, TRUE ) + + frame_r( frame, TRUE ) ) >> 1 ); + break; + + case XCB_GRAVITY_NORTH_EAST: + case XCB_GRAVITY_EAST: + case XCB_GRAVITY_SOUTH_EAST: + *cx = fx - ( cborder << 1 ) + frame_l( frame, TRUE ) + + frame_r( frame, TRUE ); + break; + + case XCB_GRAVITY_STATIC: + *cx = fx - cborder + frame_l( frame, TRUE ); + break; + } + + switch( win_gravity ) { + case XCB_GRAVITY_NORTH_WEST: + case XCB_GRAVITY_NORTH: + case XCB_GRAVITY_NORTH_EAST: + default: + *cy = fy; + break; + + case XCB_GRAVITY_WEST: + case XCB_GRAVITY_CENTER: + case XCB_GRAVITY_EAST: + *cy = fy - cborder + ( ( frame_t( frame, TRUE ) + + frame_b( frame, TRUE ) ) >> 1 ); + break; + + case XCB_GRAVITY_SOUTH_WEST: + case XCB_GRAVITY_SOUTH: + case XCB_GRAVITY_SOUTH_EAST: + *cy = fy - ( cborder << 1 ) + frame_t( frame, TRUE ) + + frame_b( frame, TRUE ); + break; + + case XCB_GRAVITY_STATIC: + *cy = fy - cborder + frame_t( frame, TRUE ); + break; + } +} + +extern void apply_size_constraints( struct gwm_window *window, int *width, + int *height ) { + + int eff_base_width = window->u.managed.base_width ? + window->u.managed.base_width : window->u.managed.min_width, + eff_base_height = window->u.managed.base_height ? + window->u.managed.base_height : window->u.managed.min_height; + + /* Apply the minimum and maximum constraints. These are already known + to be compatible. */ + if( *width < window->u.managed.min_width ) + *width = window->u.managed.min_width; + + if( *height < window->u.managed.min_height ) + *height = window->u.managed.min_height; + + if( *width > window->u.managed.max_width ) + *width = window->u.managed.max_width; + + if( *height > window->u.managed.max_height ) + *height = window->u.managed.max_height; + + /* Now round down each dimension to an integer multiple of increments. + Rounding down cannot violate the maximum constraint, and since + eff_base_* >= min_*, it will not reduce below the minimum constraint. */ + *width -= ( *width - eff_base_width ) % window->u.managed.width_inc; + *height -= ( *height - eff_base_height ) % window->u.managed.height_inc; + + if( window->u.managed.min_aspect_x * *height > + window->u.managed.min_aspect_y * *width ) { + /* Minimum aspect ratio violated. Attempt to either increase the + width or decrease the height (whichever is a smaller change), but + don't do either if it would go outside the min/max bounds. + Both division operations are safe (min_aspect_y is always + positive, and min_aspect_x must be positive if there is a + violation). Note that an exact solution might not be possible + (e.g. certain cases where the aspect ratio and increments are + coprime). */ + int min_x, max_y; + + min_x = ( window->u.managed.min_aspect_x * *height + + ( window->u.managed.min_aspect_y - 1 ) ) / + window->u.managed.min_aspect_y + window->u.managed.width_inc - 1; + min_x -= ( min_x - eff_base_width ) % window->u.managed.width_inc; + + max_y = window->u.managed.min_aspect_y * *width / + window->u.managed.min_aspect_x; + max_y -= ( max_y - eff_base_height ) % window->u.managed.height_inc; + + if( min_x - *width < *height - max_y ) { + /* The width change is smaller: prefer it if possible. */ + if( min_x >= window->u.managed.min_width ) + *width = min_x; + else if( max_y < window->u.managed.max_height ) + *height = max_y; + } else { + /* The height change is smaller: prefer it if possible. */ + if( max_y < window->u.managed.max_height ) + *height = max_y; + else if( min_x >= window->u.managed.min_width ) + *width = min_x; + } + } + + if( window->u.managed.max_aspect_x * *height < + window->u.managed.max_aspect_y * *width ) { + /* Maximum aspect ratio violated. Much like the case above... */ + int min_y, max_x; + + min_y = ( window->u.managed.max_aspect_y * *width + + ( window->u.managed.max_aspect_x - 1 ) ) / + window->u.managed.max_aspect_x + window->u.managed.height_inc - 1; + min_y -= ( min_y - eff_base_height ) % window->u.managed.height_inc; + + max_x = window->u.managed.max_aspect_x * *height / + window->u.managed.max_aspect_y; + max_x -= ( max_x - eff_base_width ) % window->u.managed.width_inc; + + if( min_y - *height < *width - max_x ) { + /* The height change is smaller: prefer it if possible. */ + if( min_y >= window->u.managed.min_height ) + *height = min_y; + else if( max_x < window->u.managed.max_width ) + *width = max_x; + } else { + /* The width change is smaller: prefer it if possible. */ + if( max_x < window->u.managed.max_width ) + *width = max_x; + else if( min_y >= window->u.managed.min_height ) + *height = min_y; + } + } +} + static enum _window_operation { OP_NONE, OP_MOVE, OP_RESIZE } window_op; @@ -104,10 +361,10 @@ static void build_edges( int screen ) { window->screen == screen ) { int t = window->u.frame.y, b = window->u.frame.y + window->u.frame.height + - ( FRAME_X_BORDER << 1 ), + ( frame_xb( window ) << 1 ), l = window->u.frame.x, r = window->u.frame.x + window->u.frame.width + - ( FRAME_X_BORDER << 1 ); + ( frame_xb( window ) << 1 ); if( t >= screens[ screen ]->height_in_pixels || b <= 0 || l >= screens[ screen ]->width_in_pixels || r <= 0 ) @@ -266,9 +523,9 @@ static void recalc_size( struct gwm_window *window, int x, int y, int old_t, old_b, old_l, old_r, new_t, new_b, new_l, new_r; old_t = window->u.frame.y; - old_b = old_t + window->u.frame.height + ( FRAME_X_BORDER << 1 ); + old_b = old_t + window->u.frame.height + ( frame_xb( window ) << 1 ); old_l = window->u.frame.x; - old_r = old_l + window->u.frame.width + ( FRAME_X_BORDER << 1 ); + old_r = old_l + window->u.frame.width + ( frame_xb( window ) << 1 ); if( size_x == SIZE_LESSER ) { new_l = x - dx; @@ -342,21 +599,25 @@ static void recalc_size( struct gwm_window *window, int x, int y, new_b += ey; } - new_width = new_r - new_l - ( FRAME_X_BORDER << 1 ); - new_height = new_b - new_t - ( FRAME_X_BORDER << 1 ); + new_width = new_r - new_l - ( frame_xb( window ) << 1 ); + new_height = new_b - new_t - ( frame_xb( window ) << 1 ); - child_width = new_width - ( FRAME_BORDER_WIDTH << 1 ); - child_height = new_height - FRAME_TITLE_HEIGHT - FRAME_BORDER_WIDTH; + child_width = new_width - frame_l( window, FALSE ) - + frame_r( window, FALSE ); + child_height = new_height - frame_t( window, FALSE ) - + frame_b( window, FALSE ); apply_size_constraints( window->u.frame.child, &child_width, &child_height ); - new_width = child_width + ( FRAME_BORDER_WIDTH << 1 ); - new_height = child_height + FRAME_TITLE_HEIGHT + FRAME_BORDER_WIDTH; + new_width = child_width + frame_l( window, FALSE ) + + frame_r( window, FALSE ); + new_height = child_height + frame_t( window, FALSE ) + + frame_b( window, FALSE ); if( size_x == SIZE_LESSER ) - new_l = new_r - new_width - ( FRAME_X_BORDER << 1 ); + new_l = new_r - new_width - ( frame_xb( window ) << 1 ); if( size_y == SIZE_LESSER ) - new_t = new_b - new_height - ( FRAME_X_BORDER << 1 ); + new_t = new_b - new_height - ( frame_xb( window ) << 1 ); if( new_l != window->u.frame.x || new_t != window->u.frame.y || new_width != window->u.frame.width || @@ -368,8 +629,10 @@ static void recalc_size( struct gwm_window *window, int x, int y, XCB_CONFIG_WINDOW_Y | XCB_CONFIG_WINDOW_WIDTH | XCB_CONFIG_WINDOW_HEIGHT, values ); - values[ 0 ] = new_width - ( FRAME_BORDER_WIDTH << 1 ); - values[ 1 ] = new_height - FRAME_TITLE_HEIGHT - FRAME_BORDER_WIDTH; + values[ 0 ] = new_width - frame_l( window, FALSE ) - + frame_r( window, FALSE ); + values[ 1 ] = new_height - frame_t( window, FALSE ) - + frame_b( window, FALSE ); /* FIXME See _NET_WM_SYNC_REQUEST in the EWMH to avoid resizing the window faster than the client can redraw it. */ xcb_configure_window( c, window->u.frame.child->w, @@ -431,8 +694,8 @@ static void frame_button_press( struct gwm_window *window, if( !initial_press( ev ) || ev->child ) return; - window_op = ( ev->detail > 1 ) == ( ev->event_y < FRAME_TITLE_HEIGHT ) ? - OP_RESIZE : OP_MOVE; + window_op = ( ev->detail > 1 ) == + ( ev->event_y < frame_t( window, FALSE ) ) ? OP_RESIZE : OP_MOVE; init_x = ev->root_x; init_y = ev->root_y; @@ -482,13 +745,13 @@ static void frame_motion_notify( struct gwm_window *window, case OP_MOVE: old_t = window->u.frame.y; - old_b = old_t + window->u.frame.height + ( FRAME_X_BORDER << 1 ); + old_b = old_t + window->u.frame.height + ( frame_xb( window ) << 1 ); old_l = window->u.frame.x; - old_r = old_l + window->u.frame.width + ( FRAME_X_BORDER << 1 ); - new_t = ev->root_y - dy - FRAME_X_BORDER; - new_b = new_t + window->u.frame.height + ( FRAME_X_BORDER << 1 ); - new_l = ev->root_x - dx - FRAME_X_BORDER; - new_r = new_l + window->u.frame.width + ( FRAME_X_BORDER << 1 ); + old_r = old_l + window->u.frame.width + ( frame_xb( window ) << 1 ); + new_t = ev->root_y - dy - frame_xb( window ); + new_b = new_t + window->u.frame.height + ( frame_xb( window ) << 1 ); + new_l = ev->root_x - dx - frame_xb( window ); + new_r = new_l + window->u.frame.width + ( frame_xb( window ) << 1 ); if( !( ev->state & XCB_MOD_MASK_CONTROL ) ) { int ex, ey; @@ -647,13 +910,14 @@ extern void synthetic_configure_notify( struct gwm_window *window ) { msg.response_type = XCB_CONFIGURE_NOTIFY; msg.event = msg.window = window->u.frame.child->w; msg.above_sibling = XCB_NONE; - msg.x = window->u.frame.x + FRAME_BORDER_WIDTH + FRAME_X_BORDER - + msg.x = window->u.frame.x + frame_l( window, TRUE ) - window->u.frame.child->u.managed.border_width; - msg.y = window->u.frame.y + FRAME_TITLE_HEIGHT + FRAME_X_BORDER - + msg.y = window->u.frame.y + frame_t( window, TRUE ) - window->u.frame.child->u.managed.border_width; - msg.width = window->u.frame.width - ( FRAME_BORDER_WIDTH << 1 ); - msg.height = window->u.frame.height - FRAME_TITLE_HEIGHT - - FRAME_BORDER_WIDTH; + msg.width = window->u.frame.width - frame_l( window, FALSE ) - + frame_r( window, FALSE ); + msg.height = window->u.frame.height - frame_t( window, FALSE ) - + frame_b( window, FALSE ); msg.border_width = window->u.frame.child->u.managed.border_width; msg.override_redirect = FALSE; xcb_send_event( c, FALSE, window->u.frame.child->w, @@ -684,16 +948,17 @@ static void frame_configure_request( struct gwm_window *window, /* Ignore border width request, but remember what was asked for. */ window->u.frame.child->u.managed.border_width = ev->border_width; - translate_frame_to_child( &child_x, &child_y, window->u.frame.x, - window->u.frame.y, + translate_frame_to_child( window, &child_x, &child_y, + window->u.frame.x, window->u.frame.y, window->u.frame.child->u.managed.border_width, window->u.frame.child->u.managed.win_gravity ); x = ev->value_mask & XCB_CONFIG_WINDOW_X ? ev->x : child_x; y = ev->value_mask & XCB_CONFIG_WINDOW_Y ? ev->y : child_y; - translate_child_to_frame( &frame_x, &frame_y, &frame_width, &frame_height, - x, y, ev->width, ev->height, + translate_child_to_frame( window, &frame_x, &frame_y, + &frame_width, &frame_height, x, y, + ev->width, ev->height, window->u.frame.child->u.managed.border_width, window->u.frame.child->u.managed.win_gravity ); @@ -717,9 +982,10 @@ static void frame_configure_request( struct gwm_window *window, if( frame_width != window->u.frame.width || frame_height != window->u.frame.height ) { - values[ 0 ] = frame_width - ( FRAME_BORDER_WIDTH << 1 ); - values[ 1 ] = frame_height - FRAME_TITLE_HEIGHT - - FRAME_BORDER_WIDTH; + values[ 0 ] = frame_width - frame_l( window, FALSE ) - + frame_r( window, FALSE ); + values[ 1 ] = frame_height - frame_t( window, FALSE ) - + frame_b( window, FALSE ); xcb_configure_window( c, ev->window, XCB_CONFIG_WINDOW_WIDTH | XCB_CONFIG_WINDOW_HEIGHT, values ); } |