1/////////////////////////////////////////////////////////////////////////////
2// Name:        src/cocoa/dialog.mm
3// Purpose:     wxDialog class
4// Author:      David Elliott
5// Modified by:
6// Created:     2002/12/15
7// Copyright:   2002 David Elliott
8// Licence:     wxWindows licence
9/////////////////////////////////////////////////////////////////////////////
10
11#include "wx/wxprec.h"
12
13#include "wx/dialog.h"
14
15#ifndef WX_PRECOMP
16    #include "wx/log.h"
17    #include "wx/app.h"
18    #include "wx/settings.h"
19#endif //WX_PRECOMP
20
21#include "wx/modalhook.h"
22#include "wx/cocoa/autorelease.h"
23#include "wx/cocoa/string.h"
24
25#import <AppKit/NSPanel.h>
26#import <AppKit/NSApplication.h>
27#import <AppKit/NSEvent.h>
28#import <Foundation/NSRunLoop.h>
29
30// Lists to keep track of windows, so we can disable/enable them
31// for modal dialogs
32static wxWindowList wxModalDialogs;
33
34IMPLEMENT_DYNAMIC_CLASS(wxDialog, wxTopLevelWindow)
35
36WX_IMPLEMENT_COCOA_OWNER(wxDialog,NSPanel,NSWindow,NSWindow)
37
38void wxDialog::Init()
39{
40    m_isModal = false;
41    SetBackgroundColour(wxSystemSettings::GetColour(wxSYS_COLOUR_3DFACE));
42}
43
44bool wxDialog::Create(wxWindow *parent, wxWindowID winid,
45           const wxString& title,
46           const wxPoint& pos,
47           const wxSize& size,
48           long style,
49           const wxString& name)
50{
51    wxAutoNSAutoreleasePool pool;
52    wxTopLevelWindows.Append(this);
53
54    if(!CreateBase(parent,winid,pos,size,style,wxDefaultValidator,name))
55        return false;
56
57    if (parent)
58        parent->AddChild(this);
59
60    unsigned int cocoaStyle = NSWindowStyleForWxStyle(style);
61
62    NSRect cocoaRect = MakeInitialNSWindowContentRect(pos,size,cocoaStyle);
63
64    m_cocoaNSWindow = NULL;
65    SetNSPanel([[NSPanel alloc] initWithContentRect:cocoaRect styleMask:cocoaStyle backing:NSBackingStoreBuffered defer:NO]);
66    // NOTE: SetNSWindow has retained the Cocoa object for this object.
67    // Because we do not release on close, the following release matches the
68    // above alloc and thus the retain count will be 1.
69    [m_cocoaNSWindow release];
70    wxLogTrace(wxTRACE_COCOA_RetainRelease,wxT("wxDialog m_cocoaNSWindow retainCount=%d"),[m_cocoaNSWindow retainCount]);
71    [m_cocoaNSWindow setTitle:wxNSStringWithWxString(title)];
72    [m_cocoaNSWindow setHidesOnDeactivate:NO];
73
74    return true;
75}
76
77wxDialog::~wxDialog()
78{
79    DisassociateNSPanel(GetNSPanel());
80}
81
82void wxDialog::CocoaDelegate_windowWillClose(void)
83{
84    m_closed = true;
85    /* Actually, this isn't true anymore */
86    wxLogTrace(wxTRACE_COCOA,wxT("Woah: Dialogs are not generally closed"));
87}
88
89void wxDialog::SetModal(bool flag)
90{
91    wxFAIL_MSG( wxT("wxDialog:SetModal obsolete now") );
92}
93
94bool wxDialog::Show(bool show)
95{
96    if(m_isShown == show)
97        return false;
98
99    if(show)
100    {
101        wxAutoNSAutoreleasePool pool;
102
103    	if (CanDoLayoutAdaptation())
104        	DoLayoutAdaptation();
105
106        InitDialog();
107        if(IsModal())
108        {   // ShowModal() will show the dialog
109            m_isShown = true;
110            return true;
111        }
112    }
113    else
114    {
115        if(IsModal())
116        {   // this doesn't hide the dialog, base class Show(false) does.
117            wxLogTrace(wxTRACE_COCOA,wxT("abortModal"));
118            [wxTheApp->GetNSApplication() abortModal];
119            wxModalDialogs.DeleteObject(this);
120            m_isModal = false;
121        }
122    }
123    return wxTopLevelWindow::Show(show);
124}
125
126// Shows the dialog and begins a modal event loop.  When the event loop
127// is stopped (via EndModal()) it returns the exit code.
128int wxDialog::ShowModal()
129{
130    WX_HOOK_MODAL_DIALOG();
131
132    wxCHECK_MSG(!IsModal(),GetReturnCode(),wxT("wxDialog::ShowModal called within its own modal loop"));
133
134    // Show(true) will set m_isShown = true
135    m_isShown = false;
136    m_isModal = true;
137    wxModalDialogs.Append(this);
138
139    wxLogTrace(wxTRACE_COCOA,wxT("runModal"));
140    NSApplication *theNSApp = wxTheApp->GetNSApplication();
141    // If the app hasn't started, flush the event queue
142    // If we don't do this, the Dock doesn't get the message that
143    // the app has started so will refuse to activate it.
144    if(![theNSApp isRunning])
145    {
146        // We should only do a few iterations so one pool should be okay
147        wxAutoNSAutoreleasePool pool;
148        while(NSEvent *event = [theNSApp
149                    nextEventMatchingMask:NSAnyEventMask
150                    untilDate:[NSDate distantPast]
151                    inMode:NSDefaultRunLoopMode
152                    dequeue: YES])
153        {
154            [theNSApp sendEvent: event];
155        }
156    }
157
158    Show(true);
159    do {
160        wxAutoNSAutoreleasePool pool;
161        [wxTheApp->GetNSApplication() runModalForWindow:m_cocoaNSWindow];
162    } while(0);
163    wxLogTrace(wxTRACE_COCOA,wxT("runModal END"));
164
165    return GetReturnCode();
166}
167
168void wxDialog::EndModal(int retCode)
169{
170    wxASSERT_MSG(IsModal(), wxT("EndModal() should only be used within ShowModal()"));
171    SetReturnCode(retCode);
172    Show(false);
173}
174