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