Also update documentation (manpage, userguide).
To make the code easier to read/write when checking if a client is
floating, introduce client_is_floating().
13 files changed:
cmd := [ <times> ] [ <move> | <snap> ] <where>
with := <w> { [ <times> ] <where> }+ <space> <cmd>
jump := [ "<window class>[/<window title>]" | <workspace> [ <column> <row> ] ]
cmd := [ <times> ] [ <move> | <snap> ] <where>
with := <w> { [ <times> ] <where> }+ <space> <cmd>
jump := [ "<window class>[/<window title>]" | <workspace> [ <column> <row> ] ]
-focus := focus [ <times> ]
+focus := focus [ <times> | floating | tiling | ft ]
(travels the focus stack backwards the given amount of times (by default 1), so
it selects the window which had the focus before you focused the current one when
(travels the focus stack backwards the given amount of times (by default 1), so
it selects the window which had the focus before you focused the current one when
+ specifying "focus 1".
+ The special values 'floating' (select the next floating window), 'tiling'
+ (select the next tiling window), 'ft' (if the current window is floating,
+ select the next tiling window and vice-versa) are also valid)
special := [ exec <path> | kill | exit | restart ]
input := [ <cmd> | <with> | <jump> | <focus> | <special> ]
special := [ exec <path> | kill | exit | restart ]
input := [ <cmd> | <with> | <jump> | <focus> | <special> ]
+focus [number] | floating | tilling | ft
--------------
Where +number+ by default is 1 meaning that the next client in the focus stack will
be selected.
--------------
Where +number+ by default is 1 meaning that the next client in the focus stack will
be selected.
+The special values have the following meaning:
+
+floating::
+ The next floating window is selected.
+tiling::
+ The next tiling window is selected.
+ft::
+ If the current window is floating, the next tiling window will be selected
+ and vice-versa.
+
=== Changing colors
You can change all colors which i3 uses to draw the window decorations and the
=== Changing colors
You can change all colors which i3 uses to draw the window decorations and the
# Default (Mod1+e)
bind Mod1+26 d
# Default (Mod1+e)
bind Mod1+26 d
-# Toggle tiling/floating of the current window
+# Toggle tiling/floating of the current window (Mod1+Shift+Space)
+# Go into the tiling layer / floating layer, depending on whether
+# the current window is tiling / floating (Mod1+t)
+bind Mod1+28 focus ft
+
# Focus (Mod1+j/k/l/;)
bind Mod1+44 h
bind Mod1+45 j
# Focus (Mod1+j/k/l/;)
bind Mod1+44 h
bind Mod1+45 j
*/
void client_set_below_floating(xcb_connection_t *conn, Client *client);
*/
void client_set_below_floating(xcb_connection_t *conn, Client *client);
+/**
+ * Returns true if the client is floating. Makes the code more beatiful, as floating
+ * is not simply a boolean, but also saves whether the user selected the current state
+ * or whether it was automatically set.
+ *
+ */
+bool client_is_floating(Client *client);
+
Mod1+e::
Enable default layout for the current container.
Mod1+e::
Enable default layout for the current container.
+Mod1+Shift+Space::
+Toggle tiling/floating for the current window.
+
+Mod1+t::
+Select the first tiling window if the current window is floating and vice-versa.
+
Mod1+Shift+q::
Kills the current client.
Mod1+Shift+q::
Kills the current client.
# Default (Mod1+e)
bind Mod1+26 d
# Default (Mod1+e)
bind Mod1+26 d
+# Toggle tiling/floating of the current window (Mod1+Shift+Space)
+bind Mod1+Shift+65 t
+
+# Go into the tiling layer / floating layer, depending on whether
+# the current window is tiling / floating (Mod1+t)
+bind Mod1+28 focus ft
+
# Focus (Mod1+j/k/l/;)
bind Mod1+44 h
bind Mod1+45 j
# Focus (Mod1+j/k/l/;)
bind Mod1+44 h
bind Mod1+45 j
LOG("leaving fullscreen mode\n");
client->fullscreen = false;
workspace->fullscreen_client = NULL;
LOG("leaving fullscreen mode\n");
client->fullscreen = false;
workspace->fullscreen_client = NULL;
- if (client->floating >= FLOATING_AUTO_ON) {
+ 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.) */
reposition_client(conn, client);
/* For floating clients it’s enough if we just reconfigure that window (in fact,
* re-rendering the layout will not update the client.) */
reposition_client(conn, client);
xcb_configure_window(conn, client->frame, XCB_CONFIG_WINDOW_SIBLING | XCB_CONFIG_WINDOW_STACK_MODE, values);
}
}
xcb_configure_window(conn, client->frame, XCB_CONFIG_WINDOW_SIBLING | XCB_CONFIG_WINDOW_STACK_MODE, values);
}
}
+
+/*
+ * Returns true if the client is floating. Makes the code more beatiful, as floating
+ * is not simply a boolean, but also saves whether the user selected the current state
+ * or whether it was automatically set.
+ *
+ */
+bool client_is_floating(Client *client) {
+ return (client->floating >= FLOATING_AUTO_ON);
+}
* was specified). That is, selects the window you were in before you focused
* the current window.
*
* was specified). That is, selects the window you were in before you focused
* the current window.
*
+ * The special values 'floating' (select the next floating window), 'tiling'
+ * (select the next tiling window), 'ft' (if the current window is floating,
+ * select the next tiling window and vice-versa) are also valid
+ *
*/
static void travel_focus_stack(xcb_connection_t *conn, const char *arguments) {
/* Start count at -1 to always skip the first element */
int times, count = -1;
Client *current;
*/
static void travel_focus_stack(xcb_connection_t *conn, const char *arguments) {
/* Start count at -1 to always skip the first element */
int times, count = -1;
Client *current;
+ bool floating_criteria;
+
+ /* Either it’s one of the special values… */
+ if (strcasecmp(arguments, "floating") == 0) {
+ floating_criteria = true;
+ } else if (strcasecmp(arguments, "tiling") == 0) {
+ floating_criteria = false;
+ } else if (strcasecmp(arguments, "ft") == 0) {
+ Client *last_focused = SLIST_FIRST(&(c_ws->focus_stack));
+ if (last_focused == SLIST_END(&(c_ws->focus_stack))) {
+ LOG("Cannot select the next floating/tiling client because there is no client at all\n");
+ return;
+ }
- if (sscanf(arguments, "%u", ×) != 1) {
- LOG("No or invalid argument given (\"%s\"), using default of 1 times\n", arguments);
- times = 1;
- }
+ floating_criteria = !client_is_floating(last_focused);
+ } else {
+ /* …or a number was specified */
+ if (sscanf(arguments, "%u", ×) != 1) {
+ LOG("No or invalid argument given (\"%s\"), using default of 1 times\n", arguments);
+ times = 1;
+ }
- Workspace *ws = CUR_CELL->workspace;
+ SLIST_FOREACH(current, &(CUR_CELL->workspace->focus_stack), focus_clients) {
+ if (++count < times) {
+ LOG("Skipping\n");
+ continue;
+ }
- SLIST_FOREACH(current, &(ws->focus_stack), focus_clients) {
- if (++count < times) {
- LOG("Skipping\n");
- continue;
+ LOG("Focussing\n");
+ set_focus(conn, current, true);
+ break;
-
- LOG("Focussing\n");
- set_focus(conn, current, true);
- break;
+
+ /* Select the next client matching the criteria parsed above */
+ SLIST_FOREACH(current, &(CUR_CELL->workspace->focus_stack), focus_clients)
+ if (client_is_floating(current) == floating_criteria) {
+ set_focus(conn, current, true);
+ break;
+ }
/* Should we travel the focus stack? */
if (STARTS_WITH(command, "focus")) {
/* Should we travel the focus stack? */
if (STARTS_WITH(command, "focus")) {
- const char *arguments = command + strlen("focus");
+ const char *arguments = command + strlen("focus ");
travel_focus_stack(conn, arguments);
return;
}
travel_focus_stack(conn, arguments);
return;
}
/* Is it just 's' for stacking or 'd' for default? */
if ((command[0] == 's' || command[0] == 'd') && (command[1] == '\0')) {
/* Is it just 's' for stacking or 'd' for default? */
if ((command[0] == 's' || command[0] == 'd') && (command[1] == '\0')) {
- if (last_focused == NULL || last_focused->floating >= FLOATING_AUTO_ON) {
+ if (last_focused == NULL || client_is_floating(last_focused)) {
LOG("not switching, this is a floating client\n");
return;
}
LOG("not switching, this is a floating client\n");
return;
}
- if (last_focused != NULL && last_focused->floating >= FLOATING_AUTO_ON)
+ if (last_focused != NULL && client_is_floating(last_focused))
move_floating_window_to_workspace(conn, last_focused, workspace);
else move_current_window_to_workspace(conn, workspace);
return;
move_floating_window_to_workspace(conn, last_focused, workspace);
else move_current_window_to_workspace(conn, workspace);
return;
- if (last_focused->floating >= FLOATING_AUTO_ON &&
- (action != ACTION_FOCUS && action != ACTION_MOVE)) {
+ if (client_is_floating(last_focused) &&
+ (action != ACTION_FOCUS && action != ACTION_MOVE)) {
LOG("Not performing (floating)\n");
return;
}
LOG("Not performing (floating)\n");
return;
}
rest++;
if (action == ACTION_FOCUS) {
rest++;
if (action == ACTION_FOCUS) {
- if (last_focused->floating >= FLOATING_AUTO_ON) {
+ if (client_is_floating(last_focused)) {
floating_focus_direction(conn, last_focused, direction);
continue;
}
floating_focus_direction(conn, last_focused, direction);
continue;
}
}
if (action == ACTION_MOVE) {
}
if (action == ACTION_MOVE) {
- if (last_focused->floating >= FLOATING_AUTO_ON) {
+ if (client_is_floating(last_focused)) {
floating_move(conn, last_focused, direction);
continue;
}
floating_move(conn, last_focused, direction);
continue;
}
LOG("This client is already in floating (container == NULL), re-inserting\n");
Client *next_tiling;
SLIST_FOREACH(next_tiling, &(client->workspace->focus_stack), focus_clients)
LOG("This client is already in floating (container == NULL), re-inserting\n");
Client *next_tiling;
SLIST_FOREACH(next_tiling, &(client->workspace->focus_stack), focus_clients)
- if (next_tiling->floating <= FLOATING_USER_OFF)
+ if (!client_is_floating(next_tiling))
break;
/* If there are no tiling clients on this workspace, there can only be one
* container: the first one */
break;
/* If there are no tiling clients on this workspace, there can only be one
* container: the first one */
/* If we just unmapped all floating windows we should ensure that the focus
* is set correctly, that ist, to the first non-floating client in stack */
if (workspace->floating_hidden)
/* If we just unmapped all floating windows we should ensure that the focus
* is set correctly, that ist, to the first non-floating client in stack */
if (workspace->floating_hidden)
- SLIST_FOREACH(client, &(workspace->focus_stack), focus_clients)
- if (client->floating <= FLOATING_USER_OFF) {
- set_focus(conn, client, true);
- return;
- }
+ SLIST_FOREACH(client, &(workspace->focus_stack), focus_clients) {
+ if (client_is_floating(client))
+ continue;
+ set_focus(conn, client, true);
+ return;
+ }
LOG("Not handling, Mod1 was pressed and no client found\n");
return 1;
}
LOG("Not handling, Mod1 was pressed and no client found\n");
return 1;
}
- if (client->floating >= FLOATING_AUTO_ON) {
+ if (client_is_floating(client)) {
floating_drag_window(conn, client, event);
return 1;
}
floating_drag_window(conn, client, event);
return 1;
}
LOG("client. done.\n");
xcb_allow_events(conn, XCB_ALLOW_REPLAY_POINTER, event->time);
/* Floating clients should be raised on click */
LOG("client. done.\n");
xcb_allow_events(conn, XCB_ALLOW_REPLAY_POINTER, event->time);
/* Floating clients should be raised on click */
- if (client->floating >= FLOATING_AUTO_ON)
+ if (client_is_floating(client))
xcb_raise_window(conn, client->frame);
xcb_flush(conn);
return 1;
xcb_raise_window(conn, client->frame);
xcb_flush(conn);
return 1;
LOG("click on titlebar\n");
/* Floating clients can be dragged by grabbing their titlebar */
LOG("click on titlebar\n");
/* Floating clients can be dragged by grabbing their titlebar */
- if (client->floating >= FLOATING_AUTO_ON) {
+ if (client_is_floating(client)) {
/* Firstly, we raise it. Maybe the user just wanted to raise it without grabbing */
xcb_raise_window(conn, client->frame);
xcb_flush(conn);
/* Firstly, we raise it. Maybe the user just wanted to raise it without grabbing */
xcb_raise_window(conn, client->frame);
xcb_flush(conn);
- if (client->floating >= FLOATING_AUTO_ON)
+ if (client_is_floating(client))
return floating_border_click(conn, client, event);
if (event->event_y < 2) {
return floating_border_click(conn, client, event);
if (event->event_y < 2) {
}
/* Floating clients can be reconfigured */
}
/* Floating clients can be reconfigured */
- if (client->floating >= FLOATING_AUTO_ON) {
+ if (client_is_floating(client)) {
i3Font *font = load_font(conn, config.font);
if (event->value_mask & XCB_CONFIG_WINDOW_X)
i3Font *font = load_font(conn, config.font);
if (event->value_mask & XCB_CONFIG_WINDOW_X)
/* Only if this is the active container, we need to really change focus */
if ((con->currently_focused != NULL) && ((con == CUR_CELL) || client->fullscreen))
set_focus(conn, con->currently_focused, true);
/* Only if this is the active container, we need to really change focus */
if ((con->currently_focused != NULL) && ((con == CUR_CELL) || client->fullscreen))
set_focus(conn, con->currently_focused, true);
- } else if (client->floating >= FLOATING_AUTO_ON) {
+ } else if (client_is_floating(client)) {
SLIST_REMOVE(&(client->workspace->focus_stack), client, Client, focus_clients);
}
SLIST_REMOVE(&(client->workspace->focus_stack), client, Client, focus_clients);
}
#include "util.h"
#include "xinerama.h"
#include "layout.h"
#include "util.h"
#include "xinerama.h"
#include "layout.h"
/*
* Updates *destination with new_value and returns true if it was changed or false
/*
* Updates *destination with new_value and returns true if it was changed or false
return;
LOG("redecorating child %08x\n", client->child);
return;
LOG("redecorating child %08x\n", client->child);
- if (client->floating >= FLOATING_AUTO_ON || client->container->currently_focused == client) {
+ if (client_is_floating(client) || client->container->currently_focused == client) {
/* Distinguish if the window is currently focused… */
/* Distinguish if the window is currently focused… */
- if (client->floating >= FLOATING_AUTO_ON || CUR_CELL->currently_focused == client)
+ if (client_is_floating(client) || CUR_CELL->currently_focused == client)
color = &(config.client.focused);
/* …or if it is the focused window in a not focused container */
else color = &(config.client.focused_inactive);
color = &(config.client.focused);
/* …or if it is the focused window in a not focused container */
else color = &(config.client.focused_inactive);
c_ws = &workspaces[screen->current_workspace];
}
c_ws = &workspaces[screen->current_workspace];
}
+ /* Handle the events which arrived until now */
+ xcb_check_cb(NULL, NULL, 0);
+
/* Ungrab the server to receive events and enter libev’s eventloop */
xcb_ungrab_server(conn);
ev_loop(loop, 0);
/* Ungrab the server to receive events and enter libev’s eventloop */
xcb_ungrab_server(conn);
ev_loop(loop, 0);
} else if (!new->dock) {
/* Focus the new window if we’re not in fullscreen mode and if it is not a dock window */
if (new->container->workspace->fullscreen_client == NULL) {
} else if (!new->dock) {
/* Focus the new window if we’re not in fullscreen mode and if it is not a dock window */
if (new->container->workspace->fullscreen_client == NULL) {
- if (new->floating <= FLOATING_USER_OFF)
+ if (!client_is_floating(new))
new->container->currently_focused = new;
if (new->container == CUR_CELL)
xcb_set_input_focus(conn, XCB_INPUT_FOCUS_POINTER_ROOT, new->child, XCB_CURRENT_TIME);
new->container->currently_focused = new;
if (new->container == CUR_CELL)
xcb_set_input_focus(conn, XCB_INPUT_FOCUS_POINTER_ROOT, new->child, XCB_CURRENT_TIME);
}
/* Insert into the currently active container, if it’s not a dock window */
}
/* Insert into the currently active container, if it’s not a dock window */
- if (!new->dock && new->floating <= FLOATING_USER_OFF) {
+ if (!new->dock && !client_is_floating(new)) {
/* Insert after the old active client, if existing. If it does not exist, the
container is empty and it does not matter, where we insert it */
if (old_focused != NULL && !old_focused->dock)
/* Insert after the old active client, if existing. If it does not exist, the
container is empty and it does not matter, where we insert it */
if (old_focused != NULL && !old_focused->dock)
client_set_below_floating(conn, new);
}
client_set_below_floating(conn, new);
}
- if (new->floating >= FLOATING_AUTO_ON) {
+ if (client_is_floating(new)) {
SLIST_INSERT_HEAD(&(new->workspace->focus_stack), new, focus_clients);
/* Add the client to the list of floating clients for its workspace */
SLIST_INSERT_HEAD(&(new->workspace->focus_stack), new, focus_clients);
/* Add the client to the list of floating clients for its workspace */
/* To find floating clients, we traverse the focus stack */
SLIST_FOREACH(client, &(u_ws->focus_stack), focus_clients) {
/* To find floating clients, we traverse the focus stack */
SLIST_FOREACH(client, &(u_ws->focus_stack), focus_clients) {
- if (client->floating <= FLOATING_USER_OFF)
+ if (!client_is_floating(client))
continue;
xcb_unmap_window(conn, client->frame);
continue;
xcb_unmap_window(conn, client->frame);