*
* cmdparse.y: the parser for commands you send to i3 (or bind on keys)
*
-
*/
#include <sys/types.h>
#include <sys/stat.h>
context->filename = "cmd";
if (cmdyyparse() != 0) {
fprintf(stderr, "Could not parse command\n");
- asprintf(&json_output, "{\"success\":false, \"error\":\"%s at position %d\"}",
- context->compact_error, context->first_column);
+ sasprintf(&json_output, "{\"success\":false, \"error\":\"%s at position %d\"}",
+ context->compact_error, context->first_column);
FREE(context->line_copy);
FREE(context->compact_error);
free(context);
%token TOK_OPEN "open"
%token TOK_NEXT "next"
%token TOK_PREV "prev"
+%token TOK_SCRATCHPAD "scratchpad"
+%token TOK_SHOW "show"
%token TOK_SPLIT "split"
%token TOK_HORIZONTAL "horizontal"
%token TOK_VERTICAL "vertical"
%token TOK_OR "or"
%token TOK_PPT "ppt"
%token TOK_NOP "nop"
+%token TOK_BACK_AND_FORTH "back_and_forth"
+%token TOK_NO_STARTUP_ID "--no-startup-id"
%token TOK_CLASS "class"
%token TOK_INSTANCE "instance"
%type <number> resize_way
%type <number> resize_tiling
%type <number> optional_kill_mode
+%type <number> optional_no_startup_id
%%
| mark
| resize
| nop
+ | scratchpad
| mode
;
exec:
- TOK_EXEC STR
+ TOK_EXEC optional_no_startup_id STR
{
- printf("should execute %s\n", $2);
- start_application($2);
- free($2);
+ char *command = $3;
+ bool no_startup_id = $2;
+
+ printf("should execute %s, no_startup_id = %d\n", command, no_startup_id);
+ start_application(command, no_startup_id);
+ free($3);
}
;
+optional_no_startup_id:
+ /* empty */ { $$ = false; }
+ | TOK_NO_STARTUP_ID { $$ = true; }
+ ;
+
exit:
TOK_EXIT
{
focus:
TOK_FOCUS
{
+ if (focused &&
+ focused->type != CT_WORKSPACE &&
+ focused->fullscreen_mode != CF_NONE) {
+ LOG("Cannot change focus while in fullscreen mode.\n");
+ break;
+ }
+
owindow *current;
if (match_is_empty(¤t_match)) {
ELOG("You have to specify which window/container should be focused.\n");
ELOG("Example: [class=\"urxvt\" title=\"irssi\"] focus\n");
- asprintf(&json_output, "{\"success\":false, \"error\":\"You have to "
- "specify which window/container should be focused\"}");
+ sasprintf(&json_output, "{\"success\":false, \"error\":\"You have to "
+ "specify which window/container should be focused\"}");
break;
}
int count = 0;
TAILQ_FOREACH(current, &owindows, owindows) {
Con *ws = con_get_workspace(current->con);
+ /* If no workspace could be found, this was a dock window.
+ * Just skip it, you cannot focus dock windows. */
+ if (!ws)
+ continue;
+
+ /* If the container is not on the current workspace,
+ * workspace_show() will switch to a different workspace and (if
+ * enabled) trigger a mouse pointer warp to the currently focused
+ * container (!) on the target workspace.
+ *
+ * Therefore, before calling workspace_show(), we make sure that
+ * 'current' will be focused on the workspace. However, we cannot
+ * just con_focus(current) because then the pointer will not be
+ * warped at all (the code thinks we are already there).
+ *
+ * So we focus 'current' to make it the currently focused window of
+ * the target workspace, then revert focus. */
+ Con *currently_focused = focused;
+ con_focus(current->con);
+ con_focus(currently_focused);
+
+ /* Now switch to the workspace, then focus */
workspace_show(ws);
LOG("focusing %p / %s\n", current->con, current->con->name);
con_focus(current->con);
}
| TOK_FOCUS direction
{
+ if (focused &&
+ focused->type != CT_WORKSPACE &&
+ focused->fullscreen_mode != CF_NONE) {
+ LOG("Cannot change focus while in fullscreen mode.\n");
+ break;
+ }
+
int direction = $2;
switch (direction) {
case TOK_LEFT:
}
| TOK_FOCUS window_mode
{
+ if (focused &&
+ focused->type != CT_WORKSPACE &&
+ focused->fullscreen_mode != CF_NONE) {
+ LOG("Cannot change focus while in fullscreen mode.\n");
+ break;
+ }
+
printf("should focus: ");
if ($2 == TOK_TILING)
}
| TOK_FOCUS level
{
+ if (focused &&
+ focused->type != CT_WORKSPACE &&
+ focused->fullscreen_mode != CF_NONE) {
+ LOG("Cannot change focus while in fullscreen mode.\n");
+ break;
+ }
+
if ($2 == TOK_PARENT)
level_up();
else level_down();
workspace_show(workspace_prev());
tree_render();
}
+ | TOK_WORKSPACE TOK_BACK_AND_FORTH
+ {
+ workspace_back_and_forth();
+ tree_render();
+ }
| TOK_WORKSPACE STR
{
+ if (strncasecmp($2, "__i3_", strlen("__i3_")) == 0) {
+ printf("You cannot switch to the i3 internal workspaces.\n");
+ break;
+ }
+
printf("should switch to workspace %s\n", $2);
+
+ Con *ws = con_get_workspace(focused);
+
+ /* Check if the command wants to switch to the current workspace */
+ if (strcmp(ws->name, $2) == 0) {
+ printf("This workspace is already focused.\n");
+ if (config.workspace_auto_back_and_forth) {
+ workspace_back_and_forth();
+ free($2);
+ tree_render();
+ }
+ break;
+ }
+
workspace_show_by_name($2);
free($2);
printf("opening new container\n");
Con *con = tree_open_con(NULL, NULL);
con_focus(con);
- asprintf(&json_output, "{\"success\":true, \"id\":%ld}", (long int)con);
+ sasprintf(&json_output, "{\"success\":true, \"id\":%ld}", (long int)con);
tree_render();
}
TAILQ_FOREACH(current, &owindows, owindows) {
printf("matching: %p / %s\n", current->con, current->con->name);
+ int border_style = current->con->border_style;
if ($2 == TOK_TOGGLE) {
- current->con->border_style++;
- current->con->border_style %= 3;
- } else current->con->border_style = $2;
+ border_style++;
+ border_style %= 3;
+ } else border_style = $2;
+ con_set_border_style(current->con, border_style);
}
tree_render();
;
move:
- TOK_MOVE direction
+ TOK_MOVE direction resize_px
{
- printf("moving in direction %d\n", $2);
- tree_move($2);
+ int direction = $2;
+ int px = $3;
- tree_render();
+ /* TODO: make 'move' work with criteria. */
+ printf("moving in direction %d\n", direction);
+ if (con_is_floating(focused)) {
+ printf("floating move with %d pixels\n", px);
+ Rect newrect = focused->parent->rect;
+ if (direction == TOK_LEFT) {
+ newrect.x -= px;
+ } else if (direction == TOK_RIGHT) {
+ newrect.x += px;
+ } else if (direction == TOK_UP) {
+ newrect.y -= px;
+ } else if (direction == TOK_DOWN) {
+ newrect.y += px;
+ }
+ floating_reposition(focused->parent, newrect);
+ } else {
+ tree_move(direction);
+ tree_render();
+ }
}
| TOK_MOVE TOK_WORKSPACE STR
{
+ if (strncasecmp($3, "__i3_", strlen("__i3_")) == 0) {
+ printf("You cannot switch to the i3 internal workspaces.\n");
+ break;
+ }
+
owindow *current;
+ /* Error out early to not create a non-existing workspace (in
+ * workspace_get()) if we are not actually able to move anything. */
+ if (match_is_empty(¤t_match) && focused->type == CT_WORKSPACE)
+ break;
+
printf("should move window to workspace %s\n", $3);
/* get the workspace */
Con *ws = workspace_get($3, NULL);
{
owindow *current;
- printf("should move window to output %s", $3);
+ printf("should move window to output %s\n", $3);
HANDLE_EMPTY_MATCH;
output = get_output_by_name($3);
free($3);
- if (!output)
+ if (!output) {
+ printf("No such output found.\n");
break;
+ }
/* get visible workspace on output */
Con *ws = NULL;
tree_render();
}
+ | TOK_MOVE TOK_SCRATCHPAD
+ {
+ printf("should move window to scratchpad\n");
+ owindow *current;
+
+ HANDLE_EMPTY_MATCH;
+
+ TAILQ_FOREACH(current, &owindows, owindows) {
+ printf("matching: %p / %s\n", current->con, current->con->name);
+ scratchpad_move(current->con);
+ }
+
+ tree_render();
+ }
;
append_layout:
mark:
TOK_MARK STR
{
+ printf("Clearing all windows which have that mark first\n");
+
+ Con *con;
+ TAILQ_FOREACH(con, &all_cons, all_cons) {
+ if (con->mark && strcmp(con->mark, $2) == 0)
+ FREE(con->mark);
+ }
+
printf("marking window with str %s\n", $2);
owindow *current;
TAILQ_FOREACH(current, &owindows, owindows) {
printf("matching: %p / %s\n", current->con, current->con->name);
- current->con->mark = sstrdup($2);
+ current->con->mark = $2;
}
- free($<string>2);
-
tree_render();
}
;
}
;
+scratchpad:
+ TOK_SCRATCHPAD TOK_SHOW
+ {
+ printf("should show scratchpad window\n");
+ owindow *current;
+
+ if (match_is_empty(¤t_match)) {
+ scratchpad_show(NULL);
+ } else {
+ TAILQ_FOREACH(current, &owindows, owindows) {
+ printf("matching: %p / %s\n", current->con, current->con->name);
+ scratchpad_show(current->con);
+ }
+ }
+
+ tree_render();
+ }
+ ;
+
+
resize:
TOK_RESIZE resize_way direction resize_px resize_tiling
{
ppt *= -1;
}
- if (con_is_floating(focused)) {
+ Con *floating_con;
+ if ((floating_con = con_inside_floating(focused))) {
printf("floating resize\n");
if (direction == TOK_UP) {
- focused->parent->rect.y -= px;
- focused->parent->rect.height += px;
+ floating_con->rect.y -= px;
+ floating_con->rect.height += px;
} else if (direction == TOK_DOWN) {
- focused->parent->rect.height += px;
+ floating_con->rect.height += px;
} else if (direction == TOK_LEFT) {
- focused->parent->rect.x -= px;
- focused->parent->rect.width += px;
+ floating_con->rect.x -= px;
+ floating_con->rect.width += px;
} else {
- focused->parent->rect.width += px;
+ floating_con->rect.width += px;
}
} else {
LOG("tiling resize\n");
while (current->parent->layout == L_STACKED ||
current->parent->layout == L_TABBED)
current = current->parent;
+
+ /* Then further go up until we find one with the matching orientation. */
+ orientation_t search_orientation =
+ (direction == TOK_LEFT || direction == TOK_RIGHT ? HORIZ : VERT);
+
+ while (current->type != CT_WORKSPACE &&
+ current->type != CT_FLOATING_CON &&
+ current->parent->orientation != search_orientation)
+ current = current->parent;
+
/* get the default percentage */
int children = con_num_children(current->parent);
Con *other;