From e49d61a4b469ee34d11473b5c134f8cbddaaefe6 Mon Sep 17 00:00:00 2001 From: Nikita Tsukanov Date: Thu, 19 Oct 2023 18:42:44 +0300 Subject: [PATCH] iBus support fixes (#13297) * iBus: Fixed crash when iBus was provided by fcitx daemon * iBus: Ignore CommitText signal if it was sent while context is being Reset --- .../DBusIme/DBusTextInputMethodBase.cs | 2 +- .../DBusIme/IBus/IBusX11TextInputMethod.cs | 46 +++++++++++++++---- 2 files changed, 38 insertions(+), 10 deletions(-) diff --git a/src/Avalonia.FreeDesktop/DBusIme/DBusTextInputMethodBase.cs b/src/Avalonia.FreeDesktop/DBusIme/DBusTextInputMethodBase.cs index ee118d92b5..6cd24c49eb 100644 --- a/src/Avalonia.FreeDesktop/DBusIme/DBusTextInputMethodBase.cs +++ b/src/Avalonia.FreeDesktop/DBusIme/DBusTextInputMethodBase.cs @@ -308,9 +308,9 @@ namespace Avalonia.FreeDesktop.DBusIme void ITextInputMethodImpl.Reset() { - Reset(); _queue.Enqueue(async () => { + Reset(); if (!IsConnected) return; await ResetContextCore(); diff --git a/src/Avalonia.FreeDesktop/DBusIme/IBus/IBusX11TextInputMethod.cs b/src/Avalonia.FreeDesktop/DBusIme/IBus/IBusX11TextInputMethod.cs index e96172e5a6..35dc18288a 100644 --- a/src/Avalonia.FreeDesktop/DBusIme/IBus/IBusX11TextInputMethod.cs +++ b/src/Avalonia.FreeDesktop/DBusIme/IBus/IBusX11TextInputMethod.cs @@ -18,6 +18,7 @@ namespace Avalonia.FreeDesktop.DBusIme.IBus private string? _preeditText; private int _preeditCursor; private bool _preeditShown = true; + private int _insideReset = 0; public IBusX11TextInputMethod(Connection connection) : base(connection, "org.freedesktop.portal.IBus") { } @@ -52,8 +53,7 @@ namespace Avalonia.FreeDesktop.DBusIme.IBus private void OnUpdatePreedit(Exception? arg1, (DBusVariantItem text, uint cursor_pos, bool visible) preeditComponents) { - - if (preeditComponents.text.Value is DBusStructItem { Count: >= 3 } structItem && + if (preeditComponents.text is { Value: DBusStructItem { Count: >= 3 } structItem } && structItem[2] is DBusStringItem stringItem) { _preeditText = stringItem.Value; @@ -63,11 +63,17 @@ namespace Avalonia.FreeDesktop.DBusIme.IBus : 0; _preeditShown = true; - - if (Client?.SupportsPreedit == true) - Client.SetPreeditText( - _preeditText, _preeditCursor); } + else + { + _preeditText = null; + _preeditShown = false; + _preeditCursor = 0; + } + + if (Client?.SupportsPreedit == true) + Client.SetPreeditText( + _preeditShown ? _preeditText : null, _preeditCursor); } private void OnForwardKey(Exception? e, (uint keyval, uint keycode, uint state) k) @@ -98,6 +104,14 @@ namespace Avalonia.FreeDesktop.DBusIme.IBus private void OnCommitText(Exception? e, DBusVariantItem variantItem) { + if (_insideReset > 0) + { + // For some reason iBus can trigger a CommitText while being reset. + // Thankfully the signal is sent _during_ Reset call processing, + // so it arrives on-the-wire before Reset call result, so we can + // check if we have any pending Reset calls and ignore the signal here + return; + } if (e is not null) { Logger.TryGet(LogEventLevel.Error, LogArea.FreeDesktopPlatform)?.Log(this, $"OnCommitText failed: {e}"); @@ -125,10 +139,23 @@ namespace Avalonia.FreeDesktop.DBusIme.IBus => (active ? _context?.FocusInAsync() : _context?.FocusOutAsync()) ?? Task.CompletedTask; - protected override Task ResetContextCore() + protected override async Task ResetContextCore() { _preeditShown = true; - return _context?.ResetAsync() ?? Task.CompletedTask; + if (_context == null) + return; + if (_context == null) + return; + + try + { + _insideReset++; + await _context.ResetAsync(); + } + finally + { + _insideReset--; + } } protected override Task HandleKeyCore(RawKeyEventArgs args, int keyVal, int keyCode) @@ -159,7 +186,8 @@ namespace Avalonia.FreeDesktop.DBusIme.IBus var caps = IBusCapability.CapFocus; if (supportsPreedit) caps |= IBusCapability.CapPreeditText; - await _context.SetCapabilitiesAsync((uint)caps); + if (_context != null) + await _context.SetCapabilitiesAsync((uint)caps); } } }