1# ---------------------------------------------------------------------------- 2# pyglet 3# Copyright (c) 2006-2008 Alex Holkner 4# Copyright (c) 2008-2021 pyglet contributors 5# All rights reserved. 6# 7# Redistribution and use in source and binary forms, with or without 8# modification, are permitted provided that the following conditions 9# are met: 10# 11# * Redistributions of source code must retain the above copyright 12# notice, this list of conditions and the following disclaimer. 13# * Redistributions in binary form must reproduce the above copyright 14# notice, this list of conditions and the following disclaimer in 15# the documentation and/or other materials provided with the 16# distribution. 17# * Neither the name of pyglet nor the names of its 18# contributors may be used to endorse or promote products 19# derived from this software without specific prior written 20# permission. 21# 22# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 23# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 24# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 25# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE 26# COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, 27# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 28# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 29# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 30# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 31# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN 32# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 33# POSSIBILITY OF SUCH DAMAGE. 34# ---------------------------------------------------------------------------- 35 36from ctypes import * 37 38import pyglet 39from pyglet import gl 40from pyglet.window import BaseWindow, WindowException 41from pyglet.window import MouseCursor, DefaultMouseCursor 42from pyglet.event import EventDispatcher 43 44from pyglet.canvas.cocoa import CocoaCanvas 45 46from pyglet.libs.darwin import cocoapy, CGPoint 47 48from .systemcursor import SystemCursor 49from .pyglet_delegate import PygletDelegate 50from .pyglet_textview import PygletTextView 51from .pyglet_window import PygletWindow, PygletToolWindow 52from .pyglet_view import PygletView 53 54NSApplication = cocoapy.ObjCClass('NSApplication') 55NSCursor = cocoapy.ObjCClass('NSCursor') 56NSAutoreleasePool = cocoapy.ObjCClass('NSAutoreleasePool') 57NSColor = cocoapy.ObjCClass('NSColor') 58NSEvent = cocoapy.ObjCClass('NSEvent') 59NSImage = cocoapy.ObjCClass('NSImage') 60 61quartz = cocoapy.quartz 62cf = cocoapy.cf 63 64 65class CocoaMouseCursor(MouseCursor): 66 gl_drawable = False 67 68 def __init__(self, cursorName): 69 # cursorName is a string identifying one of the named default NSCursors 70 # e.g. 'pointingHandCursor', and can be sent as message to NSCursor class. 71 self.cursorName = cursorName 72 73 def set(self): 74 cursor = getattr(NSCursor, self.cursorName)() 75 cursor.set() 76 77 78class CocoaWindow(BaseWindow): 79 80 # NSWindow instance. 81 _nswindow = None 82 83 # Delegate object. 84 _delegate = None 85 86 # Window properties 87 _minimum_size = None 88 _maximum_size = None 89 90 _is_mouse_exclusive = False 91 _mouse_platform_visible = True 92 _mouse_ignore_motion = False 93 94 _is_keyboard_exclusive = False 95 96 # Flag set during close() method. 97 _was_closed = False 98 99 # NSWindow style masks. 100 _style_masks = { 101 BaseWindow.WINDOW_STYLE_DEFAULT: cocoapy.NSTitledWindowMask | 102 cocoapy.NSClosableWindowMask | 103 cocoapy.NSMiniaturizableWindowMask, 104 BaseWindow.WINDOW_STYLE_DIALOG: cocoapy.NSTitledWindowMask | 105 cocoapy.NSClosableWindowMask, 106 BaseWindow.WINDOW_STYLE_TOOL: cocoapy.NSTitledWindowMask | 107 cocoapy.NSClosableWindowMask | 108 cocoapy.NSUtilityWindowMask, 109 BaseWindow.WINDOW_STYLE_BORDERLESS: cocoapy.NSBorderlessWindowMask, 110 } 111 112 def _recreate(self, changes): 113 if 'context' in changes: 114 self.context.set_current() 115 116 if 'fullscreen' in changes: 117 if not self._fullscreen: # leaving fullscreen 118 self.screen.release_display() 119 120 self._create() 121 122 def _create(self): 123 # Create a temporary autorelease pool for this method. 124 pool = NSAutoreleasePool.alloc().init() 125 126 if self._nswindow: 127 # The window is about the be recreated so destroy everything 128 # associated with the old window, then destroy the window itself. 129 nsview = self.canvas.nsview 130 self.canvas = None 131 self._nswindow.orderOut_(None) 132 self._nswindow.close() 133 self.context.detach() 134 self._nswindow.release() 135 self._nswindow = None 136 nsview.release() 137 self._delegate.release() 138 self._delegate = None 139 140 # Determine window parameters. 141 content_rect = cocoapy.NSMakeRect(0, 0, self._width, self._height) 142 WindowClass = PygletWindow 143 if self._fullscreen: 144 style_mask = cocoapy.NSBorderlessWindowMask 145 else: 146 if self._style not in self._style_masks: 147 self._style = self.WINDOW_STYLE_DEFAULT 148 style_mask = self._style_masks[self._style] 149 if self._resizable: 150 style_mask |= cocoapy.NSResizableWindowMask 151 if self._style == BaseWindow.WINDOW_STYLE_TOOL: 152 WindowClass = PygletToolWindow 153 154 # First create an instance of our NSWindow subclass. 155 156 # FIX ME: 157 # Need to use this initializer to have any hope of multi-monitor support. 158 # But currently causes problems on Mac OS X Lion. So for now, we initialize the 159 # window without including screen information. 160 # 161 # self._nswindow = WindowClass.alloc().initWithContentRect_styleMask_backing_defer_screen_( 162 # content_rect, # contentRect 163 # style_mask, # styleMask 164 # NSBackingStoreBuffered, # backing 165 # False, # defer 166 # self.screen.get_nsscreen()) # screen 167 168 self._nswindow = WindowClass.alloc().initWithContentRect_styleMask_backing_defer_( 169 content_rect, # contentRect 170 style_mask, # styleMask 171 cocoapy.NSBackingStoreBuffered, # backing 172 False) # defer 173 174 if self._fullscreen: 175 # BUG: I suspect that this doesn't do the right thing when using 176 # multiple monitors (which would be to go fullscreen on the monitor 177 # where the window is located). However I've no way to test. 178 blackColor = NSColor.blackColor() 179 self._nswindow.setBackgroundColor_(blackColor) 180 self._nswindow.setOpaque_(True) 181 self.screen.capture_display() 182 self._nswindow.setLevel_(quartz.CGShieldingWindowLevel()) 183 self.context.set_full_screen() 184 self._center_window() 185 self._mouse_in_window = True 186 else: 187 self._set_nice_window_location() 188 self._mouse_in_window = self._mouse_in_content_rect() 189 190 # Then create a view and set it as our NSWindow's content view. 191 self._nsview = PygletView.alloc().initWithFrame_cocoaWindow_(content_rect, self) 192 self._nswindow.setContentView_(self._nsview) 193 self._nswindow.makeFirstResponder_(self._nsview) 194 195 # Create a canvas with the view as its drawable and attach context to it. 196 self.canvas = CocoaCanvas(self.display, self.screen, self._nsview) 197 self.context.attach(self.canvas) 198 199 # Configure the window. 200 self._nswindow.setAcceptsMouseMovedEvents_(True) 201 self._nswindow.setReleasedWhenClosed_(False) 202 self._nswindow.useOptimizedDrawing_(True) 203 self._nswindow.setPreservesContentDuringLiveResize_(False) 204 205 # Set the delegate. 206 self._delegate = PygletDelegate.alloc().initWithWindow_(self) 207 208 # Configure CocoaWindow. 209 self.set_caption(self._caption) 210 if self._minimum_size is not None: 211 self.set_minimum_size(*self._minimum_size) 212 if self._maximum_size is not None: 213 self.set_maximum_size(*self._maximum_size) 214 215 # TODO: Add support for file drops. 216 if self._file_drops: 217 raise NotImplementedError("File drops are not implemented on MacOS") 218 219 self.context.update_geometry() 220 self.switch_to() 221 self.set_vsync(self._vsync) 222 self.set_visible(self._visible) 223 224 pool.drain() 225 226 def _set_nice_window_location(self): 227 # Construct a list of all visible windows that aren't us. 228 visible_windows = [win for win in pyglet.app.windows if 229 win is not self and 230 win._nswindow and 231 win._nswindow.isVisible()] 232 # If there aren't any visible windows, then center this window. 233 if not visible_windows: 234 self._center_window() 235 # Otherwise, cascade from last window in list. 236 else: 237 point = visible_windows[-1]._nswindow.cascadeTopLeftFromPoint_(cocoapy.NSZeroPoint) 238 self._nswindow.cascadeTopLeftFromPoint_(point) 239 240 def _center_window(self): 241 # [NSWindow center] does not move the window to a true center position 242 # and also always moves the window to the main display. 243 x = self.screen.x + int((self.screen.width - self._width) // 2) 244 y = self.screen.y + int((self.screen.height - self._height) // 2) 245 self._nswindow.setFrameOrigin_(cocoapy.NSPoint(x, y)) 246 247 def close(self): 248 # If we've already gone through this once, don't do it again. 249 if self._was_closed: 250 return 251 252 # Create a temporary autorelease pool for this method. 253 pool = NSAutoreleasePool.new() 254 255 # Restore cursor visibility 256 self.set_mouse_platform_visible(True) 257 self.set_exclusive_mouse(False) 258 self.set_exclusive_keyboard(False) 259 260 # Remove the delegate object 261 if self._delegate: 262 self._nswindow.setDelegate_(None) 263 self._delegate.release() 264 self._delegate = None 265 266 # Remove window from display and remove its view. 267 if self._nswindow: 268 self._nswindow.orderOut_(None) 269 self._nswindow.setContentView_(None) 270 self._nswindow.close() 271 272 # Restore screen mode. This also releases the display 273 # if it was captured for fullscreen mode. 274 self.screen.restore_mode() 275 276 # Remove view from canvas and then remove canvas. 277 if self.canvas: 278 self.canvas.nsview.release() 279 self.canvas.nsview = None 280 self.canvas = None 281 282 # Do this last, so that we don't see white flash 283 # when exiting application from fullscreen mode. 284 super(CocoaWindow, self).close() 285 286 self._was_closed = True 287 pool.drain() 288 289 def switch_to(self): 290 if self.context: 291 self.context.set_current() 292 293 def flip(self): 294 self.draw_mouse_cursor() 295 if self.context: 296 self.context.flip() 297 298 def dispatch_events(self): 299 self._allow_dispatch_event = True 300 # Process all pyglet events. 301 self.dispatch_pending_events() 302 event = True 303 304 # Dequeue and process all of the pending Cocoa events. 305 pool = NSAutoreleasePool.new() 306 NSApp = NSApplication.sharedApplication() 307 while event and self._nswindow and self._context: 308 event = NSApp.nextEventMatchingMask_untilDate_inMode_dequeue_( 309 cocoapy.NSAnyEventMask, None, cocoapy.NSEventTrackingRunLoopMode, True) 310 311 if event: 312 event_type = event.type() 313 # Pass on all events. 314 NSApp.sendEvent_(event) 315 # And resend key events to special handlers. 316 if event_type == cocoapy.NSKeyDown and not event.isARepeat(): 317 NSApp.sendAction_to_from_(cocoapy.get_selector('pygletKeyDown:'), None, event) 318 elif event_type == cocoapy.NSKeyUp: 319 NSApp.sendAction_to_from_(cocoapy.get_selector('pygletKeyUp:'), None, event) 320 elif event_type == cocoapy.NSFlagsChanged: 321 NSApp.sendAction_to_from_(cocoapy.get_selector('pygletFlagsChanged:'), None, event) 322 NSApp.updateWindows() 323 324 pool.drain() 325 326 self._allow_dispatch_event = False 327 328 def dispatch_pending_events(self): 329 while self._event_queue: 330 event = self._event_queue.pop(0) 331 EventDispatcher.dispatch_event(self, *event) 332 333 def set_caption(self, caption): 334 self._caption = caption 335 if self._nswindow is not None: 336 self._nswindow.setTitle_(cocoapy.get_NSString(caption)) 337 338 def set_icon(self, *images): 339 # Only use the biggest image from the list. 340 max_image = images[0] 341 for img in images: 342 if img.width > max_image.width and img.height > max_image.height: 343 max_image = img 344 345 # Grab image data from pyglet image. 346 image = max_image.get_image_data() 347 format = 'ARGB' 348 bytesPerRow = len(format) * image.width 349 data = image.get_data(format, -bytesPerRow) 350 351 # Use image data to create a data provider. 352 # Using CGDataProviderCreateWithData crashes PyObjC 2.2b3, so we create 353 # a CFDataRef object first and use it to create the data provider. 354 cfdata = c_void_p(cf.CFDataCreate(None, data, len(data))) 355 provider = c_void_p(quartz.CGDataProviderCreateWithCFData(cfdata)) 356 357 colorSpace = c_void_p(quartz.CGColorSpaceCreateDeviceRGB()) 358 359 # Then create a CGImage from the provider. 360 cgimage = c_void_p(quartz.CGImageCreate( 361 image.width, image.height, 8, 32, bytesPerRow, 362 colorSpace, 363 cocoapy.kCGImageAlphaFirst, 364 provider, 365 None, 366 True, 367 cocoapy.kCGRenderingIntentDefault)) 368 369 if not cgimage: 370 return 371 372 cf.CFRelease(cfdata) 373 quartz.CGDataProviderRelease(provider) 374 quartz.CGColorSpaceRelease(colorSpace) 375 376 # Turn the CGImage into an NSImage. 377 size = cocoapy.NSMakeSize(image.width, image.height) 378 nsimage = NSImage.alloc().initWithCGImage_size_(cgimage, size) 379 if not nsimage: 380 return 381 382 # And finally set the app icon. 383 NSApp = NSApplication.sharedApplication() 384 NSApp.setApplicationIconImage_(nsimage) 385 nsimage.release() 386 387 def get_location(self): 388 window_frame = self._nswindow.frame() 389 rect = self._nswindow.contentRectForFrameRect_(window_frame) 390 screen_frame = self._nswindow.screen().frame() 391 screen_width = int(screen_frame.size.width) 392 screen_height = int(screen_frame.size.height) 393 return int(rect.origin.x), int(screen_height - rect.origin.y - rect.size.height) 394 395 def set_location(self, x, y): 396 window_frame = self._nswindow.frame() 397 rect = self._nswindow.contentRectForFrameRect_(window_frame) 398 screen_frame = self._nswindow.screen().frame() 399 screen_width = int(screen_frame.size.width) 400 screen_height = int(screen_frame.size.height) 401 origin = cocoapy.NSPoint(x, screen_height - y - rect.size.height) 402 self._nswindow.setFrameOrigin_(origin) 403 404 def get_size(self): 405 window_frame = self._nswindow.frame() 406 rect = self._nswindow.contentRectForFrameRect_(window_frame) 407 return int(rect.size.width), int(rect.size.height) 408 409 def get_framebuffer_size(self): 410 view = self.context._nscontext.view() 411 bounds = view.convertRectToBacking_(view.bounds()).size 412 return int(bounds.width), int(bounds.height) 413 414 # :deprecated: Use Window.get_framebuffer_size 415 get_viewport_size = get_framebuffer_size 416 417 def set_size(self, width, height): 418 if self._fullscreen: 419 raise WindowException('Cannot set size of fullscreen window.') 420 self._width = max(1, int(width)) 421 self._height = max(1, int(height)) 422 # Move frame origin down so that top-left corner of window doesn't move. 423 window_frame = self._nswindow.frame() 424 rect = self._nswindow.contentRectForFrameRect_(window_frame) 425 rect.origin.y += rect.size.height - self._height 426 rect.size.width = self._width 427 rect.size.height = self._height 428 new_frame = self._nswindow.frameRectForContentRect_(rect) 429 # The window background flashes when the frame size changes unless it's 430 # animated, but we can set the window's animationResizeTime to zero. 431 is_visible = self._nswindow.isVisible() 432 self._nswindow.setFrame_display_animate_(new_frame, True, is_visible) 433 434 def set_minimum_size(self, width, height): 435 self._minimum_size = cocoapy.NSSize(width, height) 436 437 if self._nswindow is not None: 438 self._nswindow.setContentMinSize_(self._minimum_size) 439 440 def set_maximum_size(self, width, height): 441 self._maximum_size = cocoapy.NSSize(width, height) 442 443 if self._nswindow is not None: 444 self._nswindow.setContentMaxSize_(self._maximum_size) 445 446 def activate(self): 447 if self._nswindow is not None: 448 NSApp = NSApplication.sharedApplication() 449 NSApp.activateIgnoringOtherApps_(True) 450 self._nswindow.makeKeyAndOrderFront_(None) 451 452 def set_visible(self, visible=True): 453 self._visible = visible 454 if self._nswindow is not None: 455 if visible: 456 # Not really sure why on_resize needs to be here, 457 # but it's what pyglet wants. 458 self.dispatch_event('on_resize', self._width, self._height) 459 self.dispatch_event('on_show') 460 self.dispatch_event('on_expose') 461 self._nswindow.makeKeyAndOrderFront_(None) 462 else: 463 self._nswindow.orderOut_(None) 464 465 def minimize(self): 466 self._mouse_in_window = False 467 if self._nswindow is not None: 468 self._nswindow.miniaturize_(None) 469 470 def maximize(self): 471 if self._nswindow is not None: 472 self._nswindow.zoom_(None) 473 474 def set_vsync(self, vsync): 475 if pyglet.options['vsync'] is not None: 476 vsync = pyglet.options['vsync'] 477 self._vsync = vsync # _recreate depends on this 478 if self.context: 479 self.context.set_vsync(vsync) 480 481 def _mouse_in_content_rect(self): 482 # Returns true if mouse is inside the window's content rectangle. 483 # Better to use this method to check manually rather than relying 484 # on instance variables that may not be set correctly. 485 point = NSEvent.mouseLocation() 486 window_frame = self._nswindow.frame() 487 rect = self._nswindow.contentRectForFrameRect_(window_frame) 488 return cocoapy.foundation.NSMouseInRect(point, rect, False) 489 490 def set_mouse_platform_visible(self, platform_visible=None): 491 # When the platform_visible argument is supplied with a boolean, then this 492 # method simply sets whether or not the platform mouse cursor is visible. 493 if platform_visible is not None: 494 if platform_visible: 495 SystemCursor.unhide() 496 else: 497 SystemCursor.hide() 498 # But if it has been called without an argument, it turns into 499 # a completely different function. Now we are trying to figure out 500 # whether or not the mouse *should* be visible, and if so, what it should 501 # look like. 502 else: 503 # If we are in mouse exclusive mode, then hide the mouse cursor. 504 if self._is_mouse_exclusive: 505 SystemCursor.hide() 506 # If we aren't inside the window, then always show the mouse 507 # and make sure that it is the default cursor. 508 elif not self._mouse_in_content_rect(): 509 NSCursor.arrowCursor().set() 510 SystemCursor.unhide() 511 # If we are in the window, then what we do depends on both 512 # the current pyglet-set visibility setting for the mouse and 513 # the type of the mouse cursor. If the cursor has been hidden 514 # in the window with set_mouse_visible() then don't show it. 515 elif not self._mouse_visible: 516 SystemCursor.hide() 517 # If the mouse is set as a system-defined cursor, then we 518 # need to set the cursor and show the mouse. 519 # *** FIX ME *** 520 elif isinstance(self._mouse_cursor, CocoaMouseCursor): 521 self._mouse_cursor.set() 522 SystemCursor.unhide() 523 # If the mouse cursor is OpenGL drawable, then it we need to hide 524 # the system mouse cursor, so that the cursor can draw itself. 525 elif self._mouse_cursor.gl_drawable: 526 SystemCursor.hide() 527 # Otherwise, show the default cursor. 528 else: 529 NSCursor.arrowCursor().set() 530 SystemCursor.unhide() 531 532 def get_system_mouse_cursor(self, name): 533 # It would make a lot more sense for most of this code to be 534 # inside the CocoaMouseCursor class, but all of the CURSOR_xxx 535 # constants are defined as properties of BaseWindow. 536 if name == self.CURSOR_DEFAULT: 537 return DefaultMouseCursor() 538 cursors = { 539 self.CURSOR_CROSSHAIR: 'crosshairCursor', 540 self.CURSOR_HAND: 'pointingHandCursor', 541 self.CURSOR_HELP: 'arrowCursor', 542 self.CURSOR_NO: 'operationNotAllowedCursor', # Mac OS 10.6 543 self.CURSOR_SIZE: 'arrowCursor', 544 self.CURSOR_SIZE_UP: 'resizeUpCursor', 545 self.CURSOR_SIZE_UP_RIGHT: 'arrowCursor', 546 self.CURSOR_SIZE_RIGHT: 'resizeRightCursor', 547 self.CURSOR_SIZE_DOWN_RIGHT: 'arrowCursor', 548 self.CURSOR_SIZE_DOWN: 'resizeDownCursor', 549 self.CURSOR_SIZE_DOWN_LEFT: 'arrowCursor', 550 self.CURSOR_SIZE_LEFT: 'resizeLeftCursor', 551 self.CURSOR_SIZE_UP_LEFT: 'arrowCursor', 552 self.CURSOR_SIZE_UP_DOWN: 'resizeUpDownCursor', 553 self.CURSOR_SIZE_LEFT_RIGHT: 'resizeLeftRightCursor', 554 self.CURSOR_TEXT: 'IBeamCursor', 555 self.CURSOR_WAIT: 'arrowCursor', # No wristwatch cursor in Cocoa 556 self.CURSOR_WAIT_ARROW: 'arrowCursor', # No wristwatch cursor in Cocoa 557 } 558 if name not in cursors: 559 raise RuntimeError('Unknown cursor name "%s"' % name) 560 return CocoaMouseCursor(cursors[name]) 561 562 def set_mouse_position(self, x, y, absolute=False): 563 if absolute: 564 # If absolute, then x, y is given in global display coordinates 565 # which sets (0,0) at top left corner of main display. It is possible 566 # to warp the mouse position to a point inside of another display. 567 quartz.CGWarpMouseCursorPosition(CGPoint(x,y)) 568 else: 569 # Window-relative coordinates: (x, y) are given in window coords 570 # with (0,0) at bottom-left corner of window and y up. We find 571 # which display the window is in and then convert x, y into local 572 # display coords where (0,0) is now top-left of display and y down. 573 screenInfo = self._nswindow.screen().deviceDescription() 574 displayID = screenInfo.objectForKey_(cocoapy.get_NSString('NSScreenNumber')) 575 displayID = displayID.intValue() 576 displayBounds = quartz.CGDisplayBounds(displayID) 577 frame = self._nswindow.frame() 578 windowOrigin = frame.origin 579 x += windowOrigin.x 580 y = displayBounds.size.height - windowOrigin.y - y 581 quartz.CGDisplayMoveCursorToPoint(displayID, cocoapy.NSPoint(x, y)) 582 583 def set_exclusive_mouse(self, exclusive=True): 584 self._is_mouse_exclusive = exclusive 585 if exclusive: 586 # Skip the next motion event, which would return a large delta. 587 self._mouse_ignore_motion = True 588 # Move mouse to center of window. 589 frame = self._nswindow.frame() 590 width, height = frame.size.width, frame.size.height 591 self.set_mouse_position(width/2, height/2) 592 quartz.CGAssociateMouseAndMouseCursorPosition(False) 593 else: 594 quartz.CGAssociateMouseAndMouseCursorPosition(True) 595 596 # Update visibility of mouse cursor. 597 self.set_mouse_platform_visible() 598 599 def set_exclusive_keyboard(self, exclusive=True): 600 # http://developer.apple.com/mac/library/technotes/tn2002/tn2062.html 601 # http://developer.apple.com/library/mac/#technotes/KioskMode/ 602 603 # BUG: System keys like F9 or command-tab are disabled, however 604 # pyglet also does not receive key press events for them. 605 606 # This flag is queried by window delegate to determine whether 607 # the quit menu item is active. 608 self._is_keyboard_exclusive = exclusive 609 610 if exclusive: 611 # "Be nice! Don't disable force-quit!" 612 # -- Patrick Swayze, Road House (1989) 613 options = cocoapy.NSApplicationPresentationHideDock | \ 614 cocoapy.NSApplicationPresentationHideMenuBar | \ 615 cocoapy.NSApplicationPresentationDisableProcessSwitching | \ 616 cocoapy.NSApplicationPresentationDisableHideApplication 617 else: 618 options = cocoapy.NSApplicationPresentationDefault 619 620 NSApp = NSApplication.sharedApplication() 621 NSApp.setPresentationOptions_(options) 622 623 624__all__ = ["CocoaWindow"] 625