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