]> git.saurik.com Git - wxWidgets.git/blob - src/osx/cocoa/utils.mm
Catch attempts to create a window with itself as parent.
[wxWidgets.git] / src / osx / cocoa / utils.mm
1 /////////////////////////////////////////////////////////////////////////////
2 // Name: src/osx/cocoa/utils.mm
3 // Purpose: various cocoa utility functions
4 // Author: Stefan Csomor
5 // Modified by:
6 // Created: 1998-01-01
7 // RCS-ID: $Id$
8 // Copyright: (c) Stefan Csomor
9 // Licence: wxWindows licence
10 /////////////////////////////////////////////////////////////////////////////
11
12 #include "wx/wxprec.h"
13
14 #include "wx/utils.h"
15
16 #ifndef WX_PRECOMP
17 #include "wx/intl.h"
18 #include "wx/app.h"
19 #if wxUSE_GUI
20 #include "wx/dialog.h"
21 #include "wx/toplevel.h"
22 #include "wx/font.h"
23 #endif
24 #endif
25
26 #include "wx/apptrait.h"
27
28 #include "wx/osx/private.h"
29
30 #if wxUSE_GUI
31 #if wxOSX_USE_COCOA_OR_CARBON
32 #include <CoreServices/CoreServices.h>
33 #include "wx/osx/dcclient.h"
34 #include "wx/osx/private/timer.h"
35 #endif
36 #endif // wxUSE_GUI
37
38 #if wxOSX_USE_COCOA
39
40 #if wxUSE_GUI
41
42 // Emit a beeeeeep
43 void wxBell()
44 {
45 NSBeep();
46 }
47
48 @implementation wxNSAppController
49
50 - (void)applicationWillFinishLaunching:(NSNotification *)application {
51 wxUnusedVar(application);
52
53 // we must install our handlers later than setting the app delegate, because otherwise our handlers
54 // get overwritten in the meantime
55
56 NSAppleEventManager *appleEventManager = [NSAppleEventManager sharedAppleEventManager];
57
58 [appleEventManager setEventHandler:self andSelector:@selector(handleGetURLEvent:withReplyEvent:)
59 forEventClass:kInternetEventClass andEventID:kAEGetURL];
60
61 [appleEventManager setEventHandler:self andSelector:@selector(handleOpenAppEvent:withReplyEvent:)
62 forEventClass:kCoreEventClass andEventID:kAEOpenApplication];
63
64 }
65
66 - (void)application:(NSApplication *)sender openFiles:(NSArray *)fileNames
67 {
68 wxUnusedVar(sender);
69 wxArrayString fileList;
70 size_t i;
71 const size_t count = [fileNames count];
72 for (i = 0; i < count; i++)
73 {
74 fileList.Add( wxCFStringRef::AsStringWithNormalizationFormC([fileNames objectAtIndex:i]) );
75 }
76
77 wxTheApp->MacOpenFiles(fileList);
78 }
79
80 - (BOOL)application:(NSApplication *)sender printFile:(NSString *)filename
81 {
82 wxUnusedVar(sender);
83 wxCFStringRef cf(wxCFRetain(filename));
84 wxTheApp->MacPrintFile(cf.AsString()) ;
85 return YES;
86 }
87
88 - (BOOL)applicationShouldHandleReopen:(NSApplication *)sender hasVisibleWindows:(BOOL)flag
89 {
90 wxUnusedVar(flag);
91 wxUnusedVar(sender);
92 wxTheApp->MacReopenApp() ;
93 return NO;
94 }
95
96 - (void)handleGetURLEvent:(NSAppleEventDescriptor *)event
97 withReplyEvent:(NSAppleEventDescriptor *)replyEvent
98 {
99 wxUnusedVar(replyEvent);
100 NSString* url = [[event descriptorAtIndex:1] stringValue];
101 wxCFStringRef cf(wxCFRetain(url));
102 wxTheApp->MacOpenURL(cf.AsString()) ;
103 }
104
105 - (void)handleOpenAppEvent:(NSAppleEventDescriptor *)event
106 withReplyEvent:(NSAppleEventDescriptor *)replyEvent
107 {
108 wxUnusedVar(replyEvent);
109 wxTheApp->MacNewFile() ;
110 }
111
112 /*
113 Allowable return values are:
114 NSTerminateNow - it is ok to proceed with termination
115 NSTerminateCancel - the application should not be terminated
116 NSTerminateLater - it may be ok to proceed with termination later. The application must call -replyToApplicationShouldTerminate: with YES or NO once the answer is known
117 this return value is for delegates who need to provide document modal alerts (sheets) in order to decide whether to quit.
118 */
119 - (NSApplicationTerminateReply)applicationShouldTerminate:(NSApplication *)sender
120 {
121 wxUnusedVar(sender);
122 wxCloseEvent event;
123 wxTheApp->OnQueryEndSession(event);
124 if ( event.GetVeto() )
125 return NSTerminateCancel;
126
127 return NSTerminateNow;
128 }
129
130 - (void)applicationWillTerminate:(NSNotification *)application {
131 wxUnusedVar(application);
132 wxCloseEvent event;
133 event.SetCanVeto(false);
134 wxTheApp->OnEndSession(event);
135 }
136
137 - (BOOL)applicationShouldTerminateAfterLastWindowClosed:(NSApplication *)sender
138 {
139 wxUnusedVar(sender);
140 // let wx do this, not cocoa
141 return NO;
142 }
143
144 - (void)applicationDidBecomeActive:(NSNotification *)notification
145 {
146 wxUnusedVar(notification);
147
148 for ( wxWindowList::const_iterator i = wxTopLevelWindows.begin(),
149 end = wxTopLevelWindows.end();
150 i != end;
151 ++i )
152 {
153 wxTopLevelWindow * const win = static_cast<wxTopLevelWindow *>(*i);
154 wxNonOwnedWindowImpl* winimpl = win ? win->GetNonOwnedPeer() : NULL;
155 WXWindow nswindow = win ? win->GetWXWindow() : nil;
156
157 if ( nswindow && [nswindow hidesOnDeactivate] == NO && winimpl)
158 winimpl->RestoreWindowLevel();
159 }
160 if ( wxTheApp )
161 wxTheApp->SetActive( true , NULL ) ;
162 }
163
164 - (void)applicationWillResignActive:(NSNotification *)notification
165 {
166 wxUnusedVar(notification);
167 for ( wxWindowList::const_iterator i = wxTopLevelWindows.begin(),
168 end = wxTopLevelWindows.end();
169 i != end;
170 ++i )
171 {
172 wxTopLevelWindow * const win = static_cast<wxTopLevelWindow *>(*i);
173 WXWindow nswindow = win ? win->GetWXWindow() : nil;
174
175 if ( nswindow && [nswindow level] == kCGFloatingWindowLevel && [nswindow hidesOnDeactivate] == NO )
176 [nswindow setLevel:kCGNormalWindowLevel];
177 }
178 }
179
180 - (void)applicationDidResignActive:(NSNotification *)notification
181 {
182 wxUnusedVar(notification);
183 if ( wxTheApp )
184 wxTheApp->SetActive( false , NULL ) ;
185 }
186
187 @end
188
189 /*
190 allows ShowModal to work when using sheets.
191 see include/wx/osx/cocoa/private.h for more info
192 */
193 @implementation ModalDialogDelegate
194 - (id)init
195 {
196 self = [super init];
197 sheetFinished = NO;
198 resultCode = -1;
199 impl = 0;
200 return self;
201 }
202
203 - (void)setImplementation: (wxDialog *)dialog
204 {
205 impl = dialog;
206 }
207
208 - (BOOL)finished
209 {
210 return sheetFinished;
211 }
212
213 - (int)code
214 {
215 return resultCode;
216 }
217
218 - (void)waitForSheetToFinish
219 {
220 while (!sheetFinished)
221 {
222 wxSafeYield();
223 }
224 }
225
226 - (void)sheetDidEnd:(NSWindow *)sheet returnCode:(int)returnCode contextInfo:(void *)contextInfo
227 {
228 wxUnusedVar(contextInfo);
229 resultCode = returnCode;
230 sheetFinished = YES;
231 // NSAlerts don't need nor respond to orderOut
232 if ([sheet respondsToSelector:@selector(orderOut:)])
233 [sheet orderOut: self];
234
235 if (impl)
236 impl->ModalFinishedCallback(sheet, returnCode);
237 }
238 @end
239
240 // here we subclass NSApplication, for the purpose of being able to override sendEvent.
241 @interface wxNSApplication : NSApplication
242 {
243 }
244
245 - (void)sendEvent:(NSEvent *)anEvent;
246
247 @end
248
249 @implementation wxNSApplication
250
251 /* This is needed because otherwise we don't receive any key-up events for command-key
252 combinations (an AppKit bug, apparently) */
253 - (void)sendEvent:(NSEvent *)anEvent
254 {
255 if ([anEvent type] == NSKeyUp && ([anEvent modifierFlags] & NSCommandKeyMask))
256 [[self keyWindow] sendEvent:anEvent];
257 else [super sendEvent:anEvent];
258 }
259
260 @end
261
262 WX_NSObject appcontroller = nil;
263
264 NSLayoutManager* gNSLayoutManager = nil;
265
266 WX_NSObject wxApp::OSXCreateAppController()
267 {
268 return [[wxNSAppController alloc] init];
269 }
270
271 bool wxApp::DoInitGui()
272 {
273 wxMacAutoreleasePool pool;
274
275 if (!sm_isEmbedded)
276 {
277 [wxNSApplication sharedApplication];
278
279 appcontroller = OSXCreateAppController();
280 [NSApp setDelegate:appcontroller];
281
282 // calling finishLaunching so early before running the loop seems to trigger some 'MenuManager compatibility' which leads
283 // to the duplication of menus under 10.5 and a warning under 10.6
284 #if 0
285 [NSApp finishLaunching];
286 #endif
287 }
288 gNSLayoutManager = [[NSLayoutManager alloc] init];
289
290 return true;
291 }
292
293 void wxApp::DoCleanUp()
294 {
295 if ( appcontroller != nil )
296 {
297 [NSApp setDelegate:nil];
298 [appcontroller release];
299 appcontroller = nil;
300 }
301 if ( gNSLayoutManager != nil )
302 {
303 [gNSLayoutManager release];
304 gNSLayoutManager = nil;
305 }
306 }
307
308 void wxClientDisplayRect(int *x, int *y, int *width, int *height)
309 {
310 NSRect displayRect = [wxOSXGetMenuScreen() visibleFrame];
311 wxRect r = wxFromNSRect( NULL, displayRect );
312 if ( x )
313 *x = r.x;
314 if ( y )
315 *y = r.y;
316 if ( width )
317 *width = r.GetWidth();
318 if ( height )
319 *height = r.GetHeight();
320
321 }
322
323 void wxGetMousePosition( int* x, int* y )
324 {
325 wxPoint pt = wxFromNSPoint(NULL, [NSEvent mouseLocation]);
326 if ( x )
327 *x = pt.x;
328 if ( y )
329 *y = pt.y;
330 };
331
332 #if wxOSX_USE_COCOA && MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_6
333
334 wxMouseState wxGetMouseState()
335 {
336 wxMouseState ms;
337
338 wxPoint pt = wxGetMousePosition();
339 ms.SetX(pt.x);
340 ms.SetY(pt.y);
341
342 NSUInteger modifiers = [NSEvent modifierFlags];
343 NSUInteger buttons = [NSEvent pressedMouseButtons];
344
345 ms.SetLeftDown( (buttons & 0x01) != 0 );
346 ms.SetMiddleDown( (buttons & 0x04) != 0 );
347 ms.SetRightDown( (buttons & 0x02) != 0 );
348
349 ms.SetRawControlDown(modifiers & NSControlKeyMask);
350 ms.SetShiftDown(modifiers & NSShiftKeyMask);
351 ms.SetAltDown(modifiers & NSAlternateKeyMask);
352 ms.SetControlDown(modifiers & NSCommandKeyMask);
353
354 return ms;
355 }
356
357
358 #endif
359
360 wxTimerImpl* wxGUIAppTraits::CreateTimerImpl(wxTimer *timer)
361 {
362 return new wxOSXTimerImpl(timer);
363 }
364
365 int gs_wxBusyCursorCount = 0;
366 extern wxCursor gMacCurrentCursor;
367 wxCursor gMacStoredActiveCursor;
368
369 // Set the cursor to the busy cursor for all windows
370 void wxBeginBusyCursor(const wxCursor *cursor)
371 {
372 if (gs_wxBusyCursorCount++ == 0)
373 {
374 NSEnumerator *enumerator = [[[NSApplication sharedApplication] windows] objectEnumerator];
375 id object;
376
377 while ((object = [enumerator nextObject])) {
378 [(NSWindow*) object disableCursorRects];
379 }
380
381 gMacStoredActiveCursor = gMacCurrentCursor;
382 cursor->MacInstall();
383
384 wxSetCursor(*cursor);
385 }
386 //else: nothing to do, already set
387 }
388
389 // Restore cursor to normal
390 void wxEndBusyCursor()
391 {
392 wxCHECK_RET( gs_wxBusyCursorCount > 0,
393 wxT("no matching wxBeginBusyCursor() for wxEndBusyCursor()") );
394
395 if (--gs_wxBusyCursorCount == 0)
396 {
397 NSEnumerator *enumerator = [[[NSApplication sharedApplication] windows] objectEnumerator];
398 id object;
399
400 while ((object = [enumerator nextObject])) {
401 [(NSWindow*) object enableCursorRects];
402 }
403
404 wxSetCursor(wxNullCursor);
405
406 gMacStoredActiveCursor.MacInstall();
407 gMacStoredActiveCursor = wxNullCursor;
408 }
409 }
410
411 // true if we're between the above two calls
412 bool wxIsBusy()
413 {
414 return (gs_wxBusyCursorCount > 0);
415 }
416
417 wxBitmap wxWindowDCImpl::DoGetAsBitmap(const wxRect *subrect) const
418 {
419 // wxScreenDC is derived from wxWindowDC, so a screen dc will
420 // call this method when a Blit is performed with it as a source.
421 if (!m_window)
422 return wxNullBitmap;
423
424 wxSize sz = m_window->GetSize();
425
426 int width = subrect != NULL ? subrect->width : sz.x;
427 int height = subrect != NULL ? subrect->height : sz.y ;
428
429 wxBitmap bitmap(width, height);
430
431 NSView* view = (NSView*) m_window->GetHandle();
432 if ( [view isHiddenOrHasHiddenAncestor] == NO )
433 {
434 [view lockFocus];
435 // we use this method as other methods force a repaint, and this method can be
436 // called from OnPaint, even with the window's paint dc as source (see wxHTMLWindow)
437 NSBitmapImageRep *rep = [[NSBitmapImageRep alloc] initWithFocusedViewRect: [view bounds]];
438 [view unlockFocus];
439 if ( [rep respondsToSelector:@selector(CGImage)] )
440 {
441 CGImageRef cgImageRef = (CGImageRef)[rep CGImage];
442
443 CGRect r = CGRectMake( 0 , 0 , CGImageGetWidth(cgImageRef) , CGImageGetHeight(cgImageRef) );
444 // since our context is upside down we dont use CGContextDrawImage
445 wxMacDrawCGImage( (CGContextRef) bitmap.GetHBITMAP() , &r, cgImageRef ) ;
446 }
447 else
448 {
449 // TODO for 10.4 in case we can support this for osx_cocoa
450 }
451 [rep release];
452 }
453
454 return bitmap;
455 }
456
457 #endif // wxUSE_GUI
458
459 #endif // wxOSX_USE_COCOA