From b11c346e3b0fad9221aabe991a0ea357947641b2 Mon Sep 17 00:00:00 2001 From: rti Date: Fri, 5 Nov 2010 12:57:31 +0100 Subject: [PATCH] Fixed: #1156 Handle window close/application quit cleanly --- code/nel/src/3d/driver/opengl/driver_opengl.h | 7 ++- .../3d/driver/opengl/driver_opengl_window.cpp | 15 ++++- .../opengl/mac/cocoa_application_delegate.h | 33 ++++++++++ .../opengl/mac/cocoa_application_delegate.mm | 62 +++++++++++++++++++ .../driver/opengl/mac/cocoa_event_emitter.cpp | 11 ++++ .../driver/opengl/mac/cocoa_event_emitter.h | 1 + .../3d/driver/opengl/mac/cocoa_opengl_view.m | 2 - 7 files changed, 125 insertions(+), 6 deletions(-) create mode 100644 code/nel/src/3d/driver/opengl/mac/cocoa_application_delegate.h create mode 100644 code/nel/src/3d/driver/opengl/mac/cocoa_application_delegate.mm diff --git a/code/nel/src/3d/driver/opengl/driver_opengl.h b/code/nel/src/3d/driver/opengl/driver_opengl.h index 8ab0b3f6a..5b3b11dfe 100644 --- a/code/nel/src/3d/driver/opengl/driver_opengl.h +++ b/code/nel/src/3d/driver/opengl/driver_opengl.h @@ -782,9 +782,10 @@ private: #elif defined(NL_OS_MAC) - friend bool GlWndProc(CDriverGL*, const void*); - friend void windowDidMove(NSWindow*, CDriverGL*); - friend void viewDidResize(NSView*, CDriverGL*); + friend bool GlWndProc(CDriverGL*, const void*); + friend void windowDidMove(NSWindow*, CDriverGL*); + friend void viewDidResize(NSView*, CDriverGL*); + friend NSApplicationTerminateReply applicationShouldTerminate(CDriverGL*); NLMISC::CCocoaEventEmitter _EventEmitter; NSOpenGLContext* _ctx; diff --git a/code/nel/src/3d/driver/opengl/driver_opengl_window.cpp b/code/nel/src/3d/driver/opengl/driver_opengl_window.cpp index e340520ca..8afce2f80 100644 --- a/code/nel/src/3d/driver/opengl/driver_opengl_window.cpp +++ b/code/nel/src/3d/driver/opengl/driver_opengl_window.cpp @@ -26,7 +26,8 @@ # include #elif defined(NL_OS_MAC) # import "mac/cocoa_window_delegate.h" -# import +# import "mac/cocoa_application_delegate.h" +# import #elif defined (NL_OS_UNIX) # include # include @@ -1432,6 +1433,18 @@ bool CDriverGL::createWindow(const GfxMode &mode) return false; } + // create an application delegate + CocoaApplicationDelegate* appDelegate = + [[CocoaApplicationDelegate alloc] initWithDriver:this]; + + // set the application delegate, this will handle window/app close events + [NSApp setDelegate:appDelegate]; + + // bind the close button of the window to applicationShouldTerminate + id closeButton = [cocoa_window standardWindowButton:NSWindowCloseButton]; + [closeButton setAction:@selector(applicationShouldTerminate:)]; + [closeButton setTarget:appDelegate]; + // set the delegate which will handle window move events [cocoa_window setDelegate:[[CocoaWindowDelegate alloc] initWithDriver:this]]; diff --git a/code/nel/src/3d/driver/opengl/mac/cocoa_application_delegate.h b/code/nel/src/3d/driver/opengl/mac/cocoa_application_delegate.h new file mode 100644 index 000000000..cd0afe2fa --- /dev/null +++ b/code/nel/src/3d/driver/opengl/mac/cocoa_application_delegate.h @@ -0,0 +1,33 @@ +// NeL - MMORPG Framework +// Copyright (C) 2010 Winch Gate Property Limited +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU Affero General Public License as +// published by the Free Software Foundation, either version 3 of the +// License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Affero General Public License for more details. +// +// You should have received a copy of the GNU Affero General Public License +// along with this program. If not, see . + +#import + +namespace NL3D +{ + class CDriverGL; + NSApplicationTerminateReply applicationShouldTerminate(CDriverGL*); +} + +@interface CocoaApplicationDelegate : NSObject +{ + NL3D::CDriverGL* _driver; +} + +-(id)initWithDriver:(NL3D::CDriverGL*)driver; +-(NSApplicationTerminateReply)applicationShouldTerminate:(NSApplication *)sender; + +@end diff --git a/code/nel/src/3d/driver/opengl/mac/cocoa_application_delegate.mm b/code/nel/src/3d/driver/opengl/mac/cocoa_application_delegate.mm new file mode 100644 index 000000000..2a667d13b --- /dev/null +++ b/code/nel/src/3d/driver/opengl/mac/cocoa_application_delegate.mm @@ -0,0 +1,62 @@ +// NeL - MMORPG Framework +// Copyright (C) 2010 Winch Gate Property Limited +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU Affero General Public License as +// published by the Free Software Foundation, either version 3 of the +// License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Affero General Public License for more details. +// +// You should have received a copy of the GNU Affero General Public License +// along with this program. If not, see . + +#include "../driver_opengl.h" + +#include "cocoa_application_delegate.h" +#include "cocoa_event_emitter.h" + +namespace NL3D +{ + NSApplicationTerminateReply applicationShouldTerminate(CDriverGL* driver) + { + // cancel if there is a driver and a custom exit handler set up + if(driver && driver->ExitFunc) + { + driver->ExitFunc(); + return NSTerminateCancel; + } + + NLMISC::CCocoaEventEmitter* eventEmitter = + NLMISC::safe_cast(&(driver->_EventEmitter)); + + // cancel if there is a driver and cocoa event emitter handles the quit + if(driver && eventEmitter && eventEmitter->handleQuitRequest()) + return NSTerminateCancel; + + // just let the app terminate if no custom quit handling worked + return NSTerminateNow; + } +} + +@implementation CocoaApplicationDelegate + +-(id)initWithDriver:(NL3D::CDriverGL*)driver +{ + if((self = [super init])) + { + _driver = driver; + return self; + } + return nil; +} + +-(NSApplicationTerminateReply)applicationShouldTerminate:(NSApplication*)sender +{ + return NL3D::applicationShouldTerminate(_driver); +} + +@end diff --git a/code/nel/src/3d/driver/opengl/mac/cocoa_event_emitter.cpp b/code/nel/src/3d/driver/opengl/mac/cocoa_event_emitter.cpp index 734478d8a..7cec8ed9c 100644 --- a/code/nel/src/3d/driver/opengl/mac/cocoa_event_emitter.cpp +++ b/code/nel/src/3d/driver/opengl/mac/cocoa_event_emitter.cpp @@ -410,6 +410,17 @@ bool CCocoaEventEmitter::processMessage(NSEvent* event, CEventServer* server) return true; } +bool CCocoaEventEmitter::handleQuitRequest() +{ + if(_server) + { + _server->postEvent(new CEventDestroyWindow(this)); + return true; + } + + return false; +} + typedef bool (*cocoaProc)(NL3D::IDriver*, const void* e); void CCocoaEventEmitter::submitEvents(CEventServer& server, bool /* allWins */) diff --git a/code/nel/src/3d/driver/opengl/mac/cocoa_event_emitter.h b/code/nel/src/3d/driver/opengl/mac/cocoa_event_emitter.h index 806bb4d2c..f96cfea11 100644 --- a/code/nel/src/3d/driver/opengl/mac/cocoa_event_emitter.h +++ b/code/nel/src/3d/driver/opengl/mac/cocoa_event_emitter.h @@ -50,6 +50,7 @@ public: bool processMessage(NSEvent* event, CEventServer* server = NULL); virtual void submitEvents(CEventServer& server, bool allWindows); virtual void emulateMouseRawMode(bool enable); + bool handleQuitRequest(); virtual bool copyTextToClipboard(const ucstring &text); virtual bool pasteTextFromClipboard(ucstring &text); diff --git a/code/nel/src/3d/driver/opengl/mac/cocoa_opengl_view.m b/code/nel/src/3d/driver/opengl/mac/cocoa_opengl_view.m index bb9a4ece4..9bcec1714 100644 --- a/code/nel/src/3d/driver/opengl/mac/cocoa_opengl_view.m +++ b/code/nel/src/3d/driver/opengl/mac/cocoa_opengl_view.m @@ -18,8 +18,6 @@ #import "cocoa_opengl_view.h" -#include - namespace NL3D { void viewDidResize(NSView* view, CDriverGL* driver)