From 093832032341720a964f97d7387dcb5e440d03e7 Mon Sep 17 00:00:00 2001 From: kunitoki Date: Tue, 17 Dec 2024 00:08:55 +0100 Subject: [PATCH] Improved sdl display handling --- examples/render/source/main.cpp | 29 +- justfile | 4 +- modules/juce_core/juce_core.h | 14 + modules/juce_core/profiling/juce_Profiler.h | 20 +- .../native/juce_MessageManager_mac.mm | 1 + .../yup_gui/component/yup_ComponentNative.h | 1 + modules/yup_gui/desktop/yup_Desktop.cpp | 24 +- modules/yup_gui/desktop/yup_Desktop.h | 16 +- modules/yup_gui/desktop/yup_Display.h | 4 +- modules/yup_gui/native/yup_Windowing_ios.mm | 2 +- modules/yup_gui/native/yup_Windowing_sdl2.cpp | 491 ++++-------------- modules/yup_gui/native/yup_Windowing_utils.h | 376 ++++++++++++++ .../yup_gui/windowing/yup_DocumentWindow.cpp | 7 + .../yup_gui/windowing/yup_DocumentWindow.h | 2 + modules/yup_gui/yup_gui.cpp | 9 +- 15 files changed, 603 insertions(+), 397 deletions(-) create mode 100644 modules/yup_gui/native/yup_Windowing_utils.h diff --git a/examples/render/source/main.cpp b/examples/render/source/main.cpp index 70f16fde..08ee688b 100644 --- a/examples/render/source/main.cpp +++ b/examples/render/source/main.cpp @@ -177,6 +177,24 @@ class CustomWindow //============================================================================== +class CustomWindow2 + : public yup::DocumentWindow +{ +public: + CustomWindow2() + : yup::DocumentWindow (yup::ComponentNative::Options(), {}) + { + setTitle ("secondary"); + } + + void userTriedToCloseWindow() override + { + setVisible (false); + } +}; + +//============================================================================== + struct Application : yup::YUPApplication { Application() = default; @@ -198,14 +216,18 @@ struct Application : yup::YUPApplication yup::Logger::outputDebugString ("Starting app " + commandLineParameters); window = std::make_unique(); - #if JUCE_IOS || JUCE_ANDROID window->centreWithSize ({ 1080, 2400 }); #else window->centreWithSize ({ 1280, 866 }); #endif - window->setVisible (true); + window->toFront(); + + window2 = std::make_unique(); + window2->centreWithSize ({ 300, 300 }); + window2->setVisible (true); + window2->toFront(); } void shutdown() override @@ -214,11 +236,14 @@ struct Application : yup::YUPApplication window.reset(); + window2.reset(); + YUP_PROFILE_STOP(); } private: std::unique_ptr window; + std::unique_ptr window2; }; START_JUCE_APPLICATION (Application) diff --git a/justfile b/justfile index 88184540..3c4cde4d 100644 --- a/justfile +++ b/justfile @@ -7,8 +7,8 @@ default: clean: rm -Rf build/* -osx: - cmake -G Xcode -B build -DYUP_ENABLE_PROFILING=OFF +osx PROFILING="OFF": + cmake -G Xcode -B build -DYUP_ENABLE_PROFILING={{PROFILING}} -open build/yup.xcodeproj ios: diff --git a/modules/juce_core/juce_core.h b/modules/juce_core/juce_core.h index 22915380..e1d34458 100644 --- a/modules/juce_core/juce_core.h +++ b/modules/juce_core/juce_core.h @@ -204,6 +204,20 @@ #define JUCE_ENABLE_ALLOCATION_HOOKS 0 #endif +/** Config: JUCE_PROFILING_CATEGORIES + If enabled, this will add global profiling categories to the profiler. The "yup" category should + always be defined, only additional categories should be provided (note the first comma). + Format of the categories is like: + ``` + #define JUCE_PROFILING_CATEGORIES \ + , perfetto::Category ("custom1") \ + , perfetto::Category ("custom2") + ``` +*/ +#ifndef JUCE_PROFILING_CATEGORIES +#define JUCE_PROFILING_CATEGORIES +#endif + #ifndef JUCE_STRING_UTF_TYPE #define JUCE_STRING_UTF_TYPE 8 #endif diff --git a/modules/juce_core/profiling/juce_Profiler.h b/modules/juce_core/profiling/juce_Profiler.h index 4e4274cc..4b325299 100644 --- a/modules/juce_core/profiling/juce_Profiler.h +++ b/modules/juce_core/profiling/juce_Profiler.h @@ -22,8 +22,8 @@ #if JUCE_ENABLE_PROFILING PERFETTO_DEFINE_CATEGORIES ( - perfetto::Category ("rendering"), - perfetto::Category ("network")); + perfetto::Category ("yup") + JUCE_PROFILING_CATEGORIES); namespace juce { @@ -153,6 +153,7 @@ constexpr auto Profiler::compileTimePrettierFunction (F func) */ #define YUP_PROFILE_STOP(...) ::juce::Profiler::getInstance()->stopTracing() +#if ! YUP_PROFILE_DISABLE_TRACE /** Records a profiling trace event. This macro is used to trace events for profiling purposes. @@ -162,12 +163,24 @@ constexpr auto Profiler::compileTimePrettierFunction (F func) @param category The category for the trace event. @param ... Optional additional arguments for the trace event. */ -#if ! YUP_PROFILE_DISABLE_TRACE #define YUP_PROFILE_TRACE(category, ...) \ constexpr auto JUCE_JOIN_MACRO (juce_pfn_, __LINE__) = ::juce::Profiler::compileTimePrettierFunction ([] { return PERFETTO_DEBUG_FUNCTION_IDENTIFIER(); }); \ TRACE_EVENT (category, ::perfetto::StaticString (JUCE_JOIN_MACRO (juce_pfn_, __LINE__).data()), ##__VA_ARGS__) + +/** Records a profiling internal trace event. + + This macro is used internally by the yup framework to trace events for profiling purposes. + + @param ... Optional additional arguments for the trace event. +*/ +#define YUP_PROFILE_INTERNAL_TRACE(...) \ + constexpr auto JUCE_JOIN_MACRO (juce_pfn_, __LINE__) = ::juce::Profiler::compileTimePrettierFunction ([] { return PERFETTO_DEBUG_FUNCTION_IDENTIFIER(); }); \ + TRACE_EVENT ("yup", ::perfetto::StaticString (JUCE_JOIN_MACRO (juce_pfn_, __LINE__).data()), ##__VA_ARGS__) + #else #define YUP_PROFILE_TRACE(category, ...) +#define YUP_PROFILE_INTERNAL_TRACE(...) + #endif // clang-format on @@ -175,5 +188,6 @@ constexpr auto Profiler::compileTimePrettierFunction (F func) #define YUP_PROFILE_START(...) #define YUP_PROFILE_STOP(...) #define YUP_PROFILE_TRACE(category, ...) +#define YUP_PROFILE_INTERNAL_TRACE(...) #endif diff --git a/modules/juce_events/native/juce_MessageManager_mac.mm b/modules/juce_events/native/juce_MessageManager_mac.mm index da719b83..4ec27e8b 100644 --- a/modules/juce_events/native/juce_MessageManager_mac.mm +++ b/modules/juce_events/native/juce_MessageManager_mac.mm @@ -354,6 +354,7 @@ static String quotedIfContainsSpaces(NSString* file) static void shutdownNSApp() { [NSApp stop:nil]; + [NSEvent stopPeriodicEvents]; [NSEvent startPeriodicEventsAfterDelay:0 withPeriod:0.1]; } diff --git a/modules/yup_gui/component/yup_ComponentNative.h b/modules/yup_gui/component/yup_ComponentNative.h index f59df160..87830b8d 100644 --- a/modules/yup_gui/component/yup_ComponentNative.h +++ b/modules/yup_gui/component/yup_ComponentNative.h @@ -154,6 +154,7 @@ class JUCE_API ComponentNative virtual void enableWireframe (bool shouldBeEnabld) = 0; //============================================================================== + virtual void repaint() = 0; virtual void repaint (const Rectangle& rect) = 0; virtual Rectangle getRepaintArea() const = 0; diff --git a/modules/yup_gui/desktop/yup_Desktop.cpp b/modules/yup_gui/desktop/yup_Desktop.cpp index 0b8b5dda..696fa2b6 100644 --- a/modules/yup_gui/desktop/yup_Desktop.cpp +++ b/modules/yup_gui/desktop/yup_Desktop.cpp @@ -36,7 +36,7 @@ int Desktop::getNumDisplays() const return displays.size(); } -Display* Desktop::getDisplay (int displayIndex) const +Display::Ptr Desktop::getDisplay (int displayIndex) const { if (isPositiveAndBelow (displayIndex, displays.size())) return displays.getUnchecked (displayIndex); @@ -44,11 +44,31 @@ Display* Desktop::getDisplay (int displayIndex) const return nullptr; } -Display* Desktop::getPrimaryDisplay() const +Display::Ptr Desktop::getPrimaryDisplay() const { return ! displays.isEmpty() ? getDisplay (0) : nullptr; } +void Desktop::handleDisplayConnected (int displayIndex) +{ + updateDisplays(); +} + +void Desktop::handleDisplayDisconnected (int displayIndex) +{ + updateDisplays(); +} + +void Desktop::handleDisplayMoved (int displayIndex) +{ + updateDisplays(); +} + +void Desktop::handleDisplayOrientationChanged (int displayIndex) +{ + updateDisplays(); +} + JUCE_IMPLEMENT_SINGLETON (Desktop) } // namespace yup diff --git a/modules/yup_gui/desktop/yup_Desktop.h b/modules/yup_gui/desktop/yup_Desktop.h index 7382eba4..563d70d4 100644 --- a/modules/yup_gui/desktop/yup_Desktop.h +++ b/modules/yup_gui/desktop/yup_Desktop.h @@ -48,7 +48,7 @@ class JUCE_API Desktop @return A pointer to the `Display` object, or nullptr if the index is out of range. */ - Display* getDisplay (int displayIndex) const; + Display::Ptr getDisplay (int displayIndex) const; /** Retrieves a pointer to the primary `Display` object. @@ -56,7 +56,7 @@ class JUCE_API Desktop @return A pointer to the primary `Display` object. */ - Display* getPrimaryDisplay() const; + Display::Ptr getPrimaryDisplay() const; //============================================================================== // TODO - doxygen @@ -65,12 +65,22 @@ class JUCE_API Desktop //============================================================================== JUCE_DECLARE_SINGLETON (Desktop, false) + //============================================================================== + /** @internal */ + void handleDisplayConnected (int displayIndex); + /** @internal */ + void handleDisplayDisconnected (int displayIndex); + /** @internal */ + void handleDisplayMoved (int displayIndex); + /** @internal */ + void handleDisplayOrientationChanged (int displayIndex); + private: friend class YUPApplication; Desktop(); - OwnedArray displays; + ReferenceCountedArray displays; JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (Desktop) }; diff --git a/modules/yup_gui/desktop/yup_Display.h b/modules/yup_gui/desktop/yup_Display.h index febae55a..45b03d62 100644 --- a/modules/yup_gui/desktop/yup_Display.h +++ b/modules/yup_gui/desktop/yup_Display.h @@ -22,9 +22,11 @@ namespace yup { -class JUCE_API Display +class JUCE_API Display : public ReferenceCountedObject { public: + using Ptr = ReferenceCountedObjectPtr; + Display() {} Size physicalSizeMillimeters; diff --git a/modules/yup_gui/native/yup_Windowing_ios.mm b/modules/yup_gui/native/yup_Windowing_ios.mm index 6a429f4e..73030bf5 100644 --- a/modules/yup_gui/native/yup_Windowing_ios.mm +++ b/modules/yup_gui/native/yup_Windowing_ios.mm @@ -2,7 +2,7 @@ ============================================================================== This file is part of the YUP library. - Copyright (c): return { KeyPress::xxx, modifiers, sc }; - kunitoki@gmail.com + Copyright (c) 2024 - kunitoki@gmail.com YUP is an open source library subject to open-source licensing. diff --git a/modules/yup_gui/native/yup_Windowing_sdl2.cpp b/modules/yup_gui/native/yup_Windowing_sdl2.cpp index 8d5f9d1f..cf56af54 100644 --- a/modules/yup_gui/native/yup_Windowing_sdl2.cpp +++ b/modules/yup_gui/native/yup_Windowing_sdl2.cpp @@ -2,7 +2,7 @@ ============================================================================== This file is part of the YUP library. - Copyright (c): return { KeyPress::xxx, modifiers, sc }; - kunitoki@gmail.com + Copyright (c) 2024 - kunitoki@gmail.com YUP is an open source library subject to open-source licensing. @@ -24,357 +24,6 @@ namespace yup //============================================================================== -MouseEvent::Buttons toMouseButton (Uint8 sdlButton) noexcept -{ - switch (sdlButton) - { - case SDL_BUTTON_LEFT: - return MouseEvent::Buttons::leftButton; - - case SDL_BUTTON_RIGHT: - return MouseEvent::Buttons::rightButton; - - case SDL_BUTTON_MIDDLE: - return MouseEvent::Buttons::middleButton; - - default: - return MouseEvent::Buttons::noButtons; - } -} - -//============================================================================== - -KeyModifiers toKeyModifiers (Uint16 sdlMod) noexcept -{ - int modifiers; - - if (sdlMod & KMOD_CTRL) - modifiers |= KeyModifiers::controlMask; - - if (sdlMod & KMOD_SHIFT) - modifiers |= KeyModifiers::shiftMask; - - if (sdlMod & KMOD_ALT) - modifiers |= KeyModifiers::altMask; - - if (sdlMod & KMOD_GUI) - modifiers |= KeyModifiers::superMask; - - return modifiers; -} - -// clang-format off -KeyPress toKeyPress (SDL_Keycode key, SDL_Scancode scancode, KeyModifiers modifiers) noexcept -{ - const char32_t sc = static_cast (scancode); - - switch (key) - { - case SDLK_SPACE: return { KeyPress::spaceKey, modifiers, sc }; - //case SDLK_APOSTROPHE: return { KeyPress::apostropheKey, modifiers, sc }; - case SDLK_COMMA: return { KeyPress::commaKey, modifiers, sc }; - case SDLK_MINUS: return { KeyPress::minusKey, modifiers, sc }; - case SDLK_PERIOD: return { KeyPress::periodKey, modifiers, sc }; - case SDLK_SLASH: return { KeyPress::slashKey, modifiers, sc }; - case SDLK_0: return { KeyPress::number0Key, modifiers, sc }; - case SDLK_1: return { KeyPress::number1Key, modifiers, sc }; - case SDLK_2: return { KeyPress::number2Key, modifiers, sc }; - case SDLK_3: return { KeyPress::number3Key, modifiers, sc }; - case SDLK_4: return { KeyPress::number4Key, modifiers, sc }; - case SDLK_5: return { KeyPress::number5Key, modifiers, sc }; - case SDLK_6: return { KeyPress::number6Key, modifiers, sc }; - case SDLK_7: return { KeyPress::number7Key, modifiers, sc }; - case SDLK_8: return { KeyPress::number8Key, modifiers, sc }; - case SDLK_9: return { KeyPress::number9Key, modifiers, sc }; - case SDLK_SEMICOLON: return { KeyPress::semicolonKey, modifiers, sc }; - case SDLK_EQUALS: return { KeyPress::equalKey, modifiers, sc }; - case SDLK_a: return { KeyPress::textAKey, modifiers, sc }; - case SDLK_b: return { KeyPress::textBKey, modifiers, sc }; - case SDLK_c: return { KeyPress::textCKey, modifiers, sc }; - case SDLK_d: return { KeyPress::textDKey, modifiers, sc }; - case SDLK_e: return { KeyPress::textEKey, modifiers, sc }; - case SDLK_f: return { KeyPress::textFKey, modifiers, sc }; - case SDLK_g: return { KeyPress::textGKey, modifiers, sc }; - case SDLK_h: return { KeyPress::textHKey, modifiers, sc }; - case SDLK_i: return { KeyPress::textIKey, modifiers, sc }; - case SDLK_j: return { KeyPress::textJKey, modifiers, sc }; - case SDLK_k: return { KeyPress::textKKey, modifiers, sc }; - case SDLK_l: return { KeyPress::textLKey, modifiers, sc }; - case SDLK_m: return { KeyPress::textMKey, modifiers, sc }; - case SDLK_n: return { KeyPress::textNKey, modifiers, sc }; - case SDLK_o: return { KeyPress::textOKey, modifiers, sc }; - case SDLK_p: return { KeyPress::textPKey, modifiers, sc }; - case SDLK_q: return { KeyPress::textQKey, modifiers, sc }; - case SDLK_r: return { KeyPress::textRKey, modifiers, sc }; - case SDLK_s: return { KeyPress::textSKey, modifiers, sc }; - case SDLK_t: return { KeyPress::textTKey, modifiers, sc }; - case SDLK_u: return { KeyPress::textUKey, modifiers, sc }; - case SDLK_v: return { KeyPress::textVKey, modifiers, sc }; - case SDLK_w: return { KeyPress::textWKey, modifiers, sc }; - case SDLK_x: return { KeyPress::textXKey, modifiers, sc }; - case SDLK_y: return { KeyPress::textYKey, modifiers, sc }; - case SDLK_z: return { KeyPress::textZKey, modifiers, sc }; - case SDLK_LEFTBRACKET: return { KeyPress::leftBracketKey, modifiers, sc }; - case SDLK_BACKSLASH: return { KeyPress::backslashKey, modifiers, sc }; - case SDLK_RIGHTBRACKET: return { KeyPress::rightBracketKey, modifiers, sc }; - //case SDLK_GRAVE_ACCENT: return { KeyPress::graveAccentKey, modifiers, sc }; - //case SDLK_WORLD_1: return { KeyPress::world1Key, modifiers, sc }; - //case SDLK_WORLD_2: return { KeyPress::world2Key, modifiers, sc }; - case SDLK_ESCAPE: return { KeyPress::escapeKey, modifiers, sc }; - case SDLK_RETURN: return { KeyPress::enterKey, modifiers, sc }; - case SDLK_TAB: return { KeyPress::tabKey, modifiers, sc }; - case SDLK_BACKSPACE: return { KeyPress::backspaceKey, modifiers, sc }; - case SDLK_INSERT: return { KeyPress::insertKey, modifiers, sc }; - case SDLK_DELETE: return { KeyPress::deleteKey, modifiers, sc }; - case SDLK_RIGHT: return { KeyPress::rightKey, modifiers, sc }; - case SDLK_LEFT: return { KeyPress::leftKey, modifiers, sc }; - case SDLK_DOWN: return { KeyPress::downKey, modifiers, sc }; - case SDLK_UP: return { KeyPress::upKey, modifiers, sc }; - case SDLK_PAGEUP: return { KeyPress::pageUpKey, modifiers, sc }; - case SDLK_PAGEDOWN: return { KeyPress::pageDownKey, modifiers, sc }; - case SDLK_HOME: return { KeyPress::homeKey, modifiers, sc }; - case SDLK_END: return { KeyPress::endKey, modifiers, sc }; - case SDLK_CAPSLOCK: return { KeyPress::capsLockKey, modifiers, sc }; - case SDLK_SCROLLLOCK: return { KeyPress::scrollLockKey, modifiers, sc }; - case SDLK_NUMLOCKCLEAR: return { KeyPress::numLockKey, modifiers, sc }; - case SDLK_PRINTSCREEN: return { KeyPress::printScreenKey, modifiers, sc }; - case SDLK_PAUSE: return { KeyPress::pauseKey, modifiers, sc }; - case SDLK_F1: return { KeyPress::f1Key, modifiers, sc }; - case SDLK_F2: return { KeyPress::f2Key, modifiers, sc }; - case SDLK_F3: return { KeyPress::f3Key, modifiers, sc }; - case SDLK_F4: return { KeyPress::f4Key, modifiers, sc }; - case SDLK_F5: return { KeyPress::f5Key, modifiers, sc }; - case SDLK_F6: return { KeyPress::f6Key, modifiers, sc }; - case SDLK_F7: return { KeyPress::f7Key, modifiers, sc }; - case SDLK_F8: return { KeyPress::f8Key, modifiers, sc }; - case SDLK_F9: return { KeyPress::f9Key, modifiers, sc }; - case SDLK_F10: return { KeyPress::f10Key, modifiers, sc }; - case SDLK_F11: return { KeyPress::f11Key, modifiers, sc }; - case SDLK_F12: return { KeyPress::f12Key, modifiers, sc }; - case SDLK_F13: return { KeyPress::f13Key, modifiers, sc }; - case SDLK_F14: return { KeyPress::f14Key, modifiers, sc }; - case SDLK_F15: return { KeyPress::f15Key, modifiers, sc }; - case SDLK_F16: return { KeyPress::f16Key, modifiers, sc }; - case SDLK_F17: return { KeyPress::f17Key, modifiers, sc }; - case SDLK_F18: return { KeyPress::f18Key, modifiers, sc }; - case SDLK_F19: return { KeyPress::f19Key, modifiers, sc }; - case SDLK_F20: return { KeyPress::f20Key, modifiers, sc }; - case SDLK_F21: return { KeyPress::f21Key, modifiers, sc }; - case SDLK_F22: return { KeyPress::f22Key, modifiers, sc }; - case SDLK_F23: return { KeyPress::f23Key, modifiers, sc }; - case SDLK_F24: return { KeyPress::f24Key, modifiers, sc }; - //case SDLK_F25: return { KeyPress::f25Key, modifiers, sc }; - case SDLK_KP_0: return { KeyPress::kp0Key, modifiers, sc }; - case SDLK_KP_1: return { KeyPress::kp1Key, modifiers, sc }; - case SDLK_KP_2: return { KeyPress::kp2Key, modifiers, sc }; - case SDLK_KP_3: return { KeyPress::kp3Key, modifiers, sc }; - case SDLK_KP_4: return { KeyPress::kp4Key, modifiers, sc }; - case SDLK_KP_5: return { KeyPress::kp5Key, modifiers, sc }; - case SDLK_KP_6: return { KeyPress::kp6Key, modifiers, sc }; - case SDLK_KP_7: return { KeyPress::kp7Key, modifiers, sc }; - case SDLK_KP_8: return { KeyPress::kp8Key, modifiers, sc }; - case SDLK_KP_9: return { KeyPress::kp9Key, modifiers, sc }; - case SDLK_KP_DECIMAL: return { KeyPress::kpDecimalKey, modifiers, sc }; - case SDLK_KP_DIVIDE: return { KeyPress::kpDivideKey, modifiers, sc }; - case SDLK_KP_POWER: return { KeyPress::kpMultiplyKey, modifiers, sc }; - case SDLK_KP_MINUS: return { KeyPress::kpSubtractKey, modifiers, sc }; - case SDLK_KP_PLUS: return { KeyPress::kpAddKey, modifiers, sc }; - case SDLK_KP_ENTER: return { KeyPress::kpEnterKey, modifiers, sc }; - case SDLK_KP_EQUALS: return { KeyPress::kpEqualKey, modifiers, sc }; - case SDLK_LSHIFT: return { KeyPress::leftShiftKey, modifiers, sc }; - case SDLK_LCTRL: return { KeyPress::leftControlKey, modifiers, sc }; - case SDLK_LALT: return { KeyPress::leftAltKey, modifiers, sc }; - case SDLK_LGUI: return { KeyPress::leftSuperKey, modifiers, sc }; - case SDLK_RSHIFT: return { KeyPress::rightShiftKey, modifiers, sc }; - case SDLK_RCTRL: return { KeyPress::rightControlKey, modifiers, sc }; - case SDLK_RALT: return { KeyPress::rightAltKey, modifiers, sc }; - case SDLK_RGUI: return { KeyPress::rightSuperKey, modifiers, sc }; - case SDLK_MENU: return { KeyPress::menuKey, modifiers, sc }; - - default: - break; - } - - return {}; -} - -// clang-format on - -//============================================================================== - -void* getNativeWindowHandle (SDL_Window* window) -{ - if (window == nullptr) - return nullptr; - - SDL_SysWMinfo wmInfo; - SDL_VERSION (&wmInfo.version); - if (SDL_GetWindowWMInfo (window, &wmInfo)) - { -#if JUCE_MAC - return (__bridge void*) wmInfo.info.cocoa.window; // NSWindow* - -#elif JUCE_IOS - return (__bridge void*) wmInfo.info.uikit.window; // UIWindow* - -#elif JUCE_WINDOWS - return wmInfo.info.win.window; // HWND - -#elif JUCE_LINUX - return reinterpret_cast (wmInfo.info.x11.window); // X11 Window - -#elif JUCE_ANDROID - return reinterpret_cast (wmInfo.info.android.window); // ANativeWindow* - -#endif - } - - return nullptr; -} - -Rectangle getNativeWindowPosition (void* nativeDisplay, void* nativeWindow) -{ -#if JUCE_WINDOWS - RECT windowRect; - - GetWindowRect (reinterpret_cast (nativeWindow), &windowRect); - - return { - windowRect.left, - windowRect.top, - windowRect.right - windowRect.left, - windowRect.bottom - windowRect.top - }; - -#elif JUCE_MAC - NSView* view = reinterpret_cast (nativeWindow); - NSRect viewRect = [view convertRect:[view bounds] toView:nil]; - - NSRect windowRect = [[view window] convertRectToScreen:viewRect]; - windowRect.origin.y = CGDisplayBounds (CGMainDisplayID()).size.height - (windowRect.origin.y + windowRect.size.height); - - return { - static_cast (windowRect.origin.x), - static_cast (windowRect.origin.y), - static_cast (windowRect.size.width), - static_cast (windowRect.size.height) - }; - -#elif JUCE_LINUX - return {}; - -#else - return {}; - -#endif -} - -void setNativeParent (void* nativeDisplay, void* nativeWindow, SDL_Window* window) -{ -#if JUCE_WINDOWS - HWND hpar = reinterpret_cast (nativeWindow); - HWND hwnd = reinterpret_cast (getNativeWindowHandle (window)); - SetParent (hwnd, hpar); - - long style = GetWindowLong (hwnd, GWL_STYLE); - style &= ~WS_POPUP; - style |= WS_CHILDWINDOW; - SetWindowLong (hwnd, GWL_STYLE, style); - - SetWindowPos (hwnd, nullptr, 0, 0, 0, 0, SWP_NOZORDER | SWP_NOSIZE | SWP_NOACTIVATE); - -#elif JUCE_MAC - NSWindow* parentWindow = [reinterpret_cast (nativeWindow) window]; - NSWindow* currentWindow = reinterpret_cast (getNativeWindowHandle (window)); - [parentWindow addChildWindow:currentWindow ordered:NSWindowAbove]; - -#elif JUCE_LINUX - -#else - -#endif -} - -//============================================================================== - -GraphicsContext::Api getGraphicsContextApi (const std::optional& forceContextApi) -{ - GraphicsContext::Api desiredApi; - -#if JUCE_MAC || JUCE_IOS -#if YUP_RIVE_USE_METAL - desiredApi = forceContextApi.value_or (GraphicsContext::Metal); -#elif YUP_RIVE_USE_OPENGL - desiredApi = forceContextApi.value_or (GraphicsContext::OpenGL); -#endif - -#elif JUCE_WINDOWS -#if YUP_RIVE_USE_D3D - desiredApi = forceContextApi.value_or (GraphicsContext::Direct3D); -#elif YUP_RIVE_USE_OPENGL - desiredApi = forceContextApi.value_or (GraphicsContext::OpenGL); -#endif - -#elif JUCE_LINUX - desiredApi = forceContextApi.value_or (GraphicsContext::OpenGL); - -#else - desiredApi = forceContextApi.value_or (GraphicsContext::OpenGL); - -#endif - - return desiredApi; -} - -Uint32 setContextWindowHints (GraphicsContext::Api desiredApi) -{ - if (desiredApi == GraphicsContext::Metal) - { - SDL_SetHint (SDL_HINT_RENDER_DRIVER, "metal"); - - return SDL_WINDOW_METAL; - } - - if (desiredApi == GraphicsContext::Direct3D) - { - SDL_SetHint (SDL_HINT_RENDER_DRIVER, "direct3d11"); - - return 0; - } - - if (desiredApi == GraphicsContext::OpenGL) - { -#if defined(ANGLE) || defined(JUCE_ANDROID) || defined(JUCE_EMSCRIPTEN) - SDL_SetHint (SDL_HINT_RENDER_DRIVER, "opengles2"); - - SDL_GL_SetAttribute (SDL_GL_CONTEXT_MAJOR_VERSION, 3); - SDL_GL_SetAttribute (SDL_GL_CONTEXT_MINOR_VERSION, 0); - SDL_GL_SetAttribute (SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_ES); - SDL_GL_SetAttribute (SDL_GL_RED_SIZE, 8); - SDL_GL_SetAttribute (SDL_GL_GREEN_SIZE, 8); - SDL_GL_SetAttribute (SDL_GL_BLUE_SIZE, 8); - SDL_GL_SetAttribute (SDL_GL_ALPHA_SIZE, 8); - SDL_GL_SetAttribute (SDL_GL_DEPTH_SIZE, 24); - SDL_GL_SetAttribute (SDL_GL_STENCIL_SIZE, 8); - SDL_GL_SetAttribute (SDL_GL_DOUBLEBUFFER, 1); - - return SDL_WINDOW_OPENGL; -#else - SDL_SetHint (SDL_HINT_RENDER_DRIVER, "opengl"); - - SDL_GL_SetAttribute (SDL_GL_CONTEXT_MAJOR_VERSION, YUP_RIVE_OPENGL_MAJOR); - SDL_GL_SetAttribute (SDL_GL_CONTEXT_MINOR_VERSION, YUP_RIVE_OPENGL_MINOR); - SDL_GL_SetAttribute (SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_CORE); - - return SDL_WINDOW_OPENGL; -#endif - } - - return 0; -} - -//============================================================================== - class SDL2ComponentNative final : public ComponentNative , public Timer @@ -382,8 +31,6 @@ class SDL2ComponentNative final , public AsyncUpdater { public: - static std::atomic_flag isInitialised; - //============================================================================== SDL2ComponentNative (Component& component, @@ -432,6 +79,7 @@ class SDL2ComponentNative final void enableWireframe (bool shouldBeEnabled) override; //============================================================================== + void repaint() override; void repaint (const Rectangle& rect) override; Rectangle getRepaintArea() const override; @@ -478,6 +126,10 @@ class SDL2ComponentNative final void handleMoved (int xpos, int ypos); void handleResized (int width, int height); void handleFocusChanged (bool gotFocus); + void handleMinimized(); + void handleMaximized(); + void handleRestored(); + void handleExposed(); void handleContentScaleChanged(); void handleUserTriedToCloseWindow(); @@ -488,6 +140,9 @@ class SDL2ComponentNative final void handleEvent (SDL_Event* event); static int eventDispatcher (void* userdata, SDL_Event* event); + //============================================================================== + static std::atomic_flag isInitialised; + private: void updateComponentUnderMouse (const MouseEvent& event); void triggerRenderingUpdate(); @@ -620,6 +275,9 @@ SDL2ComponentNative::~SDL2ComponentNative() // Stop the rendering stopRendering(); + // Remove event watch + SDL_DelEventWatch (eventDispatcher, this); + // Destroy the renderer and window if (windowRenderer != nullptr) SDL_DestroyRenderer (windowRenderer); @@ -877,6 +535,13 @@ void SDL2ComponentNative::enableWireframe (bool shouldBeEnabled) //============================================================================== +void SDL2ComponentNative::repaint() +{ + currentRepaintArea = Rectangle().withSize (getContentSize().to()); + + triggerRenderingUpdate(); +} + void SDL2ComponentNative::repaint (const Rectangle& rect) { if (! currentRepaintArea.isEmpty()) @@ -1305,7 +970,27 @@ void SDL2ComponentNative::handleResized (int width, int height) void SDL2ComponentNative::handleFocusChanged (bool gotFocus) { - //DBG ("handleFocusChanged: " << (gotFocus ? 1 : 0)); + DBG ("handleFocusChanged: " << (gotFocus ? 1 : 0)); +} + +void SDL2ComponentNative::handleMinimized() +{ + DBG ("handleMinimized"); +} + +void SDL2ComponentNative::handleMaximized() +{ + DBG ("handleMaximized"); +} + +void SDL2ComponentNative::handleRestored() +{ + DBG ("handleRestored"); +} + +void SDL2ComponentNative::handleExposed() +{ + DBG ("handleExposed"); } void SDL2ComponentNative::handleContentScaleChanged() @@ -1367,6 +1052,10 @@ void SDL2ComponentNative::handleWindowEvent (const SDL_WindowEvent& windowEvent) { switch (windowEvent.event) { + case SDL_WINDOWEVENT_CLOSE: + component.internalUserTriedToCloseWindow(); + break; + case SDL_WINDOWEVENT_RESIZED: case SDL_WINDOWEVENT_SIZE_CHANGED: handleResized (windowEvent.data1, windowEvent.data2); @@ -1377,12 +1066,20 @@ void SDL2ComponentNative::handleWindowEvent (const SDL_WindowEvent& windowEvent) break; case SDL_WINDOWEVENT_MINIMIZED: + handleMinimized(); break; case SDL_WINDOWEVENT_MAXIMIZED: + handleMaximized(); break; case SDL_WINDOWEVENT_RESTORED: + handleRestored(); + break; + + case SDL_WINDOWEVENT_EXPOSED: + if (! shouldRenderContinuous) + repaint(); break; case SDL_WINDOWEVENT_FOCUS_GAINED: @@ -1407,18 +1104,14 @@ void SDL2ComponentNative::handleEvent (SDL_Event* event) { case SDL_QUIT: { - // component.internalUserTriedToCloseWindow(); + component.internalUserTriedToCloseWindow(); break; } case SDL_WINDOWEVENT: { - handleWindowEvent (event->window); - break; - } - - case SDL_DISPLAYEVENT: - { + if (event->window.windowID == SDL_GetWindowID (window)) + handleWindowEvent (event->window); break; } @@ -1434,7 +1127,9 @@ void SDL2ComponentNative::handleEvent (SDL_Event* event) case SDL_MOUSEMOTION: { - handleMouseMoveOrDrag ({ static_cast (event->motion.x), static_cast (event->motion.y) }); + if (event->window.windowID == SDL_GetWindowID (window)) + handleMouseMoveOrDrag ({ static_cast (event->motion.x), static_cast (event->motion.y) }); + break; } @@ -1442,7 +1137,8 @@ void SDL2ComponentNative::handleEvent (SDL_Event* event) { auto cursorPosition = Point { static_cast (event->button.x), static_cast (event->button.y) }; - handleMouseDown (cursorPosition, toMouseButton (event->button.button), KeyModifiers()); + if (event->button.windowID == SDL_GetWindowID (window)) + handleMouseDown (cursorPosition, toMouseButton (event->button.button), KeyModifiers()); break; } @@ -1451,7 +1147,8 @@ void SDL2ComponentNative::handleEvent (SDL_Event* event) { auto cursorPosition = Point { static_cast (event->button.x), static_cast (event->button.y) }; - handleMouseUp (cursorPosition, toMouseButton (event->button.button), KeyModifiers()); + if (event->button.windowID == SDL_GetWindowID (window)) + handleMouseUp (cursorPosition, toMouseButton (event->button.button), KeyModifiers()); break; } @@ -1460,7 +1157,8 @@ void SDL2ComponentNative::handleEvent (SDL_Event* event) { auto cursorPosition = getCursorPosition(); - handleMouseWheel (cursorPosition, { static_cast (event->wheel.x), static_cast (event->wheel.y) }); + if (event->wheel.windowID == SDL_GetWindowID (window)) + handleMouseWheel (cursorPosition, { static_cast (event->wheel.x), static_cast (event->wheel.y) }); break; } @@ -1470,7 +1168,8 @@ void SDL2ComponentNative::handleEvent (SDL_Event* event) auto cursorPosition = getCursorPosition(); auto modifiers = toKeyModifiers (event->key.keysym.mod); - handleKeyDown (toKeyPress (event->key.keysym.sym, event->key.keysym.scancode, modifiers), cursorPosition); + if (event->key.windowID == SDL_GetWindowID (window)) + handleKeyDown (toKeyPress (event->key.keysym.sym, event->key.keysym.scancode, modifiers), cursorPosition); break; } @@ -1480,7 +1179,8 @@ void SDL2ComponentNative::handleEvent (SDL_Event* event) auto cursorPosition = getCursorPosition(); auto modifiers = toKeyModifiers (event->key.keysym.mod); - handleKeyUp (toKeyPress (event->key.keysym.sym, event->key.keysym.scancode, modifiers), cursorPosition); + if (event->key.windowID == SDL_GetWindowID (window)) + handleKeyUp (toKeyPress (event->key.keysym.sym, event->key.keysym.scancode, modifiers), cursorPosition); break; } @@ -1500,6 +1200,40 @@ int SDL2ComponentNative::eventDispatcher (void* userdata, SDL_Event* event) //============================================================================== +namespace +{ + +int displayEventDispatcher (void* userdata, SDL_Event* event) +{ + if (event->type != SDL_DISPLAYEVENT) + return 0; + + auto desktop = static_cast (userdata); + + switch (event->display.event) + { + case SDL_DISPLAYEVENT_CONNECTED: + desktop->handleDisplayConnected (event->display.display); + break; + + case SDL_DISPLAYEVENT_DISCONNECTED: + desktop->handleDisplayDisconnected (event->display.display); + break; + + case SDL_DISPLAYEVENT_MOVED: + desktop->handleDisplayMoved (event->display.display); + break; + + case SDL_DISPLAYEVENT_ORIENTATION: + desktop->handleDisplayOrientationChanged (event->display.display); + break; + } + + return 0; +} + +} // namespace + void Desktop::updateDisplays() { const int numDisplays = SDL_GetNumVideoDisplays(); @@ -1510,6 +1244,8 @@ void Desktop::updateDisplays() continue; auto display = std::make_unique(); + display->name = String::fromUTF8 (SDL_GetDisplayName (i)); + display->isPrimary = (i == 0); display->virtualPosition = Point (bounds.x, bounds.y); display->workArea = Rectangle (bounds.x, bounds.y, bounds.w, bounds.h); @@ -1524,9 +1260,6 @@ void Desktop::updateDisplays() display->contentScaleX = hdpi / 96.0f; // Assuming 96 DPI as standard display->contentScaleY = vdpi / 96.0f; - display->name = String (SDL_GetDisplayName (i)); - display->isPrimary = (i == 0); - displays.add (display.release()); } } @@ -1538,20 +1271,19 @@ void initialiseYup_Windowing() // Initialise SDL2 if (SDL_Init (SDL_INIT_VIDEO) != 0) { - DBG ("Error initialising SDL"); - return; // quit ! + DBG ("Error initialising SDL: " << SDL_GetError()); + + jassertfalse; + + exit(1); } // Update available displays + SDL_AddEventWatch (displayEventDispatcher, Desktop::getInstance()); Desktop::getInstance()->updateDisplays(); // Allow SDL to poll events - auto loopCallback = [] - { - SDL_PumpEvents(); - }; - - MessageManager::getInstance()->registerEventLoopCallback (loopCallback); + MessageManager::getInstance()->registerEventLoopCallback (&SDL_PumpEvents); SDL2ComponentNative::isInitialised.test_and_set(); } @@ -1562,6 +1294,7 @@ void shutdownYup_Windowing() MessageManager::getInstance()->registerEventLoopCallback (nullptr); + SDL_DelEventWatch (displayEventDispatcher, Desktop::getInstance()); Desktop::getInstance()->deleteInstance(); SDL_Quit(); diff --git a/modules/yup_gui/native/yup_Windowing_utils.h b/modules/yup_gui/native/yup_Windowing_utils.h new file mode 100644 index 00000000..b1be49f1 --- /dev/null +++ b/modules/yup_gui/native/yup_Windowing_utils.h @@ -0,0 +1,376 @@ +/* + ============================================================================== + + This file is part of the YUP library. + Copyright (c) 2024 - kunitoki@gmail.com + + YUP is an open source library subject to open-source licensing. + + The code included in this file is provided under the terms of the ISC license + http://www.isc.org/downloads/software-support-policy/isc-license. Permission + to use, copy, modify, and/or distribute this software for any purpose with or + without fee is hereby granted provided that the above copyright notice and + this permission notice appear in all copies. + + YUP IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER + EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE + DISCLAIMED. + + ============================================================================== +*/ + +namespace yup +{ + +//============================================================================== + +MouseEvent::Buttons toMouseButton (Uint8 sdlButton) noexcept +{ + switch (sdlButton) + { + case SDL_BUTTON_LEFT: + return MouseEvent::Buttons::leftButton; + + case SDL_BUTTON_RIGHT: + return MouseEvent::Buttons::rightButton; + + case SDL_BUTTON_MIDDLE: + return MouseEvent::Buttons::middleButton; + + default: + return MouseEvent::Buttons::noButtons; + } +} + +//============================================================================== + +KeyModifiers toKeyModifiers (Uint16 sdlMod) noexcept +{ + int modifiers; + + if (sdlMod & KMOD_CTRL) + modifiers |= KeyModifiers::controlMask; + + if (sdlMod & KMOD_SHIFT) + modifiers |= KeyModifiers::shiftMask; + + if (sdlMod & KMOD_ALT) + modifiers |= KeyModifiers::altMask; + + if (sdlMod & KMOD_GUI) + modifiers |= KeyModifiers::superMask; + + return modifiers; +} + +// clang-format off +KeyPress toKeyPress (SDL_Keycode key, SDL_Scancode scancode, KeyModifiers modifiers) noexcept +{ + const char32_t sc = static_cast (scancode); + + switch (key) + { + case SDLK_SPACE: return { KeyPress::spaceKey, modifiers, sc }; + //case SDLK_APOSTROPHE: return { KeyPress::apostropheKey, modifiers, sc }; + case SDLK_COMMA: return { KeyPress::commaKey, modifiers, sc }; + case SDLK_MINUS: return { KeyPress::minusKey, modifiers, sc }; + case SDLK_PERIOD: return { KeyPress::periodKey, modifiers, sc }; + case SDLK_SLASH: return { KeyPress::slashKey, modifiers, sc }; + case SDLK_0: return { KeyPress::number0Key, modifiers, sc }; + case SDLK_1: return { KeyPress::number1Key, modifiers, sc }; + case SDLK_2: return { KeyPress::number2Key, modifiers, sc }; + case SDLK_3: return { KeyPress::number3Key, modifiers, sc }; + case SDLK_4: return { KeyPress::number4Key, modifiers, sc }; + case SDLK_5: return { KeyPress::number5Key, modifiers, sc }; + case SDLK_6: return { KeyPress::number6Key, modifiers, sc }; + case SDLK_7: return { KeyPress::number7Key, modifiers, sc }; + case SDLK_8: return { KeyPress::number8Key, modifiers, sc }; + case SDLK_9: return { KeyPress::number9Key, modifiers, sc }; + case SDLK_SEMICOLON: return { KeyPress::semicolonKey, modifiers, sc }; + case SDLK_EQUALS: return { KeyPress::equalKey, modifiers, sc }; + case SDLK_a: return { KeyPress::textAKey, modifiers, sc }; + case SDLK_b: return { KeyPress::textBKey, modifiers, sc }; + case SDLK_c: return { KeyPress::textCKey, modifiers, sc }; + case SDLK_d: return { KeyPress::textDKey, modifiers, sc }; + case SDLK_e: return { KeyPress::textEKey, modifiers, sc }; + case SDLK_f: return { KeyPress::textFKey, modifiers, sc }; + case SDLK_g: return { KeyPress::textGKey, modifiers, sc }; + case SDLK_h: return { KeyPress::textHKey, modifiers, sc }; + case SDLK_i: return { KeyPress::textIKey, modifiers, sc }; + case SDLK_j: return { KeyPress::textJKey, modifiers, sc }; + case SDLK_k: return { KeyPress::textKKey, modifiers, sc }; + case SDLK_l: return { KeyPress::textLKey, modifiers, sc }; + case SDLK_m: return { KeyPress::textMKey, modifiers, sc }; + case SDLK_n: return { KeyPress::textNKey, modifiers, sc }; + case SDLK_o: return { KeyPress::textOKey, modifiers, sc }; + case SDLK_p: return { KeyPress::textPKey, modifiers, sc }; + case SDLK_q: return { KeyPress::textQKey, modifiers, sc }; + case SDLK_r: return { KeyPress::textRKey, modifiers, sc }; + case SDLK_s: return { KeyPress::textSKey, modifiers, sc }; + case SDLK_t: return { KeyPress::textTKey, modifiers, sc }; + case SDLK_u: return { KeyPress::textUKey, modifiers, sc }; + case SDLK_v: return { KeyPress::textVKey, modifiers, sc }; + case SDLK_w: return { KeyPress::textWKey, modifiers, sc }; + case SDLK_x: return { KeyPress::textXKey, modifiers, sc }; + case SDLK_y: return { KeyPress::textYKey, modifiers, sc }; + case SDLK_z: return { KeyPress::textZKey, modifiers, sc }; + case SDLK_LEFTBRACKET: return { KeyPress::leftBracketKey, modifiers, sc }; + case SDLK_BACKSLASH: return { KeyPress::backslashKey, modifiers, sc }; + case SDLK_RIGHTBRACKET: return { KeyPress::rightBracketKey, modifiers, sc }; + //case SDLK_GRAVE_ACCENT: return { KeyPress::graveAccentKey, modifiers, sc }; + //case SDLK_WORLD_1: return { KeyPress::world1Key, modifiers, sc }; + //case SDLK_WORLD_2: return { KeyPress::world2Key, modifiers, sc }; + case SDLK_ESCAPE: return { KeyPress::escapeKey, modifiers, sc }; + case SDLK_RETURN: return { KeyPress::enterKey, modifiers, sc }; + case SDLK_TAB: return { KeyPress::tabKey, modifiers, sc }; + case SDLK_BACKSPACE: return { KeyPress::backspaceKey, modifiers, sc }; + case SDLK_INSERT: return { KeyPress::insertKey, modifiers, sc }; + case SDLK_DELETE: return { KeyPress::deleteKey, modifiers, sc }; + case SDLK_RIGHT: return { KeyPress::rightKey, modifiers, sc }; + case SDLK_LEFT: return { KeyPress::leftKey, modifiers, sc }; + case SDLK_DOWN: return { KeyPress::downKey, modifiers, sc }; + case SDLK_UP: return { KeyPress::upKey, modifiers, sc }; + case SDLK_PAGEUP: return { KeyPress::pageUpKey, modifiers, sc }; + case SDLK_PAGEDOWN: return { KeyPress::pageDownKey, modifiers, sc }; + case SDLK_HOME: return { KeyPress::homeKey, modifiers, sc }; + case SDLK_END: return { KeyPress::endKey, modifiers, sc }; + case SDLK_CAPSLOCK: return { KeyPress::capsLockKey, modifiers, sc }; + case SDLK_SCROLLLOCK: return { KeyPress::scrollLockKey, modifiers, sc }; + case SDLK_NUMLOCKCLEAR: return { KeyPress::numLockKey, modifiers, sc }; + case SDLK_PRINTSCREEN: return { KeyPress::printScreenKey, modifiers, sc }; + case SDLK_PAUSE: return { KeyPress::pauseKey, modifiers, sc }; + case SDLK_F1: return { KeyPress::f1Key, modifiers, sc }; + case SDLK_F2: return { KeyPress::f2Key, modifiers, sc }; + case SDLK_F3: return { KeyPress::f3Key, modifiers, sc }; + case SDLK_F4: return { KeyPress::f4Key, modifiers, sc }; + case SDLK_F5: return { KeyPress::f5Key, modifiers, sc }; + case SDLK_F6: return { KeyPress::f6Key, modifiers, sc }; + case SDLK_F7: return { KeyPress::f7Key, modifiers, sc }; + case SDLK_F8: return { KeyPress::f8Key, modifiers, sc }; + case SDLK_F9: return { KeyPress::f9Key, modifiers, sc }; + case SDLK_F10: return { KeyPress::f10Key, modifiers, sc }; + case SDLK_F11: return { KeyPress::f11Key, modifiers, sc }; + case SDLK_F12: return { KeyPress::f12Key, modifiers, sc }; + case SDLK_F13: return { KeyPress::f13Key, modifiers, sc }; + case SDLK_F14: return { KeyPress::f14Key, modifiers, sc }; + case SDLK_F15: return { KeyPress::f15Key, modifiers, sc }; + case SDLK_F16: return { KeyPress::f16Key, modifiers, sc }; + case SDLK_F17: return { KeyPress::f17Key, modifiers, sc }; + case SDLK_F18: return { KeyPress::f18Key, modifiers, sc }; + case SDLK_F19: return { KeyPress::f19Key, modifiers, sc }; + case SDLK_F20: return { KeyPress::f20Key, modifiers, sc }; + case SDLK_F21: return { KeyPress::f21Key, modifiers, sc }; + case SDLK_F22: return { KeyPress::f22Key, modifiers, sc }; + case SDLK_F23: return { KeyPress::f23Key, modifiers, sc }; + case SDLK_F24: return { KeyPress::f24Key, modifiers, sc }; + //case SDLK_F25: return { KeyPress::f25Key, modifiers, sc }; + case SDLK_KP_0: return { KeyPress::kp0Key, modifiers, sc }; + case SDLK_KP_1: return { KeyPress::kp1Key, modifiers, sc }; + case SDLK_KP_2: return { KeyPress::kp2Key, modifiers, sc }; + case SDLK_KP_3: return { KeyPress::kp3Key, modifiers, sc }; + case SDLK_KP_4: return { KeyPress::kp4Key, modifiers, sc }; + case SDLK_KP_5: return { KeyPress::kp5Key, modifiers, sc }; + case SDLK_KP_6: return { KeyPress::kp6Key, modifiers, sc }; + case SDLK_KP_7: return { KeyPress::kp7Key, modifiers, sc }; + case SDLK_KP_8: return { KeyPress::kp8Key, modifiers, sc }; + case SDLK_KP_9: return { KeyPress::kp9Key, modifiers, sc }; + case SDLK_KP_DECIMAL: return { KeyPress::kpDecimalKey, modifiers, sc }; + case SDLK_KP_DIVIDE: return { KeyPress::kpDivideKey, modifiers, sc }; + case SDLK_KP_POWER: return { KeyPress::kpMultiplyKey, modifiers, sc }; + case SDLK_KP_MINUS: return { KeyPress::kpSubtractKey, modifiers, sc }; + case SDLK_KP_PLUS: return { KeyPress::kpAddKey, modifiers, sc }; + case SDLK_KP_ENTER: return { KeyPress::kpEnterKey, modifiers, sc }; + case SDLK_KP_EQUALS: return { KeyPress::kpEqualKey, modifiers, sc }; + case SDLK_LSHIFT: return { KeyPress::leftShiftKey, modifiers, sc }; + case SDLK_LCTRL: return { KeyPress::leftControlKey, modifiers, sc }; + case SDLK_LALT: return { KeyPress::leftAltKey, modifiers, sc }; + case SDLK_LGUI: return { KeyPress::leftSuperKey, modifiers, sc }; + case SDLK_RSHIFT: return { KeyPress::rightShiftKey, modifiers, sc }; + case SDLK_RCTRL: return { KeyPress::rightControlKey, modifiers, sc }; + case SDLK_RALT: return { KeyPress::rightAltKey, modifiers, sc }; + case SDLK_RGUI: return { KeyPress::rightSuperKey, modifiers, sc }; + case SDLK_MENU: return { KeyPress::menuKey, modifiers, sc }; + + default: + break; + } + + return {}; +} + +// clang-format on + +//============================================================================== + +void* getNativeWindowHandle (SDL_Window* window) +{ + if (window == nullptr) + return nullptr; + + SDL_SysWMinfo wmInfo; + SDL_VERSION (&wmInfo.version); + if (SDL_GetWindowWMInfo (window, &wmInfo)) + { +#if JUCE_MAC + return (__bridge void*) wmInfo.info.cocoa.window; // NSWindow* + +#elif JUCE_IOS + return (__bridge void*) wmInfo.info.uikit.window; // UIWindow* + +#elif JUCE_WINDOWS + return wmInfo.info.win.window; // HWND + +#elif JUCE_LINUX + return reinterpret_cast (wmInfo.info.x11.window); // X11 Window + +#elif JUCE_ANDROID + return reinterpret_cast (wmInfo.info.android.window); // ANativeWindow* + +#endif + } + + return nullptr; +} + +Rectangle getNativeWindowPosition (void* nativeDisplay, void* nativeWindow) +{ +#if JUCE_WINDOWS + RECT windowRect; + + GetWindowRect (reinterpret_cast (nativeWindow), &windowRect); + + return { + windowRect.left, + windowRect.top, + windowRect.right - windowRect.left, + windowRect.bottom - windowRect.top + }; + +#elif JUCE_MAC + NSView* view = reinterpret_cast (nativeWindow); + NSRect viewRect = [view convertRect:[view bounds] toView:nil]; + + NSRect windowRect = [[view window] convertRectToScreen:viewRect]; + windowRect.origin.y = CGDisplayBounds (CGMainDisplayID()).size.height - (windowRect.origin.y + windowRect.size.height); + + return { + static_cast (windowRect.origin.x), + static_cast (windowRect.origin.y), + static_cast (windowRect.size.width), + static_cast (windowRect.size.height) + }; + +#elif JUCE_LINUX + return {}; + +#else + return {}; + +#endif +} + +void setNativeParent (void* nativeDisplay, void* nativeWindow, SDL_Window* window) +{ +#if JUCE_WINDOWS + HWND hpar = reinterpret_cast (nativeWindow); + HWND hwnd = reinterpret_cast (getNativeWindowHandle (window)); + SetParent (hwnd, hpar); + + long style = GetWindowLong (hwnd, GWL_STYLE); + style &= ~WS_POPUP; + style |= WS_CHILDWINDOW; + SetWindowLong (hwnd, GWL_STYLE, style); + + SetWindowPos (hwnd, nullptr, 0, 0, 0, 0, SWP_NOZORDER | SWP_NOSIZE | SWP_NOACTIVATE); + +#elif JUCE_MAC + NSWindow* parentWindow = [reinterpret_cast (nativeWindow) window]; + NSWindow* currentWindow = reinterpret_cast (getNativeWindowHandle (window)); + [parentWindow addChildWindow:currentWindow ordered:NSWindowAbove]; + +#elif JUCE_LINUX + +#else + +#endif +} + +//============================================================================== + +GraphicsContext::Api getGraphicsContextApi (const std::optional& forceContextApi) +{ + GraphicsContext::Api desiredApi; + +#if JUCE_MAC || JUCE_IOS +#if YUP_RIVE_USE_METAL + desiredApi = forceContextApi.value_or (GraphicsContext::Metal); +#elif YUP_RIVE_USE_OPENGL + desiredApi = forceContextApi.value_or (GraphicsContext::OpenGL); +#endif + +#elif JUCE_WINDOWS +#if YUP_RIVE_USE_D3D + desiredApi = forceContextApi.value_or (GraphicsContext::Direct3D); +#elif YUP_RIVE_USE_OPENGL + desiredApi = forceContextApi.value_or (GraphicsContext::OpenGL); +#endif + +#elif JUCE_LINUX + desiredApi = forceContextApi.value_or (GraphicsContext::OpenGL); + +#else + desiredApi = forceContextApi.value_or (GraphicsContext::OpenGL); + +#endif + + return desiredApi; +} + +Uint32 setContextWindowHints (GraphicsContext::Api desiredApi) +{ + if (desiredApi == GraphicsContext::Metal) + { + SDL_SetHint (SDL_HINT_RENDER_DRIVER, "metal"); + + return SDL_WINDOW_METAL; + } + + if (desiredApi == GraphicsContext::Direct3D) + { + SDL_SetHint (SDL_HINT_RENDER_DRIVER, "direct3d11"); + + return 0; + } + + if (desiredApi == GraphicsContext::OpenGL) + { +#if defined(ANGLE) || defined(JUCE_ANDROID) || defined(JUCE_EMSCRIPTEN) + SDL_SetHint (SDL_HINT_RENDER_DRIVER, "opengles2"); + + SDL_GL_SetAttribute (SDL_GL_CONTEXT_MAJOR_VERSION, 3); + SDL_GL_SetAttribute (SDL_GL_CONTEXT_MINOR_VERSION, 0); + SDL_GL_SetAttribute (SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_ES); + SDL_GL_SetAttribute (SDL_GL_RED_SIZE, 8); + SDL_GL_SetAttribute (SDL_GL_GREEN_SIZE, 8); + SDL_GL_SetAttribute (SDL_GL_BLUE_SIZE, 8); + SDL_GL_SetAttribute (SDL_GL_ALPHA_SIZE, 8); + SDL_GL_SetAttribute (SDL_GL_DEPTH_SIZE, 24); + SDL_GL_SetAttribute (SDL_GL_STENCIL_SIZE, 8); + SDL_GL_SetAttribute (SDL_GL_DOUBLEBUFFER, 1); + + return SDL_WINDOW_OPENGL; +#else + SDL_SetHint (SDL_HINT_RENDER_DRIVER, "opengl"); + + SDL_GL_SetAttribute (SDL_GL_CONTEXT_MAJOR_VERSION, YUP_RIVE_OPENGL_MAJOR); + SDL_GL_SetAttribute (SDL_GL_CONTEXT_MINOR_VERSION, YUP_RIVE_OPENGL_MINOR); + SDL_GL_SetAttribute (SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_CORE); + + return SDL_WINDOW_OPENGL; +#endif + } + + return 0; +} + +} // namespace yup diff --git a/modules/yup_gui/windowing/yup_DocumentWindow.cpp b/modules/yup_gui/windowing/yup_DocumentWindow.cpp index caa940c1..4ebfc75d 100644 --- a/modules/yup_gui/windowing/yup_DocumentWindow.cpp +++ b/modules/yup_gui/windowing/yup_DocumentWindow.cpp @@ -67,4 +67,11 @@ void DocumentWindow::paint (Graphics& g) g.fillAll(); } +//============================================================================== + +void DocumentWindow::userTriedToCloseWindow() +{ + jassertfalse; // Must implement this method to decide what to do when the window is closing ! +} + } // namespace yup diff --git a/modules/yup_gui/windowing/yup_DocumentWindow.h b/modules/yup_gui/windowing/yup_DocumentWindow.h index b57f78a8..23348e21 100644 --- a/modules/yup_gui/windowing/yup_DocumentWindow.h +++ b/modules/yup_gui/windowing/yup_DocumentWindow.h @@ -39,6 +39,8 @@ class JUCE_API DocumentWindow : public Component //============================================================================== /** @internal */ void paint (Graphics& g) override; + /** @internal */ + void userTriedToCloseWindow() override; private: Color backgroundColor; diff --git a/modules/yup_gui/yup_gui.cpp b/modules/yup_gui/yup_gui.cpp index 5dc26b55..2c5ba2cc 100644 --- a/modules/yup_gui/yup_gui.cpp +++ b/modules/yup_gui/yup_gui.cpp @@ -38,6 +38,10 @@ #include #include +//============================================================================== +#include +#include + //============================================================================== #include "application/yup_Application.cpp" #include "desktop/yup_Desktop.cpp" @@ -50,10 +54,6 @@ #include "artboard/yup_Artboard.cpp" #include "windowing/yup_DocumentWindow.cpp" -//============================================================================== -#include -#include - //============================================================================== #if JUCE_MAC || JUCE_IOS #import @@ -88,4 +88,5 @@ #endif //============================================================================== +#include "native/yup_Windowing_utils.h" #include "native/yup_Windowing_sdl2.cpp"