vcl/unx/gtk3/a11y/atklistener.cxx | 27 ++++++++++----------------- vcl/unx/gtk3/a11y/atktext.cxx | 18 ------------------ 2 files changed, 10 insertions(+), 35 deletions(-)
New commits: commit 4162feb37109d4e9da44933831e10b5732721c72 Author: Michael Weghorn <m.wegh...@posteo.de> AuthorDate: Tue Feb 22 13:39:56 2022 +0100 Commit: Michael Weghorn <m.wegh...@posteo.de> CommitDate: Wed Feb 23 06:26:32 2022 +0100 gtk3 a11y: Migrate from deprecated "text-changed" ATK signal The "text-changed" ATK signal (which has a detail of "insert" or "delete" to indicate what type of change happened) is deprecated since ATK 2.9.4 and "text-insert" or "text-remove" should be used instead [1], so do this. Those have the inserted/removed text as a third argument, so this also obsoletes the workaround to remember the deleted text under the "ooo::text_changed::delete" key for the ATK object in the "text-changed:delete" case. (See inline comments dropped in this commit for more details on how that was used, by now "appropriate API exists in atk to pass the string value directly".) Note that this only changes the signal on the ATK layer, the corresponding signal on the (underlying) AT-SPI layer is still "object::text-changed::inserted" or "object::text-changed::deleted", but other than the ATK signal of the same name, this event already has the inserted/deleted text as extra data. [2] (The conversion from the ATK signal to the AT-SPI one happens in at-spi2-atk. [3]). I used this script to check the emitted AT-SPI events: #!/usr/bin/python3 import pyatspi def listener(e): try: if e.host_application.name != 'soffice': return if e.source.role != pyatspi.role.ROLE_PARAGRAPH: return except: return print(e) pyatspi.Registry.registerEventListener(listener, "object:text-changed") pyatspi.Registry.start() Pasting the Chinese sample text from tdf#147285 into an empty Writer document, removing the third character and typing "a" instead resulted in the expected output: > object:text-changed:insert(0, 12, 维基百科,自由的百科全书) > source: [paragraph | ] > host_application: [application | soffice] > sender: [application | soffice] > object:text-changed:delete(2, 1, 百) > source: [paragraph | ] > host_application: [application | soffice] > sender: [application | soffice] > object:text-changed:insert(2, 1, a) > source: [paragraph | ] > host_application: [application | soffice] > sender: [application | soffice] Given this test worked, drop the old > // TESTME: and remove this comment: comment as well, and also drop the > // TODO: when GNOME starts to send "update" kind of events, change > // we need to re-think this implementation as well comment. From what I can see this is still the way to handle events using ATK (i.e. for Gtk 3 at least, Gtk 4 has a new a11y implementation [4], but that will have to be looked at separately anyway). [1] https://docs.gtk.org/atk/signal.Text.text-changed.html [2] https://accessibility.linuxfoundation.org/a11yspecs/atspi/adoc/atspi-events.html [3] https://gitlab.gnome.org/GNOME/at-spi2-atk/-/blob/0af3f73b/atk-adaptor/event.c#L962 [4] https://blog.gtk.org/2020/10/21/accessibility-in-gtk-4/ Change-Id: Ibcae27ecfccf41a909e06d01ce681e4b7b97eb25 Reviewed-on: https://gerrit.libreoffice.org/c/core/+/130352 Tested-by: Jenkins Reviewed-by: Michael Weghorn <m.wegh...@posteo.de> diff --git a/vcl/unx/gtk3/a11y/atklistener.cxx b/vcl/unx/gtk3/a11y/atklistener.cxx index 2ef96be4616e..6d81a9a60531 100644 --- a/vcl/unx/gtk3/a11y/atklistener.cxx +++ b/vcl/unx/gtk3/a11y/atklistener.cxx @@ -566,34 +566,27 @@ void AtkListener::notifyEvent( const accessibility::AccessibleEventObject& aEven } case accessibility::AccessibleEventId::TEXT_CHANGED: { - // TESTME: and remove this comment: // cf. comphelper/source/misc/accessibletexthelper.cxx (implInitTextChangedEvent) accessibility::TextSegment aDeletedText; accessibility::TextSegment aInsertedText; - // TODO: when GNOME starts to send "update" kind of events, change - // we need to re-think this implementation as well if( aEvent.OldValue >>= aDeletedText ) { - /* Remember the text segment here to be able to return removed text in get_text(). - * This is clearly a hack to be used until appropriate API exists in atk to pass - * the string value directly or we find a compelling reason to start caching the - * UTF-8 converted strings in the atk wrapper object. - */ - - g_object_set_data( G_OBJECT(atk_obj), "ooo::text_changed::delete", &aDeletedText); - - g_signal_emit_by_name( atk_obj, "text_changed::delete", + const OString aDeletedTextUtf8 = OUStringToOString(aDeletedText.SegmentText, RTL_TEXTENCODING_UTF8); + g_signal_emit_by_name( atk_obj, "text-remove", static_cast<gint>(aDeletedText.SegmentStart), - static_cast<gint>( aDeletedText.SegmentEnd - aDeletedText.SegmentStart ) ); + static_cast<gint>(aDeletedText.SegmentEnd - aDeletedText.SegmentStart), + g_strdup(aDeletedTextUtf8.getStr())); - g_object_steal_data( G_OBJECT(atk_obj), "ooo::text_changed::delete" ); } - if( aEvent.NewValue >>= aInsertedText ) - g_signal_emit_by_name( atk_obj, "text_changed::insert", + { + const OString aInsertedTextUtf8 = OUStringToOString(aInsertedText.SegmentText, RTL_TEXTENCODING_UTF8); + g_signal_emit_by_name( atk_obj, "text-insert", static_cast<gint>(aInsertedText.SegmentStart), - static_cast<gint>( aInsertedText.SegmentEnd - aInsertedText.SegmentStart ) ); + static_cast<gint>(aInsertedText.SegmentEnd - aInsertedText.SegmentStart), + g_strdup(aInsertedTextUtf8.getStr())); + } break; } diff --git a/vcl/unx/gtk3/a11y/atktext.cxx b/vcl/unx/gtk3/a11y/atktext.cxx index 8fc773224768..aee5c5ef5db0 100644 --- a/vcl/unx/gtk3/a11y/atktext.cxx +++ b/vcl/unx/gtk3/a11y/atktext.cxx @@ -254,24 +254,6 @@ text_wrapper_get_text (AtkText *text, g_return_val_if_fail( (end_offset == -1) || (end_offset >= start_offset), nullptr ); - /* at-spi expects the delete event to be send before the deletion happened - * so we save the deleted string object in the UNO event notification and - * fool libatk-bridge.so here .. - */ - void * pData = g_object_get_data( G_OBJECT(text), "ooo::text_changed::delete" ); - if( pData != nullptr ) - { - accessibility::TextSegment * pTextSegment = - static_cast <accessibility::TextSegment *> (pData); - - if( pTextSegment->SegmentStart == start_offset && - pTextSegment->SegmentEnd == end_offset ) - { - OString aUtf8 = OUStringToOString( pTextSegment->SegmentText, RTL_TEXTENCODING_UTF8 ); - return g_strdup( aUtf8.getStr() ); - } - } - try { css::uno::Reference<css::accessibility::XAccessibleText> pText = getText( text );