// Author: Stefan Csomor
// Modified by:
// Created: 2008-06-20
-// RCS-ID: $Id$
// Copyright: (c) Stefan Csomor
// Licence: wxWindows licence
/////////////////////////////////////////////////////////////////////////////
#include "wx/log.h"
#include "wx/textctrl.h"
#include "wx/combobox.h"
+ #include "wx/radiobut.h"
#endif
#ifdef __WXMAC__
// Get the window with the focus
-NSView* GetViewFromResponder( NSResponder* responder )
+NSView* wxOSXGetViewFromResponder( NSResponder* responder )
{
NSView* view = nil;
if ( [responder isKindOfClass:[NSTextView class]] )
{
NSView* focusedView = nil;
if ( keyWindow != nil )
- focusedView = GetViewFromResponder([keyWindow firstResponder]);
+ focusedView = wxOSXGetViewFromResponder([keyWindow firstResponder]);
return focusedView;
}
WXWidget wxWidgetImpl::FindFocus()
{
- return GetFocusedViewInWindow( [NSApp keyWindow] );
+ return GetFocusedViewInWindow( [NSApp keyWindow] );;
}
+wxWidgetImpl* wxWidgetImpl::FindBestFromWXWidget(WXWidget control)
+{
+ wxWidgetImpl* impl = FindFromWXWidget(control);
+
+ // NSScrollViews can have their subviews like NSClipView
+ // therefore check and use the NSScrollView peer in that case
+ if ( impl == NULL && [[control superview] isKindOfClass:[NSScrollView class]])
+ impl = FindFromWXWidget([control superview]);
+
+ return impl;
+}
+
+
NSRect wxOSXGetFrameForControl( wxWindowMac* window , const wxPoint& pos , const wxSize &size , bool adjustForOrigin )
{
int x, y, w, h ;
@interface wxNSView : NSView
{
- NSTrackingRectTag rectTag;
-#if MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_5
- NSTrackingArea* _trackingArea;
-#endif
+ BOOL _hasToolTip;
+ NSTrackingRectTag _lastToolTipTrackTag;
+ id _lastToolTipOwner;
+ void* _lastUserData;
+
}
-// the tracking tag is needed to track mouse enter / exit events
-- (void) setTrackingTag: (NSTrackingRectTag)tag;
-- (NSTrackingRectTag) trackingTag;
-#if MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_5
-// under 10.5 we can also track mouse moved events on non-focused windows if
-// we use the new NSTrackingArea APIs.
-- (void) updateTrackingArea;
-- (NSTrackingArea*) trackingArea;
-#endif
@end // wxNSView
+@interface wxNSView(TextInput) <NSTextInputClient>
+
+- (void)insertText:(id)aString replacementRange:(NSRange)replacementRange;
+- (void)doCommandBySelector:(SEL)aSelector;
+- (void)setMarkedText:(id)aString selectedRange:(NSRange)selectedRange replacementRange:(NSRange)replacementRange;
+- (void)unmarkText;
+- (NSRange)selectedRange;
+- (NSRange)markedRange;
+- (BOOL)hasMarkedText;
+- (NSAttributedString *)attributedSubstringForProposedRange:(NSRange)aRange actualRange:(NSRangePointer)actualRange;
+- (NSArray*)validAttributesForMarkedText;
+- (NSRect)firstRectForCharacterRange:(NSRange)aRange actualRange:(NSRangePointer)actualRange;
+- (NSUInteger)characterIndexForPoint:(NSPoint)aPoint;
+
+@end
+
@interface NSView(PossibleMethods)
- (void)setTitle:(NSString *)aString;
- (void)setStringValue:(NSString *)aString;
- (void)setImagePosition:(NSCellImagePosition)aPosition;
@end
-// in case we want to use the native tooltip callbacks
-
-#if 0
-
-@interface NSView(wxToolTip)
-- (NSString *)view:(NSView *)view stringForToolTip:(NSToolTipTag)tag point:(NSPoint)point userData:(void *)userData;
-@end
-
-@implementation NSView(wxToolTip)
-
-- (NSString *)view:(NSView *)view stringForToolTip:(NSToolTipTag)tag point:(NSPoint)point userData:(void *)userData {
- wxWidgetCocoaImpl* impl = (wxWidgetCocoaImpl* ) wxWidgetImpl::FindFromWXWidget( view );
- if (impl == NULL)
- return nil;
-
- return @"Tag";
-}
-@end
-
-#endif
-
// The following code is a combination of the code listed here:
// http://lists.apple.com/archives/cocoa-dev/2008/Apr/msg01582.html
// (which can't be used because KLGetCurrentKeyboardLayout etc aren't 64-bit)
case 48:
retval = WXK_TAB;
break;
-
- case 75: // /
- retval = WXK_NUMPAD_DIVIDE;
- break;
- case 67: // *
- retval = WXK_NUMPAD_MULTIPLY;
- break;
- case 78: // -
- retval = WXK_NUMPAD_SUBTRACT;
- break;
- case 69: // +
- retval = WXK_NUMPAD_ADD;
- break;
- case 76: // Enter
- retval = WXK_NUMPAD_ENTER;
- break;
- case 65: // .
- retval = WXK_NUMPAD_DECIMAL;
- break;
- case 82: // 0
- retval = WXK_NUMPAD0;
- break;
- case 83: // 1
- retval = WXK_NUMPAD1;
- break;
- case 84: // 2
- retval = WXK_NUMPAD2;
- break;
- case 85: // 3
- retval = WXK_NUMPAD3;
- break;
- case 86: // 4
- retval = WXK_NUMPAD4;
- break;
- case 87: // 5
- retval = WXK_NUMPAD5;
- break;
- case 88: // 6
- retval = WXK_NUMPAD6;
- break;
- case 89: // 7
- retval = WXK_NUMPAD7;
- break;
- case 91: // 8
- retval = WXK_NUMPAD8;
- break;
- case 92: // 9
- retval = WXK_NUMPAD9;
- break;
default:
- //retval = [event keyCode];
break;
}
+
+ // Check for NUMPAD keys. For KEY_UP/DOWN events we need to use the
+ // WXK_NUMPAD constants, but for the CHAR event we want to use the
+ // standard ascii values
+ if ( eventType != wxEVT_CHAR )
+ {
+ switch( [event keyCode] )
+ {
+ case 75: // /
+ retval = WXK_NUMPAD_DIVIDE;
+ break;
+ case 67: // *
+ retval = WXK_NUMPAD_MULTIPLY;
+ break;
+ case 78: // -
+ retval = WXK_NUMPAD_SUBTRACT;
+ break;
+ case 69: // +
+ retval = WXK_NUMPAD_ADD;
+ break;
+ case 76: // Enter
+ retval = WXK_NUMPAD_ENTER;
+ break;
+ case 65: // .
+ retval = WXK_NUMPAD_DECIMAL;
+ break;
+ case 82: // 0
+ retval = WXK_NUMPAD0;
+ break;
+ case 83: // 1
+ retval = WXK_NUMPAD1;
+ break;
+ case 84: // 2
+ retval = WXK_NUMPAD2;
+ break;
+ case 85: // 3
+ retval = WXK_NUMPAD3;
+ break;
+ case 86: // 4
+ retval = WXK_NUMPAD4;
+ break;
+ case 87: // 5
+ retval = WXK_NUMPAD5;
+ break;
+ case 88: // 6
+ retval = WXK_NUMPAD6;
+ break;
+ case 89: // 7
+ retval = WXK_NUMPAD7;
+ break;
+ case 91: // 8
+ retval = WXK_NUMPAD8;
+ break;
+ case 92: // 9
+ retval = WXK_NUMPAD9;
+ break;
+ default:
+ //retval = [event keyCode];
+ break;
+ }
+ }
return retval;
}
@interface NSEvent (DeviceDelta)
- (CGFloat)deviceDeltaX;
- (CGFloat)deviceDeltaY;
+
+// 10.7+
+- (BOOL)hasPreciseScrollingDeltas;
+- (CGFloat)scrollingDeltaX;
+- (CGFloat)scrollingDeltaY;
@end
-void wxWidgetCocoaImpl::SetupMouseEvent( wxMouseEvent &wxevent , NSEvent * nsEvent )
+void wxWidgetCocoaImpl::SetupCoordinates(wxCoord &x, wxCoord &y, NSEvent* nsEvent)
{
- int eventType = [nsEvent type];
- UInt32 modifiers = [nsEvent modifierFlags] ;
-
NSPoint locationInWindow = [nsEvent locationInWindow];
// adjust coordinates for the window of the target view
{
if ( [nsEvent window] != nil )
locationInWindow = [[nsEvent window] convertBaseToScreen:locationInWindow];
-
+
if ( [m_osxView window] != nil )
locationInWindow = [[m_osxView window] convertScreenToBase:locationInWindow];
}
-
+
NSPoint locationInView = [m_osxView convertPoint:locationInWindow fromView:nil];
wxPoint locationInViewWX = wxFromNSPoint( m_osxView, locationInView );
+
+ x = locationInViewWX.x;
+ y = locationInViewWX.y;
+
+}
+
+void wxWidgetCocoaImpl::SetupMouseEvent( wxMouseEvent &wxevent , NSEvent * nsEvent )
+{
+ int eventType = [nsEvent type];
+ UInt32 modifiers = [nsEvent modifierFlags] ;
+
+ SetupCoordinates(wxevent.m_x, wxevent.m_y, nsEvent);
// these parameters are not given for all events
UInt32 button = [nsEvent buttonNumber];
UInt32 clickCount = 0;
- wxevent.m_x = locationInViewWX.x;
- wxevent.m_y = locationInViewWX.y;
wxevent.m_shiftDown = modifiers & NSShiftKeyMask;
wxevent.m_rawControlDown = modifiers & NSControlKeyMask;
wxevent.m_altDown = modifiers & NSAlternateKeyMask;
wxevent.SetEventType( wxEVT_MOUSEWHEEL ) ;
- // see http://developer.apple.com/qa/qa2005/qa1453.html
- // for more details on why we have to look for the exact type
-
- const EventRef cEvent = (EventRef) [nsEvent eventRef];
- bool isMouseScrollEvent = false;
- if ( cEvent )
- isMouseScrollEvent = ::GetEventKind(cEvent) == kEventMouseScroll;
-
- if ( isMouseScrollEvent )
+ if ( UMAGetSystemVersion() >= 0x1070 )
{
- deltaX = [nsEvent deviceDeltaX];
- deltaY = [nsEvent deviceDeltaY];
+ if ( [nsEvent hasPreciseScrollingDeltas] )
+ {
+ deltaX = [nsEvent scrollingDeltaX];
+ deltaY = [nsEvent scrollingDeltaY];
+ }
+ else
+ {
+ deltaX = [nsEvent scrollingDeltaX] * 10;
+ deltaY = [nsEvent scrollingDeltaY] * 10;
+ }
}
else
{
- deltaX = ([nsEvent deltaX] * 10);
- deltaY = ([nsEvent deltaY] * 10);
+ const EventRef cEvent = (EventRef) [nsEvent eventRef];
+ // see http://developer.apple.com/qa/qa2005/qa1453.html
+ // for more details on why we have to look for the exact type
+
+ bool isMouseScrollEvent = false;
+ if ( cEvent )
+ isMouseScrollEvent = ::GetEventKind(cEvent) == kEventMouseScroll;
+
+ if ( isMouseScrollEvent )
+ {
+ deltaX = [nsEvent deviceDeltaX];
+ deltaY = [nsEvent deviceDeltaY];
+ }
+ else
+ {
+ deltaX = ([nsEvent deltaX] * 10);
+ deltaY = ([nsEvent deltaY] * 10);
+ }
}
wxevent.m_wheelDelta = 10;
wxevent.m_linesPerAction = 1;
+ wxevent.m_columnsPerAction = 1;
if ( fabs(deltaX) > fabs(deltaY) )
{
- wxevent.m_wheelAxis = 1;
- wxevent.m_wheelRotation = (int)deltaX;
+ // wx conventions for horizontal are inverted from vertical (originating from native msw behavior)
+ // right and up are positive values, left and down are negative values, while on OSX right and down
+ // are negative and left and up are positive.
+ wxevent.m_wheelAxis = wxMOUSE_WHEEL_HORIZONTAL;
+ wxevent.m_wheelRotation = -(int)deltaX;
}
else
{
}
}
-- (void) setTrackingTag: (NSTrackingRectTag)tag
+/* idea taken from webkit sources: overwrite the methods that (private) NSToolTipManager will use to attach its tracking rectangle
+ * then when changing the tooltip send fake view-exit and view-enter methods which will lead to a tooltip refresh
+ */
+
+
+- (void)_sendToolTipMouseExited
{
- rectTag = tag;
+ // Nothing matters except window, trackingNumber, and userData.
+ NSEvent *fakeEvent = [NSEvent enterExitEventWithType:NSMouseExited
+ location:NSMakePoint(0, 0)
+ modifierFlags:0
+ timestamp:0
+ windowNumber:[[self window] windowNumber]
+ context:NULL
+ eventNumber:0
+ trackingNumber:_lastToolTipTrackTag
+ userData:_lastUserData];
+ [_lastToolTipOwner mouseExited:fakeEvent];
}
-- (NSTrackingRectTag) trackingTag
+- (void)_sendToolTipMouseEntered
{
- return rectTag;
+ // Nothing matters except window, trackingNumber, and userData.
+ NSEvent *fakeEvent = [NSEvent enterExitEventWithType:NSMouseEntered
+ location:NSMakePoint(0, 0)
+ modifierFlags:0
+ timestamp:0
+ windowNumber:[[self window] windowNumber]
+ context:NULL
+ eventNumber:0
+ trackingNumber:_lastToolTipTrackTag
+ userData:_lastUserData];
+ [_lastToolTipOwner mouseEntered:fakeEvent];
}
-#if MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_5
-- (void) updateTrackingArea
+- (void)setToolTip:(NSString *)string;
{
- if (_trackingArea)
+ if (string)
{
- [self removeTrackingArea: _trackingArea];
- [_trackingArea release];
+ if ( _hasToolTip )
+ {
+ [self _sendToolTipMouseExited];
+ }
+
+ [super setToolTip:string];
+ _hasToolTip = YES;
+ [self _sendToolTipMouseEntered];
}
-
- NSTrackingAreaOptions options = NSTrackingMouseEnteredAndExited|NSTrackingMouseMoved|NSTrackingActiveAlways;
-
- NSTrackingArea* area = [[NSTrackingArea alloc] initWithRect: [self bounds] options: options owner: self userInfo: nil];
- [self addTrackingArea: area];
+ else
+ {
+ if ( _hasToolTip )
+ {
+ [self _sendToolTipMouseExited];
+ [super setToolTip:nil];
+ _hasToolTip = NO;
+ }
+ }
+}
+
+- (NSTrackingRectTag)addTrackingRect:(NSRect)rect owner:(id)owner userData:(void *)data assumeInside:(BOOL)assumeInside
+{
+ NSTrackingRectTag tag = [super addTrackingRect:rect owner:owner userData:data assumeInside:assumeInside];
+ if ( owner != self )
+ {
+ _lastUserData = data;
+ _lastToolTipOwner = owner;
+ _lastToolTipTrackTag = tag;
+ }
+ return tag;
+}
- _trackingArea = area;
+- (void)removeTrackingRect:(NSTrackingRectTag)tag
+{
+ if (tag == _lastToolTipTrackTag)
+ {
+ _lastUserData = NULL;
+ _lastToolTipOwner = nil;
+ _lastToolTipTrackTag = 0;
+ }
+ [super removeTrackingRect:tag];
}
-- (NSTrackingArea*) trackingArea
+#if wxOSX_USE_NATIVE_FLIPPED
+- (BOOL)isFlipped
{
- return _trackingArea;
+ return YES;
}
#endif
+
+- (BOOL) canBecomeKeyView
+{
+ wxWidgetCocoaImpl* viewimpl = (wxWidgetCocoaImpl* ) wxWidgetImpl::FindFromWXWidget( self );
+ if ( viewimpl && viewimpl->IsUserPane() && viewimpl->GetWXPeer() )
+ return viewimpl->GetWXPeer()->AcceptsFocus();
+ return NO;
+}
+
@end // wxNSView
+// We need to adopt NSTextInputClient protocol in order to interpretKeyEvents: to work.
+// Currently, only insertText:(replacementRange:) is
+// implemented here, and the rest of the methods are stubs.
+// It is hoped that someday IME-related functionality is implemented in
+// wxWidgets and the methods of this protocol are fully working.
+
+@implementation wxNSView(TextInput)
+
+void wxOSX_insertText(NSView* self, SEL _cmd, NSString* text);
+
+- (void)insertText:(id)aString replacementRange:(NSRange)replacementRange
+{
+ wxOSX_insertText(self, @selector(insertText:), aString);
+}
+
+- (void)doCommandBySelector:(SEL)aSelector
+{
+ // these are already caught in the keyEvent handler
+}
+
+- (void)setMarkedText:(id)aString selectedRange:(NSRange)selectedRange replacementRange:(NSRange)replacementRange
+{
+}
+
+- (void)unmarkText
+{
+}
+
+- (NSRange)selectedRange
+{
+ return NSMakeRange(NSNotFound, 0);
+}
+
+- (NSRange)markedRange
+{
+ return NSMakeRange(NSNotFound, 0);
+}
+
+- (BOOL)hasMarkedText
+{
+ return NO;
+}
+
+- (NSAttributedString *)attributedSubstringForProposedRange:(NSRange)aRange actualRange:(NSRangePointer)actualRange
+{
+ return nil;
+}
+
+- (NSArray*)validAttributesForMarkedText
+{
+ return nil;
+}
+
+- (NSRect)firstRectForCharacterRange:(NSRange)aRange actualRange:(NSRangePointer)actualRange
+{
+ return NSMakeRect(0, 0, 0, 0);
+}
+- (NSUInteger)characterIndexForPoint:(NSPoint)aPoint
+{
+ return NSNotFound;
+}
+
+@end // wxNSView(TextInput)
+
+
//
// event handlers
//
impl->mouseEvent(event, self, _cmd);
}
+void wxOSX_cursorUpdate(NSView* self, SEL _cmd, NSEvent *event)
+{
+ wxWidgetCocoaImpl* impl = (wxWidgetCocoaImpl* ) wxWidgetImpl::FindFromWXWidget( self );
+ if (impl == NULL)
+ return;
+
+ impl->cursorUpdate(event, self, _cmd);
+}
+
BOOL wxOSX_acceptsFirstMouse(NSView* WXUNUSED(self), SEL WXUNUSED(_cmd), NSEvent *WXUNUSED(event))
{
// This is needed to support click through, otherwise the first click on a window
return impl->resignFirstResponder(self, _cmd);
}
-void wxOSX_resetCursorRects(NSView* self, SEL _cmd)
-{
- wxWidgetCocoaImpl* impl = (wxWidgetCocoaImpl* ) wxWidgetImpl::FindFromWXWidget( self );
- if (impl == NULL)
- return;
-
- impl->resetCursorRects(self, _cmd);
-}
+#if !wxOSX_USE_NATIVE_FLIPPED
BOOL wxOSX_isFlipped(NSView* self, SEL _cmd)
{
return impl->isFlipped(self, _cmd) ? YES:NO;
}
+#endif
+
typedef void (*wxOSX_DrawRectHandlerPtr)(NSView* self, SEL _cmd, NSRect rect);
void wxOSX_drawRect(NSView* self, SEL _cmd, NSRect rect)
if (impl == NULL)
return;
-#ifdef wxUSE_THREADS
+#if wxUSE_THREADS
// OS X starts a NSUIHeartBeatThread for animating the default button in a
// dialog. This causes a drawRect of the active dialog from outside the
// main UI thread. This causes an occasional crash since the wx drawing
return result != wxDragNone;
}
-typedef void (*wxOSX_TextEventHandlerPtr)(NSView* self, SEL _cmd, NSString *event);
-typedef void (*wxOSX_EventHandlerPtr)(NSView* self, SEL _cmd, NSEvent *event);
-typedef BOOL (*wxOSX_PerformKeyEventHandlerPtr)(NSView* self, SEL _cmd, NSEvent *event);
-typedef BOOL (*wxOSX_FocusHandlerPtr)(NSView* self, SEL _cmd);
-typedef BOOL (*wxOSX_ResetCursorRectsHandlerPtr)(NSView* self, SEL _cmd);
-
void wxWidgetCocoaImpl::mouseEvent(WX_NSEvent event, WXWidget slf, void *_cmd)
{
+ // we are getting moved events for all windows in the hierarchy, not something wx expects
+ // therefore we only handle it for the deepest child in the hierarchy
+ if ( [event type] == NSMouseMoved )
+ {
+ NSView* hitview = [[[slf window] contentView] hitTest:[event locationInWindow]];
+ if ( hitview == NULL || hitview != slf)
+ return;
+ }
+
if ( !DoHandleMouseEvent(event) )
{
// for plain NSView mouse events would propagate to parents otherwise
- if (!IsUserPane())
+ // scrollwheel events have to be propagated if not handled in all cases
+ if (!IsUserPane() || [event type] == NSScrollWheel )
{
wxOSX_EventHandlerPtr superimpl = (wxOSX_EventHandlerPtr) [[slf superclass] instanceMethodForSelector:(SEL)_cmd];
superimpl(slf, (SEL)_cmd, event);
// super of built-ins keeps the mouse up, as wx expects this event, we have to synthesize it
-
- if ( [ event type] == NSLeftMouseDown )
+ // only trigger if at this moment the mouse is already up
+ if ( [ event type] == NSLeftMouseDown && !wxGetMouseState().LeftIsDown() )
{
wxMouseEvent wxevent(wxEVT_LEFT_DOWN);
SetupMouseEvent(wxevent , event) ;
}
}
+void wxWidgetCocoaImpl::cursorUpdate(WX_NSEvent event, WXWidget slf, void *_cmd)
+{
+ if ( !SetupCursor(event) )
+ {
+ wxOSX_EventHandlerPtr superimpl = (wxOSX_EventHandlerPtr) [[slf superclass] instanceMethodForSelector:(SEL)_cmd];
+ superimpl(slf, (SEL)_cmd, event);
+ }
+ }
+
+bool wxWidgetCocoaImpl::SetupCursor(WX_NSEvent event)
+{
+ extern wxCursor gGlobalCursor;
+
+ if ( gGlobalCursor.IsOk() )
+ {
+ gGlobalCursor.MacInstall();
+ return true;
+ }
+ else
+ {
+ wxWindow* cursorTarget = GetWXPeer();
+ wxCoord x,y;
+ SetupCoordinates(x, y, event);
+ wxPoint cursorPoint( x , y ) ;
+
+ while ( cursorTarget && !cursorTarget->MacSetupCursor( cursorPoint ) )
+ {
+ // at least in GTK cursor events are not propagated either ...
+#if 1
+ cursorTarget = NULL;
+#else
+ cursorTarget = cursorTarget->GetParent() ;
+ if ( cursorTarget )
+ cursorPoint += cursorTarget->GetPosition();
+#endif
+ }
+
+ return cursorTarget != NULL;
+ }
+}
+
void wxWidgetCocoaImpl::keyEvent(WX_NSEvent event, WXWidget slf, void *_cmd)
{
if ( [event type] == NSKeyDown )
{
wxEvtHandler * const handler = m_wxPeer->GetEventHandler();
- wxCommandEvent command_event( wxEVT_COMMAND_MENU_SELECTED, command );
+ wxCommandEvent command_event( wxEVT_MENU, command );
command_event.SetEventObject( wxevent.GetEventObject() );
handled = handler->ProcessEvent( command_event );
if ( !handled )
{
// accelerators can also be used with buttons, try them too
- command_event.SetEventType(wxEVT_COMMAND_BUTTON_CLICKED);
+ command_event.SetEventType(wxEVT_BUTTON);
handled = handler->ProcessEvent( command_event );
}
}
{
wxOSX_FocusHandlerPtr superimpl = (wxOSX_FocusHandlerPtr) [[slf superclass] instanceMethodForSelector:(SEL)_cmd];
BOOL r = superimpl(slf, (SEL)_cmd);
- // get the current focus after running resignFirstResponder
- // note that this value isn't reliable, it might return the same view that
- // is resigning
- NSView* otherView = FindFocus();
- wxWidgetImpl* otherWindow = FindFromWXWidget(otherView);
+
+ NSResponder * responder = wxNonOwnedWindowCocoaImpl::GetNextFirstResponder();
+ NSView* otherView = wxOSXGetViewFromResponder(responder);
- // It doesn't make sense to notify about the loss of focus if we're not
- // really losing it and the window which has just gained focus is the same
- // one as this window itself. Of course, this should never happen in the
- // first place but somehow it does in wxGrid code and without this check we
- // enter into an infinite recursion, see #12267.
+ wxWidgetImpl* otherWindow = FindBestFromWXWidget(otherView);
+
+ // It doesn't make sense to notify about the loss of focus if it's the same
+ // control in the end, and just a different subview
if ( otherWindow == this )
return r;
-
+
// NSTextViews have an editor as true responder, therefore the might get the
// resign notification if their editor takes over, don't trigger any event then
if ( r && !m_hasEditor)
return r;
}
-void wxWidgetCocoaImpl::resetCursorRects(WXWidget slf, void *_cmd)
-{
- wxWindow* wxpeer = GetWXPeer();
- if ( wxpeer )
- {
- NSCursor *cursor = (NSCursor*)wxpeer->GetCursor().GetHCURSOR();
- if (cursor == NULL)
- {
- wxOSX_ResetCursorRectsHandlerPtr superimpl = (wxOSX_ResetCursorRectsHandlerPtr) [[slf superclass] instanceMethodForSelector:(SEL)_cmd];
- superimpl(slf, (SEL)_cmd);
- }
- else
- {
- [slf addCursorRect: [slf bounds]
- cursor: cursor];
- }
- }
-}
+#if !wxOSX_USE_NATIVE_FLIPPED
-bool wxWidgetCocoaImpl::isFlipped(WXWidget WXUNUSED(slf), void *WXUNUSED(_cmd))
+bool wxWidgetCocoaImpl::isFlipped(WXWidget slf, void *WXUNUSED(_cmd))
{
return m_isFlipped;
}
+#endif
#define OSX_DEBUG_DRAWING 0
// preparing the update region
wxRegion updateRgn;
+
+ // since adding many rects to a region is a costly process, by default use the bounding rect
+#if 0
const NSRect *rects;
NSInteger count;
-
[slf getRectsBeingDrawn:&rects count:&count];
for ( int i = 0 ; i < count ; ++i )
{
updateRgn.Union(wxFromNSRect(slf, rects[i]));
}
-
+#else
+ updateRgn.Union(wxFromNSRect(slf,*(NSRect*)rect));
+#endif
+
wxWindow* wxpeer = GetWXPeer();
if ( wxpeer->MacGetLeftBorderSize() != 0 || wxpeer->MacGetTopBorderSize() != 0 )
CGContextStrokePath(context);
#endif
- if ( !m_isFlipped )
+ if ( ![slf isFlipped] )
{
CGContextTranslateCTM( context, 0, [m_osxView bounds].size.height );
CGContextScaleCTM( context, 1, -1 );
CGContextSaveGState( context );
}
// as we called restore above, we have to flip again if necessary
- if ( !m_isFlipped )
+ if ( ![slf isFlipped] )
{
CGContextTranslateCTM( context, 0, [m_osxView bounds].size.height );
CGContextScaleCTM( context, 1, -1 );
{
wxWindow* wxpeer = (wxWindow*) GetWXPeer();
if ( wxpeer )
+ {
+ wxpeer->OSXSimulateFocusEvents();
wxpeer->OSXHandleClicked(0);
+ }
}
void wxWidgetCocoaImpl::controlDoubleAction( WXWidget WXUNUSED(slf), void *WXUNUSED(_cmd), void *WXUNUSED(sender))
wxOSX_CLASS_ADD_METHOD(c, @selector(mouseEntered:), (IMP) wxOSX_mouseEvent, "v@:@" )
wxOSX_CLASS_ADD_METHOD(c, @selector(mouseExited:), (IMP) wxOSX_mouseEvent, "v@:@" )
+ wxOSX_CLASS_ADD_METHOD(c, @selector(cursorUpdate:), (IMP) wxOSX_cursorUpdate, "v@:@" )
+
wxOSX_CLASS_ADD_METHOD(c, @selector(keyDown:), (IMP) wxOSX_keyEvent, "v@:@" )
wxOSX_CLASS_ADD_METHOD(c, @selector(keyUp:), (IMP) wxOSX_keyEvent, "v@:@" )
wxOSX_CLASS_ADD_METHOD(c, @selector(flagsChanged:), (IMP) wxOSX_keyEvent, "v@:@" )
wxOSX_CLASS_ADD_METHOD(c, @selector(acceptsFirstResponder), (IMP) wxOSX_acceptsFirstResponder, "c@:" )
wxOSX_CLASS_ADD_METHOD(c, @selector(becomeFirstResponder), (IMP) wxOSX_becomeFirstResponder, "c@:" )
wxOSX_CLASS_ADD_METHOD(c, @selector(resignFirstResponder), (IMP) wxOSX_resignFirstResponder, "c@:" )
- wxOSX_CLASS_ADD_METHOD(c, @selector(resetCursorRects), (IMP) wxOSX_resetCursorRects, "v@:" )
+#if !wxOSX_USE_NATIVE_FLIPPED
wxOSX_CLASS_ADD_METHOD(c, @selector(isFlipped), (IMP) wxOSX_isFlipped, "c@:" )
+#endif
wxOSX_CLASS_ADD_METHOD(c, @selector(drawRect:), (IMP) wxOSX_drawRect, "v@:{_NSRect={_NSPoint=ff}{_NSSize=ff}}" )
wxOSX_CLASS_ADD_METHOD(c, @selector(controlAction:), (IMP) wxOSX_controlAction, "v@:@" )
void wxWidgetCocoaImpl::Init()
{
m_osxView = NULL;
+#if !wxOSX_USE_NATIVE_FLIPPED
m_isFlipped = true;
+#endif
m_lastKeyDownEvent = NULL;
m_hasEditor = false;
}
[m_osxView setHidden:(visible ? NO:YES)];
}
+double wxWidgetCocoaImpl::GetContentScaleFactor() const
+{
+#if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_7
+ NSWindow* tlw = [m_osxView window];
+ if ( [ tlw respondsToSelector:@selector(backingScaleFactor) ] )
+ return [tlw backingScaleFactor];
+ else
+#endif
+ return 1.0;
+}
+
// ----------------------------------------------------------------------------
// window animation stuff
// ----------------------------------------------------------------------------
wxUnusedVar(progress);
m_win->SendSizeEvent();
- m_win->MacOnInternalSize();
}
- (void)animationDidEnd:(NSAnimation*)animation
// refresh it once again after the end to ensure that everything is in
// place
win->SendSizeEvent();
- win->MacOnInternalSize();
}
[anim setDelegate:nil];
NSRect r = wxToNSRect( [m_osxView superview], wxRect(x,y,width, height) );
[m_osxView setFrame:r];
[[m_osxView superview] setNeedsDisplayInRect:r];
-
- wxNSView* wxview = (wxNSView*)m_osxView;
-#if MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_5
- if ([wxview respondsToSelector:@selector(updateTrackingArea)] )
- [wxview updateTrackingArea];
-#else
- if ([m_osxView respondsToSelector:@selector(trackingTag)] )
- {
- if ( [wxview trackingTag] )
- [wxview removeTrackingRect: [wxview trackingTag]];
-
- [wxview setTrackingTag: [wxview addTrackingRect: [m_osxView bounds] owner: wxview userData: nil assumeInside: NO]];
- }
-#endif
}
void wxWidgetCocoaImpl::GetPosition( int &x, int &y ) const
return true;
}
+void wxWidgetCocoaImpl::SetDropTarget(wxDropTarget* target)
+{
+ [m_osxView unregisterDraggedTypes];
+
+ if ( target == NULL )
+ return;
+
+ wxDataObject* dobj = target->GetDataObject();
+
+ if( dobj )
+ {
+ CFMutableArrayRef typesarray = CFArrayCreateMutable(kCFAllocatorDefault,0,&kCFTypeArrayCallBacks);
+ dobj->AddSupportedTypes(typesarray);
+ NSView* targetView = m_osxView;
+ if ( [m_osxView isKindOfClass:[NSScrollView class] ] )
+ targetView = [(NSScrollView*) m_osxView documentView];
+
+ [targetView registerForDraggedTypes:(NSArray*)typesarray];
+ CFRelease(typesarray);
+ }
+}
void wxWidgetCocoaImpl::RemoveFromParent()
{
NSView* container = parent->GetWXWidget() ;
wxASSERT_MSG( container != NULL , wxT("No valid mac container control") ) ;
[container addSubview:m_osxView];
+
+ if( m_wxPeer->IsFrozen() )
+ [[m_osxView window] disableFlushWindow];
}
void wxWidgetCocoaImpl::SetBackgroundColour( const wxColour &col )
if ([cell respondsToSelector:@selector(setControlSize:)])
[cell setControlSize:size];
}
+
+ // we need to propagate this to inner views as well
+ if ( [m_osxView isKindOfClass:[NSScrollView class] ] )
+ {
+ NSView* targetView = [(NSScrollView*) m_osxView documentView];
+
+ if ( [targetView respondsToSelector:@selector(setControlSize:)] )
+ [targetView setControlSize:size];
+ else if ([targetView respondsToSelector:@selector(cell)])
+ {
+ id cell = [(id)targetView cell];
+ if ([cell respondsToSelector:@selector(setControlSize:)])
+ [cell setControlSize:size];
+ }
+ }
}
void wxWidgetCocoaImpl::SetFont(wxFont const& font, wxColour const&col, long, bool)
{
- if ([m_osxView respondsToSelector:@selector(setFont:)])
- [m_osxView setFont: font.OSXGetNSFont()];
- if ([m_osxView respondsToSelector:@selector(setTextColor:)])
- [m_osxView setTextColor:[NSColor colorWithCalibratedRed:(CGFloat) (col.Red() / 255.0)
+ NSView* targetView = m_osxView;
+ if ( [m_osxView isKindOfClass:[NSScrollView class] ] )
+ targetView = [(NSScrollView*) m_osxView documentView];
+
+ if ([targetView respondsToSelector:@selector(setFont:)])
+ [targetView setFont: font.OSXGetNSFont()];
+ if ([targetView respondsToSelector:@selector(setTextColor:)])
+ [targetView setTextColor:[NSColor colorWithCalibratedRed:(CGFloat) (col.Red() / 255.0)
green:(CGFloat) (col.Green() / 255.0)
blue:(CGFloat) (col.Blue() / 255.0)
alpha:(CGFloat) (col.Alpha() / 255.0)]];
}
-NSToolTipTag tt = 0;
-
void wxWidgetCocoaImpl::SetToolTip(wxToolTip* tooltip)
{
- if (tooltip)
+ if ( tooltip )
{
- /*
- if ( tt != 0 )
- {
- [m_osxView removeToolTip:tt];
- tt = 0;
- }
- */
wxCFStringRef cf( tooltip->GetTip() , m_wxPeer->GetFont().GetEncoding() );
[m_osxView setToolTip: cf.AsNSString()];
- // tt = [m_osxView addToolTipRect:[m_osxView bounds] owner:m_osxView userData:nil];
}
else
{
- if ( tt != 0 )
- {
- [m_osxView removeToolTip:tt];
- tt = 0;
- }
+ [m_osxView setToolTip:nil];
}
-
}
void wxWidgetCocoaImpl::InstallEventHandler( WXWidget control )
if ([c respondsToSelector:@selector(setAction:)])
{
[c setTarget: c];
- [c setAction: @selector(controlAction:)];
+ if ( dynamic_cast<wxRadioButton*>(GetWXPeer()) )
+ {
+ // everything already set up
+ }
+ else
+ [c setAction: @selector(controlAction:)];
+
if ([c respondsToSelector:@selector(setDoubleAction:)])
{
[c setDoubleAction: @selector(controlDoubleAction:)];
}
}
-}
+ NSTrackingAreaOptions options = NSTrackingMouseEnteredAndExited|NSTrackingCursorUpdate|NSTrackingMouseMoved|NSTrackingActiveAlways|NSTrackingInVisibleRect;
+ NSTrackingArea* area = [[NSTrackingArea alloc] initWithRect: NSZeroRect options: options owner: m_osxView userInfo: nil];
+ [m_osxView addTrackingArea: area];
+ [area release];
+ }
bool wxWidgetCocoaImpl::DoHandleCharEvent(NSEvent *event, NSString *text)
{
- wxKeyEvent wxevent(wxEVT_CHAR);
- SetupKeyEvent( wxevent, event, text );
+ bool result = false;
+
+ for (NSUInteger i = 0; i < [text length]; ++i)
+ {
+ wxKeyEvent wxevent(wxEVT_CHAR);
+ unichar c = [text characterAtIndex:i];
+ SetupKeyEvent( wxevent, event, [NSString stringWithCharacters:&c length:1]);
- return GetWXPeer()->OSXHandleKeyEvent(wxevent);
+ result = GetWXPeer()->OSXHandleKeyEvent(wxevent) || result;
+ }
+
+ return result;
}
bool wxWidgetCocoaImpl::DoHandleKeyEvent(NSEvent *event)
if ( !result )
{
- if ( IsUserPane() && [event type] == NSKeyDown)
+ if ( [event type] == NSKeyDown)
{
long keycode = wxOSXTranslateCocoaKey( event, wxEVT_CHAR );
// eventually we could setup a doCommandBySelector catcher and retransform this into the wx key chars
wxKeyEvent wxevent2(wxevent) ;
wxevent2.SetEventType(wxEVT_CHAR);
+ SetupKeyEvent( wxevent2, event );
wxevent2.m_keyCode = keycode;
result = GetWXPeer()->OSXHandleKeyEvent(wxevent2);
}
+ else if (wxevent.CmdDown())
+ {
+ wxKeyEvent wxevent2(wxevent) ;
+ wxevent2.SetEventType(wxEVT_CHAR);
+ SetupKeyEvent( wxevent2, event );
+ result = GetWXPeer()->OSXHandleKeyEvent(wxevent2);
+ }
else
{
- if ( !wxevent.CmdDown() )
+ if ( IsUserPane() && !wxevent.CmdDown() )
{
if ( [m_osxView isKindOfClass:[NSScrollView class] ] )
[[(NSScrollView*)m_osxView documentView] interpretKeyEvents:[NSArray arrayWithObject:event]];
{
wxMouseEvent wxevent(wxEVT_LEFT_DOWN);
SetupMouseEvent(wxevent , event) ;
+ bool result = GetWXPeer()->HandleWindowEvent(wxevent);
+
+ (void)SetupCursor(event);
- return GetWXPeer()->HandleWindowEvent(wxevent);
+ return result;
}
void wxWidgetCocoaImpl::DoNotifyFocusEvent(bool receivedFocus, wxWidgetImpl* otherWindow)
event.SetWindow(otherWindow->GetWXPeer());
thisWindow->HandleWindowEvent(event) ;
}
- else // !receivedFocuss
+ else // !receivedFocus
{
#if wxUSE_CARET
if ( thisWindow->GetCaret() )
[(NSCursor*)cursor.GetHCURSOR() set];
}
}
- [[m_osxView window] invalidateCursorRectsForView:m_osxView];
}
void wxWidgetCocoaImpl::CaptureMouse()
{
- [[m_osxView window] disableCursorRects];
+ // TODO remove if we don't get into problems with cursor settings
+ // [[m_osxView window] disableCursorRects];
}
void wxWidgetCocoaImpl::ReleaseMouse()
{
- [[m_osxView window] enableCursorRects];
+ // TODO remove if we don't get into problems with cursor settings
+ // [[m_osxView window] enableCursorRects];
}
+#if !wxOSX_USE_NATIVE_FLIPPED
+
void wxWidgetCocoaImpl::SetFlipped(bool flipped)
{
m_isFlipped = flipped;
}
+#endif
+
+void wxWidgetCocoaImpl::SetDrawingEnabled(bool enabled)
+{
+ if ( enabled )
+ {
+ [[m_osxView window] enableFlushWindow];
+ [m_osxView setNeedsDisplay:YES];
+ }
+ else
+ {
+ [[m_osxView window] disableFlushWindow];
+ }
+}
//
// Factory methods
//
NSRect r = wxOSXGetFrameForControl( wxpeer, pos , size ) ;
wxNSView* v = [[wxNSView alloc] initWithFrame:r];
- // temporary hook for dnd
- [v registerForDraggedTypes:[NSArray arrayWithObjects:
- NSStringPboardType, NSFilenamesPboardType, NSTIFFPboardType, NSPICTPboardType, NSPDFPboardType, nil]];
-
wxWidgetCocoaImpl* c = new wxWidgetCocoaImpl( wxpeer, v, false, true );
return c;
}
{
NSView* cv = [tlw contentView];
c = new wxWidgetCocoaImpl( now, cv, true );
- // increase ref count, because the impl destructor will decrement it again
- CFRetain(cv);
- if ( !now->IsShown() )
- [cv setHidden:NO];
-
+ if ( cv != nil )
+ {
+ // increase ref count, because the impl destructor will decrement it again
+ CFRetain(cv);
+ if ( !now->IsShown() )
+ [cv setHidden:NO];
+ }
}
else
{