summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--src/plugins/platforms/cocoa/qcocoawindow.h13
-rw-r--r--src/plugins/platforms/cocoa/qcocoawindow.mm340
-rw-r--r--src/plugins/platforms/cocoa/qnsview.mm26
-rw-r--r--tests/auto/other/qfocusevent/tst_qfocusevent.cpp3
-rw-r--r--tests/manual/windowchildgeometry/controllerwidget.cpp536
-rw-r--r--tests/manual/windowchildgeometry/controllerwidget.h158
-rw-r--r--tests/manual/windowchildgeometry/main.cpp51
-rw-r--r--tests/manual/windowchildgeometry/windowchildgeometry.pro10
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