summaryrefslogtreecommitdiffstats
path: root/src/plugins
diff options
context:
space:
mode:
authorOswald Buddenhagen <oswald.buddenhagen@digia.com>2013-03-20 13:46:57 +0100
committerOswald Buddenhagen <oswald.buddenhagen@digia.com>2013-03-20 13:49:28 +0100
commit76c0be34cd4ff4564693162fa7528463e23ce9d8 (patch)
treef165b7bc319548fb0082365411a871028f92e89e /src/plugins
parent27b4fe96b59e9e63d1e570e802c072e9afdfb2d4 (diff)
parent36cb3f3f655a9090c82de609010cbfb88651a0f3 (diff)
Merge branch 'dev' into stable
This starts Qt 5.1 release cycle Conflicts: src/gui/text/qfontdatabase.cpp src/gui/text/qharfbuzz_copy_p.h src/widgets/kernel/qapplication.cpp src/widgets/kernel/qcoreapplication.cpp Change-Id: I72fbf83ab3c2206aeea1b089428b0fc2a89bd62b
Diffstat (limited to 'src/plugins')
-rw-r--r--src/plugins/accessible/widgets/complexwidgets.h4
-rw-r--r--src/plugins/accessible/widgets/itemviews.cpp221
-rw-r--r--src/plugins/accessible/widgets/itemviews.h14
-rw-r--r--src/plugins/accessible/widgets/main.cpp3
-rw-r--r--src/plugins/accessible/widgets/qaccessiblemenu.h2
-rw-r--r--src/plugins/accessible/widgets/qaccessiblewidgets.h4
-rw-r--r--src/plugins/accessible/widgets/rangecontrols.h4
-rw-r--r--src/plugins/accessible/widgets/simplewidgets.h4
-rw-r--r--src/plugins/accessible/widgets/widgets.json4
-rw-r--r--src/plugins/bearer/bearer.pro4
-rw-r--r--src/plugins/bearer/connman/qconnmanengine.cpp2
-rw-r--r--src/plugins/bearer/connman/qconnmanservice_linux.cpp4
-rw-r--r--src/plugins/bearer/connman/qconnmanservice_linux_p.h2
-rw-r--r--src/plugins/bearer/corewlan/corewlan.pro4
-rw-r--r--src/plugins/bearer/networkmanager/qnetworkmanagerservice.h84
-rw-r--r--src/plugins/bearer/qnetworksession_impl.h2
-rw-r--r--src/plugins/generic/meego/qmeegointegration.h4
-rw-r--r--src/plugins/generic/tslib/qtslib.h4
-rw-r--r--src/plugins/imageformats/gif/gif.json3
-rw-r--r--src/plugins/imageformats/ico/ico.json3
-rw-r--r--src/plugins/imageformats/ico/qicohandler.cpp2
-rw-r--r--src/plugins/imageformats/ico/qicohandler.h6
-rw-r--r--src/plugins/imageformats/jpeg/jpeg.json3
-rw-r--r--src/plugins/platforminputcontexts/ibus/qibusplatforminputcontext.cpp20
-rw-r--r--src/plugins/platforminputcontexts/platforminputcontexts.pro2
-rw-r--r--src/plugins/platforms/android/android.pro3
-rw-r--r--src/plugins/platforms/android/opengl/opengl.pro30
-rw-r--r--src/plugins/platforms/android/raster/raster.pro19
-rw-r--r--src/plugins/platforms/android/src/android.json3
-rw-r--r--src/plugins/platforms/android/src/androidjniclipboard.cpp120
-rw-r--r--src/plugins/platforms/android/src/androidjniclipboard.h61
-rw-r--r--src/plugins/platforms/android/src/androidjniinput.cpp497
-rw-r--r--src/plugins/platforms/android/src/androidjniinput.h59
-rw-r--r--src/plugins/platforms/android/src/androidjnimain.cpp845
-rw-r--r--src/plugins/platforms/android/src/androidjnimain.h121
-rw-r--r--src/plugins/platforms/android/src/androidjnimenu.cpp405
-rw-r--r--src/plugins/platforms/android/src/androidjnimenu.h69
-rw-r--r--src/plugins/platforms/android/src/androidplatformplugin.cpp66
-rw-r--r--src/plugins/platforms/android/src/opengl/qandroidopenglcontext.cpp78
-rw-r--r--src/plugins/platforms/android/src/opengl/qandroidopenglcontext.h68
-rw-r--r--src/plugins/platforms/android/src/opengl/qandroidopenglplatformwindow.cpp72
-rw-r--r--src/plugins/platforms/android/src/opengl/qandroidopenglplatformwindow.h73
-rw-r--r--src/plugins/platforms/android/src/opengl/qeglfshooks_android.cpp132
-rw-r--r--src/plugins/platforms/android/src/qandroidassetsfileenginehandler.cpp288
-rw-r--r--src/plugins/platforms/android/src/qandroidassetsfileenginehandler.h60
-rw-r--r--src/plugins/platforms/android/src/qandroidinputcontext.cpp644
-rw-r--r--src/plugins/platforms/android/src/qandroidinputcontext.h130
-rw-r--r--src/plugins/platforms/android/src/qandroidplatformclipboard.cpp79
-rw-r--r--src/plugins/platforms/android/src/qandroidplatformclipboard.h63
-rw-r--r--src/plugins/platforms/android/src/qandroidplatformfontdatabase.cpp79
-rw-r--r--src/plugins/platforms/android/src/qandroidplatformfontdatabase.h58
-rw-r--r--src/plugins/platforms/android/src/qandroidplatformintegration.cpp285
-rw-r--r--src/plugins/platforms/android/src/qandroidplatformintegration.h164
-rw-r--r--src/plugins/platforms/android/src/qandroidplatformmenu.cpp167
-rw-r--r--src/plugins/platforms/android/src/qandroidplatformmenu.h91
-rw-r--r--src/plugins/platforms/android/src/qandroidplatformmenubar.cpp109
-rw-r--r--src/plugins/platforms/android/src/qandroidplatformmenubar.h74
-rw-r--r--src/plugins/platforms/android/src/qandroidplatformmenuitem.cpp180
-rw-r--r--src/plugins/platforms/android/src/qandroidplatformmenuitem.h99
-rw-r--r--src/plugins/platforms/android/src/qandroidplatformservices.cpp83
-rw-r--r--src/plugins/platforms/android/src/qandroidplatformservices.h61
-rw-r--r--src/plugins/platforms/android/src/qandroidplatformtheme.cpp78
-rw-r--r--src/plugins/platforms/android/src/qandroidplatformtheme.h56
-rw-r--r--src/plugins/platforms/android/src/raster/qandroidplatformscreen.cpp71
-rw-r--r--src/plugins/platforms/android/src/raster/qandroidplatformscreen.h59
-rw-r--r--src/plugins/platforms/android/src/raster/qandroidplatformwindow.cpp56
-rw-r--r--src/plugins/platforms/android/src/raster/qandroidplatformwindow.h60
-rw-r--r--src/plugins/platforms/android/src/raster/raster.pri7
-rw-r--r--src/plugins/platforms/android/src/src.pri47
-rw-r--r--src/plugins/platforms/cocoa/cocoa.pro2
-rw-r--r--src/plugins/platforms/cocoa/qcocoaaccessibility.mm2
-rw-r--r--src/plugins/platforms/cocoa/qcocoaaccessibilityelement.h1
-rw-r--r--src/plugins/platforms/cocoa/qcocoaaccessibilityelement.mm2
-rw-r--r--src/plugins/platforms/cocoa/qcocoaapplicationdelegate.h13
-rw-r--r--src/plugins/platforms/cocoa/qcocoabackingstore.mm6
-rw-r--r--src/plugins/platforms/cocoa/qcocoacursor.mm7
-rw-r--r--src/plugins/platforms/cocoa/qcocoaeventdispatcher.h12
-rw-r--r--src/plugins/platforms/cocoa/qcocoaeventdispatcher.mm239
-rw-r--r--src/plugins/platforms/cocoa/qcocoafiledialoghelper.mm34
-rw-r--r--src/plugins/platforms/cocoa/qcocoaglcontext.mm16
-rw-r--r--src/plugins/platforms/cocoa/qcocoahelpers.h2
-rw-r--r--src/plugins/platforms/cocoa/qcocoahelpers.mm35
-rw-r--r--src/plugins/platforms/cocoa/qcocoaintegration.mm4
-rw-r--r--src/plugins/platforms/cocoa/qcocoaintrospection.mm4
-rw-r--r--src/plugins/platforms/cocoa/qcocoamenu.h12
-rw-r--r--src/plugins/platforms/cocoa/qcocoamenu.mm35
-rw-r--r--src/plugins/platforms/cocoa/qcocoamenuitem.h5
-rw-r--r--src/plugins/platforms/cocoa/qcocoaprintersupport.h1
-rw-r--r--src/plugins/platforms/cocoa/qcocoaprintersupport.mm31
-rwxr-xr-xsrc/plugins/platforms/cocoa/qcocoasystemtrayicon.h2
-rwxr-xr-xsrc/plugins/platforms/cocoa/qcocoasystemtrayicon.mm47
-rw-r--r--src/plugins/platforms/cocoa/qcocoawindow.h4
-rw-r--r--src/plugins/platforms/cocoa/qcocoawindow.mm33
-rw-r--r--src/plugins/platforms/cocoa/qmacdefines_mac.h4
-rw-r--r--src/plugins/platforms/cocoa/qmultitouch_mac.mm5
-rw-r--r--src/plugins/platforms/cocoa/qmultitouch_mac_p.h4
-rw-r--r--src/plugins/platforms/cocoa/qnsview.h4
-rw-r--r--src/plugins/platforms/cocoa/qnsview.mm29
-rw-r--r--src/plugins/platforms/cocoa/qnsviewaccessibility.mm2
-rw-r--r--src/plugins/platforms/cocoa/qnswindowdelegate.h20
-rw-r--r--src/plugins/platforms/cocoa/qpaintengine_mac.mm27
-rw-r--r--src/plugins/platforms/cocoa/qpaintengine_mac_p.h2
-rw-r--r--src/plugins/platforms/cocoa/qprintengine_mac.mm56
-rw-r--r--src/plugins/platforms/cocoa/qprintengine_mac_p.h3
-rw-r--r--src/plugins/platforms/directfb/qdirectfbcursor.cpp5
-rw-r--r--src/plugins/platforms/eglfs/eglfs.pri44
-rw-r--r--src/plugins/platforms/eglfs/eglfs.pro46
-rw-r--r--src/plugins/platforms/eglfs/qeglfscontext.cpp22
-rw-r--r--src/plugins/platforms/eglfs/qeglfscursor.cpp7
-rw-r--r--src/plugins/platforms/eglfs/qeglfshooks.h20
-rw-r--r--src/plugins/platforms/eglfs/qeglfshooks_stub.cpp134
-rw-r--r--src/plugins/platforms/eglfs/qeglfsintegration.cpp48
-rw-r--r--src/plugins/platforms/eglfs/qeglfsintegration.h9
-rw-r--r--src/plugins/platforms/eglfs/qeglfsscreen.cpp13
-rw-r--r--src/plugins/platforms/eglfs/qeglfsscreen.h2
-rw-r--r--src/plugins/platforms/eglfs/qeglfswindow.cpp37
-rw-r--r--src/plugins/platforms/eglfs/qeglfswindow.h4
-rw-r--r--src/plugins/platforms/ios/ios.json3
-rw-r--r--src/plugins/platforms/ios/ios.pro3
-rw-r--r--src/plugins/platforms/ios/plugin.mm69
-rw-r--r--src/plugins/platforms/ios/plugin.pro36
-rw-r--r--src/plugins/platforms/ios/qiosapplicationdelegate.h53
-rw-r--r--src/plugins/platforms/ios/qiosapplicationdelegate.mm94
-rw-r--r--src/plugins/platforms/ios/qiosbackingstore.h70
-rw-r--r--src/plugins/platforms/ios/qiosbackingstore.mm125
-rw-r--r--src/plugins/platforms/ios/qioscontext.h91
-rw-r--r--src/plugins/platforms/ios/qioscontext.mm204
-rw-r--r--src/plugins/platforms/ios/qioseventdispatcher.h133
-rw-r--r--src/plugins/platforms/ios/qioseventdispatcher.mm322
-rw-r--r--src/plugins/platforms/ios/qiosglobal.h67
-rw-r--r--src/plugins/platforms/ios/qiosglobal.mm144
-rw-r--r--src/plugins/platforms/ios/qiosinputcontext.h73
-rw-r--r--src/plugins/platforms/ios/qiosinputcontext.mm142
-rw-r--r--src/plugins/platforms/ios/qiosintegration.h88
-rw-r--r--src/plugins/platforms/ios/qiosintegration.mm180
-rw-r--r--src/plugins/platforms/ios/qiosscreen.h88
-rw-r--r--src/plugins/platforms/ios/qiosscreen.mm238
-rw-r--r--src/plugins/platforms/ios/qiossoftwareinputhandler.h71
-rw-r--r--src/plugins/platforms/ios/qiostheme.h64
-rw-r--r--src/plugins/platforms/ios/qiostheme.mm96
-rw-r--r--src/plugins/platforms/ios/qiosviewcontroller.h46
-rw-r--r--src/plugins/platforms/ios/qiosviewcontroller.mm90
-rw-r--r--src/plugins/platforms/ios/qioswindow.h103
-rw-r--r--src/plugins/platforms/ios/qioswindow.mm523
-rw-r--r--src/plugins/platforms/ios/qtmain.mm93
-rw-r--r--src/plugins/platforms/ios/qtmain.pro8
-rw-r--r--src/plugins/platforms/kms/kms.pro5
-rw-r--r--src/plugins/platforms/kms/qkmscursor.cpp68
-rw-r--r--src/plugins/platforms/kms/qkmscursor.h10
-rw-r--r--src/plugins/platforms/kms/qkmsscreen.cpp12
-rw-r--r--src/plugins/platforms/minimalegl/qminimaleglbackingstore.cpp1
-rw-r--r--src/plugins/platforms/minimalegl/qminimaleglintegration.h3
-rw-r--r--src/plugins/platforms/offscreen/main.cpp67
-rw-r--r--src/plugins/platforms/offscreen/offscreen.json3
-rw-r--r--src/plugins/platforms/offscreen/offscreen.pro25
-rw-r--r--src/plugins/platforms/offscreen/qoffscreencommon.cpp229
-rw-r--r--src/plugins/platforms/offscreen/qoffscreencommon.h109
-rw-r--r--src/plugins/platforms/offscreen/qoffscreenintegration.cpp162
-rw-r--r--src/plugins/platforms/offscreen/qoffscreenintegration.h80
-rw-r--r--src/plugins/platforms/offscreen/qoffscreenintegration_dummy.cpp47
-rw-r--r--src/plugins/platforms/offscreen/qoffscreenintegration_x11.cpp252
-rw-r--r--src/plugins/platforms/offscreen/qoffscreenintegration_x11.h108
-rw-r--r--src/plugins/platforms/offscreen/qoffscreenwindow.cpp199
-rw-r--r--src/plugins/platforms/offscreen/qoffscreenwindow.h86
-rw-r--r--src/plugins/platforms/platforms.pro9
-rw-r--r--src/plugins/platforms/qnx/qqnxbpseventfilter.cpp22
-rw-r--r--src/plugins/platforms/qnx/qqnxclipboard.h2
-rw-r--r--src/plugins/platforms/qnx/qqnxintegration.cpp2
-rw-r--r--src/plugins/platforms/qnx/qqnxnavigatoreventhandler.cpp6
-rw-r--r--src/plugins/platforms/qnx/qqnxnavigatoreventhandler.h2
-rw-r--r--src/plugins/platforms/qnx/qqnxscreen.cpp41
-rw-r--r--src/plugins/platforms/qnx/qqnxscreen.h3
-rw-r--r--src/plugins/platforms/qnx/qqnxwindow.cpp38
-rw-r--r--src/plugins/platforms/qnx/qqnxwindow.h1
-rw-r--r--src/plugins/platforms/windows/accessible/iaccessible2.cpp2
-rw-r--r--src/plugins/platforms/windows/accessible/qwindowsaccessibility.cpp17
-rw-r--r--src/plugins/platforms/windows/accessible/qwindowsaccessibility.h2
-rw-r--r--src/plugins/platforms/windows/accessible/qwindowsmsaaaccessible.cpp2
-rw-r--r--src/plugins/platforms/windows/qtwindows_additional.h4
-rw-r--r--src/plugins/platforms/windows/qwindowscontext.cpp90
-rw-r--r--src/plugins/platforms/windows/qwindowscursor.cpp35
-rw-r--r--src/plugins/platforms/windows/qwindowscursor.h5
-rw-r--r--src/plugins/platforms/windows/qwindowsdialoghelpers.cpp567
-rw-r--r--src/plugins/platforms/windows/qwindowsdialoghelpers.h10
-rw-r--r--src/plugins/platforms/windows/qwindowsdrag.cpp6
-rw-r--r--src/plugins/platforms/windows/qwindowsfontdatabase.cpp147
-rw-r--r--src/plugins/platforms/windows/qwindowsfontdatabase.h4
-rw-r--r--src/plugins/platforms/windows/qwindowsfontdatabase_ft.cpp12
-rw-r--r--src/plugins/platforms/windows/qwindowsfontdatabase_ft.h4
-rw-r--r--src/plugins/platforms/windows/qwindowsfontengine.cpp20
-rw-r--r--src/plugins/platforms/windows/qwindowsfontengine.h2
-rw-r--r--src/plugins/platforms/windows/qwindowsfontenginedirectwrite.cpp6
-rw-r--r--src/plugins/platforms/windows/qwindowsfontenginedirectwrite.h2
-rw-r--r--src/plugins/platforms/windows/qwindowsglcontext.cpp14
-rw-r--r--src/plugins/platforms/windows/qwindowsintegration.cpp42
-rw-r--r--src/plugins/platforms/windows/qwindowskeymapper.cpp14
-rw-r--r--src/plugins/platforms/windows/qwindowsmime.cpp4
-rw-r--r--src/plugins/platforms/windows/qwindowsmousehandler.cpp4
-rw-r--r--src/plugins/platforms/windows/qwindowsservices.cpp4
-rw-r--r--src/plugins/platforms/windows/qwindowswindow.cpp175
-rw-r--r--src/plugins/platforms/windows/qwindowswindow.h23
-rw-r--r--src/plugins/platforms/windows/windows.pro4
-rw-r--r--src/plugins/platforms/xcb/qglxintegration.cpp193
-rw-r--r--src/plugins/platforms/xcb/qglxintegration.h20
-rw-r--r--src/plugins/platforms/xcb/qxcbconnection.cpp6
-rw-r--r--src/plugins/platforms/xcb/qxcbconnection.h2
-rw-r--r--src/plugins/platforms/xcb/qxcbcursor.cpp34
-rw-r--r--src/plugins/platforms/xcb/qxcbintegration.cpp22
-rw-r--r--src/plugins/platforms/xcb/qxcbintegration.h2
-rw-r--r--src/plugins/platforms/xcb/qxcbkeyboard.cpp9
-rw-r--r--src/plugins/platforms/xcb/qxcbwindow.cpp242
-rw-r--r--src/plugins/platforms/xcb/qxcbwindow.h9
-rw-r--r--src/plugins/platformthemes/gtk2/gtk2.json3
-rw-r--r--src/plugins/platformthemes/gtk2/gtk2.pro20
-rw-r--r--src/plugins/platformthemes/gtk2/main.cpp67
-rw-r--r--src/plugins/platformthemes/gtk2/qgtk2dialoghelpers.cpp609
-rw-r--r--src/plugins/platformthemes/gtk2/qgtk2dialoghelpers.h143
-rw-r--r--src/plugins/platformthemes/gtk2/qgtk2theme.cpp108
-rw-r--r--src/plugins/platformthemes/gtk2/qgtk2theme.h64
-rw-r--r--src/plugins/platformthemes/platformthemes.pro3
-rw-r--r--src/plugins/plugins.pro5
-rw-r--r--src/plugins/printsupport/cups/qcupsprintengine.cpp47
-rw-r--r--src/plugins/printsupport/cups/qcupsprintengine_p.h1
-rw-r--r--src/plugins/printsupport/cups/qcupsprintersupport.cpp5
-rw-r--r--src/plugins/printsupport/cups/qcupsprintersupport_p.h3
-rw-r--r--src/plugins/printsupport/windows/qwindowsprintersupport.cpp5
-rw-r--r--src/plugins/printsupport/windows/qwindowsprintersupport.h3
-rw-r--r--src/plugins/sqldrivers/db2/main.cpp2
-rw-r--r--src/plugins/sqldrivers/ibase/main.cpp2
-rw-r--r--src/plugins/sqldrivers/mysql/main.cpp2
-rw-r--r--src/plugins/sqldrivers/oci/main.cpp2
-rw-r--r--src/plugins/sqldrivers/odbc/main.cpp2
-rw-r--r--src/plugins/sqldrivers/psql/main.cpp2
-rw-r--r--src/plugins/sqldrivers/sqlite/smain.cpp2
-rw-r--r--src/plugins/sqldrivers/sqlite2/smain.cpp2
-rw-r--r--src/plugins/sqldrivers/tds/main.cpp2
236 files changed, 13935 insertions, 1212 deletions
diff --git a/src/plugins/accessible/widgets/complexwidgets.h b/src/plugins/accessible/widgets/complexwidgets.h
index 1dc4d99ea8..32f67c9c69 100644
--- a/src/plugins/accessible/widgets/complexwidgets.h
+++ b/src/plugins/accessible/widgets/complexwidgets.h
@@ -43,9 +43,9 @@
#define COMPLEXWIDGETS_H
#include <QtCore/qpointer.h>
-#include <QtWidgets/qaccessiblewidget.h>
+#include <QtWidgets/private/qaccessiblewidget_p.h>
#include <QtWidgets/qabstractitemview.h>
-#include <QtGui/qaccessible2.h>
+#include <QtGui/private/qaccessible2_p.h>
QT_BEGIN_NAMESPACE
diff --git a/src/plugins/accessible/widgets/itemviews.cpp b/src/plugins/accessible/widgets/itemviews.cpp
index a3fcc22fc4..cb34116f32 100644
--- a/src/plugins/accessible/widgets/itemviews.cpp
+++ b/src/plugins/accessible/widgets/itemviews.cpp
@@ -46,7 +46,7 @@
#include <qlistview.h>
#include <qtreeview.h>
#include <private/qtreewidget_p.h>
-#include <qaccessible2.h>
+#include <QtGui/private/qaccessible2_p.h>
#include <QDebug>
#ifndef QT_NO_ACCESSIBILITY
@@ -299,9 +299,28 @@ bool QAccessibleTable::selectRow(int row)
if (!view()->model() || !view()->selectionModel())
return false;
QModelIndex index = view()->model()->index(row, 0, view()->rootIndex());
- if (!index.isValid() || view()->selectionMode() & QAbstractItemView::NoSelection)
+
+ if (!index.isValid() || view()->selectionBehavior() == QAbstractItemView::SelectColumns)
+ return false;
+
+ switch (view()->selectionMode()) {
+ case QAbstractItemView::NoSelection:
return false;
- view()->selectionModel()->select(index, QItemSelectionModel::Select);
+ case QAbstractItemView::SingleSelection:
+ if (view()->selectionBehavior() != QAbstractItemView::SelectRows && columnCount() > 1 )
+ return false;
+ view()->clearSelection();
+ break;
+ case QAbstractItemView::ContiguousSelection:
+ if ((!row || !view()->selectionModel()->isRowSelected(row - 1, view()->rootIndex()))
+ && !view()->selectionModel()->isRowSelected(row + 1, view()->rootIndex()))
+ view()->clearSelection();
+ break;
+ default:
+ break;
+ }
+
+ view()->selectionModel()->select(index, QItemSelectionModel::Select | QItemSelectionModel::Rows);
return true;
}
@@ -310,9 +329,26 @@ bool QAccessibleTable::selectColumn(int column)
if (!view()->model() || !view()->selectionModel())
return false;
QModelIndex index = view()->model()->index(0, column, view()->rootIndex());
- if (!index.isValid() || view()->selectionMode() & QAbstractItemView::NoSelection)
+
+ if (!index.isValid() || view()->selectionBehavior() == QAbstractItemView::SelectRows)
+ return false;
+
+ switch (view()->selectionMode()) {
+ case QAbstractItemView::NoSelection:
return false;
- view()->selectionModel()->select(index, QItemSelectionModel::Select);
+ case QAbstractItemView::SingleSelection:
+ if (view()->selectionBehavior() != QAbstractItemView::SelectColumns && rowCount() > 1)
+ return false;
+ case QAbstractItemView::ContiguousSelection:
+ if ((!column || !view()->selectionModel()->isColumnSelected(column - 1, view()->rootIndex()))
+ && !view()->selectionModel()->isColumnSelected(column + 1, view()->rootIndex()))
+ view()->clearSelection();
+ break;
+ default:
+ break;
+ }
+
+ view()->selectionModel()->select(index, QItemSelectionModel::Select | QItemSelectionModel::Columns);
return true;
}
@@ -320,10 +356,35 @@ bool QAccessibleTable::unselectRow(int row)
{
if (!view()->model() || !view()->selectionModel())
return false;
+
QModelIndex index = view()->model()->index(row, 0, view()->rootIndex());
- if (!index.isValid() || view()->selectionMode() & QAbstractItemView::NoSelection)
+ if (!index.isValid())
return false;
- view()->selectionModel()->select(index, QItemSelectionModel::Deselect);
+
+ QItemSelection selection(index, index);
+
+ switch (view()->selectionMode()) {
+ case QAbstractItemView::SingleSelection:
+ //In SingleSelection and ContiguousSelection once an item
+ //is selected, there's no way for the user to unselect all items
+ if (selectedRowCount() == 1)
+ return false;
+ break;
+ case QAbstractItemView::ContiguousSelection:
+ if (selectedRowCount() == 1)
+ return false;
+
+ if ((!row || view()->selectionModel()->isRowSelected(row - 1, view()->rootIndex()))
+ && view()->selectionModel()->isRowSelected(row + 1, view()->rootIndex())) {
+ //If there are rows selected both up the current row and down the current rown,
+ //the ones which are down the current row will be deselected
+ selection = QItemSelection(index, view()->model()->index(rowCount() - 1, 0, view()->rootIndex()));
+ }
+ default:
+ break;
+ }
+
+ view()->selectionModel()->select(selection, QItemSelectionModel::Deselect | QItemSelectionModel::Rows);
return true;
}
@@ -331,10 +392,35 @@ bool QAccessibleTable::unselectColumn(int column)
{
if (!view()->model() || !view()->selectionModel())
return false;
+
QModelIndex index = view()->model()->index(0, column, view()->rootIndex());
- if (!index.isValid() || view()->selectionMode() & QAbstractItemView::NoSelection)
+ if (!index.isValid())
return false;
- view()->selectionModel()->select(index, QItemSelectionModel::Columns & QItemSelectionModel::Deselect);
+
+ QItemSelection selection(index, index);
+
+ switch (view()->selectionMode()) {
+ case QAbstractItemView::SingleSelection:
+ //In SingleSelection and ContiguousSelection once an item
+ //is selected, there's no way for the user to unselect all items
+ if (selectedColumnCount() == 1)
+ return false;
+ break;
+ case QAbstractItemView::ContiguousSelection:
+ if (selectedColumnCount() == 1)
+ return false;
+
+ if ((!column || view()->selectionModel()->isColumnSelected(column - 1, view()->rootIndex()))
+ && view()->selectionModel()->isColumnSelected(column + 1, view()->rootIndex())) {
+ //If there are columns selected both at the left of the current row and at the right
+ //of the current rown, the ones which are at the right will be deselected
+ selection = QItemSelection(index, view()->model()->index(0, columnCount() - 1, view()->rootIndex()));
+ }
+ default:
+ break;
+ }
+
+ view()->selectionModel()->select(selection, QItemSelectionModel::Deselect | QItemSelectionModel::Columns);
return true;
}
@@ -415,7 +501,7 @@ QRect QAccessibleTable::rect() const
QAccessibleInterface *QAccessibleTable::parent() const
{
- if (view()->parent()) {
+ if (view() && view()->parent()) {
if (qstrcmp("QComboBoxPrivateContainer", view()->parent()->metaObject()->className()) == 0) {
return QAccessible::queryAccessibleInterface(view()->parent()->parent());
}
@@ -576,9 +662,28 @@ bool QAccessibleTree::selectRow(int row)
if (!view()->selectionModel())
return false;
QModelIndex index = indexFromLogical(row);
- if (!index.isValid() || view()->selectionMode() & QAbstractItemView::NoSelection)
+
+ if (!index.isValid() || view()->selectionBehavior() == QAbstractItemView::SelectColumns)
return false;
- view()->selectionModel()->select(index, QItemSelectionModel::Select);
+
+ switch (view()->selectionMode()) {
+ case QAbstractItemView::NoSelection:
+ return false;
+ case QAbstractItemView::SingleSelection:
+ if ((view()->selectionBehavior() != QAbstractItemView::SelectRows) && (columnCount() > 1))
+ return false;
+ view()->clearSelection();
+ break;
+ case QAbstractItemView::ContiguousSelection:
+ if ((!row || !view()->selectionModel()->isRowSelected(row - 1, view()->rootIndex()))
+ && !view()->selectionModel()->isRowSelected(row + 1, view()->rootIndex()))
+ view()->clearSelection();
+ break;
+ default:
+ break;
+ }
+
+ view()->selectionModel()->select(index, QItemSelectionModel::Select | QItemSelectionModel::Rows);
return true;
}
@@ -595,6 +700,8 @@ void *QAccessibleTableCell::interface_cast(QAccessible::InterfaceType t)
{
if (t == QAccessible::TableCellInterface)
return static_cast<QAccessibleTableCellInterface*>(this);
+ if (t == QAccessible::ActionInterface)
+ return static_cast<QAccessibleActionInterface*>(this);
return 0;
}
@@ -668,6 +775,89 @@ bool QAccessibleTableCell::isSelected() const
return view->selectionModel()->isSelected(m_index);
}
+QStringList QAccessibleTableCell::actionNames() const
+{
+ QStringList names;
+ names << toggleAction();
+ return names;
+}
+
+void QAccessibleTableCell::doAction(const QString& actionName)
+{
+ if (actionName == toggleAction()) {
+ if (isSelected())
+ unselectCell();
+ else
+ selectCell();
+ }
+}
+
+QStringList QAccessibleTableCell::keyBindingsForAction(const QString &) const
+{
+ return QStringList();
+}
+
+
+void QAccessibleTableCell::selectCell()
+{
+ QAbstractItemView::SelectionMode selectionMode = view->selectionMode();
+ if (!m_index.isValid() || (selectionMode == QAbstractItemView::NoSelection))
+ return;
+
+ QSharedPointer<QAccessibleTableInterface> cellTable(table()->tableInterface());
+
+ switch (view->selectionBehavior()) {
+ case QAbstractItemView::SelectItems:
+ break;
+ case QAbstractItemView::SelectColumns:
+ if (cellTable.data())
+ cellTable->selectColumn(m_index.column());
+ return;
+ case QAbstractItemView::SelectRows:
+ if (cellTable.data())
+ cellTable->selectRow(m_index.row());
+ return;
+ }
+
+ if (selectionMode == QAbstractItemView::SingleSelection) {
+ view->clearSelection();
+ }
+
+ view->selectionModel()->select(m_index, QItemSelectionModel::Select);
+}
+
+void QAccessibleTableCell::unselectCell()
+{
+
+ QAbstractItemView::SelectionMode selectionMode = view->selectionMode();
+ if (!m_index.isValid() || (selectionMode & QAbstractItemView::NoSelection))
+ return;
+
+ QSharedPointer<QAccessibleTableInterface> cellTable(table()->tableInterface());
+
+ switch (view->selectionBehavior()) {
+ case QAbstractItemView::SelectItems:
+ break;
+ case QAbstractItemView::SelectColumns:
+ if (cellTable.data())
+ cellTable->unselectColumn(m_index.column());
+ return;
+ case QAbstractItemView::SelectRows:
+ if (cellTable.data())
+ cellTable->unselectRow(m_index.row());
+ return;
+ }
+
+ //If the mode is not MultiSelection or ExtendedSelection and only
+ //one cell is selected it cannot be unselected by the user
+ if ((selectionMode != QAbstractItemView::MultiSelection)
+ && (selectionMode != QAbstractItemView::ExtendedSelection)
+ && (view->selectionModel()->selectedIndexes().count() <= 1))
+ return;
+
+ view->selectionModel()->select(m_index, QItemSelectionModel::Deselect);
+}
+
void QAccessibleTableCell::rowColumnExtents(int *row, int *column, int *rowExtents, int *columnExtents, bool *selected) const
{
*row = m_index.row();
@@ -856,14 +1046,11 @@ bool QAccessibleTableHeaderCell::isValid() const
QAccessibleInterface *QAccessibleTableHeaderCell::parent() const
{
- if (false) {
#ifndef QT_NO_TREEVIEW
- } else if (qobject_cast<const QTreeView*>(view)) {
+ if (qobject_cast<const QTreeView*>(view))
return new QAccessibleTree(view);
#endif
- } else {
- return new QAccessibleTable(view);
- }
+ return new QAccessibleTable(view);
}
QAccessibleInterface *QAccessibleTableHeaderCell::child(int) const
diff --git a/src/plugins/accessible/widgets/itemviews.h b/src/plugins/accessible/widgets/itemviews.h
index d58d504690..bba698bda2 100644
--- a/src/plugins/accessible/widgets/itemviews.h
+++ b/src/plugins/accessible/widgets/itemviews.h
@@ -44,8 +44,8 @@
#include "QtCore/qpointer.h"
#include <QtGui/qaccessible.h>
-#include <QtGui/qaccessible2.h>
-#include <QtWidgets/qaccessiblewidget.h>
+#include <QtGui/private/qaccessible2_p.h>
+#include <QtWidgets/private/qaccessiblewidget_p.h>
#include <QtWidgets/qabstractitemview.h>
#include <QtWidgets/qheaderview.h>
@@ -159,7 +159,7 @@ private:
QModelIndex indexFromLogical(int row, int column = 0) const;
};
-class QAccessibleTableCell: public QAccessibleInterface, public QAccessibleTableCellInterface
+class QAccessibleTableCell: public QAccessibleInterface, public QAccessibleTableCellInterface, public QAccessibleActionInterface
{
public:
QAccessibleTableCell(QAbstractItemView *view, const QModelIndex &m_index, QAccessible::Role role);
@@ -192,6 +192,11 @@ public:
virtual void rowColumnExtents(int *row, int *column, int *rowExtents, int *columnExtents, bool *selected) const;
virtual QAccessibleInterface* table() const;
+ //action interface
+ virtual QStringList actionNames() const;
+ virtual void doAction(const QString &actionName);
+ virtual QStringList keyBindingsForAction(const QString &actionName) const;
+
private:
QHeaderView *verticalHeader() const;
QHeaderView *horizontalHeader() const;
@@ -199,6 +204,9 @@ private:
QModelIndex m_index;
QAccessible::Role m_role;
+ void selectCell();
+ void unselectCell();
+
friend class QAccessibleTable;
friend class QAccessibleTree;
};
diff --git a/src/plugins/accessible/widgets/main.cpp b/src/plugins/accessible/widgets/main.cpp
index 9a42474910..92cda9f3ca 100644
--- a/src/plugins/accessible/widgets/main.cpp
+++ b/src/plugins/accessible/widgets/main.cpp
@@ -251,6 +251,9 @@ QAccessibleInterface *AccessibleFactory::create(const QString &classname, QObjec
} else if (classname == QLatin1String("QDockWidget")) {
iface = new QAccessibleDockWidget(widget);
#endif
+
+ } else if (classname == QLatin1String("QDesktopScreenWidget")) {
+ iface = 0;
} else {
iface = new QAccessibleWidget(widget);
}
diff --git a/src/plugins/accessible/widgets/qaccessiblemenu.h b/src/plugins/accessible/widgets/qaccessiblemenu.h
index 0241cebab6..74d118a09e 100644
--- a/src/plugins/accessible/widgets/qaccessiblemenu.h
+++ b/src/plugins/accessible/widgets/qaccessiblemenu.h
@@ -42,7 +42,7 @@
#ifndef QACCESSIBLEMENU_H
#define QACCESSIBLEMENU_H
-#include <QtWidgets/qaccessiblewidget.h>
+#include <QtWidgets/private/qaccessiblewidget_p.h>
QT_BEGIN_NAMESPACE
diff --git a/src/plugins/accessible/widgets/qaccessiblewidgets.h b/src/plugins/accessible/widgets/qaccessiblewidgets.h
index 683893f477..35ef3ce905 100644
--- a/src/plugins/accessible/widgets/qaccessiblewidgets.h
+++ b/src/plugins/accessible/widgets/qaccessiblewidgets.h
@@ -42,8 +42,8 @@
#ifndef QACCESSIBLEWIDGETS_H
#define QACCESSIBLEWIDGETS_H
-#include <QtGui/qaccessible2.h>
-#include <QtWidgets/qaccessiblewidget.h>
+#include <QtGui/private/qaccessible2_p.h>
+#include <QtWidgets/private/qaccessiblewidget_p.h>
#ifndef QT_NO_ACCESSIBILITY
diff --git a/src/plugins/accessible/widgets/rangecontrols.h b/src/plugins/accessible/widgets/rangecontrols.h
index ef6f3fa226..a5bc11e1c8 100644
--- a/src/plugins/accessible/widgets/rangecontrols.h
+++ b/src/plugins/accessible/widgets/rangecontrols.h
@@ -42,8 +42,8 @@
#ifndef RANGECONTROLS_H
#define RANGECONTROLS_H
-#include <QtWidgets/qaccessiblewidget.h>
-#include <QtGui/qaccessible2.h>
+#include <QtWidgets/private/qaccessiblewidget_p.h>
+#include <QtGui/private/qaccessible2_p.h>
QT_BEGIN_NAMESPACE
diff --git a/src/plugins/accessible/widgets/simplewidgets.h b/src/plugins/accessible/widgets/simplewidgets.h
index ae1a041dab..4701634ca0 100644
--- a/src/plugins/accessible/widgets/simplewidgets.h
+++ b/src/plugins/accessible/widgets/simplewidgets.h
@@ -43,8 +43,8 @@
#define SIMPLEWIDGETS_H
#include <QtCore/qcoreapplication.h>
-#include <QtGui/qaccessible2.h>
-#include <QtWidgets/qaccessiblewidget.h>
+#include <QtGui/private/qaccessible2_p.h>
+#include <QtWidgets/private/qaccessiblewidget_p.h>
QT_BEGIN_NAMESPACE
diff --git a/src/plugins/accessible/widgets/widgets.json b/src/plugins/accessible/widgets/widgets.json
index 69584b9bc8..094987daf5 100644
--- a/src/plugins/accessible/widgets/widgets.json
+++ b/src/plugins/accessible/widgets/widgets.json
@@ -47,5 +47,7 @@
"QScrollArea",
"QCalendarWidget",
"QDockWidget",
- "QAccessibleWidget" ]
+ "QAccessibleWidget",
+ "QDesktopScreenWidget"
+ ]
}
diff --git a/src/plugins/bearer/bearer.pro b/src/plugins/bearer/bearer.pro
index 0375500306..42f039b19b 100644
--- a/src/plugins/bearer/bearer.pro
+++ b/src/plugins/bearer/bearer.pro
@@ -9,7 +9,7 @@ linux*:qtHaveModule(dbus) {
win32:SUBDIRS += generic
blackberry:SUBDIRS += blackberry
win32:!wince*:SUBDIRS += nativewifi
-macx:contains(QT_CONFIG, corewlan):SUBDIRS += corewlan
-macx:SUBDIRS += generic
+mac:contains(QT_CONFIG, corewlan):SUBDIRS += corewlan
+mac:SUBDIRS += generic
isEmpty(SUBDIRS):SUBDIRS = generic
diff --git a/src/plugins/bearer/connman/qconnmanengine.cpp b/src/plugins/bearer/connman/qconnmanengine.cpp
index 589b0e2c24..e85949afb6 100644
--- a/src/plugins/bearer/connman/qconnmanengine.cpp
+++ b/src/plugins/bearer/connman/qconnmanengine.cpp
@@ -574,7 +574,7 @@ void QConnmanEngine::addServiceConfiguration(const QString &servicePath)
QNetworkConfigurationPrivatePointer ptr(cpPriv);
accessPointConfigurations.insert(ptr->id, ptr);
foundConfigurations.append(cpPriv);
- configInterfaces[cpPriv->id] = serv->getInterface();
+ configInterfaces[cpPriv->id] = serv->getInterface();
locker.unlock();
emit configurationAdded(ptr);
diff --git a/src/plugins/bearer/connman/qconnmanservice_linux.cpp b/src/plugins/bearer/connman/qconnmanservice_linux.cpp
index 56ae2b6e3c..e78a597433 100644
--- a/src/plugins/bearer/connman/qconnmanservice_linux.cpp
+++ b/src/plugins/bearer/connman/qconnmanservice_linux.cpp
@@ -405,7 +405,7 @@ QVariant QConnmanProfileInterface::getProperty(const QString &property)
QVariantMap map = getProperties();
if (map.contains(property)) {
var = map.value(property);
- }
+ }
return var;
}
@@ -493,7 +493,7 @@ QVariant QConnmanServiceInterface::getProperty(const QString &property)
QVariantMap map = getProperties();
if (map.contains(property)) {
var = map.value(property);
- }
+ }
return var;
}
diff --git a/src/plugins/bearer/connman/qconnmanservice_linux_p.h b/src/plugins/bearer/connman/qconnmanservice_linux_p.h
index d1524ca753..a437c6609c 100644
--- a/src/plugins/bearer/connman/qconnmanservice_linux_p.h
+++ b/src/plugins/bearer/connman/qconnmanservice_linux_p.h
@@ -134,7 +134,7 @@ public:
QString requestSession(const QString &bearerName);
void releaseSession();
-
+
// properties
QString getState();
QStringList getAvailableTechnologies();
diff --git a/src/plugins/bearer/corewlan/corewlan.pro b/src/plugins/bearer/corewlan/corewlan.pro
index db8651de6e..674af0cbbe 100644
--- a/src/plugins/bearer/corewlan/corewlan.pro
+++ b/src/plugins/bearer/corewlan/corewlan.pro
@@ -8,9 +8,7 @@ QT = core-private network-private
LIBS += -framework Foundation -framework SystemConfiguration
contains(QT_CONFIG, corewlan) {
- !contains(QMAKE_MAC_SDK, ".*MacOSX10\\.[345]\\.sdk") {
- LIBS += -framework CoreWLAN -framework Security
- }
+ LIBS += -framework CoreWLAN -framework Security
}
HEADERS += qcorewlanengine.h \
diff --git a/src/plugins/bearer/networkmanager/qnetworkmanagerservice.h b/src/plugins/bearer/networkmanager/qnetworkmanagerservice.h
index 7038dde3d9..7febe27ad2 100644
--- a/src/plugins/bearer/networkmanager/qnetworkmanagerservice.h
+++ b/src/plugins/bearer/networkmanager/qnetworkmanagerservice.h
@@ -139,26 +139,26 @@ class QNetworkManagerInterfacePrivate;
class QNetworkManagerInterface : public QObject
{
Q_OBJECT
-
+
public:
-
+
QNetworkManagerInterface(QObject *parent = 0);
~QNetworkManagerInterface();
-
+
QList <QDBusObjectPath> getDevices() const;
void activateConnection(const QString &serviceName, QDBusObjectPath connection, QDBusObjectPath device, QDBusObjectPath specificObject);
void deactivateConnection(QDBusObjectPath connectionPath) const;
-
+
QDBusObjectPath path() const;
QDBusInterface *connectionInterface() const;
-
+
bool wirelessEnabled() const;
bool wirelessHardwareEnabled() const;
QList <QDBusObjectPath> activeConnections() const;
quint32 state();
bool setConnections();
bool isValid();
-
+
Q_SIGNALS:
void deviceAdded(QDBusObjectPath);
void deviceRemoved(QDBusObjectPath);
@@ -176,9 +176,9 @@ class QNetworkManagerInterfaceAccessPointPrivate;
class QNetworkManagerInterfaceAccessPoint : public QObject
{
Q_OBJECT
-
+
public:
-
+
enum DeviceState {
Unknown = 0,
Unmanaged,
@@ -191,14 +191,14 @@ public:
Activated,
Failed
};
-
+
enum ApFlag {
ApNone = 0x0,
Privacy = 0x1
};
-
+
Q_DECLARE_FLAGS(ApFlags, ApFlag);
-
+
enum ApSecurityFlag {
ApSecurityNone = 0x0,
PairWep40 = 0x1,
@@ -212,9 +212,9 @@ public:
KeyPsk = 0x100,
Key8021x = 0x200
};
-
+
Q_DECLARE_FLAGS(ApSecurityFlags, ApSecurityFlag);
-
+
explicit QNetworkManagerInterfaceAccessPoint(const QString &dbusPathName, QObject *parent = 0);
~QNetworkManagerInterfaceAccessPoint();
@@ -231,7 +231,7 @@ public:
quint32 strength() const;
bool setConnections();
bool isValid();
-
+
Q_SIGNALS:
void propertiesChanged(QMap <QString,QVariant>);
void propertiesChanged( const QString &, QMap<QString,QVariant>);
@@ -245,23 +245,23 @@ class QNetworkManagerInterfaceDevicePrivate;
class QNetworkManagerInterfaceDevice : public QObject
{
Q_OBJECT
-
+
public:
-
+
explicit QNetworkManagerInterfaceDevice(const QString &deviceObjectPath, QObject *parent = 0);
~QNetworkManagerInterfaceDevice();
-
+
QString udi() const;
QString networkInterface() const;
QDBusInterface *connectionInterface() const;
quint32 ip4Address() const;
quint32 state() const;
quint32 deviceType() const;
-
+
QDBusObjectPath ip4config() const;
bool setConnections();
bool isValid();
-
+
Q_SIGNALS:
void stateChanged(const QString &, quint32);
@@ -274,20 +274,20 @@ class QNetworkManagerInterfaceDeviceWiredPrivate;
class QNetworkManagerInterfaceDeviceWired : public QObject
{
Q_OBJECT
-
+
public:
-
+
explicit QNetworkManagerInterfaceDeviceWired(const QString &ifaceDevicePath,
QObject *parent = 0);
~QNetworkManagerInterfaceDeviceWired();
-
+
QDBusInterface *connectionInterface() const;
QString hwAddress() const;
quint32 speed() const;
bool carrier() const;
bool setConnections();
bool isValid();
-
+
Q_SIGNALS:
void propertiesChanged( const QString &, QMap<QString,QVariant>);
private:
@@ -299,9 +299,9 @@ class QNetworkManagerInterfaceDeviceWirelessPrivate;
class QNetworkManagerInterfaceDeviceWireless : public QObject
{
Q_OBJECT
-
+
public:
-
+
enum DeviceCapability {
None = 0x0,
Wep40 = 0x1,
@@ -311,11 +311,11 @@ public:
Wpa = 0x10,
Rsn = 0x20
};
-
+
explicit QNetworkManagerInterfaceDeviceWireless(const QString &ifaceDevicePath,
QObject *parent = 0);
~QNetworkManagerInterfaceDeviceWireless();
-
+
QDBusObjectPath path() const;
QList <QDBusObjectPath> getAccessPoints();
QDBusInterface *connectionInterface() const;
@@ -327,7 +327,7 @@ public:
quint32 wirelessCapabilities() const;
bool setConnections();
bool isValid();
-
+
Q_SIGNALS:
void propertiesChanged( const QString &, QMap<QString,QVariant>);
void accessPointAdded(const QString &,QDBusObjectPath);
@@ -341,12 +341,12 @@ class QNetworkManagerSettingsPrivate;
class QNetworkManagerSettings : public QObject
{
Q_OBJECT
-
+
public:
-
+
explicit QNetworkManagerSettings(const QString &settingsService, QObject *parent = 0);
~QNetworkManagerSettings();
-
+
QDBusInterface *connectionInterface() const;
QList <QDBusObjectPath> listConnections();
bool setConnections();
@@ -362,12 +362,12 @@ class QNetworkManagerSettingsConnectionPrivate;
class QNetworkManagerSettingsConnection : public QObject
{
Q_OBJECT
-
+
public:
-
+
QNetworkManagerSettingsConnection(const QString &settingsService, const QString &connectionObjectPath, QObject *parent = 0);
~QNetworkManagerSettingsConnection();
-
+
QDBusInterface *connectionInterface() const;
QNmSettingsMap getSettings();
bool setConnections();
@@ -382,7 +382,7 @@ public:
bool isValid();
Q_SIGNALS:
-
+
void updated(const QNmSettingsMap &settings);
void removed(const QString &path);
@@ -395,18 +395,18 @@ class QNetworkManagerConnectionActivePrivate;
class QNetworkManagerConnectionActive : public QObject
{
Q_OBJECT
-
+
public:
-
+
enum ActiveConnectionState {
Unknown = 0,
Activating = 1,
Activated = 2
};
-
+
explicit QNetworkManagerConnectionActive(const QString &dbusPathName, QObject *parent = 0);
~ QNetworkManagerConnectionActive();
-
+
QDBusInterface *connectionInterface() const;
QString serviceName() const;
QDBusObjectPath connection() const;
@@ -417,7 +417,7 @@ public:
bool setConnections();
bool isValid();
-
+
Q_SIGNALS:
void propertiesChanged(QList<QDBusObjectPath>);
void propertiesChanged( const QString &, QMap<QString,QVariant>);
@@ -430,7 +430,7 @@ class QNetworkManagerIp4ConfigPrivate;
class QNetworkManagerIp4Config : public QObject
{
Q_OBJECT
-
+
public:
explicit QNetworkManagerIp4Config(const QString &dbusPathName, QObject *parent = 0);
~QNetworkManagerIp4Config();
@@ -439,7 +439,7 @@ public:
bool isValid();
private:
- QNetworkManagerIp4ConfigPrivate *d;
+ QNetworkManagerIp4ConfigPrivate *d;
};
QT_END_NAMESPACE
diff --git a/src/plugins/bearer/qnetworksession_impl.h b/src/plugins/bearer/qnetworksession_impl.h
index 12893108dc..23828c885c 100644
--- a/src/plugins/bearer/qnetworksession_impl.h
+++ b/src/plugins/bearer/qnetworksession_impl.h
@@ -77,7 +77,7 @@ public:
//called by QNetworkSession constructor and ensures
//that the state is immediately updated (w/o actually opening
- //a session). Also this function should take care of
+ //a session). Also this function should take care of
//notification hooks to discover future state changes.
void syncStateWithInterface();
diff --git a/src/plugins/generic/meego/qmeegointegration.h b/src/plugins/generic/meego/qmeegointegration.h
index 88e2aae721..998bbbf8d3 100644
--- a/src/plugins/generic/meego/qmeegointegration.h
+++ b/src/plugins/generic/meego/qmeegointegration.h
@@ -47,8 +47,6 @@
#include "contextkitproperty.h"
-QT_BEGIN_HEADER
-
QT_BEGIN_NAMESPACE
class QMeeGoIntegration : public QObject
@@ -67,6 +65,4 @@ private:
QT_END_NAMESPACE
-QT_END_HEADER
-
#endif // QMEEGOINTEGRATION_H
diff --git a/src/plugins/generic/tslib/qtslib.h b/src/plugins/generic/tslib/qtslib.h
index 0c5c74f672..9342fdfea5 100644
--- a/src/plugins/generic/tslib/qtslib.h
+++ b/src/plugins/generic/tslib/qtslib.h
@@ -45,8 +45,6 @@
#include <qobject.h>
//#include <Qt>
-QT_BEGIN_HEADER
-
QT_BEGIN_NAMESPACE
class QSocketNotifier;
@@ -72,6 +70,4 @@ private:
QT_END_NAMESPACE
-QT_END_HEADER
-
#endif // QTSLIB_H
diff --git a/src/plugins/imageformats/gif/gif.json b/src/plugins/imageformats/gif/gif.json
index b599b40ffe..1d6cb126c4 100644
--- a/src/plugins/imageformats/gif/gif.json
+++ b/src/plugins/imageformats/gif/gif.json
@@ -1,3 +1,4 @@
{
- "Keys": [ "gif" ]
+ "Keys": [ "gif" ],
+ "MimeTypes": [ "image/gif" ]
}
diff --git a/src/plugins/imageformats/ico/ico.json b/src/plugins/imageformats/ico/ico.json
index d22cb739a1..bd46e07e54 100644
--- a/src/plugins/imageformats/ico/ico.json
+++ b/src/plugins/imageformats/ico/ico.json
@@ -1,3 +1,4 @@
{
- "Keys": [ "ico" ]
+ "Keys": [ "ico" ],
+ "MimeTypes": [ "image/vnd.microsoft.icon" ]
}
diff --git a/src/plugins/imageformats/ico/qicohandler.cpp b/src/plugins/imageformats/ico/qicohandler.cpp
index b1ef823068..a45c3875bc 100644
--- a/src/plugins/imageformats/ico/qicohandler.cpp
+++ b/src/plugins/imageformats/ico/qicohandler.cpp
@@ -39,7 +39,7 @@
**
****************************************************************************/
-/*!
+/*!
\class QtIcoHandler
\since 4.4
\brief The QtIcoHandler class provides support for the ICO image format.
diff --git a/src/plugins/imageformats/ico/qicohandler.h b/src/plugins/imageformats/ico/qicohandler.h
index c0439b9d11..65c0f5cf59 100644
--- a/src/plugins/imageformats/ico/qicohandler.h
+++ b/src/plugins/imageformats/ico/qicohandler.h
@@ -57,13 +57,13 @@ public:
bool write(const QImage &image);
QByteArray name() const;
-
+
int imageCount() const;
bool jumpToImage(int imageNumber);
bool jumpToNextImage();
-
+
static bool canRead(QIODevice *device);
-
+
bool supportsOption(ImageOption option) const;
QVariant option(ImageOption option) const;
diff --git a/src/plugins/imageformats/jpeg/jpeg.json b/src/plugins/imageformats/jpeg/jpeg.json
index 132c642c05..5e26a97206 100644
--- a/src/plugins/imageformats/jpeg/jpeg.json
+++ b/src/plugins/imageformats/jpeg/jpeg.json
@@ -1,3 +1,4 @@
{
- "Keys": [ "jpg", "jpeg" ]
+ "Keys": [ "jpg", "jpeg" ],
+ "MimeTypes": [ "image/jpeg", "image/jpeg" ]
}
diff --git a/src/plugins/platforminputcontexts/ibus/qibusplatforminputcontext.cpp b/src/plugins/platforminputcontexts/ibus/qibusplatforminputcontext.cpp
index f4e7666a85..53e9b171d5 100644
--- a/src/plugins/platforminputcontexts/ibus/qibusplatforminputcontext.cpp
+++ b/src/plugins/platforminputcontexts/ibus/qibusplatforminputcontext.cpp
@@ -226,26 +226,6 @@ void QIBusPlatformInputContext::updatePreeditText(const QDBusVariant &text, uint
}
-/* Kernel keycode -> X keycode table */
-static const unsigned int keycode_table[256] = {
- 0, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23,
- 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39,
- 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55,
- 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71,
- 72, 73, 74, 75, 76, 77, 76, 79, 80, 81, 82, 83, 84, 85, 86, 87,
- 88, 89, 90, 91, 111, 221, 94, 95, 96, 211, 128, 127, 129, 208, 131, 126,
- 108, 109, 112, 111, 113, 181, 97, 98, 99, 100, 102, 103, 104, 105, 106, 107,
- 239, 160, 174, 176, 222, 157, 123, 110, 139, 134, 209, 210, 133, 115, 116, 117,
- 232, 133, 134, 135, 140, 248, 191, 192, 122, 188, 245, 158, 161, 193, 223, 227,
- 198, 199, 200, 147, 159, 151, 178, 201, 146, 203, 166, 236, 230, 235, 234, 233,
- 163, 204, 253, 153, 162, 144, 164, 177, 152, 190, 208, 129, 130, 231, 209, 210,
- 136, 220, 143, 246, 251, 137, 138, 182, 183, 184, 93, 184, 247, 132, 170, 219,
- 249, 205, 207, 149, 150, 154, 155, 167, 168, 169, 171, 172, 173, 165, 175, 179,
- 180, 0, 185, 186, 187, 118, 119, 120, 121, 229, 194, 195, 196, 197, 148, 202,
- 101, 212, 237, 214, 215, 216, 217, 218, 228, 142, 213, 240, 241, 242, 243, 244,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
-};
-
bool
QIBusPlatformInputContext::x11FilterEvent(uint keyval, uint keycode, uint state, bool press)
{
diff --git a/src/plugins/platforminputcontexts/platforminputcontexts.pro b/src/plugins/platforminputcontexts/platforminputcontexts.pro
index c8449e7e44..7b3c6e9c36 100644
--- a/src/plugins/platforminputcontexts/platforminputcontexts.pro
+++ b/src/plugins/platforminputcontexts/platforminputcontexts.pro
@@ -1,4 +1,4 @@
TEMPLATE = subdirs
qtHaveModule(dbus) {
-!macx:!win32:SUBDIRS += ibus maliit
+!mac:!win32:SUBDIRS += ibus maliit
}
diff --git a/src/plugins/platforms/android/android.pro b/src/plugins/platforms/android/android.pro
new file mode 100644
index 0000000000..aa5ab4ddbd
--- /dev/null
+++ b/src/plugins/platforms/android/android.pro
@@ -0,0 +1,3 @@
+TEMPLATE = subdirs
+
+SUBDIRS += raster opengl
diff --git a/src/plugins/platforms/android/opengl/opengl.pro b/src/plugins/platforms/android/opengl/opengl.pro
new file mode 100644
index 0000000000..301c8e6e4c
--- /dev/null
+++ b/src/plugins/platforms/android/opengl/opengl.pro
@@ -0,0 +1,30 @@
+TARGET = qtforandroidGL
+
+PLUGIN_TYPE = platforms
+load(qt_plugin)
+
+# STATICPLUGIN needed because there's a Q_IMPORT_PLUGIN in androidjnimain.cpp
+# Yes, the plugin imports itself statically
+DEFINES += QT_STATICPLUGIN ANDROID_PLUGIN_OPENGL
+
+!equals(ANDROID_PLATFORM, android-9) {
+ INCLUDEPATH += $$NDK_ROOT/platforms/android-9/arch-$$ANDROID_ARCHITECTURE/usr/include
+ LIBS += -L$$NDK_ROOT/platforms/android-9/arch-$$ANDROID_ARCHITECTURE/usr/lib -ljnigraphics -landroid
+} else {
+ LIBS += -ljnigraphics -landroid
+}
+
+EGLFS_PLATFORM_HOOKS_SOURCES = $$PWD/../src/opengl/qeglfshooks_android.cpp
+
+INCLUDEPATH += $$PWD/../src/opengl/
+
+HEADERS += \
+ $$PWD/../src/opengl/qandroidopenglcontext.h \
+ $$PWD/../src/opengl/qandroidopenglplatformwindow.h
+
+SOURCES += \
+ $$PWD/../src/opengl/qandroidopenglcontext.cpp \
+ $$PWD/../src/opengl/qandroidopenglplatformwindow.cpp
+
+include($$PWD/../../eglfs/eglfs.pri)
+include($$PWD/../src/src.pri)
diff --git a/src/plugins/platforms/android/raster/raster.pro b/src/plugins/platforms/android/raster/raster.pro
new file mode 100644
index 0000000000..53d8ee7a2b
--- /dev/null
+++ b/src/plugins/platforms/android/raster/raster.pro
@@ -0,0 +1,19 @@
+TARGET = qtforandroid
+
+PLUGIN_TYPE = platforms
+
+# STATICPLUGIN needed because there's a Q_IMPORT_PLUGIN in androidjnimain.cpp
+# Yes, the plugin imports itself statically
+DEFINES += QT_STATICPLUGIN
+
+load(qt_plugin)
+
+!contains(ANDROID_PLATFORM, android-9) {
+ INCLUDEPATH += $$NDK_ROOT/platforms/android-9/arch-$$ANDROID_ARCHITECTURE/usr/include
+ LIBS += -L$$NDK_ROOT/platforms/android-9/arch-$$ANDROID_ARCHITECTURE/usr/lib -ljnigraphics -landroid
+} else {
+ LIBS += -ljnigraphics -landroid
+}
+
+include($$PWD/../src/src.pri)
+include($$PWD/../src/raster/raster.pri)
diff --git a/src/plugins/platforms/android/src/android.json b/src/plugins/platforms/android/src/android.json
new file mode 100644
index 0000000000..6843bd3301
--- /dev/null
+++ b/src/plugins/platforms/android/src/android.json
@@ -0,0 +1,3 @@
+{
+ "Keys": [ "android" ]
+}
diff --git a/src/plugins/platforms/android/src/androidjniclipboard.cpp b/src/plugins/platforms/android/src/androidjniclipboard.cpp
new file mode 100644
index 0000000000..05270ac374
--- /dev/null
+++ b/src/plugins/platforms/android/src/androidjniclipboard.cpp
@@ -0,0 +1,120 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 BogDan Vatra <bogdan@kde.org>
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the plugins of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Digia. For licensing terms and
+** conditions see http://qt.digia.com/licensing. For further information
+** use the contact form at http://qt.digia.com/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Digia gives you certain additional
+** rights. These rights are described in the Digia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "androidjniclipboard.h"
+#include "androidjnimain.h"
+
+using namespace QtAndroid;
+namespace QtAndroidClipboard
+{
+ // Clipboard support
+ static jmethodID m_registerClipboardManagerMethodID = 0;
+ static jmethodID m_setClipboardTextMethodID = 0;
+ static jmethodID m_hasClipboardTextMethodID = 0;
+ static jmethodID m_getClipboardTextMethodID = 0;
+ // Clipboard support
+
+ void setClipboardListener(QAndroidPlatformClipboard *listener)
+ {
+ Q_UNUSED(listener);
+
+ AttachedJNIEnv env;
+ if (!env.jniEnv)
+ return;
+
+ env.jniEnv->CallStaticVoidMethod(applicationClass(), m_registerClipboardManagerMethodID);
+ }
+
+ void setClipboardText(const QString &text)
+ {
+ AttachedJNIEnv env;
+ if (!env.jniEnv)
+ return;
+
+ jstring jtext = env.jniEnv->NewString(reinterpret_cast<const jchar *>(text.data()),
+ text.length());
+ env.jniEnv->CallStaticVoidMethod(applicationClass(), m_setClipboardTextMethodID, jtext);
+ env.jniEnv->DeleteLocalRef(jtext);
+ }
+
+ bool hasClipboardText()
+ {
+ AttachedJNIEnv env;
+ if (!env.jniEnv)
+ return false;
+
+ return env.jniEnv->CallStaticBooleanMethod(applicationClass(), m_hasClipboardTextMethodID);
+ }
+
+ QString clipboardText()
+ {
+ AttachedJNIEnv env;
+ if (!env.jniEnv)
+ return QString();
+
+ jstring text = reinterpret_cast<jstring>(env.jniEnv->CallStaticObjectMethod(applicationClass(),
+ m_getClipboardTextMethodID));
+ const jchar *jstr = env.jniEnv->GetStringChars(text, 0);
+ QString str(reinterpret_cast<const QChar *>(jstr), env.jniEnv->GetStringLength(text));
+ env.jniEnv->ReleaseStringChars(text, jstr);
+ return str;
+ }
+
+
+#define GET_AND_CHECK_STATIC_METHOD(VAR, CLASS, METHOD_NAME, METHOD_SIGNATURE) \
+ VAR = env->GetStaticMethodID(CLASS, METHOD_NAME, METHOD_SIGNATURE); \
+ if (!VAR) { \
+ __android_log_print(ANDROID_LOG_FATAL, qtTagText(), methodErrorMsgFmt(), METHOD_NAME, METHOD_SIGNATURE); \
+ return false; \
+ }
+
+ bool registerNatives(JNIEnv *env)
+ {
+ jclass appClass = QtAndroid::applicationClass();
+
+ GET_AND_CHECK_STATIC_METHOD(m_registerClipboardManagerMethodID, appClass, "registerClipboardManager", "()V");
+ GET_AND_CHECK_STATIC_METHOD(m_setClipboardTextMethodID, appClass, "setClipboardText", "(Ljava/lang/String;)V");
+ GET_AND_CHECK_STATIC_METHOD(m_hasClipboardTextMethodID, appClass, "hasClipboardText", "()Z");
+ GET_AND_CHECK_STATIC_METHOD(m_getClipboardTextMethodID, appClass, "getClipboardText", "()Ljava/lang/String;");
+
+ return true;
+ }
+}
diff --git a/src/plugins/platforms/android/src/androidjniclipboard.h b/src/plugins/platforms/android/src/androidjniclipboard.h
new file mode 100644
index 0000000000..15cd93202e
--- /dev/null
+++ b/src/plugins/platforms/android/src/androidjniclipboard.h
@@ -0,0 +1,61 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 BogDan Vatra <bogdan@kde.org>
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the plugins of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Digia. For licensing terms and
+** conditions see http://qt.digia.com/licensing. For further information
+** use the contact form at http://qt.digia.com/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Digia gives you certain additional
+** rights. These rights are described in the Digia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef ANDROIDJNICLIPBOARD_H
+#define ANDROIDJNICLIPBOARD_H
+
+#include <jni.h>
+#include <QString>
+
+class QAndroidPlatformClipboard;
+namespace QtAndroidClipboard
+{
+ // Clipboard support
+ void setClipboardListener(QAndroidPlatformClipboard *listener);
+ void setClipboardText(const QString &text);
+ bool hasClipboardText();
+ QString clipboardText();
+ // Clipboard support
+
+ bool registerNatives(JNIEnv *env);
+}
+
+#endif // ANDROIDJNICLIPBOARD_H
diff --git a/src/plugins/platforms/android/src/androidjniinput.cpp b/src/plugins/platforms/android/src/androidjniinput.cpp
new file mode 100644
index 0000000000..da6156a330
--- /dev/null
+++ b/src/plugins/platforms/android/src/androidjniinput.cpp
@@ -0,0 +1,497 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 BogDan Vatra <bogdan@kde.org>
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the plugins of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Digia. For licensing terms and
+** conditions see http://qt.digia.com/licensing. For further information
+** use the contact form at http://qt.digia.com/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Digia gives you certain additional
+** rights. These rights are described in the Digia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "androidjniinput.h"
+#include "androidjnimain.h"
+#include "qandroidplatformintegration.h"
+
+#include <qpa/qwindowsysteminterface.h>
+#include <QTouchEvent>
+#include <QPointer>
+
+using namespace QtAndroid;
+
+namespace QtAndroidInput
+{
+ static jmethodID m_showSoftwareKeyboardMethodID = 0;
+ static jmethodID m_resetSoftwareKeyboardMethodID = 0;
+ static jmethodID m_hideSoftwareKeyboardMethodID = 0;
+ static jmethodID m_isSoftwareKeyboardVisibleMethodID = 0;
+ static jmethodID m_updateSelectionMethodID = 0;
+
+ static bool m_ignoreMouseEvents = false;
+
+ static QList<QWindowSystemInterface::TouchPoint> m_touchPoints;
+
+ static QPointer<QWindow> m_mouseGrabber;
+
+ void updateSelection(int selStart, int selEnd, int candidatesStart, int candidatesEnd)
+ {
+ AttachedJNIEnv env;
+ if (!env.jniEnv)
+ return;
+
+ env.jniEnv->CallStaticVoidMethod(applicationClass(), m_updateSelectionMethodID,
+ selStart, selEnd, candidatesStart, candidatesEnd);
+ }
+
+ void showSoftwareKeyboard(int left, int top, int width, int height, int inputHints)
+ {
+ AttachedJNIEnv env;
+ if (!env.jniEnv)
+ return;
+
+ env.jniEnv->CallStaticVoidMethod(applicationClass(),
+ m_showSoftwareKeyboardMethodID,
+ left,
+ top,
+ width,
+ height,
+ inputHints);
+ }
+
+ void resetSoftwareKeyboard()
+ {
+ AttachedJNIEnv env;
+ if (!env.jniEnv)
+ return;
+
+ env.jniEnv->CallStaticVoidMethod(applicationClass(), m_resetSoftwareKeyboardMethodID);
+ }
+
+ void hideSoftwareKeyboard()
+ {
+ AttachedJNIEnv env;
+ if (!env.jniEnv)
+ return;
+
+ env.jniEnv->CallStaticVoidMethod(applicationClass(), m_hideSoftwareKeyboardMethodID);
+ }
+
+ bool isSoftwareKeyboardVisible()
+ {
+ AttachedJNIEnv env;
+ if (!env.jniEnv)
+ return false;
+
+ return env.jniEnv->CallStaticBooleanMethod(applicationClass(), m_isSoftwareKeyboardVisibleMethodID);
+ }
+
+
+ static void mouseDown(JNIEnv */*env*/, jobject /*thiz*/, jint /*winId*/, jint x, jint y)
+ {
+ if (m_ignoreMouseEvents)
+ return;
+
+ QPoint globalPos(x,y);
+ QWindow *tlw = topLevelWindowAt(globalPos);
+ m_mouseGrabber = tlw;
+ QPoint localPos = tlw ? (globalPos - tlw->position()) : globalPos;
+ QWindowSystemInterface::handleMouseEvent(tlw,
+ localPos,
+ globalPos,
+ Qt::MouseButtons(Qt::LeftButton));
+ }
+
+ static void mouseUp(JNIEnv */*env*/, jobject /*thiz*/, jint /*winId*/, jint x, jint y)
+ {
+ QPoint globalPos(x,y);
+ QWindow *tlw = m_mouseGrabber.data();
+ if (!tlw)
+ tlw = topLevelWindowAt(globalPos);
+ QPoint localPos = tlw ? (globalPos -tlw->position()) : globalPos;
+ QWindowSystemInterface::handleMouseEvent(tlw, localPos, globalPos
+ , Qt::MouseButtons(Qt::NoButton));
+ m_ignoreMouseEvents = false;
+ m_mouseGrabber = 0;
+ }
+
+ static void mouseMove(JNIEnv */*env*/, jobject /*thiz*/, jint /*winId*/, jint x, jint y)
+ {
+
+ if (m_ignoreMouseEvents)
+ return;
+
+ QPoint globalPos(x,y);
+ QWindow *tlw = m_mouseGrabber.data();
+ if (!tlw)
+ tlw = topLevelWindowAt(globalPos);
+ QPoint localPos = tlw ? (globalPos-tlw->position()) : globalPos;
+ QWindowSystemInterface::handleMouseEvent(tlw,
+ localPos,
+ globalPos,
+ Qt::MouseButtons(Qt::LeftButton));
+ }
+
+ static void longPress(JNIEnv */*env*/, jobject /*thiz*/, jint /*winId*/, jint x, jint y)
+ {
+ m_ignoreMouseEvents = true;
+ QPoint globalPos(x,y);
+ QWindow *tlw = topLevelWindowAt(globalPos);
+ QPoint localPos = tlw ? (globalPos-tlw->position()) : globalPos;
+
+ // Release left button
+ QWindowSystemInterface::handleMouseEvent(tlw,
+ localPos,
+ globalPos,
+ Qt::MouseButtons(Qt::NoButton));
+
+ // Press right button
+ QWindowSystemInterface::handleMouseEvent(tlw,
+ localPos,
+ globalPos,
+ Qt::MouseButtons(Qt::RightButton));
+ }
+
+ static void touchBegin(JNIEnv */*env*/, jobject /*thiz*/, jint /*winId*/)
+ {
+ m_touchPoints.clear();
+ }
+
+ static void touchAdd(JNIEnv */*env*/, jobject /*thiz*/, jint /*winId*/, jint id, jint action, jboolean /*primary*/, jint x, jint y, jfloat size, jfloat pressure)
+ {
+ Qt::TouchPointState state = Qt::TouchPointStationary;
+ switch (action) {
+ case 0:
+ state = Qt::TouchPointPressed;
+ break;
+ case 1:
+ state = Qt::TouchPointMoved;
+ break;
+ case 2:
+ state = Qt::TouchPointStationary;
+ break;
+ case 3:
+ state = Qt::TouchPointReleased;
+ break;
+ }
+
+ const int dw = desktopWidthPixels();
+ const int dh = desktopHeightPixels();
+ QWindowSystemInterface::TouchPoint touchPoint;
+ touchPoint.id = id;
+ touchPoint.pressure = pressure;
+ touchPoint.normalPosition = QPointF(double(x / dw), double(y / dh));
+ touchPoint.state = state;
+ touchPoint.area = QRectF(x - double(dw*size) / 2.0,
+ y - double(dh*size) / 2.0,
+ double(dw*size),
+ double(dh*size));
+ m_touchPoints.push_back(touchPoint);
+ }
+
+ static void touchEnd(JNIEnv */*env*/, jobject /*thiz*/, jint /*winId*/, jint action)
+ {
+ if (m_touchPoints.isEmpty())
+ return;
+
+ QEvent::Type eventType = QEvent::None;
+ switch (action) {
+ case 0:
+ eventType = QEvent::TouchBegin;
+ break;
+ case 1:
+ eventType = QEvent::TouchUpdate;
+ break;
+ case 2:
+ eventType = QEvent::TouchEnd;
+ break;
+ }
+
+ QAndroidPlatformIntegration *platformIntegration = QtAndroid::androidPlatformIntegration();
+ QTouchDevice *touchDevice = platformIntegration->touchDevice();
+ if (touchDevice == 0) {
+ touchDevice = new QTouchDevice;
+ touchDevice->setType(QTouchDevice::TouchScreen);
+ touchDevice->setCapabilities(QTouchDevice::Position
+ | QTouchDevice::Area
+ | QTouchDevice::Pressure
+ | QTouchDevice::NormalizedPosition);
+ QWindowSystemInterface::registerTouchDevice(touchDevice);
+ platformIntegration->setTouchDevice(touchDevice);
+ }
+
+ QWindow *window = QtAndroid::topLevelWindowAt(m_touchPoints.at(0).area.center().toPoint());
+ QWindowSystemInterface::handleTouchEvent(window, touchDevice, m_touchPoints);
+ }
+
+ static int mapAndroidKey(int key)
+ {
+ // 0--9 0x00000007 -- 0x00000010
+ if (key >= 0x00000007 && key <= 0x00000010)
+ return Qt::Key_0 + key - 0x00000007;
+
+ // A--Z 0x0000001d -- 0x00000036
+ if (key >= 0x0000001d && key <= 0x00000036)
+ return Qt::Key_A + key - 0x0000001d;
+
+ switch (key) {
+ case 0x00000039:
+ case 0x0000003a:
+ return Qt::Key_Alt;
+
+ case 0x0000004b:
+ return Qt::Key_Apostrophe;
+
+ case 0x00000004: // KEYCODE_BACK
+ return Qt::Key_Back;
+
+ case 0x00000049:
+ return Qt::Key_Backslash;
+
+ case 0x00000005:
+ return Qt::Key_Call;
+
+ case 0x0000001b:
+ return Qt::Key_WebCam;
+
+ case 0x0000001c:
+ return Qt::Key_Clear;
+
+ case 0x00000037:
+ return Qt::Key_Comma;
+
+ case 0x00000043:
+ return Qt::Key_Backspace;
+
+ case 0x00000017: // KEYCODE_DPAD_CENTER
+ return Qt::Key_Enter;
+
+ case 0x00000014: // KEYCODE_DPAD_DOWN
+ return Qt::Key_Down;
+
+ case 0x00000015: //KEYCODE_DPAD_LEFT
+ return Qt::Key_Left;
+
+ case 0x00000016: //KEYCODE_DPAD_RIGHT
+ return Qt::Key_Right;
+
+ case 0x00000013: //KEYCODE_DPAD_UP
+ return Qt::Key_Up;
+
+ case 0x00000006: //KEYCODE_ENDCALL
+ return Qt::Key_Hangup;
+
+ case 0x00000042:
+ return Qt::Key_Return;
+
+ case 0x00000041: //KEYCODE_ENVELOPE
+ return Qt::Key_LaunchMail;
+
+ case 0x00000046:
+ return Qt::Key_Equal;
+
+ case 0x00000040:
+ return Qt::Key_Explorer;
+
+ case 0x00000003:
+ return Qt::Key_Home;
+
+ case 0x00000047:
+ return Qt::Key_BracketLeft;
+
+ case 0x0000005a: // KEYCODE_MEDIA_FAST_FORWARD
+ return Qt::Key_Forward;
+
+ case 0x00000057:
+ return Qt::Key_MediaNext;
+
+ case 0x00000055:
+ return Qt::Key_MediaPlay;
+
+ case 0x00000058:
+ return Qt::Key_MediaPrevious;
+
+ case 0x00000059:
+ return Qt::Key_AudioRewind;
+
+ case 0x00000056:
+ return Qt::Key_MediaStop;
+
+ case 0x00000052: //KEYCODE_MENU
+ return Qt::Key_Menu;
+
+ case 0x00000045:
+ return Qt::Key_Minus;
+
+ case 0x0000005b:
+ return Qt::Key_VolumeMute;
+
+ case 0x0000004e:
+ return Qt::Key_NumLock;
+
+ case 0x00000038:
+ return Qt::Key_Period;
+
+ case 0x00000051:
+ return Qt::Key_Plus;
+
+ case 0x0000001a:
+ return Qt::Key_PowerOff;
+
+ case 0x00000048:
+ return Qt::Key_BracketRight;
+
+ case 0x00000054:
+ return Qt::Key_Search;
+
+ case 0x0000004a:
+ return Qt::Key_Semicolon;
+
+ case 0x0000003b:
+ case 0x0000003c:
+ return Qt::Key_Shift;
+
+ case 0x0000004c:
+ return Qt::Key_Slash;
+
+ case 0x00000001:
+ return Qt::Key_Left;
+
+ case 0x00000002:
+ return Qt::Key_Right;
+
+ case 0x0000003e:
+ return Qt::Key_Space;
+
+ case 0x0000003f: // KEYCODE_SYM
+ return Qt::Key_Meta;
+
+ case 0x0000003d:
+ return Qt::Key_Tab;
+
+ case 0x00000019:
+ return Qt::Key_VolumeDown;
+
+ case 0x00000018:
+ return Qt::Key_VolumeUp;
+
+ case 0x00000000: // KEYCODE_UNKNOWN
+ case 0x00000011: // KEYCODE_STAR ?!?!?
+ case 0x00000012: // KEYCODE_POUND ?!?!?
+ case 0x00000053: // KEYCODE_NOTIFICATION ?!?!?
+ case 0x0000004f: // KEYCODE_HEADSETHOOK ?!?!?
+ case 0x00000044: // KEYCODE_GRAVE ?!?!?
+ case 0x00000050: // KEYCODE_FOCUS ?!?!?
+ return Qt::Key_Any;
+
+ default:
+ return 0;
+ }
+ }
+
+ static void keyDown(JNIEnv */*env*/, jobject /*thiz*/, jint key, jint unicode, jint modifier)
+ {
+ Qt::KeyboardModifiers modifiers;
+ if (modifier & 1)
+ modifiers |= Qt::ShiftModifier;
+
+ if (modifier & 2)
+ modifiers |= Qt::AltModifier;
+
+ if (modifier & 4)
+ modifiers |= Qt::MetaModifier;
+
+ QWindowSystemInterface::handleKeyEvent(0,
+ QEvent::KeyPress,
+ mapAndroidKey(key),
+ modifiers,
+ QChar(unicode),
+ true);
+ }
+
+ static void keyUp(JNIEnv */*env*/, jobject /*thiz*/, jint key, jint unicode, jint modifier)
+ {
+ Qt::KeyboardModifiers modifiers;
+ if (modifier & 1)
+ modifiers |= Qt::ShiftModifier;
+
+ if (modifier & 2)
+ modifiers |= Qt::AltModifier;
+
+ if (modifier & 4)
+ modifiers |= Qt::MetaModifier;
+
+ QWindowSystemInterface::handleKeyEvent(0,
+ QEvent::KeyRelease,
+ mapAndroidKey(key),
+ modifiers,
+ QChar(unicode),
+ true);
+ }
+
+
+ static JNINativeMethod methods[] = {
+ {"touchBegin","(I)V",(void*)touchBegin},
+ {"touchAdd","(IIIZIIFF)V",(void*)touchAdd},
+ {"touchEnd","(II)V",(void*)touchEnd},
+ {"mouseDown", "(III)V", (void *)mouseDown},
+ {"mouseUp", "(III)V", (void *)mouseUp},
+ {"mouseMove", "(III)V", (void *)mouseMove},
+ {"longPress", "(III)V", (void *)longPress},
+ {"keyDown", "(III)V", (void *)keyDown},
+ {"keyUp", "(III)V", (void *)keyUp}
+ };
+
+#define GET_AND_CHECK_STATIC_METHOD(VAR, CLASS, METHOD_NAME, METHOD_SIGNATURE) \
+ VAR = env->GetStaticMethodID(CLASS, METHOD_NAME, METHOD_SIGNATURE); \
+ if (!VAR) { \
+ __android_log_print(ANDROID_LOG_FATAL, qtTagText(), methodErrorMsgFmt(), METHOD_NAME, METHOD_SIGNATURE); \
+ return false; \
+ }
+
+ bool registerNatives(JNIEnv *env)
+ {
+ jclass appClass = QtAndroid::applicationClass();
+
+ if (env->RegisterNatives(appClass, methods, sizeof(methods) / sizeof(methods[0])) < 0) {
+ __android_log_print(ANDROID_LOG_FATAL,"Qt", "RegisterNatives failed");
+ return false;
+ }
+
+ GET_AND_CHECK_STATIC_METHOD(m_showSoftwareKeyboardMethodID, appClass, "showSoftwareKeyboard", "(IIIII)V");
+ GET_AND_CHECK_STATIC_METHOD(m_resetSoftwareKeyboardMethodID, appClass, "resetSoftwareKeyboard", "()V");
+ GET_AND_CHECK_STATIC_METHOD(m_hideSoftwareKeyboardMethodID, appClass, "hideSoftwareKeyboard", "()V");
+ GET_AND_CHECK_STATIC_METHOD(m_isSoftwareKeyboardVisibleMethodID, appClass, "isSoftwareKeyboardVisible", "()Z");
+ GET_AND_CHECK_STATIC_METHOD(m_updateSelectionMethodID, appClass, "updateSelection", "(IIII)V");
+ return true;
+ }
+}
diff --git a/src/plugins/platforms/android/src/androidjniinput.h b/src/plugins/platforms/android/src/androidjniinput.h
new file mode 100644
index 0000000000..a78c7519db
--- /dev/null
+++ b/src/plugins/platforms/android/src/androidjniinput.h
@@ -0,0 +1,59 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 BogDan Vatra <bogdan@kde.org>
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the plugins of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Digia. For licensing terms and
+** conditions see http://qt.digia.com/licensing. For further information
+** use the contact form at http://qt.digia.com/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Digia gives you certain additional
+** rights. These rights are described in the Digia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef ANDROIDJNIINPUT_H
+#define ANDROIDJNIINPUT_H
+#include <jni.h>
+
+namespace QtAndroidInput
+{
+ // Software keyboard support
+ void showSoftwareKeyboard(int top, int left, int width, int height, int inputHints);
+ void resetSoftwareKeyboard();
+ void hideSoftwareKeyboard();
+ bool isSoftwareKeyboardVisible();
+ void updateSelection(int selStart, int selEnd, int candidatesStart, int candidatesEnd);
+ // Software keyboard support
+
+ bool registerNatives(JNIEnv *env);
+}
+
+#endif // ANDROIDJNIINPUT_H
diff --git a/src/plugins/platforms/android/src/androidjnimain.cpp b/src/plugins/platforms/android/src/androidjnimain.cpp
new file mode 100644
index 0000000000..f8f077908c
--- /dev/null
+++ b/src/plugins/platforms/android/src/androidjnimain.cpp
@@ -0,0 +1,845 @@
+/****************************************************************************
+**
+** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
+** Copyright (C) 2012 BogDan Vatra <bogdan@kde.org>
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the plugins of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Digia. For licensing terms and
+** conditions see http://qt.digia.com/licensing. For further information
+** use the contact form at http://qt.digia.com/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Digia gives you certain additional
+** rights. These rights are described in the Digia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+
+#include <dlfcn.h>
+#include <pthread.h>
+#include <qcoreapplication.h>
+#include <qimage.h>
+#include <qpoint.h>
+#include <qplugin.h>
+#include <qsemaphore.h>
+#include <qmutex.h>
+#include <qdebug.h>
+#include <qglobal.h>
+#include <qobjectdefs.h>
+#include <stdlib.h>
+
+#include "androidjnimain.h"
+#include "androidjniinput.h"
+#include "androidjniclipboard.h"
+#include "androidjnimenu.h"
+#include "qandroidplatformintegration.h"
+#include <QtWidgets/QApplication>
+
+#include <qabstracteventdispatcher.h>
+
+#include <android/bitmap.h>
+#include <android/asset_manager_jni.h>
+#include "qandroidassetsfileenginehandler.h"
+#include <android/api-level.h>
+
+#include <qpa/qwindowsysteminterface.h>
+
+#ifdef ANDROID_PLUGIN_OPENGL
+# include "qandroidopenglplatformwindow.h"
+#endif
+
+#if __ANDROID_API__ > 8
+# include <android/native_window_jni.h>
+#endif
+
+static jmethodID m_redrawSurfaceMethodID = 0;
+
+Q_IMPORT_PLUGIN(QAndroidPlatformIntegrationPlugin)
+
+static JavaVM *m_javaVM = NULL;
+static jclass m_applicationClass = NULL;
+static jobject m_classLoaderObject = NULL;
+static jmethodID m_loadClassMethodID = NULL;
+static AAssetManager *m_assetManager = NULL;
+static jobject m_resourcesObj;
+static jobject m_activityObject = NULL;
+
+static jclass m_bitmapClass = 0;
+static jmethodID m_createBitmapMethodID = 0;
+static jobject m_ARGB_8888_BitmapConfigValue = 0;
+static jobject m_RGB_565_BitmapConfigValue = 0;
+
+static jclass m_bitmapDrawableClass = 0;
+static jmethodID m_bitmapDrawableConstructorMethodID = 0;
+
+extern "C" typedef int (*Main)(int, char **); //use the standard main method to start the application
+static Main m_main = NULL;
+static void *m_mainLibraryHnd = NULL;
+static QList<QByteArray> m_applicationParams;
+
+#ifndef ANDROID_PLUGIN_OPENGL
+static jobject m_surface = NULL;
+#else
+static EGLNativeWindowType m_nativeWindow = 0;
+static QSemaphore m_waitForWindowSemaphore;
+static bool m_waitForWindow = false;
+
+static jfieldID m_surfaceFieldID = 0;
+#endif
+
+
+static QSemaphore m_quitAppSemaphore;
+static QMutex m_surfaceMutex(QMutex::Recursive);
+static QSemaphore m_pauseApplicationSemaphore;
+static QMutex m_pauseApplicationMutex;
+
+static QAndroidPlatformIntegration *m_androidPlatformIntegration = 0;
+
+static int m_desktopWidthPixels = 0;
+static int m_desktopHeightPixels = 0;
+
+static volatile bool m_pauseApplication;
+
+static jmethodID m_setFullScreenMethodID = 0;
+
+static AndroidAssetsFileEngineHandler *m_androidAssetsFileEngineHandler = 0;
+
+
+
+static const char m_qtTag[] = "Qt";
+static const char m_classErrorMsg[] = "Can't find class \"%s\"";
+static const char m_methodErrorMsg[] = "Can't find method \"%s%s\"";
+
+static inline void checkPauseApplication()
+{
+ m_pauseApplicationMutex.lock();
+ if (m_pauseApplication) {
+ m_pauseApplicationMutex.unlock();
+ m_pauseApplicationSemaphore.acquire(); // wait until surface is created
+
+ m_pauseApplicationMutex.lock();
+ m_pauseApplication = false;
+ m_pauseApplicationMutex.unlock();
+
+ //FIXME
+// QWindowSystemInterface::handleScreenAvailableGeometryChange(0);
+// QWindowSystemInterface::handleScreenGeometryChange(0);
+ } else {
+ m_pauseApplicationMutex.unlock();
+ }
+}
+
+namespace QtAndroid
+{
+#ifndef ANDROID_PLUGIN_OPENGL
+ void flushImage(const QPoint &pos, const QImage &image, const QRect &destinationRect)
+ {
+ checkPauseApplication();
+ QMutexLocker locker(&m_surfaceMutex);
+ if (!m_surface)
+ return;
+ AttachedJNIEnv env;
+ if (!env.jniEnv)
+ return;
+
+ int bpp = 2;
+ AndroidBitmapInfo info;
+ int ret;
+
+ if ((ret = AndroidBitmap_getInfo(env.jniEnv, m_surface, &info)) < 0) {
+ qWarning() << "AndroidBitmap_getInfo() failed ! error=" << ret;
+ m_javaVM->DetachCurrentThread();
+ return;
+ }
+
+ if (info.format != ANDROID_BITMAP_FORMAT_RGB_565) {
+ qWarning() << "Bitmap format is not RGB_565!";
+ m_javaVM->DetachCurrentThread();
+ return;
+ }
+
+ void *pixels;
+ unsigned char *screenBits;
+ if ((ret = AndroidBitmap_lockPixels(env.jniEnv, m_surface, &pixels)) < 0) {
+ qWarning() << "AndroidBitmap_lockPixels() failed! error=" << ret;
+ m_javaVM->DetachCurrentThread();
+ return;
+ }
+
+ screenBits = static_cast<unsigned char *>(pixels);
+ int sbpl = info.stride;
+ int swidth = info.width;
+ int sheight = info.height;
+
+ unsigned sposx = pos.x() + destinationRect.x();
+ unsigned sposy = pos.y() + destinationRect.y();
+
+ screenBits += sposy * sbpl;
+
+ unsigned ibpl = image.bytesPerLine();
+ unsigned iposx = destinationRect.x();
+ unsigned iposy = destinationRect.y();
+
+ const unsigned char *imageBits = static_cast<const unsigned char *>(image.bits());
+ imageBits += iposy * ibpl;
+
+ unsigned width = swidth - sposx < unsigned(destinationRect.width())
+ ? (swidth-sposx)
+ : destinationRect.width();
+ unsigned height = sheight - sposy < unsigned(destinationRect.height())
+ ? (sheight - sposy)
+ : destinationRect.height();
+
+ for (unsigned y = 0; y < height; y++) {
+ memcpy(screenBits + y*sbpl + sposx*bpp,
+ imageBits + y*ibpl + iposx*bpp,
+ width*bpp);
+ }
+ AndroidBitmap_unlockPixels(env.jniEnv, m_surface);
+
+ env.jniEnv->CallStaticVoidMethod(m_applicationClass,
+ m_redrawSurfaceMethodID,
+ jint(destinationRect.left()),
+ jint(destinationRect.top()),
+ jint(destinationRect.right() + 1),
+ jint(destinationRect.bottom() + 1));
+#warning FIXME dirty hack, figure out why it needs to add 1 to right and bottom !!!!
+ }
+
+#else // for #ifndef ANDROID_PLUGIN_OPENGL
+ EGLNativeWindowType nativeWindow(bool waitForWindow)
+ {
+ m_surfaceMutex.lock();
+ if (!m_nativeWindow && waitForWindow) {
+ m_waitForWindow = true;
+ m_surfaceMutex.unlock();
+ m_waitForWindowSemaphore.acquire();
+ m_waitForWindow = false;
+ return m_nativeWindow;
+ }
+ m_surfaceMutex.unlock();
+ return m_nativeWindow;
+ }
+
+ QSize nativeWindowSize()
+ {
+ if (m_nativeWindow == 0)
+ return QAndroidPlatformIntegration::defaultDesktopSize();
+
+ int width = ANativeWindow_getWidth(m_nativeWindow);
+ int height = ANativeWindow_getHeight(m_nativeWindow);
+
+ return QSize(width, height);
+ }
+#endif
+
+ void setAndroidPlatformIntegration(QAndroidPlatformIntegration *androidPlatformIntegration)
+ {
+ m_surfaceMutex.lock();
+ m_androidPlatformIntegration = androidPlatformIntegration;
+ m_surfaceMutex.unlock();
+ }
+
+ QAndroidPlatformIntegration *androidPlatformIntegration()
+ {
+ QMutexLocker locker(&m_surfaceMutex);
+ return m_androidPlatformIntegration;
+ }
+
+ void setFullScreen(QWidget *widget)
+ {
+ AttachedJNIEnv env;
+ if (!env.jniEnv)
+ return;
+
+ bool fullScreen = widget->isFullScreen();
+ if (!fullScreen) {
+ foreach (QWidget *w, qApp->topLevelWidgets()) {
+ fullScreen |= w->isFullScreen();
+ if (fullScreen)
+ break;
+ }
+ }
+
+ env.jniEnv->CallStaticVoidMethod(m_applicationClass, m_setFullScreenMethodID, fullScreen);
+ }
+
+ QWindow *topLevelWindowAt(const QPoint &globalPos)
+ {
+ return m_androidPlatformIntegration
+ ? m_androidPlatformIntegration->screen()->topLevelAt(globalPos)
+ : 0;
+ }
+
+ int desktopWidthPixels()
+ {
+ return m_desktopWidthPixels;
+ }
+
+ int desktopHeightPixels()
+ {
+ return m_desktopHeightPixels;
+ }
+
+ JavaVM *javaVM()
+ {
+ return m_javaVM;
+ }
+
+ jclass findClass(const QString &className, JNIEnv *env)
+ {
+ return static_cast<jclass>(env->CallObjectMethod(m_classLoaderObject,
+ m_loadClassMethodID,
+ env->NewString(reinterpret_cast<const jchar *>(className.constData()),
+ jsize(className.length()))));
+ }
+
+ AAssetManager *assetManager()
+ {
+ return m_assetManager;
+ }
+
+ jclass applicationClass()
+ {
+ return m_applicationClass;
+ }
+
+ jobject activity()
+ {
+ return m_activityObject;
+ }
+
+ jobject createBitmap(QImage img, JNIEnv *env)
+ {
+ if (img.format() != QImage::Format_ARGB32 && img.format() != QImage::Format_RGB16)
+ img = img.convertToFormat(QImage::Format_ARGB32);
+
+ jobject bitmap = env->CallStaticObjectMethod(m_bitmapClass,
+ m_createBitmapMethodID,
+ img.width(),
+ img.height(),
+ img.format() == QImage::Format_ARGB32
+ ? m_ARGB_8888_BitmapConfigValue
+ : m_RGB_565_BitmapConfigValue);
+ if (!bitmap)
+ return 0;
+
+ AndroidBitmapInfo info;
+ if (AndroidBitmap_getInfo(env, bitmap, &info) < 0) {
+ env->DeleteLocalRef(bitmap);
+ return 0;
+ }
+
+ void *pixels;
+ if (AndroidBitmap_lockPixels(env, bitmap, &pixels) < 0) {
+ env->DeleteLocalRef(bitmap);
+ return 0;
+ }
+
+ if (info.stride == uint(img.bytesPerLine())
+ && info.width == uint(img.width())
+ && info.height == uint(img.height())) {
+ memcpy(pixels, img.constBits(), info.stride * info.height);
+ } else {
+ uchar *bmpPtr = static_cast<uchar *>(pixels);
+ const unsigned width = qMin(info.width, (uint)img.width()); //should be the same
+ const unsigned height = qMin(info.height, (uint)img.height()); //should be the same
+ for (unsigned y = 0; y < height; y++, bmpPtr += info.stride)
+ memcpy(bmpPtr, img.constScanLine(y), width);
+ }
+ AndroidBitmap_unlockPixels(env, bitmap);
+ return bitmap;
+ }
+
+ jobject createBitmapDrawable(jobject bitmap, JNIEnv *env)
+ {
+ if (!bitmap)
+ return 0;
+
+ return env->NewObject(m_bitmapDrawableClass,
+ m_bitmapDrawableConstructorMethodID,
+ m_resourcesObj,
+ bitmap);
+ }
+
+ const char *classErrorMsgFmt()
+ {
+ return m_classErrorMsg;
+ }
+
+ const char *methodErrorMsgFmt()
+ {
+ return m_methodErrorMsg;
+ }
+
+ const char *qtTagText()
+ {
+ return m_qtTag;
+ }
+}
+
+static jboolean startQtAndroidPlugin(JNIEnv* /*env*/, jobject /*object*//*, jobject applicationAssetManager*/)
+{
+#ifndef ANDROID_PLUGIN_OPENGL
+ m_surface = 0;
+#else
+ m_nativeWindow = 0;
+ m_waitForWindow = false;
+#endif
+
+ m_androidPlatformIntegration = 0;
+ m_androidAssetsFileEngineHandler = new AndroidAssetsFileEngineHandler();
+
+#ifdef ANDROID_PLUGIN_OPENGL
+ return true;
+#else
+ return false;
+#endif
+}
+
+static void *startMainMethod(void */*data*/)
+{
+ char const **params;
+ params = static_cast<char const **>(malloc(m_applicationParams.length() * sizeof(char *)));
+ for (int i = 0; i < m_applicationParams.size(); i++)
+ params[i] = static_cast<const char *>(m_applicationParams[i].constData());
+
+ int ret = m_main(m_applicationParams.length(), const_cast<char **>(params));
+
+ free(params);
+ Q_UNUSED(ret);
+
+ if (m_mainLibraryHnd) {
+ int res = dlclose(m_mainLibraryHnd);
+ if (res < 0)
+ qWarning() << "dlclose failed:" << dlerror();
+ }
+
+ QtAndroid::AttachedJNIEnv env;
+ if (!env.jniEnv)
+ return 0;
+
+ if (m_applicationClass) {
+ jmethodID quitApp = env.jniEnv->GetStaticMethodID(m_applicationClass, "quitApp", "()V");
+ env.jniEnv->CallStaticVoidMethod(m_applicationClass, quitApp);
+ }
+
+ return 0;
+}
+
+static jboolean startQtApplication(JNIEnv *env, jobject /*object*/, jstring paramsString, jstring environmentString)
+{
+ m_mainLibraryHnd = NULL;
+ const char *nativeString = env->GetStringUTFChars(environmentString, 0);
+ QByteArray string = nativeString;
+ env->ReleaseStringUTFChars(environmentString, nativeString);
+ m_applicationParams=string.split('\t');
+ foreach (string, m_applicationParams) {
+ if (putenv(string.constData()))
+ qWarning() << "Can't set environment" << string;
+ }
+
+ nativeString = env->GetStringUTFChars(paramsString, 0);
+ string = nativeString;
+ env->ReleaseStringUTFChars(paramsString, nativeString);
+
+ m_applicationParams=string.split('\t');
+
+ // Go home
+ QDir::setCurrent(QDir::homePath());
+
+ //look for main()
+ if (m_applicationParams.length()) {
+ // Obtain a handle to the main library (the library that contains the main() function).
+ // This library should already be loaded, and calling dlopen() will just return a reference to it.
+ m_mainLibraryHnd = dlopen(m_applicationParams.first().data(), 0);
+ if (m_mainLibraryHnd == NULL) {
+ qCritical() << "dlopen failed:" << dlerror();
+ return false;
+ }
+ m_main = (Main)dlsym(m_mainLibraryHnd, "main");
+ } else {
+ qWarning() << "No main library was specified; searching entire process (this is slow!)";
+ m_main = (Main)dlsym(RTLD_DEFAULT, "main");
+ }
+
+ if (!m_main) {
+ qCritical() << "dlsym failed:" << dlerror();
+ qCritical() << "Could not find main method";
+ return false;
+ }
+
+ pthread_t appThread;
+ return pthread_create(&appThread, NULL, startMainMethod, NULL) == 0;
+}
+
+static void pauseQtApp(JNIEnv */*env*/, jobject /*thiz*/)
+{
+ m_surfaceMutex.lock();
+ m_pauseApplicationMutex.lock();
+
+ if (m_androidPlatformIntegration)
+ m_androidPlatformIntegration->pauseApp();
+ m_pauseApplication = true;
+
+ m_pauseApplicationMutex.unlock();
+ m_surfaceMutex.unlock();
+}
+
+static void resumeQtApp(JNIEnv */*env*/, jobject /*thiz*/)
+{
+ m_surfaceMutex.lock();
+ m_pauseApplicationMutex.lock();
+ if (m_androidPlatformIntegration)
+ m_androidPlatformIntegration->resumeApp();
+
+ if (m_pauseApplication)
+ m_pauseApplicationSemaphore.release();
+
+ m_pauseApplicationMutex.unlock();
+ m_surfaceMutex.unlock();
+}
+
+static void quitQtAndroidPlugin(JNIEnv *env, jclass /*clazz*/)
+{
+#ifndef ANDROID_PLUGIN_OPENGL
+ if (m_surface) {
+ env->DeleteGlobalRef(m_surface);
+ m_surface = 0;
+ }
+#else
+ Q_UNUSED(env);
+#endif
+
+ m_androidPlatformIntegration = 0;
+ delete m_androidAssetsFileEngineHandler;
+}
+
+static void terminateQt(JNIEnv *env, jclass /*clazz*/)
+{
+#ifndef ANDROID_PLUGIN_OPENGL
+ if (m_surface)
+ env->DeleteGlobalRef(m_surface);
+#endif
+ env->DeleteGlobalRef(m_applicationClass);
+ env->DeleteGlobalRef(m_classLoaderObject);
+ env->DeleteGlobalRef(m_resourcesObj);
+ env->DeleteGlobalRef(m_activityObject);
+ env->DeleteGlobalRef(m_bitmapClass);
+ env->DeleteGlobalRef(m_ARGB_8888_BitmapConfigValue);
+ env->DeleteGlobalRef(m_RGB_565_BitmapConfigValue);
+ env->DeleteGlobalRef(m_bitmapDrawableClass);
+}
+
+#ifdef ANDROID_PLUGIN_OPENGL
+#if __ANDROID_API__ < 9
+struct FakeNativeWindow
+{
+ long long dummyNativeWindow;// force 64 bits alignment
+};
+
+class FakeSurface: public FakeNativeWindow
+{
+public:
+ virtual void FakeSurfaceMethod()
+ {
+ fakeSurface = 0;
+ }
+
+ int fakeSurface;
+};
+
+EGLNativeWindowType ANativeWindow_fromSurface(JNIEnv *env, jobject jSurface)
+{
+ FakeSurface *surface = static_cast<FakeSurface *>(env->GetIntField(jSurface, m_surfaceFieldID));
+ return static_cast<EGLNativeWindowType>(static_cast<FakeNativeWindow*>(surface));
+}
+#endif // __ANDROID_API__ < 9
+#endif // ANDROID_PLUGIN_OPENGL
+
+static void setSurface(JNIEnv *env, jobject /*thiz*/, jobject jSurface)
+{
+#ifndef ANDROID_PLUGIN_OPENGL
+ if (m_surface)
+ env->DeleteGlobalRef(m_surface);
+ m_surface = env->NewGlobalRef(jSurface);
+#else
+ m_surfaceMutex.lock();
+ EGLNativeWindowType nativeWindow = ANativeWindow_fromSurface(env, jSurface);
+ bool sameNativeWindow = (nativeWindow != 0 && nativeWindow == m_nativeWindow);
+
+ m_nativeWindow = nativeWindow;
+ if (m_waitForWindow)
+ m_waitForWindowSemaphore.release();
+ if (m_androidPlatformIntegration && !sameNativeWindow) {
+ m_surfaceMutex.unlock();
+ m_androidPlatformIntegration->surfaceChanged();
+ } else if (m_androidPlatformIntegration && sameNativeWindow) {
+ QAndroidOpenGLPlatformWindow *window = m_androidPlatformIntegration->primaryWindow();
+ QPlatformScreen *screen = m_androidPlatformIntegration->screen();
+ QSize size = QtAndroid::nativeWindowSize();
+
+ QRect geometry(QPoint(0, 0), size);
+ QWindowSystemInterface::handleScreenAvailableGeometryChange(screen->screen(), geometry);
+ QWindowSystemInterface::handleScreenGeometryChange(screen->screen(), geometry);
+
+ if (window != 0) {
+ window->lock();
+ window->scheduleResize(size);
+
+ QWindowSystemInterface::handleExposeEvent(window->window(),
+ QRegion(window->window()->geometry()));
+ window->unlock();
+ }
+
+ m_surfaceMutex.unlock();
+ } else {
+ m_surfaceMutex.unlock();
+ }
+#endif // for #ifndef ANDROID_PLUGIN_OPENGL
+}
+
+static void destroySurface(JNIEnv *env, jobject /*thiz*/)
+{
+#ifndef ANDROID_PLUGIN_OPENGL
+ if (m_surface) {
+ env->DeleteGlobalRef(m_surface);
+ m_surface = 0;
+ }
+#else
+ Q_UNUSED(env);
+ m_nativeWindow = 0;
+ if (m_androidPlatformIntegration != 0)
+ m_androidPlatformIntegration->invalidateNativeSurface();
+#endif
+}
+
+static void setDisplayMetrics(JNIEnv */*env*/, jclass /*clazz*/,
+ jint /*widthPixels*/, jint /*heightPixels*/,
+ jint desktopWidthPixels, jint desktopHeightPixels,
+ jdouble xdpi, jdouble ydpi)
+{
+ m_desktopWidthPixels = desktopWidthPixels;
+ m_desktopHeightPixels = desktopHeightPixels;
+
+ if (!m_androidPlatformIntegration) {
+ QAndroidPlatformIntegration::setDefaultDisplayMetrics(desktopWidthPixels,desktopHeightPixels,
+ qRound(double(desktopWidthPixels) / xdpi * 25.4),
+ qRound(double(desktopHeightPixels) / ydpi * 25.4));
+ } else {
+ m_androidPlatformIntegration->setDisplayMetrics(qRound(double(desktopWidthPixels) / xdpi * 25.4),
+ qRound(double(desktopHeightPixels) / ydpi * 25.4));
+ m_androidPlatformIntegration->setDesktopSize(desktopWidthPixels, desktopHeightPixels);
+ }
+}
+
+static void lockSurface(JNIEnv */*env*/, jobject /*thiz*/)
+{
+ m_surfaceMutex.lock();
+}
+
+static void unlockSurface(JNIEnv */*env*/, jobject /*thiz*/)
+{
+ m_surfaceMutex.unlock();
+}
+
+static void updateWindow(JNIEnv */*env*/, jobject /*thiz*/)
+{
+ if (!m_androidPlatformIntegration)
+ return;
+
+ if (qApp != 0) {
+ foreach (QWidget *w, qApp->topLevelWidgets())
+ w->update();
+ }
+
+#ifndef ANDROID_PLUGIN_OPENGL
+ QAndroidPlatformScreen *screen = static_cast<QAndroidPlatformScreen *>(m_androidPlatformIntegration->screen());
+ QMetaObject::invokeMethod(screen, "setDirty", Qt::QueuedConnection, Q_ARG(QRect,screen->geometry()));
+#else
+ qWarning("updateWindow: Dirty screen not implemented yet on OpenGL");
+#endif
+}
+
+static void handleOrientationChanged(JNIEnv */*env*/, jobject /*thiz*/, jint newOrientation)
+{
+ if (m_androidPlatformIntegration == 0)
+ return;
+
+ Qt::ScreenOrientation screenOrientation = newOrientation == 1
+ ? Qt::PortraitOrientation
+ : Qt::LandscapeOrientation;
+ QPlatformScreen *screen = m_androidPlatformIntegration->screen();
+ QWindowSystemInterface::handleScreenOrientationChange(screen->screen(),
+ screenOrientation);
+}
+
+static JNINativeMethod methods[] = {
+ {"startQtAndroidPlugin", "()Z", (void *)startQtAndroidPlugin},
+ {"startQtApplication", "(Ljava/lang/String;Ljava/lang/String;)V", (void *)startQtApplication},
+ {"pauseQtApp", "()V", (void *)pauseQtApp},
+ {"resumeQtApp", "()V", (void *)resumeQtApp},
+ {"quitQtAndroidPlugin", "()V", (void *)quitQtAndroidPlugin},
+ {"terminateQt", "()V", (void *)terminateQt},
+ {"setDisplayMetrics", "(IIIIDD)V", (void *)setDisplayMetrics},
+ {"setSurface", "(Ljava/lang/Object;)V", (void *)setSurface},
+ {"destroySurface", "()V", (void *)destroySurface},
+ {"lockSurface", "()V", (void *)lockSurface},
+ {"unlockSurface", "()V", (void *)unlockSurface},
+ {"updateWindow", "()V", (void *)updateWindow},
+ {"handleOrientationChanged", "(I)V", (void *)handleOrientationChanged}
+};
+
+#define FIND_AND_CHECK_CLASS(CLASS_NAME) \
+clazz = env->FindClass(CLASS_NAME); \
+if (!clazz) { \
+ __android_log_print(ANDROID_LOG_FATAL, m_qtTag, m_classErrorMsg, CLASS_NAME); \
+ return JNI_FALSE; \
+}
+
+#define GET_AND_CHECK_METHOD(VAR, CLASS, METHOD_NAME, METHOD_SIGNATURE) \
+VAR = env->GetMethodID(CLASS, METHOD_NAME, METHOD_SIGNATURE); \
+if (!VAR) { \
+ __android_log_print(ANDROID_LOG_FATAL, m_qtTag, m_methodErrorMsg, METHOD_NAME, METHOD_SIGNATURE); \
+ return JNI_FALSE; \
+}
+
+#define GET_AND_CHECK_STATIC_METHOD(VAR, CLASS, METHOD_NAME, METHOD_SIGNATURE) \
+VAR = env->GetStaticMethodID(CLASS, METHOD_NAME, METHOD_SIGNATURE); \
+if (!VAR) { \
+ __android_log_print(ANDROID_LOG_FATAL, m_qtTag, m_methodErrorMsg, METHOD_NAME, METHOD_SIGNATURE); \
+ return JNI_FALSE; \
+}
+
+#define GET_AND_CHECK_FIELD(VAR, CLASS, FIELD_NAME, FIELD_SIGNATURE) \
+VAR = env->GetFieldID(CLASS, FIELD_NAME, FIELD_SIGNATURE); \
+if (!VAR) { \
+ __android_log_print(ANDROID_LOG_FATAL, m_qtTag, m_methodErrorMsg, FIELD_NAME, FIELD_SIGNATURE); \
+ return JNI_FALSE; \
+}
+
+#define GET_AND_CHECK_STATIC_FIELD(VAR, CLASS, FIELD_NAME, FIELD_SIGNATURE) \
+VAR = env->GetStaticFieldID(CLASS, FIELD_NAME, FIELD_SIGNATURE); \
+if (!VAR) { \
+ __android_log_print(ANDROID_LOG_FATAL, m_qtTag, m_methodErrorMsg, FIELD_NAME, FIELD_SIGNATURE); \
+ return JNI_FALSE; \
+}
+
+static int registerNatives(JNIEnv *env)
+{
+ jclass clazz;
+ FIND_AND_CHECK_CLASS("org/qtproject/qt5/android/QtNative");
+ m_applicationClass = static_cast<jclass>(env->NewGlobalRef(clazz));
+
+ if (env->RegisterNatives(m_applicationClass, methods, sizeof(methods) / sizeof(methods[0])) < 0) {
+ __android_log_print(ANDROID_LOG_FATAL,"Qt", "RegisterNatives failed");
+ return JNI_FALSE;
+ }
+
+ GET_AND_CHECK_STATIC_METHOD(m_redrawSurfaceMethodID, m_applicationClass, "redrawSurface", "(IIII)V");
+ GET_AND_CHECK_STATIC_METHOD(m_setFullScreenMethodID, m_applicationClass, "setFullScreen", "(Z)V");
+
+#ifdef ANDROID_PLUGIN_OPENGL
+ FIND_AND_CHECK_CLASS("android/view/Surface");
+#if __ANDROID_API__ < 9
+# define ANDROID_VIEW_SURFACE_JNI_ID "mSurface"
+#else
+# define ANDROID_VIEW_SURFACE_JNI_ID "mNativeSurface"
+#endif
+ GET_AND_CHECK_FIELD(m_surfaceFieldID, clazz, ANDROID_VIEW_SURFACE_JNI_ID, "I");
+#endif
+
+ jmethodID methodID;
+ GET_AND_CHECK_STATIC_METHOD(methodID, m_applicationClass, "activity", "()Landroid/app/Activity;");
+ jobject activityObject = env->CallStaticObjectMethod(m_applicationClass, methodID);
+ m_activityObject = env->NewGlobalRef(activityObject);
+ GET_AND_CHECK_STATIC_METHOD(methodID, m_applicationClass, "classLoader", "()Ljava/lang/ClassLoader;");
+ m_classLoaderObject = env->NewGlobalRef(env->CallStaticObjectMethod(m_applicationClass, methodID));
+
+ clazz = env->GetObjectClass(m_classLoaderObject);
+ GET_AND_CHECK_METHOD(m_loadClassMethodID, clazz, "loadClass", "(Ljava/lang/String;)Ljava/lang/Class;");
+
+ FIND_AND_CHECK_CLASS("android/content/ContextWrapper");
+ GET_AND_CHECK_METHOD(methodID, clazz, "getAssets", "()Landroid/content/res/AssetManager;");
+ m_assetManager = AAssetManager_fromJava(env, env->CallObjectMethod(activityObject, methodID));
+
+ GET_AND_CHECK_METHOD(methodID, clazz, "getResources", "()Landroid/content/res/Resources;");
+ m_resourcesObj = env->NewGlobalRef(env->CallObjectMethod(activityObject, methodID));
+
+ FIND_AND_CHECK_CLASS("android/graphics/Bitmap");
+ m_bitmapClass = static_cast<jclass>(env->NewGlobalRef(clazz));
+ GET_AND_CHECK_STATIC_METHOD(m_createBitmapMethodID, m_bitmapClass
+ , "createBitmap", "(IILandroid/graphics/Bitmap$Config;)Landroid/graphics/Bitmap;");
+
+ FIND_AND_CHECK_CLASS("android/graphics/Bitmap$Config");
+ jfieldID fieldId;
+ GET_AND_CHECK_STATIC_FIELD(fieldId, clazz, "ARGB_8888", "Landroid/graphics/Bitmap$Config;");
+ m_ARGB_8888_BitmapConfigValue = env->NewGlobalRef(env->GetStaticObjectField(clazz, fieldId));
+ GET_AND_CHECK_STATIC_FIELD(fieldId, clazz, "RGB_565", "Landroid/graphics/Bitmap$Config;");
+ m_RGB_565_BitmapConfigValue = env->NewGlobalRef(env->GetStaticObjectField(clazz, fieldId));
+
+ FIND_AND_CHECK_CLASS("android/graphics/drawable/BitmapDrawable");
+ m_bitmapDrawableClass = static_cast<jclass>(env->NewGlobalRef(clazz));
+ GET_AND_CHECK_METHOD(m_bitmapDrawableConstructorMethodID,
+ m_bitmapDrawableClass,
+ "<init>",
+ "(Landroid/content/res/Resources;Landroid/graphics/Bitmap;)V");
+
+ return JNI_TRUE;
+}
+
+Q_DECL_EXPORT jint JNICALL JNI_OnLoad(JavaVM *vm, void */*reserved*/)
+{
+ typedef union {
+ JNIEnv *nativeEnvironment;
+ void *venv;
+ } UnionJNIEnvToVoid;
+
+ __android_log_print(ANDROID_LOG_INFO, "Qt", "qt start");
+ UnionJNIEnvToVoid uenv;
+ uenv.venv = NULL;
+ m_javaVM = 0;
+
+ if (vm->GetEnv(&uenv.venv, JNI_VERSION_1_4) != JNI_OK) {
+ __android_log_print(ANDROID_LOG_FATAL, "Qt", "GetEnv failed");
+ return -1;
+ }
+
+ JNIEnv *env = uenv.nativeEnvironment;
+ if (!registerNatives(env)
+ || !QtAndroidInput::registerNatives(env)
+ || !QtAndroidClipboard::registerNatives(env)
+ || !QtAndroidMenu::registerNatives(env)) {
+ __android_log_print(ANDROID_LOG_FATAL, "Qt", "registerNatives failed");
+ return -1;
+ }
+
+ m_javaVM = vm;
+ return JNI_VERSION_1_4;
+}
diff --git a/src/plugins/platforms/android/src/androidjnimain.h b/src/plugins/platforms/android/src/androidjnimain.h
new file mode 100644
index 0000000000..618bd87cdb
--- /dev/null
+++ b/src/plugins/platforms/android/src/androidjnimain.h
@@ -0,0 +1,121 @@
+/****************************************************************************
+**
+** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
+** Copyright (C) 2012 BogDan Vatra <bogdan@kde.org>
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the plugins of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Digia. For licensing terms and
+** conditions see http://qt.digia.com/licensing. For further information
+** use the contact form at http://qt.digia.com/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Digia gives you certain additional
+** rights. These rights are described in the Digia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef ANDROID_APP_H
+#define ANDROID_APP_H
+
+#include <android/log.h>
+
+#ifdef ANDROID_PLUGIN_OPENGL
+# include <EGL/eglplatform.h>
+#endif
+
+#include <QtCore/qsize.h>
+
+#include <jni.h>
+#include <android/asset_manager.h>
+
+class QImage;
+class QRect;
+class QPoint;
+class QThread;
+class QAndroidPlatformIntegration;
+class QWidget;
+class QString;
+class QWindow;
+
+namespace QtAndroid
+{
+ QAndroidPlatformIntegration *androidPlatformIntegration();
+ void setAndroidPlatformIntegration(QAndroidPlatformIntegration *androidPlatformIntegration);
+ void setQtThread(QThread *thread);
+
+ void setFullScreen(QWidget *widget);
+
+#ifndef ANDROID_PLUGIN_OPENGL
+ void flushImage(const QPoint &pos, const QImage &image, const QRect &rect);
+#else
+ EGLNativeWindowType nativeWindow(bool waitToCreate = true);
+ QSize nativeWindowSize();
+#endif
+
+ QWindow *topLevelWindowAt(const QPoint &globalPos);
+ int desktopWidthPixels();
+ int desktopHeightPixels();
+ JavaVM *javaVM();
+ jclass findClass(const QString &className, JNIEnv *env);
+ AAssetManager *assetManager();
+ jclass applicationClass();
+ jobject activity();
+
+ jobject createBitmap(QImage img, JNIEnv *env = 0);
+ jobject createBitmapDrawable(jobject bitmap, JNIEnv *env = 0);
+
+ struct AttachedJNIEnv
+ {
+ AttachedJNIEnv()
+ {
+ attached = false;
+ if (QtAndroid::javaVM()->GetEnv((void**)&jniEnv, JNI_VERSION_1_6) < 0) {
+ if (QtAndroid::javaVM()->AttachCurrentThread(&jniEnv, NULL) < 0) {
+ __android_log_print(ANDROID_LOG_ERROR, "Qt", "AttachCurrentThread failed");
+ jniEnv = 0;
+ return;
+ }
+ attached = true;
+ }
+ }
+
+ ~AttachedJNIEnv()
+ {
+ if (attached)
+ QtAndroid::javaVM()->DetachCurrentThread();
+ }
+ bool attached;
+ JNIEnv *jniEnv;
+ };
+ const char *classErrorMsgFmt();
+ const char *methodErrorMsgFmt();
+ const char *qtTagText();
+
+}
+#endif // ANDROID_APP_H
diff --git a/src/plugins/platforms/android/src/androidjnimenu.cpp b/src/plugins/platforms/android/src/androidjnimenu.cpp
new file mode 100644
index 0000000000..e49af0fdac
--- /dev/null
+++ b/src/plugins/platforms/android/src/androidjnimenu.cpp
@@ -0,0 +1,405 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 BogDan Vatra <bogdan@kde.org>
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the plugins of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Digia. For licensing terms and
+** conditions see http://qt.digia.com/licensing. For further information
+** use the contact form at http://qt.digia.com/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Digia gives you certain additional
+** rights. These rights are described in the Digia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "androidjnimenu.h"
+#include "androidjnimain.h"
+#include <qmutex.h>
+#include <qset.h>
+#include <qqueue.h>
+#include <android/log.h>
+#include "qandroidplatformmenubar.h"
+#include "qandroidplatformmenu.h"
+#include <qandroidplatformmenuitem.h>
+
+using namespace QtAndroid;
+
+namespace QtAndroidMenu
+{
+ static QQueue<QAndroidPlatformMenu *> pendingContextMenus;
+ static QAndroidPlatformMenu *visibleMenu = 0;
+ static QMutex visibleMenuMutex(QMutex::Recursive);
+
+ static QSet<QAndroidPlatformMenuBar *> menuBars;
+ static QAndroidPlatformMenuBar *visibleMenuBar = 0;
+ static QWindow *activeTopLevelWindow = 0;
+ static QMutex menuBarMutex(QMutex::Recursive);
+
+ static jmethodID openContextMenuMethodID = 0;
+ static jmethodID closeContextMenuMethodID = 0;
+ static jmethodID resetOptionsMenuMethodID = 0;
+
+ static jmethodID clearMenuMethodID = 0;
+ static jmethodID addMenuItemMethodID = 0;
+ static int menuNoneValue = 0;
+ static jmethodID setHeaderTitleContextMenuMethodID = 0;
+
+ static jmethodID setCheckableMenuItemMethodID = 0;
+ static jmethodID setCheckedMenuItemMethodID = 0;
+ static jmethodID setEnabledMenuItemMethodID = 0;
+ static jmethodID setIconMenuItemMethodID = 0;
+ static jmethodID setVisibleMenuItemMethodID = 0;
+
+ void resetMenuBar()
+ {
+ AttachedJNIEnv env;
+ if (env.jniEnv)
+ env.jniEnv->CallStaticVoidMethod(applicationClass(), resetOptionsMenuMethodID);
+ }
+
+ void showContextMenu(QAndroidPlatformMenu *menu, JNIEnv *env)
+ {
+ QMutexLocker lock(&visibleMenuMutex);
+ if (visibleMenu) {
+ pendingContextMenus.enqueue(menu);
+ } else {
+ visibleMenu = menu;
+ menu->aboutToShow();
+ if (env) {
+ env->CallStaticVoidMethod(applicationClass(), openContextMenuMethodID);
+ } else {
+ AttachedJNIEnv aenv;
+ if (aenv.jniEnv)
+ aenv.jniEnv->CallStaticVoidMethod(applicationClass(), openContextMenuMethodID);
+ }
+ }
+ }
+
+ void hideContextMenu(QAndroidPlatformMenu *menu)
+ {
+ QMutexLocker lock(&visibleMenuMutex);
+ if (visibleMenu == menu) {
+ AttachedJNIEnv env;
+ if (env.jniEnv)
+ env.jniEnv->CallStaticVoidMethod(applicationClass(), openContextMenuMethodID);
+ } else {
+ pendingContextMenus.removeOne(menu);
+ }
+ }
+
+ void syncMenu(QAndroidPlatformMenu */*menu*/)
+ {
+// QMutexLocker lock(&visibleMenuMutex);
+// if (visibleMenu == menu)
+// {
+// hideContextMenu(menu);
+// showContextMenu(menu);
+// }
+ }
+
+ void androidPlatformMenuDestroyed(QAndroidPlatformMenu *menu)
+ {
+ QMutexLocker lock(&visibleMenuMutex);
+ if (visibleMenu == menu)
+ visibleMenu = 0;
+ }
+
+ void setMenuBar(QAndroidPlatformMenuBar *menuBar, QWindow *window)
+ {
+ if (activeTopLevelWindow == window && visibleMenuBar != menuBar) {
+ visibleMenuBar = menuBar;
+ resetMenuBar();
+ }
+ }
+
+ void setActiveTopLevelWindow(QWindow *window)
+ {
+ QMutexLocker lock(&menuBarMutex);
+ if (activeTopLevelWindow == window)
+ return;
+
+ visibleMenuBar = 0;
+ activeTopLevelWindow = window;
+#ifdef ANDROID_PLUGIN_OPENGL
+ //only one toplevel window, so the menu bar always belongs to us
+ if (menuBars.size() == 1) {
+ visibleMenuBar = *menuBars.constBegin(); //since QSet doesn't have first()
+ } else
+#endif
+ foreach (QAndroidPlatformMenuBar *menuBar, menuBars) {
+ if (menuBar->parentWindow() == window) {
+ visibleMenuBar = menuBar;
+ break;
+ }
+ }
+
+ resetMenuBar();
+ }
+
+ void addMenuBar(QAndroidPlatformMenuBar *menuBar)
+ {
+ QMutexLocker lock(&menuBarMutex);
+ menuBars.insert(menuBar);
+ }
+
+ void removeMenuBar(QAndroidPlatformMenuBar *menuBar)
+ {
+ QMutexLocker lock(&menuBarMutex);
+ menuBars.remove(menuBar);
+ if (visibleMenuBar == menuBar)
+ resetMenuBar();
+ }
+
+ static void fillMenuItem(JNIEnv *env, jobject menuItem, bool checkable, bool checked, bool enabled, bool visible, const QIcon &icon=QIcon())
+ {
+ env->CallObjectMethod(menuItem, setCheckableMenuItemMethodID, checkable);
+ env->CallObjectMethod(menuItem, setCheckedMenuItemMethodID, checked);
+ env->CallObjectMethod(menuItem, setEnabledMenuItemMethodID, enabled);
+
+ if (!icon.isNull()) {
+ int sz = qMax(36, qgetenv("QT_ANDROID_APP_ICON_SIZE").toInt());
+ QImage img = icon.pixmap(QSize(sz,sz),
+ enabled
+ ? QIcon::Normal
+ : QIcon::Disabled,
+ QIcon::On).toImage();
+ env->CallObjectMethod(menuItem,
+ setIconMenuItemMethodID,
+ createBitmapDrawable(createBitmap(img, env), env));
+ }
+
+ env->CallObjectMethod(menuItem, setVisibleMenuItemMethodID, visible);
+ }
+
+ static int addAllMenuItemsToMenu(JNIEnv *env, jobject menu, QAndroidPlatformMenu *platformMenu) {
+ int order = 0;
+ QMutexLocker lock(platformMenu->menuItemsMutex());
+ foreach (QAndroidPlatformMenuItem *item, platformMenu->menuItems()) {
+ if (item->isSeparator())
+ continue;
+ jstring jtext = env->NewString(reinterpret_cast<const jchar *>(item->text().data()),
+ item->text().length());
+ jobject menuItem = env->CallObjectMethod(menu,
+ addMenuItemMethodID,
+ menuNoneValue,
+ int(item->tag()),
+ order++,
+ jtext);
+ env->DeleteLocalRef(jtext);
+ fillMenuItem(env,
+ menuItem,
+ item->isCheckable(),
+ item->isChecked(),
+ item->isEnabled(),
+ item->isVisible(),
+ item->icon());
+ }
+
+ return order;
+ }
+
+ static jboolean onPrepareOptionsMenu(JNIEnv *env, jobject /*thiz*/, jobject menu)
+ {
+ env->CallVoidMethod(menu, clearMenuMethodID);
+ QMutexLocker lock(&menuBarMutex);
+ if (!visibleMenuBar)
+ return JNI_FALSE;
+
+ const QAndroidPlatformMenuBar::PlatformMenusType &menus = visibleMenuBar->menus();
+ int order = 0;
+ QMutexLocker lockMenuBarMutex(visibleMenuBar->menusListMutex());
+ if (menus.size() == 1) { // Expand the menu
+ order = addAllMenuItemsToMenu(env, menu, static_cast<QAndroidPlatformMenu *>(menus.front()));
+ } else {
+ foreach (QAndroidPlatformMenu *item, menus) {
+ jstring jtext = env->NewString(reinterpret_cast<const jchar *>(item->text().data()),
+ item->text().length());
+ jobject menuItem = env->CallObjectMethod(menu,
+ addMenuItemMethodID,
+ menuNoneValue,
+ int(item->tag()),
+ order++,
+ jtext);
+ env->DeleteLocalRef(jtext);
+
+ fillMenuItem(env,
+ menuItem,
+ false,
+ false,
+ item->isEnabled(),
+ item->isVisible(),
+ item->icon());
+ }
+ }
+ return order ? JNI_TRUE : JNI_FALSE;
+ }
+
+ static jboolean onOptionsItemSelected(JNIEnv *env, jobject /*thiz*/, jint menuId, jboolean checked)
+ {
+ QMutexLocker lock(&menuBarMutex);
+ if (!visibleMenuBar)
+ return JNI_FALSE;
+
+ const QAndroidPlatformMenuBar::PlatformMenusType &menus = visibleMenuBar->menus();
+ if (menus.size() == 1) { // Expanded menu
+ QAndroidPlatformMenuItem *item = static_cast<QAndroidPlatformMenuItem *>(menus.front()->menuItemForTag(menuId));
+ if (item) {
+ if (item->menu()) {
+ showContextMenu(item->menu(), env);
+ } else {
+ if (item->isCheckable())
+ item->setChecked(checked);
+ item->activated();
+ }
+ }
+ } else {
+ QAndroidPlatformMenu *menu = static_cast<QAndroidPlatformMenu *>(visibleMenuBar->menuForTag(menuId));
+ if (menu)
+ showContextMenu(menu, env);
+ }
+
+ return JNI_TRUE;
+ }
+
+ static void onOptionsMenuClosed(JNIEnv */*env*/, jobject /*thiz*/, jobject /*menu*/)
+ {
+ }
+
+ static void onCreateContextMenu(JNIEnv *env, jobject /*thiz*/, jobject menu)
+ {
+ env->CallVoidMethod(menu, clearMenuMethodID);
+ QMutexLocker lock(&visibleMenuMutex);
+ if (!visibleMenu)
+ return;
+
+ jstring jtext = env->NewString(reinterpret_cast<const jchar*>(visibleMenu->text().data()),
+ visibleMenu->text().length());
+ env->CallObjectMethod(menu, setHeaderTitleContextMenuMethodID, jtext);
+ env->DeleteLocalRef(jtext);
+ addAllMenuItemsToMenu(env, menu, visibleMenu);
+ }
+
+ static jboolean onContextItemSelected(JNIEnv *env, jobject /*thiz*/, jint menuId, jboolean checked)
+ {
+ QMutexLocker lock(&visibleMenuMutex);
+ QAndroidPlatformMenuItem * item = static_cast<QAndroidPlatformMenuItem *>(visibleMenu->menuItemForTag(menuId));
+ if (item) {
+ if (item->menu()) {
+ showContextMenu(item->menu(), env);
+ } else {
+ if (item->isCheckable())
+ item->setChecked(checked);
+ item->activated();
+ }
+ }
+ return JNI_TRUE;
+ }
+
+ static void onContextMenuClosed(JNIEnv *env, jobject /*thiz*/, jobject /*menu*/)
+ {
+ QMutexLocker lock(&visibleMenuMutex);
+ if (!visibleMenu)
+ return;
+ visibleMenu->aboutToHide();
+ visibleMenu = 0;
+ if (!pendingContextMenus.empty())
+ showContextMenu(pendingContextMenus.dequeue(), env);
+ }
+
+ static JNINativeMethod methods[] = {
+ {"onPrepareOptionsMenu", "(Landroid/view/Menu;)Z", (void *)onPrepareOptionsMenu},
+ {"onOptionsItemSelected", "(IZ)Z", (void *)onOptionsItemSelected},
+ {"onOptionsMenuClosed", "(Landroid/view/Menu;)V", (void*)onOptionsMenuClosed},
+ {"onCreateContextMenu", "(Landroid/view/ContextMenu;)V", (void *)onCreateContextMenu},
+ {"onContextItemSelected", "(IZ)Z", (void *)onContextItemSelected},
+ {"onContextMenuClosed", "(Landroid/view/Menu;)V", (void*)onContextMenuClosed},
+ };
+
+#define FIND_AND_CHECK_CLASS(CLASS_NAME) \
+ clazz = env->FindClass(CLASS_NAME); \
+ if (!clazz) { \
+ __android_log_print(ANDROID_LOG_FATAL, qtTagText(), classErrorMsgFmt(), CLASS_NAME); \
+ return false; \
+ }
+
+#define GET_AND_CHECK_METHOD(VAR, CLASS, METHOD_NAME, METHOD_SIGNATURE) \
+ VAR = env->GetMethodID(CLASS, METHOD_NAME, METHOD_SIGNATURE); \
+ if (!VAR) { \
+ __android_log_print(ANDROID_LOG_FATAL, qtTagText(), methodErrorMsgFmt(), METHOD_NAME, METHOD_SIGNATURE); \
+ return false; \
+ }
+
+#define GET_AND_CHECK_STATIC_METHOD(VAR, CLASS, METHOD_NAME, METHOD_SIGNATURE) \
+ VAR = env->GetStaticMethodID(CLASS, METHOD_NAME, METHOD_SIGNATURE); \
+ if (!VAR) { \
+ __android_log_print(ANDROID_LOG_FATAL, qtTagText(), methodErrorMsgFmt(), METHOD_NAME, METHOD_SIGNATURE); \
+ return false; \
+ }
+
+#define GET_AND_CHECK_STATIC_FIELD(VAR, CLASS, FIELD_NAME, FIELD_SIGNATURE) \
+ VAR = env->GetStaticFieldID(CLASS, FIELD_NAME, FIELD_SIGNATURE); \
+ if (!VAR) { \
+ __android_log_print(ANDROID_LOG_FATAL, qtTagText(), methodErrorMsgFmt(), FIELD_NAME, FIELD_SIGNATURE); \
+ return false; \
+ }
+
+ bool registerNatives(JNIEnv *env)
+ {
+ jclass appClass = applicationClass();
+
+ if (env->RegisterNatives(appClass, methods, sizeof(methods) / sizeof(methods[0])) < 0) {
+ __android_log_print(ANDROID_LOG_FATAL,"Qt", "RegisterNatives failed");
+ return false;
+ }
+
+ GET_AND_CHECK_STATIC_METHOD(openContextMenuMethodID, appClass, "openContextMenu", "()V");
+ GET_AND_CHECK_STATIC_METHOD(closeContextMenuMethodID, appClass, "closeContextMenu", "()V");
+ GET_AND_CHECK_STATIC_METHOD(resetOptionsMenuMethodID, appClass, "resetOptionsMenu", "()V");
+
+ jclass clazz;
+ FIND_AND_CHECK_CLASS("android/view/Menu");
+ GET_AND_CHECK_METHOD(clearMenuMethodID, clazz, "clear", "()V");
+ GET_AND_CHECK_METHOD(addMenuItemMethodID, clazz, "add", "(IIILjava/lang/CharSequence;)Landroid/view/MenuItem;");
+ jfieldID menuNoneFiledId;
+ GET_AND_CHECK_STATIC_FIELD(menuNoneFiledId, clazz, "NONE", "I");
+ menuNoneValue = env->GetStaticIntField(clazz, menuNoneFiledId);
+
+ FIND_AND_CHECK_CLASS("android/view/ContextMenu");
+ GET_AND_CHECK_METHOD(setHeaderTitleContextMenuMethodID, clazz, "setHeaderTitle","(Ljava/lang/CharSequence;)Landroid/view/ContextMenu;");
+
+ FIND_AND_CHECK_CLASS("android/view/MenuItem");
+ GET_AND_CHECK_METHOD(setCheckableMenuItemMethodID, clazz, "setCheckable", "(Z)Landroid/view/MenuItem;");
+ GET_AND_CHECK_METHOD(setCheckedMenuItemMethodID, clazz, "setChecked", "(Z)Landroid/view/MenuItem;");
+ GET_AND_CHECK_METHOD(setEnabledMenuItemMethodID, clazz, "setEnabled", "(Z)Landroid/view/MenuItem;");
+ GET_AND_CHECK_METHOD(setIconMenuItemMethodID, clazz, "setIcon", "(Landroid/graphics/drawable/Drawable;)Landroid/view/MenuItem;");
+ GET_AND_CHECK_METHOD(setVisibleMenuItemMethodID, clazz, "setVisible", "(Z)Landroid/view/MenuItem;");
+ return true;
+ }
+}
diff --git a/src/plugins/platforms/android/src/androidjnimenu.h b/src/plugins/platforms/android/src/androidjnimenu.h
new file mode 100644
index 0000000000..7c5422f67b
--- /dev/null
+++ b/src/plugins/platforms/android/src/androidjnimenu.h
@@ -0,0 +1,69 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 BogDan Vatra <bogdan@kde.org>
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the plugins of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Digia. For licensing terms and
+** conditions see http://qt.digia.com/licensing. For further information
+** use the contact form at http://qt.digia.com/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Digia gives you certain additional
+** rights. These rights are described in the Digia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef ANDROIDJNIMENU_H
+#define ANDROIDJNIMENU_H
+
+#include <jni.h>
+
+class QAndroidPlatformMenuBar;
+class QAndroidPlatformMenu;
+class QAndroidPlatformMenuItem;
+class QWindow;
+
+namespace QtAndroidMenu
+{
+ // Menu support
+ void showContextMenu(QAndroidPlatformMenu *menu, JNIEnv *env = 0);
+ void hideContextMenu(QAndroidPlatformMenu *menu);
+ void syncMenu(QAndroidPlatformMenu *menu);
+ void androidPlatformMenuDestroyed(QAndroidPlatformMenu *menu);
+
+ void setMenuBar(QAndroidPlatformMenuBar *menuBar, QWindow *window);
+ void setActiveTopLevelWindow(QWindow *window);
+ void addMenuBar(QAndroidPlatformMenuBar *menuBar);
+ void removeMenuBar(QAndroidPlatformMenuBar *menuBar);
+
+ // Menu support
+ bool registerNatives(JNIEnv *env);
+}
+
+#endif // ANDROIDJNIMENU_H
diff --git a/src/plugins/platforms/android/src/androidplatformplugin.cpp b/src/plugins/platforms/android/src/androidplatformplugin.cpp
new file mode 100644
index 0000000000..71c5096e16
--- /dev/null
+++ b/src/plugins/platforms/android/src/androidplatformplugin.cpp
@@ -0,0 +1,66 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 BogDan Vatra <bogdan@kde.org>
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the plugins of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Digia. For licensing terms and
+** conditions see http://qt.digia.com/licensing. For further information
+** use the contact form at http://qt.digia.com/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Digia gives you certain additional
+** rights. These rights are described in the Digia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include <qpa/qplatformintegrationplugin.h>
+#include "qandroidplatformintegration.h"
+
+QT_BEGIN_NAMESPACE
+
+class QAndroidPlatformIntegrationPlugin: public QPlatformIntegrationPlugin
+{
+ Q_OBJECT
+ Q_PLUGIN_METADATA(IID "org.qt-project.Qt.QPA.QPlatformIntegrationFactoryInterface.5.1" FILE "android.json")
+public:
+ QPlatformIntegration *create(const QString &key, const QStringList &paramList);
+};
+
+
+QPlatformIntegration *QAndroidPlatformIntegrationPlugin::create(const QString &key, const QStringList &paramList)
+{
+ Q_UNUSED(paramList);
+ if (key.toLower() == "android")
+ return new QAndroidPlatformIntegration(paramList);
+ return 0;
+}
+
+QT_END_NAMESPACE
+#include "androidplatformplugin.moc"
+
diff --git a/src/plugins/platforms/android/src/opengl/qandroidopenglcontext.cpp b/src/plugins/platforms/android/src/opengl/qandroidopenglcontext.cpp
new file mode 100644
index 0000000000..aa8ee57341
--- /dev/null
+++ b/src/plugins/platforms/android/src/opengl/qandroidopenglcontext.cpp
@@ -0,0 +1,78 @@
+/****************************************************************************
+**
+** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the plugins of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Digia. For licensing terms and
+** conditions see http://qt.digia.com/licensing. For further information
+** use the contact form at http://qt.digia.com/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Digia gives you certain additional
+** rights. These rights are described in the Digia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qandroidopenglcontext.h"
+#include "qandroidopenglplatformwindow.h"
+#include "qandroidplatformintegration.h"
+
+#include <QtCore/qdebug.h>
+#include <qpa/qwindowsysteminterface.h>
+
+QT_BEGIN_NAMESPACE
+
+QAndroidOpenGLContext::QAndroidOpenGLContext(const QAndroidPlatformIntegration *integration,
+ const QSurfaceFormat &format,
+ QPlatformOpenGLContext *share,
+ EGLDisplay display,
+ EGLenum eglApi)
+ : QEglFSContext(format, share, display, eglApi)
+ , m_platformIntegration(integration)
+{
+}
+
+void QAndroidOpenGLContext::swapBuffers(QPlatformSurface *surface)
+{
+ QEglFSContext::swapBuffers(surface);
+
+ QAndroidOpenGLPlatformWindow *primaryWindow = m_platformIntegration->primaryWindow();
+ if (primaryWindow == surface) {
+ primaryWindow->lock();
+ QSize size = primaryWindow->scheduledResize();
+ if (size.isValid()) {
+ QRect geometry(QPoint(0, 0), size);
+ primaryWindow->setGeometry(geometry);
+ primaryWindow->scheduleResize(QSize());
+ }
+ primaryWindow->unlock();
+ }
+}
+
+QT_END_NAMESPACE
diff --git a/src/plugins/platforms/android/src/opengl/qandroidopenglcontext.h b/src/plugins/platforms/android/src/opengl/qandroidopenglcontext.h
new file mode 100644
index 0000000000..c4c5a430ad
--- /dev/null
+++ b/src/plugins/platforms/android/src/opengl/qandroidopenglcontext.h
@@ -0,0 +1,68 @@
+/****************************************************************************
+**
+** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the plugins of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Digia. For licensing terms and
+** conditions see http://qt.digia.com/licensing. For further information
+** use the contact form at http://qt.digia.com/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Digia gives you certain additional
+** rights. These rights are described in the Digia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QANDROIDOPENGLCONTEXT_H
+#define QANDROIDOPENGLCONTEXT_H
+
+#include <QtCore/qreadwritelock.h>
+#include "qeglfscontext.h"
+
+QT_BEGIN_NAMESPACE
+
+class QAndroidPlatformIntegration;
+class QAndroidOpenGLContext : public QEglFSContext
+{
+public:
+ QAndroidOpenGLContext(const QAndroidPlatformIntegration *integration,
+ const QSurfaceFormat &format,
+ QPlatformOpenGLContext *share,
+ EGLDisplay display,
+ EGLenum eglApi = EGL_OPENGL_ES_API);
+
+ void swapBuffers(QPlatformSurface *surface);
+
+private:
+ const QAndroidPlatformIntegration *m_platformIntegration;
+};
+
+QT_END_NAMESPACE
+
+#endif // QANDROIDOPENGLCONTEXT_H
diff --git a/src/plugins/platforms/android/src/opengl/qandroidopenglplatformwindow.cpp b/src/plugins/platforms/android/src/opengl/qandroidopenglplatformwindow.cpp
new file mode 100644
index 0000000000..15c6559157
--- /dev/null
+++ b/src/plugins/platforms/android/src/opengl/qandroidopenglplatformwindow.cpp
@@ -0,0 +1,72 @@
+/****************************************************************************
+**
+** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the plugins of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Digia. For licensing terms and
+** conditions see http://qt.digia.com/licensing. For further information
+** use the contact form at http://qt.digia.com/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Digia gives you certain additional
+** rights. These rights are described in the Digia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qandroidopenglplatformwindow.h"
+#include "androidjnimain.h"
+#include <qpa/qwindowsysteminterface.h>
+
+QT_BEGIN_NAMESPACE
+
+QAndroidOpenGLPlatformWindow::QAndroidOpenGLPlatformWindow(QWindow *window)
+ : QEglFSWindow(window)
+{
+}
+
+bool QAndroidOpenGLPlatformWindow::isExposed() const
+{
+ return QtAndroid::nativeWindow(false) != 0 && QEglFSWindow::isExposed();
+}
+
+void QAndroidOpenGLPlatformWindow::invalidateSurface()
+{
+ QWindowSystemInterface::handleExposeEvent(window(), QRegion()); // Obscure event
+ QWindowSystemInterface::flushWindowSystemEvents();
+ QEglFSWindow::invalidateSurface();
+}
+
+void QAndroidOpenGLPlatformWindow::resetSurface()
+{
+ QEglFSWindow::resetSurface();
+ QWindowSystemInterface::handleExposeEvent(window(), QRegion(geometry())); // Expose event
+ QWindowSystemInterface::flushWindowSystemEvents();
+}
+
+QT_END_NAMESPACE
diff --git a/src/plugins/platforms/android/src/opengl/qandroidopenglplatformwindow.h b/src/plugins/platforms/android/src/opengl/qandroidopenglplatformwindow.h
new file mode 100644
index 0000000000..b835cb3246
--- /dev/null
+++ b/src/plugins/platforms/android/src/opengl/qandroidopenglplatformwindow.h
@@ -0,0 +1,73 @@
+/****************************************************************************
+**
+** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the plugins of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Digia. For licensing terms and
+** conditions see http://qt.digia.com/licensing. For further information
+** use the contact form at http://qt.digia.com/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Digia gives you certain additional
+** rights. These rights are described in the Digia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QANDROIDOPENGLPLATFORMWINDOW_H
+#define QANDROIDOPENGLPLATFORMWINDOW_H
+
+#include "qeglfswindow.h"
+#include <QtCore/qmutex.h>
+
+QT_BEGIN_NAMESPACE
+
+class QAndroidOpenGLPlatformWindow : public QEglFSWindow
+{
+public:
+ QAndroidOpenGLPlatformWindow(QWindow *window);
+
+ QSize scheduledResize() const { return m_scheduledResize; }
+ void scheduleResize(const QSize &size) { m_scheduledResize = size; }
+
+ void lock() { m_lock.lock(); }
+ void unlock() { m_lock.unlock(); }
+
+ bool isExposed() const;
+
+ void invalidateSurface();
+ void resetSurface();
+
+private:
+ QSize m_scheduledResize;
+ QMutex m_lock;
+};
+
+QT_END_NAMESPACE
+
+#endif // QANDROIDOPENGLPLATFORMWINDOW_H
diff --git a/src/plugins/platforms/android/src/opengl/qeglfshooks_android.cpp b/src/plugins/platforms/android/src/opengl/qeglfshooks_android.cpp
new file mode 100644
index 0000000000..cd415843a7
--- /dev/null
+++ b/src/plugins/platforms/android/src/opengl/qeglfshooks_android.cpp
@@ -0,0 +1,132 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 Digia Plc and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the plugins of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Digia. For licensing terms and
+** conditions see http://qt.digia.com/licensing. For further information
+** use the contact form at http://qt.digia.com/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Digia gives you certain additional
+** rights. These rights are described in the Digia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qeglfshooks.h"
+#include "androidjnimain.h"
+#include "qandroidplatformintegration.h"
+
+#include <android/native_window.h>
+#include <jni.h>
+
+QT_BEGIN_NAMESPACE
+
+class QEglFSAndroidHooks: public QEglFSHooks
+{
+public:
+ void platformInit();
+ void platformDestroy();
+ EGLNativeDisplayType platformDisplay() const;
+ QSize screenSize() const;
+ QSizeF physicalScreenSize() const;
+ int screenDepth() const;
+ QSurfaceFormat surfaceFormatFor(const QSurfaceFormat &inputFormat) const;
+ EGLNativeWindowType createNativeWindow(const QSize &size, const QSurfaceFormat &format);
+ void destroyNativeWindow(EGLNativeWindowType window);
+ bool hasCapability(QPlatformIntegration::Capability cap) const;
+};
+
+void QEglFSAndroidHooks::platformInit()
+{
+}
+
+void QEglFSAndroidHooks::platformDestroy()
+{
+}
+
+EGLNativeDisplayType QEglFSAndroidHooks::platformDisplay() const
+{
+ return EGL_DEFAULT_DISPLAY;
+}
+
+QSize QEglFSAndroidHooks::screenSize() const
+{
+ return QtAndroid::nativeWindowSize();
+}
+
+QSizeF QEglFSAndroidHooks::physicalScreenSize() const
+{
+ return QSizeF(QAndroidPlatformIntegration::m_defaultPhysicalSizeWidth, QAndroidPlatformIntegration::m_defaultPhysicalSizeHeight);
+}
+
+
+EGLNativeWindowType QEglFSAndroidHooks::createNativeWindow(const QSize &size, const QSurfaceFormat &format)
+{
+ ANativeWindow *window = QtAndroid::nativeWindow();
+ if (window != 0)
+ ANativeWindow_acquire(window);
+
+ return window;
+}
+
+void QEglFSAndroidHooks::destroyNativeWindow(EGLNativeWindowType window)
+{
+ ANativeWindow_release(window);
+}
+
+bool QEglFSAndroidHooks::hasCapability(QPlatformIntegration::Capability capability) const
+{
+ switch (capability) {
+ case QPlatformIntegration::OpenGL: return true;
+ case QPlatformIntegration::ThreadedOpenGL: return true;
+ default: return false;
+ };
+}
+
+int QEglFSAndroidHooks::screenDepth() const
+{
+ // ### Hardcoded
+ return 32;
+}
+
+QSurfaceFormat QEglFSAndroidHooks::surfaceFormatFor(const QSurfaceFormat &inputFormat) const
+{
+ QSurfaceFormat ret(inputFormat);
+ ret.setAlphaBufferSize(8);
+ ret.setRedBufferSize(8);
+ ret.setGreenBufferSize(8);
+ ret.setBlueBufferSize(8);
+ return ret;
+}
+
+static QEglFSAndroidHooks eglFSAndroidHooks;
+QEglFSHooks *platformHooks = &eglFSAndroidHooks;
+
+QT_END_NAMESPACE
diff --git a/src/plugins/platforms/android/src/qandroidassetsfileenginehandler.cpp b/src/plugins/platforms/android/src/qandroidassetsfileenginehandler.cpp
new file mode 100644
index 0000000000..f3cb2586cc
--- /dev/null
+++ b/src/plugins/platforms/android/src/qandroidassetsfileenginehandler.cpp
@@ -0,0 +1,288 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 BogDan Vatra <bogdan@kde.org>
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the plugins of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Digia. For licensing terms and
+** conditions see http://qt.digia.com/licensing. For further information
+** use the contact form at http://qt.digia.com/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Digia gives you certain additional
+** rights. These rights are described in the Digia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qandroidassetsfileenginehandler.h"
+#include "androidjnimain.h"
+
+#include <QCoreApplication>
+
+class AndroidAbstractFileEngineIterator: public QAbstractFileEngineIterator
+{
+public:
+ AndroidAbstractFileEngineIterator(QDir::Filters filters,
+ const QStringList &nameFilters,
+ AAssetDir *asset,
+ const QString &path)
+ : QAbstractFileEngineIterator(filters, nameFilters)
+ {
+ AAssetDir_rewind(asset);
+ const char *fileName;
+ while ((fileName = AAssetDir_getNextFileName(asset)))
+ m_items << fileName;
+ m_index = -1;
+ m_path = path;
+ }
+
+ virtual QFileInfo currentFileInfo() const
+ {
+ return QFileInfo(currentFilePath());
+ }
+
+ virtual QString currentFileName() const
+ {
+ if (m_index < 0 || m_index >= m_items.size())
+ return QString();
+ return m_items[m_index];
+ }
+
+ virtual QString currentFilePath() const
+ {
+ return m_path + currentFileName();
+ }
+
+ virtual bool hasNext() const
+ {
+ return m_items.size() && (m_index < m_items.size() - 1);
+ }
+
+ virtual QString next()
+ {
+ if (!hasNext())
+ return QString();
+ m_index++;
+ return currentFileName();
+ }
+
+private:
+ QString m_path;
+ QStringList m_items;
+ int m_index;
+};
+
+class AndroidAbstractFileEngine: public QAbstractFileEngine
+{
+public:
+ explicit AndroidAbstractFileEngine(AAsset *asset, const QString &fileName)
+ {
+ m_assetDir = 0;
+ m_assetFile = asset;
+ m_fileName = fileName;
+ }
+
+ explicit AndroidAbstractFileEngine(AAssetDir *asset, const QString &fileName)
+ {
+ m_assetFile = 0;
+ m_assetDir = asset;
+ m_fileName = fileName;
+ if (!m_fileName.endsWith(QChar(QLatin1Char('/'))))
+ m_fileName += "/";
+ }
+
+ ~AndroidAbstractFileEngine()
+ {
+ close();
+ if (m_assetDir)
+ AAssetDir_close(m_assetDir);
+ }
+
+ virtual bool open(QIODevice::OpenMode openMode)
+ {
+ if (m_assetFile)
+ return openMode & QIODevice::ReadOnly;
+ return false;
+ }
+
+ virtual bool close()
+ {
+ if (m_assetFile) {
+ AAsset_close(m_assetFile);
+ m_assetFile = 0;
+ return true;
+ }
+ return false;
+ }
+
+ virtual qint64 size() const
+ {
+ if (m_assetFile)
+ return AAsset_getLength(m_assetFile);
+ return -1;
+ }
+
+ virtual qint64 pos() const
+ {
+ if (m_assetFile)
+ return AAsset_seek(m_assetFile, 0, SEEK_CUR);
+ return -1;
+ }
+
+ virtual bool seek(qint64 pos)
+ {
+ if (m_assetFile)
+ return pos == AAsset_seek(m_assetFile, pos, SEEK_SET);
+ return false;
+ }
+
+ virtual qint64 read(char *data, qint64 maxlen)
+ {
+ if (m_assetFile)
+ return AAsset_read(m_assetFile, data, maxlen);
+ return -1;
+ }
+
+ virtual bool isSequential() const
+ {
+ return false;
+ }
+
+ virtual bool caseSensitive() const
+ {
+ return true;
+ }
+
+ virtual bool isRelativePath() const
+ {
+ return false;
+ }
+
+ virtual FileFlags fileFlags(FileFlags type = FileInfoAll) const
+ {
+ FileFlags flags(ReadOwnerPerm|ReadUserPerm|ReadGroupPerm|ReadOtherPerm|ExistsFlag);
+ if (m_assetFile)
+ flags |= FileType;
+ if (m_assetDir)
+ flags |= DirectoryType;
+
+ return type & flags;
+ }
+
+ virtual QString fileName(FileName file = DefaultName) const
+ {
+ int pos;
+ switch (file) {
+ case DefaultName:
+ case AbsoluteName:
+ case CanonicalName:
+ return m_fileName;
+ case BaseName:
+ if ((pos = m_fileName.lastIndexOf(QChar(QLatin1Char('/')))) != -1)
+ return m_fileName.mid(pos);
+ else
+ return m_fileName;
+ case PathName:
+ case AbsolutePathName:
+ case CanonicalPathName:
+ if ((pos = m_fileName.lastIndexOf(QChar(QLatin1Char('/')))) != -1)
+ return m_fileName.left(pos);
+ else
+ return m_fileName;
+ default:
+ return QString();
+ }
+ }
+
+ virtual void setFileName(const QString &file)
+ {
+ if (file == m_fileName)
+ return;
+
+ m_fileName = file;
+ if (!m_fileName.endsWith(QChar(QLatin1Char('/'))))
+ m_fileName += "/";
+
+ close();
+ }
+
+ virtual Iterator *beginEntryList(QDir::Filters filters, const QStringList &filterNames)
+ {
+ if (m_assetDir)
+ return new AndroidAbstractFileEngineIterator(filters, filterNames, m_assetDir, m_fileName);
+ return 0;
+ }
+
+private:
+ AAsset *m_assetFile;
+ AAssetDir *m_assetDir;
+ QString m_fileName;
+};
+
+
+AndroidAssetsFileEngineHandler::AndroidAssetsFileEngineHandler()
+{
+ m_assetManager = QtAndroid::assetManager();
+}
+
+AndroidAssetsFileEngineHandler::~AndroidAssetsFileEngineHandler()
+{
+}
+
+QAbstractFileEngine * AndroidAssetsFileEngineHandler::create(const QString &fileName) const
+{
+ if (fileName.isEmpty())
+ return 0;
+
+ if (!fileName.startsWith(QLatin1String("assets:/")))
+ return 0;
+
+ int prefixSize=8;
+
+ m_path.clear();
+ if (!fileName.endsWith(QLatin1Char('/'))) {
+ m_path = fileName.toUtf8();
+ AAsset *asset = AAssetManager_open(m_assetManager,
+ m_path.constData() + prefixSize,
+ AASSET_MODE_BUFFER);
+ if (asset)
+ return new AndroidAbstractFileEngine(asset, fileName);
+ }
+
+ if (!m_path.size())
+ m_path = fileName.left(fileName.length() - 1).toUtf8();
+
+ AAssetDir *assetDir = AAssetManager_openDir(m_assetManager, m_path.constData() + prefixSize);
+ if (assetDir) {
+ if (AAssetDir_getNextFileName(assetDir))
+ return new AndroidAbstractFileEngine(assetDir, fileName);
+ else
+ AAssetDir_close(assetDir);
+ }
+ return 0;
+}
diff --git a/src/plugins/platforms/android/src/qandroidassetsfileenginehandler.h b/src/plugins/platforms/android/src/qandroidassetsfileenginehandler.h
new file mode 100644
index 0000000000..9bff6a012e
--- /dev/null
+++ b/src/plugins/platforms/android/src/qandroidassetsfileenginehandler.h
@@ -0,0 +1,60 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 BogDan Vatra <bogdan@kde.org>
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the plugins of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Digia. For licensing terms and
+** conditions see http://qt.digia.com/licensing. For further information
+** use the contact form at http://qt.digia.com/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Digia gives you certain additional
+** rights. These rights are described in the Digia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QANDROIDASSETSFILEENGINEHANDLER_H
+#define QANDROIDASSETSFILEENGINEHANDLER_H
+
+#include <QtCore/private/qabstractfileengine_p.h>
+#include <android/asset_manager.h>
+
+class AndroidAssetsFileEngineHandler: public QAbstractFileEngineHandler
+{
+public:
+ AndroidAssetsFileEngineHandler();
+ virtual ~AndroidAssetsFileEngineHandler();
+ QAbstractFileEngine *create(const QString &fileName) const;
+
+private:
+ AAssetManager *m_assetManager;
+ mutable QByteArray m_path;
+};
+
+#endif // QANDROIDASSETSFILEENGINEHANDLER_H
diff --git a/src/plugins/platforms/android/src/qandroidinputcontext.cpp b/src/plugins/platforms/android/src/qandroidinputcontext.cpp
new file mode 100644
index 0000000000..37fb605ea8
--- /dev/null
+++ b/src/plugins/platforms/android/src/qandroidinputcontext.cpp
@@ -0,0 +1,644 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 BogDan Vatra <bogdan@kde.org>
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the plugins of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Digia. For licensing terms and
+** conditions see http://qt.digia.com/licensing. For further information
+** use the contact form at http://qt.digia.com/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Digia gives you certain additional
+** rights. These rights are described in the Digia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include <android/log.h>
+
+#include "qandroidinputcontext.h"
+#include "androidjnimain.h"
+#include "androidjniinput.h"
+#include <QDebug>
+#include <qevent.h>
+#include <qguiapplication.h>
+#include <qsharedpointer.h>
+#include <qthread.h>
+#include <qinputmethod.h>
+#include <qwindow.h>
+
+#include <QTextCharFormat>
+
+QT_BEGIN_NAMESPACE
+
+static QAndroidInputContext *m_androidInputContext = 0;
+static char const *const QtNativeInputConnectionClassName = "org/qtproject/qt5/android/QtNativeInputConnection";
+static char const *const QtExtractedTextClassName = "org/qtproject/qt5/android/QtExtractedText";
+static jclass m_extractedTextClass = 0;
+static jmethodID m_classConstructorMethodID = 0;
+static jfieldID m_partialEndOffsetFieldID = 0;
+static jfieldID m_partialStartOffsetFieldID = 0;
+static jfieldID m_selectionEndFieldID = 0;
+static jfieldID m_selectionStartFieldID = 0;
+static jfieldID m_startOffsetFieldID = 0;
+static jfieldID m_textFieldID = 0;
+
+static jboolean commitText(JNIEnv *env, jobject /*thiz*/, jstring text, jint newCursorPosition)
+{
+ if (!m_androidInputContext)
+ return JNI_FALSE;
+
+ jboolean isCopy;
+ const jchar *jstr = env->GetStringChars(text, &isCopy);
+ QString str(reinterpret_cast<const QChar *>(jstr), env->GetStringLength(text));
+ env->ReleaseStringChars(text, jstr);
+
+ return m_androidInputContext->commitText(str, newCursorPosition);
+}
+
+static jboolean deleteSurroundingText(JNIEnv */*env*/, jobject /*thiz*/, jint leftLength, jint rightLength)
+{
+ if (!m_androidInputContext)
+ return JNI_FALSE;
+
+ return m_androidInputContext->deleteSurroundingText(leftLength, rightLength);
+}
+
+static jboolean finishComposingText(JNIEnv */*env*/, jobject /*thiz*/)
+{
+ if (!m_androidInputContext)
+ return JNI_FALSE;
+
+ return m_androidInputContext->finishComposingText();
+}
+
+static jint getCursorCapsMode(JNIEnv */*env*/, jobject /*thiz*/, jint reqModes)
+{
+ if (!m_androidInputContext)
+ return 0;
+
+ return m_androidInputContext->getCursorCapsMode(reqModes);
+}
+
+static jobject getExtractedText(JNIEnv *env, jobject /*thiz*/, int hintMaxChars, int hintMaxLines, jint flags)
+{
+ if (!m_androidInputContext)
+ return 0;
+
+ const QAndroidInputContext::ExtractedText &extractedText =
+ m_androidInputContext->getExtractedText(hintMaxChars, hintMaxLines, flags);
+
+ jobject object = env->NewObject(m_extractedTextClass, m_classConstructorMethodID);
+ env->SetIntField(object, m_partialStartOffsetFieldID, extractedText.partialStartOffset);
+ env->SetIntField(object, m_partialEndOffsetFieldID, extractedText.partialEndOffset);
+ env->SetIntField(object, m_selectionStartFieldID, extractedText.selectionStart);
+ env->SetIntField(object, m_selectionEndFieldID, extractedText.selectionEnd);
+ env->SetIntField(object, m_startOffsetFieldID, extractedText.startOffset);
+ env->SetObjectField(object,
+ m_textFieldID,
+ env->NewString(reinterpret_cast<const jchar *>(extractedText.text.constData()),
+ jsize(extractedText.text.length())));
+
+ return object;
+}
+
+static jstring getSelectedText(JNIEnv *env, jobject /*thiz*/, jint flags)
+{
+ if (!m_androidInputContext)
+ return 0;
+
+ const QString &text = m_androidInputContext->getSelectedText(flags);
+ return env->NewString(reinterpret_cast<const jchar *>(text.constData()), jsize(text.length()));
+}
+
+static jstring getTextAfterCursor(JNIEnv *env, jobject /*thiz*/, jint length, jint flags)
+{
+ if (!m_androidInputContext)
+ return 0;
+
+ const QString &text = m_androidInputContext->getTextAfterCursor(length, flags);
+ return env->NewString(reinterpret_cast<const jchar *>(text.constData()), jsize(text.length()));
+}
+
+static jstring getTextBeforeCursor(JNIEnv *env, jobject /*thiz*/, jint length, jint flags)
+{
+ if (!m_androidInputContext)
+ return 0;
+
+ const QString &text = m_androidInputContext->getTextBeforeCursor(length, flags);
+ return env->NewString(reinterpret_cast<const jchar *>(text.constData()), jsize(text.length()));
+}
+
+static jboolean setComposingText(JNIEnv *env, jobject /*thiz*/, jstring text, jint newCursorPosition)
+{
+ if (!m_androidInputContext)
+ return JNI_FALSE;
+
+ jboolean isCopy;
+ const jchar *jstr = env->GetStringChars(text, &isCopy);
+ QString str(reinterpret_cast<const QChar *>(jstr), env->GetStringLength(text));
+ env->ReleaseStringChars(text, jstr);
+
+ return m_androidInputContext->setComposingText(str, newCursorPosition);
+}
+
+static jboolean setSelection(JNIEnv */*env*/, jobject /*thiz*/, jint start, jint end)
+{
+ if (!m_androidInputContext)
+ return JNI_FALSE;
+
+ return m_androidInputContext->setSelection(start, end);
+}
+
+static jboolean selectAll(JNIEnv */*env*/, jobject /*thiz*/)
+{
+ if (!m_androidInputContext)
+ return JNI_FALSE;
+
+ return m_androidInputContext->selectAll();
+}
+
+static jboolean cut(JNIEnv */*env*/, jobject /*thiz*/)
+{
+ if (!m_androidInputContext)
+ return JNI_FALSE;
+
+ return m_androidInputContext->cut();
+}
+
+static jboolean copy(JNIEnv */*env*/, jobject /*thiz*/)
+{
+ if (!m_androidInputContext)
+ return JNI_FALSE;
+
+ return m_androidInputContext->copy();
+}
+
+static jboolean copyURL(JNIEnv */*env*/, jobject /*thiz*/)
+{
+ if (!m_androidInputContext)
+ return JNI_FALSE;
+
+ return m_androidInputContext->copyURL();
+}
+
+static jboolean paste(JNIEnv */*env*/, jobject /*thiz*/)
+{
+ if (!m_androidInputContext)
+ return JNI_FALSE;
+
+ return m_androidInputContext->paste();
+}
+
+
+static JNINativeMethod methods[] = {
+ {"commitText", "(Ljava/lang/String;I)Z", (void *)commitText},
+ {"deleteSurroundingText", "(II)Z", (void *)deleteSurroundingText},
+ {"finishComposingText", "()Z", (void *)finishComposingText},
+ {"getCursorCapsMode", "(I)I", (void *)getCursorCapsMode},
+ {"getExtractedText", "(III)Lorg/qtproject/qt5/android/QtExtractedText;", (void *)getExtractedText},
+ {"getSelectedText", "(I)Ljava/lang/String;", (void *)getSelectedText},
+ {"getTextAfterCursor", "(II)Ljava/lang/String;", (void *)getTextAfterCursor},
+ {"getTextBeforeCursor", "(II)Ljava/lang/String;", (void *)getTextBeforeCursor},
+ {"setComposingText", "(Ljava/lang/String;I)Z", (void *)setComposingText},
+ {"setSelection", "(II)Z", (void *)setSelection},
+ {"selectAll", "()Z", (void *)selectAll},
+ {"cut", "()Z", (void *)cut},
+ {"copy", "()Z", (void *)copy},
+ {"copyURL", "()Z", (void *)copyURL},
+ {"paste", "()Z", (void *)paste}
+};
+
+
+QAndroidInputContext::QAndroidInputContext():QPlatformInputContext()
+{
+ JNIEnv *env = 0;
+ if (QtAndroid::javaVM()->AttachCurrentThread(&env, NULL) < 0) {
+ qCritical() << "AttachCurrentThread failed";
+ return;
+ }
+
+ jclass clazz = QtAndroid::findClass(QtNativeInputConnectionClassName, env);
+ if (clazz == NULL) {
+ qCritical() << "Native registration unable to find class '"
+ << QtNativeInputConnectionClassName
+ << "'";
+ return;
+ }
+
+ if (env->RegisterNatives(clazz, methods, sizeof(methods) / sizeof(methods[0])) < 0) {
+ qCritical() << "RegisterNatives failed for '"
+ << QtNativeInputConnectionClassName
+ << "'";
+ return;
+ }
+
+ clazz = QtAndroid::findClass(QtExtractedTextClassName, env);
+ if (clazz == NULL) {
+ qCritical() << "Native registration unable to find class '"
+ << QtExtractedTextClassName
+ << "'";
+ return;
+ }
+
+ m_extractedTextClass = static_cast<jclass>(env->NewGlobalRef(clazz));
+ m_classConstructorMethodID = env->GetMethodID(m_extractedTextClass, "<init>", "()V");
+ if (m_classConstructorMethodID == NULL) {
+ qCritical() << "GetMethodID failed";
+ return;
+ }
+
+ m_partialEndOffsetFieldID = env->GetFieldID(m_extractedTextClass, "partialEndOffset", "I");
+ if (m_partialEndOffsetFieldID == NULL) {
+ qCritical() << "Can't find field partialEndOffset";
+ return;
+ }
+
+ m_partialStartOffsetFieldID = env->GetFieldID(m_extractedTextClass, "partialStartOffset", "I");
+ if (m_partialStartOffsetFieldID == NULL) {
+ qCritical() << "Can't find field partialStartOffset";
+ return;
+ }
+
+ m_selectionEndFieldID = env->GetFieldID(m_extractedTextClass, "selectionEnd", "I");
+ if (m_selectionEndFieldID == NULL) {
+ qCritical() << "Can't find field selectionEnd";
+ return;
+ }
+
+ m_selectionStartFieldID = env->GetFieldID(m_extractedTextClass, "selectionStart", "I");
+ if (m_selectionStartFieldID == NULL) {
+ qCritical() << "Can't find field selectionStart";
+ return;
+ }
+
+ m_startOffsetFieldID = env->GetFieldID(m_extractedTextClass, "startOffset", "I");
+ if (m_startOffsetFieldID == NULL) {
+ qCritical() << "Can't find field startOffset";
+ return;
+ }
+
+ m_textFieldID = env->GetFieldID(m_extractedTextClass, "text", "Ljava/lang/String;");
+ if (m_textFieldID == NULL) {
+ qCritical() << "Can't find field text";
+ return;
+ }
+ qRegisterMetaType<QInputMethodEvent *>("QInputMethodEvent*");
+ qRegisterMetaType<QInputMethodQueryEvent *>("QInputMethodQueryEvent*");
+ m_androidInputContext = this;
+}
+
+QAndroidInputContext::~QAndroidInputContext()
+{
+ m_androidInputContext = 0;
+ m_extractedTextClass = 0;
+ m_partialEndOffsetFieldID = 0;
+ m_partialStartOffsetFieldID = 0;
+ m_selectionEndFieldID = 0;
+ m_selectionStartFieldID = 0;
+ m_startOffsetFieldID = 0;
+ m_textFieldID = 0;
+}
+
+void QAndroidInputContext::reset()
+{
+ clear();
+ if (qGuiApp->focusObject())
+ QtAndroidInput::resetSoftwareKeyboard();
+ else
+ QtAndroidInput::hideSoftwareKeyboard();
+}
+
+void QAndroidInputContext::commit()
+{
+ finishComposingText();
+
+ QSharedPointer<QInputMethodQueryEvent> query = focusObjectInputMethodQuery();
+ if (!query.isNull()) {
+ const int cursorPos = query->value(Qt::ImCursorPosition).toInt();
+ QtAndroidInput::updateSelection(cursorPos, cursorPos, -1, -1); //selection empty and no pre-edit text
+ }
+}
+
+void QAndroidInputContext::update(Qt::InputMethodQueries queries)
+{
+ QSharedPointer<QInputMethodQueryEvent> query = focusObjectInputMethodQuery(queries);
+ if (query.isNull())
+ return;
+#warning TODO extract the needed data from query
+}
+
+void QAndroidInputContext::invokeAction(QInputMethod::Action action, int cursorPosition)
+{
+#warning TODO Handle at least QInputMethod::ContextMenu action
+ Q_UNUSED(action)
+ Q_UNUSED(cursorPosition)
+
+ if (action == QInputMethod::Click)
+ commit();
+}
+
+QRectF QAndroidInputContext::keyboardRect() const
+{
+ return QPlatformInputContext::keyboardRect();
+}
+
+bool QAndroidInputContext::isAnimating() const
+{
+ return false;
+}
+
+void QAndroidInputContext::showInputPanel()
+{
+ QSharedPointer<QInputMethodQueryEvent> query = focusObjectInputMethodQuery();
+ if (query.isNull())
+ return;
+ QRectF itemRect = qGuiApp->inputMethod()->inputItemRectangle();
+ QRect rect = qGuiApp->inputMethod()->inputItemTransform().mapRect(itemRect).toRect();
+ QWindow *window = qGuiApp->focusWindow();
+ if (window)
+ rect = QRect(window->mapToGlobal(rect.topLeft()), rect.size());
+
+ QtAndroidInput::showSoftwareKeyboard(rect.left(),
+ rect.top(),
+ rect.width(),
+ rect.height(),
+ query->value(Qt::ImHints).toUInt());
+}
+
+void QAndroidInputContext::hideInputPanel()
+{
+ QtAndroidInput::hideSoftwareKeyboard();
+}
+
+bool QAndroidInputContext::isInputPanelVisible() const
+{
+ return QtAndroidInput::isSoftwareKeyboardVisible();
+}
+
+bool QAndroidInputContext::isComposing() const
+{
+ return m_composingText.length();
+}
+
+void QAndroidInputContext::clear()
+{
+ m_composingText.clear();
+ m_extractedText.clear();
+}
+
+void QAndroidInputContext::sendEvent(QObject *receiver, QInputMethodEvent *event)
+{
+ QCoreApplication::sendEvent(receiver, event);
+}
+
+void QAndroidInputContext::sendEvent(QObject *receiver, QInputMethodQueryEvent *event)
+{
+ QCoreApplication::sendEvent(receiver, event);
+}
+
+jboolean QAndroidInputContext::commitText(const QString &text, jint /*newCursorPosition*/)
+{
+ m_composingText = text;
+ return finishComposingText();
+}
+
+jboolean QAndroidInputContext::deleteSurroundingText(jint leftLength, jint rightLength)
+{
+ QSharedPointer<QInputMethodQueryEvent> query = focusObjectInputMethodQuery();
+ if (query.isNull())
+ return JNI_TRUE;
+
+ m_composingText.clear();
+
+ QInputMethodEvent event;
+ event.setCommitString(QString(), -leftLength, leftLength+rightLength);
+ sendInputMethodEvent(&event);
+ clear();
+
+ return JNI_TRUE;
+}
+
+jboolean QAndroidInputContext::finishComposingText()
+{
+ QInputMethodEvent event;
+ event.setCommitString(m_composingText);
+ sendInputMethodEvent(&event);
+ clear();
+
+ return JNI_TRUE;
+}
+
+jint QAndroidInputContext::getCursorCapsMode(jint /*reqModes*/)
+{
+ jint res = 0;
+ QSharedPointer<QInputMethodQueryEvent> query = focusObjectInputMethodQuery();
+ if (query.isNull())
+ return res;
+
+ const uint qtInputMethodHints = query->value(Qt::ImHints).toUInt();
+
+ if (qtInputMethodHints & Qt::ImhPreferUppercase)
+ res = CAP_MODE_SENTENCES;
+
+ if (qtInputMethodHints & Qt::ImhUppercaseOnly)
+ res = CAP_MODE_CHARACTERS;
+
+ return res;
+}
+
+const QAndroidInputContext::ExtractedText &QAndroidInputContext::getExtractedText(jint hintMaxChars, jint /*hintMaxLines*/, jint /*flags*/)
+{
+ QSharedPointer<QInputMethodQueryEvent> query = focusObjectInputMethodQuery();
+ if (query.isNull())
+ return m_extractedText;
+
+ if (hintMaxChars)
+ m_extractedText.text = query->value(Qt::ImSurroundingText).toString().right(hintMaxChars);
+
+ m_extractedText.startOffset = query->value(Qt::ImCursorPosition).toInt();
+ const QString &selection = query->value(Qt::ImCurrentSelection).toString();
+ const int selLen = selection.length();
+ if (selLen) {
+ m_extractedText.selectionStart = query->value(Qt::ImAnchorPosition).toInt();
+ m_extractedText.selectionEnd = m_extractedText.startOffset;
+ }
+
+ return m_extractedText;
+}
+
+QString QAndroidInputContext::getSelectedText(jint /*flags*/)
+{
+ QSharedPointer<QInputMethodQueryEvent> query = focusObjectInputMethodQuery();
+ if (query.isNull())
+ return QString();
+
+ return query->value(Qt::ImCurrentSelection).toString();
+}
+
+QString QAndroidInputContext::getTextAfterCursor(jint length, jint /*flags*/)
+{
+ QSharedPointer<QInputMethodQueryEvent> query = focusObjectInputMethodQuery();
+ if (query.isNull())
+ return QString();
+
+ QString text = query->value(Qt::ImSurroundingText).toString();
+ if (!text.length())
+ return text;
+
+ int cursorPos = query->value(Qt::ImCursorPosition).toInt();
+ return text.mid(cursorPos, length);
+}
+
+QString QAndroidInputContext::getTextBeforeCursor(jint length, jint /*flags*/)
+{
+ QSharedPointer<QInputMethodQueryEvent> query = focusObjectInputMethodQuery();
+ if (query.isNull())
+ return QString();
+
+ QString text = query->value(Qt::ImSurroundingText).toString();
+ if (!text.length())
+ return text;
+
+ int cursorPos = query->value(Qt::ImCursorPosition).toInt();
+ const int wordLeftPos = cursorPos - length;
+ return text.mid(wordLeftPos > 0 ? wordLeftPos : 0, cursorPos);
+}
+
+jboolean QAndroidInputContext::setComposingText(const QString &text, jint newCursorPosition)
+{
+ if (newCursorPosition > 0)
+ newCursorPosition += text.length() - 1;
+ m_composingText = text;
+ QList<QInputMethodEvent::Attribute> attributes;
+ attributes.append(QInputMethodEvent::Attribute(QInputMethodEvent::Cursor,
+ newCursorPosition,
+ 1,
+ QVariant()));
+ // Show compose text underlined
+ QTextCharFormat underlined;
+ underlined.setFontUnderline(true);
+ attributes.append(QInputMethodEvent::Attribute(QInputMethodEvent::TextFormat,0, text.length(),
+ QVariant(underlined)));
+
+ QInputMethodEvent event(m_composingText, attributes);
+ sendInputMethodEvent(&event);
+
+ QSharedPointer<QInputMethodQueryEvent> query = focusObjectInputMethodQuery();
+ if (!query.isNull()) {
+ int cursorPos = query->value(Qt::ImCursorPosition).toInt();
+ int preeditLength = text.length();
+ QtAndroidInput::updateSelection(cursorPos+preeditLength, cursorPos+preeditLength, cursorPos, cursorPos+preeditLength);
+ }
+
+ return JNI_TRUE;
+}
+
+jboolean QAndroidInputContext::setSelection(jint start, jint end)
+{
+ QList<QInputMethodEvent::Attribute> attributes;
+ attributes.append(QInputMethodEvent::Attribute(QInputMethodEvent::Selection,
+ start,
+ end - start,
+ QVariant()));
+
+ QInputMethodEvent event(QString(), attributes);
+ sendInputMethodEvent(&event);
+ return JNI_TRUE;
+}
+
+jboolean QAndroidInputContext::selectAll()
+{
+#warning TODO
+ return JNI_FALSE;
+}
+
+jboolean QAndroidInputContext::cut()
+{
+#warning TODO
+ return JNI_FALSE;
+}
+
+jboolean QAndroidInputContext::copy()
+{
+#warning TODO
+ return JNI_FALSE;
+}
+
+jboolean QAndroidInputContext::copyURL()
+{
+#warning TODO
+ return JNI_FALSE;
+}
+
+jboolean QAndroidInputContext::paste()
+{
+#warning TODO
+ return JNI_FALSE;
+}
+
+QSharedPointer<QInputMethodQueryEvent> QAndroidInputContext::focusObjectInputMethodQuery(Qt::InputMethodQueries queries)
+{
+#warning TODO make qGuiApp->focusObject() thread safe !!!
+ QObject *focusObject = qGuiApp->focusObject();
+ if (!focusObject)
+ return QSharedPointer<QInputMethodQueryEvent>();
+
+ QSharedPointer<QInputMethodQueryEvent> ret = QSharedPointer<QInputMethodQueryEvent>(new QInputMethodQueryEvent(queries));
+ if (qGuiApp->thread()==QThread::currentThread()) {
+ QCoreApplication::sendEvent(focusObject, ret.data());
+ } else {
+ QMetaObject::invokeMethod(this,
+ "sendEvent",
+ Qt::BlockingQueuedConnection,
+ Q_ARG(QObject*, focusObject),
+ Q_ARG(QInputMethodQueryEvent*, ret.data()));
+ }
+
+ return ret;
+}
+
+void QAndroidInputContext::sendInputMethodEvent(QInputMethodEvent *event)
+{
+#warning TODO make qGuiApp->focusObject() thread safe !!!
+ QObject *focusObject = qGuiApp->focusObject();
+ if (!focusObject)
+ return;
+
+ if (qGuiApp->thread() == QThread::currentThread()) {
+ QCoreApplication::sendEvent(focusObject, event);
+ } else {
+ QMetaObject::invokeMethod(this,
+ "sendEvent",
+ Qt::BlockingQueuedConnection,
+ Q_ARG(QObject*, focusObject),
+ Q_ARG(QInputMethodEvent*, event));
+ }
+}
+
+QT_END_NAMESPACE
diff --git a/src/plugins/platforms/android/src/qandroidinputcontext.h b/src/plugins/platforms/android/src/qandroidinputcontext.h
new file mode 100644
index 0000000000..e2b8107044
--- /dev/null
+++ b/src/plugins/platforms/android/src/qandroidinputcontext.h
@@ -0,0 +1,130 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 BogDan Vatra <bogdan@kde.org>
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the plugins of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Digia. For licensing terms and
+** conditions see http://qt.digia.com/licensing. For further information
+** use the contact form at http://qt.digia.com/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Digia gives you certain additional
+** rights. These rights are described in the Digia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef ANDROIDINPUTCONTEXT_H
+#define ANDROIDINPUTCONTEXT_H
+
+#include <qpa/qplatforminputcontext.h>
+#include <jni.h>
+#include <qevent.h>
+
+QT_BEGIN_NAMESPACE
+
+class QAndroidInputContext: public QPlatformInputContext
+{
+ Q_OBJECT
+ enum CapsMode
+ {
+ CAP_MODE_CHARACTERS = 0x00001000,
+ CAP_MODE_SENTENCES = 0x00004000,
+ CAP_MODE_WORDS = 0x00002000
+ };
+
+public:
+ struct ExtractedText
+ {
+ ExtractedText() { clear(); }
+
+ void clear()
+ {
+ partialEndOffset = partialStartOffset = selectionEnd = selectionStart = startOffset = -1;
+ text.clear();
+ }
+
+ int partialEndOffset;
+ int partialStartOffset;
+ int selectionEnd;
+ int selectionStart;
+ int startOffset;
+ QString text;
+ };
+
+public:
+ QAndroidInputContext();
+ ~QAndroidInputContext();
+ bool isValid() const { return true; }
+
+ void reset();
+ void commit();
+ void update(Qt::InputMethodQueries queries);
+ void invokeAction(QInputMethod::Action action, int cursorPosition);
+ QRectF keyboardRect() const;
+ bool isAnimating() const;
+ void showInputPanel();
+ void hideInputPanel();
+ bool isInputPanelVisible() const;
+
+ bool isComposing() const;
+ void clear();
+
+ //---------------//
+ jboolean commitText(const QString &text, jint newCursorPosition);
+ jboolean deleteSurroundingText(jint leftLength, jint rightLength);
+ jboolean finishComposingText();
+ jint getCursorCapsMode(jint reqModes);
+ const ExtractedText &getExtractedText(jint hintMaxChars, jint hintMaxLines, jint flags);
+ QString getSelectedText(jint flags);
+ QString getTextAfterCursor(jint length, jint flags);
+ QString getTextBeforeCursor(jint length, jint flags);
+ jboolean setComposingText(const QString &text, jint newCursorPosition);
+ jboolean setSelection(jint start, jint end);
+ jboolean selectAll();
+ jboolean cut();
+ jboolean copy();
+ jboolean copyURL();
+ jboolean paste();
+
+private:
+ QSharedPointer<QInputMethodQueryEvent> focusObjectInputMethodQuery(Qt::InputMethodQueries queries = Qt::ImQueryAll);
+ void sendInputMethodEvent(QInputMethodEvent *event);
+
+private slots:
+ virtual void sendEvent(QObject *receiver, QInputMethodEvent *event);
+ virtual void sendEvent(QObject *receiver, QInputMethodQueryEvent *event);
+
+private:
+ ExtractedText m_extractedText;
+ QString m_composingText;
+};
+
+QT_END_NAMESPACE
+
+#endif // ANDROIDINPUTCONTEXT_H
diff --git a/src/plugins/platforms/android/src/qandroidplatformclipboard.cpp b/src/plugins/platforms/android/src/qandroidplatformclipboard.cpp
new file mode 100644
index 0000000000..bc48b4935b
--- /dev/null
+++ b/src/plugins/platforms/android/src/qandroidplatformclipboard.cpp
@@ -0,0 +1,79 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 BogDan Vatra <bogdan@kde.org>
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the plugins of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Digia. For licensing terms and
+** conditions see http://qt.digia.com/licensing. For further information
+** use the contact form at http://qt.digia.com/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Digia gives you certain additional
+** rights. These rights are described in the Digia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qandroidplatformclipboard.h"
+#include "androidjniclipboard.h"
+#ifndef QT_NO_CLIPBOARD
+#include <QMimeData>
+
+QT_BEGIN_NAMESPACE
+
+QAndroidPlatformClipboard::QAndroidPlatformClipboard()
+{
+ QtAndroidClipboard::setClipboardListener(this);
+}
+
+QMimeData *QAndroidPlatformClipboard::mimeData(QClipboard::Mode mode)
+{
+ if (QClipboard::Clipboard != mode || !QtAndroidClipboard::hasClipboardText())
+ return 0;
+
+ QMimeData *mimeData = new QMimeData();
+ mimeData->setText(QtAndroidClipboard::clipboardText());
+ return mimeData;
+}
+
+void QAndroidPlatformClipboard::setMimeData(QMimeData *data, QClipboard::Mode mode)
+{
+ if (!data || !data->hasText() || QClipboard::Clipboard != mode)
+ return;
+
+ QtAndroidClipboard::setClipboardText(data->text());
+}
+
+bool QAndroidPlatformClipboard::supportsMode(QClipboard::Mode mode) const
+{
+ return QClipboard::Clipboard == mode;
+}
+
+QT_END_NAMESPACE
+
+#endif // QT_NO_CLIPBOARD
diff --git a/src/plugins/platforms/android/src/qandroidplatformclipboard.h b/src/plugins/platforms/android/src/qandroidplatformclipboard.h
new file mode 100644
index 0000000000..644f326934
--- /dev/null
+++ b/src/plugins/platforms/android/src/qandroidplatformclipboard.h
@@ -0,0 +1,63 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 BogDan Vatra <bogdan@kde.org>
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the plugins of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Digia. For licensing terms and
+** conditions see http://qt.digia.com/licensing. For further information
+** use the contact form at http://qt.digia.com/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Digia gives you certain additional
+** rights. These rights are described in the Digia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QANDROIDPLATFORMCLIPBOARD_H
+#define QANDROIDPLATFORMCLIPBOARD_H
+
+#include <qpa/qplatformclipboard.h>
+
+#ifndef QT_NO_CLIPBOARD
+QT_BEGIN_NAMESPACE
+
+class QAndroidPlatformClipboard: public QPlatformClipboard
+{
+public:
+ QAndroidPlatformClipboard();
+
+ virtual QMimeData *mimeData(QClipboard::Mode mode = QClipboard::Clipboard);
+ virtual void setMimeData(QMimeData *data, QClipboard::Mode mode = QClipboard::Clipboard);
+ virtual bool supportsMode(QClipboard::Mode mode) const;
+};
+
+QT_END_NAMESPACE
+#endif // QT_NO_CLIPBOARD
+
+#endif // QANDROIDPLATFORMCLIPBOARD_H
diff --git a/src/plugins/platforms/android/src/qandroidplatformfontdatabase.cpp b/src/plugins/platforms/android/src/qandroidplatformfontdatabase.cpp
new file mode 100644
index 0000000000..7f68b44ed8
--- /dev/null
+++ b/src/plugins/platforms/android/src/qandroidplatformfontdatabase.cpp
@@ -0,0 +1,79 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 BogDan Vatra <bogdan@kde.org>
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the plugins of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Digia. For licensing terms and
+** conditions see http://qt.digia.com/licensing. For further information
+** use the contact form at http://qt.digia.com/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Digia gives you certain additional
+** rights. These rights are described in the Digia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include <QDir>
+
+#include "qandroidplatformfontdatabase.h"
+
+QString QAndroidPlatformFontDatabase::fontDir() const
+{
+ return QLatin1String("/system/fonts");
+}
+
+void QAndroidPlatformFontDatabase::populateFontDatabase()
+{
+ QString fontpath = fontDir();
+
+ if (!QFile::exists(fontpath)) {
+ qFatal("QFontDatabase: Cannot find font directory %s - is Qt installed correctly?",
+ qPrintable(fontpath));
+ }
+
+ QDir dir(fontpath, QLatin1String("*.ttf"));
+ for (int i = 0; i < int(dir.count()); ++i) {
+ const QByteArray file = QFile::encodeName(dir.absoluteFilePath(dir[i]));
+ addTTFile(QByteArray(), file);
+ }
+}
+
+QStringList QAndroidPlatformFontDatabase::fallbacksForFamily(const QString &family,
+ QFont::Style style,
+ QFont::StyleHint styleHint,
+ QChar::Script script) const
+{
+ Q_UNUSED(family);
+ Q_UNUSED(style);
+ Q_UNUSED(script);
+ if (styleHint == QFont::Monospace)
+ return QString(qgetenv("QT_ANDROID_FONTS_MONOSPACE")).split(";");
+
+ return QString(qgetenv("QT_ANDROID_FONTS")).split(";");
+}
diff --git a/src/plugins/platforms/android/src/qandroidplatformfontdatabase.h b/src/plugins/platforms/android/src/qandroidplatformfontdatabase.h
new file mode 100644
index 0000000000..3cbfe95d36
--- /dev/null
+++ b/src/plugins/platforms/android/src/qandroidplatformfontdatabase.h
@@ -0,0 +1,58 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 BogDan Vatra <bogdan@kde.org>
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the plugins of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Digia. For licensing terms and
+** conditions see http://qt.digia.com/licensing. For further information
+** use the contact form at http://qt.digia.com/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Digia gives you certain additional
+** rights. These rights are described in the Digia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QANDROIDPLATFORMFONTDATABASE_H
+#define QANDROIDPLATFORMFONTDATABASE_H
+
+#include <QtPlatformSupport/private/qbasicfontdatabase_p.h>
+
+class QAndroidPlatformFontDatabase: public QBasicFontDatabase
+{
+public:
+ QString fontDir() const;
+ void populateFontDatabase();
+ QStringList fallbacksForFamily(const QString &family,
+ QFont::Style style,
+ QFont::StyleHint styleHint,
+ QChar::Script script) const;
+};
+
+#endif // QANDROIDPLATFORMFONTDATABASE_H
diff --git a/src/plugins/platforms/android/src/qandroidplatformintegration.cpp b/src/plugins/platforms/android/src/qandroidplatformintegration.cpp
new file mode 100644
index 0000000000..cbd0f26835
--- /dev/null
+++ b/src/plugins/platforms/android/src/qandroidplatformintegration.cpp
@@ -0,0 +1,285 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 BogDan Vatra <bogdan@kde.org>
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the plugins of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Digia. For licensing terms and
+** conditions see http://qt.digia.com/licensing. For further information
+** use the contact form at http://qt.digia.com/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Digia gives you certain additional
+** rights. These rights are described in the Digia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qandroidplatformintegration.h"
+#include "qabstracteventdispatcher.h"
+#include "androidjnimain.h"
+#include <QtGui/private/qpixmap_raster_p.h>
+#include <qpa/qwindowsysteminterface.h>
+#include <QThread>
+#include <qpa/qplatformwindow.h>
+#include "qandroidplatformservices.h"
+#include "qandroidplatformfontdatabase.h"
+#include "qandroidplatformclipboard.h"
+#include <QtPlatformSupport/private/qgenericunixeventdispatcher_p.h>
+
+#ifndef ANDROID_PLUGIN_OPENGL
+# include "qandroidplatformscreen.h"
+# include "qandroidplatformwindow.h"
+# include <QtPlatformSupport/private/qfbbackingstore_p.h>
+#else
+# include "qeglfswindow.h"
+# include "androidjnimenu.h"
+# include "qandroidopenglcontext.h"
+# include "qandroidopenglplatformwindow.h"
+# include "qeglfshooks.h"
+# include <QtGui/qopenglcontext.h>
+#endif
+
+#include "qandroidplatformtheme.h"
+
+QT_BEGIN_NAMESPACE
+
+int QAndroidPlatformIntegration::m_defaultGeometryWidth = 320;
+int QAndroidPlatformIntegration::m_defaultGeometryHeight = 455;
+int QAndroidPlatformIntegration::m_defaultPhysicalSizeWidth = 50;
+int QAndroidPlatformIntegration::m_defaultPhysicalSizeHeight = 71;
+
+void *QAndroidPlatformNativeInterface::nativeResourceForIntegration(const QByteArray &resource)
+{
+ if (resource=="JavaVM")
+ return QtAndroid::javaVM();
+ if (resource == "QtActivity")
+ return QtAndroid::activity();
+
+ return 0;
+}
+
+QAndroidPlatformIntegration::QAndroidPlatformIntegration(const QStringList &paramList)
+ : m_touchDevice(0)
+#ifdef ANDROID_PLUGIN_OPENGL
+ , m_primaryWindow(0)
+#endif
+{
+ Q_UNUSED(paramList);
+
+#ifndef ANDROID_PLUGIN_OPENGL
+ m_eventDispatcher = createUnixEventDispatcher();
+#endif
+
+ m_androidPlatformNativeInterface = new QAndroidPlatformNativeInterface();
+
+#ifndef ANDROID_PLUGIN_OPENGL
+ m_primaryScreen = new QAndroidPlatformScreen();
+ screenAdded(m_primaryScreen);
+ m_primaryScreen->setPhysicalSize(QSize(m_defaultPhysicalSizeWidth, m_defaultPhysicalSizeHeight));
+ m_primaryScreen->setGeometry(QRect(0, 0, m_defaultGeometryWidth, m_defaultGeometryHeight));
+#endif
+
+ m_mainThread = QThread::currentThread();
+ QtAndroid::setAndroidPlatformIntegration(this);
+
+ m_androidFDB = new QAndroidPlatformFontDatabase();
+ m_androidPlatformServices = new QAndroidPlatformServices();
+ m_androidPlatformClipboard = new QAndroidPlatformClipboard();
+}
+
+bool QAndroidPlatformIntegration::hasCapability(Capability cap) const
+{
+ switch (cap) {
+ case ThreadedPixmaps: return true;
+ default:
+#ifndef ANDROID_PLUGIN_OPENGL
+ return QPlatformIntegration::hasCapability(cap);
+#else
+ return QEglFSIntegration::hasCapability(cap);
+#endif
+ }
+}
+
+#ifndef ANDROID_PLUGIN_OPENGL
+QPlatformBackingStore *QAndroidPlatformIntegration::createPlatformBackingStore(QWindow *window) const
+{
+ return new QFbBackingStore(window);
+}
+
+QPlatformWindow *QAndroidPlatformIntegration::createPlatformWindow(QWindow *window) const
+{
+ return new QAndroidPlatformWindow(window);
+}
+
+QAbstractEventDispatcher *QAndroidPlatformIntegration::guiThreadEventDispatcher() const
+{
+ return m_eventDispatcher;
+}
+#else // !ANDROID_PLUGIN_OPENGL
+QPlatformWindow *QAndroidPlatformIntegration::createPlatformWindow(QWindow *window) const
+{
+ if (m_primaryWindow != 0) {
+ qWarning("QAndroidPlatformIntegration::createPlatformWindow: Unsupported case: More than "
+ "one top-level window created.");
+ }
+
+ m_primaryWindow = new QAndroidOpenGLPlatformWindow(window);
+ m_primaryWindow->requestActivateWindow();
+ QtAndroidMenu::setActiveTopLevelWindow(window);
+
+ return m_primaryWindow;
+}
+
+void QAndroidPlatformIntegration::invalidateNativeSurface()
+{
+ if (m_primaryWindow != 0)
+ m_primaryWindow->invalidateSurface();
+}
+
+void QAndroidPlatformIntegration::surfaceChanged()
+{
+ if (m_primaryWindow != 0)
+ m_primaryWindow->resetSurface();
+}
+
+QPlatformOpenGLContext *QAndroidPlatformIntegration::createPlatformOpenGLContext(QOpenGLContext *context) const
+{
+ return new QAndroidOpenGLContext(this,
+ QEglFSHooks::hooks()->surfaceFormatFor(context->format()),
+ context->shareHandle(),
+ display());
+}
+#endif // ANDROID_PLUGIN_OPENGL
+
+QAndroidPlatformIntegration::~QAndroidPlatformIntegration()
+{
+ delete m_androidPlatformNativeInterface;
+ delete m_androidFDB;
+ delete m_touchDevice;
+ QtAndroid::setAndroidPlatformIntegration(NULL);
+}
+QPlatformFontDatabase *QAndroidPlatformIntegration::fontDatabase() const
+{
+ return m_androidFDB;
+}
+
+#ifndef QT_NO_CLIPBOARD
+QPlatformClipboard *QAndroidPlatformIntegration::clipboard() const
+{
+static QAndroidPlatformClipboard *clipboard = 0;
+ if (!clipboard)
+ clipboard = new QAndroidPlatformClipboard;
+
+ return clipboard;
+}
+#endif
+
+QPlatformInputContext *QAndroidPlatformIntegration::inputContext() const
+{
+ return &m_platformInputContext;
+}
+
+QPlatformNativeInterface *QAndroidPlatformIntegration::nativeInterface() const
+{
+ return m_androidPlatformNativeInterface;
+}
+
+QPlatformServices *QAndroidPlatformIntegration::services() const
+{
+ return m_androidPlatformServices;
+}
+
+static const QLatin1String androidThemeName("android");
+QStringList QAndroidPlatformIntegration::themeNames() const
+{
+ return QStringList(QString(androidThemeName));
+}
+
+QPlatformTheme *QAndroidPlatformIntegration::createPlatformTheme(const QString &name) const
+{
+ if (androidThemeName == name)
+ return new QAndroidPlatformTheme;
+
+ return 0;
+}
+
+void QAndroidPlatformIntegration::setDefaultDisplayMetrics(int gw, int gh, int sw, int sh)
+{
+ m_defaultGeometryWidth = gw;
+ m_defaultGeometryHeight = gh;
+ m_defaultPhysicalSizeWidth = sw;
+ m_defaultPhysicalSizeHeight = sh;
+}
+
+void QAndroidPlatformIntegration::setDefaultDesktopSize(int gw, int gh)
+{
+ m_defaultGeometryWidth = gw;
+ m_defaultGeometryHeight = gh;
+}
+
+
+#ifndef ANDROID_PLUGIN_OPENGL
+void QAndroidPlatformIntegration::setDesktopSize(int width, int height)
+{
+ if (m_primaryScreen)
+ QMetaObject::invokeMethod(m_primaryScreen, "setGeometry", Qt::AutoConnection, Q_ARG(QRect, QRect(0,0,width, height)));
+}
+
+void QAndroidPlatformIntegration::setDisplayMetrics(int width, int height)
+{
+ if (m_primaryScreen)
+ QMetaObject::invokeMethod(m_primaryScreen, "setPhysicalSize", Qt::AutoConnection, Q_ARG(QSize, QSize(width, height)));
+}
+#else
+void QAndroidPlatformIntegration::setDesktopSize(int width, int height)
+{
+ m_defaultGeometryWidth = width;
+ m_defaultGeometryHeight = height;
+}
+
+void QAndroidPlatformIntegration::setDisplayMetrics(int width, int height)
+{
+ m_defaultPhysicalSizeWidth = width;
+ m_defaultPhysicalSizeHeight = height;
+}
+
+#endif
+
+void QAndroidPlatformIntegration::pauseApp()
+{
+ if (QAbstractEventDispatcher::instance(m_mainThread))
+ QAbstractEventDispatcher::instance(m_mainThread)->interrupt();
+}
+
+void QAndroidPlatformIntegration::resumeApp()
+{
+ if (QAbstractEventDispatcher::instance(m_mainThread))
+ QAbstractEventDispatcher::instance(m_mainThread)->wakeUp();
+}
+
+QT_END_NAMESPACE
diff --git a/src/plugins/platforms/android/src/qandroidplatformintegration.h b/src/plugins/platforms/android/src/qandroidplatformintegration.h
new file mode 100644
index 0000000000..3f8cc5a809
--- /dev/null
+++ b/src/plugins/platforms/android/src/qandroidplatformintegration.h
@@ -0,0 +1,164 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 BogDan Vatra <bogdan@kde.org>
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the plugins of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Digia. For licensing terms and
+** conditions see http://qt.digia.com/licensing. For further information
+** use the contact form at http://qt.digia.com/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Digia gives you certain additional
+** rights. These rights are described in the Digia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QANDROIDPLATFORMINTERATION_H
+#define QANDROIDPLATFORMINTERATION_H
+
+#include <qpa/qplatformintegration.h>
+#include <qpa/qplatformmenu.h>
+#include <qpa/qplatformnativeinterface.h>
+#include <QtWidgets/QAction>
+
+#include <jni.h>
+#include "qandroidinputcontext.h"
+
+#ifndef ANDROID_PLUGIN_OPENGL
+# include "qandroidplatformscreen.h"
+#else
+# include "qeglfsintegration.h"
+#endif
+
+QT_BEGIN_NAMESPACE
+
+class QDesktopWidget;
+class QAndroidPlatformServices;
+
+#ifdef ANDROID_PLUGIN_OPENGL
+class QAndroidOpenGLPlatformWindow;
+#endif
+
+class QAndroidPlatformNativeInterface: public QPlatformNativeInterface
+{
+public:
+ void *nativeResourceForIntegration(const QByteArray &resource);
+};
+
+class QAndroidPlatformIntegration
+#ifndef ANDROID_PLUGIN_OPENGL
+ : public QPlatformIntegration
+#else
+ : public QEglFSIntegration
+#endif
+{
+ friend class QAndroidPlatformScreen;
+
+public:
+ QAndroidPlatformIntegration(const QStringList &paramList);
+ ~QAndroidPlatformIntegration();
+
+ bool hasCapability(QPlatformIntegration::Capability cap) const;
+
+#ifndef ANDROID_PLUGIN_OPENGL
+ QPlatformBackingStore *createPlatformBackingStore(QWindow *window) const;
+ QPlatformWindow *createPlatformWindow(QWindow *window) const;
+ QAbstractEventDispatcher *guiThreadEventDispatcher() const;
+ QAndroidPlatformScreen *screen() { return m_primaryScreen; }
+#else
+ QPlatformWindow *createPlatformWindow(QWindow *window) const;
+ void invalidateNativeSurface();
+ void surfaceChanged();
+ QAndroidOpenGLPlatformWindow *primaryWindow() const { return m_primaryWindow; }
+ QPlatformOpenGLContext *createPlatformOpenGLContext(QOpenGLContext *context) const;
+#endif
+
+ virtual void setDesktopSize(int width, int height);
+ virtual void setDisplayMetrics(int width, int height);
+ bool isVirtualDesktop() { return true; }
+
+ QPlatformFontDatabase *fontDatabase() const;
+
+#ifndef QT_NO_CLIPBOARD
+ QPlatformClipboard *clipboard() const;
+#endif
+
+ QPlatformInputContext *inputContext() const;
+ QPlatformNativeInterface *nativeInterface() const;
+ QPlatformServices *services() const;
+
+ QStringList themeNames() const;
+ QPlatformTheme *createPlatformTheme(const QString &name) const;
+
+ void pauseApp();
+ void resumeApp();
+ static void setDefaultDisplayMetrics(int gw, int gh, int sw, int sh);
+ static void setDefaultDesktopSize(int gw, int gh);
+
+ static QSize defaultDesktopSize()
+ {
+ return QSize(m_defaultGeometryWidth, m_defaultGeometryHeight);
+ }
+
+ QTouchDevice *touchDevice() const { return m_touchDevice; }
+ void setTouchDevice(QTouchDevice *touchDevice) { m_touchDevice = touchDevice; }
+
+private:
+
+ friend class QEglFSAndroidHooks;
+
+ QTouchDevice *m_touchDevice;
+
+#ifndef ANDROID_PLUGIN_OPENGL
+ QAbstractEventDispatcher *m_eventDispatcher;
+ QAndroidPlatformScreen *m_primaryScreen;
+#else
+ mutable QAndroidOpenGLPlatformWindow *m_primaryWindow;
+#endif
+
+ QThread *m_mainThread;
+
+ static int m_defaultGeometryWidth;
+ static int m_defaultGeometryHeight;
+ static int m_defaultPhysicalSizeWidth;
+ static int m_defaultPhysicalSizeHeight;
+
+ QPlatformFontDatabase *m_androidFDB;
+ QImage *m_FbScreenImage;
+ QPainter *m_compositePainter;
+ QAndroidPlatformNativeInterface *m_androidPlatformNativeInterface;
+ QAndroidPlatformServices *m_androidPlatformServices;
+ QPlatformClipboard *m_androidPlatformClipboard;
+
+ mutable QAndroidInputContext m_platformInputContext;
+};
+
+QT_END_NAMESPACE
+
+#endif
diff --git a/src/plugins/platforms/android/src/qandroidplatformmenu.cpp b/src/plugins/platforms/android/src/qandroidplatformmenu.cpp
new file mode 100644
index 0000000000..36247e86f9
--- /dev/null
+++ b/src/plugins/platforms/android/src/qandroidplatformmenu.cpp
@@ -0,0 +1,167 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 BogDan Vatra <bogdan@kde.org>
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the plugins of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Digia. For licensing terms and
+** conditions see http://qt.digia.com/licensing. For further information
+** use the contact form at http://qt.digia.com/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Digia gives you certain additional
+** rights. These rights are described in the Digia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qandroidplatformmenu.h"
+#include "qandroidplatformmenuitem.h"
+#include "androidjnimenu.h"
+
+QAndroidPlatformMenu::QAndroidPlatformMenu()
+{
+ m_tag = reinterpret_cast<quintptr>(this); // QMenu will overwrite this later, but we need a unique ID for QtQuick
+ m_enabled = true;
+ m_isVisible = true;
+}
+
+QAndroidPlatformMenu::~QAndroidPlatformMenu()
+{
+ QtAndroidMenu::androidPlatformMenuDestroyed(this);
+}
+
+void QAndroidPlatformMenu::insertMenuItem(QPlatformMenuItem *menuItem, QPlatformMenuItem *before)
+{
+ QMutexLocker lock(&m_menuItemsMutex);
+ m_menuItems.insert(qFind(m_menuItems.begin(),
+ m_menuItems.end(),
+ static_cast<QAndroidPlatformMenuItem *>(before)),
+ static_cast<QAndroidPlatformMenuItem *>(menuItem));
+}
+
+void QAndroidPlatformMenu::removeMenuItem(QPlatformMenuItem *menuItem)
+{
+ QMutexLocker lock(&m_menuItemsMutex);
+ m_menuItems.erase(qFind(m_menuItems.begin(),
+ m_menuItems.end(),
+ static_cast<QAndroidPlatformMenuItem *>(menuItem)));
+}
+
+void QAndroidPlatformMenu::syncMenuItem(QPlatformMenuItem *menuItem)
+{
+ PlatformMenuItemsType::iterator it;
+ for (it = m_menuItems.begin(); it != m_menuItems.end(); ++it) {
+ if ((*it)->tag() == menuItem->tag())
+ break;
+ }
+
+ if (it != m_menuItems.end())
+ QtAndroidMenu::syncMenu(this);
+}
+
+void QAndroidPlatformMenu::syncSeparatorsCollapsible(bool enable)
+{
+ Q_UNUSED(enable)
+}
+
+void QAndroidPlatformMenu::setTag(quintptr tag)
+{
+ m_tag = tag;
+}
+
+quintptr QAndroidPlatformMenu::tag() const
+{
+ return m_tag;
+}
+
+void QAndroidPlatformMenu::setText(const QString &text)
+{
+ m_text = text;
+}
+
+QString QAndroidPlatformMenu::text() const
+{
+ return m_text;
+}
+
+void QAndroidPlatformMenu::setIcon(const QIcon &icon)
+{
+ m_icon = icon;
+}
+
+QIcon QAndroidPlatformMenu::icon() const
+{
+ return m_icon;
+}
+
+void QAndroidPlatformMenu::setEnabled(bool enabled)
+{
+ m_enabled = enabled;
+}
+
+bool QAndroidPlatformMenu::isEnabled() const
+{
+ return m_enabled;
+}
+
+void QAndroidPlatformMenu::setVisible(bool visible)
+{
+ m_isVisible = visible;
+}
+
+bool QAndroidPlatformMenu::isVisible() const
+{
+ return m_isVisible;
+}
+
+QPlatformMenuItem *QAndroidPlatformMenu::menuItemAt(int position) const
+{
+ if (position < m_menuItems.size())
+ return m_menuItems[position];
+ return 0;
+}
+
+QPlatformMenuItem *QAndroidPlatformMenu::menuItemForTag(quintptr tag) const
+{
+ foreach (QPlatformMenuItem *menuItem, m_menuItems) {
+ if (menuItem->tag() == tag)
+ return menuItem;
+ }
+
+ return 0;
+}
+
+QAndroidPlatformMenu::PlatformMenuItemsType QAndroidPlatformMenu::menuItems() const
+{
+ return m_menuItems;
+}
+
+QMutex *QAndroidPlatformMenu::menuItemsMutex()
+{
+ return &m_menuItemsMutex;
+}
diff --git a/src/plugins/platforms/android/src/qandroidplatformmenu.h b/src/plugins/platforms/android/src/qandroidplatformmenu.h
new file mode 100644
index 0000000000..20236cb636
--- /dev/null
+++ b/src/plugins/platforms/android/src/qandroidplatformmenu.h
@@ -0,0 +1,91 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 BogDan Vatra <bogdan@kde.org>
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the plugins of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Digia. For licensing terms and
+** conditions see http://qt.digia.com/licensing. For further information
+** use the contact form at http://qt.digia.com/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Digia gives you certain additional
+** rights. These rights are described in the Digia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QANDROIDPLATFORMMENU_H
+#define QANDROIDPLATFORMMENU_H
+
+#include <qpa/qplatformmenu.h>
+#include <qvector.h>
+#include <qmutex.h>
+
+class QAndroidPlatformMenuItem;
+class QAndroidPlatformMenu: public QPlatformMenu
+{
+public:
+ typedef QVector<QAndroidPlatformMenuItem *> PlatformMenuItemsType;
+
+public:
+ QAndroidPlatformMenu();
+ ~QAndroidPlatformMenu();
+
+ void insertMenuItem(QPlatformMenuItem *menuItem, QPlatformMenuItem *before);
+ void removeMenuItem(QPlatformMenuItem *menuItem);
+ void syncMenuItem(QPlatformMenuItem *menuItem);
+ void syncSeparatorsCollapsible(bool enable);
+
+ void setTag(quintptr tag);
+ quintptr tag() const;
+ void setText(const QString &text);
+ QString text() const;
+ void setIcon(const QIcon &icon);
+ QIcon icon() const;
+ void setEnabled(bool enabled);
+ bool isEnabled() const;
+ void setVisible(bool visible);
+ bool isVisible() const;
+
+ QPlatformMenuItem *menuItemAt(int position) const;
+ QPlatformMenuItem *menuItemForTag(quintptr tag) const;
+
+ PlatformMenuItemsType menuItems() const;
+ QMutex *menuItemsMutex();
+
+private:
+ PlatformMenuItemsType m_menuItems;
+ quintptr m_tag;
+ QString m_text;
+ QIcon m_icon;
+ bool m_enabled;
+ bool m_isVisible;
+ QMutex m_menuItemsMutex;
+};
+
+#endif // QANDROIDPLATFORMMENU_H
diff --git a/src/plugins/platforms/android/src/qandroidplatformmenubar.cpp b/src/plugins/platforms/android/src/qandroidplatformmenubar.cpp
new file mode 100644
index 0000000000..ef1ac61356
--- /dev/null
+++ b/src/plugins/platforms/android/src/qandroidplatformmenubar.cpp
@@ -0,0 +1,109 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 BogDan Vatra <bogdan@kde.org>
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the plugins of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Digia. For licensing terms and
+** conditions see http://qt.digia.com/licensing. For further information
+** use the contact form at http://qt.digia.com/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Digia gives you certain additional
+** rights. These rights are described in the Digia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qandroidplatformmenubar.h"
+#include "qandroidplatformmenu.h"
+#include "androidjnimenu.h"
+
+
+QAndroidPlatformMenuBar::QAndroidPlatformMenuBar()
+{
+ m_parentWindow = 0;
+ QtAndroidMenu::addMenuBar(this);
+}
+
+QAndroidPlatformMenuBar::~QAndroidPlatformMenuBar()
+{
+ QtAndroidMenu::removeMenuBar(this);
+}
+
+void QAndroidPlatformMenuBar::insertMenu(QPlatformMenu *menu, QPlatformMenu *before)
+{
+ QMutexLocker lock(&m_menusListMutex);
+ m_menus.insert(qFind(m_menus.begin(),
+ m_menus.end(),
+ static_cast<QAndroidPlatformMenu *>(before)),
+ static_cast<QAndroidPlatformMenu *>(menu));
+}
+
+void QAndroidPlatformMenuBar::removeMenu(QPlatformMenu *menu)
+{
+ QMutexLocker lock(&m_menusListMutex);
+ m_menus.erase(qFind(m_menus.begin(),
+ m_menus.end(),
+ static_cast<QAndroidPlatformMenu *>(menu)));
+}
+
+void QAndroidPlatformMenuBar::syncMenu(QPlatformMenu *menu)
+{
+ QtAndroidMenu::syncMenu(static_cast<QAndroidPlatformMenu *>(menu));
+}
+
+void QAndroidPlatformMenuBar::handleReparent(QWindow *newParentWindow)
+{
+ m_parentWindow = newParentWindow;
+ QtAndroidMenu::setMenuBar(this, newParentWindow);
+}
+
+QPlatformMenu *QAndroidPlatformMenuBar::menuForTag(quintptr tag) const
+{
+ foreach (QPlatformMenu *menu, m_menus) {
+ if (menu->tag() == tag)
+ return menu;
+ }
+
+ return 0;
+}
+
+QWindow *QAndroidPlatformMenuBar::parentWindow() const
+{
+ return m_parentWindow;
+}
+
+QAndroidPlatformMenuBar::PlatformMenusType QAndroidPlatformMenuBar::menus() const
+{
+ return m_menus;
+}
+
+QMutex *QAndroidPlatformMenuBar::menusListMutex()
+{
+ return &m_menusListMutex;
+}
diff --git a/src/plugins/platforms/android/src/qandroidplatformmenubar.h b/src/plugins/platforms/android/src/qandroidplatformmenubar.h
new file mode 100644
index 0000000000..56915335c2
--- /dev/null
+++ b/src/plugins/platforms/android/src/qandroidplatformmenubar.h
@@ -0,0 +1,74 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 BogDan Vatra <bogdan@kde.org>
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the plugins of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Digia. For licensing terms and
+** conditions see http://qt.digia.com/licensing. For further information
+** use the contact form at http://qt.digia.com/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Digia gives you certain additional
+** rights. These rights are described in the Digia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QANDROIDPLATFORMMENUBAR_H
+#define QANDROIDPLATFORMMENUBAR_H
+
+#include <qpa/qplatformmenu.h>
+#include <qvector.h>
+#include <qmutex.h>
+
+class QAndroidPlatformMenu;
+class QAndroidPlatformMenuBar: public QPlatformMenuBar
+{
+public:
+ typedef QVector<QAndroidPlatformMenu *> PlatformMenusType;
+public:
+ QAndroidPlatformMenuBar();
+ ~QAndroidPlatformMenuBar();
+
+ void insertMenu(QPlatformMenu *menu, QPlatformMenu *before);
+ void removeMenu(QPlatformMenu *menu);
+ void syncMenu(QPlatformMenu *menu);
+ void handleReparent(QWindow *newParentWindow);
+ QPlatformMenu *menuForTag(quintptr tag) const;
+
+ QWindow *parentWindow() const;
+ PlatformMenusType menus() const;
+ QMutex *menusListMutex();
+
+private:
+ PlatformMenusType m_menus;
+ QWindow *m_parentWindow;
+ QMutex m_menusListMutex;
+};
+
+#endif // QANDROIDPLATFORMMENUBAR_H
diff --git a/src/plugins/platforms/android/src/qandroidplatformmenuitem.cpp b/src/plugins/platforms/android/src/qandroidplatformmenuitem.cpp
new file mode 100644
index 0000000000..bd37834d2a
--- /dev/null
+++ b/src/plugins/platforms/android/src/qandroidplatformmenuitem.cpp
@@ -0,0 +1,180 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 BogDan Vatra <bogdan@kde.org>
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the plugins of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Digia. For licensing terms and
+** conditions see http://qt.digia.com/licensing. For further information
+** use the contact form at http://qt.digia.com/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Digia gives you certain additional
+** rights. These rights are described in the Digia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qandroidplatformmenuitem.h"
+#include "qandroidplatformmenu.h"
+
+QAndroidPlatformMenuItem::QAndroidPlatformMenuItem()
+{
+ m_tag = reinterpret_cast<quintptr>(this); // QMenu will overwrite this later, but we need a unique ID for QtQuick
+ m_menu = 0;
+ m_isVisible = true;
+ m_isSeparator = false;
+ m_role = NoRole;
+ m_isCheckable = false;
+ m_isChecked = false;
+ m_isEnabled = true;
+}
+
+void QAndroidPlatformMenuItem::setTag(quintptr tag)
+{
+ m_tag = tag;
+}
+
+quintptr QAndroidPlatformMenuItem::tag() const
+{
+ return m_tag;
+}
+
+void QAndroidPlatformMenuItem::setText(const QString &text)
+{
+ m_text = text;
+ if (m_menu)
+ m_menu->setText(m_text);
+}
+
+QString QAndroidPlatformMenuItem::text() const
+{
+ return m_text;
+}
+
+void QAndroidPlatformMenuItem::setIcon(const QIcon &icon)
+{
+ m_icon = icon;
+ if (m_menu)
+ m_menu->setIcon(m_icon);
+}
+
+QIcon QAndroidPlatformMenuItem::icon() const
+{
+ return m_icon;
+}
+
+void QAndroidPlatformMenuItem::setMenu(QPlatformMenu *menu)
+{
+ m_menu = static_cast<QAndroidPlatformMenu *>(menu);
+ if (!m_menu)
+ return;
+
+ m_menu->setText(m_text);
+ m_menu->setIcon(m_icon);
+ m_menu->setVisible(m_isVisible);
+ m_menu->setEnabled(m_isEnabled);
+}
+
+QAndroidPlatformMenu *QAndroidPlatformMenuItem::menu() const
+{
+ return m_menu;
+}
+
+void QAndroidPlatformMenuItem::setVisible(bool isVisible)
+{
+ m_isVisible = isVisible;
+ if (m_menu)
+ m_menu->setVisible(m_isVisible);
+}
+
+bool QAndroidPlatformMenuItem::isVisible() const
+{
+ return m_isVisible;
+}
+
+void QAndroidPlatformMenuItem::setIsSeparator(bool isSeparator)
+{
+ m_isSeparator = isSeparator;
+}
+
+bool QAndroidPlatformMenuItem::isSeparator() const
+{
+ return m_isSeparator;
+}
+
+void QAndroidPlatformMenuItem::setFont(const QFont &font)
+{
+ Q_UNUSED(font)
+}
+
+void QAndroidPlatformMenuItem::setRole(QPlatformMenuItem::MenuRole role)
+{
+ m_role = role;
+}
+
+QPlatformMenuItem::MenuRole QAndroidPlatformMenuItem::role() const
+{
+ return m_role;
+}
+
+void QAndroidPlatformMenuItem::setCheckable(bool checkable)
+{
+ m_isCheckable = checkable;
+}
+
+bool QAndroidPlatformMenuItem::isCheckable() const
+{
+ return m_isCheckable;
+}
+
+void QAndroidPlatformMenuItem::setChecked(bool isChecked)
+{
+ m_isChecked = isChecked;
+}
+
+bool QAndroidPlatformMenuItem::isChecked() const
+{
+ return m_isChecked;
+}
+
+void QAndroidPlatformMenuItem::setShortcut(const QKeySequence &shortcut)
+{
+ Q_UNUSED(shortcut)
+}
+
+void QAndroidPlatformMenuItem::setEnabled(bool enabled)
+{
+ m_isEnabled = enabled;
+ if (m_menu)
+ m_menu->setEnabled(m_isEnabled);
+}
+
+bool QAndroidPlatformMenuItem::isEnabled() const
+{
+ return m_isEnabled;
+}
diff --git a/src/plugins/platforms/android/src/qandroidplatformmenuitem.h b/src/plugins/platforms/android/src/qandroidplatformmenuitem.h
new file mode 100644
index 0000000000..5861e8e195
--- /dev/null
+++ b/src/plugins/platforms/android/src/qandroidplatformmenuitem.h
@@ -0,0 +1,99 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 BogDan Vatra <bogdan@kde.org>
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the plugins of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Digia. For licensing terms and
+** conditions see http://qt.digia.com/licensing. For further information
+** use the contact form at http://qt.digia.com/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Digia gives you certain additional
+** rights. These rights are described in the Digia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QANDROIDPLATFORMMENUITEM_H
+#define QANDROIDPLATFORMMENUITEM_H
+#include <qpa/qplatformmenu.h>
+
+class QAndroidPlatformMenu;
+
+class QAndroidPlatformMenuItem: public QPlatformMenuItem
+{
+public:
+ QAndroidPlatformMenuItem();
+ void setTag(quintptr tag);
+ quintptr tag() const;
+
+ void setText(const QString &text);
+ QString text() const;
+
+ void setIcon(const QIcon &icon);
+ QIcon icon() const;
+
+ void setMenu(QPlatformMenu *menu);
+ QAndroidPlatformMenu *menu() const;
+
+ void setVisible(bool isVisible);
+ bool isVisible() const;
+
+ void setIsSeparator(bool isSeparator);
+ bool isSeparator() const;
+
+ void setFont(const QFont &font);
+
+ void setRole(MenuRole role);
+ MenuRole role() const;
+
+ void setCheckable(bool checkable);
+ bool isCheckable() const;
+
+ void setChecked(bool isChecked);
+ bool isChecked() const;
+
+ void setShortcut(const QKeySequence &shortcut);
+
+ void setEnabled(bool enabled);
+ bool isEnabled() const;
+
+private:
+ quintptr m_tag;
+ QString m_text;
+ QIcon m_icon;
+ QAndroidPlatformMenu *m_menu;
+ bool m_isVisible;
+ bool m_isSeparator;
+ MenuRole m_role;
+ bool m_isCheckable;
+ bool m_isChecked;
+ bool m_isEnabled;
+};
+
+#endif // QANDROIDPLATFORMMENUITEM_H
diff --git a/src/plugins/platforms/android/src/qandroidplatformservices.cpp b/src/plugins/platforms/android/src/qandroidplatformservices.cpp
new file mode 100644
index 0000000000..841a9d4d51
--- /dev/null
+++ b/src/plugins/platforms/android/src/qandroidplatformservices.cpp
@@ -0,0 +1,83 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 BogDan Vatra <bogdan@kde.org>
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the plugins of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Digia. For licensing terms and
+** conditions see http://qt.digia.com/licensing. For further information
+** use the contact form at http://qt.digia.com/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Digia gives you certain additional
+** rights. These rights are described in the Digia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qandroidplatformservices.h"
+#include <QUrl>
+#include <QDir>
+#include <QDebug>
+
+QAndroidPlatformServices::QAndroidPlatformServices()
+{
+ JNIEnv *env;
+ if (QtAndroid::javaVM()->AttachCurrentThread(&env, NULL) < 0) {
+ qCritical() << "AttachCurrentThread failed";
+ return;
+ }
+
+ m_openURIMethodID = env->GetStaticMethodID(QtAndroid::applicationClass(),
+ "openURL",
+ "(Ljava/lang/String;)V");
+}
+
+bool QAndroidPlatformServices::openUrl(const QUrl &url)
+{
+ JNIEnv *env;
+ if (QtAndroid::javaVM()->AttachCurrentThread(&env, NULL) < 0) {
+ qCritical() << "AttachCurrentThread failed";
+ return false;
+ }
+
+ jstring string = env->NewString(reinterpret_cast<const jchar *>(url.toString().constData()),
+ url.toString().length());
+ env->CallStaticVoidMethod(QtAndroid::applicationClass(), m_openURIMethodID, string);
+ env->DeleteLocalRef(string);
+ return true;
+}
+
+bool QAndroidPlatformServices::openDocument(const QUrl &url)
+{
+ return openUrl(url);
+}
+
+QByteArray QAndroidPlatformServices::desktopEnvironment() const
+{
+ return QByteArray("Android");
+}
diff --git a/src/plugins/platforms/android/src/qandroidplatformservices.h b/src/plugins/platforms/android/src/qandroidplatformservices.h
new file mode 100644
index 0000000000..8368b19043
--- /dev/null
+++ b/src/plugins/platforms/android/src/qandroidplatformservices.h
@@ -0,0 +1,61 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 BogDan Vatra <bogdan@kde.org>
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the plugins of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Digia. For licensing terms and
+** conditions see http://qt.digia.com/licensing. For further information
+** use the contact form at http://qt.digia.com/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Digia gives you certain additional
+** rights. These rights are described in the Digia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef ANDROIDPLATFORMDESKTOPSERVICE_H
+#define ANDROIDPLATFORMDESKTOPSERVICE_H
+
+#include <qpa/qplatformservices.h>
+#include "androidjnimain.h"
+#include <jni.h>
+
+class QAndroidPlatformServices: public QPlatformServices
+{
+public:
+ QAndroidPlatformServices();
+ bool openUrl(const QUrl &url);
+ bool openDocument(const QUrl &url);
+ QByteArray desktopEnvironment() const;
+private:
+ jmethodID m_openURIMethodID;
+
+};
+
+#endif // ANDROIDPLATFORMDESKTOPSERVICE_H
diff --git a/src/plugins/platforms/android/src/qandroidplatformtheme.cpp b/src/plugins/platforms/android/src/qandroidplatformtheme.cpp
new file mode 100644
index 0000000000..25f2ade11a
--- /dev/null
+++ b/src/plugins/platforms/android/src/qandroidplatformtheme.cpp
@@ -0,0 +1,78 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 BogDan Vatra <bogdan@kde.org>
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the plugins of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Digia. For licensing terms and
+** conditions see http://qt.digia.com/licensing. For further information
+** use the contact form at http://qt.digia.com/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Digia gives you certain additional
+** rights. These rights are described in the Digia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qandroidplatformtheme.h"
+#include "qandroidplatformmenubar.h"
+#include "qandroidplatformmenu.h"
+#include "qandroidplatformmenuitem.h"
+#include <QVariant>
+#include <QFileInfo>
+
+QPlatformMenuBar *QAndroidPlatformTheme::createPlatformMenuBar() const
+{
+ return new QAndroidPlatformMenuBar;
+}
+
+QPlatformMenu *QAndroidPlatformTheme::createPlatformMenu() const
+{
+ return new QAndroidPlatformMenu;
+}
+
+QPlatformMenuItem *QAndroidPlatformTheme::createPlatformMenuItem() const
+{
+ return new QAndroidPlatformMenuItem;
+}
+
+QVariant QAndroidPlatformTheme::themeHint(ThemeHint hint) const
+{
+ switch (hint) {
+ case StyleNames:
+ if (qgetenv("QT_USE_ANDROID_NATIVE_STYLE").toInt()
+ && (!qgetenv("MINISTRO_ANDROID_STYLE_PATH").isEmpty()
+ || QFileInfo("/data/data/org.kde.necessitas.ministro/files/qt/style/style.json").exists())) {
+ return QStringList("android");
+ }
+ return QStringList("fusion");
+ break;
+ default:
+ return QPlatformTheme::themeHint(hint);
+ }
+}
diff --git a/src/plugins/platforms/android/src/qandroidplatformtheme.h b/src/plugins/platforms/android/src/qandroidplatformtheme.h
new file mode 100644
index 0000000000..263878ee16
--- /dev/null
+++ b/src/plugins/platforms/android/src/qandroidplatformtheme.h
@@ -0,0 +1,56 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 BogDan Vatra <bogdan@kde.org>
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the plugins of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Digia. For licensing terms and
+** conditions see http://qt.digia.com/licensing. For further information
+** use the contact form at http://qt.digia.com/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Digia gives you certain additional
+** rights. These rights are described in the Digia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QANDROIDPLATFORMTHEME_H
+#define QANDROIDPLATFORMTHEME_H
+
+#include <qpa/qplatformtheme.h>
+
+class QAndroidPlatformTheme: public QPlatformTheme
+{
+public:
+ virtual QPlatformMenuBar *createPlatformMenuBar() const;
+ virtual QPlatformMenu *createPlatformMenu() const;
+ virtual QPlatformMenuItem *createPlatformMenuItem() const;
+ virtual QVariant themeHint(ThemeHint hint) const;
+};
+
+#endif // QANDROIDPLATFORMTHEME_H
diff --git a/src/plugins/platforms/android/src/raster/qandroidplatformscreen.cpp b/src/plugins/platforms/android/src/raster/qandroidplatformscreen.cpp
new file mode 100644
index 0000000000..2779d7cffd
--- /dev/null
+++ b/src/plugins/platforms/android/src/raster/qandroidplatformscreen.cpp
@@ -0,0 +1,71 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 BogDan Vatra <bogdan@kde.org>
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the plugins of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Digia. For licensing terms and
+** conditions see http://qt.digia.com/licensing. For further information
+** use the contact form at http://qt.digia.com/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Digia gives you certain additional
+** rights. These rights are described in the Digia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qandroidplatformscreen.h"
+#include "qandroidplatformintegration.h"
+#include "androidjnimain.h"
+#include "androidjnimenu.h"
+
+QAndroidPlatformScreen::QAndroidPlatformScreen():QFbScreen()
+{
+ mGeometry = QRect(0, 0, QAndroidPlatformIntegration::m_defaultGeometryWidth, QAndroidPlatformIntegration::m_defaultGeometryHeight);
+ mFormat = QImage::Format_RGB16;
+ mDepth = 16;
+ mPhysicalSize.setHeight(QAndroidPlatformIntegration::m_defaultPhysicalSizeHeight);
+ mPhysicalSize.setWidth(QAndroidPlatformIntegration::m_defaultPhysicalSizeWidth);
+ initializeCompositor();
+}
+
+void QAndroidPlatformScreen::topWindowChanged(QWindow *w)
+{
+ QtAndroidMenu::setActiveTopLevelWindow(w);
+}
+
+QRegion QAndroidPlatformScreen::doRedraw()
+{
+ QRegion touched;
+ touched = QFbScreen::doRedraw();
+ if (touched.isEmpty())
+ return touched;
+
+ QtAndroid::flushImage(mGeometry.topLeft(), *mScreenImage, touched.boundingRect());
+ return touched;
+}
diff --git a/src/plugins/platforms/android/src/raster/qandroidplatformscreen.h b/src/plugins/platforms/android/src/raster/qandroidplatformscreen.h
new file mode 100644
index 0000000000..df08e43af4
--- /dev/null
+++ b/src/plugins/platforms/android/src/raster/qandroidplatformscreen.h
@@ -0,0 +1,59 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 BogDan Vatra <bogdan@kde.org>
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the plugins of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Digia. For licensing terms and
+** conditions see http://qt.digia.com/licensing. For further information
+** use the contact form at http://qt.digia.com/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Digia gives you certain additional
+** rights. These rights are described in the Digia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QANDROIDPLATFORMSCREEN_H
+#define QANDROIDPLATFORMSCREEN_H
+
+#include <QtPlatformSupport/private/qfbscreen_p.h>
+
+class QAndroidPlatformScreen: public QFbScreen
+{
+ Q_OBJECT
+public:
+ QAndroidPlatformScreen();
+ void topWindowChanged(QWindow *w);
+
+public slots:
+ QRegion doRedraw();
+
+};
+
+#endif
diff --git a/src/plugins/platforms/android/src/raster/qandroidplatformwindow.cpp b/src/plugins/platforms/android/src/raster/qandroidplatformwindow.cpp
new file mode 100644
index 0000000000..94a69c10c7
--- /dev/null
+++ b/src/plugins/platforms/android/src/raster/qandroidplatformwindow.cpp
@@ -0,0 +1,56 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 BogDan Vatra <bogdan@kde.org>
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the plugins of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Digia. For licensing terms and
+** conditions see http://qt.digia.com/licensing. For further information
+** use the contact form at http://qt.digia.com/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Digia gives you certain additional
+** rights. These rights are described in the Digia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qandroidplatformwindow.h"
+
+QAndroidPlatformWindow::QAndroidPlatformWindow(QWindow *window) : QFbWindow(window)
+{
+}
+
+void QAndroidPlatformWindow::setGeometry(const QRect &rect)
+{
+ QFbWindow::setGeometry(rect);
+}
+
+void QAndroidPlatformWindow::propagateSizeHints()
+{
+ //shut up warning from default implementation
+}
diff --git a/src/plugins/platforms/android/src/raster/qandroidplatformwindow.h b/src/plugins/platforms/android/src/raster/qandroidplatformwindow.h
new file mode 100644
index 0000000000..3ee815fd69
--- /dev/null
+++ b/src/plugins/platforms/android/src/raster/qandroidplatformwindow.h
@@ -0,0 +1,60 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 BogDan Vatra <bogdan@kde.org>
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the plugins of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Digia. For licensing terms and
+** conditions see http://qt.digia.com/licensing. For further information
+** use the contact form at http://qt.digia.com/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Digia gives you certain additional
+** rights. These rights are described in the Digia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef ANDROIDPLATFORMWINDOW_H
+#define ANDROIDPLATFORMWINDOW_H
+#include <qobject.h>
+#include <QtPlatformSupport/private/qfbwindow_p.h>
+
+class QAndroidPlatformWindow: public QObject, public QFbWindow
+{
+ Q_OBJECT
+public:
+ explicit QAndroidPlatformWindow(QWindow *window);
+
+ void propagateSizeHints();
+
+public slots:
+ void setGeometry(const QRect &rect);
+
+};
+
+#endif // ANDROIDPLATFORMWINDOW_H
diff --git a/src/plugins/platforms/android/src/raster/raster.pri b/src/plugins/platforms/android/src/raster/raster.pri
new file mode 100644
index 0000000000..86e5aa235f
--- /dev/null
+++ b/src/plugins/platforms/android/src/raster/raster.pri
@@ -0,0 +1,7 @@
+INCLUDEPATH += $$PWD
+
+SOURCES += $$PWD/qandroidplatformscreen.cpp \
+ $$PWD/qandroidplatformwindow.cpp
+
+HEADERS += $$PWD/qandroidplatformscreen.h \
+ $$PWD/qandroidplatformwindow.h
diff --git a/src/plugins/platforms/android/src/src.pri b/src/plugins/platforms/android/src/src.pri
new file mode 100644
index 0000000000..9bf36b2337
--- /dev/null
+++ b/src/plugins/platforms/android/src/src.pri
@@ -0,0 +1,47 @@
+load(qt_plugin)
+
+QT += core-private gui-private widgets-private platformsupport-private
+
+CONFIG += qpa/genericunixfontdatabase
+
+OTHER_FILES += $$PWD/android.json
+
+INCLUDEPATH += $$PWD
+INCLUDEPATH += $$PWD/../../../../3rdparty/android/src
+
+SOURCES += $$PWD/androidplatformplugin.cpp \
+ $$PWD/androidjnimain.cpp \
+ $$PWD/androidjniinput.cpp \
+ $$PWD/androidjnimenu.cpp \
+ $$PWD/androidjniclipboard.cpp \
+ $$PWD/qandroidplatformintegration.cpp \
+ $$PWD/qandroidplatformservices.cpp \
+ $$PWD/qandroidassetsfileenginehandler.cpp \
+ $$PWD/qandroidinputcontext.cpp \
+ $$PWD/qandroidplatformfontdatabase.cpp \
+ $$PWD/qandroidplatformclipboard.cpp \
+ $$PWD/qandroidplatformtheme.cpp \
+ $$PWD/qandroidplatformmenubar.cpp \
+ $$PWD/qandroidplatformmenu.cpp \
+ $$PWD/qandroidplatformmenuitem.cpp
+
+
+HEADERS += $$PWD/qandroidplatformintegration.h \
+ $$PWD/androidjnimain.h \
+ $$PWD/androidjniinput.h \
+ $$PWD/androidjnimenu.h \
+ $$PWD/androidjniclipboard.h \
+ $$PWD/qandroidplatformservices.h \
+ $$PWD/qandroidassetsfileenginehandler.h \
+ $$PWD/qandroidinputcontext.h \
+ $$PWD/qandroidplatformfontdatabase.h \
+ $$PWD/qandroidplatformclipboard.h \
+ $$PWD/qandroidplatformtheme.h \
+ $$PWD/qandroidplatformmenubar.h \
+ $$PWD/qandroidplatformmenu.h \
+ $$PWD/qandroidplatformmenuitem.h
+
+
+#Non-standard install directory, QTBUG-29859
+DESTDIR = $$DESTDIR/android
+target.path = $${target.path}/android
diff --git a/src/plugins/platforms/cocoa/cocoa.pro b/src/plugins/platforms/cocoa/cocoa.pro
index 83e2a88e6a..6ed26f9e6c 100644
--- a/src/plugins/platforms/cocoa/cocoa.pro
+++ b/src/plugins/platforms/cocoa/cocoa.pro
@@ -78,7 +78,7 @@ HEADERS += qcocoaintegration.h \
RESOURCES += qcocoaresources.qrc
-LIBS += -framework Cocoa -framework IOKit
+LIBS += -framework Cocoa -framework Carbon -framework IOKit
QT += core-private gui-private platformsupport-private
diff --git a/src/plugins/platforms/cocoa/qcocoaaccessibility.mm b/src/plugins/platforms/cocoa/qcocoaaccessibility.mm
index 070f23f028..adeb423cf9 100644
--- a/src/plugins/platforms/cocoa/qcocoaaccessibility.mm
+++ b/src/plugins/platforms/cocoa/qcocoaaccessibility.mm
@@ -41,7 +41,7 @@
#include "qcocoaaccessibility.h"
#include "qcocoaaccessibilityelement.h"
#include <qaccessible.h>
-#include <qaccessible2.h>
+#include <QtGui/private/qaccessible2_p.h>
#include <private/qcore_mac_p.h>
#ifndef QT_NO_COCOA_ACCESSIBILITY
diff --git a/src/plugins/platforms/cocoa/qcocoaaccessibilityelement.h b/src/plugins/platforms/cocoa/qcocoaaccessibilityelement.h
index 7ebe7a4e9d..3b1fbe042d 100644
--- a/src/plugins/platforms/cocoa/qcocoaaccessibilityelement.h
+++ b/src/plugins/platforms/cocoa/qcocoaaccessibilityelement.h
@@ -41,6 +41,7 @@
#ifndef QCOCOAACCESIBILITYELEMENT_H
#define QCOCOAACCESIBILITYELEMENT_H
+#include <QtCore/qglobal.h>
#import <Cocoa/Cocoa.h>
#import <AppKit/NSAccessibility.h>
diff --git a/src/plugins/platforms/cocoa/qcocoaaccessibilityelement.mm b/src/plugins/platforms/cocoa/qcocoaaccessibilityelement.mm
index f5f37c5b00..df496a413b 100644
--- a/src/plugins/platforms/cocoa/qcocoaaccessibilityelement.mm
+++ b/src/plugins/platforms/cocoa/qcocoaaccessibilityelement.mm
@@ -43,7 +43,7 @@
#include "qcocoahelpers.h"
#include <QAccessible>
-#include "QAccessibleActionInterface"
+#include <QtGui/private/qaccessible2_p.h>
#import <AppKit/NSAccessibility.h>
diff --git a/src/plugins/platforms/cocoa/qcocoaapplicationdelegate.h b/src/plugins/platforms/cocoa/qcocoaapplicationdelegate.h
index 6dd7ea2fb3..e44b2d1b6d 100644
--- a/src/plugins/platforms/cocoa/qcocoaapplicationdelegate.h
+++ b/src/plugins/platforms/cocoa/qcocoaapplicationdelegate.h
@@ -93,19 +93,6 @@
@class QT_MANGLE_NAMESPACE(QCocoaMenuLoader);
-#if MAC_OS_X_VERSION_MAX_ALLOWED <= MAC_OS_X_VERSION_10_5
-
-@protocol NSApplicationDelegate <NSObject>
-- (NSApplicationTerminateReply)applicationShouldTerminate:(NSApplication *)sender;
-- (void)applicationDidFinishLaunching:(NSNotification *)aNotification;
-- (void)application:(NSApplication *)sender openFiles:(NSArray *)filenames;
-- (BOOL)applicationShouldTerminateAfterLastWindowClosed:(NSApplication *)sender;
-- (void)applicationDidBecomeActive:(NSNotification *)notification;
-- (void)applicationDidResignActive:(NSNotification *)notification;
-@end
-
-#endif
-
@interface QT_MANGLE_NAMESPACE(QCocoaApplicationDelegate) : NSObject <NSApplicationDelegate> {
bool startedQuit;
NSMenu *dockMenu;
diff --git a/src/plugins/platforms/cocoa/qcocoabackingstore.mm b/src/plugins/platforms/cocoa/qcocoabackingstore.mm
index 31726268f1..4881dcef71 100644
--- a/src/plugins/platforms/cocoa/qcocoabackingstore.mm
+++ b/src/plugins/platforms/cocoa/qcocoabackingstore.mm
@@ -92,8 +92,10 @@ void QCocoaBackingStore::flush(QWindow *win, const QRegion &region, const QPoint
// m_cgImage is only a reference to the data inside m_qImage, it is not a copy.
CGImageRelease(m_cgImage);
m_cgImage = 0;
- if (QCocoaWindow *cocoaWindow = static_cast<QCocoaWindow *>(win->handle()))
- [cocoaWindow->m_qtView flushBackingStore:this region:region offset:offset];
+ if (!m_qImage.isNull()) {
+ if (QCocoaWindow *cocoaWindow = static_cast<QCocoaWindow *>(win->handle()))
+ [cocoaWindow->m_qtView flushBackingStore:this region:region offset:offset];
+ }
}
void QCocoaBackingStore::resize(const QSize &size, const QRegion &)
diff --git a/src/plugins/platforms/cocoa/qcocoacursor.mm b/src/plugins/platforms/cocoa/qcocoacursor.mm
index a36a855bcd..12808b7041 100644
--- a/src/plugins/platforms/cocoa/qcocoacursor.mm
+++ b/src/plugins/platforms/cocoa/qcocoacursor.mm
@@ -65,8 +65,9 @@ void QCocoaCursor::changeCursor(QCursor *cursor, QWindow *window)
{
Q_UNUSED(window);
+ const Qt::CursorShape newShape = cursor ? cursor->shape() : Qt::ArrowCursor;
// Check for a suitable built-in NSCursor first:
- switch (cursor->shape()) {
+ switch (newShape) {
case Qt::ArrowCursor:
[[NSCursor arrowCursor] set];
break;
@@ -104,7 +105,7 @@ void QCocoaCursor::changeCursor(QCursor *cursor, QWindow *window)
default : {
// No suitable OS cursor exist, use cursors provided
// by Qt for the rest. Check for a cached cursor:
- NSCursor *cocoaCursor = m_cursors.value(cursor->shape());
+ NSCursor *cocoaCursor = m_cursors.value(newShape);
if (cocoaCursor && cursor->shape() == Qt::BitmapCursor) {
[cocoaCursor release];
cocoaCursor = 0;
@@ -115,7 +116,7 @@ void QCocoaCursor::changeCursor(QCursor *cursor, QWindow *window)
[[NSCursor arrowCursor] set];
return;
}
- m_cursors.insert(cursor->shape(), cocoaCursor);
+ m_cursors.insert(newShape, cocoaCursor);
}
[cocoaCursor set];
diff --git a/src/plugins/platforms/cocoa/qcocoaeventdispatcher.h b/src/plugins/platforms/cocoa/qcocoaeventdispatcher.h
index f63ac0d205..93476ee1b4 100644
--- a/src/plugins/platforms/cocoa/qcocoaeventdispatcher.h
+++ b/src/plugins/platforms/cocoa/qcocoaeventdispatcher.h
@@ -93,6 +93,7 @@
#include <QtGui/qwindowdefs.h>
#include <QtCore/private/qabstracteventdispatcher_p.h>
#include <QtCore/private/qtimerinfo_unix_p.h>
+#include <QtPlatformSupport/private/qcfsocketnotifier_p.h>
#include <CoreFoundation/CoreFoundation.h>
@@ -132,16 +133,9 @@ public:
void wakeUp();
void interrupt();
void flush();
-};
-struct MacSocketInfo {
- MacSocketInfo() : socket(0), runloop(0), readNotifier(0), writeNotifier(0) {}
- CFSocketRef socket;
- CFRunLoopSourceRef runloop;
- QObject *readNotifier;
- QObject *writeNotifier;
+ friend void qt_mac_maybeCancelWaitForMoreEventsForwarder(QAbstractEventDispatcher *eventDispatcher);
};
-typedef QHash<int, MacSocketInfo *> MacSocketHash;
class QCocoaEventDispatcherPrivate : public QAbstractEventDispatcherPrivate
{
@@ -183,7 +177,7 @@ public:
void maybeCancelWaitForMoreEvents();
void ensureNSAppInitialized();
- MacSocketHash macSockets;
+ QCFSocketNotifier cfSocketNotifier;
QList<void *> queuedUserInputEvents; // NSEvent *
CFRunLoopSourceRef postedEventsSource;
CFRunLoopObserverRef waitingObserver;
diff --git a/src/plugins/platforms/cocoa/qcocoaeventdispatcher.mm b/src/plugins/platforms/cocoa/qcocoaeventdispatcher.mm
index a0734530c5..5c487b0bdd 100644
--- a/src/plugins/platforms/cocoa/qcocoaeventdispatcher.mm
+++ b/src/plugins/platforms/cocoa/qcocoaeventdispatcher.mm
@@ -149,10 +149,10 @@ void QCocoaEventDispatcherPrivate::maybeStartCFRunLoopTimer()
CFTimeInterval oneyear = CFTimeInterval(3600. * 24. * 365.);
// Q: when should the CFRunLoopTimer fire for the first time?
- struct timeval tv;
+ struct timespec tv;
if (timerInfoList.timerWait(tv)) {
// A: when we have timers to fire, of course
- interval = qMax(tv.tv_sec + tv.tv_usec / 1000000., 0.0000001);
+ interval = qMax(tv.tv_sec + tv.tv_nsec / 1000000000., 0.0000001);
} else {
// this shouldn't really happen, but in case it does, set the timer to fire a some point in the distant future
interval = oneyear;
@@ -172,10 +172,10 @@ void QCocoaEventDispatcherPrivate::maybeStartCFRunLoopTimer()
CFTimeInterval interval;
// Q: when should the timer first next?
- struct timeval tv;
+ struct timespec tv;
if (timerInfoList.timerWait(tv)) {
// A: when we have timers to fire, of course
- interval = qMax(tv.tv_sec + tv.tv_usec / 1000000., 0.0000001);
+ interval = qMax(tv.tv_sec + tv.tv_nsec / 1000000000., 0.0000001);
} else {
// no timers can fire, but we cannot stop the CFRunLoopTimer, set the timer to fire at some
// point in the distant future (the timer interval is one year)
@@ -270,58 +270,6 @@ QCocoaEventDispatcher::registeredTimers(QObject *object) const
return d->timerInfoList.registeredTimers(object);
}
-/**************************************************************************
- Socket Notifiers
- *************************************************************************/
-void qt_mac_socket_callback(CFSocketRef s, CFSocketCallBackType callbackType, CFDataRef,
- const void *, void *info) {
- QCocoaEventDispatcherPrivate *const eventDispatcher
- = static_cast<QCocoaEventDispatcherPrivate *>(info);
- int nativeSocket = CFSocketGetNative(s);
- MacSocketInfo *socketInfo = eventDispatcher->macSockets.value(nativeSocket);
- QEvent notifierEvent(QEvent::SockAct);
-
- // There is a race condition that happen where we disable the notifier and
- // the kernel still has a notification to pass on. We then get this
- // notification after we've successfully disabled the CFSocket, but our Qt
- // notifier is now gone. The upshot is we have to check the notifier
- // everytime.
- if (callbackType == kCFSocketReadCallBack) {
- if (socketInfo->readNotifier)
- QGuiApplication::sendEvent(socketInfo->readNotifier, &notifierEvent);
- } else if (callbackType == kCFSocketWriteCallBack) {
- if (socketInfo->writeNotifier)
- QGuiApplication::sendEvent(socketInfo->writeNotifier, &notifierEvent);
- }
-
- eventDispatcher->maybeCancelWaitForMoreEvents();
-}
-
-/*
- Adds a loop source for the given socket to the current run loop.
-*/
-CFRunLoopSourceRef qt_mac_add_socket_to_runloop(const CFSocketRef socket)
-{
- CFRunLoopSourceRef loopSource = CFSocketCreateRunLoopSource(kCFAllocatorDefault, socket, 0);
- if (!loopSource)
- return 0;
-
- CFRunLoopAddSource(mainRunLoop(), loopSource, kCFRunLoopCommonModes);
- return loopSource;
-}
-
-/*
- Removes the loop source for the given socket from the current run loop.
-*/
-void qt_mac_remove_socket_from_runloop(const CFSocketRef socket, CFRunLoopSourceRef runloop)
-{
- Q_ASSERT(runloop);
- CFRunLoopRemoveSource(mainRunLoop(), runloop, kCFRunLoopCommonModes);
- CFSocketDisableCallBacks(socket, kCFSocketReadCallBack);
- CFSocketDisableCallBacks(socket, kCFSocketWriteCallBack);
- CFRunLoopSourceInvalidate(runloop);
-}
-
/*
Register a QSocketNotifier with the mac event system by creating a CFSocket with
with a read/write callback.
@@ -331,130 +279,14 @@ void qt_mac_remove_socket_from_runloop(const CFSocketRef socket, CFRunLoopSource
*/
void QCocoaEventDispatcher::registerSocketNotifier(QSocketNotifier *notifier)
{
- Q_ASSERT(notifier);
- int nativeSocket = notifier->socket();
- int type = notifier->type();
-#ifndef QT_NO_DEBUG
- if (nativeSocket < 0 || nativeSocket > FD_SETSIZE) {
- qWarning("QSocketNotifier: Internal error");
- return;
- } else if (notifier->thread() != thread()
- || thread() != QThread::currentThread()) {
- qWarning("QSocketNotifier: socket notifiers cannot be enabled from another thread");
- return;
- }
-#endif
-
Q_D(QCocoaEventDispatcher);
-
- if (type == QSocketNotifier::Exception) {
- qWarning("QSocketNotifier::Exception is not supported on Mac OS X");
- return;
- }
-
- // Check if we have a CFSocket for the native socket, create one if not.
- MacSocketInfo *socketInfo = d->macSockets.value(nativeSocket);
- if (!socketInfo) {
- socketInfo = new MacSocketInfo();
-
- // Create CFSocket, specify that we want both read and write callbacks (the callbacks
- // are enabled/disabled later on).
- const int callbackTypes = kCFSocketReadCallBack | kCFSocketWriteCallBack;
- CFSocketContext context = {0, d, 0, 0, 0};
- socketInfo->socket = CFSocketCreateWithNative(kCFAllocatorDefault, nativeSocket, callbackTypes, qt_mac_socket_callback, &context);
- if (CFSocketIsValid(socketInfo->socket) == false) {
- qWarning("QEventDispatcherMac::registerSocketNotifier: Failed to create CFSocket");
- return;
- }
-
- CFOptionFlags flags = CFSocketGetSocketFlags(socketInfo->socket);
- flags |= kCFSocketAutomaticallyReenableWriteCallBack; //QSocketNotifier stays enabled after a write
- flags &= ~kCFSocketCloseOnInvalidate; //QSocketNotifier doesn't close the socket upon destruction/invalidation
- CFSocketSetSocketFlags(socketInfo->socket, flags);
-
- // Add CFSocket to runloop.
- if(!(socketInfo->runloop = qt_mac_add_socket_to_runloop(socketInfo->socket))) {
- qWarning("QEventDispatcherMac::registerSocketNotifier: Failed to add CFSocket to runloop");
- CFSocketInvalidate(socketInfo->socket);
- CFRelease(socketInfo->socket);
- return;
- }
-
- // Disable both callback types by default. This must be done after
- // we add the CFSocket to the runloop, or else these calls will have
- // no effect.
- CFSocketDisableCallBacks(socketInfo->socket, kCFSocketReadCallBack);
- CFSocketDisableCallBacks(socketInfo->socket, kCFSocketWriteCallBack);
-
- d->macSockets.insert(nativeSocket, socketInfo);
- }
-
- // Increment read/write counters and select enable callbacks if necessary.
- if (type == QSocketNotifier::Read) {
- Q_ASSERT(socketInfo->readNotifier == 0);
- socketInfo->readNotifier = notifier;
- CFSocketEnableCallBacks(socketInfo->socket, kCFSocketReadCallBack);
- } else if (type == QSocketNotifier::Write) {
- Q_ASSERT(socketInfo->writeNotifier == 0);
- socketInfo->writeNotifier = notifier;
- CFSocketEnableCallBacks(socketInfo->socket, kCFSocketWriteCallBack);
- }
+ d->cfSocketNotifier.registerSocketNotifier(notifier);
}
-/*
- Unregister QSocketNotifer. The CFSocket correspoding to this notifier is
- removed from the runloop of this is the last notifier that users
- that CFSocket.
-*/
void QCocoaEventDispatcher::unregisterSocketNotifier(QSocketNotifier *notifier)
{
- Q_ASSERT(notifier);
- int nativeSocket = notifier->socket();
- int type = notifier->type();
-#ifndef QT_NO_DEBUG
- if (nativeSocket < 0 || nativeSocket > FD_SETSIZE) {
- qWarning("QSocketNotifier: Internal error");
- return;
- } else if (notifier->thread() != thread() || thread() != QThread::currentThread()) {
- qWarning("QSocketNotifier: socket notifiers cannot be disabled from another thread");
- return;
- }
-#endif
-
Q_D(QCocoaEventDispatcher);
-
- if (type == QSocketNotifier::Exception) {
- qWarning("QSocketNotifier::Exception is not supported on Mac OS X");
- return;
- }
- MacSocketInfo *socketInfo = d->macSockets.value(nativeSocket);
- if (!socketInfo) {
- qWarning("QEventDispatcherMac::unregisterSocketNotifier: Tried to unregister a not registered notifier");
- return;
- }
-
- // Decrement read/write counters and disable callbacks if necessary.
- if (type == QSocketNotifier::Read) {
- Q_ASSERT(notifier == socketInfo->readNotifier);
- socketInfo->readNotifier = 0;
- CFSocketDisableCallBacks(socketInfo->socket, kCFSocketReadCallBack);
- } else if (type == QSocketNotifier::Write) {
- Q_ASSERT(notifier == socketInfo->writeNotifier);
- socketInfo->writeNotifier = 0;
- CFSocketDisableCallBacks(socketInfo->socket, kCFSocketWriteCallBack);
- }
-
- // Remove CFSocket from runloop if this was the last QSocketNotifier.
- if (socketInfo->readNotifier == 0 && socketInfo->writeNotifier == 0) {
- if (CFSocketIsValid(socketInfo->socket))
- qt_mac_remove_socket_from_runloop(socketInfo->socket, socketInfo->runloop);
- CFRunLoopSourceInvalidate(socketInfo->runloop);
- CFRelease(socketInfo->runloop);
- CFSocketInvalidate(socketInfo->socket);
- CFRelease(socketInfo->socket);
- delete socketInfo;
- d->macSockets.remove(nativeSocket);
- }
+ d->cfSocketNotifier.unregisterSocketNotifier(notifier);
}
bool QCocoaEventDispatcher::hasPendingEvents()
@@ -467,37 +299,35 @@ bool QCocoaEventDispatcher::hasPendingEvents()
static bool IsMouseOrKeyEvent( NSEvent* event )
{
bool result = false;
-
+
switch( [event type] )
{
- case NSLeftMouseDown:
- case NSLeftMouseUp:
- case NSRightMouseDown:
- case NSRightMouseUp:
+ case NSLeftMouseDown:
+ case NSLeftMouseUp:
+ case NSRightMouseDown:
+ case NSRightMouseUp:
case NSMouseMoved: // ??
- case NSLeftMouseDragged:
+ case NSLeftMouseDragged:
case NSRightMouseDragged:
- case NSMouseEntered:
- case NSMouseExited:
- case NSKeyDown:
- case NSKeyUp:
+ case NSMouseEntered:
+ case NSMouseExited:
+ case NSKeyDown:
+ case NSKeyUp:
case NSFlagsChanged: // key modifiers changed?
case NSCursorUpdate: // ??
- case NSScrollWheel:
- case NSTabletPoint:
- case NSTabletProximity:
- case NSOtherMouseDown:
- case NSOtherMouseUp:
+ case NSScrollWheel:
+ case NSTabletPoint:
+ case NSTabletProximity:
+ case NSOtherMouseDown:
+ case NSOtherMouseUp:
case NSOtherMouseDragged:
#ifndef QT_NO_GESTURES
-#if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_6
case NSEventTypeGesture: // touch events
case NSEventTypeMagnify:
case NSEventTypeSwipe:
case NSEventTypeRotate:
case NSEventTypeBeginGesture:
case NSEventTypeEndGesture:
-#endif
#endif // QT_NO_GESTURES
result = true;
break;
@@ -809,7 +639,7 @@ static void setChildrenWorksWhenModal(QWindow *window, bool worksWhenModal)
Q_UNUSED(worksWhenModal)
// For NSPanels (but not NSWindows, sadly), we can set the flag
- // worksWhenModal, so that they are active even when they are not modal.
+ // worksWhenModal, so that they are active even when they are not modal.
/*
### not ported
QList<QDialog *> dialogs = window->findChildren<QDialog *>();
@@ -850,7 +680,7 @@ void QCocoaEventDispatcherPrivate::cleanupModalSessions()
// this to actually end the sessions for real (rather than at the
// point they were marked as stopped), is that ending a session
// when no other session runs below it on the stack will make cocoa
- // drop some events on the floor.
+ // drop some events on the floor.
QCocoaAutoReleasePool pool;
int stackSize = cocoaModalSessionStack.size();
@@ -942,11 +772,19 @@ QCocoaEventDispatcherPrivate::QCocoaEventDispatcherPrivate()
{
}
+void qt_mac_maybeCancelWaitForMoreEventsForwarder(QAbstractEventDispatcher *eventDispatcher)
+{
+ static_cast<QCocoaEventDispatcher *>(eventDispatcher)->d_func()->maybeCancelWaitForMoreEvents();
+}
+
QCocoaEventDispatcher::QCocoaEventDispatcher(QObject *parent)
: QAbstractEventDispatcher(*new QCocoaEventDispatcherPrivate, parent)
{
Q_D(QCocoaEventDispatcher);
+ d->cfSocketNotifier.setHostEventDispatcher(this);
+ d->cfSocketNotifier.setMaybeCancelWaitForMoreEventsCallback(qt_mac_maybeCancelWaitForMoreEventsForwarder);
+
// keep our sources running when modal loops are running
CFRunLoopAddCommonMode(mainRunLoop(), (CFStringRef) NSModalPanelRunLoopMode);
@@ -1021,7 +859,7 @@ void QCocoaEventDispatcherPrivate::processPostedEvents()
if (currentExecIsNSAppRun) {
// The event dispatcher has been interrupted. But since
// [NSApplication run] is running the event loop, we
- // delayed stopping it until now (to let cocoa process
+ // delayed stopping it until now (to let cocoa process
// pending cocoa events first).
if (currentModalSessionCached)
temporarilyStopAllModalSessions();
@@ -1129,17 +967,8 @@ QCocoaEventDispatcher::~QCocoaEventDispatcher()
[nsevent release];
}
- // Remove CFSockets from the runloop.
- for (MacSocketHash::ConstIterator it = d->macSockets.constBegin(); it != d->macSockets.constEnd(); ++it) {
- MacSocketInfo *socketInfo = (*it);
- if (CFSocketIsValid(socketInfo->socket)) {
- qt_mac_remove_socket_from_runloop(socketInfo->socket, socketInfo->runloop);
- CFRunLoopSourceInvalidate(socketInfo->runloop);
- CFRelease(socketInfo->runloop);
- CFSocketInvalidate(socketInfo->socket);
- CFRelease(socketInfo->socket);
- }
- }
+ d->cfSocketNotifier.removeSocketNotifiers();
+
CFRunLoopRemoveSource(mainRunLoop(), d->postedEventsSource, kCFRunLoopCommonModes);
CFRelease(d->postedEventsSource);
diff --git a/src/plugins/platforms/cocoa/qcocoafiledialoghelper.mm b/src/plugins/platforms/cocoa/qcocoafiledialoghelper.mm
index 61646041fb..9cc0353dc6 100644
--- a/src/plugins/platforms/cocoa/qcocoafiledialoghelper.mm
+++ b/src/plugins/platforms/cocoa/qcocoafiledialoghelper.mm
@@ -77,11 +77,7 @@ typedef QSharedPointer<QFileDialogOptions> SharedPointerFileDialogOptions;
@class QT_MANGLE_NAMESPACE(QNSOpenSavePanelDelegate);
@interface QT_MANGLE_NAMESPACE(QNSOpenSavePanelDelegate)
-#if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_6
: NSObject<NSOpenSavePanelDelegate>
-#else
- : NSObject
-#endif
{
@public
NSOpenPanel *mOpenPanel;
@@ -216,7 +212,7 @@ static QString strippedText(QString s)
- (void)closePanel
{
*mCurrentSelection = QT_PREPEND_NAMESPACE(QCFString::toQString)([[mSavePanel URL] path]);
- if ([mSavePanel respondsToSelector:@selector(closePanel:)])
+ if ([mSavePanel respondsToSelector:@selector(close)])
[mSavePanel close];
if ([mSavePanel isSheet])
[NSApp endSheet: mSavePanel];
@@ -230,6 +226,7 @@ static QString strippedText(QString s)
bool selectable = (mOptions->acceptMode() == QFileDialogOptions::AcceptSave)
|| [self panel:nil shouldShowFilename:filepath];
+ [self updateProperties];
[mOpenPanel setAllowedFileTypes:nil];
[mOpenPanel setDirectoryURL:selectable ? [NSURL fileURLWithPath:QT_PREPEND_NAMESPACE(QCFString::toNSString)(info.filePath())]
: [NSURL fileURLWithPath:QT_PREPEND_NAMESPACE(QCFString::toNSString)(info.path())]];
@@ -274,6 +271,7 @@ static QString strippedText(QString s)
bool selectable = (mOptions->acceptMode() == QFileDialogOptions::AcceptSave)
|| [self panel:nil shouldShowFilename:filepath];
+ [self updateProperties];
[mSavePanel setDirectoryURL:selectable ? [NSURL fileURLWithPath:QT_PREPEND_NAMESPACE(QCFString::toNSString)(info.filePath())]
: [NSURL fileURLWithPath:QT_PREPEND_NAMESPACE(QCFString::toNSString)(info.path())]];
[mSavePanel setNameFieldStringValue:selectable ? QT_PREPEND_NAMESPACE(QCFString::toNSString)(info.fileName()) : nil];
@@ -405,6 +403,9 @@ static QString strippedText(QString s)
[mSavePanel setCanCreateDirectories:!(mOptions->testOption(QT_PREPEND_NAMESPACE(QFileDialogOptions::ReadOnly)))];
[mOpenPanel setAllowsMultipleSelection:(fileMode == QT_PREPEND_NAMESPACE(QFileDialogOptions::ExistingFiles))];
[mOpenPanel setResolvesAliases:!(mOptions->testOption(QT_PREPEND_NAMESPACE(QFileDialogOptions::DontResolveSymlinks)))];
+ [mOpenPanel setTitle:QCFString::toNSString(mOptions->windowTitle())];
+ [mSavePanel setTitle:QCFString::toNSString(mOptions->windowTitle())];
+ [mPopUpButton setHidden:chooseDirsOnly]; // TODO hide the whole sunken pane instead?
QStringList ext = [self acceptableExtensionsForSave];
const QString defaultSuffix = mOptions->defaultSuffix();
@@ -577,13 +578,16 @@ extern void qt_mac_to_pascal_string(QString s, Str255 str, TextEncoding encoding
void QCocoaFileDialogHelper::setDirectory(const QString &directory)
{
QT_MANGLE_NAMESPACE(QNSOpenSavePanelDelegate) *delegate = static_cast<QT_MANGLE_NAMESPACE(QNSOpenSavePanelDelegate) *>(mDelegate);
- [delegate->mSavePanel setDirectoryURL:[NSURL fileURLWithPath:QCFString::toNSString(directory)]];
+ if (delegate)
+ [delegate->mSavePanel setDirectoryURL:[NSURL fileURLWithPath:QCFString::toNSString(directory)]];
}
QString QCocoaFileDialogHelper::directory() const
{
QT_MANGLE_NAMESPACE(QNSOpenSavePanelDelegate) *delegate = static_cast<QT_MANGLE_NAMESPACE(QNSOpenSavePanelDelegate) *>(mDelegate);
- return QCFString::toQString([delegate->mSavePanel directory]);
+ if (delegate)
+ return QCFString::toQString([delegate->mSavePanel directory]);
+ return QString();
}
void QCocoaFileDialogHelper::selectFile(const QString &filename)
@@ -600,12 +604,16 @@ void QCocoaFileDialogHelper::selectFile(const QString &filename)
QStringList QCocoaFileDialogHelper::selectedFiles() const
{
QT_MANGLE_NAMESPACE(QNSOpenSavePanelDelegate) *delegate = static_cast<QT_MANGLE_NAMESPACE(QNSOpenSavePanelDelegate) *>(mDelegate);
- return [delegate selectedFiles];
+ if (delegate)
+ return [delegate selectedFiles];
+ return QStringList();
}
void QCocoaFileDialogHelper::setFilter()
{
QT_MANGLE_NAMESPACE(QNSOpenSavePanelDelegate) *delegate = static_cast<QT_MANGLE_NAMESPACE(QNSOpenSavePanelDelegate) *>(mDelegate);
+ if (!delegate)
+ return;
const SharedPointerFileDialogOptions &opts = options();
[delegate->mSavePanel setTitle:QCFString::toNSString(opts->windowTitle())];
if (opts->isLabelExplicitlySet(QFileDialogOptions::Accept))
@@ -618,9 +626,13 @@ void QCocoaFileDialogHelper::setFilter()
void QCocoaFileDialogHelper::selectNameFilter(const QString &filter)
{
+ if (!options())
+ return;
const int index = options()->nameFilters().indexOf(filter);
if (index != -1) {
QT_MANGLE_NAMESPACE(QNSOpenSavePanelDelegate) *delegate = static_cast<QT_MANGLE_NAMESPACE(QNSOpenSavePanelDelegate) *>(mDelegate);
+ if (!delegate)
+ return;
[delegate->mPopUpButton selectItemAtIndex:index];
[delegate filterChanged:nil];
}
@@ -629,7 +641,11 @@ void QCocoaFileDialogHelper::selectNameFilter(const QString &filter)
QString QCocoaFileDialogHelper::selectedNameFilter() const
{
QT_MANGLE_NAMESPACE(QNSOpenSavePanelDelegate) *delegate = static_cast<QT_MANGLE_NAMESPACE(QNSOpenSavePanelDelegate) *>(mDelegate);
+ if (!delegate)
+ return QString();
int index = [delegate->mPopUpButton indexOfSelectedItem];
+ if (index >= options()->nameFilters().count())
+ return QString();
return index != -1 ? options()->nameFilters().at(index) : QString();
}
@@ -675,6 +691,8 @@ bool QCocoaFileDialogHelper::showCocoaFilePanel(Qt::WindowModality windowModalit
{
createNSOpenSavePanelDelegate();
QT_MANGLE_NAMESPACE(QNSOpenSavePanelDelegate) *delegate = static_cast<QT_MANGLE_NAMESPACE(QNSOpenSavePanelDelegate) *>(mDelegate);
+ if (!delegate)
+ return false;
if (windowModality == Qt::NonModal)
[delegate showModelessPanel];
else if (windowModality == Qt::WindowModal && parent)
diff --git a/src/plugins/platforms/cocoa/qcocoaglcontext.mm b/src/plugins/platforms/cocoa/qcocoaglcontext.mm
index d0f5a58e22..d4673baaef 100644
--- a/src/plugins/platforms/cocoa/qcocoaglcontext.mm
+++ b/src/plugins/platforms/cocoa/qcocoaglcontext.mm
@@ -49,11 +49,19 @@
#import <Cocoa/Cocoa.h>
QCocoaGLContext::QCocoaGLContext(const QSurfaceFormat &format, QPlatformOpenGLContext *share)
- : m_format(format)
+ : m_context(nil),
+ m_shareContext(nil),
+ m_format(format)
{
+ // we only support OpenGL contexts under Cocoa
+ if (m_format.renderableType() == QSurfaceFormat::DefaultRenderableType)
+ m_format.setRenderableType(QSurfaceFormat::OpenGL);
+ if (m_format.renderableType() != QSurfaceFormat::OpenGL)
+ return;
+
QCocoaAutoReleasePool pool; // For the SG Canvas render thread
- NSOpenGLPixelFormat *pixelFormat = static_cast <NSOpenGLPixelFormat *>(qcgl_createNSOpenGLPixelFormat(format));
+ NSOpenGLPixelFormat *pixelFormat = static_cast <NSOpenGLPixelFormat *>(qcgl_createNSOpenGLPixelFormat(m_format));
m_shareContext = share ? static_cast<QCocoaGLContext *>(share)->nsOpenGLContext() : nil;
m_context = [NSOpenGLContext alloc];
@@ -70,6 +78,10 @@ QCocoaGLContext::QCocoaGLContext(const QSurfaceFormat &format, QPlatformOpenGLCo
const GLint interval = 1;
[m_context setValues:&interval forParameter:NSOpenGLCPSwapInterval];
+ if (format.alphaBufferSize() > 0) {
+ int zeroOpacity = 0;
+ [m_context setValues:&zeroOpacity forParameter:NSOpenGLCPSurfaceOpacity];
+ }
}
QCocoaGLContext::~QCocoaGLContext()
diff --git a/src/plugins/platforms/cocoa/qcocoahelpers.h b/src/plugins/platforms/cocoa/qcocoahelpers.h
index 831ab579f5..c801d9d926 100644
--- a/src/plugins/platforms/cocoa/qcocoahelpers.h
+++ b/src/plugins/platforms/cocoa/qcocoahelpers.h
@@ -84,8 +84,6 @@ HIMutableShapeRef qt_mac_QRegionToHIMutableShape(const QRegion &region);
OSStatus qt_mac_drawCGImage(CGContextRef inContext, const CGRect *inBounds, CGImageRef inImage);
-CGFloat qt_mac_get_scalefactor();
-
QChar qt_mac_qtKey2CocoaKey(Qt::Key key);
Qt::Key qt_mac_cocoaKey2QtKey(QChar keyCode);
diff --git a/src/plugins/platforms/cocoa/qcocoahelpers.mm b/src/plugins/platforms/cocoa/qcocoahelpers.mm
index 91a6f5a4c7..5ec2cea362 100644
--- a/src/plugins/platforms/cocoa/qcocoahelpers.mm
+++ b/src/plugins/platforms/cocoa/qcocoahelpers.mm
@@ -47,6 +47,7 @@
#include <QtGui>
#include <qpa/qplatformscreen.h>
#include <private/qguiapplication_p.h>
+#include <private/qwindow_p.h>
#ifndef QT_NO_WIDGETS
#include <QtWidgets/QWidget>
@@ -466,20 +467,17 @@ QString qt_mac_removeMnemonics(const QString &original)
return returnText;
}
-
-CGColorSpaceRef m_genericColorSpace = 0;
-QHash<CGDirectDisplayID, CGColorSpaceRef> m_displayColorSpaceHash;
-bool m_postRoutineRegistered = false;
+static CGColorSpaceRef m_genericColorSpace = 0;
+static QHash<CGDirectDisplayID, CGColorSpaceRef> m_displayColorSpaceHash;
+static bool m_postRoutineRegistered = false;
CGColorSpaceRef qt_mac_genericColorSpace()
{
#if 0
if (!m_genericColorSpace) {
-#if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_4
if (QSysInfo::MacintoshVersion >= QSysInfo::MV_10_4) {
m_genericColorSpace = CGColorSpaceCreateWithName(kCGColorSpaceGenericRGB);
} else
-#endif
{
m_genericColorSpace = CGColorSpaceCreateDeviceRGB();
}
@@ -587,10 +585,28 @@ QString qt_mac_applicationName()
return appName;
}
+/*
+ Mac window coordinates are in the first quadrant: 0, 0 is at the lower-left
+ corner of the primary screen. This function converts the given rect to an
+ NSRect for the window geometry, flipping from 4th quadrant to 1st quadrant
+ and simultaneously ensuring that as much of the window as possible will be
+ onscreen. If the rect is too tall for the screen, the OS will reduce the
+ window's height anyway; but by moving the window upwards we can have more
+ of it onscreen. But the application can still control the y coordinate
+ in case it really wants the window to be positioned partially offscreen.
+*/
NSRect qt_mac_flipRect(const QRect &rect, QWindow *window)
{
QPlatformScreen *onScreen = QPlatformScreen::platformScreenForWindow(window);
- int flippedY = onScreen->geometry().height() - rect.y() - rect.height();
+ int flippedY = onScreen->geometry().height() - (rect.y() + rect.height());
+
+ // In case of automatic positioning, try to put as much of the window onscreen as possible.
+ if (window->isTopLevel() && qt_window_private(const_cast<QWindow*>(window))->positionAutomatic && flippedY < 0)
+ flippedY = onScreen->geometry().height() - onScreen->availableGeometry().height() - onScreen->availableGeometry().y();
+#ifdef QT_COCOA_ENABLE_WINDOW_DEBUG
+ qDebug() << Q_FUNC_INFO << rect << "flippedY" << flippedY <<
+ "screen" << onScreen->geometry() << "available" << onScreen->availableGeometry();
+#endif
return NSMakeRect(rect.x(), flippedY, rect.width(), rect.height());
}
@@ -616,11 +632,6 @@ InvalidContext:
return err;
}
-CGFloat qt_mac_get_scalefactor()
-{
- return [[NSScreen mainScreen] userSpaceScaleFactor];
-}
-
Qt::MouseButton cocoaButton2QtButton(NSInteger buttonNum)
{
if (buttonNum == 0)
diff --git a/src/plugins/platforms/cocoa/qcocoaintegration.mm b/src/plugins/platforms/cocoa/qcocoaintegration.mm
index 93831158d0..d0fcf93b8c 100644
--- a/src/plugins/platforms/cocoa/qcocoaintegration.mm
+++ b/src/plugins/platforms/cocoa/qcocoaintegration.mm
@@ -105,7 +105,9 @@ void QCocoaScreen::updateGeometry()
m_physicalSize = QSizeF(size.width, size.height);
m_logicalDpi.first = 72;
m_logicalDpi.second = 72;
- m_refreshRate = CGDisplayModeGetRefreshRate(CGDisplayCopyDisplayMode(dpy));
+ float refresh = CGDisplayModeGetRefreshRate(CGDisplayCopyDisplayMode(dpy));
+ if (refresh > 0)
+ m_refreshRate = refresh;
// Get m_name (brand/model of the monitor)
NSDictionary *deviceInfo = (NSDictionary *)IODisplayCreateInfoDictionary(CGDisplayIOServicePort(dpy), kIODisplayOnlyPreferredName);
diff --git a/src/plugins/platforms/cocoa/qcocoaintrospection.mm b/src/plugins/platforms/cocoa/qcocoaintrospection.mm
index ffb6ae4294..806effc929 100644
--- a/src/plugins/platforms/cocoa/qcocoaintrospection.mm
+++ b/src/plugins/platforms/cocoa/qcocoaintrospection.mm
@@ -83,7 +83,6 @@ void qt_cocoa_change_implementation(Class baseClass, SEL originalSel, Class prox
if (QSysInfo::MacintoshVersion >= QSysInfo::MV_10_5)
#endif
{
-#if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_5
// The following code replaces the _implementation_ for the selector we want to hack
// (originalSel) with the implementation found in proxyClass. Then it creates
// a new 'backup' method inside baseClass containing the old, original,
@@ -104,7 +103,6 @@ void qt_cocoa_change_implementation(Class baseClass, SEL originalSel, Class prox
Method backupMethod = class_getInstanceMethod(proxyClass, backupSel);
class_addMethod(baseClass, backupSel, originalImp, method_getTypeEncoding(backupMethod));
}
-#endif
}
}
@@ -114,11 +112,9 @@ void qt_cocoa_change_back_implementation(Class baseClass, SEL originalSel, SEL b
if (QSysInfo::MacintoshVersion >= QSysInfo::MV_10_5)
#endif
{
-#if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_5
Method originalMethod = class_getInstanceMethod(baseClass, originalSel);
Method backupMethodInBaseClass = class_getInstanceMethod(baseClass, backupSel);
method_setImplementation(originalMethod, method_getImplementation(backupMethodInBaseClass));
-#endif
}
}
diff --git a/src/plugins/platforms/cocoa/qcocoamenu.h b/src/plugins/platforms/cocoa/qcocoamenu.h
index 09b62a9bcd..439b7f1a75 100644
--- a/src/plugins/platforms/cocoa/qcocoamenu.h
+++ b/src/plugins/platforms/cocoa/qcocoamenu.h
@@ -51,8 +51,6 @@
@class NSMenu;
@class NSObject;
-QT_BEGIN_HEADER
-
QT_BEGIN_NAMESPACE
class QCocoaMenu : public QPlatformMenu
@@ -71,11 +69,17 @@ public:
void syncMenuItem(QPlatformMenuItem *menuItem);
void setEnabled(bool enabled);
void setVisible(bool visible);
+ void showPopup(const QWindow *parentWindow, QPoint pos, const QPlatformMenuItem *item);
+
void syncSeparatorsCollapsible(bool enable);
void syncModalState(bool modal);
- virtual void setText(const QString &text);
+ virtual void setIcon(const QIcon &icon) { Q_UNUSED(icon) }
+
+ void setText(const QString &text);
+ void setMinimumWidth(int width);
+ void setFont(const QFont &font);
void setParentItem(QCocoaMenuItem* item);
@@ -102,6 +106,4 @@ private:
QT_END_NAMESPACE
-QT_END_HEADER
-
#endif
diff --git a/src/plugins/platforms/cocoa/qcocoamenu.mm b/src/plugins/platforms/cocoa/qcocoamenu.mm
index 676f0683fa..0fe4c48510 100644
--- a/src/plugins/platforms/cocoa/qcocoamenu.mm
+++ b/src/plugins/platforms/cocoa/qcocoamenu.mm
@@ -47,6 +47,8 @@
#include <QtCore/QtDebug>
#include "qcocoaapplication.h"
#include "qcocoamenuloader.h"
+#include "qcocoawindow.h"
+#import "qnsview.h"
static inline QT_MANGLE_NAMESPACE(QCocoaMenuLoader) *getMenuLoader()
{
@@ -133,6 +135,20 @@ void QCocoaMenu::setText(const QString &text)
[m_nativeItem setTitle:QCFString::toNSString(stripped)];
}
+void QCocoaMenu::setMinimumWidth(int width)
+{
+ m_nativeMenu.minimumWidth = width;
+}
+
+void QCocoaMenu::setFont(const QFont &font)
+{
+ if (font.resolve()) {
+ NSFont *customMenuFont = [NSFont fontWithName:QCFString::toNSString(font.family())
+ size:font.pointSize()];
+ m_nativeMenu.font = customMenuFont;
+ }
+}
+
void QCocoaMenu::insertMenuItem(QPlatformMenuItem *menuItem, QPlatformMenuItem *before)
{
QCocoaAutoReleasePool pool;
@@ -290,9 +306,26 @@ void QCocoaMenu::setVisible(bool visible)
[m_nativeItem setSubmenu:(visible ? m_nativeMenu : nil)];
}
+void QCocoaMenu::showPopup(const QWindow *parentWindow, QPoint pos, const QPlatformMenuItem *item)
+{
+ QCocoaWindow *cocoaWindow = parentWindow ? static_cast<QCocoaWindow *>(parentWindow->handle()) : 0;
+ NSView *view = cocoaWindow ? cocoaWindow->contentView() : nil;
+ NSMenuItem *nsItem = item ? ((QCocoaMenuItem *)item)->nsItem() : nil;
+ NSPoint nsPos = NSMakePoint(pos.x(), pos.y());
+ [m_nativeMenu popUpMenuPositioningItem:nsItem atLocation:nsPos inView:view];
+
+ // The call above blocks, and also swallows any mouse release event,
+ // so we need to clear any mouse button that triggered the menu popup.
+ if ([view isKindOfClass:[QNSView class]])
+ [(QNSView *)view resetMouseButtons];
+}
+
QPlatformMenuItem *QCocoaMenu::menuItemAt(int position) const
{
- return m_menuItems.at(position);
+ if (0 <= position && position < m_menuItems.count())
+ return m_menuItems.at(position);
+
+ return 0;
}
QPlatformMenuItem *QCocoaMenu::menuItemForTag(quintptr tag) const
diff --git a/src/plugins/platforms/cocoa/qcocoamenuitem.h b/src/plugins/platforms/cocoa/qcocoamenuitem.h
index fe5193a50c..0e6d17343d 100644
--- a/src/plugins/platforms/cocoa/qcocoamenuitem.h
+++ b/src/plugins/platforms/cocoa/qcocoamenuitem.h
@@ -51,8 +51,6 @@
@class NSMenuItem;
@class NSMenu;
-QT_BEGIN_HEADER
-
QT_BEGIN_NAMESPACE
class QCocoaMenu;
@@ -76,6 +74,7 @@ public:
void setFont(const QFont &font);
void setRole(MenuRole role);
void setShortcut(const QKeySequence& shortcut);
+ void setCheckable(bool checkable) { Q_UNUSED(checkable) }
void setChecked(bool isChecked);
void setEnabled(bool isEnabled);
@@ -110,8 +109,6 @@ private:
quintptr m_tag;
};
-QT_END_HEADER
-
QT_END_NAMESPACE
#endif
diff --git a/src/plugins/platforms/cocoa/qcocoaprintersupport.h b/src/plugins/platforms/cocoa/qcocoaprintersupport.h
index 040b687c4e..83cf1ffada 100644
--- a/src/plugins/platforms/cocoa/qcocoaprintersupport.h
+++ b/src/plugins/platforms/cocoa/qcocoaprintersupport.h
@@ -55,6 +55,7 @@ public:
QPrintEngine *createNativePrintEngine(QPrinter::PrinterMode printerMode) Q_DECL_OVERRIDE;
QPaintEngine *createPaintEngine(QPrintEngine *, QPrinter::PrinterMode printerMode) Q_DECL_OVERRIDE;
QList<QPrinter::PaperSize> supportedPaperSizes(const QPrinterInfo &) const Q_DECL_OVERRIDE;
+ QList<QPair<QString, QSizeF> > supportedSizesWithNames(const QPrinterInfo &) const Q_DECL_OVERRIDE;
QList<QPrinterInfo> availablePrinters() Q_DECL_OVERRIDE;
QPrinterInfo printerInfo(const QString &printerName) Q_DECL_OVERRIDE;
diff --git a/src/plugins/platforms/cocoa/qcocoaprintersupport.mm b/src/plugins/platforms/cocoa/qcocoaprintersupport.mm
index a48db02949..cfa23b7a30 100644
--- a/src/plugins/platforms/cocoa/qcocoaprintersupport.mm
+++ b/src/plugins/platforms/cocoa/qcocoaprintersupport.mm
@@ -138,3 +138,34 @@ QPrinterInfo QCocoaPrinterSupport::printerInfoFromPMPrinter(const PMPrinter &pri
return createPrinterInfo(name, description, location, makeAndModel, isDefault, 0);
}
+
+QList<QPair<QString, QSizeF> > QCocoaPrinterSupport::supportedSizesWithNames(const QPrinterInfo &printerInfo) const
+{
+ QList<QPair<QString, QSizeF> > returnValue;
+ if (printerInfo.isNull())
+ return returnValue;
+
+ PMPrinter printer = PMPrinterCreateFromPrinterID(QCFString::toCFStringRef(printerInfo.printerName()));
+ if (!printer)
+ return returnValue;
+
+ CFArrayRef array;
+ if (PMPrinterGetPaperList(printer, &array) != noErr) {
+ PMRelease(printer);
+ return returnValue;
+ }
+
+ int count = CFArrayGetCount(array);
+ for (int i = 0; i < count; ++i) {
+ PMPaper paper = static_cast<PMPaper>(const_cast<void *>(CFArrayGetValueAtIndex(array, i)));
+ double width, height;
+ if (PMPaperGetWidth(paper, &width) == noErr && PMPaperGetHeight(paper, &height) == noErr) {
+ static const double OnePointInMillimeters = 1.0 / 72.0 * 25.4;
+ QCFString paperName;
+ if (PMPaperCreateLocalizedName(paper, printer, &paperName) == noErr)
+ returnValue.append(qMakePair(QString(paperName), QSizeF(width * OnePointInMillimeters, height * OnePointInMillimeters)));
+ }
+ }
+ PMRelease(printer);
+ return returnValue;
+}
diff --git a/src/plugins/platforms/cocoa/qcocoasystemtrayicon.h b/src/plugins/platforms/cocoa/qcocoasystemtrayicon.h
index 89ab51cf05..61a6ba3e2f 100755
--- a/src/plugins/platforms/cocoa/qcocoasystemtrayicon.h
+++ b/src/plugins/platforms/cocoa/qcocoasystemtrayicon.h
@@ -43,6 +43,8 @@
#ifndef QCOCOASYSTEMTRAYICON_P_H
#define QCOCOASYSTEMTRAYICON_P_H
+#include <QtCore/qglobal.h>
+
#ifndef QT_NO_SYSTEMTRAYICON
#include "QtCore/qstring.h"
diff --git a/src/plugins/platforms/cocoa/qcocoasystemtrayicon.mm b/src/plugins/platforms/cocoa/qcocoasystemtrayicon.mm
index e092db8172..99f533b33a 100755
--- a/src/plugins/platforms/cocoa/qcocoasystemtrayicon.mm
+++ b/src/plugins/platforms/cocoa/qcocoasystemtrayicon.mm
@@ -93,7 +93,11 @@ QT_USE_NAMESPACE
@class QT_MANGLE_NAMESPACE(QNSMenu);
@class QT_MANGLE_NAMESPACE(QNSImageView);
-@interface QT_MANGLE_NAMESPACE(QNSStatusItem) : NSObject {
+@interface QT_MANGLE_NAMESPACE(QNSStatusItem) : NSObject
+#if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_8
+ <NSUserNotificationCenterDelegate>
+#endif
+ {
@public
QCocoaSystemTrayIcon *systray;
NSStatusItem *item;
@@ -108,6 +112,11 @@ QT_USE_NAMESPACE
-(QRectF)geometry;
- (void)triggerSelector:(id)sender button:(Qt::MouseButton)mouseButton;
- (void)doubleClickSelector:(id)sender;
+
+#if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_8
+- (BOOL)userNotificationCenter:(NSUserNotificationCenter *)center shouldPresentNotification:(NSUserNotification *)notification;
+- (void)userNotificationCenter:(NSUserNotificationCenter *)center didActivateNotification:(NSUserNotification *)notification;
+#endif
@end
@interface QT_MANGLE_NAMESPACE(QNSImageView) : NSImageView {
@@ -132,9 +141,19 @@ class QSystemTrayIconSys
public:
QSystemTrayIconSys(QCocoaSystemTrayIcon *sys) {
item = [[QT_MANGLE_NAMESPACE(QNSStatusItem) alloc] initWithSysTray:sys];
+#if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_8
+ if (QSysInfo::MacintoshVersion >= QSysInfo::MV_10_8) {
+ [[NSUserNotificationCenter defaultUserNotificationCenter] setDelegate:item];
+ }
+#endif
}
~QSystemTrayIconSys() {
[[[item item] view] setHidden: YES];
+#if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_8
+ if (QSysInfo::MacintoshVersion >= QSysInfo::MV_10_8) {
+ [[NSUserNotificationCenter defaultUserNotificationCenter] setDelegate:nil];
+ }
+#endif
[item release];
}
QT_MANGLE_NAMESPACE(QNSStatusItem) *item;
@@ -223,6 +242,18 @@ void QCocoaSystemTrayIcon::showMessage(const QString &title, const QString &mess
if (!m_sys)
return;
+#if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_8
+ if (QSysInfo::MacintoshVersion >= QSysInfo::MV_10_8) {
+ NSUserNotification *notification = [[NSUserNotification alloc] init];
+ notification.title = [NSString stringWithUTF8String:title.toUtf8().data()];
+ notification.informativeText = [NSString stringWithUTF8String:message.toUtf8().data()];
+
+ [[NSUserNotificationCenter defaultUserNotificationCenter] deliverNotification:notification];
+
+ return;
+ }
+#endif
+
#ifdef QT_MAC_SYSTEMTRAY_USE_GROWL
// Make sure that we have Growl installed on the machine we are running on.
QCFType<CFURLRef> cfurl;
@@ -439,6 +470,20 @@ QT_END_NAMESPACE
emit systray->activated(QPlatformSystemTrayIcon::DoubleClick);
}
+#if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_8
+- (BOOL)userNotificationCenter:(NSUserNotificationCenter *)center shouldPresentNotification:(NSUserNotification *)notification {
+ Q_UNUSED(center);
+ Q_UNUSED(notification);
+ return YES;
+}
+
+- (void)userNotificationCenter:(NSUserNotificationCenter *)center didActivateNotification:(NSUserNotification *)notification {
+ Q_UNUSED(center);
+ Q_UNUSED(notification);
+ emit systray->messageClicked();
+}
+#endif
+
@end
class QSystemTrayIconQMenu : public QPlatformMenu
diff --git a/src/plugins/platforms/cocoa/qcocoawindow.h b/src/plugins/platforms/cocoa/qcocoawindow.h
index 08c516b4f4..fdb3f4672f 100644
--- a/src/plugins/platforms/cocoa/qcocoawindow.h
+++ b/src/plugins/platforms/cocoa/qcocoawindow.h
@@ -116,6 +116,8 @@ public:
bool setMouseGrabEnabled(bool grab);
QMargins frameMargins() const;
+ void requestActivateWindow();
+
WId winId() const;
void setParent(const QPlatformWindow *window);
@@ -159,6 +161,8 @@ protected:
QCocoaWindow *parentCocoaWindow() const;
void syncWindowState(Qt::WindowState newState);
+ void updateOpaque();
+
// private:
public: // for QNSView
friend class QCocoaBackingStore;
diff --git a/src/plugins/platforms/cocoa/qcocoawindow.mm b/src/plugins/platforms/cocoa/qcocoawindow.mm
index 467025c77b..9466b68bec 100644
--- a/src/plugins/platforms/cocoa/qcocoawindow.mm
+++ b/src/plugins/platforms/cocoa/qcocoawindow.mm
@@ -420,6 +420,8 @@ void QCocoaWindow::setWindowFlags(Qt::WindowFlags flags)
NSInteger level = this->windowLevel(flags);
[m_nsWindow setStyleMask:styleMask];
[m_nsWindow setLevel:level];
+ [m_nsWindow setIgnoresMouseEvents:((flags & Qt::ToolTip) == Qt::ToolTip) ? YES : NO];
+ // TODO deal with WindowTransparentForInput; setIgnoresMouseEvents is too extreme, you can't click the titlebar
setWindowShadow(flags);
}
@@ -534,20 +536,30 @@ void QCocoaWindow::propagateSizeHints()
}
}
+void QCocoaWindow::updateOpaque()
+{
+ bool translucent = window()->format().alphaBufferSize() > 0
+ || window()->opacity() < 1
+ || (m_contentView && [m_contentView hasMask]);
+ [m_nsWindow setOpaque:!translucent];
+}
+
+
void QCocoaWindow::setOpacity(qreal level)
{
- if (m_nsWindow)
+ if (m_nsWindow) {
[m_nsWindow setAlphaValue:level];
+ updateOpaque();
+ }
}
void QCocoaWindow::setMask(const QRegion &region)
{
- if (m_nsWindow) {
- [m_nsWindow setOpaque:NO];
+ if (m_nsWindow)
[m_nsWindow setBackgroundColor:[NSColor clearColor]];
- }
[m_qtView setMaskRegion:&region];
+ updateOpaque();
}
bool QCocoaWindow::setKeyboardGrabEnabled(bool grab)
@@ -691,6 +703,13 @@ void QCocoaWindow::recreateWindow(const QPlatformWindow *parentWindow)
setOpacity(opacity);
}
+void QCocoaWindow::requestActivateWindow()
+{
+ NSWindow *window = [m_contentView window];
+ [ window makeFirstResponder : m_contentView ];
+ [ window makeKeyWindow ];
+}
+
NSWindow * QCocoaWindow::createNSWindow()
{
QCocoaAutoReleasePool pool;
@@ -753,6 +772,12 @@ NSWindow * QCocoaWindow::createNSWindow()
NSInteger level = windowLevel(flags);
[createdWindow setLevel:level];
+
+ if (window()->format().alphaBufferSize() > 0) {
+ [createdWindow setBackgroundColor:[NSColor clearColor]];
+ [createdWindow setOpaque:NO];
+ }
+
m_windowModality = window()->modality();
return createdWindow;
}
diff --git a/src/plugins/platforms/cocoa/qmacdefines_mac.h b/src/plugins/platforms/cocoa/qmacdefines_mac.h
index 18c1ac84de..c03b398836 100644
--- a/src/plugins/platforms/cocoa/qmacdefines_mac.h
+++ b/src/plugins/platforms/cocoa/qmacdefines_mac.h
@@ -79,15 +79,11 @@
*/
/* This is just many defines. Therefore it doesn't need things like:
-QT_BEGIN_HEADER
-
QT_BEGIN_NAMESPACE
QT_END_NAMESPACE
-QT_END_HEADER
-
Yes, it is an informative comment ;-)
*/
diff --git a/src/plugins/platforms/cocoa/qmultitouch_mac.mm b/src/plugins/platforms/cocoa/qmultitouch_mac.mm
index 337d962c7f..fc0048f998 100644
--- a/src/plugins/platforms/cocoa/qmultitouch_mac.mm
+++ b/src/plugins/platforms/cocoa/qmultitouch_mac.mm
@@ -42,8 +42,6 @@
#include "qmultitouch_mac_p.h"
#include "qcocoahelpers.h"
-#if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_6
-
QT_BEGIN_NAMESPACE
QHash<qint64, QCocoaTouch*> QCocoaTouch::_currentTouches;
@@ -214,6 +212,3 @@ QCocoaTouch::getCurrentTouchPointList(NSEvent *event, bool acceptSingleTouch)
}
QT_END_NAMESPACE
-
-#endif // MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_6
-
diff --git a/src/plugins/platforms/cocoa/qmultitouch_mac_p.h b/src/plugins/platforms/cocoa/qmultitouch_mac_p.h
index 1244b8223f..736eb3f878 100644
--- a/src/plugins/platforms/cocoa/qmultitouch_mac_p.h
+++ b/src/plugins/platforms/cocoa/qmultitouch_mac_p.h
@@ -61,8 +61,6 @@
#include <qhash.h>
#include <QtCore>
-#if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_6
-
QT_BEGIN_NAMESPACE
class QCocoaTouch
@@ -92,7 +90,5 @@ class QCocoaTouch
QT_END_NAMESPACE
-#endif // MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_6
-
#endif // QMULTITOUCH_MAC_P_H
diff --git a/src/plugins/platforms/cocoa/qnsview.h b/src/plugins/platforms/cocoa/qnsview.h
index 853b4b99e1..5ccea3c387 100644
--- a/src/plugins/platforms/cocoa/qnsview.h
+++ b/src/plugins/platforms/cocoa/qnsview.h
@@ -86,6 +86,10 @@ QT_END_NAMESPACE
- (BOOL)isFlipped;
- (BOOL)acceptsFirstResponder;
+- (BOOL)becomeFirstResponder;
+- (BOOL)hasMask;
+
+- (void)resetMouseButtons;
- (void)handleMouseEvent:(NSEvent *)theEvent;
- (void)mouseDown:(NSEvent *)theEvent;
diff --git a/src/plugins/platforms/cocoa/qnsview.mm b/src/plugins/platforms/cocoa/qnsview.mm
index 0c122eaf2d..e608731cc1 100644
--- a/src/plugins/platforms/cocoa/qnsview.mm
+++ b/src/plugins/platforms/cocoa/qnsview.mm
@@ -304,6 +304,11 @@ static QTouchDevice *touchDevice = 0;
[self setNeedsDisplayInRect:NSMakeRect(br.x(), br.y(), br.width(), br.height())];
}
+- (BOOL) hasMask
+{
+ return m_maskData != 0;
+}
+
- (void) setMaskRegion:(const QRegion *)region
{
m_shouldInvalidateWindowShadow = true;
@@ -397,8 +402,27 @@ static QTouchDevice *touchDevice = 0;
return YES;
}
+- (BOOL)becomeFirstResponder
+{
+ QWindow *focusWindow = m_window;
+
+ // For widgets we need to do a bit of trickery as the window
+ // to activate is the window of the top-level widget.
+ if (m_window->metaObject()->className() == QStringLiteral("QWidgetWindow")) {
+ while (focusWindow->parent()) {
+ focusWindow = focusWindow->parent();
+ }
+ }
+ QWindowSystemInterface::handleWindowActivated(focusWindow);
+ return YES;
+}
+
- (BOOL)acceptsFirstResponder
{
+ if (m_window->flags() & Qt::WindowDoesNotAcceptFocus)
+ return NO;
+ if ((m_window->flags() & Qt::ToolTip) == Qt::ToolTip)
+ return NO;
return YES;
}
@@ -447,6 +471,11 @@ static QTouchDevice *touchDevice = 0;
}
}
+- (void)resetMouseButtons
+{
+ m_buttons = Qt::NoButton;
+}
+
- (void)handleMouseEvent:(NSEvent *)theEvent
{
QPoint qtWindowPoint, qtScreenPoint;
diff --git a/src/plugins/platforms/cocoa/qnsviewaccessibility.mm b/src/plugins/platforms/cocoa/qnsviewaccessibility.mm
index 8ee39bf767..e05ffbe343 100644
--- a/src/plugins/platforms/cocoa/qnsviewaccessibility.mm
+++ b/src/plugins/platforms/cocoa/qnsviewaccessibility.mm
@@ -46,7 +46,7 @@
#include "qcocoaaccessibility.h"
#include "qcocoaaccessibilityelement.h"
-#include "QAccessibleActionInterface"
+#include <QtGui/private/qaccessible2_p.h>
#include <QtCore/QDebug>
#import <AppKit/NSAccessibility.h>
diff --git a/src/plugins/platforms/cocoa/qnswindowdelegate.h b/src/plugins/platforms/cocoa/qnswindowdelegate.h
index 53bbeb1318..98ad7b8c9d 100644
--- a/src/plugins/platforms/cocoa/qnswindowdelegate.h
+++ b/src/plugins/platforms/cocoa/qnswindowdelegate.h
@@ -46,26 +46,6 @@
#include "qcocoawindow.h"
-#if MAC_OS_X_VERSION_MAX_ALLOWED <= MAC_OS_X_VERSION_10_5
-@protocol NSWindowDelegate <NSObject>
-//- (NSSize)windowWillResize:(NSWindow *)window toSize:(NSSize)proposedFrameSize;
-//- (void)windowDidMiniaturize:(NSNotification*)notification;
-- (void)windowDidResize:(NSNotification *)notification;
-- (void)windowWillClose:(NSNotification *)notification;
-//- (NSRect)windowWillUseStandardFrame:(NSWindow *)window defaultFrame:(NSRect)defaultFrame;
-- (void)windowDidMove:(NSNotification *)notification;
-//- (BOOL)windowShouldClose:(id)window;
-//- (void)windowDidDeminiaturize:(NSNotification *)notification;
-//- (void)windowDidBecomeMain:(NSNotification*)notification;
-//- (void)windowDidResignMain:(NSNotification*)notification;
-//- (void)windowDidBecomeKey:(NSNotification*)notification;
-//- (void)windowDidResignKey:(NSNotification*)notification;
-//- (BOOL)window:(NSWindow *)window shouldPopUpDocumentPathMenu:(NSMenu *)menu;
-//- (BOOL)window:(NSWindow *)window shouldDragDocumentWithEvent:(NSEvent *)event from:(NSPoint)dragImageLocation withPasteboard:(NSPasteboard *)pasteboard;
-//- (BOOL)windowShouldZoom:(NSWindow *)window toFrame:(NSRect)newFrame;
-@end
-#endif
-
@interface QNSWindowDelegate : NSObject <NSWindowDelegate>
{
QCocoaWindow *m_cocoaWindow;
diff --git a/src/plugins/platforms/cocoa/qpaintengine_mac.mm b/src/plugins/platforms/cocoa/qpaintengine_mac.mm
index 0b6392fb65..301beb11c1 100644
--- a/src/plugins/platforms/cocoa/qpaintengine_mac.mm
+++ b/src/plugins/platforms/cocoa/qpaintengine_mac.mm
@@ -76,7 +76,7 @@ QT_BEGIN_NAMESPACE
QCoreGraphicsPaintEngine utility functions
*****************************************************************************/
-void qt_mac_clip_cg(CGContextRef hd, const QRegion &rgn, CGAffineTransform *orig_xform)
+static void qt_mac_clip_cg(CGContextRef hd, const QRegion &rgn, CGAffineTransform *orig_xform)
{
CGAffineTransform old_xform = CGAffineTransformIdentity;
if (orig_xform) { //setup xforms
@@ -90,14 +90,11 @@ void qt_mac_clip_cg(CGContextRef hd, const QRegion &rgn, CGAffineTransform *orig
if (rgn.isEmpty()) {
CGContextAddRect(hd, CGRectMake(0, 0, 0, 0));
} else {
-#if (MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_5)
if (QSysInfo::MacintoshVersion >= QSysInfo::MV_10_5) {
QCFType<HIMutableShapeRef> shape = qt_mac_QRegionToHIMutableShape(rgn);
Q_ASSERT(!HIShapeIsEmpty(shape));
HIShapeReplacePathInCGContext(shape, hd);
- } else
-#endif
- {
+ } else {
QVector<QRect> rects = rgn.rects();
const int count = rects.size();
for (int i = 0; i < count; i++) {
@@ -338,11 +335,9 @@ CGColorSpaceRef QCoreGraphicsPaintEngine::macGenericColorSpace()
{
#if 0
if (!m_genericColorSpace) {
-#if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_4
if (QSysInfo::MacintoshVersion >= QSysInfo::MV_10_4) {
m_genericColorSpace = CGColorSpaceCreateWithName(kCGColorSpaceGenericRGB);
} else
-#endif
{
m_genericColorSpace = CGColorSpaceCreateDeviceRGB();
}
@@ -1185,7 +1180,6 @@ extern "C" {
void
QCoreGraphicsPaintEngine::updateCompositionMode(QPainter::CompositionMode mode)
{
-#if (MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_5)
if (QSysInfo::MacintoshVersion >= QSysInfo::MV_10_5) {
int cg_mode = kCGBlendModeNormal;
switch (mode) {
@@ -1267,11 +1261,9 @@ QCoreGraphicsPaintEngine::updateCompositionMode(QPainter::CompositionMode mode)
if (cg_mode > -1) {
CGContextSetBlendMode(d_func()->hd, CGBlendMode(cg_mode));
}
- } else
-#endif
- // The standard porter duff ops.
- if (QSysInfo::MacintoshVersion >= QSysInfo::MV_10_3
+ } else if (QSysInfo::MacintoshVersion >= QSysInfo::MV_10_3
&& mode <= QPainter::CompositionMode_Xor) {
+ // The standard porter duff ops.
int cg_mode = kCGCompositeModeCopy;
switch (mode) {
case QPainter::CompositionMode_SourceOver:
@@ -1317,7 +1309,6 @@ QCoreGraphicsPaintEngine::updateCompositionMode(QPainter::CompositionMode mode)
if (cg_mode > -1)
CGContextSetCompositeOperation(d_func()->hd, CGCompositeMode(cg_mode));
} else {
-#if (MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_4)
bool needPrivateAPI = false;
if (QSysInfo::MacintoshVersion >= QSysInfo::MV_10_4) {
int cg_mode = kCGBlendModeNormal;
@@ -1367,7 +1358,6 @@ QCoreGraphicsPaintEngine::updateCompositionMode(QPainter::CompositionMode mode)
else
CGContextSetCompositeOperation(d_func()->hd, CGCompositeMode(cg_mode));
}
-#endif
}
}
@@ -1376,13 +1366,8 @@ QCoreGraphicsPaintEngine::updateRenderHints(QPainter::RenderHints hints)
{
Q_D(QCoreGraphicsPaintEngine);
CGContextSetShouldAntialias(d->hd, hints & QPainter::Antialiasing);
- static const CGFloat ScaleFactor = qt_mac_get_scalefactor();
- if (ScaleFactor > 1.) {
- CGContextSetInterpolationQuality(d->hd, kCGInterpolationHigh);
- } else {
- CGContextSetInterpolationQuality(d->hd, (hints & QPainter::SmoothPixmapTransform) ?
- kCGInterpolationHigh : kCGInterpolationNone);
- }
+ CGContextSetInterpolationQuality(d->hd, (hints & QPainter::SmoothPixmapTransform) ?
+ kCGInterpolationHigh : kCGInterpolationNone);
bool textAntialiasing = (hints & QPainter::TextAntialiasing) == QPainter::TextAntialiasing;
if (!textAntialiasing || d->disabledSmoothFonts) {
d->disabledSmoothFonts = !textAntialiasing;
diff --git a/src/plugins/platforms/cocoa/qpaintengine_mac_p.h b/src/plugins/platforms/cocoa/qpaintengine_mac_p.h
index 2763a14690..fa000b9f92 100644
--- a/src/plugins/platforms/cocoa/qpaintengine_mac_p.h
+++ b/src/plugins/platforms/cocoa/qpaintengine_mac_p.h
@@ -122,8 +122,6 @@ public:
void drawPolygon(const QPoint *points, int pointCount, PolygonDrawMode mode)
{ QPaintEngine::drawPolygon(points, pointCount, mode); }
- bool supportsTransformations(qreal, const QTransform &) const { return true; };
-
protected:
friend class QMacPrintEngine;
friend class QMacPrintEnginePrivate;
diff --git a/src/plugins/platforms/cocoa/qprintengine_mac.mm b/src/plugins/platforms/cocoa/qprintengine_mac.mm
index 54019372bc..4748005f1a 100644
--- a/src/plugins/platforms/cocoa/qprintengine_mac.mm
+++ b/src/plugins/platforms/cocoa/qprintengine_mac.mm
@@ -180,6 +180,38 @@ QPrinter::PaperSize QMacPrintEnginePrivate::paperSize() const
return QPlatformPrinterSupport::convertQSizeFToPaperSize(sizef);
}
+void QMacPrintEnginePrivate::setPaperName(const QString &name)
+{
+ Q_Q(QMacPrintEngine);
+ PMPrinter printer;
+
+ if (PMSessionGetCurrentPrinter(session(), &printer) == noErr) {
+ CFArrayRef array;
+ if (PMPrinterGetPaperList(printer, &array) != noErr) {
+ PMRelease(printer);
+ return;
+ }
+ int count = CFArrayGetCount(array);
+ for (int i = 0; i < count; ++i) {
+ PMPaper paper = static_cast<PMPaper>(const_cast<void *>(CFArrayGetValueAtIndex(array, i)));
+ QCFString paperName;
+ if (PMPaperCreateLocalizedName(paper, printer, &paperName) == noErr) {
+ if (QString(paperName) == name) {
+ PMPageFormat tmp;
+ PMCreatePageFormatWithPMPaper(&tmp, paper);
+ PMCopyPageFormat(tmp, format());
+ q->setProperty(QPrintEngine::PPK_Orientation, orient);
+ if (PMSessionValidatePageFormat(session(), format(), kPMDontWantBoolean) != noErr) {
+ // Don't know, warn for the moment.
+ qWarning("QMacPrintEngine, problem setting paper name");
+ }
+ }
+ }
+ }
+ PMRelease(printer);
+ }
+}
+
QList<QVariant> QMacPrintEnginePrivate::supportedResolutions() const
{
Q_ASSERT_X(printInfo, "QMacPrinterEngine::supportedResolutions",
@@ -190,23 +222,7 @@ QList<QVariant> QMacPrintEnginePrivate::supportedResolutions() const
if (PMSessionGetCurrentPrinter(session(), &printer) == noErr) {
PMResolution res;
OSStatus status = PMPrinterGetPrinterResolutionCount(printer, &resCount);
- if (status == kPMNotImplemented) {
-#if (MAC_OS_X_VERSION_MAX_ALLOWED < MAC_OS_X_VERSION_10_5)
- // *Sigh* we have to use the non-indexed version.
- if (PMPrinterGetPrinterResolution(printer, kPMMinSquareResolution, &res) == noErr)
- resolutions.append(int(res.hRes));
- if (PMPrinterGetPrinterResolution(printer, kPMMaxSquareResolution, &res) == noErr) {
- QVariant var(int(res.hRes));
- if (!resolutions.contains(var))
- resolutions.append(var);
- }
- if (PMPrinterGetPrinterResolution(printer, kPMDefaultResolution, &res) == noErr) {
- QVariant var(int(res.hRes));
- if (!resolutions.contains(var))
- resolutions.append(var);
- }
-#endif
- } else if (status == noErr) {
+ if (status == noErr) {
// According to the docs, index start at 1.
for (UInt32 i = 1; i <= resCount; ++i) {
if (PMPrinterGetIndexedPrinterResolution(printer, i, &res) == noErr)
@@ -617,6 +633,9 @@ void QMacPrintEngine::setProperty(PrintEnginePropertyKey key, const QVariant &va
case PPK_PaperSize:
d->setPaperSize(QPrinter::PaperSize(value.toInt()));
break;
+ case PPK_PaperName:
+ d->setPaperName(value.toString());
+ break;
case PPK_PrinterName: {
bool printerNameSet = false;
OSStatus status = noErr;
@@ -755,6 +774,9 @@ QVariant QMacPrintEngine::property(PrintEnginePropertyKey key) const
case PPK_PaperSize:
ret = d->paperSize();
break;
+ case PPK_PaperName:
+ ret = QCFString::toQString([d->printInfo localizedPaperName]);
+ break;
case PPK_PaperRect: {
QRect r;
PMRect macrect;
diff --git a/src/plugins/platforms/cocoa/qprintengine_mac_p.h b/src/plugins/platforms/cocoa/qprintengine_mac_p.h
index e122cc5822..28183118d8 100644
--- a/src/plugins/platforms/cocoa/qprintengine_mac_p.h
+++ b/src/plugins/platforms/cocoa/qprintengine_mac_p.h
@@ -53,6 +53,8 @@
// We mean it.
//
+#include <QtCore/qglobal.h>
+
#ifndef QT_NO_PRINTER
#include <QtPrintSupport/qprinter.h>
@@ -142,6 +144,7 @@ public:
bool newPage_helper();
void setPaperSize(QPrinter::PaperSize ps);
QPrinter::PaperSize paperSize() const;
+ void setPaperName(const QString &name);
QList<QVariant> supportedResolutions() const;
inline bool isPrintSessionInitialized() const
{
diff --git a/src/plugins/platforms/directfb/qdirectfbcursor.cpp b/src/plugins/platforms/directfb/qdirectfbcursor.cpp
index afddba3482..b03af51b1a 100644
--- a/src/plugins/platforms/directfb/qdirectfbcursor.cpp
+++ b/src/plugins/platforms/directfb/qdirectfbcursor.cpp
@@ -59,8 +59,9 @@ void QDirectFBCursor::changeCursor(QCursor *cursor, QWindow *)
int ySpot;
QPixmap map;
- if (cursor->shape() != Qt::BitmapCursor) {
- m_image->set(cursor->shape());
+ const Qt::CursorShape newShape = cursor ? cursor->shape() : Qt::ArrowCursor;
+ if (newShape != Qt::BitmapCursor) {
+ m_image->set(newShape);
xSpot = m_image->hotspot().x();
ySpot = m_image->hotspot().y();
QImage *i = m_image->image();
diff --git a/src/plugins/platforms/eglfs/eglfs.pri b/src/plugins/platforms/eglfs/eglfs.pri
new file mode 100644
index 0000000000..eb66e17479
--- /dev/null
+++ b/src/plugins/platforms/eglfs/eglfs.pri
@@ -0,0 +1,44 @@
+QT += core-private gui-private platformsupport-private
+
+#DEFINES += QEGL_EXTRA_DEBUG
+
+#Avoid X11 header collision
+DEFINES += MESA_EGL_NO_X11_HEADERS
+
+#To test the hooks on x11 (xlib), comment the above define too
+#EGLFS_PLATFORM_HOOKS_SOURCES += qeglfshooks_x11.cpp
+#LIBS += -lX11
+
+SOURCES += $$PWD/qeglfsintegration.cpp \
+ $$PWD/qeglfswindow.cpp \
+ $$PWD/qeglfsbackingstore.cpp \
+ $$PWD/qeglfsscreen.cpp \
+ $$PWD/qeglfshooks_stub.cpp \
+ $$PWD/qeglfscursor.cpp \
+ $$PWD/qeglfscontext.cpp
+
+HEADERS += $$PWD/qeglfsintegration.h \
+ $$PWD/qeglfswindow.h \
+ $$PWD/qeglfsbackingstore.h \
+ $$PWD/qeglfsscreen.h \
+ $$PWD/qeglfscursor.h \
+ $$PWD/qeglfshooks.h \
+ $$PWD/qeglfscontext.h
+
+QMAKE_LFLAGS += $$QMAKE_LFLAGS_NOUNDEF
+
+INCLUDEPATH += $$PWD
+
+!isEmpty(EGLFS_PLATFORM_HOOKS_SOURCES) {
+ HEADERS += $$EGLFS_PLATFORM_HOOKS_HEADERS
+ SOURCES += $$EGLFS_PLATFORM_HOOKS_SOURCES
+ LIBS += $$EGLFS_PLATFORM_HOOKS_LIBS
+ DEFINES += EGLFS_PLATFORM_HOOKS
+}
+
+CONFIG += egl qpa/genericunixfontdatabase
+
+RESOURCES += $$PWD/cursor.qrc
+
+OTHER_FILES += \
+ $$PWD/eglfs.json
diff --git a/src/plugins/platforms/eglfs/eglfs.pro b/src/plugins/platforms/eglfs/eglfs.pro
index 45059a9cb9..8827f7680c 100644
--- a/src/plugins/platforms/eglfs/eglfs.pro
+++ b/src/plugins/platforms/eglfs/eglfs.pro
@@ -4,48 +4,6 @@ PLUGIN_TYPE = platforms
PLUGIN_CLASS_NAME = QEglFSIntegrationPlugin
load(qt_plugin)
-QT += core-private gui-private platformsupport-private
+SOURCES += $$PWD/main.cpp
-#DEFINES += QEGL_EXTRA_DEBUG
-
-#Avoid X11 header collision
-DEFINES += MESA_EGL_NO_X11_HEADERS
-
-#To test the hooks on x11 (xlib), comment the above define too
-#EGLFS_PLATFORM_HOOKS_SOURCES += qeglfshooks_x11.cpp
-#LIBS += -lX11
-
-SOURCES = main.cpp \
- qeglfsintegration.cpp \
- qeglfswindow.cpp \
- qeglfsbackingstore.cpp \
- qeglfsscreen.cpp \
- qeglfshooks_stub.cpp \
- qeglfscursor.cpp \
- qeglfscontext.cpp
-
-HEADERS = qeglfsintegration.h \
- qeglfswindow.h \
- qeglfsbackingstore.h \
- qeglfsscreen.h \
- qeglfscursor.h \
- qeglfshooks.h \
- qeglfscontext.h
-
-QMAKE_LFLAGS += $$QMAKE_LFLAGS_NOUNDEF
-
-INCLUDEPATH += $$PWD
-
-!isEmpty(EGLFS_PLATFORM_HOOKS_SOURCES) {
- HEADERS += $$EGLFS_PLATFORM_HOOKS_HEADERS
- SOURCES += $$EGLFS_PLATFORM_HOOKS_SOURCES
- LIBS += $$EGLFS_PLATFORM_HOOKS_LIBS
- DEFINES += EGLFS_PLATFORM_HOOKS
-}
-
-CONFIG += egl qpa/genericunixfontdatabase
-
-RESOURCES += cursor.qrc
-
-OTHER_FILES += \
- eglfs.json
+include(eglfs.pri)
diff --git a/src/plugins/platforms/eglfs/qeglfscontext.cpp b/src/plugins/platforms/eglfs/qeglfscontext.cpp
index 66b42d64e7..51439646c6 100644
--- a/src/plugins/platforms/eglfs/qeglfscontext.cpp
+++ b/src/plugins/platforms/eglfs/qeglfscontext.cpp
@@ -43,14 +43,17 @@
#include "qeglfswindow.h"
#include "qeglfscursor.h"
#include "qeglfshooks.h"
+#include "qeglfsintegration.h"
+#include <QtPlatformSupport/private/qeglpbuffer_p.h>
+#include <QtGui/QSurface>
#include <QtDebug>
QT_BEGIN_NAMESPACE
QEglFSContext::QEglFSContext(const QSurfaceFormat &format, QPlatformOpenGLContext *share,
EGLDisplay display, EGLenum eglApi)
- : QEGLPlatformContext(hooks->surfaceFormatFor(format), share, display, eglApi)
+ : QEGLPlatformContext(QEglFSHooks::hooks()->surfaceFormatFor(format), share, display, QEglFSIntegration::chooseConfig(display, QEglFSHooks::hooks()->surfaceFormatFor(format)), eglApi)
{
}
@@ -61,17 +64,22 @@ bool QEglFSContext::makeCurrent(QPlatformSurface *surface)
EGLSurface QEglFSContext::eglSurfaceForPlatformSurface(QPlatformSurface *surface)
{
- QEglFSWindow *window = static_cast<QEglFSWindow *>(surface);
- return window->surface();
+ if (surface->surface()->surfaceClass() == QSurface::Window)
+ return static_cast<QEglFSWindow *>(surface)->surface();
+ else
+ return static_cast<QEGLPbuffer *>(surface)->pbuffer();
}
void QEglFSContext::swapBuffers(QPlatformSurface *surface)
{
- QEglFSWindow *window = static_cast<QEglFSWindow *>(surface);
- // draw the cursor
- if (QEglFSCursor *cursor = static_cast<QEglFSCursor *>(window->screen()->cursor()))
- cursor->paintOnScreen();
+ if (surface->surface()->surfaceClass() == QSurface::Window) {
+ QEglFSWindow *window = static_cast<QEglFSWindow *>(surface);
+ // draw the cursor
+ if (QEglFSCursor *cursor = static_cast<QEglFSCursor *>(window->screen()->cursor()))
+ cursor->paintOnScreen();
+ }
+ QEglFSHooks::hooks()->waitForVSync();
QEGLPlatformContext::swapBuffers(surface);
}
diff --git a/src/plugins/platforms/eglfs/qeglfscursor.cpp b/src/plugins/platforms/eglfs/qeglfscursor.cpp
index c245b1b5bb..9dc836b8b1 100644
--- a/src/plugins/platforms/eglfs/qeglfscursor.cpp
+++ b/src/plugins/platforms/eglfs/qeglfscursor.cpp
@@ -196,15 +196,16 @@ void QEglFSCursor::changeCursor(QCursor *cursor, QWindow *window)
bool QEglFSCursor::setCurrentCursor(QCursor *cursor)
{
- if (m_cursor.shape == cursor->shape() && cursor->shape() != Qt::BitmapCursor)
+ const Qt::CursorShape newShape = cursor ? cursor->shape() : Qt::ArrowCursor;
+ if (m_cursor.shape == newShape && newShape != Qt::BitmapCursor)
return false;
if (m_cursor.shape == Qt::BitmapCursor) {
m_cursor.customCursorImage = QImage(); // in case render() never uploaded it
}
- m_cursor.shape = cursor->shape();
- if (cursor->shape() != Qt::BitmapCursor) { // standard cursor
+ m_cursor.shape = newShape;
+ if (newShape != Qt::BitmapCursor) { // standard cursor
const float ws = (float)m_cursorAtlas.cursorWidth / m_cursorAtlas.width,
hs = (float)m_cursorAtlas.cursorHeight / m_cursorAtlas.height;
m_cursor.textureRect = QRectF(ws * (m_cursor.shape % m_cursorAtlas.cursorsPerRow),
diff --git a/src/plugins/platforms/eglfs/qeglfshooks.h b/src/plugins/platforms/eglfs/qeglfshooks.h
index 2d095ba934..c4ac7185fb 100644
--- a/src/plugins/platforms/eglfs/qeglfshooks.h
+++ b/src/plugins/platforms/eglfs/qeglfshooks.h
@@ -55,10 +55,11 @@ class QEglFSScreen;
class QEglFSHooks
{
public:
- virtual ~QEglFSHooks() {};
+ virtual ~QEglFSHooks() {}
virtual void platformInit();
virtual void platformDestroy();
virtual EGLNativeDisplayType platformDisplay() const;
+ virtual QSizeF physicalScreenSize() const;
virtual QSize screenSize() const;
virtual int screenDepth() const;
virtual QImage::Format screenFormat() const;
@@ -67,15 +68,22 @@ public:
virtual void destroyNativeWindow(EGLNativeWindowType window);
virtual bool hasCapability(QPlatformIntegration::Capability cap) const;
virtual QEglFSCursor *createCursor(QEglFSScreen *screen) const;
-};
+ virtual bool filterConfig(EGLDisplay display, EGLConfig config) const;
+ virtual void waitForVSync() const;
+
+ virtual const char *fbDeviceName() const;
+ static QEglFSHooks *hooks()
+ {
#ifdef EGLFS_PLATFORM_HOOKS
-extern QEglFSHooks *platformHooks;
-static QEglFSHooks *hooks = platformHooks;
+ extern QEglFSHooks *platformHooks;
+ return platformHooks;
#else
-extern QEglFSHooks stubHooks;
-static QEglFSHooks *hooks = &stubHooks;
+ extern QEglFSHooks stubHooks;
+ return &stubHooks;
#endif
+ }
+};
QT_END_NAMESPACE
diff --git a/src/plugins/platforms/eglfs/qeglfshooks_stub.cpp b/src/plugins/platforms/eglfs/qeglfshooks_stub.cpp
index e9a22ea605..8200fa70b2 100644
--- a/src/plugins/platforms/eglfs/qeglfshooks_stub.cpp
+++ b/src/plugins/platforms/eglfs/qeglfshooks_stub.cpp
@@ -46,15 +46,32 @@
#include <linux/fb.h>
#include <sys/ioctl.h>
+#include <private/qmath_p.h>
+#include <private/qcore_unix_p.h>
+
QT_BEGIN_NAMESPACE
+// file descriptor for the frame buffer
+// this is a global static to keep the QEglFSHooks interface as clean as possible
+static int framebuffer = -1;
+
+const char *QEglFSHooks::fbDeviceName() const
+{
+ return "/dev/fb0";
+}
+
void QEglFSHooks::platformInit()
{
- Q_UNUSED(hooks);
+ framebuffer = qt_safe_open(fbDeviceName(), O_RDONLY);
+
+ if (framebuffer == -1)
+ qWarning("EGLFS: Failed to open %s", fbDeviceName());
}
void QEglFSHooks::platformDestroy()
{
+ if (framebuffer != -1)
+ close(framebuffer);
}
EGLNativeDisplayType QEglFSHooks::platformDisplay() const
@@ -62,6 +79,55 @@ EGLNativeDisplayType QEglFSHooks::platformDisplay() const
return EGL_DEFAULT_DISPLAY;
}
+QSizeF QEglFSHooks::physicalScreenSize() const
+{
+ static QSizeF size;
+ if (size.isEmpty()) {
+
+ // Note: in millimeters
+ int width = qgetenv("QT_QPA_EGLFS_PHYSICAL_WIDTH").toInt();
+ int height = qgetenv("QT_QPA_EGLFS_PHYSICAL_HEIGHT").toInt();
+
+ if (width && height) {
+ // no need to read fb0
+ size.setWidth(width);
+ size.setHeight(height);
+ return size;
+ }
+
+ struct fb_var_screeninfo vinfo;
+ int w = -1;
+ int h = -1;
+
+ if (framebuffer != -1) {
+ if (ioctl(framebuffer, FBIOGET_VSCREENINFO, &vinfo) == -1) {
+ qWarning("EGLFS: Could not query variable screen info.");
+ } else {
+ w = vinfo.width;
+ h = vinfo.height;
+ }
+ }
+
+ const int defaultPhysicalDpi = 100;
+ size.setWidth(w <= 0 ? vinfo.xres * Q_MM_PER_INCH / defaultPhysicalDpi : qreal(w));
+ size.setHeight(h <= 0 ? vinfo.yres * Q_MM_PER_INCH / defaultPhysicalDpi : qreal(h));
+
+ if (w <= 0 || h <= 0) {
+ qWarning("EGLFS: Unable to query physical screen size, defaulting to %d dpi.\n"
+ "EGLFS: To override, set QT_QPA_EGLFS_PHYSICAL_WIDTH "
+ "and QT_QPA_EGLFS_PHYSICAL_HEIGHT (in millimeters).",
+ defaultPhysicalDpi);
+ }
+
+ // override fb0 from environment var setting
+ if (width)
+ size.setWidth(width);
+ if (height)
+ size.setWidth(height);
+ }
+ return size;
+}
+
QSize QEglFSHooks::screenSize() const
{
static QSize size;
@@ -78,17 +144,28 @@ QSize QEglFSHooks::screenSize() const
}
struct fb_var_screeninfo vinfo;
- int fd = open("/dev/fb0", O_RDONLY);
- if (fd != -1) {
- if (ioctl(fd, FBIOGET_VSCREENINFO, &vinfo) == -1)
- qWarning("Could not query variable screen info.");
- else
- size = QSize(vinfo.xres, vinfo.yres);
+ int xres = -1;
+ int yres = -1;
+
+ if (framebuffer != -1) {
+ if (ioctl(framebuffer, FBIOGET_VSCREENINFO, &vinfo) == -1) {
+ qWarning("EGLFS: Could not query variable screen info.");
+ } else {
+ xres = vinfo.xres;
+ yres = vinfo.yres;
+ }
+ }
+
+ const int defaultWidth = 800;
+ const int defaultHeight = 600;
+ size.setWidth(xres <= 0 ? defaultWidth : xres);
+ size.setHeight(yres <= 0 ? defaultHeight : yres);
- close(fd);
- } else {
- qWarning("Failed to open /dev/fb0 to detect screen resolution.");
+ if (xres <= 0 || yres <= 0) {
+ qWarning("EGLFS: Unable to query screen resolution, defaulting to %dx%d.\n"
+ "EGLFS: To override, set QT_QPA_EGLFS_WIDTH and QT_QPA_EGLFS_HEIGHT.",
+ defaultWidth, defaultHeight);
}
// override fb0 from environment var setting
@@ -107,21 +184,25 @@ int QEglFSHooks::screenDepth() const
if (depth == 0) {
struct fb_var_screeninfo vinfo;
- int fd = open("/dev/fb0", O_RDONLY);
- if (fd != -1) {
- if (ioctl(fd, FBIOGET_VSCREENINFO, &vinfo) == -1)
- qWarning("Could not query variable screen info.");
+ if (framebuffer != -1) {
+ if (ioctl(framebuffer, FBIOGET_VSCREENINFO, &vinfo) == -1)
+ qWarning("EGLFS: Could not query variable screen info.");
else
depth = vinfo.bits_per_pixel;
+ }
+
+ const int defaultDepth = 32;
+
+ if (depth <= 0) {
+ depth = defaultDepth;
- close(fd);
- } else {
- qWarning("Failed to open /dev/fb0 to detect screen depth.");
+ qWarning("EGLFS: Unable to query screen depth, defaulting to %d.\n"
+ "EGLFS: To override, set QT_QPA_EGLFS_DEPTH.", defaultDepth);
}
}
- return depth == 0 ? 32 : depth;
+ return depth;
}
QImage::Format QEglFSHooks::screenFormat() const
@@ -134,6 +215,11 @@ QSurfaceFormat QEglFSHooks::surfaceFormatFor(const QSurfaceFormat &inputFormat)
return inputFormat;
}
+bool QEglFSHooks::filterConfig(EGLDisplay, EGLConfig) const
+{
+ return true;
+}
+
EGLNativeWindowType QEglFSHooks::createNativeWindow(const QSize &size, const QSurfaceFormat &format)
{
Q_UNUSED(size);
@@ -158,6 +244,18 @@ QEglFSCursor *QEglFSHooks::createCursor(QEglFSScreen *screen) const
return 0;
}
+void QEglFSHooks::waitForVSync() const
+{
+#if defined(FBIO_WAITFORVSYNC)
+ static const bool forceSync = qgetenv("QT_QPA_EGLFS_FORCEVSYNC").toInt();
+ if (forceSync && framebuffer != -1) {
+ int arg = 0;
+ if (ioctl(framebuffer, FBIO_WAITFORVSYNC, &arg) == -1)
+ qWarning("Could not wait for vsync.");
+ }
+#endif
+}
+
#ifndef EGLFS_PLATFORM_HOOKS
QEglFSHooks stubHooks;
#endif
diff --git a/src/plugins/platforms/eglfs/qeglfsintegration.cpp b/src/plugins/platforms/eglfs/qeglfsintegration.cpp
index 0dcde9ca36..8cebe16775 100644
--- a/src/plugins/platforms/eglfs/qeglfsintegration.cpp
+++ b/src/plugins/platforms/eglfs/qeglfsintegration.cpp
@@ -49,9 +49,11 @@
#include <QtPlatformSupport/private/qgenericunixfontdatabase_p.h>
#include <QtPlatformSupport/private/qgenericunixeventdispatcher_p.h>
+#include <QtPlatformSupport/private/qeglconvenience_p.h>
#include <QtPlatformSupport/private/qeglplatformcontext_p.h>
+#include <QtPlatformSupport/private/qeglpbuffer_p.h>
-#if !defined(QT_NO_EVDEV)
+#if !defined(QT_NO_EVDEV) && !defined(Q_OS_ANDROID)
#include <QtPlatformSupport/private/qevdevmousemanager_p.h>
#include <QtPlatformSupport/private/qevdevkeyboardmanager_p.h>
#include <QtPlatformSupport/private/qevdevtouch_p.h>
@@ -61,6 +63,7 @@
#include <QtGui/QSurfaceFormat>
#include <QtGui/QOpenGLContext>
#include <QtGui/QScreen>
+#include <QtGui/QOffscreenSurface>
#include <qpa/qplatformcursor.h>
#include "qeglfscontext.h"
@@ -74,13 +77,13 @@ QEglFSIntegration::QEglFSIntegration()
{
QGuiApplicationPrivate::instance()->setEventDispatcher(mEventDispatcher);
-#if !defined(QT_NO_EVDEV)
+#if !defined(QT_NO_EVDEV) && !defined(Q_OS_ANDROID)
new QEvdevKeyboardManager(QLatin1String("EvdevKeyboard"), QString() /* spec */, this);
new QEvdevMouseManager(QLatin1String("EvdevMouse"), QString() /* spec */, this);
new QEvdevTouchScreenHandlerThread(QString() /* spec */, this);
#endif
- hooks->platformInit();
+ QEglFSHooks::hooks()->platformInit();
EGLint major, minor;
@@ -89,7 +92,7 @@ QEglFSIntegration::QEglFSIntegration()
qFatal("EGL error");
}
- mDisplay = eglGetDisplay(hooks ? hooks->platformDisplay() : EGL_DEFAULT_DISPLAY);
+ mDisplay = eglGetDisplay(QEglFSHooks::hooks() ? QEglFSHooks::hooks()->platformDisplay() : EGL_DEFAULT_DISPLAY);
if (mDisplay == EGL_NO_DISPLAY) {
qWarning("Could not open egl display\n");
qFatal("EGL error");
@@ -119,13 +122,13 @@ QEglFSIntegration::~QEglFSIntegration()
delete mScreen;
eglTerminate(mDisplay);
- hooks->platformDestroy();
+ QEglFSHooks::hooks()->platformDestroy();
}
bool QEglFSIntegration::hasCapability(QPlatformIntegration::Capability cap) const
{
// We assume that devices will have more and not less capabilities
- if (hooks && hooks->hasCapability(cap))
+ if (QEglFSHooks::hooks() && QEglFSHooks::hooks()->hasCapability(cap))
return true;
switch (cap) {
@@ -150,7 +153,13 @@ QPlatformBackingStore *QEglFSIntegration::createPlatformBackingStore(QWindow *wi
QPlatformOpenGLContext *QEglFSIntegration::createPlatformOpenGLContext(QOpenGLContext *context) const
{
- return new QEglFSContext(context->format(), 0 /*share*/, mDisplay);
+ return new QEglFSContext(QEglFSHooks::hooks()->surfaceFormatFor(context->format()), context->shareHandle(), mDisplay);
+}
+
+QPlatformOffscreenSurface *QEglFSIntegration::createPlatformOffscreenSurface(QOffscreenSurface *surface) const
+{
+ QEglFSScreen *screen = static_cast<QEglFSScreen *>(surface->screen()->handle());
+ return new QEGLPbuffer(screen->display(), QEglFSHooks::hooks()->surfaceFormatFor(surface->requestedFormat()), surface);
}
QPlatformFontDatabase *QEglFSIntegration::fontDatabase() const
@@ -201,4 +210,29 @@ void *QEglFSIntegration::nativeResourceForContext(const QByteArray &resource, QO
return 0;
}
+EGLConfig QEglFSIntegration::chooseConfig(EGLDisplay display, const QSurfaceFormat &format)
+{
+ class Chooser : public QEglConfigChooser {
+ public:
+ Chooser(EGLDisplay display, QEglFSHooks *hooks)
+ : QEglConfigChooser(display)
+ , m_hooks(hooks)
+ {
+ }
+
+ protected:
+ bool filterConfig(EGLConfig config) const
+ {
+ return m_hooks->filterConfig(display(), config) && QEglConfigChooser::filterConfig(config);
+ }
+
+ private:
+ QEglFSHooks *m_hooks;
+ };
+
+ Chooser chooser(display, QEglFSHooks::hooks());
+ chooser.setSurfaceFormat(format);
+ return chooser.chooseConfig();
+}
+
QT_END_NAMESPACE
diff --git a/src/plugins/platforms/eglfs/qeglfsintegration.h b/src/plugins/platforms/eglfs/qeglfsintegration.h
index 42b132b73a..5427137463 100644
--- a/src/plugins/platforms/eglfs/qeglfsintegration.h
+++ b/src/plugins/platforms/eglfs/qeglfsintegration.h
@@ -48,8 +48,6 @@
#include <qpa/qplatformnativeinterface.h>
#include <qpa/qplatformscreen.h>
-QT_BEGIN_HEADER
-
QT_BEGIN_NAMESPACE
class QEglFSIntegration : public QPlatformIntegration, public QPlatformNativeInterface
@@ -63,6 +61,7 @@ public:
QPlatformWindow *createPlatformWindow(QWindow *window) const;
QPlatformBackingStore *createPlatformBackingStore(QWindow *window) const;
QPlatformOpenGLContext *createPlatformOpenGLContext(QOpenGLContext *context) const;
+ QPlatformOffscreenSurface *createPlatformOffscreenSurface(QOffscreenSurface *surface) const;
QPlatformNativeInterface *nativeInterface() const;
QPlatformFontDatabase *fontDatabase() const;
@@ -75,6 +74,11 @@ public:
void *nativeResourceForIntegration(const QByteArray &resource);
void *nativeResourceForContext(const QByteArray &resource, QOpenGLContext *context);
+ QPlatformScreen *screen() const { return mScreen; }
+ static EGLConfig chooseConfig(EGLDisplay display, const QSurfaceFormat &format);
+
+ EGLDisplay display() const { return mDisplay; }
+
private:
EGLDisplay mDisplay;
QAbstractEventDispatcher *mEventDispatcher;
@@ -83,6 +87,5 @@ private:
};
QT_END_NAMESPACE
-QT_END_HEADER
#endif // QEGLFSINTEGRATION_H
diff --git a/src/plugins/platforms/eglfs/qeglfsscreen.cpp b/src/plugins/platforms/eglfs/qeglfsscreen.cpp
index 1bc1e944de..83f50dd382 100644
--- a/src/plugins/platforms/eglfs/qeglfsscreen.cpp
+++ b/src/plugins/platforms/eglfs/qeglfsscreen.cpp
@@ -56,7 +56,7 @@ QEglFSScreen::QEglFSScreen(EGLDisplay dpy)
static int hideCursor = qgetenv("QT_QPA_EGLFS_HIDECURSOR").toInt();
if (!hideCursor) {
- if (QEglFSCursor *customCursor = hooks->createCursor(this))
+ if (QEglFSCursor *customCursor = QEglFSHooks::hooks()->createCursor(this))
m_cursor = customCursor;
else
m_cursor = new QEglFSCursor(this);
@@ -70,17 +70,22 @@ QEglFSScreen::~QEglFSScreen()
QRect QEglFSScreen::geometry() const
{
- return QRect(QPoint(0, 0), hooks->screenSize());
+ return QRect(QPoint(0, 0), QEglFSHooks::hooks()->screenSize());
}
int QEglFSScreen::depth() const
{
- return hooks->screenDepth();
+ return QEglFSHooks::hooks()->screenDepth();
}
QImage::Format QEglFSScreen::format() const
{
- return hooks->screenFormat();
+ return QEglFSHooks::hooks()->screenFormat();
+}
+
+QSizeF QEglFSScreen::physicalSize() const
+{
+ return QEglFSHooks::hooks()->physicalScreenSize();
}
QPlatformCursor *QEglFSScreen::cursor() const
diff --git a/src/plugins/platforms/eglfs/qeglfsscreen.h b/src/plugins/platforms/eglfs/qeglfsscreen.h
index 309791d6c2..8d3c5dbaec 100644
--- a/src/plugins/platforms/eglfs/qeglfsscreen.h
+++ b/src/plugins/platforms/eglfs/qeglfsscreen.h
@@ -63,6 +63,8 @@ public:
int depth() const;
QImage::Format format() const;
+ QSizeF physicalSize() const;
+
QPlatformCursor *cursor() const;
EGLDisplay display() const { return m_dpy; }
diff --git a/src/plugins/platforms/eglfs/qeglfswindow.cpp b/src/plugins/platforms/eglfs/qeglfswindow.cpp
index ceb04901c4..68cef6253e 100644
--- a/src/plugins/platforms/eglfs/qeglfswindow.cpp
+++ b/src/plugins/platforms/eglfs/qeglfswindow.cpp
@@ -76,18 +76,36 @@ void QEglFSWindow::create()
return;
if (window()->type() == Qt::Desktop) {
- QRect rect(QPoint(), hooks->screenSize());
+ QRect rect(QPoint(), QEglFSHooks::hooks()->screenSize());
QPlatformWindow::setGeometry(rect);
QWindowSystemInterface::handleGeometryChange(window(), rect);
return;
}
EGLDisplay display = (static_cast<QEglFSScreen *>(window()->screen()->handle()))->display();
- QSurfaceFormat platformFormat = hooks->surfaceFormatFor(window()->requestedFormat());
- EGLConfig config = q_configFromGLFormat(display, platformFormat);
- m_format = q_glFormatFromConfig(display, config);
- m_window = hooks->createNativeWindow(hooks->screenSize(), m_format);
- m_surface = eglCreateWindowSurface(display, config, m_window, NULL);
+ QSurfaceFormat platformFormat = QEglFSHooks::hooks()->surfaceFormatFor(window()->requestedFormat());
+ m_config = QEglFSIntegration::chooseConfig(display, platformFormat);
+ m_format = q_glFormatFromConfig(display, m_config);
+ resetSurface();
+}
+
+void QEglFSWindow::invalidateSurface()
+{
+ // Native surface has been deleted behind our backs
+ m_window = 0;
+ if (m_surface != 0) {
+ EGLDisplay display = (static_cast<QEglFSScreen *>(window()->screen()->handle()))->display();
+ eglDestroySurface(display, m_surface);
+ m_surface = 0;
+ }
+}
+
+void QEglFSWindow::resetSurface()
+{
+ EGLDisplay display = static_cast<QEglFSScreen *>(screen())->display();
+
+ m_window = QEglFSHooks::hooks()->createNativeWindow(QEglFSHooks::hooks()->screenSize(), m_format);
+ m_surface = eglCreateWindowSurface(display, m_config, m_window, NULL);
if (m_surface == EGL_NO_SURFACE) {
EGLint error = eglGetError();
eglTerminate(display);
@@ -98,13 +116,13 @@ void QEglFSWindow::create()
void QEglFSWindow::destroy()
{
if (m_surface) {
- EGLDisplay display = (static_cast<QEglFSScreen *>(window()->screen()->handle()))->display();
+ EGLDisplay display = static_cast<QEglFSScreen *>(screen())->display();
eglDestroySurface(display, m_surface);
m_surface = 0;
}
if (m_window) {
- hooks->destroyNativeWindow(m_window);
+ QEglFSHooks::hooks()->destroyNativeWindow(m_window);
m_window = 0;
}
}
@@ -113,9 +131,8 @@ void QEglFSWindow::setGeometry(const QRect &)
{
// We only support full-screen windows
QRect rect(screen()->availableGeometry());
- QWindowSystemInterface::handleGeometryChange(window(), rect);
-
QPlatformWindow::setGeometry(rect);
+ QWindowSystemInterface::handleGeometryChange(window(), rect);
}
void QEglFSWindow::setWindowState(Qt::WindowState)
diff --git a/src/plugins/platforms/eglfs/qeglfswindow.h b/src/plugins/platforms/eglfs/qeglfswindow.h
index 706bbddd22..a351b4a6f4 100644
--- a/src/plugins/platforms/eglfs/qeglfswindow.h
+++ b/src/plugins/platforms/eglfs/qeglfswindow.h
@@ -65,10 +65,14 @@ public:
void create();
void destroy();
+ virtual void invalidateSurface();
+ virtual void resetSurface();
+
private:
WId m_winid;
EGLSurface m_surface;
EGLNativeWindowType m_window;
+ EGLConfig m_config;
QSurfaceFormat m_format;
};
QT_END_NAMESPACE
diff --git a/src/plugins/platforms/ios/ios.json b/src/plugins/platforms/ios/ios.json
new file mode 100644
index 0000000000..f0b766dae1
--- /dev/null
+++ b/src/plugins/platforms/ios/ios.json
@@ -0,0 +1,3 @@
+{
+ "Keys": [ "ios" ]
+}
diff --git a/src/plugins/platforms/ios/ios.pro b/src/plugins/platforms/ios/ios.pro
new file mode 100644
index 0000000000..842ff17f1c
--- /dev/null
+++ b/src/plugins/platforms/ios/ios.pro
@@ -0,0 +1,3 @@
+TEMPLATE = subdirs
+
+SUBDIRS += plugin.pro qtmain.pro
diff --git a/src/plugins/platforms/ios/plugin.mm b/src/plugins/platforms/ios/plugin.mm
new file mode 100644
index 0000000000..a93b6037ad
--- /dev/null
+++ b/src/plugins/platforms/ios/plugin.mm
@@ -0,0 +1,69 @@
+/****************************************************************************
+**
+** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the plugins of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Digia. For licensing terms and
+** conditions see http://qt.digia.com/licensing. For further information
+** use the contact form at http://qt.digia.com/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Digia gives you certain additional
+** rights. These rights are described in the Digia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include <qpa/qplatformintegrationplugin.h>
+#include <qpa/qplatformthemeplugin.h>
+#include "qiosintegration.h"
+
+QT_BEGIN_NAMESPACE
+
+class QIOSIntegrationPlugin : public QPlatformIntegrationPlugin
+{
+ Q_OBJECT
+ Q_PLUGIN_METADATA(IID "org.qt-project.Qt.QPA.QPlatformIntegrationFactoryInterface.5.1" FILE "ios.json")
+ public:
+ QPlatformIntegration *create(const QString&, const QStringList&);
+};
+
+QPlatformIntegration * QIOSIntegrationPlugin::create(const QString& system, const QStringList& paramList)
+{
+ Q_UNUSED(paramList);
+ if (system.toLower() == "ios")
+ return new QIOSIntegration;
+
+ return 0;
+}
+
+QT_END_NAMESPACE
+
+#include "plugin.moc"
+
+Q_IMPORT_PLUGIN(QIOSIntegrationPlugin)
diff --git a/src/plugins/platforms/ios/plugin.pro b/src/plugins/platforms/ios/plugin.pro
new file mode 100644
index 0000000000..591a0a67ed
--- /dev/null
+++ b/src/plugins/platforms/ios/plugin.pro
@@ -0,0 +1,36 @@
+TARGET = qios
+
+PLUGIN_TYPE = platforms
+load(qt_plugin)
+
+QT += core-private gui-private platformsupport-private
+LIBS += -framework UIKit -framework QuartzCore
+
+OBJECTIVE_SOURCES = \
+ plugin.mm \
+ qiosintegration.mm \
+ qioswindow.mm \
+ qiosscreen.mm \
+ qioseventdispatcher.mm \
+ qiosbackingstore.mm \
+ qiosapplicationdelegate.mm \
+ qiosviewcontroller.mm \
+ qioscontext.mm \
+ qiosinputcontext.mm \
+ qiostheme.mm \
+ qiosglobal.mm
+
+HEADERS = \
+ qiosintegration.h \
+ qioswindow.h \
+ qiosscreen.h \
+ qioseventdispatcher.h \
+ qiosbackingstore.h \
+ qiosapplicationdelegate.h \
+ qiosviewcontroller.h \
+ qioscontext.h \
+ qiosinputcontext.h \
+ qiostheme.h \
+ qiosglobal.h
+
+#HEADERS = qiossoftwareinputhandler.h
diff --git a/src/plugins/platforms/ios/qiosapplicationdelegate.h b/src/plugins/platforms/ios/qiosapplicationdelegate.h
new file mode 100644
index 0000000000..442b37f1b3
--- /dev/null
+++ b/src/plugins/platforms/ios/qiosapplicationdelegate.h
@@ -0,0 +1,53 @@
+/****************************************************************************
+**
+** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the plugins of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Digia. For licensing terms and
+** conditions see http://qt.digia.com/licensing. For further information
+** use the contact form at http://qt.digia.com/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Digia gives you certain additional
+** rights. These rights are described in the Digia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#import <UIKit/UIKit.h>
+#import <QtGui/QtGui>
+
+@interface QIOSApplicationDelegate : UIResponder <UIApplicationDelegate>
+
+@property (strong, nonatomic) UIWindow *window;
+
+@end
+
+@interface QIOSMainWrapperApplicationDelegate : QIOSApplicationDelegate
+@end
+
diff --git a/src/plugins/platforms/ios/qiosapplicationdelegate.mm b/src/plugins/platforms/ios/qiosapplicationdelegate.mm
new file mode 100644
index 0000000000..41a3fff84f
--- /dev/null
+++ b/src/plugins/platforms/ios/qiosapplicationdelegate.mm
@@ -0,0 +1,94 @@
+/****************************************************************************
+**
+** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the plugins of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Digia. For licensing terms and
+** conditions see http://qt.digia.com/licensing. For further information
+** use the contact form at http://qt.digia.com/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Digia gives you certain additional
+** rights. These rights are described in the Digia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#import "qiosapplicationdelegate.h"
+#include "qioswindow.h"
+#include <QtCore/QtCore>
+
+@implementation QIOSApplicationDelegate
+
+@synthesize window;
+
+- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
+{
+ Q_UNUSED(application)
+ Q_UNUSED(launchOptions)
+
+ return YES;
+}
+
+- (void)applicationWillResignActive:(UIApplication *)application
+{
+ Q_UNUSED(application)
+}
+
+- (void)applicationDidEnterBackground:(UIApplication *)application
+{
+ Q_UNUSED(application)
+}
+
+- (void)applicationWillEnterForeground:(UIApplication *)application
+{
+ Q_UNUSED(application)
+ // Called as part of the transition from the background to the inactive state; here you can undo many of the changes made on entering the background.
+}
+
+- (void)applicationDidBecomeActive:(UIApplication *)application
+{
+ Q_UNUSED(application)
+ // Restart any tasks that were paused (or not yet started) while the application was inactive. If the application was previously in the background, optionally refresh the user interface.
+}
+
+- (void)applicationWillTerminate:(UIApplication *)application
+{
+ Q_UNUSED(application)
+ // Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground:.
+}
+
+- (void)dealloc
+{
+ [window release];
+ [super dealloc];
+}
+
+@end
+
+
diff --git a/src/plugins/platforms/ios/qiosbackingstore.h b/src/plugins/platforms/ios/qiosbackingstore.h
new file mode 100644
index 0000000000..c110f0e4d1
--- /dev/null
+++ b/src/plugins/platforms/ios/qiosbackingstore.h
@@ -0,0 +1,70 @@
+/****************************************************************************
+**
+** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the plugins of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Digia. For licensing terms and
+** conditions see http://qt.digia.com/licensing. For further information
+** use the contact form at http://qt.digia.com/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Digia gives you certain additional
+** rights. These rights are described in the Digia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QIOSBACKINGSTORE_H
+#define QIOSBACKINGSTORE_H
+
+#include <qpa/qplatformbackingstore.h>
+
+QT_BEGIN_NAMESPACE
+
+class QIOSBackingStore : public QPlatformBackingStore
+{
+public:
+ QIOSBackingStore(QWindow *window);
+ ~QIOSBackingStore();
+
+ QPaintDevice *paintDevice();
+
+ void beginPaint(const QRegion &);
+ void endPaint();
+
+ void flush(QWindow *window, const QRegion &region, const QPoint &offset);
+ void resize(const QSize &size, const QRegion &staticContents);
+
+private:
+ QOpenGLContext *m_context;
+ QPaintDevice *m_device;
+};
+
+QT_END_NAMESPACE
+
+#endif // QIOSBACKINGSTORE_H
diff --git a/src/plugins/platforms/ios/qiosbackingstore.mm b/src/plugins/platforms/ios/qiosbackingstore.mm
new file mode 100644
index 0000000000..566ff3a672
--- /dev/null
+++ b/src/plugins/platforms/ios/qiosbackingstore.mm
@@ -0,0 +1,125 @@
+/****************************************************************************
+**
+** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the plugins of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Digia. For licensing terms and
+** conditions see http://qt.digia.com/licensing. For further information
+** use the contact form at http://qt.digia.com/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Digia gives you certain additional
+** rights. These rights are described in the Digia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qiosbackingstore.h"
+#include "qioswindow.h"
+
+#include <QtGui/QOpenGLContext>
+#include <QtGui/QOpenGLPaintDevice>
+
+#include <QtDebug>
+
+QIOSBackingStore::QIOSBackingStore(QWindow *window)
+ : QPlatformBackingStore(window)
+ , m_context(new QOpenGLContext)
+ , m_device(0)
+{
+ m_context->setFormat(window->requestedFormat());
+ m_context->setScreen(window->screen());
+ m_context->create();
+}
+
+QIOSBackingStore::~QIOSBackingStore()
+{
+ delete m_context;
+ delete m_device;
+}
+
+void QIOSBackingStore::beginPaint(const QRegion &)
+{
+ // Needed to prevent QOpenGLContext::makeCurrent() from failing
+ window()->setSurfaceType(QSurface::OpenGLSurface);
+
+ m_context->makeCurrent(window());
+
+ static_cast<QOpenGLPaintDevice *>(paintDevice())->setSize(window()->size());
+ QIOSWindow *iosWindow = static_cast<QIOSWindow *>(window()->handle());
+ static_cast<QOpenGLPaintDevice *>(paintDevice())->setSize(window()->size() * iosWindow->devicePixelRatio());
+}
+
+QPaintDevice *QIOSBackingStore::paintDevice()
+{
+ if (!m_device) {
+ QIOSWindow *iosWindow = static_cast<QIOSWindow *>(window()->handle());
+ QOpenGLPaintDevice *openGLDevice = new QOpenGLPaintDevice(window()->size() * iosWindow->devicePixelRatio());
+ openGLDevice->setDevicePixelRatio(iosWindow->devicePixelRatio());
+ m_device = openGLDevice;
+ }
+
+ return m_device;
+}
+
+void QIOSBackingStore::flush(QWindow *window, const QRegion &region, const QPoint &offset)
+{
+ Q_UNUSED(region);
+ Q_UNUSED(offset);
+
+ if (window != this->window()) {
+ // We skip flushing raster-based child windows, to avoid the extra cost of copying from the
+ // parent FBO into the child FBO. Since the child is already drawn inside the parent FBO, it
+ // will become visible when flushing the parent. The only case we end up not supporting is if
+ // the child window overlaps a sibling window that's draws using a separate QOpenGLContext.
+ return;
+ }
+ m_context->swapBuffers(window);
+}
+
+void QIOSBackingStore::endPaint()
+{
+ // Calling makeDone() on the context here would be an option,
+ // but is not needed, and would actually add some overhead.
+}
+
+void QIOSBackingStore::resize(const QSize &size, const QRegion &staticContents)
+{
+ Q_UNUSED(staticContents);
+
+ // Resizing the backing store would in our case mean resizing the QWindow,
+ // as we cheat and use an QOpenGLPaintDevice that we target at the window.
+ // That's probably not what the user intended, so we ignore resizes of the
+ // backing store and always keep the paint device's size in sync with the
+ // window size in beginPaint().
+
+ if (size != window()->size())
+ qWarning() << "QIOSBackingStore needs to have the same size as its window";
+}
+
+QT_END_NAMESPACE
diff --git a/src/plugins/platforms/ios/qioscontext.h b/src/plugins/platforms/ios/qioscontext.h
new file mode 100644
index 0000000000..082ec4794c
--- /dev/null
+++ b/src/plugins/platforms/ios/qioscontext.h
@@ -0,0 +1,91 @@
+/****************************************************************************
+**
+** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the plugins of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Digia. For licensing terms and
+** conditions see http://qt.digia.com/licensing. For further information
+** use the contact form at http://qt.digia.com/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Digia gives you certain additional
+** rights. These rights are described in the Digia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QIOSCONTEXT_H
+#define QIOSCONTEXT_H
+
+#include <qpa/qplatformopenglcontext.h>
+
+@class EAGLContext;
+
+QT_BEGIN_NAMESPACE
+
+class QIOSContext : public QObject, public QPlatformOpenGLContext
+{
+ Q_OBJECT
+
+public:
+ QIOSContext(QOpenGLContext *context);
+ ~QIOSContext();
+
+ QSurfaceFormat format() const;
+
+ void swapBuffers(QPlatformSurface *surface);
+
+ bool makeCurrent(QPlatformSurface *surface);
+ void doneCurrent();
+
+ GLuint defaultFramebufferObject(QPlatformSurface *) const;
+ QFunctionPointer getProcAddress(const QByteArray &procName);
+
+private Q_SLOTS:
+ void windowDestroyed(QObject *object);
+
+private:
+ EAGLContext *m_eaglContext;
+ QSurfaceFormat m_format;
+
+ struct FramebufferObject {
+ GLuint handle;
+ GLuint colorRenderbuffer;
+ GLuint depthRenderbuffer;
+ GLint renderbufferWidth;
+ GLint renderbufferHeight;
+ };
+
+ static void deleteBuffers(const FramebufferObject &framebufferObject);
+
+ mutable QHash<QWindow *, FramebufferObject> m_framebufferObjects;
+};
+
+QT_END_NAMESPACE
+
+#endif // QIOSCONTEXT_H
diff --git a/src/plugins/platforms/ios/qioscontext.mm b/src/plugins/platforms/ios/qioscontext.mm
new file mode 100644
index 0000000000..d3966964e0
--- /dev/null
+++ b/src/plugins/platforms/ios/qioscontext.mm
@@ -0,0 +1,204 @@
+/****************************************************************************
+**
+** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the plugins of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Digia. For licensing terms and
+** conditions see http://qt.digia.com/licensing. For further information
+** use the contact form at http://qt.digia.com/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Digia gives you certain additional
+** rights. These rights are described in the Digia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qioscontext.h"
+#include "qioswindow.h"
+
+#include <dlfcn.h>
+
+#include <QtGui/QOpenGlContext>
+
+#import <OpenGLES/EAGL.h>
+#import <QuartzCore/CAEAGLLayer.h>
+
+QIOSContext::QIOSContext(QOpenGLContext *context)
+ : QPlatformOpenGLContext()
+ , m_eaglContext([[EAGLContext alloc] initWithAPI:kEAGLRenderingAPIOpenGLES2])
+{
+ // Start out with the requested format
+ QSurfaceFormat format = context->format();
+
+ format.setRenderableType(QSurfaceFormat::OpenGLES);
+ format.setMajorVersion(2);
+ format.setMinorVersion(0);
+
+ // Even though iOS internally double-buffers its rendering, we
+ // report single-buffered here since the buffer remains unchanged
+ // when swapping unlesss you manually clear it yourself.
+ format.setSwapBehavior(QSurfaceFormat::SingleBuffer);
+
+ m_format = format;
+}
+
+QIOSContext::~QIOSContext()
+{
+ [EAGLContext setCurrentContext:m_eaglContext];
+
+ foreach (const FramebufferObject &framebufferObject, m_framebufferObjects)
+ deleteBuffers(framebufferObject);
+
+ [EAGLContext setCurrentContext:nil];
+ [m_eaglContext release];
+}
+
+void QIOSContext::deleteBuffers(const FramebufferObject &framebufferObject)
+{
+ if (framebufferObject.handle)
+ glDeleteFramebuffers(1, &framebufferObject.handle);
+ if (framebufferObject.colorRenderbuffer)
+ glDeleteRenderbuffers(1, &framebufferObject.colorRenderbuffer);
+ if (framebufferObject.depthRenderbuffer)
+ glDeleteRenderbuffers(1, &framebufferObject.depthRenderbuffer);
+}
+
+QSurfaceFormat QIOSContext::format() const
+{
+ return m_format;
+}
+
+bool QIOSContext::makeCurrent(QPlatformSurface *surface)
+{
+ Q_ASSERT(surface && surface->surface()->surfaceType() == QSurface::OpenGLSurface);
+
+ [EAGLContext setCurrentContext:m_eaglContext];
+ glBindFramebuffer(GL_FRAMEBUFFER, defaultFramebufferObject(surface));
+
+ return true;
+}
+
+void QIOSContext::doneCurrent()
+{
+ [EAGLContext setCurrentContext:nil];
+}
+
+void QIOSContext::swapBuffers(QPlatformSurface *surface)
+{
+ Q_ASSERT(surface && surface->surface()->surfaceType() == QSurface::OpenGLSurface);
+ Q_ASSERT(surface->surface()->surfaceClass() == QSurface::Window);
+ QWindow *window = static_cast<QWindow *>(surface->surface());
+ Q_ASSERT(m_framebufferObjects.contains(window));
+
+ [EAGLContext setCurrentContext:m_eaglContext];
+ glBindRenderbuffer(GL_RENDERBUFFER, m_framebufferObjects[window].colorRenderbuffer);
+ [m_eaglContext presentRenderbuffer:GL_RENDERBUFFER];
+}
+
+GLuint QIOSContext::defaultFramebufferObject(QPlatformSurface *surface) const
+{
+ Q_ASSERT(surface && surface->surface()->surfaceClass() == QSurface::Window);
+ QWindow *window = static_cast<QWindow *>(surface->surface());
+
+ FramebufferObject &framebufferObject = m_framebufferObjects[window];
+
+ // Set up an FBO for the window if it hasn't been created yet
+ if (!framebufferObject.handle) {
+ [EAGLContext setCurrentContext:m_eaglContext];
+
+ glGenFramebuffers(1, &framebufferObject.handle);
+ glBindFramebuffer(GL_FRAMEBUFFER, framebufferObject.handle);
+
+ glGenRenderbuffers(1, &framebufferObject.colorRenderbuffer);
+ glBindRenderbuffer(GL_RENDERBUFFER, framebufferObject.colorRenderbuffer);
+ glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER,
+ framebufferObject.colorRenderbuffer);
+
+ if (m_format.depthBufferSize() > 0 || m_format.stencilBufferSize() > 0) {
+ glGenRenderbuffers(1, &framebufferObject.depthRenderbuffer);
+ glBindRenderbuffer(GL_RENDERBUFFER, framebufferObject.depthRenderbuffer);
+ glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER,
+ framebufferObject.depthRenderbuffer);
+
+ if (m_format.stencilBufferSize() > 0)
+ glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_STENCIL_ATTACHMENT, GL_RENDERBUFFER,
+ framebufferObject.depthRenderbuffer);
+ }
+
+ connect(window, SIGNAL(destroyed(QObject*)), this, SLOT(windowDestroyed(QObject*)));
+ }
+
+ // Ensure that the FBO's buffers match the size of the window
+ QIOSWindow *platformWindow = static_cast<QIOSWindow *>(surface);
+ if (framebufferObject.renderbufferWidth != platformWindow->effectiveWidth() ||
+ framebufferObject.renderbufferHeight != platformWindow->effectiveHeight()) {
+
+ glBindRenderbuffer(GL_RENDERBUFFER, framebufferObject.colorRenderbuffer);
+ UIView *view = reinterpret_cast<UIView *>(platformWindow->winId());
+ CAEAGLLayer *layer = static_cast<CAEAGLLayer *>(view.layer);
+ [m_eaglContext renderbufferStorage:GL_RENDERBUFFER fromDrawable:layer];
+
+ glGetRenderbufferParameteriv(GL_RENDERBUFFER, GL_RENDERBUFFER_WIDTH, &framebufferObject.renderbufferWidth);
+ glGetRenderbufferParameteriv(GL_RENDERBUFFER, GL_RENDERBUFFER_HEIGHT, &framebufferObject.renderbufferHeight);
+
+ if (framebufferObject.depthRenderbuffer) {
+ glBindRenderbuffer(GL_RENDERBUFFER, framebufferObject.depthRenderbuffer);
+
+ // FIXME: Support more fine grained control over depth/stencil buffer sizes
+ if (m_format.stencilBufferSize() > 0)
+ glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH24_STENCIL8_OES,
+ framebufferObject.renderbufferWidth, framebufferObject.renderbufferHeight);
+ else
+ glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT16,
+ framebufferObject.renderbufferWidth, framebufferObject.renderbufferHeight);
+ }
+
+ if (glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE)
+ NSLog(@"Failed to make complete framebuffer object %x", glCheckFramebufferStatus(GL_FRAMEBUFFER));
+ }
+
+ return framebufferObject.handle;
+}
+
+void QIOSContext::windowDestroyed(QObject *object)
+{
+ QWindow *window = static_cast<QWindow *>(object);
+ if (m_framebufferObjects.contains(window)) {
+ deleteBuffers(m_framebufferObjects[window]);
+ m_framebufferObjects.remove(window);
+ }
+}
+
+QFunctionPointer QIOSContext::getProcAddress(const QByteArray& functionName)
+{
+ return reinterpret_cast<QFunctionPointer>(dlsym(RTLD_NEXT, functionName.constData()));
+}
+
+#include "moc_qioscontext.cpp"
+
diff --git a/src/plugins/platforms/ios/qioseventdispatcher.h b/src/plugins/platforms/ios/qioseventdispatcher.h
new file mode 100644
index 0000000000..53a75618ce
--- /dev/null
+++ b/src/plugins/platforms/ios/qioseventdispatcher.h
@@ -0,0 +1,133 @@
+/****************************************************************************
+**
+** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the plugins of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Digia. For licensing terms and
+** conditions see http://qt.digia.com/licensing. For further information
+** use the contact form at http://qt.digia.com/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Digia gives you certain additional
+** rights. These rights are described in the Digia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+/****************************************************************************
+**
+** Copyright (c) 2007-2008, Apple, Inc.
+**
+** All rights reserved.
+**
+** Redistribution and use in source and binary forms, with or without
+** modification, are permitted provided that the following conditions are met:
+**
+** * Redistributions of source code must retain the above copyright notice,
+** this list of conditions and the following disclaimer.
+**
+** * Redistributions in binary form must reproduce the above copyright notice,
+** this list of conditions and the following disclaimer in the documentation
+** and/or other materials provided with the distribution.
+**
+** * Neither the name of Apple, Inc. nor the names of its contributors
+** may be used to endorse or promote products derived from this software
+** without specific prior written permission.
+**
+** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+** CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+** EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+** PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+** PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+** LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+** NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+** SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+**
+****************************************************************************/
+
+#ifndef QEVENTDISPATCHER_IOS_P_H
+#define QEVENTDISPATCHER_IOS_P_H
+
+#include <QtCore/qabstracteventdispatcher.h>
+#include <QtCore/private/qtimerinfo_unix_p.h>
+#include <QtPlatformSupport/private/qcfsocketnotifier_p.h>
+#include <CoreFoundation/CoreFoundation.h>
+
+QT_BEGIN_NAMESPACE
+
+class QIOSEventDispatcher : public QAbstractEventDispatcher
+{
+ Q_OBJECT
+
+public:
+ explicit QIOSEventDispatcher(QObject *parent = 0);
+ ~QIOSEventDispatcher();
+
+ bool processEvents(QEventLoop::ProcessEventsFlags flags);
+ bool hasPendingEvents();
+
+ void registerSocketNotifier(QSocketNotifier *notifier);
+ void unregisterSocketNotifier(QSocketNotifier *notifier);
+
+ void registerTimer(int timerId, int interval, Qt::TimerType timerType, QObject *object);
+ bool unregisterTimer(int timerId);
+ bool unregisterTimers(QObject *object);
+ QList<QAbstractEventDispatcher::TimerInfo> registeredTimers(QObject *object) const;
+
+ int remainingTime(int timerId);
+
+ void wakeUp();
+ void interrupt();
+ void flush();
+
+private:
+ bool m_interrupted;
+
+ CFRunLoopSourceRef m_postedEventsRunLoopSource;
+ CFRunLoopSourceRef m_blockingTimerRunLoopSource;
+
+ QTimerInfoList m_timerInfoList;
+ CFRunLoopTimerRef m_runLoopTimerRef;
+
+ QCFSocketNotifier m_cfSocketNotifier;
+
+ void processPostedEvents();
+ void maybeStartCFRunLoopTimer();
+ void maybeStopCFRunLoopTimer();
+
+ static void postedEventsRunLoopCallback(void *info);
+ static void nonBlockingTimerRunLoopCallback(CFRunLoopTimerRef, void *info);
+ static void blockingTimerRunLoopCallback(void *info);
+};
+
+QT_END_NAMESPACE
+
+#endif // QEVENTDISPATCHER_IOS_P_H
diff --git a/src/plugins/platforms/ios/qioseventdispatcher.mm b/src/plugins/platforms/ios/qioseventdispatcher.mm
new file mode 100644
index 0000000000..e9bf039047
--- /dev/null
+++ b/src/plugins/platforms/ios/qioseventdispatcher.mm
@@ -0,0 +1,322 @@
+/****************************************************************************
+**
+** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the plugins of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Digia. For licensing terms and
+** conditions see http://qt.digia.com/licensing. For further information
+** use the contact form at http://qt.digia.com/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Digia gives you certain additional
+** rights. These rights are described in the Digia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qioseventdispatcher.h"
+#import "qiosapplicationdelegate.h"
+#include <qdebug.h>
+#include <qpa/qwindowsysteminterface.h>
+#include <QtCore/QThread>
+#include <QtCore/private/qcoreapplication_p.h>
+#include <UIKit/UIApplication.h>
+
+QT_BEGIN_NAMESPACE
+QT_USE_NAMESPACE
+
+static Boolean runLoopSourceEqualCallback(const void *info1, const void *info2)
+{
+ return info1 == info2;
+}
+
+void QIOSEventDispatcher::postedEventsRunLoopCallback(void *info)
+{
+ QIOSEventDispatcher *self = static_cast<QIOSEventDispatcher *>(info);
+ self->processPostedEvents();
+}
+
+void QIOSEventDispatcher::nonBlockingTimerRunLoopCallback(CFRunLoopTimerRef, void *info)
+{
+ // The (one and only) CFRunLoopTimer has fired, which means that at least
+ // one QTimer should now fire as well. Note that CFRunLoopTimer's callback will
+ // never recurse. So if the app starts a new QEventLoop within this callback, other
+ // timers will stop working. The work-around is to forward the callback to a
+ // dedicated CFRunLoopSource that can recurse:
+ QIOSEventDispatcher *self = static_cast<QIOSEventDispatcher *>(info);
+ CFRunLoopSourceSignal(self->m_blockingTimerRunLoopSource);
+}
+
+void QIOSEventDispatcher::blockingTimerRunLoopCallback(void *info)
+{
+ // TODO:
+ // We also need to block this new timer source
+ // along with the posted event source when calling processEvents()
+ // "manually" to prevent livelock deep in CFRunLoop.
+
+ QIOSEventDispatcher *self = static_cast<QIOSEventDispatcher *>(info);
+ self->m_timerInfoList.activateTimers();
+ self->maybeStartCFRunLoopTimer();
+}
+
+void QIOSEventDispatcher::maybeStartCFRunLoopTimer()
+{
+ // Find out when the next registered timer should fire, and schedule
+ // runLoopTimer accordingly. If the runLoopTimer does not yet exist, and
+ // at least one timer is registered, start by creating the timer:
+ if (m_timerInfoList.isEmpty()) {
+ Q_ASSERT(m_runLoopTimerRef == 0);
+ return;
+ }
+
+ CFAbsoluteTime ttf = CFAbsoluteTimeGetCurrent();
+ CFTimeInterval interval;
+
+ if (m_runLoopTimerRef == 0) {
+ // start the CFRunLoopTimer
+ CFTimeInterval oneyear = CFTimeInterval(3600. * 24. * 365.);
+
+ // calculate when the next timer should fire:
+ struct timespec tv;
+ if (m_timerInfoList.timerWait(tv)) {
+ interval = qMax(tv.tv_sec + tv.tv_nsec / 1000000000., 0.0000001);
+ } else {
+ // this shouldn't really happen, but in case it does, set the timer
+ // to fire a some point in the distant future:
+ interval = oneyear;
+ }
+
+ ttf += interval;
+ CFRunLoopTimerContext info = { 0, this, 0, 0, 0 };
+ // create the timer with a large interval, as recommended by the CFRunLoopTimerSetNextFireDate()
+ // documentation, since we will adjust the timer's time-to-fire as needed to keep Qt timers working
+ m_runLoopTimerRef = CFRunLoopTimerCreate(0, ttf, oneyear, 0, 0, QIOSEventDispatcher::nonBlockingTimerRunLoopCallback, &info);
+ Q_ASSERT(m_runLoopTimerRef != 0);
+
+ CFRunLoopAddTimer(CFRunLoopGetMain(), m_runLoopTimerRef, kCFRunLoopCommonModes);
+ } else {
+ struct timespec tv;
+ // Calculate when the next timer should fire:
+ if (m_timerInfoList.timerWait(tv)) {
+ interval = qMax(tv.tv_sec + tv.tv_nsec / 1000000000., 0.0000001);
+ } else {
+ // no timers can fire, but we cannot stop the CFRunLoopTimer, set the timer to fire at some
+ // point in the distant future (the timer interval is one year)
+ interval = CFRunLoopTimerGetInterval(m_runLoopTimerRef);
+ }
+
+ ttf += interval;
+ CFRunLoopTimerSetNextFireDate(m_runLoopTimerRef, ttf);
+ }
+}
+
+void QIOSEventDispatcher::maybeStopCFRunLoopTimer()
+{
+ if (m_runLoopTimerRef == 0)
+ return;
+
+ CFRunLoopTimerInvalidate(m_runLoopTimerRef);
+ CFRelease(m_runLoopTimerRef);
+ m_runLoopTimerRef = 0;
+}
+
+void QIOSEventDispatcher::processPostedEvents()
+{
+ QWindowSystemInterface::sendWindowSystemEvents(QEventLoop::AllEvents);
+}
+
+QIOSEventDispatcher::QIOSEventDispatcher(QObject *parent)
+ : QAbstractEventDispatcher(parent)
+ , m_interrupted(false)
+ , m_runLoopTimerRef(0)
+{
+ m_cfSocketNotifier.setHostEventDispatcher(this);
+
+ CFRunLoopRef mainRunLoop = CFRunLoopGetMain();
+ CFRunLoopSourceContext context;
+ bzero(&context, sizeof(CFRunLoopSourceContext));
+ context.equal = runLoopSourceEqualCallback;
+ context.info = this;
+
+ // source used to handle timers:
+ context.perform = QIOSEventDispatcher::blockingTimerRunLoopCallback;
+ m_blockingTimerRunLoopSource = CFRunLoopSourceCreate(kCFAllocatorDefault, 0, &context);
+ Q_ASSERT(m_blockingTimerRunLoopSource);
+ CFRunLoopAddSource(mainRunLoop, m_blockingTimerRunLoopSource, kCFRunLoopCommonModes);
+
+ // source used to handle posted events:
+ context.perform = QIOSEventDispatcher::postedEventsRunLoopCallback;
+ m_postedEventsRunLoopSource = CFRunLoopSourceCreate(kCFAllocatorDefault, 0, &context);
+ Q_ASSERT(m_postedEventsRunLoopSource);
+ CFRunLoopAddSource(mainRunLoop, m_postedEventsRunLoopSource, kCFRunLoopCommonModes);
+}
+
+QIOSEventDispatcher::~QIOSEventDispatcher()
+{
+ CFRunLoopRef mainRunLoop = CFRunLoopGetMain();
+ CFRunLoopRemoveSource(mainRunLoop, m_postedEventsRunLoopSource, kCFRunLoopCommonModes);
+ CFRelease(m_postedEventsRunLoopSource);
+
+ qDeleteAll(m_timerInfoList);
+ maybeStopCFRunLoopTimer();
+ CFRunLoopRemoveSource(CFRunLoopGetMain(), m_blockingTimerRunLoopSource, kCFRunLoopCommonModes);
+ CFRelease(m_blockingTimerRunLoopSource);
+
+ m_cfSocketNotifier.removeSocketNotifiers();
+}
+
+bool QIOSEventDispatcher::processEvents(QEventLoop::ProcessEventsFlags flags)
+{
+ m_interrupted = false;
+ bool eventsProcessed = false;
+
+ bool excludeUserEvents = flags & QEventLoop::ExcludeUserInputEvents;
+ bool execFlagSet = (flags & QEventLoop::DialogExec) || (flags & QEventLoop::EventLoopExec);
+ bool useExecMode = execFlagSet && !excludeUserEvents;
+
+ if (useExecMode) {
+ NSRunLoop *runLoop = [NSRunLoop currentRunLoop];
+ while ([runLoop runMode:NSDefaultRunLoopMode beforeDate:[NSDate distantFuture]] && !m_interrupted);
+ eventsProcessed = true;
+ } else {
+ if (!(flags & QEventLoop::WaitForMoreEvents))
+ wakeUp();
+ eventsProcessed = [[NSRunLoop currentRunLoop] runMode:NSDefaultRunLoopMode beforeDate:[NSDate distantFuture]];
+ }
+ return eventsProcessed;
+}
+
+bool QIOSEventDispatcher::hasPendingEvents()
+{
+ qDebug() << __FUNCTION__ << "not implemented";
+ return false;
+}
+
+void QIOSEventDispatcher::registerSocketNotifier(QSocketNotifier *notifier)
+{
+ m_cfSocketNotifier.registerSocketNotifier(notifier);
+}
+
+void QIOSEventDispatcher::unregisterSocketNotifier(QSocketNotifier *notifier)
+{
+ m_cfSocketNotifier.unregisterSocketNotifier(notifier);
+}
+
+void QIOSEventDispatcher::registerTimer(int timerId, int interval, Qt::TimerType timerType, QObject *obj)
+{
+#ifndef QT_NO_DEBUG
+ if (timerId < 1 || interval < 0 || !obj) {
+ qWarning("QIOSEventDispatcher::registerTimer: invalid arguments");
+ return;
+ } else if (obj->thread() != thread() || thread() != QThread::currentThread()) {
+ qWarning("QIOSEventDispatcher: timers cannot be started from another thread");
+ return;
+ }
+#endif
+
+ m_timerInfoList.registerTimer(timerId, interval, timerType, obj);
+ maybeStartCFRunLoopTimer();
+}
+
+bool QIOSEventDispatcher::unregisterTimer(int timerId)
+{
+#ifndef QT_NO_DEBUG
+ if (timerId < 1) {
+ qWarning("QIOSEventDispatcher::unregisterTimer: invalid argument");
+ return false;
+ } else if (thread() != QThread::currentThread()) {
+ qWarning("QObject::killTimer: timers cannot be stopped from another thread");
+ return false;
+ }
+#endif
+
+ bool returnValue = m_timerInfoList.unregisterTimer(timerId);
+ m_timerInfoList.isEmpty() ? maybeStopCFRunLoopTimer() : maybeStartCFRunLoopTimer();
+ return returnValue;
+}
+
+bool QIOSEventDispatcher::unregisterTimers(QObject *object)
+{
+#ifndef QT_NO_DEBUG
+ if (!object) {
+ qWarning("QIOSEventDispatcher::unregisterTimers: invalid argument");
+ return false;
+ } else if (object->thread() != thread() || thread() != QThread::currentThread()) {
+ qWarning("QObject::killTimers: timers cannot be stopped from another thread");
+ return false;
+ }
+#endif
+
+ bool returnValue = m_timerInfoList.unregisterTimers(object);
+ m_timerInfoList.isEmpty() ? maybeStopCFRunLoopTimer() : maybeStartCFRunLoopTimer();
+ return returnValue;
+}
+
+QList<QAbstractEventDispatcher::TimerInfo> QIOSEventDispatcher::registeredTimers(QObject *object) const
+{
+#ifndef QT_NO_DEBUG
+ if (!object) {
+ qWarning("QIOSEventDispatcher:registeredTimers: invalid argument");
+ return QList<TimerInfo>();
+ }
+#endif
+
+ return m_timerInfoList.registeredTimers(object);
+}
+
+int QIOSEventDispatcher::remainingTime(int timerId)
+{
+#ifndef QT_NO_DEBUG
+ if (timerId < 1) {
+ qWarning("QIOSEventDispatcher::remainingTime: invalid argument");
+ return -1;
+ }
+#endif
+
+ return m_timerInfoList.timerRemainingTime(timerId);
+}
+
+void QIOSEventDispatcher::wakeUp()
+{
+ CFRunLoopSourceSignal(m_postedEventsRunLoopSource);
+ CFRunLoopWakeUp(CFRunLoopGetMain());
+}
+
+void QIOSEventDispatcher::interrupt()
+{
+ wakeUp();
+ m_interrupted = true;
+}
+
+void QIOSEventDispatcher::flush()
+{
+ // X11 only.
+}
+
+QT_END_NAMESPACE
+
diff --git a/src/plugins/platforms/ios/qiosglobal.h b/src/plugins/platforms/ios/qiosglobal.h
new file mode 100644
index 0000000000..3be9f8bb21
--- /dev/null
+++ b/src/plugins/platforms/ios/qiosglobal.h
@@ -0,0 +1,67 @@
+/****************************************************************************
+**
+** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the plugins of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Digia. For licensing terms and
+** conditions see http://qt.digia.com/licensing. For further information
+** use the contact form at http://qt.digia.com/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Digia gives you certain additional
+** rights. These rights are described in the Digia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QIOSGLOBAL_H
+#define QIOSGLOBAL_H
+
+#import <UIKit/UIKit.h>
+#include <QtCore/QtCore>
+
+@class QIOSViewController;
+
+QT_BEGIN_NAMESPACE
+
+class QPlatformScreen;
+
+bool isQtApplication();
+QIOSViewController *rootViewController();
+
+CGRect toCGRect(const QRect &rect);
+QRect fromCGRect(const CGRect &rect);
+CGPoint toCGPoint(const QPoint &point);
+QPoint fromCGPoint(const CGPoint &point);
+Qt::ScreenOrientation toQtScreenOrientation(UIDeviceOrientation uiDeviceOrientation);
+UIDeviceOrientation fromQtScreenOrientation(Qt::ScreenOrientation qtOrientation);
+QRect fromPortraitToPrimary(const QRect &rect, QPlatformScreen *screen);
+
+QT_END_NAMESPACE
+
+#endif // QIOSGLOBAL_H
diff --git a/src/plugins/platforms/ios/qiosglobal.mm b/src/plugins/platforms/ios/qiosglobal.mm
new file mode 100644
index 0000000000..5860078372
--- /dev/null
+++ b/src/plugins/platforms/ios/qiosglobal.mm
@@ -0,0 +1,144 @@
+/****************************************************************************
+**
+** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the plugins of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Digia. For licensing terms and
+** conditions see http://qt.digia.com/licensing. For further information
+** use the contact form at http://qt.digia.com/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Digia gives you certain additional
+** rights. These rights are described in the Digia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qiosglobal.h"
+#include "qiosapplicationdelegate.h"
+#include "qiosviewcontroller.h"
+#include "qiosscreen.h"
+
+QT_BEGIN_NAMESPACE
+
+bool isQtApplication()
+{
+ // Returns true if the plugin is in full control of the whole application. This means
+ // that we control the application delegate and the top view controller, and can take
+ // actions that impacts all parts of the application. The opposite means that we are
+ // embedded inside a native iOS application, and should be more focused on playing along
+ // with native UIControls, and less inclined to change structures that lies outside the
+ // scope of our QWindows/UIViews.
+ static bool isQt = ([[UIApplication sharedApplication].delegate isKindOfClass:[QIOSApplicationDelegate class]]);
+ return isQt;
+}
+
+QIOSViewController *rootViewController()
+{
+ static QIOSViewController *c = isQtApplication() ?
+ static_cast<QIOSViewController *>([UIApplication sharedApplication].delegate.window.rootViewController) : nil;
+ return c;
+}
+
+CGRect toCGRect(const QRect &rect)
+{
+ return CGRectMake(rect.x(), rect.y(), rect.width(), rect.height());
+}
+
+QRect fromCGRect(const CGRect &rect)
+{
+ return QRect(rect.origin.x, rect.origin.y, rect.size.width, rect.size.height);
+}
+
+CGPoint toCGPoint(const QPoint &point)
+{
+ return CGPointMake(point.x(), point.y());
+}
+
+QPoint fromCGPoint(const CGPoint &point)
+{
+ return QPoint(point.x, point.y);
+}
+
+Qt::ScreenOrientation toQtScreenOrientation(UIDeviceOrientation uiDeviceOrientation)
+{
+ Qt::ScreenOrientation qtOrientation;
+ switch (uiDeviceOrientation) {
+ case UIDeviceOrientationPortraitUpsideDown:
+ qtOrientation = Qt::InvertedPortraitOrientation;
+ break;
+ case UIDeviceOrientationLandscapeLeft:
+ qtOrientation = Qt::InvertedLandscapeOrientation;
+ break;
+ case UIDeviceOrientationLandscapeRight:
+ qtOrientation = Qt::LandscapeOrientation;
+ break;
+ case UIDeviceOrientationFaceUp:
+ case UIDeviceOrientationFaceDown:
+ qtOrientation = static_cast<Qt::ScreenOrientation>(-1); // not supported ATM.
+ break;
+ default:
+ qtOrientation = Qt::PortraitOrientation;
+ break;
+ }
+ return qtOrientation;
+}
+
+UIDeviceOrientation fromQtScreenOrientation(Qt::ScreenOrientation qtOrientation)
+{
+ UIDeviceOrientation uiOrientation;
+ switch (qtOrientation) {
+ case Qt::LandscapeOrientation:
+ uiOrientation = UIDeviceOrientationLandscapeRight;
+ break;
+ case Qt::InvertedLandscapeOrientation:
+ uiOrientation = UIDeviceOrientationLandscapeLeft;
+ break;
+ case Qt::InvertedPortraitOrientation:
+ uiOrientation = UIDeviceOrientationPortraitUpsideDown;
+ break;
+ case Qt::PrimaryOrientation:
+ case Qt::PortraitOrientation:
+ default:
+ uiOrientation = UIDeviceOrientationPortrait;
+ break;
+ }
+ return uiOrientation;
+}
+
+QRect fromPortraitToPrimary(const QRect &rect, QPlatformScreen *screen)
+{
+ // UIScreen is always in portrait. Use this function to convert CGRects
+ // aligned with UIScreen into whatever is the current orientation of QScreen.
+ QRect geometry = screen->geometry();
+ return geometry.width() < geometry.height() ? rect
+ : QRect(rect.y(), geometry.width() - rect.width() - rect.x(), rect.height(), rect.width());
+}
+
+QT_END_NAMESPACE
+
diff --git a/src/plugins/platforms/ios/qiosinputcontext.h b/src/plugins/platforms/ios/qiosinputcontext.h
new file mode 100644
index 0000000000..176ad05733
--- /dev/null
+++ b/src/plugins/platforms/ios/qiosinputcontext.h
@@ -0,0 +1,73 @@
+/****************************************************************************
+**
+** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the plugins of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Digia. For licensing terms and
+** conditions see http://qt.digia.com/licensing. For further information
+** use the contact form at http://qt.digia.com/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Digia gives you certain additional
+** rights. These rights are described in the Digia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QIOSINPUTCONTEXT_H
+#define QIOSINPUTCONTEXT_H
+
+#include <UIKit/UIKit.h>
+
+#include <qpa/qplatforminputcontext.h>
+
+QT_BEGIN_NAMESPACE
+
+@class QIOSKeyboardListener;
+
+class QIOSInputContext : public QPlatformInputContext
+{
+public:
+ QIOSInputContext();
+ ~QIOSInputContext();
+
+ QRectF keyboardRect() const;
+ void showInputPanel();
+ void hideInputPanel();
+ bool isInputPanelVisible() const;
+
+ void focusViewChanged(UIView *view);
+
+private:
+ QIOSKeyboardListener *m_keyboardListener;
+ UIView *m_focusView;
+};
+
+QT_END_NAMESPACE
+
+#endif
diff --git a/src/plugins/platforms/ios/qiosinputcontext.mm b/src/plugins/platforms/ios/qiosinputcontext.mm
new file mode 100644
index 0000000000..1d3ab12de9
--- /dev/null
+++ b/src/plugins/platforms/ios/qiosinputcontext.mm
@@ -0,0 +1,142 @@
+/****************************************************************************
+**
+** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the plugins of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Digia. For licensing terms and
+** conditions see http://qt.digia.com/licensing. For further information
+** use the contact form at http://qt.digia.com/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Digia gives you certain additional
+** rights. These rights are described in the Digia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qiosglobal.h"
+#include "qiosinputcontext.h"
+#include "qioswindow.h"
+#include <QGuiApplication>
+
+@interface QIOSKeyboardListener : NSObject {
+@public
+ QIOSInputContext *m_context;
+ BOOL m_keyboardVisible;
+ QRectF m_keyboardRect;
+}
+@end
+
+@implementation QIOSKeyboardListener
+
+- (id)initWithQIOSInputContext:(QIOSInputContext *)context
+{
+ self = [super init];
+ if (self) {
+ m_context = context;
+ m_keyboardVisible = NO;
+ // After the keyboard became undockable (iOS5), UIKeyboardWillShow/UIKeyboardWillHide
+ // no longer works for all cases. So listen to keyboard frame changes instead:
+ [[NSNotificationCenter defaultCenter]
+ addObserver:self
+ selector:@selector(keyboardDidChangeFrame:)
+ name:@"UIKeyboardDidChangeFrameNotification" object:nil];
+ }
+ return self;
+}
+
+- (void) dealloc
+{
+ [[NSNotificationCenter defaultCenter]
+ removeObserver:self
+ name:@"UIKeyboardDidChangeFrameNotification" object:nil];
+ [super dealloc];
+}
+
+- (void) keyboardDidChangeFrame:(NSNotification *)notification
+{
+ CGRect frame;
+ [[[notification userInfo] objectForKey:UIKeyboardFrameEndUserInfoKey] getValue:&frame];
+
+ m_keyboardRect = fromPortraitToPrimary(fromCGRect(frame), QGuiApplication::primaryScreen()->handle());
+ m_context->emitKeyboardRectChanged();
+
+ BOOL visible = CGRectIntersectsRect(frame, [UIScreen mainScreen].bounds);
+ if (m_keyboardVisible != visible) {
+ m_keyboardVisible = visible;
+ m_context->emitInputPanelVisibleChanged();
+ }
+}
+
+@end
+
+QIOSInputContext::QIOSInputContext()
+ : QPlatformInputContext()
+ , m_keyboardListener([[QIOSKeyboardListener alloc] initWithQIOSInputContext:this])
+ , m_focusView(0)
+{
+}
+
+QIOSInputContext::~QIOSInputContext()
+{
+ [m_keyboardListener release];
+ [m_focusView release];
+}
+
+QRectF QIOSInputContext::keyboardRect() const
+{
+ return m_keyboardListener->m_keyboardRect;
+}
+
+void QIOSInputContext::showInputPanel()
+{
+ // Documentation tells that one should call (and recall, if necessary) becomeFirstResponder/resignFirstResponder
+ // to show/hide the keyboard. This is slightly inconvenient, since there exist no API to get the current first
+ // responder. Rather than searching for it from the top, we let the active QIOSWindow tell us which view to use.
+ // Note that Qt will forward keyevents to whichever QObject that needs it, regardless of which UIView the input
+ // actually came from. So in this respect, we're undermining iOS' responder chain.
+ [m_focusView becomeFirstResponder];
+}
+
+void QIOSInputContext::hideInputPanel()
+{
+ [m_focusView resignFirstResponder];
+}
+
+bool QIOSInputContext::isInputPanelVisible() const
+{
+ return m_keyboardListener->m_keyboardVisible;
+}
+
+void QIOSInputContext::focusViewChanged(UIView *view)
+{
+ if ([m_focusView isFirstResponder])
+ [view becomeFirstResponder];
+ [m_focusView release];
+ m_focusView = [view retain];
+}
diff --git a/src/plugins/platforms/ios/qiosintegration.h b/src/plugins/platforms/ios/qiosintegration.h
new file mode 100644
index 0000000000..329a0a3d9b
--- /dev/null
+++ b/src/plugins/platforms/ios/qiosintegration.h
@@ -0,0 +1,88 @@
+/****************************************************************************
+**
+** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the plugins of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Digia. For licensing terms and
+** conditions see http://qt.digia.com/licensing. For further information
+** use the contact form at http://qt.digia.com/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Digia gives you certain additional
+** rights. These rights are described in the Digia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QPLATFORMINTEGRATION_UIKIT_H
+#define QPLATFORMINTEGRATION_UIKIT_H
+
+#include <qpa/qplatformintegration.h>
+#include <qpa/qplatformnativeinterface.h>
+#include <qpa/qwindowsysteminterface.h>
+
+QT_BEGIN_NAMESPACE
+
+class QIOSIntegration : public QPlatformIntegration, public QPlatformNativeInterface
+{
+public:
+ QIOSIntegration();
+ ~QIOSIntegration();
+
+ bool hasCapability(Capability cap) const;
+
+ QPlatformWindow *createPlatformWindow(QWindow *window) const;
+ QPlatformBackingStore *createPlatformBackingStore(QWindow *window) const;
+
+ QPlatformOpenGLContext *createPlatformOpenGLContext(QOpenGLContext *context) const;
+
+ QPlatformFontDatabase *fontDatabase() const;
+ QPlatformInputContext *inputContext() const;
+
+ QVariant styleHint(StyleHint hint) const;
+
+ QStringList themeNames() const;
+ QPlatformTheme *createPlatformTheme(const QString &name) const;
+
+ QAbstractEventDispatcher *guiThreadEventDispatcher() const;
+ QPlatformNativeInterface *nativeInterface() const;
+
+ void *nativeResourceForWindow(const QByteArray &resource, QWindow *window);
+
+ QTouchDevice *touchDevice();
+private:
+ QPlatformFontDatabase *m_fontDatabase;
+ QPlatformInputContext *m_inputContext;
+ QPlatformScreen *m_screen;
+ QTouchDevice *m_touchDevice;
+};
+
+QT_END_NAMESPACE
+
+#endif
+
diff --git a/src/plugins/platforms/ios/qiosintegration.mm b/src/plugins/platforms/ios/qiosintegration.mm
new file mode 100644
index 0000000000..c7541c3e38
--- /dev/null
+++ b/src/plugins/platforms/ios/qiosintegration.mm
@@ -0,0 +1,180 @@
+/****************************************************************************
+**
+** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the plugins of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Digia. For licensing terms and
+** conditions see http://qt.digia.com/licensing. For further information
+** use the contact form at http://qt.digia.com/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Digia gives you certain additional
+** rights. These rights are described in the Digia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qiosintegration.h"
+#include "qioswindow.h"
+#include "qiosbackingstore.h"
+#include "qiosscreen.h"
+#include "qioseventdispatcher.h"
+#include "qioscontext.h"
+#include "qiosinputcontext.h"
+#include "qiostheme.h"
+
+#include <QtPlatformSupport/private/qcoretextfontdatabase_p.h>
+
+#include <QtDebug>
+
+QT_BEGIN_NAMESPACE
+
+QIOSIntegration::QIOSIntegration()
+ : m_fontDatabase(new QCoreTextFontDatabase)
+ , m_inputContext(new QIOSInputContext)
+ , m_screen(new QIOSScreen(QIOSScreen::MainScreen))
+{
+ if (![UIApplication sharedApplication]) {
+ qWarning()
+ << "Error: You are creating QApplication before calling UIApplicationMain.\n"
+ << "If you are writing a native iOS application, and only want to use Qt for\n"
+ << "parts of the application, a good place to create QApplication is from within\n"
+ << "'applicationDidFinishLaunching' inside your UIApplication delegate.\n"
+ << "If you instead create a cross-platform Qt application and do not intend to call\n"
+ << "UIApplicationMain, you need to link in libqtmain.a, and substitute main with qt_main.\n"
+ << "This is normally done automatically by qmake.\n";
+ exit(-1);
+ }
+
+ screenAdded(m_screen);
+
+ m_touchDevice = new QTouchDevice;
+ m_touchDevice->setType(QTouchDevice::TouchScreen);
+ m_touchDevice->setCapabilities(QTouchDevice::Position | QTouchDevice::NormalizedPosition);
+ QWindowSystemInterface::registerTouchDevice(m_touchDevice);
+}
+
+QIOSIntegration::~QIOSIntegration()
+{
+ delete m_touchDevice;
+}
+
+bool QIOSIntegration::hasCapability(Capability cap) const
+{
+ switch (cap) {
+ case OpenGL:
+ return true;
+ case MultipleWindows:
+ return true;
+ default:
+ return QPlatformIntegration::hasCapability(cap);
+ }
+}
+
+QPlatformWindow *QIOSIntegration::createPlatformWindow(QWindow *window) const
+{
+ return new QIOSWindow(window);
+}
+
+// Used when the QWindow's surface type is set by the client to QSurface::RasterSurface
+QPlatformBackingStore *QIOSIntegration::createPlatformBackingStore(QWindow *window) const
+{
+ return new QIOSBackingStore(window);
+}
+
+// Used when the QWindow's surface type is set by the client to QSurface::OpenGLSurface
+QPlatformOpenGLContext *QIOSIntegration::createPlatformOpenGLContext(QOpenGLContext *context) const
+{
+ Q_UNUSED(context);
+ return new QIOSContext(context);
+}
+
+QAbstractEventDispatcher *QIOSIntegration::guiThreadEventDispatcher() const
+{
+ return new QIOSEventDispatcher();
+}
+
+QPlatformFontDatabase * QIOSIntegration::fontDatabase() const
+{
+ return m_fontDatabase;
+}
+
+QPlatformInputContext *QIOSIntegration::inputContext() const
+{
+ return m_inputContext;
+}
+
+QVariant QIOSIntegration::styleHint(StyleHint hint) const
+{
+ switch (hint) {
+ case ShowIsFullScreen:
+ return true;
+ default:
+ return QPlatformIntegration::styleHint(hint);
+ }
+}
+
+QStringList QIOSIntegration::themeNames() const
+{
+ return QStringList(QLatin1String(QIOSTheme::name));
+}
+
+QPlatformTheme *QIOSIntegration::createPlatformTheme(const QString &name) const
+{
+ if (name == QLatin1String(QIOSTheme::name))
+ return new QIOSTheme;
+
+ return QPlatformIntegration::createPlatformTheme(name);
+}
+
+QPlatformNativeInterface *QIOSIntegration::nativeInterface() const
+{
+ return const_cast<QIOSIntegration *>(this);
+}
+
+void *QIOSIntegration::nativeResourceForWindow(const QByteArray &resource, QWindow *window)
+{
+ if (!window || !window->handle())
+ return 0;
+
+ QByteArray lowerCaseResource = resource.toLower();
+
+ QIOSWindow *platformWindow = static_cast<QIOSWindow *>(window->handle());
+
+ if (lowerCaseResource == "uiview")
+ return reinterpret_cast<void *>(platformWindow->winId());
+
+ return 0;
+}
+
+QTouchDevice *QIOSIntegration::touchDevice()
+{
+ return m_touchDevice;
+}
+
+QT_END_NAMESPACE
diff --git a/src/plugins/platforms/ios/qiosscreen.h b/src/plugins/platforms/ios/qiosscreen.h
new file mode 100644
index 0000000000..40c7a3ccf7
--- /dev/null
+++ b/src/plugins/platforms/ios/qiosscreen.h
@@ -0,0 +1,88 @@
+/****************************************************************************
+**
+** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the plugins of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Digia. For licensing terms and
+** conditions see http://qt.digia.com/licensing. For further information
+** use the contact form at http://qt.digia.com/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Digia gives you certain additional
+** rights. These rights are described in the Digia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QIOSSCREEN_H
+#define QIOSSCREEN_H
+
+#include <UIKit/UIKit.h>
+
+#include <qpa/qplatformscreen.h>
+
+@class QIOSOrientationListener;
+
+QT_BEGIN_NAMESPACE
+
+class QIOSScreen : public QPlatformScreen
+{
+public:
+ QIOSScreen(unsigned int screenIndex);
+ ~QIOSScreen();
+
+ enum ScreenIndex { MainScreen = 0 };
+
+ QRect geometry() const;
+ QRect availableGeometry() const;
+ int depth() const;
+ QImage::Format format() const;
+ QSizeF physicalSize() const;
+ QDpi logicalDpi() const;
+ qreal devicePixelRatio() const;
+
+ Qt::ScreenOrientation nativeOrientation() const;
+ Qt::ScreenOrientation orientation() const;
+ void setOrientationUpdateMask(Qt::ScreenOrientations mask);
+
+ UIScreen *uiScreen() const;
+
+ void setPrimaryOrientation(Qt::ScreenOrientation orientation);
+
+private:
+ UIScreen *m_uiScreen;
+ QRect m_geometry;
+ QRect m_availableGeometry;
+ int m_depth;
+ QSizeF m_physicalSize;
+ QIOSOrientationListener *m_orientationListener;
+};
+
+QT_END_NAMESPACE
+
+#endif
diff --git a/src/plugins/platforms/ios/qiosscreen.mm b/src/plugins/platforms/ios/qiosscreen.mm
new file mode 100644
index 0000000000..3265ed8e37
--- /dev/null
+++ b/src/plugins/platforms/ios/qiosscreen.mm
@@ -0,0 +1,238 @@
+/****************************************************************************
+**
+** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the plugins of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Digia. For licensing terms and
+** conditions see http://qt.digia.com/licensing. For further information
+** use the contact form at http://qt.digia.com/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Digia gives you certain additional
+** rights. These rights are described in the Digia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qiosglobal.h"
+#include "qiosscreen.h"
+#include "qioswindow.h"
+#include <qpa/qwindowsysteminterface.h>
+#include "qiosapplicationdelegate.h"
+#include "qiosviewcontroller.h"
+
+#include <sys/sysctl.h>
+
+@interface QIOSOrientationListener : NSObject {
+ @public
+ QIOSScreen *m_screen;
+}
+- (id) initWithQIOSScreen:(QIOSScreen *)screen;
+@end
+
+@implementation QIOSOrientationListener
+
+- (id) initWithQIOSScreen:(QIOSScreen *)screen
+{
+ self = [super init];
+ if (self) {
+ m_screen = screen;
+ [[UIDevice currentDevice] beginGeneratingDeviceOrientationNotifications];
+ [[NSNotificationCenter defaultCenter]
+ addObserver:self
+ selector:@selector(orientationChanged:)
+ name:@"UIDeviceOrientationDidChangeNotification" object:nil];
+ }
+ return self;
+}
+
+- (void) dealloc
+{
+ [[UIDevice currentDevice] endGeneratingDeviceOrientationNotifications];
+ [[NSNotificationCenter defaultCenter]
+ removeObserver:self
+ name:@"UIDeviceOrientationDidChangeNotification" object:nil];
+ [super dealloc];
+}
+
+- (void) orientationChanged:(NSNotification *)notification
+{
+ Q_UNUSED(notification);
+ Qt::ScreenOrientation orientation = toQtScreenOrientation([UIDevice currentDevice].orientation);
+ if (orientation != -1)
+ QWindowSystemInterface::handleScreenOrientationChange(m_screen->screen(), orientation);
+}
+
+@end
+
+/*!
+ Returns the model identifier of the device.
+
+ When running under the simulator, the identifier will not
+ match the simulated device, but will be x86_64 or i386.
+*/
+static QString deviceModelIdentifier()
+{
+ static const char key[] = "hw.machine";
+
+ size_t size;
+ sysctlbyname(key, NULL, &size, NULL, 0);
+
+ char value[size];
+ sysctlbyname(key, &value, &size, NULL, 0);
+
+ return QString::fromLatin1(value);
+}
+
+QIOSScreen::QIOSScreen(unsigned int screenIndex)
+ : QPlatformScreen()
+ , m_uiScreen([[UIScreen screens] objectAtIndex:qMin(screenIndex, [[UIScreen screens] count] - 1)])
+ , m_orientationListener(0)
+{
+ NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
+
+ QString deviceIdentifier = deviceModelIdentifier();
+
+ if (deviceIdentifier == QStringLiteral("iPhone2,1") /* iPhone 3GS */
+ || deviceIdentifier == QStringLiteral("iPod3,1") /* iPod touch 3G */) {
+ m_depth = 18;
+ } else {
+ m_depth = 24;
+ }
+
+ int unscaledDpi = 163; // Regular iPhone DPI
+ if ([[UIDevice currentDevice] userInterfaceIdiom] == UIUserInterfaceIdiomPad
+ && deviceIdentifier != QStringLiteral("iPad2,5") /* iPad Mini */) {
+ unscaledDpi = 132;
+ };
+
+ CGRect bounds = [m_uiScreen bounds];
+ m_geometry = QRect(bounds.origin.x, bounds.origin.y, bounds.size.width, bounds.size.height);
+
+ CGRect frame = m_uiScreen.applicationFrame;
+ m_availableGeometry = QRect(frame.origin.x, frame.origin.y, frame.size.width, frame.size.height);
+
+ const qreal millimetersPerInch = 25.4;
+ m_physicalSize = QSizeF(m_geometry.size()) / unscaledDpi * millimetersPerInch;
+
+ if (isQtApplication()) {
+ // When in a non-mixed environment, let QScreen follow the current interface orientation:
+ setPrimaryOrientation(toQtScreenOrientation(rootViewController().interfaceOrientation));
+ }
+
+ [pool release];
+}
+
+QIOSScreen::~QIOSScreen()
+{
+ [m_orientationListener release];
+}
+
+QRect QIOSScreen::geometry() const
+{
+ return m_geometry;
+}
+
+QRect QIOSScreen::availableGeometry() const
+{
+ return m_availableGeometry;
+}
+
+int QIOSScreen::depth() const
+{
+ return m_depth;
+}
+
+QImage::Format QIOSScreen::format() const
+{
+ return QImage::Format_ARGB32_Premultiplied;
+}
+
+QSizeF QIOSScreen::physicalSize() const
+{
+ return m_physicalSize;
+}
+
+QDpi QIOSScreen::logicalDpi() const
+{
+ return QDpi(72, 72);
+}
+
+qreal QIOSScreen::devicePixelRatio() const
+{
+ return [m_uiScreen scale];
+}
+
+Qt::ScreenOrientation QIOSScreen::nativeOrientation() const
+{
+ return Qt::PortraitOrientation;
+}
+
+Qt::ScreenOrientation QIOSScreen::orientation() const
+{
+ return toQtScreenOrientation([UIDevice currentDevice].orientation);
+}
+
+void QIOSScreen::setOrientationUpdateMask(Qt::ScreenOrientations mask)
+{
+ if (m_orientationListener && mask == Qt::PrimaryOrientation) {
+ [m_orientationListener release];
+ m_orientationListener = 0;
+ } else if (!m_orientationListener) {
+ m_orientationListener = [[QIOSOrientationListener alloc] initWithQIOSScreen:this];
+ }
+}
+
+void QIOSScreen::setPrimaryOrientation(Qt::ScreenOrientation orientation)
+{
+ // Note that UIScreen never changes orientation, but QScreen should. To work around
+ // this, we let QIOSViewController call us whenever interface orientation changes, and
+ // use that as primary orientation. After all, the viewcontrollers geometry is what we
+ // place QWindows on top of. A problem with this approach is that QIOSViewController is
+ // not in use in a mixed environment, which results in no change to primary orientation.
+ // We see that as acceptable since Qt should most likely not interfere with orientation
+ // for that case anyway.
+ bool portrait = screen()->isPortrait(orientation);
+ if (portrait && m_geometry.width() < m_geometry.height())
+ return;
+
+ // Switching portrait/landscape means swapping width/height (and adjusting x/y):
+ m_geometry = QRect(0, 0, m_geometry.height(), m_geometry.width());
+ m_physicalSize = QSizeF(m_physicalSize.height(), m_physicalSize.width());
+ m_availableGeometry = fromPortraitToPrimary(fromCGRect(m_uiScreen.applicationFrame), this);
+
+ QWindowSystemInterface::handleScreenGeometryChange(screen(), m_geometry);
+ QWindowSystemInterface::handleScreenAvailableGeometryChange(screen(), m_availableGeometry);
+}
+
+UIScreen *QIOSScreen::uiScreen() const
+{
+ return m_uiScreen;
+}
+
+QT_END_NAMESPACE
diff --git a/src/plugins/platforms/ios/qiossoftwareinputhandler.h b/src/plugins/platforms/ios/qiossoftwareinputhandler.h
new file mode 100644
index 0000000000..5dad6b8d86
--- /dev/null
+++ b/src/plugins/platforms/ios/qiossoftwareinputhandler.h
@@ -0,0 +1,71 @@
+/****************************************************************************
+**
+** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the plugins of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Digia. For licensing terms and
+** conditions see http://qt.digia.com/licensing. For further information
+** use the contact form at http://qt.digia.com/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Digia gives you certain additional
+** rights. These rights are described in the Digia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QIOSSOFTWAREINPUTHANDLER_H
+#define QIOSSOFTWAREINPUTHANDLER_H
+
+#include <QtCore/QObject>
+#include <QtCore/QPointer>
+#include <QtWidgets/QWidget>
+
+QT_BEGIN_NAMESPACE
+
+class QIOSSoftwareInputHandler : public QObject
+{
+ Q_OBJECT
+
+public:
+ QIOSSoftwareInputHandler() : m_CurrentFocusWidget(0), m_CurrentFocusObject(0) {}
+ bool eventFilter(QObject *obj, QEvent *event);
+
+private slots:
+ void activeFocusChanged(bool focus);
+
+private:
+ bool closeSoftwareInputPanel(QWidget *widget);
+
+ QPointer<QWidget> m_currentFocusWidget;
+ QPointer<QObject> m_currentFocusObject;
+};
+
+QT_END_NAMESPACE
+
+#endif
diff --git a/src/plugins/platforms/ios/qiostheme.h b/src/plugins/platforms/ios/qiostheme.h
new file mode 100644
index 0000000000..5ccbcac710
--- /dev/null
+++ b/src/plugins/platforms/ios/qiostheme.h
@@ -0,0 +1,64 @@
+/****************************************************************************
+**
+** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the plugins of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Digia. For licensing terms and
+** conditions see http://qt.digia.com/licensing. For further information
+** use the contact form at http://qt.digia.com/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Digia gives you certain additional
+** rights. These rights are described in the Digia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QIOSTHEME_H
+#define QIOSTHEME_H
+
+#include <qpa/qplatformtheme.h>
+
+QT_BEGIN_NAMESPACE
+
+class QIOSTheme : public QPlatformTheme
+{
+public:
+ QIOSTheme();
+ ~QIOSTheme();
+
+ QVariant themeHint(ThemeHint hint) const;
+
+ const QFont *font(Font type = SystemFont) const;
+
+ static const char *name;
+};
+
+QT_END_NAMESPACE
+
+#endif
diff --git a/src/plugins/platforms/ios/qiostheme.mm b/src/plugins/platforms/ios/qiostheme.mm
new file mode 100644
index 0000000000..f98781f8a7
--- /dev/null
+++ b/src/plugins/platforms/ios/qiostheme.mm
@@ -0,0 +1,96 @@
+/****************************************************************************
+**
+** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the plugins of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Digia. For licensing terms and
+** conditions see http://qt.digia.com/licensing. For further information
+** use the contact form at http://qt.digia.com/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Digia gives you certain additional
+** rights. These rights are described in the Digia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qiostheme.h"
+
+#include <QtCore/QStringList>
+#include <QtCore/QVariant>
+
+#include <QtGui/QFont>
+
+#include <UIKit/UIFont.h>
+#include <UIKit/UIInterface.h>
+
+QT_BEGIN_NAMESPACE
+
+const char *QIOSTheme::name = "ios";
+
+QIOSTheme::QIOSTheme()
+{
+}
+
+QIOSTheme::~QIOSTheme()
+{
+}
+
+QVariant QIOSTheme::themeHint(ThemeHint hint) const
+{
+ switch (hint) {
+ case QPlatformTheme::StyleNames:
+ return QStringList(QStringLiteral("fusion"));
+ default:
+ return QPlatformTheme::themeHint(hint);
+ }
+}
+
+const QFont *QIOSTheme::font(Font type) const
+{
+ static QHash<QPlatformTheme::Font, QFont *> fonts;
+ if (fonts.isEmpty()) {
+ // The real system font on iOS is '.Helvetica Neue UI', as returned by both [UIFont systemFontOfSize]
+ // and CTFontCreateUIFontForLanguage(kCTFontSystemFontType, ...), but this font is not included when
+ // populating the available fonts in QCoreTextFontDatabase::populateFontDatabase(), since the font
+ // is internal to iOS and not supposed to be used by applications. We could potentially add this
+ // font to the font-database, but it would then show up when enumerating user fonts from Qt
+ // applications since we don't have a flag in Qt to mark a font as a private system font.
+ // For now we hard-code the font to Helvetica, which should be very close to the actual
+ // system font.
+ QLatin1String systemFontFamilyName("Helvetica");
+ fonts.insert(QPlatformTheme::SystemFont, new QFont(systemFontFamilyName, [UIFont systemFontSize]));
+ fonts.insert(QPlatformTheme::SmallFont, new QFont(systemFontFamilyName, [UIFont smallSystemFontSize]));
+ fonts.insert(QPlatformTheme::LabelFont, new QFont(systemFontFamilyName, [UIFont labelFontSize]));
+ fonts.insert(QPlatformTheme::PushButtonFont, new QFont(systemFontFamilyName, [UIFont buttonFontSize]));
+ }
+
+ return fonts.value(type, 0);
+}
+
+QT_END_NAMESPACE
diff --git a/src/plugins/platforms/ios/qiosviewcontroller.h b/src/plugins/platforms/ios/qiosviewcontroller.h
new file mode 100644
index 0000000000..d5a61cb3f4
--- /dev/null
+++ b/src/plugins/platforms/ios/qiosviewcontroller.h
@@ -0,0 +1,46 @@
+/****************************************************************************
+**
+** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the plugins of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Digia. For licensing terms and
+** conditions see http://qt.digia.com/licensing. For further information
+** use the contact form at http://qt.digia.com/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Digia gives you certain additional
+** rights. These rights are described in the Digia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#import <UIKit/UIKit.h>
+
+@interface QIOSViewController : UIViewController
+@end
+
diff --git a/src/plugins/platforms/ios/qiosviewcontroller.mm b/src/plugins/platforms/ios/qiosviewcontroller.mm
new file mode 100644
index 0000000000..c52bfd7345
--- /dev/null
+++ b/src/plugins/platforms/ios/qiosviewcontroller.mm
@@ -0,0 +1,90 @@
+/****************************************************************************
+**
+** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the plugins of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Digia. For licensing terms and
+** conditions see http://qt.digia.com/licensing. For further information
+** use the contact form at http://qt.digia.com/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Digia gives you certain additional
+** rights. These rights are described in the Digia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#import "qiosviewcontroller.h"
+
+#include <QtGui/QGuiApplication>
+#include <QtGui/QScreen>
+#include "qiosscreen.h"
+#include "qiosglobal.h"
+
+@implementation QIOSViewController
+
+- (void)viewDidLoad
+{
+#ifdef QT_DEBUG
+ if (!self.nibName)
+ self.view.backgroundColor = [UIColor magentaColor];
+#endif
+}
+
+-(BOOL)shouldAutorotate
+{
+ // For now we assume that if the application doesn't listen to orientation
+ // updates it means it would like to enable auto-rotation, and vice versa.
+ if (QGuiApplication *guiApp = qobject_cast<QGuiApplication *>(qApp))
+ return !guiApp->primaryScreen()->orientationUpdateMask();
+ else
+ return YES; // Startup case: QGuiApplication is not ready yet.
+
+ // FIXME: Investigate a proper Qt API for auto-rotation and orientation locking
+}
+
+-(NSUInteger)supportedInterfaceOrientations
+{
+ // We need to tell iOS that we support all orientations in order to set
+ // status bar orientation when application content orientation changes.
+ return UIInterfaceOrientationMaskAll;
+}
+
+- (void)willRotateToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation duration:(NSTimeInterval)duration
+{
+ Q_UNUSED(duration);
+ Qt::ScreenOrientation orientation = toQtScreenOrientation(toInterfaceOrientation);
+ if (orientation == -1)
+ return;
+
+ QIOSScreen *qiosScreen = static_cast<QIOSScreen *>(QGuiApplication::primaryScreen()->handle());
+ qiosScreen->setPrimaryOrientation(orientation);
+}
+
+@end
+
diff --git a/src/plugins/platforms/ios/qioswindow.h b/src/plugins/platforms/ios/qioswindow.h
new file mode 100644
index 0000000000..cefb6f9388
--- /dev/null
+++ b/src/plugins/platforms/ios/qioswindow.h
@@ -0,0 +1,103 @@
+/****************************************************************************
+**
+** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the plugins of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Digia. For licensing terms and
+** conditions see http://qt.digia.com/licensing. For further information
+** use the contact form at http://qt.digia.com/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Digia gives you certain additional
+** rights. These rights are described in the Digia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QIOSWINDOW_H
+#define QIOSWINDOW_H
+
+#include <qpa/qplatformwindow.h>
+#include <qpa/qwindowsysteminterface.h>
+
+#import <UIKit/UIKit.h>
+
+class QIOSContext;
+class QIOSWindow;
+
+@interface UIView (QIOS)
+@property(readonly) QWindow *qwindow;
+@end
+
+QT_BEGIN_NAMESPACE
+
+class QIOSWindow : public QPlatformWindow
+{
+public:
+ explicit QIOSWindow(QWindow *window);
+ ~QIOSWindow();
+
+ void setGeometry(const QRect &rect);
+
+ void setWindowState(Qt::WindowState state);
+ void setParent(const QPlatformWindow *window);
+ void handleContentOrientationChange(Qt::ScreenOrientation orientation);
+ void setVisible(bool visible);
+
+ void raise() { raiseOrLower(true); }
+ void lower() { raiseOrLower(false); }
+ void requestActivateWindow();
+
+ qreal devicePixelRatio() const;
+ int effectiveWidth() const;
+ int effectiveHeight() const;
+
+ WId winId() const { return WId(m_view); };
+
+ QList<QWindowSystemInterface::TouchPoint> &touchPoints() { return m_touchPoints; }
+ QHash<UITouch *, int> &activeTouches() { return m_activeTouches; }
+ int &touchId() { return m_touchId; }
+
+private:
+ UIView *m_view;
+ QList<QWindowSystemInterface::TouchPoint> m_touchPoints;
+ QHash<UITouch *, int> m_activeTouches;
+ int m_touchId;
+
+ QRect m_requestedGeometry;
+ int m_windowLevel;
+ qreal m_devicePixelRatio;
+
+ void raiseOrLower(bool raise);
+ void updateWindowLevel();
+ bool blockedByModal();
+};
+
+QT_END_NAMESPACE
+
+#endif // QIOSWINDOW_H
diff --git a/src/plugins/platforms/ios/qioswindow.mm b/src/plugins/platforms/ios/qioswindow.mm
new file mode 100644
index 0000000000..e4fb5e2e1c
--- /dev/null
+++ b/src/plugins/platforms/ios/qioswindow.mm
@@ -0,0 +1,523 @@
+/****************************************************************************
+**
+** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the plugins of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Digia. For licensing terms and
+** conditions see http://qt.digia.com/licensing. For further information
+** use the contact form at http://qt.digia.com/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Digia gives you certain additional
+** rights. These rights are described in the Digia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qiosglobal.h"
+#include "qioswindow.h"
+#include "qioscontext.h"
+#include "qiosinputcontext.h"
+#include "qiosscreen.h"
+#include "qiosapplicationdelegate.h"
+#include "qiosviewcontroller.h"
+#include "qiosintegration.h"
+#include <QtGui/private/qguiapplication_p.h>
+#include <qpa/qplatformintegration.h>
+
+#import <QuartzCore/CAEAGLLayer.h>
+
+#include <QtGui/QKeyEvent>
+#include <qpa/qwindowsysteminterface.h>
+
+#include <QtDebug>
+
+@interface EAGLView : UIView <UIKeyInput>
+{
+@public
+ UITextAutocapitalizationType autocapitalizationType;
+ UITextAutocorrectionType autocorrectionType;
+ BOOL enablesReturnKeyAutomatically;
+ UIKeyboardAppearance keyboardAppearance;
+ UIKeyboardType keyboardType;
+ UIReturnKeyType returnKeyType;
+ BOOL secureTextEntry;
+ QIOSWindow *m_qioswindow;
+}
+
+@property(nonatomic) UITextAutocapitalizationType autocapitalizationType;
+@property(nonatomic) UITextAutocorrectionType autocorrectionType;
+@property(nonatomic) BOOL enablesReturnKeyAutomatically;
+@property(nonatomic) UIKeyboardAppearance keyboardAppearance;
+@property(nonatomic) UIKeyboardType keyboardType;
+@property(nonatomic) UIReturnKeyType returnKeyType;
+@property(nonatomic, getter=isSecureTextEntry) BOOL secureTextEntry;
+
+@end
+
+@implementation EAGLView
+
++ (Class)layerClass
+{
+ return [CAEAGLLayer class];
+}
+
+-(id)initWithQIOSWindow:(QIOSWindow *)window
+{
+ if (self = [self initWithFrame:toCGRect(window->geometry())])
+ m_qioswindow = window;
+
+ return self;
+}
+
+- (id)initWithFrame:(CGRect)frame
+{
+ if ((self = [super initWithFrame:frame])) {
+ // Set up EAGL layer
+ CAEAGLLayer *eaglLayer = static_cast<CAEAGLLayer *>(self.layer);
+ eaglLayer.opaque = TRUE;
+ eaglLayer.drawableProperties = [NSDictionary dictionaryWithObjectsAndKeys:
+ [NSNumber numberWithBool:YES], kEAGLDrawablePropertyRetainedBacking,
+ kEAGLColorFormatRGBA8, kEAGLDrawablePropertyColorFormat, nil];
+
+ // Set up text input
+ autocapitalizationType = UITextAutocapitalizationTypeNone;
+ autocorrectionType = UITextAutocorrectionTypeNo;
+ enablesReturnKeyAutomatically = NO;
+ keyboardAppearance = UIKeyboardAppearanceDefault;
+ keyboardType = UIKeyboardTypeDefault;
+ returnKeyType = UIReturnKeyDone;
+ secureTextEntry = NO;
+
+ if (isQtApplication())
+ self.hidden = YES;
+
+ self.multipleTouchEnabled = YES;
+ }
+
+ return self;
+}
+
+- (void)layoutSubviews
+{
+ // This method is the de facto way to know that view has been resized,
+ // or otherwise needs invalidation of its buffers. Note though that we
+ // do not get this callback when the view just changes its position, so
+ // the position of our QWindow (and platform window) will only get updated
+ // when the size is also changed.
+
+ if (!CGAffineTransformIsIdentity(self.transform))
+ qWarning() << m_qioswindow->window()
+ << "is backed by a UIView that has a transform set. This is not supported.";
+
+ QRect geometry = fromCGRect(self.frame);
+ m_qioswindow->QPlatformWindow::setGeometry(geometry);
+ QWindowSystemInterface::handleGeometryChange(m_qioswindow->window(), geometry);
+
+ // If we have a new size here we need to resize the FBO's corresponding buffers,
+ // but we defer that to when the application calls makeCurrent.
+
+ [super layoutSubviews];
+}
+
+/*
+ Touch handling:
+
+ UIKit generates [Began -> Moved -> Ended] event sequences for
+ each touch point. The iOS plugin tracks each individual
+ touch and assigns it an id for use by Qt. The id counter is
+ incremented on each began and decrement as follows:
+ 1) by one when the most recent touch ends.
+ 2) to zero when all touches ends.
+
+ The TouchPoint list is reused between events.
+*/
+- (void)updateTouchList:(NSSet *)touches withState:(Qt::TouchPointState)state
+{
+ QList<QWindowSystemInterface::TouchPoint> &touchPoints = m_qioswindow->touchPoints();
+ QHash<UITouch *, int> &activeTouches = m_qioswindow->activeTouches();
+
+ // Mark all touch points as stationary
+ for (QList<QWindowSystemInterface::TouchPoint>::iterator it = touchPoints.begin(); it != touchPoints.end(); ++it)
+ it->state = Qt::TouchPointStationary;
+
+ // Update changed touch points with the new state
+ for (UITouch *touch in touches) {
+ const int touchId = activeTouches.value(touch);
+ QWindowSystemInterface::TouchPoint &touchPoint = touchPoints[touchId];
+ touchPoint.state = state;
+ if (state == Qt::TouchPointPressed)
+ touchPoint.pressure = 1.0;
+ else if (state == Qt::TouchPointReleased)
+ touchPoint.pressure = 0.0;
+
+ // Set position
+ QRect viewGeometry = fromCGRect(self.frame);
+ QPoint touchViewLocation = fromCGPoint([touch locationInView:self]);
+ QPoint touchScreenLocation = touchViewLocation + viewGeometry.topLeft();
+ touchPoint.area = QRectF(touchScreenLocation , QSize(0, 0));
+
+ CGSize fullscreenSize = self.window.rootViewController.view.bounds.size;
+ touchPoint.normalPosition = QPointF(touchScreenLocation.x() / fullscreenSize.width, touchScreenLocation.y() / fullscreenSize.height);
+ }
+}
+
+- (void) sendTouchEventWithTimestamp:(ulong)timeStamp
+{
+ // Send touch event synchronously
+ QIOSIntegration *iosIntegration = static_cast<QIOSIntegration *>(QGuiApplicationPrivate::platformIntegration());
+ QWindowSystemInterface::handleTouchEvent(m_qioswindow->window(), timeStamp,
+ iosIntegration->touchDevice(), m_qioswindow->touchPoints());
+ QWindowSystemInterface::flushWindowSystemEvents();
+}
+
+- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
+{
+ QWindow *window = m_qioswindow->window();
+
+ // Transfer focus to the touched window:
+ if (window != QGuiApplication::focusWindow())
+ m_qioswindow->requestActivateWindow();
+
+ // Track Cocoa touch id to Qt touch id. The UITouch pointer is constant
+ // for the touch duration.
+ QHash<UITouch *, int> &activeTouches = m_qioswindow->activeTouches();
+ QList<QWindowSystemInterface::TouchPoint> &touchPoints = m_qioswindow->touchPoints();
+ for (UITouch *touch in touches)
+ activeTouches.insert(touch, m_qioswindow->touchId()++);
+
+ // Create new touch points if needed.
+ int newTouchPointsNeeded = m_qioswindow->touchId() - touchPoints.count();
+ for (int i = 0; i < newTouchPointsNeeded; ++i) {
+ QWindowSystemInterface::TouchPoint touchPoint;
+ touchPoint.id = touchPoints.count(); // id is the index in the touchPoints list.
+ touchPoints.append(touchPoint);
+ }
+
+ [self updateTouchList:touches withState:Qt::TouchPointPressed];
+ [self sendTouchEventWithTimestamp:ulong(event.timestamp * 1000)];
+}
+
+- (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event
+{
+ [self updateTouchList:touches withState:Qt::TouchPointMoved];
+ [self sendTouchEventWithTimestamp:ulong(event.timestamp * 1000)];
+}
+
+- (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event
+{
+ [self updateTouchList:touches withState:Qt::TouchPointReleased];
+ [self sendTouchEventWithTimestamp:ulong(event.timestamp * 1000)];
+
+ // Remove ended touch points from the active set (event processing has completed at this point)
+ QHash<UITouch *, int> &activeTouches = m_qioswindow->activeTouches();
+ for (UITouch *touch in touches) {
+ int id = activeTouches.take(touch);
+
+ // If this touch is the most recent touch we can reuse its id
+ if (id == m_qioswindow->touchId() - 1)
+ --m_qioswindow->touchId();
+ }
+
+ // Reset the touch id when there are no more active touches
+ if (activeTouches.isEmpty())
+ m_qioswindow->touchId() = 0;
+}
+
+- (void)touchesCancelled:(NSSet *)touches withEvent:(UIEvent *)event
+{
+ Q_UNUSED(touches) // ### can a subset of the active touches be cancelled?
+
+ // Clear current touch points
+ m_qioswindow->activeTouches().clear();
+ m_qioswindow->touchId() = 0;
+
+ // Send cancel touch event synchronously
+ QIOSIntegration *iosIntegration = static_cast<QIOSIntegration *>(QGuiApplicationPrivate::platformIntegration());
+ QWindowSystemInterface::handleTouchCancelEvent(m_qioswindow->window(), ulong(event.timestamp * 1000), iosIntegration->touchDevice());
+ QWindowSystemInterface::flushWindowSystemEvents();
+}
+
+@synthesize autocapitalizationType;
+@synthesize autocorrectionType;
+@synthesize enablesReturnKeyAutomatically;
+@synthesize keyboardAppearance;
+@synthesize keyboardType;
+@synthesize returnKeyType;
+@synthesize secureTextEntry;
+
+- (BOOL)canBecomeFirstResponder
+{
+ return YES;
+}
+
+- (BOOL)hasText
+{
+ return YES;
+}
+
+- (void)insertText:(NSString *)text
+{
+ QString string = QString::fromUtf8([text UTF8String]);
+ int key = 0;
+ if ([text isEqualToString:@"\n"])
+ key = (int)Qt::Key_Return;
+
+ // Send key event to window system interface
+ QWindowSystemInterface::handleKeyEvent(
+ 0, QEvent::KeyPress, key, Qt::NoModifier, string, false, int(string.length()));
+ QWindowSystemInterface::handleKeyEvent(
+ 0, QEvent::KeyRelease, key, Qt::NoModifier, string, false, int(string.length()));
+}
+
+- (void)deleteBackward
+{
+ // Send key event to window system interface
+ QWindowSystemInterface::handleKeyEvent(
+ 0, QEvent::KeyPress, (int)Qt::Key_Backspace, Qt::NoModifier);
+ QWindowSystemInterface::handleKeyEvent(
+ 0, QEvent::KeyRelease, (int)Qt::Key_Backspace, Qt::NoModifier);
+}
+
+@end
+
+@implementation UIView (QIOS)
+
+- (QWindow *)qwindow
+{
+ if ([self isKindOfClass:[EAGLView class]])
+ return static_cast<EAGLView *>(self)->m_qioswindow->window();
+ return nil;
+}
+
+@end
+
+QT_BEGIN_NAMESPACE
+
+QIOSWindow::QIOSWindow(QWindow *window)
+ : QPlatformWindow(window)
+ , m_view([[EAGLView alloc] initWithQIOSWindow:this])
+ , m_touchId(0)
+ , m_requestedGeometry(QPlatformWindow::geometry())
+ , m_windowLevel(0)
+ , m_devicePixelRatio(1.0)
+{
+ setParent(parent());
+ setWindowState(window->windowState());
+
+ // Retina support: get screen scale factor and set it in the content view.
+ // This will make framebufferObject() create a 2x frame buffer on retina
+ // displays. Also set m_devicePixelRatio which is used for scaling the
+ // paint device.
+ if ([[UIScreen mainScreen] respondsToSelector:@selector(scale)] == YES) {
+ m_devicePixelRatio = [[UIScreen mainScreen] scale];
+ [m_view setContentScaleFactor: m_devicePixelRatio];
+ }
+}
+
+QIOSWindow::~QIOSWindow()
+{
+ [m_view removeFromSuperview];
+ [m_view release];
+}
+
+bool QIOSWindow::blockedByModal()
+{
+ QWindow *modalWindow = QGuiApplication::modalWindow();
+ return modalWindow && modalWindow != window();
+}
+
+void QIOSWindow::setVisible(bool visible)
+{
+ QPlatformWindow::setVisible(visible);
+ m_view.hidden = !visible;
+
+ if (!isQtApplication())
+ return;
+
+ // Since iOS doesn't do window management the way a Qt application
+ // expects, we need to raise and activate windows ourselves:
+ if (visible)
+ updateWindowLevel();
+
+ if (blockedByModal()) {
+ if (visible)
+ raise();
+ return;
+ }
+
+ if (visible) {
+ requestActivateWindow();
+ } else {
+ // Activate top-most visible QWindow:
+ NSArray *subviews = rootViewController().view.subviews;
+ for (int i = int(subviews.count) - 1; i >= 0; --i) {
+ UIView *view = [subviews objectAtIndex:i];
+ if (!view.hidden) {
+ if (QWindow *window = view.qwindow) {
+ static_cast<QIOSWindow *>(window->handle())->requestActivateWindow();
+ break;
+ }
+ }
+ }
+ }
+}
+
+void QIOSWindow::setGeometry(const QRect &rect)
+{
+ // If the window is in fullscreen, just bookkeep the requested
+ // geometry in case the window goes into Qt::WindowNoState later:
+ m_requestedGeometry = rect;
+ if (window()->windowState() & (Qt::WindowMaximized | Qt::WindowFullScreen))
+ return;
+
+ // Since we don't support transformations on the UIView, we can set the frame
+ // directly and let UIKit deal with translating that into bounds and center.
+ // Changing the size of the view will end up in a call to -[EAGLView layoutSubviews]
+ // which will update QWindowSystemInterface with the new size.
+ m_view.frame = toCGRect(rect);
+}
+
+void QIOSWindow::setWindowState(Qt::WindowState state)
+{
+ // FIXME: Figure out where or how we should disable/enable the statusbar.
+ // Perhaps setting QWindow to maximized should also mean that we'll show
+ // the statusbar, and vice versa for fullscreen?
+
+ switch (state) {
+ case Qt::WindowMaximized:
+ case Qt::WindowFullScreen: {
+ // Since UIScreen does not take orientation into account when
+ // reporting geometry, we need to look at the top view instead:
+ CGSize fullscreenSize = m_view.window.rootViewController.view.bounds.size;
+ m_view.frame = CGRectMake(0, 0, fullscreenSize.width, fullscreenSize.height);
+ m_view.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight;
+ break; }
+ default:
+ m_view.frame = toCGRect(m_requestedGeometry);
+ m_view.autoresizingMask = UIViewAutoresizingNone;
+ break;
+ }
+}
+
+void QIOSWindow::setParent(const QPlatformWindow *parentWindow)
+{
+ if (parentWindow) {
+ UIView *parentView = reinterpret_cast<UIView *>(parentWindow->winId());
+ [parentView addSubview:m_view];
+ } else if (isQtApplication()) {
+ [rootViewController().view addSubview:m_view];
+ }
+}
+
+void QIOSWindow::requestActivateWindow()
+{
+ // Note that several windows can be active at the same time if they exist in the same
+ // hierarchy (transient children). But only one window can be QGuiApplication::focusWindow().
+ // Dispite the name, 'requestActivateWindow' means raise and transfer focus to the window:
+ if (blockedByModal())
+ return;
+
+ raise();
+ QPlatformInputContext *context = QGuiApplicationPrivate::platformIntegration()->inputContext();
+ static_cast<QIOSInputContext *>(context)->focusViewChanged(m_view);
+ QPlatformWindow::requestActivateWindow();
+}
+
+void QIOSWindow::raiseOrLower(bool raise)
+{
+ // Re-insert m_view at the correct index among its sibling views
+ // (QWindows) according to their current m_windowLevel:
+ if (!isQtApplication())
+ return;
+
+ NSArray *subviews = m_view.superview.subviews;
+ if (subviews.count == 1)
+ return;
+
+ for (int i = int(subviews.count) - 1; i >= 0; --i) {
+ UIView *view = static_cast<UIView *>([subviews objectAtIndex:i]);
+ if (view.hidden || view == m_view)
+ continue;
+ int level = static_cast<QIOSWindow *>(view.qwindow->handle())->m_windowLevel;
+ if (m_windowLevel > level || (raise && m_windowLevel == level)) {
+ [m_view.superview insertSubview:m_view aboveSubview:view];
+ return;
+ }
+ }
+ [m_view.superview insertSubview:m_view atIndex:0];
+}
+
+void QIOSWindow::updateWindowLevel()
+{
+ Qt::WindowType type = static_cast<Qt::WindowType>(int(window()->flags() & Qt::WindowType_Mask));
+
+ if (type == Qt::ToolTip)
+ m_windowLevel = 120;
+ else if (window()->flags() & Qt::WindowStaysOnTopHint)
+ m_windowLevel = 100;
+ else if (window()->isModal())
+ m_windowLevel = 30;
+ else if (type & Qt::Popup & ~Qt::Window)
+ m_windowLevel = 20;
+ else if (type == Qt::Tool)
+ m_windowLevel = 10;
+ else
+ m_windowLevel = 0;
+
+ // A window should be in at least the same m_windowLevel as its parent:
+ QWindow *transientParent = window()->transientParent();
+ QIOSWindow *transientParentWindow = transientParent ? static_cast<QIOSWindow *>(transientParent->handle()) : 0;
+ if (transientParentWindow)
+ m_windowLevel = qMax(transientParentWindow->m_windowLevel, m_windowLevel);
+}
+
+void QIOSWindow::handleContentOrientationChange(Qt::ScreenOrientation orientation)
+{
+ // Keep the status bar in sync with content orientation. This will ensure
+ // that the task bar (and associated gestures) are aligned correctly:
+ UIDeviceOrientation uiOrientation = fromQtScreenOrientation(orientation);
+ [[UIApplication sharedApplication] setStatusBarOrientation:uiOrientation animated:NO];
+}
+
+qreal QIOSWindow::devicePixelRatio() const
+{
+ return m_devicePixelRatio;
+}
+
+int QIOSWindow::effectiveWidth() const
+{
+ return geometry().width() * m_devicePixelRatio;
+}
+
+int QIOSWindow::effectiveHeight() const
+{
+ return geometry().height() * m_devicePixelRatio;
+}
+
+QT_END_NAMESPACE
diff --git a/src/plugins/platforms/ios/qtmain.mm b/src/plugins/platforms/ios/qtmain.mm
new file mode 100644
index 0000000000..916224f936
--- /dev/null
+++ b/src/plugins/platforms/ios/qtmain.mm
@@ -0,0 +1,93 @@
+/****************************************************************************
+**
+** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the plugins of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Digia. For licensing terms and
+** conditions see http://qt.digia.com/licensing. For further information
+** use the contact form at http://qt.digia.com/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Digia gives you certain additional
+** rights. These rights are described in the Digia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qiosapplicationdelegate.h"
+#include "qiosviewcontroller.h"
+
+int main(int argc, char *argv[])
+{
+ @autoreleasepool {
+ return UIApplicationMain(argc, argv, nil, NSStringFromClass([QIOSMainWrapperApplicationDelegate class]));
+ }
+}
+
+extern int qt_main(int argc, char *argv[]);
+
+@implementation QIOSMainWrapperApplicationDelegate
+
+- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
+{
+ self.window = [[[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]] autorelease];
+ self.window.rootViewController = [[[QIOSViewController alloc] init] autorelease];
+
+#ifdef QT_DEBUG
+ self.window.backgroundColor = [UIColor cyanColor];
+#endif
+
+ [self.window makeKeyAndVisible];
+
+ // We schedule the main-redirection for the next eventloop pass so that we
+ // can return from this function and let UIApplicationMain finish its job.
+ [NSTimer scheduledTimerWithTimeInterval:.01f target:self
+ selector:@selector(runUserMain) userInfo:nil repeats:NO];
+
+ if ([QIOSApplicationDelegate instancesRespondToSelector:_cmd])
+ return [super application:application didFinishLaunchingWithOptions:launchOptions];
+ else
+ return YES;
+}
+
+- (void)runUserMain
+{
+ NSArray *arguments = [[NSProcessInfo processInfo] arguments];
+ int argc = arguments.count;
+ char **argv = new char*[argc];
+ for (int i = 0; i < argc; ++i) {
+ NSString *arg = [arguments objectAtIndex:i];
+ argv[i] = reinterpret_cast<char *>(malloc([arg lengthOfBytesUsingEncoding:[NSString defaultCStringEncoding]]));
+ strcpy(argv[i], [arg cStringUsingEncoding:[NSString defaultCStringEncoding]]);
+ }
+
+ qt_main(argc, argv);
+ delete[] argv;
+}
+
+@end
diff --git a/src/plugins/platforms/ios/qtmain.pro b/src/plugins/platforms/ios/qtmain.pro
new file mode 100644
index 0000000000..cbcb272217
--- /dev/null
+++ b/src/plugins/platforms/ios/qtmain.pro
@@ -0,0 +1,8 @@
+TARGET = qiosmain
+
+PLUGIN_TYPE = platforms
+load(qt_plugin)
+
+QT += gui-private
+
+OBJECTIVE_SOURCES = qtmain.mm
diff --git a/src/plugins/platforms/kms/kms.pro b/src/plugins/platforms/kms/kms.pro
index c0300e0960..711cf9e5c7 100644
--- a/src/plugins/platforms/kms/kms.pro
+++ b/src/plugins/platforms/kms/kms.pro
@@ -4,9 +4,10 @@ PLUGIN_TYPE = platforms
PLUGIN_CLASS_NAME = QKmsIntegrationPlugin
load(qt_plugin)
-QT += core-private gui-private platformsupport-private opengl-private
+QT += core-private gui-private platformsupport-private
+qtHaveModule(opengl):QT += opengl-private
-DEFINES += MESA_EGL_NO_X11_HEADERS
+DEFINES += MESA_EGL_NO_X11_HEADERS __GBM__
CONFIG += link_pkgconfig egl qpa/genericunixfontdatabase
diff --git a/src/plugins/platforms/kms/qkmscursor.cpp b/src/plugins/platforms/kms/qkmscursor.cpp
index d9345ce89b..da5dc9bb06 100644
--- a/src/plugins/platforms/kms/qkmscursor.cpp
+++ b/src/plugins/platforms/kms/qkmscursor.cpp
@@ -48,22 +48,17 @@ QT_BEGIN_NAMESPACE
QKmsCursor::QKmsCursor(QKmsScreen *screen)
: m_screen(screen),
m_graphicsBufferManager(screen->device()->gbmDevice()),
+ m_cursorBufferObject(gbm_bo_create(m_graphicsBufferManager, 64, 64, GBM_FORMAT_ARGB8888,
+ GBM_BO_USE_CURSOR_64X64|GBM_BO_USE_WRITE)),
+ m_cursorImage(new QPlatformCursorImage(0, 0, 0, 0, 0, 0)),
m_moved(false)
{
- gbm_bo *bo = gbm_bo_create(m_graphicsBufferManager, 64, 64,
- GBM_BO_FORMAT_ARGB8888,
- GBM_BO_USE_CURSOR_64X64 | GBM_BO_USE_RENDERING);
-
- m_eglImage = eglCreateImageKHR(m_screen->device()->eglDisplay(), 0, EGL_NATIVE_PIXMAP_KHR,
- bo, 0);
- gbm_bo_destroy(bo);
- m_cursorImage = new QPlatformCursorImage(0, 0, 0, 0, 0, 0);
}
QKmsCursor::~QKmsCursor()
{
- drmModeSetCursor(m_screen->device()->fd(), m_screen->crtcId(),
- 0, 0, 0);
+ drmModeSetCursor(m_screen->device()->fd(), m_screen->crtcId(), 0, 0, 0);
+ gbm_bo_destroy(m_cursorBufferObject);
}
void QKmsCursor::pointerEvent(const QMouseEvent &event)
@@ -78,57 +73,30 @@ void QKmsCursor::pointerEvent(const QMouseEvent &event)
}
}
-void QKmsCursor::changeCursor(QCursor *widgetCursor, QWindow *window)
+void QKmsCursor::changeCursor(QCursor *windowCursor, QWindow *window)
{
Q_UNUSED(window)
if (!m_moved)
drmModeMoveCursor(m_screen->device()->fd(), m_screen->crtcId(), 0, 0);
- if (widgetCursor->shape() != Qt::BitmapCursor) {
- m_cursorImage->set(widgetCursor->shape());
- } else {
- m_cursorImage->set(widgetCursor->pixmap().toImage(),
- widgetCursor->hotSpot().x(),
- widgetCursor->hotSpot().y());
- }
-
- if ((m_cursorImage->image()->width() > 64) || (m_cursorImage->image()->width() > 64)) {
- qWarning("failed to set hardware cursor: larger than 64x64.");
- return;
- }
-
- QImage cursorImage = m_cursorImage->image()->convertToFormat(QImage::Format_RGB32);
-
- //Load cursor image into EGLImage
- GLuint cursorTexture;
- glGenTextures(1, &cursorTexture);
- glBindTexture(GL_TEXTURE_2D, cursorTexture);
- glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
- glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
- glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
- glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
-
-
- //TODO: Format may be wrong here, need a color icon to test.
- if (m_eglImage != EGL_NO_IMAGE_KHR) {
- glEGLImageTargetTexture2DOES(GL_TEXTURE_2D, m_eglImage);
- glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, cursorImage.width(),
- cursorImage.height(), GL_RGBA,
- GL_UNSIGNED_BYTE, cursorImage.constBits());
+ const Qt::CursorShape newShape = windowCursor ? windowCursor->shape() : Qt::ArrowCursor;
+ if (newShape != Qt::BitmapCursor) {
+ m_cursorImage->set(newShape);
} else {
- glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, cursorImage.width(),
- cursorImage.height(), 0, GL_RGBA,
- GL_UNSIGNED_BYTE, cursorImage.constBits());
+ m_cursorImage->set(windowCursor->pixmap().toImage(),
+ windowCursor->hotSpot().x(),
+ windowCursor->hotSpot().y());
}
- //EGLImage needs to contain sprite before calling this:
- gbm_bo *bufferObject = gbm_bo_import(m_graphicsBufferManager, GBM_BO_IMPORT_EGL_IMAGE,
- m_eglImage, GBM_BO_USE_CURSOR_64X64);
- quint32 handle = gbm_bo_get_handle(bufferObject).u32;
+ if ((m_cursorImage->image()->width() > 64) || (m_cursorImage->image()->width() > 64))
+ qWarning("Warning: cursor larger than 64x64; only 64x64 pixels will be shown.");
- gbm_bo_destroy(bufferObject);
+ QImage cursorImage = m_cursorImage->image()->
+ convertToFormat(QImage::Format_ARGB32).copy(0, 0, 64, 64);
+ gbm_bo_write(m_cursorBufferObject, cursorImage.constBits(), cursorImage.byteCount());
+ quint32 handle = gbm_bo_get_handle(m_cursorBufferObject).u32;
int status = drmModeSetCursor(m_screen->device()->fd(),
m_screen->crtcId(), handle, 64, 64);
diff --git a/src/plugins/platforms/kms/qkmscursor.h b/src/plugins/platforms/kms/qkmscursor.h
index fda47ebedc..ee65b01e36 100644
--- a/src/plugins/platforms/kms/qkmscursor.h
+++ b/src/plugins/platforms/kms/qkmscursor.h
@@ -44,15 +44,11 @@
#include <qpa/qplatformcursor.h>
-#define EGL_EGLEXT_PROTOTYPES 1
-
-#include <EGL/egl.h>
-#include <EGL/eglext.h>
-
QT_BEGIN_NAMESPACE
class QKmsScreen;
class gbm_device;
+class gbm_bo;
class QKmsCursor : public QPlatformCursor
{
@@ -61,12 +57,12 @@ public:
~QKmsCursor();
void pointerEvent(const QMouseEvent &event);
- void changeCursor(QCursor *widgetCursor, QWindow *window);
+ void changeCursor(QCursor *windowCursor, QWindow *window);
private:
QKmsScreen *m_screen;
gbm_device *m_graphicsBufferManager;
- EGLImageKHR m_eglImage;
+ gbm_bo *m_cursorBufferObject;
QPlatformCursorImage *m_cursorImage;
bool m_moved;
};
diff --git a/src/plugins/platforms/kms/qkmsscreen.cpp b/src/plugins/platforms/kms/qkmsscreen.cpp
index 123dcc283f..892f7bb01f 100644
--- a/src/plugins/platforms/kms/qkmsscreen.cpp
+++ b/src/plugins/platforms/kms/qkmsscreen.cpp
@@ -124,10 +124,14 @@ void QKmsScreen::initializeScreenMode()
drmModeConnector *connector = drmModeGetConnector(m_device->fd(), m_connectorId);
drmModeModeInfo *mode = 0;
- if (connector->count_modes > 0)
- mode = &connector->modes[0];
- else
- mode = &builtin_1024x768;
+ for (int i = 0; i < connector->count_modes; ++i) {
+ if (connector->modes[i].type & DRM_MODE_TYPE_PREFERRED) {
+ mode = &connector->modes[i];
+ break;
+ }
+ }
+ if (!mode)
+ mode = mode = &builtin_1024x768;
drmModeEncoder *encoder = drmModeGetEncoder(m_device->fd(), connector->encoders[0]);
if (encoder == 0)
diff --git a/src/plugins/platforms/minimalegl/qminimaleglbackingstore.cpp b/src/plugins/platforms/minimalegl/qminimaleglbackingstore.cpp
index da89100359..cb245f2e5c 100644
--- a/src/plugins/platforms/minimalegl/qminimaleglbackingstore.cpp
+++ b/src/plugins/platforms/minimalegl/qminimaleglbackingstore.cpp
@@ -49,6 +49,7 @@ QT_BEGIN_NAMESPACE
QMinimalEglBackingStore::QMinimalEglBackingStore(QWindow *window)
: QPlatformBackingStore(window)
, m_context(new QOpenGLContext)
+ , m_device(0)
{
m_context->setFormat(window->requestedFormat());
m_context->setScreen(window->screen());
diff --git a/src/plugins/platforms/minimalegl/qminimaleglintegration.h b/src/plugins/platforms/minimalegl/qminimaleglintegration.h
index fb86c967e1..dba7504033 100644
--- a/src/plugins/platforms/minimalegl/qminimaleglintegration.h
+++ b/src/plugins/platforms/minimalegl/qminimaleglintegration.h
@@ -47,8 +47,6 @@
#include <qpa/qplatformintegration.h>
#include <qpa/qplatformscreen.h>
-QT_BEGIN_HEADER
-
QT_BEGIN_NAMESPACE
class QMinimalEglIntegration : public QPlatformIntegration
@@ -75,6 +73,5 @@ private:
};
QT_END_NAMESPACE
-QT_END_HEADER
#endif // QMINIMALEGLINTEGRATION_H
diff --git a/src/plugins/platforms/offscreen/main.cpp b/src/plugins/platforms/offscreen/main.cpp
new file mode 100644
index 0000000000..ca7dc1d18b
--- /dev/null
+++ b/src/plugins/platforms/offscreen/main.cpp
@@ -0,0 +1,67 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 Digia Plc and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the plugins of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Digia. For licensing terms and
+** conditions see http://qt.digia.com/licensing. For further information
+** use the contact form at http://qt.digia.com/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Digia gives you certain additional
+** rights. These rights are described in the Digia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+
+#include <qpa/qplatformintegrationplugin.h>
+#include "qoffscreenintegration.h"
+
+QT_BEGIN_NAMESPACE
+
+class QOffscreenIntegrationPlugin : public QPlatformIntegrationPlugin
+{
+ Q_OBJECT
+ Q_PLUGIN_METADATA(IID "org.qt-project.Qt.QPA.QPlatformIntegrationFactoryInterface.5.1" FILE "offscreen.json")
+public:
+ QPlatformIntegration *create(const QString&, const QStringList&);
+};
+
+QPlatformIntegration *QOffscreenIntegrationPlugin::create(const QString& system, const QStringList& paramList)
+{
+ Q_UNUSED(paramList);
+ if (system.toLower() == "offscreen")
+ return QOffscreenIntegration::createOffscreenIntegration();
+
+ return 0;
+}
+
+QT_END_NAMESPACE
+
+#include "main.moc"
diff --git a/src/plugins/platforms/offscreen/offscreen.json b/src/plugins/platforms/offscreen/offscreen.json
new file mode 100644
index 0000000000..6e87744de0
--- /dev/null
+++ b/src/plugins/platforms/offscreen/offscreen.json
@@ -0,0 +1,3 @@
+{
+ "Keys": [ "offscreen" ]
+}
diff --git a/src/plugins/platforms/offscreen/offscreen.pro b/src/plugins/platforms/offscreen/offscreen.pro
new file mode 100644
index 0000000000..270e3ce228
--- /dev/null
+++ b/src/plugins/platforms/offscreen/offscreen.pro
@@ -0,0 +1,25 @@
+TARGET = qoffscreen
+
+PLUGIN_TYPE = platforms
+load(qt_plugin)
+
+QT += core-private gui-private platformsupport-private
+
+SOURCES = main.cpp \
+ qoffscreenintegration.cpp \
+ qoffscreenwindow.cpp \
+ qoffscreencommon.cpp
+
+HEADERS = qoffscreenintegration.h \
+ qoffscreenwindow.h \
+ qoffscreencommon.h
+
+OTHER_FILES += offscreen.json
+
+contains(QT_CONFIG, xcb):contains(QT_CONFIG, opengl):!contains(QT_CONFIG, opengles2) {
+ SOURCES += qoffscreenintegration_x11.cpp
+ HEADERS += qoffscreenintegration_x11.h
+ system(echo "Using X11 offscreen integration with GLX")
+} else {
+ SOURCES += qoffscreenintegration_dummy.cpp
+}
diff --git a/src/plugins/platforms/offscreen/qoffscreencommon.cpp b/src/plugins/platforms/offscreen/qoffscreencommon.cpp
new file mode 100644
index 0000000000..069b20693d
--- /dev/null
+++ b/src/plugins/platforms/offscreen/qoffscreencommon.cpp
@@ -0,0 +1,229 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 Digia Plc and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the plugins of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Digia. For licensing terms and
+** conditions see http://qt.digia.com/licensing. For further information
+** use the contact form at http://qt.digia.com/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Digia gives you certain additional
+** rights. These rights are described in the Digia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qoffscreencommon.h"
+#include "qoffscreenwindow.h"
+
+#include <QtGui/private/qpixmap_raster_p.h>
+#include <QtGui/private/qguiapplication_p.h>
+
+#include <qpa/qplatformcursor.h>
+#include <qpa/qplatformwindow.h>
+
+QT_BEGIN_NAMESPACE
+
+QPlatformWindow *QOffscreenScreen::windowContainingCursor = 0;
+
+class QOffscreenCursor : public QPlatformCursor
+{
+public:
+ QOffscreenCursor() : m_pos(10, 10) {}
+
+ QPoint pos() const { return m_pos; }
+ void setPos(const QPoint &pos)
+ {
+ m_pos = pos;
+ QWindowList wl = QGuiApplication::topLevelWindows();
+ QWindow *containing = 0;
+ foreach (QWindow *w, wl) {
+ if (w->type() != Qt::Desktop && w->isExposed() && w->geometry().contains(pos)) {
+ containing = w;
+ break;
+ }
+ }
+
+ QPoint local = pos;
+ if (containing)
+ local -= containing->position();
+
+ QWindow *previous = QOffscreenScreen::windowContainingCursor ? QOffscreenScreen::windowContainingCursor->window() : 0;
+
+ if (containing != previous)
+ QWindowSystemInterface::handleEnterLeaveEvent(containing, previous, local, pos);
+
+ QWindowSystemInterface::handleMouseEvent(containing, local, pos, QGuiApplication::mouseButtons(), QGuiApplication::keyboardModifiers());
+
+ QOffscreenScreen::windowContainingCursor = containing ? containing->handle() : 0;
+ }
+
+ void changeCursor(QCursor *windowCursor, QWindow *window)
+ {
+ Q_UNUSED(windowCursor);
+ Q_UNUSED(window);
+ }
+
+private:
+ QPoint m_pos;
+};
+
+QOffscreenScreen::QOffscreenScreen()
+ : m_geometry(0, 0, 800, 600)
+ , m_cursor(new QOffscreenCursor)
+{
+}
+
+QPixmap QOffscreenScreen::grabWindow(WId id, int x, int y, int width, int height) const
+{
+ QRect rect(x, y, width, height);
+
+ QOffscreenWindow *window = QOffscreenWindow::windowForWinId(id);
+ if (!window || window->window()->type() == Qt::Desktop) {
+ QWindowList wl = QGuiApplication::topLevelWindows();
+ QWindow *containing = 0;
+ foreach (QWindow *w, wl) {
+ if (w->type() != Qt::Desktop && w->isExposed() && w->geometry().contains(rect)) {
+ containing = w;
+ break;
+ }
+ }
+
+ if (!containing)
+ return QPixmap();
+
+ id = containing->winId();
+ rect = rect.translated(-containing->geometry().topLeft());
+ }
+
+ QOffscreenBackingStore *store = QOffscreenBackingStore::backingStoreForWinId(id);
+ if (store)
+ return store->grabWindow(id, rect);
+ return QPixmap();
+}
+
+QOffscreenBackingStore::QOffscreenBackingStore(QWindow *window)
+ : QPlatformBackingStore(window)
+{
+}
+
+QOffscreenBackingStore::~QOffscreenBackingStore()
+{
+ clearHash();
+}
+
+QPaintDevice *QOffscreenBackingStore::paintDevice()
+{
+ return &m_image;
+}
+
+void QOffscreenBackingStore::flush(QWindow *window, const QRegion &region, const QPoint &offset)
+{
+ Q_UNUSED(region);
+
+ if (m_image.size().isEmpty())
+ return;
+
+ QSize imageSize = m_image.size();
+
+ QRegion clipped = QRect(0, 0, window->width(), window->height());
+ clipped &= QRect(0, 0, imageSize.width(), imageSize.height()).translated(-offset);
+
+ QRect bounds = clipped.boundingRect().translated(offset);
+
+ if (bounds.isNull())
+ return;
+
+ WId id = window->winId();
+
+ m_windowAreaHash[id] = bounds;
+ m_backingStoreForWinIdHash[id] = this;
+}
+
+void QOffscreenBackingStore::resize(const QSize &size, const QRegion &)
+{
+ QImage::Format format = QGuiApplication::primaryScreen()->handle()->format();
+ if (m_image.size() != size)
+ m_image = QImage(size, format);
+ clearHash();
+}
+
+extern void qt_scrollRectInImage(QImage &img, const QRect &rect, const QPoint &offset);
+
+bool QOffscreenBackingStore::scroll(const QRegion &area, int dx, int dy)
+{
+ if (m_image.isNull())
+ return false;
+
+ const QVector<QRect> rects = area.rects();
+ for (int i = 0; i < rects.size(); ++i)
+ qt_scrollRectInImage(m_image, rects.at(i), QPoint(dx, dy));
+
+ return true;
+}
+
+QPixmap QOffscreenBackingStore::grabWindow(WId window, const QRect &rect) const
+{
+ QRect area = m_windowAreaHash.value(window, QRect());
+ if (area.isNull())
+ return QPixmap();
+
+ QRect adjusted = rect;
+ if (adjusted.width() <= 0)
+ adjusted.setWidth(area.width());
+ if (adjusted.height() <= 0)
+ adjusted.setHeight(area.height());
+
+ adjusted = adjusted.translated(area.topLeft()) & area;
+
+ if (adjusted.isEmpty())
+ return QPixmap();
+
+ return QPixmap::fromImage(m_image.copy(adjusted));
+}
+
+QOffscreenBackingStore *QOffscreenBackingStore::backingStoreForWinId(WId id)
+{
+ return m_backingStoreForWinIdHash.value(id, 0);
+}
+
+void QOffscreenBackingStore::clearHash()
+{
+ QList<WId> ids = m_windowAreaHash.keys();
+ foreach (WId id, ids) {
+ QHash<WId, QOffscreenBackingStore *>::iterator it = m_backingStoreForWinIdHash.find(id);
+ if (it.value() == this)
+ m_backingStoreForWinIdHash.remove(id);
+ }
+ m_windowAreaHash.clear();
+}
+
+QHash<WId, QOffscreenBackingStore *> QOffscreenBackingStore::m_backingStoreForWinIdHash;
+
+QT_END_NAMESPACE
diff --git a/src/plugins/platforms/offscreen/qoffscreencommon.h b/src/plugins/platforms/offscreen/qoffscreencommon.h
new file mode 100644
index 0000000000..a5df7d05d3
--- /dev/null
+++ b/src/plugins/platforms/offscreen/qoffscreencommon.h
@@ -0,0 +1,109 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 Digia Plc and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the plugins of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Digia. For licensing terms and
+** conditions see http://qt.digia.com/licensing. For further information
+** use the contact form at http://qt.digia.com/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Digia gives you certain additional
+** rights. These rights are described in the Digia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QOFFSCREENCOMMON_H
+#define QOFFSCREENCOMMON_H
+
+#include <qpa/qplatformbackingstore.h>
+#include <qpa/qplatformdrag.h>
+#include <qpa/qplatformintegration.h>
+#include <qpa/qplatformscreen.h>
+#include <qpa/qplatformwindow.h>
+
+#include <qscopedpointer.h>
+#include <qimage.h>
+#include <qhash.h>
+
+QT_BEGIN_NAMESPACE
+
+class QOffscreenScreen : public QPlatformScreen
+{
+public:
+ QOffscreenScreen();
+
+ QRect geometry() const { return m_geometry; }
+ int depth() const { return 32; }
+ QImage::Format format() const { return QImage::Format_RGB32; }
+ QPlatformCursor *cursor() const { return m_cursor.data(); }
+
+ QPixmap grabWindow(WId window, int x, int y, int width, int height) const;
+
+ static QPlatformWindow *windowContainingCursor;
+
+public:
+ QRect m_geometry;
+ QScopedPointer<QPlatformCursor> m_cursor;
+};
+
+class QOffscreenDrag : public QPlatformDrag
+{
+public:
+ QMimeData *platformDropData() { return 0; }
+ Qt::DropAction drag(QDrag *) { return Qt::IgnoreAction; }
+};
+
+class QOffscreenBackingStore : public QPlatformBackingStore
+{
+public:
+ QOffscreenBackingStore(QWindow *window);
+ ~QOffscreenBackingStore();
+
+ QPaintDevice *paintDevice();
+ void flush(QWindow *window, const QRegion &region, const QPoint &offset);
+ void resize(const QSize &size, const QRegion &staticContents);
+ bool scroll(const QRegion &area, int dx, int dy);
+
+ QPixmap grabWindow(WId window, const QRect &rect) const;
+
+ static QOffscreenBackingStore *backingStoreForWinId(WId id);
+
+private:
+ void clearHash();
+
+ QImage m_image;
+ QHash<WId, QRect> m_windowAreaHash;
+
+ static QHash<WId, QOffscreenBackingStore *> m_backingStoreForWinIdHash;
+};
+
+QT_END_NAMESPACE
+
+#endif
diff --git a/src/plugins/platforms/offscreen/qoffscreenintegration.cpp b/src/plugins/platforms/offscreen/qoffscreenintegration.cpp
new file mode 100644
index 0000000000..e3fcc7ebb0
--- /dev/null
+++ b/src/plugins/platforms/offscreen/qoffscreenintegration.cpp
@@ -0,0 +1,162 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 Digia Plc and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the plugins of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Digia. For licensing terms and
+** conditions see http://qt.digia.com/licensing. For further information
+** use the contact form at http://qt.digia.com/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Digia gives you certain additional
+** rights. These rights are described in the Digia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qoffscreenintegration.h"
+#include "qoffscreenwindow.h"
+#include "qoffscreencommon.h"
+
+#if defined(Q_OS_UNIX)
+#include <QtPlatformSupport/private/qgenericunixeventdispatcher_p.h>
+#if defined(Q_OS_MAC)
+#include <qpa/qplatformfontdatabase.h>
+#else
+#include <QtPlatformSupport/private/qgenericunixfontdatabase_p.h>
+#endif
+#elif defined(Q_OS_WIN)
+#include <QtPlatformSupport/private/qbasicfontdatabase_p.h>
+#include <QtCore/private/qeventdispatcher_win_p.h>
+#endif
+
+#include <QtGui/private/qpixmap_raster_p.h>
+#include <QtGui/private/qguiapplication_p.h>
+
+#include <qpa/qplatformservices.h>
+
+QT_BEGIN_NAMESPACE
+
+template <typename BaseEventDispatcher>
+class QOffscreenEventDispatcher : public BaseEventDispatcher
+{
+public:
+ explicit QOffscreenEventDispatcher(QObject *parent = 0)
+ : BaseEventDispatcher(parent)
+ {
+ }
+
+ bool processEvents(QEventLoop::ProcessEventsFlags flags)
+ {
+ bool didSendEvents = QWindowSystemInterface::sendWindowSystemEvents(flags);
+
+ return BaseEventDispatcher::processEvents(flags) || didSendEvents;
+ }
+
+ bool hasPendingEvents()
+ {
+ return BaseEventDispatcher::hasPendingEvents()
+ || QWindowSystemInterface::windowSystemEventsQueued();
+ }
+
+ void flush()
+ {
+ if (qApp)
+ qApp->sendPostedEvents();
+ BaseEventDispatcher::flush();
+ }
+};
+
+QOffscreenIntegration::QOffscreenIntegration()
+{
+#if defined(Q_OS_UNIX)
+ m_eventDispatcher = createUnixEventDispatcher();
+#if defined(Q_OS_MAC)
+ m_fontDatabase.reset(new QPlatformFontDatabase());
+#else
+ m_fontDatabase.reset(new QGenericUnixFontDatabase());
+#endif
+#elif defined(Q_OS_WIN)
+ m_eventDispatcher = new QOffscreenEventDispatcher<QEventDispatcherWin32>();
+ m_fontDatabase.reset(new QBasicFontDatabase());
+#endif
+
+ m_drag.reset(new QOffscreenDrag);
+ m_services.reset(new QPlatformServices);
+
+ QGuiApplicationPrivate::instance()->setEventDispatcher(m_eventDispatcher);
+ screenAdded(new QOffscreenScreen);
+}
+
+QOffscreenIntegration::~QOffscreenIntegration()
+{
+}
+
+bool QOffscreenIntegration::hasCapability(QPlatformIntegration::Capability cap) const
+{
+ switch (cap) {
+ case ThreadedPixmaps: return true;
+ case MultipleWindows: return true;
+ default: return QPlatformIntegration::hasCapability(cap);
+ }
+}
+
+QPlatformWindow *QOffscreenIntegration::createPlatformWindow(QWindow *window) const
+{
+ Q_UNUSED(window);
+ QPlatformWindow *w = new QOffscreenWindow(window);
+ w->requestActivateWindow();
+ return w;
+}
+
+QPlatformBackingStore *QOffscreenIntegration::createPlatformBackingStore(QWindow *window) const
+{
+ return new QOffscreenBackingStore(window);
+}
+
+QAbstractEventDispatcher *QOffscreenIntegration::guiThreadEventDispatcher() const
+{
+ return m_eventDispatcher;
+}
+
+QPlatformFontDatabase *QOffscreenIntegration::fontDatabase() const
+{
+ return m_fontDatabase.data();
+}
+
+QPlatformDrag *QOffscreenIntegration::drag() const
+{
+ return m_drag.data();
+}
+
+QPlatformServices *QOffscreenIntegration::services() const
+{
+ return m_services.data();
+}
+
+QT_END_NAMESPACE
diff --git a/src/plugins/platforms/offscreen/qoffscreenintegration.h b/src/plugins/platforms/offscreen/qoffscreenintegration.h
new file mode 100644
index 0000000000..eb03100ec9
--- /dev/null
+++ b/src/plugins/platforms/offscreen/qoffscreenintegration.h
@@ -0,0 +1,80 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 Digia Plc and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the plugins of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Digia. For licensing terms and
+** conditions see http://qt.digia.com/licensing. For further information
+** use the contact form at http://qt.digia.com/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Digia gives you certain additional
+** rights. These rights are described in the Digia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QOFFSCREENINTEGRATION_H
+#define QOFFSCREENINTEGRATION_H
+
+#include <qpa/qplatformintegration.h>
+
+#include <qscopedpointer.h>
+
+QT_BEGIN_NAMESPACE
+
+class QOffscreenBackendData;
+
+class QOffscreenIntegration : public QPlatformIntegration
+{
+public:
+ QOffscreenIntegration();
+ ~QOffscreenIntegration();
+
+ bool hasCapability(QPlatformIntegration::Capability cap) const;
+
+ QPlatformWindow *createPlatformWindow(QWindow *window) const;
+ QPlatformBackingStore *createPlatformBackingStore(QWindow *window) const;
+ QPlatformDrag *drag() const;
+ QPlatformServices *services() const;
+
+ QPlatformFontDatabase *fontDatabase() const;
+ QAbstractEventDispatcher *guiThreadEventDispatcher() const;
+
+ static QOffscreenIntegration *createOffscreenIntegration();
+
+private:
+ QAbstractEventDispatcher *m_eventDispatcher;
+ QScopedPointer<QPlatformFontDatabase> m_fontDatabase;
+ QScopedPointer<QPlatformDrag> m_drag;
+ QScopedPointer<QPlatformServices> m_services;
+};
+
+QT_END_NAMESPACE
+
+#endif
diff --git a/src/plugins/platforms/offscreen/qoffscreenintegration_dummy.cpp b/src/plugins/platforms/offscreen/qoffscreenintegration_dummy.cpp
new file mode 100644
index 0000000000..8bc1b17a56
--- /dev/null
+++ b/src/plugins/platforms/offscreen/qoffscreenintegration_dummy.cpp
@@ -0,0 +1,47 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 Digia Plc and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the plugins of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Digia. For licensing terms and
+** conditions see http://qt.digia.com/licensing. For further information
+** use the contact form at http://qt.digia.com/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Digia gives you certain additional
+** rights. These rights are described in the Digia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qoffscreenintegration.h"
+
+QOffscreenIntegration *QOffscreenIntegration::createOffscreenIntegration()
+{
+ return new QOffscreenIntegration;
+}
diff --git a/src/plugins/platforms/offscreen/qoffscreenintegration_x11.cpp b/src/plugins/platforms/offscreen/qoffscreenintegration_x11.cpp
new file mode 100644
index 0000000000..6c6c516a4e
--- /dev/null
+++ b/src/plugins/platforms/offscreen/qoffscreenintegration_x11.cpp
@@ -0,0 +1,252 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 Digia Plc and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the plugins of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Digia. For licensing terms and
+** conditions see http://qt.digia.com/licensing. For further information
+** use the contact form at http://qt.digia.com/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Digia gives you certain additional
+** rights. These rights are described in the Digia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qoffscreenintegration_x11.h"
+
+#include <QByteArray>
+#include <QOpenGLContext>
+
+#include <X11/Xlib.h>
+#include <GL/glx.h>
+
+#include <QtPlatformSupport/private/qglxconvenience_p.h>
+
+#include <qpa/qplatformsurface.h>
+#include <qsurface.h>
+
+QT_BEGIN_NAMESPACE
+
+QOffscreenIntegration *QOffscreenIntegration::createOffscreenIntegration()
+{
+ return new QOffscreenX11Integration;
+}
+
+bool QOffscreenX11Integration::hasCapability(QPlatformIntegration::Capability cap) const
+{
+ switch (cap) {
+ case OpenGL: return true;
+ case ThreadedOpenGL: return true;
+ default: return QOffscreenIntegration::hasCapability(cap);
+ }
+}
+
+QPlatformOpenGLContext *QOffscreenX11Integration::createPlatformOpenGLContext(QOpenGLContext *context) const
+{
+ if (!m_connection)
+ m_connection.reset(new QOffscreenX11Connection);
+
+ return new QOffscreenX11GLXContext(m_connection->x11Info(), context);
+}
+
+QOffscreenX11Connection::QOffscreenX11Connection()
+{
+ XInitThreads();
+
+ QByteArray displayName = qgetenv("DISPLAY");
+ Display *display = XOpenDisplay(displayName.constData());
+ m_display = display;
+ m_screenNumber = DefaultScreen(display);
+}
+
+QOffscreenX11Connection::~QOffscreenX11Connection()
+{
+ XCloseDisplay((Display *)m_display);
+}
+
+class QOffscreenX11Info
+{
+public:
+ QOffscreenX11Info(QOffscreenX11Connection *connection)
+ : m_connection(connection)
+ {
+ }
+
+ Display *display() const {
+ return (Display *)m_connection->display();
+ }
+
+ Window root() const {
+ return DefaultRootWindow(display());
+ }
+
+ int screenNumber() const {
+ return m_connection->screenNumber();
+ }
+
+private:
+ QOffscreenX11Connection *m_connection;
+};
+
+QOffscreenX11Info *QOffscreenX11Connection::x11Info()
+{
+ if (!m_x11Info)
+ m_x11Info.reset(new QOffscreenX11Info(this));
+ return m_x11Info.data();
+}
+
+class QOffscreenX11GLXContextData
+{
+public:
+ QOffscreenX11Info *x11;
+ QSurfaceFormat format;
+ GLXContext context;
+ GLXContext shareContext;
+ Window window;
+};
+
+static Window createDummyWindow(QOffscreenX11Info *x11, XVisualInfo *visualInfo)
+{
+ Colormap cmap = XCreateColormap(x11->display(), x11->root(), visualInfo->visual, AllocNone);
+ XSetWindowAttributes a;
+ a.background_pixel = WhitePixel(x11->display(), x11->screenNumber());
+ a.border_pixel = BlackPixel(x11->display(), x11->screenNumber());
+ a.colormap = cmap;
+
+ Window window = XCreateWindow(x11->display(), x11->root(),
+ 0, 0, 100, 100,
+ 0, visualInfo->depth, InputOutput, visualInfo->visual,
+ CWBackPixel|CWBorderPixel|CWColormap, &a);
+ XFreeColormap(x11->display(), cmap);
+ return window;
+}
+
+static Window createDummyWindow(QOffscreenX11Info *x11, GLXFBConfig config)
+{
+ XVisualInfo *visualInfo = glXGetVisualFromFBConfig(x11->display(), config);
+ if (!visualInfo)
+ qFatal("Could not initialize GLX");
+ Window window = createDummyWindow(x11, visualInfo);
+ XFree(visualInfo);
+ return window;
+}
+
+QOffscreenX11GLXContext::QOffscreenX11GLXContext(QOffscreenX11Info *x11, QOpenGLContext *context)
+ : d(new QOffscreenX11GLXContextData)
+{
+ d->x11 = x11;
+ d->format = context->format();
+
+ d->shareContext = 0;
+ if (context->shareHandle())
+ d->shareContext = static_cast<QOffscreenX11GLXContext *>(context->shareHandle())->d->context;
+
+ GLXFBConfig config = qglx_findConfig(x11->display(), x11->screenNumber(), d->format);
+ if (config) {
+ d->context = glXCreateNewContext(x11->display(), config, GLX_RGBA_TYPE, d->shareContext, true);
+ if (!d->context && d->shareContext) {
+ d->shareContext = 0;
+ // re-try without a shared glx context
+ d->context = glXCreateNewContext(x11->display(), config, GLX_RGBA_TYPE, 0, true);
+ }
+
+ // Get the basic surface format details
+ if (d->context)
+ qglx_surfaceFormatFromGLXFBConfig(&d->format, x11->display(), config, d->context);
+
+ // Create a temporary window so that we can make the new context current
+ d->window = createDummyWindow(x11, config);
+ } else {
+ XVisualInfo *visualInfo = qglx_findVisualInfo(x11->display(), 0, &d->format);
+ if (!visualInfo)
+ qFatal("Could not initialize GLX");
+ d->context = glXCreateContext(x11->display(), visualInfo, d->shareContext, true);
+ if (!d->context && d->shareContext) {
+ // re-try without a shared glx context
+ d->shareContext = 0;
+ d->context = glXCreateContext(x11->display(), visualInfo, 0, true);
+ }
+
+ d->window = createDummyWindow(x11, visualInfo);
+ XFree(visualInfo);
+ }
+}
+
+QOffscreenX11GLXContext::~QOffscreenX11GLXContext()
+{
+ glXDestroyContext(d->x11->display(), d->context);
+ XDestroyWindow(d->x11->display(), d->window);
+}
+
+bool QOffscreenX11GLXContext::makeCurrent(QPlatformSurface *surface)
+{
+ QSize size = surface->surface()->size();
+
+ XResizeWindow(d->x11->display(), d->window, size.width(), size.height());
+ XSync(d->x11->display(), true);
+
+ if (glXMakeCurrent(d->x11->display(), d->window, d->context)) {
+ glViewport(0, 0, size.width(), size.height());
+ return true;
+ }
+
+ return false;
+}
+
+void QOffscreenX11GLXContext::doneCurrent()
+{
+ glXMakeCurrent(d->x11->display(), 0, 0);
+}
+
+void QOffscreenX11GLXContext::swapBuffers(QPlatformSurface *)
+{
+}
+
+void (*QOffscreenX11GLXContext::getProcAddress(const QByteArray &procName)) ()
+{
+ return (void (*)())glXGetProcAddressARB(reinterpret_cast<const GLubyte *>(procName.constData()));
+}
+
+QSurfaceFormat QOffscreenX11GLXContext::format() const
+{
+ return d->format;
+}
+
+bool QOffscreenX11GLXContext::isSharing() const
+{
+ return d->shareContext;
+}
+
+bool QOffscreenX11GLXContext::isValid() const
+{
+ return d->context && d->window;
+}
+
+QT_END_NAMESPACE
diff --git a/src/plugins/platforms/offscreen/qoffscreenintegration_x11.h b/src/plugins/platforms/offscreen/qoffscreenintegration_x11.h
new file mode 100644
index 0000000000..9afa302b04
--- /dev/null
+++ b/src/plugins/platforms/offscreen/qoffscreenintegration_x11.h
@@ -0,0 +1,108 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 Digia Plc and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the plugins of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Digia. For licensing terms and
+** conditions see http://qt.digia.com/licensing. For further information
+** use the contact form at http://qt.digia.com/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Digia gives you certain additional
+** rights. These rights are described in the Digia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QOFFSCREENINTEGRATION_X11_H
+#define QOFFSCREENINTEGRATION_X11_H
+
+#include "qoffscreenintegration.h"
+
+#include <qglobal.h>
+#include <qscopedpointer.h>
+
+#include <qpa/qplatformopenglcontext.h>
+
+QT_BEGIN_NAMESPACE
+
+class QOffscreenX11Connection;
+class QOffscreenX11Info;
+
+class QOffscreenX11Integration : public QOffscreenIntegration
+{
+public:
+ bool hasCapability(QPlatformIntegration::Capability cap) const;
+
+ QPlatformOpenGLContext *createPlatformOpenGLContext(QOpenGLContext *context) const;
+
+private:
+ mutable QScopedPointer<QOffscreenX11Connection> m_connection;
+};
+
+class QOffscreenX11Connection {
+public:
+ QOffscreenX11Connection();
+ ~QOffscreenX11Connection();
+
+ QOffscreenX11Info *x11Info();
+
+ void *display() const { return m_display; }
+ int screenNumber() const { return m_screenNumber; }
+
+private:
+ void *m_display;
+ int m_screenNumber;
+
+ QScopedPointer<QOffscreenX11Info> m_x11Info;
+};
+
+class QOffscreenX11GLXContextData;
+
+class QOffscreenX11GLXContext : public QPlatformOpenGLContext
+{
+public:
+ QOffscreenX11GLXContext(QOffscreenX11Info *x11, QOpenGLContext *context);
+ ~QOffscreenX11GLXContext();
+
+ bool makeCurrent(QPlatformSurface *surface);
+ void doneCurrent();
+ void swapBuffers(QPlatformSurface *surface);
+ void (*getProcAddress(const QByteArray &procName)) ();
+
+ QSurfaceFormat format() const;
+ bool isSharing() const;
+ bool isValid() const;
+
+private:
+ QScopedPointer<QOffscreenX11GLXContextData> d;
+};
+
+QT_END_NAMESPACE
+
+#endif
diff --git a/src/plugins/platforms/offscreen/qoffscreenwindow.cpp b/src/plugins/platforms/offscreen/qoffscreenwindow.cpp
new file mode 100644
index 0000000000..702ef2300c
--- /dev/null
+++ b/src/plugins/platforms/offscreen/qoffscreenwindow.cpp
@@ -0,0 +1,199 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 Digia Plc and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the plugins of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Digia. For licensing terms and
+** conditions see http://qt.digia.com/licensing. For further information
+** use the contact form at http://qt.digia.com/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Digia gives you certain additional
+** rights. These rights are described in the Digia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qoffscreenwindow.h"
+#include "qoffscreencommon.h"
+
+#include <qpa/qplatformscreen.h>
+#include <qpa/qwindowsysteminterface.h>
+
+#include <private/qwindow_p.h>
+
+QT_BEGIN_NAMESPACE
+
+QOffscreenWindow::QOffscreenWindow(QWindow *window)
+ : QPlatformWindow(window)
+ , m_positionIncludesFrame(false)
+ , m_visible(false)
+ , m_pendingGeometryChangeOnShow(true)
+{
+ if (window->windowState() == Qt::WindowNoState)
+ setGeometry(window->geometry());
+ else
+ setWindowState(window->windowState());
+
+ QWindowSystemInterface::flushWindowSystemEvents();
+
+ static WId counter = 0;
+ m_winId = ++counter;
+
+ m_windowForWinIdHash[m_winId] = this;
+}
+
+QOffscreenWindow::~QOffscreenWindow()
+{
+ if (QOffscreenScreen::windowContainingCursor == this)
+ QOffscreenScreen::windowContainingCursor = 0;
+ m_windowForWinIdHash.remove(m_winId);
+}
+
+void QOffscreenWindow::setGeometry(const QRect &rect)
+{
+ if (window()->windowState() != Qt::WindowNoState)
+ return;
+
+ m_positionIncludesFrame = qt_window_private(window())->positionPolicy == QWindowPrivate::WindowFrameInclusive;
+
+ setFrameMarginsEnabled(true);
+ setGeometryImpl(rect);
+
+ m_normalGeometry = geometry();
+}
+
+void QOffscreenWindow::setGeometryImpl(const QRect &rect)
+{
+ QRect adjusted = rect;
+ if (adjusted.width() <= 0)
+ adjusted.setWidth(1);
+ if (adjusted.height() <= 0)
+ adjusted.setHeight(1);
+
+ if (m_positionIncludesFrame) {
+ adjusted.translate(m_margins.left(), m_margins.top());
+ } else {
+ // make sure we're not placed off-screen
+ if (adjusted.left() < m_margins.left())
+ adjusted.translate(m_margins.left(), 0);
+ if (adjusted.top() < m_margins.top())
+ adjusted.translate(0, m_margins.top());
+ }
+
+ QPlatformWindow::setGeometry(adjusted);
+
+ if (m_visible) {
+ QWindowSystemInterface::handleGeometryChange(window(), adjusted);
+ QWindowSystemInterface::handleExposeEvent(window(), QRect(QPoint(), adjusted.size()));
+ } else {
+ m_pendingGeometryChangeOnShow = true;
+ }
+}
+
+void QOffscreenWindow::setVisible(bool visible)
+{
+ if (visible == m_visible)
+ return;
+
+ if (visible) {
+ if (window()->type() != Qt::ToolTip)
+ QWindowSystemInterface::handleWindowActivated(window());
+
+ if (m_pendingGeometryChangeOnShow) {
+ m_pendingGeometryChangeOnShow = false;
+ QWindowSystemInterface::handleGeometryChange(window(), geometry());
+ }
+ }
+
+ if (visible) {
+ QRect rect(QPoint(), geometry().size());
+ QWindowSystemInterface::handleExposeEvent(window(), rect);
+ } else {
+ QWindowSystemInterface::handleExposeEvent(window(), QRegion());
+ }
+
+ m_visible = visible;
+}
+
+void QOffscreenWindow::requestActivateWindow()
+{
+ if (m_visible)
+ QWindowSystemInterface::handleWindowActivated(window());
+}
+
+WId QOffscreenWindow::winId() const
+{
+ return m_winId;
+}
+
+QMargins QOffscreenWindow::frameMargins() const
+{
+ return m_margins;
+}
+
+void QOffscreenWindow::setFrameMarginsEnabled(bool enabled)
+{
+ if (enabled && !(window()->flags() & Qt::FramelessWindowHint))
+ m_margins = QMargins(2, 2, 2, 2);
+ else
+ m_margins = QMargins(0, 0, 0, 0);
+}
+
+void QOffscreenWindow::setWindowState(Qt::WindowState state)
+{
+ setFrameMarginsEnabled(state != Qt::WindowFullScreen);
+ m_positionIncludesFrame = false;
+
+ switch (state) {
+ case Qt::WindowFullScreen:
+ setGeometryImpl(screen()->geometry());
+ break;
+ case Qt::WindowMaximized:
+ setGeometryImpl(screen()->availableGeometry().adjusted(m_margins.left(), m_margins.top(), -m_margins.right(), -m_margins.bottom()));
+ break;
+ case Qt::WindowMinimized:
+ break;
+ case Qt::WindowNoState:
+ setGeometryImpl(m_normalGeometry);
+ break;
+ default:
+ break;
+ }
+
+ QWindowSystemInterface::handleWindowStateChanged(window(), state);
+}
+
+QOffscreenWindow *QOffscreenWindow::windowForWinId(WId id)
+{
+ return m_windowForWinIdHash.value(id, 0);
+}
+
+QHash<WId, QOffscreenWindow *> QOffscreenWindow::m_windowForWinIdHash;
+
+QT_END_NAMESPACE
diff --git a/src/plugins/platforms/offscreen/qoffscreenwindow.h b/src/plugins/platforms/offscreen/qoffscreenwindow.h
new file mode 100644
index 0000000000..cd1cf8e0aa
--- /dev/null
+++ b/src/plugins/platforms/offscreen/qoffscreenwindow.h
@@ -0,0 +1,86 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 Digia Plc and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the plugins of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Digia. For licensing terms and
+** conditions see http://qt.digia.com/licensing. For further information
+** use the contact form at http://qt.digia.com/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Digia gives you certain additional
+** rights. These rights are described in the Digia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QOFFSCREENWINDOW_H
+#define QOFFSCREENWINDOW_H
+
+#include <qpa/qplatformbackingstore.h>
+#include <qpa/qplatformwindow.h>
+
+#include <qhash.h>
+
+QT_BEGIN_NAMESPACE
+
+class QOffscreenWindow : public QPlatformWindow
+{
+public:
+ QOffscreenWindow(QWindow *window);
+ ~QOffscreenWindow();
+
+ void setGeometry(const QRect &rect);
+ void setWindowState(Qt::WindowState state);
+
+ QMargins frameMargins() const;
+
+ void setVisible(bool visible);
+ void requestActivateWindow();
+
+ WId winId() const;
+
+ static QOffscreenWindow *windowForWinId(WId id);
+
+private:
+ void setFrameMarginsEnabled(bool enabled);
+ void setGeometryImpl(const QRect &rect);
+
+ QRect m_normalGeometry;
+ QMargins m_margins;
+ bool m_positionIncludesFrame;
+ bool m_visible;
+ bool m_pendingGeometryChangeOnShow;
+ WId m_winId;
+
+ static QHash<WId, QOffscreenWindow *> m_windowForWinIdHash;
+};
+
+QT_END_NAMESPACE
+
+#endif
diff --git a/src/plugins/platforms/platforms.pro b/src/plugins/platforms/platforms.pro
index 828867c3a7..92664826ab 100644
--- a/src/plugins/platforms/platforms.pro
+++ b/src/plugins/platforms/platforms.pro
@@ -1,12 +1,17 @@
TEMPLATE = subdirs
-SUBDIRS += minimal
+android:!android-no-sdk: SUBDIRS += android
+
+SUBDIRS += minimal offscreen
contains(QT_CONFIG, xcb) {
SUBDIRS += xcb
}
-mac:!ios: SUBDIRS += cocoa
+mac {
+ ios: SUBDIRS += ios
+ else: SUBDIRS += cocoa
+}
win32: SUBDIRS += windows
diff --git a/src/plugins/platforms/qnx/qqnxbpseventfilter.cpp b/src/plugins/platforms/qnx/qqnxbpseventfilter.cpp
index 2d19537896..765853e392 100644
--- a/src/plugins/platforms/qnx/qqnxbpseventfilter.cpp
+++ b/src/plugins/platforms/qnx/qqnxbpseventfilter.cpp
@@ -87,7 +87,7 @@ void QQnxBpsEventFilter::installOnEventDispatcher(QAbstractEventDispatcher *disp
{
qBpsEventFilterDebug() << Q_FUNC_INFO << "dispatcher=" << dispatcher;
- if (navigator_request_events(0) != BPS_SUCCESS)
+ if (navigator_request_events(NAVIGATOR_EXTENDED_DATA) != BPS_SUCCESS)
qWarning("QQNX: failed to register for navigator events");
dispatcher->installNativeEventFilter(this);
@@ -210,6 +210,26 @@ bool QQnxBpsEventFilter::handleNavigatorEvent(bps_event_t *event)
m_navigatorEventHandler->handleExit();
break;
+ case NAVIGATOR_WINDOW_STATE: {
+ qBpsEventFilterDebug() << Q_FUNC_INFO << "WINDOW STATE event";
+ const navigator_window_state_t state = navigator_event_get_window_state(event);
+ const QByteArray id(navigator_event_get_groupid(event));
+
+ switch (state) {
+ case NAVIGATOR_WINDOW_FULLSCREEN:
+ m_navigatorEventHandler->handleWindowGroupStateChanged(id, Qt::WindowFullScreen);
+ break;
+ case NAVIGATOR_WINDOW_THUMBNAIL:
+ m_navigatorEventHandler->handleWindowGroupStateChanged(id, Qt::WindowMinimized);
+ break;
+ case NAVIGATOR_WINDOW_INVISIBLE:
+ m_navigatorEventHandler->handleWindowGroupDeactivated(id);
+ break;
+ }
+
+ break;
+ }
+
case NAVIGATOR_WINDOW_ACTIVE: {
qBpsEventFilterDebug() << Q_FUNC_INFO << "WINDOW ACTIVE event";
const QByteArray id(navigator_event_get_groupid(event));
diff --git a/src/plugins/platforms/qnx/qqnxclipboard.h b/src/plugins/platforms/qnx/qqnxclipboard.h
index 0b75393efd..e069355adc 100644
--- a/src/plugins/platforms/qnx/qqnxclipboard.h
+++ b/src/plugins/platforms/qnx/qqnxclipboard.h
@@ -42,6 +42,8 @@
#ifndef QQNXCLIPBOARD_H
#define QQNXCLIPBOARD_H
+#include <QtCore/qglobal.h>
+
#ifndef QT_NO_CLIPBOARD
#include <qpa/qplatformclipboard.h>
diff --git a/src/plugins/platforms/qnx/qqnxintegration.cpp b/src/plugins/platforms/qnx/qqnxintegration.cpp
index f3cfdab9c6..2d5c2e54e7 100644
--- a/src/plugins/platforms/qnx/qqnxintegration.cpp
+++ b/src/plugins/platforms/qnx/qqnxintegration.cpp
@@ -495,6 +495,8 @@ void QQnxIntegration::createDisplay(screen_display_t display, bool isPrimary)
QObject::connect(m_navigatorEventHandler, SIGNAL(rotationChanged(int)), screen, SLOT(setRotation(int)));
QObject::connect(m_navigatorEventHandler, SIGNAL(windowGroupActivated(QByteArray)), screen, SLOT(activateWindowGroup(QByteArray)));
QObject::connect(m_navigatorEventHandler, SIGNAL(windowGroupDeactivated(QByteArray)), screen, SLOT(deactivateWindowGroup(QByteArray)));
+ QObject::connect(m_navigatorEventHandler, SIGNAL(windowGroupStateChanged(QByteArray,Qt::WindowState)),
+ screen, SLOT(windowGroupStateChanged(QByteArray,Qt::WindowState)));
}
void QQnxIntegration::removeDisplay(QQnxScreen *screen)
diff --git a/src/plugins/platforms/qnx/qqnxnavigatoreventhandler.cpp b/src/plugins/platforms/qnx/qqnxnavigatoreventhandler.cpp
index 19fa9c5a9f..d561482b47 100644
--- a/src/plugins/platforms/qnx/qqnxnavigatoreventhandler.cpp
+++ b/src/plugins/platforms/qnx/qqnxnavigatoreventhandler.cpp
@@ -106,4 +106,10 @@ void QQnxNavigatorEventHandler::handleWindowGroupDeactivated(const QByteArray &i
Q_EMIT windowGroupDeactivated(id);
}
+void QQnxNavigatorEventHandler::handleWindowGroupStateChanged(const QByteArray &id, Qt::WindowState state)
+{
+ qNavigatorEventHandlerDebug() << Q_FUNC_INFO << id;
+ Q_EMIT windowGroupStateChanged(id, state);
+}
+
QT_END_NAMESPACE
diff --git a/src/plugins/platforms/qnx/qqnxnavigatoreventhandler.h b/src/plugins/platforms/qnx/qqnxnavigatoreventhandler.h
index 2068163473..cce3921a27 100644
--- a/src/plugins/platforms/qnx/qqnxnavigatoreventhandler.h
+++ b/src/plugins/platforms/qnx/qqnxnavigatoreventhandler.h
@@ -58,11 +58,13 @@ public:
void handleExit();
void handleWindowGroupActivated(const QByteArray &id);
void handleWindowGroupDeactivated(const QByteArray &id);
+ void handleWindowGroupStateChanged(const QByteArray &id, Qt::WindowState state);
Q_SIGNALS:
void rotationChanged(int angle);
void windowGroupActivated(const QByteArray &id);
void windowGroupDeactivated(const QByteArray &id);
+ void windowGroupStateChanged(const QByteArray &id, Qt::WindowState state);
};
QT_END_NAMESPACE
diff --git a/src/plugins/platforms/qnx/qqnxscreen.cpp b/src/plugins/platforms/qnx/qqnxscreen.cpp
index dfd7ccf0cc..f9efbde40c 100644
--- a/src/plugins/platforms/qnx/qqnxscreen.cpp
+++ b/src/plugins/platforms/qnx/qqnxscreen.cpp
@@ -553,6 +553,21 @@ void QQnxScreen::windowClosed(void *window)
removeOverlayWindow(windowHandle);
}
+void QQnxScreen::windowGroupStateChanged(const QByteArray &id, Qt::WindowState state)
+{
+ qScreenDebug() << Q_FUNC_INFO;
+
+ if (!rootWindow() || id != rootWindow()->groupName())
+ return;
+
+ QWindow * const window = topMostChildWindow();
+
+ if (!window)
+ return;
+
+ QWindowSystemInterface::handleWindowStateChanged(window, state);
+}
+
void QQnxScreen::activateWindowGroup(const QByteArray &id)
{
qScreenDebug() << Q_FUNC_INFO;
@@ -560,13 +575,12 @@ void QQnxScreen::activateWindowGroup(const QByteArray &id)
if (!rootWindow() || id != rootWindow()->groupName())
return;
- if (!m_childWindows.isEmpty()) {
- // We're picking up the last window of the list here
- // because this list is ordered by stacking order.
- // Last window is effectively the one on top.
- QWindow * const window = m_childWindows.last()->window();
- QWindowSystemInterface::handleWindowActivated(window);
- }
+ QWindow * const window = topMostChildWindow();
+
+ if (!window)
+ return;
+
+ QWindowSystemInterface::handleWindowActivated(window);
}
void QQnxScreen::deactivateWindowGroup(const QByteArray &id)
@@ -588,4 +602,17 @@ QSharedPointer<QQnxRootWindow> QQnxScreen::rootWindow() const
return m_rootWindow;
}
+QWindow * QQnxScreen::topMostChildWindow() const
+{
+ if (!m_childWindows.isEmpty()) {
+
+ // We're picking up the last window of the list here
+ // because this list is ordered by stacking order.
+ // Last window is effectively the one on top.
+ return m_childWindows.last()->window();
+ }
+
+ return 0;
+}
+
QT_END_NAMESPACE
diff --git a/src/plugins/platforms/qnx/qqnxscreen.h b/src/plugins/platforms/qnx/qqnxscreen.h
index 39cd4159d1..41dc675599 100644
--- a/src/plugins/platforms/qnx/qqnxscreen.h
+++ b/src/plugins/platforms/qnx/qqnxscreen.h
@@ -101,6 +101,7 @@ public Q_SLOTS:
void setRotation(int rotation);
void newWindowCreated(void *window);
void windowClosed(void *window);
+ void windowGroupStateChanged(const QByteArray &id, Qt::WindowState state);
void activateWindowGroup(const QByteArray &id);
void deactivateWindowGroup(const QByteArray &id);
@@ -114,6 +115,8 @@ private:
void addOverlayWindow(screen_window_t window);
void removeOverlayWindow(screen_window_t window);
+ QWindow *topMostChildWindow() const;
+
screen_context_t m_screenContext;
screen_display_t m_display;
mutable QSharedPointer<QQnxRootWindow> m_rootWindow;
diff --git a/src/plugins/platforms/qnx/qqnxwindow.cpp b/src/plugins/platforms/qnx/qqnxwindow.cpp
index cabbd405e5..51435a1e55 100644
--- a/src/plugins/platforms/qnx/qqnxwindow.cpp
+++ b/src/plugins/platforms/qnx/qqnxwindow.cpp
@@ -53,6 +53,11 @@
#include <errno.h>
+#ifdef Q_OS_BLACKBERRY
+#include <sys/pps.h>
+#include <bps/navigator.h>
+#endif
+
#ifdef QQNXWINDOW_DEBUG
#define qWindowDebug qDebug
#else
@@ -624,12 +629,20 @@ void QQnxWindow::setWindowState(Qt::WindowState state)
switch (state) {
- // WindowMinimized is not supported - navigator does not have an API to minimize a window
// WindowActive is not an accepted parameter according to the docs
- case Qt::WindowMinimized:
case Qt::WindowActive:
return;
+ case Qt::WindowMinimized:
+ minimize();
+
+ if (m_unmaximizedGeometry.isValid())
+ setGeometry(m_unmaximizedGeometry);
+ else
+ setGeometry(m_screen->geometry());
+
+ break;
+
case Qt::WindowMaximized:
case Qt::WindowFullScreen:
m_unmaximizedGeometry = geometry();
@@ -689,6 +702,27 @@ void QQnxWindow::blitFrom(QQnxWindow *sourceWindow, const QPoint &sourceOffset,
blitHelper(sourceBuffer, targetBuffer, sourceOffset, QPoint(0, 0), targetRegion, true);
}
+void QQnxWindow::minimize()
+{
+#if defined(Q_OS_BLACKBERRY) && !defined(Q_OS_BLACKBERRY_TABLET)
+ qWindowDebug() << Q_FUNC_INFO;
+
+ pps_encoder_t encoder;
+
+ pps_encoder_initialize(&encoder, false);
+ pps_encoder_add_string(&encoder, "msg", "minimizeWindow");
+
+ if (navigator_raw_write(pps_encoder_buffer(&encoder),
+ pps_encoder_length(&encoder)) != BPS_SUCCESS) {
+ qWindowDebug() << Q_FUNC_INFO << "navigator_raw_write failed:" << strerror(errno);
+ }
+
+ pps_encoder_cleanup(&encoder);
+#else
+ qWarning("Qt::WindowMinimized is not supported by this OS version");
+#endif
+}
+
void QQnxWindow::updateZorder(int &topZorder)
{
errno = 0;
diff --git a/src/plugins/platforms/qnx/qqnxwindow.h b/src/plugins/platforms/qnx/qqnxwindow.h
index 90226bb9a4..ad136227e3 100644
--- a/src/plugins/platforms/qnx/qqnxwindow.h
+++ b/src/plugins/platforms/qnx/qqnxwindow.h
@@ -116,6 +116,7 @@ public:
QQnxWindow *findWindow(screen_window_t windowHandle);
void blitFrom(QQnxWindow *sourceWindow, const QPoint &sourceOffset, const QRegion &targetRegion);
+ void minimize();
private:
QRect setGeometryHelper(const QRect &rect);
diff --git a/src/plugins/platforms/windows/accessible/iaccessible2.cpp b/src/plugins/platforms/windows/accessible/iaccessible2.cpp
index 164bd6eed9..fb08daa38e 100644
--- a/src/plugins/platforms/windows/accessible/iaccessible2.cpp
+++ b/src/plugins/platforms/windows/accessible/iaccessible2.cpp
@@ -44,7 +44,7 @@
#include "iaccessible2.h"
#include "qwindowsaccessibility.h"
-#include <QtGui/qaccessible2.h>
+#include <QtGui/private/qaccessible2_p.h>
#include <QtGui/qclipboard.h>
#include <QtWidgets/qapplication.h>
#include <QtCore/qdebug.h>
diff --git a/src/plugins/platforms/windows/accessible/qwindowsaccessibility.cpp b/src/plugins/platforms/windows/accessible/qwindowsaccessibility.cpp
index 3ccc6212a9..752b9e7c20 100644
--- a/src/plugins/platforms/windows/accessible/qwindowsaccessibility.cpp
+++ b/src/plugins/platforms/windows/accessible/qwindowsaccessibility.cpp
@@ -51,7 +51,7 @@
#include <QtCore/qpointer.h>
#include <QtCore/qsettings.h>
#include <QtGui/qaccessible.h>
-#include <QtGui/qaccessible2.h>
+#include <QtGui/private/qaccessible2_p.h>
#include <qpa/qplatformnativeinterface.h>
#include <QtGui/qwindow.h>
#include <QtGui/qguiapplication.h>
@@ -162,21 +162,10 @@ void QWindowsAccessibility::notifyAccessibilityUpdate(QAccessibleEvent *event)
}
}
- typedef void (WINAPI *PtrNotifyWinEvent)(DWORD, HWND, LONG, LONG);
-
#if defined(Q_OS_WINCE) // ### TODO: check for NotifyWinEvent in CE 6.0
// There is no user32.lib nor NotifyWinEvent for CE
return;
#else
- static PtrNotifyWinEvent ptrNotifyWinEvent = 0;
- static bool resolvedNWE = false;
- if (!resolvedNWE) {
- resolvedNWE = true;
- ptrNotifyWinEvent = (PtrNotifyWinEvent)QSystemLibrary::resolve(QLatin1String("user32"), "NotifyWinEvent");
- }
- if (!ptrNotifyWinEvent)
- return;
-
// An event has to be associated with a window,
// so find the first parent that is a widget and that has a WId
QAccessibleInterface *iface = event->accessibleInterface();
@@ -213,7 +202,7 @@ void QWindowsAccessibility::notifyAccessibilityUpdate(QAccessibleEvent *event)
eventNum %= 50; //[0..49]
int eventId = - (eventNum - 1);
qAccessibleRecentSentEvents()->insert(eventId, qMakePair(QPointer<QObject>(event->object()), event->child()));
- ptrNotifyWinEvent(event->type(), hWnd, OBJID_CLIENT, eventId);
+ ::NotifyWinEvent(event->type(), hWnd, OBJID_CLIENT, eventId);
++eventNum;
}
#endif // Q_OS_WINCE
@@ -283,7 +272,7 @@ bool QWindowsAccessibility::handleAccessibleObjectFromWindowRequest(HWND hwnd, W
{
if (static_cast<long>(lParam) == static_cast<long>(UiaRootObjectId)) {
/* For UI Automation */
- } else if ((DWORD)lParam == OBJID_CLIENT) {
+ } else if ((DWORD)lParam == DWORD(OBJID_CLIENT)) {
#if 1
// Ignoring all requests while starting up
// ### Maybe QPA takes care of this???
diff --git a/src/plugins/platforms/windows/accessible/qwindowsaccessibility.h b/src/plugins/platforms/windows/accessible/qwindowsaccessibility.h
index af0bd65c80..5a6dc0c2e5 100644
--- a/src/plugins/platforms/windows/accessible/qwindowsaccessibility.h
+++ b/src/plugins/platforms/windows/accessible/qwindowsaccessibility.h
@@ -48,7 +48,6 @@
#include <oleacc.h>
-QT_BEGIN_HEADER
QT_BEGIN_NAMESPACE
class QWindowsAccessibility : public QPlatformAccessibility
@@ -69,6 +68,5 @@ public:
};
QT_END_NAMESPACE
-QT_END_HEADER
#endif // QWINDOWSACCESSIBILITY_H
diff --git a/src/plugins/platforms/windows/accessible/qwindowsmsaaaccessible.cpp b/src/plugins/platforms/windows/accessible/qwindowsmsaaaccessible.cpp
index c23902014c..bb5d5d13a7 100644
--- a/src/plugins/platforms/windows/accessible/qwindowsmsaaaccessible.cpp
+++ b/src/plugins/platforms/windows/accessible/qwindowsmsaaaccessible.cpp
@@ -54,7 +54,7 @@
#include <QtCore/qpair.h>
#include <QtCore/qsettings.h>
#include <QtGui/qaccessible.h>
-#include <QtGui/qaccessible2.h>
+#include <QtGui/private/qaccessible2_p.h>
#include <QtGui/qguiapplication.h>
#include <qpa/qplatformnativeinterface.h>
#include <QtGui/qwindow.h>
diff --git a/src/plugins/platforms/windows/qtwindows_additional.h b/src/plugins/platforms/windows/qtwindows_additional.h
index 8d59fbd7c6..3b2e9787a2 100644
--- a/src/plugins/platforms/windows/qtwindows_additional.h
+++ b/src/plugins/platforms/windows/qtwindows_additional.h
@@ -126,6 +126,10 @@ typedef struct tagUPDATELAYEREDWINDOWINFO {
// IME.
#define IMR_CONFIRMRECONVERTSTRING 0x0005
+#ifndef MAPVK_VK_TO_CHAR
+# define MAPVK_VK_TO_CHAR 2
+#endif
+
#endif // if defined(Q_CC_MINGW)
/* Touch is supported from Windows 7 onwards and data structures
diff --git a/src/plugins/platforms/windows/qwindowscontext.cpp b/src/plugins/platforms/windows/qwindowscontext.cpp
index 1ea660d944..7e6b55dead 100644
--- a/src/plugins/platforms/windows/qwindowscontext.cpp
+++ b/src/plugins/platforms/windows/qwindowscontext.cpp
@@ -368,56 +368,53 @@ void QWindowsContext::setKeyGrabber(QWindow *w)
}
// Window class registering code (from qapplication_win.cpp)
-// If 0 is passed as the widget pointer, register a window class
-// for QWidget as default. This is used in QGLTemporaryContext
-// during GL initialization, where we don't want to use temporary
-// QWidgets or QGLWidgets, neither do we want to have separate code
-// to register window classes.
QString QWindowsContext::registerWindowClass(const QWindow *w, bool isGL)
{
- const Qt::WindowFlags flags = w ? w->flags() : (Qt::WindowFlags)0;
+ Q_ASSERT(w);
+ const Qt::WindowFlags flags = w->flags();
const Qt::WindowFlags type = flags & Qt::WindowType_Mask;
-
- uint style = 0;
- bool icon = false;
- QString cname = QStringLiteral("Qt5");
- if (w && isGL) {
- cname += QStringLiteral("QGLWindow");
- style = CS_DBLCLKS|CS_OWNDC;
- icon = true;
- } else if (w && (flags & Qt::MSWindowsOwnDC)) {
- cname += QStringLiteral("QWindowOwnDC");
- style = CS_DBLCLKS|CS_OWNDC;
- icon = true;
- } else if (w && (type == Qt::Tool || type == Qt::ToolTip)) {
- style = CS_DBLCLKS;
- if (w->inherits("QTipLabel") || w->inherits("QAlphaWidget")) {
- if ((QSysInfo::WindowsVersion >= QSysInfo::WV_XP
- && (QSysInfo::WindowsVersion & QSysInfo::WV_NT_based))) {
- style |= CS_DROPSHADOW;
- }
- cname += QStringLiteral("QToolTip");
- } else {
- cname += QStringLiteral("QTool");
- }
- style |= CS_SAVEBITS;
- icon = false;
- } else if (w && (type == Qt::Popup)) {
- cname += QStringLiteral("QPopup");
- style = CS_DBLCLKS|CS_SAVEBITS;
- if ((QSysInfo::WindowsVersion >= QSysInfo::WV_XP
- && (QSysInfo::WindowsVersion & QSysInfo::WV_NT_based)))
- style |= CS_DROPSHADOW;
+ // Determine style and icon.
+ uint style = CS_DBLCLKS;
+ bool icon = true;
+ if (isGL || (flags & Qt::MSWindowsOwnDC))
+ style |= CS_OWNDC;
+ if ((QSysInfo::WindowsVersion & QSysInfo::WV_NT_based)
+ && (type == Qt::Popup || w->property("_q_windowsDropShadow").toBool())) {
+ style |= CS_DROPSHADOW;
+ }
+ if (type == Qt::Tool || type == Qt::ToolTip || type == Qt::Popup) {
+ style |= CS_SAVEBITS; // Save/restore background
icon = false;
- } else {
- cname += QStringLiteral("QWindow");
- style = CS_DBLCLKS;
- icon = true;
}
+ // Create a unique name for the flag combination
+ QString cname = QStringLiteral("Qt5QWindow");
+ switch (type) {
+ case Qt::Tool:
+ cname += QStringLiteral("Tool");
+ break;
+ case Qt::ToolTip:
+ cname += QStringLiteral("ToolTip");
+ break;
+ case Qt::Popup:
+ cname += QStringLiteral("Popup");
+ break;
+ default:
+ break;
+ }
+ if (isGL)
+ cname += QStringLiteral("GL");
+ if (style & CS_DROPSHADOW)
+ cname += QStringLiteral("DropShadow");
+ if (style & CS_SAVEBITS)
+ cname += QStringLiteral("SaveBits");
+ if (style & CS_OWNDC)
+ cname += QStringLiteral("OwnDC");
+ if (icon)
+ cname += QStringLiteral("Icon");
HBRUSH brush = 0;
- if (w && !isGL)
+ if (!isGL)
brush = GetSysColorBrush(COLOR_WINDOW);
return registerWindowClass(cname, qWindowsWndProc, style, brush, icon);
}
@@ -783,7 +780,7 @@ bool QWindowsContext::windowsProc(HWND hwnd, UINT message,
d->m_creationContext->obtainedGeometry.moveTo(GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam));
return true;
case QtWindows::CalculateSize:
- return false;
+ return QWindowsGeometryHint::handleCalculateSize(d->m_creationContext->customMargins, msg, result);
default:
break;
}
@@ -818,12 +815,7 @@ bool QWindowsContext::windowsProc(HWND hwnd, UINT message,
platformWindow->getSizeHints(reinterpret_cast<MINMAXINFO *>(lParam));
return true;// maybe available on some SDKs revisit WM_NCCALCSIZE
case QtWindows::CalculateSize:
- // NCCALCSIZE_PARAMS structure if wParam==TRUE
- if (wParam && QWindowsContext::verboseWindows) {
- const NCCALCSIZE_PARAMS *ncp = reinterpret_cast<NCCALCSIZE_PARAMS *>(lParam);
- qDebug() << platformWindow->window() << *ncp;
- }
- break;
+ return QWindowsGeometryHint::handleCalculateSize(platformWindow->customMargins(), msg, result);
#endif
case QtWindows::ExposeEvent:
return platformWindow->handleWmPaint(hwnd, message, wParam, lParam);
diff --git a/src/plugins/platforms/windows/qwindowscursor.cpp b/src/plugins/platforms/windows/qwindowscursor.cpp
index 4dc9af61d8..5b2a3acbae 100644
--- a/src/plugins/platforms/windows/qwindowscursor.cpp
+++ b/src/plugins/platforms/windows/qwindowscursor.cpp
@@ -395,6 +395,19 @@ QWindowsWindowCursor QWindowsCursor::standardWindowCursor(Qt::CursorShape shape)
}
/*!
+ \brief Return cached pixmap cursor or create new one.
+*/
+
+QWindowsWindowCursor QWindowsCursor::pixmapWindowCursor(const QCursor &c)
+{
+ const qint64 cacheKey = c.pixmap().cacheKey();
+ PixmapCursorCache::iterator it = m_pixmapCursorCache.find(cacheKey);
+ if (it == m_pixmapCursorCache.end())
+ it = m_pixmapCursorCache.insert(cacheKey, QWindowsWindowCursor(c));
+ return it.value();
+}
+
+/*!
\brief Set a cursor on a window.
This is called frequently as the mouse moves over widgets in the window
@@ -406,11 +419,15 @@ void QWindowsCursor::changeCursor(QCursor *cursorIn, QWindow *window)
if (QWindowsContext::verboseWindows > 1)
qDebug() << __FUNCTION__ << cursorIn << window;
- if (!cursorIn || !window)
+ if (!window)
+ return;
+ if (!cursorIn) {
+ QWindowsWindow::baseWindowOf(window)->setCursor(QWindowsWindowCursor());
return;
+ }
const QWindowsWindowCursor wcursor =
cursorIn->shape() == Qt::BitmapCursor ?
- QWindowsWindowCursor(*cursorIn) : standardWindowCursor(cursorIn->shape());
+ pixmapWindowCursor(*cursorIn) : standardWindowCursor(cursorIn->shape());
if (wcursor.handle()) {
QWindowsWindow::baseWindowOf(window)->setCursor(wcursor);
} else {
@@ -449,6 +466,7 @@ void QWindowsCursor::setPos(const QPoint &pos)
class QWindowsWindowCursorData : public QSharedData
{
public:
+ QWindowsWindowCursorData() : m_cursor(Qt::ArrowCursor), m_handle(0) {}
explicit QWindowsWindowCursorData(const QCursor &c);
~QWindowsWindowCursorData();
@@ -464,7 +482,13 @@ QWindowsWindowCursorData::QWindowsWindowCursorData(const QCursor &c) :
QWindowsWindowCursorData::~QWindowsWindowCursorData()
{
- DestroyCursor(m_handle);
+ if (m_handle)
+ DestroyCursor(m_handle);
+}
+
+QWindowsWindowCursor::QWindowsWindowCursor() :
+ m_data(new QWindowsWindowCursorData)
+{
}
QWindowsWindowCursor::QWindowsWindowCursor(const QCursor &c) :
@@ -488,6 +512,11 @@ QWindowsWindowCursor & QWindowsWindowCursor::operator =(const QWindowsWindowCurs
return *this;
}
+bool QWindowsWindowCursor::isNull() const
+{
+ return m_data->m_handle == 0;
+}
+
QCursor QWindowsWindowCursor::cursor() const
{
return m_data->m_cursor;
diff --git a/src/plugins/platforms/windows/qwindowscursor.h b/src/plugins/platforms/windows/qwindowscursor.h
index b0256d4203..1e818bc9b8 100644
--- a/src/plugins/platforms/windows/qwindowscursor.h
+++ b/src/plugins/platforms/windows/qwindowscursor.h
@@ -55,11 +55,13 @@ class QWindowsWindowCursorData;
class QWindowsWindowCursor
{
public:
+ QWindowsWindowCursor();
explicit QWindowsWindowCursor(const QCursor &c);
~QWindowsWindowCursor();
QWindowsWindowCursor(const QWindowsWindowCursor &c);
QWindowsWindowCursor &operator=(const QWindowsWindowCursor &c);
+ bool isNull() const;
QCursor cursor() const;
HCURSOR handle() const;
@@ -81,11 +83,14 @@ public:
static QPoint mousePosition();
QWindowsWindowCursor standardWindowCursor(Qt::CursorShape s = Qt::ArrowCursor);
+ QWindowsWindowCursor pixmapWindowCursor(const QCursor &c);
private:
typedef QHash<Qt::CursorShape, QWindowsWindowCursor> StandardCursorCache;
+ typedef QHash<qint64, QWindowsWindowCursor> PixmapCursorCache;
StandardCursorCache m_standardCursorCache;
+ PixmapCursorCache m_pixmapCursorCache;
};
QT_END_NAMESPACE
diff --git a/src/plugins/platforms/windows/qwindowsdialoghelpers.cpp b/src/plugins/platforms/windows/qwindowsdialoghelpers.cpp
index 28438dd53d..5cc5230832 100644
--- a/src/plugins/platforms/windows/qwindowsdialoghelpers.cpp
+++ b/src/plugins/platforms/windows/qwindowsdialoghelpers.cpp
@@ -58,6 +58,10 @@
#include <QtCore/QObject>
#include <QtCore/QThread>
#include <QtCore/QSysInfo>
+#include <QtCore/QSharedData>
+#include <QtCore/QExplicitlySharedDataPointer>
+#include <QtCore/QMutex>
+#include <QtCore/QMutexLocker>
#include <QtCore/private/qsystemlibrary_p.h>
#include "qtwindows_additional.h"
@@ -82,6 +86,8 @@ static const IID q_IID_IShellItem = {0x43826d1e, 0xe718, 0x42ee, {0xbc, 0
#define IID_IShellItem q_IID_IShellItem
#else
static const IID IID_IShellItem = {0x43826d1e, 0xe718, 0x42ee, {0xbc, 0x55, 0xa1, 0xe2, 0x61, 0xc3, 0x7b, 0xfe}};
+static const IID IID_IShellItemArray = {0xb63ea76d, 0x1f85, 0x456f, {0xa1, 0x9c, 0x48, 0x15, 0x9e, 0xfa, 0x85, 0x8b}};
+# define LFF_FORCEFILESYSTEM 1
#endif
static const IID IID_IFileDialogEvents = {0x973510db, 0x7d7f, 0x452b,{0x89, 0x75, 0x74, 0xa8, 0x58, 0x28, 0xd3, 0x54}};
static const CLSID CLSID_FileOpenDialog = {0xdc1c5a9c, 0xe88a, 0x4dde, {0xa5, 0xa1, 0x60, 0xf8, 0x2a, 0x20, 0xae, 0xf7}};
@@ -249,6 +255,34 @@ DECLARE_INTERFACE_(IShellItemArray, IUnknown)
};
#endif
+#ifndef __IShellLibrary_INTERFACE_DEFINED__
+
+enum LIBRARYOPTIONFLAGS {};
+enum DEFAULTSAVEFOLDERTYPE { DSFT_DETECT = 1 };
+enum LIBRARYSAVEFLAGS {};
+
+DECLARE_INTERFACE_(IShellLibrary, IUnknown)
+{
+ STDMETHOD(LoadLibraryFromItem)(THIS_ IShellItem *psiLibrary, DWORD grfMode) PURE;
+ STDMETHOD(LoadLibraryFromKnownFolder)(THIS_ const GUID &kfidLibrary, DWORD grfMode) PURE;
+ STDMETHOD(AddFolder)(THIS_ IShellItem *psiLocation) PURE;
+ STDMETHOD(RemoveFolder)(THIS_ IShellItem *psiLocation) PURE;
+ STDMETHOD(GetFolders)(THIS_ int lff, REFIID riid, void **ppv) PURE;
+ STDMETHOD(ResolveFolder)(THIS_ IShellItem *psiFolderToResolve, DWORD dwTimeout, REFIID riid, void **ppv) PURE;
+ STDMETHOD(GetDefaultSaveFolder)(THIS_ DEFAULTSAVEFOLDERTYPE dsft, REFIID riid, void **ppv) PURE;
+ STDMETHOD(SetDefaultSaveFolder)(THIS_ DEFAULTSAVEFOLDERTYPE dsft, IShellItem *psi) PURE;
+ STDMETHOD(GetOptions)(THIS_ LIBRARYOPTIONFLAGS *plofOptions) PURE;
+ STDMETHOD(SetOptions)(THIS_ LIBRARYOPTIONFLAGS lofMask, LIBRARYOPTIONFLAGS lofOptions) PURE;
+ STDMETHOD(GetFolderType)(THIS_ GUID *pftid) PURE;
+ STDMETHOD(SetFolderType)(THIS_ const GUID &ftid) PURE;
+ STDMETHOD(GetIcon)(THIS_ LPWSTR *ppszIcon) PURE;
+ STDMETHOD(SetIcon)(THIS_ LPCWSTR pszIcon) PURE;
+ STDMETHOD(Commit)(THIS_) PURE;
+ STDMETHOD(Save)(THIS_ IShellItem *psiFolderToSaveIn, LPCWSTR pszLibraryName, LIBRARYSAVEFLAGS lsf, IShellItem **ppsiSavedTo) PURE;
+ STDMETHOD(SaveInKnownFolder)(THIS_ const GUID &kfidToSaveIn, LPCWSTR pszLibraryName, LIBRARYSAVEFLAGS lsf,IShellItem **ppsiSavedTo) PURE;
+};
+#endif
+
#ifndef __IModalWindow_INTERFACE_DEFINED__
DECLARE_INTERFACE_(IModalWindow, IUnknown)
{
@@ -387,6 +421,9 @@ void eatMouseMove()
Vista on) that mimick the behaviour of their QDialog
counterparts as close as possible.
+ Instances of derived classes are controlled by
+ QWindowsDialogHelperBase-derived classes.
+
A major difference is that there is only an exec(), which
is a modal, blocking call; there is no non-blocking show().
There 2 types of native dialogs:
@@ -401,6 +438,7 @@ void eatMouseMove()
like close() can be called on them from event handlers.
\endlist
+ \sa QWindowsDialogHelperBase
\internal
\ingroup qt-lighthouse-win
*/
@@ -411,7 +449,6 @@ class QWindowsNativeDialogBase : public QObject
public:
virtual void setWindowTitle(const QString &title) = 0;
virtual void exec(HWND owner = 0) = 0;
- virtual QPlatformDialogHelper::DialogCode result() const = 0;
signals:
void accepted();
@@ -432,12 +469,10 @@ protected:
The native dialog is created in setVisible_sys() since
then modality and the state of DontUseNativeDialog is known.
- Modal dialogs are then started via the platformNativeDialogModalHelp(),
- platformNativeDialogModalHelp() slots.
- Non-modal dialogs are shown using a separate thread should
- they support it.
+ Modal dialogs are then run by exec(). Non-modal dialogs are shown using a
+ separate thread started in show() should they support it.
- \sa QWindowsDialogThread
+ \sa QWindowsDialogThread, QWindowsNativeDialogBase
\internal
\ingroup qt-lighthouse-win
*/
@@ -445,17 +480,12 @@ protected:
template <class BaseClass>
QWindowsDialogHelperBase<BaseClass>::QWindowsDialogHelperBase() :
m_nativeDialog(0),
- m_ownerWindow(0)
+ m_ownerWindow(0),
+ m_timerId(0)
{
}
template <class BaseClass>
-QWindowsDialogHelperBase<BaseClass>::~QWindowsDialogHelperBase()
-{
- delete m_nativeDialog;
-}
-
-template <class BaseClass>
QWindowsNativeDialogBase *QWindowsDialogHelperBase<BaseClass>::nativeDialog() const
{
if (!m_nativeDialog) {
@@ -466,6 +496,19 @@ QWindowsNativeDialogBase *QWindowsDialogHelperBase<BaseClass>::nativeDialog() co
}
template <class BaseClass>
+void QWindowsDialogHelperBase<BaseClass>::deleteNativeDialog()
+{
+ delete m_nativeDialog;
+ m_nativeDialog = 0;
+}
+
+template <class BaseClass>
+void QWindowsDialogHelperBase<BaseClass>::timerEvent(QTimerEvent *)
+{
+ startDialogThread();
+}
+
+template <class BaseClass>
QWindowsNativeDialogBase *QWindowsDialogHelperBase<BaseClass>::ensureNativeDialog()
{
// Create dialog and apply common settings.
@@ -486,22 +529,18 @@ QWindowsNativeDialogBase *QWindowsDialogHelperBase<BaseClass>::ensureNativeDialo
class QWindowsDialogThread : public QThread
{
public:
- QWindowsDialogThread(QWindowsNativeDialogBase *dialog,
- HWND owner = 0) :
- m_dialog(dialog), m_owner(owner) {}
-
+ QWindowsDialogThread(QPlatformDialogHelper *h) : m_helper(h) {}
void run();
private:
- QWindowsNativeDialogBase *m_dialog;
- const HWND m_owner;
+ QPlatformDialogHelper *m_helper;
};
void QWindowsDialogThread::run()
{
if (QWindowsContext::verboseDialogs)
qDebug(">%s" , __FUNCTION__);
- m_dialog->exec(m_owner);
+ m_helper->exec();
deleteLater();
if (QWindowsContext::verboseDialogs)
qDebug("<%s" , __FUNCTION__);
@@ -512,7 +551,7 @@ bool QWindowsDialogHelperBase<BaseClass>::show(Qt::WindowFlags,
Qt::WindowModality windowModality,
QWindow *parent)
{
- const bool modal = (windowModality == Qt::ApplicationModal);
+ const bool modal = (windowModality != Qt::NonModal);
if (parent) {
m_ownerWindow = QWindowsWindow::handleOf(parent);
} else {
@@ -521,18 +560,40 @@ bool QWindowsDialogHelperBase<BaseClass>::show(Qt::WindowFlags,
if (QWindowsContext::verboseDialogs)
qDebug("%s modal=%d native=%p parent=%p" ,
__FUNCTION__, modal, m_nativeDialog, m_ownerWindow);
- if (!modal && !supportsNonModalDialog())
+ if (!modal && !supportsNonModalDialog(parent))
return false; // Was it changed in-between?
if (!ensureNativeDialog())
return false;
- if (!modal) { // Modal dialogs are shown in separate slot.
- QWindowsDialogThread *thread = new QWindowsDialogThread(m_nativeDialog, m_ownerWindow);
- thread->start();
+ // Start a background thread to show the dialog. For modal dialogs,
+ // a subsequent call to exec() may follow. So, start an idle timer
+ // which will start the dialog thread. If exec() is then called, the
+ // timer is stopped and dialog->exec() is called directly.
+ if (modal) {
+ m_timerId = this->startTimer(0);
+ } else {
+ startDialogThread();
}
return true;
}
template <class BaseClass>
+void QWindowsDialogHelperBase<BaseClass>::startDialogThread()
+{
+ QWindowsDialogThread *thread = new QWindowsDialogThread(this);
+ thread->start();
+ stopTimer();
+}
+
+template <class BaseClass>
+void QWindowsDialogHelperBase<BaseClass>::stopTimer()
+{
+ if (m_timerId) {
+ this->killTimer(m_timerId);
+ m_timerId = 0;
+ }
+}
+
+template <class BaseClass>
void QWindowsDialogHelperBase<BaseClass>::hide()
{
if (m_nativeDialog)
@@ -545,8 +606,11 @@ void QWindowsDialogHelperBase<BaseClass>::exec()
{
if (QWindowsContext::verboseDialogs)
qDebug("%s" , __FUNCTION__);
- if (QWindowsNativeDialogBase *nd = nativeDialog())
+ stopTimer();
+ if (QWindowsNativeDialogBase *nd = nativeDialog()) {
nd->exec(m_ownerWindow);
+ deleteNativeDialog();
+ }
}
static inline bool snapToDefaultButtonHint()
@@ -568,6 +632,101 @@ QVariant QWindowsDialogHelperBase<BaseClass>::styleHint(QPlatformDialogHelper::S
}
/*!
+ \class QWindowsFileDialogSharedData
+ \brief Explicitly shared file dialog parameters that are not in QFileDialogOptions.
+
+ Contain Parameters that need to be cached while the native dialog does not
+ exist yet. In addition, the data are updated by the change notifications of the
+ IFileDialogEvent, as querying them after the dialog has closed
+ does not reliably work. Provides thread-safe setters (for the non-modal case).
+
+ \internal
+ \ingroup qt-lighthouse-win
+ \sa QFileDialogOptions
+*/
+
+class QWindowsFileDialogSharedData
+{
+public:
+ QWindowsFileDialogSharedData() : m_data(new Data) {}
+ void fromOptions(const QSharedPointer<QFileDialogOptions> &o);
+
+ QString directory() const;
+ void setDirectory(const QString &);
+ QString selectedNameFilter() const;
+ void setSelectedNameFilter(const QString &);
+ QStringList selectedFiles() const;
+ void setSelectedFiles(const QStringList &);
+ QString selectedFile() const;
+
+private:
+ class Data : public QSharedData {
+ public:
+ QString directory;
+ QString selectedNameFilter;
+ QStringList selectedFiles;
+ QMutex mutex;
+ };
+ QExplicitlySharedDataPointer<Data> m_data;
+};
+
+inline QString QWindowsFileDialogSharedData::directory() const
+{
+ m_data->mutex.lock();
+ const QString result = m_data->directory;
+ m_data->mutex.unlock();
+ return result;
+}
+
+inline void QWindowsFileDialogSharedData::setDirectory(const QString &d)
+{
+ QMutexLocker (&m_data->mutex);
+ m_data->directory = d;
+}
+
+inline QString QWindowsFileDialogSharedData::selectedNameFilter() const
+{
+ m_data->mutex.lock();
+ const QString result = m_data->selectedNameFilter;
+ m_data->mutex.unlock();
+ return result;
+}
+
+inline void QWindowsFileDialogSharedData::setSelectedNameFilter(const QString &f)
+{
+ QMutexLocker (&m_data->mutex);
+ m_data->selectedNameFilter = f;
+}
+
+inline QStringList QWindowsFileDialogSharedData::selectedFiles() const
+{
+ m_data->mutex.lock();
+ const QStringList result = m_data->selectedFiles;
+ m_data->mutex.unlock();
+ return result;
+}
+
+inline QString QWindowsFileDialogSharedData::selectedFile() const
+{
+ const QStringList files = selectedFiles();
+ return files.isEmpty() ? QString() : files.front();
+}
+
+inline void QWindowsFileDialogSharedData::setSelectedFiles(const QStringList &f)
+{
+ QMutexLocker (&m_data->mutex);
+ m_data->selectedFiles = f;
+}
+
+inline void QWindowsFileDialogSharedData::fromOptions(const QSharedPointer<QFileDialogOptions> &o)
+{
+ QMutexLocker (&m_data->mutex);
+ m_data->directory = o->initialDirectory();
+ m_data->selectedFiles = o->initiallySelectedFiles();
+ m_data->selectedNameFilter = o->initiallySelectedNameFilter();
+}
+
+/*!
\class QWindowsNativeFileDialogEventHandler
\brief Listens to IFileDialog events and forwards them to QWindowsNativeFileDialogBase
@@ -609,7 +768,7 @@ public:
}
// IFileDialogEvents methods
- IFACEMETHODIMP OnFileOk(IFileDialog *) { return S_OK; }
+ IFACEMETHODIMP OnFileOk(IFileDialog *);
IFACEMETHODIMP OnFolderChange(IFileDialog *) { return S_OK; }
IFACEMETHODIMP OnFolderChanging(IFileDialog *, IShellItem *);
IFACEMETHODIMP OnHelp(IFileDialog *) { return S_OK; }
@@ -658,15 +817,17 @@ class QWindowsNativeFileDialogBase : public QWindowsNativeDialogBase
public:
~QWindowsNativeFileDialogBase();
- inline static QWindowsNativeFileDialogBase *create(QFileDialogOptions::AcceptMode am);
+ inline static QWindowsNativeFileDialogBase *create(QFileDialogOptions::AcceptMode am, const QWindowsFileDialogSharedData &data);
virtual void setWindowTitle(const QString &title);
inline void setMode(QFileDialogOptions::FileMode mode, QFileDialogOptions::FileDialogOptions options);
inline void setDirectory(const QString &directory);
+ inline void updateDirectory() { setDirectory(m_data.directory()); }
inline QString directory() const;
virtual void exec(HWND owner = 0);
inline void setNameFilters(const QStringList &f);
inline void selectNameFilter(const QString &filter);
+ inline void updateSelectedNameFilter() { selectNameFilter(m_data.selectedNameFilter()); }
inline QString selectedNameFilter() const;
void selectFile(const QString &fileName) const;
bool hideFiltersDetails() const { return m_hideFiltersDetails; }
@@ -674,14 +835,16 @@ public:
void setDefaultSuffix(const QString &s);
inline void setLabelText(QFileDialogOptions::DialogLabel l, const QString &text);
- virtual QPlatformDialogHelper::DialogCode result() const
- { return fileResult(); }
- virtual QPlatformDialogHelper::DialogCode fileResult(QStringList *fileResult = 0) const = 0;
+ // Return the selected files for tracking in OnSelectionChanged().
virtual QStringList selectedFiles() const = 0;
+ // Return the result for tracking in OnFileOk(). Differs from selection for
+ // example by appended default suffixes, etc.
+ virtual QStringList dialogResult() const = 0;
inline void onFolderChange(IShellItem *);
inline void onSelectionChange();
inline void onTypeChange();
+ inline bool onFileOk();
signals:
void directoryEntered(const QString& directory);
@@ -692,23 +855,30 @@ public slots:
virtual void close() { m_fileDialog->Close(S_OK); }
protected:
- QWindowsNativeFileDialogBase();
+ explicit QWindowsNativeFileDialogBase(const QWindowsFileDialogSharedData &data);
bool init(const CLSID &clsId, const IID &iid);
inline IFileDialog * fileDialog() const { return m_fileDialog; }
static QString itemPath(IShellItem *item);
+ static QStringList libraryItemFolders(IShellItem *item);
+ static QString libraryItemDefaultSaveFolder(IShellItem *item);
static int itemPaths(IShellItemArray *items, QStringList *fileResult = 0);
static IShellItem *shellItem(const QString &path);
+ const QWindowsFileDialogSharedData &data() const { return m_data; }
+ QWindowsFileDialogSharedData &data() { return m_data; }
+
private:
IFileDialog *m_fileDialog;
IFileDialogEvents *m_dialogEvents;
DWORD m_cookie;
QStringList m_nameFilters;
bool m_hideFiltersDetails;
+ QWindowsFileDialogSharedData m_data;
};
-QWindowsNativeFileDialogBase::QWindowsNativeFileDialogBase() :
- m_fileDialog(0), m_dialogEvents(0), m_cookie(0), m_hideFiltersDetails(false)
+QWindowsNativeFileDialogBase::QWindowsNativeFileDialogBase(const QWindowsFileDialogSharedData &data) :
+ m_fileDialog(0), m_dialogEvents(0), m_cookie(0), m_hideFiltersDetails(false),
+ m_data(data)
{
}
@@ -764,15 +934,17 @@ IShellItem *QWindowsNativeFileDialogBase::shellItem(const QString &path)
return result;
}
#endif
- qErrnoWarning("%s: SHCreateItemFromParsingName()) failed", __FUNCTION__);
+ qErrnoWarning("%s: SHCreateItemFromParsingName(%s)) failed", __FUNCTION__, qPrintable(path));
return 0;
}
void QWindowsNativeFileDialogBase::setDirectory(const QString &directory)
{
- if (IShellItem *psi = QWindowsNativeFileDialogBase::shellItem(directory)) {
- m_fileDialog->SetFolder(psi);
- psi->Release();
+ if (!directory.isEmpty()) {
+ if (IShellItem *psi = QWindowsNativeFileDialogBase::shellItem(directory)) {
+ m_fileDialog->SetFolder(psi);
+ psi->Release();
+ }
}
}
@@ -832,17 +1004,94 @@ void QWindowsNativeFileDialogBase::setMode(QFileDialogOptions::FileMode mode, QF
qErrnoWarning("%s: SetOptions() failed", __FUNCTION__);
}
-QString QWindowsNativeFileDialogBase::itemPath(IShellItem *item)
+#if !defined(Q_OS_WINCE) && defined(__IShellLibrary_INTERFACE_DEFINED__) // Windows SDK 7
+
+// Helper for "Libraries": collections of folders appearing from Windows 7
+// on, visible in the file dialogs.
+
+// Load a library from a IShellItem (sanitized copy of the inline function
+// SHLoadLibraryFromItem from ShObjIdl.h, which does not exist for MinGW).
+static IShellLibrary *sHLoadLibraryFromItem(IShellItem *libraryItem, DWORD mode)
+{
+ // ID symbols present from Windows 7 on:
+ static const CLSID classId_ShellLibrary = {0xd9b3211d, 0xe57f, 0x4426, {0xaa, 0xef, 0x30, 0xa8, 0x6, 0xad, 0xd3, 0x97}};
+ static const IID iId_IShellLibrary = {0x11a66efa, 0x382e, 0x451a, {0x92, 0x34, 0x1e, 0xe, 0x12, 0xef, 0x30, 0x85}};
+
+ IShellLibrary *helper = 0;
+ IShellLibrary *result = 0;
+ if (SUCCEEDED(CoCreateInstance(classId_ShellLibrary, NULL, CLSCTX_INPROC_SERVER, iId_IShellLibrary, reinterpret_cast<void **>(&helper))))
+ if (SUCCEEDED(helper->LoadLibraryFromItem(libraryItem, mode)))
+ helper->QueryInterface(iId_IShellLibrary, reinterpret_cast<void **>(&result));
+ if (helper)
+ helper->Release();
+ return result;
+}
+
+// Return all folders of a library-type item.
+QStringList QWindowsNativeFileDialogBase::libraryItemFolders(IShellItem *item)
+{
+ QStringList result;
+ if (IShellLibrary *library = sHLoadLibraryFromItem(item, STGM_READ | STGM_SHARE_DENY_WRITE)) {
+ IShellItemArray *itemArray = 0;
+ if (SUCCEEDED(library->GetFolders(LFF_FORCEFILESYSTEM, IID_IShellItemArray, reinterpret_cast<void **>(&itemArray)))) {
+ QWindowsNativeFileDialogBase::itemPaths(itemArray, &result);
+ itemArray->Release();
+ }
+ library->Release();
+ }
+ return result;
+}
+
+// Return default save folders of a library-type item.
+QString QWindowsNativeFileDialogBase::libraryItemDefaultSaveFolder(IShellItem *item)
{
QString result;
- LPWSTR name = 0;
- if (SUCCEEDED(item->GetDisplayName(SIGDN_FILESYSPATH, &name))) {
- result = QDir::cleanPath(QString::fromWCharArray(name));
- CoTaskMemFree(name);
+ if (IShellLibrary *library = sHLoadLibraryFromItem(item, STGM_READ | STGM_SHARE_DENY_WRITE)) {
+ IShellItem *item = 0;
+ if (SUCCEEDED(library->GetDefaultSaveFolder(DSFT_DETECT, IID_IShellItem, reinterpret_cast<void **>(&item)))) {
+ result = QWindowsNativeFileDialogBase::itemPath(item);
+ item->Release();
+ }
+ library->Release();
}
return result;
}
+#else // !Q_OS_WINCE && __IShellLibrary_INTERFACE_DEFINED__
+
+QStringList QWindowsNativeFileDialogBase::libraryItemFolders(IShellItem *)
+{
+ return QStringList();
+}
+
+QString QWindowsNativeFileDialogBase::libraryItemDefaultSaveFolder(IShellItem *)
+{
+ return QString();
+}
+
+#endif // Q_OS_WINCE || !__IShellLibrary_INTERFACE_DEFINED__
+
+QString QWindowsNativeFileDialogBase::itemPath(IShellItem *item)
+{
+ SFGAOF attributes = 0;
+ // Check whether it has a file system representation?
+ if (FAILED(item->GetAttributes(SFGAO_FILESYSTEM, &attributes)))
+ return QString();
+ if (attributes & SFGAO_FILESYSTEM) {
+ LPWSTR name = 0;
+ QString result;
+ if (SUCCEEDED(item->GetDisplayName(SIGDN_FILESYSPATH, &name))) {
+ result = QDir::cleanPath(QString::fromWCharArray(name));
+ CoTaskMemFree(name);
+ }
+ return result;
+ }
+ // Check for a "Library" item
+ if ((QSysInfo::windowsVersion() & QSysInfo::WV_NT_based) && QSysInfo::windowsVersion() >= QSysInfo::WV_WINDOWS7)
+ return QWindowsNativeFileDialogBase::libraryItemDefaultSaveFolder(item);
+ return QString();
+}
+
int QWindowsNativeFileDialogBase::itemPaths(IShellItemArray *items,
QStringList *result /* = 0 */)
{
@@ -983,14 +1232,16 @@ static int indexOfNameFilter(const QStringList &filters, const QString &needle)
void QWindowsNativeFileDialogBase::selectNameFilter(const QString &filter)
{
+ if (filter.isEmpty())
+ return;
const int index = indexOfNameFilter(m_nameFilters, filter);
- if (index >= 0) {
- m_fileDialog->SetFileTypeIndex(index + 1); // one-based.
- } else {
+ if (index < 0) {
qWarning("%s: Invalid parameter '%s' not found in '%s'.",
__FUNCTION__, qPrintable(filter),
qPrintable(m_nameFilters.join(QStringLiteral(", "))));
+ return;
}
+ m_fileDialog->SetFileTypeIndex(index + 1); // one-based.
}
QString QWindowsNativeFileDialogBase::selectedNameFilter() const
@@ -1008,6 +1259,7 @@ void QWindowsNativeFileDialogBase::onFolderChange(IShellItem *item)
{
if (item) {
const QString directory = QWindowsNativeFileDialogBase::itemPath(item);
+ m_data.setDirectory(directory);
emit directoryEntered(directory);
}
}
@@ -1015,13 +1267,23 @@ void QWindowsNativeFileDialogBase::onFolderChange(IShellItem *item)
void QWindowsNativeFileDialogBase::onSelectionChange()
{
const QStringList current = selectedFiles();
+ m_data.setSelectedFiles(current);
if (current.size() == 1)
emit currentChanged(current.front());
}
void QWindowsNativeFileDialogBase::onTypeChange()
{
- emit filterSelected(selectedNameFilter());
+ const QString filter = selectedNameFilter();
+ m_data.setSelectedNameFilter(filter);
+ emit filterSelected(filter);
+}
+
+bool QWindowsNativeFileDialogBase::onFileOk()
+{
+ // Store selected files as GetResults() returns invalid data after the dialog closes.
+ m_data.setSelectedFiles(dialogResult());
+ return true;
}
HRESULT QWindowsNativeFileDialogEventHandler::OnFolderChanging(IFileDialog *, IShellItem *item)
@@ -1042,6 +1304,11 @@ HRESULT QWindowsNativeFileDialogEventHandler::OnTypeChange(IFileDialog *)
return S_OK;
}
+HRESULT QWindowsNativeFileDialogEventHandler::OnFileOk(IFileDialog *)
+{
+ return m_nativeFileDialog->onFileOk() ? S_OK : S_FALSE;
+}
+
/*!
\class QWindowsNativeSaveFileDialog
\brief Windows native file save dialog wrapper around IFileSaveDialog.
@@ -1055,8 +1322,10 @@ HRESULT QWindowsNativeFileDialogEventHandler::OnTypeChange(IFileDialog *)
class QWindowsNativeSaveFileDialog : public QWindowsNativeFileDialogBase
{
public:
- virtual QPlatformDialogHelper::DialogCode fileResult(QStringList *fileResult = 0) const;
+ explicit QWindowsNativeSaveFileDialog(const QWindowsFileDialogSharedData &data) :
+ QWindowsNativeFileDialogBase(data) {}
virtual QStringList selectedFiles() const;
+ virtual QStringList dialogResult() const;
};
// Append a suffix from the name filter "Foo files (*.foo;*.bar)"
@@ -1079,17 +1348,13 @@ static inline QString appendSuffix(const QString &fileName, const QString &filte
return fileName + QLatin1Char('.') + filter.mid(suffixPos, endPos - suffixPos);
}
-QPlatformDialogHelper::DialogCode QWindowsNativeSaveFileDialog::fileResult(QStringList *result /* = 0 */) const
+QStringList QWindowsNativeSaveFileDialog::dialogResult() const
{
- if (result)
- result->clear();
+ QStringList result;
IShellItem *item = 0;
- const HRESULT hr = fileDialog()->GetResult(&item);
- if (FAILED(hr) || !item)
- return QPlatformDialogHelper::Rejected;
- if (result)
- result->push_back(appendSuffix(QWindowsNativeFileDialogBase::itemPath(item), selectedNameFilter()));
- return QPlatformDialogHelper::Accepted;
+ if (SUCCEEDED(fileDialog()->GetResult(&item)) && item)
+ result.push_back(appendSuffix(QWindowsNativeFileDialogBase::itemPath(item), selectedNameFilter()));
+ return result;
}
QStringList QWindowsNativeSaveFileDialog::selectedFiles() const
@@ -1115,23 +1380,23 @@ QStringList QWindowsNativeSaveFileDialog::selectedFiles() const
class QWindowsNativeOpenFileDialog : public QWindowsNativeFileDialogBase
{
public:
- virtual QPlatformDialogHelper::DialogCode fileResult(QStringList *fileResult = 0) const;
+ explicit QWindowsNativeOpenFileDialog(const QWindowsFileDialogSharedData &data) :
+ QWindowsNativeFileDialogBase(data) {}
virtual QStringList selectedFiles() const;
+ virtual QStringList dialogResult() const;
private:
inline IFileOpenDialog *openFileDialog() const
{ return static_cast<IFileOpenDialog *>(fileDialog()); }
};
-QPlatformDialogHelper::DialogCode QWindowsNativeOpenFileDialog::fileResult(QStringList *result /* = 0 */) const
+QStringList QWindowsNativeOpenFileDialog::dialogResult() const
{
- if (result)
- result->clear();
+ QStringList result;
IShellItemArray *items = 0;
- const HRESULT hr = openFileDialog()->GetResults(&items);
- if (SUCCEEDED(hr) && items && QWindowsNativeFileDialogBase::itemPaths(items, result) > 0)
- return QPlatformDialogHelper::Accepted;
- return QPlatformDialogHelper::Rejected;
+ if (SUCCEEDED(openFileDialog()->GetResults(&items)) && items)
+ QWindowsNativeFileDialogBase::itemPaths(items, &result);
+ return result;
}
QStringList QWindowsNativeOpenFileDialog::selectedFiles() const
@@ -1150,17 +1415,18 @@ QStringList QWindowsNativeOpenFileDialog::selectedFiles() const
QFileDialog::AcceptMode.
*/
-QWindowsNativeFileDialogBase *QWindowsNativeFileDialogBase::create(QFileDialogOptions::AcceptMode am)
+QWindowsNativeFileDialogBase *QWindowsNativeFileDialogBase::create(QFileDialogOptions::AcceptMode am,
+ const QWindowsFileDialogSharedData &data)
{
QWindowsNativeFileDialogBase *result = 0;
if (am == QFileDialogOptions::AcceptOpen) {
- result = new QWindowsNativeOpenFileDialog;
+ result = new QWindowsNativeOpenFileDialog(data);
if (!result->init(CLSID_FileOpenDialog, IID_IFileOpenDialog)) {
delete result;
return 0;
}
} else {
- result = new QWindowsNativeSaveFileDialog;
+ result = new QWindowsNativeSaveFileDialog(data);
if (!result->init(CLSID_FileSaveDialog, IID_IFileSaveDialog)) {
delete result;
return 0;
@@ -1169,16 +1435,17 @@ QWindowsNativeFileDialogBase *QWindowsNativeFileDialogBase::create(QFileDialogOp
return result;
}
+static inline bool isQQuickWindow(const QWindow *w = 0)
+{
+ return w && w->inherits("QQuickWindow");
+}
+
/*!
\class QWindowsFileDialogHelper
\brief Helper for native Windows file dialogs
- Non-modal dialogs are disabled for now. The functionality is
- implemented in principle, however there are failures
- when querying the results from a dialog run in another thread.
- This could probably be fixed be calling CoInitializeEx() with
- the right parameters from each thread. The problem is though
- that calls to CoInitialize() occur in several places in Qt.
+ For Qt 4 compatibility, do not create native non-modal dialogs on widgets,
+ but only on QQuickWindows, which do not have a fallback.
\internal
\ingroup qt-lighthouse-win
@@ -1188,8 +1455,9 @@ class QWindowsFileDialogHelper : public QWindowsDialogHelperBase<QPlatformFileDi
{
public:
QWindowsFileDialogHelper() {}
- virtual bool supportsNonModalDialog() const { return false; }
-
+ // For Qt 4 compatibility, do not create native non-modal dialogs on widgets,
+ // but only on QQuickWindows, which do not have a fallback.
+ virtual bool supportsNonModalDialog(const QWindow *parent = 0) const { return isQQuickWindow(parent); }
virtual bool defaultNameFilterDisables() const
{ return true; }
virtual void setDirectory(const QString &directory);
@@ -1205,11 +1473,14 @@ private:
virtual QWindowsNativeDialogBase *createNativeDialog();
inline QWindowsNativeFileDialogBase *nativeFileDialog() const
{ return static_cast<QWindowsNativeFileDialogBase *>(nativeDialog()); }
+
+ // Cache for the case no native dialog is created.
+ QWindowsFileDialogSharedData m_data;
};
QWindowsNativeDialogBase *QWindowsFileDialogHelper::createNativeDialog()
{
- QWindowsNativeFileDialogBase *result = QWindowsNativeFileDialogBase::create(options()->acceptMode());
+ QWindowsNativeFileDialogBase *result = QWindowsNativeFileDialogBase::create(options()->acceptMode(), m_data);
if (!result)
return 0;
QObject::connect(result, SIGNAL(accepted()), this, SIGNAL(accept()));
@@ -1223,6 +1494,7 @@ QWindowsNativeDialogBase *QWindowsFileDialogHelper::createNativeDialog()
// Apply settings.
const QSharedPointer<QFileDialogOptions> &opts = options();
+ m_data.fromOptions(opts);
const QFileDialogOptions::FileMode mode = opts->fileMode();
result->setWindowTitle(opts->windowTitle());
result->setMode(mode, opts->options());
@@ -1234,9 +1506,8 @@ QWindowsNativeDialogBase *QWindowsFileDialogHelper::createNativeDialog()
result->setLabelText(QFileDialogOptions::FileName, opts->labelText(QFileDialogOptions::FileName));
if (opts->isLabelExplicitlySet(QFileDialogOptions::Accept))
result->setLabelText(QFileDialogOptions::Accept, opts->labelText(QFileDialogOptions::Accept));
- const QString initialDirectory = opts->initialDirectory();
- if (!initialDirectory.isEmpty())
- result->setDirectory(initialDirectory);
+ result->updateDirectory();
+ result->updateSelectedNameFilter();
const QStringList initialSelection = opts->initiallySelectedFiles();
if (initialSelection.size() > 0) {
QFileInfo info(initialSelection.front());
@@ -1260,15 +1531,14 @@ void QWindowsFileDialogHelper::setDirectory(const QString &directory)
if (QWindowsContext::verboseDialogs)
qDebug("%s %s" , __FUNCTION__, qPrintable(directory));
- if (QWindowsNativeFileDialogBase *nfd = nativeFileDialog())
- nfd->setDirectory(directory);
+ m_data.setDirectory(directory);
+ if (hasNativeDialog())
+ nativeFileDialog()->updateDirectory();
}
QString QWindowsFileDialogHelper::directory() const
{
- if (const QWindowsNativeFileDialogBase *nfd = nativeFileDialog())
- return nfd->directory();
- return QString();
+ return m_data.directory();
}
void QWindowsFileDialogHelper::selectFile(const QString &fileName)
@@ -1282,13 +1552,7 @@ void QWindowsFileDialogHelper::selectFile(const QString &fileName)
QStringList QWindowsFileDialogHelper::selectedFiles() const
{
- QStringList files;
- if (const QWindowsNativeFileDialogBase *nfd = nativeFileDialog())
- nfd->fileResult(&files);
- if (QWindowsContext::verboseDialogs)
- qDebug("%s files='%s'" , __FUNCTION__,
- qPrintable(files.join(QStringLiteral(", "))));
- return files;
+ return m_data.selectedFiles();
}
void QWindowsFileDialogHelper::setFilter()
@@ -1307,15 +1571,14 @@ void QWindowsFileDialogHelper::setNameFilters(const QStringList &filters)
void QWindowsFileDialogHelper::selectNameFilter(const QString &filter)
{
- if (QWindowsNativeFileDialogBase *nfd = nativeFileDialog())
- nfd->selectNameFilter(filter);
+ m_data.setSelectedNameFilter(filter);
+ if (hasNativeDialog())
+ nativeFileDialog()->updateSelectedNameFilter();
}
QString QWindowsFileDialogHelper::selectedNameFilter() const
{
- if (const QWindowsNativeFileDialogBase *nfd = nativeFileDialog())
- return nfd->selectedNameFilter();
- return QString();
+ return m_data.selectedNameFilter();
}
#ifndef Q_OS_WINCE
@@ -1339,20 +1602,12 @@ class QWindowsXpNativeFileDialog : public QWindowsNativeDialogBase
public:
typedef QSharedPointer<QFileDialogOptions> OptionsPtr;
- static QWindowsXpNativeFileDialog *create(const OptionsPtr &options);
+ static QWindowsXpNativeFileDialog *create(const OptionsPtr &options, const QWindowsFileDialogSharedData &data);
virtual void setWindowTitle(const QString &t) { m_title = t; }
virtual void exec(HWND owner = 0);
virtual QPlatformDialogHelper::DialogCode result() const { return m_result; }
- void setDirectory(const QString &d) { m_directory = d; }
- QString directory() const { return m_directory; }
- void selectFile(const QString &f) { m_initialFile = f; }
- QStringList selectedFiles() const { return m_selectedFiles; }
- void setNameFilters(const QStringList &n) { m_nameFilters = n; }
- void selectNameFilter(const QString &f);
- QString selectedNameFilter() const { return m_selectedNameFilter; }
-
int existingDirCallback(HWND hwnd, UINT uMsg, LPARAM lParam);
public slots:
@@ -1362,19 +1617,15 @@ private:
typedef BOOL (APIENTRY *PtrGetOpenFileNameW)(LPOPENFILENAMEW);
typedef BOOL (APIENTRY *PtrGetSaveFileNameW)(LPOPENFILENAMEW);
- explicit QWindowsXpNativeFileDialog(const OptionsPtr &options);
+ explicit QWindowsXpNativeFileDialog(const OptionsPtr &options, const QWindowsFileDialogSharedData &data);
void populateOpenFileName(OPENFILENAME *ofn, HWND owner) const;
QStringList execExistingDir(HWND owner);
QStringList execFileNames(HWND owner, int *selectedFilterIndex) const;
const OptionsPtr m_options;
QString m_title;
- QString m_directory;
- QString m_initialFile;
- QStringList m_selectedFiles;
- QString m_selectedNameFilter;
- QStringList m_nameFilters;
QPlatformDialogHelper::DialogCode m_result;
+ QWindowsFileDialogSharedData m_data;
static PtrGetOpenFileNameW m_getOpenFileNameW;
static PtrGetSaveFileNameW m_getSaveFileNameW;
@@ -1383,7 +1634,7 @@ private:
QWindowsXpNativeFileDialog::PtrGetOpenFileNameW QWindowsXpNativeFileDialog::m_getOpenFileNameW = 0;
QWindowsXpNativeFileDialog::PtrGetSaveFileNameW QWindowsXpNativeFileDialog::m_getSaveFileNameW = 0;
-QWindowsXpNativeFileDialog *QWindowsXpNativeFileDialog::create(const OptionsPtr &options)
+QWindowsXpNativeFileDialog *QWindowsXpNativeFileDialog::create(const OptionsPtr &options, const QWindowsFileDialogSharedData &data)
{
// GetOpenFileNameW() GetSaveFileName() are resolved
// dynamically as not to create a dependency on Comdlg32, which
@@ -1394,51 +1645,33 @@ QWindowsXpNativeFileDialog *QWindowsXpNativeFileDialog::create(const OptionsPtr
m_getSaveFileNameW = (PtrGetSaveFileNameW)(library.resolve("GetSaveFileNameW"));
}
if (m_getOpenFileNameW && m_getSaveFileNameW)
- return new QWindowsXpNativeFileDialog(options);
+ return new QWindowsXpNativeFileDialog(options, data);
return 0;
}
-QWindowsXpNativeFileDialog::QWindowsXpNativeFileDialog(const OptionsPtr &options) :
- m_options(options), m_result(QPlatformDialogHelper::Rejected)
+QWindowsXpNativeFileDialog::QWindowsXpNativeFileDialog(const OptionsPtr &options,
+ const QWindowsFileDialogSharedData &data) :
+ m_options(options), m_result(QPlatformDialogHelper::Rejected), m_data(data)
{
- const QStringList nameFilters = m_options->nameFilters();
- if (!nameFilters.isEmpty())
- setNameFilters(nameFilters);
- const QString initialDirectory = m_options->initialDirectory();
- if (!initialDirectory.isEmpty())
- setDirectory(initialDirectory);
- const QString initialNameFilter = m_options->initiallySelectedNameFilter();
- if (!initialNameFilter.isEmpty())
- selectNameFilter(initialNameFilter);
- const QStringList selectedFiles = m_options->initiallySelectedFiles();
- if (!selectedFiles.isEmpty())
- selectFile(selectedFiles.front());
setWindowTitle(m_options->windowTitle());
}
-void QWindowsXpNativeFileDialog::selectNameFilter(const QString &f)
-{
- const int index = indexOfNameFilter(m_nameFilters, f);
- if (index >= 0)
- m_selectedNameFilter = m_nameFilters.at(index);
-}
-
void QWindowsXpNativeFileDialog::exec(HWND owner)
{
int selectedFilterIndex = -1;
- m_selectedFiles = m_options->fileMode() == QFileDialogOptions::DirectoryOnly ?
+ const QStringList selectedFiles =
+ m_options->fileMode() == QFileDialogOptions::DirectoryOnly ?
execExistingDir(owner) : execFileNames(owner, &selectedFilterIndex);
+ m_data.setSelectedFiles(selectedFiles);
QWindowsDialogs::eatMouseMove();
- if (m_selectedFiles.isEmpty()) {
+ if (selectedFiles.isEmpty()) {
m_result = QPlatformDialogHelper::Rejected;
emit rejected();
} else {
- if (selectedFilterIndex >= 0 && selectedFilterIndex < m_nameFilters.size()) {
- m_selectedNameFilter = m_nameFilters.at(selectedFilterIndex);
- } else {
- m_selectedNameFilter.clear();
- }
- m_directory = QFileInfo(m_selectedFiles.front()).absolutePath();
+ const QStringList nameFilters = m_options->nameFilters();
+ if (selectedFilterIndex >= 0 && selectedFilterIndex < nameFilters.size())
+ m_data.setSelectedNameFilter(nameFilters.at(selectedFilterIndex));
+ m_data.setDirectory(QFileInfo(selectedFiles.front()).absolutePath());
m_result = QPlatformDialogHelper::Accepted;
emit accepted();
}
@@ -1462,9 +1695,11 @@ typedef PIDLIST_ABSOLUTE qt_LpItemIdList;
int QWindowsXpNativeFileDialog::existingDirCallback(HWND hwnd, UINT uMsg, LPARAM lParam)
{
switch (uMsg) {
- case BFFM_INITIALIZED:
- if (!m_initialFile.isEmpty())
- SendMessage(hwnd, BFFM_SETSELECTION, TRUE, LPARAM(m_initialFile.utf16()));
+ case BFFM_INITIALIZED: {
+ const QString initialFile = m_data.selectedFile();
+ if (!initialFile.isEmpty())
+ SendMessage(hwnd, BFFM_SETSELECTION, TRUE, LPARAM(initialFile.utf16()));
+ }
break;
case BFFM_SELCHANGED: {
wchar_t path[MAX_PATH];
@@ -1536,7 +1771,7 @@ void QWindowsXpNativeFileDialog::populateOpenFileName(OPENFILENAME *ofn, HWND ow
*ptr++ = 0;
}
*ptr = 0;
- const int nameFilterIndex = indexOfNameFilter(m_nameFilters, m_selectedNameFilter);
+ const int nameFilterIndex = indexOfNameFilter(m_options->nameFilters(), m_data.selectedNameFilter());
if (nameFilterIndex >= 0)
ofn->nFilterIndex = nameFilterIndex + 1; // 1..n based.
// lpstrFile receives the initial selection and is the buffer
@@ -1544,10 +1779,10 @@ void QWindowsXpNativeFileDialog::populateOpenFileName(OPENFILENAME *ofn, HWND ow
// will not show.
ofn->nMaxFile = 65535;
const QString initiallySelectedFile =
- QDir::toNativeSeparators(m_initialFile).remove(QLatin1Char('<')).
+ QDir::toNativeSeparators(m_data.selectedFile()).remove(QLatin1Char('<')).
remove(QLatin1Char('>')).remove(QLatin1Char('"')).remove(QLatin1Char('|'));
ofn->lpstrFile = qStringToWCharArray(initiallySelectedFile, ofn->nMaxFile);
- ofn->lpstrInitialDir = qStringToWCharArray(QDir::toNativeSeparators(m_directory));
+ ofn->lpstrInitialDir = qStringToWCharArray(QDir::toNativeSeparators(m_data.directory()));
ofn->lpstrTitle = (wchar_t*)m_title.utf16();
// Determine lpstrDefExt. Note that the current MSDN docs document this
// member wrong. It should rather be documented as "the default extension
@@ -1616,8 +1851,7 @@ class QWindowsXpFileDialogHelper : public QWindowsDialogHelperBase<QPlatformFile
{
public:
QWindowsXpFileDialogHelper() {}
- virtual bool supportsNonModalDialog() const { return false; }
-
+ virtual bool supportsNonModalDialog(const QWindow *parent = 0) const { return isQQuickWindow(parent); }
virtual bool defaultNameFilterDisables() const
{ return true; }
virtual void setDirectory(const QString &directory);
@@ -1633,11 +1867,14 @@ private:
virtual QWindowsNativeDialogBase *createNativeDialog();
inline QWindowsXpNativeFileDialog *nativeFileDialog() const
{ return static_cast<QWindowsXpNativeFileDialog *>(nativeDialog()); }
+
+ QWindowsFileDialogSharedData m_data;
};
QWindowsNativeDialogBase *QWindowsXpFileDialogHelper::createNativeDialog()
{
- if (QWindowsNativeDialogBase *result = QWindowsXpNativeFileDialog::create(options())) {
+ m_data.fromOptions(options());
+ if (QWindowsXpNativeFileDialog *result = QWindowsXpNativeFileDialog::create(options(), m_data)) {
QObject::connect(result, SIGNAL(accepted()), this, SIGNAL(accept()));
QObject::connect(result, SIGNAL(rejected()), this, SIGNAL(reject()));
return result;
@@ -1647,47 +1884,37 @@ QWindowsNativeDialogBase *QWindowsXpFileDialogHelper::createNativeDialog()
void QWindowsXpFileDialogHelper::setDirectory(const QString &directory)
{
- if (QWindowsXpNativeFileDialog *nfd = nativeFileDialog())
- nfd->setDirectory(directory);
+ m_data.setDirectory(directory); // Dialog cannot be updated at run-time.
}
QString QWindowsXpFileDialogHelper::directory() const
{
- if (const QWindowsXpNativeFileDialog *nfd = nativeFileDialog())
- return nfd->directory();
- return QString();
+ return m_data.directory();
}
void QWindowsXpFileDialogHelper::selectFile(const QString &filename)
{
- if (QWindowsXpNativeFileDialog *nfd = nativeFileDialog())
- nfd->selectFile(filename);
+ m_data.setSelectedFiles(QStringList(filename)); // Dialog cannot be updated at run-time.
}
QStringList QWindowsXpFileDialogHelper::selectedFiles() const
{
- if (const QWindowsXpNativeFileDialog *nfd = nativeFileDialog())
- return nfd->selectedFiles();
- return QStringList();
+ return m_data.selectedFiles();
}
-void QWindowsXpFileDialogHelper::setNameFilters(const QStringList &n)
+void QWindowsXpFileDialogHelper::setNameFilters(const QStringList &)
{
- if (QWindowsXpNativeFileDialog *nfd = nativeFileDialog())
- nfd->setNameFilters(n);
+ // Dialog cannot be updated at run-time.
}
void QWindowsXpFileDialogHelper::selectNameFilter(const QString &f)
{
- if (QWindowsXpNativeFileDialog *nfd = nativeFileDialog())
- nfd->selectNameFilter(f);
+ m_data.setSelectedNameFilter(f); // Dialog cannot be updated at run-time.
}
QString QWindowsXpFileDialogHelper::selectedNameFilter() const
{
- if (const QWindowsXpNativeFileDialog *nfd = nativeFileDialog())
- return nfd->selectedNameFilter();
- return QString();
+ return m_data.selectedNameFilter();
}
#endif // Q_OS_WINCE
diff --git a/src/plugins/platforms/windows/qwindowsdialoghelpers.h b/src/plugins/platforms/windows/qwindowsdialoghelpers.h
index 07f105cb35..7884f398f3 100644
--- a/src/plugins/platforms/windows/qwindowsdialoghelpers.h
+++ b/src/plugins/platforms/windows/qwindowsdialoghelpers.h
@@ -65,6 +65,7 @@ template <class BaseClass>
class QWindowsDialogHelperBase : public BaseClass
{
public:
+ ~QWindowsDialogHelperBase() { deleteNativeDialog(); }
virtual void exec();
virtual bool show(Qt::WindowFlags windowFlags,
@@ -73,19 +74,24 @@ public:
virtual void hide();
virtual QVariant styleHint(QPlatformDialogHelper::StyleHint) const;
- virtual bool supportsNonModalDialog() const { return true; }
+ virtual bool supportsNonModalDialog(const QWindow * /* parent */ = 0) const { return true; }
protected:
QWindowsDialogHelperBase();
- ~QWindowsDialogHelperBase();
QWindowsNativeDialogBase *nativeDialog() const;
+ inline bool hasNativeDialog() const { return m_nativeDialog; }
+ void deleteNativeDialog();
+ void timerEvent(QTimerEvent *);
private:
virtual QWindowsNativeDialogBase *createNativeDialog() = 0;
inline QWindowsNativeDialogBase *ensureNativeDialog();
+ inline void startDialogThread();
+ inline void stopTimer();
QWindowsNativeDialogBase *m_nativeDialog;
HWND m_ownerWindow;
+ int m_timerId;
};
QT_END_NAMESPACE
diff --git a/src/plugins/platforms/windows/qwindowsdrag.cpp b/src/plugins/platforms/windows/qwindowsdrag.cpp
index 1286f5c106..fedda750d9 100644
--- a/src/plugins/platforms/windows/qwindowsdrag.cpp
+++ b/src/plugins/platforms/windows/qwindowsdrag.cpp
@@ -304,10 +304,10 @@ private:
class DragCursorHandle {
Q_DISABLE_COPY(DragCursorHandle)
public:
- DragCursorHandle(HCURSOR c, quint64 k) : cursor(c), cacheKey(k) {}
+ DragCursorHandle(HCURSOR c, qint64 k) : cursor(c), cacheKey(k) {}
~DragCursorHandle() { DestroyCursor(cursor); }
HCURSOR cursor;
- quint64 cacheKey;
+ qint64 cacheKey;
};
typedef QMap <Qt::DropAction, QSharedPointer<DragCursorHandle> > ActionCursorMap;
@@ -490,7 +490,7 @@ QWindowsOleDropSource::GiveFeedback(DWORD dwEffect)
qDebug("%s dwEffect=%lu, action=%d", __FUNCTION__, dwEffect, action);
QSharedPointer<DragCursorHandle> cursorHandler = m_cursors.value(action);
- quint64 currentCacheKey = m_drag->currentDrag()->dragCursor(action).cacheKey();
+ qint64 currentCacheKey = m_drag->currentDrag()->dragCursor(action).cacheKey();
if (cursorHandler.isNull() || currentCacheKey != cursorHandler->cacheKey)
createCursors();
diff --git a/src/plugins/platforms/windows/qwindowsfontdatabase.cpp b/src/plugins/platforms/windows/qwindowsfontdatabase.cpp
index b4fb19e8e8..c59b0edf78 100644
--- a/src/plugins/platforms/windows/qwindowsfontdatabase.cpp
+++ b/src/plugins/platforms/windows/qwindowsfontdatabase.cpp
@@ -606,130 +606,6 @@ QDebug operator<<(QDebug d, const QFontDef &def)
return d;
}
-/* From QFontDatabase.cpp, qt_determine_writing_systems_from_truetype_bits().
- * Fixme: Make public? */
-
-// see the Unicode subset bitfields in the MSDN docs
-static int requiredUnicodeBits[QFontDatabase::WritingSystemsCount][2] = {
- // Any,
- { 127, 127 },
- // Latin,
- { 0, 127 },
- // Greek,
- { 7, 127 },
- // Cyrillic,
- { 9, 127 },
- // Armenian,
- { 10, 127 },
- // Hebrew,
- { 11, 127 },
- // Arabic,
- { 13, 127 },
- // Syriac,
- { 71, 127 },
- //Thaana,
- { 72, 127 },
- //Devanagari,
- { 15, 127 },
- //Bengali,
- { 16, 127 },
- //Gurmukhi,
- { 17, 127 },
- //Gujarati,
- { 18, 127 },
- //Oriya,
- { 19, 127 },
- //Tamil,
- { 20, 127 },
- //Telugu,
- { 21, 127 },
- //Kannada,
- { 22, 127 },
- //Malayalam,
- { 23, 127 },
- //Sinhala,
- { 73, 127 },
- //Thai,
- { 24, 127 },
- //Lao,
- { 25, 127 },
- //Tibetan,
- { 70, 127 },
- //Myanmar,
- { 74, 127 },
- // Georgian,
- { 26, 127 },
- // Khmer,
- { 80, 127 },
- // SimplifiedChinese,
- { 126, 127 },
- // TraditionalChinese,
- { 126, 127 },
- // Japanese,
- { 126, 127 },
- // Korean,
- { 56, 127 },
- // Vietnamese,
- { 0, 127 }, // same as latin1
- // Other,
- { 126, 127 },
- // Ogham,
- { 78, 127 },
- // Runic,
- { 79, 127 },
- // Nko,
- { 14, 127 },
-};
-
-enum
-{
- SimplifiedChineseCsbBit = 18,
- TraditionalChineseCsbBit = 20,
- JapaneseCsbBit = 17,
- KoreanCsbBit = 21
-};
-
-static inline void writingSystemsFromTrueTypeBits(quint32 unicodeRange[4],
- quint32 codePageRange[2],
- QSupportedWritingSystems *ws)
-{
- bool hasScript = false;
- for(int i = 0; i < QFontDatabase::WritingSystemsCount; i++) {
- int bit = requiredUnicodeBits[i][0];
- int index = bit/32;
- int flag = 1 << (bit&31);
- if (bit != 126 && unicodeRange[index] & flag) {
- bit = requiredUnicodeBits[i][1];
- index = bit/32;
-
- flag = 1 << (bit&31);
- if (bit == 127 || unicodeRange[index] & flag) {
- ws->setSupported(QFontDatabase::WritingSystem(i), true);
- hasScript = true;
- }
- }
- }
- if(codePageRange[0] & (1 << SimplifiedChineseCsbBit)) {
- ws->setSupported(QFontDatabase::SimplifiedChinese, true);
- hasScript = true;
- }
- if(codePageRange[0] & (1 << TraditionalChineseCsbBit)) {
- ws->setSupported(QFontDatabase::TraditionalChinese, true);
- hasScript = true;
- }
- if(codePageRange[0] & (1 << JapaneseCsbBit)) {
- ws->setSupported(QFontDatabase::Japanese, true);
- hasScript = true;
- //qDebug("font %s supports Japanese", familyName.latin1());
- }
- if(codePageRange[0] & (1 << KoreanCsbBit)) {
- ws->setSupported(QFontDatabase::Korean, true);
- hasScript = true;
- }
- if (!hasScript)
- ws->setSupported(QFontDatabase::Symbol, true);
-}
-
// convert 0 ~ 1000 integer to QFont::Weight
static inline QFont::Weight weightFromInteger(long weight)
{
@@ -1019,7 +895,7 @@ static bool addFontToDatabase(QString familyName, const QString &scriptName,
unicodeRange[3] = 0xffffffff;
}
#endif
- writingSystemsFromTrueTypeBits(unicodeRange, codePageRange, &writingSystems);
+ writingSystems = QPlatformFontDatabase::writingSystemsFromTrueTypeBits(unicodeRange, codePageRange);
// ### Hack to work around problem with Thai text on Windows 7. Segoe UI contains
// the symbol for Baht, and Windows thus reports that it supports the Thai script.
// Since it's the default UI font on this platform, most widgets will be unable to
@@ -1160,9 +1036,7 @@ QWindowsFontDatabase::~QWindowsFontDatabase()
removeApplicationFonts();
}
-QFontEngine * QWindowsFontDatabase::fontEngine(const QFontDef &fontDef,
- QUnicodeTables::Script script,
- void *handle)
+QFontEngine * QWindowsFontDatabase::fontEngine(const QFontDef &fontDef, QChar::Script script, void *handle)
{
QFontEngine *fe = QWindowsFontDatabase::createEngine(script, fontDef,
0, QWindowsContext::instance()->defaultDPI(), false,
@@ -1215,7 +1089,7 @@ QFontEngine *QWindowsFontDatabase::fontEngine(const QByteArray &fontData, qreal
request.styleStrategy = QFont::NoFontMerging | QFont::PreferMatch;
request.hintingPreference = hintingPreference;
- fontEngine = QWindowsFontDatabase::createEngine(QUnicodeTables::Common, request, 0,
+ fontEngine = QWindowsFontDatabase::createEngine(QChar::Script_Common, request, 0,
QWindowsContext::instance()->defaultDPI(), false, QStringList(),
sharedFontData());
@@ -1223,11 +1097,11 @@ QFontEngine *QWindowsFontDatabase::fontEngine(const QByteArray &fontData, qreal
if (request.family != fontEngine->fontDef.family) {
qWarning("%s: Failed to load font. Got fallback instead: %s",
__FUNCTION__, qPrintable(fontEngine->fontDef.family));
- if (fontEngine->cache_count == 0 && fontEngine->ref.load() == 0)
+ if (fontEngine->ref.load() == 0)
delete fontEngine;
fontEngine = 0;
} else {
- Q_ASSERT(fontEngine->cache_count == 0 && fontEngine->ref.load() == 0);
+ Q_ASSERT(fontEngine->ref.load() == 0);
// Override the generated font name
static_cast<QWindowsFontEngine *>(fontEngine)->setUniqueFamilyName(uniqueFamilyName);
@@ -1529,8 +1403,8 @@ HFONT QWindowsFontDatabase::systemFont()
static inline bool scriptRequiresOpenType(int script)
{
- return ((script >= QUnicodeTables::Syriac && script <= QUnicodeTables::Sinhala)
- || script == QUnicodeTables::Khmer || script == QUnicodeTables::Nko);
+ return ((script >= QChar::Script_Syriac && script <= QChar::Script_Sinhala)
+ || script == QChar::Script_Khmer || script == QChar::Script_Nko);
}
static const char *other_tryFonts[] = {
@@ -1715,7 +1589,7 @@ static QStringList extraTryFontsForFamily(const QString& family)
return result;
}
-QStringList QWindowsFontDatabase::fallbacksForFamily(const QString family, const QFont::Style &style, const QFont::StyleHint &styleHint, const QUnicodeTables::Script &script) const
+QStringList QWindowsFontDatabase::fallbacksForFamily(const QString &family, QFont::Style style, QFont::StyleHint styleHint, QChar::Script script) const
{
QStringList result = QPlatformFontDatabase::fallbacksForFamily(family, style, styleHint, script);
if (!result.isEmpty())
@@ -1885,8 +1759,7 @@ QFontEngine *QWindowsFontDatabase::createEngine(int script, const QFontDef &requ
// for scripts that do not require OpenType we should just look at the list of
// supported writing systems in the font's OS/2 table.
if (scriptRequiresOpenType(script)) {
- HB_Face hbFace = few->harfbuzzFace();
- if (!hbFace || !hbFace->supported_scripts[script]) {
+ if (!few->supportsScript(QChar::Script(script))) {
qWarning(" OpenType support missing for script\n");
delete few;
return 0;
@@ -1917,7 +1790,7 @@ QFontEngine *QWindowsFontDatabase::createEngine(int script, const QFontDef &requ
directWriteFont->Release();
#endif
- if (script == QUnicodeTables::Common
+ if (script == QChar::Script_Common
&& !(request.styleStrategy & QFont::NoFontMerging)) {
QStringList extraFonts = extraTryFontsForFamily(request.family);
if (extraFonts.size()) {
diff --git a/src/plugins/platforms/windows/qwindowsfontdatabase.h b/src/plugins/platforms/windows/qwindowsfontdatabase.h
index c14d6027c2..b9e6c38eaa 100644
--- a/src/plugins/platforms/windows/qwindowsfontdatabase.h
+++ b/src/plugins/platforms/windows/qwindowsfontdatabase.h
@@ -78,9 +78,9 @@ public:
~QWindowsFontDatabase();
virtual void populateFontDatabase();
- virtual QFontEngine *fontEngine(const QFontDef &fontDef, QUnicodeTables::Script script, void *handle);
+ virtual QFontEngine *fontEngine(const QFontDef &fontDef, QChar::Script script, void *handle);
virtual QFontEngine *fontEngine(const QByteArray &fontData, qreal pixelSize, QFont::HintingPreference hintingPreference);
- virtual QStringList fallbacksForFamily(const QString family, const QFont::Style &style, const QFont::StyleHint &styleHint, const QUnicodeTables::Script &script) const;
+ virtual QStringList fallbacksForFamily(const QString &family, QFont::Style style, QFont::StyleHint styleHint, QChar::Script script) const;
virtual QStringList addApplicationFont(const QByteArray &fontData, const QString &fileName);
virtual void releaseHandle(void *handle);
virtual QString fontDir() const;
diff --git a/src/plugins/platforms/windows/qwindowsfontdatabase_ft.cpp b/src/plugins/platforms/windows/qwindowsfontdatabase_ft.cpp
index 406dc636b8..99b8d215f2 100644
--- a/src/plugins/platforms/windows/qwindowsfontdatabase_ft.cpp
+++ b/src/plugins/platforms/windows/qwindowsfontdatabase_ft.cpp
@@ -175,7 +175,7 @@ static bool addFontToDatabase(QString familyName, const QString &scriptName,
quint32 codePageRange[2] = {
signature->fsCsb[0], signature->fsCsb[1]
};
- writingSystems = QBasicFontDatabase::determineWritingSystemsFromTrueTypeBits(unicodeRange, codePageRange);
+ writingSystems = QPlatformFontDatabase::writingSystemsFromTrueTypeBits(unicodeRange, codePageRange);
// ### Hack to work around problem with Thai text on Windows 7. Segoe UI contains
// the symbol for Baht, and Windows thus reports that it supports the Thai script.
// Since it's the default UI font on this platform, most widgets will be unable to
@@ -362,7 +362,7 @@ void QWindowsFontDatabaseFT::populate(const QString &family)
ReleaseDC(0, dummy);
}
-QFontEngine * QWindowsFontDatabaseFT::fontEngine(const QFontDef &fontDef, QUnicodeTables::Script script, void *handle)
+QFontEngine * QWindowsFontDatabaseFT::fontEngine(const QFontDef &fontDef, QChar::Script script, void *handle)
{
QFontEngine *fe = QBasicFontDatabase::fontEngine(fontDef, script, handle);
if (QWindowsContext::verboseFonts)
@@ -430,9 +430,9 @@ static const char *kr_tryFonts[] = {
static const char **tryFonts = 0;
-QStringList QWindowsFontDatabaseFT::fallbacksForFamily(const QString family, const QFont::Style &style, const QFont::StyleHint &styleHint, const QUnicodeTables::Script &script) const
+QStringList QWindowsFontDatabaseFT::fallbacksForFamily(const QString &family, QFont::Style style, QFont::StyleHint styleHint, QChar::Script script) const
{
- if(script == QUnicodeTables::Common) {
+ if (script == QChar::Script_Common) {
// && !(request.styleStrategy & QFont::NoFontMerging)) {
QFontDatabase db;
if (!db.writingSystems(family).contains(QFontDatabase::Symbol)) {
@@ -518,8 +518,8 @@ HFONT QWindowsFontDatabaseFT::systemFont()
static inline bool scriptRequiresOpenType(int script)
{
- return ((script >= QUnicodeTables::Syriac && script <= QUnicodeTables::Sinhala)
- || script == QUnicodeTables::Khmer || script == QUnicodeTables::Nko);
+ return ((script >= QChar::Script_Syriac && script <= QChar::Script_Sinhala)
+ || script == QChar::Script_Khmer || script == QChar::Script_Nko);
}
static inline int verticalDPI()
diff --git a/src/plugins/platforms/windows/qwindowsfontdatabase_ft.h b/src/plugins/platforms/windows/qwindowsfontdatabase_ft.h
index 2ce429d012..d3cbc0210a 100644
--- a/src/plugins/platforms/windows/qwindowsfontdatabase_ft.h
+++ b/src/plugins/platforms/windows/qwindowsfontdatabase_ft.h
@@ -52,10 +52,10 @@ class QWindowsFontDatabaseFT : public QBasicFontDatabase
{
public:
void populateFontDatabase();
- QFontEngine *fontEngine(const QFontDef &fontDef, QUnicodeTables::Script script, void *handle);
+ QFontEngine *fontEngine(const QFontDef &fontDef, QChar::Script script, void *handle);
QFontEngine *fontEngine(const QByteArray &fontData, qreal pixelSize, QFont::HintingPreference hintingPreference);
- QStringList fallbacksForFamily(const QString family, const QFont::Style &style, const QFont::StyleHint &styleHint, const QUnicodeTables::Script &script) const;
+ QStringList fallbacksForFamily(const QString &family, QFont::Style style, QFont::StyleHint styleHint, QChar::Script script) const;
virtual QString fontDir() const;
virtual QFont defaultFont() const;
diff --git a/src/plugins/platforms/windows/qwindowsfontengine.cpp b/src/plugins/platforms/windows/qwindowsfontengine.cpp
index 7fcd9814bd..c402f00453 100644
--- a/src/plugins/platforms/windows/qwindowsfontengine.cpp
+++ b/src/plugins/platforms/windows/qwindowsfontengine.cpp
@@ -66,7 +66,6 @@
#include <QtCore/QThreadStorage>
#include <QtCore/private/qsystemlibrary_p.h>
-#include <QtCore/private/qunicodetables_p.h>
#include <QtCore/QDebug>
#include <limits.h>
@@ -155,9 +154,20 @@ static OUTLINETEXTMETRIC *getOutlineTextMetric(HDC hdc)
return otm;
}
+bool QWindowsFontEngine::hasCFFTable() const
+{
+ HDC hdc = m_fontEngineData->hdc;
+ SelectObject(hdc, hfont);
+ return GetFontData(hdc, MAKE_TAG('C', 'F', 'F', ' '), 0, 0, 0) != GDI_ERROR;
+}
+
void QWindowsFontEngine::getCMap()
{
ttf = (bool)(tm.tmPitchAndFamily & TMPF_TRUETYPE);
+
+ // TMPF_TRUETYPE is not set for fonts with CFF tables
+ cffTable = !ttf && hasCFFTable();
+
HDC hdc = m_fontEngineData->hdc;
SelectObject(hdc, hfont);
bool symb = false;
@@ -1041,7 +1051,7 @@ void QWindowsFontEngine::getUnscaledGlyph(glyph_t glyph, QPainterPath *path, gly
bool QWindowsFontEngine::getSfntTableData(uint tag, uchar *buffer, uint *length) const
{
- if (!ttf)
+ if (!ttf && !cffTable)
return false;
HDC hdc = m_fontEngineData->hdc;
SelectObject(hdc, hfont);
@@ -1216,13 +1226,13 @@ QImage QWindowsFontEngine::alphaRGBMapForGlyph(glyph_t glyph, QFixed, const QTra
{
HFONT font = hfont;
- int contrast;
+ UINT contrast;
SystemParametersInfo(SPI_GETFONTSMOOTHINGCONTRAST, 0, &contrast, 0);
SystemParametersInfo(SPI_SETFONTSMOOTHINGCONTRAST, 0, (void *) 1000, 0);
int margin = glyphMargin(QFontEngineGlyphCache::Raster_RGBMask);
QWindowsNativeImage *mask = drawGDIGlyph(font, glyph, margin, t, QImage::Format_RGB32);
- SystemParametersInfo(SPI_SETFONTSMOOTHINGCONTRAST, 0, (void *) contrast, 0);
+ SystemParametersInfo(SPI_SETFONTSMOOTHINGCONTRAST, 0, (void *) quintptr(contrast), 0);
if (mask == 0)
return QImage();
@@ -1258,7 +1268,7 @@ QFontEngine *QWindowsFontEngine::cloneWithSize(qreal pixelSize) const
request.styleStrategy |= QFont::NoFontMerging;
QFontEngine *fontEngine =
- QWindowsFontDatabase::createEngine(QUnicodeTables::Common, request, 0,
+ QWindowsFontDatabase::createEngine(QChar::Script_Common, request, 0,
QWindowsContext::instance()->defaultDPI(),
false,
QStringList(), m_fontEngineData);
diff --git a/src/plugins/platforms/windows/qwindowsfontengine.h b/src/plugins/platforms/windows/qwindowsfontengine.h
index a23db2f235..2bf6ead503 100644
--- a/src/plugins/platforms/windows/qwindowsfontengine.h
+++ b/src/plugins/platforms/windows/qwindowsfontengine.h
@@ -145,6 +145,7 @@ public:
private:
QWindowsNativeImage *drawGDIGlyph(HFONT font, glyph_t, int margin, const QTransform &xform,
QImage::Format mask_format);
+ bool hasCFFTable() const;
const QSharedPointer<QWindowsFontEngineData> m_fontEngineData;
@@ -155,6 +156,7 @@ private:
uint stockFont : 1;
uint ttf : 1;
uint hasOutline : 1;
+ uint cffTable : 1;
TEXTMETRIC tm;
int lw;
const unsigned char *cmap;
diff --git a/src/plugins/platforms/windows/qwindowsfontenginedirectwrite.cpp b/src/plugins/platforms/windows/qwindowsfontenginedirectwrite.cpp
index 183acedfc8..5b6ce695d8 100644
--- a/src/plugins/platforms/windows/qwindowsfontenginedirectwrite.cpp
+++ b/src/plugins/platforms/windows/qwindowsfontenginedirectwrite.cpp
@@ -376,10 +376,12 @@ void QWindowsFontEngineDirectWrite::recalcAdvances(QGlyphLayout *glyphs, QFontEn
if (SUCCEEDED(hr)) {
for (int i=0; i<glyphs->numGlyphs; ++i) {
glyphs->advances_x[i] = DESIGN_TO_LOGICAL(glyphMetrics[i].advanceWidth);
- if (fontDef.styleStrategy & QFont::ForceIntegerMetrics)
- glyphs->advances_x[i] = glyphs->advances_x[i].round();
glyphs->advances_y[i] = 0;
}
+ if (fontDef.styleStrategy & QFont::ForceIntegerMetrics) {
+ for (int i = 0; i < glyphs->numGlyphs; ++i)
+ glyphs->advances_x[i] = glyphs->advances_x[i].round();
+ }
} else {
qErrnoWarning("%s: GetDesignGlyphMetrics failed", __FUNCTION__);
}
diff --git a/src/plugins/platforms/windows/qwindowsfontenginedirectwrite.h b/src/plugins/platforms/windows/qwindowsfontenginedirectwrite.h
index 35ed6f3891..106087f757 100644
--- a/src/plugins/platforms/windows/qwindowsfontenginedirectwrite.h
+++ b/src/plugins/platforms/windows/qwindowsfontenginedirectwrite.h
@@ -42,6 +42,8 @@
#ifndef QWINDOWSFONTENGINEDIRECTWRITE_H
#define QWINDOWSFONTENGINEDIRECTWRITE_H
+#include <QtCore/qglobal.h>
+
#ifndef QT_NO_DIRECTWRITE
#include <QtGui/private/qfontengine_p.h>
diff --git a/src/plugins/platforms/windows/qwindowsglcontext.cpp b/src/plugins/platforms/windows/qwindowsglcontext.cpp
index 081b42ce65..6f59b33e62 100644
--- a/src/plugins/platforms/windows/qwindowsglcontext.cpp
+++ b/src/plugins/platforms/windows/qwindowsglcontext.cpp
@@ -232,6 +232,7 @@ static QSurfaceFormat
QWindowsOpenGLAdditionalFormat *additionalIn = 0)
{
QSurfaceFormat format;
+ format.setRenderableType(QSurfaceFormat::OpenGL);
if (pfd.dwFlags & PFD_DOUBLEBUFFER)
format.setSwapBehavior(QSurfaceFormat::DoubleBuffer);
format.setDepthBufferSize(pfd.cDepthBits);
@@ -500,6 +501,7 @@ static QSurfaceFormat
enum { attribSize =40 };
QSurfaceFormat result;
+ result.setRenderableType(QSurfaceFormat::OpenGL);
if (!staticContext.hasExtensions())
return result;
int iAttributes[attribSize];
@@ -875,6 +877,12 @@ QWindowsGLContext::QWindowsGLContext(const QOpenGLStaticContextPtr &staticContex
m_renderingContext(0),
m_pixelFormat(0), m_extensionsUsed(false)
{
+ QSurfaceFormat format = context->format();
+ if (format.renderableType() == QSurfaceFormat::DefaultRenderableType)
+ format.setRenderableType(QSurfaceFormat::OpenGL);
+ if (format.renderableType() != QSurfaceFormat::OpenGL)
+ return;
+
// workaround for matrox driver:
// make a cheap call to opengl to force loading of DLL
static bool opengl32dll = false;
@@ -912,7 +920,7 @@ QWindowsGLContext::QWindowsGLContext(const QOpenGLStaticContextPtr &staticContex
QWindowsOpenGLAdditionalFormat obtainedAdditional;
if (tryExtensions) {
m_pixelFormat =
- ARB::choosePixelFormat(hdc, *m_staticContext, context->format(),
+ ARB::choosePixelFormat(hdc, *m_staticContext, format,
requestedAdditional, &m_obtainedPixelFormatDescriptor);
if (m_pixelFormat > 0) {
m_obtainedFormat =
@@ -922,7 +930,7 @@ QWindowsGLContext::QWindowsGLContext(const QOpenGLStaticContextPtr &staticContex
}
} // tryExtensions
if (!m_pixelFormat) { // Failed, try GDI
- m_pixelFormat = GDI::choosePixelFormat(hdc, context->format(), requestedAdditional,
+ m_pixelFormat = GDI::choosePixelFormat(hdc, format, requestedAdditional,
&m_obtainedPixelFormatDescriptor);
if (m_pixelFormat)
m_obtainedFormat =
@@ -945,7 +953,7 @@ QWindowsGLContext::QWindowsGLContext(const QOpenGLStaticContextPtr &staticContex
if (m_extensionsUsed)
m_renderingContext =
ARB::createContext(*m_staticContext, hdc,
- context->format(),
+ format,
requestedAdditional,
sharingRenderingContext);
if (!m_renderingContext)
diff --git a/src/plugins/platforms/windows/qwindowsintegration.cpp b/src/plugins/platforms/windows/qwindowsintegration.cpp
index da4519199f..30e0478e64 100644
--- a/src/plugins/platforms/windows/qwindowsintegration.cpp
+++ b/src/plugins/platforms/windows/qwindowsintegration.cpp
@@ -77,6 +77,7 @@
#include <QtCore/private/qeventdispatcher_win_p.h>
#include <QtCore/QDebug>
+#include <QtCore/QVariant>
QT_BEGIN_NAMESPACE
@@ -114,6 +115,11 @@ public:
bool asyncExpose() const;
void setAsyncExpose(bool value);
+
+ QVariantMap windowProperties(QPlatformWindow *window) const;
+ QVariant windowProperty(QPlatformWindow *window, const QString &name) const;
+ QVariant windowProperty(QPlatformWindow *window, const QString &name, const QVariant &defaultValue) const;
+ void setWindowProperty(QPlatformWindow *window, const QString &name, const QVariant &value);
};
void *QWindowsNativeInterface::nativeResourceForWindow(const QByteArray &resource, QWindow *window)
@@ -150,6 +156,37 @@ void *QWindowsNativeInterface::nativeResourceForBackingStore(const QByteArray &r
return 0;
}
+static const char customMarginPropertyC[] = "WindowsCustomMargins";
+
+QVariant QWindowsNativeInterface::windowProperty(QPlatformWindow *window, const QString &name) const
+{
+ QWindowsWindow *platformWindow = static_cast<QWindowsWindow *>(window);
+ if (name == QLatin1String(customMarginPropertyC))
+ return qVariantFromValue(platformWindow->customMargins());
+ return QVariant();
+}
+
+QVariant QWindowsNativeInterface::windowProperty(QPlatformWindow *window, const QString &name, const QVariant &defaultValue) const
+{
+ const QVariant result = windowProperty(window, name);
+ return result.isValid() ? result : defaultValue;
+}
+
+void QWindowsNativeInterface::setWindowProperty(QPlatformWindow *window, const QString &name, const QVariant &value)
+{
+ QWindowsWindow *platformWindow = static_cast<QWindowsWindow *>(window);
+ if (name == QLatin1String(customMarginPropertyC))
+ platformWindow->setCustomMargins(qvariant_cast<QMargins>(value));
+}
+
+QVariantMap QWindowsNativeInterface::windowProperties(QPlatformWindow *window) const
+{
+ QVariantMap result;
+ const QString customMarginProperty = QLatin1String(customMarginPropertyC);
+ result.insert(customMarginProperty, windowProperty(window, customMarginProperty));
+ return result;
+}
+
#ifndef QT_NO_OPENGL
void *QWindowsNativeInterface::nativeResourceForContext(const QByteArray &resource, QOpenGLContext *context)
{
@@ -372,6 +409,11 @@ QPlatformWindow *QWindowsIntegration::createPlatformWindow(QWindow *window) cons
QWindowsWindow::WindowData requested;
requested.flags = window->flags();
requested.geometry = window->geometry();
+ // Apply custom margins (see QWindowsWindow::setCustomMargins())).
+ const QVariant customMarginsV = window->property("_q_windowsCustomMargins");
+ if (customMarginsV.isValid())
+ requested.customMargins = qvariant_cast<QMargins>(customMarginsV);
+
const QWindowsWindow::WindowData obtained
= QWindowsWindow::WindowData::create(window, requested, window->title());
if (QWindowsContext::verboseIntegration || QWindowsContext::verboseWindows)
diff --git a/src/plugins/platforms/windows/qwindowskeymapper.cpp b/src/plugins/platforms/windows/qwindowskeymapper.cpp
index 56deb27442..924d604641 100644
--- a/src/plugins/platforms/windows/qwindowskeymapper.cpp
+++ b/src/plugins/platforms/windows/qwindowskeymapper.cpp
@@ -856,9 +856,15 @@ bool QWindowsKeyMapper::translateKeyEventInternal(QWindow *window, const MSG &ms
if (isNumpad && (nModifiers & AltAny)) {
code = winceKeyBend(msg.wParam);
} else if (!isDeadKey) {
- unsigned char kbdBuffer[256]; // Will hold the complete keyboard state
- GetKeyboardState(kbdBuffer);
- code = toKeyOrUnicode(msg.wParam, scancode, kbdBuffer);
+ // QTBUG-8764, QTBUG-10032
+ // Can't call toKeyOrUnicode because that would call ToUnicode, and, if a dead key
+ // is pressed at the moment, Windows would NOT use it to compose a character for the next
+ // WM_CHAR event.
+
+ // Instead, use MapVirtualKey, which will provide adequate values.
+ code = MapVirtualKey(msg.wParam, MAPVK_VK_TO_CHAR);
+ if (code < 0x20 || code == 0x7f) // The same logic as in toKeyOrUnicode()
+ code = winceKeyBend(msg.wParam);
}
// Invert state logic:
@@ -1120,7 +1126,7 @@ QList<int> QWindowsKeyMapper::possibleKeys(const QKeyEvent *e) const
}
result << int(baseKey + keyMods); // The base key is _always_ valid, of course
- for (int i = 1; i < NumMods; ++i) {
+ for (size_t i = 1; i < NumMods; ++i) {
Qt::KeyboardModifiers neededMods = ModsTbl[i];
quint32 key = kbItem.qtKey[i];
if (key && key != baseKey && ((keyMods & neededMods) == neededMods))
diff --git a/src/plugins/platforms/windows/qwindowsmime.cpp b/src/plugins/platforms/windows/qwindowsmime.cpp
index 7fb32d3513..a8bacd631d 100644
--- a/src/plugins/platforms/windows/qwindowsmime.cpp
+++ b/src/plugins/platforms/windows/qwindowsmime.cpp
@@ -703,14 +703,14 @@ QWindowsMimeURI::QWindowsMimeURI()
bool QWindowsMimeURI::canConvertFromMime(const FORMATETC &formatetc, const QMimeData *mimeData) const
{
- if (getCf(formatetc) == CF_HDROP) {
+ if (mimeData->hasUrls() && getCf(formatetc) == CF_HDROP) {
QList<QUrl> urls = mimeData->urls();
for (int i=0; i<urls.size(); i++) {
if (!urls.at(i).toLocalFile().isEmpty())
return true;
}
}
- return (getCf(formatetc) == CF_INETURL_W || getCf(formatetc) == CF_INETURL) && mimeData->hasFormat(QStringLiteral("text/uri-list"));
+ return (getCf(formatetc) == CF_INETURL_W || getCf(formatetc) == CF_INETURL) && mimeData->hasUrls();
}
bool QWindowsMimeURI::convertFromMime(const FORMATETC &formatetc, const QMimeData *mimeData, STGMEDIUM *pmedium) const
diff --git a/src/plugins/platforms/windows/qwindowsmousehandler.cpp b/src/plugins/platforms/windows/qwindowsmousehandler.cpp
index e1f4f4b143..dd16ea1c6f 100644
--- a/src/plugins/platforms/windows/qwindowsmousehandler.cpp
+++ b/src/plugins/platforms/windows/qwindowsmousehandler.cpp
@@ -49,6 +49,7 @@
#include <qpa/qwindowsysteminterface.h>
#include <QtGui/QGuiApplication>
#include <QtGui/QScreen>
+#include <QtGui/QWindow>
#include <QtCore/QDebug>
#include <QtCore/QScopedArrayPointer>
@@ -236,6 +237,9 @@ bool QWindowsMouseHandler::translateMouseEvent(QWindow *window, HWND hwnd,
platformWindow->setFlag(QWindowsWindow::AutoMouseCapture);
if (QWindowsContext::verboseEvents)
qDebug() << "Automatic mouse capture " << window;
+ // Implement "Click to focus" for native child windows.
+ if (!window->isTopLevel() && QGuiApplication::focusWindow() != window)
+ window->requestActivate();
} else if (platformWindow->hasMouseCapture()
&& platformWindow->testFlag(QWindowsWindow::AutoMouseCapture)
&& (msg.message == WM_LBUTTONUP || msg.message == WM_MBUTTONUP
diff --git a/src/plugins/platforms/windows/qwindowsservices.cpp b/src/plugins/platforms/windows/qwindowsservices.cpp
index bcae2e0816..250fea56b1 100644
--- a/src/plugins/platforms/windows/qwindowsservices.cpp
+++ b/src/plugins/platforms/windows/qwindowsservices.cpp
@@ -44,6 +44,7 @@
#include <QtCore/QUrl>
#include <QtCore/QDebug>
+#include <QtCore/QDir>
#include <shlobj.h>
#ifndef Q_OS_WINCE
@@ -57,7 +58,8 @@ enum { debug = 0 };
static inline bool shellExecute(const QString &file)
{
#ifndef Q_OS_WINCE
- const quintptr result = (quintptr)ShellExecute(0, 0, (wchar_t*)file.utf16(), 0, 0, SW_SHOWNORMAL);
+ const QString nativeFilePath = QDir::toNativeSeparators(file);
+ const quintptr result = (quintptr)ShellExecute(0, 0, (wchar_t*)nativeFilePath.utf16(), 0, 0, SW_SHOWNORMAL);
// ShellExecute returns a value greater than 32 if successful
if (result <= 32) {
qWarning("ShellExecute '%s' failed (error %s).", qPrintable(file), qPrintable(QString::number(result)));
diff --git a/src/plugins/platforms/windows/qwindowswindow.cpp b/src/plugins/platforms/windows/qwindowswindow.cpp
index 60b455bac9..6cbe3e8cf7 100644
--- a/src/plugins/platforms/windows/qwindowswindow.cpp
+++ b/src/plugins/platforms/windows/qwindowswindow.cpp
@@ -302,7 +302,7 @@ struct WindowCreationData
tool(false), embedded(false), hasAlpha(false) {}
void fromWindow(const QWindow *w, const Qt::WindowFlags flags, unsigned creationFlags = 0);
- inline WindowData create(const QWindow *w, const QRect &geometry, QString title) const;
+ inline WindowData create(const QWindow *w, const WindowData &data, QString title) const;
inline void applyWindowFlags(HWND hwnd) const;
void initialize(HWND h, bool frameChange, qreal opacityLevel) const;
@@ -454,7 +454,7 @@ void WindowCreationData::fromWindow(const QWindow *w, const Qt::WindowFlags flag
}
QWindowsWindow::WindowData
- WindowCreationData::create(const QWindow *w, const QRect &geometry, QString title) const
+ WindowCreationData::create(const QWindow *w, const WindowData &data, QString title) const
{
typedef QSharedPointer<QWindowCreationContext> QWindowCreationContextPtr;
@@ -474,7 +474,7 @@ QWindowsWindow::WindowData
const QString windowClassName = QWindowsContext::instance()->registerWindowClass(w, isGL);
- QRect rect = QPlatformWindow::initialGeometry(w, geometry, defaultWindowWidth, defaultWindowHeight);
+ QRect rect = QPlatformWindow::initialGeometry(w, data.geometry, defaultWindowWidth, defaultWindowHeight);
if (title.isEmpty() && (result.flags & Qt::WindowTitleHint))
title = topLevel ? qAppName() : w->objectName();
@@ -482,24 +482,30 @@ QWindowsWindow::WindowData
const wchar_t *titleUtf16 = reinterpret_cast<const wchar_t *>(title.utf16());
const wchar_t *classNameUtf16 = reinterpret_cast<const wchar_t *>(windowClassName.utf16());
- // Capture events before CreateWindowEx() returns.
- const QWindowCreationContextPtr context(new QWindowCreationContext(w, rect, style, exStyle));
+ // Capture events before CreateWindowEx() returns. The context is cleared in
+ // the QWindowsWindow constructor.
+ const QWindowCreationContextPtr context(new QWindowCreationContext(w, rect, data.customMargins, style, exStyle));
QWindowsContext::instance()->setWindowCreationContext(context);
+ if (context->frameX < 0)
+ context->frameX = 0;
+ if (context->frameY < 0)
+ context->frameY = 0;
+
if (QWindowsContext::verboseWindows)
qDebug().nospace()
<< "CreateWindowEx: " << w << *this
<< " class=" <<windowClassName << " title=" << title
<< "\nrequested: " << rect << ": "
<< context->frameWidth << 'x' << context->frameHeight
- << '+' << context->frameX << '+' << context->frameY;
+ << '+' << context->frameX << '+' << context->frameY
+ << " custom margins: " << context->customMargins;
result.hwnd = CreateWindowEx(exStyle, classNameUtf16, titleUtf16,
style,
context->frameX, context->frameY,
context->frameWidth, context->frameHeight,
parentHandle, NULL, appinst, NULL);
- QWindowsContext::instance()->setWindowCreationContext(QWindowCreationContextPtr());
if (QWindowsContext::verboseWindows)
qDebug().nospace()
<< "CreateWindowEx: returns " << w << ' ' << result.hwnd << " obtained geometry: "
@@ -513,6 +519,7 @@ QWindowsWindow::WindowData
result.geometry = context->obtainedGeometry;
result.frame = context->margins;
result.embedded = embedded;
+ result.customMargins = context->customMargins;
return result;
}
@@ -551,6 +558,8 @@ void WindowCreationData::initialize(HWND hwnd, bool frameChange, qreal opacityLe
qWarning() << "QWidget: Incompatible window flags: the window can't be on top and on bottom at the same time";
} else if (flags & Qt::WindowStaysOnBottomHint) {
SetWindowPos(hwnd, HWND_BOTTOM, 0, 0, 0, 0, swpFlags);
+ } else if (frameChange) { // Force WM_NCCALCSIZE with wParam=1 in case of custom margins.
+ SetWindowPos(hwnd, 0, 0, 0, 0, 0, swpFlags);
}
if (flags & (Qt::CustomizeWindowHint|Qt::WindowTitleHint)) {
HMENU systemMenu = GetSystemMenu(hwnd, FALSE);
@@ -579,9 +588,10 @@ void WindowCreationData::initialize(HWND hwnd, bool frameChange, qreal opacityLe
#define QWINDOWSIZE_MAX ((1<<24)-1)
-QWindowsGeometryHint::QWindowsGeometryHint(const QWindow *w) :
+QWindowsGeometryHint::QWindowsGeometryHint(const QWindow *w, const QMargins &cm) :
minimumSize(w->minimumSize()),
- maximumSize(w->maximumSize())
+ maximumSize(w->maximumSize()),
+ customMargins(cm)
{
}
@@ -611,6 +621,33 @@ QMargins QWindowsGeometryHint::frame(DWORD style, DWORD exStyle)
return result;
}
+bool QWindowsGeometryHint::handleCalculateSize(const QMargins &customMargins, const MSG &msg, LRESULT *result)
+{
+#ifndef Q_OS_WINCE
+ // NCCALCSIZE_PARAMS structure if wParam==TRUE
+ if (!msg.wParam || customMargins.isNull())
+ return false;
+ *result = DefWindowProc(msg.hwnd, msg.message, msg.wParam, msg.lParam);
+ NCCALCSIZE_PARAMS *ncp = reinterpret_cast<NCCALCSIZE_PARAMS *>(msg.lParam);
+ const RECT oldClientArea = ncp->rgrc[0];
+ ncp->rgrc[0].left += customMargins.left();
+ ncp->rgrc[0].top += customMargins.top();
+ ncp->rgrc[0].right -= customMargins.right();
+ ncp->rgrc[0].bottom -= customMargins.bottom();
+ result = 0;
+ if (QWindowsContext::verboseWindows)
+ qDebug() << __FUNCTION__ << oldClientArea << '+' << customMargins << "-->"
+ << ncp->rgrc[0] << ' ' << ncp->rgrc[1] << ' ' << ncp->rgrc[2]
+ << ' ' << ncp->lppos->cx << ',' << ncp->lppos->cy;
+ return true;
+#else
+ Q_UNUSED(customMargins)
+ Q_UNUSED(msg)
+ Q_UNUSED(result)
+ return false;
+#endif
+}
+
#ifndef Q_OS_WINCE
void QWindowsGeometryHint::applyToMinMaxInfo(HWND hwnd, MINMAXINFO *mmi) const
{
@@ -627,8 +664,8 @@ void QWindowsGeometryHint::applyToMinMaxInfo(DWORD style, DWORD exStyle, MINMAXI
<< " in " << *mmi;
const QMargins margins = QWindowsGeometryHint::frame(style, exStyle);
- const int frameWidth = margins.left() + margins.right();
- const int frameHeight = margins.top() + margins.bottom();
+ const int frameWidth = margins.left() + margins.right() + customMargins.left() + customMargins.right();
+ const int frameHeight = margins.top() + margins.bottom() + customMargins.top() + customMargins.bottom();
if (minimumSize.width() > 0)
mmi->ptMinTrackSize.x = minimumSize.width() + frameWidth;
if (minimumSize.height() > 0)
@@ -677,10 +714,11 @@ bool QWindowsGeometryHint::positionIncludesFrame(const QWindow *w)
QWindowCreationContext::QWindowCreationContext(const QWindow *w,
const QRect &geometry,
+ const QMargins &cm,
DWORD style_, DWORD exStyle_) :
- geometryHint(w), style(style_), exStyle(exStyle_),
+ geometryHint(w, cm), style(style_), exStyle(exStyle_),
requestedGeometry(geometry), obtainedGeometry(geometry),
- margins(QWindowsGeometryHint::frame(style, exStyle)),
+ margins(QWindowsGeometryHint::frame(style, exStyle)), customMargins(cm),
frameX(CW_USEDEFAULT), frameY(CW_USEDEFAULT),
frameWidth(CW_USEDEFAULT), frameHeight(CW_USEDEFAULT)
{
@@ -691,14 +729,16 @@ QWindowCreationContext::QWindowCreationContext(const QWindow *w,
if (geometry.isValid()) {
frameX = geometry.x();
frameY = geometry.y();
- frameWidth = margins.left() + geometry.width() + margins.right();
- frameHeight = margins.top() + geometry.height() + margins.bottom();
+ const QMargins effectiveMargins = margins + customMargins;
+ frameWidth = effectiveMargins.left() + geometry.width() + effectiveMargins.right();
+ frameHeight = effectiveMargins.top() + geometry.height() + effectiveMargins.bottom();
const bool isDefaultPosition = !frameX && !frameY && w->isTopLevel();
if (!QWindowsGeometryHint::positionIncludesFrame(w) && !isDefaultPosition) {
- frameX -= margins.left();
- frameY -= margins.top();
+ frameX -= effectiveMargins.left();
+ frameY -= effectiveMargins.top();
}
}
+
if (QWindowsContext::verboseWindows)
qDebug().nospace()
<< __FUNCTION__ << ' ' << w << geometry
@@ -706,7 +746,8 @@ QWindowCreationContext::QWindowCreationContext(const QWindow *w,
<< " frame: " << frameWidth << 'x' << frameHeight << '+'
<< frameX << '+' << frameY
<< " min" << geometryHint.minimumSize
- << " max" << geometryHint.maximumSize;
+ << " max" << geometryHint.maximumSize
+ << " custom margins " << customMargins;
}
/*!
@@ -738,9 +779,6 @@ QWindowsWindow::QWindowsWindow(QWindow *aWindow, const WindowData &data) :
m_hdc(0),
m_windowState(Qt::WindowNoState),
m_opacity(1.0),
-#ifndef QT_NO_CURSOR
- m_cursor(QWindowsScreen::screenOf(aWindow)->windowsCursor()->standardWindowCursor()),
-#endif
m_dropTarget(0),
m_savedStyle(0),
m_format(aWindow->format()),
@@ -755,6 +793,8 @@ QWindowsWindow::QWindowsWindow(QWindow *aWindow, const WindowData &data) :
{
if (aWindow->surfaceType() == QWindow::OpenGLSurface)
setFlag(OpenGLSurface);
+ // Clear the creation context as the window can be found in QWindowsContext's map.
+ QWindowsContext::instance()->setWindowCreationContext(QSharedPointer<QWindowCreationContext>());
QWindowsContext::instance()->addWindow(m_data.hwnd, this);
if (aWindow->isTopLevel()) {
switch (aWindow->type()) {
@@ -881,8 +921,9 @@ QWindowsWindow::WindowData
{
WindowCreationData creationData;
creationData.fromWindow(w, parameters.flags);
- WindowData result = creationData.create(w, parameters.geometry, title);
- creationData.initialize(result.hwnd, false, 1);
+ WindowData result = creationData.create(w, parameters, title);
+ // Force WM_NCCALCSIZE (with wParam=1) via SWP_FRAMECHANGED for custom margin.
+ creationData.initialize(result.hwnd, !parameters.customMargins.isNull(), 1);
return result;
}
@@ -1069,7 +1110,7 @@ void QWindowsWindow::setGeometry(const QRect &rectIn)
const QSize newSize = rect.size();
// Check on hint.
if (newSize != oldSize) {
- const QWindowsGeometryHint hint(window());
+ const QWindowsGeometryHint hint(window(), m_data.customMargins);
if (!hint.validSize(newSize)) {
qWarning("%s: Attempt to set a size (%dx%d) violating the constraints"
"(%dx%d - %dx%d) on window '%s'.", __FUNCTION__,
@@ -1087,14 +1128,19 @@ void QWindowsWindow::setGeometry(const QRect &rectIn)
if (m_data.geometry != rect) {
qWarning("%s: Unable to set geometry %dx%d+%d+%d on '%s'."
" Resulting geometry: %dx%d+%d+%d "
- "(frame: %d, %d, %d, %d).",
+ "(frame: %d, %d, %d, %d, custom margin: %d, %d, %d, %d"
+ ", minimum size: %dx%d, maximum size: %dx%d).",
__FUNCTION__,
rect.width(), rect.height(), rect.x(), rect.y(),
qPrintable(window()->objectName()),
m_data.geometry.width(), m_data.geometry.height(),
m_data.geometry.x(), m_data.geometry.y(),
m_data.frame.left(), m_data.frame.top(),
- m_data.frame.right(), m_data.frame.bottom());
+ m_data.frame.right(), m_data.frame.bottom(),
+ m_data.customMargins.left(), m_data.customMargins.top(),
+ m_data.customMargins.right(), m_data.customMargins.bottom(),
+ window()->minimumWidth(), window()->minimumHeight(),
+ window()->maximumWidth(), window()->maximumHeight());
}
} else {
QPlatformWindow::setGeometry(rect);
@@ -1172,7 +1218,7 @@ QRect QWindowsWindow::frameGeometry_sys() const
QRect QWindowsWindow::geometry_sys() const
{
- return frameGeometry_sys() - frameMargins();
+ return frameGeometry_sys().marginsRemoved(frameMargins());
}
/*!
@@ -1499,7 +1545,7 @@ QMargins QWindowsWindow::frameMargins() const
m_data.frame = QWindowsGeometryHint::frame(style(), exStyle());
clearFlag(FrameDirty);
}
- return m_data.frame;
+ return m_data.frame + m_data.customMargins;
}
void QWindowsWindow::setOpacity(qreal level)
@@ -1657,13 +1703,23 @@ void QWindowsWindow::setFrameStrutEventsEnabled(bool enabled)
#ifndef Q_OS_WINCE // maybe available on some SDKs revisit WM_GETMINMAXINFO
void QWindowsWindow::getSizeHints(MINMAXINFO *mmi) const
{
- const QWindowsGeometryHint hint(window());
+ const QWindowsGeometryHint hint(window(), m_data.customMargins);
hint.applyToMinMaxInfo(m_data.hwnd, mmi);
if (QWindowsContext::verboseWindows)
qDebug() << __FUNCTION__ << window() << *mmi;
}
#endif // !Q_OS_WINCE
+// Return the default cursor (Arrow) from QWindowsCursor's cache.
+static inline QWindowsWindowCursor defaultCursor(const QWindow *w)
+{
+ if (QScreen *screen = w->screen())
+ if (const QPlatformScreen *platformScreen = screen->handle())
+ if (QPlatformCursor *cursor = platformScreen->cursor())
+ return static_cast<QWindowsCursor *>(cursor)->standardWindowCursor(Qt::ArrowCursor);
+ return QWindowsWindowCursor(Qt::ArrowCursor);
+}
+
/*!
\brief Applies to cursor property set on the window to the global cursor.
@@ -1673,20 +1729,45 @@ void QWindowsWindow::getSizeHints(MINMAXINFO *mmi) const
void QWindowsWindow::applyCursor()
{
#ifndef QT_NO_CURSOR
- SetCursor(m_cursor.handle());
+ if (m_cursor.isNull()) { // Recurse up to parent with non-null cursor. Set default for toplevel.
+ if (const QWindow *p = window()->parent()) {
+ QWindowsWindow::baseWindowOf(p)->applyCursor();
+ } else {
+ SetCursor(defaultCursor(window()).handle());
+ }
+ } else {
+ SetCursor(m_cursor.handle());
+ }
#endif
}
+// Check whether to apply a new cursor. Either the window in question is
+// currently under mouse, or it is the parent of the window under mouse and
+// there is no other window with an explicitly set cursor in-between.
+static inline bool applyNewCursor(const QWindow *w)
+{
+ const QWindow *underMouse = QWindowsContext::instance()->windowUnderMouse();
+ if (underMouse == w)
+ return true;
+ for (const QWindow *p = underMouse; p ; p = p->parent()) {
+ if (p == w)
+ return true;
+ if (!QWindowsWindow::baseWindowOf(p)->cursor().isNull())
+ return false;
+ }
+ return false;
+}
+
void QWindowsWindow::setCursor(const QWindowsWindowCursor &c)
{
#ifndef QT_NO_CURSOR
if (c.handle() != m_cursor.handle()) {
- const bool underMouse = QWindowsContext::instance()->windowUnderMouse() == window();
+ const bool apply = applyNewCursor(window());
if (QWindowsContext::verboseWindows)
qDebug() << window() << __FUNCTION__ << "Shape=" << c.cursor().shape()
- << " isWUM=" << underMouse;
+ << " doApply=" << apply;
m_cursor = c;
- if (underMouse)
+ if (apply)
applyCursor();
}
#endif
@@ -1859,4 +1940,32 @@ void QWindowsWindow::setWindowIcon(const QIcon &icon)
}
}
+/*!
+ \brief Sets custom margins to be added to the default margins determined by
+ the windows style in the handling of the WM_NCCALCSIZE message.
+
+ This is currently used to give the Aero-style QWizard a smaller top margin.
+ The property can be set using QPlatformNativeInterface::setWindowProperty() or,
+ before platform window creation, by setting a dynamic property
+ on the QWindow (see QWindowsIntegration::createPlatformWindow()).
+*/
+
+void QWindowsWindow::setCustomMargins(const QMargins &newCustomMargins)
+{
+ if (newCustomMargins != m_data.customMargins) {
+ const QMargins oldCustomMargins = m_data.customMargins;
+ m_data.customMargins = newCustomMargins;
+ // Re-trigger WM_NCALCSIZE with wParam=1 by passing SWP_FRAMECHANGED
+ const QRect currentFrameGeometry = frameGeometry_sys();
+ const QPoint topLeft = currentFrameGeometry.topLeft();
+ QRect newFrame = currentFrameGeometry.marginsRemoved(oldCustomMargins) + m_data.customMargins;
+ newFrame.moveTo(topLeft);
+ setFlag(FrameDirty);
+ if (QWindowsContext::verboseWindows)
+ qDebug() << __FUNCTION__ << oldCustomMargins << "->" << newCustomMargins
+ << currentFrameGeometry << "->" << newFrame;
+ SetWindowPos(m_data.hwnd, 0, newFrame.x(), newFrame.y(), newFrame.width(), newFrame.height(), SWP_NOZORDER | SWP_FRAMECHANGED);
+ }
+}
+
QT_END_NAMESPACE
diff --git a/src/plugins/platforms/windows/qwindowswindow.h b/src/plugins/platforms/windows/qwindowswindow.h
index f3b480b0af..87397f1c1d 100644
--- a/src/plugins/platforms/windows/qwindowswindow.h
+++ b/src/plugins/platforms/windows/qwindowswindow.h
@@ -67,8 +67,9 @@ class QWindowsEGLStaticContext;
struct QWindowsGeometryHint
{
QWindowsGeometryHint() {}
- explicit QWindowsGeometryHint(const QWindow *w);
+ explicit QWindowsGeometryHint(const QWindow *w, const QMargins &customMargins);
static QMargins frame(DWORD style, DWORD exStyle);
+ static bool handleCalculateSize(const QMargins &customMargins, const MSG &msg, LRESULT *result);
#ifndef Q_OS_WINCE //MinMax maybe define struct if not available
void applyToMinMaxInfo(DWORD style, DWORD exStyle, MINMAXINFO *mmi) const;
void applyToMinMaxInfo(HWND hwnd, MINMAXINFO *mmi) const;
@@ -84,11 +85,13 @@ struct QWindowsGeometryHint
QSize minimumSize;
QSize maximumSize;
+ QMargins customMargins;
};
struct QWindowCreationContext
{
QWindowCreationContext(const QWindow *w, const QRect &r,
+ const QMargins &customMargins,
DWORD style, DWORD exStyle);
#ifndef Q_OS_WINCE //MinMax maybe define struct if not available
void applyToMinMaxInfo(MINMAXINFO *mmi) const
@@ -101,6 +104,7 @@ struct QWindowCreationContext
QRect requestedGeometry;
QRect obtainedGeometry;
QMargins margins;
+ QMargins customMargins; // User-defined, additional frame for WM_NCCALCSIZE
int frameX; // Passed on to CreateWindowEx(), including frame.
int frameY;
int frameWidth;
@@ -137,6 +141,7 @@ public:
Qt::WindowFlags flags;
QRect geometry;
QMargins frame; // Do not use directly for windows, see FrameDirty.
+ QMargins customMargins; // User-defined, additional frame for NCCALCSIZE
HWND hwnd;
bool embedded;
@@ -191,6 +196,9 @@ public:
void setFrameStrutEventsEnabled(bool enabled);
bool frameStrutEventsEnabled() const { return testFlag(FrameStrutEventsEnabled); }
+ QMargins customMargins() const { return m_data.customMargins; }
+ void setCustomMargins(const QMargins &m);
+
#ifdef QT_OPENGL_ES_2
EGLSurface eglSurfaceHandle() const { return m_eglSurface;}
EGLSurface ensureEglSurfaceHandle(const QWindowsEGLStaticContextPtr &staticContext, EGLConfig config);
@@ -290,17 +298,6 @@ private:
HICON m_iconBig;
};
-// Conveniences for window frames.
-inline QRect operator+(const QRect &r, const QMargins &m)
-{
- return r.adjusted(-m.left(), -m.top(), m.right(), m.bottom());
-}
-
-inline QRect operator-(const QRect &r, const QMargins &m)
-{
- return r.adjusted(m.left(), m.top(), -m.right(), -m.bottom());
-}
-
// Debug
QDebug operator<<(QDebug d, const RECT &r);
#ifndef Q_OS_WINCE // maybe available on some SDKs revisit WM_GETMINMAXINFO/WM_NCCALCSIZE
@@ -371,4 +368,6 @@ inline void QWindowsWindow::destroyIcon()
QT_END_NAMESPACE
+Q_DECLARE_METATYPE(QMargins)
+
#endif // QWINDOWSWINDOW_H
diff --git a/src/plugins/platforms/windows/windows.pro b/src/plugins/platforms/windows/windows.pro
index ff162e2d41..3aa9caaa0f 100644
--- a/src/plugins/platforms/windows/windows.pro
+++ b/src/plugins/platforms/windows/windows.pro
@@ -102,12 +102,8 @@ contains(QT_CONFIG, opengles2) {
}
}
-# Enable access to HB_Face in harfbuzz includes included by qfontengine_p.h.
-DEFINES *= QT_COMPILES_IN_HARFBUZZ
-
contains(QT_CONFIG, freetype) {
DEFINES *= QT_NO_FONTCONFIG
- DEFINES *= QT_COMPILES_IN_HARFBUZZ
QT_FREETYPE_DIR = $$QT_SOURCE_TREE/src/3rdparty/freetype
HEADERS += \
diff --git a/src/plugins/platforms/xcb/qglxintegration.cpp b/src/plugins/platforms/xcb/qglxintegration.cpp
index 2a6ef5a6ee..516b35dac8 100644
--- a/src/plugins/platforms/xcb/qglxintegration.cpp
+++ b/src/plugins/platforms/xcb/qglxintegration.cpp
@@ -50,6 +50,7 @@
#include <GL/glx.h>
#include <QtGui/QOpenGLContext>
+#include <QtGui/QOffscreenSurface>
#include "qglxintegration.h"
#include <QtPlatformSupport/private/qglxconvenience_p.h>
@@ -70,6 +71,10 @@ typedef GLXContext (*glXCreateContextAttribsARBProc)(Display*, GLXFBConfig, GLXC
#define GLX_CONTEXT_COMPATIBILITY_PROFILE_BIT_ARB 0x00000002
#endif
+#ifndef GLX_CONTEXT_ES2_PROFILE_BIT_EXT
+#define GLX_CONTEXT_ES2_PROFILE_BIT_EXT 0x00000004
+#endif
+
#ifndef GLX_CONTEXT_PROFILE_MASK_ARB
#define GLX_CONTEXT_PROFILE_MASK_ARB 0x9126
#endif
@@ -122,46 +127,53 @@ static void updateFormatFromContext(QSurfaceFormat &format)
}
format.setProfile(QSurfaceFormat::NoProfile);
+ format.setOption(QSurfaceFormat::FormatOptions());
- const int version = (major << 8) + minor;
- if (version < 0x0300) {
- format.setProfile(QSurfaceFormat::NoProfile);
- format.setOption(QSurfaceFormat::DeprecatedFunctions);
- return;
- }
-
- // Version 3.0 onwards - check if it includes deprecated functionality or is
- // a debug context
- GLint value = 0;
- glGetIntegerv(GL_CONTEXT_FLAGS, &value);
- if (!(value & GL_CONTEXT_FLAG_FORWARD_COMPATIBLE_BIT))
- format.setOption(QSurfaceFormat::DeprecatedFunctions);
- if (value & GL_CONTEXT_FLAG_DEBUG_BIT)
- format.setOption(QSurfaceFormat::DebugContext);
- if (version < 0x0302)
- return;
-
- // Version 3.2 and newer have a profile
- value = 0;
- glGetIntegerv(GL_CONTEXT_PROFILE_MASK, &value);
+ if (format.renderableType() == QSurfaceFormat::OpenGL) {
+ if (format.version() < qMakePair(3, 0)) {
+ format.setOption(QSurfaceFormat::DeprecatedFunctions);
+ return;
+ }
- if (value & GL_CONTEXT_CORE_PROFILE_BIT)
- format.setProfile(QSurfaceFormat::CoreProfile);
- else if (value & GL_CONTEXT_COMPATIBILITY_PROFILE_BIT)
- format.setProfile(QSurfaceFormat::CompatibilityProfile);
+ // Version 3.0 onwards - check if it includes deprecated functionality or is
+ // a debug context
+ GLint value = 0;
+ glGetIntegerv(GL_CONTEXT_FLAGS, &value);
+ if (!(value & GL_CONTEXT_FLAG_FORWARD_COMPATIBLE_BIT))
+ format.setOption(QSurfaceFormat::DeprecatedFunctions);
+ if (value & GL_CONTEXT_FLAG_DEBUG_BIT)
+ format.setOption(QSurfaceFormat::DebugContext);
+ if (format.version() < qMakePair(3, 2))
+ return;
+
+ // Version 3.2 and newer have a profile
+ value = 0;
+ glGetIntegerv(GL_CONTEXT_PROFILE_MASK, &value);
+
+ if (value & GL_CONTEXT_CORE_PROFILE_BIT)
+ format.setProfile(QSurfaceFormat::CoreProfile);
+ else if (value & GL_CONTEXT_COMPATIBILITY_PROFILE_BIT)
+ format.setProfile(QSurfaceFormat::CompatibilityProfile);
+ }
}
QGLXContext::QGLXContext(QXcbScreen *screen, const QSurfaceFormat &format, QPlatformOpenGLContext *share)
: QPlatformOpenGLContext()
, m_screen(screen)
, m_context(0)
+ , m_shareContext(0)
, m_format(format)
+ , m_isPBufferCurrent(false)
{
- m_shareContext = 0;
+ if (m_format.renderableType() == QSurfaceFormat::DefaultRenderableType)
+ m_format.setRenderableType(QSurfaceFormat::OpenGL);
+ if (m_format.renderableType() != QSurfaceFormat::OpenGL && m_format.renderableType() != QSurfaceFormat::OpenGLES)
+ return;
+
if (share)
m_shareContext = static_cast<const QGLXContext*>(share)->glxContext();
- GLXFBConfig config = qglx_findConfig(DISPLAY_FROM_XCB(screen),screen->screenNumber(),format);
+ GLXFBConfig config = qglx_findConfig(DISPLAY_FROM_XCB(screen),screen->screenNumber(),m_format);
XVisualInfo *visualInfo = 0;
Window window = 0; // Temporary window used to query OpenGL context
@@ -174,17 +186,31 @@ QGLXContext::QGLXContext(QXcbScreen *screen, const QSurfaceFormat &format, QPlat
bool supportsProfiles = glxExt.contains("GLX_ARB_create_context_profile");
// Use glXCreateContextAttribsARB if available
- if (glxExt.contains("GLX_ARB_create_context") && glXCreateContextAttribsARB != 0) {
+ // Also, GL ES context creation requires GLX_EXT_create_context_es2_profile
+ if (glxExt.contains("GLX_ARB_create_context") && glXCreateContextAttribsARB != 0
+ && (m_format.renderableType() != QSurfaceFormat::OpenGLES || (supportsProfiles && glxExt.contains("GLX_EXT_create_context_es2_profile")))) {
// Try to create an OpenGL context for each known OpenGL version in descending
// order from the requested version.
const int requestedVersion = format.majorVersion() * 10 + qMin(format.minorVersion(), 9);
QVector<int> glVersions;
- if (requestedVersion > 43)
- glVersions << requestedVersion;
+ if (m_format.renderableType() == QSurfaceFormat::OpenGL) {
+ if (requestedVersion > 43)
+ glVersions << requestedVersion;
+
+ // Don't bother with versions below 2.0
+ glVersions << 43 << 42 << 41 << 40 << 33 << 32 << 31 << 30 << 21 << 20;
+ } else if (m_format.renderableType() == QSurfaceFormat::OpenGLES) {
+ if (requestedVersion > 30)
+ glVersions << requestedVersion;
+
+ // Don't bother with versions below ES 2.0
+ glVersions << 30 << 20;
+ // ES does not support any format option
+ m_format.setOption(QSurfaceFormat::FormatOptions());
+ }
- // Don't bother with versions below 2.0
- glVersions << 43 << 42 << 41 << 40 << 33 << 32 << 31 << 30 << 21 << 20;
+ Q_ASSERT(glVersions.count() > 0);
for (int i = 0; !m_context && i < glVersions.count(); i++) {
const int version = glVersions[i];
@@ -198,25 +224,30 @@ QGLXContext::QGLXContext(QXcbScreen *screen, const QSurfaceFormat &format, QPlat
contextAttributes << GLX_CONTEXT_MAJOR_VERSION_ARB << majorVersion
<< GLX_CONTEXT_MINOR_VERSION_ARB << minorVersion;
- // If asking for OpenGL 3.2 or newer we should also specify a profile
- if (version >= 32 && supportsProfiles) {
- if (m_format.profile() == QSurfaceFormat::CoreProfile)
- contextAttributes << GLX_CONTEXT_PROFILE_MASK_ARB << GLX_CONTEXT_CORE_PROFILE_BIT_ARB;
- else
- contextAttributes << GLX_CONTEXT_PROFILE_MASK_ARB << GLX_CONTEXT_COMPATIBILITY_PROFILE_BIT_ARB;
- }
- int flags = 0;
+ if (m_format.renderableType() == QSurfaceFormat::OpenGL) {
+ // If asking for OpenGL 3.2 or newer we should also specify a profile
+ if (version >= 32 && supportsProfiles) {
+ if (m_format.profile() == QSurfaceFormat::CoreProfile)
+ contextAttributes << GLX_CONTEXT_PROFILE_MASK_ARB << GLX_CONTEXT_CORE_PROFILE_BIT_ARB;
+ else
+ contextAttributes << GLX_CONTEXT_PROFILE_MASK_ARB << GLX_CONTEXT_COMPATIBILITY_PROFILE_BIT_ARB;
+ }
+
+ int flags = 0;
- if (m_format.testOption(QSurfaceFormat::DebugContext))
- flags |= GLX_CONTEXT_DEBUG_BIT_ARB;
+ if (m_format.testOption(QSurfaceFormat::DebugContext))
+ flags |= GLX_CONTEXT_DEBUG_BIT_ARB;
- // A forward-compatible context may be requested for 3.0 and later
- if (version >= 30 && !m_format.testOption(QSurfaceFormat::DeprecatedFunctions))
- flags |= GLX_CONTEXT_FORWARD_COMPATIBLE_BIT_ARB;
+ // A forward-compatible context may be requested for 3.0 and later
+ if (version >= 30 && !m_format.testOption(QSurfaceFormat::DeprecatedFunctions))
+ flags |= GLX_CONTEXT_FORWARD_COMPATIBLE_BIT_ARB;
- if (flags != 0)
- contextAttributes << GLX_CONTEXT_FLAGS_ARB << flags;
+ if (flags != 0)
+ contextAttributes << GLX_CONTEXT_FLAGS_ARB << flags;
+ } else if (m_format.renderableType() == QSurfaceFormat::OpenGLES) {
+ contextAttributes << GLX_CONTEXT_PROFILE_MASK_ARB << GLX_CONTEXT_ES2_PROFILE_BIT_EXT;
+ }
contextAttributes << None;
@@ -232,6 +263,10 @@ QGLXContext::QGLXContext(QXcbScreen *screen, const QSurfaceFormat &format, QPlat
// Could not create a context using glXCreateContextAttribsARB, falling back to glXCreateNewContext.
if (!m_context) {
+ // requesting an OpenGL ES context requires glXCreateContextAttribsARB, so bail out
+ if (m_format.renderableType() == QSurfaceFormat::OpenGLES)
+ return;
+
m_context = glXCreateNewContext(DISPLAY_FROM_XCB(screen), config, GLX_RGBA_TYPE, m_shareContext, true);
if (!m_context && m_shareContext) {
// re-try without a shared glx context
@@ -243,11 +278,15 @@ QGLXContext::QGLXContext(QXcbScreen *screen, const QSurfaceFormat &format, QPlat
// Get the basic surface format details
if (m_context)
- m_format = qglx_surfaceFormatFromGLXFBConfig(DISPLAY_FROM_XCB(screen), config, m_context);
+ qglx_surfaceFormatFromGLXFBConfig(&m_format, DISPLAY_FROM_XCB(screen), config, m_context);
// Create a temporary window so that we can make the new context current
window = createDummyWindow(screen, config);
} else {
+ // requesting an OpenGL ES context requires glXCreateContextAttribsARB, so bail out
+ if (m_format.renderableType() == QSurfaceFormat::OpenGLES)
+ return;
+
// Note that m_format gets updated with the used surface format
visualInfo = qglx_findVisualInfo(DISPLAY_FROM_XCB(screen), screen->screenNumber(), &m_format);
if (!visualInfo)
@@ -286,19 +325,35 @@ bool QGLXContext::makeCurrent(QPlatformSurface *surface)
{
Q_ASSERT(surface->surface()->surfaceType() == QSurface::OpenGLSurface);
- GLXDrawable glxDrawable = static_cast<QXcbWindow *>(surface)->xcb_window();
-
- return glXMakeCurrent(DISPLAY_FROM_XCB(m_screen), glxDrawable, m_context);
+ QSurface::SurfaceClass surfaceClass = surface->surface()->surfaceClass();
+ if (surfaceClass == QSurface::Window) {
+ m_isPBufferCurrent = false;
+ QXcbWindow *window = static_cast<QXcbWindow *>(surface);
+ return glXMakeCurrent(DISPLAY_FROM_XCB(m_screen), window->xcb_window(), m_context);
+ } else if (surfaceClass == QSurface::Offscreen) {
+ m_isPBufferCurrent = true;
+ QGLXPbuffer *pbuffer = static_cast<QGLXPbuffer *>(surface);
+ return glXMakeContextCurrent(DISPLAY_FROM_XCB(m_screen), pbuffer->pbuffer(), pbuffer->pbuffer(), m_context);
+ }
+ return false;
}
void QGLXContext::doneCurrent()
{
- glXMakeCurrent(DISPLAY_FROM_XCB(m_screen), 0, 0);
+ if (m_isPBufferCurrent)
+ glXMakeContextCurrent(DISPLAY_FROM_XCB(m_screen), 0, 0, 0);
+ else
+ glXMakeCurrent(DISPLAY_FROM_XCB(m_screen), 0, 0);
+ m_isPBufferCurrent = false;
}
void QGLXContext::swapBuffers(QPlatformSurface *surface)
{
- GLXDrawable glxDrawable = static_cast<QXcbWindow *>(surface)->xcb_window();
+ GLXDrawable glxDrawable = 0;
+ if (surface->surface()->surfaceClass() == QSurface::Offscreen)
+ glxDrawable = static_cast<QGLXPbuffer *>(surface)->pbuffer();
+ else
+ glxDrawable = static_cast<QXcbWindow *>(surface)->xcb_window();
glXSwapBuffers(DISPLAY_FROM_XCB(m_screen), glxDrawable);
}
@@ -350,4 +405,36 @@ bool QGLXContext::isValid() const
return m_context != 0;
}
+
+QGLXPbuffer::QGLXPbuffer(QOffscreenSurface *offscreenSurface)
+ : QPlatformOffscreenSurface(offscreenSurface)
+ , m_format(offscreenSurface->requestedFormat())
+ , m_screen(static_cast<QXcbScreen *>(offscreenSurface->screen()->handle()))
+ , m_pbuffer(0)
+{
+ GLXFBConfig config = qglx_findConfig(DISPLAY_FROM_XCB(m_screen), m_screen->screenNumber(), m_format);
+
+ if (config) {
+ const int attributes[] = {
+ GLX_PBUFFER_WIDTH, offscreenSurface->size().width(),
+ GLX_PBUFFER_HEIGHT, offscreenSurface->size().height(),
+ GLX_LARGEST_PBUFFER, False,
+ GLX_PRESERVED_CONTENTS, False,
+ GLX_NONE
+ };
+
+ m_pbuffer = glXCreatePbuffer(DISPLAY_FROM_XCB(m_screen), config, attributes);
+
+ if (m_pbuffer)
+ qglx_surfaceFormatFromGLXFBConfig(&m_format, DISPLAY_FROM_XCB(m_screen), config);
+ }
+}
+
+QGLXPbuffer::~QGLXPbuffer()
+{
+ if (m_pbuffer)
+ glXDestroyPbuffer(DISPLAY_FROM_XCB(m_screen), m_pbuffer);
+}
+
+
QT_END_NAMESPACE
diff --git a/src/plugins/platforms/xcb/qglxintegration.h b/src/plugins/platforms/xcb/qglxintegration.h
index 98aee78b14..7116b2389d 100644
--- a/src/plugins/platforms/xcb/qglxintegration.h
+++ b/src/plugins/platforms/xcb/qglxintegration.h
@@ -46,6 +46,7 @@
#include "qxcbscreen.h"
#include <qpa/qplatformopenglcontext.h>
+#include <qpa/qplatformoffscreensurface.h>
#include <QtGui/QSurfaceFormat>
#include <QtCore/QMutex>
@@ -76,6 +77,25 @@ private:
GLXContext m_context;
GLXContext m_shareContext;
QSurfaceFormat m_format;
+ bool m_isPBufferCurrent;
+};
+
+
+class QGLXPbuffer : public QPlatformOffscreenSurface
+{
+public:
+ explicit QGLXPbuffer(QOffscreenSurface *offscreenSurface);
+ ~QGLXPbuffer();
+
+ QSurfaceFormat format() const { return m_format; }
+ bool isValid() const { return m_pbuffer != 0; }
+
+ GLXPbuffer pbuffer() const { return m_pbuffer; }
+
+private:
+ QSurfaceFormat m_format;
+ QXcbScreen *m_screen;
+ GLXPbuffer m_pbuffer;
};
QT_END_NAMESPACE
diff --git a/src/plugins/platforms/xcb/qxcbconnection.cpp b/src/plugins/platforms/xcb/qxcbconnection.cpp
index 4525cb8ccb..1504bd99d2 100644
--- a/src/plugins/platforms/xcb/qxcbconnection.cpp
+++ b/src/plugins/platforms/xcb/qxcbconnection.cpp
@@ -184,7 +184,7 @@ void QXcbConnection::updateScreens()
activeScreens << screen;
++screenNumber;
if (!primaryScreen && primary) {
- if (primary->output == XCB_NONE || outputs[i] == primary->output) {
+ if (m_primaryScreen == xcbScreenNumber && (primary->output == XCB_NONE || outputs[i] == primary->output)) {
primaryScreen = screen;
siblings.prepend(siblings.takeLast());
#ifdef Q_XCB_DEBUG
@@ -1066,7 +1066,7 @@ void QXcbConnection::processXcbEvents()
while (it != m_peekFuncs.end()) {
// These callbacks return true if the event is what they were
// waiting for, remove them from the list in that case.
- if ((*it)(event))
+ if ((*it)(this, event))
it = m_peekFuncs.erase(it);
else
++it;
@@ -1086,7 +1086,7 @@ void QXcbConnection::processXcbEvents()
// Indicate with a null event that the event the callbacks are waiting for
// is not in the queue currently.
Q_FOREACH (PeekFunc f, m_peekFuncs)
- f(0);
+ f(this, 0);
m_peekFuncs.clear();
xcb_flush(xcb_connection());
diff --git a/src/plugins/platforms/xcb/qxcbconnection.h b/src/plugins/platforms/xcb/qxcbconnection.h
index b499f75b78..f69a8a9f35 100644
--- a/src/plugins/platforms/xcb/qxcbconnection.h
+++ b/src/plugins/platforms/xcb/qxcbconnection.h
@@ -364,7 +364,7 @@ public:
template<typename T>
inline xcb_generic_event_t *checkEvent(T &checker);
- typedef bool (*PeekFunc)(xcb_generic_event_t *);
+ typedef bool (*PeekFunc)(QXcbConnection *, xcb_generic_event_t *);
void addPeekFunc(PeekFunc f);
inline xcb_timestamp_t time() const { return m_time; }
diff --git a/src/plugins/platforms/xcb/qxcbcursor.cpp b/src/plugins/platforms/xcb/qxcbcursor.cpp
index e29b21c9c8..ff40c6a9ab 100644
--- a/src/plugins/platforms/xcb/qxcbcursor.cpp
+++ b/src/plugins/platforms/xcb/qxcbcursor.cpp
@@ -287,8 +287,14 @@ QXcbCursor::QXcbCursor(QXcbConnection *conn, QXcbScreen *screen)
QXcbCursor::~QXcbCursor()
{
+ xcb_connection_t *conn = xcb_connection();
if (!--cursorCount)
- xcb_close_font(xcb_connection(), cursorFont);
+ xcb_close_font(conn, cursorFont);
+
+ foreach (xcb_cursor_t cursor, m_bitmapCursorMap)
+ xcb_free_cursor(conn, cursor);
+ foreach (xcb_cursor_t cursor, m_shapeCursorMap)
+ xcb_free_cursor(conn, cursor);
}
#ifndef QT_NO_CURSOR
@@ -300,18 +306,20 @@ void QXcbCursor::changeCursor(QCursor *cursor, QWindow *widget)
else
// No X11 cursor control when there is no widget under the cursor
return;
-
- xcb_cursor_t c;
- if (cursor->shape() == Qt::BitmapCursor) {
- qint64 id = cursor->pixmap().cacheKey();
- if (!m_bitmapCursorMap.contains(id))
- m_bitmapCursorMap.insert(id, createBitmapCursor(cursor));
- c = m_bitmapCursorMap.value(id);
- } else {
- int id = cursor->shape();
- if (!m_shapeCursorMap.contains(id))
- m_shapeCursorMap.insert(id, createFontCursor(cursor->shape()));
- c = m_shapeCursorMap.value(id);
+
+ xcb_cursor_t c = XCB_CURSOR_NONE;
+ if (cursor) {
+ if (cursor->shape() == Qt::BitmapCursor) {
+ qint64 id = cursor->pixmap().cacheKey();
+ if (!m_bitmapCursorMap.contains(id))
+ m_bitmapCursorMap.insert(id, createBitmapCursor(cursor));
+ c = m_bitmapCursorMap.value(id);
+ } else {
+ int id = cursor->shape();
+ if (!m_shapeCursorMap.contains(id))
+ m_shapeCursorMap.insert(id, createFontCursor(cursor->shape()));
+ c = m_shapeCursorMap.value(id);
+ }
}
w->setCursor(c);
diff --git a/src/plugins/platforms/xcb/qxcbintegration.cpp b/src/plugins/platforms/xcb/qxcbintegration.cpp
index 60acf1ff02..f0cabea43d 100644
--- a/src/plugins/platforms/xcb/qxcbintegration.cpp
+++ b/src/plugins/platforms/xcb/qxcbintegration.cpp
@@ -78,10 +78,12 @@
#elif defined(XCB_USE_EGL)
#include "qxcbeglsurface.h"
#include <QtPlatformSupport/private/qeglplatformcontext_p.h>
+#include <QtPlatformSupport/private/qeglpbuffer_p.h>
#endif
#include <QtGui/QOpenGLContext>
#include <QtGui/QScreen>
+#include <QtGui/QOffscreenSurface>
#ifndef QT_NO_ACCESSIBILITY
#include <qpa/qplatformaccessibility.h>
#ifndef QT_NO_ACCESSIBILITY_ATSPI_BRIDGE
@@ -165,7 +167,10 @@ public:
EGLSurface eglSurfaceForPlatformSurface(QPlatformSurface *surface)
{
- return static_cast<QXcbWindow *>(surface)->eglSurface()->surface();
+ if (surface->surface()->surfaceClass() == QSurface::Window)
+ return static_cast<QXcbWindow *>(surface)->eglSurface()->surface();
+ else
+ return static_cast<QEGLPbuffer *>(surface)->pbuffer();
}
private:
@@ -195,6 +200,20 @@ QPlatformBackingStore *QXcbIntegration::createPlatformBackingStore(QWindow *wind
return new QXcbBackingStore(window);
}
+QPlatformOffscreenSurface *QXcbIntegration::createPlatformOffscreenSurface(QOffscreenSurface *surface) const
+{
+#if defined(XCB_USE_GLX)
+ return new QGLXPbuffer(surface);
+#elif defined(XCB_USE_EGL)
+ QXcbScreen *screen = static_cast<QXcbScreen *>(surface->screen()->handle());
+ return new QEGLPbuffer(screen->connection()->egl_display(), surface->requestedFormat(), surface);
+#else
+ Q_UNUSED(surface);
+ qWarning("QXcbIntegration: Cannot create platform offscreen surface, neither GLX nor EGL are enabled");
+ return 0;
+#endif
+}
+
bool QXcbIntegration::hasCapability(QPlatformIntegration::Capability cap) const
{
switch (cap) {
@@ -209,6 +228,7 @@ bool QXcbIntegration::hasCapability(QPlatformIntegration::Capability cap) const
case ThreadedOpenGL: return m_connections.at(0)->supportsThreadedRendering();
case WindowMasks: return true;
case MultipleWindows: return true;
+ case ForeignWindows: return true;
default: return QPlatformIntegration::hasCapability(cap);
}
}
diff --git a/src/plugins/platforms/xcb/qxcbintegration.h b/src/plugins/platforms/xcb/qxcbintegration.h
index 1dd8d4576b..6db9d82cca 100644
--- a/src/plugins/platforms/xcb/qxcbintegration.h
+++ b/src/plugins/platforms/xcb/qxcbintegration.h
@@ -64,6 +64,8 @@ public:
#endif
QPlatformBackingStore *createPlatformBackingStore(QWindow *window) const;
+ QPlatformOffscreenSurface *createPlatformOffscreenSurface(QOffscreenSurface *surface) const;
+
bool hasCapability(Capability cap) const;
QAbstractEventDispatcher *guiThreadEventDispatcher() const;
diff --git a/src/plugins/platforms/xcb/qxcbkeyboard.cpp b/src/plugins/platforms/xcb/qxcbkeyboard.cpp
index bda54b4682..4ac60f6077 100644
--- a/src/plugins/platforms/xcb/qxcbkeyboard.cpp
+++ b/src/plugins/platforms/xcb/qxcbkeyboard.cpp
@@ -1081,6 +1081,7 @@ void QXcbKeyboard::handleKeyEvent(QWindow *window, QEvent::Type type, xcb_keycod
int qtcode = 0;
int count = chars.count();
QString string = translateKeySym(sym, state, qtcode, modifiers, chars, count);
+ string.truncate(count);
bool isAutoRepeat = false;
@@ -1102,7 +1103,7 @@ void QXcbKeyboard::handleKeyEvent(QWindow *window, QEvent::Type type, xcb_keycod
bool filtered = false;
if (inputContext) {
- QKeyEvent event(type, qtcode, modifiers, code, sym, state, string.left(count), isAutoRepeat, count);
+ QKeyEvent event(type, qtcode, modifiers, code, sym, state, string, isAutoRepeat, count);
event.setTimestamp(time);
filtered = inputContext->filterEvent(&event);
}
@@ -1114,7 +1115,7 @@ void QXcbKeyboard::handleKeyEvent(QWindow *window, QEvent::Type type, xcb_keycod
QWindowSystemInterface::handleContextMenuEvent(window, false, pos, globalPos, modifiers);
}
QWindowSystemInterface::handleExtendedKeyEvent(window, time, type, qtcode, modifiers,
- code, sym, state, string.left(count), isAutoRepeat);
+ code, sym, state, string, isAutoRepeat);
}
if (isAutoRepeat && type == QEvent::KeyRelease) {
@@ -1130,13 +1131,13 @@ void QXcbKeyboard::handleKeyEvent(QWindow *window, QEvent::Type type, xcb_keycod
}
if (!filtered && inputContext) {
- QKeyEvent event(QEvent::KeyPress, qtcode, modifiers, code, sym, state, string.left(count), isAutoRepeat, count);
+ QKeyEvent event(QEvent::KeyPress, qtcode, modifiers, code, sym, state, string, isAutoRepeat, count);
event.setTimestamp(time);
filtered = inputContext->filterEvent(&event);
}
if (!filtered)
QWindowSystemInterface::handleExtendedKeyEvent(window, time, QEvent::KeyPress, qtcode, modifiers,
- code, sym, state, string.left(count), isAutoRepeat);
+ code, sym, state, string, isAutoRepeat);
}
}
diff --git a/src/plugins/platforms/xcb/qxcbwindow.cpp b/src/plugins/platforms/xcb/qxcbwindow.cpp
index 11ce1126ae..5af6a9ec9d 100644
--- a/src/plugins/platforms/xcb/qxcbwindow.cpp
+++ b/src/plugins/platforms/xcb/qxcbwindow.cpp
@@ -122,6 +122,36 @@ enum {
QT_BEGIN_NAMESPACE
+#undef FocusIn
+
+enum QX11EmbedFocusInDetail {
+ XEMBED_FOCUS_CURRENT = 0,
+ XEMBED_FOCUS_FIRST = 1,
+ XEMBED_FOCUS_LAST = 2
+};
+
+enum QX11EmbedInfoFlags {
+ XEMBED_MAPPED = (1 << 0),
+};
+
+enum QX11EmbedMessageType {
+ XEMBED_EMBEDDED_NOTIFY = 0,
+ XEMBED_WINDOW_ACTIVATE = 1,
+ XEMBED_WINDOW_DEACTIVATE = 2,
+ XEMBED_REQUEST_FOCUS = 3,
+ XEMBED_FOCUS_IN = 4,
+ XEMBED_FOCUS_OUT = 5,
+ XEMBED_FOCUS_NEXT = 6,
+ XEMBED_FOCUS_PREV = 7,
+ XEMBED_MODALITY_ON = 10,
+ XEMBED_MODALITY_OFF = 11,
+ XEMBED_REGISTER_ACCELERATOR = 12,
+ XEMBED_UNREGISTER_ACCELERATOR = 13,
+ XEMBED_ACTIVATE_ACCELERATOR = 14
+};
+
+static unsigned int XEMBED_VERSION = 0;
+
// Returns true if we should set WM_TRANSIENT_FOR on \a w
static inline bool isTransient(const QWindow *w)
{
@@ -158,6 +188,7 @@ QXcbWindow::QXcbWindow(QWindow *window)
, m_transparent(false)
, m_usingSyncProtocol(false)
, m_deferredActivation(false)
+ , m_embedded(false)
, m_netWmUserTimeWindow(XCB_NONE)
, m_dirtyFrameMargins(false)
#if defined(XCB_USE_EGL)
@@ -169,7 +200,10 @@ QXcbWindow::QXcbWindow(QWindow *window)
setConnection(m_screen->connection());
- create();
+ if (window->type() != Qt::ForeignWindow)
+ create();
+ else
+ m_window = window->winId();
}
void QXcbWindow::create()
@@ -236,8 +270,10 @@ void QXcbWindow::create()
}
xcb_window_t xcb_parent_id = m_screen->root();
- if (parent())
+ if (parent()) {
xcb_parent_id = static_cast<QXcbWindow *>(parent())->xcb_window();
+ m_embedded = parent()->window()->type() == Qt::ForeignWindow;
+ }
m_format = window()->requestedFormat();
@@ -371,6 +407,14 @@ void QXcbWindow::create()
atom(QXcbAtom::WM_CLIENT_LEADER), XCB_ATOM_WINDOW, 32,
1, &leader));
+ /* Add XEMBED info; this operation doesn't initiate the embedding. */
+ long data[] = { XEMBED_VERSION, XEMBED_MAPPED };
+ Q_XCB_CALL(xcb_change_property(xcb_connection(), XCB_PROP_MODE_REPLACE, m_window,
+ atom(QXcbAtom::_XEMBED_INFO),
+ atom(QXcbAtom::_XEMBED_INFO),
+ 32, 2, (void *)data));
+
+
#ifdef XCB_USE_XINPUT2_MAEMO
if (connection()->isUsingXInput2Maemo()) {
XIEventMask xieventmask;
@@ -413,7 +457,8 @@ void QXcbWindow::create()
QXcbWindow::~QXcbWindow()
{
- destroy();
+ if (window()->type() != Qt::ForeignWindow)
+ destroy();
}
void QXcbWindow::destroy()
@@ -577,9 +622,10 @@ void QXcbWindow::show()
propagateSizeHints();
// update WM_TRANSIENT_FOR
- if (isTransient(window())) {
+ const QWindow *tp = window()->transientParent();
+ if (isTransient(window()) || tp != 0) {
xcb_window_t transientXcbParent = 0;
- if (const QWindow *tp = window()->transientParent())
+ if (tp)
transientXcbParent = static_cast<const QXcbWindow *>(tp->handle())->winId();
// Default to client leader if there is no transient parent, else modal dialogs can
// be hidden by their parents.
@@ -1143,7 +1189,15 @@ void QXcbWindow::setParent(const QPlatformWindow *parent)
{
QPoint topLeft = geometry().topLeft();
- xcb_window_t xcb_parent_id = parent ? static_cast<const QXcbWindow *>(parent)->xcb_window() : m_screen->root();
+ xcb_window_t xcb_parent_id;
+ if (parent) {
+ const QXcbWindow *qXcbParent = static_cast<const QXcbWindow *>(parent);
+ xcb_parent_id = qXcbParent->xcb_window();
+ m_embedded = qXcbParent->window()->type() == Qt::ForeignWindow;
+ } else {
+ xcb_parent_id = m_screen->root();
+ m_embedded = false;
+ }
Q_XCB_CALL(xcb_reparent_window(xcb_connection(), xcb_window(), xcb_parent_id, topLeft.x(), topLeft.y()));
}
@@ -1274,6 +1328,13 @@ void QXcbWindow::propagateSizeHints()
void QXcbWindow::requestActivateWindow()
{
+ /* Never activate embedded windows; doing that would prevent the container
+ * to re-gain the keyboard focus later. */
+ if (m_embedded) {
+ QPlatformWindow::requestActivateWindow();
+ return;
+ }
+
if (!m_mapped) {
m_deferredActivation = true;
return;
@@ -1437,7 +1498,8 @@ void QXcbWindow::handleClientMessageEvent(const xcb_client_message_event_t *even
} else if (event->type == atom(QXcbAtom::XdndDrop)) {
connection()->drag()->handleDrop(window(), event);
#endif
- } else if (event->type == atom(QXcbAtom::_XEMBED)) { // QSystemTrayIcon
+ } else if (event->type == atom(QXcbAtom::_XEMBED)) {
+ handleXEmbedMessage(event);
} else {
qWarning() << "QXcbWindow: Unhandled client message:" << connection()->atomName(event->type);
}
@@ -1479,6 +1541,53 @@ bool QXcbWindow::isExposed() const
return m_mapped;
}
+bool QXcbWindow::isEmbedded(const QPlatformWindow *parentWindow) const
+{
+ if (!m_embedded)
+ return false;
+
+ return parentWindow ? (parentWindow == parent()) : true;
+}
+
+QPoint QXcbWindow::mapToGlobal(const QPoint &pos) const
+{
+ if (!m_embedded)
+ return pos;
+
+ QPoint ret;
+ xcb_translate_coordinates_cookie_t cookie =
+ xcb_translate_coordinates(xcb_connection(), xcb_window(), m_screen->root(),
+ pos.x(), pos.y());
+ xcb_translate_coordinates_reply_t *reply =
+ xcb_translate_coordinates_reply(xcb_connection(), cookie, NULL);
+ if (reply) {
+ ret.setX(reply->dst_x);
+ ret.setY(reply->dst_y);
+ free(reply);
+ }
+
+ return ret;
+}
+
+QPoint QXcbWindow::mapFromGlobal(const QPoint &pos) const
+{
+ if (!m_embedded)
+ return pos;
+ QPoint ret;
+ xcb_translate_coordinates_cookie_t cookie =
+ xcb_translate_coordinates(xcb_connection(), m_screen->root(), xcb_window(),
+ pos.x(), pos.y());
+ xcb_translate_coordinates_reply_t *reply =
+ xcb_translate_coordinates_reply(xcb_connection(), cookie, NULL);
+ if (reply) {
+ ret.setX(reply->dst_x);
+ ret.setY(reply->dst_y);
+ free(reply);
+ }
+
+ return ret;
+}
+
void QXcbWindow::handleMapNotifyEvent(const xcb_map_notify_event_t *event)
{
if (event->window == m_window) {
@@ -1509,6 +1618,15 @@ void QXcbWindow::handleButtonPressEvent(const xcb_button_press_event_t *event)
updateNetWmUserTime(event->time);
+ if (m_embedded) {
+ if (window() != QGuiApplication::focusWindow()) {
+ const QXcbWindow *container = static_cast<const QXcbWindow *>(parent());
+ Q_ASSERT(container != 0);
+
+ sendXEmbedMessage(container->xcb_window(), XEMBED_REQUEST_FOCUS);
+ }
+ }
+
QPoint local(event->event_x, event->event_y);
QPoint global(event->root_x, event->root_y);
@@ -1664,6 +1782,7 @@ void QXcbWindow::handlePropertyNotifyEvent(const xcb_property_notify_event_t *ev
QWindowSystemInterface::handleWindowStateChanged(window(), newState);
m_lastWindowStateEvent = newState;
}
+ return;
}
}
@@ -1675,7 +1794,7 @@ void QXcbWindow::handleFocusInEvent(const xcb_focus_in_event_t *)
QWindowSystemInterface::handleWindowActivated(w);
}
-static bool focusInPeeker(xcb_generic_event_t *event)
+static bool focusInPeeker(QXcbConnection *connection, xcb_generic_event_t *event)
{
if (!event) {
// FocusIn event is not in the queue, proceed with FocusOut normally.
@@ -1683,7 +1802,18 @@ static bool focusInPeeker(xcb_generic_event_t *event)
return true;
}
uint response_type = event->response_type & ~0x80;
- return response_type == XCB_FOCUS_IN;
+ if (response_type == XCB_FOCUS_IN)
+ return true;
+
+ /* We are also interested in XEMBED_FOCUS_IN events */
+ if (response_type == XCB_CLIENT_MESSAGE) {
+ xcb_client_message_event_t *cme = (xcb_client_message_event_t *)event;
+ if (cme->type == connection->atom(QXcbAtom::_XEMBED)
+ && cme->data.data32[1] == XEMBED_FOCUS_IN)
+ return true;
+ }
+
+ return false;
}
void QXcbWindow::handleFocusOutEvent(const xcb_focus_out_event_t *)
@@ -1747,6 +1877,35 @@ void QXcbWindow::setCursor(xcb_cursor_t cursor)
xcb_flush(xcb_connection());
}
+void QXcbWindow::windowEvent(QEvent *event)
+{
+ switch (event->type()) {
+ case QEvent::FocusIn:
+ if (m_embedded && !event->spontaneous()) {
+ QFocusEvent *focusEvent = static_cast<QFocusEvent *>(event);
+ switch (focusEvent->reason()) {
+ case Qt::TabFocusReason:
+ case Qt::BacktabFocusReason:
+ {
+ const QXcbWindow *container =
+ static_cast<const QXcbWindow *>(parent());
+ sendXEmbedMessage(container->xcb_window(),
+ focusEvent->reason() == Qt::TabFocusReason ?
+ XEMBED_FOCUS_NEXT : XEMBED_FOCUS_PREV);
+ event->accept();
+ }
+ break;
+ default:
+ break;
+ }
+ }
+ break;
+ default:
+ break;
+ }
+ QPlatformWindow::windowEvent(event);
+}
+
bool QXcbWindow::startSystemResize(const QPoint &pos, Qt::Corner corner)
{
const xcb_atom_t moveResize = connection()->atom(QXcbAtom::_NET_WM_MOVERESIZE);
@@ -1775,6 +1934,71 @@ bool QXcbWindow::startSystemResize(const QPoint &pos, Qt::Corner corner)
return true;
}
+// Sends an XEmbed message.
+void QXcbWindow::sendXEmbedMessage(xcb_window_t window, long message,
+ long detail, long data1, long data2)
+{
+ xcb_client_message_event_t event;
+
+ event.response_type = XCB_CLIENT_MESSAGE;
+ event.format = 32;
+ event.window = window;
+ event.type = atom(QXcbAtom::_XEMBED);
+ event.data.data32[0] = connection()->time();
+ event.data.data32[1] = message;
+ event.data.data32[2] = detail;
+ event.data.data32[3] = data1;
+ event.data.data32[4] = data2;
+ Q_XCB_CALL(xcb_send_event(xcb_connection(), false, window,
+ XCB_EVENT_MASK_NO_EVENT, (const char *)&event));
+}
+
+static bool activeWindowChangeQueued(const QWindow *window)
+{
+ /* Check from window system event queue if the next queued activation
+ * targets a window other than @window.
+ */
+ QWindowSystemInterfacePrivate::ActivatedWindowEvent *systemEvent =
+ static_cast<QWindowSystemInterfacePrivate::ActivatedWindowEvent *>
+ (QWindowSystemInterfacePrivate::peekWindowSystemEvent(QWindowSystemInterfacePrivate::ActivatedWindow));
+ return systemEvent && systemEvent->activated != window;
+}
+
+void QXcbWindow::handleXEmbedMessage(const xcb_client_message_event_t *event)
+{
+ connection()->setTime(event->data.data32[0]);
+ switch (event->data.data32[1]) {
+ case XEMBED_WINDOW_ACTIVATE:
+ case XEMBED_WINDOW_DEACTIVATE:
+ case XEMBED_EMBEDDED_NOTIFY:
+ break;
+ case XEMBED_FOCUS_IN:
+ Qt::FocusReason reason;
+ switch (event->data.data32[2]) {
+ case XEMBED_FOCUS_FIRST:
+ reason = Qt::TabFocusReason;
+ break;
+ case XEMBED_FOCUS_LAST:
+ reason = Qt::BacktabFocusReason;
+ break;
+ case XEMBED_FOCUS_CURRENT:
+ default:
+ reason = Qt::OtherFocusReason;
+ break;
+ }
+ connection()->setFocusWindow(static_cast<QXcbWindow*>(window()->handle()));
+ QWindowSystemInterface::handleWindowActivated(window(), reason);
+ break;
+ case XEMBED_FOCUS_OUT:
+ if (window() == QGuiApplication::focusWindow()
+ && !activeWindowChangeQueued(window())) {
+ connection()->setFocusWindow(0);
+ QWindowSystemInterface::handleWindowActivated(0);
+ }
+ break;
+ }
+}
+
#if !defined(QT_NO_SHAPE)
static inline xcb_rectangle_t qRectToXCBRectangle(const QRect &r)
diff --git a/src/plugins/platforms/xcb/qxcbwindow.h b/src/plugins/platforms/xcb/qxcbwindow.h
index 6a8b98ff0d..f4bd2d96ff 100644
--- a/src/plugins/platforms/xcb/qxcbwindow.h
+++ b/src/plugins/platforms/xcb/qxcbwindow.h
@@ -87,6 +87,9 @@ public:
void setParent(const QPlatformWindow *window);
bool isExposed() const;
+ bool isEmbedded(const QPlatformWindow *parentWindow) const;
+ QPoint mapToGlobal(const QPoint &pos) const;
+ QPoint mapFromGlobal(const QPoint &pos) const;
void setWindowTitle(const QString &title);
void setWindowIcon(const QIcon &icon);
@@ -107,6 +110,8 @@ public:
QSurfaceFormat format() const;
+ void windowEvent(QEvent *event);
+
bool startSystemResize(const QPoint &pos, Qt::Corner corner);
void setOpacity(qreal level);
@@ -158,6 +163,9 @@ private:
void updateDoesNotAcceptFocus(bool doesNotAcceptFocus);
QRect windowToWmGeometry(QRect r) const;
+ void sendXEmbedMessage(xcb_window_t window, long message,
+ long detail = 0, long data1 = 0, long data2 = 0);
+ void handleXEmbedMessage(const xcb_client_message_event_t *event);
void create();
void destroy();
@@ -185,6 +193,7 @@ private:
bool m_deferredActivation;
bool m_deferredExpose;
bool m_configureNotifyPending;
+ bool m_embedded;
xcb_window_t m_netWmUserTimeWindow;
QSurfaceFormat m_format;
diff --git a/src/plugins/platformthemes/gtk2/gtk2.json b/src/plugins/platformthemes/gtk2/gtk2.json
new file mode 100644
index 0000000000..86dd8e58fa
--- /dev/null
+++ b/src/plugins/platformthemes/gtk2/gtk2.json
@@ -0,0 +1,3 @@
+{
+ "Keys": [ "gtk2" ]
+}
diff --git a/src/plugins/platformthemes/gtk2/gtk2.pro b/src/plugins/platformthemes/gtk2/gtk2.pro
new file mode 100644
index 0000000000..bb02192f91
--- /dev/null
+++ b/src/plugins/platformthemes/gtk2/gtk2.pro
@@ -0,0 +1,20 @@
+TARGET = qgtk2
+
+PLUGIN_TYPE = platformthemes
+PLUGIN_CLASS_NAME = QGtk2ThemePlugin
+load(qt_plugin)
+
+QT += core-private gui-private platformsupport-private
+
+CONFIG += X11
+QMAKE_CXXFLAGS += $$QT_CFLAGS_QGTK2
+LIBS += $$QT_LIBS_QGTK2
+
+HEADERS += \
+ qgtk2dialoghelpers.h \
+ qgtk2theme.h
+
+SOURCES += \
+ main.cpp \
+ qgtk2dialoghelpers.cpp \
+ qgtk2theme.cpp \
diff --git a/src/plugins/platformthemes/gtk2/main.cpp b/src/plugins/platformthemes/gtk2/main.cpp
new file mode 100644
index 0000000000..13e7d57b13
--- /dev/null
+++ b/src/plugins/platformthemes/gtk2/main.cpp
@@ -0,0 +1,67 @@
+/****************************************************************************
+**
+** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the plugins of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Digia. For licensing terms and
+** conditions see http://qt.digia.com/licensing. For further information
+** use the contact form at http://qt.digia.com/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Digia gives you certain additional
+** rights. These rights are described in the Digia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include <qpa/qplatformthemeplugin.h>
+#include "qgtk2theme.h"
+
+QT_BEGIN_NAMESPACE
+
+class QGtk2ThemePlugin : public QPlatformThemePlugin
+{
+ Q_OBJECT
+ Q_PLUGIN_METADATA(IID "org.qt-project.Qt.QPA.QPlatformThemeFactoryInterface.5.1" FILE "gtk2.json")
+
+public:
+ QPlatformTheme *create(const QString &key, const QStringList &params);
+};
+
+QPlatformTheme *QGtk2ThemePlugin::create(const QString &key, const QStringList &params)
+{
+ Q_UNUSED(params);
+ if (!key.compare(QLatin1String(QGtk2Theme::name), Qt::CaseInsensitive))
+ return new QGtk2Theme;
+
+ return 0;
+}
+
+QT_END_NAMESPACE
+
+#include "main.moc"
diff --git a/src/plugins/platformthemes/gtk2/qgtk2dialoghelpers.cpp b/src/plugins/platformthemes/gtk2/qgtk2dialoghelpers.cpp
new file mode 100644
index 0000000000..25d45eb81d
--- /dev/null
+++ b/src/plugins/platformthemes/gtk2/qgtk2dialoghelpers.cpp
@@ -0,0 +1,609 @@
+/****************************************************************************
+**
+** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the plugins of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Digia. For licensing terms and
+** conditions see http://qt.digia.com/licensing. For further information
+** use the contact form at http://qt.digia.com/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Digia gives you certain additional
+** rights. These rights are described in the Digia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qgtk2dialoghelpers.h"
+
+#include <qeventloop.h>
+#include <qwindow.h>
+#include <qcolor.h>
+#include <qdebug.h>
+#include <qfont.h>
+
+#include <private/qguiapplication_p.h>
+
+#undef signals
+#include <gtk/gtk.h>
+#include <gdk/gdk.h>
+#include <gdk/gdkx.h>
+#include <pango/pango.h>
+
+QT_BEGIN_NAMESPACE
+
+class QGtk2Dialog : public QWindow
+{
+ Q_OBJECT
+
+public:
+ QGtk2Dialog(GtkWidget *gtkWidget);
+ ~QGtk2Dialog();
+
+ GtkDialog *gtkDialog() const;
+
+ void exec();
+ bool show(Qt::WindowFlags flags, Qt::WindowModality modality, QWindow *parent);
+ void hide();
+
+Q_SIGNALS:
+ void accept();
+ void reject();
+
+protected:
+ static void onResponse(QGtk2Dialog *dialog, int response);
+
+private:
+ GtkWidget *gtkWidget;
+};
+
+QGtk2Dialog::QGtk2Dialog(GtkWidget *gtkWidget) : gtkWidget(gtkWidget)
+{
+ g_signal_connect_swapped(G_OBJECT(gtkWidget), "response", G_CALLBACK(onResponse), this);
+ g_signal_connect(G_OBJECT(gtkWidget), "delete-event", G_CALLBACK(gtk_widget_hide_on_delete), NULL);
+}
+
+QGtk2Dialog::~QGtk2Dialog()
+{
+ gtk_widget_destroy(gtkWidget);
+}
+
+GtkDialog *QGtk2Dialog::gtkDialog() const
+{
+ return GTK_DIALOG(gtkWidget);
+}
+
+void QGtk2Dialog::exec()
+{
+ if (modality() == Qt::ApplicationModal) {
+ // block input to the whole app, including other GTK dialogs
+ gtk_dialog_run(gtkDialog());
+ } else {
+ // block input to the window, allow input to other GTK dialogs
+ QEventLoop loop;
+ connect(this, SIGNAL(accept()), &loop, SLOT(quit()));
+ connect(this, SIGNAL(reject()), &loop, SLOT(quit()));
+ loop.exec();
+ }
+}
+
+bool QGtk2Dialog::show(Qt::WindowFlags flags, Qt::WindowModality modality, QWindow *parent)
+{
+ setParent(parent);
+ setFlags(flags);
+ setModality(modality);
+
+ gtk_widget_realize(gtkWidget); // creates X window
+
+ if (parent) {
+ XSetTransientForHint(gdk_x11_drawable_get_xdisplay(gtkWidget->window),
+ gdk_x11_drawable_get_xid(gtkWidget->window),
+ parent->winId());
+ }
+
+ if (modality != Qt::NonModal) {
+ gdk_window_set_modal_hint(gtkWidget->window, true);
+ QGuiApplicationPrivate::showModalWindow(this);
+ }
+
+ gtk_widget_show(gtkWidget);
+ return true;
+}
+
+void QGtk2Dialog::hide()
+{
+ QGuiApplicationPrivate::hideModalWindow(this);
+ gtk_widget_hide(gtkWidget);
+}
+
+void QGtk2Dialog::onResponse(QGtk2Dialog *dialog, int response)
+{
+ if (response == GTK_RESPONSE_OK)
+ emit dialog->accept();
+ else
+ emit dialog->reject();
+}
+
+QGtk2ColorDialogHelper::QGtk2ColorDialogHelper()
+{
+ d.reset(new QGtk2Dialog(gtk_color_selection_dialog_new("")));
+ connect(d.data(), SIGNAL(accept()), this, SLOT(onAccepted()));
+ connect(d.data(), SIGNAL(reject()), this, SIGNAL(reject()));
+
+ GtkWidget *gtkColorSelection = gtk_color_selection_dialog_get_color_selection(GTK_COLOR_SELECTION_DIALOG(d->gtkDialog()));
+ g_signal_connect_swapped(gtkColorSelection, "color-changed", G_CALLBACK(onColorChanged), this);
+}
+
+QGtk2ColorDialogHelper::~QGtk2ColorDialogHelper()
+{
+}
+
+bool QGtk2ColorDialogHelper::show(Qt::WindowFlags flags, Qt::WindowModality modality, QWindow *parent)
+{
+ applyOptions();
+ return d->show(flags, modality, parent);
+}
+
+void QGtk2ColorDialogHelper::exec()
+{
+ d->exec();
+}
+
+void QGtk2ColorDialogHelper::hide()
+{
+ d->hide();
+}
+
+void QGtk2ColorDialogHelper::setCurrentColor(const QColor &color)
+{
+ GtkDialog *gtkDialog = d->gtkDialog();
+ GtkWidget *gtkColorSelection = gtk_color_selection_dialog_get_color_selection(GTK_COLOR_SELECTION_DIALOG(gtkDialog));
+ GdkColor gdkColor;
+ gdkColor.red = color.red() << 8;
+ gdkColor.green = color.green() << 8;
+ gdkColor.blue = color.blue() << 8;
+ gtk_color_selection_set_current_color(GTK_COLOR_SELECTION(gtkColorSelection), &gdkColor);
+ if (color.alpha() < 255) {
+ gtk_color_selection_set_has_opacity_control(GTK_COLOR_SELECTION(gtkColorSelection), true);
+ gtk_color_selection_set_current_alpha(GTK_COLOR_SELECTION(gtkColorSelection), color.alpha() << 8);
+ }
+}
+
+QColor QGtk2ColorDialogHelper::currentColor() const
+{
+ GtkDialog *gtkDialog = d->gtkDialog();
+ GtkWidget *gtkColorSelection = gtk_color_selection_dialog_get_color_selection(GTK_COLOR_SELECTION_DIALOG(gtkDialog));
+ GdkColor gdkColor;
+ gtk_color_selection_get_current_color(GTK_COLOR_SELECTION(gtkColorSelection), &gdkColor);
+ guint16 alpha = gtk_color_selection_get_current_alpha(GTK_COLOR_SELECTION(gtkColorSelection));
+ return QColor(gdkColor.red >> 8, gdkColor.green >> 8, gdkColor.blue >> 8, alpha >> 8);
+}
+
+void QGtk2ColorDialogHelper::onAccepted()
+{
+ emit accept();
+ emit colorSelected(currentColor());
+}
+
+void QGtk2ColorDialogHelper::onColorChanged(QGtk2ColorDialogHelper *dialog)
+{
+ emit dialog->currentColorChanged(dialog->currentColor());
+}
+
+void QGtk2ColorDialogHelper::applyOptions()
+{
+ GtkDialog *gtkDialog = d->gtkDialog();
+ gtk_window_set_title(GTK_WINDOW(gtkDialog), options()->windowTitle().toUtf8());
+
+ GtkWidget *gtkColorSelection = gtk_color_selection_dialog_get_color_selection(GTK_COLOR_SELECTION_DIALOG(gtkDialog));
+ gtk_color_selection_set_has_opacity_control(GTK_COLOR_SELECTION(gtkColorSelection), options()->testOption(QColorDialogOptions::ShowAlphaChannel));
+
+ GtkWidget *okButton = 0;
+ GtkWidget *cancelButton = 0;
+ GtkWidget *helpButton = 0;
+ g_object_get(G_OBJECT(gtkDialog), "ok-button", &okButton, "cancel-button", &cancelButton, "help-button", &helpButton, NULL);
+ if (okButton)
+ g_object_set(G_OBJECT(okButton), "visible", !options()->testOption(QColorDialogOptions::NoButtons), NULL);
+ if (cancelButton)
+ g_object_set(G_OBJECT(cancelButton), "visible", !options()->testOption(QColorDialogOptions::NoButtons), NULL);
+ if (helpButton)
+ gtk_widget_hide(helpButton);
+}
+
+QGtk2FileDialogHelper::QGtk2FileDialogHelper()
+{
+ d.reset(new QGtk2Dialog(gtk_file_chooser_dialog_new("", 0,
+ GTK_FILE_CHOOSER_ACTION_OPEN,
+ GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
+ GTK_STOCK_OK, GTK_RESPONSE_OK, NULL)));
+ connect(d.data(), SIGNAL(accept()), this, SLOT(onAccepted()));
+ connect(d.data(), SIGNAL(reject()), this, SIGNAL(reject()));
+
+ g_signal_connect(GTK_FILE_CHOOSER(d->gtkDialog()), "selection-changed", G_CALLBACK(onSelectionChanged), this);
+ g_signal_connect_swapped(GTK_FILE_CHOOSER(d->gtkDialog()), "current-folder-changed", G_CALLBACK(onCurrentFolderChanged), this);
+}
+
+QGtk2FileDialogHelper::~QGtk2FileDialogHelper()
+{
+}
+
+bool QGtk2FileDialogHelper::show(Qt::WindowFlags flags, Qt::WindowModality modality, QWindow *parent)
+{
+ _dir.clear();
+ _selection.clear();
+
+ applyOptions();
+ return d->show(flags, modality, parent);
+}
+
+void QGtk2FileDialogHelper::exec()
+{
+ d->exec();
+}
+
+void QGtk2FileDialogHelper::hide()
+{
+ // After GtkFileChooserDialog has been hidden, gtk_file_chooser_get_current_folder()
+ // & gtk_file_chooser_get_filenames() will return bogus values -> cache the actual
+ // values before hiding the dialog
+ _dir = directory();
+ _selection = selectedFiles();
+
+ d->hide();
+}
+
+bool QGtk2FileDialogHelper::defaultNameFilterDisables() const
+{
+ return false;
+}
+
+void QGtk2FileDialogHelper::setDirectory(const QString &directory)
+{
+ GtkDialog *gtkDialog = d->gtkDialog();
+ gtk_file_chooser_set_current_folder(GTK_FILE_CHOOSER(gtkDialog), directory.toUtf8());
+}
+
+QString QGtk2FileDialogHelper::directory() const
+{
+ // While GtkFileChooserDialog is hidden, gtk_file_chooser_get_current_folder()
+ // returns a bogus value -> return the cached value before hiding
+ if (!_dir.isEmpty())
+ return _dir;
+
+ QString ret;
+ GtkDialog *gtkDialog = d->gtkDialog();
+ gchar *folder = gtk_file_chooser_get_current_folder(GTK_FILE_CHOOSER(gtkDialog));
+ if (folder) {
+ ret = QString::fromUtf8(folder);
+ g_free(folder);
+ }
+ return ret;
+}
+
+void QGtk2FileDialogHelper::selectFile(const QString &filename)
+{
+ GtkDialog *gtkDialog = d->gtkDialog();
+ gtk_file_chooser_select_filename(GTK_FILE_CHOOSER(gtkDialog), filename.toUtf8());
+}
+
+QStringList QGtk2FileDialogHelper::selectedFiles() const
+{
+ // While GtkFileChooserDialog is hidden, gtk_file_chooser_get_filenames()
+ // returns a bogus value -> return the cached value before hiding
+ if (!_selection.isEmpty())
+ return _selection;
+
+ QStringList selection;
+ GtkDialog *gtkDialog = d->gtkDialog();
+ GSList *filenames = gtk_file_chooser_get_filenames(GTK_FILE_CHOOSER(gtkDialog));
+ for (GSList *it = filenames; it; it = it->next)
+ selection += QString::fromUtf8((const char*)it->data);
+ g_slist_free(filenames);
+ return selection;
+}
+
+void QGtk2FileDialogHelper::setFilter()
+{
+ applyOptions();
+}
+
+void QGtk2FileDialogHelper::selectNameFilter(const QString &filter)
+{
+ GtkFileFilter *gtkFilter = _filters.value(filter);
+ if (gtkFilter) {
+ GtkDialog *gtkDialog = d->gtkDialog();
+ gtk_file_chooser_set_filter(GTK_FILE_CHOOSER(gtkDialog), gtkFilter);
+ }
+}
+
+QString QGtk2FileDialogHelper::selectedNameFilter() const
+{
+ GtkDialog *gtkDialog = d->gtkDialog();
+ GtkFileFilter *gtkFilter = gtk_file_chooser_get_filter(GTK_FILE_CHOOSER(gtkDialog));
+ return _filterNames.value(gtkFilter);
+}
+
+void QGtk2FileDialogHelper::onAccepted()
+{
+ emit accept();
+
+ QString filter = selectedNameFilter();
+ if (filter.isEmpty())
+ emit filterSelected(filter);
+
+ QStringList files = selectedFiles();
+ emit filesSelected(files);
+ if (files.count() == 1)
+ emit fileSelected(files.first());
+}
+
+void QGtk2FileDialogHelper::onSelectionChanged(GtkDialog *gtkDialog, QGtk2FileDialogHelper *helper)
+{
+ QString selection;
+ gchar *filename = gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(gtkDialog));
+ if (filename) {
+ selection = QString::fromUtf8(filename);
+ g_free(filename);
+ }
+ emit helper->currentChanged(selection);
+}
+
+void QGtk2FileDialogHelper::onCurrentFolderChanged(QGtk2FileDialogHelper *dialog)
+{
+ emit dialog->directoryEntered(dialog->directory());
+}
+
+static GtkFileChooserAction gtkFileChooserAction(const QSharedPointer<QFileDialogOptions> &options)
+{
+ switch (options->fileMode()) {
+ case QFileDialogOptions::AnyFile:
+ case QFileDialogOptions::ExistingFile:
+ case QFileDialogOptions::ExistingFiles:
+ if (options->acceptMode() == QFileDialogOptions::AcceptOpen)
+ return GTK_FILE_CHOOSER_ACTION_OPEN;
+ else
+ return GTK_FILE_CHOOSER_ACTION_SAVE;
+ case QFileDialogOptions::Directory:
+ case QFileDialogOptions::DirectoryOnly:
+ default:
+ if (options->acceptMode() == QFileDialogOptions::AcceptOpen)
+ return GTK_FILE_CHOOSER_ACTION_SELECT_FOLDER;
+ else
+ return GTK_FILE_CHOOSER_ACTION_CREATE_FOLDER;
+ }
+}
+
+void QGtk2FileDialogHelper::applyOptions()
+{
+ GtkDialog *gtkDialog = d->gtkDialog();
+ const QSharedPointer<QFileDialogOptions> &opts = options();
+
+ gtk_window_set_title(GTK_WINDOW(gtkDialog), opts->windowTitle().toUtf8());
+ gtk_file_chooser_set_local_only(GTK_FILE_CHOOSER(gtkDialog), true);
+
+ const GtkFileChooserAction action = gtkFileChooserAction(opts);
+ gtk_file_chooser_set_action(GTK_FILE_CHOOSER(gtkDialog), action);
+
+ const bool selectMultiple = opts->fileMode() == QFileDialogOptions::ExistingFiles;
+ gtk_file_chooser_set_select_multiple(GTK_FILE_CHOOSER(gtkDialog), selectMultiple);
+
+ const bool confirmOverwrite = !opts->testOption(QFileDialogOptions::DontConfirmOverwrite);
+ gtk_file_chooser_set_do_overwrite_confirmation(GTK_FILE_CHOOSER(gtkDialog), confirmOverwrite);
+
+ const QStringList nameFilters = opts->nameFilters();
+ if (!nameFilters.isEmpty())
+ setNameFilters(nameFilters);
+
+ const QString initialDirectory = opts->initialDirectory();
+ if (!initialDirectory.isEmpty())
+ setDirectory(initialDirectory);
+
+ foreach (const QString &filename, opts->initiallySelectedFiles())
+ selectFile(filename);
+
+ const QString initialNameFilter = opts->initiallySelectedNameFilter();
+ if (!initialNameFilter.isEmpty())
+ selectNameFilter(initialNameFilter);
+
+ GtkWidget *acceptButton = gtk_dialog_get_widget_for_response(gtkDialog, GTK_RESPONSE_OK);
+ if (acceptButton) {
+ if (opts->isLabelExplicitlySet(QFileDialogOptions::Accept))
+ gtk_button_set_label(GTK_BUTTON(acceptButton), opts->labelText(QFileDialogOptions::Accept).toUtf8());
+ else if (opts->acceptMode() == QFileDialogOptions::AcceptOpen)
+ gtk_button_set_label(GTK_BUTTON(acceptButton), GTK_STOCK_OPEN);
+ else
+ gtk_button_set_label(GTK_BUTTON(acceptButton), GTK_STOCK_SAVE);
+ }
+
+ GtkWidget *rejectButton = gtk_dialog_get_widget_for_response(gtkDialog, GTK_RESPONSE_CANCEL);
+ if (rejectButton) {
+ if (opts->isLabelExplicitlySet(QFileDialogOptions::Reject))
+ gtk_button_set_label(GTK_BUTTON(rejectButton), opts->labelText(QFileDialogOptions::Reject).toUtf8());
+ else
+ gtk_button_set_label(GTK_BUTTON(rejectButton), GTK_STOCK_CANCEL);
+ }
+}
+
+void QGtk2FileDialogHelper::setNameFilters(const QStringList &filters)
+{
+ GtkDialog *gtkDialog = d->gtkDialog();
+ foreach (GtkFileFilter *filter, _filters)
+ gtk_file_chooser_remove_filter(GTK_FILE_CHOOSER(gtkDialog), filter);
+
+ _filters.clear();
+ _filterNames.clear();
+
+ foreach (const QString &filter, filters) {
+ GtkFileFilter *gtkFilter = gtk_file_filter_new();
+ const QString name = filter.left(filter.indexOf(QLatin1Char('(')));
+ const QStringList extensions = cleanFilterList(filter);
+
+ gtk_file_filter_set_name(gtkFilter, name.isEmpty() ? extensions.join(QStringLiteral(", ")).toUtf8() : name.toUtf8());
+ foreach (const QString &ext, extensions)
+ gtk_file_filter_add_pattern(gtkFilter, ext.toUtf8());
+
+ gtk_file_chooser_add_filter(GTK_FILE_CHOOSER(gtkDialog), gtkFilter);
+
+ _filters.insert(filter, gtkFilter);
+ _filterNames.insert(gtkFilter, filter);
+ }
+}
+
+QGtk2FontDialogHelper::QGtk2FontDialogHelper()
+{
+ d.reset(new QGtk2Dialog(gtk_font_selection_dialog_new("")));
+ connect(d.data(), SIGNAL(accept()), this, SLOT(onAccepted()));
+ connect(d.data(), SIGNAL(reject()), this, SIGNAL(reject()));
+}
+
+QGtk2FontDialogHelper::~QGtk2FontDialogHelper()
+{
+}
+
+bool QGtk2FontDialogHelper::show(Qt::WindowFlags flags, Qt::WindowModality modality, QWindow *parent)
+{
+ applyOptions();
+ return d->show(flags, modality, parent);
+}
+
+void QGtk2FontDialogHelper::exec()
+{
+ d->exec();
+}
+
+void QGtk2FontDialogHelper::hide()
+{
+ d->hide();
+}
+
+static QString qt_fontToString(const QFont &font)
+{
+ PangoFontDescription *desc = pango_font_description_new();
+ pango_font_description_set_size(desc, font.pointSizeF() * PANGO_SCALE);
+ pango_font_description_set_family(desc, font.family().toUtf8());
+
+ int weight = font.weight();
+ if (weight >= QFont::Black)
+ pango_font_description_set_weight(desc, PANGO_WEIGHT_HEAVY);
+ else if (weight >= QFont::Bold)
+ pango_font_description_set_weight(desc, PANGO_WEIGHT_BOLD);
+ else if (weight >= QFont::DemiBold)
+ pango_font_description_set_weight(desc, PANGO_WEIGHT_SEMIBOLD);
+ else if (weight >= QFont::Normal)
+ pango_font_description_set_weight(desc, PANGO_WEIGHT_NORMAL);
+ else
+ pango_font_description_set_weight(desc, PANGO_WEIGHT_LIGHT);
+
+ int style = font.style();
+ if (style == QFont::StyleItalic)
+ pango_font_description_set_style(desc, PANGO_STYLE_ITALIC);
+ else if (style == QFont::StyleOblique)
+ pango_font_description_set_style(desc, PANGO_STYLE_OBLIQUE);
+ else
+ pango_font_description_set_style(desc, PANGO_STYLE_NORMAL);
+
+ char *str = pango_font_description_to_string(desc);
+ QString name = QString::fromUtf8(str);
+ pango_font_description_free(desc);
+ g_free(str);
+ return name;
+}
+
+static QFont qt_fontFromString(const QString &name)
+{
+ QFont font;
+ PangoFontDescription *desc = pango_font_description_from_string(name.toUtf8());
+ font.setPointSizeF(static_cast<float>(pango_font_description_get_size(desc)) / PANGO_SCALE);
+
+ QString family = QString::fromUtf8(pango_font_description_get_family(desc));
+ if (!family.isEmpty())
+ font.setFamily(family);
+
+ int weight = pango_font_description_get_weight(desc);
+ if (weight >= PANGO_WEIGHT_HEAVY)
+ font.setWeight(QFont::Black);
+ else if (weight >= PANGO_WEIGHT_BOLD)
+ font.setWeight(QFont::Bold);
+ else if (weight >= PANGO_WEIGHT_SEMIBOLD)
+ font.setWeight(QFont::DemiBold);
+ else if (weight >= PANGO_WEIGHT_NORMAL)
+ font.setWeight(QFont::Normal);
+ else
+ font.setWeight(QFont::Light);
+
+ PangoStyle style = pango_font_description_get_style(desc);
+ if (style == PANGO_STYLE_ITALIC)
+ font.setStyle(QFont::StyleItalic);
+ else if (style == PANGO_STYLE_OBLIQUE)
+ font.setStyle(QFont::StyleOblique);
+ else
+ font.setStyle(QFont::StyleNormal);
+
+ pango_font_description_free(desc);
+ return font;
+}
+
+void QGtk2FontDialogHelper::setCurrentFont(const QFont &font)
+{
+ GtkFontSelectionDialog *gtkDialog = GTK_FONT_SELECTION_DIALOG(d->gtkDialog());
+ gtk_font_selection_dialog_set_font_name(gtkDialog, qt_fontToString(font).toUtf8());
+}
+
+QFont QGtk2FontDialogHelper::currentFont() const
+{
+ GtkFontSelectionDialog *gtkDialog = GTK_FONT_SELECTION_DIALOG(d->gtkDialog());
+ gchar *name = gtk_font_selection_dialog_get_font_name(gtkDialog);
+ QFont font = qt_fontFromString(QString::fromUtf8(name));
+ g_free(name);
+ return font;
+}
+
+void QGtk2FontDialogHelper::onAccepted()
+{
+ emit accept();
+ emit fontSelected(currentFont());
+}
+
+void QGtk2FontDialogHelper::applyOptions()
+{
+ GtkDialog *gtkDialog = d->gtkDialog();
+ const QSharedPointer<QFontDialogOptions> &opts = options();
+
+ gtk_window_set_title(GTK_WINDOW(gtkDialog), opts->windowTitle().toUtf8());
+
+ GtkWidget *okButton = gtk_font_selection_dialog_get_ok_button(GTK_FONT_SELECTION_DIALOG(gtkDialog));
+ GtkWidget *cancelButton = gtk_font_selection_dialog_get_cancel_button(GTK_FONT_SELECTION_DIALOG(gtkDialog));
+ if (okButton)
+ gtk_widget_set_visible(okButton, !options()->testOption(QFontDialogOptions::NoButtons));
+ if (cancelButton)
+ gtk_widget_set_visible(cancelButton, !options()->testOption(QFontDialogOptions::NoButtons));
+}
+
+QT_END_NAMESPACE
+
+#include "qgtk2dialoghelpers.moc"
diff --git a/src/plugins/platformthemes/gtk2/qgtk2dialoghelpers.h b/src/plugins/platformthemes/gtk2/qgtk2dialoghelpers.h
new file mode 100644
index 0000000000..c2d12625f5
--- /dev/null
+++ b/src/plugins/platformthemes/gtk2/qgtk2dialoghelpers.h
@@ -0,0 +1,143 @@
+/****************************************************************************
+**
+** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the plugins of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Digia. For licensing terms and
+** conditions see http://qt.digia.com/licensing. For further information
+** use the contact form at http://qt.digia.com/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Digia gives you certain additional
+** rights. These rights are described in the Digia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QGTK2DIALOGHELPERS_P_H
+#define QGTK2DIALOGHELPERS_P_H
+
+#include <QtCore/qscopedpointer.h>
+#include <qpa/qplatformdialoghelper.h>
+
+typedef struct _GtkDialog GtkDialog;
+typedef struct _GtkFileFilter GtkFileFilter;
+
+QT_BEGIN_NAMESPACE
+
+class QGtk2Dialog;
+
+class QGtk2ColorDialogHelper : public QPlatformColorDialogHelper
+{
+ Q_OBJECT
+
+public:
+ QGtk2ColorDialogHelper();
+ ~QGtk2ColorDialogHelper();
+
+ bool show(Qt::WindowFlags flags, Qt::WindowModality modality, QWindow *parent);
+ void exec();
+ void hide();
+
+ void setCurrentColor(const QColor &color);
+ QColor currentColor() const;
+
+private Q_SLOTS:
+ void onAccepted();
+
+private:
+ static void onColorChanged(QGtk2ColorDialogHelper *helper);
+ void applyOptions();
+
+ QScopedPointer<QGtk2Dialog> d;
+};
+
+class QGtk2FileDialogHelper : public QPlatformFileDialogHelper
+{
+ Q_OBJECT
+
+public:
+ QGtk2FileDialogHelper();
+ ~QGtk2FileDialogHelper();
+
+ bool show(Qt::WindowFlags flags, Qt::WindowModality modality, QWindow *parent);
+ void exec();
+ void hide();
+
+ bool defaultNameFilterDisables() const;
+ void setDirectory(const QString &directory);
+ QString directory() const;
+ void selectFile(const QString &filename);
+ QStringList selectedFiles() const;
+ void setFilter();
+ void selectNameFilter(const QString &filter);
+ QString selectedNameFilter() const;
+
+private Q_SLOTS:
+ void onAccepted();
+
+private:
+ static void onSelectionChanged(GtkDialog *dialog, QGtk2FileDialogHelper *helper);
+ static void onCurrentFolderChanged(QGtk2FileDialogHelper *helper);
+ void applyOptions();
+ void setNameFilters(const QStringList &filters);
+
+ QString _dir;
+ QStringList _selection;
+ QHash<QString, GtkFileFilter*> _filters;
+ QHash<GtkFileFilter*, QString> _filterNames;
+ QScopedPointer<QGtk2Dialog> d;
+};
+
+class QGtk2FontDialogHelper : public QPlatformFontDialogHelper
+{
+ Q_OBJECT
+
+public:
+ QGtk2FontDialogHelper();
+ ~QGtk2FontDialogHelper();
+
+ bool show(Qt::WindowFlags flags, Qt::WindowModality modality, QWindow *parent);
+ void exec();
+ void hide();
+
+ void setCurrentFont(const QFont &font);
+ QFont currentFont() const;
+
+private Q_SLOTS:
+ void onAccepted();
+
+private:
+ void applyOptions();
+
+ QScopedPointer<QGtk2Dialog> d;
+};
+
+QT_END_NAMESPACE
+
+#endif // QGTK2DIALOGHELPERS_P_H
diff --git a/src/plugins/platformthemes/gtk2/qgtk2theme.cpp b/src/plugins/platformthemes/gtk2/qgtk2theme.cpp
new file mode 100644
index 0000000000..f069d9f97c
--- /dev/null
+++ b/src/plugins/platformthemes/gtk2/qgtk2theme.cpp
@@ -0,0 +1,108 @@
+/****************************************************************************
+**
+** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the plugins of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Digia. For licensing terms and
+** conditions see http://qt.digia.com/licensing. For further information
+** use the contact form at http://qt.digia.com/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Digia gives you certain additional
+** rights. These rights are described in the Digia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qgtk2theme.h"
+#include "qgtk2dialoghelpers.h"
+#include <QVariant>
+
+#undef signals
+#include <gtk/gtk.h>
+
+#include <X11/Xlib.h>
+
+QT_BEGIN_NAMESPACE
+
+const char *QGtk2Theme::name = "gtk2";
+
+static QString gtkSetting(const gchar *propertyName)
+{
+ GtkSettings *settings = gtk_settings_get_default();
+ gchararray value;
+ g_object_get(settings, propertyName, &value, NULL);
+ QString str = QString::fromUtf8(value);
+ g_free(value);
+ return str;
+}
+
+QGtk2Theme::QGtk2Theme()
+{
+ // gtk_init will reset the Xlib error handler, and that causes
+ // Qt applications to quit on X errors. Therefore, we need to manually restore it.
+ int (*oldErrorHandler)(Display *, XErrorEvent *) = XSetErrorHandler(NULL);
+
+ gtk_init(0, 0);
+
+ XSetErrorHandler(oldErrorHandler);
+}
+
+QVariant QGtk2Theme::themeHint(QPlatformTheme::ThemeHint hint) const
+{
+ switch (hint) {
+ case QPlatformTheme::SystemIconThemeName:
+ return QVariant(gtkSetting("gtk-icon-theme-name"));
+ case QPlatformTheme::SystemIconFallbackThemeName:
+ return QVariant(gtkSetting("gtk-fallback-icon-theme"));
+ default:
+ return QGnomeTheme::themeHint(hint);
+ }
+}
+
+bool QGtk2Theme::usePlatformNativeDialog(DialogType type) const
+{
+ Q_UNUSED(type);
+ return true;
+}
+
+QPlatformDialogHelper *QGtk2Theme::createPlatformDialogHelper(DialogType type) const
+{
+ switch (type) {
+ case ColorDialog:
+ return new QGtk2ColorDialogHelper;
+ case FileDialog:
+ return new QGtk2FileDialogHelper;
+ case FontDialog:
+ return new QGtk2FontDialogHelper;
+ default:
+ return 0;
+ }
+}
+
+QT_END_NAMESPACE
diff --git a/src/plugins/platformthemes/gtk2/qgtk2theme.h b/src/plugins/platformthemes/gtk2/qgtk2theme.h
new file mode 100644
index 0000000000..a0bd34ed9f
--- /dev/null
+++ b/src/plugins/platformthemes/gtk2/qgtk2theme.h
@@ -0,0 +1,64 @@
+/****************************************************************************
+**
+** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the plugins of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Digia. For licensing terms and
+** conditions see http://qt.digia.com/licensing. For further information
+** use the contact form at http://qt.digia.com/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Digia gives you certain additional
+** rights. These rights are described in the Digia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QGTK2THEME_H
+#define QGTK2THEME_H
+
+#include <private/qgenericunixthemes_p.h>
+
+QT_BEGIN_NAMESPACE
+
+class QGtk2Theme : public QGnomeTheme
+{
+public:
+ QGtk2Theme();
+
+ QVariant themeHint(ThemeHint hint) const;
+
+ bool usePlatformNativeDialog(DialogType type) const;
+ QPlatformDialogHelper *createPlatformDialogHelper(DialogType type) const;
+
+ static const char *name;
+};
+
+QT_END_NAMESPACE
+
+#endif // QGTK2THEME_H
diff --git a/src/plugins/platformthemes/platformthemes.pro b/src/plugins/platformthemes/platformthemes.pro
new file mode 100644
index 0000000000..23dcda2c82
--- /dev/null
+++ b/src/plugins/platformthemes/platformthemes.pro
@@ -0,0 +1,3 @@
+TEMPLATE = subdirs
+
+contains(QT_CONFIG, gtk2): SUBDIRS += gtk2
diff --git a/src/plugins/plugins.pro b/src/plugins/plugins.pro
index 3b0ff3f6c8..516105401e 100644
--- a/src/plugins/plugins.pro
+++ b/src/plugins/plugins.pro
@@ -1,7 +1,8 @@
TEMPLATE = subdirs
-SUBDIRS *= sqldrivers bearer
-qtHaveModule(gui): SUBDIRS *= imageformats platforms platforminputcontexts generic
+SUBDIRS *= sqldrivers
+qtHaveModule(network): SUBDIRS += bearer
+qtHaveModule(gui): SUBDIRS *= imageformats platforms platforminputcontexts platformthemes generic
qtHaveModule(widgets): SUBDIRS += accessible
!wince*:qtHaveModule(widgets): SUBDIRS += printsupport
diff --git a/src/plugins/printsupport/cups/qcupsprintengine.cpp b/src/plugins/printsupport/cups/qcupsprintengine.cpp
index 21895e9d28..1c86420cb2 100644
--- a/src/plugins/printsupport/cups/qcupsprintengine.cpp
+++ b/src/plugins/printsupport/cups/qcupsprintengine.cpp
@@ -103,7 +103,9 @@ void QCupsPrintEngine::setProperty(PrintEnginePropertyKey key, const QVariant &v
d->cupsOptions = value.toStringList();
break;
case PPK_CupsStringPageSize:
+ case PPK_PaperName:
d->cupsStringPageSize = value.toString();
+ d->setPaperName();
break;
case PPK_PrinterName:
// prevent setting the defaults again for the same printer
@@ -140,6 +142,7 @@ QVariant QCupsPrintEngine::property(PrintEnginePropertyKey key) const
ret = d->cupsOptions;
break;
case PPK_CupsStringPageSize:
+ case PPK_PaperName:
ret = d->cupsStringPageSize;
break;
default:
@@ -284,6 +287,7 @@ void QCupsPrintEnginePrivate::setPaperSize()
QPdf::PaperSize size = QPdf::paperSize(QPrinter::PaperSize(printerPaperSize));
if (cups.currentPPD()) {
+ cupsStringPageSize = QLatin1String("Custom");
const ppd_option_t* pageSizes = cups.pageSizes();
for (int i = 0; i < pageSizes->num_choices; ++i) {
QByteArray cupsPageSize = pageSizes->choices[i].choice;
@@ -293,7 +297,7 @@ void QCupsPrintEnginePrivate::setPaperSize()
if (qAbs(size.width - tmpCupsPaperRect.width()) < 5 && qAbs(size.height - tmpCupsPaperRect.height()) < 5) {
cupsPaperRect = tmpCupsPaperRect;
cupsPageRect = tmpCupsPageRect;
-
+ cupsStringPageSize = pageSizes->choices[i].text;
leftMargin = cupsPageRect.x() - cupsPaperRect.x();
topMargin = cupsPageRect.y() - cupsPaperRect.y();
rightMargin = cupsPaperRect.right() - cupsPageRect.right();
@@ -307,6 +311,43 @@ void QCupsPrintEnginePrivate::setPaperSize()
}
}
+void QCupsPrintEnginePrivate::setPaperName()
+{
+ if (QCUPSSupport::isAvailable()) {
+ QCUPSSupport cups;
+ if (cups.currentPPD()) {
+ const ppd_option_t* pageSizes = cups.pageSizes();
+ bool foundPaperName = false;
+ for (int i = 0; i < pageSizes->num_choices; ++i) {
+ if (cupsStringPageSize == pageSizes->choices[i].text) {
+ foundPaperName = true;
+ QByteArray cupsPageSize = pageSizes->choices[i].choice;
+ cupsPaperRect = cups.paperRect(cupsPageSize);
+ cupsPageRect = cups.pageRect(cupsPageSize);
+ leftMargin = cupsPageRect.x() - cupsPaperRect.x();
+ topMargin = cupsPageRect.y() - cupsPaperRect.y();
+ rightMargin = cupsPaperRect.right() - cupsPageRect.right();
+ bottomMargin = cupsPaperRect.bottom() - cupsPageRect.bottom();
+ printerPaperSize = QPrinter::Custom;
+ customPaperSize = cupsPaperRect.size();
+ for (int ps = 0; ps < QPrinter::NPageSize; ++ps) {
+ QPdf::PaperSize size = QPdf::paperSize(QPrinter::PaperSize(ps));
+ if (qAbs(size.width - cupsPaperRect.width()) < 5 && qAbs(size.height - cupsPaperRect.height()) < 5) {
+ printerPaperSize = static_cast<QPrinter::PaperSize>(ps);
+ customPaperSize = QSize();
+ break;
+ }
+ }
+ updatePaperSize();
+ break;
+ }
+ }
+ if (!foundPaperName)
+ cupsStringPageSize = QString();
+ }
+ }
+}
+
void QCupsPrintEnginePrivate::setCupsDefaults()
{
if (QCUPSSupport::isAvailable()) {
@@ -348,8 +389,10 @@ void QCupsPrintEnginePrivate::setCupsDefaults()
const ppd_option_t* pageSizes = cups.pageSizes();
QByteArray cupsPageSize;
for (int i = 0; i < pageSizes->num_choices; ++i) {
- if (static_cast<int>(pageSizes->choices[i].marked) == 1)
+ if (static_cast<int>(pageSizes->choices[i].marked) == 1) {
cupsPageSize = pageSizes->choices[i].choice;
+ cupsStringPageSize = pageSizes->choices[i].text;
+ }
}
cupsOptions = cups.options();
diff --git a/src/plugins/printsupport/cups/qcupsprintengine_p.h b/src/plugins/printsupport/cups/qcupsprintengine_p.h
index 31ee6bb256..db947a0232 100644
--- a/src/plugins/printsupport/cups/qcupsprintengine_p.h
+++ b/src/plugins/printsupport/cups/qcupsprintengine_p.h
@@ -97,6 +97,7 @@ public:
void updatePaperSize();
void setPaperSize();
+ void setPaperName();
void setCupsDefaults();
private:
diff --git a/src/plugins/printsupport/cups/qcupsprintersupport.cpp b/src/plugins/printsupport/cups/qcupsprintersupport.cpp
index c2e9bd445f..f41d4f5047 100644
--- a/src/plugins/printsupport/cups/qcupsprintersupport.cpp
+++ b/src/plugins/printsupport/cups/qcupsprintersupport.cpp
@@ -86,6 +86,11 @@ QList<QPrinter::PaperSize> QCupsPrinterSupport::supportedPaperSizes(const QPrint
return QCUPSSupport::getCupsPrinterPaperSizes(printerIndex(printerInfo));
}
+QList<QPair<QString, QSizeF> > QCupsPrinterSupport::supportedSizesWithNames(const QPrinterInfo &printerInfo) const
+{
+ return QCUPSSupport::getCupsPrinterPaperSizesWithNames(printerIndex(printerInfo));
+}
+
void QCupsPrinterSupport::loadCups()
{
cupsGetDests = (CupsGetDests) m_cups.resolve("cupsGetDests");
diff --git a/src/plugins/printsupport/cups/qcupsprintersupport_p.h b/src/plugins/printsupport/cups/qcupsprintersupport_p.h
index 43fe871021..e9fe24203e 100644
--- a/src/plugins/printsupport/cups/qcupsprintersupport_p.h
+++ b/src/plugins/printsupport/cups/qcupsprintersupport_p.h
@@ -52,7 +52,6 @@
#include <cups/cups.h>
-QT_BEGIN_HEADER
QT_BEGIN_NAMESPACE
typedef int (*CupsGetDests)(cups_dest_t **dests);
@@ -68,6 +67,7 @@ public:
virtual QPrintEngine *createNativePrintEngine(QPrinter::PrinterMode printerMode);
virtual QPaintEngine *createPaintEngine(QPrintEngine *printEngine, QPrinter::PrinterMode);
virtual QList<QPrinter::PaperSize> supportedPaperSizes(const QPrinterInfo &) const;
+ virtual QList<QPair<QString, QSizeF> > supportedSizesWithNames(const QPrinterInfo &) const;
virtual QString printerOption(const QPrinterInfo &printer, const QString &key) const;
virtual PrinterOptions printerOptions(const QPrinterInfo &printer) const;
@@ -86,7 +86,6 @@ private:
};
QT_END_NAMESPACE
-QT_END_HEADER
#endif // QT_NO_PRINTER
#endif // QCUPSPRINTERSUPPORT_H
diff --git a/src/plugins/printsupport/windows/qwindowsprintersupport.cpp b/src/plugins/printsupport/windows/qwindowsprintersupport.cpp
index 469dbdb34e..36e7a3fb8e 100644
--- a/src/plugins/printsupport/windows/qwindowsprintersupport.cpp
+++ b/src/plugins/printsupport/windows/qwindowsprintersupport.cpp
@@ -93,4 +93,9 @@ QList<QPrinter::PaperSize> QWindowsPrinterSupport::supportedPaperSizes(const QPr
return QWin32PrintEngine::supportedPaperSizes(printerInfo);
}
+QList<QPair<QString, QSizeF> >QWindowsPrinterSupport::supportedSizesWithNames(const QPrinterInfo &printerInfo) const
+{
+ return QWin32PrintEngine::supportedSizesWithNames(printerInfo);
+}
+
QT_END_NAMESPACE
diff --git a/src/plugins/printsupport/windows/qwindowsprintersupport.h b/src/plugins/printsupport/windows/qwindowsprintersupport.h
index afa341a82f..1d5a4f3da4 100644
--- a/src/plugins/printsupport/windows/qwindowsprintersupport.h
+++ b/src/plugins/printsupport/windows/qwindowsprintersupport.h
@@ -44,7 +44,6 @@
#include <qpa/qplatformprintersupport.h>
-QT_BEGIN_HEADER
QT_BEGIN_NAMESPACE
class QWin32PrintEngine;
@@ -58,9 +57,9 @@ public:
virtual QPrintEngine *createNativePrintEngine(QPrinter::PrinterMode printerMode);
virtual QPaintEngine *createPaintEngine(QPrintEngine *printEngine, QPrinter::PrinterMode);
virtual QList<QPrinter::PaperSize> supportedPaperSizes(const QPrinterInfo &) const;
+ virtual QList<QPair<QString, QSizeF> >supportedSizesWithNames(const QPrinterInfo &printerInfo) const;
};
QT_END_NAMESPACE
-QT_END_HEADER
#endif // WINDOWSPRINTERSUPPORT_H
diff --git a/src/plugins/sqldrivers/db2/main.cpp b/src/plugins/sqldrivers/db2/main.cpp
index abde11b178..6c796beff6 100644
--- a/src/plugins/sqldrivers/db2/main.cpp
+++ b/src/plugins/sqldrivers/db2/main.cpp
@@ -41,7 +41,7 @@
#include <qsqldriverplugin.h>
#include <qstringlist.h>
-#include "../../../sql/drivers/db2/qsql_db2.h"
+#include "../../../sql/drivers/db2/qsql_db2_p.h"
QT_BEGIN_NAMESPACE
diff --git a/src/plugins/sqldrivers/ibase/main.cpp b/src/plugins/sqldrivers/ibase/main.cpp
index 1ce663d868..e7d1c38690 100644
--- a/src/plugins/sqldrivers/ibase/main.cpp
+++ b/src/plugins/sqldrivers/ibase/main.cpp
@@ -41,7 +41,7 @@
#include <qsqldriverplugin.h>
#include <qstringlist.h>
-#include "../../../sql/drivers/ibase/qsql_ibase.h"
+#include "../../../sql/drivers/ibase/qsql_ibase_p.h"
QT_BEGIN_NAMESPACE
diff --git a/src/plugins/sqldrivers/mysql/main.cpp b/src/plugins/sqldrivers/mysql/main.cpp
index d313152cd7..8aaee6c268 100644
--- a/src/plugins/sqldrivers/mysql/main.cpp
+++ b/src/plugins/sqldrivers/mysql/main.cpp
@@ -41,7 +41,7 @@
#include <qsqldriverplugin.h>
#include <qstringlist.h>
-#include "../../../sql/drivers/mysql/qsql_mysql.h"
+#include "../../../sql/drivers/mysql/qsql_mysql_p.h"
QT_BEGIN_NAMESPACE
diff --git a/src/plugins/sqldrivers/oci/main.cpp b/src/plugins/sqldrivers/oci/main.cpp
index fc069df534..f1b0266536 100644
--- a/src/plugins/sqldrivers/oci/main.cpp
+++ b/src/plugins/sqldrivers/oci/main.cpp
@@ -41,7 +41,7 @@
#include <qsqldriverplugin.h>
#include <qstringlist.h>
-#include "../../../sql/drivers/oci/qsql_oci.h"
+#include "../../../sql/drivers/oci/qsql_oci_p.h"
QT_BEGIN_NAMESPACE
diff --git a/src/plugins/sqldrivers/odbc/main.cpp b/src/plugins/sqldrivers/odbc/main.cpp
index 215cbf6042..fda5c68fcc 100644
--- a/src/plugins/sqldrivers/odbc/main.cpp
+++ b/src/plugins/sqldrivers/odbc/main.cpp
@@ -41,7 +41,7 @@
#include <qsqldriverplugin.h>
#include <qstringlist.h>
-#include "../../../sql/drivers/odbc/qsql_odbc.h"
+#include "../../../sql/drivers/odbc/qsql_odbc_p.h"
QT_BEGIN_NAMESPACE
diff --git a/src/plugins/sqldrivers/psql/main.cpp b/src/plugins/sqldrivers/psql/main.cpp
index b3cba82f3e..3851ba6bfe 100644
--- a/src/plugins/sqldrivers/psql/main.cpp
+++ b/src/plugins/sqldrivers/psql/main.cpp
@@ -41,7 +41,7 @@
#include <qsqldriverplugin.h>
#include <qstringlist.h>
-#include "../../../sql/drivers/psql/qsql_psql.h"
+#include "../../../sql/drivers/psql/qsql_psql_p.h"
QT_BEGIN_NAMESPACE
diff --git a/src/plugins/sqldrivers/sqlite/smain.cpp b/src/plugins/sqldrivers/sqlite/smain.cpp
index e52c235c18..1835962331 100644
--- a/src/plugins/sqldrivers/sqlite/smain.cpp
+++ b/src/plugins/sqldrivers/sqlite/smain.cpp
@@ -41,7 +41,7 @@
#include <qsqldriverplugin.h>
#include <qstringlist.h>
-#include "../../../../src/sql/drivers/sqlite/qsql_sqlite.h"
+#include "../../../../src/sql/drivers/sqlite/qsql_sqlite_p.h"
QT_BEGIN_NAMESPACE
diff --git a/src/plugins/sqldrivers/sqlite2/smain.cpp b/src/plugins/sqldrivers/sqlite2/smain.cpp
index 38eb8e7fed..e15834a18e 100644
--- a/src/plugins/sqldrivers/sqlite2/smain.cpp
+++ b/src/plugins/sqldrivers/sqlite2/smain.cpp
@@ -41,7 +41,7 @@
#include <qsqldriverplugin.h>
#include <qstringlist.h>
-#include "../../../../src/sql/drivers/sqlite2/qsql_sqlite2.h"
+#include "../../../../src/sql/drivers/sqlite2/qsql_sqlite2_p.h"
QT_BEGIN_NAMESPACE
diff --git a/src/plugins/sqldrivers/tds/main.cpp b/src/plugins/sqldrivers/tds/main.cpp
index 9066efa172..1cb04e9e07 100644
--- a/src/plugins/sqldrivers/tds/main.cpp
+++ b/src/plugins/sqldrivers/tds/main.cpp
@@ -47,7 +47,7 @@
#define _WINSCARD_H_
#include <windows.h>
#endif
-#include "../../../sql/drivers/tds/qsql_tds.h"
+#include "../../../sql/drivers/tds/qsql_tds_p.h"
QT_BEGIN_NAMESPACE