1 ///////////////////////////////////////////////////////////////////////////////
2 // Name: cocoa/toplevel.mm
3 // Purpose: implements wxTopLevelWindow for Cocoa
4 // Author: David Elliott
8 // Copyright: (c) 2002 David Elliott
9 // Licence: wxWindows licence
10 ///////////////////////////////////////////////////////////////////////////////
12 // ============================================================================
14 // ============================================================================
16 // ----------------------------------------------------------------------------
18 // ----------------------------------------------------------------------------
20 // For compilers that support precompilation, includes "wx.h".
21 #include "wx/wxprec.h"
23 #include "wx/window.h"
24 #include "wx/toplevel.h"
25 #include "wx/menuitem.h"
31 #include "wx/cocoa/autorelease.h"
32 #include "wx/cocoa/string.h"
34 #import <AppKit/NSView.h>
35 #import <AppKit/NSWindow.h>
36 #import <AppKit/NSPanel.h>
37 // ----------------------------------------------------------------------------
39 // ----------------------------------------------------------------------------
41 // list of all frames and modeless dialogs
42 wxWindowList wxModelessWindows;
44 // ============================================================================
45 // wxTopLevelWindowCocoa implementation
46 // ============================================================================
48 // ----------------------------------------------------------------------------
49 // wxTopLevelWindowCocoa creation
50 // ----------------------------------------------------------------------------
51 BEGIN_EVENT_TABLE(wxTopLevelWindowCocoa,wxTopLevelWindowBase)
52 EVT_CLOSE(wxTopLevelWindowCocoa::OnCloseWindow)
55 void wxTopLevelWindowCocoa::Init()
62 unsigned int wxTopLevelWindowCocoa::NSWindowStyleForWxStyle(long style)
64 unsigned int styleMask = 0;
66 styleMask |= NSTitledWindowMask;
67 if(style & wxMINIMIZE_BOX)
68 styleMask |= NSMiniaturizableWindowMask;
70 if(style & wxMAXIMIZE_BOX)
71 styleMask |= NSWindowMask;
73 if(style & wxCLOSE_BOX)
74 styleMask |= NSClosableWindowMask;
75 if(style & wxRESIZE_BORDER)
76 styleMask |= NSResizableWindowMask;
77 if(style & wxSIMPLE_BORDER)
78 styleMask |= NSBorderlessWindowMask;
82 bool wxTopLevelWindowCocoa::Create(wxWindow *parent,
84 const wxString& title,
90 wxAutoNSAutoreleasePool pool;
91 wxTopLevelWindows.Append(this);
93 if(!CreateBase(parent,winid,pos,size,style,wxDefaultValidator,name))
97 parent->AddChild(this);
99 unsigned int cocoaStyle = NSWindowStyleForWxStyle(style);
100 if(style & wxFRAME_TOOL_WINDOW)
101 cocoaStyle |= NSUtilityWindowMask;
103 // NOTE: y-origin needs to be flipped.
104 NSRect cocoaRect = [NSWindow contentRectForFrameRect:NSMakeRect(pos.x,pos.y,size.x,size.y) styleMask:cocoaStyle];
106 m_cocoaNSWindow = NULL;
107 m_cocoaNSView = NULL;
108 if(style & wxFRAME_TOOL_WINDOW)
109 SetNSWindow([[NSPanel alloc] initWithContentRect:cocoaRect styleMask:cocoaStyle backing:NSBackingStoreBuffered defer:NO]);
111 SetNSWindow([[NSWindow alloc] initWithContentRect:cocoaRect styleMask:cocoaStyle backing:NSBackingStoreBuffered defer:NO]);
112 // NOTE: SetNSWindow has retained the Cocoa object for this object.
113 // Because we do not release on close, the following release matches the
114 // above alloc and thus the retain count will be 1.
115 [m_cocoaNSWindow release];
117 if(style & wxFRAME_NO_TASKBAR)
118 [m_cocoaNSWindow setExcludedFromWindowsMenu: YES];
119 if(style & wxSTAY_ON_TOP)
120 [m_cocoaNSWindow setLevel:NSFloatingWindowLevel];
121 [m_cocoaNSWindow setTitle:wxNSStringWithWxString(title)];
125 wxTopLevelWindowCocoa::~wxTopLevelWindowCocoa()
127 wxAutoNSAutoreleasePool pool;
132 // ----------------------------------------------------------------------------
133 // wxTopLevelWindowCocoa Cocoa Specifics
134 // ----------------------------------------------------------------------------
136 wxMenuBar* wxTopLevelWindowCocoa::GetAppMenuBar(wxCocoaNSWindow *win)
138 wxTopLevelWindowCocoa *parent = wxDynamicCast(GetParent(),wxTopLevelWindow);
140 return parent->GetAppMenuBar(win);
144 void wxTopLevelWindowCocoa::SetNSWindow(WX_NSWindow cocoaNSWindow)
146 bool need_debug = cocoaNSWindow || m_cocoaNSWindow;
147 if(need_debug) wxLogDebug("wxTopLevelWindowCocoa=%p::SetNSWindow [m_cocoaNSWindow=%p retainCount]=%d",this,m_cocoaNSWindow,[m_cocoaNSWindow retainCount]);
148 DisassociateNSWindow(m_cocoaNSWindow);
149 [cocoaNSWindow retain];
150 [m_cocoaNSWindow release];
151 m_cocoaNSWindow = cocoaNSWindow;
153 SetNSView([m_cocoaNSWindow contentView]);
156 AssociateNSWindow(m_cocoaNSWindow);
157 if(need_debug) wxLogDebug("wxTopLevelWindowCocoa=%p::SetNSWindow [cocoaNSWindow=%p retainCount]=%d",this,cocoaNSWindow,[cocoaNSWindow retainCount]);
160 void wxTopLevelWindowCocoa::CocoaReplaceView(WX_NSView oldView, WX_NSView newView)
162 if([m_cocoaNSWindow contentView] == (id)oldView)
163 [m_cocoaNSWindow setContentView:newView];
166 void wxTopLevelWindowCocoa::CocoaDelegate_windowDidBecomeKey(void)
168 wxLogDebug("wxTopLevelWindowCocoa=%p::CocoaDelegate_windowDidBecomeKey",this);
169 wxActivateEvent event(wxEVT_ACTIVATE, TRUE, GetId());
170 event.SetEventObject(this);
171 GetEventHandler()->ProcessEvent(event);
174 void wxTopLevelWindowCocoa::CocoaDelegate_windowDidResignKey(void)
176 wxLogDebug("wxTopLevelWindowCocoa=%p::CocoaDelegate_windowDidResignKey",this);
177 wxActivateEvent event(wxEVT_ACTIVATE, FALSE, GetId());
178 event.SetEventObject(this);
179 GetEventHandler()->ProcessEvent(event);
182 void wxTopLevelWindowCocoa::CocoaDelegate_windowDidBecomeMain(void)
184 wxLogDebug("wxTopLevelWindowCocoa=%p::CocoaDelegate_windowDidBecomeMain",this);
187 void wxTopLevelWindowCocoa::CocoaDelegate_windowDidResignMain(void)
189 wxLogDebug("wxTopLevelWindowCocoa=%p::CocoaDelegate_windowDidResignMain",this);
192 void wxTopLevelWindowCocoa::CocoaDelegate_windowWillClose(void)
196 /* Be SURE that idle events get ran. If the window was not active when
197 it was closed, then there will be no more events to trigger this and
198 therefore it must be done here */
199 wxTheApp->CocoaInstallRequestedIdleHandler();
202 bool wxTopLevelWindowCocoa::CocoaDelegate_windowShouldClose()
204 return wxWindowBase::Close(false);
207 // ----------------------------------------------------------------------------
208 // wxTopLevelWindowCocoa maximize/minimize
209 // ----------------------------------------------------------------------------
211 void wxTopLevelWindowCocoa::Maximize(bool maximize)
215 bool wxTopLevelWindowCocoa::IsMaximized() const
220 void wxTopLevelWindowCocoa::Iconize(bool iconize)
224 bool wxTopLevelWindowCocoa::IsIconized() const
229 void wxTopLevelWindowCocoa::Restore()
233 bool wxTopLevelWindowCocoa::Show(bool show)
235 if(m_isShown == show)
237 wxAutoNSAutoreleasePool pool;
240 // Send the window a size event because wxWindows apps expect it
241 // NOTE: This should really only be done the first time a window
242 // is shown. I doubt this will cause any problems though.
243 wxSizeEvent event(GetSize(), GetId());
244 event.SetEventObject(this);
245 GetEventHandler()->ProcessEvent(event);
247 [m_cocoaNSWindow makeKeyAndOrderFront:m_cocoaNSWindow];
250 [m_cocoaNSWindow orderOut:m_cocoaNSWindow];
255 bool wxTopLevelWindowCocoa::Close(bool force)
258 return wxWindowBase::Close(force);
259 // performClose will fake the user clicking the close button which
260 // will invoke windowShouldClose which will call the base class version
261 // of Close() which will NOT Destroy() the window (see below) but
262 // if closing is not stopped, then performClose will go ahead and
263 // close the window which will send the close notifications setting
264 // m_closed to true and Destroy()ing the window.
265 [m_cocoaNSWindow performClose:m_cocoaNSWindow];
269 void wxTopLevelWindowCocoa::OnCloseWindow(wxCloseEvent& event)
271 // If the event was forced, close the window which will Destroy() it
273 [m_cocoaNSWindow close];
274 // if the event was not forced, it's probably because the user clicked
275 // the close button, or Close(false) was called which (see above) is
276 // redirected to performClose and thus Cocoa itself will close the window
279 // ----------------------------------------------------------------------------
280 // wxTopLevelWindowCocoa misc
281 // ----------------------------------------------------------------------------
283 bool wxTopLevelWindowCocoa::ShowFullScreen(bool show, long style)
288 bool wxTopLevelWindowCocoa::IsFullScreen() const
293 void wxTopLevelWindowCocoa::CocoaSetWxWindowSize(int width, int height)
295 // Set the NSView size by setting the frame size to enclose it
296 unsigned int styleMask = [m_cocoaNSWindow styleMask];
297 NSRect frameRect = [m_cocoaNSWindow frame];
298 NSRect contentRect = [NSWindow
299 contentRectForFrameRect: frameRect
300 styleMask: styleMask];
301 contentRect.size.width = width;
302 contentRect.size.height = height;
303 frameRect = [NSWindow
304 frameRectForContentRect: contentRect
305 styleMask: styleMask];
306 [m_cocoaNSWindow setFrame: frameRect display: NO];
309 void wxTopLevelWindowCocoa::DoMoveWindow(int x, int y, int width, int height)
311 // wxLogDebug("wxTopLevelWindow=%p::DoMoveWindow(%d,%d,%d,%d)",this,x,y,width,height);
313 NSRect cocoaRect = NSMakeRect(x,y,width,height);
314 [m_cocoaNSWindow setFrame: cocoaRect display:NO];
317 void wxTopLevelWindowCocoa::DoGetSize(int *w, int *h) const
319 NSRect cocoaRect = [m_cocoaNSWindow frame];
321 *w=(int)cocoaRect.size.width;
323 *h=(int)cocoaRect.size.height;
324 // wxLogDebug("wxTopLevelWindow=%p::DoGetSize = (%d,%d)",this,(int)cocoaRect.size.width,(int)cocoaRect.size.height);
327 void wxTopLevelWindowCocoa::DoGetPosition(int *x, int *y) const
329 NSRect cocoaRect = [m_cocoaNSWindow frame];
331 *x=(int)cocoaRect.origin.x;
333 *y=(int)cocoaRect.origin.y;
334 // wxLogDebug("wxTopLevelWindow=%p::DoGetPosition = (%d,%d)",this,(int)cocoaRect.origin.x,(int)cocoaRect.origin.y);