diff --git a/docs/userguide b/docs/userguide index fb537a90..b7c84b21 100644 --- a/docs/userguide +++ b/docs/userguide @@ -86,6 +86,9 @@ image:modes.png[Container modes] To display a window fullscreen or to go out of fullscreen mode again, press +Mod1+f+. +There is also a global fullscreen mode in i3 in which the client will use all +available outputs. To use it, or to get out of it again, press +Mod1+Shift+f+. + === Opening other applications Aside from opening applicatios from a terminal, you can also use the handy @@ -515,7 +518,8 @@ focus_follows_mouse no To change the layout of the current container to stacking, use +s+, for default use +d+ and for tabbed, use +T+. To make the current client (!) fullscreen, -use +f+, to make it floating (or tiling again) use +t+: +use +f+, to make it spanning all outputs, use +fg+, to make it floating (or +tiling again) use +t+: *Examples*: -------------- @@ -526,6 +530,9 @@ bindsym Mod1+w T # Toggle fullscreen bindsym Mod1+f f +# Toggle global fullscreen +bindsym Mod1+Shift+f fg + # Toggle floating/tiling bindsym Mod1+t t -------------- diff --git a/include/client.h b/include/client.h index 4eac127e..8f97eb44 100644 --- a/include/client.h +++ b/include/client.h @@ -51,7 +51,13 @@ bool client_matches_class_name(Client *client, char *to_class, char *to_title, * and when moving a fullscreen client to another screen. * */ -void client_enter_fullscreen(xcb_connection_t *conn, Client *client); +void client_enter_fullscreen(xcb_connection_t *conn, Client *client, bool global); + +/** + * Leaves fullscreen mode for the given client. This is called by toggle_fullscreen. + * + */ +void client_leave_fullscreen(xcb_connection_t *conn, Client *client); /** * Toggles fullscreen mode for the given client. It updates the data @@ -62,6 +68,12 @@ void client_enter_fullscreen(xcb_connection_t *conn, Client *client); */ void client_toggle_fullscreen(xcb_connection_t *conn, Client *client); +/** + * Like client_toggle_fullscreen(), but putting it in global fullscreen-mode. + * + */ +void client_toggle_fullscreen_global(xcb_connection_t *conn, Client *client); + /** * Sets the position of the given client in the X stack to the highest (tiling * layer is always on the same position, so this doesn’t matter) below the diff --git a/src/client.c b/src/client.c index 1ca35dc7..f5e7718e 100644 --- a/src/client.c +++ b/src/client.c @@ -13,6 +13,7 @@ #include #include #include +#include #include #include @@ -152,20 +153,62 @@ bool client_matches_class_name(Client *client, char *to_class, char *to_title, * and when moving a fullscreen client to another screen. * */ -void client_enter_fullscreen(xcb_connection_t *conn, Client *client) { - Workspace *workspace = client->workspace; +void client_enter_fullscreen(xcb_connection_t *conn, Client *client, bool global) { + Workspace *workspace; + Rect r; - if (workspace->fullscreen_client != NULL) { - LOG("Not entering fullscreen mode, there already is a fullscreen client.\n"); - return; + if (global) { + TAILQ_FOREACH(workspace, workspaces, workspaces) { + if (workspace->fullscreen_client == NULL && workspace->fullscreen_client != client) + continue; + + LOG("Not entering global fullscreen mode, there already is a fullscreen client.\n"); + return; + } + + r = (Rect) { UINT_MAX, UINT_MAX, 0,0 }; + Output *output; + + /* Set fullscreen_client for each active workspace. + * Expand the rectangle to contain all outputs. */ + TAILQ_FOREACH(output, &outputs, outputs) { + if(!output->active) + continue; + + output->current_workspace->fullscreen_client = client; + + /* Temporarily abuse width/heigth as coordinates of the lower right corner */ + if(r.x > output->rect.x) + r.x = output->rect.x; + if(r.y > output->rect.y) + r.y = output->rect.y; + if(r.x + r.width < output->rect.x + output->rect.width) + r.width = output->rect.x + output->rect.width; + if(r.y + r.height < output->rect.y + output->rect.height) + r.height = output->rect.y + output->rect.height; + } + + /* Putting them back to their original meaning */ + r.height -= r.x; + r.width -= r.y; + + LOG("Entering global fullscreen mode...\n"); + } else { + workspace = client->workspace; + if (workspace->fullscreen_client != NULL && workspace->fullscreen_client != client) { + LOG("Not entering fullscreen mode, there already is a fullscreen client.\n"); + return; + } + + workspace->fullscreen_client = client; + r = workspace->rect; + + LOG("Entering fullscreen mode...\n"); } client->fullscreen = true; - workspace->fullscreen_client = client; - LOG("Entering fullscreen mode...\n"); - /* We just entered fullscreen mode, let’s configure the window */ - Rect r = workspace->rect; + /* We just entered fullscreen mode, let’s configure the window */ DLOG("child itself will be at %dx%d with size %dx%d\n", r.x, r.y, r.width, r.height); @@ -186,25 +229,17 @@ void client_enter_fullscreen(xcb_connection_t *conn, Client *client) { } /* - * Toggles fullscreen mode for the given client. It updates the data structures and - * reconfigures (= resizes/moves) the client and its frame to the full size of the - * screen. When leaving fullscreen, re-rendering the layout is forced. + * Leaves fullscreen mode for the current client. This is called by toggle_fullscreen. * */ -void client_toggle_fullscreen(xcb_connection_t *conn, Client *client) { - /* dock clients cannot enter fullscreen mode */ - assert(!client->dock); - - Workspace *workspace = client->workspace; - - if (!client->fullscreen) { - client_enter_fullscreen(conn, client); - return; - } - +void client_leave_fullscreen(xcb_connection_t *conn, Client *client) { LOG("leaving fullscreen mode\n"); client->fullscreen = false; - workspace->fullscreen_client = NULL; + Workspace *ws; + TAILQ_FOREACH(ws, workspaces, workspaces) + if (ws->fullscreen_client == client) + ws->fullscreen_client = NULL; + if (client_is_floating(client)) { /* For floating clients it’s enough if we just reconfigure that window (in fact, * re-rendering the layout will not update the client.) */ @@ -225,6 +260,38 @@ void client_toggle_fullscreen(xcb_connection_t *conn, Client *client) { xcb_flush(conn); } +/* + * Toggles fullscreen mode for the given client. It updates the data structures and + * reconfigures (= resizes/moves) the client and its frame to the full size of the + * screen. When leaving fullscreen, re-rendering the layout is forced. + * + */ +void client_toggle_fullscreen(xcb_connection_t *conn, Client *client) { + /* dock clients cannot enter fullscreen mode */ + assert(!client->dock); + + if (!client->fullscreen) { + client_enter_fullscreen(conn, client, false); + } else { + client_leave_fullscreen(conn, client); + } +} + +/* + * Like client_toggle_fullscreen(), but putting it in global fullscreen-mode. + * + */ +void client_toggle_fullscreen_global(xcb_connection_t *conn, Client *client) { + /* dock clients cannot enter fullscreen mode */ + assert(!client->dock); + + if (!client->fullscreen) { + client_enter_fullscreen(conn, client, true); + } else { + client_leave_fullscreen(conn, client); + } +} + /* * Sets the position of the given client in the X stack to the highest (tiling layer is always * on the same position, so this doesn’t matter) below the first floating client, so that diff --git a/src/commands.c b/src/commands.c index 184394b4..fd81e65c 100644 --- a/src/commands.c +++ b/src/commands.c @@ -629,7 +629,7 @@ static void move_current_window_to_workspace(xcb_connection_t *conn, int workspa } else { if (current_client->fullscreen) { DLOG("Calling client_enter_fullscreen again\n"); - client_enter_fullscreen(conn, current_client); + client_enter_fullscreen(conn, current_client, false); } } @@ -1021,11 +1021,14 @@ void parse_command(xcb_connection_t *conn, const char *command) { return; } - /* Is it 'f' for fullscreen? */ + /* Is it 'f' for fullscreen, or 'fg' for fullscreen_global? */ if (command[0] == 'f') { if (last_focused == NULL) return; - client_toggle_fullscreen(conn, last_focused); + if (command[1] == 'g') + client_toggle_fullscreen_global(conn, last_focused); + else + client_toggle_fullscreen(conn, last_focused); return; } diff --git a/src/workspace.c b/src/workspace.c index a17560ed..f3cc24c8 100644 --- a/src/workspace.c +++ b/src/workspace.c @@ -144,6 +144,12 @@ void workspace_show(xcb_connection_t *conn, int workspace) { if ((old_client != NULL) && !old_client->dock) redecorate_window(conn, old_client); else xcb_flush(conn); + + /* We need to check, if a global fullscreen-client is blocking the t_ws and if + * necessary switch that to local fullscreen */ + Client* client = c_ws->fullscreen_client; + if (client != NULL && client->workspace != c_ws) + client_enter_fullscreen(conn, client, false); } /* Check if we need to change something or if we’re already there */