Merge pull request #212 from sce/mouse_warping

Learn mouse_warping
This commit is contained in:
Drew DeVault 2015-10-29 17:52:16 -04:00
commit ca5a2a387c
10 changed files with 166 additions and 109 deletions

View file

@ -2,6 +2,7 @@
#define _SWAY_COMMANDS_H #define _SWAY_COMMANDS_H
#include <stdbool.h> #include <stdbool.h>
#include <json-c/json.h> #include <json-c/json.h>
#include <wlc/wlc.h>
#include "config.h" #include "config.h"

View file

@ -98,6 +98,8 @@ swayc_t *swayc_by_name(const char *name);
swayc_t *swayc_active_output(void); swayc_t *swayc_active_output(void);
swayc_t *swayc_active_workspace(void); swayc_t *swayc_active_workspace(void);
swayc_t *swayc_active_workspace_for(swayc_t *view); swayc_t *swayc_active_workspace_for(swayc_t *view);
// set focus to current pointer location and return focused container
swayc_t *container_under_pointer(void);
// Container information // Container information

View file

@ -5,10 +5,6 @@
#include <wlc/wlc.h> #include <wlc/wlc.h>
extern struct wlc_interface interface; extern struct wlc_interface interface;
extern struct wlc_origin mouse_origin;
extern uint32_t keys_pressed[32]; extern uint32_t keys_pressed[32];
// set focus to current pointer location and return focused container
swayc_t *container_under_pointer(void);
#endif #endif

View file

@ -48,11 +48,6 @@ extern struct pointer_state {
struct pointer_button_state right; struct pointer_button_state right;
struct pointer_button_state scroll; struct pointer_button_state scroll;
// pointer position
struct mouse_origin{
int x, y;
} origin;
// change in pointer position // change in pointer position
struct { struct {
int x, y; int x, y;
@ -65,6 +60,9 @@ extern struct pointer_state {
int mode; int mode;
} pointer_state; } pointer_state;
void pointer_position_set(struct wlc_origin *new_origin, bool force_focus);
void center_pointer_on(swayc_t *view);
// on button release unset mode depending on the button. // on button release unset mode depending on the button.
// on button press set mode conditionally depending on the button // on button press set mode conditionally depending on the button
void pointer_mode_set(uint32_t button, bool condition); void pointer_mode_set(uint32_t button, bool condition);

View file

@ -102,6 +102,10 @@ Commands
Moves the focused container to the workspace identified by _name_. Moves the focused container to the workspace identified by _name_.
_name_ may be a special workspace name. See **workspace**. _name_ may be a special workspace name. See **workspace**.
**mouse_warping** <output|none>::
When _output_: place mouse at center of newly focused window when changing
output. When _none_: don't move mouse.
**output** <name> <resolution|res WIDTHxHEIGHT> <position|pos X,Y>:: **output** <name> <resolution|res WIDTHxHEIGHT> <position|pos X,Y>::
Configures the specified output. It will use the given resolution and be Configures the specified output. It will use the given resolution and be
arranged at the given position in the layout tree. You may omit either of arranged at the given position in the layout tree. You may omit either of

View file

@ -21,6 +21,7 @@
#include "handlers.h" #include "handlers.h"
#include "sway.h" #include "sway.h"
#include "resize.h" #include "resize.h"
#include "input_state.h"
typedef struct cmd_results *sway_cmd(int argc, char **argv); typedef struct cmd_results *sway_cmd(int argc, char **argv);
@ -45,6 +46,7 @@ static sway_cmd cmd_kill;
static sway_cmd cmd_layout; static sway_cmd cmd_layout;
static sway_cmd cmd_log_colors; static sway_cmd cmd_log_colors;
static sway_cmd cmd_mode; static sway_cmd cmd_mode;
static sway_cmd cmd_mouse_warping;
static sway_cmd cmd_move; static sway_cmd cmd_move;
static sway_cmd cmd_output; static sway_cmd cmd_output;
static sway_cmd cmd_reload; static sway_cmd cmd_reload;
@ -383,9 +385,13 @@ static struct cmd_results *cmd_focus(int argc, char **argv) {
} else if (!workspace_switch(swayc_active_workspace_for(output))) { } else if (!workspace_switch(swayc_active_workspace_for(output))) {
return cmd_results_new(CMD_FAILURE, "focus output", return cmd_results_new(CMD_FAILURE, "focus output",
"Switching to workspace on output '%s' was blocked", argv[1]); "Switching to workspace on output '%s' was blocked", argv[1]);
} else { } else if (config->mouse_warping) {
return cmd_results_new(CMD_SUCCESS, NULL, NULL); swayc_t *focused = get_focused_view(output);
if (focused && focused->type == C_VIEW) {
center_pointer_on(focused);
}
} }
return cmd_results_new(CMD_SUCCESS, NULL, NULL);
} else if ((error = checkarg(argc, "focus", EXPECTED_EQUAL_TO, 1))) { } else if ((error = checkarg(argc, "focus", EXPECTED_EQUAL_TO, 1))) {
return error; return error;
} }
@ -528,6 +534,20 @@ static struct cmd_results *cmd_mode(int argc, char **argv) {
return cmd_results_new(mode_make ? CMD_BLOCK_MODE : CMD_SUCCESS, NULL, NULL); return cmd_results_new(mode_make ? CMD_BLOCK_MODE : CMD_SUCCESS, NULL, NULL);
} }
static struct cmd_results *cmd_mouse_warping(int argc, char **argv) {
struct cmd_results *error = NULL;
if ((error = checkarg(argc, "mouse_warping", EXPECTED_EQUAL_TO, 1))) {
return error;
} else if (strcasecmp(argv[0], "output") == 0) {
config->mouse_warping = true;
} else if (strcasecmp(argv[0], "none") == 0) {
config->mouse_warping = false;
} else {
return cmd_results_new(CMD_FAILURE, "mouse_warping", "Expected 'mouse_warping output|none'");
}
return cmd_results_new(CMD_SUCCESS, NULL, NULL);
}
static struct cmd_results *cmd_move(int argc, char **argv) { static struct cmd_results *cmd_move(int argc, char **argv) {
struct cmd_results *error = NULL; struct cmd_results *error = NULL;
if (config->reading) return cmd_results_new(CMD_FAILURE, "move", "Can't be used in config file."); if (config->reading) return cmd_results_new(CMD_FAILURE, "move", "Can't be used in config file.");
@ -1165,7 +1185,16 @@ static struct cmd_results *cmd_workspace(int argc, char **argv) {
ws = workspace_create(argv[0]); ws = workspace_create(argv[0]);
} }
} }
swayc_t *old_output = swayc_active_output();
workspace_switch(ws); workspace_switch(ws);
swayc_t *new_output = swayc_active_output();
if (config->mouse_warping && old_output != new_output) {
swayc_t *focused = get_focused_view(ws);
if (focused && focused->type == C_VIEW) {
center_pointer_on(focused);
}
}
} else { } else {
if (strcasecmp(argv[1], "output") == 0) { if (strcasecmp(argv[1], "output") == 0) {
if ((error = checkarg(argc, "workspace", EXPECTED_EQUAL_TO, 3))) { if ((error = checkarg(argc, "workspace", EXPECTED_EQUAL_TO, 3))) {
@ -1217,6 +1246,7 @@ static struct cmd_handler handlers[] = {
{ "layout", cmd_layout }, { "layout", cmd_layout },
{ "log_colors", cmd_log_colors }, { "log_colors", cmd_log_colors },
{ "mode", cmd_mode }, { "mode", cmd_mode },
{ "mouse_warping", cmd_mouse_warping },
{ "move", cmd_move }, { "move", cmd_move },
{ "output", cmd_output }, { "output", cmd_output },
{ "reload", cmd_reload }, { "reload", cmd_reload },

View file

@ -8,6 +8,7 @@
#include "workspace.h" #include "workspace.h"
#include "focus.h" #include "focus.h"
#include "layout.h" #include "layout.h"
#include "input_state.h"
#include "log.h" #include "log.h"
#define ASSERT_NONNULL(PTR) \ #define ASSERT_NONNULL(PTR) \
@ -508,6 +509,70 @@ swayc_t *swayc_active_workspace_for(swayc_t *cont) {
} }
} }
static bool pointer_test(swayc_t *view, void *_origin) {
const struct wlc_origin *origin = _origin;
// Determine the output that the view is under
swayc_t *parent = swayc_parent_by_type(view, C_OUTPUT);
if (origin->x >= view->x && origin->y >= view->y
&& origin->x < view->x + view->width && origin->y < view->y + view->height
&& view->visible && parent == root_container.focused) {
return true;
}
return false;
}
swayc_t *container_under_pointer(void) {
// root.output->workspace
if (!root_container.focused || !root_container.focused->focused) {
return NULL;
}
swayc_t *lookup = root_container.focused->focused;
// Case of empty workspace
if (lookup->children == 0) {
return NULL;
}
struct wlc_origin origin;
wlc_pointer_get_origin(&origin);
while (lookup->type != C_VIEW) {
int i;
int len;
// if tabbed/stacked go directly to focused container, otherwise search
// children
if (lookup->layout == L_TABBED || lookup->layout == L_STACKED) {
lookup = lookup->focused;
continue;
}
// if workspace, search floating
if (lookup->type == C_WORKSPACE) {
i = len = lookup->floating->length;
bool got_floating = false;
while (--i > -1) {
if (pointer_test(lookup->floating->items[i], &origin)) {
lookup = lookup->floating->items[i];
got_floating = true;
break;
}
}
if (got_floating) {
continue;
}
}
// search children
len = lookup->children->length;
for (i = 0; i < len; ++i) {
if (pointer_test(lookup->children->items[i], &origin)) {
lookup = lookup->children->items[i];
break;
}
}
// when border and titles are done, this could happen
if (i == len) {
break;
}
}
return lookup;
}
// Container information // Container information
bool swayc_is_fullscreen(swayc_t *view) { bool swayc_is_fullscreen(swayc_t *view) {

View file

@ -4,6 +4,8 @@
#include "log.h" #include "log.h"
#include "workspace.h" #include "workspace.h"
#include "layout.h" #include "layout.h"
#include "config.h"
#include "input_state.h"
bool locked_container_focus = false; bool locked_container_focus = false;
bool locked_view_focus = false; bool locked_view_focus = false;
@ -49,14 +51,24 @@ static void update_focus(swayc_t *c) {
} }
bool move_focus(enum movement_direction direction) { bool move_focus(enum movement_direction direction) {
swayc_t *view = get_focused_container(&root_container); swayc_t *old_view = get_focused_container(&root_container);
view = get_swayc_in_direction(view, direction); swayc_t *new_view = get_swayc_in_direction(old_view, direction);
if (view) { if (!new_view) {
if (direction == MOVE_PARENT) { return false;
return set_focused_container(view); } else if (direction == MOVE_PARENT) {
} else { return set_focused_container(new_view);
return set_focused_container(get_focused_view(view)); } else if (config->mouse_warping) {
swayc_t *old_op = old_view->type == C_OUTPUT ?
old_view : swayc_parent_by_type(old_view, C_OUTPUT);
swayc_t *focused = get_focused_view(new_view);
if (set_focused_container(focused)) {
if (old_op != swayc_active_output() && focused && focused->type == C_VIEW) {
center_pointer_on(focused);
}
return true;
} }
} else {
return set_focused_container(get_focused_view(new_view));
} }
return false; return false;
} }

View file

@ -24,68 +24,6 @@
// Event handled by sway and should not be sent to client // Event handled by sway and should not be sent to client
#define EVENT_HANDLED true #define EVENT_HANDLED true
static bool pointer_test(swayc_t *view, void *_origin) {
const struct mouse_origin *origin = _origin;
// Determine the output that the view is under
swayc_t *parent = swayc_parent_by_type(view, C_OUTPUT);
if (origin->x >= view->x && origin->y >= view->y
&& origin->x < view->x + view->width && origin->y < view->y + view->height
&& view->visible && parent == root_container.focused) {
return true;
}
return false;
}
swayc_t *container_under_pointer(void) {
// root.output->workspace
if (!root_container.focused || !root_container.focused->focused) {
return NULL;
}
swayc_t *lookup = root_container.focused->focused;
// Case of empty workspace
if (lookup->children == 0) {
return NULL;
}
while (lookup->type != C_VIEW) {
int i;
int len;
// if tabbed/stacked go directly to focused container, otherwise search
// children
if (lookup->layout == L_TABBED || lookup->layout == L_STACKED) {
lookup = lookup->focused;
continue;
}
// if workspace, search floating
if (lookup->type == C_WORKSPACE) {
i = len = lookup->floating->length;
bool got_floating = false;
while (--i > -1) {
if (pointer_test(lookup->floating->items[i], &pointer_state.origin)) {
lookup = lookup->floating->items[i];
got_floating = true;
break;
}
}
if (got_floating) {
continue;
}
}
// search children
len = lookup->children->length;
for (i = 0; i < len; ++i) {
if (pointer_test(lookup->children->items[i], &pointer_state.origin)) {
lookup = lookup->children->items[i];
break;
}
}
// when border and titles are done, this could happen
if (i == len) {
break;
}
}
return lookup;
}
/* Handles */ /* Handles */
static bool handle_output_created(wlc_handle output) { static bool handle_output_created(wlc_handle output) {
@ -394,27 +332,7 @@ static bool handle_pointer_motion(wlc_handle handle, uint32_t time, const struct
} }
} }
// Update pointer origin pointer_position_set(&new_origin, false);
pointer_state.delta.x = origin->x - pointer_state.origin.x;
pointer_state.delta.y = origin->y - pointer_state.origin.y;
pointer_state.origin.x = origin->x;
pointer_state.origin.y = origin->y;
// Update view under pointer
swayc_t *prev_view = pointer_state.view;
pointer_state.view = container_under_pointer();
// If pointer is in a mode, update it
if (pointer_state.mode) {
pointer_mode_update();
}
// Otherwise change focus if config is set an
else if (prev_view != pointer_state.view && config->focus_follows_mouse) {
if (pointer_state.view && pointer_state.view->type == C_VIEW) {
set_focused_container(pointer_state.view);
}
}
wlc_pointer_set_origin(&new_origin);
return EVENT_PASSTHROUGH; return EVENT_PASSTHROUGH;
} }
@ -425,10 +343,6 @@ static bool handle_pointer_button(wlc_handle view, uint32_t time, const struct w
// Update view pointer is on // Update view pointer is on
pointer_state.view = container_under_pointer(); pointer_state.view = container_under_pointer();
// Update pointer origin
pointer_state.origin.x = origin->x;
pointer_state.origin.y = origin->y;
// Update pointer_state // Update pointer_state
switch (button) { switch (button) {
case M_LEFT_CLICK: case M_LEFT_CLICK:

View file

@ -2,6 +2,7 @@
#include <stdbool.h> #include <stdbool.h>
#include <ctype.h> #include <ctype.h>
#include "log.h" #include "log.h"
#include "config.h"
#include "input_state.h" #include "input_state.h"
@ -161,6 +162,36 @@ static void reset_initial_sibling(void) {
pointer_state.mode = 0; pointer_state.mode = 0;
} }
void pointer_position_set(struct wlc_origin *new_origin, bool force_focus) {
struct wlc_origin origin;
wlc_pointer_get_origin(&origin);
pointer_state.delta.x = new_origin->x - origin.x;
pointer_state.delta.y = new_origin->y - origin.y;
// Update view under pointer
swayc_t *prev_view = pointer_state.view;
pointer_state.view = container_under_pointer();
// If pointer is in a mode, update it
if (pointer_state.mode) {
pointer_mode_update();
// Otherwise change focus if config is set
} else if (force_focus || (prev_view != pointer_state.view && config->focus_follows_mouse)) {
if (pointer_state.view && pointer_state.view->type == C_VIEW) {
set_focused_container(pointer_state.view);
}
}
wlc_pointer_set_origin(new_origin);
}
void center_pointer_on(swayc_t *view) {
struct wlc_origin new_origin;
new_origin.x = view->x + view->width/2;
new_origin.y = view->y + view->height/2;
pointer_position_set(&new_origin, true);
}
// Mode set left/right click // Mode set left/right click
static void pointer_mode_set_left(void) { static void pointer_mode_set_left(void) {
@ -183,8 +214,10 @@ static void pointer_mode_set_right(void) {
int midway_x = initial.ptr->x + initial.ptr->width/2; int midway_x = initial.ptr->x + initial.ptr->width/2;
int midway_y = initial.ptr->y + initial.ptr->height/2; int midway_y = initial.ptr->y + initial.ptr->height/2;
lock.left = pointer_state.origin.x > midway_x; struct wlc_origin origin;
lock.top = pointer_state.origin.y > midway_y; wlc_pointer_get_origin(&origin);
lock.left = origin.x > midway_x;
lock.top = origin.y > midway_y;
if (initial.ptr->is_floating) { if (initial.ptr->is_floating) {
pointer_state.mode = M_RESIZING | M_FLOATING; pointer_state.mode = M_RESIZING | M_FLOATING;
@ -246,8 +279,10 @@ void pointer_mode_update(void) {
pointer_state.mode = 0; pointer_state.mode = 0;
return; return;
} }
int dx = pointer_state.origin.x; struct wlc_origin origin;
int dy = pointer_state.origin.y; wlc_pointer_get_origin(&origin);
int dx = origin.x;
int dy = origin.y;
switch (pointer_state.mode) { switch (pointer_state.mode) {
case M_FLOATING | M_DRAGGING: case M_FLOATING | M_DRAGGING: