From 34b6e22a06adccb7580782a848c0ff8e0bbae2c6 Mon Sep 17 00:00:00 2001 From: Sergey Fedorov Date: Fri, 17 Jul 2026 19:41:33 +0000 Subject: [PATCH 5/6] 0005-leopard --- src/gui/macOS/QMPlay2MacExtensions.mm | 129 +++++++++++------- src/gui/macOS/ScreenSaver.cpp | 5 + .../3rdparty/CoreAudio/AudioDevice.mm | 4 + .../3rdparty/CoreAudio/AudioDeviceList.cpp | 4 + src/qmplay2/opengl/OpenGLCommon.cpp | 3 + 5 files changed, 95 insertions(+), 50 deletions(-) diff --git a/src/gui/macOS/QMPlay2MacExtensions.mm b/src/gui/macOS/QMPlay2MacExtensions.mm index edeb8c94..54d924b9 100644 --- a/src/gui/macOS/QMPlay2MacExtensions.mm +++ b/src/gui/macOS/QMPlay2MacExtensions.mm @@ -4,48 +4,56 @@ #include #include -// For media keys on macOS 10.6.8 with gcc (no blocks) #include #include #include #include #include -// Qt4 doesn't have QAbstractNativeEventFilter (Qt5.2+) -// For macOS 10.6.8 with gcc (no blocks support), we use a polling-based approach -// or carbon event handlers instead of Cocoa blocks - -// Forward declaration for the carbon event handler -static OSStatus MediaKeysEventHandler(EventHandlerCallRef nextHandler, EventRef event, void *userData); - +// Media keys handling for 10.5 +// We need to tap into system events, not keyboard events class MediaKeysFilter : public QObject { public: MediaKeysFilter(const QMPlay2MacExtensions::MediaKeysCallback &cb) : m_mediaKeysCallback(cb), - m_eventHandlerRef(NULL) + m_eventTap(NULL) { - // Use Carbon Event Manager for media keys support on 10.6.8 with gcc - // This doesn't require Apple blocks - EventTypeSpec eventTypes[1]; - eventTypes[0].eventClass = kEventClassKeyboard; - eventTypes[0].eventKind = kEventHotKeyPressed; - - InstallApplicationEventHandler( - NewEventHandlerUPP(MediaKeysEventHandler), - 1, - eventTypes, - this, - &m_eventHandlerRef + // Create an event tap for system-defined events + // This works on 10.5+ and doesn't require blocks + CGEventMask eventMask = CGEventMaskBit(kCGEventTapDisabledByTimeout) | + CGEventMaskBit(kCGEventTapDisabledByUserInput) | + CGEventMaskBit(NX_SYSDEFINED); + + m_eventTap = CGEventTapCreate( + kCGSessionEventTap, + kCGHeadInsertEventTap, + kCGEventTapOptionDefault, + eventMask, + MediaKeysEventTapCallback, + this ); + + if (m_eventTap) + { + m_runLoopSource = CFMachPortCreateRunLoopSource(kCFAllocatorDefault, m_eventTap, 0); + CFRunLoopAddSource(CFRunLoopGetCurrent(), m_runLoopSource, kCFRunLoopCommonModes); + CGEventTapEnable(m_eventTap, true); + } } ~MediaKeysFilter() { - if (m_eventHandlerRef != NULL) + if (m_eventTap) { - RemoveEventHandler(m_eventHandlerRef); - m_eventHandlerRef = NULL; + CGEventTapEnable(m_eventTap, false); + if (m_runLoopSource) + { + CFRunLoopRemoveSource(CFRunLoopGetCurrent(), m_runLoopSource, kCFRunLoopCommonModes); + CFRelease(m_runLoopSource); + } + CFRelease(m_eventTap); + m_eventTap = NULL; } } @@ -67,34 +75,41 @@ public: } } - QMPlay2MacExtensions::MediaKeysCallback m_mediaKeysCallback; - EventHandlerRef m_eventHandlerRef; -} static *g_mediaKeysFilter; - -// Carbon event handler callback (no blocks needed) -static OSStatus MediaKeysEventHandler(EventHandlerCallRef nextHandler, EventRef event, void *userData) -{ - Q_UNUSED(nextHandler) + static CGEventRef MediaKeysEventTapCallback(CGEventTapProxy proxy, CGEventType type, CGEventRef event, void *refcon) + { + Q_UNUSED(proxy) - MediaKeysFilter *filter = static_cast(userData); - if (!filter) - return eventNotHandledErr; + MediaKeysFilter *filter = static_cast(refcon); - UInt32 eventClass = GetEventClass(event); - UInt32 eventKind = GetEventKind(event); + if (type == kCGEventTapDisabledByTimeout) + { + CGEventTapEnable(filter->m_eventTap, true); + return event; + } - if (eventClass == kEventClassKeyboard && eventKind == kEventHotKeyPressed) - { - EventHotKeyID hotKeyID; - GetEventParameter(event, kEventParamDirectObject, typeEventHotKeyID, NULL, sizeof(hotKeyID), NULL, &hotKeyID); + if (type == NX_SYSDEFINED) + { + NSEvent *nsEvent = [NSEvent eventWithCGEvent:event]; + if ([nsEvent type] == NSSystemDefined && [nsEvent subtype] == 8) + { + int keyCode = (([nsEvent data1] & 0xFFFF0000) >> 16); + int keyFlags = ([nsEvent data1] & 0x0000FFFF); + int keyState = (((keyFlags & 0xFF00) >> 8) == 0xA); + + if (keyState == 1) + { + filter->handleMediaKey(keyCode); + } + } + } - // Handle media key based on hotKeyID - filter->handleMediaKey(hotKeyID.id); - return noErr; + return event; } - return eventNotHandledErr; -} + QMPlay2MacExtensions::MediaKeysCallback m_mediaKeysCallback; + CFMachPortRef m_eventTap; + CFRunLoopSourceRef m_runLoopSource; +} static *g_mediaKeysFilter = NULL; /**/ @@ -112,27 +127,41 @@ void QMPlay2MacExtensions::registerMacOSMediaKeys(const MediaKeysCallback &cb) if (!g_mediaKeysFilter) { g_mediaKeysFilter = new MediaKeysFilter(cb); - // Qt4 doesn't need installNativeEventFilter - Carbon events are handled directly } } + void QMPlay2MacExtensions::unregisterMacOSMediaKeys() { if (g_mediaKeysFilter) { delete g_mediaKeysFilter; - g_mediaKeysFilter = nullptr; + g_mediaKeysFilter = NULL; } } void QMPlay2MacExtensions::showSystemUi(QWidget *mainWindow, bool visible) { Q_UNUSED(mainWindow) - // macOS 10.6.8 doesn't have screensHaveSeparateSpaces (10.9+) - // Simplified for older macOS version + Q_UNUSED(visible) + + // NSApplicationPresentationOptions and setPresentationOptions: are 10.6+ + // On 10.5, we need to use the older SetSystemUIMode API from Carbon + +#if MAC_OS_X_VERSION_MIN_REQUIRED < 1060 + if (visible) + { + SetSystemUIMode(kUIModeNormal, 0); + } + else + { + SetSystemUIMode(kUIModeAllHidden, kUIOptionAutoShowMenuBar); + } +#else NSApplicationPresentationOptions flags; if (visible) flags = NSApplicationPresentationDefault; else flags = (NSApplicationPresentationOptions)(NSApplicationPresentationHideDock | NSApplicationPresentationAutoHideMenuBar); [NSApp setPresentationOptions:flags]; +#endif } diff --git a/src/gui/macOS/ScreenSaver.cpp b/src/gui/macOS/ScreenSaver.cpp index 36885a39..fa890a29 100644 --- a/src/gui/macOS/ScreenSaver.cpp +++ b/src/gui/macOS/ScreenSaver.cpp @@ -39,8 +39,13 @@ public: inline void inhibit() { +#if MAC_OS_X_VERSION_MAX_ALLOWED < 1060 + m_okDisp = (IOPMAssertionCreate(kIOPMAssertionTypeNoDisplaySleep, kIOPMAssertionLevelOn, &m_idDisp) == kIOReturnSuccess); + m_okSys = (IOPMAssertionCreate(kIOPMAssertionTypeNoIdleSleep, kIOPMAssertionLevelOn, &m_idSys) == kIOReturnSuccess); +#else m_okDisp = (IOPMAssertionCreateWithName(kIOPMAssertPreventUserIdleDisplaySleep, kIOPMAssertionLevelOn, QMPLAY2_MEDIA_PLAYBACK, &m_idDisp) == kIOReturnSuccess); m_okSys = (IOPMAssertionCreateWithName(kIOPMAssertPreventUserIdleSystemSleep, kIOPMAssertionLevelOn, QMPLAY2_MEDIA_PLAYBACK, &m_idSys) == kIOReturnSuccess); +#endif } inline void unInhibit() { diff --git a/src/modules/PortAudio/3rdparty/CoreAudio/AudioDevice.mm b/src/modules/PortAudio/3rdparty/CoreAudio/AudioDevice.mm index d08a3ff6..9c3b9ef2 100644 --- a/src/modules/PortAudio/3rdparty/CoreAudio/AudioDevice.mm +++ b/src/modules/PortAudio/3rdparty/CoreAudio/AudioDevice.mm @@ -49,6 +49,10 @@ #include "AudioDevice.h" #import +#if MAC_OS_X_VERSION_MIN_REQUIRED < 1060 +#define __Verify_noErr verify_noerr +#endif + char *OSTStr(OSType type) { static union OSTStr { diff --git a/src/modules/PortAudio/3rdparty/CoreAudio/AudioDeviceList.cpp b/src/modules/PortAudio/3rdparty/CoreAudio/AudioDeviceList.cpp index 1efb0bd2..749fce9f 100644 --- a/src/modules/PortAudio/3rdparty/CoreAudio/AudioDeviceList.cpp +++ b/src/modules/PortAudio/3rdparty/CoreAudio/AudioDeviceList.cpp @@ -48,6 +48,10 @@ #include "AudioDeviceList.h" +#if MAC_OS_X_VERSION_MIN_REQUIRED < 1060 +#define __Verify_noErr verify_noerr +#endif + AudioDeviceList::AudioDeviceList(bool forInput) : mForInput(forInput) { diff --git a/src/qmplay2/opengl/OpenGLCommon.cpp b/src/qmplay2/opengl/OpenGLCommon.cpp index c7fe3540..1f709308 100644 --- a/src/qmplay2/opengl/OpenGLCommon.cpp +++ b/src/qmplay2/opengl/OpenGLCommon.cpp @@ -52,6 +52,9 @@ #ifndef GL_TEXTURE_RECTANGLE_ARB #define GL_TEXTURE_RECTANGLE_ARB 0x84F5 #endif +#ifndef GL_R16_EXT + #define GL_R16_EXT 0x822A +#endif #ifndef GL_R16 #define GL_R16 GL_R16_EXT #endif