barrier: Add ways to make barriers sticky
A sticky barrier means that a pointer in motion intersecting a barrier doesn't move once having hit it. The intention with this is to allow an input capture clients to continue a motion once a barrier is hit. Part-of: <https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/2628>
This commit is contained in:
parent
a8b013b006
commit
221ac2af76
@ -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 */
|
||||
|
@ -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)
|
||||
{
|
||||
|
@ -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))
|
||||
{
|
||||
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->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);
|
||||
|
@ -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
|
||||
|
Loading…
Reference in New Issue
Block a user