]> git.sur5r.net Git - i3/i3/blobdiff - src/commands.c
Bugfix: don’t errnously render floating fullscreen windows during restart
[i3/i3] / src / commands.c
index d8eff106f59e318894d5bac80308751ad6c9d901..d6c6fc412ee112286a0ccc172b4854d577fee660 100644 (file)
 #include "shmlog.h"
 
 // Macros to make the YAJL API a bit easier to use.
-#define y(x, ...) yajl_gen_ ## x (cmd_output->json_gen, ##__VA_ARGS__)
-#define ystr(str) yajl_gen_string(cmd_output->json_gen, (unsigned char*)str, strlen(str))
+#define y(x, ...) (cmd_output->json_gen != NULL ? yajl_gen_ ## x (cmd_output->json_gen, ##__VA_ARGS__) : 0)
+#define ystr(str) (cmd_output->json_gen != NULL ? yajl_gen_string(cmd_output->json_gen, (unsigned char*)str, strlen(str)) : 0)
 #define ysuccess(success) do { \
-    y(map_open); \
-    ystr("success"); \
-    y(bool, success); \
-    y(map_close); \
+    if (cmd_output->json_gen != NULL) { \
+        y(map_open); \
+        ystr("success"); \
+        y(bool, success); \
+        y(map_close); \
+    } \
 } while (0)
 #define yerror(message) do { \
-    y(map_open); \
-    ystr("success"); \
-    y(bool, false); \
-    ystr("error"); \
-    ystr(message); \
-    y(map_close); \
+    if (cmd_output->json_gen != NULL) { \
+        y(map_open); \
+        ystr("success"); \
+        y(bool, false); \
+        ystr("error"); \
+        ystr(message); \
+        y(map_close); \
+    } \
 } while (0)
 
 /** When the command did not include match criteria (!), we use the currently
@@ -95,7 +99,7 @@ static Output *get_output_of_con(Con *con) {
  * and return true, signaling that no further workspace switching should occur in the calling function.
  *
  */
-static bool maybe_back_and_forth(struct CommandResult *cmd_output, char *name) {
+static bool maybe_back_and_forth(struct CommandResultIR *cmd_output, char *name) {
     Con *ws = con_get_workspace(focused);
 
     /* If we switched to a different workspace, do nothing */
@@ -257,6 +261,7 @@ void cmd_criteria_init(I3_CMD) {
     owindow *ow;
 
     DLOG("Initializing criteria, current_match = %p\n", current_match);
+    match_free(current_match);
     match_init(current_match);
     while (!TAILQ_EMPTY(&owindows)) {
         ow = TAILQ_FIRST(&owindows);
@@ -297,15 +302,16 @@ void cmd_criteria_match_windows(I3_CMD) {
             if (current_match->con_id == current->con) {
                 DLOG("matches container!\n");
                 TAILQ_INSERT_TAIL(&owindows, current, owindows);
+            } else {
+                DLOG("doesnt match\n");
+                free(current);
             }
         } else if (current_match->mark != NULL && current->con->mark != NULL &&
                    regex_matches(current_match->mark, current->con->mark)) {
             DLOG("match by mark\n");
             TAILQ_INSERT_TAIL(&owindows, current, owindows);
         } else {
-            if (current->con->window == NULL)
-                continue;
-            if (match_matches_window(current_match, current->con->window)) {
+            if (current->con->window && match_matches_window(current_match, current->con->window)) {
                 DLOG("matches window!\n");
                 TAILQ_INSERT_TAIL(&owindows, current, owindows);
             } else {
@@ -353,7 +359,7 @@ void cmd_criteria_add(I3_CMD, char *ctype, char *cvalue) {
             ELOG("Could not parse con id \"%s\"\n", cvalue);
         } else {
             current_match->con_id = (Con*)parsed;
-            printf("id as int = %p\n", current_match->con_id);
+            DLOG("id as int = %p\n", current_match->con_id);
         }
         return;
     }
@@ -368,7 +374,7 @@ void cmd_criteria_add(I3_CMD, char *ctype, char *cvalue) {
             ELOG("Could not parse window id \"%s\"\n", cvalue);
         } else {
             current_match->id = parsed;
-            printf("window id as int = %d\n", current_match->id);
+            DLOG("window id as int = %d\n", current_match->id);
         }
         return;
     }
@@ -481,8 +487,8 @@ void cmd_move_con_to_workspace_back_and_forth(I3_CMD) {
  *
  */
 void cmd_move_con_to_workspace_name(I3_CMD, char *name) {
-    if (strncasecmp(name, "__i3_", strlen("__i3_")) == 0) {
-        LOG("You cannot switch to the i3 internal workspaces.\n");
+    if (strncasecmp(name, "__", strlen("__")) == 0) {
+        LOG("You cannot move containers to i3-internal workspaces (\"%s\").\n", name);
         ysuccess(false);
         return;
     }
@@ -779,6 +785,12 @@ void cmd_resize(I3_CMD, char *way, char *direction, char *resize_px, char *resiz
 
     owindow *current;
     TAILQ_FOREACH(current, &owindows, owindows) {
+        /* Don't handle dock windows (issue #1201) */
+        if (current->con->window && current->con->window->dock) {
+            DLOG("This is a dock window. Not resizing (con = %p)\n)", current->con);
+            continue;
+        }
+
         Con *floating_con;
         if ((floating_con = con_inside_floating(current->con))) {
             cmd_resize_floating(current_match, cmd_output, way, direction, floating_con, px);
@@ -869,7 +881,26 @@ void cmd_nop(I3_CMD, char *comment) {
 void cmd_append_layout(I3_CMD, char *path) {
     LOG("Appending layout \"%s\"\n", path);
     Con *parent = focused;
-    tree_append_json(path);
+    /* We need to append the layout to a split container, since a leaf
+     * container must not have any children (by definition).
+     * Note that we explicitly check for workspaces, since they are okay for
+     * this purpose, but con_accepts_window() returns false for workspaces. */
+    while (parent->type != CT_WORKSPACE && !con_accepts_window(parent))
+        parent = parent->parent;
+    DLOG("Appending to parent=%p instead of focused=%p\n",
+         parent, focused);
+    char *errormsg = NULL;
+    tree_append_json(parent, path, &errormsg);
+    if (errormsg != NULL) {
+        yerror(errormsg);
+        free(errormsg);
+        /* Note that we continue executing since tree_append_json() has
+         * side-effects — user-provided layouts can be partly valid, partly
+         * invalid, leading to half of the placeholder containers being
+         * created. */
+    } else {
+        ysuccess(true);
+    }
 
     // XXX: This is a bit of a kludge. Theoretically, render_con(parent,
     // false); should be enough, but when sending 'workspace 4; append_layout
@@ -882,8 +913,6 @@ void cmd_append_layout(I3_CMD, char *path) {
     restore_open_placeholder_windows(parent);
 
     cmd_output->needs_tree_render = true;
-    // XXX: default reply for now, make this a better reply
-    ysuccess(true);
 }
 
 /*
@@ -973,8 +1002,8 @@ void cmd_workspace_back_and_forth(I3_CMD) {
  *
  */
 void cmd_workspace_name(I3_CMD, char *name) {
-    if (strncasecmp(name, "__i3_", strlen("__i3_")) == 0) {
-        LOG("You cannot switch to the i3 internal workspaces.\n");
+    if (strncasecmp(name, "__", strlen("__")) == 0) {
+        LOG("You cannot switch to the i3-internal workspaces (\"%s\").\n", name);
         ysuccess(false);
         return;
     }
@@ -1620,6 +1649,8 @@ void cmd_layout_toggle(I3_CMD, char *toggle_mode) {
  */
 void cmd_exit(I3_CMD) {
     LOG("Exiting due to user command.\n");
+    ipc_shutdown();
+    unlink(config.ipc_socket_path);
     xcb_disconnect(conn);
     exit(0);
 
@@ -1651,6 +1682,14 @@ void cmd_reload(I3_CMD) {
  */
 void cmd_restart(I3_CMD) {
     LOG("restarting i3\n");
+    ipc_shutdown();
+    /* We need to call this manually since atexit handlers don’t get called
+     * when exec()ing */
+    purge_zerobyte_logfile();
+    /* The unlink call is intentionally after the purge_zerobyte_logfile() so
+     * that the latter does not remove the directory yet. We need to store the
+     * restart layout state in there. */
+    unlink(config.ipc_socket_path);
     i3_restart(false);
 
     // XXX: default reply for now, make this a better reply
@@ -1842,6 +1881,11 @@ void cmd_scratchpad_show(I3_CMD) {
  *
  */
 void cmd_rename_workspace(I3_CMD, char *old_name, char *new_name) {
+    if (strncasecmp(new_name, "__", strlen("__")) == 0) {
+        LOG("Cannot rename workspace to \"%s\": names starting with __ are i3-internal.", new_name);
+        ysuccess(false);
+        return;
+    }
     if (old_name) {
         LOG("Renaming workspace \"%s\" to \"%s\"\n", old_name, new_name);
     } else {