Refactor workspaces to be stored in a TAILQ instead of an array

This fixes many problems we were having with a dynamically growing
array because of the realloc (pointers inside the area which was
allocated were no longer valid as soon as the realloc moved the
memory to another address).

Again, this is a rather big change, so expect problems and enable
core-dumps.
This commit is contained in:
Michael Stapelberg 2009-09-29 19:45:41 +02:00
parent 5a77081c55
commit 2b70e05ee9
15 changed files with 142 additions and 172 deletions

View File

@ -232,6 +232,8 @@ struct Workspace {
* opened, for example) have the same size as always */ * opened, for example) have the same size as always */
float *width_factor; float *width_factor;
float *height_factor; float *height_factor;
TAILQ_ENTRY(Workspace) workspaces;
}; };
/** /**
@ -492,7 +494,7 @@ struct Screen {
int num; int num;
/** Current workspace selected on this virtual screen */ /** Current workspace selected on this virtual screen */
int current_workspace; Workspace *current_workspace;
/** x, y, width, height */ /** x, y, width, height */
Rect rect; Rect rect;

View File

@ -21,8 +21,8 @@
#define CUR_CELL (CUR_TABLE[current_col][current_row]) #define CUR_CELL (CUR_TABLE[current_col][current_row])
extern Workspace *c_ws; extern Workspace *c_ws;
extern Workspace *workspaces; extern TAILQ_HEAD(workspaces_head, Workspace) *workspaces;
extern int num_workspaces; //extern int num_workspaces;
extern int current_col; extern int current_col;
extern int current_row; extern int current_row;

View File

@ -112,7 +112,7 @@ void parse_file(const char *f) {
/* Then, allocate a new buffer and copy the file over to the new one, /* Then, allocate a new buffer and copy the file over to the new one,
* but replace occurences of our variables */ * but replace occurences of our variables */
char *walk = buf, *destwalk; char *walk = buf, *destwalk;
char *new = smalloc((stbuf.st_size + extra_bytes) * sizeof(char)); char *new = smalloc((stbuf.st_size + extra_bytes + 1) * sizeof(char));
destwalk = new; destwalk = new;
while (walk < (buf + stbuf.st_size)) { while (walk < (buf + stbuf.st_size)) {
/* Find the next variable */ /* Find the next variable */
@ -335,11 +335,12 @@ new_container:
* Thus, the user very likely awaits the default container mode * Thus, the user very likely awaits the default container mode
* to trigger in this case, regardless of where it is inside * to trigger in this case, regardless of where it is inside
* his configuration file. */ * his configuration file. */
for (int c = 0; c < num_workspaces; c++) { Workspace *ws;
if (workspaces[c].table == NULL) TAILQ_FOREACH(ws, workspaces, workspaces) {
if (ws->table == NULL)
continue; continue;
switch_layout_mode(global_conn, switch_layout_mode(global_conn,
workspaces[c].table[0][0], ws->table[0][0],
config.container_mode); config.container_mode);
} }
} }
@ -350,10 +351,11 @@ new_container:
config.container_stack_limit_value = $<number>7; config.container_stack_limit_value = $<number>7;
/* See the comment above */ /* See the comment above */
for (int c = 0; c < num_workspaces; c++) { Workspace *ws;
if (workspaces[c].table == NULL) TAILQ_FOREACH(ws, workspaces, workspaces) {
if (ws->table == NULL)
continue; continue;
Container *con = workspaces[c].table[0][0]; Container *con = ws->table[0][0];
con->stack_limit = config.container_stack_limit; con->stack_limit = config.container_stack_limit;
con->stack_limit_value = config.container_stack_limit_value; con->stack_limit_value = config.container_stack_limit_value;
} }

View File

@ -128,29 +128,40 @@ static bool button_press_bar(xcb_connection_t *conn, xcb_button_press_event_t *e
/* Check if the button was one of button4 or button5 (scroll up / scroll down) */ /* Check if the button was one of button4 or button5 (scroll up / scroll down) */
if (event->detail == XCB_BUTTON_INDEX_4 || event->detail == XCB_BUTTON_INDEX_5) { if (event->detail == XCB_BUTTON_INDEX_4 || event->detail == XCB_BUTTON_INDEX_5) {
int add = (event->detail == XCB_BUTTON_INDEX_4 ? -1 : 1); Workspace *ws = c_ws;
for (int i = c_ws->num + add; (i >= 0) && (i < num_workspaces); i += add) if (event->detail == XCB_BUTTON_INDEX_5) {
if (workspaces[i].screen == screen) { while ((ws = TAILQ_NEXT(ws, workspaces)) != TAILQ_END(workspaces_head)) {
workspace_show(conn, i+1); if (ws->screen == screen) {
workspace_show(conn, ws->num + 1);
return true; return true;
} }
}
} else {
while ((ws = TAILQ_PREV(ws, workspaces_head, workspaces)) != TAILQ_END(workspaces)) {
if (ws->screen == screen) {
workspace_show(conn, ws->num + 1);
return true;
}
}
}
return true; return true;
} }
int drawn = 0; int drawn = 0;
/* Because workspaces can be on different screens, we need to loop /* Because workspaces can be on different screens, we need to loop
through all of them and decide to count it based on its ->screen */ through all of them and decide to count it based on its ->screen */
for (int i = 0; i < num_workspaces; i++) { Workspace *ws;
if (workspaces[i].screen != screen) TAILQ_FOREACH(ws, workspaces, workspaces) {
if (ws->screen != screen)
continue; continue;
LOG("Checking if click was on workspace %d with drawn = %d, tw = %d\n", LOG("Checking if click was on workspace %d with drawn = %d, tw = %d\n",
i, drawn, workspaces[i].text_width); ws->num, drawn, ws->text_width);
if (event->event_x > (drawn + 1) && if (event->event_x > (drawn + 1) &&
event->event_x <= (drawn + 1 + workspaces[i].text_width + 5 + 5)) { event->event_x <= (drawn + 1 + ws->text_width + 5 + 5)) {
workspace_show(conn, i+1); workspace_show(conn, ws->num + 1);
return true; return true;
} }
drawn += workspaces[i].text_width + 5 + 5 + 2; drawn += ws->text_width + 5 + 5 + 2;
} }
return true; return true;
} }

View File

@ -332,8 +332,9 @@ void client_mark(xcb_connection_t *conn, Client *client, const char *mark) {
/* Make sure no other client has this mark set */ /* Make sure no other client has this mark set */
Client *current; Client *current;
for (int c = 0; c < 10; c++) Workspace *ws;
SLIST_FOREACH(current, &(workspaces[c].focus_stack), focus_clients) { TAILQ_FOREACH(ws, workspaces, workspaces)
SLIST_FOREACH(current, &(ws->focus_stack), focus_clients) {
if (current == client || if (current == client ||
current->mark == NULL || current->mark == NULL ||
strcmp(current->mark, mark) != 0) strcmp(current->mark, mark) != 0)

View File

@ -63,8 +63,9 @@ static void jump_to_mark(xcb_connection_t *conn, const char *mark) {
Client *current; Client *current;
LOG("Jumping to \"%s\"\n", mark); LOG("Jumping to \"%s\"\n", mark);
for (int c = 0; c < num_workspaces; c++) Workspace *ws;
SLIST_FOREACH(current, &(workspaces[c].focus_stack), focus_clients) { TAILQ_FOREACH(ws, workspaces, workspaces)
SLIST_FOREACH(current, &(ws->focus_stack), focus_clients) {
if (current->mark == NULL || strcmp(current->mark, mark) != 0) if (current->mark == NULL || strcmp(current->mark, mark) != 0)
continue; continue;
@ -130,7 +131,7 @@ static void focus_thing(xcb_connection_t *conn, direction_t direction, thing_t t
} }
LOG("Switching to ws %d\n", target->current_workspace + 1); LOG("Switching to ws %d\n", target->current_workspace + 1);
workspace_show(conn, target->current_workspace + 1); workspace_show(conn, target->current_workspace->num + 1);
return; return;
} }
@ -165,7 +166,7 @@ static void focus_thing(xcb_connection_t *conn, direction_t direction, thing_t t
/* No screen found? Then wrap */ /* No screen found? Then wrap */
screen = get_screen_most((direction == D_UP ? D_DOWN : D_UP), container->workspace->screen); screen = get_screen_most((direction == D_UP ? D_DOWN : D_UP), container->workspace->screen);
} }
t_ws = workspace_get(screen->current_workspace); t_ws = screen->current_workspace;
new_row = (direction == D_UP ? (t_ws->rows - 1) : 0); new_row = (direction == D_UP ? (t_ws->rows - 1) : 0);
} }
@ -207,7 +208,7 @@ static void focus_thing(xcb_connection_t *conn, direction_t direction, thing_t t
LOG("Wrapping screen around horizontally\n"); LOG("Wrapping screen around horizontally\n");
screen = get_screen_most((direction == D_LEFT ? D_RIGHT : D_LEFT), container->workspace->screen); screen = get_screen_most((direction == D_LEFT ? D_RIGHT : D_LEFT), container->workspace->screen);
} }
t_ws = workspace_get(screen->current_workspace); t_ws = screen->current_workspace;
new_col = (direction == D_LEFT ? (t_ws->cols - 1) : 0); new_col = (direction == D_LEFT ? (t_ws->cols - 1) : 0);
} }
@ -784,31 +785,25 @@ static char **append_argument(char **original, char *argument) {
* *
*/ */
static void next_previous_workspace(xcb_connection_t *conn, int direction) { static void next_previous_workspace(xcb_connection_t *conn, int direction) {
Workspace *t_ws; Workspace *ws = c_ws;
int i;
if (direction == 'n') { if (direction == 'n') {
/* If we are on the last workspace, we cannot go any further */ while ((ws = TAILQ_NEXT(ws, workspaces)) != TAILQ_END(workspaces_head)) {
if (c_ws->num == (num_workspaces-1)) if (ws->screen == NULL)
return; continue;
for (i = c_ws->num + 1; i < num_workspaces; i++) { workspace_show(conn, ws->num + 1);
t_ws = &(workspaces[i]); return;
if (t_ws->screen != NULL)
break;
} }
} else if (direction == 'p') { } else if (direction == 'p') {
if (c_ws->num == 0) while ((ws = TAILQ_PREV(ws, workspaces_head, workspaces)) != TAILQ_END(workspaces)) {
return; if (ws->screen == NULL)
for (i = c_ws->num - 1; i >= 0 ; i--) { continue;
t_ws = &(workspaces[i]);
if (t_ws->screen != NULL)
break;
}
}
if (t_ws->screen != NULL) workspace_show(conn, ws->num + 1);
workspace_show(conn, i+1); return;
}
}
} }
static void parse_resize_command(xcb_connection_t *conn, Client *last_focused, const char *command) { static void parse_resize_command(xcb_connection_t *conn, Client *last_focused, const char *command) {

View File

@ -183,6 +183,7 @@ void load_configuration(xcb_connection_t *conn, const char *override_configpath,
while (!TAILQ_EMPTY(bindings)) { while (!TAILQ_EMPTY(bindings)) {
bind = TAILQ_FIRST(bindings); bind = TAILQ_FIRST(bindings);
TAILQ_REMOVE(bindings, bind, bindings); TAILQ_REMOVE(bindings, bind, bindings);
FREE(bind->translated_to);
FREE(bind->command); FREE(bind->command);
FREE(bind); FREE(bind);
} }
@ -481,7 +482,7 @@ void load_configuration(xcb_connection_t *conn, const char *override_configpath,
LOG("setting name to \"%s\"\n", name); LOG("setting name to \"%s\"\n", name);
if (*name != '\0') if (*name != '\0')
workspace_set_name(&(workspaces[ws_num - 1]), name); workspace_set_name(workspace_get(ws_num - 1), name);
free(ws_str); free(ws_str);
continue; continue;
} }
@ -590,8 +591,8 @@ void load_configuration(xcb_connection_t *conn, const char *override_configpath,
REQUIRED_OPTION(font); REQUIRED_OPTION(font);
/* Set an empty name for every workspace which got no name */ /* Set an empty name for every workspace which got no name */
for (int i = 0; i < num_workspaces; i++) { Workspace *ws;
Workspace *ws = &(workspaces[i]); TAILQ_FOREACH(ws, workspaces, workspaces) {
if (ws->name != NULL) { if (ws->name != NULL) {
/* If the font was not specified when the workspace name /* If the font was not specified when the workspace name
* was loaded, we need to predict the text width now */ * was loaded, we need to predict the text width now */
@ -601,7 +602,7 @@ void load_configuration(xcb_connection_t *conn, const char *override_configpath,
continue; continue;
} }
workspace_set_name(&(workspaces[i]), NULL); workspace_set_name(ws, NULL);
} }
return; return;

View File

@ -170,7 +170,7 @@ static void check_crossing_screen_boundary(uint32_t x, uint32_t y) {
c_ws->current_row = current_row; c_ws->current_row = current_row;
c_ws->current_col = current_col; c_ws->current_col = current_col;
c_ws = &workspaces[screen->current_workspace]; c_ws = screen->current_workspace;
current_row = c_ws->current_row; current_row = c_ws->current_row;
current_col = c_ws->current_col; current_col = c_ws->current_col;
LOG("We're now on virtual screen number %d\n", screen->num); LOG("We're now on virtual screen number %d\n", screen->num);
@ -486,7 +486,7 @@ int handle_unmap_notify_event(void *data, xcb_connection_t *conn, xcb_unmap_noti
/* If this workspace is currently active, we dont delete it */ /* If this workspace is currently active, we dont delete it */
i3Screen *screen; i3Screen *screen;
TAILQ_FOREACH(screen, virtual_screens, screens) TAILQ_FOREACH(screen, virtual_screens, screens)
if (screen->current_workspace == client->workspace->num) { if (screen->current_workspace == client->workspace) {
workspace_active = true; workspace_active = true;
workspace_empty = false; workspace_empty = false;
break; break;
@ -908,7 +908,7 @@ int handle_hints(void *data, xcb_connection_t *conn, uint8_t state, xcb_window_t
* the workspace bar */ * the workspace bar */
if (!workspace_is_visible(client->workspace)) { if (!workspace_is_visible(client->workspace)) {
i3Screen *screen = client->workspace->screen; i3Screen *screen = client->workspace->screen;
render_workspace(conn, screen, &(workspaces[screen->current_workspace])); render_workspace(conn, screen, screen->current_workspace);
xcb_flush(conn); xcb_flush(conn);
} }

View File

@ -238,7 +238,7 @@ void reposition_client(xcb_connection_t *conn, Client *client) {
LOG("Client is on workspace %p with screen %p\n", client->workspace, client->workspace->screen); LOG("Client is on workspace %p with screen %p\n", client->workspace, client->workspace->screen);
LOG("but screen at %d, %d is %p\n", client->rect.x, client->rect.y, screen); LOG("but screen at %d, %d is %p\n", client->rect.x, client->rect.y, screen);
floating_assign_to_workspace(client, workspace_get(screen->current_workspace)); floating_assign_to_workspace(client, screen->current_workspace);
} }
/* /*
@ -586,14 +586,14 @@ static void render_internal_bar(xcb_connection_t *conn, Workspace *r_ws, int wid
xcb_change_gc_single(conn, screen->bargc, XCB_GC_FONT, font->id); xcb_change_gc_single(conn, screen->bargc, XCB_GC_FONT, font->id);
int drawn = 0; int drawn = 0;
for (int c = 0; c < num_workspaces; c++) { Workspace *ws;
if (workspaces[c].screen != screen) TAILQ_FOREACH(ws, workspaces, workspaces) {
if (ws->screen != screen)
continue; continue;
struct Colortriple *color; struct Colortriple *color;
Workspace *ws = &workspaces[c];
if (screen->current_workspace == c) if (screen->current_workspace == ws)
color = &(config.bar.focused); color = &(config.bar.focused);
else if (ws->urgent) else if (ws->urgent)
color = &(config.bar.urgent); color = &(config.bar.urgent);
@ -742,7 +742,8 @@ void render_layout(xcb_connection_t *conn) {
return; return;
TAILQ_FOREACH(screen, virtual_screens, screens) TAILQ_FOREACH(screen, virtual_screens, screens)
render_workspace(conn, screen, &(workspaces[screen->current_workspace])); if (screen->current_workspace != NULL)
render_workspace(conn, screen, screen->current_workspace);
xcb_flush(conn); xcb_flush(conn);
} }

View File

@ -211,8 +211,8 @@ int main(int argc, char *argv[], char *env[]) {
* connection and a loaded configuration (default mode for new * connection and a loaded configuration (default mode for new
* containers may be stacking, which requires a new window to be * containers may be stacking, which requires a new window to be
* created), it had to be delayed. */ * created), it had to be delayed. */
expand_table_cols(&(workspaces[0])); expand_table_cols(TAILQ_FIRST(workspaces));
expand_table_rows(&(workspaces[0])); expand_table_rows(TAILQ_FIRST(workspaces));
/* 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);
@ -456,7 +456,7 @@ int main(int argc, char *argv[], char *env[]) {
} }
LOG("Starting on %d\n", screen->current_workspace); LOG("Starting on %d\n", screen->current_workspace);
c_ws = &workspaces[screen->current_workspace]; c_ws = screen->current_workspace;
manage_existing_windows(conn, &prophs, root); manage_existing_windows(conn, &prophs, root);

View File

@ -329,7 +329,7 @@ void reparent_window(xcb_connection_t *conn, xcb_window_t child,
LOG("Assignment \"%s\" matches, so putting it on workspace %d\n", LOG("Assignment \"%s\" matches, so putting it on workspace %d\n",
assign->windowclass_title, assign->workspace); assign->windowclass_title, assign->workspace);
if (c_ws->screen->current_workspace == (assign->workspace-1)) { if (c_ws->screen->current_workspace->num == (assign->workspace-1)) {
LOG("We are already there, no need to do anything\n"); LOG("We are already there, no need to do anything\n");
break; break;
} }

View File

@ -26,10 +26,11 @@
#include "i3.h" #include "i3.h"
#include "layout.h" #include "layout.h"
#include "config.h" #include "config.h"
#include "workspace.h"
int current_workspace = 0; int current_workspace = 0;
int num_workspaces = 1; int num_workspaces = 1;
Workspace *workspaces; struct workspaces_head *workspaces;
/* Convenience pointer to the current workspace */ /* Convenience pointer to the current workspace */
Workspace *c_ws; Workspace *c_ws;
int current_col = 0; int current_col = 0;
@ -40,12 +41,13 @@ int current_row = 0;
* *
*/ */
void init_table() { void init_table() {
workspaces = scalloc(sizeof(Workspace)); workspaces = scalloc(sizeof(struct workspaces_head));
c_ws = workspaces; TAILQ_INIT(workspaces);
workspaces[0].screen = NULL; c_ws = scalloc(sizeof(Workspace));
workspaces[0].num = 0; workspace_set_name(c_ws, NULL);
TAILQ_INIT(&(workspaces[0].floating_clients)); TAILQ_INIT(&(c_ws->floating_clients));
TAILQ_INSERT_TAIL(workspaces, c_ws, workspaces);
} }
static void new_container(Workspace *workspace, Container **container, int col, int row) { static void new_container(Workspace *workspace, Container **container, int col, int row) {

View File

@ -458,12 +458,13 @@ Client *get_matching_client(xcb_connection_t *conn, const char *window_classtitl
} }
LOG("Getting clients for class \"%s\" / title \"%s\"\n", to_class, to_title); LOG("Getting clients for class \"%s\" / title \"%s\"\n", to_class, to_title);
for (int workspace = 0; workspace < num_workspaces; workspace++) { Workspace *ws;
if (workspaces[workspace].screen == NULL) TAILQ_FOREACH(ws, workspaces, workspaces) {
if (ws->screen == NULL)
continue; continue;
Client *client; Client *client;
SLIST_FOREACH(client, &(workspaces[workspace].focus_stack), focus_clients) { SLIST_FOREACH(client, &(ws->focus_stack), focus_clients) {
LOG("Checking client with class=%s, name=%s\n", client->window_class, client->name); LOG("Checking client with class=%s, name=%s\n", client->window_class, client->name);
if (!client_matches_class_name(client, to_class, to_title, to_title_ucs, to_title_ucs_len)) if (!client_matches_class_name(client, to_class, to_title, to_title_ucs, to_title_ucs_len))
continue; continue;

View File

@ -34,80 +34,31 @@
* *
*/ */
Workspace *workspace_get(int number) { Workspace *workspace_get(int number) {
if (number > (num_workspaces-1)) { Workspace *ws;
int old_num_workspaces = num_workspaces; TAILQ_FOREACH(ws, workspaces, workspaces)
if (ws->num == number)
return ws;
/* Convert all container->workspace and client->workspace /* If we are still there, we could not find the requested workspace. */
* pointers to numbers representing their workspace. Necessary int last_ws = TAILQ_LAST(workspaces, workspaces_head)->num;
* because the realloc() may make all the pointers invalid, so
* we need to preserve them this way and restore them later.
*
* To distinguish between the first workspace and a NULL
* pointer, we store <workspace number> + 1. */
for (int c = 0; c < num_workspaces; c++) {
FOR_TABLE(&(workspaces[c])) {
Container *con = workspaces[c].table[cols][rows];
if (con->workspace != NULL) {
LOG("Handling con %p with pointer %p (num %d)\n", con, con->workspace, con->workspace->num);
con->workspace = (Workspace*)(con->workspace->num + 1);
}
}
Client *current;
SLIST_FOREACH(current, &(workspaces[c].focus_stack), focus_clients) {
if (current->workspace == NULL)
continue;
LOG("Handling client %p with pointer %p (num %d)\n", current, current->workspace, current->workspace->num);
current->workspace = (Workspace*)(current->workspace->num + 1);
}
}
/* preserve c_ws */ LOG("We need to initialize that one, last ws = %d\n", last_ws);
c_ws = (Workspace*)(c_ws->num);
LOG("We need to initialize that one\n"); for (int c = last_ws; c < number; c++) {
num_workspaces = number+1; LOG("Creating new ws\n");
workspaces = realloc(workspaces, num_workspaces * sizeof(Workspace));
/* 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));
/* Immediately after the realloc(), we restore the pointers. ws = scalloc(sizeof(Workspace));
* They may be used when initializing the new workspaces, for ws->num = number;
* example when the user configures containers to be stacking TAILQ_INIT(&(ws->floating_clients));
* by default, thus requiring re-rendering the layout. */ expand_table_cols(ws);
c_ws = workspace_get((int)c_ws); expand_table_rows(ws);
workspace_set_name(ws, NULL);
for (int c = 0; c < old_num_workspaces; c++) { TAILQ_INSERT_TAIL(workspaces, ws, workspaces);
FOR_TABLE(&(workspaces[c])) {
Container *con = workspaces[c].table[cols][rows];
if (con->workspace != NULL) {
LOG("Handling con %p with (num %d)\n", con, con->workspace);
con->workspace = workspace_get((int)con->workspace - 1);
} }
}
Client *current;
SLIST_FOREACH(current, &(workspaces[c].focus_stack), focus_clients) {
if (current->workspace == NULL)
continue;
LOG("Handling client %p with (num %d)\n", current, current->workspace);
current->workspace = workspace_get((int)current->workspace - 1);
}
}
/* 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");
}
return &(workspaces[number]); return ws;
} }
/* /*
@ -145,7 +96,7 @@ void workspace_set_name(Workspace *ws, const char *name) {
* *
*/ */
bool workspace_is_visible(Workspace *ws) { bool workspace_is_visible(Workspace *ws) {
return (ws->screen->current_workspace == ws->num); return (ws->screen->current_workspace == ws);
} }
/* /*
@ -174,7 +125,7 @@ void workspace_show(xcb_connection_t *conn, int workspace) {
/* Store the old client */ /* Store the old client */
Client *old_client = CUR_CELL->currently_focused; Client *old_client = CUR_CELL->currently_focused;
c_ws = workspace_get(t_ws->screen->current_workspace); c_ws = t_ws->screen->current_workspace;
current_col = c_ws->current_col; current_col = c_ws->current_col;
current_row = c_ws->current_row; current_row = c_ws->current_row;
if (CUR_CELL->currently_focused != NULL) if (CUR_CELL->currently_focused != NULL)
@ -192,7 +143,7 @@ void workspace_show(xcb_connection_t *conn, int workspace) {
} }
/* Check if we need to change something or if were already there */ /* Check if we need to change something or if were already there */
if (c_ws->screen->current_workspace == (workspace-1)) { if (c_ws->screen->current_workspace->num == (workspace-1)) {
Client *last_focused = SLIST_FIRST(&(c_ws->focus_stack)); Client *last_focused = SLIST_FIRST(&(c_ws->focus_stack));
if (last_focused != SLIST_END(&(c_ws->focus_stack))) if (last_focused != SLIST_END(&(c_ws->focus_stack)))
set_focus(conn, last_focused, true); set_focus(conn, last_focused, true);
@ -204,9 +155,8 @@ void workspace_show(xcb_connection_t *conn, int workspace) {
return; return;
} }
t_ws->screen->current_workspace = workspace-1;
Workspace *old_workspace = c_ws; Workspace *old_workspace = c_ws;
c_ws = workspace_get(workspace-1); c_ws = t_ws->screen->current_workspace = workspace_get(workspace-1);
/* Unmap all clients of the old workspace */ /* Unmap all clients of the old workspace */
workspace_unmap_clients(conn, old_workspace); workspace_unmap_clients(conn, old_workspace);
@ -325,8 +275,8 @@ void workspace_initialize(Workspace *ws, i3Screen *screen) {
Workspace *get_first_workspace_for_screen(struct screens_head *slist, i3Screen *screen) { Workspace *get_first_workspace_for_screen(struct screens_head *slist, i3Screen *screen) {
Workspace *result = NULL; Workspace *result = NULL;
for (int c = 0; c < num_workspaces; c++) { Workspace *ws;
Workspace *ws = workspace_get(c); TAILQ_FOREACH(ws, workspaces, workspaces) {
if (ws->preferred_screen == NULL || if (ws->preferred_screen == NULL ||
!screens_are_equal(get_screen_from_preference(slist, ws->preferred_screen), screen)) !screens_are_equal(get_screen_from_preference(slist, ws->preferred_screen), screen))
continue; continue;
@ -337,11 +287,12 @@ Workspace *get_first_workspace_for_screen(struct screens_head *slist, i3Screen *
if (result == NULL) { if (result == NULL) {
/* No assignment found, returning first unused workspace */ /* No assignment found, returning first unused workspace */
for (int c = 0; c < num_workspaces; c++) { Workspace *ws;
if (workspaces[c].screen != NULL) TAILQ_FOREACH(ws, workspaces, workspaces) {
if (ws->screen != NULL)
continue; continue;
result = workspace_get(c); result = ws;
break; break;
} }
} }
@ -349,7 +300,11 @@ Workspace *get_first_workspace_for_screen(struct screens_head *slist, i3Screen *
if (result == NULL) { if (result == NULL) {
LOG("No existing free workspace found to assign, creating a new one\n"); LOG("No existing free workspace found to assign, creating a new one\n");
result = workspace_get(num_workspaces); Workspace *ws;
int last_ws = 0;
TAILQ_FOREACH(ws, workspaces, workspaces)
last_ws = ws->num;
result = workspace_get(last_ws + 1);
} }
workspace_initialize(result, screen); workspace_initialize(result, screen);

View File

@ -133,7 +133,7 @@ static void initialize_screen(xcb_connection_t *conn, i3Screen *screen, Workspac
i3Font *font = load_font(conn, config.font); i3Font *font = load_font(conn, config.font);
workspace->screen = screen; workspace->screen = screen;
screen->current_workspace = workspace->num; screen->current_workspace = workspace;
/* Create a bar for each screen */ /* Create a bar for each screen */
Rect bar_rect = {screen->rect.x, Rect bar_rect = {screen->rect.x,
@ -298,12 +298,13 @@ void xinerama_requery_screens(xcb_connection_t *conn) {
int screen_count = 0; int screen_count = 0;
/* Mark each workspace which currently is assigned to a screen, so we /* Mark each workspace which currently is assigned to a screen, so we
* can garbage-collect afterwards */ * can garbage-collect afterwards */
for (int c = 0; c < num_workspaces; c++) Workspace *ws;
workspaces[c].reassigned = (workspaces[c].screen == NULL); TAILQ_FOREACH(ws, workspaces, workspaces)
ws->reassigned = (ws->screen == NULL);
TAILQ_FOREACH(screen, new_screens, screens) { TAILQ_FOREACH(screen, new_screens, screens) {
screen->num = screen_count; screen->num = screen_count;
screen->current_workspace = -1; screen->current_workspace = NULL;
TAILQ_FOREACH(old_screen, virtual_screens, screens) { TAILQ_FOREACH(old_screen, virtual_screens, screens) {
if (old_screen->num != screen_count) if (old_screen->num != screen_count)
@ -334,8 +335,8 @@ void xinerama_requery_screens(xcb_connection_t *conn) {
screen->dock_clients = old_screen->dock_clients; screen->dock_clients = old_screen->dock_clients;
/* Update the dimensions */ /* Update the dimensions */
for (int c = 0; c < num_workspaces; c++) { Workspace *ws;
Workspace *ws = &(workspaces[c]); TAILQ_FOREACH(ws, workspaces, workspaces) {
if (ws->screen != old_screen) if (ws->screen != old_screen)
continue; continue;
@ -347,7 +348,7 @@ void xinerama_requery_screens(xcb_connection_t *conn) {
break; break;
} }
if (screen->current_workspace == -1) { if (screen->current_workspace == NULL) {
/* Find the first unused workspace, preferring the ones /* Find the first unused workspace, preferring the ones
* which are assigned to this screen and initialize * which are assigned to this screen and initialize
* the screen with it. */ * the screen with it. */
@ -364,38 +365,36 @@ void xinerama_requery_screens(xcb_connection_t *conn) {
} }
/* Check for workspaces which are out of bounds */ /* Check for workspaces which are out of bounds */
for (int c = 0; c < num_workspaces; c++) { TAILQ_FOREACH(ws, workspaces, workspaces) {
if (workspaces[c].reassigned) if (ws->reassigned)
continue; continue;
/* f_ws is a shortcut to the workspace to fix */
Workspace *f_ws = &(workspaces[c]);
Client *client; Client *client;
LOG("Closing bar window (%p)\n", f_ws->screen->bar); LOG("Closing bar window (%p)\n", ws->screen->bar);
xcb_destroy_window(conn, f_ws->screen->bar); xcb_destroy_window(conn, ws->screen->bar);
LOG("Workspace %d's screen out of bounds, assigning to first screen\n", c+1); LOG("Workspace %d's screen out of bounds, assigning to first screen\n", ws->num + 1);
f_ws->screen = first; ws->screen = first;
memcpy(&(f_ws->rect), &(first->rect), sizeof(Rect)); memcpy(&(ws->rect), &(first->rect), sizeof(Rect));
/* Force reconfiguration for each client on that workspace */ /* Force reconfiguration for each client on that workspace */
FOR_TABLE(f_ws) FOR_TABLE(ws)
CIRCLEQ_FOREACH(client, &(f_ws->table[cols][rows]->clients), clients) CIRCLEQ_FOREACH(client, &(ws->table[cols][rows]->clients), clients)
client->force_reconfigure = true; client->force_reconfigure = true;
/* Render the workspace to reconfigure the clients. However, they will be visible now, so… */ /* Render the workspace to reconfigure the clients. However, they will be visible now, so… */
render_workspace(conn, first, f_ws); render_workspace(conn, first, ws);
/* …unless we want to see them at the moment, we should hide that workspace */ /* …unless we want to see them at the moment, we should hide that workspace */
if (workspace_is_visible(f_ws)) if (workspace_is_visible(ws))
continue; continue;
workspace_unmap_clients(conn, f_ws); workspace_unmap_clients(conn, ws);
if (c_ws == f_ws) { if (c_ws == ws) {
LOG("Need to adjust c_ws...\n"); LOG("Need to adjust c_ws...\n");
c_ws = &(workspaces[first->current_workspace]); c_ws = first->current_workspace;
} }
} }
xcb_flush(conn); xcb_flush(conn);