diff --git a/docs/userguide b/docs/userguide index 64063831..46a19e93 100644 --- a/docs/userguide +++ b/docs/userguide @@ -468,6 +468,22 @@ new_window 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. + +*Syntax*: +---------------------------- +hide_edge_borders +---------------------------- + +*Example*: +---------------------- +hide_edge_borders yes +---------------------- + === Arbitrary commands for specific windows (for_window) With the +for_window+ command, you can let i3 execute any command when it diff --git a/include/con.h b/include/con.h index 1965da7c..20e83df9 100644 --- a/include/con.h +++ b/include/con.h @@ -221,6 +221,12 @@ Con *con_descend_direction(Con *con, direction_t direction); */ Rect con_border_style_rect(Con *con); +/** + * Returns adjacent borders of the window. We need this if hide_edge_borders is + * enabled. + */ +adjacent_t con_adjacent_borders(Con *con); + /** * Use this function to get a container’s border style. This is important * because when inside a stack, the border style is always BS_NORMAL. diff --git a/include/config.h b/include/config.h index 310f8b02..b6f356ad 100644 --- a/include/config.h +++ b/include/config.h @@ -108,6 +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. + * This is useful if you are reaching scrollbar on the edge of the + * screen. By default, this is disabled. */ + bool 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 * the whole bar by dzen2, for example using the i3-wsbar script which diff --git a/include/data.h b/include/data.h index d28f1756..acce59be 100644 --- a/include/data.h +++ b/include/data.h @@ -60,6 +60,11 @@ typedef enum { BS_NORMAL = 0, BS_NONE = 1, BS_1PIXEL = 2 } border_style_t; * only this specific window or the whole X11 client */ typedef enum { DONT_KILL_WINDOW = 0, KILL_WINDOW = 1, KILL_CLIENT = 2 } kill_window_t; +/** 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; + enum { BIND_NONE = 0, BIND_SHIFT = XCB_MOD_MASK_SHIFT, /* (1 << 0) */ diff --git a/src/cfgparse.l b/src/cfgparse.l index cdf110d3..e2705b17 100644 --- a/src/cfgparse.l +++ b/src/cfgparse.l @@ -200,6 +200,7 @@ new_float { return TOKNEWFLOAT; } normal { return TOK_NORMAL; } none { return TOK_NONE; } 1pixel { return TOK_1PIXEL; } +hide_edge_borders { return TOK_HIDE_EDGE_BORDERS; } 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 68a51996..a2f1b9f4 100644 --- a/src/cfgparse.y +++ b/src/cfgparse.y @@ -735,6 +735,7 @@ void parse_file(const char *f) { %token TOK_NORMAL "normal" %token TOK_NONE "none" %token TOK_1PIXEL "1pixel" +%token TOK_HIDE_EDGE_BORDERS "hide_edge_borders" %token TOKFOCUSFOLLOWSMOUSE "focus_follows_mouse" %token TOK_FORCE_FOCUS_WRAPPING "force_focus_wrapping" %token TOK_FORCE_XINERAMA "force_xinerama" @@ -833,6 +834,7 @@ line: | workspace_layout | new_window | new_float + | hide_edge_borders | focus_follows_mouse | force_focus_wrapping | force_xinerama @@ -1474,6 +1476,14 @@ bool: } ; +hide_edge_borders: + TOK_HIDE_EDGE_BORDERS bool + { + DLOG("hide edge borders = %d\n", $2); + config.hide_edge_borders = $2; + } + ; + focus_follows_mouse: TOKFOCUSFOLLOWSMOUSE bool { diff --git a/src/con.c b/src/con.c index 01305f1a..4cddf227 100644 --- a/src/con.c +++ b/src/con.c @@ -934,12 +934,32 @@ Con *con_descend_direction(Con *con, direction_t direction) { * */ Rect con_border_style_rect(Con *con) { + adjacent_t adjacent_to = ADJ_NONE; + Rect result; + if (config.hide_edge_borders) + adjacent_to = con_adjacent_borders(con); switch (con_border_style(con)) { case BS_NORMAL: - return (Rect){2, 0, -(2 * 2), -2}; + result = (Rect){2, 0, -(2 * 2), -2}; + if (adjacent_to & ADJ_LEFT_SCREEN_EDGE) { + result.x -= 2; + result.width += 2; + } + if (adjacent_to & ADJ_RIGHT_SCREEN_EDGE) { + result.width += 2; + } + return result; case BS_1PIXEL: - return (Rect){1, 1, -2, -2}; + result = (Rect){1, 1, -2, -2}; + if (adjacent_to & ADJ_LEFT_SCREEN_EDGE) { + result.x -= 1; + result.width += 1; + } + if (adjacent_to & ADJ_RIGHT_SCREEN_EDGE) { + result.width += 1; + } + return result; case BS_NONE: return (Rect){0, 0, 0, 0}; @@ -949,6 +969,20 @@ Rect con_border_style_rect(Con *con) { } } +/* + * Returns adjacent borders of the window. We need this if hide_edge_borders is + * enabled. + */ +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) + result |= ADJ_LEFT_SCREEN_EDGE; + if (con->rect.x + con->rect.width == output->rect.x + output->rect.width) + result |= ADJ_RIGHT_SCREEN_EDGE; + return result; +} + /* * Use this function to get a container’s border style. This is important * because when inside a stack, the border style is always BS_NORMAL. diff --git a/src/x.c b/src/x.c index 08eb8fee..f4d1416f 100644 --- a/src/x.c +++ b/src/x.c @@ -299,6 +299,9 @@ 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 @@ -408,12 +411,16 @@ 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 }); - xcb_rectangle_t borders[] = { - { 0, 0, br.x, r->height }, - { 0, r->height + br.height + br.y, r->width, r->height }, - { r->width + br.width + br.x, 0, r->width, r->height } - }; - xcb_poly_fill_rectangle(conn, con->pixmap, con->pm_gc, 3, borders); + if (!(adjacent_to & 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)) { + 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); /* 1pixel border needs an additional line at the top */ if (p->border_style == BS_1PIXEL) { xcb_rectangle_t topline = { br.x, 0, con->rect.width + br.width + br.x, br.y };