Compare commits

...

5 Commits

Author SHA1 Message Date
Carlos Garnacho
27fa62f110 wayland: Reword comment
This is no longer directly related to DBus messages, but our own event
queue. Change the wording and use CLUTTER_PRIORITY_EVENTS to make it
bolder, even though it's the same than G_PRIORITY_DEFAULT.

https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1286
2020-08-17 12:39:15 +02:00
Carlos Garnacho
35680ee7c6 wayland: Flush text_input.done event after IM key event
We set an idle to coalesce multiple IM events together, as the protocol
requires us to send them in one frame, and unfortunately there is no
idea about whether more IM events are upcoming.

One good hint though are key events generated from the IM, we want to
apply all IM changes before the key event is processed, so make it sure
that the .done event is flushed before the key event is handled.

https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1286
2020-08-17 12:36:10 +02:00
Carlos Garnacho
98c1a469ad clutter: Push commit/delete_sourrounding as IM events
These are not given directly to the input focus anymore, instead
queued up as events. This way, all actions triggered by the input
method (commit and preedit buffer ones, but also synthesized key
events) queue up the same way, and are thus processed in the exact
same order than they are given to us.

https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1286
2020-08-17 12:31:08 +02:00
Carlos Garnacho
4a43e295d2 clutter: Prepare input focus for IM event delivery
The clutter_input_focus_filter_key_event() function has been made
a more generic filter_event(). Besides its old role about letting
key events go through the IM, it will also process the IM events
that are possibly injected as a result.

Users have been updated to these changes.

https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1286
2020-08-17 12:30:38 +02:00
Carlos Garnacho
612a17443a clutter: Add IM events
These will be used to make IM commands into something that is processed
in a fixed order relative to key events.

https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1286
2020-08-17 12:30:28 +02:00
12 changed files with 188 additions and 37 deletions

View File

@ -1097,6 +1097,7 @@ static GQuark quark_touch = 0;
static GQuark quark_touchpad = 0;
static GQuark quark_proximity = 0;
static GQuark quark_pad = 0;
static GQuark quark_im = 0;
G_DEFINE_TYPE_WITH_CODE (ClutterActor,
clutter_actor,
@ -6006,6 +6007,7 @@ clutter_actor_class_init (ClutterActorClass *klass)
quark_touchpad = g_quark_from_static_string ("touchpad");
quark_proximity = g_quark_from_static_string ("proximity");
quark_pad = g_quark_from_static_string ("pad");
quark_im = g_quark_from_static_string ("im");
object_class->constructor = clutter_actor_constructor;
object_class->set_property = clutter_actor_set_property;
@ -12715,6 +12717,12 @@ clutter_actor_event (ClutterActor *actor,
signal_num = -1;
detail = quark_stage;
break;
case CLUTTER_IM_COMMIT:
case CLUTTER_IM_DELETE:
case CLUTTER_IM_PREEDIT:
signal_num = -1;
detail = quark_im;
break;
case CLUTTER_EVENT_LAST: /* Just keep compiler warnings quiet */
break;
}

View File

@ -906,6 +906,9 @@ typedef enum /*< prefix=CLUTTER >*/
CLUTTER_PAD_BUTTON_RELEASE,
CLUTTER_PAD_STRIP,
CLUTTER_PAD_RING,
CLUTTER_IM_COMMIT,
CLUTTER_IM_DELETE,
CLUTTER_IM_PREEDIT,
CLUTTER_EVENT_LAST /* helper */
} ClutterEventType;

View File

@ -414,6 +414,9 @@ clutter_event_get_position (const ClutterEvent *event,
case CLUTTER_PAD_BUTTON_RELEASE:
case CLUTTER_PAD_STRIP:
case CLUTTER_PAD_RING:
case CLUTTER_IM_COMMIT:
case CLUTTER_IM_DELETE:
case CLUTTER_IM_PREEDIT:
graphene_point_init (position, 0.f, 0.f);
break;
@ -487,6 +490,9 @@ clutter_event_set_coords (ClutterEvent *event,
case CLUTTER_PAD_BUTTON_RELEASE:
case CLUTTER_PAD_STRIP:
case CLUTTER_PAD_RING:
case CLUTTER_IM_COMMIT:
case CLUTTER_IM_DELETE:
case CLUTTER_IM_PREEDIT:
break;
case CLUTTER_ENTER:
@ -1104,6 +1110,9 @@ clutter_event_set_device (ClutterEvent *event,
case CLUTTER_DESTROY_NOTIFY:
case CLUTTER_CLIENT_MESSAGE:
case CLUTTER_EVENT_LAST:
case CLUTTER_IM_COMMIT:
case CLUTTER_IM_DELETE:
case CLUTTER_IM_PREEDIT:
break;
case CLUTTER_ENTER:
@ -1199,6 +1208,9 @@ clutter_event_get_device (const ClutterEvent *event)
case CLUTTER_STAGE_STATE:
case CLUTTER_DESTROY_NOTIFY:
case CLUTTER_CLIENT_MESSAGE:
case CLUTTER_IM_COMMIT:
case CLUTTER_IM_DELETE:
case CLUTTER_IM_PREEDIT:
case CLUTTER_EVENT_LAST:
break;
@ -1407,6 +1419,11 @@ clutter_event_copy (const ClutterEvent *event)
sizeof (gdouble) * n_axes);
break;
case CLUTTER_IM_COMMIT:
case CLUTTER_IM_PREEDIT:
new_event->im.text = g_strdup (event->im.text);
break;
default:
break;
}
@ -1462,6 +1479,11 @@ clutter_event_free (ClutterEvent *event)
g_free (event->touch.axes);
break;
case CLUTTER_IM_COMMIT:
case CLUTTER_IM_PREEDIT:
g_free (event->im.text);
break;
default:
break;
}
@ -1756,6 +1778,9 @@ clutter_event_get_axes (const ClutterEvent *event,
case CLUTTER_PAD_BUTTON_RELEASE:
case CLUTTER_PAD_STRIP:
case CLUTTER_PAD_RING:
case CLUTTER_IM_COMMIT:
case CLUTTER_IM_DELETE:
case CLUTTER_IM_PREEDIT:
break;
}

View File

@ -121,6 +121,7 @@ typedef struct _ClutterProximityEvent ClutterProximityEvent;
typedef struct _ClutterPadButtonEvent ClutterPadButtonEvent;
typedef struct _ClutterPadStripEvent ClutterPadStripEvent;
typedef struct _ClutterPadRingEvent ClutterPadRingEvent;
typedef struct _ClutterIMEvent ClutterIMEvent;
/**
* ClutterAnyEvent:
@ -544,6 +545,19 @@ struct _ClutterPadRingEvent
guint32 mode;
};
struct _ClutterIMEvent
{
ClutterEventType type;
uint32_t time;
ClutterEventFlags flags;
ClutterStage *stage;
ClutterActor *source;
char *text;
int32_t offset;
uint32_t len;
};
/**
* ClutterEvent:
*
@ -570,6 +584,7 @@ union _ClutterEvent
ClutterPadButtonEvent pad_button;
ClutterPadStripEvent pad_strip;
ClutterPadRingEvent pad_ring;
ClutterIMEvent im;
};
/**

View File

@ -147,8 +147,8 @@ clutter_input_focus_set_content_purpose (ClutterInputFocus *focus,
}
gboolean
clutter_input_focus_filter_key_event (ClutterInputFocus *focus,
const ClutterKeyEvent *key)
clutter_input_focus_filter_event (ClutterInputFocus *focus,
const ClutterEvent *event)
{
ClutterInputFocusPrivate *priv;
@ -157,7 +157,30 @@ clutter_input_focus_filter_key_event (ClutterInputFocus *focus,
priv = clutter_input_focus_get_instance_private (focus);
return clutter_input_method_filter_key_event (priv->im, key);
if (event->type == CLUTTER_KEY_PRESS ||
event->type == CLUTTER_KEY_RELEASE)
{
return clutter_input_method_filter_key_event (priv->im, &event->key);
}
else if (event->type == CLUTTER_IM_COMMIT)
{
clutter_input_focus_commit (focus, event->im.text);
return TRUE;
}
else if (event->type == CLUTTER_IM_DELETE)
{
clutter_input_focus_delete_surrounding (focus, event->im.offset,
event->im.len);
return TRUE;
}
else if (event->type == CLUTTER_IM_PREEDIT)
{
clutter_input_focus_set_preedit_text (focus, event->im.text,
event->im.offset);
return TRUE;
}
return FALSE;
}
void

View File

@ -72,8 +72,8 @@ CLUTTER_EXPORT
void clutter_input_focus_set_content_purpose (ClutterInputFocus *focus,
ClutterInputContentPurpose purpose);
CLUTTER_EXPORT
gboolean clutter_input_focus_filter_key_event (ClutterInputFocus *focus,
const ClutterKeyEvent *key);
gboolean clutter_input_focus_filter_event (ClutterInputFocus *focus,
const ClutterEvent *event);
CLUTTER_EXPORT
void clutter_input_focus_set_can_show_preedit (ClutterInputFocus *focus,
gboolean can_show_preedit);

View File

@ -277,17 +277,45 @@ clutter_input_method_get_focus (ClutterInputMethod *im)
return priv->focus;
}
static void
clutter_input_method_put_im_event (ClutterInputMethod *im,
ClutterEventType event_type,
const char *text,
int32_t offset,
uint32_t len)
{
ClutterInputDevice *keyboard;
ClutterSeat *seat;
ClutterStage *stage;
ClutterEvent *event;
seat = clutter_backend_get_default_seat (clutter_get_default_backend ());
keyboard = clutter_seat_get_keyboard (seat);
stage = _clutter_input_device_get_stage (keyboard);
if (stage == NULL)
return;
event = clutter_event_new (event_type);
event->im.text = g_strdup (text);
event->im.offset = offset;
event->im.len = len;
clutter_event_set_device (event, keyboard);
clutter_event_set_source_device (event, keyboard);
clutter_event_set_flags (event, CLUTTER_EVENT_FLAG_INPUT_METHOD);
clutter_event_set_stage (event, stage);
clutter_event_put (event);
clutter_event_free (event);
}
void
clutter_input_method_commit (ClutterInputMethod *im,
const gchar *text)
{
ClutterInputMethodPrivate *priv;
g_return_if_fail (CLUTTER_IS_INPUT_METHOD (im));
priv = clutter_input_method_get_instance_private (im);
if (priv->focus)
clutter_input_focus_commit (priv->focus, text);
clutter_input_method_put_im_event (im, CLUTTER_IM_COMMIT, text, 0, 0);
}
void
@ -295,13 +323,9 @@ clutter_input_method_delete_surrounding (ClutterInputMethod *im,
int offset,
guint len)
{
ClutterInputMethodPrivate *priv;
g_return_if_fail (CLUTTER_IS_INPUT_METHOD (im));
priv = clutter_input_method_get_instance_private (im);
if (priv->focus)
clutter_input_focus_delete_surrounding (priv->focus, offset, len);
clutter_input_method_put_im_event (im, CLUTTER_IM_DELETE, NULL, offset, len);
}
void
@ -329,13 +353,9 @@ clutter_input_method_set_preedit_text (ClutterInputMethod *im,
const gchar *preedit,
guint cursor)
{
ClutterInputMethodPrivate *priv;
g_return_if_fail (CLUTTER_IS_INPUT_METHOD (im));
priv = clutter_input_method_get_instance_private (im);
if (priv->focus)
clutter_input_focus_set_preedit_text (priv->focus, preedit, cursor);
clutter_input_method_put_im_event (im, CLUTTER_IM_PREEDIT, preedit, cursor, 0);
}
void

View File

@ -1590,6 +1590,9 @@ _clutter_process_event_details (ClutterActor *stage,
case CLUTTER_PAD_BUTTON_RELEASE:
case CLUTTER_PAD_STRIP:
case CLUTTER_PAD_RING:
case CLUTTER_IM_COMMIT:
case CLUTTER_IM_DELETE:
case CLUTTER_IM_PREEDIT:
{
ClutterActor *actor = NULL;

View File

@ -2400,7 +2400,8 @@ clutter_text_key_press (ClutterActor *actor,
if (!(event->flags & CLUTTER_EVENT_FLAG_INPUT_METHOD) &&
clutter_input_focus_is_focused (priv->input_focus) &&
clutter_input_focus_filter_key_event (priv->input_focus, event))
clutter_input_focus_filter_event (priv->input_focus,
(ClutterEvent *) event))
return CLUTTER_EVENT_STOP;
/* we allow passing synthetic events that only contain
@ -2469,7 +2470,8 @@ clutter_text_key_release (ClutterActor *actor,
ClutterTextPrivate *priv = self->priv;
if (clutter_input_focus_is_focused (priv->input_focus) &&
clutter_input_focus_filter_key_event (priv->input_focus, event))
clutter_input_focus_filter_event (priv->input_focus,
(ClutterEvent *) event))
return CLUTTER_EVENT_STOP;
return CLUTTER_EVENT_PROPAGATE;
@ -3068,6 +3070,24 @@ clutter_text_resource_scale_changed (ClutterActor *actor)
clutter_actor_queue_immediate_relayout (actor);
}
static gboolean
clutter_text_event (ClutterActor *self,
ClutterEvent *event)
{
ClutterText *text = CLUTTER_TEXT (self);
ClutterTextPrivate *priv = text->priv;
if (clutter_input_focus_is_focused (priv->input_focus) &&
(event->type == CLUTTER_IM_COMMIT ||
event->type == CLUTTER_IM_DELETE ||
event->type == CLUTTER_IM_PREEDIT))
{
return clutter_input_focus_filter_event (priv->input_focus, event);
}
return CLUTTER_EVENT_PROPAGATE;
}
static void
clutter_text_im_focus (ClutterText *text)
{
@ -3818,6 +3838,7 @@ clutter_text_class_init (ClutterTextClass *klass)
actor_class->has_overlaps = clutter_text_has_overlaps;
actor_class->calculate_resource_scale = clutter_text_calculate_resource_scale;
actor_class->resource_scale_changed = clutter_text_resource_scale_changed;
actor_class->event = clutter_text_event;
/**
* ClutterText:buffer:

View File

@ -406,6 +406,16 @@ meta_wayland_seat_handle_event (MetaWaylandSeat *seat,
if (meta_wayland_seat_has_touch (seat))
return meta_wayland_touch_handle_event (seat->touch, event);
break;
case CLUTTER_IM_COMMIT:
case CLUTTER_IM_DELETE:
case CLUTTER_IM_PREEDIT:
if (meta_wayland_text_input_handle_event (seat->text_input, event))
return TRUE;
if (meta_wayland_gtk_text_input_handle_event (seat->gtk_text_input,
event))
return TRUE;
break;
default:
break;

View File

@ -629,6 +629,5 @@ meta_wayland_gtk_text_input_handle_event (MetaWaylandGtkTextInput *text_input,
!clutter_input_focus_is_focused (text_input->input_focus))
return FALSE;
return clutter_input_focus_filter_key_event (text_input->input_focus,
(const ClutterKeyEvent *) event);
return clutter_input_focus_filter_event (text_input->input_focus, event);
}

View File

@ -118,10 +118,9 @@ increment_serial (MetaWaylandTextInput *text_input,
GUINT_TO_POINTER (serial + 1));
}
static gboolean
done_idle_cb (gpointer user_data)
static void
clutter_input_focus_send_done (ClutterInputFocus *focus)
{
ClutterInputFocus *focus = user_data;
MetaWaylandTextInput *text_input;
struct wl_resource *resource;
@ -132,6 +131,16 @@ done_idle_cb (gpointer user_data)
zwp_text_input_v3_send_done (resource,
lookup_serial (text_input, resource));
}
}
static gboolean
done_idle_cb (gpointer user_data)
{
ClutterInputFocus *focus = user_data;
MetaWaylandTextInput *text_input;
text_input = META_WAYLAND_TEXT_INPUT_FOCUS (focus)->text_input;
clutter_input_focus_send_done (focus);
text_input->done_idle_id = 0;
return G_SOURCE_REMOVE;
@ -147,23 +156,34 @@ meta_wayland_text_input_focus_defer_done (ClutterInputFocus *focus)
if (text_input->done_idle_id != 0)
return;
/* This operates on 3 principles:
* - GDBus uses G_PRIORITY_DEFAULT to put messages in the thread default main
* context.
* - All relevant ClutterInputFocus methods are ultimately backed by
* DBus methods inside IBus.
/* This operates on 2 principles:
* - IM operations come as individual ClutterEvents
* - We want to run .done after them all. The slightly lower
* G_PRIORITY_DEFAULT + 1 priority should ensure we at least group
* all messages seen so far.
* CLUTTER_PRIORITY_EVENTS + 1 priority should ensure we at least group
* all events seen so far.
*
* FIXME: .done may be delayed indefinitely if there's a high enough
* priority idle source in the main loop. It's unlikely that
* recurring idles run at this high priority though.
*/
text_input->done_idle_id = g_idle_add_full (G_PRIORITY_DEFAULT + 1,
text_input->done_idle_id = g_idle_add_full (CLUTTER_PRIORITY_EVENTS + 1,
done_idle_cb, focus, NULL);
}
static void
meta_wayland_text_input_focus_flush_done (ClutterInputFocus *focus)
{
MetaWaylandTextInput *text_input;
text_input = META_WAYLAND_TEXT_INPUT_FOCUS (focus)->text_input;
if (text_input->done_idle_id == 0)
return;
g_clear_handle_id (&text_input->done_idle_id, g_source_remove);
clutter_input_focus_send_done (focus);
}
static void
meta_wayland_text_input_focus_delete_surrounding (ClutterInputFocus *focus,
int offset,
@ -737,6 +757,10 @@ meta_wayland_text_input_handle_event (MetaWaylandTextInput *text_input,
!clutter_input_focus_is_focused (text_input->input_focus))
return FALSE;
return clutter_input_focus_filter_key_event (text_input->input_focus,
(const ClutterKeyEvent *) event);
if ((event->type == CLUTTER_KEY_PRESS ||
event->type == CLUTTER_KEY_RELEASE) &&
clutter_event_get_flags (event) & CLUTTER_EVENT_FLAG_INPUT_METHOD)
meta_wayland_text_input_focus_flush_done (text_input->input_focus);
return clutter_input_focus_filter_event (text_input->input_focus, event);
}