Implement Pending and Dispatch
[wxWidgets.git] / src / cocoa / evtloop.mm
1 ///////////////////////////////////////////////////////////////////////////////
2 // Name:        cocoa/evtloop.mm
3 // Purpose:     implements wxEventLoop for Cocoa
4 // Author:      David Elliott
5 // Modified by:
6 // Created:     2003/10/02
7 // RCS-ID:      $Id$
8 // Copyright:   (c) 2003 David Elliott <dfe@cox.net>
9 // License:     wxWindows licence
10 ///////////////////////////////////////////////////////////////////////////////
11
12 #include "wx/wxprec.h"
13 #ifndef WX_PRECOMP
14     #include "wx/log.h"
15 #endif //WX_PRECOMP
16
17 #include "wx/evtloop.h"
18
19 #import <AppKit/NSApplication.h>
20 #import <AppKit/NSEvent.h>
21 #import <Foundation/NSRunLoop.h>
22
23 // ========================================================================
24 // wxEventLoopImpl
25 // ========================================================================
26
27 class WXDLLEXPORT wxEventLoopImpl
28 {
29 public:
30     // ctor
31     wxEventLoopImpl() { SetExitCode(0); }
32
33     // set/get the exit code
34     void SetExitCode(int exitcode) { m_exitcode = exitcode; }
35     int GetExitCode() const { return m_exitcode; }
36
37 private:
38     // the exit code of the event loop
39     int m_exitcode;
40 };
41
42 // ========================================================================
43 // wxEventLoop
44 // ========================================================================
45
46 // ----------------------------------------------------------------------------
47 // wxEventLoop running and exiting
48 // ----------------------------------------------------------------------------
49
50 wxEventLoop *wxEventLoop::ms_activeLoop = NULL;
51
52 wxEventLoop::~wxEventLoop()
53 {
54     wxASSERT_MSG( !m_impl, _T("should have been deleted in Run()") );
55 }
56
57 bool wxEventLoop::IsRunning() const
58 {
59     return m_impl;
60 }
61
62 int wxEventLoop::Run()
63 {
64     // event loops are not recursive, you need to create another loop!
65     wxCHECK_MSG( !IsRunning(), -1, _T("can't reenter a message loop") );
66
67     wxEventLoop *oldLoop = ms_activeLoop;
68     ms_activeLoop = this;
69
70     m_impl = new wxEventLoopImpl;
71
72     [[NSApplication sharedApplication] run];
73
74     int exitcode = m_impl->GetExitCode();
75     delete m_impl;
76     m_impl = NULL;
77
78     ms_activeLoop = oldLoop;
79
80     return exitcode;
81 }
82
83 void wxEventLoop::Exit(int rc)
84 {
85     wxCHECK_RET( IsRunning(), _T("can't call Exit() if not running") );
86
87     m_impl->SetExitCode(rc);
88
89     NSApplication *cocoaApp = [NSApplication sharedApplication];
90     wxLogDebug("wxEventLoop::Exit isRunning=%d", (int)[cocoaApp isRunning]);
91     [cocoaApp stop: cocoaApp];
92 }
93
94 // ----------------------------------------------------------------------------
95 // wxEventLoop message processing dispatching
96 // ----------------------------------------------------------------------------
97
98 bool wxEventLoop::Pending() const
99 {
100     // a pointer to the event is returned if there is one, or nil if not
101     return [[NSApplication sharedApplication]
102             nextEventMatchingMask: NSAnyEventMask
103             untilDate: nil /* Equivalent to [NSDate distantPast] */
104             inMode: NSDefaultRunLoopMode
105             dequeue: NO];
106 }
107
108 bool wxEventLoop::Dispatch()
109 {
110     // This check is required by wxGTK but probably not really for wxCocoa
111     // Keep it here to encourage developers to write cross-platform code
112     wxCHECK_MSG( IsRunning(), false, _T("can't call Dispatch() if not running") );
113     NSApplication *cocoaApp = [NSApplication sharedApplication];
114     // Block to retrieve an event then send it
115     if(NSEvent *event = [cocoaApp
116                 nextEventMatchingMask:NSAnyEventMask
117                 untilDate:[NSDate distantFuture]
118                 inMode:NSDefaultRunLoopMode
119                 dequeue: YES])
120     {
121         [cocoaApp sendEvent: event];
122         return true;
123     }
124     return false;
125 }
126