summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAlexis Menard <alexis.menard@nokia.com>2009-10-20 10:39:56 +0200
committerAlexis Menard <alexis.menard@nokia.com>2009-10-20 10:45:47 +0200
commita210a1efb3a255235ab22e618c61d0aaccba3d9f (patch)
treec6842a515fd54ecdcd961a6c4d49180fd0966267
parent93550050f4fe4f411bfbd80d7b30ff5bc8a20df7 (diff)
QToolButton popup menu is shown at wrong position when embedded in a
QGraphicsView. The main problem here is that QWidget assume that they are in the screen somewhere, which means inside the available geometry provided by QDesktopWidget. But in QGraphicsView the button can be in a position that is way bigger than the screen resolution. Lot of widgets make this assumption when positionning subpopups or submenus. Instead of applying the same code on tons of QWidgets, it's better to have an helper function in desktop widget which catch this case. It's not pretty (since it has nothing to do with QDesktopWidget) but we don't have better solution. Task-number:QTBUG-3822 Reviewed-by:brad
-rw-r--r--src/gui/kernel/kernel.pri1
-rw-r--r--src/gui/kernel/qdesktopwidget.cpp67
-rw-r--r--src/gui/kernel/qdesktopwidget.h6
-rw-r--r--src/gui/kernel/qwidget.cpp22
-rw-r--r--src/gui/kernel/qwidget_p.h53
-rw-r--r--src/gui/widgets/qmenu.cpp31
-rw-r--r--src/gui/widgets/qmenu_p.h3
-rw-r--r--src/gui/widgets/qpushbutton.cpp4
8 files changed, 155 insertions, 32 deletions
diff --git a/src/gui/kernel/kernel.pri b/src/gui/kernel/kernel.pri
index 53c26115f7..8859358d06 100644
--- a/src/gui/kernel/kernel.pri
+++ b/src/gui/kernel/kernel.pri
@@ -84,6 +84,7 @@ SOURCES += \
kernel/qgesturerecognizer.cpp \
kernel/qgesturemanager.cpp \
kernel/qsoftkeymanager.cpp \
+ kernel/qdesktopwidget.cpp \
kernel/qguiplatformplugin.cpp
win32 {
diff --git a/src/gui/kernel/qdesktopwidget.cpp b/src/gui/kernel/qdesktopwidget.cpp
new file mode 100644
index 0000000000..b1e100879b
--- /dev/null
+++ b/src/gui/kernel/qdesktopwidget.cpp
@@ -0,0 +1,67 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtGui module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** 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, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qglobal.h"
+
+QT_BEGIN_NAMESPACE
+
+#include "qdesktopwidget.h"
+#include "qwidget_p.h"
+
+const QRect QDesktopWidget::screenGeometry(const QWidget *widget) const
+{
+ QRect rect = QWidgetPrivate::screenGeometry(widget);
+ if (rect.isNull())
+ return screenGeometry(screenNumber(widget));
+ else return rect;
+}
+
+const QRect QDesktopWidget::availableGeometry(const QWidget *widget) const
+{
+ QRect rect = QWidgetPrivate::screenGeometry(widget);
+ if (rect.isNull())
+ return availableGeometry(screenNumber(widget));
+ else
+ return rect;
+}
+
+QT_END_NAMESPACE
+
diff --git a/src/gui/kernel/qdesktopwidget.h b/src/gui/kernel/qdesktopwidget.h
index 85f479e346..6e3447ce2a 100644
--- a/src/gui/kernel/qdesktopwidget.h
+++ b/src/gui/kernel/qdesktopwidget.h
@@ -75,14 +75,12 @@ public:
QWidget *screen(int screen = -1);
const QRect screenGeometry(int screen = -1) const;
- const QRect screenGeometry(const QWidget *widget) const
- { return screenGeometry(screenNumber(widget)); }
+ const QRect screenGeometry(const QWidget *widget) const;
const QRect screenGeometry(const QPoint &point) const
{ return screenGeometry(screenNumber(point)); }
const QRect availableGeometry(int screen = -1) const;
- const QRect availableGeometry(const QWidget *widget) const
- { return availableGeometry(screenNumber(widget)); }
+ const QRect availableGeometry(const QWidget *widget) const;
const QRect availableGeometry(const QPoint &point) const
{ return availableGeometry(screenNumber(point)); }
diff --git a/src/gui/kernel/qwidget.cpp b/src/gui/kernel/qwidget.cpp
index 7dc3ae9c56..e561aca4a9 100644
--- a/src/gui/kernel/qwidget.cpp
+++ b/src/gui/kernel/qwidget.cpp
@@ -149,24 +149,6 @@ static inline bool hasBackingStoreSupport()
#endif
}
-/*!
- \internal
-
- Returns true if \a p or any of its parents enable the
- Qt::BypassGraphicsProxyWidget window flag. Used in QWidget::show() and
- QWidget::setParent() to determine whether it's necessary to embed the
- widget into a QGraphicsProxyWidget or not.
-*/
-static inline bool bypassGraphicsProxyWidget(QWidget *p)
-{
- while (p) {
- if (p->windowFlags() & Qt::BypassGraphicsProxyWidget)
- return true;
- p = p->parentWidget();
- }
- return false;
-}
-
#ifdef Q_WS_MAC
# define QT_NO_PAINT_DEBUG
#endif
@@ -5473,6 +5455,7 @@ QPixmap QWidgetEffectSourcePrivate::pixmap(Qt::CoordinateSystem system, QPoint *
return pixmap;
}
+#ifndef QT_NO_GRAPHICSVIEW
/*!
\internal
@@ -5481,7 +5464,7 @@ QPixmap QWidgetEffectSourcePrivate::pixmap(Qt::CoordinateSystem system, QPoint *
If successful, the function returns the proxy that embeds the widget, or 0 if no embedded
widget was found.
*/
-QGraphicsProxyWidget * QWidgetPrivate::nearestGraphicsProxyWidget(QWidget *origin)
+QGraphicsProxyWidget * QWidgetPrivate::nearestGraphicsProxyWidget(const QWidget *origin)
{
if (origin) {
QWExtra *extra = origin->d_func()->extra;
@@ -5491,6 +5474,7 @@ QGraphicsProxyWidget * QWidgetPrivate::nearestGraphicsProxyWidget(QWidget *origi
}
return 0;
}
+#endif
/*!
\property QWidget::locale
diff --git a/src/gui/kernel/qwidget_p.h b/src/gui/kernel/qwidget_p.h
index a5497404d9..2132474c84 100644
--- a/src/gui/kernel/qwidget_p.h
+++ b/src/gui/kernel/qwidget_p.h
@@ -63,7 +63,9 @@
#include "QtGui/qstyle.h"
#include "QtGui/qapplication.h"
#include <private/qgraphicseffect_p.h>
-
+#include "QtGui/qgraphicsproxywidget.h"
+#include "QtGui/qgraphicsscene.h"
+#include "QtGui/qgraphicsview.h"
#include <private/qgesture_p.h>
#ifdef Q_WS_WIN
@@ -180,7 +182,9 @@ struct QWExtra {
// Regular pointers (keep them together to avoid gaps on 64 bits architectures).
void *glContext; // if the widget is hijacked by QGLWindowSurface
QTLWExtra *topextra; // only useful for TLWs
+#ifndef QT_NO_GRAPHICSVIEW
QGraphicsProxyWidget *proxyWidget; // if the widget is embedded
+#endif
#ifndef QT_NO_CURSOR
QCursor *curs;
#endif
@@ -235,6 +239,24 @@ struct QWExtra {
#endif
};
+/*!
+ \internal
+
+ Returns true if \a p or any of its parents enable the
+ Qt::BypassGraphicsProxyWidget window flag. Used in QWidget::show() and
+ QWidget::setParent() to determine whether it's necessary to embed the
+ widget into a QGraphicsProxyWidget or not.
+*/
+static inline bool bypassGraphicsProxyWidget(const QWidget *p)
+{
+ while (p) {
+ if (p->windowFlags() & Qt::BypassGraphicsProxyWidget)
+ return true;
+ p = p->parentWidget();
+ }
+ return false;
+}
+
class Q_GUI_EXPORT QWidgetPrivate : public QObjectPrivate
{
Q_DECLARE_PUBLIC(QWidget)
@@ -344,7 +366,9 @@ public:
QPainter *beginSharedPainter();
bool endSharedPainter();
- static QGraphicsProxyWidget * nearestGraphicsProxyWidget(QWidget *origin);
+#ifndef QT_NO_GRAPHICSVIEW
+ static QGraphicsProxyWidget * nearestGraphicsProxyWidget(const QWidget *origin);
+#endif
QWindowSurface *createDefaultWindowSurface();
QWindowSurface *createDefaultWindowSurface_sys();
void repaint_sys(const QRegion &rgn);
@@ -441,6 +465,31 @@ public:
void setModal_sys();
+ // This is an helper function that return the available geometry for
+ // a widget and takes care is this one is in QGraphicsView.
+ // If the widget is not embed in a scene then the geometry available is
+ // null, we let QDesktopWidget decide for us.
+ static QRect screenGeometry(const QWidget *widget)
+ {
+ QRect screen;
+#ifndef QT_NO_GRAPHICSVIEW
+ QGraphicsProxyWidget *ancestorProxy = widget->d_func()->nearestGraphicsProxyWidget(widget);
+ //It's embedded if it has an ancestor
+ if (ancestorProxy) {
+ if (!bypassGraphicsProxyWidget(widget)) {
+ // One view, let be smart and return the viewport rect then the popup is aligned
+ if (ancestorProxy->scene()->views().size() == 1) {
+ QGraphicsView *view = ancestorProxy->scene()->views().at(0);
+ screen = view->mapToScene(view->viewport()->rect()).boundingRect().toRect();
+ } else {
+ screen = ancestorProxy->scene()->sceneRect().toRect();
+ }
+ }
+ }
+#endif
+ return screen;
+ }
+
inline void setRedirected(QPaintDevice *replacement, const QPoint &offset)
{
Q_ASSERT(q_func()->testAttribute(Qt::WA_WState_InPaintEvent));
diff --git a/src/gui/widgets/qmenu.cpp b/src/gui/widgets/qmenu.cpp
index 687e1bc3b4..324bc90424 100644
--- a/src/gui/widgets/qmenu.cpp
+++ b/src/gui/widgets/qmenu.cpp
@@ -180,6 +180,21 @@ int QMenuPrivate::scrollerHeight() const
}
//Windows and KDE allows menus to cover the taskbar, while GNOME and Mac don't
+QRect QMenuPrivate::popupGeometry(const QWidget *widget) const
+{
+#ifdef Q_WS_WIN
+ return QApplication::desktop()->screenGeometry(widget);
+#elif defined Q_WS_X11
+ if (X11->desktopEnvironment == DE_KDE)
+ return QApplication::desktop()->screenGeometry(widget);
+ else
+ return QApplication::desktop()->availableGeometry(widget);
+#else
+ return QApplication::desktop()->availableGeometry(widget);
+#endif
+}
+
+//Windows and KDE allows menus to cover the taskbar, while GNOME and Mac don't
QRect QMenuPrivate::popupGeometry(int screen) const
{
#ifdef Q_WS_WIN
@@ -234,7 +249,7 @@ void QMenuPrivate::updateActionRects() const
}
int max_column_width = 0,
- dh = popupGeometry(QApplication::desktop()->screenNumber(q)).height(),
+ dh = popupGeometry(q).height(),
y = 0;
QStyle *style = q->style();
QStyleOption opt;
@@ -744,7 +759,7 @@ void QMenuPrivate::scrollMenu(QAction *action, QMenuScroller::ScrollLocation loc
if (newScrollFlags & QMenuScroller::ScrollUp)
newOffset -= vmargin;
- QRect screen = popupGeometry(QApplication::desktop()->screenNumber(q));
+ QRect screen = popupGeometry(q);
const int desktopFrame = q->style()->pixelMetric(QStyle::PM_MenuDesktopFrameWidth, 0, q);
if (q->height() < screen.height()-(desktopFrame*2)-1) {
QRect geom = q->geometry();
@@ -1789,7 +1804,15 @@ void QMenu::popup(const QPoint &p, QAction *atAction)
d->updateActionRects();
QPoint pos = p;
QSize size = sizeHint();
- QRect screen = d->popupGeometry(QApplication::desktop()->screenNumber(p));
+ QRect screen;
+#ifndef QT_NO_GRAPHICSVIEW
+ bool isEmbedded = d->nearestGraphicsProxyWidget(this);
+ if (isEmbedded)
+ screen = d->popupGeometry(this);
+ else
+#endif
+ screen = d->popupGeometry(QApplication::desktop()->screenNumber(p));
+
const int desktopFrame = style()->pixelMetric(QStyle::PM_MenuDesktopFrameWidth, 0, this);
bool adjustToDesktop = !window()->testAttribute(Qt::WA_DontShowOnScreen);
#ifdef QT_KEYPAD_NAVIGATION
@@ -2927,7 +2950,7 @@ void QMenu::internalDelayedPopup()
QPoint pos(rightPos);
QMenu *caused = qobject_cast<QMenu*>(d->activeMenu->d_func()->causedPopup.widget);
- const QRect availGeometry(d->popupGeometry(QApplication::desktop()->screenNumber(caused)));
+ const QRect availGeometry(d->popupGeometry(caused));
if (isRightToLeft()) {
pos = leftPos;
if ((caused && caused->x() < x()) || pos.x() < availGeometry.left()) {
diff --git a/src/gui/widgets/qmenu_p.h b/src/gui/widgets/qmenu_p.h
index 9c4f260896..6a8e4b01b1 100644
--- a/src/gui/widgets/qmenu_p.h
+++ b/src/gui/widgets/qmenu_p.h
@@ -192,7 +192,8 @@ public:
mutable QVector<QRect> actionRects;
mutable QWidgetList widgetItems;
void updateActionRects() const;
- QRect popupGeometry(int screen=-1) const;
+ QRect popupGeometry(const QWidget *widget) const;
+ QRect popupGeometry(int screen = -1) const;
mutable uint ncols : 4; //4 bits is probably plenty
uint collapsibleSeparators : 1;
diff --git a/src/gui/widgets/qpushbutton.cpp b/src/gui/widgets/qpushbutton.cpp
index 1352e1b614..eb34336a53 100644
--- a/src/gui/widgets/qpushbutton.cpp
+++ b/src/gui/widgets/qpushbutton.cpp
@@ -590,7 +590,7 @@ void QPushButtonPrivate::_q_popupPressed()
int x = globalPos.x();
int y = globalPos.y();
if (horizontal) {
- if (globalPos.y() + rect.height() + menuSize.height() <= QApplication::desktop()->height()) {
+ if (globalPos.y() + rect.height() + menuSize.height() <= QApplication::desktop()->availableGeometry(q).height()) {
y += rect.height();
} else {
y -= menuSize.height();
@@ -598,7 +598,7 @@ void QPushButtonPrivate::_q_popupPressed()
if (q->layoutDirection() == Qt::RightToLeft)
x += rect.width() - menuSize.width();
} else {
- if (globalPos.x() + rect.width() + menu->sizeHint().width() <= QApplication::desktop()->width())
+ if (globalPos.x() + rect.width() + menu->sizeHint().width() <= QApplication::desktop()->availableGeometry(q).width())
x += rect.width();
else
x -= menuSize.width();