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