1 /////////////////////////////////////////////////////////////////////////////
2 // Name: src/osx/cocoa/utils.mm
3 // Purpose: various cocoa utility functions
4 // Author: Stefan Csomor
8 // Copyright: (c) Stefan Csomor
9 // Licence: wxWindows licence
10 /////////////////////////////////////////////////////////////////////////////
12 #include "wx/wxprec.h"
20 #include "wx/dialog.h"
21 #include "wx/toplevel.h"
26 #include "wx/apptrait.h"
28 #include "wx/osx/private.h"
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"
48 @implementation wxNSAppController
50 - (void)applicationWillFinishLaunching:(NSNotification *)application
52 wxUnusedVar(application);
54 // we must install our handlers later than setting the app delegate, because otherwise our handlers
55 // get overwritten in the meantime
57 NSAppleEventManager *appleEventManager = [NSAppleEventManager sharedAppleEventManager];
59 [appleEventManager setEventHandler:self andSelector:@selector(handleGetURLEvent:withReplyEvent:)
60 forEventClass:kInternetEventClass andEventID:kAEGetURL];
62 [appleEventManager setEventHandler:self andSelector:@selector(handleOpenAppEvent:withReplyEvent:)
63 forEventClass:kCoreEventClass andEventID:kAEOpenApplication];
65 wxTheApp->OSXOnWillFinishLaunching();
68 - (void)applicationDidFinishLaunching:(NSNotification *)notification
70 wxTheApp->OSXOnDidFinishLaunching();
73 - (void)application:(NSApplication *)sender openFiles:(NSArray *)fileNames
76 wxArrayString fileList;
78 const size_t count = [fileNames count];
79 for (i = 0; i < count; i++)
81 fileList.Add( wxCFStringRef::AsStringWithNormalizationFormC([fileNames objectAtIndex:i]) );
84 wxTheApp->MacOpenFiles(fileList);
87 - (BOOL)application:(NSApplication *)sender printFile:(NSString *)filename
90 wxCFStringRef cf(wxCFRetain(filename));
91 wxTheApp->MacPrintFile(cf.AsString()) ;
95 - (BOOL)applicationShouldHandleReopen:(NSApplication *)sender hasVisibleWindows:(BOOL)flag
99 wxTheApp->MacReopenApp() ;
103 - (void)handleGetURLEvent:(NSAppleEventDescriptor *)event
104 withReplyEvent:(NSAppleEventDescriptor *)replyEvent
106 wxUnusedVar(replyEvent);
107 NSString* url = [[event descriptorAtIndex:1] stringValue];
108 wxCFStringRef cf(wxCFRetain(url));
109 wxTheApp->MacOpenURL(cf.AsString()) ;
112 - (void)handleOpenAppEvent:(NSAppleEventDescriptor *)event
113 withReplyEvent:(NSAppleEventDescriptor *)replyEvent
115 wxUnusedVar(replyEvent);
116 wxTheApp->MacNewFile() ;
120 Allowable return values are:
121 NSTerminateNow - it is ok to proceed with termination
122 NSTerminateCancel - the application should not be terminated
123 NSTerminateLater - it may be ok to proceed with termination later. The application must call -replyToApplicationShouldTerminate: with YES or NO once the answer is known
124 this return value is for delegates who need to provide document modal alerts (sheets) in order to decide whether to quit.
126 - (NSApplicationTerminateReply)applicationShouldTerminate:(NSApplication *)sender
130 wxTheApp->OnQueryEndSession(event);
131 if ( event.GetVeto() )
132 return NSTerminateCancel;
134 return NSTerminateNow;
137 - (void)applicationWillTerminate:(NSNotification *)application {
138 wxUnusedVar(application);
140 event.SetCanVeto(false);
141 wxTheApp->OnEndSession(event);
144 - (BOOL)applicationShouldTerminateAfterLastWindowClosed:(NSApplication *)sender
147 // let wx do this, not cocoa
151 - (void)applicationDidBecomeActive:(NSNotification *)notification
153 wxUnusedVar(notification);
155 for ( wxWindowList::const_iterator i = wxTopLevelWindows.begin(),
156 end = wxTopLevelWindows.end();
160 wxTopLevelWindow * const win = static_cast<wxTopLevelWindow *>(*i);
161 wxNonOwnedWindowImpl* winimpl = win ? win->GetNonOwnedPeer() : NULL;
162 WXWindow nswindow = win ? win->GetWXWindow() : nil;
164 if ( nswindow && [nswindow hidesOnDeactivate] == NO && winimpl)
165 winimpl->RestoreWindowLevel();
168 wxTheApp->SetActive( true , NULL ) ;
171 - (void)applicationWillResignActive:(NSNotification *)notification
173 wxUnusedVar(notification);
174 for ( wxWindowList::const_iterator i = wxTopLevelWindows.begin(),
175 end = wxTopLevelWindows.end();
179 wxTopLevelWindow * const win = static_cast<wxTopLevelWindow *>(*i);
180 WXWindow nswindow = win ? win->GetWXWindow() : nil;
182 if ( nswindow && [nswindow level] == kCGFloatingWindowLevel && [nswindow hidesOnDeactivate] == NO )
183 [nswindow setLevel:kCGNormalWindowLevel];
187 - (void)applicationDidResignActive:(NSNotification *)notification
189 wxUnusedVar(notification);
191 wxTheApp->SetActive( false , NULL ) ;
197 allows ShowModal to work when using sheets.
198 see include/wx/osx/cocoa/private.h for more info
200 @implementation ModalDialogDelegate
210 - (void)setImplementation: (wxDialog *)dialog
217 return sheetFinished;
225 - (void)waitForSheetToFinish
227 while (!sheetFinished)
233 - (void)sheetDidEnd:(NSWindow *)sheet returnCode:(int)returnCode contextInfo:(void *)contextInfo
235 wxUnusedVar(contextInfo);
236 resultCode = returnCode;
238 // NSAlerts don't need nor respond to orderOut
239 if ([sheet respondsToSelector:@selector(orderOut:)])
240 [sheet orderOut: self];
243 impl->ModalFinishedCallback(sheet, returnCode);
247 // here we subclass NSApplication, for the purpose of being able to override sendEvent.
248 @interface wxNSApplication : NSApplication
252 - (void)sendEvent:(NSEvent *)anEvent;
256 @implementation wxNSApplication
258 /* This is needed because otherwise we don't receive any key-up events for command-key
259 combinations (an AppKit bug, apparently) */
260 - (void)sendEvent:(NSEvent *)anEvent
262 if ([anEvent type] == NSKeyUp && ([anEvent modifierFlags] & NSCommandKeyMask))
263 [[self keyWindow] sendEvent:anEvent];
264 else [super sendEvent:anEvent];
269 WX_NSObject appcontroller = nil;
271 NSLayoutManager* gNSLayoutManager = nil;
273 WX_NSObject wxApp::OSXCreateAppController()
275 return [[wxNSAppController alloc] init];
278 bool wxApp::DoInitGui()
280 wxMacAutoreleasePool pool;
284 [wxNSApplication sharedApplication];
286 appcontroller = OSXCreateAppController();
287 [NSApp setDelegate:appcontroller];
288 [NSColor setIgnoresAlpha:NO];
290 // calling finishLaunching so early before running the loop seems to trigger some 'MenuManager compatibility' which leads
291 // to the duplication of menus under 10.5 and a warning under 10.6
293 [NSApp finishLaunching];
296 gNSLayoutManager = [[NSLayoutManager alloc] init];
301 void wxApp::DoCleanUp()
303 if ( appcontroller != nil )
305 [NSApp setDelegate:nil];
306 [appcontroller release];
309 if ( gNSLayoutManager != nil )
311 [gNSLayoutManager release];
312 gNSLayoutManager = nil;
316 void wxClientDisplayRect(int *x, int *y, int *width, int *height)
318 NSRect displayRect = [wxOSXGetMenuScreen() visibleFrame];
319 wxRect r = wxFromNSRect( NULL, displayRect );
325 *width = r.GetWidth();
327 *height = r.GetHeight();
331 void wxGetMousePosition( int* x, int* y )
333 wxPoint pt = wxFromNSPoint(NULL, [NSEvent mouseLocation]);
340 #if wxOSX_USE_COCOA && MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_6
342 wxMouseState wxGetMouseState()
346 wxPoint pt = wxGetMousePosition();
350 NSUInteger modifiers = [NSEvent modifierFlags];
351 NSUInteger buttons = [NSEvent pressedMouseButtons];
353 ms.SetLeftDown( (buttons & 0x01) != 0 );
354 ms.SetMiddleDown( (buttons & 0x04) != 0 );
355 ms.SetRightDown( (buttons & 0x02) != 0 );
357 ms.SetRawControlDown(modifiers & NSControlKeyMask);
358 ms.SetShiftDown(modifiers & NSShiftKeyMask);
359 ms.SetAltDown(modifiers & NSAlternateKeyMask);
360 ms.SetControlDown(modifiers & NSCommandKeyMask);
368 wxTimerImpl* wxGUIAppTraits::CreateTimerImpl(wxTimer *timer)
370 return new wxOSXTimerImpl(timer);
373 int gs_wxBusyCursorCount = 0;
374 extern wxCursor gMacCurrentCursor;
375 wxCursor gMacStoredActiveCursor;
377 // Set the cursor to the busy cursor for all windows
378 void wxBeginBusyCursor(const wxCursor *cursor)
380 if (gs_wxBusyCursorCount++ == 0)
382 NSEnumerator *enumerator = [[[NSApplication sharedApplication] windows] objectEnumerator];
385 while ((object = [enumerator nextObject])) {
386 [(NSWindow*) object disableCursorRects];
389 gMacStoredActiveCursor = gMacCurrentCursor;
390 cursor->MacInstall();
392 wxSetCursor(*cursor);
394 //else: nothing to do, already set
397 // Restore cursor to normal
398 void wxEndBusyCursor()
400 wxCHECK_RET( gs_wxBusyCursorCount > 0,
401 wxT("no matching wxBeginBusyCursor() for wxEndBusyCursor()") );
403 if (--gs_wxBusyCursorCount == 0)
405 NSEnumerator *enumerator = [[[NSApplication sharedApplication] windows] objectEnumerator];
408 while ((object = [enumerator nextObject])) {
409 [(NSWindow*) object enableCursorRects];
412 wxSetCursor(wxNullCursor);
414 gMacStoredActiveCursor.MacInstall();
415 gMacStoredActiveCursor = wxNullCursor;
419 // true if we're between the above two calls
422 return (gs_wxBusyCursorCount > 0);
425 wxBitmap wxWindowDCImpl::DoGetAsBitmap(const wxRect *subrect) const
427 // wxScreenDC is derived from wxWindowDC, so a screen dc will
428 // call this method when a Blit is performed with it as a source.
432 wxSize sz = m_window->GetSize();
434 int width = subrect != NULL ? subrect->width : sz.x;
435 int height = subrect != NULL ? subrect->height : sz.y ;
437 wxBitmap bitmap(width, height);
439 NSView* view = (NSView*) m_window->GetHandle();
440 if ( [view isHiddenOrHasHiddenAncestor] == NO )
443 // we use this method as other methods force a repaint, and this method can be
444 // called from OnPaint, even with the window's paint dc as source (see wxHTMLWindow)
445 NSBitmapImageRep *rep = [[NSBitmapImageRep alloc] initWithFocusedViewRect: [view bounds]];
447 if ( [rep respondsToSelector:@selector(CGImage)] )
449 CGImageRef cgImageRef = (CGImageRef)[rep CGImage];
451 CGRect r = CGRectMake( 0 , 0 , CGImageGetWidth(cgImageRef) , CGImageGetHeight(cgImageRef) );
452 // since our context is upside down we dont use CGContextDrawImage
453 wxMacDrawCGImage( (CGContextRef) bitmap.GetHBITMAP() , &r, cgImageRef ) ;
457 // TODO for 10.4 in case we can support this for osx_cocoa
467 #endif // wxOSX_USE_COCOA