*/
void ignore_enter_notify_forall(xcb_connection_t *conn, Workspace *workspace, bool ignore_enter_notify);
+/**
+ * Renders the given workspace on the given screen
+ *
+ */
+void render_workspace(xcb_connection_t *conn, i3Screen *screen, Workspace *r_ws);
+
/**
* Renders the whole layout, that is: Go through each screen, each workspace, each container
* and render each client. This also renders the bars.
#define CIRCLEQ_PREV_OR_NULL(head, elm, field) (CIRCLEQ_PREV(elm, field) != CIRCLEQ_END(head) ? \
CIRCLEQ_PREV(elm, field) : NULL)
#define FOR_TABLE(workspace) \
- for (int cols = 0; cols < workspace->cols; cols++) \
- for (int rows = 0; rows < workspace->rows; rows++)
+ for (int cols = 0; cols < (workspace)->cols; cols++) \
+ for (int rows = 0; rows < (workspace)->rows; rows++)
#define FREE(pointer) do { \
if (pointer == NULL) { \
free(pointer); \
*/
Client *get_last_focused_client(xcb_connection_t *conn, Container *container, Client *exclude);
+/**
+ * Unmaps all clients (and stack windows) of the given workspace.
+ *
+ * This needs to be called separately when temporarily rendering
+ * a workspace which is not the active workspace to force
+ * reconfiguration of all clients, like in src/xinerama.c when
+ * re-assigning a workspace to another screen.
+ *
+ */
+void unmap_workspace(xcb_connection_t *conn, Workspace *u_ws);
+
/**
* Sets the given client as focused by updating the data structures correctly,
* updating the X input focus and finally re-decorating both windows (to signalize
t_ws->screen->current_workspace = workspace-1;
- /* TODO: does grabbing the server actually bring us any (speed)advantages? */
- //xcb_grab_server(conn);
-
- ignore_enter_notify_forall(conn, c_ws, true);
-
/* Unmap all clients of the current workspace */
- int unmapped_clients = 0;
- FOR_TABLE(c_ws)
- CIRCLEQ_FOREACH(client, &(c_ws->table[cols][rows]->clients), clients) {
- xcb_unmap_window(conn, client->frame);
- unmapped_clients++;
- }
-
- /* If we did not unmap any clients, the workspace is empty and we can destroy it */
- if (unmapped_clients == 0)
- c_ws->screen = NULL;
-
- /* Unmap the stack windows on the current workspace, if any */
- struct Stack_Window *stack_win;
- SLIST_FOREACH(stack_win, &stack_wins, stack_windows)
- if (stack_win->container->workspace == c_ws)
- xcb_unmap_window(conn, stack_win->window);
-
- ignore_enter_notify_forall(conn, c_ws, false);
+ unmap_workspace(conn, c_ws);
c_ws = &workspaces[workspace-1];
current_row = c_ws->current_row;
xcb_map_window(conn, client->frame);
/* Map all stack windows, if any */
+ struct Stack_Window *stack_win;
SLIST_FOREACH(stack_win, &stack_wins, stack_windows)
if (stack_win->container->workspace == c_ws)
xcb_map_window(conn, stack_win->window);
}
} else xcb_set_input_focus(conn, XCB_INPUT_FOCUS_POINTER_ROOT, root, XCB_CURRENT_TIME);
- //xcb_ungrab_server(conn);
-
render_layout(conn);
}
}
}
+/*
+ * Renders the given workspace on the given screen
+ *
+ */
+void render_workspace(xcb_connection_t *conn, i3Screen *screen, Workspace *r_ws) {
+ i3Font *font = load_font(conn, config.font);
+ int width = r_ws->rect.width;
+ int height = r_ws->rect.height;
+
+ /* Reserve space for dock clients */
+ Client *client;
+ SLIST_FOREACH(client, &(screen->dock_clients), dock_clients)
+ height -= client->desired_height;
+
+ /* Space for the internal bar */
+ height -= (font->height + 6);
+
+ LOG("got %d rows and %d cols\n", r_ws->rows, r_ws->cols);
+
+ int xoffset[r_ws->rows];
+ int yoffset[r_ws->cols];
+ /* Initialize offsets */
+ for (int cols = 0; cols < r_ws->cols; cols++)
+ yoffset[cols] = r_ws->rect.y;
+ for (int rows = 0; rows < r_ws->rows; rows++)
+ xoffset[rows] = r_ws->rect.x;
+
+ dump_table(conn, r_ws);
+
+ ignore_enter_notify_forall(conn, r_ws, true);
+
+ /* Go through the whole table and render what’s necessary */
+ FOR_TABLE(r_ws) {
+ Container *container = r_ws->table[cols][rows];
+ int single_width, single_height;
+ LOG("\n");
+ LOG("========\n");
+ LOG("container has %d colspan, %d rowspan\n",
+ container->colspan, container->rowspan);
+ LOG("container at %d, %d\n", xoffset[rows], yoffset[cols]);
+ /* Update position of the container */
+ container->row = rows;
+ container->col = cols;
+ container->x = xoffset[rows];
+ container->y = yoffset[cols];
+
+ if (container->width_factor == 0)
+ container->width = (width / r_ws->cols);
+ else container->width = get_unoccupied_x(r_ws, rows) * container->width_factor;
+ single_width = container->width;
+ container->width *= container->colspan;
+
+ if (container->height_factor == 0)
+ container->height = (height / r_ws->rows);
+ else container->height = get_unoccupied_y(r_ws, cols) * container->height_factor;
+ single_height = container->height;
+ container->height *= container->rowspan;
+
+ /* Render the container if it is not empty */
+ render_container(conn, container);
+
+ xoffset[rows] += single_width;
+ yoffset[cols] += single_height;
+ LOG("==========\n");
+ }
+
+ ignore_enter_notify_forall(conn, r_ws, false);
+
+ render_bars(conn, r_ws, width, &height);
+ render_internal_bar(conn, r_ws, width, font->height + 6);
+}
+
/*
* Renders the whole layout, that is: Go through each screen, each workspace, each container
* and render each client. This also renders the bars.
*/
void render_layout(xcb_connection_t *conn) {
i3Screen *screen;
- i3Font *font = load_font(conn, config.font);
TAILQ_FOREACH(screen, virtual_screens, screens) {
- /* r_ws (rendering workspace) is just a shortcut to the Workspace being currently rendered */
- Workspace *r_ws = &(workspaces[screen->current_workspace]);
-
LOG("Rendering screen %d\n", screen->num);
-
- int width = r_ws->rect.width;
- int height = r_ws->rect.height;
-
- /* Reserve space for dock clients */
- Client *client;
- SLIST_FOREACH(client, &(screen->dock_clients), dock_clients)
- height -= client->desired_height;
-
- /* Space for the internal bar */
- height -= (font->height + 6);
-
- LOG("got %d rows and %d cols\n", r_ws->rows, r_ws->cols);
-
- int xoffset[r_ws->rows];
- int yoffset[r_ws->cols];
- /* Initialize offsets */
- for (int cols = 0; cols < r_ws->cols; cols++)
- yoffset[cols] = r_ws->rect.y;
- for (int rows = 0; rows < r_ws->rows; rows++)
- xoffset[rows] = r_ws->rect.x;
-
- dump_table(conn, r_ws);
-
- ignore_enter_notify_forall(conn, r_ws, true);
-
- /* Go through the whole table and render what’s necessary */
- FOR_TABLE(r_ws) {
- Container *container = r_ws->table[cols][rows];
- int single_width, single_height;
- LOG("\n");
- LOG("========\n");
- LOG("container has %d colspan, %d rowspan\n",
- container->colspan, container->rowspan);
- LOG("container at %d, %d\n", xoffset[rows], yoffset[cols]);
- /* Update position of the container */
- container->row = rows;
- container->col = cols;
- container->x = xoffset[rows];
- container->y = yoffset[cols];
-
- if (container->width_factor == 0)
- container->width = (width / r_ws->cols);
- else container->width = get_unoccupied_x(r_ws, rows) * container->width_factor;
- single_width = container->width;
- container->width *= container->colspan;
-
- if (container->height_factor == 0)
- container->height = (height / r_ws->rows);
- else container->height = get_unoccupied_y(r_ws, cols) * container->height_factor;
- single_height = container->height;
- container->height *= container->rowspan;
-
- /* Render the container if it is not empty */
- render_container(conn, container);
-
- xoffset[rows] += single_width;
- yoffset[cols] += single_height;
- LOG("==========\n");
- }
-
- ignore_enter_notify_forall(conn, r_ws, false);
-
- render_bars(conn, r_ws, width, &height);
- render_internal_bar(conn, r_ws, width, font->height + 6);
+ render_workspace(conn, screen, &(workspaces[screen->current_workspace]));
}
xcb_flush(conn);
return NULL;
}
+/*
+ * Unmaps all clients (and stack windows) of the given workspace.
+ *
+ * This needs to be called separately when temporarily rendering
+ * a workspace which is not the active workspace to force
+ * reconfiguration of all clients, like in src/xinerama.c when
+ * re-assigning a workspace to another screen.
+ *
+ */
+void unmap_workspace(xcb_connection_t *conn, Workspace *u_ws) {
+ Client *client;
+ struct Stack_Window *stack_win;
+
+ /* Ignore notify events because they would cause focus to be changed */
+ ignore_enter_notify_forall(conn, u_ws, true);
+
+ /* Unmap all clients of the current workspace */
+ int unmapped_clients = 0;
+ FOR_TABLE(u_ws)
+ CIRCLEQ_FOREACH(client, &(u_ws->table[cols][rows]->clients), clients) {
+ xcb_unmap_window(conn, client->frame);
+ unmapped_clients++;
+ }
+
+ /* If we did not unmap any clients, the workspace is empty and we can destroy it */
+ if (unmapped_clients == 0)
+ u_ws->screen = NULL;
+
+ /* Unmap the stack windows on the current workspace, if any */
+ SLIST_FOREACH(stack_win, &stack_wins, stack_windows)
+ if (stack_win->container->workspace == u_ws)
+ xcb_unmap_window(conn, stack_win->window);
+
+ ignore_enter_notify_forall(conn, u_ws, false);
+}
+
/*
* Sets the given client as focused by updating the data structures correctly,
* updating the X input focus and finally re-decorating both windows (to signalize
}
/* Check for workspaces which are out of bounds */
- for (int c = 0; c < 10; c++)
- if ((workspaces[c].screen != NULL) &&
- (workspaces[c].screen->num >= num_screens)) {
- LOG("Closing bar window\n");
- xcb_destroy_window(conn, workspaces[c].screen->bar);
-
- LOG("Workspace %d's screen out of bounds, assigning to first screen\n", c+1);
- workspaces[c].screen = first;
- memcpy(&(workspaces[c].rect), &(first->rect), sizeof(Rect));
- }
+ for (int c = 0; c < 10; c++) {
+ if ((workspaces[c].screen == NULL) || (workspaces[c].screen->num < num_screens))
+ continue;
+
+ /* f_ws is a shortcut to the workspace to fix */
+ Workspace *f_ws = &(workspaces[c]);
+ Client *client;
+
+ LOG("Closing bar window\n");
+ xcb_destroy_window(conn, f_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));
+
+ /* Force reconfiguration for each client on that workspace */
+ FOR_TABLE(f_ws)
+ CIRCLEQ_FOREACH(client, &(f_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);
+
+ /* …unless we want to see them at the moment, we should hide that workspace */
+ if (first->current_workspace == c)
+ continue;
+
+ unmap_workspace(conn, f_ws);
+ }
+ xcb_flush(conn);
/* Free the old list */
while (!TAILQ_EMPTY(virtual_screens)) {