]> git.saurik.com Git - wxWidgets.git/blame - src/osx/cocoa/utils.mm
Add wxTimer::StartOnce().
[wxWidgets.git] / src / osx / cocoa / utils.mm
CommitLineData
33e90275 1/////////////////////////////////////////////////////////////////////////////
0f9b48d1 2// Name: src/osx/cocoa/utils.mm
33e90275
SC
3// Purpose: various cocoa utility functions
4// Author: Stefan Csomor
5// Modified by:
6// Created: 1998-01-01
a9a4f229 7// RCS-ID: $Id$
33e90275
SC
8// Copyright: (c) Stefan Csomor
9// Licence: wxWindows licence
10/////////////////////////////////////////////////////////////////////////////
11
12#include "wx/wxprec.h"
13
33e90275
SC
14#include "wx/utils.h"
15
16#ifndef WX_PRECOMP
17 #include "wx/intl.h"
18 #include "wx/app.h"
19 #if wxUSE_GUI
bfa92264 20 #include "wx/dialog.h"
33e90275
SC
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
33e90275 32 #include <CoreServices/CoreServices.h>
928e7a7e 33 #include "wx/osx/dcclient.h"
33e90275
SC
34 #include "wx/osx/private/timer.h"
35#endif
36#endif // wxUSE_GUI
37
38#if wxOSX_USE_COCOA
39
598fe99d 40#if wxUSE_GUI
33e90275
SC
41
42// Emit a beeeeeep
43void wxBell()
44{
45 NSBeep();
46}
47
c6aa5caf
SC
48@implementation wxNSAppController
49
a5d0c88a 50- (void)applicationWillFinishLaunching:(NSNotification *)application {
175e9d71 51 wxUnusedVar(application);
77aa5fa0 52
6a0d7a98
SC
53 // we must install our handlers later than setting the app delegate, because otherwise our handlers
54 // get overwritten in the meantime
77aa5fa0
SC
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
c6aa5caf
SC
64}
65
ee7553e9 66- (void)application:(NSApplication *)sender openFiles:(NSArray *)fileNames
c6aa5caf 67{
d8207702 68 wxUnusedVar(sender);
ee7553e9
DS
69 wxArrayString fileList;
70 size_t i;
71 const size_t count = [fileNames count];
72 for (i = 0; i < count; i++)
73 {
31895560 74 fileList.Add( wxCFStringRef::AsStringWithNormalizationFormC([fileNames objectAtIndex:i]) );
ee7553e9
DS
75 }
76
77 wxTheApp->MacOpenFiles(fileList);
c6aa5caf
SC
78}
79
c6aa5caf
SC
80- (BOOL)application:(NSApplication *)sender printFile:(NSString *)filename
81{
d8207702 82 wxUnusedVar(sender);
c6aa5caf
SC
83 wxCFStringRef cf(wxCFRetain(filename));
84 wxTheApp->MacPrintFile(cf.AsString()) ;
85 return YES;
86}
87
175e9d71
SC
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
77aa5fa0
SC
105- (void)handleOpenAppEvent:(NSAppleEventDescriptor *)event
106 withReplyEvent:(NSAppleEventDescriptor *)replyEvent
107{
108 wxUnusedVar(replyEvent);
109 wxTheApp->MacNewFile() ;
110}
111
945eac79 112/*
c6aa5caf
SC
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{
d8207702 121 wxUnusedVar(sender);
175e9d71
SC
122 wxCloseEvent event;
123 wxTheApp->OnQueryEndSession(event);
124 if ( event.GetVeto() )
125 return NSTerminateCancel;
126
127 return NSTerminateNow;
c6aa5caf
SC
128}
129
a5d0c88a 130- (void)applicationWillTerminate:(NSNotification *)application {
175e9d71
SC
131 wxUnusedVar(application);
132 wxCloseEvent event;
133 event.SetCanVeto(false);
134 wxTheApp->OnEndSession(event);
135}
136
137- (BOOL)applicationShouldTerminateAfterLastWindowClosed:(NSApplication *)sender
c6aa5caf 138{
d8207702 139 wxUnusedVar(sender);
175e9d71 140 // let wx do this, not cocoa
c6aa5caf
SC
141 return NO;
142}
143
74518cea
SC
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
c6aa5caf
SC
187@end
188
03647350 189/*
724999ee 190 allows ShowModal to work when using sheets.
03647350 191 see include/wx/osx/cocoa/private.h for more info
724999ee
KO
192*/
193@implementation ModalDialogDelegate
194- (id)init
195{
e5062a31 196 self = [super init];
724999ee
KO
197 sheetFinished = NO;
198 resultCode = -1;
bfa92264 199 impl = 0;
724999ee
KO
200 return self;
201}
202
bfa92264
KO
203- (void)setImplementation: (wxDialog *)dialog
204{
205 impl = dialog;
206}
207
03647350 208- (BOOL)finished
724999ee
KO
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{
d8207702 228 wxUnusedVar(contextInfo);
724999ee
KO
229 resultCode = returnCode;
230 sheetFinished = YES;
037f9d3b
KO
231 // NSAlerts don't need nor respond to orderOut
232 if ([sheet respondsToSelector:@selector(orderOut:)])
233 [sheet orderOut: self];
bfa92264
KO
234
235 if (impl)
236 impl->ModalFinishedCallback(sheet, returnCode);
724999ee
KO
237}
238@end
239
ee6a122f
SC
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
395506ea 262WX_NSObject appcontroller = nil;
e1875c78 263
befe64ed
SC
264NSLayoutManager* gNSLayoutManager = nil;
265
395506ea
SC
266WX_NSObject wxApp::OSXCreateAppController()
267{
268 return [[wxNSAppController alloc] init];
269}
befe64ed 270
dbeddfb9
SC
271bool wxApp::DoInitGui()
272{
ab9df4fb 273 wxMacAutoreleasePool pool;
c6aa5caf
SC
274
275 if (!sm_isEmbedded)
276 {
ee6a122f
SC
277 [wxNSApplication sharedApplication];
278
395506ea 279 appcontroller = OSXCreateAppController();
e1875c78 280 [NSApp setDelegate:appcontroller];
7aa09d43 281 [NSColor setIgnoresAlpha:NO];
945eac79 282
e8f25fcf
SC
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
285#if 0
cc96f525 286 [NSApp finishLaunching];
e8f25fcf 287#endif
c6aa5caf 288 }
befe64ed
SC
289 gNSLayoutManager = [[NSLayoutManager alloc] init];
290
dbeddfb9
SC
291 return true;
292}
293
294void wxApp::DoCleanUp()
295{
e1875c78
SC
296 if ( appcontroller != nil )
297 {
298 [NSApp setDelegate:nil];
299 [appcontroller release];
300 appcontroller = nil;
301 }
befe64ed
SC
302 if ( gNSLayoutManager != nil )
303 {
304 [gNSLayoutManager release];
305 gNSLayoutManager = nil;
306 }
dbeddfb9 307}
33e90275 308
33e90275
SC
309void wxClientDisplayRect(int *x, int *y, int *width, int *height)
310{
5d57348e 311 NSRect displayRect = [wxOSXGetMenuScreen() visibleFrame];
33e90275
SC
312 wxRect r = wxFromNSRect( NULL, displayRect );
313 if ( x )
314 *x = r.x;
315 if ( y )
316 *y = r.y;
317 if ( width )
318 *width = r.GetWidth();
319 if ( height )
320 *height = r.GetHeight();
945eac79 321
33e90275
SC
322}
323
324void wxGetMousePosition( int* x, int* y )
325{
326 wxPoint pt = wxFromNSPoint(NULL, [NSEvent mouseLocation]);
54f11060
SC
327 if ( x )
328 *x = pt.x;
329 if ( y )
330 *y = pt.y;
33e90275
SC
331};
332
f3769d53
SC
333#if wxOSX_USE_COCOA && MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_6
334
335wxMouseState wxGetMouseState()
336{
337 wxMouseState ms;
338
339 wxPoint pt = wxGetMousePosition();
340 ms.SetX(pt.x);
341 ms.SetY(pt.y);
342
343 NSUInteger modifiers = [NSEvent modifierFlags];
344 NSUInteger buttons = [NSEvent pressedMouseButtons];
345
346 ms.SetLeftDown( (buttons & 0x01) != 0 );
347 ms.SetMiddleDown( (buttons & 0x04) != 0 );
348 ms.SetRightDown( (buttons & 0x02) != 0 );
349
8b14528f 350 ms.SetRawControlDown(modifiers & NSControlKeyMask);
f3769d53
SC
351 ms.SetShiftDown(modifiers & NSShiftKeyMask);
352 ms.SetAltDown(modifiers & NSAlternateKeyMask);
dd9ec596 353 ms.SetControlDown(modifiers & NSCommandKeyMask);
f3769d53
SC
354
355 return ms;
356}
357
358
359#endif
360
33e90275
SC
361wxTimerImpl* wxGUIAppTraits::CreateTimerImpl(wxTimer *timer)
362{
dbeddfb9 363 return new wxOSXTimerImpl(timer);
33e90275
SC
364}
365
366int gs_wxBusyCursorCount = 0;
367extern wxCursor gMacCurrentCursor;
368wxCursor gMacStoredActiveCursor;
369
370// Set the cursor to the busy cursor for all windows
371void wxBeginBusyCursor(const wxCursor *cursor)
372{
373 if (gs_wxBusyCursorCount++ == 0)
374 {
3ac88921
SC
375 NSEnumerator *enumerator = [[[NSApplication sharedApplication] windows] objectEnumerator];
376 id object;
377
378 while ((object = [enumerator nextObject])) {
379 [(NSWindow*) object disableCursorRects];
380 }
381
33e90275
SC
382 gMacStoredActiveCursor = gMacCurrentCursor;
383 cursor->MacInstall();
384
385 wxSetCursor(*cursor);
386 }
387 //else: nothing to do, already set
388}
389
390// Restore cursor to normal
391void wxEndBusyCursor()
392{
393 wxCHECK_RET( gs_wxBusyCursorCount > 0,
394 wxT("no matching wxBeginBusyCursor() for wxEndBusyCursor()") );
395
396 if (--gs_wxBusyCursorCount == 0)
397 {
3ac88921
SC
398 NSEnumerator *enumerator = [[[NSApplication sharedApplication] windows] objectEnumerator];
399 id object;
400
401 while ((object = [enumerator nextObject])) {
402 [(NSWindow*) object enableCursorRects];
403 }
33e90275
SC
404
405 wxSetCursor(wxNullCursor);
3ac88921
SC
406
407 gMacStoredActiveCursor.MacInstall();
408 gMacStoredActiveCursor = wxNullCursor;
33e90275
SC
409 }
410}
411
412// true if we're between the above two calls
413bool wxIsBusy()
414{
415 return (gs_wxBusyCursorCount > 0);
416}
417
928e7a7e
KO
418wxBitmap wxWindowDCImpl::DoGetAsBitmap(const wxRect *subrect) const
419{
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.
422 if (!m_window)
423 return wxNullBitmap;
945eac79 424
928e7a7e 425 wxSize sz = m_window->GetSize();
945eac79 426
928e7a7e
KO
427 int width = subrect != NULL ? subrect->width : sz.x;
428 int height = subrect != NULL ? subrect->height : sz.y ;
945eac79 429
1034a6bb 430 wxBitmap bitmap(width, height);
945eac79 431
bda7c353
SC
432 NSView* view = (NSView*) m_window->GetHandle();
433 if ( [view isHiddenOrHasHiddenAncestor] == NO )
1034a6bb 434 {
bda7c353
SC
435 [view lockFocus];
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)
e5062a31 438 NSBitmapImageRep *rep = [[NSBitmapImageRep alloc] initWithFocusedViewRect: [view bounds]];
bda7c353
SC
439 [view unlockFocus];
440 if ( [rep respondsToSelector:@selector(CGImage)] )
441 {
442 CGImageRef cgImageRef = (CGImageRef)[rep CGImage];
443
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 ) ;
bda7c353
SC
447 }
448 else
449 {
450 // TODO for 10.4 in case we can support this for osx_cocoa
451 }
452 [rep release];
1034a6bb 453 }
945eac79 454
928e7a7e
KO
455 return bitmap;
456}
457
33e90275
SC
458#endif // wxUSE_GUI
459
3c7eea25 460#endif // wxOSX_USE_COCOA