border (string)::
Can be either "normal", "none" or "1pixel", dependending on the
container’s 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".
*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
* 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>'.
* 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
int default_layout;
int container_stack_limit;
int container_stack_limit_value;
+ int default_border_width;
/** Default orientation for new containers */
int default_orientation;
*****************************************************************************/
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 */
/* the x11 border pixel attribute */
int border_width;
+ int current_border_width;
/* minimum increment size specified for the window (in pixels) */
int width_increment;
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]
%s OUTPUT_COND
%s FOR_WINDOW_COND
%s EAT_WHITESPACE
+%s BORDER_WIDTH
%x BUFFER_LINE
%x BAR
}
<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; }
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; }
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) {
%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"
%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
;
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:
}
;
+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; }
}
/*
- * 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;
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;
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);
*/
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;
+
}
/*
* 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;
}
/* 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);
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;
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);
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);
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;
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);
}
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);
}
}
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);
}
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
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;
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)};
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)};
@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);
@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);