1
0
Fork 0
mutter-performance-source/clutter/clutter/clutter-input-focus.c
Carlos Garnacho 3b6f9111c7 clutter: Only reset preedit text if set
On ClutterInputFocus::reset, avoid to unset the preedit text if
none was set earlier. This seems to trick GTK clients into focusing
the cursor position again, even when we are moving away from it.

Fixes: https://gitlab.gnome.org/GNOME/gnome-shell/-/issues/4647
Part-of: <https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/2059>
2021-10-19 17:52:54 +00:00

306 lines
8.8 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);
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);
}
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)
{
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);
return TRUE;
}
else if (event->type == CLUTTER_TOUCH_BEGIN ||
(event->type == CLUTTER_BUTTON_PRESS &&
event->button.button == CLUTTER_BUTTON_PRIMARY))
{
clutter_input_focus_reset (focus);
/* pointing events are not consumed by IMs */
return FALSE;
}
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,
guint cursor)
{
g_return_if_fail (CLUTTER_IS_INPUT_FOCUS (focus));
CLUTTER_INPUT_FOCUS_GET_CLASS (focus)->set_preedit_text (focus, preedit, cursor);
}