]> git.saurik.com Git - wxWidgets.git/blame - src/osx/cocoa/utils.mm
Disable handling of wxEVT_MOUSEWHEEL in wxVarScrollHelperEvtHandler in wxGTK.
[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
33e90275
SC
7// Copyright: (c) Stefan Csomor
8// Licence: wxWindows licence
9/////////////////////////////////////////////////////////////////////////////
10
11#include "wx/wxprec.h"
12
33e90275
SC
13#include "wx/utils.h"
14
15#ifndef WX_PRECOMP
16 #include "wx/intl.h"
17 #include "wx/app.h"
18 #if wxUSE_GUI
bfa92264 19 #include "wx/dialog.h"
33e90275
SC
20 #include "wx/toplevel.h"
21 #include "wx/font.h"
22 #endif
23#endif
24
25#include "wx/apptrait.h"
26
27#include "wx/osx/private.h"
28
29#if wxUSE_GUI
30#if wxOSX_USE_COCOA_OR_CARBON
33e90275 31 #include <CoreServices/CoreServices.h>
928e7a7e 32 #include "wx/osx/dcclient.h"
33e90275
SC
33 #include "wx/osx/private/timer.h"
34#endif
35#endif // wxUSE_GUI
36
37#if wxOSX_USE_COCOA
38
598fe99d 39#if wxUSE_GUI
33e90275
SC
40
41// Emit a beeeeeep
42void wxBell()
43{
44 NSBeep();
45}
46
c6aa5caf
SC
47@implementation wxNSAppController
48
f9148f98
SC
49- (void)applicationWillFinishLaunching:(NSNotification *)application
50{
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
f9148f98
SC
64 wxTheApp->OSXOnWillFinishLaunching();
65}
66
67- (void)applicationDidFinishLaunching:(NSNotification *)notification
68{
69 wxTheApp->OSXOnDidFinishLaunching();
c6aa5caf
SC
70}
71
ee7553e9 72- (void)application:(NSApplication *)sender openFiles:(NSArray *)fileNames
c6aa5caf 73{
d8207702 74 wxUnusedVar(sender);
ee7553e9
DS
75 wxArrayString fileList;
76 size_t i;
77 const size_t count = [fileNames count];
78 for (i = 0; i < count; i++)
79 {
31895560 80 fileList.Add( wxCFStringRef::AsStringWithNormalizationFormC([fileNames objectAtIndex:i]) );
ee7553e9
DS
81 }
82
83 wxTheApp->MacOpenFiles(fileList);
c6aa5caf
SC
84}
85
c6aa5caf
SC
86- (BOOL)application:(NSApplication *)sender printFile:(NSString *)filename
87{
d8207702 88 wxUnusedVar(sender);
c6aa5caf
SC
89 wxCFStringRef cf(wxCFRetain(filename));
90 wxTheApp->MacPrintFile(cf.AsString()) ;
91 return YES;
92}
93
175e9d71
SC
94- (BOOL)applicationShouldHandleReopen:(NSApplication *)sender hasVisibleWindows:(BOOL)flag
95{
96 wxUnusedVar(flag);
97 wxUnusedVar(sender);
98 wxTheApp->MacReopenApp() ;
99 return NO;
100}
101
102- (void)handleGetURLEvent:(NSAppleEventDescriptor *)event
103 withReplyEvent:(NSAppleEventDescriptor *)replyEvent
104{
105 wxUnusedVar(replyEvent);
106 NSString* url = [[event descriptorAtIndex:1] stringValue];
107 wxCFStringRef cf(wxCFRetain(url));
108 wxTheApp->MacOpenURL(cf.AsString()) ;
109}
110
77aa5fa0
SC
111- (void)handleOpenAppEvent:(NSAppleEventDescriptor *)event
112 withReplyEvent:(NSAppleEventDescriptor *)replyEvent
113{
114 wxUnusedVar(replyEvent);
115 wxTheApp->MacNewFile() ;
116}
117
945eac79 118/*
c6aa5caf
SC
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.
124*/
125- (NSApplicationTerminateReply)applicationShouldTerminate:(NSApplication *)sender
126{
d8207702 127 wxUnusedVar(sender);
15160da2 128 if ( !wxTheApp->OSXOnShouldTerminate() )
175e9d71
SC
129 return NSTerminateCancel;
130
131 return NSTerminateNow;
c6aa5caf
SC
132}
133
a5d0c88a 134- (void)applicationWillTerminate:(NSNotification *)application {
175e9d71 135 wxUnusedVar(application);
15160da2 136 wxTheApp->OSXOnWillTerminate();
175e9d71
SC
137}
138
139- (BOOL)applicationShouldTerminateAfterLastWindowClosed:(NSApplication *)sender
c6aa5caf 140{
d8207702 141 wxUnusedVar(sender);
175e9d71 142 // let wx do this, not cocoa
c6aa5caf
SC
143 return NO;
144}
145
74518cea
SC
146- (void)applicationDidBecomeActive:(NSNotification *)notification
147{
148 wxUnusedVar(notification);
149
150 for ( wxWindowList::const_iterator i = wxTopLevelWindows.begin(),
151 end = wxTopLevelWindows.end();
152 i != end;
153 ++i )
154 {
155 wxTopLevelWindow * const win = static_cast<wxTopLevelWindow *>(*i);
156 wxNonOwnedWindowImpl* winimpl = win ? win->GetNonOwnedPeer() : NULL;
157 WXWindow nswindow = win ? win->GetWXWindow() : nil;
158
159 if ( nswindow && [nswindow hidesOnDeactivate] == NO && winimpl)
160 winimpl->RestoreWindowLevel();
161 }
162 if ( wxTheApp )
163 wxTheApp->SetActive( true , NULL ) ;
164}
165
166- (void)applicationWillResignActive:(NSNotification *)notification
167{
168 wxUnusedVar(notification);
169 for ( wxWindowList::const_iterator i = wxTopLevelWindows.begin(),
170 end = wxTopLevelWindows.end();
171 i != end;
172 ++i )
173 {
174 wxTopLevelWindow * const win = static_cast<wxTopLevelWindow *>(*i);
175 WXWindow nswindow = win ? win->GetWXWindow() : nil;
176
177 if ( nswindow && [nswindow level] == kCGFloatingWindowLevel && [nswindow hidesOnDeactivate] == NO )
178 [nswindow setLevel:kCGNormalWindowLevel];
179 }
180}
181
182- (void)applicationDidResignActive:(NSNotification *)notification
183{
184 wxUnusedVar(notification);
185 if ( wxTheApp )
186 wxTheApp->SetActive( false , NULL ) ;
187}
188
c6aa5caf
SC
189@end
190
03647350 191/*
724999ee 192 allows ShowModal to work when using sheets.
03647350 193 see include/wx/osx/cocoa/private.h for more info
724999ee
KO
194*/
195@implementation ModalDialogDelegate
196- (id)init
197{
e5062a31 198 self = [super init];
724999ee
KO
199 sheetFinished = NO;
200 resultCode = -1;
bfa92264 201 impl = 0;
724999ee
KO
202 return self;
203}
204
bfa92264
KO
205- (void)setImplementation: (wxDialog *)dialog
206{
207 impl = dialog;
208}
209
03647350 210- (BOOL)finished
724999ee
KO
211{
212 return sheetFinished;
213}
214
215- (int)code
216{
217 return resultCode;
218}
219
220- (void)waitForSheetToFinish
221{
222 while (!sheetFinished)
223 {
224 wxSafeYield();
225 }
226}
227
228- (void)sheetDidEnd:(NSWindow *)sheet returnCode:(int)returnCode contextInfo:(void *)contextInfo
229{
d8207702 230 wxUnusedVar(contextInfo);
724999ee
KO
231 resultCode = returnCode;
232 sheetFinished = YES;
037f9d3b
KO
233 // NSAlerts don't need nor respond to orderOut
234 if ([sheet respondsToSelector:@selector(orderOut:)])
235 [sheet orderOut: self];
bfa92264
KO
236
237 if (impl)
238 impl->ModalFinishedCallback(sheet, returnCode);
724999ee
KO
239}
240@end
241
ee6a122f
SC
242// here we subclass NSApplication, for the purpose of being able to override sendEvent.
243@interface wxNSApplication : NSApplication
244{
17243986 245 BOOL firstPass;
ee6a122f
SC
246}
247
17243986
SC
248- (id)init;
249
ee6a122f
SC
250- (void)sendEvent:(NSEvent *)anEvent;
251
252@end
253
254@implementation wxNSApplication
255
17243986
SC
256- (id)init
257{
258 self = [super init];
259 firstPass = YES;
260 return self;
261}
262
ee6a122f
SC
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
266{
267 if ([anEvent type] == NSKeyUp && ([anEvent modifierFlags] & NSCommandKeyMask))
268 [[self keyWindow] sendEvent:anEvent];
17243986
SC
269 else
270 [super sendEvent:anEvent];
271
272 if ( firstPass )
273 {
274 [NSApp stop:nil];
275 firstPass = NO;
276 return;
277 }
ee6a122f
SC
278}
279
280@end
281
395506ea 282WX_NSObject appcontroller = nil;
e1875c78 283
befe64ed
SC
284NSLayoutManager* gNSLayoutManager = nil;
285
395506ea
SC
286WX_NSObject wxApp::OSXCreateAppController()
287{
288 return [[wxNSAppController alloc] init];
289}
befe64ed 290
dbeddfb9
SC
291bool wxApp::DoInitGui()
292{
ab9df4fb 293 wxMacAutoreleasePool pool;
c6aa5caf
SC
294
295 if (!sm_isEmbedded)
296 {
ee6a122f
SC
297 [wxNSApplication sharedApplication];
298
395506ea 299 appcontroller = OSXCreateAppController();
e1875c78 300 [NSApp setDelegate:appcontroller];
7aa09d43 301 [NSColor setIgnoresAlpha:NO];
945eac79 302
e8f25fcf
SC
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
305#if 0
cc96f525 306 [NSApp finishLaunching];
e8f25fcf 307#endif
c6aa5caf 308 }
befe64ed
SC
309 gNSLayoutManager = [[NSLayoutManager alloc] init];
310
dbeddfb9
SC
311 return true;
312}
313
17243986
SC
314bool wxApp::CallOnInit()
315{
316 wxMacAutoreleasePool autoreleasepool;
b0fa6efc 317 // this will only run one cycle to make sure the OS is ready
17243986 318 [NSApp run];
b0fa6efc 319 return OnInit();
17243986
SC
320}
321
dbeddfb9
SC
322void wxApp::DoCleanUp()
323{
e1875c78
SC
324 if ( appcontroller != nil )
325 {
326 [NSApp setDelegate:nil];
327 [appcontroller release];
328 appcontroller = nil;
329 }
befe64ed
SC
330 if ( gNSLayoutManager != nil )
331 {
332 [gNSLayoutManager release];
333 gNSLayoutManager = nil;
334 }
dbeddfb9 335}
33e90275 336
33e90275
SC
337void wxClientDisplayRect(int *x, int *y, int *width, int *height)
338{
5d57348e 339 NSRect displayRect = [wxOSXGetMenuScreen() visibleFrame];
33e90275
SC
340 wxRect r = wxFromNSRect( NULL, displayRect );
341 if ( x )
342 *x = r.x;
343 if ( y )
344 *y = r.y;
345 if ( width )
346 *width = r.GetWidth();
347 if ( height )
348 *height = r.GetHeight();
945eac79 349
33e90275
SC
350}
351
352void wxGetMousePosition( int* x, int* y )
353{
354 wxPoint pt = wxFromNSPoint(NULL, [NSEvent mouseLocation]);
54f11060
SC
355 if ( x )
356 *x = pt.x;
357 if ( y )
358 *y = pt.y;
33e90275
SC
359};
360
f3769d53
SC
361#if wxOSX_USE_COCOA && MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_6
362
363wxMouseState wxGetMouseState()
364{
365 wxMouseState ms;
366
367 wxPoint pt = wxGetMousePosition();
368 ms.SetX(pt.x);
369 ms.SetY(pt.y);
370
371 NSUInteger modifiers = [NSEvent modifierFlags];
372 NSUInteger buttons = [NSEvent pressedMouseButtons];
373
374 ms.SetLeftDown( (buttons & 0x01) != 0 );
375 ms.SetMiddleDown( (buttons & 0x04) != 0 );
376 ms.SetRightDown( (buttons & 0x02) != 0 );
377
8b14528f 378 ms.SetRawControlDown(modifiers & NSControlKeyMask);
f3769d53
SC
379 ms.SetShiftDown(modifiers & NSShiftKeyMask);
380 ms.SetAltDown(modifiers & NSAlternateKeyMask);
dd9ec596 381 ms.SetControlDown(modifiers & NSCommandKeyMask);
f3769d53
SC
382
383 return ms;
384}
385
386
387#endif
388
33e90275
SC
389wxTimerImpl* wxGUIAppTraits::CreateTimerImpl(wxTimer *timer)
390{
dbeddfb9 391 return new wxOSXTimerImpl(timer);
33e90275
SC
392}
393
394int gs_wxBusyCursorCount = 0;
395extern wxCursor gMacCurrentCursor;
396wxCursor gMacStoredActiveCursor;
397
398// Set the cursor to the busy cursor for all windows
399void wxBeginBusyCursor(const wxCursor *cursor)
400{
401 if (gs_wxBusyCursorCount++ == 0)
402 {
3ac88921
SC
403 NSEnumerator *enumerator = [[[NSApplication sharedApplication] windows] objectEnumerator];
404 id object;
405
406 while ((object = [enumerator nextObject])) {
407 [(NSWindow*) object disableCursorRects];
408 }
409
33e90275
SC
410 gMacStoredActiveCursor = gMacCurrentCursor;
411 cursor->MacInstall();
412
413 wxSetCursor(*cursor);
414 }
415 //else: nothing to do, already set
416}
417
418// Restore cursor to normal
419void wxEndBusyCursor()
420{
421 wxCHECK_RET( gs_wxBusyCursorCount > 0,
422 wxT("no matching wxBeginBusyCursor() for wxEndBusyCursor()") );
423
424 if (--gs_wxBusyCursorCount == 0)
425 {
3ac88921
SC
426 NSEnumerator *enumerator = [[[NSApplication sharedApplication] windows] objectEnumerator];
427 id object;
428
429 while ((object = [enumerator nextObject])) {
430 [(NSWindow*) object enableCursorRects];
431 }
33e90275
SC
432
433 wxSetCursor(wxNullCursor);
3ac88921
SC
434
435 gMacStoredActiveCursor.MacInstall();
436 gMacStoredActiveCursor = wxNullCursor;
33e90275
SC
437 }
438}
439
440// true if we're between the above two calls
441bool wxIsBusy()
442{
443 return (gs_wxBusyCursorCount > 0);
444}
445
928e7a7e
KO
446wxBitmap wxWindowDCImpl::DoGetAsBitmap(const wxRect *subrect) const
447{
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.
450 if (!m_window)
451 return wxNullBitmap;
945eac79 452
928e7a7e 453 wxSize sz = m_window->GetSize();
945eac79 454
928e7a7e
KO
455 int width = subrect != NULL ? subrect->width : sz.x;
456 int height = subrect != NULL ? subrect->height : sz.y ;
945eac79 457
1034a6bb 458 wxBitmap bitmap(width, height);
945eac79 459
bda7c353
SC
460 NSView* view = (NSView*) m_window->GetHandle();
461 if ( [view isHiddenOrHasHiddenAncestor] == NO )
1034a6bb 462 {
bda7c353
SC
463 [view lockFocus];
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)
e5062a31 466 NSBitmapImageRep *rep = [[NSBitmapImageRep alloc] initWithFocusedViewRect: [view bounds]];
bda7c353
SC
467 [view unlockFocus];
468 if ( [rep respondsToSelector:@selector(CGImage)] )
469 {
470 CGImageRef cgImageRef = (CGImageRef)[rep CGImage];
471
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 ) ;
bda7c353
SC
475 }
476 else
477 {
478 // TODO for 10.4 in case we can support this for osx_cocoa
479 }
480 [rep release];
1034a6bb 481 }
945eac79 482
928e7a7e
KO
483 return bitmap;
484}
485
33e90275
SC
486#endif // wxUSE_GUI
487
3c7eea25 488#endif // wxOSX_USE_COCOA