input-capture: Hook up barrier adding
Adding a barrier and later enabling the input capture session will create MetaBarrier instances for each added input capture barrier. The barriers are created as "sticky" which means that when a pointer hits the barrier, it'll stick to the point of entry, until it's released. The input capture session is also turned into a state machine with explicit state, to more easily track things. Part-of: <https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/2628>
This commit is contained in:
parent
a8f461a4eb
commit
1d1983edb5
@ -29,6 +29,7 @@
|
|||||||
#include "backends/meta-monitor-manager-private.h"
|
#include "backends/meta-monitor-manager-private.h"
|
||||||
#include "backends/meta-logical-monitor.h"
|
#include "backends/meta-logical-monitor.h"
|
||||||
#include "backends/meta-remote-access-controller-private.h"
|
#include "backends/meta-remote-access-controller-private.h"
|
||||||
|
#include "meta/barrier.h"
|
||||||
#include "meta/boxes.h"
|
#include "meta/boxes.h"
|
||||||
#include "meta/meta-backend.h"
|
#include "meta/meta-backend.h"
|
||||||
|
|
||||||
@ -36,6 +37,8 @@
|
|||||||
|
|
||||||
#define META_INPUT_CAPTURE_SESSION_DBUS_PATH "/org/gnome/Mutter/InputCapture/Session"
|
#define META_INPUT_CAPTURE_SESSION_DBUS_PATH "/org/gnome/Mutter/InputCapture/Session"
|
||||||
|
|
||||||
|
static GQuark quark_barrier_id;
|
||||||
|
|
||||||
enum
|
enum
|
||||||
{
|
{
|
||||||
PROP_0,
|
PROP_0,
|
||||||
@ -43,6 +46,25 @@ enum
|
|||||||
N_PROPS
|
N_PROPS
|
||||||
};
|
};
|
||||||
|
|
||||||
|
typedef enum _InputCaptureState
|
||||||
|
{
|
||||||
|
INPUT_CAPTURE_STATE_INIT,
|
||||||
|
INPUT_CAPTURE_STATE_ENABLED,
|
||||||
|
INPUT_CAPTURE_STATE_ACTIVATED,
|
||||||
|
INPUT_CAPTURE_STATE_CLOSED,
|
||||||
|
} InputCaptureState;
|
||||||
|
|
||||||
|
typedef struct _InputCaptureBarrier
|
||||||
|
{
|
||||||
|
int x1;
|
||||||
|
int y1;
|
||||||
|
int x2;
|
||||||
|
int y2;
|
||||||
|
|
||||||
|
unsigned int id;
|
||||||
|
MetaBarrier *barrier;
|
||||||
|
} InputCaptureBarrier;
|
||||||
|
|
||||||
struct _MetaInputCaptureSession
|
struct _MetaInputCaptureSession
|
||||||
{
|
{
|
||||||
MetaDBusInputCaptureSessionSkeleton parent;
|
MetaDBusInputCaptureSessionSkeleton parent;
|
||||||
@ -55,9 +77,11 @@ struct _MetaInputCaptureSession
|
|||||||
char *session_id;
|
char *session_id;
|
||||||
char *object_path;
|
char *object_path;
|
||||||
|
|
||||||
gboolean enabled;
|
InputCaptureState state;
|
||||||
|
GHashTable *barriers;
|
||||||
|
|
||||||
uint32_t serial;
|
uint32_t zones_serial;
|
||||||
|
uint32_t activation_id;
|
||||||
|
|
||||||
MetaInputCaptureSessionHandle *handle;
|
MetaInputCaptureSessionHandle *handle;
|
||||||
};
|
};
|
||||||
@ -107,31 +131,149 @@ init_remote_access_handle (MetaInputCaptureSession *session)
|
|||||||
remote_access_handle);
|
remote_access_handle);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
release_remote_access_handle (MetaInputCaptureSession *session)
|
||||||
|
{
|
||||||
|
MetaRemoteAccessHandle *remote_access_handle =
|
||||||
|
META_REMOTE_ACCESS_HANDLE (session->handle);
|
||||||
|
|
||||||
|
meta_remote_access_handle_notify_stopped (remote_access_handle);
|
||||||
|
g_clear_object (&session->handle);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
on_barrier_hit (MetaBarrier *barrier,
|
||||||
|
const MetaBarrierEvent *event,
|
||||||
|
MetaInputCaptureSession *session)
|
||||||
|
{
|
||||||
|
MetaDBusInputCaptureSession *skeleton =
|
||||||
|
META_DBUS_INPUT_CAPTURE_SESSION (session);
|
||||||
|
GVariant *cursor_position;
|
||||||
|
unsigned int barrier_id;
|
||||||
|
|
||||||
|
switch (session->state)
|
||||||
|
{
|
||||||
|
case INPUT_CAPTURE_STATE_ACTIVATED:
|
||||||
|
return;
|
||||||
|
case INPUT_CAPTURE_STATE_ENABLED:
|
||||||
|
break;
|
||||||
|
case INPUT_CAPTURE_STATE_INIT:
|
||||||
|
case INPUT_CAPTURE_STATE_CLOSED:
|
||||||
|
g_warn_if_reached ();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
session->state = INPUT_CAPTURE_STATE_ACTIVATED;
|
||||||
|
|
||||||
|
barrier_id = GPOINTER_TO_UINT (g_object_get_qdata (G_OBJECT (barrier),
|
||||||
|
quark_barrier_id));
|
||||||
|
cursor_position = g_variant_new ("(dd)", event->x, event->y);
|
||||||
|
|
||||||
|
meta_dbus_input_capture_session_emit_activated (skeleton,
|
||||||
|
barrier_id,
|
||||||
|
++session->activation_id,
|
||||||
|
cursor_position);
|
||||||
|
|
||||||
|
init_remote_access_handle (session);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
clear_all_barriers (MetaInputCaptureSession *session)
|
||||||
|
{
|
||||||
|
GHashTableIter iter;
|
||||||
|
InputCaptureBarrier *input_capture_barrier;
|
||||||
|
|
||||||
|
g_hash_table_iter_init (&iter, session->barriers);
|
||||||
|
while (g_hash_table_iter_next (&iter, NULL,
|
||||||
|
(gpointer *) &input_capture_barrier))
|
||||||
|
g_clear_pointer (&input_capture_barrier->barrier, meta_barrier_destroy);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
release_all_barriers (MetaInputCaptureSession *session)
|
||||||
|
{
|
||||||
|
GHashTableIter iter;
|
||||||
|
InputCaptureBarrier *input_capture_barrier;
|
||||||
|
|
||||||
|
g_hash_table_iter_init (&iter, session->barriers);
|
||||||
|
while (g_hash_table_iter_next (&iter, NULL,
|
||||||
|
(gpointer *) &input_capture_barrier))
|
||||||
|
{
|
||||||
|
MetaBarrier *barrier;
|
||||||
|
|
||||||
|
barrier = input_capture_barrier->barrier;
|
||||||
|
if (!barrier)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
meta_barrier_release (barrier, NULL);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
static gboolean
|
static gboolean
|
||||||
meta_input_capture_session_enable (MetaInputCaptureSession *session,
|
meta_input_capture_session_enable (MetaInputCaptureSession *session,
|
||||||
GError **error)
|
GError **error)
|
||||||
{
|
{
|
||||||
g_assert (!session->enabled);
|
MetaBackend *backend =
|
||||||
|
meta_dbus_session_manager_get_backend (session->session_manager);
|
||||||
|
GHashTableIter iter;
|
||||||
|
gpointer key, value;
|
||||||
|
|
||||||
session->enabled = TRUE;
|
g_warn_if_fail (session->state == INPUT_CAPTURE_STATE_INIT);
|
||||||
|
|
||||||
init_remote_access_handle (session);
|
g_hash_table_iter_init (&iter, session->barriers);
|
||||||
|
while (g_hash_table_iter_next (&iter, &key, &value))
|
||||||
|
{
|
||||||
|
unsigned int barrier_id = GPOINTER_TO_UINT (key);
|
||||||
|
InputCaptureBarrier *input_capture_barrier = value;
|
||||||
|
g_autoptr (MetaBarrier) barrier = NULL;
|
||||||
|
|
||||||
|
barrier = meta_barrier_new (backend,
|
||||||
|
input_capture_barrier->x1,
|
||||||
|
input_capture_barrier->y1,
|
||||||
|
input_capture_barrier->x2,
|
||||||
|
input_capture_barrier->y2,
|
||||||
|
0,
|
||||||
|
META_BARRIER_FLAG_STICKY,
|
||||||
|
error);
|
||||||
|
if (!barrier)
|
||||||
|
goto err;
|
||||||
|
|
||||||
|
g_object_set_qdata (G_OBJECT (barrier), quark_barrier_id,
|
||||||
|
GUINT_TO_POINTER (barrier_id));
|
||||||
|
g_signal_connect (barrier, "hit", G_CALLBACK (on_barrier_hit), session);
|
||||||
|
input_capture_barrier->barrier = barrier;
|
||||||
|
}
|
||||||
|
|
||||||
|
session->state = INPUT_CAPTURE_STATE_ENABLED;
|
||||||
|
|
||||||
return TRUE;
|
return TRUE;
|
||||||
|
|
||||||
|
err:
|
||||||
|
clear_all_barriers (session);
|
||||||
|
return FALSE;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
meta_input_capture_session_disable (MetaInputCaptureSession *session)
|
meta_input_capture_session_disable (MetaInputCaptureSession *session)
|
||||||
{
|
{
|
||||||
session->enabled = FALSE;
|
switch (session->state)
|
||||||
|
{
|
||||||
|
case INPUT_CAPTURE_STATE_INIT:
|
||||||
|
return;
|
||||||
|
case INPUT_CAPTURE_STATE_ACTIVATED:
|
||||||
|
case INPUT_CAPTURE_STATE_ENABLED:
|
||||||
|
break;
|
||||||
|
case INPUT_CAPTURE_STATE_CLOSED:
|
||||||
|
g_warn_if_reached ();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
clear_all_barriers (session);
|
||||||
|
|
||||||
|
session->state = INPUT_CAPTURE_STATE_INIT;
|
||||||
|
|
||||||
if (session->handle)
|
if (session->handle)
|
||||||
{
|
release_remote_access_handle (session);
|
||||||
MetaRemoteAccessHandle *remote_access_handle =
|
|
||||||
META_REMOTE_ACCESS_HANDLE (session->handle);
|
|
||||||
|
|
||||||
meta_remote_access_handle_notify_stopped (remote_access_handle);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
@ -142,8 +284,8 @@ meta_input_capture_session_close (MetaDbusSession *dbus_session)
|
|||||||
MetaDBusInputCaptureSession *skeleton =
|
MetaDBusInputCaptureSession *skeleton =
|
||||||
META_DBUS_INPUT_CAPTURE_SESSION (session);
|
META_DBUS_INPUT_CAPTURE_SESSION (session);
|
||||||
|
|
||||||
if (session->enabled)
|
meta_input_capture_session_disable (session);
|
||||||
meta_input_capture_session_disable (session);
|
session->state = INPUT_CAPTURE_STATE_CLOSED;
|
||||||
|
|
||||||
meta_dbus_session_notify_closed (META_DBUS_SESSION (session));
|
meta_dbus_session_notify_closed (META_DBUS_SESSION (session));
|
||||||
meta_dbus_input_capture_session_emit_closed (skeleton);
|
meta_dbus_input_capture_session_emit_closed (skeleton);
|
||||||
@ -160,15 +302,233 @@ check_permission (MetaInputCaptureSession *session,
|
|||||||
g_dbus_method_invocation_get_sender (invocation)) == 0;
|
g_dbus_method_invocation_get_sender (invocation)) == 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
typedef enum
|
||||||
|
{
|
||||||
|
LINE_ADJACENCY_ERROR,
|
||||||
|
LINE_ADJACENCY_NONE,
|
||||||
|
LINE_ADJACENCY_OVERLAP,
|
||||||
|
LINE_ADJACENCY_CONTAINED,
|
||||||
|
LINE_ADJACENCY_PARTIAL,
|
||||||
|
} LineAdjacency;
|
||||||
|
|
||||||
|
static LineAdjacency
|
||||||
|
get_barrier_adjacency (MetaRectangle *rect,
|
||||||
|
int x1,
|
||||||
|
int y1,
|
||||||
|
int x2,
|
||||||
|
int y2,
|
||||||
|
GError **error)
|
||||||
|
{
|
||||||
|
int x_min, x_max;
|
||||||
|
int y_min, y_max;
|
||||||
|
|
||||||
|
x_min = MIN (x1, x2);
|
||||||
|
x_max = MAX (x1, x2);
|
||||||
|
y_min = MIN (y1, y2);
|
||||||
|
y_max = MAX (y1, y2);
|
||||||
|
|
||||||
|
if (x1 == x2)
|
||||||
|
{
|
||||||
|
int x = x1;
|
||||||
|
|
||||||
|
if (x < rect->x || x > rect->x + rect->width)
|
||||||
|
return LINE_ADJACENCY_NONE;
|
||||||
|
|
||||||
|
if (y_max < rect->y ||
|
||||||
|
y_min > rect->y + rect->height)
|
||||||
|
return LINE_ADJACENCY_NONE;
|
||||||
|
|
||||||
|
if (rect->x + rect->width == x || rect->x == x)
|
||||||
|
{
|
||||||
|
if (y_max > rect->y + rect->height ||
|
||||||
|
y_min < rect->y)
|
||||||
|
return LINE_ADJACENCY_PARTIAL;
|
||||||
|
else
|
||||||
|
return LINE_ADJACENCY_CONTAINED;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return LINE_ADJACENCY_OVERLAP;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (y1 == y2)
|
||||||
|
{
|
||||||
|
int y = y1;
|
||||||
|
|
||||||
|
if (y < rect->y || y > rect->y + rect->height)
|
||||||
|
return LINE_ADJACENCY_NONE;
|
||||||
|
|
||||||
|
if (x_max < rect->x ||
|
||||||
|
x_min > rect->x + rect->width)
|
||||||
|
return LINE_ADJACENCY_NONE;
|
||||||
|
|
||||||
|
if (rect->y + rect->height == y || rect->y == y)
|
||||||
|
{
|
||||||
|
if (x_max > rect->x + rect->width ||
|
||||||
|
x_min < rect->x)
|
||||||
|
return LINE_ADJACENCY_PARTIAL;
|
||||||
|
else
|
||||||
|
return LINE_ADJACENCY_CONTAINED;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return LINE_ADJACENCY_OVERLAP;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return LINE_ADJACENCY_NONE;
|
||||||
|
}
|
||||||
|
|
||||||
|
static gboolean
|
||||||
|
check_barrier (MetaInputCaptureSession *session,
|
||||||
|
int x1,
|
||||||
|
int y1,
|
||||||
|
int x2,
|
||||||
|
int y2,
|
||||||
|
GError **error)
|
||||||
|
{
|
||||||
|
MetaBackend *backend =
|
||||||
|
meta_dbus_session_manager_get_backend (session->session_manager);
|
||||||
|
MetaMonitorManager *monitor_manager =
|
||||||
|
meta_backend_get_monitor_manager (backend);
|
||||||
|
gboolean has_adjecent_monitor = FALSE;
|
||||||
|
GList *logical_monitors;
|
||||||
|
GList *l;
|
||||||
|
|
||||||
|
if (x1 != x2 && y1 != y2)
|
||||||
|
{
|
||||||
|
g_set_error (error, G_IO_ERROR, G_IO_ERROR_INVALID_DATA,
|
||||||
|
"Barrier coordinates not axis aligned");
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (x1 == x2 && y1 == y2)
|
||||||
|
{
|
||||||
|
g_set_error (error, G_IO_ERROR, G_IO_ERROR_INVALID_DATA,
|
||||||
|
"Barrier cannot be a singularity");
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
logical_monitors =
|
||||||
|
meta_monitor_manager_get_logical_monitors (monitor_manager);
|
||||||
|
for (l = logical_monitors; l; l = l->next)
|
||||||
|
{
|
||||||
|
MetaLogicalMonitor *logical_monitor = l->data;
|
||||||
|
MetaRectangle layout;
|
||||||
|
|
||||||
|
layout = meta_logical_monitor_get_layout (logical_monitor);
|
||||||
|
switch (get_barrier_adjacency (&layout, x1, y1, x2, y2, error))
|
||||||
|
{
|
||||||
|
case LINE_ADJACENCY_ERROR:
|
||||||
|
return FALSE;
|
||||||
|
case LINE_ADJACENCY_NONE:
|
||||||
|
break;
|
||||||
|
case LINE_ADJACENCY_CONTAINED:
|
||||||
|
if (has_adjecent_monitor)
|
||||||
|
{
|
||||||
|
g_set_error (error, G_IO_ERROR, G_IO_ERROR_INVALID_DATA,
|
||||||
|
"Adjecent to multiple monitor edges");
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
has_adjecent_monitor = TRUE;
|
||||||
|
break;
|
||||||
|
case LINE_ADJACENCY_OVERLAP:
|
||||||
|
g_set_error (error, G_IO_ERROR, G_IO_ERROR_INVALID_DATA,
|
||||||
|
"Line overlaps with monitor region");
|
||||||
|
return FALSE;
|
||||||
|
case LINE_ADJACENCY_PARTIAL:
|
||||||
|
g_set_error (error, G_IO_ERROR, G_IO_ERROR_INVALID_DATA,
|
||||||
|
"Line partially with monitor region");
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return has_adjecent_monitor;
|
||||||
|
}
|
||||||
|
|
||||||
|
static unsigned int
|
||||||
|
find_available_barrier_id (MetaInputCaptureSession *session)
|
||||||
|
{
|
||||||
|
unsigned int id;
|
||||||
|
|
||||||
|
for (id = 1;; id++)
|
||||||
|
{
|
||||||
|
if (!g_hash_table_contains (session->barriers, GUINT_TO_POINTER (id)))
|
||||||
|
return id;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
input_capture_barrier_free (gpointer user_data)
|
||||||
|
{
|
||||||
|
InputCaptureBarrier *input_capture_barrier = user_data;
|
||||||
|
|
||||||
|
g_clear_pointer (&input_capture_barrier->barrier, meta_barrier_destroy);
|
||||||
|
g_free (input_capture_barrier);
|
||||||
|
}
|
||||||
|
|
||||||
static gboolean
|
static gboolean
|
||||||
handle_add_barrier (MetaDBusInputCaptureSession *object,
|
handle_add_barrier (MetaDBusInputCaptureSession *object,
|
||||||
GDBusMethodInvocation *invocation,
|
GDBusMethodInvocation *invocation,
|
||||||
unsigned int serial,
|
unsigned int serial,
|
||||||
GVariant *position)
|
GVariant *position)
|
||||||
{
|
{
|
||||||
g_dbus_method_invocation_return_error (invocation, G_DBUS_ERROR,
|
MetaInputCaptureSession *session = META_INPUT_CAPTURE_SESSION (object);
|
||||||
G_DBUS_ERROR_FAILED,
|
int x1, y1, x2, y2;
|
||||||
"Not implemented");
|
g_autoptr (GError) error = NULL;
|
||||||
|
InputCaptureBarrier *input_capture_barrier;
|
||||||
|
unsigned int barrier_id;
|
||||||
|
|
||||||
|
if (!check_permission (session, invocation))
|
||||||
|
{
|
||||||
|
g_dbus_method_invocation_return_error (invocation, G_DBUS_ERROR,
|
||||||
|
G_DBUS_ERROR_ACCESS_DENIED,
|
||||||
|
"Permission denied");
|
||||||
|
return G_DBUS_METHOD_INVOCATION_HANDLED;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (session->zones_serial != serial)
|
||||||
|
{
|
||||||
|
g_dbus_method_invocation_return_error (invocation, G_DBUS_ERROR,
|
||||||
|
G_DBUS_ERROR_BAD_ADDRESS,
|
||||||
|
"State out of date");
|
||||||
|
return G_DBUS_METHOD_INVOCATION_HANDLED;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (session->state != INPUT_CAPTURE_STATE_INIT)
|
||||||
|
{
|
||||||
|
g_dbus_method_invocation_return_error (invocation, G_DBUS_ERROR,
|
||||||
|
G_DBUS_ERROR_ACCESS_DENIED,
|
||||||
|
"Session already enabled");
|
||||||
|
return G_DBUS_METHOD_INVOCATION_HANDLED;
|
||||||
|
}
|
||||||
|
|
||||||
|
g_variant_get (position, "(iiii)", &x1, &y1, &x2, &y2);
|
||||||
|
if (!check_barrier (session, x1, y1, x2, y2, &error))
|
||||||
|
{
|
||||||
|
g_dbus_method_invocation_return_error_literal (invocation, G_DBUS_ERROR,
|
||||||
|
G_DBUS_ERROR_ACCESS_DENIED,
|
||||||
|
error->message);
|
||||||
|
return G_DBUS_METHOD_INVOCATION_HANDLED;
|
||||||
|
}
|
||||||
|
|
||||||
|
barrier_id = find_available_barrier_id (session);
|
||||||
|
|
||||||
|
input_capture_barrier = g_new0 (InputCaptureBarrier, 1);
|
||||||
|
*input_capture_barrier = (InputCaptureBarrier) {
|
||||||
|
.id = barrier_id,
|
||||||
|
.x1 = x1,
|
||||||
|
.y1 = y1,
|
||||||
|
.x2 = x2,
|
||||||
|
.y2 = y2,
|
||||||
|
};
|
||||||
|
g_hash_table_insert (session->barriers,
|
||||||
|
GUINT_TO_POINTER (barrier_id),
|
||||||
|
input_capture_barrier);
|
||||||
|
|
||||||
|
meta_dbus_input_capture_session_complete_add_barrier (object, invocation,
|
||||||
|
barrier_id);
|
||||||
|
|
||||||
return G_DBUS_METHOD_INVOCATION_HANDLED;
|
return G_DBUS_METHOD_INVOCATION_HANDLED;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -204,7 +564,7 @@ handle_get_zones (MetaDBusInputCaptureSession *object,
|
|||||||
zones_variant = g_variant_builder_end (&zones_builder);
|
zones_variant = g_variant_builder_end (&zones_builder);
|
||||||
|
|
||||||
meta_dbus_input_capture_session_complete_get_zones (object, invocation,
|
meta_dbus_input_capture_session_complete_get_zones (object, invocation,
|
||||||
session->serial,
|
session->zones_serial,
|
||||||
zones_variant);
|
zones_variant);
|
||||||
return G_DBUS_METHOD_INVOCATION_HANDLED;
|
return G_DBUS_METHOD_INVOCATION_HANDLED;
|
||||||
}
|
}
|
||||||
@ -224,7 +584,7 @@ handle_enable (MetaDBusInputCaptureSession *skeleton,
|
|||||||
return G_DBUS_METHOD_INVOCATION_HANDLED;
|
return G_DBUS_METHOD_INVOCATION_HANDLED;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (session->enabled)
|
if (session->state != INPUT_CAPTURE_STATE_INIT)
|
||||||
{
|
{
|
||||||
g_dbus_method_invocation_return_error (invocation, G_DBUS_ERROR,
|
g_dbus_method_invocation_return_error (invocation, G_DBUS_ERROR,
|
||||||
G_DBUS_ERROR_FAILED,
|
G_DBUS_ERROR_FAILED,
|
||||||
@ -261,7 +621,8 @@ handle_disable (MetaDBusInputCaptureSession *skeleton,
|
|||||||
return G_DBUS_METHOD_INVOCATION_HANDLED;
|
return G_DBUS_METHOD_INVOCATION_HANDLED;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!session->enabled)
|
if (session->state != INPUT_CAPTURE_STATE_ENABLED &&
|
||||||
|
session->state != INPUT_CAPTURE_STATE_ACTIVATED)
|
||||||
{
|
{
|
||||||
g_dbus_method_invocation_return_error (invocation, G_DBUS_ERROR,
|
g_dbus_method_invocation_return_error (invocation, G_DBUS_ERROR,
|
||||||
G_DBUS_ERROR_FAILED,
|
G_DBUS_ERROR_FAILED,
|
||||||
@ -281,9 +642,40 @@ handle_release (MetaDBusInputCaptureSession *object,
|
|||||||
GDBusMethodInvocation *invocation,
|
GDBusMethodInvocation *invocation,
|
||||||
GVariant *position)
|
GVariant *position)
|
||||||
{
|
{
|
||||||
g_dbus_method_invocation_return_error (invocation, G_DBUS_ERROR,
|
MetaInputCaptureSession *session = META_INPUT_CAPTURE_SESSION (object);
|
||||||
G_DBUS_ERROR_ACCESS_DENIED,
|
MetaBackend *backend =
|
||||||
"Not implemented");
|
meta_dbus_session_manager_get_backend (session->session_manager);
|
||||||
|
ClutterSeat *seat = meta_backend_get_default_seat (backend);
|
||||||
|
double x, y;
|
||||||
|
|
||||||
|
if (!check_permission (session, invocation))
|
||||||
|
{
|
||||||
|
g_dbus_method_invocation_return_error (invocation, G_DBUS_ERROR,
|
||||||
|
G_DBUS_ERROR_ACCESS_DENIED,
|
||||||
|
"Permission denied");
|
||||||
|
return G_DBUS_METHOD_INVOCATION_HANDLED;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (session->state != INPUT_CAPTURE_STATE_ACTIVATED)
|
||||||
|
{
|
||||||
|
g_dbus_method_invocation_return_error (invocation, G_DBUS_ERROR,
|
||||||
|
G_DBUS_ERROR_ACCESS_DENIED,
|
||||||
|
"Capture not active");
|
||||||
|
return G_DBUS_METHOD_INVOCATION_HANDLED;
|
||||||
|
}
|
||||||
|
|
||||||
|
release_all_barriers (session);
|
||||||
|
|
||||||
|
session->state = INPUT_CAPTURE_STATE_ENABLED;
|
||||||
|
|
||||||
|
g_variant_get (position, "(dd)", &x, &y);
|
||||||
|
clutter_seat_warp_pointer (seat, x, y);
|
||||||
|
|
||||||
|
if (session->handle)
|
||||||
|
release_remote_access_handle (session);
|
||||||
|
|
||||||
|
meta_dbus_input_capture_session_complete_release (object, invocation);
|
||||||
|
|
||||||
return G_DBUS_METHOD_INVOCATION_HANDLED;
|
return G_DBUS_METHOD_INVOCATION_HANDLED;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -315,7 +707,7 @@ on_monitors_changed (MetaMonitorManager *monitor_manager,
|
|||||||
MetaDBusInputCaptureSession *skeleton =
|
MetaDBusInputCaptureSession *skeleton =
|
||||||
META_DBUS_INPUT_CAPTURE_SESSION (session);
|
META_DBUS_INPUT_CAPTURE_SESSION (session);
|
||||||
|
|
||||||
session->serial++;
|
session->zones_serial++;
|
||||||
meta_input_capture_session_disable (session);
|
meta_input_capture_session_disable (session);
|
||||||
meta_dbus_input_capture_session_emit_zones_changed (skeleton);
|
meta_dbus_input_capture_session_emit_zones_changed (skeleton);
|
||||||
}
|
}
|
||||||
@ -375,6 +767,8 @@ meta_input_capture_session_finalize (GObject *object)
|
|||||||
{
|
{
|
||||||
MetaInputCaptureSession *session = META_INPUT_CAPTURE_SESSION (object);
|
MetaInputCaptureSession *session = META_INPUT_CAPTURE_SESSION (object);
|
||||||
|
|
||||||
|
g_clear_pointer (&session->barriers, g_hash_table_unref);
|
||||||
|
|
||||||
g_clear_object (&session->handle);
|
g_clear_object (&session->handle);
|
||||||
g_free (session->peer_name);
|
g_free (session->peer_name);
|
||||||
g_free (session->session_id);
|
g_free (session->session_id);
|
||||||
@ -444,6 +838,9 @@ meta_input_capture_session_class_init (MetaInputCaptureSessionClass *klass)
|
|||||||
object_class->get_property = meta_input_capture_session_get_property;
|
object_class->get_property = meta_input_capture_session_get_property;
|
||||||
|
|
||||||
meta_dbus_session_install_properties (object_class, N_PROPS);
|
meta_dbus_session_install_properties (object_class, N_PROPS);
|
||||||
|
|
||||||
|
quark_barrier_id =
|
||||||
|
g_quark_from_static_string ("meta-input-capture-barrier-id-quark");
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
@ -454,6 +851,9 @@ meta_input_capture_session_init (MetaInputCaptureSession *session)
|
|||||||
session->object_path =
|
session->object_path =
|
||||||
g_strdup_printf (META_INPUT_CAPTURE_SESSION_DBUS_PATH "/u%u",
|
g_strdup_printf (META_INPUT_CAPTURE_SESSION_DBUS_PATH "/u%u",
|
||||||
++global_session_number);
|
++global_session_number);
|
||||||
|
|
||||||
|
session->barriers = g_hash_table_new_full (NULL, NULL, NULL,
|
||||||
|
input_capture_barrier_free);
|
||||||
}
|
}
|
||||||
|
|
||||||
char *
|
char *
|
||||||
|
@ -21,6 +21,7 @@
|
|||||||
#include "config.h"
|
#include "config.h"
|
||||||
|
|
||||||
#include <glib.h>
|
#include <glib.h>
|
||||||
|
#include <gio/gunixinputstream.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
|
|
||||||
#include "meta-dbus-input-capture.h"
|
#include "meta-dbus-input-capture.h"
|
||||||
@ -54,6 +55,8 @@ typedef struct _InputCaptureSession
|
|||||||
unsigned int serial;
|
unsigned int serial;
|
||||||
} InputCaptureSession;
|
} InputCaptureSession;
|
||||||
|
|
||||||
|
static GDataInputStream *stdin_reader;
|
||||||
|
|
||||||
static void
|
static void
|
||||||
ping_mutter (InputCaptureSession *session)
|
ping_mutter (InputCaptureSession *session)
|
||||||
{
|
{
|
||||||
@ -80,6 +83,54 @@ write_state (InputCaptureSession *session,
|
|||||||
fflush (stdout);
|
fflush (stdout);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
typedef struct
|
||||||
|
{
|
||||||
|
GMainLoop *loop;
|
||||||
|
const char *expected_state;
|
||||||
|
} WaitData;
|
||||||
|
|
||||||
|
static void
|
||||||
|
on_line_read (GObject *source_object,
|
||||||
|
GAsyncResult *res,
|
||||||
|
gpointer user_data)
|
||||||
|
{
|
||||||
|
WaitData *data = user_data;
|
||||||
|
g_autofree char *line = NULL;
|
||||||
|
g_autoptr (GError) error = NULL;
|
||||||
|
|
||||||
|
line =
|
||||||
|
g_data_input_stream_read_line_finish (G_DATA_INPUT_STREAM (source_object),
|
||||||
|
res, NULL, &error);
|
||||||
|
if (error)
|
||||||
|
g_error ("Failed to read line from test client: %s", error->message);
|
||||||
|
if (!line)
|
||||||
|
g_error ("Unexpected EOF");
|
||||||
|
|
||||||
|
g_assert_cmpstr (data->expected_state, ==, line);
|
||||||
|
|
||||||
|
g_main_loop_quit (data->loop);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
wait_for_state (InputCaptureSession *session,
|
||||||
|
const char *expected_state)
|
||||||
|
{
|
||||||
|
WaitData data;
|
||||||
|
|
||||||
|
data.loop = g_main_loop_new (NULL, FALSE);
|
||||||
|
data.expected_state = expected_state;
|
||||||
|
|
||||||
|
g_data_input_stream_read_line_async (stdin_reader,
|
||||||
|
G_PRIORITY_DEFAULT,
|
||||||
|
NULL,
|
||||||
|
on_line_read,
|
||||||
|
&data);
|
||||||
|
|
||||||
|
g_main_loop_run (data.loop);
|
||||||
|
g_main_loop_unref (data.loop);
|
||||||
|
ping_mutter (session);
|
||||||
|
}
|
||||||
|
|
||||||
static InputCapture *
|
static InputCapture *
|
||||||
input_capture_new (void)
|
input_capture_new (void)
|
||||||
{
|
{
|
||||||
@ -174,6 +225,31 @@ input_capture_session_get_zones (InputCaptureSession *session)
|
|||||||
return zones;
|
return zones;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static unsigned int
|
||||||
|
input_capture_session_add_barrier (InputCaptureSession *session,
|
||||||
|
int x1,
|
||||||
|
int y1,
|
||||||
|
int x2,
|
||||||
|
int y2)
|
||||||
|
{
|
||||||
|
g_autoptr (GError) error = NULL;
|
||||||
|
unsigned int barrier_id;
|
||||||
|
|
||||||
|
if (!meta_dbus_input_capture_session_call_add_barrier_sync (
|
||||||
|
session->proxy,
|
||||||
|
session->serial,
|
||||||
|
g_variant_new ("(iiii)", x1, y1, x2, y2),
|
||||||
|
&barrier_id,
|
||||||
|
NULL,
|
||||||
|
&error))
|
||||||
|
{
|
||||||
|
g_warning ("Failed to add barrier: %s", error->message);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
return barrier_id;
|
||||||
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
input_capture_session_enable (InputCaptureSession *session)
|
input_capture_session_enable (InputCaptureSession *session)
|
||||||
{
|
{
|
||||||
@ -194,6 +270,21 @@ input_capture_session_disable (InputCaptureSession *session)
|
|||||||
g_warning ("Failed to disable session: %s", error->message);
|
g_warning ("Failed to disable session: %s", error->message);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
input_capture_session_release (InputCaptureSession *session,
|
||||||
|
double x,
|
||||||
|
double y)
|
||||||
|
{
|
||||||
|
g_autoptr (GError) error = NULL;
|
||||||
|
GVariant *position;
|
||||||
|
|
||||||
|
position = g_variant_new ("(dd)", x, y);
|
||||||
|
if (!meta_dbus_input_capture_session_call_release_sync (session->proxy,
|
||||||
|
position,
|
||||||
|
NULL, &error))
|
||||||
|
g_warning ("Failed to release pointer: %s", error->message);
|
||||||
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
test_sanity (void)
|
test_sanity (void)
|
||||||
{
|
{
|
||||||
@ -296,6 +387,98 @@ test_zones (void)
|
|||||||
input_capture_session_close (session);
|
input_capture_session_close (session);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
typedef struct
|
||||||
|
{
|
||||||
|
unsigned int activated_barrier_id;
|
||||||
|
double activated_x;
|
||||||
|
double activated_y;
|
||||||
|
unsigned int activated_serial;
|
||||||
|
} BarriersTestData;
|
||||||
|
|
||||||
|
static void
|
||||||
|
on_activated (MetaDBusInputCaptureSession *proxy,
|
||||||
|
unsigned int barrier_id,
|
||||||
|
unsigned int serial,
|
||||||
|
GVariant *cursor_position,
|
||||||
|
BarriersTestData *data)
|
||||||
|
{
|
||||||
|
g_assert_cmpuint (data->activated_barrier_id, ==, 0);
|
||||||
|
|
||||||
|
data->activated_barrier_id = barrier_id;
|
||||||
|
data->activated_serial = serial;
|
||||||
|
g_variant_get (cursor_position, "(dd)",
|
||||||
|
&data->activated_x, &data->activated_y);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
test_barriers (void)
|
||||||
|
{
|
||||||
|
InputCapture *input_capture;
|
||||||
|
InputCaptureSession *session;
|
||||||
|
g_autolist (Zone) zones = NULL;
|
||||||
|
unsigned int barrier1, barrier2;
|
||||||
|
BarriersTestData data = {};
|
||||||
|
unsigned int prev_activated_serial;
|
||||||
|
|
||||||
|
input_capture = input_capture_new ();
|
||||||
|
session = input_capture_create_session (input_capture);
|
||||||
|
|
||||||
|
zones = input_capture_session_get_zones (session);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* +-------------+--------------+
|
||||||
|
* || | |
|
||||||
|
* ||<--B#1 | |
|
||||||
|
* || | B#2 |
|
||||||
|
* +-------------+ | |
|
||||||
|
* | V |
|
||||||
|
* +==============+
|
||||||
|
*/
|
||||||
|
barrier1 = input_capture_session_add_barrier (session, 0, 0, 0, 600);
|
||||||
|
barrier2 = input_capture_session_add_barrier (session, 800, 768, 1824, 768);
|
||||||
|
|
||||||
|
g_assert_cmpuint (barrier1, !=, 0);
|
||||||
|
g_assert_cmpuint (barrier2, !=, 0);
|
||||||
|
g_assert_cmpuint (barrier1, !=, barrier2);
|
||||||
|
|
||||||
|
g_signal_connect (session->proxy, "activated",
|
||||||
|
G_CALLBACK (on_activated), &data);
|
||||||
|
|
||||||
|
input_capture_session_enable (session);
|
||||||
|
|
||||||
|
write_state (session, "1");
|
||||||
|
|
||||||
|
while (data.activated_barrier_id == 0)
|
||||||
|
g_main_context_iteration (NULL, TRUE);
|
||||||
|
|
||||||
|
g_assert_cmpuint (data.activated_serial, !=, 0);
|
||||||
|
g_assert_cmpuint (data.activated_barrier_id, ==, barrier1);
|
||||||
|
g_assert_cmpfloat_with_epsilon (data.activated_x, 0.0, DBL_EPSILON);
|
||||||
|
g_assert_cmpfloat_with_epsilon (data.activated_y, 15.0, DBL_EPSILON);
|
||||||
|
|
||||||
|
wait_for_state (session, "1");
|
||||||
|
|
||||||
|
input_capture_session_release (session, 200, 150);
|
||||||
|
|
||||||
|
write_state (session, "2");
|
||||||
|
|
||||||
|
prev_activated_serial = data.activated_serial;
|
||||||
|
|
||||||
|
data = (BarriersTestData) {};
|
||||||
|
while (data.activated_barrier_id == 0)
|
||||||
|
g_main_context_iteration (NULL, TRUE);
|
||||||
|
g_assert_cmpuint (data.activated_serial, !=, 0);
|
||||||
|
g_assert_cmpuint (data.activated_serial, !=, prev_activated_serial);
|
||||||
|
g_assert_cmpuint (data.activated_barrier_id, ==, barrier2);
|
||||||
|
g_assert_cmpfloat_with_epsilon (data.activated_x, 1000.0, DBL_EPSILON);
|
||||||
|
g_assert_cmpfloat_with_epsilon (data.activated_y, 768.0, DBL_EPSILON);
|
||||||
|
|
||||||
|
input_capture_session_release (session, 1200, 700);
|
||||||
|
write_state (session, "3");
|
||||||
|
|
||||||
|
input_capture_session_close (session);
|
||||||
|
}
|
||||||
|
|
||||||
static const struct
|
static const struct
|
||||||
{
|
{
|
||||||
const char *name;
|
const char *name;
|
||||||
@ -303,6 +486,7 @@ static const struct
|
|||||||
} test_cases[] = {
|
} test_cases[] = {
|
||||||
{ "sanity", test_sanity, },
|
{ "sanity", test_sanity, },
|
||||||
{ "zones", test_zones, },
|
{ "zones", test_zones, },
|
||||||
|
{ "barriers", test_barriers, },
|
||||||
};
|
};
|
||||||
|
|
||||||
static void
|
static void
|
||||||
@ -330,7 +514,16 @@ main (int argc,
|
|||||||
{
|
{
|
||||||
if (g_strcmp0 (test_cases[i].name, test_case) == 0)
|
if (g_strcmp0 (test_cases[i].name, test_case) == 0)
|
||||||
{
|
{
|
||||||
|
g_autoptr (GInputStream) stdin_stream = NULL;
|
||||||
|
|
||||||
|
stdin_stream = g_unix_input_stream_new (fileno (stdin), FALSE);
|
||||||
|
stdin_reader = g_data_input_stream_new (stdin_stream);
|
||||||
|
|
||||||
test_cases[i].func ();
|
test_cases[i].func ();
|
||||||
|
|
||||||
|
g_clear_object (&stdin_reader);
|
||||||
|
g_clear_object (&stdin_stream);
|
||||||
|
|
||||||
return EXIT_SUCCESS;
|
return EXIT_SUCCESS;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -22,6 +22,7 @@
|
|||||||
|
|
||||||
#include <gio/gio.h>
|
#include <gio/gio.h>
|
||||||
|
|
||||||
|
#include "backends/meta-backend-private.h"
|
||||||
#include "meta-test/meta-context-test.h"
|
#include "meta-test/meta-context-test.h"
|
||||||
#include "tests/meta-test-utils.h"
|
#include "tests/meta-test-utils.h"
|
||||||
|
|
||||||
@ -31,6 +32,7 @@ typedef struct _InputCaptureTestClient
|
|||||||
char *path;
|
char *path;
|
||||||
GMainLoop *main_loop;
|
GMainLoop *main_loop;
|
||||||
GDataInputStream *line_reader;
|
GDataInputStream *line_reader;
|
||||||
|
GDataOutputStream *line_writer;
|
||||||
} InputCaptureTestClient;
|
} InputCaptureTestClient;
|
||||||
|
|
||||||
static MetaContext *test_context;
|
static MetaContext *test_context;
|
||||||
@ -45,13 +47,16 @@ input_capture_test_client_new (const char *test_case)
|
|||||||
InputCaptureTestClient *test_client;
|
InputCaptureTestClient *test_client;
|
||||||
GInputStream *stdout_stream;
|
GInputStream *stdout_stream;
|
||||||
GDataInputStream *line_reader;
|
GDataInputStream *line_reader;
|
||||||
|
GOutputStream *stdin_stream;
|
||||||
|
GDataOutputStream *line_writer;
|
||||||
|
|
||||||
test_client_path = g_test_build_filename (G_TEST_BUILT,
|
test_client_path = g_test_build_filename (G_TEST_BUILT,
|
||||||
"src",
|
"src",
|
||||||
"tests",
|
"tests",
|
||||||
"mutter-input-capture-test-client",
|
"mutter-input-capture-test-client",
|
||||||
NULL);
|
NULL);
|
||||||
launcher = g_subprocess_launcher_new (G_SUBPROCESS_FLAGS_STDOUT_PIPE);
|
launcher = g_subprocess_launcher_new (G_SUBPROCESS_FLAGS_STDOUT_PIPE |
|
||||||
|
G_SUBPROCESS_FLAGS_STDIN_PIPE);
|
||||||
subprocess = g_subprocess_launcher_spawn (launcher,
|
subprocess = g_subprocess_launcher_spawn (launcher,
|
||||||
&error,
|
&error,
|
||||||
test_client_path,
|
test_client_path,
|
||||||
@ -63,10 +68,14 @@ input_capture_test_client_new (const char *test_case)
|
|||||||
stdout_stream = g_subprocess_get_stdout_pipe (subprocess);
|
stdout_stream = g_subprocess_get_stdout_pipe (subprocess);
|
||||||
line_reader = g_data_input_stream_new (stdout_stream);
|
line_reader = g_data_input_stream_new (stdout_stream);
|
||||||
|
|
||||||
|
stdin_stream = g_subprocess_get_stdin_pipe (subprocess);
|
||||||
|
line_writer = g_data_output_stream_new (stdin_stream);
|
||||||
|
|
||||||
test_client = g_new0 (InputCaptureTestClient, 1);
|
test_client = g_new0 (InputCaptureTestClient, 1);
|
||||||
test_client->subprocess = subprocess;
|
test_client->subprocess = subprocess;
|
||||||
test_client->main_loop = g_main_loop_new (NULL, FALSE);
|
test_client->main_loop = g_main_loop_new (NULL, FALSE);
|
||||||
test_client->line_reader = line_reader;
|
test_client->line_reader = line_reader;
|
||||||
|
test_client->line_writer = line_writer;
|
||||||
|
|
||||||
return test_client;
|
return test_client;
|
||||||
}
|
}
|
||||||
@ -118,6 +127,24 @@ input_capture_test_client_wait_for_state (InputCaptureTestClient *test_client,
|
|||||||
g_main_loop_unref (data.loop);
|
g_main_loop_unref (data.loop);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
input_capture_test_client_write_state (InputCaptureTestClient *test_client,
|
||||||
|
const char *state)
|
||||||
|
{
|
||||||
|
g_autoptr (GError) error = NULL;
|
||||||
|
g_autofree char *line = NULL;
|
||||||
|
|
||||||
|
line = g_strdup_printf ("%s\n", state);
|
||||||
|
|
||||||
|
if (!g_data_output_stream_put_string (test_client->line_writer,
|
||||||
|
line, NULL, &error))
|
||||||
|
g_error ("Failed to write state: %s", error->message);
|
||||||
|
|
||||||
|
if (!g_output_stream_flush (G_OUTPUT_STREAM (test_client->line_writer),
|
||||||
|
NULL, &error))
|
||||||
|
g_error ("Failed to flush state: %s", error->message);
|
||||||
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
input_capture_test_client_finished (GObject *source_object,
|
input_capture_test_client_finished (GObject *source_object,
|
||||||
GAsyncResult *res,
|
GAsyncResult *res,
|
||||||
@ -181,6 +208,83 @@ meta_test_input_capture_zones (void)
|
|||||||
input_capture_test_client_finish (test_client);
|
input_capture_test_client_finish (test_client);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
assert_pointer_position (ClutterSeat *seat,
|
||||||
|
double x,
|
||||||
|
double y)
|
||||||
|
{
|
||||||
|
graphene_point_t pos;
|
||||||
|
|
||||||
|
clutter_seat_query_state (seat,
|
||||||
|
clutter_seat_get_pointer (seat),
|
||||||
|
NULL, &pos, NULL);
|
||||||
|
|
||||||
|
g_assert_cmpfloat_with_epsilon (pos.x, x, DBL_EPSILON);
|
||||||
|
g_assert_cmpfloat_with_epsilon (pos.y, y, DBL_EPSILON);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
meta_test_input_capture_barriers (void)
|
||||||
|
{
|
||||||
|
MetaBackend *backend = meta_context_get_backend (test_context);
|
||||||
|
ClutterSeat *seat = meta_backend_get_default_seat (backend);
|
||||||
|
g_autoptr (MetaVirtualMonitor) virtual_monitor1 = NULL;
|
||||||
|
g_autoptr (MetaVirtualMonitor) virtual_monitor2 = NULL;
|
||||||
|
g_autoptr (ClutterVirtualInputDevice) virtual_pointer = NULL;
|
||||||
|
InputCaptureTestClient *test_client;
|
||||||
|
|
||||||
|
virtual_monitor1 = meta_create_test_monitor (test_context, 800, 600, 20.0);
|
||||||
|
virtual_monitor2 = meta_create_test_monitor (test_context, 1024, 768, 20.0);
|
||||||
|
|
||||||
|
virtual_pointer = clutter_seat_create_virtual_device (seat,
|
||||||
|
CLUTTER_POINTER_DEVICE);
|
||||||
|
clutter_virtual_input_device_notify_absolute_motion (virtual_pointer,
|
||||||
|
g_get_monotonic_time (),
|
||||||
|
10.0, 10.0);
|
||||||
|
|
||||||
|
test_client = input_capture_test_client_new ("barriers");
|
||||||
|
input_capture_test_client_wait_for_state (test_client, "1");
|
||||||
|
|
||||||
|
clutter_virtual_input_device_notify_relative_motion (virtual_pointer,
|
||||||
|
g_get_monotonic_time (),
|
||||||
|
-20.0, 10.0);
|
||||||
|
clutter_virtual_input_device_notify_relative_motion (virtual_pointer,
|
||||||
|
g_get_monotonic_time (),
|
||||||
|
-20.0, 10.0);
|
||||||
|
clutter_virtual_input_device_notify_relative_motion (virtual_pointer,
|
||||||
|
g_get_monotonic_time (),
|
||||||
|
-20.0, 10.0);
|
||||||
|
|
||||||
|
meta_flush_input (test_context);
|
||||||
|
meta_wait_for_paint (test_context);
|
||||||
|
|
||||||
|
assert_pointer_position (seat, 0.0, 15.0);
|
||||||
|
|
||||||
|
input_capture_test_client_write_state (test_client, "1");
|
||||||
|
input_capture_test_client_wait_for_state (test_client, "2");
|
||||||
|
|
||||||
|
meta_flush_input (test_context);
|
||||||
|
meta_wait_for_paint (test_context);
|
||||||
|
|
||||||
|
assert_pointer_position (seat, 200.0, 150.0);
|
||||||
|
|
||||||
|
clutter_virtual_input_device_notify_relative_motion (virtual_pointer,
|
||||||
|
g_get_monotonic_time (),
|
||||||
|
800.0, 300.0);
|
||||||
|
meta_flush_input (test_context);
|
||||||
|
|
||||||
|
assert_pointer_position (seat, 1000.0, 450.0);
|
||||||
|
|
||||||
|
clutter_virtual_input_device_notify_relative_motion (virtual_pointer,
|
||||||
|
g_get_monotonic_time (),
|
||||||
|
0.0, 400.0);
|
||||||
|
|
||||||
|
input_capture_test_client_wait_for_state (test_client, "3");
|
||||||
|
assert_pointer_position (seat, 1200.0, 700.0);
|
||||||
|
|
||||||
|
input_capture_test_client_finish (test_client);
|
||||||
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
init_tests (void)
|
init_tests (void)
|
||||||
{
|
{
|
||||||
@ -188,6 +292,8 @@ init_tests (void)
|
|||||||
meta_test_input_capture_sanity);
|
meta_test_input_capture_sanity);
|
||||||
g_test_add_func ("/backends/native/input-capture/zones",
|
g_test_add_func ("/backends/native/input-capture/zones",
|
||||||
meta_test_input_capture_zones);
|
meta_test_input_capture_zones);
|
||||||
|
g_test_add_func ("/backends/native/input-capture/barriers",
|
||||||
|
meta_test_input_capture_barriers);
|
||||||
}
|
}
|
||||||
|
|
||||||
int
|
int
|
||||||
|
Loading…
x
Reference in New Issue
Block a user