1// 2// Copyright 2015 The ANGLE Project Authors. All rights reserved. 3// Use of this source code is governed by a BSD-style license that can be 4// found in the LICENSE file. 5// 6 7// OSXWindow.mm: Implementation of OSWindow for OSX 8 9#include "util/osx/OSXWindow.h" 10 11#include <set> 12// Include Carbon to use the keycode names in Carbon's Event.h 13#include <Carbon/Carbon.h> 14 15#include "anglebase/no_destructor.h" 16#include "common/debug.h" 17 18// On OSX 10.12 a number of AppKit interfaces have been renamed for consistency, and the previous 19// symbols tagged as deprecated. However we can't simply use the new symbols as it would break 20// compilation on our automated testing that doesn't use OSX 10.12 yet. So we just ignore the 21// warnings. 22#pragma GCC diagnostic ignored "-Wdeprecated-declarations" 23 24// Some events such as "ShouldTerminate" are sent to the whole application so we keep a list of 25// all the windows in order to forward the event to each of them. However this and calling pushEvent 26// in ApplicationDelegate is inherently unsafe in a multithreaded environment. 27static std::set<OSXWindow *> &AllWindows() 28{ 29 static angle::base::NoDestructor<std::set<OSXWindow *>> allWindows; 30 return *allWindows; 31} 32 33@interface Application : NSApplication 34@end 35 36@implementation Application 37- (void)sendEvent:(NSEvent *)nsEvent 38{ 39 if ([nsEvent type] == NSApplicationDefined) 40 { 41 for (auto window : AllWindows()) 42 { 43 if ([window->getNSWindow() windowNumber] == [nsEvent windowNumber]) 44 { 45 Event event; 46 event.Type = Event::EVENT_TEST; 47 window->pushEvent(event); 48 } 49 } 50 } 51 [super sendEvent:nsEvent]; 52} 53@end 54 55// The Delegate receiving application-wide events. 56@interface ApplicationDelegate : NSObject 57@end 58 59@implementation ApplicationDelegate 60- (NSApplicationTerminateReply)applicationShouldTerminate:(NSApplication *)sender 61{ 62 Event event; 63 event.Type = Event::EVENT_CLOSED; 64 for (auto window : AllWindows()) 65 { 66 window->pushEvent(event); 67 } 68 return NSTerminateCancel; 69} 70@end 71static ApplicationDelegate *gApplicationDelegate = nil; 72 73static bool InitializeAppKit() 74{ 75 if (NSApp != nil) 76 { 77 return true; 78 } 79 80 // Initialize the global variable "NSApp" 81 [Application sharedApplication]; 82 83 // Make us appear in the dock 84 [NSApp setActivationPolicy:NSApplicationActivationPolicyRegular]; 85 86 // Register our global event handler 87 gApplicationDelegate = [[ApplicationDelegate alloc] init]; 88 if (gApplicationDelegate == nil) 89 { 90 return false; 91 } 92 [NSApp setDelegate:static_cast<id>(gApplicationDelegate)]; 93 94 // Set our status to "started" so we are not bouncing in the doc and can activate 95 [NSApp finishLaunching]; 96 return true; 97} 98 99// NS's and CG's coordinate systems start at the bottom left, while OSWindow's coordinate 100// system starts at the top left. This function converts the Y coordinate accordingly. 101static float YCoordToFromCG(float y) 102{ 103 float screenHeight = CGDisplayBounds(CGMainDisplayID()).size.height; 104 return screenHeight - y; 105} 106 107// Delegate for window-wide events, note that the protocol doesn't contain anything input related. 108@implementation WindowDelegate 109- (id)initWithWindow:(OSXWindow *)window 110{ 111 self = [super init]; 112 if (self != nil) 113 { 114 mWindow = window; 115 } 116 return self; 117} 118 119- (void)onOSXWindowDeleted 120{ 121 mWindow = nil; 122} 123 124- (BOOL)windowShouldClose:(id)sender 125{ 126 Event event; 127 event.Type = Event::EVENT_CLOSED; 128 mWindow->pushEvent(event); 129 return NO; 130} 131 132- (void)windowDidResize:(NSNotification *)notification 133{ 134 NSSize windowSize = [[mWindow->getNSWindow() contentView] frame].size; 135 Event event; 136 event.Type = Event::EVENT_RESIZED; 137 event.Size.Width = (int)windowSize.width; 138 event.Size.Height = (int)windowSize.height; 139 mWindow->pushEvent(event); 140} 141 142- (void)windowDidMove:(NSNotification *)notification 143{ 144 NSRect screenspace = [mWindow->getNSWindow() frame]; 145 Event event; 146 event.Type = Event::EVENT_MOVED; 147 event.Move.X = (int)screenspace.origin.x; 148 event.Move.Y = (int)YCoordToFromCG(screenspace.origin.y + screenspace.size.height); 149 mWindow->pushEvent(event); 150} 151 152- (void)windowDidBecomeKey:(NSNotification *)notification 153{ 154 Event event; 155 event.Type = Event::EVENT_GAINED_FOCUS; 156 mWindow->pushEvent(event); 157 [self retain]; 158} 159 160- (void)windowDidResignKey:(NSNotification *)notification 161{ 162 if (mWindow != nil) 163 { 164 Event event; 165 event.Type = Event::EVENT_LOST_FOCUS; 166 mWindow->pushEvent(event); 167 } 168 [self release]; 169} 170@end 171 172static Key NSCodeToKey(int keyCode) 173{ 174 // Missing KEY_PAUSE 175 switch (keyCode) 176 { 177 case kVK_Shift: 178 return KEY_LSHIFT; 179 case kVK_RightShift: 180 return KEY_RSHIFT; 181 case kVK_Option: 182 return KEY_LALT; 183 case kVK_RightOption: 184 return KEY_RALT; 185 case kVK_Control: 186 return KEY_LCONTROL; 187 case kVK_RightControl: 188 return KEY_RCONTROL; 189 case kVK_Command: 190 return KEY_LSYSTEM; 191 // Right System doesn't have a name, but shows up as 0x36. 192 case 0x36: 193 return KEY_RSYSTEM; 194 case kVK_Function: 195 return KEY_MENU; 196 197 case kVK_ANSI_Semicolon: 198 return KEY_SEMICOLON; 199 case kVK_ANSI_Slash: 200 return KEY_SLASH; 201 case kVK_ANSI_Equal: 202 return KEY_EQUAL; 203 case kVK_ANSI_Minus: 204 return KEY_DASH; 205 case kVK_ANSI_LeftBracket: 206 return KEY_LBRACKET; 207 case kVK_ANSI_RightBracket: 208 return KEY_RBRACKET; 209 case kVK_ANSI_Comma: 210 return KEY_COMMA; 211 case kVK_ANSI_Period: 212 return KEY_PERIOD; 213 case kVK_ANSI_Backslash: 214 return KEY_BACKSLASH; 215 case kVK_ANSI_Grave: 216 return KEY_TILDE; 217 case kVK_Escape: 218 return KEY_ESCAPE; 219 case kVK_Space: 220 return KEY_SPACE; 221 case kVK_Return: 222 return KEY_RETURN; 223 case kVK_Delete: 224 return KEY_BACK; 225 case kVK_Tab: 226 return KEY_TAB; 227 case kVK_PageUp: 228 return KEY_PAGEUP; 229 case kVK_PageDown: 230 return KEY_PAGEDOWN; 231 case kVK_End: 232 return KEY_END; 233 case kVK_Home: 234 return KEY_HOME; 235 case kVK_Help: 236 return KEY_INSERT; 237 case kVK_ForwardDelete: 238 return KEY_DELETE; 239 case kVK_ANSI_KeypadPlus: 240 return KEY_ADD; 241 case kVK_ANSI_KeypadMinus: 242 return KEY_SUBTRACT; 243 case kVK_ANSI_KeypadMultiply: 244 return KEY_MULTIPLY; 245 case kVK_ANSI_KeypadDivide: 246 return KEY_DIVIDE; 247 248 case kVK_F1: 249 return KEY_F1; 250 case kVK_F2: 251 return KEY_F2; 252 case kVK_F3: 253 return KEY_F3; 254 case kVK_F4: 255 return KEY_F4; 256 case kVK_F5: 257 return KEY_F5; 258 case kVK_F6: 259 return KEY_F6; 260 case kVK_F7: 261 return KEY_F7; 262 case kVK_F8: 263 return KEY_F8; 264 case kVK_F9: 265 return KEY_F9; 266 case kVK_F10: 267 return KEY_F10; 268 case kVK_F11: 269 return KEY_F11; 270 case kVK_F12: 271 return KEY_F12; 272 case kVK_F13: 273 return KEY_F13; 274 case kVK_F14: 275 return KEY_F14; 276 case kVK_F15: 277 return KEY_F15; 278 279 case kVK_LeftArrow: 280 return KEY_LEFT; 281 case kVK_RightArrow: 282 return KEY_RIGHT; 283 case kVK_DownArrow: 284 return KEY_DOWN; 285 case kVK_UpArrow: 286 return KEY_UP; 287 288 case kVK_ANSI_Keypad0: 289 return KEY_NUMPAD0; 290 case kVK_ANSI_Keypad1: 291 return KEY_NUMPAD1; 292 case kVK_ANSI_Keypad2: 293 return KEY_NUMPAD2; 294 case kVK_ANSI_Keypad3: 295 return KEY_NUMPAD3; 296 case kVK_ANSI_Keypad4: 297 return KEY_NUMPAD4; 298 case kVK_ANSI_Keypad5: 299 return KEY_NUMPAD5; 300 case kVK_ANSI_Keypad6: 301 return KEY_NUMPAD6; 302 case kVK_ANSI_Keypad7: 303 return KEY_NUMPAD7; 304 case kVK_ANSI_Keypad8: 305 return KEY_NUMPAD8; 306 case kVK_ANSI_Keypad9: 307 return KEY_NUMPAD9; 308 309 case kVK_ANSI_A: 310 return KEY_A; 311 case kVK_ANSI_B: 312 return KEY_B; 313 case kVK_ANSI_C: 314 return KEY_C; 315 case kVK_ANSI_D: 316 return KEY_D; 317 case kVK_ANSI_E: 318 return KEY_E; 319 case kVK_ANSI_F: 320 return KEY_F; 321 case kVK_ANSI_G: 322 return KEY_G; 323 case kVK_ANSI_H: 324 return KEY_H; 325 case kVK_ANSI_I: 326 return KEY_I; 327 case kVK_ANSI_J: 328 return KEY_J; 329 case kVK_ANSI_K: 330 return KEY_K; 331 case kVK_ANSI_L: 332 return KEY_L; 333 case kVK_ANSI_M: 334 return KEY_M; 335 case kVK_ANSI_N: 336 return KEY_N; 337 case kVK_ANSI_O: 338 return KEY_O; 339 case kVK_ANSI_P: 340 return KEY_P; 341 case kVK_ANSI_Q: 342 return KEY_Q; 343 case kVK_ANSI_R: 344 return KEY_R; 345 case kVK_ANSI_S: 346 return KEY_S; 347 case kVK_ANSI_T: 348 return KEY_T; 349 case kVK_ANSI_U: 350 return KEY_U; 351 case kVK_ANSI_V: 352 return KEY_V; 353 case kVK_ANSI_W: 354 return KEY_W; 355 case kVK_ANSI_X: 356 return KEY_X; 357 case kVK_ANSI_Y: 358 return KEY_Y; 359 case kVK_ANSI_Z: 360 return KEY_Z; 361 362 case kVK_ANSI_1: 363 return KEY_NUM1; 364 case kVK_ANSI_2: 365 return KEY_NUM2; 366 case kVK_ANSI_3: 367 return KEY_NUM3; 368 case kVK_ANSI_4: 369 return KEY_NUM4; 370 case kVK_ANSI_5: 371 return KEY_NUM5; 372 case kVK_ANSI_6: 373 return KEY_NUM6; 374 case kVK_ANSI_7: 375 return KEY_NUM7; 376 case kVK_ANSI_8: 377 return KEY_NUM8; 378 case kVK_ANSI_9: 379 return KEY_NUM9; 380 case kVK_ANSI_0: 381 return KEY_NUM0; 382 } 383 384 return Key(0); 385} 386 387static void AddNSKeyStateToEvent(Event *event, NSEventModifierFlags state) 388{ 389 event->Key.Shift = state & NSShiftKeyMask; 390 event->Key.Control = state & NSControlKeyMask; 391 event->Key.Alt = state & NSAlternateKeyMask; 392 event->Key.System = state & NSCommandKeyMask; 393} 394 395static MouseButton TranslateMouseButton(NSInteger button) 396{ 397 switch (button) 398 { 399 case 2: 400 return MOUSEBUTTON_MIDDLE; 401 case 3: 402 return MOUSEBUTTON_BUTTON4; 403 case 4: 404 return MOUSEBUTTON_BUTTON5; 405 default: 406 return MOUSEBUTTON_UNKNOWN; 407 } 408} 409 410// Delegate for NSView events, mostly the input events 411@implementation ContentView 412- (id)initWithWindow:(OSXWindow *)window 413{ 414 self = [super init]; 415 if (self != nil) 416 { 417 mWindow = window; 418 mTrackingArea = nil; 419 mCurrentModifier = 0; 420 [self updateTrackingAreas]; 421 } 422 return self; 423} 424 425- (void)dealloc 426{ 427 [mTrackingArea release]; 428 [super dealloc]; 429} 430 431- (void)updateTrackingAreas 432{ 433 if (mTrackingArea != nil) 434 { 435 [self removeTrackingArea:mTrackingArea]; 436 [mTrackingArea release]; 437 mTrackingArea = nil; 438 } 439 440 NSRect bounds = [self bounds]; 441 NSTrackingAreaOptions flags = NSTrackingMouseEnteredAndExited | NSTrackingActiveInKeyWindow | 442 NSTrackingCursorUpdate | NSTrackingInVisibleRect | 443 NSTrackingAssumeInside; 444 mTrackingArea = [[NSTrackingArea alloc] initWithRect:bounds 445 options:flags 446 owner:self 447 userInfo:nil]; 448 449 [self addTrackingArea:mTrackingArea]; 450 [super updateTrackingAreas]; 451} 452 453// Helps with performance 454- (BOOL)isOpaque 455{ 456 return YES; 457} 458 459- (BOOL)canBecomeKeyView 460{ 461 return YES; 462} 463 464- (BOOL)acceptsFirstResponder 465{ 466 return YES; 467} 468 469// Handle mouse events from the NSResponder protocol 470- (float)translateMouseY:(float)y 471{ 472 return [self frame].size.height - y; 473} 474 475- (void)addButtonEvent:(NSEvent *)nsEvent 476 type:(Event::EventType)eventType 477 button:(MouseButton)button 478{ 479 Event event; 480 event.Type = eventType; 481 event.MouseButton.Button = button; 482 event.MouseButton.X = (int)[nsEvent locationInWindow].x; 483 event.MouseButton.Y = (int)[self translateMouseY:[nsEvent locationInWindow].y]; 484 mWindow->pushEvent(event); 485} 486 487- (void)mouseDown:(NSEvent *)event 488{ 489 [self addButtonEvent:event type:Event::EVENT_MOUSE_BUTTON_PRESSED button:MOUSEBUTTON_LEFT]; 490} 491 492- (void)mouseDragged:(NSEvent *)event 493{ 494 [self mouseMoved:event]; 495} 496 497- (void)mouseUp:(NSEvent *)event 498{ 499 [self addButtonEvent:event type:Event::EVENT_MOUSE_BUTTON_RELEASED button:MOUSEBUTTON_LEFT]; 500} 501 502- (void)mouseMoved:(NSEvent *)nsEvent 503{ 504 Event event; 505 event.Type = Event::EVENT_MOUSE_MOVED; 506 event.MouseMove.X = (int)[nsEvent locationInWindow].x; 507 event.MouseMove.Y = (int)[self translateMouseY:[nsEvent locationInWindow].y]; 508 mWindow->pushEvent(event); 509} 510 511- (void)mouseEntered:(NSEvent *)nsEvent 512{ 513 Event event; 514 event.Type = Event::EVENT_MOUSE_ENTERED; 515 mWindow->pushEvent(event); 516} 517 518- (void)mouseExited:(NSEvent *)nsEvent 519{ 520 Event event; 521 event.Type = Event::EVENT_MOUSE_LEFT; 522 mWindow->pushEvent(event); 523} 524 525- (void)rightMouseDown:(NSEvent *)event 526{ 527 [self addButtonEvent:event type:Event::EVENT_MOUSE_BUTTON_PRESSED button:MOUSEBUTTON_RIGHT]; 528} 529 530- (void)rightMouseDragged:(NSEvent *)event 531{ 532 [self mouseMoved:event]; 533} 534 535- (void)rightMouseUp:(NSEvent *)event 536{ 537 [self addButtonEvent:event type:Event::EVENT_MOUSE_BUTTON_RELEASED button:MOUSEBUTTON_RIGHT]; 538} 539 540- (void)otherMouseDown:(NSEvent *)event 541{ 542 [self addButtonEvent:event 543 type:Event::EVENT_MOUSE_BUTTON_PRESSED 544 button:TranslateMouseButton([event buttonNumber])]; 545} 546 547- (void)otherMouseDragged:(NSEvent *)event 548{ 549 [self mouseMoved:event]; 550} 551 552- (void)otherMouseUp:(NSEvent *)event 553{ 554 [self addButtonEvent:event 555 type:Event::EVENT_MOUSE_BUTTON_RELEASED 556 button:TranslateMouseButton([event buttonNumber])]; 557} 558 559- (void)scrollWheel:(NSEvent *)nsEvent 560{ 561 if (static_cast<int>([nsEvent deltaY]) == 0) 562 { 563 return; 564 } 565 566 Event event; 567 event.Type = Event::EVENT_MOUSE_WHEEL_MOVED; 568 event.MouseWheel.Delta = (int)[nsEvent deltaY]; 569 mWindow->pushEvent(event); 570} 571 572// Handle key events from the NSResponder protocol 573- (void)keyDown:(NSEvent *)nsEvent 574{ 575 // TODO(cwallez) also send text events 576 Event event; 577 event.Type = Event::EVENT_KEY_PRESSED; 578 event.Key.Code = NSCodeToKey([nsEvent keyCode]); 579 AddNSKeyStateToEvent(&event, [nsEvent modifierFlags]); 580 mWindow->pushEvent(event); 581} 582 583- (void)keyUp:(NSEvent *)nsEvent 584{ 585 Event event; 586 event.Type = Event::EVENT_KEY_RELEASED; 587 event.Key.Code = NSCodeToKey([nsEvent keyCode]); 588 AddNSKeyStateToEvent(&event, [nsEvent modifierFlags]); 589 mWindow->pushEvent(event); 590} 591 592// Modifier keys do not trigger keyUp/Down events but only flagsChanged events. 593- (void)flagsChanged:(NSEvent *)nsEvent 594{ 595 Event event; 596 597 // Guess if the key has been pressed or released with the change of modifiers 598 // It currently doesn't work when modifiers are unchanged, such as when pressing 599 // both shift keys. GLFW has a solution for this but it requires tracking the 600 // state of the keys. Implementing this is still TODO(cwallez) 601 int modifier = [nsEvent modifierFlags] & NSDeviceIndependentModifierFlagsMask; 602 if (modifier < mCurrentModifier) 603 { 604 event.Type = Event::EVENT_KEY_RELEASED; 605 } 606 else 607 { 608 event.Type = Event::EVENT_KEY_PRESSED; 609 } 610 mCurrentModifier = modifier; 611 612 event.Key.Code = NSCodeToKey([nsEvent keyCode]); 613 AddNSKeyStateToEvent(&event, [nsEvent modifierFlags]); 614 mWindow->pushEvent(event); 615} 616@end 617 618OSXWindow::OSXWindow() : mWindow(nil), mDelegate(nil), mView(nil) {} 619 620OSXWindow::~OSXWindow() 621{ 622 destroy(); 623} 624 625bool OSXWindow::initializeImpl(const std::string &name, int width, int height) 626{ 627 if (!InitializeAppKit()) 628 { 629 return false; 630 } 631 632 unsigned int styleMask = NSTitledWindowMask | NSClosableWindowMask | NSResizableWindowMask | 633 NSMiniaturizableWindowMask; 634 mWindow = [[NSWindow alloc] initWithContentRect:NSMakeRect(0, 0, width, height) 635 styleMask:styleMask 636 backing:NSBackingStoreBuffered 637 defer:NO]; 638 639 if (mWindow == nil) 640 { 641 return false; 642 } 643 644 mDelegate = [[WindowDelegate alloc] initWithWindow:this]; 645 if (mDelegate == nil) 646 { 647 return false; 648 } 649 [mWindow setDelegate:static_cast<id>(mDelegate)]; 650 651 mView = [[ContentView alloc] initWithWindow:this]; 652 if (mView == nil) 653 { 654 return false; 655 } 656 [mView setWantsLayer:YES]; 657 658 // Disable scaling for this view. If scaling is enabled, the metal backend's 659 // frame buffer's size will be this window's size multiplied by contentScale. 660 // It will cause inconsistent testing & example apps' results. 661 mView.layer.contentsScale = 1; 662 663 [mWindow setContentView:mView]; 664 [mWindow setTitle:[NSString stringWithUTF8String:name.c_str()]]; 665 [mWindow setAcceptsMouseMovedEvents:YES]; 666 [mWindow center]; 667 668 [NSApp activateIgnoringOtherApps:YES]; 669 670 mX = 0; 671 mY = 0; 672 mWidth = width; 673 mHeight = height; 674 675 AllWindows().insert(this); 676 return true; 677} 678 679void OSXWindow::disableErrorMessageDialog() {} 680 681void OSXWindow::destroy() 682{ 683 AllWindows().erase(this); 684 685 [mView release]; 686 mView = nil; 687 [mDelegate onOSXWindowDeleted]; 688 [mDelegate release]; 689 mDelegate = nil; 690 // NSWindow won't be completely released unless its content view is set to nil: 691 [mWindow setContentView:nil]; 692 [mWindow release]; 693 mWindow = nil; 694} 695 696void OSXWindow::resetNativeWindow() {} 697 698EGLNativeWindowType OSXWindow::getNativeWindow() const 699{ 700 return [mView layer]; 701} 702 703EGLNativeDisplayType OSXWindow::getNativeDisplay() const 704{ 705 // TODO(cwallez): implement it once we have defined what EGLNativeDisplayType is 706 return static_cast<EGLNativeDisplayType>(0); 707} 708 709void OSXWindow::messageLoop() 710{ 711 @autoreleasepool 712 { 713 while (true) 714 { 715 NSEvent *event = [NSApp nextEventMatchingMask:NSAnyEventMask 716 untilDate:[NSDate distantPast] 717 inMode:NSDefaultRunLoopMode 718 dequeue:YES]; 719 if (event == nil) 720 { 721 break; 722 } 723 724 if ([event type] == NSAppKitDefined) 725 { 726 continue; 727 } 728 [NSApp sendEvent:event]; 729 } 730 } 731} 732 733void OSXWindow::setMousePosition(int x, int y) 734{ 735 y = (int)([mWindow frame].size.height) - y - 1; 736 NSPoint screenspace; 737 738#if MAC_OS_X_VERSION_MIN_REQUIRED < MAC_OS_X_VERSION_10_7 739 screenspace = [mWindow convertBaseToScreen:NSMakePoint(x, y)]; 740#else 741 screenspace = [mWindow convertRectToScreen:NSMakeRect(x, y, 0, 0)].origin; 742#endif 743 CGWarpMouseCursorPosition(CGPointMake(screenspace.x, YCoordToFromCG(screenspace.y))); 744} 745 746bool OSXWindow::setOrientation(int width, int height) 747{ 748 UNIMPLEMENTED(); 749 return false; 750} 751 752bool OSXWindow::setPosition(int x, int y) 753{ 754 // Given CG and NS's coordinate system, the "Y" position of a window is the Y coordinate 755 // of the bottom of the window. 756 int newBottom = (int)([mWindow frame].size.height) + y; 757 NSRect emptyRect = NSMakeRect(x, YCoordToFromCG(newBottom), 0, 0); 758 [mWindow setFrameOrigin:[mWindow frameRectForContentRect:emptyRect].origin]; 759 return true; 760} 761 762bool OSXWindow::resize(int width, int height) 763{ 764 [mWindow setContentSize:NSMakeSize(width, height)]; 765 return true; 766} 767 768void OSXWindow::setVisible(bool isVisible) 769{ 770 if (isVisible) 771 { 772 [mWindow makeKeyAndOrderFront:nil]; 773 } 774 else 775 { 776 [mWindow orderOut:nil]; 777 } 778} 779 780void OSXWindow::signalTestEvent() 781{ 782 @autoreleasepool 783 { 784 NSEvent *event = [NSEvent otherEventWithType:NSApplicationDefined 785 location:NSMakePoint(0, 0) 786 modifierFlags:0 787 timestamp:0.0 788 windowNumber:[mWindow windowNumber] 789 context:nil 790 subtype:0 791 data1:0 792 data2:0]; 793 [NSApp postEvent:event atStart:YES]; 794 } 795} 796 797NSWindow *OSXWindow::getNSWindow() const 798{ 799 return mWindow; 800} 801 802// static 803OSWindow *OSWindow::New() 804{ 805 return new OSXWindow; 806} 807