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
129 if ( !wxTheApp->OSXOnShouldTerminate() )
130 return NSTerminateCancel;
132 return NSTerminateNow;
135 - (void)applicationWillTerminate:(NSNotification *)application {
136 wxUnusedVar(application);
137 wxTheApp->OSXOnWillTerminate();
140 - (BOOL)applicationShouldTerminateAfterLastWindowClosed:(NSApplication *)sender
143 // let wx do this, not cocoa
147 - (void)applicationDidBecomeActive:(NSNotification *)notification
149 wxUnusedVar(notification);
151 for ( wxWindowList::const_iterator i = wxTopLevelWindows.begin(),
152 end = wxTopLevelWindows.end();
156 wxTopLevelWindow * const win = static_cast<wxTopLevelWindow *>(*i);
157 wxNonOwnedWindowImpl* winimpl = win ? win->GetNonOwnedPeer() : NULL;
158 WXWindow nswindow = win ? win->GetWXWindow() : nil;
160 if ( nswindow && [nswindow hidesOnDeactivate] == NO && winimpl)
161 winimpl->RestoreWindowLevel();
164 wxTheApp->SetActive( true , NULL ) ;
167 - (void)applicationWillResignActive:(NSNotification *)notification
169 wxUnusedVar(notification);
170 for ( wxWindowList::const_iterator i = wxTopLevelWindows.begin(),
171 end = wxTopLevelWindows.end();
175 wxTopLevelWindow * const win = static_cast<wxTopLevelWindow *>(*i);
176 WXWindow nswindow = win ? win->GetWXWindow() : nil;
178 if ( nswindow && [nswindow level] == kCGFloatingWindowLevel && [nswindow hidesOnDeactivate] == NO )
179 [nswindow setLevel:kCGNormalWindowLevel];
183 - (void)applicationDidResignActive:(NSNotification *)notification
185 wxUnusedVar(notification);
187 wxTheApp->SetActive( false , NULL ) ;
193 allows ShowModal to work when using sheets.
194 see include/wx/osx/cocoa/private.h for more info
196 @implementation ModalDialogDelegate
206 - (void)setImplementation: (wxDialog *)dialog
213 return sheetFinished;
221 - (void)waitForSheetToFinish
223 while (!sheetFinished)
229 - (void)sheetDidEnd:(NSWindow *)sheet returnCode:(int)returnCode contextInfo:(void *)contextInfo
231 wxUnusedVar(contextInfo);
232 resultCode = returnCode;
234 // NSAlerts don't need nor respond to orderOut
235 if ([sheet respondsToSelector:@selector(orderOut:)])
236 [sheet orderOut: self];
239 impl->ModalFinishedCallback(sheet, returnCode);
243 // here we subclass NSApplication, for the purpose of being able to override sendEvent.
244 @interface wxNSApplication : NSApplication
248 - (void)sendEvent:(NSEvent *)anEvent;
252 @implementation wxNSApplication
254 /* This is needed because otherwise we don't receive any key-up events for command-key
255 combinations (an AppKit bug, apparently) */
256 - (void)sendEvent:(NSEvent *)anEvent
258 if ([anEvent type] == NSKeyUp && ([anEvent modifierFlags] & NSCommandKeyMask))
259 [[self keyWindow] sendEvent:anEvent];
260 else [super sendEvent:anEvent];
265 WX_NSObject appcontroller = nil;
267 NSLayoutManager* gNSLayoutManager = nil;
269 WX_NSObject wxApp::OSXCreateAppController()
271 return [[wxNSAppController alloc] init];
274 bool wxApp::DoInitGui()
276 wxMacAutoreleasePool pool;
280 [wxNSApplication sharedApplication];
282 appcontroller = OSXCreateAppController();
283 [NSApp setDelegate:appcontroller];
284 [NSColor setIgnoresAlpha:NO];
286 // calling finishLaunching so early before running the loop seems to trigger some 'MenuManager compatibility' which leads
287 // to the duplication of menus under 10.5 and a warning under 10.6
289 [NSApp finishLaunching];
292 gNSLayoutManager = [[NSLayoutManager alloc] init];
297 void wxApp::DoCleanUp()
299 if ( appcontroller != nil )
301 [NSApp setDelegate:nil];
302 [appcontroller release];
305 if ( gNSLayoutManager != nil )
307 [gNSLayoutManager release];
308 gNSLayoutManager = nil;
312 void wxClientDisplayRect(int *x, int *y, int *width, int *height)
314 NSRect displayRect = [wxOSXGetMenuScreen() visibleFrame];
315 wxRect r = wxFromNSRect( NULL, displayRect );
321 *width = r.GetWidth();
323 *height = r.GetHeight();
327 void wxGetMousePosition( int* x, int* y )
329 wxPoint pt = wxFromNSPoint(NULL, [NSEvent mouseLocation]);
336 #if wxOSX_USE_COCOA && MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_6
338 wxMouseState wxGetMouseState()
342 wxPoint pt = wxGetMousePosition();
346 NSUInteger modifiers = [NSEvent modifierFlags];
347 NSUInteger buttons = [NSEvent pressedMouseButtons];
349 ms.SetLeftDown( (buttons & 0x01) != 0 );
350 ms.SetMiddleDown( (buttons & 0x04) != 0 );
351 ms.SetRightDown( (buttons & 0x02) != 0 );
353 ms.SetRawControlDown(modifiers & NSControlKeyMask);
354 ms.SetShiftDown(modifiers & NSShiftKeyMask);
355 ms.SetAltDown(modifiers & NSAlternateKeyMask);
356 ms.SetControlDown(modifiers & NSCommandKeyMask);
364 wxTimerImpl* wxGUIAppTraits::CreateTimerImpl(wxTimer *timer)
366 return new wxOSXTimerImpl(timer);
369 int gs_wxBusyCursorCount = 0;
370 extern wxCursor gMacCurrentCursor;
371 wxCursor gMacStoredActiveCursor;
373 // Set the cursor to the busy cursor for all windows
374 void wxBeginBusyCursor(const wxCursor *cursor)
376 if (gs_wxBusyCursorCount++ == 0)
378 NSEnumerator *enumerator = [[[NSApplication sharedApplication] windows] objectEnumerator];
381 while ((object = [enumerator nextObject])) {
382 [(NSWindow*) object disableCursorRects];
385 gMacStoredActiveCursor = gMacCurrentCursor;
386 cursor->MacInstall();
388 wxSetCursor(*cursor);
390 //else: nothing to do, already set
393 // Restore cursor to normal
394 void wxEndBusyCursor()
396 wxCHECK_RET( gs_wxBusyCursorCount > 0,
397 wxT("no matching wxBeginBusyCursor() for wxEndBusyCursor()") );
399 if (--gs_wxBusyCursorCount == 0)
401 NSEnumerator *enumerator = [[[NSApplication sharedApplication] windows] objectEnumerator];
404 while ((object = [enumerator nextObject])) {
405 [(NSWindow*) object enableCursorRects];
408 wxSetCursor(wxNullCursor);
410 gMacStoredActiveCursor.MacInstall();
411 gMacStoredActiveCursor = wxNullCursor;
415 // true if we're between the above two calls
418 return (gs_wxBusyCursorCount > 0);
421 wxBitmap wxWindowDCImpl::DoGetAsBitmap(const wxRect *subrect) const
423 // wxScreenDC is derived from wxWindowDC, so a screen dc will
424 // call this method when a Blit is performed with it as a source.
428 wxSize sz = m_window->GetSize();
430 int width = subrect != NULL ? subrect->width : sz.x;
431 int height = subrect != NULL ? subrect->height : sz.y ;
433 wxBitmap bitmap(width, height);
435 NSView* view = (NSView*) m_window->GetHandle();
436 if ( [view isHiddenOrHasHiddenAncestor] == NO )
439 // we use this method as other methods force a repaint, and this method can be
440 // called from OnPaint, even with the window's paint dc as source (see wxHTMLWindow)
441 NSBitmapImageRep *rep = [[NSBitmapImageRep alloc] initWithFocusedViewRect: [view bounds]];
443 if ( [rep respondsToSelector:@selector(CGImage)] )
445 CGImageRef cgImageRef = (CGImageRef)[rep CGImage];
447 CGRect r = CGRectMake( 0 , 0 , CGImageGetWidth(cgImageRef) , CGImageGetHeight(cgImageRef) );
448 // since our context is upside down we dont use CGContextDrawImage
449 wxMacDrawCGImage( (CGContextRef) bitmap.GetHBITMAP() , &r, cgImageRef ) ;
453 // TODO for 10.4 in case we can support this for osx_cocoa
463 #endif // wxOSX_USE_COCOA