1 /////////////////////////////////////////////////////////////////////////////
2 // Name: src/osx/cocoa/nonownedwnd.mm
3 // Purpose: non owned window for cocoa
4 // Author: DavidStefan Csomor
7 // RCS-ID: $Id: nonownedwnd.mm 48805 2007-09-19 14:52:25Z SC $
8 // Copyright: (c) Stefan Csomor
9 // Licence: wxWindows licence
10 /////////////////////////////////////////////////////////////////////////////
12 #include "wx/wxprec.h"
14 #include "wx/nonownedwnd.h"
18 #include "wx/osx/private.h"
20 NSRect wxToNSRect( NSView* parent, const wxRect& r )
22 NSRect frame = parent ? [parent bounds] : [[NSScreen mainScreen] frame];
25 if ( parent == NULL || ![ parent isFlipped ] )
26 y = frame.size.height - ( r.y + r.height );
27 return NSMakeRect(x, y, r.width , r.height);
30 wxRect wxFromNSRect( NSView* parent, const NSRect& rect )
32 NSRect frame = parent ? [parent bounds] : [[NSScreen mainScreen] frame];
33 int y = rect.origin.y;
34 int x = rect.origin.x;
35 if ( parent == NULL || ![ parent isFlipped ] )
36 y = frame.size.height - (rect.origin.y + rect.size.height);
37 return wxRect( x, y, rect.size.width, rect.size.height );
40 NSPoint wxToNSPoint( NSView* parent, const wxPoint& p )
42 NSRect frame = parent ? [parent bounds] : [[NSScreen mainScreen] frame];
45 if ( parent == NULL || ![ parent isFlipped ] )
46 y = frame.size.height - ( p.y );
47 return NSMakePoint(x, y);
50 wxPoint wxFromNSPoint( NSView* parent, const NSPoint& p )
52 NSRect frame = parent ? [parent bounds] : [[NSScreen mainScreen] frame];
55 if ( parent == NULL || ![ parent isFlipped ] )
56 y = frame.size.height - ( p.y );
57 return wxPoint( x, y);
60 bool shouldHandleSelector(SEL selector)
62 if (selector == @selector(noop:)
63 || selector == @selector(complete:)
64 || selector == @selector(deleteBackward:)
65 || selector == @selector(deleteForward:)
66 || selector == @selector(insertNewline:)
67 || selector == @selector(insertTab:)
68 || selector == @selector(keyDown:)
69 || selector == @selector(keyUp:)
70 || selector == @selector(scrollPageUp:)
71 || selector == @selector(scrollPageDown:)
72 || selector == @selector(scrollToBeginningOfDocument:)
73 || selector == @selector(scrollToEndOfDocument:))
81 // wx native implementation classes
84 typedef void (*wxOSX_NoResponderHandlerPtr)(NSView* self, SEL _cmd, SEL selector);
86 @interface wxNSWindow : NSWindow
88 wxNonOwnedWindowCocoaImpl* impl;
91 - (void)setImplementation: (wxNonOwnedWindowCocoaImpl *) theImplementation;
92 - (wxNonOwnedWindowCocoaImpl*) implementation;
93 - (void)noResponderFor: (SEL) selector;
96 @implementation wxNSWindow
98 - (void)setImplementation: (wxNonOwnedWindowCocoaImpl *) theImplementation
100 impl = theImplementation;
103 - (wxNonOwnedWindowCocoaImpl*) implementation
108 - (void)doCommandBySelector:(SEL)selector
110 if (shouldHandleSelector(selector) &&
111 !(selector == @selector(cancel:) || selector == @selector(cancelOperation:)) )
112 [super doCommandBySelector:selector];
116 // NB: if we don't do this, all key downs that get handled lead to a NSBeep
117 - (void)noResponderFor: (SEL) selector
119 if (selector != @selector(keyDown:) && selector != @selector(keyUp:))
121 wxOSX_NoResponderHandlerPtr superimpl = (wxOSX_NoResponderHandlerPtr) [[self superclass] instanceMethodForSelector:@selector(noResponderFor:)];
122 superimpl(self, @selector(noResponderFor:), selector);
128 @interface wxNSPanel : NSPanel
131 wxNonOwnedWindowCocoaImpl* impl;
134 - (void)setImplementation: (wxNonOwnedWindowCocoaImpl *) theImplementation;
135 - (wxNonOwnedWindowCocoaImpl*) implementation;
136 - (void)noResponderFor: (SEL) selector;
139 @implementation wxNSPanel
141 - (void)setImplementation: (wxNonOwnedWindowCocoaImpl *) theImplementation
143 impl = theImplementation;
146 - (BOOL)canBecomeKeyWindow
151 - (wxNonOwnedWindowCocoaImpl*) implementation
156 - (void)doCommandBySelector:(SEL)selector
158 if (shouldHandleSelector(selector))
159 [super doCommandBySelector:selector];
162 // NB: if we don't do this, it seems that all events that end here lead to a NSBeep
163 - (void)noResponderFor: (SEL) selector
165 if (selector != @selector(keyDown:) && selector != @selector(keyUp:))
167 wxOSX_NoResponderHandlerPtr superimpl = (wxOSX_NoResponderHandlerPtr) [[self superclass] instanceMethodForSelector:@selector(noResponderFor:)];
168 superimpl(self, @selector(noResponderFor:), selector);
179 @interface wxNonOwnedWindowController : NSObject
183 - (void)windowDidResize:(NSNotification *)notification;
184 - (NSSize)windowWillResize:(NSWindow *)window toSize:(NSSize)proposedFrameSize;
185 - (void)windowDidResignKey:(NSNotification *)notification;
186 - (void)windowDidBecomeKey:(NSNotification *)notification;
187 - (void)windowDidMove:(NSNotification *)notification;
188 - (BOOL)windowShouldClose:(id)window;
192 @implementation wxNonOwnedWindowController
200 - (BOOL)windowShouldClose:(id)nwindow
202 wxNSWindow* window = (wxNSWindow*) nwindow;
203 wxNonOwnedWindowCocoaImpl* windowimpl = [window implementation];
206 wxNonOwnedWindow* wxpeer = windowimpl->GetWXPeer();
213 - (NSSize)windowWillResize:(NSWindow *)win
214 toSize:(NSSize)proposedFrameSize
216 NSRect frame = [win frame];
217 wxRect wxframe = wxFromNSRect( NULL, frame );
218 wxframe.SetWidth( proposedFrameSize.width );
219 wxframe.SetHeight( proposedFrameSize.height );
220 wxNSWindow* window = (wxNSWindow*) win;
221 wxNonOwnedWindowCocoaImpl* windowimpl = [window implementation];
224 wxNonOwnedWindow* wxpeer = windowimpl->GetWXPeer();
227 wxpeer->HandleResizing( 0, &wxframe );
228 NSSize newSize = NSMakeSize(wxframe.GetWidth(), wxframe.GetHeight());
233 return proposedFrameSize;
236 - (void)windowDidResize:(NSNotification *)notification
238 wxNSWindow* window = (wxNSWindow*) [notification object];
239 wxNonOwnedWindowCocoaImpl* windowimpl = [window implementation];
242 wxNonOwnedWindow* wxpeer = windowimpl->GetWXPeer();
244 wxpeer->HandleResized(0);
248 - (void)windowDidMove:(NSNotification *)notification
250 wxNSWindow* window = (wxNSWindow*) [notification object];
251 wxNonOwnedWindowCocoaImpl* windowimpl = [window implementation];
254 wxNonOwnedWindow* wxpeer = windowimpl->GetWXPeer();
256 wxpeer->HandleMoved(0);
260 - (void)windowDidBecomeKey:(NSNotification *)notification
262 wxNSWindow* window = (wxNSWindow*) [notification object];
263 wxNonOwnedWindowCocoaImpl* windowimpl = [window implementation];
266 wxNonOwnedWindow* wxpeer = windowimpl->GetWXPeer();
268 wxpeer->HandleActivated(0, true);
272 - (void)windowDidResignKey:(NSNotification *)notification
274 wxNSWindow* window = (wxNSWindow*) [notification object];
275 wxNonOwnedWindowCocoaImpl* windowimpl = [window implementation];
278 wxNonOwnedWindow* wxpeer = windowimpl->GetWXPeer();
281 wxpeer->HandleActivated(0, false);
282 // Needed for popup window since the firstResponder
283 // (focus in wx) doesn't change when this
284 // TLW becomes inactive.
285 wxFocusEvent event( wxEVT_KILL_FOCUS, wxpeer->GetId());
286 event.SetEventObject(wxpeer);
287 wxpeer->HandleWindowEvent(event);
294 IMPLEMENT_DYNAMIC_CLASS( wxNonOwnedWindowCocoaImpl , wxNonOwnedWindowImpl )
296 wxNonOwnedWindowCocoaImpl::wxNonOwnedWindowCocoaImpl( wxNonOwnedWindow* nonownedwnd) :
297 wxNonOwnedWindowImpl(nonownedwnd)
300 m_macFullScreenData = NULL;
303 wxNonOwnedWindowCocoaImpl::wxNonOwnedWindowCocoaImpl()
306 m_macFullScreenData = NULL;
309 wxNonOwnedWindowCocoaImpl::~wxNonOwnedWindowCocoaImpl()
311 [m_macWindow setImplementation:nil];
312 [m_macWindow setDelegate:nil];
313 [m_macWindow release];
316 void wxNonOwnedWindowCocoaImpl::Destroy()
318 wxPendingDelete.Append( new wxDeferredObjectDeleter( this ) );
321 void wxNonOwnedWindowCocoaImpl::Create( wxWindow* parent, const wxPoint& pos, const wxSize& size,
322 long style, long extraStyle, const wxString& name )
324 static wxNonOwnedWindowController* controller = NULL;
327 controller =[[wxNonOwnedWindowController alloc] init];
330 int windowstyle = NSBorderlessWindowMask;
332 if ( style & wxFRAME_TOOL_WINDOW || ( style & wxPOPUP_WINDOW ) ||
333 GetWXPeer()->GetExtraStyle() & wxTOPLEVEL_EX_DIALOG )
335 m_macWindow = [wxNSPanel alloc];
338 m_macWindow = [wxNSWindow alloc];
340 CGWindowLevel level = kCGNormalWindowLevel;
342 if ( style & wxFRAME_TOOL_WINDOW )
344 windowstyle |= NSUtilityWindowMask;
345 if ( ( style & wxMINIMIZE_BOX ) || ( style & wxMAXIMIZE_BOX ) ||
346 ( style & wxCLOSE_BOX ) || ( style & wxSYSTEM_MENU ) )
348 windowstyle |= NSTitledWindowMask ;
351 else if ( ( style & wxPOPUP_WINDOW ) )
353 level = kCGPopUpMenuWindowLevel;
355 if ( ( style & wxBORDER_NONE ) )
357 wclass = kHelpWindowClass ; // has no border
358 attr |= kWindowNoShadowAttribute;
362 wclass = kPlainWindowClass ; // has a single line border, it will have to do for now
366 else if ( ( style & wxCAPTION ) )
368 windowstyle |= NSTitledWindowMask ;
370 else if ( ( style & wxFRAME_DRAWER ) )
373 wclass = kDrawerWindowClass;
378 // set these even if we have no title, otherwise the controls won't be visible
379 if ( ( style & wxMINIMIZE_BOX ) || ( style & wxMAXIMIZE_BOX ) ||
380 ( style & wxCLOSE_BOX ) || ( style & wxSYSTEM_MENU ) )
382 windowstyle |= NSTitledWindowMask ;
385 else if ( ( style & wxNO_BORDER ) )
387 wclass = kSimpleWindowClass ;
391 wclass = kPlainWindowClass ;
396 if ( windowstyle & NSTitledWindowMask )
398 if ( ( style & wxMINIMIZE_BOX ) )
399 windowstyle |= NSMiniaturizableWindowMask ;
401 if ( ( style & wxMAXIMIZE_BOX ) )
402 windowstyle |= NSResizableWindowMask ; // TODO showing ZOOM ?
404 if ( ( style & wxRESIZE_BORDER ) )
405 windowstyle |= NSResizableWindowMask ;
407 if ( ( style & wxCLOSE_BOX) )
408 windowstyle |= NSClosableWindowMask ;
410 if ( extraStyle & wxFRAME_EX_METAL)
411 windowstyle |= NSTexturedBackgroundWindowMask;
413 if ( ( style & wxFRAME_FLOAT_ON_PARENT ) || ( style & wxFRAME_TOOL_WINDOW ) )
414 level = kCGFloatingWindowLevel;
416 if ( ( style & wxSTAY_ON_TOP ) )
417 level = kCGUtilityWindowLevel;
419 NSRect r = wxToNSRect( NULL, wxRect( pos, size) );
421 [m_macWindow setImplementation:this];
423 [m_macWindow initWithContentRect:r
424 styleMask:windowstyle
425 backing:NSBackingStoreBuffered
429 [m_macWindow setLevel:level];
431 [m_macWindow setDelegate:controller];
433 [m_macWindow setAcceptsMouseMovedEvents: YES];
437 WXWindow wxNonOwnedWindowCocoaImpl::GetWXWindow() const
442 void wxNonOwnedWindowCocoaImpl::Raise()
444 [m_macWindow orderWindow:NSWindowAbove relativeTo:0];
447 void wxNonOwnedWindowCocoaImpl::Lower()
449 [m_macWindow orderWindow:NSWindowBelow relativeTo:0];
452 bool wxNonOwnedWindowCocoaImpl::Show(bool show)
456 [m_macWindow makeKeyAndOrderFront:nil];
457 [[m_macWindow contentView] setNeedsDisplay:YES];
460 [m_macWindow orderOut:nil];
464 bool wxNonOwnedWindowCocoaImpl::ShowWithEffect(bool show, wxShowEffect effect, unsigned timeout)
469 void wxNonOwnedWindowCocoaImpl::Update()
471 [m_macWindow displayIfNeeded];
474 bool wxNonOwnedWindowCocoaImpl::SetTransparent(wxByte alpha)
476 [m_macWindow setAlphaValue:(CGFloat) alpha/255.0];
480 bool wxNonOwnedWindowCocoaImpl::SetBackgroundColour(const wxColour& col )
485 void wxNonOwnedWindowCocoaImpl::SetExtraStyle( long exStyle )
489 bool metal = exStyle & wxFRAME_EX_METAL ;
490 int windowStyle = [ m_macWindow styleMask];
491 if ( metal && !(windowStyle & NSTexturedBackgroundWindowMask) )
493 wxFAIL_MSG( _T("Metal Style cannot be changed after creation") );
495 else if ( !metal && (windowStyle & NSTexturedBackgroundWindowMask ) )
497 wxFAIL_MSG( _T("Metal Style cannot be changed after creation") );
502 bool wxNonOwnedWindowCocoaImpl::SetBackgroundStyle(wxBackgroundStyle style)
507 bool wxNonOwnedWindowCocoaImpl::CanSetTransparent()
512 void wxNonOwnedWindowCocoaImpl::MoveWindow(int x, int y, int width, int height)
514 NSRect r = wxToNSRect( NULL, wxRect(x,y,width, height) );
515 // do not trigger refreshes upon invisible and possible partly created objects
516 [m_macWindow setFrame:r display:GetWXPeer()->IsShownOnScreen()];
519 void wxNonOwnedWindowCocoaImpl::GetPosition( int &x, int &y ) const
521 wxRect r = wxFromNSRect( NULL, [m_macWindow frame] );
526 void wxNonOwnedWindowCocoaImpl::GetSize( int &width, int &height ) const
528 NSRect rect = [m_macWindow frame];
529 width = rect.size.width;
530 height = rect.size.height;
533 void wxNonOwnedWindowCocoaImpl::GetContentArea( int& left, int &top, int &width, int &height ) const
535 NSRect outer = NSMakeRect(100,100,100,100);
536 NSRect content = [NSWindow contentRectForFrameRect:outer styleMask:[m_macWindow styleMask] ];
537 NSRect rect = [[m_macWindow contentView] frame];
538 left = rect.origin.x;
540 width = rect.size.width;
541 height = rect.size.height;
544 bool wxNonOwnedWindowCocoaImpl::SetShape(const wxRegion& region)
549 void wxNonOwnedWindowCocoaImpl::SetTitle( const wxString& title, wxFontEncoding encoding )
551 [m_macWindow setTitle:wxCFStringRef( title , encoding ).AsNSString()];
554 bool wxNonOwnedWindowCocoaImpl::IsMaximized() const
556 return [m_macWindow isZoomed];
559 bool wxNonOwnedWindowCocoaImpl::IsIconized() const
561 return [m_macWindow isMiniaturized];
564 void wxNonOwnedWindowCocoaImpl::Iconize( bool iconize )
567 [m_macWindow miniaturize:nil];
569 [m_macWindow deminiaturize:nil];
572 void wxNonOwnedWindowCocoaImpl::Maximize(bool maximize)
574 [m_macWindow zoom:nil];
578 // http://cocoadevcentral.com/articles/000028.php
583 NSRect m_formerFrame;
586 bool wxNonOwnedWindowCocoaImpl::IsFullScreen() const
588 return m_macFullScreenData != NULL ;
591 bool wxNonOwnedWindowCocoaImpl::ShowFullScreen(bool show, long style)
595 FullScreenData *data = (FullScreenData *)m_macFullScreenData ;
597 data = new FullScreenData();
599 m_macFullScreenData = data ;
600 data->m_formerLevel = [m_macWindow level];
601 data->m_formerFrame = [m_macWindow frame];
602 CGDisplayCapture( kCGDirectMainDisplay );
603 [m_macWindow setLevel:CGShieldingWindowLevel()];
604 [m_macWindow setFrame:[[NSScreen mainScreen] frame] display:YES];
606 else if ( m_macFullScreenData != NULL )
608 FullScreenData *data = (FullScreenData *) m_macFullScreenData ;
609 CGDisplayRelease( kCGDirectMainDisplay );
610 [m_macWindow setLevel:data->m_formerLevel];
611 [m_macWindow setFrame:data->m_formerFrame display:YES];
613 m_macFullScreenData = NULL ;
619 void wxNonOwnedWindowCocoaImpl::RequestUserAttention(int WXUNUSED(flags))
623 void wxNonOwnedWindowCocoaImpl::ScreenToWindow( int *x, int *y )
625 wxPoint p((x ? *x : 0), (y ? *y : 0) );
626 NSPoint nspt = wxToNSPoint( NULL, p );
627 nspt = [m_macWindow convertScreenToBase:nspt];
628 nspt = [[m_macWindow contentView] convertPoint:nspt fromView:nil];
629 p = wxFromNSPoint([m_macWindow contentView], nspt);
636 void wxNonOwnedWindowCocoaImpl::WindowToScreen( int *x, int *y )
638 wxPoint p((x ? *x : 0), (y ? *y : 0) );
639 NSPoint nspt = wxToNSPoint( [m_macWindow contentView], p );
640 nspt = [[m_macWindow contentView] convertPoint:nspt toView:nil];
641 nspt = [m_macWindow convertBaseToScreen:nspt];
642 p = wxFromNSPoint( NULL, nspt);
649 wxNonOwnedWindowImpl* wxNonOwnedWindowImpl::CreateNonOwnedWindow( wxNonOwnedWindow* wxpeer, wxWindow* parent, const wxPoint& pos, const wxSize& size,
650 long style, long extraStyle, const wxString& name )
652 wxNonOwnedWindowImpl* now = new wxNonOwnedWindowCocoaImpl( wxpeer );
653 now->Create( parent, pos, size, style , extraStyle, name );