* opened, for example) have the same size as always */
float *width_factor;
float *height_factor;
+
+ TAILQ_ENTRY(Workspace) workspaces;
};
/**
int num;
/** Current workspace selected on this virtual screen */
- int current_workspace;
+ Workspace *current_workspace;
/** x, y, width, height */
Rect rect;
#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;
/* 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 */
* 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);
}
}
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;
}
/* 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);
- return true;
+ 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;
}
/* 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)
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;
}
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;
}
/* 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);
}
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);
}
*
*/
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)
+ while ((ws = TAILQ_PREV(ws, workspaces_head, workspaces)) != TAILQ_END(workspaces)) {
+ if (ws->screen == NULL)
+ continue;
+
+ workspace_show(conn, ws->num + 1);
return;
- for (i = c_ws->num - 1; i >= 0 ; i--) {
- t_ws = &(workspaces[i]);
- if (t_ws->screen != NULL)
- break;
}
}
-
- if (t_ws->screen != NULL)
- workspace_show(conn, i+1);
}
static void parse_resize_command(xcb_connection_t *conn, Client *last_focused, const char *command) {
while (!TAILQ_EMPTY(bindings)) {
bind = TAILQ_FIRST(bindings);
TAILQ_REMOVE(bindings, bind, bindings);
+ FREE(bind->translated_to);
FREE(bind->command);
FREE(bind);
}
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;
}
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 */
continue;
}
- workspace_set_name(&(workspaces[i]), NULL);
+ workspace_set_name(ws, NULL);
}
return;
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);
/* 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;
* 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);
}
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);
}
/*
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);
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);
}
* 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);
}
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);
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;
}
#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;
*
*/
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) {
}
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;
*
*/
Workspace *workspace_get(int number) {
- if (number > (num_workspaces-1)) {
- int old_num_workspaces = num_workspaces;
-
- /* 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);
- }
- }
+ Workspace *ws;
+ TAILQ_FOREACH(ws, workspaces, workspaces)
+ if (ws->num == number)
+ return ws;
- /* preserve c_ws */
- c_ws = (Workspace*)(c_ws->num);
-
- 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));
-
- /* 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++) {
- 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);
- }
- }
+ /* If we are still there, we could not find the requested workspace. */
+ int last_ws = TAILQ_LAST(workspaces, workspaces_head)->num;
- /* 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("We need to initialize that one, last ws = %d\n", last_ws);
+
+ for (int c = last_ws; c < number; c++) {
+ LOG("Creating new ws\n");
+
+ 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);
- LOG("done\n");
+ TAILQ_INSERT_TAIL(workspaces, ws, workspaces);
}
+ LOG("done\n");
- return &(workspaces[number]);
+ return ws;
}
/*
*
*/
bool workspace_is_visible(Workspace *ws) {
- return (ws->screen->current_workspace == ws->num);
+ return (ws->screen->current_workspace == ws);
}
/*
/* 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)
}
/* 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);
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);
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;
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;
}
}
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);
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,
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)
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;
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. */
}
/* 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);