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