-
Notifications
You must be signed in to change notification settings - Fork 3
/
CocoaSurface.mm
104 lines (102 loc) · 4.26 KB
/
CocoaSurface.mm
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
/*
* Copyright (c) 2020-2024 WangBin <wbsecg1 at gmail.com>
* Universal Graphics Surface
* Source code: https://github.com/wang-bin/ugs
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*/
#include "ugs/PlatformSurface.h"
#import <QuartzCore/CALayer.h>
#import <AppKit/NSApplication.h>
#import <AppKit/NSView.h>
#import <AppKit/NSWindow.h>
#import <AppKit/NSScreen.h>
#define USE_CFNOTIFICATION
UGS_NS_BEGIN
class CocoaSurface final: public PlatformSurface
{
public:
CocoaSurface() : PlatformSurface() {
setNativeHandleChangeCallback([this](void* old){
auto getView = [](NSObject* obj){
if ([obj isKindOfClass:[CALayer class]])
return (NSView*)nil;
if ([obj isKindOfClass:[NSWindow class]]) {
auto win = (NSWindow*)obj;
return (NSView*)win.contentView;
}
return (NSView*)obj;
};
if (old) { // updateNativeWindow(nullptr) called outside or resetNativeHandle(nullptr) in dtor
auto view = getView((__bridge NSObject*)old);
if (view) {
#ifdef USE_CFNOTIFICATION
CFNotificationCenterRemoveObserver(CFNotificationCenterGetLocalCenter(), this, CFSTR("NSViewFrameDidChangeNotification"), nullptr);
#endif
}
if (observer_)
[[NSNotificationCenter defaultCenter] removeObserver:observer_];
//CFRelease((CFTypeRef)view);
}
auto obj = (__bridge NSObject*)nativeHandle();
if (!obj)
return;
view_ = getView(obj);
if (!view_)
return;
#ifdef USE_CFNOTIFICATION // TODO: move to ugs surface like UIKitSurface
CFNotificationCenterAddObserver(CFNotificationCenterGetLocalCenter(), this
, [](CFNotificationCenterRef center, void *observer, CFNotificationName name, const void *object, CFDictionaryRef userInfo){
auto s = static_cast<CocoaSurface*>(observer);
auto view = (__bridge NSView*)object;
s->resize(static_cast<int>(view.layer.frame.size.width*view.layer.contentsScale), static_cast<int>(view.layer.frame.size.height*view.layer.contentsScale));
}
, CFSTR("NSViewFrameDidChangeNotification")
, (const void*)view_
, CFNotificationSuspensionBehaviorDeliverImmediately
);
#else
observer_ = [[NSNotificationCenter defaultCenter] addObserverForName:NSViewFrameDidChangeNotification
object:view_
queue:[NSOperationQueue mainQueue] // or nil
usingBlock:^(NSNotification *note) {
resize(view_.frame.size.width*view.layer.contentsScale, view_.frame.size.height*view.layer.contentsScale);
}];
#endif
});
}
~CocoaSurface() override {
//if (layer_)
// CFRelease((CFTypeRef)layer_);
resetNativeHandle(nullptr);
#ifdef USE_CFNOTIFICATION
CFNotificationCenterRemoveObserver(CFNotificationCenterGetLocalCenter(), this, CFSTR("NSViewFrameDidChangeNotification"), nullptr);
#else
[[NSNotificationCenter defaultCenter] removeObserver:observer_];
# if !__has_feature(objc_arc)
[observer_ release];
# endif
#endif
}
bool size(int *w, int *h) const override {
if (!view_)
return false;
auto scale = view_.layer.contentsScale;
if (scale < 1) {
scale = [NSScreen mainScreen].backingScaleFactor;
}
//printf("%p~~~~~~view size: %fx%f, .layer: %p, layer size: %fx%f @%f~~~~~~\n", this, view_.frame.size.width, view_.frame.size.height, view_.layer, view_.layer.bounds.size.width, view_.layer.bounds.size.height, view_.layer.contentsScale);
if (w)
*w = (int)(view_.frame.size.width * scale);
if (h)
*h = (int)(view_.frame.size.height * scale);
return true;
}
private:
NSView *view_ = nil;
NSObject *observer_ = nullptr;
};
PlatformSurface* create_cocoa_surface() { return new CocoaSurface();}
UGS_NS_END