|
4 | 4 |
|
5 | 5 | from .rs_ffi import ffi, lib |
6 | 6 |
|
| 7 | +if sys.platform.startswith("darwin"): |
| 8 | + from rubicon.objc.api import ObjCInstance, ObjCClass |
| 9 | + |
7 | 10 |
|
8 | 11 | def get_memoryview_and_address(data): |
9 | 12 | """Get a memoryview for the given data and its memory address. |
@@ -67,57 +70,53 @@ def get_surface_id_from_canvas(canvas): |
67 | 70 |
|
68 | 71 | elif sys.platform.startswith("darwin"): # no-cover |
69 | 72 | # This is what the triangle example from wgpu-native does: |
70 | | - # #if WGPU_TARGET == WGPU_TARGET_MACOS |
71 | | - # { |
72 | | - # id metal_layer = NULL; |
73 | | - # NSWindow *ns_window = glfwGetCocoaWindow(window); |
74 | | - # [ns_window.contentView setWantsLayer:YES]; |
75 | | - # metal_layer = [CAMetalLayer layer]; |
76 | | - # [ns_window.contentView setLayer:metal_layer]; |
77 | | - # surface = wgpu_create_surface_from_metal_layer(metal_layer); |
78 | | - # } |
| 73 | + # if WGPU_TARGET == WGPU_TARGET_MACOS |
| 74 | + # { |
| 75 | + # id metal_layer = NULL; |
| 76 | + # NSWindow *ns_window = glfwGetCocoaWindow(window); |
| 77 | + # [ns_window.contentView setWantsLayer:YES]; |
| 78 | + # metal_layer = [CAMetalLayer layer]; |
| 79 | + # [ns_window.contentView setLayer:metal_layer]; |
| 80 | + # surface = wgpu_create_surface_from_metal_layer(metal_layer); |
| 81 | + # } |
79 | 82 | window = ctypes.c_void_p(win_id) |
80 | 83 |
|
81 | | - objc = ctypes.cdll.LoadLibrary(ctypes.util.find_library("objc")) |
82 | | - objc.objc_getClass.restype = ctypes.c_void_p |
83 | | - objc.sel_registerName.restype = ctypes.c_void_p |
84 | | - objc.objc_msgSend.restype = ctypes.c_void_p |
85 | | - objc.objc_msgSend.argtypes = [ctypes.c_void_p, ctypes.c_void_p] |
86 | | - |
87 | | - content_view_sel = objc.sel_registerName(b"contentView") |
88 | | - set_wants_layer_sel = objc.sel_registerName(b"setWantsLayer:") |
89 | | - responds_to_sel_sel = objc.sel_registerName(b"respondsToSelector:") |
90 | | - layer_sel = objc.sel_registerName(b"layer") |
91 | | - set_layer_sel = objc.sel_registerName(b"setLayer:") |
92 | | - |
93 | | - # Try some duck typing to see what kind of object the window pointer points to |
94 | | - # Qt doesn't return a NSWindow, but a QNSView instead, which is subclass of NSView. |
95 | | - if objc.objc_msgSend( |
96 | | - window, responds_to_sel_sel, ctypes.c_void_p(content_view_sel) |
97 | | - ): |
98 | | - # NSWindow instances respond to contentView selector |
99 | | - content_view = objc.objc_msgSend(window, content_view_sel) |
100 | | - elif objc.objc_msgSend(window, responds_to_sel_sel, ctypes.c_void_p(layer_sel)): |
101 | | - # NSView instances respond to layer selector |
102 | | - # Let's assume that the given window pointer is actually the content view |
103 | | - content_view = window |
| 84 | + cw = ObjCInstance(window) |
| 85 | + try: |
| 86 | + cv = cw.contentView |
| 87 | + except AttributeError: |
| 88 | + # With wxPython, ObjCInstance is actually already a wxNSView and |
| 89 | + # not a NSWindow so no need to get the contentView (which is a |
| 90 | + # NSWindow method) |
| 91 | + wx_view = ObjCInstance(window) |
| 92 | + # Creating a metal layer directly in the wxNSView does not seem to |
| 93 | + # work, so instead add a subview with the same bounds that resizes |
| 94 | + # with the wxNSView and add a metal layer to that |
| 95 | + if not len(wx_view.subviews): |
| 96 | + new_view = ObjCClass("NSView").alloc().initWithFrame(wx_view.bounds) |
| 97 | + # typedef NS_OPTIONS(NSUInteger, NSAutoresizingMaskOptions) { |
| 98 | + # ... |
| 99 | + # NSViewWidthSizable = 2, |
| 100 | + # NSViewHeightSizable = 16, |
| 101 | + # ... |
| 102 | + # }; |
| 103 | + # Make subview resize with superview by combining |
| 104 | + # NSViewHeightSizable and NSViewWidthSizable |
| 105 | + new_view.setAutoresizingMask(18) |
| 106 | + wx_view.setAutoresizesSubviews(True) |
| 107 | + wx_view.addSubview(new_view) |
| 108 | + cv = wx_view.subviews[0] |
| 109 | + |
| 110 | + if cv.layer and cv.layer.isKindOfClass(ObjCClass("CAMetalLayer")): |
| 111 | + # No need to create a metal layer again |
| 112 | + metal_layer = cv.layer |
104 | 113 | else: |
105 | | - # If the code reaches this part, we know that `window` is an |
106 | | - # objective-c object but the type is neither NSView or NSWindow. |
107 | | - raise RuntimeError("Received unidentified objective-c object.") |
108 | | - |
109 | | - # [ns_window.contentView setWantsLayer:YES] |
110 | | - objc.objc_msgSend(content_view, set_wants_layer_sel, True) |
111 | | - |
112 | | - # metal_layer = [CAMetalLayer layer]; |
113 | | - ca_metal_layer_class = objc.objc_getClass(b"CAMetalLayer") |
114 | | - metal_layer = objc.objc_msgSend(ca_metal_layer_class, layer_sel) |
115 | | - |
116 | | - # [ns_window.content_view setLayer:metal_layer]; |
117 | | - objc.objc_msgSend(content_view, set_layer_sel, ctypes.c_void_p(metal_layer)) |
| 114 | + metal_layer = ObjCClass("CAMetalLayer").layer() |
| 115 | + cv.setLayer(metal_layer) |
| 116 | + cv.setWantsLayer(True) |
118 | 117 |
|
119 | 118 | struct = ffi.new("WGPUSurfaceDescriptorFromMetalLayer *") |
120 | | - struct.layer = ffi.cast("void *", metal_layer) |
| 119 | + struct.layer = ffi.cast("void *", metal_layer.ptr.value) |
121 | 120 | struct.chain.sType = lib.WGPUSType_SurfaceDescriptorFromMetalLayer |
122 | 121 |
|
123 | 122 | elif sys.platform.startswith("linux"): # no-cover |
|
0 commit comments