Implement variable border widths for pixel/normal

fixes #325
next
Yaroslav Molochko 2012-09-24 02:14:00 +03:00 committed by Michael Stapelberg
parent b235c469c1
commit 04c58c7325
20 changed files with 144 additions and 73 deletions

View File

@ -274,6 +274,8 @@ name (string)::
border (string)::
Can be either "normal", "none" or "1pixel", dependending on the
containers border style.
current_border_width (integer)::
Number of pixels of the border width.
layout (string)::
Can be either "splith", "splitv", "stacked", "tabbed", "dockarea" or
"output".

View File

@ -483,14 +483,26 @@ This option determines which border style new windows will have. The default is
*Syntax*:
---------------------------------------------
new_window <normal|1pixel|none>
new_window <normal|1pixel|none|pixel>
---------------------------------------------
*Example*:
---------------------
new_window 1pixel
---------------------
The "normal" and "pixel" border styles support an optional border width in
pixels:
*Example*:
---------------------
# The same as new_window none
new_window pixel 0
# A 3 px border
new_window pixel 3
---------------------
=== Hiding vertical borders
You can hide vertical borders adjacent to the screen edges using

View File

@ -83,7 +83,7 @@ void cmd_resize(I3_CMD, char *way, char *direction, char *resize_px, char *resiz
* Implementation of 'border normal|none|1pixel|toggle'.
*
*/
void cmd_border(I3_CMD, char *border_style_str);
void cmd_border(I3_CMD, char *border_style_str, char *border_width);
/**
* Implementation of 'nop <comment>'.

View File

@ -250,7 +250,7 @@ int con_border_style(Con *con);
* floating window.
*
*/
void con_set_border_style(Con *con, int border_style);
void con_set_border_style(Con *con, int border_style, int border_width);
/**
* This function changes the layout of a given container. Use it to handle

View File

@ -98,6 +98,7 @@ struct Config {
int default_layout;
int container_stack_limit;
int container_stack_limit_value;
int default_border_width;
/** Default orientation for new containers */
int default_orientation;

View File

@ -55,7 +55,7 @@ typedef struct Window i3Window;
*****************************************************************************/
typedef enum { D_LEFT, D_RIGHT, D_UP, D_DOWN } direction_t;
typedef enum { NO_ORIENTATION = 0, HORIZ, VERT } orientation_t;
typedef enum { BS_NORMAL = 0, BS_NONE = 1, BS_1PIXEL = 2 } border_style_t;
typedef enum { BS_NORMAL = 0, BS_NONE = 1, BS_PIXEL = 2 } border_style_t;
/** parameter to specify whether tree_close() and x_window_kill() should kill
* only this specific window or the whole X11 client */
@ -485,6 +485,7 @@ struct Con {
/* the x11 border pixel attribute */
int border_width;
int current_border_width;
/* minimum increment size specified for the window (in pixels) */
int width_increment;

View File

@ -61,10 +61,20 @@ state EXEC:
command = string
-> call cmd_exec($nosn, $command)
# border normal|none|1pixel|toggle
# border normal|none|1pixel|toggle|1pixel
state BORDER:
border_style = 'normal', 'none', '1pixel', 'toggle'
-> call cmd_border($border_style)
border_style = 'normal', 'pixel'
-> BORDER_WIDTH
border_style = 'none', 'toggle'
-> call cmd_border($border_style, "0")
border_style = '1pixel'
-> call cmd_border($border_style, "1")
state BORDER_WIDTH:
end
-> call cmd_border($border_style, "2")
border_width = word
-> call cmd_border($border_style, $border_width)
# layout default|stacked|stacking|tabbed|splitv|splith
# layout toggle [split|all]

View File

@ -56,6 +56,7 @@ EOL (\r?\n)
%s OUTPUT_COND
%s FOR_WINDOW_COND
%s EAT_WHITESPACE
%s BORDER_WIDTH
%x BUFFER_LINE
%x BAR
@ -171,6 +172,7 @@ EOL (\r?\n)
}
<ASSIGN_TARGET_COND>[ \t]*→[ \t]* { BEGIN(WANT_STRING); }
<ASSIGN_TARGET_COND>[ \t]+ { BEGIN(WANT_STRING); }
<BORDER_WIDTH>[^\n][0-9]+ { printf("Border width set to: %s\n", yytext); yylval.number = atoi(yytext); return NUMBER;}
<EXEC>--no-startup-id { printf("no startup id\n"); yy_pop_state(); return TOK_NO_STARTUP_ID; }
<EXEC>. { printf("anything else: *%s*\n", yytext); yyless(0); yy_pop_state(); yy_pop_state(); }
<OPTRELEASE>--release { printf("--release\n"); yy_pop_state(); return TOK_RELEASE; }
@ -200,9 +202,10 @@ auto { return TOK_AUTO; }
workspace_layout { return TOK_WORKSPACE_LAYOUT; }
new_window { return TOKNEWWINDOW; }
new_float { return TOKNEWFLOAT; }
normal { return TOK_NORMAL; }
normal { yy_push_state(BORDER_WIDTH); return TOK_NORMAL; }
none { return TOK_NONE; }
1pixel { return TOK_1PIXEL; }
pixel { yy_push_state(BORDER_WIDTH); return TOK_PIXEL; }
hide_edge_borders { return TOK_HIDE_EDGE_BORDERS; }
both { return TOK_BOTH; }
focus_follows_mouse { return TOKFOCUSFOLLOWSMOUSE; }

View File

@ -108,6 +108,7 @@ static int detect_version(char *buf) {
strncasecmp(bind, "focus down", strlen("focus down")) == 0 ||
strncasecmp(bind, "border normal", strlen("border normal")) == 0 ||
strncasecmp(bind, "border 1pixel", strlen("border 1pixel")) == 0 ||
strncasecmp(bind, "border pixel", strlen("border pixel")) == 0 ||
strncasecmp(bind, "border borderless", strlen("border borderless")) == 0 ||
strncasecmp(bind, "--no-startup-id", strlen("--no-startup-id")) == 0 ||
strncasecmp(bind, "bar", strlen("bar")) == 0) {
@ -739,6 +740,7 @@ void parse_file(const char *f) {
%token TOKNEWFLOAT "new_float"
%token TOK_NORMAL "normal"
%token TOK_NONE "none"
%token TOK_PIXEL "pixel"
%token TOK_1PIXEL "1pixel"
%token TOK_HIDE_EDGE_BORDERS "hide_edge_borders"
%token TOK_BOTH "both"
@ -818,6 +820,7 @@ void parse_file(const char *f) {
%type <number> bar_mode_mode
%type <number> bar_modifier_modifier
%type <number> optional_no_startup_id
%type <number> optional_border_width
%type <number> optional_release
%type <string> command
%type <string> word_or_number
@ -1480,9 +1483,26 @@ new_float:
;
border_style:
TOK_NORMAL { $$ = BS_NORMAL; }
| TOK_NONE { $$ = BS_NONE; }
| TOK_1PIXEL { $$ = BS_1PIXEL; }
TOK_NORMAL optional_border_width
{
config.default_border_width = $2;
$$ = BS_NORMAL;
}
| TOK_1PIXEL
{
config.default_border_width = 1;
$$ = BS_PIXEL;
}
| TOK_NONE
{
config.default_border_width = 0;
$$ = BS_NONE;
}
| TOK_PIXEL optional_border_width
{
config.default_border_width = $2;
$$ = BS_PIXEL;
}
;
bool:
@ -1753,6 +1773,11 @@ exec_always:
}
;
optional_border_width:
/* empty */ { $$ = 2; } // 2 pixels is the default value for any type of border
| NUMBER { $$ = $1; }
;
optional_no_startup_id:
/* empty */ { $$ = false; }
| TOK_NO_STARTUP_ID { $$ = true; }

View File

@ -776,11 +776,11 @@ void cmd_resize(I3_CMD, char *way, char *direction, char *resize_px, char *resiz
}
/*
* Implementation of 'border normal|none|1pixel|toggle'.
* Implementation of 'border normal|none|1pixel|toggle|pixel'.
*
*/
void cmd_border(I3_CMD, char *border_style_str) {
DLOG("border style should be changed to %s\n", border_style_str);
void cmd_border(I3_CMD, char *border_style_str, char *border_width ) {
DLOG("border style should be changed to %s with border width %s\n", border_style_str, border_width);
owindow *current;
HANDLE_EMPTY_MATCH;
@ -788,23 +788,39 @@ void cmd_border(I3_CMD, char *border_style_str) {
TAILQ_FOREACH(current, &owindows, owindows) {
DLOG("matching: %p / %s\n", current->con, current->con->name);
int border_style = current->con->border_style;
char *end;
int tmp_border_width = -1;
tmp_border_width = strtol(border_width, &end, 10);
if (end == border_width) {
/* no valid digits found */
tmp_border_width = -1;
}
if (strcmp(border_style_str, "toggle") == 0) {
border_style++;
border_style %= 3;
if (border_style == BS_NORMAL)
current->con->current_border_width = 2;
else if (border_style == BS_NONE)
current->con->current_border_width = 0;
else if (border_style == BS_PIXEL)
current->con->current_border_width = 1;
} else {
if (strcmp(border_style_str, "normal") == 0)
border_style = BS_NORMAL;
else if (strcmp(border_style_str, "none") == 0)
else if (strcmp(border_style_str, "pixel") == 0)
border_style = BS_PIXEL;
else if (strcmp(border_style_str, "1pixel") == 0){
border_style = BS_PIXEL;
tmp_border_width = 1;
} else if (strcmp(border_style_str, "none") == 0)
border_style = BS_NONE;
else if (strcmp(border_style_str, "1pixel") == 0)
border_style = BS_1PIXEL;
else {
ELOG("BUG: called with border_style=%s\n", border_style_str);
ysuccess(false);
return;
}
}
con_set_border_style(current->con, border_style);
con_set_border_style(current->con, border_style, tmp_border_width);
}
cmd_output->needs_tree_render = true;

View File

@ -55,6 +55,7 @@ Con *con_new(Con *parent, i3Window *window) {
new->type = CT_CON;
new->window = window;
new->border_style = config.default_border;
new->current_border_width = -1;
static int cnt = 0;
DLOG("opening window %d\n", cnt);
@ -968,52 +969,38 @@ Con *con_descend_direction(Con *con, direction_t direction) {
*/
Rect con_border_style_rect(Con *con) {
adjacent_t borders_to_hide = ADJ_NONE;
int border_width = con->current_border_width;
DLOG("The border width for con is set to: %d\n", con->current_border_width);
Rect result;
if (con->current_border_width < 0)
border_width = config.default_border_width;
DLOG("Effective border width is set to: %d\n", border_width);
/* Shortcut to avoid calling con_adjacent_borders() on dock containers. */
int border_style = con_border_style(con);
if (border_style == BS_NONE)
return (Rect){ 0, 0, 0, 0 };
borders_to_hide = con_adjacent_borders(con) & config.hide_edge_borders;
switch (border_style) {
case BS_NORMAL:
result = (Rect){2, 0, -(2 * 2), -2};
if (borders_to_hide & ADJ_LEFT_SCREEN_EDGE) {
result.x -= 2;
result.width += 2;
}
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 (borders_to_hide & ADJ_LEFT_SCREEN_EDGE) {
result.x -= 1;
result.width += 1;
}
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:
return (Rect){0, 0, 0, 0};
default:
assert(false);
if (border_style == BS_NORMAL) {
result = (Rect){border_width, 0 , -(2 * border_width), -(border_width)};
} else {
result = (Rect){border_width, border_width, -(2 * border_width), -(2 * border_width)};
}
if (borders_to_hide & ADJ_LEFT_SCREEN_EDGE) {
result.x -= border_width;
result.width += border_width;
}
if (borders_to_hide & ADJ_RIGHT_SCREEN_EDGE) {
result.width += border_width;
}
if (borders_to_hide & ADJ_UPPER_SCREEN_EDGE && (border_style != BS_NORMAL)) {
result.y -= border_width;
result.height += border_width;
}
if (borders_to_hide & ADJ_LOWER_SCREEN_EDGE) {
result.height += border_width;
}
return result;
}
/*
@ -1068,10 +1055,11 @@ int con_border_style(Con *con) {
* floating window.
*
*/
void con_set_border_style(Con *con, int border_style) {
void con_set_border_style(Con *con, int border_style, int border_width) {
/* Handle the simple case: non-floating containerns */
if (!con_is_floating(con)) {
con->border_style = border_style;
con->current_border_width = border_width;
return;
}
@ -1090,6 +1078,7 @@ void con_set_border_style(Con *con, int border_style) {
/* Change the border style, get new border/decoration values. */
con->border_style = border_style;
con->current_border_width = border_width;
bsr = con_border_style_rect(con);
int deco_height =
(con->border_style == BS_NORMAL ? config.font.height + 5 : 0);

View File

@ -417,6 +417,7 @@ void load_configuration(xcb_connection_t *conn, const char *override_configpath,
config.default_border = BS_NORMAL;
config.default_floating_border = BS_NORMAL;
config.default_border_width = 2;
/* Set default_orientation to NO_ORIENTATION for auto orientation. */
config.default_orientation = NO_ORIENTATION;

View File

@ -266,11 +266,14 @@ void dump_node(yajl_gen gen, struct Con *con, bool inplace_restart) {
case BS_NONE:
ystr("none");
break;
case BS_1PIXEL:
ystr("1pixel");
case BS_PIXEL:
ystr("pixel");
break;
}
ystr("current_border_width");
y(integer, con->current_border_width);
dump_rect(gen, "rect", con->rect);
dump_rect(gen, "window_rect", con->window_rect);
dump_rect(gen, "geometry", con->geometry);

View File

@ -183,8 +183,11 @@ static int json_string(void *ctx, const unsigned char *val, unsigned int len) {
sasprintf(&buf, "%.*s", (int)len, val);
if (strcasecmp(buf, "none") == 0)
json_node->border_style = BS_NONE;
else if (strcasecmp(buf, "1pixel") == 0)
json_node->border_style = BS_1PIXEL;
else if (strcasecmp(buf, "1pixel") == 0) {
json_node->border_style = BS_PIXEL;
json_node->current_border_width = 1;
} else if (strcasecmp(buf, "pixel") == 0)
json_node->border_style = BS_PIXEL;
else if (strcasecmp(buf, "normal") == 0)
json_node->border_style = BS_NORMAL;
else LOG("Unhandled \"border\": %s\n", buf);
@ -278,6 +281,9 @@ static int json_int(void *ctx, long val) {
if (strcasecmp(last_key, "num") == 0)
json_node->num = val;
if (strcasecmp(last_key, "current_border_width") == 0)
json_node->current_border_width = val;
if (!parsing_swallows && strcasecmp(last_key, "id") == 0)
json_node->old_id = val;

View File

@ -311,7 +311,7 @@ void render_con(Con *con, bool render_fullscreen) {
child->deco_rect.width = child->rect.width;
child->deco_rect.height = deco_height;
if (children > 1 || (child->border_style != BS_1PIXEL && child->border_style != BS_NONE)) {
if (children > 1 || (child->border_style != BS_PIXEL && child->border_style != BS_NONE)) {
child->rect.y += (deco_height * children);
child->rect.height -= (deco_height * children);
}
@ -328,12 +328,12 @@ void render_con(Con *con, bool render_fullscreen) {
child->deco_rect.x = x - con->rect.x + i * child->deco_rect.width;
child->deco_rect.y = y - con->rect.y;
if (children > 1 || (child->border_style != BS_1PIXEL && child->border_style != BS_NONE)) {
if (children > 1 || (child->border_style != BS_PIXEL && child->border_style != BS_NONE)) {
child->rect.y += deco_height;
child->rect.height -= deco_height;
child->deco_rect.height = deco_height;
} else {
child->deco_rect.height = (child->border_style == BS_1PIXEL ? 1 : 0);
child->deco_rect.height = (child->border_style == BS_PIXEL ? 1 : 0);
}
}

View File

@ -431,7 +431,7 @@ void x_draw_decoration(Con *con) {
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 && !(borders_to_hide & ADJ_UPPER_SCREEN_EDGE)) {
if (p->border_style == BS_PIXEL && !(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);
}

View File

@ -69,6 +69,7 @@ my $expected = {
border => 'normal',
'floating_nodes' => $ignore,
workspace_layout => 'default',
current_border_width => -1,
};
# a shallow copy is sufficient, since we only ignore values at the root

View File

@ -36,13 +36,13 @@ is(get_border_style(), 'normal', 'border style normal');
cmd 'border 1pixel';
is(get_border_style(), '1pixel', 'border style 1pixel after changing');
is(get_border_style(), 'pixel', 'border style 1pixel after changing');
# perform an inplace-restart
cmd 'restart';
does_i3_live;
is(get_border_style(), '1pixel', 'border style still 1pixel after restart');
is(get_border_style(), 'pixel', 'border style still 1pixel after restart');
done_testing;

View File

@ -28,7 +28,7 @@ is($nodes[0]->{border}, 'normal', 'border style normal');
cmd 'border 1pixel';
@nodes = @{get_ws_content($tmp)};
is($nodes[0]->{border}, '1pixel', 'border style 1pixel');
is($nodes[0]->{border}, 'pixel', 'border style 1pixel');
cmd 'border none';
@nodes = @{get_ws_content($tmp)};
@ -44,7 +44,7 @@ is($nodes[0]->{border}, 'none', 'border style none');
cmd 'border toggle';
@nodes = @{get_ws_content($tmp)};
is($nodes[0]->{border}, '1pixel', 'border style 1pixel');
is($nodes[0]->{border}, 'pixel', 'border style 1pixel');
cmd 'border toggle';
@nodes = @{get_ws_content($tmp)};

View File

@ -65,7 +65,8 @@ $first = open_window;
@content = @{get_ws_content($tmp)};
ok(@content == 1, 'one container opened');
is($content[0]->{border}, '1pixel', 'border normal by default');
is($content[0]->{border}, 'pixel', 'border pixel by default');
is($content[0]->{current_border_width}, -1, 'border width pixels -1 (default)');
exit_gracefully($pid);
@ -119,7 +120,7 @@ $wscontent = get_ws($tmp);
@floating = @{$wscontent->{floating_nodes}};
ok(@floating == 1, 'one floating container opened');
$floatingcon = $floating[0];
is($floatingcon->{nodes}->[0]->{border}, '1pixel', 'border normal by default');
is($floatingcon->{nodes}->[0]->{border}, 'pixel', 'border pixel by default');
exit_gracefully($pid);