summaryrefslogtreecommitdiffstats
path: root/vcl/unx/gtk3/a11y/atkcomponent.cxx
diff options
context:
space:
mode:
Diffstat (limited to 'vcl/unx/gtk3/a11y/atkcomponent.cxx')
-rw-r--r--vcl/unx/gtk3/a11y/atkcomponent.cxx431
1 files changed, 431 insertions, 0 deletions
diff --git a/vcl/unx/gtk3/a11y/atkcomponent.cxx b/vcl/unx/gtk3/a11y/atkcomponent.cxx
new file mode 100644
index 000000000..154f0117f
--- /dev/null
+++ b/vcl/unx/gtk3/a11y/atkcomponent.cxx
@@ -0,0 +1,431 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include "atkwrapper.hxx"
+#include <com/sun/star/accessibility/XAccessibleComponent.hpp>
+#include <sal/log.hxx>
+#include <gtk/gtk.h>
+
+using namespace ::com::sun::star;
+
+static AtkObjectWrapper* getObjectWrapper(AtkComponent *pComponent)
+{
+ AtkObjectWrapper *pWrap = nullptr;
+ if (ATK_IS_OBJECT_WRAPPER(pComponent))
+ pWrap = ATK_OBJECT_WRAPPER(pComponent);
+ else if (GTK_IS_DRAWING_AREA(pComponent)) //when using a GtkDrawingArea as a custom widget in welded gtk3
+ {
+ GtkWidget* pDrawingArea = GTK_WIDGET(pComponent);
+ AtkObject* pAtkObject = gtk_widget_get_accessible(pDrawingArea);
+ pWrap = ATK_IS_OBJECT_WRAPPER(pAtkObject) ? ATK_OBJECT_WRAPPER(pAtkObject) : nullptr;
+ }
+ return pWrap;
+}
+
+/// @throws uno::RuntimeException
+static css::uno::Reference<css::accessibility::XAccessibleComponent>
+ getComponent(AtkObjectWrapper *pWrap)
+{
+ if (pWrap)
+ {
+ if (!pWrap->mpComponent.is())
+ pWrap->mpComponent.set(pWrap->mpContext, css::uno::UNO_QUERY);
+ return pWrap->mpComponent;
+ }
+
+ return css::uno::Reference<css::accessibility::XAccessibleComponent>();
+}
+
+static awt::Point
+lcl_getLocationInWindow(AtkComponent* pAtkComponent,
+ css::uno::Reference<accessibility::XAccessibleComponent> const& xComponent)
+{
+ // calculate position in window by adding the component's position in the parent
+ // to the parent's position in the window (unless parent is a window itself)
+ awt::Point aPos = xComponent->getLocation();
+ AtkObject* pParent = atk_object_get_parent(ATK_OBJECT(pAtkComponent));
+ if (ATK_IS_COMPONENT(pParent) && pParent->role != AtkRole::ATK_ROLE_DIALOG
+ && pParent->role != AtkRole::ATK_ROLE_FILE_CHOOSER
+ && pParent->role != AtkRole::ATK_ROLE_FRAME
+ && pParent->role != AtkRole::ATK_ROLE_WINDOW)
+ {
+ int nX;
+ int nY;
+ atk_component_get_extents(ATK_COMPONENT(pParent), &nX, &nY, nullptr, nullptr, ATK_XY_WINDOW);
+ aPos.X += nX;
+ aPos.Y += nY;
+ }
+
+ return aPos;
+}
+
+/*****************************************************************************/
+
+static awt::Point
+translatePoint( AtkComponent* pAtkComponent,
+ css::uno::Reference<accessibility::XAccessibleComponent> const & pComponent,
+ gint x, gint y, AtkCoordType t)
+{
+ awt::Point aOrigin( 0, 0 );
+ if( t == ATK_XY_SCREEN )
+ aOrigin = pComponent->getLocationOnScreen();
+ else if (t == ATK_XY_WINDOW)
+ aOrigin = lcl_getLocationInWindow(pAtkComponent, pComponent);
+ return awt::Point( x - aOrigin.X, y - aOrigin.Y );
+}
+
+/*****************************************************************************/
+
+extern "C" {
+
+static gboolean
+component_wrapper_grab_focus (AtkComponent *component)
+{
+ AtkObjectWrapper* obj = getObjectWrapper(component);
+ //if we're a native GtkDrawingArea with custom a11y, use the default toolkit a11y
+ if (obj && obj->mpOrig)
+ return atk_component_grab_focus(ATK_COMPONENT(obj->mpOrig));
+
+ try
+ {
+ css::uno::Reference<css::accessibility::XAccessibleComponent> pComponent
+ = getComponent(obj);
+ if( pComponent.is() )
+ {
+ pComponent->grabFocus();
+ return true;
+ }
+ }
+ catch( const uno::Exception & )
+ {
+ g_warning( "Exception in grabFocus()" );
+ }
+
+ return FALSE;
+}
+
+/*****************************************************************************/
+
+static gboolean
+component_wrapper_contains (AtkComponent *component,
+ gint x,
+ gint y,
+ AtkCoordType coord_type)
+{
+ AtkObjectWrapper* obj = getObjectWrapper(component);
+ //if we're a native GtkDrawingArea with custom a11y, use the default toolkit a11y
+ if (obj && obj->mpOrig)
+ return atk_component_contains(ATK_COMPONENT(obj->mpOrig), x, y, coord_type);
+
+ try
+ {
+ css::uno::Reference<css::accessibility::XAccessibleComponent> pComponent
+ = getComponent(obj);
+ if( pComponent.is() )
+ return pComponent->containsPoint(
+ translatePoint(component, pComponent, x, y, coord_type));
+ }
+ catch( const uno::Exception & )
+ {
+ g_warning( "Exception in containsPoint()" );
+ }
+
+ return FALSE;
+}
+
+/*****************************************************************************/
+
+static AtkObject *
+component_wrapper_ref_accessible_at_point (AtkComponent *component,
+ gint x,
+ gint y,
+ AtkCoordType coord_type)
+{
+ AtkObjectWrapper* obj = getObjectWrapper(component);
+ //if we're a native GtkDrawingArea with custom a11y, use the default toolkit a11y
+ if (obj && obj->mpOrig)
+ return atk_component_ref_accessible_at_point(ATK_COMPONENT(obj->mpOrig), x, y, coord_type);
+
+ try
+ {
+ css::uno::Reference<css::accessibility::XAccessibleComponent> pComponent
+ = getComponent(obj);
+
+ if( pComponent.is() )
+ {
+ uno::Reference< accessibility::XAccessible > xAccessible = pComponent->getAccessibleAtPoint(
+ translatePoint(component, pComponent, x, y, coord_type));
+ return atk_object_wrapper_ref( xAccessible );
+ }
+ }
+ catch( const uno::Exception & )
+ {
+ g_warning( "Exception in getAccessibleAtPoint()" );
+ }
+
+ return nullptr;
+}
+
+/*****************************************************************************/
+
+static void
+component_wrapper_get_position (AtkComponent *component,
+ gint *x,
+ gint *y,
+ AtkCoordType coord_type)
+{
+ AtkObjectWrapper* obj = getObjectWrapper(component);
+ //if we're a native GtkDrawingArea with custom a11y, use the default toolkit a11y
+ if (obj && obj->mpOrig)
+ {
+ atk_component_get_extents(ATK_COMPONENT(obj->mpOrig), x, y, nullptr, nullptr, coord_type);
+ return;
+ }
+
+ *x = *y = -1;
+
+ try
+ {
+ css::uno::Reference<css::accessibility::XAccessibleComponent> pComponent
+ = getComponent(obj);
+ if( pComponent.is() )
+ {
+ awt::Point aPos;
+
+ if( coord_type == ATK_XY_SCREEN )
+ aPos = pComponent->getLocationOnScreen();
+ else if (coord_type == ATK_XY_WINDOW)
+ aPos = lcl_getLocationInWindow(component, pComponent);
+#if ATK_CHECK_VERSION(2, 30, 0)
+ else if (coord_type == ATK_XY_PARENT)
+#else
+ // ATK_XY_PARENT added in ATK 2.30, so can't use the constant here
+ else
+#endif
+ aPos = pComponent->getLocation();
+#if ATK_CHECK_VERSION(2, 30, 0)
+ else
+ {
+ SAL_WARN("vcl.gtk",
+ "component_wrapper_get_position called with unknown AtkCoordType "
+ << coord_type);
+ return;
+ }
+#endif
+
+ *x = aPos.X;
+ *y = aPos.Y;
+ }
+ }
+ catch( const uno::Exception & )
+ {
+ g_warning( "Exception in getLocation[OnScreen]()" );
+ }
+}
+
+/*****************************************************************************/
+
+static void
+component_wrapper_get_size (AtkComponent *component,
+ gint *width,
+ gint *height)
+{
+ AtkObjectWrapper* obj = getObjectWrapper(component);
+ //if we're a native GtkDrawingArea with custom a11y, use the default toolkit a11y
+ if (obj && obj->mpOrig)
+ {
+ atk_component_get_extents(ATK_COMPONENT(obj->mpOrig), nullptr, nullptr, width, height, ATK_XY_WINDOW);
+ return;
+ }
+
+ *width = *height = -1;
+
+ try
+ {
+ css::uno::Reference<css::accessibility::XAccessibleComponent> pComponent
+ = getComponent(obj);
+ if( pComponent.is() )
+ {
+ awt::Size aSize = pComponent->getSize();
+ *width = aSize.Width;
+ *height = aSize.Height;
+ }
+ }
+ catch( const uno::Exception & )
+ {
+ g_warning( "Exception in getSize()" );
+ }
+}
+
+/*****************************************************************************/
+
+static void
+component_wrapper_get_extents (AtkComponent *component,
+ gint *x,
+ gint *y,
+ gint *width,
+ gint *height,
+ AtkCoordType coord_type)
+{
+ component_wrapper_get_position( component, x, y, coord_type );
+ component_wrapper_get_size( component, width, height );
+}
+
+/*****************************************************************************/
+
+static gboolean
+component_wrapper_set_extents (AtkComponent *, gint, gint, gint, gint, AtkCoordType)
+{
+ g_warning( "AtkComponent::set_extents unimplementable" );
+ return FALSE;
+}
+
+/*****************************************************************************/
+
+static gboolean
+component_wrapper_set_position (AtkComponent *, gint, gint, AtkCoordType)
+{
+ g_warning( "AtkComponent::set_position unimplementable" );
+ return FALSE;
+}
+
+/*****************************************************************************/
+
+static gboolean
+component_wrapper_set_size (AtkComponent *, gint, gint)
+{
+ g_warning( "AtkComponent::set_size unimplementable" );
+ return FALSE;
+}
+
+/*****************************************************************************/
+
+static AtkLayer
+component_wrapper_get_layer (AtkComponent *component)
+{
+ AtkRole role = atk_object_get_role( ATK_OBJECT( component ) );
+ AtkLayer layer = ATK_LAYER_WIDGET;
+
+ switch (role)
+ {
+ case ATK_ROLE_POPUP_MENU:
+ case ATK_ROLE_MENU_ITEM:
+ case ATK_ROLE_CHECK_MENU_ITEM:
+ case ATK_ROLE_SEPARATOR:
+ case ATK_ROLE_LIST_ITEM:
+ layer = ATK_LAYER_POPUP;
+ break;
+ case ATK_ROLE_MENU:
+ {
+ AtkObject * parent = atk_object_get_parent( ATK_OBJECT( component ) );
+ if( atk_object_get_role( parent ) != ATK_ROLE_MENU_BAR )
+ layer = ATK_LAYER_POPUP;
+ }
+ break;
+
+ case ATK_ROLE_LIST:
+ {
+ AtkObject * parent = atk_object_get_parent( ATK_OBJECT( component ) );
+ if( atk_object_get_role( parent ) == ATK_ROLE_COMBO_BOX )
+ layer = ATK_LAYER_POPUP;
+ }
+ break;
+
+ default:
+ ;
+ }
+
+ return layer;
+}
+
+/*****************************************************************************/
+
+static gint
+component_wrapper_get_mdi_zorder (AtkComponent *)
+{
+ // only needed for ATK_LAYER_MDI (not used) or ATK_LAYER_WINDOW (inherited from GAIL)
+ return G_MININT;
+}
+
+/*****************************************************************************/
+
+// This code is mostly stolen from libgail ..
+
+static guint
+component_wrapper_add_focus_handler (AtkComponent *component,
+ AtkFocusHandler handler)
+{
+ GSignalMatchType match_type;
+ gulong ret;
+ guint signal_id;
+
+ match_type = GSignalMatchType(G_SIGNAL_MATCH_ID | G_SIGNAL_MATCH_FUNC);
+ signal_id = g_signal_lookup( "focus-event", ATK_TYPE_OBJECT );
+
+ ret = g_signal_handler_find( component, match_type, signal_id, 0, nullptr,
+ static_cast<gpointer>(&handler), nullptr);
+ if (!ret)
+ {
+ return g_signal_connect_closure_by_id (component,
+ signal_id, 0,
+ g_cclosure_new (
+ G_CALLBACK (handler), nullptr,
+ nullptr),
+ FALSE);
+ }
+ else
+ {
+ return 0;
+ }
+}
+
+/*****************************************************************************/
+
+static void
+component_wrapper_remove_focus_handler (AtkComponent *component,
+ guint handler_id)
+{
+ g_signal_handler_disconnect (component, handler_id);
+}
+
+/*****************************************************************************/
+
+} // extern "C"
+
+void
+componentIfaceInit (AtkComponentIface *iface)
+{
+ g_return_if_fail (iface != nullptr);
+
+ iface->add_focus_handler = component_wrapper_add_focus_handler;
+ iface->contains = component_wrapper_contains;
+ iface->get_extents = component_wrapper_get_extents;
+ iface->get_layer = component_wrapper_get_layer;
+ iface->get_mdi_zorder = component_wrapper_get_mdi_zorder;
+ iface->get_position = component_wrapper_get_position;
+ iface->get_size = component_wrapper_get_size;
+ iface->grab_focus = component_wrapper_grab_focus;
+ iface->ref_accessible_at_point = component_wrapper_ref_accessible_at_point;
+ iface->remove_focus_handler = component_wrapper_remove_focus_handler;
+ iface->set_extents = component_wrapper_set_extents;
+ iface->set_position = component_wrapper_set_position;
+ iface->set_size = component_wrapper_set_size;
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */