diff --git a/src/backends/meta-barrier-private.h b/src/backends/meta-barrier-private.h index ebe22cb54..38b1bfa07 100644 --- a/src/backends/meta-barrier-private.h +++ b/src/backends/meta-barrier-private.h @@ -58,6 +58,8 @@ MetaBackend * meta_barrier_get_backend (MetaBarrier *barrier); MetaBorder * meta_barrier_get_border (MetaBarrier *barrier); +MetaBarrierFlags meta_barrier_get_flags (MetaBarrier *barrier); + G_END_DECLS #endif /* META_BARRIER_PRIVATE_H */ diff --git a/src/backends/meta-barrier.c b/src/backends/meta-barrier.c index 30323942b..4338d808f 100644 --- a/src/backends/meta-barrier.c +++ b/src/backends/meta-barrier.c @@ -28,6 +28,7 @@ typedef struct _MetaBarrierPrivate MetaBackend *backend; MetaBorder border; MetaBarrierImpl *impl; + MetaBarrierFlags flags; } MetaBarrierPrivate; static void initable_iface_init (GInitableIface *initable_iface); @@ -60,6 +61,7 @@ enum PROP_X2, PROP_Y2, PROP_DIRECTIONS, + PROP_FLAGS, PROP_LAST, }; @@ -125,6 +127,9 @@ meta_barrier_get_property (GObject *object, g_value_set_flags (value, meta_border_get_allows_directions (&priv->border)); break; + case PROP_FLAGS: + g_value_set_flags (value, priv->flags); + break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); break; @@ -170,6 +175,9 @@ meta_barrier_set_property (GObject *object, meta_border_set_allows_directions (&priv->border, g_value_get_flags (value)); break; + case PROP_FLAGS: + priv->flags = g_value_get_flags (value); + break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); break; @@ -362,6 +370,15 @@ meta_barrier_class_init (MetaBarrierClass *klass) G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS); + obj_props[PROP_FLAGS] = + g_param_spec_flags ("flags", + "Flags", + "Flags for manipulating barrier behavior", + META_TYPE_BARRIER_FLAGS, + META_BARRIER_FLAG_NONE, + G_PARAM_READWRITE | + G_PARAM_CONSTRUCT_ONLY | + G_PARAM_STATIC_STRINGS); g_object_class_install_properties (object_class, PROP_LAST, obj_props); @@ -426,6 +443,7 @@ meta_barrier_new (MetaBackend *backend, int x2, int y2, MetaBarrierDirection directions, + MetaBarrierFlags flags, GError **error) { return g_initable_new (META_TYPE_BARRIER, @@ -436,6 +454,7 @@ meta_barrier_new (MetaBackend *backend, "x2", x2, "y2", y2, "directions", directions, + "flags", flags, NULL); } @@ -469,6 +488,14 @@ meta_barrier_get_border (MetaBarrier *barrier) return &priv->border; } +MetaBarrierFlags +meta_barrier_get_flags (MetaBarrier *barrier) +{ + MetaBarrierPrivate *priv = meta_barrier_get_instance_private (barrier); + + return priv->flags; +} + static void meta_barrier_impl_class_init (MetaBarrierImplClass *klass) { diff --git a/src/backends/native/meta-barrier-native.c b/src/backends/native/meta-barrier-native.c index 30c86632d..828cdad2f 100644 --- a/src/backends/native/meta-barrier-native.c +++ b/src/backends/native/meta-barrier-native.c @@ -44,6 +44,7 @@ struct _MetaBarrierManagerNative { GHashTable *barriers; GMutex mutex; + MetaBarrierImplNative *pointer_trap; }; typedef enum @@ -504,6 +505,38 @@ clamp_to_barrier (MetaBarrierImplNative *self, self->state = META_BARRIER_STATE_HIT; } +static gboolean +stick_to_barrier (MetaBarrierImplNative *self, + MetaBarrierDirection motion_dir, + float prev_x, + float prev_y, + float *x, + float *y) +{ + MetaLine2 motion = { + .a = { .x = prev_x, .y = prev_y }, + .b = { .x = *x, .y = *y }, + }; + MetaBorder *border = meta_barrier_get_border (self->barrier); + MetaVector2 intersection; + + if (meta_line2_intersects_with (&motion, &border->line, + &intersection)) + { + *x = intersection.x; + *y = intersection.y; + + self->blocked_dir = motion_dir; + self->state = META_BARRIER_STATE_HIT; + self->manager->pointer_trap = self; + return TRUE; + } + else + { + return FALSE; + } +} + void meta_barrier_manager_native_process_in_impl (MetaBarrierManagerNative *manager, ClutterInputDevice *device, @@ -524,11 +557,18 @@ meta_barrier_manager_native_process_in_impl (MetaBarrierManagerNative *manager, device, NULL, &prev_pos, NULL)) return; - g_mutex_lock (&manager->mutex); - prev_x = prev_pos.x; prev_y = prev_pos.y; + if (manager->pointer_trap) + { + *x = prev_pos.x; + *y = prev_pos.y; + return; + } + + g_mutex_lock (&manager->mutex); + /* Get the direction of the motion vector. */ if (prev_x < *x) motion_dir |= META_BARRIER_DIRECTION_POSITIVE_X; @@ -548,7 +588,18 @@ meta_barrier_manager_native_process_in_impl (MetaBarrierManagerNative *manager, *x, *y, motion_dir, &barrier_impl)) - clamp_to_barrier (barrier_impl, &motion_dir, x, y); + { + MetaBarrier *barrier = barrier_impl->barrier; + + if (meta_barrier_get_flags (barrier) & META_BARRIER_FLAG_STICKY) + { + if (stick_to_barrier (barrier_impl, motion_dir, + prev_x, prev_y, x, y)) + break; + } + + clamp_to_barrier (barrier_impl, &motion_dir, x, y); + } else break; } @@ -590,7 +641,10 @@ meta_barrier_impl_native_release (MetaBarrierImpl *impl, if (self->state == META_BARRIER_STATE_HELD && event->event_id == self->trigger_serial) - self->state = META_BARRIER_STATE_RELEASE; + { + self->state = META_BARRIER_STATE_RELEASE; + self->manager->pointer_trap = NULL; + } } static void @@ -599,6 +653,8 @@ meta_barrier_impl_native_destroy (MetaBarrierImpl *impl) MetaBarrierImplNative *self = META_BARRIER_IMPL_NATIVE (impl); g_mutex_lock (&self->manager->mutex); + if (self->manager->pointer_trap == self) + self->manager->pointer_trap = NULL; g_hash_table_remove (self->manager->barriers, self); g_mutex_unlock (&self->manager->mutex); g_main_context_unref (self->main_context); diff --git a/src/meta/barrier.h b/src/meta/barrier.h index ac090fb67..844bfe824 100644 --- a/src/meta/barrier.h +++ b/src/meta/barrier.h @@ -26,6 +26,12 @@ typedef enum META_BARRIER_DIRECTION_NEGATIVE_Y = 1 << 3, } MetaBarrierDirection; +typedef enum +{ + META_BARRIER_FLAG_NONE = 1 << 0, + META_BARRIER_FLAG_STICKY = 1 << 1, +} MetaBarrierFlags; + #define META_TYPE_BARRIER (meta_barrier_get_type ()) META_EXPORT G_DECLARE_DERIVABLE_TYPE (MetaBarrier, meta_barrier, @@ -45,6 +51,7 @@ MetaBarrier * meta_barrier_new (MetaBackend *backend, int x2, int y2, MetaBarrierDirection directions, + MetaBarrierFlags flags, GError **error); META_EXPORT