Merge branch 'win32-ime-fix-popup-positioning' into 'main'

Win32 IME: Fix popup positioning

Closes #374 and #2338

See merge request GNOME/gtk!4501
This commit is contained in:
Luca Bacci 2022-02-22 07:52:59 +00:00
commit 8a8cd4e248
2 changed files with 48 additions and 66 deletions

View File

@ -124,9 +124,6 @@ gtk_im_context_ime_message_filter (GdkWin32Display *display,
MSG *msg,
int *ret_valp,
gpointer data);
static void get_window_position (GdkSurface *win,
int *x,
int *y);
G_DEFINE_TYPE_WITH_CODE (GtkIMContextIME, gtk_im_context_ime, GTK_TYPE_IM_CONTEXT,
gtk_im_module_ensure_extension_point ();
@ -159,6 +156,7 @@ gtk_im_context_ime_class_init (GtkIMContextIMEClass *class)
static void
gtk_im_context_ime_init (GtkIMContextIME *context_ime)
{
context_ime->client_widget = NULL;
context_ime->client_surface = NULL;
context_ime->use_preedit = TRUE;
context_ime->preediting = FALSE;
@ -248,17 +246,17 @@ gtk_im_context_ime_set_client_widget (GtkIMContext *context,
GtkWidget *widget)
{
GtkIMContextIME *context_ime;
GdkSurface *client_surface = NULL;
GdkSurface *surface = NULL;
g_return_if_fail (GTK_IS_IM_CONTEXT_IME (context));
context_ime = GTK_IM_CONTEXT_IME (context);
if (widget)
client_surface = gtk_native_get_surface (gtk_widget_get_native (widget));
surface = gtk_native_get_surface (gtk_widget_get_native (widget));
if (client_surface != NULL)
if (surface != NULL)
{
HWND hwnd = gdk_win32_surface_get_impl_hwnd (client_surface);
HWND hwnd = gdk_win32_surface_get_impl_hwnd (surface);
HIMC himc = ImmGetContext (hwnd);
if (himc)
{
@ -275,7 +273,8 @@ gtk_im_context_ime_set_client_widget (GtkIMContext *context,
gtk_im_context_ime_focus_out (context);
}
context_ime->client_surface = client_surface;
context_ime->client_widget = widget;
context_ime->client_surface = surface;
}
static gunichar
@ -766,7 +765,6 @@ static void
gtk_im_context_ime_set_cursor_location (GtkIMContext *context,
GdkRectangle *area)
{
int wx = 0, wy = 0;
GtkIMContextIME *context_ime;
COMPOSITIONFORM cf;
HWND hwnd;
@ -788,10 +786,10 @@ gtk_im_context_ime_set_cursor_location (GtkIMContext *context,
return;
scale = gdk_surface_get_scale_factor (context_ime->client_surface);
get_window_position (context_ime->client_surface, &wx, &wy);
cf.dwStyle = CFS_POINT;
cf.ptCurrentPos.x = (wx + context_ime->cursor_location.x) * scale;
cf.ptCurrentPos.y = (wy + context_ime->cursor_location.y) * scale;
cf.ptCurrentPos.x = context_ime->cursor_location.x * scale;
cf.ptCurrentPos.y = context_ime->cursor_location.y * scale;
ImmSetCompositionWindow (himc, &cf);
ImmReleaseContext (hwnd, himc);
@ -829,7 +827,6 @@ static void
gtk_im_context_ime_set_preedit_font (GtkIMContext *context)
{
GtkIMContextIME *context_ime;
GtkWidget *widget = NULL;
HWND hwnd;
HIMC himc;
HKL ime = GetKeyboardLayout (0);
@ -843,11 +840,8 @@ gtk_im_context_ime_set_preedit_font (GtkIMContext *context)
g_return_if_fail (GTK_IS_IM_CONTEXT_IME (context));
context_ime = GTK_IM_CONTEXT_IME (context);
if (!context_ime->client_surface)
return;
widget = GTK_WIDGET (gtk_native_get_for_surface (context_ime->client_surface));
if (!widget)
if (!(context_ime->client_widget && context_ime->client_surface))
return;
hwnd = gdk_win32_surface_get_impl_hwnd (context_ime->client_surface);
@ -856,7 +850,7 @@ gtk_im_context_ime_set_preedit_font (GtkIMContext *context)
return;
/* set font */
pango_context = gtk_widget_get_pango_context (widget);
pango_context = gtk_widget_get_pango_context (context_ime->client_widget);
if (!pango_context)
goto ERROR_OUT;
@ -891,7 +885,7 @@ gtk_im_context_ime_set_preedit_font (GtkIMContext *context)
lang = ""; break;
}
font_desc = gtk_css_style_get_pango_font (gtk_style_context_lookup_style (gtk_widget_get_style_context (widget)));
font_desc = gtk_css_style_get_pango_font (gtk_style_context_lookup_style (gtk_widget_get_style_context (context_ime->client_widget)));
if (lang[0])
{
@ -975,31 +969,45 @@ gtk_im_context_ime_message_filter (GdkWin32Display *display,
{
case WM_IME_COMPOSITION:
{
int wx = 0, wy = 0;
CANDIDATEFORM cf;
int scale = gdk_surface_get_scale_factor (context_ime->client_surface);
int wx = 0;
int wy = 0;
int scale = 1;
get_window_position (context_ime->client_surface, &wx, &wy);
/* FIXME! */
{
HWND impl_hwnd;
POINT pt;
RECT rc;
if (context_ime->client_surface && context_ime->client_widget)
{
GtkNative *native = gtk_native_get_for_surface (context_ime->client_surface);
if G_LIKELY (native)
{
double x = 0.0;
double y = 0.0;
double decor_x = 0.0;
double decor_y = 0.0;
gtk_widget_translate_coordinates (context_ime->client_widget,
GTK_WIDGET (native),
0.0, 0.0, &x, &y);
gtk_native_get_surface_transform (native, &decor_x, &decor_y);
x += decor_x;
y += decor_y;
wx = (int) x;
wy = (int) y;
}
scale = gtk_widget_get_scale_factor (context_ime->client_widget);
}
impl_hwnd =
gdk_win32_surface_get_impl_hwnd (context_ime->client_surface);
GetWindowRect (impl_hwnd, &rc);
pt.x = wx * scale;
pt.y = wy * scale;
ClientToScreen (impl_hwnd, &pt);
wx = (pt.x - rc.left) / scale;
wy = (pt.y - rc.top) / scale;
}
cf.dwIndex = 0;
cf.dwStyle = CFS_CANDIDATEPOS;
cf.dwStyle = CFS_EXCLUDE;
cf.ptCurrentPos.x = (wx + context_ime->cursor_location.x) * scale;
cf.ptCurrentPos.y = (wy + context_ime->cursor_location.y
+ context_ime->cursor_location.height) * scale;
cf.ptCurrentPos.y = (wy + context_ime->cursor_location.y) * scale;
cf.rcArea.left = cf.ptCurrentPos.x;
cf.rcArea.right = cf.rcArea.left + context_ime->cursor_location.width * scale;
cf.rcArea.top = cf.ptCurrentPos.y;
cf.rcArea.bottom = cf.rcArea.top + context_ime->cursor_location.height * scale;
ImmSetCandidateWindow (himc, &cf);
if ((msg->lParam & GCS_COMPSTR))
@ -1069,30 +1077,3 @@ gtk_im_context_ime_message_filter (GdkWin32Display *display,
ImmReleaseContext (hwnd, himc);
return retval;
}
/*
* x and y must be initialized to 0.
*/
static void
get_window_position (GdkSurface *surface, int *x, int *y)
{
GdkSurface *parent, *toplevel;
g_return_if_fail (GDK_IS_SURFACE (surface));
g_return_if_fail (x && y);
if (GDK_IS_POPUP (surface))
{
parent = gdk_popup_get_parent (GDK_POPUP (surface));
toplevel = surface;
}
else
{
parent = NULL;
toplevel = surface;
}
if (parent && parent != toplevel)
get_window_position (parent, x, y);
}

View File

@ -36,6 +36,7 @@ struct _GtkIMContextIME
{
GtkIMContext object;
GtkWidget *client_widget;
GdkSurface *client_surface;
guint use_preedit : 1;
guint preediting : 1;