Implement options to change the default mode of containers

The following new directives have been implemented for the configuration
file:

	new_container <default|stacking|tabbed>
	new_container stack-limit <cols|rows> <value>

Note that they require using the new lexer/parser, which you can
do by passing -l to i3 when starting.
This commit is contained in:
Michael Stapelberg 2009-09-27 23:08:27 +02:00
parent fa868ed61c
commit e101940c5e
8 changed files with 92 additions and 14 deletions

View File

@ -17,6 +17,7 @@
#include <stdbool.h> #include <stdbool.h>
#include "queue.h" #include "queue.h"
#include "i3.h"
typedef struct Config Config; typedef struct Config Config;
extern Config config; extern Config config;
@ -71,6 +72,10 @@ struct Config {
const char *ipc_socket_path; 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 /** The modifier which needs to be pressed in combination with your mouse
* buttons to do things with floating windows (move, resize) */ * buttons to do things with floating windows (move, resize) */
uint32_t floating_modifier; uint32_t floating_modifier;

View File

@ -37,6 +37,13 @@ assign { BEGIN(ASSIGN_COND); return TOKASSIGN; }
set[^\n]* { return TOKCOMMENT; } set[^\n]* { return TOKCOMMENT; }
ipc-socket { BEGIN(BIND_AWS_COND); return TOKIPCSOCKET; } ipc-socket { BEGIN(BIND_AWS_COND); return TOKIPCSOCKET; }
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; } exec { BEGIN(BIND_AWS_COND); return TOKEXEC; }
client.focused { BEGIN(COLOR_COND); yylval.color = &config.client.focused; return TOKCOLOR; } 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; } client.focused_inactive { BEGIN(COLOR_COND); yylval.color = &config.client.focused_inactive; return TOKCOLOR; }

View File

@ -189,6 +189,9 @@ void parse_file(const char *f) {
%token TOKCOLOR %token TOKCOLOR
%token TOKARROW %token TOKARROW
%token TOKMODE %token TOKMODE
%token TOKNEWCONTAINER
%token TOKCONTAINERMODE
%token TOKSTACKLIMIT
%% %%
@ -201,6 +204,7 @@ line:
bindline bindline
| mode | mode
| floating_modifier | floating_modifier
| new_container
| workspace | workspace
| assign | assign
| ipcsocket | ipcsocket
@ -309,6 +313,45 @@ floating_modifier:
} }
; ;
new_container:
TOKNEWCONTAINER WHITESPACE TOKCONTAINERMODE
{
LOG("new containers will be in mode %d\n", $<number>3);
config.container_mode = $<number>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", $<number>5, $<number>7);
config.container_stack_limit = $<number>5;
config.container_stack_limit_value = $<number>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: workspace:
TOKWORKSPACE WHITESPACE NUMBER WHITESPACE TOKSCREEN WHITESPACE screen workspace_name TOKWORKSPACE WHITESPACE NUMBER WHITESPACE TOKSCREEN WHITESPACE screen workspace_name
{ {

View File

@ -732,6 +732,9 @@ void render_workspace(xcb_connection_t *conn, i3Screen *screen, Workspace *r_ws)
void render_layout(xcb_connection_t *conn) { void render_layout(xcb_connection_t *conn) {
i3Screen *screen; i3Screen *screen;
if (virtual_screens == NULL)
return;
TAILQ_FOREACH(screen, virtual_screens, screens) TAILQ_FOREACH(screen, virtual_screens, screens)
render_workspace(conn, screen, &(workspaces[screen->current_workspace])); render_workspace(conn, screen, &(workspaces[screen->current_workspace]));

View File

@ -206,6 +206,14 @@ int main(int argc, char *argv[], char *env[]) {
load_configuration(conn, override_configpath, false); 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 */ /* 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); #define REQUEST_ATOM(name) atom_cookies[name] = xcb_intern_atom(conn, 0, strlen(#name), #name);

View File

@ -25,6 +25,7 @@
#include "util.h" #include "util.h"
#include "i3.h" #include "i3.h"
#include "layout.h" #include "layout.h"
#include "config.h"
int current_workspace = 0; int current_workspace = 0;
int num_workspaces = 1; int num_workspaces = 1;
@ -45,8 +46,6 @@ void init_table() {
workspaces[0].screen = NULL; workspaces[0].screen = NULL;
workspaces[0].num = 0; workspaces[0].num = 0;
TAILQ_INIT(&(workspaces[0].floating_clients)); 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) { 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->col = col;
new->row = row; new->row = row;
new->workspace = workspace; 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;
} }
/* /*

View File

@ -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) if (container->mode == MODE_STACK || container->mode == MODE_TABBED)
goto after_stackwin; goto after_stackwin;
/* When entering stacking mode, we need to open a window on which we can draw the /* When entering stacking mode, we need to open a window on
title bars of the clients, it has height 1 because we dont bother here with * which we can draw the title bars of the clients, it has
calculating the correct height - it will be adjusted when rendering anyways. */ * height 1 because we dont bother here with calculating the
Rect rect = {container->x, container->y, container->width, 1}; * 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 mask = 0;
uint32_t values[2]; uint32_t values[2];

View File

@ -66,16 +66,14 @@ Workspace *workspace_get(int number) {
LOG("We need to initialize that one\n"); LOG("We need to initialize that one\n");
num_workspaces = number+1; num_workspaces = number+1;
workspaces = realloc(workspaces, num_workspaces * sizeof(Workspace)); 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)); 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); c_ws = workspace_get((int)c_ws);
for (int c = 0; c < old_num_workspaces; c++) 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"); LOG("done\n");
} }