]> git.saurik.com Git - wxWidgets.git/blob - src/osx/cocoa/utils.mm
adjusting keyboardstate to new ctrl / raw_ctrl handling on osx
[wxWidgets.git] / src / osx / cocoa / utils.mm
1 /////////////////////////////////////////////////////////////////////////////
2 // Name: src/osx/cocoa/utils.mm
3 // Purpose: various cocoa utility functions
4 // Author: Stefan Csomor
5 // Modified by:
6 // Created: 1998-01-01
7 // RCS-ID: $Id$
8 // Copyright: (c) Stefan Csomor
9 // Licence: wxWindows licence
10 /////////////////////////////////////////////////////////////////////////////
11
12 #include "wx/wxprec.h"
13
14 #include "wx/utils.h"
15
16 #ifndef WX_PRECOMP
17 #include "wx/intl.h"
18 #include "wx/app.h"
19 #if wxUSE_GUI
20 #include "wx/dialog.h"
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
32 #include <CoreServices/CoreServices.h>
33 #include "wx/osx/dcclient.h"
34 #include "wx/osx/private/timer.h"
35 #endif
36 #endif // wxUSE_GUI
37
38 #if wxOSX_USE_COCOA
39
40 #if wxUSE_BASE
41
42 // Emit a beeeeeep
43 void wxBell()
44 {
45 NSBeep();
46 }
47
48 #endif // wxUSE_BASE
49
50 #if wxUSE_GUI
51
52 @implementation wxNSAppController
53
54 - (void)applicationWillFinishLaunching:(NSNotification *)application {
55 wxUnusedVar(application);
56
57 // we must install our handlers later than setting the app delegate, because otherwise our handlers
58 // get overwritten in the meantime
59
60 NSAppleEventManager *appleEventManager = [NSAppleEventManager sharedAppleEventManager];
61
62 [appleEventManager setEventHandler:self andSelector:@selector(handleGetURLEvent:withReplyEvent:)
63 forEventClass:kInternetEventClass andEventID:kAEGetURL];
64
65 [appleEventManager setEventHandler:self andSelector:@selector(handleOpenAppEvent:withReplyEvent:)
66 forEventClass:kCoreEventClass andEventID:kAEOpenApplication];
67
68 }
69
70 - (void)application:(NSApplication *)sender openFiles:(NSArray *)fileNames
71 {
72 wxUnusedVar(sender);
73 wxArrayString fileList;
74 size_t i;
75 const size_t count = [fileNames count];
76 for (i = 0; i < count; i++)
77 {
78 fileList.Add( wxCFStringRef::AsString([fileNames objectAtIndex:i]) );
79 }
80
81 wxTheApp->MacOpenFiles(fileList);
82 }
83
84 - (BOOL)application:(NSApplication *)sender printFile:(NSString *)filename
85 {
86 wxUnusedVar(sender);
87 wxCFStringRef cf(wxCFRetain(filename));
88 wxTheApp->MacPrintFile(cf.AsString()) ;
89 return YES;
90 }
91
92 - (BOOL)applicationShouldHandleReopen:(NSApplication *)sender hasVisibleWindows:(BOOL)flag
93 {
94 wxUnusedVar(flag);
95 wxUnusedVar(sender);
96 wxTheApp->MacReopenApp() ;
97 return NO;
98 }
99
100 - (void)handleGetURLEvent:(NSAppleEventDescriptor *)event
101 withReplyEvent:(NSAppleEventDescriptor *)replyEvent
102 {
103 wxUnusedVar(replyEvent);
104 NSString* url = [[event descriptorAtIndex:1] stringValue];
105 wxCFStringRef cf(wxCFRetain(url));
106 wxTheApp->MacOpenURL(cf.AsString()) ;
107 }
108
109 - (void)handleOpenAppEvent:(NSAppleEventDescriptor *)event
110 withReplyEvent:(NSAppleEventDescriptor *)replyEvent
111 {
112 wxUnusedVar(replyEvent);
113 wxTheApp->MacNewFile() ;
114 }
115
116 /*
117 Allowable return values are:
118 NSTerminateNow - it is ok to proceed with termination
119 NSTerminateCancel - the application should not be terminated
120 NSTerminateLater - it may be ok to proceed with termination later. The application must call -replyToApplicationShouldTerminate: with YES or NO once the answer is known
121 this return value is for delegates who need to provide document modal alerts (sheets) in order to decide whether to quit.
122 */
123 - (NSApplicationTerminateReply)applicationShouldTerminate:(NSApplication *)sender
124 {
125 wxUnusedVar(sender);
126 wxCloseEvent event;
127 wxTheApp->OnQueryEndSession(event);
128 if ( event.GetVeto() )
129 return NSTerminateCancel;
130
131 return NSTerminateNow;
132 }
133
134 - (void)applicationWillTerminate:(NSNotification *)application {
135 wxUnusedVar(application);
136 wxCloseEvent event;
137 event.SetCanVeto(false);
138 wxTheApp->OnEndSession(event);
139 }
140
141 - (BOOL)applicationShouldTerminateAfterLastWindowClosed:(NSApplication *)sender
142 {
143 wxUnusedVar(sender);
144 // let wx do this, not cocoa
145 return NO;
146 }
147
148 - (void)applicationDidBecomeActive:(NSNotification *)notification
149 {
150 wxUnusedVar(notification);
151
152 for ( wxWindowList::const_iterator i = wxTopLevelWindows.begin(),
153 end = wxTopLevelWindows.end();
154 i != end;
155 ++i )
156 {
157 wxTopLevelWindow * const win = static_cast<wxTopLevelWindow *>(*i);
158 wxNonOwnedWindowImpl* winimpl = win ? win->GetNonOwnedPeer() : NULL;
159 WXWindow nswindow = win ? win->GetWXWindow() : nil;
160
161 if ( nswindow && [nswindow hidesOnDeactivate] == NO && winimpl)
162 winimpl->RestoreWindowLevel();
163 }
164 if ( wxTheApp )
165 wxTheApp->SetActive( true , NULL ) ;
166 }
167
168 - (void)applicationWillResignActive:(NSNotification *)notification
169 {
170 wxUnusedVar(notification);
171 for ( wxWindowList::const_iterator i = wxTopLevelWindows.begin(),
172 end = wxTopLevelWindows.end();
173 i != end;
174 ++i )
175 {
176 wxTopLevelWindow * const win = static_cast<wxTopLevelWindow *>(*i);
177 WXWindow nswindow = win ? win->GetWXWindow() : nil;
178
179 if ( nswindow && [nswindow level] == kCGFloatingWindowLevel && [nswindow hidesOnDeactivate] == NO )
180 [nswindow setLevel:kCGNormalWindowLevel];
181 }
182 }
183
184 - (void)applicationDidResignActive:(NSNotification *)notification
185 {
186 wxUnusedVar(notification);
187 if ( wxTheApp )
188 wxTheApp->SetActive( false , NULL ) ;
189 }
190
191 @end
192
193 /*
194 allows ShowModal to work when using sheets.
195 see include/wx/osx/cocoa/private.h for more info
196 */
197 @implementation ModalDialogDelegate
198 - (id)init
199 {
200 self = [super init];
201 sheetFinished = NO;
202 resultCode = -1;
203 impl = 0;
204 return self;
205 }
206
207 - (void)setImplementation: (wxDialog *)dialog
208 {
209 impl = dialog;
210 }
211
212 - (BOOL)finished
213 {
214 return sheetFinished;
215 }
216
217 - (int)code
218 {
219 return resultCode;
220 }
221
222 - (void)waitForSheetToFinish
223 {
224 while (!sheetFinished)
225 {
226 wxSafeYield();
227 }
228 }
229
230 - (void)sheetDidEnd:(NSWindow *)sheet returnCode:(int)returnCode contextInfo:(void *)contextInfo
231 {
232 wxUnusedVar(contextInfo);
233 resultCode = returnCode;
234 sheetFinished = YES;
235 // NSAlerts don't need nor respond to orderOut
236 if ([sheet respondsToSelector:@selector(orderOut:)])
237 [sheet orderOut: self];
238
239 if (impl)
240 impl->ModalFinishedCallback(sheet, returnCode);
241 }
242 @end
243
244 bool wxApp::DoInitGui()
245 {
246 wxMacAutoreleasePool pool;
247 [NSApplication sharedApplication];
248
249 if (!sm_isEmbedded)
250 {
251 wxNSAppController* controller = [[wxNSAppController alloc] init];
252 [NSApp setDelegate:controller];
253
254 // calling finishLaunching so early before running the loop seems to trigger some 'MenuManager compatibility' which leads
255 // to the duplication of menus under 10.5 and a warning under 10.6
256 #if 0
257 [NSApp finishLaunching];
258 #endif
259 }
260 return true;
261 }
262
263 void wxApp::DoCleanUp()
264 {
265 }
266
267 void wxClientDisplayRect(int *x, int *y, int *width, int *height)
268 {
269 NSRect displayRect = [wxOSXGetMenuScreen() visibleFrame];
270 wxRect r = wxFromNSRect( NULL, displayRect );
271 if ( x )
272 *x = r.x;
273 if ( y )
274 *y = r.y;
275 if ( width )
276 *width = r.GetWidth();
277 if ( height )
278 *height = r.GetHeight();
279
280 }
281
282 void wxGetMousePosition( int* x, int* y )
283 {
284 wxPoint pt = wxFromNSPoint(NULL, [NSEvent mouseLocation]);
285 if ( x )
286 *x = pt.x;
287 if ( y )
288 *y = pt.y;
289 };
290
291 #if wxOSX_USE_COCOA && MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_6
292
293 wxMouseState wxGetMouseState()
294 {
295 wxMouseState ms;
296
297 wxPoint pt = wxGetMousePosition();
298 ms.SetX(pt.x);
299 ms.SetY(pt.y);
300
301 NSUInteger modifiers = [NSEvent modifierFlags];
302 NSUInteger buttons = [NSEvent pressedMouseButtons];
303
304 ms.SetLeftDown( (buttons & 0x01) != 0 );
305 ms.SetMiddleDown( (buttons & 0x04) != 0 );
306 ms.SetRightDown( (buttons & 0x02) != 0 );
307
308 ms.SetRealControlDown(modifiers & NSControlKeyMask);
309 ms.SetShiftDown(modifiers & NSShiftKeyMask);
310 ms.SetAltDown(modifiers & NSAlternateKeyMask);
311 ms.SetControlDown(modifiers & NSCommandKeyMask);
312
313 return ms;
314 }
315
316
317 #endif
318
319 wxTimerImpl* wxGUIAppTraits::CreateTimerImpl(wxTimer *timer)
320 {
321 return new wxOSXTimerImpl(timer);
322 }
323
324 int gs_wxBusyCursorCount = 0;
325 extern wxCursor gMacCurrentCursor;
326 wxCursor gMacStoredActiveCursor;
327
328 // Set the cursor to the busy cursor for all windows
329 void wxBeginBusyCursor(const wxCursor *cursor)
330 {
331 if (gs_wxBusyCursorCount++ == 0)
332 {
333 NSEnumerator *enumerator = [[[NSApplication sharedApplication] windows] objectEnumerator];
334 id object;
335
336 while ((object = [enumerator nextObject])) {
337 [(NSWindow*) object disableCursorRects];
338 }
339
340 gMacStoredActiveCursor = gMacCurrentCursor;
341 cursor->MacInstall();
342
343 wxSetCursor(*cursor);
344 }
345 //else: nothing to do, already set
346 }
347
348 // Restore cursor to normal
349 void wxEndBusyCursor()
350 {
351 wxCHECK_RET( gs_wxBusyCursorCount > 0,
352 wxT("no matching wxBeginBusyCursor() for wxEndBusyCursor()") );
353
354 if (--gs_wxBusyCursorCount == 0)
355 {
356 NSEnumerator *enumerator = [[[NSApplication sharedApplication] windows] objectEnumerator];
357 id object;
358
359 while ((object = [enumerator nextObject])) {
360 [(NSWindow*) object enableCursorRects];
361 }
362
363 wxSetCursor(wxNullCursor);
364
365 gMacStoredActiveCursor.MacInstall();
366 gMacStoredActiveCursor = wxNullCursor;
367 }
368 }
369
370 // true if we're between the above two calls
371 bool wxIsBusy()
372 {
373 return (gs_wxBusyCursorCount > 0);
374 }
375
376 wxBitmap wxWindowDCImpl::DoGetAsBitmap(const wxRect *subrect) const
377 {
378 // wxScreenDC is derived from wxWindowDC, so a screen dc will
379 // call this method when a Blit is performed with it as a source.
380 if (!m_window)
381 return wxNullBitmap;
382
383 wxSize sz = m_window->GetSize();
384
385 int width = subrect != NULL ? subrect->width : sz.x;
386 int height = subrect != NULL ? subrect->height : sz.y ;
387
388 wxBitmap bitmap(width, height);
389
390 NSView* view = (NSView*) m_window->GetHandle();
391 if ( [view isHiddenOrHasHiddenAncestor] == NO )
392 {
393 [view lockFocus];
394 // we use this method as other methods force a repaint, and this method can be
395 // called from OnPaint, even with the window's paint dc as source (see wxHTMLWindow)
396 NSBitmapImageRep *rep = [[NSBitmapImageRep alloc] initWithFocusedViewRect: [view bounds]];
397 [view unlockFocus];
398 if ( [rep respondsToSelector:@selector(CGImage)] )
399 {
400 CGImageRef cgImageRef = (CGImageRef)[rep CGImage];
401
402 CGRect r = CGRectMake( 0 , 0 , CGImageGetWidth(cgImageRef) , CGImageGetHeight(cgImageRef) );
403 // since our context is upside down we dont use CGContextDrawImage
404 wxMacDrawCGImage( (CGContextRef) bitmap.GetHBITMAP() , &r, cgImageRef ) ;
405 }
406 else
407 {
408 // TODO for 10.4 in case we can support this for osx_cocoa
409 }
410 [rep release];
411 }
412
413 return bitmap;
414 }
415
416 #endif // wxUSE_GUI
417
418 #endif // wxOSX_USE_COCOA