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:
parent
5a77081c55
commit
2b70e05ee9
|
@ -232,6 +232,8 @@ struct Workspace {
|
|||
* opened, for example) have the same size as always */
|
||||
float *width_factor;
|
||||
float *height_factor;
|
||||
|
||||
TAILQ_ENTRY(Workspace) workspaces;
|
||||
};
|
||||
|
||||
/**
|
||||
|
@ -492,7 +494,7 @@ struct Screen {
|
|||
int num;
|
||||
|
||||
/** Current workspace selected on this virtual screen */
|
||||
int current_workspace;
|
||||
Workspace *current_workspace;
|
||||
|
||||
/** x, y, width, height */
|
||||
Rect rect;
|
||||
|
|
|
@ -21,8 +21,8 @@
|
|||
#define CUR_CELL (CUR_TABLE[current_col][current_row])
|
||||
|
||||
extern Workspace *c_ws;
|
||||
extern Workspace *workspaces;
|
||||
extern int num_workspaces;
|
||||
extern TAILQ_HEAD(workspaces_head, Workspace) *workspaces;
|
||||
//extern int num_workspaces;
|
||||
extern int current_col;
|
||||
extern int current_row;
|
||||
|
||||
|
|
|
@ -112,7 +112,7 @@ void parse_file(const char *f) {
|
|||
/* Then, allocate a new buffer and copy the file over to the new one,
|
||||
* but replace occurences of our variables */
|
||||
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;
|
||||
while (walk < (buf + stbuf.st_size)) {
|
||||
/* Find the next variable */
|
||||
|
@ -335,11 +335,12 @@ new_container:
|
|||
* 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)
|
||||
Workspace *ws;
|
||||
TAILQ_FOREACH(ws, workspaces, workspaces) {
|
||||
if (ws->table == NULL)
|
||||
continue;
|
||||
switch_layout_mode(global_conn,
|
||||
workspaces[c].table[0][0],
|
||||
ws->table[0][0],
|
||||
config.container_mode);
|
||||
}
|
||||
}
|
||||
|
@ -350,10 +351,11 @@ new_container:
|
|||
config.container_stack_limit_value = $<number>7;
|
||||
|
||||
/* See the comment above */
|
||||
for (int c = 0; c < num_workspaces; c++) {
|
||||
if (workspaces[c].table == NULL)
|
||||
Workspace *ws;
|
||||
TAILQ_FOREACH(ws, workspaces, workspaces) {
|
||||
if (ws->table == NULL)
|
||||
continue;
|
||||
Container *con = workspaces[c].table[0][0];
|
||||
Container *con = ws->table[0][0];
|
||||
con->stack_limit = config.container_stack_limit;
|
||||
con->stack_limit_value = config.container_stack_limit_value;
|
||||
}
|
||||
|
|
31
src/click.c
31
src/click.c
|
@ -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) */
|
||||
if (event->detail == XCB_BUTTON_INDEX_4 || event->detail == XCB_BUTTON_INDEX_5) {
|
||||
int add = (event->detail == XCB_BUTTON_INDEX_4 ? -1 : 1);
|
||||
for (int i = c_ws->num + add; (i >= 0) && (i < num_workspaces); i += add)
|
||||
if (workspaces[i].screen == screen) {
|
||||
workspace_show(conn, i+1);
|
||||
Workspace *ws = c_ws;
|
||||
if (event->detail == XCB_BUTTON_INDEX_5) {
|
||||
while ((ws = TAILQ_NEXT(ws, workspaces)) != TAILQ_END(workspaces_head)) {
|
||||
if (ws->screen == screen) {
|
||||
workspace_show(conn, ws->num + 1);
|
||||
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;
|
||||
}
|
||||
int drawn = 0;
|
||||
/* Because workspaces can be on different screens, we need to loop
|
||||
through all of them and decide to count it based on its ->screen */
|
||||
for (int i = 0; i < num_workspaces; i++) {
|
||||
if (workspaces[i].screen != screen)
|
||||
Workspace *ws;
|
||||
TAILQ_FOREACH(ws, workspaces, workspaces) {
|
||||
if (ws->screen != screen)
|
||||
continue;
|
||||
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) &&
|
||||
event->event_x <= (drawn + 1 + workspaces[i].text_width + 5 + 5)) {
|
||||
workspace_show(conn, i+1);
|
||||
event->event_x <= (drawn + 1 + ws->text_width + 5 + 5)) {
|
||||
workspace_show(conn, ws->num + 1);
|
||||
return true;
|
||||
}
|
||||
|
||||
drawn += workspaces[i].text_width + 5 + 5 + 2;
|
||||
drawn += ws->text_width + 5 + 5 + 2;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
|
|
@ -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 */
|
||||
Client *current;
|
||||
for (int c = 0; c < 10; c++)
|
||||
SLIST_FOREACH(current, &(workspaces[c].focus_stack), focus_clients) {
|
||||
Workspace *ws;
|
||||
TAILQ_FOREACH(ws, workspaces, workspaces)
|
||||
SLIST_FOREACH(current, &(ws->focus_stack), focus_clients) {
|
||||
if (current == client ||
|
||||
current->mark == NULL ||
|
||||
strcmp(current->mark, mark) != 0)
|
||||
|
|
|
@ -63,8 +63,9 @@ static void jump_to_mark(xcb_connection_t *conn, const char *mark) {
|
|||
Client *current;
|
||||
LOG("Jumping to \"%s\"\n", mark);
|
||||
|
||||
for (int c = 0; c < num_workspaces; c++)
|
||||
SLIST_FOREACH(current, &(workspaces[c].focus_stack), focus_clients) {
|
||||
Workspace *ws;
|
||||
TAILQ_FOREACH(ws, workspaces, workspaces)
|
||||
SLIST_FOREACH(current, &(ws->focus_stack), focus_clients) {
|
||||
if (current->mark == NULL || strcmp(current->mark, mark) != 0)
|
||||
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);
|
||||
workspace_show(conn, target->current_workspace + 1);
|
||||
workspace_show(conn, target->current_workspace->num + 1);
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -165,7 +166,7 @@ static void focus_thing(xcb_connection_t *conn, direction_t direction, thing_t t
|
|||
/* No screen found? Then wrap */
|
||||
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);
|
||||
}
|
||||
|
||||
|
@ -207,7 +208,7 @@ static void focus_thing(xcb_connection_t *conn, direction_t direction, thing_t t
|
|||
LOG("Wrapping screen around horizontally\n");
|
||||
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);
|
||||
}
|
||||
|
||||
|
@ -784,31 +785,25 @@ static char **append_argument(char **original, char *argument) {
|
|||
*
|
||||
*/
|
||||
static void next_previous_workspace(xcb_connection_t *conn, int direction) {
|
||||
Workspace *t_ws;
|
||||
int i;
|
||||
Workspace *ws = c_ws;
|
||||
|
||||
if (direction == 'n') {
|
||||
/* If we are on the last workspace, we cannot go any further */
|
||||
if (c_ws->num == (num_workspaces-1))
|
||||
return;
|
||||
while ((ws = TAILQ_NEXT(ws, workspaces)) != TAILQ_END(workspaces_head)) {
|
||||
if (ws->screen == NULL)
|
||||
continue;
|
||||
|
||||
for (i = c_ws->num + 1; i < num_workspaces; i++) {
|
||||
t_ws = &(workspaces[i]);
|
||||
if (t_ws->screen != NULL)
|
||||
break;
|
||||
workspace_show(conn, ws->num + 1);
|
||||
return;
|
||||
}
|
||||
} else if (direction == 'p') {
|
||||
if (c_ws->num == 0)
|
||||
return;
|
||||
for (i = c_ws->num - 1; i >= 0 ; i--) {
|
||||
t_ws = &(workspaces[i]);
|
||||
if (t_ws->screen != NULL)
|
||||
break;
|
||||
}
|
||||
}
|
||||
while ((ws = TAILQ_PREV(ws, workspaces_head, workspaces)) != TAILQ_END(workspaces)) {
|
||||
if (ws->screen == NULL)
|
||||
continue;
|
||||
|
||||
if (t_ws->screen != NULL)
|
||||
workspace_show(conn, i+1);
|
||||
workspace_show(conn, ws->num + 1);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void parse_resize_command(xcb_connection_t *conn, Client *last_focused, const char *command) {
|
||||
|
|
|
@ -183,6 +183,7 @@ void load_configuration(xcb_connection_t *conn, const char *override_configpath,
|
|||
while (!TAILQ_EMPTY(bindings)) {
|
||||
bind = TAILQ_FIRST(bindings);
|
||||
TAILQ_REMOVE(bindings, bind, bindings);
|
||||
FREE(bind->translated_to);
|
||||
FREE(bind->command);
|
||||
FREE(bind);
|
||||
}
|
||||
|
@ -481,7 +482,7 @@ void load_configuration(xcb_connection_t *conn, const char *override_configpath,
|
|||
LOG("setting name to \"%s\"\n", name);
|
||||
|
||||
if (*name != '\0')
|
||||
workspace_set_name(&(workspaces[ws_num - 1]), name);
|
||||
workspace_set_name(workspace_get(ws_num - 1), name);
|
||||
free(ws_str);
|
||||
continue;
|
||||
}
|
||||
|
@ -590,8 +591,8 @@ void load_configuration(xcb_connection_t *conn, const char *override_configpath,
|
|||
REQUIRED_OPTION(font);
|
||||
|
||||
/* Set an empty name for every workspace which got no name */
|
||||
for (int i = 0; i < num_workspaces; i++) {
|
||||
Workspace *ws = &(workspaces[i]);
|
||||
Workspace *ws;
|
||||
TAILQ_FOREACH(ws, workspaces, workspaces) {
|
||||
if (ws->name != NULL) {
|
||||
/* If the font was not specified when the workspace name
|
||||
* 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;
|
||||
}
|
||||
|
||||
workspace_set_name(&(workspaces[i]), NULL);
|
||||
workspace_set_name(ws, NULL);
|
||||
}
|
||||
|
||||
return;
|
||||
|
|
|
@ -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_col = current_col;
|
||||
c_ws = &workspaces[screen->current_workspace];
|
||||
c_ws = screen->current_workspace;
|
||||
current_row = c_ws->current_row;
|
||||
current_col = c_ws->current_col;
|
||||
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 don’t delete it */
|
||||
i3Screen *screen;
|
||||
TAILQ_FOREACH(screen, virtual_screens, screens)
|
||||
if (screen->current_workspace == client->workspace->num) {
|
||||
if (screen->current_workspace == client->workspace) {
|
||||
workspace_active = true;
|
||||
workspace_empty = false;
|
||||
break;
|
||||
|
@ -908,7 +908,7 @@ int handle_hints(void *data, xcb_connection_t *conn, uint8_t state, xcb_window_t
|
|||
* the workspace bar */
|
||||
if (!workspace_is_visible(client->workspace)) {
|
||||
i3Screen *screen = client->workspace->screen;
|
||||
render_workspace(conn, screen, &(workspaces[screen->current_workspace]));
|
||||
render_workspace(conn, screen, screen->current_workspace);
|
||||
xcb_flush(conn);
|
||||
}
|
||||
|
||||
|
|
13
src/layout.c
13
src/layout.c
|
@ -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("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);
|
||||
|
||||
int drawn = 0;
|
||||
for (int c = 0; c < num_workspaces; c++) {
|
||||
if (workspaces[c].screen != screen)
|
||||
Workspace *ws;
|
||||
TAILQ_FOREACH(ws, workspaces, workspaces) {
|
||||
if (ws->screen != screen)
|
||||
continue;
|
||||
|
||||
struct Colortriple *color;
|
||||
Workspace *ws = &workspaces[c];
|
||||
|
||||
if (screen->current_workspace == c)
|
||||
if (screen->current_workspace == ws)
|
||||
color = &(config.bar.focused);
|
||||
else if (ws->urgent)
|
||||
color = &(config.bar.urgent);
|
||||
|
@ -742,7 +742,8 @@ void render_layout(xcb_connection_t *conn) {
|
|||
return;
|
||||
|
||||
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);
|
||||
}
|
||||
|
|
|
@ -211,8 +211,8 @@ int main(int argc, char *argv[], char *env[]) {
|
|||
* 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]));
|
||||
expand_table_cols(TAILQ_FIRST(workspaces));
|
||||
expand_table_rows(TAILQ_FIRST(workspaces));
|
||||
|
||||
/* 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);
|
||||
|
@ -456,7 +456,7 @@ int main(int argc, char *argv[], char *env[]) {
|
|||
}
|
||||
|
||||
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);
|
||||
|
||||
|
|
|
@ -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",
|
||||
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");
|
||||
break;
|
||||
}
|
||||
|
|
14
src/table.c
14
src/table.c
|
@ -26,10 +26,11 @@
|
|||
#include "i3.h"
|
||||
#include "layout.h"
|
||||
#include "config.h"
|
||||
#include "workspace.h"
|
||||
|
||||
int current_workspace = 0;
|
||||
int num_workspaces = 1;
|
||||
Workspace *workspaces;
|
||||
struct workspaces_head *workspaces;
|
||||
/* Convenience pointer to the current workspace */
|
||||
Workspace *c_ws;
|
||||
int current_col = 0;
|
||||
|
@ -40,12 +41,13 @@ int current_row = 0;
|
|||
*
|
||||
*/
|
||||
void init_table() {
|
||||
workspaces = scalloc(sizeof(Workspace));
|
||||
c_ws = workspaces;
|
||||
workspaces = scalloc(sizeof(struct workspaces_head));
|
||||
TAILQ_INIT(workspaces);
|
||||
|
||||
workspaces[0].screen = NULL;
|
||||
workspaces[0].num = 0;
|
||||
TAILQ_INIT(&(workspaces[0].floating_clients));
|
||||
c_ws = scalloc(sizeof(Workspace));
|
||||
workspace_set_name(c_ws, NULL);
|
||||
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) {
|
||||
|
|
|
@ -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);
|
||||
for (int workspace = 0; workspace < num_workspaces; workspace++) {
|
||||
if (workspaces[workspace].screen == NULL)
|
||||
Workspace *ws;
|
||||
TAILQ_FOREACH(ws, workspaces, workspaces) {
|
||||
if (ws->screen == NULL)
|
||||
continue;
|
||||
|
||||
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);
|
||||
if (!client_matches_class_name(client, to_class, to_title, to_title_ucs, to_title_ucs_len))
|
||||
continue;
|
||||
|
|
109
src/workspace.c
109
src/workspace.c
|
@ -34,80 +34,31 @@
|
|||
*
|
||||
*/
|
||||
Workspace *workspace_get(int number) {
|
||||
if (number > (num_workspaces-1)) {
|
||||
int old_num_workspaces = num_workspaces;
|
||||
Workspace *ws;
|
||||
TAILQ_FOREACH(ws, workspaces, workspaces)
|
||||
if (ws->num == number)
|
||||
return ws;
|
||||
|
||||
/* Convert all container->workspace and client->workspace
|
||||
* pointers to numbers representing their workspace. Necessary
|
||||
* 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);
|
||||
}
|
||||
}
|
||||
/* If we are still there, we could not find the requested workspace. */
|
||||
int last_ws = TAILQ_LAST(workspaces, workspaces_head)->num;
|
||||
|
||||
/* preserve c_ws */
|
||||
c_ws = (Workspace*)(c_ws->num);
|
||||
LOG("We need to initialize that one, last ws = %d\n", last_ws);
|
||||
|
||||
LOG("We need to initialize that one\n");
|
||||
num_workspaces = number+1;
|
||||
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));
|
||||
for (int c = last_ws; c < number; c++) {
|
||||
LOG("Creating new ws\n");
|
||||
|
||||
/* 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);
|
||||
ws = scalloc(sizeof(Workspace));
|
||||
ws->num = number;
|
||||
TAILQ_INIT(&(ws->floating_clients));
|
||||
expand_table_cols(ws);
|
||||
expand_table_rows(ws);
|
||||
workspace_set_name(ws, NULL);
|
||||
|
||||
for (int c = 0; c < old_num_workspaces; c++) {
|
||||
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);
|
||||
TAILQ_INSERT_TAIL(workspaces, ws, workspaces);
|
||||
}
|
||||
}
|
||||
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");
|
||||
}
|
||||
|
||||
return &(workspaces[number]);
|
||||
return ws;
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -145,7 +96,7 @@ void workspace_set_name(Workspace *ws, const char *name) {
|
|||
*
|
||||
*/
|
||||
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 */
|
||||
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_row = c_ws->current_row;
|
||||
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 we’re 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));
|
||||
if (last_focused != SLIST_END(&(c_ws->focus_stack)))
|
||||
set_focus(conn, last_focused, true);
|
||||
|
@ -204,9 +155,8 @@ void workspace_show(xcb_connection_t *conn, int workspace) {
|
|||
return;
|
||||
}
|
||||
|
||||
t_ws->screen->current_workspace = workspace-1;
|
||||
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 */
|
||||
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 *result = NULL;
|
||||
|
||||
for (int c = 0; c < num_workspaces; c++) {
|
||||
Workspace *ws = workspace_get(c);
|
||||
Workspace *ws;
|
||||
TAILQ_FOREACH(ws, workspaces, workspaces) {
|
||||
if (ws->preferred_screen == NULL ||
|
||||
!screens_are_equal(get_screen_from_preference(slist, ws->preferred_screen), screen))
|
||||
continue;
|
||||
|
@ -337,11 +287,12 @@ Workspace *get_first_workspace_for_screen(struct screens_head *slist, i3Screen *
|
|||
|
||||
if (result == NULL) {
|
||||
/* No assignment found, returning first unused workspace */
|
||||
for (int c = 0; c < num_workspaces; c++) {
|
||||
if (workspaces[c].screen != NULL)
|
||||
Workspace *ws;
|
||||
TAILQ_FOREACH(ws, workspaces, workspaces) {
|
||||
if (ws->screen != NULL)
|
||||
continue;
|
||||
|
||||
result = workspace_get(c);
|
||||
result = ws;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
@ -349,7 +300,11 @@ Workspace *get_first_workspace_for_screen(struct screens_head *slist, i3Screen *
|
|||
if (result == NULL) {
|
||||
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);
|
||||
|
|
|
@ -133,7 +133,7 @@ static void initialize_screen(xcb_connection_t *conn, i3Screen *screen, Workspac
|
|||
i3Font *font = load_font(conn, config.font);
|
||||
|
||||
workspace->screen = screen;
|
||||
screen->current_workspace = workspace->num;
|
||||
screen->current_workspace = workspace;
|
||||
|
||||
/* Create a bar for each screen */
|
||||
Rect bar_rect = {screen->rect.x,
|
||||
|
@ -298,12 +298,13 @@ void xinerama_requery_screens(xcb_connection_t *conn) {
|
|||
int screen_count = 0;
|
||||
/* Mark each workspace which currently is assigned to a screen, so we
|
||||
* can garbage-collect afterwards */
|
||||
for (int c = 0; c < num_workspaces; c++)
|
||||
workspaces[c].reassigned = (workspaces[c].screen == NULL);
|
||||
Workspace *ws;
|
||||
TAILQ_FOREACH(ws, workspaces, workspaces)
|
||||
ws->reassigned = (ws->screen == NULL);
|
||||
|
||||
TAILQ_FOREACH(screen, new_screens, screens) {
|
||||
screen->num = screen_count;
|
||||
screen->current_workspace = -1;
|
||||
screen->current_workspace = NULL;
|
||||
|
||||
TAILQ_FOREACH(old_screen, virtual_screens, screens) {
|
||||
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;
|
||||
|
||||
/* Update the dimensions */
|
||||
for (int c = 0; c < num_workspaces; c++) {
|
||||
Workspace *ws = &(workspaces[c]);
|
||||
Workspace *ws;
|
||||
TAILQ_FOREACH(ws, workspaces, workspaces) {
|
||||
if (ws->screen != old_screen)
|
||||
continue;
|
||||
|
||||
|
@ -347,7 +348,7 @@ void xinerama_requery_screens(xcb_connection_t *conn) {
|
|||
|
||||
break;
|
||||
}
|
||||
if (screen->current_workspace == -1) {
|
||||
if (screen->current_workspace == NULL) {
|
||||
/* Find the first unused workspace, preferring the ones
|
||||
* which are assigned to this screen and initialize
|
||||
* the screen with it. */
|
||||
|
@ -364,38 +365,36 @@ void xinerama_requery_screens(xcb_connection_t *conn) {
|
|||
}
|
||||
|
||||
/* Check for workspaces which are out of bounds */
|
||||
for (int c = 0; c < num_workspaces; c++) {
|
||||
if (workspaces[c].reassigned)
|
||||
TAILQ_FOREACH(ws, workspaces, workspaces) {
|
||||
if (ws->reassigned)
|
||||
continue;
|
||||
|
||||
/* f_ws is a shortcut to the workspace to fix */
|
||||
Workspace *f_ws = &(workspaces[c]);
|
||||
Client *client;
|
||||
|
||||
LOG("Closing bar window (%p)\n", f_ws->screen->bar);
|
||||
xcb_destroy_window(conn, f_ws->screen->bar);
|
||||
LOG("Closing bar window (%p)\n", 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);
|
||||
f_ws->screen = first;
|
||||
memcpy(&(f_ws->rect), &(first->rect), sizeof(Rect));
|
||||
LOG("Workspace %d's screen out of bounds, assigning to first screen\n", ws->num + 1);
|
||||
ws->screen = first;
|
||||
memcpy(&(ws->rect), &(first->rect), sizeof(Rect));
|
||||
|
||||
/* Force reconfiguration for each client on that workspace */
|
||||
FOR_TABLE(f_ws)
|
||||
CIRCLEQ_FOREACH(client, &(f_ws->table[cols][rows]->clients), clients)
|
||||
FOR_TABLE(ws)
|
||||
CIRCLEQ_FOREACH(client, &(ws->table[cols][rows]->clients), clients)
|
||||
client->force_reconfigure = true;
|
||||
|
||||
/* 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 */
|
||||
if (workspace_is_visible(f_ws))
|
||||
if (workspace_is_visible(ws))
|
||||
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");
|
||||
c_ws = &(workspaces[first->current_workspace]);
|
||||
c_ws = first->current_workspace;
|
||||
}
|
||||
}
|
||||
xcb_flush(conn);
|
||||
|
|
Loading…
Reference in New Issue