migrating to the latest JUCE version
This commit is contained in:
		@@ -1,111 +1,302 @@
 | 
			
		||||
/*
 | 
			
		||||
  ==============================================================================
 | 
			
		||||
 | 
			
		||||
   This file is part of the JUCE library.
 | 
			
		||||
   Copyright (c) 2020 - Raw Material Software Limited
 | 
			
		||||
 | 
			
		||||
   JUCE is an open source library subject to commercial or open-source
 | 
			
		||||
   licensing.
 | 
			
		||||
 | 
			
		||||
   By using JUCE, you agree to the terms of both the JUCE 6 End-User License
 | 
			
		||||
   Agreement and JUCE Privacy Policy (both effective as of the 16th June 2020).
 | 
			
		||||
 | 
			
		||||
   End User License Agreement: www.juce.com/juce-6-licence
 | 
			
		||||
   Privacy Policy: www.juce.com/juce-privacy-policy
 | 
			
		||||
 | 
			
		||||
   Or: You may also use this code under the terms of the GPL v3 (see
 | 
			
		||||
   www.gnu.org/licenses).
 | 
			
		||||
 | 
			
		||||
   JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
 | 
			
		||||
   EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
 | 
			
		||||
   DISCLAIMED.
 | 
			
		||||
 | 
			
		||||
  ==============================================================================
 | 
			
		||||
*/
 | 
			
		||||
 | 
			
		||||
namespace juce
 | 
			
		||||
{
 | 
			
		||||
 | 
			
		||||
namespace AccessibilityTextHelpers
 | 
			
		||||
{
 | 
			
		||||
    enum class BoundaryType
 | 
			
		||||
    {
 | 
			
		||||
        character,
 | 
			
		||||
        word,
 | 
			
		||||
        line,
 | 
			
		||||
        document
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    enum class Direction
 | 
			
		||||
    {
 | 
			
		||||
        forwards,
 | 
			
		||||
        backwards
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    static int findTextBoundary (const AccessibilityTextInterface& textInterface,
 | 
			
		||||
                                 int currentPosition,
 | 
			
		||||
                                 BoundaryType boundary,
 | 
			
		||||
                                 Direction direction)
 | 
			
		||||
    {
 | 
			
		||||
        const auto numCharacters = textInterface.getTotalNumCharacters();
 | 
			
		||||
        const auto isForwards = (direction == Direction::forwards);
 | 
			
		||||
 | 
			
		||||
        auto offsetWithDirecton = [isForwards] (int input) { return isForwards ? input : -input; };
 | 
			
		||||
 | 
			
		||||
        switch (boundary)
 | 
			
		||||
        {
 | 
			
		||||
            case BoundaryType::character:
 | 
			
		||||
                return jlimit (0, numCharacters, currentPosition + offsetWithDirecton (1));
 | 
			
		||||
 | 
			
		||||
            case BoundaryType::word:
 | 
			
		||||
            case BoundaryType::line:
 | 
			
		||||
            {
 | 
			
		||||
                const auto text = [&]() -> String
 | 
			
		||||
                {
 | 
			
		||||
                    if (isForwards)
 | 
			
		||||
                        return textInterface.getText ({ currentPosition, textInterface.getTotalNumCharacters() });
 | 
			
		||||
 | 
			
		||||
                    const auto str = textInterface.getText ({ 0, currentPosition });
 | 
			
		||||
 | 
			
		||||
                    auto start = str.getCharPointer();
 | 
			
		||||
                    auto end = start.findTerminatingNull();
 | 
			
		||||
                    const auto size = getAddressDifference (end.getAddress(), start.getAddress());
 | 
			
		||||
 | 
			
		||||
                    String reversed;
 | 
			
		||||
 | 
			
		||||
                    if (size > 0)
 | 
			
		||||
                    {
 | 
			
		||||
                        reversed.preallocateBytes ((size_t) size);
 | 
			
		||||
 | 
			
		||||
                        auto destPtr = reversed.getCharPointer();
 | 
			
		||||
 | 
			
		||||
                        for (;;)
 | 
			
		||||
                        {
 | 
			
		||||
                            destPtr.write (*--end);
 | 
			
		||||
 | 
			
		||||
                            if (end == start)
 | 
			
		||||
                                break;
 | 
			
		||||
                        }
 | 
			
		||||
 | 
			
		||||
                        destPtr.writeNull();
 | 
			
		||||
                    }
 | 
			
		||||
 | 
			
		||||
                    return reversed;
 | 
			
		||||
                }();
 | 
			
		||||
 | 
			
		||||
                auto tokens = (boundary == BoundaryType::line ? StringArray::fromLines (text)
 | 
			
		||||
                                                              : StringArray::fromTokens (text, false));
 | 
			
		||||
 | 
			
		||||
                return currentPosition + offsetWithDirecton (tokens[0].length());
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            case BoundaryType::document:
 | 
			
		||||
                return isForwards ? numCharacters : 0;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        jassertfalse;
 | 
			
		||||
        return -1;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
} // namespace juce
 | 
			
		||||
/*
 | 
			
		||||
  ==============================================================================
 | 
			
		||||
 | 
			
		||||
   This file is part of the JUCE library.
 | 
			
		||||
   Copyright (c) 2022 - Raw Material Software Limited
 | 
			
		||||
 | 
			
		||||
   JUCE is an open source library subject to commercial or open-source
 | 
			
		||||
   licensing.
 | 
			
		||||
 | 
			
		||||
   By using JUCE, you agree to the terms of both the JUCE 7 End-User License
 | 
			
		||||
   Agreement and JUCE Privacy Policy.
 | 
			
		||||
 | 
			
		||||
   End User License Agreement: www.juce.com/juce-7-licence
 | 
			
		||||
   Privacy Policy: www.juce.com/juce-privacy-policy
 | 
			
		||||
 | 
			
		||||
   Or: You may also use this code under the terms of the GPL v3 (see
 | 
			
		||||
   www.gnu.org/licenses).
 | 
			
		||||
 | 
			
		||||
   JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
 | 
			
		||||
   EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
 | 
			
		||||
   DISCLAIMED.
 | 
			
		||||
 | 
			
		||||
  ==============================================================================
 | 
			
		||||
*/
 | 
			
		||||
 | 
			
		||||
namespace juce
 | 
			
		||||
{
 | 
			
		||||
 | 
			
		||||
struct AccessibilityTextHelpers
 | 
			
		||||
{
 | 
			
		||||
    /*  Wraps a CharPtr into a stdlib-compatible iterator.
 | 
			
		||||
 | 
			
		||||
        MSVC's std::reverse_iterator requires the wrapped iterator to be default constructible
 | 
			
		||||
        when building in C++20 mode, but I don't really want to add public default constructors to
 | 
			
		||||
        the CharPtr types. Instead, we add a very basic default constructor here which sets the
 | 
			
		||||
        wrapped CharPtr to nullptr.
 | 
			
		||||
    */
 | 
			
		||||
    template <typename CharPtr>
 | 
			
		||||
    class CharPtrIteratorAdapter
 | 
			
		||||
    {
 | 
			
		||||
    public:
 | 
			
		||||
        using difference_type = int;
 | 
			
		||||
        using value_type = decltype (*std::declval<CharPtr>());
 | 
			
		||||
        using pointer = value_type*;
 | 
			
		||||
        using reference = value_type;
 | 
			
		||||
        using iterator_category = std::bidirectional_iterator_tag;
 | 
			
		||||
 | 
			
		||||
        CharPtrIteratorAdapter() = default;
 | 
			
		||||
        constexpr explicit CharPtrIteratorAdapter (CharPtr arg) : ptr (arg) {}
 | 
			
		||||
 | 
			
		||||
        constexpr auto operator*() const { return *ptr; }
 | 
			
		||||
 | 
			
		||||
        constexpr CharPtrIteratorAdapter& operator++()
 | 
			
		||||
        {
 | 
			
		||||
            ++ptr;
 | 
			
		||||
            return *this;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        constexpr CharPtrIteratorAdapter& operator--()
 | 
			
		||||
        {
 | 
			
		||||
            --ptr;
 | 
			
		||||
            return *this;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        constexpr bool operator== (const CharPtrIteratorAdapter& other) const { return ptr == other.ptr; }
 | 
			
		||||
        constexpr bool operator!= (const CharPtrIteratorAdapter& other) const { return ptr != other.ptr; }
 | 
			
		||||
 | 
			
		||||
        constexpr auto operator+ (difference_type offset) const { return CharPtrIteratorAdapter { ptr + offset }; }
 | 
			
		||||
        constexpr auto operator- (difference_type offset) const { return CharPtrIteratorAdapter { ptr - offset }; }
 | 
			
		||||
 | 
			
		||||
    private:
 | 
			
		||||
        CharPtr ptr { {} };
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    template <typename CharPtr>
 | 
			
		||||
    static auto makeCharPtrIteratorAdapter (CharPtr ptr)
 | 
			
		||||
    {
 | 
			
		||||
        return CharPtrIteratorAdapter<CharPtr> { ptr };
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    enum class BoundaryType
 | 
			
		||||
    {
 | 
			
		||||
        character,
 | 
			
		||||
        word,
 | 
			
		||||
        line,
 | 
			
		||||
        document
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    enum class Direction
 | 
			
		||||
    {
 | 
			
		||||
        forwards,
 | 
			
		||||
        backwards
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    enum class ExtendSelection
 | 
			
		||||
    {
 | 
			
		||||
        no,
 | 
			
		||||
        yes
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    /*  Indicates whether a function may return the current text position, in the case that the
 | 
			
		||||
        position already falls on a text unit boundary.
 | 
			
		||||
    */
 | 
			
		||||
    enum class IncludeThisBoundary
 | 
			
		||||
    {
 | 
			
		||||
        no,     //< Always search for the following boundary, even if the current position falls on a boundary
 | 
			
		||||
        yes     //< Return the current position if it falls on a boundary
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    /*  Indicates whether a word boundary should include any whitespaces that follow the
 | 
			
		||||
        non-whitespace characters.
 | 
			
		||||
    */
 | 
			
		||||
    enum class IncludeWhitespaceAfterWords
 | 
			
		||||
    {
 | 
			
		||||
        no,     //< The word ends on the first whitespace character
 | 
			
		||||
        yes     //< The word ends after the last whitespace character
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    /*  Like std::distance, but always does an O(N) count rather than an O(1) count, and doesn't
 | 
			
		||||
        require the iterators to have any member type aliases.
 | 
			
		||||
    */
 | 
			
		||||
    template <typename Iter>
 | 
			
		||||
    static int countDifference (Iter from, Iter to)
 | 
			
		||||
    {
 | 
			
		||||
        int distance = 0;
 | 
			
		||||
 | 
			
		||||
        while (from != to)
 | 
			
		||||
        {
 | 
			
		||||
            ++from;
 | 
			
		||||
            ++distance;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        return distance;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /*  Returns the number of characters between ptr and the next word end in a specific
 | 
			
		||||
        direction.
 | 
			
		||||
 | 
			
		||||
        If ptr is inside a word, the result will be the distance to the end of the same
 | 
			
		||||
        word.
 | 
			
		||||
    */
 | 
			
		||||
    template <typename CharPtr>
 | 
			
		||||
    static int findNextWordEndOffset (CharPtr beginIn,
 | 
			
		||||
                                      CharPtr endIn,
 | 
			
		||||
                                      CharPtr ptrIn,
 | 
			
		||||
                                      Direction direction,
 | 
			
		||||
                                      IncludeThisBoundary includeBoundary,
 | 
			
		||||
                                      IncludeWhitespaceAfterWords includeWhitespace)
 | 
			
		||||
    {
 | 
			
		||||
        const auto begin = makeCharPtrIteratorAdapter (beginIn);
 | 
			
		||||
        const auto end   = makeCharPtrIteratorAdapter (endIn);
 | 
			
		||||
        const auto ptr   = makeCharPtrIteratorAdapter (ptrIn);
 | 
			
		||||
 | 
			
		||||
        const auto move = [&] (auto b, auto e, auto iter)
 | 
			
		||||
        {
 | 
			
		||||
            const auto isSpace = [] (juce_wchar c) { return CharacterFunctions::isWhitespace (c); };
 | 
			
		||||
 | 
			
		||||
            const auto start = [&]
 | 
			
		||||
            {
 | 
			
		||||
                if (iter == b && includeBoundary == IncludeThisBoundary::yes)
 | 
			
		||||
                    return b;
 | 
			
		||||
 | 
			
		||||
                const auto nudged = iter - (iter != b && includeBoundary == IncludeThisBoundary::yes ? 1 : 0);
 | 
			
		||||
 | 
			
		||||
                return includeWhitespace == IncludeWhitespaceAfterWords::yes
 | 
			
		||||
                       ? std::find_if (nudged, e, isSpace)
 | 
			
		||||
                       : std::find_if_not (nudged, e, isSpace);
 | 
			
		||||
            }();
 | 
			
		||||
 | 
			
		||||
            const auto found = includeWhitespace == IncludeWhitespaceAfterWords::yes
 | 
			
		||||
                             ? std::find_if_not (start, e, isSpace)
 | 
			
		||||
                             : std::find_if (start, e, isSpace);
 | 
			
		||||
 | 
			
		||||
            return countDifference (iter, found);
 | 
			
		||||
        };
 | 
			
		||||
 | 
			
		||||
        return direction == Direction::forwards ? move (begin, end, ptr)
 | 
			
		||||
                                                : -move (std::make_reverse_iterator (end),
 | 
			
		||||
                                                         std::make_reverse_iterator (begin),
 | 
			
		||||
                                                         std::make_reverse_iterator (ptr));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /*  Returns the number of characters between ptr and the beginning of the next line in a
 | 
			
		||||
        specific direction.
 | 
			
		||||
    */
 | 
			
		||||
    template <typename CharPtr>
 | 
			
		||||
    static int findNextLineOffset (CharPtr beginIn,
 | 
			
		||||
                                   CharPtr endIn,
 | 
			
		||||
                                   CharPtr ptrIn,
 | 
			
		||||
                                   Direction direction,
 | 
			
		||||
                                   IncludeThisBoundary includeBoundary)
 | 
			
		||||
    {
 | 
			
		||||
        const auto begin = makeCharPtrIteratorAdapter (beginIn);
 | 
			
		||||
        const auto end   = makeCharPtrIteratorAdapter (endIn);
 | 
			
		||||
        const auto ptr   = makeCharPtrIteratorAdapter (ptrIn);
 | 
			
		||||
 | 
			
		||||
        const auto findNewline = [] (auto from, auto to) { return std::find (from, to, juce_wchar { '\n' }); };
 | 
			
		||||
 | 
			
		||||
        if (direction == Direction::forwards)
 | 
			
		||||
        {
 | 
			
		||||
            if (ptr != begin && includeBoundary == IncludeThisBoundary::yes && *(ptr - 1) == '\n')
 | 
			
		||||
                return 0;
 | 
			
		||||
 | 
			
		||||
            const auto newline = findNewline (ptr, end);
 | 
			
		||||
            return countDifference (ptr, newline) + (newline == end ? 0 : 1);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        const auto rbegin   = std::make_reverse_iterator (ptr);
 | 
			
		||||
        const auto rend     = std::make_reverse_iterator (begin);
 | 
			
		||||
 | 
			
		||||
        return -countDifference (rbegin, findNewline (rbegin + (rbegin == rend || includeBoundary == IncludeThisBoundary::yes ? 0 : 1), rend));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /*  Unfortunately, the method of computing end-points of text units depends on context, and on
 | 
			
		||||
        the current platform.
 | 
			
		||||
 | 
			
		||||
        Some examples of different behaviour:
 | 
			
		||||
        - On Android, updating the cursor/selection always searches for the next text unit boundary;
 | 
			
		||||
          but on Windows, ExpandToEnclosingUnit() should not move the starting point of the
 | 
			
		||||
          selection if it already at a unit boundary. This means that we need both inclusive and
 | 
			
		||||
          exclusive methods for finding the next text boundary.
 | 
			
		||||
        - On Android, moving the cursor by 'words' should move to the first space following a
 | 
			
		||||
          non-space character in the requested direction. On Windows, a 'word' includes trailing
 | 
			
		||||
          whitespace, but not preceding whitespace. This means that we need a way of specifying
 | 
			
		||||
          whether whitespace should be included when navigating by words.
 | 
			
		||||
    */
 | 
			
		||||
    static int findTextBoundary (const AccessibilityTextInterface& textInterface,
 | 
			
		||||
                                 int currentPosition,
 | 
			
		||||
                                 BoundaryType boundary,
 | 
			
		||||
                                 Direction direction,
 | 
			
		||||
                                 IncludeThisBoundary includeBoundary,
 | 
			
		||||
                                 IncludeWhitespaceAfterWords includeWhitespace)
 | 
			
		||||
    {
 | 
			
		||||
        const auto numCharacters = textInterface.getTotalNumCharacters();
 | 
			
		||||
        const auto isForwards = (direction == Direction::forwards);
 | 
			
		||||
        const auto currentClamped = jlimit (0, numCharacters, currentPosition);
 | 
			
		||||
 | 
			
		||||
        switch (boundary)
 | 
			
		||||
        {
 | 
			
		||||
            case BoundaryType::character:
 | 
			
		||||
            {
 | 
			
		||||
                const auto offset = includeBoundary == IncludeThisBoundary::yes ? 0
 | 
			
		||||
                                                                                : (isForwards ? 1 : -1);
 | 
			
		||||
                return jlimit (0, numCharacters, currentPosition + offset);
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            case BoundaryType::word:
 | 
			
		||||
            {
 | 
			
		||||
                const auto str = textInterface.getText ({ 0, numCharacters });
 | 
			
		||||
                return currentClamped + findNextWordEndOffset (str.begin(),
 | 
			
		||||
                                                               str.end(),
 | 
			
		||||
                                                               str.begin() + currentClamped,
 | 
			
		||||
                                                               direction,
 | 
			
		||||
                                                               includeBoundary,
 | 
			
		||||
                                                               includeWhitespace);
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            case BoundaryType::line:
 | 
			
		||||
            {
 | 
			
		||||
                const auto str = textInterface.getText ({ 0, numCharacters });
 | 
			
		||||
                return currentClamped + findNextLineOffset (str.begin(),
 | 
			
		||||
                                                            str.end(),
 | 
			
		||||
                                                            str.begin() + currentClamped,
 | 
			
		||||
                                                            direction,
 | 
			
		||||
                                                            includeBoundary);
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            case BoundaryType::document:
 | 
			
		||||
                return isForwards ? numCharacters : 0;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        jassertfalse;
 | 
			
		||||
        return -1;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /*  Adjusts the current text selection range, using an algorithm appropriate for cursor movement
 | 
			
		||||
        on Android.
 | 
			
		||||
    */
 | 
			
		||||
    static Range<int> findNewSelectionRangeAndroid (const AccessibilityTextInterface& textInterface,
 | 
			
		||||
                                                    BoundaryType boundaryType,
 | 
			
		||||
                                                    ExtendSelection extend,
 | 
			
		||||
                                                    Direction direction)
 | 
			
		||||
    {
 | 
			
		||||
        const auto oldPos = textInterface.getTextInsertionOffset();
 | 
			
		||||
        const auto cursorPos = findTextBoundary (textInterface,
 | 
			
		||||
                                                 oldPos,
 | 
			
		||||
                                                 boundaryType,
 | 
			
		||||
                                                 direction,
 | 
			
		||||
                                                 IncludeThisBoundary::no,
 | 
			
		||||
                                                 IncludeWhitespaceAfterWords::no);
 | 
			
		||||
 | 
			
		||||
        if (extend == ExtendSelection::no)
 | 
			
		||||
            return { cursorPos, cursorPos };
 | 
			
		||||
 | 
			
		||||
        const auto currentSelection = textInterface.getSelection();
 | 
			
		||||
        const auto start = currentSelection.getStart();
 | 
			
		||||
        const auto end   = currentSelection.getEnd();
 | 
			
		||||
        return Range<int>::between (cursorPos, oldPos == start ? end : start);
 | 
			
		||||
    }
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
} // namespace juce
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										155
									
								
								deps/juce/modules/juce_gui_basics/native/accessibility/juce_AccessibilityTextHelpers_test.cpp
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										155
									
								
								deps/juce/modules/juce_gui_basics/native/accessibility/juce_AccessibilityTextHelpers_test.cpp
									
									
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,155 @@
 | 
			
		||||
/*
 | 
			
		||||
  ==============================================================================
 | 
			
		||||
 | 
			
		||||
   This file is part of the JUCE library.
 | 
			
		||||
   Copyright (c) 2020 - Raw Material Software Limited
 | 
			
		||||
 | 
			
		||||
   JUCE is an open source library subject to commercial or open-source
 | 
			
		||||
   licensing.
 | 
			
		||||
 | 
			
		||||
   By using JUCE, you agree to the terms of both the JUCE 6 End-User License
 | 
			
		||||
   Agreement and JUCE Privacy Policy (both effective as of the 16th June 2020).
 | 
			
		||||
 | 
			
		||||
   End User License Agreement: www.juce.com/juce-6-licence
 | 
			
		||||
   Privacy Policy: www.juce.com/juce-privacy-policy
 | 
			
		||||
 | 
			
		||||
   Or: You may also use this code under the terms of the GPL v3 (see
 | 
			
		||||
   www.gnu.org/licenses).
 | 
			
		||||
 | 
			
		||||
   JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
 | 
			
		||||
   EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
 | 
			
		||||
   DISCLAIMED.
 | 
			
		||||
 | 
			
		||||
  ==============================================================================
 | 
			
		||||
*/
 | 
			
		||||
 | 
			
		||||
namespace juce
 | 
			
		||||
{
 | 
			
		||||
 | 
			
		||||
struct AccessibilityTextHelpersTest : public UnitTest
 | 
			
		||||
{
 | 
			
		||||
    AccessibilityTextHelpersTest()
 | 
			
		||||
        : UnitTest ("AccessibilityTextHelpers", UnitTestCategories::gui) {}
 | 
			
		||||
 | 
			
		||||
    void runTest() override
 | 
			
		||||
    {
 | 
			
		||||
        using ATH = AccessibilityTextHelpers;
 | 
			
		||||
 | 
			
		||||
        beginTest ("Android find word end");
 | 
			
		||||
        {
 | 
			
		||||
            const auto testMultiple = [this] (String str,
 | 
			
		||||
                                              int start,
 | 
			
		||||
                                              const std::vector<int>& collection)
 | 
			
		||||
            {
 | 
			
		||||
                auto it = collection.begin();
 | 
			
		||||
 | 
			
		||||
                for (const auto direction : { ATH::Direction::forwards, ATH::Direction::backwards })
 | 
			
		||||
                {
 | 
			
		||||
                    for (const auto includeBoundary : { ATH::IncludeThisBoundary::no, ATH::IncludeThisBoundary::yes })
 | 
			
		||||
                    {
 | 
			
		||||
                        for (const auto includeWhitespace : { ATH::IncludeWhitespaceAfterWords::no, ATH::IncludeWhitespaceAfterWords::yes })
 | 
			
		||||
                        {
 | 
			
		||||
                            const auto actual = ATH::findNextWordEndOffset (str.begin(), str.end(), str.begin() + start, direction, includeBoundary, includeWhitespace);
 | 
			
		||||
                            const auto expected = *it++;
 | 
			
		||||
                            expect (expected == actual);
 | 
			
		||||
                        }
 | 
			
		||||
                    }
 | 
			
		||||
                }
 | 
			
		||||
            };
 | 
			
		||||
 | 
			
		||||
            // Character Indices         0  3 56       13                                                                    50          51
 | 
			
		||||
            //                           |  | ||       |                                                                     |           |
 | 
			
		||||
            const auto string = String ("hello world \r\n with some  spaces in this sentence ") + String (CharPointer_UTF8 ("\xe2\x88\xae E\xe2\x8b\x85""da = Q"));
 | 
			
		||||
            // Direction                 forwards    forwards    forwards    forwards    backwards   backwards   backwards   backwards
 | 
			
		||||
            // IncludeBoundary           no          no          yes         yes         no          no          yes         yes
 | 
			
		||||
            // IncludeWhitespace         no          yes         no          yes         no          yes         no          yes
 | 
			
		||||
            testMultiple (string,   0, { 5,          6,          5,          0,           0,          0,          0,          0 });
 | 
			
		||||
            testMultiple (string,   3, { 2,          3,          2,          3,          -3,         -3,         -3,         -3 });
 | 
			
		||||
            testMultiple (string,   5, { 6,          1,          0,          1,          -5,         -5,         -5,          0 });
 | 
			
		||||
            testMultiple (string,   6, { 5,          9,          5,          0,          -6,         -1,          0,         -1 });
 | 
			
		||||
            testMultiple (string,  13, { 6,          2,          6,          2,          -7,         -2,         -7,         -2 });
 | 
			
		||||
            testMultiple (string,  50, { 1,          2,          1,          0,          -9,         -1,          0,         -1 });
 | 
			
		||||
            testMultiple (string,  51, { 5,          1,          0,          1,          -1,         -2,         -1,          0 });
 | 
			
		||||
 | 
			
		||||
            testMultiple ("  a b ", 0, { 3,          2,          0,          2,           0,          0,          0,          0 });
 | 
			
		||||
            testMultiple ("  a b ", 1, { 2,          1,          2,          1,          -1,         -1,         -1,         -1 });
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        beginTest ("Android text range adjustment");
 | 
			
		||||
        {
 | 
			
		||||
            const auto testMultiple = [this] (String str,
 | 
			
		||||
                                              Range<int> initial,
 | 
			
		||||
                                              auto boundary,
 | 
			
		||||
                                              const std::vector<Range<int>>& collection)
 | 
			
		||||
            {
 | 
			
		||||
                auto it = collection.begin();
 | 
			
		||||
 | 
			
		||||
                for (auto extend : { ATH::ExtendSelection::no, ATH::ExtendSelection::yes })
 | 
			
		||||
                {
 | 
			
		||||
                    for (auto direction : { ATH::Direction::forwards, ATH::Direction::backwards })
 | 
			
		||||
                    {
 | 
			
		||||
                        for (auto insert : { CursorPosition::begin, CursorPosition::end })
 | 
			
		||||
                        {
 | 
			
		||||
                            const MockAccessibilityTextInterface mock { str, initial, insert };
 | 
			
		||||
                            const auto actual = ATH::findNewSelectionRangeAndroid (mock, boundary, extend, direction);
 | 
			
		||||
                            const auto expected = *it++;
 | 
			
		||||
                            expect (expected == actual);
 | 
			
		||||
                        }
 | 
			
		||||
                    }
 | 
			
		||||
                }
 | 
			
		||||
            };
 | 
			
		||||
 | 
			
		||||
            // Extend                                                                       no              no              no              no              yes             yes             yes             yes
 | 
			
		||||
            // Direction                                                                    forwards        forwards        backwards       backwards       forwards        forwards        backwards       backwards
 | 
			
		||||
            // Insert                                                                       begin           end             begin           end             begin           end             begin           end
 | 
			
		||||
            testMultiple ("hello world", {  5,  5 }, ATH::BoundaryType::character,        { { 6,  6 },      { 6, 6 },       { 4, 4 },       { 4, 4 },       { 5, 6 },       { 5, 6 },       { 4, 5 },       { 4, 5 } });
 | 
			
		||||
            testMultiple ("hello world", {  0,  0 }, ATH::BoundaryType::character,        { { 1, 1 },       { 1, 1 },       { 0, 0 },       { 0, 0 },       { 0, 1 },       { 0, 1 },       { 0, 0 },       { 0, 0 } });
 | 
			
		||||
            testMultiple ("hello world", { 11, 11 }, ATH::BoundaryType::character,        { { 11, 11 },     { 11, 11 },     { 10, 10 },     { 10, 10 },     { 11, 11 },     { 11, 11 },     { 10, 11 },     { 10, 11 } });
 | 
			
		||||
            testMultiple ("hello world", {  4,  5 }, ATH::BoundaryType::character,        { { 5, 5 },       { 6, 6 },       { 3, 3 },       { 4, 4 },       { 5, 5 },       { 4, 6 },       { 3, 5 },       { 4, 4 } });
 | 
			
		||||
            testMultiple ("hello world", {  0,  1 }, ATH::BoundaryType::character,        { { 1, 1 },       { 2, 2 },       { 0, 0 },       { 0, 0 },       { 1, 1 },       { 0, 2 },       { 0, 1 },       { 0, 0 } });
 | 
			
		||||
            testMultiple ("hello world", { 10, 11 }, ATH::BoundaryType::character,        { { 11, 11 },     { 11, 11 },     { 9, 9 },       { 10, 10 },     { 11, 11 },     { 10, 11 },     { 9, 11 },      { 10, 10 } });
 | 
			
		||||
 | 
			
		||||
            testMultiple ("foo  bar  baz", { 0, 0 }, ATH::BoundaryType::word,             { { 3, 3 },       { 3, 3 },       { 0, 0 },       { 0, 0 },       { 0, 3 },       { 0, 3 },       { 0, 0 },       { 0, 0 } });
 | 
			
		||||
            testMultiple ("foo  bar  baz", { 1, 6 }, ATH::BoundaryType::word,             { { 3, 3 },       { 8, 8 },       { 0, 0 },       { 5, 5 },       { 3, 6 },       { 1, 8 },       { 0, 6 },       { 1, 5 } });
 | 
			
		||||
            testMultiple ("foo  bar  baz", { 3, 3 }, ATH::BoundaryType::word,             { { 8, 8 },       { 8, 8 },       { 0, 0 },       { 0, 0 },       { 3, 8 },       { 3, 8 },       { 0, 3 },       { 0, 3 } });
 | 
			
		||||
            testMultiple ("foo  bar  baz", { 3, 5 }, ATH::BoundaryType::word,             { { 8, 8 },       { 8, 8 },       { 0, 0 },       { 0, 0 },       { 5, 8 },       { 3, 8 },       { 0, 5 },       { 0, 3 } });
 | 
			
		||||
 | 
			
		||||
            testMultiple ("foo bar\n\n\na b\nc d e", { 0, 0 }, ATH::BoundaryType::line,   { { 8, 8 },       { 8, 8 },       { 0, 0 },       { 0, 0 },       { 0, 8 },       { 0, 8 },       { 0, 0 },       { 0, 0 } });
 | 
			
		||||
            testMultiple ("foo bar\n\n\na b\nc d e", { 7, 7 }, ATH::BoundaryType::line,   { { 8, 8 },       { 8, 8 },       { 0, 0 },       { 0, 0 },       { 7, 8 },       { 7, 8 },       { 0, 7 },       { 0, 7 } });
 | 
			
		||||
            testMultiple ("foo bar\n\n\na b\nc d e", { 8, 8 }, ATH::BoundaryType::line,   { { 9, 9 },       { 9, 9 },       { 0, 0 },       { 0, 0 },       { 8, 9 },       { 8, 9 },       { 0, 8 },       { 0, 8 } });
 | 
			
		||||
 | 
			
		||||
            testMultiple ("foo bar\r\na b\r\nxyz", {  0,  0 }, ATH::BoundaryType::line,   { { 9, 9 },       { 9, 9 },       { 0, 0 },       { 0, 0 },       { 0, 9 },       { 0, 9 },       { 0, 0 },       { 0, 0 } });
 | 
			
		||||
            testMultiple ("foo bar\r\na b\r\nxyz", { 10, 10 }, ATH::BoundaryType::line,   { { 14, 14 },     { 14, 14 },     { 9, 9 },       { 9, 9 },       { 10, 14 },     { 10, 14 },     { 9, 10 },      { 9, 10 } });
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    enum class CursorPosition { begin, end };
 | 
			
		||||
 | 
			
		||||
    class MockAccessibilityTextInterface : public AccessibilityTextInterface
 | 
			
		||||
    {
 | 
			
		||||
    public:
 | 
			
		||||
        MockAccessibilityTextInterface (String stringIn, Range<int> selectionIn, CursorPosition insertIn)
 | 
			
		||||
            : string (stringIn), selection (selectionIn), insert (insertIn) {}
 | 
			
		||||
 | 
			
		||||
        bool isDisplayingProtectedText()                  const override { return false; }
 | 
			
		||||
        bool isReadOnly()                                 const override { return false; }
 | 
			
		||||
        int getTotalNumCharacters()                       const override { return string.length(); }
 | 
			
		||||
        Range<int> getSelection()                         const override { return selection; }
 | 
			
		||||
        int getTextInsertionOffset()                      const override { return insert == CursorPosition::begin ? selection.getStart() : selection.getEnd(); }
 | 
			
		||||
        String getText (Range<int> range)                 const override { return string.substring (range.getStart(), range.getEnd()); }
 | 
			
		||||
        RectangleList<int> getTextBounds (Range<int>)     const override { return {}; }
 | 
			
		||||
        int getOffsetAtPoint (Point<int>)                 const override { return 0; }
 | 
			
		||||
 | 
			
		||||
        void setSelection (Range<int> newRange)                 override { selection = newRange; }
 | 
			
		||||
        void setText (const String& newText)                    override { string = newText; }
 | 
			
		||||
 | 
			
		||||
    private:
 | 
			
		||||
        String string;
 | 
			
		||||
        Range<int> selection;
 | 
			
		||||
        CursorPosition insert;
 | 
			
		||||
    };
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
static AccessibilityTextHelpersTest accessibilityTextHelpersTest;
 | 
			
		||||
 | 
			
		||||
} // namespace juce
 | 
			
		||||
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							@@ -2,15 +2,15 @@
 | 
			
		||||
  ==============================================================================
 | 
			
		||||
 | 
			
		||||
   This file is part of the JUCE library.
 | 
			
		||||
   Copyright (c) 2020 - Raw Material Software Limited
 | 
			
		||||
   Copyright (c) 2022 - Raw Material Software Limited
 | 
			
		||||
 | 
			
		||||
   JUCE is an open source library subject to commercial or open-source
 | 
			
		||||
   licensing.
 | 
			
		||||
 | 
			
		||||
   By using JUCE, you agree to the terms of both the JUCE 6 End-User License
 | 
			
		||||
   Agreement and JUCE Privacy Policy (both effective as of the 16th June 2020).
 | 
			
		||||
   By using JUCE, you agree to the terms of both the JUCE 7 End-User License
 | 
			
		||||
   Agreement and JUCE Privacy Policy.
 | 
			
		||||
 | 
			
		||||
   End User License Agreement: www.juce.com/juce-6-licence
 | 
			
		||||
   End User License Agreement: www.juce.com/juce-7-licence
 | 
			
		||||
   Privacy Policy: www.juce.com/juce-privacy-policy
 | 
			
		||||
 | 
			
		||||
   Or: You may also use this code under the terms of the GPL v3 (see
 | 
			
		||||
@@ -37,60 +37,47 @@ static void juceFreeAccessibilityPlatformSpecificData (UIAccessibilityElement* e
 | 
			
		||||
namespace juce
 | 
			
		||||
{
 | 
			
		||||
 | 
			
		||||
#if (defined (__IPHONE_11_0) && __IPHONE_OS_VERSION_MIN_REQUIRED >= __IPHONE_11_0)
 | 
			
		||||
 #define JUCE_IOS_CONTAINER_API_AVAILABLE 1
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
constexpr auto juceUIAccessibilityContainerTypeNone =
 | 
			
		||||
                   #if JUCE_IOS_CONTAINER_API_AVAILABLE
 | 
			
		||||
                    UIAccessibilityContainerTypeNone;
 | 
			
		||||
                   #else
 | 
			
		||||
                    0;
 | 
			
		||||
                   #endif
 | 
			
		||||
 | 
			
		||||
constexpr auto juceUIAccessibilityContainerTypeDataTable =
 | 
			
		||||
                   #if JUCE_IOS_CONTAINER_API_AVAILABLE
 | 
			
		||||
                    UIAccessibilityContainerTypeDataTable;
 | 
			
		||||
                   #else
 | 
			
		||||
                    1;
 | 
			
		||||
                   #endif
 | 
			
		||||
 | 
			
		||||
constexpr auto juceUIAccessibilityContainerTypeList =
 | 
			
		||||
                   #if JUCE_IOS_CONTAINER_API_AVAILABLE
 | 
			
		||||
                    UIAccessibilityContainerTypeList;
 | 
			
		||||
                   #else
 | 
			
		||||
                    2;
 | 
			
		||||
                   #endif
 | 
			
		||||
 | 
			
		||||
#define JUCE_NATIVE_ACCESSIBILITY_INCLUDED 1
 | 
			
		||||
 | 
			
		||||
//==============================================================================
 | 
			
		||||
static NSArray* getContainerAccessibilityElements (AccessibilityHandler& handler)
 | 
			
		||||
{
 | 
			
		||||
    const auto children = handler.getChildren();
 | 
			
		||||
template <typename> struct Signature;
 | 
			
		||||
 | 
			
		||||
    NSMutableArray* accessibleChildren = [NSMutableArray arrayWithCapacity: (NSUInteger) children.size()];
 | 
			
		||||
template <typename Result, typename... Args>
 | 
			
		||||
struct Signature<Result (Args...)> {};
 | 
			
		||||
 | 
			
		||||
    [accessibleChildren addObject: (id) handler.getNativeImplementation()];
 | 
			
		||||
 | 
			
		||||
    for (auto* childHandler : children)
 | 
			
		||||
    {
 | 
			
		||||
        id accessibleElement = [&childHandler]
 | 
			
		||||
        {
 | 
			
		||||
            id native = (id) childHandler->getNativeImplementation();
 | 
			
		||||
 | 
			
		||||
            if (childHandler->getChildren().size() > 0)
 | 
			
		||||
                return [native accessibilityContainer];
 | 
			
		||||
 | 
			
		||||
            return native;
 | 
			
		||||
        }();
 | 
			
		||||
 | 
			
		||||
        if (accessibleElement != nil)
 | 
			
		||||
            [accessibleChildren addObject: accessibleElement];
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    return accessibleChildren;
 | 
			
		||||
}
 | 
			
		||||
// @selector isn't constexpr, so the 'sel' members are functions rather than static constexpr data members
 | 
			
		||||
struct SignatureHasText                         : Signature<BOOL()>                                                              { static auto sel() { return @selector (hasText); } };
 | 
			
		||||
struct SignatureSetSelectedTextRange            : Signature<void (UITextRange*)>                                                 { static auto sel() { return @selector (setSelectedTextRange:); } };
 | 
			
		||||
struct SignatureSelectedTextRange               : Signature<UITextRange*()>                                                      { static auto sel() { return @selector (selectedTextRange); } };
 | 
			
		||||
struct SignatureMarkedTextRange                 : Signature<UITextRange*()>                                                      { static auto sel() { return @selector (markedTextRange); } };
 | 
			
		||||
struct SignatureSetMarkedTextSelectedRange      : Signature<void (NSString*, NSRange)>                                           { static auto sel() { return @selector (setMarkedText:selectedRange:); } };
 | 
			
		||||
struct SignatureUnmarkText                      : Signature<void()>                                                              { static auto sel() { return @selector (unmarkText); } };
 | 
			
		||||
struct SignatureMarkedTextStyle                 : Signature<NSDictionary<NSAttributedStringKey, id>*()>                          { static auto sel() { return @selector (markedTextStyle); } };
 | 
			
		||||
struct SignatureSetMarkedTextStyle              : Signature<void (NSDictionary<NSAttributedStringKey, id>*)>                     { static auto sel() { return @selector (setMarkedTextStyle:); } };
 | 
			
		||||
struct SignatureBeginningOfDocument             : Signature<UITextPosition*()>                                                   { static auto sel() { return @selector (beginningOfDocument); } };
 | 
			
		||||
struct SignatureEndOfDocument                   : Signature<UITextPosition*()>                                                   { static auto sel() { return @selector (endOfDocument); } };
 | 
			
		||||
struct SignatureTokenizer                       : Signature<id<UITextInputTokenizer>()>                                          { static auto sel() { return @selector (tokenizer); } };
 | 
			
		||||
struct SignatureBaseWritingDirection            : Signature<NSWritingDirection (UITextPosition*, UITextStorageDirection)>        { static auto sel() { return @selector (baseWritingDirectionForPosition:inDirection:); } };
 | 
			
		||||
struct SignatureCaretRectForPosition            : Signature<CGRect (UITextPosition*)>                                            { static auto sel() { return @selector (caretRectForPosition:); } };
 | 
			
		||||
struct SignatureCharacterRangeByExtending       : Signature<UITextRange* (UITextPosition*, UITextLayoutDirection)>               { static auto sel() { return @selector (characterRangeByExtendingPosition:inDirection:); } };
 | 
			
		||||
struct SignatureCharacterRangeAtPoint           : Signature<UITextRange* (CGPoint)>                                              { static auto sel() { return @selector (characterRangeAtPoint:); } };
 | 
			
		||||
struct SignatureClosestPositionToPoint          : Signature<UITextPosition* (CGPoint)>                                           { static auto sel() { return @selector (closestPositionToPoint:); } };
 | 
			
		||||
struct SignatureClosestPositionToPointInRange   : Signature<UITextPosition* (CGPoint, UITextRange*)>                             { static auto sel() { return @selector (closestPositionToPoint:withinRange:); } };
 | 
			
		||||
struct SignatureComparePositionToPosition       : Signature<NSComparisonResult (UITextPosition*, UITextPosition*)>               { static auto sel() { return @selector (comparePosition:toPosition:); } };
 | 
			
		||||
struct SignatureOffsetFromPositionToPosition    : Signature<NSInteger (UITextPosition*, UITextPosition*)>                        { static auto sel() { return @selector (offsetFromPosition:toPosition:); } };
 | 
			
		||||
struct SignaturePositionFromPositionInDirection : Signature<UITextPosition* (UITextPosition*, UITextLayoutDirection, NSInteger)> { static auto sel() { return @selector (positionFromPosition:inDirection:offset:); } };
 | 
			
		||||
struct SignaturePositionFromPositionOffset      : Signature<UITextPosition* (UITextPosition*, NSInteger)>                        { static auto sel() { return @selector (positionFromPosition:offset:); } };
 | 
			
		||||
struct SignatureFirstRectForRange               : Signature<CGRect (UITextRange*)>                                               { static auto sel() { return @selector (firstRectForRange:); } };
 | 
			
		||||
struct SignatureSelectionRectsForRange          : Signature<NSArray<UITextSelectionRect*>* (UITextRange*)>                       { static auto sel() { return @selector (selectionRectsForRange:); } };
 | 
			
		||||
struct SignaturePositionWithinRange             : Signature<UITextPosition* (UITextRange*, UITextLayoutDirection)>               { static auto sel() { return @selector (positionWithinRange:farthestInDirection:); } };
 | 
			
		||||
struct SignatureReplaceRangeWithText            : Signature<void (UITextRange*, NSString*)>                                      { static auto sel() { return @selector (replaceRange:withText:); } };
 | 
			
		||||
struct SignatureSetBaseWritingDirection         : Signature<void (NSWritingDirection, UITextRange*)>                             { static auto sel() { return @selector (setBaseWritingDirection:forRange:); } };
 | 
			
		||||
struct SignatureTextInRange                     : Signature<NSString* (UITextRange*)>                                            { static auto sel() { return @selector (textInRange:); } };
 | 
			
		||||
struct SignatureTextRangeFromPosition           : Signature<UITextRange* (UITextPosition*, UITextPosition*)>                     { static auto sel() { return @selector (textRangeFromPosition:toPosition:); } };
 | 
			
		||||
struct SignatureSetInputDelegate                : Signature<void (id)>                                                           { static auto sel() { return @selector (setInputDelegate:); } };
 | 
			
		||||
struct SignatureInputDelegate                   : Signature<id()>                                                                { static auto sel() { return @selector (inputDelegate); } };
 | 
			
		||||
struct SignatureKeyboardType                    : Signature<UIKeyboardType()>                                                    { static auto sel() { return @selector (keyboardType); } };
 | 
			
		||||
struct SignatureAutocapitalizationType          : Signature<UITextAutocapitalizationType()>                                      { static auto sel() { return @selector (autocapitalizationType); } };
 | 
			
		||||
struct SignatureAutocorrectionType              : Signature<UITextAutocorrectionType()>                                          { static auto sel() { return @selector (autocorrectionType); } };
 | 
			
		||||
 | 
			
		||||
//==============================================================================
 | 
			
		||||
class AccessibilityHandler::AccessibilityNativeImpl
 | 
			
		||||
@@ -108,73 +95,131 @@ public:
 | 
			
		||||
 | 
			
		||||
private:
 | 
			
		||||
    //==============================================================================
 | 
			
		||||
    class AccessibilityContainer  : public ObjCClass<UIAccessibilityElement>
 | 
			
		||||
    class AccessibilityContainer  : public AccessibleObjCClass<NSObject>
 | 
			
		||||
    {
 | 
			
		||||
    public:
 | 
			
		||||
        AccessibilityContainer()
 | 
			
		||||
            : ObjCClass ("JUCEUIAccessibilityElementContainer_")
 | 
			
		||||
            : AccessibleObjCClass ("JUCEUIAccessibilityContainer_")
 | 
			
		||||
        {
 | 
			
		||||
            addMethod (@selector (isAccessibilityElement),     getIsAccessibilityElement,     "c@:");
 | 
			
		||||
            addMethod (@selector (accessibilityFrame),         getAccessibilityFrame,         @encode (CGRect), "@:");
 | 
			
		||||
            addMethod (@selector (accessibilityElements),      getAccessibilityElements,      "@@:");
 | 
			
		||||
            addMethod (@selector (accessibilityContainerType), getAccessibilityContainerType, "i@:");
 | 
			
		||||
            addMethod (@selector (isAccessibilityElement), [] (id, SEL) { return false; });
 | 
			
		||||
 | 
			
		||||
            addIvar<AccessibilityHandler*> ("handler");
 | 
			
		||||
            addMethod (@selector (accessibilityFrame), [] (id self, SEL)
 | 
			
		||||
            {
 | 
			
		||||
                if (auto* handler = getHandler (self))
 | 
			
		||||
                    return convertToCGRect (handler->getComponent().getScreenBounds());
 | 
			
		||||
 | 
			
		||||
                return CGRectZero;
 | 
			
		||||
            });
 | 
			
		||||
 | 
			
		||||
            addMethod (@selector (accessibilityElements), [] (id self, SEL) -> NSArray*
 | 
			
		||||
            {
 | 
			
		||||
                if (auto* handler = getHandler (self))
 | 
			
		||||
                    return getContainerAccessibilityElements (*handler);
 | 
			
		||||
 | 
			
		||||
                return nil;
 | 
			
		||||
            });
 | 
			
		||||
 | 
			
		||||
            if (@available (iOS 11.0, *))
 | 
			
		||||
            {
 | 
			
		||||
                addMethod (@selector (accessibilityDataTableCellElementForRow:column:), [] (id self, SEL, NSUInteger row, NSUInteger column) -> id
 | 
			
		||||
                {
 | 
			
		||||
                    if (auto* tableHandler = getEnclosingHandlerWithInterface (getHandler (self), &AccessibilityHandler::getTableInterface))
 | 
			
		||||
                        if (auto* tableInterface = tableHandler->getTableInterface())
 | 
			
		||||
                            if (auto* cellHandler = tableInterface->getCellHandler ((int) row, (int) column))
 | 
			
		||||
                                if (auto* parent = getAccessibleParent (cellHandler))
 | 
			
		||||
                                    return static_cast<id> (parent->getNativeImplementation());
 | 
			
		||||
 | 
			
		||||
                    return nil;
 | 
			
		||||
                });
 | 
			
		||||
 | 
			
		||||
                addMethod (@selector (accessibilityRowCount),                           getAccessibilityRowCount);
 | 
			
		||||
                addMethod (@selector (accessibilityColumnCount),                        getAccessibilityColumnCount);
 | 
			
		||||
 | 
			
		||||
                addMethod (@selector (accessibilityHeaderElementsForColumn:), [] (id self, SEL, NSUInteger column) -> NSArray*
 | 
			
		||||
                {
 | 
			
		||||
                    if (auto* tableHandler = getEnclosingHandlerWithInterface (getHandler (self), &AccessibilityHandler::getTableInterface))
 | 
			
		||||
                    {
 | 
			
		||||
                        if (auto* tableInterface = tableHandler->getTableInterface())
 | 
			
		||||
                        {
 | 
			
		||||
                            if (auto* header = tableInterface->getHeaderHandler())
 | 
			
		||||
                            {
 | 
			
		||||
                                if (isPositiveAndBelow (column, header->getChildren().size()))
 | 
			
		||||
                                {
 | 
			
		||||
                                    auto* result = [NSMutableArray new];
 | 
			
		||||
                                    [result addObject: static_cast<id> (header->getChildren()[(size_t) column]->getNativeImplementation())];
 | 
			
		||||
                                    return result;
 | 
			
		||||
                                }
 | 
			
		||||
                            }
 | 
			
		||||
                        }
 | 
			
		||||
                    }
 | 
			
		||||
 | 
			
		||||
                    return nullptr;
 | 
			
		||||
                });
 | 
			
		||||
 | 
			
		||||
                addProtocol (@protocol (UIAccessibilityContainerDataTable));
 | 
			
		||||
 | 
			
		||||
                addMethod (@selector (accessibilityContainerType), [] (id self, SEL) -> NSInteger
 | 
			
		||||
                {
 | 
			
		||||
                    if (auto* handler = getHandler (self))
 | 
			
		||||
                    {
 | 
			
		||||
                        if (handler->getTableInterface() != nullptr)
 | 
			
		||||
                        {
 | 
			
		||||
                            if (@available (iOS 11.0, *))
 | 
			
		||||
                                return UIAccessibilityContainerTypeDataTable;
 | 
			
		||||
 | 
			
		||||
                            return 1; // UIAccessibilityContainerTypeDataTable
 | 
			
		||||
                        }
 | 
			
		||||
 | 
			
		||||
                        const auto handlerRole = handler->getRole();
 | 
			
		||||
 | 
			
		||||
                        if (handlerRole == AccessibilityRole::popupMenu
 | 
			
		||||
                            || handlerRole == AccessibilityRole::list
 | 
			
		||||
                            || handlerRole == AccessibilityRole::tree)
 | 
			
		||||
                        {
 | 
			
		||||
                            if (@available (iOS 11.0, *))
 | 
			
		||||
                                return UIAccessibilityContainerTypeList;
 | 
			
		||||
 | 
			
		||||
                            return 2; // UIAccessibilityContainerTypeList
 | 
			
		||||
                        }
 | 
			
		||||
                    }
 | 
			
		||||
 | 
			
		||||
                    if (@available (iOS 11.0, *))
 | 
			
		||||
                        return UIAccessibilityContainerTypeNone;
 | 
			
		||||
 | 
			
		||||
                    return 0; // UIAccessibilityContainerTypeNone
 | 
			
		||||
                });
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            registerClass();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
    private:
 | 
			
		||||
        static const AccessibilityHandler* getAccessibleParent (const AccessibilityHandler* h)
 | 
			
		||||
        {
 | 
			
		||||
            if (h == nullptr)
 | 
			
		||||
                return nullptr;
 | 
			
		||||
 | 
			
		||||
            if ([static_cast<id> (h->getNativeImplementation()) isAccessibilityElement])
 | 
			
		||||
                return h;
 | 
			
		||||
 | 
			
		||||
            return getAccessibleParent (h->getParent());
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        static AccessibilityHandler* getHandler (id self)
 | 
			
		||||
        {
 | 
			
		||||
            return getIvar<AccessibilityHandler*> (self, "handler");
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        static BOOL getIsAccessibilityElement (id, SEL)
 | 
			
		||||
        {
 | 
			
		||||
            return NO;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        static CGRect getAccessibilityFrame (id self, SEL)
 | 
			
		||||
        {
 | 
			
		||||
            if (auto* handler = getHandler (self))
 | 
			
		||||
                return convertToCGRect (handler->getComponent().getScreenBounds());
 | 
			
		||||
 | 
			
		||||
            return CGRectZero;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        static NSArray* getAccessibilityElements (id self, SEL)
 | 
			
		||||
        {
 | 
			
		||||
            if (auto* handler = getHandler (self))
 | 
			
		||||
                return getContainerAccessibilityElements (*handler);
 | 
			
		||||
 | 
			
		||||
            return nil;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        static NSInteger getAccessibilityContainerType (id self, SEL)
 | 
			
		||||
        {
 | 
			
		||||
            if (auto* handler = getHandler (self))
 | 
			
		||||
            {
 | 
			
		||||
                if (handler->getTableInterface() != nullptr)
 | 
			
		||||
                    return juceUIAccessibilityContainerTypeDataTable;
 | 
			
		||||
 | 
			
		||||
                const auto role = handler->getRole();
 | 
			
		||||
 | 
			
		||||
                if (role == AccessibilityRole::popupMenu
 | 
			
		||||
                    || role == AccessibilityRole::list
 | 
			
		||||
                    || role == AccessibilityRole::tree)
 | 
			
		||||
                {
 | 
			
		||||
                    return juceUIAccessibilityContainerTypeList;
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            return juceUIAccessibilityContainerTypeNone;
 | 
			
		||||
        }
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    //==============================================================================
 | 
			
		||||
    class AccessibilityElement  : public AccessibleObjCClass<UIAccessibilityElement>
 | 
			
		||||
    {
 | 
			
		||||
        template <typename Func, typename... Items>
 | 
			
		||||
        static constexpr void forEach (Func&& func, Items&&... items)
 | 
			
		||||
        {
 | 
			
		||||
            (void) std::initializer_list<int> { ((void) func (std::forward<Items> (items)), 0)... };
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
    public:
 | 
			
		||||
        enum class Type  { defaultElement, textElement };
 | 
			
		||||
 | 
			
		||||
@@ -185,49 +230,282 @@ private:
 | 
			
		||||
 | 
			
		||||
            id instance = (hasEditableText (handler) ? textCls : cls).createInstance();
 | 
			
		||||
 | 
			
		||||
            Holder element ([instance initWithAccessibilityContainer: (id) handler.getComponent().getWindowHandle()]);
 | 
			
		||||
            Holder element ([instance initWithAccessibilityContainer: static_cast<id> (handler.getComponent().getWindowHandle())]);
 | 
			
		||||
            object_setInstanceVariable (element.get(), "handler", &handler);
 | 
			
		||||
            return element;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        AccessibilityElement (Type elementType)
 | 
			
		||||
        {
 | 
			
		||||
            addMethod (@selector (isAccessibilityElement),     getIsAccessibilityElement,     "c@:");
 | 
			
		||||
            addMethod (@selector (accessibilityContainer),     getAccessibilityContainer,     "@@:");
 | 
			
		||||
            addMethod (@selector (accessibilityFrame),         getAccessibilityFrame,         @encode (CGRect), "@:");
 | 
			
		||||
            addMethod (@selector (accessibilityTraits),        getAccessibilityTraits,        "i@:");
 | 
			
		||||
            addMethod (@selector (accessibilityLabel),         getAccessibilityTitle,         "@@:");
 | 
			
		||||
            addMethod (@selector (accessibilityHint),          getAccessibilityHelp,          "@@:");
 | 
			
		||||
            addMethod (@selector (accessibilityValue),         getAccessibilityValue,         "@@:");
 | 
			
		||||
            addMethod (@selector (setAccessibilityValue:),     setAccessibilityValue,         "v@:@");
 | 
			
		||||
            addMethod (@selector (isAccessibilityElement), [] (id self, SEL)
 | 
			
		||||
            {
 | 
			
		||||
                auto* handler = getHandler (self);
 | 
			
		||||
 | 
			
		||||
            addMethod (@selector (accessibilityElementDidBecomeFocused), onFocusGain, "v@:");
 | 
			
		||||
            addMethod (@selector (accessibilityElementDidLoseFocus),     onFocusLoss, "v@:");
 | 
			
		||||
            addMethod (@selector (accessibilityElementIsFocused),        isFocused,   "c@:");
 | 
			
		||||
            addMethod (@selector (accessibilityViewIsModal),             getIsAccessibilityModal, "c@:");
 | 
			
		||||
                const auto hasAccessiblePropertiesOrIsTableCell = [] (auto& handlerRef)
 | 
			
		||||
                {
 | 
			
		||||
                    const auto isTableCell = [&]
 | 
			
		||||
                    {
 | 
			
		||||
                        if (auto* tableHandler = getEnclosingHandlerWithInterface (&handlerRef, &AccessibilityHandler::getTableInterface))
 | 
			
		||||
                        {
 | 
			
		||||
                            if (auto* tableInterface = tableHandler->getTableInterface())
 | 
			
		||||
                            {
 | 
			
		||||
                                return tableInterface->getRowSpan    (handlerRef).hasValue()
 | 
			
		||||
                                    && tableInterface->getColumnSpan (handlerRef).hasValue();
 | 
			
		||||
                            }
 | 
			
		||||
                        }
 | 
			
		||||
 | 
			
		||||
            addMethod (@selector (accessibilityActivate),  accessibilityPerformActivate,  "c@:");
 | 
			
		||||
            addMethod (@selector (accessibilityIncrement), accessibilityPerformIncrement, "c@:");
 | 
			
		||||
            addMethod (@selector (accessibilityDecrement), accessibilityPerformDecrement, "c@:");
 | 
			
		||||
            addMethod (@selector (accessibilityPerformEscape),  accessibilityEscape,  "c@:");
 | 
			
		||||
                        return false;
 | 
			
		||||
                    };
 | 
			
		||||
 | 
			
		||||
            addMethod (@selector (accessibilityDataTableCellElementForRow:column:), getAccessibilityDataTableCellElementForRowColumn, "@@:ii");
 | 
			
		||||
            addMethod (@selector (accessibilityRowCount),                           getAccessibilityRowCount,                         "i@:");
 | 
			
		||||
            addMethod (@selector (accessibilityColumnCount),                        getAccessibilityColumnCount,                      "i@:");
 | 
			
		||||
            addProtocol (@protocol (UIAccessibilityContainerDataTable));
 | 
			
		||||
                    return handlerRef.getTitle().isNotEmpty()
 | 
			
		||||
                        || handlerRef.getHelp().isNotEmpty()
 | 
			
		||||
                        || handlerRef.getTextInterface()  != nullptr
 | 
			
		||||
                        || handlerRef.getValueInterface() != nullptr
 | 
			
		||||
                        || isTableCell();
 | 
			
		||||
                };
 | 
			
		||||
 | 
			
		||||
            addMethod (@selector (accessibilityRowRange),                           getAccessibilityRowIndexRange,                    @encode (NSRange), "@:");
 | 
			
		||||
            addMethod (@selector (accessibilityColumnRange),                        getAccessibilityColumnIndexRange,                 @encode (NSRange), "@:");
 | 
			
		||||
            addProtocol (@protocol (UIAccessibilityContainerDataTableCell));
 | 
			
		||||
                return handler != nullptr
 | 
			
		||||
                    && ! handler->isIgnored()
 | 
			
		||||
                    && handler->getRole() != AccessibilityRole::window
 | 
			
		||||
                    && hasAccessiblePropertiesOrIsTableCell (*handler);
 | 
			
		||||
            });
 | 
			
		||||
 | 
			
		||||
            addMethod (@selector (accessibilityContainer), [] (id self, SEL) -> id
 | 
			
		||||
            {
 | 
			
		||||
                if (auto* handler = getHandler (self))
 | 
			
		||||
                {
 | 
			
		||||
                    if (handler->getComponent().isOnDesktop())
 | 
			
		||||
                        return static_cast<id> (handler->getComponent().getWindowHandle());
 | 
			
		||||
 | 
			
		||||
                    if (! handler->getChildren().empty())
 | 
			
		||||
                    {
 | 
			
		||||
                        if (UIAccessibilityElement* container = getContainer (self))
 | 
			
		||||
                            return container;
 | 
			
		||||
 | 
			
		||||
                        static AccessibilityContainer cls;
 | 
			
		||||
 | 
			
		||||
                        id container = cls.createInstance();
 | 
			
		||||
 | 
			
		||||
                        object_setInstanceVariable (container, "handler", handler);
 | 
			
		||||
                        object_setInstanceVariable (self, "container", container);
 | 
			
		||||
 | 
			
		||||
                        return container;
 | 
			
		||||
                    }
 | 
			
		||||
 | 
			
		||||
                    if (auto* parent = handler->getParent())
 | 
			
		||||
                        return [static_cast<id> (parent->getNativeImplementation()) accessibilityContainer];
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
                return nil;
 | 
			
		||||
            });
 | 
			
		||||
 | 
			
		||||
            addMethod (@selector (accessibilityFrame), [] (id self, SEL)
 | 
			
		||||
            {
 | 
			
		||||
                if (auto* handler = getHandler (self))
 | 
			
		||||
                    return convertToCGRect (handler->getComponent().getScreenBounds());
 | 
			
		||||
 | 
			
		||||
                return CGRectZero;
 | 
			
		||||
            });
 | 
			
		||||
 | 
			
		||||
            addMethod (@selector (accessibilityTraits), [] (id self, SEL)
 | 
			
		||||
            {
 | 
			
		||||
                auto traits = UIAccessibilityTraits{};
 | 
			
		||||
 | 
			
		||||
                if (auto* handler = getHandler (self))
 | 
			
		||||
                {
 | 
			
		||||
                    traits |= [&handler]
 | 
			
		||||
                    {
 | 
			
		||||
                        switch (handler->getRole())
 | 
			
		||||
                        {
 | 
			
		||||
                            case AccessibilityRole::button:
 | 
			
		||||
                            case AccessibilityRole::toggleButton:
 | 
			
		||||
                            case AccessibilityRole::radioButton:
 | 
			
		||||
                            case AccessibilityRole::comboBox:      return UIAccessibilityTraitButton;
 | 
			
		||||
 | 
			
		||||
                            case AccessibilityRole::label:
 | 
			
		||||
                            case AccessibilityRole::staticText:    return UIAccessibilityTraitStaticText;
 | 
			
		||||
 | 
			
		||||
                            case AccessibilityRole::image:         return UIAccessibilityTraitImage;
 | 
			
		||||
                            case AccessibilityRole::tableHeader:   return UIAccessibilityTraitHeader;
 | 
			
		||||
                            case AccessibilityRole::hyperlink:     return UIAccessibilityTraitLink;
 | 
			
		||||
                            case AccessibilityRole::ignored:       return UIAccessibilityTraitNotEnabled;
 | 
			
		||||
 | 
			
		||||
                            case AccessibilityRole::editableText:  return UIAccessibilityTraitKeyboardKey;
 | 
			
		||||
 | 
			
		||||
                            case AccessibilityRole::slider:
 | 
			
		||||
                            case AccessibilityRole::menuItem:
 | 
			
		||||
                            case AccessibilityRole::menuBar:
 | 
			
		||||
                            case AccessibilityRole::popupMenu:
 | 
			
		||||
                            case AccessibilityRole::table:
 | 
			
		||||
                            case AccessibilityRole::column:
 | 
			
		||||
                            case AccessibilityRole::row:
 | 
			
		||||
                            case AccessibilityRole::cell:
 | 
			
		||||
                            case AccessibilityRole::list:
 | 
			
		||||
                            case AccessibilityRole::listItem:
 | 
			
		||||
                            case AccessibilityRole::tree:
 | 
			
		||||
                            case AccessibilityRole::treeItem:
 | 
			
		||||
                            case AccessibilityRole::progressBar:
 | 
			
		||||
                            case AccessibilityRole::group:
 | 
			
		||||
                            case AccessibilityRole::dialogWindow:
 | 
			
		||||
                            case AccessibilityRole::window:
 | 
			
		||||
                            case AccessibilityRole::scrollBar:
 | 
			
		||||
                            case AccessibilityRole::tooltip:
 | 
			
		||||
                            case AccessibilityRole::splashScreen:
 | 
			
		||||
                            case AccessibilityRole::unspecified:   break;
 | 
			
		||||
                        }
 | 
			
		||||
 | 
			
		||||
                        return UIAccessibilityTraitNone;
 | 
			
		||||
                    }();
 | 
			
		||||
 | 
			
		||||
                    const auto state = handler->getCurrentState();
 | 
			
		||||
 | 
			
		||||
                    if (state.isSelected() || state.isChecked())
 | 
			
		||||
                        traits |= UIAccessibilityTraitSelected;
 | 
			
		||||
 | 
			
		||||
                    if (auto* valueInterface = getValueInterface (self))
 | 
			
		||||
                        if (! valueInterface->isReadOnly() && valueInterface->getRange().isValid())
 | 
			
		||||
                            traits |= UIAccessibilityTraitAdjustable;
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
                return traits | sendSuperclassMessage<UIAccessibilityTraits> (self, @selector (accessibilityTraits));
 | 
			
		||||
            });
 | 
			
		||||
 | 
			
		||||
            addMethod (@selector (accessibilityLabel), getAccessibilityTitle);
 | 
			
		||||
            addMethod (@selector (accessibilityHint),  getAccessibilityHelp);
 | 
			
		||||
 | 
			
		||||
            addMethod (@selector (accessibilityValue), [] (id self, SEL) -> NSString*
 | 
			
		||||
            {
 | 
			
		||||
                if (auto* handler = getHandler (self))
 | 
			
		||||
                {
 | 
			
		||||
                    if (handler->getCurrentState().isCheckable())
 | 
			
		||||
                        return handler->getCurrentState().isChecked() ? @"1" : @"0";
 | 
			
		||||
 | 
			
		||||
                    return (NSString*) getAccessibilityValueFromInterfaces (*handler);
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
                return nil;
 | 
			
		||||
            });
 | 
			
		||||
 | 
			
		||||
            addMethod (@selector (setAccessibilityValue:), setAccessibilityValue);
 | 
			
		||||
 | 
			
		||||
            addMethod (@selector (accessibilityElementDidBecomeFocused), [] (id self, SEL)
 | 
			
		||||
            {
 | 
			
		||||
                if (auto* handler = getHandler (self))
 | 
			
		||||
                {
 | 
			
		||||
                    const WeakReference<Component> safeComponent (&handler->getComponent());
 | 
			
		||||
 | 
			
		||||
                    performActionIfSupported (self, AccessibilityActionType::focus);
 | 
			
		||||
 | 
			
		||||
                    if (safeComponent != nullptr)
 | 
			
		||||
                        handler->grabFocus();
 | 
			
		||||
                }
 | 
			
		||||
            });
 | 
			
		||||
 | 
			
		||||
            addMethod (@selector (accessibilityElementDidLoseFocus), [] (id self, SEL)
 | 
			
		||||
            {
 | 
			
		||||
                if (auto* handler = getHandler (self))
 | 
			
		||||
                    handler->giveAwayFocus();
 | 
			
		||||
            });
 | 
			
		||||
 | 
			
		||||
            addMethod (@selector (accessibilityElementIsFocused), [] (id self, SEL) -> BOOL
 | 
			
		||||
            {
 | 
			
		||||
                if (auto* handler = getHandler (self))
 | 
			
		||||
                    return handler->hasFocus (false);
 | 
			
		||||
 | 
			
		||||
                return NO;
 | 
			
		||||
            });
 | 
			
		||||
 | 
			
		||||
            addMethod (@selector (accessibilityViewIsModal), getIsAccessibilityModal);
 | 
			
		||||
 | 
			
		||||
            addMethod (@selector (accessibilityActivate), [] (id self, SEL)
 | 
			
		||||
            {
 | 
			
		||||
                if (auto* handler = getHandler (self))
 | 
			
		||||
                {
 | 
			
		||||
                    // Occasionally VoiceOver sends accessibilityActivate to the wrong element, so we first query
 | 
			
		||||
                    // which element it thinks has focus and forward the event on to that element if it differs
 | 
			
		||||
                    id focusedElement = UIAccessibilityFocusedElement (UIAccessibilityNotificationVoiceOverIdentifier);
 | 
			
		||||
 | 
			
		||||
                    if (focusedElement != nullptr && ! [static_cast<id> (handler->getNativeImplementation()) isEqual: focusedElement])
 | 
			
		||||
                        return [focusedElement accessibilityActivate];
 | 
			
		||||
 | 
			
		||||
                    if (handler->hasFocus (false))
 | 
			
		||||
                        return accessibilityPerformPress (self, {});
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
                return NO;
 | 
			
		||||
            });
 | 
			
		||||
 | 
			
		||||
            addMethod (@selector (accessibilityIncrement), accessibilityPerformIncrement);
 | 
			
		||||
            addMethod (@selector (accessibilityDecrement), accessibilityPerformDecrement);
 | 
			
		||||
 | 
			
		||||
            addMethod (@selector (accessibilityPerformEscape), [] (id self, SEL)
 | 
			
		||||
            {
 | 
			
		||||
                if (auto* handler = getHandler (self))
 | 
			
		||||
                {
 | 
			
		||||
                    if (auto* modal = Component::getCurrentlyModalComponent())
 | 
			
		||||
                    {
 | 
			
		||||
                        if (auto* modalHandler = modal->getAccessibilityHandler())
 | 
			
		||||
                        {
 | 
			
		||||
                            if (modalHandler == handler || modalHandler->isParentOf (handler))
 | 
			
		||||
                            {
 | 
			
		||||
                                modal->exitModalState (0);
 | 
			
		||||
                                return YES;
 | 
			
		||||
                            }
 | 
			
		||||
                        }
 | 
			
		||||
                    }
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
                return NO;
 | 
			
		||||
            });
 | 
			
		||||
 | 
			
		||||
            if (elementType == Type::textElement)
 | 
			
		||||
            {
 | 
			
		||||
                addMethod (@selector (accessibilityLineNumberForPoint:),   getAccessibilityLineNumberForPoint,   "i@:", @encode (CGPoint));
 | 
			
		||||
                addMethod (@selector (accessibilityContentForLineNumber:), getAccessibilityContentForLineNumber, "@@:i");
 | 
			
		||||
                addMethod (@selector (accessibilityFrameForLineNumber:),   getAccessibilityFrameForLineNumber,   @encode (CGRect), "@:i");
 | 
			
		||||
                addMethod (@selector (accessibilityPageContent),           getAccessibilityPageContent,          "@@:");
 | 
			
		||||
                addMethod (@selector (deleteBackward), [] (id, SEL) {});
 | 
			
		||||
                addMethod (@selector (insertText:), [] (id, SEL, NSString*) {});
 | 
			
		||||
 | 
			
		||||
                addProtocol (@protocol (UIAccessibilityReadingContent));
 | 
			
		||||
                forEach ([this] (auto signature) { addPassthroughMethodWithSignature (signature); },
 | 
			
		||||
                         SignatureHasText{},
 | 
			
		||||
                         SignatureSetSelectedTextRange{},
 | 
			
		||||
                         SignatureSelectedTextRange{},
 | 
			
		||||
                         SignatureMarkedTextRange{},
 | 
			
		||||
                         SignatureSetMarkedTextSelectedRange{},
 | 
			
		||||
                         SignatureUnmarkText{},
 | 
			
		||||
                         SignatureMarkedTextStyle{},
 | 
			
		||||
                         SignatureSetMarkedTextStyle{},
 | 
			
		||||
                         SignatureBeginningOfDocument{},
 | 
			
		||||
                         SignatureEndOfDocument{},
 | 
			
		||||
                         SignatureTokenizer{},
 | 
			
		||||
                         SignatureBaseWritingDirection{},
 | 
			
		||||
                         SignatureCaretRectForPosition{},
 | 
			
		||||
                         SignatureCharacterRangeByExtending{},
 | 
			
		||||
                         SignatureCharacterRangeAtPoint{},
 | 
			
		||||
                         SignatureClosestPositionToPoint{},
 | 
			
		||||
                         SignatureClosestPositionToPointInRange{},
 | 
			
		||||
                         SignatureComparePositionToPosition{},
 | 
			
		||||
                         SignatureOffsetFromPositionToPosition{},
 | 
			
		||||
                         SignaturePositionFromPositionInDirection{},
 | 
			
		||||
                         SignaturePositionFromPositionOffset{},
 | 
			
		||||
                         SignatureFirstRectForRange{},
 | 
			
		||||
                         SignatureSelectionRectsForRange{},
 | 
			
		||||
                         SignaturePositionWithinRange{},
 | 
			
		||||
                         SignatureReplaceRangeWithText{},
 | 
			
		||||
                         SignatureSetBaseWritingDirection{},
 | 
			
		||||
                         SignatureTextInRange{},
 | 
			
		||||
                         SignatureTextRangeFromPosition{},
 | 
			
		||||
                         SignatureSetInputDelegate{},
 | 
			
		||||
                         SignatureInputDelegate{},
 | 
			
		||||
                         SignatureKeyboardType{},
 | 
			
		||||
                         SignatureAutocapitalizationType{},
 | 
			
		||||
                         SignatureAutocorrectionType{});
 | 
			
		||||
 | 
			
		||||
                addProtocol (@protocol (UITextInput));
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            if (@available (iOS 11.0, *))
 | 
			
		||||
            {
 | 
			
		||||
                addMethod (@selector (accessibilityRowRange),                           getAccessibilityRowIndexRange);
 | 
			
		||||
                addMethod (@selector (accessibilityColumnRange),                        getAccessibilityColumnIndexRange);
 | 
			
		||||
                addProtocol (@protocol (UIAccessibilityContainerDataTableCell));
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            addIvar<UIAccessibilityElement*> ("container");
 | 
			
		||||
@@ -236,246 +514,65 @@ private:
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
    private:
 | 
			
		||||
        //==============================================================================
 | 
			
		||||
        template <typename Result>
 | 
			
		||||
        static auto getResult (NSInvocation* invocation, detail::Tag<Result>)
 | 
			
		||||
        {
 | 
			
		||||
            Result result{};
 | 
			
		||||
            [invocation getReturnValue: &result];
 | 
			
		||||
            return result;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        static void getResult (NSInvocation*, detail::Tag<void>) {}
 | 
			
		||||
 | 
			
		||||
        template <typename HasSelector, typename Result, typename... Args>
 | 
			
		||||
        auto makePassthroughCallback (HasSelector, Signature<Result (Args...)>)
 | 
			
		||||
        {
 | 
			
		||||
            return [] (id self, SEL, Args... args) -> Result
 | 
			
		||||
            {
 | 
			
		||||
                if (auto* input = getPeerTextInput (self))
 | 
			
		||||
                {
 | 
			
		||||
                    const auto s = detail::makeCompileTimeStr (@encode (Result), @encode (id), @encode (SEL), @encode (Args)...);
 | 
			
		||||
                    const auto signature = [NSMethodSignature signatureWithObjCTypes: s.data()];
 | 
			
		||||
                    const auto invocation = [NSInvocation invocationWithMethodSignature: signature];
 | 
			
		||||
                    invocation.selector = HasSelector::sel();
 | 
			
		||||
 | 
			
		||||
                    // Indices 0 and 1 are 'id self' and 'SEL _cmd' respectively
 | 
			
		||||
                    auto counter = 2;
 | 
			
		||||
                    forEach ([&] (auto& arg) { [invocation setArgument: &arg atIndex: counter++]; }, args...);
 | 
			
		||||
 | 
			
		||||
                    [invocation invokeWithTarget: input];
 | 
			
		||||
 | 
			
		||||
                    return getResult (invocation, detail::Tag<Result>{});
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
                jassertfalse;
 | 
			
		||||
                return {};
 | 
			
		||||
            };
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        template <typename Signature>
 | 
			
		||||
        void addPassthroughMethodWithSignature (Signature signature)
 | 
			
		||||
        {
 | 
			
		||||
            addMethod (Signature::sel(), makePassthroughCallback (signature, signature));
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        static UIAccessibilityElement* getContainer (id self)
 | 
			
		||||
        {
 | 
			
		||||
            return getIvar<UIAccessibilityElement*> (self, "container");
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        //==============================================================================
 | 
			
		||||
        static id getAccessibilityContainer (id self, SEL)
 | 
			
		||||
        static UIViewComponentPeer* getPeer (id self)
 | 
			
		||||
        {
 | 
			
		||||
            if (auto* handler = getHandler (self))
 | 
			
		||||
            {
 | 
			
		||||
                if (handler->getComponent().isOnDesktop())
 | 
			
		||||
                    return (id) handler->getComponent().getWindowHandle();
 | 
			
		||||
 | 
			
		||||
                if (handler->getChildren().size() > 0)
 | 
			
		||||
                {
 | 
			
		||||
                    if (UIAccessibilityElement* container = getContainer (self))
 | 
			
		||||
                        return container;
 | 
			
		||||
 | 
			
		||||
                    static AccessibilityContainer cls;
 | 
			
		||||
 | 
			
		||||
                    id windowHandle = (id) handler->getComponent().getWindowHandle();
 | 
			
		||||
                    UIAccessibilityElement* container = [cls.createInstance() initWithAccessibilityContainer: windowHandle];
 | 
			
		||||
 | 
			
		||||
                    [container retain];
 | 
			
		||||
 | 
			
		||||
                    object_setInstanceVariable (container, "handler", handler);
 | 
			
		||||
                    object_setInstanceVariable (self, "container", container);
 | 
			
		||||
 | 
			
		||||
                    return container;
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
                if (auto* parent = handler->getParent())
 | 
			
		||||
                    return [(id) parent->getNativeImplementation() accessibilityContainer];
 | 
			
		||||
            }
 | 
			
		||||
                return static_cast<UIViewComponentPeer*> (handler->getComponent().getPeer());
 | 
			
		||||
 | 
			
		||||
            return nil;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        static CGRect getAccessibilityFrame (id self, SEL)
 | 
			
		||||
        static JuceTextView* getPeerTextInput (id self)
 | 
			
		||||
        {
 | 
			
		||||
            if (auto* handler = getHandler (self))
 | 
			
		||||
                return convertToCGRect (handler->getComponent().getScreenBounds());
 | 
			
		||||
 | 
			
		||||
            return CGRectZero;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        static UIAccessibilityTraits getAccessibilityTraits (id self, SEL)
 | 
			
		||||
        {
 | 
			
		||||
            auto traits = UIAccessibilityTraits{};
 | 
			
		||||
 | 
			
		||||
            if (auto* handler = getHandler (self))
 | 
			
		||||
            {
 | 
			
		||||
                traits |= [&handler]
 | 
			
		||||
                {
 | 
			
		||||
                    switch (handler->getRole())
 | 
			
		||||
                    {
 | 
			
		||||
                        case AccessibilityRole::button:
 | 
			
		||||
                        case AccessibilityRole::toggleButton:
 | 
			
		||||
                        case AccessibilityRole::radioButton:
 | 
			
		||||
                        case AccessibilityRole::comboBox:      return UIAccessibilityTraitButton;
 | 
			
		||||
 | 
			
		||||
                        case AccessibilityRole::label:
 | 
			
		||||
                        case AccessibilityRole::staticText:    return UIAccessibilityTraitStaticText;
 | 
			
		||||
 | 
			
		||||
                        case AccessibilityRole::image:         return UIAccessibilityTraitImage;
 | 
			
		||||
                        case AccessibilityRole::tableHeader:   return UIAccessibilityTraitHeader;
 | 
			
		||||
                        case AccessibilityRole::hyperlink:     return UIAccessibilityTraitLink;
 | 
			
		||||
                        case AccessibilityRole::editableText:  return UIAccessibilityTraitKeyboardKey;
 | 
			
		||||
                        case AccessibilityRole::ignored:       return UIAccessibilityTraitNotEnabled;
 | 
			
		||||
 | 
			
		||||
                        case AccessibilityRole::slider:
 | 
			
		||||
                        case AccessibilityRole::menuItem:
 | 
			
		||||
                        case AccessibilityRole::menuBar:
 | 
			
		||||
                        case AccessibilityRole::popupMenu:
 | 
			
		||||
                        case AccessibilityRole::table:
 | 
			
		||||
                        case AccessibilityRole::column:
 | 
			
		||||
                        case AccessibilityRole::row:
 | 
			
		||||
                        case AccessibilityRole::cell:
 | 
			
		||||
                        case AccessibilityRole::list:
 | 
			
		||||
                        case AccessibilityRole::listItem:
 | 
			
		||||
                        case AccessibilityRole::tree:
 | 
			
		||||
                        case AccessibilityRole::treeItem:
 | 
			
		||||
                        case AccessibilityRole::progressBar:
 | 
			
		||||
                        case AccessibilityRole::group:
 | 
			
		||||
                        case AccessibilityRole::dialogWindow:
 | 
			
		||||
                        case AccessibilityRole::window:
 | 
			
		||||
                        case AccessibilityRole::scrollBar:
 | 
			
		||||
                        case AccessibilityRole::tooltip:
 | 
			
		||||
                        case AccessibilityRole::splashScreen:
 | 
			
		||||
                        case AccessibilityRole::unspecified:   break;
 | 
			
		||||
                    }
 | 
			
		||||
 | 
			
		||||
                    return UIAccessibilityTraitNone;
 | 
			
		||||
                }();
 | 
			
		||||
 | 
			
		||||
                const auto state = handler->getCurrentState();
 | 
			
		||||
 | 
			
		||||
                if (state.isSelected() || state.isChecked())
 | 
			
		||||
                    traits |= UIAccessibilityTraitSelected;
 | 
			
		||||
 | 
			
		||||
                if (auto* valueInterface = getValueInterface (self))
 | 
			
		||||
                    if (! valueInterface->isReadOnly() && valueInterface->getRange().isValid())
 | 
			
		||||
                        traits |= UIAccessibilityTraitAdjustable;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            return traits | sendSuperclassMessage<UIAccessibilityTraits> (self, @selector (accessibilityTraits));
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        static NSString* getAccessibilityValue (id self, SEL)
 | 
			
		||||
        {
 | 
			
		||||
            if (auto* handler = getHandler (self))
 | 
			
		||||
            {
 | 
			
		||||
                if (handler->getCurrentState().isCheckable())
 | 
			
		||||
                    return handler->getCurrentState().isChecked() ? @"1" : @"0";
 | 
			
		||||
 | 
			
		||||
                return (NSString*) getAccessibilityValueFromInterfaces (*handler);
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            return nil;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        static void onFocusGain (id self, SEL)
 | 
			
		||||
        {
 | 
			
		||||
            if (auto* handler = getHandler (self))
 | 
			
		||||
            {
 | 
			
		||||
                const WeakReference<Component> safeComponent (&handler->getComponent());
 | 
			
		||||
 | 
			
		||||
                performActionIfSupported (self, AccessibilityActionType::focus);
 | 
			
		||||
 | 
			
		||||
                if (safeComponent != nullptr)
 | 
			
		||||
                    handler->grabFocus();
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        static void onFocusLoss (id self, SEL)
 | 
			
		||||
        {
 | 
			
		||||
            if (auto* handler = getHandler (self))
 | 
			
		||||
                handler->giveAwayFocus();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        static BOOL isFocused (id self, SEL)
 | 
			
		||||
        {
 | 
			
		||||
            if (auto* handler = getHandler (self))
 | 
			
		||||
                return handler->hasFocus (false);
 | 
			
		||||
 | 
			
		||||
            return NO;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        static BOOL accessibilityPerformActivate (id self, SEL)
 | 
			
		||||
        {
 | 
			
		||||
            if (auto* handler = getHandler (self))
 | 
			
		||||
            {
 | 
			
		||||
                // occasionaly VoiceOver sends accessibilityActivate to the wrong element, so we first query
 | 
			
		||||
                // which element it thinks has focus and forward the event on to that element if it differs
 | 
			
		||||
                id focusedElement = UIAccessibilityFocusedElement (UIAccessibilityNotificationVoiceOverIdentifier);
 | 
			
		||||
 | 
			
		||||
                if (! [(id) handler->getNativeImplementation() isEqual: focusedElement])
 | 
			
		||||
                    return [focusedElement accessibilityActivate];
 | 
			
		||||
 | 
			
		||||
                if (handler->hasFocus (false))
 | 
			
		||||
                    return accessibilityPerformPress (self, {});
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            return NO;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        static BOOL accessibilityEscape (id self, SEL)
 | 
			
		||||
        {
 | 
			
		||||
            if (auto* handler = getHandler (self)) {
 | 
			
		||||
                // HACK - look for parent that is a CalloutBox and dismiss it
 | 
			
		||||
                if (CallOutBox* const cb = handler->getComponent().findParentComponentOfClass<CallOutBox>()) {
 | 
			
		||||
                    cb->dismiss();
 | 
			
		||||
                    return YES;
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
            return NO;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        static id getAccessibilityDataTableCellElementForRowColumn (id self, SEL, NSUInteger row, NSUInteger column)
 | 
			
		||||
        {
 | 
			
		||||
            if (auto* tableInterface = getTableInterface (self))
 | 
			
		||||
                if (auto* cellHandler = tableInterface->getCellHandler ((int) row, (int) column))
 | 
			
		||||
                    return (id) cellHandler->getNativeImplementation();
 | 
			
		||||
 | 
			
		||||
            return nil;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        static NSInteger getAccessibilityLineNumberForPoint (id self, SEL, CGPoint point)
 | 
			
		||||
        {
 | 
			
		||||
            if (auto* handler = getHandler (self))
 | 
			
		||||
            {
 | 
			
		||||
                if (auto* textInterface = handler->getTextInterface())
 | 
			
		||||
                {
 | 
			
		||||
                    auto pointInt = roundToIntPoint (point);
 | 
			
		||||
 | 
			
		||||
                    if (handler->getComponent().getScreenBounds().contains (pointInt))
 | 
			
		||||
                    {
 | 
			
		||||
                        auto textBounds = textInterface->getTextBounds ({ 0, textInterface->getTotalNumCharacters() });
 | 
			
		||||
 | 
			
		||||
                        for (int i = 0; i < textBounds.getNumRectangles(); ++i)
 | 
			
		||||
                            if (textBounds.getRectangle (i).contains (pointInt))
 | 
			
		||||
                                return (NSInteger) i;
 | 
			
		||||
                    }
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            return NSNotFound;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        static NSString* getAccessibilityContentForLineNumber (id self, SEL, NSInteger lineNumber)
 | 
			
		||||
        {
 | 
			
		||||
            if (auto* textInterface = getTextInterface (self))
 | 
			
		||||
            {
 | 
			
		||||
                auto lines = StringArray::fromLines (textInterface->getText ({ 0, textInterface->getTotalNumCharacters() }));
 | 
			
		||||
 | 
			
		||||
                if ((int) lineNumber < lines.size())
 | 
			
		||||
                    return juceStringToNS (lines[(int) lineNumber]);
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            return nil;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        static CGRect getAccessibilityFrameForLineNumber (id self, SEL, NSInteger lineNumber)
 | 
			
		||||
        {
 | 
			
		||||
            if (auto* textInterface = getTextInterface (self))
 | 
			
		||||
            {
 | 
			
		||||
                auto textBounds = textInterface->getTextBounds ({ 0, textInterface->getTotalNumCharacters() });
 | 
			
		||||
 | 
			
		||||
                if (lineNumber < textBounds.getNumRectangles())
 | 
			
		||||
                    return convertToCGRect (textBounds.getRectangle ((int) lineNumber));
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            return CGRectZero;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        static NSString* getAccessibilityPageContent (id self, SEL)
 | 
			
		||||
        {
 | 
			
		||||
            if (auto* textInterface = getTextInterface (self))
 | 
			
		||||
                return juceStringToNS (textInterface->getText ({ 0, textInterface->getTotalNumCharacters() }));
 | 
			
		||||
            if (auto* peer = getPeer (self))
 | 
			
		||||
                return peer->hiddenTextInput.get();
 | 
			
		||||
 | 
			
		||||
            return nil;
 | 
			
		||||
        }
 | 
			
		||||
@@ -535,9 +632,8 @@ void notifyAccessibilityEventInternal (const AccessibilityHandler& handler, Inte
 | 
			
		||||
        const bool moveToHandler = (eventType == InternalAccessibilityEvent::focusChanged && handler.hasFocus (false));
 | 
			
		||||
 | 
			
		||||
        sendAccessibilityEvent (notification,
 | 
			
		||||
                                moveToHandler ? (id) handler.getNativeImplementation() : nil);
 | 
			
		||||
                                moveToHandler ? static_cast<id> (handler.getNativeImplementation()) : nil);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void AccessibilityHandler::notifyAccessibilityEvent (AccessibilityEvent eventType) const
 | 
			
		||||
@@ -559,7 +655,7 @@ void AccessibilityHandler::notifyAccessibilityEvent (AccessibilityEvent eventTyp
 | 
			
		||||
    }();
 | 
			
		||||
 | 
			
		||||
    if (notification != UIAccessibilityNotifications{})
 | 
			
		||||
        sendAccessibilityEvent (notification, (id) getNativeImplementation());
 | 
			
		||||
        sendAccessibilityEvent (notification, static_cast<id> (getNativeImplementation()));
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void AccessibilityHandler::postAnnouncement (const String& announcementString, AnnouncementPriority)
 | 
			
		||||
 
 | 
			
		||||
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							@@ -2,15 +2,15 @@
 | 
			
		||||
  ==============================================================================
 | 
			
		||||
 | 
			
		||||
   This file is part of the JUCE library.
 | 
			
		||||
   Copyright (c) 2020 - Raw Material Software Limited
 | 
			
		||||
   Copyright (c) 2022 - Raw Material Software Limited
 | 
			
		||||
 | 
			
		||||
   JUCE is an open source library subject to commercial or open-source
 | 
			
		||||
   licensing.
 | 
			
		||||
 | 
			
		||||
   By using JUCE, you agree to the terms of both the JUCE 6 End-User License
 | 
			
		||||
   Agreement and JUCE Privacy Policy (both effective as of the 16th June 2020).
 | 
			
		||||
   By using JUCE, you agree to the terms of both the JUCE 7 End-User License
 | 
			
		||||
   Agreement and JUCE Privacy Policy.
 | 
			
		||||
 | 
			
		||||
   End User License Agreement: www.juce.com/juce-6-licence
 | 
			
		||||
   End User License Agreement: www.juce.com/juce-7-licence
 | 
			
		||||
   Privacy Policy: www.juce.com/juce-privacy-policy
 | 
			
		||||
 | 
			
		||||
   Or: You may also use this code under the terms of the GPL v3 (see
 | 
			
		||||
@@ -46,7 +46,9 @@ public:
 | 
			
		||||
    using Holder = std::unique_ptr<Base, AccessibleObjCClassDeleter>;
 | 
			
		||||
 | 
			
		||||
protected:
 | 
			
		||||
    AccessibleObjCClass()  : ObjCClass<Base> ("JUCEAccessibilityElement_")
 | 
			
		||||
    AccessibleObjCClass() : AccessibleObjCClass ("JUCEAccessibilityElement_") {}
 | 
			
		||||
 | 
			
		||||
    explicit AccessibleObjCClass (const char* name)  : ObjCClass<Base> (name)
 | 
			
		||||
    {
 | 
			
		||||
        ObjCClass<Base>::template addIvar<AccessibilityHandler*> ("handler");
 | 
			
		||||
    }
 | 
			
		||||
@@ -93,8 +95,7 @@ protected:
 | 
			
		||||
    static BOOL getIsAccessibilityElement (id self, SEL)
 | 
			
		||||
    {
 | 
			
		||||
        if (auto* handler = getHandler (self))
 | 
			
		||||
            return ! handler->isIgnored()
 | 
			
		||||
                  && handler->getRole() != AccessibilityRole::window;
 | 
			
		||||
            return ! handler->isIgnored() && handler->getRole() != AccessibilityRole::window;
 | 
			
		||||
 | 
			
		||||
        return NO;
 | 
			
		||||
    }
 | 
			
		||||
@@ -126,6 +127,10 @@ protected:
 | 
			
		||||
 | 
			
		||||
    static BOOL accessibilityPerformPress (id self, SEL)
 | 
			
		||||
    {
 | 
			
		||||
        if (auto* handler = getHandler (self))
 | 
			
		||||
            if (handler->getCurrentState().isCheckable() && handler->getActions().invoke (AccessibilityActionType::toggle))
 | 
			
		||||
                return YES;
 | 
			
		||||
 | 
			
		||||
        return performActionIfSupported (self, AccessibilityActionType::press);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
@@ -182,10 +187,8 @@ protected:
 | 
			
		||||
 | 
			
		||||
            NSString* nsString = juceStringToNS (title);
 | 
			
		||||
 | 
			
		||||
           #if ! JUCE_IOS
 | 
			
		||||
            if (nsString != nil && [[self accessibilityValue] isEqual: nsString])
 | 
			
		||||
                return @"";
 | 
			
		||||
           #endif
 | 
			
		||||
 | 
			
		||||
            return nsString;
 | 
			
		||||
        }
 | 
			
		||||
@@ -211,36 +214,58 @@ protected:
 | 
			
		||||
 | 
			
		||||
    static NSInteger getAccessibilityRowCount (id self, SEL)
 | 
			
		||||
    {
 | 
			
		||||
        if (auto* tableInterface = getTableInterface (self))
 | 
			
		||||
            return tableInterface->getNumRows();
 | 
			
		||||
        if (auto* tableHandler = getEnclosingHandlerWithInterface (getHandler (self), &AccessibilityHandler::getTableInterface))
 | 
			
		||||
            if (auto* tableInterface = tableHandler->getTableInterface())
 | 
			
		||||
                return tableInterface->getNumRows();
 | 
			
		||||
 | 
			
		||||
        return 0;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    static NSInteger getAccessibilityColumnCount (id self, SEL)
 | 
			
		||||
    {
 | 
			
		||||
        if (auto* tableInterface = getTableInterface (self))
 | 
			
		||||
            return tableInterface->getNumColumns();
 | 
			
		||||
        if (auto* tableHandler = getEnclosingHandlerWithInterface (getHandler (self), &AccessibilityHandler::getTableInterface))
 | 
			
		||||
            if (auto* tableInterface = tableHandler->getTableInterface())
 | 
			
		||||
                return tableInterface->getNumColumns();
 | 
			
		||||
 | 
			
		||||
        return 0;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    template <typename Getter>
 | 
			
		||||
    static NSRange getCellDimensions (id self, Getter getter)
 | 
			
		||||
    {
 | 
			
		||||
        const auto notFound = NSMakeRange (NSNotFound, 0);
 | 
			
		||||
 | 
			
		||||
        auto* handler = getHandler (self);
 | 
			
		||||
 | 
			
		||||
        if (handler == nullptr)
 | 
			
		||||
            return notFound;
 | 
			
		||||
 | 
			
		||||
        auto* tableHandler = getEnclosingHandlerWithInterface (getHandler (self), &AccessibilityHandler::getTableInterface);
 | 
			
		||||
 | 
			
		||||
        if (tableHandler == nullptr)
 | 
			
		||||
            return notFound;
 | 
			
		||||
 | 
			
		||||
        auto* tableInterface = tableHandler->getTableInterface();
 | 
			
		||||
 | 
			
		||||
        if (tableInterface == nullptr)
 | 
			
		||||
            return notFound;
 | 
			
		||||
 | 
			
		||||
        const auto result = (tableInterface->*getter) (*handler);
 | 
			
		||||
 | 
			
		||||
        if (! result.hasValue())
 | 
			
		||||
            return notFound;
 | 
			
		||||
 | 
			
		||||
        return NSMakeRange ((NSUInteger) result->begin, (NSUInteger) result->num);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    static NSRange getAccessibilityRowIndexRange (id self, SEL)
 | 
			
		||||
    {
 | 
			
		||||
        if (auto* cellInterface = getCellInterface (self))
 | 
			
		||||
            return NSMakeRange ((NSUInteger) cellInterface->getRowIndex(),
 | 
			
		||||
                                (NSUInteger) cellInterface->getRowSpan());
 | 
			
		||||
 | 
			
		||||
        return NSMakeRange (0, 0);
 | 
			
		||||
        return getCellDimensions (self, &AccessibilityTableInterface::getRowSpan);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    static NSRange getAccessibilityColumnIndexRange (id self, SEL)
 | 
			
		||||
    {
 | 
			
		||||
        if (auto* cellInterface = getCellInterface (self))
 | 
			
		||||
            return NSMakeRange ((NSUInteger) cellInterface->getColumnIndex(),
 | 
			
		||||
                                (NSUInteger) cellInterface->getColumnSpan());
 | 
			
		||||
 | 
			
		||||
        return NSMakeRange (0, 0);
 | 
			
		||||
        return getCellDimensions (self, &AccessibilityTableInterface::getColumnSpan);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (AccessibleObjCClass)
 | 
			
		||||
 
 | 
			
		||||
@@ -1,301 +1,327 @@
 | 
			
		||||
/*
 | 
			
		||||
  ==============================================================================
 | 
			
		||||
 | 
			
		||||
   This file is part of the JUCE library.
 | 
			
		||||
   Copyright (c) 2020 - Raw Material Software Limited
 | 
			
		||||
 | 
			
		||||
   JUCE is an open source library subject to commercial or open-source
 | 
			
		||||
   licensing.
 | 
			
		||||
 | 
			
		||||
   By using JUCE, you agree to the terms of both the JUCE 6 End-User License
 | 
			
		||||
   Agreement and JUCE Privacy Policy (both effective as of the 16th June 2020).
 | 
			
		||||
 | 
			
		||||
   End User License Agreement: www.juce.com/juce-6-licence
 | 
			
		||||
   Privacy Policy: www.juce.com/juce-privacy-policy
 | 
			
		||||
 | 
			
		||||
   Or: You may also use this code under the terms of the GPL v3 (see
 | 
			
		||||
   www.gnu.org/licenses).
 | 
			
		||||
 | 
			
		||||
   JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
 | 
			
		||||
   EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
 | 
			
		||||
   DISCLAIMED.
 | 
			
		||||
 | 
			
		||||
  ==============================================================================
 | 
			
		||||
*/
 | 
			
		||||
 | 
			
		||||
namespace juce
 | 
			
		||||
{
 | 
			
		||||
 | 
			
		||||
#define JUCE_NATIVE_ACCESSIBILITY_INCLUDED 1
 | 
			
		||||
 | 
			
		||||
JUCE_BEGIN_IGNORE_WARNINGS_GCC_LIKE ("-Wlanguage-extension-token")
 | 
			
		||||
 | 
			
		||||
static bool isStartingUpOrShuttingDown()
 | 
			
		||||
{
 | 
			
		||||
    if (auto* app = JUCEApplicationBase::getInstance())
 | 
			
		||||
        if (app->isInitialising())
 | 
			
		||||
            return true;
 | 
			
		||||
 | 
			
		||||
    if (auto* mm = MessageManager::getInstanceWithoutCreating())
 | 
			
		||||
        if (mm->hasStopMessageBeenSent())
 | 
			
		||||
            return true;
 | 
			
		||||
 | 
			
		||||
    return false;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static bool isHandlerValid (const AccessibilityHandler& handler)
 | 
			
		||||
{
 | 
			
		||||
    if (auto* provider = handler.getNativeImplementation())
 | 
			
		||||
        return provider->isElementValid();
 | 
			
		||||
 | 
			
		||||
    return false;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
//==============================================================================
 | 
			
		||||
class AccessibilityHandler::AccessibilityNativeImpl
 | 
			
		||||
{
 | 
			
		||||
public:
 | 
			
		||||
    explicit AccessibilityNativeImpl (AccessibilityHandler& owner)
 | 
			
		||||
        : accessibilityElement (new AccessibilityNativeHandle (owner))
 | 
			
		||||
    {
 | 
			
		||||
        ++providerCount;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    ~AccessibilityNativeImpl()
 | 
			
		||||
    {
 | 
			
		||||
        accessibilityElement->invalidateElement();
 | 
			
		||||
        --providerCount;
 | 
			
		||||
 | 
			
		||||
        if (auto* uiaWrapper = WindowsUIAWrapper::getInstanceWithoutCreating())
 | 
			
		||||
        {
 | 
			
		||||
            ComSmartPtr<IRawElementProviderSimple> provider;
 | 
			
		||||
            accessibilityElement->QueryInterface (IID_PPV_ARGS (provider.resetAndGetPointerAddress()));
 | 
			
		||||
 | 
			
		||||
            uiaWrapper->disconnectProvider (provider);
 | 
			
		||||
 | 
			
		||||
            if (providerCount == 0)
 | 
			
		||||
                uiaWrapper->disconnectAllProviders();
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    //==============================================================================
 | 
			
		||||
    ComSmartPtr<AccessibilityNativeHandle> accessibilityElement;
 | 
			
		||||
    static int providerCount;
 | 
			
		||||
 | 
			
		||||
    //==============================================================================
 | 
			
		||||
    JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (AccessibilityNativeImpl)
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
int AccessibilityHandler::AccessibilityNativeImpl::providerCount = 0;
 | 
			
		||||
 | 
			
		||||
//==============================================================================
 | 
			
		||||
AccessibilityNativeHandle* AccessibilityHandler::getNativeImplementation() const
 | 
			
		||||
{
 | 
			
		||||
    return nativeImpl->accessibilityElement;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static bool areAnyAccessibilityClientsActive()
 | 
			
		||||
{
 | 
			
		||||
    const auto areClientsListening = []
 | 
			
		||||
    {
 | 
			
		||||
        if (auto* uiaWrapper = WindowsUIAWrapper::getInstanceWithoutCreating())
 | 
			
		||||
            return uiaWrapper->clientsAreListening() != 0;
 | 
			
		||||
 | 
			
		||||
        return false;
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    const auto isScreenReaderRunning = []
 | 
			
		||||
    {
 | 
			
		||||
        BOOL isRunning = FALSE;
 | 
			
		||||
        SystemParametersInfo (SPI_GETSCREENREADER, 0, (PVOID) &isRunning, 0);
 | 
			
		||||
 | 
			
		||||
        return isRunning != 0;
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    return areClientsListening() || isScreenReaderRunning();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
template <typename Callback>
 | 
			
		||||
void getProviderWithCheckedWrapper (const AccessibilityHandler& handler, Callback&& callback)
 | 
			
		||||
{
 | 
			
		||||
    if (! areAnyAccessibilityClientsActive() || isStartingUpOrShuttingDown() || ! isHandlerValid (handler))
 | 
			
		||||
        return;
 | 
			
		||||
 | 
			
		||||
    if (auto* uiaWrapper = WindowsUIAWrapper::getInstanceWithoutCreating())
 | 
			
		||||
    {
 | 
			
		||||
        ComSmartPtr<IRawElementProviderSimple> provider;
 | 
			
		||||
        handler.getNativeImplementation()->QueryInterface (IID_PPV_ARGS (provider.resetAndGetPointerAddress()));
 | 
			
		||||
 | 
			
		||||
        callback (uiaWrapper, provider);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void sendAccessibilityAutomationEvent (const AccessibilityHandler& handler, EVENTID event)
 | 
			
		||||
{
 | 
			
		||||
    jassert (event != EVENTID{});
 | 
			
		||||
 | 
			
		||||
    getProviderWithCheckedWrapper (handler,  [event] (WindowsUIAWrapper* uiaWrapper, ComSmartPtr<IRawElementProviderSimple>& provider)
 | 
			
		||||
    {
 | 
			
		||||
        uiaWrapper->raiseAutomationEvent (provider, event);
 | 
			
		||||
    });
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void sendAccessibilityPropertyChangedEvent (const AccessibilityHandler& handler, PROPERTYID property, VARIANT newValue)
 | 
			
		||||
{
 | 
			
		||||
    jassert (property != PROPERTYID{});
 | 
			
		||||
 | 
			
		||||
    getProviderWithCheckedWrapper (handler, [property, newValue] (WindowsUIAWrapper* uiaWrapper, ComSmartPtr<IRawElementProviderSimple>& provider)
 | 
			
		||||
    {
 | 
			
		||||
        VARIANT oldValue;
 | 
			
		||||
        VariantHelpers::clear (&oldValue);
 | 
			
		||||
 | 
			
		||||
        uiaWrapper->raiseAutomationPropertyChangedEvent (provider, property, oldValue, newValue);
 | 
			
		||||
    });
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void notifyAccessibilityEventInternal (const AccessibilityHandler& handler, InternalAccessibilityEvent eventType)
 | 
			
		||||
{
 | 
			
		||||
    if (eventType == InternalAccessibilityEvent::elementCreated
 | 
			
		||||
        || eventType == InternalAccessibilityEvent::elementDestroyed)
 | 
			
		||||
    {
 | 
			
		||||
        if (auto* parent = handler.getParent())
 | 
			
		||||
            sendAccessibilityAutomationEvent (*parent, UIA_LayoutInvalidatedEventId);
 | 
			
		||||
 | 
			
		||||
        return;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    auto event = [eventType]() -> EVENTID
 | 
			
		||||
    {
 | 
			
		||||
        switch (eventType)
 | 
			
		||||
        {
 | 
			
		||||
            case InternalAccessibilityEvent::focusChanged:           return UIA_AutomationFocusChangedEventId;
 | 
			
		||||
            case InternalAccessibilityEvent::windowOpened:           return UIA_Window_WindowOpenedEventId;
 | 
			
		||||
            case InternalAccessibilityEvent::windowClosed:           return UIA_Window_WindowClosedEventId;
 | 
			
		||||
            case InternalAccessibilityEvent::elementCreated:
 | 
			
		||||
            case InternalAccessibilityEvent::elementDestroyed:
 | 
			
		||||
            case InternalAccessibilityEvent::elementMovedOrResized:  break;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        return {};
 | 
			
		||||
    }();
 | 
			
		||||
 | 
			
		||||
    if (event != EVENTID{})
 | 
			
		||||
        sendAccessibilityAutomationEvent (handler, event);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void AccessibilityHandler::notifyAccessibilityEvent (AccessibilityEvent eventType) const
 | 
			
		||||
{
 | 
			
		||||
    if (eventType == AccessibilityEvent::titleChanged)
 | 
			
		||||
    {
 | 
			
		||||
        VARIANT newValue;
 | 
			
		||||
        VariantHelpers::setString (getTitle(), &newValue);
 | 
			
		||||
 | 
			
		||||
        sendAccessibilityPropertyChangedEvent (*this, UIA_NamePropertyId, newValue);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    auto event = [eventType]() -> EVENTID
 | 
			
		||||
    {
 | 
			
		||||
        switch (eventType)
 | 
			
		||||
        {
 | 
			
		||||
            case AccessibilityEvent::textSelectionChanged:  return UIA_Text_TextSelectionChangedEventId;
 | 
			
		||||
            case AccessibilityEvent::textChanged:           return UIA_Text_TextChangedEventId;
 | 
			
		||||
            case AccessibilityEvent::structureChanged:      return UIA_StructureChangedEventId;
 | 
			
		||||
            case AccessibilityEvent::rowSelectionChanged:   return UIA_SelectionItem_ElementSelectedEventId;
 | 
			
		||||
            case AccessibilityEvent::titleChanged:
 | 
			
		||||
            case AccessibilityEvent::valueChanged:          break;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        return {};
 | 
			
		||||
    }();
 | 
			
		||||
 | 
			
		||||
    if (event != EVENTID{})
 | 
			
		||||
        sendAccessibilityAutomationEvent (*this, event);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
struct SpVoiceWrapper  : public DeletedAtShutdown
 | 
			
		||||
{
 | 
			
		||||
    SpVoiceWrapper()
 | 
			
		||||
    {
 | 
			
		||||
        auto hr = voice.CoCreateInstance (CLSID_SpVoice);
 | 
			
		||||
 | 
			
		||||
        jassertquiet (SUCCEEDED (hr));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    ~SpVoiceWrapper() override
 | 
			
		||||
    {
 | 
			
		||||
        clearSingletonInstance();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    ComSmartPtr<ISpVoice> voice;
 | 
			
		||||
 | 
			
		||||
    JUCE_DECLARE_SINGLETON (SpVoiceWrapper, false)
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
JUCE_IMPLEMENT_SINGLETON (SpVoiceWrapper)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
void AccessibilityHandler::postAnnouncement (const String& announcementString, AnnouncementPriority priority)
 | 
			
		||||
{
 | 
			
		||||
    if (! areAnyAccessibilityClientsActive())
 | 
			
		||||
        return;
 | 
			
		||||
 | 
			
		||||
    if (auto* sharedVoice = SpVoiceWrapper::getInstance())
 | 
			
		||||
    {
 | 
			
		||||
        auto voicePriority = [priority]
 | 
			
		||||
        {
 | 
			
		||||
            switch (priority)
 | 
			
		||||
            {
 | 
			
		||||
                case AnnouncementPriority::low:    return SPVPRI_OVER;
 | 
			
		||||
                case AnnouncementPriority::medium: return SPVPRI_NORMAL;
 | 
			
		||||
                case AnnouncementPriority::high:   return SPVPRI_ALERT;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            jassertfalse;
 | 
			
		||||
            return SPVPRI_OVER;
 | 
			
		||||
        }();
 | 
			
		||||
 | 
			
		||||
        sharedVoice->voice->SetPriority (voicePriority);
 | 
			
		||||
        sharedVoice->voice->Speak (announcementString.toWideCharPointer(), SPF_ASYNC, nullptr);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
//==============================================================================
 | 
			
		||||
namespace WindowsAccessibility
 | 
			
		||||
{
 | 
			
		||||
    long getUiaRootObjectId()
 | 
			
		||||
    {
 | 
			
		||||
        return static_cast<long> (UiaRootObjectId);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    bool handleWmGetObject (AccessibilityHandler* handler, WPARAM wParam, LPARAM lParam, LRESULT* res)
 | 
			
		||||
    {
 | 
			
		||||
        if (isStartingUpOrShuttingDown() || (handler == nullptr || ! isHandlerValid (*handler)))
 | 
			
		||||
            return false;
 | 
			
		||||
 | 
			
		||||
        if (auto* uiaWrapper = WindowsUIAWrapper::getInstance())
 | 
			
		||||
        {
 | 
			
		||||
            ComSmartPtr<IRawElementProviderSimple> provider;
 | 
			
		||||
            handler->getNativeImplementation()->QueryInterface (IID_PPV_ARGS (provider.resetAndGetPointerAddress()));
 | 
			
		||||
 | 
			
		||||
            if (! uiaWrapper->isProviderDisconnecting (provider))
 | 
			
		||||
                *res = uiaWrapper->returnRawElementProvider ((HWND) handler->getComponent().getWindowHandle(), wParam, lParam, provider);
 | 
			
		||||
 | 
			
		||||
            return true;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        return false;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    void revokeUIAMapEntriesForWindow (HWND hwnd)
 | 
			
		||||
    {
 | 
			
		||||
        if (auto* uiaWrapper = WindowsUIAWrapper::getInstanceWithoutCreating())
 | 
			
		||||
            uiaWrapper->returnRawElementProvider (hwnd, 0, 0, nullptr);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
JUCE_IMPLEMENT_SINGLETON (WindowsUIAWrapper)
 | 
			
		||||
 | 
			
		||||
JUCE_END_IGNORE_WARNINGS_GCC_LIKE
 | 
			
		||||
 | 
			
		||||
} // namespace juce
 | 
			
		||||
/*
 | 
			
		||||
  ==============================================================================
 | 
			
		||||
 | 
			
		||||
   This file is part of the JUCE library.
 | 
			
		||||
   Copyright (c) 2022 - Raw Material Software Limited
 | 
			
		||||
 | 
			
		||||
   JUCE is an open source library subject to commercial or open-source
 | 
			
		||||
   licensing.
 | 
			
		||||
 | 
			
		||||
   By using JUCE, you agree to the terms of both the JUCE 7 End-User License
 | 
			
		||||
   Agreement and JUCE Privacy Policy.
 | 
			
		||||
 | 
			
		||||
   End User License Agreement: www.juce.com/juce-7-licence
 | 
			
		||||
   Privacy Policy: www.juce.com/juce-privacy-policy
 | 
			
		||||
 | 
			
		||||
   Or: You may also use this code under the terms of the GPL v3 (see
 | 
			
		||||
   www.gnu.org/licenses).
 | 
			
		||||
 | 
			
		||||
   JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
 | 
			
		||||
   EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
 | 
			
		||||
   DISCLAIMED.
 | 
			
		||||
 | 
			
		||||
  ==============================================================================
 | 
			
		||||
*/
 | 
			
		||||
 | 
			
		||||
namespace juce
 | 
			
		||||
{
 | 
			
		||||
 | 
			
		||||
#define JUCE_NATIVE_ACCESSIBILITY_INCLUDED 1
 | 
			
		||||
 | 
			
		||||
JUCE_BEGIN_IGNORE_WARNINGS_GCC_LIKE ("-Wlanguage-extension-token")
 | 
			
		||||
 | 
			
		||||
static bool isStartingUpOrShuttingDown()
 | 
			
		||||
{
 | 
			
		||||
    if (auto* app = JUCEApplicationBase::getInstance())
 | 
			
		||||
        if (app->isInitialising())
 | 
			
		||||
            return true;
 | 
			
		||||
 | 
			
		||||
    if (auto* mm = MessageManager::getInstanceWithoutCreating())
 | 
			
		||||
        if (mm->hasStopMessageBeenSent())
 | 
			
		||||
            return true;
 | 
			
		||||
 | 
			
		||||
    return false;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static bool isHandlerValid (const AccessibilityHandler& handler)
 | 
			
		||||
{
 | 
			
		||||
    if (auto* provider = handler.getNativeImplementation())
 | 
			
		||||
        return provider->isElementValid();
 | 
			
		||||
 | 
			
		||||
    return false;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
//==============================================================================
 | 
			
		||||
class AccessibilityHandler::AccessibilityNativeImpl
 | 
			
		||||
{
 | 
			
		||||
public:
 | 
			
		||||
    explicit AccessibilityNativeImpl (AccessibilityHandler& owner)
 | 
			
		||||
        : accessibilityElement (new AccessibilityNativeHandle (owner))
 | 
			
		||||
    {
 | 
			
		||||
        ++providerCount;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    ~AccessibilityNativeImpl()
 | 
			
		||||
    {
 | 
			
		||||
        ComSmartPtr<IRawElementProviderSimple> provider;
 | 
			
		||||
        accessibilityElement->QueryInterface (IID_PPV_ARGS (provider.resetAndGetPointerAddress()));
 | 
			
		||||
 | 
			
		||||
        accessibilityElement->invalidateElement();
 | 
			
		||||
        --providerCount;
 | 
			
		||||
 | 
			
		||||
        if (auto* uiaWrapper = WindowsUIAWrapper::getInstanceWithoutCreating())
 | 
			
		||||
        {
 | 
			
		||||
            uiaWrapper->disconnectProvider (provider);
 | 
			
		||||
 | 
			
		||||
            if (providerCount == 0 && JUCEApplicationBase::isStandaloneApp())
 | 
			
		||||
                uiaWrapper->disconnectAllProviders();
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    //==============================================================================
 | 
			
		||||
    ComSmartPtr<AccessibilityNativeHandle> accessibilityElement;
 | 
			
		||||
    static int providerCount;
 | 
			
		||||
 | 
			
		||||
    //==============================================================================
 | 
			
		||||
    JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (AccessibilityNativeImpl)
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
int AccessibilityHandler::AccessibilityNativeImpl::providerCount = 0;
 | 
			
		||||
 | 
			
		||||
//==============================================================================
 | 
			
		||||
AccessibilityNativeHandle* AccessibilityHandler::getNativeImplementation() const
 | 
			
		||||
{
 | 
			
		||||
    return nativeImpl->accessibilityElement;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static bool areAnyAccessibilityClientsActive()
 | 
			
		||||
{
 | 
			
		||||
    const auto areClientsListening = []
 | 
			
		||||
    {
 | 
			
		||||
        if (auto* uiaWrapper = WindowsUIAWrapper::getInstanceWithoutCreating())
 | 
			
		||||
            return uiaWrapper->clientsAreListening() != 0;
 | 
			
		||||
 | 
			
		||||
        return false;
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    const auto isScreenReaderRunning = []
 | 
			
		||||
    {
 | 
			
		||||
        BOOL isRunning = FALSE;
 | 
			
		||||
        SystemParametersInfo (SPI_GETSCREENREADER, 0, (PVOID) &isRunning, 0);
 | 
			
		||||
 | 
			
		||||
        return isRunning != 0;
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    return areClientsListening() || isScreenReaderRunning();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
template <typename Callback>
 | 
			
		||||
void getProviderWithCheckedWrapper (const AccessibilityHandler& handler, Callback&& callback)
 | 
			
		||||
{
 | 
			
		||||
    if (! areAnyAccessibilityClientsActive() || isStartingUpOrShuttingDown() || ! isHandlerValid (handler))
 | 
			
		||||
        return;
 | 
			
		||||
 | 
			
		||||
    if (auto* uiaWrapper = WindowsUIAWrapper::getInstanceWithoutCreating())
 | 
			
		||||
    {
 | 
			
		||||
        ComSmartPtr<IRawElementProviderSimple> provider;
 | 
			
		||||
        handler.getNativeImplementation()->QueryInterface (IID_PPV_ARGS (provider.resetAndGetPointerAddress()));
 | 
			
		||||
 | 
			
		||||
        callback (uiaWrapper, provider);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void sendAccessibilityAutomationEvent (const AccessibilityHandler& handler, EVENTID event)
 | 
			
		||||
{
 | 
			
		||||
    jassert (event != EVENTID{});
 | 
			
		||||
 | 
			
		||||
    getProviderWithCheckedWrapper (handler, [event] (WindowsUIAWrapper* uiaWrapper, ComSmartPtr<IRawElementProviderSimple>& provider)
 | 
			
		||||
    {
 | 
			
		||||
        uiaWrapper->raiseAutomationEvent (provider, event);
 | 
			
		||||
    });
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void sendAccessibilityPropertyChangedEvent (const AccessibilityHandler& handler, PROPERTYID property, VARIANT newValue)
 | 
			
		||||
{
 | 
			
		||||
    jassert (property != PROPERTYID{});
 | 
			
		||||
 | 
			
		||||
    getProviderWithCheckedWrapper (handler, [property, newValue] (WindowsUIAWrapper* uiaWrapper, ComSmartPtr<IRawElementProviderSimple>& provider)
 | 
			
		||||
    {
 | 
			
		||||
        VARIANT oldValue;
 | 
			
		||||
        VariantHelpers::clear (&oldValue);
 | 
			
		||||
 | 
			
		||||
        uiaWrapper->raiseAutomationPropertyChangedEvent (provider, property, oldValue, newValue);
 | 
			
		||||
    });
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void notifyAccessibilityEventInternal (const AccessibilityHandler& handler, InternalAccessibilityEvent eventType)
 | 
			
		||||
{
 | 
			
		||||
    if (eventType == InternalAccessibilityEvent::elementCreated
 | 
			
		||||
        || eventType == InternalAccessibilityEvent::elementDestroyed)
 | 
			
		||||
    {
 | 
			
		||||
        if (auto* parent = handler.getParent())
 | 
			
		||||
            sendAccessibilityAutomationEvent (*parent, ComTypes::UIA_LayoutInvalidatedEventId);
 | 
			
		||||
 | 
			
		||||
        return;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if (eventType == InternalAccessibilityEvent::windowOpened
 | 
			
		||||
        || eventType == InternalAccessibilityEvent::windowClosed)
 | 
			
		||||
    {
 | 
			
		||||
        if (auto* peer = handler.getComponent().getPeer())
 | 
			
		||||
            if ((peer->getStyleFlags() & ComponentPeer::windowHasTitleBar) == 0)
 | 
			
		||||
                return;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    auto event = [eventType]() -> EVENTID
 | 
			
		||||
    {
 | 
			
		||||
        switch (eventType)
 | 
			
		||||
        {
 | 
			
		||||
            case InternalAccessibilityEvent::focusChanged:           return ComTypes::UIA_AutomationFocusChangedEventId;
 | 
			
		||||
            case InternalAccessibilityEvent::windowOpened:           return ComTypes::UIA_Window_WindowOpenedEventId;
 | 
			
		||||
            case InternalAccessibilityEvent::windowClosed:           return ComTypes::UIA_Window_WindowClosedEventId;
 | 
			
		||||
            case InternalAccessibilityEvent::elementCreated:
 | 
			
		||||
            case InternalAccessibilityEvent::elementDestroyed:
 | 
			
		||||
            case InternalAccessibilityEvent::elementMovedOrResized:  break;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        return {};
 | 
			
		||||
    }();
 | 
			
		||||
 | 
			
		||||
    if (event != EVENTID{})
 | 
			
		||||
        sendAccessibilityAutomationEvent (handler, event);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void AccessibilityHandler::notifyAccessibilityEvent (AccessibilityEvent eventType) const
 | 
			
		||||
{
 | 
			
		||||
    if (eventType == AccessibilityEvent::titleChanged)
 | 
			
		||||
    {
 | 
			
		||||
        VARIANT newValue;
 | 
			
		||||
        VariantHelpers::setString (getTitle(), &newValue);
 | 
			
		||||
 | 
			
		||||
        sendAccessibilityPropertyChangedEvent (*this, UIA_NamePropertyId, newValue);
 | 
			
		||||
        return;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if (eventType == AccessibilityEvent::valueChanged)
 | 
			
		||||
    {
 | 
			
		||||
        if (auto* valueInterface = getValueInterface())
 | 
			
		||||
        {
 | 
			
		||||
            const auto propertyType = getRole() == AccessibilityRole::slider ? UIA_RangeValueValuePropertyId
 | 
			
		||||
                                                                             : UIA_ValueValuePropertyId;
 | 
			
		||||
 | 
			
		||||
            const auto value = getRole() == AccessibilityRole::slider
 | 
			
		||||
                               ? VariantHelpers::getWithValue (valueInterface->getCurrentValue())
 | 
			
		||||
                               : VariantHelpers::getWithValue (valueInterface->getCurrentValueAsString());
 | 
			
		||||
 | 
			
		||||
            sendAccessibilityPropertyChangedEvent (*this, propertyType, value);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        return;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    auto event = [eventType]() -> EVENTID
 | 
			
		||||
    {
 | 
			
		||||
        switch (eventType)
 | 
			
		||||
        {
 | 
			
		||||
            case AccessibilityEvent::textSelectionChanged:  return ComTypes::UIA_Text_TextSelectionChangedEventId;
 | 
			
		||||
            case AccessibilityEvent::textChanged:           return ComTypes::UIA_Text_TextChangedEventId;
 | 
			
		||||
            case AccessibilityEvent::structureChanged:      return ComTypes::UIA_StructureChangedEventId;
 | 
			
		||||
            case AccessibilityEvent::rowSelectionChanged:   return ComTypes::UIA_SelectionItem_ElementSelectedEventId;
 | 
			
		||||
            case AccessibilityEvent::titleChanged:
 | 
			
		||||
            case AccessibilityEvent::valueChanged:          break;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        return {};
 | 
			
		||||
    }();
 | 
			
		||||
 | 
			
		||||
    if (event != EVENTID{})
 | 
			
		||||
        sendAccessibilityAutomationEvent (*this, event);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
struct SpVoiceWrapper  : public DeletedAtShutdown
 | 
			
		||||
{
 | 
			
		||||
    SpVoiceWrapper()
 | 
			
		||||
    {
 | 
			
		||||
        auto hr = voice.CoCreateInstance (ComTypes::CLSID_SpVoice);
 | 
			
		||||
 | 
			
		||||
        jassertquiet (SUCCEEDED (hr));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    ~SpVoiceWrapper() override
 | 
			
		||||
    {
 | 
			
		||||
        clearSingletonInstance();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    ComSmartPtr<ISpVoice> voice;
 | 
			
		||||
 | 
			
		||||
    JUCE_DECLARE_SINGLETON (SpVoiceWrapper, false)
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
JUCE_IMPLEMENT_SINGLETON (SpVoiceWrapper)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
void AccessibilityHandler::postAnnouncement (const String& announcementString, AnnouncementPriority priority)
 | 
			
		||||
{
 | 
			
		||||
    if (! areAnyAccessibilityClientsActive())
 | 
			
		||||
        return;
 | 
			
		||||
 | 
			
		||||
    if (auto* sharedVoice = SpVoiceWrapper::getInstance())
 | 
			
		||||
    {
 | 
			
		||||
        auto voicePriority = [priority]
 | 
			
		||||
        {
 | 
			
		||||
            switch (priority)
 | 
			
		||||
            {
 | 
			
		||||
                case AnnouncementPriority::low:    return SPVPRI_OVER;
 | 
			
		||||
                case AnnouncementPriority::medium: return SPVPRI_NORMAL;
 | 
			
		||||
                case AnnouncementPriority::high:   return SPVPRI_ALERT;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            jassertfalse;
 | 
			
		||||
            return SPVPRI_OVER;
 | 
			
		||||
        }();
 | 
			
		||||
 | 
			
		||||
        sharedVoice->voice->SetPriority (voicePriority);
 | 
			
		||||
        sharedVoice->voice->Speak (announcementString.toWideCharPointer(), SPF_ASYNC, nullptr);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
//==============================================================================
 | 
			
		||||
namespace WindowsAccessibility
 | 
			
		||||
{
 | 
			
		||||
    static long getUiaRootObjectId()
 | 
			
		||||
    {
 | 
			
		||||
        return static_cast<long> (UiaRootObjectId);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    static bool handleWmGetObject (AccessibilityHandler* handler, WPARAM wParam, LPARAM lParam, LRESULT* res)
 | 
			
		||||
    {
 | 
			
		||||
        if (isStartingUpOrShuttingDown() || (handler == nullptr || ! isHandlerValid (*handler)))
 | 
			
		||||
            return false;
 | 
			
		||||
 | 
			
		||||
        if (auto* uiaWrapper = WindowsUIAWrapper::getInstance())
 | 
			
		||||
        {
 | 
			
		||||
            ComSmartPtr<IRawElementProviderSimple> provider;
 | 
			
		||||
            handler->getNativeImplementation()->QueryInterface (IID_PPV_ARGS (provider.resetAndGetPointerAddress()));
 | 
			
		||||
 | 
			
		||||
            if (! uiaWrapper->isProviderDisconnecting (provider))
 | 
			
		||||
                *res = uiaWrapper->returnRawElementProvider ((HWND) handler->getComponent().getWindowHandle(), wParam, lParam, provider);
 | 
			
		||||
 | 
			
		||||
            return true;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        return false;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    static void revokeUIAMapEntriesForWindow (HWND hwnd)
 | 
			
		||||
    {
 | 
			
		||||
        if (auto* uiaWrapper = WindowsUIAWrapper::getInstanceWithoutCreating())
 | 
			
		||||
            uiaWrapper->returnRawElementProvider (hwnd, 0, 0, nullptr);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
JUCE_IMPLEMENT_SINGLETON (WindowsUIAWrapper)
 | 
			
		||||
 | 
			
		||||
JUCE_END_IGNORE_WARNINGS_GCC_LIKE
 | 
			
		||||
 | 
			
		||||
} // namespace juce
 | 
			
		||||
 
 | 
			
		||||
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							@@ -1,80 +1,80 @@
 | 
			
		||||
/*
 | 
			
		||||
  ==============================================================================
 | 
			
		||||
 | 
			
		||||
   This file is part of the JUCE library.
 | 
			
		||||
   Copyright (c) 2020 - Raw Material Software Limited
 | 
			
		||||
 | 
			
		||||
   JUCE is an open source library subject to commercial or open-source
 | 
			
		||||
   licensing.
 | 
			
		||||
 | 
			
		||||
   By using JUCE, you agree to the terms of both the JUCE 6 End-User License
 | 
			
		||||
   Agreement and JUCE Privacy Policy (both effective as of the 16th June 2020).
 | 
			
		||||
 | 
			
		||||
   End User License Agreement: www.juce.com/juce-6-licence
 | 
			
		||||
   Privacy Policy: www.juce.com/juce-privacy-policy
 | 
			
		||||
 | 
			
		||||
   Or: You may also use this code under the terms of the GPL v3 (see
 | 
			
		||||
   www.gnu.org/licenses).
 | 
			
		||||
 | 
			
		||||
   JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
 | 
			
		||||
   EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
 | 
			
		||||
   DISCLAIMED.
 | 
			
		||||
 | 
			
		||||
  ==============================================================================
 | 
			
		||||
*/
 | 
			
		||||
 | 
			
		||||
namespace juce
 | 
			
		||||
{
 | 
			
		||||
 | 
			
		||||
#define UIA_FullDescriptionPropertyId 30159
 | 
			
		||||
#define UIA_IsDialogPropertyId        30174
 | 
			
		||||
 | 
			
		||||
class AccessibilityNativeHandle  : public ComBaseClassHelper<IRawElementProviderSimple,
 | 
			
		||||
                                                             IRawElementProviderFragment,
 | 
			
		||||
                                                             IRawElementProviderFragmentRoot>
 | 
			
		||||
{
 | 
			
		||||
public:
 | 
			
		||||
    explicit AccessibilityNativeHandle (AccessibilityHandler& handler);
 | 
			
		||||
 | 
			
		||||
    //==============================================================================
 | 
			
		||||
    void invalidateElement() noexcept         { valid = false; }
 | 
			
		||||
    bool isElementValid() const noexcept      { return valid; }
 | 
			
		||||
 | 
			
		||||
    const AccessibilityHandler& getHandler()  { return accessibilityHandler; }
 | 
			
		||||
 | 
			
		||||
    //==============================================================================
 | 
			
		||||
    JUCE_COMRESULT QueryInterface (REFIID refId, void** result) override;
 | 
			
		||||
 | 
			
		||||
    //==============================================================================
 | 
			
		||||
    JUCE_COMRESULT get_HostRawElementProvider (IRawElementProviderSimple** provider) override;
 | 
			
		||||
    JUCE_COMRESULT get_ProviderOptions (ProviderOptions* options) override;
 | 
			
		||||
    JUCE_COMRESULT GetPatternProvider (PATTERNID pId, IUnknown** provider) override;
 | 
			
		||||
    JUCE_COMRESULT GetPropertyValue (PROPERTYID propertyId, VARIANT* pRetVal) override;
 | 
			
		||||
 | 
			
		||||
    JUCE_COMRESULT Navigate (NavigateDirection direction, IRawElementProviderFragment** pRetVal) override;
 | 
			
		||||
    JUCE_COMRESULT GetRuntimeId (SAFEARRAY** pRetVal) override;
 | 
			
		||||
    JUCE_COMRESULT get_BoundingRectangle (UiaRect* pRetVal) override;
 | 
			
		||||
    JUCE_COMRESULT GetEmbeddedFragmentRoots (SAFEARRAY** pRetVal) override;
 | 
			
		||||
    JUCE_COMRESULT SetFocus() override;
 | 
			
		||||
    JUCE_COMRESULT get_FragmentRoot (IRawElementProviderFragmentRoot** pRetVal) override;
 | 
			
		||||
 | 
			
		||||
    JUCE_COMRESULT ElementProviderFromPoint (double x, double y, IRawElementProviderFragment** pRetVal) override;
 | 
			
		||||
    JUCE_COMRESULT GetFocus (IRawElementProviderFragment** pRetVal) override;
 | 
			
		||||
 | 
			
		||||
private:
 | 
			
		||||
    //==============================================================================
 | 
			
		||||
    String getElementName() const;
 | 
			
		||||
    bool isFragmentRoot() const     { return accessibilityHandler.getComponent().isOnDesktop(); }
 | 
			
		||||
 | 
			
		||||
    //==============================================================================
 | 
			
		||||
    AccessibilityHandler& accessibilityHandler;
 | 
			
		||||
 | 
			
		||||
    static int idCounter;
 | 
			
		||||
    std::array<int, 2> rtid { UiaAppendRuntimeId,  ++idCounter };
 | 
			
		||||
    bool valid = true;
 | 
			
		||||
 | 
			
		||||
    //==============================================================================
 | 
			
		||||
    JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (AccessibilityNativeHandle)
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
/*
 | 
			
		||||
  ==============================================================================
 | 
			
		||||
 | 
			
		||||
   This file is part of the JUCE library.
 | 
			
		||||
   Copyright (c) 2022 - Raw Material Software Limited
 | 
			
		||||
 | 
			
		||||
   JUCE is an open source library subject to commercial or open-source
 | 
			
		||||
   licensing.
 | 
			
		||||
 | 
			
		||||
   By using JUCE, you agree to the terms of both the JUCE 7 End-User License
 | 
			
		||||
   Agreement and JUCE Privacy Policy.
 | 
			
		||||
 | 
			
		||||
   End User License Agreement: www.juce.com/juce-7-licence
 | 
			
		||||
   Privacy Policy: www.juce.com/juce-privacy-policy
 | 
			
		||||
 | 
			
		||||
   Or: You may also use this code under the terms of the GPL v3 (see
 | 
			
		||||
   www.gnu.org/licenses).
 | 
			
		||||
 | 
			
		||||
   JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
 | 
			
		||||
   EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
 | 
			
		||||
   DISCLAIMED.
 | 
			
		||||
 | 
			
		||||
  ==============================================================================
 | 
			
		||||
*/
 | 
			
		||||
 | 
			
		||||
namespace juce
 | 
			
		||||
{
 | 
			
		||||
 | 
			
		||||
#define UIA_FullDescriptionPropertyId 30159
 | 
			
		||||
#define UIA_IsDialogPropertyId        30174
 | 
			
		||||
 | 
			
		||||
class AccessibilityNativeHandle  : public ComBaseClassHelper<IRawElementProviderSimple,
 | 
			
		||||
                                                             ComTypes::IRawElementProviderFragment,
 | 
			
		||||
                                                             ComTypes::IRawElementProviderFragmentRoot>
 | 
			
		||||
{
 | 
			
		||||
public:
 | 
			
		||||
    explicit AccessibilityNativeHandle (AccessibilityHandler& handler);
 | 
			
		||||
 | 
			
		||||
    //==============================================================================
 | 
			
		||||
    void invalidateElement() noexcept         { valid = false; }
 | 
			
		||||
    bool isElementValid() const noexcept      { return valid; }
 | 
			
		||||
 | 
			
		||||
    const AccessibilityHandler& getHandler()  { return accessibilityHandler; }
 | 
			
		||||
 | 
			
		||||
    //==============================================================================
 | 
			
		||||
    JUCE_COMRESULT QueryInterface (REFIID refId, void** result) override;
 | 
			
		||||
 | 
			
		||||
    //==============================================================================
 | 
			
		||||
    JUCE_COMRESULT get_HostRawElementProvider (IRawElementProviderSimple** provider) override;
 | 
			
		||||
    JUCE_COMRESULT get_ProviderOptions (ProviderOptions* options) override;
 | 
			
		||||
    JUCE_COMRESULT GetPatternProvider (PATTERNID pId, IUnknown** provider) override;
 | 
			
		||||
    JUCE_COMRESULT GetPropertyValue (PROPERTYID propertyId, VARIANT* pRetVal) override;
 | 
			
		||||
 | 
			
		||||
    JUCE_COMRESULT Navigate (ComTypes::NavigateDirection direction, ComTypes::IRawElementProviderFragment** pRetVal) override;
 | 
			
		||||
    JUCE_COMRESULT GetRuntimeId (SAFEARRAY** pRetVal) override;
 | 
			
		||||
    JUCE_COMRESULT get_BoundingRectangle (ComTypes::UiaRect* pRetVal) override;
 | 
			
		||||
    JUCE_COMRESULT GetEmbeddedFragmentRoots (SAFEARRAY** pRetVal) override;
 | 
			
		||||
    JUCE_COMRESULT SetFocus() override;
 | 
			
		||||
    JUCE_COMRESULT get_FragmentRoot (ComTypes::IRawElementProviderFragmentRoot** pRetVal) override;
 | 
			
		||||
 | 
			
		||||
    JUCE_COMRESULT ElementProviderFromPoint (double x, double y, ComTypes::IRawElementProviderFragment** pRetVal) override;
 | 
			
		||||
    JUCE_COMRESULT GetFocus (ComTypes::IRawElementProviderFragment** pRetVal) override;
 | 
			
		||||
 | 
			
		||||
private:
 | 
			
		||||
    //==============================================================================
 | 
			
		||||
    String getElementName() const;
 | 
			
		||||
    bool isFragmentRoot() const     { return accessibilityHandler.getComponent().isOnDesktop(); }
 | 
			
		||||
 | 
			
		||||
    //==============================================================================
 | 
			
		||||
    AccessibilityHandler& accessibilityHandler;
 | 
			
		||||
 | 
			
		||||
    static int idCounter;
 | 
			
		||||
    std::array<int, 2> rtid { UiaAppendRuntimeId, ++idCounter };
 | 
			
		||||
    bool valid = true;
 | 
			
		||||
 | 
			
		||||
    //==============================================================================
 | 
			
		||||
    JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (AccessibilityNativeHandle)
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										429
									
								
								deps/juce/modules/juce_gui_basics/native/accessibility/juce_win32_ComInterfaces.h
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										429
									
								
								deps/juce/modules/juce_gui_basics/native/accessibility/juce_win32_ComInterfaces.h
									
									
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,429 @@
 | 
			
		||||
/*
 | 
			
		||||
  ==============================================================================
 | 
			
		||||
 | 
			
		||||
   This file is part of the JUCE library.
 | 
			
		||||
   Copyright (c) 2022 - Raw Material Software Limited
 | 
			
		||||
 | 
			
		||||
   JUCE is an open source library subject to commercial or open-source
 | 
			
		||||
   licensing.
 | 
			
		||||
 | 
			
		||||
   By using JUCE, you agree to the terms of both the JUCE 7 End-User License
 | 
			
		||||
   Agreement and JUCE Privacy Policy.
 | 
			
		||||
 | 
			
		||||
   End User License Agreement: www.juce.com/juce-7-licence
 | 
			
		||||
   Privacy Policy: www.juce.com/juce-privacy-policy
 | 
			
		||||
 | 
			
		||||
   Or: You may also use this code under the terms of the GPL v3 (see
 | 
			
		||||
   www.gnu.org/licenses).
 | 
			
		||||
 | 
			
		||||
   JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
 | 
			
		||||
   EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
 | 
			
		||||
   DISCLAIMED.
 | 
			
		||||
 | 
			
		||||
  ==============================================================================
 | 
			
		||||
*/
 | 
			
		||||
 | 
			
		||||
namespace juce
 | 
			
		||||
{
 | 
			
		||||
namespace ComTypes
 | 
			
		||||
{
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
    These interfaces would normally be included in the system platform headers.
 | 
			
		||||
    However, those headers are likely to be incomplete when building with
 | 
			
		||||
    MinGW. In order to allow building accessible applications under MinGW,
 | 
			
		||||
    we reproduce all necessary definitions here.
 | 
			
		||||
*/
 | 
			
		||||
 | 
			
		||||
struct UiaPoint
 | 
			
		||||
{
 | 
			
		||||
    double x;
 | 
			
		||||
    double y;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
struct UiaRect
 | 
			
		||||
{
 | 
			
		||||
    double left;
 | 
			
		||||
    double top;
 | 
			
		||||
    double width;
 | 
			
		||||
    double height;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
enum NavigateDirection
 | 
			
		||||
{
 | 
			
		||||
    NavigateDirection_Parent = 0,
 | 
			
		||||
    NavigateDirection_NextSibling = 1,
 | 
			
		||||
    NavigateDirection_PreviousSibling = 2,
 | 
			
		||||
    NavigateDirection_FirstChild = 3,
 | 
			
		||||
    NavigateDirection_LastChild = 4
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
enum ExpandCollapseState
 | 
			
		||||
{
 | 
			
		||||
    ExpandCollapseState_Collapsed = 0,
 | 
			
		||||
    ExpandCollapseState_Expanded = 1,
 | 
			
		||||
    ExpandCollapseState_PartiallyExpanded = 2,
 | 
			
		||||
    ExpandCollapseState_LeafNode = 3
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
enum TextPatternRangeEndpoint
 | 
			
		||||
{
 | 
			
		||||
    TextPatternRangeEndpoint_Start = 0,
 | 
			
		||||
    TextPatternRangeEndpoint_End = 1
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
enum TextUnit
 | 
			
		||||
{
 | 
			
		||||
    TextUnit_Character = 0,
 | 
			
		||||
    TextUnit_Format = 1,
 | 
			
		||||
    TextUnit_Word = 2,
 | 
			
		||||
    TextUnit_Line = 3,
 | 
			
		||||
    TextUnit_Paragraph = 4,
 | 
			
		||||
    TextUnit_Page = 5,
 | 
			
		||||
    TextUnit_Document = 6
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
enum SupportedTextSelection
 | 
			
		||||
{
 | 
			
		||||
    SupportedTextSelection_None = 0,
 | 
			
		||||
    SupportedTextSelection_Single = 1,
 | 
			
		||||
    SupportedTextSelection_Multiple = 2
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
enum CaretPosition
 | 
			
		||||
{
 | 
			
		||||
    CaretPosition_Unknown = 0,
 | 
			
		||||
    CaretPosition_EndOfLine = 1,
 | 
			
		||||
    CaretPosition_BeginningOfLine = 2
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
enum ToggleState
 | 
			
		||||
{
 | 
			
		||||
    ToggleState_Off = 0,
 | 
			
		||||
    ToggleState_On = 1,
 | 
			
		||||
    ToggleState_Indeterminate = 2
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
enum WindowVisualState
 | 
			
		||||
{
 | 
			
		||||
    WindowVisualState_Normal = 0,
 | 
			
		||||
    WindowVisualState_Maximized = 1,
 | 
			
		||||
    WindowVisualState_Minimized = 2
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
enum WindowInteractionState
 | 
			
		||||
{
 | 
			
		||||
    WindowInteractionState_Running = 0,
 | 
			
		||||
    WindowInteractionState_Closing = 1,
 | 
			
		||||
    WindowInteractionState_ReadyForUserInteraction = 2,
 | 
			
		||||
    WindowInteractionState_BlockedByModalWindow = 3,
 | 
			
		||||
    WindowInteractionState_NotResponding = 4
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
enum RowOrColumnMajor
 | 
			
		||||
{
 | 
			
		||||
    RowOrColumnMajor_RowMajor = 0,
 | 
			
		||||
    RowOrColumnMajor_ColumnMajor = 1,
 | 
			
		||||
    RowOrColumnMajor_Indeterminate = 2
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
enum ScrollAmount
 | 
			
		||||
{
 | 
			
		||||
    ScrollAmount_LargeDecrement = 0,
 | 
			
		||||
    ScrollAmount_SmallDecrement = 1,
 | 
			
		||||
    ScrollAmount_NoAmount = 2,
 | 
			
		||||
    ScrollAmount_LargeIncrement = 3,
 | 
			
		||||
    ScrollAmount_SmallIncrement = 4
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
const long UIA_InvokePatternId = 10000;
 | 
			
		||||
const long UIA_SelectionPatternId = 10001;
 | 
			
		||||
const long UIA_ValuePatternId = 10002;
 | 
			
		||||
const long UIA_RangeValuePatternId = 10003;
 | 
			
		||||
const long UIA_ScrollPatternId = 10004;
 | 
			
		||||
const long UIA_ExpandCollapsePatternId = 10005;
 | 
			
		||||
const long UIA_GridPatternId = 10006;
 | 
			
		||||
const long UIA_GridItemPatternId = 10007;
 | 
			
		||||
const long UIA_WindowPatternId = 10009;
 | 
			
		||||
const long UIA_SelectionItemPatternId = 10010;
 | 
			
		||||
const long UIA_TablePatternId = 10012;
 | 
			
		||||
const long UIA_TableItemPatternId = 10013;
 | 
			
		||||
const long UIA_TextPatternId = 10014;
 | 
			
		||||
const long UIA_TogglePatternId = 10015;
 | 
			
		||||
const long UIA_TransformPatternId = 10016;
 | 
			
		||||
const long UIA_ScrollItemPatternId = 10017;
 | 
			
		||||
const long UIA_TextPattern2Id = 10024;
 | 
			
		||||
const long UIA_StructureChangedEventId = 20002;
 | 
			
		||||
const long UIA_MenuOpenedEventId = 20003;
 | 
			
		||||
const long UIA_AutomationFocusChangedEventId = 20005;
 | 
			
		||||
const long UIA_MenuClosedEventId = 20007;
 | 
			
		||||
const long UIA_LayoutInvalidatedEventId = 20008;
 | 
			
		||||
const long UIA_Invoke_InvokedEventId = 20009;
 | 
			
		||||
const long UIA_SelectionItem_ElementSelectedEventId = 20012;
 | 
			
		||||
const long UIA_Text_TextSelectionChangedEventId = 20014;
 | 
			
		||||
const long UIA_Text_TextChangedEventId = 20015;
 | 
			
		||||
const long UIA_Window_WindowOpenedEventId = 20016;
 | 
			
		||||
const long UIA_Window_WindowClosedEventId = 20017;
 | 
			
		||||
const long UIA_IsPeripheralPropertyId = 30150;
 | 
			
		||||
const long UIA_IsReadOnlyAttributeId = 40015;
 | 
			
		||||
const long UIA_CaretPositionAttributeId = 40038;
 | 
			
		||||
const long UIA_ButtonControlTypeId = 50000;
 | 
			
		||||
const long UIA_CheckBoxControlTypeId = 50002;
 | 
			
		||||
const long UIA_ComboBoxControlTypeId = 50003;
 | 
			
		||||
const long UIA_EditControlTypeId = 50004;
 | 
			
		||||
const long UIA_HyperlinkControlTypeId = 50005;
 | 
			
		||||
const long UIA_ImageControlTypeId = 50006;
 | 
			
		||||
const long UIA_ListItemControlTypeId = 50007;
 | 
			
		||||
const long UIA_ListControlTypeId = 50008;
 | 
			
		||||
const long UIA_MenuBarControlTypeId = 50010;
 | 
			
		||||
const long UIA_MenuItemControlTypeId = 50011;
 | 
			
		||||
const long UIA_ProgressBarControlTypeId = 50012;
 | 
			
		||||
const long UIA_RadioButtonControlTypeId = 50013;
 | 
			
		||||
const long UIA_ScrollBarControlTypeId = 50014;
 | 
			
		||||
const long UIA_SliderControlTypeId = 50015;
 | 
			
		||||
const long UIA_TextControlTypeId = 50020;
 | 
			
		||||
const long UIA_ToolTipControlTypeId = 50022;
 | 
			
		||||
const long UIA_TreeControlTypeId = 50023;
 | 
			
		||||
const long UIA_TreeItemControlTypeId = 50024;
 | 
			
		||||
const long UIA_CustomControlTypeId = 50025;
 | 
			
		||||
const long UIA_GroupControlTypeId = 50026;
 | 
			
		||||
const long UIA_DataItemControlTypeId = 50029;
 | 
			
		||||
const long UIA_WindowControlTypeId = 50032;
 | 
			
		||||
const long UIA_HeaderControlTypeId = 50034;
 | 
			
		||||
const long UIA_HeaderItemControlTypeId = 50035;
 | 
			
		||||
const long UIA_TableControlTypeId = 50036;
 | 
			
		||||
 | 
			
		||||
interface IRawElementProviderFragmentRoot;
 | 
			
		||||
interface IRawElementProviderFragment;
 | 
			
		||||
 | 
			
		||||
JUCE_COMCLASS (IRawElementProviderFragmentRoot, "620ce2a5-ab8f-40a9-86cb-de3c75599b58") : public IUnknown
 | 
			
		||||
{
 | 
			
		||||
public:
 | 
			
		||||
    JUCE_COMCALL ElementProviderFromPoint (double x, double y, __RPC__deref_out_opt IRawElementProviderFragment** pRetVal) = 0;
 | 
			
		||||
    JUCE_COMCALL GetFocus (__RPC__deref_out_opt IRawElementProviderFragment * *pRetVal) = 0;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
JUCE_COMCLASS (IRawElementProviderFragment, "f7063da8-8359-439c-9297-bbc5299a7d87") : public IUnknown
 | 
			
		||||
{
 | 
			
		||||
public:
 | 
			
		||||
    JUCE_COMCALL Navigate (NavigateDirection direction, __RPC__deref_out_opt IRawElementProviderFragment** pRetVal) = 0;
 | 
			
		||||
    JUCE_COMCALL GetRuntimeId (__RPC__deref_out_opt SAFEARRAY * *pRetVal) = 0;
 | 
			
		||||
    JUCE_COMCALL get_BoundingRectangle (__RPC__out UiaRect * pRetVal) = 0;
 | 
			
		||||
    JUCE_COMCALL GetEmbeddedFragmentRoots (__RPC__deref_out_opt SAFEARRAY * *pRetVal) = 0;
 | 
			
		||||
    JUCE_COMCALL SetFocus() = 0;
 | 
			
		||||
    JUCE_COMCALL get_FragmentRoot (__RPC__deref_out_opt IRawElementProviderFragmentRoot * *pRetVal) = 0;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
JUCE_COMCLASS (IExpandCollapseProvider, "d847d3a5-cab0-4a98-8c32-ecb45c59ad24") : public IUnknown
 | 
			
		||||
{
 | 
			
		||||
public:
 | 
			
		||||
    JUCE_COMCALL Expand() = 0;
 | 
			
		||||
    JUCE_COMCALL Collapse() = 0;
 | 
			
		||||
    JUCE_COMCALL get_ExpandCollapseState (__RPC__out ExpandCollapseState * pRetVal) = 0;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
JUCE_COMCLASS (IGridItemProvider, "d02541f1-fb81-4d64-ae32-f520f8a6dbd1") : public IUnknown
 | 
			
		||||
{
 | 
			
		||||
public:
 | 
			
		||||
    JUCE_COMCALL get_Row (__RPC__out int* pRetVal) = 0;
 | 
			
		||||
    JUCE_COMCALL get_Column (__RPC__out int* pRetVal) = 0;
 | 
			
		||||
    JUCE_COMCALL get_RowSpan (__RPC__out int* pRetVal) = 0;
 | 
			
		||||
    JUCE_COMCALL get_ColumnSpan (__RPC__out int* pRetVal) = 0;
 | 
			
		||||
    JUCE_COMCALL get_ContainingGrid (__RPC__deref_out_opt IRawElementProviderSimple * *pRetVal) = 0;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
JUCE_COMCLASS (IGridProvider, "b17d6187-0907-464b-a168-0ef17a1572b1") : public IUnknown
 | 
			
		||||
{
 | 
			
		||||
public:
 | 
			
		||||
    JUCE_COMCALL GetItem (int row, int column, __RPC__deref_out_opt IRawElementProviderSimple** pRetVal) = 0;
 | 
			
		||||
    JUCE_COMCALL get_RowCount (__RPC__out int* pRetVal) = 0;
 | 
			
		||||
    JUCE_COMCALL get_ColumnCount (__RPC__out int* pRetVal) = 0;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
JUCE_COMCLASS (ITableItemProvider, "b9734fa6-771f-4d78-9c90-2517999349cd") : public IUnknown
 | 
			
		||||
{
 | 
			
		||||
public:
 | 
			
		||||
    JUCE_COMCALL GetRowHeaderItems (SAFEARRAY** pRetVal) = 0;
 | 
			
		||||
    JUCE_COMCALL GetColumnHeaderItems (SAFEARRAY** pRetVal) = 0;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
JUCE_COMCLASS (ITableProvider, "9c860395-97b3-490a-b52a-858cc22af166") : public IUnknown
 | 
			
		||||
{
 | 
			
		||||
public:
 | 
			
		||||
    JUCE_COMCALL GetRowHeaders (SAFEARRAY** pRetVal) = 0;
 | 
			
		||||
    JUCE_COMCALL GetColumnHeaders (SAFEARRAY** pRetVal) = 0;
 | 
			
		||||
    JUCE_COMCALL get_RowOrColumnMajor (RowOrColumnMajor* pRetVal) = 0;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
JUCE_COMCLASS (IInvokeProvider, "54fcb24b-e18e-47a2-b4d3-eccbe77599a2") : public IUnknown
 | 
			
		||||
{
 | 
			
		||||
public:
 | 
			
		||||
    JUCE_COMCALL Invoke() = 0;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
JUCE_COMCLASS (IRangeValueProvider, "36dc7aef-33e6-4691-afe1-2be7274b3d33") : public IUnknown
 | 
			
		||||
{
 | 
			
		||||
public:
 | 
			
		||||
    JUCE_COMCALL SetValue (double val) = 0;
 | 
			
		||||
    JUCE_COMCALL get_Value (__RPC__out double* pRetVal) = 0;
 | 
			
		||||
    JUCE_COMCALL get_IsReadOnly (__RPC__out BOOL * pRetVal) = 0;
 | 
			
		||||
    JUCE_COMCALL get_Maximum (__RPC__out double* pRetVal) = 0;
 | 
			
		||||
    JUCE_COMCALL get_Minimum (__RPC__out double* pRetVal) = 0;
 | 
			
		||||
    JUCE_COMCALL get_LargeChange (__RPC__out double* pRetVal) = 0;
 | 
			
		||||
    JUCE_COMCALL get_SmallChange (__RPC__out double* pRetVal) = 0;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
JUCE_COMCLASS (ISelectionProvider, "fb8b03af-3bdf-48d4-bd36-1a65793be168") : public IUnknown
 | 
			
		||||
{
 | 
			
		||||
public:
 | 
			
		||||
    JUCE_COMCALL GetSelection (__RPC__deref_out_opt SAFEARRAY * *pRetVal) = 0;
 | 
			
		||||
    JUCE_COMCALL get_CanSelectMultiple (__RPC__out BOOL * pRetVal) = 0;
 | 
			
		||||
    JUCE_COMCALL get_IsSelectionRequired (__RPC__out BOOL * pRetVal) = 0;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
JUCE_COMCLASS (ISelectionProvider2, "14f68475-ee1c-44f6-a869-d239381f0fe7") : public ISelectionProvider
 | 
			
		||||
{
 | 
			
		||||
    JUCE_COMCALL get_FirstSelectedItem (IRawElementProviderSimple * *retVal) = 0;
 | 
			
		||||
    JUCE_COMCALL get_LastSelectedItem (IRawElementProviderSimple * *retVal) = 0;
 | 
			
		||||
    JUCE_COMCALL get_CurrentSelectedItem (IRawElementProviderSimple * *retVal) = 0;
 | 
			
		||||
    JUCE_COMCALL get_ItemCount (int* retVal) = 0;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
JUCE_COMCLASS (ISelectionItemProvider, "2acad808-b2d4-452d-a407-91ff1ad167b2") : public IUnknown
 | 
			
		||||
{
 | 
			
		||||
public:
 | 
			
		||||
    JUCE_COMCALL Select() = 0;
 | 
			
		||||
    JUCE_COMCALL AddToSelection() = 0;
 | 
			
		||||
    JUCE_COMCALL RemoveFromSelection() = 0;
 | 
			
		||||
    JUCE_COMCALL get_IsSelected (__RPC__out BOOL * pRetVal) = 0;
 | 
			
		||||
    JUCE_COMCALL get_SelectionContainer (__RPC__deref_out_opt IRawElementProviderSimple * *pRetVal) = 0;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
JUCE_COMCLASS (ITextRangeProvider, "5347ad7b-c355-46f8-aff5-909033582f63") : public IUnknown
 | 
			
		||||
{
 | 
			
		||||
public:
 | 
			
		||||
    JUCE_COMCALL Clone (__RPC__deref_out_opt ITextRangeProvider * *pRetVal) = 0;
 | 
			
		||||
    JUCE_COMCALL Compare (__RPC__in_opt ITextRangeProvider * range, __RPC__out BOOL * pRetVal) = 0;
 | 
			
		||||
    JUCE_COMCALL CompareEndpoints (TextPatternRangeEndpoint endpoint, __RPC__in_opt ITextRangeProvider * targetRange, TextPatternRangeEndpoint targetEndpoint, __RPC__out int* pRetVal) = 0;
 | 
			
		||||
    JUCE_COMCALL ExpandToEnclosingUnit (TextUnit unit) = 0;
 | 
			
		||||
    JUCE_COMCALL FindAttribute (TEXTATTRIBUTEID attributeId, VARIANT val, BOOL backward, __RPC__deref_out_opt ITextRangeProvider * *pRetVal) = 0;
 | 
			
		||||
    JUCE_COMCALL FindText (__RPC__in BSTR text, BOOL backward, BOOL ignoreCase, __RPC__deref_out_opt ITextRangeProvider * *pRetVal) = 0;
 | 
			
		||||
    JUCE_COMCALL GetAttributeValue (TEXTATTRIBUTEID attributeId, __RPC__out VARIANT * pRetVal) = 0;
 | 
			
		||||
    JUCE_COMCALL GetBoundingRectangles (__RPC__deref_out_opt SAFEARRAY * *pRetVal) = 0;
 | 
			
		||||
    JUCE_COMCALL GetEnclosingElement (__RPC__deref_out_opt IRawElementProviderSimple * *pRetVal) = 0;
 | 
			
		||||
    JUCE_COMCALL GetText (int maxLength, __RPC__deref_out_opt BSTR* pRetVal) = 0;
 | 
			
		||||
    JUCE_COMCALL Move (TextUnit unit, int count, __RPC__out int* pRetVal) = 0;
 | 
			
		||||
    JUCE_COMCALL MoveEndpointByUnit (TextPatternRangeEndpoint endpoint, TextUnit unit, int count, __RPC__out int* pRetVal) = 0;
 | 
			
		||||
    JUCE_COMCALL MoveEndpointByRange (TextPatternRangeEndpoint endpoint, __RPC__in_opt ITextRangeProvider * targetRange, TextPatternRangeEndpoint targetEndpoint) = 0;
 | 
			
		||||
    JUCE_COMCALL Select() = 0;
 | 
			
		||||
    JUCE_COMCALL AddToSelection() = 0;
 | 
			
		||||
    JUCE_COMCALL RemoveFromSelection() = 0;
 | 
			
		||||
    JUCE_COMCALL ScrollIntoView (BOOL alignToTop) = 0;
 | 
			
		||||
    JUCE_COMCALL GetChildren (__RPC__deref_out_opt SAFEARRAY * *pRetVal) = 0;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
JUCE_COMCLASS (ITextProvider, "3589c92c-63f3-4367-99bb-ada653b77cf2") : public IUnknown
 | 
			
		||||
{
 | 
			
		||||
public:
 | 
			
		||||
    JUCE_COMCALL GetSelection (__RPC__deref_out_opt SAFEARRAY * *pRetVal) = 0;
 | 
			
		||||
    JUCE_COMCALL GetVisibleRanges (__RPC__deref_out_opt SAFEARRAY * *pRetVal) = 0;
 | 
			
		||||
    JUCE_COMCALL RangeFromChild (__RPC__in_opt IRawElementProviderSimple * childElement, __RPC__deref_out_opt ITextRangeProvider * *pRetVal) = 0;
 | 
			
		||||
    JUCE_COMCALL RangeFromPoint (UiaPoint point, __RPC__deref_out_opt ITextRangeProvider * *pRetVal) = 0;
 | 
			
		||||
    JUCE_COMCALL get_DocumentRange (__RPC__deref_out_opt ITextRangeProvider * *pRetVal) = 0;
 | 
			
		||||
    JUCE_COMCALL get_SupportedTextSelection (__RPC__out SupportedTextSelection * pRetVal) = 0;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
JUCE_COMCLASS (ITextProvider2, "0dc5e6ed-3e16-4bf1-8f9a-a979878bc195") : public ITextProvider
 | 
			
		||||
{
 | 
			
		||||
public:
 | 
			
		||||
    JUCE_COMCALL RangeFromAnnotation (__RPC__in_opt IRawElementProviderSimple * annotationElement, __RPC__deref_out_opt ITextRangeProvider * *pRetVal) = 0;
 | 
			
		||||
    JUCE_COMCALL GetCaretRange (__RPC__out BOOL * isActive, __RPC__deref_out_opt ITextRangeProvider * *pRetVal) = 0;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
JUCE_COMCLASS (IToggleProvider, "56d00bd0-c4f4-433c-a836-1a52a57e0892") : public IUnknown
 | 
			
		||||
{
 | 
			
		||||
public:
 | 
			
		||||
    JUCE_COMCALL Toggle() = 0;
 | 
			
		||||
    JUCE_COMCALL get_ToggleState (__RPC__out ToggleState * pRetVal) = 0;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
JUCE_COMCLASS (ITransformProvider, "6829ddc4-4f91-4ffa-b86f-bd3e2987cb4c") : public IUnknown
 | 
			
		||||
{
 | 
			
		||||
public:
 | 
			
		||||
    JUCE_COMCALL Move (double x, double y) = 0;
 | 
			
		||||
    JUCE_COMCALL Resize (double width, double height) = 0;
 | 
			
		||||
    JUCE_COMCALL Rotate (double degrees) = 0;
 | 
			
		||||
    JUCE_COMCALL get_CanMove (__RPC__out BOOL * pRetVal) = 0;
 | 
			
		||||
    JUCE_COMCALL get_CanResize (__RPC__out BOOL * pRetVal) = 0;
 | 
			
		||||
    JUCE_COMCALL get_CanRotate (__RPC__out BOOL * pRetVal) = 0;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
JUCE_COMCLASS (IValueProvider, "c7935180-6fb3-4201-b174-7df73adbf64a") : public IUnknown
 | 
			
		||||
{
 | 
			
		||||
public:
 | 
			
		||||
    JUCE_COMCALL SetValue (__RPC__in LPCWSTR val) = 0;
 | 
			
		||||
    JUCE_COMCALL get_Value (__RPC__deref_out_opt BSTR * pRetVal) = 0;
 | 
			
		||||
    JUCE_COMCALL get_IsReadOnly (__RPC__out BOOL * pRetVal) = 0;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
JUCE_COMCLASS (IWindowProvider, "987df77b-db06-4d77-8f8a-86a9c3bb90b9") : public IUnknown
 | 
			
		||||
{
 | 
			
		||||
public:
 | 
			
		||||
    JUCE_COMCALL SetVisualState (WindowVisualState state) = 0;
 | 
			
		||||
    JUCE_COMCALL Close() = 0;
 | 
			
		||||
    JUCE_COMCALL WaitForInputIdle (int milliseconds, __RPC__out BOOL* pRetVal) = 0;
 | 
			
		||||
    JUCE_COMCALL get_CanMaximize (__RPC__out BOOL * pRetVal) = 0;
 | 
			
		||||
    JUCE_COMCALL get_CanMinimize (__RPC__out BOOL * pRetVal) = 0;
 | 
			
		||||
    JUCE_COMCALL get_IsModal (__RPC__out BOOL * pRetVal) = 0;
 | 
			
		||||
    JUCE_COMCALL get_WindowVisualState (__RPC__out WindowVisualState * pRetVal) = 0;
 | 
			
		||||
    JUCE_COMCALL get_WindowInteractionState (__RPC__out WindowInteractionState * pRetVal) = 0;
 | 
			
		||||
    JUCE_COMCALL get_IsTopmost (__RPC__out BOOL * pRetVal) = 0;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
JUCE_COMCLASS (IScrollProvider, "b38b8077-1fc3-42a5-8cae-d40c2215055a") : public IUnknown
 | 
			
		||||
{
 | 
			
		||||
public:
 | 
			
		||||
    JUCE_COMCALL Scroll (ScrollAmount horizontalAmount, ScrollAmount verticalAmount) = 0;
 | 
			
		||||
    JUCE_COMCALL SetScrollPercent (double horizontalPercent,double verticalPercent) = 0;
 | 
			
		||||
    JUCE_COMCALL get_HorizontalScrollPercent (double* pRetVal) = 0;
 | 
			
		||||
    JUCE_COMCALL get_VerticalScrollPercent (double* pRetVal) = 0;
 | 
			
		||||
    JUCE_COMCALL get_HorizontalViewSize (double* pRetVal) = 0;
 | 
			
		||||
    JUCE_COMCALL get_VerticalViewSize (double* pRetVal) = 0;
 | 
			
		||||
    JUCE_COMCALL get_HorizontallyScrollable (BOOL* pRetVal) = 0;
 | 
			
		||||
    JUCE_COMCALL get_VerticallyScrollable (BOOL* pRetVal) = 0;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
JUCE_COMCLASS (IScrollItemProvider, "2360c714-4bf1-4b26-ba65-9b21316127eb")  : public IUnknown
 | 
			
		||||
{
 | 
			
		||||
public:
 | 
			
		||||
    JUCE_COMCALL ScrollIntoView() = 0;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
constexpr CLSID CLSID_SpVoice { 0x96749377, 0x3391, 0x11D2, { 0x9E, 0xE3, 0x00, 0xC0, 0x4F, 0x79, 0x73, 0x96 } };
 | 
			
		||||
 | 
			
		||||
} // namespace ComTypes
 | 
			
		||||
} // namespace juce
 | 
			
		||||
 | 
			
		||||
#ifdef __CRT_UUID_DECL
 | 
			
		||||
__CRT_UUID_DECL (juce::ComTypes::IRawElementProviderFragmentRoot, 0x620ce2a5, 0xab8f, 0x40a9, 0x86, 0xcb, 0xde, 0x3c, 0x75, 0x59, 0x9b, 0x58)
 | 
			
		||||
__CRT_UUID_DECL (juce::ComTypes::IRawElementProviderFragment,     0xf7063da8, 0x8359, 0x439c, 0x92, 0x97, 0xbb, 0xc5, 0x29, 0x9a, 0x7d, 0x87)
 | 
			
		||||
__CRT_UUID_DECL (juce::ComTypes::IExpandCollapseProvider,         0xd847d3a5, 0xcab0, 0x4a98, 0x8c, 0x32, 0xec, 0xb4, 0x5c, 0x59, 0xad, 0x24)
 | 
			
		||||
__CRT_UUID_DECL (juce::ComTypes::IGridItemProvider,               0xd02541f1, 0xfb81, 0x4d64, 0xae, 0x32, 0xf5, 0x20, 0xf8, 0xa6, 0xdb, 0xd1)
 | 
			
		||||
__CRT_UUID_DECL (juce::ComTypes::IGridProvider,                   0xb17d6187, 0x0907, 0x464b, 0xa1, 0x68, 0x0e, 0xf1, 0x7a, 0x15, 0x72, 0xb1)
 | 
			
		||||
__CRT_UUID_DECL (juce::ComTypes::IInvokeProvider,                 0x54fcb24b, 0xe18e, 0x47a2, 0xb4, 0xd3, 0xec, 0xcb, 0xe7, 0x75, 0x99, 0xa2)
 | 
			
		||||
__CRT_UUID_DECL (juce::ComTypes::IRangeValueProvider,             0x36dc7aef, 0x33e6, 0x4691, 0xaf, 0xe1, 0x2b, 0xe7, 0x27, 0x4b, 0x3d, 0x33)
 | 
			
		||||
__CRT_UUID_DECL (juce::ComTypes::ISelectionProvider,              0xfb8b03af, 0x3bdf, 0x48d4, 0xbd, 0x36, 0x1a, 0x65, 0x79, 0x3b, 0xe1, 0x68)
 | 
			
		||||
__CRT_UUID_DECL (juce::ComTypes::ISelectionProvider2,             0x14f68475, 0xee1c, 0x44f6, 0xa8, 0x69, 0xd2, 0x39, 0x38, 0x1f, 0x0f, 0xe7)
 | 
			
		||||
__CRT_UUID_DECL (juce::ComTypes::ISelectionItemProvider,          0x2acad808, 0xb2d4, 0x452d, 0xa4, 0x07, 0x91, 0xff, 0x1a, 0xd1, 0x67, 0xb2)
 | 
			
		||||
__CRT_UUID_DECL (juce::ComTypes::ITextRangeProvider,              0x5347ad7b, 0xc355, 0x46f8, 0xaf, 0xf5, 0x90, 0x90, 0x33, 0x58, 0x2f, 0x63)
 | 
			
		||||
__CRT_UUID_DECL (juce::ComTypes::ITextProvider,                   0x3589c92c, 0x63f3, 0x4367, 0x99, 0xbb, 0xad, 0xa6, 0x53, 0xb7, 0x7c, 0xf2)
 | 
			
		||||
__CRT_UUID_DECL (juce::ComTypes::ITextProvider2,                  0x0dc5e6ed, 0x3e16, 0x4bf1, 0x8f, 0x9a, 0xa9, 0x79, 0x87, 0x8b, 0xc1, 0x95)
 | 
			
		||||
__CRT_UUID_DECL (juce::ComTypes::IToggleProvider,                 0x56d00bd0, 0xc4f4, 0x433c, 0xa8, 0x36, 0x1a, 0x52, 0xa5, 0x7e, 0x08, 0x92)
 | 
			
		||||
__CRT_UUID_DECL (juce::ComTypes::ITransformProvider,              0x6829ddc4, 0x4f91, 0x4ffa, 0xb8, 0x6f, 0xbd, 0x3e, 0x29, 0x87, 0xcb, 0x4c)
 | 
			
		||||
__CRT_UUID_DECL (juce::ComTypes::IValueProvider,                  0xc7935180, 0x6fb3, 0x4201, 0xb1, 0x74, 0x7d, 0xf7, 0x3a, 0xdb, 0xf6, 0x4a)
 | 
			
		||||
__CRT_UUID_DECL (juce::ComTypes::IWindowProvider,                 0x987df77b, 0xdb06, 0x4d77, 0x8f, 0x8a, 0x86, 0xa9, 0xc3, 0xbb, 0x90, 0xb9)
 | 
			
		||||
__CRT_UUID_DECL (juce::ComTypes::ITableItemProvider,              0xb9734fa6, 0x771f, 0x4d78, 0x9c, 0x90, 0x25, 0x17, 0x99, 0x93, 0x49, 0xcd)
 | 
			
		||||
__CRT_UUID_DECL (juce::ComTypes::ITableProvider,                  0x9c860395, 0x97b3, 0x490a, 0xb5, 0x2a, 0x85, 0x8c, 0xc2, 0x2a, 0xf1, 0x66)
 | 
			
		||||
__CRT_UUID_DECL (juce::ComTypes::IScrollProvider,                 0xb38b8077, 0x1fc3, 0x42a5, 0x8c, 0xae, 0xd4, 0x0c, 0x22, 0x15, 0x05, 0x5a)
 | 
			
		||||
__CRT_UUID_DECL (juce::ComTypes::IScrollItemProvider,             0x2360c714, 0x4bf1, 0x4b26, 0xba, 0x65, 0x9b, 0x21, 0x31, 0x61, 0x27, 0xeb)
 | 
			
		||||
#endif
 | 
			
		||||
@@ -1,86 +1,83 @@
 | 
			
		||||
/*
 | 
			
		||||
  ==============================================================================
 | 
			
		||||
 | 
			
		||||
   This file is part of the JUCE library.
 | 
			
		||||
   Copyright (c) 2020 - Raw Material Software Limited
 | 
			
		||||
 | 
			
		||||
   JUCE is an open source library subject to commercial or open-source
 | 
			
		||||
   licensing.
 | 
			
		||||
 | 
			
		||||
   By using JUCE, you agree to the terms of both the JUCE 6 End-User License
 | 
			
		||||
   Agreement and JUCE Privacy Policy (both effective as of the 16th June 2020).
 | 
			
		||||
 | 
			
		||||
   End User License Agreement: www.juce.com/juce-6-licence
 | 
			
		||||
   Privacy Policy: www.juce.com/juce-privacy-policy
 | 
			
		||||
 | 
			
		||||
   Or: You may also use this code under the terms of the GPL v3 (see
 | 
			
		||||
   www.gnu.org/licenses).
 | 
			
		||||
 | 
			
		||||
   JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
 | 
			
		||||
   EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
 | 
			
		||||
   DISCLAIMED.
 | 
			
		||||
 | 
			
		||||
  ==============================================================================
 | 
			
		||||
*/
 | 
			
		||||
 | 
			
		||||
namespace juce
 | 
			
		||||
{
 | 
			
		||||
 | 
			
		||||
//==============================================================================
 | 
			
		||||
class UIAExpandCollapseProvider  : public UIAProviderBase,
 | 
			
		||||
                                   public ComBaseClassHelper<IExpandCollapseProvider>
 | 
			
		||||
{
 | 
			
		||||
public:
 | 
			
		||||
    explicit UIAExpandCollapseProvider (AccessibilityNativeHandle* nativeHandle)
 | 
			
		||||
        : UIAProviderBase (nativeHandle)
 | 
			
		||||
    {
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    //==============================================================================
 | 
			
		||||
    JUCE_COMRESULT Expand() override
 | 
			
		||||
    {
 | 
			
		||||
        return invokeShowMenu();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    JUCE_COMRESULT Collapse() override
 | 
			
		||||
    {
 | 
			
		||||
        return invokeShowMenu();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    JUCE_COMRESULT get_ExpandCollapseState (ExpandCollapseState* pRetVal) override
 | 
			
		||||
    {
 | 
			
		||||
        return withCheckedComArgs (pRetVal, *this, [&]
 | 
			
		||||
        {
 | 
			
		||||
            *pRetVal = getHandler().getCurrentState().isExpanded()
 | 
			
		||||
                           ? ExpandCollapseState_Expanded
 | 
			
		||||
                           : ExpandCollapseState_Collapsed;
 | 
			
		||||
 | 
			
		||||
            return S_OK;
 | 
			
		||||
        });
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
private:
 | 
			
		||||
    JUCE_COMRESULT invokeShowMenu()
 | 
			
		||||
    {
 | 
			
		||||
        if (! isElementValid())
 | 
			
		||||
            return (HRESULT) UIA_E_ELEMENTNOTAVAILABLE;
 | 
			
		||||
 | 
			
		||||
        const auto& handler = getHandler();
 | 
			
		||||
 | 
			
		||||
        if (handler.getActions().invoke (AccessibilityActionType::showMenu))
 | 
			
		||||
        {
 | 
			
		||||
            sendAccessibilityAutomationEvent (handler, handler.getCurrentState().isExpanded()
 | 
			
		||||
                                                           ? UIA_MenuOpenedEventId
 | 
			
		||||
                                                           : UIA_MenuClosedEventId);
 | 
			
		||||
 | 
			
		||||
            return S_OK;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        return (HRESULT) UIA_E_NOTSUPPORTED;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    //==============================================================================
 | 
			
		||||
    JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (UIAExpandCollapseProvider)
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
} // namespace juce
 | 
			
		||||
/*
 | 
			
		||||
  ==============================================================================
 | 
			
		||||
 | 
			
		||||
   This file is part of the JUCE library.
 | 
			
		||||
   Copyright (c) 2022 - Raw Material Software Limited
 | 
			
		||||
 | 
			
		||||
   JUCE is an open source library subject to commercial or open-source
 | 
			
		||||
   licensing.
 | 
			
		||||
 | 
			
		||||
   By using JUCE, you agree to the terms of both the JUCE 7 End-User License
 | 
			
		||||
   Agreement and JUCE Privacy Policy.
 | 
			
		||||
 | 
			
		||||
   End User License Agreement: www.juce.com/juce-7-licence
 | 
			
		||||
   Privacy Policy: www.juce.com/juce-privacy-policy
 | 
			
		||||
 | 
			
		||||
   Or: You may also use this code under the terms of the GPL v3 (see
 | 
			
		||||
   www.gnu.org/licenses).
 | 
			
		||||
 | 
			
		||||
   JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
 | 
			
		||||
   EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
 | 
			
		||||
   DISCLAIMED.
 | 
			
		||||
 | 
			
		||||
  ==============================================================================
 | 
			
		||||
*/
 | 
			
		||||
 | 
			
		||||
namespace juce
 | 
			
		||||
{
 | 
			
		||||
 | 
			
		||||
//==============================================================================
 | 
			
		||||
class UIAExpandCollapseProvider  : public UIAProviderBase,
 | 
			
		||||
                                   public ComBaseClassHelper<ComTypes::IExpandCollapseProvider>
 | 
			
		||||
{
 | 
			
		||||
public:
 | 
			
		||||
    using UIAProviderBase::UIAProviderBase;
 | 
			
		||||
 | 
			
		||||
    //==============================================================================
 | 
			
		||||
    JUCE_COMRESULT Expand() override
 | 
			
		||||
    {
 | 
			
		||||
        return invokeShowMenu();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    JUCE_COMRESULT Collapse() override
 | 
			
		||||
    {
 | 
			
		||||
        return invokeShowMenu();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    JUCE_COMRESULT get_ExpandCollapseState (ComTypes::ExpandCollapseState* pRetVal) override
 | 
			
		||||
    {
 | 
			
		||||
        return withCheckedComArgs (pRetVal, *this, [&]
 | 
			
		||||
        {
 | 
			
		||||
            *pRetVal = getHandler().getCurrentState().isExpanded()
 | 
			
		||||
                           ? ComTypes::ExpandCollapseState_Expanded
 | 
			
		||||
                           : ComTypes::ExpandCollapseState_Collapsed;
 | 
			
		||||
 | 
			
		||||
            return S_OK;
 | 
			
		||||
        });
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
private:
 | 
			
		||||
    JUCE_COMRESULT invokeShowMenu()
 | 
			
		||||
    {
 | 
			
		||||
        if (! isElementValid())
 | 
			
		||||
            return (HRESULT) UIA_E_ELEMENTNOTAVAILABLE;
 | 
			
		||||
 | 
			
		||||
        const auto& handler = getHandler();
 | 
			
		||||
 | 
			
		||||
        if (handler.getActions().invoke (AccessibilityActionType::showMenu))
 | 
			
		||||
        {
 | 
			
		||||
            sendAccessibilityAutomationEvent (handler, handler.getCurrentState().isExpanded()
 | 
			
		||||
                                                           ? ComTypes::UIA_MenuOpenedEventId
 | 
			
		||||
                                                           : ComTypes::UIA_MenuClosedEventId);
 | 
			
		||||
 | 
			
		||||
            return S_OK;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        return (HRESULT) UIA_E_NOTSUPPORTED;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    //==============================================================================
 | 
			
		||||
    JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (UIAExpandCollapseProvider)
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
} // namespace juce
 | 
			
		||||
 
 | 
			
		||||
@@ -1,105 +1,153 @@
 | 
			
		||||
/*
 | 
			
		||||
  ==============================================================================
 | 
			
		||||
 | 
			
		||||
   This file is part of the JUCE library.
 | 
			
		||||
   Copyright (c) 2020 - Raw Material Software Limited
 | 
			
		||||
 | 
			
		||||
   JUCE is an open source library subject to commercial or open-source
 | 
			
		||||
   licensing.
 | 
			
		||||
 | 
			
		||||
   By using JUCE, you agree to the terms of both the JUCE 6 End-User License
 | 
			
		||||
   Agreement and JUCE Privacy Policy (both effective as of the 16th June 2020).
 | 
			
		||||
 | 
			
		||||
   End User License Agreement: www.juce.com/juce-6-licence
 | 
			
		||||
   Privacy Policy: www.juce.com/juce-privacy-policy
 | 
			
		||||
 | 
			
		||||
   Or: You may also use this code under the terms of the GPL v3 (see
 | 
			
		||||
   www.gnu.org/licenses).
 | 
			
		||||
 | 
			
		||||
   JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
 | 
			
		||||
   EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
 | 
			
		||||
   DISCLAIMED.
 | 
			
		||||
 | 
			
		||||
  ==============================================================================
 | 
			
		||||
*/
 | 
			
		||||
 | 
			
		||||
namespace juce
 | 
			
		||||
{
 | 
			
		||||
 | 
			
		||||
//==============================================================================
 | 
			
		||||
class UIAGridItemProvider  : public UIAProviderBase,
 | 
			
		||||
                             public ComBaseClassHelper<IGridItemProvider>
 | 
			
		||||
{
 | 
			
		||||
public:
 | 
			
		||||
    explicit UIAGridItemProvider (AccessibilityNativeHandle* nativeHandle)
 | 
			
		||||
        : UIAProviderBase (nativeHandle)
 | 
			
		||||
    {
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    //==============================================================================
 | 
			
		||||
    JUCE_COMRESULT get_Row (int* pRetVal) override
 | 
			
		||||
    {
 | 
			
		||||
        return withCellInterface (pRetVal, [&] (const AccessibilityCellInterface& cellInterface)
 | 
			
		||||
        {
 | 
			
		||||
            *pRetVal = cellInterface.getRowIndex();
 | 
			
		||||
        });
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    JUCE_COMRESULT get_Column (int* pRetVal) override
 | 
			
		||||
    {
 | 
			
		||||
        return withCellInterface (pRetVal, [&] (const AccessibilityCellInterface& cellInterface)
 | 
			
		||||
        {
 | 
			
		||||
            *pRetVal = cellInterface.getColumnIndex();
 | 
			
		||||
        });
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    JUCE_COMRESULT get_RowSpan (int* pRetVal) override
 | 
			
		||||
    {
 | 
			
		||||
        return withCellInterface (pRetVal, [&] (const AccessibilityCellInterface& cellInterface)
 | 
			
		||||
        {
 | 
			
		||||
            *pRetVal = cellInterface.getRowSpan();
 | 
			
		||||
        });
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    JUCE_COMRESULT get_ColumnSpan (int* pRetVal) override
 | 
			
		||||
    {
 | 
			
		||||
        return withCellInterface (pRetVal, [&] (const AccessibilityCellInterface& cellInterface)
 | 
			
		||||
        {
 | 
			
		||||
            *pRetVal = cellInterface.getColumnSpan();
 | 
			
		||||
        });
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    JUCE_COMRESULT get_ContainingGrid (IRawElementProviderSimple** pRetVal) override
 | 
			
		||||
    {
 | 
			
		||||
        return withCellInterface (pRetVal, [&] (const AccessibilityCellInterface& cellInterface)
 | 
			
		||||
        {
 | 
			
		||||
            JUCE_BEGIN_IGNORE_WARNINGS_GCC_LIKE ("-Wlanguage-extension-token")
 | 
			
		||||
 | 
			
		||||
            if (auto* handler = cellInterface.getTableHandler())
 | 
			
		||||
                handler->getNativeImplementation()->QueryInterface (IID_PPV_ARGS (pRetVal));
 | 
			
		||||
 | 
			
		||||
            JUCE_END_IGNORE_WARNINGS_GCC_LIKE
 | 
			
		||||
        });
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
private:
 | 
			
		||||
    template <typename Value, typename Callback>
 | 
			
		||||
    JUCE_COMRESULT withCellInterface (Value* pRetVal, Callback&& callback) const
 | 
			
		||||
    {
 | 
			
		||||
        return withCheckedComArgs (pRetVal, *this, [&]() -> HRESULT
 | 
			
		||||
        {
 | 
			
		||||
            if (auto* cellInterface = getHandler().getCellInterface())
 | 
			
		||||
            {
 | 
			
		||||
                callback (*cellInterface);
 | 
			
		||||
                return S_OK;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            return (HRESULT) UIA_E_NOTSUPPORTED;
 | 
			
		||||
        });
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    //==============================================================================
 | 
			
		||||
    JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (UIAGridItemProvider)
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
} // namespace juce
 | 
			
		||||
/*
 | 
			
		||||
  ==============================================================================
 | 
			
		||||
 | 
			
		||||
   This file is part of the JUCE library.
 | 
			
		||||
   Copyright (c) 2022 - Raw Material Software Limited
 | 
			
		||||
 | 
			
		||||
   JUCE is an open source library subject to commercial or open-source
 | 
			
		||||
   licensing.
 | 
			
		||||
 | 
			
		||||
   By using JUCE, you agree to the terms of both the JUCE 7 End-User License
 | 
			
		||||
   Agreement and JUCE Privacy Policy.
 | 
			
		||||
 | 
			
		||||
   End User License Agreement: www.juce.com/juce-7-licence
 | 
			
		||||
   Privacy Policy: www.juce.com/juce-privacy-policy
 | 
			
		||||
 | 
			
		||||
   Or: You may also use this code under the terms of the GPL v3 (see
 | 
			
		||||
   www.gnu.org/licenses).
 | 
			
		||||
 | 
			
		||||
   JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
 | 
			
		||||
   EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
 | 
			
		||||
   DISCLAIMED.
 | 
			
		||||
 | 
			
		||||
  ==============================================================================
 | 
			
		||||
*/
 | 
			
		||||
 | 
			
		||||
namespace juce
 | 
			
		||||
{
 | 
			
		||||
 | 
			
		||||
//==============================================================================
 | 
			
		||||
class UIAGridItemProvider  : public UIAProviderBase,
 | 
			
		||||
                             public ComBaseClassHelper<ComTypes::IGridItemProvider, ComTypes::ITableItemProvider>
 | 
			
		||||
{
 | 
			
		||||
public:
 | 
			
		||||
    using UIAProviderBase::UIAProviderBase;
 | 
			
		||||
 | 
			
		||||
    //==============================================================================
 | 
			
		||||
    JUCE_COMRESULT get_Row (int* pRetVal) override
 | 
			
		||||
    {
 | 
			
		||||
        return withTableSpan (pRetVal,
 | 
			
		||||
                              &AccessibilityTableInterface::getRowSpan,
 | 
			
		||||
                              &AccessibilityTableInterface::Span::begin);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    JUCE_COMRESULT get_Column (int* pRetVal) override
 | 
			
		||||
    {
 | 
			
		||||
        return withTableSpan (pRetVal,
 | 
			
		||||
                              &AccessibilityTableInterface::getColumnSpan,
 | 
			
		||||
                              &AccessibilityTableInterface::Span::begin);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    JUCE_COMRESULT get_RowSpan (int* pRetVal) override
 | 
			
		||||
    {
 | 
			
		||||
        return withTableSpan (pRetVal,
 | 
			
		||||
                              &AccessibilityTableInterface::getRowSpan,
 | 
			
		||||
                              &AccessibilityTableInterface::Span::num);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    JUCE_COMRESULT get_ColumnSpan (int* pRetVal) override
 | 
			
		||||
    {
 | 
			
		||||
        return withTableSpan (pRetVal,
 | 
			
		||||
                              &AccessibilityTableInterface::getColumnSpan,
 | 
			
		||||
                              &AccessibilityTableInterface::Span::num);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    JUCE_COMRESULT get_ContainingGrid (IRawElementProviderSimple** pRetVal) override
 | 
			
		||||
    {
 | 
			
		||||
        return withTableInterface (pRetVal, [&] (const AccessibilityHandler& tableHandler)
 | 
			
		||||
        {
 | 
			
		||||
            JUCE_BEGIN_IGNORE_WARNINGS_GCC_LIKE ("-Wlanguage-extension-token")
 | 
			
		||||
            tableHandler.getNativeImplementation()->QueryInterface (IID_PPV_ARGS (pRetVal));
 | 
			
		||||
            JUCE_END_IGNORE_WARNINGS_GCC_LIKE
 | 
			
		||||
 | 
			
		||||
            return true;
 | 
			
		||||
        });
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    JUCE_COMRESULT GetRowHeaderItems (SAFEARRAY**) override
 | 
			
		||||
    {
 | 
			
		||||
        return (HRESULT) UIA_E_NOTSUPPORTED;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    JUCE_COMRESULT GetColumnHeaderItems (SAFEARRAY** pRetVal) override
 | 
			
		||||
    {
 | 
			
		||||
        return withTableInterface (pRetVal, [&] (const AccessibilityHandler& tableHandler)
 | 
			
		||||
        {
 | 
			
		||||
            if (auto* tableInterface = tableHandler.getTableInterface())
 | 
			
		||||
            {
 | 
			
		||||
                if (const auto column = tableInterface->getColumnSpan (getHandler()))
 | 
			
		||||
                {
 | 
			
		||||
                    if (auto* header = tableInterface->getHeaderHandler())
 | 
			
		||||
                    {
 | 
			
		||||
                        const auto children = header->getChildren();
 | 
			
		||||
 | 
			
		||||
                        if (isPositiveAndBelow (column->begin, children.size()))
 | 
			
		||||
                        {
 | 
			
		||||
                            IRawElementProviderSimple* provider = nullptr;
 | 
			
		||||
 | 
			
		||||
                            if (auto* child = children[(size_t) column->begin])
 | 
			
		||||
                            {
 | 
			
		||||
                                JUCE_BEGIN_IGNORE_WARNINGS_GCC_LIKE ("-Wlanguage-extension-token")
 | 
			
		||||
                                if (child->getNativeImplementation()->QueryInterface (IID_PPV_ARGS (&provider)) == S_OK && provider != nullptr)
 | 
			
		||||
                                {
 | 
			
		||||
                                    *pRetVal = SafeArrayCreateVector (VT_UNKNOWN, 0, 1);
 | 
			
		||||
                                    LONG index = 0;
 | 
			
		||||
                                    const auto hr = SafeArrayPutElement (*pRetVal, &index, provider);
 | 
			
		||||
 | 
			
		||||
                                    return ! FAILED (hr);
 | 
			
		||||
                                }
 | 
			
		||||
                                JUCE_END_IGNORE_WARNINGS_GCC_LIKE
 | 
			
		||||
                            }
 | 
			
		||||
                        }
 | 
			
		||||
                    }
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            return false;
 | 
			
		||||
        });
 | 
			
		||||
    }
 | 
			
		||||
private:
 | 
			
		||||
    template <typename Value, typename Callback>
 | 
			
		||||
    JUCE_COMRESULT withTableInterface (Value* pRetVal, Callback&& callback) const
 | 
			
		||||
    {
 | 
			
		||||
        return withCheckedComArgs (pRetVal, *this, [&]() -> HRESULT
 | 
			
		||||
        {
 | 
			
		||||
            if (auto* handler = getEnclosingHandlerWithInterface (&getHandler(), &AccessibilityHandler::getTableInterface))
 | 
			
		||||
                if (handler->getTableInterface() != nullptr && callback (*handler))
 | 
			
		||||
                    return S_OK;
 | 
			
		||||
 | 
			
		||||
            return (HRESULT) UIA_E_NOTSUPPORTED;
 | 
			
		||||
        });
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    JUCE_COMRESULT withTableSpan (int* pRetVal,
 | 
			
		||||
                                  Optional<AccessibilityTableInterface::Span> (AccessibilityTableInterface::* getSpan) (const AccessibilityHandler&) const,
 | 
			
		||||
                                  int AccessibilityTableInterface::Span::* spanMember) const
 | 
			
		||||
    {
 | 
			
		||||
        return withTableInterface (pRetVal, [&] (const AccessibilityHandler& handler)
 | 
			
		||||
        {
 | 
			
		||||
            if (const auto span = ((handler.getTableInterface())->*getSpan) (getHandler()))
 | 
			
		||||
            {
 | 
			
		||||
                *pRetVal = (*span).*spanMember;
 | 
			
		||||
                return true;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            return false;
 | 
			
		||||
        });
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    //==============================================================================
 | 
			
		||||
    JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (UIAGridItemProvider)
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
} // namespace juce
 | 
			
		||||
 
 | 
			
		||||
@@ -1,94 +1,151 @@
 | 
			
		||||
/*
 | 
			
		||||
  ==============================================================================
 | 
			
		||||
 | 
			
		||||
   This file is part of the JUCE library.
 | 
			
		||||
   Copyright (c) 2020 - Raw Material Software Limited
 | 
			
		||||
 | 
			
		||||
   JUCE is an open source library subject to commercial or open-source
 | 
			
		||||
   licensing.
 | 
			
		||||
 | 
			
		||||
   By using JUCE, you agree to the terms of both the JUCE 6 End-User License
 | 
			
		||||
   Agreement and JUCE Privacy Policy (both effective as of the 16th June 2020).
 | 
			
		||||
 | 
			
		||||
   End User License Agreement: www.juce.com/juce-6-licence
 | 
			
		||||
   Privacy Policy: www.juce.com/juce-privacy-policy
 | 
			
		||||
 | 
			
		||||
   Or: You may also use this code under the terms of the GPL v3 (see
 | 
			
		||||
   www.gnu.org/licenses).
 | 
			
		||||
 | 
			
		||||
   JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
 | 
			
		||||
   EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
 | 
			
		||||
   DISCLAIMED.
 | 
			
		||||
 | 
			
		||||
  ==============================================================================
 | 
			
		||||
*/
 | 
			
		||||
 | 
			
		||||
namespace juce
 | 
			
		||||
{
 | 
			
		||||
 | 
			
		||||
//==============================================================================
 | 
			
		||||
class UIAGridProvider  : public UIAProviderBase,
 | 
			
		||||
                         public ComBaseClassHelper<IGridProvider>
 | 
			
		||||
{
 | 
			
		||||
public:
 | 
			
		||||
    explicit UIAGridProvider (AccessibilityNativeHandle* nativeHandle)
 | 
			
		||||
        : UIAProviderBase (nativeHandle)
 | 
			
		||||
    {
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    //==============================================================================
 | 
			
		||||
    JUCE_COMRESULT GetItem (int row, int column, IRawElementProviderSimple** pRetVal) override
 | 
			
		||||
    {
 | 
			
		||||
        return withTableInterface (pRetVal, [&] (const AccessibilityTableInterface& tableInterface)
 | 
			
		||||
        {
 | 
			
		||||
            if (! isPositiveAndBelow (row, tableInterface.getNumRows())
 | 
			
		||||
                || ! isPositiveAndBelow (column, tableInterface.getNumColumns()))
 | 
			
		||||
                return E_INVALIDARG;
 | 
			
		||||
 | 
			
		||||
            JUCE_BEGIN_IGNORE_WARNINGS_GCC_LIKE ("-Wlanguage-extension-token")
 | 
			
		||||
 | 
			
		||||
            if (auto* handler = tableInterface.getCellHandler (row, column))
 | 
			
		||||
                handler->getNativeImplementation()->QueryInterface (IID_PPV_ARGS (pRetVal));
 | 
			
		||||
 | 
			
		||||
            JUCE_END_IGNORE_WARNINGS_GCC_LIKE
 | 
			
		||||
 | 
			
		||||
            return S_OK;
 | 
			
		||||
        });
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    JUCE_COMRESULT get_RowCount (int* pRetVal) override
 | 
			
		||||
    {
 | 
			
		||||
        return withTableInterface (pRetVal, [&] (const AccessibilityTableInterface& tableInterface)
 | 
			
		||||
        {
 | 
			
		||||
            *pRetVal = tableInterface.getNumRows();
 | 
			
		||||
            return S_OK;
 | 
			
		||||
        });
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    JUCE_COMRESULT get_ColumnCount (int* pRetVal) override
 | 
			
		||||
    {
 | 
			
		||||
        return withTableInterface (pRetVal, [&] (const AccessibilityTableInterface& tableInterface)
 | 
			
		||||
        {
 | 
			
		||||
            *pRetVal = tableInterface.getNumColumns();
 | 
			
		||||
            return S_OK;
 | 
			
		||||
        });
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
private:
 | 
			
		||||
    template <typename Value, typename Callback>
 | 
			
		||||
    JUCE_COMRESULT withTableInterface (Value* pRetVal, Callback&& callback) const
 | 
			
		||||
    {
 | 
			
		||||
        return withCheckedComArgs (pRetVal, *this, [&]() -> HRESULT
 | 
			
		||||
        {
 | 
			
		||||
            if (auto* tableInterface = getHandler().getTableInterface())
 | 
			
		||||
                return callback (*tableInterface);
 | 
			
		||||
 | 
			
		||||
            return (HRESULT) UIA_E_NOTSUPPORTED;
 | 
			
		||||
        });
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    //==============================================================================
 | 
			
		||||
    JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (UIAGridProvider)
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
} // namespace juce
 | 
			
		||||
/*
 | 
			
		||||
  ==============================================================================
 | 
			
		||||
 | 
			
		||||
   This file is part of the JUCE library.
 | 
			
		||||
   Copyright (c) 2022 - Raw Material Software Limited
 | 
			
		||||
 | 
			
		||||
   JUCE is an open source library subject to commercial or open-source
 | 
			
		||||
   licensing.
 | 
			
		||||
 | 
			
		||||
   By using JUCE, you agree to the terms of both the JUCE 7 End-User License
 | 
			
		||||
   Agreement and JUCE Privacy Policy.
 | 
			
		||||
 | 
			
		||||
   End User License Agreement: www.juce.com/juce-7-licence
 | 
			
		||||
   Privacy Policy: www.juce.com/juce-privacy-policy
 | 
			
		||||
 | 
			
		||||
   Or: You may also use this code under the terms of the GPL v3 (see
 | 
			
		||||
   www.gnu.org/licenses).
 | 
			
		||||
 | 
			
		||||
   JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
 | 
			
		||||
   EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
 | 
			
		||||
   DISCLAIMED.
 | 
			
		||||
 | 
			
		||||
  ==============================================================================
 | 
			
		||||
*/
 | 
			
		||||
 | 
			
		||||
namespace juce
 | 
			
		||||
{
 | 
			
		||||
 | 
			
		||||
//==============================================================================
 | 
			
		||||
class UIAGridProvider  : public UIAProviderBase,
 | 
			
		||||
                         public ComBaseClassHelper<ComTypes::IGridProvider, ComTypes::ITableProvider>
 | 
			
		||||
{
 | 
			
		||||
public:
 | 
			
		||||
    using UIAProviderBase::UIAProviderBase;
 | 
			
		||||
 | 
			
		||||
    //==============================================================================
 | 
			
		||||
    JUCE_COMRESULT GetItem (int row, int column, IRawElementProviderSimple** pRetVal) override
 | 
			
		||||
    {
 | 
			
		||||
        return withTableInterface (pRetVal, [&] (const AccessibilityTableInterface& tableInterface)
 | 
			
		||||
        {
 | 
			
		||||
            if (! isPositiveAndBelow (row, tableInterface.getNumRows())
 | 
			
		||||
                || ! isPositiveAndBelow (column, tableInterface.getNumColumns()))
 | 
			
		||||
                return E_INVALIDARG;
 | 
			
		||||
 | 
			
		||||
            JUCE_BEGIN_IGNORE_WARNINGS_GCC_LIKE ("-Wlanguage-extension-token")
 | 
			
		||||
 | 
			
		||||
            if (auto* cellHandler = tableInterface.getCellHandler (row, column))
 | 
			
		||||
            {
 | 
			
		||||
                cellHandler->getNativeImplementation()->QueryInterface (IID_PPV_ARGS (pRetVal));
 | 
			
		||||
                return S_OK;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            if (auto* rowHandler = tableInterface.getRowHandler (row))
 | 
			
		||||
            {
 | 
			
		||||
                rowHandler->getNativeImplementation()->QueryInterface (IID_PPV_ARGS (pRetVal));
 | 
			
		||||
                return S_OK;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            JUCE_END_IGNORE_WARNINGS_GCC_LIKE
 | 
			
		||||
 | 
			
		||||
            return E_FAIL;
 | 
			
		||||
        });
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    JUCE_COMRESULT get_RowCount (int* pRetVal) override
 | 
			
		||||
    {
 | 
			
		||||
        return withTableInterface (pRetVal, [&] (const AccessibilityTableInterface& tableInterface)
 | 
			
		||||
        {
 | 
			
		||||
            *pRetVal = tableInterface.getNumRows();
 | 
			
		||||
            return S_OK;
 | 
			
		||||
        });
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    JUCE_COMRESULT get_ColumnCount (int* pRetVal) override
 | 
			
		||||
    {
 | 
			
		||||
        return withTableInterface (pRetVal, [&] (const AccessibilityTableInterface& tableInterface)
 | 
			
		||||
        {
 | 
			
		||||
            *pRetVal = tableInterface.getNumColumns();
 | 
			
		||||
            return S_OK;
 | 
			
		||||
        });
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    JUCE_COMRESULT GetRowHeaders (SAFEARRAY**) override
 | 
			
		||||
    {
 | 
			
		||||
        return (HRESULT) UIA_E_NOTSUPPORTED;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    JUCE_COMRESULT GetColumnHeaders (SAFEARRAY** pRetVal) override
 | 
			
		||||
    {
 | 
			
		||||
        return withTableInterface (pRetVal, [&] (const AccessibilityTableInterface& tableInterface)
 | 
			
		||||
        {
 | 
			
		||||
            if (auto* header = tableInterface.getHeaderHandler())
 | 
			
		||||
            {
 | 
			
		||||
                const auto children = header->getChildren();
 | 
			
		||||
 | 
			
		||||
                *pRetVal = SafeArrayCreateVector (VT_UNKNOWN, 0, (ULONG) children.size());
 | 
			
		||||
 | 
			
		||||
                LONG index = 0;
 | 
			
		||||
 | 
			
		||||
                for (const auto& child : children)
 | 
			
		||||
                {
 | 
			
		||||
                    IRawElementProviderSimple* provider = nullptr;
 | 
			
		||||
 | 
			
		||||
                    JUCE_BEGIN_IGNORE_WARNINGS_GCC_LIKE ("-Wlanguage-extension-token")
 | 
			
		||||
                    if (child != nullptr)
 | 
			
		||||
                        child->getNativeImplementation()->QueryInterface (IID_PPV_ARGS (&provider));
 | 
			
		||||
                    JUCE_END_IGNORE_WARNINGS_GCC_LIKE
 | 
			
		||||
 | 
			
		||||
                    if (provider == nullptr)
 | 
			
		||||
                        return E_FAIL;
 | 
			
		||||
 | 
			
		||||
                    const auto hr = SafeArrayPutElement (*pRetVal, &index, provider);
 | 
			
		||||
 | 
			
		||||
                    if (FAILED (hr))
 | 
			
		||||
                        return E_FAIL;
 | 
			
		||||
 | 
			
		||||
                    ++index;
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
                return S_OK;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            return (HRESULT) UIA_E_NOTSUPPORTED;
 | 
			
		||||
        });
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    JUCE_COMRESULT get_RowOrColumnMajor (ComTypes::RowOrColumnMajor* pRetVal) override
 | 
			
		||||
    {
 | 
			
		||||
        *pRetVal = ComTypes::RowOrColumnMajor_RowMajor;
 | 
			
		||||
        return S_OK;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
private:
 | 
			
		||||
    template <typename Value, typename Callback>
 | 
			
		||||
    JUCE_COMRESULT withTableInterface (Value* pRetVal, Callback&& callback) const
 | 
			
		||||
    {
 | 
			
		||||
        return withCheckedComArgs (pRetVal, *this, [&]() -> HRESULT
 | 
			
		||||
        {
 | 
			
		||||
            if (auto* tableHandler = getEnclosingHandlerWithInterface (&getHandler(), &AccessibilityHandler::getTableInterface))
 | 
			
		||||
                if (auto* tableInterface = tableHandler->getTableInterface())
 | 
			
		||||
                    return callback (*tableInterface);
 | 
			
		||||
 | 
			
		||||
            return (HRESULT) UIA_E_NOTSUPPORTED;
 | 
			
		||||
        });
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    //==============================================================================
 | 
			
		||||
    JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (UIAGridProvider)
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
} // namespace juce
 | 
			
		||||
 
 | 
			
		||||
@@ -1,105 +1,119 @@
 | 
			
		||||
/*
 | 
			
		||||
  ==============================================================================
 | 
			
		||||
 | 
			
		||||
   This file is part of the JUCE library.
 | 
			
		||||
   Copyright (c) 2020 - Raw Material Software Limited
 | 
			
		||||
 | 
			
		||||
   JUCE is an open source library subject to commercial or open-source
 | 
			
		||||
   licensing.
 | 
			
		||||
 | 
			
		||||
   By using JUCE, you agree to the terms of both the JUCE 6 End-User License
 | 
			
		||||
   Agreement and JUCE Privacy Policy (both effective as of the 16th June 2020).
 | 
			
		||||
 | 
			
		||||
   End User License Agreement: www.juce.com/juce-6-licence
 | 
			
		||||
   Privacy Policy: www.juce.com/juce-privacy-policy
 | 
			
		||||
 | 
			
		||||
   Or: You may also use this code under the terms of the GPL v3 (see
 | 
			
		||||
   www.gnu.org/licenses).
 | 
			
		||||
 | 
			
		||||
   JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
 | 
			
		||||
   EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
 | 
			
		||||
   DISCLAIMED.
 | 
			
		||||
 | 
			
		||||
  ==============================================================================
 | 
			
		||||
*/
 | 
			
		||||
 | 
			
		||||
namespace juce
 | 
			
		||||
{
 | 
			
		||||
 | 
			
		||||
namespace VariantHelpers
 | 
			
		||||
{
 | 
			
		||||
    inline void clear (VARIANT* variant)
 | 
			
		||||
    {
 | 
			
		||||
        variant->vt = VT_EMPTY;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    inline void setInt (int value, VARIANT* variant)
 | 
			
		||||
    {
 | 
			
		||||
        variant->vt   = VT_I4;
 | 
			
		||||
        variant->lVal = value;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    inline void setBool (bool value, VARIANT* variant)
 | 
			
		||||
    {
 | 
			
		||||
        variant->vt      = VT_BOOL;
 | 
			
		||||
        variant->boolVal = value ? -1 : 0;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    inline void setString (const String& value, VARIANT* variant)
 | 
			
		||||
    {
 | 
			
		||||
        variant->vt      = VT_BSTR;
 | 
			
		||||
        variant->bstrVal = SysAllocString ((const OLECHAR*) value.toWideCharPointer());
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    inline void setDouble (double value, VARIANT* variant)
 | 
			
		||||
    {
 | 
			
		||||
        variant->vt     = VT_R8;
 | 
			
		||||
        variant->dblVal = value;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
inline JUCE_COMRESULT addHandlersToArray (const std::vector<const AccessibilityHandler*>& handlers, SAFEARRAY** pRetVal)
 | 
			
		||||
{
 | 
			
		||||
    auto numHandlers = handlers.size();
 | 
			
		||||
 | 
			
		||||
    *pRetVal = SafeArrayCreateVector (VT_UNKNOWN, 0, (ULONG) numHandlers);
 | 
			
		||||
 | 
			
		||||
    if (pRetVal != nullptr)
 | 
			
		||||
    {
 | 
			
		||||
        for (LONG i = 0; i < (LONG) numHandlers; ++i)
 | 
			
		||||
        {
 | 
			
		||||
            auto* handler = handlers[(size_t) i];
 | 
			
		||||
 | 
			
		||||
            if (handler == nullptr)
 | 
			
		||||
                continue;
 | 
			
		||||
 | 
			
		||||
            ComSmartPtr<IRawElementProviderSimple> provider;
 | 
			
		||||
            JUCE_BEGIN_IGNORE_WARNINGS_GCC_LIKE ("-Wlanguage-extension-token")
 | 
			
		||||
            handler->getNativeImplementation()->QueryInterface (IID_PPV_ARGS (provider.resetAndGetPointerAddress()));
 | 
			
		||||
            JUCE_END_IGNORE_WARNINGS_GCC_LIKE
 | 
			
		||||
 | 
			
		||||
            auto hr = SafeArrayPutElement (*pRetVal, &i, provider);
 | 
			
		||||
 | 
			
		||||
            if (FAILED (hr))
 | 
			
		||||
                return E_FAIL;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    return S_OK;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
template <typename Value, typename Object, typename Callback>
 | 
			
		||||
inline JUCE_COMRESULT withCheckedComArgs (Value* pRetVal, Object& handle, Callback&& callback)
 | 
			
		||||
{
 | 
			
		||||
    if (pRetVal == nullptr)
 | 
			
		||||
        return E_INVALIDARG;
 | 
			
		||||
 | 
			
		||||
    *pRetVal = Value{};
 | 
			
		||||
 | 
			
		||||
    if (! handle.isElementValid())
 | 
			
		||||
        return (HRESULT) UIA_E_ELEMENTNOTAVAILABLE;
 | 
			
		||||
 | 
			
		||||
    return callback();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
} // namespace juce
 | 
			
		||||
/*
 | 
			
		||||
  ==============================================================================
 | 
			
		||||
 | 
			
		||||
   This file is part of the JUCE library.
 | 
			
		||||
   Copyright (c) 2022 - Raw Material Software Limited
 | 
			
		||||
 | 
			
		||||
   JUCE is an open source library subject to commercial or open-source
 | 
			
		||||
   licensing.
 | 
			
		||||
 | 
			
		||||
   By using JUCE, you agree to the terms of both the JUCE 7 End-User License
 | 
			
		||||
   Agreement and JUCE Privacy Policy.
 | 
			
		||||
 | 
			
		||||
   End User License Agreement: www.juce.com/juce-7-licence
 | 
			
		||||
   Privacy Policy: www.juce.com/juce-privacy-policy
 | 
			
		||||
 | 
			
		||||
   Or: You may also use this code under the terms of the GPL v3 (see
 | 
			
		||||
   www.gnu.org/licenses).
 | 
			
		||||
 | 
			
		||||
   JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
 | 
			
		||||
   EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
 | 
			
		||||
   DISCLAIMED.
 | 
			
		||||
 | 
			
		||||
  ==============================================================================
 | 
			
		||||
*/
 | 
			
		||||
 | 
			
		||||
namespace juce
 | 
			
		||||
{
 | 
			
		||||
 | 
			
		||||
namespace VariantHelpers
 | 
			
		||||
{
 | 
			
		||||
    namespace Detail
 | 
			
		||||
    {
 | 
			
		||||
        template <typename Fn, typename ValueType>
 | 
			
		||||
        inline VARIANT getWithValueGeneric (Fn&& setter, ValueType value)
 | 
			
		||||
        {
 | 
			
		||||
            VARIANT result{};
 | 
			
		||||
            setter (value, &result);
 | 
			
		||||
            return result;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    inline void clear (VARIANT* variant)
 | 
			
		||||
    {
 | 
			
		||||
        variant->vt = VT_EMPTY;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    inline void setInt (int value, VARIANT* variant)
 | 
			
		||||
    {
 | 
			
		||||
        variant->vt   = VT_I4;
 | 
			
		||||
        variant->lVal = value;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    inline void setBool (bool value, VARIANT* variant)
 | 
			
		||||
    {
 | 
			
		||||
        variant->vt      = VT_BOOL;
 | 
			
		||||
        variant->boolVal = value ? -1 : 0;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    inline void setString (const String& value, VARIANT* variant)
 | 
			
		||||
    {
 | 
			
		||||
        variant->vt      = VT_BSTR;
 | 
			
		||||
        variant->bstrVal = SysAllocString ((const OLECHAR*) value.toWideCharPointer());
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    inline void setDouble (double value, VARIANT* variant)
 | 
			
		||||
    {
 | 
			
		||||
        variant->vt     = VT_R8;
 | 
			
		||||
        variant->dblVal = value;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    inline VARIANT getWithValue (double value)        { return Detail::getWithValueGeneric (&setDouble, value); }
 | 
			
		||||
    inline VARIANT getWithValue (const String& value) { return Detail::getWithValueGeneric (&setString, value); }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
inline JUCE_COMRESULT addHandlersToArray (const std::vector<const AccessibilityHandler*>& handlers, SAFEARRAY** pRetVal)
 | 
			
		||||
{
 | 
			
		||||
    auto numHandlers = handlers.size();
 | 
			
		||||
 | 
			
		||||
    *pRetVal = SafeArrayCreateVector (VT_UNKNOWN, 0, (ULONG) numHandlers);
 | 
			
		||||
 | 
			
		||||
    if (pRetVal != nullptr)
 | 
			
		||||
    {
 | 
			
		||||
        for (LONG i = 0; i < (LONG) numHandlers; ++i)
 | 
			
		||||
        {
 | 
			
		||||
            auto* handler = handlers[(size_t) i];
 | 
			
		||||
 | 
			
		||||
            if (handler == nullptr)
 | 
			
		||||
                continue;
 | 
			
		||||
 | 
			
		||||
            ComSmartPtr<IRawElementProviderSimple> provider;
 | 
			
		||||
            JUCE_BEGIN_IGNORE_WARNINGS_GCC_LIKE ("-Wlanguage-extension-token")
 | 
			
		||||
            handler->getNativeImplementation()->QueryInterface (IID_PPV_ARGS (provider.resetAndGetPointerAddress()));
 | 
			
		||||
            JUCE_END_IGNORE_WARNINGS_GCC_LIKE
 | 
			
		||||
 | 
			
		||||
            auto hr = SafeArrayPutElement (*pRetVal, &i, provider);
 | 
			
		||||
 | 
			
		||||
            if (FAILED (hr))
 | 
			
		||||
                return E_FAIL;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    return S_OK;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
template <typename Value, typename Object, typename Callback>
 | 
			
		||||
inline JUCE_COMRESULT withCheckedComArgs (Value* pRetVal, Object& handle, Callback&& callback)
 | 
			
		||||
{
 | 
			
		||||
    if (pRetVal == nullptr)
 | 
			
		||||
        return E_INVALIDARG;
 | 
			
		||||
 | 
			
		||||
    *pRetVal = Value{};
 | 
			
		||||
 | 
			
		||||
    if (! handle.isElementValid())
 | 
			
		||||
        return (HRESULT) UIA_E_ELEMENTNOTAVAILABLE;
 | 
			
		||||
 | 
			
		||||
    return callback();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
} // namespace juce
 | 
			
		||||
 
 | 
			
		||||
@@ -1,62 +1,59 @@
 | 
			
		||||
/*
 | 
			
		||||
  ==============================================================================
 | 
			
		||||
 | 
			
		||||
   This file is part of the JUCE library.
 | 
			
		||||
   Copyright (c) 2020 - Raw Material Software Limited
 | 
			
		||||
 | 
			
		||||
   JUCE is an open source library subject to commercial or open-source
 | 
			
		||||
   licensing.
 | 
			
		||||
 | 
			
		||||
   By using JUCE, you agree to the terms of both the JUCE 6 End-User License
 | 
			
		||||
   Agreement and JUCE Privacy Policy (both effective as of the 16th June 2020).
 | 
			
		||||
 | 
			
		||||
   End User License Agreement: www.juce.com/juce-6-licence
 | 
			
		||||
   Privacy Policy: www.juce.com/juce-privacy-policy
 | 
			
		||||
 | 
			
		||||
   Or: You may also use this code under the terms of the GPL v3 (see
 | 
			
		||||
   www.gnu.org/licenses).
 | 
			
		||||
 | 
			
		||||
   JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
 | 
			
		||||
   EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
 | 
			
		||||
   DISCLAIMED.
 | 
			
		||||
 | 
			
		||||
  ==============================================================================
 | 
			
		||||
*/
 | 
			
		||||
 | 
			
		||||
namespace juce
 | 
			
		||||
{
 | 
			
		||||
 | 
			
		||||
//==============================================================================
 | 
			
		||||
class UIAInvokeProvider  : public UIAProviderBase,
 | 
			
		||||
                           public ComBaseClassHelper<IInvokeProvider>
 | 
			
		||||
{
 | 
			
		||||
public:
 | 
			
		||||
    explicit UIAInvokeProvider (AccessibilityNativeHandle* nativeHandle)
 | 
			
		||||
        : UIAProviderBase (nativeHandle)
 | 
			
		||||
    {
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    //==============================================================================
 | 
			
		||||
    JUCE_COMRESULT Invoke() override
 | 
			
		||||
    {
 | 
			
		||||
        if (! isElementValid())
 | 
			
		||||
            return (HRESULT) UIA_E_ELEMENTNOTAVAILABLE;
 | 
			
		||||
 | 
			
		||||
        const auto& handler = getHandler();
 | 
			
		||||
 | 
			
		||||
        if (handler.getActions().invoke (AccessibilityActionType::press))
 | 
			
		||||
        {
 | 
			
		||||
            if (isElementValid())
 | 
			
		||||
                sendAccessibilityAutomationEvent (handler, UIA_Invoke_InvokedEventId);
 | 
			
		||||
 | 
			
		||||
            return S_OK;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        return (HRESULT) UIA_E_NOTSUPPORTED;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    //==============================================================================
 | 
			
		||||
    JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (UIAInvokeProvider)
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
} // namespace juce
 | 
			
		||||
/*
 | 
			
		||||
  ==============================================================================
 | 
			
		||||
 | 
			
		||||
   This file is part of the JUCE library.
 | 
			
		||||
   Copyright (c) 2022 - Raw Material Software Limited
 | 
			
		||||
 | 
			
		||||
   JUCE is an open source library subject to commercial or open-source
 | 
			
		||||
   licensing.
 | 
			
		||||
 | 
			
		||||
   By using JUCE, you agree to the terms of both the JUCE 7 End-User License
 | 
			
		||||
   Agreement and JUCE Privacy Policy.
 | 
			
		||||
 | 
			
		||||
   End User License Agreement: www.juce.com/juce-7-licence
 | 
			
		||||
   Privacy Policy: www.juce.com/juce-privacy-policy
 | 
			
		||||
 | 
			
		||||
   Or: You may also use this code under the terms of the GPL v3 (see
 | 
			
		||||
   www.gnu.org/licenses).
 | 
			
		||||
 | 
			
		||||
   JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
 | 
			
		||||
   EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
 | 
			
		||||
   DISCLAIMED.
 | 
			
		||||
 | 
			
		||||
  ==============================================================================
 | 
			
		||||
*/
 | 
			
		||||
 | 
			
		||||
namespace juce
 | 
			
		||||
{
 | 
			
		||||
 | 
			
		||||
//==============================================================================
 | 
			
		||||
class UIAInvokeProvider  : public UIAProviderBase,
 | 
			
		||||
                           public ComBaseClassHelper<ComTypes::IInvokeProvider>
 | 
			
		||||
{
 | 
			
		||||
public:
 | 
			
		||||
    using UIAProviderBase::UIAProviderBase;
 | 
			
		||||
 | 
			
		||||
    //==============================================================================
 | 
			
		||||
    JUCE_COMRESULT Invoke() override
 | 
			
		||||
    {
 | 
			
		||||
        if (! isElementValid())
 | 
			
		||||
            return (HRESULT) UIA_E_ELEMENTNOTAVAILABLE;
 | 
			
		||||
 | 
			
		||||
        const auto& handler = getHandler();
 | 
			
		||||
 | 
			
		||||
        if (handler.getActions().invoke (AccessibilityActionType::press))
 | 
			
		||||
        {
 | 
			
		||||
            if (isElementValid())
 | 
			
		||||
                sendAccessibilityAutomationEvent (handler, ComTypes::UIA_Invoke_InvokedEventId);
 | 
			
		||||
 | 
			
		||||
            return S_OK;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        return (HRESULT) UIA_E_NOTSUPPORTED;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    //==============================================================================
 | 
			
		||||
    JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (UIAInvokeProvider)
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
} // namespace juce
 | 
			
		||||
 
 | 
			
		||||
@@ -1,58 +1,58 @@
 | 
			
		||||
/*
 | 
			
		||||
  ==============================================================================
 | 
			
		||||
 | 
			
		||||
   This file is part of the JUCE library.
 | 
			
		||||
   Copyright (c) 2020 - Raw Material Software Limited
 | 
			
		||||
 | 
			
		||||
   JUCE is an open source library subject to commercial or open-source
 | 
			
		||||
   licensing.
 | 
			
		||||
 | 
			
		||||
   By using JUCE, you agree to the terms of both the JUCE 6 End-User License
 | 
			
		||||
   Agreement and JUCE Privacy Policy (both effective as of the 16th June 2020).
 | 
			
		||||
 | 
			
		||||
   End User License Agreement: www.juce.com/juce-6-licence
 | 
			
		||||
   Privacy Policy: www.juce.com/juce-privacy-policy
 | 
			
		||||
 | 
			
		||||
   Or: You may also use this code under the terms of the GPL v3 (see
 | 
			
		||||
   www.gnu.org/licenses).
 | 
			
		||||
 | 
			
		||||
   JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
 | 
			
		||||
   EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
 | 
			
		||||
   DISCLAIMED.
 | 
			
		||||
 | 
			
		||||
  ==============================================================================
 | 
			
		||||
*/
 | 
			
		||||
 | 
			
		||||
namespace juce
 | 
			
		||||
{
 | 
			
		||||
 | 
			
		||||
//==============================================================================
 | 
			
		||||
class UIAProviderBase
 | 
			
		||||
{
 | 
			
		||||
public:
 | 
			
		||||
    explicit UIAProviderBase (AccessibilityNativeHandle* nativeHandleIn)
 | 
			
		||||
        : nativeHandle (nativeHandleIn)
 | 
			
		||||
    {
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    bool isElementValid() const
 | 
			
		||||
    {
 | 
			
		||||
        if (nativeHandle != nullptr)
 | 
			
		||||
            return nativeHandle->isElementValid();
 | 
			
		||||
 | 
			
		||||
        return false;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    const AccessibilityHandler& getHandler() const
 | 
			
		||||
    {
 | 
			
		||||
        return nativeHandle->getHandler();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
private:
 | 
			
		||||
    ComSmartPtr<AccessibilityNativeHandle> nativeHandle;
 | 
			
		||||
 | 
			
		||||
    //==============================================================================
 | 
			
		||||
    JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (UIAProviderBase)
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
} // namespace juce
 | 
			
		||||
/*
 | 
			
		||||
  ==============================================================================
 | 
			
		||||
 | 
			
		||||
   This file is part of the JUCE library.
 | 
			
		||||
   Copyright (c) 2022 - Raw Material Software Limited
 | 
			
		||||
 | 
			
		||||
   JUCE is an open source library subject to commercial or open-source
 | 
			
		||||
   licensing.
 | 
			
		||||
 | 
			
		||||
   By using JUCE, you agree to the terms of both the JUCE 7 End-User License
 | 
			
		||||
   Agreement and JUCE Privacy Policy.
 | 
			
		||||
 | 
			
		||||
   End User License Agreement: www.juce.com/juce-7-licence
 | 
			
		||||
   Privacy Policy: www.juce.com/juce-privacy-policy
 | 
			
		||||
 | 
			
		||||
   Or: You may also use this code under the terms of the GPL v3 (see
 | 
			
		||||
   www.gnu.org/licenses).
 | 
			
		||||
 | 
			
		||||
   JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
 | 
			
		||||
   EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
 | 
			
		||||
   DISCLAIMED.
 | 
			
		||||
 | 
			
		||||
  ==============================================================================
 | 
			
		||||
*/
 | 
			
		||||
 | 
			
		||||
namespace juce
 | 
			
		||||
{
 | 
			
		||||
 | 
			
		||||
//==============================================================================
 | 
			
		||||
class UIAProviderBase
 | 
			
		||||
{
 | 
			
		||||
public:
 | 
			
		||||
    explicit UIAProviderBase (AccessibilityNativeHandle* nativeHandleIn)
 | 
			
		||||
        : nativeHandle (nativeHandleIn)
 | 
			
		||||
    {
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    bool isElementValid() const
 | 
			
		||||
    {
 | 
			
		||||
        if (nativeHandle != nullptr)
 | 
			
		||||
            return nativeHandle->isElementValid();
 | 
			
		||||
 | 
			
		||||
        return false;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    const AccessibilityHandler& getHandler() const
 | 
			
		||||
    {
 | 
			
		||||
        return nativeHandle->getHandler();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
private:
 | 
			
		||||
    ComSmartPtr<AccessibilityNativeHandle> nativeHandle;
 | 
			
		||||
 | 
			
		||||
    //==============================================================================
 | 
			
		||||
    JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (UIAProviderBase)
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
} // namespace juce
 | 
			
		||||
 
 | 
			
		||||
@@ -1,43 +1,43 @@
 | 
			
		||||
/*
 | 
			
		||||
  ==============================================================================
 | 
			
		||||
 | 
			
		||||
   This file is part of the JUCE library.
 | 
			
		||||
   Copyright (c) 2020 - Raw Material Software Limited
 | 
			
		||||
 | 
			
		||||
   JUCE is an open source library subject to commercial or open-source
 | 
			
		||||
   licensing.
 | 
			
		||||
 | 
			
		||||
   By using JUCE, you agree to the terms of both the JUCE 6 End-User License
 | 
			
		||||
   Agreement and JUCE Privacy Policy (both effective as of the 16th June 2020).
 | 
			
		||||
 | 
			
		||||
   End User License Agreement: www.juce.com/juce-6-licence
 | 
			
		||||
   Privacy Policy: www.juce.com/juce-privacy-policy
 | 
			
		||||
 | 
			
		||||
   Or: You may also use this code under the terms of the GPL v3 (see
 | 
			
		||||
   www.gnu.org/licenses).
 | 
			
		||||
 | 
			
		||||
   JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
 | 
			
		||||
   EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
 | 
			
		||||
   DISCLAIMED.
 | 
			
		||||
 | 
			
		||||
  ==============================================================================
 | 
			
		||||
*/
 | 
			
		||||
 | 
			
		||||
namespace juce
 | 
			
		||||
{
 | 
			
		||||
    void sendAccessibilityAutomationEvent (const AccessibilityHandler&, EVENTID);
 | 
			
		||||
    void sendAccessibilityPropertyChangedEvent (const AccessibilityHandler&, PROPERTYID, VARIANT);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#include "juce_win32_UIAProviderBase.h"
 | 
			
		||||
#include "juce_win32_UIAExpandCollapseProvider.h"
 | 
			
		||||
#include "juce_win32_UIAGridItemProvider.h"
 | 
			
		||||
#include "juce_win32_UIAGridProvider.h"
 | 
			
		||||
#include "juce_win32_UIAInvokeProvider.h"
 | 
			
		||||
#include "juce_win32_UIARangeValueProvider.h"
 | 
			
		||||
#include "juce_win32_UIASelectionProvider.h"
 | 
			
		||||
#include "juce_win32_UIATextProvider.h"
 | 
			
		||||
#include "juce_win32_UIAToggleProvider.h"
 | 
			
		||||
#include "juce_win32_UIATransformProvider.h"
 | 
			
		||||
#include "juce_win32_UIAValueProvider.h"
 | 
			
		||||
#include "juce_win32_UIAWindowProvider.h"
 | 
			
		||||
/*
 | 
			
		||||
  ==============================================================================
 | 
			
		||||
 | 
			
		||||
   This file is part of the JUCE library.
 | 
			
		||||
   Copyright (c) 2022 - Raw Material Software Limited
 | 
			
		||||
 | 
			
		||||
   JUCE is an open source library subject to commercial or open-source
 | 
			
		||||
   licensing.
 | 
			
		||||
 | 
			
		||||
   By using JUCE, you agree to the terms of both the JUCE 7 End-User License
 | 
			
		||||
   Agreement and JUCE Privacy Policy.
 | 
			
		||||
 | 
			
		||||
   End User License Agreement: www.juce.com/juce-7-licence
 | 
			
		||||
   Privacy Policy: www.juce.com/juce-privacy-policy
 | 
			
		||||
 | 
			
		||||
   Or: You may also use this code under the terms of the GPL v3 (see
 | 
			
		||||
   www.gnu.org/licenses).
 | 
			
		||||
 | 
			
		||||
   JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
 | 
			
		||||
   EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
 | 
			
		||||
   DISCLAIMED.
 | 
			
		||||
 | 
			
		||||
  ==============================================================================
 | 
			
		||||
*/
 | 
			
		||||
 | 
			
		||||
namespace juce
 | 
			
		||||
{
 | 
			
		||||
    void sendAccessibilityAutomationEvent (const AccessibilityHandler&, EVENTID);
 | 
			
		||||
    void sendAccessibilityPropertyChangedEvent (const AccessibilityHandler&, PROPERTYID, VARIANT);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#include "juce_win32_UIAProviderBase.h"
 | 
			
		||||
#include "juce_win32_UIAExpandCollapseProvider.h"
 | 
			
		||||
#include "juce_win32_UIAGridItemProvider.h"
 | 
			
		||||
#include "juce_win32_UIAGridProvider.h"
 | 
			
		||||
#include "juce_win32_UIAInvokeProvider.h"
 | 
			
		||||
#include "juce_win32_UIARangeValueProvider.h"
 | 
			
		||||
#include "juce_win32_UIASelectionProvider.h"
 | 
			
		||||
#include "juce_win32_UIATextProvider.h"
 | 
			
		||||
#include "juce_win32_UIAToggleProvider.h"
 | 
			
		||||
#include "juce_win32_UIATransformProvider.h"
 | 
			
		||||
#include "juce_win32_UIAValueProvider.h"
 | 
			
		||||
#include "juce_win32_UIAWindowProvider.h"
 | 
			
		||||
 
 | 
			
		||||
@@ -1,140 +1,137 @@
 | 
			
		||||
/*
 | 
			
		||||
  ==============================================================================
 | 
			
		||||
 | 
			
		||||
   This file is part of the JUCE library.
 | 
			
		||||
   Copyright (c) 2020 - Raw Material Software Limited
 | 
			
		||||
 | 
			
		||||
   JUCE is an open source library subject to commercial or open-source
 | 
			
		||||
   licensing.
 | 
			
		||||
 | 
			
		||||
   By using JUCE, you agree to the terms of both the JUCE 6 End-User License
 | 
			
		||||
   Agreement and JUCE Privacy Policy (both effective as of the 16th June 2020).
 | 
			
		||||
 | 
			
		||||
   End User License Agreement: www.juce.com/juce-6-licence
 | 
			
		||||
   Privacy Policy: www.juce.com/juce-privacy-policy
 | 
			
		||||
 | 
			
		||||
   Or: You may also use this code under the terms of the GPL v3 (see
 | 
			
		||||
   www.gnu.org/licenses).
 | 
			
		||||
 | 
			
		||||
   JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
 | 
			
		||||
   EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
 | 
			
		||||
   DISCLAIMED.
 | 
			
		||||
 | 
			
		||||
  ==============================================================================
 | 
			
		||||
*/
 | 
			
		||||
 | 
			
		||||
namespace juce
 | 
			
		||||
{
 | 
			
		||||
 | 
			
		||||
//==============================================================================
 | 
			
		||||
class UIARangeValueProvider  : public UIAProviderBase,
 | 
			
		||||
                               public ComBaseClassHelper<IRangeValueProvider>
 | 
			
		||||
{
 | 
			
		||||
public:
 | 
			
		||||
    explicit UIARangeValueProvider (AccessibilityNativeHandle* nativeHandle)
 | 
			
		||||
        : UIAProviderBase (nativeHandle)
 | 
			
		||||
    {
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    //==============================================================================
 | 
			
		||||
    JUCE_COMRESULT SetValue (double val) override
 | 
			
		||||
    {
 | 
			
		||||
        if (! isElementValid())
 | 
			
		||||
            return (HRESULT) UIA_E_ELEMENTNOTAVAILABLE;
 | 
			
		||||
 | 
			
		||||
        const auto& handler = getHandler();
 | 
			
		||||
 | 
			
		||||
        if (auto* valueInterface = handler.getValueInterface())
 | 
			
		||||
        {
 | 
			
		||||
            auto range = valueInterface->getRange();
 | 
			
		||||
 | 
			
		||||
            if (range.isValid())
 | 
			
		||||
            {
 | 
			
		||||
                if (val < range.getMinimumValue() || val > range.getMaximumValue())
 | 
			
		||||
                    return E_INVALIDARG;
 | 
			
		||||
 | 
			
		||||
                if (! valueInterface->isReadOnly())
 | 
			
		||||
                {
 | 
			
		||||
                    valueInterface->setValue (val);
 | 
			
		||||
 | 
			
		||||
                    VARIANT newValue;
 | 
			
		||||
                    VariantHelpers::setDouble (valueInterface->getCurrentValue(), &newValue);
 | 
			
		||||
                    sendAccessibilityPropertyChangedEvent (handler, UIA_RangeValueValuePropertyId, newValue);
 | 
			
		||||
 | 
			
		||||
                    return S_OK;
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        return (HRESULT) UIA_E_NOTSUPPORTED;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    JUCE_COMRESULT get_Value (double* pRetVal) override
 | 
			
		||||
    {
 | 
			
		||||
        return withValueInterface (pRetVal, [] (const AccessibilityValueInterface& valueInterface)
 | 
			
		||||
        {
 | 
			
		||||
            return valueInterface.getCurrentValue();
 | 
			
		||||
        });
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    JUCE_COMRESULT get_IsReadOnly (BOOL* pRetVal) override
 | 
			
		||||
    {
 | 
			
		||||
        return withValueInterface (pRetVal, [] (const AccessibilityValueInterface& valueInterface)
 | 
			
		||||
        {
 | 
			
		||||
            return valueInterface.isReadOnly();
 | 
			
		||||
        });
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    JUCE_COMRESULT get_Maximum (double* pRetVal) override
 | 
			
		||||
    {
 | 
			
		||||
        return withValueInterface (pRetVal, [] (const AccessibilityValueInterface& valueInterface)
 | 
			
		||||
        {
 | 
			
		||||
            return valueInterface.getRange().getMaximumValue();
 | 
			
		||||
        });
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    JUCE_COMRESULT get_Minimum (double* pRetVal) override
 | 
			
		||||
    {
 | 
			
		||||
        return withValueInterface (pRetVal, [] (const AccessibilityValueInterface& valueInterface)
 | 
			
		||||
        {
 | 
			
		||||
            return valueInterface.getRange().getMinimumValue();
 | 
			
		||||
        });
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    JUCE_COMRESULT get_LargeChange (double* pRetVal) override
 | 
			
		||||
    {
 | 
			
		||||
        return get_SmallChange (pRetVal);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    JUCE_COMRESULT get_SmallChange (double* pRetVal) override
 | 
			
		||||
    {
 | 
			
		||||
        return withValueInterface (pRetVal, [] (const AccessibilityValueInterface& valueInterface)
 | 
			
		||||
        {
 | 
			
		||||
            return valueInterface.getRange().getInterval();
 | 
			
		||||
        });
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
private:
 | 
			
		||||
    template <typename Value, typename Callback>
 | 
			
		||||
    JUCE_COMRESULT withValueInterface (Value* pRetVal, Callback&& callback) const
 | 
			
		||||
    {
 | 
			
		||||
        return withCheckedComArgs (pRetVal, *this, [&]() -> HRESULT
 | 
			
		||||
        {
 | 
			
		||||
            if (auto* valueInterface = getHandler().getValueInterface())
 | 
			
		||||
            {
 | 
			
		||||
                if (valueInterface->getRange().isValid())
 | 
			
		||||
                {
 | 
			
		||||
                    *pRetVal = callback (*valueInterface);
 | 
			
		||||
                    return S_OK;
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            return (HRESULT) UIA_E_NOTSUPPORTED;
 | 
			
		||||
        });
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    //==============================================================================
 | 
			
		||||
    JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (UIARangeValueProvider)
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
} // namespace juce
 | 
			
		||||
/*
 | 
			
		||||
  ==============================================================================
 | 
			
		||||
 | 
			
		||||
   This file is part of the JUCE library.
 | 
			
		||||
   Copyright (c) 2022 - Raw Material Software Limited
 | 
			
		||||
 | 
			
		||||
   JUCE is an open source library subject to commercial or open-source
 | 
			
		||||
   licensing.
 | 
			
		||||
 | 
			
		||||
   By using JUCE, you agree to the terms of both the JUCE 7 End-User License
 | 
			
		||||
   Agreement and JUCE Privacy Policy.
 | 
			
		||||
 | 
			
		||||
   End User License Agreement: www.juce.com/juce-7-licence
 | 
			
		||||
   Privacy Policy: www.juce.com/juce-privacy-policy
 | 
			
		||||
 | 
			
		||||
   Or: You may also use this code under the terms of the GPL v3 (see
 | 
			
		||||
   www.gnu.org/licenses).
 | 
			
		||||
 | 
			
		||||
   JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
 | 
			
		||||
   EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
 | 
			
		||||
   DISCLAIMED.
 | 
			
		||||
 | 
			
		||||
  ==============================================================================
 | 
			
		||||
*/
 | 
			
		||||
 | 
			
		||||
namespace juce
 | 
			
		||||
{
 | 
			
		||||
 | 
			
		||||
//==============================================================================
 | 
			
		||||
class UIARangeValueProvider  : public UIAProviderBase,
 | 
			
		||||
                               public ComBaseClassHelper<ComTypes::IRangeValueProvider>
 | 
			
		||||
{
 | 
			
		||||
public:
 | 
			
		||||
    using UIAProviderBase::UIAProviderBase;
 | 
			
		||||
 | 
			
		||||
    //==============================================================================
 | 
			
		||||
    JUCE_COMRESULT SetValue (double val) override
 | 
			
		||||
    {
 | 
			
		||||
        if (! isElementValid())
 | 
			
		||||
            return (HRESULT) UIA_E_ELEMENTNOTAVAILABLE;
 | 
			
		||||
 | 
			
		||||
        const auto& handler = getHandler();
 | 
			
		||||
 | 
			
		||||
        if (auto* valueInterface = handler.getValueInterface())
 | 
			
		||||
        {
 | 
			
		||||
            auto range = valueInterface->getRange();
 | 
			
		||||
 | 
			
		||||
            if (range.isValid())
 | 
			
		||||
            {
 | 
			
		||||
                if (val < range.getMinimumValue() || val > range.getMaximumValue())
 | 
			
		||||
                    return E_INVALIDARG;
 | 
			
		||||
 | 
			
		||||
                if (! valueInterface->isReadOnly())
 | 
			
		||||
                {
 | 
			
		||||
                    valueInterface->setValue (val);
 | 
			
		||||
 | 
			
		||||
                    VARIANT newValue;
 | 
			
		||||
                    VariantHelpers::setDouble (valueInterface->getCurrentValue(), &newValue);
 | 
			
		||||
                    sendAccessibilityPropertyChangedEvent (handler, UIA_RangeValueValuePropertyId, newValue);
 | 
			
		||||
 | 
			
		||||
                    return S_OK;
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        return (HRESULT) UIA_E_NOTSUPPORTED;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    JUCE_COMRESULT get_Value (double* pRetVal) override
 | 
			
		||||
    {
 | 
			
		||||
        return withValueInterface (pRetVal, [] (const AccessibilityValueInterface& valueInterface)
 | 
			
		||||
        {
 | 
			
		||||
            return valueInterface.getCurrentValue();
 | 
			
		||||
        });
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    JUCE_COMRESULT get_IsReadOnly (BOOL* pRetVal) override
 | 
			
		||||
    {
 | 
			
		||||
        return withValueInterface (pRetVal, [] (const AccessibilityValueInterface& valueInterface)
 | 
			
		||||
        {
 | 
			
		||||
            return valueInterface.isReadOnly();
 | 
			
		||||
        });
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    JUCE_COMRESULT get_Maximum (double* pRetVal) override
 | 
			
		||||
    {
 | 
			
		||||
        return withValueInterface (pRetVal, [] (const AccessibilityValueInterface& valueInterface)
 | 
			
		||||
        {
 | 
			
		||||
            return valueInterface.getRange().getMaximumValue();
 | 
			
		||||
        });
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    JUCE_COMRESULT get_Minimum (double* pRetVal) override
 | 
			
		||||
    {
 | 
			
		||||
        return withValueInterface (pRetVal, [] (const AccessibilityValueInterface& valueInterface)
 | 
			
		||||
        {
 | 
			
		||||
            return valueInterface.getRange().getMinimumValue();
 | 
			
		||||
        });
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    JUCE_COMRESULT get_LargeChange (double* pRetVal) override
 | 
			
		||||
    {
 | 
			
		||||
        return get_SmallChange (pRetVal);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    JUCE_COMRESULT get_SmallChange (double* pRetVal) override
 | 
			
		||||
    {
 | 
			
		||||
        return withValueInterface (pRetVal, [] (const AccessibilityValueInterface& valueInterface)
 | 
			
		||||
        {
 | 
			
		||||
            return valueInterface.getRange().getInterval();
 | 
			
		||||
        });
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
private:
 | 
			
		||||
    template <typename Value, typename Callback>
 | 
			
		||||
    JUCE_COMRESULT withValueInterface (Value* pRetVal, Callback&& callback) const
 | 
			
		||||
    {
 | 
			
		||||
        return withCheckedComArgs (pRetVal, *this, [&]() -> HRESULT
 | 
			
		||||
        {
 | 
			
		||||
            if (auto* valueInterface = getHandler().getValueInterface())
 | 
			
		||||
            {
 | 
			
		||||
                if (valueInterface->getRange().isValid())
 | 
			
		||||
                {
 | 
			
		||||
                    *pRetVal = callback (*valueInterface);
 | 
			
		||||
                    return S_OK;
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            return (HRESULT) UIA_E_NOTSUPPORTED;
 | 
			
		||||
        });
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    //==============================================================================
 | 
			
		||||
    JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (UIARangeValueProvider)
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
} // namespace juce
 | 
			
		||||
 
 | 
			
		||||
@@ -1,256 +1,245 @@
 | 
			
		||||
/*
 | 
			
		||||
  ==============================================================================
 | 
			
		||||
 | 
			
		||||
   This file is part of the JUCE library.
 | 
			
		||||
   Copyright (c) 2020 - Raw Material Software Limited
 | 
			
		||||
 | 
			
		||||
   JUCE is an open source library subject to commercial or open-source
 | 
			
		||||
   licensing.
 | 
			
		||||
 | 
			
		||||
   By using JUCE, you agree to the terms of both the JUCE 6 End-User License
 | 
			
		||||
   Agreement and JUCE Privacy Policy (both effective as of the 16th June 2020).
 | 
			
		||||
 | 
			
		||||
   End User License Agreement: www.juce.com/juce-6-licence
 | 
			
		||||
   Privacy Policy: www.juce.com/juce-privacy-policy
 | 
			
		||||
 | 
			
		||||
   Or: You may also use this code under the terms of the GPL v3 (see
 | 
			
		||||
   www.gnu.org/licenses).
 | 
			
		||||
 | 
			
		||||
   JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
 | 
			
		||||
   EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
 | 
			
		||||
   DISCLAIMED.
 | 
			
		||||
 | 
			
		||||
  ==============================================================================
 | 
			
		||||
*/
 | 
			
		||||
 | 
			
		||||
namespace juce
 | 
			
		||||
{
 | 
			
		||||
 | 
			
		||||
JUCE_BEGIN_IGNORE_WARNINGS_GCC_LIKE ("-Wlanguage-extension-token")
 | 
			
		||||
 | 
			
		||||
JUCE_COMCLASS (ISelectionProvider2, "14f68475-ee1c-44f6-a869-d239381f0fe7")  : public ISelectionProvider
 | 
			
		||||
{
 | 
			
		||||
    JUCE_COMCALL get_FirstSelectedItem   (IRawElementProviderSimple** retVal) = 0;
 | 
			
		||||
    JUCE_COMCALL get_LastSelectedItem    (IRawElementProviderSimple** retVal) = 0;
 | 
			
		||||
    JUCE_COMCALL get_CurrentSelectedItem (IRawElementProviderSimple** retVal) = 0;
 | 
			
		||||
    JUCE_COMCALL get_ItemCount (int* retVal) = 0;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
//==============================================================================
 | 
			
		||||
class UIASelectionItemProvider  : public UIAProviderBase,
 | 
			
		||||
                                  public ComBaseClassHelper<ISelectionItemProvider>
 | 
			
		||||
{
 | 
			
		||||
public:
 | 
			
		||||
    explicit UIASelectionItemProvider (AccessibilityNativeHandle* nativeHandle)
 | 
			
		||||
        : UIAProviderBase (nativeHandle),
 | 
			
		||||
          isRadioButton (getHandler().getRole() == AccessibilityRole::radioButton)
 | 
			
		||||
    {
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    //==============================================================================
 | 
			
		||||
    JUCE_COMRESULT AddToSelection() override
 | 
			
		||||
    {
 | 
			
		||||
        if (! isElementValid())
 | 
			
		||||
            return (HRESULT) UIA_E_ELEMENTNOTAVAILABLE;
 | 
			
		||||
 | 
			
		||||
        const auto& handler = getHandler();
 | 
			
		||||
 | 
			
		||||
        if (isRadioButton)
 | 
			
		||||
        {
 | 
			
		||||
            handler.getActions().invoke (AccessibilityActionType::press);
 | 
			
		||||
            sendAccessibilityAutomationEvent (handler, UIA_SelectionItem_ElementSelectedEventId);
 | 
			
		||||
 | 
			
		||||
            return S_OK;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        handler.getActions().invoke (AccessibilityActionType::toggle);
 | 
			
		||||
        handler.getActions().invoke (AccessibilityActionType::press);
 | 
			
		||||
 | 
			
		||||
        return S_OK;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    JUCE_COMRESULT get_IsSelected (BOOL* pRetVal) override
 | 
			
		||||
    {
 | 
			
		||||
        return withCheckedComArgs (pRetVal, *this, [&]
 | 
			
		||||
        {
 | 
			
		||||
            const auto state = getHandler().getCurrentState();
 | 
			
		||||
            *pRetVal = isRadioButton ? state.isChecked() : state.isSelected();
 | 
			
		||||
            return S_OK;
 | 
			
		||||
        });
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    JUCE_COMRESULT get_SelectionContainer (IRawElementProviderSimple** pRetVal) override
 | 
			
		||||
    {
 | 
			
		||||
        return withCheckedComArgs (pRetVal, *this, [&]
 | 
			
		||||
        {
 | 
			
		||||
            if (! isRadioButton)
 | 
			
		||||
                if (auto* parent = getHandler().getParent())
 | 
			
		||||
                    parent->getNativeImplementation()->QueryInterface (IID_PPV_ARGS (pRetVal));
 | 
			
		||||
 | 
			
		||||
            return S_OK;
 | 
			
		||||
        });
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    JUCE_COMRESULT RemoveFromSelection() override
 | 
			
		||||
    {
 | 
			
		||||
        if (! isElementValid())
 | 
			
		||||
            return (HRESULT) UIA_E_ELEMENTNOTAVAILABLE;
 | 
			
		||||
 | 
			
		||||
        if (! isRadioButton)
 | 
			
		||||
        {
 | 
			
		||||
            const auto& handler = getHandler();
 | 
			
		||||
 | 
			
		||||
            if (handler.getCurrentState().isSelected())
 | 
			
		||||
                getHandler().getActions().invoke (AccessibilityActionType::toggle);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        return S_OK;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    JUCE_COMRESULT Select() override
 | 
			
		||||
    {
 | 
			
		||||
        if (! isElementValid())
 | 
			
		||||
            return (HRESULT) UIA_E_ELEMENTNOTAVAILABLE;
 | 
			
		||||
 | 
			
		||||
        AddToSelection();
 | 
			
		||||
 | 
			
		||||
        if (isElementValid() && ! isRadioButton)
 | 
			
		||||
        {
 | 
			
		||||
            const auto& handler = getHandler();
 | 
			
		||||
 | 
			
		||||
            if (auto* parent = handler.getParent())
 | 
			
		||||
                for (auto* child : parent->getChildren())
 | 
			
		||||
                    if (child != &handler && child->getCurrentState().isSelected())
 | 
			
		||||
                        child->getActions().invoke (AccessibilityActionType::toggle);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        return S_OK;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
private:
 | 
			
		||||
    const bool isRadioButton;
 | 
			
		||||
 | 
			
		||||
    //==============================================================================
 | 
			
		||||
    JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (UIASelectionItemProvider)
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
//==============================================================================
 | 
			
		||||
class UIASelectionProvider  : public UIAProviderBase,
 | 
			
		||||
                              public ComBaseClassHelper<ISelectionProvider2>
 | 
			
		||||
{
 | 
			
		||||
public:
 | 
			
		||||
    explicit UIASelectionProvider (AccessibilityNativeHandle* nativeHandle)
 | 
			
		||||
        : UIAProviderBase (nativeHandle)
 | 
			
		||||
    {
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    //==============================================================================
 | 
			
		||||
    JUCE_COMRESULT QueryInterface (REFIID iid, void** result) override
 | 
			
		||||
    {
 | 
			
		||||
        if (iid == _uuidof (IUnknown) || iid == _uuidof (ISelectionProvider))
 | 
			
		||||
            return castToType<ISelectionProvider> (result);
 | 
			
		||||
 | 
			
		||||
        if (iid == _uuidof (ISelectionProvider2))
 | 
			
		||||
            return castToType<ISelectionProvider2> (result);
 | 
			
		||||
 | 
			
		||||
        *result = nullptr;
 | 
			
		||||
        return E_NOINTERFACE;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    //==============================================================================
 | 
			
		||||
    JUCE_COMRESULT get_CanSelectMultiple (BOOL* pRetVal) override
 | 
			
		||||
    {
 | 
			
		||||
        return withCheckedComArgs (pRetVal, *this, [&]
 | 
			
		||||
        {
 | 
			
		||||
            *pRetVal = isMultiSelectable();
 | 
			
		||||
            return S_OK;
 | 
			
		||||
        });
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    JUCE_COMRESULT get_IsSelectionRequired (BOOL* pRetVal) override
 | 
			
		||||
    {
 | 
			
		||||
        return withCheckedComArgs (pRetVal, *this, [&]
 | 
			
		||||
        {
 | 
			
		||||
            *pRetVal = getSelectedChildren().size() > 0 && ! isMultiSelectable();
 | 
			
		||||
            return S_OK;
 | 
			
		||||
        });
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    JUCE_COMRESULT GetSelection (SAFEARRAY** pRetVal) override
 | 
			
		||||
    {
 | 
			
		||||
        return withCheckedComArgs (pRetVal, *this, [&]
 | 
			
		||||
        {
 | 
			
		||||
            return addHandlersToArray (getSelectedChildren(), pRetVal);
 | 
			
		||||
        });
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    //==============================================================================
 | 
			
		||||
    JUCE_COMRESULT get_FirstSelectedItem (IRawElementProviderSimple** pRetVal) override
 | 
			
		||||
    {
 | 
			
		||||
        return withCheckedComArgs (pRetVal, *this, [&]
 | 
			
		||||
        {
 | 
			
		||||
            auto selectedChildren = getSelectedChildren();
 | 
			
		||||
 | 
			
		||||
            if (! selectedChildren.empty())
 | 
			
		||||
                selectedChildren.front()->getNativeImplementation()->QueryInterface (IID_PPV_ARGS (pRetVal));
 | 
			
		||||
 | 
			
		||||
            return S_OK;
 | 
			
		||||
        });
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    JUCE_COMRESULT get_LastSelectedItem (IRawElementProviderSimple** pRetVal) override
 | 
			
		||||
    {
 | 
			
		||||
        return withCheckedComArgs (pRetVal, *this, [&]
 | 
			
		||||
        {
 | 
			
		||||
            auto selectedChildren = getSelectedChildren();
 | 
			
		||||
 | 
			
		||||
            if (! selectedChildren.empty())
 | 
			
		||||
                selectedChildren.back()->getNativeImplementation()->QueryInterface (IID_PPV_ARGS (pRetVal));
 | 
			
		||||
 | 
			
		||||
            return S_OK;
 | 
			
		||||
        });
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    JUCE_COMRESULT get_CurrentSelectedItem (IRawElementProviderSimple** pRetVal) override
 | 
			
		||||
    {
 | 
			
		||||
        return withCheckedComArgs (pRetVal, *this, [&]
 | 
			
		||||
        {
 | 
			
		||||
            get_FirstSelectedItem (pRetVal);
 | 
			
		||||
            return S_OK;
 | 
			
		||||
        });
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    JUCE_COMRESULT get_ItemCount (int* pRetVal) override
 | 
			
		||||
    {
 | 
			
		||||
        return withCheckedComArgs (pRetVal, *this, [&]
 | 
			
		||||
        {
 | 
			
		||||
            *pRetVal = (int) getSelectedChildren().size();
 | 
			
		||||
            return S_OK;
 | 
			
		||||
        });
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
private:
 | 
			
		||||
    bool isMultiSelectable() const noexcept
 | 
			
		||||
    {
 | 
			
		||||
         return getHandler().getCurrentState().isMultiSelectable();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    std::vector<const AccessibilityHandler*> getSelectedChildren() const
 | 
			
		||||
    {
 | 
			
		||||
        std::vector<const AccessibilityHandler*> selectedHandlers;
 | 
			
		||||
 | 
			
		||||
        for (auto* child : getHandler().getComponent().getChildren())
 | 
			
		||||
            if (auto* handler = child->getAccessibilityHandler())
 | 
			
		||||
                if (handler->getCurrentState().isSelected())
 | 
			
		||||
                    selectedHandlers.push_back (handler);
 | 
			
		||||
 | 
			
		||||
        return selectedHandlers;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    //==============================================================================
 | 
			
		||||
    JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (UIASelectionProvider)
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
JUCE_END_IGNORE_WARNINGS_GCC_LIKE
 | 
			
		||||
 | 
			
		||||
} // namespace juce
 | 
			
		||||
/*
 | 
			
		||||
  ==============================================================================
 | 
			
		||||
 | 
			
		||||
   This file is part of the JUCE library.
 | 
			
		||||
   Copyright (c) 2022 - Raw Material Software Limited
 | 
			
		||||
 | 
			
		||||
   JUCE is an open source library subject to commercial or open-source
 | 
			
		||||
   licensing.
 | 
			
		||||
 | 
			
		||||
   By using JUCE, you agree to the terms of both the JUCE 7 End-User License
 | 
			
		||||
   Agreement and JUCE Privacy Policy.
 | 
			
		||||
 | 
			
		||||
   End User License Agreement: www.juce.com/juce-7-licence
 | 
			
		||||
   Privacy Policy: www.juce.com/juce-privacy-policy
 | 
			
		||||
 | 
			
		||||
   Or: You may also use this code under the terms of the GPL v3 (see
 | 
			
		||||
   www.gnu.org/licenses).
 | 
			
		||||
 | 
			
		||||
   JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
 | 
			
		||||
   EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
 | 
			
		||||
   DISCLAIMED.
 | 
			
		||||
 | 
			
		||||
  ==============================================================================
 | 
			
		||||
*/
 | 
			
		||||
 | 
			
		||||
namespace juce
 | 
			
		||||
{
 | 
			
		||||
 | 
			
		||||
JUCE_BEGIN_IGNORE_WARNINGS_GCC_LIKE ("-Wlanguage-extension-token")
 | 
			
		||||
 | 
			
		||||
//==============================================================================
 | 
			
		||||
class UIASelectionItemProvider  : public UIAProviderBase,
 | 
			
		||||
                                  public ComBaseClassHelper<ComTypes::ISelectionItemProvider>
 | 
			
		||||
{
 | 
			
		||||
public:
 | 
			
		||||
    explicit UIASelectionItemProvider (AccessibilityNativeHandle* handle)
 | 
			
		||||
        : UIAProviderBase (handle),
 | 
			
		||||
          isRadioButton (getHandler().getRole() == AccessibilityRole::radioButton)
 | 
			
		||||
    {
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    //==============================================================================
 | 
			
		||||
    JUCE_COMRESULT AddToSelection() override
 | 
			
		||||
    {
 | 
			
		||||
        if (! isElementValid())
 | 
			
		||||
            return (HRESULT) UIA_E_ELEMENTNOTAVAILABLE;
 | 
			
		||||
 | 
			
		||||
        const auto& handler = getHandler();
 | 
			
		||||
 | 
			
		||||
        if (isRadioButton)
 | 
			
		||||
        {
 | 
			
		||||
            handler.getActions().invoke (AccessibilityActionType::press);
 | 
			
		||||
            sendAccessibilityAutomationEvent (handler, ComTypes::UIA_SelectionItem_ElementSelectedEventId);
 | 
			
		||||
 | 
			
		||||
            return S_OK;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        handler.getActions().invoke (AccessibilityActionType::toggle);
 | 
			
		||||
        handler.getActions().invoke (AccessibilityActionType::press);
 | 
			
		||||
 | 
			
		||||
        return S_OK;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    JUCE_COMRESULT get_IsSelected (BOOL* pRetVal) override
 | 
			
		||||
    {
 | 
			
		||||
        return withCheckedComArgs (pRetVal, *this, [&]
 | 
			
		||||
        {
 | 
			
		||||
            const auto state = getHandler().getCurrentState();
 | 
			
		||||
            *pRetVal = isRadioButton ? state.isChecked() : state.isSelected();
 | 
			
		||||
            return S_OK;
 | 
			
		||||
        });
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    JUCE_COMRESULT get_SelectionContainer (IRawElementProviderSimple** pRetVal) override
 | 
			
		||||
    {
 | 
			
		||||
        return withCheckedComArgs (pRetVal, *this, [&]
 | 
			
		||||
        {
 | 
			
		||||
            if (! isRadioButton)
 | 
			
		||||
                if (auto* parent = getHandler().getParent())
 | 
			
		||||
                    parent->getNativeImplementation()->QueryInterface (IID_PPV_ARGS (pRetVal));
 | 
			
		||||
 | 
			
		||||
            return S_OK;
 | 
			
		||||
        });
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    JUCE_COMRESULT RemoveFromSelection() override
 | 
			
		||||
    {
 | 
			
		||||
        if (! isElementValid())
 | 
			
		||||
            return (HRESULT) UIA_E_ELEMENTNOTAVAILABLE;
 | 
			
		||||
 | 
			
		||||
        if (! isRadioButton)
 | 
			
		||||
        {
 | 
			
		||||
            const auto& handler = getHandler();
 | 
			
		||||
 | 
			
		||||
            if (handler.getCurrentState().isSelected())
 | 
			
		||||
                getHandler().getActions().invoke (AccessibilityActionType::toggle);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        return S_OK;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    JUCE_COMRESULT Select() override
 | 
			
		||||
    {
 | 
			
		||||
        if (! isElementValid())
 | 
			
		||||
            return (HRESULT) UIA_E_ELEMENTNOTAVAILABLE;
 | 
			
		||||
 | 
			
		||||
        AddToSelection();
 | 
			
		||||
 | 
			
		||||
        if (isElementValid() && ! isRadioButton)
 | 
			
		||||
        {
 | 
			
		||||
            const auto& handler = getHandler();
 | 
			
		||||
 | 
			
		||||
            if (auto* parent = handler.getParent())
 | 
			
		||||
                for (auto* child : parent->getChildren())
 | 
			
		||||
                    if (child != &handler && child->getCurrentState().isSelected())
 | 
			
		||||
                        child->getActions().invoke (AccessibilityActionType::toggle);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        return S_OK;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
private:
 | 
			
		||||
    const bool isRadioButton;
 | 
			
		||||
 | 
			
		||||
    //==============================================================================
 | 
			
		||||
    JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (UIASelectionItemProvider)
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
//==============================================================================
 | 
			
		||||
class UIASelectionProvider  : public UIAProviderBase,
 | 
			
		||||
                              public ComBaseClassHelper<ComTypes::ISelectionProvider2>
 | 
			
		||||
{
 | 
			
		||||
public:
 | 
			
		||||
    using UIAProviderBase::UIAProviderBase;
 | 
			
		||||
 | 
			
		||||
    //==============================================================================
 | 
			
		||||
    JUCE_COMRESULT QueryInterface (REFIID iid, void** result) override
 | 
			
		||||
    {
 | 
			
		||||
        if (iid == __uuidof (IUnknown) || iid == __uuidof (ComTypes::ISelectionProvider))
 | 
			
		||||
            return castToType<ComTypes::ISelectionProvider> (result);
 | 
			
		||||
 | 
			
		||||
        if (iid == __uuidof (ComTypes::ISelectionProvider2))
 | 
			
		||||
            return castToType<ComTypes::ISelectionProvider2> (result);
 | 
			
		||||
 | 
			
		||||
        *result = nullptr;
 | 
			
		||||
        return E_NOINTERFACE;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    //==============================================================================
 | 
			
		||||
    JUCE_COMRESULT get_CanSelectMultiple (BOOL* pRetVal) override
 | 
			
		||||
    {
 | 
			
		||||
        return withCheckedComArgs (pRetVal, *this, [&]
 | 
			
		||||
        {
 | 
			
		||||
            *pRetVal = isMultiSelectable();
 | 
			
		||||
            return S_OK;
 | 
			
		||||
        });
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    JUCE_COMRESULT get_IsSelectionRequired (BOOL* pRetVal) override
 | 
			
		||||
    {
 | 
			
		||||
        return withCheckedComArgs (pRetVal, *this, [&]
 | 
			
		||||
        {
 | 
			
		||||
            *pRetVal = getSelectedChildren().size() > 0 && ! isMultiSelectable();
 | 
			
		||||
            return S_OK;
 | 
			
		||||
        });
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    JUCE_COMRESULT GetSelection (SAFEARRAY** pRetVal) override
 | 
			
		||||
    {
 | 
			
		||||
        return withCheckedComArgs (pRetVal, *this, [&]
 | 
			
		||||
        {
 | 
			
		||||
            return addHandlersToArray (getSelectedChildren(), pRetVal);
 | 
			
		||||
        });
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    //==============================================================================
 | 
			
		||||
    JUCE_COMRESULT get_FirstSelectedItem (IRawElementProviderSimple** pRetVal) override
 | 
			
		||||
    {
 | 
			
		||||
        return withCheckedComArgs (pRetVal, *this, [&]
 | 
			
		||||
        {
 | 
			
		||||
            auto selectedChildren = getSelectedChildren();
 | 
			
		||||
 | 
			
		||||
            if (! selectedChildren.empty())
 | 
			
		||||
                selectedChildren.front()->getNativeImplementation()->QueryInterface (IID_PPV_ARGS (pRetVal));
 | 
			
		||||
 | 
			
		||||
            return S_OK;
 | 
			
		||||
        });
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    JUCE_COMRESULT get_LastSelectedItem (IRawElementProviderSimple** pRetVal) override
 | 
			
		||||
    {
 | 
			
		||||
        return withCheckedComArgs (pRetVal, *this, [&]
 | 
			
		||||
        {
 | 
			
		||||
            auto selectedChildren = getSelectedChildren();
 | 
			
		||||
 | 
			
		||||
            if (! selectedChildren.empty())
 | 
			
		||||
                selectedChildren.back()->getNativeImplementation()->QueryInterface (IID_PPV_ARGS (pRetVal));
 | 
			
		||||
 | 
			
		||||
            return S_OK;
 | 
			
		||||
        });
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    JUCE_COMRESULT get_CurrentSelectedItem (IRawElementProviderSimple** pRetVal) override
 | 
			
		||||
    {
 | 
			
		||||
        return withCheckedComArgs (pRetVal, *this, [&]
 | 
			
		||||
        {
 | 
			
		||||
            get_FirstSelectedItem (pRetVal);
 | 
			
		||||
            return S_OK;
 | 
			
		||||
        });
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    JUCE_COMRESULT get_ItemCount (int* pRetVal) override
 | 
			
		||||
    {
 | 
			
		||||
        return withCheckedComArgs (pRetVal, *this, [&]
 | 
			
		||||
        {
 | 
			
		||||
            *pRetVal = (int) getSelectedChildren().size();
 | 
			
		||||
            return S_OK;
 | 
			
		||||
        });
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
private:
 | 
			
		||||
    bool isMultiSelectable() const noexcept
 | 
			
		||||
    {
 | 
			
		||||
         return getHandler().getCurrentState().isMultiSelectable();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    std::vector<const AccessibilityHandler*> getSelectedChildren() const
 | 
			
		||||
    {
 | 
			
		||||
        std::vector<const AccessibilityHandler*> selectedHandlers;
 | 
			
		||||
 | 
			
		||||
        for (auto* child : getHandler().getComponent().getChildren())
 | 
			
		||||
            if (auto* handler = child->getAccessibilityHandler())
 | 
			
		||||
                if (handler->getCurrentState().isSelected())
 | 
			
		||||
                    selectedHandlers.push_back (handler);
 | 
			
		||||
 | 
			
		||||
        return selectedHandlers;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    //==============================================================================
 | 
			
		||||
    JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (UIASelectionProvider)
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
JUCE_END_IGNORE_WARNINGS_GCC_LIKE
 | 
			
		||||
 | 
			
		||||
} // namespace juce
 | 
			
		||||
 
 | 
			
		||||
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							@@ -1,80 +1,78 @@
 | 
			
		||||
/*
 | 
			
		||||
  ==============================================================================
 | 
			
		||||
 | 
			
		||||
   This file is part of the JUCE library.
 | 
			
		||||
   Copyright (c) 2020 - Raw Material Software Limited
 | 
			
		||||
 | 
			
		||||
   JUCE is an open source library subject to commercial or open-source
 | 
			
		||||
   licensing.
 | 
			
		||||
 | 
			
		||||
   By using JUCE, you agree to the terms of both the JUCE 6 End-User License
 | 
			
		||||
   Agreement and JUCE Privacy Policy (both effective as of the 16th June 2020).
 | 
			
		||||
 | 
			
		||||
   End User License Agreement: www.juce.com/juce-6-licence
 | 
			
		||||
   Privacy Policy: www.juce.com/juce-privacy-policy
 | 
			
		||||
 | 
			
		||||
   Or: You may also use this code under the terms of the GPL v3 (see
 | 
			
		||||
   www.gnu.org/licenses).
 | 
			
		||||
 | 
			
		||||
   JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
 | 
			
		||||
   EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
 | 
			
		||||
   DISCLAIMED.
 | 
			
		||||
 | 
			
		||||
  ==============================================================================
 | 
			
		||||
*/
 | 
			
		||||
 | 
			
		||||
namespace juce
 | 
			
		||||
{
 | 
			
		||||
 | 
			
		||||
//==============================================================================
 | 
			
		||||
class UIAToggleProvider  : public UIAProviderBase,
 | 
			
		||||
                           public ComBaseClassHelper<IToggleProvider>
 | 
			
		||||
{
 | 
			
		||||
public:
 | 
			
		||||
    explicit UIAToggleProvider (AccessibilityNativeHandle* nativeHandle)
 | 
			
		||||
        : UIAProviderBase (nativeHandle)
 | 
			
		||||
    {
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    //==============================================================================
 | 
			
		||||
    JUCE_COMRESULT Toggle() override
 | 
			
		||||
    {
 | 
			
		||||
        if (! isElementValid())
 | 
			
		||||
            return (HRESULT) UIA_E_ELEMENTNOTAVAILABLE;
 | 
			
		||||
 | 
			
		||||
        const auto& handler = getHandler();
 | 
			
		||||
 | 
			
		||||
        if (handler.getActions().invoke (AccessibilityActionType::toggle))
 | 
			
		||||
        {
 | 
			
		||||
            VARIANT newValue;
 | 
			
		||||
            VariantHelpers::setInt (getCurrentToggleState(), &newValue);
 | 
			
		||||
 | 
			
		||||
            sendAccessibilityPropertyChangedEvent (handler, UIA_ToggleToggleStatePropertyId, newValue);
 | 
			
		||||
 | 
			
		||||
            return S_OK;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        return (HRESULT) UIA_E_NOTSUPPORTED;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    JUCE_COMRESULT get_ToggleState (ToggleState* pRetVal) override
 | 
			
		||||
    {
 | 
			
		||||
        return withCheckedComArgs (pRetVal, *this, [&]
 | 
			
		||||
        {
 | 
			
		||||
            *pRetVal = getCurrentToggleState();
 | 
			
		||||
            return S_OK;
 | 
			
		||||
        });
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
private:
 | 
			
		||||
    ToggleState getCurrentToggleState() const
 | 
			
		||||
    {
 | 
			
		||||
        return getHandler().getCurrentState().isChecked() ? ToggleState_On
 | 
			
		||||
                                                          : ToggleState_Off;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    //==============================================================================
 | 
			
		||||
    JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (UIAToggleProvider)
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
} // namespace juce
 | 
			
		||||
/*
 | 
			
		||||
  ==============================================================================
 | 
			
		||||
 | 
			
		||||
   This file is part of the JUCE library.
 | 
			
		||||
   Copyright (c) 2022 - Raw Material Software Limited
 | 
			
		||||
 | 
			
		||||
   JUCE is an open source library subject to commercial or open-source
 | 
			
		||||
   licensing.
 | 
			
		||||
 | 
			
		||||
   By using JUCE, you agree to the terms of both the JUCE 7 End-User License
 | 
			
		||||
   Agreement and JUCE Privacy Policy.
 | 
			
		||||
 | 
			
		||||
   End User License Agreement: www.juce.com/juce-7-licence
 | 
			
		||||
   Privacy Policy: www.juce.com/juce-privacy-policy
 | 
			
		||||
 | 
			
		||||
   Or: You may also use this code under the terms of the GPL v3 (see
 | 
			
		||||
   www.gnu.org/licenses).
 | 
			
		||||
 | 
			
		||||
   JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
 | 
			
		||||
   EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
 | 
			
		||||
   DISCLAIMED.
 | 
			
		||||
 | 
			
		||||
  ==============================================================================
 | 
			
		||||
*/
 | 
			
		||||
 | 
			
		||||
namespace juce
 | 
			
		||||
{
 | 
			
		||||
 | 
			
		||||
//==============================================================================
 | 
			
		||||
class UIAToggleProvider  : public UIAProviderBase,
 | 
			
		||||
                           public ComBaseClassHelper<ComTypes::IToggleProvider>
 | 
			
		||||
{
 | 
			
		||||
public:
 | 
			
		||||
    using UIAProviderBase::UIAProviderBase;
 | 
			
		||||
 | 
			
		||||
    //==============================================================================
 | 
			
		||||
    JUCE_COMRESULT Toggle() override
 | 
			
		||||
    {
 | 
			
		||||
        if (! isElementValid())
 | 
			
		||||
            return (HRESULT) UIA_E_ELEMENTNOTAVAILABLE;
 | 
			
		||||
 | 
			
		||||
        const auto& handler = getHandler();
 | 
			
		||||
 | 
			
		||||
        if (handler.getActions().invoke (AccessibilityActionType::toggle)
 | 
			
		||||
            || handler.getActions().invoke (AccessibilityActionType::press))
 | 
			
		||||
        {
 | 
			
		||||
            VARIANT newValue;
 | 
			
		||||
            VariantHelpers::setInt (getCurrentToggleState(), &newValue);
 | 
			
		||||
 | 
			
		||||
            sendAccessibilityPropertyChangedEvent (handler, UIA_ToggleToggleStatePropertyId, newValue);
 | 
			
		||||
 | 
			
		||||
            return S_OK;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        return (HRESULT) UIA_E_NOTSUPPORTED;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    JUCE_COMRESULT get_ToggleState (ComTypes::ToggleState* pRetVal) override
 | 
			
		||||
    {
 | 
			
		||||
        return withCheckedComArgs (pRetVal, *this, [&]
 | 
			
		||||
        {
 | 
			
		||||
            *pRetVal = getCurrentToggleState();
 | 
			
		||||
            return S_OK;
 | 
			
		||||
        });
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
private:
 | 
			
		||||
    ComTypes::ToggleState getCurrentToggleState() const
 | 
			
		||||
    {
 | 
			
		||||
        return getHandler().getCurrentState().isChecked() ? ComTypes::ToggleState_On
 | 
			
		||||
                                                          : ComTypes::ToggleState_Off;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    //==============================================================================
 | 
			
		||||
    JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (UIAToggleProvider)
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
} // namespace juce
 | 
			
		||||
 
 | 
			
		||||
@@ -1,125 +1,122 @@
 | 
			
		||||
/*
 | 
			
		||||
  ==============================================================================
 | 
			
		||||
 | 
			
		||||
   This file is part of the JUCE library.
 | 
			
		||||
   Copyright (c) 2020 - Raw Material Software Limited
 | 
			
		||||
 | 
			
		||||
   JUCE is an open source library subject to commercial or open-source
 | 
			
		||||
   licensing.
 | 
			
		||||
 | 
			
		||||
   By using JUCE, you agree to the terms of both the JUCE 6 End-User License
 | 
			
		||||
   Agreement and JUCE Privacy Policy (both effective as of the 16th June 2020).
 | 
			
		||||
 | 
			
		||||
   End User License Agreement: www.juce.com/juce-6-licence
 | 
			
		||||
   Privacy Policy: www.juce.com/juce-privacy-policy
 | 
			
		||||
 | 
			
		||||
   Or: You may also use this code under the terms of the GPL v3 (see
 | 
			
		||||
   www.gnu.org/licenses).
 | 
			
		||||
 | 
			
		||||
   JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
 | 
			
		||||
   EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
 | 
			
		||||
   DISCLAIMED.
 | 
			
		||||
 | 
			
		||||
  ==============================================================================
 | 
			
		||||
*/
 | 
			
		||||
 | 
			
		||||
namespace juce
 | 
			
		||||
{
 | 
			
		||||
 | 
			
		||||
//==============================================================================
 | 
			
		||||
class UIATransformProvider  : public UIAProviderBase,
 | 
			
		||||
                              public ComBaseClassHelper<ITransformProvider>
 | 
			
		||||
{
 | 
			
		||||
public:
 | 
			
		||||
    explicit UIATransformProvider (AccessibilityNativeHandle* nativeHandle)
 | 
			
		||||
        : UIAProviderBase (nativeHandle)
 | 
			
		||||
    {
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    //==============================================================================
 | 
			
		||||
    JUCE_COMRESULT Move (double x, double y) override
 | 
			
		||||
    {
 | 
			
		||||
        if (! isElementValid())
 | 
			
		||||
            return (HRESULT) UIA_E_ELEMENTNOTAVAILABLE;
 | 
			
		||||
 | 
			
		||||
        if (auto* peer = getPeer())
 | 
			
		||||
        {
 | 
			
		||||
            RECT rect;
 | 
			
		||||
            GetWindowRect ((HWND) peer->getNativeHandle(), &rect);
 | 
			
		||||
 | 
			
		||||
            rect.left = roundToInt (x);
 | 
			
		||||
            rect.top  = roundToInt (y);
 | 
			
		||||
 | 
			
		||||
            auto bounds = Rectangle<int>::leftTopRightBottom (rect.left, rect.top, rect.right, rect.bottom);
 | 
			
		||||
 | 
			
		||||
            peer->setBounds (Desktop::getInstance().getDisplays().physicalToLogical (bounds),
 | 
			
		||||
                             peer->isFullScreen());
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        return S_OK;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    JUCE_COMRESULT Resize (double width, double height) override
 | 
			
		||||
    {
 | 
			
		||||
        if (! isElementValid())
 | 
			
		||||
            return (HRESULT) UIA_E_ELEMENTNOTAVAILABLE;
 | 
			
		||||
 | 
			
		||||
        if (auto* peer = getPeer())
 | 
			
		||||
        {
 | 
			
		||||
            auto scale = peer->getPlatformScaleFactor();
 | 
			
		||||
 | 
			
		||||
            peer->getComponent().setSize (roundToInt (width  / scale),
 | 
			
		||||
                                          roundToInt (height / scale));
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        return S_OK;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    JUCE_COMRESULT Rotate (double) override
 | 
			
		||||
    {
 | 
			
		||||
        if (! isElementValid())
 | 
			
		||||
            return (HRESULT) UIA_E_ELEMENTNOTAVAILABLE;
 | 
			
		||||
 | 
			
		||||
        return (HRESULT) UIA_E_NOTSUPPORTED;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    JUCE_COMRESULT get_CanMove (BOOL* pRetVal) override
 | 
			
		||||
    {
 | 
			
		||||
        return withCheckedComArgs (pRetVal, *this, [&]
 | 
			
		||||
        {
 | 
			
		||||
            *pRetVal = true;
 | 
			
		||||
            return S_OK;
 | 
			
		||||
        });
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    JUCE_COMRESULT get_CanResize (BOOL* pRetVal) override
 | 
			
		||||
    {
 | 
			
		||||
        return withCheckedComArgs (pRetVal, *this, [&]
 | 
			
		||||
        {
 | 
			
		||||
            if (auto* peer = getPeer())
 | 
			
		||||
                *pRetVal = ((peer->getStyleFlags() & ComponentPeer::windowIsResizable) != 0);
 | 
			
		||||
 | 
			
		||||
            return S_OK;
 | 
			
		||||
        });
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    JUCE_COMRESULT get_CanRotate (BOOL* pRetVal) override
 | 
			
		||||
    {
 | 
			
		||||
        return withCheckedComArgs (pRetVal, *this, [&]
 | 
			
		||||
        {
 | 
			
		||||
            *pRetVal = false;
 | 
			
		||||
            return S_OK;
 | 
			
		||||
        });
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
private:
 | 
			
		||||
    ComponentPeer* getPeer() const
 | 
			
		||||
    {
 | 
			
		||||
        return getHandler().getComponent().getPeer();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    //==============================================================================
 | 
			
		||||
    JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (UIATransformProvider)
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
} // namespace juce
 | 
			
		||||
/*
 | 
			
		||||
  ==============================================================================
 | 
			
		||||
 | 
			
		||||
   This file is part of the JUCE library.
 | 
			
		||||
   Copyright (c) 2022 - Raw Material Software Limited
 | 
			
		||||
 | 
			
		||||
   JUCE is an open source library subject to commercial or open-source
 | 
			
		||||
   licensing.
 | 
			
		||||
 | 
			
		||||
   By using JUCE, you agree to the terms of both the JUCE 7 End-User License
 | 
			
		||||
   Agreement and JUCE Privacy Policy.
 | 
			
		||||
 | 
			
		||||
   End User License Agreement: www.juce.com/juce-7-licence
 | 
			
		||||
   Privacy Policy: www.juce.com/juce-privacy-policy
 | 
			
		||||
 | 
			
		||||
   Or: You may also use this code under the terms of the GPL v3 (see
 | 
			
		||||
   www.gnu.org/licenses).
 | 
			
		||||
 | 
			
		||||
   JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
 | 
			
		||||
   EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
 | 
			
		||||
   DISCLAIMED.
 | 
			
		||||
 | 
			
		||||
  ==============================================================================
 | 
			
		||||
*/
 | 
			
		||||
 | 
			
		||||
namespace juce
 | 
			
		||||
{
 | 
			
		||||
 | 
			
		||||
//==============================================================================
 | 
			
		||||
class UIATransformProvider  : public UIAProviderBase,
 | 
			
		||||
                              public ComBaseClassHelper<ComTypes::ITransformProvider>
 | 
			
		||||
{
 | 
			
		||||
public:
 | 
			
		||||
    using UIAProviderBase::UIAProviderBase;
 | 
			
		||||
 | 
			
		||||
    //==============================================================================
 | 
			
		||||
    JUCE_COMRESULT Move (double x, double y) override
 | 
			
		||||
    {
 | 
			
		||||
        if (! isElementValid())
 | 
			
		||||
            return (HRESULT) UIA_E_ELEMENTNOTAVAILABLE;
 | 
			
		||||
 | 
			
		||||
        if (auto* peer = getPeer())
 | 
			
		||||
        {
 | 
			
		||||
            RECT rect;
 | 
			
		||||
            GetWindowRect ((HWND) peer->getNativeHandle(), &rect);
 | 
			
		||||
 | 
			
		||||
            rect.left = roundToInt (x);
 | 
			
		||||
            rect.top  = roundToInt (y);
 | 
			
		||||
 | 
			
		||||
            auto bounds = Rectangle<int>::leftTopRightBottom (rect.left, rect.top, rect.right, rect.bottom);
 | 
			
		||||
 | 
			
		||||
            peer->setBounds (Desktop::getInstance().getDisplays().physicalToLogical (bounds),
 | 
			
		||||
                             peer->isFullScreen());
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        return S_OK;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    JUCE_COMRESULT Resize (double width, double height) override
 | 
			
		||||
    {
 | 
			
		||||
        if (! isElementValid())
 | 
			
		||||
            return (HRESULT) UIA_E_ELEMENTNOTAVAILABLE;
 | 
			
		||||
 | 
			
		||||
        if (auto* peer = getPeer())
 | 
			
		||||
        {
 | 
			
		||||
            auto scale = peer->getPlatformScaleFactor();
 | 
			
		||||
 | 
			
		||||
            peer->getComponent().setSize (roundToInt (width  / scale),
 | 
			
		||||
                                          roundToInt (height / scale));
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        return S_OK;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    JUCE_COMRESULT Rotate (double) override
 | 
			
		||||
    {
 | 
			
		||||
        if (! isElementValid())
 | 
			
		||||
            return (HRESULT) UIA_E_ELEMENTNOTAVAILABLE;
 | 
			
		||||
 | 
			
		||||
        return (HRESULT) UIA_E_NOTSUPPORTED;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    JUCE_COMRESULT get_CanMove (BOOL* pRetVal) override
 | 
			
		||||
    {
 | 
			
		||||
        return withCheckedComArgs (pRetVal, *this, [&]
 | 
			
		||||
        {
 | 
			
		||||
            *pRetVal = true;
 | 
			
		||||
            return S_OK;
 | 
			
		||||
        });
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    JUCE_COMRESULT get_CanResize (BOOL* pRetVal) override
 | 
			
		||||
    {
 | 
			
		||||
        return withCheckedComArgs (pRetVal, *this, [&]
 | 
			
		||||
        {
 | 
			
		||||
            if (auto* peer = getPeer())
 | 
			
		||||
                *pRetVal = ((peer->getStyleFlags() & ComponentPeer::windowIsResizable) != 0);
 | 
			
		||||
 | 
			
		||||
            return S_OK;
 | 
			
		||||
        });
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    JUCE_COMRESULT get_CanRotate (BOOL* pRetVal) override
 | 
			
		||||
    {
 | 
			
		||||
        return withCheckedComArgs (pRetVal, *this, [&]
 | 
			
		||||
        {
 | 
			
		||||
            *pRetVal = false;
 | 
			
		||||
            return S_OK;
 | 
			
		||||
        });
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
private:
 | 
			
		||||
    ComponentPeer* getPeer() const
 | 
			
		||||
    {
 | 
			
		||||
        return getHandler().getComponent().getPeer();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    //==============================================================================
 | 
			
		||||
    JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (UIATransformProvider)
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
} // namespace juce
 | 
			
		||||
 
 | 
			
		||||
@@ -1,86 +1,83 @@
 | 
			
		||||
/*
 | 
			
		||||
  ==============================================================================
 | 
			
		||||
 | 
			
		||||
   This file is part of the JUCE library.
 | 
			
		||||
   Copyright (c) 2020 - Raw Material Software Limited
 | 
			
		||||
 | 
			
		||||
   JUCE is an open source library subject to commercial or open-source
 | 
			
		||||
   licensing.
 | 
			
		||||
 | 
			
		||||
   By using JUCE, you agree to the terms of both the JUCE 6 End-User License
 | 
			
		||||
   Agreement and JUCE Privacy Policy (both effective as of the 16th June 2020).
 | 
			
		||||
 | 
			
		||||
   End User License Agreement: www.juce.com/juce-6-licence
 | 
			
		||||
   Privacy Policy: www.juce.com/juce-privacy-policy
 | 
			
		||||
 | 
			
		||||
   Or: You may also use this code under the terms of the GPL v3 (see
 | 
			
		||||
   www.gnu.org/licenses).
 | 
			
		||||
 | 
			
		||||
   JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
 | 
			
		||||
   EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
 | 
			
		||||
   DISCLAIMED.
 | 
			
		||||
 | 
			
		||||
  ==============================================================================
 | 
			
		||||
*/
 | 
			
		||||
 | 
			
		||||
namespace juce
 | 
			
		||||
{
 | 
			
		||||
 | 
			
		||||
//==============================================================================
 | 
			
		||||
class UIAValueProvider  : public UIAProviderBase,
 | 
			
		||||
                          public ComBaseClassHelper<IValueProvider>
 | 
			
		||||
{
 | 
			
		||||
public:
 | 
			
		||||
    UIAValueProvider (AccessibilityNativeHandle* nativeHandle)
 | 
			
		||||
        : UIAProviderBase (nativeHandle)
 | 
			
		||||
    {
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    //==============================================================================
 | 
			
		||||
    JUCE_COMRESULT SetValue (LPCWSTR val) override
 | 
			
		||||
    {
 | 
			
		||||
        if (! isElementValid())
 | 
			
		||||
            return (HRESULT) UIA_E_ELEMENTNOTAVAILABLE;
 | 
			
		||||
 | 
			
		||||
        const auto& handler = getHandler();
 | 
			
		||||
        auto& valueInterface = *handler.getValueInterface();
 | 
			
		||||
 | 
			
		||||
        if (valueInterface.isReadOnly())
 | 
			
		||||
            return (HRESULT) UIA_E_NOTSUPPORTED;
 | 
			
		||||
 | 
			
		||||
        valueInterface.setValueAsString (String (val));
 | 
			
		||||
 | 
			
		||||
        VARIANT newValue;
 | 
			
		||||
        VariantHelpers::setString (valueInterface.getCurrentValueAsString(), &newValue);
 | 
			
		||||
 | 
			
		||||
        sendAccessibilityPropertyChangedEvent (handler, UIA_ValueValuePropertyId, newValue);
 | 
			
		||||
 | 
			
		||||
        return S_OK;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    JUCE_COMRESULT get_Value (BSTR* pRetVal) override
 | 
			
		||||
    {
 | 
			
		||||
        return withCheckedComArgs (pRetVal, *this, [&]
 | 
			
		||||
        {
 | 
			
		||||
            auto currentValueString = getHandler().getValueInterface()->getCurrentValueAsString();
 | 
			
		||||
 | 
			
		||||
            *pRetVal = SysAllocString ((const OLECHAR*) currentValueString.toWideCharPointer());
 | 
			
		||||
            return S_OK;
 | 
			
		||||
        });
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    JUCE_COMRESULT get_IsReadOnly (BOOL* pRetVal) override
 | 
			
		||||
    {
 | 
			
		||||
        return withCheckedComArgs (pRetVal, *this, [&]
 | 
			
		||||
        {
 | 
			
		||||
            *pRetVal = getHandler().getValueInterface()->isReadOnly();
 | 
			
		||||
            return S_OK;
 | 
			
		||||
        });
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
private:
 | 
			
		||||
    //==============================================================================
 | 
			
		||||
    JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (UIAValueProvider)
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
} // namespace juce
 | 
			
		||||
/*
 | 
			
		||||
  ==============================================================================
 | 
			
		||||
 | 
			
		||||
   This file is part of the JUCE library.
 | 
			
		||||
   Copyright (c) 2022 - Raw Material Software Limited
 | 
			
		||||
 | 
			
		||||
   JUCE is an open source library subject to commercial or open-source
 | 
			
		||||
   licensing.
 | 
			
		||||
 | 
			
		||||
   By using JUCE, you agree to the terms of both the JUCE 7 End-User License
 | 
			
		||||
   Agreement and JUCE Privacy Policy.
 | 
			
		||||
 | 
			
		||||
   End User License Agreement: www.juce.com/juce-7-licence
 | 
			
		||||
   Privacy Policy: www.juce.com/juce-privacy-policy
 | 
			
		||||
 | 
			
		||||
   Or: You may also use this code under the terms of the GPL v3 (see
 | 
			
		||||
   www.gnu.org/licenses).
 | 
			
		||||
 | 
			
		||||
   JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
 | 
			
		||||
   EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
 | 
			
		||||
   DISCLAIMED.
 | 
			
		||||
 | 
			
		||||
  ==============================================================================
 | 
			
		||||
*/
 | 
			
		||||
 | 
			
		||||
namespace juce
 | 
			
		||||
{
 | 
			
		||||
 | 
			
		||||
//==============================================================================
 | 
			
		||||
class UIAValueProvider  : public UIAProviderBase,
 | 
			
		||||
                          public ComBaseClassHelper<ComTypes::IValueProvider>
 | 
			
		||||
{
 | 
			
		||||
public:
 | 
			
		||||
    using UIAProviderBase::UIAProviderBase;
 | 
			
		||||
 | 
			
		||||
    //==============================================================================
 | 
			
		||||
    JUCE_COMRESULT SetValue (LPCWSTR val) override
 | 
			
		||||
    {
 | 
			
		||||
        if (! isElementValid())
 | 
			
		||||
            return (HRESULT) UIA_E_ELEMENTNOTAVAILABLE;
 | 
			
		||||
 | 
			
		||||
        const auto& handler = getHandler();
 | 
			
		||||
        auto& valueInterface = *handler.getValueInterface();
 | 
			
		||||
 | 
			
		||||
        if (valueInterface.isReadOnly())
 | 
			
		||||
            return (HRESULT) UIA_E_NOTSUPPORTED;
 | 
			
		||||
 | 
			
		||||
        valueInterface.setValueAsString (String (val));
 | 
			
		||||
 | 
			
		||||
        VARIANT newValue;
 | 
			
		||||
        VariantHelpers::setString (valueInterface.getCurrentValueAsString(), &newValue);
 | 
			
		||||
 | 
			
		||||
        sendAccessibilityPropertyChangedEvent (handler, UIA_ValueValuePropertyId, newValue);
 | 
			
		||||
 | 
			
		||||
        return S_OK;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    JUCE_COMRESULT get_Value (BSTR* pRetVal) override
 | 
			
		||||
    {
 | 
			
		||||
        return withCheckedComArgs (pRetVal, *this, [&]
 | 
			
		||||
        {
 | 
			
		||||
            auto currentValueString = getHandler().getValueInterface()->getCurrentValueAsString();
 | 
			
		||||
 | 
			
		||||
            *pRetVal = SysAllocString ((const OLECHAR*) currentValueString.toWideCharPointer());
 | 
			
		||||
            return S_OK;
 | 
			
		||||
        });
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    JUCE_COMRESULT get_IsReadOnly (BOOL* pRetVal) override
 | 
			
		||||
    {
 | 
			
		||||
        return withCheckedComArgs (pRetVal, *this, [&]
 | 
			
		||||
        {
 | 
			
		||||
            *pRetVal = getHandler().getValueInterface()->isReadOnly();
 | 
			
		||||
            return S_OK;
 | 
			
		||||
        });
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
private:
 | 
			
		||||
    //==============================================================================
 | 
			
		||||
    JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (UIAValueProvider)
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
} // namespace juce
 | 
			
		||||
 
 | 
			
		||||
@@ -1,197 +1,194 @@
 | 
			
		||||
/*
 | 
			
		||||
  ==============================================================================
 | 
			
		||||
 | 
			
		||||
   This file is part of the JUCE library.
 | 
			
		||||
   Copyright (c) 2020 - Raw Material Software Limited
 | 
			
		||||
 | 
			
		||||
   JUCE is an open source library subject to commercial or open-source
 | 
			
		||||
   licensing.
 | 
			
		||||
 | 
			
		||||
   By using JUCE, you agree to the terms of both the JUCE 6 End-User License
 | 
			
		||||
   Agreement and JUCE Privacy Policy (both effective as of the 16th June 2020).
 | 
			
		||||
 | 
			
		||||
   End User License Agreement: www.juce.com/juce-6-licence
 | 
			
		||||
   Privacy Policy: www.juce.com/juce-privacy-policy
 | 
			
		||||
 | 
			
		||||
   Or: You may also use this code under the terms of the GPL v3 (see
 | 
			
		||||
   www.gnu.org/licenses).
 | 
			
		||||
 | 
			
		||||
   JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
 | 
			
		||||
   EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
 | 
			
		||||
   DISCLAIMED.
 | 
			
		||||
 | 
			
		||||
  ==============================================================================
 | 
			
		||||
*/
 | 
			
		||||
 | 
			
		||||
namespace juce
 | 
			
		||||
{
 | 
			
		||||
 | 
			
		||||
//==============================================================================
 | 
			
		||||
class UIAWindowProvider : public UIAProviderBase,
 | 
			
		||||
                          public ComBaseClassHelper<IWindowProvider>
 | 
			
		||||
{
 | 
			
		||||
public:
 | 
			
		||||
    explicit UIAWindowProvider (AccessibilityNativeHandle* nativeHandle)
 | 
			
		||||
        : UIAProviderBase (nativeHandle)
 | 
			
		||||
    {
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    //==============================================================================
 | 
			
		||||
    JUCE_COMRESULT SetVisualState (WindowVisualState state) override
 | 
			
		||||
    {
 | 
			
		||||
        if (! isElementValid())
 | 
			
		||||
            return (HRESULT) UIA_E_ELEMENTNOTAVAILABLE;
 | 
			
		||||
 | 
			
		||||
        if (auto* peer = getPeer())
 | 
			
		||||
        {
 | 
			
		||||
            switch (state)
 | 
			
		||||
            {
 | 
			
		||||
                case WindowVisualState_Maximized:
 | 
			
		||||
                    peer->setFullScreen (true);
 | 
			
		||||
                    break;
 | 
			
		||||
 | 
			
		||||
                case WindowVisualState_Minimized:
 | 
			
		||||
                    peer->setMinimised (true);
 | 
			
		||||
                    break;
 | 
			
		||||
 | 
			
		||||
                case WindowVisualState_Normal:
 | 
			
		||||
                    peer->setFullScreen (false);
 | 
			
		||||
                    peer->setMinimised (false);
 | 
			
		||||
                    break;
 | 
			
		||||
 | 
			
		||||
                default:
 | 
			
		||||
                    break;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            return S_OK;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        return (HRESULT) UIA_E_NOTSUPPORTED;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    JUCE_COMRESULT Close() override
 | 
			
		||||
    {
 | 
			
		||||
        if (! isElementValid())
 | 
			
		||||
            return (HRESULT) UIA_E_ELEMENTNOTAVAILABLE;
 | 
			
		||||
 | 
			
		||||
        if (auto* peer = getPeer())
 | 
			
		||||
        {
 | 
			
		||||
            peer->handleUserClosingWindow();
 | 
			
		||||
            return S_OK;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        return (HRESULT) UIA_E_NOTSUPPORTED;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    JUCE_COMRESULT WaitForInputIdle (int, BOOL* pRetVal) override
 | 
			
		||||
    {
 | 
			
		||||
        return withCheckedComArgs (pRetVal, *this, []
 | 
			
		||||
        {
 | 
			
		||||
            return (HRESULT) UIA_E_NOTSUPPORTED;
 | 
			
		||||
        });
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    JUCE_COMRESULT get_CanMaximize (BOOL* pRetVal) override
 | 
			
		||||
    {
 | 
			
		||||
        return withCheckedComArgs (pRetVal, *this, [&]() -> HRESULT
 | 
			
		||||
        {
 | 
			
		||||
            if (auto* peer = getPeer())
 | 
			
		||||
            {
 | 
			
		||||
                *pRetVal = (peer->getStyleFlags() & ComponentPeer::windowHasMaximiseButton) != 0;
 | 
			
		||||
                return S_OK;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            return (HRESULT) UIA_E_NOTSUPPORTED;
 | 
			
		||||
        });
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    JUCE_COMRESULT get_CanMinimize (BOOL* pRetVal) override
 | 
			
		||||
    {
 | 
			
		||||
        return withCheckedComArgs (pRetVal, *this, [&]() -> HRESULT
 | 
			
		||||
        {
 | 
			
		||||
            if (auto* peer = getPeer())
 | 
			
		||||
            {
 | 
			
		||||
                *pRetVal = (peer->getStyleFlags() & ComponentPeer::windowHasMinimiseButton) != 0;
 | 
			
		||||
                return S_OK;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            return (HRESULT) UIA_E_NOTSUPPORTED;
 | 
			
		||||
        });
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    JUCE_COMRESULT get_IsModal (BOOL* pRetVal) override
 | 
			
		||||
    {
 | 
			
		||||
        return withCheckedComArgs (pRetVal, *this, [&]() -> HRESULT
 | 
			
		||||
        {
 | 
			
		||||
            if (auto* peer = getPeer())
 | 
			
		||||
            {
 | 
			
		||||
                *pRetVal = peer->getComponent().isCurrentlyModal();
 | 
			
		||||
                return S_OK;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            return (HRESULT) UIA_E_NOTSUPPORTED;
 | 
			
		||||
        });
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    JUCE_COMRESULT get_WindowVisualState (WindowVisualState* pRetVal) override
 | 
			
		||||
    {
 | 
			
		||||
        return withCheckedComArgs (pRetVal, *this, [&]() -> HRESULT
 | 
			
		||||
        {
 | 
			
		||||
            if (auto* peer = getPeer())
 | 
			
		||||
            {
 | 
			
		||||
                if (peer->isFullScreen())
 | 
			
		||||
                    *pRetVal = WindowVisualState_Maximized;
 | 
			
		||||
                else if (peer->isMinimised())
 | 
			
		||||
                    *pRetVal = WindowVisualState_Minimized;
 | 
			
		||||
                else
 | 
			
		||||
                    *pRetVal = WindowVisualState_Normal;
 | 
			
		||||
 | 
			
		||||
                return S_OK;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            return (HRESULT) UIA_E_NOTSUPPORTED;
 | 
			
		||||
        });
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    JUCE_COMRESULT get_WindowInteractionState (WindowInteractionState* pRetVal) override
 | 
			
		||||
    {
 | 
			
		||||
        return withCheckedComArgs (pRetVal, *this, [&]() -> HRESULT
 | 
			
		||||
        {
 | 
			
		||||
            if (auto* peer = getPeer())
 | 
			
		||||
            {
 | 
			
		||||
                *pRetVal = peer->getComponent().isCurrentlyBlockedByAnotherModalComponent()
 | 
			
		||||
                    ? WindowInteractionState::WindowInteractionState_BlockedByModalWindow
 | 
			
		||||
                    : WindowInteractionState::WindowInteractionState_Running;
 | 
			
		||||
 | 
			
		||||
                return S_OK;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            return (HRESULT) UIA_E_NOTSUPPORTED;
 | 
			
		||||
        });
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    JUCE_COMRESULT get_IsTopmost (BOOL* pRetVal) override
 | 
			
		||||
    {
 | 
			
		||||
        return withCheckedComArgs (pRetVal, *this, [&]() -> HRESULT
 | 
			
		||||
        {
 | 
			
		||||
            if (auto* peer = getPeer())
 | 
			
		||||
            {
 | 
			
		||||
                *pRetVal = peer->isFocused();
 | 
			
		||||
                return S_OK;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            return (HRESULT) UIA_E_NOTSUPPORTED;
 | 
			
		||||
        });
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
private:
 | 
			
		||||
    ComponentPeer* getPeer() const
 | 
			
		||||
    {
 | 
			
		||||
        return getHandler().getComponent().getPeer();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    //==============================================================================
 | 
			
		||||
    JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (UIAWindowProvider)
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
} // namespace juce
 | 
			
		||||
/*
 | 
			
		||||
  ==============================================================================
 | 
			
		||||
 | 
			
		||||
   This file is part of the JUCE library.
 | 
			
		||||
   Copyright (c) 2022 - Raw Material Software Limited
 | 
			
		||||
 | 
			
		||||
   JUCE is an open source library subject to commercial or open-source
 | 
			
		||||
   licensing.
 | 
			
		||||
 | 
			
		||||
   By using JUCE, you agree to the terms of both the JUCE 7 End-User License
 | 
			
		||||
   Agreement and JUCE Privacy Policy.
 | 
			
		||||
 | 
			
		||||
   End User License Agreement: www.juce.com/juce-7-licence
 | 
			
		||||
   Privacy Policy: www.juce.com/juce-privacy-policy
 | 
			
		||||
 | 
			
		||||
   Or: You may also use this code under the terms of the GPL v3 (see
 | 
			
		||||
   www.gnu.org/licenses).
 | 
			
		||||
 | 
			
		||||
   JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
 | 
			
		||||
   EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
 | 
			
		||||
   DISCLAIMED.
 | 
			
		||||
 | 
			
		||||
  ==============================================================================
 | 
			
		||||
*/
 | 
			
		||||
 | 
			
		||||
namespace juce
 | 
			
		||||
{
 | 
			
		||||
 | 
			
		||||
//==============================================================================
 | 
			
		||||
class UIAWindowProvider : public UIAProviderBase,
 | 
			
		||||
                          public ComBaseClassHelper<ComTypes::IWindowProvider>
 | 
			
		||||
{
 | 
			
		||||
public:
 | 
			
		||||
    using UIAProviderBase::UIAProviderBase;
 | 
			
		||||
 | 
			
		||||
    //==============================================================================
 | 
			
		||||
    JUCE_COMRESULT SetVisualState (ComTypes::WindowVisualState state) override
 | 
			
		||||
    {
 | 
			
		||||
        if (! isElementValid())
 | 
			
		||||
            return (HRESULT) UIA_E_ELEMENTNOTAVAILABLE;
 | 
			
		||||
 | 
			
		||||
        if (auto* peer = getPeer())
 | 
			
		||||
        {
 | 
			
		||||
            switch (state)
 | 
			
		||||
            {
 | 
			
		||||
                case ComTypes::WindowVisualState_Maximized:
 | 
			
		||||
                    peer->setFullScreen (true);
 | 
			
		||||
                    break;
 | 
			
		||||
 | 
			
		||||
                case ComTypes::WindowVisualState_Minimized:
 | 
			
		||||
                    peer->setMinimised (true);
 | 
			
		||||
                    break;
 | 
			
		||||
 | 
			
		||||
                case ComTypes::WindowVisualState_Normal:
 | 
			
		||||
                    peer->setFullScreen (false);
 | 
			
		||||
                    peer->setMinimised (false);
 | 
			
		||||
                    break;
 | 
			
		||||
 | 
			
		||||
                default:
 | 
			
		||||
                    break;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            return S_OK;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        return (HRESULT) UIA_E_NOTSUPPORTED;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    JUCE_COMRESULT Close() override
 | 
			
		||||
    {
 | 
			
		||||
        if (! isElementValid())
 | 
			
		||||
            return (HRESULT) UIA_E_ELEMENTNOTAVAILABLE;
 | 
			
		||||
 | 
			
		||||
        if (auto* peer = getPeer())
 | 
			
		||||
        {
 | 
			
		||||
            peer->handleUserClosingWindow();
 | 
			
		||||
            return S_OK;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        return (HRESULT) UIA_E_NOTSUPPORTED;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    JUCE_COMRESULT WaitForInputIdle (int, BOOL* pRetVal) override
 | 
			
		||||
    {
 | 
			
		||||
        return withCheckedComArgs (pRetVal, *this, []
 | 
			
		||||
        {
 | 
			
		||||
            return (HRESULT) UIA_E_NOTSUPPORTED;
 | 
			
		||||
        });
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    JUCE_COMRESULT get_CanMaximize (BOOL* pRetVal) override
 | 
			
		||||
    {
 | 
			
		||||
        return withCheckedComArgs (pRetVal, *this, [&]() -> HRESULT
 | 
			
		||||
        {
 | 
			
		||||
            if (auto* peer = getPeer())
 | 
			
		||||
            {
 | 
			
		||||
                *pRetVal = (peer->getStyleFlags() & ComponentPeer::windowHasMaximiseButton) != 0;
 | 
			
		||||
                return S_OK;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            return (HRESULT) UIA_E_NOTSUPPORTED;
 | 
			
		||||
        });
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    JUCE_COMRESULT get_CanMinimize (BOOL* pRetVal) override
 | 
			
		||||
    {
 | 
			
		||||
        return withCheckedComArgs (pRetVal, *this, [&]() -> HRESULT
 | 
			
		||||
        {
 | 
			
		||||
            if (auto* peer = getPeer())
 | 
			
		||||
            {
 | 
			
		||||
                *pRetVal = (peer->getStyleFlags() & ComponentPeer::windowHasMinimiseButton) != 0;
 | 
			
		||||
                return S_OK;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            return (HRESULT) UIA_E_NOTSUPPORTED;
 | 
			
		||||
        });
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    JUCE_COMRESULT get_IsModal (BOOL* pRetVal) override
 | 
			
		||||
    {
 | 
			
		||||
        return withCheckedComArgs (pRetVal, *this, [&]() -> HRESULT
 | 
			
		||||
        {
 | 
			
		||||
            if (auto* peer = getPeer())
 | 
			
		||||
            {
 | 
			
		||||
                *pRetVal = peer->getComponent().isCurrentlyModal();
 | 
			
		||||
                return S_OK;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            return (HRESULT) UIA_E_NOTSUPPORTED;
 | 
			
		||||
        });
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    JUCE_COMRESULT get_WindowVisualState (ComTypes::WindowVisualState* pRetVal) override
 | 
			
		||||
    {
 | 
			
		||||
        return withCheckedComArgs (pRetVal, *this, [&]() -> HRESULT
 | 
			
		||||
        {
 | 
			
		||||
            if (auto* peer = getPeer())
 | 
			
		||||
            {
 | 
			
		||||
                if (peer->isFullScreen())
 | 
			
		||||
                    *pRetVal = ComTypes::WindowVisualState_Maximized;
 | 
			
		||||
                else if (peer->isMinimised())
 | 
			
		||||
                    *pRetVal = ComTypes::WindowVisualState_Minimized;
 | 
			
		||||
                else
 | 
			
		||||
                    *pRetVal = ComTypes::WindowVisualState_Normal;
 | 
			
		||||
 | 
			
		||||
                return S_OK;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            return (HRESULT) UIA_E_NOTSUPPORTED;
 | 
			
		||||
        });
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    JUCE_COMRESULT get_WindowInteractionState (ComTypes::WindowInteractionState* pRetVal) override
 | 
			
		||||
    {
 | 
			
		||||
        return withCheckedComArgs (pRetVal, *this, [&]() -> HRESULT
 | 
			
		||||
        {
 | 
			
		||||
            if (auto* peer = getPeer())
 | 
			
		||||
            {
 | 
			
		||||
                *pRetVal = peer->getComponent().isCurrentlyBlockedByAnotherModalComponent()
 | 
			
		||||
                    ? ComTypes::WindowInteractionState::WindowInteractionState_BlockedByModalWindow
 | 
			
		||||
                    : ComTypes::WindowInteractionState::WindowInteractionState_Running;
 | 
			
		||||
 | 
			
		||||
                return S_OK;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            return (HRESULT) UIA_E_NOTSUPPORTED;
 | 
			
		||||
        });
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    JUCE_COMRESULT get_IsTopmost (BOOL* pRetVal) override
 | 
			
		||||
    {
 | 
			
		||||
        return withCheckedComArgs (pRetVal, *this, [&]() -> HRESULT
 | 
			
		||||
        {
 | 
			
		||||
            if (auto* peer = getPeer())
 | 
			
		||||
            {
 | 
			
		||||
                *pRetVal = peer->isFocused();
 | 
			
		||||
                return S_OK;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            return (HRESULT) UIA_E_NOTSUPPORTED;
 | 
			
		||||
        });
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
private:
 | 
			
		||||
    ComponentPeer* getPeer() const
 | 
			
		||||
    {
 | 
			
		||||
        return getHandler().getComponent().getPeer();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    //==============================================================================
 | 
			
		||||
    JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (UIAWindowProvider)
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
} // namespace juce
 | 
			
		||||
 
 | 
			
		||||
@@ -1,158 +1,160 @@
 | 
			
		||||
/*
 | 
			
		||||
  ==============================================================================
 | 
			
		||||
 | 
			
		||||
   This file is part of the JUCE library.
 | 
			
		||||
   Copyright (c) 2020 - Raw Material Software Limited
 | 
			
		||||
 | 
			
		||||
   JUCE is an open source library subject to commercial or open-source
 | 
			
		||||
   licensing.
 | 
			
		||||
 | 
			
		||||
   By using JUCE, you agree to the terms of both the JUCE 6 End-User License
 | 
			
		||||
   Agreement and JUCE Privacy Policy (both effective as of the 16th June 2020).
 | 
			
		||||
 | 
			
		||||
   End User License Agreement: www.juce.com/juce-6-licence
 | 
			
		||||
   Privacy Policy: www.juce.com/juce-privacy-policy
 | 
			
		||||
 | 
			
		||||
   Or: You may also use this code under the terms of the GPL v3 (see
 | 
			
		||||
   www.gnu.org/licenses).
 | 
			
		||||
 | 
			
		||||
   JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
 | 
			
		||||
   EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
 | 
			
		||||
   DISCLAIMED.
 | 
			
		||||
 | 
			
		||||
  ==============================================================================
 | 
			
		||||
*/
 | 
			
		||||
 | 
			
		||||
namespace juce
 | 
			
		||||
{
 | 
			
		||||
 | 
			
		||||
class WindowsUIAWrapper  : public DeletedAtShutdown
 | 
			
		||||
{
 | 
			
		||||
public:
 | 
			
		||||
    bool isLoaded() const noexcept
 | 
			
		||||
    {
 | 
			
		||||
        return uiaReturnRawElementProvider            != nullptr
 | 
			
		||||
            && uiaHostProviderFromHwnd                != nullptr
 | 
			
		||||
            && uiaRaiseAutomationPropertyChangedEvent != nullptr
 | 
			
		||||
            && uiaRaiseAutomationEvent                != nullptr
 | 
			
		||||
            && uiaClientsAreListening                 != nullptr
 | 
			
		||||
            && uiaDisconnectProvider                  != nullptr
 | 
			
		||||
            && uiaDisconnectAllProviders              != nullptr;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    //==============================================================================
 | 
			
		||||
    LRESULT returnRawElementProvider (HWND hwnd, WPARAM wParam, LPARAM lParam, IRawElementProviderSimple* provider)
 | 
			
		||||
    {
 | 
			
		||||
        return uiaReturnRawElementProvider != nullptr ? uiaReturnRawElementProvider (hwnd, wParam, lParam, provider)
 | 
			
		||||
                                                      : (LRESULT) nullptr;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    JUCE_COMRESULT hostProviderFromHwnd (HWND hwnd, IRawElementProviderSimple** provider)
 | 
			
		||||
    {
 | 
			
		||||
        return uiaHostProviderFromHwnd != nullptr ? uiaHostProviderFromHwnd (hwnd, provider)
 | 
			
		||||
                                                  : (HRESULT) UIA_E_NOTSUPPORTED;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    JUCE_COMRESULT raiseAutomationPropertyChangedEvent (IRawElementProviderSimple* provider, PROPERTYID propID, VARIANT oldValue, VARIANT newValue)
 | 
			
		||||
    {
 | 
			
		||||
        return uiaRaiseAutomationPropertyChangedEvent != nullptr ? uiaRaiseAutomationPropertyChangedEvent (provider, propID, oldValue, newValue)
 | 
			
		||||
                                                                 : (HRESULT) UIA_E_NOTSUPPORTED;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    JUCE_COMRESULT raiseAutomationEvent (IRawElementProviderSimple* provider, EVENTID eventID)
 | 
			
		||||
    {
 | 
			
		||||
        return uiaRaiseAutomationEvent != nullptr ? uiaRaiseAutomationEvent (provider, eventID)
 | 
			
		||||
                                                  : (HRESULT) UIA_E_NOTSUPPORTED;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    BOOL clientsAreListening()
 | 
			
		||||
    {
 | 
			
		||||
        return uiaClientsAreListening != nullptr ? uiaClientsAreListening()
 | 
			
		||||
                                                 : false;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    JUCE_COMRESULT disconnectProvider (IRawElementProviderSimple* provider)
 | 
			
		||||
    {
 | 
			
		||||
        if (uiaDisconnectProvider != nullptr)
 | 
			
		||||
        {
 | 
			
		||||
            const ScopedValueSetter<IRawElementProviderSimple*> disconnectingProviderSetter (disconnectingProvider, provider);
 | 
			
		||||
            return uiaDisconnectProvider (provider);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        return (HRESULT) UIA_E_NOTSUPPORTED;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    JUCE_COMRESULT disconnectAllProviders()
 | 
			
		||||
    {
 | 
			
		||||
        if (uiaDisconnectAllProviders != nullptr)
 | 
			
		||||
        {
 | 
			
		||||
            const ScopedValueSetter<bool> disconnectingAllProvidersSetter (disconnectingAllProviders, true);
 | 
			
		||||
            return uiaDisconnectAllProviders();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        return (HRESULT) UIA_E_NOTSUPPORTED;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    //==============================================================================
 | 
			
		||||
    bool isProviderDisconnecting (IRawElementProviderSimple* provider)
 | 
			
		||||
    {
 | 
			
		||||
        return disconnectingProvider == provider || disconnectingAllProviders;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    //==============================================================================
 | 
			
		||||
    JUCE_DECLARE_SINGLETON_SINGLETHREADED_MINIMAL (WindowsUIAWrapper)
 | 
			
		||||
 | 
			
		||||
private:
 | 
			
		||||
    //==============================================================================
 | 
			
		||||
    WindowsUIAWrapper()
 | 
			
		||||
    {
 | 
			
		||||
        // force UIA COM library initialisation here to prevent an exception when calling methods from SendMessage()
 | 
			
		||||
        if (isLoaded())
 | 
			
		||||
            returnRawElementProvider (nullptr, 0, 0, nullptr);
 | 
			
		||||
        else
 | 
			
		||||
            jassertfalse; // UIAutomationCore could not be loaded!
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    ~WindowsUIAWrapper()
 | 
			
		||||
    {
 | 
			
		||||
        disconnectAllProviders();
 | 
			
		||||
 | 
			
		||||
        if (uiaHandle != nullptr)
 | 
			
		||||
            ::FreeLibrary (uiaHandle);
 | 
			
		||||
 | 
			
		||||
        clearSingletonInstance();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    //==============================================================================
 | 
			
		||||
    template<typename FuncType>
 | 
			
		||||
    static FuncType getUiaFunction (HMODULE module, StringRef funcName)
 | 
			
		||||
    {
 | 
			
		||||
        return (FuncType) GetProcAddress (module, funcName);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    //==============================================================================
 | 
			
		||||
    using UiaReturnRawElementProviderFunc            = LRESULT (WINAPI*) (HWND, WPARAM, LPARAM, IRawElementProviderSimple*);
 | 
			
		||||
    using UiaHostProviderFromHwndFunc                = HRESULT (WINAPI*) (HWND, IRawElementProviderSimple**);
 | 
			
		||||
    using UiaRaiseAutomationPropertyChangedEventFunc = HRESULT (WINAPI*) (IRawElementProviderSimple*, PROPERTYID, VARIANT, VARIANT);
 | 
			
		||||
    using UiaRaiseAutomationEventFunc                = HRESULT (WINAPI*) (IRawElementProviderSimple*, EVENTID);
 | 
			
		||||
    using UiaClientsAreListeningFunc                 = BOOL    (WINAPI*) ();
 | 
			
		||||
    using UiaDisconnectProviderFunc                  = HRESULT (WINAPI*) (IRawElementProviderSimple*);
 | 
			
		||||
    using UiaDisconnectAllProvidersFunc              = HRESULT (WINAPI*) ();
 | 
			
		||||
 | 
			
		||||
    HMODULE uiaHandle = ::LoadLibraryA ("UIAutomationCore.dll");
 | 
			
		||||
    UiaReturnRawElementProviderFunc            uiaReturnRawElementProvider            = getUiaFunction<UiaReturnRawElementProviderFunc>            (uiaHandle, "UiaReturnRawElementProvider");
 | 
			
		||||
    UiaHostProviderFromHwndFunc                uiaHostProviderFromHwnd                = getUiaFunction<UiaHostProviderFromHwndFunc>                (uiaHandle, "UiaHostProviderFromHwnd");
 | 
			
		||||
    UiaRaiseAutomationPropertyChangedEventFunc uiaRaiseAutomationPropertyChangedEvent = getUiaFunction<UiaRaiseAutomationPropertyChangedEventFunc> (uiaHandle, "UiaRaiseAutomationPropertyChangedEvent");
 | 
			
		||||
    UiaRaiseAutomationEventFunc                uiaRaiseAutomationEvent                = getUiaFunction<UiaRaiseAutomationEventFunc>                (uiaHandle, "UiaRaiseAutomationEvent");
 | 
			
		||||
    UiaClientsAreListeningFunc                 uiaClientsAreListening                 = getUiaFunction<UiaClientsAreListeningFunc>                 (uiaHandle, "UiaClientsAreListening");
 | 
			
		||||
    UiaDisconnectProviderFunc                  uiaDisconnectProvider                  = getUiaFunction<UiaDisconnectProviderFunc>                  (uiaHandle, "UiaDisconnectProvider");
 | 
			
		||||
    UiaDisconnectAllProvidersFunc              uiaDisconnectAllProviders              = getUiaFunction<UiaDisconnectAllProvidersFunc>              (uiaHandle, "UiaDisconnectAllProviders");
 | 
			
		||||
 | 
			
		||||
    IRawElementProviderSimple* disconnectingProvider = nullptr;
 | 
			
		||||
    bool disconnectingAllProviders = false;
 | 
			
		||||
 | 
			
		||||
    //==============================================================================
 | 
			
		||||
    JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (WindowsUIAWrapper)
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
} // namespace juce
 | 
			
		||||
/*
 | 
			
		||||
  ==============================================================================
 | 
			
		||||
 | 
			
		||||
   This file is part of the JUCE library.
 | 
			
		||||
   Copyright (c) 2022 - Raw Material Software Limited
 | 
			
		||||
 | 
			
		||||
   JUCE is an open source library subject to commercial or open-source
 | 
			
		||||
   licensing.
 | 
			
		||||
 | 
			
		||||
   By using JUCE, you agree to the terms of both the JUCE 7 End-User License
 | 
			
		||||
   Agreement and JUCE Privacy Policy.
 | 
			
		||||
 | 
			
		||||
   End User License Agreement: www.juce.com/juce-7-licence
 | 
			
		||||
   Privacy Policy: www.juce.com/juce-privacy-policy
 | 
			
		||||
 | 
			
		||||
   Or: You may also use this code under the terms of the GPL v3 (see
 | 
			
		||||
   www.gnu.org/licenses).
 | 
			
		||||
 | 
			
		||||
   JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
 | 
			
		||||
   EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
 | 
			
		||||
   DISCLAIMED.
 | 
			
		||||
 | 
			
		||||
  ==============================================================================
 | 
			
		||||
*/
 | 
			
		||||
 | 
			
		||||
namespace juce
 | 
			
		||||
{
 | 
			
		||||
 | 
			
		||||
class WindowsUIAWrapper  : public DeletedAtShutdown
 | 
			
		||||
{
 | 
			
		||||
public:
 | 
			
		||||
    bool isLoaded() const noexcept
 | 
			
		||||
    {
 | 
			
		||||
        return uiaReturnRawElementProvider            != nullptr
 | 
			
		||||
            && uiaHostProviderFromHwnd                != nullptr
 | 
			
		||||
            && uiaRaiseAutomationPropertyChangedEvent != nullptr
 | 
			
		||||
            && uiaRaiseAutomationEvent                != nullptr
 | 
			
		||||
            && uiaClientsAreListening                 != nullptr
 | 
			
		||||
            && uiaDisconnectProvider                  != nullptr
 | 
			
		||||
            && uiaDisconnectAllProviders              != nullptr;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    //==============================================================================
 | 
			
		||||
    LRESULT returnRawElementProvider (HWND hwnd, WPARAM wParam, LPARAM lParam, IRawElementProviderSimple* provider)
 | 
			
		||||
    {
 | 
			
		||||
        return uiaReturnRawElementProvider != nullptr ? uiaReturnRawElementProvider (hwnd, wParam, lParam, provider)
 | 
			
		||||
                                                      : (LRESULT) nullptr;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    JUCE_COMRESULT hostProviderFromHwnd (HWND hwnd, IRawElementProviderSimple** provider)
 | 
			
		||||
    {
 | 
			
		||||
        return uiaHostProviderFromHwnd != nullptr ? uiaHostProviderFromHwnd (hwnd, provider)
 | 
			
		||||
                                                  : (HRESULT) UIA_E_NOTSUPPORTED;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    JUCE_COMRESULT raiseAutomationPropertyChangedEvent (IRawElementProviderSimple* provider, PROPERTYID propID, VARIANT oldValue, VARIANT newValue)
 | 
			
		||||
    {
 | 
			
		||||
        return uiaRaiseAutomationPropertyChangedEvent != nullptr ? uiaRaiseAutomationPropertyChangedEvent (provider, propID, oldValue, newValue)
 | 
			
		||||
                                                                 : (HRESULT) UIA_E_NOTSUPPORTED;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    JUCE_COMRESULT raiseAutomationEvent (IRawElementProviderSimple* provider, EVENTID eventID)
 | 
			
		||||
    {
 | 
			
		||||
        return uiaRaiseAutomationEvent != nullptr ? uiaRaiseAutomationEvent (provider, eventID)
 | 
			
		||||
                                                  : (HRESULT) UIA_E_NOTSUPPORTED;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    BOOL clientsAreListening()
 | 
			
		||||
    {
 | 
			
		||||
        return uiaClientsAreListening != nullptr ? uiaClientsAreListening()
 | 
			
		||||
                                                 : false;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    JUCE_COMRESULT disconnectProvider (IRawElementProviderSimple* provider)
 | 
			
		||||
    {
 | 
			
		||||
        if (uiaDisconnectProvider != nullptr)
 | 
			
		||||
        {
 | 
			
		||||
            const ScopedValueSetter<IRawElementProviderSimple*> disconnectingProviderSetter (disconnectingProvider, provider);
 | 
			
		||||
            return uiaDisconnectProvider (provider);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        return (HRESULT) UIA_E_NOTSUPPORTED;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    JUCE_COMRESULT disconnectAllProviders()
 | 
			
		||||
    {
 | 
			
		||||
        if (uiaDisconnectAllProviders != nullptr)
 | 
			
		||||
        {
 | 
			
		||||
            const ScopedValueSetter<bool> disconnectingAllProvidersSetter (disconnectingAllProviders, true);
 | 
			
		||||
            return uiaDisconnectAllProviders();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        return (HRESULT) UIA_E_NOTSUPPORTED;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    //==============================================================================
 | 
			
		||||
    bool isProviderDisconnecting (IRawElementProviderSimple* provider)
 | 
			
		||||
    {
 | 
			
		||||
        return disconnectingProvider == provider || disconnectingAllProviders;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    //==============================================================================
 | 
			
		||||
    JUCE_DECLARE_SINGLETON_SINGLETHREADED_MINIMAL (WindowsUIAWrapper)
 | 
			
		||||
 | 
			
		||||
private:
 | 
			
		||||
    //==============================================================================
 | 
			
		||||
    WindowsUIAWrapper()
 | 
			
		||||
    {
 | 
			
		||||
        // force UIA COM library initialisation here to prevent an exception when calling methods from SendMessage()
 | 
			
		||||
        if (isLoaded())
 | 
			
		||||
            returnRawElementProvider (nullptr, 0, 0, nullptr);
 | 
			
		||||
        else
 | 
			
		||||
            jassertfalse; // UIAutomationCore could not be loaded!
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    ~WindowsUIAWrapper()
 | 
			
		||||
    {
 | 
			
		||||
        disconnectAllProviders();
 | 
			
		||||
 | 
			
		||||
        if (uiaHandle != nullptr)
 | 
			
		||||
            ::FreeLibrary (uiaHandle);
 | 
			
		||||
 | 
			
		||||
        clearSingletonInstance();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    //==============================================================================
 | 
			
		||||
    template <typename FuncType>
 | 
			
		||||
    static FuncType getUiaFunction (HMODULE module, LPCSTR funcName)
 | 
			
		||||
    {
 | 
			
		||||
        JUCE_BEGIN_IGNORE_WARNINGS_GCC_LIKE ("-Wcast-function-type")
 | 
			
		||||
        return (FuncType) GetProcAddress (module, funcName);
 | 
			
		||||
        JUCE_END_IGNORE_WARNINGS_GCC_LIKE
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    //==============================================================================
 | 
			
		||||
    using UiaReturnRawElementProviderFunc            = LRESULT (WINAPI*) (HWND, WPARAM, LPARAM, IRawElementProviderSimple*);
 | 
			
		||||
    using UiaHostProviderFromHwndFunc                = HRESULT (WINAPI*) (HWND, IRawElementProviderSimple**);
 | 
			
		||||
    using UiaRaiseAutomationPropertyChangedEventFunc = HRESULT (WINAPI*) (IRawElementProviderSimple*, PROPERTYID, VARIANT, VARIANT);
 | 
			
		||||
    using UiaRaiseAutomationEventFunc                = HRESULT (WINAPI*) (IRawElementProviderSimple*, EVENTID);
 | 
			
		||||
    using UiaClientsAreListeningFunc                 = BOOL    (WINAPI*) ();
 | 
			
		||||
    using UiaDisconnectProviderFunc                  = HRESULT (WINAPI*) (IRawElementProviderSimple*);
 | 
			
		||||
    using UiaDisconnectAllProvidersFunc              = HRESULT (WINAPI*) ();
 | 
			
		||||
 | 
			
		||||
    HMODULE uiaHandle = ::LoadLibraryA ("UIAutomationCore.dll");
 | 
			
		||||
    UiaReturnRawElementProviderFunc            uiaReturnRawElementProvider            = getUiaFunction<UiaReturnRawElementProviderFunc>            (uiaHandle, "UiaReturnRawElementProvider");
 | 
			
		||||
    UiaHostProviderFromHwndFunc                uiaHostProviderFromHwnd                = getUiaFunction<UiaHostProviderFromHwndFunc>                (uiaHandle, "UiaHostProviderFromHwnd");
 | 
			
		||||
    UiaRaiseAutomationPropertyChangedEventFunc uiaRaiseAutomationPropertyChangedEvent = getUiaFunction<UiaRaiseAutomationPropertyChangedEventFunc> (uiaHandle, "UiaRaiseAutomationPropertyChangedEvent");
 | 
			
		||||
    UiaRaiseAutomationEventFunc                uiaRaiseAutomationEvent                = getUiaFunction<UiaRaiseAutomationEventFunc>                (uiaHandle, "UiaRaiseAutomationEvent");
 | 
			
		||||
    UiaClientsAreListeningFunc                 uiaClientsAreListening                 = getUiaFunction<UiaClientsAreListeningFunc>                 (uiaHandle, "UiaClientsAreListening");
 | 
			
		||||
    UiaDisconnectProviderFunc                  uiaDisconnectProvider                  = getUiaFunction<UiaDisconnectProviderFunc>                  (uiaHandle, "UiaDisconnectProvider");
 | 
			
		||||
    UiaDisconnectAllProvidersFunc              uiaDisconnectAllProviders              = getUiaFunction<UiaDisconnectAllProvidersFunc>              (uiaHandle, "UiaDisconnectAllProviders");
 | 
			
		||||
 | 
			
		||||
    IRawElementProviderSimple* disconnectingProvider = nullptr;
 | 
			
		||||
    bool disconnectingAllProviders = false;
 | 
			
		||||
 | 
			
		||||
    //==============================================================================
 | 
			
		||||
    JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (WindowsUIAWrapper)
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
} // namespace juce
 | 
			
		||||
 
 | 
			
		||||
@@ -2,15 +2,15 @@
 | 
			
		||||
  ==============================================================================
 | 
			
		||||
 | 
			
		||||
   This file is part of the JUCE library.
 | 
			
		||||
   Copyright (c) 2020 - Raw Material Software Limited
 | 
			
		||||
   Copyright (c) 2022 - Raw Material Software Limited
 | 
			
		||||
 | 
			
		||||
   JUCE is an open source library subject to commercial or open-source
 | 
			
		||||
   licensing.
 | 
			
		||||
 | 
			
		||||
   By using JUCE, you agree to the terms of both the JUCE 6 End-User License
 | 
			
		||||
   Agreement and JUCE Privacy Policy (both effective as of the 16th June 2020).
 | 
			
		||||
   By using JUCE, you agree to the terms of both the JUCE 7 End-User License
 | 
			
		||||
   Agreement and JUCE Privacy Policy.
 | 
			
		||||
 | 
			
		||||
   End User License Agreement: www.juce.com/juce-6-licence
 | 
			
		||||
   End User License Agreement: www.juce.com/juce-7-licence
 | 
			
		||||
   Privacy Policy: www.juce.com/juce-privacy-policy
 | 
			
		||||
 | 
			
		||||
   Or: You may also use this code under the terms of the GPL v3 (see
 | 
			
		||||
@@ -144,6 +144,7 @@ public final class ComponentPeerView extends ViewGroup
 | 
			
		||||
    private native void handleMouseDown (long host, int index, float x, float y, long time);
 | 
			
		||||
    private native void handleMouseDrag (long host, int index, float x, float y, long time);
 | 
			
		||||
    private native void handleMouseUp (long host, int index, float x, float y, long time);
 | 
			
		||||
    private native void handleAccessibilityHover (long host, int action, float x, float y, long time);
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
    public boolean onTouchEvent (MotionEvent event)
 | 
			
		||||
@@ -227,35 +228,17 @@ public final class ComponentPeerView extends ViewGroup
 | 
			
		||||
    @Override
 | 
			
		||||
    public boolean onHoverEvent (MotionEvent event)
 | 
			
		||||
    {
 | 
			
		||||
        if (host == 0 || ! accessibilityManager.isTouchExplorationEnabled ())
 | 
			
		||||
            return false;
 | 
			
		||||
 | 
			
		||||
        int action = event.getAction ();
 | 
			
		||||
        long time = event.getEventTime ();
 | 
			
		||||
 | 
			
		||||
        switch (action & MotionEvent.ACTION_MASK) // simulate "mouse" events when touch exploration is enabled
 | 
			
		||||
        if (accessibilityManager.isTouchExplorationEnabled())
 | 
			
		||||
        {
 | 
			
		||||
            case MotionEvent.ACTION_HOVER_ENTER:
 | 
			
		||||
                handleMouseDown (host, event.getPointerId (0), event.getRawX (), event.getRawY (), time);
 | 
			
		||||
                return true;
 | 
			
		||||
 | 
			
		||||
            case MotionEvent.ACTION_HOVER_EXIT:
 | 
			
		||||
                handleMouseUp (host, event.getPointerId (0), event.getRawX (), event.getRawY (), time);
 | 
			
		||||
                return true;
 | 
			
		||||
 | 
			
		||||
            case MotionEvent.ACTION_HOVER_MOVE:
 | 
			
		||||
                handleMouseDrag (host, event.getPointerId (0), event.getRawX (), event.getRawY (), time);
 | 
			
		||||
                return true;
 | 
			
		||||
 | 
			
		||||
            default:
 | 
			
		||||
                break;
 | 
			
		||||
            handleAccessibilityHover (host, event.getActionMasked(), event.getRawX(), event.getRawY(), event.getEventTime());
 | 
			
		||||
            return true;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        return false;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    //==============================================================================
 | 
			
		||||
    private native void handleKeyDown (long host, int keycode, int textchar);
 | 
			
		||||
    private native void handleKeyDown (long host, int keycode, int textchar, int kbFlags);
 | 
			
		||||
    private native void handleKeyUp (long host, int keycode, int textchar);
 | 
			
		||||
    private native void handleBackButton (long host);
 | 
			
		||||
    private native void handleKeyboardHidden (long host);
 | 
			
		||||
@@ -300,7 +283,7 @@ public final class ComponentPeerView extends ViewGroup
 | 
			
		||||
                return super.onKeyDown (keyCode, event);
 | 
			
		||||
            case KeyEvent.KEYCODE_BACK:
 | 
			
		||||
            {
 | 
			
		||||
                backButtonPressed();
 | 
			
		||||
                backButtonPressed ();
 | 
			
		||||
                return true;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
@@ -308,7 +291,10 @@ public final class ComponentPeerView extends ViewGroup
 | 
			
		||||
                break;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        handleKeyDown (host, keyCode, event.getUnicodeChar ());
 | 
			
		||||
        handleKeyDown (host,
 | 
			
		||||
                       keyCode,
 | 
			
		||||
                       event.getUnicodeChar (),
 | 
			
		||||
                       event.getMetaState ());
 | 
			
		||||
        return true;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
@@ -334,7 +320,11 @@ public final class ComponentPeerView extends ViewGroup
 | 
			
		||||
        if (event.getCharacters () != null)
 | 
			
		||||
        {
 | 
			
		||||
            int utf8Char = event.getCharacters ().codePointAt (0);
 | 
			
		||||
            handleKeyDown (host, utf8Char, utf8Char);
 | 
			
		||||
 | 
			
		||||
            handleKeyDown (host,
 | 
			
		||||
                           keyCode,
 | 
			
		||||
                           utf8Char,
 | 
			
		||||
                           event.getMetaState ());
 | 
			
		||||
            return true;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -2,15 +2,15 @@
 | 
			
		||||
  ==============================================================================
 | 
			
		||||
 | 
			
		||||
   This file is part of the JUCE library.
 | 
			
		||||
   Copyright (c) 2020 - Raw Material Software Limited
 | 
			
		||||
   Copyright (c) 2022 - Raw Material Software Limited
 | 
			
		||||
 | 
			
		||||
   JUCE is an open source library subject to commercial or open-source
 | 
			
		||||
   licensing.
 | 
			
		||||
 | 
			
		||||
   By using JUCE, you agree to the terms of both the JUCE 6 End-User License
 | 
			
		||||
   Agreement and JUCE Privacy Policy (both effective as of the 16th June 2020).
 | 
			
		||||
   By using JUCE, you agree to the terms of both the JUCE 7 End-User License
 | 
			
		||||
   Agreement and JUCE Privacy Policy.
 | 
			
		||||
 | 
			
		||||
   End User License Agreement: www.juce.com/juce-6-licence
 | 
			
		||||
   End User License Agreement: www.juce.com/juce-7-licence
 | 
			
		||||
   Privacy Policy: www.juce.com/juce-privacy-policy
 | 
			
		||||
 | 
			
		||||
   Or: You may also use this code under the terms of the GPL v3 (see
 | 
			
		||||
 
 | 
			
		||||
@@ -2,15 +2,15 @@
 | 
			
		||||
  ==============================================================================
 | 
			
		||||
 | 
			
		||||
   This file is part of the JUCE library.
 | 
			
		||||
   Copyright (c) 2020 - Raw Material Software Limited
 | 
			
		||||
   Copyright (c) 2022 - Raw Material Software Limited
 | 
			
		||||
 | 
			
		||||
   JUCE is an open source library subject to commercial or open-source
 | 
			
		||||
   licensing.
 | 
			
		||||
 | 
			
		||||
   By using JUCE, you agree to the terms of both the JUCE 6 End-User License
 | 
			
		||||
   Agreement and JUCE Privacy Policy (both effective as of the 16th June 2020).
 | 
			
		||||
   By using JUCE, you agree to the terms of both the JUCE 7 End-User License
 | 
			
		||||
   Agreement and JUCE Privacy Policy.
 | 
			
		||||
 | 
			
		||||
   End User License Agreement: www.juce.com/juce-6-licence
 | 
			
		||||
   End User License Agreement: www.juce.com/juce-7-licence
 | 
			
		||||
   Privacy Policy: www.juce.com/juce-privacy-policy
 | 
			
		||||
 | 
			
		||||
   Or: You may also use this code under the terms of the GPL v3 (see
 | 
			
		||||
 
 | 
			
		||||
@@ -2,15 +2,15 @@
 | 
			
		||||
  ==============================================================================
 | 
			
		||||
 | 
			
		||||
   This file is part of the JUCE library.
 | 
			
		||||
   Copyright (c) 2020 - Raw Material Software Limited
 | 
			
		||||
   Copyright (c) 2022 - Raw Material Software Limited
 | 
			
		||||
 | 
			
		||||
   JUCE is an open source library subject to commercial or open-source
 | 
			
		||||
   licensing.
 | 
			
		||||
 | 
			
		||||
   By using JUCE, you agree to the terms of both the JUCE 6 End-User License
 | 
			
		||||
   Agreement and JUCE Privacy Policy (both effective as of the 16th June 2020).
 | 
			
		||||
   By using JUCE, you agree to the terms of both the JUCE 7 End-User License
 | 
			
		||||
   Agreement and JUCE Privacy Policy.
 | 
			
		||||
 | 
			
		||||
   End User License Agreement: www.juce.com/juce-6-licence
 | 
			
		||||
   End User License Agreement: www.juce.com/juce-7-licence
 | 
			
		||||
   Privacy Policy: www.juce.com/juce-privacy-policy
 | 
			
		||||
 | 
			
		||||
   Or: You may also use this code under the terms of the GPL v3 (see
 | 
			
		||||
@@ -33,6 +33,7 @@ public class JuceActivity   extends Activity
 | 
			
		||||
{
 | 
			
		||||
    //==============================================================================
 | 
			
		||||
    private native void appNewIntent (Intent intent);
 | 
			
		||||
    private native void appOnResume();
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
    protected void onNewIntent (Intent intent)
 | 
			
		||||
@@ -42,4 +43,12 @@ public class JuceActivity   extends Activity
 | 
			
		||||
 | 
			
		||||
        appNewIntent (intent);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
    protected void onResume()
 | 
			
		||||
    {
 | 
			
		||||
        super.onResume();
 | 
			
		||||
 | 
			
		||||
        appOnResume();
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -2,15 +2,15 @@
 | 
			
		||||
  ==============================================================================
 | 
			
		||||
 | 
			
		||||
   This file is part of the JUCE library.
 | 
			
		||||
   Copyright (c) 2020 - Raw Material Software Limited
 | 
			
		||||
   Copyright (c) 2022 - Raw Material Software Limited
 | 
			
		||||
 | 
			
		||||
   JUCE is an open source library subject to commercial or open-source
 | 
			
		||||
   licensing.
 | 
			
		||||
 | 
			
		||||
   By using JUCE, you agree to the terms of both the JUCE 6 End-User License
 | 
			
		||||
   Agreement and JUCE Privacy Policy (both effective as of the 16th June 2020).
 | 
			
		||||
   By using JUCE, you agree to the terms of both the JUCE 7 End-User License
 | 
			
		||||
   Agreement and JUCE Privacy Policy.
 | 
			
		||||
 | 
			
		||||
   End User License Agreement: www.juce.com/juce-6-licence
 | 
			
		||||
   End User License Agreement: www.juce.com/juce-7-licence
 | 
			
		||||
   Privacy Policy: www.juce.com/juce-privacy-policy
 | 
			
		||||
 | 
			
		||||
   Or: You may also use this code under the terms of the GPL v3 (see
 | 
			
		||||
 
 | 
			
		||||
@@ -1,107 +1,107 @@
 | 
			
		||||
/*
 | 
			
		||||
  ==============================================================================
 | 
			
		||||
 | 
			
		||||
   This file is part of the JUCE library.
 | 
			
		||||
   Copyright (c) 2020 - Raw Material Software Limited
 | 
			
		||||
 | 
			
		||||
   JUCE is an open source library subject to commercial or open-source
 | 
			
		||||
   licensing.
 | 
			
		||||
 | 
			
		||||
   By using JUCE, you agree to the terms of both the JUCE 6 End-User License
 | 
			
		||||
   Agreement and JUCE Privacy Policy (both effective as of the 16th June 2020).
 | 
			
		||||
 | 
			
		||||
   End User License Agreement: www.juce.com/juce-6-licence
 | 
			
		||||
   Privacy Policy: www.juce.com/juce-privacy-policy
 | 
			
		||||
 | 
			
		||||
   Or: You may also use this code under the terms of the GPL v3 (see
 | 
			
		||||
   www.gnu.org/licenses).
 | 
			
		||||
 | 
			
		||||
   JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
 | 
			
		||||
   EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
 | 
			
		||||
   DISCLAIMED.
 | 
			
		||||
 | 
			
		||||
  ==============================================================================
 | 
			
		||||
*/
 | 
			
		||||
 | 
			
		||||
JUCE_BEGIN_IGNORE_WARNINGS_GCC_LIKE ("-Wzero-as-null-pointer-constant")
 | 
			
		||||
 | 
			
		||||
namespace juce
 | 
			
		||||
{
 | 
			
		||||
 | 
			
		||||
template <typename IDType>
 | 
			
		||||
class MultiTouchMapper
 | 
			
		||||
{
 | 
			
		||||
public:
 | 
			
		||||
    MultiTouchMapper() {}
 | 
			
		||||
 | 
			
		||||
    int getIndexOfTouch (ComponentPeer* peer, IDType touchID)
 | 
			
		||||
    {
 | 
			
		||||
        jassert (touchID != 0); // need to rethink this if IDs can be 0!
 | 
			
		||||
        TouchInfo info {touchID, peer};
 | 
			
		||||
 | 
			
		||||
        int touchIndex = currentTouches.indexOf (info);
 | 
			
		||||
 | 
			
		||||
        if (touchIndex < 0)
 | 
			
		||||
        {
 | 
			
		||||
            auto emptyTouchIndex = currentTouches.indexOf ({});
 | 
			
		||||
            touchIndex = (emptyTouchIndex >= 0 ? emptyTouchIndex : currentTouches.size());
 | 
			
		||||
 | 
			
		||||
            currentTouches.set (touchIndex, info);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        return touchIndex;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    void clear()
 | 
			
		||||
    {
 | 
			
		||||
        currentTouches.clear();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    void clearTouch (int index)
 | 
			
		||||
    {
 | 
			
		||||
        currentTouches.set (index, {});
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    bool areAnyTouchesActive() const noexcept
 | 
			
		||||
    {
 | 
			
		||||
        for (auto& t : currentTouches)
 | 
			
		||||
            if (t.touchId != 0)
 | 
			
		||||
                return true;
 | 
			
		||||
 | 
			
		||||
        return false;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    void deleteAllTouchesForPeer (ComponentPeer* peer)
 | 
			
		||||
    {
 | 
			
		||||
        for (auto& t : currentTouches)
 | 
			
		||||
            if (t.owner == peer)
 | 
			
		||||
                t.touchId = 0;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
private:
 | 
			
		||||
    //==============================================================================
 | 
			
		||||
    struct TouchInfo
 | 
			
		||||
    {
 | 
			
		||||
        TouchInfo() noexcept  : touchId (0), owner (nullptr) {}
 | 
			
		||||
        TouchInfo (IDType idToUse, ComponentPeer* peer) noexcept  : touchId (idToUse), owner (peer) {}
 | 
			
		||||
 | 
			
		||||
        TouchInfo (const TouchInfo&) = default;
 | 
			
		||||
        TouchInfo& operator= (const TouchInfo&) = default;
 | 
			
		||||
        TouchInfo (TouchInfo&&) noexcept = default;
 | 
			
		||||
        TouchInfo& operator= (TouchInfo&&) noexcept = default;
 | 
			
		||||
 | 
			
		||||
        IDType touchId;
 | 
			
		||||
        ComponentPeer* owner;
 | 
			
		||||
 | 
			
		||||
        bool operator== (const TouchInfo& o) const noexcept     { return (touchId == o.touchId); }
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    //==============================================================================
 | 
			
		||||
    Array<TouchInfo> currentTouches;
 | 
			
		||||
 | 
			
		||||
    JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (MultiTouchMapper)
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
} // namespace juce
 | 
			
		||||
 | 
			
		||||
JUCE_END_IGNORE_WARNINGS_GCC_LIKE
 | 
			
		||||
/*
 | 
			
		||||
  ==============================================================================
 | 
			
		||||
 | 
			
		||||
   This file is part of the JUCE library.
 | 
			
		||||
   Copyright (c) 2022 - Raw Material Software Limited
 | 
			
		||||
 | 
			
		||||
   JUCE is an open source library subject to commercial or open-source
 | 
			
		||||
   licensing.
 | 
			
		||||
 | 
			
		||||
   By using JUCE, you agree to the terms of both the JUCE 7 End-User License
 | 
			
		||||
   Agreement and JUCE Privacy Policy.
 | 
			
		||||
 | 
			
		||||
   End User License Agreement: www.juce.com/juce-7-licence
 | 
			
		||||
   Privacy Policy: www.juce.com/juce-privacy-policy
 | 
			
		||||
 | 
			
		||||
   Or: You may also use this code under the terms of the GPL v3 (see
 | 
			
		||||
   www.gnu.org/licenses).
 | 
			
		||||
 | 
			
		||||
   JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
 | 
			
		||||
   EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
 | 
			
		||||
   DISCLAIMED.
 | 
			
		||||
 | 
			
		||||
  ==============================================================================
 | 
			
		||||
*/
 | 
			
		||||
 | 
			
		||||
JUCE_BEGIN_IGNORE_WARNINGS_GCC_LIKE ("-Wzero-as-null-pointer-constant")
 | 
			
		||||
 | 
			
		||||
namespace juce
 | 
			
		||||
{
 | 
			
		||||
 | 
			
		||||
template <typename IDType>
 | 
			
		||||
class MultiTouchMapper
 | 
			
		||||
{
 | 
			
		||||
public:
 | 
			
		||||
    MultiTouchMapper() {}
 | 
			
		||||
 | 
			
		||||
    int getIndexOfTouch (ComponentPeer* peer, IDType touchID)
 | 
			
		||||
    {
 | 
			
		||||
        jassert (touchID != 0); // need to rethink this if IDs can be 0!
 | 
			
		||||
        TouchInfo info {touchID, peer};
 | 
			
		||||
 | 
			
		||||
        int touchIndex = currentTouches.indexOf (info);
 | 
			
		||||
 | 
			
		||||
        if (touchIndex < 0)
 | 
			
		||||
        {
 | 
			
		||||
            auto emptyTouchIndex = currentTouches.indexOf ({});
 | 
			
		||||
            touchIndex = (emptyTouchIndex >= 0 ? emptyTouchIndex : currentTouches.size());
 | 
			
		||||
 | 
			
		||||
            currentTouches.set (touchIndex, info);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        return touchIndex;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    void clear()
 | 
			
		||||
    {
 | 
			
		||||
        currentTouches.clear();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    void clearTouch (int index)
 | 
			
		||||
    {
 | 
			
		||||
        currentTouches.set (index, {});
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    bool areAnyTouchesActive() const noexcept
 | 
			
		||||
    {
 | 
			
		||||
        for (auto& t : currentTouches)
 | 
			
		||||
            if (t.touchId != 0)
 | 
			
		||||
                return true;
 | 
			
		||||
 | 
			
		||||
        return false;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    void deleteAllTouchesForPeer (ComponentPeer* peer)
 | 
			
		||||
    {
 | 
			
		||||
        for (auto& t : currentTouches)
 | 
			
		||||
            if (t.owner == peer)
 | 
			
		||||
                t.touchId = 0;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
private:
 | 
			
		||||
    //==============================================================================
 | 
			
		||||
    struct TouchInfo
 | 
			
		||||
    {
 | 
			
		||||
        TouchInfo() noexcept  : touchId (0), owner (nullptr) {}
 | 
			
		||||
        TouchInfo (IDType idToUse, ComponentPeer* peer) noexcept  : touchId (idToUse), owner (peer) {}
 | 
			
		||||
 | 
			
		||||
        TouchInfo (const TouchInfo&) = default;
 | 
			
		||||
        TouchInfo& operator= (const TouchInfo&) = default;
 | 
			
		||||
        TouchInfo (TouchInfo&&) noexcept = default;
 | 
			
		||||
        TouchInfo& operator= (TouchInfo&&) noexcept = default;
 | 
			
		||||
 | 
			
		||||
        IDType touchId;
 | 
			
		||||
        ComponentPeer* owner;
 | 
			
		||||
 | 
			
		||||
        bool operator== (const TouchInfo& o) const noexcept     { return (touchId == o.touchId); }
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    //==============================================================================
 | 
			
		||||
    Array<TouchInfo> currentTouches;
 | 
			
		||||
 | 
			
		||||
    JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (MultiTouchMapper)
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
} // namespace juce
 | 
			
		||||
 | 
			
		||||
JUCE_END_IGNORE_WARNINGS_GCC_LIKE
 | 
			
		||||
 
 | 
			
		||||
@@ -1,54 +1,54 @@
 | 
			
		||||
/*
 | 
			
		||||
  ==============================================================================
 | 
			
		||||
 | 
			
		||||
   This file is part of the JUCE library.
 | 
			
		||||
   Copyright (c) 2020 - Raw Material Software Limited
 | 
			
		||||
 | 
			
		||||
   JUCE is an open source library subject to commercial or open-source
 | 
			
		||||
   licensing.
 | 
			
		||||
 | 
			
		||||
   By using JUCE, you agree to the terms of both the JUCE 6 End-User License
 | 
			
		||||
   Agreement and JUCE Privacy Policy (both effective as of the 16th June 2020).
 | 
			
		||||
 | 
			
		||||
   End User License Agreement: www.juce.com/juce-6-licence
 | 
			
		||||
   Privacy Policy: www.juce.com/juce-privacy-policy
 | 
			
		||||
 | 
			
		||||
   Or: You may also use this code under the terms of the GPL v3 (see
 | 
			
		||||
   www.gnu.org/licenses).
 | 
			
		||||
 | 
			
		||||
   JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
 | 
			
		||||
   EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
 | 
			
		||||
   DISCLAIMED.
 | 
			
		||||
 | 
			
		||||
  ==============================================================================
 | 
			
		||||
*/
 | 
			
		||||
 | 
			
		||||
namespace juce
 | 
			
		||||
{
 | 
			
		||||
 | 
			
		||||
//==============================================================================
 | 
			
		||||
/**
 | 
			
		||||
    A Windows-specific class that temporarily sets the DPI awareness context of
 | 
			
		||||
    the current thread to be DPI unaware and resets it to the previous context
 | 
			
		||||
    when it goes out of scope.
 | 
			
		||||
 | 
			
		||||
    If you create one of these before creating a top-level window, the window
 | 
			
		||||
    will be DPI unaware and bitmap stretched by the OS on a display with >100%
 | 
			
		||||
    scaling.
 | 
			
		||||
 | 
			
		||||
    You shouldn't use this unless you really know what you are doing and
 | 
			
		||||
    are dealing with native HWNDs.
 | 
			
		||||
 | 
			
		||||
    @tags{GUI}
 | 
			
		||||
*/
 | 
			
		||||
class JUCE_API  ScopedDPIAwarenessDisabler
 | 
			
		||||
{
 | 
			
		||||
public:
 | 
			
		||||
    ScopedDPIAwarenessDisabler();
 | 
			
		||||
    ~ScopedDPIAwarenessDisabler();
 | 
			
		||||
 | 
			
		||||
private:
 | 
			
		||||
    void* previousContext = nullptr;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
} // namespace juce
 | 
			
		||||
/*
 | 
			
		||||
  ==============================================================================
 | 
			
		||||
 | 
			
		||||
   This file is part of the JUCE library.
 | 
			
		||||
   Copyright (c) 2022 - Raw Material Software Limited
 | 
			
		||||
 | 
			
		||||
   JUCE is an open source library subject to commercial or open-source
 | 
			
		||||
   licensing.
 | 
			
		||||
 | 
			
		||||
   By using JUCE, you agree to the terms of both the JUCE 7 End-User License
 | 
			
		||||
   Agreement and JUCE Privacy Policy.
 | 
			
		||||
 | 
			
		||||
   End User License Agreement: www.juce.com/juce-7-licence
 | 
			
		||||
   Privacy Policy: www.juce.com/juce-privacy-policy
 | 
			
		||||
 | 
			
		||||
   Or: You may also use this code under the terms of the GPL v3 (see
 | 
			
		||||
   www.gnu.org/licenses).
 | 
			
		||||
 | 
			
		||||
   JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
 | 
			
		||||
   EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
 | 
			
		||||
   DISCLAIMED.
 | 
			
		||||
 | 
			
		||||
  ==============================================================================
 | 
			
		||||
*/
 | 
			
		||||
 | 
			
		||||
namespace juce
 | 
			
		||||
{
 | 
			
		||||
 | 
			
		||||
//==============================================================================
 | 
			
		||||
/**
 | 
			
		||||
    A Windows-specific class that temporarily sets the DPI awareness context of
 | 
			
		||||
    the current thread to be DPI unaware and resets it to the previous context
 | 
			
		||||
    when it goes out of scope.
 | 
			
		||||
 | 
			
		||||
    If you create one of these before creating a top-level window, the window
 | 
			
		||||
    will be DPI unaware and bitmap stretched by the OS on a display with >100%
 | 
			
		||||
    scaling.
 | 
			
		||||
 | 
			
		||||
    You shouldn't use this unless you really know what you are doing and
 | 
			
		||||
    are dealing with native HWNDs.
 | 
			
		||||
 | 
			
		||||
    @tags{GUI}
 | 
			
		||||
*/
 | 
			
		||||
class JUCE_API  ScopedDPIAwarenessDisabler
 | 
			
		||||
{
 | 
			
		||||
public:
 | 
			
		||||
    ScopedDPIAwarenessDisabler();
 | 
			
		||||
    ~ScopedDPIAwarenessDisabler();
 | 
			
		||||
 | 
			
		||||
private:
 | 
			
		||||
    void* previousContext = nullptr;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
} // namespace juce
 | 
			
		||||
 
 | 
			
		||||
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							@@ -1,240 +1,280 @@
 | 
			
		||||
/*
 | 
			
		||||
  ==============================================================================
 | 
			
		||||
 | 
			
		||||
   This file is part of the JUCE library.
 | 
			
		||||
   Copyright (c) 2020 - Raw Material Software Limited
 | 
			
		||||
 | 
			
		||||
   JUCE is an open source library subject to commercial or open-source
 | 
			
		||||
   licensing.
 | 
			
		||||
 | 
			
		||||
   By using JUCE, you agree to the terms of both the JUCE 6 End-User License
 | 
			
		||||
   Agreement and JUCE Privacy Policy (both effective as of the 16th June 2020).
 | 
			
		||||
 | 
			
		||||
   End User License Agreement: www.juce.com/juce-6-licence
 | 
			
		||||
   Privacy Policy: www.juce.com/juce-privacy-policy
 | 
			
		||||
 | 
			
		||||
   Or: You may also use this code under the terms of the GPL v3 (see
 | 
			
		||||
   www.gnu.org/licenses).
 | 
			
		||||
 | 
			
		||||
   JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
 | 
			
		||||
   EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
 | 
			
		||||
   DISCLAIMED.
 | 
			
		||||
 | 
			
		||||
  ==============================================================================
 | 
			
		||||
*/
 | 
			
		||||
 | 
			
		||||
namespace juce
 | 
			
		||||
{
 | 
			
		||||
 | 
			
		||||
class FileChooser::Native     : public FileChooser::Pimpl
 | 
			
		||||
{
 | 
			
		||||
public:
 | 
			
		||||
    //==============================================================================
 | 
			
		||||
    Native (FileChooser& fileChooser, int flags)    : owner (fileChooser)
 | 
			
		||||
    {
 | 
			
		||||
        if (currentFileChooser == nullptr)
 | 
			
		||||
        {
 | 
			
		||||
            currentFileChooser = this;
 | 
			
		||||
            auto* env = getEnv();
 | 
			
		||||
 | 
			
		||||
            auto sdkVersion         = getAndroidSDKVersion();
 | 
			
		||||
            auto saveMode           = ((flags & FileBrowserComponent::saveMode) != 0);
 | 
			
		||||
            auto selectsDirectories = ((flags & FileBrowserComponent::canSelectDirectories) != 0);
 | 
			
		||||
 | 
			
		||||
            // You cannot save a directory
 | 
			
		||||
            jassert (! (saveMode && selectsDirectories));
 | 
			
		||||
 | 
			
		||||
            if (sdkVersion < 19)
 | 
			
		||||
            {
 | 
			
		||||
                // native save dialogs are only supported in Android versions >= 19
 | 
			
		||||
                jassert (! saveMode);
 | 
			
		||||
                saveMode = false;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            if (sdkVersion < 21)
 | 
			
		||||
            {
 | 
			
		||||
                // native directory chooser dialogs are only supported in Android versions >= 21
 | 
			
		||||
                jassert (! selectsDirectories);
 | 
			
		||||
                selectsDirectories = false;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            const char* action = (selectsDirectories ? "android.intent.action.OPEN_DOCUMENT_TREE"
 | 
			
		||||
                                                     : (saveMode ? "android.intent.action.CREATE_DOCUMENT"
 | 
			
		||||
                                                     : (sdkVersion >= 19 ? "android.intent.action.OPEN_DOCUMENT"
 | 
			
		||||
                                                     : "android.intent.action.GET_CONTENT")));
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
            intent = GlobalRef (LocalRef<jobject> (env->NewObject (AndroidIntent, AndroidIntent.constructWithString,
 | 
			
		||||
                                                                   javaString (action).get())));
 | 
			
		||||
 | 
			
		||||
            if (owner.startingFile != File())
 | 
			
		||||
            {
 | 
			
		||||
                if (saveMode && (! owner.startingFile.isDirectory()))
 | 
			
		||||
                    env->CallObjectMethod (intent.get(), AndroidIntent.putExtraString,
 | 
			
		||||
                                           javaString ("android.intent.extra.TITLE").get(),
 | 
			
		||||
                                           javaString (owner.startingFile.getFileName()).get());
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
                URL url (owner.startingFile);
 | 
			
		||||
                LocalRef<jobject> uri (env->CallStaticObjectMethod (AndroidUri, AndroidUri.parse,
 | 
			
		||||
                                                                    javaString (url.toString (true)).get()));
 | 
			
		||||
 | 
			
		||||
                if (uri)
 | 
			
		||||
                    env->CallObjectMethod (intent.get(), AndroidIntent.putExtraParcelable,
 | 
			
		||||
                                           javaString ("android.provider.extra.INITIAL_URI").get(),
 | 
			
		||||
                                           uri.get());
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
            if (! selectsDirectories)
 | 
			
		||||
            {
 | 
			
		||||
                env->CallObjectMethod (intent.get(), AndroidIntent.addCategory,
 | 
			
		||||
                                       javaString ("android.intent.category.OPENABLE").get());
 | 
			
		||||
 | 
			
		||||
                auto mimeTypes = convertFiltersToMimeTypes (owner.filters);
 | 
			
		||||
 | 
			
		||||
                if (mimeTypes.size() == 1)
 | 
			
		||||
                {
 | 
			
		||||
                    env->CallObjectMethod (intent.get(), AndroidIntent.setType, javaString (mimeTypes[0]).get());
 | 
			
		||||
                }
 | 
			
		||||
                else
 | 
			
		||||
                {
 | 
			
		||||
                    String mimeGroup = "*";
 | 
			
		||||
 | 
			
		||||
                    if (mimeTypes.size() > 0)
 | 
			
		||||
                    {
 | 
			
		||||
                        mimeGroup = mimeTypes[0].upToFirstOccurrenceOf ("/", false, false);
 | 
			
		||||
                        auto allMimeTypesHaveSameGroup = true;
 | 
			
		||||
 | 
			
		||||
                        LocalRef<jobjectArray> jMimeTypes (env->NewObjectArray (mimeTypes.size(), JavaString,
 | 
			
		||||
                                                                                javaString("").get()));
 | 
			
		||||
 | 
			
		||||
                        for (int i = 0; i < mimeTypes.size(); ++i)
 | 
			
		||||
                        {
 | 
			
		||||
                            env->SetObjectArrayElement (jMimeTypes.get(), i, javaString (mimeTypes[i]).get());
 | 
			
		||||
 | 
			
		||||
                            if (mimeGroup != mimeTypes[i].upToFirstOccurrenceOf ("/", false, false))
 | 
			
		||||
                                allMimeTypesHaveSameGroup = false;
 | 
			
		||||
                        }
 | 
			
		||||
 | 
			
		||||
                        env->CallObjectMethod (intent.get(), AndroidIntent.putExtraStrings,
 | 
			
		||||
                                               javaString ("android.intent.extra.MIME_TYPES").get(),
 | 
			
		||||
                                               jMimeTypes.get());
 | 
			
		||||
 | 
			
		||||
                        if (! allMimeTypesHaveSameGroup)
 | 
			
		||||
                            mimeGroup = "*";
 | 
			
		||||
                    }
 | 
			
		||||
 | 
			
		||||
                    env->CallObjectMethod (intent.get(), AndroidIntent.setType, javaString (mimeGroup + "/*").get());
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
        else
 | 
			
		||||
            jassertfalse; // there can only be a single file chooser
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    ~Native() override
 | 
			
		||||
    {
 | 
			
		||||
        masterReference.clear();
 | 
			
		||||
        currentFileChooser = nullptr;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    void runModally() override
 | 
			
		||||
    {
 | 
			
		||||
        // Android does not support modal file choosers
 | 
			
		||||
        jassertfalse;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    void launch() override
 | 
			
		||||
    {
 | 
			
		||||
        auto* env = getEnv();
 | 
			
		||||
 | 
			
		||||
        if (currentFileChooser != nullptr)
 | 
			
		||||
        {
 | 
			
		||||
            startAndroidActivityForResult (LocalRef<jobject> (env->NewLocalRef (intent.get())), /*READ_REQUEST_CODE*/ 42,
 | 
			
		||||
                                           [myself = WeakReference<Native> { this }] (int requestCode, int resultCode, LocalRef<jobject> intentData) mutable
 | 
			
		||||
                                           {
 | 
			
		||||
                                               if (myself != nullptr)
 | 
			
		||||
                                                   myself->onActivityResult (requestCode, resultCode, intentData);
 | 
			
		||||
                                           });
 | 
			
		||||
        }
 | 
			
		||||
        else
 | 
			
		||||
        {
 | 
			
		||||
            jassertfalse; // There is already a file chooser running
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    void onActivityResult (int /*requestCode*/, int resultCode, const LocalRef<jobject>& intentData)
 | 
			
		||||
    {
 | 
			
		||||
        currentFileChooser = nullptr;
 | 
			
		||||
        auto* env = getEnv();
 | 
			
		||||
 | 
			
		||||
        Array<URL> chosenURLs;
 | 
			
		||||
 | 
			
		||||
        if (resultCode == /*Activity.RESULT_OK*/ -1 && intentData != nullptr)
 | 
			
		||||
        {
 | 
			
		||||
            LocalRef<jobject> uri (env->CallObjectMethod (intentData.get(), AndroidIntent.getData));
 | 
			
		||||
 | 
			
		||||
            if (uri != nullptr)
 | 
			
		||||
            {
 | 
			
		||||
                auto jStr = (jstring) env->CallObjectMethod (uri, JavaObject.toString);
 | 
			
		||||
 | 
			
		||||
                if (jStr != nullptr)
 | 
			
		||||
                    chosenURLs.add (URL (juceString (env, jStr)));
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        owner.finished (chosenURLs);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    static Native* currentFileChooser;
 | 
			
		||||
 | 
			
		||||
    static StringArray convertFiltersToMimeTypes (const String& fileFilters)
 | 
			
		||||
    {
 | 
			
		||||
        StringArray result;
 | 
			
		||||
        auto wildcards = StringArray::fromTokens (fileFilters, ";", "");
 | 
			
		||||
 | 
			
		||||
        for (auto wildcard : wildcards)
 | 
			
		||||
        {
 | 
			
		||||
            if (wildcard.upToLastOccurrenceOf (".", false, false) == "*")
 | 
			
		||||
            {
 | 
			
		||||
                auto extension = wildcard.fromLastOccurrenceOf (".", false, false);
 | 
			
		||||
 | 
			
		||||
                result.addArray (getMimeTypesForFileExtension (extension));
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        result.removeDuplicates (false);
 | 
			
		||||
        return result;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
private:
 | 
			
		||||
    JUCE_DECLARE_WEAK_REFERENCEABLE (Native)
 | 
			
		||||
 | 
			
		||||
    FileChooser& owner;
 | 
			
		||||
    GlobalRef intent;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
FileChooser::Native* FileChooser::Native::currentFileChooser = nullptr;
 | 
			
		||||
 | 
			
		||||
std::shared_ptr<FileChooser::Pimpl> FileChooser::showPlatformDialog (FileChooser& owner, int flags,
 | 
			
		||||
                                                                     FilePreviewComponent*)
 | 
			
		||||
{
 | 
			
		||||
    if (FileChooser::Native::currentFileChooser == nullptr)
 | 
			
		||||
        return std::make_shared<FileChooser::Native> (owner, flags);
 | 
			
		||||
 | 
			
		||||
    // there can only be one file chooser on Android at a once
 | 
			
		||||
    jassertfalse;
 | 
			
		||||
    return nullptr;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
bool FileChooser::isPlatformDialogAvailable()
 | 
			
		||||
{
 | 
			
		||||
   #if JUCE_DISABLE_NATIVE_FILECHOOSERS
 | 
			
		||||
    return false;
 | 
			
		||||
   #else
 | 
			
		||||
    return true;
 | 
			
		||||
   #endif
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
} // namespace juce
 | 
			
		||||
/*
 | 
			
		||||
  ==============================================================================
 | 
			
		||||
 | 
			
		||||
   This file is part of the JUCE library.
 | 
			
		||||
   Copyright (c) 2022 - Raw Material Software Limited
 | 
			
		||||
 | 
			
		||||
   JUCE is an open source library subject to commercial or open-source
 | 
			
		||||
   licensing.
 | 
			
		||||
 | 
			
		||||
   By using JUCE, you agree to the terms of both the JUCE 7 End-User License
 | 
			
		||||
   Agreement and JUCE Privacy Policy.
 | 
			
		||||
 | 
			
		||||
   End User License Agreement: www.juce.com/juce-7-licence
 | 
			
		||||
   Privacy Policy: www.juce.com/juce-privacy-policy
 | 
			
		||||
 | 
			
		||||
   Or: You may also use this code under the terms of the GPL v3 (see
 | 
			
		||||
   www.gnu.org/licenses).
 | 
			
		||||
 | 
			
		||||
   JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
 | 
			
		||||
   EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
 | 
			
		||||
   DISCLAIMED.
 | 
			
		||||
 | 
			
		||||
  ==============================================================================
 | 
			
		||||
*/
 | 
			
		||||
 | 
			
		||||
namespace juce
 | 
			
		||||
{
 | 
			
		||||
 | 
			
		||||
#define JNI_CLASS_MEMBERS(METHOD, STATICMETHOD, FIELD, STATICFIELD, CALLBACK) \
 | 
			
		||||
  METHOD (getItemCount, "getItemCount", "()I") \
 | 
			
		||||
  METHOD (getItemAt,    "getItemAt",    "(I)Landroid/content/ClipData$Item;")
 | 
			
		||||
 | 
			
		||||
DECLARE_JNI_CLASS (ClipData, "android/content/ClipData")
 | 
			
		||||
#undef JNI_CLASS_MEMBERS
 | 
			
		||||
 | 
			
		||||
#define JNI_CLASS_MEMBERS(METHOD, STATICMETHOD, FIELD, STATICFIELD, CALLBACK) \
 | 
			
		||||
  METHOD (getUri, "getUri", "()Landroid/net/Uri;")
 | 
			
		||||
 | 
			
		||||
DECLARE_JNI_CLASS (ClipDataItem, "android/content/ClipData$Item")
 | 
			
		||||
#undef JNI_CLASS_MEMBERS
 | 
			
		||||
 | 
			
		||||
class FileChooser::Native     : public FileChooser::Pimpl
 | 
			
		||||
{
 | 
			
		||||
public:
 | 
			
		||||
    //==============================================================================
 | 
			
		||||
    Native (FileChooser& fileChooser, int flags)    : owner (fileChooser)
 | 
			
		||||
    {
 | 
			
		||||
        if (currentFileChooser == nullptr)
 | 
			
		||||
        {
 | 
			
		||||
            currentFileChooser = this;
 | 
			
		||||
            auto* env = getEnv();
 | 
			
		||||
 | 
			
		||||
            auto sdkVersion         = getAndroidSDKVersion();
 | 
			
		||||
            auto saveMode           = ((flags & FileBrowserComponent::saveMode) != 0);
 | 
			
		||||
            auto selectsDirectories = ((flags & FileBrowserComponent::canSelectDirectories) != 0);
 | 
			
		||||
            auto canSelectMultiple  = ((flags & FileBrowserComponent::canSelectMultipleItems) != 0);
 | 
			
		||||
 | 
			
		||||
            // You cannot save a directory
 | 
			
		||||
            jassert (! (saveMode && selectsDirectories));
 | 
			
		||||
 | 
			
		||||
            if (sdkVersion < 19)
 | 
			
		||||
            {
 | 
			
		||||
                // native save dialogs are only supported in Android versions >= 19
 | 
			
		||||
                jassert (! saveMode);
 | 
			
		||||
                saveMode = false;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            if (sdkVersion < 21)
 | 
			
		||||
            {
 | 
			
		||||
                // native directory chooser dialogs are only supported in Android versions >= 21
 | 
			
		||||
                jassert (! selectsDirectories);
 | 
			
		||||
                selectsDirectories = false;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            const char* action = (selectsDirectories ? "android.intent.action.OPEN_DOCUMENT_TREE"
 | 
			
		||||
                                                     : (saveMode ? "android.intent.action.CREATE_DOCUMENT"
 | 
			
		||||
                                                     : (sdkVersion >= 19 ? "android.intent.action.OPEN_DOCUMENT"
 | 
			
		||||
                                                     : "android.intent.action.GET_CONTENT")));
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
            intent = GlobalRef (LocalRef<jobject> (env->NewObject (AndroidIntent, AndroidIntent.constructWithString,
 | 
			
		||||
                                                                   javaString (action).get())));
 | 
			
		||||
 | 
			
		||||
            if (owner.startingFile != File())
 | 
			
		||||
            {
 | 
			
		||||
                if (saveMode && (! owner.startingFile.isDirectory()))
 | 
			
		||||
                    env->CallObjectMethod (intent.get(), AndroidIntent.putExtraString,
 | 
			
		||||
                                           javaString ("android.intent.extra.TITLE").get(),
 | 
			
		||||
                                           javaString (owner.startingFile.getFileName()).get());
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
                URL url (owner.startingFile);
 | 
			
		||||
                LocalRef<jobject> uri (env->CallStaticObjectMethod (AndroidUri, AndroidUri.parse,
 | 
			
		||||
                                                                    javaString (url.toString (true)).get()));
 | 
			
		||||
 | 
			
		||||
                if (uri)
 | 
			
		||||
                    env->CallObjectMethod (intent.get(), AndroidIntent.putExtraParcelable,
 | 
			
		||||
                                           javaString ("android.provider.extra.INITIAL_URI").get(),
 | 
			
		||||
                                           uri.get());
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            if (canSelectMultiple && sdkVersion >= 18)
 | 
			
		||||
            {
 | 
			
		||||
                env->CallObjectMethod (intent.get(),
 | 
			
		||||
                                       AndroidIntent.putExtraBool,
 | 
			
		||||
                                       javaString ("android.intent.extra.ALLOW_MULTIPLE").get(),
 | 
			
		||||
                                       true);
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            if (! selectsDirectories)
 | 
			
		||||
            {
 | 
			
		||||
                env->CallObjectMethod (intent.get(), AndroidIntent.addCategory,
 | 
			
		||||
                                       javaString ("android.intent.category.OPENABLE").get());
 | 
			
		||||
 | 
			
		||||
                auto mimeTypes = convertFiltersToMimeTypes (owner.filters);
 | 
			
		||||
 | 
			
		||||
                if (mimeTypes.size() == 1)
 | 
			
		||||
                {
 | 
			
		||||
                    env->CallObjectMethod (intent.get(), AndroidIntent.setType, javaString (mimeTypes[0]).get());
 | 
			
		||||
                }
 | 
			
		||||
                else
 | 
			
		||||
                {
 | 
			
		||||
                    String mimeGroup = "*";
 | 
			
		||||
 | 
			
		||||
                    if (mimeTypes.size() > 0)
 | 
			
		||||
                    {
 | 
			
		||||
                        mimeGroup = mimeTypes[0].upToFirstOccurrenceOf ("/", false, false);
 | 
			
		||||
                        auto allMimeTypesHaveSameGroup = true;
 | 
			
		||||
 | 
			
		||||
                        LocalRef<jobjectArray> jMimeTypes (env->NewObjectArray (mimeTypes.size(), JavaString,
 | 
			
		||||
                                                                                javaString("").get()));
 | 
			
		||||
 | 
			
		||||
                        for (int i = 0; i < mimeTypes.size(); ++i)
 | 
			
		||||
                        {
 | 
			
		||||
                            env->SetObjectArrayElement (jMimeTypes.get(), i, javaString (mimeTypes[i]).get());
 | 
			
		||||
 | 
			
		||||
                            if (mimeGroup != mimeTypes[i].upToFirstOccurrenceOf ("/", false, false))
 | 
			
		||||
                                allMimeTypesHaveSameGroup = false;
 | 
			
		||||
                        }
 | 
			
		||||
 | 
			
		||||
                        env->CallObjectMethod (intent.get(), AndroidIntent.putExtraStrings,
 | 
			
		||||
                                               javaString ("android.intent.extra.MIME_TYPES").get(),
 | 
			
		||||
                                               jMimeTypes.get());
 | 
			
		||||
 | 
			
		||||
                        if (! allMimeTypesHaveSameGroup)
 | 
			
		||||
                            mimeGroup = "*";
 | 
			
		||||
                    }
 | 
			
		||||
 | 
			
		||||
                    env->CallObjectMethod (intent.get(), AndroidIntent.setType, javaString (mimeGroup + "/*").get());
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
        else
 | 
			
		||||
            jassertfalse; // there can only be a single file chooser
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    ~Native() override
 | 
			
		||||
    {
 | 
			
		||||
        masterReference.clear();
 | 
			
		||||
        currentFileChooser = nullptr;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    void runModally() override
 | 
			
		||||
    {
 | 
			
		||||
        // Android does not support modal file choosers
 | 
			
		||||
        jassertfalse;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    void launch() override
 | 
			
		||||
    {
 | 
			
		||||
        auto* env = getEnv();
 | 
			
		||||
 | 
			
		||||
        if (currentFileChooser != nullptr)
 | 
			
		||||
        {
 | 
			
		||||
            startAndroidActivityForResult (LocalRef<jobject> (env->NewLocalRef (intent.get())), /*READ_REQUEST_CODE*/ 42,
 | 
			
		||||
                                           [myself = WeakReference<Native> { this }] (int requestCode, int resultCode, LocalRef<jobject> intentData) mutable
 | 
			
		||||
                                           {
 | 
			
		||||
                                               if (myself != nullptr)
 | 
			
		||||
                                                   myself->onActivityResult (requestCode, resultCode, intentData);
 | 
			
		||||
                                           });
 | 
			
		||||
        }
 | 
			
		||||
        else
 | 
			
		||||
        {
 | 
			
		||||
            jassertfalse; // There is already a file chooser running
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    void onActivityResult (int /*requestCode*/, int resultCode, const LocalRef<jobject>& intentData)
 | 
			
		||||
    {
 | 
			
		||||
        currentFileChooser = nullptr;
 | 
			
		||||
        auto* env = getEnv();
 | 
			
		||||
 | 
			
		||||
        const auto getUrls = [&]() -> Array<URL>
 | 
			
		||||
        {
 | 
			
		||||
            if (resultCode != /*Activity.RESULT_OK*/ -1 || intentData == nullptr)
 | 
			
		||||
                return {};
 | 
			
		||||
 | 
			
		||||
            Array<URL> chosenURLs;
 | 
			
		||||
 | 
			
		||||
            const auto addUrl = [env, &chosenURLs] (jobject uri)
 | 
			
		||||
            {
 | 
			
		||||
                if (auto jStr = (jstring) env->CallObjectMethod (uri, JavaObject.toString))
 | 
			
		||||
                    chosenURLs.add (URL (juceString (env, jStr)));
 | 
			
		||||
            };
 | 
			
		||||
 | 
			
		||||
            if (LocalRef<jobject> clipData { env->CallObjectMethod (intentData.get(), AndroidIntent.getClipData) })
 | 
			
		||||
            {
 | 
			
		||||
                const auto count = env->CallIntMethod (clipData.get(), ClipData.getItemCount);
 | 
			
		||||
 | 
			
		||||
                for (auto i = 0; i < count; ++i)
 | 
			
		||||
                {
 | 
			
		||||
                    if (LocalRef<jobject> item { env->CallObjectMethod (clipData.get(), ClipData.getItemAt, i) })
 | 
			
		||||
                    {
 | 
			
		||||
                        if (LocalRef<jobject> itemUri { env->CallObjectMethod (item.get(), ClipDataItem.getUri) })
 | 
			
		||||
                            addUrl (itemUri.get());
 | 
			
		||||
                    }
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
            else if (LocalRef<jobject> uri { env->CallObjectMethod (intentData.get(), AndroidIntent.getData )})
 | 
			
		||||
            {
 | 
			
		||||
                addUrl (uri.get());
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            return chosenURLs;
 | 
			
		||||
        };
 | 
			
		||||
 | 
			
		||||
        owner.finished (getUrls());
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    static Native* currentFileChooser;
 | 
			
		||||
 | 
			
		||||
    static StringArray convertFiltersToMimeTypes (const String& fileFilters)
 | 
			
		||||
    {
 | 
			
		||||
        StringArray result;
 | 
			
		||||
        auto wildcards = StringArray::fromTokens (fileFilters, ";", "");
 | 
			
		||||
 | 
			
		||||
        for (auto wildcard : wildcards)
 | 
			
		||||
        {
 | 
			
		||||
            if (wildcard.upToLastOccurrenceOf (".", false, false) == "*")
 | 
			
		||||
            {
 | 
			
		||||
                auto extension = wildcard.fromLastOccurrenceOf (".", false, false);
 | 
			
		||||
 | 
			
		||||
                result.addArray (MimeTypeTable::getMimeTypesForFileExtension (extension));
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        result.removeDuplicates (false);
 | 
			
		||||
        return result;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
private:
 | 
			
		||||
    JUCE_DECLARE_WEAK_REFERENCEABLE (Native)
 | 
			
		||||
 | 
			
		||||
    FileChooser& owner;
 | 
			
		||||
    GlobalRef intent;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
FileChooser::Native* FileChooser::Native::currentFileChooser = nullptr;
 | 
			
		||||
 | 
			
		||||
std::shared_ptr<FileChooser::Pimpl> FileChooser::showPlatformDialog (FileChooser& owner, int flags,
 | 
			
		||||
                                                                     FilePreviewComponent*)
 | 
			
		||||
{
 | 
			
		||||
    if (FileChooser::Native::currentFileChooser == nullptr)
 | 
			
		||||
        return std::make_shared<FileChooser::Native> (owner, flags);
 | 
			
		||||
 | 
			
		||||
    // there can only be one file chooser on Android at a once
 | 
			
		||||
    jassertfalse;
 | 
			
		||||
    return nullptr;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
bool FileChooser::isPlatformDialogAvailable()
 | 
			
		||||
{
 | 
			
		||||
   #if JUCE_DISABLE_NATIVE_FILECHOOSERS
 | 
			
		||||
    return false;
 | 
			
		||||
   #else
 | 
			
		||||
    return true;
 | 
			
		||||
   #endif
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
} // namespace juce
 | 
			
		||||
 
 | 
			
		||||
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							@@ -1,693 +0,0 @@
 | 
			
		||||
/*
 | 
			
		||||
  ==============================================================================
 | 
			
		||||
 | 
			
		||||
   This file is part of the JUCE library.
 | 
			
		||||
   Copyright (c) 2020 - Raw Material Software Limited
 | 
			
		||||
 | 
			
		||||
   JUCE is an open source library subject to commercial or open-source
 | 
			
		||||
   licensing.
 | 
			
		||||
 | 
			
		||||
   By using JUCE, you agree to the terms of both the JUCE 6 End-User License
 | 
			
		||||
   Agreement and JUCE Privacy Policy (both effective as of the 16th June 2020).
 | 
			
		||||
 | 
			
		||||
   End User License Agreement: www.juce.com/juce-6-licence
 | 
			
		||||
   Privacy Policy: www.juce.com/juce-privacy-policy
 | 
			
		||||
 | 
			
		||||
   Or: You may also use this code under the terms of the GPL v3 (see
 | 
			
		||||
   www.gnu.org/licenses).
 | 
			
		||||
 | 
			
		||||
   JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
 | 
			
		||||
   EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
 | 
			
		||||
   DISCLAIMED.
 | 
			
		||||
 | 
			
		||||
  ==============================================================================
 | 
			
		||||
*/
 | 
			
		||||
 | 
			
		||||
namespace juce
 | 
			
		||||
{
 | 
			
		||||
 | 
			
		||||
struct MimeTypeTableEntry
 | 
			
		||||
{
 | 
			
		||||
    const char* fileExtension, *mimeType;
 | 
			
		||||
 | 
			
		||||
    static MimeTypeTableEntry table[641];
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
static StringArray getMimeTypesForFileExtension (const String& fileExtension)
 | 
			
		||||
{
 | 
			
		||||
    StringArray result;
 | 
			
		||||
 | 
			
		||||
    for (auto type : MimeTypeTableEntry::table)
 | 
			
		||||
        if (fileExtension == type.fileExtension)
 | 
			
		||||
            result.add (type.mimeType);
 | 
			
		||||
 | 
			
		||||
    return result;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
//==============================================================================
 | 
			
		||||
MimeTypeTableEntry MimeTypeTableEntry::table[641] =
 | 
			
		||||
{
 | 
			
		||||
    {"3dm",      "x-world/x-3dmf"},
 | 
			
		||||
    {"3dmf",     "x-world/x-3dmf"},
 | 
			
		||||
    {"a",        "application/octet-stream"},
 | 
			
		||||
    {"aab",      "application/x-authorware-bin"},
 | 
			
		||||
    {"aam",      "application/x-authorware-map"},
 | 
			
		||||
    {"aas",      "application/x-authorware-seg"},
 | 
			
		||||
    {"abc",      "text/vnd.abc"},
 | 
			
		||||
    {"acgi",     "text/html"},
 | 
			
		||||
    {"afl",      "video/animaflex"},
 | 
			
		||||
    {"ai",       "application/postscript"},
 | 
			
		||||
    {"aif",      "audio/aiff"},
 | 
			
		||||
    {"aif",      "audio/x-aiff"},
 | 
			
		||||
    {"aifc",     "audio/aiff"},
 | 
			
		||||
    {"aifc",     "audio/x-aiff"},
 | 
			
		||||
    {"aiff",     "audio/aiff"},
 | 
			
		||||
    {"aiff",     "audio/x-aiff"},
 | 
			
		||||
    {"aim",      "application/x-aim"},
 | 
			
		||||
    {"aip",      "text/x-audiosoft-intra"},
 | 
			
		||||
    {"ani",      "application/x-navi-animation"},
 | 
			
		||||
    {"aos",      "application/x-nokia-9000-communicator-add-on-software"},
 | 
			
		||||
    {"aps",      "application/mime"},
 | 
			
		||||
    {"arc",      "application/octet-stream"},
 | 
			
		||||
    {"arj",      "application/arj"},
 | 
			
		||||
    {"arj",      "application/octet-stream"},
 | 
			
		||||
    {"art",      "image/x-jg"},
 | 
			
		||||
    {"asf",      "video/x-ms-asf"},
 | 
			
		||||
    {"asm",      "text/x-asm"},
 | 
			
		||||
    {"asp",      "text/asp"},
 | 
			
		||||
    {"asx",      "application/x-mplayer2"},
 | 
			
		||||
    {"asx",      "video/x-ms-asf"},
 | 
			
		||||
    {"asx",      "video/x-ms-asf-plugin"},
 | 
			
		||||
    {"au",       "audio/basic"},
 | 
			
		||||
    {"au",       "audio/x-au"},
 | 
			
		||||
    {"avi",      "application/x-troff-msvideo"},
 | 
			
		||||
    {"avi",      "video/avi"},
 | 
			
		||||
    {"avi",      "video/msvideo"},
 | 
			
		||||
    {"avi",      "video/x-msvideo"},
 | 
			
		||||
    {"avs",      "video/avs-video"},
 | 
			
		||||
    {"bcpio",    "application/x-bcpio"},
 | 
			
		||||
    {"bin",      "application/mac-binary"},
 | 
			
		||||
    {"bin",      "application/macbinary"},
 | 
			
		||||
    {"bin",      "application/octet-stream"},
 | 
			
		||||
    {"bin",      "application/x-binary"},
 | 
			
		||||
    {"bin",      "application/x-macbinary"},
 | 
			
		||||
    {"bm",       "image/bmp"},
 | 
			
		||||
    {"bmp",      "image/bmp"},
 | 
			
		||||
    {"bmp",      "image/x-windows-bmp"},
 | 
			
		||||
    {"boo",      "application/book"},
 | 
			
		||||
    {"book",     "application/book"},
 | 
			
		||||
    {"boz",      "application/x-bzip2"},
 | 
			
		||||
    {"bsh",      "application/x-bsh"},
 | 
			
		||||
    {"bz",       "application/x-bzip"},
 | 
			
		||||
    {"bz2",      "application/x-bzip2"},
 | 
			
		||||
    {"c",        "text/plain"},
 | 
			
		||||
    {"c",        "text/x-c"},
 | 
			
		||||
    {"c++",      "text/plain"},
 | 
			
		||||
    {"cat",      "application/vnd.ms-pki.seccat"},
 | 
			
		||||
    {"cc",       "text/plain"},
 | 
			
		||||
    {"cc",       "text/x-c"},
 | 
			
		||||
    {"ccad",     "application/clariscad"},
 | 
			
		||||
    {"cco",      "application/x-cocoa"},
 | 
			
		||||
    {"cdf",      "application/cdf"},
 | 
			
		||||
    {"cdf",      "application/x-cdf"},
 | 
			
		||||
    {"cdf",      "application/x-netcdf"},
 | 
			
		||||
    {"cer",      "application/pkix-cert"},
 | 
			
		||||
    {"cer",      "application/x-x509-ca-cert"},
 | 
			
		||||
    {"cha",      "application/x-chat"},
 | 
			
		||||
    {"chat",     "application/x-chat"},
 | 
			
		||||
    {"class",    "application/java"},
 | 
			
		||||
    {"class",    "application/java-byte-code"},
 | 
			
		||||
    {"class",    "application/x-java-class"},
 | 
			
		||||
    {"com",      "application/octet-stream"},
 | 
			
		||||
    {"com",      "text/plain"},
 | 
			
		||||
    {"conf",     "text/plain"},
 | 
			
		||||
    {"cpio",     "application/x-cpio"},
 | 
			
		||||
    {"cpp",      "text/x-c"},
 | 
			
		||||
    {"cpt",      "application/mac-compactpro"},
 | 
			
		||||
    {"cpt",      "application/x-compactpro"},
 | 
			
		||||
    {"cpt",      "application/x-cpt"},
 | 
			
		||||
    {"crl",      "application/pkcs-crl"},
 | 
			
		||||
    {"crl",      "application/pkix-crl"},
 | 
			
		||||
    {"crt",      "application/pkix-cert"},
 | 
			
		||||
    {"crt",      "application/x-x509-ca-cert"},
 | 
			
		||||
    {"crt",      "application/x-x509-user-cert"},
 | 
			
		||||
    {"csh",      "application/x-csh"},
 | 
			
		||||
    {"csh",      "text/x-script.csh"},
 | 
			
		||||
    {"css",      "application/x-pointplus"},
 | 
			
		||||
    {"css",      "text/css"},
 | 
			
		||||
    {"cxx",      "text/plain"},
 | 
			
		||||
    {"dcr",      "application/x-director"},
 | 
			
		||||
    {"deepv",    "application/x-deepv"},
 | 
			
		||||
    {"def",      "text/plain"},
 | 
			
		||||
    {"der",      "application/x-x509-ca-cert"},
 | 
			
		||||
    {"dif",      "video/x-dv"},
 | 
			
		||||
    {"dir",      "application/x-director"},
 | 
			
		||||
    {"dl",       "video/dl"},
 | 
			
		||||
    {"dl",       "video/x-dl"},
 | 
			
		||||
    {"doc",      "application/msword"},
 | 
			
		||||
    {"dot",      "application/msword"},
 | 
			
		||||
    {"dp",       "application/commonground"},
 | 
			
		||||
    {"drw",      "application/drafting"},
 | 
			
		||||
    {"dump",     "application/octet-stream"},
 | 
			
		||||
    {"dv",       "video/x-dv"},
 | 
			
		||||
    {"dvi",      "application/x-dvi"},
 | 
			
		||||
    {"dwf",      "drawing/x-dwf"},
 | 
			
		||||
    {"dwf",      "model/vnd.dwf"},
 | 
			
		||||
    {"dwg",      "application/acad"},
 | 
			
		||||
    {"dwg",      "image/vnd.dwg"},
 | 
			
		||||
    {"dwg",      "image/x-dwg"},
 | 
			
		||||
    {"dxf",      "application/dxf"},
 | 
			
		||||
    {"dxf",      "image/vnd.dwg"},
 | 
			
		||||
    {"dxf",      "image/x-dwg"},
 | 
			
		||||
    {"dxr",      "application/x-director"},
 | 
			
		||||
    {"el",       "text/x-script.elisp"},
 | 
			
		||||
    {"elc",      "application/x-bytecode.elisp"},
 | 
			
		||||
    {"elc",      "application/x-elc"},
 | 
			
		||||
    {"env",      "application/x-envoy"},
 | 
			
		||||
    {"eps",      "application/postscript"},
 | 
			
		||||
    {"es",       "application/x-esrehber"},
 | 
			
		||||
    {"etx",      "text/x-setext"},
 | 
			
		||||
    {"evy",      "application/envoy"},
 | 
			
		||||
    {"evy",      "application/x-envoy"},
 | 
			
		||||
    {"exe",      "application/octet-stream"},
 | 
			
		||||
    {"f",        "text/plain"},
 | 
			
		||||
    {"f",        "text/x-fortran"},
 | 
			
		||||
    {"f77",      "text/x-fortran"},
 | 
			
		||||
    {"f90",      "text/plain"},
 | 
			
		||||
    {"f90",      "text/x-fortran"},
 | 
			
		||||
    {"fdf",      "application/vnd.fdf"},
 | 
			
		||||
    {"fif",      "application/fractals"},
 | 
			
		||||
    {"fif",      "image/fif"},
 | 
			
		||||
    {"fli",      "video/fli"},
 | 
			
		||||
    {"fli",      "video/x-fli"},
 | 
			
		||||
    {"flo",      "image/florian"},
 | 
			
		||||
    {"flx",      "text/vnd.fmi.flexstor"},
 | 
			
		||||
    {"fmf",      "video/x-atomic3d-feature"},
 | 
			
		||||
    {"for",      "text/plain"},
 | 
			
		||||
    {"for",      "text/x-fortran"},
 | 
			
		||||
    {"fpx",      "image/vnd.fpx"},
 | 
			
		||||
    {"fpx",      "image/vnd.net-fpx"},
 | 
			
		||||
    {"frl",      "application/freeloader"},
 | 
			
		||||
    {"funk",     "audio/make"},
 | 
			
		||||
    {"g",        "text/plain"},
 | 
			
		||||
    {"g3",       "image/g3fax"},
 | 
			
		||||
    {"gif",      "image/gif"},
 | 
			
		||||
    {"gl",       "video/gl"},
 | 
			
		||||
    {"gl",       "video/x-gl"},
 | 
			
		||||
    {"gsd",      "audio/x-gsm"},
 | 
			
		||||
    {"gsm",      "audio/x-gsm"},
 | 
			
		||||
    {"gsp",      "application/x-gsp"},
 | 
			
		||||
    {"gss",      "application/x-gss"},
 | 
			
		||||
    {"gtar",     "application/x-gtar"},
 | 
			
		||||
    {"gz",       "application/x-compressed"},
 | 
			
		||||
    {"gz",       "application/x-gzip"},
 | 
			
		||||
    {"gzip",     "application/x-gzip"},
 | 
			
		||||
    {"gzip",     "multipart/x-gzip"},
 | 
			
		||||
    {"h",        "text/plain"},
 | 
			
		||||
    {"h",        "text/x-h"},
 | 
			
		||||
    {"hdf",      "application/x-hdf"},
 | 
			
		||||
    {"help",     "application/x-helpfile"},
 | 
			
		||||
    {"hgl",      "application/vnd.hp-hpgl"},
 | 
			
		||||
    {"hh",       "text/plain"},
 | 
			
		||||
    {"hh",       "text/x-h"},
 | 
			
		||||
    {"hlb",      "text/x-script"},
 | 
			
		||||
    {"hlp",      "application/hlp"},
 | 
			
		||||
    {"hlp",      "application/x-helpfile"},
 | 
			
		||||
    {"hlp",      "application/x-winhelp"},
 | 
			
		||||
    {"hpg",      "application/vnd.hp-hpgl"},
 | 
			
		||||
    {"hpgl",     "application/vnd.hp-hpgl"},
 | 
			
		||||
    {"hqx",      "application/binhex"},
 | 
			
		||||
    {"hqx",      "application/binhex4"},
 | 
			
		||||
    {"hqx",      "application/mac-binhex"},
 | 
			
		||||
    {"hqx",      "application/mac-binhex40"},
 | 
			
		||||
    {"hqx",      "application/x-binhex40"},
 | 
			
		||||
    {"hqx",      "application/x-mac-binhex40"},
 | 
			
		||||
    {"hta",      "application/hta"},
 | 
			
		||||
    {"htc",      "text/x-component"},
 | 
			
		||||
    {"htm",      "text/html"},
 | 
			
		||||
    {"html",     "text/html"},
 | 
			
		||||
    {"htmls",    "text/html"},
 | 
			
		||||
    {"htt",      "text/webviewhtml"},
 | 
			
		||||
    {"htx",      "text/html"},
 | 
			
		||||
    {"ice",      "x-conference/x-cooltalk"},
 | 
			
		||||
    {"ico",      "image/x-icon"},
 | 
			
		||||
    {"idc",      "text/plain"},
 | 
			
		||||
    {"ief",      "image/ief"},
 | 
			
		||||
    {"iefs",     "image/ief"},
 | 
			
		||||
    {"iges",     "application/iges"},
 | 
			
		||||
    {"iges",     "model/iges"},
 | 
			
		||||
    {"igs",      "application/iges"},
 | 
			
		||||
    {"igs",      "model/iges"},
 | 
			
		||||
    {"ima",      "application/x-ima"},
 | 
			
		||||
    {"imap",     "application/x-httpd-imap"},
 | 
			
		||||
    {"inf",      "application/inf"},
 | 
			
		||||
    {"ins",      "application/x-internett-signup"},
 | 
			
		||||
    {"ip",       "application/x-ip2"},
 | 
			
		||||
    {"isu",      "video/x-isvideo"},
 | 
			
		||||
    {"it",       "audio/it"},
 | 
			
		||||
    {"iv",       "application/x-inventor"},
 | 
			
		||||
    {"ivr",      "i-world/i-vrml"},
 | 
			
		||||
    {"ivy",      "application/x-livescreen"},
 | 
			
		||||
    {"jam",      "audio/x-jam"},
 | 
			
		||||
    {"jav",      "text/plain"},
 | 
			
		||||
    {"jav",      "text/x-java-source"},
 | 
			
		||||
    {"java",     "text/plain"},
 | 
			
		||||
    {"java",     "text/x-java-source"},
 | 
			
		||||
    {"jcm",      "application/x-java-commerce"},
 | 
			
		||||
    {"jfif",     "image/jpeg"},
 | 
			
		||||
    {"jfif",     "image/pjpeg"},
 | 
			
		||||
    {"jpe",      "image/jpeg"},
 | 
			
		||||
    {"jpe",      "image/pjpeg"},
 | 
			
		||||
    {"jpeg",     "image/jpeg"},
 | 
			
		||||
    {"jpeg",     "image/pjpeg"},
 | 
			
		||||
    {"jpg",      "image/jpeg"},
 | 
			
		||||
    {"jpg",      "image/pjpeg"},
 | 
			
		||||
    {"jps",      "image/x-jps"},
 | 
			
		||||
    {"js",       "application/x-javascript"},
 | 
			
		||||
    {"jut",      "image/jutvision"},
 | 
			
		||||
    {"kar",      "audio/midi"},
 | 
			
		||||
    {"kar",      "music/x-karaoke"},
 | 
			
		||||
    {"ksh",      "application/x-ksh"},
 | 
			
		||||
    {"ksh",      "text/x-script.ksh"},
 | 
			
		||||
    {"la",       "audio/nspaudio"},
 | 
			
		||||
    {"la",       "audio/x-nspaudio"},
 | 
			
		||||
    {"lam",      "audio/x-liveaudio"},
 | 
			
		||||
    {"latex",    "application/x-latex"},
 | 
			
		||||
    {"lha",      "application/lha"},
 | 
			
		||||
    {"lha",      "application/octet-stream"},
 | 
			
		||||
    {"lha",      "application/x-lha"},
 | 
			
		||||
    {"lhx",      "application/octet-stream"},
 | 
			
		||||
    {"list",     "text/plain"},
 | 
			
		||||
    {"lma",      "audio/nspaudio"},
 | 
			
		||||
    {"lma",      "audio/x-nspaudio"},
 | 
			
		||||
    {"log",      "text/plain"},
 | 
			
		||||
    {"lsp",      "application/x-lisp"},
 | 
			
		||||
    {"lsp",      "text/x-script.lisp"},
 | 
			
		||||
    {"lst",      "text/plain"},
 | 
			
		||||
    {"lsx",      "text/x-la-asf"},
 | 
			
		||||
    {"ltx",      "application/x-latex"},
 | 
			
		||||
    {"lzh",      "application/octet-stream"},
 | 
			
		||||
    {"lzh",      "application/x-lzh"},
 | 
			
		||||
    {"lzx",      "application/lzx"},
 | 
			
		||||
    {"lzx",      "application/octet-stream"},
 | 
			
		||||
    {"lzx",      "application/x-lzx"},
 | 
			
		||||
    {"m",        "text/plain"},
 | 
			
		||||
    {"m",        "text/x-m"},
 | 
			
		||||
    {"m1v",      "video/mpeg"},
 | 
			
		||||
    {"m2a",      "audio/mpeg"},
 | 
			
		||||
    {"m2v",      "video/mpeg"},
 | 
			
		||||
    {"m3u",      "audio/x-mpequrl"},
 | 
			
		||||
    {"man",      "application/x-troff-man"},
 | 
			
		||||
    {"map",      "application/x-navimap"},
 | 
			
		||||
    {"mar",      "text/plain"},
 | 
			
		||||
    {"mbd",      "application/mbedlet"},
 | 
			
		||||
    {"mc$",      "application/x-magic-cap-package-1.0"},
 | 
			
		||||
    {"mcd",      "application/mcad"},
 | 
			
		||||
    {"mcd",      "application/x-mathcad"},
 | 
			
		||||
    {"mcf",      "image/vasa"},
 | 
			
		||||
    {"mcf",      "text/mcf"},
 | 
			
		||||
    {"mcp",      "application/netmc"},
 | 
			
		||||
    {"me",       "application/x-troff-me"},
 | 
			
		||||
    {"mht",      "message/rfc822"},
 | 
			
		||||
    {"mhtml",    "message/rfc822"},
 | 
			
		||||
    {"mid",      "application/x-midi"},
 | 
			
		||||
    {"mid",      "audio/midi"},
 | 
			
		||||
    {"mid",      "audio/x-mid"},
 | 
			
		||||
    {"mid",      "audio/x-midi"},
 | 
			
		||||
    {"mid",      "music/crescendo"},
 | 
			
		||||
    {"mid",      "x-music/x-midi"},
 | 
			
		||||
    {"midi",     "application/x-midi"},
 | 
			
		||||
    {"midi",     "audio/midi"},
 | 
			
		||||
    {"midi",     "audio/x-mid"},
 | 
			
		||||
    {"midi",     "audio/x-midi"},
 | 
			
		||||
    {"midi",     "music/crescendo"},
 | 
			
		||||
    {"midi",     "x-music/x-midi"},
 | 
			
		||||
    {"mif",      "application/x-frame"},
 | 
			
		||||
    {"mif",      "application/x-mif"},
 | 
			
		||||
    {"mime",     "message/rfc822"},
 | 
			
		||||
    {"mime",     "www/mime"},
 | 
			
		||||
    {"mjf",      "audio/x-vnd.audioexplosion.mjuicemediafile"},
 | 
			
		||||
    {"mjpg",     "video/x-motion-jpeg"},
 | 
			
		||||
    {"mm",       "application/base64"},
 | 
			
		||||
    {"mm",       "application/x-meme"},
 | 
			
		||||
    {"mme",      "application/base64"},
 | 
			
		||||
    {"mod",      "audio/mod"},
 | 
			
		||||
    {"mod",      "audio/x-mod"},
 | 
			
		||||
    {"moov",     "video/quicktime"},
 | 
			
		||||
    {"mov",      "video/quicktime"},
 | 
			
		||||
    {"movie",    "video/x-sgi-movie"},
 | 
			
		||||
    {"mp2",      "audio/mpeg"},
 | 
			
		||||
    {"mp2",      "audio/x-mpeg"},
 | 
			
		||||
    {"mp2",      "video/mpeg"},
 | 
			
		||||
    {"mp2",      "video/x-mpeg"},
 | 
			
		||||
    {"mp2",      "video/x-mpeq2a"},
 | 
			
		||||
    {"mp3",      "audio/mpeg"},
 | 
			
		||||
    {"mp3",      "audio/mpeg3"},
 | 
			
		||||
    {"mp3",      "audio/x-mpeg-3"},
 | 
			
		||||
    {"mp3",      "video/mpeg"},
 | 
			
		||||
    {"mp3",      "video/x-mpeg"},
 | 
			
		||||
    {"mpa",      "audio/mpeg"},
 | 
			
		||||
    {"mpa",      "video/mpeg"},
 | 
			
		||||
    {"mpc",      "application/x-project"},
 | 
			
		||||
    {"mpe",      "video/mpeg"},
 | 
			
		||||
    {"mpeg",     "video/mpeg"},
 | 
			
		||||
    {"mpg",      "audio/mpeg"},
 | 
			
		||||
    {"mpg",      "video/mpeg"},
 | 
			
		||||
    {"mpga",     "audio/mpeg"},
 | 
			
		||||
    {"mpp",      "application/vnd.ms-project"},
 | 
			
		||||
    {"mpt",      "application/x-project"},
 | 
			
		||||
    {"mpv",      "application/x-project"},
 | 
			
		||||
    {"mpx",      "application/x-project"},
 | 
			
		||||
    {"mrc",      "application/marc"},
 | 
			
		||||
    {"ms",       "application/x-troff-ms"},
 | 
			
		||||
    {"mv",       "video/x-sgi-movie"},
 | 
			
		||||
    {"my",       "audio/make"},
 | 
			
		||||
    {"mzz",      "application/x-vnd.audioexplosion.mzz"},
 | 
			
		||||
    {"nap",      "image/naplps"},
 | 
			
		||||
    {"naplps",   "image/naplps"},
 | 
			
		||||
    {"nc",       "application/x-netcdf"},
 | 
			
		||||
    {"ncm",      "application/vnd.nokia.configuration-message"},
 | 
			
		||||
    {"nif",      "image/x-niff"},
 | 
			
		||||
    {"niff",     "image/x-niff"},
 | 
			
		||||
    {"nix",      "application/x-mix-transfer"},
 | 
			
		||||
    {"nsc",      "application/x-conference"},
 | 
			
		||||
    {"nvd",      "application/x-navidoc"},
 | 
			
		||||
    {"o",        "application/octet-stream"},
 | 
			
		||||
    {"oda",      "application/oda"},
 | 
			
		||||
    {"omc",      "application/x-omc"},
 | 
			
		||||
    {"omcd",     "application/x-omcdatamaker"},
 | 
			
		||||
    {"omcr",     "application/x-omcregerator"},
 | 
			
		||||
    {"p",        "text/x-pascal"},
 | 
			
		||||
    {"p10",      "application/pkcs10"},
 | 
			
		||||
    {"p10",      "application/x-pkcs10"},
 | 
			
		||||
    {"p12",      "application/pkcs-12"},
 | 
			
		||||
    {"p12",      "application/x-pkcs12"},
 | 
			
		||||
    {"p7a",      "application/x-pkcs7-signature"},
 | 
			
		||||
    {"p7c",      "application/pkcs7-mime"},
 | 
			
		||||
    {"p7c",      "application/x-pkcs7-mime"},
 | 
			
		||||
    {"p7m",      "application/pkcs7-mime"},
 | 
			
		||||
    {"p7m",      "application/x-pkcs7-mime"},
 | 
			
		||||
    {"p7r",      "application/x-pkcs7-certreqresp"},
 | 
			
		||||
    {"p7s",      "application/pkcs7-signature"},
 | 
			
		||||
    {"part",     "application/pro_eng"},
 | 
			
		||||
    {"pas",      "text/pascal"},
 | 
			
		||||
    {"pbm",      "image/x-portable-bitmap"},
 | 
			
		||||
    {"pcl",      "application/vnd.hp-pcl"},
 | 
			
		||||
    {"pcl",      "application/x-pcl"},
 | 
			
		||||
    {"pct",      "image/x-pict"},
 | 
			
		||||
    {"pcx",      "image/x-pcx"},
 | 
			
		||||
    {"pdb",      "chemical/x-pdb"},
 | 
			
		||||
    {"pdf",      "application/pdf"},
 | 
			
		||||
    {"pfunk",    "audio/make"},
 | 
			
		||||
    {"pfunk",    "audio/make.my.funk"},
 | 
			
		||||
    {"pgm",      "image/x-portable-graymap"},
 | 
			
		||||
    {"pgm",      "image/x-portable-greymap"},
 | 
			
		||||
    {"pic",      "image/pict"},
 | 
			
		||||
    {"pict",     "image/pict"},
 | 
			
		||||
    {"pkg",      "application/x-newton-compatible-pkg"},
 | 
			
		||||
    {"pko",      "application/vnd.ms-pki.pko"},
 | 
			
		||||
    {"pl",       "text/plain"},
 | 
			
		||||
    {"pl",       "text/x-script.perl"},
 | 
			
		||||
    {"plx",      "application/x-pixclscript"},
 | 
			
		||||
    {"pm",       "image/x-xpixmap"},
 | 
			
		||||
    {"pm",       "text/x-script.perl-module"},
 | 
			
		||||
    {"pm4",      "application/x-pagemaker"},
 | 
			
		||||
    {"pm5",      "application/x-pagemaker"},
 | 
			
		||||
    {"png",      "image/png"},
 | 
			
		||||
    {"pnm",      "application/x-portable-anymap"},
 | 
			
		||||
    {"pnm",      "image/x-portable-anymap"},
 | 
			
		||||
    {"pot",      "application/mspowerpoint"},
 | 
			
		||||
    {"pot",      "application/vnd.ms-powerpoint"},
 | 
			
		||||
    {"pov",      "model/x-pov"},
 | 
			
		||||
    {"ppa",      "application/vnd.ms-powerpoint"},
 | 
			
		||||
    {"ppm",      "image/x-portable-pixmap"},
 | 
			
		||||
    {"pps",      "application/mspowerpoint"},
 | 
			
		||||
    {"pps",      "application/vnd.ms-powerpoint"},
 | 
			
		||||
    {"ppt",      "application/mspowerpoint"},
 | 
			
		||||
    {"ppt",      "application/powerpoint"},
 | 
			
		||||
    {"ppt",      "application/vnd.ms-powerpoint"},
 | 
			
		||||
    {"ppt",      "application/x-mspowerpoint"},
 | 
			
		||||
    {"ppz",      "application/mspowerpoint"},
 | 
			
		||||
    {"pre",      "application/x-freelance"},
 | 
			
		||||
    {"prt",      "application/pro_eng"},
 | 
			
		||||
    {"ps",       "application/postscript"},
 | 
			
		||||
    {"psd",      "application/octet-stream"},
 | 
			
		||||
    {"pvu",      "paleovu/x-pv"},
 | 
			
		||||
    {"pwz",      "application/vnd.ms-powerpoint"},
 | 
			
		||||
    {"py",       "text/x-script.phyton"},
 | 
			
		||||
    {"pyc",      "application/x-bytecode.python"},
 | 
			
		||||
    {"qcp",      "audio/vnd.qcelp"},
 | 
			
		||||
    {"qd3",      "x-world/x-3dmf"},
 | 
			
		||||
    {"qd3d",     "x-world/x-3dmf"},
 | 
			
		||||
    {"qif",      "image/x-quicktime"},
 | 
			
		||||
    {"qt",       "video/quicktime"},
 | 
			
		||||
    {"qtc",      "video/x-qtc"},
 | 
			
		||||
    {"qti",      "image/x-quicktime"},
 | 
			
		||||
    {"qtif",     "image/x-quicktime"},
 | 
			
		||||
    {"ra",       "audio/x-pn-realaudio"},
 | 
			
		||||
    {"ra",       "audio/x-pn-realaudio-plugin"},
 | 
			
		||||
    {"ra",       "audio/x-realaudio"},
 | 
			
		||||
    {"ram",      "audio/x-pn-realaudio"},
 | 
			
		||||
    {"ras",      "application/x-cmu-raster"},
 | 
			
		||||
    {"ras",      "image/cmu-raster"},
 | 
			
		||||
    {"ras",      "image/x-cmu-raster"},
 | 
			
		||||
    {"rast",     "image/cmu-raster"},
 | 
			
		||||
    {"rexx",     "text/x-script.rexx"},
 | 
			
		||||
    {"rf",       "image/vnd.rn-realflash"},
 | 
			
		||||
    {"rgb",      "image/x-rgb"},
 | 
			
		||||
    {"rm",       "application/vnd.rn-realmedia"},
 | 
			
		||||
    {"rm",       "audio/x-pn-realaudio"},
 | 
			
		||||
    {"rmi",      "audio/mid"},
 | 
			
		||||
    {"rmm",      "audio/x-pn-realaudio"},
 | 
			
		||||
    {"rmp",      "audio/x-pn-realaudio"},
 | 
			
		||||
    {"rmp",      "audio/x-pn-realaudio-plugin"},
 | 
			
		||||
    {"rng",      "application/ringing-tones"},
 | 
			
		||||
    {"rng",      "application/vnd.nokia.ringing-tone"},
 | 
			
		||||
    {"rnx",      "application/vnd.rn-realplayer"},
 | 
			
		||||
    {"roff",     "application/x-troff"},
 | 
			
		||||
    {"rp",       "image/vnd.rn-realpix"},
 | 
			
		||||
    {"rpm",      "audio/x-pn-realaudio-plugin"},
 | 
			
		||||
    {"rt",       "text/richtext"},
 | 
			
		||||
    {"rt",       "text/vnd.rn-realtext"},
 | 
			
		||||
    {"rtf",      "application/rtf"},
 | 
			
		||||
    {"rtf",      "application/x-rtf"},
 | 
			
		||||
    {"rtf",      "text/richtext"},
 | 
			
		||||
    {"rtx",      "application/rtf"},
 | 
			
		||||
    {"rtx",      "text/richtext"},
 | 
			
		||||
    {"rv",       "video/vnd.rn-realvideo"},
 | 
			
		||||
    {"s",        "text/x-asm"},
 | 
			
		||||
    {"s3m",      "audio/s3m"},
 | 
			
		||||
    {"saveme",   "application/octet-stream"},
 | 
			
		||||
    {"sbk",      "application/x-tbook"},
 | 
			
		||||
    {"scm",      "application/x-lotusscreencam"},
 | 
			
		||||
    {"scm",      "text/x-script.guile"},
 | 
			
		||||
    {"scm",      "text/x-script.scheme"},
 | 
			
		||||
    {"scm",      "video/x-scm"},
 | 
			
		||||
    {"sdml",     "text/plain"},
 | 
			
		||||
    {"sdp",      "application/sdp"},
 | 
			
		||||
    {"sdp",      "application/x-sdp"},
 | 
			
		||||
    {"sdr",      "application/sounder"},
 | 
			
		||||
    {"sea",      "application/sea"},
 | 
			
		||||
    {"sea",      "application/x-sea"},
 | 
			
		||||
    {"set",      "application/set"},
 | 
			
		||||
    {"sgm",      "text/sgml"},
 | 
			
		||||
    {"sgm",      "text/x-sgml"},
 | 
			
		||||
    {"sgml",     "text/sgml"},
 | 
			
		||||
    {"sgml",     "text/x-sgml"},
 | 
			
		||||
    {"sh",       "application/x-bsh"},
 | 
			
		||||
    {"sh",       "application/x-sh"},
 | 
			
		||||
    {"sh",       "application/x-shar"},
 | 
			
		||||
    {"sh",       "text/x-script.sh"},
 | 
			
		||||
    {"shar",     "application/x-bsh"},
 | 
			
		||||
    {"shar",     "application/x-shar"},
 | 
			
		||||
    {"shtml",    "text/html"},
 | 
			
		||||
    {"shtml",    "text/x-server-parsed-html"},
 | 
			
		||||
    {"sid",      "audio/x-psid"},
 | 
			
		||||
    {"sit",      "application/x-sit"},
 | 
			
		||||
    {"sit",      "application/x-stuffit"},
 | 
			
		||||
    {"skd",      "application/x-koan"},
 | 
			
		||||
    {"skm",      "application/x-koan"},
 | 
			
		||||
    {"skp",      "application/x-koan"},
 | 
			
		||||
    {"skt",      "application/x-koan"},
 | 
			
		||||
    {"sl",       "application/x-seelogo"},
 | 
			
		||||
    {"smi",      "application/smil"},
 | 
			
		||||
    {"smil",     "application/smil"},
 | 
			
		||||
    {"snd",      "audio/basic"},
 | 
			
		||||
    {"snd",      "audio/x-adpcm"},
 | 
			
		||||
    {"sol",      "application/solids"},
 | 
			
		||||
    {"spc",      "application/x-pkcs7-certificates"},
 | 
			
		||||
    {"spc",      "text/x-speech"},
 | 
			
		||||
    {"spl",      "application/futuresplash"},
 | 
			
		||||
    {"spr",      "application/x-sprite"},
 | 
			
		||||
    {"sprite",   "application/x-sprite"},
 | 
			
		||||
    {"src",      "application/x-wais-source"},
 | 
			
		||||
    {"ssi",      "text/x-server-parsed-html"},
 | 
			
		||||
    {"ssm",      "application/streamingmedia"},
 | 
			
		||||
    {"sst",      "application/vnd.ms-pki.certstore"},
 | 
			
		||||
    {"step",     "application/step"},
 | 
			
		||||
    {"stl",      "application/sla"},
 | 
			
		||||
    {"stl",      "application/vnd.ms-pki.stl"},
 | 
			
		||||
    {"stl",      "application/x-navistyle"},
 | 
			
		||||
    {"stp",      "application/step"},
 | 
			
		||||
    {"sv4cpio,", "application/x-sv4cpio"},
 | 
			
		||||
    {"sv4crc",   "application/x-sv4crc"},
 | 
			
		||||
    {"svf",      "image/vnd.dwg"},
 | 
			
		||||
    {"svf",      "image/x-dwg"},
 | 
			
		||||
    {"svr",      "application/x-world"},
 | 
			
		||||
    {"svr",      "x-world/x-svr"},
 | 
			
		||||
    {"swf",      "application/x-shockwave-flash"},
 | 
			
		||||
    {"t",        "application/x-troff"},
 | 
			
		||||
    {"talk",     "text/x-speech"},
 | 
			
		||||
    {"tar",      "application/x-tar"},
 | 
			
		||||
    {"tbk",      "application/toolbook"},
 | 
			
		||||
    {"tbk",      "application/x-tbook"},
 | 
			
		||||
    {"tcl",      "application/x-tcl"},
 | 
			
		||||
    {"tcl",      "text/x-script.tcl"},
 | 
			
		||||
    {"tcsh",     "text/x-script.tcsh"},
 | 
			
		||||
    {"tex",      "application/x-tex"},
 | 
			
		||||
    {"texi",     "application/x-texinfo"},
 | 
			
		||||
    {"texinfo,", "application/x-texinfo"},
 | 
			
		||||
    {"text",     "application/plain"},
 | 
			
		||||
    {"text",     "text/plain"},
 | 
			
		||||
    {"tgz",      "application/gnutar"},
 | 
			
		||||
    {"tgz",      "application/x-compressed"},
 | 
			
		||||
    {"tif",      "image/tiff"},
 | 
			
		||||
    {"tif",      "image/x-tiff"},
 | 
			
		||||
    {"tiff",     "image/tiff"},
 | 
			
		||||
    {"tiff",     "image/x-tiff"},
 | 
			
		||||
    {"tr",       "application/x-troff"},
 | 
			
		||||
    {"tsi",      "audio/tsp-audio"},
 | 
			
		||||
    {"tsp",      "application/dsptype"},
 | 
			
		||||
    {"tsp",      "audio/tsplayer"},
 | 
			
		||||
    {"tsv",      "text/tab-separated-values"},
 | 
			
		||||
    {"turbot",   "image/florian"},
 | 
			
		||||
    {"txt",      "text/plain"},
 | 
			
		||||
    {"uil",      "text/x-uil"},
 | 
			
		||||
    {"uni",      "text/uri-list"},
 | 
			
		||||
    {"unis",     "text/uri-list"},
 | 
			
		||||
    {"unv",      "application/i-deas"},
 | 
			
		||||
    {"uri",      "text/uri-list"},
 | 
			
		||||
    {"uris",     "text/uri-list"},
 | 
			
		||||
    {"ustar",    "application/x-ustar"},
 | 
			
		||||
    {"ustar",    "multipart/x-ustar"},
 | 
			
		||||
    {"uu",       "application/octet-stream"},
 | 
			
		||||
    {"uu",       "text/x-uuencode"},
 | 
			
		||||
    {"uue",      "text/x-uuencode"},
 | 
			
		||||
    {"vcd",      "application/x-cdlink"},
 | 
			
		||||
    {"vcs",      "text/x-vcalendar"},
 | 
			
		||||
    {"vda",      "application/vda"},
 | 
			
		||||
    {"vdo",      "video/vdo"},
 | 
			
		||||
    {"vew",      "application/groupwise"},
 | 
			
		||||
    {"viv",      "video/vivo"},
 | 
			
		||||
    {"viv",      "video/vnd.vivo"},
 | 
			
		||||
    {"vivo",     "video/vivo"},
 | 
			
		||||
    {"vivo",     "video/vnd.vivo"},
 | 
			
		||||
    {"vmd",      "application/vocaltec-media-desc"},
 | 
			
		||||
    {"vmf",      "application/vocaltec-media-file"},
 | 
			
		||||
    {"voc",      "audio/voc"},
 | 
			
		||||
    {"voc",      "audio/x-voc"},
 | 
			
		||||
    {"vos",      "video/vosaic"},
 | 
			
		||||
    {"vox",      "audio/voxware"},
 | 
			
		||||
    {"vqe",      "audio/x-twinvq-plugin"},
 | 
			
		||||
    {"vqf",      "audio/x-twinvq"},
 | 
			
		||||
    {"vql",      "audio/x-twinvq-plugin"},
 | 
			
		||||
    {"vrml",     "application/x-vrml"},
 | 
			
		||||
    {"vrml",     "model/vrml"},
 | 
			
		||||
    {"vrml",     "x-world/x-vrml"},
 | 
			
		||||
    {"vrt",      "x-world/x-vrt"},
 | 
			
		||||
    {"vsd",      "application/x-visio"},
 | 
			
		||||
    {"vst",      "application/x-visio"},
 | 
			
		||||
    {"vsw",      "application/x-visio"},
 | 
			
		||||
    {"w60",      "application/wordperfect6.0"},
 | 
			
		||||
    {"w61",      "application/wordperfect6.1"},
 | 
			
		||||
    {"w6w",      "application/msword"},
 | 
			
		||||
    {"wav",      "audio/wav"},
 | 
			
		||||
    {"wav",      "audio/x-wav"},
 | 
			
		||||
    {"wb1",      "application/x-qpro"},
 | 
			
		||||
    {"wbmp",     "image/vnd.wap.wbmp"},
 | 
			
		||||
    {"web",      "application/vnd.xara"},
 | 
			
		||||
    {"wiz",      "application/msword"},
 | 
			
		||||
    {"wk1",      "application/x-123"},
 | 
			
		||||
    {"wmf",      "windows/metafile"},
 | 
			
		||||
    {"wml",      "text/vnd.wap.wml"},
 | 
			
		||||
    {"wmlc",     "application/vnd.wap.wmlc"},
 | 
			
		||||
    {"wmls",     "text/vnd.wap.wmlscript"},
 | 
			
		||||
    {"wmlsc",    "application/vnd.wap.wmlscriptc"},
 | 
			
		||||
    {"word",     "application/msword"},
 | 
			
		||||
    {"wp",       "application/wordperfect"},
 | 
			
		||||
    {"wp5",      "application/wordperfect"},
 | 
			
		||||
    {"wp5",      "application/wordperfect6.0"},
 | 
			
		||||
    {"wp6",      "application/wordperfect"},
 | 
			
		||||
    {"wpd",      "application/wordperfect"},
 | 
			
		||||
    {"wpd",      "application/x-wpwin"},
 | 
			
		||||
    {"wq1",      "application/x-lotus"},
 | 
			
		||||
    {"wri",      "application/mswrite"},
 | 
			
		||||
    {"wri",      "application/x-wri"},
 | 
			
		||||
    {"wrl",      "application/x-world"},
 | 
			
		||||
    {"wrl",      "model/vrml"},
 | 
			
		||||
    {"wrl",      "x-world/x-vrml"},
 | 
			
		||||
    {"wrz",      "model/vrml"},
 | 
			
		||||
    {"wrz",      "x-world/x-vrml"},
 | 
			
		||||
    {"wsc",      "text/scriplet"},
 | 
			
		||||
    {"wsrc",     "application/x-wais-source"},
 | 
			
		||||
    {"wtk",      "application/x-wintalk"},
 | 
			
		||||
    {"xbm",      "image/x-xbitmap"},
 | 
			
		||||
    {"xbm",      "image/x-xbm"},
 | 
			
		||||
    {"xbm",      "image/xbm"},
 | 
			
		||||
    {"xdr",      "video/x-amt-demorun"},
 | 
			
		||||
    {"xgz",      "xgl/drawing"},
 | 
			
		||||
    {"xif",      "image/vnd.xiff"},
 | 
			
		||||
    {"xl",       "application/excel"},
 | 
			
		||||
    {"xla",      "application/excel"},
 | 
			
		||||
    {"xla",      "application/x-excel"},
 | 
			
		||||
    {"xla",      "application/x-msexcel"},
 | 
			
		||||
    {"xlb",      "application/excel"},
 | 
			
		||||
    {"xlb",      "application/vnd.ms-excel"},
 | 
			
		||||
    {"xlb",      "application/x-excel"},
 | 
			
		||||
    {"xlc",      "application/excel"},
 | 
			
		||||
    {"xlc",      "application/vnd.ms-excel"},
 | 
			
		||||
    {"xlc",      "application/x-excel"},
 | 
			
		||||
    {"xld",      "application/excel"},
 | 
			
		||||
    {"xld",      "application/x-excel"},
 | 
			
		||||
    {"xlk",      "application/excel"},
 | 
			
		||||
    {"xlk",      "application/x-excel"},
 | 
			
		||||
    {"xll",      "application/excel"},
 | 
			
		||||
    {"xll",      "application/vnd.ms-excel"},
 | 
			
		||||
    {"xll",      "application/x-excel"},
 | 
			
		||||
    {"xlm",      "application/excel"},
 | 
			
		||||
    {"xlm",      "application/vnd.ms-excel"},
 | 
			
		||||
    {"xlm",      "application/x-excel"},
 | 
			
		||||
    {"xls",      "application/excel"},
 | 
			
		||||
    {"xls",      "application/vnd.ms-excel"},
 | 
			
		||||
    {"xls",      "application/x-excel"},
 | 
			
		||||
    {"xls",      "application/x-msexcel"},
 | 
			
		||||
    {"xlt",      "application/excel"},
 | 
			
		||||
    {"xlt",      "application/x-excel"},
 | 
			
		||||
    {"xlv",      "application/excel"},
 | 
			
		||||
    {"xlv",      "application/x-excel"},
 | 
			
		||||
    {"xlw",      "application/excel"},
 | 
			
		||||
    {"xlw",      "application/vnd.ms-excel"},
 | 
			
		||||
    {"xlw",      "application/x-excel"},
 | 
			
		||||
    {"xlw",      "application/x-msexcel"},
 | 
			
		||||
    {"xm",       "audio/xm"},
 | 
			
		||||
    {"xml",      "application/xml"},
 | 
			
		||||
    {"xml",      "text/xml"},
 | 
			
		||||
    {"xmz",      "xgl/movie"},
 | 
			
		||||
    {"xpix",     "application/x-vnd.ls-xpix"},
 | 
			
		||||
    {"xpm",      "image/x-xpixmap"},
 | 
			
		||||
    {"xpm",      "image/xpm"},
 | 
			
		||||
    {"x-png",    "image/png"},
 | 
			
		||||
    {"xsr",      "video/x-amt-showrun"},
 | 
			
		||||
    {"xwd",      "image/x-xwd"},
 | 
			
		||||
    {"xwd",      "image/x-xwindowdump"},
 | 
			
		||||
    {"xyz",      "chemical/x-pdb"},
 | 
			
		||||
    {"z",        "application/x-compress"},
 | 
			
		||||
    {"z",        "application/x-compressed"},
 | 
			
		||||
    {"zip",      "application/x-compressed"},
 | 
			
		||||
    {"zip",      "application/x-zip-compressed"},
 | 
			
		||||
    {"zip",      "application/zip"},
 | 
			
		||||
    {"zip",      "multipart/x-zip"},
 | 
			
		||||
    {"zoo",      "application/octet-stream"}
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
} // namespace juce
 | 
			
		||||
@@ -1,212 +1,207 @@
 | 
			
		||||
/*
 | 
			
		||||
  ==============================================================================
 | 
			
		||||
 | 
			
		||||
   This file is part of the JUCE library.
 | 
			
		||||
   Copyright (c) 2020 - Raw Material Software Limited
 | 
			
		||||
 | 
			
		||||
   JUCE is an open source library subject to commercial or open-source
 | 
			
		||||
   licensing.
 | 
			
		||||
 | 
			
		||||
   By using JUCE, you agree to the terms of both the JUCE 6 End-User License
 | 
			
		||||
   Agreement and JUCE Privacy Policy (both effective as of the 16th June 2020).
 | 
			
		||||
 | 
			
		||||
   End User License Agreement: www.juce.com/juce-6-licence
 | 
			
		||||
   Privacy Policy: www.juce.com/juce-privacy-policy
 | 
			
		||||
 | 
			
		||||
   Or: You may also use this code under the terms of the GPL v3 (see
 | 
			
		||||
   www.gnu.org/licenses).
 | 
			
		||||
 | 
			
		||||
   JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
 | 
			
		||||
   EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
 | 
			
		||||
   DISCLAIMED.
 | 
			
		||||
 | 
			
		||||
  ==============================================================================
 | 
			
		||||
*/
 | 
			
		||||
 | 
			
		||||
namespace juce
 | 
			
		||||
{
 | 
			
		||||
 | 
			
		||||
class ContentSharer::ContentSharerNativeImpl    : public ContentSharer::Pimpl,
 | 
			
		||||
                                                  private Component
 | 
			
		||||
{
 | 
			
		||||
public:
 | 
			
		||||
    ContentSharerNativeImpl (ContentSharer& cs)
 | 
			
		||||
        : owner (cs)
 | 
			
		||||
    {
 | 
			
		||||
        static PopoverDelegateClass cls;
 | 
			
		||||
        popoverDelegate.reset ([cls.createInstance() init]);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    ~ContentSharerNativeImpl() override
 | 
			
		||||
    {
 | 
			
		||||
        exitModalState (0);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    void shareFiles (const Array<URL>& files) override
 | 
			
		||||
    {
 | 
			
		||||
        auto urls = [NSMutableArray arrayWithCapacity: (NSUInteger) files.size()];
 | 
			
		||||
 | 
			
		||||
        for (const auto& f : files)
 | 
			
		||||
        {
 | 
			
		||||
            NSString* nativeFilePath = nil;
 | 
			
		||||
 | 
			
		||||
            if (f.isLocalFile())
 | 
			
		||||
            {
 | 
			
		||||
                nativeFilePath = juceStringToNS (f.getLocalFile().getFullPathName());
 | 
			
		||||
            }
 | 
			
		||||
            else
 | 
			
		||||
            {
 | 
			
		||||
                auto filePath = f.toString (false);
 | 
			
		||||
 | 
			
		||||
                auto* fileDirectory = filePath.contains ("/")
 | 
			
		||||
                                    ? juceStringToNS (filePath.upToLastOccurrenceOf ("/", false, false))
 | 
			
		||||
                                    : [NSString string];
 | 
			
		||||
 | 
			
		||||
                auto fileName = juceStringToNS (filePath.fromLastOccurrenceOf ("/", false, false)
 | 
			
		||||
                                                        .upToLastOccurrenceOf (".", false, false));
 | 
			
		||||
 | 
			
		||||
                auto fileExt = juceStringToNS (filePath.fromLastOccurrenceOf (".", false, false));
 | 
			
		||||
 | 
			
		||||
                if ([fileDirectory length] == NSUInteger (0))
 | 
			
		||||
                    nativeFilePath = [[NSBundle mainBundle] pathForResource: fileName
 | 
			
		||||
                                                                     ofType: fileExt];
 | 
			
		||||
                else
 | 
			
		||||
                    nativeFilePath = [[NSBundle mainBundle] pathForResource: fileName
 | 
			
		||||
                                                                     ofType: fileExt
 | 
			
		||||
                                                                inDirectory: fileDirectory];
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            if (nativeFilePath != nil) {
 | 
			
		||||
                [urls addObject: [NSURL fileURLWithPath: nativeFilePath]];
 | 
			
		||||
            }
 | 
			
		||||
            else {
 | 
			
		||||
                // just add the URL as-is (eg, NON file URLS like links, etc)
 | 
			
		||||
                [urls addObject: [NSURL URLWithString:juceStringToNS(f.toString(true))]]; 
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        share (urls);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    void shareText (const String& text) override
 | 
			
		||||
    {
 | 
			
		||||
        auto array = [NSArray arrayWithObject: juceStringToNS (text)];
 | 
			
		||||
        share (array);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
private:
 | 
			
		||||
    void share (NSArray* items)
 | 
			
		||||
    {
 | 
			
		||||
        if ([items count] == 0)
 | 
			
		||||
        {
 | 
			
		||||
            jassertfalse;
 | 
			
		||||
            owner.sharingFinished (false, "No valid items found for sharing.");
 | 
			
		||||
            return;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        controller.reset ([[UIActivityViewController alloc] initWithActivityItems: items
 | 
			
		||||
                                                            applicationActivities: nil]);
 | 
			
		||||
 | 
			
		||||
        controller.get().excludedActivityTypes = nil;
 | 
			
		||||
 | 
			
		||||
        controller.get().completionWithItemsHandler = ^ (UIActivityType type, BOOL completed,
 | 
			
		||||
                                                         NSArray* returnedItems, NSError* error)
 | 
			
		||||
        {
 | 
			
		||||
            ignoreUnused (type);
 | 
			
		||||
            ignoreUnused (returnedItems);
 | 
			
		||||
 | 
			
		||||
            succeeded = completed;
 | 
			
		||||
 | 
			
		||||
            if (error != nil)
 | 
			
		||||
                errorDescription = nsStringToJuce ([error localizedDescription]);
 | 
			
		||||
 | 
			
		||||
            exitModalState (0);
 | 
			
		||||
        };
 | 
			
		||||
 | 
			
		||||
        controller.get().modalTransitionStyle = UIModalTransitionStyleCoverVertical;
 | 
			
		||||
 | 
			
		||||
        auto bounds = Desktop::getInstance().getDisplays().getPrimaryDisplay()->userArea;
 | 
			
		||||
        setBounds (bounds);
 | 
			
		||||
 | 
			
		||||
        setAlwaysOnTop (true);
 | 
			
		||||
        setVisible (true);
 | 
			
		||||
        addToDesktop (0);
 | 
			
		||||
 | 
			
		||||
        enterModalState (true,
 | 
			
		||||
                         ModalCallbackFunction::create ([this] (int)
 | 
			
		||||
                         {
 | 
			
		||||
                             owner.sharingFinished (succeeded, errorDescription);
 | 
			
		||||
                         }),
 | 
			
		||||
                         false);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    static bool isIPad()
 | 
			
		||||
    {
 | 
			
		||||
        return [UIDevice currentDevice].userInterfaceIdiom == UIUserInterfaceIdiomPad;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    //==============================================================================
 | 
			
		||||
    void parentHierarchyChanged() override
 | 
			
		||||
    {
 | 
			
		||||
        auto* newPeer = dynamic_cast<UIViewComponentPeer*> (getPeer());
 | 
			
		||||
 | 
			
		||||
        if (peer != newPeer)
 | 
			
		||||
        {
 | 
			
		||||
            peer = newPeer;
 | 
			
		||||
 | 
			
		||||
            if (isIPad())
 | 
			
		||||
            {
 | 
			
		||||
                controller.get().preferredContentSize = peer->view.frame.size;
 | 
			
		||||
 | 
			
		||||
                auto screenBounds = [UIScreen mainScreen].bounds;
 | 
			
		||||
 | 
			
		||||
                auto* popoverController = controller.get().popoverPresentationController;
 | 
			
		||||
                popoverController.sourceView = peer->view;
 | 
			
		||||
                popoverController.sourceRect = CGRectMake (0.f, screenBounds.size.height - 10.f, screenBounds.size.width, 10.f);
 | 
			
		||||
                popoverController.canOverlapSourceViewRect = YES;
 | 
			
		||||
                popoverController.delegate = popoverDelegate.get();
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            if (auto* parentController = peer->controller)
 | 
			
		||||
                [parentController showViewController: controller.get() sender: parentController];
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    //==============================================================================
 | 
			
		||||
    struct PopoverDelegateClass    : public ObjCClass<NSObject<UIPopoverPresentationControllerDelegate>>
 | 
			
		||||
    {
 | 
			
		||||
        PopoverDelegateClass()  : ObjCClass<NSObject<UIPopoverPresentationControllerDelegate>> ("PopoverDelegateClass_")
 | 
			
		||||
        {
 | 
			
		||||
            addMethod (@selector (popoverPresentationController:willRepositionPopoverToRect:inView:), willRepositionPopover, "v@:@@@");
 | 
			
		||||
 | 
			
		||||
            registerClass();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        //==============================================================================
 | 
			
		||||
        static void willRepositionPopover (id, SEL, UIPopoverPresentationController*, CGRect* rect, UIView*)
 | 
			
		||||
        {
 | 
			
		||||
            auto screenBounds = [UIScreen mainScreen].bounds;
 | 
			
		||||
 | 
			
		||||
            rect->origin.x = 0.f;
 | 
			
		||||
            rect->origin.y = screenBounds.size.height - 10.f;
 | 
			
		||||
            rect->size.width = screenBounds.size.width;
 | 
			
		||||
            rect->size.height = 10.f;
 | 
			
		||||
        }
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    ContentSharer& owner;
 | 
			
		||||
    UIViewComponentPeer* peer = nullptr;
 | 
			
		||||
    NSUniquePtr<UIActivityViewController> controller;
 | 
			
		||||
    NSUniquePtr<NSObject<UIPopoverPresentationControllerDelegate>> popoverDelegate;
 | 
			
		||||
 | 
			
		||||
    bool succeeded = false;
 | 
			
		||||
    String errorDescription;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
//==============================================================================
 | 
			
		||||
ContentSharer::Pimpl* ContentSharer::createPimpl()
 | 
			
		||||
{
 | 
			
		||||
    return new ContentSharerNativeImpl (*this);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
} // namespace juce
 | 
			
		||||
/*
 | 
			
		||||
  ==============================================================================
 | 
			
		||||
 | 
			
		||||
   This file is part of the JUCE library.
 | 
			
		||||
   Copyright (c) 2022 - Raw Material Software Limited
 | 
			
		||||
 | 
			
		||||
   JUCE is an open source library subject to commercial or open-source
 | 
			
		||||
   licensing.
 | 
			
		||||
 | 
			
		||||
   By using JUCE, you agree to the terms of both the JUCE 7 End-User License
 | 
			
		||||
   Agreement and JUCE Privacy Policy.
 | 
			
		||||
 | 
			
		||||
   End User License Agreement: www.juce.com/juce-7-licence
 | 
			
		||||
   Privacy Policy: www.juce.com/juce-privacy-policy
 | 
			
		||||
 | 
			
		||||
   Or: You may also use this code under the terms of the GPL v3 (see
 | 
			
		||||
   www.gnu.org/licenses).
 | 
			
		||||
 | 
			
		||||
   JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
 | 
			
		||||
   EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
 | 
			
		||||
   DISCLAIMED.
 | 
			
		||||
 | 
			
		||||
  ==============================================================================
 | 
			
		||||
*/
 | 
			
		||||
 | 
			
		||||
namespace juce
 | 
			
		||||
{
 | 
			
		||||
 | 
			
		||||
class ContentSharer::ContentSharerNativeImpl    : public ContentSharer::Pimpl,
 | 
			
		||||
                                                  private Component
 | 
			
		||||
{
 | 
			
		||||
public:
 | 
			
		||||
    ContentSharerNativeImpl (ContentSharer& cs)
 | 
			
		||||
        : owner (cs)
 | 
			
		||||
    {
 | 
			
		||||
        static PopoverDelegateClass cls;
 | 
			
		||||
        popoverDelegate.reset ([cls.createInstance() init]);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    ~ContentSharerNativeImpl() override
 | 
			
		||||
    {
 | 
			
		||||
        exitModalState (0);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    void shareFiles (const Array<URL>& files) override
 | 
			
		||||
    {
 | 
			
		||||
        auto urls = [NSMutableArray arrayWithCapacity: (NSUInteger) files.size()];
 | 
			
		||||
 | 
			
		||||
        for (const auto& f : files)
 | 
			
		||||
        {
 | 
			
		||||
            NSString* nativeFilePath = nil;
 | 
			
		||||
 | 
			
		||||
            if (f.isLocalFile())
 | 
			
		||||
            {
 | 
			
		||||
                nativeFilePath = juceStringToNS (f.getLocalFile().getFullPathName());
 | 
			
		||||
            }
 | 
			
		||||
            else
 | 
			
		||||
            {
 | 
			
		||||
                auto filePath = f.toString (false);
 | 
			
		||||
 | 
			
		||||
                auto* fileDirectory = filePath.contains ("/")
 | 
			
		||||
                                    ? juceStringToNS (filePath.upToLastOccurrenceOf ("/", false, false))
 | 
			
		||||
                                    : [NSString string];
 | 
			
		||||
 | 
			
		||||
                auto fileName = juceStringToNS (filePath.fromLastOccurrenceOf ("/", false, false)
 | 
			
		||||
                                                        .upToLastOccurrenceOf (".", false, false));
 | 
			
		||||
 | 
			
		||||
                auto fileExt = juceStringToNS (filePath.fromLastOccurrenceOf (".", false, false));
 | 
			
		||||
 | 
			
		||||
                if ([fileDirectory length] == NSUInteger (0))
 | 
			
		||||
                    nativeFilePath = [[NSBundle mainBundle] pathForResource: fileName
 | 
			
		||||
                                                                     ofType: fileExt];
 | 
			
		||||
                else
 | 
			
		||||
                    nativeFilePath = [[NSBundle mainBundle] pathForResource: fileName
 | 
			
		||||
                                                                     ofType: fileExt
 | 
			
		||||
                                                                inDirectory: fileDirectory];
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            if (nativeFilePath != nil)
 | 
			
		||||
                [urls addObject: [NSURL fileURLWithPath: nativeFilePath]];
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        share (urls);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    void shareText (const String& text) override
 | 
			
		||||
    {
 | 
			
		||||
        auto array = [NSArray arrayWithObject: juceStringToNS (text)];
 | 
			
		||||
        share (array);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
private:
 | 
			
		||||
    void share (NSArray* items)
 | 
			
		||||
    {
 | 
			
		||||
        if ([items count] == 0)
 | 
			
		||||
        {
 | 
			
		||||
            jassertfalse;
 | 
			
		||||
            owner.sharingFinished (false, "No valid items found for sharing.");
 | 
			
		||||
            return;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        controller.reset ([[UIActivityViewController alloc] initWithActivityItems: items
 | 
			
		||||
                                                            applicationActivities: nil]);
 | 
			
		||||
 | 
			
		||||
        controller.get().excludedActivityTypes = nil;
 | 
			
		||||
 | 
			
		||||
        controller.get().completionWithItemsHandler = ^ (UIActivityType type, BOOL completed,
 | 
			
		||||
                                                         NSArray* returnedItems, NSError* error)
 | 
			
		||||
        {
 | 
			
		||||
            ignoreUnused (type);
 | 
			
		||||
            ignoreUnused (returnedItems);
 | 
			
		||||
 | 
			
		||||
            succeeded = completed;
 | 
			
		||||
 | 
			
		||||
            if (error != nil)
 | 
			
		||||
                errorDescription = nsStringToJuce ([error localizedDescription]);
 | 
			
		||||
 | 
			
		||||
            exitModalState (0);
 | 
			
		||||
        };
 | 
			
		||||
 | 
			
		||||
        controller.get().modalTransitionStyle = UIModalTransitionStyleCoverVertical;
 | 
			
		||||
 | 
			
		||||
        auto bounds = Desktop::getInstance().getDisplays().getPrimaryDisplay()->userArea;
 | 
			
		||||
        setBounds (bounds);
 | 
			
		||||
 | 
			
		||||
        setAlwaysOnTop (true);
 | 
			
		||||
        setVisible (true);
 | 
			
		||||
        addToDesktop (0);
 | 
			
		||||
 | 
			
		||||
        enterModalState (true,
 | 
			
		||||
                         ModalCallbackFunction::create ([this] (int)
 | 
			
		||||
                         {
 | 
			
		||||
                             owner.sharingFinished (succeeded, errorDescription);
 | 
			
		||||
                         }),
 | 
			
		||||
                         false);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    static bool isIPad()
 | 
			
		||||
    {
 | 
			
		||||
        return [UIDevice currentDevice].userInterfaceIdiom == UIUserInterfaceIdiomPad;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    //==============================================================================
 | 
			
		||||
    void parentHierarchyChanged() override
 | 
			
		||||
    {
 | 
			
		||||
        auto* newPeer = dynamic_cast<UIViewComponentPeer*> (getPeer());
 | 
			
		||||
 | 
			
		||||
        if (peer != newPeer)
 | 
			
		||||
        {
 | 
			
		||||
            peer = newPeer;
 | 
			
		||||
 | 
			
		||||
            if (isIPad())
 | 
			
		||||
            {
 | 
			
		||||
                controller.get().preferredContentSize = peer->view.frame.size;
 | 
			
		||||
 | 
			
		||||
                auto screenBounds = [UIScreen mainScreen].bounds;
 | 
			
		||||
 | 
			
		||||
                auto* popoverController = controller.get().popoverPresentationController;
 | 
			
		||||
                popoverController.sourceView = peer->view;
 | 
			
		||||
                popoverController.sourceRect = CGRectMake (0.f, screenBounds.size.height - 10.f, screenBounds.size.width, 10.f);
 | 
			
		||||
                popoverController.canOverlapSourceViewRect = YES;
 | 
			
		||||
                popoverController.delegate = popoverDelegate.get();
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            if (auto* parentController = peer->controller)
 | 
			
		||||
                [parentController showViewController: controller.get() sender: parentController];
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    //==============================================================================
 | 
			
		||||
    struct PopoverDelegateClass    : public ObjCClass<NSObject<UIPopoverPresentationControllerDelegate>>
 | 
			
		||||
    {
 | 
			
		||||
        PopoverDelegateClass()  : ObjCClass<NSObject<UIPopoverPresentationControllerDelegate>> ("PopoverDelegateClass_")
 | 
			
		||||
        {
 | 
			
		||||
            addMethod (@selector (popoverPresentationController:willRepositionPopoverToRect:inView:), willRepositionPopover);
 | 
			
		||||
 | 
			
		||||
            registerClass();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        //==============================================================================
 | 
			
		||||
        static void willRepositionPopover (id, SEL, UIPopoverPresentationController*, CGRect* rect, UIView*)
 | 
			
		||||
        {
 | 
			
		||||
            auto screenBounds = [UIScreen mainScreen].bounds;
 | 
			
		||||
 | 
			
		||||
            rect->origin.x = 0.f;
 | 
			
		||||
            rect->origin.y = screenBounds.size.height - 10.f;
 | 
			
		||||
            rect->size.width = screenBounds.size.width;
 | 
			
		||||
            rect->size.height = 10.f;
 | 
			
		||||
        }
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    ContentSharer& owner;
 | 
			
		||||
    UIViewComponentPeer* peer = nullptr;
 | 
			
		||||
    NSUniquePtr<UIActivityViewController> controller;
 | 
			
		||||
    NSUniquePtr<NSObject<UIPopoverPresentationControllerDelegate>> popoverDelegate;
 | 
			
		||||
 | 
			
		||||
    bool succeeded = false;
 | 
			
		||||
    String errorDescription;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
//==============================================================================
 | 
			
		||||
ContentSharer::Pimpl* ContentSharer::createPimpl()
 | 
			
		||||
{
 | 
			
		||||
    return new ContentSharerNativeImpl (*this);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
} // namespace juce
 | 
			
		||||
 
 | 
			
		||||
@@ -2,15 +2,15 @@
 | 
			
		||||
  ==============================================================================
 | 
			
		||||
 | 
			
		||||
   This file is part of the JUCE library.
 | 
			
		||||
   Copyright (c) 2020 - Raw Material Software Limited
 | 
			
		||||
   Copyright (c) 2022 - Raw Material Software Limited
 | 
			
		||||
 | 
			
		||||
   JUCE is an open source library subject to commercial or open-source
 | 
			
		||||
   licensing.
 | 
			
		||||
 | 
			
		||||
   By using JUCE, you agree to the terms of both the JUCE 6 End-User License
 | 
			
		||||
   Agreement and JUCE Privacy Policy (both effective as of the 16th June 2020).
 | 
			
		||||
   By using JUCE, you agree to the terms of both the JUCE 7 End-User License
 | 
			
		||||
   Agreement and JUCE Privacy Policy.
 | 
			
		||||
 | 
			
		||||
   End User License Agreement: www.juce.com/juce-6-licence
 | 
			
		||||
   End User License Agreement: www.juce.com/juce-7-licence
 | 
			
		||||
   Privacy Policy: www.juce.com/juce-privacy-policy
 | 
			
		||||
 | 
			
		||||
   Or: You may also use this code under the terms of the GPL v3 (see
 | 
			
		||||
@@ -26,7 +26,7 @@
 | 
			
		||||
namespace juce
 | 
			
		||||
{
 | 
			
		||||
 | 
			
		||||
#if ! (defined (__IPHONE_16_0) && __IPHONE_OS_VERSION_MIN_REQUIRED >= __IPHONE_16_0)
 | 
			
		||||
#if ! (defined (__IPHONE_16_0) && __IPHONE_OS_VERSION_MAX_ALLOWED >= __IPHONE_16_0)
 | 
			
		||||
 JUCE_BEGIN_IGNORE_WARNINGS_GCC_LIKE ("-Wdeprecated-declarations")
 | 
			
		||||
 #define JUCE_DEPRECATION_IGNORED 1
 | 
			
		||||
#endif
 | 
			
		||||
@@ -87,14 +87,8 @@ public:
 | 
			
		||||
        {
 | 
			
		||||
            controller.reset ([controllerClassInstance initWithDocumentTypes: utTypeArray
 | 
			
		||||
                                                                      inMode: UIDocumentPickerModeOpen]);
 | 
			
		||||
 | 
			
		||||
            if (@available(iOS 13, *)) {
 | 
			
		||||
                if (owner.startingFile.exists()) {
 | 
			
		||||
                    auto url = [[NSURL alloc] initFileURLWithPath: juceStringToNS (owner.startingFile.getFullPathName())];
 | 
			
		||||
                    [controller.get() setDirectoryURL:url];
 | 
			
		||||
                    [url release];
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
            if (@available (iOS 11.0, *))
 | 
			
		||||
                [controller.get() setAllowsMultipleSelection: (flags & FileBrowserComponent::canSelectMultipleItems) != 0];
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        FileChooserControllerClass::setOwner (controller.get(), this);
 | 
			
		||||
@@ -137,6 +131,16 @@ public:
 | 
			
		||||
    ~Native() override
 | 
			
		||||
    {
 | 
			
		||||
        exitModalState (0);
 | 
			
		||||
 | 
			
		||||
        // Our old peer may not have received a becomeFirstResponder call at this point,
 | 
			
		||||
        // so the static currentlyFocusedPeer may be null.
 | 
			
		||||
        // We'll try to find an appropriate peer to focus.
 | 
			
		||||
 | 
			
		||||
        for (auto i = 0; i < ComponentPeer::getNumPeers(); ++i)
 | 
			
		||||
            if (auto* p = ComponentPeer::getPeer (i))
 | 
			
		||||
                if (p != getPeer())
 | 
			
		||||
                    if (auto* view = (UIView*) p->getNativeHandle())
 | 
			
		||||
                        [view becomeFirstResponder];
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    void launch() override
 | 
			
		||||
@@ -232,37 +236,47 @@ private:
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    //==============================================================================
 | 
			
		||||
    void didPickDocumentAtURL (NSURL* url)
 | 
			
		||||
    void didPickDocumentsAtURLs (NSArray<NSURL*>* urls)
 | 
			
		||||
    {
 | 
			
		||||
        cancelPendingUpdate();
 | 
			
		||||
 | 
			
		||||
        bool isWriting = controller.get().documentPickerMode == UIDocumentPickerModeExportToService
 | 
			
		||||
                       | controller.get().documentPickerMode == UIDocumentPickerModeMoveToService;
 | 
			
		||||
        const auto isWriting =  controller.get().documentPickerMode == UIDocumentPickerModeExportToService
 | 
			
		||||
                             || controller.get().documentPickerMode == UIDocumentPickerModeMoveToService;
 | 
			
		||||
        const auto accessOptions = isWriting ? 0 : NSFileCoordinatorReadingWithoutChanges;
 | 
			
		||||
 | 
			
		||||
        NSUInteger accessOptions = isWriting ? 0 : NSFileCoordinatorReadingWithoutChanges;
 | 
			
		||||
        auto* fileCoordinator = [[[NSFileCoordinator alloc] initWithFilePresenter: nil] autorelease];
 | 
			
		||||
        auto* intents = [[[NSMutableArray alloc] init] autorelease];
 | 
			
		||||
 | 
			
		||||
        auto* fileAccessIntent = isWriting
 | 
			
		||||
                               ? [NSFileAccessIntent writingIntentWithURL: url options: accessOptions]
 | 
			
		||||
                               : [NSFileAccessIntent readingIntentWithURL: url options: accessOptions];
 | 
			
		||||
 | 
			
		||||
        NSArray<NSFileAccessIntent*>* intents = @[fileAccessIntent];
 | 
			
		||||
 | 
			
		||||
        auto fileCoordinator = [[[NSFileCoordinator alloc] initWithFilePresenter: nil] autorelease];
 | 
			
		||||
        for (NSURL* url in urls)
 | 
			
		||||
        {
 | 
			
		||||
            auto* fileAccessIntent = isWriting
 | 
			
		||||
                                   ? [NSFileAccessIntent writingIntentWithURL: url options: accessOptions]
 | 
			
		||||
                                   : [NSFileAccessIntent readingIntentWithURL: url options: accessOptions];
 | 
			
		||||
            [intents addObject: fileAccessIntent];
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        [fileCoordinator coordinateAccessWithIntents: intents queue: [NSOperationQueue mainQueue] byAccessor: ^(NSError* err)
 | 
			
		||||
        {
 | 
			
		||||
            Array<URL> chooserResults;
 | 
			
		||||
            if (err != nil)
 | 
			
		||||
            {
 | 
			
		||||
                auto desc = [err localizedDescription];
 | 
			
		||||
                ignoreUnused (desc);
 | 
			
		||||
                jassertfalse;
 | 
			
		||||
                return;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            if (err == nil)
 | 
			
		||||
            Array<URL> result;
 | 
			
		||||
 | 
			
		||||
            for (NSURL* url in urls)
 | 
			
		||||
            {
 | 
			
		||||
                [url startAccessingSecurityScopedResource];
 | 
			
		||||
 | 
			
		||||
                NSError* error = nil;
 | 
			
		||||
 | 
			
		||||
                NSData* bookmark = [url bookmarkDataWithOptions: 0
 | 
			
		||||
                                 includingResourceValuesForKeys: nil
 | 
			
		||||
                                                  relativeToURL: nil
 | 
			
		||||
                                                          error: &error];
 | 
			
		||||
                auto* bookmark = [url bookmarkDataWithOptions: 0
 | 
			
		||||
                               includingResourceValuesForKeys: nil
 | 
			
		||||
                                                relativeToURL: nil
 | 
			
		||||
                                                        error: &error];
 | 
			
		||||
 | 
			
		||||
                [bookmark retain];
 | 
			
		||||
 | 
			
		||||
@@ -281,25 +295,23 @@ private:
 | 
			
		||||
                    jassertfalse;
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
                chooserResults.add (juceUrl);
 | 
			
		||||
            }
 | 
			
		||||
            else
 | 
			
		||||
            {
 | 
			
		||||
                auto desc = [err localizedDescription];
 | 
			
		||||
                ignoreUnused (desc);
 | 
			
		||||
                jassertfalse;
 | 
			
		||||
                result.add (std::move (juceUrl));
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            owner.finished (chooserResults);
 | 
			
		||||
            owner.finished (std::move (result));
 | 
			
		||||
        }];
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    void didPickDocumentAtURL (NSURL* url)
 | 
			
		||||
    {
 | 
			
		||||
        didPickDocumentsAtURLs (@[url]);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    void pickerWasCancelled()
 | 
			
		||||
    {
 | 
			
		||||
        cancelPendingUpdate();
 | 
			
		||||
 | 
			
		||||
        owner.finished ({});
 | 
			
		||||
        exitModalState (0);
 | 
			
		||||
        // Calling owner.finished will delete this Pimpl instance, so don't call any more member functions here!
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    //==============================================================================
 | 
			
		||||
@@ -309,8 +321,9 @@ private:
 | 
			
		||||
        {
 | 
			
		||||
            addIvar<Native*> ("owner");
 | 
			
		||||
 | 
			
		||||
            addMethod (@selector (documentPicker:didPickDocumentAtURL:), didPickDocumentAtURL,       "v@:@@");
 | 
			
		||||
            addMethod (@selector (documentPickerWasCancelled:),          documentPickerWasCancelled, "v@:@");
 | 
			
		||||
            addMethod (@selector (documentPicker:didPickDocumentAtURL:),   didPickDocumentAtURL);
 | 
			
		||||
            addMethod (@selector (documentPicker:didPickDocumentsAtURLs:), didPickDocumentsAtURLs);
 | 
			
		||||
            addMethod (@selector (documentPickerWasCancelled:),            documentPickerWasCancelled);
 | 
			
		||||
 | 
			
		||||
            addProtocol (@protocol (UIDocumentPickerDelegate));
 | 
			
		||||
 | 
			
		||||
@@ -327,6 +340,12 @@ private:
 | 
			
		||||
                picker->didPickDocumentAtURL (url);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        static void didPickDocumentsAtURLs (id self, SEL, UIDocumentPickerViewController*, NSArray<NSURL*>* urls)
 | 
			
		||||
        {
 | 
			
		||||
            if (auto* picker = getOwner (self))
 | 
			
		||||
                picker->didPickDocumentsAtURLs (urls);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        static void documentPickerWasCancelled (id self, SEL, UIDocumentPickerViewController*)
 | 
			
		||||
        {
 | 
			
		||||
            if (auto* picker = getOwner (self))
 | 
			
		||||
@@ -339,7 +358,7 @@ private:
 | 
			
		||||
        FileChooserControllerClass()  : ObjCClass<UIDocumentPickerViewController> ("FileChooserController_")
 | 
			
		||||
        {
 | 
			
		||||
            addIvar<Native*> ("owner");
 | 
			
		||||
            addMethod (@selector (viewDidDisappear:), viewDidDisappear, "v@:@c");
 | 
			
		||||
            addMethod (@selector (viewDidDisappear:), viewDidDisappear);
 | 
			
		||||
 | 
			
		||||
            registerClass();
 | 
			
		||||
        }
 | 
			
		||||
@@ -390,6 +409,4 @@ std::shared_ptr<FileChooser::Pimpl> FileChooser::showPlatformDialog (FileChooser
 | 
			
		||||
 JUCE_END_IGNORE_WARNINGS_GCC_LIKE
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#undef JUCE_DEPRECATION_IGNORED
 | 
			
		||||
 | 
			
		||||
} // namespace juce
 | 
			
		||||
 
 | 
			
		||||
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							@@ -2,15 +2,15 @@
 | 
			
		||||
  ==============================================================================
 | 
			
		||||
 | 
			
		||||
   This file is part of the JUCE library.
 | 
			
		||||
   Copyright (c) 2020 - Raw Material Software Limited
 | 
			
		||||
   Copyright (c) 2022 - Raw Material Software Limited
 | 
			
		||||
 | 
			
		||||
   JUCE is an open source library subject to commercial or open-source
 | 
			
		||||
   licensing.
 | 
			
		||||
 | 
			
		||||
   By using JUCE, you agree to the terms of both the JUCE 6 End-User License
 | 
			
		||||
   Agreement and JUCE Privacy Policy (both effective as of the 16th June 2020).
 | 
			
		||||
   By using JUCE, you agree to the terms of both the JUCE 7 End-User License
 | 
			
		||||
   Agreement and JUCE Privacy Policy.
 | 
			
		||||
 | 
			
		||||
   End User License Agreement: www.juce.com/juce-6-licence
 | 
			
		||||
   End User License Agreement: www.juce.com/juce-7-licence
 | 
			
		||||
   Privacy Policy: www.juce.com/juce-privacy-policy
 | 
			
		||||
 | 
			
		||||
   Or: You may also use this code under the terms of the GPL v3 (see
 | 
			
		||||
@@ -37,7 +37,7 @@ namespace juce
 | 
			
		||||
    Array<AppInactivityCallback*> appBecomingInactiveCallbacks;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#if JUCE_PUSH_NOTIFICATIONS && defined (__IPHONE_10_0) && __IPHONE_OS_VERSION_MAX_ALLOWED >= __IPHONE_10_0
 | 
			
		||||
#if JUCE_PUSH_NOTIFICATIONS
 | 
			
		||||
@interface JuceAppStartupDelegate : NSObject <UIApplicationDelegate, UNUserNotificationCenterDelegate>
 | 
			
		||||
#else
 | 
			
		||||
@interface JuceAppStartupDelegate : NSObject <UIApplicationDelegate>
 | 
			
		||||
@@ -59,27 +59,47 @@ namespace juce
 | 
			
		||||
   completionHandler: (void (^)(void)) completionHandler;
 | 
			
		||||
- (void) applicationDidReceiveMemoryWarning: (UIApplication *) application;
 | 
			
		||||
#if JUCE_PUSH_NOTIFICATIONS
 | 
			
		||||
- (void) application: (UIApplication*) application didRegisterUserNotificationSettings: (UIUserNotificationSettings*) notificationSettings;
 | 
			
		||||
- (void) application: (UIApplication*) application didRegisterForRemoteNotificationsWithDeviceToken: (NSData*) deviceToken;
 | 
			
		||||
- (void) application: (UIApplication*) application didFailToRegisterForRemoteNotificationsWithError: (NSError*) error;
 | 
			
		||||
- (void) application: (UIApplication*) application didReceiveRemoteNotification: (NSDictionary*) userInfo;
 | 
			
		||||
- (void) application: (UIApplication*) application didReceiveRemoteNotification: (NSDictionary*) userInfo
 | 
			
		||||
  fetchCompletionHandler: (void (^)(UIBackgroundFetchResult result)) completionHandler;
 | 
			
		||||
- (void) application: (UIApplication*) application handleActionWithIdentifier: (NSString*) identifier
 | 
			
		||||
  forRemoteNotification: (NSDictionary*) userInfo withResponseInfo: (NSDictionary*) responseInfo
 | 
			
		||||
   completionHandler: (void(^)()) completionHandler;
 | 
			
		||||
- (void) application: (UIApplication*) application didReceiveLocalNotification: (UILocalNotification*) notification;
 | 
			
		||||
- (void) application: (UIApplication*) application handleActionWithIdentifier: (NSString*) identifier
 | 
			
		||||
  forLocalNotification: (UILocalNotification*) notification completionHandler: (void(^)()) completionHandler;
 | 
			
		||||
- (void) application: (UIApplication*) application handleActionWithIdentifier: (NSString*) identifier
 | 
			
		||||
  forLocalNotification: (UILocalNotification*) notification withResponseInfo: (NSDictionary*) responseInfo
 | 
			
		||||
   completionHandler: (void(^)()) completionHandler;
 | 
			
		||||
#if defined (__IPHONE_10_0) && __IPHONE_OS_VERSION_MAX_ALLOWED >= __IPHONE_10_0
 | 
			
		||||
- (void) userNotificationCenter: (UNUserNotificationCenter*) center willPresentNotification: (UNNotification*) notification
 | 
			
		||||
 | 
			
		||||
- (void)                                 application: (UIApplication*) application
 | 
			
		||||
    didRegisterForRemoteNotificationsWithDeviceToken: (NSData*) deviceToken;
 | 
			
		||||
- (void)                                 application: (UIApplication*) application
 | 
			
		||||
    didFailToRegisterForRemoteNotificationsWithError: (NSError*) error;
 | 
			
		||||
- (void)                                 application: (UIApplication*) application
 | 
			
		||||
                        didReceiveRemoteNotification: (NSDictionary*) userInfo;
 | 
			
		||||
- (void)                                 application: (UIApplication*) application
 | 
			
		||||
                        didReceiveRemoteNotification: (NSDictionary*) userInfo
 | 
			
		||||
                              fetchCompletionHandler: (void (^)(UIBackgroundFetchResult result)) completionHandler;
 | 
			
		||||
- (void)                                 application: (UIApplication*) application
 | 
			
		||||
                          handleActionWithIdentifier: (NSString*) identifier
 | 
			
		||||
                               forRemoteNotification: (NSDictionary*) userInfo
 | 
			
		||||
                                    withResponseInfo: (NSDictionary*) responseInfo
 | 
			
		||||
                                   completionHandler: (void(^)()) completionHandler;
 | 
			
		||||
 | 
			
		||||
JUCE_BEGIN_IGNORE_WARNINGS_GCC_LIKE ("-Wdeprecated-declarations")
 | 
			
		||||
 | 
			
		||||
- (void)                    application: (UIApplication*) application
 | 
			
		||||
    didRegisterUserNotificationSettings: (UIUserNotificationSettings*) notificationSettings;
 | 
			
		||||
- (void)                    application: (UIApplication*) application
 | 
			
		||||
            didReceiveLocalNotification: (UILocalNotification*) notification;
 | 
			
		||||
- (void)                    application: (UIApplication*) application
 | 
			
		||||
             handleActionWithIdentifier: (NSString*) identifier
 | 
			
		||||
                   forLocalNotification: (UILocalNotification*) notification
 | 
			
		||||
                      completionHandler: (void(^)()) completionHandler;
 | 
			
		||||
- (void)                    application: (UIApplication*) application
 | 
			
		||||
             handleActionWithIdentifier: (NSString*) identifier
 | 
			
		||||
                   forLocalNotification: (UILocalNotification*) notification
 | 
			
		||||
                       withResponseInfo: (NSDictionary*) responseInfo
 | 
			
		||||
                      completionHandler: (void(^)()) completionHandler;
 | 
			
		||||
 | 
			
		||||
JUCE_END_IGNORE_WARNINGS_GCC_LIKE
 | 
			
		||||
 | 
			
		||||
- (void) userNotificationCenter: (UNUserNotificationCenter*) center
 | 
			
		||||
        willPresentNotification: (UNNotification*) notification
 | 
			
		||||
          withCompletionHandler: (void (^)(UNNotificationPresentationOptions options)) completionHandler;
 | 
			
		||||
- (void) userNotificationCenter: (UNUserNotificationCenter*) center didReceiveNotificationResponse: (UNNotificationResponse*) response
 | 
			
		||||
- (void) userNotificationCenter: (UNUserNotificationCenter*) center
 | 
			
		||||
 didReceiveNotificationResponse: (UNNotificationResponse*) response
 | 
			
		||||
          withCompletionHandler: (void(^)())completionHandler;
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
@end
 | 
			
		||||
@@ -93,7 +113,7 @@ namespace juce
 | 
			
		||||
    self = [super init];
 | 
			
		||||
    appSuspendTask = UIBackgroundTaskInvalid;
 | 
			
		||||
 | 
			
		||||
   #if JUCE_PUSH_NOTIFICATIONS && defined (__IPHONE_10_0) && __IPHONE_OS_VERSION_MAX_ALLOWED >= __IPHONE_10_0
 | 
			
		||||
   #if JUCE_PUSH_NOTIFICATIONS
 | 
			
		||||
    [UNUserNotificationCenter currentNotificationCenter].delegate = self;
 | 
			
		||||
   #endif
 | 
			
		||||
 | 
			
		||||
@@ -193,87 +213,10 @@ namespace juce
 | 
			
		||||
    _pushNotificationsDelegate = delegate;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
- (BOOL) application:(UIApplication *)application openURL:(NSURL *)
 | 
			
		||||
        url sourceApplication:(NSString *)sourceApplication annotation:(id)
 | 
			
		||||
        annotation
 | 
			
		||||
{
 | 
			
		||||
    if(!JUCEApplicationBase::getInstance())
 | 
			
		||||
    {
 | 
			
		||||
        [self applicationDidFinishLaunching:application];
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // mostly stolen from didPickDocumentAtURL
 | 
			
		||||
    NSUInteger accessOptions = NSFileCoordinatorReadingWithoutChanges;
 | 
			
		||||
 | 
			
		||||
    auto *fileAccessIntent = [NSFileAccessIntent readingIntentWithURL:url options:accessOptions];
 | 
			
		||||
 | 
			
		||||
    NSArray<NSFileAccessIntent *> *intents = @[fileAccessIntent];
 | 
			
		||||
 | 
			
		||||
    auto *fileCoordinator = [[NSFileCoordinator alloc] initWithFilePresenter:nil];
 | 
			
		||||
 | 
			
		||||
    [fileCoordinator coordinateAccessWithIntents:intents queue:[NSOperationQueue mainQueue] byAccessor:^(NSError *err) {
 | 
			
		||||
        if (err == nil) {
 | 
			
		||||
            [url startAccessingSecurityScopedResource];
 | 
			
		||||
 | 
			
		||||
            NSError *error = nil;
 | 
			
		||||
 | 
			
		||||
            NSData *bookmark = [url bookmarkDataWithOptions:0
 | 
			
		||||
                             includingResourceValuesForKeys:nil
 | 
			
		||||
                                              relativeToURL:nil
 | 
			
		||||
                                                      error:&error];
 | 
			
		||||
 | 
			
		||||
            [bookmark retain];
 | 
			
		||||
 | 
			
		||||
            [url stopAccessingSecurityScopedResource];
 | 
			
		||||
 | 
			
		||||
            URL juceUrl(nsStringToJuce([url absoluteString]));
 | 
			
		||||
 | 
			
		||||
            if (error == nil) {
 | 
			
		||||
                setURLBookmark(juceUrl, (void *) bookmark);
 | 
			
		||||
            } else {
 | 
			
		||||
                auto *desc = [error localizedDescription];
 | 
			
		||||
                ignoreUnused(desc);
 | 
			
		||||
                jassertfalse;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            if (auto *app = JUCEApplicationBase::getInstance())
 | 
			
		||||
            {
 | 
			
		||||
                app->urlOpened(juceUrl);
 | 
			
		||||
            }
 | 
			
		||||
            else
 | 
			
		||||
            {
 | 
			
		||||
                jassertfalse;
 | 
			
		||||
            }
 | 
			
		||||
        } else {
 | 
			
		||||
            auto *desc = [err localizedDescription];
 | 
			
		||||
            ignoreUnused(desc);
 | 
			
		||||
            jassertfalse;
 | 
			
		||||
        }
 | 
			
		||||
    }];
 | 
			
		||||
 | 
			
		||||
    return YES;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#if JUCE_PUSH_NOTIFICATIONS
 | 
			
		||||
- (void) application: (UIApplication*) application didRegisterUserNotificationSettings: (UIUserNotificationSettings*) notificationSettings
 | 
			
		||||
{
 | 
			
		||||
    ignoreUnused (application);
 | 
			
		||||
 | 
			
		||||
    SEL selector = @selector (application:didRegisterUserNotificationSettings:);
 | 
			
		||||
 | 
			
		||||
    if (_pushNotificationsDelegate != nil && [_pushNotificationsDelegate respondsToSelector: selector])
 | 
			
		||||
    {
 | 
			
		||||
        NSInvocation* invocation = [NSInvocation invocationWithMethodSignature: [_pushNotificationsDelegate methodSignatureForSelector: selector]];
 | 
			
		||||
        [invocation setSelector: selector];
 | 
			
		||||
        [invocation setTarget: _pushNotificationsDelegate];
 | 
			
		||||
        [invocation setArgument: &application          atIndex:2];
 | 
			
		||||
        [invocation setArgument: ¬ificationSettings atIndex:3];
 | 
			
		||||
 | 
			
		||||
        [invocation invoke];
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
- (void) application: (UIApplication*) application didRegisterForRemoteNotificationsWithDeviceToken: (NSData*) deviceToken
 | 
			
		||||
- (void)                                 application: (UIApplication*) application
 | 
			
		||||
    didRegisterForRemoteNotificationsWithDeviceToken: (NSData*) deviceToken
 | 
			
		||||
{
 | 
			
		||||
    ignoreUnused (application);
 | 
			
		||||
 | 
			
		||||
@@ -291,7 +234,8 @@ namespace juce
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
- (void) application: (UIApplication*) application didFailToRegisterForRemoteNotificationsWithError: (NSError*) error
 | 
			
		||||
- (void)                                 application: (UIApplication*) application
 | 
			
		||||
    didFailToRegisterForRemoteNotificationsWithError: (NSError*) error
 | 
			
		||||
{
 | 
			
		||||
    ignoreUnused (application);
 | 
			
		||||
 | 
			
		||||
@@ -309,7 +253,8 @@ namespace juce
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
- (void) application: (UIApplication*) application didReceiveRemoteNotification: (NSDictionary*) userInfo
 | 
			
		||||
- (void)             application: (UIApplication*) application
 | 
			
		||||
    didReceiveRemoteNotification: (NSDictionary*) userInfo
 | 
			
		||||
{
 | 
			
		||||
    ignoreUnused (application);
 | 
			
		||||
 | 
			
		||||
@@ -327,8 +272,9 @@ namespace juce
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
- (void) application: (UIApplication*) application didReceiveRemoteNotification: (NSDictionary*) userInfo
 | 
			
		||||
  fetchCompletionHandler: (void (^)(UIBackgroundFetchResult result)) completionHandler
 | 
			
		||||
- (void)             application: (UIApplication*) application
 | 
			
		||||
    didReceiveRemoteNotification: (NSDictionary*) userInfo
 | 
			
		||||
          fetchCompletionHandler: (void (^)(UIBackgroundFetchResult result)) completionHandler
 | 
			
		||||
{
 | 
			
		||||
    ignoreUnused (application);
 | 
			
		||||
 | 
			
		||||
@@ -347,9 +293,11 @@ namespace juce
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
- (void) application: (UIApplication*) application handleActionWithIdentifier: (NSString*) identifier
 | 
			
		||||
  forRemoteNotification: (NSDictionary*) userInfo withResponseInfo: (NSDictionary*) responseInfo
 | 
			
		||||
  completionHandler: (void(^)()) completionHandler
 | 
			
		||||
- (void)           application: (UIApplication*) application
 | 
			
		||||
    handleActionWithIdentifier: (NSString*) identifier
 | 
			
		||||
         forRemoteNotification: (NSDictionary*) userInfo
 | 
			
		||||
              withResponseInfo: (NSDictionary*) responseInfo
 | 
			
		||||
             completionHandler: (void(^)()) completionHandler
 | 
			
		||||
{
 | 
			
		||||
    ignoreUnused (application);
 | 
			
		||||
 | 
			
		||||
@@ -370,7 +318,29 @@ namespace juce
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
- (void) application: (UIApplication*) application didReceiveLocalNotification: (UILocalNotification*) notification
 | 
			
		||||
JUCE_BEGIN_IGNORE_WARNINGS_GCC_LIKE ("-Wdeprecated-declarations")
 | 
			
		||||
 | 
			
		||||
- (void)                    application: (UIApplication*) application
 | 
			
		||||
    didRegisterUserNotificationSettings: (UIUserNotificationSettings*) notificationSettings
 | 
			
		||||
{
 | 
			
		||||
    ignoreUnused (application);
 | 
			
		||||
 | 
			
		||||
    SEL selector = @selector (application:didRegisterUserNotificationSettings:);
 | 
			
		||||
 | 
			
		||||
    if (_pushNotificationsDelegate != nil && [_pushNotificationsDelegate respondsToSelector:selector])
 | 
			
		||||
    {
 | 
			
		||||
        NSInvocation* invocation = [NSInvocation invocationWithMethodSignature: [_pushNotificationsDelegate methodSignatureForSelector: selector]];
 | 
			
		||||
        [invocation setSelector: selector];
 | 
			
		||||
        [invocation setTarget: _pushNotificationsDelegate];
 | 
			
		||||
        [invocation setArgument: &application atIndex: 2];
 | 
			
		||||
        [invocation setArgument: ¬ificationSettings atIndex: 3];
 | 
			
		||||
 | 
			
		||||
        [invocation invoke];
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
- (void)            application: (UIApplication*) application
 | 
			
		||||
    didReceiveLocalNotification: (UILocalNotification*) notification
 | 
			
		||||
{
 | 
			
		||||
    ignoreUnused (application);
 | 
			
		||||
 | 
			
		||||
@@ -381,15 +351,17 @@ namespace juce
 | 
			
		||||
        NSInvocation* invocation = [NSInvocation invocationWithMethodSignature: [_pushNotificationsDelegate methodSignatureForSelector: selector]];
 | 
			
		||||
        [invocation setSelector: selector];
 | 
			
		||||
        [invocation setTarget: _pushNotificationsDelegate];
 | 
			
		||||
        [invocation setArgument: &application  atIndex:2];
 | 
			
		||||
        [invocation setArgument: ¬ification atIndex:3];
 | 
			
		||||
        [invocation setArgument: &application  atIndex: 2];
 | 
			
		||||
        [invocation setArgument: ¬ification atIndex: 3];
 | 
			
		||||
 | 
			
		||||
        [invocation invoke];
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
- (void) application: (UIApplication*) application handleActionWithIdentifier: (NSString*) identifier
 | 
			
		||||
  forLocalNotification: (UILocalNotification*) notification completionHandler: (void(^)()) completionHandler
 | 
			
		||||
- (void)           application: (UIApplication*) application
 | 
			
		||||
    handleActionWithIdentifier: (NSString*) identifier
 | 
			
		||||
          forLocalNotification: (UILocalNotification*) notification
 | 
			
		||||
             completionHandler: (void(^)()) completionHandler
 | 
			
		||||
{
 | 
			
		||||
    ignoreUnused (application);
 | 
			
		||||
 | 
			
		||||
@@ -409,9 +381,11 @@ namespace juce
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
- (void) application: (UIApplication*) application handleActionWithIdentifier: (NSString*) identifier
 | 
			
		||||
  forLocalNotification: (UILocalNotification*) notification withResponseInfo: (NSDictionary*) responseInfo
 | 
			
		||||
  completionHandler: (void(^)()) completionHandler
 | 
			
		||||
- (void)           application: (UIApplication*) application
 | 
			
		||||
    handleActionWithIdentifier: (NSString*) identifier
 | 
			
		||||
          forLocalNotification: (UILocalNotification*) notification
 | 
			
		||||
              withResponseInfo: (NSDictionary*) responseInfo
 | 
			
		||||
             completionHandler: (void(^)()) completionHandler
 | 
			
		||||
{
 | 
			
		||||
    ignoreUnused (application);
 | 
			
		||||
 | 
			
		||||
@@ -432,9 +406,11 @@ namespace juce
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#if defined (__IPHONE_10_0) && __IPHONE_OS_VERSION_MAX_ALLOWED >= __IPHONE_10_0
 | 
			
		||||
- (void) userNotificationCenter: (UNUserNotificationCenter*) center willPresentNotification: (UNNotification*) notification
 | 
			
		||||
         withCompletionHandler: (void (^)(UNNotificationPresentationOptions options)) completionHandler
 | 
			
		||||
JUCE_END_IGNORE_WARNINGS_GCC_LIKE
 | 
			
		||||
 | 
			
		||||
- (void) userNotificationCenter: (UNUserNotificationCenter*) center
 | 
			
		||||
        willPresentNotification: (UNNotification*) notification
 | 
			
		||||
          withCompletionHandler: (void (^)(UNNotificationPresentationOptions options)) completionHandler
 | 
			
		||||
{
 | 
			
		||||
    ignoreUnused (center);
 | 
			
		||||
 | 
			
		||||
@@ -453,8 +429,9 @@ namespace juce
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
- (void) userNotificationCenter: (UNUserNotificationCenter*) center didReceiveNotificationResponse: (UNNotificationResponse*) response
 | 
			
		||||
         withCompletionHandler: (void(^)()) completionHandler
 | 
			
		||||
- (void) userNotificationCenter: (UNUserNotificationCenter*) center
 | 
			
		||||
 didReceiveNotificationResponse: (UNNotificationResponse*) response
 | 
			
		||||
          withCompletionHandler: (void(^)()) completionHandler
 | 
			
		||||
{
 | 
			
		||||
    ignoreUnused (center);
 | 
			
		||||
 | 
			
		||||
@@ -473,7 +450,6 @@ namespace juce
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
#endif
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
@end
 | 
			
		||||
 | 
			
		||||
@@ -498,8 +474,11 @@ void LookAndFeel::playAlertSound()
 | 
			
		||||
class iOSMessageBox
 | 
			
		||||
{
 | 
			
		||||
public:
 | 
			
		||||
    iOSMessageBox (const MessageBoxOptions& opts, std::unique_ptr<ModalComponentManager::Callback>&& cb)
 | 
			
		||||
        : callback (std::move (cb))
 | 
			
		||||
    iOSMessageBox (const MessageBoxOptions& opts,
 | 
			
		||||
                   std::unique_ptr<ModalComponentManager::Callback>&& cb,
 | 
			
		||||
                   bool deleteOnCompletion)
 | 
			
		||||
        : callback (std::move (cb)),
 | 
			
		||||
          shouldDeleteThis (deleteOnCompletion)
 | 
			
		||||
    {
 | 
			
		||||
        if (currentlyFocusedPeer != nullptr)
 | 
			
		||||
        {
 | 
			
		||||
@@ -541,10 +520,10 @@ public:
 | 
			
		||||
        result = buttonIndex;
 | 
			
		||||
 | 
			
		||||
        if (callback != nullptr)
 | 
			
		||||
        {
 | 
			
		||||
            callback->modalStateFinished (result);
 | 
			
		||||
 | 
			
		||||
        if (shouldDeleteThis)
 | 
			
		||||
            delete this;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
private:
 | 
			
		||||
@@ -562,6 +541,7 @@ private:
 | 
			
		||||
 | 
			
		||||
    int result = -1;
 | 
			
		||||
    std::unique_ptr<ModalComponentManager::Callback> callback;
 | 
			
		||||
    const bool shouldDeleteThis;
 | 
			
		||||
 | 
			
		||||
    JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (iOSMessageBox)
 | 
			
		||||
};
 | 
			
		||||
@@ -578,13 +558,24 @@ static int showDialog (const MessageBoxOptions& options,
 | 
			
		||||
        {
 | 
			
		||||
            jassert (mapFn != nullptr);
 | 
			
		||||
 | 
			
		||||
            iOSMessageBox messageBox (options, nullptr);
 | 
			
		||||
            iOSMessageBox messageBox (options, nullptr, false);
 | 
			
		||||
            return mapFn (messageBox.getResult());
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
   #endif
 | 
			
		||||
 | 
			
		||||
    new iOSMessageBox (options, AlertWindowMappings::getWrappedCallback (callbackIn, mapFn));
 | 
			
		||||
    const auto showBox = [options, callbackIn, mapFn]
 | 
			
		||||
    {
 | 
			
		||||
        new iOSMessageBox (options,
 | 
			
		||||
                           AlertWindowMappings::getWrappedCallback (callbackIn, mapFn),
 | 
			
		||||
                           true);
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    if (MessageManager::getInstance()->isThisTheMessageThread())
 | 
			
		||||
        showBox();
 | 
			
		||||
    else
 | 
			
		||||
        MessageManager::callAsync (showBox);
 | 
			
		||||
 | 
			
		||||
    return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@@ -719,11 +710,7 @@ void SystemClipboard::copyTextToClipboard (const String& text)
 | 
			
		||||
 | 
			
		||||
String SystemClipboard::getTextFromClipboard()
 | 
			
		||||
{
 | 
			
		||||
    id value = [[UIPasteboard generalPasteboard] valueForPasteboardType: @"public.text"];
 | 
			
		||||
    if ([value isKindOfClass:[NSString class]]) {
 | 
			
		||||
        return nsStringToJuce (value);
 | 
			
		||||
    }
 | 
			
		||||
    return {};
 | 
			
		||||
    return nsStringToJuce ([[UIPasteboard generalPasteboard] string]);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
//==============================================================================
 | 
			
		||||
@@ -745,42 +732,24 @@ bool Desktop::canUseSemiTransparentWindows() noexcept
 | 
			
		||||
 | 
			
		||||
bool Desktop::isDarkModeActive() const
 | 
			
		||||
{
 | 
			
		||||
   #if defined (__IPHONE_12_0) && __IPHONE_OS_VERSION_MAX_ALLOWED >= __IPHONE_12_0
 | 
			
		||||
    if (@available (iOS 12.0, *))
 | 
			
		||||
        return [[[UIScreen mainScreen] traitCollection] userInterfaceStyle] == UIUserInterfaceStyleDark;
 | 
			
		||||
   #endif
 | 
			
		||||
 | 
			
		||||
    return false;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
JUCE_BEGIN_IGNORE_WARNINGS_GCC_LIKE ("-Wundeclared-selector")
 | 
			
		||||
static const auto darkModeSelector = @selector (darkModeChanged:);
 | 
			
		||||
JUCE_END_IGNORE_WARNINGS_GCC_LIKE
 | 
			
		||||
 | 
			
		||||
class Desktop::NativeDarkModeChangeDetectorImpl
 | 
			
		||||
{
 | 
			
		||||
public:
 | 
			
		||||
    NativeDarkModeChangeDetectorImpl()
 | 
			
		||||
    {
 | 
			
		||||
        static DelegateClass delegateClass;
 | 
			
		||||
 | 
			
		||||
        delegate = [delegateClass.createInstance() init];
 | 
			
		||||
        object_setInstanceVariable (delegate, "owner", this);
 | 
			
		||||
 | 
			
		||||
        JUCE_BEGIN_IGNORE_WARNINGS_GCC_LIKE ("-Wundeclared-selector")
 | 
			
		||||
        [[NSNotificationCenter defaultCenter] addObserver: delegate
 | 
			
		||||
                                                 selector: @selector (darkModeChanged:)
 | 
			
		||||
                                                     name: UIViewComponentPeer::getDarkModeNotificationName()
 | 
			
		||||
                                                   object: nil];
 | 
			
		||||
        JUCE_END_IGNORE_WARNINGS_GCC_LIKE
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    ~NativeDarkModeChangeDetectorImpl()
 | 
			
		||||
    {
 | 
			
		||||
        object_setInstanceVariable (delegate, "owner", nullptr);
 | 
			
		||||
        [[NSNotificationCenter defaultCenter] removeObserver: delegate];
 | 
			
		||||
        [delegate release];
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    void darkModeChanged()
 | 
			
		||||
    {
 | 
			
		||||
        Desktop::getInstance().darkModeChanged();
 | 
			
		||||
        delegate.reset ([delegateClass.createInstance() init]);
 | 
			
		||||
        observer.emplace (delegate.get(), darkModeSelector, UIViewComponentPeer::getDarkModeNotificationName(), nil);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
private:
 | 
			
		||||
@@ -788,23 +757,13 @@ private:
 | 
			
		||||
    {
 | 
			
		||||
        DelegateClass()  : ObjCClass<NSObject> ("JUCEDelegate_")
 | 
			
		||||
        {
 | 
			
		||||
            addIvar<NativeDarkModeChangeDetectorImpl*> ("owner");
 | 
			
		||||
 | 
			
		||||
            JUCE_BEGIN_IGNORE_WARNINGS_GCC_LIKE ("-Wundeclared-selector")
 | 
			
		||||
            addMethod (@selector (darkModeChanged:), darkModeChanged, "v@:@");
 | 
			
		||||
            JUCE_END_IGNORE_WARNINGS_GCC_LIKE
 | 
			
		||||
 | 
			
		||||
            addMethod (darkModeSelector, [] (id, SEL, NSNotification*) { Desktop::getInstance().darkModeChanged(); });
 | 
			
		||||
            registerClass();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        static void darkModeChanged (id self, SEL, NSNotification*)
 | 
			
		||||
        {
 | 
			
		||||
            if (auto* owner = getIvar<NativeDarkModeChangeDetectorImpl*> (self, "owner"))
 | 
			
		||||
                owner->darkModeChanged();
 | 
			
		||||
        }
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    id delegate = nil;
 | 
			
		||||
    NSUniquePtr<NSObject> delegate;
 | 
			
		||||
    Optional<ScopedNotificationCenterObserver> observer;
 | 
			
		||||
 | 
			
		||||
    JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (NativeDarkModeChangeDetectorImpl)
 | 
			
		||||
};
 | 
			
		||||
@@ -814,6 +773,7 @@ std::unique_ptr<Desktop::NativeDarkModeChangeDetectorImpl> Desktop::createNative
 | 
			
		||||
    return std::make_unique<NativeDarkModeChangeDetectorImpl>();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
//==============================================================================
 | 
			
		||||
Point<float> MouseInputSource::getCurrentRawMousePosition()
 | 
			
		||||
{
 | 
			
		||||
    return juce_lastMousePos;
 | 
			
		||||
@@ -836,6 +796,24 @@ Desktop::DisplayOrientation Desktop::getCurrentOrientation() const
 | 
			
		||||
    return Orientations::convertToJuce (orientation);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
template <typename Value>
 | 
			
		||||
static BorderSize<Value> operator/ (BorderSize<Value> border, Value scale)
 | 
			
		||||
{
 | 
			
		||||
    return { border.getTop()    / scale,
 | 
			
		||||
             border.getLeft()   / scale,
 | 
			
		||||
             border.getBottom() / scale,
 | 
			
		||||
             border.getRight()  / scale };
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
template <typename Value>
 | 
			
		||||
static BorderSize<int> roundToInt (BorderSize<Value> border)
 | 
			
		||||
{
 | 
			
		||||
    return { roundToInt (border.getTop()),
 | 
			
		||||
             roundToInt (border.getLeft()),
 | 
			
		||||
             roundToInt (border.getBottom()),
 | 
			
		||||
             roundToInt (border.getRight()) };
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// The most straightforward way of retrieving the screen area available to an iOS app
 | 
			
		||||
// seems to be to create a new window (which will take up all available space) and to
 | 
			
		||||
// query its frame.
 | 
			
		||||
@@ -852,34 +830,120 @@ static Rectangle<int> getRecommendedWindowBounds()
 | 
			
		||||
 | 
			
		||||
static BorderSize<int> getSafeAreaInsets (float masterScale)
 | 
			
		||||
{
 | 
			
		||||
   #if defined (__IPHONE_11_0)
 | 
			
		||||
    if (@available (iOS 11.0, *))
 | 
			
		||||
    {
 | 
			
		||||
        UIEdgeInsets safeInsets = TemporaryWindow().window.safeAreaInsets;
 | 
			
		||||
 | 
			
		||||
        auto getInset = [&] (CGFloat original) { return roundToInt (original / masterScale); };
 | 
			
		||||
 | 
			
		||||
        return { getInset (safeInsets.top),    getInset (safeInsets.left),
 | 
			
		||||
                 getInset (safeInsets.bottom), getInset (safeInsets.right) };
 | 
			
		||||
        return roundToInt (BorderSize<double> { safeInsets.top,
 | 
			
		||||
                                                safeInsets.left,
 | 
			
		||||
                                                safeInsets.bottom,
 | 
			
		||||
                                                safeInsets.right } / (double) masterScale);
 | 
			
		||||
    }
 | 
			
		||||
   #endif
 | 
			
		||||
 | 
			
		||||
    JUCE_BEGIN_IGNORE_WARNINGS_GCC_LIKE ("-Wdeprecated-declarations")
 | 
			
		||||
    auto statusBarSize = [UIApplication sharedApplication].statusBarFrame.size;
 | 
			
		||||
    JUCE_END_IGNORE_WARNINGS_GCC_LIKE
 | 
			
		||||
 | 
			
		||||
    auto statusBarHeight = jmin (statusBarSize.width, statusBarSize.height);
 | 
			
		||||
 | 
			
		||||
    return { roundToInt (statusBarHeight / masterScale), 0, 0, 0 };
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
//==============================================================================
 | 
			
		||||
void Displays::findDisplays (float masterScale)
 | 
			
		||||
{
 | 
			
		||||
    JUCE_BEGIN_IGNORE_WARNINGS_GCC_LIKE ("-Wundeclared-selector")
 | 
			
		||||
    static const auto keyboardShownSelector = @selector (keyboardShown:);
 | 
			
		||||
    static const auto keyboardHiddenSelector = @selector (keyboardHidden:);
 | 
			
		||||
    JUCE_END_IGNORE_WARNINGS_GCC_LIKE
 | 
			
		||||
 | 
			
		||||
    class OnScreenKeyboardChangeDetectorImpl
 | 
			
		||||
    {
 | 
			
		||||
    public:
 | 
			
		||||
        OnScreenKeyboardChangeDetectorImpl()
 | 
			
		||||
        {
 | 
			
		||||
            static DelegateClass delegateClass;
 | 
			
		||||
            delegate.reset ([delegateClass.createInstance() init]);
 | 
			
		||||
            object_setInstanceVariable (delegate.get(), "owner", this);
 | 
			
		||||
            observers.emplace_back (delegate.get(), keyboardShownSelector,  UIKeyboardDidShowNotification, nil);
 | 
			
		||||
            observers.emplace_back (delegate.get(), keyboardHiddenSelector, UIKeyboardDidHideNotification, nil);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        auto getInsets() const { return insets; }
 | 
			
		||||
 | 
			
		||||
    private:
 | 
			
		||||
        struct DelegateClass : public ObjCClass<NSObject>
 | 
			
		||||
        {
 | 
			
		||||
            DelegateClass() : ObjCClass<NSObject> ("JUCEOnScreenKeyboardObserver_")
 | 
			
		||||
            {
 | 
			
		||||
                addIvar<OnScreenKeyboardChangeDetectorImpl*> ("owner");
 | 
			
		||||
 | 
			
		||||
                addMethod (keyboardShownSelector, [] (id self, SEL, NSNotification* notification)
 | 
			
		||||
                {
 | 
			
		||||
                    setKeyboardScreenBounds (self, [&]() -> BorderSize<double>
 | 
			
		||||
                    {
 | 
			
		||||
                        auto* info = [notification userInfo];
 | 
			
		||||
 | 
			
		||||
                        if (info == nullptr)
 | 
			
		||||
                            return {};
 | 
			
		||||
 | 
			
		||||
                        auto* value = static_cast<NSValue*> ([info objectForKey: UIKeyboardFrameEndUserInfoKey]);
 | 
			
		||||
 | 
			
		||||
                        if (value == nullptr)
 | 
			
		||||
                            return {};
 | 
			
		||||
 | 
			
		||||
                        auto* display = getPrimaryDisplayImpl (Desktop::getInstance().getDisplays());
 | 
			
		||||
 | 
			
		||||
                        if (display == nullptr)
 | 
			
		||||
                            return {};
 | 
			
		||||
 | 
			
		||||
                        const auto rect = convertToRectInt ([value CGRectValue]);
 | 
			
		||||
 | 
			
		||||
                        BorderSize<double> result;
 | 
			
		||||
 | 
			
		||||
                        if (rect.getY() == display->totalArea.getY())
 | 
			
		||||
                            result.setTop (rect.getHeight());
 | 
			
		||||
 | 
			
		||||
                        if (rect.getBottom() == display->totalArea.getBottom())
 | 
			
		||||
                            result.setBottom (rect.getHeight());
 | 
			
		||||
 | 
			
		||||
                        return result;
 | 
			
		||||
                    }());
 | 
			
		||||
                });
 | 
			
		||||
 | 
			
		||||
                addMethod (keyboardHiddenSelector, [] (id self, SEL, NSNotification*)
 | 
			
		||||
                {
 | 
			
		||||
                    setKeyboardScreenBounds (self, {});
 | 
			
		||||
                });
 | 
			
		||||
 | 
			
		||||
                registerClass();
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
        private:
 | 
			
		||||
            static void setKeyboardScreenBounds (id self, BorderSize<double> insets)
 | 
			
		||||
            {
 | 
			
		||||
                if (std::exchange (getIvar<OnScreenKeyboardChangeDetectorImpl*> (self, "owner")->insets, insets) != insets)
 | 
			
		||||
                    Desktop::getInstance().displays->refresh();
 | 
			
		||||
            }
 | 
			
		||||
        };
 | 
			
		||||
 | 
			
		||||
        BorderSize<double> insets;
 | 
			
		||||
        NSUniquePtr<NSObject> delegate;
 | 
			
		||||
        std::vector<ScopedNotificationCenterObserver> observers;
 | 
			
		||||
 | 
			
		||||
        JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (OnScreenKeyboardChangeDetectorImpl)
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    JUCE_AUTORELEASEPOOL
 | 
			
		||||
    {
 | 
			
		||||
        static OnScreenKeyboardChangeDetectorImpl keyboardChangeDetector;
 | 
			
		||||
 | 
			
		||||
        UIScreen* s = [UIScreen mainScreen];
 | 
			
		||||
 | 
			
		||||
        Display d;
 | 
			
		||||
        d.totalArea = convertToRectInt ([s bounds]) / masterScale;
 | 
			
		||||
        d.userArea = getRecommendedWindowBounds() / masterScale;
 | 
			
		||||
        d.safeAreaInsets = getSafeAreaInsets (masterScale);
 | 
			
		||||
        d.keyboardInsets = roundToInt (keyboardChangeDetector.getInsets() / (double) masterScale);
 | 
			
		||||
        d.isMain = true;
 | 
			
		||||
        d.scale = masterScale * s.scale;
 | 
			
		||||
        d.dpi = 160 * d.scale;
 | 
			
		||||
 
 | 
			
		||||
@@ -1,274 +1,274 @@
 | 
			
		||||
/*
 | 
			
		||||
  ==============================================================================
 | 
			
		||||
 | 
			
		||||
   This file is part of the JUCE library.
 | 
			
		||||
   Copyright (c) 2020 - Raw Material Software Limited
 | 
			
		||||
 | 
			
		||||
   JUCE is an open source library subject to commercial or open-source
 | 
			
		||||
   licensing.
 | 
			
		||||
 | 
			
		||||
   By using JUCE, you agree to the terms of both the JUCE 6 End-User License
 | 
			
		||||
   Agreement and JUCE Privacy Policy (both effective as of the 16th June 2020).
 | 
			
		||||
 | 
			
		||||
   End User License Agreement: www.juce.com/juce-6-licence
 | 
			
		||||
   Privacy Policy: www.juce.com/juce-privacy-policy
 | 
			
		||||
 | 
			
		||||
   Or: You may also use this code under the terms of the GPL v3 (see
 | 
			
		||||
   www.gnu.org/licenses).
 | 
			
		||||
 | 
			
		||||
   JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
 | 
			
		||||
   EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
 | 
			
		||||
   DISCLAIMED.
 | 
			
		||||
 | 
			
		||||
  ==============================================================================
 | 
			
		||||
*/
 | 
			
		||||
 | 
			
		||||
namespace juce
 | 
			
		||||
{
 | 
			
		||||
 | 
			
		||||
static bool exeIsAvailable (String executable)
 | 
			
		||||
{
 | 
			
		||||
    ChildProcess child;
 | 
			
		||||
 | 
			
		||||
    if (child.start ("which " + executable))
 | 
			
		||||
    {
 | 
			
		||||
        child.waitForProcessToFinish (60 * 1000);
 | 
			
		||||
        return (child.getExitCode() == 0);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    return false;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static bool isSet (int flags, int toCheck)
 | 
			
		||||
{
 | 
			
		||||
    return (flags & toCheck) != 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
class FileChooser::Native    : public FileChooser::Pimpl,
 | 
			
		||||
                               private Timer
 | 
			
		||||
{
 | 
			
		||||
public:
 | 
			
		||||
    Native (FileChooser& fileChooser, int flags)
 | 
			
		||||
        : owner (fileChooser),
 | 
			
		||||
          // kdialog/zenity only support opening either files or directories.
 | 
			
		||||
          // Files should take precedence, if requested.
 | 
			
		||||
          isDirectory         (isSet (flags, FileBrowserComponent::canSelectDirectories) && ! isSet (flags, FileBrowserComponent::canSelectFiles)),
 | 
			
		||||
          isSave              (isSet (flags, FileBrowserComponent::saveMode)),
 | 
			
		||||
          selectMultipleFiles (isSet (flags, FileBrowserComponent::canSelectMultipleItems)),
 | 
			
		||||
          warnAboutOverwrite  (isSet (flags, FileBrowserComponent::warnAboutOverwriting))
 | 
			
		||||
    {
 | 
			
		||||
        const File previousWorkingDirectory (File::getCurrentWorkingDirectory());
 | 
			
		||||
 | 
			
		||||
        // use kdialog for KDE sessions or if zenity is missing
 | 
			
		||||
        if (exeIsAvailable ("kdialog") && (isKdeFullSession() || ! exeIsAvailable ("zenity")))
 | 
			
		||||
            addKDialogArgs();
 | 
			
		||||
        else
 | 
			
		||||
            addZenityArgs();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    ~Native() override
 | 
			
		||||
    {
 | 
			
		||||
        finish (true);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    void runModally() override
 | 
			
		||||
    {
 | 
			
		||||
       #if JUCE_MODAL_LOOPS_PERMITTED
 | 
			
		||||
        child.start (args, ChildProcess::wantStdOut);
 | 
			
		||||
 | 
			
		||||
        while (child.isRunning())
 | 
			
		||||
            if (! MessageManager::getInstance()->runDispatchLoopUntil (20))
 | 
			
		||||
                break;
 | 
			
		||||
 | 
			
		||||
        finish (false);
 | 
			
		||||
       #else
 | 
			
		||||
        jassertfalse;
 | 
			
		||||
       #endif
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    void launch() override
 | 
			
		||||
    {
 | 
			
		||||
        child.start (args, ChildProcess::wantStdOut);
 | 
			
		||||
        startTimer (100);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
private:
 | 
			
		||||
    FileChooser& owner;
 | 
			
		||||
    bool isDirectory, isSave, selectMultipleFiles, warnAboutOverwrite;
 | 
			
		||||
 | 
			
		||||
    ChildProcess child;
 | 
			
		||||
    StringArray args;
 | 
			
		||||
    String separator;
 | 
			
		||||
 | 
			
		||||
    void timerCallback() override
 | 
			
		||||
    {
 | 
			
		||||
        if (! child.isRunning())
 | 
			
		||||
        {
 | 
			
		||||
            stopTimer();
 | 
			
		||||
            finish (false);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    void finish (bool shouldKill)
 | 
			
		||||
    {
 | 
			
		||||
        String result;
 | 
			
		||||
        Array<URL> selection;
 | 
			
		||||
 | 
			
		||||
        if (shouldKill)
 | 
			
		||||
            child.kill();
 | 
			
		||||
        else
 | 
			
		||||
            result = child.readAllProcessOutput().trim();
 | 
			
		||||
 | 
			
		||||
        if (result.isNotEmpty())
 | 
			
		||||
        {
 | 
			
		||||
            StringArray tokens;
 | 
			
		||||
 | 
			
		||||
            if (selectMultipleFiles)
 | 
			
		||||
                tokens.addTokens (result, separator, "\"");
 | 
			
		||||
            else
 | 
			
		||||
                tokens.add (result);
 | 
			
		||||
 | 
			
		||||
            for (auto& token : tokens)
 | 
			
		||||
                selection.add (URL (File::getCurrentWorkingDirectory().getChildFile (token)));
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        if (! shouldKill)
 | 
			
		||||
        {
 | 
			
		||||
            child.waitForProcessToFinish (60 * 1000);
 | 
			
		||||
            owner.finished (selection);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    static uint64 getTopWindowID() noexcept
 | 
			
		||||
    {
 | 
			
		||||
        if (TopLevelWindow* top = TopLevelWindow::getActiveTopLevelWindow())
 | 
			
		||||
            return (uint64) (pointer_sized_uint) top->getWindowHandle();
 | 
			
		||||
 | 
			
		||||
        return 0;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    static bool isKdeFullSession()
 | 
			
		||||
    {
 | 
			
		||||
        return SystemStats::getEnvironmentVariable ("KDE_FULL_SESSION", String())
 | 
			
		||||
                     .equalsIgnoreCase ("true");
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    void addKDialogArgs()
 | 
			
		||||
    {
 | 
			
		||||
        args.add ("kdialog");
 | 
			
		||||
 | 
			
		||||
        if (owner.title.isNotEmpty())
 | 
			
		||||
            args.add ("--title=" + owner.title);
 | 
			
		||||
 | 
			
		||||
        if (uint64 topWindowID = getTopWindowID())
 | 
			
		||||
        {
 | 
			
		||||
            args.add ("--attach");
 | 
			
		||||
            args.add (String (topWindowID));
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        if (selectMultipleFiles)
 | 
			
		||||
        {
 | 
			
		||||
            separator = "\n";
 | 
			
		||||
            args.add ("--multiple");
 | 
			
		||||
            args.add ("--separate-output");
 | 
			
		||||
            args.add ("--getopenfilename");
 | 
			
		||||
        }
 | 
			
		||||
        else
 | 
			
		||||
        {
 | 
			
		||||
            if (isSave)             args.add ("--getsavefilename");
 | 
			
		||||
            else if (isDirectory)   args.add ("--getexistingdirectory");
 | 
			
		||||
            else                    args.add ("--getopenfilename");
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        File startPath;
 | 
			
		||||
 | 
			
		||||
        if (owner.startingFile.exists())
 | 
			
		||||
        {
 | 
			
		||||
            startPath = owner.startingFile;
 | 
			
		||||
        }
 | 
			
		||||
        else if (owner.startingFile.getParentDirectory().exists())
 | 
			
		||||
        {
 | 
			
		||||
            startPath = owner.startingFile.getParentDirectory();
 | 
			
		||||
        }
 | 
			
		||||
        else
 | 
			
		||||
        {
 | 
			
		||||
            startPath = File::getSpecialLocation (File::userHomeDirectory);
 | 
			
		||||
 | 
			
		||||
            if (isSave)
 | 
			
		||||
                startPath = startPath.getChildFile (owner.startingFile.getFileName());
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        args.add (startPath.getFullPathName());
 | 
			
		||||
        args.add ("(" + owner.filters.replaceCharacter (';', ' ') + ")");
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    void addZenityArgs()
 | 
			
		||||
    {
 | 
			
		||||
        args.add ("zenity");
 | 
			
		||||
        args.add ("--file-selection");
 | 
			
		||||
 | 
			
		||||
        if (warnAboutOverwrite)
 | 
			
		||||
            args.add("--confirm-overwrite");
 | 
			
		||||
 | 
			
		||||
        if (owner.title.isNotEmpty())
 | 
			
		||||
            args.add ("--title=" + owner.title);
 | 
			
		||||
 | 
			
		||||
        if (selectMultipleFiles)
 | 
			
		||||
        {
 | 
			
		||||
            separator = ":";
 | 
			
		||||
            args.add ("--multiple");
 | 
			
		||||
            args.add ("--separator=" + separator);
 | 
			
		||||
        }
 | 
			
		||||
        else
 | 
			
		||||
        {
 | 
			
		||||
            if (isSave)
 | 
			
		||||
                args.add ("--save");
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        if (isDirectory)
 | 
			
		||||
            args.add ("--directory");
 | 
			
		||||
 | 
			
		||||
        if (owner.filters.isNotEmpty() && owner.filters != "*" && owner.filters != "*.*")
 | 
			
		||||
        {
 | 
			
		||||
            StringArray tokens;
 | 
			
		||||
            tokens.addTokens (owner.filters, ";,|", "\"");
 | 
			
		||||
 | 
			
		||||
            args.add ("--file-filter=" + tokens.joinIntoString (" "));
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        if (owner.startingFile.isDirectory())
 | 
			
		||||
            owner.startingFile.setAsCurrentWorkingDirectory();
 | 
			
		||||
        else if (owner.startingFile.getParentDirectory().exists())
 | 
			
		||||
            owner.startingFile.getParentDirectory().setAsCurrentWorkingDirectory();
 | 
			
		||||
        else
 | 
			
		||||
            File::getSpecialLocation (File::userHomeDirectory).setAsCurrentWorkingDirectory();
 | 
			
		||||
 | 
			
		||||
        auto filename = owner.startingFile.getFileName();
 | 
			
		||||
 | 
			
		||||
        if (! filename.isEmpty())
 | 
			
		||||
            args.add ("--filename=" + filename);
 | 
			
		||||
 | 
			
		||||
        // supplying the window ID of the topmost window makes sure that Zenity pops up..
 | 
			
		||||
        if (uint64 topWindowID = getTopWindowID())
 | 
			
		||||
            setenv ("WINDOWID", String (topWindowID).toRawUTF8(), true);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (Native)
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
bool FileChooser::isPlatformDialogAvailable()
 | 
			
		||||
{
 | 
			
		||||
   #if JUCE_DISABLE_NATIVE_FILECHOOSERS
 | 
			
		||||
    return false;
 | 
			
		||||
   #else
 | 
			
		||||
    static bool canUseNativeBox = exeIsAvailable ("zenity") || exeIsAvailable ("kdialog");
 | 
			
		||||
    return canUseNativeBox;
 | 
			
		||||
   #endif
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
std::shared_ptr<FileChooser::Pimpl> FileChooser::showPlatformDialog (FileChooser& owner, int flags, FilePreviewComponent*)
 | 
			
		||||
{
 | 
			
		||||
    return std::make_shared<Native> (owner, flags);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
} // namespace juce
 | 
			
		||||
/*
 | 
			
		||||
  ==============================================================================
 | 
			
		||||
 | 
			
		||||
   This file is part of the JUCE library.
 | 
			
		||||
   Copyright (c) 2022 - Raw Material Software Limited
 | 
			
		||||
 | 
			
		||||
   JUCE is an open source library subject to commercial or open-source
 | 
			
		||||
   licensing.
 | 
			
		||||
 | 
			
		||||
   By using JUCE, you agree to the terms of both the JUCE 7 End-User License
 | 
			
		||||
   Agreement and JUCE Privacy Policy.
 | 
			
		||||
 | 
			
		||||
   End User License Agreement: www.juce.com/juce-7-licence
 | 
			
		||||
   Privacy Policy: www.juce.com/juce-privacy-policy
 | 
			
		||||
 | 
			
		||||
   Or: You may also use this code under the terms of the GPL v3 (see
 | 
			
		||||
   www.gnu.org/licenses).
 | 
			
		||||
 | 
			
		||||
   JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
 | 
			
		||||
   EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
 | 
			
		||||
   DISCLAIMED.
 | 
			
		||||
 | 
			
		||||
  ==============================================================================
 | 
			
		||||
*/
 | 
			
		||||
 | 
			
		||||
namespace juce
 | 
			
		||||
{
 | 
			
		||||
 | 
			
		||||
static bool exeIsAvailable (String executable)
 | 
			
		||||
{
 | 
			
		||||
    ChildProcess child;
 | 
			
		||||
 | 
			
		||||
    if (child.start ("which " + executable))
 | 
			
		||||
    {
 | 
			
		||||
        child.waitForProcessToFinish (60 * 1000);
 | 
			
		||||
        return (child.getExitCode() == 0);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    return false;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static bool isSet (int flags, int toCheck)
 | 
			
		||||
{
 | 
			
		||||
    return (flags & toCheck) != 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
class FileChooser::Native    : public FileChooser::Pimpl,
 | 
			
		||||
                               private Timer
 | 
			
		||||
{
 | 
			
		||||
public:
 | 
			
		||||
    Native (FileChooser& fileChooser, int flags)
 | 
			
		||||
        : owner (fileChooser),
 | 
			
		||||
          // kdialog/zenity only support opening either files or directories.
 | 
			
		||||
          // Files should take precedence, if requested.
 | 
			
		||||
          isDirectory         (isSet (flags, FileBrowserComponent::canSelectDirectories) && ! isSet (flags, FileBrowserComponent::canSelectFiles)),
 | 
			
		||||
          isSave              (isSet (flags, FileBrowserComponent::saveMode)),
 | 
			
		||||
          selectMultipleFiles (isSet (flags, FileBrowserComponent::canSelectMultipleItems)),
 | 
			
		||||
          warnAboutOverwrite  (isSet (flags, FileBrowserComponent::warnAboutOverwriting))
 | 
			
		||||
    {
 | 
			
		||||
        const File previousWorkingDirectory (File::getCurrentWorkingDirectory());
 | 
			
		||||
 | 
			
		||||
        // use kdialog for KDE sessions or if zenity is missing
 | 
			
		||||
        if (exeIsAvailable ("kdialog") && (isKdeFullSession() || ! exeIsAvailable ("zenity")))
 | 
			
		||||
            addKDialogArgs();
 | 
			
		||||
        else
 | 
			
		||||
            addZenityArgs();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    ~Native() override
 | 
			
		||||
    {
 | 
			
		||||
        finish (true);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    void runModally() override
 | 
			
		||||
    {
 | 
			
		||||
       #if JUCE_MODAL_LOOPS_PERMITTED
 | 
			
		||||
        child.start (args, ChildProcess::wantStdOut);
 | 
			
		||||
 | 
			
		||||
        while (child.isRunning())
 | 
			
		||||
            if (! MessageManager::getInstance()->runDispatchLoopUntil (20))
 | 
			
		||||
                break;
 | 
			
		||||
 | 
			
		||||
        finish (false);
 | 
			
		||||
       #else
 | 
			
		||||
        jassertfalse;
 | 
			
		||||
       #endif
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    void launch() override
 | 
			
		||||
    {
 | 
			
		||||
        child.start (args, ChildProcess::wantStdOut);
 | 
			
		||||
        startTimer (100);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
private:
 | 
			
		||||
    FileChooser& owner;
 | 
			
		||||
    bool isDirectory, isSave, selectMultipleFiles, warnAboutOverwrite;
 | 
			
		||||
 | 
			
		||||
    ChildProcess child;
 | 
			
		||||
    StringArray args;
 | 
			
		||||
    String separator;
 | 
			
		||||
 | 
			
		||||
    void timerCallback() override
 | 
			
		||||
    {
 | 
			
		||||
        if (! child.isRunning())
 | 
			
		||||
        {
 | 
			
		||||
            stopTimer();
 | 
			
		||||
            finish (false);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    void finish (bool shouldKill)
 | 
			
		||||
    {
 | 
			
		||||
        String result;
 | 
			
		||||
        Array<URL> selection;
 | 
			
		||||
 | 
			
		||||
        if (shouldKill)
 | 
			
		||||
            child.kill();
 | 
			
		||||
        else
 | 
			
		||||
            result = child.readAllProcessOutput().trim();
 | 
			
		||||
 | 
			
		||||
        if (result.isNotEmpty())
 | 
			
		||||
        {
 | 
			
		||||
            StringArray tokens;
 | 
			
		||||
 | 
			
		||||
            if (selectMultipleFiles)
 | 
			
		||||
                tokens.addTokens (result, separator, "\"");
 | 
			
		||||
            else
 | 
			
		||||
                tokens.add (result);
 | 
			
		||||
 | 
			
		||||
            for (auto& token : tokens)
 | 
			
		||||
                selection.add (URL (File::getCurrentWorkingDirectory().getChildFile (token)));
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        if (! shouldKill)
 | 
			
		||||
        {
 | 
			
		||||
            child.waitForProcessToFinish (60 * 1000);
 | 
			
		||||
            owner.finished (selection);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    static uint64 getTopWindowID() noexcept
 | 
			
		||||
    {
 | 
			
		||||
        if (TopLevelWindow* top = TopLevelWindow::getActiveTopLevelWindow())
 | 
			
		||||
            return (uint64) (pointer_sized_uint) top->getWindowHandle();
 | 
			
		||||
 | 
			
		||||
        return 0;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    static bool isKdeFullSession()
 | 
			
		||||
    {
 | 
			
		||||
        return SystemStats::getEnvironmentVariable ("KDE_FULL_SESSION", String())
 | 
			
		||||
                     .equalsIgnoreCase ("true");
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    void addKDialogArgs()
 | 
			
		||||
    {
 | 
			
		||||
        args.add ("kdialog");
 | 
			
		||||
 | 
			
		||||
        if (owner.title.isNotEmpty())
 | 
			
		||||
            args.add ("--title=" + owner.title);
 | 
			
		||||
 | 
			
		||||
        if (uint64 topWindowID = getTopWindowID())
 | 
			
		||||
        {
 | 
			
		||||
            args.add ("--attach");
 | 
			
		||||
            args.add (String (topWindowID));
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        if (selectMultipleFiles)
 | 
			
		||||
        {
 | 
			
		||||
            separator = "\n";
 | 
			
		||||
            args.add ("--multiple");
 | 
			
		||||
            args.add ("--separate-output");
 | 
			
		||||
            args.add ("--getopenfilename");
 | 
			
		||||
        }
 | 
			
		||||
        else
 | 
			
		||||
        {
 | 
			
		||||
            if (isSave)             args.add ("--getsavefilename");
 | 
			
		||||
            else if (isDirectory)   args.add ("--getexistingdirectory");
 | 
			
		||||
            else                    args.add ("--getopenfilename");
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        File startPath;
 | 
			
		||||
 | 
			
		||||
        if (owner.startingFile.exists())
 | 
			
		||||
        {
 | 
			
		||||
            startPath = owner.startingFile;
 | 
			
		||||
        }
 | 
			
		||||
        else if (owner.startingFile.getParentDirectory().exists())
 | 
			
		||||
        {
 | 
			
		||||
            startPath = owner.startingFile.getParentDirectory();
 | 
			
		||||
        }
 | 
			
		||||
        else
 | 
			
		||||
        {
 | 
			
		||||
            startPath = File::getSpecialLocation (File::userHomeDirectory);
 | 
			
		||||
 | 
			
		||||
            if (isSave)
 | 
			
		||||
                startPath = startPath.getChildFile (owner.startingFile.getFileName());
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        args.add (startPath.getFullPathName());
 | 
			
		||||
        args.add ("(" + owner.filters.replaceCharacter (';', ' ') + ")");
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    void addZenityArgs()
 | 
			
		||||
    {
 | 
			
		||||
        args.add ("zenity");
 | 
			
		||||
        args.add ("--file-selection");
 | 
			
		||||
 | 
			
		||||
        if (warnAboutOverwrite)
 | 
			
		||||
            args.add("--confirm-overwrite");
 | 
			
		||||
 | 
			
		||||
        if (owner.title.isNotEmpty())
 | 
			
		||||
            args.add ("--title=" + owner.title);
 | 
			
		||||
 | 
			
		||||
        if (selectMultipleFiles)
 | 
			
		||||
        {
 | 
			
		||||
            separator = ":";
 | 
			
		||||
            args.add ("--multiple");
 | 
			
		||||
            args.add ("--separator=" + separator);
 | 
			
		||||
        }
 | 
			
		||||
        else
 | 
			
		||||
        {
 | 
			
		||||
            if (isSave)
 | 
			
		||||
                args.add ("--save");
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        if (isDirectory)
 | 
			
		||||
            args.add ("--directory");
 | 
			
		||||
 | 
			
		||||
        if (owner.filters.isNotEmpty() && owner.filters != "*" && owner.filters != "*.*")
 | 
			
		||||
        {
 | 
			
		||||
            StringArray tokens;
 | 
			
		||||
            tokens.addTokens (owner.filters, ";,|", "\"");
 | 
			
		||||
 | 
			
		||||
            args.add ("--file-filter=" + tokens.joinIntoString (" "));
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        if (owner.startingFile.isDirectory())
 | 
			
		||||
            owner.startingFile.setAsCurrentWorkingDirectory();
 | 
			
		||||
        else if (owner.startingFile.getParentDirectory().exists())
 | 
			
		||||
            owner.startingFile.getParentDirectory().setAsCurrentWorkingDirectory();
 | 
			
		||||
        else
 | 
			
		||||
            File::getSpecialLocation (File::userHomeDirectory).setAsCurrentWorkingDirectory();
 | 
			
		||||
 | 
			
		||||
        auto filename = owner.startingFile.getFileName();
 | 
			
		||||
 | 
			
		||||
        if (! filename.isEmpty())
 | 
			
		||||
            args.add ("--filename=" + filename);
 | 
			
		||||
 | 
			
		||||
        // supplying the window ID of the topmost window makes sure that Zenity pops up..
 | 
			
		||||
        if (uint64 topWindowID = getTopWindowID())
 | 
			
		||||
            setenv ("WINDOWID", String (topWindowID).toRawUTF8(), true);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (Native)
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
bool FileChooser::isPlatformDialogAvailable()
 | 
			
		||||
{
 | 
			
		||||
   #if JUCE_DISABLE_NATIVE_FILECHOOSERS
 | 
			
		||||
    return false;
 | 
			
		||||
   #else
 | 
			
		||||
    static bool canUseNativeBox = exeIsAvailable ("zenity") || exeIsAvailable ("kdialog");
 | 
			
		||||
    return canUseNativeBox;
 | 
			
		||||
   #endif
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
std::shared_ptr<FileChooser::Pimpl> FileChooser::showPlatformDialog (FileChooser& owner, int flags, FilePreviewComponent*)
 | 
			
		||||
{
 | 
			
		||||
    return std::make_shared<Native> (owner, flags);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
} // namespace juce
 | 
			
		||||
 
 | 
			
		||||
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							
							
								
								
									
										400
									
								
								deps/juce/modules/juce_gui_basics/native/juce_mac_CGMetalLayerRenderer.h
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										400
									
								
								deps/juce/modules/juce_gui_basics/native/juce_mac_CGMetalLayerRenderer.h
									
									
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,400 @@
 | 
			
		||||
/*
 | 
			
		||||
  ==============================================================================
 | 
			
		||||
 | 
			
		||||
   This file is part of the JUCE library.
 | 
			
		||||
   Copyright (c) 2022 - Raw Material Software Limited
 | 
			
		||||
 | 
			
		||||
   JUCE is an open source library subject to commercial or open-source
 | 
			
		||||
   licensing.
 | 
			
		||||
 | 
			
		||||
   By using JUCE, you agree to the terms of both the JUCE 7 End-User License
 | 
			
		||||
   Agreement and JUCE Privacy Policy.
 | 
			
		||||
 | 
			
		||||
   End User License Agreement: www.juce.com/juce-7-licence
 | 
			
		||||
   Privacy Policy: www.juce.com/juce-privacy-policy
 | 
			
		||||
 | 
			
		||||
   Or: You may also use this code under the terms of the GPL v3 (see
 | 
			
		||||
   www.gnu.org/licenses).
 | 
			
		||||
 | 
			
		||||
   JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
 | 
			
		||||
   EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
 | 
			
		||||
   DISCLAIMED.
 | 
			
		||||
 | 
			
		||||
  ==============================================================================
 | 
			
		||||
*/
 | 
			
		||||
 | 
			
		||||
// The CoreGraphicsMetalLayerRenderer requires macOS 10.14 and iOS 12.
 | 
			
		||||
JUCE_BEGIN_IGNORE_WARNINGS_GCC_LIKE ("-Wunguarded-availability", "-Wunguarded-availability-new")
 | 
			
		||||
 | 
			
		||||
namespace juce
 | 
			
		||||
{
 | 
			
		||||
 | 
			
		||||
//==============================================================================
 | 
			
		||||
template <typename ViewType>
 | 
			
		||||
class CoreGraphicsMetalLayerRenderer
 | 
			
		||||
{
 | 
			
		||||
public:
 | 
			
		||||
    //==============================================================================
 | 
			
		||||
    CoreGraphicsMetalLayerRenderer (ViewType* view, bool isOpaque)
 | 
			
		||||
    {
 | 
			
		||||
        device.reset (MTLCreateSystemDefaultDevice());
 | 
			
		||||
        commandQueue.reset ([device.get() newCommandQueue]);
 | 
			
		||||
 | 
			
		||||
        attach (view, isOpaque);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    ~CoreGraphicsMetalLayerRenderer()
 | 
			
		||||
    {
 | 
			
		||||
        if (memoryBlitCommandBuffer != nullptr)
 | 
			
		||||
        {
 | 
			
		||||
            stopGpuCommandSubmission = true;
 | 
			
		||||
            [memoryBlitCommandBuffer.get() waitUntilCompleted];
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    void attach (ViewType* view, bool isOpaque)
 | 
			
		||||
    {
 | 
			
		||||
       #if JUCE_MAC
 | 
			
		||||
        view.wantsLayer = YES;
 | 
			
		||||
        view.layerContentsPlacement = NSViewLayerContentsPlacementTopLeft;
 | 
			
		||||
        view.layer = [CAMetalLayer layer];
 | 
			
		||||
       #endif
 | 
			
		||||
 | 
			
		||||
        auto layer = (CAMetalLayer*) view.layer;
 | 
			
		||||
 | 
			
		||||
        layer.device = device.get();
 | 
			
		||||
        layer.framebufferOnly = NO;
 | 
			
		||||
        layer.pixelFormat = MTLPixelFormatBGRA8Unorm_sRGB;
 | 
			
		||||
        layer.opaque = isOpaque;
 | 
			
		||||
        layer.allowsNextDrawableTimeout = NO;
 | 
			
		||||
 | 
			
		||||
        attachedView = view;
 | 
			
		||||
        doSynchronousRender = true;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    void detach()
 | 
			
		||||
    {
 | 
			
		||||
       #if JUCE_MAC
 | 
			
		||||
        attachedView.wantsLayer = NO;
 | 
			
		||||
        attachedView.layer = nil;
 | 
			
		||||
       #endif
 | 
			
		||||
 | 
			
		||||
        attachedView = nullptr;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    bool isAttachedToView (ViewType* view) const
 | 
			
		||||
    {
 | 
			
		||||
        return view == attachedView && attachedView != nullptr;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    template <typename Callback>
 | 
			
		||||
    bool drawRectangleList (ViewType* view,
 | 
			
		||||
                            float scaleFactor,
 | 
			
		||||
                            Callback&& drawRectWithContext,
 | 
			
		||||
                            const RectangleList<float>& dirtyRegions)
 | 
			
		||||
    {
 | 
			
		||||
        auto layer = (CAMetalLayer*) view.layer;
 | 
			
		||||
 | 
			
		||||
        if (memoryBlitCommandBuffer != nullptr)
 | 
			
		||||
        {
 | 
			
		||||
            switch ([memoryBlitCommandBuffer.get() status])
 | 
			
		||||
            {
 | 
			
		||||
                case MTLCommandBufferStatusNotEnqueued:
 | 
			
		||||
                case MTLCommandBufferStatusEnqueued:
 | 
			
		||||
                case MTLCommandBufferStatusCommitted:
 | 
			
		||||
                case MTLCommandBufferStatusScheduled:
 | 
			
		||||
                    // If we haven't finished blitting the CPU texture to the GPU then
 | 
			
		||||
                    // report that we have been unable to draw anything.
 | 
			
		||||
                    return false;
 | 
			
		||||
                case MTLCommandBufferStatusCompleted:
 | 
			
		||||
                case MTLCommandBufferStatusError:
 | 
			
		||||
                    break;
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        layer.contentsScale = scaleFactor;
 | 
			
		||||
        const auto drawableSizeTansform = CGAffineTransformMakeScale (layer.contentsScale,
 | 
			
		||||
                                                                      layer.contentsScale);
 | 
			
		||||
        const auto transformedFrameSize = CGSizeApplyAffineTransform (view.frame.size, drawableSizeTansform);
 | 
			
		||||
 | 
			
		||||
        if (resources == nullptr || ! CGSizeEqualToSize (layer.drawableSize, transformedFrameSize))
 | 
			
		||||
        {
 | 
			
		||||
            layer.drawableSize = transformedFrameSize;
 | 
			
		||||
            resources = std::make_unique<Resources> (device.get(), layer);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        auto gpuTexture = resources->getGpuTexture();
 | 
			
		||||
 | 
			
		||||
        if (gpuTexture == nullptr)
 | 
			
		||||
        {
 | 
			
		||||
            jassertfalse;
 | 
			
		||||
            return false;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        auto cgContext = resources->getCGContext();
 | 
			
		||||
 | 
			
		||||
        for (auto rect : dirtyRegions)
 | 
			
		||||
        {
 | 
			
		||||
            const auto cgRect = convertToCGRect (rect);
 | 
			
		||||
 | 
			
		||||
            CGContextSaveGState (cgContext);
 | 
			
		||||
 | 
			
		||||
            CGContextClipToRect (cgContext, cgRect);
 | 
			
		||||
            drawRectWithContext (cgContext, cgRect);
 | 
			
		||||
 | 
			
		||||
            CGContextRestoreGState (cgContext);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        resources->signalBufferModifiedByCpu();
 | 
			
		||||
 | 
			
		||||
        auto sharedTexture = resources->getSharedTexture();
 | 
			
		||||
 | 
			
		||||
        auto encodeBlit = [] (id<MTLCommandBuffer> commandBuffer,
 | 
			
		||||
                              id<MTLTexture> source,
 | 
			
		||||
                              id<MTLTexture> destination)
 | 
			
		||||
        {
 | 
			
		||||
            auto blitCommandEncoder = [commandBuffer blitCommandEncoder];
 | 
			
		||||
            [blitCommandEncoder copyFromTexture: source
 | 
			
		||||
                                    sourceSlice: 0
 | 
			
		||||
                                    sourceLevel: 0
 | 
			
		||||
                                   sourceOrigin: MTLOrigin{}
 | 
			
		||||
                                     sourceSize: MTLSize { source.width, source.height, 1 }
 | 
			
		||||
                                      toTexture: destination
 | 
			
		||||
                               destinationSlice: 0
 | 
			
		||||
                               destinationLevel: 0
 | 
			
		||||
                              destinationOrigin: MTLOrigin{}];
 | 
			
		||||
            [blitCommandEncoder endEncoding];
 | 
			
		||||
        };
 | 
			
		||||
 | 
			
		||||
        if (doSynchronousRender)
 | 
			
		||||
        {
 | 
			
		||||
            @autoreleasepool
 | 
			
		||||
            {
 | 
			
		||||
                id<MTLCommandBuffer> commandBuffer = [commandQueue.get() commandBuffer];
 | 
			
		||||
 | 
			
		||||
                id<CAMetalDrawable> drawable = [layer nextDrawable];
 | 
			
		||||
                encodeBlit (commandBuffer, sharedTexture, drawable.texture);
 | 
			
		||||
 | 
			
		||||
                [commandBuffer presentDrawable: drawable];
 | 
			
		||||
                [commandBuffer commit];
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            doSynchronousRender = false;
 | 
			
		||||
        }
 | 
			
		||||
        else
 | 
			
		||||
        {
 | 
			
		||||
            // Command buffers are usually considered temporary, and are automatically released by
 | 
			
		||||
            // the operating system when the rendering pipeline is finsihed. However, we want to keep
 | 
			
		||||
            // this one alive so that we can wait for pipeline completion in the destructor.
 | 
			
		||||
            memoryBlitCommandBuffer.reset ([[commandQueue.get() commandBuffer] retain]);
 | 
			
		||||
 | 
			
		||||
            encodeBlit (memoryBlitCommandBuffer.get(), sharedTexture, gpuTexture);
 | 
			
		||||
 | 
			
		||||
            [memoryBlitCommandBuffer.get() addScheduledHandler: ^(id<MTLCommandBuffer>)
 | 
			
		||||
            {
 | 
			
		||||
                // We're on a Metal thread, so we can make a blocking nextDrawable call
 | 
			
		||||
                // without stalling the message thread.
 | 
			
		||||
 | 
			
		||||
                // Check if we can do an early exit.
 | 
			
		||||
                if (stopGpuCommandSubmission)
 | 
			
		||||
                    return;
 | 
			
		||||
 | 
			
		||||
                @autoreleasepool
 | 
			
		||||
                {
 | 
			
		||||
                    id<CAMetalDrawable> drawable = [layer nextDrawable];
 | 
			
		||||
 | 
			
		||||
                    id<MTLCommandBuffer> presentationCommandBuffer = [commandQueue.get() commandBuffer];
 | 
			
		||||
 | 
			
		||||
                    encodeBlit (presentationCommandBuffer, gpuTexture, drawable.texture);
 | 
			
		||||
 | 
			
		||||
                    [presentationCommandBuffer addScheduledHandler: ^(id<MTLCommandBuffer>)
 | 
			
		||||
                    {
 | 
			
		||||
                        [drawable present];
 | 
			
		||||
                    }];
 | 
			
		||||
 | 
			
		||||
                    [presentationCommandBuffer commit];
 | 
			
		||||
                }
 | 
			
		||||
            }];
 | 
			
		||||
 | 
			
		||||
            [memoryBlitCommandBuffer.get() commit];
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        return true;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
private:
 | 
			
		||||
    //==============================================================================
 | 
			
		||||
    static auto alignTo (size_t n, size_t alignment)
 | 
			
		||||
    {
 | 
			
		||||
        return ((n + alignment - 1) / alignment) * alignment;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    //==============================================================================
 | 
			
		||||
    class GpuTexturePool
 | 
			
		||||
    {
 | 
			
		||||
    public:
 | 
			
		||||
        GpuTexturePool (id<MTLDevice> metalDevice, MTLTextureDescriptor* descriptor)
 | 
			
		||||
        {
 | 
			
		||||
            for (auto& t : textureCache)
 | 
			
		||||
                t.reset ([metalDevice newTextureWithDescriptor: descriptor]);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        id<MTLTexture> take() const
 | 
			
		||||
        {
 | 
			
		||||
            auto iter = std::find_if (textureCache.begin(), textureCache.end(),
 | 
			
		||||
                                      [] (const ObjCObjectHandle<id<MTLTexture>>& t) { return [t.get() retainCount] == 1; });
 | 
			
		||||
            return iter == textureCache.end() ? nullptr : (*iter).get();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
    private:
 | 
			
		||||
        std::array<ObjCObjectHandle<id<MTLTexture>>, 3> textureCache;
 | 
			
		||||
 | 
			
		||||
        JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (GpuTexturePool)
 | 
			
		||||
        JUCE_DECLARE_NON_MOVEABLE (GpuTexturePool)
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    //==============================================================================
 | 
			
		||||
    class Resources
 | 
			
		||||
    {
 | 
			
		||||
    public:
 | 
			
		||||
        Resources (id<MTLDevice> metalDevice, CAMetalLayer* layer)
 | 
			
		||||
        {
 | 
			
		||||
            const auto bytesPerRow = alignTo ((size_t) layer.drawableSize.width * 4, 256);
 | 
			
		||||
 | 
			
		||||
            const auto allocationSize = cpuRenderMemory.ensureSize (bytesPerRow * (size_t) layer.drawableSize.height);
 | 
			
		||||
 | 
			
		||||
            buffer.reset ([metalDevice newBufferWithBytesNoCopy: cpuRenderMemory.get()
 | 
			
		||||
                                                         length: allocationSize
 | 
			
		||||
                                                        options:
 | 
			
		||||
                                                                #if JUCE_MAC
 | 
			
		||||
                                                                 MTLResourceStorageModeManaged
 | 
			
		||||
                                                                #else
 | 
			
		||||
                                                                 MTLResourceStorageModeShared
 | 
			
		||||
                                                                #endif
 | 
			
		||||
                                                    deallocator: nullptr]);
 | 
			
		||||
 | 
			
		||||
            auto* textureDesc = [MTLTextureDescriptor texture2DDescriptorWithPixelFormat: layer.pixelFormat
 | 
			
		||||
                                                                                   width: (NSUInteger) layer.drawableSize.width
 | 
			
		||||
                                                                                  height: (NSUInteger) layer.drawableSize.height
 | 
			
		||||
                                                                               mipmapped: NO];
 | 
			
		||||
            textureDesc.storageMode =
 | 
			
		||||
                                     #if JUCE_MAC
 | 
			
		||||
                                      MTLStorageModeManaged;
 | 
			
		||||
                                     #else
 | 
			
		||||
                                      MTLStorageModeShared;
 | 
			
		||||
                                     #endif
 | 
			
		||||
            textureDesc.usage = MTLTextureUsageShaderRead;
 | 
			
		||||
 | 
			
		||||
            sharedTexture.reset ([buffer.get() newTextureWithDescriptor: textureDesc
 | 
			
		||||
                                                                 offset: 0
 | 
			
		||||
                                                            bytesPerRow: bytesPerRow]);
 | 
			
		||||
 | 
			
		||||
            cgContext.reset (CGBitmapContextCreate (cpuRenderMemory.get(),
 | 
			
		||||
                                                    (size_t) layer.drawableSize.width,
 | 
			
		||||
                                                    (size_t) layer.drawableSize.height,
 | 
			
		||||
                                                    8, // Bits per component
 | 
			
		||||
                                                    bytesPerRow,
 | 
			
		||||
                                                    CGColorSpaceCreateWithName (kCGColorSpaceSRGB),
 | 
			
		||||
                                                    (uint32_t) kCGImageAlphaPremultipliedFirst | (uint32_t) kCGBitmapByteOrder32Host));
 | 
			
		||||
 | 
			
		||||
            CGContextTranslateCTM (cgContext.get(), 0, layer.drawableSize.height);
 | 
			
		||||
            CGContextScaleCTM (cgContext.get(), layer.contentsScale, -layer.contentsScale);
 | 
			
		||||
 | 
			
		||||
            textureDesc.storageMode = MTLStorageModePrivate;
 | 
			
		||||
            gpuTexturePool = std::make_unique<GpuTexturePool> (metalDevice, textureDesc);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        CGContextRef getCGContext() const noexcept       { return cgContext.get(); }
 | 
			
		||||
        id<MTLTexture> getSharedTexture() const noexcept { return sharedTexture.get(); }
 | 
			
		||||
        id<MTLTexture> getGpuTexture() noexcept          { return gpuTexturePool == nullptr ? nullptr : gpuTexturePool->take(); }
 | 
			
		||||
 | 
			
		||||
        void signalBufferModifiedByCpu()
 | 
			
		||||
        {
 | 
			
		||||
           #if JUCE_MAC
 | 
			
		||||
            [buffer.get() didModifyRange: { 0, buffer.get().length }];
 | 
			
		||||
           #endif
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
    private:
 | 
			
		||||
        class AlignedMemory
 | 
			
		||||
        {
 | 
			
		||||
        public:
 | 
			
		||||
            AlignedMemory() = default;
 | 
			
		||||
 | 
			
		||||
            void* get()
 | 
			
		||||
            {
 | 
			
		||||
                return allocation != nullptr ? allocation->data : nullptr;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            size_t ensureSize (size_t newSize)
 | 
			
		||||
            {
 | 
			
		||||
                const auto alignedSize = alignTo (newSize, pagesize);
 | 
			
		||||
 | 
			
		||||
                if (alignedSize > size)
 | 
			
		||||
                {
 | 
			
		||||
                    size = std::max (alignedSize, alignTo ((size_t) (size * growthFactor), pagesize));
 | 
			
		||||
                    allocation = std::make_unique<AllocationWrapper> (pagesize, size);
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
                return size;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
        private:
 | 
			
		||||
            static constexpr float growthFactor = 1.3f;
 | 
			
		||||
 | 
			
		||||
            const size_t pagesize = (size_t) getpagesize();
 | 
			
		||||
 | 
			
		||||
            struct AllocationWrapper
 | 
			
		||||
            {
 | 
			
		||||
                AllocationWrapper (size_t alignment, size_t allocationSize)
 | 
			
		||||
                {
 | 
			
		||||
                    if (posix_memalign (&data, alignment, allocationSize) != 0)
 | 
			
		||||
                        jassertfalse;
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
                ~AllocationWrapper()
 | 
			
		||||
                {
 | 
			
		||||
                    ::free (data);
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
                void* data = nullptr;
 | 
			
		||||
            };
 | 
			
		||||
 | 
			
		||||
            std::unique_ptr<AllocationWrapper> allocation;
 | 
			
		||||
            size_t size = 0;
 | 
			
		||||
 | 
			
		||||
            JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (AlignedMemory)
 | 
			
		||||
            JUCE_DECLARE_NON_MOVEABLE (AlignedMemory)
 | 
			
		||||
        };
 | 
			
		||||
 | 
			
		||||
        AlignedMemory cpuRenderMemory;
 | 
			
		||||
 | 
			
		||||
        detail::ContextPtr cgContext;
 | 
			
		||||
 | 
			
		||||
        ObjCObjectHandle<id<MTLBuffer>> buffer;
 | 
			
		||||
        ObjCObjectHandle<id<MTLTexture>> sharedTexture;
 | 
			
		||||
        std::unique_ptr<GpuTexturePool> gpuTexturePool;
 | 
			
		||||
 | 
			
		||||
        JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (Resources)
 | 
			
		||||
        JUCE_DECLARE_NON_MOVEABLE (Resources)
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    //==============================================================================
 | 
			
		||||
    ViewType* attachedView = nullptr;
 | 
			
		||||
    bool doSynchronousRender = false;
 | 
			
		||||
 | 
			
		||||
    std::unique_ptr<Resources> resources;
 | 
			
		||||
 | 
			
		||||
    ObjCObjectHandle<id<MTLDevice>> device;
 | 
			
		||||
    ObjCObjectHandle<id<MTLCommandQueue>> commandQueue;
 | 
			
		||||
    ObjCObjectHandle<id<MTLCommandBuffer>> memoryBlitCommandBuffer;
 | 
			
		||||
 | 
			
		||||
    std::atomic<bool> stopGpuCommandSubmission { false };
 | 
			
		||||
 | 
			
		||||
    JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (CoreGraphicsMetalLayerRenderer)
 | 
			
		||||
    JUCE_DECLARE_NON_MOVEABLE (CoreGraphicsMetalLayerRenderer)
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
JUCE_END_IGNORE_WARNINGS_GCC_LIKE
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
@@ -2,15 +2,15 @@
 | 
			
		||||
  ==============================================================================
 | 
			
		||||
 | 
			
		||||
   This file is part of the JUCE library.
 | 
			
		||||
   Copyright (c) 2020 - Raw Material Software Limited
 | 
			
		||||
   Copyright (c) 2022 - Raw Material Software Limited
 | 
			
		||||
 | 
			
		||||
   JUCE is an open source library subject to commercial or open-source
 | 
			
		||||
   licensing.
 | 
			
		||||
 | 
			
		||||
   By using JUCE, you agree to the terms of both the JUCE 6 End-User License
 | 
			
		||||
   Agreement and JUCE Privacy Policy (both effective as of the 16th June 2020).
 | 
			
		||||
   By using JUCE, you agree to the terms of both the JUCE 7 End-User License
 | 
			
		||||
   Agreement and JUCE Privacy Policy.
 | 
			
		||||
 | 
			
		||||
   End User License Agreement: www.juce.com/juce-6-licence
 | 
			
		||||
   End User License Agreement: www.juce.com/juce-7-licence
 | 
			
		||||
   Privacy Policy: www.juce.com/juce-privacy-policy
 | 
			
		||||
 | 
			
		||||
   Or: You may also use this code under the terms of the GPL v3 (see
 | 
			
		||||
@@ -82,8 +82,9 @@ public:
 | 
			
		||||
        filters.trim();
 | 
			
		||||
        filters.removeEmptyStrings();
 | 
			
		||||
 | 
			
		||||
        NSString* nsTitle = juceStringToNS (owner.title);
 | 
			
		||||
        auto* nsTitle = juceStringToNS (owner.title);
 | 
			
		||||
        [panel setTitle: nsTitle];
 | 
			
		||||
        [panel setReleasedWhenClosed: YES];
 | 
			
		||||
 | 
			
		||||
        JUCE_BEGIN_IGNORE_WARNINGS_GCC_LIKE ("-Wdeprecated-declarations")
 | 
			
		||||
        [panel setAllowedFileTypes: createAllowedTypesArray (filters)];
 | 
			
		||||
@@ -111,10 +112,13 @@ public:
 | 
			
		||||
            preview->addToDesktop (0, (void*) nsViewPreview);
 | 
			
		||||
            preview->setVisible (true);
 | 
			
		||||
 | 
			
		||||
            if (! isSave)
 | 
			
		||||
            if (@available (macOS 10.11, *))
 | 
			
		||||
            {
 | 
			
		||||
                auto* openPanel = static_cast<NSOpenPanel*> (panel);
 | 
			
		||||
                [openPanel setAccessoryViewDisclosed: YES];
 | 
			
		||||
                if (! isSave)
 | 
			
		||||
                {
 | 
			
		||||
                    auto* openPanel = static_cast<NSOpenPanel*> (panel);
 | 
			
		||||
                    [openPanel setAccessoryViewDisclosed: YES];
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
@@ -153,22 +157,14 @@ public:
 | 
			
		||||
            if (nsViewPreview != nil)
 | 
			
		||||
            {
 | 
			
		||||
                [panel setAccessoryView: nil];
 | 
			
		||||
 | 
			
		||||
                [nsViewPreview release];
 | 
			
		||||
 | 
			
		||||
                nsViewPreview = nil;
 | 
			
		||||
                preview = nullptr;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            [panel close];
 | 
			
		||||
            [panel release];
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        if (delegate != nil)
 | 
			
		||||
        {
 | 
			
		||||
            [delegate release];
 | 
			
		||||
            delegate = nil;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    void launch() override
 | 
			
		||||
@@ -179,10 +175,17 @@ public:
 | 
			
		||||
            addToDesktop (0);
 | 
			
		||||
 | 
			
		||||
            enterModalState (true);
 | 
			
		||||
            [panel beginWithCompletionHandler:CreateObjCBlock (this, &Native::finished)];
 | 
			
		||||
 | 
			
		||||
            if (preview != nullptr)
 | 
			
		||||
                preview->toFront (true);
 | 
			
		||||
            MessageManager::callAsync ([ref = SafePointer<Native> (this)]
 | 
			
		||||
            {
 | 
			
		||||
                if (ref == nullptr)
 | 
			
		||||
                    return;
 | 
			
		||||
 | 
			
		||||
                [ref->panel beginWithCompletionHandler: CreateObjCBlock (ref.getComponent(), &Native::finished)];
 | 
			
		||||
 | 
			
		||||
                if (ref->preview != nullptr)
 | 
			
		||||
                    ref->preview->toFront (true);
 | 
			
		||||
            });
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
@@ -213,6 +216,18 @@ private:
 | 
			
		||||
    //==============================================================================
 | 
			
		||||
    typedef NSObject<NSOpenSavePanelDelegate> DelegateType;
 | 
			
		||||
 | 
			
		||||
    static URL urlFromNSURL (NSURL* url)
 | 
			
		||||
    {
 | 
			
		||||
        const auto scheme = nsStringToJuce ([url scheme]);
 | 
			
		||||
 | 
			
		||||
        auto pathComponents = StringArray::fromTokens (nsStringToJuce ([url path]), "/", {});
 | 
			
		||||
 | 
			
		||||
        for (auto& component : pathComponents)
 | 
			
		||||
            component = URL::addEscapeChars (component, false);
 | 
			
		||||
 | 
			
		||||
        return { scheme + "://" + pathComponents.joinIntoString ("/") };
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    void finished (NSInteger result)
 | 
			
		||||
    {
 | 
			
		||||
        Array<URL> chooserResults;
 | 
			
		||||
@@ -224,20 +239,16 @@ private:
 | 
			
		||||
            if (@available (macOS 10.9, *))
 | 
			
		||||
                return NSModalResponseOK;
 | 
			
		||||
 | 
			
		||||
            JUCE_BEGIN_IGNORE_WARNINGS_GCC_LIKE ("-Wdeprecated-declarations")
 | 
			
		||||
            return NSFileHandlingPanelOKButton;
 | 
			
		||||
            JUCE_END_IGNORE_WARNINGS_GCC_LIKE
 | 
			
		||||
        }();
 | 
			
		||||
 | 
			
		||||
        if (panel != nil && result == okResult)
 | 
			
		||||
        {
 | 
			
		||||
            auto addURLResult = [&chooserResults] (NSURL* urlToAdd)
 | 
			
		||||
            {
 | 
			
		||||
                auto scheme = nsStringToJuce ([urlToAdd scheme]);
 | 
			
		||||
                auto pathComponents = StringArray::fromTokens (nsStringToJuce ([urlToAdd path]), "/", {});
 | 
			
		||||
 | 
			
		||||
                for (auto& component : pathComponents)
 | 
			
		||||
                    component = URL::addEscapeChars (component, false);
 | 
			
		||||
 | 
			
		||||
                chooserResults.add (URL (scheme + "://" + pathComponents.joinIntoString ("/")));
 | 
			
		||||
                chooserResults.add (urlFromNSURL (urlToAdd));
 | 
			
		||||
            };
 | 
			
		||||
 | 
			
		||||
            if (isSave)
 | 
			
		||||
@@ -257,17 +268,15 @@ private:
 | 
			
		||||
        owner.finished (chooserResults);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    bool shouldShowFilename (const String& filenameToTest)
 | 
			
		||||
    BOOL shouldShowURL (const URL& urlToTest)
 | 
			
		||||
    {
 | 
			
		||||
        const File f (filenameToTest);
 | 
			
		||||
        auto nsFilename = juceStringToNS (filenameToTest);
 | 
			
		||||
 | 
			
		||||
        for (int i = filters.size(); --i >= 0;)
 | 
			
		||||
            if (f.getFileName().matchesWildcard (filters[i], true))
 | 
			
		||||
                return true;
 | 
			
		||||
            if (urlToTest.getFileName().matchesWildcard (filters[i], true))
 | 
			
		||||
                return YES;
 | 
			
		||||
 | 
			
		||||
        const auto f = urlToTest.getLocalFile();
 | 
			
		||||
        return f.isDirectory()
 | 
			
		||||
                 && ! [[NSWorkspace sharedWorkspace] isFilePackageAtPath: nsFilename];
 | 
			
		||||
                 && ! [[NSWorkspace sharedWorkspace] isFilePackageAtPath: juceStringToNS (f.getFullPathName())];
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    void panelSelectionDidChange (id sender)
 | 
			
		||||
@@ -326,7 +335,7 @@ private:
 | 
			
		||||
        jassert ([panel preventsApplicationTerminationWhenModal]);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    static BOOL preventsApplicationTerminationWhenModal() { return YES; }
 | 
			
		||||
    static BOOL preventsApplicationTerminationWhenModal (id, SEL) { return YES; }
 | 
			
		||||
 | 
			
		||||
    template <typename Base>
 | 
			
		||||
    struct SafeModalPanel : public ObjCClass<Base>
 | 
			
		||||
@@ -334,8 +343,7 @@ private:
 | 
			
		||||
        explicit SafeModalPanel (const char* name) : ObjCClass<Base> (name)
 | 
			
		||||
        {
 | 
			
		||||
            this->addMethod (@selector (preventsApplicationTerminationWhenModal),
 | 
			
		||||
                             preventsApplicationTerminationWhenModal,
 | 
			
		||||
                             "c@:");
 | 
			
		||||
                             preventsApplicationTerminationWhenModal);
 | 
			
		||||
 | 
			
		||||
            this->registerClass();
 | 
			
		||||
        }
 | 
			
		||||
@@ -358,8 +366,8 @@ private:
 | 
			
		||||
        {
 | 
			
		||||
            addIvar<Native*> ("cppObject");
 | 
			
		||||
 | 
			
		||||
            addMethod (@selector (panel:shouldShowFilename:), shouldShowFilename,      "c@:@@");
 | 
			
		||||
            addMethod (@selector (panelSelectionDidChange:),  panelSelectionDidChange, "c@");
 | 
			
		||||
            addMethod (@selector (panel:shouldEnableURL:),   shouldEnableURL);
 | 
			
		||||
            addMethod (@selector (panelSelectionDidChange:), panelSelectionDidChange);
 | 
			
		||||
 | 
			
		||||
            addProtocol (@protocol (NSOpenSavePanelDelegate));
 | 
			
		||||
 | 
			
		||||
@@ -367,18 +375,14 @@ private:
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
    private:
 | 
			
		||||
        static BOOL shouldShowFilename (id self, SEL, id /*sender*/, NSString* filename)
 | 
			
		||||
        static BOOL shouldEnableURL (id self, SEL, id /*sender*/, NSURL* url)
 | 
			
		||||
        {
 | 
			
		||||
            auto* _this = getIvar<Native*> (self, "cppObject");
 | 
			
		||||
 | 
			
		||||
            return _this->shouldShowFilename (nsStringToJuce (filename)) ? YES : NO;
 | 
			
		||||
            return getIvar<Native*> (self, "cppObject")->shouldShowURL (urlFromNSURL (url));
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        static void panelSelectionDidChange (id self, SEL, id sender)
 | 
			
		||||
        {
 | 
			
		||||
            auto* _this = getIvar<Native*> (self, "cppObject");
 | 
			
		||||
 | 
			
		||||
            _this->panelSelectionDidChange (sender);
 | 
			
		||||
            getIvar<Native*> (self, "cppObject")->panelSelectionDidChange (sender);
 | 
			
		||||
        }
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -2,15 +2,15 @@
 | 
			
		||||
  ==============================================================================
 | 
			
		||||
 | 
			
		||||
   This file is part of the JUCE library.
 | 
			
		||||
   Copyright (c) 2020 - Raw Material Software Limited
 | 
			
		||||
   Copyright (c) 2022 - Raw Material Software Limited
 | 
			
		||||
 | 
			
		||||
   JUCE is an open source library subject to commercial or open-source
 | 
			
		||||
   licensing.
 | 
			
		||||
 | 
			
		||||
   By using JUCE, you agree to the terms of both the JUCE 6 End-User License
 | 
			
		||||
   Agreement and JUCE Privacy Policy (both effective as of the 16th June 2020).
 | 
			
		||||
   By using JUCE, you agree to the terms of both the JUCE 7 End-User License
 | 
			
		||||
   Agreement and JUCE Privacy Policy.
 | 
			
		||||
 | 
			
		||||
   End User License Agreement: www.juce.com/juce-6-licence
 | 
			
		||||
   End User License Agreement: www.juce.com/juce-7-licence
 | 
			
		||||
   Privacy Policy: www.juce.com/juce-privacy-policy
 | 
			
		||||
 | 
			
		||||
   Or: You may also use this code under the terms of the GPL v3 (see
 | 
			
		||||
@@ -26,6 +26,10 @@
 | 
			
		||||
namespace juce
 | 
			
		||||
{
 | 
			
		||||
 | 
			
		||||
JUCE_BEGIN_IGNORE_WARNINGS_GCC_LIKE ("-Wundeclared-selector")
 | 
			
		||||
const auto menuItemInvokedSelector = @selector (menuItemInvoked:);
 | 
			
		||||
JUCE_END_IGNORE_WARNINGS_GCC_LIKE
 | 
			
		||||
 | 
			
		||||
//==============================================================================
 | 
			
		||||
struct JuceMainMenuBarHolder : private DeletedAtShutdown
 | 
			
		||||
{
 | 
			
		||||
@@ -283,19 +287,13 @@ public:
 | 
			
		||||
        }
 | 
			
		||||
        else
 | 
			
		||||
        {
 | 
			
		||||
            JUCE_BEGIN_IGNORE_WARNINGS_GCC_LIKE ("-Wundeclared-selector")
 | 
			
		||||
            auto item = [[NSMenuItem alloc] initWithTitle: text
 | 
			
		||||
                                                   action: @selector (menuItemInvoked:)
 | 
			
		||||
                                                   action: menuItemInvokedSelector
 | 
			
		||||
                                            keyEquivalent: nsEmptyString()];
 | 
			
		||||
            JUCE_END_IGNORE_WARNINGS_GCC_LIKE
 | 
			
		||||
 | 
			
		||||
            [item setTag: topLevelIndex];
 | 
			
		||||
            [item setEnabled: i.isEnabled];
 | 
			
		||||
           #if defined (MAC_OS_X_VERSION_10_13) && MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_13
 | 
			
		||||
            [item setState: i.isTicked ? NSControlStateValueOn : NSControlStateValueOff];
 | 
			
		||||
           #else
 | 
			
		||||
            [item setState: i.isTicked ? NSOnState : NSOffState];
 | 
			
		||||
           #endif
 | 
			
		||||
            [item setTarget: (id) callback];
 | 
			
		||||
 | 
			
		||||
            auto* juceItem = new PopupMenu::Item (i);
 | 
			
		||||
@@ -445,9 +443,32 @@ private:
 | 
			
		||||
        NSString* f35String = [NSString stringWithCharacters: &f35Key length: 1];
 | 
			
		||||
 | 
			
		||||
        NSMenuItem* item = [[NSMenuItem alloc] initWithTitle: nsStringLiteral ("x")
 | 
			
		||||
                                                      action: nil
 | 
			
		||||
                                                      action: menuItemInvokedSelector
 | 
			
		||||
                                               keyEquivalent: f35String];
 | 
			
		||||
        [item setTarget: nil];
 | 
			
		||||
 | 
			
		||||
        // When the f35Event is invoked, the item's enablement is checked and a
 | 
			
		||||
        // NSBeep is triggered if the item appears to be disabled.
 | 
			
		||||
        // This ValidatorClass exists solely to return YES from validateMenuItem.
 | 
			
		||||
        struct ValidatorClass   : public ObjCClass<NSObject>
 | 
			
		||||
        {
 | 
			
		||||
            ValidatorClass()  : ObjCClass ("JUCEMenuValidator_")
 | 
			
		||||
            {
 | 
			
		||||
                addMethod (menuItemInvokedSelector,       menuItemInvoked);
 | 
			
		||||
                addMethod (@selector (validateMenuItem:), validateMenuItem);
 | 
			
		||||
                addProtocol (@protocol (NSMenuItemValidation));
 | 
			
		||||
 | 
			
		||||
                registerClass();
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
        private:
 | 
			
		||||
            static BOOL validateMenuItem (id, SEL, NSMenuItem*)      { return YES; }
 | 
			
		||||
            static void menuItemInvoked  (id, SEL, NSMenuItem*)      {}
 | 
			
		||||
        };
 | 
			
		||||
 | 
			
		||||
        static ValidatorClass validatorClass;
 | 
			
		||||
        static auto* instance = validatorClass.createInstance();
 | 
			
		||||
 | 
			
		||||
        [item setTarget: instance];
 | 
			
		||||
        [menu insertItem: item atIndex: [menu numberOfItems]];
 | 
			
		||||
        [item release];
 | 
			
		||||
 | 
			
		||||
@@ -523,18 +544,12 @@ private:
 | 
			
		||||
        {
 | 
			
		||||
            addIvar<JuceMainMenuHandler*> ("owner");
 | 
			
		||||
 | 
			
		||||
            JUCE_BEGIN_IGNORE_WARNINGS_GCC_LIKE ("-Wundeclared-selector")
 | 
			
		||||
            addMethod (@selector (menuItemInvoked:),  menuItemInvoked, "v@:@");
 | 
			
		||||
            JUCE_END_IGNORE_WARNINGS_GCC_LIKE
 | 
			
		||||
 | 
			
		||||
            addMethod (@selector (menuNeedsUpdate:),  menuNeedsUpdate,  "v@:@");
 | 
			
		||||
            addMethod (@selector (validateMenuItem:), validateMenuItem, "c@:@");
 | 
			
		||||
            addMethod (menuItemInvokedSelector,       menuItemInvoked);
 | 
			
		||||
            addMethod (@selector (menuNeedsUpdate:),  menuNeedsUpdate);
 | 
			
		||||
            addMethod (@selector (validateMenuItem:), validateMenuItem);
 | 
			
		||||
 | 
			
		||||
            addProtocol (@protocol (NSMenuDelegate));
 | 
			
		||||
 | 
			
		||||
           #if defined (MAC_OS_X_VERSION_10_14)
 | 
			
		||||
            addProtocol (@protocol (NSMenuItemValidation));
 | 
			
		||||
           #endif
 | 
			
		||||
 | 
			
		||||
            registerClass();
 | 
			
		||||
        }
 | 
			
		||||
 
 | 
			
		||||
@@ -2,15 +2,15 @@
 | 
			
		||||
  ==============================================================================
 | 
			
		||||
 | 
			
		||||
   This file is part of the JUCE library.
 | 
			
		||||
   Copyright (c) 2020 - Raw Material Software Limited
 | 
			
		||||
   Copyright (c) 2022 - Raw Material Software Limited
 | 
			
		||||
 | 
			
		||||
   JUCE is an open source library subject to commercial or open-source
 | 
			
		||||
   licensing.
 | 
			
		||||
 | 
			
		||||
   By using JUCE, you agree to the terms of both the JUCE 6 End-User License
 | 
			
		||||
   Agreement and JUCE Privacy Policy (both effective as of the 16th June 2020).
 | 
			
		||||
   By using JUCE, you agree to the terms of both the JUCE 7 End-User License
 | 
			
		||||
   Agreement and JUCE Privacy Policy.
 | 
			
		||||
 | 
			
		||||
   End User License Agreement: www.juce.com/juce-6-licence
 | 
			
		||||
   End User License Agreement: www.juce.com/juce-7-licence
 | 
			
		||||
   Privacy Policy: www.juce.com/juce-privacy-policy
 | 
			
		||||
 | 
			
		||||
   Or: You may also use this code under the terms of the GPL v3 (see
 | 
			
		||||
@@ -29,8 +29,34 @@ namespace juce
 | 
			
		||||
#if JUCE_MAC
 | 
			
		||||
 | 
			
		||||
//==============================================================================
 | 
			
		||||
namespace MouseCursorHelpers
 | 
			
		||||
class MouseCursor::PlatformSpecificHandle
 | 
			
		||||
{
 | 
			
		||||
public:
 | 
			
		||||
    PlatformSpecificHandle (const MouseCursor::StandardCursorType type)
 | 
			
		||||
        : cursorHandle (createCursor (type)) {}
 | 
			
		||||
 | 
			
		||||
    PlatformSpecificHandle (const CustomMouseCursorInfo& info)
 | 
			
		||||
        : cursorHandle (createCursor (info)) {}
 | 
			
		||||
 | 
			
		||||
    ~PlatformSpecificHandle()
 | 
			
		||||
    {
 | 
			
		||||
        [cursorHandle release];
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    static void showInWindow (PlatformSpecificHandle* handle, ComponentPeer*)
 | 
			
		||||
    {
 | 
			
		||||
        auto c = [&]
 | 
			
		||||
        {
 | 
			
		||||
            if (handle == nullptr || handle->cursorHandle == nullptr)
 | 
			
		||||
                return [NSCursor arrowCursor];
 | 
			
		||||
 | 
			
		||||
            return handle->cursorHandle;
 | 
			
		||||
        }();
 | 
			
		||||
 | 
			
		||||
        [c set];
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
private:
 | 
			
		||||
    static NSCursor* fromNSImage (NSImage* im, NSPoint hotspot)
 | 
			
		||||
    {
 | 
			
		||||
        NSCursor* c = [[NSCursor alloc] initWithImage: im
 | 
			
		||||
@@ -39,13 +65,13 @@ namespace MouseCursorHelpers
 | 
			
		||||
        return c;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    static void* fromHIServices (const char* filename)
 | 
			
		||||
    static NSCursor* fromHIServices (const char* filename)
 | 
			
		||||
    {
 | 
			
		||||
        JUCE_AUTORELEASEPOOL
 | 
			
		||||
        {
 | 
			
		||||
            auto cursorPath = String ("/System/Library/Frameworks/ApplicationServices.framework/Versions/A/Frameworks/"
 | 
			
		||||
                                      "HIServices.framework/Versions/A/Resources/cursors/")
 | 
			
		||||
                                  + filename;
 | 
			
		||||
                              + filename;
 | 
			
		||||
 | 
			
		||||
            NSImage* originalImage = [[NSImage alloc] initByReferencingFile: juceStringToNS (cursorPath + "/cursor.pdf")];
 | 
			
		||||
            NSSize originalSize = [originalImage size];
 | 
			
		||||
@@ -59,7 +85,7 @@ namespace MouseCursorHelpers
 | 
			
		||||
                if (CGImageRef rasterCGImage = [originalImage CGImageForProposedRect: nil
 | 
			
		||||
                                                                             context: nil
 | 
			
		||||
                                                                               hints: [NSDictionary dictionaryWithObjectsAndKeys:
 | 
			
		||||
                                                                                         NSImageHintCTM, scaleTransform, nil]])
 | 
			
		||||
                                                                                                            NSImageHintCTM, scaleTransform, nil]])
 | 
			
		||||
                {
 | 
			
		||||
                    NSBitmapImageRep* imageRep = [[NSBitmapImageRep alloc] initWithCGImage: rasterCGImage];
 | 
			
		||||
                    [imageRep setSize: originalSize];
 | 
			
		||||
@@ -83,98 +109,88 @@ namespace MouseCursorHelpers
 | 
			
		||||
            return fromNSImage (resultImage, NSMakePoint (hotspotX, hotspotY));
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void* CustomMouseCursorInfo::create() const
 | 
			
		||||
{
 | 
			
		||||
    return MouseCursorHelpers::fromNSImage (imageToNSImage (image, scaleFactor),
 | 
			
		||||
                                            NSMakePoint (hotspot.x, hotspot.y));
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void* MouseCursor::createStandardMouseCursor (MouseCursor::StandardCursorType type)
 | 
			
		||||
{
 | 
			
		||||
    JUCE_AUTORELEASEPOOL
 | 
			
		||||
    static NSCursor* createCursor (const CustomMouseCursorInfo& info)
 | 
			
		||||
    {
 | 
			
		||||
        NSCursor* c = nil;
 | 
			
		||||
        return fromNSImage (imageToNSImage (info.image),
 | 
			
		||||
                            NSMakePoint (info.hotspot.x, info.hotspot.y));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
        switch (type)
 | 
			
		||||
    static NSCursor* createCursor (const MouseCursor::StandardCursorType type)
 | 
			
		||||
    {
 | 
			
		||||
        JUCE_AUTORELEASEPOOL
 | 
			
		||||
        {
 | 
			
		||||
            case NormalCursor:
 | 
			
		||||
            case ParentCursor:          c = [NSCursor arrowCursor]; break;
 | 
			
		||||
            case NoCursor:              return CustomMouseCursorInfo (Image (Image::ARGB, 8, 8, true), {}).create();
 | 
			
		||||
            case DraggingHandCursor:    c = [NSCursor openHandCursor]; break;
 | 
			
		||||
            case WaitCursor:            c = [NSCursor arrowCursor]; break; // avoid this on the mac, let the OS provide the beachball
 | 
			
		||||
            case IBeamCursor:           c = [NSCursor IBeamCursor]; break;
 | 
			
		||||
            case PointingHandCursor:    c = [NSCursor pointingHandCursor]; break;
 | 
			
		||||
            case LeftEdgeResizeCursor:  c = [NSCursor resizeLeftCursor]; break;
 | 
			
		||||
            case RightEdgeResizeCursor: c = [NSCursor resizeRightCursor]; break;
 | 
			
		||||
            case CrosshairCursor:       c = [NSCursor crosshairCursor]; break;
 | 
			
		||||
            NSCursor* c = nil;
 | 
			
		||||
 | 
			
		||||
            case CopyingCursor:
 | 
			
		||||
            switch (type)
 | 
			
		||||
            {
 | 
			
		||||
                c = [NSCursor dragCopyCursor];
 | 
			
		||||
                break;
 | 
			
		||||
                case NormalCursor:
 | 
			
		||||
                case ParentCursor:          c = [NSCursor arrowCursor]; break;
 | 
			
		||||
                case NoCursor:              return createCursor ({ ScaledImage (Image (Image::ARGB, 8, 8, true)), {} });
 | 
			
		||||
                case DraggingHandCursor:    c = [NSCursor openHandCursor]; break;
 | 
			
		||||
                case WaitCursor:            c = [NSCursor arrowCursor]; break; // avoid this on the mac, let the OS provide the beachball
 | 
			
		||||
                case IBeamCursor:           c = [NSCursor IBeamCursor]; break;
 | 
			
		||||
                case PointingHandCursor:    c = [NSCursor pointingHandCursor]; break;
 | 
			
		||||
                case LeftEdgeResizeCursor:  c = [NSCursor resizeLeftCursor]; break;
 | 
			
		||||
                case RightEdgeResizeCursor: c = [NSCursor resizeRightCursor]; break;
 | 
			
		||||
                case CrosshairCursor:       c = [NSCursor crosshairCursor]; break;
 | 
			
		||||
 | 
			
		||||
                case CopyingCursor:
 | 
			
		||||
                {
 | 
			
		||||
                    c = [NSCursor dragCopyCursor];
 | 
			
		||||
                    break;
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
                case UpDownResizeCursor:
 | 
			
		||||
                case TopEdgeResizeCursor:
 | 
			
		||||
                case BottomEdgeResizeCursor:
 | 
			
		||||
                    if (NSCursor* m = fromHIServices ("resizenorthsouth"))
 | 
			
		||||
                        return m;
 | 
			
		||||
 | 
			
		||||
                    c = [NSCursor resizeUpDownCursor];
 | 
			
		||||
                    break;
 | 
			
		||||
 | 
			
		||||
                case LeftRightResizeCursor:
 | 
			
		||||
                    if (NSCursor* m = fromHIServices ("resizeeastwest"))
 | 
			
		||||
                        return m;
 | 
			
		||||
 | 
			
		||||
                    c = [NSCursor resizeLeftRightCursor];
 | 
			
		||||
                    break;
 | 
			
		||||
 | 
			
		||||
                case TopLeftCornerResizeCursor:
 | 
			
		||||
                case BottomRightCornerResizeCursor:
 | 
			
		||||
                    return fromHIServices ("resizenorthwestsoutheast");
 | 
			
		||||
 | 
			
		||||
                case TopRightCornerResizeCursor:
 | 
			
		||||
                case BottomLeftCornerResizeCursor:
 | 
			
		||||
                    return fromHIServices ("resizenortheastsouthwest");
 | 
			
		||||
 | 
			
		||||
                case UpDownLeftRightResizeCursor:
 | 
			
		||||
                    return fromHIServices ("move");
 | 
			
		||||
 | 
			
		||||
                case NumStandardCursorTypes:
 | 
			
		||||
                default:
 | 
			
		||||
                    jassertfalse;
 | 
			
		||||
                    break;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            case UpDownResizeCursor:
 | 
			
		||||
            case TopEdgeResizeCursor:
 | 
			
		||||
            case BottomEdgeResizeCursor:
 | 
			
		||||
                if (void* m = MouseCursorHelpers::fromHIServices ("resizenorthsouth"))
 | 
			
		||||
                    return m;
 | 
			
		||||
 | 
			
		||||
                c = [NSCursor resizeUpDownCursor];
 | 
			
		||||
                break;
 | 
			
		||||
 | 
			
		||||
            case LeftRightResizeCursor:
 | 
			
		||||
                if (void* m = MouseCursorHelpers::fromHIServices ("resizeeastwest"))
 | 
			
		||||
                    return m;
 | 
			
		||||
 | 
			
		||||
                c = [NSCursor resizeLeftRightCursor];
 | 
			
		||||
                break;
 | 
			
		||||
 | 
			
		||||
            case TopLeftCornerResizeCursor:
 | 
			
		||||
            case BottomRightCornerResizeCursor:
 | 
			
		||||
                return MouseCursorHelpers::fromHIServices ("resizenorthwestsoutheast");
 | 
			
		||||
 | 
			
		||||
            case TopRightCornerResizeCursor:
 | 
			
		||||
            case BottomLeftCornerResizeCursor:
 | 
			
		||||
                return MouseCursorHelpers::fromHIServices ("resizenortheastsouthwest");
 | 
			
		||||
 | 
			
		||||
            case UpDownLeftRightResizeCursor:
 | 
			
		||||
                return MouseCursorHelpers::fromHIServices ("move");
 | 
			
		||||
 | 
			
		||||
            case NumStandardCursorTypes:
 | 
			
		||||
            default:
 | 
			
		||||
                jassertfalse;
 | 
			
		||||
                break;
 | 
			
		||||
            [c retain];
 | 
			
		||||
            return c;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        [c retain];
 | 
			
		||||
        return c;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void MouseCursor::deleteMouseCursor (void* const cursorHandle, const bool /*isStandard*/)
 | 
			
		||||
{
 | 
			
		||||
    [((NSCursor*) cursorHandle) release];
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void MouseCursor::showInWindow (ComponentPeer*) const
 | 
			
		||||
{
 | 
			
		||||
    auto c = (NSCursor*) getHandle();
 | 
			
		||||
 | 
			
		||||
    if (c == nil)
 | 
			
		||||
        c = [NSCursor arrowCursor];
 | 
			
		||||
 | 
			
		||||
    [c set];
 | 
			
		||||
}
 | 
			
		||||
    NSCursor* cursorHandle;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
#else
 | 
			
		||||
 | 
			
		||||
void* CustomMouseCursorInfo::create() const                                              { return nullptr; }
 | 
			
		||||
void* MouseCursor::createStandardMouseCursor (MouseCursor::StandardCursorType)           { return nullptr; }
 | 
			
		||||
void MouseCursor::deleteMouseCursor (void*, bool)                                        {}
 | 
			
		||||
void MouseCursor::showInWindow (ComponentPeer*) const                                    {}
 | 
			
		||||
class MouseCursor::PlatformSpecificHandle
 | 
			
		||||
{
 | 
			
		||||
public:
 | 
			
		||||
    PlatformSpecificHandle (const MouseCursor::StandardCursorType)      {}
 | 
			
		||||
    PlatformSpecificHandle (const CustomMouseCursorInfo&)               {}
 | 
			
		||||
 | 
			
		||||
    static void showInWindow (PlatformSpecificHandle*, ComponentPeer*)  {}
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							@@ -2,15 +2,15 @@
 | 
			
		||||
  ==============================================================================
 | 
			
		||||
 | 
			
		||||
   This file is part of the JUCE library.
 | 
			
		||||
   Copyright (c) 2020 - Raw Material Software Limited
 | 
			
		||||
   Copyright (c) 2022 - Raw Material Software Limited
 | 
			
		||||
 | 
			
		||||
   JUCE is an open source library subject to commercial or open-source
 | 
			
		||||
   licensing.
 | 
			
		||||
 | 
			
		||||
   By using JUCE, you agree to the terms of both the JUCE 6 End-User License
 | 
			
		||||
   Agreement and JUCE Privacy Policy (both effective as of the 16th June 2020).
 | 
			
		||||
   By using JUCE, you agree to the terms of both the JUCE 7 End-User License
 | 
			
		||||
   Agreement and JUCE Privacy Policy.
 | 
			
		||||
 | 
			
		||||
   End User License Agreement: www.juce.com/juce-6-licence
 | 
			
		||||
   End User License Agreement: www.juce.com/juce-7-licence
 | 
			
		||||
   Privacy Policy: www.juce.com/juce-privacy-policy
 | 
			
		||||
 | 
			
		||||
   Or: You may also use this code under the terms of the GPL v3 (see
 | 
			
		||||
@@ -43,7 +43,15 @@ public:
 | 
			
		||||
 | 
			
		||||
    int getResult() const
 | 
			
		||||
    {
 | 
			
		||||
        switch (getRawResult())
 | 
			
		||||
        return convertResult ([getAlert() runModal]);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    using AsyncUpdater::triggerAsyncUpdate;
 | 
			
		||||
 | 
			
		||||
private:
 | 
			
		||||
    static int convertResult (NSModalResponse response)
 | 
			
		||||
    {
 | 
			
		||||
        switch (response)
 | 
			
		||||
        {
 | 
			
		||||
            case NSAlertFirstButtonReturn:   return 0;
 | 
			
		||||
            case NSAlertSecondButtonReturn:  return 1;
 | 
			
		||||
@@ -55,15 +63,37 @@ public:
 | 
			
		||||
        return 0;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    using AsyncUpdater::triggerAsyncUpdate;
 | 
			
		||||
 | 
			
		||||
private:
 | 
			
		||||
    void handleAsyncUpdate() override
 | 
			
		||||
    {
 | 
			
		||||
        auto result = getResult();
 | 
			
		||||
        if (auto* comp = options.getAssociatedComponent())
 | 
			
		||||
        {
 | 
			
		||||
            if (auto* peer = comp->getPeer())
 | 
			
		||||
            {
 | 
			
		||||
                if (auto* view = static_cast<NSView*> (peer->getNativeHandle()))
 | 
			
		||||
                {
 | 
			
		||||
                    if (auto* window = [view window])
 | 
			
		||||
                    {
 | 
			
		||||
                        if (@available (macOS 10.9, *))
 | 
			
		||||
                        {
 | 
			
		||||
                            [getAlert() beginSheetModalForWindow: window completionHandler: ^(NSModalResponse result)
 | 
			
		||||
                            {
 | 
			
		||||
                                handleModalFinished (result);
 | 
			
		||||
                            }];
 | 
			
		||||
 | 
			
		||||
                            return;
 | 
			
		||||
                        }
 | 
			
		||||
                    }
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        handleModalFinished ([getAlert() runModal]);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    void handleModalFinished (NSModalResponse result)
 | 
			
		||||
    {
 | 
			
		||||
        if (callback != nullptr)
 | 
			
		||||
            callback->modalStateFinished (result);
 | 
			
		||||
            callback->modalStateFinished (convertResult (result));
 | 
			
		||||
 | 
			
		||||
        delete this;
 | 
			
		||||
    }
 | 
			
		||||
@@ -74,7 +104,7 @@ private:
 | 
			
		||||
            [alert addButtonWithTitle: juceStringToNS (button)];
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    NSInteger getRawResult() const
 | 
			
		||||
    NSAlert* getAlert() const
 | 
			
		||||
    {
 | 
			
		||||
        NSAlert* alert = [[[NSAlert alloc] init] autorelease];
 | 
			
		||||
 | 
			
		||||
@@ -82,7 +112,7 @@ private:
 | 
			
		||||
        [alert setInformativeText: juceStringToNS (options.getMessage())];
 | 
			
		||||
 | 
			
		||||
        [alert setAlertStyle: options.getIconType() == MessageBoxIconType::WarningIcon ? NSAlertStyleCritical
 | 
			
		||||
                                                                                                : NSAlertStyleInformational];
 | 
			
		||||
                                                                                       : NSAlertStyleInformational];
 | 
			
		||||
 | 
			
		||||
        const auto button1Text = options.getButtonText (0);
 | 
			
		||||
 | 
			
		||||
@@ -90,7 +120,7 @@ private:
 | 
			
		||||
        addButton (alert, options.getButtonText (1));
 | 
			
		||||
        addButton (alert, options.getButtonText (2));
 | 
			
		||||
 | 
			
		||||
        return [alert runModal];
 | 
			
		||||
        return alert;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    MessageBoxOptions options;
 | 
			
		||||
@@ -125,13 +155,14 @@ static int showDialog (const MessageBoxOptions& options,
 | 
			
		||||
#if JUCE_MODAL_LOOPS_PERMITTED
 | 
			
		||||
void JUCE_CALLTYPE NativeMessageBox::showMessageBox (MessageBoxIconType iconType,
 | 
			
		||||
                                                     const String& title, const String& message,
 | 
			
		||||
                                                     Component* /*associatedComponent*/)
 | 
			
		||||
                                                     Component* associatedComponent)
 | 
			
		||||
{
 | 
			
		||||
    showDialog (MessageBoxOptions()
 | 
			
		||||
                 .withIconType (iconType)
 | 
			
		||||
                 .withTitle (title)
 | 
			
		||||
                 .withMessage (message)
 | 
			
		||||
                 .withButton (TRANS("OK")),
 | 
			
		||||
                 .withButton (TRANS("OK"))
 | 
			
		||||
                 .withAssociatedComponent (associatedComponent),
 | 
			
		||||
                nullptr, AlertWindowMappings::messageBox);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@@ -143,20 +174,21 @@ int JUCE_CALLTYPE NativeMessageBox::show (const MessageBoxOptions& options)
 | 
			
		||||
 | 
			
		||||
void JUCE_CALLTYPE NativeMessageBox::showMessageBoxAsync (MessageBoxIconType iconType,
 | 
			
		||||
                                                          const String& title, const String& message,
 | 
			
		||||
                                                          Component* /*associatedComponent*/,
 | 
			
		||||
                                                          Component* associatedComponent,
 | 
			
		||||
                                                          ModalComponentManager::Callback* callback)
 | 
			
		||||
{
 | 
			
		||||
    showDialog (MessageBoxOptions()
 | 
			
		||||
                  .withIconType (iconType)
 | 
			
		||||
                  .withTitle (title)
 | 
			
		||||
                  .withMessage (message)
 | 
			
		||||
                  .withButton (TRANS("OK")),
 | 
			
		||||
                  .withButton (TRANS("OK"))
 | 
			
		||||
                  .withAssociatedComponent (associatedComponent),
 | 
			
		||||
                callback, AlertWindowMappings::messageBox);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
bool JUCE_CALLTYPE NativeMessageBox::showOkCancelBox (MessageBoxIconType iconType,
 | 
			
		||||
                                                      const String& title, const String& message,
 | 
			
		||||
                                                      Component* /*associatedComponent*/,
 | 
			
		||||
                                                      Component* associatedComponent,
 | 
			
		||||
                                                      ModalComponentManager::Callback* callback)
 | 
			
		||||
{
 | 
			
		||||
    return showDialog (MessageBoxOptions()
 | 
			
		||||
@@ -164,13 +196,14 @@ bool JUCE_CALLTYPE NativeMessageBox::showOkCancelBox (MessageBoxIconType iconTyp
 | 
			
		||||
                         .withTitle (title)
 | 
			
		||||
                         .withMessage (message)
 | 
			
		||||
                         .withButton (TRANS("OK"))
 | 
			
		||||
                         .withButton (TRANS("Cancel")),
 | 
			
		||||
                         .withButton (TRANS("Cancel"))
 | 
			
		||||
                         .withAssociatedComponent (associatedComponent),
 | 
			
		||||
                       callback, AlertWindowMappings::okCancel) != 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int JUCE_CALLTYPE NativeMessageBox::showYesNoCancelBox (MessageBoxIconType iconType,
 | 
			
		||||
                                                        const String& title, const String& message,
 | 
			
		||||
                                                        Component* /*associatedComponent*/,
 | 
			
		||||
                                                        Component* associatedComponent,
 | 
			
		||||
                                                        ModalComponentManager::Callback* callback)
 | 
			
		||||
{
 | 
			
		||||
    return showDialog (MessageBoxOptions()
 | 
			
		||||
@@ -179,13 +212,14 @@ int JUCE_CALLTYPE NativeMessageBox::showYesNoCancelBox (MessageBoxIconType iconT
 | 
			
		||||
                         .withMessage (message)
 | 
			
		||||
                         .withButton (TRANS("Yes"))
 | 
			
		||||
                         .withButton (TRANS("No"))
 | 
			
		||||
                         .withButton (TRANS("Cancel")),
 | 
			
		||||
                         .withButton (TRANS("Cancel"))
 | 
			
		||||
                         .withAssociatedComponent (associatedComponent),
 | 
			
		||||
                       callback, AlertWindowMappings::yesNoCancel);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int JUCE_CALLTYPE NativeMessageBox::showYesNoBox (MessageBoxIconType iconType,
 | 
			
		||||
                                                  const String& title, const String& message,
 | 
			
		||||
                                                  Component* /*associatedComponent*/,
 | 
			
		||||
                                                  Component* associatedComponent,
 | 
			
		||||
                                                  ModalComponentManager::Callback* callback)
 | 
			
		||||
{
 | 
			
		||||
    return showDialog (MessageBoxOptions()
 | 
			
		||||
@@ -193,7 +227,8 @@ int JUCE_CALLTYPE NativeMessageBox::showYesNoBox (MessageBoxIconType iconType,
 | 
			
		||||
                         .withTitle (title)
 | 
			
		||||
                         .withMessage (message)
 | 
			
		||||
                         .withButton (TRANS("Yes"))
 | 
			
		||||
                         .withButton (TRANS("No")),
 | 
			
		||||
                         .withButton (TRANS("No"))
 | 
			
		||||
                         .withAssociatedComponent (associatedComponent),
 | 
			
		||||
                       callback, AlertWindowMappings::okCancel);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@@ -239,11 +274,11 @@ struct NSDraggingSourceHelper   : public ObjCClass<NSObject<NSDraggingSource>>
 | 
			
		||||
        addIvar<String*> ("text");
 | 
			
		||||
        addIvar<NSDragOperation*> ("operation");
 | 
			
		||||
 | 
			
		||||
        addMethod (@selector (dealloc), dealloc, "v@:");
 | 
			
		||||
        addMethod (@selector (pasteboard:item:provideDataForType:), provideDataForType, "v@:@@@");
 | 
			
		||||
        addMethod (@selector (dealloc), dealloc);
 | 
			
		||||
        addMethod (@selector (pasteboard:item:provideDataForType:), provideDataForType);
 | 
			
		||||
 | 
			
		||||
        addMethod (@selector (draggingSession:sourceOperationMaskForDraggingContext:), sourceOperationMaskForDraggingContext, "c@:@@");
 | 
			
		||||
        addMethod (@selector (draggingSession:endedAtPoint:operation:), draggingSessionEnded, "v@:@@@");
 | 
			
		||||
        addMethod (@selector (draggingSession:sourceOperationMaskForDraggingContext:), sourceOperationMaskForDraggingContext);
 | 
			
		||||
        addMethod (@selector (draggingSession:endedAtPoint:operation:), draggingSessionEnded);
 | 
			
		||||
 | 
			
		||||
        addProtocol (@protocol (NSPasteboardItemDataProvider));
 | 
			
		||||
 | 
			
		||||
@@ -436,34 +471,19 @@ bool Desktop::isDarkModeActive() const
 | 
			
		||||
                isEqualToString: nsStringLiteral ("Dark")];
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
JUCE_BEGIN_IGNORE_WARNINGS_GCC_LIKE ("-Wundeclared-selector")
 | 
			
		||||
static const auto darkModeSelector = @selector (darkModeChanged:);
 | 
			
		||||
static const auto keyboardVisibilitySelector = @selector (keyboardVisiblityChanged:);
 | 
			
		||||
JUCE_END_IGNORE_WARNINGS_GCC_LIKE
 | 
			
		||||
 | 
			
		||||
class Desktop::NativeDarkModeChangeDetectorImpl
 | 
			
		||||
{
 | 
			
		||||
public:
 | 
			
		||||
    NativeDarkModeChangeDetectorImpl()
 | 
			
		||||
    {
 | 
			
		||||
        static DelegateClass delegateClass;
 | 
			
		||||
 | 
			
		||||
        delegate = [delegateClass.createInstance() init];
 | 
			
		||||
        object_setInstanceVariable (delegate, "owner", this);
 | 
			
		||||
 | 
			
		||||
        JUCE_BEGIN_IGNORE_WARNINGS_GCC_LIKE ("-Wundeclared-selector")
 | 
			
		||||
        [[NSDistributedNotificationCenter defaultCenter] addObserver: delegate
 | 
			
		||||
                                                            selector: @selector (darkModeChanged:)
 | 
			
		||||
                                                                name: @"AppleInterfaceThemeChangedNotification"
 | 
			
		||||
                                                              object: nil];
 | 
			
		||||
        JUCE_END_IGNORE_WARNINGS_GCC_LIKE
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    ~NativeDarkModeChangeDetectorImpl()
 | 
			
		||||
    {
 | 
			
		||||
        object_setInstanceVariable (delegate, "owner", nullptr);
 | 
			
		||||
        [[NSDistributedNotificationCenter defaultCenter] removeObserver: delegate];
 | 
			
		||||
        [delegate release];
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    void darkModeChanged()
 | 
			
		||||
    {
 | 
			
		||||
        Desktop::getInstance().darkModeChanged();
 | 
			
		||||
        delegate.reset ([delegateClass.createInstance() init]);
 | 
			
		||||
        observer.emplace (delegate.get(), darkModeSelector, @"AppleInterfaceThemeChangedNotification", nil);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
private:
 | 
			
		||||
@@ -471,23 +491,13 @@ private:
 | 
			
		||||
    {
 | 
			
		||||
        DelegateClass()  : ObjCClass<NSObject> ("JUCEDelegate_")
 | 
			
		||||
        {
 | 
			
		||||
            addIvar<NativeDarkModeChangeDetectorImpl*> ("owner");
 | 
			
		||||
 | 
			
		||||
            JUCE_BEGIN_IGNORE_WARNINGS_GCC_LIKE ("-Wundeclared-selector")
 | 
			
		||||
            addMethod (@selector (darkModeChanged:), darkModeChanged, "v@:@");
 | 
			
		||||
            JUCE_END_IGNORE_WARNINGS_GCC_LIKE
 | 
			
		||||
 | 
			
		||||
            addMethod (darkModeSelector, [] (id, SEL, NSNotification*) { Desktop::getInstance().darkModeChanged(); });
 | 
			
		||||
            registerClass();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        static void darkModeChanged (id self, SEL, NSNotification*)
 | 
			
		||||
        {
 | 
			
		||||
            if (auto* owner = getIvar<NativeDarkModeChangeDetectorImpl*> (self, "owner"))
 | 
			
		||||
                owner->darkModeChanged();
 | 
			
		||||
        }
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    id delegate = nil;
 | 
			
		||||
    NSUniquePtr<NSObject> delegate;
 | 
			
		||||
    Optional<ScopedNotificationCenterObserver> observer;
 | 
			
		||||
 | 
			
		||||
    JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (NativeDarkModeChangeDetectorImpl)
 | 
			
		||||
};
 | 
			
		||||
@@ -645,11 +655,16 @@ static void selectImageForDrawing (const Image& image)
 | 
			
		||||
    [NSGraphicsContext saveGraphicsState];
 | 
			
		||||
 | 
			
		||||
    if (@available (macOS 10.10, *))
 | 
			
		||||
    {
 | 
			
		||||
        [NSGraphicsContext setCurrentContext: [NSGraphicsContext graphicsContextWithCGContext: juce_getImageContext (image)
 | 
			
		||||
                                                                                      flipped: false]];
 | 
			
		||||
    else
 | 
			
		||||
        [NSGraphicsContext setCurrentContext: [NSGraphicsContext graphicsContextWithGraphicsPort: juce_getImageContext (image)
 | 
			
		||||
                                                                                         flipped: false]];
 | 
			
		||||
        return;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    JUCE_BEGIN_IGNORE_WARNINGS_GCC_LIKE ("-Wdeprecated-declarations")
 | 
			
		||||
    [NSGraphicsContext setCurrentContext: [NSGraphicsContext graphicsContextWithGraphicsPort: juce_getImageContext (image)
 | 
			
		||||
                                                                                     flipped: false]];
 | 
			
		||||
    JUCE_END_IGNORE_WARNINGS_GCC_LIKE
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void releaseImageAfterDrawing()
 | 
			
		||||
 
 | 
			
		||||
@@ -1,368 +1,368 @@
 | 
			
		||||
/*
 | 
			
		||||
  ==============================================================================
 | 
			
		||||
 | 
			
		||||
   This file is part of the JUCE library.
 | 
			
		||||
   Copyright (c) 2020 - Raw Material Software Limited
 | 
			
		||||
 | 
			
		||||
   JUCE is an open source library subject to commercial or open-source
 | 
			
		||||
   licensing.
 | 
			
		||||
 | 
			
		||||
   By using JUCE, you agree to the terms of both the JUCE 6 End-User License
 | 
			
		||||
   Agreement and JUCE Privacy Policy (both effective as of the 16th June 2020).
 | 
			
		||||
 | 
			
		||||
   End User License Agreement: www.juce.com/juce-6-licence
 | 
			
		||||
   Privacy Policy: www.juce.com/juce-privacy-policy
 | 
			
		||||
 | 
			
		||||
   Or: You may also use this code under the terms of the GPL v3 (see
 | 
			
		||||
   www.gnu.org/licenses).
 | 
			
		||||
 | 
			
		||||
   JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
 | 
			
		||||
   EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
 | 
			
		||||
   DISCLAIMED.
 | 
			
		||||
 | 
			
		||||
  ==============================================================================
 | 
			
		||||
*/
 | 
			
		||||
 | 
			
		||||
namespace juce
 | 
			
		||||
{
 | 
			
		||||
 | 
			
		||||
namespace DragAndDropHelpers
 | 
			
		||||
{
 | 
			
		||||
    //==============================================================================
 | 
			
		||||
    struct JuceDropSource   : public ComBaseClassHelper<IDropSource>
 | 
			
		||||
    {
 | 
			
		||||
        JuceDropSource() {}
 | 
			
		||||
 | 
			
		||||
        JUCE_COMRESULT QueryContinueDrag (BOOL escapePressed, DWORD keys) override
 | 
			
		||||
        {
 | 
			
		||||
            if (escapePressed)
 | 
			
		||||
                return DRAGDROP_S_CANCEL;
 | 
			
		||||
 | 
			
		||||
            if ((keys & (MK_LBUTTON | MK_RBUTTON)) == 0)
 | 
			
		||||
                return DRAGDROP_S_DROP;
 | 
			
		||||
 | 
			
		||||
            return S_OK;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        JUCE_COMRESULT GiveFeedback (DWORD) override
 | 
			
		||||
        {
 | 
			
		||||
            return DRAGDROP_S_USEDEFAULTCURSORS;
 | 
			
		||||
        }
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    //==============================================================================
 | 
			
		||||
    struct JuceEnumFormatEtc   : public ComBaseClassHelper<IEnumFORMATETC>
 | 
			
		||||
    {
 | 
			
		||||
        JuceEnumFormatEtc (const FORMATETC* f)  : format (f) {}
 | 
			
		||||
 | 
			
		||||
        JUCE_COMRESULT Clone (IEnumFORMATETC** result) override
 | 
			
		||||
        {
 | 
			
		||||
            if (result == nullptr)
 | 
			
		||||
                return E_POINTER;
 | 
			
		||||
 | 
			
		||||
            auto newOne = new JuceEnumFormatEtc (format);
 | 
			
		||||
            newOne->index = index;
 | 
			
		||||
            *result = newOne;
 | 
			
		||||
            return S_OK;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        JUCE_COMRESULT Next (ULONG celt, LPFORMATETC lpFormatEtc, ULONG* pceltFetched) override
 | 
			
		||||
        {
 | 
			
		||||
            if (pceltFetched != nullptr)
 | 
			
		||||
                *pceltFetched = 0;
 | 
			
		||||
            else if (celt != 1)
 | 
			
		||||
                return S_FALSE;
 | 
			
		||||
 | 
			
		||||
            if (index == 0 && celt > 0 && lpFormatEtc != nullptr)
 | 
			
		||||
            {
 | 
			
		||||
                copyFormatEtc (lpFormatEtc [0], *format);
 | 
			
		||||
                ++index;
 | 
			
		||||
 | 
			
		||||
                if (pceltFetched != nullptr)
 | 
			
		||||
                    *pceltFetched = 1;
 | 
			
		||||
 | 
			
		||||
                return S_OK;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            return S_FALSE;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        JUCE_COMRESULT Skip (ULONG celt) override
 | 
			
		||||
        {
 | 
			
		||||
            if (index + (int) celt >= 1)
 | 
			
		||||
                return S_FALSE;
 | 
			
		||||
 | 
			
		||||
            index += (int) celt;
 | 
			
		||||
            return S_OK;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        JUCE_COMRESULT Reset() override
 | 
			
		||||
        {
 | 
			
		||||
            index = 0;
 | 
			
		||||
            return S_OK;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
    private:
 | 
			
		||||
        const FORMATETC* const format;
 | 
			
		||||
        int index = 0;
 | 
			
		||||
 | 
			
		||||
        static void copyFormatEtc (FORMATETC& dest, const FORMATETC& source)
 | 
			
		||||
        {
 | 
			
		||||
            dest = source;
 | 
			
		||||
 | 
			
		||||
            if (source.ptd != nullptr)
 | 
			
		||||
            {
 | 
			
		||||
                dest.ptd = (DVTARGETDEVICE*) CoTaskMemAlloc (sizeof (DVTARGETDEVICE));
 | 
			
		||||
 | 
			
		||||
                if (dest.ptd != nullptr)
 | 
			
		||||
                    *(dest.ptd) = *(source.ptd);
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        JUCE_DECLARE_NON_COPYABLE (JuceEnumFormatEtc)
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    //==============================================================================
 | 
			
		||||
    class JuceDataObject  : public ComBaseClassHelper <IDataObject>
 | 
			
		||||
    {
 | 
			
		||||
    public:
 | 
			
		||||
        JuceDataObject (const FORMATETC* f, const STGMEDIUM* m)
 | 
			
		||||
            : format (f), medium (m)
 | 
			
		||||
        {
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        ~JuceDataObject()
 | 
			
		||||
        {
 | 
			
		||||
            jassert (refCount == 0);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        JUCE_COMRESULT GetData (FORMATETC* pFormatEtc, STGMEDIUM* pMedium)
 | 
			
		||||
        {
 | 
			
		||||
            if ((pFormatEtc->tymed & format->tymed) != 0
 | 
			
		||||
                 && pFormatEtc->cfFormat == format->cfFormat
 | 
			
		||||
                 && pFormatEtc->dwAspect == format->dwAspect)
 | 
			
		||||
            {
 | 
			
		||||
                pMedium->tymed = format->tymed;
 | 
			
		||||
                pMedium->pUnkForRelease = nullptr;
 | 
			
		||||
 | 
			
		||||
                if (format->tymed == TYMED_HGLOBAL)
 | 
			
		||||
                {
 | 
			
		||||
                    auto len = GlobalSize (medium->hGlobal);
 | 
			
		||||
                    void* const src = GlobalLock (medium->hGlobal);
 | 
			
		||||
                    void* const dst = GlobalAlloc (GMEM_FIXED, len);
 | 
			
		||||
 | 
			
		||||
                    if (src != nullptr && dst != nullptr)
 | 
			
		||||
                        memcpy (dst, src, len);
 | 
			
		||||
 | 
			
		||||
                    GlobalUnlock (medium->hGlobal);
 | 
			
		||||
 | 
			
		||||
                    pMedium->hGlobal = dst;
 | 
			
		||||
                    return S_OK;
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            return DV_E_FORMATETC;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        JUCE_COMRESULT QueryGetData (FORMATETC* f)
 | 
			
		||||
        {
 | 
			
		||||
            if (f == nullptr)
 | 
			
		||||
                return E_INVALIDARG;
 | 
			
		||||
 | 
			
		||||
            if (f->tymed == format->tymed
 | 
			
		||||
                  && f->cfFormat == format->cfFormat
 | 
			
		||||
                  && f->dwAspect == format->dwAspect)
 | 
			
		||||
                return S_OK;
 | 
			
		||||
 | 
			
		||||
            return DV_E_FORMATETC;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        JUCE_COMRESULT GetCanonicalFormatEtc (FORMATETC*, FORMATETC* pFormatEtcOut)
 | 
			
		||||
        {
 | 
			
		||||
            pFormatEtcOut->ptd = nullptr;
 | 
			
		||||
            return E_NOTIMPL;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        JUCE_COMRESULT EnumFormatEtc (DWORD direction, IEnumFORMATETC** result)
 | 
			
		||||
        {
 | 
			
		||||
            if (result == nullptr)
 | 
			
		||||
                return E_POINTER;
 | 
			
		||||
 | 
			
		||||
            if (direction == DATADIR_GET)
 | 
			
		||||
            {
 | 
			
		||||
                *result = new JuceEnumFormatEtc (format);
 | 
			
		||||
                return S_OK;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            *result = nullptr;
 | 
			
		||||
            return E_NOTIMPL;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        JUCE_COMRESULT GetDataHere (FORMATETC*, STGMEDIUM*)                  { return DATA_E_FORMATETC; }
 | 
			
		||||
        JUCE_COMRESULT SetData (FORMATETC*, STGMEDIUM*, BOOL)                { return E_NOTIMPL; }
 | 
			
		||||
        JUCE_COMRESULT DAdvise (FORMATETC*, DWORD, IAdviseSink*, DWORD*)     { return OLE_E_ADVISENOTSUPPORTED; }
 | 
			
		||||
        JUCE_COMRESULT DUnadvise (DWORD)                                     { return E_NOTIMPL; }
 | 
			
		||||
        JUCE_COMRESULT EnumDAdvise (IEnumSTATDATA**)                         { return OLE_E_ADVISENOTSUPPORTED; }
 | 
			
		||||
 | 
			
		||||
    private:
 | 
			
		||||
        const FORMATETC* const format;
 | 
			
		||||
        const STGMEDIUM* const medium;
 | 
			
		||||
 | 
			
		||||
        JUCE_DECLARE_NON_COPYABLE (JuceDataObject)
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    //==============================================================================
 | 
			
		||||
    HDROP createHDrop (const StringArray& fileNames)
 | 
			
		||||
    {
 | 
			
		||||
        size_t totalBytes = 0;
 | 
			
		||||
        for (int i = fileNames.size(); --i >= 0;)
 | 
			
		||||
            totalBytes += CharPointer_UTF16::getBytesRequiredFor (fileNames[i].getCharPointer()) + sizeof (WCHAR);
 | 
			
		||||
 | 
			
		||||
        struct Deleter
 | 
			
		||||
        {
 | 
			
		||||
            void operator() (void* ptr) const noexcept { GlobalFree (ptr); }
 | 
			
		||||
        };
 | 
			
		||||
 | 
			
		||||
        auto hDrop = std::unique_ptr<void, Deleter> ((HDROP) GlobalAlloc (GMEM_MOVEABLE | GMEM_ZEROINIT, sizeof (DROPFILES) + totalBytes + 4));
 | 
			
		||||
 | 
			
		||||
        if (hDrop != nullptr)
 | 
			
		||||
        {
 | 
			
		||||
            auto pDropFiles = (LPDROPFILES) GlobalLock (hDrop.get());
 | 
			
		||||
 | 
			
		||||
            if (pDropFiles == nullptr)
 | 
			
		||||
                return nullptr;
 | 
			
		||||
 | 
			
		||||
            pDropFiles->pFiles = sizeof (DROPFILES);
 | 
			
		||||
            pDropFiles->fWide = true;
 | 
			
		||||
 | 
			
		||||
            auto* fname = reinterpret_cast<WCHAR*> (addBytesToPointer (pDropFiles, sizeof (DROPFILES)));
 | 
			
		||||
 | 
			
		||||
            for (int i = 0; i < fileNames.size(); ++i)
 | 
			
		||||
            {
 | 
			
		||||
                auto bytesWritten = fileNames[i].copyToUTF16 (fname, 2048);
 | 
			
		||||
                fname = reinterpret_cast<WCHAR*> (addBytesToPointer (fname, bytesWritten));
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            *fname = 0;
 | 
			
		||||
 | 
			
		||||
            GlobalUnlock (hDrop.get());
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        return static_cast<HDROP> (hDrop.release());
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    struct DragAndDropJob   : public ThreadPoolJob
 | 
			
		||||
    {
 | 
			
		||||
        DragAndDropJob (FORMATETC f, STGMEDIUM m, DWORD d, std::function<void()>&& cb)
 | 
			
		||||
            : ThreadPoolJob ("DragAndDrop"),
 | 
			
		||||
              format (f), medium (m), whatToDo (d),
 | 
			
		||||
              completionCallback (std::move (cb))
 | 
			
		||||
        {
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        JobStatus runJob() override
 | 
			
		||||
        {
 | 
			
		||||
            ignoreUnused (OleInitialize (nullptr));
 | 
			
		||||
 | 
			
		||||
            auto* source = new JuceDropSource();
 | 
			
		||||
            auto* data = new JuceDataObject (&format, &medium);
 | 
			
		||||
 | 
			
		||||
            DWORD effect;
 | 
			
		||||
            DoDragDrop (data, source, whatToDo, &effect);
 | 
			
		||||
 | 
			
		||||
            data->Release();
 | 
			
		||||
            source->Release();
 | 
			
		||||
 | 
			
		||||
            OleUninitialize();
 | 
			
		||||
 | 
			
		||||
            if (completionCallback != nullptr)
 | 
			
		||||
                MessageManager::callAsync (std::move (completionCallback));
 | 
			
		||||
 | 
			
		||||
            return jobHasFinished;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        FORMATETC format;
 | 
			
		||||
        STGMEDIUM medium;
 | 
			
		||||
        DWORD whatToDo;
 | 
			
		||||
 | 
			
		||||
        std::function<void()> completionCallback;
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    class ThreadPoolHolder   : private DeletedAtShutdown
 | 
			
		||||
    {
 | 
			
		||||
    public:
 | 
			
		||||
        ThreadPoolHolder() = default;
 | 
			
		||||
 | 
			
		||||
        ~ThreadPoolHolder()
 | 
			
		||||
        {
 | 
			
		||||
            // Wait forever if there's a job running. The user needs to cancel the transfer
 | 
			
		||||
            // in the GUI.
 | 
			
		||||
            pool.removeAllJobs (true, -1);
 | 
			
		||||
 | 
			
		||||
            clearSingletonInstance();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        JUCE_DECLARE_SINGLETON_SINGLETHREADED (ThreadPoolHolder, false)
 | 
			
		||||
 | 
			
		||||
        // We need to make sure we don't do simultaneous text and file drag and drops,
 | 
			
		||||
        // so use a pool that can only run a single job.
 | 
			
		||||
        ThreadPool pool { 1 };
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    JUCE_IMPLEMENT_SINGLETON (ThreadPoolHolder)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
//==============================================================================
 | 
			
		||||
bool DragAndDropContainer::performExternalDragDropOfFiles (const StringArray& files, const bool canMove,
 | 
			
		||||
                                                           Component*, std::function<void()> callback)
 | 
			
		||||
{
 | 
			
		||||
    if (files.isEmpty())
 | 
			
		||||
        return false;
 | 
			
		||||
 | 
			
		||||
    FORMATETC format = { CF_HDROP, nullptr, DVASPECT_CONTENT, -1, TYMED_HGLOBAL };
 | 
			
		||||
    STGMEDIUM medium = { TYMED_HGLOBAL, { nullptr }, nullptr };
 | 
			
		||||
 | 
			
		||||
    medium.hGlobal = DragAndDropHelpers::createHDrop (files);
 | 
			
		||||
 | 
			
		||||
    auto& pool = DragAndDropHelpers::ThreadPoolHolder::getInstance()->pool;
 | 
			
		||||
    pool.addJob (new DragAndDropHelpers::DragAndDropJob (format, medium,
 | 
			
		||||
                                                         canMove ? (DROPEFFECT_COPY | DROPEFFECT_MOVE) : DROPEFFECT_COPY,
 | 
			
		||||
                                                         std::move (callback)),
 | 
			
		||||
                true);
 | 
			
		||||
 | 
			
		||||
    return true;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
bool DragAndDropContainer::performExternalDragDropOfText (const String& text, Component*, std::function<void()> callback)
 | 
			
		||||
{
 | 
			
		||||
    if (text.isEmpty())
 | 
			
		||||
        return false;
 | 
			
		||||
 | 
			
		||||
    FORMATETC format = { CF_TEXT, nullptr, DVASPECT_CONTENT, -1, TYMED_HGLOBAL };
 | 
			
		||||
    STGMEDIUM medium = { TYMED_HGLOBAL, { nullptr }, nullptr };
 | 
			
		||||
 | 
			
		||||
    auto numBytes = CharPointer_UTF16::getBytesRequiredFor (text.getCharPointer());
 | 
			
		||||
 | 
			
		||||
    medium.hGlobal = GlobalAlloc (GMEM_MOVEABLE | GMEM_ZEROINIT, numBytes + 2);
 | 
			
		||||
 | 
			
		||||
    if (medium.hGlobal == nullptr)
 | 
			
		||||
        return false;
 | 
			
		||||
 | 
			
		||||
    auto* data = static_cast<WCHAR*> (GlobalLock (medium.hGlobal));
 | 
			
		||||
 | 
			
		||||
    text.copyToUTF16 (data, numBytes + 2);
 | 
			
		||||
    format.cfFormat = CF_UNICODETEXT;
 | 
			
		||||
 | 
			
		||||
    GlobalUnlock (medium.hGlobal);
 | 
			
		||||
 | 
			
		||||
    auto& pool = DragAndDropHelpers::ThreadPoolHolder::getInstance()->pool;
 | 
			
		||||
    pool.addJob (new DragAndDropHelpers::DragAndDropJob (format,
 | 
			
		||||
                                                        medium,
 | 
			
		||||
                                                        DROPEFFECT_COPY | DROPEFFECT_MOVE,
 | 
			
		||||
                                                        std::move (callback)),
 | 
			
		||||
                 true);
 | 
			
		||||
 | 
			
		||||
    return true;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
} // namespace juce
 | 
			
		||||
/*
 | 
			
		||||
  ==============================================================================
 | 
			
		||||
 | 
			
		||||
   This file is part of the JUCE library.
 | 
			
		||||
   Copyright (c) 2022 - Raw Material Software Limited
 | 
			
		||||
 | 
			
		||||
   JUCE is an open source library subject to commercial or open-source
 | 
			
		||||
   licensing.
 | 
			
		||||
 | 
			
		||||
   By using JUCE, you agree to the terms of both the JUCE 7 End-User License
 | 
			
		||||
   Agreement and JUCE Privacy Policy.
 | 
			
		||||
 | 
			
		||||
   End User License Agreement: www.juce.com/juce-7-licence
 | 
			
		||||
   Privacy Policy: www.juce.com/juce-privacy-policy
 | 
			
		||||
 | 
			
		||||
   Or: You may also use this code under the terms of the GPL v3 (see
 | 
			
		||||
   www.gnu.org/licenses).
 | 
			
		||||
 | 
			
		||||
   JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
 | 
			
		||||
   EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
 | 
			
		||||
   DISCLAIMED.
 | 
			
		||||
 | 
			
		||||
  ==============================================================================
 | 
			
		||||
*/
 | 
			
		||||
 | 
			
		||||
namespace juce
 | 
			
		||||
{
 | 
			
		||||
 | 
			
		||||
namespace DragAndDropHelpers
 | 
			
		||||
{
 | 
			
		||||
    //==============================================================================
 | 
			
		||||
    struct JuceDropSource   : public ComBaseClassHelper<IDropSource>
 | 
			
		||||
    {
 | 
			
		||||
        JuceDropSource() {}
 | 
			
		||||
 | 
			
		||||
        JUCE_COMRESULT QueryContinueDrag (BOOL escapePressed, DWORD keys) override
 | 
			
		||||
        {
 | 
			
		||||
            if (escapePressed)
 | 
			
		||||
                return DRAGDROP_S_CANCEL;
 | 
			
		||||
 | 
			
		||||
            if ((keys & (MK_LBUTTON | MK_RBUTTON)) == 0)
 | 
			
		||||
                return DRAGDROP_S_DROP;
 | 
			
		||||
 | 
			
		||||
            return S_OK;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        JUCE_COMRESULT GiveFeedback (DWORD) override
 | 
			
		||||
        {
 | 
			
		||||
            return DRAGDROP_S_USEDEFAULTCURSORS;
 | 
			
		||||
        }
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    //==============================================================================
 | 
			
		||||
    struct JuceEnumFormatEtc   : public ComBaseClassHelper<IEnumFORMATETC>
 | 
			
		||||
    {
 | 
			
		||||
        JuceEnumFormatEtc (const FORMATETC* f)  : format (f) {}
 | 
			
		||||
 | 
			
		||||
        JUCE_COMRESULT Clone (IEnumFORMATETC** result) override
 | 
			
		||||
        {
 | 
			
		||||
            if (result == nullptr)
 | 
			
		||||
                return E_POINTER;
 | 
			
		||||
 | 
			
		||||
            auto newOne = new JuceEnumFormatEtc (format);
 | 
			
		||||
            newOne->index = index;
 | 
			
		||||
            *result = newOne;
 | 
			
		||||
            return S_OK;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        JUCE_COMRESULT Next (ULONG celt, LPFORMATETC lpFormatEtc, ULONG* pceltFetched) override
 | 
			
		||||
        {
 | 
			
		||||
            if (pceltFetched != nullptr)
 | 
			
		||||
                *pceltFetched = 0;
 | 
			
		||||
            else if (celt != 1)
 | 
			
		||||
                return S_FALSE;
 | 
			
		||||
 | 
			
		||||
            if (index == 0 && celt > 0 && lpFormatEtc != nullptr)
 | 
			
		||||
            {
 | 
			
		||||
                copyFormatEtc (lpFormatEtc [0], *format);
 | 
			
		||||
                ++index;
 | 
			
		||||
 | 
			
		||||
                if (pceltFetched != nullptr)
 | 
			
		||||
                    *pceltFetched = 1;
 | 
			
		||||
 | 
			
		||||
                return S_OK;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            return S_FALSE;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        JUCE_COMRESULT Skip (ULONG celt) override
 | 
			
		||||
        {
 | 
			
		||||
            if (index + (int) celt >= 1)
 | 
			
		||||
                return S_FALSE;
 | 
			
		||||
 | 
			
		||||
            index += (int) celt;
 | 
			
		||||
            return S_OK;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        JUCE_COMRESULT Reset() override
 | 
			
		||||
        {
 | 
			
		||||
            index = 0;
 | 
			
		||||
            return S_OK;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
    private:
 | 
			
		||||
        const FORMATETC* const format;
 | 
			
		||||
        int index = 0;
 | 
			
		||||
 | 
			
		||||
        static void copyFormatEtc (FORMATETC& dest, const FORMATETC& source)
 | 
			
		||||
        {
 | 
			
		||||
            dest = source;
 | 
			
		||||
 | 
			
		||||
            if (source.ptd != nullptr)
 | 
			
		||||
            {
 | 
			
		||||
                dest.ptd = (DVTARGETDEVICE*) CoTaskMemAlloc (sizeof (DVTARGETDEVICE));
 | 
			
		||||
 | 
			
		||||
                if (dest.ptd != nullptr)
 | 
			
		||||
                    *(dest.ptd) = *(source.ptd);
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        JUCE_DECLARE_NON_COPYABLE (JuceEnumFormatEtc)
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    //==============================================================================
 | 
			
		||||
    class JuceDataObject  : public ComBaseClassHelper <IDataObject>
 | 
			
		||||
    {
 | 
			
		||||
    public:
 | 
			
		||||
        JuceDataObject (const FORMATETC* f, const STGMEDIUM* m)
 | 
			
		||||
            : format (f), medium (m)
 | 
			
		||||
        {
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        ~JuceDataObject()
 | 
			
		||||
        {
 | 
			
		||||
            jassert (refCount == 0);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        JUCE_COMRESULT GetData (FORMATETC* pFormatEtc, STGMEDIUM* pMedium)
 | 
			
		||||
        {
 | 
			
		||||
            if ((pFormatEtc->tymed & format->tymed) != 0
 | 
			
		||||
                 && pFormatEtc->cfFormat == format->cfFormat
 | 
			
		||||
                 && pFormatEtc->dwAspect == format->dwAspect)
 | 
			
		||||
            {
 | 
			
		||||
                pMedium->tymed = format->tymed;
 | 
			
		||||
                pMedium->pUnkForRelease = nullptr;
 | 
			
		||||
 | 
			
		||||
                if (format->tymed == TYMED_HGLOBAL)
 | 
			
		||||
                {
 | 
			
		||||
                    auto len = GlobalSize (medium->hGlobal);
 | 
			
		||||
                    void* const src = GlobalLock (medium->hGlobal);
 | 
			
		||||
                    void* const dst = GlobalAlloc (GMEM_FIXED, len);
 | 
			
		||||
 | 
			
		||||
                    if (src != nullptr && dst != nullptr)
 | 
			
		||||
                        memcpy (dst, src, len);
 | 
			
		||||
 | 
			
		||||
                    GlobalUnlock (medium->hGlobal);
 | 
			
		||||
 | 
			
		||||
                    pMedium->hGlobal = dst;
 | 
			
		||||
                    return S_OK;
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            return DV_E_FORMATETC;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        JUCE_COMRESULT QueryGetData (FORMATETC* f)
 | 
			
		||||
        {
 | 
			
		||||
            if (f == nullptr)
 | 
			
		||||
                return E_INVALIDARG;
 | 
			
		||||
 | 
			
		||||
            if (f->tymed == format->tymed
 | 
			
		||||
                  && f->cfFormat == format->cfFormat
 | 
			
		||||
                  && f->dwAspect == format->dwAspect)
 | 
			
		||||
                return S_OK;
 | 
			
		||||
 | 
			
		||||
            return DV_E_FORMATETC;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        JUCE_COMRESULT GetCanonicalFormatEtc (FORMATETC*, FORMATETC* pFormatEtcOut)
 | 
			
		||||
        {
 | 
			
		||||
            pFormatEtcOut->ptd = nullptr;
 | 
			
		||||
            return E_NOTIMPL;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        JUCE_COMRESULT EnumFormatEtc (DWORD direction, IEnumFORMATETC** result)
 | 
			
		||||
        {
 | 
			
		||||
            if (result == nullptr)
 | 
			
		||||
                return E_POINTER;
 | 
			
		||||
 | 
			
		||||
            if (direction == DATADIR_GET)
 | 
			
		||||
            {
 | 
			
		||||
                *result = new JuceEnumFormatEtc (format);
 | 
			
		||||
                return S_OK;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            *result = nullptr;
 | 
			
		||||
            return E_NOTIMPL;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        JUCE_COMRESULT GetDataHere (FORMATETC*, STGMEDIUM*)                  { return DATA_E_FORMATETC; }
 | 
			
		||||
        JUCE_COMRESULT SetData (FORMATETC*, STGMEDIUM*, BOOL)                { return E_NOTIMPL; }
 | 
			
		||||
        JUCE_COMRESULT DAdvise (FORMATETC*, DWORD, IAdviseSink*, DWORD*)     { return OLE_E_ADVISENOTSUPPORTED; }
 | 
			
		||||
        JUCE_COMRESULT DUnadvise (DWORD)                                     { return E_NOTIMPL; }
 | 
			
		||||
        JUCE_COMRESULT EnumDAdvise (IEnumSTATDATA**)                         { return OLE_E_ADVISENOTSUPPORTED; }
 | 
			
		||||
 | 
			
		||||
    private:
 | 
			
		||||
        const FORMATETC* const format;
 | 
			
		||||
        const STGMEDIUM* const medium;
 | 
			
		||||
 | 
			
		||||
        JUCE_DECLARE_NON_COPYABLE (JuceDataObject)
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    //==============================================================================
 | 
			
		||||
    static HDROP createHDrop (const StringArray& fileNames)
 | 
			
		||||
    {
 | 
			
		||||
        size_t totalBytes = 0;
 | 
			
		||||
        for (int i = fileNames.size(); --i >= 0;)
 | 
			
		||||
            totalBytes += CharPointer_UTF16::getBytesRequiredFor (fileNames[i].getCharPointer()) + sizeof (WCHAR);
 | 
			
		||||
 | 
			
		||||
        struct Deleter
 | 
			
		||||
        {
 | 
			
		||||
            void operator() (void* ptr) const noexcept { GlobalFree (ptr); }
 | 
			
		||||
        };
 | 
			
		||||
 | 
			
		||||
        auto hDrop = std::unique_ptr<void, Deleter> ((HDROP) GlobalAlloc (GMEM_MOVEABLE | GMEM_ZEROINIT, sizeof (DROPFILES) + totalBytes + 4));
 | 
			
		||||
 | 
			
		||||
        if (hDrop != nullptr)
 | 
			
		||||
        {
 | 
			
		||||
            auto pDropFiles = (LPDROPFILES) GlobalLock (hDrop.get());
 | 
			
		||||
 | 
			
		||||
            if (pDropFiles == nullptr)
 | 
			
		||||
                return nullptr;
 | 
			
		||||
 | 
			
		||||
            pDropFiles->pFiles = sizeof (DROPFILES);
 | 
			
		||||
            pDropFiles->fWide = true;
 | 
			
		||||
 | 
			
		||||
            auto* fname = reinterpret_cast<WCHAR*> (addBytesToPointer (pDropFiles, sizeof (DROPFILES)));
 | 
			
		||||
 | 
			
		||||
            for (int i = 0; i < fileNames.size(); ++i)
 | 
			
		||||
            {
 | 
			
		||||
                auto bytesWritten = fileNames[i].copyToUTF16 (fname, 2048);
 | 
			
		||||
                fname = reinterpret_cast<WCHAR*> (addBytesToPointer (fname, bytesWritten));
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            *fname = 0;
 | 
			
		||||
 | 
			
		||||
            GlobalUnlock (hDrop.get());
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        return static_cast<HDROP> (hDrop.release());
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    struct DragAndDropJob   : public ThreadPoolJob
 | 
			
		||||
    {
 | 
			
		||||
        DragAndDropJob (FORMATETC f, STGMEDIUM m, DWORD d, std::function<void()>&& cb)
 | 
			
		||||
            : ThreadPoolJob ("DragAndDrop"),
 | 
			
		||||
              format (f), medium (m), whatToDo (d),
 | 
			
		||||
              completionCallback (std::move (cb))
 | 
			
		||||
        {
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        JobStatus runJob() override
 | 
			
		||||
        {
 | 
			
		||||
            ignoreUnused (OleInitialize (nullptr));
 | 
			
		||||
 | 
			
		||||
            auto* source = new JuceDropSource();
 | 
			
		||||
            auto* data = new JuceDataObject (&format, &medium);
 | 
			
		||||
 | 
			
		||||
            DWORD effect;
 | 
			
		||||
            DoDragDrop (data, source, whatToDo, &effect);
 | 
			
		||||
 | 
			
		||||
            data->Release();
 | 
			
		||||
            source->Release();
 | 
			
		||||
 | 
			
		||||
            OleUninitialize();
 | 
			
		||||
 | 
			
		||||
            if (completionCallback != nullptr)
 | 
			
		||||
                MessageManager::callAsync (std::move (completionCallback));
 | 
			
		||||
 | 
			
		||||
            return jobHasFinished;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        FORMATETC format;
 | 
			
		||||
        STGMEDIUM medium;
 | 
			
		||||
        DWORD whatToDo;
 | 
			
		||||
 | 
			
		||||
        std::function<void()> completionCallback;
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    class ThreadPoolHolder   : private DeletedAtShutdown
 | 
			
		||||
    {
 | 
			
		||||
    public:
 | 
			
		||||
        ThreadPoolHolder() = default;
 | 
			
		||||
 | 
			
		||||
        ~ThreadPoolHolder()
 | 
			
		||||
        {
 | 
			
		||||
            // Wait forever if there's a job running. The user needs to cancel the transfer
 | 
			
		||||
            // in the GUI.
 | 
			
		||||
            pool.removeAllJobs (true, -1);
 | 
			
		||||
 | 
			
		||||
            clearSingletonInstance();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        JUCE_DECLARE_SINGLETON_SINGLETHREADED (ThreadPoolHolder, false)
 | 
			
		||||
 | 
			
		||||
        // We need to make sure we don't do simultaneous text and file drag and drops,
 | 
			
		||||
        // so use a pool that can only run a single job.
 | 
			
		||||
        ThreadPool pool { 1 };
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    JUCE_IMPLEMENT_SINGLETON (ThreadPoolHolder)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
//==============================================================================
 | 
			
		||||
bool DragAndDropContainer::performExternalDragDropOfFiles (const StringArray& files, const bool canMove,
 | 
			
		||||
                                                           Component*, std::function<void()> callback)
 | 
			
		||||
{
 | 
			
		||||
    if (files.isEmpty())
 | 
			
		||||
        return false;
 | 
			
		||||
 | 
			
		||||
    FORMATETC format = { CF_HDROP, nullptr, DVASPECT_CONTENT, -1, TYMED_HGLOBAL };
 | 
			
		||||
    STGMEDIUM medium = { TYMED_HGLOBAL, { nullptr }, nullptr };
 | 
			
		||||
 | 
			
		||||
    medium.hGlobal = DragAndDropHelpers::createHDrop (files);
 | 
			
		||||
 | 
			
		||||
    auto& pool = DragAndDropHelpers::ThreadPoolHolder::getInstance()->pool;
 | 
			
		||||
    pool.addJob (new DragAndDropHelpers::DragAndDropJob (format, medium,
 | 
			
		||||
                                                         canMove ? (DROPEFFECT_COPY | DROPEFFECT_MOVE) : DROPEFFECT_COPY,
 | 
			
		||||
                                                         std::move (callback)),
 | 
			
		||||
                true);
 | 
			
		||||
 | 
			
		||||
    return true;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
bool DragAndDropContainer::performExternalDragDropOfText (const String& text, Component*, std::function<void()> callback)
 | 
			
		||||
{
 | 
			
		||||
    if (text.isEmpty())
 | 
			
		||||
        return false;
 | 
			
		||||
 | 
			
		||||
    FORMATETC format = { CF_TEXT, nullptr, DVASPECT_CONTENT, -1, TYMED_HGLOBAL };
 | 
			
		||||
    STGMEDIUM medium = { TYMED_HGLOBAL, { nullptr }, nullptr };
 | 
			
		||||
 | 
			
		||||
    auto numBytes = CharPointer_UTF16::getBytesRequiredFor (text.getCharPointer());
 | 
			
		||||
 | 
			
		||||
    medium.hGlobal = GlobalAlloc (GMEM_MOVEABLE | GMEM_ZEROINIT, numBytes + 2);
 | 
			
		||||
 | 
			
		||||
    if (medium.hGlobal == nullptr)
 | 
			
		||||
        return false;
 | 
			
		||||
 | 
			
		||||
    auto* data = static_cast<WCHAR*> (GlobalLock (medium.hGlobal));
 | 
			
		||||
 | 
			
		||||
    text.copyToUTF16 (data, numBytes + 2);
 | 
			
		||||
    format.cfFormat = CF_UNICODETEXT;
 | 
			
		||||
 | 
			
		||||
    GlobalUnlock (medium.hGlobal);
 | 
			
		||||
 | 
			
		||||
    auto& pool = DragAndDropHelpers::ThreadPoolHolder::getInstance()->pool;
 | 
			
		||||
    pool.addJob (new DragAndDropHelpers::DragAndDropJob (format,
 | 
			
		||||
                                                        medium,
 | 
			
		||||
                                                        DROPEFFECT_COPY | DROPEFFECT_MOVE,
 | 
			
		||||
                                                        std::move (callback)),
 | 
			
		||||
                 true);
 | 
			
		||||
 | 
			
		||||
    return true;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
} // namespace juce
 | 
			
		||||
 
 | 
			
		||||
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							@@ -1,43 +1,43 @@
 | 
			
		||||
/*
 | 
			
		||||
  ==============================================================================
 | 
			
		||||
 | 
			
		||||
   This file is part of the JUCE library.
 | 
			
		||||
   Copyright (c) 2020 - Raw Material Software Limited
 | 
			
		||||
 | 
			
		||||
   JUCE is an open source library subject to commercial or open-source
 | 
			
		||||
   licensing.
 | 
			
		||||
 | 
			
		||||
   By using JUCE, you agree to the terms of both the JUCE 6 End-User License
 | 
			
		||||
   Agreement and JUCE Privacy Policy (both effective as of the 16th June 2020).
 | 
			
		||||
 | 
			
		||||
   End User License Agreement: www.juce.com/juce-6-licence
 | 
			
		||||
   Privacy Policy: www.juce.com/juce-privacy-policy
 | 
			
		||||
 | 
			
		||||
   Or: You may also use this code under the terms of the GPL v3 (see
 | 
			
		||||
   www.gnu.org/licenses).
 | 
			
		||||
 | 
			
		||||
   JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
 | 
			
		||||
   EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
 | 
			
		||||
   DISCLAIMED.
 | 
			
		||||
 | 
			
		||||
  ==============================================================================
 | 
			
		||||
*/
 | 
			
		||||
 | 
			
		||||
namespace juce
 | 
			
		||||
{
 | 
			
		||||
 | 
			
		||||
//==============================================================================
 | 
			
		||||
class ScopedThreadDPIAwarenessSetter
 | 
			
		||||
{
 | 
			
		||||
public:
 | 
			
		||||
    explicit ScopedThreadDPIAwarenessSetter (void* nativeWindow);
 | 
			
		||||
    ~ScopedThreadDPIAwarenessSetter();
 | 
			
		||||
 | 
			
		||||
private:
 | 
			
		||||
    class NativeImpl;
 | 
			
		||||
    std::unique_ptr<NativeImpl> pimpl;
 | 
			
		||||
 | 
			
		||||
    JUCE_LEAK_DETECTOR (ScopedThreadDPIAwarenessSetter)
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
} // namespace juce
 | 
			
		||||
/*
 | 
			
		||||
  ==============================================================================
 | 
			
		||||
 | 
			
		||||
   This file is part of the JUCE library.
 | 
			
		||||
   Copyright (c) 2022 - Raw Material Software Limited
 | 
			
		||||
 | 
			
		||||
   JUCE is an open source library subject to commercial or open-source
 | 
			
		||||
   licensing.
 | 
			
		||||
 | 
			
		||||
   By using JUCE, you agree to the terms of both the JUCE 7 End-User License
 | 
			
		||||
   Agreement and JUCE Privacy Policy.
 | 
			
		||||
 | 
			
		||||
   End User License Agreement: www.juce.com/juce-7-licence
 | 
			
		||||
   Privacy Policy: www.juce.com/juce-privacy-policy
 | 
			
		||||
 | 
			
		||||
   Or: You may also use this code under the terms of the GPL v3 (see
 | 
			
		||||
   www.gnu.org/licenses).
 | 
			
		||||
 | 
			
		||||
   JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
 | 
			
		||||
   EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
 | 
			
		||||
   DISCLAIMED.
 | 
			
		||||
 | 
			
		||||
  ==============================================================================
 | 
			
		||||
*/
 | 
			
		||||
 | 
			
		||||
namespace juce
 | 
			
		||||
{
 | 
			
		||||
 | 
			
		||||
//==============================================================================
 | 
			
		||||
class ScopedThreadDPIAwarenessSetter
 | 
			
		||||
{
 | 
			
		||||
public:
 | 
			
		||||
    explicit ScopedThreadDPIAwarenessSetter (void* nativeWindow);
 | 
			
		||||
    ~ScopedThreadDPIAwarenessSetter();
 | 
			
		||||
 | 
			
		||||
private:
 | 
			
		||||
    class NativeImpl;
 | 
			
		||||
    std::unique_ptr<NativeImpl> pimpl;
 | 
			
		||||
 | 
			
		||||
    JUCE_LEAK_DETECTOR (ScopedThreadDPIAwarenessSetter)
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
} // namespace juce
 | 
			
		||||
 
 | 
			
		||||
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							@@ -1,240 +1,240 @@
 | 
			
		||||
/*
 | 
			
		||||
  ==============================================================================
 | 
			
		||||
 | 
			
		||||
   This file is part of the JUCE library.
 | 
			
		||||
   Copyright (c) 2020 - Raw Material Software Limited
 | 
			
		||||
 | 
			
		||||
   JUCE is an open source library subject to commercial or open-source
 | 
			
		||||
   licensing.
 | 
			
		||||
 | 
			
		||||
   By using JUCE, you agree to the terms of both the JUCE 6 End-User License
 | 
			
		||||
   Agreement and JUCE Privacy Policy (both effective as of the 16th June 2020).
 | 
			
		||||
 | 
			
		||||
   End User License Agreement: www.juce.com/juce-6-licence
 | 
			
		||||
   Privacy Policy: www.juce.com/juce-privacy-policy
 | 
			
		||||
 | 
			
		||||
   Or: You may also use this code under the terms of the GPL v3 (see
 | 
			
		||||
   www.gnu.org/licenses).
 | 
			
		||||
 | 
			
		||||
   JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
 | 
			
		||||
   EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
 | 
			
		||||
   DISCLAIMED.
 | 
			
		||||
 | 
			
		||||
  ==============================================================================
 | 
			
		||||
*/
 | 
			
		||||
 | 
			
		||||
namespace juce
 | 
			
		||||
{
 | 
			
		||||
 | 
			
		||||
namespace X11SymbolHelpers
 | 
			
		||||
{
 | 
			
		||||
 | 
			
		||||
template <typename FuncPtr>
 | 
			
		||||
struct SymbolBinding
 | 
			
		||||
{
 | 
			
		||||
    FuncPtr& func;
 | 
			
		||||
    const char* name;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
template <typename FuncPtr>
 | 
			
		||||
SymbolBinding<FuncPtr> makeSymbolBinding (FuncPtr& func, const char* name)
 | 
			
		||||
{
 | 
			
		||||
    return { func, name };
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
template <typename FuncPtr>
 | 
			
		||||
bool loadSymbols (DynamicLibrary& lib, SymbolBinding<FuncPtr> binding)
 | 
			
		||||
{
 | 
			
		||||
    if (auto* func = lib.getFunction (binding.name))
 | 
			
		||||
    {
 | 
			
		||||
        binding.func = reinterpret_cast<FuncPtr> (func);
 | 
			
		||||
        return true;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    return false;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
template <typename FuncPtr, typename... Args>
 | 
			
		||||
bool loadSymbols (DynamicLibrary& lib1, DynamicLibrary& lib2, SymbolBinding<FuncPtr> binding)
 | 
			
		||||
{
 | 
			
		||||
    return loadSymbols (lib1, binding) || loadSymbols (lib2, binding);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
template <typename FuncPtr, typename... Args>
 | 
			
		||||
bool loadSymbols (DynamicLibrary& lib, SymbolBinding<FuncPtr> binding, Args... args)
 | 
			
		||||
{
 | 
			
		||||
    return loadSymbols (lib, binding) && loadSymbols (lib, args...);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
template <typename FuncPtr, typename... Args>
 | 
			
		||||
bool loadSymbols (DynamicLibrary& lib1, DynamicLibrary& lib2, SymbolBinding<FuncPtr> binding, Args... args)
 | 
			
		||||
{
 | 
			
		||||
    return loadSymbols (lib1, lib2, binding) && loadSymbols (lib1, lib2, args...);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
//==============================================================================
 | 
			
		||||
bool X11Symbols::loadAllSymbols()
 | 
			
		||||
{
 | 
			
		||||
    using namespace X11SymbolHelpers;
 | 
			
		||||
 | 
			
		||||
    if (! loadSymbols (xLib, xextLib,
 | 
			
		||||
                       makeSymbolBinding (xAllocClassHint,             "XAllocClassHint"),
 | 
			
		||||
                       makeSymbolBinding (xAllocSizeHints,             "XAllocSizeHints"),
 | 
			
		||||
                       makeSymbolBinding (xAllocWMHints,               "XAllocWMHints"),
 | 
			
		||||
                       makeSymbolBinding (xBitmapBitOrder,             "XBitmapBitOrder"),
 | 
			
		||||
                       makeSymbolBinding (xBitmapUnit,                 "XBitmapUnit"),
 | 
			
		||||
                       makeSymbolBinding (xChangeActivePointerGrab,    "XChangeActivePointerGrab"),
 | 
			
		||||
                       makeSymbolBinding (xChangeProperty,             "XChangeProperty"),
 | 
			
		||||
                       makeSymbolBinding (xCheckTypedWindowEvent,      "XCheckTypedWindowEvent"),
 | 
			
		||||
                       makeSymbolBinding (xCheckWindowEvent,           "XCheckWindowEvent"),
 | 
			
		||||
                       makeSymbolBinding (xClearArea,                  "XClearArea"),
 | 
			
		||||
                       makeSymbolBinding (xCloseDisplay,               "XCloseDisplay"),
 | 
			
		||||
                       makeSymbolBinding (xConnectionNumber,           "XConnectionNumber"),
 | 
			
		||||
                       makeSymbolBinding (xConvertSelection,           "XConvertSelection"),
 | 
			
		||||
                       makeSymbolBinding (xCreateColormap,             "XCreateColormap"),
 | 
			
		||||
                       makeSymbolBinding (xCreateFontCursor,           "XCreateFontCursor"),
 | 
			
		||||
                       makeSymbolBinding (xCreateGC,                   "XCreateGC"),
 | 
			
		||||
                       makeSymbolBinding (xCreateImage,                "XCreateImage"),
 | 
			
		||||
                       makeSymbolBinding (xCreatePixmap,               "XCreatePixmap"),
 | 
			
		||||
                       makeSymbolBinding (xCreatePixmapCursor,         "XCreatePixmapCursor"),
 | 
			
		||||
                       makeSymbolBinding (xCreatePixmapFromBitmapData, "XCreatePixmapFromBitmapData"),
 | 
			
		||||
                       makeSymbolBinding (xCreateWindow,               "XCreateWindow"),
 | 
			
		||||
                       makeSymbolBinding (xDefaultRootWindow,          "XDefaultRootWindow"),
 | 
			
		||||
                       makeSymbolBinding (xDefaultScreen,              "XDefaultScreen"),
 | 
			
		||||
                       makeSymbolBinding (xDefaultScreenOfDisplay,     "XDefaultScreenOfDisplay"),
 | 
			
		||||
                       makeSymbolBinding (xDefaultVisual,              "XDefaultVisual"),
 | 
			
		||||
                       makeSymbolBinding (xDefineCursor,               "XDefineCursor"),
 | 
			
		||||
                       makeSymbolBinding (xDeleteContext,              "XDeleteContext"),
 | 
			
		||||
                       makeSymbolBinding (xDeleteProperty,             "XDeleteProperty"),
 | 
			
		||||
                       makeSymbolBinding (xDestroyImage,               "XDestroyImage"),
 | 
			
		||||
                       makeSymbolBinding (xDestroyWindow,              "XDestroyWindow"),
 | 
			
		||||
                       makeSymbolBinding (xDisplayHeight,              "XDisplayHeight"),
 | 
			
		||||
                       makeSymbolBinding (xDisplayHeightMM,            "XDisplayHeightMM"),
 | 
			
		||||
                       makeSymbolBinding (xDisplayWidth,               "XDisplayWidth"),
 | 
			
		||||
                       makeSymbolBinding (xDisplayWidthMM,             "XDisplayWidthMM"),
 | 
			
		||||
                       makeSymbolBinding (xEventsQueued,               "XEventsQueued"),
 | 
			
		||||
                       makeSymbolBinding (xFindContext,                "XFindContext"),
 | 
			
		||||
                       makeSymbolBinding (xFlush,                      "XFlush"),
 | 
			
		||||
                       makeSymbolBinding (xFree,                       "XFree"),
 | 
			
		||||
                       makeSymbolBinding (xFreeCursor,                 "XFreeCursor"),
 | 
			
		||||
                       makeSymbolBinding (xFreeColormap,               "XFreeColormap"),
 | 
			
		||||
                       makeSymbolBinding (xFreeGC,                     "XFreeGC"),
 | 
			
		||||
                       makeSymbolBinding (xFreeModifiermap,            "XFreeModifiermap"),
 | 
			
		||||
                       makeSymbolBinding (xFreePixmap,                 "XFreePixmap"),
 | 
			
		||||
                       makeSymbolBinding (xGetAtomName,                "XGetAtomName"),
 | 
			
		||||
                       makeSymbolBinding (xGetErrorDatabaseText,       "XGetErrorDatabaseText"),
 | 
			
		||||
                       makeSymbolBinding (xGetErrorText,               "XGetErrorText"),
 | 
			
		||||
                       makeSymbolBinding (xGetGeometry,                "XGetGeometry"),
 | 
			
		||||
                       makeSymbolBinding (xGetImage,                   "XGetImage"),
 | 
			
		||||
                       makeSymbolBinding (xGetInputFocus,              "XGetInputFocus"),
 | 
			
		||||
                       makeSymbolBinding (xGetModifierMapping,         "XGetModifierMapping"),
 | 
			
		||||
                       makeSymbolBinding (xGetPointerMapping,          "XGetPointerMapping"),
 | 
			
		||||
                       makeSymbolBinding (xGetSelectionOwner,          "XGetSelectionOwner"),
 | 
			
		||||
                       makeSymbolBinding (xGetVisualInfo,              "XGetVisualInfo"),
 | 
			
		||||
                       makeSymbolBinding (xGetWMHints,                 "XGetWMHints"),
 | 
			
		||||
                       makeSymbolBinding (xGetWindowAttributes,        "XGetWindowAttributes"),
 | 
			
		||||
                       makeSymbolBinding (xGetWindowProperty,          "XGetWindowProperty"),
 | 
			
		||||
                       makeSymbolBinding (xGrabPointer,                "XGrabPointer"),
 | 
			
		||||
                       makeSymbolBinding (xGrabServer,                 "XGrabServer"),
 | 
			
		||||
                       makeSymbolBinding (xImageByteOrder,             "XImageByteOrder"),
 | 
			
		||||
                       makeSymbolBinding (xInitImage,                  "XInitImage"),
 | 
			
		||||
                       makeSymbolBinding (xInitThreads,                "XInitThreads"),
 | 
			
		||||
                       makeSymbolBinding (xInstallColormap,            "XInstallColormap"),
 | 
			
		||||
                       makeSymbolBinding (xInternAtom,                 "XInternAtom"),
 | 
			
		||||
                       makeSymbolBinding (xkbKeycodeToKeysym,          "XkbKeycodeToKeysym"),
 | 
			
		||||
                       makeSymbolBinding (xKeysymToKeycode,            "XKeysymToKeycode"),
 | 
			
		||||
                       makeSymbolBinding (xListProperties,             "XListProperties"),
 | 
			
		||||
                       makeSymbolBinding (xLockDisplay,                "XLockDisplay"),
 | 
			
		||||
                       makeSymbolBinding (xLookupString,               "XLookupString"),
 | 
			
		||||
                       makeSymbolBinding (xMapRaised,                  "XMapRaised"),
 | 
			
		||||
                       makeSymbolBinding (xMapWindow,                  "XMapWindow"),
 | 
			
		||||
                       makeSymbolBinding (xMoveResizeWindow,           "XMoveResizeWindow"),
 | 
			
		||||
                       makeSymbolBinding (xNextEvent,                  "XNextEvent"),
 | 
			
		||||
                       makeSymbolBinding (xOpenDisplay,                "XOpenDisplay"),
 | 
			
		||||
                       makeSymbolBinding (xPeekEvent,                  "XPeekEvent"),
 | 
			
		||||
                       makeSymbolBinding (xPending,                    "XPending"),
 | 
			
		||||
                       makeSymbolBinding (xPutImage,                   "XPutImage"),
 | 
			
		||||
                       makeSymbolBinding (xPutPixel,                   "XPutPixel"),
 | 
			
		||||
                       makeSymbolBinding (xQueryBestCursor,            "XQueryBestCursor"),
 | 
			
		||||
                       makeSymbolBinding (xQueryExtension,             "XQueryExtension"),
 | 
			
		||||
                       makeSymbolBinding (xQueryPointer,               "XQueryPointer"),
 | 
			
		||||
                       makeSymbolBinding (xQueryTree,                  "XQueryTree"),
 | 
			
		||||
                       makeSymbolBinding (xRefreshKeyboardMapping,     "XRefreshKeyboardMapping"),
 | 
			
		||||
                       makeSymbolBinding (xReparentWindow,             "XReparentWindow"),
 | 
			
		||||
                       makeSymbolBinding (xResizeWindow,               "XResizeWindow"),
 | 
			
		||||
                       makeSymbolBinding (xRestackWindows,             "XRestackWindows"),
 | 
			
		||||
                       makeSymbolBinding (xRootWindow,                 "XRootWindow"),
 | 
			
		||||
                       makeSymbolBinding (xSaveContext,                "XSaveContext"),
 | 
			
		||||
                       makeSymbolBinding (xScreenCount,                "XScreenCount"),
 | 
			
		||||
                       makeSymbolBinding (xScreenNumberOfScreen,       "XScreenNumberOfScreen"),
 | 
			
		||||
                       makeSymbolBinding (xSelectInput,                "XSelectInput"),
 | 
			
		||||
                       makeSymbolBinding (xSendEvent,                  "XSendEvent"),
 | 
			
		||||
                       makeSymbolBinding (xSetClassHint,               "XSetClassHint"),
 | 
			
		||||
                       makeSymbolBinding (xSetErrorHandler,            "XSetErrorHandler"),
 | 
			
		||||
                       makeSymbolBinding (xSetIOErrorHandler,          "XSetIOErrorHandler"),
 | 
			
		||||
                       makeSymbolBinding (xSetInputFocus,              "XSetInputFocus"),
 | 
			
		||||
                       makeSymbolBinding (xSetSelectionOwner,          "XSetSelectionOwner"),
 | 
			
		||||
                       makeSymbolBinding (xSetWMHints,                 "XSetWMHints"),
 | 
			
		||||
                       makeSymbolBinding (xSetWMIconName,              "XSetWMIconName"),
 | 
			
		||||
                       makeSymbolBinding (xSetWMName,                  "XSetWMName"),
 | 
			
		||||
                       makeSymbolBinding (xSetWMNormalHints,           "XSetWMNormalHints"),
 | 
			
		||||
                       makeSymbolBinding (xStringListToTextProperty,   "XStringListToTextProperty"),
 | 
			
		||||
                       makeSymbolBinding (xSync,                       "XSync"),
 | 
			
		||||
                       makeSymbolBinding (xSynchronize,                "XSynchronize"),
 | 
			
		||||
                       makeSymbolBinding (xTranslateCoordinates,       "XTranslateCoordinates"),
 | 
			
		||||
                       makeSymbolBinding (xrmUniqueQuark,              "XrmUniqueQuark"),
 | 
			
		||||
                       makeSymbolBinding (xUngrabPointer,              "XUngrabPointer"),
 | 
			
		||||
                       makeSymbolBinding (xUngrabServer,               "XUngrabServer"),
 | 
			
		||||
                       makeSymbolBinding (xUnlockDisplay,              "XUnlockDisplay"),
 | 
			
		||||
                       makeSymbolBinding (xUnmapWindow,                "XUnmapWindow"),
 | 
			
		||||
                       makeSymbolBinding (xutf8TextListToTextProperty, "Xutf8TextListToTextProperty"),
 | 
			
		||||
                       makeSymbolBinding (xWarpPointer,                "XWarpPointer")))
 | 
			
		||||
        return false;
 | 
			
		||||
 | 
			
		||||
   #if JUCE_USE_XCURSOR
 | 
			
		||||
    loadSymbols (xcursorLib,
 | 
			
		||||
                 makeSymbolBinding (xcursorImageCreate,          "XcursorImageCreate"),
 | 
			
		||||
                 makeSymbolBinding (xcursorImageLoadCursor,      "XcursorImageLoadCursor"),
 | 
			
		||||
                 makeSymbolBinding (xcursorImageDestroy,         "XcursorImageDestroy"));
 | 
			
		||||
   #endif
 | 
			
		||||
   #if JUCE_USE_XINERAMA
 | 
			
		||||
    loadSymbols (xineramaLib,
 | 
			
		||||
                 makeSymbolBinding (xineramaIsActive,            "XineramaIsActive"),
 | 
			
		||||
                 makeSymbolBinding (xineramaQueryScreens,        "XineramaQueryScreens"));
 | 
			
		||||
   #endif
 | 
			
		||||
   #if JUCE_USE_XRENDER
 | 
			
		||||
    loadSymbols (xrenderLib,
 | 
			
		||||
                 makeSymbolBinding (xRenderQueryVersion,         "XRenderQueryVersion"),
 | 
			
		||||
                 makeSymbolBinding (xRenderFindStandardFormat,   "XRenderFindStandardFormat"),
 | 
			
		||||
                 makeSymbolBinding (xRenderFindFormat,           "XRenderFindFormat"),
 | 
			
		||||
                 makeSymbolBinding (xRenderFindVisualFormat,     "XRenderFindVisualFormat"));
 | 
			
		||||
   #endif
 | 
			
		||||
   #if JUCE_USE_XRANDR
 | 
			
		||||
    loadSymbols (xrandrLib,
 | 
			
		||||
                 makeSymbolBinding (xRRGetScreenResources,       "XRRGetScreenResources"),
 | 
			
		||||
                 makeSymbolBinding (xRRFreeScreenResources,      "XRRFreeScreenResources"),
 | 
			
		||||
                 makeSymbolBinding (xRRGetOutputInfo,            "XRRGetOutputInfo"),
 | 
			
		||||
                 makeSymbolBinding (xRRFreeOutputInfo,           "XRRFreeOutputInfo"),
 | 
			
		||||
                 makeSymbolBinding (xRRGetCrtcInfo,              "XRRGetCrtcInfo"),
 | 
			
		||||
                 makeSymbolBinding (xRRFreeCrtcInfo,             "XRRFreeCrtcInfo"),
 | 
			
		||||
                 makeSymbolBinding (xRRGetOutputPrimary,         "XRRGetOutputPrimary"));
 | 
			
		||||
   #endif
 | 
			
		||||
   #if JUCE_USE_XSHM
 | 
			
		||||
    loadSymbols (xLib, xextLib,
 | 
			
		||||
                 makeSymbolBinding (xShmAttach,                  "XShmAttach"),
 | 
			
		||||
                 makeSymbolBinding (xShmCreateImage,             "XShmCreateImage"),
 | 
			
		||||
                 makeSymbolBinding (xShmDetach,                  "XShmDetach"),
 | 
			
		||||
                 makeSymbolBinding (xShmGetEventBase,            "XShmGetEventBase"),
 | 
			
		||||
                 makeSymbolBinding (xShmPutImage,                "XShmPutImage"),
 | 
			
		||||
                 makeSymbolBinding (xShmQueryVersion,            "XShmQueryVersion"));
 | 
			
		||||
   #endif
 | 
			
		||||
 | 
			
		||||
    return true;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
//==============================================================================
 | 
			
		||||
JUCE_IMPLEMENT_SINGLETON (X11Symbols)
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
/*
 | 
			
		||||
  ==============================================================================
 | 
			
		||||
 | 
			
		||||
   This file is part of the JUCE library.
 | 
			
		||||
   Copyright (c) 2022 - Raw Material Software Limited
 | 
			
		||||
 | 
			
		||||
   JUCE is an open source library subject to commercial or open-source
 | 
			
		||||
   licensing.
 | 
			
		||||
 | 
			
		||||
   By using JUCE, you agree to the terms of both the JUCE 7 End-User License
 | 
			
		||||
   Agreement and JUCE Privacy Policy.
 | 
			
		||||
 | 
			
		||||
   End User License Agreement: www.juce.com/juce-7-licence
 | 
			
		||||
   Privacy Policy: www.juce.com/juce-privacy-policy
 | 
			
		||||
 | 
			
		||||
   Or: You may also use this code under the terms of the GPL v3 (see
 | 
			
		||||
   www.gnu.org/licenses).
 | 
			
		||||
 | 
			
		||||
   JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
 | 
			
		||||
   EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
 | 
			
		||||
   DISCLAIMED.
 | 
			
		||||
 | 
			
		||||
  ==============================================================================
 | 
			
		||||
*/
 | 
			
		||||
 | 
			
		||||
namespace juce
 | 
			
		||||
{
 | 
			
		||||
 | 
			
		||||
namespace X11SymbolHelpers
 | 
			
		||||
{
 | 
			
		||||
 | 
			
		||||
template <typename FuncPtr>
 | 
			
		||||
struct SymbolBinding
 | 
			
		||||
{
 | 
			
		||||
    FuncPtr& func;
 | 
			
		||||
    const char* name;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
template <typename FuncPtr>
 | 
			
		||||
SymbolBinding<FuncPtr> makeSymbolBinding (FuncPtr& func, const char* name)
 | 
			
		||||
{
 | 
			
		||||
    return { func, name };
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
template <typename FuncPtr>
 | 
			
		||||
bool loadSymbols (DynamicLibrary& lib, SymbolBinding<FuncPtr> binding)
 | 
			
		||||
{
 | 
			
		||||
    if (auto* func = lib.getFunction (binding.name))
 | 
			
		||||
    {
 | 
			
		||||
        binding.func = reinterpret_cast<FuncPtr> (func);
 | 
			
		||||
        return true;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    return false;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
template <typename FuncPtr, typename... Args>
 | 
			
		||||
bool loadSymbols (DynamicLibrary& lib1, DynamicLibrary& lib2, SymbolBinding<FuncPtr> binding)
 | 
			
		||||
{
 | 
			
		||||
    return loadSymbols (lib1, binding) || loadSymbols (lib2, binding);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
template <typename FuncPtr, typename... Args>
 | 
			
		||||
bool loadSymbols (DynamicLibrary& lib, SymbolBinding<FuncPtr> binding, Args... args)
 | 
			
		||||
{
 | 
			
		||||
    return loadSymbols (lib, binding) && loadSymbols (lib, args...);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
template <typename FuncPtr, typename... Args>
 | 
			
		||||
bool loadSymbols (DynamicLibrary& lib1, DynamicLibrary& lib2, SymbolBinding<FuncPtr> binding, Args... args)
 | 
			
		||||
{
 | 
			
		||||
    return loadSymbols (lib1, lib2, binding) && loadSymbols (lib1, lib2, args...);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
//==============================================================================
 | 
			
		||||
bool X11Symbols::loadAllSymbols()
 | 
			
		||||
{
 | 
			
		||||
    using namespace X11SymbolHelpers;
 | 
			
		||||
 | 
			
		||||
    if (! loadSymbols (xLib, xextLib,
 | 
			
		||||
                       makeSymbolBinding (xAllocClassHint,             "XAllocClassHint"),
 | 
			
		||||
                       makeSymbolBinding (xAllocSizeHints,             "XAllocSizeHints"),
 | 
			
		||||
                       makeSymbolBinding (xAllocWMHints,               "XAllocWMHints"),
 | 
			
		||||
                       makeSymbolBinding (xBitmapBitOrder,             "XBitmapBitOrder"),
 | 
			
		||||
                       makeSymbolBinding (xBitmapUnit,                 "XBitmapUnit"),
 | 
			
		||||
                       makeSymbolBinding (xChangeActivePointerGrab,    "XChangeActivePointerGrab"),
 | 
			
		||||
                       makeSymbolBinding (xChangeProperty,             "XChangeProperty"),
 | 
			
		||||
                       makeSymbolBinding (xCheckTypedWindowEvent,      "XCheckTypedWindowEvent"),
 | 
			
		||||
                       makeSymbolBinding (xCheckWindowEvent,           "XCheckWindowEvent"),
 | 
			
		||||
                       makeSymbolBinding (xClearArea,                  "XClearArea"),
 | 
			
		||||
                       makeSymbolBinding (xCloseDisplay,               "XCloseDisplay"),
 | 
			
		||||
                       makeSymbolBinding (xConnectionNumber,           "XConnectionNumber"),
 | 
			
		||||
                       makeSymbolBinding (xConvertSelection,           "XConvertSelection"),
 | 
			
		||||
                       makeSymbolBinding (xCreateColormap,             "XCreateColormap"),
 | 
			
		||||
                       makeSymbolBinding (xCreateFontCursor,           "XCreateFontCursor"),
 | 
			
		||||
                       makeSymbolBinding (xCreateGC,                   "XCreateGC"),
 | 
			
		||||
                       makeSymbolBinding (xCreateImage,                "XCreateImage"),
 | 
			
		||||
                       makeSymbolBinding (xCreatePixmap,               "XCreatePixmap"),
 | 
			
		||||
                       makeSymbolBinding (xCreatePixmapCursor,         "XCreatePixmapCursor"),
 | 
			
		||||
                       makeSymbolBinding (xCreatePixmapFromBitmapData, "XCreatePixmapFromBitmapData"),
 | 
			
		||||
                       makeSymbolBinding (xCreateWindow,               "XCreateWindow"),
 | 
			
		||||
                       makeSymbolBinding (xDefaultRootWindow,          "XDefaultRootWindow"),
 | 
			
		||||
                       makeSymbolBinding (xDefaultScreen,              "XDefaultScreen"),
 | 
			
		||||
                       makeSymbolBinding (xDefaultScreenOfDisplay,     "XDefaultScreenOfDisplay"),
 | 
			
		||||
                       makeSymbolBinding (xDefaultVisual,              "XDefaultVisual"),
 | 
			
		||||
                       makeSymbolBinding (xDefineCursor,               "XDefineCursor"),
 | 
			
		||||
                       makeSymbolBinding (xDeleteContext,              "XDeleteContext"),
 | 
			
		||||
                       makeSymbolBinding (xDeleteProperty,             "XDeleteProperty"),
 | 
			
		||||
                       makeSymbolBinding (xDestroyImage,               "XDestroyImage"),
 | 
			
		||||
                       makeSymbolBinding (xDestroyWindow,              "XDestroyWindow"),
 | 
			
		||||
                       makeSymbolBinding (xDisplayHeight,              "XDisplayHeight"),
 | 
			
		||||
                       makeSymbolBinding (xDisplayHeightMM,            "XDisplayHeightMM"),
 | 
			
		||||
                       makeSymbolBinding (xDisplayWidth,               "XDisplayWidth"),
 | 
			
		||||
                       makeSymbolBinding (xDisplayWidthMM,             "XDisplayWidthMM"),
 | 
			
		||||
                       makeSymbolBinding (xEventsQueued,               "XEventsQueued"),
 | 
			
		||||
                       makeSymbolBinding (xFindContext,                "XFindContext"),
 | 
			
		||||
                       makeSymbolBinding (xFlush,                      "XFlush"),
 | 
			
		||||
                       makeSymbolBinding (xFree,                       "XFree"),
 | 
			
		||||
                       makeSymbolBinding (xFreeCursor,                 "XFreeCursor"),
 | 
			
		||||
                       makeSymbolBinding (xFreeColormap,               "XFreeColormap"),
 | 
			
		||||
                       makeSymbolBinding (xFreeGC,                     "XFreeGC"),
 | 
			
		||||
                       makeSymbolBinding (xFreeModifiermap,            "XFreeModifiermap"),
 | 
			
		||||
                       makeSymbolBinding (xFreePixmap,                 "XFreePixmap"),
 | 
			
		||||
                       makeSymbolBinding (xGetAtomName,                "XGetAtomName"),
 | 
			
		||||
                       makeSymbolBinding (xGetErrorDatabaseText,       "XGetErrorDatabaseText"),
 | 
			
		||||
                       makeSymbolBinding (xGetErrorText,               "XGetErrorText"),
 | 
			
		||||
                       makeSymbolBinding (xGetGeometry,                "XGetGeometry"),
 | 
			
		||||
                       makeSymbolBinding (xGetImage,                   "XGetImage"),
 | 
			
		||||
                       makeSymbolBinding (xGetInputFocus,              "XGetInputFocus"),
 | 
			
		||||
                       makeSymbolBinding (xGetModifierMapping,         "XGetModifierMapping"),
 | 
			
		||||
                       makeSymbolBinding (xGetPointerMapping,          "XGetPointerMapping"),
 | 
			
		||||
                       makeSymbolBinding (xGetSelectionOwner,          "XGetSelectionOwner"),
 | 
			
		||||
                       makeSymbolBinding (xGetVisualInfo,              "XGetVisualInfo"),
 | 
			
		||||
                       makeSymbolBinding (xGetWMHints,                 "XGetWMHints"),
 | 
			
		||||
                       makeSymbolBinding (xGetWindowAttributes,        "XGetWindowAttributes"),
 | 
			
		||||
                       makeSymbolBinding (xGetWindowProperty,          "XGetWindowProperty"),
 | 
			
		||||
                       makeSymbolBinding (xGrabPointer,                "XGrabPointer"),
 | 
			
		||||
                       makeSymbolBinding (xGrabServer,                 "XGrabServer"),
 | 
			
		||||
                       makeSymbolBinding (xImageByteOrder,             "XImageByteOrder"),
 | 
			
		||||
                       makeSymbolBinding (xInitImage,                  "XInitImage"),
 | 
			
		||||
                       makeSymbolBinding (xInitThreads,                "XInitThreads"),
 | 
			
		||||
                       makeSymbolBinding (xInstallColormap,            "XInstallColormap"),
 | 
			
		||||
                       makeSymbolBinding (xInternAtom,                 "XInternAtom"),
 | 
			
		||||
                       makeSymbolBinding (xkbKeycodeToKeysym,          "XkbKeycodeToKeysym"),
 | 
			
		||||
                       makeSymbolBinding (xKeysymToKeycode,            "XKeysymToKeycode"),
 | 
			
		||||
                       makeSymbolBinding (xListProperties,             "XListProperties"),
 | 
			
		||||
                       makeSymbolBinding (xLockDisplay,                "XLockDisplay"),
 | 
			
		||||
                       makeSymbolBinding (xLookupString,               "XLookupString"),
 | 
			
		||||
                       makeSymbolBinding (xMapRaised,                  "XMapRaised"),
 | 
			
		||||
                       makeSymbolBinding (xMapWindow,                  "XMapWindow"),
 | 
			
		||||
                       makeSymbolBinding (xMoveResizeWindow,           "XMoveResizeWindow"),
 | 
			
		||||
                       makeSymbolBinding (xNextEvent,                  "XNextEvent"),
 | 
			
		||||
                       makeSymbolBinding (xOpenDisplay,                "XOpenDisplay"),
 | 
			
		||||
                       makeSymbolBinding (xPeekEvent,                  "XPeekEvent"),
 | 
			
		||||
                       makeSymbolBinding (xPending,                    "XPending"),
 | 
			
		||||
                       makeSymbolBinding (xPutImage,                   "XPutImage"),
 | 
			
		||||
                       makeSymbolBinding (xPutPixel,                   "XPutPixel"),
 | 
			
		||||
                       makeSymbolBinding (xQueryBestCursor,            "XQueryBestCursor"),
 | 
			
		||||
                       makeSymbolBinding (xQueryExtension,             "XQueryExtension"),
 | 
			
		||||
                       makeSymbolBinding (xQueryPointer,               "XQueryPointer"),
 | 
			
		||||
                       makeSymbolBinding (xQueryTree,                  "XQueryTree"),
 | 
			
		||||
                       makeSymbolBinding (xRefreshKeyboardMapping,     "XRefreshKeyboardMapping"),
 | 
			
		||||
                       makeSymbolBinding (xReparentWindow,             "XReparentWindow"),
 | 
			
		||||
                       makeSymbolBinding (xResizeWindow,               "XResizeWindow"),
 | 
			
		||||
                       makeSymbolBinding (xRestackWindows,             "XRestackWindows"),
 | 
			
		||||
                       makeSymbolBinding (xRootWindow,                 "XRootWindow"),
 | 
			
		||||
                       makeSymbolBinding (xSaveContext,                "XSaveContext"),
 | 
			
		||||
                       makeSymbolBinding (xScreenCount,                "XScreenCount"),
 | 
			
		||||
                       makeSymbolBinding (xScreenNumberOfScreen,       "XScreenNumberOfScreen"),
 | 
			
		||||
                       makeSymbolBinding (xSelectInput,                "XSelectInput"),
 | 
			
		||||
                       makeSymbolBinding (xSendEvent,                  "XSendEvent"),
 | 
			
		||||
                       makeSymbolBinding (xSetClassHint,               "XSetClassHint"),
 | 
			
		||||
                       makeSymbolBinding (xSetErrorHandler,            "XSetErrorHandler"),
 | 
			
		||||
                       makeSymbolBinding (xSetIOErrorHandler,          "XSetIOErrorHandler"),
 | 
			
		||||
                       makeSymbolBinding (xSetInputFocus,              "XSetInputFocus"),
 | 
			
		||||
                       makeSymbolBinding (xSetSelectionOwner,          "XSetSelectionOwner"),
 | 
			
		||||
                       makeSymbolBinding (xSetWMHints,                 "XSetWMHints"),
 | 
			
		||||
                       makeSymbolBinding (xSetWMIconName,              "XSetWMIconName"),
 | 
			
		||||
                       makeSymbolBinding (xSetWMName,                  "XSetWMName"),
 | 
			
		||||
                       makeSymbolBinding (xSetWMNormalHints,           "XSetWMNormalHints"),
 | 
			
		||||
                       makeSymbolBinding (xStringListToTextProperty,   "XStringListToTextProperty"),
 | 
			
		||||
                       makeSymbolBinding (xSync,                       "XSync"),
 | 
			
		||||
                       makeSymbolBinding (xSynchronize,                "XSynchronize"),
 | 
			
		||||
                       makeSymbolBinding (xTranslateCoordinates,       "XTranslateCoordinates"),
 | 
			
		||||
                       makeSymbolBinding (xrmUniqueQuark,              "XrmUniqueQuark"),
 | 
			
		||||
                       makeSymbolBinding (xUngrabPointer,              "XUngrabPointer"),
 | 
			
		||||
                       makeSymbolBinding (xUngrabServer,               "XUngrabServer"),
 | 
			
		||||
                       makeSymbolBinding (xUnlockDisplay,              "XUnlockDisplay"),
 | 
			
		||||
                       makeSymbolBinding (xUnmapWindow,                "XUnmapWindow"),
 | 
			
		||||
                       makeSymbolBinding (xutf8TextListToTextProperty, "Xutf8TextListToTextProperty"),
 | 
			
		||||
                       makeSymbolBinding (xWarpPointer,                "XWarpPointer")))
 | 
			
		||||
        return false;
 | 
			
		||||
 | 
			
		||||
   #if JUCE_USE_XCURSOR
 | 
			
		||||
    loadSymbols (xcursorLib,
 | 
			
		||||
                 makeSymbolBinding (xcursorImageCreate,          "XcursorImageCreate"),
 | 
			
		||||
                 makeSymbolBinding (xcursorImageLoadCursor,      "XcursorImageLoadCursor"),
 | 
			
		||||
                 makeSymbolBinding (xcursorImageDestroy,         "XcursorImageDestroy"));
 | 
			
		||||
   #endif
 | 
			
		||||
   #if JUCE_USE_XINERAMA
 | 
			
		||||
    loadSymbols (xineramaLib,
 | 
			
		||||
                 makeSymbolBinding (xineramaIsActive,            "XineramaIsActive"),
 | 
			
		||||
                 makeSymbolBinding (xineramaQueryScreens,        "XineramaQueryScreens"));
 | 
			
		||||
   #endif
 | 
			
		||||
   #if JUCE_USE_XRENDER
 | 
			
		||||
    loadSymbols (xrenderLib,
 | 
			
		||||
                 makeSymbolBinding (xRenderQueryVersion,         "XRenderQueryVersion"),
 | 
			
		||||
                 makeSymbolBinding (xRenderFindStandardFormat,   "XRenderFindStandardFormat"),
 | 
			
		||||
                 makeSymbolBinding (xRenderFindFormat,           "XRenderFindFormat"),
 | 
			
		||||
                 makeSymbolBinding (xRenderFindVisualFormat,     "XRenderFindVisualFormat"));
 | 
			
		||||
   #endif
 | 
			
		||||
   #if JUCE_USE_XRANDR
 | 
			
		||||
    loadSymbols (xrandrLib,
 | 
			
		||||
                 makeSymbolBinding (xRRGetScreenResources,       "XRRGetScreenResources"),
 | 
			
		||||
                 makeSymbolBinding (xRRFreeScreenResources,      "XRRFreeScreenResources"),
 | 
			
		||||
                 makeSymbolBinding (xRRGetOutputInfo,            "XRRGetOutputInfo"),
 | 
			
		||||
                 makeSymbolBinding (xRRFreeOutputInfo,           "XRRFreeOutputInfo"),
 | 
			
		||||
                 makeSymbolBinding (xRRGetCrtcInfo,              "XRRGetCrtcInfo"),
 | 
			
		||||
                 makeSymbolBinding (xRRFreeCrtcInfo,             "XRRFreeCrtcInfo"),
 | 
			
		||||
                 makeSymbolBinding (xRRGetOutputPrimary,         "XRRGetOutputPrimary"));
 | 
			
		||||
   #endif
 | 
			
		||||
   #if JUCE_USE_XSHM
 | 
			
		||||
    loadSymbols (xLib, xextLib,
 | 
			
		||||
                 makeSymbolBinding (xShmAttach,                  "XShmAttach"),
 | 
			
		||||
                 makeSymbolBinding (xShmCreateImage,             "XShmCreateImage"),
 | 
			
		||||
                 makeSymbolBinding (xShmDetach,                  "XShmDetach"),
 | 
			
		||||
                 makeSymbolBinding (xShmGetEventBase,            "XShmGetEventBase"),
 | 
			
		||||
                 makeSymbolBinding (xShmPutImage,                "XShmPutImage"),
 | 
			
		||||
                 makeSymbolBinding (xShmQueryVersion,            "XShmQueryVersion"));
 | 
			
		||||
   #endif
 | 
			
		||||
 | 
			
		||||
    return true;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
//==============================================================================
 | 
			
		||||
JUCE_IMPLEMENT_SINGLETON (X11Symbols)
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							@@ -1,346 +1,350 @@
 | 
			
		||||
/*
 | 
			
		||||
  ==============================================================================
 | 
			
		||||
 | 
			
		||||
   This file is part of the JUCE library.
 | 
			
		||||
   Copyright (c) 2020 - Raw Material Software Limited
 | 
			
		||||
 | 
			
		||||
   JUCE is an open source library subject to commercial or open-source
 | 
			
		||||
   licensing.
 | 
			
		||||
 | 
			
		||||
   By using JUCE, you agree to the terms of both the JUCE 6 End-User License
 | 
			
		||||
   Agreement and JUCE Privacy Policy (both effective as of the 16th June 2020).
 | 
			
		||||
 | 
			
		||||
   End User License Agreement: www.juce.com/juce-6-licence
 | 
			
		||||
   Privacy Policy: www.juce.com/juce-privacy-policy
 | 
			
		||||
 | 
			
		||||
   Or: You may also use this code under the terms of the GPL v3 (see
 | 
			
		||||
   www.gnu.org/licenses).
 | 
			
		||||
 | 
			
		||||
   JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
 | 
			
		||||
   EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
 | 
			
		||||
   DISCLAIMED.
 | 
			
		||||
 | 
			
		||||
  ==============================================================================
 | 
			
		||||
*/
 | 
			
		||||
 | 
			
		||||
namespace juce
 | 
			
		||||
{
 | 
			
		||||
 | 
			
		||||
//==============================================================================
 | 
			
		||||
namespace XWindowSystemUtilities
 | 
			
		||||
{
 | 
			
		||||
    //==============================================================================
 | 
			
		||||
    /** A handy struct that uses XLockDisplay and XUnlockDisplay to lock the X server
 | 
			
		||||
        using RAII.
 | 
			
		||||
 | 
			
		||||
        @tags{GUI}
 | 
			
		||||
    */
 | 
			
		||||
    struct ScopedXLock
 | 
			
		||||
    {
 | 
			
		||||
        ScopedXLock();
 | 
			
		||||
        ~ScopedXLock();
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    //==============================================================================
 | 
			
		||||
    /** Gets a specified window property and stores its associated data, freeing it
 | 
			
		||||
        on deletion.
 | 
			
		||||
 | 
			
		||||
        @tags{GUI}
 | 
			
		||||
    */
 | 
			
		||||
    struct GetXProperty
 | 
			
		||||
    {
 | 
			
		||||
        GetXProperty (::Display* display, ::Window windowH, Atom property,
 | 
			
		||||
                      long offset, long length, bool shouldDelete, Atom requestedType);
 | 
			
		||||
        ~GetXProperty();
 | 
			
		||||
 | 
			
		||||
        bool success = false;
 | 
			
		||||
        unsigned char* data = nullptr;
 | 
			
		||||
        unsigned long numItems = 0, bytesLeft = 0;
 | 
			
		||||
        Atom actualType;
 | 
			
		||||
        int actualFormat = -1;
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    //==============================================================================
 | 
			
		||||
    /** Initialises and stores some atoms for the display.
 | 
			
		||||
 | 
			
		||||
        @tags{GUI}
 | 
			
		||||
    */
 | 
			
		||||
    struct Atoms
 | 
			
		||||
    {
 | 
			
		||||
        enum ProtocolItems
 | 
			
		||||
        {
 | 
			
		||||
            TAKE_FOCUS = 0,
 | 
			
		||||
            DELETE_WINDOW = 1,
 | 
			
		||||
            PING = 2
 | 
			
		||||
        };
 | 
			
		||||
 | 
			
		||||
        Atoms() = default;
 | 
			
		||||
        explicit Atoms (::Display*);
 | 
			
		||||
 | 
			
		||||
        static Atom getIfExists (::Display*, const char* name);
 | 
			
		||||
        static Atom getCreating (::Display*, const char* name);
 | 
			
		||||
 | 
			
		||||
        static String getName (::Display*, Atom);
 | 
			
		||||
        static bool isMimeTypeFile (::Display*, Atom);
 | 
			
		||||
 | 
			
		||||
        static constexpr unsigned long DndVersion = 3;
 | 
			
		||||
 | 
			
		||||
        Atom protocols, protocolList[3], changeState, state, userTime, activeWin, pid, windowType, windowState, windowStateHidden,
 | 
			
		||||
             XdndAware, XdndEnter, XdndLeave, XdndPosition, XdndStatus, XdndDrop, XdndFinished, XdndSelection,
 | 
			
		||||
             XdndTypeList, XdndActionList, XdndActionDescription, XdndActionCopy, XdndActionPrivate,
 | 
			
		||||
             XembedMsgType, XembedInfo, allowedActions[5], allowedMimeTypes[4], utf8String, clipboard, targets;
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    //==============================================================================
 | 
			
		||||
    /** Represents a setting according to the XSETTINGS specification.
 | 
			
		||||
 | 
			
		||||
        @tags{GUI}
 | 
			
		||||
    */
 | 
			
		||||
    struct XSetting
 | 
			
		||||
    {
 | 
			
		||||
        enum class Type
 | 
			
		||||
        {
 | 
			
		||||
            integer,
 | 
			
		||||
            string,
 | 
			
		||||
            colour,
 | 
			
		||||
            invalid
 | 
			
		||||
        };
 | 
			
		||||
 | 
			
		||||
        XSetting() = default;
 | 
			
		||||
 | 
			
		||||
        XSetting (const String& n, int v)            : name (n), type (Type::integer), integerValue (v)  {}
 | 
			
		||||
        XSetting (const String& n, const String& v)  : name (n), type (Type::string),  stringValue (v)   {}
 | 
			
		||||
        XSetting (const String& n, const Colour& v)  : name (n), type (Type::colour),  colourValue (v)   {}
 | 
			
		||||
 | 
			
		||||
        bool isValid() const noexcept  { return type != Type::invalid; }
 | 
			
		||||
 | 
			
		||||
        String name;
 | 
			
		||||
        Type type = Type::invalid;
 | 
			
		||||
 | 
			
		||||
        int integerValue = -1;
 | 
			
		||||
        String stringValue;
 | 
			
		||||
        Colour colourValue;
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    /** Parses and stores the X11 settings for a display according to the XSETTINGS
 | 
			
		||||
        specification.
 | 
			
		||||
 | 
			
		||||
        @tags{GUI}
 | 
			
		||||
    */
 | 
			
		||||
    class XSettings
 | 
			
		||||
    {
 | 
			
		||||
    public:
 | 
			
		||||
        explicit XSettings (::Display*);
 | 
			
		||||
 | 
			
		||||
        //==============================================================================
 | 
			
		||||
        void update();
 | 
			
		||||
        ::Window getSettingsWindow() const noexcept  { return settingsWindow; }
 | 
			
		||||
 | 
			
		||||
        XSetting getSetting (const String& settingName) const;
 | 
			
		||||
 | 
			
		||||
        //==============================================================================
 | 
			
		||||
        struct Listener
 | 
			
		||||
        {
 | 
			
		||||
            virtual ~Listener() = default;
 | 
			
		||||
            virtual void settingChanged (const XSetting& settingThatHasChanged) = 0;
 | 
			
		||||
        };
 | 
			
		||||
 | 
			
		||||
        void addListener (Listener* listenerToAdd)        { listeners.add (listenerToAdd); }
 | 
			
		||||
        void removeListener (Listener* listenerToRemove)  { listeners.remove (listenerToRemove); }
 | 
			
		||||
 | 
			
		||||
    private:
 | 
			
		||||
        ::Display* display = nullptr;
 | 
			
		||||
        ::Window settingsWindow = None;
 | 
			
		||||
        Atom settingsAtom;
 | 
			
		||||
 | 
			
		||||
        int lastUpdateSerial = -1;
 | 
			
		||||
 | 
			
		||||
        std::unordered_map<String, XSetting> settings;
 | 
			
		||||
        ListenerList<Listener> listeners;
 | 
			
		||||
 | 
			
		||||
        //==============================================================================
 | 
			
		||||
        JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (XSettings)
 | 
			
		||||
    };
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
//==============================================================================
 | 
			
		||||
class LinuxComponentPeer;
 | 
			
		||||
 | 
			
		||||
class XWindowSystem  : public DeletedAtShutdown
 | 
			
		||||
{
 | 
			
		||||
public:
 | 
			
		||||
    //==============================================================================
 | 
			
		||||
    ::Window createWindow (::Window parentWindow, LinuxComponentPeer*) const;
 | 
			
		||||
    void destroyWindow    (::Window);
 | 
			
		||||
 | 
			
		||||
    void setTitle (::Window, const String&) const;
 | 
			
		||||
    void setIcon (::Window , const Image&) const;
 | 
			
		||||
    void setVisible (::Window, bool shouldBeVisible) const;
 | 
			
		||||
    void setBounds (::Window, Rectangle<int>, bool fullScreen) const;
 | 
			
		||||
 | 
			
		||||
    BorderSize<int> getBorderSize   (::Window) const;
 | 
			
		||||
    Rectangle<int>  getWindowBounds (::Window, ::Window parentWindow);
 | 
			
		||||
    Point<int> getPhysicalParentScreenPosition() const;
 | 
			
		||||
 | 
			
		||||
    bool contains (::Window, Point<int> localPos) const;
 | 
			
		||||
 | 
			
		||||
    void setMinimised (::Window, bool shouldBeMinimised) const;
 | 
			
		||||
    bool isMinimised  (::Window) const;
 | 
			
		||||
 | 
			
		||||
    void setMaximised (::Window, bool shouldBeMinimised) const;
 | 
			
		||||
 | 
			
		||||
    void toFront  (::Window, bool makeActive) const;
 | 
			
		||||
    void toBehind (::Window, ::Window otherWindow) const;
 | 
			
		||||
 | 
			
		||||
    bool isFocused (::Window) const;
 | 
			
		||||
    bool grabFocus (::Window) const;
 | 
			
		||||
 | 
			
		||||
    bool canUseSemiTransparentWindows() const;
 | 
			
		||||
    bool canUseARGBImages() const;
 | 
			
		||||
    bool isDarkModeActive() const;
 | 
			
		||||
 | 
			
		||||
    int getNumPaintsPendingForWindow (::Window);
 | 
			
		||||
    void processPendingPaintsForWindow (::Window);
 | 
			
		||||
    void addPendingPaintForWindow (::Window);
 | 
			
		||||
    void removePendingPaintForWindow (::Window);
 | 
			
		||||
 | 
			
		||||
    Image createImage (bool isSemiTransparentWindow, int width, int height, bool argb) const;
 | 
			
		||||
    void blitToWindow (::Window, Image, Rectangle<int> destinationRect, Rectangle<int> totalRect) const;
 | 
			
		||||
 | 
			
		||||
    void setScreenSaverEnabled (bool enabled) const;
 | 
			
		||||
 | 
			
		||||
    Point<float> getCurrentMousePosition() const;
 | 
			
		||||
    void setMousePosition (Point<float> pos) const;
 | 
			
		||||
 | 
			
		||||
    void* createCustomMouseCursorInfo (const Image&, Point<int> hotspot) const;
 | 
			
		||||
    void deleteMouseCursor (void* cursorHandle) const;
 | 
			
		||||
    void* createStandardMouseCursor (MouseCursor::StandardCursorType) const;
 | 
			
		||||
    void showCursor (::Window, void* cursorHandle) const;
 | 
			
		||||
 | 
			
		||||
    bool isKeyCurrentlyDown (int keyCode) const;
 | 
			
		||||
    ModifierKeys getNativeRealtimeModifiers() const;
 | 
			
		||||
 | 
			
		||||
    Array<Displays::Display> findDisplays (float masterScale) const;
 | 
			
		||||
 | 
			
		||||
    ::Window createKeyProxy (::Window) const;
 | 
			
		||||
    void deleteKeyProxy (::Window) const;
 | 
			
		||||
 | 
			
		||||
    bool externalDragFileInit (LinuxComponentPeer*, const StringArray& files, bool canMove, std::function<void()>&& callback) const;
 | 
			
		||||
    bool externalDragTextInit (LinuxComponentPeer*, const String& text, std::function<void()>&& callback) const;
 | 
			
		||||
 | 
			
		||||
    void copyTextToClipboard (const String&);
 | 
			
		||||
    String getTextFromClipboard() const;
 | 
			
		||||
    String getLocalClipboardContent() const noexcept  { return localClipboardContent; }
 | 
			
		||||
 | 
			
		||||
    ::Display* getDisplay() const noexcept                            { return display; }
 | 
			
		||||
    const XWindowSystemUtilities::Atoms& getAtoms() const noexcept    { return atoms; }
 | 
			
		||||
    XWindowSystemUtilities::XSettings* getXSettings() const noexcept  { return xSettings.get(); }
 | 
			
		||||
 | 
			
		||||
    bool isX11Available() const noexcept  { return xIsAvailable; }
 | 
			
		||||
 | 
			
		||||
    static String getWindowScalingFactorSettingName()  { return "Gdk/WindowScalingFactor"; }
 | 
			
		||||
    static String getThemeNameSettingName()            { return "Net/ThemeName"; }
 | 
			
		||||
 | 
			
		||||
    //==============================================================================
 | 
			
		||||
    void handleWindowMessage (LinuxComponentPeer*, XEvent&) const;
 | 
			
		||||
    bool isParentWindowOf (::Window, ::Window possibleChild) const;
 | 
			
		||||
 | 
			
		||||
    //==============================================================================
 | 
			
		||||
    JUCE_DECLARE_SINGLETON (XWindowSystem, false)
 | 
			
		||||
 | 
			
		||||
private:
 | 
			
		||||
    XWindowSystem();
 | 
			
		||||
    ~XWindowSystem();
 | 
			
		||||
 | 
			
		||||
    //==============================================================================
 | 
			
		||||
    struct VisualAndDepth
 | 
			
		||||
    {
 | 
			
		||||
        Visual* visual;
 | 
			
		||||
        int depth;
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    struct DisplayVisuals
 | 
			
		||||
    {
 | 
			
		||||
        explicit DisplayVisuals (::Display*);
 | 
			
		||||
 | 
			
		||||
        VisualAndDepth getBestVisualForWindow (bool) const;
 | 
			
		||||
        bool isValid() const noexcept;
 | 
			
		||||
 | 
			
		||||
        Visual* visual16Bit = nullptr;
 | 
			
		||||
        Visual* visual24Bit = nullptr;
 | 
			
		||||
        Visual* visual32Bit = nullptr;
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    bool initialiseXDisplay();
 | 
			
		||||
    void destroyXDisplay();
 | 
			
		||||
 | 
			
		||||
    //==============================================================================
 | 
			
		||||
    ::Window getFocusWindow (::Window) const;
 | 
			
		||||
 | 
			
		||||
    bool isFrontWindow (::Window) const;
 | 
			
		||||
 | 
			
		||||
    //==============================================================================
 | 
			
		||||
    void xchangeProperty (::Window, Atom, Atom, int, const void*, int) const;
 | 
			
		||||
 | 
			
		||||
    void removeWindowDecorations (::Window) const;
 | 
			
		||||
    void addWindowButtons        (::Window, int) const;
 | 
			
		||||
    void setWindowType           (::Window, int) const;
 | 
			
		||||
 | 
			
		||||
    void initialisePointerMap();
 | 
			
		||||
    void deleteIconPixmaps (::Window) const;
 | 
			
		||||
    void updateModifierMappings() const;
 | 
			
		||||
 | 
			
		||||
    long getUserTime (::Window) const;
 | 
			
		||||
 | 
			
		||||
    void initialiseXSettings();
 | 
			
		||||
 | 
			
		||||
    //==============================================================================
 | 
			
		||||
    void handleKeyPressEvent        (LinuxComponentPeer*, XKeyEvent&) const;
 | 
			
		||||
    void handleKeyReleaseEvent      (LinuxComponentPeer*, const XKeyEvent&) const;
 | 
			
		||||
    void handleWheelEvent           (LinuxComponentPeer*, const XButtonPressedEvent&, float) const;
 | 
			
		||||
    void handleButtonPressEvent     (LinuxComponentPeer*, const XButtonPressedEvent&, int) const;
 | 
			
		||||
    void handleButtonPressEvent     (LinuxComponentPeer*, const XButtonPressedEvent&) const;
 | 
			
		||||
    void handleButtonReleaseEvent   (LinuxComponentPeer*, const XButtonReleasedEvent&) const;
 | 
			
		||||
    void handleMotionNotifyEvent    (LinuxComponentPeer*, const XPointerMovedEvent&) const;
 | 
			
		||||
    void handleEnterNotifyEvent     (LinuxComponentPeer*, const XEnterWindowEvent&) const;
 | 
			
		||||
    void handleLeaveNotifyEvent     (LinuxComponentPeer*, const XLeaveWindowEvent&) const;
 | 
			
		||||
    void handleFocusInEvent         (LinuxComponentPeer*) const;
 | 
			
		||||
    void handleFocusOutEvent        (LinuxComponentPeer*) const;
 | 
			
		||||
    void handleExposeEvent          (LinuxComponentPeer*, XExposeEvent&) const;
 | 
			
		||||
    void handleConfigureNotifyEvent (LinuxComponentPeer*, XConfigureEvent&) const;
 | 
			
		||||
    void handleGravityNotify        (LinuxComponentPeer*) const;
 | 
			
		||||
    void propertyNotifyEvent        (LinuxComponentPeer*, const XPropertyEvent&) const;
 | 
			
		||||
    void handleMappingNotify        (XMappingEvent&) const;
 | 
			
		||||
    void handleClientMessageEvent   (LinuxComponentPeer*, XClientMessageEvent&, XEvent&) const;
 | 
			
		||||
    void handleXEmbedMessage        (LinuxComponentPeer*, XClientMessageEvent&) const;
 | 
			
		||||
 | 
			
		||||
    void dismissBlockingModals      (LinuxComponentPeer*) const;
 | 
			
		||||
    void dismissBlockingModals      (LinuxComponentPeer*, const XConfigureEvent&) const;
 | 
			
		||||
 | 
			
		||||
    ::Window findTopLevelWindowOf (::Window) const;
 | 
			
		||||
 | 
			
		||||
    static void windowMessageReceive (XEvent&);
 | 
			
		||||
 | 
			
		||||
    //==============================================================================
 | 
			
		||||
    bool xIsAvailable = false;
 | 
			
		||||
 | 
			
		||||
    XWindowSystemUtilities::Atoms atoms;
 | 
			
		||||
    ::Display* display = nullptr;
 | 
			
		||||
    std::unique_ptr<DisplayVisuals> displayVisuals;
 | 
			
		||||
    std::unique_ptr<XWindowSystemUtilities::XSettings> xSettings;
 | 
			
		||||
 | 
			
		||||
   #if JUCE_USE_XSHM
 | 
			
		||||
    std::map<::Window, int> shmPaintsPendingMap;
 | 
			
		||||
   #endif
 | 
			
		||||
 | 
			
		||||
    int shmCompletionEvent = 0;
 | 
			
		||||
    int pointerMap[5] = {};
 | 
			
		||||
    String localClipboardContent;
 | 
			
		||||
 | 
			
		||||
    Point<int> parentScreenPosition;
 | 
			
		||||
 | 
			
		||||
    //==============================================================================
 | 
			
		||||
    JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (XWindowSystem)
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
} // namespace juce
 | 
			
		||||
/*
 | 
			
		||||
  ==============================================================================
 | 
			
		||||
 | 
			
		||||
   This file is part of the JUCE library.
 | 
			
		||||
   Copyright (c) 2022 - Raw Material Software Limited
 | 
			
		||||
 | 
			
		||||
   JUCE is an open source library subject to commercial or open-source
 | 
			
		||||
   licensing.
 | 
			
		||||
 | 
			
		||||
   By using JUCE, you agree to the terms of both the JUCE 7 End-User License
 | 
			
		||||
   Agreement and JUCE Privacy Policy.
 | 
			
		||||
 | 
			
		||||
   End User License Agreement: www.juce.com/juce-7-licence
 | 
			
		||||
   Privacy Policy: www.juce.com/juce-privacy-policy
 | 
			
		||||
 | 
			
		||||
   Or: You may also use this code under the terms of the GPL v3 (see
 | 
			
		||||
   www.gnu.org/licenses).
 | 
			
		||||
 | 
			
		||||
   JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
 | 
			
		||||
   EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
 | 
			
		||||
   DISCLAIMED.
 | 
			
		||||
 | 
			
		||||
  ==============================================================================
 | 
			
		||||
*/
 | 
			
		||||
 | 
			
		||||
namespace juce
 | 
			
		||||
{
 | 
			
		||||
 | 
			
		||||
//==============================================================================
 | 
			
		||||
namespace XWindowSystemUtilities
 | 
			
		||||
{
 | 
			
		||||
    //==============================================================================
 | 
			
		||||
    /** A handy struct that uses XLockDisplay and XUnlockDisplay to lock the X server
 | 
			
		||||
        using RAII.
 | 
			
		||||
 | 
			
		||||
        @tags{GUI}
 | 
			
		||||
    */
 | 
			
		||||
    struct ScopedXLock
 | 
			
		||||
    {
 | 
			
		||||
        ScopedXLock();
 | 
			
		||||
        ~ScopedXLock();
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    //==============================================================================
 | 
			
		||||
    /** Gets a specified window property and stores its associated data, freeing it
 | 
			
		||||
        on deletion.
 | 
			
		||||
 | 
			
		||||
        @tags{GUI}
 | 
			
		||||
    */
 | 
			
		||||
    struct GetXProperty
 | 
			
		||||
    {
 | 
			
		||||
        GetXProperty (::Display* display, ::Window windowH, Atom property,
 | 
			
		||||
                      long offset, long length, bool shouldDelete, Atom requestedType);
 | 
			
		||||
        ~GetXProperty();
 | 
			
		||||
 | 
			
		||||
        bool success = false;
 | 
			
		||||
        unsigned char* data = nullptr;
 | 
			
		||||
        unsigned long numItems = 0, bytesLeft = 0;
 | 
			
		||||
        Atom actualType;
 | 
			
		||||
        int actualFormat = -1;
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    //==============================================================================
 | 
			
		||||
    /** Initialises and stores some atoms for the display.
 | 
			
		||||
 | 
			
		||||
        @tags{GUI}
 | 
			
		||||
    */
 | 
			
		||||
    struct Atoms
 | 
			
		||||
    {
 | 
			
		||||
        enum ProtocolItems
 | 
			
		||||
        {
 | 
			
		||||
            TAKE_FOCUS = 0,
 | 
			
		||||
            DELETE_WINDOW = 1,
 | 
			
		||||
            PING = 2
 | 
			
		||||
        };
 | 
			
		||||
 | 
			
		||||
        Atoms() = default;
 | 
			
		||||
        explicit Atoms (::Display*);
 | 
			
		||||
 | 
			
		||||
        static Atom getIfExists (::Display*, const char* name);
 | 
			
		||||
        static Atom getCreating (::Display*, const char* name);
 | 
			
		||||
 | 
			
		||||
        static String getName (::Display*, Atom);
 | 
			
		||||
        static bool isMimeTypeFile (::Display*, Atom);
 | 
			
		||||
 | 
			
		||||
        static constexpr unsigned long DndVersion = 3;
 | 
			
		||||
 | 
			
		||||
        Atom protocols, protocolList[3], changeState, state, userTime, activeWin, pid, windowType, windowState, windowStateHidden,
 | 
			
		||||
             XdndAware, XdndEnter, XdndLeave, XdndPosition, XdndStatus, XdndDrop, XdndFinished, XdndSelection,
 | 
			
		||||
             XdndTypeList, XdndActionList, XdndActionDescription, XdndActionCopy, XdndActionPrivate,
 | 
			
		||||
             XembedMsgType, XembedInfo, allowedActions[5], allowedMimeTypes[4], utf8String, clipboard, targets;
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    //==============================================================================
 | 
			
		||||
    /** Represents a setting according to the XSETTINGS specification.
 | 
			
		||||
 | 
			
		||||
        @tags{GUI}
 | 
			
		||||
    */
 | 
			
		||||
    struct XSetting
 | 
			
		||||
    {
 | 
			
		||||
        enum class Type
 | 
			
		||||
        {
 | 
			
		||||
            integer,
 | 
			
		||||
            string,
 | 
			
		||||
            colour,
 | 
			
		||||
            invalid
 | 
			
		||||
        };
 | 
			
		||||
 | 
			
		||||
        XSetting() = default;
 | 
			
		||||
 | 
			
		||||
        XSetting (const String& n, int v)            : name (n), type (Type::integer), integerValue (v)  {}
 | 
			
		||||
        XSetting (const String& n, const String& v)  : name (n), type (Type::string),  stringValue (v)   {}
 | 
			
		||||
        XSetting (const String& n, const Colour& v)  : name (n), type (Type::colour),  colourValue (v)   {}
 | 
			
		||||
 | 
			
		||||
        bool isValid() const noexcept  { return type != Type::invalid; }
 | 
			
		||||
 | 
			
		||||
        String name;
 | 
			
		||||
        Type type = Type::invalid;
 | 
			
		||||
 | 
			
		||||
        int integerValue = -1;
 | 
			
		||||
        String stringValue;
 | 
			
		||||
        Colour colourValue;
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    /** Parses and stores the X11 settings for a display according to the XSETTINGS
 | 
			
		||||
        specification.
 | 
			
		||||
 | 
			
		||||
        @tags{GUI}
 | 
			
		||||
    */
 | 
			
		||||
    class XSettings
 | 
			
		||||
    {
 | 
			
		||||
    public:
 | 
			
		||||
        static std::unique_ptr<XSettings> createXSettings (::Display*);
 | 
			
		||||
 | 
			
		||||
        //==============================================================================
 | 
			
		||||
        void update();
 | 
			
		||||
        ::Window getSettingsWindow() const noexcept  { return settingsWindow; }
 | 
			
		||||
 | 
			
		||||
        XSetting getSetting (const String& settingName) const;
 | 
			
		||||
 | 
			
		||||
        //==============================================================================
 | 
			
		||||
        struct Listener
 | 
			
		||||
        {
 | 
			
		||||
            virtual ~Listener() = default;
 | 
			
		||||
            virtual void settingChanged (const XSetting& settingThatHasChanged) = 0;
 | 
			
		||||
        };
 | 
			
		||||
 | 
			
		||||
        void addListener (Listener* listenerToAdd)        { listeners.add (listenerToAdd); }
 | 
			
		||||
        void removeListener (Listener* listenerToRemove)  { listeners.remove (listenerToRemove); }
 | 
			
		||||
 | 
			
		||||
    private:
 | 
			
		||||
        ::Display* display = nullptr;
 | 
			
		||||
        ::Window settingsWindow = None;
 | 
			
		||||
        Atom settingsAtom;
 | 
			
		||||
 | 
			
		||||
        int lastUpdateSerial = -1;
 | 
			
		||||
 | 
			
		||||
        std::unordered_map<String, XSetting> settings;
 | 
			
		||||
        ListenerList<Listener> listeners;
 | 
			
		||||
 | 
			
		||||
        XSettings (::Display*, Atom, ::Window);
 | 
			
		||||
 | 
			
		||||
        //==============================================================================
 | 
			
		||||
        JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (XSettings)
 | 
			
		||||
    };
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
//==============================================================================
 | 
			
		||||
class LinuxComponentPeer;
 | 
			
		||||
 | 
			
		||||
class XWindowSystem  : public DeletedAtShutdown
 | 
			
		||||
{
 | 
			
		||||
public:
 | 
			
		||||
    //==============================================================================
 | 
			
		||||
    ::Window createWindow (::Window parentWindow, LinuxComponentPeer*) const;
 | 
			
		||||
    void destroyWindow    (::Window);
 | 
			
		||||
 | 
			
		||||
    void setTitle (::Window, const String&) const;
 | 
			
		||||
    void setIcon (::Window , const Image&) const;
 | 
			
		||||
    void setVisible (::Window, bool shouldBeVisible) const;
 | 
			
		||||
    void setBounds (::Window, Rectangle<int>, bool fullScreen) const;
 | 
			
		||||
    void updateConstraints (::Window) const;
 | 
			
		||||
 | 
			
		||||
    ComponentPeer::OptionalBorderSize getBorderSize (::Window) const;
 | 
			
		||||
    Rectangle<int> getWindowBounds (::Window, ::Window parentWindow);
 | 
			
		||||
    Point<int> getPhysicalParentScreenPosition() const;
 | 
			
		||||
 | 
			
		||||
    bool contains (::Window, Point<int> localPos) const;
 | 
			
		||||
 | 
			
		||||
    void setMinimised (::Window, bool shouldBeMinimised) const;
 | 
			
		||||
    bool isMinimised  (::Window) const;
 | 
			
		||||
 | 
			
		||||
    void setMaximised (::Window, bool shouldBeMinimised) const;
 | 
			
		||||
 | 
			
		||||
    void toFront  (::Window, bool makeActive) const;
 | 
			
		||||
    void toBehind (::Window, ::Window otherWindow) const;
 | 
			
		||||
 | 
			
		||||
    bool isFocused (::Window) const;
 | 
			
		||||
    bool grabFocus (::Window) const;
 | 
			
		||||
 | 
			
		||||
    bool canUseSemiTransparentWindows() const;
 | 
			
		||||
    bool canUseARGBImages() const;
 | 
			
		||||
    bool isDarkModeActive() const;
 | 
			
		||||
 | 
			
		||||
    int getNumPaintsPendingForWindow (::Window);
 | 
			
		||||
    void processPendingPaintsForWindow (::Window);
 | 
			
		||||
    void addPendingPaintForWindow (::Window);
 | 
			
		||||
    void removePendingPaintForWindow (::Window);
 | 
			
		||||
 | 
			
		||||
    Image createImage (bool isSemiTransparentWindow, int width, int height, bool argb) const;
 | 
			
		||||
    void blitToWindow (::Window, Image, Rectangle<int> destinationRect, Rectangle<int> totalRect) const;
 | 
			
		||||
 | 
			
		||||
    void setScreenSaverEnabled (bool enabled) const;
 | 
			
		||||
 | 
			
		||||
    Point<float> getCurrentMousePosition() const;
 | 
			
		||||
    void setMousePosition (Point<float> pos) const;
 | 
			
		||||
 | 
			
		||||
    Cursor createCustomMouseCursorInfo (const Image&, Point<int> hotspot) const;
 | 
			
		||||
    void deleteMouseCursor (Cursor cursorHandle) const;
 | 
			
		||||
    Cursor createStandardMouseCursor (MouseCursor::StandardCursorType) const;
 | 
			
		||||
    void showCursor (::Window, Cursor cursorHandle) const;
 | 
			
		||||
 | 
			
		||||
    bool isKeyCurrentlyDown (int keyCode) const;
 | 
			
		||||
    ModifierKeys getNativeRealtimeModifiers() const;
 | 
			
		||||
 | 
			
		||||
    Array<Displays::Display> findDisplays (float masterScale) const;
 | 
			
		||||
 | 
			
		||||
    ::Window createKeyProxy (::Window) const;
 | 
			
		||||
    void deleteKeyProxy (::Window) const;
 | 
			
		||||
 | 
			
		||||
    bool externalDragFileInit (LinuxComponentPeer*, const StringArray& files, bool canMove, std::function<void()>&& callback) const;
 | 
			
		||||
    bool externalDragTextInit (LinuxComponentPeer*, const String& text, std::function<void()>&& callback) const;
 | 
			
		||||
 | 
			
		||||
    void copyTextToClipboard (const String&);
 | 
			
		||||
    String getTextFromClipboard() const;
 | 
			
		||||
    String getLocalClipboardContent() const noexcept  { return localClipboardContent; }
 | 
			
		||||
 | 
			
		||||
    ::Display* getDisplay() const noexcept                            { return display; }
 | 
			
		||||
    const XWindowSystemUtilities::Atoms& getAtoms() const noexcept    { return atoms; }
 | 
			
		||||
    XWindowSystemUtilities::XSettings* getXSettings() const noexcept  { return xSettings.get(); }
 | 
			
		||||
 | 
			
		||||
    bool isX11Available() const noexcept  { return xIsAvailable; }
 | 
			
		||||
 | 
			
		||||
    static String getWindowScalingFactorSettingName()  { return "Gdk/WindowScalingFactor"; }
 | 
			
		||||
    static String getThemeNameSettingName()            { return "Net/ThemeName"; }
 | 
			
		||||
 | 
			
		||||
    //==============================================================================
 | 
			
		||||
    void handleWindowMessage (LinuxComponentPeer*, XEvent&) const;
 | 
			
		||||
    bool isParentWindowOf (::Window, ::Window possibleChild) const;
 | 
			
		||||
 | 
			
		||||
    //==============================================================================
 | 
			
		||||
    JUCE_DECLARE_SINGLETON (XWindowSystem, false)
 | 
			
		||||
 | 
			
		||||
private:
 | 
			
		||||
    XWindowSystem();
 | 
			
		||||
    ~XWindowSystem();
 | 
			
		||||
 | 
			
		||||
    //==============================================================================
 | 
			
		||||
    struct VisualAndDepth
 | 
			
		||||
    {
 | 
			
		||||
        Visual* visual;
 | 
			
		||||
        int depth;
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    struct DisplayVisuals
 | 
			
		||||
    {
 | 
			
		||||
        explicit DisplayVisuals (::Display*);
 | 
			
		||||
 | 
			
		||||
        VisualAndDepth getBestVisualForWindow (bool) const;
 | 
			
		||||
        bool isValid() const noexcept;
 | 
			
		||||
 | 
			
		||||
        Visual* visual16Bit = nullptr;
 | 
			
		||||
        Visual* visual24Bit = nullptr;
 | 
			
		||||
        Visual* visual32Bit = nullptr;
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    bool initialiseXDisplay();
 | 
			
		||||
    void destroyXDisplay();
 | 
			
		||||
 | 
			
		||||
    //==============================================================================
 | 
			
		||||
    ::Window getFocusWindow (::Window) const;
 | 
			
		||||
 | 
			
		||||
    bool isFrontWindow (::Window) const;
 | 
			
		||||
 | 
			
		||||
    //==============================================================================
 | 
			
		||||
    void xchangeProperty (::Window, Atom, Atom, int, const void*, int) const;
 | 
			
		||||
 | 
			
		||||
    void removeWindowDecorations (::Window) const;
 | 
			
		||||
    void addWindowButtons        (::Window, int) const;
 | 
			
		||||
    void setWindowType           (::Window, int) const;
 | 
			
		||||
 | 
			
		||||
    void initialisePointerMap();
 | 
			
		||||
    void deleteIconPixmaps (::Window) const;
 | 
			
		||||
    void updateModifierMappings() const;
 | 
			
		||||
 | 
			
		||||
    long getUserTime (::Window) const;
 | 
			
		||||
 | 
			
		||||
    void initialiseXSettings();
 | 
			
		||||
 | 
			
		||||
    //==============================================================================
 | 
			
		||||
    void handleKeyPressEvent        (LinuxComponentPeer*, XKeyEvent&) const;
 | 
			
		||||
    void handleKeyReleaseEvent      (LinuxComponentPeer*, const XKeyEvent&) const;
 | 
			
		||||
    void handleWheelEvent           (LinuxComponentPeer*, const XButtonPressedEvent&, float) const;
 | 
			
		||||
    void handleButtonPressEvent     (LinuxComponentPeer*, const XButtonPressedEvent&, int) const;
 | 
			
		||||
    void handleButtonPressEvent     (LinuxComponentPeer*, const XButtonPressedEvent&) const;
 | 
			
		||||
    void handleButtonReleaseEvent   (LinuxComponentPeer*, const XButtonReleasedEvent&) const;
 | 
			
		||||
    void handleMotionNotifyEvent    (LinuxComponentPeer*, const XPointerMovedEvent&) const;
 | 
			
		||||
    void handleEnterNotifyEvent     (LinuxComponentPeer*, const XEnterWindowEvent&) const;
 | 
			
		||||
    void handleLeaveNotifyEvent     (LinuxComponentPeer*, const XLeaveWindowEvent&) const;
 | 
			
		||||
    void handleFocusInEvent         (LinuxComponentPeer*) const;
 | 
			
		||||
    void handleFocusOutEvent        (LinuxComponentPeer*) const;
 | 
			
		||||
    void handleExposeEvent          (LinuxComponentPeer*, XExposeEvent&) const;
 | 
			
		||||
    void handleConfigureNotifyEvent (LinuxComponentPeer*, XConfigureEvent&) const;
 | 
			
		||||
    void handleGravityNotify        (LinuxComponentPeer*) const;
 | 
			
		||||
    void propertyNotifyEvent        (LinuxComponentPeer*, const XPropertyEvent&) const;
 | 
			
		||||
    void handleMappingNotify        (XMappingEvent&) const;
 | 
			
		||||
    void handleClientMessageEvent   (LinuxComponentPeer*, XClientMessageEvent&, XEvent&) const;
 | 
			
		||||
    void handleXEmbedMessage        (LinuxComponentPeer*, XClientMessageEvent&) const;
 | 
			
		||||
 | 
			
		||||
    void dismissBlockingModals      (LinuxComponentPeer*) const;
 | 
			
		||||
    void dismissBlockingModals      (LinuxComponentPeer*, const XConfigureEvent&) const;
 | 
			
		||||
    void updateConstraints          (::Window, ComponentPeer&) const;
 | 
			
		||||
 | 
			
		||||
    ::Window findTopLevelWindowOf (::Window) const;
 | 
			
		||||
 | 
			
		||||
    static void windowMessageReceive (XEvent&);
 | 
			
		||||
 | 
			
		||||
    //==============================================================================
 | 
			
		||||
    bool xIsAvailable = false;
 | 
			
		||||
 | 
			
		||||
    XWindowSystemUtilities::Atoms atoms;
 | 
			
		||||
    ::Display* display = nullptr;
 | 
			
		||||
    std::unique_ptr<DisplayVisuals> displayVisuals;
 | 
			
		||||
    std::unique_ptr<XWindowSystemUtilities::XSettings> xSettings;
 | 
			
		||||
 | 
			
		||||
   #if JUCE_USE_XSHM
 | 
			
		||||
    std::map<::Window, int> shmPaintsPendingMap;
 | 
			
		||||
   #endif
 | 
			
		||||
 | 
			
		||||
    int shmCompletionEvent = 0;
 | 
			
		||||
    int pointerMap[5] = {};
 | 
			
		||||
    String localClipboardContent;
 | 
			
		||||
 | 
			
		||||
    Point<int> parentScreenPosition;
 | 
			
		||||
 | 
			
		||||
    //==============================================================================
 | 
			
		||||
    JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (XWindowSystem)
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
} // namespace juce
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user