From f5ef0eb1a6543abdd29e07c23de7fa1128f6d623 Mon Sep 17 00:00:00 2001 From: Norwegian Rock Cat Date: Thu, 26 Mar 2009 16:10:05 +0100 Subject: Fix a bug where lineedits in a second page of a stack widget would not get key events. We need to be more explicit in setting the first responder, and a bit more agressing about rejecting it when called with no responder. It seems that Cocoa has a tendency to reset the first responder when lots of widgets get hidden or shown. During this it will call "makeFirstResponder" on the window with a nil responder. Doing this will reset our what Cocoa thinks is the focus widget, but Qt will still show a focus widget. The way to solve it is to reject the make first responder if the responder is nil. I'm not sure if there will be far reaching implications for this, but it seems to be doing the right thing at the moment. We also need to share this code between QCocoaWindow and QCocoaPanel. Thanks to the dynamic nature of objective-C we have to have a copy of the code in both places. It's unfortunate. Finally, it's also important to have the QWidget let Cocoa know it has focus after it has been created. So, make sure that is in sync. Task-number: 249296 Reviewed-by: Prasanth Ullattil --- src/gui/kernel/qcocoapanel_mac.mm | 102 ++++++++++++++++++++++++++++++++++++- src/gui/kernel/qcocoawindow_mac.mm | 18 +++++++ src/gui/kernel/qwidget_mac.mm | 2 + 3 files changed, 121 insertions(+), 1 deletion(-) diff --git a/src/gui/kernel/qcocoapanel_mac.mm b/src/gui/kernel/qcocoapanel_mac.mm index 6aeee34..c17b30c 100644 --- a/src/gui/kernel/qcocoapanel_mac.mm +++ b/src/gui/kernel/qcocoapanel_mac.mm @@ -43,10 +43,14 @@ #ifdef QT_MAC_USE_COCOA #import #import +#import +#import #import #include +extern Qt::MouseButton cocoaButton2QtButton(NSInteger buttonNum); // qcocoaview.mm + QT_USE_NAMESPACE @implementation QT_MANGLE_NAMESPACE(QCocoaPanel) @@ -60,14 +64,110 @@ QT_USE_NAMESPACE return !(isPopup || isToolTip); } +/*********************************************************************** + BEGIN Copy and Paste between QCocoaWindow and QCocoaPanel + This is a bit unfortunate, but thanks to the dynamic dispatch we + have to duplicate this code or resort to really silly forwarding methods +**************************************************************************/ + +/* + The methods keyDown, keyUp, and flagsChanged... These really shouldn't ever + get hit. We automatically say we can be first responder if we are a window. + So, the handling should get handled by the view. This is here more as a + last resort (i.e., this is code that can potentially be removed). + */ + +- (void)keyDown:(NSEvent *)theEvent +{ + bool keyOK = qt_dispatchKeyEvent(theEvent, [self QT_MANGLE_NAMESPACE(qt_qwidget)]); + if (!keyOK) + [super keyDown:theEvent]; +} + +- (void)keyUp:(NSEvent *)theEvent +{ + bool keyOK = qt_dispatchKeyEvent(theEvent, [self QT_MANGLE_NAMESPACE(qt_qwidget)]); + if (!keyOK) + [super keyUp:theEvent]; +} + +- (void)flagsChanged:(NSEvent *)theEvent +{ + qt_dispatchModifiersChanged(theEvent, [self QT_MANGLE_NAMESPACE(qt_qwidget)]); + [super flagsChanged:theEvent]; +} + + +- (void)tabletProximity:(NSEvent *)tabletEvent +{ + qt_dispatchTabletProximityEvent(tabletEvent); +} + - (void)sendEvent:(NSEvent *)event { [self retain]; - [super sendEvent:event]; + + QWidget *widget = [[QT_MANGLE_NAMESPACE(QCocoaWindowDelegate) sharedDelegate] qt_qwidgetForWindow:self]; + QCocoaView *view = static_cast(qt_mac_nativeview_for(widget)); + Qt::MouseButton mouseButton = cocoaButton2QtButton([event buttonNumber]); + + // sometimes need to redirect mouse events to the popup. + QWidget *popup = qAppInstance()->activePopupWidget(); + if (popup && popup != widget) { + switch([event type]) + { + case NSLeftMouseDown: + qt_mac_handleMouseEvent(view, event, QEvent::MouseButtonPress, mouseButton); + // Don't call super here. This prevents us from getting the mouseUp event, + // which we need to send even if the mouseDown event was not accepted. + // (this is standard Qt behavior.) + break; + case NSRightMouseDown: + case NSOtherMouseDown: + if (!qt_mac_handleMouseEvent(view, event, QEvent::MouseButtonPress, mouseButton)) + [super sendEvent:event]; + break; + case NSLeftMouseUp: + case NSRightMouseUp: + case NSOtherMouseUp: + if (!qt_mac_handleMouseEvent(view, event, QEvent::MouseButtonRelease, mouseButton)) + [super sendEvent:event]; + break; + case NSMouseMoved: + qt_mac_handleMouseEvent(view, event, QEvent::MouseMove, Qt::NoButton); + break; + case NSLeftMouseDragged: + case NSRightMouseDragged: + case NSOtherMouseDragged: + [QT_MANGLE_NAMESPACE(QCocoaView) currentMouseEvent]->view = view; + [QT_MANGLE_NAMESPACE(QCocoaView) currentMouseEvent]->theEvent = event; + if (!qt_mac_handleMouseEvent(view, event, QEvent::MouseMove, mouseButton)) + [super sendEvent:event]; + break; + default: + [super sendEvent:event]; + break; + } + } else { + [super sendEvent:event]; + } qt_mac_dispatchNCMouseMessage(self, event, [self QT_MANGLE_NAMESPACE(qt_qwidget)], leftButtonIsRightButton); + + [self release]; } + +- (BOOL)makeFirstResponder:(NSResponder *)responder +{ + if (responder == nil) + return NO; + return [super makeFirstResponder:responder]; +} + +/*********************************************************************** + END Copy and Paste between QCocoaWindow and QCocoaPanel +***********************************************************************/ + (Class)frameViewClassForStyleMask:(NSUInteger)styleMask { if (styleMask & QtMacCustomizeWindow) diff --git a/src/gui/kernel/qcocoawindow_mac.mm b/src/gui/kernel/qcocoawindow_mac.mm index 6b30444..ba121cd 100644 --- a/src/gui/kernel/qcocoawindow_mac.mm +++ b/src/gui/kernel/qcocoawindow_mac.mm @@ -86,6 +86,12 @@ extern Qt::MouseButton cocoaButton2QtButton(NSInteger buttonNum); // qcocoaview. return YES; } +/*********************************************************************** + BEGIN Copy and Paste between QCocoaWindow and QCocoaPanel + This is a bit unfortunate, but thanks to the dynamic dispatch we + have to duplicate this code or resort to really silly forwarding methods +**************************************************************************/ + /* The methods keyDown, keyUp, and flagsChanged... These really shouldn't ever get hit. We automatically say we can be first responder if we are a window. @@ -173,6 +179,18 @@ extern Qt::MouseButton cocoaButton2QtButton(NSInteger buttonNum); // qcocoaview. [self release]; } + +- (BOOL)makeFirstResponder:(NSResponder *)responder +{ + if (responder == nil) + return NO; + return [super makeFirstResponder:responder]; +} + +/*********************************************************************** + END Copy and Paste between QCocoaWindow and QCocoaPanel +***********************************************************************/ + + (Class)frameViewClassForStyleMask:(NSUInteger)styleMask { if (styleMask & QtMacCustomizeWindow) diff --git a/src/gui/kernel/qwidget_mac.mm b/src/gui/kernel/qwidget_mac.mm index f599b7c..7a586e1 100644 --- a/src/gui/kernel/qwidget_mac.mm +++ b/src/gui/kernel/qwidget_mac.mm @@ -2514,6 +2514,8 @@ void QWidgetPrivate::create_sys(WId window, bool initializeWindow, bool destroyO } updateIsOpaque(); + if (q->hasFocus()) + setFocus_sys(); if (!topLevel && initializeWindow) setWSGeometry(); -- cgit v0.12