a lot of improvements

This commit is contained in:
rdb 2012-06-07 07:52:56 +00:00
parent 24cdca64e7
commit b71bca5c49
11 changed files with 632 additions and 214 deletions

View File

@ -13,24 +13,24 @@
////////////////////////////////////////////////////////////////////
/*////////////////////////////////////////////////////////////////////
// Function: CocoaGraphicsPipe::get_display
// Access: Public
// Description: Returns a pointer to the X display associated with
// the pipe: the display on which to create the windows.
////////////////////////////////////////////////////////////////////
INLINE X11_Display *CocoaGraphicsPipe::
get_display() const {
// Function: CocoaGraphicsPipe::get_display_id
// Access: Public
// Description: Returns the Quartz display ID associated with
// this graphics pipe.
////////////////////////////////////////////////////////////////////
INLINE CGDirectDisplayID CocoaGraphicsPipe::
get_display_id() const {
return _display;
}
////////////////////////////////////////////////////////////////////
// Function: CocoaGraphicsPipe::get_screen
// Function: CocoaGraphicsPipe::get_nsscreen
// Access: Public
// Description: Returns the X screen number associated with the pipe.
// Description: Returns the Cocoa NSScreen pointer associated with
// this graphics pipe.
////////////////////////////////////////////////////////////////////
INLINE int CocoaGraphicsPipe::
get_screen() const {
INLINE NSScreen *CocoaGraphicsPipe::
get_nsscreen() const {
return _screen;
}
*/

View File

@ -39,6 +39,9 @@ public:
CocoaGraphicsPipe(NSScreen *screen);
virtual ~CocoaGraphicsPipe();
INLINE CGDirectDisplayID get_display_id() const;
INLINE NSScreen *get_nsscreen() const;
virtual string get_interface_name() const;
static PT(GraphicsPipe) pipe_constructor();

View File

@ -32,8 +32,6 @@ static void init_app() {
[NSApp setActivationPolicy:nil];
[NSApp finishLaunching];
[NSApp activateIgnoringOtherApps:YES];
//[pool release];
}
}

View File

@ -45,6 +45,7 @@ public:
FrameBufferProperties _fbprops;
protected:
virtual void query_gl_version();
virtual void *do_get_extension_func(const char *prefix, const char *name);
public:

View File

@ -176,7 +176,7 @@ choose_pixel_format(const FrameBufferProperties &properties,
}
if (need_window) {
//TODO: fullscreen != window on OSX
//TODO: when to request fullscreen on Cocoa?
attribs.push_back(NSOpenGLPFAWindow);
//attribs.push_back(NSOpenGLPFAFullScreen);
}
@ -217,6 +217,27 @@ choose_pixel_format(const FrameBufferProperties &properties,
<< "Created context " << _context << ": " << _fbprops << "\n";
}
////////////////////////////////////////////////////////////////////
// Function: CocoaGraphicsStateGuardian::query_gl_version
// Access: Protected, Virtual
// Description: Queries the runtime version of OpenGL in use.
////////////////////////////////////////////////////////////////////
void CocoaGraphicsStateGuardian::
query_gl_version() {
GLGraphicsStateGuardian::query_gl_version();
// We output to glgsg_cat instead of glxdisplay_cat, since this is
// where the GL version has been output, and it's nice to see the
// two of these together.
if (glgsg_cat.is_debug()) {
//GLint major, minor;
//NSOpenGLGetVersion(&major, &minor);
//glgsg_cat.debug()
// << "NSOpenGLVersion = " << major << "." << minor << "\n";
}
}
////////////////////////////////////////////////////////////////////
// Function: CocoaGraphicsStateGuardian::do_get_extension_func
// Access: Public, Virtual

View File

@ -66,6 +66,9 @@ protected:
virtual void close_window();
virtual bool open_window();
CGDisplayModeRef find_display_mode(int width, int height);
bool do_switch_fullscreen(CGDisplayModeRef mode);
virtual void mouse_mode_absolute();
virtual void mouse_mode_relative();
@ -80,7 +83,10 @@ private:
NSView *_view;
NSUInteger _modifier_keys;
CGDirectDisplayID _display;
CGDisplayModeRef _fullscreen_mode;
CGDisplayModeRef _windowed_mode;
bool _mouse_hidden;
bool _context_needs_update;
public:
static TypeHandle get_class_type() {

View File

@ -30,11 +30,14 @@
#import "cocoaPandaView.h"
#import "cocoaPandaWindow.h"
#import <ApplicationServices/ApplicationServices.h>
#import <Foundation/NSAutoreleasePool.h>
#import <AppKit/NSApplication.h>
#import <AppKit/NSCursor.h>
#import <AppKit/NSEvent.h>
#import <AppKit/NSScreen.h>
#import <OpenGL/OpenGL.h>
#import <Carbon/Carbon.h>
TypeHandle CocoaGraphicsWindow::_type_handle;
@ -57,6 +60,9 @@ CocoaGraphicsWindow(GraphicsEngine *engine, GraphicsPipe *pipe,
_view = nil;
_modifier_keys = 0;
_mouse_hidden = false;
_context_needs_update = true;
_fullscreen_mode = NULL;
_windowed_mode = NULL;
GraphicsWindowInputDevice device =
GraphicsWindowInputDevice::pointer_and_keyboard(this, "keyboard_mouse");
@ -126,11 +132,10 @@ begin_frame(FrameMode mode, Thread *current_thread) {
CocoaGraphicsStateGuardian *cocoagsg;
DCAST_INTO_R(cocoagsg, _gsg, false);
nassertr(cocoagsg->_context != nil, false);
nassertr(_view != nil, false);
// Let's not bother drawing to ta miniaturized window, eh?
if (_properties.get_minimized()) {
return false;
}
// Place a lock on the context.
CGLLockContext((CGLContextObj) [cocoagsg->_context CGLContextObj]);
// Set the drawable.
if (_properties.get_fullscreen()) {
@ -138,8 +143,20 @@ begin_frame(FrameMode mode, Thread *current_thread) {
[cocoagsg->_context setFullScreen];
} else {
nassertr([_view lockFocusIfCanDraw], false);
// Although not recommended, it is technically possible to
// use the same context with multiple different-sized windows.
// If that happens, the context needs to be updated accordingly.
if ([cocoagsg->_context view] != _view) {
_context_needs_update = true;
[cocoagsg->_context setView:_view];
}
}
// Update the context if necessary, to make it reallocate buffers etc.
if (_context_needs_update) {
[cocoagsg->_context update];
_context_needs_update = false;
}
// Make the context current.
[cocoagsg->_context makeCurrentContext];
@ -198,12 +215,6 @@ void CocoaGraphicsWindow::
end_flip() {
if (_gsg != (GraphicsStateGuardian *)NULL && _flip_ready) {
// It doesn't appear to be necessary to ensure the graphics
// context is current before flipping the windows, and insisting
// on doing so can be a significant performance hit.
//make_current();
CocoaGraphicsStateGuardian *cocoagsg;
DCAST_INTO_V(cocoagsg, _gsg);
@ -211,6 +222,9 @@ end_flip() {
if (!_properties.get_fullscreen()) {
[_view unlockFocus];
}
// Release the context.
CGLUnlockContext((CGLContextObj) [cocoagsg->_context CGLContextObj]);
}
GraphicsWindow::end_flip();
}
@ -313,9 +327,115 @@ open_window() {
_properties.set_cursor_hidden(false);
}
// Check if we have a parent view.
NSView *parent_nsview = nil;
HIViewRef parent_hiview = NULL;
_parent_window_handle = NULL;
WindowHandle *window_handle = _properties.get_parent_window();
if (window_handle != NULL) {
cocoadisplay_cat.info()
<< "Got parent_window " << *window_handle << "\n";
WindowHandle::OSHandle *os_handle = window_handle->get_os_handle();
if (os_handle != NULL) {
cocoadisplay_cat.info()
<< "os_handle type " << os_handle->get_type() << "\n";
void *ptr_handle;
// Depending on whether the window handle comes from a Carbon or a Cocoa
// application, it could be either a HIViewRef or an NSView or NSWindow.
// We try to find out which it is, and if it is a HIView, we use the
// HICocoaView functions to create a wrapper view to host our own Cocoa view.
if (os_handle->is_of_type(NativeWindowHandle::IntHandle::get_class_type())) {
NativeWindowHandle::IntHandle *int_handle = DCAST(NativeWindowHandle::IntHandle, os_handle);
ptr_handle = (void*) int_handle->get_handle();
}
if (ptr_handle != NULL) {
// Check if it is actually a valid Carbon ControlRef.
ControlRef control = (ControlRef)ptr_handle;
ControlKind kind;
if (IsValidControlHandle(control) &&
GetControlKind(control, &kind) == 0 &&
kind.signature == kControlKindSignatureApple) {
// Now verify that it is also a valid HIViewRef.
parent_hiview = (HIViewRef)control;
HIViewKind viewkind;
if (HIViewIsValid(parent_hiview) &&
HIViewGetKind(parent_hiview, &viewkind) == 0 &&
viewkind.signature == kHIViewKindSignatureApple) {
_parent_window_handle = window_handle;
cocoadisplay_cat.info()
<< "Parent window handle is a valid HIViewRef\n";
} else {
parent_hiview = NULL;
cocoadisplay_cat.error()
<< "Parent window handle is a valid ControlRef, but not a valid HIViewRef!\n";
return false;
}
} else {
// If it is not a Carbon ControlRef, perhaps it is a Cocoa NSView.
// Unfortunately, there's no reliable way to check if it is actually
// an NSObject in the first place, so this may crash - which is why
// this case is a last resort.
NSObject *nsobj = (NSObject *)ptr_handle;
if ([nsobj isKindOfClass:[NSView class]]) {
// Yep.
parent_nsview = (NSView *)nsobj;
_parent_window_handle = window_handle;
cocoadisplay_cat.info()
<< "Parent window handle is a valid NSView pointer\n";
} else {
cocoadisplay_cat.error()
<< "Parent window handle is not a valid HIViewRef or NSView pointer!\n";
return false;
}
}
}
}
}
// Center the window if coordinates were set to -1 or -2
NSRect container;
if (parent_nsview != NULL) {
container = [parent_nsview bounds];
} else if (parent_hiview != NULL) {
HIRect hirect;
HIViewGetBounds(parent_hiview, &hirect);
container = NSRectFromCGRect(hirect);
} else {
container = [cocoa_pipe->_screen frame];
container.origin = NSMakePoint(0, 0);
}
int x = _properties.get_x_origin();
int y = _properties.get_y_origin();
if (x < 0) {
x = floor(container.size.width / 2 - _properties.get_x_size() / 2);
}
if (y < 0) {
y = floor(container.size.height / 2 - _properties.get_y_size() / 2);
}
_properties.set_origin(x, y);
if (_parent_window_handle == (WindowHandle *)NULL) {
// Content rectangle
NSRect rect;
if (_properties.get_fullscreen()) {
rect = container;
} else {
rect = NSMakeRect(x, container.size.height - _properties.get_y_size() - y,
_properties.get_x_size(), _properties.get_y_size());
}
// Configure the window decorations
NSUInteger windowStyle;
if (_properties.get_undecorated()) {
if (_properties.get_undecorated() || _properties.get_fullscreen()) {
windowStyle = NSBorderlessWindowMask;
} else if (_properties.get_fixed_size()) {
// Fixed size windows should not show the resize button.
@ -326,29 +446,13 @@ open_window() {
NSMiniaturizableWindowMask | NSResizableWindowMask;
}
// Center the window if coordinates were set to -1 or -2
NSRect screenFrame = [cocoa_pipe->_screen frame];
int x = _properties.get_x_origin();
int y = _properties.get_y_origin();
if (x < 0) {
x = floor(screenFrame.size.width / 2 - _properties.get_x_size() / 2);
}
if (y < 0) {
y = floor(screenFrame.size.height / 2 - _properties.get_y_size() / 2);
}
_properties.set_origin(x, y);
// Content rectangle
NSRect rect = NSMakeRect(_properties.get_x_origin(),
screenFrame.size.height - _properties.get_y_origin(),
_properties.get_x_size(), _properties.get_y_size());
// Create the window.
if (cocoadisplay_cat.is_debug()) {
NSString *str = NSStringFromRect(rect);
cocoadisplay_cat.debug()
<< "Creating NSWindow with content rect " << [str UTF8String] << "\n";
}
_window = [[CocoaPandaWindow alloc]
initWithContentRect: rect
styleMask:windowStyle
@ -360,27 +464,68 @@ open_window() {
<< "Failed to create Cocoa window.\n";
return false;
}
}
// Lock the context, so we can safely operate on it.
CGLLockContext((CGLContextObj) [cocoagsg->_context CGLContextObj]);
// Create the NSView to render to.
NSRect rect = NSMakeRect(0, 0, _properties.get_x_size(), _properties.get_y_size());
_view = [[CocoaPandaView alloc] initWithFrame:rect context:cocoagsg->_context window:this];
if (_parent_window_handle == (WindowHandle *)NULL) {
[_window setContentView:_view];
[_window setReleasedWhenClosed:YES];
[_window makeFirstResponder:_view];
}
// Create a WindowHandle for ourselves
// I'd rather store a window number than an NSWindow pointer,
// but wxWidgets seems to use the NSWindow/NSView pointer approach,
// Check if we have a parent HIView to create a wrapper for.
if (parent_hiview != NULL) {
HIViewRef hiview;
if (HICocoaViewCreate(_view, 0, &hiview) == 0) {
cocoadisplay_cat.debug()
<< "Successfully created HICocoaView " << hiview << ".\n";
if (HIViewAddSubview(parent_hiview, hiview) != 0) {
cocoadisplay_cat.error()
<< "Failed to attach HICocoaView " << hiview
<< " to parent HIView " << parent_hiview << "!\n";
return false;
}
HIViewSetVisible(hiview, TRUE);
HIRect hirect;
HIViewGetBounds(parent_hiview, &hirect);
HIViewSetFrame(hiview, &hirect);
} else {
cocoadisplay_cat.error()
<< "Failed to create HICocoaView.\n";
}
}
// Check if we have an NSView to attach our NSView to.
if (parent_nsview != NULL) {
[parent_nsview addSubview:_view];
}
// Create a WindowHandle for ourselves.
// wxWidgets seems to use the NSView pointer approach,
// so let's do the same here.
_window_handle = NativeWindowHandle::make_int((size_t) _window);
_window_handle = NativeWindowHandle::make_int((size_t) _view);
// And tell our parent window that we're now its child.
if (_parent_window_handle != (WindowHandle *)NULL) {
_parent_window_handle->attach_child(_window_handle);
}
// Set the properties
if (_window != nil) {
if (_properties.has_title()) {
[_window setTitle: [NSString stringWithUTF8String: _properties.get_title().c_str()]];
}
[_window setShowsResizeIndicator: !_properties.get_fixed_size()];
if (_properties.get_minimized()) {
if (_properties.get_fullscreen()) {
[_window makeKeyAndOrderFront: nil];
} else if (_properties.get_minimized()) {
[_window makeKeyAndOrderFront: nil];
[_window miniaturize: nil];
} else if (_properties.get_foreground()) {
@ -389,8 +534,12 @@ open_window() {
[_window orderBack: nil];
}
if (_properties.get_fullscreen()) {
[_window setLevel: NSMainMenuWindowLevel + 1];
} else {
switch (_properties.get_z_order()) {
case WindowProperties::Z_bottom:
// Seems to work!
[_window setLevel: NSNormalWindowLevel - 1];
break;
@ -402,12 +551,36 @@ open_window() {
[_window setLevel: NSPopUpMenuWindowLevel];
break;
}
}
}
if (_properties.get_fullscreen()) {
// Change the display mode.
CGDisplayModeRef mode = find_display_mode(_properties.get_x_size(),
_properties.get_y_size());
if (mode == NULL) {
cocoadisplay_cat.error()
<< "Could not find a suitable display mode!\n";
return false;
} else if (!do_switch_fullscreen(mode)) {
cocoadisplay_cat.error()
<< "Failed to change display mode.\n";
return false;
}
}
// Make the context current.
_context_needs_update = false;
[cocoagsg->_context update];
[cocoagsg->_context makeCurrentContext];
cocoagsg->reset_if_new();
// Release the context.
CGLUnlockContext((CGLContextObj) [cocoagsg->_context CGLContextObj]);
if (!cocoagsg->is_valid()) {
close_window();
return false;
@ -420,11 +593,6 @@ open_window() {
}
_fb_properties = cocoagsg->get_fb_properties();
// And tell our parent window that we're now its child.
//if (_parent_window_handle != (WindowHandle *)NULL) {
// _parent_window_handle->attach_child(_window_handle);
//
//TODO: update initial mouse position in the case that
// the NSWindow delegate doesn't send the make key event, ie
// if setParentWindow was used.
@ -437,10 +605,6 @@ open_window() {
mouse_mode_relative();
}
if (_properties.get_fullscreen() && !_properties.get_minimized()) {
CGDisplayCapture(_display);
}
return true;
}
@ -462,7 +626,9 @@ close_window() {
cocoagsg = DCAST(CocoaGraphicsStateGuardian, _gsg);
if (cocoagsg != NULL && cocoagsg->_context != nil) {
CGLLockContext((CGLContextObj) [cocoagsg->_context CGLContextObj]);
[cocoagsg->_context clearDrawable];
CGLUnlockContext((CGLContextObj) [cocoagsg->_context CGLContextObj]);
}
_gsg.clear();
}
@ -532,94 +698,161 @@ set_properties_now(WindowProperties &properties) {
return;
}
// The window is already open; we are limited to what we can change
// on the fly.
if (properties.has_fullscreen()) {
if (_properties.get_fullscreen() != properties.get_fullscreen()) {
if (properties.get_fullscreen()) {
int width, height;
if (properties.has_size()) {
width = properties.get_x_size();
height = properties.get_y_size();
} else {
width = _properties.get_x_size();
height = _properties.get_y_size();
}
if (properties.has_minimized()) {
CGDisplayModeRef mode = find_display_mode(width, height);
if (mode == NULL) {
cocoadisplay_cat.error()
<< "Could not find a suitable display mode with size " << width
<< "x" << height << "!\n";
} else if (do_switch_fullscreen(mode)) {
if (_window != nil) {
// For some reason, setting the style mask
// makes it give up its first-responder status.
[_window setStyleMask:NSBorderlessWindowMask];
[_window makeFirstResponder:_view];
[_window setLevel:NSMainMenuWindowLevel+1];
[_window makeKeyAndOrderFront:nil];
}
// We've already set the size property this way; clear it.
properties.clear_size();
_properties.set_size(width, height);
properties.clear_origin();
_properties.set_origin(0, 0);
properties.clear_fullscreen();
_properties.set_fullscreen(true);
} else {
cocoadisplay_cat.error()
<< "Failed to change display mode.\n";
}
} else {
do_switch_fullscreen(NULL);
_properties.set_fullscreen(false);
// Force properties to be reset to their actual values
properties.set_undecorated(_properties.get_undecorated());
properties.set_z_order(_properties.get_z_order());
properties.clear_fullscreen();
}
}
_context_needs_update = true;
}
if (properties.has_minimized() && !_properties.get_fullscreen() && _window != nil) {
_properties.set_minimized(properties.get_minimized());
if (properties.get_minimized()) {
[_window miniaturize:nil];
} else {
[_window deminiaturize:nil];
}
if (_properties.get_fullscreen()) {
if (properties.get_minimized()) {
CGDisplayRelease(_display);
} else {
CGDisplayCapture(_display);
}
}
properties.clear_minimized();
}
if (properties.has_fullscreen()) {
if (_properties.get_fullscreen() != properties.get_fullscreen()) {
if (properties.get_fullscreen()) {
// Capture the display
if (!_properties.get_minimized()) {
CGDisplayCapture(_display);
if (properties.has_size()) {
int width = properties.get_x_size();
int height = properties.get_y_size();
if (!_properties.get_fullscreen()) {
_properties.set_size(width, height);
if (_window != nil) {
[_window setContentSize:NSMakeSize(width, height)];
}
[_view setFrameSize:NSMakeSize(width, height)];
cocoadisplay_cat.debug()
<< "Setting size to " << width << ", " << height << "\n";
_context_needs_update = true;
properties.clear_size();
} else {
// Release the display
CGDisplayRelease(_display);
CGDisplayModeRef mode = find_display_mode(width, height);
if (mode == NULL) {
cocoadisplay_cat.error()
<< "Could not find a suitable display mode with size " << width
<< "x" << height << "!\n";
} else if (do_switch_fullscreen(mode)) {
// Yay! Our resolution has changed.
_properties.set_size(width, height);
properties.clear_size();
} else {
cocoadisplay_cat.error()
<< "Failed to change display mode.\n";
}
_properties.set_fullscreen(properties.get_fullscreen());
}
properties.clear_fullscreen();
}
if (properties.has_origin()) {
if (properties.has_origin() && !_properties.get_fullscreen()) {
int x = properties.get_x_origin();
int y = properties.get_y_origin();
//TODO: what if parent window was set
// Get the frame for the screen
NSRect frame = [_window frame];
NSRect frame;
NSRect container;
if (_window != nil) {
frame = [_window contentRectForFrameRect:[_window frame]];
NSScreen *screen = [_window screen];
nassertv(screen != nil);
NSRect screenFrame = [screen frame];
container = [screen frame];
} else {
frame = [_view frame];
container = [[_view superview] frame];
}
if (x < 0) {
x = floor(screenFrame.size.width / 2 - _properties.get_x_size() / 2);
x = floor(container.size.width / 2 - frame.size.width / 2);
}
if (y < 0) {
y = floor(screenFrame.size.height / 2 - _properties.get_y_size() / 2);
y = floor(container.size.height / 2 - frame.size.height / 2);
}
_properties.set_origin(x, y);
if (!_properties.get_fullscreen()) {
// Convert to content rect, change pos, convert back.
// Remember, Mac OS X coordinates are flipped in the vertical axis.
NSRect content = [_window contentRectForFrameRect: frame];
content.origin.x = screenFrame.origin.x + x;
content.origin.y = screenFrame.origin.y + screenFrame.size.height - y - content.size.height;
frame = [_window frameRectForContentRect: content];
frame.origin.x = x;
frame.origin.y = container.size.height - y - frame.size.height;
cocoadisplay_cat.debug()
<< "Setting frame origin to " << screenFrame.origin.x << ", " << screenFrame.origin.y << "\n";
<< "Setting window content origin to " << frame.origin.x << ", " << frame.origin.y << "\n";
[_window setFrame: frame display: NO];
if (_window != nil) {
[_window setFrame:[_window frameRectForContentRect:frame] display:NO];
} else {
[_view setFrame:frame];
}
}
properties.clear_origin();
}
if (properties.has_size()) {
_properties.set_size(properties.get_x_size(), properties.get_y_size());
if (!_properties.get_fullscreen()) {
[_window setContentSize: NSMakeSize(properties.get_x_size(), properties.get_y_size())];
}
properties.clear_size();
}
//TODO: mouse mode
if (properties.has_title()) {
if (properties.has_title() && _window != nil) {
_properties.set_title(properties.get_title());
[_window setTitle:[NSString stringWithUTF8String:properties.get_title().c_str()]];
properties.clear_title();
}
if (properties.has_fixed_size()) {
if (properties.has_fixed_size() && _window != nil) {
_properties.set_fixed_size(properties.get_fixed_size());
[_window setShowsResizeIndicator:!properties.get_fixed_size()];
@ -627,7 +860,7 @@ set_properties_now(WindowProperties &properties) {
// If our window is decorated, change the style mask
// to show or hide the resize button appropriately.
// However, if we're specifying the 'undecorated' property also,
// then we'll be setting the style mask about 20 LOC further down,
// then we'll be setting the style mask about 25 LOC further down,
// so we won't need to bother setting it here.
if (!properties.has_undecorated() && !_properties.get_undecorated()) {
if (properties.get_fixed_size()) {
@ -637,13 +870,14 @@ set_properties_now(WindowProperties &properties) {
[_window setStyleMask:NSTitledWindowMask | NSClosableWindowMask |
NSMiniaturizableWindowMask | NSResizableWindowMask ];
}
[_window makeFirstResponder:_view];
}
}
properties.clear_fixed_size();
}
if (properties.has_undecorated()) {
if (properties.has_undecorated() && _window != nil) {
_properties.set_undecorated(properties.get_undecorated());
if (!_properties.get_fullscreen()) {
@ -657,12 +891,13 @@ set_properties_now(WindowProperties &properties) {
[_window setStyleMask: NSTitledWindowMask | NSClosableWindowMask |
NSMiniaturizableWindowMask | NSResizableWindowMask ];
}
[_window makeFirstResponder:_view];
}
properties.clear_undecorated();
}
if (properties.has_foreground()) {
if (properties.has_foreground() && !_properties.get_fullscreen() && _window != nil) {
_properties.set_foreground(properties.get_foreground());
if (!_properties.get_minimized()) {
if (properties.get_foreground()) {
@ -700,7 +935,7 @@ set_properties_now(WindowProperties &properties) {
//XXX cursor filename
if (properties.has_z_order()) {
if (properties.has_z_order() && _window != nil) {
_properties.set_z_order(properties.get_z_order());
if (!_properties.get_fullscreen()) {
@ -728,6 +963,110 @@ set_properties_now(WindowProperties &properties) {
}
}
////////////////////////////////////////////////////////////////////
// Function: CocoaGraphicsWindow::find_display_mode
// Access: Protected
// Description: Returns an appropriate CGDisplayModeRef for the
// given width and height, or NULL if none was found.
////////////////////////////////////////////////////////////////////
CGDisplayModeRef CocoaGraphicsWindow::
find_display_mode(int width, int height) {
CFArrayRef modes = CGDisplayCopyAllDisplayModes(_display, NULL);
size_t num_modes = CFArrayGetCount(modes);
CGDisplayModeRef mode;
// Get the current refresh rate and pixel encoding.
CFStringRef current_pixel_encoding;
int refresh_rate;
mode = CGDisplayCopyDisplayMode(_display);
// First check if the current mode is adequate.
if (CGDisplayModeGetWidth(mode) == width &&
CGDisplayModeGetHeight(mode) == height) {
return mode;
}
current_pixel_encoding = CGDisplayModeCopyPixelEncoding(mode);
refresh_rate = CGDisplayModeGetRefreshRate(mode);
CGDisplayModeRelease(mode);
for (size_t i = 0; i < num_modes; ++i) {
mode = (CGDisplayModeRef) CFArrayGetValueAtIndex(modes, i);
CFStringRef pixel_encoding = CGDisplayModeCopyPixelEncoding(mode);
if (CGDisplayModeGetWidth(mode) == width &&
CGDisplayModeGetHeight(mode) == height &&
CGDisplayModeGetRefreshRate(mode) == refresh_rate &&
CFStringCompare(pixel_encoding, current_pixel_encoding, 0) == kCFCompareEqualTo) {
CFRetain(mode);
CFRelease(pixel_encoding);
CFRelease(current_pixel_encoding);
CFRelease(modes);
return mode;
}
}
CFRelease(current_pixel_encoding);
CFRelease(modes);
return NULL;
}
////////////////////////////////////////////////////////////////////
// Function: CocoaGraphicsWindow::do_switch_fullscreen
// Access: Protected
// Description: Switches to the indicated fullscreen mode, or
// back to windowed if NULL was given. Returns true
// on success, false on failure.
////////////////////////////////////////////////////////////////////
bool CocoaGraphicsWindow::
do_switch_fullscreen(CGDisplayModeRef mode) {
if (mode == NULL) {
if (_windowed_mode == NULL) {
// Already windowed.
return true;
}
// Switch back to the mode we were in when we were still windowed.
CGDisplaySetDisplayMode(_display, _windowed_mode, NULL);
CGDisplayModeRelease(_windowed_mode);
CGDisplayRelease(_display);
_windowed_mode = NULL;
_context_needs_update = true;
} else {
if (_windowed_mode != NULL && _fullscreen_mode == mode) {
// Already fullscreen in that size.
return true;
}
_windowed_mode = CGDisplayCopyDisplayMode(_display);
_fullscreen_mode = mode;
_context_needs_update = true;
if (CGDisplaySetDisplayMode(_display, _fullscreen_mode, NULL) != kCGErrorSuccess) {
return false;
}
CGDisplayCaptureWithOptions(_display, kCGCaptureNoFill);
NSRect frame = [[[_view window] screen] frame];
if (cocoadisplay_cat.is_debug()) {
NSString *str = NSStringFromRect(frame);
cocoadisplay_cat.debug()
<< "Switched to fullscreen, screen rect is now " << [str UTF8String] << "\n";
}
if (_window != nil) {
[_window setFrame:frame display:YES];
[_view setFrame:NSMakeRect(0, 0, frame.size.width, frame.size.height)];
[_window update];
}
}
return true;
}
////////////////////////////////////////////////////////////////////
// Function: CocoaGraphicsWindow::handle_move_event
// Access: Public
@ -736,22 +1075,28 @@ set_properties_now(WindowProperties &properties) {
////////////////////////////////////////////////////////////////////
void CocoaGraphicsWindow::
handle_move_event() {
NSRect frame = [_window frame];
NSRect screenFrame = [[_window screen] frame];
NSRect content = [_window contentRectForFrameRect: frame];
// Remember, Mac OS X uses flipped coordinates
WindowProperties properties;
properties.set_origin(content.origin.x - screenFrame.origin.x,
screenFrame.size.height - content.size.height - (content.origin.y - screenFrame.origin.y));
NSRect frame;
int x, y;
if (_window == nil) {
frame = [_view frame];
x = frame.origin.x;
y = [[_view superview] bounds].size.height - frame.origin.y - frame.size.height;
} else {
frame = [_window contentRectForFrameRect:[_window frame]];
x = frame.origin.x;
y = [[_window screen] frame].size.height - frame.origin.y - frame.size.height;
}
if (properties.get_x_origin() != _properties.get_x_origin() ||
properties.get_y_origin() != _properties.get_y_origin()) {
if (x != _properties.get_x_origin() ||
y != _properties.get_y_origin()) {
WindowProperties properties;
properties.set_origin(x, y);
if (cocoadisplay_cat.is_spam()) {
cocoadisplay_cat.spam()
<< "Window changed origin to (" << properties.get_x_origin()
<< ", " << properties.get_y_origin() << ")\n";
<< "Window changed origin to (" << x << ", " << y << ")\n";
}
system_changed_properties(properties);
}
@ -765,23 +1110,28 @@ handle_move_event() {
////////////////////////////////////////////////////////////////////
void CocoaGraphicsWindow::
handle_resize_event() {
NSRect frame = [_window frame];
NSRect screenFrame = [[_window screen] frame];
NSRect content = [_window contentRectForFrameRect: frame];
if (_window != nil) {
NSRect contentRect = [_window contentRectForFrameRect:[_window frame]];
[_view setFrameSize:contentRect.size];
}
NSRect frame = [_view convertRect:[_view bounds] toView:nil];
if (frame.size.width != _properties.get_x_size() ||
frame.size.height != _properties.get_y_size()) {
WindowProperties properties;
properties.set_size(content.size.width, content.size.height);
if (properties.get_x_size() != _properties.get_x_size() ||
properties.get_y_size() != _properties.get_y_size()) {
properties.set_size(frame.size.width, frame.size.height);
if (cocoadisplay_cat.is_spam()) {
cocoadisplay_cat.spam()
<< "Window changed size to (" << properties.get_x_size()
<< ", " << properties.get_y_size() << ")\n";
<< "Window changed size to (" << frame.size.width
<< ", " << frame.size.height << ")\n";
}
system_changed_properties(properties);
}
_context_needs_update = true;
}
////////////////////////////////////////////////////////////////////
@ -800,14 +1150,6 @@ handle_minimize_event(bool minimized) {
properties.set_minimized(minimized);
system_changed_properties(properties);
if (_properties.get_fullscreen()) {
if (minimized) {
CGDisplayRelease(_display);
} else {
CGDisplayCapture(_display);
}
}
if (cocoadisplay_cat.is_debug()) {
if (minimized) {
cocoadisplay_cat.debug() << "Window was miniaturized\n";
@ -840,15 +1182,12 @@ handle_foreground_event(bool foreground) {
if (foreground && _properties.get_mouse_mode() != WindowProperties::M_relative) {
// The mouse position may have changed during
// the time that we were not the key window.
NSPoint pos = [NSEvent mouseLocation];
NSRect frame = [_window frame];
pos.x -= frame.origin.x;
pos.y -= frame.origin.y;
NSPoint pos = [_window mouseLocationOutsideOfEventStream];
NSPoint loc = [_view convertPoint:pos fromView:nil];
BOOL inside = [_view mouse:loc inRect:[_view bounds]];
handle_mouse_moved_event(inside, loc.x, [_view bounds].size.height - loc.y, true);
handle_mouse_moved_event(inside, loc.x, loc.y, true);
}
}
@ -895,8 +1234,6 @@ void CocoaGraphicsWindow::
handle_close_event() {
cocoadisplay_cat.debug() << "Window is about to close\n";
// Make sure that the window gets released
[_window setReleasedWhenClosed: YES];
_window = nil;
// Get rid of the GSG
@ -905,7 +1242,9 @@ handle_close_event() {
cocoagsg = DCAST(CocoaGraphicsStateGuardian, _gsg);
if (cocoagsg != NULL && cocoagsg->_context != nil) {
CGLLockContext((CGLContextObj) [cocoagsg->_context CGLContextObj]);
[cocoagsg->_context clearDrawable];
CGLUnlockContext((CGLContextObj) [cocoagsg->_context CGLContextObj]);
}
_gsg.clear();
}
@ -1078,6 +1417,7 @@ handle_mouse_button_event(int button, bool down) {
////////////////////////////////////////////////////////////////////
void CocoaGraphicsWindow::
handle_mouse_moved_event(bool in_window, int x, int y, bool absolute) {
if (absolute) {
if (cocoadisplay_cat.is_spam()) {
if (in_window != _input_devices[0].get_pointer().get_in_window()) {
if (in_window) {
@ -1088,9 +1428,10 @@ handle_mouse_moved_event(bool in_window, int x, int y, bool absolute) {
}
}
if (absolute) {
_input_devices[0].set_pointer(in_window, x, y,
// Strangely enough, in Cocoa, mouse Y coordinates are 1-based.
_input_devices[0].set_pointer(in_window, x, y - 1,
ClockObject::get_global_clock()->get_frame_time());
} else {
//TODO: also get initial mouse position
MouseData md = _input_devices[0].get_pointer();
@ -1117,7 +1458,25 @@ handle_mouse_moved_event(bool in_window, int x, int y, bool absolute) {
////////////////////////////////////////////////////////////////////
void CocoaGraphicsWindow::
handle_wheel_event(double x, double y) {
//TODO
cocoadisplay_cat.spam()
<< "Wheel delta " << x << ", " << y << "\n";
if (y > 0.0) {
_input_devices[0].button_down(MouseButton::wheel_up());
_input_devices[0].button_up(MouseButton::wheel_up());
} else if (y < 0.0) {
_input_devices[0].button_down(MouseButton::wheel_down());
_input_devices[0].button_up(MouseButton::wheel_down());
}
//TODO: check if this is correct
if (x > 0.0) {
_input_devices[0].button_down(MouseButton::wheel_right());
_input_devices[0].button_up(MouseButton::wheel_right());
} else if (y < 0.0) {
_input_devices[0].button_down(MouseButton::wheel_left());
_input_devices[0].button_up(MouseButton::wheel_left());
}
}
////////////////////////////////////////////////////////////////////

View File

@ -23,6 +23,8 @@ class CocoaGraphicsWindow;
}
- (id) initWithFrame:(NSRect)frameRect context:(NSOpenGLContext*)context window:(CocoaGraphicsWindow*)window;
- (void) finalize;
- (BOOL) isFlipped;
- (BOOL) acceptsFirstResponder;
- (BOOL) becomeFirstResponder;
- (BOOL) resignFirstResponder;

View File

@ -25,12 +25,20 @@
<< "Created CocoaPandaView " << self << " for GraphicsWindow " << window << "\n";
_graphicsWindow = window;
// Make sure that the view automatically resizes with the window
//[self setAutoresizingMask: NSViewWidthSizable | NSViewHeightSizable];
return self;
}
- (void) finalize {
_graphicsWindow->handle_close_event();
[super finalize];
}
- (BOOL) isFlipped {
// Apple uses a coordinate system where the lower-left corner
// represents (0, 0). In Panda, this is the upper-left corner.
return YES;
}
- (BOOL) acceptsFirstResponder {
return YES;
}
@ -45,9 +53,8 @@
- (void) setFrame: (NSRect) frame {
[super setFrame: frame];
[_context update];
_graphicsWindow->handle_resize_event();
//[_context update];
//_graphicsWindow->handle_resize_event();
}
- (void) keyDown: (NSEvent *) event {
@ -81,7 +88,7 @@
if (_graphicsWindow->get_properties().get_mouse_mode() == WindowProperties::M_relative) {
_graphicsWindow->handle_mouse_moved_event(inside, [event deltaX], [event deltaY], false);
} else {
_graphicsWindow->handle_mouse_moved_event(inside, loc.x, [self bounds].size.height - loc.y, true);
_graphicsWindow->handle_mouse_moved_event(inside, loc.x, loc.y, true);
}
}

View File

@ -23,5 +23,9 @@ class CocoaGraphicsWindow;
- (id) initWithContentRect:(NSRect)rect styleMask:(NSUInteger)styleMask screen:(NSScreen*)screen window:(CocoaGraphicsWindow*)window;
- (BOOL) canBecomeKeyWindow;
- (BOOL) canBecomeMainWindow;
- (BOOL) acceptsFirstResponder;
- (BOOL) becomeFirstResponder;
- (BOOL) resignFirstResponder;
@end

View File

@ -28,6 +28,7 @@
CocoaPandaWindowDelegate *delegate = [[CocoaPandaWindowDelegate alloc] initWithGraphicsWindow:window];
[self setDelegate:delegate];
[self setOpaque:YES];
[self setReleasedWhenClosed:YES];
// Necessary to be able to accept mouseMoved in the NSView
[self setAcceptsMouseMovedEvents:YES];
@ -41,4 +42,20 @@
return YES;
}
- (BOOL) canBecomeMainWindow {
return YES;
}
- (BOOL) acceptsFirstResponder {
return YES;
}
- (BOOL) becomeFirstResponder {
return YES;
}
- (BOOL) resignFirstResponder {
return YES;
}
@end