diff options
-rw-r--r-- | src/plugins/platforms/cocoa/qcocoawindow.h | 13 | ||||
-rw-r--r-- | src/plugins/platforms/cocoa/qcocoawindow.mm | 340 | ||||
-rw-r--r-- | src/plugins/platforms/cocoa/qnsview.mm | 26 | ||||
-rw-r--r-- | tests/auto/other/qfocusevent/tst_qfocusevent.cpp | 3 | ||||
-rw-r--r-- | tests/manual/windowchildgeometry/controllerwidget.cpp | 536 | ||||
-rw-r--r-- | tests/manual/windowchildgeometry/controllerwidget.h | 158 | ||||
-rw-r--r-- | tests/manual/windowchildgeometry/main.cpp | 51 | ||||
-rw-r--r-- | tests/manual/windowchildgeometry/windowchildgeometry.pro | 10 |
8 files changed, 1086 insertions, 51 deletions
diff --git a/src/plugins/platforms/cocoa/qcocoawindow.h b/src/plugins/platforms/cocoa/qcocoawindow.h index 18d512ce30..9fbd10dea5 100644 --- a/src/plugins/platforms/cocoa/qcocoawindow.h +++ b/src/plugins/platforms/cocoa/qcocoawindow.h @@ -98,6 +98,10 @@ public: void setGeometry(const QRect &rect); void setCocoaGeometry(const QRect &rect); + void clipChildWindows(); + void clipWindow(const NSRect &clipRect); + void show(bool becauseOfAncestor = false); + void hide(bool becauseOfAncestor = false); void setVisible(bool visible); void setWindowFlags(Qt::WindowFlags flags); void setWindowState(Qt::WindowState state); @@ -166,8 +170,6 @@ public: void updateExposedGeometry(); QWindow *childWindowAt(QPoint windowPoint); protected: - // NSWindow handling. The QCocoaWindow/QNSView can either be displayed - // in an existing NSWindow or in one created by Qt. void recreateWindow(const QPlatformWindow *parentWindow); QNSWindow *createNSWindow(); void setNSWindow(QNSWindow *window); @@ -176,6 +178,8 @@ protected: QRect windowGeometry() const; QCocoaWindow *parentCocoaWindow() const; void syncWindowState(Qt::WindowState newState); + void reinsertChildWindow(QCocoaWindow *child); + void removeChildWindow(QCocoaWindow *child); // private: public: // for QNSView @@ -185,12 +189,15 @@ public: // for QNSView NSView *m_contentView; QNSView *m_qtView; QNSWindow *m_nsWindow; + QCocoaWindow *m_forwardWindow; // TODO merge to one variable if possible bool m_contentViewIsEmbedded; // true if the m_contentView is actually embedded in a "foreign" NSView hiearchy bool m_contentViewIsToBeEmbedded; // true if the m_contentView is intended to be embedded in a "foreign" NSView hiearchy QCocoaWindow *m_parentCocoaWindow; + bool m_isNSWindowChild; // this window is a non-top level QWindow with a NSWindow. + QList<QCocoaWindow *> m_childWindows; QNSWindowDelegate *m_nsWindowDelegate; Qt::WindowFlags m_windowFlags; @@ -213,6 +220,8 @@ public: // for QNSView int m_registerTouchCount; bool m_resizableTransientParent; bool m_overrideBecomeKey; + bool m_hiddenByClipping; + bool m_hiddenByAncestor; static const int NoAlertRequest; NSInteger m_alertRequest; diff --git a/src/plugins/platforms/cocoa/qcocoawindow.mm b/src/plugins/platforms/cocoa/qcocoawindow.mm index c8d6541d3f..17f5f4888d 100644 --- a/src/plugins/platforms/cocoa/qcocoawindow.mm +++ b/src/plugins/platforms/cocoa/qcocoawindow.mm @@ -117,7 +117,9 @@ static bool isMouseEvent(NSEvent *ev) - (BOOL)canBecomeKeyWindow { - if (!m_cocoaPlatformWindow) + // Prevent child NSWindows from becoming the key window in + // order keep the active apperance of the top-level window. + if (!m_cocoaPlatformWindow || m_cocoaPlatformWindow->m_isNSWindowChild) return NO; // Only tool or dialog windows should become key: @@ -141,7 +143,8 @@ static bool isMouseEvent(NSEvent *ev) // Windows with a transient parent (such as combobox popup windows) // cannot become the main window: - if (!m_cocoaPlatformWindow || m_cocoaPlatformWindow->window()->transientParent()) + if (!m_cocoaPlatformWindow || m_cocoaPlatformWindow->m_isNSWindowChild + || m_cocoaPlatformWindow->window()->transientParent()) canBecomeMain = NO; if (m_cocoaPlatformWindow && m_cocoaPlatformWindow->windowShouldBehaveAsPanel()) @@ -152,6 +155,24 @@ static bool isMouseEvent(NSEvent *ev) - (void) sendEvent: (NSEvent*) theEvent { + if (m_cocoaPlatformWindow && m_cocoaPlatformWindow->m_forwardWindow) { + if (theEvent.type == NSLeftMouseUp || theEvent.type == NSLeftMouseDragged) { + QNSView *forwardView = m_cocoaPlatformWindow->m_qtView; + if (theEvent.type == NSLeftMouseUp) { + [forwardView mouseUp:theEvent]; + m_cocoaPlatformWindow->m_forwardWindow = 0; + } else { + [forwardView mouseDragged:theEvent]; + } + + return; + } + + if (theEvent.type == NSLeftMouseDown) { + m_cocoaPlatformWindow->m_forwardWindow = 0; + } + } + [super sendEvent: theEvent]; if (!m_cocoaPlatformWindow) @@ -184,8 +205,11 @@ QCocoaWindow::QCocoaWindow(QWindow *tlw) , m_contentView(nil) , m_qtView(nil) , m_nsWindow(0) + , m_forwardWindow(0) , m_contentViewIsEmbedded(false) , m_contentViewIsToBeEmbedded(false) + , m_parentCocoaWindow(0) + , m_isNSWindowChild(false) , m_nsWindowDelegate(0) , m_synchedWindowState(Qt::WindowActive) , m_windowModality(Qt::NonModal) @@ -201,6 +225,8 @@ QCocoaWindow::QCocoaWindow(QWindow *tlw) , m_registerTouchCount(0) , m_resizableTransientParent(false) , m_overrideBecomeKey(false) + , m_hiddenByClipping(false) + , m_hiddenByAncestor(false) , m_alertRequest(NoAlertRequest) , monitor(nil) , m_drawContentBorderGradient(false) @@ -246,8 +272,21 @@ QCocoaWindow::~QCocoaWindow() QCocoaAutoReleasePool pool; clearNSWindow(m_nsWindow); - if (parent()) + if (m_isNSWindowChild) { + if (m_parentCocoaWindow) + m_parentCocoaWindow->removeChildWindow(this); + } else if (parent()) { [m_contentView removeFromSuperview]; + } else if (m_qtView) { + [[NSNotificationCenter defaultCenter] removeObserver:m_qtView + name:nil object:m_nsWindow]; + } + + foreach (QCocoaWindow *child, m_childWindows) { + [m_nsWindow removeChildWindow:child->m_nsWindow]; + child->m_parentCocoaWindow = 0; + } + [m_contentView release]; [m_nsWindow release]; [m_nsWindowDelegate release]; @@ -285,7 +324,16 @@ void QCocoaWindow::setCocoaGeometry(const QRect &rect) return; } - if (m_nsWindow) { + if (m_isNSWindowChild) { + QPlatformWindow::setGeometry(rect); + NSWindow *parentNSWindow = m_parentCocoaWindow->m_nsWindow; + NSRect parentWindowFrame = [parentNSWindow contentRectForFrameRect:parentNSWindow.frame]; + clipWindow(parentWindowFrame); + + // call this here: updateGeometry in qnsview.mm is a no-op for this case + QWindowSystemInterface::handleGeometryChange(window(), rect); + QWindowSystemInterface::handleExposeEvent(window(), rect); + } else if (m_nsWindow) { NSRect bounds = qt_mac_flipRect(rect, window()); [m_nsWindow setFrame:[m_nsWindow frameRectForContentRect:bounds] display:YES animate:NO]; } else { @@ -295,8 +343,99 @@ void QCocoaWindow::setCocoaGeometry(const QRect &rect) // will call QPlatformWindow::setGeometry(rect) during resize confirmation (see qnsview.mm) } +void QCocoaWindow::clipChildWindows() +{ + foreach (QCocoaWindow *childWindow, m_childWindows) { + childWindow->clipWindow(m_nsWindow.frame); + } +} + +void QCocoaWindow::clipWindow(const NSRect &clipRect) +{ + if (!m_isNSWindowChild) + return; + + NSRect clippedWindowRect = NSZeroRect; + if (!NSIsEmptyRect(clipRect)) { + NSRect windowFrame = qt_mac_flipRect(QRect(window()->mapToGlobal(QPoint(0, 0)), geometry().size()), window()); + clippedWindowRect = NSIntersectionRect(windowFrame, clipRect); + // Clipping top/left offsets the content. Move it back. + NSPoint contentViewOffset = NSMakePoint(qMax(CGFloat(0), NSMinX(clippedWindowRect) - NSMinX(windowFrame)), + qMax(CGFloat(0), NSMaxY(windowFrame) - NSMaxY(clippedWindowRect))); + [m_contentView setBoundsOrigin:contentViewOffset]; + } + + if (NSIsEmptyRect(clippedWindowRect)) { + if (!m_hiddenByClipping) { + // We dont call hide() here as we will recurse further down + [m_nsWindow orderOut:nil]; + m_hiddenByClipping = true; + } + } else { + [m_nsWindow setFrame:clippedWindowRect display:YES animate:NO]; + if (m_hiddenByClipping) { + m_hiddenByClipping = false; + if (!m_hiddenByAncestor) { + [m_nsWindow orderFront:nil]; + m_parentCocoaWindow->reinsertChildWindow(this); + } + } + } + + // recurse + foreach (QCocoaWindow *childWindow, m_childWindows) { + childWindow->clipWindow(clippedWindowRect); + } +} + +void QCocoaWindow::hide(bool becauseOfAncestor) +{ + bool visible = [m_nsWindow isVisible]; + + if (!m_hiddenByAncestor && !visible) // Already explicitly hidden + return; + if (m_hiddenByAncestor && becauseOfAncestor) // Trying to hide some child again + return; + + m_hiddenByAncestor = becauseOfAncestor; + + if (!visible) // Could have been clipped before + return; + + foreach (QCocoaWindow *childWindow, m_childWindows) + childWindow->hide(true); + + [m_nsWindow orderOut:nil]; +} + +void QCocoaWindow::show(bool becauseOfAncestor) +{ + if ([m_nsWindow isVisible]) + return; + + if (m_parentCocoaWindow && ![m_parentCocoaWindow->m_nsWindow isVisible]) { + m_hiddenByAncestor = true; // Parent still hidden, don't show now + } else if ((becauseOfAncestor == m_hiddenByAncestor) // Was NEITHER explicitly hidden + && !m_hiddenByClipping) { // ... NOR clipped + if (m_isNSWindowChild) { + m_hiddenByAncestor = false; + setCocoaGeometry(window()->geometry()); + } + if (!m_hiddenByClipping) { // setCocoaGeometry() can change the clipping status + [m_nsWindow orderFront:nil]; + if (m_isNSWindowChild) + m_parentCocoaWindow->reinsertChildWindow(this); + foreach (QCocoaWindow *childWindow, m_childWindows) + childWindow->show(true); + } + } +} + void QCocoaWindow::setVisible(bool visible) { + if (m_isNSWindowChild && m_hiddenByClipping) + return; + QCocoaAutoReleasePool pool; QCocoaWindow *parentCocoaWindow = 0; if (window()->transientParent()) @@ -361,8 +500,10 @@ void QCocoaWindow::setVisible(bool visible) m_hasModalSession = true; } else if ([m_nsWindow canBecomeKeyWindow]) { [m_nsWindow makeKeyAndOrderFront:nil]; + foreach (QCocoaWindow *childWindow, m_childWindows) + childWindow->show(true); } else { - [m_nsWindow orderFront: nil]; + show(); } // We want the events to properly reach the popup, dialog, and tool @@ -386,28 +527,27 @@ void QCocoaWindow::setVisible(bool visible) // qDebug() << "close" << this; if (m_glContext) m_glContext->windowWasHidden(); + QCocoaEventDispatcher *cocoaEventDispatcher = qobject_cast<QCocoaEventDispatcher *>(QGuiApplication::instance()->eventDispatcher()); + Q_ASSERT(cocoaEventDispatcher != 0); + QCocoaEventDispatcherPrivate *cocoaEventDispatcherPrivate = static_cast<QCocoaEventDispatcherPrivate *>(QObjectPrivate::get(cocoaEventDispatcher)); if (m_nsWindow) { if (m_hasModalSession) { - QCocoaEventDispatcher *cocoaEventDispatcher = qobject_cast<QCocoaEventDispatcher *>(QGuiApplication::instance()->eventDispatcher()); - Q_ASSERT(cocoaEventDispatcher != 0); - QCocoaEventDispatcherPrivate *cocoaEventDispatcherPrivate = static_cast<QCocoaEventDispatcherPrivate *>(QObjectPrivate::get(cocoaEventDispatcher)); cocoaEventDispatcherPrivate->endModalSession(window()); m_hasModalSession = false; - - [m_nsWindow orderOut:m_nsWindow]; - if (m_nsWindow == [NSApp keyWindow] && !cocoaEventDispatcherPrivate->currentModalSession()) { - // Probably because we call runModalSession: outside [NSApp run] in QCocoaEventDispatcher - // (e.g., when show()-ing a modal QDialog instead of exec()-ing it), it can happen that - // the current NSWindow is still key after being ordered out. Then, after checking we - // don't have any other modal session left, it's safe to make the main window key again. - NSWindow *mainWindow = [NSApp mainWindow]; - if (mainWindow && [mainWindow canBecomeKeyWindow]) - [mainWindow makeKeyWindow]; - } } else { if ([m_nsWindow isSheet]) [NSApp endSheet:m_nsWindow]; - [m_nsWindow orderOut:m_nsWindow]; + } + + hide(); + if (m_nsWindow == [NSApp keyWindow] && !cocoaEventDispatcherPrivate->currentModalSession()) { + // Probably because we call runModalSession: outside [NSApp run] in QCocoaEventDispatcher + // (e.g., when show()-ing a modal QDialog instead of exec()-ing it), it can happen that + // the current NSWindow is still key after being ordered out. Then, after checking we + // don't have any other modal session left, it's safe to make the main window key again. + NSWindow *mainWindow = [NSApp mainWindow]; + if (mainWindow && [mainWindow canBecomeKeyWindow]) + [mainWindow makeKeyWindow]; } } else { [m_contentView setHidden:YES]; @@ -514,7 +654,7 @@ void QCocoaWindow::setWindowShadow(Qt::WindowFlags flags) void QCocoaWindow::setWindowFlags(Qt::WindowFlags flags) { - if (m_nsWindow) { + if (m_nsWindow && !m_isNSWindowChild) { NSUInteger styleMask = windowStyleMask(flags); NSInteger level = this->windowLevel(flags); [m_nsWindow setStyleMask:styleMask]; @@ -618,16 +758,55 @@ void QCocoaWindow::raise() // ### handle spaces (see Qt 4 raise_sys in qwidget_mac.mm) if (!m_nsWindow) return; - if ([m_nsWindow isVisible]) - [m_nsWindow orderFront: m_nsWindow]; + if (m_isNSWindowChild) { + QList<QCocoaWindow *> &siblings = m_parentCocoaWindow->m_childWindows; + siblings.removeOne(this); + siblings.append(this); + if (m_hiddenByClipping) + return; + } + if ([m_nsWindow isVisible]) { + if (m_isNSWindowChild) { + // -[NSWindow orderFront:] doesn't work with attached windows. + // The only solution is to remove and add the child window. + // This will place it on top of all the other NSWindows. + NSWindow *parentNSWindow = m_parentCocoaWindow->m_nsWindow; + [parentNSWindow removeChildWindow:m_nsWindow]; + [parentNSWindow addChildWindow:m_nsWindow ordered:NSWindowAbove]; + } else { + [m_nsWindow orderFront: m_nsWindow]; + } + } } void QCocoaWindow::lower() { if (!m_nsWindow) return; - if ([m_nsWindow isVisible]) - [m_nsWindow orderBack: m_nsWindow]; + if (m_isNSWindowChild) { + QList<QCocoaWindow *> &siblings = m_parentCocoaWindow->m_childWindows; + siblings.removeOne(this); + siblings.prepend(this); + if (m_hiddenByClipping) + return; + } + if ([m_nsWindow isVisible]) { + if (m_isNSWindowChild) { + // -[NSWindow orderBack:] doesn't work with attached windows. + // The only solution is to remove and add all the child windows except this one. + // This will keep the current window at the bottom while adding the others on top of it, + // hopefully in the same order (this is not documented anywhere in the Cocoa documentation). + NSWindow *parentNSWindow = m_parentCocoaWindow->m_nsWindow; + NSArray *children = [parentNSWindow.childWindows copy]; + for (NSWindow *child in children) + if (m_nsWindow != child) { + [parentNSWindow removeChildWindow:child]; + [parentNSWindow addChildWindow:child ordered:NSWindowAbove]; + } + } else { + [m_nsWindow orderBack: m_nsWindow]; + } + } } bool QCocoaWindow::isExposed() const @@ -777,6 +956,9 @@ void QCocoaWindow::windowWillMove() void QCocoaWindow::windowDidMove() { + if (m_isNSWindowChild) + return; + [m_qtView updateGeometry]; } @@ -785,6 +967,10 @@ void QCocoaWindow::windowDidResize() if (!m_nsWindow) return; + if (m_isNSWindowChild) + return; + + clipChildWindows(); [m_qtView updateGeometry]; } @@ -832,8 +1018,18 @@ QCocoaGLContext *QCocoaWindow::currentContext() const void QCocoaWindow::recreateWindow(const QPlatformWindow *parentWindow) { + bool wasNSWindowChild = m_isNSWindowChild; + bool needsNSWindow = m_isNSWindowChild || !parentWindow; + + QCocoaWindow *oldParentCocoaWindow = m_parentCocoaWindow; + m_parentCocoaWindow = const_cast<QCocoaWindow *>(static_cast<const QCocoaWindow *>(parentWindow)); + + // No child QNSWindow should notify its QNSView + if (m_nsWindow && m_qtView && m_parentCocoaWindow && !oldParentCocoaWindow) + [[NSNotificationCenter defaultCenter] removeObserver:m_qtView + name:nil object:m_nsWindow]; // Remove current window (if any) - if (m_nsWindow) { + if (m_nsWindow && !needsNSWindow) { clearNSWindow(m_nsWindow); [m_nsWindow close]; [m_nsWindow release]; @@ -842,22 +1038,64 @@ void QCocoaWindow::recreateWindow(const QPlatformWindow *parentWindow) m_nsWindowDelegate = 0; } + if (needsNSWindow) { + bool noPreviousWindow = m_nsWindow == 0; + if (noPreviousWindow) + m_nsWindow = createNSWindow(); + + // Only non-child QNSWindows should notify their QNSViews + // (but don't register more than once). + if (m_qtView && (noPreviousWindow || (wasNSWindowChild && !m_isNSWindowChild))) + [[NSNotificationCenter defaultCenter] addObserver:m_qtView + selector:@selector(windowNotification:) + name:nil // Get all notifications + object:m_nsWindow]; + + if (oldParentCocoaWindow) { + if (!m_isNSWindowChild || oldParentCocoaWindow != m_parentCocoaWindow) + oldParentCocoaWindow->removeChildWindow(this); + m_forwardWindow = oldParentCocoaWindow; + } + + setNSWindow(m_nsWindow); + } + + if (m_contentViewIsToBeEmbedded) { // An embedded window doesn't have its own NSWindow. } else if (!parentWindow) { - // Create a new NSWindow if this is a top-level window. - m_nsWindow = createNSWindow(); - setNSWindow(m_nsWindow); - // QPlatformWindow subclasses must sync up with QWindow on creation: propagateSizeHints(); setWindowFlags(window()->flags()); setWindowTitle(window()->title()); setWindowState(window()->windowState()); + } else if (m_isNSWindowChild) { + m_nsWindow.styleMask = NSBorderlessWindowMask; + m_nsWindow.hasShadow = NO; + m_nsWindow.level = NSNormalWindowLevel; + NSWindowCollectionBehavior collectionBehavior = + NSWindowCollectionBehaviorManaged | NSWindowCollectionBehaviorIgnoresCycle; +#if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_7 + if (QSysInfo::QSysInfo::MacintoshVersion >= QSysInfo::MV_10_7) { + collectionBehavior |= NSWindowCollectionBehaviorFullScreenAuxiliary; + m_nsWindow.animationBehavior = NSWindowAnimationBehaviorNone; + } +#endif + m_nsWindow.collectionBehavior = collectionBehavior; + setCocoaGeometry(window()->geometry()); + + QList<QCocoaWindow *> &siblings = m_parentCocoaWindow->m_childWindows; + if (siblings.contains(this)) { + if (!m_hiddenByClipping) + m_parentCocoaWindow->reinsertChildWindow(this); + } else { + if (!m_hiddenByClipping) + [m_parentCocoaWindow->m_nsWindow addChildWindow:m_nsWindow ordered:NSWindowAbove]; + siblings.append(this); + } } else { // Child windows have no NSWindow, link the NSViews instead. - const QCocoaWindow *parentCococaWindow = static_cast<const QCocoaWindow *>(parentWindow); - [parentCococaWindow->m_contentView addSubview : m_contentView]; + [m_parentCocoaWindow->m_contentView addSubview : m_contentView]; QRect rect = window()->geometry(); NSRect frame = NSMakeRect(rect.x(), rect.y(), rect.width(), rect.height()); [m_contentView setFrame:frame]; @@ -869,6 +1107,19 @@ void QCocoaWindow::recreateWindow(const QPlatformWindow *parentWindow) setOpacity(opacity); } +void QCocoaWindow::reinsertChildWindow(QCocoaWindow *child) +{ + int childIndex = m_childWindows.indexOf(child); + Q_ASSERT(childIndex != -1); + + for (int i = childIndex; i < m_childWindows.size(); i++) { + NSWindow *nsChild = m_childWindows[i]->m_nsWindow; + if (i != childIndex) + [m_nsWindow removeChildWindow:nsChild]; + [m_nsWindow addChildWindow:nsChild ordered:NSWindowAbove]; + } +} + void QCocoaWindow::requestActivateWindow() { NSWindow *window = [m_contentView window]; @@ -886,7 +1137,11 @@ QNSWindow * QCocoaWindow::createNSWindow() Qt::WindowFlags flags = window()->flags(); NSUInteger styleMask; - styleMask = windowStyleMask(flags); + if (m_isNSWindowChild) { + styleMask = NSBorderlessWindowMask; + } else { + styleMask = windowStyleMask(flags); + } QNSWindow *createdWindow = [[QNSWindow alloc] initWithContentRect:frame styleMask:styleMask qPlatformWindow:this]; @@ -924,12 +1179,6 @@ void QCocoaWindow::setNSWindow(QNSWindow *window) // QCocoaWindow is deleted by Qt. [window setReleasedWhenClosed : NO]; - if (m_qtView) - [[NSNotificationCenter defaultCenter] addObserver:m_qtView - selector:@selector(windowNotification:) - name:nil // Get all notifications - object:m_nsWindow]; - if (window.contentView != m_contentView) { [m_contentView setPostsFrameChangedNotifications: NO]; [window setContentView:m_contentView]; @@ -942,16 +1191,21 @@ void QCocoaWindow::clearNSWindow(QNSWindow *window) [window setContentView:nil]; [window setDelegate:nil]; [window clearPlatformWindow]; + if (m_isNSWindowChild) { + m_parentCocoaWindow->removeChildWindow(this); + } +} - if (m_qtView) - [[NSNotificationCenter defaultCenter] removeObserver:m_qtView - name:nil object:window]; +void QCocoaWindow::removeChildWindow(QCocoaWindow *child) +{ + m_childWindows.removeOne(child); + [m_nsWindow removeChildWindow:child->m_nsWindow]; } // Returns the current global screen geometry for the nswindow associated with this window. QRect QCocoaWindow::windowGeometry() const { - if (!m_nsWindow) + if (!m_nsWindow || m_isNSWindowChild) return geometry(); NSRect rect = [m_nsWindow frame]; diff --git a/src/plugins/platforms/cocoa/qnsview.mm b/src/plugins/platforms/cocoa/qnsview.mm index 849a75f03c..7cd74c6725 100644 --- a/src/plugins/platforms/cocoa/qnsview.mm +++ b/src/plugins/platforms/cocoa/qnsview.mm @@ -227,7 +227,21 @@ static QTouchDevice *touchDevice = 0; - (void)updateGeometry { QRect geometry; - if (m_platformWindow->m_nsWindow) { + + if (m_platformWindow->m_isNSWindowChild) { + return; +#if 0 + //geometry = qt_mac_toQRect([self frame]); + qDebug() << "nsview updateGeometry" << m_platformWindow->window(); + QRect screenRect = qt_mac_toQRect([m_platformWindow->m_nsWindow convertRectToScreen:[self frame]]); + qDebug() << "screenRect" << screenRect; + + screenRect.moveTop(qt_mac_flipYCoordinate(screenRect.y() + screenRect.height())); + geometry = QRect(m_platformWindow->window()->parent()->mapFromGlobal(screenRect.topLeft()), screenRect.size()); + qDebug() << "geometry" << geometry; +#endif + //geometry = QRect(screenRect.origin.x, qt_mac_flipYCoordinate(screenRect.origin.y + screenRect.size.height), screenRect.size.width, screenRect.size.height); + } else if (m_platformWindow->m_nsWindow) { // top level window, get window rect and flip y. NSRect rect = [self frame]; NSRect windowRect = [[self window] frame]; @@ -548,14 +562,20 @@ static QTouchDevice *touchDevice = 0; QPointF qtWindowPoint; QPointF qtScreenPoint; - [self convertFromScreen:[NSEvent mouseLocation] toWindowPoint:&qtWindowPoint andScreenPoint:&qtScreenPoint]; + QNSView *targetView = self; + if (m_platformWindow && m_platformWindow->m_forwardWindow + && (theEvent.type == NSLeftMouseDragged || theEvent.type == NSLeftMouseUp)) { + targetView = m_platformWindow->m_forwardWindow->m_qtView; + } + + [targetView convertFromScreen:[NSEvent mouseLocation] toWindowPoint:&qtWindowPoint andScreenPoint:&qtScreenPoint]; ulong timestamp = [theEvent timestamp] * 1000; QCocoaDrag* nativeDrag = QCocoaIntegration::instance()->drag(); nativeDrag->setLastMouseEvent(theEvent, self); Qt::KeyboardModifiers keyboardModifiers = [QNSView convertKeyModifiers:[theEvent modifierFlags]]; - QWindowSystemInterface::handleMouseEvent(m_window, timestamp, qtWindowPoint, qtScreenPoint, m_buttons, keyboardModifiers); + QWindowSystemInterface::handleMouseEvent(targetView->m_window, timestamp, qtWindowPoint, qtScreenPoint, m_buttons, keyboardModifiers); } - (void)handleFrameStrutMouseEvent:(NSEvent *)theEvent diff --git a/tests/auto/other/qfocusevent/tst_qfocusevent.cpp b/tests/auto/other/qfocusevent/tst_qfocusevent.cpp index df26407fe6..33deed9737 100644 --- a/tests/auto/other/qfocusevent/tst_qfocusevent.cpp +++ b/tests/auto/other/qfocusevent/tst_qfocusevent.cpp @@ -372,9 +372,6 @@ void tst_QFocusEvent::checkReason_ActiveWindow() #if defined(Q_OS_IRIX) QEXPECT_FAIL("", "IRIX requires explicit activateWindow(), so this test does not make any sense.", Abort); #endif -#ifdef Q_OS_MAC - QEXPECT_FAIL("", "QTBUG-22815", Abort); -#endif QTRY_VERIFY(childFocusWidgetOne->focusInEventRecieved); QVERIFY(childFocusWidgetOne->focusInEventGotFocus); diff --git a/tests/manual/windowchildgeometry/controllerwidget.cpp b/tests/manual/windowchildgeometry/controllerwidget.cpp new file mode 100644 index 0000000000..f1cdfbf855 --- /dev/null +++ b/tests/manual/windowchildgeometry/controllerwidget.cpp @@ -0,0 +1,536 @@ +/**************************************************************************** +** +** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/legal +** +** This file is part of the test suite of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Digia. For licensing terms and +** conditions see http://qt.digia.com/licensing. For further information +** use the contact form at http://qt.digia.com/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Digia gives you certain additional +** rights. These rights are described in the Digia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "controllerwidget.h" +#include <controls.h> + +#if QT_VERSION >= 0x050000 +# include <QtWidgets> +# include <QWindow> +# include <QBackingStore> +# include <QPaintDevice> +# include <QPainter> +#else +# include <QtGui> +#endif + +#include <QResizeEvent> + +CoordinateControl::CoordinateControl(const QString &sep) : m_x(new QSpinBox), m_y(new QSpinBox) +{ + m_x->setMinimum(-2000); + m_x->setMaximum(2000); + connect(m_x, SIGNAL(valueChanged(int)), this, SLOT(spinBoxChanged())); + m_y->setMinimum(-2000); + m_y->setMaximum(2000); + connect(m_y, SIGNAL(valueChanged(int)), this, SLOT(spinBoxChanged())); + QHBoxLayout *l = new QHBoxLayout(this); + l->setSpacing(2); + l->addWidget(m_x); + l->addWidget(new QLabel(sep)); + l->addWidget(m_y); +} + +void CoordinateControl::setCoordinates(int x, int y) +{ + m_x->blockSignals(true); + m_y->blockSignals(true); + m_x->setValue(x); + m_y->setValue(y); + m_x->blockSignals(false); + m_y->blockSignals(false); +} + +QPair<int, int> CoordinateControl::coordinates() const +{ + return QPair<int, int>(m_x->value(), m_y->value()); +} + +void CoordinateControl::spinBoxChanged() +{ + const int x = m_x->value(); + const int y = m_y->value(); + emit pointValueChanged(QPoint(x, y)); + emit sizeValueChanged(QSize(x, y)); +} + +RectControl::RectControl() + : m_point(new CoordinateControl(QLatin1String("+"))) + , m_size(new CoordinateControl(QLatin1String("x"))) +{ + QHBoxLayout *l = new QHBoxLayout(this); + l->setSpacing(0); + l->setMargin(ControlLayoutMargin); + connect(m_point, SIGNAL(pointValueChanged(QPoint)), this, SLOT(handleChanged())); + connect(m_point, SIGNAL(pointValueChanged(QPoint)), this, SIGNAL(positionChanged(QPoint))); + l->addWidget(m_point); + l->addSpacerItem(new QSpacerItem(0, 0, QSizePolicy::MinimumExpanding, QSizePolicy::Ignored)); + connect(m_size, SIGNAL(sizeValueChanged(QSize)), this, SLOT(handleChanged())); + connect(m_size, SIGNAL(sizeValueChanged(QSize)), this, SIGNAL(sizeChanged(QSize))); + l->addWidget(m_size); +} + +void RectControl::setRectValue(const QRect &r) +{ + m_point->setPointValue(r.topLeft()); + m_size->setSizeValue(r.size()); +} + +QRect RectControl::rectValue() const +{ + return QRect(m_point->pointValue(), m_size->sizeValue()); +} + +void RectControl::handleChanged() +{ + emit changed(rectValue()); +} + +BaseWindowControl::BaseWindowControl(QObject *w) + : m_layout(new QGridLayout(this)) + , m_object(w) + , m_geometry(new RectControl) + , m_framePosition(new CoordinateControl(QLatin1String("x"))) + , m_moveEventLabel(new QLabel(tr("Move events"))) + , m_resizeEventLabel(new QLabel(tr("Resize events"))) + , m_mouseEventLabel(new QLabel(tr("Mouse events"))) + , m_moveCount(0) + , m_resizeCount(0) +{ + m_object->installEventFilter(this); + m_geometry->setTitle(tr("Geometry")); + int row = 0; + m_layout->addWidget(m_geometry, row, 0, 1, 2); + m_layout->setMargin(ControlLayoutMargin); + QGroupBox *frameGB = new QGroupBox(tr("Frame")); + QVBoxLayout *frameL = new QVBoxLayout(frameGB); + frameL->setSpacing(0); + frameL->setMargin(ControlLayoutMargin); + frameL->addWidget(m_framePosition); + m_layout->addWidget(frameGB, row, 2); + + QGroupBox *eventGroupBox = new QGroupBox(tr("Events")); + QVBoxLayout *l = new QVBoxLayout(eventGroupBox); + l->setSpacing(0); + l->setMargin(ControlLayoutMargin); + l->addWidget(m_moveEventLabel); + l->addWidget(m_resizeEventLabel); + l->addWidget(m_mouseEventLabel); + m_layout->addWidget(eventGroupBox, ++row, 2); + + connect(m_geometry, SIGNAL(positionChanged(QPoint)), this, SLOT(posChanged(QPoint))); + connect(m_geometry, SIGNAL(sizeChanged(QSize)), this, SLOT(sizeChanged(QSize))); + connect(m_framePosition, SIGNAL(pointValueChanged(QPoint)), this, SLOT(framePosChanged(QPoint))); +} + +bool BaseWindowControl::eventFilter(QObject *, QEvent *e) +{ + switch (e->type()) { + case QEvent::Resize: { + const QResizeEvent *re = static_cast<const QResizeEvent *>(e); + m_resizeEventLabel->setText(tr("Resize %1x%2 (#%3)") + .arg(re->size().width()).arg(re->size().height()) + .arg(++m_resizeCount)); + refresh(); + } + break; + case QEvent::Move: { + const QMoveEvent *me = static_cast<const QMoveEvent *>(e); + m_moveEventLabel->setText(tr("Move %1,%2 (#%3)") + .arg(me->pos().x()).arg(me->pos().y()) + .arg(++m_moveCount)); + refresh(); + } + break; + case QEvent::MouseMove: { + const QMouseEvent *me = static_cast<const QMouseEvent *>(e); + const QPoint pos = me->pos(); + QPoint globalPos = objectMapToGlobal(m_object, pos); + m_mouseEventLabel->setText(tr("Mouse: %1,%2 Global: %3,%4 "). + arg(pos.x()).arg(pos.y()).arg(globalPos.x()).arg(globalPos.y())); + } + break; + case QEvent::WindowStateChange: + refresh(); + default: + break; + } + return false; +} + +void BaseWindowControl::posChanged(const QPoint &p) +{ + QRect geom = objectGeometry(m_object); + geom.moveTopLeft(p); + setObjectGeometry(m_object, geom); +} + +void BaseWindowControl::sizeChanged(const QSize &s) +{ + QRect geom = objectGeometry(m_object); + geom.setSize(s); + setObjectGeometry(m_object, geom); +} + +void BaseWindowControl::framePosChanged(const QPoint &p) +{ + setObjectFramePosition(m_object, p); +} + +void BaseWindowControl::refresh() +{ + m_geometry->setRectValue(objectGeometry(m_object)); + m_framePosition->setPointValue(objectFramePosition(m_object)); +} + +// A control for a QWidget +class WidgetWindowControl : public BaseWindowControl +{ + Q_OBJECT +public: + explicit WidgetWindowControl(QWidget *w); + + virtual void refresh(); + +private slots: + void statesChanged(); + +private: + virtual QRect objectGeometry(const QObject *o) const + { return static_cast<const QWidget *>(o)->geometry(); } + virtual void setObjectGeometry(QObject *o, const QRect &r) const + { static_cast<QWidget *>(o)->setGeometry(r); } + virtual QPoint objectFramePosition(const QObject *o) const + { return static_cast<const QWidget *>(o)->pos(); } + virtual void setObjectFramePosition(QObject *o, const QPoint &p) const + { static_cast<QWidget *>(o)->move(p); } + virtual QPoint objectMapToGlobal(const QObject *o, const QPoint &p) const + { return static_cast<const QWidget *>(o)->mapToGlobal(p); } + virtual Qt::WindowFlags objectWindowFlags(const QObject *o) const + { return static_cast<const QWidget *>(o)->windowFlags(); } + virtual void setObjectWindowFlags(QObject *o, Qt::WindowFlags f); + + WindowStatesControl *m_statesControl; +}; + +WidgetWindowControl::WidgetWindowControl(QWidget *w ) + : BaseWindowControl(w) + , m_statesControl(new WindowStatesControl(WindowStatesControl::WantVisibleCheckBox | WindowStatesControl::WantActiveCheckBox)) +{ + setTitle(w->windowTitle()); + m_layout->addWidget(m_statesControl, 2, 0); + connect(m_statesControl, SIGNAL(changed()), this, SLOT(statesChanged())); +} + +void WidgetWindowControl::setObjectWindowFlags(QObject *o, Qt::WindowFlags f) +{ + QWidget *w = static_cast<QWidget *>(o); + const bool visible = w->isVisible(); + w->setWindowFlags(f); // hides. + if (visible) + w->show(); +} + +void WidgetWindowControl::refresh() +{ + const QWidget *w = static_cast<const QWidget *>(m_object); + m_statesControl->setVisibleValue(w->isVisible()); + m_statesControl->setStates(w->windowState()); + BaseWindowControl::refresh(); +} + +void WidgetWindowControl::statesChanged() +{ + QWidget *w = static_cast<QWidget *>(m_object); + w->setVisible(m_statesControl->visibleValue()); + w->setWindowState(m_statesControl->states()); +} + +#if QT_VERSION >= 0x050000 + +// Test window drawing diagonal lines +class Window : public QWindow +{ +public: + explicit Window(QWindow *parent = 0) + : QWindow(parent) + , m_backingStore(new QBackingStore(this)) + , m_color(Qt::GlobalColor(qrand() % 18)) + { + setObjectName(QStringLiteral("window")); + setTitle(tr("TestWindow")); + setFlags(flags() | Qt::MacUseNSWindow); + } + +protected: + void mouseMoveEvent(QMouseEvent * ev); + void mousePressEvent(QMouseEvent * ev); + void mouseReleaseEvent(QMouseEvent * e); + void exposeEvent(QExposeEvent *) + { render(); } + +private: + QBackingStore *m_backingStore; + Qt::GlobalColor m_color; + QPoint m_mouseDownPosition; + void render(); +}; + +void Window::mouseMoveEvent(QMouseEvent * ev) +{ + if (m_mouseDownPosition.isNull()) + return; + + QPoint delta = ev->pos() - m_mouseDownPosition; + QPoint newPosition = position() + delta; + setPosition(newPosition); +// qDebug() << "diff" << delta << newPosition; +} + +void Window::mousePressEvent(QMouseEvent * ev) +{ + m_mouseDownPosition = ev->pos(); +} + +void Window::mouseReleaseEvent(QMouseEvent * e) +{ + m_mouseDownPosition = QPoint(); +} + +void Window::render() +{ + QRect rect(QPoint(), geometry().size()); + m_backingStore->resize(rect.size()); + m_backingStore->beginPaint(rect); + if (!rect.size().isEmpty()) { + QPaintDevice *device = m_backingStore->paintDevice(); + QPainter p(device); + p.fillRect(rect, m_color); + p.drawLine(0, 0, rect.width(), rect.height()); + p.drawLine(0, rect.height(), rect.width(), 0); + } + m_backingStore->endPaint(); + m_backingStore->flush(rect); +} + +// A control for a QWindow +class WindowControl : public BaseWindowControl +{ + Q_OBJECT +public: + explicit WindowControl(QWindow *w); + + virtual void refresh(); + +private slots: + void showWindow(); + void hideWindow(); + void raiseWindow(); + void lowerWindow(); + void toggleAttachWindow(); + void addChildWindow(); +private: + virtual QRect objectGeometry(const QObject *o) const + { return static_cast<const QWindow *>(o)->geometry(); } + virtual void setObjectGeometry(QObject *o, const QRect &r) const + { static_cast<QWindow *>(o)->setGeometry(r); } + virtual QPoint objectFramePosition(const QObject *o) const + { return static_cast<const QWindow *>(o)->framePosition(); } + virtual void setObjectFramePosition(QObject *o, const QPoint &p) const + { static_cast<QWindow *>(o)->setFramePosition(p); } + virtual QPoint objectMapToGlobal(const QObject *o, const QPoint &p) const + { return static_cast<const QWindow *>(o)->mapToGlobal(p); } + virtual void setObjectWindowFlags(QObject *o, Qt::WindowFlags f) + { static_cast<QWindow *>(o)->setFlags(f); } + + WindowStateControl *m_stateControl; + QWindow *m_window; + QWindow *m_detachedParent; // set when this window is detached. This is the window we should re-attach to. +}; + +WindowControl::WindowControl(QWindow *w ) + : BaseWindowControl(w) + , m_stateControl(new WindowStateControl(WindowStateControl::WantVisibleCheckBox | WindowStateControl::WantMinimizeRadioButton)) + , m_window(w) + , m_detachedParent(0) +{ + setTitle(w->title()); + + QPushButton *button = new QPushButton("Show Window"); + connect(button, SIGNAL(clicked()), SLOT(showWindow())); + m_layout->addWidget(button, 1, 0); + + button = new QPushButton("hide Window"); + connect(button, SIGNAL(clicked()), SLOT(hideWindow())); + m_layout->addWidget(button, 1, 1); + + button = new QPushButton("Rase Window"); + connect(button, SIGNAL(clicked()), SLOT(raiseWindow())); + m_layout->addWidget(button, 2, 0); + + button = new QPushButton("Lower Window"); + connect(button, SIGNAL(clicked()), SLOT(lowerWindow())); + m_layout->addWidget(button, 2, 1); + + button = new QPushButton("Toggle attach"); + connect(button, SIGNAL(clicked()), SLOT(toggleAttachWindow())); + m_layout->addWidget(button, 3, 0); + + button = new QPushButton("Add Child Window"); + connect(button, SIGNAL(clicked()), SLOT(addChildWindow())); + m_layout->addWidget(button, 3, 1); +} + +void WindowControl::refresh() +{ + const QWindow *w = static_cast<const QWindow *>(m_object); + BaseWindowControl::refresh(); +} + +void WindowControl::showWindow() +{ + m_window->show(); +} + +void WindowControl::hideWindow() +{ + m_window->hide(); +} + +void WindowControl::raiseWindow() +{ + m_window->raise(); +} + +void WindowControl::lowerWindow() +{ + m_window->lower(); +} + +void WindowControl::toggleAttachWindow() +{ + if (m_detachedParent) { + m_window->hide(); + m_window->setParent(m_detachedParent); + m_window->show(); + m_detachedParent = 0; + } else { + m_detachedParent = m_window->parent(); + m_window->hide(); + m_window->setParent(0); + m_window->show(); + } +} + +void WindowControl::addChildWindow() +{ + qDebug() << "WindowControl::addChildWindow"; + Window *childWindow = new Window(m_window); + + QRect childGeometry(50, 50, 40, 40); + childWindow->setGeometry(childGeometry); + WindowControl *control = new WindowControl(childWindow); + control->show(); +} + +#endif + +ControllerWidget::ControllerWidget(QWidget *parent) + : QMainWindow(parent) + , m_testWindow(new Window) +{ + QMenu *fileMenu = menuBar()->addMenu(tr("File")); + QAction *exitAction = fileMenu->addAction(tr("Exit")); + exitAction->setShortcut(QKeySequence(Qt::CTRL | Qt::Key_Q)); + connect(exitAction, SIGNAL(triggered()), qApp, SLOT(closeAllWindows())); + + QString title = QLatin1String("Child Window Geometry test, (Qt "); + title += QLatin1String(QT_VERSION_STR); + title += QLatin1String(", "); + title += qApp->platformName(); + title += QLatin1Char(')'); + setWindowTitle(title); + + int x = 100; + int y = 100; + const QStringList args = QApplication::arguments(); + const int offsetArgIndex = args.indexOf(QLatin1String("-offset")); + if (offsetArgIndex >=0 && offsetArgIndex < args.size() - 1) { + y += args.at(offsetArgIndex + 1).toInt(); + } else { + if (QT_VERSION < 0x050000) + y += 400; + } + + move(x, y); + + x += 800; + + x += 300; + m_testWindow->setFlags(Qt::Window | Qt::WindowSystemMenuHint | Qt::WindowCloseButtonHint + | Qt::WindowMinimizeButtonHint | Qt::WindowMaximizeButtonHint + | Qt::WindowTitleHint | Qt::WindowFullscreenButtonHint); + m_testWindow->setFramePosition(QPoint(x, y)); + m_testWindow->resize(200, 200); + m_testWindow->setTitle(tr("TestWindow")); + + QWidget *central = new QWidget ; + QVBoxLayout *l = new QVBoxLayout(central); + + const QString labelText = tr( + "<html><head/><body><p>This example lets you control the geometry" + " of QWindows and child QWindows"); + + l->addWidget(new QLabel(labelText)); + + WindowControl *windowControl = new WindowControl(m_testWindow.data()); + l->addWidget(windowControl); + + setCentralWidget(central); +} + +ControllerWidget::~ControllerWidget() +{ + + +} + +#include "controllerwidget.moc" diff --git a/tests/manual/windowchildgeometry/controllerwidget.h b/tests/manual/windowchildgeometry/controllerwidget.h new file mode 100644 index 0000000000..9774ca408c --- /dev/null +++ b/tests/manual/windowchildgeometry/controllerwidget.h @@ -0,0 +1,158 @@ +/**************************************************************************** +** +** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/legal +** +** This file is part of the test suite of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Digia. For licensing terms and +** conditions see http://qt.digia.com/licensing. For further information +** use the contact form at http://qt.digia.com/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Digia gives you certain additional +** rights. These rights are described in the Digia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef CONTROLLERWIDGET_H +#define CONTROLLERWIDGET_H + +#include <QMainWindow> +#include <QGroupBox> +#include <QScopedPointer> + +QT_BEGIN_NAMESPACE +class QSpinBox; +class QLabel; +class QGridLayout; +QT_END_NAMESPACE + +class TypeControl; +class HintControl; + +// A control for editing points or sizes +class CoordinateControl : public QWidget +{ + Q_OBJECT + +public: + CoordinateControl(const QString &sep); + + void setPointValue(const QPoint &p) { setCoordinates(p.x(), p.y()); } + QPoint pointValue() const { const QPair<int, int> t = coordinates(); return QPoint(t.first, t.second); } + + void setSizeValue(const QSize &s) { setCoordinates(s.width(), s.height()); } + QSize sizeValue() const { const QPair<int, int> t = coordinates(); return QSize(t.first, t.second); } + +signals: + void pointValueChanged(const QPoint &p); + void sizeValueChanged(const QSize &s); + +private slots: + void spinBoxChanged(); + +private: + void setCoordinates(int x, int y); + QPair<int, int> coordinates() const; + + QSpinBox *m_x; + QSpinBox *m_y; +}; + +// A control for editing QRect +class RectControl : public QGroupBox +{ + Q_OBJECT +public: + RectControl(); + void setRectValue(const QRect &r); + QRect rectValue() const; + +signals: + void changed(const QRect &r); + void sizeChanged(const QSize &s); + void positionChanged(const QPoint &s); + +private slots: + void handleChanged(); + +private: + CoordinateControl *m_point; + CoordinateControl *m_size; +}; + +// Base class for controlling the position of a Window (QWindow or QWidget) +class BaseWindowControl : public QGroupBox +{ + Q_OBJECT + +protected: + explicit BaseWindowControl(QObject *w); + +public: + virtual bool eventFilter(QObject *, QEvent *); + virtual void refresh(); + +private slots: + void posChanged(const QPoint &); + void sizeChanged(const QSize &); + void framePosChanged(const QPoint &); + +protected: + QGridLayout *m_layout; + QObject *m_object; + +private: + virtual QRect objectGeometry(const QObject *o) const = 0; + virtual void setObjectGeometry(QObject *o, const QRect &) const = 0; + + virtual QPoint objectFramePosition(const QObject *o) const = 0; + virtual void setObjectFramePosition(QObject *o, const QPoint &) const = 0; + + virtual QPoint objectMapToGlobal(const QObject *o, const QPoint &) const = 0; + + RectControl *m_geometry; + CoordinateControl *m_framePosition; + QLabel *m_moveEventLabel; + QLabel *m_resizeEventLabel; + QLabel *m_mouseEventLabel; + unsigned m_moveCount; + unsigned m_resizeCount; +}; + +class ControllerWidget : public QMainWindow +{ + Q_OBJECT +public: + explicit ControllerWidget(QWidget *parent = 0); + ~ControllerWidget(); +private: + QScopedPointer<QWindow> m_testWindow; +}; + +#endif // CONTROLLERWIDGET_H diff --git a/tests/manual/windowchildgeometry/main.cpp b/tests/manual/windowchildgeometry/main.cpp new file mode 100644 index 0000000000..42266b777a --- /dev/null +++ b/tests/manual/windowchildgeometry/main.cpp @@ -0,0 +1,51 @@ +/**************************************************************************** +** +** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/legal +** +** This file is part of the test suite of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Digia. For licensing terms and +** conditions see http://qt.digia.com/licensing. For further information +** use the contact form at http://qt.digia.com/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Digia gives you certain additional +** rights. These rights are described in the Digia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include <QApplication> +#include "controllerwidget.h" + +int main(int argc, char *argv[]) +{ + QApplication a(argc, argv); + ControllerWidget controller; + controller.show(); + return a.exec(); +} diff --git a/tests/manual/windowchildgeometry/windowchildgeometry.pro b/tests/manual/windowchildgeometry/windowchildgeometry.pro new file mode 100644 index 0000000000..921acd8a4e --- /dev/null +++ b/tests/manual/windowchildgeometry/windowchildgeometry.pro @@ -0,0 +1,10 @@ +QT += core gui +greaterThan(QT_MAJOR_VERSION, 4): QT += widgets +TARGET = windowchildgeometry +TEMPLATE = app + +INCLUDEPATH += ../windowflags +SOURCES += $$PWD/main.cpp controllerwidget.cpp ../windowflags/controls.cpp +HEADERS += controllerwidget.h ../windowflags/controls.h + +DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0 |