]> git.saurik.com Git - wxWidgets.git/blob - src/cocoa/toplevel.mm
Fix scrolling bug where client size was reported wrong
[wxWidgets.git] / src / cocoa / toplevel.mm
1 ///////////////////////////////////////////////////////////////////////////////
2 // Name: src/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: wxWidgets 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
23 #include "wx/toplevel.h"
24
25 #ifndef WX_PRECOMP
26 #include "wx/window.h"
27 #include "wx/menuitem.h"
28 #include "wx/frame.h"
29 #include "wx/log.h"
30 #include "wx/app.h"
31 #endif //WX_PRECOMP
32
33 #include "wx/cocoa/autorelease.h"
34 #include "wx/cocoa/string.h"
35
36 #import <AppKit/NSView.h>
37 #import <AppKit/NSWindow.h>
38 #import <AppKit/NSPanel.h>
39 // ----------------------------------------------------------------------------
40 // globals
41 // ----------------------------------------------------------------------------
42
43 // list of all frames and modeless dialogs
44 wxWindowList wxModelessWindows;
45
46 // ============================================================================
47 // wxTopLevelWindowCocoa implementation
48 // ============================================================================
49
50 wxTopLevelWindowCocoa *wxTopLevelWindowCocoa::sm_cocoaDeactivateWindow = NULL;
51
52 // ----------------------------------------------------------------------------
53 // wxTopLevelWindowCocoa creation
54 // ----------------------------------------------------------------------------
55 BEGIN_EVENT_TABLE(wxTopLevelWindowCocoa,wxTopLevelWindowBase)
56 EVT_CLOSE(wxTopLevelWindowCocoa::OnCloseWindow)
57 END_EVENT_TABLE()
58
59 void wxTopLevelWindowCocoa::Init()
60 {
61 m_iconized =
62 m_maximizeOnShow =
63 m_closed = false;
64 }
65
66 unsigned int wxTopLevelWindowCocoa::NSWindowStyleForWxStyle(long style)
67 {
68 unsigned int styleMask = 0;
69 if(style & wxCAPTION)
70 styleMask |= NSTitledWindowMask;
71 if(style & wxMINIMIZE_BOX)
72 styleMask |= NSMiniaturizableWindowMask;
73 #if 0
74 if(style & wxMAXIMIZE_BOX)
75 styleMask |= NSWindowMask;
76 #endif
77 if(style & wxCLOSE_BOX)
78 styleMask |= NSClosableWindowMask;
79 if(style & wxRESIZE_BORDER)
80 styleMask |= NSResizableWindowMask;
81 if(style & wxSIMPLE_BORDER)
82 styleMask |= NSBorderlessWindowMask;
83 return styleMask;
84 }
85
86 bool wxTopLevelWindowCocoa::Create(wxWindow *parent,
87 wxWindowID winid,
88 const wxString& title,
89 const wxPoint& pos,
90 const wxSize& size,
91 long style,
92 const wxString& name)
93 {
94 wxAutoNSAutoreleasePool pool;
95 wxTopLevelWindows.Append(this);
96
97 if(!CreateBase(parent,winid,pos,size,style,wxDefaultValidator,name))
98 return false;
99
100 if ( parent )
101 parent->AddChild(this);
102
103 unsigned int cocoaStyle = NSWindowStyleForWxStyle(style);
104 if(style & wxFRAME_TOOL_WINDOW)
105 cocoaStyle |= NSUtilityWindowMask;
106
107 // Create frame and check and handle default position and size
108 int realx,
109 realy;
110
111 // WX has no set default position - the carbon port caps the low
112 // end at 20, 50. Here we do the same, except instead of setting
113 // it to 20 and 50, we set it to 100 and 100 if the values are too low
114 if (pos.x < 20)
115 realx = 100;
116 else
117 realx = pos.x;
118
119 if (pos.y < 50)
120 realy = 100;
121 else
122 realy = pos.y;
123
124 int realw = WidthDefault(size.x);
125 int realh = HeightDefault(size.y);
126
127 // NOTE: y-origin needs to be flipped.
128 NSRect cocoaRect = [NSWindow
129 contentRectForFrameRect:NSMakeRect(realx,realy,realw,realh)
130 styleMask:cocoaStyle];
131
132 m_cocoaNSWindow = NULL;
133 m_cocoaNSView = NULL;
134 if(style & wxFRAME_TOOL_WINDOW)
135 SetNSWindow([[NSPanel alloc] initWithContentRect:cocoaRect styleMask:cocoaStyle backing:NSBackingStoreBuffered defer:NO]);
136 else
137 SetNSWindow([[NSWindow alloc] initWithContentRect:cocoaRect styleMask:cocoaStyle backing:NSBackingStoreBuffered defer:NO]);
138 // NOTE: SetNSWindow has retained the Cocoa object for this object.
139 // Because we do not release on close, the following release matches the
140 // above alloc and thus the retain count will be 1.
141 [m_cocoaNSWindow release];
142
143 if(style & wxFRAME_NO_TASKBAR)
144 [m_cocoaNSWindow setExcludedFromWindowsMenu: YES];
145 if(style & wxSTAY_ON_TOP)
146 [m_cocoaNSWindow setLevel:NSFloatingWindowLevel];
147 [m_cocoaNSWindow setTitle:wxNSStringWithWxString(title)];
148 return true;
149 }
150
151 wxTopLevelWindowCocoa::~wxTopLevelWindowCocoa()
152 {
153 wxASSERT(sm_cocoaDeactivateWindow!=this);
154 wxAutoNSAutoreleasePool pool;
155 DestroyChildren();
156 if(m_cocoaNSView)
157 SendDestroyEvent();
158 SetNSWindow(NULL);
159 }
160
161 bool wxTopLevelWindowCocoa::Destroy()
162 {
163 if(sm_cocoaDeactivateWindow==this)
164 {
165 sm_cocoaDeactivateWindow = NULL;
166 wxTopLevelWindowCocoa::CocoaDelegate_windowDidResignKey();
167 }
168 return wxTopLevelWindowBase::Destroy();
169 }
170
171 // ----------------------------------------------------------------------------
172 // wxTopLevelWindowCocoa Cocoa Specifics
173 // ----------------------------------------------------------------------------
174
175 wxMenuBar* wxTopLevelWindowCocoa::GetAppMenuBar(wxCocoaNSWindow *win)
176 {
177 wxTopLevelWindowCocoa *parent = wxDynamicCast(GetParent(),wxTopLevelWindow);
178 if(parent)
179 return parent->GetAppMenuBar(win);
180 return NULL;
181 }
182
183 void wxTopLevelWindowCocoa::SetNSWindow(WX_NSWindow cocoaNSWindow)
184 {
185 bool need_debug = cocoaNSWindow || m_cocoaNSWindow;
186 if(need_debug) wxLogTrace(wxTRACE_COCOA_RetainRelease,wxT("wxTopLevelWindowCocoa=%p::SetNSWindow [m_cocoaNSWindow=%p retainCount]=%d"),this,m_cocoaNSWindow,[m_cocoaNSWindow retainCount]);
187 DisassociateNSWindow(m_cocoaNSWindow);
188 [cocoaNSWindow retain];
189 [m_cocoaNSWindow release];
190 m_cocoaNSWindow = cocoaNSWindow;
191 if(m_cocoaNSWindow)
192 SetNSView([m_cocoaNSWindow contentView]);
193 else
194 SetNSView(NULL);
195 AssociateNSWindow(m_cocoaNSWindow);
196 if(need_debug) wxLogTrace(wxTRACE_COCOA_RetainRelease,wxT("wxTopLevelWindowCocoa=%p::SetNSWindow [cocoaNSWindow=%p retainCount]=%d"),this,cocoaNSWindow,[cocoaNSWindow retainCount]);
197 }
198
199 void wxTopLevelWindowCocoa::CocoaReplaceView(WX_NSView oldView, WX_NSView newView)
200 {
201 if([m_cocoaNSWindow contentView] == (id)oldView)
202 [m_cocoaNSWindow setContentView:newView];
203 }
204
205 /*static*/ void wxTopLevelWindowCocoa::DeactivatePendingWindow()
206 {
207 if(sm_cocoaDeactivateWindow)
208 sm_cocoaDeactivateWindow->wxTopLevelWindowCocoa::CocoaDelegate_windowDidResignKey();
209 sm_cocoaDeactivateWindow = NULL;
210 }
211
212 void wxTopLevelWindowCocoa::CocoaDelegate_windowDidBecomeKey(void)
213 {
214 DeactivatePendingWindow();
215 wxLogTrace(wxTRACE_COCOA,wxT("wxTopLevelWindowCocoa=%p::CocoaDelegate_windowDidBecomeKey"),this);
216 wxActivateEvent event(wxEVT_ACTIVATE, true, GetId());
217 event.SetEventObject(this);
218 GetEventHandler()->ProcessEvent(event);
219 }
220
221 void wxTopLevelWindowCocoa::CocoaDelegate_windowDidResignKey(void)
222 {
223 wxLogTrace(wxTRACE_COCOA,wxT("wxTopLevelWindowCocoa=%p::CocoaDelegate_windowDidResignKey"),this);
224 wxActivateEvent event(wxEVT_ACTIVATE, false, GetId());
225 event.SetEventObject(this);
226 GetEventHandler()->ProcessEvent(event);
227 }
228
229 void wxTopLevelWindowCocoa::CocoaDelegate_windowDidBecomeMain(void)
230 {
231 wxLogTrace(wxTRACE_COCOA,wxT("wxTopLevelWindowCocoa=%p::CocoaDelegate_windowDidBecomeMain"),this);
232 }
233
234 void wxTopLevelWindowCocoa::CocoaDelegate_windowDidResignMain(void)
235 {
236 wxLogTrace(wxTRACE_COCOA,wxT("wxTopLevelWindowCocoa=%p::CocoaDelegate_windowDidResignMain"),this);
237 }
238
239 void wxTopLevelWindowCocoa::CocoaDelegate_windowWillClose(void)
240 {
241 m_closed = true;
242 Destroy();
243 }
244
245 bool wxTopLevelWindowCocoa::CocoaDelegate_windowShouldClose()
246 {
247 return wxWindowBase::Close(false);
248 }
249
250 void wxTopLevelWindowCocoa::CocoaDelegate_wxMenuItemAction(WX_NSMenuItem menuItem)
251 {
252 }
253
254 bool wxTopLevelWindowCocoa::CocoaDelegate_validateMenuItem(WX_NSMenuItem menuItem)
255 {
256 return false;
257 }
258
259 // ----------------------------------------------------------------------------
260 // wxTopLevelWindowCocoa maximize/minimize
261 // ----------------------------------------------------------------------------
262
263 void wxTopLevelWindowCocoa::Maximize(bool maximize)
264 {
265 }
266
267 bool wxTopLevelWindowCocoa::IsMaximized() const
268 {
269 return false ;
270 }
271
272 void wxTopLevelWindowCocoa::Iconize(bool iconize)
273 {
274 }
275
276 bool wxTopLevelWindowCocoa::IsIconized() const
277 {
278 return false;
279 }
280
281 void wxTopLevelWindowCocoa::Restore()
282 {
283 }
284
285 bool wxTopLevelWindowCocoa::Show(bool show)
286 {
287 if(m_isShown == show)
288 return false;
289 wxAutoNSAutoreleasePool pool;
290 if(show)
291 {
292 // Send the window a size event because wxWidgets apps expect it
293 // NOTE: This should really only be done the first time a window
294 // is shown. I doubt this will cause any problems though.
295 wxSizeEvent event(GetSize(), GetId());
296 event.SetEventObject(this);
297 GetEventHandler()->ProcessEvent(event);
298
299 [m_cocoaNSWindow makeKeyAndOrderFront:m_cocoaNSWindow];
300 }
301 else
302 [m_cocoaNSWindow orderOut:m_cocoaNSWindow];
303 m_isShown = show;
304 return true;
305 }
306
307 bool wxTopLevelWindowCocoa::Close(bool force)
308 {
309 if(force)
310 return wxWindowBase::Close(force);
311 // performClose will fake the user clicking the close button which
312 // will invoke windowShouldClose which will call the base class version
313 // of Close() which will NOT Destroy() the window (see below) but
314 // if closing is not stopped, then performClose will go ahead and
315 // close the window which will send the close notifications setting
316 // m_closed to true and Destroy()ing the window.
317 [m_cocoaNSWindow performClose:m_cocoaNSWindow];
318 return m_closed;
319 }
320
321 void wxTopLevelWindowCocoa::OnCloseWindow(wxCloseEvent& event)
322 {
323 // If the event was forced, close the window which will Destroy() it
324 if(!event.CanVeto())
325 [m_cocoaNSWindow close];
326 // if the event was not forced, it's probably because the user clicked
327 // the close button, or Close(false) was called which (see above) is
328 // redirected to performClose and thus Cocoa itself will close the window
329 }
330
331 // ----------------------------------------------------------------------------
332 // wxTopLevelWindowCocoa misc
333 // ----------------------------------------------------------------------------
334
335 void wxTopLevelWindowCocoa::SetTitle( const wxString& WXUNUSED(title))
336 {
337 // TODO
338 }
339
340 wxString wxTopLevelWindowCocoa::GetTitle() const
341 {
342 // TODO
343 return wxEmptyString;
344 }
345
346 bool wxTopLevelWindowCocoa::ShowFullScreen(bool show, long style)
347 {
348 return false;
349 }
350
351 bool wxTopLevelWindowCocoa::IsFullScreen() const
352 {
353 return false;
354 }
355
356 void wxTopLevelWindowCocoa::CocoaSetWxWindowSize(int width, int height)
357 {
358 // Set the NSView size by setting the frame size to enclose it
359 unsigned int styleMask = [m_cocoaNSWindow styleMask];
360 NSRect frameRect = [m_cocoaNSWindow frame];
361 NSRect contentRect = [NSWindow
362 contentRectForFrameRect: frameRect
363 styleMask: styleMask];
364 contentRect.size.width = width;
365 contentRect.size.height = height;
366 frameRect = [NSWindow
367 frameRectForContentRect: contentRect
368 styleMask: styleMask];
369 [m_cocoaNSWindow setFrame: frameRect display: NO];
370 }
371
372 void wxTopLevelWindowCocoa::DoMoveWindow(int x, int y, int width, int height)
373 {
374 wxLogTrace(wxTRACE_COCOA_TopLevelWindow_Size,wxT("wxTopLevelWindow=%p::DoMoveWindow(%d,%d,%d,%d)"),this,x,y,width,height);
375
376 NSRect cocoaRect = NSMakeRect(x,y,width,height);
377 [m_cocoaNSWindow setFrame: cocoaRect display:NO];
378 }
379
380 void wxTopLevelWindowCocoa::DoGetSize(int *w, int *h) const
381 {
382 NSRect cocoaRect = [m_cocoaNSWindow frame];
383 if(w)
384 *w=(int)cocoaRect.size.width;
385 if(h)
386 *h=(int)cocoaRect.size.height;
387 wxLogTrace(wxTRACE_COCOA_TopLevelWindow_Size,wxT("wxTopLevelWindow=%p::DoGetSize = (%d,%d)"),this,(int)cocoaRect.size.width,(int)cocoaRect.size.height);
388 }
389
390 void wxTopLevelWindowCocoa::DoGetPosition(int *x, int *y) const
391 {
392 NSRect cocoaRect = [m_cocoaNSWindow frame];
393 if(x)
394 *x=(int)cocoaRect.origin.x;
395 if(y)
396 *y=(int)cocoaRect.origin.y;
397 wxLogTrace(wxTRACE_COCOA_TopLevelWindow_Size,wxT("wxTopLevelWindow=%p::DoGetPosition = (%d,%d)"),this,(int)cocoaRect.origin.x,(int)cocoaRect.origin.y);
398 }