Files
wxWidgets/src/cocoa/evtloop.mm
2003-10-09 15:56:38 +00:00

145 lines
4.5 KiB
Plaintext

///////////////////////////////////////////////////////////////////////////////
// Name: cocoa/evtloop.mm
// Purpose: implements wxEventLoop for Cocoa
// Author: David Elliott
// Modified by:
// Created: 2003/10/02
// RCS-ID: $Id$
// Copyright: (c) 2003 David Elliott <dfe@cox.net>
// License: wxWindows licence
///////////////////////////////////////////////////////////////////////////////
#include "wx/wxprec.h"
#ifndef WX_PRECOMP
#include "wx/log.h"
#endif //WX_PRECOMP
#include "wx/evtloop.h"
#import <AppKit/NSApplication.h>
#import <AppKit/NSEvent.h>
#import <Foundation/NSRunLoop.h>
// ========================================================================
// wxEventLoopImpl
// ========================================================================
class WXDLLEXPORT wxEventLoopImpl
{
public:
// ctor
wxEventLoopImpl() { SetExitCode(0); }
// set/get the exit code
void SetExitCode(int exitcode) { m_exitcode = exitcode; }
int GetExitCode() const { return m_exitcode; }
private:
// the exit code of the event loop
int m_exitcode;
};
// ========================================================================
// wxEventLoop
// ========================================================================
// ----------------------------------------------------------------------------
// wxEventLoop running and exiting
// ----------------------------------------------------------------------------
wxEventLoop *wxEventLoop::ms_activeLoop = NULL;
wxEventLoop::~wxEventLoop()
{
wxASSERT_MSG( !m_impl, _T("should have been deleted in Run()") );
}
bool wxEventLoop::IsRunning() const
{
return m_impl;
}
int wxEventLoop::Run()
{
// event loops are not recursive, you need to create another loop!
wxCHECK_MSG( !IsRunning(), -1, _T("can't reenter a message loop") );
wxEventLoop *oldLoop = ms_activeLoop;
ms_activeLoop = this;
m_impl = new wxEventLoopImpl;
[[NSApplication sharedApplication] run];
int exitcode = m_impl->GetExitCode();
delete m_impl;
m_impl = NULL;
ms_activeLoop = oldLoop;
return exitcode;
}
void wxEventLoop::Exit(int rc)
{
wxCHECK_RET( IsRunning(), _T("can't call Exit() if not running") );
m_impl->SetExitCode(rc);
NSApplication *cocoaApp = [NSApplication sharedApplication];
wxLogDebug("wxEventLoop::Exit isRunning=%d", (int)[cocoaApp isRunning]);
// This works around a bug in Cocoa.
[NSEvent startPeriodicEventsAfterDelay:0.0 withPeriod:5.0];
/* Notes:
This function is most often called during idle time. See
wxApp::CocoaInstallIdleHandler() for an overview of the implications
of idle event time. In short, Cocoa must have at least one real event
in the queue (of which an idle "event" is not) in order for it to
realize that the application has been stopped. The above method
generates the first periodic event immediately, and would generate
further events every 5 seconds if not for the fact that the next
method stops the event loop.
If the application was active when closed then this is unnecessary
because it would receive a deactivate event anyway. However, if the
application was not active when closed, then no events would be
added to the queue by Cocoa and thus the application would wait
indefinitely for the next event.
*/
[cocoaApp stop: cocoaApp];
}
// ----------------------------------------------------------------------------
// wxEventLoop message processing dispatching
// ----------------------------------------------------------------------------
bool wxEventLoop::Pending() const
{
// a pointer to the event is returned if there is one, or nil if not
return [[NSApplication sharedApplication]
nextEventMatchingMask: NSAnyEventMask
untilDate: nil /* Equivalent to [NSDate distantPast] */
inMode: NSDefaultRunLoopMode
dequeue: NO];
}
bool wxEventLoop::Dispatch()
{
// This check is required by wxGTK but probably not really for wxCocoa
// Keep it here to encourage developers to write cross-platform code
wxCHECK_MSG( IsRunning(), false, _T("can't call Dispatch() if not running") );
NSApplication *cocoaApp = [NSApplication sharedApplication];
// Block to retrieve an event then send it
if(NSEvent *event = [cocoaApp
nextEventMatchingMask:NSAnyEventMask
untilDate:[NSDate distantFuture]
inMode:NSDefaultRunLoopMode
dequeue: YES])
{
[cocoaApp sendEvent: event];
return true;
}
return false;
}