Quellcodebibliothek Statistik Leitseite products/sources/formale Sprachen/C/LibreOffice/vcl/unx/gtk4/   (Office von Apache Version 25.8.3.2©)  Datei vom 5.10.2025 mit Größe 35 kB image not shown  

Quelle  a11y.cxx   Sprache: C

 
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4; fill-column: 100 -*- */
/*
 * 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/.
 */


#include <com/sun/star/accessibility/AccessibleRelationType.hpp>
#include <com/sun/star/accessibility/AccessibleRole.hpp>
#include <com/sun/star/accessibility/AccessibleStateType.hpp>
#include <com/sun/star/accessibility/XAccessibleComponent.hpp>
#include <com/sun/star/accessibility/XAccessibleEventBroadcaster.hpp>
#include <com/sun/star/accessibility/XAccessibleExtendedAttributes.hpp>
#include <com/sun/star/accessibility/XAccessibleText.hpp>
#include <com/sun/star/accessibility/XAccessibleValue.hpp>
#include <unx/gtk/gtkframe.hxx>
#include <gtk/gtk.h>
#include <o3tl/string_view.hxx>

#include "a11y.hxx"
#include "gtkaccessibleeventlistener.hxx"
#include "gtkaccessibleregistry.hxx"
#include "gtkaccessibletext.hxx"

#define OOO_TYPE_FIXED (ooo_fixed_get_type())
#define OOO_FIXED(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), OOO_TYPE_FIXED, OOoFixed))
// #define OOO_IS_FIXED(obj)        (G_TYPE_CHECK_INSTANCE_TYPE((obj), OOO_TYPE_FIXED))

struct OOoFixed
{
    GtkFixed parent_instance;
    GtkATContext* at_context;
};

struct OOoFixedClass
{
    GtkFixedClass parent_class;
};

static GtkAccessibleRole
map_accessible_role(const css::uno::Reference<css::accessibility::XAccessible>& rAccessible)
{
    GtkAccessibleRole eRole(GTK_ACCESSIBLE_ROLE_WIDGET);

    if (rAccessible.is())
    {
        css::uno::Reference<css::accessibility::XAccessibleContext> xContext(
            rAccessible->getAccessibleContext());

        if (!xContext.is())
            return GTK_ACCESSIBLE_ROLE_NONE;

        // https://w3c.github.io/core-aam/#mapping_role
        // https://hg.mozilla.org/mozilla-central/file/tip/accessible/base/RoleMap.h
        // https://gitlab.gnome.org/GNOME/gtk/-/blob/main/gtk/a11y/gtkatspiutils.c
        switch (xContext->getAccessibleRole())
        {
            case css::accessibility::AccessibleRole::ALERT:
            case css::accessibility::AccessibleRole::NOTIFICATION:
                eRole = GTK_ACCESSIBLE_ROLE_ALERT;
                break;
            case css::accessibility::AccessibleRole::BLOCK_QUOTE:
#if GTK_CHECK_VERSION(4, 13, 4)
                eRole = GTK_ACCESSIBLE_ROLE_BLOCK_QUOTE;
#else
                eRole = GTK_ACCESSIBLE_ROLE_GROUP;
#endif
                break;
            case css::accessibility::AccessibleRole::CAPTION:
                eRole = GTK_ACCESSIBLE_ROLE_CAPTION;
                break;
            case css::accessibility::AccessibleRole::COLUMN_HEADER:
                eRole = GTK_ACCESSIBLE_ROLE_COLUMN_HEADER;
                break;
            case css::accessibility::AccessibleRole::COMBO_BOX:
                eRole = GTK_ACCESSIBLE_ROLE_COMBO_BOX;
                break;
            case css::accessibility::AccessibleRole::DIALOG:
            case css::accessibility::AccessibleRole::FILE_CHOOSER:
                eRole = GTK_ACCESSIBLE_ROLE_DIALOG;
                break;
            case css::accessibility::AccessibleRole::FOOTNOTE:
            case css::accessibility::AccessibleRole::NOTE:
                eRole = GTK_ACCESSIBLE_ROLE_NOTE;
                break;
            case css::accessibility::AccessibleRole::FORM:
                eRole = GTK_ACCESSIBLE_ROLE_FORM;
                break;
            case css::accessibility::AccessibleRole::HEADING:
                eRole = GTK_ACCESSIBLE_ROLE_HEADING;
                break;
            case css::accessibility::AccessibleRole::HYPER_LINK:
                eRole = GTK_ACCESSIBLE_ROLE_LINK;
                break;
            case css::accessibility::AccessibleRole::PANEL:
            case css::accessibility::AccessibleRole::ROOT_PANE:
            case css::accessibility::AccessibleRole::SPLIT_PANE:
                eRole = GTK_ACCESSIBLE_ROLE_GENERIC;
                break;
            case css::accessibility::AccessibleRole::MENU_BAR:
                eRole = GTK_ACCESSIBLE_ROLE_MENU_BAR;
                break;
            case css::accessibility::AccessibleRole::STATUS_BAR:
                eRole = GTK_ACCESSIBLE_ROLE_STATUS;
                break;
            case css::accessibility::AccessibleRole::MENU:
            case css::accessibility::AccessibleRole::POPUP_MENU:
                eRole = GTK_ACCESSIBLE_ROLE_MENU;
                break;
            case css::accessibility::AccessibleRole::TOOL_BAR:
                eRole = GTK_ACCESSIBLE_ROLE_TOOLBAR;
                break;
            case css::accessibility::AccessibleRole::LABEL:
            case css::accessibility::AccessibleRole::STATIC:
                eRole = GTK_ACCESSIBLE_ROLE_LABEL;
                break;
            case css::accessibility::AccessibleRole::LIST:
                eRole = GTK_ACCESSIBLE_ROLE_LIST;
                break;
            case css::accessibility::AccessibleRole::LIST_ITEM:
                eRole = GTK_ACCESSIBLE_ROLE_LIST_ITEM;
                break;
            case css::accessibility::AccessibleRole::MENU_ITEM:
                eRole = GTK_ACCESSIBLE_ROLE_MENU_ITEM;
                break;
            case css::accessibility::AccessibleRole::SEPARATOR:
                eRole = GTK_ACCESSIBLE_ROLE_SEPARATOR;
                break;
            case css::accessibility::AccessibleRole::CHECK_BOX:
                eRole = GTK_ACCESSIBLE_ROLE_CHECKBOX;
                break;
            case css::accessibility::AccessibleRole::CHECK_MENU_ITEM:
                eRole = GTK_ACCESSIBLE_ROLE_MENU_ITEM_CHECKBOX;
                break;
            case css::accessibility::AccessibleRole::RADIO_MENU_ITEM:
                eRole = GTK_ACCESSIBLE_ROLE_MENU_ITEM_RADIO;
                break;
            case css::accessibility::AccessibleRole::DOCUMENT:
            case css::accessibility::AccessibleRole::DOCUMENT_PRESENTATION:
            case css::accessibility::AccessibleRole::DOCUMENT_SPREADSHEET:
            case css::accessibility::AccessibleRole::DOCUMENT_TEXT:
                eRole = GTK_ACCESSIBLE_ROLE_DOCUMENT;
                break;
            case css::accessibility::AccessibleRole::ROW_HEADER:
                eRole = GTK_ACCESSIBLE_ROLE_ROW_HEADER;
                break;
            case css::accessibility::AccessibleRole::RULER:
                eRole = GTK_ACCESSIBLE_ROLE_WIDGET;
                break;
            case css::accessibility::AccessibleRole::PARAGRAPH:
#if GTK_CHECK_VERSION(4, 13, 1)
                eRole = GTK_ACCESSIBLE_ROLE_PARAGRAPH;
#else
                eRole = GTK_ACCESSIBLE_ROLE_GROUP;
#endif
                break;
            case css::accessibility::AccessibleRole::FILLER:
                // GTK maps this to ATSPI_ROLE_FILLER
                eRole = GTK_ACCESSIBLE_ROLE_WIDGET;
                break;
            case css::accessibility::AccessibleRole::PUSH_BUTTON:
            case css::accessibility::AccessibleRole::BUTTON_DROPDOWN:
            case css::accessibility::AccessibleRole::BUTTON_MENU:
                eRole = GTK_ACCESSIBLE_ROLE_BUTTON;
                break;
            case css::accessibility::AccessibleRole::TOGGLE_BUTTON:
                eRole = GTK_ACCESSIBLE_ROLE_TOGGLE_BUTTON;
                break;
            case css::accessibility::AccessibleRole::TABLE:
                eRole = GTK_ACCESSIBLE_ROLE_TABLE;
                break;
            case css::accessibility::AccessibleRole::TABLE_CELL:
                eRole = GTK_ACCESSIBLE_ROLE_CELL;
                break;
            case css::accessibility::AccessibleRole::PAGE_TAB:
                eRole = GTK_ACCESSIBLE_ROLE_TAB;
                break;
            case css::accessibility::AccessibleRole::PAGE_TAB_LIST:
                eRole = GTK_ACCESSIBLE_ROLE_TAB_LIST;
                break;
            case css::accessibility::AccessibleRole::PROGRESS_BAR:
                eRole = GTK_ACCESSIBLE_ROLE_PROGRESS_BAR;
                break;
            case css::accessibility::AccessibleRole::RADIO_BUTTON:
                eRole = GTK_ACCESSIBLE_ROLE_RADIO;
                break;
            case css::accessibility::AccessibleRole::SCROLL_BAR:
                eRole = GTK_ACCESSIBLE_ROLE_SCROLLBAR;
                break;
            case css::accessibility::AccessibleRole::SLIDER:
                eRole = GTK_ACCESSIBLE_ROLE_SLIDER;
                break;
            case css::accessibility::AccessibleRole::SPIN_BOX:
                eRole = GTK_ACCESSIBLE_ROLE_SPIN_BUTTON;
                break;
            case css::accessibility::AccessibleRole::TEXT:
            case css::accessibility::AccessibleRole::PASSWORD_TEXT:
                eRole = GTK_ACCESSIBLE_ROLE_TEXT_BOX;
                break;
            case css::accessibility::AccessibleRole::TOOL_TIP:
                eRole = GTK_ACCESSIBLE_ROLE_TOOLTIP;
                break;
            case css::accessibility::AccessibleRole::TREE:
                eRole = GTK_ACCESSIBLE_ROLE_TREE;
                break;
            case css::accessibility::AccessibleRole::TREE_ITEM:
                eRole = GTK_ACCESSIBLE_ROLE_TREE_ITEM;
                break;
            case css::accessibility::AccessibleRole::TREE_TABLE:
                eRole = GTK_ACCESSIBLE_ROLE_TREE_GRID;
                break;
            case css::accessibility::AccessibleRole::GRAPHIC:
            case css::accessibility::AccessibleRole::ICON:
            case css::accessibility::AccessibleRole::SHAPE:
                eRole = GTK_ACCESSIBLE_ROLE_IMG;
                break;
            case css::accessibility::AccessibleRole::COMMENT:
#if GTK_CHECK_VERSION(4, 13, 4)
                eRole = GTK_ACCESSIBLE_ROLE_COMMENT;
                break;
#endif
            default:
                SAL_WARN("vcl.gtk",
                         "unmapped GtkAccessibleRole: " << xContext->getAccessibleRole());
                break;
        }
    }

    return eRole;
}

static css::uno::Reference<css::accessibility::XAccessible> get_uno_accessible(GtkWidget* pWidget)
{
    GtkWidget* pTopLevel = widget_get_toplevel(pWidget);
    if (!pTopLevel)
        return nullptr;

    GtkSalFrame* pFrame = GtkSalFrame::getFromWindow(pTopLevel);
    if (!pFrame)
        return nullptr;

    vcl::Window* pFrameWindow = pFrame->GetWindow();
    if (!pFrameWindow)
        return nullptr;

    vcl::Window* pWindow = pFrameWindow;

    // skip accessible objects already exposed by the frame objects
    if (WindowType::BORDERWINDOW == pWindow->GetType())
        pWindow = pFrameWindow->GetAccessibleChildWindow(0);

    if (!pWindow)
        return nullptr;

    return pWindow->GetAccessible();
}

/**
 * Based on the states set in xContext, set the corresponding Gtk states/properties
 * in pGtkAccessible.
 */

static void applyStates(GtkAccessible* pGtkAccessible,
                        css::uno::Reference<css::accessibility::XAccessibleContext>& xContext)
{
    assert(pGtkAccessible);

    if (!xContext.is())
        return;

    // Gtk differentiates between GtkAccessibleState and GtkAccessibleProperty
    // (both handled here) and GtkAccessiblePlatformState (handled in
    // 'lo_accessible_get_platform_state')
    const sal_Int64 nStates = xContext->getAccessibleStateSet();
    gtk_accessible_update_property(
        pGtkAccessible, GTK_ACCESSIBLE_PROPERTY_MODAL,
        bool(nStates & css::accessibility::AccessibleStateType::MODAL),
        GTK_ACCESSIBLE_PROPERTY_MULTI_LINE,
        bool(nStates & css::accessibility::AccessibleStateType::MULTI_LINE),
        GTK_ACCESSIBLE_PROPERTY_MULTI_SELECTABLE,
        bool(nStates & css::accessibility::AccessibleStateType::MULTI_SELECTABLE),
        GTK_ACCESSIBLE_PROPERTY_READ_ONLY,
        bool(!(nStates & css::accessibility::AccessibleStateType::EDITABLE)), -1);
    if (nStates & css::accessibility::AccessibleStateType::HORIZONTAL)
    {
        gtk_accessible_update_property(pGtkAccessible, GTK_ACCESSIBLE_PROPERTY_ORIENTATION,
                                       GTK_ORIENTATION_HORIZONTAL, -1);
    }
    else if (nStates & css::accessibility::AccessibleStateType::VERTICAL)
    {
        gtk_accessible_update_property(pGtkAccessible, GTK_ACCESSIBLE_PROPERTY_ORIENTATION,
                                       GTK_ORIENTATION_VERTICAL, -1);
    }

    gtk_accessible_update_state(pGtkAccessible, GTK_ACCESSIBLE_STATE_BUSY,
                                bool(nStates & css::accessibility::AccessibleStateType::BUSY),
                                GTK_ACCESSIBLE_STATE_DISABLED,
                                bool(!(nStates & css::accessibility::AccessibleStateType::ENABLED)),
                                -1);

    // when explicitly setting any value for GTK_ACCESSIBLE_STATE_CHECKED,
    // Gtk will also report ATSPI_STATE_CHECKABLE on the AT-SPI layer
    if (nStates & css::accessibility::AccessibleStateType::CHECKABLE)
    {
        GtkAccessibleTristate eState = GTK_ACCESSIBLE_TRISTATE_FALSE;
        if (nStates & css::accessibility::AccessibleStateType::INDETERMINATE)
            eState = GTK_ACCESSIBLE_TRISTATE_MIXED;
        else if (nStates & css::accessibility::AccessibleStateType::CHECKED)
            eState = GTK_ACCESSIBLE_TRISTATE_TRUE;
        gtk_accessible_update_state(pGtkAccessible, GTK_ACCESSIBLE_STATE_CHECKED, eState, -1);
    }

    if (nStates & css::accessibility::AccessibleStateType::EXPANDABLE)
    {
        gtk_accessible_update_state(
            pGtkAccessible, GTK_ACCESSIBLE_STATE_EXPANDED,
            bool(nStates & css::accessibility::AccessibleStateType::EXPANDED), -1);
    }

    if (nStates & css::accessibility::AccessibleStateType::SELECTABLE)
    {
        gtk_accessible_update_state(
            pGtkAccessible, GTK_ACCESSIBLE_STATE_SELECTED,
            bool(nStates & css::accessibility::AccessibleStateType::SELECTED), -1);
    }

    const sal_Int16 nRole = xContext->getAccessibleRole();
    if (nRole == css::accessibility::AccessibleRole::TOGGLE_BUTTON)
    {
        GtkAccessibleTristate eState = GTK_ACCESSIBLE_TRISTATE_FALSE;
        if (nStates & css::accessibility::AccessibleStateType::INDETERMINATE)
            eState = GTK_ACCESSIBLE_TRISTATE_MIXED;
        else if (nStates & css::accessibility::AccessibleStateType::PRESSED)
            eState = GTK_ACCESSIBLE_TRISTATE_TRUE;
        gtk_accessible_update_state(pGtkAccessible, GTK_ACCESSIBLE_STATE_PRESSED, eState, -1);
    }
}

static void applyObjectAttribute(GtkAccessible* pGtkAccessible, std::u16string_view rName,
                                 const OUString& rValue)
{
    assert(pGtkAccessible);

    if (rName == u"colindextext")
    {
        gtk_accessible_update_relation(pGtkAccessible, GTK_ACCESSIBLE_RELATION_COL_INDEX_TEXT,
                                       rValue.toUtf8().getStr(), -1);
    }
    else if (rName == u"level")
    {
        const int nLevel = o3tl::toInt32(rValue);
        gtk_accessible_update_property(pGtkAccessible, GTK_ACCESSIBLE_PROPERTY_LEVEL, nLevel, -1);
    }
    else if (rName == u"rowindextext")
    {
        gtk_accessible_update_relation(pGtkAccessible, GTK_ACCESSIBLE_RELATION_ROW_INDEX_TEXT,
                                       rValue.toUtf8().getStr(), -1);
    }
}

/**
 * Based on the object attributes set for xContext, set the corresponding Gtk equivalents
 * in pGtkAccessible, where applicable.
 */

static void
applyObjectAttributes(GtkAccessible* pGtkAccessible,
                      css::uno::Reference<css::accessibility::XAccessibleContext>& xContext)
{
    assert(pGtkAccessible);

    css::uno::Reference<css::accessibility::XAccessibleExtendedAttributes> xAttributes(
        xContext, css::uno::UNO_QUERY);
    if (!xAttributes.is())
        return;

    const OUString sAttrs = xAttributes->getExtendedAttributes();

    sal_Int32 nIndex = 0;
    do
    {
        const OUString sAttribute = sAttrs.getToken(0, ';', nIndex);
        sal_Int32 nColonPos = 0;
        const OUString sName = sAttribute.getToken(0, ':', nColonPos);
        const OUString sValue = sAttribute.getToken(0, ':', nColonPos);
        assert(nColonPos == -1
               && "Too many colons in attribute that should have \"name:value\" syntax");

        applyObjectAttribute(pGtkAccessible, sName, sValue);
    } while (nIndex >= 0);
}

static void applyRelations(LoAccessible* pLoAccessible,
                           css::uno::Reference<css::accessibility::XAccessibleContext>& xContext)
{
    assert(pLoAccessible);

    if (!xContext)
        return;

    css::uno::Reference<css::accessibility::XAccessibleRelationSet> xRelationSet
        = xContext->getAccessibleRelationSet();
    if (!xRelationSet.is())
        return;

    for (sal_Int32 i = 0; i < xRelationSet->getRelationCount(); i++)
    {
        GtkAccessibleRelation eGtkRelation;
        css::accessibility::AccessibleRelation aRelation = xRelationSet->getRelation(i);
        switch (aRelation.RelationType)
        {
            case css::accessibility::AccessibleRelationType_CONTENT_FLOWS_TO:
                eGtkRelation = GTK_ACCESSIBLE_RELATION_FLOW_TO;
                break;
            case css::accessibility::AccessibleRelationType_CONTROLLER_FOR:
                eGtkRelation = GTK_ACCESSIBLE_RELATION_CONTROLS;
                break;
            case css::accessibility::AccessibleRelationType_DESCRIBED_BY:
                eGtkRelation = GTK_ACCESSIBLE_RELATION_DESCRIBED_BY;
                break;
            case css::accessibility::AccessibleRelationType_LABELED_BY:
                eGtkRelation = GTK_ACCESSIBLE_RELATION_LABELLED_BY;
                break;
            case css::accessibility::AccessibleRelationType_CONTENT_FLOWS_FROM:
            case css::accessibility::AccessibleRelationType_CONTROLLED_BY:
            case css::accessibility::AccessibleRelationType_INVALID:
            case css::accessibility::AccessibleRelationType_LABEL_FOR:
            case css::accessibility::AccessibleRelationType_MEMBER_OF:
            case css::accessibility::AccessibleRelationType_NODE_CHILD_OF:
            case css::accessibility::AccessibleRelationType_SUB_WINDOW_OF:
                // GTK has no equivalent for these
                continue;
            default:
                assert(false && "Unhandled relation type");
        }

        gtk_accessible_reset_relation(GTK_ACCESSIBLE(pLoAccessible),
                                      GTK_ACCESSIBLE_RELATION_FLOW_TO);

        GList* pTargetObjects = nullptr;
        for (const css::uno::Reference<css::accessibility::XAccessible>& xTargetAcc :
             aRelation.TargetSet)
        {
            LoAccessible* pTargetLOAcc
                = GtkAccessibleRegistry::getLOAccessible(xTargetAcc, pLoAccessible->display);
            assert(pTargetLOAcc);
            GObject* pObject = G_OBJECT(pTargetLOAcc);
            g_object_ref(pObject);
            pTargetObjects = g_list_append(pTargetObjects, pObject);
        }

        GValue aValue = G_VALUE_INIT;
        gtk_accessible_relation_init_value(eGtkRelation, &aValue);
        g_value_set_pointer(&aValue, pTargetObjects);
        gtk_accessible_update_relation_value(GTK_ACCESSIBLE(pLoAccessible), 1, &eGtkRelation,
                                             &aValue);
    }
}

struct LoAccessibleClass
{
    GObjectClass parent_class;
};

static void lo_accessible_range_init(gpointer iface_, gpointer);
static gboolean lo_accessible_range_set_current_value(GtkAccessibleRange* self, double fNewValue);

extern "C" {
typedef GType (*GetGIfaceType)();
}
const struct
{
    const char* name;
    GInterfaceInitFunc const aInit;
    GetGIfaceType const aGetGIfaceType;
    const css::uno::Type& (*aGetUnoType)();
} TYPE_TABLE[] = {
#if GTK_CHECK_VERSION(4, 14, 0)
    { "Text", lo_accessible_text_init, gtk_accessible_text_get_type,
      cppu::UnoType<css::accessibility::XAccessibleText>::get },
#endif
    { "Value", lo_accessible_range_init, gtk_accessible_range_get_type,
      cppu::UnoType<css::accessibility::XAccessibleValue>::get },
};

static bool isOfType(css::uno::XInterface* xInterface, const css::uno::Type& rType)
{
    if (!xInterface)
        return false;

    try
    {
        css::uno::Any aRet = xInterface->queryInterface(rType);
        const bool bIs = (typelib_TypeClass_INTERFACE == aRet.pType->eTypeClass)
                         && (aRet.pReserved != nullptr);
        return bIs;
    }
    catch (const css::uno::Exception&)
    {
        return false;
    }
}

static GType ensureTypeFor(css::uno::XInterface* xAccessible)
{
    OStringBuffer aTypeNameBuf("OOoGtkAccessibleObj");
    std::vector<bool> bTypes(std::size(TYPE_TABLE), false);
    for (size_t i = 0; i < std::size(TYPE_TABLE); i++)
    {
        if (isOfType(xAccessible, TYPE_TABLE[i].aGetUnoType()))
        {
            aTypeNameBuf.append(TYPE_TABLE[i].name);
            bTypes[i] = true;
        }
    }

    const OString aTypeName = aTypeNameBuf.makeStringAndClear();
    GType nType = g_type_from_name(aTypeName.getStr());
    if (nType != G_TYPE_INVALID)
        return nType;

    GTypeInfo aTypeInfo = { sizeof(LoAccessibleClass), nullptr, nullptr, nullptr, nullptr, nullptr,
                            sizeof(LoAccessible),      0,       nullptr, nullptr };
    nType
        = g_type_register_static(LO_TYPE_ACCESSIBLE, aTypeName.getStr(), &aTypeInfo, GTypeFlags(0));

    for (size_t i = 0; i < std::size(TYPE_TABLE); i++)
    {
        if (bTypes[i])
        {
            GInterfaceInfo aIfaceInfo = { nullptr, nullptr, nullptr };
            aIfaceInfo.interface_init = TYPE_TABLE[i].aInit;
            g_type_add_interface_static(nType, TYPE_TABLE[i].aGetGIfaceType(), &aIfaceInfo);
        }
    }
    return nType;
}

enum
{
    CHILD_PROP_0,
    LAST_CHILD_PROP,

    PROP_ACCESSIBLE_ROLE
};

static void lo_accessible_get_property(GObject* object, guint property_id, GValue* value,
                                       GParamSpec* pspec)
{
    LoAccessible* accessible = LO_ACCESSIBLE(object);

    switch (property_id)
    {
        case PROP_ACCESSIBLE_ROLE:
        {
            GtkAccessibleRole eRole(map_accessible_role(accessible->uno_accessible));
            g_value_set_enum(value, eRole);
            break;
        }
        default:
            G_OBJECT_WARN_INVALID_PROPERTY_ID(object, property_id, pspec);
            break;
    }
}

static void lo_accessible_set_property(GObject* object, guint property_id, const GValue/*value*/,
                                       GParamSpec* pspec)
{
    //    LoAccessible* accessible = LO_ACCESSIBLE(object);

    switch (property_id)
    {
        case PROP_ACCESSIBLE_ROLE:
            break;
        default:
            G_OBJECT_WARN_INVALID_PROPERTY_ID(object, property_id, pspec);
            break;
    }
}

static GtkAccessible* lo_accessible_get_accessible_parent(GtkAccessible* accessible)
{
    LoAccessible* lo_accessible = LO_ACCESSIBLE(accessible);
    if (!lo_accessible->parent)
        return nullptr;
    return GTK_ACCESSIBLE(g_object_ref(lo_accessible->parent));
}

static GtkATContext* lo_accessible_get_at_context(GtkAccessible* self)
{
    LoAccessible* pAccessible = LO_ACCESSIBLE(self);

    if (!pAccessible->at_context)
    {
        GtkAccessibleRole eRole = map_accessible_role(pAccessible->uno_accessible);
        pAccessible->at_context = gtk_at_context_create(eRole, self, pAccessible->display);
        if (!pAccessible->at_context)
            return nullptr;
    }

    return g_object_ref(pAccessible->at_context);
}

static GtkAccessible* lo_accessible_get_first_accessible_child(GtkAccessible* self);

static GtkAccessible* lo_accessible_get_next_accessible_sibling(GtkAccessible* self);

static gboolean lo_accessible_get_platform_state(GtkAccessible* self,
                                                 GtkAccessiblePlatformState state);

static gboolean lo_accessible_get_bounds(GtkAccessible* accessible, int* x, int* y, intwidth,
                                         int* height);

static void lo_accessible_accessible_init(GtkAccessibleInterface* iface)
{
    iface->get_accessible_parent = lo_accessible_get_accessible_parent;
    iface->get_at_context = lo_accessible_get_at_context;
    iface->get_bounds = lo_accessible_get_bounds;
    iface->get_first_accessible_child = lo_accessible_get_first_accessible_child;
    iface->get_next_accessible_sibling = lo_accessible_get_next_accessible_sibling;
    iface->get_platform_state = lo_accessible_get_platform_state;
}

static void lo_accessible_range_init(gpointer iface_, gpointer)
{
    auto const iface = static_cast<GtkAccessibleRangeInterface*>(iface_);
    iface->set_current_value = lo_accessible_range_set_current_value;
}

// silence loplugin:unreffun
#ifdef __GNUC__
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wunused-function"
#endif
G_DEFINE_TYPE_WITH_CODE(LoAccessible, lo_accessible, G_TYPE_OBJECT,
                        G_IMPLEMENT_INTERFACE(GTK_TYPE_ACCESSIBLE, lo_accessible_accessible_init))
#ifdef __GNUC__
#pragma GCC diagnostic pop
#endif

static void lo_accessible_class_init(LoAccessibleClass* klass)
{
    GObjectClass* object_class = G_OBJECT_CLASS(klass);

    //    object_class->finalize = lo_accessible_finalize;
    //    object_class->dispose = lo_accessible_dispose;
    object_class->get_property = lo_accessible_get_property;
    object_class->set_property = lo_accessible_set_property;
    //    object_class->constructed = lo_accessible_constructed;

    //    g_object_class_install_properties(object_class, LAST_CHILD_PROP, lo_accessible_props);
    g_object_class_override_property(object_class, PROP_ACCESSIBLE_ROLE, "accessible-role");
}

LoAccessible*
lo_accessible_new(GdkDisplay* pDisplay, GtkAccessible* pParent,
                  const css::uno::Reference<css::accessibility::XAccessible>& rAccessible)
{
    assert(rAccessible.is());

    GType nType = ensureTypeFor(rAccessible.get());
    LoAccessible* ret = LO_ACCESSIBLE(g_object_new(nType, nullptr));
    ret->display = pDisplay;
    ret->parent = pParent;
    ret->uno_accessible = rAccessible;

    css::uno::Reference<css::accessibility::XAccessibleContext> xContext(
        ret->uno_accessible->getAccessibleContext());
    assert(xContext.is() && "No accessible context");

    GtkAccessible* pGtkAccessible = GTK_ACCESSIBLE(ret);

    // set accessible name and description
    gtk_accessible_update_property(pGtkAccessible, GTK_ACCESSIBLE_PROPERTY_LABEL,
                                   xContext->getAccessibleName().toUtf8().getStr(),
                                   GTK_ACCESSIBLE_PROPERTY_DESCRIPTION,
                                   xContext->getAccessibleDescription().toUtf8().getStr(), -1);

    applyStates(pGtkAccessible, xContext);

    applyObjectAttributes(GTK_ACCESSIBLE(ret), xContext);

    applyRelations(ret, xContext);

    // set values from XAccessibleValue interface if that's implemented
    css::uno::Reference<css::accessibility::XAccessibleValue> xAccessibleValue(xContext,
                                                                               css::uno::UNO_QUERY);
    if (xAccessibleValue.is())
    {
        double fCurrentValue = 0, fMinValue = 0, fMaxValue = 0;
        xAccessibleValue->getCurrentValue() >>= fCurrentValue;
        xAccessibleValue->getMinimumValue() >>= fMinValue;
        xAccessibleValue->getMaximumValue() >>= fMaxValue;
        gtk_accessible_update_property(GTK_ACCESSIBLE(ret), GTK_ACCESSIBLE_PROPERTY_VALUE_NOW,
                                       fCurrentValue, GTK_ACCESSIBLE_PROPERTY_VALUE_MIN, fMinValue,
                                       GTK_ACCESSIBLE_PROPERTY_VALUE_MAX, fMaxValue, -1);
    }

    // register event listener
    css::uno::Reference<css::accessibility::XAccessibleEventBroadcaster> xBroadcaster(
        xContext, css::uno::UNO_QUERY);
    if (xBroadcaster.is())
    {
        css::uno::Reference<css::accessibility::XAccessibleEventListener> xListener(
            new GtkAccessibleEventListener(ret));
        xBroadcaster->addAccessibleEventListener(xListener);
    }

    return ret;
}

static gboolean lo_accessible_get_bounds(GtkAccessible* self, int* x, int* y, int* width,
                                         int* height)
{
    LoAccessible* pAccessible = LO_ACCESSIBLE(self);

    if (!pAccessible->uno_accessible)
        return false;

    css::uno::Reference<css::accessibility::XAccessibleContext> xContext(
        pAccessible->uno_accessible->getAccessibleContext());
    css::uno::Reference<css::accessibility::XAccessibleComponent> xAccessibleComponent(
        xContext, css::uno::UNO_QUERY);
    if (!xAccessibleComponent)
        return false;

    css::awt::Rectangle aBounds = xAccessibleComponent->getBounds();
    *x = aBounds.X;
    *y = aBounds.Y;
    *width = aBounds.Width;
    *height = aBounds.Height;
    return true;
}

static GtkAccessible* lo_accessible_get_first_accessible_child(GtkAccessible* self)
{
    LoAccessible* pAccessible = LO_ACCESSIBLE(self);

    if (!pAccessible->uno_accessible)
        return nullptr;

    css::uno::Reference<css::accessibility::XAccessibleContext> xContext(
        pAccessible->uno_accessible->getAccessibleContext());
    if (!xContext->getAccessibleChildCount())
        return nullptr;
    css::uno::Reference<css::accessibility::XAccessible> xFirstChild(
        xContext->getAccessibleChild(0));
    if (!xFirstChild)
        return nullptr;

    LoAccessible* child_accessible
        = GtkAccessibleRegistry::getLOAccessible(xFirstChild, pAccessible->display, self);
    return GTK_ACCESSIBLE(g_object_ref(child_accessible));
}

static GtkAccessible* lo_accessible_get_next_accessible_sibling(GtkAccessible* self)
{
    LoAccessible* pAccessible = LO_ACCESSIBLE(self);

    if (!pAccessible->uno_accessible)
        return nullptr;

    css::uno::Reference<css::accessibility::XAccessibleContext> xContext(
        pAccessible->uno_accessible->getAccessibleContext());
    if (!xContext.is())
    {
        SAL_WARN("vcl.gtk""Accessible has no accessible context");
        return nullptr;
    }

    sal_Int64 nThisChildIndex = xContext->getAccessibleIndexInParent();
    if (nThisChildIndex < 0)
    {
        SAL_WARN("vcl.gtk""Invalid accessible index in parent");
        return nullptr;
    }
    sal_Int64 nNextChildIndex = nThisChildIndex + 1;

    css::uno::Reference<css::accessibility::XAccessible> xParent = xContext->getAccessibleParent();
    css::uno::Reference<css::accessibility::XAccessibleContext> xParentContext(
        xParent->getAccessibleContext());
    if (nNextChildIndex >= xParentContext->getAccessibleChildCount())
        return nullptr;
    css::uno::Reference<css::accessibility::XAccessible> xNextChild(
        xParentContext->getAccessibleChild(nNextChildIndex));
    if (!xNextChild)
        return nullptr;

    LoAccessible* child_accessible = GtkAccessibleRegistry::getLOAccessible(
        xNextChild, pAccessible->display, pAccessible->parent);
    return GTK_ACCESSIBLE(g_object_ref(child_accessible));
}

static gboolean lo_accessible_get_platform_state(GtkAccessible* self,
                                                 GtkAccessiblePlatformState state)
{
    LoAccessible* pAccessible = LO_ACCESSIBLE(self);

    if (!pAccessible->uno_accessible)
        return false;

    css::uno::Reference<css::accessibility::XAccessibleContext> xContext(
        pAccessible->uno_accessible->getAccessibleContext());
    sal_Int64 nStateSet = xContext->getAccessibleStateSet();

    switch (state)
    {
        case GTK_ACCESSIBLE_PLATFORM_STATE_FOCUSABLE:
            return (nStateSet & css::accessibility::AccessibleStateType::FOCUSABLE) != 0;
        case GTK_ACCESSIBLE_PLATFORM_STATE_FOCUSED:
            return (nStateSet & css::accessibility::AccessibleStateType::FOCUSED) != 0;
        case GTK_ACCESSIBLE_PLATFORM_STATE_ACTIVE:
            return (nStateSet & css::accessibility::AccessibleStateType::ACTIVE) != 0;
    }

    return false;
}

static gboolean lo_accessible_range_set_current_value(GtkAccessibleRange* self, double fNewValue)
{
    // return 'true' in any case, since otherwise no proper AT-SPI DBus reply gets sent
    // and the app crashes, s.
    // https://gitlab.gnome.org/GNOME/gtk/-/issues/6150
    // https://gitlab.gnome.org/GNOME/gtk/-/commit/0dbd2bd09eff8c9233e45338a05daf2a835529ab

    LoAccessible* pAccessible = LO_ACCESSIBLE(self);
    if (!pAccessible->uno_accessible)
        return true;

    css::uno::Reference<css::accessibility::XAccessibleContext> xContext(
        pAccessible->uno_accessible->getAccessibleContext());

    css::uno::Reference<css::accessibility::XAccessibleValue> xValue(xContext, css::uno::UNO_QUERY);
    if (!xValue.is())
        return true;

    // Different types of numerical values for XAccessibleValue are possible.
    // If current value has an integer type, also use that for the new value, to make
    // sure underlying implementations expecting that can handle the value properly.
    const css::uno::Any aCurrentValue = xValue->getCurrentValue();
    if (aCurrentValue.getValueTypeClass() == css::uno::TypeClass::TypeClass_LONG)
    {
        const sal_Int32 nValue = std::round<sal_Int32>(fNewValue);
        xValue->setCurrentValue(css::uno::Any(nValue));
        return true;
    }
    else if (aCurrentValue.getValueTypeClass() == css::uno::TypeClass::TypeClass_HYPER)
    {
        const sal_Int64 nValue = std::round<sal_Int64>(fNewValue);
        xValue->setCurrentValue(css::uno::Any(nValue));
        return true;
    }

    css::uno::Any aValue;
    aValue <<= fNewValue;
    xValue->setCurrentValue(aValue);
    return true;
}

static void lo_accessible_init(LoAccessible* /*iface*/) {}

#if 0
gboolean get_platform_state(GtkAccessible* self, GtkAccessiblePlatformState state)
{
    return false;
}
#endif

static gboolean get_bounds(GtkAccessible* accessible, int* x, int* y, int* width, int* height)
{
    OOoFixed* pFixed = OOO_FIXED(accessible);
    css::uno::Reference<css::accessibility::XAccessible> xAccessible(
        get_uno_accessible(GTK_WIDGET(pFixed)));
    css::uno::Reference<css::accessibility::XAccessibleContext> xContext(
        xAccessible->getAccessibleContext());
    css::uno::Reference<css::accessibility::XAccessibleComponent> xAccessibleComponent(
        xContext, css::uno::UNO_QUERY);

    css::awt::Rectangle aBounds = xAccessibleComponent->getBounds();
    *x = aBounds.X;
    *y = aBounds.Y;
    *width = aBounds.Width;
    *height = aBounds.Height;
    return true;
}

static GtkAccessible* get_first_accessible_child(GtkAccessible* accessible)
{
    OOoFixed* pFixed = OOO_FIXED(accessible);
    css::uno::Reference<css::accessibility::XAccessible> xAccessible(
        get_uno_accessible(GTK_WIDGET(pFixed)));
    if (!xAccessible)
        return nullptr;
    css::uno::Reference<css::accessibility::XAccessibleContext> xContext(
        xAccessible->getAccessibleContext());
    if (!xContext->getAccessibleChildCount())
        return nullptr;
    css::uno::Reference<css::accessibility::XAccessible> xFirstChild(
        xContext->getAccessibleChild(0));
    LoAccessible* child_accessible = GtkAccessibleRegistry::getLOAccessible(
        xFirstChild, gtk_widget_get_display(GTK_WIDGET(pFixed)), accessible);
    return GTK_ACCESSIBLE(g_object_ref(child_accessible));
}

static void ooo_fixed_accessible_init(GtkAccessibleInterface* iface)
{
    GtkAccessibleInterface* parent_iface
        = static_cast<GtkAccessibleInterface*>(g_type_interface_peek_parent(iface));
    iface->get_bounds = get_bounds;
    iface->get_first_accessible_child = get_first_accessible_child;
    iface->get_platform_state = parent_iface->get_platform_state;
    //    iface->get_platform_state = get_platform_state;
}

// silence loplugin:unreffun
#ifdef __GNUC__
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wunused-function"
#endif
G_DEFINE_TYPE_WITH_CODE(OOoFixed, ooo_fixed, GTK_TYPE_FIXED,
                        G_IMPLEMENT_INTERFACE(GTK_TYPE_ACCESSIBLE, ooo_fixed_accessible_init))
#ifdef __GNUC__
#pragma GCC diagnostic pop
#endif

static void ooo_fixed_class_init(OOoFixedClass* /*klass*/) {}

static void ooo_fixed_init(OOoFixed* /*area*/) {}

GtkWidget* ooo_fixed_new() { return GTK_WIDGET(g_object_new(OOO_TYPE_FIXED, nullptr)); }

/* vim:set shiftwidth=4 softtabstop=4 expandtab cinoptions=b1,g0,N-s cinkeys+=0=break: */

Messung V0.5
C=96 H=94 G=94

¤ Dauer der Verarbeitung: 0.9 Sekunden  ¤

*© Formatika GbR, Deutschland






Wurzel

Suchen

Beweissystem der NASA

Beweissystem Isabelle

NIST Cobol Testsuite

Cephes Mathematical Library

Wiener Entwicklungsmethode

Haftungshinweis

Die Informationen auf dieser Webseite wurden nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit, noch Qualität der bereit gestellten Informationen zugesichert.

Bemerkung:

Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.