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