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