Skip to content

Load AppKit before calling into CoreText - #32376

Open
iccir wants to merge 1 commit into
matplotlib:mainfrom
iccir:load-appkit-before-coretext
Open

iccir wants to merge 1 commit into
matplotlib:mainfrom
iccir:load-appkit-before-coretext

Conversation

@iccir

@iccir iccir commented Sep 19, 2026

Copy link
Copy Markdown
Contributor

PR summary

On macOS, using the CoreText framework when AppKit is not loaded into memory can result in exceptions if AppKit is later used.

Consider the following example:

example.py
import ctypes
from ctypes import c_void_p, c_double

LOAD_APPKIT_FIRST = False

appkit = None
if LOAD_APPKIT_FIRST:
    appkit = ctypes.CDLL("/System/Library/Frameworks/AppKit.framework/AppKit")

objc = ctypes.CDLL("/usr/lib/libobjc.A.dylib")
coretext = ctypes.CDLL("/System/Library/Frameworks/CoreText.framework/CoreText")

CTFontCollectionCreateFromAvailableFonts = (
    coretext.CTFontCollectionCreateFromAvailableFonts
)
CTFontCollectionCreateFromAvailableFonts.argtypes = [c_void_p]
CTFontCollectionCreateFromAvailableFonts.restype = c_void_p

collection = CTFontCollectionCreateFromAvailableFonts(None)

objc_getClass = objc.objc_getClass
objc_getClass.argtypes = [ctypes.c_char_p]
objc_getClass.restype = c_void_p

sel_registerName = objc.sel_registerName
sel_registerName.argtypes = [ctypes.c_char_p]
sel_registerName.restype = c_void_p

objc_msgSend = ctypes.cast(
    objc.objc_msgSend,
    ctypes.CFUNCTYPE(c_void_p, c_void_p, c_void_p, c_double, c_double)
)

if not appkit:
    appkit = ctypes.CDLL("/System/Library/Frameworks/AppKit.framework/AppKit")

NSFont = objc_getClass(b"NSFont")
selector = sel_registerName(b"monospacedSystemFontOfSize:weight:")

font = objc_msgSend(NSFont, selector, 0, 400.0)

If LOAD_APPKIT_FIRST is True, we will load AppKit before our call to CTFontCollectionCreateFromAvailableFonts(). This sets up bridging and allows later calls in AppKit that assume a NSFont object to instead operate on a CTFont object.

If LOAD_APPKIT_FIRST is False, AppKit will later try to send an Obj-C message to a CTFont object and we will get an exception. I'm not 100% sure of the exact details here. I could find out, but it would require a few hours of decompiling AppKit code.

I don't want to always pull in AppKit when _c_internal_utils is loaded. Instead, this PR only loads it in mpl_get_available_fonts(), which should only be called when rebuilding the font cache.

AI Disclosure

  • I used AI to write some examples and tests during development.
  • All final code is my own.

PR quality check

  • Use an expressive title, e.g. "Fix title font property precedence"
  • [N/A] New and changed code is tested
  • [N/A] Plotting related features are demonstrated in an example
  • [N/A] New features and API changes have release notes
  • [N/A] Documentation complies with general and docstring guidelines

@iccir iccir added this to the v3.12.0 milestone Sep 19, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant