* Added NSWindowStyleForWxStyle static method
[wxWidgets.git] / src / cocoa / toplevel.mm
1 ///////////////////////////////////////////////////////////////////////////////
2 // Name:        cocoa/toplevel.mm
3 // Purpose:     implements wxTopLevelWindow for Cocoa
4 // Author:      David Elliott 
5 // Modified by:
6 // Created:     2002/11/27
7 // RCS-ID:      $Id:
8 // Copyright:   (c) 2002 David Elliott
9 // License:     wxWindows license
10 ///////////////////////////////////////////////////////////////////////////////
11
12 // ============================================================================
13 // declarations
14 // ============================================================================
15
16 // ----------------------------------------------------------------------------
17 // headers
18 // ----------------------------------------------------------------------------
19
20 // For compilers that support precompilation, includes "wx.h".
21 #include "wx/wxprec.h"
22 #ifndef WX_PRECOMP
23     #include "wx/window.h"
24     #include "wx/toplevel.h"
25     #include "wx/menuitem.h"
26     #include "wx/frame.h"
27     #include "wx/log.h"
28     #include "wx/app.h"
29 #endif //WX_PRECOMP
30
31 #include "wx/cocoa/autorelease.h"
32 #include "wx/cocoa/string.h"
33 #include "wx/cocoa/mbarman.h"
34
35 #import <AppKit/NSView.h>
36 #import <AppKit/NSWindow.h>
37 #import <AppKit/NSPanel.h>
38 // ----------------------------------------------------------------------------
39 // globals
40 // ----------------------------------------------------------------------------
41
42 // list of all frames and modeless dialogs
43 wxWindowList       wxModelessWindows;
44
45 // ============================================================================
46 // wxTopLevelWindowCocoa implementation
47 // ============================================================================
48
49 // ----------------------------------------------------------------------------
50 // wxTopLevelWindowCocoa creation
51 // ----------------------------------------------------------------------------
52 BEGIN_EVENT_TABLE(wxTopLevelWindowCocoa,wxTopLevelWindowBase)
53     EVT_CLOSE(wxTopLevelWindowCocoa::OnCloseWindow)
54 END_EVENT_TABLE()
55
56 void wxTopLevelWindowCocoa::Init()
57 {
58     m_iconized =
59     m_maximizeOnShow =
60     m_closed = false;
61 }
62
63 unsigned int wxTopLevelWindowCocoa::NSWindowStyleForWxStyle(long style)
64 {
65     unsigned int styleMask = 0;
66     if(style & wxCAPTION)
67         styleMask |= NSTitledWindowMask;
68     if(style & wxMINIMIZE_BOX)
69         styleMask |= NSMiniaturizableWindowMask;
70     #if 0
71     if(style & wxMAXIMIZE_BOX)
72         styleMask |= NSWindowMask;
73         #endif
74     if(style & wxCLOSE_BOX)
75         styleMask |= NSClosableWindowMask;
76     if(style & wxRESIZE_BORDER)
77         styleMask |= NSResizableWindowMask;
78     if(style & wxSIMPLE_BORDER)
79         styleMask |= NSBorderlessWindowMask;
80     return styleMask;
81 }
82
83 bool wxTopLevelWindowCocoa::Create(wxWindow *parent,
84                                  wxWindowID winid,
85                                  const wxString& title,
86                                  const wxPoint& pos,
87                                  const wxSize& size,
88                                  long style,
89                                  const wxString& name)
90 {
91     wxAutoNSAutoreleasePool pool;
92     wxTopLevelWindows.Append(this);
93
94     if(!CreateBase(parent,winid,pos,size,style,wxDefaultValidator,name))
95         return FALSE;
96
97     if ( parent )
98         parent->AddChild(this);
99
100     unsigned int cocoaStyle = NSWindowStyleForWxStyle(style);
101     if(style & wxFRAME_TOOL_WINDOW)
102         cocoaStyle |= NSUtilityWindowMask;
103
104     // NOTE: y-origin needs to be flipped.
105     NSRect cocoaRect = [NSWindow contentRectForFrameRect:NSMakeRect(pos.x,pos.y,size.x,size.y) styleMask:cocoaStyle];
106
107     m_cocoaNSWindow = NULL;
108     m_cocoaNSView = NULL;
109     if(style & wxFRAME_TOOL_WINDOW)
110         SetNSWindow([[NSPanel alloc] initWithContentRect:cocoaRect styleMask:cocoaStyle backing:NSBackingStoreBuffered defer:NO]);
111     else
112         SetNSWindow([[NSWindow alloc] initWithContentRect:cocoaRect styleMask:cocoaStyle backing:NSBackingStoreBuffered defer:NO]);
113     // NOTE: SetNSWindow has retained the Cocoa object for this object.
114     // Because we do not release on close, the following release matches the
115     // above alloc and thus the retain count will be 1.
116     [m_cocoaNSWindow release];
117
118     if(style & wxFRAME_NO_TASKBAR)
119         [m_cocoaNSWindow setExcludedFromWindowsMenu: YES];
120     if(style & wxSTAY_ON_TOP)
121         [m_cocoaNSWindow setLevel:NSFloatingWindowLevel];
122     [m_cocoaNSWindow setTitle:wxNSStringWithWxString(title)];
123     return TRUE;
124 }
125
126 wxTopLevelWindowCocoa::~wxTopLevelWindowCocoa()
127 {
128     wxAutoNSAutoreleasePool pool;
129     DestroyChildren();
130     SetNSWindow(NULL);
131 }
132
133 // ----------------------------------------------------------------------------
134 // wxTopLevelWindowCocoa Cocoa Specifics
135 // ----------------------------------------------------------------------------
136
137 void wxTopLevelWindowCocoa::SetNSWindow(WX_NSWindow cocoaNSWindow)
138 {
139     bool need_debug = cocoaNSWindow || m_cocoaNSWindow;
140     if(need_debug) wxLogDebug("wxTopLevelWindowCocoa=%p::SetNSWindow [m_cocoaNSWindow=%p retainCount]=%d",this,m_cocoaNSWindow,[m_cocoaNSWindow retainCount]);
141     DisassociateNSWindow(m_cocoaNSWindow);
142     [cocoaNSWindow retain];
143     [m_cocoaNSWindow release];
144     m_cocoaNSWindow = cocoaNSWindow;
145     if(m_cocoaNSWindow)
146         SetNSView([m_cocoaNSWindow contentView]);
147     else
148         SetNSView(NULL);
149     AssociateNSWindow(m_cocoaNSWindow);
150     if(need_debug) wxLogDebug("wxTopLevelWindowCocoa=%p::SetNSWindow [cocoaNSWindow=%p retainCount]=%d",this,cocoaNSWindow,[cocoaNSWindow retainCount]);
151 }
152
153 void wxTopLevelWindowCocoa::CocoaReplaceView(WX_NSView oldView, WX_NSView newView)
154 {
155     if([m_cocoaNSWindow contentView] == (id)oldView)
156         [m_cocoaNSWindow setContentView:newView];
157 }
158
159 void wxTopLevelWindowCocoa::CocoaDelegate_windowDidBecomeKey(void)
160 {
161     wxLogDebug("wxTopLevelWindowCocoa=%p::CocoaDelegate_windowDidBecomeKey",this);
162     wxMenuBarManager::GetInstance()->WindowDidBecomeKey(this);
163     wxActivateEvent event(wxEVT_ACTIVATE, TRUE, GetId());
164     event.SetEventObject(this);
165     GetEventHandler()->ProcessEvent(event);
166 }
167
168 void wxTopLevelWindowCocoa::CocoaDelegate_windowDidResignKey(void)
169 {
170     wxLogDebug("wxTopLevelWindowCocoa=%p::CocoaDelegate_windowDidResignKey",this);
171     wxActivateEvent event(wxEVT_ACTIVATE, FALSE, GetId());
172     event.SetEventObject(this);
173     GetEventHandler()->ProcessEvent(event);
174     wxMenuBarManager::GetInstance()->WindowDidResignKey(this);
175 }
176
177 void wxTopLevelWindowCocoa::CocoaDelegate_windowDidBecomeMain(void)
178 {
179     wxLogDebug("wxTopLevelWindowCocoa=%p::CocoaDelegate_windowDidBecomeMain",this);
180     wxMenuBarManager::GetInstance()->WindowDidBecomeMain(this);
181 }
182
183 void wxTopLevelWindowCocoa::CocoaDelegate_windowDidResignMain(void)
184 {
185     wxLogDebug("wxTopLevelWindowCocoa=%p::CocoaDelegate_windowDidResignMain",this);
186     wxMenuBarManager::GetInstance()->WindowDidResignMain(this);
187 }
188
189 void wxTopLevelWindowCocoa::Cocoa_close(void)
190 {
191     m_closed = true;
192     Destroy();
193     /* Be SURE that idle events get ran.  If the window was not active when
194     it was closed, then there will be no more events to trigger this and
195     therefore it must be done here */
196     wxTheApp->CocoaInstallRequestedIdleHandler();
197 }
198
199 bool wxTopLevelWindowCocoa::CocoaDelegate_windowShouldClose()
200 {
201     return wxWindowBase::Close(false);
202 }
203
204 // ----------------------------------------------------------------------------
205 // wxTopLevelWindowCocoa maximize/minimize
206 // ----------------------------------------------------------------------------
207
208 void wxTopLevelWindowCocoa::Maximize(bool maximize)
209 {
210 }
211
212 bool wxTopLevelWindowCocoa::IsMaximized() const
213 {
214     return false ; 
215 }
216
217 void wxTopLevelWindowCocoa::Iconize(bool iconize)
218 {
219 }
220
221 bool wxTopLevelWindowCocoa::IsIconized() const
222 {
223     return FALSE;
224 }
225
226 void wxTopLevelWindowCocoa::Restore()
227 {
228 }
229
230 bool wxTopLevelWindowCocoa::Show(bool show)
231 {
232     if(m_isShown == show)
233         return false;
234     wxAutoNSAutoreleasePool pool;
235     if(show)
236     {
237         // Send the window a size event because wxWindows apps expect it
238         // NOTE: This should really only be done the first time a window
239         // is shown.  I doubt this will cause any problems though.
240         wxSizeEvent event(GetSize(), GetId());
241         event.SetEventObject(this);
242         GetEventHandler()->ProcessEvent(event);
243
244         [m_cocoaNSWindow makeKeyAndOrderFront:m_cocoaNSWindow];
245     }
246     else
247         [m_cocoaNSWindow orderOut:m_cocoaNSWindow];
248     m_isShown = show;
249     return true;
250 }
251
252 bool wxTopLevelWindowCocoa::Close(bool force)
253 {
254     if(force)
255         return wxWindowBase::Close(force);
256     // performClose  will fake the user clicking the close button which
257     // will invoke windowShouldClose which will call the base class version
258     // of Close() which will NOT Destroy() the window (see below) but
259     // if closing is not stopped, then performClose will go ahead and
260     // close the window which will invoke Cocoa_close() setting m_closed
261     // to true and Destroy()ing the window.
262     [m_cocoaNSWindow performClose:m_cocoaNSWindow];
263     return m_closed;
264 }
265
266 void wxTopLevelWindowCocoa::OnCloseWindow(wxCloseEvent& event)
267 {
268     // If the event was forced, close the window which will Destroy() it
269     if(!event.CanVeto())
270         [m_cocoaNSWindow close];
271     // if the event was not forced, it's probably because the user clicked
272     // the close button, or Close(false) was called which (see above) is
273     // redirected to performClose and thus Cocoa itself will close the window
274 }
275
276 // ----------------------------------------------------------------------------
277 // wxTopLevelWindowCocoa misc
278 // ----------------------------------------------------------------------------
279
280 bool wxTopLevelWindowCocoa::ShowFullScreen(bool show, long style)
281 {
282     return FALSE;
283 }
284
285 bool wxTopLevelWindowCocoa::IsFullScreen() const
286 {
287     return FALSE;
288 }
289
290 void wxTopLevelWindowCocoa::CocoaSetWxWindowSize(int width, int height)
291 {
292     // Set the NSView size by setting the frame size to enclose it
293     unsigned int styleMask = [m_cocoaNSWindow styleMask];
294     NSRect frameRect = [m_cocoaNSWindow frame];
295     NSRect contentRect = [NSWindow
296         contentRectForFrameRect: frameRect
297         styleMask: styleMask];
298     contentRect.size.width = width;
299     contentRect.size.height = height;
300     frameRect = [NSWindow
301         frameRectForContentRect: contentRect
302         styleMask: styleMask];
303     [m_cocoaNSWindow setFrame: frameRect display: NO];
304 }
305
306 void wxTopLevelWindowCocoa::DoMoveWindow(int x, int y, int width, int height)
307 {
308 //    wxLogDebug("wxTopLevelWindow=%p::DoMoveWindow(%d,%d,%d,%d)",this,x,y,width,height);
309
310     NSRect cocoaRect = NSMakeRect(x,y,width,height);
311     [m_cocoaNSWindow setFrame: cocoaRect display:NO];
312 }
313
314 void wxTopLevelWindowCocoa::DoGetSize(int *w, int *h) const
315 {
316     NSRect cocoaRect = [m_cocoaNSWindow frame];
317     if(w)
318         *w=(int)cocoaRect.size.width;
319     if(h)
320         *h=(int)cocoaRect.size.height;
321 //    wxLogDebug("wxTopLevelWindow=%p::DoGetSize = (%d,%d)",this,(int)cocoaRect.size.width,(int)cocoaRect.size.height);
322 }
323
324 void wxTopLevelWindowCocoa::DoGetPosition(int *x, int *y) const
325 {
326     NSRect cocoaRect = [m_cocoaNSWindow frame];
327     if(x)
328         *x=(int)cocoaRect.origin.x;
329     if(y)
330         *y=(int)cocoaRect.origin.y;
331 //    wxLogDebug("wxTopLevelWindow=%p::DoGetPosition = (%d,%d)",this,(int)cocoaRect.origin.x,(int)cocoaRect.origin.y);
332 }
333