backends/native: Protect MetaBarrierManagerNative

While barriers will be added from the main thread, the native barrier
manager will sit close to the MetaSeatImpl in its own thread. Add the
necessary locking so that we can pass MetaBarrierImplNative from the
UI thread to the input thread, and ensure the MetaBarrier signals are
still emitted in the UI thread.

https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1403
This commit is contained in:
Carlos Garnacho 2020-08-11 20:21:08 +02:00
parent 6496cd7c55
commit d55b44df50

View File

@ -43,6 +43,7 @@
struct _MetaBarrierManagerNative
{
GHashTable *barriers;
GMutex mutex;
};
typedef enum
@ -77,6 +78,7 @@ struct _MetaBarrierImplNative
int trigger_serial;
guint32 last_event_time;
MetaBarrierDirection blocked_dir;
GMainContext *context;
};
G_DEFINE_TYPE (MetaBarrierImplNative,
@ -340,6 +342,48 @@ typedef struct _MetaBarrierEventData
float dy;
} MetaBarrierEventData;
typedef struct
{
MetaBarrierEvent *event;
MetaBarrier *barrier;
MetaBarrierState state;
} MetaBarrierIdleData;
static gboolean
emit_event_idle (MetaBarrierIdleData *idle_data)
{
if (idle_data->state == META_BARRIER_STATE_HELD)
_meta_barrier_emit_hit_signal (idle_data->barrier, idle_data->event);
else
_meta_barrier_emit_left_signal (idle_data->barrier, idle_data->event);
meta_barrier_event_unref (idle_data->event);
return G_SOURCE_REMOVE;
}
static void
emit_event (MetaBarrierImplNative *self,
MetaBarrierEvent *event)
{
MetaBarrierIdleData *idle_data;
GSource *source;
idle_data = g_new0 (MetaBarrierIdleData, 1);
idle_data->state = self->state;
idle_data->barrier = self->barrier;
idle_data->event = event;
source = g_idle_source_new ();
g_source_set_priority (source, G_PRIORITY_HIGH);
g_source_set_callback (source,
(GSourceFunc) emit_event_idle,
idle_data,
g_free);
g_source_attach (source, self->context);
}
static void
emit_barrier_event (MetaBarrierImplNative *self,
guint32 time,
@ -350,7 +394,6 @@ emit_barrier_event (MetaBarrierImplNative *self,
float dx,
float dy)
{
MetaBarrier *barrier = self->barrier;
MetaBarrierEvent *event = g_slice_new0 (MetaBarrierEvent);
MetaBarrierState old_state = self->state;
@ -389,12 +432,7 @@ emit_barrier_event (MetaBarrierImplNative *self,
self->last_event_time = time;
if (self->state == META_BARRIER_STATE_HELD)
_meta_barrier_emit_hit_signal (barrier, event);
else
_meta_barrier_emit_left_signal (barrier, event);
meta_barrier_event_unref (event);
emit_event (self, event);
}
static void
@ -479,6 +517,8 @@ meta_barrier_manager_native_process (MetaBarrierManagerNative *manager,
if (!clutter_input_device_get_coords (device, NULL, &prev_pos))
return;
g_mutex_lock (&manager->mutex);
prev_x = prev_pos.x;
prev_y = prev_pos.y;
@ -523,6 +563,8 @@ meta_barrier_manager_native_process (MetaBarrierManagerNative *manager,
g_hash_table_foreach (manager->barriers,
maybe_emit_barrier_event,
&barrier_event_data);
g_mutex_unlock (&manager->mutex);
}
static gboolean
@ -549,7 +591,10 @@ _meta_barrier_impl_native_destroy (MetaBarrierImpl *impl)
{
MetaBarrierImplNative *self = META_BARRIER_IMPL_NATIVE (impl);
g_mutex_lock (&self->manager->mutex);
g_hash_table_remove (self->manager->barriers, self);
g_mutex_unlock (&self->manager->mutex);
g_main_context_unref (self->context);
self->is_active = FALSE;
}
@ -565,10 +610,13 @@ meta_barrier_impl_native_new (MetaBarrier *barrier)
self->barrier = barrier;
self->is_active = TRUE;
self->context = g_main_context_ref_thread_default ();
manager = meta_seat_native_get_barrier_manager (META_SEAT_NATIVE (seat));
self->manager = manager;
g_mutex_lock (&manager->mutex);
g_hash_table_add (manager->barriers, self);
g_mutex_unlock (&manager->mutex);
return META_BARRIER_IMPL (self);
}
@ -596,6 +644,7 @@ meta_barrier_manager_native_new (void)
manager = g_new0 (MetaBarrierManagerNative, 1);
manager->barriers = g_hash_table_new (NULL, NULL);
g_mutex_init (&manager->mutex);
return manager;
}