From e101940c5edd3094463fea362fc21e924a46eca4 Mon Sep 17 00:00:00 2001 From: Michael Stapelberg Date: Sun, 27 Sep 2009 23:08:27 +0200 Subject: [PATCH] Implement options to change the default mode of containers The following new directives have been implemented for the configuration file: new_container new_container stack-limit Note that they require using the new lexer/parser, which you can do by passing -l to i3 when starting. --- include/config.h | 5 +++++ src/cfgparse.l | 7 +++++++ src/cfgparse.y | 43 +++++++++++++++++++++++++++++++++++++++++++ src/layout.c | 3 +++ src/mainx.c | 8 ++++++++ src/table.c | 6 ++++-- src/util.c | 11 +++++++---- src/workspace.c | 23 +++++++++++++++-------- 8 files changed, 92 insertions(+), 14 deletions(-) diff --git a/include/config.h b/include/config.h index 6bb53209..f11a7b5b 100644 --- a/include/config.h +++ b/include/config.h @@ -17,6 +17,7 @@ #include #include "queue.h" +#include "i3.h" typedef struct Config Config; extern Config config; @@ -71,6 +72,10 @@ struct Config { const char *ipc_socket_path; + int container_mode; + int container_stack_limit; + int container_stack_limit_value; + /** The modifier which needs to be pressed in combination with your mouse * buttons to do things with floating windows (move, resize) */ uint32_t floating_modifier; diff --git a/src/cfgparse.l b/src/cfgparse.l index 9ef12a86..45ea6333 100644 --- a/src/cfgparse.l +++ b/src/cfgparse.l @@ -37,6 +37,13 @@ assign { BEGIN(ASSIGN_COND); return TOKASSIGN; } set[^\n]* { return TOKCOMMENT; } ipc-socket { BEGIN(BIND_AWS_COND); return TOKIPCSOCKET; } ipc_socket { BEGIN(BIND_AWS_COND); return TOKIPCSOCKET; } +new_container { return TOKNEWCONTAINER; } +default { yylval.number = MODE_DEFAULT; return TOKCONTAINERMODE; } +stacking { yylval.number = MODE_STACK; return TOKCONTAINERMODE; } +tabbed { yylval.number = MODE_TABBED; return TOKCONTAINERMODE; } +stack-limit { return TOKSTACKLIMIT; } +cols { yylval.number = STACK_LIMIT_COLS; return TOKSTACKLIMIT; } +rows { yylval.number = STACK_LIMIT_ROWS; return TOKSTACKLIMIT; } exec { BEGIN(BIND_AWS_COND); return TOKEXEC; } client.focused { BEGIN(COLOR_COND); yylval.color = &config.client.focused; return TOKCOLOR; } client.focused_inactive { BEGIN(COLOR_COND); yylval.color = &config.client.focused_inactive; return TOKCOLOR; } diff --git a/src/cfgparse.y b/src/cfgparse.y index f41a69b0..d706b400 100644 --- a/src/cfgparse.y +++ b/src/cfgparse.y @@ -189,6 +189,9 @@ void parse_file(const char *f) { %token TOKCOLOR %token TOKARROW %token TOKMODE +%token TOKNEWCONTAINER +%token TOKCONTAINERMODE +%token TOKSTACKLIMIT %% @@ -201,6 +204,7 @@ line: bindline | mode | floating_modifier + | new_container | workspace | assign | ipcsocket @@ -309,6 +313,45 @@ floating_modifier: } ; +new_container: + TOKNEWCONTAINER WHITESPACE TOKCONTAINERMODE + { + LOG("new containers will be in mode %d\n", $3); + config.container_mode = $3; + + /* We also need to change the layout of the already existing + * workspaces here. Workspaces may exist at this point because + * of the other directives which are modifying workspaces + * (setting the preferred screen or name). While the workspace + * objects are already created, they have never been used. + * Thus, the user very likely awaits the default container mode + * to trigger in this case, regardless of where it is inside + * his configuration file. */ + for (int c = 0; c < num_workspaces; c++) { + if (workspaces[c].table == NULL) + continue; + switch_layout_mode(global_conn, + workspaces[c].table[0][0], + config.container_mode); + } + } + | TOKNEWCONTAINER WHITESPACE TOKSTACKLIMIT WHITESPACE TOKSTACKLIMIT WHITESPACE NUMBER + { + LOG("stack-limit %d with val %d\n", $5, $7); + config.container_stack_limit = $5; + config.container_stack_limit_value = $7; + + /* See the comment above */ + for (int c = 0; c < num_workspaces; c++) { + if (workspaces[c].table == NULL) + continue; + Container *con = workspaces[c].table[0][0]; + con->stack_limit = config.container_stack_limit; + con->stack_limit_value = config.container_stack_limit_value; + } + } + ; + workspace: TOKWORKSPACE WHITESPACE NUMBER WHITESPACE TOKSCREEN WHITESPACE screen workspace_name { diff --git a/src/layout.c b/src/layout.c index 7ae3672c..fa18bbc1 100644 --- a/src/layout.c +++ b/src/layout.c @@ -732,6 +732,9 @@ void render_workspace(xcb_connection_t *conn, i3Screen *screen, Workspace *r_ws) void render_layout(xcb_connection_t *conn) { i3Screen *screen; + if (virtual_screens == NULL) + return; + TAILQ_FOREACH(screen, virtual_screens, screens) render_workspace(conn, screen, &(workspaces[screen->current_workspace])); diff --git a/src/mainx.c b/src/mainx.c index 5ed63f17..4f235eca 100644 --- a/src/mainx.c +++ b/src/mainx.c @@ -206,6 +206,14 @@ int main(int argc, char *argv[], char *env[]) { load_configuration(conn, override_configpath, false); + /* Create the initial container on the first workspace. This used to + * be part of init_table, but since it possibly requires an X + * connection and a loaded configuration (default mode for new + * containers may be stacking, which requires a new window to be + * created), it had to be delayed. */ + expand_table_cols(&(workspaces[0])); + expand_table_rows(&(workspaces[0])); + /* Place requests for the atoms we need as soon as possible */ #define REQUEST_ATOM(name) atom_cookies[name] = xcb_intern_atom(conn, 0, strlen(#name), #name); diff --git a/src/table.c b/src/table.c index 6612a5e3..4c5653aa 100644 --- a/src/table.c +++ b/src/table.c @@ -25,6 +25,7 @@ #include "util.h" #include "i3.h" #include "layout.h" +#include "config.h" int current_workspace = 0; int num_workspaces = 1; @@ -45,8 +46,6 @@ void init_table() { workspaces[0].screen = NULL; workspaces[0].num = 0; TAILQ_INIT(&(workspaces[0].floating_clients)); - expand_table_cols(&(workspaces[0])); - expand_table_rows(&(workspaces[0])); } static void new_container(Workspace *workspace, Container **container, int col, int row) { @@ -58,6 +57,9 @@ static void new_container(Workspace *workspace, Container **container, int col, new->col = col; new->row = row; new->workspace = workspace; + switch_layout_mode(global_conn, new, config.container_mode); + new->stack_limit = config.container_stack_limit; + new->stack_limit_value = config.container_stack_limit_value; } /* diff --git a/src/util.c b/src/util.c index 94a5e336..7990b56e 100644 --- a/src/util.c +++ b/src/util.c @@ -352,10 +352,13 @@ void switch_layout_mode(xcb_connection_t *conn, Container *container, int mode) if (container->mode == MODE_STACK || container->mode == MODE_TABBED) goto after_stackwin; - /* When entering stacking mode, we need to open a window on which we can draw the - title bars of the clients, it has height 1 because we don’t bother here with - calculating the correct height - it will be adjusted when rendering anyways. */ - Rect rect = {container->x, container->y, container->width, 1}; + /* When entering stacking mode, we need to open a window on + * which we can draw the title bars of the clients, it has + * height 1 because we don’t bother here with calculating the + * correct height - it will be adjusted when rendering anyways. + * Also, we need to use max(width, 1) because windows cannot + * be created with either width == 0 or height == 0. */ + Rect rect = {container->x, container->y, max(container->width, 1), 1}; uint32_t mask = 0; uint32_t values[2]; diff --git a/src/workspace.c b/src/workspace.c index de630875..94759ceb 100644 --- a/src/workspace.c +++ b/src/workspace.c @@ -66,16 +66,14 @@ Workspace *workspace_get(int number) { LOG("We need to initialize that one\n"); num_workspaces = number+1; workspaces = realloc(workspaces, num_workspaces * sizeof(Workspace)); - for (int c = old_num_workspaces; c < num_workspaces; c++) { + /* Zero out the new workspaces so that we have sane default values */ + for (int c = old_num_workspaces; c < num_workspaces; c++) memset(&workspaces[c], 0, sizeof(Workspace)); - workspaces[c].screen = NULL; - workspaces[c].num = c; - TAILQ_INIT(&(workspaces[c].floating_clients)); - expand_table_cols(&(workspaces[c])); - expand_table_rows(&(workspaces[c])); - workspace_set_name(&(workspaces[c]), NULL); - } + /* Immediately after the realloc(), we restore the pointers. + * They may be used when initializing the new workspaces, for + * example when the user configures containers to be stacking + * by default, thus requiring re-rendering the layout. */ c_ws = workspace_get((int)c_ws); for (int c = 0; c < old_num_workspaces; c++) @@ -94,6 +92,15 @@ Workspace *workspace_get(int number) { } } + /* Initialize the new workspaces */ + for (int c = old_num_workspaces; c < num_workspaces; c++) { + memset(&workspaces[c], 0, sizeof(Workspace)); + workspaces[c].num = c; + TAILQ_INIT(&(workspaces[c].floating_clients)); + expand_table_cols(&(workspaces[c])); + expand_table_rows(&(workspaces[c])); + workspace_set_name(&(workspaces[c]), NULL); + } LOG("done\n"); }