summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAnder Conselvan de Oliveira <ander.conselvan.de.oliveira@intel.com>2013-12-13 22:10:56 +0200
committerKristian Høgsberg <krh@bitplanet.net>2013-12-16 17:23:08 -0800
commit54e90c7e1e20d9d51f516b42b4c846d26a8cfb5e (patch)
tree580af00a1575ac9097e668f2920f1cf65bbfa86d
parente1e2352dcc157fd0bd7c880379ba42b9e5d9be75 (diff)
compositor: Make pointers visible when an output is unplugged
Previously, if a pointer was inside an output that was unplugged, it could potentialy end up outside any valid output forever. With this patch, the pointer is moved to the "closest" output to the pointer.
-rw-r--r--src/compositor.c15
-rw-r--r--src/compositor.h2
-rw-r--r--src/input.c76
3 files changed, 81 insertions, 12 deletions
diff --git a/src/compositor.c b/src/compositor.c
index ed6548c6..af33fdae 100644
--- a/src/compositor.c
+++ b/src/compositor.c
@@ -3105,6 +3105,19 @@ weston_compositor_remove_output(struct weston_compositor *compositor,
}
}
+static void
+weston_compositor_verify_pointers(struct weston_compositor *ec)
+{
+ struct weston_seat *seat;
+
+ wl_list_for_each(seat, &ec->seat_list, link) {
+ if (!seat->pointer)
+ continue;
+
+ weston_pointer_verify(seat->pointer);
+ }
+}
+
WL_EXPORT void
weston_output_destroy(struct weston_output *output)
{
@@ -3113,6 +3126,8 @@ weston_output_destroy(struct weston_output *output)
weston_compositor_remove_output(output->compositor, output);
wl_list_remove(&output->link);
+ weston_compositor_verify_pointers(output->compositor);
+
wl_signal_emit(&output->destroy_signal, output);
free(output->name);
diff --git a/src/compositor.h b/src/compositor.h
index 901366fb..d344e37e 100644
--- a/src/compositor.h
+++ b/src/compositor.h
@@ -375,6 +375,8 @@ weston_pointer_move(struct weston_pointer *pointer,
void
weston_pointer_set_default_grab(struct weston_pointer *pointer,
const struct weston_pointer_grab_interface *interface);
+void
+weston_pointer_verify(struct weston_pointer *pointer);
struct weston_keyboard *
weston_keyboard_create(void);
diff --git a/src/input.c b/src/input.c
index f4944b6c..07e9d6cb 100644
--- a/src/input.c
+++ b/src/input.c
@@ -29,6 +29,7 @@
#include <assert.h>
#include <unistd.h>
#include <fcntl.h>
+#include <limits.h>
#include "../shared/os-compatibility.h"
#include "compositor.h"
@@ -791,6 +792,28 @@ weston_touch_cancel_grab(struct weston_touch *touch)
touch->grab->interface->cancel(touch->grab);
}
+static void
+weston_pointer_clamp_for_output(struct weston_pointer *pointer,
+ struct weston_output *output,
+ wl_fixed_t *fx, wl_fixed_t *fy)
+{
+ int x, y;
+
+ x = wl_fixed_to_int(*fx);
+ y = wl_fixed_to_int(*fy);
+
+ if (x < output->x)
+ *fx = wl_fixed_from_int(output->x);
+ else if (x >= output->x + output->width)
+ *fx = wl_fixed_from_int(output->x +
+ output->width - 1);
+ if (y < output->y)
+ *fy = wl_fixed_from_int(output->y);
+ else if (y >= output->y + output->height)
+ *fy = wl_fixed_from_int(output->y +
+ output->height - 1);
+}
+
WL_EXPORT void
weston_pointer_clamp(struct weston_pointer *pointer, wl_fixed_t *fx, wl_fixed_t *fy)
{
@@ -817,18 +840,8 @@ weston_pointer_clamp(struct weston_pointer *pointer, wl_fixed_t *fx, wl_fixed_t
if (!prev)
prev = pointer->seat->output;
- if (prev && !valid) {
- if (x < prev->x)
- *fx = wl_fixed_from_int(prev->x);
- else if (x >= prev->x + prev->width)
- *fx = wl_fixed_from_int(prev->x +
- prev->width - 1);
- if (y < prev->y)
- *fy = wl_fixed_from_int(prev->y);
- else if (y >= prev->y + prev->height)
- *fy = wl_fixed_from_int(prev->y +
- prev->height - 1);
- }
+ if (prev && !valid)
+ weston_pointer_clamp_for_output(pointer, prev, fx, fy);
}
/* Takes absolute values */
@@ -856,6 +869,45 @@ weston_pointer_move(struct weston_pointer *pointer, wl_fixed_t x, wl_fixed_t y)
wl_signal_emit(&pointer->motion_signal, pointer);
}
+/** Verify if the pointer is in a valid position and move it if it isn't.
+ */
+WL_EXPORT void
+weston_pointer_verify(struct weston_pointer *pointer)
+{
+ struct weston_compositor *ec = pointer->seat->compositor;
+ struct weston_output *output, *closest = NULL;
+ int x, y, distance, min = INT_MAX;
+ wl_fixed_t fx, fy;
+
+ x = wl_fixed_to_int(pointer->x);
+ y = wl_fixed_to_int(pointer->y);
+
+ wl_list_for_each(output, &ec->output_list, link) {
+ if (pixman_region32_contains_point(&output->region,
+ x, y, NULL))
+ return;
+
+ /* Aproximante the distance from the pointer to the center of
+ * the output. */
+ distance = abs(output->x + output->width / 2 - x) +
+ abs(output->y + output->height / 2 - y);
+ if (distance < min) {
+ min = distance;
+ closest = output;
+ }
+ }
+
+ /* Nothing to do if there's no output left. */
+ if (!closest)
+ return;
+
+ fx = pointer->x;
+ fy = pointer->y;
+
+ weston_pointer_clamp_for_output(pointer, closest, &fx, &fy);
+ weston_pointer_move(pointer, fx, fy);
+}
+
WL_EXPORT void
notify_motion(struct weston_seat *seat,
uint32_t time, wl_fixed_t dx, wl_fixed_t dy)