diff --git a/modules/juce_gui_basics/juce_gui_basics.cpp b/modules/juce_gui_basics/juce_gui_basics.cpp index d150073588..5d913cac44 100644 --- a/modules/juce_gui_basics/juce_gui_basics.cpp +++ b/modules/juce_gui_basics/juce_gui_basics.cpp @@ -124,7 +124,20 @@ namespace juce } bool isWindowOnCurrentVirtualDesktop (void*); -} + + struct CustomMouseCursorInfo + { + CustomMouseCursorInfo() = default; + + CustomMouseCursorInfo (const Image& im, Point hs, float scale = 1.0f) noexcept + : image (im), hotspot (hs), scaleFactor (scale) + {} + + Image image; + Point 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" diff --git a/modules/juce_gui_basics/mouse/juce_MouseCursor.cpp b/modules/juce_gui_basics/mouse/juce_MouseCursor.cpp index 54b04efdc0..ea69da45f7 100644 --- a/modules/juce_gui_basics/mouse/juce_MouseCursor.cpp +++ b/modules/juce_gui_basics/mouse/juce_MouseCursor.cpp @@ -26,34 +26,21 @@ namespace juce { -struct CustomMouseCursorInfo -{ - CustomMouseCursorInfo (const Image& im, Point hs, float scale = 1.0f) noexcept - : image (im), hotspot (hs), scaleFactor (scale) - {} - - void* create() const; - - Image image; - const Point 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 hotSpot, float scaleFactor) - : info (std::make_unique (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 info; - std::unique_ptr 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 diff --git a/modules/juce_gui_basics/mouse/juce_MouseCursor.h b/modules/juce_gui_basics/mouse/juce_MouseCursor.h index c6996b5d53..23bea4de05 100644 --- a/modules/juce_gui_basics/mouse/juce_MouseCursor.h +++ b/modules/juce_gui_basics/mouse/juce_MouseCursor.h @@ -168,12 +168,11 @@ private: class SharedCursorHandle; std::shared_ptr 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) }; diff --git a/modules/juce_gui_basics/native/juce_android_Windowing.cpp b/modules/juce_gui_basics/native/juce_android_Windowing.cpp index 1a63a983bd..48dfbe4a45 100644 --- a/modules/juce_gui_basics/native/juce_android_Windowing.cpp +++ b/modules/juce_gui_basics/native/juce_android_Windowing.cpp @@ -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*/, diff --git a/modules/juce_gui_basics/native/juce_linux_Windowing.cpp b/modules/juce_gui_basics/native/juce_linux_Windowing.cpp index e94d482d19..d87c1ebe0b 100644 --- a/modules/juce_gui_basics/native/juce_linux_Windowing.cpp +++ b/modules/juce_gui_basics/native/juce_linux_Windowing.cpp @@ -648,27 +648,46 @@ void MouseInputSource::setRawMousePosition (Point 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) diff --git a/modules/juce_gui_basics/native/juce_mac_MouseCursor.mm b/modules/juce_gui_basics/native/juce_mac_MouseCursor.mm index 60d6049feb..07f620c01b 100644 --- a/modules/juce_gui_basics/native/juce_mac_MouseCursor.mm +++ b/modules/juce_gui_basics/native/juce_mac_MouseCursor.mm @@ -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 diff --git a/modules/juce_gui_basics/native/juce_win32_Windowing.cpp b/modules/juce_gui_basics/native/juce_win32_Windowing.cpp index 13f9dd521d..4b9f2430d8 100644 --- a/modules/juce_gui_basics/native/juce_win32_Windowing.cpp +++ b/modules/juce_gui_basics/native/juce_win32_Windowing.cpp @@ -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 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 hotspot; + std::map 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 makeHandle (const CustomMouseCursorInfo& info) + { + return std::make_unique (info.image, info.hotspot); + } + + static std::unique_ptr makeHandle (const MouseCursor::StandardCursorType type) + { + LPCTSTR cursorName = IDC_ARROW; + + switch (type) + { + case NormalCursor: + case ParentCursor: break; + case NoCursor: return std::make_unique (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 ([&] + { + 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; +}; //============================================================================== -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 diff --git a/modules/juce_gui_basics/native/x11/juce_linux_X11_DragAndDrop.cpp b/modules/juce_gui_basics/native/x11/juce_linux_X11_DragAndDrop.cpp index da96498a44..911defdfb8 100644 --- a/modules/juce_gui_basics/native/x11/juce_linux_X11_DragAndDrop.cpp +++ b/modules/juce_gui_basics/native/x11/juce_linux_X11_DragAndDrop.cpp @@ -26,8 +26,8 @@ namespace juce { -extern void* createDraggingHandCursor(); -extern ComponentPeer* getPeerFor (::Window); +static Cursor createDraggingHandCursor(); +ComponentPeer* getPeerFor (::Window); //============================================================================== class X11DragState diff --git a/modules/juce_gui_basics/native/x11/juce_linux_XWindowSystem.cpp b/modules/juce_gui_basics/native/x11/juce_linux_XWindowSystem.cpp index 7d543132a7..022ba820cd 100644 --- a/modules/juce_gui_basics/native/x11/juce_linux_XWindowSystem.cpp +++ b/modules/juce_gui_basics/native/x11/juce_linux_XWindowSystem.cpp @@ -2193,10 +2193,10 @@ void XWindowSystem::setMousePosition (Point pos) const roundToInt (pos.getX()), roundToInt (pos.getY())); } -void* XWindowSystem::createCustomMouseCursorInfo (const Image& image, Point hotspot) const +Cursor XWindowSystem::createCustomMouseCursorInfo (const Image& image, Point hotspot) const { if (display == nullptr) - return nullptr; + return {}; XWindowSystemUtilities::ScopedXLock xLock; @@ -2217,9 +2217,9 @@ void* XWindowSystem::createCustomMouseCursorInfo (const Image& image, Point 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 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 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); diff --git a/modules/juce_gui_basics/native/x11/juce_linux_XWindowSystem.h b/modules/juce_gui_basics/native/x11/juce_linux_XWindowSystem.h index 9877165c1b..9bc284a407 100644 --- a/modules/juce_gui_basics/native/x11/juce_linux_XWindowSystem.h +++ b/modules/juce_gui_basics/native/x11/juce_linux_XWindowSystem.h @@ -213,10 +213,10 @@ public: Point getCurrentMousePosition() const; void setMousePosition (Point pos) const; - void* createCustomMouseCursorInfo (const Image&, Point hotspot) const; - void deleteMouseCursor (void* cursorHandle) const; - void* createStandardMouseCursor (MouseCursor::StandardCursorType) const; - void showCursor (::Window, void* cursorHandle) const; + Cursor createCustomMouseCursorInfo (const Image&, Point 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;