y(map_close); \
} \
} while (0)
-#define yerror(message) \
- do { \
- if (cmd_output->json_gen != NULL) { \
- y(map_open); \
- ystr("success"); \
- y(bool, false); \
- ystr("error"); \
- ystr(message); \
- y(map_close); \
- } \
+#define yerror(format, ...) \
+ do { \
+ if (cmd_output->json_gen != NULL) { \
+ char *message; \
+ sasprintf(&message, format, ##__VA_ARGS__); \
+ y(map_open); \
+ ystr("success"); \
+ y(bool, false); \
+ ystr("error"); \
+ ystr(message); \
+ y(map_close); \
+ free(message); \
+ } \
} while (0)
/** When the command did not include match criteria (!), we use the currently
LOG("should move window to workspace %s\n", name);
/* get the workspace */
- Con *ws = workspace_get(name, NULL);
+ Con *ws = NULL;
+ Con *output = NULL;
+
+ /* first look for a workspace with this name */
+ TAILQ_FOREACH(output, &(croot->nodes_head), nodes) {
+ GREP_FIRST(ws, output_get_content(output), !strcasecmp(child->name, name));
+ }
+
+ /* if the name is plain digits, we interpret this as a "workspace number"
+ * command */
+ if (!ws && name_is_digits(name)) {
+ long parsed_num = ws_name_to_number(name);
+ TAILQ_FOREACH(output, &(croot->nodes_head), nodes) {
+ GREP_FIRST(ws, output_get_content(output),
+ child->num == parsed_num);
+ }
+ }
+
+ /* if no workspace was found, make a new one */
+ if (!ws)
+ ws = workspace_get(name, NULL);
ws = maybe_auto_back_and_forth_workspace(ws);
if (parsed_num == -1) {
LOG("Could not parse initial part of \"%s\" as a number.\n", which);
- // TODO: better error message
- yerror("Could not parse number");
+ yerror("Could not parse number \"%s\"", which);
return;
}
*/
void cmd_append_layout(I3_CMD, char *path) {
LOG("Appending layout \"%s\"\n", path);
+
+ json_content_t content = json_determine_content(path);
+ LOG("JSON content = %d\n", content);
+ if (content == JSON_CONTENT_UNKNOWN) {
+ ELOG("Could not determine the contents of \"%s\", not loading.\n", path);
+ ysuccess(false);
+ return;
+ }
+
Con *parent = focused;
- /* 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);
+ if (content == JSON_CONTENT_WORKSPACE) {
+ parent = output_get_content(con_get_output(parent));
+ } else {
+ /* 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) {
restore_open_placeholder_windows(parent);
+ if (content == JSON_CONTENT_WORKSPACE)
+ ipc_send_workspace_event("restored", parent, NULL);
+
cmd_output->needs_tree_render = true;
}
DLOG("which=%s\n", which);
+ if (con_get_fullscreen_con(croot, CF_GLOBAL)) {
+ LOG("Cannot switch workspace while in global fullscreen\n");
+ ysuccess(false);
+ return;
+ }
+
if (strcmp(which, "next") == 0)
ws = workspace_next();
else if (strcmp(which, "prev") == 0)
void cmd_workspace_number(I3_CMD, char *which) {
Con *output, *workspace = NULL;
+ if (con_get_fullscreen_con(croot, CF_GLOBAL)) {
+ LOG("Cannot switch workspace while in global fullscreen\n");
+ ysuccess(false);
+ return;
+ }
+
long parsed_num = ws_name_to_number(which);
if (parsed_num == -1) {
LOG("Could not parse initial part of \"%s\" as a number.\n", which);
- // TODO: better error message
- yerror("Could not parse number");
+ yerror("Could not parse number \"%s\"", which);
return;
}
*
*/
void cmd_workspace_back_and_forth(I3_CMD) {
+ if (con_get_fullscreen_con(croot, CF_GLOBAL)) {
+ LOG("Cannot switch workspace while in global fullscreen\n");
+ ysuccess(false);
+ return;
+ }
+
workspace_back_and_forth();
cmd_output->needs_tree_render = true;
return;
}
+ if (con_get_fullscreen_con(croot, CF_GLOBAL)) {
+ LOG("Cannot switch workspace while in global fullscreen\n");
+ ysuccess(false);
+ return;
+ }
+
DLOG("should switch to workspace %s\n", name);
if (maybe_back_and_forth(cmd_output, name))
return;
- workspace_show_by_name(name);
+
+ Con *ws = NULL;
+ Con *output = NULL;
+
+ /* first look for a workspace with this name */
+ TAILQ_FOREACH(output, &(croot->nodes_head), nodes) {
+ GREP_FIRST(ws, output_get_content(output), !strcasecmp(child->name, name));
+ }
+
+ /* if the name is only digits, we interpret this as a "workspace number"
+ * command */
+ if (!ws && name_is_digits(name)) {
+ long parsed_num = ws_name_to_number(name);
+ TAILQ_FOREACH(output, &(croot->nodes_head), nodes) {
+ GREP_FIRST(ws, output_get_content(output),
+ child->num == parsed_num);
+ }
+ }
+
+ /* if no workspace was found, make a new one */
+ if (!ws)
+ ws = workspace_get(name, NULL);
+
+ workspace_show(ws);
cmd_output->needs_tree_render = true;
// XXX: default reply for now, make this a better reply
create_workspace_on_output(current_output, ws->parent);
/* notify the IPC listeners */
- ipc_send_event("workspace", I3_IPC_EVENT_WORKSPACE, "{\"change\":\"init\"}");
+ ipc_send_workspace_event("init", ws, NULL);
}
DLOG("Detaching\n");
TAILQ_FOREACH(floating_con, &(ws->floating_head), floating_windows)
floating_fix_coordinates(floating_con, &(old_content->rect), &(content->rect));
- ipc_send_event("workspace", I3_IPC_EVENT_WORKSPACE, "{\"change\":\"move\"}");
+ ipc_send_workspace_event("move", ws, NULL);
if (workspace_was_visible) {
/* Focus the moved workspace on the destination output. */
workspace_show(ws);
}
/*
- * Implementation of 'fullscreen [global]'.
+ * Implementation of 'fullscreen enable|toggle [global]' and
+ * 'fullscreen disable'
*
*/
-void cmd_fullscreen(I3_CMD, char *fullscreen_mode) {
- if (fullscreen_mode == NULL)
- fullscreen_mode = "output";
- DLOG("toggling fullscreen, mode = %s\n", fullscreen_mode);
+void cmd_fullscreen(I3_CMD, char *action, char *fullscreen_mode) {
+ fullscreen_mode_t mode = strcmp(fullscreen_mode, "global") == 0 ? CF_GLOBAL : CF_OUTPUT;
+ DLOG("%s fullscreen, mode = %s\n", action, fullscreen_mode);
owindow *current;
HANDLE_EMPTY_MATCH;
TAILQ_FOREACH(current, &owindows, owindows) {
DLOG("matching: %p / %s\n", current->con, current->con->name);
- con_toggle_fullscreen(current->con, (strcmp(fullscreen_mode, "global") == 0 ? CF_GLOBAL : CF_OUTPUT));
+ if (strcmp(action, "toggle") == 0) {
+ con_toggle_fullscreen(current->con, mode);
+ } else if (strcmp(action, "enable") == 0) {
+ con_enable_fullscreen(current->con, mode);
+ } else if (strcmp(action, "disable") == 0) {
+ con_disable_fullscreen(current->con);
+ }
}
cmd_output->needs_tree_render = true;
Con *initially_focused = focused;
- TAILQ_FOREACH (current, &owindows, owindows) {
+ TAILQ_FOREACH(current, &owindows, owindows) {
DLOG("moving in direction %s, px %s\n", direction, move_px);
if (con_is_floating(current->con)) {
DLOG("floating move with %d pixels\n", px);
load_configuration(conn, NULL, true);
x_set_i3_atoms();
/* Send an IPC event just in case the ws names have changed */
- ipc_send_event("workspace", I3_IPC_EVENT_WORKSPACE, "{\"change\":\"reload\"}");
+ ipc_send_workspace_event("reload", NULL, NULL);
/* Send an update event for the barconfig just in case it has changed */
update_barconfig();
void cmd_restart(I3_CMD) {
LOG("restarting i3\n");
ipc_shutdown();
+ unlink(config.ipc_socket_path);
/* 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
void cmd_move_window_to_position(I3_CMD, char *method, char *cx, char *cy) {
int x = atoi(cx);
int y = atoi(cy);
+ bool has_error = false;
- if (!con_is_floating(focused)) {
- ELOG("Cannot change position. The window/container is not floating\n");
- yerror("Cannot change position. The window/container is not floating.");
- return;
- }
+ owindow *current;
+ HANDLE_EMPTY_MATCH;
- if (strcmp(method, "absolute") == 0) {
- focused->parent->rect.x = x;
- focused->parent->rect.y = y;
+ TAILQ_FOREACH(current, &owindows, owindows) {
+ if (!con_is_floating(current->con)) {
+ ELOG("Cannot change position. The window/container is not floating\n");
- DLOG("moving to absolute position %d %d\n", x, y);
- floating_maybe_reassign_ws(focused->parent);
- cmd_output->needs_tree_render = true;
- }
+ if (!has_error) {
+ yerror("Cannot change position of a window/container because it is not floating.");
+ has_error = true;
+ }
- if (strcmp(method, "position") == 0) {
- Rect newrect = focused->parent->rect;
+ continue;
+ }
- DLOG("moving to position %d %d\n", x, y);
- newrect.x = x;
- newrect.y = y;
+ if (strcmp(method, "absolute") == 0) {
+ current->con->parent->rect.x = x;
+ current->con->parent->rect.y = y;
- floating_reposition(focused->parent, newrect);
+ DLOG("moving to absolute position %d %d\n", x, y);
+ floating_maybe_reassign_ws(current->con->parent);
+ cmd_output->needs_tree_render = true;
+ }
+
+ if (strcmp(method, "position") == 0) {
+ Rect newrect = current->con->parent->rect;
+
+ DLOG("moving to position %d %d\n", x, y);
+ newrect.x = x;
+ newrect.y = y;
+
+ floating_reposition(current->con->parent, newrect);
+ }
}
// XXX: default reply for now, make this a better reply
- ysuccess(true);
+ if (!has_error)
+ ysuccess(true);
}
/*
}
if (!workspace) {
- // TODO: we should include the old workspace name here and use yajl for
- // generating the reply.
- // TODO: better error message
- yerror("Old workspace not found");
+ yerror("Old workspace \"%s\" not found", old_name);
return;
}
!strcasecmp(child->name, new_name));
if (check_dest != NULL) {
- // TODO: we should include the new workspace name here and use yajl for
- // generating the reply.
- // TODO: better error message
- yerror("New workspace already exists");
+ yerror("New workspace \"%s\" already exists", new_name);
return;
}
cmd_output->needs_tree_render = true;
ysuccess(true);
- ipc_send_event("workspace", I3_IPC_EVENT_WORKSPACE, "{\"change\":\"rename\"}");
+ ipc_send_workspace_event("rename", workspace, NULL);
+ ewmh_update_desktop_names();
+ ewmh_update_desktop_viewport();
+ ewmh_update_current_desktop();
}
/*