]> git.saurik.com Git - wxWidgets.git/blame - src/osx/cocoa/utils.mm
Add missing WXK constants for the control keys
[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 {
74 fileList.Add( wxCFStringRef::AsString([fileNames objectAtIndex:i]) );
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
e1875c78
SC
262wxNSAppController* appcontroller = nil;
263
befe64ed
SC
264NSLayoutManager* gNSLayoutManager = nil;
265
266
dbeddfb9
SC
267bool wxApp::DoInitGui()
268{
ab9df4fb 269 wxMacAutoreleasePool pool;
c6aa5caf
SC
270
271 if (!sm_isEmbedded)
272 {
ee6a122f
SC
273 [wxNSApplication sharedApplication];
274
e1875c78
SC
275 appcontroller = [[wxNSAppController alloc] init];
276 [NSApp setDelegate:appcontroller];
945eac79 277
e8f25fcf
SC
278 // calling finishLaunching so early before running the loop seems to trigger some 'MenuManager compatibility' which leads
279 // to the duplication of menus under 10.5 and a warning under 10.6
280#if 0
cc96f525 281 [NSApp finishLaunching];
e8f25fcf 282#endif
c6aa5caf 283 }
befe64ed
SC
284 gNSLayoutManager = [[NSLayoutManager alloc] init];
285
dbeddfb9
SC
286 return true;
287}
288
289void wxApp::DoCleanUp()
290{
e1875c78
SC
291 if ( appcontroller != nil )
292 {
293 [NSApp setDelegate:nil];
294 [appcontroller release];
295 appcontroller = nil;
296 }
befe64ed
SC
297 if ( gNSLayoutManager != nil )
298 {
299 [gNSLayoutManager release];
300 gNSLayoutManager = nil;
301 }
dbeddfb9 302}
33e90275 303
33e90275
SC
304void wxClientDisplayRect(int *x, int *y, int *width, int *height)
305{
5d57348e 306 NSRect displayRect = [wxOSXGetMenuScreen() visibleFrame];
33e90275
SC
307 wxRect r = wxFromNSRect( NULL, displayRect );
308 if ( x )
309 *x = r.x;
310 if ( y )
311 *y = r.y;
312 if ( width )
313 *width = r.GetWidth();
314 if ( height )
315 *height = r.GetHeight();
945eac79 316
33e90275
SC
317}
318
319void wxGetMousePosition( int* x, int* y )
320{
321 wxPoint pt = wxFromNSPoint(NULL, [NSEvent mouseLocation]);
54f11060
SC
322 if ( x )
323 *x = pt.x;
324 if ( y )
325 *y = pt.y;
33e90275
SC
326};
327
f3769d53
SC
328#if wxOSX_USE_COCOA && MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_6
329
330wxMouseState wxGetMouseState()
331{
332 wxMouseState ms;
333
334 wxPoint pt = wxGetMousePosition();
335 ms.SetX(pt.x);
336 ms.SetY(pt.y);
337
338 NSUInteger modifiers = [NSEvent modifierFlags];
339 NSUInteger buttons = [NSEvent pressedMouseButtons];
340
341 ms.SetLeftDown( (buttons & 0x01) != 0 );
342 ms.SetMiddleDown( (buttons & 0x04) != 0 );
343 ms.SetRightDown( (buttons & 0x02) != 0 );
344
8b14528f 345 ms.SetRawControlDown(modifiers & NSControlKeyMask);
f3769d53
SC
346 ms.SetShiftDown(modifiers & NSShiftKeyMask);
347 ms.SetAltDown(modifiers & NSAlternateKeyMask);
dd9ec596 348 ms.SetControlDown(modifiers & NSCommandKeyMask);
f3769d53
SC
349
350 return ms;
351}
352
353
354#endif
355
33e90275
SC
356wxTimerImpl* wxGUIAppTraits::CreateTimerImpl(wxTimer *timer)
357{
dbeddfb9 358 return new wxOSXTimerImpl(timer);
33e90275
SC
359}
360
361int gs_wxBusyCursorCount = 0;
362extern wxCursor gMacCurrentCursor;
363wxCursor gMacStoredActiveCursor;
364
365// Set the cursor to the busy cursor for all windows
366void wxBeginBusyCursor(const wxCursor *cursor)
367{
368 if (gs_wxBusyCursorCount++ == 0)
369 {
3ac88921
SC
370 NSEnumerator *enumerator = [[[NSApplication sharedApplication] windows] objectEnumerator];
371 id object;
372
373 while ((object = [enumerator nextObject])) {
374 [(NSWindow*) object disableCursorRects];
375 }
376
33e90275
SC
377 gMacStoredActiveCursor = gMacCurrentCursor;
378 cursor->MacInstall();
379
380 wxSetCursor(*cursor);
381 }
382 //else: nothing to do, already set
383}
384
385// Restore cursor to normal
386void wxEndBusyCursor()
387{
388 wxCHECK_RET( gs_wxBusyCursorCount > 0,
389 wxT("no matching wxBeginBusyCursor() for wxEndBusyCursor()") );
390
391 if (--gs_wxBusyCursorCount == 0)
392 {
3ac88921
SC
393 NSEnumerator *enumerator = [[[NSApplication sharedApplication] windows] objectEnumerator];
394 id object;
395
396 while ((object = [enumerator nextObject])) {
397 [(NSWindow*) object enableCursorRects];
398 }
33e90275
SC
399
400 wxSetCursor(wxNullCursor);
3ac88921
SC
401
402 gMacStoredActiveCursor.MacInstall();
403 gMacStoredActiveCursor = wxNullCursor;
33e90275
SC
404 }
405}
406
407// true if we're between the above two calls
408bool wxIsBusy()
409{
410 return (gs_wxBusyCursorCount > 0);
411}
412
928e7a7e
KO
413wxBitmap wxWindowDCImpl::DoGetAsBitmap(const wxRect *subrect) const
414{
415 // wxScreenDC is derived from wxWindowDC, so a screen dc will
416 // call this method when a Blit is performed with it as a source.
417 if (!m_window)
418 return wxNullBitmap;
945eac79 419
928e7a7e 420 wxSize sz = m_window->GetSize();
945eac79 421
928e7a7e
KO
422 int width = subrect != NULL ? subrect->width : sz.x;
423 int height = subrect != NULL ? subrect->height : sz.y ;
945eac79 424
1034a6bb 425 wxBitmap bitmap(width, height);
945eac79 426
bda7c353
SC
427 NSView* view = (NSView*) m_window->GetHandle();
428 if ( [view isHiddenOrHasHiddenAncestor] == NO )
1034a6bb 429 {
bda7c353
SC
430 [view lockFocus];
431 // we use this method as other methods force a repaint, and this method can be
432 // called from OnPaint, even with the window's paint dc as source (see wxHTMLWindow)
e5062a31 433 NSBitmapImageRep *rep = [[NSBitmapImageRep alloc] initWithFocusedViewRect: [view bounds]];
bda7c353
SC
434 [view unlockFocus];
435 if ( [rep respondsToSelector:@selector(CGImage)] )
436 {
437 CGImageRef cgImageRef = (CGImageRef)[rep CGImage];
438
439 CGRect r = CGRectMake( 0 , 0 , CGImageGetWidth(cgImageRef) , CGImageGetHeight(cgImageRef) );
440 // since our context is upside down we dont use CGContextDrawImage
441 wxMacDrawCGImage( (CGContextRef) bitmap.GetHBITMAP() , &r, cgImageRef ) ;
bda7c353
SC
442 }
443 else
444 {
445 // TODO for 10.4 in case we can support this for osx_cocoa
446 }
447 [rep release];
1034a6bb 448 }
945eac79 449
928e7a7e
KO
450 return bitmap;
451}
452
33e90275
SC
453#endif // wxUSE_GUI
454
3c7eea25 455#endif // wxOSX_USE_COCOA