Skip to content

macOS

Warning

The current page still doesn't have a translation for this language.

You can read it through google translate.

macOS 的平台 API 全部在 swinx 内部实现swinx/src/platform/cocoa),不依赖外部桥接库,也不使用 g_platformAPI。swinx 会自己创建并接管 NSApplication,因此业务代码只需要写一个 _tWinMain

构建选择

# swinx/CMakeLists.txt
elseif(CMAKE_SYSTEM_NAME MATCHES Darwin)
    include(macos.cmake)

swinx/macos.cmake 编译的源码集合:

file(GLOB SRCS
    src/*.cpp
    src/cmnctl32/*.cpp
    src/cmnctl32/*.c
    src/platform/cocoa/*.mm       # Cocoa 平台层(Objective-C++)
    src/gdi/apple/*.cpp           # Core Graphics 2D 后端
    )

整个 swinx 以 ARC 编译并使用 libc++:

target_compile_options(swinx PRIVATE "-fobjc-arc")
target_compile_options(swinx PRIVATE -stdlib=libc++)
target_link_options(swinx PRIVATE -stdlib=libc++)

Framework 依赖

find_package(Iconv REQUIRED)
find_library(COCOA_LIBRARY Cocoa)
find_library(QUARTZ_LIBRARY QuartzCore)
find_library(IOKit_LIBRARY IOKit)
find_library(Carbon_LIBRARY Carbon)
find_library(Audio_LIBRARY AudioToolbox)
find_library(CoreFoundation_LIBRARY CoreFoundation)
find_library(ImageIO_LIBRARY ImageIO)
Framework 用途
Cocoa(AppKit) 窗口、视图、菜单、托盘、拖放
QuartzCore / CoreGraphics 2D 绘制(Core Graphics 由 Cocoa 伞式框架带入)
CoreFoundation RunLoop、字符串与基础类型
Carbon 少量遗留 API(键盘布局等)
IOKit 设备与显示信息
AudioToolbox PlaySound 音效播放
ImageIO 图片解码
Iconv 字符编码转换(系统提供)

字体与图形基础库仍来自 swinx/thirdpartyfontconfigfreetypepixman-1)。

NSApplication 由 swinx 接管

swinx/src/platform/cocoa/os_state.mm 定义了 NSApplication 子类 SwinXApplication 与配套的 AppDelegate,并在 OsState 构造时完成初始化:

OsState::OsState() {
  @autoreleasepool {
    SwinXApplication *nsApp = [SwinXApplication sharedApplication];
    [nsApp setActivationPolicy:NSApplicationActivationPolicyRegular];
    [nsApp activateIgnoringOtherApps:YES];
    AppDelegate *appDelegate = [[AppDelegate alloc] init];
    [nsApp setDelegate:appDelegate];
    [nsApp finishLaunching];
    ...
  }
}

要点:

  • 注意用的是 finishLaunching 而不是 NSApplicationMain / run。这样 AppKit 完成启动初始化后不会进入自己的事件循环,主导权仍在 SOUI 的 GetMessage 循环手中。
  • 事件由 SwinXApplication 拦截后转换成 Win32 消息投递给 SOUI。
  • AppDelegate 处理 applicationShouldTerminateAfterLastWindowClosed:applicationDockMenu: 等生命周期与 Dock 菜单回调。

因此 macOS 上的入口与 Linux 完全一样,是直接转发的薄 main()

#if !defined(_WIN32) || defined(__MINGW32__)
int main(int argc, char **argv)
{
    HINSTANCE hInst = GetModuleHandle(NULL);
    return _tWinMain(hInst, 0, NULL, SW_SHOWNORMAL);
}
#endif

这一点与 iOS 不同:iOS 的 UIApplicationMain 是阻塞且永不返回的,必须通过 swinx_ios_entry() 包装(见 iOS 适配)。

窗口:SNsWindow

SNsWindow.mm 定义的 SNsWindow 是一个 NSView 子类,同时实现两个协议:

@interface SNsWindow : NSView <NSDraggingDestination, NSTextInputClient>
  • NSDraggingDestination:接收系统拖放(draggingEntered:performDragOperation:),通过 SNsDataObjectProxy 与 swinx 的 IDataObject 互转,把 NSPasteboard 数据映射到 Win32 剪贴板格式。
  • NSTextInputClient:实现输入法组合输入(insertText:replacementRange:markedText 等),转换为 WM_IME_* / WM_CHAR 消息。

2D 绘制:Core Graphics

GDI 调用由 swinx/src/gdi/apple/gdi.cpp 翻译到 Core Graphics(CGBitmapContext / CGContext),与 iOS 共用同一份实现。

同样需要区分层次:Core Graphics 是 swinx 的 2D 后端,SOUI 上层通常仍用 Render_Skia 渲染工厂绘制 UI,最终经 Core Graphics 上屏。这里不涉及 Metal

桌面集成特性

特性 实现文件 机制
托盘图标 STrayIconMgr.mm [[NSStatusBar systemStatusBar] statusItemWithLength:NSVariableStatusItemLength]
拖放 SNsWindow.mm + SNsDataObjectProxy.mm NSPasteboardIDataObject 双向代理
剪贴板 SClipboard.mm NSPasteboard
输入法 imm.mm + SImContext.h NSTextInputClient
通用对话框 dlghelper.mm NSOpenPanel / NSSavePanel
系统主题 os_state.mm 监听 NSApplicationDidBecomeActiveNotification 等通知

部署版本

两处都会影响最低系统版本,注意它们的生效顺序:

# swinx/macos.cmake:swinx 自身的下限
if(NOT CMAKE_OSX_DEPLOYMENT_TARGET OR CMAKE_OSX_DEPLOYMENT_TARGET VERSION_LESS "10.13")
    set(CMAKE_OSX_DEPLOYMENT_TARGET "10.13")
endif()

# 根 CMakeLists.txt:SOUI 主体的设定
if(CMAKE_SYSTEM_NAME MATCHES Darwin)
    set(CMAKE_OSX_DEPLOYMENT_TARGET "12.0")
    ...
    set(CMAKE_CXX_STANDARD 11)
endif()

macos.cmake 中给出的下限依据是:渐变 API(CGShadingCreateAxial)需要 10.2+、ARC 需要 10.6+、libc++ 需要 10.7+,取最高并上浮到 10.13。如需支持更低版本,可显式传入 -DCMAKE_OSX_DEPLOYMENT_TARGET=...,但需自行验证。

资源加载

macOS 与 Linux 用同一套接口,路径指向 .app Bundle 内的资源目录:

cfg.SetSysResZip(bundleRes + "/soui-sys-resource.zip", "");
cfg.SetAppResZip(bundleRes + "/uires.zip", "");
// 或 SetSysResFile / SetAppResFile 指向解开的目录

同时建议随 Bundle 分发字体并显式加载:

AddFontResource(bundleRes + "/simsun.ttc");

构建

cmake -S . -B build -G Xcode
cmake --build build --config Release

动态库配置下 swinx 会加上 -Wl,-all_loadMACOSX_RPATH,以确保 fontconfig / freetype 的符号被完整导出。

相关文档