
Currently, we let the same function handle key event filtering as they are passed to the IM, and the IM events resulting in actions like text commit or preedit changes. Split these two aspects into filter/process functions, and port ClutterText to it. MetaWaylandTextInput still handles everything in a single place, but that will be split in later commits. Part-of: <https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/3044>
317 lines
9.1 KiB
C
317 lines
9.1 KiB
C
/*
|
|
* Copyright (C) 2017,2018 Red Hat
|
|
*
|
|
* This program is free software; you can redistribute it and/or
|
|
* modify it under the terms of the GNU General Public License as
|
|
* published by the Free Software Foundation; either version 2 of the
|
|
* License, or (at your option) any later version.
|
|
*
|
|
* This program is distributed in the hope that it will be useful, but
|
|
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
* General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU General Public License
|
|
* along with this program; if not, write to the Free Software
|
|
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
|
|
* 02111-1307, USA.
|
|
*
|
|
* Author: Carlos Garnacho <carlosg@gnome.org>
|
|
*/
|
|
|
|
#include "clutter-build-config.h"
|
|
|
|
#include "clutter/clutter-input-focus.h"
|
|
#include "clutter/clutter-input-focus-private.h"
|
|
#include "clutter/clutter-input-method-private.h"
|
|
|
|
typedef struct _ClutterInputFocusPrivate ClutterInputFocusPrivate;
|
|
|
|
struct _ClutterInputFocusPrivate
|
|
{
|
|
ClutterInputMethod *im;
|
|
char *preedit;
|
|
ClutterPreeditResetMode mode;
|
|
};
|
|
|
|
G_DEFINE_ABSTRACT_TYPE_WITH_PRIVATE (ClutterInputFocus, clutter_input_focus, G_TYPE_OBJECT)
|
|
|
|
static void
|
|
clutter_input_focus_real_focus_in (ClutterInputFocus *focus,
|
|
ClutterInputMethod *im)
|
|
{
|
|
ClutterInputFocusPrivate *priv;
|
|
|
|
priv = clutter_input_focus_get_instance_private (focus);
|
|
priv->im = im;
|
|
}
|
|
|
|
static void
|
|
clutter_input_focus_real_focus_out (ClutterInputFocus *focus)
|
|
{
|
|
ClutterInputFocusPrivate *priv;
|
|
|
|
priv = clutter_input_focus_get_instance_private (focus);
|
|
priv->im = NULL;
|
|
}
|
|
|
|
static void
|
|
clutter_input_focus_finalize (GObject *object)
|
|
{
|
|
ClutterInputFocus *focus = CLUTTER_INPUT_FOCUS (object);
|
|
ClutterInputFocusPrivate *priv =
|
|
clutter_input_focus_get_instance_private (focus);
|
|
|
|
g_clear_pointer (&priv->preedit, g_free);
|
|
|
|
G_OBJECT_CLASS (clutter_input_focus_parent_class)->finalize (object);
|
|
}
|
|
|
|
static void
|
|
clutter_input_focus_class_init (ClutterInputFocusClass *klass)
|
|
{
|
|
GObjectClass *object_class = G_OBJECT_CLASS (klass);
|
|
|
|
object_class->finalize = clutter_input_focus_finalize;
|
|
|
|
klass->focus_in = clutter_input_focus_real_focus_in;
|
|
klass->focus_out = clutter_input_focus_real_focus_out;
|
|
}
|
|
|
|
static void
|
|
clutter_input_focus_init (ClutterInputFocus *focus)
|
|
{
|
|
}
|
|
|
|
gboolean
|
|
clutter_input_focus_is_focused (ClutterInputFocus *focus)
|
|
{
|
|
ClutterInputFocusPrivate *priv;
|
|
|
|
priv = clutter_input_focus_get_instance_private (focus);
|
|
|
|
return !!priv->im;
|
|
}
|
|
|
|
void
|
|
clutter_input_focus_reset (ClutterInputFocus *focus)
|
|
{
|
|
ClutterInputFocusPrivate *priv;
|
|
|
|
g_return_if_fail (CLUTTER_IS_INPUT_FOCUS (focus));
|
|
g_return_if_fail (clutter_input_focus_is_focused (focus));
|
|
|
|
priv = clutter_input_focus_get_instance_private (focus);
|
|
|
|
if (priv->preedit)
|
|
{
|
|
if (priv->mode == CLUTTER_PREEDIT_RESET_COMMIT)
|
|
clutter_input_focus_commit (focus, priv->preedit);
|
|
|
|
clutter_input_focus_set_preedit_text (focus, NULL, 0, 0);
|
|
g_clear_pointer (&priv->preedit, g_free);
|
|
}
|
|
|
|
priv->mode = CLUTTER_PREEDIT_RESET_CLEAR;
|
|
clutter_input_method_reset (priv->im);
|
|
}
|
|
|
|
void
|
|
clutter_input_focus_set_cursor_location (ClutterInputFocus *focus,
|
|
const graphene_rect_t *rect)
|
|
{
|
|
ClutterInputFocusPrivate *priv;
|
|
|
|
g_return_if_fail (CLUTTER_IS_INPUT_FOCUS (focus));
|
|
g_return_if_fail (clutter_input_focus_is_focused (focus));
|
|
|
|
priv = clutter_input_focus_get_instance_private (focus);
|
|
|
|
clutter_input_method_set_cursor_location (priv->im, rect);
|
|
}
|
|
|
|
void
|
|
clutter_input_focus_set_surrounding (ClutterInputFocus *focus,
|
|
const gchar *text,
|
|
guint cursor,
|
|
guint anchor)
|
|
{
|
|
ClutterInputFocusPrivate *priv;
|
|
|
|
g_return_if_fail (CLUTTER_IS_INPUT_FOCUS (focus));
|
|
g_return_if_fail (clutter_input_focus_is_focused (focus));
|
|
|
|
priv = clutter_input_focus_get_instance_private (focus);
|
|
|
|
clutter_input_method_set_surrounding (priv->im, text, cursor, anchor);
|
|
}
|
|
|
|
void
|
|
clutter_input_focus_set_content_hints (ClutterInputFocus *focus,
|
|
ClutterInputContentHintFlags hints)
|
|
{
|
|
ClutterInputFocusPrivate *priv;
|
|
|
|
g_return_if_fail (CLUTTER_IS_INPUT_FOCUS (focus));
|
|
g_return_if_fail (clutter_input_focus_is_focused (focus));
|
|
|
|
priv = clutter_input_focus_get_instance_private (focus);
|
|
|
|
clutter_input_method_set_content_hints (priv->im, hints);
|
|
}
|
|
|
|
void
|
|
clutter_input_focus_set_content_purpose (ClutterInputFocus *focus,
|
|
ClutterInputContentPurpose purpose)
|
|
{
|
|
ClutterInputFocusPrivate *priv;
|
|
|
|
g_return_if_fail (CLUTTER_IS_INPUT_FOCUS (focus));
|
|
g_return_if_fail (clutter_input_focus_is_focused (focus));
|
|
|
|
priv = clutter_input_focus_get_instance_private (focus);
|
|
|
|
clutter_input_method_set_content_purpose (priv->im, purpose);
|
|
}
|
|
|
|
gboolean
|
|
clutter_input_focus_filter_event (ClutterInputFocus *focus,
|
|
const ClutterEvent *event)
|
|
{
|
|
ClutterInputFocusPrivate *priv;
|
|
|
|
g_return_val_if_fail (CLUTTER_IS_INPUT_FOCUS (focus), FALSE);
|
|
g_return_val_if_fail (clutter_input_focus_is_focused (focus), FALSE);
|
|
|
|
priv = clutter_input_focus_get_instance_private (focus);
|
|
|
|
if (event->type == CLUTTER_KEY_PRESS ||
|
|
event->type == CLUTTER_KEY_RELEASE)
|
|
{
|
|
return clutter_input_method_filter_key_event (priv->im, &event->key);
|
|
}
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
gboolean
|
|
clutter_input_focus_process_event (ClutterInputFocus *focus,
|
|
const ClutterEvent *event)
|
|
{
|
|
ClutterInputFocusPrivate *priv;
|
|
|
|
g_return_val_if_fail (CLUTTER_IS_INPUT_FOCUS (focus), FALSE);
|
|
g_return_val_if_fail (clutter_input_focus_is_focused (focus), FALSE);
|
|
|
|
priv = clutter_input_focus_get_instance_private (focus);
|
|
|
|
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)
|
|
{
|
|
g_clear_pointer (&priv->preedit, g_free);
|
|
priv->preedit = g_strdup (event->im.text);
|
|
priv->mode = event->im.mode;
|
|
clutter_input_focus_set_preedit_text (focus, event->im.text,
|
|
event->im.offset,
|
|
event->im.anchor);
|
|
return TRUE;
|
|
}
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
void
|
|
clutter_input_focus_set_can_show_preedit (ClutterInputFocus *focus,
|
|
gboolean can_show_preedit)
|
|
{
|
|
ClutterInputFocusPrivate *priv;
|
|
|
|
g_return_if_fail (CLUTTER_IS_INPUT_FOCUS (focus));
|
|
g_return_if_fail (clutter_input_focus_is_focused (focus));
|
|
|
|
priv = clutter_input_focus_get_instance_private (focus);
|
|
|
|
clutter_input_method_set_can_show_preedit (priv->im, can_show_preedit);
|
|
}
|
|
|
|
void
|
|
clutter_input_focus_set_input_panel_state (ClutterInputFocus *focus,
|
|
ClutterInputPanelState state)
|
|
{
|
|
ClutterInputFocusPrivate *priv;
|
|
|
|
g_return_if_fail (CLUTTER_IS_INPUT_FOCUS (focus));
|
|
g_return_if_fail (clutter_input_focus_is_focused (focus));
|
|
|
|
priv = clutter_input_focus_get_instance_private (focus);
|
|
|
|
clutter_input_method_set_input_panel_state (priv->im, state);
|
|
}
|
|
|
|
void
|
|
clutter_input_focus_focus_in (ClutterInputFocus *focus,
|
|
ClutterInputMethod *im)
|
|
{
|
|
g_return_if_fail (CLUTTER_IS_INPUT_FOCUS (focus));
|
|
g_return_if_fail (CLUTTER_IS_INPUT_METHOD (im));
|
|
|
|
CLUTTER_INPUT_FOCUS_GET_CLASS (focus)->focus_in (focus, im);
|
|
}
|
|
|
|
void
|
|
clutter_input_focus_focus_out (ClutterInputFocus *focus)
|
|
{
|
|
g_return_if_fail (CLUTTER_IS_INPUT_FOCUS (focus));
|
|
|
|
CLUTTER_INPUT_FOCUS_GET_CLASS (focus)->focus_out (focus);
|
|
}
|
|
|
|
void
|
|
clutter_input_focus_commit (ClutterInputFocus *focus,
|
|
const gchar *text)
|
|
{
|
|
g_return_if_fail (CLUTTER_IS_INPUT_FOCUS (focus));
|
|
|
|
CLUTTER_INPUT_FOCUS_GET_CLASS (focus)->commit_text (focus, text);
|
|
}
|
|
|
|
void
|
|
clutter_input_focus_delete_surrounding (ClutterInputFocus *focus,
|
|
int offset,
|
|
guint len)
|
|
{
|
|
g_return_if_fail (CLUTTER_IS_INPUT_FOCUS (focus));
|
|
|
|
CLUTTER_INPUT_FOCUS_GET_CLASS (focus)->delete_surrounding (focus, offset, len);
|
|
}
|
|
|
|
void
|
|
clutter_input_focus_request_surrounding (ClutterInputFocus *focus)
|
|
{
|
|
g_return_if_fail (CLUTTER_IS_INPUT_FOCUS (focus));
|
|
|
|
CLUTTER_INPUT_FOCUS_GET_CLASS (focus)->request_surrounding (focus);
|
|
}
|
|
|
|
void
|
|
clutter_input_focus_set_preedit_text (ClutterInputFocus *focus,
|
|
const gchar *preedit,
|
|
unsigned int cursor,
|
|
unsigned int anchor)
|
|
{
|
|
g_return_if_fail (CLUTTER_IS_INPUT_FOCUS (focus));
|
|
|
|
CLUTTER_INPUT_FOCUS_GET_CLASS (focus)->set_preedit_text (focus, preedit,
|
|
cursor, anchor);
|
|
}
|