xinerama: correctly put windows which are assigned to a specific screen on that screen when it becomes available (Thanks badboy)
This commit is contained in:
parent
0b5554c762
commit
e900a8d23d
|
@ -44,6 +44,17 @@ bool workspace_is_visible(Workspace *ws);
|
||||||
/** Switches to the given workspace */
|
/** Switches to the given workspace */
|
||||||
void workspace_show(xcb_connection_t *conn, int workspace);
|
void workspace_show(xcb_connection_t *conn, int workspace);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Assigns the given workspace to the given screen by correctly updating its
|
||||||
|
* state and reconfiguring all the clients on this workspace.
|
||||||
|
*
|
||||||
|
* This is called when initializing a screen and when re-assigning it to a
|
||||||
|
* different screen which just got available (if you configured it to be on
|
||||||
|
* screen 1 and you just plugged in screen 1).
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
void workspace_assign_to(Workspace *ws, i3Screen *screen);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Initializes the given workspace if it is not already initialized. The given
|
* Initializes the given workspace if it is not already initialized. The given
|
||||||
* screen is to be understood as a fallback, if the workspace itself either
|
* screen is to be understood as a fallback, if the workspace itself either
|
||||||
|
@ -51,7 +62,7 @@ void workspace_show(xcb_connection_t *conn, int workspace);
|
||||||
* the screen is not attached at the moment.
|
* the screen is not attached at the moment.
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
void workspace_initialize(Workspace *ws, i3Screen *screen);
|
void workspace_initialize(Workspace *ws, i3Screen *screen, bool recheck);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets the first unused workspace for the given screen, taking into account
|
* Gets the first unused workspace for the given screen, taking into account
|
||||||
|
|
|
@ -531,7 +531,7 @@ static void move_floating_window_to_workspace(xcb_connection_t *conn, Client *cl
|
||||||
|
|
||||||
LOG("moving floating\n");
|
LOG("moving floating\n");
|
||||||
|
|
||||||
workspace_initialize(t_ws, c_ws->screen);
|
workspace_initialize(t_ws, c_ws->screen, false);
|
||||||
|
|
||||||
/* Check if there is already a fullscreen client on the destination workspace and
|
/* Check if there is already a fullscreen client on the destination workspace and
|
||||||
* stop moving if so. */
|
* stop moving if so. */
|
||||||
|
@ -592,7 +592,7 @@ static void move_current_window_to_workspace(xcb_connection_t *conn, int workspa
|
||||||
if (to_focus == NULL)
|
if (to_focus == NULL)
|
||||||
to_focus = CIRCLEQ_PREV_OR_NULL(&(container->clients), current_client, clients);
|
to_focus = CIRCLEQ_PREV_OR_NULL(&(container->clients), current_client, clients);
|
||||||
|
|
||||||
workspace_initialize(t_ws, container->workspace->screen);
|
workspace_initialize(t_ws, container->workspace->screen, false);
|
||||||
/* Check if there is already a fullscreen client on the destination workspace and
|
/* Check if there is already a fullscreen client on the destination workspace and
|
||||||
* stop moving if so. */
|
* stop moving if so. */
|
||||||
if (current_client->fullscreen && (t_ws->fullscreen_client != NULL)) {
|
if (current_client->fullscreen && (t_ws->fullscreen_client != NULL)) {
|
||||||
|
|
|
@ -340,7 +340,7 @@ void reparent_window(xcb_connection_t *conn, xcb_window_t child,
|
||||||
|
|
||||||
DLOG("Changing container/workspace and unmapping the client\n");
|
DLOG("Changing container/workspace and unmapping the client\n");
|
||||||
Workspace *t_ws = workspace_get(assign->workspace-1);
|
Workspace *t_ws = workspace_get(assign->workspace-1);
|
||||||
workspace_initialize(t_ws, c_ws->screen);
|
workspace_initialize(t_ws, c_ws->screen, false);
|
||||||
|
|
||||||
new->container = t_ws->table[t_ws->current_col][t_ws->current_row];
|
new->container = t_ws->table[t_ws->current_col][t_ws->current_row];
|
||||||
new->workspace = t_ws;
|
new->workspace = t_ws;
|
||||||
|
|
|
@ -117,7 +117,7 @@ void workspace_show(xcb_connection_t *conn, int workspace) {
|
||||||
c_ws->current_col = current_col;
|
c_ws->current_col = current_col;
|
||||||
|
|
||||||
/* Check if the workspace has not been used yet */
|
/* Check if the workspace has not been used yet */
|
||||||
workspace_initialize(t_ws, c_ws->screen);
|
workspace_initialize(t_ws, c_ws->screen, false);
|
||||||
|
|
||||||
if (c_ws->screen != t_ws->screen) {
|
if (c_ws->screen != t_ws->screen) {
|
||||||
/* We need to switch to the other screen first */
|
/* We need to switch to the other screen first */
|
||||||
|
@ -244,6 +244,49 @@ static i3Screen *get_screen_from_preference(struct screens_head *slist, char *pr
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Assigns the given workspace to the given screen by correctly updating its
|
||||||
|
* state and reconfiguring all the clients on this workspace.
|
||||||
|
*
|
||||||
|
* This is called when initializing a screen and when re-assigning it to a
|
||||||
|
* different screen which just got available (if you configured it to be on
|
||||||
|
* screen 1 and you just plugged in screen 1).
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
void workspace_assign_to(Workspace *ws, i3Screen *screen) {
|
||||||
|
Client *client;
|
||||||
|
bool empty = true;
|
||||||
|
|
||||||
|
ws->screen = screen;
|
||||||
|
|
||||||
|
/* Copy the dimensions from the virtual screen */
|
||||||
|
memcpy(&(ws->rect), &(ws->screen->rect), sizeof(Rect));
|
||||||
|
|
||||||
|
/* Force reconfiguration for each client on that workspace */
|
||||||
|
FOR_TABLE(ws)
|
||||||
|
CIRCLEQ_FOREACH(client, &(ws->table[cols][rows]->clients), clients) {
|
||||||
|
client->force_reconfigure = true;
|
||||||
|
empty = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (empty)
|
||||||
|
return;
|
||||||
|
|
||||||
|
/* Render the workspace to reconfigure the clients. However, they will be visible now, so… */
|
||||||
|
render_workspace(global_conn, screen, ws);
|
||||||
|
|
||||||
|
/* …unless we want to see them at the moment, we should hide that workspace */
|
||||||
|
if (workspace_is_visible(ws))
|
||||||
|
return;
|
||||||
|
|
||||||
|
workspace_unmap_clients(global_conn, ws);
|
||||||
|
|
||||||
|
if (c_ws == ws) {
|
||||||
|
DLOG("Need to adjust c_ws...\n");
|
||||||
|
c_ws = screen->current_workspace;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Initializes the given workspace if it is not already initialized. The given
|
* Initializes the given workspace if it is not already initialized. The given
|
||||||
* screen is to be understood as a fallback, if the workspace itself either
|
* screen is to be understood as a fallback, if the workspace itself either
|
||||||
|
@ -251,12 +294,16 @@ static i3Screen *get_screen_from_preference(struct screens_head *slist, char *pr
|
||||||
* the screen is not attached at the moment.
|
* the screen is not attached at the moment.
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
void workspace_initialize(Workspace *ws, i3Screen *screen) {
|
void workspace_initialize(Workspace *ws, i3Screen *screen, bool recheck) {
|
||||||
if (ws->screen != NULL) {
|
i3Screen *old_screen;
|
||||||
|
|
||||||
|
if (ws->screen != NULL && !recheck) {
|
||||||
DLOG("Workspace already initialized\n");
|
DLOG("Workspace already initialized\n");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
old_screen = ws->screen;
|
||||||
|
|
||||||
/* If this workspace has no preferred screen or if the screen it wants
|
/* If this workspace has no preferred screen or if the screen it wants
|
||||||
* to be on is not available at the moment, we initialize it with
|
* to be on is not available at the moment, we initialize it with
|
||||||
* the screen which was given */
|
* the screen which was given */
|
||||||
|
@ -264,8 +311,12 @@ void workspace_initialize(Workspace *ws, i3Screen *screen) {
|
||||||
(ws->screen = get_screen_from_preference(virtual_screens, ws->preferred_screen)) == NULL)
|
(ws->screen = get_screen_from_preference(virtual_screens, ws->preferred_screen)) == NULL)
|
||||||
ws->screen = screen;
|
ws->screen = screen;
|
||||||
|
|
||||||
/* Copy the dimensions from the virtual screen */
|
DLOG("old_screen = %p, ws->screen = %p\n", old_screen, ws->screen);
|
||||||
memcpy(&(ws->rect), &(ws->screen->rect), sizeof(Rect));
|
/* If the assignment did not change, we do not need to update anything */
|
||||||
|
if (old_screen != NULL && ws->screen == old_screen)
|
||||||
|
return;
|
||||||
|
|
||||||
|
workspace_assign_to(ws, ws->screen);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -308,7 +359,7 @@ Workspace *get_first_workspace_for_screen(struct screens_head *slist, i3Screen *
|
||||||
result = workspace_get(last_ws + 1);
|
result = workspace_get(last_ws + 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
workspace_initialize(result, screen);
|
workspace_initialize(result, screen, false);
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -203,12 +203,14 @@ static void query_screens(xcb_connection_t *conn, struct screens_head *screenlis
|
||||||
for (int screen = 0; screen < screens; screen++) {
|
for (int screen = 0; screen < screens; screen++) {
|
||||||
i3Screen *s = get_screen_at(screen_info[screen].x_org, screen_info[screen].y_org, screenlist);
|
i3Screen *s = get_screen_at(screen_info[screen].x_org, screen_info[screen].y_org, screenlist);
|
||||||
if (s != NULL) {
|
if (s != NULL) {
|
||||||
|
DLOG("Re-used old Xinerama screen %p\n", s);
|
||||||
/* This screen already exists. We use the littlest screen so that the user
|
/* This screen already exists. We use the littlest screen so that the user
|
||||||
can always see the complete workspace */
|
can always see the complete workspace */
|
||||||
s->rect.width = min(s->rect.width, screen_info[screen].width);
|
s->rect.width = min(s->rect.width, screen_info[screen].width);
|
||||||
s->rect.height = min(s->rect.height, screen_info[screen].height);
|
s->rect.height = min(s->rect.height, screen_info[screen].height);
|
||||||
} else {
|
} else {
|
||||||
s = calloc(sizeof(i3Screen), 1);
|
s = calloc(sizeof(i3Screen), 1);
|
||||||
|
DLOG("Created new Xinerama screen %p\n", s);
|
||||||
s->rect.x = screen_info[screen].x_org;
|
s->rect.x = screen_info[screen].x_org;
|
||||||
s->rect.y = screen_info[screen].y_org;
|
s->rect.y = screen_info[screen].y_org;
|
||||||
s->rect.width = screen_info[screen].width;
|
s->rect.width = screen_info[screen].width;
|
||||||
|
@ -331,7 +333,7 @@ void xinerama_requery_screens(xcb_connection_t *conn) {
|
||||||
|
|
||||||
Rect bar_rect = {screen->rect.x,
|
Rect bar_rect = {screen->rect.x,
|
||||||
screen->rect.y + screen->rect.height - (font->height + 6),
|
screen->rect.y + screen->rect.height - (font->height + 6),
|
||||||
screen->rect.x + screen->rect.width,
|
screen->rect.width,
|
||||||
font->height + 6};
|
font->height + 6};
|
||||||
|
|
||||||
DLOG("configuring bar to be at %d x %d with %d x %d\n",
|
DLOG("configuring bar to be at %d x %d with %d x %d\n",
|
||||||
|
@ -401,34 +403,13 @@ void xinerama_requery_screens(xcb_connection_t *conn) {
|
||||||
if (ws->reassigned)
|
if (ws->reassigned)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
Client *client;
|
|
||||||
|
|
||||||
DLOG("Closing bar window (%p)\n", ws->screen->bar);
|
DLOG("Closing bar window (%p)\n", ws->screen->bar);
|
||||||
xcb_destroy_window(conn, ws->screen->bar);
|
xcb_destroy_window(conn, ws->screen->bar);
|
||||||
|
|
||||||
DLOG("Workspace %d's screen out of bounds, assigning to first screen\n", ws->num + 1);
|
DLOG("Workspace %d's screen out of bounds, assigning to first screen\n", ws->num + 1);
|
||||||
ws->screen = first;
|
workspace_assign_to(ws, first);
|
||||||
memcpy(&(ws->rect), &(first->rect), sizeof(Rect));
|
|
||||||
|
|
||||||
/* Force reconfiguration for each client on that workspace */
|
|
||||||
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, ws);
|
|
||||||
|
|
||||||
/* …unless we want to see them at the moment, we should hide that workspace */
|
|
||||||
if (workspace_is_visible(ws))
|
|
||||||
continue;
|
|
||||||
|
|
||||||
workspace_unmap_clients(conn, ws);
|
|
||||||
|
|
||||||
if (c_ws == ws) {
|
|
||||||
DLOG("Need to adjust c_ws...\n");
|
|
||||||
c_ws = first->current_workspace;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
xcb_flush(conn);
|
xcb_flush(conn);
|
||||||
|
|
||||||
/* Free the old list */
|
/* Free the old list */
|
||||||
|
@ -441,6 +422,15 @@ void xinerama_requery_screens(xcb_connection_t *conn) {
|
||||||
|
|
||||||
virtual_screens = new_screens;
|
virtual_screens = new_screens;
|
||||||
|
|
||||||
|
/* Check for workspaces which need to be assigned to specific screens
|
||||||
|
* which may now be available */
|
||||||
|
TAILQ_FOREACH(ws, workspaces, workspaces) {
|
||||||
|
if (ws->preferred_screen == NULL)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
workspace_initialize(ws, ws->screen, true);
|
||||||
|
}
|
||||||
|
|
||||||
DLOG("Current workspace is now: %d\n", first->current_workspace);
|
DLOG("Current workspace is now: %d\n", first->current_workspace);
|
||||||
|
|
||||||
render_layout(conn);
|
render_layout(conn);
|
||||||
|
|
Loading…
Reference in New Issue