]> git.sur5r.net Git - i3/i3/commitdiff
Implement selecting the next tiling/floating window (using "focus")
authorMichael Stapelberg <michael@stapelberg.de>
Sun, 21 Jun 2009 14:14:15 +0000 (16:14 +0200)
committerMichael Stapelberg <michael@stapelberg.de>
Sun, 21 Jun 2009 14:14:15 +0000 (16:14 +0200)
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:
CMDMODE
docs/userguide
i3.config
include/client.h
man/i3.man
src/client.c
src/commands.c
src/floating.c
src/handlers.c
src/layout.c
src/mainx.c
src/manage.c
src/util.c

diff --git a/CMDMODE b/CMDMODE
index 7428729a9bded1e26d06e641e8bb66af56276ce3..7d8f6f23a1426f2803d5e03e8d977ec2751dcb02 100644 (file)
--- a/CMDMODE
+++ b/CMDMODE
@@ -16,10 +16,13 @@ snap  := <s>
 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> ]
index 4ba97ee90aa07c97755c247a52ebc995d999c9af..aa7575bcefb093c653ca10cd12f333617941ff32 100644 (file)
@@ -300,12 +300,22 @@ the focus stack and jumps to the window you focused before.
 
 *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
index 7bc3fe80927a96dda12681f2250cb45cd7d7d9ab..19f3caee50cdd3ddfb135b42202797dc60191a1c 100644 (file)
--- a/i3.config
+++ b/i3.config
@@ -18,9 +18,13 @@ bind Mod1+43 s
 # 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
index 068a364a518a278bab507fb0451aa6abd4863b1b..964dd2ea79983c1a51542ba43fa920d10eb8392c 100644 (file)
@@ -60,4 +60,12 @@ void client_toggle_fullscreen(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);
+
 #endif
index fbe2ac83a2c91dd99100490de7325face44a02ef..c1513ea43f7994b0ccd4676d13709f442988f26f 100644 (file)
@@ -106,6 +106,12 @@ Enable stacking 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.
 
@@ -165,6 +171,13 @@ bind Mod1+43 s
 # 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
index 18126a1a911cd290e83bbfc653e964a024615f29..5d78d38f77958ee03b3ff9e88bfd113f94160ab1 100644 (file)
@@ -187,7 +187,7 @@ void client_toggle_fullscreen(xcb_connection_t *conn, Client *client) {
                 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);
@@ -223,3 +223,13 @@ void client_set_below_floating(xcb_connection_t *conn, Client *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);
+}
index 89e19615ce29bf7eb220c962c85d78de166dd9bf..084a388e63c4fd081b559eaf0b187b82caff1e00 100644 (file)
@@ -720,29 +720,56 @@ static void jump_to_container(xcb_connection_t *conn, const char *arguments) {
  * 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", &times) != 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", &times) != 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;
+                }
 }
 
 /*
@@ -829,7 +856,7 @@ void parse_command(xcb_connection_t *conn, const char *command) {
 
         /* 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;
         }
@@ -844,7 +871,7 @@ void parse_command(xcb_connection_t *conn, const char *command) {
 
         /* 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;
                 }
@@ -930,7 +957,7 @@ void parse_command(xcb_connection_t *conn, const char *command) {
         }
 
         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;
@@ -941,8 +968,8 @@ void parse_command(xcb_connection_t *conn, const char *command) {
                 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;
         }
@@ -964,7 +991,7 @@ void parse_command(xcb_connection_t *conn, const char *command) {
                 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;
                         }
@@ -973,7 +1000,7 @@ void parse_command(xcb_connection_t *conn, const char *command) {
                 }
 
                 if (action == ACTION_MOVE) {
-                        if (last_focused->floating >= FLOATING_AUTO_ON) {
+                        if (client_is_floating(last_focused)) {
                                 floating_move(conn, last_focused, direction);
                                 continue;
                         }
index 09b33ba166a648a0cb709b855c2a07d8ec35a530..1664d602f8cb1adbe7cbb26c970577bec33481a9 100644 (file)
@@ -52,7 +52,7 @@ void toggle_floating_mode(xcb_connection_t *conn, Client *client, bool automatic
                 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 */
@@ -386,11 +386,12 @@ void floating_toggle_hide(xcb_connection_t *conn, Workspace *workspace) {
         /* 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);
 }
index 129eca9522b0c169f1661ee67a4576e73cdb11e8..3dbef90d2745fb6eee1ca30c6fd5c835af76efe2 100644 (file)
@@ -309,7 +309,7 @@ int handle_button_press(void *ignored, xcb_connection_t *conn, xcb_button_press_
                         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;
                 }
@@ -350,7 +350,7 @@ int handle_button_press(void *ignored, xcb_connection_t *conn, xcb_button_press_
                 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;
@@ -362,7 +362,7 @@ int handle_button_press(void *ignored, xcb_connection_t *conn, xcb_button_press_
                 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);
@@ -372,7 +372,7 @@ int handle_button_press(void *ignored, xcb_connection_t *conn, xcb_button_press_
                 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) {
@@ -477,7 +477,7 @@ int handle_configure_request(void *prophs, xcb_connection_t *conn, xcb_configure
         }
 
         /* 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)
@@ -598,7 +598,7 @@ int handle_unmap_notify_event(void *data, xcb_connection_t *conn, xcb_unmap_noti
                 /* 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);
         }
 
index 952f3d60453cefdc2cd721649d90f377eceaaec4..2b01f90c55a72f309438f3c6d3dcfa5705a1a395 100644 (file)
@@ -24,6 +24,7 @@
 #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
@@ -107,9 +108,9 @@ void decorate_window(xcb_connection_t *conn, Client *client, xcb_drawable_t draw
                 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);
index a832f0985c622d594d696d0f0e4a07e3918b0f8b..d95ca4653dcff818b0d8cb19c82d8b49db373421 100644 (file)
@@ -375,6 +375,9 @@ int main(int argc, char *argv[], char *env[]) {
                 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);
index 8cacd2a0628d19027eb820318af8139196d9fbdc..203a66d913ffce5d3cd40a6bd2a4ecb5b54f96db 100644 (file)
@@ -356,7 +356,7 @@ void reparent_window(xcb_connection_t *conn, xcb_window_t child,
         } 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);
@@ -364,7 +364,7 @@ void reparent_window(xcb_connection_t *conn, xcb_window_t child,
         }
 
         /* 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)
@@ -376,7 +376,7 @@ void reparent_window(xcb_connection_t *conn, xcb_window_t child,
                 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 */
index 762b9481338a14fa58e3da63561a939cd91c5d23..ed9dc49ab8ceb7f8422c2900618a4d41adb39514 100644 (file)
@@ -264,7 +264,7 @@ void unmap_workspace(xcb_connection_t *conn, Workspace *u_ws) {
 
         /* 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);