From 4a585748a475b23f55aa6b62cd1029453f15fb86 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ingo=20B=C3=BCrk?= Date: Sun, 3 May 2015 00:19:26 +0200 Subject: [PATCH 1/4] Implemented new command 'move [window|container] [to] position mouse|cursor|pointer fixes #1696 --- include/commands.h | 6 ++++++ include/floating.h | 6 ++++++ parser-specs/commands.spec | 3 +++ src/commands.c | 24 ++++++++++++++++++++++++ src/floating.c | 32 ++++++++++++++++++++++++++++++++ 5 files changed, 71 insertions(+) diff --git a/include/commands.h b/include/commands.h index bbcd7f6f..afb3c32a 100644 --- a/include/commands.h +++ b/include/commands.h @@ -258,6 +258,12 @@ void cmd_move_window_to_position(I3_CMD, char *method, char *x, char *y); */ void cmd_move_window_to_center(I3_CMD, char *method); +/** + * Implementation of 'move [window|container] [to] position mouse' + * + */ +void cmd_move_window_to_mouse(I3_CMD); + /** * Implementation of 'move scratchpad'. * diff --git a/include/floating.h b/include/floating.h index 5e7b8e31..78e75be8 100644 --- a/include/floating.h +++ b/include/floating.h @@ -70,6 +70,12 @@ bool floating_maybe_reassign_ws(Con *con); */ void floating_center(Con *con, Rect rect); +/** + * Moves the given floating con to the current pointer position. + * + */ +void floating_move_to_pointer(Con *con); + #if 0 /** * Removes the floating client from its workspace and attaches it to the new diff --git a/parser-specs/commands.spec b/parser-specs/commands.spec index 1cd8d2f6..8d497cd1 100644 --- a/parser-specs/commands.spec +++ b/parser-specs/commands.spec @@ -271,6 +271,7 @@ state RENAME_WORKSPACE_NEW_NAME: # move workspace to [output] # move scratchpad # move [window|container] [to] [absolute] position [ [ [px] [px]] | center ] +# move [window|container] [to] position mouse|cursor|pointer state MOVE: 'window' -> @@ -342,6 +343,8 @@ state MOVE_TO_ABSOLUTE_POSITION: state MOVE_TO_POSITION: 'center' -> call cmd_move_window_to_center($method) + 'mouse', 'cursor', 'pointer' + -> call cmd_move_window_to_mouse() coord_x = word -> MOVE_TO_POSITION_X diff --git a/src/commands.c b/src/commands.c index 3263dd03..1f5c8f44 100644 --- a/src/commands.c +++ b/src/commands.c @@ -1833,6 +1833,30 @@ void cmd_move_window_to_center(I3_CMD, char *method) { ysuccess(true); } +/* + * Implementation of 'move [window|container] [to] position mouse' + * + */ +void cmd_move_window_to_mouse(I3_CMD) { + HANDLE_EMPTY_MATCH; + + owindow *current; + TAILQ_FOREACH(current, &owindows, owindows) { + Con *floating_con = con_inside_floating(current->con); + if (floating_con == NULL) { + DLOG("con %p / %s is not floating, cannot move it to the mouse position.\n", + current->con, current->con->name); + continue; + } + + DLOG("moving floating container %p / %s to cursor position\n", floating_con, floating_con->name); + floating_move_to_pointer(floating_con); + } + + cmd_output->needs_tree_render = true; + ysuccess(true); +} + /* * Implementation of 'move scratchpad'. * diff --git a/src/floating.c b/src/floating.c index f5641fff..d44334fe 100644 --- a/src/floating.c +++ b/src/floating.c @@ -426,6 +426,38 @@ void floating_center(Con *con, Rect rect) { con->rect.y = rect.y + (rect.height / 2) - (con->rect.height / 2); } +/* + * Moves the given floating con to the current pointer position. + * + */ +void floating_move_to_pointer(Con *con) { + assert(con->type == CT_FLOATING_CON); + + xcb_query_pointer_reply_t *reply = xcb_query_pointer_reply(conn, xcb_query_pointer(conn, root), NULL); + if (reply == NULL) { + ELOG("could not query pointer position, not moving this container\n"); + return; + } + + Output *output = get_output_containing(reply->root_x, reply->root_y); + + /* Determine where to put the window. */ + int32_t x = reply->root_x - con->rect.width / 2; + int32_t y = reply->root_y - con->rect.height / 2; + FREE(reply); + + /* Correct target coordinates to be in-bounds. */ + x = MAX(x, (int32_t)output->rect.x); + y = MAX(y, (int32_t)output->rect.y); + if (x + con->rect.width > output->rect.x + output->rect.width) + x = output->rect.x + output->rect.width - con->rect.width; + if (y + con->rect.height > output->rect.y + output->rect.height) + y = output->rect.y + output->rect.height - con->rect.height; + + /* Update container's coordinates to position it correctly. */ + floating_reposition(con, (Rect){x, y, con->rect.width, con->rect.height}); +} + DRAGGING_CB(drag_window_callback) { const struct xcb_button_press_event_t *event = extra; From d2cfe38c048302db7c7d5b306d11ed5c8845ff49 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ingo=20B=C3=BCrk?= Date: Sun, 3 May 2015 14:59:30 +0200 Subject: [PATCH 2/4] Added 'move position mouse' command to the userguide. --- docs/userguide | 68 +++++++++++++++++++++++++++++++++----------------- 1 file changed, 45 insertions(+), 23 deletions(-) diff --git a/docs/userguide b/docs/userguide index 301d8c81..d52e8045 100644 --- a/docs/userguide +++ b/docs/userguide @@ -1637,15 +1637,17 @@ bindsym $mod+f fullscreen toggle bindsym $mod+t floating toggle -------------- -=== Focusing/Moving containers +[[_focusing_moving_containers]] -To change the focus, use the focus command: +focus left+, +focus right+, +focus -down+ and +focus up+. +=== Focusing containers -There are a few special parameters you can use for the focus command: +To change focus, you can use the +focus+ command. The following options are +available: +left|right|up|down:: + Sets focus to the nearest container in the given direction. parent:: - Sets focus to the +Parent Container+ of the current +Container+. + Sets focus to the parent container of the current container. child:: The opposite of +focus parent+, sets the focus to the last focused child container. @@ -1659,23 +1661,16 @@ output:: Followed by a direction or an output name, this will focus the corresponding output. -For moving, use +move left+, +move right+, +move down+ and +move up+. - *Syntax*: ------------------------------------ -focus -focus -focus output <|output> -move [ px] -move [absolute] position [[ px] [ px]|center] ------------------------------------ - -Note that the amount of pixels you can specify for the +move+ command is only -relevant for floating containers. The default amount is 10 pixels. +---------------------------------------------- +focus left|right|down|up +focus parent|child|floating|tiling|mode_toggle +focus output left|right|up|down| +---------------------------------------------- *Examples*: ----------------------- -# Focus container on the left, bottom, top, right: +------------------------------------------------- +# Focus container on the left, bottom, top, right bindsym $mod+j focus left bindsym $mod+k focus down bindsym $mod+l focus up @@ -1692,8 +1687,33 @@ bindsym $mod+x focus output right # Focus the big output bindsym $mod+x focus output HDMI-2 +------------------------------------------------- -# Move container to the left, bottom, top, right: +=== Moving containers + +Use the +move+ command to move a container. + +*Syntax*: +----------------------------------------------------- +# Moves the container into the given direction. +# The optional pixel argument specifies how far the +# container should be moved if it is floating and +# defaults to 10 pixels. +move [ px] + +# Moves the container either to a specific location +# or to the center of the screen. If 'absolute' is +# used, it is moved to the center of all outputs. +move [absolute] position [[ px] [ px]|center] + +# Moves the container to the current position of the +# mouse cursor. Only affects floating containers. +move position mouse +----------------------------------------------------- + +*Examples*: +------------------------------------------------------- +# Move container to the left, bottom, top, right bindsym $mod+j move left bindsym $mod+k move down bindsym $mod+l move up @@ -1703,10 +1723,12 @@ bindsym $mod+semicolon move right # move more than the default bindsym $mod+j move left 20 px -# Move floating container to the center -# of all outputs +# Move floating container to the center of all outputs bindsym $mod+c move absolute position center ----------------------- + +# Move container to the current position of the cursor +bindsym $mod+m move position mouse +------------------------------------------------------- === Changing (named) workspaces/moving to workspaces From fbbe9cf2e8648fe05b682d4004e6a63750b54a67 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ingo=20B=C3=BCrk?= Date: Sun, 3 May 2015 16:19:23 +0200 Subject: [PATCH 3/4] Added testcases for 'move position mouse' --- testcases/t/245-move-position-mouse.t | 142 ++++++++++++++++++++++++++ 1 file changed, 142 insertions(+) create mode 100644 testcases/t/245-move-position-mouse.t diff --git a/testcases/t/245-move-position-mouse.t b/testcases/t/245-move-position-mouse.t new file mode 100644 index 00000000..ae049271 --- /dev/null +++ b/testcases/t/245-move-position-mouse.t @@ -0,0 +1,142 @@ +#!perl +# vim:ts=4:sw=4:expandtab +# +# Please read the following documents before working on tests: +# • http://build.i3wm.org/docs/testsuite.html +# (or docs/testsuite) +# +# • http://build.i3wm.org/docs/lib-i3test.html +# (alternatively: perldoc ./testcases/lib/i3test.pm) +# +# • http://build.i3wm.org/docs/ipc.html +# (or docs/ipc) +# +# • http://onyxneon.com/books/modern_perl/modern_perl_a4.pdf +# (unless you are already familiar with Perl) +# +# Tests the 'move [window|container] [to] position mouse|cursor|pointer command. +# Ticket: #1696 +use i3test i3_autostart => 0; +use POSIX qw(floor); + +sub warp_pointer { + my ($pos_x, $pos_y) = @_; + $x->root->warp_pointer($pos_x, $pos_y); + sync_with_i3; +} + +my ($pid, $config, $ws, $rect, @cons); +my $root_rect = $x->root->rect; + +########################################################################## + +########################################################################## +# Given a floating container and the cursor far from any edges, when +# moving the container to the mouse, then the container is moved such +# that the cursor is centered inside it. +########################################################################## + +$config = <{floating_nodes}}; +$rect = $cons[0]->{rect}; + +is(floor($rect->{x} + $rect->{width} / 2), 100, "con is centered around cursor horizontally"); +is(floor($rect->{y} + $rect->{height} / 2), 100, "con is centered around cursor vertically"); + +exit_gracefully($pid); + +########################################################################## +# Given a floating container and the cursor is in the left upper edge +# of the output, when moving the container to the mouse, then the +# container is moved but adjusted to stay in-bounds. +########################################################################## + +$config = <{floating_nodes}}; +$rect = $cons[0]->{rect}; + +is($rect->{x}, 0, "con is on the left edge"); +is($rect->{y}, 0, "con is on the upper edge"); + +exit_gracefully($pid); + +########################################################################## +# Given a floating container and the cursor is in the left right lower +# edge of the output, when moving the container to the mouse, then the +# container is moved but adjusted to stay in-bounds. +########################################################################## + +$config = <width - 5, $root_rect->height - 5); + +cmd 'move position mouse'; + +@cons = @{get_ws($ws)->{floating_nodes}}; +$rect = $cons[0]->{rect}; + +is($rect->{x} + $rect->{width}, $root_rect->width, "con is on the right edge"); +is($rect->{y} + $rect->{height}, $root_rect->height, "con is on the lower edge"); + +exit_gracefully($pid); + +########################################################################## +# Given a floating container and the cursor being close to the corner of +# an output, when the container is moved to the mouse, then the container +# is moved but adjusted to the output boundaries. +# This test verifies that boundaries of individual outputs are respected +# and not just boundaries of the entire X root screen. +########################################################################## + +$config = <{floating_nodes}}; +$rect = $cons[0]->{rect}; + +is($rect->{x} + $rect->{width}, 500, "con is on the right edge"); +is($rect->{y} + $rect->{height}, 500, "con is on the lower edge"); + +exit_gracefully($pid); + +########################################################################## + +done_testing; From 8801de2399e0c28f3c9acbc717d79fa374f1979f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ingo=20B=C3=BCrk?= Date: Thu, 14 May 2015 13:07:56 -0400 Subject: [PATCH 4/4] Protect "move position mouse" against a NULL access. This could happen if two outputs are set up to have a gap in between them and the mouse cursor being in said gap when the command is triggered. --- src/floating.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/floating.c b/src/floating.c index d44334fe..a2843535 100644 --- a/src/floating.c +++ b/src/floating.c @@ -440,6 +440,10 @@ void floating_move_to_pointer(Con *con) { } Output *output = get_output_containing(reply->root_x, reply->root_y); + if (output == NULL) { + ELOG("The pointer is not on any output, cannot move the container here."); + return; + } /* Determine where to put the window. */ int32_t x = reply->root_x - con->rect.width / 2;