Bug 571740 - [GTK] StyledText: IllegalArgumentException on dead keys
The GTK's bug is in `gtk_im_context_simple_get_preedit_string()`, which
incorrectly returns `len`, which is expressed in bytes instead of
characters.
Note that on GNOME, SWT forces a different IM called "ibus" via
Bug 546349 and the bug is not seen there. The bug also won't trigger on
systems that are configured to use any other IM.
Change-Id: I4d24a62e9aa34e0ee6fe2d3ec1395f97aa89dfd6
Signed-off-by: Alexandr Miloslavskiy <alexandr.miloslavskiy@syntevo.com>
Reviewed-on: https://git.eclipse.org/r/c/platform/eclipse.platform.swt/+/179531
Tested-by: Platform Bot <platform-bot@eclipse.org>
Reviewed-by: Soraphol (Paul) Damrongpiriyapong <sdamrong@redhat.com>
Reviewed-by: Alexander Kurtakov <akurtako@redhat.com>
diff --git a/bundles/org.eclipse.swt/Eclipse SWT/gtk/org/eclipse/swt/widgets/IME.java b/bundles/org.eclipse.swt/Eclipse SWT/gtk/org/eclipse/swt/widgets/IME.java
index cbd41b1..1a6faca 100644
--- a/bundles/org.eclipse.swt/Eclipse SWT/gtk/org/eclipse/swt/widgets/IME.java
+++ b/bundles/org.eclipse.swt/Eclipse SWT/gtk/org/eclipse/swt/widgets/IME.java
@@ -302,6 +302,19 @@
byte [] buffer = new byte [length];
C.memmove (buffer, preeditString [0], length);
chars = Converter.mbcsToWcs (buffer);
+
+ /*
+ * Bug 571740: GTK has a bug in 'gtk-im-context-simple' IM context
+ * which is default. It incorrectly reports 'cursorPos' in bytes
+ * instead of characters. Somewhere around GTK 3.24.26 this IM
+ * was reworked and it started sending 'gtk_preedit_changed' where
+ * it previously did not, causing SWT to step on that old bug.
+ * If caret's position is already at the end, this will result in
+ * trying to set caret outside the text. The workaround is to limit
+ * caret's position.
+ */
+ caretOffset = Math.min(caretOffset, chars.length);
+
if (pangoAttrs [0] != 0) {
int count = 0;
long iterator = OS.pango_attr_list_get_iterator (pangoAttrs [0]);
diff --git a/tests/org.eclipse.swt.tests.gtk/ManualTests/org/eclipse/swt/tests/gtk/snippets/Bug571740_IAE_AccentChars.java b/tests/org.eclipse.swt.tests.gtk/ManualTests/org/eclipse/swt/tests/gtk/snippets/Bug571740_IAE_AccentChars.java
new file mode 100644
index 0000000..e28081f
--- /dev/null
+++ b/tests/org.eclipse.swt.tests.gtk/ManualTests/org/eclipse/swt/tests/gtk/snippets/Bug571740_IAE_AccentChars.java
@@ -0,0 +1,54 @@
+/*******************************************************************************
+ * Copyright (c) 2021 Syntevo and others.
+ *
+ * This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License 2.0
+ * which accompanies this distribution, and is available at
+ * https://www.eclipse.org/legal/epl-2.0/
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ * Contributors:
+ * Syntevo - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.swt.tests.gtk.snippets;
+
+import org.eclipse.swt.*;
+import org.eclipse.swt.custom.*;
+import org.eclipse.swt.layout.*;
+import org.eclipse.swt.widgets.*;
+
+public class Bug571740_IAE_AccentChars {
+ public static void main(String[] args) {
+ final Display display = new Display();
+
+ final Shell shell = new Shell(display);
+ shell.setLayout(new GridLayout(1, true));
+
+ Label hint = new Label(shell, 0);
+ hint.setText(
+ "1) Use GTK 3.24.26 or higher\n" +
+ "2) Do not use GNOME, because SWT forces 'ibus' IM there\n" +
+ "3) Do not have any IM method configured, so that GTK's default is used\n" +
+ "4) Install Spanish keyboard layout\n" +
+ "5) Switch to Spanish keyboard layout\n" +
+ "6) In StyledText below, type ' key according to US layout\n" +
+ "7) Before the patch, SWT will throw IAE\n" +
+ "8) After the patch or with XFCE, ´ character will (correctly) appear\n" +
+ "9) After the patch or with XFCE, if you now type A, ´ will (correctly) be replaced with á"
+ );
+
+ new StyledText(shell, SWT.BORDER);
+
+ shell.pack();
+ shell.open();
+
+ while (!shell.isDisposed()) {
+ if (!display.readAndDispatch()) {
+ display.sleep();
+ }
+ }
+
+ display.dispose();
+ }
+}