From bb4f6e5fb316fb10400fa0d77ce076105fa1861b Mon Sep 17 00:00:00 2001 From: Gary Wong Date: Thu, 27 Aug 2009 10:42:14 -0600 Subject: Implement edge resistance when resizing frames. --- ChangeLog | 6 ++ frame.c | 334 ++++++++++++++++++++++++++++++++------------------------------ 2 files changed, 177 insertions(+), 163 deletions(-) diff --git a/ChangeLog b/ChangeLog index f712496..ce89b5b 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,9 @@ +2009-08-27 Gary Wong + + * frame.c (recalc_size): Implement edge resistance when resizing + frames. + (edge_resist): New function. + 2009-08-26 Gary Wong * frame.c (frame_motion_notify, frame_button_release): Implement diff --git a/frame.c b/frame.c index 7994978..5e92d58 100644 --- a/frame.c +++ b/frame.c @@ -40,7 +40,7 @@ static enum _window_operation { static enum size_which { SIZE_LESSER, SIZE_NONE, SIZE_GREATER } size_x, size_y; -static int dx, dy, var_x, fixed_x, var_y, fixed_y, init_x, init_y, moved; +static int dx, dy, init_x, init_y, moved; static struct gwm_window *feedback; static struct h_edge { @@ -164,59 +164,158 @@ static void free_edges( void ) { r_edges = NULL; } +static void edge_resist( int old_t, int old_b, int old_l, int old_r, + int new_t, int new_b, int new_l, int new_r, + int *ex, int *ey ) { + + *ex = *ey = 0; + + if( new_t < old_t ) { + /* Trying to move up; look for bottom edges with + new_t < y <= new_t + EDGE_RESIST. */ + int i0 = 0, i1 = num_b_edges - 1, i; + + while( i1 > i0 + 1 ) { + int i_mid = ( i0 + i1 ) >> 1; + + if( b_edges[ i_mid ].y <= new_t ) + i0 = i_mid; + else + i1 = i_mid; + } + + while( i0 < num_b_edges && b_edges[ i0 ].y <= new_t ) + i0++; + + for( i = i0; i < num_b_edges && b_edges[ i ].y <= new_t + EDGE_RESIST; + i++ ) + if( b_edges[ i ].x_min < new_r && b_edges[ i ].x_max > new_l ) + *ey = b_edges[ i ].y - new_t; + } else if( new_b > old_b ) { + /* Trying to move down; look for top edges with + new_b > y >= new_b - EDGE_RESIST. */ + int i0 = 0, i1 = num_t_edges - 1, i; + + while( i1 > i0 + 1 ) { + int i_mid = ( i0 + i1 ) >> 1; + + if( t_edges[ i_mid ].y >= new_b ) + i1 = i_mid; + else + i0 = i_mid; + } + + while( i1 >= 0 && t_edges[ i1 ].y >= new_b ) + i1--; + + for( i = i1; i >= 0 && t_edges[ i ].y >= new_b - EDGE_RESIST; i-- ) + if( t_edges[ i ].x_min < new_r && t_edges[ i ].x_max > new_l ) + *ey = t_edges[ i ].y - new_b; + } + + if( new_l < old_l ) { + /* Trying to move left; look for right edges with + new_l < x <= new_l + EDGE_RESIST. */ + int i0 = 0, i1 = num_r_edges - 1, i; + + while( i1 > i0 + 1 ) { + int i_mid = ( i0 + i1 ) >> 1; + + if( r_edges[ i_mid ].x <= new_l ) + i0 = i_mid; + else + i1 = i_mid; + } + + while( i0 < num_r_edges && r_edges[ i0 ].x <= new_l ) + i0++; + + for( i = i0; i < num_r_edges && r_edges[ i ].x <= new_l + EDGE_RESIST; + i++ ) + if( r_edges[ i ].y_min < new_b && r_edges[ i ].y_max > new_t ) + *ex = r_edges[ i ].x - new_l; + } else if( new_r > old_r ) { + /* Trying to move right; look for left edges with + new_r > x >= new_r - EDGE_RESIST. */ + int i0 = 0, i1 = num_l_edges - 1, i; + + while( i1 > i0 + 1 ) { + int i_mid = ( i0 + i1 ) >> 1; + + if( l_edges[ i_mid ].x >= new_r ) + i1 = i_mid; + else + i0 = i_mid; + } + + while( i1 >= 0 && l_edges[ i1 ].x >= new_r ) + i1--; + + for( i = i1; i >= 0 && l_edges[ i ].x >= new_r - EDGE_RESIST; i-- ) + if( l_edges[ i ].y_min < new_b && l_edges[ i ].y_max > new_t ) + *ex = l_edges[ i ].x - new_r; + } +} + static void recalc_size( struct gwm_window *window, int x, int y, - xcb_timestamp_t t ) { + int apply_edge_resist, xcb_timestamp_t t ) { - int new_x, new_y, new_width, new_height, child_width, child_height; + int new_width, new_height, child_width, child_height; enum size_which old_size_x = size_x, old_size_y = size_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_l = window->u.frame.x; + old_r = old_l + window->u.frame.width + ( FRAME_X_BORDER << 1 ); if( size_x == SIZE_LESSER ) { - var_x = x - dx; - new_width = fixed_x - var_x; + new_l = x - dx; + new_r = old_r; } else if( size_x == SIZE_GREATER ) { - var_x = x - dx; - new_width = var_x - fixed_x; + new_l = old_l; + new_r = x - dx; } else if( x < window->u.frame.x + ( window->u.frame.width >> 2 ) ) { /* Start sizing left border. */ size_x = SIZE_LESSER; - var_x = window->u.frame.x; - fixed_x = window->u.frame.x + window->u.frame.width; - dx = x - var_x; - new_width = fixed_x - var_x; + new_l = old_l; + new_r = old_r; + dx = x - old_l; } else if( x > window->u.frame.x + window->u.frame.width - ( window->u.frame.width >> 2 ) ) { /* Start sizing right border. */ size_x = SIZE_GREATER; - var_x = window->u.frame.x + window->u.frame.width; - fixed_x = window->u.frame.x; - dx = x - var_x; - new_width = var_x - fixed_x; - } else - new_width = window->u.frame.width; + new_l = old_l; + new_r = old_r; + dx = x - old_r; + } else { + new_l = old_l; + new_r = old_r; + } if( size_y == SIZE_LESSER ) { - var_y = y - dy; - new_height = fixed_y - var_y; + new_t = y - dy; + new_b = old_b; } else if( size_y == SIZE_GREATER ) { - var_y = y - dy; - new_height = var_y - fixed_y; + new_t = old_t; + new_b = y - dy; } else if( y < window->u.frame.y + ( window->u.frame.height >> 2 ) ) { /* Start sizing top border. */ size_y = SIZE_LESSER; - var_y = window->u.frame.y; - fixed_y = window->u.frame.y + window->u.frame.height; - dy = y - var_y; - new_height = fixed_y - var_y; + new_t = old_t; + new_b = old_b; + dy = y - old_t; } else if( y > window->u.frame.y + window->u.frame.height - ( window->u.frame.height >> 2 ) ) { /* Start sizing bottom border. */ size_y = SIZE_GREATER; - var_y = window->u.frame.y + window->u.frame.height; - fixed_y = window->u.frame.y; - dy = y - var_y; - new_height = var_y - fixed_y; - } else - new_height = window->u.frame.height; + new_t = old_t; + new_b = old_b; + dy = y - old_b; + } else { + new_t = old_t; + new_b = old_b; + } if( size_x != old_size_x || size_y != old_size_y ) xcb_change_active_pointer_grab( c, cursors[ CURSOR_TL + size_y * 3 + @@ -224,7 +323,27 @@ static void recalc_size( struct gwm_window *window, int x, int y, XCB_EVENT_MASK_BUTTON_RELEASE | XCB_EVENT_MASK_POINTER_MOTION_HINT | XCB_EVENT_MASK_BUTTON_MOTION ); - + + if( apply_edge_resist ) { + int ex, ey; + + edge_resist( old_t, old_b, old_l, old_r, + new_t, new_b, new_l, new_r, &ex, &ey ); + + if( ex > 0 ) + new_l += ex; + else + new_r += ex; + + if( ey > 0 ) + new_t += ey; + else + new_b += ey; + } + + new_width = new_r - new_l - ( FRAME_X_BORDER << 1 ); + new_height = new_b - new_t - ( FRAME_X_BORDER << 1 ); + child_width = new_width - ( FRAME_BORDER_WIDTH << 1 ); child_height = new_height - FRAME_TITLE_HEIGHT - FRAME_BORDER_WIDTH; apply_size_constraints( window->u.frame.child, &child_width, @@ -232,39 +351,17 @@ static void recalc_size( struct gwm_window *window, int x, int y, new_width = child_width + ( FRAME_BORDER_WIDTH << 1 ); new_height = child_height + FRAME_TITLE_HEIGHT + FRAME_BORDER_WIDTH; - switch( size_x ) { - case SIZE_NONE: - new_x = window->u.frame.x; - break; + if( size_x == SIZE_LESSER ) + new_l = new_r - new_width - ( FRAME_X_BORDER << 1 ); - case SIZE_LESSER: - new_x = fixed_x - new_width; - break; - - case SIZE_GREATER: - new_x = fixed_x; - break; - } + if( size_y == SIZE_LESSER ) + new_t = new_b - new_height - ( FRAME_X_BORDER << 1 ); - switch( size_y ) { - case SIZE_NONE: - new_y = window->u.frame.y; - break; - - case SIZE_LESSER: - new_y = fixed_y - new_height; - break; - - case SIZE_GREATER: - new_y = fixed_y; - break; - } - - if( new_x != window->u.frame.x || new_y != window->u.frame.y || + if( new_l != window->u.frame.x || new_t != window->u.frame.y || new_width != window->u.frame.width || new_height != window->u.frame.height ) { int new_fb_width, new_fb_height; - uint32_t values[ 4 ] = { new_x, new_y, new_width, new_height }; + uint32_t values[ 4 ] = { new_l, new_t, new_width, new_height }; xcb_configure_window( c, window->w, XCB_CONFIG_WINDOW_X | XCB_CONFIG_WINDOW_Y | XCB_CONFIG_WINDOW_WIDTH | @@ -339,7 +436,7 @@ static void frame_button_press( struct gwm_window *window, if( window_op == OP_RESIZE ) { size_x = size_y = SIZE_NONE; - recalc_size( window, ev->root_x, ev->root_y, ev->time ); + recalc_size( window, ev->root_x, ev->root_y, FALSE, ev->time ); } else { dx = ev->event_x; dy = ev->event_y; @@ -391,105 +488,15 @@ static void frame_motion_notify( struct gwm_window *window, new_r = new_l + window->u.frame.width + ( FRAME_X_BORDER << 1 ); if( !( ev->state & XCB_MOD_MASK_CONTROL ) ) { - int dx = 0, dy = 0; - - if( new_t < old_t ) { - /* Trying to move up; look for bottom edges with - new_t < y <= new_t + EDGE_RESIST. */ - int i0 = 0, i1 = num_b_edges - 1, i; - - while( i1 > i0 + 1 ) { - int i_mid = ( i0 + i1 ) >> 1; - - if( b_edges[ i_mid ].y <= new_t ) - i0 = i_mid; - else - i1 = i_mid; - } - - while( i0 < num_b_edges && b_edges[ i0 ].y <= new_t ) - i0++; - - for( i = i0; i < num_b_edges && b_edges[ i ].y <= - new_t + EDGE_RESIST; i++ ) - if( b_edges[ i ].x_min < new_r && - b_edges[ i ].x_max > new_l ) - dy = b_edges[ i ].y - new_t; - } else if( new_b > old_b ) { - /* Trying to move down; look for top edges with - new_b > y >= new_b - EDGE_RESIST. */ - int i0 = 0, i1 = num_t_edges - 1, i; - - while( i1 > i0 + 1 ) { - int i_mid = ( i0 + i1 ) >> 1; - - if( t_edges[ i_mid ].y >= new_b ) - i1 = i_mid; - else - i0 = i_mid; - } - - while( i1 >= 0 && t_edges[ i1 ].y >= new_b ) - i1--; - - for( i = i1; i >= 0 && t_edges[ i ].y >= - new_b - EDGE_RESIST; i-- ) - if( t_edges[ i ].x_min < new_r && - t_edges[ i ].x_max > new_l ) - dy = t_edges[ i ].y - new_b; - } - - new_t += dy; - new_b += dy; - - if( new_l < old_l ) { - /* Trying to move left; look for right edges with - new_l < x <= new_l + EDGE_RESIST. */ - int i0 = 0, i1 = num_r_edges - 1, i; - - while( i1 > i0 + 1 ) { - int i_mid = ( i0 + i1 ) >> 1; - - if( r_edges[ i_mid ].x <= new_l ) - i0 = i_mid; - else - i1 = i_mid; - } - - while( i0 < num_r_edges && r_edges[ i0 ].x <= new_l ) - i0++; - - for( i = i0; i < num_r_edges && r_edges[ i ].x <= - new_l + EDGE_RESIST; i++ ) - if( r_edges[ i ].y_min < new_b && - r_edges[ i ].y_max > new_t ) - dx = r_edges[ i ].x - new_l; - } else if( new_r > old_r ) { - /* Trying to move right; look for left edges with - new_r > x >= new_r - EDGE_RESIST. */ - int i0 = 0, i1 = num_l_edges - 1, i; - - while( i1 > i0 + 1 ) { - int i_mid = ( i0 + i1 ) >> 1; - - if( l_edges[ i_mid ].x >= new_r ) - i1 = i_mid; - else - i0 = i_mid; - } - - while( i1 >= 0 && l_edges[ i1 ].x >= new_r ) - i1--; - - for( i = i1; i >= 0 && l_edges[ i ].x >= - new_r - EDGE_RESIST; i-- ) - if( l_edges[ i ].y_min < new_b && - l_edges[ i ].y_max > new_t ) - dx = l_edges[ i ].x - new_r; - } + int ex, ey; - new_l += dx; - new_r += dx; + edge_resist( old_t, old_b, old_l, old_r, + new_t, new_b, new_l, new_r, &ex, &ey ); + + new_t += ey; + new_b += ey; + new_l += ex; + new_r += ex; } if( new_t != old_t || new_l != old_l ) { @@ -506,10 +513,11 @@ static void frame_motion_notify( struct gwm_window *window, break; case OP_RESIZE: - /* FIXME Implement edge resistance when resizing, too. This is a - bit harder than moving, because size constraints might prevent - us from sizing exactly to an edge. */ - recalc_size( window, ev->root_x, ev->root_y, ev->time ); + recalc_size( window, ev->root_x, ev->root_y, + !( ev->state & XCB_MOD_MASK_CONTROL ) && + window->u.frame.child->u.managed.width_inc == 1 && + window->u.frame.child->u.managed.height_inc == 1, + ev->time ); break; default: -- cgit v1.2.3