summaryrefslogtreecommitdiffstats
path: root/src/gui/kernel
diff options
context:
space:
mode:
Diffstat (limited to 'src/gui/kernel')
-rw-r--r--src/gui/kernel/kernel.pri8
-rw-r--r--src/gui/kernel/qapplication.cpp31
-rw-r--r--src/gui/kernel/qapplication_mac.mm124
-rw-r--r--src/gui/kernel/qapplication_p.h6
-rw-r--r--src/gui/kernel/qapplication_qpa.cpp44
-rw-r--r--src/gui/kernel/qapplication_qws.cpp5
-rw-r--r--src/gui/kernel/qapplication_s60.cpp199
-rw-r--r--src/gui/kernel/qapplication_x11.cpp48
-rw-r--r--src/gui/kernel/qclipboard_qpa.cpp82
-rw-r--r--src/gui/kernel/qclipboard_win.cpp15
-rw-r--r--src/gui/kernel/qcocoaapplicationdelegate_mac.mm24
-rw-r--r--src/gui/kernel/qcocoapanel_mac.mm7
-rw-r--r--src/gui/kernel/qcocoapanel_mac_p.h16
-rw-r--r--src/gui/kernel/qcocoasharedwindowmethods_mac_p.h421
-rw-r--r--src/gui/kernel/qcocoaview_mac.mm962
-rw-r--r--src/gui/kernel/qcocoaview_mac_p.h29
-rw-r--r--src/gui/kernel/qcocoawindow_mac.mm2
-rw-r--r--src/gui/kernel/qcocoawindow_mac_p.h17
-rw-r--r--src/gui/kernel/qcocoawindowdelegate_mac.mm21
-rw-r--r--src/gui/kernel/qcursor.h5
-rw-r--r--src/gui/kernel/qcursor_mac.mm128
-rw-r--r--src/gui/kernel/qcursor_s60.cpp4
-rw-r--r--src/gui/kernel/qdesktopwidget_qpa_p.h8
-rw-r--r--src/gui/kernel/qdesktopwidget_s60.cpp164
-rw-r--r--src/gui/kernel/qdnd_mac.mm4
-rw-r--r--src/gui/kernel/qdnd_p.h2
-rw-r--r--src/gui/kernel/qevent.cpp77
-rw-r--r--src/gui/kernel/qevent.h9
-rw-r--r--src/gui/kernel/qevent_p.h8
-rw-r--r--src/gui/kernel/qeventdispatcher_mac.mm68
-rw-r--r--src/gui/kernel/qeventdispatcher_qpa.cpp1
-rw-r--r--src/gui/kernel/qgesture.cpp2
-rw-r--r--src/gui/kernel/qkeymapper_p.h1
-rw-r--r--src/gui/kernel/qkeymapper_s60.cpp32
-rw-r--r--src/gui/kernel/qkeymapper_x11_p.cpp1
-rw-r--r--src/gui/kernel/qlayout.cpp6
-rw-r--r--src/gui/kernel/qmacgesturerecognizer_mac.mm6
-rw-r--r--src/gui/kernel/qplatformclipboard_qpa.cpp105
-rw-r--r--src/gui/kernel/qplatformclipboard_qpa.h73
-rw-r--r--src/gui/kernel/qplatformglcontext_qpa.cpp2
-rw-r--r--src/gui/kernel/qplatformglcontext_qpa.h2
-rw-r--r--src/gui/kernel/qplatformintegration_qpa.cpp38
-rw-r--r--src/gui/kernel/qplatformintegration_qpa.h16
-rw-r--r--src/gui/kernel/qplatformintegrationfactory_qpa.cpp27
-rw-r--r--src/gui/kernel/qplatformintegrationfactory_qpa_p.h4
-rw-r--r--src/gui/kernel/qplatformnativeinterface_qpa.cpp53
-rw-r--r--src/gui/kernel/qplatformnativeinterface_qpa.h65
-rw-r--r--src/gui/kernel/qplatformscreen_qpa.cpp15
-rw-r--r--src/gui/kernel/qplatformscreen_qpa.h4
-rw-r--r--src/gui/kernel/qplatformwindow_qpa.cpp19
-rw-r--r--src/gui/kernel/qplatformwindow_qpa.h1
-rw-r--r--src/gui/kernel/qt_cocoa_helpers_mac.mm483
-rw-r--r--src/gui/kernel/qt_cocoa_helpers_mac_p.h116
-rw-r--r--src/gui/kernel/qt_s60_p.h91
-rw-r--r--src/gui/kernel/qwidget.cpp158
-rw-r--r--src/gui/kernel/qwidget_mac.mm838
-rw-r--r--src/gui/kernel/qwidget_p.h36
-rw-r--r--src/gui/kernel/qwidget_qpa.cpp64
-rw-r--r--src/gui/kernel/qwidget_s60.cpp108
-rw-r--r--src/gui/kernel/qwidget_x11.cpp66
-rw-r--r--src/gui/kernel/qwindowsysteminterface_qpa.cpp36
-rw-r--r--src/gui/kernel/qwindowsysteminterface_qpa.h12
-rw-r--r--src/gui/kernel/qwindowsysteminterface_qpa_p.h21
-rw-r--r--src/gui/kernel/qx11embed_x11.cpp7
64 files changed, 3385 insertions, 1662 deletions
diff --git a/src/gui/kernel/kernel.pri b/src/gui/kernel/kernel.pri
index 4261e93..32fa3d3 100644
--- a/src/gui/kernel/kernel.pri
+++ b/src/gui/kernel/kernel.pri
@@ -222,7 +222,9 @@ qpa {
kernel/qplatformglcontext_qpa.h \
kernel/qdesktopwidget_qpa_p.h \
kernel/qplatformeventloopintegration_qpa.h \
- kernel/qplatformcursor_qpa.h
+ kernel/qplatformcursor_qpa.h \
+ kernel/qplatformclipboard_qpa.h \
+ kernel/qplatformnativeinterface_qpa.h
SOURCES += \
kernel/qapplication_qpa.cpp \
@@ -244,7 +246,9 @@ qpa {
kernel/qplatformwindowformat_qpa.cpp \
kernel/qplatformeventloopintegration_qpa.cpp \
kernel/qplatformglcontext_qpa.cpp \
- kernel/qplatformcursor_qpa.cpp
+ kernel/qplatformcursor_qpa.cpp \
+ kernel/qplatformclipboard_qpa.cpp \
+ kernel/qplatformnativeinterface_qpa.cpp
contains(QT_CONFIG, glib) {
SOURCES += \
diff --git a/src/gui/kernel/qapplication.cpp b/src/gui/kernel/qapplication.cpp
index 5c4a314..e91fe04 100644
--- a/src/gui/kernel/qapplication.cpp
+++ b/src/gui/kernel/qapplication.cpp
@@ -2771,7 +2771,7 @@ void QApplicationPrivate::dispatchEnterLeave(QWidget* enter, QWidget* leave) {
for (int i = 0; i < leaveList.size(); ++i) {
w = leaveList.at(i);
if (!QApplication::activeModalWidget() || QApplicationPrivate::tryModalHelper(w, 0)) {
-#if defined(Q_WS_WIN) || defined(Q_WS_X11)
+#if defined(Q_WS_WIN) || defined(Q_WS_X11) || defined(Q_WS_MAC)
if (leaveAfterRelease == w)
leaveAfterRelease = 0;
#endif
@@ -3142,13 +3142,11 @@ bool QApplicationPrivate::sendMouseEvent(QWidget *receiver, QMouseEvent *event,
// Dispatch enter/leave if:
// 1) the mouse grabber is an alien widget
// 2) the button is released on an alien widget
-
QWidget *enter = 0;
if (nativeGuard)
enter = alienGuard ? alienWidget : nativeWidget;
else // The receiver is typically deleted on mouse release with drag'n'drop.
enter = QApplication::widgetAt(event->globalPos());
-
dispatchEnterLeave(enter, leaveAfterRelease);
leaveAfterRelease = 0;
lastMouseReceiver = enter;
@@ -3695,15 +3693,6 @@ void QApplication::changeOverrideCursor(const QCursor &cursor)
if (qApp->d_func()->cursor_list.isEmpty())
return;
qApp->d_func()->cursor_list.removeFirst();
-#ifdef QT_MAC_USE_COCOA
- // We use native NSCursor stacks in Cocoa. The currentCursor is the
- // top of this stack. So to avoid flickering of cursor, we have to
- // change the cusor instead of pop-ing the existing OverrideCursor
- // and pushing the new one.
- qApp->d_func()->cursor_list.prepend(cursor);
- qt_cocoaChangeOverrideCursor(cursor);
- return;
-#endif
setOverrideCursor(cursor);
}
#endif
@@ -4434,6 +4423,24 @@ bool QApplication::notify(QObject *receiver, QEvent *e)
break;
}
#endif // QT_NO_GESTURES
+#ifdef QT_MAC_USE_COCOA
+ case QEvent::Enter:
+ if (receiver->isWidgetType()) {
+ QWidget *w = static_cast<QWidget *>(receiver);
+ if (w->testAttribute(Qt::WA_AcceptTouchEvents))
+ qt_widget_private(w)->registerTouchWindow(true);
+ }
+ res = d->notify_helper(receiver, e);
+ break;
+ case QEvent::Leave:
+ if (receiver->isWidgetType()) {
+ QWidget *w = static_cast<QWidget *>(receiver);
+ if (w->testAttribute(Qt::WA_AcceptTouchEvents))
+ qt_widget_private(w)->registerTouchWindow(false);
+ }
+ res = d->notify_helper(receiver, e);
+ break;
+#endif
default:
res = d->notify_helper(receiver, e);
break;
diff --git a/src/gui/kernel/qapplication_mac.mm b/src/gui/kernel/qapplication_mac.mm
index b22a6b3..f607a72 100644
--- a/src/gui/kernel/qapplication_mac.mm
+++ b/src/gui/kernel/qapplication_mac.mm
@@ -165,6 +165,7 @@ QT_BEGIN_NAMESPACE
//for qt_mac.h
QPaintDevice *qt_mac_safe_pdev = 0;
QList<QMacWindowChangeEvent*> *QMacWindowChangeEvent::change_events = 0;
+QPointer<QWidget> topLevelAt_cache = 0;
/*****************************************************************************
Internal variables and functions
@@ -192,7 +193,6 @@ static bool qt_mac_previous_press_in_popup_mode = false;
static bool qt_mac_no_click_through_mode = false;
static int tablet_button_state = 0;
#endif
-QPointer<QWidget> qt_mouseover;
#if defined(QT_DEBUG)
static bool appNoGrab = false; // mouse/keyboard grabbing
#endif
@@ -216,11 +216,12 @@ extern bool qt_mac_can_clickThrough(const QWidget *); //qwidget_mac.cpp
extern bool qt_mac_is_macdrawer(const QWidget *); //qwidget_mac.cpp
extern OSWindowRef qt_mac_window_for(const QWidget*); //qwidget_mac.cpp
extern QWidget *qt_mac_find_window(OSWindowRef); //qwidget_mac.cpp
-extern void qt_mac_set_cursor(const QCursor *, const QPoint &); //qcursor_mac.cpp
+extern void qt_mac_set_cursor(const QCursor *); //qcursor_mac.cpp
extern bool qt_mac_is_macsheet(const QWidget *); //qwidget_mac.cpp
extern QString qt_mac_from_pascal_string(const Str255); //qglobal.cpp
extern void qt_mac_command_set_enabled(MenuRef, UInt32, bool); //qmenu_mac.cpp
extern bool qt_sendSpontaneousEvent(QObject *obj, QEvent *event); // qapplication.cpp
+extern void qt_mac_update_cursor(); // qcursor_mac.mm
// Forward Decls
void onApplicationWindowChangedActivation( QWidget*widget, bool activated );
@@ -1364,43 +1365,16 @@ void QApplication::setMainWidget(QWidget *mainWidget)
/*****************************************************************************
QApplication cursor stack
*****************************************************************************/
-#ifdef QT_MAC_USE_COCOA
-void QApplicationPrivate::disableUsageOfCursorRects(bool disable)
-{
- // In Cocoa there are two competing ways of setting the cursor; either
- // by using cursor rects (see qcocoaview_mac.mm), or by pushing/popping
- // the cursor manually. When we use override cursors, it makes most sense
- // to use the latter. But then we need to tell cocoa to stop using the
- // first approach so it doesn't change the cursor back when hovering over
- // a cursor rect:
- QWidgetList topLevels = qApp->topLevelWidgets();
- for (int i=0; i<topLevels.size(); ++i) {
- if (NSWindow *window = qt_mac_window_for(topLevels.at(i)))
- disable ? [window disableCursorRects] : [window enableCursorRects];
- }
-}
-
-void QApplicationPrivate::updateOverrideCursor()
-{
- // Sometimes Cocoa forgets that we have set a Cursor
- // manually. In those cases, remind it again:
- if (QCursor *override = qApp->overrideCursor())
- [static_cast<NSCursor *>(qt_mac_nsCursorForQCursor(*override)) set];
-}
-#endif
void QApplication::setOverrideCursor(const QCursor &cursor)
{
qApp->d_func()->cursor_list.prepend(cursor);
#ifdef QT_MAC_USE_COCOA
- QMacCocoaAutoReleasePool pool;
- if (qApp->d_func()->cursor_list.size() == 1)
- qApp->d_func()->disableUsageOfCursorRects(true);
- [static_cast<NSCursor *>(qt_mac_nsCursorForQCursor(cursor)) push];
+ qt_mac_update_cursor();
#else
if (qApp && qApp->activeWindow())
- qt_mac_set_cursor(&qApp->d_func()->cursor_list.first(), QCursor::pos());
+ qt_mac_set_cursor(&qApp->d_func()->cursor_list.first());
#endif
}
@@ -1411,14 +1385,11 @@ void QApplication::restoreOverrideCursor()
qApp->d_func()->cursor_list.removeFirst();
#ifdef QT_MAC_USE_COCOA
- QMacCocoaAutoReleasePool pool;
- [NSCursor pop];
- if (qApp->d_func()->cursor_list.isEmpty())
- qApp->d_func()->disableUsageOfCursorRects(false);
+ qt_mac_update_cursor();
#else
if (qApp && qApp->activeWindow()) {
const QCursor def(Qt::ArrowCursor);
- qt_mac_set_cursor(qApp->d_func()->cursor_list.isEmpty() ? &def : &qApp->d_func()->cursor_list.first(), QCursor::pos());
+ qt_mac_set_cursor(qApp->d_func()->cursor_list.isEmpty() ? &def : &qApp->d_func()->cursor_list.first());
}
#endif
}
@@ -1431,30 +1402,54 @@ QWidget *QApplication::topLevelAt(const QPoint &p)
qt_mac_window_at(p.x(), p.y(), &widget);
return widget;
#else
+ // Use a cache to avoid iterate through the whole list of windows for all
+ // calls to to topLevelAt. We e.g. do this for each and every mouse
+ // move since we need to find the widget under mouse:
+ if (topLevelAt_cache && topLevelAt_cache->frameGeometry().contains(p))
+ return topLevelAt_cache;
+
+ // INVARIANT: Cache miss. Go through the list if windows instead:
+ QMacCocoaAutoReleasePool pool;
+ NSPoint cocoaPoint = flipPoint(p);
NSInteger windowCount;
NSCountWindows(&windowCount);
if (windowCount <= 0)
return 0; // There's no window to find!
- QMacCocoaAutoReleasePool pool;
- NSPoint cocoaPoint = flipPoint(p);
+
QVarLengthArray<NSInteger> windowList(windowCount);
NSWindowList(windowCount, windowList.data());
+ int firstQtWindowFound = -1;
for (int i = 0; i < windowCount; ++i) {
NSWindow *window = [NSApp windowWithWindowNumber:windowList[i]];
- if (window && NSPointInRect(cocoaPoint, [window frame])) {
+ if (window) {
QWidget *candidateWindow = [window QT_MANGLE_NAMESPACE(qt_qwidget)];
- // Check to see if there's a hole in the window where the mask is.
- // If there is, we should just continue to see if there is a window below.
- if (candidateWindow && !candidateWindow->mask().isEmpty()) {
- QPoint localPoint = candidateWindow->mapFromGlobal(p);
- if (!candidateWindow->mask().contains(localPoint)) {
- continue;
+ if (candidateWindow && firstQtWindowFound == -1)
+ firstQtWindowFound = i;
+
+ if (NSPointInRect(cocoaPoint, [window frame])) {
+ // Check to see if there's a hole in the window where the mask is.
+ // If there is, we should just continue to see if there is a window below.
+ if (candidateWindow && !candidateWindow->mask().isEmpty()) {
+ QPoint localPoint = candidateWindow->mapFromGlobal(p);
+ if (!candidateWindow->mask().contains(localPoint))
+ continue;
+ else
+ return candidateWindow;
+ } else {
+ if (i == firstQtWindowFound) {
+ // The cache will only work when the window under mouse is
+ // top most (that is, not partially obscured by other windows.
+ // And we only set it if no mask is present to optimize for the common case:
+ topLevelAt_cache = candidateWindow;
+ }
+ return candidateWindow;
}
}
- return candidateWindow;
}
}
- return 0; // Couldn't find a window at this point
+
+ topLevelAt_cache = 0;
+ return 0;
#endif
}
@@ -1480,8 +1475,8 @@ void QApplicationPrivate::enterModal_sys(QWidget *widget)
if (!qt_modal_stack)
qt_modal_stack = new QWidgetList;
- dispatchEnterLeave(0, qt_mouseover);
- qt_mouseover = 0;
+ dispatchEnterLeave(0, qt_last_mouse_receiver);
+ qt_last_mouse_receiver = 0;
qt_modal_stack->insert(0, widget);
if (!app_do_modal)
@@ -1512,8 +1507,8 @@ void QApplicationPrivate::leaveModal_sys(QWidget *widget)
w = grabber;
else
w = QApplication::widgetAt(p.x(), p.y());
- dispatchEnterLeave(w, qt_mouseover); // send synthetic enter event
- qt_mouseover = w;
+ dispatchEnterLeave(w, qt_last_mouse_receiver); // send synthetic enter event
+ qt_last_mouse_receiver = w;
}
#ifdef QT_MAC_USE_COCOA
if (!qt_mac_is_macsheet(widget))
@@ -1938,7 +1933,7 @@ QApplicationPrivate::globalEventProcessor(EventHandlerCallRef er, EventRef event
}
}
}
- qt_mac_set_cursor(&cursor, QPoint(where.h, where.v));
+ qt_mac_set_cursor(&cursor);
}
//This mouse button state stuff looks like this on purpose
@@ -2132,20 +2127,20 @@ QApplicationPrivate::globalEventProcessor(EventHandlerCallRef er, EventRef event
QWidget * const enterLeaveWidget = (inPopupMode || ekind == kEventMouseUp) ?
QApplication::widgetAt(where.h, where.v) : static_cast<QWidget*>(widget);
- if ((QWidget *) qt_mouseover != enterLeaveWidget || inNonClientArea) {
+ if ((QWidget *) qt_last_mouse_receiver != enterLeaveWidget || inNonClientArea) {
#ifdef DEBUG_MOUSE_MAPS
qDebug("Entering: %p - %s (%s), Leaving %s (%s)", (QWidget*)enterLeaveWidget,
enterLeaveWidget ? enterLeaveWidget->metaObject()->className() : "none",
enterLeaveWidget ? enterLeaveWidget->objectName().toLocal8Bit().constData() : "",
- qt_mouseover ? qt_mouseover->metaObject()->className() : "none",
- qt_mouseover ? qt_mouseover->objectName().toLocal8Bit().constData() : "");
+ qt_last_mouse_receiver ? qt_last_mouse_receiver->metaObject()->className() : "none",
+ qt_last_mouse_receiver ? qt_last_mouse_receiver->objectName().toLocal8Bit().constData() : "");
#endif
QWidget * const mouseGrabber = QWidget::mouseGrabber();
if (inPopupMode) {
QWidget *enter = enterLeaveWidget;
- QWidget *leave = qt_mouseover;
+ QWidget *leave = qt_last_mouse_receiver;
if (mouseGrabber) {
QWidget * const popupWidget = qApp->activePopupWidget();
if (leave == popupWidget)
@@ -2155,15 +2150,15 @@ QApplicationPrivate::globalEventProcessor(EventHandlerCallRef er, EventRef event
if ((enter == mouseGrabber && leave == popupWidget)
|| (leave == mouseGrabber && enter == popupWidget)) {
QApplicationPrivate::dispatchEnterLeave(enter, leave);
- qt_mouseover = enter;
+ qt_last_mouse_receiver = enter;
}
} else {
QApplicationPrivate::dispatchEnterLeave(enter, leave);
- qt_mouseover = enter;
+ qt_last_mouse_receiver = enter;
}
- } else if ((!qt_button_down || !qt_mouseover) && !mouseGrabber && !leaveAfterRelease) {
- QApplicationPrivate::dispatchEnterLeave(enterLeaveWidget, qt_mouseover);
- qt_mouseover = enterLeaveWidget;
+ } else if ((!qt_button_down || !qt_last_mouse_receiver) && !mouseGrabber && !leaveAfterRelease) {
+ QApplicationPrivate::dispatchEnterLeave(enterLeaveWidget, qt_last_mouse_receiver);
+ qt_last_mouse_receiver = enterLeaveWidget;
}
}
break; }
@@ -2240,7 +2235,7 @@ QApplicationPrivate::globalEventProcessor(EventHandlerCallRef er, EventRef event
if (leaveAfterRelease) {
QWidget *enter = QApplication::widgetAt(where.h, where.v);
QApplicationPrivate::dispatchEnterLeave(enter, leaveAfterRelease);
- qt_mouseover = enter;
+ qt_last_mouse_receiver = enter;
leaveAfterRelease = 0;
}
@@ -2503,7 +2498,7 @@ QApplicationPrivate::globalEventProcessor(EventHandlerCallRef er, EventRef event
void QApplicationPrivate::qt_initAfterNSAppStarted()
{
setupAppleEvents();
- updateOverrideCursor();
+ qt_mac_update_cursor();
}
void QApplicationPrivate::setupAppleEvents()
@@ -3080,7 +3075,7 @@ void onApplicationWindowChangedActivation(QWidget *widget, bool activated)
}
QMenuBar::macUpdateMenuBar();
- QApplicationPrivate::updateOverrideCursor();
+ qt_mac_update_cursor();
#else
Q_UNUSED(widget);
Q_UNUSED(activated);
@@ -3115,6 +3110,7 @@ void onApplicationChangedActivation( bool activated )
app->setActiveWindow(tmp_w);
}
QMenuBar::macUpdateMenuBar();
+ qt_mac_update_cursor();
} else { // de-activated
QApplicationPrivate *priv = [[QT_MANGLE_NAMESPACE(QCocoaApplicationDelegate) sharedDelegate] qAppPrivate];
while (priv->inPopupMode())
diff --git a/src/gui/kernel/qapplication_p.h b/src/gui/kernel/qapplication_p.h
index f9508a7..954c6de 100644
--- a/src/gui/kernel/qapplication_p.h
+++ b/src/gui/kernel/qapplication_p.h
@@ -489,8 +489,6 @@ public:
#ifdef QT_MAC_USE_COCOA
static void qt_initAfterNSAppStarted();
static void setupAppleEvents();
- static void updateOverrideCursor();
- static void disableUsageOfCursorRects(bool disable);
#endif
static bool qt_mac_apply_settings();
#endif
@@ -508,6 +506,8 @@ public:
static void processEnterEvent(QWindowSystemInterfacePrivate::EnterEvent *e);
static void processLeaveEvent(QWindowSystemInterfacePrivate::LeaveEvent *e);
+ static void processActivatedEvent(QWindowSystemInterfacePrivate::ActivatedWindowEvent *e);
+
static void processWindowSystemEvent(QWindowSystemInterfacePrivate::WindowSystemEvent *e);
// static void reportScreenCount(int count);
@@ -639,6 +639,8 @@ public:
int pressureSupported;
int maxTouchPressure;
QList<QTouchEvent::TouchPoint> appAllTouchPoints;
+
+ bool useTranslucentEGLSurfaces;
#endif
private:
diff --git a/src/gui/kernel/qapplication_qpa.cpp b/src/gui/kernel/qapplication_qpa.cpp
index ece035c..cb5439c 100644
--- a/src/gui/kernel/qapplication_qpa.cpp
+++ b/src/gui/kernel/qapplication_qpa.cpp
@@ -51,6 +51,7 @@
#endif
#include "private/qwidget_p.h"
+#include "private/qevent_p.h"
#include "qgenericpluginfactory_qpa.h"
#include "qplatformintegrationfactory_qpa_p.h"
@@ -79,7 +80,6 @@ int qt_last_x = 0;
int qt_last_y = 0;
QPointer<QWidget> qt_last_mouse_receiver = 0;
-static Qt::KeyboardModifiers modifiers = Qt::NoModifier;
static Qt::MouseButtons buttons = Qt::NoButton;
static ulong mousePressTime;
static Qt::MouseButton mousePressButton = Qt::NoButton;
@@ -111,6 +111,9 @@ void QApplicationPrivate::processWindowSystemEvent(QWindowSystemInterfacePrivate
case QWindowSystemInterfacePrivate::Leave:
QApplicationPrivate::processLeaveEvent(static_cast<QWindowSystemInterfacePrivate::LeaveEvent *>(e));
break;
+ case QWindowSystemInterfacePrivate::ActivatedWindow:
+ QApplicationPrivate::processActivatedEvent(static_cast<QWindowSystemInterfacePrivate::ActivatedWindowEvent *>(e));
+ break;
case QWindowSystemInterfacePrivate::Close:
QApplicationPrivate::processCloseEvent(
static_cast<QWindowSystemInterfacePrivate::CloseEvent *>(e));
@@ -441,11 +444,11 @@ void QApplication::alert(QWidget *, int)
{
}
-static void init_platform(const QString &name)
+static void init_platform(const QString &name, const QString &platformPluginPath)
{
- QApplicationPrivate::platform_integration = QPlatformIntegrationFactory::create(name);
+ QApplicationPrivate::platform_integration = QPlatformIntegrationFactory::create(name, platformPluginPath);
if (!QApplicationPrivate::platform_integration) {
- QStringList keys = QPlatformIntegrationFactory::keys();
+ QStringList keys = QPlatformIntegrationFactory::keys(platformPluginPath);
QString fatalMessage =
QString::fromLatin1("Failed to load platform plugin \"%1\". Available platforms are: \n").arg(name);
foreach(QString key, keys) {
@@ -510,6 +513,7 @@ void qt_init(QApplicationPrivate *priv, int type)
}
QList<QByteArray> pluginList;
+ QString platformPluginPath = QLatin1String(qgetenv("QT_QPA_PLATFORM_PLUGIN_PATH"));
QString platformName = QLatin1String(qgetenv("QT_QPA_PLATFORM"));
// Get command line params
@@ -524,6 +528,9 @@ void qt_init(QApplicationPrivate *priv, int type)
if (arg == "-fn" || arg == "-font") {
if (++i < argc)
appFont = QString::fromLocal8Bit(argv[i]);
+ } else if (arg == "-platformpluginpath") {
+ if (++i < argc)
+ platformPluginPath = QLatin1String(argv[i]);
} else if (arg == "-platform") {
if (++i < argc)
platformName = QLatin1String(argv[i]);
@@ -547,7 +554,7 @@ void qt_init(QApplicationPrivate *priv, int type)
}
#endif
- init_platform(platformName);
+ init_platform(platformName, platformPluginPath);
init_plugins(pluginList);
QColormap::initialize();
@@ -724,7 +731,7 @@ void QApplicationPrivate::processMouseEvent(QWindowSystemInterfacePrivate::Mouse
// qDebug() << "sending mouse ev." << ev.type() << localPoint << globalPoint << ev.button() << ev.buttons() << mouseWidget << "mouse grabber" << implicit_mouse_grabber;
- QMouseEvent ev(type, localPoint, globalPoint, button, buttons, modifiers);
+ QMouseEvent ev(type, localPoint, globalPoint, button, buttons, QApplication::keyboardModifiers());
QList<QWeakPointer<QPlatformCursor> > cursors = QPlatformCursorPrivate::getInstances();
foreach (QWeakPointer<QPlatformCursor> cursor, cursors) {
@@ -732,7 +739,15 @@ void QApplicationPrivate::processMouseEvent(QWindowSystemInterfacePrivate::Mouse
cursor.data()->pointerEvent(ev);
}
+ int oldOpenPopupCount = openPopupCount;
QApplication::sendSpontaneousEvent(mouseWidget, &ev);
+
+#ifndef QT_NO_CONTEXTMENU
+ if (type == QEvent::MouseButtonPress && button == Qt::RightButton && (openPopupCount == oldOpenPopupCount)) {
+ QContextMenuEvent e(QContextMenuEvent::Mouse, localPoint, globalPoint, QApplication::keyboardModifiers());
+ QApplication::sendSpontaneousEvent(mouseWidget, &e);
+ }
+#endif // QT_NO_CONTEXTMENU
}
@@ -771,7 +786,7 @@ void QApplicationPrivate::processWheelEvent(QWindowSystemInterfacePrivate::Wheel
p = mouseWidget->mapFromGlobal(globalPoint);
}
- QWheelEvent ev(p, globalPoint, e->delta, buttons, modifiers,
+ QWheelEvent ev(p, globalPoint, e->delta, buttons, QApplication::keyboardModifiers(),
e->orient);
QApplication::sendSpontaneousEvent(mouseWidget, &ev);
}
@@ -802,9 +817,14 @@ void QApplicationPrivate::processKeyEvent(QWindowSystemInterfacePrivate::KeyEven
if (app_do_modal && !qt_try_modal(focusW, e->keyType))
return;
- modifiers = e->modifiers;
- QKeyEvent ev(e->keyType, e->key, e->modifiers, e->unicode, e->repeat, e->repeatCount);
- QApplication::sendSpontaneousEvent(focusW, &ev);
+ if (e->nativeScanCode || e->nativeVirtualKey || e->nativeModifiers) {
+ QKeyEventEx ev(e->keyType, e->key, e->modifiers, e->unicode, e->repeat, e->repeatCount,
+ e->nativeScanCode, e->nativeVirtualKey, e->nativeModifiers);
+ QApplication::sendSpontaneousEvent(focusW, &ev);
+ } else {
+ QKeyEvent ev(e->keyType, e->key, e->modifiers, e->unicode, e->repeat, e->repeatCount);
+ QApplication::sendSpontaneousEvent(focusW, &ev);
+ }
}
void QApplicationPrivate::processEnterEvent(QWindowSystemInterfacePrivate::EnterEvent *e)
@@ -823,6 +843,10 @@ void QApplicationPrivate::processLeaveEvent(QWindowSystemInterfacePrivate::Leave
}
+void QApplicationPrivate::processActivatedEvent(QWindowSystemInterfacePrivate::ActivatedWindowEvent *e)
+{
+ QApplication::setActiveWindow(e->activated.data());
+}
void QApplicationPrivate::processGeometryChangeEvent(QWindowSystemInterfacePrivate::GeometryChangeEvent *e)
{
diff --git a/src/gui/kernel/qapplication_qws.cpp b/src/gui/kernel/qapplication_qws.cpp
index f0801e3..642d3e6 100644
--- a/src/gui/kernel/qapplication_qws.cpp
+++ b/src/gui/kernel/qapplication_qws.cpp
@@ -204,6 +204,11 @@ QString qws_dataDir()
result = QT_VFB_DATADIR(qws_display_id);
QByteArray dataDir = result.toLocal8Bit();
+#if defined(Q_OS_INTEGRITY)
+ /* ensure filesystem is ready before starting requests */
+ WaitForFileSystemInitialization();
+#endif
+
if (QT_MKDIR(dataDir, 0700)) {
if (errno != EEXIST) {
qFatal("Cannot create Qt for Embedded Linux data directory: %s", dataDir.constData());
diff --git a/src/gui/kernel/qapplication_s60.cpp b/src/gui/kernel/qapplication_s60.cpp
index e791a91..3d642d0 100644
--- a/src/gui/kernel/qapplication_s60.cpp
+++ b/src/gui/kernel/qapplication_s60.cpp
@@ -87,7 +87,7 @@
#include <hal.h>
#include <hal_data.h>
-#ifdef SYMBIAN_GRAPHICS_WSERV_QT_EFFECTS
+#ifdef Q_SYMBIAN_TRANSITION_EFFECTS
#include <graphics/wstfxconst.h>
#endif
@@ -96,6 +96,9 @@ QT_BEGIN_NAMESPACE
// Goom Events through Window Server
static const int KGoomMemoryLowEvent = 0x10282DBF;
static const int KGoomMemoryGoodEvent = 0x20026790;
+// Split view open/close events from AVKON
+static const int KSplitViewOpenEvent = 0x2001E2C0;
+static const int KSplitViewCloseEvent = 0x2001E2C1;
#if defined(QT_DEBUG)
static bool appNoGrab = false; // Grabbing enabled
@@ -401,6 +404,7 @@ QSymbianControl::QSymbianControl(QWidget *w)
, m_longTapDetector(0)
, m_ignoreFocusChanged(0)
, m_symbianPopupIsOpen(0)
+ , m_inExternalScreenOverride(false)
{
}
@@ -408,9 +412,11 @@ void QSymbianControl::ConstructL(bool isWindowOwning, bool desktop)
{
if (!desktop)
{
- if (isWindowOwning || !qwidget->parentWidget())
- CreateWindowL(S60->windowGroup());
- else
+ if (isWindowOwning || !qwidget->parentWidget()
+ || qwidget->parentWidget()->windowType() == Qt::Desktop) {
+ RWindowGroup &wg(S60->windowGroup(qwidget));
+ CreateWindowL(wg);
+ } else {
/**
* TODO: in order to avoid creating windows for all ancestors of
* this widget up to the root window, the parameter passed to
@@ -420,6 +426,7 @@ void QSymbianControl::ConstructL(bool isWindowOwning, bool desktop)
* is created for a widget between this one and the root window.
*/
CreateWindowL(qwidget->parentWidget()->winId());
+ }
// Necessary in order to be able to track the activation status of
// the control's window
@@ -432,7 +439,7 @@ void QSymbianControl::ConstructL(bool isWindowOwning, bool desktop)
DrawableWindow()->SetPointerGrab(ETrue);
}
-#ifdef SYMBIAN_GRAPHICS_WSERV_QT_EFFECTS
+#ifdef Q_SYMBIAN_TRANSITION_EFFECTS
if (OwnsWindow()) {
TTfxWindowPurpose windowPurpose(ETfxPurposeNone);
switch (qwidget->windowType()) {
@@ -452,7 +459,7 @@ void QSymbianControl::ConstructL(bool isWindowOwning, bool desktop)
windowPurpose = ETfxPurposeSplashScreenWindow;
break;
default:
- windowPurpose = (isWindowOwning || !qwidget->parentWidget())
+ windowPurpose = (isWindowOwning || !qwidget->parentWidget() || qwidget->parentWidget()->windowType() == Qt::Desktop)
? ETfxPurposeWindow : ETfxPurposeChildWindow;
break;
}
@@ -983,14 +990,15 @@ TKeyResponse QSymbianControl::handleVirtualMouse(const TKeyEvent& keyEvent,TEven
}
}
//clip to screen size (window server allows a sprite hotspot to be outside the screen)
+ int screenNumber = S60->screenNumberForWidget(qwidget);
if (x < 0)
x = 0;
- else if (x >= S60->screenWidthInPixels)
- x = S60->screenWidthInPixels - 1;
+ else if (x >= S60->screenWidthInPixelsForScreen[screenNumber])
+ x = S60->screenWidthInPixelsForScreen[screenNumber] - 1;
if (y < 0)
y = 0;
- else if (y >= S60->screenHeightInPixels)
- y = S60->screenHeightInPixels - 1;
+ else if (y >= S60->screenHeightInPixelsForScreen[screenNumber])
+ y = S60->screenHeightInPixelsForScreen[screenNumber] - 1;
TPoint epos(x, y);
TPoint cpos = epos - PositionRelativeToScreen();
fakeEvent.iPosition = cpos;
@@ -1124,7 +1132,8 @@ void QSymbianControl::Draw(const TRect& controlRect) const
// Do nothing
break;
case QWExtra::Blit:
- if (qwidget->d_func()->isOpaque)
+ case QWExtra::BlitWriteAlpha:
+ if (qwidget->d_func()->isOpaque || nativePaintMode == QWExtra::BlitWriteAlpha)
gc.SetDrawMode(CGraphicsContext::EDrawModeWriteAlpha);
gc.BitBlt(controlRect.iTl, bitmap, backingStoreRect);
break;
@@ -1167,6 +1176,18 @@ void QSymbianControl::SizeChanged()
QSize newSize(Size().iWidth, Size().iHeight);
if (oldSize != newSize) {
+ const bool isFullscreen = qwidget->windowState() & Qt::WindowFullScreen;
+ const int screenNumber = S60->screenNumberForWidget(qwidget);
+ if (!m_inExternalScreenOverride && isFullscreen && screenNumber > 0) {
+ int screenWidth = S60->screenWidthInPixelsForScreen[screenNumber];
+ int screenHeight = S60->screenHeightInPixelsForScreen[screenNumber];
+ TSize screenSize(screenWidth, screenHeight);
+ if (screenWidth > 0 && screenHeight > 0 && screenSize != Size()) {
+ m_inExternalScreenOverride = true;
+ SetExtent(TPoint(0, 0), screenSize);
+ return;
+ }
+ }
QRect cr = qwidget->geometry();
cr.setSize(newSize);
qwidget->data->crect = cr;
@@ -1189,6 +1210,8 @@ void QSymbianControl::SizeChanged()
}
}
+ m_inExternalScreenOverride = false;
+
// CCoeControl::SetExtent calls SizeChanged, but does not call
// PositionChanged, so we call it here to ensure that the widget's
// position is updated.
@@ -1224,6 +1247,11 @@ void QSymbianControl::FocusChanged(TDrawNow /* aDrawNow */)
if (m_ignoreFocusChanged || (qwidget->windowType() & Qt::WindowType_Mask) == Qt::Desktop)
return;
+#ifdef Q_WS_S60
+ if (S60->splitViewLastWidget)
+ return;
+#endif
+
// Popups never get focused, but still receive the FocusChanged when they are hidden.
if (QApplicationPrivate::popupWidgets != 0
|| (qwidget->windowType() & Qt::Popup) == Qt::Popup)
@@ -1245,12 +1273,14 @@ void QSymbianControl::FocusChanged(TDrawNow /* aDrawNow */)
#ifdef Q_WS_S60
// If widget is fullscreen/minimized, hide status pane and button container otherwise show them.
QWidget *const window = qwidget->window();
- const bool visible = !(window->windowState() & (Qt::WindowFullScreen | Qt::WindowMinimized));
- const bool statusPaneVisibility = visible;
- const bool isFullscreen = window->windowState() & Qt::WindowFullScreen;
- const bool cbaVisibilityHint = window->windowFlags() & Qt::WindowSoftkeysVisibleHint;
- const bool buttonGroupVisibility = (visible || (isFullscreen && cbaVisibilityHint));
- S60->setStatusPaneAndButtonGroupVisibility(statusPaneVisibility, buttonGroupVisibility);
+ if (!window->parentWidget()) { // Only top level native windows have control over cba/status pane
+ const bool decorationsVisible = !(window->windowState() & (Qt::WindowFullScreen | Qt::WindowMinimized));
+ const bool statusPaneVisibility = decorationsVisible;
+ const bool isFullscreen = window->windowState() & Qt::WindowFullScreen;
+ const bool cbaVisibilityHint = window->windowFlags() & Qt::WindowSoftkeysVisibleHint;
+ const bool buttonGroupVisibility = (decorationsVisible || (isFullscreen && cbaVisibilityHint));
+ S60->setStatusPaneAndButtonGroupVisibility(statusPaneVisibility, buttonGroupVisibility);
+ }
#endif
} else if (QApplication::activeWindow() == qwidget->window()) {
bool focusedControlFound = false;
@@ -1300,9 +1330,56 @@ void QSymbianControl::handleClientAreaChange()
}
}
+bool QSymbianControl::isSplitViewWidget(QWidget *widget) {
+ bool returnValue = true;
+ //Ignore events sent to non-active windows, not visible widgets and not parents of input widget.
+ if (!qwidget->isActiveWindow()
+ || !qwidget->isVisible()
+ || !qwidget->isAncestorOf(widget)) {
+
+ returnValue = false;
+ }
+ return returnValue;
+}
+
void QSymbianControl::HandleResourceChange(int resourceType)
{
switch (resourceType) {
+ case KSplitViewCloseEvent: //intentional fall-through
+ case KSplitViewOpenEvent: {
+#if !defined(QT_NO_IM) && defined(Q_WS_S60)
+
+ //Fetch widget getting the text input
+ QWidget *widget = QWidget::keyboardGrabber();
+ if (!widget) {
+ if (QApplicationPrivate::popupWidgets) {
+ widget = QApplication::activePopupWidget()->focusWidget();
+ if (!widget) {
+ widget = QApplication::activePopupWidget();
+ }
+ } else {
+ widget = QApplicationPrivate::focus_widget;
+ if (!widget) {
+ widget = qwidget;
+ }
+ }
+ }
+ if (widget) {
+ QCoeFepInputContext *ic = qobject_cast<QCoeFepInputContext *>(widget->inputContext());
+ if (!ic) {
+ ic = qobject_cast<QCoeFepInputContext *>(qApp->inputContext());
+ }
+ if (ic && isSplitViewWidget(widget)) {
+ if (resourceType == KSplitViewCloseEvent) {
+ ic->resetSplitViewWidget();
+ } else {
+ ic->ensureFocusWidgetVisible(widget);
+ }
+ }
+ }
+#endif // !defined(QT_NO_IM) && defined(Q_WS_S60)
+ }
+ break;
case KInternalStatusPaneChange:
handleClientAreaChange();
if (IsFocused() && IsVisible()) {
@@ -1431,21 +1508,20 @@ void qt_init(QApplicationPrivate * /* priv */, int)
// The S60 framework has not been initialized. We need to do it.
TApaApplicationFactory factory(S60->s60ApplicationFactory ?
S60->s60ApplicationFactory : newS60Application);
- CApaCommandLine* commandLine = 0;
- TInt err = CApaCommandLine::GetCommandLineFromProcessEnvironment(commandLine);
- // After this construction, CEikonEnv will be available from CEikonEnv::Static().
- // (much like our qApp).
- QtEikonEnv* coe = new QtEikonEnv;
- //not using QT_TRAP_THROWING, because coe owns the cleanupstack so it can't be pushed there.
- if(err == KErrNone)
- TRAP(err, coe->ConstructAppFromCommandLineL(factory,*commandLine));
- delete commandLine;
- if(err != KErrNone) {
- qWarning() << "qt_init: Eikon application construct failed ("
- << err
- << "), maybe missing resource file on S60 3.1?";
- delete coe;
- qt_symbian_throwIfError(err);
+ CApaCommandLine* commandLine = q_check_ptr(QCoreApplicationPrivate::symbianCommandLine());
+ if (commandLine) {
+ // After this construction, CEikonEnv will be available from CEikonEnv::Static().
+ // (much like our qApp).
+ QtEikonEnv* coe = new QtEikonEnv;
+ //not using QT_TRAP_THROWING, because coe owns the cleanupstack so it can't be pushed there.
+ TRAPD(err, coe->ConstructAppFromCommandLineL(factory, *commandLine));
+ if(err != KErrNone) {
+ qWarning() << "qt_init: Eikon application construct failed ("
+ << err
+ << "), maybe missing resource file on S60 3.1?";
+ delete coe;
+ qt_symbian_throwIfError(err);
+ }
}
S60->s60InstalledTrapHandler = User::SetTrapHandler(origTrapHandler);
@@ -1546,6 +1622,8 @@ void qt_init(QApplicationPrivate * /* priv */, int)
repository = 0;
#endif
+ qt_keymapper_private()->updateInputLanguage();
+
#ifdef QT_KEYPAD_NAVIGATION
if (touch) {
QApplicationPrivate::navigationMode = Qt::NavigationModeNone;
@@ -1585,10 +1663,36 @@ void qt_init(QApplicationPrivate * /* priv */, int)
systemFont.setFamily(systemFont.defaultFamily());
QApplicationPrivate::setSystemFont(systemFont);
-#ifdef SYMBIAN_GRAPHICS_WSERV_QT_EFFECTS
+#ifdef Q_SYMBIAN_TRANSITION_EFFECTS
QObject::connect(qApp, SIGNAL(aboutToQuit()), qApp, SLOT(_q_aboutToQuit()));
#endif
+#ifdef Q_SYMBIAN_SEMITRANSPARENT_BG_SURFACE
+ QApplicationPrivate::instance()->useTranslucentEGLSurfaces = true;
+
+ const TUid KIvePropertyCat = {0x2726beef};
+ enum TIvePropertyChipType {
+ EVCBCM2727B1 = 0x00000000,
+ EVCBCM2763A0 = 0x04000100,
+ EVCBCM2763B0 = 0x04000102,
+ EVCBCM2763C0 = 0x04000103,
+ EVCBCM2763C1 = 0x04000104,
+ EVCBCMUnknown = 0x7fffffff
+ };
+
+ TInt chipType = EVCBCMUnknown;
+ if (RProperty::Get(KIvePropertyCat, 0 /*chip type*/, chipType) == KErrNone) {
+ if (chipType == EVCBCM2727B1) {
+ // We have only 32MB GPU memory. Use raster surfaces
+ // for transparent TLWs.
+ QApplicationPrivate::instance()->useTranslucentEGLSurfaces = false;
+ }
+ } else {
+ QApplicationPrivate::instance()->useTranslucentEGLSurfaces = false;
+ }
+#else
+ QApplicationPrivate::instance()->useTranslucentEGLSurfaces = false;
+#endif
/*
### Commented out for now as parameter handling not needed in SOS(yet). Code below will break testlib with -o flag
int argc = priv->argc;
@@ -1617,7 +1721,9 @@ void qt_init(QApplicationPrivate * /* priv */, int)
qRegisterMetaType<WId>("WId");
}
-extern void qt_cleanup_symbianFontDatabaseExtras(); // qfontdatabase_s60.cpp
+#ifdef QT_NO_FREETYPE
+extern void qt_cleanup_symbianFontDatabase(); // qfontdatabase_s60.cpp
+#endif
/*****************************************************************************
qt_cleanup() - cleans up when the application is finished
@@ -1634,7 +1740,9 @@ void qt_cleanup()
QFontCache::cleanup(); // Has to happen now, since QFontEngineS60 has FBS handles
QPixmapCache::clear(); // Has to happen now, since QS60PixmapData has FBS handles
- qt_cleanup_symbianFontDatabaseExtras();
+#ifdef QT_NO_FREETYPE
+ qt_cleanup_symbianFontDatabase();
+#endif
// S60 structure and window server session are freed in eventdispatcher destructor as they are needed there
// It's important that this happens here, before the event dispatcher gets
@@ -1688,7 +1796,7 @@ bool QApplicationPrivate::modalState()
void QApplicationPrivate::enterModal_sys(QWidget *widget)
{
-#ifdef SYMBIAN_GRAPHICS_WSERV_QT_EFFECTS
+#ifdef Q_SYMBIAN_TRANSITION_EFFECTS
S60->wsSession().SendEffectCommand(ETfxCmdAppModalModeEnter);
#endif
if (widget) {
@@ -1706,7 +1814,7 @@ void QApplicationPrivate::enterModal_sys(QWidget *widget)
void QApplicationPrivate::leaveModal_sys(QWidget *widget)
{
-#ifdef SYMBIAN_GRAPHICS_WSERV_QT_EFFECTS
+#ifdef Q_SYMBIAN_TRANSITION_EFFECTS
S60->wsSession().SendEffectCommand(ETfxCmdAppModalModeExit);
#endif
if (widget) {
@@ -1981,7 +2089,10 @@ int QApplicationPrivate::symbianProcessWsEvent(const QSymbianEvent *symbianEvent
return 1;
}
break;
- case EEventScreenDeviceChanged:
+ case EEventScreenDeviceChanged: // fallthrough
+#if defined(Q_SYMBIAN_SUPPORTS_MULTIPLE_SCREENS)
+ case EEventDisplayChanged:
+#endif
if (callSymbianEventFilters(symbianEvent))
return 1;
if (S60)
@@ -2020,6 +2131,9 @@ int QApplicationPrivate::symbianProcessWsEvent(const QSymbianEvent *symbianEvent
S60->wsSession().SetPointerCursorMode(EPointerCursorNormal);
}
#endif
+#ifdef QT_SOFTKEYS_ENABLED
+ QSoftKeyManager::updateSoftKeys();
+#endif
break;
case EEventFocusLost:
if (callSymbianEventFilters(symbianEvent))
@@ -2086,6 +2200,13 @@ int QApplicationPrivate::symbianProcessWsEvent(const QSymbianEvent *symbianEvent
}
break;
#endif
+
+#ifdef Q_WS_S60
+ case KEikInputLanguageChange:
+ qt_keymapper_private()->updateInputLanguage();
+ break;
+#endif
+
default:
break;
}
@@ -2384,7 +2505,7 @@ void QApplication::restoreOverrideCursor()
void QApplicationPrivate::_q_aboutToQuit()
{
-#ifdef SYMBIAN_GRAPHICS_WSERV_QT_EFFECTS
+#ifdef Q_SYMBIAN_TRANSITION_EFFECTS
// Send the shutdown tfx command
S60->wsSession().SendEffectCommand(ETfxCmdAppShutDown);
#endif
diff --git a/src/gui/kernel/qapplication_x11.cpp b/src/gui/kernel/qapplication_x11.cpp
index 2c51722..589b12e 100644
--- a/src/gui/kernel/qapplication_x11.cpp
+++ b/src/gui/kernel/qapplication_x11.cpp
@@ -5227,14 +5227,15 @@ bool QETWidget::translateConfigEvent(const XEvent *event)
bool trust = isVisible()
&& (d->topData()->parentWinId == XNone ||
d->topData()->parentWinId == QX11Info::appRootWindow());
+ bool isCPos = false;
if (event->xconfigure.send_event || trust) {
// if a ConfigureNotify comes from a real sendevent request, we can
// trust its values.
newCPos.rx() = event->xconfigure.x + event->xconfigure.border_width;
newCPos.ry() = event->xconfigure.y + event->xconfigure.border_width;
+ isCPos = true;
}
-
if (isVisible())
QApplication::syncX();
@@ -5260,6 +5261,7 @@ bool QETWidget::translateConfigEvent(const XEvent *event)
otherEvent.xconfigure.border_width;
newCPos.ry() = otherEvent.xconfigure.y +
otherEvent.xconfigure.border_width;
+ isCPos = true;
}
}
#ifndef QT_NO_XSYNC
@@ -5272,6 +5274,19 @@ bool QETWidget::translateConfigEvent(const XEvent *event)
#endif // QT_NO_XSYNC
}
+ if (!isCPos) {
+ // we didn't get an updated position of the toplevel.
+ // either we haven't moved or there is a bug in the window manager.
+ // anyway, let's query the position to be certain.
+ int x, y;
+ Window child;
+ XTranslateCoordinates(X11->display, internalWinId(),
+ QApplication::desktop()->screen(d->xinfo.screen())->internalWinId(),
+ 0, 0, &x, &y, &child);
+ newCPos.rx() = x;
+ newCPos.ry() = y;
+ }
+
QRect cr (geometry());
if (newCPos != cr.topLeft()) { // compare with cpos (exluding frame)
QPoint oldPos = geometry().topLeft();
@@ -5314,18 +5329,6 @@ bool QETWidget::translateConfigEvent(const XEvent *event)
}
if (wasResize) {
- static bool slowResize = qgetenv("QT_SLOW_TOPLEVEL_RESIZE").toInt();
- if (d->extra->compress_events && !slowResize && !data->in_show && isVisible()) {
- QApplication::syncX();
- XEvent otherEvent;
- while (XCheckTypedWindowEvent(X11->display, internalWinId(), ConfigureNotify, &otherEvent)
- && !qt_x11EventFilter(&otherEvent) && !x11Event(&otherEvent)
- && otherEvent.xconfigure.event == otherEvent.xconfigure.window) {
- data->crect.setWidth(otherEvent.xconfigure.width);
- data->crect.setHeight(otherEvent.xconfigure.height);
- }
- }
-
if (isVisible() && data->crect.size() != oldSize) {
Q_ASSERT(d->extra->topextra);
QWidgetBackingStore *bs = d->extra->topextra->backingStore.data();
@@ -5334,7 +5337,7 @@ bool QETWidget::translateConfigEvent(const XEvent *event)
// resize optimization in order to get invalidated regions for resized widgets.
// The optimization discards all invalidateBuffer() calls since we're going to
// repaint everything anyways, but that's not the case with static contents.
- if (!slowResize && !hasStaticContents)
+ if (!hasStaticContents)
d->extra->topextra->inTopLevelResize = true;
QResizeEvent e(data->crect.size(), oldSize);
QApplication::sendSpontaneousEvent(this, &e);
@@ -5658,10 +5661,21 @@ static void sm_performSaveYourself(QSessionManagerPrivate* smd)
sm_setProperty(QString::fromLatin1(SmProgram), argument0);
// tell the session manager about our user as well.
struct passwd *entryPtr = 0;
-#if !defined(QT_NO_THREAD) && defined(_POSIX_THREAD_SAFE_FUNCTIONS) && !defined(Q_OS_OPENBSD)
- QVarLengthArray<char, 1024> buf(sysconf(_SC_GETPW_R_SIZE_MAX));
+#if defined(_POSIX_THREAD_SAFE_FUNCTIONS) && (_POSIX_THREAD_SAFE_FUNCTIONS - 0 > 0)
+ QVarLengthArray<char, 1024> buf(qMax<long>(sysconf(_SC_GETPW_R_SIZE_MAX), 1024L));
struct passwd entry;
- getpwuid_r(geteuid(), &entry, buf.data(), buf.size(), &entryPtr);
+ while (getpwuid_r(geteuid(), &entry, buf.data(), buf.size(), &entryPtr) == ERANGE) {
+ if (buf.size() >= 32768) {
+ // too big already, fail
+ static char badusername[] = "";
+ entryPtr = &entry;
+ entry.pw_name = badusername;
+ break;
+ }
+
+ // retry with a bigger buffer
+ buf.resize(buf.size() * 2);
+ }
#else
entryPtr = getpwuid(geteuid());
#endif
diff --git a/src/gui/kernel/qclipboard_qpa.cpp b/src/gui/kernel/qclipboard_qpa.cpp
index 92b9e83..b8ce60e 100644
--- a/src/gui/kernel/qclipboard_qpa.cpp
+++ b/src/gui/kernel/qclipboard_qpa.cpp
@@ -44,73 +44,16 @@
#ifndef QT_NO_CLIPBOARD
#include "qmimedata.h"
-#include "qapplication.h"
+#include "private/qapplication_p.h"
+#include "qplatformclipboard_qpa.h"
QT_BEGIN_NAMESPACE
QT_USE_NAMESPACE
-
-class QClipboardData
-{
-public:
- QClipboardData();
- ~QClipboardData();
-
- void setSource(QMimeData* s)
- {
- if (s == src)
- return;
- delete src;
- src = s;
- }
- QMimeData* source()
- { return src; }
-
- void clear();
-
-private:
- QMimeData* src;
-};
-
-QClipboardData::QClipboardData()
-{
- src = 0;
-}
-
-QClipboardData::~QClipboardData()
-{
- delete src;
-}
-
-void QClipboardData::clear()
-{
- delete src;
- src = 0;
-}
-
-
-static QClipboardData *internalCbData = 0;
-
-static void cleanupClipboardData()
-{
- delete internalCbData;
- internalCbData = 0;
-}
-
-static QClipboardData *clipboardData()
-{
- if (internalCbData == 0) {
- internalCbData = new QClipboardData;
- qAddPostRoutine(cleanupClipboardData);
- }
- return internalCbData;
-}
-
-
void QClipboard::clear(Mode mode)
{
- setText(QString(), mode);
+ setMimeData(0,mode);
}
@@ -121,26 +64,25 @@ bool QClipboard::event(QEvent *e)
const QMimeData* QClipboard::mimeData(Mode mode) const
{
- if (mode != Clipboard) return 0;
-
- QClipboardData *d = clipboardData();
- return d->source();
+ QPlatformClipboard *clipboard = QApplicationPrivate::platformIntegration()->clipboard();
+ if (!clipboard->supportsMode(mode)) return 0;
+ return clipboard->mimeData(mode);
}
void QClipboard::setMimeData(QMimeData* src, Mode mode)
{
- if (mode != Clipboard) return;
-
- QClipboardData *d = clipboardData();
+ QPlatformClipboard *clipboard = QApplicationPrivate::platformIntegration()->clipboard();
+ if (!clipboard->supportsMode(mode)) return;
- d->setSource(src);
+ clipboard->setMimeData(src,mode);
- emitChanged(QClipboard::Clipboard);
+ emitChanged(mode);
}
bool QClipboard::supportsMode(Mode mode) const
{
- return (mode == Clipboard);
+ QPlatformClipboard *clipboard = QApplicationPrivate::platformIntegration()->clipboard();
+ return clipboard->supportsMode(mode);
}
bool QClipboard::ownsMode(Mode mode) const
diff --git a/src/gui/kernel/qclipboard_win.cpp b/src/gui/kernel/qclipboard_win.cpp
index 52b9663..ea41165 100644
--- a/src/gui/kernel/qclipboard_win.cpp
+++ b/src/gui/kernel/qclipboard_win.cpp
@@ -52,6 +52,7 @@
#include "qt_windows.h"
#include "qdnd_p.h"
#include <private/qwidget_p.h>
+#include <private/qsystemlibrary_p.h>
QT_BEGIN_NAMESPACE
@@ -70,6 +71,9 @@ void QtCeFlushClipboard();
#endif
+typedef BOOL (WINAPI *PtrIsHungAppWindow)(HWND);
+
+static PtrIsHungAppWindow ptrIsHungAppWindow = 0;
class QClipboardWatcher : public QInternalMimeData {
public:
@@ -327,9 +331,16 @@ bool QClipboard::event(QEvent *e)
d->releaseIData();
propagate = true;
}
-
if (propagate && d->nextClipboardViewer) {
- SendMessage(d->nextClipboardViewer, m->message, m->wParam, m->lParam);
+ if (ptrIsHungAppWindow == 0) {
+ QSystemLibrary library(QLatin1String("User32"));
+ ptrIsHungAppWindow = (PtrIsHungAppWindow)library.resolve("IsHungAppWindow");
+ }
+ if (ptrIsHungAppWindow && ptrIsHungAppWindow(d->nextClipboardViewer)) {
+ qWarning("%s: Cowardly refusing to send clipboard message to hung application...", Q_FUNC_INFO);
+ } else {
+ SendMessage(d->nextClipboardViewer, m->message, m->wParam, m->lParam);
+ }
}
return true;
diff --git a/src/gui/kernel/qcocoaapplicationdelegate_mac.mm b/src/gui/kernel/qcocoaapplicationdelegate_mac.mm
index bf4d9e5..77cd890 100644
--- a/src/gui/kernel/qcocoaapplicationdelegate_mac.mm
+++ b/src/gui/kernel/qcocoaapplicationdelegate_mac.mm
@@ -90,6 +90,10 @@
QT_BEGIN_NAMESPACE
extern void onApplicationChangedActivation(bool); // qapplication_mac.mm
extern void qt_release_apple_event_handler(); //qapplication_mac.mm
+extern QPointer<QWidget> qt_last_mouse_receiver; // qapplication_mac.cpp
+extern QPointer<QWidget> qt_last_native_mouse_receiver; // qt_cocoa_helpers_mac.mm
+extern QPointer<QWidget> qt_button_down; // qapplication_mac.cpp
+
QT_END_NAMESPACE
QT_FORWARD_DECLARE_CLASS(QDesktopWidgetImplementation)
@@ -254,7 +258,20 @@ static void cleanupCocoaApplicationDelegate()
if (reflectionDelegate
&& [reflectionDelegate respondsToSelector:@selector(applicationDidBecomeActive:)])
[reflectionDelegate applicationDidBecomeActive:notification];
+
onApplicationChangedActivation(true);
+
+ if (!QWidget::mouseGrabber()){
+ // Update enter/leave immidiatly, don't wait for a move event. But only
+ // if no grab exists (even if the grab points to this widget, it seems, ref X11)
+ QPoint qlocal, qglobal;
+ QWidget *widgetUnderMouse = 0;
+ qt_mac_getTargetForMouseEvent(0, QEvent::Enter, qlocal, qglobal, 0, &widgetUnderMouse);
+ QApplicationPrivate::dispatchEnterLeave(widgetUnderMouse, 0);
+ qt_last_mouse_receiver = widgetUnderMouse;
+ qt_last_native_mouse_receiver = widgetUnderMouse ?
+ (widgetUnderMouse->internalWinId() ? widgetUnderMouse : widgetUnderMouse->nativeParentWidget()) : 0;
+ }
}
- (void)applicationDidResignActive:(NSNotification *)notification
@@ -262,7 +279,14 @@ static void cleanupCocoaApplicationDelegate()
if (reflectionDelegate
&& [reflectionDelegate respondsToSelector:@selector(applicationDidResignActive:)])
[reflectionDelegate applicationDidResignActive:notification];
+
onApplicationChangedActivation(false);
+
+ if (!QWidget::mouseGrabber())
+ QApplicationPrivate::dispatchEnterLeave(0, qt_last_mouse_receiver);
+ qt_last_mouse_receiver = 0;
+ qt_last_native_mouse_receiver = 0;
+ qt_button_down = 0;
}
- (void)applicationDidChangeScreenParameters:(NSNotification *)notification
diff --git a/src/gui/kernel/qcocoapanel_mac.mm b/src/gui/kernel/qcocoapanel_mac.mm
index a0f17bc..67a12e2 100644
--- a/src/gui/kernel/qcocoapanel_mac.mm
+++ b/src/gui/kernel/qcocoapanel_mac.mm
@@ -47,9 +47,10 @@
#import <private/qcocoaview_mac_p.h>
#import <private/qcocoawindowcustomthemeframe_mac_p.h>
#import <private/qcocoaapplication_mac_p.h>
-#include <private/qapplication_p.h>
-#include <private/qbackingstore_p.h>
-
+#import <private/qmultitouch_mac_p.h>
+#import <private/qapplication_p.h>
+#import <private/qbackingstore_p.h>
+#import <private/qdnd_p.h>
#include <QtGui/QWidget>
diff --git a/src/gui/kernel/qcocoapanel_mac_p.h b/src/gui/kernel/qcocoapanel_mac_p.h
index e4dd73b..5426159 100644
--- a/src/gui/kernel/qcocoapanel_mac_p.h
+++ b/src/gui/kernel/qcocoapanel_mac_p.h
@@ -50,20 +50,34 @@
// We mean it.
//
+#ifndef QCOCOAPANEL_MAC_P
+#define QCOCOAPANEL_MAC_P
+
#include "qmacdefines_mac.h"
#ifdef QT_MAC_USE_COCOA
#import <Cocoa/Cocoa.h>
QT_FORWARD_DECLARE_CLASS(QStringList);
+QT_FORWARD_DECLARE_CLASS(QCocoaDropData);
+
+@interface NSPanel (QtIntegration)
+- (NSDragOperation)draggingEntered:(id <NSDraggingInfo>)sender;
+- (NSDragOperation)draggingUpdated:(id <NSDraggingInfo>)sender;
+- (void)draggingExited:(id <NSDraggingInfo>)sender;
+- (BOOL)performDragOperation:(id <NSDraggingInfo>)sender;
+@end
@interface QT_MANGLE_NAMESPACE(QCocoaPanel) : NSPanel {
- bool leftButtonIsRightButton;
QStringList *currentCustomDragTypes;
+ QCocoaDropData *dropData;
+ NSInteger dragEnterSequence;
}
+ (Class)frameViewClassForStyleMask:(NSUInteger)styleMask;
- (void)registerDragTypes;
+- (void)drawRectOriginal:(NSRect)rect;
@end
#endif
+#endif
diff --git a/src/gui/kernel/qcocoasharedwindowmethods_mac_p.h b/src/gui/kernel/qcocoasharedwindowmethods_mac_p.h
index df0f24e..7d41f3d 100644
--- a/src/gui/kernel/qcocoasharedwindowmethods_mac_p.h
+++ b/src/gui/kernel/qcocoasharedwindowmethods_mac_p.h
@@ -62,7 +62,6 @@ extern void qt_event_request_window_change(QWidget *); // qapplication_mac.mm
extern void qt_mac_send_posted_gl_updates(QWidget *widget); // qapplication_mac.mm
Q_GLOBAL_STATIC(QPointer<QWidget>, currentDragTarget);
-
QT_END_NAMESPACE
- (id)initWithContentRect:(NSRect)contentRect
@@ -89,6 +88,8 @@ QT_END_NAMESPACE
QWidget *widget = [self QT_MANGLE_NAMESPACE(qt_qwidget)];
if (!widget)
return NO; // This should happen only for qt_root_win
+ if (QApplicationPrivate::isBlockedByModal(widget))
+ return NO;
bool isToolTip = (widget->windowType() == Qt::ToolTip);
bool isPopup = (widget->windowType() == Qt::Popup);
@@ -100,6 +101,8 @@ QT_END_NAMESPACE
QWidget *widget = [self QT_MANGLE_NAMESPACE(qt_qwidget)];
if (!widget)
return NO; // This should happen only for qt_root_win
+ if ([self isSheet])
+ return NO;
bool isToolTip = (widget->windowType() == Qt::ToolTip);
bool isPopup = (widget->windowType() == Qt::Popup);
@@ -145,66 +148,27 @@ QT_END_NAMESPACE
- (void)sendEvent:(NSEvent *)event
{
- QWidget *widget = [[QT_MANGLE_NAMESPACE(QCocoaWindowDelegate) sharedDelegate] qt_qwidgetForWindow:self];
- // Cocoa can hold onto the window after we've disavowed its knowledge. So,
- // if we get sent an event afterwards just have it go through the super's
- // version and don't do any stuff with Qt.
- if (!widget) {
- [super sendEvent:event];
- return;
- }
-
[self retain];
- QT_MANGLE_NAMESPACE(QCocoaView) *view = static_cast<QT_MANGLE_NAMESPACE(QCocoaView) *>(qt_mac_nativeview_for(widget));
- Qt::MouseButton mouseButton = cocoaButton2QtButton([event buttonNumber]);
bool handled = false;
- // sometimes need to redirect mouse events to the popup.
- QWidget *popup = qAppInstance()->activePopupWidget();
- if (popup && popup != widget) {
- switch([event type])
- {
- case NSLeftMouseDown:
- if (!qt_button_down)
- qt_button_down = widget;
- handled = qt_mac_handleMouseEvent(view, event, QEvent::MouseButtonPress, mouseButton);
- // Don't call super here. This prevents us from getting the mouseUp event,
- // which we need to send even if the mouseDown event was not accepted.
- // (this is standard Qt behavior.)
- break;
- case NSRightMouseDown:
- case NSOtherMouseDown:
- if (!qt_button_down)
- qt_button_down = widget;
- handled = qt_mac_handleMouseEvent(view, event, QEvent::MouseButtonPress, mouseButton);
- break;
- case NSLeftMouseUp:
- case NSRightMouseUp:
- case NSOtherMouseUp:
- handled = qt_mac_handleMouseEvent(view, event, QEvent::MouseButtonRelease, mouseButton);
- qt_button_down = 0;
- break;
- case NSMouseMoved:
- handled = qt_mac_handleMouseEvent(view, event, QEvent::MouseMove, Qt::NoButton);
- break;
- case NSLeftMouseDragged:
- case NSRightMouseDragged:
- case NSOtherMouseDragged:
- [QT_MANGLE_NAMESPACE(QCocoaView) currentMouseEvent]->view = view;
- [QT_MANGLE_NAMESPACE(QCocoaView) currentMouseEvent]->theEvent = event;
- handled = qt_mac_handleMouseEvent(view, event, QEvent::MouseMove, mouseButton);
- break;
- default:
- [super sendEvent:event];
- break;
- }
- } else {
- [super sendEvent:event];
+ switch([event type]) {
+ case NSMouseMoved:
+ // Cocoa sends move events to a parent and all its children under the mouse, much
+ // like Qt handles hover events. But we only want to handle the move event once, so
+ // to optimize a bit (since we subscribe for move event for all views), we handle it
+ // here before this logic happends. Note: it might be tempting to do this shortcut for
+ // all mouse events. The problem is that Cocoa does more than just find the correct view
+ // when sending the event, like raising windows etc. So avoid it as much as possible:
+ handled = qt_mac_handleMouseEvent(event, QEvent::MouseMove, Qt::NoButton, 0);
+ break;
+ default:
+ break;
}
- if (!handled)
- qt_mac_dispatchNCMouseMessage(self, event, [self QT_MANGLE_NAMESPACE(qt_qwidget)], leftButtonIsRightButton);
-
+ if (!handled) {
+ [super sendEvent:event];
+ qt_mac_handleNonClientAreaMouseEvent(self, event);
+ }
[self release];
}
@@ -237,6 +201,56 @@ QT_END_NAMESPACE
return [super frameViewClassForStyleMask:styleMask];
}
+#if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_6
+- (void)touchesBeganWithEvent:(NSEvent *)event;
+{
+ QPoint qlocal, qglobal;
+ QWidget *widgetToGetTouch = 0;
+ qt_mac_getTargetForMouseEvent(event, QEvent::Gesture, qlocal, qglobal, 0, &widgetToGetTouch);
+ if (!widgetToGetTouch)
+ return;
+
+ bool all = widgetToGetTouch->testAttribute(Qt::WA_TouchPadAcceptSingleTouchEvents);
+ qt_translateRawTouchEvent(widgetToGetTouch, QTouchEvent::TouchPad, QCocoaTouch::getCurrentTouchPointList(event, all));
+}
+
+- (void)touchesMovedWithEvent:(NSEvent *)event;
+{
+ QPoint qlocal, qglobal;
+ QWidget *widgetToGetTouch = 0;
+ qt_mac_getTargetForMouseEvent(event, QEvent::Gesture, qlocal, qglobal, 0, &widgetToGetTouch);
+ if (!widgetToGetTouch)
+ return;
+
+ bool all = widgetToGetTouch->testAttribute(Qt::WA_TouchPadAcceptSingleTouchEvents);
+ qt_translateRawTouchEvent(widgetToGetTouch, QTouchEvent::TouchPad, QCocoaTouch::getCurrentTouchPointList(event, all));
+}
+
+- (void)touchesEndedWithEvent:(NSEvent *)event;
+{
+ QPoint qlocal, qglobal;
+ QWidget *widgetToGetTouch = 0;
+ qt_mac_getTargetForMouseEvent(event, QEvent::Gesture, qlocal, qglobal, 0, &widgetToGetTouch);
+ if (!widgetToGetTouch)
+ return;
+
+ bool all = widgetToGetTouch->testAttribute(Qt::WA_TouchPadAcceptSingleTouchEvents);
+ qt_translateRawTouchEvent(widgetToGetTouch, QTouchEvent::TouchPad, QCocoaTouch::getCurrentTouchPointList(event, all));
+}
+
+- (void)touchesCancelledWithEvent:(NSEvent *)event;
+{
+ QPoint qlocal, qglobal;
+ QWidget *widgetToGetTouch = 0;
+ qt_mac_getTargetForMouseEvent(event, QEvent::Gesture, qlocal, qglobal, 0, &widgetToGetTouch);
+ if (!widgetToGetTouch)
+ return;
+
+ bool all = widgetToGetTouch->testAttribute(Qt::WA_TouchPadAcceptSingleTouchEvents);
+ qt_translateRawTouchEvent(widgetToGetTouch, QTouchEvent::TouchPad, QCocoaTouch::getCurrentTouchPointList(event, all));
+}
+#endif // MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_6
+
-(void)registerDragTypes
{
// Calling registerForDraggedTypes below is slow, so only do
@@ -259,21 +273,47 @@ QT_END_NAMESPACE
NSMultipleTextSelectionPboardType, mimeTypeGeneric, nil];
// Add custom types supported by the application.
for (int i = 0; i < customTypes.size(); i++) {
- [supportedTypes addObject:reinterpret_cast<const NSString *>(QCFString::toCFStringRef(customTypes[i]))];
+ [supportedTypes addObject:qt_mac_QStringToNSString(customTypes[i])];
}
[self registerForDraggedTypes:supportedTypes];
}
}
-- (QWidget *)dragTargetHitTest:(id <NSDraggingInfo>)sender
+- (void)removeDropData
+{
+ if (dropData) {
+ delete dropData;
+ dropData = 0;
+ }
+}
+
+- (void)addDropData:(id <NSDraggingInfo>)sender
+{
+ [self removeDropData];
+ CFStringRef dropPasteboard = (CFStringRef) [[sender draggingPasteboard] name];
+ dropData = new QCocoaDropData(dropPasteboard);
+}
+
+- (void)changeDraggingCursor:(NSDragOperation)newOperation
{
- // Do a hittest to find the NSView under the
- // mouse, and return the corresponding QWidget:
- NSPoint windowPoint = [sender draggingLocation];
- NSView *candidateView = [[self contentView] hitTest:windowPoint];
- if (![candidateView isKindOfClass:[QT_MANGLE_NAMESPACE(QCocoaView) class]])
- return 0;
- return [static_cast<QT_MANGLE_NAMESPACE(QCocoaView) *>(candidateView) qt_qwidget];
+ static SEL action = nil;
+ static bool operationSupported = false;
+ if (action == nil) {
+ action = NSSelectorFromString(@"operationNotAllowedCursor");
+ if ([NSCursor respondsToSelector:action]) {
+ operationSupported = true;
+ }
+ }
+ if (operationSupported) {
+ NSCursor *notAllowedCursor = [NSCursor performSelector:action];
+ bool isNotAllowedCursor = ([NSCursor currentCursor] == notAllowedCursor);
+ if (newOperation == NSDragOperationNone && !isNotAllowedCursor) {
+ [notAllowedCursor push];
+ } else if (newOperation != NSDragOperationNone && isNotAllowedCursor) {
+ [notAllowedCursor pop];
+ }
+
+ }
}
- (NSDragOperation)draggingEntered:(id <NSDraggingInfo>)sender
@@ -286,80 +326,211 @@ QT_END_NAMESPACE
// registerForDraggedTypes on the views will severly degrade initialization time
// for an application that uses a lot of drag subscribing widgets.
- QWidget *target = [self dragTargetHitTest:sender];
- if (!target)
+ NSPoint nswindowPoint = [sender draggingLocation];
+ NSPoint nsglobalPoint = [[sender draggingDestinationWindow] convertBaseToScreen:nswindowPoint];
+ QPoint globalPoint = flipPoint(nsglobalPoint).toPoint();
+
+ QWidget *qwidget = QApplication::widgetAt(globalPoint);
+ *currentDragTarget() = qwidget;
+ if (!qwidget)
return [super draggingEntered:sender];
- if (target->testAttribute(Qt::WA_DropSiteRegistered) == false)
+ if (qwidget->testAttribute(Qt::WA_DropSiteRegistered) == false)
return NSDragOperationNone;
- *currentDragTarget() = target;
- return [reinterpret_cast<NSView *>((*currentDragTarget())->winId()) draggingEntered:sender];
- }
+ [self addDropData:sender];
-- (NSDragOperation)draggingUpdated:(id < NSDraggingInfo >)sender
-{
- QWidget *target = [self dragTargetHitTest:sender];
- if (!target)
- return [super draggingUpdated:sender];
-
- if (target == *currentDragTarget()) {
- // The drag continues to move over the widget that we have sendt
- // a draggingEntered message to. So just update the view:
- return [reinterpret_cast<NSView *>((*currentDragTarget())->winId()) draggingUpdated:sender];
+ QMimeData *mimeData = dropData;
+ if (QDragManager::self()->source())
+ mimeData = QDragManager::self()->dragPrivate()->data;
+
+ NSDragOperation nsActions = [sender draggingSourceOperationMask];
+ Qt::DropActions qtAllowed = qt_mac_mapNSDragOperations(nsActions);
+ QT_PREPEND_NAMESPACE(qt_mac_dnd_answer_rec.lastOperation) = nsActions;
+ Qt::KeyboardModifiers modifiers = Qt::NoModifier;
+
+ if ([sender draggingSource] != nil) {
+ // modifier flags might have changed, update it here since we don't send any input events.
+ QApplicationPrivate::modifier_buttons = qt_cocoaModifiers2QtModifiers([[NSApp currentEvent] modifierFlags]);
+ modifiers = QApplication::keyboardModifiers();
+ } else {
+ // when the source is from another application the above technique will not work.
+ modifiers = qt_cocoaDragOperation2QtModifiers(nsActions);
+ }
+
+ // send the drag enter event to the widget.
+ QPoint localPoint(qwidget->mapFromGlobal(globalPoint));
+ QDragEnterEvent qDEEvent(localPoint, qtAllowed, mimeData, QApplication::mouseButtons(), modifiers);
+ QApplication::sendEvent(qwidget, &qDEEvent);
+
+ if (!qDEEvent.isAccepted()) {
+ // The enter event was not accepted. We mark this by removing
+ // the drop data so we don't send subsequent drag move events:
+ [self removeDropData];
+ [self changeDraggingCursor:NSDragOperationNone];
+ return NSDragOperationNone;
} else {
- // The widget under the mouse has changed.
- // So we need to fake enter/leave events:
- if (*currentDragTarget())
- [reinterpret_cast<NSView *>((*currentDragTarget())->winId()) draggingExited:sender];
- if (target->testAttribute(Qt::WA_DropSiteRegistered) == false) {
- *currentDragTarget() = 0;
- return NSDragOperationNone;
+ // Send a drag move event immediately after a drag enter event (as per documentation).
+ QDragMoveEvent qDMEvent(localPoint, qtAllowed, mimeData, QApplication::mouseButtons(), modifiers);
+ qDMEvent.setDropAction(qDEEvent.dropAction());
+ qDMEvent.accept(); // accept by default, since enter event was accepted.
+ QApplication::sendEvent(qwidget, &qDMEvent);
+
+ if (!qDMEvent.isAccepted() || qDMEvent.dropAction() == Qt::IgnoreAction) {
+ // Since we accepted the drag enter event, the widget expects
+ // future drage move events.
+ nsActions = NSDragOperationNone;
+ // Save as ignored in the answer rect.
+ qDMEvent.setDropAction(Qt::IgnoreAction);
+ } else {
+ nsActions = QT_PREPEND_NAMESPACE(qt_mac_mapDropAction)(qDMEvent.dropAction());
}
- *currentDragTarget() = target;
- return [reinterpret_cast<NSView *>((*currentDragTarget())->winId()) draggingEntered:sender];
+
+ QT_PREPEND_NAMESPACE(qt_mac_copy_answer_rect)(qDMEvent);
+ [self changeDraggingCursor:nsActions];
+ return nsActions;
}
-}
+ }
-- (void)draggingExited:(id < NSDraggingInfo >)sender
+- (NSDragOperation)draggingUpdated:(id <NSDraggingInfo>)sender
{
- QWidget *target = [self dragTargetHitTest:sender];
- if (!target)
- return [super draggingExited:sender];
+ NSPoint nswindowPoint = [sender draggingLocation];
+ NSPoint nsglobalPoint = [[sender draggingDestinationWindow] convertBaseToScreen:nswindowPoint];
+ QPoint globalPoint = flipPoint(nsglobalPoint).toPoint();
+
+ QWidget *qwidget = QApplication::widgetAt(globalPoint);
+ if (!qwidget)
+ return [super draggingEntered:sender];
+
+ // First, check if the widget under the mouse has changed since the
+ // last drag move events. If so, we need to change target, and dispatch
+ // syntetic drag enter/leave events:
+ if (qwidget != *currentDragTarget()) {
+ if (*currentDragTarget() && dropData) {
+ QDragLeaveEvent de;
+ QApplication::sendEvent(*currentDragTarget(), &de);
+ [self removeDropData];
+ }
+ return [self draggingEntered:sender];
+ }
+
+ if (qwidget->testAttribute(Qt::WA_DropSiteRegistered) == false)
+ return NSDragOperationNone;
+
+ // If we have no drop data (which will be assigned inside draggingEntered), it means
+ // that the current drag target did not accept the enter event. If so, we ignore
+ // subsequent move events as well:
+ if (dropData == 0) {
+ [self changeDraggingCursor:NSDragOperationNone];
+ return NSDragOperationNone;
+ }
+
+ // If the mouse is still within the accepted rect (provided by
+ // the application on a previous event), we follow the optimization
+ // and just return the answer given at that point:
+ NSDragOperation nsActions = [sender draggingSourceOperationMask];
+ QPoint localPoint(qwidget->mapFromGlobal(globalPoint));
+ if (qt_mac_mouse_inside_answer_rect(localPoint)
+ && QT_PREPEND_NAMESPACE(qt_mac_dnd_answer_rec.lastOperation) == nsActions) {
+ NSDragOperation operation = QT_PREPEND_NAMESPACE(qt_mac_mapDropActions)(QT_PREPEND_NAMESPACE(qt_mac_dnd_answer_rec.lastAction));
+ [self changeDraggingCursor:operation];
+ return operation;
+ }
- if (*currentDragTarget()) {
- [reinterpret_cast<NSView *>((*currentDragTarget())->winId()) draggingExited:sender];
- *currentDragTarget() = 0;
+ QT_PREPEND_NAMESPACE(qt_mac_dnd_answer_rec.lastOperation) = nsActions;
+ Qt::DropActions qtAllowed = QT_PREPEND_NAMESPACE(qt_mac_mapNSDragOperations)(nsActions);
+ Qt::KeyboardModifiers modifiers = Qt::NoModifier;
+
+ // Update modifiers:
+ if ([sender draggingSource] != nil) {
+ QApplicationPrivate::modifier_buttons = qt_cocoaModifiers2QtModifiers([[NSApp currentEvent] modifierFlags]);
+ modifiers = QApplication::keyboardModifiers();
+ } else {
+ modifiers = qt_cocoaDragOperation2QtModifiers(nsActions);
+ }
+
+ QMimeData *mimeData = dropData;
+ if (QDragManager::self()->source())
+ mimeData = QDragManager::self()->dragPrivate()->data;
+
+ // Insert the same drop action on the event according to
+ // what the application told us it should be on the previous event:
+ QDragMoveEvent qDMEvent(localPoint, qtAllowed, mimeData, QApplication::mouseButtons(), modifiers);
+ if (QT_PREPEND_NAMESPACE(qt_mac_dnd_answer_rec).lastAction != Qt::IgnoreAction
+ && QT_PREPEND_NAMESPACE(qt_mac_dnd_answer_rec).buttons == qDMEvent.mouseButtons()
+ && QT_PREPEND_NAMESPACE(qt_mac_dnd_answer_rec).modifiers == qDMEvent.keyboardModifiers())
+ qDMEvent.setDropAction(QT_PREPEND_NAMESPACE(qt_mac_dnd_answer_rec).lastAction);
+
+ // Now, end the drag move event to the widget:
+ qDMEvent.accept();
+ QApplication::sendEvent(qwidget, &qDMEvent);
+
+ NSDragOperation operation = qt_mac_mapDropAction(qDMEvent.dropAction());
+ if (!qDMEvent.isAccepted() || qDMEvent.dropAction() == Qt::IgnoreAction) {
+ // Ignore this event (we will still receive further
+ // notifications), save as ignored in the answer rect:
+ operation = NSDragOperationNone;
+ qDMEvent.setDropAction(Qt::IgnoreAction);
}
+
+ qt_mac_copy_answer_rect(qDMEvent);
+ [self changeDraggingCursor:operation];
+
+ return operation;
}
-- (BOOL)performDragOperation:(id < NSDraggingInfo >)sender
+- (void)draggingExited:(id <NSDraggingInfo>)sender
{
- QWidget *target = [self dragTargetHitTest:sender];
- if (!target)
- return [super performDragOperation:sender];
-
- BOOL dropResult = NO;
- if (*currentDragTarget()) {
- dropResult = [reinterpret_cast<NSView *>((*currentDragTarget())->winId()) performDragOperation:sender];
- *currentDragTarget() = 0;
+ NSPoint nswindowPoint = [sender draggingLocation];
+ NSPoint nsglobalPoint = [[sender draggingDestinationWindow] convertBaseToScreen:nswindowPoint];
+ QPoint globalPoint = flipPoint(nsglobalPoint).toPoint();
+
+ QWidget *qwidget = *currentDragTarget();
+ if (!qwidget)
+ return [super draggingExited:sender];
+
+ if (dropData) {
+ QDragLeaveEvent de;
+ QApplication::sendEvent(qwidget, &de);
+ [self removeDropData];
}
- return dropResult;
+
+ // Clean-up:
+ [self removeDropData];
+ *currentDragTarget() = 0;
+ [self changeDraggingCursor:NSDragOperationEvery];
}
-- (void)displayIfNeeded
+- (BOOL)performDragOperation:(id <NSDraggingInfo>)sender
{
+ QWidget *qwidget = *currentDragTarget();
+ if (!qwidget)
+ return NO;
- QWidget *qwidget = [[QT_MANGLE_NAMESPACE(QCocoaWindowDelegate) sharedDelegate] qt_qwidgetForWindow:self];
- if (qwidget == 0) {
- [super displayIfNeeded];
- return;
- }
+ *currentDragTarget() = 0;
+ NSPoint nswindowPoint = [sender draggingLocation];
+ NSPoint nsglobalPoint = [[sender draggingDestinationWindow] convertBaseToScreen:nswindowPoint];
+ QPoint globalPoint = flipPoint(nsglobalPoint).toPoint();
- if (QApplicationPrivate::graphicsSystem() != 0) {
- if (QWidgetBackingStore *bs = qt_widget_private(qwidget)->maybeBackingStore())
- bs->sync(qwidget, qwidget->rect());
- }
- [super displayIfNeeded];
+ [self addDropData:sender];
+
+ NSDragOperation nsActions = [sender draggingSourceOperationMask];
+ Qt::DropActions qtAllowed = qt_mac_mapNSDragOperations(nsActions);
+ QMimeData *mimeData = dropData;
+
+ if (QDragManager::self()->source())
+ mimeData = QDragManager::self()->dragPrivate()->data;
+ if (QDragManager::self()->object)
+ QDragManager::self()->dragPrivate()->target = qwidget;
+
+ QPoint localPoint(qwidget->mapFromGlobal(globalPoint));
+ QDropEvent de(localPoint, qtAllowed, mimeData,
+ QApplication::mouseButtons(), QApplication::keyboardModifiers());
+ QApplication::sendEvent(qwidget, &de);
+
+ if (QDragManager::self()->object)
+ QDragManager::self()->dragPrivate()->executed_action = de.dropAction();
+
+ return de.isAccepted();
}
// This is a hack and it should be removed once we find the real cause for
@@ -394,8 +565,8 @@ static bool firstDrawingInvocation = true;
- (void)drawRectSpecial:(NSRect)rect
{
// Call the original drawing method.
- [self drawRectOriginal:rect];
- NSWindow *window = [self window];
+ [id(self) drawRectOriginal:rect];
+ NSWindow *window = [id(self) window];
NSToolbar *toolbar = [window toolbar];
if(!toolbar) {
// There is no toolbar, we have to draw a line on top of the line drawn by Cocoa.
@@ -415,3 +586,11 @@ static bool firstDrawingInvocation = true;
}
}
}
+
+- (void)drawRectOriginal:(NSRect)rect
+{
+ Q_UNUSED(rect)
+ // This method implementation is here to silenct the compiler.
+ // See drawRectSpecial for information.
+}
+
diff --git a/src/gui/kernel/qcocoaview_mac.mm b/src/gui/kernel/qcocoaview_mac.mm
index 5ea893c..54e7e3e 100644
--- a/src/gui/kernel/qcocoaview_mac.mm
+++ b/src/gui/kernel/qcocoaview_mac.mm
@@ -49,9 +49,10 @@
#include <private/qt_cocoa_helpers_mac_p.h>
#include <private/qdnd_p.h>
#include <private/qmacinputcontext_p.h>
-#include <private/qmultitouch_mac_p.h>
#include <private/qevent_p.h>
#include <private/qbackingstore_p.h>
+#include <private/qwindowsurface_raster_p.h>
+#include <private/qunifiedtoolbarsurface_mac_p.h>
#include <qscrollarea.h>
#include <qhash.h>
@@ -76,70 +77,16 @@
QT_BEGIN_NAMESPACE
-Q_GLOBAL_STATIC(DnDParams, qMacDnDParams);
-
-extern void qt_mac_update_cursor_at_global_pos(const QPoint &globalPos); // qcursor_mac.mm
+extern void qt_mac_update_cursor(); // qcursor_mac.mm
extern bool qt_sendSpontaneousEvent(QObject *, QEvent *); // qapplication.cpp
+extern QPointer<QWidget> qt_last_mouse_receiver; // qapplication_mac.cpp
+extern QPointer<QWidget> qt_last_native_mouse_receiver; // qt_cocoa_helpers_mac.mm
extern OSViewRef qt_mac_nativeview_for(const QWidget *w); // qwidget_mac.mm
-extern QPointer<QWidget> qt_mouseover; //qapplication_mac.mm
+extern OSViewRef qt_mac_effectiveview_for(const QWidget *w); // qwidget_mac.mm
extern QPointer<QWidget> qt_button_down; //qapplication_mac.cpp
extern Qt::MouseButton cocoaButton2QtButton(NSInteger buttonNum);
-
-struct dndenum_mapper
-{
- NSDragOperation mac_code;
- Qt::DropAction qt_code;
- bool Qt2Mac;
-};
-
-static dndenum_mapper dnd_enums[] = {
- { NSDragOperationLink, Qt::LinkAction, true },
- { NSDragOperationMove, Qt::MoveAction, true },
- { NSDragOperationCopy, Qt::CopyAction, true },
- { NSDragOperationGeneric, Qt::CopyAction, false },
- { NSDragOperationEvery, Qt::ActionMask, false },
- { NSDragOperationNone, Qt::IgnoreAction, false }
-};
-
-static NSDragOperation qt_mac_mapDropAction(Qt::DropAction action)
-{
- for (int i=0; dnd_enums[i].qt_code; i++) {
- if (dnd_enums[i].Qt2Mac && (action & dnd_enums[i].qt_code)) {
- return dnd_enums[i].mac_code;
- }
- }
- return NSDragOperationNone;
-}
-
-static NSDragOperation qt_mac_mapDropActions(Qt::DropActions actions)
-{
- NSDragOperation nsActions = NSDragOperationNone;
- for (int i=0; dnd_enums[i].qt_code; i++) {
- if (dnd_enums[i].Qt2Mac && (actions & dnd_enums[i].qt_code))
- nsActions |= dnd_enums[i].mac_code;
- }
- return nsActions;
-}
-
-static Qt::DropAction qt_mac_mapNSDragOperation(NSDragOperation nsActions)
-{
- Qt::DropAction action = Qt::IgnoreAction;
- for (int i=0; dnd_enums[i].mac_code; i++) {
- if (nsActions & dnd_enums[i].mac_code)
- return dnd_enums[i].qt_code;
- }
- return action;
-}
-
-static Qt::DropActions qt_mac_mapNSDragOperations(NSDragOperation nsActions)
-{
- Qt::DropActions actions = Qt::IgnoreAction;
- for (int i=0; dnd_enums[i].mac_code; i++) {
- if (nsActions & dnd_enums[i].mac_code)
- actions |= dnd_enums[i].qt_code;
- }
- return actions;
-}
+extern QWidget *mac_mouse_grabber;
+extern bool qt_mac_clearDirtyOnWidgetInsideDrawWidget; // qwidget.cpp
static QColor colorFrom(NSColor *color)
{
@@ -185,6 +132,7 @@ extern "C" {
extern NSString *NSTextInputReplacementRangeAttributeName;
}
+//#define ALIEN_DEBUG 1
#ifdef ALIEN_DEBUG
static int qCocoaViewCount = 0;
#endif
@@ -202,12 +150,14 @@ static int qCocoaViewCount = 0;
#ifdef ALIEN_DEBUG
++qCocoaViewCount;
- qDebug() << "init: qCocoaViewCount is" << qCocoaViewCount;
+ qDebug() << "Alien: create native view for" << widget << ". qCocoaViewCount is:" << qCocoaViewCount;
#endif
composing = false;
sendKeyEvents = true;
fromKeyDownEvent = false;
+ alienTouchCount = 0;
+
[self setHidden:YES];
return self;
}
@@ -222,246 +172,15 @@ static int qCocoaViewCount = 0;
object:self];
}
-- (void)resetCursorRects
-{
- // [NSView addCursorRect] is slow, so bail out early if we can:
- if (NSIsEmptyRect([self visibleRect]))
- return;
-
- QWidget *cursorWidget = qwidget;
-
- if (cursorWidget->testAttribute(Qt::WA_TransparentForMouseEvents))
- cursorWidget = QApplication::widgetAt(qwidget->mapToGlobal(qwidget->rect().center()));
-
- if (cursorWidget == 0)
- return;
-
- if (!cursorWidget->testAttribute(Qt::WA_SetCursor)) {
- [super resetCursorRects];
- return;
- }
-
- QRegion mask = qt_widget_private(cursorWidget)->extra->mask;
- NSCursor *nscursor = static_cast<NSCursor *>(qt_mac_nsCursorForQCursor(cursorWidget->cursor()));
- // The mask could have the WA_MouseNoMask attribute set and that means that we have to ignore the mask.
- if (mask.isEmpty() || cursorWidget->testAttribute(Qt::WA_MouseNoMask)) {
- [self addCursorRect:[qt_mac_nativeview_for(cursorWidget) visibleRect] cursor:nscursor];
- } else {
- const QVector<QRect> &rects = mask.rects();
- for (int i = 0; i < rects.size(); ++i) {
- const QRect &rect = rects.at(i);
- [self addCursorRect:NSMakeRect(rect.x(), rect.y(), rect.width(), rect.height()) cursor:nscursor];
- }
- }
-}
-
-- (void)removeDropData
-{
- if (dropData) {
- delete dropData;
- dropData = 0;
- }
-}
-
-- (void)addDropData:(id <NSDraggingInfo>)sender
-{
- [self removeDropData];
- CFStringRef dropPasteboard = (CFStringRef) [[sender draggingPasteboard] name];
- dropData = new QCocoaDropData(dropPasteboard);
-}
-
-- (void)changeDraggingCursor:(NSDragOperation)newOperation
-{
- static SEL action = nil;
- static bool operationSupported = false;
- if (action == nil) {
- action = NSSelectorFromString(@"operationNotAllowedCursor");
- if ([NSCursor respondsToSelector:action]) {
- operationSupported = true;
- }
- }
- if (operationSupported) {
- NSCursor *notAllowedCursor = [NSCursor performSelector:action];
- bool isNotAllowedCursor = ([NSCursor currentCursor] == notAllowedCursor);
- if (newOperation == NSDragOperationNone && !isNotAllowedCursor) {
- [notAllowedCursor push];
- } else if (newOperation != NSDragOperationNone && isNotAllowedCursor) {
- [notAllowedCursor pop];
- }
-
- }
-}
-
-- (NSDragOperation)draggingEntered:(id <NSDraggingInfo>)sender
-{
- // NB: This function is called from QCoocaWindow/QCocoaPanel rather than directly
- // from Cocoa. They modify the drag target, and might fake enter/leave events.
- NSPoint windowPoint = [sender draggingLocation];
- dragEnterSequence = [sender draggingSequenceNumber];
- [self addDropData:sender];
- QMimeData *mimeData = dropData;
- if (QDragManager::self()->source())
- mimeData = QDragManager::self()->dragPrivate()->data;
- NSPoint localPoint = [self convertPoint:windowPoint fromView:nil];
- QPoint posDrag(localPoint.x, localPoint.y);
- NSDragOperation nsActions = [sender draggingSourceOperationMask];
- Qt::DropActions qtAllowed = qt_mac_mapNSDragOperations(nsActions);
- QT_PREPEND_NAMESPACE(qt_mac_dnd_answer_rec.lastOperation) = nsActions;
- Qt::KeyboardModifiers modifiers = Qt::NoModifier;
- if ([sender draggingSource] != nil) {
- // modifier flags might have changed, update it here since we don't send any input events.
- QApplicationPrivate::modifier_buttons = qt_cocoaModifiers2QtModifiers([[NSApp currentEvent] modifierFlags]);
- modifiers = QApplication::keyboardModifiers();
- } else {
- // when the source is from another application the above technique will not work.
- modifiers = qt_cocoaDragOperation2QtModifiers(nsActions);
- }
- // send the drag enter event to the widget.
- QDragEnterEvent qDEEvent(posDrag, qtAllowed, mimeData, QApplication::mouseButtons(), modifiers);
- QApplication::sendEvent(qwidget, &qDEEvent);
- if (!qDEEvent.isAccepted()) {
- // widget is not interested in this drag, so ignore this drop data.
- [self removeDropData];
- [self changeDraggingCursor:NSDragOperationNone];
- return NSDragOperationNone;
- } else {
- // save the mouse position, used by draggingExited handler.
- DnDParams *dndParams = [QT_MANGLE_NAMESPACE(QCocoaView) currentMouseEvent];
- dndParams->activeDragEnterPos = windowPoint;
- // send a drag move event immediately after a drag enter event (as per documentation).
- QDragMoveEvent qDMEvent(posDrag, qtAllowed, mimeData, QApplication::mouseButtons(), modifiers);
- qDMEvent.setDropAction(qDEEvent.dropAction());
- qDMEvent.accept(); // accept by default, since enter event was accepted.
- QApplication::sendEvent(qwidget, &qDMEvent);
- if (!qDMEvent.isAccepted() || qDMEvent.dropAction() == Qt::IgnoreAction) {
- // since we accepted the drag enter event, the widget expects
- // future drage move events.
- // ### check if we need to treat this like the drag enter event.
- nsActions = NSDragOperationNone;
- // Save as ignored in the answer rect.
- qDMEvent.setDropAction(Qt::IgnoreAction);
- } else {
- nsActions = QT_PREPEND_NAMESPACE(qt_mac_mapDropAction)(qDMEvent.dropAction());
- }
- QT_PREPEND_NAMESPACE(qt_mac_copy_answer_rect)(qDMEvent);
- [self changeDraggingCursor:nsActions];
- return nsActions;
- }
- }
-- (NSDragOperation)draggingUpdated:(id < NSDraggingInfo >)sender
-{
- // NB: This function is called from QCoocaWindow/QCocoaPanel rather than directly
- // from Cocoa. They modify the drag target, and might fake enter/leave events.
- NSPoint windowPoint = [sender draggingLocation];
- // in cases like QFocusFrame, the view under the mouse might
- // not have received the drag enter. Generate a synthetic
- // drag enter event for that view.
- if (dragEnterSequence != [sender draggingSequenceNumber])
- [self draggingEntered:sender];
- // drag enter event was rejected, so ignore the move event.
- if (dropData == 0) {
- [self changeDraggingCursor:NSDragOperationNone];
- return NSDragOperationNone;
- }
- // return last value, if we are still in the answerRect.
- NSPoint localPoint = [self convertPoint:windowPoint fromView:nil];
- NSDragOperation nsActions = [sender draggingSourceOperationMask];
- QPoint posDrag(localPoint.x, localPoint.y);
- if (qt_mac_mouse_inside_answer_rect(posDrag)
- && QT_PREPEND_NAMESPACE(qt_mac_dnd_answer_rec.lastOperation) == nsActions) {
- NSDragOperation operation = QT_PREPEND_NAMESPACE(qt_mac_mapDropActions)(QT_PREPEND_NAMESPACE(qt_mac_dnd_answer_rec.lastAction));
- [self changeDraggingCursor:operation];
- return operation;
- }
- // send drag move event to the widget
- QT_PREPEND_NAMESPACE(qt_mac_dnd_answer_rec.lastOperation) = nsActions;
- Qt::DropActions qtAllowed = QT_PREPEND_NAMESPACE(qt_mac_mapNSDragOperations)(nsActions);
- Qt::KeyboardModifiers modifiers = Qt::NoModifier;
- if ([sender draggingSource] != nil) {
- // modifier flags might have changed, update it here since we don't send any input events.
- QApplicationPrivate::modifier_buttons = qt_cocoaModifiers2QtModifiers([[NSApp currentEvent] modifierFlags]);
- modifiers = QApplication::keyboardModifiers();
- } else {
- // when the source is from another application the above technique will not work.
- modifiers = qt_cocoaDragOperation2QtModifiers(nsActions);
- }
- QMimeData *mimeData = dropData;
- if (QDragManager::self()->source())
- mimeData = QDragManager::self()->dragPrivate()->data;
- QDragMoveEvent qDMEvent(posDrag, qtAllowed, mimeData, QApplication::mouseButtons(), modifiers);
- if (QT_PREPEND_NAMESPACE(qt_mac_dnd_answer_rec).lastAction != Qt::IgnoreAction
- && QT_PREPEND_NAMESPACE(qt_mac_dnd_answer_rec).buttons == qDMEvent.mouseButtons()
- && QT_PREPEND_NAMESPACE(qt_mac_dnd_answer_rec).modifiers == qDMEvent.keyboardModifiers())
- qDMEvent.setDropAction(QT_PREPEND_NAMESPACE(qt_mac_dnd_answer_rec).lastAction);
- qDMEvent.accept();
- QApplication::sendEvent(qwidget, &qDMEvent);
-
- NSDragOperation operation = qt_mac_mapDropAction(qDMEvent.dropAction());
- if (!qDMEvent.isAccepted() || qDMEvent.dropAction() == Qt::IgnoreAction) {
- // ignore this event (we will still receive further notifications)
- operation = NSDragOperationNone;
- // Save as ignored in the answer rect.
- qDMEvent.setDropAction(Qt::IgnoreAction);
- }
- qt_mac_copy_answer_rect(qDMEvent);
- [self changeDraggingCursor:operation];
- return operation;
-}
-
-- (void)draggingExited:(id < NSDraggingInfo >)sender
-{
- // NB: This function is called from QCoocaWindow/QCocoaPanel rather than directly
- // from Cocoa. They modify the drag target, and might fake enter/leave events.
- Q_UNUSED(sender);
- dragEnterSequence = -1;
- // drag enter event was rejected, so ignore the move event.
- if (dropData) {
- QDragLeaveEvent de;
- QApplication::sendEvent(qwidget, &de);
- [self removeDropData];
- }
- [self changeDraggingCursor:NSDragOperationEvery];
-
-}
-
-- (BOOL)performDragOperation:(id <NSDraggingInfo>)sender
-{
- // NB: This function is called from QCoocaWindow/QCocoaPanel rather than directly
- // from Cocoa. They modify the drag target, and might fake enter/leave events.
- NSPoint windowPoint = [sender draggingLocation];
- dragEnterSequence = -1;
- [self addDropData:sender];
-
- NSPoint localPoint = [self convertPoint:windowPoint fromView:nil];
- QPoint posDrop(localPoint.x, localPoint.y);
-
- NSDragOperation nsActions = [sender draggingSourceOperationMask];
- Qt::DropActions qtAllowed = qt_mac_mapNSDragOperations(nsActions);
- QMimeData *mimeData = dropData;
- if (QDragManager::self()->source())
- mimeData = QDragManager::self()->dragPrivate()->data;
- // send the drop event to the widget.
- QDropEvent de(posDrop, qtAllowed, mimeData,
- QApplication::mouseButtons(), QApplication::keyboardModifiers());
- if (QDragManager::self()->object)
- QDragManager::self()->dragPrivate()->target = qwidget;
- QApplication::sendEvent(qwidget, &de);
- if (QDragManager::self()->object)
- QDragManager::self()->dragPrivate()->executed_action = de.dropAction();
- if (!de.isAccepted())
- return NO;
- else
- return YES;
-}
-
- (void)dealloc
{
+ QMacCocoaAutoReleasePool pool;
delete composingText;
[[NSNotificationCenter defaultCenter] removeObserver:self];
#ifdef ALIEN_DEBUG
--qCocoaViewCount;
- qDebug() << "qCocoaViewCount is" << qCocoaViewCount;
+ qDebug() << "Alien: widget deallocated. qCocoaViewCount is:" << qCocoaViewCount;
#endif
[super dealloc];
@@ -530,8 +249,78 @@ static int qCocoaViewCount = 0;
if (!qwidget)
return;
+ // Getting context.
+ CGContextRef context = (CGContextRef)[[NSGraphicsContext currentContext] graphicsPort];
+ qt_mac_retain_graphics_context(context);
+
// We use a different graphics system.
- if (QApplicationPrivate::graphicsSystem() != 0 && !qwidgetprivate->isInUnifiedToolbar) {
+ if (QApplicationPrivate::graphicsSystem() != 0) {
+
+ // Raster engine.
+ if (QApplicationPrivate::graphics_system_name == QLatin1String("raster")) {
+
+ if (!qwidgetprivate->isInUnifiedToolbar) {
+
+ // Qt handles the painting occuring inside the window.
+ // Cocoa also keeps track of all widgets as NSView and therefore might
+ // ask for a repainting of a widget even if Qt is already taking care of it.
+ //
+ // The only valid reason for Cocoa to call drawRect: is for window manipulation
+ // (ie. resize, ...).
+ //
+ // Qt will then forward the update to the children.
+ if (!qwidget->isWindow()) {
+ qt_mac_release_graphics_context(context);
+ return;
+ }
+
+ QRasterWindowSurface *winSurface = dynamic_cast<QRasterWindowSurface *>(qwidget->windowSurface());
+ if (!winSurface || !winSurface->needsFlush) {
+ qt_mac_release_graphics_context(context);
+ return;
+ }
+
+ // Clip to region.
+ const QVector<QRect> &rects = winSurface->regionToFlush.rects();
+ for (int i = 0; i < rects.size(); ++i) {
+ const QRect &rect = rects.at(i);
+ CGContextAddRect(context, CGRectMake(rect.x(), rect.y(), rect.width(), rect.height()));
+ }
+ CGContextClip(context);
+
+ QRect r = winSurface->regionToFlush.boundingRect();
+ const CGRect area = CGRectMake(r.x(), r.y(), r.width(), r.height());
+
+ qt_mac_draw_image(context, winSurface->imageContext(), area, area);
+
+ winSurface->needsFlush = false;
+ winSurface->regionToFlush = QRegion();
+
+ } else {
+
+ QUnifiedToolbarSurface *unifiedSurface = qwidgetprivate->unifiedSurface;
+ if (!unifiedSurface) {
+ qt_mac_release_graphics_context(context);
+ return;
+ }
+
+ int areaX = qwidgetprivate->toolbar_offset.x();
+ int areaY = qwidgetprivate->toolbar_offset.y();
+ int areaWidth = qwidget->geometry().width();
+ int areaHeight = qwidget->geometry().height();
+ const CGRect area = CGRectMake(areaX, areaY, areaWidth, areaHeight);
+ const CGRect drawingArea = CGRectMake(0, 0, areaWidth, areaHeight);
+
+ qt_mac_draw_image(context, unifiedSurface->imageContext(), area, drawingArea);
+
+ qwidgetprivate->flushRequested = false;
+
+ }
+
+ CGContextFlush(context);
+ qt_mac_release_graphics_context(context);
+ return;
+ }
// Qt handles the painting occuring inside the window.
// Cocoa also keeps track of all widgets as NSView and therefore might
@@ -547,25 +336,14 @@ static int qCocoaViewCount = 0;
}
// Since we don't want to use the native engine, we must exit, however
- // widgets that are set to paint on screen, spesifically QGLWidget,
+ // widgets that are set to paint on screen, specifically QGLWidget,
// requires the following code to execute in order to be drawn.
if (!qwidget->testAttribute(Qt::WA_PaintOnScreen))
return;
}
- CGContextRef cg = (CGContextRef)[[NSGraphicsContext currentContext] graphicsPort];
- CGContextRetain(cg);
- qwidgetprivate->hd = cg;
-
- // We steal the CGContext for flushing in the unified toolbar with the raster engine.
- if (QApplicationPrivate::graphicsSystem() != 0 && qwidgetprivate->isInUnifiedToolbar) {
- qwidgetprivate->cgContext = cg;
- qwidgetprivate->hasOwnContext = true;
- qwidgetprivate->unifiedSurface->flush(qwidget, qwidgetprivate->ut_rg, qwidgetprivate->ut_pt);
- return;
- }
-
- CGContextSaveGState(cg);
+ // Native engine.
+ qwidgetprivate->hd = context;
if (qwidget->isVisible() && qwidget->updatesEnabled()) { //process the actual paint event.
if (qwidget->testAttribute(Qt::WA_WState_InPaintEvent))
@@ -574,13 +352,13 @@ static int qCocoaViewCount = 0;
const QRect qrect = QRect(aRect.origin.x, aRect.origin.y, aRect.size.width, aRect.size.height);
QRegion qrgn;
- const NSRect *rects;
- NSInteger count;
- [self getRectsBeingDrawn:&rects count:&count];
- for (int i = 0; i < count; ++i) {
- QRect tmpRect = QRect(rects[i].origin.x, rects[i].origin.y, rects[i].size.width, rects[i].size.height);
- qrgn += tmpRect;
- }
+ const NSRect *rects;
+ NSInteger count;
+ [self getRectsBeingDrawn:&rects count:&count];
+ for (int i = 0; i < count; ++i) {
+ QRect tmpRect = QRect(rects[i].origin.x, rects[i].origin.y, rects[i].size.width, rects[i].size.height);
+ qrgn += tmpRect;
+ }
if (!qwidget->isWindow() && !qobject_cast<QAbstractScrollArea *>(qwidget->parent())) {
const QRegion &parentMask = qwidget->window()->mask();
@@ -600,48 +378,37 @@ static int qCocoaViewCount = 0;
engine->setSystemClip(qrgn);
if (qwidgetprivate->extra && qwidgetprivate->extra->hasMask) {
CGRect widgetRect = CGRectMake(0, 0, qwidget->width(), qwidget->height());
- CGContextTranslateCTM (cg, 0, widgetRect.size.height);
- CGContextScaleCTM(cg, 1, -1);
+ CGContextTranslateCTM (context, 0, widgetRect.size.height);
+ CGContextScaleCTM(context, 1, -1);
if (qwidget->isWindow())
- CGContextClearRect(cg, widgetRect);
- CGContextClipToMask(cg, widgetRect, qwidgetprivate->extra->imageMask);
- CGContextScaleCTM(cg, 1, -1);
- CGContextTranslateCTM (cg, 0, -widgetRect.size.height);
+ CGContextClearRect(context, widgetRect);
+ CGContextClipToMask(context, widgetRect, qwidgetprivate->extra->imageMask);
+ CGContextScaleCTM(context, 1, -1);
+ CGContextTranslateCTM (context, 0, -widgetRect.size.height);
}
if (qwidget->isWindow() && !qwidgetprivate->isOpaque
- && !qwidget->testAttribute(Qt::WA_MacBrushedMetal)) {
- CGContextClearRect(cg, NSRectToCGRect(aRect));
+ && !qwidget->testAttribute(Qt::WA_MacBrushedMetal)) {
+ CGContextClearRect(context, NSRectToCGRect(aRect));
}
- // Check for alien widgets, use qwidgetPrivate->drawWidget() to draw the widget if this
- // is the case. This makes sure child widgets are drawn as well, Cocoa does not know about
- // those and wont send them drawRect calls.
- if (qwidget->testAttribute(Qt::WA_NativeWindow) && qt_widget_private(qwidget)->hasAlienChildren == false) {
- if ((engine && !qwidget->testAttribute(Qt::WA_NoSystemBackground)
- && (qwidget->isWindow() || qwidget->autoFillBackground()))
- || qwidget->testAttribute(Qt::WA_TintedBackground)
- || qwidget->testAttribute(Qt::WA_StyledBackground)) {
-#ifdef DEBUG_WIDGET_PAINT
- if(doDebug)
- qDebug(" Handling erase for [%s::%s]", qwidget->metaObject()->className(),
- qwidget->objectName().local8Bit().data());
-#endif
- QPainter p(qwidget);
- qwidgetprivate->paintBackground(&p, qrgn,
- qwidget->isWindow() ? QWidgetPrivate::DrawAsRoot : 0);
- p.end();
- }
- QPaintEvent e(qrgn);
-#ifdef QT3_SUPPORT
- e.setErased(true);
-#endif
- qt_sendSpontaneousEvent(qwidget, &e);
- } else {
- qwidget->setAttribute(Qt::WA_WState_InPaintEvent, false); // QWidgetPrivate::drawWidget sets this
- QWidgetPrivate *qwidgetPrivate = qt_widget_private(qwidget);
- qwidgetPrivate->drawWidget(qwidget, qrgn, QPoint(), QWidgetPrivate::DrawAsRoot | QWidgetPrivate::DrawPaintOnScreen | QWidgetPrivate::DrawRecursive, 0);
- }
+ qwidget->setAttribute(Qt::WA_WState_InPaintEvent, false);
+ QWidgetPrivate *qwidgetPrivate = qt_widget_private(qwidget);
+
+ // We specify that we want to draw the widget itself, and
+ // all its children recursive. But we skip native children, because
+ // they will receive drawRect calls by themselves as needed:
+ int flags = QWidgetPrivate::DrawPaintOnScreen
+ | QWidgetPrivate::DrawRecursive
+ | QWidgetPrivate::DontDrawNativeChildren;
+
+ if (qwidget->isWindow())
+ flags |= QWidgetPrivate::DrawAsRoot;
+
+ // Start to draw:
+ qt_mac_clearDirtyOnWidgetInsideDrawWidget = true;
+ qwidgetPrivate->drawWidget(qwidget, qrgn, QPoint(), flags, 0);
+ qt_mac_clearDirtyOnWidgetInsideDrawWidget = false;
if (!redirectionOffset.isNull())
QPainter::restoreRedirected(qwidget);
@@ -650,20 +417,21 @@ static int qCocoaViewCount = 0;
qwidget->setAttribute(Qt::WA_WState_InPaintEvent, false);
if(!qwidget->testAttribute(Qt::WA_PaintOutsidePaintEvent) && qwidget->paintingActive())
qWarning("QWidget: It is dangerous to leave painters active on a"
- " widget outside of the PaintEvent");
+ " widget outside of the PaintEvent");
}
qwidgetprivate->hd = 0;
- CGContextRestoreGState(cg);
- CGContextRelease(cg);
+ qt_mac_release_graphics_context(context);
}
- (BOOL)acceptsFirstMouse:(NSEvent *)theEvent
{
- if (!qwidget)
+ // Find the widget that should receive the event:
+ QPoint qlocal, qglobal;
+ QWidget *widgetToGetMouse = qt_mac_getTargetForMouseEvent(theEvent, QEvent::MouseButtonPress, qlocal, qglobal, qwidget, 0);
+ if (!widgetToGetMouse)
return NO;
- Q_UNUSED(theEvent);
- return !qwidget->testAttribute(Qt::WA_MacNoClickThrough);
+ return !widgetToGetMouse->testAttribute(Qt::WA_MacNoClickThrough);
}
- (NSView *)hitTest:(NSPoint)aPoint
@@ -714,161 +482,120 @@ static int qCocoaViewCount = 0;
- (void)mouseEntered:(NSEvent *)event
{
- if (!qwidget)
- return;
- if (qwidgetprivate->data.in_destructor)
- return;
-
- if (!qAppInstance()->activeModalWidget() || QApplicationPrivate::tryModalHelper(qwidget, 0)) {
- QEvent enterEvent(QEvent::Enter);
- NSPoint windowPoint = [event locationInWindow];
- NSPoint globalPoint = [[event window] convertBaseToScreen:windowPoint];
- NSPoint viewPoint = [self convertPoint:windowPoint fromView:nil];
- QApplication::sendEvent(qwidget, &enterEvent);
- qt_mouseover = qwidget;
-
- // Update cursor icon:
- qt_mac_update_cursor_at_global_pos(flipPoint(globalPoint).toPoint());
-
- // Send mouse move and hover events as well:
- if (!qAppInstance()->activePopupWidget() || qAppInstance()->activePopupWidget() == qwidget->window()) {
- // This mouse move event should be sendt, even when mouse
- // tracking is switched off (to trigger tooltips):
- NSEvent *mouseEvent = [NSEvent mouseEventWithType:NSMouseMoved
- location:windowPoint modifierFlags:[event modifierFlags] timestamp:[event timestamp]
- windowNumber:[event windowNumber] context:[event context] eventNumber:[event eventNumber]
- clickCount:0 pressure:0];
- qt_mac_handleMouseEvent(self, mouseEvent, QEvent::MouseMove, Qt::NoButton);
-
- if (qwidget->testAttribute(Qt::WA_Hover)) {
- QHoverEvent he(QEvent::HoverEnter, QPoint(viewPoint.x, viewPoint.y), QPoint(-1, -1));
- QApplicationPrivate::instance()->notify_helper(qwidget, &he);
- }
- }
- }
+ // Cocoa will not send a move event on mouseEnter. But since
+ // Qt expect this, we fake one now. See also mouseExited below
+ // for info about enter/leave event handling
+ NSEvent *nsmoveEvent = [NSEvent
+ mouseEventWithType:NSMouseMoved
+ location:[[self window] mouseLocationOutsideOfEventStream]
+ modifierFlags: [event modifierFlags]
+ timestamp: [event timestamp]
+ windowNumber: [event windowNumber]
+ context: [event context]
+ eventNumber: [event eventNumber]
+ clickCount: 0
+ pressure: 0];
+
+ // Important: Cocoa sends us mouseEnter on all views under the mouse
+ // and not just the one on top. Therefore, to we cannot use qwidget
+ // as native widget for this case. Instead, we let qt_mac_handleMouseEvent
+ // resolve it (last argument set to 0):
+ qt_mac_handleMouseEvent(nsmoveEvent, QEvent::MouseMove, Qt::NoButton, 0);
}
- (void)mouseExited:(NSEvent *)event
{
- if (!qwidget)
- return;
-
- QEvent leaveEvent(QEvent::Leave);
- NSPoint globalPoint = [[event window] convertBaseToScreen:[event locationInWindow]];
- if (!qAppInstance()->activeModalWidget() || QApplicationPrivate::tryModalHelper(qwidget, 0)) {
- QApplication::sendEvent(qwidget, &leaveEvent);
-
- // ### Think about if it is necessary to update the cursor, should only be for a few cases.
- qt_mac_update_cursor_at_global_pos(flipPoint(globalPoint).toPoint());
- if (qwidget->testAttribute(Qt::WA_Hover)
- && (!qAppInstance()->activePopupWidget() || qAppInstance()->activePopupWidget() == qwidget->window())) {
- QHoverEvent he(QEvent::HoverLeave, QPoint(-1, -1),
- qwidget->mapFromGlobal(QApplicationPrivate::instance()->hoverGlobalPos));
- QApplicationPrivate::instance()->notify_helper(qwidget, &he);
+ // Note: normal enter/leave handling is done from within mouseMove. This handler
+ // catches the case when the mouse moves out of the window (which mouseMove do not).
+ // Updating the mouse cursor follows the same logic as enter/leave. And we update
+ // neither if a grab exists (even if the grab points to this widget, it seems, ref X11)
+ Q_UNUSED(event);
+ if (self == [[self window] contentView] && !qt_button_down && !QWidget::mouseGrabber()) {
+ qt_mac_update_cursor();
+ // If the mouse exits the content view, but qt_mac_getTargetForMouseEvent still
+ // reports a target, it means that either there is a grab involved, or the mouse
+ // hovered over another window in the application. In both cases, move events will
+ // cause qt_mac_handleMouseEvent to be called, which will handle enter/leave.
+ QPoint qlocal, qglobal;
+ QWidget *widgetUnderMouse = 0;
+ qt_mac_getTargetForMouseEvent(event, QEvent::Leave, qlocal, qglobal, qwidget, &widgetUnderMouse);
+
+ if (widgetUnderMouse == 0) {
+ QApplicationPrivate::dispatchEnterLeave(0, qt_last_mouse_receiver);
+ qt_last_mouse_receiver = 0;
+ qt_last_native_mouse_receiver = 0;
}
}
}
- (void)flagsChanged:(NSEvent *)theEvent
{
- if (!qwidget)
+ QWidget *widgetToGetKey = qt_mac_getTargetForKeyEvent(qwidget);
+ if (!widgetToGetKey)
return;
- QWidget *widgetToGetKey = qwidget;
-
- QWidget *popup = qAppInstance()->activePopupWidget();
- if (popup && popup != qwidget->window())
- widgetToGetKey = popup->focusWidget() ? popup->focusWidget() : popup;
qt_dispatchModifiersChanged(theEvent, widgetToGetKey);
[super flagsChanged:theEvent];
}
- (void)mouseMoved:(NSEvent *)theEvent
{
- if (!qwidget)
- return;
-
- // We always enable mouse tracking for all QCocoaView-s. In cases where we have
- // child views, we will receive mouseMoved for both parent & the child (if
- // mouse is over the child). We need to ignore the parent mouseMoved in such
- // cases.
- NSPoint windowPoint = [theEvent locationInWindow];
- NSView *candidateView = [[[self window] contentView] hitTest:windowPoint];
- if (candidateView && candidateView == self) {
- qt_mac_handleMouseEvent(self, theEvent, QEvent::MouseMove, Qt::NoButton);
- }
+ // Important: this method will only be called when the view's window is _not_ inside
+ // QCocoaWindow/QCocoaPanel. Otherwise, [QCocoaWindow sendEvent] will handle the event
+ // before it ends up here. So, this method is added for supporting QMacNativeWidget.
+ // TODO: Cocoa send move events to all views under the mouse. So make sure we only
+ // handle the event for the widget on top when using QMacNativeWidget.
+ qt_mac_handleMouseEvent(theEvent, QEvent::MouseMove, Qt::NoButton, qwidget);
}
- (void)mouseDown:(NSEvent *)theEvent
{
- if (!qt_button_down)
- qt_button_down = qwidget;
-
- qt_mac_handleMouseEvent(self, theEvent, QEvent::MouseButtonPress, Qt::LeftButton);
+ qt_mac_handleMouseEvent(theEvent, QEvent::MouseButtonPress, Qt::LeftButton, qwidget);
// Don't call super here. This prevents us from getting the mouseUp event,
// which we need to send even if the mouseDown event was not accepted.
// (this is standard Qt behavior.)
}
-
- (void)mouseUp:(NSEvent *)theEvent
{
- qt_mac_handleMouseEvent(self, theEvent, QEvent::MouseButtonRelease, Qt::LeftButton);
-
- qt_button_down = 0;
+ qt_mac_handleMouseEvent(theEvent, QEvent::MouseButtonRelease, Qt::LeftButton, qwidget);
}
- (void)rightMouseDown:(NSEvent *)theEvent
{
- if (!qt_button_down)
- qt_button_down = qwidget;
-
- qt_mac_handleMouseEvent(self, theEvent, QEvent::MouseButtonPress, Qt::RightButton);
+ qt_mac_handleMouseEvent(theEvent, QEvent::MouseButtonPress, Qt::RightButton, qwidget);
}
- (void)rightMouseUp:(NSEvent *)theEvent
{
- qt_mac_handleMouseEvent(self, theEvent, QEvent::MouseButtonRelease, Qt::RightButton);
-
- qt_button_down = 0;
+ qt_mac_handleMouseEvent(theEvent, QEvent::MouseButtonRelease, Qt::RightButton, qwidget);
}
- (void)otherMouseDown:(NSEvent *)theEvent
{
- if (!qt_button_down)
- qt_button_down = qwidget;
-
Qt::MouseButton mouseButton = cocoaButton2QtButton([theEvent buttonNumber]);
- qt_mac_handleMouseEvent(self, theEvent, QEvent::MouseButtonPress, mouseButton);
+ qt_mac_handleMouseEvent(theEvent, QEvent::MouseButtonPress, mouseButton, qwidget);
}
- (void)otherMouseUp:(NSEvent *)theEvent
{
Qt::MouseButton mouseButton = cocoaButton2QtButton([theEvent buttonNumber]);
- qt_mac_handleMouseEvent(self, theEvent, QEvent::MouseButtonRelease, mouseButton);
-
- qt_button_down = 0;
+ qt_mac_handleMouseEvent(theEvent, QEvent::MouseButtonRelease, mouseButton, qwidget);
}
- (void)mouseDragged:(NSEvent *)theEvent
{
- qMacDnDParams()->view = self;
- qMacDnDParams()->theEvent = theEvent;
- qt_mac_handleMouseEvent(self, theEvent, QEvent::MouseMove, Qt::NoButton);
+ qt_mac_handleMouseEvent(theEvent, QEvent::MouseMove, Qt::NoButton, qwidget);
}
- (void)rightMouseDragged:(NSEvent *)theEvent
{
- qMacDnDParams()->view = self;
- qMacDnDParams()->theEvent = theEvent;
- qt_mac_handleMouseEvent(self, theEvent, QEvent::MouseMove, Qt::NoButton);
+ qt_mac_handleMouseEvent(theEvent, QEvent::MouseMove, Qt::NoButton, qwidget);
}
- (void)otherMouseDragged:(NSEvent *)theEvent
{
- qMacDnDParams()->view = self;
- qMacDnDParams()->theEvent = theEvent;
- qt_mac_handleMouseEvent(self, theEvent, QEvent::MouseMove, Qt::NoButton);
+ qt_mac_handleMouseEvent(theEvent, QEvent::MouseMove, Qt::NoButton, qwidget);
}
- (void)scrollWheel:(NSEvent *)theEvent
@@ -879,21 +606,14 @@ static int qCocoaViewCount = 0;
[currentIManager handleMouseEvent:theEvent];
}
- NSPoint windowPoint = [theEvent locationInWindow];
- NSPoint globalPoint = [[theEvent window] convertBaseToScreen:windowPoint];
- NSPoint localPoint = [self convertPoint:windowPoint fromView:nil];
- QPoint qlocal = QPoint(localPoint.x, localPoint.y);
- QPoint qglobal = QPoint(globalPoint.x, flipYCoordinate(globalPoint.y));
Qt::MouseButtons buttons = QApplication::mouseButtons();
- bool wheelOK = false;
Qt::KeyboardModifiers keyMods = qt_cocoaModifiers2QtModifiers([theEvent modifierFlags]);
- QWidget *widgetToGetMouse = qwidget;
- // if popup is open it should get wheel events if the cursor is over the popup,
- // otherwise the event should be ignored.
- if (QWidget *popup = qAppInstance()->activePopupWidget()) {
- if (!popup->geometry().contains(qglobal))
- return;
- }
+
+ // Find the widget that should receive the event:
+ QPoint qlocal, qglobal;
+ QWidget *widgetToGetMouse = qt_mac_getTargetForMouseEvent(theEvent, QEvent::Wheel, qlocal, qglobal, qwidget, 0);
+ if (!widgetToGetMouse)
+ return;
int deltaX = 0;
int deltaY = 0;
@@ -922,46 +642,30 @@ static int qCocoaViewCount = 0;
}
#ifndef QT_NO_WHEELEVENT
+ // ### Qt 5: Send one QWheelEvent with dx, dy and dz
+
+ if (deltaX != 0 && deltaY != 0)
+ QMacScrollOptimization::initDelayedScroll();
+
if (deltaX != 0) {
QWheelEvent qwe(qlocal, qglobal, deltaX, buttons, keyMods, Qt::Horizontal);
qt_sendSpontaneousEvent(widgetToGetMouse, &qwe);
- wheelOK = qwe.isAccepted();
- if (!wheelOK && QApplicationPrivate::focus_widget
- && QApplicationPrivate::focus_widget != widgetToGetMouse) {
- QWheelEvent qwe2(QApplicationPrivate::focus_widget->mapFromGlobal(qglobal), qglobal,
- deltaX, buttons, keyMods, Qt::Horizontal);
- qt_sendSpontaneousEvent(QApplicationPrivate::focus_widget, &qwe2);
- wheelOK = qwe2.isAccepted();
- }
}
- if (deltaY) {
+ if (deltaY != 0) {
QWheelEvent qwe(qlocal, qglobal, deltaY, buttons, keyMods, Qt::Vertical);
qt_sendSpontaneousEvent(widgetToGetMouse, &qwe);
- wheelOK = qwe.isAccepted();
- if (!wheelOK && QApplicationPrivate::focus_widget
- && QApplicationPrivate::focus_widget != widgetToGetMouse) {
- QWheelEvent qwe2(QApplicationPrivate::focus_widget->mapFromGlobal(qglobal), qglobal,
- deltaY, buttons, keyMods, Qt::Vertical);
- qt_sendSpontaneousEvent(QApplicationPrivate::focus_widget, &qwe2);
- wheelOK = qwe2.isAccepted();
- }
}
- if (deltaZ) {
+ if (deltaZ != 0) {
// Qt doesn't explicitly support wheels with a Z component. In a misguided attempt to
// try to be ahead of the pack, I'm adding this extra value.
QWheelEvent qwe(qlocal, qglobal, deltaZ, buttons, keyMods, (Qt::Orientation)3);
qt_sendSpontaneousEvent(widgetToGetMouse, &qwe);
- wheelOK = qwe.isAccepted();
- if (!wheelOK && QApplicationPrivate::focus_widget
- && QApplicationPrivate::focus_widget != widgetToGetMouse) {
- QWheelEvent qwe2(QApplicationPrivate::focus_widget->mapFromGlobal(qglobal), qglobal,
- deltaZ, buttons, keyMods, (Qt::Orientation)3);
- qt_sendSpontaneousEvent(QApplicationPrivate::focus_widget, &qwe2);
- wheelOK = qwe2.isAccepted();
- }
}
+
+ if (deltaX != 0 && deltaY != 0)
+ QMacScrollOptimization::performDelayedScroll();
#endif //QT_NO_WHEELEVENT
}
@@ -976,35 +680,14 @@ static int qCocoaViewCount = 0;
[super tabletPoint:tabletEvent];
}
-#if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_6
-- (void)touchesBeganWithEvent:(NSEvent *)event
-{
- bool all = qwidget->testAttribute(Qt::WA_TouchPadAcceptSingleTouchEvents);
- qt_translateRawTouchEvent(qwidget, QTouchEvent::TouchPad, QCocoaTouch::getCurrentTouchPointList(event, all));
-}
-
-- (void)touchesMovedWithEvent:(NSEvent *)event
-{
- bool all = qwidget->testAttribute(Qt::WA_TouchPadAcceptSingleTouchEvents);
- qt_translateRawTouchEvent(qwidget, QTouchEvent::TouchPad, QCocoaTouch::getCurrentTouchPointList(event, all));
-}
-
-- (void)touchesEndedWithEvent:(NSEvent *)event
-{
- bool all = qwidget->testAttribute(Qt::WA_TouchPadAcceptSingleTouchEvents);
- qt_translateRawTouchEvent(qwidget, QTouchEvent::TouchPad, QCocoaTouch::getCurrentTouchPointList(event, all));
-}
-
-- (void)touchesCancelledWithEvent:(NSEvent *)event
-{
- bool all = qwidget->testAttribute(Qt::WA_TouchPadAcceptSingleTouchEvents);
- qt_translateRawTouchEvent(qwidget, QTouchEvent::TouchPad, QCocoaTouch::getCurrentTouchPointList(event, all));
-}
-#endif // MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_6
-
- (void)magnifyWithEvent:(NSEvent *)event
{
- if (!QApplicationPrivate::tryModalHelper(qwidget, 0))
+ QPoint qlocal, qglobal;
+ QWidget *widgetToGetGesture = 0;
+ qt_mac_getTargetForMouseEvent(event, QEvent::Gesture, qlocal, qglobal, qwidget, &widgetToGetGesture);
+ if (!widgetToGetGesture)
+ return;
+ if (!QApplicationPrivate::tryModalHelper(widgetToGetGesture, 0))
return;
#ifndef QT_NO_GESTURES
@@ -1013,13 +696,18 @@ static int qCocoaViewCount = 0;
NSPoint p = [[event window] convertBaseToScreen:[event locationInWindow]];
qNGEvent.position = flipPoint(p).toPoint();
qNGEvent.percentage = [event magnification];
- qt_sendSpontaneousEvent(qwidget, &qNGEvent);
+ qt_sendSpontaneousEvent(widgetToGetGesture, &qNGEvent);
#endif // QT_NO_GESTURES
}
- (void)rotateWithEvent:(NSEvent *)event
{
- if (!QApplicationPrivate::tryModalHelper(qwidget, 0))
+ QPoint qlocal, qglobal;
+ QWidget *widgetToGetGesture = 0;
+ qt_mac_getTargetForMouseEvent(event, QEvent::Gesture, qlocal, qglobal, qwidget, &widgetToGetGesture);
+ if (!widgetToGetGesture)
+ return;
+ if (!QApplicationPrivate::tryModalHelper(widgetToGetGesture, 0))
return;
#ifndef QT_NO_GESTURES
@@ -1028,13 +716,18 @@ static int qCocoaViewCount = 0;
NSPoint p = [[event window] convertBaseToScreen:[event locationInWindow]];
qNGEvent.position = flipPoint(p).toPoint();
qNGEvent.percentage = -[event rotation];
- qt_sendSpontaneousEvent(qwidget, &qNGEvent);
+ qt_sendSpontaneousEvent(widgetToGetGesture, &qNGEvent);
#endif // QT_NO_GESTURES
}
- (void)swipeWithEvent:(NSEvent *)event
{
- if (!QApplicationPrivate::tryModalHelper(qwidget, 0))
+ QPoint qlocal, qglobal;
+ QWidget *widgetToGetGesture = 0;
+ qt_mac_getTargetForMouseEvent(event, QEvent::Gesture, qlocal, qglobal, qwidget, &widgetToGetGesture);
+ if (!widgetToGetGesture)
+ return;
+ if (!QApplicationPrivate::tryModalHelper(widgetToGetGesture, 0))
return;
#ifndef QT_NO_GESTURES
@@ -1050,13 +743,18 @@ static int qCocoaViewCount = 0;
qNGEvent.angle = 90.0f;
else if ([event deltaY] == -1)
qNGEvent.angle = 270.0f;
- qt_sendSpontaneousEvent(qwidget, &qNGEvent);
+ qt_sendSpontaneousEvent(widgetToGetGesture, &qNGEvent);
#endif // QT_NO_GESTURES
}
- (void)beginGestureWithEvent:(NSEvent *)event
{
- if (!QApplicationPrivate::tryModalHelper(qwidget, 0))
+ QPoint qlocal, qglobal;
+ QWidget *widgetToGetGesture = 0;
+ qt_mac_getTargetForMouseEvent(event, QEvent::Gesture, qlocal, qglobal, qwidget, &widgetToGetGesture);
+ if (!widgetToGetGesture)
+ return;
+ if (!QApplicationPrivate::tryModalHelper(widgetToGetGesture, 0))
return;
#ifndef QT_NO_GESTURES
@@ -1064,13 +762,18 @@ static int qCocoaViewCount = 0;
qNGEvent.gestureType = QNativeGestureEvent::GestureBegin;
NSPoint p = [[event window] convertBaseToScreen:[event locationInWindow]];
qNGEvent.position = flipPoint(p).toPoint();
- qt_sendSpontaneousEvent(qwidget, &qNGEvent);
+ qt_sendSpontaneousEvent(widgetToGetGesture, &qNGEvent);
#endif // QT_NO_GESTURES
}
- (void)endGestureWithEvent:(NSEvent *)event
{
- if (!QApplicationPrivate::tryModalHelper(qwidget, 0))
+ QPoint qlocal, qglobal;
+ QWidget *widgetToGetGesture = 0;
+ qt_mac_getTargetForMouseEvent(event, QEvent::Gesture, qlocal, qglobal, qwidget, &widgetToGetGesture);
+ if (!widgetToGetGesture)
+ return;
+ if (!QApplicationPrivate::tryModalHelper(widgetToGetGesture, 0))
return;
#ifndef QT_NO_GESTURES
@@ -1078,9 +781,9 @@ static int qCocoaViewCount = 0;
qNGEvent.gestureType = QNativeGestureEvent::GestureEnd;
NSPoint p = [[event window] convertBaseToScreen:[event locationInWindow]];
qNGEvent.position = flipPoint(p).toPoint();
- qt_sendSpontaneousEvent(qwidget, &qNGEvent);
-#endif // QT_NO_GESTURES
+ qt_sendSpontaneousEvent(widgetToGetGesture, &qNGEvent);
}
+#endif // QT_NO_GESTURES
- (void)frameDidChange:(NSNotification *)note
{
@@ -1123,27 +826,46 @@ static int qCocoaViewCount = 0;
{
if (!qwidget)
return NO;
- // disabled widget shouldn't get focus even if it's a window.
+
+ // Disabled widget shouldn't get focus even if it's a window.
// hence disabled windows will not get any key or mouse events.
if (!qwidget->isEnabled())
return NO;
- // Before accepting the focus for a window, we check that
- // the focusWidget (if any) is not contained in the same window.
- if (qwidget->isWindow() && !qt_widget_private(qwidget)->topData()->embedded
- && (!qApp->focusWidget() || qApp->focusWidget()->window() != qwidget)) {
- return YES; // Always do it, so that windows can accept key press events.
+
+ if (qwidget->isWindow() && !qt_widget_private(qwidget)->topData()->embedded) {
+ QWidget *focusWidget = qApp->focusWidget();
+ if (!focusWidget) {
+ // There is no focus widget, but we still want to receive key events
+ // for shortcut handling etc. So we accept first responer for the
+ // content view as a last resort:
+ return YES;
+ }
+ if (!focusWidget->internalWinId() && focusWidget->nativeParentWidget() == qwidget) {
+ // The current focus widget is alien, and hence, cannot get acceptsFirstResponder
+ // calls. Since the focus widget is a child of qwidget, we let this view say YES:
+ return YES;
+ }
+ if (focusWidget->window() != qwidget) {
+ // The current focus widget is in another window. Since cocoa
+ // suggest that this window should be key now, we accept:
+ return YES;
+ }
}
+
return qwidget->focusPolicy() != Qt::NoFocus;
}
- (BOOL)resignFirstResponder
{
if (!qwidget)
- return NO;
+ return YES;
+
// Seems like the following test only triggers if this
// view is inside a QMacNativeWidget:
- if (qwidget == QApplication::focusWidget())
- qwidget->clearFocus();
+// if (QWidget *fw = QApplication::focusWidget()) {
+// if (qwidget == fw || qwidget == fw->nativeParentWidget())
+// fw->clearFocus();
+// }
return YES;
}
@@ -1172,11 +894,11 @@ static int qCocoaViewCount = 0;
{
Q_UNUSED(anImage);
Q_UNUSED(aPoint);
- qMacDnDParams()->performedAction = operation;
+ macCurrentDnDParameters()->performedAction = operation;
if (QDragManager::self()->object
&& QDragManager::self()->dragPrivate()->executed_action != Qt::ActionMask) {
- qMacDnDParams()->performedAction =
- qt_mac_mapDropAction(QDragManager::self()->dragPrivate()->executed_action);
+ macCurrentDnDParameters()->performedAction =
+ qt_mac_mapDropAction(QDragManager::self()->dragPrivate()->executed_action);
}
}
@@ -1191,51 +913,37 @@ static int qCocoaViewCount = 0;
qwidgetprivate = 0;
}
-- (BOOL)qt_leftButtonIsRightButton
-{
- return leftButtonIsRightButton;
-}
-
-- (void)qt_setLeftButtonIsRightButton:(BOOL)isSwapped
-{
- leftButtonIsRightButton = isSwapped;
-}
-
-+ (DnDParams*)currentMouseEvent
-{
- return qMacDnDParams();
-}
-
- (void)keyDown:(NSEvent *)theEvent
{
- sendKeyEvents = true;
-
- QWidget *widgetToGetKey = qwidget;
+ if (!qwidget)
+ return;
+ QWidget *widgetToGetKey = qt_mac_getTargetForKeyEvent(qwidget);
+ if (!widgetToGetKey)
+ return;
- QWidget *popup = qAppInstance()->activePopupWidget();
- bool sendToPopup = false;
- if (popup && popup != qwidget->window()) {
- widgetToGetKey = popup->focusWidget() ? popup->focusWidget() : popup;
- sendToPopup = true;
- }
+ sendKeyEvents = true;
if (widgetToGetKey->testAttribute(Qt::WA_InputMethodEnabled)
&& !(widgetToGetKey->inputMethodHints() & Qt::ImhDigitsOnly
|| widgetToGetKey->inputMethodHints() & Qt::ImhFormattedNumbersOnly
|| widgetToGetKey->inputMethodHints() & Qt::ImhHiddenText)) {
fromKeyDownEvent = true;
- [qt_mac_nativeview_for(widgetToGetKey) interpretKeyEvents:[NSArray arrayWithObject: theEvent]];
+ [qt_mac_nativeview_for(qwidget) interpretKeyEvents:[NSArray arrayWithObject: theEvent]];
fromKeyDownEvent = false;
}
+
if (sendKeyEvents && !composing) {
- bool keyOK = qt_dispatchKeyEvent(theEvent, widgetToGetKey);
- if (!keyOK && !sendToPopup) {
- // find the first responder that is not created by Qt and forward
- // the event to it (for example if Qt widget is embedded into native).
+ bool keyEventEaten = qt_dispatchKeyEvent(theEvent, widgetToGetKey);
+ if (!keyEventEaten && qwidget) {
+ // The event is not yet eaten, and if Qt is embedded inside a native
+ // cocoa application, send it to first responder not owned by Qt.
+ // The exception is if widgetToGetKey was redirected to a popup.
QWidget *toplevel = qwidget->window();
- if (toplevel && qt_widget_private(toplevel)->topData()->embedded) {
- if (NSResponder *w = [qt_mac_nativeview_for(toplevel) superview])
- [w keyDown:theEvent];
+ if (toplevel == widgetToGetKey->window()) {
+ if (qt_widget_private(toplevel)->topData()->embedded) {
+ if (NSResponder *w = [qt_mac_nativeview_for(toplevel) superview])
+ [w keyDown:theEvent];
+ }
}
}
}
@@ -1245,12 +953,21 @@ static int qCocoaViewCount = 0;
- (void)keyUp:(NSEvent *)theEvent
{
if (sendKeyEvents) {
- bool keyOK = qt_dispatchKeyEvent(theEvent, qwidget);
- if (!keyOK) {
+ QWidget *widgetToGetKey = qt_mac_getTargetForKeyEvent(qwidget);
+ if (!widgetToGetKey)
+ return;
+
+ bool keyEventEaten = qt_dispatchKeyEvent(theEvent, widgetToGetKey);
+ if (!keyEventEaten && qwidget) {
+ // The event is not yet eaten, and if Qt is embedded inside a native
+ // cocoa application, send it to first responder not owned by Qt.
+ // The exception is if widgetToGetKey was redirected to a popup.
QWidget *toplevel = qwidget->window();
- if (toplevel && qt_widget_private(toplevel)->topData()->embedded) {
- if (NSResponder *w = [qt_mac_nativeview_for(toplevel) superview])
- [w keyUp:theEvent];
+ if (toplevel == widgetToGetKey->window()) {
+ if (qt_widget_private(toplevel)->topData()->embedded) {
+ if (NSResponder *w = [qt_mac_nativeview_for(toplevel) superview])
+ [w keyUp:theEvent];
+ }
}
}
}
@@ -1298,13 +1015,14 @@ static int qCocoaViewCount = 0;
// When entering characters through Character Viewer or Keyboard Viewer, the text is passed
// through this insertText method. Since we dont receive a keyDown Event in such cases, the
// composing flag will be false.
- if (([aString length] && composing) || !fromKeyDownEvent) {
+ if (([aString length] && composing) || !fromKeyDownEvent) {
// Send the commit string to the widget.
composing = false;
sendKeyEvents = false;
QInputMethodEvent e;
e.setCommitString(commitText);
- qt_sendSpontaneousEvent(qwidget, &e);
+ if (QWidget *widgetToGetKey = qt_mac_getTargetForKeyEvent(qwidget))
+ qt_sendSpontaneousEvent(widgetToGetKey, &e);
} else {
// The key sequence "`q" on a French Keyboard will generate two calls to insertText before
// it returns from interpretKeyEvents. The first call will turn off 'composing' and accept
@@ -1326,7 +1044,7 @@ static int qCocoaViewCount = 0;
QString qtText;
// Cursor position is retrived from the range.
QList<QInputMethodEvent::Attribute> attrs;
- attrs<<QInputMethodEvent::Attribute(QInputMethodEvent::Cursor, selRange.location, 1, QVariant());
+ attrs<<QInputMethodEvent::Attribute(QInputMethodEvent::Cursor, selRange.location + selRange.length, 1, QVariant());
if ([aString isKindOfClass:[NSAttributedString class]]) {
qtText = QCFString::toQString(reinterpret_cast<CFStringRef>([aString string]));
composingLength = qtText.length();
@@ -1368,8 +1086,11 @@ static int qCocoaViewCount = 0;
0, composingLength, format);
}
*composingText = qtText;
+
QInputMethodEvent e(qtText, attrs);
- qt_sendSpontaneousEvent(qwidget, &e);
+ if (QWidget *widgetToGetKey = qt_mac_getTargetForKeyEvent(qwidget))
+ qt_sendSpontaneousEvent(widgetToGetKey, &e);
+
if (!composingLength)
composing = false;
}
@@ -1379,7 +1100,8 @@ static int qCocoaViewCount = 0;
if (composing) {
QInputMethodEvent e;
e.setCommitString(*composingText);
- qt_sendSpontaneousEvent(qwidget, &e);
+ if (QWidget *widgetToGetKey = qt_mac_getTargetForKeyEvent(qwidget))
+ qt_sendSpontaneousEvent(widgetToGetKey, &e);
}
composingText->clear();
composing = false;
@@ -1452,8 +1174,12 @@ static int qCocoaViewCount = 0;
{
Q_UNUSED(theRange);
// The returned rect is always based on the internal cursor.
- QRect mr(qwidget->inputMethodQuery(Qt::ImMicroFocus).toRect());
- QPoint mp(qwidget->mapToGlobal(QPoint(mr.bottomLeft())));
+ QWidget *widgetToGetKey = qt_mac_getTargetForKeyEvent(qwidget);
+ if (!widgetToGetKey)
+ return NSZeroRect;
+
+ QRect mr(widgetToGetKey->inputMethodQuery(Qt::ImMicroFocus).toRect());
+ QPoint mp(widgetToGetKey->mapToGlobal(QPoint(mr.bottomLeft())));
NSRect rect ;
rect.origin.x = mp.x();
rect.origin.y = flipYCoordinate(mp.y());
@@ -1471,10 +1197,11 @@ static int qCocoaViewCount = 0;
- (NSArray*) validAttributesForMarkedText
{
- if (qwidget == 0)
+ QWidget *widgetToGetKey = qt_mac_getTargetForKeyEvent(qwidget);
+ if (!widgetToGetKey)
return nil;
- if (!qwidget->testAttribute(Qt::WA_InputMethodEnabled))
+ if (!widgetToGetKey->testAttribute(Qt::WA_InputMethodEnabled))
return nil; // Not sure if that's correct, but it's saves a malloc.
// Support only underline color/style.
@@ -1488,7 +1215,7 @@ void QMacInputContext::reset()
{
QWidget *w = QInputContext::focusWidget();
if (w) {
- NSView *view = qt_mac_nativeview_for(w);
+ NSView *view = qt_mac_effectiveview_for(w);
if ([view isKindOfClass:[QT_MANGLE_NAMESPACE(QCocoaView) class]]) {
QMacCocoaAutoReleasePool pool;
QT_MANGLE_NAMESPACE(QCocoaView) *qc = static_cast<QT_MANGLE_NAMESPACE(QCocoaView) *>(view);
@@ -1505,7 +1232,7 @@ bool QMacInputContext::isComposing() const
{
QWidget *w = QInputContext::focusWidget();
if (w) {
- NSView *view = qt_mac_nativeview_for(w);
+ NSView *view = qt_mac_effectiveview_for(w);
if ([view isKindOfClass:[QT_MANGLE_NAMESPACE(QCocoaView) class]]) {
return [static_cast<QT_MANGLE_NAMESPACE(QCocoaView) *>(view) isComposing];
}
@@ -1598,38 +1325,45 @@ Qt::DropAction QDragManager::drag(QDrag *o)
} else {
hotspot = dragPrivate()->hotspot;
}
- // convert the image to NSImage.
+
+ // Convert the image to NSImage:
NSImage *image = (NSImage *)qt_mac_create_nsimage(pix);
[image retain];
- DnDParams dndParams = *[QT_MANGLE_NAMESPACE(QCocoaView) currentMouseEvent];
- // save supported actions
- [dndParams.view setSupportedActions: qt_mac_mapDropActions(dragPrivate()->possible_actions)];
- NSPoint imageLoc = {dndParams.localPoint.x - hotspot.x(),
- dndParams.localPoint.y + pix.height() - hotspot.y()};
+
+ DnDParams *dndParams = macCurrentDnDParameters();
+ QT_MANGLE_NAMESPACE(QCocoaView) *theView = static_cast<QT_MANGLE_NAMESPACE(QCocoaView) *>(dndParams->view);
+
+ // Save supported actions:
+ [theView setSupportedActions: qt_mac_mapDropActions(dragPrivate()->possible_actions)];
+ QPoint pointInView = [theView qt_qwidget]->mapFromGlobal(dndParams->globalPoint);
+ NSPoint imageLoc = {pointInView.x() - hotspot.x(), pointInView.y() + pix.height() - hotspot.y()};
NSSize mouseOffset = {0.0, 0.0};
NSPasteboard *pboard = [NSPasteboard pasteboardWithName:NSDragPboard];
dragPrivate()->executed_action = Qt::ActionMask;
- // do the drag
- [dndParams.view retain];
- [dndParams.view dragImage:image
- at:imageLoc
- offset:mouseOffset
- event:dndParams.theEvent
- pasteboard:pboard
- source:dndParams.view
- slideBack:YES];
- // reset the implicit grab widget when drag ends because we will not
- // receive the mouse release event when DND is active.
+
+ // Execute the drag:
+ [theView retain];
+ [theView dragImage:image
+ at:imageLoc
+ offset:mouseOffset
+ event:dndParams->theEvent
+ pasteboard:pboard
+ source:theView
+ slideBack:YES];
+
+ // Reset the implicit grab widget when drag ends because we will not
+ // receive the mouse release event when DND is active:
qt_button_down = 0;
- [dndParams.view release];
+ [theView release];
[image release];
if (dragPrivate())
dragPrivate()->executed_action = Qt::IgnoreAction;
object = 0;
- Qt::DropAction performedAction(qt_mac_mapNSDragOperation(qMacDnDParams()->performedAction));
- // do post drag processing, if required.
- if(performedAction != Qt::IgnoreAction) {
- // check if the receiver points us to a file location.
+ Qt::DropAction performedAction(qt_mac_mapNSDragOperation(dndParams->performedAction));
+
+ // Do post drag processing, if required.
+ if (performedAction != Qt::IgnoreAction) {
+ // Check if the receiver points us to a file location.
// if so, we need to do the file copy/move ourselves.
QCFType<CFURLRef> pasteLocation = 0;
PasteboardCopyPasteLocation(dragBoard.pasteBoard(), &pasteLocation);
@@ -1646,6 +1380,8 @@ Qt::DropAction QDragManager::drag(QDrag *o)
}
}
}
+
+ // Clean-up:
o->setMimeData(0);
o->deleteLater();
return performedAction;
diff --git a/src/gui/kernel/qcocoaview_mac_p.h b/src/gui/kernel/qcocoaview_mac_p.h
index 8d57f95..cc79b67 100644
--- a/src/gui/kernel/qcocoaview_mac_p.h
+++ b/src/gui/kernel/qcocoaview_mac_p.h
@@ -58,57 +58,30 @@
QT_FORWARD_DECLARE_CLASS(QWidgetPrivate);
QT_FORWARD_DECLARE_CLASS(QWidget);
QT_FORWARD_DECLARE_CLASS(QEvent);
-QT_FORWARD_DECLARE_CLASS(QCocoaDropData);
QT_FORWARD_DECLARE_CLASS(QString);
QT_FORWARD_DECLARE_CLASS(QStringList);
-QT_BEGIN_NAMESPACE
-struct DnDParams
-{
- QT_MANGLE_NAMESPACE(QCocoaView) *view;
- NSEvent *theEvent;
- NSPoint localPoint;
- NSDragOperation performedAction;
- NSPoint activeDragEnterPos;
-};
-
-QT_END_NAMESPACE
-
-QT_FORWARD_DECLARE_STRUCT(DnDParams);
-
Q_GUI_EXPORT
@interface QT_MANGLE_NAMESPACE(QCocoaView) : NSControl <NSTextInput> {
QWidget *qwidget;
QWidgetPrivate *qwidgetprivate;
- bool leftButtonIsRightButton;
- QCocoaDropData *dropData;
NSDragOperation supportedActions;
bool composing;
int composingLength;
bool sendKeyEvents;
bool fromKeyDownEvent;
QString *composingText;
- NSInteger dragEnterSequence;
+ @public int alienTouchCount;
}
- (id)initWithQWidget:(QWidget *)widget widgetPrivate:(QWidgetPrivate *)widgetprivate;
- (void) finishInitWithQWidget:(QWidget *)widget widgetPrivate:(QWidgetPrivate *)widgetprivate;
- (void)frameDidChange:(NSNotification *)note;
-- (NSDragOperation)draggingEntered:(id <NSDraggingInfo>)sender;
-- (NSDragOperation)draggingUpdated:(id < NSDraggingInfo >)sender;
-- (void)draggingExited:(id < NSDraggingInfo >)sender;
-- (BOOL)performDragOperation:(id <NSDraggingInfo>)sender;
-- (void)removeDropData;
-- (void)addDropData:(id <NSDraggingInfo>)sender;
- (void)setSupportedActions:(NSDragOperation)actions;
- (NSDragOperation)draggingSourceOperationMaskForLocal:(BOOL)isLocal;
- (void)draggedImage:(NSImage *)anImage endedAt:(NSPoint)aPoint operation:(NSDragOperation)operation;
- (BOOL)isComposing;
- (QWidget *)qt_qwidget;
- (void) qt_clearQWidget;
-- (BOOL)qt_leftButtonIsRightButton;
-- (void)qt_setLeftButtonIsRightButton:(BOOL)isSwapped;
-- (void)changeDraggingCursor:(NSDragOperation)newOperation;
-+ (DnDParams*)currentMouseEvent;
@end
#endif
diff --git a/src/gui/kernel/qcocoawindow_mac.mm b/src/gui/kernel/qcocoawindow_mac.mm
index 28f09ad..6e5023a 100644
--- a/src/gui/kernel/qcocoawindow_mac.mm
+++ b/src/gui/kernel/qcocoawindow_mac.mm
@@ -47,6 +47,8 @@
#import <private/qt_cocoa_helpers_mac_p.h>
#import <private/qcocoawindowcustomthemeframe_mac_p.h>
#import <private/qcocoaapplication_mac_p.h>
+#import <private/qdnd_p.h>
+#import <private/qmultitouch_mac_p.h>
#include <QtGui/QWidget>
diff --git a/src/gui/kernel/qcocoawindow_mac_p.h b/src/gui/kernel/qcocoawindow_mac_p.h
index 81e0be1..d567cab 100644
--- a/src/gui/kernel/qcocoawindow_mac_p.h
+++ b/src/gui/kernel/qcocoawindow_mac_p.h
@@ -50,17 +50,20 @@
// We mean it.
//
+#ifndef QCOCOAWINDOW_MAC_P
+#define QCOCOAWINDOW_MAC_P
+
#ifdef QT_MAC_USE_COCOA
#include "qmacdefines_mac.h"
#import <Cocoa/Cocoa.h>
#include <private/qapplication_p.h>
#include <private/qbackingstore_p.h>
-
enum { QtMacCustomizeWindow = 1 << 21 }; // This will one day be run over by
QT_FORWARD_DECLARE_CLASS(QWidget);
QT_FORWARD_DECLARE_CLASS(QStringList);
+QT_FORWARD_DECLARE_CLASS(QCocoaDropData);
@interface NSWindow (QtCoverForHackWithCategory)
+ (Class)frameViewClassForStyleMask:(NSUInteger)styleMask;
@@ -71,14 +74,24 @@ QT_FORWARD_DECLARE_CLASS(QStringList);
- (QWidget *)QT_MANGLE_NAMESPACE(qt_qwidget);
@end
+@interface NSWindow (QtIntegration)
+- (NSDragOperation)draggingEntered:(id <NSDraggingInfo>)sender;
+- (NSDragOperation)draggingUpdated:(id <NSDraggingInfo>)sender;
+- (void)draggingExited:(id <NSDraggingInfo>)sender;
+- (BOOL)performDragOperation:(id <NSDraggingInfo>)sender;
+@end
+
@interface QT_MANGLE_NAMESPACE(QCocoaWindow) : NSWindow {
- bool leftButtonIsRightButton;
QStringList *currentCustomDragTypes;
+ QCocoaDropData *dropData;
+ NSInteger dragEnterSequence;
}
+ (Class)frameViewClassForStyleMask:(NSUInteger)styleMask;
- (void)registerDragTypes;
+- (void)drawRectOriginal:(NSRect)rect;
@end
#endif
+#endif
diff --git a/src/gui/kernel/qcocoawindowdelegate_mac.mm b/src/gui/kernel/qcocoawindowdelegate_mac.mm
index b8be627..1faf068 100644
--- a/src/gui/kernel/qcocoawindowdelegate_mac.mm
+++ b/src/gui/kernel/qcocoawindowdelegate_mac.mm
@@ -48,6 +48,9 @@
#include <qlayout.h>
#include <qcoreapplication.h>
#include <qmenubar.h>
+#include <QMainWindow>
+#include <QToolBar>
+#include <private/qmainwindowlayout_p.h>
QT_BEGIN_NAMESPACE
extern QWidgetData *qt_qwidget_data(QWidget *); // qwidget.cpp
@@ -215,6 +218,24 @@ static void cleanupCocoaWindowDelegate()
QWidgetPrivate::qt_mac_update_sizer(qwidget);
[self syncSizeForWidget:qwidget toSize:newSize fromSize:oldSize];
}
+
+ // We force the repaint to be synchronized with the resize of the window.
+ // Otherwise, the resize looks sluggish because we paint one event loop later.
+ if ([[window contentView] inLiveResize]) {
+ qwidget->repaint();
+
+ // We need to repaint the toolbar as well.
+ QMainWindow* mWindow = qobject_cast<QMainWindow*>(qwidget->window());
+ if (mWindow) {
+ QMainWindowLayout *mLayout = qobject_cast<QMainWindowLayout*>(mWindow->layout());
+ QList<QToolBar *> toolbarList = mLayout->qtoolbarsInUnifiedToolbarList;
+
+ for (int i = 0; i < toolbarList.size(); ++i) {
+ QToolBar* toolbar = toolbarList.at(i);
+ toolbar->repaint();
+ }
+ }
+ }
}
- (void)windowDidMove:(NSNotification *)notification
diff --git a/src/gui/kernel/qcursor.h b/src/gui/kernel/qcursor.h
index d90375da..c993763 100644
--- a/src/gui/kernel/qcursor.h
+++ b/src/gui/kernel/qcursor.h
@@ -77,7 +77,7 @@ class QBitmap;
class QPixmap;
#if defined(Q_WS_MAC)
-void qt_mac_set_cursor(const QCursor *c, const QPoint &p);
+void qt_mac_set_cursor(const QCursor *c);
#endif
#if defined(Q_OS_SYMBIAN)
extern void qt_symbian_show_pointer_sprite();
@@ -141,7 +141,8 @@ private:
QCursorData *d;
#if defined(Q_WS_MAC)
friend void *qt_mac_nsCursorForQCursor(const QCursor &c);
- friend void qt_mac_set_cursor(const QCursor *c, const QPoint &p);
+ friend void qt_mac_set_cursor(const QCursor *c);
+ friend void qt_mac_updateCursorWithWidgetUnderMouse(QWidget *widgetUnderMouse);
#endif
#if defined(Q_OS_SYMBIAN)
friend void qt_symbian_show_pointer_sprite();
diff --git a/src/gui/kernel/qcursor_mac.mm b/src/gui/kernel/qcursor_mac.mm
index 1a82a68..0afa3ee 100644
--- a/src/gui/kernel/qcursor_mac.mm
+++ b/src/gui/kernel/qcursor_mac.mm
@@ -50,6 +50,7 @@
#include <AppKit/NSCursor.h>
#include <qpainter.h>
#include <private/qt_cocoa_helpers_mac_p.h>
+#include <private/qapplication_p.h>
QT_BEGIN_NAMESPACE
@@ -60,6 +61,7 @@ extern QCursorData *qt_cursorTable[Qt::LastCursor + 1];
extern OSWindowRef qt_mac_window_for(const QWidget *); //qwidget_mac.cpp
extern GrafPtr qt_mac_qd_context(const QPaintDevice *); //qpaintdevice_mac.cpp
extern bool qt_sendSpontaneousEvent(QObject *, QEvent *); //qapplication_mac.cpp
+extern QPointer<QWidget> qt_button_down; //qapplication_mac.cpp
/*****************************************************************************
Internal QCursorData class
@@ -95,18 +97,19 @@ protected:
}
};
-void *qt_mac_nsCursorForQCursor(const QCursor &c)
+inline void *qt_mac_nsCursorForQCursor(const QCursor &c)
{
c.d->update();
return [[static_cast<NSCursor *>(c.d->curs.cp.nscursor) retain] autorelease];
}
static QCursorData *currentCursor = 0; //current cursor
-void qt_mac_set_cursor(const QCursor *c, const QPoint &)
+
+void qt_mac_set_cursor(const QCursor *c)
{
#ifdef QT_MAC_USE_COCOA
- Q_UNUSED(c);
- return;
+ QMacCocoaAutoReleasePool pool;
+ [static_cast<NSCursor *>(qt_mac_nsCursorForQCursor(*c)) set];
#else
if (!c) {
currentCursor = 0;
@@ -128,35 +131,122 @@ void qt_mac_set_cursor(const QCursor *c, const QPoint &)
c->d->curs.tc.anim->start(c->d->curs.tc.curs);
}
}
+
currentCursor = c->d;
#endif
}
-void qt_mac_update_cursor_at_global_pos(const QPoint &globalPos)
+static QPointer<QWidget> lastWidgetUnderMouse = 0;
+static QPointer<QWidget> lastMouseCursorWidget = 0;
+static bool qt_button_down_on_prev_call = false;
+static QCursor *grabCursor = 0;
+
+void qt_mac_updateCursorWithWidgetUnderMouse(QWidget *widgetUnderMouse)
{
-#ifdef QT_MAC_USE_COCOA
- Q_UNUSED(globalPos);
- return;
-#else
QCursor cursor(Qt::ArrowCursor);
+ if (qt_button_down) {
+ // The widget that is currently pressed
+ // grabs the mouse cursor:
+ widgetUnderMouse = qt_button_down;
+ qt_button_down_on_prev_call = true;
+ } else if (qt_button_down_on_prev_call) {
+ // Grab has been released, so do
+ // a full check:
+ qt_button_down_on_prev_call = false;
+ lastWidgetUnderMouse = 0;
+ lastMouseCursorWidget = 0;
+ }
+
if (QApplication::overrideCursor()) {
cursor = *QApplication::overrideCursor();
- } else {
- for(QWidget *w = QApplication::widgetAt(globalPos); w; w = w->parentWidget()) {
- if(w->testAttribute(Qt::WA_SetCursor)) {
- cursor = w->cursor();
- break;
+ } else if (grabCursor) {
+ cursor = *grabCursor;
+ } else if (widgetUnderMouse) {
+ if (widgetUnderMouse == lastWidgetUnderMouse) {
+ // Optimization that should hit when the widget under
+ // the mouse does not change as the mouse moves:
+ if (lastMouseCursorWidget)
+ cursor = lastMouseCursorWidget->cursor();
+ } else {
+ QWidget *w = widgetUnderMouse;
+ for (; w; w = w->parentWidget()) {
+ if (w->testAttribute(Qt::WA_SetCursor)) {
+ cursor = w->cursor();
+ break;
+ }
+ if (w->isWindow())
+ break;
}
+ // One final check in case we ran out of parents in the loop:
+ if (w && !w->testAttribute(Qt::WA_SetCursor))
+ w = 0;
+
+ lastWidgetUnderMouse = widgetUnderMouse;
+ lastMouseCursorWidget = w;
}
}
- qt_mac_set_cursor(&cursor, globalPos);
+
+#ifdef QT_MAC_USE_COCOA
+ cursor.d->update();
+ NSCursor *nsCursor = static_cast<NSCursor *>(cursor.d->curs.cp.nscursor);
+ if ([NSCursor currentCursor] != nsCursor) {
+ QMacCocoaAutoReleasePool pool;
+ [nsCursor set];
+ }
+#else
+ qt_mac_set_cursor(&cursor);
#endif
}
void qt_mac_update_cursor()
{
- qt_mac_update_cursor_at_global_pos(QCursor::pos());
+ // This function is similar to qt_mac_updateCursorWithWidgetUnderMouse
+ // except that is clears the optimization cache, and finds the widget
+ // under mouse itself. Clearing the cache is useful in cases where the
+ // application has been deactivated/activated etc.
+ // NB: since we dont have any true native widget, the call to
+ // qt_mac_getTargetForMouseEvent will fail when the mouse is over QMacNativeWidgets.
+#ifdef QT_MAC_USE_COCOA
+ lastWidgetUnderMouse = 0;
+ lastMouseCursorWidget = 0;
+ QWidget *widgetUnderMouse = 0;
+
+ if (qt_button_down) {
+ widgetUnderMouse = qt_button_down;
+ } else {
+ QPoint localPoint;
+ QPoint globalPoint;
+ qt_mac_getTargetForMouseEvent(0, QEvent::None, localPoint, globalPoint, 0, &widgetUnderMouse);
+ }
+ qt_mac_updateCursorWithWidgetUnderMouse(widgetUnderMouse);
+#else
+ qt_mac_updateCursorWithWidgetUnderMouse(QApplication::widgetAt(QCursor::pos()));
+#endif
+}
+
+void qt_mac_setMouseGrabCursor(bool set, QCursor *const cursor = 0)
+{
+ if (grabCursor) {
+ delete grabCursor;
+ grabCursor = 0;
+ }
+ if (set) {
+ if (cursor)
+ grabCursor = new QCursor(*cursor);
+ else if (lastMouseCursorWidget)
+ grabCursor = new QCursor(lastMouseCursorWidget->cursor());
+ else
+ grabCursor = new QCursor(Qt::ArrowCursor);
+ }
+ qt_mac_update_cursor();
+}
+
+#ifndef QT_MAC_USE_COCOA
+void qt_mac_update_cursor_at_global_pos(const QPoint &globalPos)
+{
+ qt_mac_updateCursorWithWidgetUnderMouse(QApplication::widgetAt(globalPos));
}
+#endif
static int nextCursorId = Qt::BitmapCursor;
@@ -427,7 +517,8 @@ void QCursorData::update()
break;
case Qt::DragCopyCursor:
type = QCursorData::TYPE_ThemeCursor;
- curs.cp.nscursor = [NSCursor dragCopyCursor];
+ if ([NSCursor respondsToSelector:@selector(dragCopyCursor)])
+ curs.cp.nscursor = [NSCursor performSelector:@selector(dragCopyCursor)];
break;
case Qt::DragMoveCursor:
type = QCursorData::TYPE_ThemeCursor;
@@ -435,7 +526,8 @@ void QCursorData::update()
break;
case Qt::DragLinkCursor:
type = QCursorData::TYPE_ThemeCursor;
- curs.cp.nscursor = [NSCursor dragLinkCursor];
+ if ([NSCursor respondsToSelector:@selector(dragLinkCursor)])
+ curs.cp.nscursor = [NSCursor performSelector:@selector(dragLinkCursor)];
break;
#define QT_USE_APPROXIMATE_CURSORS
#ifdef QT_USE_APPROXIMATE_CURSORS
diff --git a/src/gui/kernel/qcursor_s60.cpp b/src/gui/kernel/qcursor_s60.cpp
index d1e58b1..8dfe87e 100644
--- a/src/gui/kernel/qcursor_s60.cpp
+++ b/src/gui/kernel/qcursor_s60.cpp
@@ -472,9 +472,9 @@ void qt_symbian_setWindowGroupCursor(const QCursor &cursor, RWindowTreeNode &nod
if (handle) {
RWsPointerCursor *pcurs = reinterpret_cast<RWsPointerCursor *> (handle);
node.SetCustomPointerCursor(*pcurs);
- }
+ } else
#ifdef Q_SYMBIAN_HAS_SYSTEM_CURSORS
- else {
+ {
TInt shape = qt_symbian_translate_cursor_shape(cursor.shape());
node.SetPointerCursor(shape);
}
diff --git a/src/gui/kernel/qdesktopwidget_qpa_p.h b/src/gui/kernel/qdesktopwidget_qpa_p.h
index 4e46d64..abee8a1 100644
--- a/src/gui/kernel/qdesktopwidget_qpa_p.h
+++ b/src/gui/kernel/qdesktopwidget_qpa_p.h
@@ -59,7 +59,13 @@
class QDesktopScreenWidget : public QWidget {
Q_OBJECT
public:
- QDesktopScreenWidget(int screenNumber = -1) { setWindowFlags(Qt::Desktop); setVisible(false); d_func()->screenNumber = screenNumber; }
+ QDesktopScreenWidget(int screenNumber = -1)
+ {
+ setWindowFlags(Qt::Desktop);
+ setVisible(false);
+ QTLWExtra *topData = d_func()->topData();
+ topData->screenIndex = screenNumber;
+ }
};
class QDesktopWidgetPrivate : public QWidgetPrivate {
diff --git a/src/gui/kernel/qdesktopwidget_s60.cpp b/src/gui/kernel/qdesktopwidget_s60.cpp
index 3653ae2..62a4d40 100644
--- a/src/gui/kernel/qdesktopwidget_s60.cpp
+++ b/src/gui/kernel/qdesktopwidget_s60.cpp
@@ -44,36 +44,67 @@
#include "qwidget_p.h"
#include "qt_s60_p.h"
#include <w32std.h>
-
-#include "hal.h"
-#include "hal_data.h"
+#if defined(Q_SYMBIAN_SUPPORTS_MULTIPLE_SCREENS)
+#include <graphics/displaycontrol.h>
+#endif
QT_BEGIN_NAMESPACE
-class QDesktopWidgetPrivate : public QWidgetPrivate
+extern int qt_symbian_create_desktop_on_screen;
+
+class QSingleDesktopWidget : public QWidget
+{
+public:
+ QSingleDesktopWidget();
+ ~QSingleDesktopWidget();
+};
+
+QSingleDesktopWidget::QSingleDesktopWidget()
+ : QWidget(0, Qt::Desktop)
+{
+}
+
+QSingleDesktopWidget::~QSingleDesktopWidget()
{
+ const QObjectList &childList = children();
+ for (int i = childList.size(); i > 0 ;) {
+ --i;
+ childList.at(i)->setParent(0);
+ }
+}
+class QDesktopWidgetPrivate : public QWidgetPrivate
+{
public:
QDesktopWidgetPrivate();
~QDesktopWidgetPrivate();
-
static void init(QDesktopWidget *that);
static void cleanup();
+ static void init_sys();
static int screenCount;
static int primaryScreen;
static QVector<QRect> *rects;
static QVector<QRect> *workrects;
+ static QVector<QWidget *> *screens;
static int refcount;
+
+#if defined(Q_SYMBIAN_SUPPORTS_MULTIPLE_SCREENS)
+ static MDisplayControl *displayControl;
+#endif
};
int QDesktopWidgetPrivate::screenCount = 1;
int QDesktopWidgetPrivate::primaryScreen = 0;
QVector<QRect> *QDesktopWidgetPrivate::rects = 0;
QVector<QRect> *QDesktopWidgetPrivate::workrects = 0;
+QVector<QWidget *> *QDesktopWidgetPrivate::screens = 0;
int QDesktopWidgetPrivate::refcount = 0;
+#if defined(Q_SYMBIAN_SUPPORTS_MULTIPLE_SCREENS)
+MDisplayControl *QDesktopWidgetPrivate::displayControl = 0;
+#endif
QDesktopWidgetPrivate::QDesktopWidgetPrivate()
{
@@ -88,25 +119,55 @@ QDesktopWidgetPrivate::~QDesktopWidgetPrivate()
void QDesktopWidgetPrivate::init(QDesktopWidget *that)
{
- Q_UNUSED(that);
-// int screenCount=0;
-
- // ### TODO: Implement proper multi-display support
- QDesktopWidgetPrivate::screenCount = 1;
-// if (HAL::Get(0, HALData::EDisplayNumberOfScreens, screenCount) == KErrNone)
-// QDesktopWidgetPrivate::screenCount = screenCount;
-// else
-// QDesktopWidgetPrivate::screenCount = 0;
+ // Note that on S^3 devices the screen count retrieved via RWsSession
+ // will always be 2 but the width and height for screen number 1 will
+ // be 0 as long as TV-out is not connected.
+ //
+ // On the other hand a valid size for screen 1 will be reported even
+ // after the cable is disconnected. In order to overcome this, we use
+ // MDisplayControl::NumberOfResolutions() to check if the display is
+ // valid or not.
+
+ screenCount = S60->screenCount();
+#if defined(Q_SYMBIAN_SUPPORTS_MULTIPLE_SCREENS)
+ if (displayControl) {
+ if (displayControl->NumberOfResolutions() < 1)
+ screenCount = 1;
+ }
+#endif
+ if (screenCount < 1) {
+ qWarning("No screen available");
+ screenCount = 1;
+ }
rects = new QVector<QRect>();
workrects = new QVector<QRect>();
-
- rects->resize(QDesktopWidgetPrivate::screenCount);
- workrects->resize(QDesktopWidgetPrivate::screenCount);
-
- (*rects)[0].setRect(0, 0, S60->screenWidthInPixels, S60->screenHeightInPixels);
- QRect wr = qt_TRect2QRect(static_cast<CEikAppUi*>(S60->appUi())->ClientRect());
- (*workrects)[0].setRect(wr.x(), wr.y(), wr.width(), wr.height());
+ screens = new QVector<QWidget *>();
+
+ rects->resize(screenCount);
+ workrects->resize(screenCount);
+ screens->resize(screenCount);
+
+ for (int i = 0; i < screenCount; ++i) {
+ // All screens will have a position of (0, 0) as there is no true virtual desktop
+ // or pointer event support for multiple screens on Symbian.
+ QRect r(0, 0,
+ S60->screenWidthInPixelsForScreen[i], S60->screenHeightInPixelsForScreen[i]);
+ // Stop here if empty and ignore this screen.
+ if (r.isEmpty()) {
+ screenCount = i;
+ break;
+ }
+ (*rects)[i] = r;
+ QRect wr;
+ if (i == 0)
+ wr = qt_TRect2QRect(static_cast<CEikAppUi*>(S60->appUi())->ClientRect());
+ else
+ wr = rects->at(i);
+ (*workrects)[i].setRect(wr.x(), wr.y(), wr.width(), wr.height());
+ (*screens)[i] = 0;
+ }
+ (*screens)[0] = that;
}
void QDesktopWidgetPrivate::cleanup()
@@ -115,6 +176,29 @@ void QDesktopWidgetPrivate::cleanup()
rects = 0;
delete workrects;
workrects = 0;
+ if (screens) {
+ // First item is the QDesktopWidget so skip it.
+ for (int i = 1; i < screens->count(); ++i)
+ delete screens->at(i);
+ }
+ delete screens;
+ screens = 0;
+}
+
+void QDesktopWidgetPrivate::init_sys()
+{
+#if defined(Q_SYMBIAN_SUPPORTS_MULTIPLE_SCREENS)
+ if (S60->screenCount() > 1) {
+ CWsScreenDevice *dev = S60->screenDevice(1);
+ if (dev) {
+ displayControl = static_cast<MDisplayControl *>(
+ dev->GetInterface(MDisplayControl::ETypeId));
+ if (displayControl) {
+ displayControl->EnableDisplayChangeEvents(ETrue);
+ }
+ }
+ }
+#endif
}
@@ -122,6 +206,7 @@ QDesktopWidget::QDesktopWidget()
: QWidget(*new QDesktopWidgetPrivate, 0, Qt::Desktop)
{
setObjectName(QLatin1String("desktop"));
+ QDesktopWidgetPrivate::init_sys();
QDesktopWidgetPrivate::init(this);
}
@@ -131,7 +216,7 @@ QDesktopWidget::~QDesktopWidget()
bool QDesktopWidget::isVirtualDesktop() const
{
- return true;
+ return false;
}
int QDesktopWidget::primaryScreen() const
@@ -145,9 +230,23 @@ int QDesktopWidget::numScreens() const
return QDesktopWidgetPrivate::screenCount;
}
-QWidget *QDesktopWidget::screen(int /* screen */)
+static inline QWidget *newSingleDesktopWidget(int screen)
{
- return this;
+ qt_symbian_create_desktop_on_screen = screen;
+ QWidget *w = new QSingleDesktopWidget;
+ qt_symbian_create_desktop_on_screen = -1;
+ return w;
+}
+
+QWidget *QDesktopWidget::screen(int screen)
+{
+ Q_D(QDesktopWidget);
+ if (screen < 0 || screen >= d->screenCount)
+ screen = d->primaryScreen;
+ if (!d->screens->at(screen)
+ || d->screens->at(screen)->windowType() != Qt::Desktop)
+ (*d->screens)[screen] = newSingleDesktopWidget(screen);
+ return (*d->screens)[screen];
}
const QRect QDesktopWidget::availableGeometry(int screen) const
@@ -168,14 +267,19 @@ const QRect QDesktopWidget::screenGeometry(int screen) const
return d->rects->at(screen);
}
-int QDesktopWidget::screenNumber(const QWidget * /* widget */) const
+int QDesktopWidget::screenNumber(const QWidget *widget) const
{
- return QDesktopWidgetPrivate::primaryScreen;
+ Q_D(const QDesktopWidget);
+ return widget
+ ? S60->screenNumberForWidget(widget)
+ : d->primaryScreen;
}
-int QDesktopWidget::screenNumber(const QPoint & /* point */) const
+int QDesktopWidget::screenNumber(const QPoint &point) const
{
- return QDesktopWidgetPrivate::primaryScreen;
+ Q_UNUSED(point);
+ Q_D(const QDesktopWidget);
+ return d->primaryScreen;
}
void QDesktopWidget::resizeEvent(QResizeEvent *)
@@ -203,6 +307,10 @@ void QDesktopWidget::resizeEvent(QResizeEvent *)
if (oldrect != newrect)
emit workAreaResized(j);
}
+
+ if (oldscreencount != d->screenCount) {
+ emit screenCountChanged(d->screenCount);
+ }
}
QT_END_NAMESPACE
diff --git a/src/gui/kernel/qdnd_mac.mm b/src/gui/kernel/qdnd_mac.mm
index d630faa..3af2ba0 100644
--- a/src/gui/kernel/qdnd_mac.mm
+++ b/src/gui/kernel/qdnd_mac.mm
@@ -491,7 +491,7 @@ bool QWidgetPrivate::qt_mac_dnd_event(uint kind, DragRef dragRef)
SetThemeCursor(cursor);
}
if(found_cursor) {
- qt_mac_set_cursor(0, QPoint()); //just use our's
+ qt_mac_set_cursor(0); //just use our's
} else {
QCursor cursor(Qt::ArrowCursor);
if(qApp && qApp->overrideCursor()) {
@@ -504,7 +504,7 @@ bool QWidgetPrivate::qt_mac_dnd_event(uint kind, DragRef dragRef)
}
}
}
- qt_mac_set_cursor(&cursor, QPoint(mouse.h, mouse.v));
+ qt_mac_set_cursor(&cursor);
}
//idle things
diff --git a/src/gui/kernel/qdnd_p.h b/src/gui/kernel/qdnd_p.h
index 9a55b18..7543666 100644
--- a/src/gui/kernel/qdnd_p.h
+++ b/src/gui/kernel/qdnd_p.h
@@ -76,7 +76,7 @@ class QEventLoop;
#if !(defined(QT_NO_DRAGANDDROP) && defined(QT_NO_CLIPBOARD))
-class QInternalMimeData : public QMimeData
+class Q_GUI_EXPORT QInternalMimeData : public QMimeData
{
Q_OBJECT
public:
diff --git a/src/gui/kernel/qevent.cpp b/src/gui/kernel/qevent.cpp
index e7abb47..277a5e8 100644
--- a/src/gui/kernel/qevent.cpp
+++ b/src/gui/kernel/qevent.cpp
@@ -43,6 +43,7 @@
#include "qcursor.h"
#include "qapplication.h"
#include "private/qapplication_p.h"
+#include "private/qevent_p.h"
#include "private/qkeysequence_p.h"
#include "qwidget.h"
#include "qgraphicsview.h"
@@ -53,6 +54,10 @@
#include "qgesture.h"
#include "qgesture_p.h"
+#ifdef Q_OS_SYMBIAN
+#include "private/qcore_symbian_p.h"
+#endif
+
QT_BEGIN_NAMESPACE
/*!
@@ -724,12 +729,12 @@ QWheelEvent::QWheelEvent(const QPoint &pos, const QPoint& globalPos, int delta,
The \a type parameter must be QEvent::KeyPress, QEvent::KeyRelease,
or QEvent::ShortcutOverride.
- Int \a key is the code for the Qt::Key that the event loop should listen
- for. If \a key is 0, the event is not a result of a known key; for
+ Int \a key is the code for the Qt::Key that the event loop should listen
+ for. If \a key is 0, the event is not a result of a known key; for
example, it may be the result of a compose sequence or keyboard macro.
- The \a modifiers holds the keyboard modifiers, and the given \a text
- is the Unicode text that the key generated. If \a autorep is true,
- isAutoRepeat() will be true. \a count is the number of keys involved
+ The \a modifiers holds the keyboard modifiers, and the given \a text
+ is the Unicode text that the key generated. If \a autorep is true,
+ isAutoRepeat() will be true. \a count is the number of keys involved
in the event.
*/
QKeyEvent::QKeyEvent(Type type, int key, Qt::KeyboardModifiers modifiers, const QString& text,
@@ -1658,7 +1663,7 @@ Qt::ButtonState QContextMenuEvent::state() const
string is controlled by the widget only). The AttributeType enum
describes the different attributes that can be set.
- A class implementing QWidget::inputMethodEvent() or
+ A class implementing QWidget::inputMethodEvent() or
QGraphicsItem::inputMethodEvent() should at least understand and
honor the \l TextFormat and \l Cursor attributes.
@@ -3023,9 +3028,16 @@ QShowEvent::~QShowEvent()
This event is only used to notify the application of a request.
It may be safely ignored.
- \note This class is currently supported for Mac OS X only.
+ \note This class is currently supported for Mac OS X and Symbian only.
*/
+QFileOpenEventPrivate::~QFileOpenEventPrivate()
+{
+#ifdef Q_OS_SYMBIAN
+ file.Close();
+#endif
+}
+
/*!
\internal
@@ -3049,6 +3061,22 @@ QFileOpenEvent::QFileOpenEvent(const QUrl &url)
f = url.toLocalFile();
}
+#ifdef Q_OS_SYMBIAN
+/*! \internal
+*/
+QFileOpenEvent::QFileOpenEvent(const RFile &fileHandle)
+ : QEvent(FileOpen)
+{
+ TFileName fullName;
+ fileHandle.FullName(fullName);
+ f = qt_TDesC2QString(fullName);
+ QScopedPointer<QFileOpenEventPrivate> priv(new QFileOpenEventPrivate(QUrl::fromLocalFile(f)));
+ // Duplicate here allows the file handle to be valid after S60 app construction is complete.
+ qt_symbian_throwIfError(priv->file.Duplicate(fileHandle));
+ d = reinterpret_cast<QEventPrivate *>(priv.take());
+}
+#endif
+
/*! \internal
*/
QFileOpenEvent::~QFileOpenEvent()
@@ -3074,6 +3102,39 @@ QUrl QFileOpenEvent::url() const
return reinterpret_cast<const QFileOpenEventPrivate *>(d)->url;
}
+/*!
+ \fn bool openFile(QFile &file, QIODevice::OpenMode flags) const
+
+ Opens a QFile on the file referenced by this event.
+ Returns true if successful; otherwise returns false.
+
+ This is necessary as some files cannot be opened by name, but require specific
+ information stored in this event.
+ For example, if this QFileOpenEvent contains a request to open a Symbian data caged file,
+ the QFile could only be opened from the Symbian RFile used in the construction of this event.
+
+ \since 4.8
+*/
+bool QFileOpenEvent::openFile(QFile &file, QIODevice::OpenMode flags) const
+{
+ file.setFileName(f);
+#ifdef Q_OS_SYMBIAN
+ const QFileOpenEventPrivate *priv = reinterpret_cast<const QFileOpenEventPrivate *>(d);
+ if (priv->file.SubSessionHandle()) {
+ RFile dup;
+ // Duplicate here means that the opened QFile will continue to be valid beyond the lifetime of this QFileOpenEvent.
+ // It also allows openFile to be used in threads other than the thread in which the QFileOpenEvent was created.
+ if (dup.Duplicate(priv->file) == KErrNone) {
+ QScopedPointer<RFile, QScopedPointerRCloser<RFile> > dupCloser(&dup);
+ bool open = file.open(dup, flags, QFile::AutoCloseHandle);
+ dupCloser.take();
+ return open;
+ }
+ }
+#endif
+ return file.open(flags);
+}
+
#ifndef QT_NO_TOOLBAR
/*!
\internal
@@ -3622,7 +3683,7 @@ QMenubarUpdatedEvent::QMenubarUpdatedEvent(QMenuBar * const menuBar)
#endif
-/*!
+/*!
\class QTouchEvent
\brief The QTouchEvent class contains parameters that describe a touch event.
\since 4.6
diff --git a/src/gui/kernel/qevent.h b/src/gui/kernel/qevent.h
index a7b06f4..93c2bc5 100644
--- a/src/gui/kernel/qevent.h
+++ b/src/gui/kernel/qevent.h
@@ -54,6 +54,11 @@
#include <QtCore/qvariant.h>
#include <QtCore/qmap.h>
#include <QtCore/qset.h>
+#include <QtCore/qfile.h>
+
+#ifdef Q_OS_SYMBIAN
+class RFile;
+#endif
QT_BEGIN_HEADER
@@ -641,10 +646,14 @@ class Q_GUI_EXPORT QFileOpenEvent : public QEvent
public:
QFileOpenEvent(const QString &file);
QFileOpenEvent(const QUrl &url);
+#ifdef Q_OS_SYMBIAN
+ QFileOpenEvent(const RFile &fileHandle);
+#endif
~QFileOpenEvent();
inline QString file() const { return f; }
QUrl url() const;
+ bool openFile(QFile &file, QIODevice::OpenMode flags) const;
private:
QString f;
};
diff --git a/src/gui/kernel/qevent_p.h b/src/gui/kernel/qevent_p.h
index 3a27023..b79f372 100644
--- a/src/gui/kernel/qevent_p.h
+++ b/src/gui/kernel/qevent_p.h
@@ -46,6 +46,10 @@
#include <QtCore/qurl.h>
#include <QtGui/qevent.h>
+#ifdef Q_OS_SYMBIAN
+#include <f32file.h>
+#endif
+
QT_BEGIN_NAMESPACE
//
@@ -174,8 +178,12 @@ public:
: url(url)
{
}
+ ~QFileOpenEventPrivate();
QUrl url;
+#ifdef Q_OS_SYMBIAN
+ RFile file;
+#endif
};
diff --git a/src/gui/kernel/qeventdispatcher_mac.mm b/src/gui/kernel/qeventdispatcher_mac.mm
index 15410ad..677a736 100644
--- a/src/gui/kernel/qeventdispatcher_mac.mm
+++ b/src/gui/kernel/qeventdispatcher_mac.mm
@@ -561,6 +561,7 @@ bool QEventDispatcherMac::processEvents(QEventLoop::ProcessEventsFlags flags)
wakeUp();
emit awake();
+ bool excludeUserEvents = flags & QEventLoop::ExcludeUserInputEvents;
bool retVal = false;
forever {
if (d->interrupt)
@@ -571,7 +572,7 @@ bool QEventDispatcherMac::processEvents(QEventLoop::ProcessEventsFlags flags)
NSEvent* event = 0;
// First, send all previously excluded input events, if any:
- if (!(flags & QEventLoop::ExcludeUserInputEvents)) {
+ if (!excludeUserEvents) {
while (!d->queuedUserInputEvents.isEmpty()) {
event = static_cast<NSEvent *>(d->queuedUserInputEvents.takeFirst());
if (!filterEvent(event)) {
@@ -586,12 +587,12 @@ bool QEventDispatcherMac::processEvents(QEventLoop::ProcessEventsFlags flags)
// application, we should not run or stop NSApplication; This will be
// done from the application itself. And if processEvents is called
// manually (rather than from a QEventLoop), we cannot enter a tight
- // loop and block this call, but instead we need to return after one flush:
+ // loop and block this call, but instead we need to return after one flush.
+ // Finally, if we are to exclude user input events, we cannot call [NSApp run]
+ // as we then loose control over which events gets dispatched:
const bool canExec_3rdParty = d->nsAppRunCalledByQt || ![NSApp isRunning];
- const bool canExec_Qt =
- (flags & QEventLoop::DialogExec || flags & QEventLoop::EventLoopExec)
- && !(flags & QEventLoop::ExcludeUserInputEvents);
-
+ const bool canExec_Qt = !excludeUserEvents &&
+ (flags & QEventLoop::DialogExec || flags & QEventLoop::EventLoopExec) ;
if (canExec_Qt && canExec_3rdParty) {
// We can use exec-mode, meaning that we can stay in a tight loop until
@@ -619,22 +620,46 @@ bool QEventDispatcherMac::processEvents(QEventLoop::ProcessEventsFlags flags)
// Instead we will process all current pending events and return.
d->ensureNSAppInitialized();
if (NSModalSession session = d->currentModalSession()) {
- if (flags & QEventLoop::WaitForMoreEvents)
- qt_mac_waitForMoreModalSessionEvents();
- NSInteger status = [NSApp runModalSession:session];
- if (status != NSRunContinuesResponse && session == d->currentModalSessionCached) {
- // INVARIANT: Someone called [NSApp stopModal:] from outside the event
- // dispatcher (e.g to stop a native dialog). But that call wrongly stopped
- // 'session' as well. As a result, we need to restart all internal sessions:
- d->temporarilyStopAllModalSessions();
- }
- retVal = true;
- } else do {
- event = [NSApp nextEventMatchingMask:NSAnyEventMask
+ // INVARIANT: a modal window is executing.
+ if (!excludeUserEvents) {
+ // Since we can dispatch all kinds of events, we choose
+ // to use cocoa's native way of running modal sessions:
+ if (flags & QEventLoop::WaitForMoreEvents)
+ qt_mac_waitForMoreModalSessionEvents();
+ NSInteger status = [NSApp runModalSession:session];
+ if (status != NSRunContinuesResponse && session == d->currentModalSessionCached) {
+ // INVARIANT: Someone called [NSApp stopModal:] from outside the event
+ // dispatcher (e.g to stop a native dialog). But that call wrongly stopped
+ // 'session' as well. As a result, we need to restart all internal sessions:
+ d->temporarilyStopAllModalSessions();
+ }
+ retVal = true;
+ } else do {
+ // Dispatch all non-user events (but que non-user events up for later). In
+ // this case, we need more control over which events gets dispatched, and
+ // cannot use [NSApp runModalSession:session]:
+ event = [NSApp nextEventMatchingMask:NSAnyEventMask
untilDate:nil
- inMode:NSDefaultRunLoopMode
+ inMode:NSModalPanelRunLoopMode
dequeue: YES];
+ if (event) {
+ if (IsMouseOrKeyEvent(event)) {
+ [event retain];
+ d->queuedUserInputEvents.append(event);
+ continue;
+ }
+ if (!filterEvent(event) && qt_mac_send_event(flags, event, 0))
+ retVal = true;
+ }
+ } while (!d->interrupt && event != nil);
+ } else do {
+ // INVARIANT: No modal window is executing.
+ event = [NSApp nextEventMatchingMask:NSAnyEventMask
+ untilDate:nil
+ inMode:NSDefaultRunLoopMode
+ dequeue: YES];
+
if (event) {
if (flags & QEventLoop::ExcludeUserInputEvents) {
if (IsMouseOrKeyEvent(event)) {
@@ -648,6 +673,11 @@ bool QEventDispatcherMac::processEvents(QEventLoop::ProcessEventsFlags flags)
}
} while (!d->interrupt && event != nil);
+ // Be sure to flush the Qt posted events when not using exec mode
+ // (exec mode will always do this call from the event loop source):
+ if (!d->interrupt)
+ QCoreApplicationPrivate::sendPostedEvents(0, 0, d->threadData);
+
// Since the window that holds modality might have changed while processing
// events, we we need to interrupt when we return back the previous process
// event recursion to ensure that we spin the correct modal session.
diff --git a/src/gui/kernel/qeventdispatcher_qpa.cpp b/src/gui/kernel/qeventdispatcher_qpa.cpp
index 7701612..de53618 100644
--- a/src/gui/kernel/qeventdispatcher_qpa.cpp
+++ b/src/gui/kernel/qeventdispatcher_qpa.cpp
@@ -172,7 +172,6 @@ public:
{
if (qApp && (qApp->thread() == QThread::currentThread())) {
m_isEventLoopIntegrationRunning = true;
- QCoreApplication::processEvents(QEventLoop::WaitForMoreEvents);
eventLoopIntegration->startEventLoop();
}
}
diff --git a/src/gui/kernel/qgesture.cpp b/src/gui/kernel/qgesture.cpp
index 17ede02..56daba2 100644
--- a/src/gui/kernel/qgesture.cpp
+++ b/src/gui/kernel/qgesture.cpp
@@ -332,7 +332,7 @@ void QPanGesture::setAcceleration(qreal value)
/*!
\class QPinchGesture
\since 4.6
- \brief The QPinchGesture class describes a pinch gesture made my the user.
+ \brief The QPinchGesture class describes a pinch gesture made by the user.
\ingroup touch
\ingroup gestures
diff --git a/src/gui/kernel/qkeymapper_p.h b/src/gui/kernel/qkeymapper_p.h
index 7a7c6a5..ec2d849 100644
--- a/src/gui/kernel/qkeymapper_p.h
+++ b/src/gui/kernel/qkeymapper_p.h
@@ -213,6 +213,7 @@ public:
int mapS60ScanCodesToQt(TUint s60key);
int mapQtToS60Key(int qtKey);
int mapQtToS60ScanCodes(int qtKey);
+ void updateInputLanguage();
#endif
};
diff --git a/src/gui/kernel/qkeymapper_s60.cpp b/src/gui/kernel/qkeymapper_s60.cpp
index f0b17ac..bcf32a5 100644
--- a/src/gui/kernel/qkeymapper_s60.cpp
+++ b/src/gui/kernel/qkeymapper_s60.cpp
@@ -40,7 +40,11 @@
****************************************************************************/
#include "private/qkeymapper_p.h"
+#include <private/qcore_symbian_p.h>
#include <e32keys.h>
+#include <e32cmn.h>
+#include <centralrepository.h>
+#include <biditext.h>
QT_BEGIN_NAMESPACE
@@ -214,4 +218,32 @@ int QKeyMapperPrivate::mapQtToS60ScanCodes(int qtKey)
}
return res;
}
+
+void QKeyMapperPrivate::updateInputLanguage()
+{
+#ifdef Q_WS_S60
+ TInt err;
+ CRepository *repo;
+ const TUid KCRUidAknFep = TUid::Uid(0x101F876D);
+ const TUint32 KAknFepInputTxtLang = 0x00000005;
+ TRAP(err, repo = CRepository::NewL(KCRUidAknFep));
+ if (err != KErrNone)
+ return;
+
+ TInt symbianLang;
+ err = repo->Get(KAknFepInputTxtLang, symbianLang);
+ delete repo;
+ if (err != KErrNone)
+ return;
+
+ QString qtLang = QString::fromAscii(qt_symbianLocaleName(symbianLang));
+ keyboardInputLocale = QLocale(qtLang);
+ keyboardInputDirection = (TBidiText::ScriptDirectionality(TLanguage(symbianLang)) == TBidiText::ERightToLeft)
+ ? Qt::RightToLeft : Qt::LeftToRight;
+#else
+ keyboardInputLocale = QLocale();
+ keyboardInputDirection = Qt::LeftToRight;
+#endif
+}
+
QT_END_NAMESPACE
diff --git a/src/gui/kernel/qkeymapper_x11_p.cpp b/src/gui/kernel/qkeymapper_x11_p.cpp
index 1fad4b0..2dbe1e7 100644
--- a/src/gui/kernel/qkeymapper_x11_p.cpp
+++ b/src/gui/kernel/qkeymapper_x11_p.cpp
@@ -40,6 +40,7 @@
****************************************************************************/
// This file is auto-generated, do not edit!
+// (Generated using util/xkbdatagen)
static struct {
const char *layout;
diff --git a/src/gui/kernel/qlayout.cpp b/src/gui/kernel/qlayout.cpp
index 1eeaf8e..e014ec8 100644
--- a/src/gui/kernel/qlayout.cpp
+++ b/src/gui/kernel/qlayout.cpp
@@ -980,10 +980,10 @@ void QLayoutPrivate::reparentChildWidgets(QWidget *mw)
/*!
This function is called from \c addWidget() functions in
- subclasses to add \a w as a child widget.
+ subclasses to add \a w as a managed widget of a layout.
- If \a w is already in a layout, this function will give a warning
- and remove \a w from the layout. This function must therefore be
+ If \a w is already managed by a layout, this function will give a warning
+ and remove \a w from that layout. This function must therefore be
called before adding \a w to the layout's data structure.
*/
void QLayout::addChildWidget(QWidget *w)
diff --git a/src/gui/kernel/qmacgesturerecognizer_mac.mm b/src/gui/kernel/qmacgesturerecognizer_mac.mm
index 0e432f3..6a4f0bb 100644
--- a/src/gui/kernel/qmacgesturerecognizer_mac.mm
+++ b/src/gui/kernel/qmacgesturerecognizer_mac.mm
@@ -69,6 +69,7 @@ QMacSwipeGestureRecognizer::recognize(QGesture *gesture, QObject *obj, QEvent *e
case QNativeGestureEvent::Swipe: {
QSwipeGesture *g = static_cast<QSwipeGesture *>(gesture);
g->setSwipeAngle(ev->angle);
+ g->setHotSpot(ev->position);
return QGestureRecognizer::FinishGesture | QGestureRecognizer::ConsumeEventHint;
break; }
default:
@@ -110,6 +111,7 @@ QMacPinchGestureRecognizer::recognize(QGesture *gesture, QObject *obj, QEvent *e
g->setCenterPoint(g->startCenterPoint());
g->setChangeFlags(QPinchGesture::CenterPointChanged);
g->setTotalChangeFlags(g->totalChangeFlags() | g->changeFlags());
+ g->setHotSpot(ev->position);
return QGestureRecognizer::MayBeGesture | QGestureRecognizer::ConsumeEventHint;
case QNativeGestureEvent::Rotate: {
g->setLastScaleFactor(g->scaleFactor());
@@ -117,6 +119,7 @@ QMacPinchGestureRecognizer::recognize(QGesture *gesture, QObject *obj, QEvent *e
g->setRotationAngle(g->rotationAngle() + ev->percentage);
g->setChangeFlags(QPinchGesture::RotationAngleChanged);
g->setTotalChangeFlags(g->totalChangeFlags() | g->changeFlags());
+ g->setHotSpot(ev->position);
return QGestureRecognizer::TriggerGesture | QGestureRecognizer::ConsumeEventHint;
}
case QNativeGestureEvent::Zoom:
@@ -125,6 +128,7 @@ QMacPinchGestureRecognizer::recognize(QGesture *gesture, QObject *obj, QEvent *e
g->setScaleFactor(g->scaleFactor() * (1 + ev->percentage));
g->setChangeFlags(QPinchGesture::ScaleFactorChanged);
g->setTotalChangeFlags(g->totalChangeFlags() | g->changeFlags());
+ g->setHotSpot(ev->position);
return QGestureRecognizer::TriggerGesture | QGestureRecognizer::ConsumeEventHint;
case QNativeGestureEvent::GestureEnd:
return QGestureRecognizer::FinishGesture | QGestureRecognizer::ConsumeEventHint;
@@ -221,6 +225,7 @@ QMacPanGestureRecognizer::recognize(QGesture *gesture, QObject *target, QEvent *
const QPointF posOffset = p - _startPos;
g->setLastOffset(g->offset());
g->setOffset(QPointF(posOffset.x(), posOffset.y()));
+ g->setHotSpot(_startPos);
return QGestureRecognizer::TriggerGesture;
}
} else if (_panTimer.isActive()) {
@@ -239,6 +244,7 @@ QMacPanGestureRecognizer::recognize(QGesture *gesture, QObject *target, QEvent *
break;
// Begin new pan session!
_startPos = QCursor::pos();
+ g->setHotSpot(_startPos);
return QGestureRecognizer::TriggerGesture | QGestureRecognizer::ConsumeEventHint;
}
break; }
diff --git a/src/gui/kernel/qplatformclipboard_qpa.cpp b/src/gui/kernel/qplatformclipboard_qpa.cpp
new file mode 100644
index 0000000..957a4df
--- /dev/null
+++ b/src/gui/kernel/qplatformclipboard_qpa.cpp
@@ -0,0 +1,105 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 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 "qplatformclipboard_qpa.h"
+
+#ifndef QT_NO_CLIPBOARD
+
+QT_BEGIN_NAMESPACE
+
+class QClipboardData
+{
+public:
+ QClipboardData();
+ ~QClipboardData();
+
+ void setSource(QMimeData* s)
+ {
+ if (s == src)
+ return;
+ delete src;
+ src = s;
+ }
+ QMimeData* source()
+ { return src; }
+
+private:
+ QMimeData* src;
+};
+
+QClipboardData::QClipboardData()
+{
+ src = 0;
+}
+
+QClipboardData::~QClipboardData()
+{
+ delete src;
+}
+
+Q_GLOBAL_STATIC(QClipboardData,q_clipboardData);
+
+QPlatformClipboard::~QPlatformClipboard()
+{
+
+}
+
+const QMimeData *QPlatformClipboard::mimeData(QClipboard::Mode mode) const
+{
+ //we know its clipboard
+ Q_UNUSED(mode);
+ return q_clipboardData()->source();
+}
+
+void QPlatformClipboard::setMimeData(QMimeData *data, QClipboard::Mode mode)
+{
+ //we know its clipboard
+ Q_UNUSED(mode);
+ q_clipboardData()->setSource(data);
+}
+
+bool QPlatformClipboard::supportsMode(QClipboard::Mode mode) const
+{
+ return mode == QClipboard::Clipboard;
+}
+
+QT_END_NAMESPACE
+
+#endif //QT_NO_CLIPBOARD
diff --git a/src/gui/kernel/qplatformclipboard_qpa.h b/src/gui/kernel/qplatformclipboard_qpa.h
new file mode 100644
index 0000000..3381c06
--- /dev/null
+++ b/src/gui/kernel/qplatformclipboard_qpa.h
@@ -0,0 +1,73 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 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$
+**
+****************************************************************************/
+
+#ifndef QPLATFORMCLIPBOARD_QPA_H
+#define QPLATFORMCLIPBOARD_QPA_H
+
+#include <qplatformdefs.h>
+
+#ifndef QT_NO_CLIPBOARD
+
+#include <QtGui/QClipboard>
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+QT_MODULE(Gui)
+
+class Q_GUI_EXPORT QPlatformClipboard
+{
+public:
+ virtual ~QPlatformClipboard();
+
+ virtual const QMimeData *mimeData(QClipboard::Mode mode = QClipboard::Clipboard ) const;
+ virtual void setMimeData(QMimeData *data, QClipboard::Mode mode = QClipboard::Clipboard);
+ virtual bool supportsMode(QClipboard::Mode mode) const;
+};
+
+QT_END_NAMESPACE
+
+QT_END_HEADER
+
+#endif // QT_NO_CLIPBOARD
+
+#endif //QPLATFORMCLIPBOARD_QPA_H
diff --git a/src/gui/kernel/qplatformglcontext_qpa.cpp b/src/gui/kernel/qplatformglcontext_qpa.cpp
index 1e5fd24..86740e8 100644
--- a/src/gui/kernel/qplatformglcontext_qpa.cpp
+++ b/src/gui/kernel/qplatformglcontext_qpa.cpp
@@ -138,7 +138,7 @@ void QPlatformGLContext::setDefaultSharedContext(QPlatformGLContext *sharedConte
Default shared context is intended to be a globally awailable pointer to a context which can
be used for sharing resources when creating new contexts. Its default value is 0;
*/
-const QPlatformGLContext *QPlatformGLContext::defaultSharedContext()
+QPlatformGLContext *QPlatformGLContext::defaultSharedContext()
{
return QPlatformGLContextPrivate::staticSharedContext;
}
diff --git a/src/gui/kernel/qplatformglcontext_qpa.h b/src/gui/kernel/qplatformglcontext_qpa.h
index b425a90..a680c85 100644
--- a/src/gui/kernel/qplatformglcontext_qpa.h
+++ b/src/gui/kernel/qplatformglcontext_qpa.h
@@ -69,7 +69,7 @@ public:
virtual QPlatformWindowFormat platformWindowFormat() const = 0;
const static QPlatformGLContext *currentContext();
- const static QPlatformGLContext *defaultSharedContext();
+ static QPlatformGLContext *defaultSharedContext();
protected:
diff --git a/src/gui/kernel/qplatformintegration_qpa.cpp b/src/gui/kernel/qplatformintegration_qpa.cpp
index 82be48b..c45a953 100644
--- a/src/gui/kernel/qplatformintegration_qpa.cpp
+++ b/src/gui/kernel/qplatformintegration_qpa.cpp
@@ -42,6 +42,7 @@
#include "qplatformintegration_qpa.h"
#include <QtGui/QPlatformFontDatabase>
+#include <QtGui/QPlatformClipboard>
QT_BEGIN_NAMESPACE
@@ -94,6 +95,33 @@ QPlatformFontDatabase *QPlatformIntegration::fontDatabase() const
}
/*!
+ Accessor for the platform integrations clipboard.
+
+ Default implementation returns a default QPlatformClipboard.
+
+ \sa QPlatformClipboard
+
+*/
+
+#ifndef QT_NO_CLIPBOARD
+
+QPlatformClipboard *QPlatformIntegration::clipboard() const
+{
+ static QPlatformClipboard *clipboard = 0;
+ if (!clipboard) {
+ clipboard = new QPlatformClipboard;
+ }
+ return clipboard;
+}
+
+#endif
+
+QPlatformNativeInterface * QPlatformIntegration::nativeInterface() const
+{
+ return 0;
+}
+
+/*!
\class QPlatformIntegration
\since 4.8
\internal
@@ -193,4 +221,14 @@ QPlatformFontDatabase *QPlatformIntegration::fontDatabase() const
QRect(x,y,width,height).
*/
+
+bool QPlatformIntegration::hasCapability(Capability cap) const
+{
+ return false;
+}
+
+
+
+
+
QT_END_NAMESPACE
diff --git a/src/gui/kernel/qplatformintegration_qpa.h b/src/gui/kernel/qplatformintegration_qpa.h
index ad5967f..0aacefa 100644
--- a/src/gui/kernel/qplatformintegration_qpa.h
+++ b/src/gui/kernel/qplatformintegration_qpa.h
@@ -59,12 +59,20 @@ class QBlittable;
class QWidget;
class QPlatformEventLoopIntegration;
class QPlatformFontDatabase;
+class QPlatformClipboard;
+class QPlatformNativeInterface;
class Q_GUI_EXPORT QPlatformIntegration
{
public:
+ enum Capability {
+ ThreadedPixmaps = 1,
+ };
+
virtual ~QPlatformIntegration() { }
+ virtual bool hasCapability(Capability cap) const;
+
// GraphicsSystem functions
virtual QPixmapData *createPixmapData(QPixmapData::PixelType type) const = 0;
virtual QPlatformWindow *createPlatformWindow(QWidget *widget, WId winId = 0) const = 0;
@@ -76,8 +84,11 @@ public:
virtual bool isVirtualDesktop() { return false; }
virtual QPixmap grabWindow(WId window, int x, int y, int width, int height) const;
-//Fontdatabase integration.
+//Deeper window system integrations
virtual QPlatformFontDatabase *fontDatabase() const;
+#ifndef QT_NO_CLIPBOARD
+ virtual QPlatformClipboard *clipboard() const;
+#endif
// Experimental in mainthread eventloop integration
// This should only be used if it is only possible to do window system event processing in
@@ -87,7 +98,8 @@ public:
//jl:XXX should it be hasGLContext and do we need it at all?
virtual bool hasOpenGL() const;
-
+// Access native handles. The window handle is already available from Wid;
+ virtual QPlatformNativeInterface *nativeInterface() const;
};
QT_END_NAMESPACE
diff --git a/src/gui/kernel/qplatformintegrationfactory_qpa.cpp b/src/gui/kernel/qplatformintegrationfactory_qpa.cpp
index 012354f..4135c9e 100644
--- a/src/gui/kernel/qplatformintegrationfactory_qpa.cpp
+++ b/src/gui/kernel/qplatformintegrationfactory_qpa.cpp
@@ -52,15 +52,27 @@ QT_BEGIN_NAMESPACE
#if !defined(QT_NO_LIBRARY) && !defined(QT_NO_SETTINGS)
Q_GLOBAL_STATIC_WITH_ARGS(QFactoryLoader, loader,
(QPlatformIntegrationFactoryInterface_iid, QLatin1String("/platforms"), Qt::CaseInsensitive))
+Q_GLOBAL_STATIC_WITH_ARGS(QFactoryLoader, directLoader,
+ (QPlatformIntegrationFactoryInterface_iid, QLatin1String(""), Qt::CaseInsensitive))
#endif
-QPlatformIntegration *QPlatformIntegrationFactory::create(const QString& key)
+QPlatformIntegration *QPlatformIntegrationFactory::create(const QString& key, const QString &platformPluginPath)
{
QPlatformIntegration *ret = 0;
QStringList paramList = key.split(QLatin1Char(':'));
QString platform = paramList.takeFirst().toLower();
#if !defined(QT_NO_LIBRARY) && !defined(QT_NO_SETTINGS)
+ // Try loading the plugin from platformPluginPath first:
+ if (!platformPluginPath.isEmpty()) {
+ QCoreApplication::addLibraryPath(platformPluginPath);
+ if (QPlatformIntegrationFactoryInterface *factory =
+ qobject_cast<QPlatformIntegrationFactoryInterface*>(directLoader()->instance(platform)))
+ ret = factory->create(key, paramList);
+
+ if (ret)
+ return ret;
+ }
if (QPlatformIntegrationFactoryInterface *factory = qobject_cast<QPlatformIntegrationFactoryInterface*>(loader()->instance(platform)))
ret = factory->create(platform, paramList);
#endif
@@ -74,10 +86,19 @@ QPlatformIntegration *QPlatformIntegrationFactory::create(const QString& key)
\sa create()
*/
-QStringList QPlatformIntegrationFactory::keys()
+QStringList QPlatformIntegrationFactory::keys(const QString &platformPluginPath)
{
#if !defined(QT_NO_LIBRARY) && !defined(QT_NO_SETTINGS)
- QStringList list = loader()->keys();
+ QStringList list;
+
+ if (!platformPluginPath.isEmpty()) {
+ QCoreApplication::addLibraryPath(platformPluginPath);
+ foreach (const QString &key, directLoader()->keys()) {
+ list += key + QString(QLatin1String(" (from %1)")).arg(platformPluginPath);
+ }
+ }
+
+ list += loader()->keys();
#else
QStringList list;
#endif
diff --git a/src/gui/kernel/qplatformintegrationfactory_qpa_p.h b/src/gui/kernel/qplatformintegrationfactory_qpa_p.h
index 8e00d6b..a6042a8 100644
--- a/src/gui/kernel/qplatformintegrationfactory_qpa_p.h
+++ b/src/gui/kernel/qplatformintegrationfactory_qpa_p.h
@@ -66,8 +66,8 @@ class QPlatformIntegration;
class QPlatformIntegrationFactory
{
public:
- static QStringList keys();
- static QPlatformIntegration *create(const QString&);
+ static QStringList keys(const QString &platformPluginPath = QString());
+ static QPlatformIntegration *create(const QString &key, const QString &platformPluginPath = QString());
};
QT_END_NAMESPACE
diff --git a/src/gui/kernel/qplatformnativeinterface_qpa.cpp b/src/gui/kernel/qplatformnativeinterface_qpa.cpp
new file mode 100644
index 0000000..281aeba
--- /dev/null
+++ b/src/gui/kernel/qplatformnativeinterface_qpa.cpp
@@ -0,0 +1,53 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 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 "qplatformnativeinterface_qpa.h"
+
+QT_BEGIN_NAMESPACE
+
+void *QPlatformNativeInterface::nativeResourceForWidget(const QByteArray &resource, QWidget *widget)
+{
+ Q_UNUSED(resource);
+ Q_UNUSED(widget);
+ return 0;
+}
+
+QT_END_NAMESPACE
diff --git a/src/gui/kernel/qplatformnativeinterface_qpa.h b/src/gui/kernel/qplatformnativeinterface_qpa.h
new file mode 100644
index 0000000..b9d0619
--- /dev/null
+++ b/src/gui/kernel/qplatformnativeinterface_qpa.h
@@ -0,0 +1,65 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 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$
+**
+****************************************************************************/
+
+#ifndef QPLATFORMNATIVEINTERFACE_QPA_H
+#define QPLATFORMNATIVEINTERFACE_QPA_H
+
+#include <QtGui/qwindowdefs.h>
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+QT_MODULE(Gui)
+
+class QWidget;
+
+class Q_GUI_EXPORT QPlatformNativeInterface
+{
+public:
+ virtual void *nativeResourceForWidget(const QByteArray &resource, QWidget *widget);
+};
+
+QT_END_NAMESPACE
+
+QT_END_HEADER
+
+#endif // QPLATFORMNATIVEINTERFACE_QPA_H
diff --git a/src/gui/kernel/qplatformscreen_qpa.cpp b/src/gui/kernel/qplatformscreen_qpa.cpp
index 6210be4..c9f3dc6 100644
--- a/src/gui/kernel/qplatformscreen_qpa.cpp
+++ b/src/gui/kernel/qplatformscreen_qpa.cpp
@@ -41,7 +41,11 @@
#include "qplatformscreen_qpa.h"
#include <QtGui/qapplication.h>
+#include <QtGui/private/qapplication_p.h>
#include <QtGui/qdesktopwidget.h>
+#include <QtGui/qplatformintegration_qpa.h>
+#include <QtGui/qwidget.h>
+#include <QtGui/private/qwidget_p.h>
/*!
Return the given top level widget for a given position.
@@ -77,6 +81,17 @@ QSize QPlatformScreen::physicalSize() const
return QSize(width,height);
}
+Q_GUI_EXPORT extern QWidgetPrivate *qt_widget_private(QWidget *widget);
+QPlatformScreen * QPlatformScreen::platformScreenForWidget(const QWidget *widget)
+{
+ QWidget *window = widget->window();
+ QWidgetPrivate *windowPrivate = qt_widget_private(window);
+ QTLWExtra * topData = windowPrivate->topData();
+ QPlatformIntegration *integration =
+ QApplicationPrivate::platformIntegration();
+ return integration->screens()[topData->screenIndex];
+}
+
/*!
\class QPlatformScreen
\since 4.8
diff --git a/src/gui/kernel/qplatformscreen_qpa.h b/src/gui/kernel/qplatformscreen_qpa.h
index 07de196..b3bb121 100644
--- a/src/gui/kernel/qplatformscreen_qpa.h
+++ b/src/gui/kernel/qplatformscreen_qpa.h
@@ -73,6 +73,10 @@ public:
//jl: should setDirty be removed.
virtual void setDirty(const QRect &) {}
virtual QWidget *topLevelAt(const QPoint &point) const;
+
+ //jl: should this function be in QPlatformIntegration
+ //jl: maybe screenForWidget is a better name?
+ static QPlatformScreen *platformScreenForWidget(const QWidget *widget);
};
QT_END_NAMESPACE
diff --git a/src/gui/kernel/qplatformwindow_qpa.cpp b/src/gui/kernel/qplatformwindow_qpa.cpp
index 54b34cc..19bf7a9 100644
--- a/src/gui/kernel/qplatformwindow_qpa.cpp
+++ b/src/gui/kernel/qplatformwindow_qpa.cpp
@@ -41,6 +41,7 @@
#include "qplatformwindow_qpa.h"
+#include <QtGui/qwindowsysteminterface_qpa.h>
#include <QtGui/qwidget.h>
class QPlatformWindowPrivate
@@ -171,6 +172,24 @@ void QPlatformWindow::setOpacity(qreal level)
}
/*!
+ Reimplement to let Qt be able to request activation/focus for a window
+
+ Some window systems will probably not have callbacks for this functionality,
+ and then calling QWindowSystemInterface::handleWindowActivated(QWidget *w)
+ would be sufficient.
+
+ If the window system has some event handling/callbacks then call
+ QWindowSystemInterface::handleWindowActivated(QWidget *w) when the window system
+ gives the notification.
+
+ Default implementation calls QWindowSystem::handleWindowActivated(QWidget *w)
+*/
+void QPlatformWindow::requestActivateWindow()
+{
+ QWindowSystemInterface::handleWindowActivated(widget());
+}
+
+/*!
Reimplement to return the glContext associated with the window.
*/
QPlatformGLContext *QPlatformWindow::glContext() const
diff --git a/src/gui/kernel/qplatformwindow_qpa.h b/src/gui/kernel/qplatformwindow_qpa.h
index f29b253..41a4bac 100644
--- a/src/gui/kernel/qplatformwindow_qpa.h
+++ b/src/gui/kernel/qplatformwindow_qpa.h
@@ -80,6 +80,7 @@ public:
virtual void lower();
virtual void setOpacity(qreal level);
+ virtual void requestActivateWindow();
virtual QPlatformGLContext *glContext() const;
protected:
diff --git a/src/gui/kernel/qt_cocoa_helpers_mac.mm b/src/gui/kernel/qt_cocoa_helpers_mac.mm
index 3a0cafd..32123ee 100644
--- a/src/gui/kernel/qt_cocoa_helpers_mac.mm
+++ b/src/gui/kernel/qt_cocoa_helpers_mac.mm
@@ -89,9 +89,16 @@
#include <private/qcocoaview_mac_p.h>
#include <private/qkeymapper_p.h>
#include <private/qwidget_p.h>
+#include <private/qcocoawindow_mac_p.h>
QT_BEGIN_NAMESPACE
+#ifdef QT_MAC_USE_COCOA
+// Cmd + left mousebutton should produce a right button
+// press (mainly for mac users with one-button mice):
+static bool qt_leftButtonIsRightButton = false;
+#endif
+
Q_GLOBAL_STATIC(QMacWindowFader, macwindowFader);
QMacWindowFader::QMacWindowFader()
@@ -141,6 +148,9 @@ void QMacWindowFader::performFade()
extern bool qt_sendSpontaneousEvent(QObject *receiver, QEvent *event); // qapplication.cpp;
extern QWidget * mac_mouse_grabber;
extern QWidget *qt_button_down; //qapplication_mac.cpp
+extern QPointer<QWidget> qt_last_mouse_receiver;
+extern OSViewRef qt_mac_effectiveview_for(const QWidget *w);
+extern void qt_mac_updateCursorWithWidgetUnderMouse(QWidget *widgetUnderMouse); // qcursor_mac.mm
void macWindowFade(void * /*OSWindowRef*/ window, float durationSeconds)
{
@@ -167,6 +177,70 @@ void macWindowFade(void * /*OSWindowRef*/ window, float durationSeconds)
}
}
}
+struct dndenum_mapper
+{
+ NSDragOperation mac_code;
+ Qt::DropAction qt_code;
+ bool Qt2Mac;
+};
+
+#if defined(QT_MAC_USE_COCOA) && defined(__OBJC__)
+
+static dndenum_mapper dnd_enums[] = {
+ { NSDragOperationLink, Qt::LinkAction, true },
+ { NSDragOperationMove, Qt::MoveAction, true },
+ { NSDragOperationCopy, Qt::CopyAction, true },
+ { NSDragOperationGeneric, Qt::CopyAction, false },
+ { NSDragOperationEvery, Qt::ActionMask, false },
+ { NSDragOperationNone, Qt::IgnoreAction, false }
+};
+
+NSDragOperation qt_mac_mapDropAction(Qt::DropAction action)
+{
+ for (int i=0; dnd_enums[i].qt_code; i++) {
+ if (dnd_enums[i].Qt2Mac && (action & dnd_enums[i].qt_code)) {
+ return dnd_enums[i].mac_code;
+ }
+ }
+ return NSDragOperationNone;
+}
+
+NSDragOperation qt_mac_mapDropActions(Qt::DropActions actions)
+{
+ NSDragOperation nsActions = NSDragOperationNone;
+ for (int i=0; dnd_enums[i].qt_code; i++) {
+ if (dnd_enums[i].Qt2Mac && (actions & dnd_enums[i].qt_code))
+ nsActions |= dnd_enums[i].mac_code;
+ }
+ return nsActions;
+}
+
+Qt::DropAction qt_mac_mapNSDragOperation(NSDragOperation nsActions)
+{
+ Qt::DropAction action = Qt::IgnoreAction;
+ for (int i=0; dnd_enums[i].mac_code; i++) {
+ if (nsActions & dnd_enums[i].mac_code)
+ return dnd_enums[i].qt_code;
+ }
+ return action;
+}
+
+Qt::DropActions qt_mac_mapNSDragOperations(NSDragOperation nsActions)
+{
+ Qt::DropActions actions = Qt::IgnoreAction;
+ for (int i=0; dnd_enums[i].mac_code; i++) {
+ if (nsActions & dnd_enums[i].mac_code)
+ actions |= dnd_enums[i].qt_code;
+ }
+ return actions;
+}
+
+Q_GLOBAL_STATIC(DnDParams, currentDnDParameters);
+DnDParams *macCurrentDnDParameters()
+{
+ return currentDnDParameters();
+}
+#endif
bool macWindowIsTextured( void * /*OSWindowRef*/ window )
{
@@ -301,7 +375,7 @@ bool qt_mac_checkForNativeSizeGrip(const QWidget *widget)
HIViewFindByID(HIViewGetRoot(HIViewGetWindow(HIViewRef(widget->winId()))), kHIViewWindowGrowBoxID, &nativeSizeGrip);
return (nativeSizeGrip != 0);
#else
- return [[reinterpret_cast<NSView *>(widget->winId()) window] showsResizeIndicator];
+ return [[reinterpret_cast<NSView *>(widget->effectiveWinId()) window] showsResizeIndicator];
#endif
}
struct qt_mac_enum_mapper
@@ -517,8 +591,12 @@ static const KeyPair entries[NumEntries] = {
{ NSNewlineCharacter, Qt::Key_Return },
{ NSCarriageReturnCharacter, Qt::Key_Return },
{ NSBackTabCharacter, Qt::Key_Backtab },
- { NSDeleteCharacter, Qt::Key_Delete },
{ kEscapeCharCode, Qt::Key_Escape },
+ // Cocoa sends us delete when pressing backspace!
+ // (NB when we reverse this list in qtKey2CocoaKey, there
+ // will be two indices of Qt::Key_Backspace. But is seems to work
+ // ok for menu shortcuts (which uses that function):
+ { NSDeleteCharacter, Qt::Key_Backspace },
{ NSUpArrowFunctionKey, Qt::Key_Up },
{ NSDownArrowFunctionKey, Qt::Key_Down },
{ NSLeftArrowFunctionKey, Qt::Key_Left },
@@ -731,7 +809,6 @@ Qt::MouseButton cocoaButton2QtButton(NSInteger buttonNum)
return Qt::NoButton;
}
-// Helper to share code between QCocoaWindow and QCocoaView
bool qt_dispatchKeyEvent(void * /*NSEvent * */ keyEvent, QWidget *widgetToGetEvent)
{
#ifndef QT_MAC_USE_COCOA
@@ -743,6 +820,7 @@ bool qt_dispatchKeyEvent(void * /*NSEvent * */ keyEvent, QWidget *widgetToGetEve
EventRef key_event = static_cast<EventRef>(const_cast<void *>([event eventRef]));
Q_ASSERT(key_event);
unsigned int info = 0;
+
if ([event type] == NSKeyDown) {
NSString *characters = [event characters];
if ([characters length]) {
@@ -752,19 +830,12 @@ bool qt_dispatchKeyEvent(void * /*NSEvent * */ keyEvent, QWidget *widgetToGetEve
}
}
- // Redirect keys to alien widgets.
- if (widgetToGetEvent->testAttribute(Qt::WA_NativeWindow) == false) {
- widgetToGetEvent = qApp->focusWidget();
- }
-
- if (widgetToGetEvent == 0)
- return false;
-
if (qt_mac_sendMacEventToWidget(widgetToGetEvent, key_event))
return true;
if (mustUseCocoaKeyEvent())
return qt_dispatchKeyEventWithCocoa(keyEvent, widgetToGetEvent);
+
bool consumed = qt_keymapper_private()->translateKeyEvent(widgetToGetEvent, 0, key_event, &info, true);
return consumed && (info != 0);
#endif
@@ -788,7 +859,6 @@ void qt_dispatchModifiersChanged(void * /*NSEvent * */flagsChangedEvent, QWidget
#endif
}
-
QPointF flipPoint(const NSPoint &p)
{
return QPointF(p.x, flipYCoordinate(p.y));
@@ -804,21 +874,15 @@ NSPoint flipPoint(const QPointF &p)
return NSMakePoint(p.x(), flipYCoordinate(p.y()));
}
-void qt_mac_dispatchNCMouseMessage(void * /* NSWindow* */eventWindow, void * /* NSEvent* */mouseEvent,
- QWidget *widgetToGetEvent, bool &leftButtonIsRightButton)
+#if QT_MAC_USE_COCOA && __OBJC__
+
+void qt_mac_handleNonClientAreaMouseEvent(NSWindow *window, NSEvent *event)
{
-#ifndef QT_MAC_USE_COCOA
- Q_UNUSED(eventWindow);
- Q_UNUSED(mouseEvent);
- Q_UNUSED(widgetToGetEvent);
- Q_UNUSED(leftButtonIsRightButton);
-#else
+ QWidget *widgetToGetEvent = [window QT_MANGLE_NAMESPACE(qt_qwidget)];
if (widgetToGetEvent == 0)
return;
- NSWindow *window = static_cast<NSWindow *>(eventWindow);
- NSEvent *event = static_cast<NSEvent *>(mouseEvent);
- NSEventType evtType = [event type];
+ NSEventType evtType = [event type];
QPoint qlocalPoint;
QPoint qglobalPoint;
bool processThisEvent = false;
@@ -936,12 +1000,12 @@ void qt_mac_dispatchNCMouseMessage(void * /* NSWindow* */eventWindow, void * /*
: QEvent::MouseButtonDblClick;
if (button == Qt::LeftButton && (keyMods & Qt::MetaModifier)) {
button = Qt::RightButton;
- leftButtonIsRightButton = true;
+ qt_leftButtonIsRightButton = true;
}
} else if (eventType == QEvent::NonClientAreaMouseButtonRelease || eventType == QEvent::MouseButtonRelease) {
- if (button == Qt::LeftButton && leftButtonIsRightButton) {
+ if (button == Qt::LeftButton && qt_leftButtonIsRightButton) {
button = Qt::RightButton;
- leftButtonIsRightButton = false;
+ qt_leftButtonIsRightButton = false;
}
}
@@ -961,97 +1025,197 @@ void qt_mac_dispatchNCMouseMessage(void * /* NSWindow* */eventWindow, void * /*
// However we might need to unset it if the event is Release.
if (eventType == QEvent::MouseButtonRelease)
qt_button_down = 0;
-#endif
}
-bool qt_mac_handleMouseEvent(void * /* NSView * */view, void * /* NSEvent * */event, QEvent::Type eventType, Qt::MouseButton button)
+QWidget *qt_mac_getTargetForKeyEvent(QWidget *widgetThatReceivedEvent)
{
-#ifndef QT_MAC_USE_COCOA
- Q_UNUSED(view);
- Q_UNUSED(event);
- Q_UNUSED(eventType);
- Q_UNUSED(button);
- return false;
-#else
- QT_MANGLE_NAMESPACE(QCocoaView) *theView = static_cast<QT_MANGLE_NAMESPACE(QCocoaView) *>(view);
- NSEvent *theEvent = static_cast<NSEvent *>(event);
+ if (QWidget *popup = QApplication::activePopupWidget()) {
+ QWidget *focusInPopup = popup->focusWidget();
+ return focusInPopup ? focusInPopup : popup;
+ }
- // Give the Input Manager a chance to process the mouse events.
- NSInputManager *currentIManager = [NSInputManager currentInputManager];
- if (currentIManager && [currentIManager wantsToHandleMouseEvents]) {
- [currentIManager handleMouseEvent:theEvent];
- }
+ QWidget *widgetToGetKey = qApp->focusWidget();
+ if (!widgetToGetKey)
+ widgetToGetKey = widgetThatReceivedEvent;
- // Handle tablet events (if any) first.
- if (qt_mac_handleTabletEvent(theView, theEvent)) {
- // Tablet event was handled. In Qt we aren't supposed to send the mouse event.
- return true;
+ return widgetToGetKey;
+}
+
+// This function will find the widget that should receive the
+// mouse event. Because of explicit/implicit mouse grabs, popups,
+// etc, this might not end up being the same as the widget under
+// the mouse (which is more interresting when handling enter/leave
+// events
+QWidget *qt_mac_getTargetForMouseEvent(
+ // You can call this function without providing an event.
+ NSEvent *event,
+ QEvent::Type eventType,
+ QPoint &returnLocalPoint,
+ QPoint &returnGlobalPoint,
+ QWidget *nativeWidget,
+ QWidget **returnWidgetUnderMouse)
+{
+ Q_UNUSED(event);
+ NSPoint nsglobalpoint = event ? [[event window] convertBaseToScreen:[event locationInWindow]] : [NSEvent mouseLocation];
+ returnGlobalPoint = flipPoint(nsglobalpoint).toPoint();
+ QWidget *mouseGrabber = QWidget::mouseGrabber();
+ bool buttonDownNotBlockedByModal = qt_button_down && !QApplicationPrivate::isBlockedByModal(qt_button_down);
+ QWidget *popup = QApplication::activePopupWidget();
+
+ // Resolve the widget under the mouse:
+ QWidget *widgetUnderMouse = 0;
+ if (popup || qt_button_down || !nativeWidget || !nativeWidget->isVisible()) {
+ // Using QApplication::widgetAt for finding the widget under the mouse
+ // is most safe, since it ignores cocoas own mouse down redirections (which
+ // we need to be prepared for when using nativeWidget as starting point).
+ // (the only exception is for QMacNativeWidget, where QApplication::widgetAt fails).
+ // But it is also slower (I guess), so we try to avoid it and use nativeWidget if we can:
+ widgetUnderMouse = QApplication::widgetAt(returnGlobalPoint);
}
- NSPoint windowPoint = [theEvent locationInWindow];
- NSPoint globalPoint = [[theEvent window] convertBaseToScreen:windowPoint];
+ if (!widgetUnderMouse && nativeWidget) {
+ // Entering here should be the common case. We
+ // also handle the QMacNativeWidget fallback case.
+ QPoint p = nativeWidget->mapFromGlobal(returnGlobalPoint);
+ widgetUnderMouse = nativeWidget->childAt(p);
+ if (!widgetUnderMouse && nativeWidget->rect().contains(p))
+ widgetUnderMouse = nativeWidget;
+ }
- // Find the widget that *should* get the event (e.g., maybe it was a pop-up,
- // they always get the mouse event).
- QWidget *qwidget = [theView qt_qwidget];
- QWidget *widgetToGetMouse = 0;
- NSView *tmpView = 0;
- QWidget *popup = qAppInstance()->activePopupWidget();
- QPoint qglobalPoint(flipPoint(globalPoint).toPoint());
+ if (widgetUnderMouse) {
+ // Check if widgetUnderMouse is blocked by a modal
+ // window, or the mouse if over the frame strut:
+ if (widgetUnderMouse == qt_button_down) {
+ // Small optimization to avoid an extra call to isBlockedByModal:
+ if (buttonDownNotBlockedByModal == false)
+ widgetUnderMouse = 0;
+ } else if (QApplicationPrivate::isBlockedByModal(widgetUnderMouse)) {
+ widgetUnderMouse = 0;
+ }
- if (popup) {
- widgetToGetMouse = popup;
- tmpView = qt_mac_nativeview_for(popup);
- windowPoint = [[tmpView window] convertScreenToBase:globalPoint];
-
- QPoint qWindowPoint(windowPoint.x, windowPoint.y);
- if (widgetToGetMouse->rect().contains(qWindowPoint)) {
- // Keeping the mouse pressed on a combobox button will make
- // the popup pop in front of the mouse. But all mouse events
- // will be sendt to the button. Since we want mouse events
- // to be sendt to widgets inside the popup, we search for the
- // widget in front of the mouse:
- tmpView = [tmpView hitTest:windowPoint];
- if (!tmpView)
- return false;
- widgetToGetMouse =
- [static_cast<QT_MANGLE_NAMESPACE(QCocoaView) *>(tmpView) qt_qwidget];
+ if (widgetUnderMouse && widgetUnderMouse->isWindow()) {
+ // Exclude the titlebar (and frame strut) when finding widget under mouse:
+ QPoint p = widgetUnderMouse->mapFromGlobal(returnGlobalPoint);
+ if (!widgetUnderMouse->rect().contains(p))
+ widgetUnderMouse = 0;
+ }
+ }
+ if (returnWidgetUnderMouse)
+ *returnWidgetUnderMouse = widgetUnderMouse;
+
+ // Resolve the target for the mouse event. Default will be
+ // widgetUnderMouse, except if there is a grab (popup/mouse/button-down):
+ if (popup && !mouseGrabber) {
+ // We special case handling of popups, since they have an implicitt mouse grab.
+ QWidget *candidate = buttonDownNotBlockedByModal ? qt_button_down : widgetUnderMouse;
+ if (!popup->isAncestorOf(candidate)) {
+ // INVARIANT: we have a popup, but the candidate is not
+ // in it. But the popup will grab the mouse anyway,
+ // except if the user scrolls:
+ if (eventType == QEvent::Wheel)
+ return 0;
+ returnLocalPoint = popup->mapFromGlobal(returnGlobalPoint);
+ return popup;
+ } else if (popup == candidate) {
+ // INVARIANT: The candidate is the popup itself, and not a child:
+ returnLocalPoint = popup->mapFromGlobal(returnGlobalPoint);
+ return popup;
+ } else {
+ // INVARIANT: The candidate is a child inside the popup:
+ returnLocalPoint = candidate->mapFromGlobal(returnGlobalPoint);
+ return candidate;
}
+ }
+
+ QWidget *target = mouseGrabber;
+ if (!target && buttonDownNotBlockedByModal)
+ target = qt_button_down;
+ if (!target)
+ target = widgetUnderMouse;
+ if (!target)
+ return 0;
+
+ returnLocalPoint = target->mapFromGlobal(returnGlobalPoint);
+ return target;
+}
+
+QPointer<QWidget> qt_last_native_mouse_receiver = 0;
+
+static inline void qt_mac_checkEnterLeaveForNativeWidgets(QWidget *maybeEnterWidget)
+{
+ // Dispatch enter/leave for the cases where QApplicationPrivate::sendMouseEvent do
+ // not. This will in general be the cases when alien widgets are not involved:
+ // 1. from a native widget to another native widget or
+ // 2. from a native widget to no widget
+ // 3. from no widget to a native or alien widget
+
+ if (qt_button_down || QWidget::mouseGrabber())
+ return;
+
+ if ((maybeEnterWidget == qt_last_native_mouse_receiver) && qt_last_native_mouse_receiver)
+ return;
+ if (maybeEnterWidget) {
+ if (!qt_last_native_mouse_receiver) {
+ // case 3
+ QApplicationPrivate::dispatchEnterLeave(maybeEnterWidget, 0);
+ qt_last_native_mouse_receiver = maybeEnterWidget->internalWinId() ? maybeEnterWidget : maybeEnterWidget->nativeParentWidget();
+ } else if (maybeEnterWidget->internalWinId()) {
+ // case 1
+ QApplicationPrivate::dispatchEnterLeave(maybeEnterWidget, qt_last_native_mouse_receiver);
+ qt_last_native_mouse_receiver = maybeEnterWidget->internalWinId() ? maybeEnterWidget : maybeEnterWidget->nativeParentWidget();
+ } // else at lest one of the widgets are alien, so enter/leave will be handled in QApplicationPrivate
} else {
- extern QWidget * qt_button_down; //qapplication_mac.cpp
- QPoint pos;
- widgetToGetMouse = QApplicationPrivate::pickMouseReceiver(qwidget, qglobalPoint,
- pos, eventType,
- button, qt_button_down, 0);
- if (widgetToGetMouse)
- tmpView = qt_mac_nativeview_for(widgetToGetMouse);
+ if (qt_last_native_mouse_receiver) {
+ // case 2
+ QApplicationPrivate::dispatchEnterLeave(0, qt_last_native_mouse_receiver);
+ qt_last_mouse_receiver = 0;
+ qt_last_native_mouse_receiver = 0;
+ }
}
+}
+
+bool qt_mac_handleMouseEvent(NSEvent *event, QEvent::Type eventType, Qt::MouseButton button, QWidget *nativeWidget)
+{
+ // Give the Input Manager a chance to process the mouse events.
+ NSInputManager *currentIManager = [NSInputManager currentInputManager];
+ if (currentIManager && [currentIManager wantsToHandleMouseEvents]) {
+ [currentIManager handleMouseEvent:event];
+ }
+
+ // Find the widget that should receive the event, and the widget under the mouse. Those
+ // can differ if an implicit or explicit mouse grab is active:
+ QWidget *widgetUnderMouse = 0;
+ QPoint localPoint, globalPoint;
+ QWidget *widgetToGetMouse = qt_mac_getTargetForMouseEvent(event, eventType, localPoint, globalPoint, nativeWidget, &widgetUnderMouse);
if (!widgetToGetMouse)
return false;
- NSPoint localPoint = [tmpView convertPoint:windowPoint fromView:nil];
- QPoint qlocalPoint = QPoint(localPoint.x, localPoint.y);
+ // From here on, we let nativeWidget actually be the native widget under widgetUnderMouse. The reason
+ // for this, is that qt_mac_getTargetForMouseEvent will set cocoa's mouse event redirection aside when
+ // determining which widget is under the mouse (in other words, it will usually ignore nativeWidget).
+ // nativeWidget will be used in QApplicationPrivate::sendMouseEvent to correctly dispatch enter/leave events.
+ if (widgetUnderMouse)
+ nativeWidget = widgetUnderMouse->internalWinId() ? widgetUnderMouse : widgetUnderMouse->nativeParentWidget();
+ if (!nativeWidget)
+ return false;
+ NSView *view = qt_mac_effectiveview_for(nativeWidget);
- // Search for alien child widgets (either on this qwidget or on the popup)
- if (widgetToGetMouse->testAttribute(Qt::WA_NativeWindow) == false || qt_widget_private(widgetToGetMouse)->hasAlienChildren) {
- QPoint qScreenPoint = flipPoint(globalPoint).toPoint();
-#ifdef ALIEN_DEBUG
- qDebug() << "alien mouse event" << qScreenPoint << possibleAlien;
-#endif
- QWidget *possibleAlien = widgetToGetMouse->childAt(qlocalPoint);
- if (possibleAlien) {
- qlocalPoint = possibleAlien->mapFromGlobal(widgetToGetMouse->mapToGlobal(qlocalPoint));
- widgetToGetMouse = possibleAlien;
- }
+ // Handle tablet events (if any) first.
+ if (qt_mac_handleTabletEvent(view, event)) {
+ // Tablet event was handled. In Qt we aren't supposed to send the mouse event.
+ return true;
}
- EventRef carbonEvent = static_cast<EventRef>(const_cast<void *>([theEvent eventRef]));
+ EventRef carbonEvent = static_cast<EventRef>(const_cast<void *>([event eventRef]));
if (qt_mac_sendMacEventToWidget(widgetToGetMouse, carbonEvent))
return true;
- // Yay! All the special cases are handled, it really is just a normal mouse event.
- Qt::KeyboardModifiers keyMods = qt_cocoaModifiers2QtModifiers([theEvent modifierFlags]);
- NSInteger clickCount = [theEvent clickCount];
+ // Keep previousButton to make sure we don't send double click
+ // events when the user double clicks using two different buttons:
+ static Qt::MouseButton previousButton = Qt::NoButton;
+
+ Qt::KeyboardModifiers keyMods = qt_cocoaModifiers2QtModifiers([event modifierFlags]);
+ NSInteger clickCount = [event clickCount];
Qt::MouseButtons buttons = 0;
{
UInt32 mac_buttons;
@@ -1059,55 +1223,67 @@ bool qt_mac_handleMouseEvent(void * /* NSView * */view, void * /* NSEvent * */ev
sizeof(mac_buttons), 0, &mac_buttons) == noErr)
buttons = qt_mac_get_buttons(mac_buttons);
}
+
+ // Send enter/leave events for the cases when QApplicationPrivate::sendMouseEvent do not:
+ qt_mac_checkEnterLeaveForNativeWidgets(widgetUnderMouse);
+
switch (eventType) {
default:
qWarning("not handled! %d", eventType);
break;
case QEvent::MouseMove:
+ if (button == Qt::LeftButton && qt_leftButtonIsRightButton)
+ button = Qt::RightButton;
break;
case QEvent::MouseButtonPress:
- [QT_MANGLE_NAMESPACE(QCocoaView) currentMouseEvent]->view = theView;
- [QT_MANGLE_NAMESPACE(QCocoaView) currentMouseEvent]->theEvent = theEvent;
-#ifndef QT_NAMESPACE
- Q_ASSERT(clickCount > 0);
-#endif
- if (clickCount % 2 == 0 && buttons == button)
+ qt_button_down = widgetUnderMouse;
+ if (clickCount % 2 == 0 && (previousButton == Qt::NoButton || previousButton == button))
eventType = QEvent::MouseButtonDblClick;
if (button == Qt::LeftButton && (keyMods & Qt::MetaModifier)) {
button = Qt::RightButton;
- [theView qt_setLeftButtonIsRightButton: true];
+ qt_leftButtonIsRightButton = true;
}
break;
case QEvent::MouseButtonRelease:
- if (button == Qt::LeftButton && [theView qt_leftButtonIsRightButton]) {
+ if (button == Qt::LeftButton && qt_leftButtonIsRightButton) {
button = Qt::RightButton;
- [theView qt_setLeftButtonIsRightButton: false];
+ qt_leftButtonIsRightButton = false;
}
qt_button_down = 0;
break;
}
- [QT_MANGLE_NAMESPACE(QCocoaView) currentMouseEvent]->localPoint = localPoint;
- QMouseEvent qme(eventType, qlocalPoint, qglobalPoint, button, buttons, keyMods);
-#ifdef ALIEN_DEBUG
- qDebug() << "sending mouse event to" << widgetToGetMouse;
-#endif
- extern QWidget *qt_button_down;
- extern QPointer<QWidget> qt_last_mouse_receiver;
+ qt_mac_updateCursorWithWidgetUnderMouse(widgetUnderMouse);
- if (qwidget->testAttribute(Qt::WA_NativeWindow) && qt_widget_private(qwidget)->hasAlienChildren == false)
- qt_sendSpontaneousEvent(widgetToGetMouse, &qme);
- else
- QApplicationPrivate::sendMouseEvent(widgetToGetMouse, &qme, widgetToGetMouse, qwidget, &qt_button_down,
- qt_last_mouse_receiver);
+ DnDParams *dndParams = currentDnDParameters();
+ dndParams->view = view;
+ dndParams->theEvent = event;
+ dndParams->globalPoint = globalPoint;
+
+ // Send the mouse event:
+ QMouseEvent qme(eventType, localPoint, globalPoint, button, buttons, keyMods);
+ QApplicationPrivate::sendMouseEvent(
+ widgetToGetMouse, &qme, widgetUnderMouse, nativeWidget,
+ &qt_button_down, qt_last_mouse_receiver, true);
if (eventType == QEvent::MouseButtonPress && button == Qt::RightButton) {
- QContextMenuEvent qcme(QContextMenuEvent::Mouse, qlocalPoint, qglobalPoint, keyMods);
+ QContextMenuEvent qcme(QContextMenuEvent::Mouse, localPoint, globalPoint, keyMods);
qt_sendSpontaneousEvent(widgetToGetMouse, &qcme);
}
+
+ if (eventType == QEvent::MouseButtonRelease) {
+ // A mouse button was released, which means that the implicit grab was
+ // released. We therefore need to re-check if should send (delayed) enter leave events:
+ // qt_button_down has now become NULL since the call at the top of the function. Also, since
+ // the relase might have closed a window, we dont give the nativeWidget hint
+ qt_mac_getTargetForMouseEvent(0, QEvent::None, localPoint, globalPoint, nativeWidget, &widgetUnderMouse);
+ qt_mac_checkEnterLeaveForNativeWidgets(widgetUnderMouse);
+ }
+
+ previousButton = button;
return true;
-#endif
}
+#endif
bool qt_mac_handleTabletEvent(void * /*QCocoaView * */view, void * /*NSEvent * */tabletEvent)
{
@@ -1291,17 +1467,17 @@ void qt_mac_replaceDrawRectOriginal(void * /*OSWindowRef */window, QWidgetPrivat
}
#endif // QT_MAC_USE_COCOA
+#if QT_MAC_USE_COCOA
void qt_mac_showBaseLineSeparator(void * /*OSWindowRef */window, bool show)
{
if(!window)
return;
-#if QT_MAC_USE_COCOA
QMacCocoaAutoReleasePool pool;
OSWindowRef theWindow = static_cast<OSWindowRef>(window);
NSToolbar *macToolbar = [theWindow toolbar];
[macToolbar setShowsBaselineSeparator:show];
-#endif // QT_MAC_USE_COCOA
}
+#endif // QT_MAC_USE_COCOA
QStringList qt_mac_NSArrayToQStringList(void *nsarray)
{
@@ -1321,6 +1497,7 @@ void *qt_mac_QStringListToNSMutableArrayVoid(const QStringList &list)
return result;
}
+#if QT_MAC_USE_COCOA
void qt_syncCocoaTitleBarButtons(OSWindowRef window, QWidget *widgetForWindow)
{
if (!widgetForWindow)
@@ -1345,6 +1522,7 @@ void qt_syncCocoaTitleBarButtons(OSWindowRef window, QWidget *widgetForWindow)
[window setShowsToolbarButton:uint(flags & Qt::MacWindowToolBarButtonHint) != 0];
}
+#endif // QT_MAC_USE_COCOA
// Carbon: Make sure you call QDEndContext on the context when done with it.
CGContextRef qt_mac_graphicsContextFor(QWidget *widget)
@@ -1446,8 +1624,10 @@ void qt_mac_constructQIconFromIconRef(const IconRef icon, const IconRef overlayI
}
}
+#ifdef QT_MAC_USE_COCOA
void qt_mac_menu_collapseSeparators(void */*NSMenu **/ theMenu, bool collapse)
{
+ QMacCocoaAutoReleasePool pool;
OSMenuRef menu = static_cast<OSMenuRef>(theMenu);
if (collapse) {
bool previousIsSeparator = true; // setting to true kills all the separators placed at the top.
@@ -1479,12 +1659,24 @@ void qt_mac_menu_collapseSeparators(void */*NSMenu **/ theMenu, bool collapse)
}
}
-#ifdef QT_MAC_USE_COCOA
-void qt_cocoaChangeOverrideCursor(const QCursor &cursor)
+class CocoaPostMessageAfterEventLoopExitHelp : public QObject
{
- QMacCocoaAutoReleasePool pool;
- [static_cast<NSCursor *>(qt_mac_nsCursorForQCursor(cursor)) set];
-}
+ id target;
+ SEL selector;
+ int argCount;
+ id arg1;
+ id arg2;
+public:
+ CocoaPostMessageAfterEventLoopExitHelp(id target, SEL selector, int argCount, id arg1, id arg2)
+ : target(target), selector(selector), argCount(argCount), arg1(arg1), arg2(arg2){
+ deleteLater();
+ }
+
+ ~CocoaPostMessageAfterEventLoopExitHelp()
+ {
+ qt_cocoaPostMessage(target, selector, argCount, arg1, arg2);
+ }
+};
void qt_cocoaPostMessage(id target, SEL selector, int argCount, id arg1, id arg2)
{
@@ -1498,6 +1690,15 @@ void qt_cocoaPostMessage(id target, SEL selector, int argCount, id arg1, id arg2
context:nil subtype:QtCocoaEventSubTypePostMessage data1:lower data2:upper];
[NSApp postEvent:e atStart:NO];
}
+
+void qt_cocoaPostMessageAfterEventLoopExit(id target, SEL selector, int argCount, id arg1, id arg2)
+{
+ if (QApplicationPrivate::instance()->threadData->eventLoops.size() <= 1)
+ qt_cocoaPostMessage(target, selector, argCount, arg1, arg2);
+ else
+ new CocoaPostMessageAfterEventLoopExitHelp(target, selector, argCount, arg1, arg2);
+}
+
#endif
QMacCocoaAutoReleasePool::QMacCocoaAutoReleasePool()
@@ -1521,6 +1722,12 @@ void qt_mac_post_retranslateAppMenu()
#endif
}
+QWidgetPrivate *QMacScrollOptimization::_target = 0;
+bool QMacScrollOptimization::_inWheelEvent = false;
+int QMacScrollOptimization::_dx = 0;
+int QMacScrollOptimization::_dy = 0;
+QRect QMacScrollOptimization::_scrollRect = QRect(0, 0, -1, -1);
+
#ifdef QT_MAC_USE_COCOA
// This method implements the magic for the drawRectSpecial method.
// We draw a line at the upper edge of the content view in order to
@@ -1587,7 +1794,29 @@ void qt_mac_display(QWidget *widget)
{
NSView *theNSView = qt_mac_nativeview_for(widget);
[theNSView display];
- return;
+}
+
+void qt_mac_setNeedsDisplay(QWidget *widget)
+{
+ NSView *theNSView = qt_mac_nativeview_for(widget);
+ [theNSView setNeedsDisplay:YES];
+}
+
+void qt_mac_setNeedsDisplayInRect(QWidget *widget, QRegion region)
+{
+ NSView *theNSView = qt_mac_nativeview_for(widget);
+ if (region.isEmpty()) {
+ [theNSView setNeedsDisplay:YES];
+ return;
+ }
+
+ QVector<QRect> rects = region.rects();
+ for (int i = 0; i < rects.count(); ++i) {
+ const QRect &rect = rects.at(i);
+ NSRect nsrect = NSMakeRect(rect.x(), rect.y(), rect.width(), rect.height());
+ [theNSView setNeedsDisplayInRect:nsrect];
+ }
+
}
#endif // QT_MAC_USE_COCOA
diff --git a/src/gui/kernel/qt_cocoa_helpers_mac_p.h b/src/gui/kernel/qt_cocoa_helpers_mac_p.h
index d61c00f..a49753a 100644
--- a/src/gui/kernel/qt_cocoa_helpers_mac_p.h
+++ b/src/gui/kernel/qt_cocoa_helpers_mac_p.h
@@ -103,6 +103,7 @@
#include <qtimer.h>
#include <qtooltip.h>
#include <private/qeffects_p.h>
+#include <private/qwidget_p.h>
#include <qtextdocument.h>
#include <qdebug.h>
#include <qpoint.h>
@@ -144,18 +145,14 @@ bool qt_mac_checkForNativeSizeGrip(const QWidget *widget);
void qt_dispatchTabletProximityEvent(void * /*NSEvent * */ tabletEvent);
#ifdef QT_MAC_USE_COCOA
bool qt_dispatchKeyEventWithCocoa(void * /*NSEvent * */ keyEvent, QWidget *widgetToGetEvent);
-void qt_cocoaChangeOverrideCursor(const QCursor &cursor);
// These methods exists only for supporting unified mode.
void macDrawRectOnTop(void * /*OSWindowRef */ window);
void macSyncDrawingOnFirstInvocation(void * /*OSWindowRef */window);
void qt_cocoaStackChildWindowOnTopOfOtherChildren(QWidget *widget);
-#endif
void qt_mac_menu_collapseSeparators(void * /*NSMenu */ menu, bool collapse);
+#endif
bool qt_dispatchKeyEvent(void * /*NSEvent * */ keyEvent, QWidget *widgetToGetEvent);
void qt_dispatchModifiersChanged(void * /*NSEvent * */flagsChangedEvent, QWidget *widgetToGetEvent);
-void qt_mac_dispatchNCMouseMessage(void */* NSWindow* */eventWindow, void */* NSEvent* */mouseEvent,
- QWidget *widgetToGetEvent, bool &leftButtonIsRightButton);
-bool qt_mac_handleMouseEvent(void * /*QCocoaView * */view, void * /*NSEvent * */event, QEvent::Type eventType, Qt::MouseButton button);
bool qt_mac_handleTabletEvent(void * /*QCocoaView * */view, void * /*NSEvent * */event);
inline QApplication *qAppInstance() { return static_cast<QApplication *>(QCoreApplication::instance()); }
struct ::TabletProximityRec;
@@ -165,6 +162,29 @@ Qt::KeyboardModifiers qt_cocoaDragOperation2QtModifiers(uint dragOperations);
QPixmap qt_mac_convert_iconref(const IconRef icon, int width, int height);
void qt_mac_constructQIconFromIconRef(const IconRef icon, const IconRef overlayIcon, QIcon *retIcon,
QStyle::StandardPixmap standardIcon = QStyle::SP_CustomBase);
+
+#if QT_MAC_USE_COCOA && __OBJC__
+struct DnDParams
+{
+ NSView *view;
+ NSEvent *theEvent;
+ QPoint globalPoint;
+ NSDragOperation performedAction;
+};
+
+DnDParams *macCurrentDnDParameters();
+NSDragOperation qt_mac_mapDropAction(Qt::DropAction action);
+NSDragOperation qt_mac_mapDropActions(Qt::DropActions actions);
+Qt::DropAction qt_mac_mapNSDragOperation(NSDragOperation nsActions);
+Qt::DropActions qt_mac_mapNSDragOperations(NSDragOperation nsActions);
+
+QWidget *qt_mac_getTargetForKeyEvent(QWidget *widgetThatReceivedEvent);
+QWidget *qt_mac_getTargetForMouseEvent(NSEvent *event, QEvent::Type eventType,
+ QPoint &returnLocalPoint, QPoint &returnGlobalPoint, QWidget *nativeWidget, QWidget **returnWidgetUnderMouse);
+bool qt_mac_handleMouseEvent(NSEvent *event, QEvent::Type eventType, Qt::MouseButton button, QWidget *nativeWidget);
+void qt_mac_handleNonClientAreaMouseEvent(NSWindow *window, NSEvent *event);
+#endif
+
inline int flipYCoordinate(int y)
{
return QApplication::desktop()->screenGeometry(0).height() - y;
@@ -221,13 +241,99 @@ public:
}
};
void qt_cocoaPostMessage(id target, SEL selector, int argCount=0, id arg1=0, id arg2=0);
+void qt_cocoaPostMessageAfterEventLoopExit(id target, SEL selector, int argCount=0, id arg1=0, id arg2=0);
#endif
#endif
+class QMacScrollOptimization {
+ // This class is made to optimize for the case when the user
+ // scrolls both horizontally and vertically at the same
+ // time. This will result in two QWheelEvents (one for each
+ // direction), which will typically result in two calls to
+ // QWidget::_scroll_sys. Rather than copying pixels twize on
+ // screen because of this, we add this helper class to try to
+ // get away with only one blit.
+ static QWidgetPrivate *_target;
+ static bool _inWheelEvent;
+ static int _dx;
+ static int _dy;
+ static QRect _scrollRect;
+
+public:
+ static void initDelayedScroll()
+ {
+ _inWheelEvent = true;
+ }
+
+ static bool delayScroll(QWidgetPrivate *target, int dx, int dy, const QRect &scrollRect)
+ {
+ if (!_inWheelEvent)
+ return false;
+ if (_target && _target != target)
+ return false;
+ if (_scrollRect.width() != -1 && _scrollRect != scrollRect)
+ return false;
+
+ _target = target;
+ _dx += dx;
+ _dy += dy;
+ _scrollRect = scrollRect;
+ return true;
+ }
+
+ static void performDelayedScroll()
+ {
+ if (!_inWheelEvent)
+ return;
+ _inWheelEvent = false;
+ if (!_target)
+ return;
+
+ _target->scroll_sys(_dx, _dy, _scrollRect);
+
+ _target = 0;
+ _dx = 0;
+ _dy = 0;
+ _scrollRect = QRect(0, 0, -1, -1);
+ }
+};
+
void qt_mac_post_retranslateAppMenu();
+#ifdef QT_MAC_USE_COCOA
void qt_mac_display(QWidget *widget);
+void qt_mac_setNeedsDisplay(QWidget *widget);
+void qt_mac_setNeedsDisplayInRect(QWidget *widget, QRegion region);
+#endif // QT_MAC_USE_COCOA
+
+
+// Utility functions to ease the use of Core Graphics contexts.
+
+inline void qt_mac_retain_graphics_context(CGContextRef context)
+{
+ CGContextRetain(context);
+ CGContextSaveGState(context);
+}
+
+inline void qt_mac_release_graphics_context(CGContextRef context)
+{
+ CGContextRestoreGState(context);
+ CGContextRelease(context);
+}
+
+inline void qt_mac_draw_image(CGContextRef context, CGContextRef imageContext, CGRect area, CGRect drawingArea)
+{
+ CGImageRef image = CGBitmapContextCreateImage(imageContext);
+ CGImageRef subImage = CGImageCreateWithImageInRect(image, area);
+
+ CGContextTranslateCTM (context, 0, drawingArea.origin.y + CGRectGetMaxY(drawingArea));
+ CGContextScaleCTM(context, 1, -1);
+ CGContextDrawImage(context, drawingArea, subImage);
+
+ CGImageRelease(subImage);
+ CGImageRelease(image);
+}
QT_END_NAMESPACE
diff --git a/src/gui/kernel/qt_s60_p.h b/src/gui/kernel/qt_s60_p.h
index fdb35d5..3bb27c3 100644
--- a/src/gui/kernel/qt_s60_p.h
+++ b/src/gui/kernel/qt_s60_p.h
@@ -64,6 +64,7 @@
#include "qapplication.h"
#include "qelapsedtimer.h"
#include "QtCore/qthreadstorage.h"
+#include "qwidget_p.h"
#include <w32std.h>
#include <coecntrl.h>
#include <eikenv.h>
@@ -84,6 +85,8 @@ QT_BEGIN_NAMESPACE
// system events seems to start with 0x10
const TInt KInternalStatusPaneChange = 0x50000000;
+static const int qt_symbian_max_screens = 4;
+
//this macro exists because EColor16MAP enum value doesn't exist in Symbian OS 9.2
#define Q_SYMBIAN_ECOLOR16MAP TDisplayMode(13)
@@ -141,7 +144,11 @@ public:
int supportsPremultipliedAlpha : 1;
int avkonComponentsSupportTransparency : 1;
int menuBeingConstructed : 1;
+ int orientationSet : 1;
+ int partial_keyboard : 1;
QApplication::QS60MainApplicationFactory s60ApplicationFactory; // typedef'ed pointer type
+ QPointer<QWidget> splitViewLastWidget;
+
static CEikButtonGroupContainer *cba;
enum ScanCodeState {
@@ -153,8 +160,14 @@ public:
static inline void updateScreenSize();
inline RWsSession& wsSession();
+ static inline int screenCount();
static inline RWindowGroup& windowGroup();
+ static inline RWindowGroup& windowGroup(const QWidget *widget);
+ static inline RWindowGroup& windowGroup(int screenNumber);
inline CWsScreenDevice* screenDevice();
+ inline CWsScreenDevice* screenDevice(const QWidget *widget);
+ inline CWsScreenDevice* screenDevice(int screenNumber);
+ static inline int screenNumberForWidget(const QWidget *widget);
static inline CCoeAppUi* appUi();
static inline CEikMenuBar* menuBar();
#ifdef Q_WS_S60
@@ -171,6 +184,11 @@ public:
#ifdef Q_OS_SYMBIAN
TTrapHandler *s60InstalledTrapHandler;
#endif
+
+ int screenWidthInPixelsForScreen[qt_symbian_max_screens];
+ int screenHeightInPixelsForScreen[qt_symbian_max_screens];
+ int screenWidthInTwipsForScreen[qt_symbian_max_screens];
+ int screenHeightInTwipsForScreen[qt_symbian_max_screens];
};
Q_AUTOTEST_EXPORT QS60Data* qGlobalS60Data();
@@ -251,6 +269,7 @@ private:
#ifdef QT_SYMBIAN_SUPPORTS_ADVANCED_POINTER
void translateAdvancedPointerEvent(const TAdvancedPointerEvent *event);
#endif
+ bool isSplitViewWidget(QWidget *widget);
public:
void handleClientAreaChange();
@@ -269,6 +288,8 @@ private:
// Fader object used to fade everything except this menu and the CBA.
TAknPopupFader popupFader;
#endif
+
+ bool m_inExternalScreenOverride : 1;
};
inline QS60Data::QS60Data()
@@ -295,6 +316,8 @@ inline QS60Data::QS60Data()
supportsPremultipliedAlpha(0),
avkonComponentsSupportTransparency(0),
menuBeingConstructed(0),
+ orientationSet(0),
+ partial_keyboard(0),
s60ApplicationFactory(0)
#ifdef Q_OS_SYMBIAN
,s60InstalledTrapHandler(0)
@@ -318,6 +341,17 @@ inline void QS60Data::updateScreenSize()
S60->defaultDpiY = S60->screenHeightInPixels / inches;
inches = S60->screenWidthInTwips / (TReal)KTwipsPerInch;
S60->defaultDpiX = S60->screenWidthInPixels / inches;
+
+ int screens = S60->screenCount();
+ for (int i = 0; i < screens; ++i) {
+ CWsScreenDevice *dev = S60->screenDevice(i);
+ mode = dev->CurrentScreenMode();
+ dev->GetScreenModeSizeAndRotation(mode, params);
+ S60->screenWidthInPixelsForScreen[i] = params.iPixelSize.iWidth;
+ S60->screenHeightInPixelsForScreen[i] = params.iPixelSize.iHeight;
+ S60->screenWidthInTwipsForScreen[i] = params.iTwipsSize.iWidth;
+ S60->screenHeightInTwipsForScreen[i] = params.iTwipsSize.iHeight;
+ }
}
inline RWsSession& QS60Data::wsSession()
@@ -328,11 +362,38 @@ inline RWsSession& QS60Data::wsSession()
return tls.localData()->wsSession;
}
+inline int QS60Data::screenCount()
+{
+#if defined(Q_SYMBIAN_SUPPORTS_MULTIPLE_SCREENS)
+ CCoeEnv *env = CCoeEnv::Static();
+ if (env) {
+ return qMin(env->WsSession().NumberOfScreens(), qt_symbian_max_screens);
+ }
+#endif
+ return 1;
+}
+
inline RWindowGroup& QS60Data::windowGroup()
{
return CCoeEnv::Static()->RootWin();
}
+inline RWindowGroup& QS60Data::windowGroup(const QWidget *widget)
+{
+ return windowGroup(screenNumberForWidget(widget));
+}
+
+inline RWindowGroup& QS60Data::windowGroup(int screenNumber)
+{
+#if defined(Q_SYMBIAN_SUPPORTS_MULTIPLE_SCREENS)
+ RWindowGroup *wg = CCoeEnv::Static()->RootWin(screenNumber);
+ return wg ? *wg : windowGroup();
+#else
+ Q_UNUSED(screenNumber);
+ return windowGroup();
+#endif
+}
+
inline CWsScreenDevice* QS60Data::screenDevice()
{
if(!tls.hasLocalData()) {
@@ -341,6 +402,36 @@ inline CWsScreenDevice* QS60Data::screenDevice()
return tls.localData()->screenDevice;
}
+inline CWsScreenDevice* QS60Data::screenDevice(const QWidget *widget)
+{
+ return screenDevice(screenNumberForWidget(widget));
+}
+
+inline CWsScreenDevice* QS60Data::screenDevice(int screenNumber)
+{
+#if defined(Q_SYMBIAN_SUPPORTS_MULTIPLE_SCREENS)
+ CCoeEnv *env = CCoeEnv::Static();
+ if (env) {
+ CWsScreenDevice *dev = env->ScreenDevice(screenNumber);
+ return dev ? dev : screenDevice();
+ } else {
+ return screenDevice();
+ }
+#else
+ return screenDevice();
+#endif
+}
+
+inline int QS60Data::screenNumberForWidget(const QWidget *widget)
+{
+ if (!widget)
+ return 0;
+ const QWidget *w = widget;
+ while (w->parentWidget())
+ w = w->parentWidget();
+ return qt_widget_private(const_cast<QWidget *>(w))->symbianScreenNumber;
+}
+
inline CCoeAppUi* QS60Data::appUi()
{
return CCoeEnv::Static()-> AppUi();
diff --git a/src/gui/kernel/qwidget.cpp b/src/gui/kernel/qwidget.cpp
index f35afb0..23d063d 100644
--- a/src/gui/kernel/qwidget.cpp
+++ b/src/gui/kernel/qwidget.cpp
@@ -127,6 +127,10 @@
#include "qtabwidget.h" // Needed in inTabWidget()
#endif // QT_KEYPAD_NAVIGATION
+#ifdef Q_WS_S60
+#include <aknappui.h>
+#endif
+
// widget/widget data creation count
//#define QWIDGET_EXTRA_DEBUG
//#define ALIEN_DEBUG
@@ -144,6 +148,10 @@ Q_GUI_EXPORT void qt_x11_set_global_double_buffer(bool enable)
}
#endif
+#if defined(QT_MAC_USE_COCOA)
+bool qt_mac_clearDirtyOnWidgetInsideDrawWidget = false;
+#endif
+
static inline bool qRectIntersects(const QRect &r1, const QRect &r2)
{
return (qMax(r1.left(), r2.left()) <= qMin(r1.right(), r2.right()) &&
@@ -300,11 +308,10 @@ QWidgetPrivate::QWidgetPrivate(int version)
#endif
#elif defined(Q_WS_MAC)
, needWindowChange(0)
- , hasAlienChildren(0)
, window_event(0)
, qd_hd(0)
-#elif defined (Q_WS_QPA)
- , screenNumber(0)
+#elif defined(Q_OS_SYMBIAN)
+ , symbianScreenNumber(0)
#endif
{
if (!qApp) {
@@ -321,9 +328,11 @@ QWidgetPrivate::QWidgetPrivate(int version)
drawRectOriginalAdded = false;
originalDrawMethod = true;
changeMethods = false;
- hasOwnContext = false;
isInUnifiedToolbar = false;
unifiedSurface = 0;
+ toolbar_ancestor = 0;
+ flushRequested = false;
+ touchEventsEnabled = false;
#endif // QT_MAC_USE_COCOA
#ifdef QWIDGET_EXTRA_DEBUG
static int count = 0;
@@ -397,11 +406,24 @@ void QWidgetPrivate::scrollChildren(int dx, int dy)
}
}
+QInputContext *QWidgetPrivate::assignedInputContext() const
+{
+#ifndef QT_NO_IM
+ const QWidget *widget = q_func();
+ while (widget) {
+ if (QInputContext *qic = widget->d_func()->ic)
+ return qic;
+ widget = widget->parentWidget();
+ }
+#endif
+ return 0;
+}
+
QInputContext *QWidgetPrivate::inputContext() const
{
#ifndef QT_NO_IM
- if (ic)
- return ic;
+ if (QInputContext *qic = assignedInputContext())
+ return qic;
return qApp->inputContext();
#else
return 0;
@@ -1275,9 +1297,13 @@ void QWidgetPrivate::init(QWidget *parentWidget, Qt::WindowFlags f)
// programmer specified desktop widget
xinfo = desktopWidget->d_func()->xinfo;
}
+#elif defined(Q_OS_SYMBIAN)
+ if (desktopWidget) {
+ symbianScreenNumber = qt_widget_private(desktopWidget)->symbianScreenNumber;
+ }
#elif defined(Q_WS_QPA)
if (desktopWidget) {
- int screen = desktopWidget->d_func()->screenNumber;
+ int screen = desktopWidget->d_func()->topData()->screenIndex;
QPlatformIntegration *platform = QApplicationPrivate::platformIntegration();
platform->moveToScreen(q, screen);
}
@@ -1305,9 +1331,9 @@ void QWidgetPrivate::init(QWidget *parentWidget, Qt::WindowFlags f)
if (f & Qt::MSWindowsOwnDC)
q->setAttribute(Qt::WA_NativeWindow);
-#ifdef Q_WS_MAC
- q->setAttribute(Qt::WA_NativeWindow);
-#endif
+//#ifdef Q_WS_MAC
+// q->setAttribute(Qt::WA_NativeWindow);
+//#endif
q->setAttribute(Qt::WA_QuitOnClose); // might be cleared in adjustQuitOnCloseAttribute()
adjustQuitOnCloseAttribute();
@@ -1317,8 +1343,8 @@ void QWidgetPrivate::init(QWidget *parentWidget, Qt::WindowFlags f)
//give potential windows a bigger "pre-initial" size; create_sys() will give them a new size later
#ifdef Q_OS_SYMBIAN
if (isGLWidget) {
- // Don't waste GPU mem for unnecessary large egl surface
- data.crect = QRect(0,0,2,2);
+ // Don't waste GPU mem for unnecessary large egl surface until resized by application
+ data.crect = QRect(0,0,1,1);
} else {
data.crect = parentWidget ? QRect(0,0,100,30) : QRect(0,0,360,640);
}
@@ -1360,6 +1386,16 @@ void QWidgetPrivate::init(QWidget *parentWidget, Qt::WindowFlags f)
QApplication::postEvent(q, new QEvent(QEvent::PolishRequest));
extraPaintEngine = 0;
+
+#ifdef QT_MAC_USE_COCOA
+ // If we add a child to the unified toolbar, we have to redirect the painting.
+ if (parentWidget && parentWidget->d_func() && parentWidget->d_func()->isInUnifiedToolbar) {
+ if (parentWidget->d_func()->unifiedSurface) {
+ QWidget *toolbar = parentWidget->d_func()->toolbar_ancestor;
+ parentWidget->d_func()->unifiedSurface->recursiveRedirect(toolbar, toolbar, toolbar->d_func()->toolbar_offset);
+ }
+ }
+#endif // QT_MAC_USE_COCOA
}
@@ -1414,10 +1450,6 @@ void QWidget::create(WId window, bool initializeWindow, bool destroyOldWindow)
#ifndef Q_WS_QPA
if (QWidget *parent = parentWidget()) {
-#ifdef Q_WS_MAC
- if (testAttribute(Qt::WA_NativeWindow) == false)
- parent->d_func()->hasAlienChildren = true;
-#endif
if (type & Qt::Window) {
if (!parent->testAttribute(Qt::WA_WState_Created))
parent->createWinId();
@@ -1729,6 +1761,7 @@ void QWidgetPrivate::createTLExtra()
#if defined(Q_WS_QPA)
x->platformWindow = 0;
x->platformWindowFormat = QPlatformWindowFormat::defaultFormat();
+ x->screenIndex = 0;
#endif
}
}
@@ -2077,6 +2110,11 @@ void QWidgetPrivate::subtractOpaqueSiblings(QRegion &sourceRegion, bool *hasDirt
if (disableSubtractOpaqueSiblings || q->isWindow())
return;
+#ifdef QT_MAC_USE_COCOA
+ if (q->d_func()->isInUnifiedToolbar)
+ return;
+#endif // QT_MAC_USE_COCOA
+
QRect clipBoundingRect;
bool dirtyClipBoundingRect = true;
@@ -5400,6 +5438,9 @@ void QWidgetPrivate::drawWidget(QPaintDevice *pdev, const QRegion &rgn, const QP
return;
#if defined(Q_WS_MAC) && defined(QT_MAC_USE_COCOA)
+ if (qt_mac_clearDirtyOnWidgetInsideDrawWidget)
+ dirtyOnWidget = QRegion();
+
// We disable the rendering of QToolBar in the backingStore if
// it's supposed to be in the unified toolbar on Mac OS X.
if (backingStore && isInUnifiedToolbar)
@@ -5487,7 +5528,6 @@ void QWidgetPrivate::drawWidget(QPaintDevice *pdev, const QRegion &rgn, const QP
//paint the background
if ((asRoot || q->autoFillBackground() || onScreen || q->testAttribute(Qt::WA_StyledBackground))
&& !q->testAttribute(Qt::WA_OpaquePaintEvent) && !q->testAttribute(Qt::WA_NoSystemBackground)) {
-
QPainter p(q);
paintBackground(&p, toBePainted, (asRoot || onScreen) ? flags | DrawAsRoot : 0);
}
@@ -5669,10 +5709,12 @@ void QWidgetPrivate::paintSiblingsRecursive(QPaintDevice *pdev, const QObjectLis
QRect boundingRect;
bool dirtyBoundingRect = true;
const bool exludeOpaqueChildren = (flags & DontDrawOpaqueChildren);
+ const bool excludeNativeChildren = (flags & DontDrawNativeChildren);
do {
QWidget *x = qobject_cast<QWidget*>(siblings.at(index));
- if (x && !(exludeOpaqueChildren && x->d_func()->isOpaque) && !x->isHidden() && !x->isWindow()) {
+ if (x && !(exludeOpaqueChildren && x->d_func()->isOpaque) && !x->isHidden() && !x->isWindow()
+ && !(excludeNativeChildren && x->internalWinId())) {
if (dirtyBoundingRect) {
boundingRect = rgn.boundingRect();
dirtyBoundingRect = false;
@@ -10076,7 +10118,13 @@ void QWidget::setParent(QWidget *parent, Qt::WindowFlags f)
#if defined(Q_WS_X11) || defined(Q_WS_WIN) || defined(Q_WS_MAC) || defined(Q_OS_SYMBIAN)
if (newParent && parent && !desktopWidget) {
- if (testAttribute(Qt::WA_NativeWindow) && !qApp->testAttribute(Qt::AA_DontCreateNativeWidgetSiblings))
+ if (testAttribute(Qt::WA_NativeWindow) && !qApp->testAttribute(Qt::AA_DontCreateNativeWidgetSiblings)
+#if defined(Q_WS_MAC) && defined(QT_MAC_USE_COCOA)
+ // On Mac, toolbars inside the unified title bar will never overlap with
+ // siblings in the content view. So we skip enforce native siblings in that case
+ && !d->isInUnifiedToolbar && parentWidget() && parentWidget()->isWindow()
+#endif // Q_WS_MAC && QT_MAC_USE_COCOA
+ )
parent->d_func()->enforceNativeChildren();
else if (parent->d_func()->nativeChildrenForced() || parent->testAttribute(Qt::WA_PaintOnScreen))
setAttribute(Qt::WA_NativeWindow);
@@ -10359,6 +10407,12 @@ void QWidget::repaint(const QRect &rect)
return;
if (hasBackingStoreSupport()) {
+#ifdef QT_MAC_USE_COCOA
+ if (qt_widget_private(this)->isInUnifiedToolbar) {
+ qt_widget_private(this)->unifiedSurface->renderToolbar(this, true);
+ return;
+ }
+#endif // QT_MAC_USE_COCOA
QTLWExtra *tlwExtra = window()->d_func()->maybeTopData();
if (tlwExtra && !tlwExtra->inTopLevelResize && tlwExtra->backingStore) {
tlwExtra->inRepaint = true;
@@ -10388,6 +10442,12 @@ void QWidget::repaint(const QRegion &rgn)
return;
if (hasBackingStoreSupport()) {
+#ifdef QT_MAC_USE_COCOA
+ if (qt_widget_private(this)->isInUnifiedToolbar) {
+ qt_widget_private(this)->unifiedSurface->renderToolbar(this, true);
+ return;
+ }
+#endif // QT_MAC_USE_COCOA
QTLWExtra *tlwExtra = window()->d_func()->maybeTopData();
if (tlwExtra && !tlwExtra->inTopLevelResize && tlwExtra->backingStore) {
tlwExtra->inRepaint = true;
@@ -10445,6 +10505,12 @@ void QWidget::update(const QRect &rect)
}
if (hasBackingStoreSupport()) {
+#ifdef QT_MAC_USE_COCOA
+ if (qt_widget_private(this)->isInUnifiedToolbar) {
+ qt_widget_private(this)->unifiedSurface->renderToolbar(this, true);
+ return;
+ }
+#endif // QT_MAC_USE_COCOA
QTLWExtra *tlwExtra = window()->d_func()->maybeTopData();
if (tlwExtra && !tlwExtra->inTopLevelResize && tlwExtra->backingStore)
tlwExtra->backingStore->markDirty(rect, this);
@@ -10469,6 +10535,12 @@ void QWidget::update(const QRegion &rgn)
}
if (hasBackingStoreSupport()) {
+#ifdef QT_MAC_USE_COCOA
+ if (qt_widget_private(this)->isInUnifiedToolbar) {
+ qt_widget_private(this)->unifiedSurface->renderToolbar(this, true);
+ return;
+ }
+#endif // QT_MAC_USE_COCOA
QTLWExtra *tlwExtra = window()->d_func()->maybeTopData();
if (tlwExtra && !tlwExtra->inTopLevelResize && tlwExtra->backingStore)
tlwExtra->backingStore->markDirty(rgn, this);
@@ -10723,7 +10795,13 @@ void QWidget::setAttribute(Qt::WidgetAttribute attribute, bool on)
ic->setFocusWidget(0);
}
}
- if (!qApp->testAttribute(Qt::AA_DontCreateNativeWidgetSiblings) && parentWidget())
+ if (!qApp->testAttribute(Qt::AA_DontCreateNativeWidgetSiblings) && parentWidget()
+#if defined(Q_WS_MAC) && defined(QT_MAC_USE_COCOA)
+ // On Mac, toolbars inside the unified title bar will never overlap with
+ // siblings in the content view. So we skip enforce native siblings in that case
+ && !d->isInUnifiedToolbar && parentWidget()->isWindow()
+#endif // Q_WS_MAC && QT_MAC_USE_COCOA
+ )
parentWidget()->d_func()->enforceNativeChildren();
if (on && !internalWinId() && testAttribute(Qt::WA_WState_Created))
d->createWinId();
@@ -10763,7 +10841,7 @@ void QWidget::setAttribute(Qt::WidgetAttribute attribute, bool on)
case Qt::WA_InputMethodEnabled: {
#ifndef QT_NO_IM
QWidget *focusWidget = d->effectiveFocusWidget();
- QInputContext *ic = focusWidget->d_func()->ic;
+ QInputContext *ic = focusWidget->d_func()->assignedInputContext();
if (!ic && (!on || hasFocus()))
ic = focusWidget->d_func()->inputContext();
if (ic) {
@@ -10856,6 +10934,42 @@ void QWidget::setAttribute(Qt::WidgetAttribute attribute, bool on)
d->registerTouchWindow();
#endif
break;
+ case Qt::WA_LockPortraitOrientation:
+ case Qt::WA_LockLandscapeOrientation:
+ case Qt::WA_AutoOrientation: {
+ const Qt::WidgetAttribute orientations[3] = {
+ Qt::WA_LockPortraitOrientation,
+ Qt::WA_LockLandscapeOrientation,
+ Qt::WA_AutoOrientation
+ };
+
+ if (on) {
+ // We can only have one of these set at a time
+ for (int i = 0; i < 3; ++i) {
+ if (orientations[i] != attribute)
+ setAttribute_internal(orientations[i], false, data, d);
+ }
+ }
+
+#ifdef Q_WS_S60
+ CAknAppUiBase* appUi = static_cast<CAknAppUiBase*>(CEikonEnv::Static()->EikAppUi());
+ const CAknAppUiBase::TAppUiOrientation s60orientations[] = {
+ CAknAppUiBase::EAppUiOrientationPortrait,
+ CAknAppUiBase::EAppUiOrientationLandscape,
+ CAknAppUiBase::EAppUiOrientationAutomatic
+ };
+ CAknAppUiBase::TAppUiOrientation s60orientation = CAknAppUiBase::EAppUiOrientationUnspecified;
+ for (int i = 0; i < 3; ++i) {
+ if (testAttribute(orientations[i])) {
+ s60orientation = s60orientations[i];
+ break;
+ }
+ }
+ QT_TRAP_THROWING(appUi->SetOrientationL(s60orientation));
+ S60->orientationSet = true;
+#endif
+ break;
+ }
default:
break;
}
@@ -11214,7 +11328,7 @@ void QWidget::updateMicroFocus()
#if !defined(QT_NO_IM) && (defined(Q_WS_X11) || defined(Q_WS_QWS) || defined(Q_OS_SYMBIAN))
Q_D(QWidget);
// and optimization to update input context only it has already been created.
- if (d->ic || qApp->d_func()->inputContext) {
+ if (d->assignedInputContext() || qApp->d_func()->inputContext) {
QInputContext *ic = inputContext();
if (ic)
ic->update();
diff --git a/src/gui/kernel/qwidget_mac.mm b/src/gui/kernel/qwidget_mac.mm
index 376999e..34918e4 100644
--- a/src/gui/kernel/qwidget_mac.mm
+++ b/src/gui/kernel/qwidget_mac.mm
@@ -155,7 +155,6 @@ static bool qt_mac_raise_process = true;
static OSWindowRef qt_root_win = 0;
QWidget *mac_mouse_grabber = 0;
QWidget *mac_keyboard_grabber = 0;
-extern QPointer<QWidget> qt_button_down; //qapplication_mac.cpp
#ifndef QT_MAC_USE_COCOA
#ifdef QT_NAMESPACE
@@ -179,13 +178,15 @@ static CFStringRef kObjectQWidget = CFSTR("com.trolltech.qt.widget");
/*****************************************************************************
Externals
*****************************************************************************/
+extern QPointer<QWidget> qt_button_down; //qapplication_mac.cpp
extern QWidget *qt_mac_modal_blocked(QWidget *); //qapplication_mac.mm
extern void qt_event_request_activate(QWidget *); //qapplication_mac.mm
extern bool qt_event_remove_activate(); //qapplication_mac.mm
extern void qt_mac_event_release(QWidget *w); //qapplication_mac.mm
extern void qt_event_request_showsheet(QWidget *); //qapplication_mac.mm
extern void qt_event_request_window_change(QWidget *); //qapplication_mac.mm
-extern QPointer<QWidget> qt_mouseover; //qapplication_mac.mm
+extern QPointer<QWidget> qt_last_mouse_receiver; //qapplication_mac.mm
+extern QPointer<QWidget> qt_last_native_mouse_receiver; //qt_cocoa_helpers_mac.mm
extern IconRef qt_mac_create_iconref(const QPixmap &); //qpixmap_mac.cpp
extern void qt_mac_set_cursor(const QCursor *, const QPoint &); //qcursor_mac.mm
extern void qt_mac_update_cursor(); //qcursor_mac.mm
@@ -193,7 +194,8 @@ extern bool qt_nograb();
extern CGImageRef qt_mac_create_cgimage(const QPixmap &, bool); //qpixmap_mac.cpp
extern RgnHandle qt_mac_get_rgn(); //qregion_mac.cpp
extern QRegion qt_mac_convert_mac_region(RgnHandle rgn); //qregion_mac.cpp
-
+extern void qt_mac_setMouseGrabCursor(bool set, QCursor *cursor = 0); // qcursor_mac.mm
+extern QPointer<QWidget> topLevelAt_cache; // qapplication_mac.mm
/*****************************************************************************
QWidget utility functions
*****************************************************************************/
@@ -217,22 +219,13 @@ static QSize qt_mac_desktopSize()
#ifdef QT_MAC_USE_COCOA
static NSDrawer *qt_mac_drawer_for(const QWidget *widget)
{
- // This only goes one level below the content view so start with the window.
- // This works fine for straight Qt stuff, but runs into problems if we are
- // embedding, but if that's the case, they probably want to be using
- // NSDrawer directly.
- NSView *widgetView = reinterpret_cast<NSView *>(widget->window()->winId());
+ NSView *widgetView = reinterpret_cast<NSView *>(widget->window()->effectiveWinId());
NSArray *windows = [NSApp windows];
for (NSWindow *window in windows) {
NSArray *drawers = [window drawers];
for (NSDrawer *drawer in drawers) {
if ([drawer contentView] == widgetView)
return drawer;
- NSArray *views = [[drawer contentView] subviews];
- for (NSView *view in views) {
- if (view == widgetView)
- return drawer;
- }
}
}
return 0;
@@ -314,7 +307,7 @@ bool qt_mac_is_macdrawer(const QWidget *w)
bool qt_mac_insideKeyWindow(const QWidget *w)
{
#ifdef QT_MAC_USE_COCOA
- return [[reinterpret_cast<NSView *>(w->winId()) window] isKeyWindow];
+ return [[reinterpret_cast<NSView *>(w->effectiveWinId()) window] isKeyWindow];
#else
Q_UNUSED(w);
#endif
@@ -421,7 +414,14 @@ inline static void qt_mac_set_fullscreen_mode(bool b)
Q_GUI_EXPORT OSViewRef qt_mac_nativeview_for(const QWidget *w)
{
- return reinterpret_cast<OSViewRef>(w->data->winid);
+ return reinterpret_cast<OSViewRef>(w->internalWinId());
+}
+
+Q_GUI_EXPORT OSViewRef qt_mac_effectiveview_for(const QWidget *w)
+{
+ // Get the first non-alien (parent) widget for
+ // w, and return its NSView (if it has one):
+ return reinterpret_cast<OSViewRef>(w->effectiveWinId());
}
Q_GUI_EXPORT OSViewRef qt_mac_get_contentview_for(OSWindowRef w)
@@ -479,11 +479,12 @@ bool qt_isGenuineQWidget(const QWidget *window)
Q_GUI_EXPORT OSWindowRef qt_mac_window_for(const QWidget *w)
{
- OSViewRef hiview = qt_mac_nativeview_for(w);
- if (hiview){
+ if (OSViewRef hiview = qt_mac_effectiveview_for(w)) {
OSWindowRef window = qt_mac_window_for(hiview);
- if (!window && qt_isGenuineQWidget(hiview)) {
- QWidget *myWindow = w->window();
+ if (window)
+ return window;
+
+ if (qt_isGenuineQWidget(hiview)) {
// This is a workaround for NSToolbar. When a widget is hidden
// by clicking the toolbar button, Cocoa reparents the widgets
// to another window (but Qt doesn't know about it).
@@ -491,18 +492,22 @@ Q_GUI_EXPORT OSWindowRef qt_mac_window_for(const QWidget *w)
// but at this point it's window is nil, but the window it's being brought
// into (the Qt one) is for sure created.
// This stops the hierarchy moving under our feet.
- if (myWindow != w && qt_mac_window_for(qt_mac_nativeview_for(myWindow)))
- return qt_mac_window_for(qt_mac_nativeview_for(myWindow));
+ QWidget *toplevel = w->window();
+ if (toplevel != w) {
+ hiview = qt_mac_nativeview_for(toplevel);
+ if (OSWindowRef w = qt_mac_window_for(hiview))
+ return w;
+ }
- myWindow->d_func()->createWindow_sys();
- // Reget the hiview since the "create window could potentially move the view (I guess).
- hiview = qt_mac_nativeview_for(w);
- window = qt_mac_window_for(hiview);
+ toplevel->d_func()->createWindow_sys();
+ // Reget the hiview since "create window" could potentially move the view (I guess).
+ hiview = qt_mac_nativeview_for(toplevel);
+ return qt_mac_window_for(hiview);
}
- return window;
}
return 0;
}
+
#ifndef QT_MAC_USE_COCOA
/* Checks if the current group is a 'stay on top' group. If so, the
group gets removed from the hash table */
@@ -580,25 +585,6 @@ inline static void qt_mac_set_window_group_to_popup(OSWindowRef window)
}
#endif
-#ifdef QT_MAC_USE_COCOA
-void qt_mac_set_needs_display(QWidget *widget, QRegion region)
-{
- NSView *theNSView = qt_mac_nativeview_for(widget);
- if (region.isEmpty()) {
- [theNSView setNeedsDisplay:YES];
- return;
- }
-
- QVector<QRect> rects = region.rects();
- for (int i = 0; i<rects.count(); ++i) {
- const QRect &rect = rects.at(i);
- NSRect nsrect = NSMakeRect(rect.x(), rect.y(), rect.width(), rect.height());
- [theNSView setNeedsDisplayInRect:nsrect];
- }
-
-}
-#endif
-
inline static bool updateRedirectedToGraphicsProxyWidget(QWidget *widget, const QRect &rect)
{
if (!widget)
@@ -636,6 +622,51 @@ inline static bool updateRedirectedToGraphicsProxyWidget(QWidget *widget, const
return false;
}
+void QWidgetPrivate::macSetNeedsDisplay(QRegion region)
+{
+ Q_Q(QWidget);
+#ifndef QT_MAC_USE_COCOA
+ if (region.isEmpty())
+ HIViewSetNeedsDisplay(qt_mac_nativeview_for(q), true);
+ else if (RgnHandle rgnHandle = region.toQDRgnForUpdate_sys())
+ HIViewSetNeedsDisplayInRegion(qt_mac_nativeview_for(q), QMacSmartQuickDrawRegion(rgnHandle), true);
+ else
+ HIViewSetNeedsDisplay(qt_mac_nativeview_for(q), true); // do a complete repaint on overflow.
+#else
+ if (NSView *nativeView = qt_mac_nativeview_for(q)) {
+ // INVARIANT: q is _not_ alien. So we can optimize a little:
+ if (region.isEmpty()) {
+ [nativeView setNeedsDisplay:YES];
+ } else {
+ QVector<QRect> rects = region.rects();
+ for (int i = 0; i<rects.count(); ++i) {
+ const QRect &rect = rects.at(i);
+ NSRect nsrect = NSMakeRect(rect.x(), rect.y(), rect.width(), rect.height());
+ [nativeView setNeedsDisplayInRect:nsrect];
+ }
+ }
+ } else if (QWidget *effectiveWidget = q->nativeParentWidget()) {
+ // INVARIANT: q is alien, and effectiveWidget is native.
+ if (NSView *effectiveView = qt_mac_nativeview_for(effectiveWidget)) {
+ if (region.isEmpty()) {
+ const QRect &rect = q->rect();
+ QPoint p = q->mapTo(effectiveWidget, rect.topLeft());
+ NSRect nsrect = NSMakeRect(p.x(), p.y(), rect.width(), rect.height());
+ [effectiveView setNeedsDisplayInRect:nsrect];
+ } else {
+ QVector<QRect> rects = region.rects();
+ for (int i = 0; i<rects.count(); ++i) {
+ const QRect &rect = rects.at(i);
+ QPoint p = q->mapTo(effectiveWidget, rect.topLeft());
+ NSRect nsrect = NSMakeRect(p.x(), p.y(), rect.width(), rect.height());
+ [effectiveView setNeedsDisplayInRect:nsrect];
+ }
+ }
+ }
+ }
+#endif
+}
+
void QWidgetPrivate::macUpdateIsOpaque()
{
Q_Q(QWidget);
@@ -1569,6 +1600,11 @@ OSViewRef qt_mac_create_widget(QWidget *widget, QWidgetPrivate *widgetPrivate, O
#ifdef QT_MAC_USE_COCOA
QMacCocoaAutoReleasePool pool;
QT_MANGLE_NAMESPACE(QCocoaView) *view = [[QT_MANGLE_NAMESPACE(QCocoaView) alloc] initWithQWidget:widget widgetPrivate:widgetPrivate];
+
+#ifdef ALIEN_DEBUG
+ qDebug() << "Creating NSView for" << widget;
+#endif
+
if (view && parent)
[parent addSubview:view];
return view;
@@ -1635,7 +1671,7 @@ bool QWidgetPrivate::qt_mac_update_sizer(QWidget *w, int up)
// to happen, prevent that here (you really want the thing hidden).
if (up >= 0 || topData->resizer != 0)
topData->resizer += up;
- OSWindowRef windowRef = qt_mac_window_for(OSViewRef(w->winId()));
+ OSWindowRef windowRef = qt_mac_window_for(OSViewRef(w->effectiveWinId()));
{
#ifndef QT_MAC_USE_COCOA
WindowClass wclass;
@@ -1670,6 +1706,7 @@ bool QWidgetPrivate::qt_mac_update_sizer(QWidget *w, int up)
void QWidgetPrivate::qt_clean_root_win()
{
#ifdef QT_MAC_USE_COCOA
+ QMacCocoaAutoReleasePool pool;
[qt_root_win release];
#else
if(!qt_root_win)
@@ -2310,15 +2347,12 @@ void QWidgetPrivate::finishCreateWindow_sys_Cocoa(void * /*NSWindow * */ voidWin
}
[windowRef setContentView:nsview];
[nsview setHidden:NO];
- if (q->testAttribute(Qt::WA_DropSiteRegistered))
- registerDropSite(true);
transferChildren();
// Tell Cocoa explicit that we wan't the view to receive key events
// (regardless of focus policy) because this is how it works on other
// platforms (and in the carbon port):
- if (!qApp->focusWidget())
- [windowRef makeFirstResponder:nsview];
+ [windowRef makeFirstResponder:nsview];
if (topExtra->posFromMove) {
updateFrameStrut();
@@ -2349,8 +2383,9 @@ void QWidgetPrivate::finishCreateWindow_sys_Cocoa(void * /*NSWindow * */ voidWin
q->setAttribute(Qt::WA_WState_WindowOpacitySet, false);
}
- if (qApp->overrideCursor())
- [windowRef disableCursorRects];
+ // Its more performant to handle the mouse cursor
+ // ourselves, expecially when using alien widgets:
+ [windowRef disableCursorRects];
setWindowLevel();
macUpdateHideOnSuspend();
@@ -2441,6 +2476,8 @@ void QWidgetPrivate::createWindow_sys()
void QWidgetPrivate::create_sys(WId window, bool initializeWindow, bool destroyOldWindow)
{
Q_Q(QWidget);
+ QMacCocoaAutoReleasePool pool;
+
OSViewRef destroyid = 0;
#ifndef QT_MAC_USE_COCOA
window_event = 0;
@@ -2468,8 +2505,6 @@ void QWidgetPrivate::create_sys(WId window, bool initializeWindow, bool destroyO
data.crect.setRect(0, 0, desktopSize.width(), desktopSize.height());
dialog = popup = false; // force these flags off
} else {
- q->setAttribute(Qt::WA_WState_Visible, false);
-
if (topLevel && (type != Qt::Drawer)) {
if (QDesktopWidget *dsk = QApplication::desktop()) { // calc pos/size from screen
const bool wasResized = q->testAttribute(Qt::WA_Resized);
@@ -2559,6 +2594,8 @@ void QWidgetPrivate::create_sys(WId window, bool initializeWindow, bool destroyO
transfer = true;
} else if (parentWidget) {
// I need to be added to my parent, therefore my parent needs an NSView
+ // Alien note: a 'window' was supplied as argument, meaning this widget
+ // is not alien. So therefore the parent cannot be alien either.
parentWidget->createWinId();
parent = qt_mac_nativeview_for(parentWidget);
}
@@ -2630,11 +2667,8 @@ void QWidgetPrivate::create_sys(WId window, bool initializeWindow, bool destroyO
data.fstrut_dirty = false; // non-toplevel widgets don't have a frame, so no need to update the strut
#ifdef QT_MAC_USE_COCOA
- if (q->testAttribute(Qt::WA_NativeWindow) == false ||
- q->internalWinId() != 0) {
-#ifdef ALIEN_DEBUG
- qDebug() << "Skipping native widget creation for" << this;
-#endif
+ if (q->testAttribute(Qt::WA_NativeWindow) == false || q->internalWinId() != 0) {
+ // INVARIANT: q is Alien, and we should not create an NSView to back it up.
} else
#endif
if (OSViewRef osview = qt_mac_create_widget(q, this, qt_mac_nativeview_for(parentWidget))) {
@@ -2646,21 +2680,26 @@ void QWidgetPrivate::create_sys(WId window, bool initializeWindow, bool destroyO
NSRect bounds = NSMakeRect(data.crect.x(), data.crect.y(), data.crect.width(), data.crect.height());
[osview setFrame:bounds];
setWinId((WId)osview);
+ if (q->isVisible()) {
+ // If q were Alien before, but now became native (e.g. if a call to
+ // winId was done from somewhere), we need to show the view immidiatly:
+ QMacCocoaAutoReleasePool pool;
+ [osview setHidden:NO];
+ }
#endif
- if (q->testAttribute(Qt::WA_DropSiteRegistered))
- registerDropSite(true);
}
}
updateIsOpaque();
+
+ if (q->testAttribute(Qt::WA_DropSiteRegistered))
+ registerDropSite(true);
if (q->hasFocus())
setFocus_sys();
if (!topLevel && initializeWindow)
setWSGeometry();
if (destroyid)
qt_mac_destructView(destroyid);
- if (q->testAttribute(Qt::WA_AcceptTouchEvents))
- registerTouchWindow();
}
/*!
@@ -2694,16 +2733,29 @@ QWidget::macCGHandle() const
return handle();
}
+void qt_mac_repaintParentUnderAlienWidget(QWidget *alienWidget)
+{
+ QWidget *nativeParent = alienWidget->nativeParentWidget();
+ if (!nativeParent)
+ return;
+
+ QPoint globalPos = alienWidget->mapToGlobal(QPoint(0, 0));
+ QRect dirtyRect = QRect(nativeParent->mapFromGlobal(globalPos), alienWidget->size());
+ nativeParent->repaint(dirtyRect);
+}
+
void QWidget::destroy(bool destroyWindow, bool destroySubWindows)
{
Q_D(QWidget);
+ QMacCocoaAutoReleasePool pool;
d->aboutToDestroy();
if (!isWindow() && parentWidget())
parentWidget()->d_func()->invalidateBuffer(d->effectiveRectFor(geometry()));
+ if (!internalWinId())
+ qt_mac_repaintParentUnderAlienWidget(this);
d->deactivateWidgetCleanup();
qt_mac_event_release(this);
if(testAttribute(Qt::WA_WState_Created)) {
- QMacCocoaAutoReleasePool pool;
setAttribute(Qt::WA_WState_Created, false);
QObjectList chldrn = children();
for(int i = 0; i < chldrn.size(); i++) { // destroy all widget children
@@ -2759,7 +2811,7 @@ void QWidget::destroy(bool destroyWindow, bool destroySubWindows)
void QWidgetPrivate::transferChildren()
{
Q_Q(QWidget);
- if (!q->testAttribute(Qt::WA_WState_Created))
+ if (!q->internalWinId())
return; // Can't add any views anyway
QObjectList chlist = q->children();
@@ -2771,7 +2823,7 @@ void QWidgetPrivate::transferChildren()
// This seems weird, no need to call it in a loop right?
if (!topData()->caption.isEmpty())
setWindowTitle_helper(extra->topextra->caption);
- if (w->testAttribute(Qt::WA_WState_Created)) {
+ if (w->internalWinId()) {
#ifndef QT_MAC_USE_COCOA
HIViewAddSubview(qt_mac_nativeview_for(q), qt_mac_nativeview_for(w));
#else
@@ -2900,11 +2952,11 @@ void QWidgetPrivate::setParent_sys(QWidget *parent, Qt::WindowFlags f)
#ifndef QT_MAC_USE_COCOA
old_window_event = window_event;
#else
- OSWindowRef oldWindow = qt_mac_window_for(old_id);
if (qt_mac_is_macdrawer(q)) {
oldDrawer = qt_mac_drawer_for(q);
}
if (wasWindow) {
+ OSWindowRef oldWindow = qt_mac_window_for(old_id);
oldToolbar = [oldWindow toolbar];
if (oldToolbar) {
[oldToolbar retain];
@@ -3026,7 +3078,7 @@ void QWidgetPrivate::setParent_sys(QWidget *parent, Qt::WindowFlags f)
QPoint QWidget::mapToGlobal(const QPoint &pos) const
{
Q_D(const QWidget);
- if (!testAttribute(Qt::WA_WState_Created) || !internalWinId()) {
+ if (!internalWinId()) {
QPoint p = pos + data->crect.topLeft();
return isWindow() ? p : parentWidget()->mapToGlobal(p);
}
@@ -3053,7 +3105,7 @@ QPoint QWidget::mapToGlobal(const QPoint &pos) const
QPoint QWidget::mapFromGlobal(const QPoint &pos) const
{
Q_D(const QWidget);
- if (!testAttribute(Qt::WA_WState_Created) || !internalWinId()) {
+ if (!internalWinId()) {
QPoint p = isWindow() ? pos : parentWidget()->mapFromGlobal(pos);
return p - data->crect.topLeft();
}
@@ -3080,28 +3132,12 @@ void QWidgetPrivate::updateSystemBackground()
void QWidgetPrivate::setCursor_sys(const QCursor &)
{
-#ifndef QT_MAC_USE_COCOA
qt_mac_update_cursor();
-#else
- Q_Q(QWidget);
- if (q->testAttribute(Qt::WA_WState_Created)) {
- QMacCocoaAutoReleasePool pool;
- [qt_mac_window_for(q) invalidateCursorRectsForView:qt_mac_nativeview_for(q)];
- }
-#endif
}
void QWidgetPrivate::unsetCursor_sys()
{
-#ifndef QT_MAC_USE_COCOA
qt_mac_update_cursor();
-#else
- Q_Q(QWidget);
- if (q->testAttribute(Qt::WA_WState_Created)) {
- QMacCocoaAutoReleasePool pool;
- [qt_mac_window_for(q) invalidateCursorRectsForView:qt_mac_nativeview_for(q)];
- }
-#endif
}
void QWidgetPrivate::setWindowTitle_sys(const QString &caption)
@@ -3205,6 +3241,8 @@ void QWidgetPrivate::setWindowIcon_sys(bool forceReset)
ReleaseIconRef(previousIcon);
#else
QMacCocoaAutoReleasePool pool;
+ if (icon.isNull())
+ return;
NSButton *iconButton = [qt_mac_window_for(q) standardWindowButton:NSWindowDocumentIconButton];
if (iconButton == nil) {
QCFString string(q->windowTitle());
@@ -3243,24 +3281,28 @@ void QWidget::grabMouse()
if(mac_mouse_grabber)
mac_mouse_grabber->releaseMouse();
mac_mouse_grabber=this;
+ qt_mac_setMouseGrabCursor(true);
}
}
#ifndef QT_NO_CURSOR
-void QWidget::grabMouse(const QCursor &)
+void QWidget::grabMouse(const QCursor &cursor)
{
if(isVisible() && !qt_nograb()) {
if(mac_mouse_grabber)
mac_mouse_grabber->releaseMouse();
mac_mouse_grabber=this;
+ qt_mac_setMouseGrabCursor(true, const_cast<QCursor *>(&cursor));
}
}
#endif
void QWidget::releaseMouse()
{
- if(!qt_nograb() && mac_mouse_grabber == this)
+ if(!qt_nograb() && mac_mouse_grabber == this) {
mac_mouse_grabber = 0;
+ qt_mac_setMouseGrabCursor(false);
+ }
}
void QWidget::grabKeyboard()
@@ -3345,35 +3387,10 @@ QWindowSurface *QWidgetPrivate::createDefaultWindowSurface_sys()
void QWidgetPrivate::update_sys(const QRect &r)
{
Q_Q(QWidget);
- if (r == q->rect()) {
- if (updateRedirectedToGraphicsProxyWidget(q, r))
- return;
- dirtyOnWidget += r;
-#ifndef QT_MAC_USE_COCOA
- HIViewSetNeedsDisplay(qt_mac_nativeview_for(q), true);
-#else
- qt_mac_set_needs_display(q, QRegion());
-#endif
+ if (updateRedirectedToGraphicsProxyWidget(q, r))
return;
- }
-
- int x = r.x(), y = r.y(), w = r.width(), h = r.height();
- if (w < 0)
- w = q->data->crect.width() - x;
- if (h < 0)
- h = q->data->crect.height() - y;
- if (w && h) {
- const QRect updateRect = QRect(x, y, w, h);
- if (updateRedirectedToGraphicsProxyWidget(q, updateRect))
- return;
-#ifndef QT_MAC_USE_COCOA
- dirtyOnWidget += updateRect;
- HIRect r = CGRectMake(x, y, w, h);
- HIViewSetNeedsDisplayInRect(qt_mac_nativeview_for(q), &r, true);
-#else
- [qt_mac_nativeview_for(q) setNeedsDisplayInRect:NSMakeRect(x, y, w, h)];
-#endif
- }
+ dirtyOnWidget += r;
+ macSetNeedsDisplay(r != q->rect() ? r : QRegion());
}
void QWidgetPrivate::update_sys(const QRegion &rgn)
@@ -3382,33 +3399,7 @@ void QWidgetPrivate::update_sys(const QRegion &rgn)
if (updateRedirectedToGraphicsProxyWidget(q, rgn))
return;
dirtyOnWidget += rgn;
-#ifndef QT_MAC_USE_COCOA
- RgnHandle rgnHandle = rgn.toQDRgnForUpdate_sys();
- if (rgnHandle)
- HIViewSetNeedsDisplayInRegion(qt_mac_nativeview_for(q), QMacSmartQuickDrawRegion(rgnHandle), true);
- else {
- HIViewSetNeedsDisplay(qt_mac_nativeview_for(q), true); // do a complete repaint on overflow.
- }
-#else
- // Alien support: get the first native ancestor widget (will be q itself in the non-alien case),
- // map the coordinates from q space to NSView space and invalidate the rect.
- QWidget *nativeParent = q->internalWinId() ? q : q->nativeParentWidget();
- if (nativeParent == 0)
- return;
-
- QVector<QRect> rects = rgn.rects();
- for (int i = 0; i < rects.count(); ++i) {
- const QRect &rect = rects.at(i);
-
- const QRect nativeBoundingRect = QRect(
- QPoint(q->mapTo(nativeParent, rect.topLeft())),
- QSize(rect.size()));
-
- [qt_mac_nativeview_for(nativeParent) setNeedsDisplayInRect:NSMakeRect(nativeBoundingRect.x(),
- nativeBoundingRect.y(), nativeBoundingRect.width(),
- nativeBoundingRect.height())];
- }
-#endif
+ macSetNeedsDisplay(rgn);
}
bool QWidgetPrivate::isRealWindow() const
@@ -3447,7 +3438,6 @@ void QWidgetPrivate::show_sys()
data.fstrut_dirty = true;
if (realWindow) {
- // Delegates can change window state, so record some things earlier.
bool isCurrentlyMinimized = (q->windowState() & Qt::WindowMinimized);
setModal_sys();
OSWindowRef window = qt_mac_window_for(q);
@@ -3494,9 +3484,11 @@ void QWidgetPrivate::show_sys()
}
}
setSubWindowStacking(true);
+ qt_mac_update_cursor();
#endif
if (q->windowType() == Qt::Popup) {
- if (q->focusWidget())
+ qt_button_down = 0;
+ if (q->focusWidget())
q->focusWidget()->d_func()->setFocus_sys();
else
setFocus_sys();
@@ -3518,21 +3510,34 @@ void QWidgetPrivate::show_sys()
#ifndef QT_MAC_USE_COCOA
HIViewSetVisible(qt_mac_nativeview_for(q), true);
#else
- [qt_mac_nativeview_for(q) setHidden:NO];
-
+ if (NSView *view = qt_mac_nativeview_for(q)) {
+ // INVARIANT: q is native. Just show the view:
+ [view setHidden:NO];
+ } else {
+ // INVARIANT: q is alien. Repaint q instead:
+ q->repaint();
+ }
#endif
}
- if (!QWidget::mouseGrabber()){
- QWidget *enterWidget = QApplication::widgetAt(QCursor::pos());
- QApplicationPrivate::dispatchEnterLeave(enterWidget, qt_mouseover);
- qt_mouseover = enterWidget;
+#ifdef QT_MAC_USE_COCOA
+ if ([NSApp isActive] && !qt_button_down && !QWidget::mouseGrabber()){
+ // Update enter/leave immidiatly, don't wait for a move event. But only
+ // if no grab exists (even if the grab points to this widget, it seems, ref X11)
+ QPoint qlocal, qglobal;
+ QWidget *widgetUnderMouse = 0;
+ qt_mac_getTargetForMouseEvent(0, QEvent::Enter, qlocal, qglobal, 0, &widgetUnderMouse);
+ QApplicationPrivate::dispatchEnterLeave(widgetUnderMouse, qt_last_mouse_receiver);
+ qt_last_mouse_receiver = widgetUnderMouse;
+ qt_last_native_mouse_receiver = widgetUnderMouse ?
+ (widgetUnderMouse->internalWinId() ? widgetUnderMouse : widgetUnderMouse->nativeParentWidget()) : 0;
}
+#endif
+ topLevelAt_cache = 0;
qt_event_request_window_change(q);
}
-
QPoint qt_mac_nativeMapFromParent(const QWidget *child, const QPoint &pt)
{
#ifndef QT_MAC_USE_COCOA
@@ -3613,6 +3618,7 @@ void QWidgetPrivate::hide_sys()
}
#endif
toggleDrawers(false);
+ qt_mac_update_cursor();
#ifndef QT_MAC_USE_COCOA
// Clear modality (because it seems something that we've always done).
if (data.window_modality != Qt::NonModal) {
@@ -3660,18 +3666,31 @@ void QWidgetPrivate::hide_sys()
#ifndef QT_MAC_USE_COCOA
HIViewSetVisible(qt_mac_nativeview_for(q), false);
#else
- [qt_mac_nativeview_for(q) setHidden:YES];
+ if (NSView *view = qt_mac_nativeview_for(q)) {
+ // INVARIANT: q is native. Just hide the view:
+ [view setHidden:YES];
+ } else {
+ // INVARIANT: q is alien. Repaint where q is placed instead:
+ qt_mac_repaintParentUnderAlienWidget(q);
+ }
#endif
}
- if (!QWidget::mouseGrabber()){
- QWidget *enterWidget = QApplication::widgetAt(QCursor::pos());
- if (enterWidget && enterWidget->data->in_destructor)
- enterWidget = 0;
- QApplicationPrivate::dispatchEnterLeave(enterWidget, qt_mouseover);
- qt_mouseover = enterWidget;
- }
-
+#ifdef QT_MAC_USE_COCOA
+ if ([NSApp isActive] && !qt_button_down && !QWidget::mouseGrabber()){
+ // Update enter/leave immidiatly, don't wait for a move event. But only
+ // if no grab exists (even if the grab points to this widget, it seems, ref X11)
+ QPoint qlocal, qglobal;
+ QWidget *widgetUnderMouse = 0;
+ qt_mac_getTargetForMouseEvent(0, QEvent::Leave, qlocal, qglobal, 0, &widgetUnderMouse);
+ QApplicationPrivate::dispatchEnterLeave(widgetUnderMouse, qt_last_native_mouse_receiver);
+ qt_last_mouse_receiver = widgetUnderMouse;
+ qt_last_native_mouse_receiver = widgetUnderMouse ?
+ (widgetUnderMouse->internalWinId() ? widgetUnderMouse : widgetUnderMouse->nativeParentWidget()) : 0;
+ }
+#endif
+
+ topLevelAt_cache = 0;
qt_event_request_window_change(q);
deactivateWidgetCleanup();
qt_mac_event_release(q);
@@ -3894,12 +3913,14 @@ void QWidgetPrivate::raise_sys()
QWidget *parentWidget = q->parentWidget();
if(parentWidget) {
OSWindowRef parentWindow = qt_mac_window_for(parentWidget);
- if(parentWindow && [parentWindow isOnActiveSpace]) {
- // The window was created in a different space. Therefore if we want
- // to show it in the current space we need to recreate it in the new
- // space.
- recreateMacWindow();
- window = qt_mac_window_for(q);
+ if(parentWindow && [parentWindow respondsToSelector:@selector(isOnActiveSpace)]) {
+ if ([parentWindow performSelector:@selector(isOnActiveSpace)]) {
+ // The window was created in a different space. Therefore if we want
+ // to show it in the current space we need to recreate it in the new
+ // space.
+ recreateMacWindow();
+ window = qt_mac_window_for(q);
+ }
}
}
}
@@ -3916,6 +3937,7 @@ void QWidgetPrivate::raise_sys()
NSView *parentView = [view superview];
[parentView sortSubviewsUsingFunction:compareViews2Raise context:reinterpret_cast<void *>(view)];
}
+ topLevelAt_cache = 0;
#else
if(q->isWindow()) {
//raise this window
@@ -3956,6 +3978,7 @@ void QWidgetPrivate::lower_sys()
NSView *parentView = [view superview];
[parentView sortSubviewsUsingFunction:compareViews2Lower context:reinterpret_cast<void *>(view)];
}
+ topLevelAt_cache = 0;
#else
if(q->isWindow()) {
SendBehind(qt_mac_window_for(q), 0);
@@ -4012,6 +4035,7 @@ void QWidgetPrivate::stackUnder_sys(QWidget *w)
#endif
}
+#ifndef QT_MAC_USE_COCOA
/*
Modifies the bounds for a widgets backing HIView during moves and resizes. Also updates the
widget, either by scrolling its contents or repainting, depending on the WA_StaticContents
@@ -4019,7 +4043,6 @@ void QWidgetPrivate::stackUnder_sys(QWidget *w)
*/
static void qt_mac_update_widget_position(QWidget *q, QRect oldRect, QRect newRect)
{
-#ifndef QT_MAC_USE_COCOA
HIRect bounds = CGRectMake(newRect.x(), newRect.y(),
newRect.width(), newRect.height());
@@ -4111,13 +4134,8 @@ static void qt_mac_update_widget_position(QWidget *q, QRect oldRect, QRect newRe
HIViewSetNeedsDisplayInRect(view, &verticalSlice, true);
const HIRect horizontalSlice = CGRectMake(0, starty, startx, stopy);
HIViewSetNeedsDisplayInRect(view, &horizontalSlice, true);
-#else
- Q_UNUSED(oldRect);
- NSRect bounds = NSMakeRect(newRect.x(), newRect.y(),
- newRect.width(), newRect.height());
- [qt_mac_nativeview_for(q) setFrame:bounds];
-#endif
}
+#endif
/*
Helper function for non-toplevel widgets. Helps to map Qt's 32bit
@@ -4138,7 +4156,15 @@ void QWidgetPrivate::setWSGeometry(bool dontShow, const QRect &oldRect)
{
Q_Q(QWidget);
Q_ASSERT(q->testAttribute(Qt::WA_WState_Created));
- Q_UNUSED(oldRect);
+
+ if (!q->internalWinId() && QApplicationPrivate::graphicsSystem() != 0) {
+ // We have no view to move, and no paint engine that
+ // we can update dirty regions on. So just return:
+ return;
+ }
+
+ QMacCocoaAutoReleasePool pool;
+
/*
There are up to four different coordinate systems here:
Qt coordinate system for this widget.
@@ -4146,13 +4172,31 @@ void QWidgetPrivate::setWSGeometry(bool dontShow, const QRect &oldRect)
Qt coordinate system for parent
X coordinate system for parent (relative to parent's wrect).
*/
+
+ // wrect is the same as crect, except that it is
+ // clipped to fit inside parent (and screen):
QRect wrect;
- //xrect is the X geometry of my X widget. (starts out in parent's Qt coord sys, and ends up in parent's X coord sys)
- QRect xrect = data.crect;
+ // wrectInParentCoordSys will be the same as wrect, except that it is
+ // originated in q's parent rather than q itself. It starts out in
+ // parent's Qt coord system, and ends up in parent's coordinate system:
+ QRect wrectInParentCoordSys = data.crect;
+
+ // If q's parent has been clipped, parentWRect will
+ // be filled with the parents clipped crect:
QRect parentWRect;
+
+ // Embedded have different meaning on each platform, and on
+ // Mac, it means that q is a QMacNativeWidget.
bool isEmbeddedWindow = (q->isWindow() && topData()->embedded);
- if (isEmbeddedWindow) {
+#ifdef QT_MAC_USE_COCOA
+ NSView *nsview = qt_mac_nativeview_for(q);
+#endif
+ if (!isEmbeddedWindow) {
+ parentWRect = q->parentWidget()->data->wrect;
+ } else {
+ // INVARIANT: q's parent view is not owned by Qt. So we need to
+ // do some extra calls to get the clipped rect of the parent view:
#ifndef QT_MAC_USE_COCOA
HIViewRef parentView = HIViewGetSuperview(qt_mac_nativeview_for(q));
#else
@@ -4171,43 +4215,57 @@ void QWidgetPrivate::setWSGeometry(bool dontShow, const QRect &oldRect)
const QRect wrectRange(-WRECT_MAX,-WRECT_MAX, 2*WRECT_MAX, 2*WRECT_MAX);
parentWRect = wrectRange;
}
- } else {
- parentWRect = q->parentWidget()->data->wrect;
}
if (parentWRect.isValid()) {
- // parent is clipped, and we have to clip to the same limit as parent
- if (!parentWRect.contains(xrect) && !isEmbeddedWindow) {
- xrect &= parentWRect;
- wrect = xrect;
- //translate from parent's to my Qt coord sys
+ // INVARIANT: q's parent has been clipped.
+ // So we fit our own wrects inside it:
+ if (!parentWRect.contains(wrectInParentCoordSys) && !isEmbeddedWindow) {
+ wrectInParentCoordSys &= parentWRect;
+ wrect = wrectInParentCoordSys;
+ // Make sure wrect is originated in q's coordinate system:
wrect.translate(-data.crect.topLeft());
}
- //translate from parent's Qt coords to parent's X coords
- xrect.translate(-parentWRect.topLeft());
-
+ // // Make sure wrectInParentCoordSys originated in q's parent coordinate system:
+ wrectInParentCoordSys.translate(-parentWRect.topLeft());
} else {
- // parent is not clipped, we may or may not have to clip
+ // INVARIANT: we dont know yet the clipping rect of q's parent.
+ // So we may or may not have to adjust our wrects:
if (data.wrect.isValid() && QRect(QPoint(),data.crect.size()).contains(data.wrect)) {
- // This is where the main optimization is: we are already
- // clipped, and if our clip is still valid, we can just
- // move our window, and do not need to move or clip
- // children
+ // This is where the main optimization is: we have an old wrect from an earlier
+ // setGeometry call, and the new crect is smaller than it. If the final wrect is
+ // also inside the old wrect, we can just move q and its children to the new
+ // location without any clipping:
+
+ // vrect will be the part of q that's will be visible inside
+ // q's parent. If it inside the old wrect, then we can just move:
+ QRect vrect = wrectInParentCoordSys & q->parentWidget()->rect();
+ vrect.translate(-data.crect.topLeft());
- QRect vrect = xrect & q->parentWidget()->rect();
- vrect.translate(-data.crect.topLeft()); //the part of me that's visible through parent, in my Qt coords
if (data.wrect.contains(vrect)) {
- xrect = data.wrect;
- xrect.translate(data.crect.topLeft());
+ wrectInParentCoordSys = data.wrect;
+ wrectInParentCoordSys.translate(data.crect.topLeft());
#ifndef QT_MAC_USE_COCOA
- HIRect bounds = CGRectMake(xrect.x(), xrect.y(),
- xrect.width(), xrect.height());
+ HIRect bounds = CGRectMake(wrectInParentCoordSys.x(), wrectInParentCoordSys.y(),
+ wrectInParentCoordSys.width(), wrectInParentCoordSys.height());
HIViewSetFrame(qt_mac_nativeview_for(q), &bounds);
#else
- NSRect bounds = NSMakeRect(xrect.x(), xrect.y(),
- xrect.width(), xrect.height());
- [qt_mac_nativeview_for(q) setFrame:bounds];
+ if (nsview) {
+ // INVARIANT: q is native. Set view frame:
+ NSRect bounds = NSMakeRect(wrectInParentCoordSys.x(), wrectInParentCoordSys.y(),
+ wrectInParentCoordSys.width(), wrectInParentCoordSys.height());
+ [nsview setFrame:bounds];
+ } else {
+ // INVARIANT: q is alien. Repaint wrect instead (includes old and new wrect):
+ QWidget *parent = q->parentWidget();
+ QPoint globalPosWRect = parent->mapToGlobal(data.wrect.topLeft());
+
+ QWidget *nativeParent = q->nativeParentWidget();
+ QRect dirtyWRect = QRect(nativeParent->mapFromGlobal(globalPosWRect), data.wrect.size());
+
+ nativeParent->update(dirtyWRect);
+ }
#endif
if (q->testAttribute(Qt::WA_OutsideWSRange)) {
q->setAttribute(Qt::WA_OutsideWSRange, false);
@@ -4216,7 +4274,8 @@ void QWidgetPrivate::setWSGeometry(bool dontShow, const QRect &oldRect)
#ifndef QT_MAC_USE_COCOA
HIViewSetVisible(qt_mac_nativeview_for(q), true);
#else
- [qt_mac_nativeview_for(q) setHidden:NO];
+ // If q is Alien, the following call does nothing:
+ [nsview setHidden:NO];
#endif
}
}
@@ -4226,8 +4285,8 @@ void QWidgetPrivate::setWSGeometry(bool dontShow, const QRect &oldRect)
#ifndef QT_MAC_USE_COCOA
const QRect validRange(-XCOORD_MAX,-XCOORD_MAX, 2*XCOORD_MAX, 2*XCOORD_MAX);
- if (!validRange.contains(xrect)) {
- // we are too big, and must clip
+ if (!validRange.contains(wrectInParentCoordSys)) {
+ // We're too big, and must clip:
QPoint screenOffset(0, 0); // offset of the part being on screen
const QWidget *parentWidget = q->parentWidget();
while (parentWidget && !parentWidget->isWindow()) {
@@ -4239,15 +4298,15 @@ void QWidgetPrivate::setWSGeometry(bool dontShow, const QRect &oldRect)
2*WRECT_MAX,
2*WRECT_MAX);
- xrect &=cropRect;
- wrect = xrect;
- wrect.translate(-data.crect.topLeft()); // translate wrect in my Qt coordinates
+ wrectInParentCoordSys &=cropRect;
+ wrect = wrectInParentCoordSys;
+ wrect.translate(-data.crect.topLeft());
}
#endif //QT_MAC_USE_COCOA
}
// unmap if we are outside the valid window system coord system
- bool outsideRange = !xrect.isValid();
+ bool outsideRange = !wrectInParentCoordSys.isValid();
bool mapWindow = false;
if (q->testAttribute(Qt::WA_OutsideWSRange) != outsideRange) {
q->setAttribute(Qt::WA_OutsideWSRange, outsideRange);
@@ -4255,7 +4314,8 @@ void QWidgetPrivate::setWSGeometry(bool dontShow, const QRect &oldRect)
#ifndef QT_MAC_USE_COCOA
HIViewSetVisible(qt_mac_nativeview_for(q), false);
#else
- [qt_mac_nativeview_for(q) setHidden:YES];
+ // If q is Alien, the following call does nothing:
+ [nsview setHidden:YES];
#endif
q->setAttribute(Qt::WA_Mapped, false);
} else if (!q->isHidden()) {
@@ -4266,10 +4326,10 @@ void QWidgetPrivate::setWSGeometry(bool dontShow, const QRect &oldRect)
if (outsideRange)
return;
+ // Store the new clipped rect:
bool jump = (data.wrect != wrect);
data.wrect = wrect;
-
// and now recursively for all children...
// ### can be optimized
for (int i = 0; i < children.size(); ++i) {
@@ -4281,17 +4341,56 @@ void QWidgetPrivate::setWSGeometry(bool dontShow, const QRect &oldRect)
}
}
- qt_mac_update_widget_position(q, oldRect, xrect);
-
- if (jump)
+#ifndef QT_MAC_USE_COCOA
+ // Move the actual HIView:
+ qt_mac_update_widget_position(q, oldRect, wrectInParentCoordSys);
+ if (jump)
q->update();
+#else
+ if (nsview) {
+ // INVARIANT: q is native. Move the actual NSView:
+ NSRect bounds = NSMakeRect(
+ wrectInParentCoordSys.x(), wrectInParentCoordSys.y(),
+ wrectInParentCoordSys.width(), wrectInParentCoordSys.height());
+ [nsview setFrame:bounds];
+ if (jump)
+ q->update();
+ } else if (QApplicationPrivate::graphicsSystem() == 0){
+ // INVARIANT: q is alien and we use native paint engine.
+ // Schedule updates where q is moved from and to:
+ const QWidget *parent = q->parentWidget();
+ const QPoint globalPosOldWRect = parent->mapToGlobal(oldRect.topLeft());
+ const QPoint globalPosNewWRect = parent->mapToGlobal(wrectInParentCoordSys.topLeft());
+
+ QWidget *nativeParent = q->nativeParentWidget();
+ const QRegion dirtyOldWRect = QRect(nativeParent->mapFromGlobal(globalPosOldWRect), oldRect.size());
+ const QRegion dirtyNewWRect = QRect(nativeParent->mapFromGlobal(globalPosNewWRect), wrectInParentCoordSys.size());
+
+ const bool sizeUnchanged = oldRect.size() == wrectInParentCoordSys.size();
+ const bool posUnchanged = oldRect.topLeft() == wrectInParentCoordSys.topLeft();
+
+ // Resolve/minimize the region that needs to update:
+ if (sizeUnchanged && q->testAttribute(Qt::WA_OpaquePaintEvent)) {
+ // INVARIANT: q is opaque, and is only moved (not resized). So in theory we only
+ // need to blit pixels, and skip a repaint. But we can only make this work if we
+ // had access to the backbuffer, so we need to update all:
+ nativeParent->update(dirtyOldWRect | dirtyNewWRect);
+ } else if (posUnchanged && q->testAttribute(Qt::WA_StaticContents)) {
+ // We only need to redraw exposed areas:
+ nativeParent->update(dirtyNewWRect - dirtyOldWRect);
+ } else {
+ nativeParent->update(dirtyOldWRect | dirtyNewWRect);
+ }
+ }
+#endif
if (mapWindow && !dontShow) {
q->setAttribute(Qt::WA_Mapped);
#ifndef QT_MAC_USE_COCOA
HIViewSetVisible(qt_mac_nativeview_for(q), true);
#else
- [qt_mac_nativeview_for(q) setHidden:NO];
+ // If q is Alien, the following call does nothing:
+ [nsview setHidden:NO];
#endif
}
}
@@ -4326,6 +4425,8 @@ void QWidgetPrivate::adjustWithinMaxAndMinSize(int &w, int &h)
void QWidgetPrivate::applyMaxAndMinSizeOnWindow()
{
Q_Q(QWidget);
+ QMacCocoaAutoReleasePool pool;
+
const float max_f(20000);
#ifndef QT_MAC_USE_COCOA
#define SF(x) ((x > max_f) ? max_f : x)
@@ -4353,7 +4454,6 @@ void QWidgetPrivate::setGeometry_sys(int x, int y, int w, int h, bool isMove)
QMacCocoaAutoReleasePool pool;
bool realWindow = isRealWindow();
- BOOL needDisplay = realWindow ? YES : NO;
if (realWindow && !q->testAttribute(Qt::WA_DontShowOnScreen)){
adjustWithinMaxAndMinSize(w, h);
@@ -4401,7 +4501,7 @@ void QWidgetPrivate::setGeometry_sys(int x, int y, int w, int h, bool isMove)
if (currTopLeft.x() == x && currTopLeft.y() == y
&& cocoaFrameRect.size.width != 0
&& cocoaFrameRect.size.height != 0) {
- [window setFrame:cocoaFrameRect display:needDisplay];
+ [window setFrame:cocoaFrameRect display:realWindow];
} else {
// The window is moved and resized (or resized to zero).
// Since Cocoa usually only sends us a resize callback after
@@ -4410,7 +4510,7 @@ void QWidgetPrivate::setGeometry_sys(int x, int y, int w, int h, bool isMove)
// would have the same origin as the setFrame call) we shift the
// window back and forth inbetween.
cocoaFrameRect.origin.y += 1;
- [window setFrame:cocoaFrameRect display:needDisplay];
+ [window setFrame:cocoaFrameRect display:realWindow];
cocoaFrameRect.origin.y -= 1;
[window setFrameOrigin:cocoaFrameRect.origin];
}
@@ -4418,6 +4518,8 @@ void QWidgetPrivate::setGeometry_sys(int x, int y, int w, int h, bool isMove)
} else {
setGeometry_sys_helper(x, y, w, h, isMove);
}
+
+ topLevelAt_cache = 0;
}
void QWidgetPrivate::setGeometry_sys_helper(int x, int y, int w, int h, bool isMove)
@@ -4468,17 +4570,11 @@ void QWidgetPrivate::setGeometry_sys_helper(int x, int y, int w, int h, bool isM
const QRect oldRect(oldp, olds);
if (!isResize && QApplicationPrivate::graphicsSystem())
moveRect(oldRect, x - oldp.x(), y - oldp.y());
+
setWSGeometry(false, oldRect);
- if (isResize && QApplicationPrivate::graphicsSystem()) {
- invalidateBuffer(q->rect());
- if (extra && !graphicsEffect && !extra->mask.isEmpty()) {
- QRegion oldRegion(extra->mask.translated(oldp));
- oldRegion &= oldRect;
- q->parentWidget()->d_func()->invalidateBuffer(oldRegion);
- } else {
- q->parentWidget()->d_func()->invalidateBuffer(effectiveRectFor(oldRect));
- }
- }
+
+ if (isResize && QApplicationPrivate::graphicsSystem())
+ invalidateBuffer_resizeHelper(oldp, olds);
}
if(isMove || isResize) {
@@ -4558,6 +4654,7 @@ void QWidgetPrivate::updateMaximizeButton_sys()
void QWidgetPrivate::scroll_sys(int dx, int dy)
{
if (QApplicationPrivate::graphicsSystem() && !paintOnScreen()) {
+ // INVARIANT: Alien paint engine
scrollChildren(dx, dy);
scrollRect(q_func()->rect(), dx, dy);
} else {
@@ -4565,37 +4662,81 @@ void QWidgetPrivate::scroll_sys(int dx, int dy)
}
}
-void QWidgetPrivate::scroll_sys(int dx, int dy, const QRect &r)
+void QWidgetPrivate::scroll_sys(int dx, int dy, const QRect &qscrollRect)
{
- Q_Q(QWidget);
+ if (QMacScrollOptimization::delayScroll(this, dx, dy, qscrollRect))
+ return;
+ Q_Q(QWidget);
if (QApplicationPrivate::graphicsSystem() && !paintOnScreen()) {
- scrollRect(r, dx, dy);
+ // INVARIANT: Alien paint engine
+ scrollRect(qscrollRect, dx, dy);
return;
}
- const bool valid_rect = r.isValid();
- if (!q->updatesEnabled() && (valid_rect || q->children().isEmpty()))
- return;
+ static int accelEnv = -1;
+ if (accelEnv == -1) {
+ accelEnv = qgetenv("QT_NO_FAST_SCROLL").toInt() == 0;
+ }
- qt_event_request_window_change(q);
+ // Scroll the whole widget if qscrollRect is not valid:
+ QRect validScrollRect = qscrollRect.isValid() ? qscrollRect : q->rect();
+ validScrollRect &= clipRect();
+
+ // If q is overlapped by other widgets, we cannot just blit pixels since
+ // this will move overlapping widgets as well. In case we just update:
+ const bool overlapped = isOverlapped(validScrollRect.translated(data.crect.topLeft()));
+ const bool accelerateScroll = accelEnv && isOpaque && !overlapped;
+ const bool isAlien = (q->internalWinId() == 0);
+ const QPoint scrollDelta(dx, dy);
+
+ // If qscrollRect is valid, we are _not_ supposed to scroll q's children (as documented).
+ // But we do scroll children (and the whole of q) if qscrollRect is invalid. This case is
+ // documented as undefined, but we exploit it to help factor our code into one function.
+ const bool scrollChildren = !qscrollRect.isValid();
+
+ if (!q->updatesEnabled()) {
+ // We are told not to update anything on q at this point. So unless
+ // we are supposed to scroll children, we bail out early:
+ if (!scrollChildren || q->children().isEmpty())
+ return;
+ }
+
+ if (!accelerateScroll) {
+ if (overlapped) {
+ QRegion region(validScrollRect);
+ subtractOpaqueSiblings(region);
+ update_sys(region);
+ }else {
+ update_sys(qscrollRect);
+ }
+ return;
+ }
#ifdef QT_MAC_USE_COCOA
QMacCocoaAutoReleasePool pool;
+#else
+ Q_UNUSED(isAlien);
+ // We're not sure what the following call is supposed to achive
+ // but until we see what it breaks, we don't bring it into the
+ // Cocoa port:
+ qt_event_request_window_change(q);
#endif
- if(!valid_rect) { // scroll children
- QPoint pd(dx, dy);
- QWidgetList moved;
- QObjectList chldrn = q->children();
- for(int i = 0; i < chldrn.size(); i++) { //first move all children
- QObject *obj = chldrn.at(i);
- if(obj->isWidgetType()) {
- QWidget *w = (QWidget*)obj;
- if(!w->isWindow()) {
- w->data->crect = QRect(w->pos() + pd, w->size());
- if (w->testAttribute(Qt::WA_WState_Created)) {
+ // First move all native children. Alien children will indirectly be
+ // moved when the parent is scrolled. All directly or indirectly moved
+ // children will receive a move event before the function call returns.
+ QWidgetList movedChildren;
+ if (scrollChildren) {
+ QObjectList children = q->children();
+
+ for (int i=0; i<children.size(); i++) {
+ QObject *obj = children.at(i);
+ if (QWidget *w = qobject_cast<QWidget*>(obj)) {
+ if (!w->isWindow()) {
+ w->data->crect = QRect(w->pos() + scrollDelta, w->size());
#ifndef QT_MAC_USE_COCOA
+ if (w->testAttribute(Qt::WA_WState_Created)) {
HIRect bounds = CGRectMake(w->data->crect.x(), w->data->crect.y(),
w->data->crect.width(), w->data->crect.height());
HIViewRef hiview = qt_mac_nativeview_for(w);
@@ -4606,83 +4747,118 @@ void QWidgetPrivate::scroll_sys(int dx, int dy, const QRect &r)
HIViewSetFrame(hiview, &bounds);
if (opaque)
HIViewSetDrawingEnabled(hiview, true);
+ }
#else
- [qt_mac_nativeview_for(w)
- setFrame:NSMakeRect(w->data->crect.x(), w->data->crect.y(),
- w->data->crect.width(), w->data->crect.height())];
-#endif
+ if (NSView *view = qt_mac_nativeview_for(w)) {
+ // INVARIANT: w is not alien
+ [view setFrame:NSMakeRect(
+ w->data->crect.x(), w->data->crect.y(),
+ w->data->crect.width(), w->data->crect.height())];
}
- moved.append(w);
+#endif
+ movedChildren.append(w);
}
}
}
- //now send move events (do not do this in the above loop, breaks QAquaFocusWidget)
- for(int i = 0; i < moved.size(); i++) {
- QWidget *w = moved.at(i);
- QMoveEvent e(w->pos(), w->pos() - pd);
- QApplication::sendEvent(w, &e);
- }
}
- if (!q->testAttribute(Qt::WA_WState_Created) || !q->isVisible())
- return;
+ if (q->testAttribute(Qt::WA_WState_Created) && q->isVisible()) {
+ // Scroll q itself according to the qscrollRect, and
+ // call update on any exposed areas so that they get redrawn:
- OSViewRef view = qt_mac_nativeview_for(q);
#ifndef QT_MAC_USE_COCOA
- HIRect scrollrect = CGRectMake(r.x(), r.y(), r.width(), r.height());
- OSStatus err = _HIViewScrollRectWithOptions(view, valid_rect ? &scrollrect : 0, dx, dy, kHIViewScrollRectAdjustInvalid);
- if (err) {
- // The only parameter that can go wrong, is the rect.
- qWarning("QWidget::scroll: Your rectangle was too big for the widget, clipping rect");
- scrollrect = CGRectMake(qMax(r.x(), 0), qMax(r.y(), 0),
- qMin(r.width(), q->width()), qMin(r.height(), q->height()));
- _HIViewScrollRectWithOptions(view, valid_rect ? &scrollrect : 0, dx, dy, kHIViewScrollRectAdjustInvalid);
- }
+ OSViewRef view = qt_mac_nativeview_for(q);
+ HIRect scrollrect = CGRectMake(qscrollRect.x(), qscrollRect.y(), qscrollRect.width(), qscrollRect.height());
+ OSStatus err = _HIViewScrollRectWithOptions(view, qscrollRect.isValid() ? &scrollrect : 0, dx, dy, kHIViewScrollRectAdjustInvalid);
+ if (err) {
+ // The only parameter that can go wrong, is the rect.
+ qWarning("QWidget::scroll: Your rectangle was too big for the widget, clipping rect");
+ scrollrect = CGRectMake(qMax(qscrollRect.x(), 0), qMax(qscrollRect.y(), 0),
+ qMin(qscrollRect.width(), q->width()), qMin(qscrollRect.height(), q->height()));
+ _HIViewScrollRectWithOptions(view, qscrollRect.isValid() ? &scrollrect : 0, dx, dy, kHIViewScrollRectAdjustInvalid);
+ }
#else
- NSRect scrollRect = valid_rect ? NSMakeRect(r.x(), r.y(), r.width(), r.height())
- : NSMakeRect(0, 0, q->width(), q->height());
+ QWidget *nativeWidget = isAlien ? q->nativeParentWidget() : q;
+ if (!nativeWidget)
+ return;
+ OSViewRef view = qt_mac_nativeview_for(nativeWidget);
+ if (!view)
+ return;
+
+ // Calculate the rectangles that needs to be redrawn
+ // after the scroll. This will be source rect minus destination rect:
+ QRect deltaXRect;
+ if (dx != 0) {
+ deltaXRect.setY(validScrollRect.y());
+ deltaXRect.setHeight(validScrollRect.height());
+ if (dx > 0) {
+ deltaXRect.setX(validScrollRect.x());
+ deltaXRect.setWidth(dx);
+ } else {
+ deltaXRect.setX(validScrollRect.x() + validScrollRect.width() + dx);
+ deltaXRect.setWidth(-dx);
+ }
+ }
- // calc the updateRect
- NSRect deltaXRect = { {0, 0}, {0, 0} };
- NSRect deltaYRect = { {0, 0}, {0, 0} };
- if (dy != 0) {
- deltaYRect.size.width = scrollRect.size.width;
- if (dy > 0) {
- deltaYRect.size.height = dy;
- } else {
- deltaYRect.size.height = -dy;
- deltaYRect.origin.y = scrollRect.size.height + dy;
+ QRect deltaYRect;
+ if (dy != 0) {
+ deltaYRect.setX(validScrollRect.x());
+ deltaYRect.setWidth(validScrollRect.width());
+ if (dy > 0) {
+ deltaYRect.setY(validScrollRect.y());
+ deltaYRect.setHeight(dy);
+ } else {
+ deltaYRect.setY(validScrollRect.y() + validScrollRect.height() + dy);
+ deltaYRect.setHeight(-dy);
+ }
}
- }
- if (dx != 0) {
- deltaXRect.size.height = scrollRect.size.height;
- if (dx > 0) {
- deltaXRect.size.width = dx;
- } else {
- deltaXRect.size.width = -dx;
- deltaXRect.origin.x = scrollRect.size.width + dx;
+
+ if (isAlien) {
+ // Adjust the scroll rect to the location as seen from the native parent:
+ QPoint scrollTopLeftInsideNative = nativeWidget->mapFromGlobal(q->mapToGlobal(validScrollRect.topLeft()));
+ validScrollRect.moveTo(scrollTopLeftInsideNative);
}
- }
- // ### Scroll the dirty regions as well, the following is not correct.
- QRegion displayRegion = r.isNull() ? dirtyOnWidget : (dirtyOnWidget & r);
- const QVector<QRect> &rects = dirtyOnWidget.rects();
- const QVector<QRect>::const_iterator end = rects.end();
- QVector<QRect>::const_iterator it = rects.begin();
- while (it != end) {
- const QRect rect = *it;
- const NSRect dirtyRect = NSMakeRect(rect.x() + dx, rect.y() + dy,
- rect.width(), rect.height());
- [view setNeedsDisplayInRect:dirtyRect];
- ++it;
- }
+ // Make the pixel copy rect within the validScrollRect bounds:
+ NSRect nsscrollRect = NSMakeRect(
+ validScrollRect.x() + (dx < 0 ? -dx : 0),
+ validScrollRect.y() + (dy < 0 ? -dy : 0),
+ validScrollRect.width() + (dx > 0 ? -dx : 0),
+ validScrollRect.height() + (dy > 0 ? -dy : 0));
+
+ NSSize deltaSize = NSMakeSize(dx, dy);
+ [view scrollRect:nsscrollRect by:deltaSize];
+
+ // Some areas inside the scroll rect might have been marked as dirty from before, which
+ // means that they are scheduled to be redrawn. But as we now scroll, those dirty rects
+ // should also move along to ensure that q receives repaints on the correct places.
+ // Since some of the dirty rects might lay outside, or only intersect with, the scroll
+ // rect, the old calls to setNeedsDisplay still makes sense.
+ // NB: Using [view translateRectsNeedingDisplayInRect:nsscrollRect by:deltaSize] have
+ // so far not been proven fruitful to solve this problem.
+ const QVector<QRect> &dirtyRectsToScroll = dirtyOnWidget.rects();
+ for (int i=0; i<dirtyRectsToScroll.size(); ++i) {
+ QRect qdirtyRect = dirtyRectsToScroll[i];
+ qdirtyRect.translate(dx, dy);
+ update_sys(qdirtyRect);
+ }
+
+ // Update newly exposed areas. This will generate new dirty areas on
+ // q, and therefore, we do it after updating the old dirty rects above:
+ if (dx != 0)
+ update_sys(deltaXRect);
+ if (dy != 0)
+ update_sys(deltaYRect);
- NSSize deltaSize = NSMakeSize(dx, dy);
- [view scrollRect:scrollRect by:deltaSize];
- [view setNeedsDisplayInRect:deltaXRect];
- [view setNeedsDisplayInRect:deltaYRect];
#endif // QT_MAC_USE_COCOA
+ }
+
+ for (int i=0; i<movedChildren.size(); i++) {
+ QWidget *w = movedChildren.at(i);
+ QMoveEvent e(w->pos(), w->pos() - scrollDelta);
+ QApplication::sendEvent(w, &e);
+ }
}
int QWidget::metric(PaintDeviceMetric m) const
@@ -4693,16 +4869,19 @@ int QWidget::metric(PaintDeviceMetric m) const
case PdmWidthMM:
return qRound(metric(PdmWidth) * 25.4 / qreal(metric(PdmDpiX)));
case PdmHeight:
- case PdmWidth: {
+ case PdmWidth:
#ifndef QT_MAC_USE_COCOA
- HIRect rect;
+ { HIRect rect;
HIViewGetFrame(qt_mac_nativeview_for(this), &rect);
-#else
- NSRect rect = [qt_mac_nativeview_for(this) frame];
-#endif
if(m == PdmWidth)
return (int)rect.size.width;
return (int)rect.size.height; }
+#else
+ if (m == PdmWidth)
+ return data->crect.width();
+ else
+ return data->crect.height();
+#endif
case PdmDepth:
return 32;
case PdmNumColors:
@@ -4817,19 +4996,35 @@ void QWidgetPrivate::registerDropSite(bool on)
#endif
}
-void QWidgetPrivate::registerTouchWindow()
+void QWidgetPrivate::registerTouchWindow(bool enable)
{
+ Q_UNUSED(enable);
+#ifdef QT_MAC_USE_COCOA
#if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_6
if (QSysInfo::MacintoshVersion < QSysInfo::MV_10_6)
return;
+
Q_Q(QWidget);
- if (!q->testAttribute(Qt::WA_WState_Created))
+ if (enable == touchEventsEnabled)
return;
-#ifndef QT_MAC_USE_COCOA
- // Needs implementation!
-#else
- NSView *view = qt_mac_nativeview_for(q);
- [view setAcceptsTouchEvents:YES];
+
+ QCocoaView *view = static_cast<QCocoaView *>(qt_mac_effectiveview_for(q));
+ if (!view)
+ return;
+
+ if (enable) {
+ ++view->alienTouchCount;
+ if (view->alienTouchCount == 1) {
+ touchEventsEnabled = true;
+ [view setAcceptsTouchEvents:YES];
+ }
+ } else {
+ --view->alienTouchCount;
+ if (view->alienTouchCount == 0) {
+ touchEventsEnabled = false;
+ [view setAcceptsTouchEvents:NO];
+ }
+ }
#endif
#endif
}
@@ -4837,13 +5032,17 @@ void QWidgetPrivate::registerTouchWindow()
void QWidgetPrivate::setMask_sys(const QRegion &region)
{
Q_UNUSED(region);
-#ifndef QT_MAC_USE_COCOA
Q_Q(QWidget);
+
+#ifndef QT_MAC_USE_COCOA
if (q->isWindow())
ReshapeCustomWindow(qt_mac_window_for(q));
else
HIViewReshapeStructure(qt_mac_nativeview_for(q));
#else
+ if (!q->internalWinId())
+ return;
+
if (extra->mask.isEmpty()) {
extra->maskBits = QImage();
finishCocoaMaskSetup();
@@ -4851,6 +5050,7 @@ void QWidgetPrivate::setMask_sys(const QRegion &region)
syncCocoaMask();
}
+ topLevelAt_cache = 0;
#endif
}
@@ -4928,7 +5128,7 @@ void QWidgetPrivate::finishCocoaMaskSetup()
[window setOpaque:(extra->imageMask == 0)];
[window invalidateShadow];
}
- qt_mac_set_needs_display(q, QRegion());
+ macSetNeedsDisplay(QRegion());
}
#endif
diff --git a/src/gui/kernel/qwidget_p.h b/src/gui/kernel/qwidget_p.h
index e37e06d..e5a2c35 100644
--- a/src/gui/kernel/qwidget_p.h
+++ b/src/gui/kernel/qwidget_p.h
@@ -113,6 +113,8 @@ class QWidgetItemV2;
class QStyle;
+class QUnifiedToolbarSurface;
+
class Q_AUTOTEST_EXPORT QWidgetBackingStoreTracker
{
@@ -233,6 +235,7 @@ struct QTLWExtra {
#elif defined(Q_WS_QPA)
QPlatformWindow *platformWindow;
QPlatformWindowFormat platformWindowFormat;
+ quint32 screenIndex; // index in qplatformscreenlist
#endif
};
@@ -321,6 +324,11 @@ struct QWExtra {
*/
ZeroFill,
+ /**
+ * Blit backing store, propagating alpha channel into the framebuffer.
+ */
+ BlitWriteAlpha,
+
Default = Blit
};
@@ -360,7 +368,8 @@ public:
DrawInvisible = 0x08,
DontSubtractOpaqueChildren = 0x10,
DontSetCompositionMode = 0x20,
- DontDrawOpaqueChildren = 0x40
+ DontDrawOpaqueChildren = 0x40,
+ DontDrawNativeChildren = 0x80
};
enum CloseMode {
@@ -566,6 +575,7 @@ public:
// sub-classes that their internals are about to be released.
virtual void aboutToDestroy() {}
+ QInputContext *assignedInputContext() const;
QInputContext *inputContext() const;
inline QWidget *effectiveFocusWidget() {
QWidget *w = q_func();
@@ -774,6 +784,8 @@ public:
void x11UpdateIsOpaque();
bool isBackgroundInherited() const;
void updateX11AcceptFocus();
+ QPoint mapToGlobal(const QPoint &pos) const;
+ QPoint mapFromGlobal(const QPoint &pos) const;
#elif defined(Q_WS_WIN) // <--------------------------------------------------------- WIN
uint noPaintOnScreen : 1; // see qwidget_win.cpp ::paintEngine()
#ifndef QT_NO_GESTURES
@@ -792,7 +804,6 @@ public:
#elif defined(Q_WS_MAC) // <--------------------------------------------------------- MAC
// This is new stuff
uint needWindowChange : 1;
- uint hasAlienChildren : 1;
// Each wiget keeps a list of all its child and grandchild OpenGL widgets.
// This list is used to update the gl context whenever a parent and a granparent
@@ -823,6 +834,7 @@ public:
void macUpdateIgnoreMouseEvents();
void macUpdateMetalAttribute();
void macUpdateIsOpaque();
+ void macSetNeedsDisplay(QRegion region);
void setEnabled_helper_sys(bool enable);
bool isRealWindow() const;
void adjustWithinMaxAndMinSize(int &w, int &h);
@@ -851,14 +863,15 @@ public:
bool originalDrawMethod;
// Do we need to change the methods?
bool changeMethods;
- bool hasOwnContext;
- CGContextRef cgContext;
- QRegion ut_rg;
- QPoint ut_pt;
+
+ // Unified toolbar variables
bool isInUnifiedToolbar;
- QWindowSurface *unifiedSurface;
+ QUnifiedToolbarSurface *unifiedSurface;
QPoint toolbar_offset;
-#endif
+ QWidget *toolbar_ancestor;
+ bool flushRequested;
+ bool touchEventsEnabled;
+#endif // QT_MAC_USE_COCOA
void determineWindowClass();
void transferChildren();
bool qt_mac_dnd_event(uint, DragRef);
@@ -870,7 +883,7 @@ public:
static OSStatus qt_window_event(EventHandlerCallRef er, EventRef event, void *);
static OSStatus qt_widget_event(EventHandlerCallRef er, EventRef event, void *);
static bool qt_widget_rgn(QWidget *, short, RgnHandle, bool);
- void registerTouchWindow();
+ void registerTouchWindow(bool enable = true);
#elif defined(Q_WS_QWS) // <--------------------------------------------------------- QWS
void setMaxWindowState_helper();
void setFullScreenSize_helper();
@@ -885,17 +898,16 @@ public:
void updateCursor() const;
#endif
QScreen* getScreen() const;
-#elif defined(Q_WS_QPA)
+#elif defined(Q_WS_QPA) // <--------------------------------------------------------- QPA
void setMaxWindowState_helper();
void setFullScreenSize_helper();
-
- int screenNumber; // screen the widget should be displayed on
#ifndef QT_NO_CURSOR
void updateCursor() const;
#endif
#elif defined(Q_OS_SYMBIAN) // <--------------------------------------------------------- SYMBIAN
static QWidget *mouseGrabber;
static QWidget *keyboardGrabber;
+ int symbianScreenNumber; // only valid for desktop widget and top-levels
void s60UpdateIsOpaque();
void reparentChildren();
void registerTouchWindow();
diff --git a/src/gui/kernel/qwidget_qpa.cpp b/src/gui/kernel/qwidget_qpa.cpp
index 617d984..001810e 100644
--- a/src/gui/kernel/qwidget_qpa.cpp
+++ b/src/gui/kernel/qwidget_qpa.cpp
@@ -53,7 +53,6 @@
#include <QtGui/QPlatformCursor>
QT_BEGIN_NAMESPACE
-static QPlatformScreen *qt_screenForWidget(const QWidget *w);
void q_createNativeChildrenAndSetParent(QPlatformWindow *parentWindow, const QWidget *parentWidget)
{
@@ -122,7 +121,7 @@ void QWidgetPrivate::create_sys(WId window, bool initializeWindow, bool destroyO
}
}
- QApplicationPrivate::platformIntegration()->moveToScreen(q, screenNumber);
+ QApplicationPrivate::platformIntegration()->moveToScreen(q, topData()->screenIndex);
// qDebug() << "create_sys" << q << q->internalWinId();
}
@@ -163,7 +162,6 @@ void QWidgetPrivate::setParent_sys(QWidget *newparent, Qt::WindowFlags f)
{
Q_Q(QWidget);
- // QWidget *oldParent = q->parentWidget();
Qt::WindowFlags oldFlags = data.window_flags;
int targetScreen = -1;
@@ -173,7 +171,7 @@ void QWidgetPrivate::setParent_sys(QWidget *newparent, Qt::WindowFlags f)
// programmer specified desktop widget
// get the desktop's screen number
- targetScreen = newparent->d_func()->screenNumber;
+ targetScreen = newparent->window()->d_func()->topData()->screenIndex;
newparent = 0;
}
@@ -192,7 +190,7 @@ void QWidgetPrivate::setParent_sys(QWidget *newparent, Qt::WindowFlags f)
f |= Qt::Window;
if (targetScreen == -1) {
if (parent)
- targetScreen = qobject_cast<QWidget *>(parent)->d_func()->screenNumber;
+ targetScreen = q->parentWidget()->window()->d_func()->topData()->screenIndex;
}
}
@@ -215,20 +213,14 @@ void QWidgetPrivate::setParent_sys(QWidget *newparent, Qt::WindowFlags f)
data.window_flags = window->setWindowFlags(data.window_flags);
}
- // Reparenting child to toplevel
- if ((f&Qt::Window) && !(oldFlags&Qt::Window)) {
- //qDebug() << "setParent_sys() change to toplevel";
- q->create(); //### too early: this ought to happen at show() time
- }
-
-
if (q->isWindow() || (!newparent || newparent->isVisible()) || explicitlyHidden)
q->setAttribute(Qt::WA_WState_Hidden);
q->setAttribute(Qt::WA_WState_ExplicitShowHide, explicitlyHidden);
// move the window to the selected screen
if (!newparent && targetScreen != -1) {
- screenNumber = targetScreen;
+ if (maybeTopData())
+ maybeTopData()->screenIndex = targetScreen;
// only if it is already created
if (q->testAttribute(Qt::WA_WState_Created)) {
QPlatformIntegration *platform = QApplicationPrivate::platformIntegration();
@@ -379,9 +371,8 @@ QWidget *QWidget::keyboardGrabber()
void QWidget::activateWindow()
{
- // XXX
-// qDebug() << "QWidget::activateWindow" << this;
- QApplication::setActiveWindow(this); //#####
+ if (platformWindow())
+ platformWindow()->requestActivateWindow();
}
void QWidgetPrivate::show_sys()
@@ -397,7 +388,11 @@ void QWidgetPrivate::show_sys()
QPlatformWindow *window = q->platformWindow();
if (window) {
- const QRect geomRect = q->geometry();
+ QRect geomRect = q->geometry();
+ if (!q->isWindow()) {
+ QPoint topLeftOfWindow = q->mapTo(q->nativeParentWidget(),QPoint());
+ geomRect.moveTopLeft(topLeftOfWindow);
+ }
const QRect windowRect = window->geometry();
if (windowRect != geomRect) {
window->setGeometry(geomRect);
@@ -409,9 +404,6 @@ void QWidgetPrivate::show_sys()
}
if (window)
window->setVisible(true);
-
- if (q->isWindow() && q->windowType() != Qt::Popup && q->windowType() != Qt::ToolTip && !(q->windowFlags() & Qt::X11BypassWindowManagerHint))
- q->activateWindow(); //### QWindowSystemInterface should have callback function for when WS actually activates window.
}
}
@@ -595,7 +587,7 @@ void QWidgetPrivate::setGeometry_sys(int x, int y, int w, int h, bool isMove)
if (q->isVisible()) {
if (q->platformWindow()) {
if (q->isWindow()) {
- q->platformWindow()->setGeometry(q->frameGeometry());
+ q->platformWindow()->setGeometry(q->geometry());
} else {
QPoint posInNativeParent = q->mapTo(q->nativeParentWidget(),QPoint());
q->platformWindow()->setGeometry(QRect(posInNativeParent,r.size()));
@@ -647,37 +639,11 @@ void QWidgetPrivate::scroll_sys(int dx, int dy, const QRect &r)
scrollRect(r, dx, dy);
}
-static QPlatformScreen *qt_screenForWidget(const QWidget *w)
-{
- if (!w)
- return 0;
- QRect frame = w->frameGeometry();
- if (!w->isWindow())
- frame.moveTopLeft(w->mapToGlobal(QPoint(0, 0)));
- const QPoint p = (frame.topLeft() + frame.bottomRight()) / 2;
-
- QPlatformIntegration *pi = QApplicationPrivate::platformIntegration();
- QList<QPlatformScreen *> screens = pi->screens();
-
- for (int i = 0; i < screens.size(); ++i) {
- if (screens[i]->geometry().contains(p))
- return screens[i];
- }
-
- // Assume screen zero if we have it.
- if (!screens.isEmpty())
- return screens[0];
- else
- qWarning("qt_screenForWidget: no screens");
-
- return 0;
-}
-
int QWidget::metric(PaintDeviceMetric m) const
{
Q_D(const QWidget);
- QPlatformScreen *screen = qt_screenForWidget(this);
+ QPlatformScreen *screen = QPlatformScreen::platformScreenForWidget(this);
if (!screen) {
if (m == PdmDpiX || m == PdmDpiY)
return 72;
@@ -798,9 +764,9 @@ void QWidgetPrivate::deleteTLSysExtra()
context->deleteQGLContext();
}
}
+ setWinId(0);
delete extra->topextra->platformWindow;
extra->topextra->platformWindow = 0;
- extra->topextra->backingStore.destroy();
}
}
diff --git a/src/gui/kernel/qwidget_s60.cpp b/src/gui/kernel/qwidget_s60.cpp
index c544215..b031936 100644
--- a/src/gui/kernel/qwidget_s60.cpp
+++ b/src/gui/kernel/qwidget_s60.cpp
@@ -63,6 +63,19 @@
// CCoeControl objects until after the CONE event handler has finished running.
Q_DECLARE_METATYPE(WId)
+// Workaround for the fact that S60 SDKs 3.x do not contain the akntoolbar.h
+// header, even though the documentation says that it should be there, and indeed
+// it is present in the library.
+class CAknToolbar : public CAknControl,
+ public MCoeControlObserver,
+ public MCoeControlBackground,
+ public MEikCommandObserver,
+ public MAknFadedComponent
+{
+public:
+ IMPORT_C void SetToolbarVisibility(const TBool visible);
+};
+
QT_BEGIN_NAMESPACE
extern bool qt_nograb();
@@ -71,6 +84,8 @@ QWidget *QWidgetPrivate::mouseGrabber = 0;
QWidget *QWidgetPrivate::keyboardGrabber = 0;
CEikButtonGroupContainer *QS60Data::cba = 0;
+int qt_symbian_create_desktop_on_screen = -1;
+
static bool isEqual(const QList<QAction*>& a, const QList<QAction*>& b)
{
if ( a.count() != b.count())
@@ -336,12 +351,18 @@ void QWidgetPrivate::create_sys(WId window, bool /* initializeWindow */, bool de
int sh = clientRect.Height();
if (desktop) {
- TSize screenSize = S60->screenDevice()->SizeInPixels();
+ symbianScreenNumber = qMax(qt_symbian_create_desktop_on_screen, 0);
+ TSize screenSize = S60->screenDevice(symbianScreenNumber)->SizeInPixels();
data.crect.setRect(0, 0, screenSize.iWidth, screenSize.iHeight);
q->setAttribute(Qt::WA_DontShowOnScreen);
} else if (topLevel && !q->testAttribute(Qt::WA_Resized)){
int width = sw;
int height = sh;
+ if (symbianScreenNumber > 0) {
+ TSize screenSize = S60->screenDevice(symbianScreenNumber)->SizeInPixels();
+ width = screenSize.iWidth;
+ height = screenSize.iHeight;
+ }
if (extra) {
width = qMax(qMin(width, extra->maxw), extra->minw);
height = qMax(qMin(height, extra->maxh), extra->minh);
@@ -488,6 +509,7 @@ void QWidgetPrivate::show_sys()
QSymbianControl *id = static_cast<QSymbianControl *>(q->internalWinId());
const bool isFullscreen = q->windowState() & Qt::WindowFullScreen;
+ const TBool cbaRequested = q->windowFlags() & Qt::WindowSoftkeysVisibleHint;
#ifdef Q_WS_S60
// Lazily initialize the S60 screen furniture when the first window is shown.
@@ -507,11 +529,25 @@ void QWidgetPrivate::show_sys()
CEikButtonGroupContainer *cba = CEikButtonGroupContainer::NewL(CEikButtonGroupContainer::ECba,
CEikButtonGroupContainer::EHorizontal,ui,R_AVKON_SOFTKEYS_EMPTY_WITH_IDS);
+ if (isFullscreen && !cbaRequested)
+ cba->MakeVisible(false);
CEikButtonGroupContainer *oldCba = factory->SwapButtonGroup(cba);
Q_ASSERT(!oldCba);
S60->setButtonGroupContainer(cba);
+ // If the creation of the first widget is delayed, for example by doing it
+ // inside the event loop, S60 somehow "forgets" to set the visibility of the
+ // toolbar (the three middle softkeys) when you flip the phone over, so we
+ // need to do it ourselves to avoid a "hole" in the application, even though
+ // Qt itself does not use the toolbar directly..
+ CAknAppUi *appui = dynamic_cast<CAknAppUi *>(CEikonEnv::Static()->AppUi());
+ if (appui) {
+ CAknToolbar *toolbar = appui->PopupToolbar();
+ if (toolbar && !toolbar->IsVisible())
+ toolbar->SetToolbarVisibility(ETrue);
+ }
+
CEikMenuBar *menuBar = new(ELeave) CEikMenuBar;
menuBar->ConstructL(ui, 0, R_AVKON_MENUPANE_EMPTY);
menuBar->SetMenuType(CEikMenuBar::EMenuOptions);
@@ -616,7 +652,7 @@ void QWidgetPrivate::raise_sys()
// If toplevel widget, raise app to foreground
if (q->isWindow())
- S60->wsSession().SetWindowGroupOrdinalPosition(S60->windowGroup().Identifier(), 0);
+ S60->wsSession().SetWindowGroupOrdinalPosition(S60->windowGroup(q).Identifier(), 0);
}
}
@@ -628,7 +664,7 @@ void QWidgetPrivate::lower_sys()
if (q->internalWinId()) {
// If toplevel widget, lower app to background
if (q->isWindow())
- S60->wsSession().SetWindowGroupOrdinalPosition(S60->windowGroup().Identifier(), -1);
+ S60->wsSession().SetWindowGroupOrdinalPosition(S60->windowGroup(q).Identifier(), -1);
else
q->internalWinId()->DrawableWindow()->SetOrdinalPosition(-1);
}
@@ -698,6 +734,11 @@ void QWidgetPrivate::setParent_sys(QWidget *parent, Qt::WindowFlags f)
{
Q_Q(QWidget);
+ if (parent && parent->windowType() == Qt::Desktop) {
+ symbianScreenNumber = qt_widget_private(parent)->symbianScreenNumber;
+ parent = 0;
+ }
+
bool wasCreated = q->testAttribute(Qt::WA_WState_Created);
if (q->isVisible() && q->parentWidget() && parent != q->parentWidget())
@@ -768,28 +809,43 @@ void QWidgetPrivate::s60UpdateIsOpaque()
{
Q_Q(QWidget);
- if (!q->testAttribute(Qt::WA_WState_Created) || !q->testAttribute(Qt::WA_TranslucentBackground))
+ if (!q->testAttribute(Qt::WA_WState_Created))
+ return;
+
+ const bool writeAlpha = extraData()->nativePaintMode == QWExtra::BlitWriteAlpha;
+ if (!q->testAttribute(Qt::WA_TranslucentBackground) && !writeAlpha)
return;
+ const bool requireAlphaChannel = !isOpaque || writeAlpha;
createTLExtra();
RWindow *const window = static_cast<RWindow *>(q->effectiveWinId()->DrawableWindow());
#ifdef Q_SYMBIAN_SEMITRANSPARENT_BG_SURFACE
- window->SetSurfaceTransparency(!isOpaque);
- extra->topextra->nativeWindowTransparencyEnabled = !isOpaque;
-#else
- if (!isOpaque) {
+ if (QApplicationPrivate::instance()->useTranslucentEGLSurfaces) {
+ window->SetSurfaceTransparency(!isOpaque);
+ extra->topextra->nativeWindowTransparencyEnabled = !isOpaque;
+ return;
+ }
+#endif
+ if (requireAlphaChannel) {
const TDisplayMode displayMode = static_cast<TDisplayMode>(window->SetRequiredDisplayMode(EColor16MA));
if (window->SetTransparencyAlphaChannel() == KErrNone) {
window->SetBackgroundColor(TRgb(255, 255, 255, 0));
extra->topextra->nativeWindowTransparencyEnabled = 1;
+ if (extra->topextra->backingStore.data() && (
+ QApplicationPrivate::graphics_system_name == QLatin1String("openvg")
+ || QApplicationPrivate::graphics_system_name == QLatin1String("opengl"))) {
+ // Semi-transparent EGL surfaces aren't supported. We need to
+ // recreate backing store to get translucent surface (raster surface).
+ extra->topextra->backingStore.create(q);
+ extra->topextra->backingStore.registerWidget(q);
+ }
}
} else if (extra->topextra->nativeWindowTransparencyEnabled) {
window->SetTransparentRegion(TRegionFix<1>());
extra->topextra->nativeWindowTransparencyEnabled = 0;
}
-#endif
}
void QWidgetPrivate::setWindowIcon_sys(bool forceReset)
@@ -1005,7 +1061,7 @@ int QWidget::metric(PaintDeviceMetric m) const
} else if (m == PdmHeight) {
val = data->crect.height();
} else {
- CWsScreenDevice *scr = S60->screenDevice();
+ CWsScreenDevice *scr = S60->screenDevice(this);
switch(m) {
case PdmDpiX:
case PdmPhysicalDpiX:
@@ -1152,14 +1208,17 @@ void QWidget::setWindowState(Qt::WindowStates newstate)
}
#ifdef Q_WS_S60
- // Hide window decoration when switching to fullsccreen / minimized otherwise show decoration.
- // The window decoration visibility has to be changed before doing actual window state
- // change since in that order the availableGeometry will return directly the right size and
- // we will avoid unnecessarty redraws
- const bool visible = !(newstate & (Qt::WindowFullScreen | Qt::WindowMinimized));
- const bool statusPaneVisibility = visible;
- const bool buttonGroupVisibility = (visible || (isFullscreen && cbaRequested));
- S60->setStatusPaneAndButtonGroupVisibility(statusPaneVisibility, buttonGroupVisibility);
+ bool decorationsVisible(false);
+ if (!parentWidget()) { // Only top level native windows have control over cba/status pane
+ // Hide window decoration when switching to fullscreen / minimized otherwise show decoration.
+ // The window decoration visibility has to be changed before doing actual window state
+ // change since in that order the availableGeometry will return directly the right size and
+ // we will avoid unnecessary redraws
+ decorationsVisible = !(newstate & (Qt::WindowFullScreen | Qt::WindowMinimized));
+ const bool statusPaneVisibility = decorationsVisible;
+ const bool buttonGroupVisibility = (decorationsVisible || (isFullscreen && cbaRequested));
+ S60->setStatusPaneAndButtonGroupVisibility(statusPaneVisibility, buttonGroupVisibility);
+ }
#endif // Q_WS_S60
// Ensure the initial size is valid, since we store it as normalGeometry below.
@@ -1172,7 +1231,16 @@ void QWidget::setWindowState(Qt::WindowStates newstate)
const bool cbaVisibilityHint = windowFlags() & Qt::WindowSoftkeysVisibleHint;
if (newstate & Qt::WindowFullScreen && !cbaVisibilityHint) {
setAttribute(Qt::WA_OutsideWSRange, false);
- window->SetExtentToWholeScreen();
+ if (d->symbianScreenNumber > 0) {
+ int w = S60->screenWidthInPixelsForScreen[d->symbianScreenNumber];
+ int h = S60->screenHeightInPixelsForScreen[d->symbianScreenNumber];
+ if (w <= 0 || h <= 0)
+ window->SetExtentToWholeScreen();
+ else
+ window->SetExtent(TPoint(0, 0), TSize(w, h));
+ } else {
+ window->SetExtentToWholeScreen();
+ }
} else if (newstate & Qt::WindowMaximized || ((newstate & Qt::WindowFullScreen) && cbaVisibilityHint)) {
setAttribute(Qt::WA_OutsideWSRange, false);
TRect maxExtent = qt_QRect2TRect(qApp->desktop()->availableGeometry(this));
@@ -1183,7 +1251,7 @@ void QWidget::setWindowState(Qt::WindowStates newstate)
// accurate because it did not consider the status pane. This means that when returning
// normal mode after showing the status pane, the geometry would overlap so we should
// move it if it never had an explicit position.
- if (!wasMoved && S60->statusPane() && visible) {
+ if (!wasMoved && S60->statusPane() && decorationsVisible) {
TPoint tl = static_cast<CEikAppUi*>(S60->appUi())->ClientRect().iTl;
normalGeometry.setTopLeft(QPoint(tl.iX, tl.iY));
}
diff --git a/src/gui/kernel/qwidget_x11.cpp b/src/gui/kernel/qwidget_x11.cpp
index cf23981..c6753fc 100644
--- a/src/gui/kernel/qwidget_x11.cpp
+++ b/src/gui/kernel/qwidget_x11.cpp
@@ -346,7 +346,7 @@ Q_GUI_EXPORT void qt_x11_enforce_cursor(QWidget * w)
qt_x11_enforce_cursor(w, false);
}
-Q_GUI_EXPORT void qt_x11_wait_for_window_manager(QWidget* w)
+void qt_x11_wait_for_window_manager(QWidget *w, bool sendPostedEvents)
{
if (!w || (!w->isWindow() && !w->internalWinId()))
return;
@@ -361,7 +361,8 @@ Q_GUI_EXPORT void qt_x11_wait_for_window_manager(QWidget* w)
WId winid = w->internalWinId();
// first deliver events that are already in the local queue
- QApplication::sendPostedEvents();
+ if (sendPostedEvents)
+ QApplication::sendPostedEvents();
// the normal sequence is:
// ... ConfigureNotify ... ReparentNotify ... MapNotify ... Expose
@@ -396,6 +397,11 @@ Q_GUI_EXPORT void qt_x11_wait_for_window_manager(QWidget* w)
} while(1);
}
+Q_GUI_EXPORT void qt_x11_wait_for_window_manager(QWidget *w)
+{
+ qt_x11_wait_for_window_manager(w, true);
+}
+
void qt_change_net_wm_state(const QWidget* w, bool set, Atom one, Atom two = 0)
{
if (!w->isVisible()) // not managed by the window manager
@@ -444,6 +450,7 @@ static QVector<Atom> getNetWmState(QWidget *w)
&& actualType == XA_ATOM && actualFormat == 32) {
returnValue.resize(bytesLeft / 4);
XFree((char*) propertyData);
+ propertyData = 0;
// fetch all data
if (XGetWindowProperty(X11->display, w->internalWinId(), ATOM(_NET_WM_STATE), 0,
@@ -458,7 +465,8 @@ static QVector<Atom> getNetWmState(QWidget *w)
if (!returnValue.isEmpty()) {
memcpy(returnValue.data(), propertyData, returnValue.size() * sizeof(Atom));
}
- XFree((char*) propertyData);
+ if (propertyData)
+ XFree((char*) propertyData);
}
return returnValue;
@@ -1289,39 +1297,49 @@ void QWidgetPrivate::setParent_sys(QWidget *parent, Qt::WindowFlags f)
#endif
}
-
-QPoint QWidget::mapToGlobal(const QPoint &pos) const
+QPoint QWidgetPrivate::mapToGlobal(const QPoint &pos) const
{
- Q_D(const QWidget);
- if (!testAttribute(Qt::WA_WState_Created) || !internalWinId()) {
- QPoint p = pos + data->crect.topLeft();
+ Q_Q(const QWidget);
+ if (!q->testAttribute(Qt::WA_WState_Created) || !q->internalWinId()) {
+ QPoint p = pos + q->data->crect.topLeft();
//cannot trust that !isWindow() implies parentWidget() before create
- return (isWindow() || !parentWidget()) ? p : parentWidget()->mapToGlobal(p);
+ return (q->isWindow() || !q->parentWidget()) ? p : q->parentWidget()->d_func()->mapToGlobal(p);
}
- int x, y;
+ int x, y;
Window child;
- QPoint p = d->mapToWS(pos);
- XTranslateCoordinates(X11->display, internalWinId(),
- QApplication::desktop()->screen(d->xinfo.screen())->internalWinId(),
+ QPoint p = mapToWS(pos);
+ XTranslateCoordinates(X11->display, q->internalWinId(),
+ QApplication::desktop()->screen(xinfo.screen())->internalWinId(),
p.x(), p.y(), &x, &y, &child);
return QPoint(x, y);
}
-
-QPoint QWidget::mapFromGlobal(const QPoint &pos) const
+QPoint QWidgetPrivate::mapFromGlobal(const QPoint &pos) const
{
- Q_D(const QWidget);
- if (!testAttribute(Qt::WA_WState_Created) || !internalWinId()) {
+ Q_Q(const QWidget);
+ if (!q->testAttribute(Qt::WA_WState_Created) || !q->internalWinId()) {
//cannot trust that !isWindow() implies parentWidget() before create
- QPoint p = (isWindow() || !parentWidget()) ? pos : parentWidget()->mapFromGlobal(pos);
- return p - data->crect.topLeft();
+ QPoint p = (q->isWindow() || !q->parentWidget()) ? pos : q->parentWidget()->d_func()->mapFromGlobal(pos);
+ return p - q->data->crect.topLeft();
}
- int x, y;
+ int x, y;
Window child;
XTranslateCoordinates(X11->display,
- QApplication::desktop()->screen(d->xinfo.screen())->internalWinId(),
- internalWinId(), pos.x(), pos.y(), &x, &y, &child);
- return d->mapFromWS(QPoint(x, y));
+ QApplication::desktop()->screen(xinfo.screen())->internalWinId(),
+ q->internalWinId(), pos.x(), pos.y(), &x, &y, &child);
+ return mapFromWS(QPoint(x, y));
+}
+
+QPoint QWidget::mapToGlobal(const QPoint &pos) const
+{
+ Q_D(const QWidget);
+ return d->mapToGlobal(pos);
+}
+
+QPoint QWidget::mapFromGlobal(const QPoint &pos) const
+{
+ Q_D(const QWidget);
+ return d->mapFromGlobal(pos);
}
void QWidgetPrivate::updateSystemBackground()
@@ -1484,7 +1502,7 @@ void QWidgetPrivate::setWindowIcon_sys(bool forceReset)
|| !QX11Info::appDefaultColormap(xinfo.screen())) {
// unknown DE or non-default visual/colormap, use 1bpp bitmap
if (!forceReset || !topData->iconPixmap)
- topData->iconPixmap = new QBitmap(qt_toX11Pixmap(icon.pixmap(QSize(64,64))));
+ topData->iconPixmap = new QPixmap(qt_toX11Pixmap(QBitmap(icon.pixmap(QSize(64,64)))));
pixmap_handle = topData->iconPixmap->handle();
} else {
// default depth, use a normal pixmap (even though this
diff --git a/src/gui/kernel/qwindowsysteminterface_qpa.cpp b/src/gui/kernel/qwindowsysteminterface_qpa.cpp
index 48ab5be..740bb82 100644
--- a/src/gui/kernel/qwindowsysteminterface_qpa.cpp
+++ b/src/gui/kernel/qwindowsysteminterface_qpa.cpp
@@ -82,6 +82,12 @@ void QWindowSystemInterface::handleLeaveEvent(QWidget *tlw)
QWindowSystemInterfacePrivate::queueWindowSystemEvent(e);
}
+void QWindowSystemInterface::handleWindowActivated(QWidget *tlw)
+{
+ QWindowSystemInterfacePrivate::ActivatedWindowEvent *e = new QWindowSystemInterfacePrivate::ActivatedWindowEvent(tlw);
+ QWindowSystemInterfacePrivate::queueWindowSystemEvent(e);
+}
+
void QWindowSystemInterface::handleGeometryChange(QWidget *tlw, const QRect &newRect)
{
if (tlw) {
@@ -144,6 +150,36 @@ void QWindowSystemInterface::handleKeyEvent(QWidget *tlw, ulong timestamp, QEven
QWindowSystemInterfacePrivate::queueWindowSystemEvent(e);
}
+void QWindowSystemInterface::handleExtendedKeyEvent(QWidget *w, QEvent::Type type, int key, Qt::KeyboardModifiers modifiers,
+ quint32 nativeScanCode, quint32 nativeVirtualKey,
+ quint32 nativeModifiers,
+ const QString& text, bool autorep,
+ ushort count)
+{
+ unsigned long time = QWindowSystemInterfacePrivate::eventTime.elapsed();
+ handleExtendedKeyEvent(w, time, type, key, modifiers, nativeScanCode, nativeVirtualKey, nativeModifiers,
+ text, autorep, count);
+}
+
+void QWindowSystemInterface::handleExtendedKeyEvent(QWidget *tlw, ulong timestamp, QEvent::Type type, int key,
+ Qt::KeyboardModifiers modifiers,
+ quint32 nativeScanCode, quint32 nativeVirtualKey,
+ quint32 nativeModifiers,
+ const QString& text, bool autorep,
+ ushort count)
+{
+ if (tlw) {
+ QWidgetData *data = qt_qwidget_data(tlw);
+ if (data->in_destructor)
+ tlw = 0;
+ }
+
+ QWindowSystemInterfacePrivate::KeyEvent * e =
+ new QWindowSystemInterfacePrivate::KeyEvent(tlw, timestamp, type, key, modifiers,
+ nativeScanCode, nativeVirtualKey, nativeModifiers, text, autorep, count);
+ QWindowSystemInterfacePrivate::queueWindowSystemEvent(e);
+}
+
void QWindowSystemInterface::handleWheelEvent(QWidget *w, const QPoint & local, const QPoint & global, int d, Qt::Orientation o) {
unsigned long time = QWindowSystemInterfacePrivate::eventTime.elapsed();
handleWheelEvent(w, time, local, global, d, o);
diff --git a/src/gui/kernel/qwindowsysteminterface_qpa.h b/src/gui/kernel/qwindowsysteminterface_qpa.h
index 39ff75a..a882fc1 100644
--- a/src/gui/kernel/qwindowsysteminterface_qpa.h
+++ b/src/gui/kernel/qwindowsysteminterface_qpa.h
@@ -64,6 +64,17 @@ public:
static void handleKeyEvent(QWidget *w, QEvent::Type t, int k, Qt::KeyboardModifiers mods, const QString & text = QString(), bool autorep = false, ushort count = 1);
static void handleKeyEvent(QWidget *w, ulong timestamp, QEvent::Type t, int k, Qt::KeyboardModifiers mods, const QString & text = QString(), bool autorep = false, ushort count = 1);
+ static void handleExtendedKeyEvent(QWidget *w, QEvent::Type type, int key, Qt::KeyboardModifiers modifiers,
+ quint32 nativeScanCode, quint32 nativeVirtualKey,
+ quint32 nativeModifiers,
+ const QString& text = QString(), bool autorep = false,
+ ushort count = 1);
+ static void handleExtendedKeyEvent(QWidget *w, ulong timestamp, QEvent::Type type, int key, Qt::KeyboardModifiers modifiers,
+ quint32 nativeScanCode, quint32 nativeVirtualKey,
+ quint32 nativeModifiers,
+ const QString& text = QString(), bool autorep = false,
+ ushort count = 1);
+
static void handleWheelEvent(QWidget *w, const QPoint & local, const QPoint & global, int d, Qt::Orientation o);
static void handleWheelEvent(QWidget *w, ulong timestamp, const QPoint & local, const QPoint & global, int d, Qt::Orientation o);
@@ -83,6 +94,7 @@ public:
static void handleCloseEvent(QWidget *w);
static void handleEnterEvent(QWidget *w);
static void handleLeaveEvent(QWidget *w);
+ static void handleWindowActivated(QWidget *w);
// Changes to the screen
static void handleScreenGeometryChange(int screenIndex);
diff --git a/src/gui/kernel/qwindowsysteminterface_qpa_p.h b/src/gui/kernel/qwindowsysteminterface_qpa_p.h
index 78e1f33..6be86ad 100644
--- a/src/gui/kernel/qwindowsysteminterface_qpa_p.h
+++ b/src/gui/kernel/qwindowsysteminterface_qpa_p.h
@@ -54,6 +54,7 @@ public:
GeometryChange,
Enter,
Leave,
+ ActivatedWindow,
Mouse,
Wheel,
Key,
@@ -102,6 +103,14 @@ public:
QWeakPointer<QWidget> leave;
};
+ class ActivatedWindowEvent : public WindowSystemEvent {
+ public:
+ ActivatedWindowEvent(QWidget *activatedWindow)
+ : WindowSystemEvent(ActivatedWindow), activated(activatedWindow)
+ { }
+ QWeakPointer<QWidget> activated;
+ };
+
class UserEvent : public WindowSystemEvent {
public:
UserEvent(QWidget * w, ulong time, EventType t)
@@ -133,13 +142,23 @@ public:
public:
KeyEvent(QWidget *w, ulong time, QEvent::Type t, int k, Qt::KeyboardModifiers mods, const QString & text = QString(), bool autorep = false, ushort count = 1)
:UserEvent(w, time, Key), key(k), unicode(text), repeat(autorep),
- repeatCount(count), modifiers(mods), keyType(t) { }
+ repeatCount(count), modifiers(mods), keyType(t),
+ nativeScanCode(0), nativeVirtualKey(0), nativeModifiers(0) { }
+ KeyEvent(QWidget *w, ulong time, QEvent::Type t, int k, Qt::KeyboardModifiers mods,
+ quint32 nativeSC, quint32 nativeVK, quint32 nativeMods,
+ const QString & text = QString(), bool autorep = false, ushort count = 1)
+ :UserEvent(w, time, Key), key(k), unicode(text), repeat(autorep),
+ repeatCount(count), modifiers(mods), keyType(t),
+ nativeScanCode(nativeSC), nativeVirtualKey(nativeVK), nativeModifiers(nativeMods) { }
int key;
QString unicode;
bool repeat;
ushort repeatCount;
Qt::KeyboardModifiers modifiers;
QEvent::Type keyType;
+ quint32 nativeScanCode;
+ quint32 nativeVirtualKey;
+ quint32 nativeModifiers;
};
class TouchEvent : public UserEvent {
diff --git a/src/gui/kernel/qx11embed_x11.cpp b/src/gui/kernel/qx11embed_x11.cpp
index 47cefe4..49a8194 100644
--- a/src/gui/kernel/qx11embed_x11.cpp
+++ b/src/gui/kernel/qx11embed_x11.cpp
@@ -415,8 +415,9 @@ static Bool functor(Display *display, XEvent *event, XPointer arg)
status = XGetWindowProperty(display, data->id, ATOM(WM_STATE), 0, 2, False, ATOM(WM_STATE),
&ret, &format, &nitems, &after, &retval );
if (status == Success && ret == ATOM(WM_STATE) && format == 32 && nitems > 0) {
- long *state = (long *)retval;
- if (state[0] == WithdrawnState) {
+ long state = *(long *)retval;
+ XFree(retval);
+ if (state == WithdrawnState) {
data->clearedWmState = true;
return true;
}
@@ -833,6 +834,8 @@ bool QX11EmbedWidget::x11Event(XEvent *event)
XUnmapWindow(x11Info().display(), internalWinId());
}
}
+ if (prop_return)
+ XFree(prop_return);
}
}