mirror of
https://github.com/juce-framework/JUCE.git
synced 2026-01-11 23:54:18 +00:00
MouseCursor: Refactor platform-specific MouseCursor internals
This new factoring is a bit more typesafe, as it avoids casting internals to void*. It also allows cursors to scale appropriately on high resolution displays on Windows.
This commit is contained in:
parent
5c50ee4f94
commit
fe4515adb6
10 changed files with 374 additions and 250 deletions
|
|
@ -124,7 +124,20 @@ namespace juce
|
|||
}
|
||||
|
||||
bool isWindowOnCurrentVirtualDesktop (void*);
|
||||
}
|
||||
|
||||
struct CustomMouseCursorInfo
|
||||
{
|
||||
CustomMouseCursorInfo() = default;
|
||||
|
||||
CustomMouseCursorInfo (const Image& im, Point<int> hs, float scale = 1.0f) noexcept
|
||||
: image (im), hotspot (hs), scaleFactor (scale)
|
||||
{}
|
||||
|
||||
Image image;
|
||||
Point<int> hotspot;
|
||||
float scaleFactor = 1.0f;
|
||||
};
|
||||
} // namespace juce
|
||||
|
||||
#include "accessibility/juce_AccessibilityHandler.cpp"
|
||||
#include "components/juce_Component.cpp"
|
||||
|
|
@ -136,7 +149,6 @@ namespace juce
|
|||
#include "components/juce_ModalComponentManager.cpp"
|
||||
#include "mouse/juce_ComponentDragger.cpp"
|
||||
#include "mouse/juce_DragAndDropContainer.cpp"
|
||||
#include "mouse/juce_MouseCursor.cpp"
|
||||
#include "mouse/juce_MouseEvent.cpp"
|
||||
#include "mouse/juce_MouseInactivityDetector.cpp"
|
||||
#include "mouse/juce_MouseListener.cpp"
|
||||
|
|
@ -428,3 +440,6 @@ bool juce::isWindowOnCurrentVirtualDesktop (void* x)
|
|||
juce::ScopedDPIAwarenessDisabler::ScopedDPIAwarenessDisabler() { ignoreUnused (previousContext); }
|
||||
juce::ScopedDPIAwarenessDisabler::~ScopedDPIAwarenessDisabler() {}
|
||||
#endif
|
||||
|
||||
// Depends on types defined in platform-specific windowing files
|
||||
#include "mouse/juce_MouseCursor.cpp"
|
||||
|
|
|
|||
|
|
@ -26,34 +26,21 @@
|
|||
namespace juce
|
||||
{
|
||||
|
||||
struct CustomMouseCursorInfo
|
||||
{
|
||||
CustomMouseCursorInfo (const Image& im, Point<int> hs, float scale = 1.0f) noexcept
|
||||
: image (im), hotspot (hs), scaleFactor (scale)
|
||||
{}
|
||||
|
||||
void* create() const;
|
||||
|
||||
Image image;
|
||||
const Point<int> hotspot;
|
||||
const float scaleFactor;
|
||||
|
||||
JUCE_DECLARE_NON_COPYABLE (CustomMouseCursorInfo)
|
||||
};
|
||||
|
||||
class MouseCursor::SharedCursorHandle
|
||||
{
|
||||
public:
|
||||
explicit SharedCursorHandle (const MouseCursor::StandardCursorType type)
|
||||
: handle (createStandardMouseCursor (type), Deleter { true }),
|
||||
standardType (type)
|
||||
: handle (type),
|
||||
standardType (type),
|
||||
standard (true)
|
||||
{
|
||||
}
|
||||
|
||||
SharedCursorHandle (const Image& image, Point<int> hotSpot, float scaleFactor)
|
||||
: info (std::make_unique<CustomMouseCursorInfo> (image, hotSpot, scaleFactor)),
|
||||
handle (info->create(), Deleter { false }),
|
||||
standardType (MouseCursor::NormalCursor)
|
||||
: info { image, hotSpot, scaleFactor },
|
||||
handle (info),
|
||||
standardType (MouseCursor::NormalCursor),
|
||||
standard (false)
|
||||
{
|
||||
// your hotspot needs to be within the bounds of the image!
|
||||
jassert (image.getBounds().contains (hotSpot));
|
||||
|
|
@ -81,23 +68,17 @@ public:
|
|||
|
||||
bool isStandardType (MouseCursor::StandardCursorType type) const noexcept
|
||||
{
|
||||
return type == standardType && handle.get_deleter().isStandard;
|
||||
return type == standardType && standard;
|
||||
}
|
||||
|
||||
void* getHandle() const noexcept { return handle.get(); }
|
||||
PlatformSpecificHandle* getHandle() noexcept { return &handle; }
|
||||
MouseCursor::StandardCursorType getType() const noexcept { return standardType; }
|
||||
CustomMouseCursorInfo* getCustomInfo() const noexcept { return info.get(); }
|
||||
|
||||
private:
|
||||
struct Deleter
|
||||
{
|
||||
void operator() (void* ptr) const noexcept { deleteMouseCursor (ptr, isStandard); }
|
||||
const bool isStandard;
|
||||
};
|
||||
|
||||
std::unique_ptr<CustomMouseCursorInfo> info;
|
||||
std::unique_ptr<void, Deleter> handle;
|
||||
CustomMouseCursorInfo info;
|
||||
PlatformSpecificHandle handle;
|
||||
const MouseCursor::StandardCursorType standardType;
|
||||
const bool standard;
|
||||
|
||||
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (SharedCursorHandle)
|
||||
};
|
||||
|
|
@ -144,11 +125,6 @@ bool MouseCursor::operator== (StandardCursorType type) const noexcept
|
|||
bool MouseCursor::operator!= (const MouseCursor& other) const noexcept { return ! operator== (other); }
|
||||
bool MouseCursor::operator!= (StandardCursorType type) const noexcept { return ! operator== (type); }
|
||||
|
||||
void* MouseCursor::getHandle() const noexcept
|
||||
{
|
||||
return cursorHandle != nullptr ? cursorHandle->getHandle() : nullptr;
|
||||
}
|
||||
|
||||
void MouseCursor::showWaitCursor()
|
||||
{
|
||||
Desktop::getInstance().getMainMouseSource().showMouseCursor (MouseCursor::WaitCursor);
|
||||
|
|
@ -159,4 +135,14 @@ void MouseCursor::hideWaitCursor()
|
|||
Desktop::getInstance().getMainMouseSource().revealCursor();
|
||||
}
|
||||
|
||||
MouseCursor::PlatformSpecificHandle* MouseCursor::getHandle() const noexcept
|
||||
{
|
||||
return cursorHandle != nullptr ? cursorHandle->getHandle() : nullptr;
|
||||
}
|
||||
|
||||
void MouseCursor::showInWindow (ComponentPeer* peer) const
|
||||
{
|
||||
PlatformSpecificHandle::showInWindow (getHandle(), peer);
|
||||
}
|
||||
|
||||
} // namespace juce
|
||||
|
|
|
|||
|
|
@ -168,12 +168,11 @@ private:
|
|||
class SharedCursorHandle;
|
||||
std::shared_ptr<SharedCursorHandle> cursorHandle;
|
||||
|
||||
class PlatformSpecificHandle;
|
||||
|
||||
friend class MouseInputSourceInternal;
|
||||
void showInWindow (ComponentPeer*) const;
|
||||
void* getHandle() const noexcept;
|
||||
|
||||
static void* createStandardMouseCursor (MouseCursor::StandardCursorType);
|
||||
static void deleteMouseCursor (void* cursorHandle, bool isStandard);
|
||||
PlatformSpecificHandle* getHandle() const noexcept;
|
||||
|
||||
JUCE_LEAK_DETECTOR (MouseCursor)
|
||||
};
|
||||
|
|
|
|||
|
|
@ -1873,12 +1873,14 @@ Image juce_createIconForFile (const File& /*file*/)
|
|||
}
|
||||
|
||||
//==============================================================================
|
||||
void* CustomMouseCursorInfo::create() const { return nullptr; }
|
||||
void* MouseCursor::createStandardMouseCursor (MouseCursor::StandardCursorType) { return nullptr; }
|
||||
void MouseCursor::deleteMouseCursor (void* /*cursorHandle*/, bool /*isStandard*/) {}
|
||||
class MouseCursor::PlatformSpecificHandle
|
||||
{
|
||||
public:
|
||||
PlatformSpecificHandle (const MouseCursor::StandardCursorType) {}
|
||||
PlatformSpecificHandle (const CustomMouseCursorInfo&) {}
|
||||
|
||||
//==============================================================================
|
||||
void MouseCursor::showInWindow (ComponentPeer*) const {}
|
||||
static void showInWindow (PlatformSpecificHandle*, ComponentPeer*) {}
|
||||
};
|
||||
|
||||
//==============================================================================
|
||||
bool DragAndDropContainer::performExternalDragDropOfFiles (const StringArray& /*files*/, bool /*canMove*/,
|
||||
|
|
|
|||
|
|
@ -648,27 +648,46 @@ void MouseInputSource::setRawMousePosition (Point<float> newPosition)
|
|||
}
|
||||
|
||||
//==============================================================================
|
||||
void* CustomMouseCursorInfo::create() const
|
||||
class MouseCursor::PlatformSpecificHandle
|
||||
{
|
||||
return XWindowSystem::getInstance()->createCustomMouseCursorInfo (image, hotspot);
|
||||
}
|
||||
public:
|
||||
explicit PlatformSpecificHandle (const MouseCursor::StandardCursorType type)
|
||||
: cursorHandle (makeHandle (type)) {}
|
||||
|
||||
void MouseCursor::deleteMouseCursor (void* cursorHandle, bool)
|
||||
{
|
||||
if (cursorHandle != nullptr)
|
||||
XWindowSystem::getInstance()->deleteMouseCursor (cursorHandle);
|
||||
}
|
||||
explicit PlatformSpecificHandle (const CustomMouseCursorInfo& info)
|
||||
: cursorHandle (makeHandle (info)) {}
|
||||
|
||||
void* MouseCursor::createStandardMouseCursor (MouseCursor::StandardCursorType type)
|
||||
{
|
||||
return XWindowSystem::getInstance()->createStandardMouseCursor (type);
|
||||
}
|
||||
~PlatformSpecificHandle()
|
||||
{
|
||||
if (cursorHandle != Cursor{})
|
||||
XWindowSystem::getInstance()->deleteMouseCursor (cursorHandle);
|
||||
}
|
||||
|
||||
void MouseCursor::showInWindow (ComponentPeer* peer) const
|
||||
{
|
||||
if (peer != nullptr)
|
||||
XWindowSystem::getInstance()->showCursor ((::Window) peer->getNativeHandle(), getHandle());
|
||||
}
|
||||
static void showInWindow (PlatformSpecificHandle* handle, ComponentPeer* peer)
|
||||
{
|
||||
const auto cursor = handle != nullptr ? handle->cursorHandle : Cursor{};
|
||||
|
||||
if (peer != nullptr)
|
||||
XWindowSystem::getInstance()->showCursor ((::Window) peer->getNativeHandle(), cursor);
|
||||
}
|
||||
|
||||
private:
|
||||
static Cursor makeHandle (const CustomMouseCursorInfo& info)
|
||||
{
|
||||
return XWindowSystem::getInstance()->createCustomMouseCursorInfo (info.image, info.hotspot);
|
||||
}
|
||||
|
||||
static Cursor makeHandle (MouseCursor::StandardCursorType type)
|
||||
{
|
||||
return XWindowSystem::getInstance()->createStandardMouseCursor (type);
|
||||
}
|
||||
|
||||
Cursor cursorHandle;
|
||||
|
||||
//==============================================================================
|
||||
JUCE_DECLARE_NON_COPYABLE (PlatformSpecificHandle)
|
||||
JUCE_DECLARE_NON_MOVEABLE (PlatformSpecificHandle)
|
||||
};
|
||||
|
||||
//==============================================================================
|
||||
static LinuxComponentPeer* getPeerForDragEvent (Component* sourceComp)
|
||||
|
|
|
|||
|
|
@ -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, info.scaleFactor),
|
||||
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 ({ 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
|
||||
|
||||
|
|
|
|||
|
|
@ -353,6 +353,7 @@ using SetProcessDPIAwarenessFunc = HRESULT (WINAPI*)
|
|||
using SetThreadDPIAwarenessContextFunc = DPI_AWARENESS_CONTEXT (WINAPI*) (DPI_AWARENESS_CONTEXT);
|
||||
using GetDPIForWindowFunc = UINT (WINAPI*) (HWND);
|
||||
using GetDPIForMonitorFunc = HRESULT (WINAPI*) (HMONITOR, Monitor_DPI_Type, UINT*, UINT*);
|
||||
using GetSystemMetricsForDpiFunc = int (WINAPI*) (int, UINT);
|
||||
using GetProcessDPIAwarenessFunc = HRESULT (WINAPI*) (HANDLE, DPI_Awareness*);
|
||||
using GetWindowDPIAwarenessContextFunc = DPI_AWARENESS_CONTEXT (WINAPI*) (HWND);
|
||||
using GetThreadDPIAwarenessContextFunc = DPI_AWARENESS_CONTEXT (WINAPI*) ();
|
||||
|
|
@ -5134,85 +5135,178 @@ Image juce_createIconForFile (const File& file)
|
|||
}
|
||||
|
||||
//==============================================================================
|
||||
void* CustomMouseCursorInfo::create() const
|
||||
class MouseCursor::PlatformSpecificHandle
|
||||
{
|
||||
const int maxW = GetSystemMetrics (SM_CXCURSOR);
|
||||
const int maxH = GetSystemMetrics (SM_CYCURSOR);
|
||||
public:
|
||||
explicit PlatformSpecificHandle (const MouseCursor::StandardCursorType type)
|
||||
: impl (makeHandle (type)) {}
|
||||
|
||||
Image im (image);
|
||||
int hotspotX = hotspot.x;
|
||||
int hotspotY = hotspot.y;
|
||||
explicit PlatformSpecificHandle (const CustomMouseCursorInfo& info)
|
||||
: impl (makeHandle (info)) {}
|
||||
|
||||
if (im.getWidth() > maxW || im.getHeight() > maxH)
|
||||
static void showInWindow (PlatformSpecificHandle* handle, ComponentPeer* peer)
|
||||
{
|
||||
im = im.rescaled (maxW, maxH);
|
||||
SetCursor ([&]
|
||||
{
|
||||
if (handle != nullptr && handle->impl != nullptr && peer != nullptr)
|
||||
return handle->impl->getCursor (*peer);
|
||||
|
||||
hotspotX = (hotspotX * maxW) / juce::jmax (1, image.getWidth());
|
||||
hotspotY = (hotspotY * maxH) / juce::jmax (1, image.getHeight());
|
||||
return LoadCursor (nullptr, IDC_ARROW);
|
||||
}());
|
||||
}
|
||||
|
||||
return IconConverters::createHICONFromImage (im, FALSE, hotspotX, hotspotY);
|
||||
}
|
||||
|
||||
void MouseCursor::deleteMouseCursor (void* cursorHandle, bool isStandard)
|
||||
{
|
||||
if (cursorHandle != nullptr && ! isStandard)
|
||||
DestroyCursor ((HCURSOR) cursorHandle);
|
||||
}
|
||||
|
||||
enum
|
||||
{
|
||||
hiddenMouseCursorHandle = 32500 // (arbitrary non-zero value to mark this type of cursor)
|
||||
};
|
||||
|
||||
void* MouseCursor::createStandardMouseCursor (const MouseCursor::StandardCursorType type)
|
||||
{
|
||||
LPCTSTR cursorName = IDC_ARROW;
|
||||
|
||||
switch (type)
|
||||
private:
|
||||
struct Impl
|
||||
{
|
||||
case NormalCursor:
|
||||
case ParentCursor: break;
|
||||
case NoCursor: return (void*) hiddenMouseCursorHandle;
|
||||
case WaitCursor: cursorName = IDC_WAIT; break;
|
||||
case IBeamCursor: cursorName = IDC_IBEAM; break;
|
||||
case PointingHandCursor: cursorName = MAKEINTRESOURCE(32649); break;
|
||||
case CrosshairCursor: cursorName = IDC_CROSS; break;
|
||||
virtual ~Impl() = default;
|
||||
virtual HCURSOR getCursor (ComponentPeer&) = 0;
|
||||
};
|
||||
|
||||
case LeftRightResizeCursor:
|
||||
case LeftEdgeResizeCursor:
|
||||
case RightEdgeResizeCursor: cursorName = IDC_SIZEWE; break;
|
||||
class BuiltinImpl : public Impl
|
||||
{
|
||||
public:
|
||||
explicit BuiltinImpl (HCURSOR cursorIn)
|
||||
: cursor (cursorIn) {}
|
||||
|
||||
case UpDownResizeCursor:
|
||||
case TopEdgeResizeCursor:
|
||||
case BottomEdgeResizeCursor: cursorName = IDC_SIZENS; break;
|
||||
HCURSOR getCursor (ComponentPeer&) override { return cursor; }
|
||||
|
||||
case TopLeftCornerResizeCursor:
|
||||
case BottomRightCornerResizeCursor: cursorName = IDC_SIZENWSE; break;
|
||||
private:
|
||||
HCURSOR cursor;
|
||||
};
|
||||
|
||||
case TopRightCornerResizeCursor:
|
||||
case BottomLeftCornerResizeCursor: cursorName = IDC_SIZENESW; break;
|
||||
class ImageImpl : public Impl
|
||||
{
|
||||
public:
|
||||
ImageImpl (Image imageIn, Point<int> hotspotIn)
|
||||
: image (std::move (imageIn)), hotspot (hotspotIn) {}
|
||||
|
||||
case UpDownLeftRightResizeCursor: cursorName = IDC_SIZEALL; break;
|
||||
|
||||
case DraggingHandCursor:
|
||||
~ImageImpl() override
|
||||
{
|
||||
static void* dragHandCursor = []
|
||||
for (auto& pair : cursorsBySize)
|
||||
DestroyCursor (pair.second);
|
||||
}
|
||||
|
||||
HCURSOR getCursor (ComponentPeer& peer) override
|
||||
{
|
||||
JUCE_ASSERT_MESSAGE_THREAD;
|
||||
|
||||
static auto getCursorSize = getCursorSizeForPeerFunction();
|
||||
|
||||
const auto size = getCursorSize (peer);
|
||||
const auto iter = cursorsBySize.find (size);
|
||||
|
||||
if (iter != cursorsBySize.end())
|
||||
return iter->second;
|
||||
|
||||
const auto imgW = jmax (1, image.getWidth());
|
||||
const auto imgH = jmax (1, image.getHeight());
|
||||
|
||||
const auto scale = (float) size / (float) unityCursorSize;
|
||||
const auto scaleToUse = scale * jmin (1.0f, jmin ((float) unityCursorSize / (float) imgW,
|
||||
(float) unityCursorSize / (float) imgH));
|
||||
const auto rescaled = image.rescaled (roundToInt (scaleToUse * (float) imgW),
|
||||
roundToInt (scaleToUse * (float) imgH));
|
||||
const auto hx = jlimit (0, rescaled.getWidth(), roundToInt (scaleToUse * (float) hotspot.x));
|
||||
const auto hy = jlimit (0, rescaled.getHeight(), roundToInt (scaleToUse * (float) hotspot.y));
|
||||
|
||||
return cursorsBySize.emplace (size, IconConverters::createHICONFromImage (rescaled, false, hx, hy)).first->second;
|
||||
}
|
||||
|
||||
private:
|
||||
Image image;
|
||||
Point<int> hotspot;
|
||||
std::map<int, HCURSOR> cursorsBySize;
|
||||
};
|
||||
|
||||
static auto getCursorSizeForPeerFunction() -> int (*) (ComponentPeer&)
|
||||
{
|
||||
static const auto getDpiForMonitor = []() -> GetDPIForMonitorFunc
|
||||
{
|
||||
constexpr auto library = "SHCore.dll";
|
||||
LoadLibraryA (library);
|
||||
|
||||
if (auto* handle = GetModuleHandleA (library))
|
||||
return (GetDPIForMonitorFunc) GetProcAddress (handle, "GetDpiForMonitor");
|
||||
|
||||
return nullptr;
|
||||
}();
|
||||
|
||||
static const auto getSystemMetricsForDpi = []() -> GetSystemMetricsForDpiFunc
|
||||
{
|
||||
constexpr auto library = "User32.dll";
|
||||
LoadLibraryA (library);
|
||||
|
||||
if (auto* handle = GetModuleHandleA (library))
|
||||
return (GetSystemMetricsForDpiFunc) GetProcAddress (handle, "GetSystemMetricsForDpi");
|
||||
|
||||
return nullptr;
|
||||
}();
|
||||
|
||||
if (getDpiForMonitor == nullptr || getSystemMetricsForDpi == nullptr)
|
||||
return [] (ComponentPeer&) { return unityCursorSize; };
|
||||
|
||||
return [] (ComponentPeer& p)
|
||||
{
|
||||
const ScopedThreadDPIAwarenessSetter threadDpiAwarenessSetter { p.getNativeHandle() };
|
||||
|
||||
UINT dpiX = 0, dpiY = 0;
|
||||
|
||||
if (auto* monitor = MonitorFromWindow ((HWND) p.getNativeHandle(), MONITOR_DEFAULTTONULL))
|
||||
if (SUCCEEDED (getDpiForMonitor (monitor, MDT_Default, &dpiX, &dpiY)))
|
||||
return getSystemMetricsForDpi (SM_CXCURSOR, dpiX);
|
||||
|
||||
return unityCursorSize;
|
||||
};
|
||||
}
|
||||
|
||||
static constexpr auto unityCursorSize = 32;
|
||||
|
||||
static std::unique_ptr<Impl> makeHandle (const CustomMouseCursorInfo& info)
|
||||
{
|
||||
return std::make_unique<ImageImpl> (info.image, info.hotspot);
|
||||
}
|
||||
|
||||
static std::unique_ptr<Impl> makeHandle (const MouseCursor::StandardCursorType type)
|
||||
{
|
||||
LPCTSTR cursorName = IDC_ARROW;
|
||||
|
||||
switch (type)
|
||||
{
|
||||
case NormalCursor:
|
||||
case ParentCursor: break;
|
||||
case NoCursor: return std::make_unique<BuiltinImpl> (nullptr);
|
||||
case WaitCursor: cursorName = IDC_WAIT; break;
|
||||
case IBeamCursor: cursorName = IDC_IBEAM; break;
|
||||
case PointingHandCursor: cursorName = MAKEINTRESOURCE(32649); break;
|
||||
case CrosshairCursor: cursorName = IDC_CROSS; break;
|
||||
|
||||
case LeftRightResizeCursor:
|
||||
case LeftEdgeResizeCursor:
|
||||
case RightEdgeResizeCursor: cursorName = IDC_SIZEWE; break;
|
||||
|
||||
case UpDownResizeCursor:
|
||||
case TopEdgeResizeCursor:
|
||||
case BottomEdgeResizeCursor: cursorName = IDC_SIZENS; break;
|
||||
|
||||
case TopLeftCornerResizeCursor:
|
||||
case BottomRightCornerResizeCursor: cursorName = IDC_SIZENWSE; break;
|
||||
|
||||
case TopRightCornerResizeCursor:
|
||||
case BottomLeftCornerResizeCursor: cursorName = IDC_SIZENESW; break;
|
||||
|
||||
case UpDownLeftRightResizeCursor: cursorName = IDC_SIZEALL; break;
|
||||
|
||||
case DraggingHandCursor:
|
||||
{
|
||||
static const unsigned char dragHandData[]
|
||||
{ 71,73,70,56,57,97,16,0,16,0,145,2,0,0,0,0,255,255,255,0,0,0,0,0,0,33,249,4,1,0,0,2,0,44,0,0,0,0,16,0,
|
||||
16,0,0,2,52,148,47,0,200,185,16,130,90,12,74,139,107,84,123,39,132,117,151,116,132,146,248,60,209,138,
|
||||
98,22,203,114,34,236,37,52,77,217,247,154,191,119,110,240,193,128,193,95,163,56,60,234,98,135,2,0,59 };
|
||||
|
||||
return CustomMouseCursorInfo (ImageFileFormat::loadFrom (dragHandData, sizeof (dragHandData)), { 8, 7 }).create();
|
||||
}();
|
||||
return makeHandle ({ ImageFileFormat::loadFrom (dragHandData, sizeof (dragHandData)), { 8, 7 } });
|
||||
}
|
||||
|
||||
return dragHandCursor;
|
||||
}
|
||||
|
||||
case CopyingCursor:
|
||||
{
|
||||
static void* copyCursor = []
|
||||
case CopyingCursor:
|
||||
{
|
||||
static const unsigned char copyCursorData[]
|
||||
{ 71,73,70,56,57,97,21,0,21,0,145,0,0,0,0,0,255,255,255,0,128,128,255,255,255,33,249,4,1,0,0,3,0,44,0,0,0,0,21,0,
|
||||
|
|
@ -5220,36 +5314,27 @@ void* MouseCursor::createStandardMouseCursor (const MouseCursor::StandardCursorT
|
|||
12,108,212,87,235,174, 15,54,214,126,237,226,37,96,59,141,16,37,18,201,142,157,230,204,51,112,252,114,147,74,83,
|
||||
5,50,68,147,208,217,16,71,149,252,124,5,0,59,0,0 };
|
||||
|
||||
return CustomMouseCursorInfo (ImageFileFormat::loadFrom (copyCursorData, sizeof (copyCursorData)), { 1, 3 }).create();
|
||||
}();
|
||||
return makeHandle ({ ImageFileFormat::loadFrom (copyCursorData, sizeof (copyCursorData)), { 1, 3 } });
|
||||
}
|
||||
|
||||
return copyCursor;
|
||||
case NumStandardCursorTypes: JUCE_FALLTHROUGH
|
||||
default:
|
||||
jassertfalse; break;
|
||||
}
|
||||
|
||||
case NumStandardCursorTypes: JUCE_FALLTHROUGH
|
||||
default:
|
||||
jassertfalse; break;
|
||||
return std::make_unique<BuiltinImpl> ([&]
|
||||
{
|
||||
if (auto* c = LoadCursor (nullptr, cursorName))
|
||||
return c;
|
||||
|
||||
return LoadCursor (nullptr, IDC_ARROW);
|
||||
}());
|
||||
}
|
||||
|
||||
if (auto cursorH = LoadCursor (nullptr, cursorName))
|
||||
return cursorH;
|
||||
|
||||
return LoadCursor (nullptr, IDC_ARROW);
|
||||
}
|
||||
std::unique_ptr<Impl> impl;
|
||||
};
|
||||
|
||||
//==============================================================================
|
||||
void MouseCursor::showInWindow (ComponentPeer*) const
|
||||
{
|
||||
auto c = (HCURSOR) getHandle();
|
||||
|
||||
if (c == nullptr)
|
||||
c = LoadCursor (nullptr, IDC_ARROW);
|
||||
else if (c == (HCURSOR) hiddenMouseCursorHandle)
|
||||
c = nullptr;
|
||||
|
||||
SetCursor (c);
|
||||
}
|
||||
|
||||
JUCE_END_IGNORE_WARNINGS_GCC_LIKE
|
||||
|
||||
} // namespace juce
|
||||
|
|
|
|||
|
|
@ -26,8 +26,8 @@
|
|||
namespace juce
|
||||
{
|
||||
|
||||
extern void* createDraggingHandCursor();
|
||||
extern ComponentPeer* getPeerFor (::Window);
|
||||
static Cursor createDraggingHandCursor();
|
||||
ComponentPeer* getPeerFor (::Window);
|
||||
|
||||
//==============================================================================
|
||||
class X11DragState
|
||||
|
|
|
|||
|
|
@ -2193,10 +2193,10 @@ void XWindowSystem::setMousePosition (Point<float> pos) const
|
|||
roundToInt (pos.getX()), roundToInt (pos.getY()));
|
||||
}
|
||||
|
||||
void* XWindowSystem::createCustomMouseCursorInfo (const Image& image, Point<int> hotspot) const
|
||||
Cursor XWindowSystem::createCustomMouseCursorInfo (const Image& image, Point<int> hotspot) const
|
||||
{
|
||||
if (display == nullptr)
|
||||
return nullptr;
|
||||
return {};
|
||||
|
||||
XWindowSystemUtilities::ScopedXLock xLock;
|
||||
|
||||
|
|
@ -2217,9 +2217,9 @@ void* XWindowSystem::createCustomMouseCursorInfo (const Image& image, Point<int>
|
|||
for (int x = 0; x < (int) imageW; ++x)
|
||||
*dest++ = image.getPixelAt (x, y).getARGB();
|
||||
|
||||
auto* result = (void*) X11Symbols::getInstance()->xcursorImageLoadCursor (display, xcImage.get());
|
||||
auto result = X11Symbols::getInstance()->xcursorImageLoadCursor (display, xcImage.get());
|
||||
|
||||
if (result != nullptr)
|
||||
if (result != Cursor{})
|
||||
return result;
|
||||
}
|
||||
#endif
|
||||
|
|
@ -2229,7 +2229,7 @@ void* XWindowSystem::createCustomMouseCursorInfo (const Image& image, Point<int>
|
|||
|
||||
unsigned int cursorW, cursorH;
|
||||
if (! X11Symbols::getInstance()->xQueryBestCursor (display, root, imageW, imageH, &cursorW, &cursorH))
|
||||
return nullptr;
|
||||
return {};
|
||||
|
||||
Image im (Image::ARGB, (int) cursorW, (int) cursorH, true);
|
||||
|
||||
|
|
@ -2279,20 +2279,20 @@ void* XWindowSystem::createCustomMouseCursorInfo (const Image& image, Point<int>
|
|||
black.red = black.green = black.blue = 0;
|
||||
white.red = white.green = white.blue = 0xffff;
|
||||
|
||||
return (void*) X11Symbols::getInstance()->xCreatePixmapCursor (display, sourcePixmap.value, maskPixmap.value, &white, &black,
|
||||
(unsigned int) hotspotX, (unsigned int) hotspotY);
|
||||
return X11Symbols::getInstance()->xCreatePixmapCursor (display, sourcePixmap.value, maskPixmap.value, &white, &black,
|
||||
(unsigned int) hotspotX, (unsigned int) hotspotY);
|
||||
}
|
||||
|
||||
void XWindowSystem::deleteMouseCursor (void* cursorHandle) const
|
||||
void XWindowSystem::deleteMouseCursor (Cursor cursorHandle) const
|
||||
{
|
||||
if (cursorHandle != nullptr && display != nullptr)
|
||||
if (cursorHandle != Cursor{} && display != nullptr)
|
||||
{
|
||||
XWindowSystemUtilities::ScopedXLock xLock;
|
||||
X11Symbols::getInstance()->xFreeCursor (display, (Cursor) cursorHandle);
|
||||
}
|
||||
}
|
||||
|
||||
void* createDraggingHandCursor()
|
||||
static Cursor createDraggingHandCursor()
|
||||
{
|
||||
constexpr unsigned char dragHandData[] = {
|
||||
71,73,70,56,57,97,16,0,16,0,145,2,0,0,0,0,255,255,255,0,0,0,0,0,0,33,249,4,1,0,0,2,0,44,0,0,0,0,16,0,16,0,
|
||||
|
|
@ -2300,10 +2300,11 @@ void* createDraggingHandCursor()
|
|||
114,34,236,37,52,77,217, 247,154,191,119,110,240,193,128,193,95,163,56,60,234,98,135,2,0,59
|
||||
};
|
||||
|
||||
return CustomMouseCursorInfo (ImageFileFormat::loadFrom (dragHandData, (size_t) numElementsInArray (dragHandData)), { 8, 7 }).create();
|
||||
auto image = ImageFileFormat::loadFrom (dragHandData, (size_t) numElementsInArray (dragHandData));
|
||||
return XWindowSystem::getInstance()->createCustomMouseCursorInfo (std::move (image), { 8, 7 });
|
||||
}
|
||||
|
||||
void* XWindowSystem::createStandardMouseCursor (MouseCursor::StandardCursorType type) const
|
||||
Cursor XWindowSystem::createStandardMouseCursor (MouseCursor::StandardCursorType type) const
|
||||
{
|
||||
if (display == nullptr)
|
||||
return None;
|
||||
|
|
@ -2314,7 +2315,7 @@ void* XWindowSystem::createStandardMouseCursor (MouseCursor::StandardCursorType
|
|||
{
|
||||
case MouseCursor::NormalCursor:
|
||||
case MouseCursor::ParentCursor: return None; // Use parent cursor
|
||||
case MouseCursor::NoCursor: return CustomMouseCursorInfo (Image (Image::ARGB, 16, 16, true), {}).create();
|
||||
case MouseCursor::NoCursor: return XWindowSystem::createCustomMouseCursorInfo (Image (Image::ARGB, 16, 16, true), {});
|
||||
|
||||
case MouseCursor::WaitCursor: shape = XC_watch; break;
|
||||
case MouseCursor::IBeamCursor: shape = XC_xterm; break;
|
||||
|
|
@ -2342,7 +2343,8 @@ void* XWindowSystem::createStandardMouseCursor (MouseCursor::StandardCursorType
|
|||
252,114,147,74,83,5,50,68,147,208,217,16,71,149,252,124,5,0,59,0,0
|
||||
};
|
||||
|
||||
return CustomMouseCursorInfo (ImageFileFormat::loadFrom (copyCursorData, (size_t) numElementsInArray (copyCursorData)), { 1, 3 }).create();
|
||||
auto image = ImageFileFormat::loadFrom (copyCursorData, (size_t) numElementsInArray (copyCursorData));
|
||||
return createCustomMouseCursorInfo (std::move (image), { 1, 3 });
|
||||
}
|
||||
|
||||
case MouseCursor::NumStandardCursorTypes:
|
||||
|
|
@ -2355,10 +2357,10 @@ void* XWindowSystem::createStandardMouseCursor (MouseCursor::StandardCursorType
|
|||
|
||||
XWindowSystemUtilities::ScopedXLock xLock;
|
||||
|
||||
return (void*) X11Symbols::getInstance()->xCreateFontCursor (display, shape);
|
||||
return X11Symbols::getInstance()->xCreateFontCursor (display, shape);
|
||||
}
|
||||
|
||||
void XWindowSystem::showCursor (::Window windowH, void* cursorHandle) const
|
||||
void XWindowSystem::showCursor (::Window windowH, Cursor cursorHandle) const
|
||||
{
|
||||
jassert (windowH != 0);
|
||||
|
||||
|
|
|
|||
|
|
@ -213,10 +213,10 @@ public:
|
|||
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;
|
||||
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;
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue