ui_cocoa: unify Cocoa + Metal event pump on RAWindow

On 10.5 Leopard (and any macOS make-build that runs the bare binary
from a terminal rather than a .app bundle), the window appeared but
didn't respond to keyboard or mouse.  The menu was unreachable.

ROOT CAUSE: input delivery used two different architectures:

  HAVE_COCOA_METAL: RAWindow : NSWindow with a -sendEvent: override.
  AppKit calls -[NSWindow sendEvent:] unconditionally on every event
  destined for the key window, so the override fires with no setup.

  HAVE_COCOA: RApplication : NSApplication with a -sendEvent: override.
  Only fires if NSApp is actually an RApplication instance, which
  requires either NSApplicationMain() + NSPrincipalClass=RApplication
  in Info.plist, or an explicit [RApplication sharedApplication] call
  before any [NSApplication sharedApplication].

The qb/make build bootstraps via plain [NSApplication sharedApplication]
in main() with no NSApplicationMain / Info.plist lookup, so RApplication
was declared but never instantiated.  -sendEvent: was dead code.  Events
flowed through plain NSApplication, got forwarded to the key window's
responder chain, and died in CocoaView's empty -keyDown: stub (which
exists only to squelch the system beep).  Result: window visible,
utterly unresponsive.

FIX: unify on the Metal architecture.  Make HAVE_COCOA also use
RAWindow : NSWindow with the same -sendEvent: override.  AppKit calls
it automatically - no NSPrincipalClass, no class-registration dance.
The two code paths converge on the same event-dispatch structure.

  ui_cocoa.m:
    - Merge the conditional RAWindow-or-RApplication declaration into
      a single unconditional @interface RAWindow : NSWindow.
    - Bracket all 11 NSEvent dot-syntax sites (event.type -> [event type],
      etc.) - now that sendEvent: compiles on the Cocoa path instead
      of being dead code, every dot-access is a compile error on the
      10.5 SDK / GCC 4.0 (pre-Obj-C-2.0, NSEvent's getters aren't
      declared @property there).  Same class of fix as c49a5258c6,
      d38dcb543f, f4d1390a19.
    - Collapse three #if HAVE_COCOA_METAL / #elif HAVE_COCOA case-label
      splits (NSEventTypeFlagsChanged vs NSFlagsChanged, etc.) into
      single modern-name labels.  cocoa_defines.h already provides the
      modern names as aliases on pre-10.12 SDKs.
    - cocoa_create_main_window(): drop the #ifdef HAVE_COCOA_METAL -
      both paths now allocate RAWindow.

Behavioral impact:

  * HAVE_COCOA_METAL (modern macOS, Xcode/make-bundle builds):
    unchanged.  Same RAWindow, same sendEvent:, same event flow.
  * HAVE_COCOA on modern macOS make-bundle: still works - now via
    RAWindow instead of going through the NSPrincipalClass dance.
  * HAVE_COCOA bare-binary from terminal (Leopard PPC, and any make
    build run without .app bundling): NOW WORKS.  Previously unable
    to receive input at all.
  * HAVE_COCOA Xcode builds (RetroArch.xcodeproj, RetroArch_OSX107.
    xcodeproj, RetroArch_PPC.xcodeproj): still work.  Those set
    NSPrincipalClass=RApplication in pkg/apple/OSX/Info.plist, which
    becomes a dangling reference now - but a dangling NSPrincipalClass
    falls back to NSApplication, which is what we want.  The plists
    can be cleaned up in a separate commit.

No per-event overhead change.  NSWindow's sendEvent: dispatch has
the same Obj-C message-send cost as NSApplication's did.  Binary
size grows by a few hundred bytes (the sendEvent: body now compiles
into the non-Metal binary instead of being dead code).
This commit is contained in:
U-DESKTOP-SPFP6AQ\twistedtechre committed 2026-04-21 03:48:36 +02:00
1 parent 53c32a2636
commit 23a945639e
1 file changed
+27 -36
+27 -36
View File
@@ -365,17 +365,16 @@ static ui_application_t ui_application_cocoa = {
@end /* @implementation CommandPerformer */
#if defined(HAVE_COCOA_METAL)
/* RAWindow : NSWindow override. Both the Metal and non-Metal paths
* use this: it's the NSWindow-level sendEvent: hook that AppKit calls
* unconditionally for every event destined for this window. Doing it
* here (rather than subclassing NSApplication) means we don't depend
* on NSPrincipalClass being set in Info.plist, and the Cocoa / Metal
* paths converge on the same event-dispatch architecture. */
@interface RAWindow : NSWindow
@end
@implementation RAWindow
#elif defined(HAVE_COCOA)
@interface RApplication : NSApplication
@end
@implementation RApplication
#endif
#ifdef HAVE_COCOA_METAL
#define CONVERT_POINT() [apple_platform.renderView convertPoint:[event locationInWindow] fromView:nil]
@@ -395,7 +394,11 @@ static ui_application_t ui_application_cocoa = {
}
- (void)sendEvent:(NSEvent *)event {
NSEventType event_type = event.type;
/* Bracket syntax throughout - GCC 4.0 on the pre-Obj-C-2.0 10.5
* SDK doesn't accept dot-syntax on NSEvent's plain getter methods
* (they aren't declared as @property there). Modern clang emits
* identical code for either form. */
NSEventType event_type = [event type];
[super sendEvent:event];
@@ -405,12 +408,12 @@ static ui_application_t ui_application_cocoa = {
case NSEventTypeKeyUp:
{
uint32_t i;
NSString* ch = event.characters;
NSString* ch = [event characters];
uint32_t mod = 0;
const char *inputTextUTF8 = ch.UTF8String;
const char *inputTextUTF8 = [ch UTF8String];
uint32_t character = inputTextUTF8[0];
NSUInteger mods = event.modifierFlags;
uint16_t keycode = event.keyCode;
NSUInteger mods = [event modifierFlags];
uint16_t keycode = [event keyCode];
if (mods & NSEventModifierFlagCapsLock)
mod |= RETROKMOD_CAPSLOCK;
@@ -425,7 +428,7 @@ static ui_application_t ui_application_cocoa = {
if (mods & NSEventModifierFlagNumericPad)
mod |= RETROKMOD_NUMLOCK;
for (i = 1; i < ch.length; i++)
for (i = 1; i < [ch length]; i++)
apple_input_keyboard_event(event_type == NSEventTypeKeyDown,
0, inputTextUTF8[i], mod, RETRO_DEVICE_KEYBOARD);
@@ -436,16 +439,12 @@ static ui_application_t ui_application_cocoa = {
keycode, character, mod, RETRO_DEVICE_KEYBOARD);
}
break;
#if defined(HAVE_COCOA_METAL)
case NSEventTypeFlagsChanged:
#elif defined(HAVE_COCOA)
case NSFlagsChanged:
#endif
case NSEventTypeFlagsChanged:
{
static NSUInteger old_flags = 0;
NSUInteger new_flags = event.modifierFlags;
NSUInteger new_flags = [event modifierFlags];
NSUInteger changed_flags = new_flags ^ old_flags;
uint16_t keycode = event.keyCode;
uint16_t keycode = [event keyCode];
bool down = false;
/* Determine if the changed modifier is being pressed or released
@@ -468,8 +467,8 @@ static ui_application_t ui_application_cocoa = {
case NSEventTypeRightMouseDragged:
case NSEventTypeOtherMouseDragged:
{
CGFloat delta_x = event.deltaX;
CGFloat delta_y = event.deltaY;
CGFloat delta_x = [event deltaX];
CGFloat delta_y = [event deltaY];
NSPoint pos = CONVERT_POINT();
cocoa_input_data_t
*apple = (cocoa_input_data_t*)
@@ -496,18 +495,14 @@ static ui_application_t ui_application_cocoa = {
}
}
break;
#if defined(HAVE_COCOA_METAL)
case NSEventTypeScrollWheel:
#elif defined(HAVE_COCOA)
case NSScrollWheel:
#endif
case NSEventTypeScrollWheel:
/* TODO/FIXME - properly implement. */
break;
case NSEventTypeLeftMouseDown:
case NSEventTypeRightMouseDown:
case NSEventTypeOtherMouseDown:
{
NSInteger number = event.buttonNumber;
NSInteger number = [event buttonNumber];
NSPoint pos = CONVERT_POINT();
cocoa_input_data_t
*apple = (cocoa_input_data_t*)
@@ -522,7 +517,7 @@ static ui_application_t ui_application_cocoa = {
case NSEventTypeRightMouseUp:
case NSEventTypeOtherMouseUp:
{
NSInteger number = event.buttonNumber;
NSInteger number = [event buttonNumber];
NSPoint pos = CONVERT_POINT();
cocoa_input_data_t
*apple = (cocoa_input_data_t*)
@@ -1410,17 +1405,13 @@ static NSWindow *cocoa_create_main_window(void)
| NSWindowStyleMaskResizable;
NSRect frame = NSMakeRect(0, 0, 480, 360);
#ifdef HAVE_COCOA_METAL
/* Both HAVE_COCOA and HAVE_COCOA_METAL use RAWindow now; its
* -sendEvent: override is what feeds keyboard/mouse events into
* the cocoa_input driver. */
NSWindow *window = [[RAWindow alloc] initWithContentRect:frame
styleMask:style
backing:NSBackingStoreBuffered
defer:NO];
#else
NSWindow *window = [[NSWindow alloc] initWithContentRect:frame
styleMask:style
backing:NSBackingStoreBuffered
defer:NO];
#endif
[window setTitle:@"RetroArch"];
[window setReleasedWhenClosed:NO];
[window setAllowsToolTipsWhenApplicationIsInactive:NO];