Also update documentation (manpage, userguide).
To make the code easier to read/write when checking if a client is
floating, introduce client_is_floating().
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
- specifying "focus 1")
+ 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> ]
*Syntax*:
--------------
-focus [number]
+focus [number] | floating | tilling | ft
--------------
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
# Default (Mod1+e)
bind Mod1+26 d
-# Toggle tiling/floating of the current window
+# 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
*/
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);
+
#endif
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.
# 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
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);
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.
*
+ * 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;
+ 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;
+ return;
}
+
+ /* 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")) {
- const char *arguments = command + strlen("focus");
+ const char *arguments = command + strlen("focus ");
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')) {
- 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;
}
}
if (*rest == '\0') {
- 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;
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;
}
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;
}
}
if (action == ACTION_MOVE) {
- if (last_focused->floating >= FLOATING_AUTO_ON) {
+ if (client_is_floating(last_focused)) {
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)
- 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 */
/* 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;
+ }
xcb_flush(conn);
}
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;
}
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;
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);
return 1;
}
- if (client->floating >= FLOATING_AUTO_ON)
+ if (client_is_floating(client))
return floating_border_click(conn, client, event);
if (event->event_y < 2) {
}
/* 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)
/* 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);
}
#include "util.h"
#include "xinerama.h"
#include "layout.h"
+#include "client.h"
/*
* Updates *destination with new_value and returns true if it was changed or false
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… */
- 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);
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);
} 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);
}
/* 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)
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 */
/* 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);