]> git.sur5r.net Git - i3/i3/blobdiff - src/commands.c
implement 'move' command in the new parser
[i3/i3] / src / commands.c
index 4317b36f6dd4a84aef40a7c9682cfee5b99edb5b..2d8155f276a162494db56b6ce416566875b2861a 100644 (file)
@@ -33,6 +33,7 @@
 #include "log.h"
 #include "sighandler.h"
 #include "manage.h"
+#include "ipc.h"
 
 bool focus_window_in_container(xcb_connection_t *conn, Container *container, direction_t direction) {
         /* If this container is empty, we’re done */
@@ -89,12 +90,13 @@ static void focus_thing(xcb_connection_t *conn, direction_t direction, thing_t t
         Workspace *t_ws = c_ws;
 
         /* Makes sure new_col and new_row are within bounds of the new workspace */
-        void check_colrow_boundaries() {
-                if (new_col >= t_ws->cols)
-                        new_col = (t_ws->cols - 1);
-                if (new_row >= t_ws->rows)
-                        new_row = (t_ws->rows - 1);
-        }
+#define CHECK_COLROW_BOUNDARIES \
+        do { \
+                if (new_col >= t_ws->cols) \
+                        new_col = (t_ws->cols - 1); \
+                if (new_row >= t_ws->rows) \
+                        new_row = (t_ws->rows - 1); \
+        } while (0)
 
         /* There always is a container. If not, current_col or current_row is wrong */
         assert(container != NULL);
@@ -174,7 +176,7 @@ static void focus_thing(xcb_connection_t *conn, direction_t direction, thing_t t
                         new_row = (direction == D_UP ? (t_ws->rows - 1) : 0);
                 }
 
-                check_colrow_boundaries();
+                CHECK_COLROW_BOUNDARIES;
 
                 DLOG("new_col = %d, new_row = %d\n", new_col, new_row);
                 if (t_ws->table[new_col][new_row]->currently_focused == NULL) {
@@ -184,9 +186,26 @@ static void focus_thing(xcb_connection_t *conn, direction_t direction, thing_t t
                                         continue;
 
                                 new_col = cols;
+                                DLOG("Fixed it to new col %d\n", new_col);
+                                break;
+                        }
+                }
+
+                if (t_ws->table[new_col][new_row]->currently_focused == NULL) {
+                        DLOG("Cell still empty, checking for full cols above spanned width...\n");
+                        DLOG("new_col = %d\n", new_col);
+                        DLOG("colspan = %d\n", container->colspan);
+                        for (int cols = new_col;
+                             cols < container->col + container->colspan;
+                             cols += t_ws->table[cols][new_row]->colspan) {
+                                DLOG("candidate: new_row = %d, cols = %d\n", new_row, cols);
+                                if (t_ws->table[cols][new_row]->currently_focused == NULL)
+                                        continue;
+
+                                new_col = cols;
+                                DLOG("Fixed it to new col %d\n", new_col);
                                 break;
                         }
-                        DLOG("Fixed it to new col %d\n", new_col);
                 }
         } else if (direction == D_LEFT || direction == D_RIGHT) {
                 if (direction == D_RIGHT && cell_exists(t_ws, current_col+1, current_row))
@@ -216,7 +235,7 @@ static void focus_thing(xcb_connection_t *conn, direction_t direction, thing_t t
                         new_col = (direction == D_LEFT ? (t_ws->cols - 1) : 0);
                 }
 
-                check_colrow_boundaries();
+                CHECK_COLROW_BOUNDARIES;
 
                 DLOG("new_col = %d, new_row = %d\n", new_col, new_row);
                 if (t_ws->table[new_col][new_row]->currently_focused == NULL) {
@@ -226,16 +245,34 @@ static void focus_thing(xcb_connection_t *conn, direction_t direction, thing_t t
                                         continue;
 
                                 new_row = rows;
+                                DLOG("Fixed it to new row %d\n", new_row);
                                 break;
                         }
-                        DLOG("Fixed it to new row %d\n", new_row);
                 }
+
+                if (t_ws->table[new_col][new_row]->currently_focused == NULL) {
+                        DLOG("Cell still empty, checking for full cols near full spanned height...\n");
+                        DLOG("new_row = %d\n", new_row);
+                        DLOG("rowspan = %d\n", container->rowspan);
+                        for (int rows = new_row;
+                             rows < container->row + container->rowspan;
+                             rows += t_ws->table[new_col][rows]->rowspan) {
+                                DLOG("candidate: new_col = %d, rows = %d\n", new_col, rows);
+                                if (t_ws->table[new_col][rows]->currently_focused == NULL)
+                                        continue;
+
+                                new_row = rows;
+                                DLOG("Fixed it to new col %d\n", new_row);
+                                break;
+                        }
+                }
+
         } else {
                 ELOG("direction unhandled\n");
                 return;
         }
 
-        check_colrow_boundaries();
+        CHECK_COLROW_BOUNDARIES;
 
         if (t_ws->table[new_col][new_row]->currently_focused != NULL)
                 set_focus(conn, t_ws->table[new_col][new_row]->currently_focused, true);
@@ -563,12 +600,30 @@ static void move_floating_window_to_workspace(xcb_connection_t *conn, Client *cl
                 xcb_flush(conn);
         }
 
+        /* Configure the window above all tiling windows (or below a fullscreen
+         * window, if any) */
+        if (t_ws->fullscreen_client != NULL) {
+                uint32_t values[] = { t_ws->fullscreen_client->frame, XCB_STACK_MODE_BELOW };
+                xcb_configure_window(conn, client->frame, XCB_CONFIG_WINDOW_SIBLING | XCB_CONFIG_WINDOW_STACK_MODE, values);
+        } else {
+                Client *last_tiling;
+                SLIST_FOREACH(last_tiling, &(t_ws->focus_stack), focus_clients)
+                        if (!client_is_floating(last_tiling))
+                                break;
+                if (last_tiling != SLIST_END(&(t_ws->focus_stack))) {
+                        uint32_t values[] = { last_tiling->frame, XCB_STACK_MODE_ABOVE };
+                        xcb_configure_window(conn, client->frame, XCB_CONFIG_WINDOW_SIBLING | XCB_CONFIG_WINDOW_STACK_MODE, values);
+                }
+        }
+
         DLOG("done\n");
 
         render_layout(conn);
 
-        if (workspace_is_visible(t_ws))
+        if (workspace_is_visible(t_ws)) {
+                client_warp_pointer_into(conn, client);
                 set_focus(conn, client, true);
+        }
 }
 
 /*
@@ -628,7 +683,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);
                 }
         }
 
@@ -666,6 +721,7 @@ static void jump_to_window(xcb_connection_t *conn, const char *arguments) {
         }
 
         free(classtitle);
+        workspace_show(conn, client->workspace->num + 1);
         set_focus(conn, client, true);
 }
 
@@ -979,12 +1035,16 @@ void parse_command(xcb_connection_t *conn, const char *command) {
         if (STARTS_WITH(command, "exit")) {
                 LOG("User issued exit-command, exiting without error.\n");
                 restore_geometry(global_conn);
+                ipc_shutdown();
                 exit(EXIT_SUCCESS);
         }
 
         /* Is it a <reload>? */
         if (STARTS_WITH(command, "reload")) {
                 load_configuration(conn, NULL, true);
+                render_layout(conn);
+                /* Send an IPC event just in case the ws names have changed */
+                ipc_send_event("workspace", I3_IPC_EVENT_WORKSPACE, "{\"change\":\"reload\"}");
                 return;
         }
 
@@ -1020,11 +1080,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;
         }
 
@@ -1036,9 +1099,9 @@ void parse_command(xcb_connection_t *conn, const char *command) {
                 }
                 LOG("Switching mode for current container\n");
                 int new_mode = MODE_DEFAULT;
-                if (command[0] == 's')
+                if (command[0] == 's' && CUR_CELL->mode != MODE_STACK)
                         new_mode = MODE_STACK;
-                if (command[0] == 'T')
+                if (command[0] == 'T' && CUR_CELL->mode != MODE_TABBED)
                         new_mode = MODE_TABBED;
                 switch_layout_mode(conn, CUR_CELL, new_mode);
                 return;
@@ -1108,6 +1171,9 @@ void parse_command(xcb_connection_t *conn, const char *command) {
 
                 Workspace *ws = last_focused->workspace;
 
+                if (last_focused->fullscreen)
+                        client_leave_fullscreen(conn, last_focused);
+
                 toggle_floating_mode(conn, last_focused, false);
                 /* delete all empty columns/rows */
                 cleanup_table(conn, ws);