summaryrefslogtreecommitdiff
path: root/frame.c
diff options
context:
space:
mode:
Diffstat (limited to 'frame.c')
-rw-r--r--frame.c334
1 files changed, 300 insertions, 34 deletions
diff --git a/frame.c b/frame.c
index 8faac26..969733d 100644
--- a/frame.c
+++ b/frame.c
@@ -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 );
}