-
Notifications
You must be signed in to change notification settings - Fork 1
Expand file tree
/
Copy pathwindow_manager_macos.mm
More file actions
291 lines (252 loc) · 8.82 KB
/
window_manager_macos.mm
File metadata and controls
291 lines (252 loc) · 8.82 KB
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
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
#import <Cocoa/Cocoa.h>
#include <cstring>
#include <iostream>
#include <string>
#include "../../window.h"
#include "../../window_manager.h"
// Forward declaration for the delegate
@class NativeAPIWindowManagerDelegate;
namespace nativeapi {
// Private implementation to hide Objective-C details
class WindowManager::WindowManagerImpl {
public:
WindowManagerImpl(WindowManager* manager);
~WindowManagerImpl();
void SetupEventMonitoring();
void CleanupEventMonitoring();
void OnWindowEvent(NSWindow* window, const std::string& event_type);
private:
WindowManager* manager_;
NativeAPIWindowManagerDelegate* delegate_;
};
} // namespace nativeapi
// Objective-C delegate class to handle NSWindow notifications
@interface NativeAPIWindowManagerDelegate : NSObject
@property (nonatomic, assign) nativeapi::WindowManager::WindowManagerImpl* impl;
- (instancetype)initWithImpl:(nativeapi::WindowManager::WindowManagerImpl*)impl;
@end
@implementation NativeAPIWindowManagerDelegate
- (instancetype)initWithImpl:(nativeapi::WindowManager::WindowManagerImpl*)impl {
if (self = [super init]) {
_impl = impl;
}
return self;
}
- (void)windowDidBecomeKey:(NSNotification*)notification {
NSWindow* window = [notification object];
if (_impl) {
_impl->OnWindowEvent(window, "focused");
}
}
- (void)windowDidResignKey:(NSNotification*)notification {
NSWindow* window = [notification object];
if (_impl) {
_impl->OnWindowEvent(window, "blurred");
}
}
- (void)windowDidMiniaturize:(NSNotification*)notification {
NSWindow* window = [notification object];
if (_impl) {
_impl->OnWindowEvent(window, "minimized");
}
}
- (void)windowDidDeminiaturize:(NSNotification*)notification {
NSWindow* window = [notification object];
if (_impl) {
_impl->OnWindowEvent(window, "restored");
}
}
- (void)windowDidResize:(NSNotification*)notification {
NSWindow* window = [notification object];
if (_impl) {
_impl->OnWindowEvent(window, "resized");
}
}
- (void)windowDidMove:(NSNotification*)notification {
NSWindow* window = [notification object];
if (_impl) {
_impl->OnWindowEvent(window, "moved");
}
}
- (void)windowWillClose:(NSNotification*)notification {
NSWindow* window = [notification object];
if (_impl) {
_impl->OnWindowEvent(window, "closing");
}
}
@end
namespace nativeapi {
WindowManager::WindowManagerImpl::WindowManagerImpl(WindowManager* manager)
: manager_(manager), delegate_(nullptr) {
}
WindowManager::WindowManagerImpl::~WindowManagerImpl() {
CleanupEventMonitoring();
}
void WindowManager::WindowManagerImpl::SetupEventMonitoring() {
if (!delegate_) {
delegate_ = [[NativeAPIWindowManagerDelegate alloc] initWithImpl:this];
NSNotificationCenter* center = [NSNotificationCenter defaultCenter];
[center addObserver:delegate_
selector:@selector(windowDidBecomeKey:)
name:NSWindowDidBecomeKeyNotification
object:nil];
[center addObserver:delegate_
selector:@selector(windowDidResignKey:)
name:NSWindowDidResignKeyNotification
object:nil];
[center addObserver:delegate_
selector:@selector(windowDidMiniaturize:)
name:NSWindowDidMiniaturizeNotification
object:nil];
[center addObserver:delegate_
selector:@selector(windowDidDeminiaturize:)
name:NSWindowDidDeminiaturizeNotification
object:nil];
[center addObserver:delegate_
selector:@selector(windowDidResize:)
name:NSWindowDidResizeNotification
object:nil];
[center addObserver:delegate_
selector:@selector(windowDidMove:)
name:NSWindowDidMoveNotification
object:nil];
[center addObserver:delegate_
selector:@selector(windowWillClose:)
name:NSWindowWillCloseNotification
object:nil];
}
}
void WindowManager::WindowManagerImpl::CleanupEventMonitoring() {
if (delegate_) {
NSNotificationCenter* center = [NSNotificationCenter defaultCenter];
[center removeObserver:delegate_];
delegate_ = nil;
}
}
void WindowManager::WindowManagerImpl::OnWindowEvent(NSWindow* window, const std::string& event_type) {
WindowID window_id = [window windowNumber];
if (event_type == "focused") {
WindowFocusedEvent event(window_id);
manager_->DispatchWindowEvent(event);
} else if (event_type == "blurred") {
WindowBlurredEvent event(window_id);
manager_->DispatchWindowEvent(event);
} else if (event_type == "minimized") {
WindowMinimizedEvent event(window_id);
manager_->DispatchWindowEvent(event);
} else if (event_type == "restored") {
WindowRestoredEvent event(window_id);
manager_->DispatchWindowEvent(event);
} else if (event_type == "resized") {
NSRect frame = [window frame];
Size new_size = {frame.size.width, frame.size.height};
WindowResizedEvent event(window_id, new_size);
manager_->DispatchWindowEvent(event);
} else if (event_type == "moved") {
NSRect frame = [window frame];
Point new_position = {frame.origin.x, frame.origin.y};
WindowMovedEvent event(window_id, new_position);
manager_->DispatchWindowEvent(event);
} else if (event_type == "closing") {
WindowClosedEvent event(window_id);
manager_->DispatchWindowEvent(event);
}
}
WindowManager::WindowManager() : impl_(std::make_unique<WindowManagerImpl>(this)) {
SetupEventMonitoring();
}
WindowManager::~WindowManager() {
CleanupEventMonitoring();
}
void WindowManager::SetupEventMonitoring() {
impl_->SetupEventMonitoring();
}
void WindowManager::CleanupEventMonitoring() {
impl_->CleanupEventMonitoring();
}
void WindowManager::DispatchWindowEvent(const Event& event) {
event_dispatcher_.DispatchSync(event);
}
// Create a new window with the given options.
std::shared_ptr<Window> WindowManager::Create(const WindowOptions& options) {
NSRect frame = NSMakeRect(100, 100, options.size.width, options.size.height);
NSUInteger style =
NSWindowStyleMaskTitled | NSWindowStyleMaskClosable | NSWindowStyleMaskResizable;
NSWindow* ns_window = [[NSWindow alloc] initWithContentRect:frame
styleMask:style
backing:NSBackingStoreBuffered
defer:NO];
[ns_window setTitle:[NSString stringWithUTF8String:options.title.c_str()]];
[ns_window center];
[ns_window makeKeyAndOrderFront:nil];
[ns_window makeMainWindow];
WindowID window_id = [ns_window windowNumber];
auto window = std::make_shared<Window>((__bridge void*)ns_window);
windows_[window_id] = window;
// Dispatch window created event
WindowCreatedEvent created_event(window_id);
DispatchWindowEvent(created_event);
return window;
}
// Destroy a window by its ID. Returns true if window was destroyed.
bool WindowManager::Destroy(WindowID id) {
auto it = windows_.find(id);
if (it != windows_.end()) {
// Get the NSWindow to close it
NSArray* ns_windows = [[NSApplication sharedApplication] windows];
for (NSWindow* ns_window in ns_windows) {
if ([ns_window windowNumber] == id) {
[ns_window close];
windows_.erase(it);
return true;
}
}
// Remove from our map even if we couldn't find the NSWindow
windows_.erase(it);
}
return false;
}
std::shared_ptr<Window> WindowManager::Get(WindowID id) {
auto it = windows_.find(id);
if (it != windows_.end()) {
return it->second;
}
NSArray* ns_windows = [[NSApplication sharedApplication] windows];
for (NSWindow* ns_window in ns_windows) {
if ([ns_window windowNumber] == id) {
auto window = std::make_shared<Window>((__bridge void*)ns_window);
windows_[id] = window;
return window;
}
}
return nullptr;
}
std::vector<std::shared_ptr<Window>> WindowManager::GetAll() {
std::vector<std::shared_ptr<Window>> windows;
NSArray* ns_windows = [[NSApplication sharedApplication] windows];
for (NSWindow* ns_window in ns_windows) {
WindowID window_id = [ns_window windowNumber];
auto it = windows_.find(window_id);
if (it == windows_.end()) {
auto window = std::make_shared<Window>((__bridge void*)ns_window);
windows_[window_id] = window;
}
}
for (auto& window : windows_) {
windows.push_back(window.second);
}
return windows;
}
std::shared_ptr<Window> WindowManager::GetCurrent() {
NSApplication* app = [NSApplication sharedApplication];
NSArray* ns_windows = [[NSApplication sharedApplication] windows];
NSWindow* ns_window = [app mainWindow];
if (ns_window == nil) {
ns_window = [ns_windows objectAtIndex:0];
}
if (ns_window != nil) {
return Get([ns_window windowNumber]);
}
return nullptr;
}
} // namespace nativeapi