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