diff --git a/docs/userguide b/docs/userguide index 46a19e93..37e55d46 100644 --- a/docs/userguide +++ b/docs/userguide @@ -471,17 +471,17 @@ new_window 1pixel === Hiding vertical borders You can hide vertical borders adjacent to the screen edges using -+hide_edge_borders+. This is useful if you are using scrollbars. This option is -disabled by default. ++hide_edge_borders+. This is useful if you are using scrollbars, or do not want +to waste even two pixels in displayspace. Default is none. *Syntax*: ---------------------------- -hide_edge_borders +hide_edge_borders ---------------------------- *Example*: ---------------------- -hide_edge_borders yes +hide_edge_borders vertical ---------------------- === Arbitrary commands for specific windows (for_window) diff --git a/include/config.h b/include/config.h index b6f356ad..ebb24864 100644 --- a/include/config.h +++ b/include/config.h @@ -108,10 +108,11 @@ struct Config { * It is not planned to add any different focus models. */ bool disable_focus_follows_mouse; - /** Remove vertical borders if they are adjacent to the screen edge. + /** Remove borders if they are adjacent to the screen edge. * This is useful if you are reaching scrollbar on the edge of the - * screen. By default, this is disabled. */ - bool hide_edge_borders; + * screen or do not want to waste a single pixel of displayspace. + * By default, this is disabled. */ + adjacent_t hide_edge_borders; /** By default, a workspace bar is drawn at the bottom of the screen. * If you want to have a more fancy bar, it is recommended to replace diff --git a/include/data.h b/include/data.h index acce59be..a5ac943c 100644 --- a/include/data.h +++ b/include/data.h @@ -62,8 +62,10 @@ typedef enum { DONT_KILL_WINDOW = 0, KILL_WINDOW = 1, KILL_CLIENT = 2 } kill_win /** describes if the window is adjacent to the output (physical screen) edges. */ typedef enum { ADJ_NONE = 0, - ADJ_LEFT_SCREEN_EDGE = 1, - ADJ_RIGHT_SCREEN_EDGE = 2} adjacent_t; + ADJ_LEFT_SCREEN_EDGE = (1 << 0), + ADJ_RIGHT_SCREEN_EDGE = (1 << 1), + ADJ_UPPER_SCREEN_EDGE = (1 << 2), + ADJ_LOWER_SCREEN_EDGE = (1 << 4)} adjacent_t; enum { BIND_NONE = 0, diff --git a/src/cfgparse.l b/src/cfgparse.l index e2705b17..04117624 100644 --- a/src/cfgparse.l +++ b/src/cfgparse.l @@ -201,6 +201,7 @@ normal { return TOK_NORMAL; } none { return TOK_NONE; } 1pixel { return TOK_1PIXEL; } hide_edge_borders { return TOK_HIDE_EDGE_BORDERS; } +both { return TOK_BOTH; } focus_follows_mouse { return TOKFOCUSFOLLOWSMOUSE; } force_focus_wrapping { return TOK_FORCE_FOCUS_WRAPPING; } force_xinerama { return TOK_FORCE_XINERAMA; } diff --git a/src/cfgparse.y b/src/cfgparse.y index a2f1b9f4..af7d77cf 100644 --- a/src/cfgparse.y +++ b/src/cfgparse.y @@ -736,6 +736,7 @@ void parse_file(const char *f) { %token TOK_NONE "none" %token TOK_1PIXEL "1pixel" %token TOK_HIDE_EDGE_BORDERS "hide_edge_borders" +%token TOK_BOTH "both" %token TOKFOCUSFOLLOWSMOUSE "focus_follows_mouse" %token TOK_FORCE_FOCUS_WRAPPING "force_focus_wrapping" %token TOK_FORCE_XINERAMA "force_xinerama" @@ -800,6 +801,8 @@ void parse_file(const char *f) { %type layout_mode %type border_style %type new_window +%type hide_edge_borders +%type edge_hiding_mode %type new_float %type colorpixel %type bool @@ -1477,13 +1480,21 @@ bool: ; hide_edge_borders: - TOK_HIDE_EDGE_BORDERS bool + TOK_HIDE_EDGE_BORDERS edge_hiding_mode { DLOG("hide edge borders = %d\n", $2); config.hide_edge_borders = $2; } ; +edge_hiding_mode: + TOK_NONE { $$ = ADJ_NONE; } + | TOK_VERT { $$ = ADJ_LEFT_SCREEN_EDGE | ADJ_RIGHT_SCREEN_EDGE; } + | TOK_HORIZ { $$ = ADJ_UPPER_SCREEN_EDGE | ADJ_LOWER_SCREEN_EDGE; } + | TOK_BOTH { $$ = ADJ_LEFT_SCREEN_EDGE | ADJ_RIGHT_SCREEN_EDGE | ADJ_UPPER_SCREEN_EDGE | ADJ_LOWER_SCREEN_EDGE; } + | bool { $$ = ($1 ? ADJ_LEFT_SCREEN_EDGE | ADJ_RIGHT_SCREEN_EDGE : ADJ_NONE); } + ; + focus_follows_mouse: TOKFOCUSFOLLOWSMOUSE bool { diff --git a/src/con.c b/src/con.c index 35ad540c..6f2a85b2 100644 --- a/src/con.c +++ b/src/con.c @@ -934,31 +934,41 @@ Con *con_descend_direction(Con *con, direction_t direction) { * */ Rect con_border_style_rect(Con *con) { - adjacent_t adjacent_to = ADJ_NONE; + adjacent_t borders_to_hide = ADJ_NONE; Rect result; - if (config.hide_edge_borders) - adjacent_to = con_adjacent_borders(con); + borders_to_hide = con_adjacent_borders(con) & config.hide_edge_borders; switch (con_border_style(con)) { case BS_NORMAL: result = (Rect){2, 0, -(2 * 2), -2}; - if (adjacent_to & ADJ_LEFT_SCREEN_EDGE) { + if (borders_to_hide & ADJ_LEFT_SCREEN_EDGE) { result.x -= 2; result.width += 2; } - if (adjacent_to & ADJ_RIGHT_SCREEN_EDGE) { + if (borders_to_hide & ADJ_RIGHT_SCREEN_EDGE) { result.width += 2; } + /* With normal borders we never hide the upper border */ + if (borders_to_hide & ADJ_LOWER_SCREEN_EDGE) { + result.height += 2; + } return result; case BS_1PIXEL: result = (Rect){1, 1, -2, -2}; - if (adjacent_to & ADJ_LEFT_SCREEN_EDGE) { + if (borders_to_hide & ADJ_LEFT_SCREEN_EDGE) { result.x -= 1; result.width += 1; } - if (adjacent_to & ADJ_RIGHT_SCREEN_EDGE) { + if (borders_to_hide & ADJ_RIGHT_SCREEN_EDGE) { result.width += 1; } + if (borders_to_hide & ADJ_UPPER_SCREEN_EDGE) { + result.y -= 1; + result.height += 1; + } + if (borders_to_hide & ADJ_LOWER_SCREEN_EDGE) { + result.height += 1; + } return result; case BS_NONE: @@ -975,11 +985,15 @@ Rect con_border_style_rect(Con *con) { */ adjacent_t con_adjacent_borders(Con *con) { adjacent_t result = ADJ_NONE; - Con *output = con_get_output(con); - if (con->rect.x == output->rect.x) + Con *workspace = con_get_workspace(con); + if (con->rect.x == workspace->rect.x) result |= ADJ_LEFT_SCREEN_EDGE; - if (con->rect.x + con->rect.width == output->rect.x + output->rect.width) + if (con->rect.x + con->rect.width == workspace->rect.x + workspace->rect.width) result |= ADJ_RIGHT_SCREEN_EDGE; + if (con->rect.y == workspace->rect.y) + result |= ADJ_UPPER_SCREEN_EDGE; + if (con->rect.y + con->rect.height == workspace->rect.y + workspace->rect.height) + result |= ADJ_LOWER_SCREEN_EDGE; return result; } diff --git a/src/x.c b/src/x.c index f4d1416f..cd85bcc6 100644 --- a/src/x.c +++ b/src/x.c @@ -299,19 +299,19 @@ void x_window_kill(xcb_window_t window, kill_window_t kill_window) { void x_draw_decoration(Con *con) { Con *parent = con->parent; bool leaf = con_is_leaf(con); - adjacent_t adjacent_to = ADJ_NONE; - if (config.hide_edge_borders) - adjacent_to = con_adjacent_borders(con); + /* This code needs to run for: * • leaf containers * • non-leaf containers which are in a stacked/tabbed container * * It does not need to run for: + * • direct children of outputs * • floating containers (they don’t have a decoration) */ if ((!leaf && parent->layout != L_STACKED && parent->layout != L_TABBED) || + parent->type == CT_OUTPUT || con->type == CT_FLOATING_CON) return; @@ -399,6 +399,10 @@ void x_draw_decoration(Con *con) { /* 3: draw a rectangle in border color around the client */ if (p->border_style != BS_NONE && p->con_is_leaf) { + /* We might hide some borders adjacent to the screen-edge */ + adjacent_t borders_to_hide = ADJ_NONE; + borders_to_hide = con_adjacent_borders(con) & config.hide_edge_borders; + Rect br = con_border_style_rect(con); #if 0 DLOG("con->rect spans %d x %d\n", con->rect.width, con->rect.height); @@ -411,18 +415,20 @@ void x_draw_decoration(Con *con) { * rectangle because some childs are not freely resizable and we want * their background color to "shine through". */ xcb_change_gc(conn, con->pm_gc, XCB_GC_FOREGROUND, (uint32_t[]){ p->color->background }); - if (!(adjacent_to & ADJ_LEFT_SCREEN_EDGE)) { + if (!(borders_to_hide & ADJ_LEFT_SCREEN_EDGE)) { xcb_rectangle_t leftline = { 0, 0, br.x, r->height }; xcb_poly_fill_rectangle(conn, con->pixmap, con->pm_gc, 1, &leftline); } - if (!(adjacent_to & ADJ_RIGHT_SCREEN_EDGE)) { + if (!(borders_to_hide & ADJ_RIGHT_SCREEN_EDGE)) { xcb_rectangle_t rightline = { r->width + br.width + br.x, 0, r->width, r->height }; xcb_poly_fill_rectangle(conn, con->pixmap, con->pm_gc, 1, &rightline); } - xcb_rectangle_t bottomline = { 0, r->height + br.height + br.y, r->width, r->height }; - xcb_poly_fill_rectangle(conn, con->pixmap, con->pm_gc, 1, &bottomline); + if (!(borders_to_hide & ADJ_LOWER_SCREEN_EDGE)) { + xcb_rectangle_t bottomline = { 0, r->height + br.height + br.y, r->width, r->height }; + xcb_poly_fill_rectangle(conn, con->pixmap, con->pm_gc, 1, &bottomline); + } /* 1pixel border needs an additional line at the top */ - if (p->border_style == BS_1PIXEL) { + if (p->border_style == BS_1PIXEL && !(borders_to_hide & ADJ_UPPER_SCREEN_EDGE)) { xcb_rectangle_t topline = { br.x, 0, con->rect.width + br.width + br.x, br.y }; xcb_poly_fill_rectangle(conn, con->pixmap, con->pm_gc, 1, &topline); }