mirror of
https://gitlab.gnome.org/GNOME/libmks.git
synced 2024-12-22 13:45:21 +00:00
lib: make clicks and motion work
We need to handle a mouse that is not absolute positioned (the default it seems) and this does that (crudely for the moment until we have some sort of grab management). Additionally, click events are propagated to the Qemu instance as well.
This commit is contained in:
parent
beb7299d25
commit
6c5829d949
@ -51,6 +51,18 @@ typedef struct
|
|||||||
* API using press/release and the hardware keycode.
|
* API using press/release and the hardware keycode.
|
||||||
*/
|
*/
|
||||||
GtkEventControllerKey *key;
|
GtkEventControllerKey *key;
|
||||||
|
|
||||||
|
/* Used to send mouse press/release events translated from the current
|
||||||
|
* button in the gesture. X,Y coordinates are expected to already be
|
||||||
|
* updated from GtkEventControllerMotion::motion events.
|
||||||
|
*/
|
||||||
|
GtkGestureClick *click;
|
||||||
|
|
||||||
|
/* Tracking the last known positions of mouse events so that we may
|
||||||
|
* emulate mks_mouse_move_by() using GtkEventControllerMotion.
|
||||||
|
*/
|
||||||
|
double last_mouse_x;
|
||||||
|
double last_mouse_y;
|
||||||
} MksDisplayPrivate;
|
} MksDisplayPrivate;
|
||||||
|
|
||||||
enum {
|
enum {
|
||||||
@ -176,23 +188,96 @@ mks_display_translate_coordinate (MksDisplay *self,
|
|||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
mks_display_motion_enter_cb (MksDisplay *self,
|
mks_display_mouse_move_to_cb (GObject *object,
|
||||||
double x,
|
GAsyncResult *result,
|
||||||
double y,
|
gpointer user_data)
|
||||||
GtkEventControllerMotion *motion)
|
{
|
||||||
|
MksMouse *mouse = (MksMouse *)object;
|
||||||
|
g_autoptr(MksDisplay) self = user_data;
|
||||||
|
g_autoptr(GError) error = NULL;
|
||||||
|
|
||||||
|
g_assert (MKS_IS_MOUSE (mouse));
|
||||||
|
g_assert (G_IS_ASYNC_RESULT (result));
|
||||||
|
g_assert (MKS_IS_DISPLAY (self));
|
||||||
|
|
||||||
|
if (!mks_mouse_move_to_finish (mouse, result, &error))
|
||||||
|
g_warning ("Failed move_to: %s", error->message);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
mks_display_mouse_move_by_cb (GObject *object,
|
||||||
|
GAsyncResult *result,
|
||||||
|
gpointer user_data)
|
||||||
|
{
|
||||||
|
MksMouse *mouse = (MksMouse *)object;
|
||||||
|
g_autoptr(MksDisplay) self = user_data;
|
||||||
|
g_autoptr(GError) error = NULL;
|
||||||
|
|
||||||
|
g_assert (MKS_IS_MOUSE (mouse));
|
||||||
|
g_assert (G_IS_ASYNC_RESULT (result));
|
||||||
|
g_assert (MKS_IS_DISPLAY (self));
|
||||||
|
|
||||||
|
if (!mks_mouse_move_by_finish (mouse, result, &error))
|
||||||
|
g_warning ("Failed move_by: %s", error->message);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
mks_display_motion (MksDisplay *self,
|
||||||
|
double x,
|
||||||
|
double y)
|
||||||
{
|
{
|
||||||
MksDisplayPrivate *priv = mks_display_get_instance_private (self);
|
MksDisplayPrivate *priv = mks_display_get_instance_private (self);
|
||||||
MksMouse *mouse;
|
MksMouse *mouse;
|
||||||
|
|
||||||
g_assert (MKS_IS_DISPLAY (self));
|
g_assert (MKS_IS_DISPLAY (self));
|
||||||
g_assert (GTK_IS_EVENT_CONTROLLER_MOTION (motion));
|
g_assert (!priv->screen || MKS_IS_SCREEN (priv->screen));
|
||||||
|
|
||||||
if (priv->screen == NULL)
|
if (priv->screen == NULL)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
/* TODO:
|
||||||
|
*
|
||||||
|
* This is pretty crappy right now because as you enter and
|
||||||
|
* leave you never really reset your position within the remote
|
||||||
|
* display.
|
||||||
|
*
|
||||||
|
* To fix this, we need real grabs or some other mechanism so
|
||||||
|
* that we can hide the local cursor and warp it to where we
|
||||||
|
* discover the cursor in the remote display upon entering
|
||||||
|
* the picture widget.
|
||||||
|
*/
|
||||||
|
|
||||||
mouse = mks_screen_get_mouse (priv->screen);
|
mouse = mks_screen_get_mouse (priv->screen);
|
||||||
|
|
||||||
|
if (mks_mouse_get_is_absolute (mouse))
|
||||||
|
mks_mouse_move_to (mouse,
|
||||||
|
x, y,
|
||||||
|
NULL,
|
||||||
|
mks_display_mouse_move_to_cb,
|
||||||
|
g_object_ref (self));
|
||||||
|
else
|
||||||
|
mks_mouse_move_by (mouse,
|
||||||
|
x - priv->last_mouse_x,
|
||||||
|
y - priv->last_mouse_y,
|
||||||
|
NULL,
|
||||||
|
mks_display_mouse_move_by_cb,
|
||||||
|
g_object_ref (self));
|
||||||
|
|
||||||
|
priv->last_mouse_x = x;
|
||||||
|
priv->last_mouse_y = y;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
mks_display_motion_enter_cb (MksDisplay *self,
|
||||||
|
double x,
|
||||||
|
double y,
|
||||||
|
GtkEventControllerMotion *motion)
|
||||||
|
{
|
||||||
|
g_assert (MKS_IS_DISPLAY (self));
|
||||||
|
g_assert (GTK_IS_EVENT_CONTROLLER_MOTION (motion));
|
||||||
|
|
||||||
mks_display_translate_coordinate (self, &x, &y);
|
mks_display_translate_coordinate (self, &x, &y);
|
||||||
mks_mouse_move_to (mouse, x, y, NULL, NULL, NULL);
|
mks_display_motion (self, x, y);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
@ -201,18 +286,11 @@ mks_display_motion_motion_cb (MksDisplay *self,
|
|||||||
double y,
|
double y,
|
||||||
GtkEventControllerMotion *motion)
|
GtkEventControllerMotion *motion)
|
||||||
{
|
{
|
||||||
MksDisplayPrivate *priv = mks_display_get_instance_private (self);
|
|
||||||
MksMouse *mouse;
|
|
||||||
|
|
||||||
g_assert (MKS_IS_DISPLAY (self));
|
g_assert (MKS_IS_DISPLAY (self));
|
||||||
g_assert (GTK_IS_EVENT_CONTROLLER_MOTION (motion));
|
g_assert (GTK_IS_EVENT_CONTROLLER_MOTION (motion));
|
||||||
|
|
||||||
if (priv->screen == NULL)
|
|
||||||
return;
|
|
||||||
|
|
||||||
mouse = mks_screen_get_mouse (priv->screen);
|
|
||||||
mks_display_translate_coordinate (self, &x, &y);
|
mks_display_translate_coordinate (self, &x, &y);
|
||||||
mks_mouse_move_to (mouse, x, y, NULL, NULL, NULL);
|
mks_display_motion (self, x, y);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
@ -223,6 +301,114 @@ mks_display_motion_leave_cb (MksDisplay *self,
|
|||||||
g_assert (GTK_IS_EVENT_CONTROLLER_MOTION (motion));
|
g_assert (GTK_IS_EVENT_CONTROLLER_MOTION (motion));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
mks_display_translate_button (MksDisplay *self,
|
||||||
|
int *button)
|
||||||
|
{
|
||||||
|
g_assert (MKS_IS_DISPLAY (self));
|
||||||
|
g_assert (button != NULL);
|
||||||
|
|
||||||
|
switch (*button)
|
||||||
|
{
|
||||||
|
case 1: *button = MKS_MOUSE_BUTTON_LEFT; break;
|
||||||
|
case 2: *button = MKS_MOUSE_BUTTON_MIDDLE; break;
|
||||||
|
case 3: *button = MKS_MOUSE_BUTTON_RIGHT; break;
|
||||||
|
case 8: *button = MKS_MOUSE_BUTTON_SIDE; break;
|
||||||
|
case 9: *button = MKS_MOUSE_BUTTON_EXTRA; break;
|
||||||
|
default: break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
mks_display_mouse_press_cb (GObject *object,
|
||||||
|
GAsyncResult *result,
|
||||||
|
gpointer user_data)
|
||||||
|
{
|
||||||
|
MksMouse *mouse = (MksMouse *)object;
|
||||||
|
g_autoptr(MksDisplay) self = user_data;
|
||||||
|
g_autoptr(GError) error = NULL;
|
||||||
|
|
||||||
|
g_assert (MKS_IS_MOUSE (mouse));
|
||||||
|
g_assert (G_IS_ASYNC_RESULT (result));
|
||||||
|
g_assert (MKS_IS_DISPLAY (self));
|
||||||
|
|
||||||
|
if (!mks_mouse_press_finish (mouse, result, &error))
|
||||||
|
g_warning ("Mouse press failed: %s", error->message);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
mks_display_click_pressed_cb (MksDisplay *self,
|
||||||
|
int n_press,
|
||||||
|
double x,
|
||||||
|
double y,
|
||||||
|
GtkGestureClick *click)
|
||||||
|
{
|
||||||
|
MksDisplayPrivate *priv = mks_display_get_instance_private (self);
|
||||||
|
MksMouse *mouse;
|
||||||
|
int button;
|
||||||
|
|
||||||
|
g_assert (MKS_IS_DISPLAY (self));
|
||||||
|
g_assert (GTK_IS_GESTURE_CLICK (click));
|
||||||
|
|
||||||
|
if (priv->screen == NULL)
|
||||||
|
return;
|
||||||
|
|
||||||
|
mouse = mks_screen_get_mouse (priv->screen);
|
||||||
|
|
||||||
|
button = gtk_gesture_single_get_current_button (GTK_GESTURE_SINGLE (click));
|
||||||
|
mks_display_translate_button (self, &button);
|
||||||
|
mks_mouse_press (mouse,
|
||||||
|
button,
|
||||||
|
NULL,
|
||||||
|
mks_display_mouse_press_cb,
|
||||||
|
g_object_ref (self));
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
mks_display_mouse_release_cb (GObject *object,
|
||||||
|
GAsyncResult *result,
|
||||||
|
gpointer user_data)
|
||||||
|
{
|
||||||
|
MksMouse *mouse = (MksMouse *)object;
|
||||||
|
g_autoptr(MksDisplay) self = user_data;
|
||||||
|
g_autoptr(GError) error = NULL;
|
||||||
|
|
||||||
|
g_assert (MKS_IS_MOUSE (mouse));
|
||||||
|
g_assert (G_IS_ASYNC_RESULT (result));
|
||||||
|
g_assert (MKS_IS_DISPLAY (self));
|
||||||
|
|
||||||
|
if (!mks_mouse_release_finish (mouse, result, &error))
|
||||||
|
g_warning ("Mouse release failed: %s", error->message);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
mks_display_click_released_cb (MksDisplay *self,
|
||||||
|
int n_press,
|
||||||
|
double x,
|
||||||
|
double y,
|
||||||
|
GtkGestureClick *click)
|
||||||
|
{
|
||||||
|
MksDisplayPrivate *priv = mks_display_get_instance_private (self);
|
||||||
|
MksMouse *mouse;
|
||||||
|
int button;
|
||||||
|
|
||||||
|
g_assert (MKS_IS_DISPLAY (self));
|
||||||
|
g_assert (GTK_IS_GESTURE_CLICK (click));
|
||||||
|
|
||||||
|
if (priv->screen == NULL)
|
||||||
|
return;
|
||||||
|
|
||||||
|
mouse = mks_screen_get_mouse (priv->screen);
|
||||||
|
|
||||||
|
button = gtk_gesture_single_get_current_button (GTK_GESTURE_SINGLE (click));
|
||||||
|
mks_display_translate_button (self, &button);
|
||||||
|
mks_mouse_release (mouse,
|
||||||
|
button,
|
||||||
|
NULL,
|
||||||
|
mks_display_mouse_release_cb,
|
||||||
|
g_object_ref (self));
|
||||||
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
mks_display_attach_cb (GObject *object,
|
mks_display_attach_cb (GObject *object,
|
||||||
GAsyncResult *result,
|
GAsyncResult *result,
|
||||||
@ -361,9 +547,12 @@ mks_display_class_init (MksDisplayClass *klass)
|
|||||||
gtk_widget_class_set_css_name (widget_class, "MksDisplay");
|
gtk_widget_class_set_css_name (widget_class, "MksDisplay");
|
||||||
gtk_widget_class_set_layout_manager_type (widget_class, GTK_TYPE_BIN_LAYOUT);
|
gtk_widget_class_set_layout_manager_type (widget_class, GTK_TYPE_BIN_LAYOUT);
|
||||||
gtk_widget_class_set_template_from_resource (widget_class, "/org/gnome/libmks/mks-display.ui");
|
gtk_widget_class_set_template_from_resource (widget_class, "/org/gnome/libmks/mks-display.ui");
|
||||||
|
gtk_widget_class_bind_template_child_private (widget_class, MksDisplay, click);
|
||||||
gtk_widget_class_bind_template_child_private (widget_class, MksDisplay, key);
|
gtk_widget_class_bind_template_child_private (widget_class, MksDisplay, key);
|
||||||
gtk_widget_class_bind_template_child_private (widget_class, MksDisplay, motion);
|
gtk_widget_class_bind_template_child_private (widget_class, MksDisplay, motion);
|
||||||
gtk_widget_class_bind_template_child_private (widget_class, MksDisplay, picture);
|
gtk_widget_class_bind_template_child_private (widget_class, MksDisplay, picture);
|
||||||
|
gtk_widget_class_bind_template_callback (widget_class, mks_display_click_pressed_cb);
|
||||||
|
gtk_widget_class_bind_template_callback (widget_class, mks_display_click_released_cb);
|
||||||
gtk_widget_class_bind_template_callback (widget_class, mks_display_motion_enter_cb);
|
gtk_widget_class_bind_template_callback (widget_class, mks_display_motion_enter_cb);
|
||||||
gtk_widget_class_bind_template_callback (widget_class, mks_display_motion_motion_cb);
|
gtk_widget_class_bind_template_callback (widget_class, mks_display_motion_motion_cb);
|
||||||
gtk_widget_class_bind_template_callback (widget_class, mks_display_motion_leave_cb);
|
gtk_widget_class_bind_template_callback (widget_class, mks_display_motion_leave_cb);
|
||||||
|
@ -13,6 +13,14 @@
|
|||||||
<signal name="motion" handler="mks_display_motion_motion_cb" swapped="true"/>
|
<signal name="motion" handler="mks_display_motion_motion_cb" swapped="true"/>
|
||||||
</object>
|
</object>
|
||||||
</child>
|
</child>
|
||||||
|
<child>
|
||||||
|
<object class="GtkGestureClick" id="click">
|
||||||
|
<property name="button">0</property>
|
||||||
|
<property name="exclusive">true</property>
|
||||||
|
<signal name="pressed" handler="mks_display_click_pressed_cb" swapped="true"/>
|
||||||
|
<signal name="released" handler="mks_display_click_released_cb" swapped="true"/>
|
||||||
|
</object>
|
||||||
|
</child>
|
||||||
<child>
|
<child>
|
||||||
<object class="GtkEventControllerKey" id="key">
|
<object class="GtkEventControllerKey" id="key">
|
||||||
<signal name="key-pressed" handler="mks_display_key_key_pressed_cb" swapped="true"/>
|
<signal name="key-pressed" handler="mks_display_key_key_pressed_cb" swapped="true"/>
|
||||||
|
@ -28,6 +28,8 @@ struct _MksMouse
|
|||||||
{
|
{
|
||||||
MksDevice parent_instance;
|
MksDevice parent_instance;
|
||||||
MksQemuMouse *mouse;
|
MksQemuMouse *mouse;
|
||||||
|
double last_known_x;
|
||||||
|
double last_known_y;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct _MksMouseClass
|
struct _MksMouseClass
|
||||||
@ -367,6 +369,9 @@ mks_mouse_move_to (MksMouse *self,
|
|||||||
task = g_task_new (self, cancellable, callback, user_data);
|
task = g_task_new (self, cancellable, callback, user_data);
|
||||||
g_task_set_source_tag (task, mks_mouse_move_to);
|
g_task_set_source_tag (task, mks_mouse_move_to);
|
||||||
|
|
||||||
|
self->last_known_x = x;
|
||||||
|
self->last_known_y = y;
|
||||||
|
|
||||||
if (!check_mouse (self, &error))
|
if (!check_mouse (self, &error))
|
||||||
g_task_return_error (task, g_steal_pointer (&error));
|
g_task_return_error (task, g_steal_pointer (&error));
|
||||||
else
|
else
|
||||||
@ -411,6 +416,9 @@ mks_mouse_move_to_sync (MksMouse *self,
|
|||||||
g_return_val_if_fail (MKS_IS_MOUSE (self), FALSE);
|
g_return_val_if_fail (MKS_IS_MOUSE (self), FALSE);
|
||||||
g_return_val_if_fail (!cancellable || G_IS_CANCELLABLE (cancellable), FALSE);
|
g_return_val_if_fail (!cancellable || G_IS_CANCELLABLE (cancellable), FALSE);
|
||||||
|
|
||||||
|
self->last_known_x = x;
|
||||||
|
self->last_known_y = y;
|
||||||
|
|
||||||
if (!check_mouse (self, error))
|
if (!check_mouse (self, error))
|
||||||
return FALSE;
|
return FALSE;
|
||||||
|
|
||||||
@ -464,6 +472,9 @@ mks_mouse_move_by (MksMouse *self,
|
|||||||
task = g_task_new (self, cancellable, callback, user_data);
|
task = g_task_new (self, cancellable, callback, user_data);
|
||||||
g_task_set_source_tag (task, mks_mouse_move_by);
|
g_task_set_source_tag (task, mks_mouse_move_by);
|
||||||
|
|
||||||
|
self->last_known_x += delta_x;
|
||||||
|
self->last_known_y += delta_y;
|
||||||
|
|
||||||
if (!check_mouse (self, &error))
|
if (!check_mouse (self, &error))
|
||||||
g_task_return_error (task, g_steal_pointer (&error));
|
g_task_return_error (task, g_steal_pointer (&error));
|
||||||
else
|
else
|
||||||
@ -508,6 +519,9 @@ mks_mouse_move_by_sync (MksMouse *self,
|
|||||||
g_return_val_if_fail (MKS_IS_MOUSE (self), FALSE);
|
g_return_val_if_fail (MKS_IS_MOUSE (self), FALSE);
|
||||||
g_return_val_if_fail (!cancellable || G_IS_CANCELLABLE (cancellable), FALSE);
|
g_return_val_if_fail (!cancellable || G_IS_CANCELLABLE (cancellable), FALSE);
|
||||||
|
|
||||||
|
self->last_known_x += delta_x;
|
||||||
|
self->last_known_y += delta_y;
|
||||||
|
|
||||||
if (!check_mouse (self, error))
|
if (!check_mouse (self, error))
|
||||||
return FALSE;
|
return FALSE;
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user