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 {
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];
66 - (void)application:(NSApplication *)sender openFiles:(NSArray *)fileNames
69 wxArrayString fileList;
71 const size_t count = [fileNames count];
72 for (i = 0; i < count; i++)
74 fileList.Add( wxCFStringRef::AsStringWithNormalizationFormC([fileNames objectAtIndex:i]) );
77 wxTheApp->MacOpenFiles(fileList);
80 - (BOOL)application:(NSApplication *)sender printFile:(NSString *)filename
83 wxCFStringRef cf(wxCFRetain(filename));
84 wxTheApp->MacPrintFile(cf.AsString()) ;
88 - (BOOL)applicationShouldHandleReopen:(NSApplication *)sender hasVisibleWindows:(BOOL)flag
92 wxTheApp->MacReopenApp() ;
96 - (void)handleGetURLEvent:(NSAppleEventDescriptor *)event
97 withReplyEvent:(NSAppleEventDescriptor *)replyEvent
99 wxUnusedVar(replyEvent);
100 NSString* url = [[event descriptorAtIndex:1] stringValue];
101 wxCFStringRef cf(wxCFRetain(url));
102 wxTheApp->MacOpenURL(cf.AsString()) ;
105 - (void)handleOpenAppEvent:(NSAppleEventDescriptor *)event
106 withReplyEvent:(NSAppleEventDescriptor *)replyEvent
108 wxUnusedVar(replyEvent);
109 wxTheApp->MacNewFile() ;
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.
119 - (NSApplicationTerminateReply)applicationShouldTerminate:(NSApplication *)sender
123 wxTheApp->OnQueryEndSession(event);
124 if ( event.GetVeto() )
125 return NSTerminateCancel;
127 return NSTerminateNow;
130 - (void)applicationWillTerminate:(NSNotification *)application {
131 wxUnusedVar(application);
133 event.SetCanVeto(false);
134 wxTheApp->OnEndSession(event);
137 - (BOOL)applicationShouldTerminateAfterLastWindowClosed:(NSApplication *)sender
140 // let wx do this, not cocoa
144 - (void)applicationDidBecomeActive:(NSNotification *)notification
146 wxUnusedVar(notification);
148 for ( wxWindowList::const_iterator i = wxTopLevelWindows.begin(),
149 end = wxTopLevelWindows.end();
153 wxTopLevelWindow * const win = static_cast<wxTopLevelWindow *>(*i);
154 wxNonOwnedWindowImpl* winimpl = win ? win->GetNonOwnedPeer() : NULL;
155 WXWindow nswindow = win ? win->GetWXWindow() : nil;
157 if ( nswindow && [nswindow hidesOnDeactivate] == NO && winimpl)
158 winimpl->RestoreWindowLevel();
161 wxTheApp->SetActive( true , NULL ) ;
164 - (void)applicationWillResignActive:(NSNotification *)notification
166 wxUnusedVar(notification);
167 for ( wxWindowList::const_iterator i = wxTopLevelWindows.begin(),
168 end = wxTopLevelWindows.end();
172 wxTopLevelWindow * const win = static_cast<wxTopLevelWindow *>(*i);
173 WXWindow nswindow = win ? win->GetWXWindow() : nil;
175 if ( nswindow && [nswindow level] == kCGFloatingWindowLevel && [nswindow hidesOnDeactivate] == NO )
176 [nswindow setLevel:kCGNormalWindowLevel];
180 - (void)applicationDidResignActive:(NSNotification *)notification
182 wxUnusedVar(notification);
184 wxTheApp->SetActive( false , NULL ) ;
190 allows ShowModal to work when using sheets.
191 see include/wx/osx/cocoa/private.h for more info
193 @implementation ModalDialogDelegate
203 - (void)setImplementation: (wxDialog *)dialog
210 return sheetFinished;
218 - (void)waitForSheetToFinish
220 while (!sheetFinished)
226 - (void)sheetDidEnd:(NSWindow *)sheet returnCode:(int)returnCode contextInfo:(void *)contextInfo
228 wxUnusedVar(contextInfo);
229 resultCode = returnCode;
231 // NSAlerts don't need nor respond to orderOut
232 if ([sheet respondsToSelector:@selector(orderOut:)])
233 [sheet orderOut: self];
236 impl->ModalFinishedCallback(sheet, returnCode);
240 // here we subclass NSApplication, for the purpose of being able to override sendEvent.
241 @interface wxNSApplication : NSApplication
245 - (void)sendEvent:(NSEvent *)anEvent;
249 @implementation wxNSApplication
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
255 if ([anEvent type] == NSKeyUp && ([anEvent modifierFlags] & NSCommandKeyMask))
256 [[self keyWindow] sendEvent:anEvent];
257 else [super sendEvent:anEvent];
262 WX_NSObject appcontroller = nil;
264 NSLayoutManager* gNSLayoutManager = nil;
266 WX_NSObject wxApp::OSXCreateAppController()
268 return [[wxNSAppController alloc] init];
271 bool wxApp::DoInitGui()
273 wxMacAutoreleasePool pool;
277 [wxNSApplication sharedApplication];
279 appcontroller = OSXCreateAppController();
280 [NSApp setDelegate:appcontroller];
281 [NSColor setIgnoresAlpha:NO];
283 // calling finishLaunching so early before running the loop seems to trigger some 'MenuManager compatibility' which leads
284 // to the duplication of menus under 10.5 and a warning under 10.6
286 [NSApp finishLaunching];
289 gNSLayoutManager = [[NSLayoutManager alloc] init];
294 void wxApp::DoCleanUp()
296 if ( appcontroller != nil )
298 [NSApp setDelegate:nil];
299 [appcontroller release];
302 if ( gNSLayoutManager != nil )
304 [gNSLayoutManager release];
305 gNSLayoutManager = nil;
309 void wxClientDisplayRect(int *x, int *y, int *width, int *height)
311 NSRect displayRect = [wxOSXGetMenuScreen() visibleFrame];
312 wxRect r = wxFromNSRect( NULL, displayRect );
318 *width = r.GetWidth();
320 *height = r.GetHeight();
324 void wxGetMousePosition( int* x, int* y )
326 wxPoint pt = wxFromNSPoint(NULL, [NSEvent mouseLocation]);
333 #if wxOSX_USE_COCOA && MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_6
335 wxMouseState wxGetMouseState()
339 wxPoint pt = wxGetMousePosition();
343 NSUInteger modifiers = [NSEvent modifierFlags];
344 NSUInteger buttons = [NSEvent pressedMouseButtons];
346 ms.SetLeftDown( (buttons & 0x01) != 0 );
347 ms.SetMiddleDown( (buttons & 0x04) != 0 );
348 ms.SetRightDown( (buttons & 0x02) != 0 );
350 ms.SetRawControlDown(modifiers & NSControlKeyMask);
351 ms.SetShiftDown(modifiers & NSShiftKeyMask);
352 ms.SetAltDown(modifiers & NSAlternateKeyMask);
353 ms.SetControlDown(modifiers & NSCommandKeyMask);
361 wxTimerImpl* wxGUIAppTraits::CreateTimerImpl(wxTimer *timer)
363 return new wxOSXTimerImpl(timer);
366 int gs_wxBusyCursorCount = 0;
367 extern wxCursor gMacCurrentCursor;
368 wxCursor gMacStoredActiveCursor;
370 // Set the cursor to the busy cursor for all windows
371 void wxBeginBusyCursor(const wxCursor *cursor)
373 if (gs_wxBusyCursorCount++ == 0)
375 NSEnumerator *enumerator = [[[NSApplication sharedApplication] windows] objectEnumerator];
378 while ((object = [enumerator nextObject])) {
379 [(NSWindow*) object disableCursorRects];
382 gMacStoredActiveCursor = gMacCurrentCursor;
383 cursor->MacInstall();
385 wxSetCursor(*cursor);
387 //else: nothing to do, already set
390 // Restore cursor to normal
391 void wxEndBusyCursor()
393 wxCHECK_RET( gs_wxBusyCursorCount > 0,
394 wxT("no matching wxBeginBusyCursor() for wxEndBusyCursor()") );
396 if (--gs_wxBusyCursorCount == 0)
398 NSEnumerator *enumerator = [[[NSApplication sharedApplication] windows] objectEnumerator];
401 while ((object = [enumerator nextObject])) {
402 [(NSWindow*) object enableCursorRects];
405 wxSetCursor(wxNullCursor);
407 gMacStoredActiveCursor.MacInstall();
408 gMacStoredActiveCursor = wxNullCursor;
412 // true if we're between the above two calls
415 return (gs_wxBusyCursorCount > 0);
418 wxBitmap wxWindowDCImpl::DoGetAsBitmap(const wxRect *subrect) const
420 // wxScreenDC is derived from wxWindowDC, so a screen dc will
421 // call this method when a Blit is performed with it as a source.
425 wxSize sz = m_window->GetSize();
427 int width = subrect != NULL ? subrect->width : sz.x;
428 int height = subrect != NULL ? subrect->height : sz.y ;
430 wxBitmap bitmap(width, height);
432 NSView* view = (NSView*) m_window->GetHandle();
433 if ( [view isHiddenOrHasHiddenAncestor] == NO )
436 // we use this method as other methods force a repaint, and this method can be
437 // called from OnPaint, even with the window's paint dc as source (see wxHTMLWindow)
438 NSBitmapImageRep *rep = [[NSBitmapImageRep alloc] initWithFocusedViewRect: [view bounds]];
440 if ( [rep respondsToSelector:@selector(CGImage)] )
442 CGImageRef cgImageRef = (CGImageRef)[rep CGImage];
444 CGRect r = CGRectMake( 0 , 0 , CGImageGetWidth(cgImageRef) , CGImageGetHeight(cgImageRef) );
445 // since our context is upside down we dont use CGContextDrawImage
446 wxMacDrawCGImage( (CGContextRef) bitmap.GetHBITMAP() , &r, cgImageRef ) ;
450 // TODO for 10.4 in case we can support this for osx_cocoa
460 #endif // wxOSX_USE_COCOA