Fixed: #1020 GLWindow, create, destroy, create would lead to creating two autorelease pools

This commit is contained in:
rti 2010-07-14 20:40:24 +02:00
parent 5f9da63b41
commit b64b7467d9

View file

@ -25,7 +25,7 @@
#include "cocoa_event_emitter.h" #include "cocoa_event_emitter.h"
#include "cocoa_opengl_view.h" #include "cocoa_opengl_view.h"
// Virtual key codes are only defined here. We still do not need to link carbon. // Virtual key codes are only defined here. Still do not need to link carbon.
// see: http://lists.apple.com/archives/Cocoa-dev/2009/May/msg01180.html // see: http://lists.apple.com/archives/Cocoa-dev/2009/May/msg01180.html
#include <Carbon/Carbon.h> #include <Carbon/Carbon.h>
@ -33,6 +33,27 @@
namespace NL3D { namespace MAC { namespace NL3D { namespace MAC {
// This cocoa adapter can be used in two environments:
// First: There is no other code which creates the NSApplication object, so
// NeL is completely in charge of starting and setting up the application.
// In this case, the NSAutoreleasePool needed to handle the cocoa style memory
// management is created by this code.
// Second: There is already a NSApplication set up. This could be the case if
// NeL is used for example in a Qt widget. So Qt already created all the
// NSApplication infrastructure, so it is not set up by this code again!
//
// Thats why, the g_pool variable (containing a pointer to the NSAutoreleasePool
// created by this code) can be used to check whether NeL created the
// NSApplication infrastructure itself or not.
//
// WARNING:
// Currently the NSApplication infrastructure is automatically created with the
// call to createWindow(). So if for example Qt already created NSApplication,
// createWindow() must not be called. Instead, setDisplay() can be provided with
// a window handle (on Mac OS Cocoa Qt this is a NSView*). In this case, this
// cocoa adapter will skip the NSApplication setup and embed itself into the
// provided view running in the already set up application.
static NSAutoreleasePool* g_pool = nil; static NSAutoreleasePool* g_pool = nil;
/* /*
TODO move to event emitter class TODO move to event emitter class
@ -40,6 +61,7 @@ static NSAutoreleasePool* g_pool = nil;
static bool g_emulateRawMode = false; static bool g_emulateRawMode = false;
static int g_bufferSize[2] = { 0, 0 }; static int g_bufferSize[2] = { 0, 0 };
/// setup an apple style application menu (located at the top bar of the screen)
static void setupApplicationMenu() static void setupApplicationMenu()
{ {
NSMenu* menu; NSMenu* menu;
@ -98,6 +120,29 @@ static void setupApplicationMenu()
[[NSApp mainMenu] addItem:menuItem]; [[NSApp mainMenu] addItem:menuItem];
} }
/// set up the basic NSApplication and NSAutoreleasePool needed for Cocoa
static bool setupNSApplication()
{
// if the pool was already created, return an error
if(g_pool)
return false;
// create a pool, cocoa code would leak memory otherwise
g_pool = [[NSAutoreleasePool alloc] init];
// init the application object
[NSApplication sharedApplication];
// create the menu in the top screen bar
setupApplicationMenu();
// finish the application launching
[NSApp finishLaunching];
return true;
}
/// setup an open gl view and embed it in the provided parent view
static void setupGLView(NSView* superview) static void setupGLView(NSView* superview)
{ {
/* /*
@ -169,20 +214,13 @@ bool unInit()
return true; return true;
} }
/// setup the basic cocoa app infrastructure and create a window
nlWindow createWindow(const GfxMode& mode) nlWindow createWindow(const GfxMode& mode)
{ {
// create a pool, cocoa code would leak memory otherwise if(!setupNSApplication())
g_pool = [[NSAutoreleasePool alloc] init]; nlerror("createWindow must not be called before the old window was "
"destroyed using destroyWindow()!");
// init the application object
[NSApplication sharedApplication];
// create the menu in the top screen bar
setupApplicationMenu();
// tell the application that we are running now
[NSApp finishLaunching];
// describe how the window should look like and behave // describe how the window should look like and behave
unsigned int styleMask = NSTitledWindowMask | NSClosableWindowMask | unsigned int styleMask = NSTitledWindowMask | NSClosableWindowMask |
NSMiniaturizableWindowMask | NSResizableWindowMask; NSMiniaturizableWindowMask | NSResizableWindowMask;
@ -201,7 +239,7 @@ nlWindow createWindow(const GfxMode& mode)
// enable mouse move events, NeL wants them // enable mouse move events, NeL wants them
[window setAcceptsMouseMovedEvents:YES]; [window setAcceptsMouseMovedEvents:YES];
// there are no overlapping subviews, so we can use the magical optimization! // there are no overlapping subviews, can use the magical optimization :)
[window useOptimizedDrawing:YES]; [window useOptimizedDrawing:YES];
// put the window to the front and make it the key window // put the window to the front and make it the key window
@ -217,6 +255,7 @@ nlWindow createWindow(const GfxMode& mode)
return view; return view;
} }
/// destroy the given window and uninitialize the cocoa application
bool destroyWindow(nlWindow wnd) bool destroyWindow(nlWindow wnd)
{ {
NSView* view = (NSView*)wnd; NSView* view = (NSView*)wnd;
@ -229,10 +268,12 @@ bool destroyWindow(nlWindow wnd)
// release the pool // release the pool
[g_pool release]; [g_pool release];
g_pool = nil;
return true; return true;
} }
/// set the displays settings, if no win is provided, a new one will be created
nlWindow setDisplay(nlWindow wnd, const GfxMode& mode, bool show, bool resizeable) nlWindow setDisplay(nlWindow wnd, const GfxMode& mode, bool show, bool resizeable)
{ {
NSView* view = (NSView*)wnd; NSView* view = (NSView*)wnd;
@ -247,6 +288,7 @@ nlWindow setDisplay(nlWindow wnd, const GfxMode& mode, bool show, bool resizeabl
return view; return view;
} }
/// switch between fullscreen and windowed mode
bool setWindowStyle(nlWindow wnd, bool fullscreen) bool setWindowStyle(nlWindow wnd, bool fullscreen)
{ {
if(wnd == EmptyWindow) if(wnd == EmptyWindow)
@ -315,7 +357,7 @@ bool setWindowStyle(nlWindow wnd, bool fullscreen)
return true; return true;
} }
/// get the current mode of the screen
void getCurrentScreenMode(nlWindow wnd, GfxMode& mode) void getCurrentScreenMode(nlWindow wnd, GfxMode& mode)
{ {
NSView* superview = (NSView*)wnd; NSView* superview = (NSView*)wnd;
@ -347,6 +389,7 @@ void getCurrentScreenMode(nlWindow wnd, GfxMode& mode)
} }
} }
/// get the size of the window's content area
void getWindowSize(nlWindow wnd, uint32 &width, uint32 &height) void getWindowSize(nlWindow wnd, uint32 &width, uint32 &height)
{ {
NSView* superview = (NSView*)wnd; NSView* superview = (NSView*)wnd;
@ -378,6 +421,7 @@ void getWindowSize(nlWindow wnd, uint32 &width, uint32 &height)
} }
} }
/// set the size of the window's content area
void setWindowSize(nlWindow wnd, uint32 width, uint32 height) void setWindowSize(nlWindow wnd, uint32 width, uint32 height)
{ {
NSView* superview = (NSView*)wnd; NSView* superview = (NSView*)wnd;
@ -398,8 +442,8 @@ void setWindowSize(nlWindow wnd, uint32 width, uint32 height)
} }
else else
{ {
// there is only a pool if nel created the window itself assuming that // there is only a pool if NeL created the window itself
// nel is also in charge of the main loop // else, the window is not NeL's, so it must not be changed
if(g_pool) if(g_pool)
{ {
NSWindow* window = [view window]; NSWindow* window = [view window];
@ -421,7 +465,7 @@ void setWindowSize(nlWindow wnd, uint32 width, uint32 height)
g_bufferSize[1] = height; g_bufferSize[1] = height;
} }
/// get the position of the window
void getWindowPos(nlWindow wnd, sint32 &x, sint32 &y) void getWindowPos(nlWindow wnd, sint32 &x, sint32 &y)
{ {
NSView* superview = (NSView*)wnd; NSView* superview = (NSView*)wnd;
@ -448,6 +492,7 @@ void getWindowPos(nlWindow wnd, sint32 &x, sint32 &y)
y = screenRect.size.height - windowRect.size.height - windowRect.origin.y; y = screenRect.size.height - windowRect.size.height - windowRect.origin.y;
} }
/// set the position of the window
void setWindowPos(nlWindow wnd, sint32 x, sint32 y) void setWindowPos(nlWindow wnd, sint32 x, sint32 y)
{ {
NSView* superview = (NSView*)wnd; NSView* superview = (NSView*)wnd;
@ -466,6 +511,7 @@ void setWindowPos(nlWindow wnd, sint32 x, sint32 y)
[window setFrameTopLeftPoint:NSMakePoint(x, y)]; [window setFrameTopLeftPoint:NSMakePoint(x, y)];
} }
/// set the windows title (not the title of the application)
void setWindowTitle(nlWindow wnd, const ucstring& title) void setWindowTitle(nlWindow wnd, const ucstring& title)
{ {
NSView* superview = (NSView*)wnd; NSView* superview = (NSView*)wnd;
@ -480,6 +526,7 @@ void showWindow(bool show)
nldebug("show: %d - implement me!", show); nldebug("show: %d - implement me!", show);
} }
/// make the opengl context the current one
bool activate(nlWindow wnd) bool activate(nlWindow wnd)
{ {
NSView* superview = (NSView*)wnd; NSView* superview = (NSView*)wnd;
@ -493,6 +540,7 @@ bool activate(nlWindow wnd)
return true; return true;
} }
/// flush current back buffer to screen
void swapBuffers(nlWindow wnd) void swapBuffers(nlWindow wnd)
{ {
NSView* superview = (NSView*)wnd; NSView* superview = (NSView*)wnd;
@ -509,6 +557,7 @@ void setCapture(bool capture)
// no need to capture // no need to capture
} }
/// show or hide the mouse cursor
void showCursor(bool show) void showCursor(bool show)
{ {
// Mac OS manages a show/hide counter for the cursor, so hiding the cursor // Mac OS manages a show/hide counter for the cursor, so hiding the cursor
@ -535,6 +584,7 @@ void showCursor(bool show)
nlerror("cannot show / hide cursor"); nlerror("cannot show / hide cursor");
} }
/// set the mouse position
void setMousePos(nlWindow wnd, float x, float y) void setMousePos(nlWindow wnd, float x, float y)
{ {
NSView* superview = (NSView*)wnd; NSView* superview = (NSView*)wnd;
@ -571,7 +621,8 @@ void setMousePos(nlWindow wnd, float x, float y)
TODO: this function has to be moved to a more central place to handle key TODO: this function has to be moved to a more central place to handle key
mapping on mac x11 as well mapping on mac x11 as well
*/ */
NLMISC::TKey virtualKeycodeToNelKey(unsigned short keycode) /// map from virtual key code to nel internal key code
static NLMISC::TKey virtualKeycodeToNelKey(unsigned short keycode)
{ {
switch(keycode) switch(keycode)
{ {
@ -702,7 +753,8 @@ NLMISC::TKey virtualKeycodeToNelKey(unsigned short keycode)
TODO: this function has to be moved to a more central place to handle key TODO: this function has to be moved to a more central place to handle key
mapping on mac x11 as well mapping on mac x11 as well
*/ */
NLMISC::TKeyButton modifierFlagsToNelKeyButton(unsigned int modifierFlags) /// convert modifier key state to nel internal modifier key state
static NLMISC::TKeyButton modifierFlagsToNelKeyButton(unsigned int modifierFlags)
{ {
unsigned int buttons = 0; unsigned int buttons = 0;
if (modifierFlags & NSControlKeyMask) buttons |= NLMISC::ctrlKeyButton; if (modifierFlags & NSControlKeyMask) buttons |= NLMISC::ctrlKeyButton;
@ -711,7 +763,8 @@ NLMISC::TKeyButton modifierFlagsToNelKeyButton(unsigned int modifierFlags)
return (NLMISC::TKeyButton)buttons; return (NLMISC::TKeyButton)buttons;
} }
bool isTextKeyEvent(NSEvent* event) /// check whether a given event represents input text
static bool isTextKeyEvent(NSEvent* event)
{ {
// if there are no characters provided with this event, it is not a text event // if there are no characters provided with this event, it is not a text event
if([[event characters] length] == 0) if([[event characters] length] == 0)
@ -763,16 +816,18 @@ bool isTextKeyEvent(NSEvent* event)
return false; return false;
} }
/// switch between raw mode emulation, see IEventEmitter::emulateMouseRawMode()
void emulateMouseRawMode(bool enable) void emulateMouseRawMode(bool enable)
{ {
g_emulateRawMode = enable; g_emulateRawMode = enable;
} }
/// submit events provided by the application to an event server
void submitEvents(NLMISC::CEventServer& server, void submitEvents(NLMISC::CEventServer& server,
bool allWindows, NLMISC::CCocoaEventEmitter* eventEmitter) bool allWindows, NLMISC::CCocoaEventEmitter* eventEmitter)
{ {
// there is only a pool if nel created the window itself assuming that // if there is a pool, NeL needs to clean it up
// nel is also in charge of the main loop // otherwise, other code must have created it (for example Qt)
if(g_pool) if(g_pool)
{ {
// cocoa style memory cleanup // cocoa style memory cleanup
@ -780,7 +835,7 @@ void submitEvents(NLMISC::CEventServer& server,
g_pool = [[NSAutoreleasePool alloc] init]; g_pool = [[NSAutoreleasePool alloc] init];
} }
// we break if there was no event to handle // break if there was no event to handle
/* TODO maximum number of events processed in one update? */ /* TODO maximum number of events processed in one update? */
while(true) while(true)
{ {