1 /////////////////////////////////////////////////////////////////////////////
2 // Name: src/osx/cocoa/utils.mm
3 // Purpose: various cocoa utility functions
4 // Author: Stefan Csomor
7 // Copyright: (c) Stefan Csomor
8 // Licence: wxWindows licence
9 /////////////////////////////////////////////////////////////////////////////
11 #include "wx/wxprec.h"
19 #include "wx/dialog.h"
20 #include "wx/toplevel.h"
25 #include "wx/apptrait.h"
27 #include "wx/osx/private.h"
30 #if wxOSX_USE_COCOA_OR_CARBON
31 #include <CoreServices/CoreServices.h>
32 #include "wx/osx/dcclient.h"
33 #include "wx/osx/private/timer.h"
47 @implementation wxNSAppController
49 - (void)applicationWillFinishLaunching:(NSNotification *)application
51 wxUnusedVar(application);
53 // we must install our handlers later than setting the app delegate, because otherwise our handlers
54 // get overwritten in the meantime
56 NSAppleEventManager *appleEventManager = [NSAppleEventManager sharedAppleEventManager];
58 [appleEventManager setEventHandler:self andSelector:@selector(handleGetURLEvent:withReplyEvent:)
59 forEventClass:kInternetEventClass andEventID:kAEGetURL];
61 [appleEventManager setEventHandler:self andSelector:@selector(handleOpenAppEvent:withReplyEvent:)
62 forEventClass:kCoreEventClass andEventID:kAEOpenApplication];
64 wxTheApp->OSXOnWillFinishLaunching();
67 - (void)applicationDidFinishLaunching:(NSNotification *)notification
69 wxTheApp->OSXOnDidFinishLaunching();
72 - (void)application:(NSApplication *)sender openFiles:(NSArray *)fileNames
75 wxArrayString fileList;
77 const size_t count = [fileNames count];
78 for (i = 0; i < count; i++)
80 fileList.Add( wxCFStringRef::AsStringWithNormalizationFormC([fileNames objectAtIndex:i]) );
83 wxTheApp->MacOpenFiles(fileList);
86 - (BOOL)application:(NSApplication *)sender printFile:(NSString *)filename
89 wxCFStringRef cf(wxCFRetain(filename));
90 wxTheApp->MacPrintFile(cf.AsString()) ;
94 - (BOOL)applicationShouldHandleReopen:(NSApplication *)sender hasVisibleWindows:(BOOL)flag
98 wxTheApp->MacReopenApp() ;
102 - (void)handleGetURLEvent:(NSAppleEventDescriptor *)event
103 withReplyEvent:(NSAppleEventDescriptor *)replyEvent
105 wxUnusedVar(replyEvent);
106 NSString* url = [[event descriptorAtIndex:1] stringValue];
107 wxCFStringRef cf(wxCFRetain(url));
108 wxTheApp->MacOpenURL(cf.AsString()) ;
111 - (void)handleOpenAppEvent:(NSAppleEventDescriptor *)event
112 withReplyEvent:(NSAppleEventDescriptor *)replyEvent
114 wxUnusedVar(replyEvent);
115 wxTheApp->MacNewFile() ;
119 Allowable return values are:
120 NSTerminateNow - it is ok to proceed with termination
121 NSTerminateCancel - the application should not be terminated
122 NSTerminateLater - it may be ok to proceed with termination later. The application must call -replyToApplicationShouldTerminate: with YES or NO once the answer is known
123 this return value is for delegates who need to provide document modal alerts (sheets) in order to decide whether to quit.
125 - (NSApplicationTerminateReply)applicationShouldTerminate:(NSApplication *)sender
128 if ( !wxTheApp->OSXOnShouldTerminate() )
129 return NSTerminateCancel;
131 return NSTerminateNow;
134 - (void)applicationWillTerminate:(NSNotification *)application {
135 wxUnusedVar(application);
136 wxTheApp->OSXOnWillTerminate();
139 - (BOOL)applicationShouldTerminateAfterLastWindowClosed:(NSApplication *)sender
142 // let wx do this, not cocoa
146 - (void)applicationDidBecomeActive:(NSNotification *)notification
148 wxUnusedVar(notification);
150 for ( wxWindowList::const_iterator i = wxTopLevelWindows.begin(),
151 end = wxTopLevelWindows.end();
155 wxTopLevelWindow * const win = static_cast<wxTopLevelWindow *>(*i);
156 wxNonOwnedWindowImpl* winimpl = win ? win->GetNonOwnedPeer() : NULL;
157 WXWindow nswindow = win ? win->GetWXWindow() : nil;
159 if ( nswindow && [nswindow hidesOnDeactivate] == NO && winimpl)
160 winimpl->RestoreWindowLevel();
163 wxTheApp->SetActive( true , NULL ) ;
166 - (void)applicationWillResignActive:(NSNotification *)notification
168 wxUnusedVar(notification);
169 for ( wxWindowList::const_iterator i = wxTopLevelWindows.begin(),
170 end = wxTopLevelWindows.end();
174 wxTopLevelWindow * const win = static_cast<wxTopLevelWindow *>(*i);
175 WXWindow nswindow = win ? win->GetWXWindow() : nil;
177 if ( nswindow && [nswindow level] == kCGFloatingWindowLevel && [nswindow hidesOnDeactivate] == NO )
178 [nswindow setLevel:kCGNormalWindowLevel];
182 - (void)applicationDidResignActive:(NSNotification *)notification
184 wxUnusedVar(notification);
186 wxTheApp->SetActive( false , NULL ) ;
192 allows ShowModal to work when using sheets.
193 see include/wx/osx/cocoa/private.h for more info
195 @implementation ModalDialogDelegate
205 - (void)setImplementation: (wxDialog *)dialog
212 return sheetFinished;
220 - (void)waitForSheetToFinish
222 while (!sheetFinished)
228 - (void)sheetDidEnd:(NSWindow *)sheet returnCode:(int)returnCode contextInfo:(void *)contextInfo
230 wxUnusedVar(contextInfo);
231 resultCode = returnCode;
233 // NSAlerts don't need nor respond to orderOut
234 if ([sheet respondsToSelector:@selector(orderOut:)])
235 [sheet orderOut: self];
238 impl->ModalFinishedCallback(sheet, returnCode);
242 // here we subclass NSApplication, for the purpose of being able to override sendEvent.
243 @interface wxNSApplication : NSApplication
250 - (void)sendEvent:(NSEvent *)anEvent;
254 @implementation wxNSApplication
263 /* This is needed because otherwise we don't receive any key-up events for command-key
264 combinations (an AppKit bug, apparently) */
265 - (void)sendEvent:(NSEvent *)anEvent
267 if ([anEvent type] == NSKeyUp && ([anEvent modifierFlags] & NSCommandKeyMask))
268 [[self keyWindow] sendEvent:anEvent];
270 [super sendEvent:anEvent];
282 WX_NSObject appcontroller = nil;
284 NSLayoutManager* gNSLayoutManager = nil;
286 WX_NSObject wxApp::OSXCreateAppController()
288 return [[wxNSAppController alloc] init];
291 bool wxApp::DoInitGui()
293 wxMacAutoreleasePool pool;
297 [wxNSApplication sharedApplication];
299 appcontroller = OSXCreateAppController();
300 [NSApp setDelegate:appcontroller];
301 [NSColor setIgnoresAlpha:NO];
303 // calling finishLaunching so early before running the loop seems to trigger some 'MenuManager compatibility' which leads
304 // to the duplication of menus under 10.5 and a warning under 10.6
306 [NSApp finishLaunching];
309 gNSLayoutManager = [[NSLayoutManager alloc] init];
314 bool wxApp::CallOnInit()
316 wxMacAutoreleasePool autoreleasepool;
317 m_onInitResult = false;
319 return m_onInitResult;
322 void wxApp::DoCleanUp()
324 if ( appcontroller != nil )
326 [NSApp setDelegate:nil];
327 [appcontroller release];
330 if ( gNSLayoutManager != nil )
332 [gNSLayoutManager release];
333 gNSLayoutManager = nil;
337 void wxClientDisplayRect(int *x, int *y, int *width, int *height)
339 NSRect displayRect = [wxOSXGetMenuScreen() visibleFrame];
340 wxRect r = wxFromNSRect( NULL, displayRect );
346 *width = r.GetWidth();
348 *height = r.GetHeight();
352 void wxGetMousePosition( int* x, int* y )
354 wxPoint pt = wxFromNSPoint(NULL, [NSEvent mouseLocation]);
361 #if wxOSX_USE_COCOA && MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_6
363 wxMouseState wxGetMouseState()
367 wxPoint pt = wxGetMousePosition();
371 NSUInteger modifiers = [NSEvent modifierFlags];
372 NSUInteger buttons = [NSEvent pressedMouseButtons];
374 ms.SetLeftDown( (buttons & 0x01) != 0 );
375 ms.SetMiddleDown( (buttons & 0x04) != 0 );
376 ms.SetRightDown( (buttons & 0x02) != 0 );
378 ms.SetRawControlDown(modifiers & NSControlKeyMask);
379 ms.SetShiftDown(modifiers & NSShiftKeyMask);
380 ms.SetAltDown(modifiers & NSAlternateKeyMask);
381 ms.SetControlDown(modifiers & NSCommandKeyMask);
389 wxTimerImpl* wxGUIAppTraits::CreateTimerImpl(wxTimer *timer)
391 return new wxOSXTimerImpl(timer);
394 int gs_wxBusyCursorCount = 0;
395 extern wxCursor gMacCurrentCursor;
396 wxCursor gMacStoredActiveCursor;
398 // Set the cursor to the busy cursor for all windows
399 void wxBeginBusyCursor(const wxCursor *cursor)
401 if (gs_wxBusyCursorCount++ == 0)
403 NSEnumerator *enumerator = [[[NSApplication sharedApplication] windows] objectEnumerator];
406 while ((object = [enumerator nextObject])) {
407 [(NSWindow*) object disableCursorRects];
410 gMacStoredActiveCursor = gMacCurrentCursor;
411 cursor->MacInstall();
413 wxSetCursor(*cursor);
415 //else: nothing to do, already set
418 // Restore cursor to normal
419 void wxEndBusyCursor()
421 wxCHECK_RET( gs_wxBusyCursorCount > 0,
422 wxT("no matching wxBeginBusyCursor() for wxEndBusyCursor()") );
424 if (--gs_wxBusyCursorCount == 0)
426 NSEnumerator *enumerator = [[[NSApplication sharedApplication] windows] objectEnumerator];
429 while ((object = [enumerator nextObject])) {
430 [(NSWindow*) object enableCursorRects];
433 wxSetCursor(wxNullCursor);
435 gMacStoredActiveCursor.MacInstall();
436 gMacStoredActiveCursor = wxNullCursor;
440 // true if we're between the above two calls
443 return (gs_wxBusyCursorCount > 0);
446 wxBitmap wxWindowDCImpl::DoGetAsBitmap(const wxRect *subrect) const
448 // wxScreenDC is derived from wxWindowDC, so a screen dc will
449 // call this method when a Blit is performed with it as a source.
453 wxSize sz = m_window->GetSize();
455 int width = subrect != NULL ? subrect->width : sz.x;
456 int height = subrect != NULL ? subrect->height : sz.y ;
458 wxBitmap bitmap(width, height);
460 NSView* view = (NSView*) m_window->GetHandle();
461 if ( [view isHiddenOrHasHiddenAncestor] == NO )
464 // we use this method as other methods force a repaint, and this method can be
465 // called from OnPaint, even with the window's paint dc as source (see wxHTMLWindow)
466 NSBitmapImageRep *rep = [[NSBitmapImageRep alloc] initWithFocusedViewRect: [view bounds]];
468 if ( [rep respondsToSelector:@selector(CGImage)] )
470 CGImageRef cgImageRef = (CGImageRef)[rep CGImage];
472 CGRect r = CGRectMake( 0 , 0 , CGImageGetWidth(cgImageRef) , CGImageGetHeight(cgImageRef) );
473 // since our context is upside down we dont use CGContextDrawImage
474 wxMacDrawCGImage( (CGContextRef) bitmap.GetHBITMAP() , &r, cgImageRef ) ;
478 // TODO for 10.4 in case we can support this for osx_cocoa
488 #endif // wxOSX_USE_COCOA