summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorKent Hansen <khansen@trolltech.com>2009-08-05 14:10:47 (GMT)
committerKent Hansen <khansen@trolltech.com>2009-08-05 14:10:47 (GMT)
commit1d7d5436eea09a232187836e59d2a937a752dee4 (patch)
tree6bd9ae61abb1467aceddc5a828fc2e65d93b2534 /src
parent791bddfcd5cc7540219835ef5d91486acd833c4b (diff)
parentfb8bb148affec842e8fa1a70616c64c7d3066ee8 (diff)
downloadQt-1d7d5436eea09a232187836e59d2a937a752dee4.zip
Qt-1d7d5436eea09a232187836e59d2a937a752dee4.tar.gz
Qt-1d7d5436eea09a232187836e59d2a937a752dee4.tar.bz2
Merge branch 'master' of git@scm.dev.nokia.troll.no:qt/qt into qtscript-jsc-backend
Conflicts: src/script/qscriptextqobject.cpp
Diffstat (limited to 'src')
-rw-r--r--src/3rdparty/phonon/ds9/abstractvideorenderer.cpp4
-rw-r--r--src/3rdparty/phonon/ds9/fakesource.cpp2
-rw-r--r--src/3rdparty/phonon/ds9/iodevicereader.cpp2
-rw-r--r--src/3rdparty/phonon/ds9/mediagraph.cpp8
-rw-r--r--src/3rdparty/phonon/ds9/mediaobject.cpp7
-rw-r--r--src/3rdparty/phonon/ds9/qbasefilter.cpp7
-rw-r--r--src/3rdparty/phonon/ds9/qmeminputpin.cpp7
-rw-r--r--src/3rdparty/phonon/ds9/qpin.cpp8
-rw-r--r--src/3rdparty/phonon/ds9/videorenderer_soft.cpp6
-rw-r--r--src/3rdparty/webkit/WebKit/qt/Api/qwebhistory.cpp15
-rw-r--r--src/activeqt/container/qaxbase.cpp14
-rw-r--r--src/activeqt/container/qaxwidget.cpp46
-rw-r--r--src/activeqt/control/qaxserverbase.cpp103
-rw-r--r--src/activeqt/shared/qaxtypes.cpp2
-rw-r--r--src/activeqt/shared/qaxtypes.h3
-rw-r--r--src/corelib/animation/qabstractanimation.cpp30
-rw-r--r--src/corelib/animation/qabstractanimation_p.h3
-rw-r--r--src/corelib/animation/qparallelanimationgroup.cpp3
-rw-r--r--src/corelib/animation/qvariantanimation.cpp2
-rw-r--r--src/corelib/arch/qatomic_vxworks.h2
-rw-r--r--src/corelib/global/qglobal.cpp4
-rw-r--r--src/corelib/global/qglobal.h21
-rw-r--r--src/corelib/global/qnamespace.h16
-rw-r--r--src/corelib/io/qfilesystemwatcher_fsevents.cpp7
-rw-r--r--src/corelib/io/qfilesystemwatcher_fsevents_p.h1
-rw-r--r--src/corelib/kernel/kernel.pri5
-rw-r--r--src/corelib/kernel/qabstractitemmodel.cpp52
-rw-r--r--src/corelib/kernel/qabstractitemmodel.h4
-rw-r--r--src/corelib/kernel/qabstractitemmodel_p.h5
-rw-r--r--src/corelib/kernel/qcore_unix.cpp73
-rw-r--r--src/corelib/kernel/qcore_unix_p.h38
-rw-r--r--src/corelib/kernel/qcoreevent.cpp2
-rw-r--r--src/corelib/kernel/qcoreevent.h2
-rw-r--r--src/corelib/kernel/qeventdispatcher_glib.cpp1
-rw-r--r--src/corelib/kernel/qeventdispatcher_unix_p.h3
-rw-r--r--src/corelib/kernel/qfunctions_vxworks.cpp4
-rw-r--r--src/corelib/kernel/qfunctions_vxworks.h2
-rw-r--r--src/corelib/kernel/qguard_p.h157
-rw-r--r--src/corelib/kernel/qmetaobject.cpp111
-rw-r--r--src/corelib/kernel/qmetaobject.h4
-rw-r--r--src/corelib/kernel/qobject.cpp132
-rw-r--r--src/corelib/kernel/qobject.h11
-rw-r--r--src/corelib/kernel/qobject_p.h148
-rw-r--r--src/corelib/kernel/qobjectdefs.h5
-rw-r--r--src/corelib/statemachine/qabstracttransition.cpp22
-rw-r--r--src/corelib/statemachine/qabstracttransition.h3
-rw-r--r--src/corelib/statemachine/qeventtransition.cpp30
-rw-r--r--src/corelib/statemachine/qeventtransition.h5
-rw-r--r--src/corelib/statemachine/qsignalevent.h6
-rw-r--r--src/corelib/statemachine/qsignaltransition.cpp15
-rw-r--r--src/corelib/statemachine/qsignaltransition.h3
-rw-r--r--src/corelib/statemachine/qstate.cpp6
-rw-r--r--src/corelib/statemachine/qstatemachine.cpp104
-rw-r--r--src/corelib/statemachine/qstatemachine_p.h12
-rw-r--r--src/corelib/tools/qbytedata_p.h12
-rw-r--r--src/corelib/tools/qcontiguouscache.h7
-rw-r--r--src/corelib/tools/qshareddata.cpp2
-rw-r--r--src/corelib/tools/qsharedpointer.cpp149
-rw-r--r--src/corelib/tools/qsharedpointer.h1
-rw-r--r--src/corelib/tools/qsharedpointer_impl.h192
-rw-r--r--src/gui/accessible/accessible.pri3
-rw-r--r--src/gui/accessible/qaccessible_mac_cocoa.mm234
-rw-r--r--src/gui/dialogs/qcolordialog.cpp22
-rw-r--r--src/gui/dialogs/qcolordialog_mac.mm221
-rw-r--r--src/gui/dialogs/qcolordialog_p.h13
-rw-r--r--src/gui/dialogs/qfiledialog.cpp13
-rw-r--r--src/gui/dialogs/qfiledialog_win.cpp6
-rw-r--r--src/gui/dialogs/qfilesystemmodel.cpp1
-rw-r--r--src/gui/egl/qegl.cpp11
-rw-r--r--src/gui/egl/qegl_p.h3
-rw-r--r--src/gui/egl/qegl_x11.cpp23
-rw-r--r--src/gui/egl/qeglproperties.cpp25
-rw-r--r--src/gui/egl/qeglproperties_p.h1
-rw-r--r--src/gui/embedded/qkbdqnx_qws.cpp10
-rw-r--r--src/gui/embedded/qkbdqnx_qws.h10
-rw-r--r--src/gui/embedded/qmouseqnx_qws.cpp10
-rw-r--r--src/gui/embedded/qmouseqnx_qws.h10
-rw-r--r--src/gui/embedded/qscreenqnx_qws.cpp10
-rw-r--r--src/gui/embedded/qscreenqnx_qws.h10
-rw-r--r--src/gui/graphicsview/qgraphicsitem.cpp252
-rw-r--r--src/gui/graphicsview/qgraphicsitem.h3
-rw-r--r--src/gui/graphicsview/qgraphicsitem_p.h9
-rw-r--r--src/gui/graphicsview/qgraphicsscene.cpp8
-rw-r--r--src/gui/graphicsview/qgraphicsscenebsptreeindex.cpp9
-rw-r--r--src/gui/graphicsview/qgraphicstransform.cpp344
-rw-r--r--src/gui/graphicsview/qgraphicstransform.h1
-rw-r--r--src/gui/image/image.pri6
-rw-r--r--src/gui/image/qimage.cpp17
-rw-r--r--src/gui/image/qimagepixmapcleanuphooks.cpp110
-rw-r--r--src/gui/image/qimagepixmapcleanuphooks_p.h (renamed from src/gui/painting/qregion_wince.cpp)104
-rw-r--r--src/gui/image/qpixmap.cpp24
-rw-r--r--src/gui/image/qpixmap_mac.cpp1
-rw-r--r--src/gui/image/qpixmap_x11.cpp23
-rw-r--r--src/gui/image/qpixmap_x11_p.h12
-rw-r--r--src/gui/image/qpixmapdata_p.h1
-rw-r--r--src/gui/itemviews/qabstractitemview.cpp1
-rw-r--r--src/gui/itemviews/qitemdelegate.cpp24
-rw-r--r--src/gui/itemviews/qstyleditemdelegate.cpp24
-rw-r--r--src/gui/kernel/qaction.h30
-rw-r--r--src/gui/kernel/qapplication.cpp108
-rw-r--r--src/gui/kernel/qapplication_mac.mm49
-rw-r--r--src/gui/kernel/qapplication_win.cpp12
-rw-r--r--src/gui/kernel/qboxlayout.cpp6
-rw-r--r--src/gui/kernel/qcocoaview_mac.mm4
-rw-r--r--src/gui/kernel/qcursor.cpp4
-rw-r--r--src/gui/kernel/qevent.cpp1
-rw-r--r--src/gui/kernel/qevent_p.h14
-rw-r--r--src/gui/kernel/qformlayout.cpp6
-rw-r--r--src/gui/kernel/qgesture.cpp51
-rw-r--r--src/gui/kernel/qgesture.h14
-rw-r--r--src/gui/kernel/qgesture_p.h11
-rw-r--r--src/gui/kernel/qgridlayout.cpp2
-rw-r--r--src/gui/kernel/qlayout.cpp4
-rw-r--r--src/gui/kernel/qstandardgestures.cpp243
-rw-r--r--src/gui/kernel/qstandardgestures.h20
-rw-r--r--src/gui/kernel/qstandardgestures_p.h29
-rw-r--r--src/gui/kernel/qwidget.cpp89
-rw-r--r--src/gui/kernel/qwidget_mac.mm59
-rw-r--r--src/gui/kernel/qwidget_win.cpp31
-rw-r--r--src/gui/painting/painting.pri8
-rw-r--r--src/gui/painting/qblendfunctions.cpp8
-rw-r--r--src/gui/painting/qdatabuffer_p.h17
-rw-r--r--src/gui/painting/qdrawhelper.cpp72
-rw-r--r--src/gui/painting/qoutlinemapper.cpp69
-rw-r--r--src/gui/painting/qpaintengine_raster.cpp6
-rw-r--r--src/gui/painting/qpaintengineex.cpp106
-rw-r--r--src/gui/painting/qpainter.cpp2
-rw-r--r--src/gui/painting/qregion.cpp28
-rw-r--r--src/gui/painting/qregion.h5
-rw-r--r--src/gui/painting/qregion_mac.cpp37
-rw-r--r--src/gui/painting/qregion_win.cpp512
-rw-r--r--src/gui/painting/qtransform.cpp48
-rw-r--r--src/gui/painting/qwindowsurface_raster.cpp4
-rw-r--r--src/gui/painting/qwindowsurface_x11.cpp4
-rw-r--r--src/gui/statemachine/qkeyeventtransition.cpp13
-rw-r--r--src/gui/statemachine/qkeyeventtransition.h3
-rw-r--r--src/gui/statemachine/qmouseeventtransition.cpp15
-rw-r--r--src/gui/statemachine/qmouseeventtransition.h4
-rw-r--r--src/gui/styles/gtksymbols.cpp19
-rw-r--r--src/gui/styles/qstylesheetstyle.cpp8
-rw-r--r--src/gui/styles/qwindowsxpstyle.cpp18
-rw-r--r--src/gui/text/qfontengine_ft.cpp4
-rw-r--r--src/gui/text/qfontengine_mac.mm9
-rw-r--r--src/gui/text/qtextcontrol_p.h2
-rw-r--r--src/gui/util/qcompleter.cpp8
-rw-r--r--src/gui/widgets/qlinecontrol.cpp4
-rw-r--r--src/gui/widgets/qlineedit_p.cpp4
-rw-r--r--src/gui/widgets/qmainwindowlayout.cpp3
-rw-r--r--src/gui/widgets/qmenu.cpp29
-rw-r--r--src/gui/widgets/qmenubar.cpp2
-rw-r--r--src/gui/widgets/qtextedit.cpp8
-rw-r--r--src/multimedia/audio/audio.pri56
-rw-r--r--src/multimedia/audio/qaudio.cpp102
-rw-r--r--src/multimedia/audio/qaudio.h71
-rw-r--r--src/multimedia/audio/qaudio_mac.cpp142
-rw-r--r--src/multimedia/audio/qaudio_mac_p.h144
-rw-r--r--src/multimedia/audio/qaudiodevicefactory.cpp250
-rw-r--r--src/multimedia/audio/qaudiodevicefactory_p.h100
-rw-r--r--src/multimedia/audio/qaudiodeviceid.cpp168
-rw-r--r--src/multimedia/audio/qaudiodeviceid.h94
-rw-r--r--src/multimedia/audio/qaudiodeviceid_p.h82
-rw-r--r--src/multimedia/audio/qaudiodeviceinfo.cpp270
-rw-r--r--src/multimedia/audio/qaudiodeviceinfo.h102
-rw-r--r--src/multimedia/audio/qaudiodeviceinfo_alsa_p.cpp394
-rw-r--r--src/multimedia/audio/qaudiodeviceinfo_alsa_p.h113
-rw-r--r--src/multimedia/audio/qaudiodeviceinfo_mac_p.cpp357
-rw-r--r--src/multimedia/audio/qaudiodeviceinfo_mac_p.h97
-rw-r--r--src/multimedia/audio/qaudiodeviceinfo_win32_p.cpp378
-rw-r--r--src/multimedia/audio/qaudiodeviceinfo_win32_p.h108
-rw-r--r--src/multimedia/audio/qaudioengine.cpp343
-rw-r--r--src/multimedia/audio/qaudioengine.h131
-rw-r--r--src/multimedia/audio/qaudioengineplugin.cpp54
-rw-r--r--src/multimedia/audio/qaudioengineplugin.h93
-rw-r--r--src/multimedia/audio/qaudioformat.cpp335
-rw-r--r--src/multimedia/audio/qaudioformat.h103
-rw-r--r--src/multimedia/audio/qaudioinput.cpp400
-rw-r--r--src/multimedia/audio/qaudioinput.h108
-rw-r--r--src/multimedia/audio/qaudioinput_alsa_p.cpp688
-rw-r--r--src/multimedia/audio/qaudioinput_alsa_p.h151
-rw-r--r--src/multimedia/audio/qaudioinput_mac_p.cpp930
-rw-r--r--src/multimedia/audio/qaudioinput_mac_p.h171
-rw-r--r--src/multimedia/audio/qaudioinput_win32_p.cpp540
-rw-r--r--src/multimedia/audio/qaudioinput_win32_p.h154
-rw-r--r--src/multimedia/audio/qaudiooutput.cpp403
-rw-r--r--src/multimedia/audio/qaudiooutput.h109
-rw-r--r--src/multimedia/audio/qaudiooutput_alsa_p.cpp706
-rw-r--r--src/multimedia/audio/qaudiooutput_alsa_p.h159
-rw-r--r--src/multimedia/audio/qaudiooutput_mac_p.cpp700
-rw-r--r--src/multimedia/audio/qaudiooutput_mac_p.h171
-rw-r--r--src/multimedia/audio/qaudiooutput_win32_p.cpp502
-rw-r--r--src/multimedia/audio/qaudiooutput_win32_p.h154
-rw-r--r--src/multimedia/multimedia.pro11
-rw-r--r--src/network/access/qhttpnetworkconnection.cpp281
-rw-r--r--src/network/access/qhttpnetworkconnection_p.h34
-rw-r--r--src/network/access/qhttpnetworkconnectionchannel.cpp214
-rw-r--r--src/network/access/qhttpnetworkconnectionchannel_p.h25
-rw-r--r--src/network/access/qhttpnetworkreply.cpp30
-rw-r--r--src/network/access/qhttpnetworkreply_p.h5
-rw-r--r--src/network/access/qnetworkaccessmanager.cpp7
-rw-r--r--src/network/access/qnetworkcookiejar.h6
-rw-r--r--src/network/access/qnetworkreply.cpp9
-rw-r--r--src/network/socket/qnet_unix_p.h2
-rw-r--r--src/opengl/opengl.pro1
-rw-r--r--src/opengl/qgl.cpp46
-rw-r--r--src/opengl/qgl_p.h14
-rw-r--r--src/opengl/qgl_x11.cpp199
-rw-r--r--src/opengl/qgl_x11egl.cpp179
-rw-r--r--src/opengl/qglcolormap.cpp24
-rw-r--r--src/plugins/audio/audio.pro3
-rw-r--r--src/plugins/gfxdrivers/directfb/qdirectfbkeyboard.cpp29
-rw-r--r--src/plugins/gfxdrivers/directfb/qdirectfbpaintdevice.cpp13
-rw-r--r--src/plugins/gfxdrivers/directfb/qdirectfbpaintdevice.h21
-rw-r--r--src/plugins/gfxdrivers/directfb/qdirectfbpaintengine.cpp293
-rw-r--r--src/plugins/gfxdrivers/directfb/qdirectfbpixmap.cpp13
-rw-r--r--src/plugins/gfxdrivers/directfb/qdirectfbpixmap.h3
-rw-r--r--src/plugins/gfxdrivers/directfb/qdirectfbscreen.cpp21
-rw-r--r--src/plugins/gfxdrivers/directfb/qdirectfbscreen.h3
-rw-r--r--src/plugins/gfxdrivers/directfb/qdirectfbwindowsurface.cpp26
-rw-r--r--src/plugins/gfxdrivers/directfb/qdirectfbwindowsurface.h7
-rw-r--r--src/plugins/plugins.pro1
-rw-r--r--src/sql/drivers/mysql/qsql_mysql.cpp47
-rw-r--r--src/sql/drivers/psql/qsql_psql.cpp10
-rw-r--r--src/src.pro4
-rw-r--r--src/svg/qsvggraphics.cpp286
-rw-r--r--src/svg/qsvggraphics_p.h51
-rw-r--r--src/svg/qsvghandler.cpp590
-rw-r--r--src/svg/qsvgnode_p.h1
-rw-r--r--src/svg/qsvgstyle.cpp126
-rw-r--r--src/svg/qsvgstyle_p.h80
-rw-r--r--src/testlib/qabstracttestlogger_p.h36
-rw-r--r--src/testlib/qplaintestlogger.cpp8
-rw-r--r--src/testlib/qtest_global.h1
-rw-r--r--src/testlib/qtestbasicstreamer.cpp24
-rw-r--r--src/testlib/qtestbasicstreamer.h10
-rw-r--r--src/testlib/qtestcase.cpp55
-rw-r--r--src/testlib/qtestlightxmlstreamer.cpp93
-rw-r--r--src/testlib/qtestlightxmlstreamer.h6
-rw-r--r--src/testlib/qtestxmlstreamer.cpp119
-rw-r--r--src/testlib/qtestxmlstreamer.h6
-rw-r--r--src/testlib/qtestxunitstreamer.cpp42
-rw-r--r--src/testlib/qtestxunitstreamer.h8
-rw-r--r--src/testlib/qxmltestlogger.cpp187
-rw-r--r--src/testlib/qxmltestlogger_p.h6
-rw-r--r--src/tools/moc/generator.cpp17
-rw-r--r--src/tools/moc/moc.cpp28
-rw-r--r--src/tools/moc/moc.h4
-rw-r--r--src/xmlpatterns/acceltree/qacceltreeresourceloader.cpp2
247 files changed, 14926 insertions, 3700 deletions
diff --git a/src/3rdparty/phonon/ds9/abstractvideorenderer.cpp b/src/3rdparty/phonon/ds9/abstractvideorenderer.cpp
index e932e70..a9d0694 100644
--- a/src/3rdparty/phonon/ds9/abstractvideorenderer.cpp
+++ b/src/3rdparty/phonon/ds9/abstractvideorenderer.cpp
@@ -99,8 +99,8 @@ namespace Phonon
m_dstX = m_dstY = 0;
if (ratio > 0) {
- if (realWidth / realHeight > ratio && scaleMode == Phonon::VideoWidget::FitInView
- || realWidth / realHeight < ratio && scaleMode == Phonon::VideoWidget::ScaleAndCrop) {
+ if ((realWidth / realHeight > ratio && scaleMode == Phonon::VideoWidget::FitInView)
+ || (realWidth / realHeight < ratio && scaleMode == Phonon::VideoWidget::ScaleAndCrop)) {
//the height is correct, let's change the width
m_dstWidth = qRound(realHeight * ratio);
m_dstX = qRound((realWidth - realHeight * ratio) / 2.);
diff --git a/src/3rdparty/phonon/ds9/fakesource.cpp b/src/3rdparty/phonon/ds9/fakesource.cpp
index a4d4640..4dce138 100644
--- a/src/3rdparty/phonon/ds9/fakesource.cpp
+++ b/src/3rdparty/phonon/ds9/fakesource.cpp
@@ -29,7 +29,7 @@ namespace Phonon
namespace DS9
{
static WAVEFORMATEX g_defaultWaveFormat = {WAVE_FORMAT_PCM, 2, 44100, 176400, 4, 16, 0};
- static VIDEOINFOHEADER2 g_defaultVideoInfo = { { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, 0, 0, 0, 0, 0, 0, 0, 0, 0, {sizeof(BITMAPINFOHEADER), 1, 1, 1, 0, 0, 0, 0, 0, 0, 0} };
+ static VIDEOINFOHEADER2 g_defaultVideoInfo = { { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, 0, 0, 0, 0, 0, 0, 0, {0}, 0, {sizeof(BITMAPINFOHEADER), 1, 1, 1, 0, 0, 0, 0, 0, 0, 0} };
static const AM_MEDIA_TYPE g_fakeAudioType = {MEDIATYPE_Audio, MEDIASUBTYPE_PCM, 0, 0, 2, FORMAT_WaveFormatEx, 0, sizeof(WAVEFORMATEX), reinterpret_cast<BYTE*>(&g_defaultWaveFormat)};
static const AM_MEDIA_TYPE g_fakeVideoType = {MEDIATYPE_Video, MEDIASUBTYPE_RGB32, TRUE, FALSE, 0, FORMAT_VideoInfo2, 0, sizeof(VIDEOINFOHEADER2), reinterpret_cast<BYTE*>(&g_defaultVideoInfo)};
diff --git a/src/3rdparty/phonon/ds9/iodevicereader.cpp b/src/3rdparty/phonon/ds9/iodevicereader.cpp
index 38c983b..a885a69 100644
--- a/src/3rdparty/phonon/ds9/iodevicereader.cpp
+++ b/src/3rdparty/phonon/ds9/iodevicereader.cpp
@@ -167,7 +167,7 @@ namespace Phonon
oldSize = currentBufferSize();
}
- DWORD bytesRead = qMin(currentBufferSize(), int(length));
+ int bytesRead = qMin(currentBufferSize(), int(length));
{
QWriteLocker locker(&m_lock);
qMemCopy(buffer, m_buffer.data(), bytesRead);
diff --git a/src/3rdparty/phonon/ds9/mediagraph.cpp b/src/3rdparty/phonon/ds9/mediagraph.cpp
index 31a0622..7b10176 100644
--- a/src/3rdparty/phonon/ds9/mediagraph.cpp
+++ b/src/3rdparty/phonon/ds9/mediagraph.cpp
@@ -68,6 +68,8 @@ namespace Phonon
return ret;
}
+
+/*
static HRESULT saveToFile(Graph graph, const QString &filepath)
{
const WCHAR wszStreamName[] = L"ActiveMovieGraph";
@@ -103,7 +105,7 @@ namespace Phonon
return hr;
}
-
+*/
MediaGraph::MediaGraph(MediaObject *mo, short index) :
m_graph(CLSID_FilterGraph, IID_IGraphBuilder),
@@ -537,7 +539,7 @@ namespace Phonon
const QList<OutputPin> outputs = BackendNode::pins(filter, PINDIR_OUTPUT);
for(int i = 0; i < outputs.count(); ++i) {
const OutputPin &pin = outputs.at(i);
- if (VFW_E_NOT_CONNECTED == pin->ConnectedTo(inPin.pparam())) {
+ if (HRESULT(VFW_E_NOT_CONNECTED) == pin->ConnectedTo(inPin.pparam())) {
return SUCCEEDED(pin->Connect(newIn, 0));
}
}
@@ -809,7 +811,7 @@ namespace Phonon
for (int i = 0; i < outputs.count(); ++i) {
const OutputPin &out = outputs.at(i);
InputPin pin;
- if (out->ConnectedTo(pin.pparam()) == VFW_E_NOT_CONNECTED) {
+ if (out->ConnectedTo(pin.pparam()) == HRESULT(VFW_E_NOT_CONNECTED)) {
m_decoderPins += out; //unconnected outputs can be decoded outputs
}
}
diff --git a/src/3rdparty/phonon/ds9/mediaobject.cpp b/src/3rdparty/phonon/ds9/mediaobject.cpp
index df42011..10782c2 100644
--- a/src/3rdparty/phonon/ds9/mediaobject.cpp
+++ b/src/3rdparty/phonon/ds9/mediaobject.cpp
@@ -786,15 +786,16 @@ namespace Phonon
case Phonon::PausedState:
pause();
break;
- case Phonon::StoppedState:
- stop();
- break;
case Phonon::PlayingState:
play();
break;
case Phonon::ErrorState:
setState(Phonon::ErrorState);
break;
+ case Phonon::StoppedState:
+ default:
+ stop();
+ break;
}
}
}
diff --git a/src/3rdparty/phonon/ds9/qbasefilter.cpp b/src/3rdparty/phonon/ds9/qbasefilter.cpp
index 95cab92..c950c41 100644
--- a/src/3rdparty/phonon/ds9/qbasefilter.cpp
+++ b/src/3rdparty/phonon/ds9/qbasefilter.cpp
@@ -92,8 +92,8 @@ namespace Phonon
return E_POINTER;
}
- int nbfetched = 0;
- while (nbfetched < int(count) && m_index < m_pins.count()) {
+ uint nbfetched = 0;
+ while (nbfetched < count && m_index < m_pins.count()) {
IPin *current = m_pins[m_index];
current->AddRef();
ret[nbfetched] = current;
@@ -211,7 +211,8 @@ namespace Phonon
}
else if (iid == IID_IMediaPosition || iid == IID_IMediaSeeking) {
if (inputPins().isEmpty()) {
- if (*out = getUpStreamInterface(iid)) {
+ *out = getUpStreamInterface(iid);
+ if (*out) {
return S_OK; //we return here to avoid adding a reference
} else {
hr = E_NOINTERFACE;
diff --git a/src/3rdparty/phonon/ds9/qmeminputpin.cpp b/src/3rdparty/phonon/ds9/qmeminputpin.cpp
index dca99db..865b8af 100644
--- a/src/3rdparty/phonon/ds9/qmeminputpin.cpp
+++ b/src/3rdparty/phonon/ds9/qmeminputpin.cpp
@@ -137,7 +137,8 @@ namespace Phonon
return E_POINTER;
}
- if (*alloc = memoryAllocator(true)) {
+ *alloc = memoryAllocator(true);
+ if (*alloc) {
return S_OK;
}
@@ -294,7 +295,7 @@ namespace Phonon
LONG length = sample->GetActualDataLength();
HRESULT hr = alloc->Commit();
- if (hr == VFW_E_SIZENOTSET) {
+ if (hr == HRESULT(VFW_E_SIZENOTSET)) {
ALLOCATOR_PROPERTIES prop = getDefaultAllocatorProperties();
prop.cbBuffer = qMax(prop.cbBuffer, length);
ALLOCATOR_PROPERTIES actual;
@@ -324,7 +325,7 @@ namespace Phonon
{
LONGLONG start, end;
hr = sample->GetMediaTime(&start, &end);
- if (hr != VFW_E_MEDIA_TIME_NOT_SET) {
+ if (hr != HRESULT(VFW_E_MEDIA_TIME_NOT_SET)) {
hr = out->SetMediaTime(&start, &end);
Q_ASSERT(SUCCEEDED(hr));
}
diff --git a/src/3rdparty/phonon/ds9/qpin.cpp b/src/3rdparty/phonon/ds9/qpin.cpp
index 68a4ec0..d14876b 100644
--- a/src/3rdparty/phonon/ds9/qpin.cpp
+++ b/src/3rdparty/phonon/ds9/qpin.cpp
@@ -91,8 +91,8 @@ namespace Phonon
return E_INVALIDARG;
}
- int nbFetched = 0;
- while (nbFetched < int(count) && m_index < m_pin->mediaTypes().count()) {
+ uint nbFetched = 0;
+ while (nbFetched < count && m_index < m_pin->mediaTypes().count()) {
//the caller will deallocate the memory
*out = static_cast<AM_MEDIA_TYPE *>(::CoTaskMemAlloc(sizeof(AM_MEDIA_TYPE)));
const AM_MEDIA_TYPE original = m_pin->mediaTypes().at(m_index);
@@ -145,9 +145,9 @@ namespace Phonon
QPin::QPin(QBaseFilter *parent, PIN_DIRECTION dir, const QVector<AM_MEDIA_TYPE> &mt) :
- m_memAlloc(0), m_parent(parent), m_refCount(1), m_connected(0),
+ m_parent(parent), m_flushing(false), m_refCount(1), m_connected(0),
m_direction(dir), m_mediaTypes(mt), m_connectedType(defaultMediaType),
- m_flushing(false)
+ m_memAlloc(0)
{
Q_ASSERT(m_parent);
m_parent->addPin(this);
diff --git a/src/3rdparty/phonon/ds9/videorenderer_soft.cpp b/src/3rdparty/phonon/ds9/videorenderer_soft.cpp
index 2112267..cf5ce96 100644
--- a/src/3rdparty/phonon/ds9/videorenderer_soft.cpp
+++ b/src/3rdparty/phonon/ds9/videorenderer_soft.cpp
@@ -194,8 +194,8 @@ namespace Phonon
m_sampleBuffer = ComPointer<IMediaSample>();
#ifndef QT_NO_OPENGL
freeGLResources();
-#endif // QT_NO_OPENGL
m_textureUploaded = false;
+#endif // QT_NO_OPENGL
}
void endOfStream()
@@ -314,7 +314,6 @@ namespace Phonon
REFERENCE_TIME m_start;
HANDLE m_renderEvent, m_receiveCanWait; // Signals sample to render
QSize m_size;
- bool m_textureUploaded;
//mixer settings
qreal m_brightness,
@@ -356,6 +355,7 @@ namespace Phonon
bool m_checkedPrograms;
bool m_usingOpenGL;
+ bool m_textureUploaded;
GLuint m_program[2];
GLuint m_texture[3];
#endif
@@ -436,7 +436,7 @@ namespace Phonon
QBaseFilter(CLSID_NULL), m_inputPin(new VideoRendererSoftPin(this)),
m_renderer(renderer), m_start(0)
#ifndef QT_NO_OPENGL
- ,m_usingOpenGL(false), m_checkedPrograms(false), m_textureUploaded(false)
+ , m_checkedPrograms(false), m_usingOpenGL(false), m_textureUploaded(false)
#endif
{
m_renderEvent = ::CreateEvent(0, 0, 0, 0);
diff --git a/src/3rdparty/webkit/WebKit/qt/Api/qwebhistory.cpp b/src/3rdparty/webkit/WebKit/qt/Api/qwebhistory.cpp
index e5eb308..1c1c72a 100644
--- a/src/3rdparty/webkit/WebKit/qt/Api/qwebhistory.cpp
+++ b/src/3rdparty/webkit/WebKit/qt/Api/qwebhistory.cpp
@@ -32,7 +32,6 @@
/*!
\class QWebHistoryItem
- \ingroup explicitly-shared
\since 4.4
\brief The QWebHistoryItem class represents one item in the history of a QWebPage
@@ -52,13 +51,17 @@
\row \o userData() \o The user specific data that was stored with the history item.
\endtable
- \note QWebHistoryItem objects are value based and \l{explicitly shared}.
+ \note QWebHistoryItem objects are value based, but \e{explicitly shared}. Changing
+ a QWebHistoryItem instance by calling setUserData() will change all copies of that
+ instance.
\sa QWebHistory, QWebPage::history(), QWebHistoryInterface
*/
/*!
- Constructs a history item from \a other.
+ Constructs a history item from \a other. The new item and \a other
+ will share their data, and modifying either this item or \a other will
+ modify both instances.
*/
QWebHistoryItem::QWebHistoryItem(const QWebHistoryItem &other)
: d(other.d)
@@ -66,7 +69,9 @@ QWebHistoryItem::QWebHistoryItem(const QWebHistoryItem &other)
}
/*!
- Assigns the \a other history item to this.
+ Assigns the \a other history item to this. This item and \a other
+ will share their data, and modifying either this item or \a other will
+ modify both instances.
*/
QWebHistoryItem &QWebHistoryItem::operator=(const QWebHistoryItem &other)
{
@@ -163,6 +168,8 @@ QVariant QWebHistoryItem::userData() const
\since 4.5
Stores user specific data \a userData with the history item.
+
+ \note All copies of this item will be modified.
\sa userData()
*/
diff --git a/src/activeqt/container/qaxbase.cpp b/src/activeqt/container/qaxbase.cpp
index 4fc9926..d602946 100644
--- a/src/activeqt/container/qaxbase.cpp
+++ b/src/activeqt/container/qaxbase.cpp
@@ -3204,12 +3204,12 @@ static const char qt_meta_stringdata_QAxBase[] = {
};
static QMetaObject qaxobject_staticMetaObject = {
- &QObject::staticMetaObject, qt_meta_stringdata_QAxBase,
- qt_meta_data_QAxBase, 0
+ { &QObject::staticMetaObject, qt_meta_stringdata_QAxBase,
+ qt_meta_data_QAxBase, 0 }
};
static QMetaObject qaxwidget_staticMetaObject = {
- &QWidget::staticMetaObject, qt_meta_stringdata_QAxBase,
- qt_meta_data_QAxBase, 0
+ { &QWidget::staticMetaObject, qt_meta_stringdata_QAxBase,
+ qt_meta_data_QAxBase, 0 }
};
/*!
@@ -3692,6 +3692,8 @@ int QAxBase::qt_metacall(QMetaObject::Call call, int id, void **v)
case QMetaMethod::Slot:
id = internalInvoke(call, id, v);
break;
+ default:
+ break;
}
break;
case QMetaObject::ReadProperty:
@@ -3706,6 +3708,8 @@ int QAxBase::qt_metacall(QMetaObject::Call call, int id, void **v)
case QMetaObject::QueryPropertyUser:
id -= mo->propertyCount();
break;
+ default:
+ break;
}
Q_ASSERT(id < 0);
return id;
@@ -3905,7 +3909,7 @@ bool QAxBase::dynamicCallHelper(const char *name, void *inout, QList<QVariant> &
else
paramType = d->metaobj->paramType(normFunction, i, &out);
- if (!parse && d->useMetaObject && var.type() == QVariant::String || var.type() == QVariant::ByteArray) {
+ if ((!parse && d->useMetaObject && var.type() == QVariant::String) || var.type() == QVariant::ByteArray) {
int enumIndex =mo->indexOfEnumerator(paramType);
if (enumIndex != -1) {
QMetaEnum metaEnum =mo->enumerator(enumIndex);
diff --git a/src/activeqt/container/qaxwidget.cpp b/src/activeqt/container/qaxwidget.cpp
index ae468ef..e4c9d42 100644
--- a/src/activeqt/container/qaxwidget.cpp
+++ b/src/activeqt/container/qaxwidget.cpp
@@ -118,6 +118,8 @@ public:
QSize minimumSizeHint() const;
int qt_metacall(QMetaObject::Call, int isignal, void **argv);
+ void* qt_metacast(const char *clname);
+
inline QAxClientSite *clientSite() const
{
return axhost;
@@ -478,7 +480,9 @@ bool axc_FilterProc(void *m)
QAxWidget *ax = 0;
QAxHostWidget *host = 0;
while (!host && hwnd) {
- host = qobject_cast<QAxHostWidget*>(QWidget::find(hwnd));
+ QWidget *widget = QWidget::find(hwnd);
+ if (widget && widget->inherits("QAxHostWidget"))
+ host = qobject_cast<QAxHostWidget*>(widget);
hwnd = ::GetParent(hwnd);
}
if (host)
@@ -527,7 +531,7 @@ bool axc_FilterProc(void *m)
}
QAxClientSite::QAxClientSite(QAxWidget *c)
-: ref(1), widget(c), host(0), eventTranslated(true)
+: eventTranslated(true), ref(1), widget(c), host(0)
{
aggregatedObject = widget->createAggregate();
if (aggregatedObject) {
@@ -976,10 +980,38 @@ HRESULT WINAPI QAxClientSite::TransformCoords(POINTL* /*pPtlHimetric*/, POINTF*
HRESULT WINAPI QAxClientSite::TranslateAccelerator(LPMSG lpMsg, DWORD /*grfModifiers*/)
{
- eventTranslated = false;
if (lpMsg->message == WM_KEYDOWN && !lpMsg->wParam)
return S_OK;
+
+ bool ActiveQtDetected = false;
+ bool fromInProcServer = false;
+#ifdef GWLP_USERDATA
+ LONG_PTR serverType = GetWindowLongPtr(lpMsg->hwnd, GWLP_USERDATA);
+#else
+ LONG serverType = GetWindowLong(lpMsg->hwnd, GWL_USERDATA);
+#endif
+ if (serverType == QAX_INPROC_SERVER) {
+ ActiveQtDetected = true;
+ fromInProcServer = true;
+ } else if (serverType == QAX_OUTPROC_SERVER) {
+ ActiveQtDetected = true;
+ fromInProcServer = false;
+ }
+
+ eventTranslated = false;
+ if (!ActiveQtDetected || !fromInProcServer) {
+ // if the request is coming from an out-of-proc server or a non ActiveQt server,
+ // we send the message to the host window. This will make sure this key event
+ // comes to Qt for processing.
SendMessage(host->winId(), lpMsg->message, lpMsg->wParam, lpMsg->lParam);
+ if (ActiveQtDetected && !fromInProcServer) {
+ // ActiveQt based servers will need further processing of the event
+ // (eg. <SPACE> key for a checkbox), so we return false.
+ return S_FALSE;
+ }
+ }
+ // ActiveQt based in-processes-servers will handle the event properly, so
+ // we dont need to send this key event to the host.
return S_OK;
}
@@ -1617,6 +1649,14 @@ int QAxHostWidget::qt_metacall(QMetaObject::Call call, int isignal, void **argv)
return -1;
}
+void* QAxHostWidget::qt_metacast(const char *clname)
+{
+ if (!clname) return 0;
+ if (!qstrcmp(clname,"QAxHostWidget"))
+ return static_cast<void*>(const_cast< QAxHostWidget*>(this));
+ return QWidget::qt_metacast(clname);
+}
+
QSize QAxHostWidget::sizeHint() const
{
return axhost ? axhost->sizeHint() : QWidget::sizeHint();
diff --git a/src/activeqt/control/qaxserverbase.cpp b/src/activeqt/control/qaxserverbase.cpp
index d7a8e07..e7ddb47 100644
--- a/src/activeqt/control/qaxserverbase.cpp
+++ b/src/activeqt/control/qaxserverbase.cpp
@@ -3502,24 +3502,24 @@ Q_GUI_EXPORT int qt_translateKeyCode(int);
HRESULT WINAPI QAxServerBase::TranslateAcceleratorW(MSG *pMsg)
{
if (pMsg->message != WM_KEYDOWN || !isWidget)
- return S_FALSE;
+ return S_FALSE;
DWORD dwKeyMod = 0;
if (::GetKeyState(VK_SHIFT) < 0)
- dwKeyMod |= 1; // KEYMOD_SHIFT
+ dwKeyMod |= 1; // KEYMOD_SHIFT
if (::GetKeyState(VK_CONTROL) < 0)
- dwKeyMod |= 2; // KEYMOD_CONTROL
+ dwKeyMod |= 2; // KEYMOD_CONTROL
if (::GetKeyState(VK_MENU) < 0)
- dwKeyMod |= 4; // KEYMOD_ALT
+ dwKeyMod |= 4; // KEYMOD_ALT
switch (LOWORD(pMsg->wParam)) {
case VK_TAB:
- if (isUIActive) {
- bool shift = ::GetKeyState(VK_SHIFT) < 0;
- bool giveUp = true;
+ if (isUIActive) {
+ bool shift = ::GetKeyState(VK_SHIFT) < 0;
+ bool giveUp = true;
QWidget *curFocus = qt.widget->focusWidget();
if (curFocus) {
- if (shift) {
+ if (shift) {
if (!curFocus->isWindow()) {
QWidget *nextFocus = curFocus->nextInFocusChain();
QWidget *prevFocus = 0;
@@ -3537,9 +3537,10 @@ HRESULT WINAPI QAxServerBase::TranslateAcceleratorW(MSG *pMsg)
if (!topLevel) {
giveUp = false;
((HackWidget*)curFocus)->focusNextPrevChild(false);
+ curFocus->window()->setAttribute(Qt::WA_KeyboardFocusChange);
}
}
- } else {
+ } else {
QWidget *nextFocus = curFocus;
while (1) {
nextFocus = nextFocus->nextInFocusChain();
@@ -3548,64 +3549,82 @@ HRESULT WINAPI QAxServerBase::TranslateAcceleratorW(MSG *pMsg)
if (nextFocus->focusPolicy() & Qt::TabFocus) {
giveUp = false;
((HackWidget*)curFocus)->focusNextPrevChild(true);
+ curFocus->window()->setAttribute(Qt::WA_KeyboardFocusChange);
break;
}
}
- }
+ }
+ }
+ if (giveUp) {
+ HWND hwnd = ::GetParent(m_hWnd);
+ ::SetFocus(hwnd);
+ } else {
+ return S_OK;
}
- if (giveUp) {
- HWND hwnd = ::GetParent(m_hWnd);
- ::SetFocus(hwnd);
- } else {
- return S_OK;
- }
- }
- break;
+ }
+ break;
case VK_LEFT:
case VK_RIGHT:
case VK_UP:
case VK_DOWN:
- if (isUIActive)
- return S_FALSE;
- break;
+ if (isUIActive)
+ return S_FALSE;
+ break;
default:
- if (isUIActive && qt.widget->focusWidget()) {
+ if (isUIActive && qt.widget->focusWidget()) {
int state = Qt::NoButton;
- if (dwKeyMod & 1)
- state |= Qt::ShiftModifier;
- if (dwKeyMod & 2)
- state |= Qt::ControlModifier;
- if (dwKeyMod & 4)
- state |= Qt::AltModifier;
-
- int key = pMsg->wParam;
+ if (dwKeyMod & 1)
+ state |= Qt::ShiftModifier;
+ if (dwKeyMod & 2)
+ state |= Qt::ControlModifier;
+ if (dwKeyMod & 4)
+ state |= Qt::AltModifier;
+
+ int key = pMsg->wParam;
if (!(key >= 'A' && key <= 'Z') && !(key >= '0' && key <= '9'))
key = qt_translateKeyCode(pMsg->wParam);
- QKeyEvent override(QEvent::ShortcutOverride, key, (Qt::KeyboardModifiers)state);
- override.ignore();
- QApplication::sendEvent(qt.widget->focusWidget(), &override);
- if (override.isAccepted())
- return S_FALSE;
- }
- break;
+ QKeyEvent override(QEvent::ShortcutOverride, key, (Qt::KeyboardModifiers)state);
+ override.ignore();
+ QApplication::sendEvent(qt.widget->focusWidget(), &override);
+ if (override.isAccepted())
+ return S_FALSE;
+ }
+ break;
}
if (!m_spClientSite)
- return S_FALSE;
+ return S_FALSE;
IOleControlSite *controlSite = 0;
m_spClientSite->QueryInterface(IID_IOleControlSite, (void**)&controlSite);
if (!controlSite)
- return S_FALSE;
-
+ return S_FALSE;
+ bool resetUserData = false;
+ // set server type in the user-data of the window.
+#ifdef GWLP_USERDATA
+ LONG_PTR serverType = QAX_INPROC_SERVER;
+#else
+ LONG serverType = QAX_INPROC_SERVER;
+#endif
+ if (qAxOutProcServer)
+ serverType = QAX_OUTPROC_SERVER;
+#ifdef GWLP_USERDATA
+ LONG_PTR oldData = SetWindowLongPtr(pMsg->hwnd, GWLP_USERDATA, serverType);
+#else
+ LONG oldData = SetWindowLong(pMsg->hwnd, GWL_USERDATA, serverType);
+#endif
HRESULT hres = controlSite->TranslateAcceleratorW(pMsg, dwKeyMod);
-
controlSite->Release();
-
+ // reset the user-data for the window.
+#ifdef GWLP_USERDATA
+ SetWindowLongPtr(pMsg->hwnd, GWLP_USERDATA, oldData);
+#else
+ SetWindowLong(pMsg->hwnd, GWL_USERDATA, oldData);
+#endif
return hres;
}
diff --git a/src/activeqt/shared/qaxtypes.cpp b/src/activeqt/shared/qaxtypes.cpp
index 49aa99c..63891c4 100644
--- a/src/activeqt/shared/qaxtypes.cpp
+++ b/src/activeqt/shared/qaxtypes.cpp
@@ -552,7 +552,7 @@ bool QVariantToVARIANT(const QVariant &var, VARIANT &arg, const QByteArray &type
int maxColumns = col.count();
if (maxColumns) {
is2D = true;
- SAFEARRAYBOUND rgsabound[2] = {0};
+ SAFEARRAYBOUND rgsabound[2] = { {0} };
rgsabound[0].cElements = count;
rgsabound[1].cElements = maxColumns;
array = SafeArrayCreate(VT_VARIANT, 2, rgsabound);
diff --git a/src/activeqt/shared/qaxtypes.h b/src/activeqt/shared/qaxtypes.h
index 4f647a3..e3c7138 100644
--- a/src/activeqt/shared/qaxtypes.h
+++ b/src/activeqt/shared/qaxtypes.h
@@ -89,6 +89,9 @@ extern QVariant VARIANTToQVariant(const VARIANT &arg, const QByteArray &typeName
extern bool QVariantToVoidStar(const QVariant &var, void *data, const QByteArray &typeName, uint type = 0);
extern void clearVARIANT(VARIANT *var);
+#define QAX_INPROC_SERVER (0x51540001)
+#define QAX_OUTPROC_SERVER (0x51540002)
+
QT_END_NAMESPACE
#endif // QT_NO_WIN_ACTIVEQT
diff --git a/src/corelib/animation/qabstractanimation.cpp b/src/corelib/animation/qabstractanimation.cpp
index ced86d2..1d274c9 100644
--- a/src/corelib/animation/qabstractanimation.cpp
+++ b/src/corelib/animation/qabstractanimation.cpp
@@ -177,17 +177,6 @@ QUnifiedTimer *QUnifiedTimer::instance()
return inst;
}
-void QUnifiedTimer::updateRecentlyStartedAnimations()
-{
- if (animationsToStart.isEmpty())
- return;
-
- animations += animationsToStart;
- updateTimer(); //we make sure we start the timer there
-
- animationsToStart.clear();
-}
-
void QUnifiedTimer::timerEvent(QTimerEvent *event)
{
//this is simply the time we last received a tick
@@ -195,15 +184,16 @@ void QUnifiedTimer::timerEvent(QTimerEvent *event)
if (time.isValid())
lastTick = consistentTiming ? oldLastTick + timingInterval : time.elapsed();
- //we transfer the waiting animations into the "really running" state
- updateRecentlyStartedAnimations();
if (event->timerId() == startStopAnimationTimer.timerId()) {
startStopAnimationTimer.stop();
+ //we transfer the waiting animations into the "really running" state
+ animations += animationsToStart;
+ animationsToStart.clear();
if (animations.isEmpty()) {
animationTimer.stop();
time = QTime();
- } else {
+ } else if (!animationTimer.isActive()) {
animationTimer.start(timingInterval, this);
lastTick = 0;
time.start();
@@ -219,27 +209,19 @@ void QUnifiedTimer::timerEvent(QTimerEvent *event)
}
}
-void QUnifiedTimer::updateTimer()
-{
- //we delay the call to start and stop for the animation timer so that if you
- //stop and start animations in batch you don't stop/start the timer too often.
- if (!startStopAnimationTimer.isActive())
- startStopAnimationTimer.start(0, this); // we delay the actual start of the animation
-}
-
void QUnifiedTimer::registerAnimation(QAbstractAnimation *animation)
{
if (animations.contains(animation) ||animationsToStart.contains(animation))
return;
animationsToStart << animation;
- updateTimer();
+ startStopAnimationTimer.start(0, this); // we delay the check if we should start/stop the global timer
}
void QUnifiedTimer::unregisterAnimation(QAbstractAnimation *animation)
{
animations.removeAll(animation);
animationsToStart.removeAll(animation);
- updateTimer();
+ startStopAnimationTimer.start(0, this); // we delay the check if we should start/stop the global timer
}
diff --git a/src/corelib/animation/qabstractanimation_p.h b/src/corelib/animation/qabstractanimation_p.h
index 0d8402e..b281aa2 100644
--- a/src/corelib/animation/qabstractanimation_p.h
+++ b/src/corelib/animation/qabstractanimation_p.h
@@ -135,11 +135,8 @@ public:
protected:
void timerEvent(QTimerEvent *);
- void updateTimer();
private:
- void updateRecentlyStartedAnimations();
-
QBasicTimer animationTimer, startStopAnimationTimer;
QTime time;
int lastTick;
diff --git a/src/corelib/animation/qparallelanimationgroup.cpp b/src/corelib/animation/qparallelanimationgroup.cpp
index 5e4b0d2..8aa04a4 100644
--- a/src/corelib/animation/qparallelanimationgroup.cpp
+++ b/src/corelib/animation/qparallelanimationgroup.cpp
@@ -214,7 +214,8 @@ void QParallelAnimationGroup::updateState(QAbstractAnimation::State oldState,
d->connectUncontrolledAnimations();
for (int i = 0; i < d->animations.size(); ++i) {
QAbstractAnimation *animation = d->animations.at(i);
- animation->stop();
+ if (oldState == Stopped)
+ animation->stop();
animation->setDirection(d->direction);
animation->start();
}
diff --git a/src/corelib/animation/qvariantanimation.cpp b/src/corelib/animation/qvariantanimation.cpp
index 48e5ec1..fdd98c2 100644
--- a/src/corelib/animation/qvariantanimation.cpp
+++ b/src/corelib/animation/qvariantanimation.cpp
@@ -267,7 +267,7 @@ void QVariantAnimationPrivate::setCurrentValueForProgress(const qreal progress)
localProgress);
qSwap(currentValue, ret);
q->updateCurrentValue(currentValue);
- if ((connectedSignals & changedSignalMask) && currentValue != ret) {
+ if ((connectedSignals[0] & changedSignalMask) && currentValue != ret) {
//the value has changed
emit q->valueChanged(currentValue);
}
diff --git a/src/corelib/arch/qatomic_vxworks.h b/src/corelib/arch/qatomic_vxworks.h
index 573a44d..b441210 100644
--- a/src/corelib/arch/qatomic_vxworks.h
+++ b/src/corelib/arch/qatomic_vxworks.h
@@ -34,7 +34,7 @@
** met: http://www.gnu.org/copyleft/gpl.html.
**
** If you are unsure which license is appropriate for your use, please
-** contact the sales department at qt-sales@nokia.com.
+** contact the sales department at http://www.qtsoftware.com/contact.
** $QT_END_LICENSE$
**
****************************************************************************/
diff --git a/src/corelib/global/qglobal.cpp b/src/corelib/global/qglobal.cpp
index 776a740..63941ef 100644
--- a/src/corelib/global/qglobal.cpp
+++ b/src/corelib/global/qglobal.cpp
@@ -1083,7 +1083,7 @@ bool qSharedBuild()
\value WV_XP Windows XP (operating system version 5.1)
\value WV_2003 Windows Server 2003, Windows Server 2003 R2, Windows Home Server, Windows XP Professional x64 Edition (operating system version 5.2)
\value WV_VISTA Windows Vista, Windows Server 2008 (operating system version 6.0)
- \value WV_WINDOWS7 Windows 7 (operating system version 6.1)
+ \value WV_WINDOWS7 Windows 7, Windows Server 2008 R2 (operating system version 6.1)
Alternatively, you may use the following macros which correspond directly to the Windows operating system version number:
@@ -1092,7 +1092,7 @@ bool qSharedBuild()
\value WV_5_1 Operating system version 5.1, corresponds to Windows XP
\value WV_5_2 Operating system version 5.2, corresponds to Windows Server 2003, Windows Server 2003 R2, Windows Home Server, and Windows XP Professional x64 Edition
\value WV_6_0 Operating system version 6.0, corresponds to Windows Vista and Windows Server 2008
- \value WV_6_1 Operating system version 6.1, corresponds to Windows 7
+ \value WV_6_1 Operating system version 6.1, corresponds to Windows 7 and Windows Server 2008 R2
CE-based versions:
diff --git a/src/corelib/global/qglobal.h b/src/corelib/global/qglobal.h
index 8263bae..1711f16 100644
--- a/src/corelib/global/qglobal.h
+++ b/src/corelib/global/qglobal.h
@@ -279,7 +279,7 @@ namespace QT_NAMESPACE {}
# endif
#endif
-#if defined(Q_OS_MAC64) && !defined(QT_MAC_USE_COCOA)
+#if defined(Q_OS_MAC64) && !defined(QT_MAC_USE_COCOA) && !defined(QT_BUILD_QMAKE)
#error "You are building a 64-bit application, but using a 32-bit version of Qt. Check your build configuration."
#endif
@@ -311,11 +311,8 @@ namespace QT_NAMESPACE {}
# if !defined(MAC_OS_X_VERSION_10_6)
# define MAC_OS_X_VERSION_10_6 MAC_OS_X_VERSION_10_5 + 1
# endif
-# if (MAC_OS_X_VERSION_MAX_ALLOWED == MAC_OS_X_VERSION_10_6)
-# warning "Support for this version of Mac OS X is still preliminary"
-# endif
# if (MAC_OS_X_VERSION_MAX_ALLOWED > MAC_OS_X_VERSION_10_6)
-# error "This version of Mac OS X is unsupported"
+# warning "This version of Mac OS X is unsupported"
# endif
#endif
@@ -1176,6 +1173,11 @@ class QDataStream;
# else
# define Q_OPENGL_EXPORT Q_DECL_IMPORT
# endif
+# if defined(QT_BUILD_MULTIMEDIA_LIB)
+# define Q_MULTIMEDIA_EXPORT Q_DECL_EXPORT
+# else
+# define Q_MULTIMEDIA_EXPORT Q_DECL_IMPORT
+# endif
# if defined(QT_BUILD_OPENVG_LIB)
# define Q_OPENVG_EXPORT Q_DECL_EXPORT
# else
@@ -1220,6 +1222,7 @@ class QDataStream;
# define Q_SVG_EXPORT Q_DECL_IMPORT
# define Q_CANVAS_EXPORT Q_DECL_IMPORT
# define Q_OPENGL_EXPORT Q_DECL_IMPORT
+# define Q_MULTIMEDIA_EXPORT Q_DECL_IMPORT
# define Q_OPENVG_EXPORT Q_DECL_IMPORT
# define Q_XML_EXPORT Q_DECL_IMPORT
# define Q_XMLPATTERNS_EXPORT Q_DECL_IMPORT
@@ -1246,6 +1249,7 @@ class QDataStream;
# define Q_NETWORK_EXPORT Q_DECL_EXPORT
# define Q_SVG_EXPORT Q_DECL_EXPORT
# define Q_OPENGL_EXPORT Q_DECL_EXPORT
+# define Q_MULTIMEDIA_EXPORT Q_DECL_EXPORT
# define Q_OPENVG_EXPORT Q_DECL_EXPORT
# define Q_XML_EXPORT Q_DECL_EXPORT
# define Q_XMLPATTERNS_EXPORT Q_DECL_EXPORT
@@ -1259,6 +1263,7 @@ class QDataStream;
# define Q_NETWORK_EXPORT
# define Q_SVG_EXPORT
# define Q_OPENGL_EXPORT
+# define Q_MULTIMEDIA_EXPORT
# define Q_XML_EXPORT
# define Q_XMLPATTERNS_EXPORT
# define Q_SCRIPT_EXPORT
@@ -2308,12 +2313,14 @@ QT3_SUPPORT Q_CORE_EXPORT const char *qInstallPathSysconf();
#define QT_MODULE_DBUS 0x08000
#define QT_MODULE_SCRIPTTOOLS 0x10000
#define QT_MODULE_OPENVG 0x20000
+#define QT_MODULE_MULTIMEDIA 0x40000
/* Qt editions */
#define QT_EDITION_CONSOLE (QT_MODULE_CORE \
| QT_MODULE_NETWORK \
| QT_MODULE_SQL \
| QT_MODULE_SCRIPT \
+ | QT_MODULE_MULTIMEDIA \
| QT_MODULE_XML \
| QT_MODULE_XMLPATTERNS \
| QT_MODULE_TEST \
@@ -2329,6 +2336,7 @@ QT3_SUPPORT Q_CORE_EXPORT const char *qInstallPathSysconf();
| QT_MODULE_OPENGL \
| QT_MODULE_OPENVG \
| QT_MODULE_SQL \
+ | QT_MODULE_MULTIMEDIA \
| QT_MODULE_XML \
| QT_MODULE_XMLPATTERNS \
| QT_MODULE_SCRIPT \
@@ -2377,6 +2385,9 @@ QT_LICENSED_MODULE(OpenVG)
#if (QT_EDITION & QT_MODULE_SQL)
QT_LICENSED_MODULE(Sql)
#endif
+#if (QT_EDITION & QT_MODULE_MULTIMEDIA)
+QT_LICENSED_MODULE(Multimedia)
+#endif
#if (QT_EDITION & QT_MODULE_XML)
QT_LICENSED_MODULE(Xml)
#endif
diff --git a/src/corelib/global/qnamespace.h b/src/corelib/global/qnamespace.h
index 7770fd6..f172d77 100644
--- a/src/corelib/global/qnamespace.h
+++ b/src/corelib/global/qnamespace.h
@@ -1406,6 +1406,21 @@ public:
ImCurrentSelection
};
+ enum InputMethodHint {
+ ImhNone = 0x0,
+ ImhHiddenText = 0x1,
+ ImhNumbersOnly = 0x2,
+ ImhUppercaseOnly = 0x4,
+ ImhLowercaseOnly = 0x8,
+ ImhNoAutoUppercase = 0x10,
+ ImhPreferNumbers = 0x20,
+ ImhPreferUppercase = 0x40,
+ ImhPreferLowercase = 0x80,
+ ImhNoPredictiveText = 0x100,
+ ImhDialableCharactersOnly = 0x200
+ };
+ Q_DECLARE_FLAGS(InputMethodHints, InputMethodHint)
+
enum ToolButtonStyle {
ToolButtonIconOnly,
ToolButtonTextOnly,
@@ -1591,6 +1606,7 @@ Q_DECLARE_OPERATORS_FOR_FLAGS(Qt::ItemFlags)
Q_DECLARE_OPERATORS_FOR_FLAGS(Qt::MatchFlags)
Q_DECLARE_OPERATORS_FOR_FLAGS(Qt::TextInteractionFlags)
Q_DECLARE_OPERATORS_FOR_FLAGS(Qt::TouchPointStates)
+Q_DECLARE_OPERATORS_FOR_FLAGS(Qt::InputMethodHints)
typedef bool (*qInternalCallback)(void **);
diff --git a/src/corelib/io/qfilesystemwatcher_fsevents.cpp b/src/corelib/io/qfilesystemwatcher_fsevents.cpp
index 3e0aee8..cb276b7 100644
--- a/src/corelib/io/qfilesystemwatcher_fsevents.cpp
+++ b/src/corelib/io/qfilesystemwatcher_fsevents.cpp
@@ -422,9 +422,12 @@ void QFSEventsFileSystemWatcherEngine::fseventsCallback(ConstFSEventStreamRef ,
void QFSEventsFileSystemWatcherEngine::stop()
{
#if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_5
+ QMutexLocker locker(&mutex);
stopFSStream(fsStream);
- if (threadsRunLoop)
+ if (threadsRunLoop) {
CFRunLoopStop(threadsRunLoop);
+ waitForStop.wait(&mutex);
+ }
#endif
}
@@ -461,6 +464,8 @@ void QFSEventsFileSystemWatcherEngine::run()
// immediately.
CFRunLoopRun();
threadsRunLoop = 0;
+ QMutexLocker locker(&mutex);
+ waitForStop.wakeAll();
#endif
}
diff --git a/src/corelib/io/qfilesystemwatcher_fsevents_p.h b/src/corelib/io/qfilesystemwatcher_fsevents_p.h
index 4770867..ffc0c68 100644
--- a/src/corelib/io/qfilesystemwatcher_fsevents_p.h
+++ b/src/corelib/io/qfilesystemwatcher_fsevents_p.h
@@ -114,6 +114,7 @@ private:
CFRunLoopRef threadsRunLoop;
QMutex mutex;
QWaitCondition waitCondition;
+ QWaitCondition waitForStop;
#if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_5
PathHash filePathInfoHash;
PathHash dirPathInfoHash;
diff --git a/src/corelib/kernel/kernel.pri b/src/corelib/kernel/kernel.pri
index 7177293..3493784 100644
--- a/src/corelib/kernel/kernel.pri
+++ b/src/corelib/kernel/kernel.pri
@@ -32,7 +32,8 @@ HEADERS += \
kernel/qsharedmemory_p.h \
kernel/qsystemsemaphore.h \
kernel/qsystemsemaphore_p.h \
- kernel/qfunctions_p.h
+ kernel/qfunctions_p.h \
+ kernel/qguard_p.h
SOURCES += \
kernel/qabstracteventdispatcher.cpp \
@@ -54,7 +55,7 @@ SOURCES += \
kernel/qcoreglobaldata.cpp \
kernel/qsharedmemory.cpp \
kernel/qsystemsemaphore.cpp \
- kernel/qpointer.cpp
+ kernel/qpointer.cpp
win32 {
SOURCES += \
diff --git a/src/corelib/kernel/qabstractitemmodel.cpp b/src/corelib/kernel/qabstractitemmodel.cpp
index 3d9263e..5d5d4cc 100644
--- a/src/corelib/kernel/qabstractitemmodel.cpp
+++ b/src/corelib/kernel/qabstractitemmodel.cpp
@@ -467,6 +467,27 @@ QAbstractItemModel *QAbstractItemModelPrivate::staticEmptyModel()
return qEmptyModel();
}
+namespace {
+ struct DefaultRoleNames : public QHash<int, QByteArray>
+ {
+ DefaultRoleNames() {
+ (*this)[Qt::DisplayRole] = "display";
+ (*this)[Qt::DecorationRole] = "decoration";
+ (*this)[Qt::EditRole] = "edit";
+ (*this)[Qt::ToolTipRole] = "toolTip";
+ (*this)[Qt::StatusTipRole] = "statusTip";
+ (*this)[Qt::WhatsThisRole] = "whatsThis";
+ }
+ };
+}
+
+Q_GLOBAL_STATIC(DefaultRoleNames, qDefaultRoleNames)
+
+const QHash<int,QByteArray> &QAbstractItemModelPrivate::defaultRoleNames()
+{
+ return *qDefaultRoleNames();
+}
+
/*!
\internal
return true if \a value contains a numerical type
@@ -1863,6 +1884,37 @@ QSize QAbstractItemModel::span(const QModelIndex &) const
}
/*!
+ \since 4.6
+
+ Sets the model's role names to \a roleNames.
+
+ This function is provided to allow mapping of role identifiers to
+ role property names in Declarative UI. This function must be called
+ before the model is used. Modifying the role names after the model
+ has been set may result in undefined behaviour.
+
+ \sa roleNames()
+*/
+void QAbstractItemModel::setRoleNames(const QHash<int,QByteArray> &roleNames)
+{
+ Q_D(QAbstractItemModel);
+ d->roleNames = roleNames;
+}
+
+/*!
+ \since 4.6
+
+ Returns the model's role names.
+
+ \sa setRoleNames()
+*/
+const QHash<int,QByteArray> &QAbstractItemModel::roleNames() const
+{
+ Q_D(const QAbstractItemModel);
+ return d->roleNames;
+}
+
+/*!
Called to let the model know that it should submit whatever it has cached
to the permanent storage. Typically used for row editing.
diff --git a/src/corelib/kernel/qabstractitemmodel.h b/src/corelib/kernel/qabstractitemmodel.h
index dc7d7bd..a6bbff4 100644
--- a/src/corelib/kernel/qabstractitemmodel.h
+++ b/src/corelib/kernel/qabstractitemmodel.h
@@ -220,6 +220,8 @@ public:
Qt::MatchFlags(Qt::MatchStartsWith|Qt::MatchWrap)) const;
virtual QSize span(const QModelIndex &index) const;
+ const QHash<int,QByteArray> &roleNames() const;
+
#ifdef Q_NO_USING_KEYWORD
inline QObject *parent() const { return QObject::parent(); }
#else
@@ -282,6 +284,8 @@ protected:
void changePersistentIndexList(const QModelIndexList &from, const QModelIndexList &to);
QModelIndexList persistentIndexList() const;
+ void setRoleNames(const QHash<int,QByteArray> &roleNames);
+
private:
Q_DECLARE_PRIVATE(QAbstractItemModel)
Q_DISABLE_COPY(QAbstractItemModel)
diff --git a/src/corelib/kernel/qabstractitemmodel_p.h b/src/corelib/kernel/qabstractitemmodel_p.h
index c047f95..6a29723 100644
--- a/src/corelib/kernel/qabstractitemmodel_p.h
+++ b/src/corelib/kernel/qabstractitemmodel_p.h
@@ -78,7 +78,7 @@ class Q_CORE_EXPORT QAbstractItemModelPrivate : public QObjectPrivate
Q_DECLARE_PUBLIC(QAbstractItemModel)
public:
- QAbstractItemModelPrivate() : QObjectPrivate(), supportedDragActions(-1) {}
+ QAbstractItemModelPrivate() : QObjectPrivate(), supportedDragActions(-1), roleNames(defaultRoleNames()) {}
void removePersistentIndexData(QPersistentModelIndexData *data);
void rowsAboutToBeInserted(const QModelIndex &parent, int first, int last);
void rowsInserted(const QModelIndex &parent, int first, int last);
@@ -144,6 +144,9 @@ public:
} persistent;
Qt::DropActions supportedDragActions;
+
+ QHash<int,QByteArray> roleNames;
+ static const QHash<int,QByteArray> &defaultRoleNames();
};
QT_END_NAMESPACE
diff --git a/src/corelib/kernel/qcore_unix.cpp b/src/corelib/kernel/qcore_unix.cpp
index b57d385..efa9c6d 100644
--- a/src/corelib/kernel/qcore_unix.cpp
+++ b/src/corelib/kernel/qcore_unix.cpp
@@ -161,76 +161,3 @@ int qt_safe_select(int nfds, fd_set *fdread, fd_set *fdwrite, fd_set *fdexcept,
}
QT_END_NAMESPACE
-
-#ifdef Q_OS_LINUX
-// Don't wait for libc to supply the calls we need
-// Make syscalls directly
-
-# if defined(__GLIBC__) && (__GLIBC__ * 0x100 + __GLIBC_MINOR__) >= 0x0204
-// glibc 2.4 has syscall(...)
-# include <sys/syscall.h>
-# include <asm/unistd.h>
-# else
-// no syscall(...)
-static inline int syscall(...) { errno = ENOSYS; return -1;}
-# endif
-
-# ifndef __NR_dup3
-# if defined(__i386__)
-# define __NR_dup3 330
-# define __NR_pipe2 331
-# elif defined(__x86_64__)
-# define __NR_dup3 292
-# define __NR_pipe2 293
-# elif defined(__ia64__)
-# define __NR_dup3 1316
-# define __NR_pipe2 1317
-# else
-// set the syscalls to absurd numbers so that they'll cause ENOSYS errors
-# warning "Please port the pipe2/dup3 code to this platform"
-# define __NR_dup3 -1
-# define __NR_pipe2 -1
-# endif
-# endif
-
-# if !defined(__NR_socketcall) && !defined(__NR_accept4)
-# if defined(__x86_64__)
-# define __NR_accept4 288
-# elif defined(__ia64__)
-// not assigned yet to IA-64
-# define __NR_accept4 -1
-# else
-// set the syscalls to absurd numbers so that they'll cause ENOSYS errors
-# warning "Please port the accept4 code to this platform"
-# define __NR_accept4 -1
-# endif
-# endif
-
-QT_BEGIN_NAMESPACE
-namespace QtLibcSupplement {
- int pipe2(int pipes[], int flags)
- {
- return syscall(__NR_pipe2, pipes, flags);
- }
-
- int dup3(int oldfd, int newfd, int flags)
- {
- return syscall(__NR_dup3, oldfd, newfd, flags);
- }
-
- int accept4(int s, sockaddr *addr, QT_SOCKLEN_T *addrlen, int flags)
- {
-# if defined(__NR_socketcall)
- // This platform uses socketcall() instead of raw syscalls
- // the SYS_ACCEPT4 number is cross-platform: 18
- return syscall(__NR_socketcall, 18, &s);
-# else
- return syscall(__NR_accept4, s, addr, addrlen, flags);
-# endif
-
- Q_UNUSED(addr); Q_UNUSED(addrlen); Q_UNUSED(flags); // they're actually used
- }
-}
-QT_END_NAMESPACE
-#endif // Q_OS_LINUX
-
diff --git a/src/corelib/kernel/qcore_unix_p.h b/src/corelib/kernel/qcore_unix_p.h
index dceb73a..3bdd5ec 100644
--- a/src/corelib/kernel/qcore_unix_p.h
+++ b/src/corelib/kernel/qcore_unix_p.h
@@ -73,32 +73,16 @@
struct sockaddr;
-#if defined(Q_OS_LINUX) && defined(__GLIBC__) && (__GLIBC__ * 0x100 + __GLIBC_MINOR__) >= 0x0204
-// Linux supports thread-safe FD_CLOEXEC
+#if defined(Q_OS_LINUX) && defined(O_CLOEXEC)
# define QT_UNIX_SUPPORTS_THREADSAFE_CLOEXEC 1
-
-// add defines for the consts for Linux
-# ifndef O_CLOEXEC
-# define O_CLOEXEC 02000000
-# endif
-# ifndef FD_DUPFD_CLOEXEC
-# define F_DUPFD_CLOEXEC 1030
-# endif
-# ifndef SOCK_CLOEXEC
-# define SOCK_CLOEXEC O_CLOEXEC
-# endif
-# ifndef SOCK_NONBLOCK
-# define SOCK_NONBLOCK O_NONBLOCK
-# endif
-# ifndef MSG_CMSG_CLOEXEC
-# define MSG_CMSG_CLOEXEC 0x40000000
-# endif
-
QT_BEGIN_NAMESPACE
namespace QtLibcSupplement {
- Q_CORE_EXPORT int accept4(int, sockaddr *, QT_SOCKLEN_T *, int flags);
- Q_CORE_EXPORT int dup3(int oldfd, int newfd, int flags);
- Q_CORE_EXPORT int pipe2(int pipes[], int flags);
+ inline int accept4(int, sockaddr *, QT_SOCKLEN_T *, int)
+ { errno = ENOSYS; return -1; }
+ inline int dup3(int, int, int)
+ { errno = ENOSYS; return -1; }
+ inline int pipe2(int [], int )
+ { errno = ENOSYS; return -1; }
}
QT_END_NAMESPACE
using namespace QT_PREPEND_NAMESPACE(QtLibcSupplement);
@@ -190,7 +174,7 @@ static inline int qt_safe_pipe(int pipefd[2], int flags = 0)
#endif
register int ret;
-#if QT_UNIX_SUPPORTS_THREADSAFE_CLOEXEC
+#if QT_UNIX_SUPPORTS_THREADSAFE_CLOEXEC && defined(O_CLOEXEC)
// use pipe2
flags |= O_CLOEXEC;
ret = ::pipe2(pipefd, flags); // pipe2 is Linux-specific and is documented not to return EINTR
@@ -246,7 +230,7 @@ static inline int qt_safe_dup2(int oldfd, int newfd, int flags = FD_CLOEXEC)
Q_ASSERT(flags == FD_CLOEXEC || flags == 0);
register int ret;
-#if QT_UNIX_SUPPORTS_THREADSAFE_CLOEXEC
+#if QT_UNIX_SUPPORTS_THREADSAFE_CLOEXEC && defined(O_CLOEXEC)
// use dup3
if (flags & FD_CLOEXEC) {
EINTR_LOOP(ret, ::dup3(oldfd, newfd, O_CLOEXEC));
@@ -323,6 +307,10 @@ static inline pid_t qt_safe_waitpid(pid_t pid, int *status, int options)
#endif // Q_OS_VXWORKS
+#if !defined(_POSIX_MONOTONIC_CLOCK)
+# define _POSIX_MONOTONIC_CLOCK -1
+#endif
+
bool qt_gettime_is_monotonic();
timeval qt_gettime();
Q_CORE_EXPORT int qt_safe_select(int nfds, fd_set *fdread, fd_set *fdwrite, fd_set *fdexcept,
diff --git a/src/corelib/kernel/qcoreevent.cpp b/src/corelib/kernel/qcoreevent.cpp
index a682fad9..ff00c1c 100644
--- a/src/corelib/kernel/qcoreevent.cpp
+++ b/src/corelib/kernel/qcoreevent.cpp
@@ -269,7 +269,7 @@ QT_BEGIN_NAMESPACE
\omitvalue FutureCallOut
\omitvalue CocoaRequestModal
\omitvalue Signal
- \omitvalue WinGesture
+ \omitvalue NativeGesture
*/
/*!
diff --git a/src/corelib/kernel/qcoreevent.h b/src/corelib/kernel/qcoreevent.h
index 1d86f47..d941286 100644
--- a/src/corelib/kernel/qcoreevent.h
+++ b/src/corelib/kernel/qcoreevent.h
@@ -276,7 +276,7 @@ public:
TouchUpdate = 195,
TouchEnd = 196,
- WinGesture = 197,
+ NativeGesture = 197, // Internal for platform gesture support
// 512 reserved for Qt Jambi's MetaCall event
// 513 reserved for Qt Jambi's DeleteOnMainThread event
diff --git a/src/corelib/kernel/qeventdispatcher_glib.cpp b/src/corelib/kernel/qeventdispatcher_glib.cpp
index 7610631..2bbe560 100644
--- a/src/corelib/kernel/qeventdispatcher_glib.cpp
+++ b/src/corelib/kernel/qeventdispatcher_glib.cpp
@@ -263,6 +263,7 @@ QEventDispatcherGlibPrivate::QEventDispatcherGlibPrivate(GMainContext *context)
(void) new (&timerSource->timerList) QTimerInfoList();
timerSource->processEventsFlags = QEventLoop::AllEvents;
g_source_set_can_recurse(&timerSource->source, true);
+ g_source_set_priority(&timerSource->source, G_PRIORITY_DEFAULT_IDLE);
g_source_attach(&timerSource->source, mainContext);
}
diff --git a/src/corelib/kernel/qeventdispatcher_unix_p.h b/src/corelib/kernel/qeventdispatcher_unix_p.h
index 9c67c70..5e016d3 100644
--- a/src/corelib/kernel/qeventdispatcher_unix_p.h
+++ b/src/corelib/kernel/qeventdispatcher_unix_p.h
@@ -69,9 +69,6 @@
#endif
QT_BEGIN_NAMESPACE
-#if !defined(_POSIX_MONOTONIC_CLOCK)
-# define _POSIX_MONOTONIC_CLOCK -1
-#endif
// internal timer info
struct QTimerInfo {
diff --git a/src/corelib/kernel/qfunctions_vxworks.cpp b/src/corelib/kernel/qfunctions_vxworks.cpp
index 6d5e7cc..def8f4c 100644
--- a/src/corelib/kernel/qfunctions_vxworks.cpp
+++ b/src/corelib/kernel/qfunctions_vxworks.cpp
@@ -1,7 +1,7 @@
/****************************************************************************
**
** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
-** Contact: Qt Software Information (qt-info@nokia.com)
+** Contact: Nokia Corporation (qt-info@nokia.com)
**
** This file is part of the QtCore module of the Qt Toolkit.
**
@@ -34,7 +34,7 @@
** met: http://www.gnu.org/copyleft/gpl.html.
**
** If you are unsure which license is appropriate for your use, please
-** contact the sales department at qt-sales@nokia.com.
+** contact the sales department at http://www.qtsoftware.com/contact.
** $QT_END_LICENSE$
**
****************************************************************************/
diff --git a/src/corelib/kernel/qfunctions_vxworks.h b/src/corelib/kernel/qfunctions_vxworks.h
index cc98948..e31d495 100644
--- a/src/corelib/kernel/qfunctions_vxworks.h
+++ b/src/corelib/kernel/qfunctions_vxworks.h
@@ -34,7 +34,7 @@
** met: http://www.gnu.org/copyleft/gpl.html.
**
** If you are unsure which license is appropriate for your use, please
-** contact the sales department at qt-sales@nokia.com.
+** contact the sales department at http://www.qtsoftware.com/contact.
** $QT_END_LICENSE$
**
****************************************************************************/
diff --git a/src/corelib/kernel/qguard_p.h b/src/corelib/kernel/qguard_p.h
new file mode 100644
index 0000000..6af01ac
--- /dev/null
+++ b/src/corelib/kernel/qguard_p.h
@@ -0,0 +1,157 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtCore module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the either Technology Preview License Agreement or the
+** Beta Release License Agreement.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain
+** additional rights. These rights are described in the Nokia Qt LGPL
+** Exception version 1.0, 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.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at http://www.qtsoftware.com/contact.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QGUARD_P_H
+#define QGUARD_P_H
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists for the convenience
+// of qapplication_*.cpp, qwidget*.cpp and qfiledialog.cpp. This header
+// file may change from version to version without notice, or even be removed.
+//
+// We mean it.
+//
+
+#include "QtCore/qglobal.h"
+
+QT_BEGIN_NAMESPACE
+
+class QObject;
+template<class T>
+class QGuard
+{
+ QObject *o;
+ QGuard<QObject> *next;
+ QGuard<QObject> **prev;
+ friend void q_guard_addGuard(QGuard<QObject> *);
+ friend void q_guard_removeGuard(QGuard<QObject> *);
+ friend class QObjectPrivate;
+public:
+ inline QGuard();
+ inline QGuard(T *);
+ inline QGuard(const QGuard<T> &);
+ inline virtual ~QGuard();
+
+ inline QGuard<T> &operator=(const QGuard<T> &o);
+ inline QGuard<T> &operator=(T *);
+
+ inline bool isNull() const
+ { return !o; }
+
+ inline T* operator->() const
+ { return static_cast<T*>(const_cast<QObject*>(o)); }
+ inline T& operator*() const
+ { return *static_cast<T*>(const_cast<QObject*>(o)); }
+ inline operator T*() const
+ { return static_cast<T*>(const_cast<QObject*>(o)); }
+ inline T* data() const
+ { return static_cast<T*>(const_cast<QObject*>(o)); }
+
+protected:
+ virtual void objectDestroyed(T *) {}
+};
+
+QT_END_NAMESPACE
+
+#include "private/qobject_p.h"
+
+QT_BEGIN_NAMESPACE
+
+inline void q_guard_addGuard(QGuard<QObject> *);
+inline void q_guard_removeGuard(QGuard<QObject> *);
+
+template<class T>
+QGuard<T>::QGuard()
+: o(0), next(0), prev(0)
+{
+}
+
+template<class T>
+QGuard<T>::QGuard(T *g)
+: o(g), next(0), prev(0)
+{
+ if (o) q_guard_addGuard(reinterpret_cast<QGuard<QObject> *>(this));
+}
+
+template<class T>
+QGuard<T>::QGuard(const QGuard<T> &g)
+: o(g.o), next(0), prev(0)
+{
+ if (o) q_guard_addGuard(reinterpret_cast<QGuard<QObject> *>(this));
+}
+
+template<class T>
+QGuard<T>::~QGuard()
+{
+ if (prev) q_guard_removeGuard(reinterpret_cast<QGuard<QObject> *>(this));
+ o = 0;
+}
+
+template<class T>
+QGuard<T> &QGuard<T>::operator=(const QGuard<T> &g)
+{
+ if (g.o != o) {
+ if (prev)
+ q_guard_removeGuard(reinterpret_cast<QGuard<QObject> *>(this));
+ o = g.o;
+ if (o) q_guard_addGuard(reinterpret_cast<QGuard<QObject> *>(this));
+ }
+ return *this;
+}
+
+template<class T>
+inline QGuard<T> &QGuard<T>::operator=(T *g)
+{
+ if (g != o) {
+ if (prev)
+ q_guard_removeGuard(reinterpret_cast<QGuard<QObject> *>(this));
+ o = g;
+ if (o) q_guard_addGuard(reinterpret_cast<QGuard<QObject> *>(this));
+ }
+ return *this;
+}
+
+QT_END_NAMESPACE
+
+#endif // QGUARD_P_H
diff --git a/src/corelib/kernel/qmetaobject.cpp b/src/corelib/kernel/qmetaobject.cpp
index 08cecaf..d43c5dd 100644
--- a/src/corelib/kernel/qmetaobject.cpp
+++ b/src/corelib/kernel/qmetaobject.cpp
@@ -148,7 +148,9 @@ enum PropertyFlags {
Resettable = 0x00000004,
EnumOrFlag = 0x00000008,
StdCppSet = 0x00000100,
-// Override = 0x00000200,
+// Override = 0x00000200,
+ Constant = 0x00000400,
+ Final = 0x00000800,
Designable = 0x00001000,
ResolveDesignable = 0x00002000,
Scriptable = 0x00004000,
@@ -179,6 +181,10 @@ enum MethodFlags {
MethodScriptable = 0x40
};
+enum MetaObjectFlags {
+ DynamicMetaObject = 0x01
+};
+
struct QMetaObjectPrivate
{
int revision;
@@ -188,6 +194,7 @@ struct QMetaObjectPrivate
int propertyCount, propertyData;
int enumeratorCount, enumeratorData;
int constructorCount, constructorData;
+ int flags;
};
static inline const QMetaObjectPrivate *priv(const uint* data)
@@ -277,6 +284,17 @@ int QMetaObject::static_metacall(Call cl, int idx, void **argv) const
}
/*!
+ \internal
+*/
+int QMetaObject::metacall(QObject *object, Call cl, int idx, void **argv)
+{
+ if (QMetaObject *mo = object->d_ptr->metaObject)
+ return static_cast<QAbstractDynamicMetaObject*>(mo)->metaCall(cl, idx, argv);
+ else
+ return object->qt_metacall(cl, idx, argv);
+}
+
+/*!
\fn const char *QMetaObject::className() const
Returns the class name.
@@ -696,6 +714,14 @@ int QMetaObject::indexOfProperty(const char *name) const
}
m = m->d.superdata;
}
+
+ if (i == -1 && priv(this->d.data)->revision >= 3 && (priv(this->d.data)->flags & DynamicMetaObject)){
+ QAbstractDynamicMetaObject *me =
+ const_cast<QAbstractDynamicMetaObject *>(static_cast<const QAbstractDynamicMetaObject *>(this));
+
+ i = me->createProperty(name, 0);
+ }
+
return i;
}
@@ -1326,6 +1352,18 @@ int QMetaMethod::attributes() const
}
/*!
+ \since 4.6
+
+ Returns this method's index.
+*/
+int QMetaMethod::methodIndex() const
+{
+ if (!mobj)
+ return -1;
+ return ((handle - priv(mobj->d.data)->methodData) / 5) + mobj->methodOffset();
+}
+
+/*!
Returns the access specification of this method (private,
protected, or public).
@@ -1525,7 +1563,7 @@ bool QMetaMethod::invoke(QObject *object,
// recompute the methodIndex by reversing the arithmetic in QMetaObject::property()
int methodIndex = ((handle - priv(mobj->d.data)->methodData) / 5) + mobj->methodOffset();
if (connectionType == Qt::DirectConnection) {
- return object->qt_metacall(QMetaObject::InvokeMetaMethod, methodIndex, param) < 0;
+ return QMetaObject::metacall(object, QMetaObject::InvokeMetaMethod, methodIndex, param) < 0;
} else {
if (returnValue.data()) {
qWarning("QMetaMethod::invoke: Unable to invoke methods with return values in "
@@ -2040,6 +2078,18 @@ int QMetaProperty::userType() const
}
/*!
+ \since 4.6
+
+ Returns this property's index.
+*/
+int QMetaProperty::propertyIndex() const
+{
+ if (!mobj)
+ return -1;
+ return idx + mobj->propertyOffset();
+}
+
+/*!
Returns true if the property's type is an enumeration value that
is used as a flag; otherwise returns false.
@@ -2151,9 +2201,8 @@ QVariant QMetaProperty::read(const QObject *object) const
value = QVariant(t, (void*)0);
argv[0] = value.data();
}
- const_cast<QObject*>(object)->qt_metacall(QMetaObject::ReadProperty,
- idx + mobj->propertyOffset(),
- argv);
+ QMetaObject::metacall(const_cast<QObject*>(object), QMetaObject::ReadProperty,
+ idx + mobj->propertyOffset(), argv);
if (status != -1)
return value;
@@ -2224,7 +2273,7 @@ bool QMetaProperty::write(QObject *object, const QVariant &value) const
argv[0] = &v;
else
argv[0] = v.data();
- object->qt_metacall(QMetaObject::WriteProperty, idx + mobj->propertyOffset(), argv);
+ QMetaObject::metacall(object, QMetaObject::WriteProperty, idx + mobj->propertyOffset(), argv);
return status;
}
@@ -2241,7 +2290,7 @@ bool QMetaProperty::reset(QObject *object) const
if (!object || !mobj || !isResettable())
return false;
void *argv[] = { 0 };
- object->qt_metacall(QMetaObject::ResetProperty, idx + mobj->propertyOffset(), argv);
+ QMetaObject::metacall(object, QMetaObject::ResetProperty, idx + mobj->propertyOffset(), argv);
return true;
}
@@ -2355,8 +2404,8 @@ bool QMetaProperty::isDesignable(const QObject *object) const
bool b = flags & Designable;
if (object) {
void *argv[] = { &b };
- const_cast<QObject*>(object)->qt_metacall(QMetaObject::QueryPropertyDesignable,
- idx + mobj->propertyOffset(), argv);
+ QMetaObject::metacall(const_cast<QObject*>(object), QMetaObject::QueryPropertyDesignable,
+ idx + mobj->propertyOffset(), argv);
}
return b;
@@ -2381,8 +2430,8 @@ bool QMetaProperty::isScriptable(const QObject *object) const
bool b = flags & Scriptable;
if (object) {
void *argv[] = { &b };
- const_cast<QObject*>(object)->qt_metacall(QMetaObject::QueryPropertyScriptable,
- idx + mobj->propertyOffset(), argv);
+ QMetaObject::metacall(const_cast<QObject*>(object), QMetaObject::QueryPropertyScriptable,
+ idx + mobj->propertyOffset(), argv);
}
return b;
}
@@ -2405,8 +2454,8 @@ bool QMetaProperty::isStored(const QObject *object) const
bool b = flags & Stored;
if (object) {
void *argv[] = { &b };
- const_cast<QObject*>(object)->qt_metacall(QMetaObject::QueryPropertyStored,
- idx + mobj->propertyOffset(), argv);
+ QMetaObject::metacall(const_cast<QObject*>(object), QMetaObject::QueryPropertyStored,
+ idx + mobj->propertyOffset(), argv);
}
return b;
}
@@ -2432,13 +2481,41 @@ bool QMetaProperty::isUser(const QObject *object) const
bool b = flags & User;
if (object) {
void *argv[] = { &b };
- const_cast<QObject*>(object)->qt_metacall(QMetaObject::QueryPropertyUser,
- idx + mobj->propertyOffset(), argv);
+ QMetaObject::metacall(const_cast<QObject*>(object), QMetaObject::QueryPropertyUser,
+ idx + mobj->propertyOffset(), argv);
}
return b;
}
/*!
+ Returns true if the property is constant; otherwise returns false.
+
+ A property is constant if the \c{Q_PROPERTY()}'s \c CONSTANT attribute
+ is set.
+*/
+bool QMetaProperty::isConstant() const
+{
+ if (!mobj)
+ return false;
+ int flags = mobj->d.data[handle + 2];
+ return flags & Constant;
+}
+
+/*!
+ Returns true if the property is final; otherwise returns false.
+
+ A property is final if the \c{Q_PROPERTY()}'s \c FINAL attribute
+ is set.
+*/
+bool QMetaProperty::isFinal() const
+{
+ if (!mobj)
+ return false;
+ int flags = mobj->d.data[handle + 2];
+ return flags & Final;
+}
+
+/*!
\obsolete
Returns true if the property is editable for the given \a object;
@@ -2458,8 +2535,8 @@ bool QMetaProperty::isEditable(const QObject *object) const
bool b = flags & Editable;
if (object) {
void *argv[] = { &b };
- const_cast<QObject*>(object)->qt_metacall(QMetaObject::QueryPropertyEditable,
- idx + mobj->propertyOffset(), argv);
+ QMetaObject::metacall(const_cast<QObject*>(object), QMetaObject::QueryPropertyEditable,
+ idx + mobj->propertyOffset(), argv);
}
return b;
}
diff --git a/src/corelib/kernel/qmetaobject.h b/src/corelib/kernel/qmetaobject.h
index 000ba6e..419fe06 100644
--- a/src/corelib/kernel/qmetaobject.h
+++ b/src/corelib/kernel/qmetaobject.h
@@ -69,6 +69,7 @@ public:
MethodType methodType() const;
enum Attributes { Compatibility = 0x1, Cloned = 0x2, Scriptable = 0x4 };
int attributes() const;
+ int methodIndex() const;
inline const QMetaObject *enclosingMetaObject() const { return mobj; }
@@ -178,6 +179,7 @@ public:
const char *typeName() const;
QVariant::Type type() const;
int userType() const;
+ int propertyIndex() const;
bool isReadable() const;
bool isWritable() const;
@@ -187,6 +189,8 @@ public:
bool isStored(const QObject *obj = 0) const;
bool isEditable(const QObject *obj = 0) const;
bool isUser(const QObject *obj = 0) const;
+ bool isConstant() const;
+ bool isFinal() const;
bool isFlagType() const;
bool isEnumType() const;
diff --git a/src/corelib/kernel/qobject.cpp b/src/corelib/kernel/qobject.cpp
index 6503ab0..e37b6d3 100644
--- a/src/corelib/kernel/qobject.cpp
+++ b/src/corelib/kernel/qobject.cpp
@@ -56,6 +56,7 @@
#include <qvarlengtharray.h>
#include <qset.h>
#include <qsemaphore.h>
+#include <qsharedpointer.h>
#include <private/qorderedmutexlocker_p.h>
#include <private/qmutexpool_p.h>
@@ -122,8 +123,11 @@ extern "C" Q_CORE_EXPORT void qt_removeObject(QObject *)
}
}
+QObjectData::~QObjectData() {}
+QDeclarativeData::~QDeclarativeData() {}
+
QObjectPrivate::QObjectPrivate(int version)
- : threadData(0), currentSender(0), currentChildBeingDeleted(0), connectionLists(0), senders(0)
+ : threadData(0), connectionLists(0), senders(0), currentSender(0), currentChildBeingDeleted(0), declarativeData(0), objectGuards(0)
{
if (version != QObjectPrivateVersion)
qFatal("Cannot mix incompatible Qt libraries");
@@ -139,15 +143,18 @@ QObjectPrivate::QObjectPrivate(int version)
receiveChildEvents = true;
postedEvents = 0;
extraData = 0;
- connectedSignals = 0;
+ for (uint i = 0; i < (sizeof connectedSignals / sizeof connectedSignals[0]); ++i)
+ connectedSignals[i] = 0;
inEventHandler = false;
inThreadChangeEvent = false;
deleteWatch = 0;
+ metaObject = 0;
hasGuards = false;
}
QObjectPrivate::~QObjectPrivate()
{
+ delete static_cast<QAbstractDynamicMetaObject*>(metaObject);
if (deleteWatch)
*deleteWatch = 1;
#ifndef QT_NO_USERDATA
@@ -425,7 +432,22 @@ void QMetaObject::changeGuard(QObject **ptr, QObject *o)
*/
void QObjectPrivate::clearGuards(QObject *object)
{
- if (!QObjectPrivate::get(object)->hasGuards)
+ QObjectPrivate *priv = QObjectPrivate::get(object);
+ QGuard<QObject> *guard = priv->objectGuards;
+ while (guard) {
+ guard->o = 0;
+ guard = guard->next;
+ }
+ while (priv->objectGuards) {
+ guard = priv->objectGuards;
+ guard->prev = 0;
+ if (guard->next) guard->next->prev = &priv->objectGuards;
+ priv->objectGuards = guard->next;
+ guard->next = 0;
+ guard->objectDestroyed(object);
+ }
+
+ if (!priv->hasGuards)
return;
GuardHash *hash = guardHash();
if (hash) {
@@ -467,7 +489,7 @@ QMetaCallEvent::~QMetaCallEvent()
*/
int QMetaCallEvent::placeMetaCall(QObject *object)
{
- return object->qt_metacall(QMetaObject::InvokeMetaMethod, id_, args_);
+ return QMetaObject::metacall(object, QMetaObject::InvokeMetaMethod, id_, args_);
}
/*!
@@ -747,7 +769,21 @@ QObject::~QObject()
QObjectPrivate::clearGuards(this);
}
+ if (d->sharedRefcount) {
+ if (d->sharedRefcount->strongref > 0) {
+ qWarning("QObject: shared QObject was deleted directly. The program is malformed and may crash.");
+ // but continue deleting, it's too late to stop anyway
+ }
+
+ // indicate to all QWeakPointers that this QObject has now been deleted
+ d->sharedRefcount->strongref = 0;
+ if (!d->sharedRefcount->weakref.deref())
+ delete d->sharedRefcount;
+ }
+
emit destroyed(this);
+ if (d->declarativeData)
+ d->declarativeData->destroyed(this);
{
QMutexLocker locker(signalSlotLock(this));
@@ -2849,10 +2885,16 @@ bool QMetaObject::connect(const QObject *sender, int signal_index,
s->d_func()->addConnection(signal_index, c);
- if (signal_index < 0)
- sender->d_func()->connectedSignals = ~0u;
- else if (signal_index < 32)
- sender->d_func()->connectedSignals |= (1 << signal_index);
+ if (signal_index < 0) {
+ for (uint i = 0; i < (sizeof sender->d_func()->connectedSignals
+ / sizeof sender->d_func()->connectedSignals[0] ); ++i)
+ sender->d_func()->connectedSignals[i] = ~0u;
+ } else if (signal_index < (int)sizeof sender->d_func()->connectedSignals * 8) {
+ uint n = (signal_index / (8 * sizeof sender->d_func()->connectedSignals[0]));
+ sender->d_func()->connectedSignals[n] |= (1 << (signal_index - n * 8
+ * sizeof sender->d_func()->connectedSignals[0]));
+ }
+
return true;
}
@@ -3140,10 +3182,10 @@ void QMetaObject::activate(QObject *sender, int from_signal_index, int to_signal
}
#if defined(QT_NO_EXCEPTIONS)
- receiver->qt_metacall(QMetaObject::InvokeMetaMethod, method, argv ? argv : empty_argv);
+ metacall(receiver, QMetaObject::InvokeMetaMethod, method, argv ? argv : empty_argv);
#else
try {
- receiver->qt_metacall(QMetaObject::InvokeMetaMethod, method, argv ? argv : empty_argv);
+ metacall(receiver, QMetaObject::InvokeMetaMethod, method, argv ? argv : empty_argv);
} catch (...) {
locker.relock();
@@ -3192,11 +3234,12 @@ void QMetaObject::activate(QObject *sender, int from_signal_index, int to_signal
*/
void QMetaObject::activate(QObject *sender, int signal_index, void **argv)
{
- if (signal_index < 32
+ if (signal_index < (int)sizeof(sender->d_func()->connectedSignals) * 8
&& !qt_signal_spy_callback_set.signal_begin_callback
&& !qt_signal_spy_callback_set.signal_end_callback) {
- uint signal_mask = 1 << signal_index;
- if ((sender->d_func()->connectedSignals & signal_mask) == 0)
+ uint n = (signal_index / (8 * sizeof sender->d_func()->connectedSignals[0]));
+ uint m = 1 << (signal_index - n * 8 * sizeof sender->d_func()->connectedSignals[0]);
+ if ((sender->d_func()->connectedSignals[n] & m) == 0)
// nothing connected to these signals, and no spy
return;
}
@@ -3209,11 +3252,12 @@ void QMetaObject::activate(QObject *sender, const QMetaObject *m, int local_sign
void **argv)
{
int signal_index = m->methodOffset() + local_signal_index;
- if (signal_index < 32
+ if (signal_index < (int)sizeof(sender->d_func()->connectedSignals) * 8
&& !qt_signal_spy_callback_set.signal_begin_callback
&& !qt_signal_spy_callback_set.signal_end_callback) {
- uint signal_mask = 1 << signal_index;
- if ((sender->d_func()->connectedSignals & signal_mask) == 0)
+ uint n = (signal_index / (8 * sizeof sender->d_func()->connectedSignals[0]));
+ uint m = 1 << (signal_index - n * 8 * sizeof sender->d_func()->connectedSignals[0]);
+ if ((sender->d_func()->connectedSignals[n] & m) == 0)
// nothing connected to these signals, and no spy
return;
}
@@ -3225,21 +3269,59 @@ void QMetaObject::activate(QObject *sender, const QMetaObject *m, int local_sign
void QMetaObject::activate(QObject *sender, const QMetaObject *m,
int from_local_signal_index, int to_local_signal_index, void **argv)
{
+ Q_ASSERT(from_local_signal_index <= to_local_signal_index);
int offset = m->methodOffset();
int from_signal_index = offset + from_local_signal_index;
int to_signal_index = offset + to_local_signal_index;
- if (to_signal_index < 32
+
+ if (to_signal_index < (int)sizeof(sender->d_func()->connectedSignals) * 8
&& !qt_signal_spy_callback_set.signal_begin_callback
&& !qt_signal_spy_callback_set.signal_end_callback) {
- uint signal_mask = (1 << (to_signal_index + 1)) - 1;
- signal_mask ^= (1 << from_signal_index) - 1;
- if ((sender->d_func()->connectedSignals & signal_mask) == 0)
+
+ uint n = (from_signal_index / (8 * sizeof sender->d_func()->connectedSignals[0]));
+ uint m = 1 << (from_signal_index - n * 8 * sizeof sender->d_func()->connectedSignals[0]);
+ uint nt = (to_signal_index / (8 * sizeof sender->d_func()->connectedSignals[0]));
+ uint mt = 1 << (to_signal_index - n * 8 * sizeof sender->d_func()->connectedSignals[0]);
+ bool connected = false;
+ quint32 *connectedSignals = sender->d_func()->connectedSignals;
+ for (uint i = 0; !connected && i < (sizeof sender->d_func()->connectedSignals
+ / sizeof sender->d_func()->connectedSignals[0]); ++i) {
+ uint mask = 0;
+ if (i > n)
+ mask = ~0u;
+ else if (i == n)
+ mask = ~(m -1);
+ if (i > nt)
+ mask = 0;
+ else if (i == nt)
+ mask &= (mt << 1) - 1;
+ connected = connectedSignals[i] & mask;
+ }
+ if (!connected)
// nothing connected to these signals, and no spy
return;
}
activate(sender, from_signal_index, to_signal_index, argv);
}
+/*! \internal
+
+ Returns true if the signal with index \a signal_index from object \a sender is connected.
+ Signals with indices above a certain range are always considered connected (see connectedSignals
+ in QObjectPrivate). If a signal spy is installed, all signals are considered connected.
+*/
+bool QMetaObject::isConnected(QObject *sender, int signal_index) {
+ if (signal_index < (int)sizeof(sender->d_func()->connectedSignals) * 8
+ && !qt_signal_spy_callback_set.signal_begin_callback
+ && !qt_signal_spy_callback_set.signal_end_callback) {
+ uint n = (signal_index / (8 * sizeof sender->d_func()->connectedSignals[0]));
+ uint m = 1 << (signal_index - n * 8 * sizeof sender->d_func()->connectedSignals[0]);
+ if ((sender->d_func()->connectedSignals[n] & m) == 0)
+ // nothing connected to these signals, and no spy
+ return false;
+ }
+ return true;
+}
/*****************************************************************************
Properties
@@ -3829,23 +3911,17 @@ QDebug operator<<(QDebug dbg, const QObject *o) {
Synonym for QList<QObject *>.
*/
-#ifdef QT_JAMBI_BUILD
-class QDPtrAccessor : public QObject {
-public:
- QObjectData *d() const { return d_ptr; }
-};
-#endif
-
void qDeleteInEventHandler(QObject *o)
{
#ifdef QT_JAMBI_BUILD
if (!o)
return;
- ((QDPtrAccessor *) o)->d()->inEventHandler = false;
+ QObjectPrivate::get(o)->inEventHandler = false;
#endif
delete o;
}
+
QT_END_NAMESPACE
#include "moc_qobject.cpp"
diff --git a/src/corelib/kernel/qobject.h b/src/corelib/kernel/qobject.h
index 1fb216b..9169a90 100644
--- a/src/corelib/kernel/qobject.h
+++ b/src/corelib/kernel/qobject.h
@@ -109,6 +109,7 @@ public:
uint hasGuards : 1; //true iff there is one or more QPointer attached to this object
uint unused : 22;
int postedEvents;
+ QMetaObject *metaObject; // assert dynamic
};
@@ -379,6 +380,9 @@ inline QList<T> qFindChildren(const QObject *o, const QRegExp &re)
#endif // Q_MOC_RUN
+template <class T> inline const char * qobject_interface_iid()
+{ return 0; }
+
template <class T> inline T qobject_cast_helper(QObject *object, T)
{ return static_cast<T>(((T)0)->staticMetaObject.cast(object)); }
@@ -395,6 +399,8 @@ inline T qobject_cast(const QObject *object)
#ifndef Q_MOC_RUN
# define Q_DECLARE_INTERFACE(IFace, IId) \
+ template <> inline const char *qobject_interface_iid<IFace *>() \
+ { return IId; } \
template <> inline IFace *qobject_cast_helper<IFace *>(QObject *object, IFace *) \
{ return (IFace *)(object ? object->qt_metacast(IId) : 0); } \
template <> inline IFace *qobject_cast_helper<IFace *>(const QObject *object, IFace *) \
@@ -458,8 +464,13 @@ inline T qobject_cast(const QObject *object)
}
+template <class T> inline const char * qobject_interface_iid()
+{ return 0; }
+
#ifndef Q_MOC_RUN
# define Q_DECLARE_INTERFACE(IFace, IId) \
+ template <> inline const char *qobject_interface_iid<IFace *>() \
+ { return IId; } \
template <> inline IFace *qobject_cast<IFace *>(QObject *object) \
{ return reinterpret_cast<IFace *>((object ? object->qt_metacast(IId) : 0)); } \
template <> inline IFace *qobject_cast<IFace *>(const QObject *object) \
diff --git a/src/corelib/kernel/qobject_p.h b/src/corelib/kernel/qobject_p.h
index 07c397f..056dee3 100644
--- a/src/corelib/kernel/qobject_p.h
+++ b/src/corelib/kernel/qobject_p.h
@@ -60,12 +60,14 @@
#include "QtCore/qvector.h"
#include "QtCore/qreadwritelock.h"
#include "QtCore/qvariant.h"
+#include "private/qguard_p.h"
QT_BEGIN_NAMESPACE
class QVariant;
class QThreadData;
class QObjectConnectionListVector;
+namespace QtSharedPointer { class ExternalRefCountData; }
/* mirrored in QtTestLib, DON'T CHANGE without prior warning */
struct QSignalSpyCallbackSet
@@ -81,56 +83,20 @@ void Q_CORE_EXPORT qt_register_signal_spy_callbacks(const QSignalSpyCallbackSet
extern QSignalSpyCallbackSet Q_CORE_EXPORT qt_signal_spy_callback_set;
-inline QObjectData::~QObjectData() {}
-
enum { QObjectPrivateVersion = QT_VERSION };
+class Q_CORE_EXPORT QDeclarativeData
+{
+public:
+ virtual ~QDeclarativeData();
+ virtual void destroyed(QObject *) = 0;
+};
+
class Q_CORE_EXPORT QObjectPrivate : public QObjectData
{
Q_DECLARE_PUBLIC(QObject)
public:
- QObjectPrivate(int version = QObjectPrivateVersion);
- virtual ~QObjectPrivate();
-
-#ifdef QT3_SUPPORT
- QList<QObject *> pendingChildInsertedEvents;
- void sendPendingChildInsertedEvents();
- void removePendingChildInsertedEvents(QObject *child);
-#else
- // preserve binary compatibility with code compiled without Qt 3 support
- QList<QObject *> unused;
-#endif
-
- // id of the thread that owns the object
- QThreadData *threadData;
- void moveToThread_helper();
- void setThreadData_helper(QThreadData *currentData, QThreadData *targetData);
- void _q_reregisterTimers(void *pointer);
-
- struct Sender
- {
- QObject *sender;
- int signal;
- int ref;
- };
- // object currently activating the object
- Sender *currentSender;
-
- QObject *currentChildBeingDeleted;
-
- bool isSender(const QObject *receiver, const char *signal) const;
- QObjectList receiverList(const char *signal) const;
- QObjectList senderList() const;
-
- QList<QPointer<QObject> > eventFilters;
-
- void setParent_helper(QObject *);
-
- void deleteChildren();
-
- static void clearGuards(QObject *);
-
struct ExtraData
{
#ifndef QT_NO_USERDATA
@@ -139,12 +105,7 @@ public:
QList<QByteArray> propertyNames;
QList<QVariant> propertyValues;
};
- ExtraData *extraData;
- mutable quint32 connectedSignals;
- QString objectName;
-
- // Note: you must hold the signalSlotLock() before accessing the lists below or calling the functions
struct Connection
{
QObject *sender;
@@ -159,11 +120,34 @@ public:
};
typedef QList<Connection *> ConnectionList;
- QObjectConnectionListVector *connectionLists;
+ struct Sender
+ {
+ QObject *sender;
+ int signal;
+ int ref;
+ };
+
+
+ QObjectPrivate(int version = QObjectPrivateVersion);
+ virtual ~QObjectPrivate();
+ void deleteChildren();
+
+ void setParent_helper(QObject *);
+ void moveToThread_helper();
+ void setThreadData_helper(QThreadData *currentData, QThreadData *targetData);
+ void _q_reregisterTimers(void *pointer);
+
+ bool isSender(const QObject *receiver, const char *signal) const;
+ QObjectList receiverList(const char *signal) const;
+ QObjectList senderList() const;
+
void addConnection(int signal, Connection *c);
void cleanConnectionLists();
- Connection *senders; //linked list;
+#ifdef QT3_SUPPORT
+ void sendPendingChildInsertedEvents();
+ void removePendingChildInsertedEvents(QObject *child);
+#endif
static Sender *setCurrentSender(QObject *receiver,
Sender *sender);
@@ -172,14 +156,66 @@ public:
Sender *previousSender);
static int *setDeleteWatch(QObjectPrivate *d, int *newWatch);
static void resetDeleteWatch(QObjectPrivate *d, int *oldWatch, int deleteWatch);
-
- int *deleteWatch;
+ static void clearGuards(QObject *);
static QObjectPrivate *get(QObject *o) {
return o->d_func();
}
+
+public:
+ QString objectName;
+ ExtraData *extraData; // extra data set by the user
+ QThreadData *threadData; // id of the thread that owns the object
+
+ QObjectConnectionListVector *connectionLists;
+
+ Connection *senders; // linked list of connections connected to this object
+ Sender *currentSender; // object currently activating the object
+ mutable quint32 connectedSignals[2]; // 64-bit, so doesn't cause padding on 64-bit platforms
+
+#ifdef QT3_SUPPORT
+ QList<QObject *> pendingChildInsertedEvents;
+#else
+ // preserve binary compatibility with code compiled without Qt 3 support
+ // ### why?
+ QList<QObject *> unused;
+#endif
+
+ QList<QPointer<QObject> > eventFilters;
+ QObject *currentChildBeingDeleted;
+
+ // these objects are all used to indicate that a QObject was deleted
+ // plus QPointer, which keeps a separate list
+ QDeclarativeData *declarativeData;
+ QGuard<QObject> *objectGuards;
+ QAtomicPointer<QtSharedPointer::ExternalRefCountData> sharedRefcount;
+ int *deleteWatch;
};
+inline void q_guard_addGuard(QGuard<QObject> *g)
+{
+ QObjectPrivate *p = QObjectPrivate::get(g->o);
+ if (p->wasDeleted) {
+ qWarning("QGuard: cannot add guard to deleted object");
+ g->o = 0;
+ return;
+ }
+
+ g->next = p->objectGuards;
+ p->objectGuards = g;
+ g->prev = &p->objectGuards;
+ if (g->next)
+ g->next->prev = &g->next;
+}
+
+inline void q_guard_removeGuard(QGuard<QObject> *g)
+{
+ if (g->next) g->next->prev = g->prev;
+ *g->prev = g->next;
+ g->next = 0;
+ g->prev = 0;
+}
+
Q_DECLARE_TYPEINFO(QObjectPrivate::Connection, Q_MOVABLE_TYPE);
Q_DECLARE_TYPEINFO(QObjectPrivate::Sender, Q_MOVABLE_TYPE);
@@ -220,6 +256,14 @@ private:
void Q_CORE_EXPORT qDeleteInEventHandler(QObject *o);
+
+struct Q_CORE_EXPORT QAbstractDynamicMetaObject : public QMetaObject
+{
+ virtual ~QAbstractDynamicMetaObject() {}
+ virtual int metaCall(QMetaObject::Call, int _id, void **) { return _id; }
+ virtual int createProperty(const char *, const char *) { return -1; }
+};
+
QT_END_NAMESPACE
#endif // QOBJECT_P_H
diff --git a/src/corelib/kernel/qobjectdefs.h b/src/corelib/kernel/qobjectdefs.h
index 9187765..1ae46d5 100644
--- a/src/corelib/kernel/qobjectdefs.h
+++ b/src/corelib/kernel/qobjectdefs.h
@@ -334,6 +334,9 @@ struct Q_CORE_EXPORT QMetaObject
static void activate(QObject *sender, int from_signal_index, int to_signal_index, void **argv);
static void activate(QObject *sender, const QMetaObject *, int local_signal_index, void **argv);
static void activate(QObject *sender, const QMetaObject *, int from_local_signal_index, int to_local_signal_index, void **argv);
+
+ static bool isConnected(QObject *sender, int signal_index);
+
// internal guarded pointers
static void addGuard(QObject **ptr);
static void removeGuard(QObject **ptr);
@@ -428,6 +431,7 @@ struct Q_CORE_EXPORT QMetaObject
};
int static_metacall(Call, int, void **) const;
+ static int metacall(QObject *, Call, int, void **);
#ifdef QT3_SUPPORT
QT3_SUPPORT const char *superClassName() const;
@@ -439,6 +443,7 @@ struct Q_CORE_EXPORT QMetaObject
const uint *data;
const void *extradata;
} d;
+
};
struct QMetaObjectExtraData
diff --git a/src/corelib/statemachine/qabstracttransition.cpp b/src/corelib/statemachine/qabstracttransition.cpp
index 0004d3e..3248dcf 100644
--- a/src/corelib/statemachine/qabstracttransition.cpp
+++ b/src/corelib/statemachine/qabstracttransition.cpp
@@ -153,34 +153,12 @@ QAbstractTransition::QAbstractTransition(QState *sourceState)
}
/*!
- Constructs a new QAbstractTransition object with the given \a targets and \a
- sourceState.
-*/
-QAbstractTransition::QAbstractTransition(const QList<QAbstractState*> &targets,
- QState *sourceState)
- : QObject(*new QAbstractTransitionPrivate, sourceState)
-{
- setTargetStates(targets);
-}
-
-/*!
- \internal
-*/
-QAbstractTransition::QAbstractTransition(QAbstractTransitionPrivate &dd,
- QState *parent)
- : QObject(dd, parent)
-{
-}
-
-/*!
\internal
*/
QAbstractTransition::QAbstractTransition(QAbstractTransitionPrivate &dd,
- const QList<QAbstractState*> &targets,
QState *parent)
: QObject(dd, parent)
{
- setTargetStates(targets);
}
/*!
diff --git a/src/corelib/statemachine/qabstracttransition.h b/src/corelib/statemachine/qabstracttransition.h
index 9ba1f11..8ff3a6e 100644
--- a/src/corelib/statemachine/qabstracttransition.h
+++ b/src/corelib/statemachine/qabstracttransition.h
@@ -72,7 +72,6 @@ class Q_CORE_EXPORT QAbstractTransition : public QObject
Q_PROPERTY(QList<QAbstractState*> targetStates READ targetStates WRITE setTargetStates)
public:
QAbstractTransition(QState *sourceState = 0);
- QAbstractTransition(const QList<QAbstractState*> &targets, QState *sourceState = 0);
virtual ~QAbstractTransition();
QState *sourceState() const;
@@ -104,8 +103,6 @@ protected:
protected:
QAbstractTransition(QAbstractTransitionPrivate &dd, QState *parent);
- QAbstractTransition(QAbstractTransitionPrivate &dd,
- const QList<QAbstractState*> &targets, QState *parent);
private:
Q_DISABLE_COPY(QAbstractTransition)
diff --git a/src/corelib/statemachine/qeventtransition.cpp b/src/corelib/statemachine/qeventtransition.cpp
index 3933981..813c960 100644
--- a/src/corelib/statemachine/qeventtransition.cpp
+++ b/src/corelib/statemachine/qeventtransition.cpp
@@ -153,22 +153,6 @@ QEventTransition::QEventTransition(QObject *object, QEvent::Type type,
}
/*!
- Constructs a new QEventTransition object associated with events of the given
- \a type for the given \a object. The transition has the given \a targets and
- \a sourceState.
-*/
-QEventTransition::QEventTransition(QObject *object, QEvent::Type type,
- const QList<QAbstractState*> &targets,
- QState *sourceState)
- : QAbstractTransition(*new QEventTransitionPrivate, targets, sourceState)
-{
- Q_D(QEventTransition);
- d->registered = false;
- d->object = object;
- d->eventType = type;
-}
-
-/*!
\internal
*/
QEventTransition::QEventTransition(QEventTransitionPrivate &dd, QState *parent)
@@ -190,20 +174,6 @@ QEventTransition::QEventTransition(QEventTransitionPrivate &dd, QObject *object,
}
/*!
- \internal
-*/
-QEventTransition::QEventTransition(QEventTransitionPrivate &dd, QObject *object,
- QEvent::Type type, const QList<QAbstractState*> &targets,
- QState *parent)
- : QAbstractTransition(dd, targets, parent)
-{
- Q_D(QEventTransition);
- d->registered = false;
- d->object = object;
- d->eventType = type;
-}
-
-/*!
Destroys this QObject event transition.
*/
QEventTransition::~QEventTransition()
diff --git a/src/corelib/statemachine/qeventtransition.h b/src/corelib/statemachine/qeventtransition.h
index b05ffef..0ebca19 100644
--- a/src/corelib/statemachine/qeventtransition.h
+++ b/src/corelib/statemachine/qeventtransition.h
@@ -62,8 +62,6 @@ class Q_CORE_EXPORT QEventTransition : public QAbstractTransition
public:
QEventTransition(QState *sourceState = 0);
QEventTransition(QObject *object, QEvent::Type type, QState *sourceState = 0);
- QEventTransition(QObject *object, QEvent::Type type,
- const QList<QAbstractState*> &targets, QState *sourceState = 0);
~QEventTransition();
QObject *eventObject() const;
@@ -82,9 +80,6 @@ protected:
QEventTransition(QEventTransitionPrivate &dd, QState *parent);
QEventTransition(QEventTransitionPrivate &dd, QObject *object,
QEvent::Type type, QState *parent);
- QEventTransition(QEventTransitionPrivate &dd, QObject *object,
- QEvent::Type type, const QList<QAbstractState*> &targets,
- QState *parent);
private:
Q_DISABLE_COPY(QEventTransition)
diff --git a/src/corelib/statemachine/qsignalevent.h b/src/corelib/statemachine/qsignalevent.h
index c09c5a3..b7ca61f 100644
--- a/src/corelib/statemachine/qsignalevent.h
+++ b/src/corelib/statemachine/qsignalevent.h
@@ -58,16 +58,16 @@ QT_MODULE(Core)
class Q_CORE_EXPORT QSignalEvent : public QEvent
{
public:
- QSignalEvent(const QObject *sender, int signalIndex,
+ QSignalEvent(QObject *sender, int signalIndex,
const QList<QVariant> &arguments);
~QSignalEvent();
- inline const QObject *sender() const { return m_sender; }
+ inline QObject *sender() const { return m_sender; }
inline int signalIndex() const { return m_signalIndex; }
inline QList<QVariant> arguments() const { return m_arguments; }
private:
- const QObject *m_sender;
+ QObject *m_sender;
int m_signalIndex;
QList<QVariant> m_arguments;
};
diff --git a/src/corelib/statemachine/qsignaltransition.cpp b/src/corelib/statemachine/qsignaltransition.cpp
index 389e513..7814699 100644
--- a/src/corelib/statemachine/qsignaltransition.cpp
+++ b/src/corelib/statemachine/qsignaltransition.cpp
@@ -159,21 +159,6 @@ QSignalTransition::QSignalTransition(QObject *sender, const char *signal,
}
/*!
- Constructs a new signal transition associated with the given \a signal of
- the given \a sender. The transition has the given \a targets and \a
- sourceState.
-*/
-QSignalTransition::QSignalTransition(QObject *sender, const char *signal,
- const QList<QAbstractState*> &targets,
- QState *sourceState)
- : QAbstractTransition(*new QSignalTransitionPrivate, targets, sourceState)
-{
- Q_D(QSignalTransition);
- d->sender = sender;
- d->signal = signal;
-}
-
-/*!
Destroys this signal transition.
*/
QSignalTransition::~QSignalTransition()
diff --git a/src/corelib/statemachine/qsignaltransition.h b/src/corelib/statemachine/qsignaltransition.h
index 69060ae..415751e 100644
--- a/src/corelib/statemachine/qsignaltransition.h
+++ b/src/corelib/statemachine/qsignaltransition.h
@@ -62,9 +62,6 @@ public:
QSignalTransition(QState *sourceState = 0);
QSignalTransition(QObject *sender, const char *signal,
QState *sourceState = 0);
- QSignalTransition(QObject *sender, const char *signal,
- const QList<QAbstractState*> &targets,
- QState *sourceState = 0);
~QSignalTransition();
QObject *senderObject() const;
diff --git a/src/corelib/statemachine/qstate.cpp b/src/corelib/statemachine/qstate.cpp
index 2042288..09d0be0 100644
--- a/src/corelib/statemachine/qstate.cpp
+++ b/src/corelib/statemachine/qstate.cpp
@@ -339,7 +339,8 @@ QSignalTransition *QState::addTransition(QObject *sender, const char *signal,
return 0;
}
}
- QSignalTransition *trans = new QSignalTransition(sender, signal, QList<QAbstractState*>() << target);
+ QSignalTransition *trans = new QSignalTransition(sender, signal);
+ trans->setTargetState(target);
addTransition(trans);
return trans;
}
@@ -351,7 +352,8 @@ class UnconditionalTransition : public QAbstractTransition
{
public:
UnconditionalTransition(QAbstractState *target)
- : QAbstractTransition(QList<QAbstractState*>() << target) {}
+ : QAbstractTransition()
+ { setTargetState(target); }
protected:
void onTransition(QEvent *) {}
bool eventTest(QEvent *) { return true; }
diff --git a/src/corelib/statemachine/qstatemachine.cpp b/src/corelib/statemachine/qstatemachine.cpp
index a02480b..9cb1d4d 100644
--- a/src/corelib/statemachine/qstatemachine.cpp
+++ b/src/corelib/statemachine/qstatemachine.cpp
@@ -205,6 +205,7 @@ This is
QStateMachinePrivate::QStateMachinePrivate()
{
state = NotRunning;
+ _startState = 0;
processing = false;
processingScheduled = false;
stop = false;
@@ -1138,7 +1139,8 @@ class InitialTransition : public QAbstractTransition
{
public:
InitialTransition(QAbstractState *target)
- : QAbstractTransition(QList<QAbstractState*>() << target) {}
+ : QAbstractTransition()
+ { setTargetState(target); }
protected:
virtual bool eventTest(QEvent *) { return true; }
virtual void onTransition(QEvent *) {}
@@ -1146,6 +1148,20 @@ protected:
} // namespace
+QState *QStateMachinePrivate::startState()
+{
+ Q_Q(QStateMachine);
+ if (_startState == 0)
+ _startState = new StartState(q);
+ return _startState;
+}
+
+void QStateMachinePrivate::removeStartState()
+{
+ delete _startState;
+ _startState = 0;
+}
+
void QStateMachinePrivate::_q_start()
{
Q_Q(QStateMachine);
@@ -1165,11 +1181,19 @@ void QStateMachinePrivate::_q_start()
processingScheduled = true; // we call _q_process() below
emit q->started();
- StartState *start = new StartState(rootState());
- QAbstractTransition *initialTransition = new InitialTransition(initial);
- start->addTransition(initialTransition);
- QList<QAbstractTransition*> transitions;
- transitions.append(initialTransition);
+ QState *start = startState();
+ Q_ASSERT(start != 0);
+
+ QList<QAbstractTransition*> transitions = QStatePrivate::get(start)->transitions();
+
+ // If a transition has already been added, then we skip this step, as the
+ // initial transition in that case has been overridden.
+ if (transitions.isEmpty()) {
+ QAbstractTransition *initialTransition = new InitialTransition(initial);
+ start->addTransition(initialTransition);
+ transitions.append(initialTransition);
+ }
+
QEvent nullEvent(QEvent::None);
executeTransitionContent(&nullEvent, transitions);
QList<QAbstractState*> enteredStates = enterStates(&nullEvent, transitions);
@@ -1177,7 +1201,7 @@ void QStateMachinePrivate::_q_start()
applyProperties(transitions, QList<QAbstractState*>() << start,
enteredStates);
#endif
- delete start;
+ removeStartState();
#ifdef QSTATEMACHINE_DEBUG
qDebug() << q << ": initial configuration:" << configuration;
@@ -1277,6 +1301,68 @@ void QStateMachinePrivate::scheduleProcess()
QMetaObject::invokeMethod(q_func(), "_q_process", Qt::QueuedConnection);
}
+namespace {
+
+class GoToStateTransition : public QAbstractTransition
+{
+public:
+ GoToStateTransition(QAbstractState *target)
+ : QAbstractTransition()
+ { setTargetState(target); }
+protected:
+ void onTransition(QEvent *) { deleteLater(); }
+ bool eventTest(QEvent *) { return true; }
+};
+
+} // namespace
+
+/*!
+ \internal
+
+ Causes this state machine to unconditionally transition to the given
+ \a targetState.
+
+ Provides a backdoor for using the state machine "imperatively"; i.e. rather
+ than defining explicit transitions, you drive the machine's execution by
+ calling this function. It breaks the whole integrity of the
+ transition-driven model, but is provided for pragmatic reasons.
+*/
+void QStateMachinePrivate::goToState(QAbstractState *targetState)
+{
+ if (!targetState) {
+ qWarning("QStateMachine::goToState(): cannot go to null state");
+ return;
+ }
+
+ if (configuration.contains(targetState))
+ return;
+
+ QState *sourceState = 0;
+ if (state == Running) {
+ QSet<QAbstractState*>::const_iterator it;
+ for (it = configuration.constBegin(); it != configuration.constEnd(); ++it) {
+ sourceState = qobject_cast<QState*>(*it);
+ if (sourceState != 0)
+ break;
+ }
+ } else {
+ sourceState = startState();
+ }
+
+ Q_ASSERT(sourceState != 0);
+ // Reuse previous GoToStateTransition in case of several calls to
+ // goToState() in a row.
+ GoToStateTransition *trans = qFindChild<GoToStateTransition*>(sourceState);
+ if (!trans) {
+ trans = new GoToStateTransition(targetState);
+ sourceState->addTransition(trans);
+ } else {
+ trans->setTargetState(targetState);
+ }
+
+ scheduleProcess();
+}
+
void QStateMachinePrivate::registerTransitions(QAbstractState *state)
{
QState *group = qobject_cast<QState*>(state);
@@ -1446,7 +1532,7 @@ void QStateMachinePrivate::unregisterEventTransition(QEventTransition *transitio
}
#endif
-void QStateMachinePrivate::handleTransitionSignal(const QObject *sender, int signalIndex,
+void QStateMachinePrivate::handleTransitionSignal(QObject *sender, int signalIndex,
void **argv)
{
Q_ASSERT(connections[sender].at(signalIndex) != 0);
@@ -2026,7 +2112,7 @@ QSignalEventGenerator::QSignalEventGenerator(QStateMachine *parent)
Constructs a new QSignalEvent object with the given \a sender, \a
signalIndex and \a arguments.
*/
-QSignalEvent::QSignalEvent(const QObject *sender, int signalIndex,
+QSignalEvent::QSignalEvent(QObject *sender, int signalIndex,
const QList<QVariant> &arguments)
: QEvent(QEvent::Signal), m_sender(sender),
m_signalIndex(signalIndex), m_arguments(arguments)
diff --git a/src/corelib/statemachine/qstatemachine_p.h b/src/corelib/statemachine/qstatemachine_p.h
index cae21aa..f0f74d6 100644
--- a/src/corelib/statemachine/qstatemachine_p.h
+++ b/src/corelib/statemachine/qstatemachine_p.h
@@ -79,7 +79,7 @@ class QAbstractAnimation;
#endif
class QStateMachine;
-class QStateMachinePrivate : public QStatePrivate
+class Q_CORE_EXPORT QStateMachinePrivate : public QStatePrivate
{
Q_DECLARE_PUBLIC(QStateMachine)
public:
@@ -116,6 +116,9 @@ public:
QState *rootState() const;
+ QState *startState();
+ void removeStartState();
+
void microstep(QEvent *event, const QList<QAbstractTransition*> &transitionList);
bool isPreempted(const QAbstractState *s, const QSet<QAbstractTransition*> &transitions) const;
QSet<QAbstractTransition*> selectTransitions(QEvent *event) const;
@@ -138,6 +141,8 @@ public:
static bool isDescendantOf(const QAbstractState *s, const QAbstractState *other);
static QList<QState*> properAncestors(const QAbstractState *s, const QState *upperBound);
+ void goToState(QAbstractState *targetState);
+
void registerTransitions(QAbstractState *state);
void registerSignalTransition(QSignalTransition *transition);
void unregisterSignalTransition(QSignalTransition *transition);
@@ -147,7 +152,7 @@ public:
#endif
void unregisterTransition(QAbstractTransition *transition);
void unregisterAllTransitions();
- void handleTransitionSignal(const QObject *sender, int signalIndex,
+ void handleTransitionSignal(QObject *sender, int signalIndex,
void **args);
void scheduleProcess();
@@ -162,6 +167,7 @@ public:
#endif
State state;
+ QState *_startState;
bool processing;
bool processingScheduled;
bool stop;
@@ -208,7 +214,7 @@ public:
f_cloneEvent cloneEvent;
};
- static Q_CORE_EXPORT const Handler *handler;
+ static const Handler *handler;
};
QT_END_NAMESPACE
diff --git a/src/corelib/tools/qbytedata_p.h b/src/corelib/tools/qbytedata_p.h
index cc10ea2..f3724f6 100644
--- a/src/corelib/tools/qbytedata_p.h
+++ b/src/corelib/tools/qbytedata_p.h
@@ -42,8 +42,18 @@
#ifndef QBYTEDATA_H
#define QBYTEDATA_H
-#include <qbytearray.h>
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists purely as an
+// implementation detail. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+#include <qbytearray.h>
QT_BEGIN_NAMESPACE
diff --git a/src/corelib/tools/qcontiguouscache.h b/src/corelib/tools/qcontiguouscache.h
index 0020d22..7221925 100644
--- a/src/corelib/tools/qcontiguouscache.h
+++ b/src/corelib/tools/qcontiguouscache.h
@@ -44,6 +44,7 @@
#include <QtCore/qatomic.h>
#include <limits.h>
+#include <new>
QT_BEGIN_HEADER
@@ -76,6 +77,12 @@ struct QContiguousCacheTypedData
int start;
int offset;
uint sharable : 1;
+ // uint unused : 31;
+
+ // total is 24 bytes (HP-UX aCC: 40 bytes)
+ // the next entry is already aligned to 8 bytes
+ // there will be an 8 byte gap here if T requires 16-byte alignment
+ // (such as long double on 64-bit platforms, __int128, __float128)
T array[1];
};
diff --git a/src/corelib/tools/qshareddata.cpp b/src/corelib/tools/qshareddata.cpp
index 3cd37a7..6cd220c 100644
--- a/src/corelib/tools/qshareddata.cpp
+++ b/src/corelib/tools/qshareddata.cpp
@@ -51,7 +51,7 @@ QT_BEGIN_NAMESPACE
QSharedData is designed to be used with QSharedDataPointer or
QExplicitlySharedDataPointer to implement custom \l{implicitly
- shared} or \l {explicitly shared} classes. QSharedData provides
+ shared} or explicitly shared classes. QSharedData provides
\l{thread-safe} reference counting.
See QSharedDataPointer and QExplicitlySharedDataPointer for details.
diff --git a/src/corelib/tools/qsharedpointer.cpp b/src/corelib/tools/qsharedpointer.cpp
index 59dfffe..f18dee8 100644
--- a/src/corelib/tools/qsharedpointer.cpp
+++ b/src/corelib/tools/qsharedpointer.cpp
@@ -128,7 +128,7 @@
To access the pointer that QWeakPointer is tracking, you
must first create a QSharedPointer object and verify if the pointer
- is null or not.
+ is null or not. See QWeakPointer::toStrongRef() for more information.
\sa QSharedPointer
*/
@@ -210,6 +210,8 @@
If \tt T is a derived type of the template parameter of this
class, QSharedPointer will perform an automatic cast. Otherwise,
you will get a compiler error.
+
+ \sa QWeakPointer::toStrongRef()
*/
/*!
@@ -362,6 +364,8 @@
Returns a weak reference object that shares the pointer referenced
by this object.
+
+ \sa QWeakPointer::QWeakPointer()
*/
/*!
@@ -478,10 +482,78 @@
*/
/*!
+ \fn T *QWeakPointer::data() const
+ \since 4.6
+
+ Returns the value of the pointer being tracked by this QWeakPointer,
+ \b without ensuring that it cannot get deleted. To have that guarantee,
+ use toStrongRef(), which returns a QSharedPointer object. If this
+ function can determine that the pointer has already been deleted, it
+ returns 0.
+
+ It is ok to obtain the value of the pointer and using that value itself,
+ like for example in debugging statements:
+
+ \code
+ qDebug("Tracking %p", weakref.data());
+ \endcode
+
+ However, dereferencing the pointer is only allowed if you can guarantee
+ by external means that the pointer does not get deleted. For example,
+ if you can be certain that no other thread can delete it, nor the
+ functions that you may call.
+
+ If that is the case, then the following code is valid:
+
+ \code
+ // this pointer cannot be used in another thread
+ // so other threads cannot delete it
+ QWeakPointer<int> weakref = obtainReference();
+
+ Object *obj = weakref.data();
+ if (obj) {
+ // if the pointer wasn't deleted yet, we know it can't get
+ // deleted by our own code here nor the functions we call
+ otherFunction(obj);
+ }
+ \endcode
+
+ Use this function with care.
+
+ \sa isNull(), toStrongRef()
+*/
+
+/*!
\fn QSharedPointer<T> QWeakPointer::toStrongRef() const
Promotes this weak reference to a strong one and returns a
- QSharedPointer object holding that reference.
+ QSharedPointer object holding that reference. When promoting to
+ QSharedPointer, this function verifies if the object has been deleted
+ already or not. If it hasn't, this function increases the reference
+ count to the shared object, thus ensuring that it will not get
+ deleted.
+
+ Since this function can fail to obtain a valid strong reference to the
+ shared object, you should always verify if the conversion succeeded,
+ by calling QSharedPointer::isNull() on the returned object.
+
+ For example, the following code promotes a QWeakPointer that was held
+ to a strong reference and, if it succeeded, it prints the value of the
+ integer that was held:
+
+ \code
+ QWeakPointer<int> weakref;
+
+ // ...
+
+ QSharedPointer<int> strong = weakref.toStrongRef();
+ if (strong)
+ qDebug() << "The value is:" << *strong;
+ else
+ qDebug() << "The value has already been deleted";
+ \endcode
+
+ \sa QSharedPointer::QSharedPointer()
*/
/*!
@@ -792,6 +864,56 @@
#include <qset.h>
#include <qmutex.h>
+#if !defined(QT_NO_QOBJECT)
+#include "../kernel/qobject_p.h"
+
+/*!
+ \internal
+ This function is called for a just-created QObject \a obj, to enable
+ the use of QSharedPointer and QWeakPointer.
+
+ When QSharedPointer is active in a QObject, the object must not be deleted
+ directly: the lifetime is managed by the QSharedPointer object. In that case,
+ the deleteLater() and parent-child relationship in QObject only decrease
+ the strong reference count, instead of deleting the object.
+*/
+void QtSharedPointer::ExternalRefCountData::setQObjectShared(const QObject *obj, bool)
+{
+ Q_ASSERT(obj);
+ QObjectPrivate *d = QObjectPrivate::get(const_cast<QObject *>(obj));
+
+ if (d->sharedRefcount)
+ qFatal("QSharedPointer: pointer %p already has reference counting", obj);
+ d->sharedRefcount = this;
+
+ // QObject decreases the refcount too, so increase it up
+ weakref.ref();
+}
+
+QtSharedPointer::ExternalRefCountData *QtSharedPointer::ExternalRefCountData::getAndRef(const QObject *obj)
+{
+ Q_ASSERT(obj);
+ QObjectPrivate *d = QObjectPrivate::get(const_cast<QObject *>(obj));
+ ExternalRefCountData *that = d->sharedRefcount;
+ if (that) {
+ that->weakref.ref();
+ return that;
+ }
+
+ // we can create the refcount data because it doesn't exist
+ ExternalRefCountData *x = new ExternalRefCountData(Qt::Uninitialized);
+ x->strongref = -1;
+ x->weakref = 2; // the QWeakPointer that called us plus the QObject itself
+ if (!d->sharedRefcount.testAndSetRelease(0, x)) {
+ delete x;
+ d->sharedRefcount->weakref.ref();
+ }
+ return d->sharedRefcount;
+}
+#endif
+
+
+
#if !defined(QT_NO_MEMBER_TEMPLATES)
//# define QT_SHARED_POINTER_BACKTRACE_SUPPORT
@@ -897,6 +1019,7 @@ QT_BEGIN_NAMESPACE
namespace QtSharedPointer {
Q_CORE_EXPORT void internalSafetyCheckAdd(const volatile void *);
Q_CORE_EXPORT void internalSafetyCheckRemove(const volatile void *);
+ Q_AUTOTEST_EXPORT void internalSafetyCheckCleanCheck();
}
/*!
@@ -961,6 +1084,7 @@ void QtSharedPointer::internalSafetyCheckAdd2(const void *d_ptr, const volatile
kp->dPointers.insert(d_ptr, data);
kp->dataPointers.insert(ptr, d_ptr);
+ Q_ASSERT(kp->dPointers.size() == kp->dataPointers.size());
}
/*!
@@ -985,10 +1109,29 @@ void QtSharedPointer::internalSafetyCheckRemove2(const void *d_ptr)
Q_ASSERT(it2 != kp->dataPointers.end());
//qDebug("Removing d=%p value=%p", d_ptr, it->pointer);
-
+
// remove entries
kp->dataPointers.erase(it2);
kp->dPointers.erase(it);
+ Q_ASSERT(kp->dPointers.size() == kp->dataPointers.size());
+}
+
+/*!
+ \internal
+ Called by the QSharedPointer autotest
+*/
+void QtSharedPointer::internalSafetyCheckCleanCheck()
+{
+# ifdef QT_BUILD_INTERNAL
+ KnownPointers *const kp = knownPointers();
+ Q_ASSERT_X(kp, "internalSafetyCheckSelfCheck()", "Called after global statics deletion!");
+
+ if (kp->dPointers.size() != kp->dataPointers.size())
+ qFatal("Internal consistency error: the number of pointers is not equal!");
+
+ if (!kp->dPointers.isEmpty())
+ qFatal("Pointer cleaning failed: %d entries remaining", kp->dPointers.size());
+# endif
}
QT_END_NAMESPACE
diff --git a/src/corelib/tools/qsharedpointer.h b/src/corelib/tools/qsharedpointer.h
index abd83ad..2f86ce7 100644
--- a/src/corelib/tools/qsharedpointer.h
+++ b/src/corelib/tools/qsharedpointer.h
@@ -115,6 +115,7 @@ public:
QWeakPointer<T> operator=(const QWeakPointer<T> &other);
QWeakPointer<T> operator=(const QSharedPointer<T> &other);
+ T *data() const;
void clear();
QSharedPointer<T> toStrongRef() const;
diff --git a/src/corelib/tools/qsharedpointer_impl.h b/src/corelib/tools/qsharedpointer_impl.h
index b8f4139..8a34362 100644
--- a/src/corelib/tools/qsharedpointer_impl.h
+++ b/src/corelib/tools/qsharedpointer_impl.h
@@ -94,26 +94,27 @@ namespace QtSharedPointer {
template <class T> class InternalRefCount;
template <class T> class ExternalRefCount;
- template <class X, class T> QSharedPointer<X> strongRefFromWeakHelper(const QWeakPointer<T> &, X*);
template <class X, class Y> QSharedPointer<X> copyAndSetPointer(X * ptr, const QSharedPointer<Y> &src);
// used in debug mode to verify the reuse of pointers
Q_CORE_EXPORT void internalSafetyCheckAdd2(const void *, const volatile void *);
Q_CORE_EXPORT void internalSafetyCheckRemove2(const void *);
-
+
template <class T, typename Klass, typename RetVal>
inline void executeDeleter(T *t, RetVal (Klass:: *memberDeleter)())
{ (t->*memberDeleter)(); }
template <class T, typename Deleter>
inline void executeDeleter(T *t, Deleter d)
{ d(t); }
+ template <class T> inline void normalDeleter(T *t) { delete t; }
+
+ // this uses partial template specialization
+ // the only compilers that didn't support this were MSVC 6.0 and 2002
+ template <class T> struct RemovePointer;
+ template <class T> struct RemovePointer<T *> { typedef T Type; };
+ template <class T> struct RemovePointer<QSharedPointer<T> > { typedef T Type; };
+ template <class T> struct RemovePointer<QWeakPointer<T> > { typedef T Type; };
- //
- // Depending on its template parameter, QSharedPointer derives from either
- // QtSharedPointer::InternalRefCount or from QtSharedPointer::ExternalRefCount.
- // Both of these classes derive from QtSharedPointer::Basic, which provides common
- // operations,
- //
template <class T>
class Basic
{
@@ -129,21 +130,10 @@ namespace QtSharedPointer {
inline T *operator->() const { return data(); }
protected:
- inline Basic() : value(0) { }
+ inline Basic(T *ptr = 0) : value(ptr) { }
+ inline Basic(Qt::Initialization) { }
// ~Basic();
- inline void verifyReconstruction(const T *ptr)
- {
- Q_ASSERT_X(!ptr || value != ptr, "QSharedPointer",
- "QSharedPointer violation: you cannot create two QSharedPointer objects "
- "from the same pointer");
-
- // make use of the "ptr" variable in the no-op statement below
- // since this function is in a public header, we don't
- // want warnings on "unused variables" to show up everywhere
- ptr = 0;
- }
-
inline void internalConstruct(T *ptr)
{
value = ptr;
@@ -160,14 +150,26 @@ namespace QtSharedPointer {
struct ExternalRefCountData
{
- QAtomicInt weakref;
- QAtomicInt strongref;
+ QBasicAtomicInt weakref;
+ QBasicAtomicInt strongref;
- inline ExternalRefCountData() : weakref(1), strongref(1) { }
- virtual inline ~ExternalRefCountData() { Q_ASSERT(!weakref); Q_ASSERT(!strongref); }
+ inline ExternalRefCountData()
+ {
+ QBasicAtomicInt proto = Q_BASIC_ATOMIC_INITIALIZER(1);
+ weakref = strongref = proto;
+ }
+ inline ExternalRefCountData(Qt::Initialization) { }
+ virtual inline ~ExternalRefCountData() { Q_ASSERT(!weakref); Q_ASSERT(strongref <= 0); }
virtual inline bool destroy() { return false; }
+
+#ifndef QT_NO_QOBJECT
+ Q_CORE_EXPORT static ExternalRefCountData *getAndRef(const QObject *);
+ Q_CORE_EXPORT void setQObjectShared(const QObject *, bool enable);
+#endif
+ inline void setQObjectShared(...) { }
};
+ // sizeof(ExternalRefCount) = 12 (32-bit) / 16 (64-bit)
template <class T, typename Deleter>
struct CustomDeleter
@@ -177,6 +179,9 @@ namespace QtSharedPointer {
inline CustomDeleter(T *p, Deleter d) : deleter(d), ptr(p) {}
};
+ // sizeof(CustomDeleter) = sizeof(Deleter) + sizeof(void*)
+ // for Deleter = function pointer: 8 (32-bit) / 16 (64-bit)
+ // for Deleter = PMF: 12 (32-bit) / 24 (64-bit) (GCC)
struct ExternalRefCountWithDestroyFn: public ExternalRefCountData
{
@@ -190,6 +195,7 @@ namespace QtSharedPointer {
inline bool destroy() { destroyer(this); return true; }
inline void operator delete(void *ptr) { ::operator delete(ptr); }
};
+ // sizeof(ExternalRefCountWithDestroyFn) = 16 (32-bit) / 24 (64-bit)
template <class T, typename Deleter>
struct ExternalRefCountWithCustomDeleter: public ExternalRefCountWithDestroyFn
@@ -203,11 +209,23 @@ namespace QtSharedPointer {
{
Self *realself = static_cast<Self *>(self);
executeDeleter(realself->extra.ptr, realself->extra.deleter);
+
+ // delete the deleter too
+ realself->extra.~Next();
+ }
+ static void safetyCheckDeleter(ExternalRefCountData *self)
+ {
+ internalSafetyCheckRemove2(self);
+ deleter(self);
}
static inline Self *create(T *ptr, Deleter userDeleter)
{
+# ifdef QT_SHAREDPOINTER_TRACK_POINTERS
+ DestroyerFn destroy = &safetyCheckDeleter;
+# else
DestroyerFn destroy = &deleter;
+# endif
Self *d = static_cast<Self *>(::operator new(sizeof(Self)));
// initialize the two sub-objects
@@ -234,10 +252,19 @@ namespace QtSharedPointer {
static_cast<ExternalRefCountWithContiguousData *>(self);
that->data.~T();
}
+ static void safetyCheckDeleter(ExternalRefCountData *self)
+ {
+ internalSafetyCheckRemove2(self);
+ deleter(self);
+ }
static inline ExternalRefCountData *create(T **ptr)
{
+# ifdef QT_SHAREDPOINTER_TRACK_POINTERS
+ DestroyerFn destroy = &safetyCheckDeleter;
+# else
DestroyerFn destroy = &deleter;
+# endif
ExternalRefCountWithContiguousData *d =
static_cast<ExternalRefCountWithContiguousData *>(::operator new(sizeof(ExternalRefCountWithContiguousData)));
@@ -258,9 +285,9 @@ namespace QtSharedPointer {
template <class T>
class ExternalRefCount: public Basic<T>
{
- typedef ExternalRefCountData Data;
- typedef void (*DeleterFunction)(T *);
protected:
+ typedef ExternalRefCountData Data;
+
inline void ref() const { d->weakref.ref(); d->strongref.ref(); }
inline bool deref()
{
@@ -272,42 +299,51 @@ namespace QtSharedPointer {
inline void internalConstruct(T *ptr)
{
- Basic<T>::internalConstruct(ptr);
- Q_ASSERT(!d);
+#ifdef QT_SHAREDPOINTER_TRACK_POINTERS
+ internalConstruct<void (*)(T *)>(ptr, normalDeleter);
+#else
if (ptr)
d = new Data;
-#ifdef QT_SHAREDPOINTER_TRACK_POINTERS
- if (ptr) internalSafetyCheckAdd2(d, ptr);
+ else
+ d = 0;
+ internalFinishConstruction(ptr);
#endif
}
template <typename Deleter>
inline void internalConstruct(T *ptr, Deleter deleter)
{
- Basic<T>::internalConstruct(ptr);
- Q_ASSERT(!d);
if (ptr)
d = ExternalRefCountWithCustomDeleter<T, Deleter>::create(ptr, deleter);
-#ifdef QT_SHAREDPOINTER_TRACK_POINTERS
- if (ptr) internalSafetyCheckAdd2(d, ptr);
-#endif
+ else
+ d = 0;
+ internalFinishConstruction(ptr);
}
inline void internalCreate()
{
T *ptr;
d = ExternalRefCountWithContiguousData<T>::create(&ptr);
+ Basic<T>::internalConstruct(ptr);
+ }
+ inline void internalFinishConstruction(T *ptr)
+ {
Basic<T>::internalConstruct(ptr);
+ if (ptr) d->setQObjectShared(ptr, true);
#ifdef QT_SHAREDPOINTER_TRACK_POINTERS
if (ptr) internalSafetyCheckAdd2(d, ptr);
#endif
}
inline ExternalRefCount() : d(0) { }
- inline ~ExternalRefCount() { if (d && !deref()) delete d; }
+ inline ExternalRefCount(Qt::Initialization i) : Basic<T>(i) { }
inline ExternalRefCount(const ExternalRefCount<T> &other) : Basic<T>(other), d(other.d)
{ if (d) ref(); }
+ template <class X>
+ inline ExternalRefCount(const ExternalRefCount<X> &other) : Basic<T>(other.value), d(other.d)
+ { if (d) ref(); }
+ inline ~ExternalRefCount() { if (d && !deref()) delete d; }
template <class X>
inline void internalCopy(const ExternalRefCount<X> &other)
@@ -317,32 +353,35 @@ namespace QtSharedPointer {
inline void internalDestroy()
{
-#ifdef QT_SHAREDPOINTER_TRACK_POINTERS
- internalSafetyCheckRemove2(d);
-#endif
if (!d->destroy())
delete this->value;
}
- private:
#if defined(Q_NO_TEMPLATE_FRIENDS)
public:
#else
template <class X> friend class ExternalRefCount;
template <class X> friend class QWeakPointer;
template <class X, class Y> friend QSharedPointer<X> copyAndSetPointer(X * ptr, const QSharedPointer<Y> &src);
- template <class X, class Y> friend QSharedPointer<X> QtSharedPointer::strongRefFromWeakHelper(const QWeakPointer<Y> &src, X *);
#endif
inline void internalSet(Data *o, T *actual)
{
- if (d == o) return;
- if (o && !o->strongref)
- o = 0;
if (o) {
- verifyReconstruction(actual);
- o->weakref.ref();
- o->strongref.ref();
+ // increase the strongref, but never up from zero
+ // or less (-1 is used by QWeakPointer on untracked QObject)
+ register int tmp = o->strongref;
+ while (tmp > 0) {
+ // try to increment from "tmp" to "tmp + 1"
+ if (o->strongref.testAndSetRelaxed(tmp, tmp + 1))
+ break; // succeeded
+ tmp = o->strongref; // failed, try again
+ }
+
+ if (tmp > 0)
+ o->weakref.ref();
+ else
+ o = 0;
}
if (d && !deref())
delete d;
@@ -350,9 +389,6 @@ namespace QtSharedPointer {
this->value = d && d->strongref ? actual : 0;
}
-#if defined(QT_BUILD_INTERNAL)
- public:
-#endif
Data *d;
private:
@@ -368,7 +404,8 @@ public:
inline QSharedPointer() { }
// inline ~QSharedPointer() { }
- inline explicit QSharedPointer(T *ptr) { internalConstruct(ptr); }
+ inline explicit QSharedPointer(T *ptr) : BaseClass(Qt::Uninitialized)
+ { internalConstruct(ptr); }
template <typename Deleter>
inline QSharedPointer(T *ptr, Deleter d) { internalConstruct(ptr, d); }
@@ -380,13 +417,9 @@ public:
return *this;
}
- inline QSharedPointer(const QWeakPointer<T> &other)
- { *this = QtSharedPointer::strongRefFromWeakHelper(other, static_cast<T*>(0)); }
- inline QSharedPointer<T> &operator=(const QWeakPointer<T> &other)
- { *this = QtSharedPointer::strongRefFromWeakHelper(other, static_cast<T*>(0)); return *this; }
-
template <class X>
- inline QSharedPointer(const QSharedPointer<X> &other) { *this = other; }
+ inline QSharedPointer(const QSharedPointer<X> &other) : BaseClass(other)
+ { }
template <class X>
inline QSharedPointer<T> &operator=(const QSharedPointer<X> &other)
@@ -397,12 +430,12 @@ public:
}
template <class X>
- inline QSharedPointer(const QWeakPointer<X> &other)
- { *this = QtSharedPointer::strongRefFromWeakHelper(other, static_cast<T *>(0)); }
+ inline QSharedPointer(const QWeakPointer<X> &other) : BaseClass(Qt::Uninitialized)
+ { this->d = 0; *this = other; }
template <class X>
inline QSharedPointer<T> &operator=(const QWeakPointer<X> &other)
- { *this = strongRefFromWeakHelper(other, static_cast<T *>(0)); return *this; }
+ { internalSet(other.d, other.value); return *this; }
template <class X>
QSharedPointer<X> staticCast() const
@@ -434,14 +467,18 @@ public:
QWeakPointer<T> toWeakRef() const;
+protected:
+ inline QSharedPointer(Qt::Initialization i) : BaseClass(i) {}
+
public:
static inline QSharedPointer<T> create()
{
- QSharedPointer<T> result;
+ QSharedPointer<T> result(Qt::Uninitialized);
result.internalCreate();
// now initialize the data
new (result.data()) T();
+ result.internalFinishConstruction(result.data());
return result;
}
};
@@ -456,9 +493,19 @@ public:
inline bool isNull() const { return d == 0 || d->strongref == 0 || value == 0; }
inline operator RestrictedBool() const { return isNull() ? 0 : &QWeakPointer::value; }
inline bool operator !() const { return isNull(); }
+ inline T *data() const { return d == 0 || d->strongref == 0 ? 0 : value; }
inline QWeakPointer() : d(0), value(0) { }
inline ~QWeakPointer() { if (d && !d->weakref.deref()) delete d; }
+
+ // special constructor that is enabled only if X derives from QObject
+ template <class X>
+ inline QWeakPointer(X *ptr) : d(ptr ? d->getAndRef(ptr) : 0), value(ptr)
+ { }
+ template <class X>
+ inline QWeakPointer &operator=(X *ptr)
+ { return *this = QWeakPointer(ptr); }
+
inline QWeakPointer(const QWeakPointer<T> &o) : d(o.d), value(o.value)
{ if (d) d->weakref.ref(); }
inline QWeakPointer<T> &operator=(const QWeakPointer<T> &o)
@@ -510,7 +557,7 @@ public:
template <class X>
inline bool operator==(const QSharedPointer<X> &o) const
- { return d == o.d && value == static_cast<const T *>(o.data()); }
+ { return d == o.d; }
template <class X>
inline bool operator!=(const QSharedPointer<X> &o) const
@@ -525,7 +572,7 @@ private:
#if defined(Q_NO_TEMPLATE_FRIENDS)
public:
#else
- template <class X, class Y> friend QSharedPointer<X> QtSharedPointer::strongRefFromWeakHelper(const QWeakPointer<Y> &src, X *);
+ template <class X> friend class QSharedPointer;
#endif
inline void internalSet(Data *o, T *actual)
@@ -602,14 +649,6 @@ namespace QtSharedPointer {
result.internalSet(src.d, ptr);
return result;
}
- template <class X, class T>
- Q_INLINE_TEMPLATE QSharedPointer<X> strongRefFromWeakHelper
- (const QT_PREPEND_NAMESPACE(QWeakPointer<T>) &src, X *)
- {
- QSharedPointer<X> result;
- result.internalSet(src.d, src.value);
- return result;
- }
}
// cast operators
@@ -669,14 +708,6 @@ Q_INLINE_TEMPLATE QSharedPointer<X> qSharedPointerObjectCast(const QWeakPointer<
return qSharedPointerObjectCast<X>(src.toStrongRef());
}
-# ifndef QT_NO_PARTIAL_TEMPLATE_SPECIALIZATION
-namespace QtSharedPointer {
- template <class T> struct RemovePointer;
- template <class T> struct RemovePointer<T *> { typedef T Type; };
- template <class T> struct RemovePointer<QSharedPointer<T> > { typedef T Type; };
- template <class T> struct RemovePointer<QWeakPointer<T> > { typedef T Type; };
-}
-
template <class X, class T>
inline QSharedPointer<typename QtSharedPointer::RemovePointer<X>::Type>
qobject_cast(const QSharedPointer<T> &src)
@@ -689,7 +720,6 @@ qobject_cast(const QWeakPointer<T> &src)
{
return qSharedPointerObjectCast<typename QtSharedPointer::RemovePointer<X>::Type, T>(src);
}
-# endif
#endif
diff --git a/src/gui/accessible/accessible.pri b/src/gui/accessible/accessible.pri
index 76b6687..ad2fb4c 100644
--- a/src/gui/accessible/accessible.pri
+++ b/src/gui/accessible/accessible.pri
@@ -14,7 +14,8 @@ contains(QT_CONFIG, accessibility) {
mac:!embedded {
HEADERS += accessible/qaccessible_mac_p.h
- OBJECTIVE_SOURCES += accessible/qaccessible_mac.mm
+ OBJECTIVE_SOURCES += accessible/qaccessible_mac.mm \
+ accessible/qaccessible_mac_cocoa.mm
} else:win32 {
SOURCES += accessible/qaccessible_win.cpp
} else {
diff --git a/src/gui/accessible/qaccessible_mac_cocoa.mm b/src/gui/accessible/qaccessible_mac_cocoa.mm
index e69de29..1cb2ffa 100644
--- a/src/gui/accessible/qaccessible_mac_cocoa.mm
+++ b/src/gui/accessible/qaccessible_mac_cocoa.mm
@@ -0,0 +1,234 @@
+
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtGui module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the either Technology Preview License Agreement or the
+** Beta Release License Agreement.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain
+** additional rights. These rights are described in the Nokia Qt LGPL
+** Exception version 1.0, 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.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at http://www.qtsoftware.com/contact.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qaccessible.h"
+#include "qaccessible_mac_p.h"
+#include "qdebug.h"
+#include "qtabwidget.h"
+
+#include <private/qt_mac_p.h>
+#include <private/qcocoaview_mac_p.h>
+#include <private/qwidget_p.h>
+
+
+#ifndef QT_NO_ACCESSIBILITY
+
+#ifdef QT_MAC_USE_COCOA
+
+QT_BEGIN_NAMESPACE
+
+//#define MAC_ACCESSIBILTY_DEVELOPER_MODE
+
+#ifdef MAC_ACCESSIBILTY_DEVELOPER_MODE
+#define MAC_ACCESSIBILTY_DEBUG qDebug
+#else
+#define MAC_ACCESSIBILTY_DEBUG if (0) qDebug
+#endif
+
+typedef QMap<QAccessible::Role, NSString *> QMacAccessibiltyRoleMap;
+Q_GLOBAL_STATIC(QMacAccessibiltyRoleMap, qMacAccessibiltyRoleMap);
+
+static QAInterface interfaceForView(QT_MANGLE_NAMESPACE(QCocoaView) *view)
+{
+ return QAInterface(QAccessible::queryAccessibleInterface([view qt_qwidget]));
+}
+
+/*
+ Set up mappings from Qt accessibilty roles to Mac accessibilty roles.
+*/
+static void populateRoleMap()
+{
+ QMacAccessibiltyRoleMap &roleMap = *qMacAccessibiltyRoleMap();
+ roleMap[QAccessible::MenuItem] = NSAccessibilityMenuItemRole;
+ roleMap[QAccessible::MenuBar] = NSAccessibilityMenuBarRole;
+ roleMap[QAccessible::ScrollBar] = NSAccessibilityScrollBarRole;
+ roleMap[QAccessible::Grip] = NSAccessibilityGrowAreaRole;
+ roleMap[QAccessible::Window] = NSAccessibilityWindowRole;
+ roleMap[QAccessible::Dialog] = NSAccessibilityWindowRole;
+ roleMap[QAccessible::AlertMessage] = NSAccessibilityWindowRole;
+ roleMap[QAccessible::ToolTip] = NSAccessibilityWindowRole;
+ roleMap[QAccessible::HelpBalloon] = NSAccessibilityWindowRole;
+ roleMap[QAccessible::PopupMenu] = NSAccessibilityMenuRole;
+ roleMap[QAccessible::Application] = NSAccessibilityApplicationRole;
+ roleMap[QAccessible::Pane] = NSAccessibilityGroupRole;
+ roleMap[QAccessible::Grouping] = NSAccessibilityGroupRole;
+ roleMap[QAccessible::Separator] = NSAccessibilitySplitterRole;
+ roleMap[QAccessible::ToolBar] = NSAccessibilityToolbarRole;
+ roleMap[QAccessible::PageTab] = NSAccessibilityRadioButtonRole;
+ roleMap[QAccessible::ButtonMenu] = NSAccessibilityMenuButtonRole;
+ roleMap[QAccessible::ButtonDropDown] = NSAccessibilityPopUpButtonRole;
+ roleMap[QAccessible::SpinBox] = NSAccessibilityIncrementorRole;
+ roleMap[QAccessible::Slider] = NSAccessibilitySliderRole;
+ roleMap[QAccessible::ProgressBar] = NSAccessibilityProgressIndicatorRole;
+ roleMap[QAccessible::ComboBox] = NSAccessibilityPopUpButtonRole;
+ roleMap[QAccessible::RadioButton] = NSAccessibilityRadioButtonRole;
+ roleMap[QAccessible::CheckBox] = NSAccessibilityCheckBoxRole;
+ roleMap[QAccessible::StaticText] = NSAccessibilityStaticTextRole;
+ roleMap[QAccessible::Table] = NSAccessibilityTableRole;
+ roleMap[QAccessible::StatusBar] = NSAccessibilityStaticTextRole;
+ roleMap[QAccessible::Column] = NSAccessibilityColumnRole;
+ roleMap[QAccessible::ColumnHeader] = NSAccessibilityColumnRole;
+ roleMap[QAccessible::Row] = NSAccessibilityRowRole;
+ roleMap[QAccessible::RowHeader] = NSAccessibilityRowRole;
+ roleMap[QAccessible::Cell] = NSAccessibilityTextFieldRole;
+ roleMap[QAccessible::PushButton] = NSAccessibilityButtonRole;
+ roleMap[QAccessible::EditableText] = NSAccessibilityTextFieldRole;
+ roleMap[QAccessible::Link] = NSAccessibilityTextFieldRole;
+ roleMap[QAccessible::Indicator] = NSAccessibilityValueIndicatorRole;
+ roleMap[QAccessible::Splitter] = NSAccessibilitySplitGroupRole;
+ roleMap[QAccessible::List] = NSAccessibilityListRole;
+ roleMap[QAccessible::ListItem] = NSAccessibilityStaticTextRole;
+ roleMap[QAccessible::Cell] = NSAccessibilityStaticTextRole;
+}
+
+/*
+ Returns a Mac accessibility role for the given interface, or
+ NSAccessibilityUnknownRole if no role mapping is found.
+*/
+static NSString *macRoleForInterface(QAInterface interface)
+{
+ const QAccessible::Role qtRole = interface.role();
+ QMacAccessibiltyRoleMap &roleMap = *qMacAccessibiltyRoleMap();
+
+ if (roleMap.isEmpty())
+ populateRoleMap();
+
+ MAC_ACCESSIBILTY_DEBUG() << "role for" << interface.object() << "interface role" << hex << qtRole;
+
+ if (roleMap.contains(qtRole)) {
+ MAC_ACCESSIBILTY_DEBUG() << "return" << roleMap[qtRole];
+ return roleMap[qtRole];
+ }
+
+ MAC_ACCESSIBILTY_DEBUG() << "return NSAccessibilityUnknownRole";
+ return NSAccessibilityUnknownRole;
+}
+
+/*
+ Is the interface a QTabBar embedded in a QTabWidget?
+ (as opposed to a stand-alone tab bar)
+*/
+static bool isEmbeddedTabBar(const QAInterface &interface)
+{
+ QObject *object = interface.object();
+ if (interface.role() == QAccessible::PageTabList && object)
+ return (qobject_cast<QTabWidget *>(object->parent()));
+
+ return false;
+}
+
+static bool isInterfaceIgnored(QAInterface interface)
+{
+ // Mac accessibility does not have an attribute that corresponds to the
+ // Invisible/Offscreen state. Use the ignore facility to disable them.
+ const QAccessible::State state = interface.state();
+ if (state & QAccessible::Invisible ||
+ state & QAccessible::Offscreen )
+ return false;
+
+ // Hide QTabBars that has a QTabWidget parent (the QTabWidget handles the accessibility)
+ if (isEmbeddedTabBar(interface))
+ return false;
+
+ if (QObject * const object = interface.object()) {
+ const QString className = QLatin1String(object->metaObject()->className());
+
+ // Prevent VoiceOver from focusing on tool tips by ignoring those
+ // interfaces. Shifting VoiceOver focus to the tool tip is confusing
+ // and the contents of the tool tip is avalible through the description
+ // attribute anyway.
+ if (className == QLatin1String("QTipLabel"))
+ return false;
+ }
+
+ // Hide interfaces with an unknown role. When developing it's often useful to disable
+ // this check to see all interfaces in the hierarchy.
+#ifndef MAC_ACCESSIBILTY_DEVELOPER_MODE
+ return [macRoleForInterface(interface) isEqualToString: NSAccessibilityUnknownRole];
+#else
+ return NO;
+#endif
+}
+
+QT_END_NAMESPACE
+
+@implementation QT_MANGLE_NAMESPACE(QCocoaView) (Accessibility)
+
+- (BOOL)accessibilityIsIgnored
+{
+ QAInterface interface = interfaceForView(self);
+ return isInterfaceIgnored(interface);
+}
+
+- (NSArray *)accessibilityAttributeNames
+{
+ QAInterface interface = interfaceForView(self);
+
+ static NSArray *attributes = nil;
+ if (attributes == nil) {
+ attributes = [super accessibilityAttributeNames];
+
+ }
+ return attributes;
+}
+
+- (id)accessibilityAttributeValue:(NSString *)attribute
+{
+ MAC_ACCESSIBILTY_DEBUG() << "accessibilityAttributeValue" << self << QCFString::toQString(reinterpret_cast<CFStringRef>(attribute));
+
+ QAInterface interface = interfaceForView(self);
+
+ // Switch on the attribute name and call the appropriate handler function.
+ // Pass the call on to the NSView class for attributes we don't handle.
+ if ([attribute isEqualToString:@"AXRole"]) {
+ return macRoleForInterface(interface);
+ } else {
+ return [super accessibilityAttributeValue:attribute];
+ }
+}
+
+@end
+
+#endif // QT_MAC_USE_COCOA
+
+#endif // QT_NO_ACCESSIBILITY
+
diff --git a/src/gui/dialogs/qcolordialog.cpp b/src/gui/dialogs/qcolordialog.cpp
index 42d3a9a..aee592c 100644
--- a/src/gui/dialogs/qcolordialog.cpp
+++ b/src/gui/dialogs/qcolordialog.cpp
@@ -1583,8 +1583,7 @@ void QColorDialog::setCurrentColor(const QColor &color)
#ifdef Q_WS_MAC
d->setCurrentQColor(color);
- if (d->delegate)
- QColorDialogPrivate::setColor(d->delegate, color);
+ d->setCocoaPanelColor(color);
#endif
}
@@ -1725,19 +1724,16 @@ void QColorDialog::setVisible(bool visible)
#if defined(Q_WS_MAC)
if (visible) {
- if (!d->delegate && QColorDialogPrivate::sharedColorPanelAvailable &&
- !(testAttribute(Qt::WA_DontShowOnScreen) || (d->opts & DontUseNativeDialog))){
- d->delegate = QColorDialogPrivate::openCocoaColorPanel(
- currentColor(), parentWidget(), windowTitle(), options(), d);
+ if (d->delegate || (QColorDialogPrivate::sharedColorPanelAvailable &&
+ !(testAttribute(Qt::WA_DontShowOnScreen) || (d->opts & DontUseNativeDialog)))){
+ d->openCocoaColorPanel(currentColor(), parentWidget(), windowTitle(), options());
QColorDialogPrivate::sharedColorPanelAvailable = false;
setAttribute(Qt::WA_DontShowOnScreen);
}
setWindowFlags(windowModality() == Qt::WindowModal ? Qt::Sheet : DefaultWindowFlags);
} else {
if (d->delegate) {
- QColorDialogPrivate::closeCocoaColorPanel(d->delegate);
- d->delegate = 0;
- QColorDialogPrivate::sharedColorPanelAvailable = true;
+ d->closeCocoaColorPanel();
setAttribute(Qt::WA_DontShowOnScreen, false);
}
}
@@ -1840,6 +1836,14 @@ QRgb QColorDialog::getRgba(QRgb initial, bool *ok, QWidget *parent)
QColorDialog::~QColorDialog()
{
+ Q_D(QColorDialog);
+#if defined(Q_WS_MAC)
+ if (d->delegate) {
+ d->releaseCocoaColorPanelDelegate();
+ QColorDialogPrivate::sharedColorPanelAvailable = true;
+ }
+#endif
+
#ifndef QT_NO_SETTINGS
if (!customSet) {
QSettings settings(QSettings::UserScope, QLatin1String("Trolltech"));
diff --git a/src/gui/dialogs/qcolordialog_mac.mm b/src/gui/dialogs/qcolordialog_mac.mm
index 1936de5..6cdb7ee 100644
--- a/src/gui/dialogs/qcolordialog_mac.mm
+++ b/src/gui/dialogs/qcolordialog_mac.mm
@@ -76,6 +76,8 @@ QT_USE_NAMESPACE
CGFloat mMinWidth; // currently unused
CGFloat mExtraHeight; // currently unused
BOOL mHackedPanel;
+ NSInteger mResultCode;
+ BOOL mDialogIsExecuting;
}
- (id)initWithColorPanel:(NSColorPanel *)panel
stolenContentView:(NSView *)stolenContentView
@@ -90,7 +92,8 @@ QT_USE_NAMESPACE
- (NSColorPanel *)colorPanel;
- (QColor)qtColor;
- (void)finishOffWithCode:(NSInteger)result;
-- (void)cleanUpAfterMyself;
+- (void)showColorPanel;
+- (void)exec;
@end
@implementation QCocoaColorPanelDelegate
@@ -110,6 +113,8 @@ QT_USE_NAMESPACE
mMinWidth = 0.0;
mExtraHeight = 0.0;
mHackedPanel = (okButton != 0);
+ mResultCode = NSCancelButton;
+ mDialogIsExecuting = false;
if (mHackedPanel) {
[self relayout];
@@ -121,19 +126,31 @@ QT_USE_NAMESPACE
[cancelButton setTarget:self];
}
- if (mPriv)
- [[NSNotificationCenter defaultCenter] addObserver:self
- selector:@selector(colorChanged:)
- name:NSColorPanelColorDidChangeNotification
- object:mColorPanel];
+ [[NSNotificationCenter defaultCenter] addObserver:self
+ selector:@selector(colorChanged:)
+ name:NSColorPanelColorDidChangeNotification
+ object:mColorPanel];
+
mQtColor = new QColor();
return self;
}
- (void)dealloc
{
- if (mPriv)
- [[NSNotificationCenter defaultCenter] removeObserver:self];
+ QMacCocoaAutoReleasePool pool;
+ if (mHackedPanel) {
+ NSView *ourContentView = [mColorPanel contentView];
+
+ // return stolen stuff to its rightful owner
+ [mStolenContentView removeFromSuperview];
+ [mColorPanel setContentView:mStolenContentView];
+
+ [mOkButton release];
+ [mCancelButton release];
+ [ourContentView release];
+ }
+ [mColorPanel setDelegate:nil];
+ [[NSNotificationCenter defaultCenter] removeObserver:self];
delete mQtColor;
[super dealloc];
}
@@ -160,8 +177,7 @@ QT_USE_NAMESPACE
- (void)colorChanged:(NSNotification *)notification;
{
Q_UNUSED(notification);
- if (mPriv)
- [self updateQtColor];
+ [self updateQtColor];
}
- (void)relayout
@@ -258,8 +274,7 @@ QT_USE_NAMESPACE
}
}
- if (mPriv)
- mPriv->setCurrentQColor(*mQtColor);
+ mPriv->setCurrentQColor(*mQtColor);
}
- (NSColorPanel *)colorPanel
@@ -274,36 +289,42 @@ QT_USE_NAMESPACE
- (void)finishOffWithCode:(NSInteger)code
{
- if (mPriv) {
- // Finish the QColorDialog as well. But since a call to accept or reject will
- // close down the QEventLoop found in QDialog, we need to make sure that the
- // current thread has exited the native dialogs modal session/run loop first.
- // We ensure this by posting the call:
+ mResultCode = code;
+ if (mDialogIsExecuting) {
+ // We stop the current modal event loop. The control
+ // will then return inside -(void)exec below.
+ // It's important that the modal event loop is stopped before
+ // we accept/reject QColorDialog, since QColorDialog has its
+ // own event loop that needs to be stopped last.
[NSApp stopModalWithCode:code];
- if (code == NSOKButton)
- QMetaObject::invokeMethod(mPriv->colorDialog(), "accept", Qt::QueuedConnection);
- else
- QMetaObject::invokeMethod(mPriv->colorDialog(), "reject", Qt::QueuedConnection);
} else {
- [NSApp stopModalWithCode:code];
+ // Since we are not in a modal event loop, we can safely close
+ // down QColorDialog
+ if (mResultCode == NSCancelButton)
+ mPriv->colorDialog()->reject();
+ else
+ mPriv->colorDialog()->accept();
}
}
-- (void)cleanUpAfterMyself
+- (void)showColorPanel
{
- if (mHackedPanel) {
- NSView *ourContentView = [mColorPanel contentView];
-
- // return stolen stuff to its rightful owner
- [mStolenContentView removeFromSuperview];
- [mColorPanel setContentView:mStolenContentView];
+ mDialogIsExecuting = false;
+ [mColorPanel makeKeyAndOrderFront:mColorPanel];
+}
- [mOkButton release];
- [mCancelButton release];
- [ourContentView release];
- }
- [mColorPanel setDelegate:nil];
+- (void)exec
+{
+ QBoolBlocker nativeDialogOnTop(QApplicationPrivate::native_modal_dialog_active);
+ QMacCocoaAutoReleasePool pool;
+ mDialogIsExecuting = true;
+ [NSApp runModalForWindow:mColorPanel];
+ if (mResultCode == NSCancelButton)
+ mPriv->colorDialog()->reject();
+ else
+ mPriv->colorDialog()->accept();
}
+
@end
QT_BEGIN_NAMESPACE
@@ -312,91 +333,90 @@ extern void macStartInterceptNSPanelCtor();
extern void macStopInterceptNSPanelCtor();
extern NSButton *macCreateButton(const char *text, NSView *superview);
-void *QColorDialogPrivate::openCocoaColorPanel(const QColor &initial,
- QWidget *parent, const QString &title, QColorDialog::ColorDialogOptions options,
- QColorDialogPrivate *priv)
+void QColorDialogPrivate::openCocoaColorPanel(const QColor &initial,
+ QWidget *parent, const QString &title, QColorDialog::ColorDialogOptions options)
{
Q_UNUSED(parent); // we would use the parent if only NSColorPanel could be a sheet
QMacCocoaAutoReleasePool pool;
- /*
- The standard Cocoa color panel has no OK or Cancel button and
- is created as a utility window, whereas we want something like
- the Carbon color panel. We need to take the following steps:
+ if (!delegate) {
+ /*
+ The standard Cocoa color panel has no OK or Cancel button and
+ is created as a utility window, whereas we want something like
+ the Carbon color panel. We need to take the following steps:
+
+ 1. Intercept the color panel constructor to turn off the
+ NSUtilityWindowMask flag. This is done by temporarily
+ replacing initWithContentRect:styleMask:backing:defer:
+ in NSPanel by our own method.
- 1. Intercept the color panel constructor to turn off the
- NSUtilityWindowMask flag. This is done by temporarily
- replacing initWithContentRect:styleMask:backing:defer:
- in NSPanel by our own method.
+ 2. Modify the color panel so that its content view is part
+ of a new content view that contains it as well as two
+ buttons (OK and Cancel).
- 2. Modify the color panel so that its content view is part
- of a new content view that contains it as well as two
- buttons (OK and Cancel).
+ 3. Lay out the original content view and the buttons when
+ the color panel is shown and whenever it is resized.
- 3. Lay out the original content view and the buttons when
- the color panel is shown and whenever it is resized.
+ 4. Clean up after ourselves.
+ */
- 4. Clean up after ourselves.
- */
+ bool hackColorPanel = !(options & QColorDialog::NoButtons);
- bool hackColorPanel = !(options & QColorDialog::NoButtons);
+ if (hackColorPanel)
+ macStartInterceptNSPanelCtor();
+ NSColorPanel *colorPanel = [NSColorPanel sharedColorPanel];
+ if (hackColorPanel)
+ macStopInterceptNSPanelCtor();
- if (hackColorPanel)
- macStartInterceptNSPanelCtor();
- NSColorPanel *colorPanel = [NSColorPanel sharedColorPanel];
- if (hackColorPanel)
- macStopInterceptNSPanelCtor();
+ [colorPanel setHidesOnDeactivate:false];
- [colorPanel setHidesOnDeactivate:false];
+ // set up the Cocoa color panel
+ [colorPanel setShowsAlpha:options & QColorDialog::ShowAlphaChannel];
+ [colorPanel setTitle:(NSString*)(CFStringRef)QCFString(title)];
- // set up the Cocoa color panel
- [colorPanel setShowsAlpha:options & QColorDialog::ShowAlphaChannel];
- [colorPanel setTitle:(NSString*)(CFStringRef)QCFString(title)];
+ NSView *stolenContentView = 0;
+ NSButton *okButton = 0;
+ NSButton *cancelButton = 0;
- NSView *stolenContentView = 0;
- NSButton *okButton = 0;
- NSButton *cancelButton = 0;
+ if (hackColorPanel) {
+ // steal the color panel's contents view
+ stolenContentView = [colorPanel contentView];
+ [stolenContentView retain];
+ [colorPanel setContentView:0];
- if (hackColorPanel) {
- // steal the color panel's contents view
- stolenContentView = [colorPanel contentView];
- [stolenContentView retain];
- [colorPanel setContentView:0];
+ // create a new content view and add the stolen one as a subview
+ NSRect frameRect = { { 0.0, 0.0 }, { 0.0, 0.0 } };
+ NSView *ourContentView = [[NSView alloc] initWithFrame:frameRect];
+ [ourContentView addSubview:stolenContentView];
- // create a new content view and add the stolen one as a subview
- NSRect frameRect = { { 0.0, 0.0 }, { 0.0, 0.0 } };
- NSView *ourContentView = [[NSView alloc] initWithFrame:frameRect];
- [ourContentView addSubview:stolenContentView];
+ // create OK and Cancel buttons and add these as subviews
+ okButton = macCreateButton("&OK", ourContentView);
+ cancelButton = macCreateButton("Cancel", ourContentView);
- // create OK and Cancel buttons and add these as subviews
- okButton = macCreateButton("&OK", ourContentView);
- cancelButton = macCreateButton("Cancel", ourContentView);
+ [colorPanel setContentView:ourContentView];
+ [colorPanel setDefaultButtonCell:[okButton cell]];
+ }
- [colorPanel setContentView:ourContentView];
- [colorPanel setDefaultButtonCell:[okButton cell]];
+ delegate = [[QCocoaColorPanelDelegate alloc] initWithColorPanel:colorPanel
+ stolenContentView:stolenContentView
+ okButton:okButton
+ cancelButton:cancelButton
+ priv:this];
+ [colorPanel setDelegate:static_cast<QCocoaColorPanelDelegate *>(delegate)];
}
- // create a delegate and set it
- QCocoaColorPanelDelegate *delegate =
- [[QCocoaColorPanelDelegate alloc] initWithColorPanel:colorPanel
- stolenContentView:stolenContentView
- okButton:okButton
- cancelButton:cancelButton
- priv:priv];
- [colorPanel setDelegate:delegate];
- setColor(delegate, initial);
- [colorPanel makeKeyAndOrderFront:colorPanel];
-
- return delegate;
+ setCocoaPanelColor(initial);
+ [static_cast<QCocoaColorPanelDelegate *>(delegate) showColorPanel];
}
-void QColorDialogPrivate::closeCocoaColorPanel(void *delegate)
+void QColorDialogPrivate::closeCocoaColorPanel()
{
- QMacCocoaAutoReleasePool pool;
- QCocoaColorPanelDelegate *theDelegate = static_cast<QCocoaColorPanelDelegate *>(delegate);
- [[theDelegate colorPanel] close];
- [theDelegate cleanUpAfterMyself];
- [theDelegate autorelease];
+ [[static_cast<QCocoaColorPanelDelegate *>(delegate) colorPanel] close];
+}
+
+void QColorDialogPrivate::releaseCocoaColorPanelDelegate()
+{
+ [static_cast<QCocoaColorPanelDelegate *>(delegate) release];
}
void QColorDialogPrivate::mac_nativeDialogModalHelp()
@@ -416,13 +436,10 @@ void QColorDialogPrivate::mac_nativeDialogModalHelp()
void QColorDialogPrivate::_q_macRunNativeAppModalPanel()
{
- QBoolBlocker nativeDialogOnTop(QApplicationPrivate::native_modal_dialog_active);
- QMacCocoaAutoReleasePool pool;
- QCocoaColorPanelDelegate *delegateCasted = static_cast<QCocoaColorPanelDelegate *>(delegate);
- [NSApp runModalForWindow:[delegateCasted colorPanel]];
+ [static_cast<QCocoaColorPanelDelegate *>(delegate) exec];
}
-void QColorDialogPrivate::setColor(void *delegate, const QColor &color)
+void QColorDialogPrivate::setCocoaPanelColor(const QColor &color)
{
QMacCocoaAutoReleasePool pool;
QCocoaColorPanelDelegate *theDelegate = static_cast<QCocoaColorPanelDelegate *>(delegate);
diff --git a/src/gui/dialogs/qcolordialog_p.h b/src/gui/dialogs/qcolordialog_p.h
index ea66d4a..00d40b6 100644
--- a/src/gui/dialogs/qcolordialog_p.h
+++ b/src/gui/dialogs/qcolordialog_p.h
@@ -116,14 +116,11 @@ public:
QByteArray memberToDisconnectOnClose;
#ifdef Q_WS_MAC
- static void *openCocoaColorPanel(const QColor &initial,
- QWidget *parent, const QString &title,
- QColorDialog::ColorDialogOptions options,
- QColorDialogPrivate *priv = 0);
- static void closeCocoaColorPanel(void *delegate);
- static QColor execCocoaColorPanel(const QColor &initial, QWidget *parent,
- const QString &title, QColorDialog::ColorDialogOptions options);
- static void setColor(void *delegate, const QColor &color);
+ void openCocoaColorPanel(const QColor &initial,
+ QWidget *parent, const QString &title, QColorDialog::ColorDialogOptions options);
+ void closeCocoaColorPanel();
+ void releaseCocoaColorPanelDelegate();
+ void setCocoaPanelColor(const QColor &color);
inline void done(int result) { q_func()->done(result); }
inline QColorDialog *colorDialog() { return q_func(); }
diff --git a/src/gui/dialogs/qfiledialog.cpp b/src/gui/dialogs/qfiledialog.cpp
index 8b4e1b1..f000033 100644
--- a/src/gui/dialogs/qfiledialog.cpp
+++ b/src/gui/dialogs/qfiledialog.cpp
@@ -394,6 +394,9 @@ QList<QUrl> QFileDialog::sidebarUrls() const
static const qint32 QFileDialogMagic = 0xbe;
+const char *qt_file_dialog_filter_reg_exp =
+"^(.*)\\(([a-zA-Z0-9_.*? +;#\\-\\[\\]@\\{\\}/!<>\\$%&=^~:\\|]*)\\)$";
+
/*!
\since 4.3
Saves the state of the dialog's layout, history and current directory.
@@ -984,8 +987,13 @@ void QFileDialog::setNameFilters(const QStringList &filters)
if (testOption(HideNameFilterDetails)) {
QStringList strippedFilters;
+ QRegExp r(QString::fromLatin1(qt_file_dialog_filter_reg_exp));
for (int i = 0; i < cleanedFilters.count(); ++i) {
- strippedFilters.append(cleanedFilters[i].mid(0, cleanedFilters[i].indexOf(QLatin1String(" ("))));
+ QString filterName;
+ int index = r.indexIn(cleanedFilters[i]);
+ if (index >= 0)
+ filterName = r.cap(1);
+ strippedFilters.append(filterName.simplified());
}
d->qFileDialogUi->fileTypeCombo->addItems(strippedFilters);
} else {
@@ -2837,9 +2845,6 @@ void QFileDialogPrivate::_q_goToDirectory(const QString &path)
}
}
-const char *qt_file_dialog_filter_reg_exp =
- "^([^()]*)\\(([a-zA-Z0-9_.*? +;#\\-\\[\\]@\\{\\}/!<>\\$%&=^~:\\|]*)\\)$";
-
// Makes a list of filters from a normal filter string "Image Files (*.png *.jpg)"
QStringList qt_clean_filter_list(const QString &filter)
{
diff --git a/src/gui/dialogs/qfiledialog_win.cpp b/src/gui/dialogs/qfiledialog_win.cpp
index 9bf82c3..02469b2 100644
--- a/src/gui/dialogs/qfiledialog_win.cpp
+++ b/src/gui/dialogs/qfiledialog_win.cpp
@@ -59,7 +59,9 @@
#endif
#include <shlobj.h>
-
+#if !defined(Q_WS_WINCE)
+#include <shobjidl.h>
+#endif
#include <objbase.h>
#if defined(__IFileDialog_INTERFACE_DEFINED__) \
@@ -441,6 +443,8 @@ static bool qt_win_set_IFileDialogOptions(IFileDialog *pfd,
QString subfilter = *it;
if (!subfilter.isEmpty()) {
offsets<<currentOffset;
+ //Here the COMMON_ITEM_DIALOG API always add the details for the filter (e.g. *.txt)
+ //so we don't need to handle the flag HideNameFilterDetails.
winfilters += subfilter; // The name of the filter.
winfilters += QChar();
currentOffset += subfilter.size()+1;
diff --git a/src/gui/dialogs/qfilesystemmodel.cpp b/src/gui/dialogs/qfilesystemmodel.cpp
index 5a5d845..b8e12b4 100644
--- a/src/gui/dialogs/qfilesystemmodel.cpp
+++ b/src/gui/dialogs/qfilesystemmodel.cpp
@@ -872,6 +872,7 @@ QVariant QFileSystemModel::headerData(int section, Qt::Orientation orientation,
pixmap.setAlphaChannel(pixmap.createAlphaMask());
return pixmap;
}
+ break;
case Qt::TextAlignmentRole:
return Qt::AlignLeft;
}
diff --git a/src/gui/egl/qegl.cpp b/src/gui/egl/qegl.cpp
index 89d9d1b..ebdac9a 100644
--- a/src/gui/egl/qegl.cpp
+++ b/src/gui/egl/qegl.cpp
@@ -400,4 +400,15 @@ void QEglContext::dumpAllConfigs()
delete [] configs;
}
+QString QEglContext::extensions()
+{
+ const char* exts = eglQueryString(dpy, EGL_EXTENSIONS);
+ return QString(QLatin1String(exts));
+}
+
+bool QEglContext::hasExtension(const char* extensionName)
+{
+ return extensions().contains(QLatin1String(extensionName));
+}
+
QT_END_NAMESPACE
diff --git a/src/gui/egl/qegl_p.h b/src/gui/egl/qegl_p.h
index ddf7d27..3ae1489 100644
--- a/src/gui/egl/qegl_p.h
+++ b/src/gui/egl/qegl_p.h
@@ -122,6 +122,9 @@ public:
void dumpAllConfigs();
+ QString extensions();
+ bool hasExtension(const char* extensionName);
+
private:
QEgl::API apiType;
EGLDisplay dpy;
diff --git a/src/gui/egl/qegl_x11.cpp b/src/gui/egl/qegl_x11.cpp
index be89efe..6772592 100644
--- a/src/gui/egl/qegl_x11.cpp
+++ b/src/gui/egl/qegl_x11.cpp
@@ -39,15 +39,18 @@
**
****************************************************************************/
+#include <QtCore/qdebug.h>
+
+#include <private/qt_x11_p.h>
+#include <QtGui/qx11info_x11.h>
+#include <private/qpixmapdata_p.h>
+#include <private/qpixmap_x11_p.h>
+
#include <QtGui/qpaintdevice.h>
#include <QtGui/qpixmap.h>
#include <QtGui/qwidget.h>
-#include <QtCore/qdebug.h>
#include "qegl_p.h"
-#include <QtGui/qx11info_x11.h>
-#include <X11/Xlib.h>
-#include <X11/Xutil.h>
QT_BEGIN_NAMESPACE
@@ -125,7 +128,17 @@ void QEglProperties::setVisualFormat(const QX11Info *xinfo)
setValue(EGL_RED_SIZE, countBits(visual->red_mask));
setValue(EGL_GREEN_SIZE, countBits(visual->green_mask));
setValue(EGL_BLUE_SIZE, countBits(visual->blue_mask));
- setValue(EGL_ALPHA_SIZE, 0); // XXX
+
+ EGLint alphaBits = 0;
+#if !defined(QT_NO_XRENDER)
+ XRenderPictFormat *format;
+ format = XRenderFindVisualFormat(xinfo->display(), visual);
+ if (format && (format->type == PictTypeDirect) && format->direct.alphaMask) {
+ alphaBits = countBits(format->direct.alphaMask);
+ qDebug("QEglProperties::setVisualFormat() - visual's alphaMask is %d", alphaBits);
+ }
+#endif
+ setValue(EGL_ALPHA_SIZE, alphaBits);
}
extern const QX11Info *qt_x11Info(const QPaintDevice *pd);
diff --git a/src/gui/egl/qeglproperties.cpp b/src/gui/egl/qeglproperties.cpp
index e0ae8a6..358ebcc 100644
--- a/src/gui/egl/qeglproperties.cpp
+++ b/src/gui/egl/qeglproperties.cpp
@@ -46,12 +46,26 @@ QT_BEGIN_NAMESPACE
#include <QtCore/qdebug.h>
#include <QtCore/qstringlist.h>
+#include "qegl_p.h"
+
+
// Initialize a property block.
QEglProperties::QEglProperties()
{
props.append(EGL_NONE);
}
+QEglProperties::QEglProperties(EGLConfig cfg)
+{
+ props.append(EGL_NONE);
+ for (int name = 0x3020; name <= 0x304F; ++name) {
+ EGLint value;
+ if (name != EGL_NONE && eglGetConfigAttrib(QEglContext::defaultDisplay(0), cfg, name, &value))
+ setValue(name, value);
+ }
+ eglGetError(); // Clear the error state.
+}
+
// Fetch the current value associated with a property.
int QEglProperties::value(int name) const
{
@@ -215,12 +229,21 @@ bool QEglProperties::reduceConfiguration()
removeValue(EGL_SAMPLES);
return true;
}
- if (removeValue(EGL_ALPHA_SIZE))
+ if (removeValue(EGL_ALPHA_SIZE)) {
+#if defined(EGL_BIND_TO_TEXTURE_RGBA) && defined(EGL_BIND_TO_TEXTURE_RGB)
+ if (removeValue(EGL_BIND_TO_TEXTURE_RGBA))
+ setValue(EGL_BIND_TO_TEXTURE_RGB, TRUE);
+#endif
return true;
+ }
if (removeValue(EGL_STENCIL_SIZE))
return true;
if (removeValue(EGL_DEPTH_SIZE))
return true;
+#if defined(EGL_BIND_TO_TEXTURE_RGB)
+ if (removeValue(EGL_BIND_TO_TEXTURE_RGB))
+ return true;
+#endif
return false;
}
diff --git a/src/gui/egl/qeglproperties_p.h b/src/gui/egl/qeglproperties_p.h
index 81af4cd..bcdc657 100644
--- a/src/gui/egl/qeglproperties_p.h
+++ b/src/gui/egl/qeglproperties_p.h
@@ -107,6 +107,7 @@ class Q_GUI_EXPORT QEglProperties
{
public:
QEglProperties();
+ QEglProperties(EGLConfig);
QEglProperties(const QEglProperties& other) : props(other.props) {}
~QEglProperties() {}
diff --git a/src/gui/embedded/qkbdqnx_qws.cpp b/src/gui/embedded/qkbdqnx_qws.cpp
index 06163c7..089b868 100644
--- a/src/gui/embedded/qkbdqnx_qws.cpp
+++ b/src/gui/embedded/qkbdqnx_qws.cpp
@@ -6,11 +6,11 @@
** This file is part of the QtGui module of the Qt Toolkit.
**
** $QT_BEGIN_LICENSE:LGPL$
-** Commercial Usage
-** Licensees holding valid Qt Commercial licenses may use this file in
-** accordance with the Qt Commercial License Agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and Nokia.
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the either Technology Preview License Agreement or the
+** Beta Release License Agreement.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
diff --git a/src/gui/embedded/qkbdqnx_qws.h b/src/gui/embedded/qkbdqnx_qws.h
index c046c8d..fa3ae56 100644
--- a/src/gui/embedded/qkbdqnx_qws.h
+++ b/src/gui/embedded/qkbdqnx_qws.h
@@ -6,11 +6,11 @@
** This file is part of the QtGui module of the Qt Toolkit.
**
** $QT_BEGIN_LICENSE:LGPL$
-** Commercial Usage
-** Licensees holding valid Qt Commercial licenses may use this file in
-** accordance with the Qt Commercial License Agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and Nokia.
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the either Technology Preview License Agreement or the
+** Beta Release License Agreement.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
diff --git a/src/gui/embedded/qmouseqnx_qws.cpp b/src/gui/embedded/qmouseqnx_qws.cpp
index 98f8f06..59cd5be 100644
--- a/src/gui/embedded/qmouseqnx_qws.cpp
+++ b/src/gui/embedded/qmouseqnx_qws.cpp
@@ -6,11 +6,11 @@
** This file is part of the QtGui module of the Qt Toolkit.
**
** $QT_BEGIN_LICENSE:LGPL$
-** Commercial Usage
-** Licensees holding valid Qt Commercial licenses may use this file in
-** accordance with the Qt Commercial License Agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and Nokia.
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the either Technology Preview License Agreement or the
+** Beta Release License Agreement.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
diff --git a/src/gui/embedded/qmouseqnx_qws.h b/src/gui/embedded/qmouseqnx_qws.h
index a61562e..f8cad4a 100644
--- a/src/gui/embedded/qmouseqnx_qws.h
+++ b/src/gui/embedded/qmouseqnx_qws.h
@@ -6,11 +6,11 @@
** This file is part of the QtGui module of the Qt Toolkit.
**
** $QT_BEGIN_LICENSE:LGPL$
-** Commercial Usage
-** Licensees holding valid Qt Commercial licenses may use this file in
-** accordance with the Qt Commercial License Agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and Nokia.
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the either Technology Preview License Agreement or the
+** Beta Release License Agreement.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
diff --git a/src/gui/embedded/qscreenqnx_qws.cpp b/src/gui/embedded/qscreenqnx_qws.cpp
index 7101bc7..c79ee59 100644
--- a/src/gui/embedded/qscreenqnx_qws.cpp
+++ b/src/gui/embedded/qscreenqnx_qws.cpp
@@ -6,11 +6,11 @@
** This file is part of the QtGui module of the Qt Toolkit.
**
** $QT_BEGIN_LICENSE:LGPL$
-** Commercial Usage
-** Licensees holding valid Qt Commercial licenses may use this file in
-** accordance with the Qt Commercial License Agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and Nokia.
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the either Technology Preview License Agreement or the
+** Beta Release License Agreement.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
diff --git a/src/gui/embedded/qscreenqnx_qws.h b/src/gui/embedded/qscreenqnx_qws.h
index 837c061..30312fe 100644
--- a/src/gui/embedded/qscreenqnx_qws.h
+++ b/src/gui/embedded/qscreenqnx_qws.h
@@ -6,11 +6,11 @@
** This file is part of the QtGui module of the Qt Toolkit.
**
** $QT_BEGIN_LICENSE:LGPL$
-** Commercial Usage
-** Licensees holding valid Qt Commercial licenses may use this file in
-** accordance with the Qt Commercial License Agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and Nokia.
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the either Technology Preview License Agreement or the
+** Beta Release License Agreement.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
diff --git a/src/gui/graphicsview/qgraphicsitem.cpp b/src/gui/graphicsview/qgraphicsitem.cpp
index 5aae93e..beaf42b 100644
--- a/src/gui/graphicsview/qgraphicsitem.cpp
+++ b/src/gui/graphicsview/qgraphicsitem.cpp
@@ -135,38 +135,39 @@
\section1 Transformation
- QGraphicsItem supports affine transformations in addition to its base
- position, pos(). To change the item's transformation, you can pass
- a transformation matrix to setTransform()
-
- Item transformations accumulate from parent to child, so if both a
- parent and child item are rotated 90 degrees, the child's total
- transformation will be 180 degrees. Similarly, if the item's
- parent is scaled to 2x its original size, its children will also
- be twice as large. An item's transformation does not affect its
- own local geometry; all geometry functions (e.g., contains(),
- update(), and all the mapping functions) still operate in local
- coordinates. For convenience, QGraphicsItem provides the functions
- sceneTransform(), which returns the item's total transformation
+ QGraphicsItem supports projective transformations in addition to its base
+ position, pos(). There are several ways to change an item's transformation.
+ For simple transformations, you can call either of the convenience
+ functions setRotation() or setScale(), or you can pass any transformation
+ matrix to setTransform(). For advanced transformation control you also have
+ the option of setting several combined transformations by calling
+ setTransformations().
+
+ Item transformations accumulate from parent to child, so if both a parent
+ and child item are rotated 90 degrees, the child's total transformation
+ will be 180 degrees. Similarly, if the item's parent is scaled to 2x its
+ original size, its children will also be twice as large. An item's
+ transformation does not affect its own local geometry; all geometry
+ functions (e.g., contains(), update(), and all the mapping functions) still
+ operate in local coordinates. For convenience, QGraphicsItem provides the
+ functions sceneTransform(), which returns the item's total transformation
matrix (including its position and all parents' positions and
- transformations), and scenePos(), which returns its position in
- scene coordinates. To reset an item's matrix, call
- resetTransform().
+ transformations), and scenePos(), which returns its position in scene
+ coordinates. To reset an item's matrix, call resetTransform().
- Another way to apply transformation to an item is to use the , or
- set the different transformation properties (transformOrigin,
- x/y/zRotation, x/yScale, horizontal/verticalShear). Those
- properties come in addition to the base transformation
+ Certain transformation operations produce a different outcome depending on
+ the order in which they are applied. For example, if you scale an
+ transform, and then rotate it, you may get a different result than if the
+ transform was rotated first. However, the order you set the transformation
+ properties on QGraphicsItem does not affect the resulting transformation;
+ QGraphicsItem always applies the properties in a fixed, defined order:
- The order you set the transformation properties does not affect
- the resulting transformation The resulting transformation is
- always computed in the following order
-
- \code
- [Origin] [Base] [RotateX] [RotateY] [RotateZ] [Shear] [Scale] [-Origin]
- \endcode
-
- Where [Base] is the stransformation set by setTransform
+ \list
+ \o The item's base transform is applied (transform())
+ \o The item's transformations list is applied in order (transformations())
+ \o The item is rotated relative to its transform origin point (rotation(), transformOriginPoint())
+ \o The item is scaled relative to its transform origin point (scale(), transformOriginPoint())
+ \endlist
\section1 Painting
@@ -674,19 +675,22 @@ void QGraphicsItemPrivate::updateAncestorFlag(QGraphicsItem::GraphicsItemFlag ch
return;
}
- // Inherit the enabled-state from our parents.
- if ((parent && ((parent->d_ptr->ancestorFlags & flag)
- || (int(parent->d_ptr->flags & childFlag) == childFlag)
+ if (parent) {
+ // Inherit the enabled-state from our parents.
+ if ((parent->d_ptr->ancestorFlags & flag)
+ || (int(parent->d_ptr->flags & childFlag) == childFlag)
|| (childFlag == -1 && parent->d_ptr->handlesChildEvents)
- || (childFlag == -2 && parent->d_ptr->filtersDescendantEvents)))) {
- enabled = true;
- ancestorFlags |= flag;
- }
-
- // Top-level root items don't have any ancestors, so there are no
- // ancestor flags either.
- if (!parent)
+ || (childFlag == -2 && parent->d_ptr->filtersDescendantEvents)) {
+ enabled = true;
+ ancestorFlags |= flag;
+ } else {
+ ancestorFlags &= ~flag;
+ }
+ } else {
+ // Top-level root items don't have any ancestors, so there are no
+ // ancestor flags either.
ancestorFlags = 0;
+ }
} else {
// Don't set or propagate the ancestor flag if it's already correct.
if (((ancestorFlags & flag) && enabled) || (!(ancestorFlags & flag) && !enabled))
@@ -2969,11 +2973,10 @@ QMatrix QGraphicsItem::matrix() const
Returns this item's transformation matrix.
- Either the one set by setTransform, or the resulting transformation from
- all the transfmation properties
-
- If no matrix or transformation property has been set, the
- identity matrix is returned.
+ The transformation matrix is combined with the item's rotation(), scale()
+ and transformations() into a combined transformations for the item.
+
+ The default transformation matrix is an identity matrix.
\sa setTransform(), sceneTransform()
*/
@@ -2987,13 +2990,13 @@ QTransform QGraphicsItem::transform() const
/*!
\since 4.6
- Returns the rotation around the Z axis.
-
- The default is 0
+ Returns the clockwise rotation, in degrees, around the Z axis. The default
+ value is 0 (i.e., the item is not rotated).
- \warning The value doesn't take in account any rotation set with the setTransform() method.
+ The rotation is combined with the item's scale(), transform() and
+ transformations() to map the item's coordinate system to the parent item.
- \sa setRotation(), {Transformations}
+ \sa setRotation(), transformOriginPoint(), {Transformations}
*/
qreal QGraphicsItem::rotation() const
{
@@ -3005,9 +3008,19 @@ qreal QGraphicsItem::rotation() const
/*!
\since 4.6
- Sets the rotation around the Z axis to \a angle degrees.
+ Sets the clockwise rotation \a angle, in degrees, around the Z axis. The
+ default value is 0 (i.e., the item is not rotated). Assigning a negative
+ value will rotate the item counter-clockwise. Normally the rotation angle
+ is in the range (-360, 360), but it's also possible to assign values
+ outside of this range (e.g., a rotation of 370 degrees is the same as a
+ rotation of 10 degrees).
- \warning The value doesn't take in account any rotation set with the setTransform() method.
+ The item is rotated around its transform origin point, which by default
+ is (0, 0). You can select a different transformation origin by calling
+ setTransformOriginPoint().
+
+ The rotation is combined with the item's scale(), transform() and
+ transformations() to map the item's coordinate system to the parent item.
\sa rotation(), setTransformOriginPoint(), {Transformations}
*/
@@ -3027,13 +3040,13 @@ void QGraphicsItem::setRotation(qreal angle)
/*!
\since 4.6
- Returns the scale factor of the item.
-
- The default is 1
+ Returns the scale factor of the item. The default scale factor is 1.0
+ (i.e., the item is not scaled).
- \warning The value doesn't take in account any scaling set with the setTransform() method.
+ The scale is combined with the item's rotation(), transform() and
+ transformations() to map the item's coordinate system to the parent item.
- \sa setScale(), {Transformations}
+ \sa setScale(), rotation(), {Transformations}
*/
qreal QGraphicsItem::scale() const
{
@@ -3045,9 +3058,17 @@ qreal QGraphicsItem::scale() const
/*!
\since 4.6
- Sets the scale factor of the item to \a factor.
+ Sets the scale \a factor of the item. The default scale factor is 1.0
+ (i.e., the item is not scaled). A scale factor of 0.0 will collapse the
+ item to a single point. If you provide a negative scale factor, the
+ item will be flipped and mirrored (i.e., rotated 180 degrees).
- \warning The value doesn't take in account any scaling set with the setTransform() method.
+ The item is scaled around its transform origin point, which by default
+ is (0, 0). You can select a different transformation origin by calling
+ setTransformOriginPoint().
+
+ The scale is combined with the item's rotation(), transform() and
+ transformations() to map the item's coordinate system to the parent item.
\sa scale(), setTransformOriginPoint(), {Transformations}
*/
@@ -3068,9 +3089,17 @@ void QGraphicsItem::setScale(qreal factor)
/*!
\since 4.6
- returns list of graphics transformations on the item.
+ Returns a list of graphics transforms that currently apply to this item.
- \sa scale(), setTransformOriginPoint(), {Transformations}
+ QGraphicsTransform is for applying and controlling a chain of individual
+ transformation operations on an item. It's particularily useful in
+ animations, where each transform operation needs to be interpolated
+ independently, or differently.
+
+ The transformations are combined with the item's rotation(), scale() and
+ transform() to map the item's coordinate system to the parent item.
+
+ \sa scale(), rotation(), transformOriginPoint(), {Transformations}
*/
QList<QGraphicsTransform *> QGraphicsItem::transformations() const
{
@@ -3082,7 +3111,20 @@ QList<QGraphicsTransform *> QGraphicsItem::transformations() const
/*!
\since 4.6
- Sets a list of graphics transformations on the item to \a transformations.
+ Sets a list of graphics \a transformations (QGraphicsTransform) that
+ currently apply to this item.
+
+ If all you want is to rotate or scale an item, you should call setRotation()
+ or setScale() instead. If you want to set an arbitrary transformation on
+ an item, you can call setTransform().
+
+ QGraphicsTransform is for applying and controlling a chain of individual
+ transformation operations on an item. It's particularily useful in
+ animations, where each transform operation needs to be interpolated
+ independently, or differently.
+
+ The transformations are combined with the item's rotation(), scale() and
+ transform() to map the item's coordinate system to the parent item.
\sa scale(), setTransformOriginPoint(), {Transformations}
*/
@@ -3098,7 +3140,9 @@ void QGraphicsItem::setTransformations(const QList<QGraphicsTransform *> &transf
d_ptr->dirtySceneTransform = 1;
}
-
+/*!
+ \internal
+*/
void QGraphicsItemPrivate::appendGraphicsTransform(QGraphicsTransform *t)
{
if (!transformData)
@@ -3432,7 +3476,9 @@ void QGraphicsItem::setMatrix(const QMatrix &matrix, bool combine)
to map an item coordiate to a scene coordinate, or mapFromScene() to map
from scene coordinates to item coordinates.
- \warning using this function doesnt affect the value of the transformation properties
+ The transformation matrix is combined with the item's rotation(), scale()
+ and transformations() into a combined transformation that maps the item's
+ coordinate system to its parent.
\sa transform(), setRotation(), setScale(), setTransformOriginPoint(), {The Graphics View Coordinate System}, {Transformations}
*/
@@ -3491,7 +3537,14 @@ void QGraphicsItem::resetTransform()
/*!
\obsolete
- Use setZRotation() instead
+
+ Use
+
+ \code
+ setRotation(rotation() + angle);
+ \endcode
+
+ instead.
Rotates the current item transformation \a angle degrees clockwise around
its origin. To translate around an arbitrary point (x, y), you need to
@@ -3501,8 +3554,6 @@ void QGraphicsItem::resetTransform()
\snippet doc/src/snippets/code/src_gui_graphicsview_qgraphicsitem.cpp 6
- \warning using this functionhas no effect on the zRotation value
-
\sa setTransform(), transform(), scale(), shear(), translate()
*/
void QGraphicsItem::rotate(qreal angle)
@@ -3512,7 +3563,14 @@ void QGraphicsItem::rotate(qreal angle)
/*!
\obsolete
- Use setScale() instead
+
+ Use
+
+ \code
+ setTransform(QTransform::fromScale(sx, sy), true);
+ \endcode
+
+ instead.
Scales the current item transformation by (\a sx, \a sy) around its
origin. To scale from an arbitrary point (x, y), you need to combine
@@ -3522,8 +3580,6 @@ void QGraphicsItem::rotate(qreal angle)
\snippet doc/src/snippets/code/src_gui_graphicsview_qgraphicsitem.cpp 7
- \warning using this function has no effect on the xScale or yScale value
-
\sa setTransform(), transform()
*/
void QGraphicsItem::scale(qreal sx, qreal sy)
@@ -3533,11 +3589,16 @@ void QGraphicsItem::scale(qreal sx, qreal sy)
/*!
\obsolete
- Use setShear instead.
- Shears the current item transformation by (\a sh, \a sv).
+ Use
- \warning using this function has no effect on the horizontalShear or verticalShear value
+ \code
+ setTransform(QTransform().shear(sh, sv), true);
+ \endcode
+
+ instead.
+
+ Shears the current item transformation by (\a sh, \a sv).
\sa setTransform(), transform()
*/
@@ -3548,7 +3609,13 @@ void QGraphicsItem::shear(qreal sh, qreal sv)
/*!
\obsolete
- Use setPos() or setTransformOriginPoint() instead.
+
+ Use setPos() or setTransformOriginPoint() instead. For identical
+ behavior, use
+
+ \code
+ setTransform(QTransform::fromTranslate(dx, dy), true);
+ \endcode
Translates the current item transformation by (\a dx, \a dy).
@@ -6320,7 +6387,7 @@ void QGraphicsItem::inputMethodEvent(QInputMethodEvent *event)
surrounding text and reconversions. \a query specifies which
property is queried.
- \sa inputMethodEvent()
+ \sa inputMethodEvent(), QInputMethodEvent, QInputContext
*/
QVariant QGraphicsItem::inputMethodQuery(Qt::InputMethodQuery query) const
{
@@ -6336,6 +6403,39 @@ QVariant QGraphicsItem::inputMethodQuery(Qt::InputMethodQuery query) const
}
/*!
+ Returns the current input method hints of this item.
+
+ Input method hints are only relevant for input items.
+ The hints are used by the input method to indicate how it should operate.
+ For example, if the Qt::ImhNumbersOnly flag is set, the input method may change
+ its visual components to reflect that only numbers can be entered.
+
+ The effect may vary between input method implementations.
+
+ \since 4.6
+
+ \sa setInputMethodHints(), inputMethodQuery(), QInputContext
+*/
+Qt::InputMethodHints QGraphicsItem::inputMethodHints() const
+{
+ Q_D(const QGraphicsItem);
+ return d->imHints;
+}
+
+/*!
+ Sets the current input method hints of this item to \a hints.
+
+ \since 4.6
+
+ \sa inputMethodHints(), inputMethodQuery(), QInputContext
+*/
+void QGraphicsItem::setInputMethodHints(Qt::InputMethodHints hints)
+{
+ Q_D(QGraphicsItem);
+ d->imHints = hints;
+}
+
+/*!
This virtual function is called by QGraphicsItem to notify custom items
that some part of the item's state changes. By reimplementing this
function, your can react to a change, and in some cases, (depending on \a
@@ -6462,7 +6562,7 @@ void QGraphicsItem::prepareGeometryChange()
// if someone is connected to the changed signal or the scene has no views.
// Note that this has to be done *after* markDirty to ensure that
// _q_processDirtyItems is called before _q_emitUpdated.
- if ((scenePrivate->connectedSignals & scenePrivate->changedSignalMask)
+ if ((scenePrivate->connectedSignals[0] & scenePrivate->changedSignalMask)
|| scenePrivate->views.isEmpty()) {
if (d_ptr->hasTranslateOnlySceneTransform()) {
d_ptr->scene->update(boundingRect().translated(d_ptr->sceneTransform.dx(),
diff --git a/src/gui/graphicsview/qgraphicsitem.h b/src/gui/graphicsview/qgraphicsitem.h
index b94fb97..f142b0f 100644
--- a/src/gui/graphicsview/qgraphicsitem.h
+++ b/src/gui/graphicsview/qgraphicsitem.h
@@ -375,6 +375,9 @@ public:
QVariant data(int key) const;
void setData(int key, const QVariant &value);
+ Qt::InputMethodHints inputMethodHints() const;
+ void setInputMethodHints(Qt::InputMethodHints hints);
+
enum {
Type = 1,
UserType = 65536
diff --git a/src/gui/graphicsview/qgraphicsitem_p.h b/src/gui/graphicsview/qgraphicsitem_p.h
index b8d98c1..805b554 100644
--- a/src/gui/graphicsview/qgraphicsitem_p.h
+++ b/src/gui/graphicsview/qgraphicsitem_p.h
@@ -126,6 +126,7 @@ public:
depth(0),
focusProxy(0),
subFocusItem(0),
+ imHints(Qt::ImhNone),
acceptedMouseButtons(0x1f),
visible(1),
explicitlyHidden(0),
@@ -419,8 +420,9 @@ public:
int depth;
QGraphicsItem *focusProxy;
QGraphicsItem *subFocusItem;
+ Qt::InputMethodHints imHints;
- // Packed 32 bytes
+ // Packed 32 bits
quint32 acceptedMouseButtons : 5;
quint32 visible : 1;
quint32 explicitlyHidden : 1;
@@ -468,7 +470,8 @@ public:
QGraphicsItem *q_ptr;
};
-struct QGraphicsItemPrivate::TransformData {
+struct QGraphicsItemPrivate::TransformData
+{
QTransform transform;
qreal scale;
qreal rotation;
@@ -481,7 +484,7 @@ struct QGraphicsItemPrivate::TransformData {
scale(1.0), rotation(0.0),
xOrigin(0.0), yOrigin(0.0),
onlyTransform(true)
- {}
+ { }
QTransform computedFullTransform(QTransform *postmultiplyTransform = 0) const
{
diff --git a/src/gui/graphicsview/qgraphicsscene.cpp b/src/gui/graphicsview/qgraphicsscene.cpp
index a846cf6..da4a347 100644
--- a/src/gui/graphicsview/qgraphicsscene.cpp
+++ b/src/gui/graphicsview/qgraphicsscene.cpp
@@ -344,7 +344,7 @@ void QGraphicsScenePrivate::_q_emitUpdated()
// the optimization that items send updates directly to the views, but it
// needs to happen in order to keep compatibility with the behavior from
// Qt 4.4 and backward.
- if (connectedSignals & changedSignalMask) {
+ if (connectedSignals[0] & changedSignalMask) {
for (int i = 0; i < views.size(); ++i) {
QGraphicsView *view = views.at(i);
if (!view->d_func()->connectedToScene) {
@@ -2899,7 +2899,7 @@ void QGraphicsScene::update(const QRectF &rect)
// Check if anyone's connected; if not, we can send updates directly to
// the views. Otherwise or if there are no views, use old behavior.
- bool directUpdates = !(d->connectedSignals & d->changedSignalMask) && !d->views.isEmpty();
+ bool directUpdates = !(d->connectedSignals[0] & d->changedSignalMask) && !d->views.isEmpty();
if (rect.isNull()) {
d->updateAll = true;
d->updatedRects.clear();
@@ -4477,7 +4477,7 @@ void QGraphicsScenePrivate::markDirty(QGraphicsItem *item, const QRectF &rect, b
if (removingItemFromScene) {
// Note that this function can be called from the item's destructor, so
// do NOT call any virtual functions on it within this block.
- if ((connectedSignals & changedSignalMask) || views.isEmpty()) {
+ if ((connectedSignals[0] & changedSignalMask) || views.isEmpty()) {
// This block of code is kept for compatibility. Since 4.5, by default
// QGraphicsView does not connect the signal and we use the below
// method of delivering updates.
@@ -4623,7 +4623,7 @@ void QGraphicsScenePrivate::processDirtyItemsRecursive(QGraphicsItem *item, bool
// Process item.
if (item->d_ptr->dirty || item->d_ptr->paintedViewBoundingRectsNeedRepaint) {
- const bool useCompatUpdate = views.isEmpty() || (connectedSignals & changedSignalMask);
+ const bool useCompatUpdate = views.isEmpty() || (connectedSignals[0] & changedSignalMask);
const QRectF itemBoundingRect = adjustedItemBoundingRect(item);
if (useCompatUpdate && !itemIsUntransformable && qFuzzyIsNull(item->boundingRegionGranularity())) {
diff --git a/src/gui/graphicsview/qgraphicsscenebsptreeindex.cpp b/src/gui/graphicsview/qgraphicsscenebsptreeindex.cpp
index 3cb33d1..07d23b7 100644
--- a/src/gui/graphicsview/qgraphicsscenebsptreeindex.cpp
+++ b/src/gui/graphicsview/qgraphicsscenebsptreeindex.cpp
@@ -525,7 +525,7 @@ QGraphicsSceneBspTreeIndex::~QGraphicsSceneBspTreeIndex()
}
/*!
- \reimp
+ \internal
Clear the all the BSP index.
*/
void QGraphicsSceneBspTreeIndex::clear()
@@ -566,7 +566,7 @@ void QGraphicsSceneBspTreeIndex::removeItem(QGraphicsItem *item)
}
/*!
- \reimp
+ \internal
Update the BSP when the \a item 's bounding rect has changed.
*/
void QGraphicsSceneBspTreeIndex::prepareBoundingRectChange(const QGraphicsItem *item)
@@ -682,7 +682,7 @@ void QGraphicsSceneBspTreeIndex::setBspTreeDepth(int depth)
}
/*!
- \reimp
+ \internal
This method react to the \a rect change of the scene and
reset the BSP tree index.
@@ -695,11 +695,10 @@ void QGraphicsSceneBspTreeIndex::updateSceneRect(const QRectF &rect)
}
/*!
- \reimp
+ \internal
This method react to the \a change of the \a item and use the \a value to
update the BSP tree if necessary.
-
*/
void QGraphicsSceneBspTreeIndex::itemChange(const QGraphicsItem *item, QGraphicsItem::GraphicsItemChange change, const QVariant &value)
{
diff --git a/src/gui/graphicsview/qgraphicstransform.cpp b/src/gui/graphicsview/qgraphicstransform.cpp
index b55d78e..778cd94 100644
--- a/src/gui/graphicsview/qgraphicstransform.cpp
+++ b/src/gui/graphicsview/qgraphicstransform.cpp
@@ -1,7 +1,7 @@
/****************************************************************************
**
** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
-** Contact: Qt Software Information (qt-info@nokia.com)
+** Contact: Nokia Corporation (qt-info@nokia.com)
**
** This file is part of the QtDeclarative module of the Qt Toolkit.
**
@@ -34,11 +34,48 @@
** met: http://www.gnu.org/copyleft/gpl.html.
**
** If you are unsure which license is appropriate for your use, please
-** contact the sales department at qt-sales@nokia.com.
+** contact the sales department at http://www.qtsoftware.com/contact.
** $QT_END_LICENSE$
**
****************************************************************************/
+/*!
+ \class QGraphicsTransform
+ \brief The QGraphicsTransform class is an abstract base class for building
+ advanced transformations on QGraphicsItems.
+ \since 4.6
+
+ As an alternative to QGraphicsItem::transform, QGraphicsTransform lets you
+ create and control advanced transformations that can be configured
+ independently using specialized properties.
+
+ QGraphicsItem allows you to assign any number of QGraphicsTransform
+ instances to one QGraphicsItem. Each QGraphicsTransform is applied in
+ order, one at a time, to the QGraphicsItem it's assigned to.
+
+ QGraphicsTransform is particularily useful for animations. Whereas
+ QGraphicsItem::setTransform() lets you assign any transform directly to an
+ item, there is no direct way to interpolate between two different
+ transformations (e.g., when transitioning between two states, each for
+ which the item has a different arbitrary transform assigned). Using
+ QGraphicsTransform you can interpolate the property values of each
+ independent transformation. The resulting operation is then combined into a
+ single transform which is applied to QGraphicsItem.
+
+ If you want to create your own configurable transformation, you can create
+ a subclass of QGraphicsTransform (or any or the existing subclasses), and
+ reimplement the pure virtual applyTo() function, which takes a pointer to a
+ QTransform. Each operation you would like to apply should be exposed as
+ properties (e.g., customTransform->setVerticalShear(2.5)). Inside you
+ reimplementation of applyTo(), you can modify the provided transform
+ respectively.
+
+ QGraphicsTransform can be used together with QGraphicsItem::setTransform(),
+ QGraphicsItem::setRotation(), and QGraphicsItem::setScale().
+
+ \sa QGraphicsItem::transform(), QGraphicsScale, QGraphicsRotation, QGraphicsRotation3D
+*/
+
#include "qgraphicstransform.h"
#include "qgraphicsitem_p.h"
#include "qgraphicstransform_p.h"
@@ -51,7 +88,6 @@
QT_BEGIN_NAMESPACE
-
void QGraphicsTransformPrivate::setItem(QGraphicsItem *i)
{
if (item == i)
@@ -77,15 +113,38 @@ void QGraphicsTransformPrivate::updateItem(QGraphicsItem *item)
item->d_ptr->dirtySceneTransform = 1;
}
-void QGraphicsTransform::update()
+/*!
+ Constructs a new QGraphicsTransform with the given \a parent.
+*/
+QGraphicsTransform::QGraphicsTransform(QObject *parent)
+ : QObject(*new QGraphicsTransformPrivate, parent)
+{
+}
+
+/*!
+ Destroys the graphics transform.
+*/
+QGraphicsTransform::~QGraphicsTransform()
{
Q_D(QGraphicsTransform);
- if (d->item)
- d->updateItem(d->item);
+ d->setItem(0);
+}
+
+/*!
+ \internal
+*/
+QGraphicsTransform::QGraphicsTransform(QGraphicsTransformPrivate &p, QObject *parent)
+ : QObject(p, parent)
+{
}
/*!
- returns this object as a QTransform.
+ Applies this transformation to an identity transform, and returns the
+ resulting transform.
+
+ This is equivalent to passing an identity transform to applyTo().
+
+ \sa applyTo()
*/
QTransform QGraphicsTransform::transform() const
{
@@ -95,76 +154,65 @@ QTransform QGraphicsTransform::transform() const
}
/*!
- \class QGraphicsTransform
- \brief The QGraphicsTransform class is an abstract base class for tranformations on QGraphicsItems.
- \since 4.6
-
- The classes that inherit QGraphicsTransform express different types of transformations
- that can be applied to graphics items.
+ \fn void QGraphicsTransform::applyTo(QTransform *transform) const
- A list of these transformations can be applied to any graphics item. These
- transformations are then easily modifyable and usable from e.g. within animations.
+ This pure virtual method has to be reimplemented in derived classes.
- QGraphicsTransform is an abstract base class that is implemented by QGraphicsScale,
- QGraphicsRotation and QGraphicsRotation3D. Subclasses have to implement the applyTo method.
+ It applies this transformation to \a transform.
- \sa QGraphicsItem::transform(), QGraphicsScale, QGraphicsRotation, QGraphicsRotation3D
+ \sa QGraphicsItem::transform()
*/
/*!
- Constructs a new QGraphicsTransform with \a parent.
-*/
-QGraphicsTransform::QGraphicsTransform(QObject *parent) :
- QObject(*new QGraphicsTransformPrivate, parent)
-{
-}
+ Notifies that this transform operation has changed its parameters in such a
+ way that applyTo() will return a different result than before.
-/*!
- Destructs the graphics transform.
+ When implementing you own custom graphics transform, you must call this
+ function every time you change a parameter, to let QGraphicsItem know that
+ its transformation needs to be updated.
+
+ \sa applyTo()
*/
-QGraphicsTransform::~QGraphicsTransform()
+void QGraphicsTransform::update()
{
Q_D(QGraphicsTransform);
- d->setItem(0);
+ if (d->item)
+ d->updateItem(d->item);
}
/*!
- \internal
-*/
-QGraphicsTransform::QGraphicsTransform(QGraphicsTransformPrivate &p, QObject *parent)
- : QObject(p, parent)
-{
-}
-
-/*! \fn void QGraphicsTransform::applyTo(QTransform *transform) const
+ \class QGraphicsScale
+ \brief The QGraphicsScale class provides a scale transformation.
+ \since 4.6
- This pure virtual method has to be reimplemented in derived classes.
+ QGraphicsScene provides certain parameters to help control how the scale
+ should be applied.
- It applies this transformation to \a transform.
-*/
+ The origin is the point that the item is scaled from (i.e., it stays fixed
+ relative to the parent as the rest of the item grows). By default the
+ origin is QPointF(0, 0).
+ The two parameters xScale and yScale describe the scale factors to apply in
+ horizontal and vertical direction. They can take on any value, including 0
+ (to collapse the item to a point) or negativate value. A negative xScale
+ value will mirror the item horizontally. A negative yScale value will flip
+ the item vertically.
-/*!
- \class QGraphicsScale
- \brief The QGraphicsScale class provides a way to scale a graphics item in 2 dimensions.
- \since 4.6
-
- QGraphicsScale contains an \a origin around which the scaling happens, and two
- scale factors, xScale and yScale, the x and one for the y axis.
+ \sa QGraphicsTransform, QGraphicsItem::setScale(), QTransform::scale()
*/
class QGraphicsScalePrivate : public QGraphicsTransformPrivate
{
public:
QGraphicsScalePrivate()
- : xScale(1), yScale(1) {}
+ : xScale(1), yScale(1) {}
QPointF origin;
qreal xScale;
qreal yScale;
};
/*!
- Constructs a new graphics scale object with \a parent.
+ Constructs an empty QGraphicsScale object with the given \a parent.
*/
QGraphicsScale::QGraphicsScale(QObject *parent)
: QGraphicsTransform(*new QGraphicsScalePrivate, parent)
@@ -172,24 +220,26 @@ QGraphicsScale::QGraphicsScale(QObject *parent)
}
/*!
- Destroys the object
+ Destroys the graphics scale.
*/
QGraphicsScale::~QGraphicsScale()
{
}
/*!
- \property QGraphicsScale::origin
- The origin of the scale. All scaling will be done relative to this point.
+ \property QGraphicsScale::origin
+ \brief The QGraphicsScene class provides the origin of the scale.
+
+ All scaling will be done relative to this point (i.e., this point
+ will stay fixed, relative to the parent, when the item is scaled).
- The \a origin is in other words the fixed point for the transformation.
+ \sa xScale, yScale
*/
QPointF QGraphicsScale::origin() const
{
Q_D(const QGraphicsScale);
return d->origin;
}
-
void QGraphicsScale::setOrigin(const QPointF &point)
{
Q_D(QGraphicsScale);
@@ -199,26 +249,21 @@ void QGraphicsScale::setOrigin(const QPointF &point)
}
/*!
- \fn QGraphicsScale::originChanged()
-
- This signal is emitted whenever the origin of the object
- changes.
-*/
-
-/*!
- \property QGraphicsScale::xScale
+ \property QGraphicsScale::xScale
+ \brief the horizontal scale factor.
- The scale factor in x direction. The x direction is
- in the graphics items logical coordinates.
+ The scale factor can be any real number; the default value is 1.0. If you
+ set the factor to 0.0, the item will be collapsed to a single point. If you
+ provide a negative value, the item will be mirrored horizontally around its
+ origin.
- \sa yScale
+ \sa yScale, origin
*/
qreal QGraphicsScale::xScale() const
{
Q_D(const QGraphicsScale);
return d->xScale;
}
-
void QGraphicsScale::setXScale(qreal scale)
{
Q_D(QGraphicsScale);
@@ -230,19 +275,21 @@ void QGraphicsScale::setXScale(qreal scale)
}
/*!
- \property QGraphicsScale::yScale
+ \property QGraphicsScale::yScale
+ \brief the vertical scale factor.
- The scale factor in y direction. The y direction is
- in the graphics items logical coordinates.
+ The scale factor can be any real number; the default value is 1.0. If you
+ set the factor to 0.0, the item will be collapsed to a single point. If you
+ provide a negative value, the item will be flipped vertically around its
+ origin.
- \sa xScale
+ \sa xScale, origin
*/
qreal QGraphicsScale::yScale() const
{
Q_D(const QGraphicsScale);
return d->yScale;
}
-
void QGraphicsScale::setYScale(qreal scale)
{
Q_D(QGraphicsScale);
@@ -254,14 +301,7 @@ void QGraphicsScale::setYScale(qreal scale)
}
/*!
- \fn QGraphicsScale::scaleChanged()
-
- This signal is emitted whenever the xScale or yScale of the object
- changes.
-*/
-
-/*!
- \reimp
+ \reimp
*/
void QGraphicsScale::applyTo(QTransform *transform) const
{
@@ -272,12 +312,41 @@ void QGraphicsScale::applyTo(QTransform *transform) const
}
/*!
- \class QGraphicsRotation
- \brief The QGraphicsRotation class provides a way to rotate a graphics item in 2 dimensions.
- \since 4.6
+ \fn QGraphicsScale::originChanged()
+
+ QGraphicsScale emits this signal when its origin changes.
+
+ \sa QGraphicsScale::origin
+*/
+
+/*!
+ \fn QGraphicsScale::scaleChanged()
+
+ This signal is emitted whenever the xScale or yScale of the object
+ changes.
- QGraphicsRotation contains an \a origin around which the rotation happens, and one
- angle in degrees describing the amount of the rotation.
+ \sa QGraphicsScale::xScale, QGraphicsScale::yScale
+*/
+
+/*!
+ \class QGraphicsRotation
+ \brief The QGraphicsRotation class provides a rotation transformation.
+ \since 4.6
+
+ QGraphicsRotation provides certain parameters to help control how the
+ rotation should be applied.
+
+ The origin is the point that the item is rotated around (i.e., it stays
+ fixed relative to the parent as the rest of the item is rotated). By
+ default the origin is QPointF(0, 0).
+
+ The angle property provides the number of degrees to rotate the item
+ clockwise around the origin. This value also be negative, indicating a
+ counter-clockwise rotation. For animation purposes it may also be useful to
+ provide rotation angles exceeding (-360, 360) degrees, for instance to
+ animate how an item rotates several times.
+
+ \sa QGraphicsTransform, QGraphicsItem::setRotation(), QTransform::rotate()
*/
class QGraphicsRotationPrivate : public QGraphicsTransformPrivate
@@ -291,7 +360,7 @@ public:
};
/*!
- Constructs a new graphics rotation with \a parent.
+ Constructs a new QGraphicsRotation with the given \a parent.
*/
QGraphicsRotation::QGraphicsRotation(QObject *parent)
: QGraphicsTransform(*new QGraphicsRotationPrivate, parent)
@@ -299,7 +368,7 @@ QGraphicsRotation::QGraphicsRotation(QObject *parent)
}
/*!
- \internal
+ \internal
*/
QGraphicsRotation::QGraphicsRotation(QGraphicsRotationPrivate &p, QObject *parent)
: QGraphicsTransform(p, parent)
@@ -307,24 +376,26 @@ QGraphicsRotation::QGraphicsRotation(QGraphicsRotationPrivate &p, QObject *paren
}
/*!
- Destructs the object
+ Destroys the graphics rotation.
*/
QGraphicsRotation::~QGraphicsRotation()
{
}
/*!
- \property QGraphicsRotation::origin
- The origin around which this object will rotate the graphics item.
+ \property QGraphicsRotation::origin
+ \brief the origin of the rotation.
- The \a origin is in other words the fixed point for the transformation.
+ All rotations will be done relative to this point (i.e., this point
+ will stay fixed, relative to the parent, when the item is rotated).
+
+ \sa angle
*/
QPointF QGraphicsRotation::origin() const
{
Q_D(const QGraphicsRotation);
return d->origin;
}
-
void QGraphicsRotation::setOrigin(const QPointF &point)
{
Q_D(QGraphicsRotation);
@@ -334,22 +405,22 @@ void QGraphicsRotation::setOrigin(const QPointF &point)
}
/*!
- \fn QGraphicsRotation::originChanged()
+ \property QGraphicsRotation::angle
+ \brief the angle for clockwise rotation, in degrees.
- This signal is emitted whenever the origin of the object
- changes.
-*/
+ The angle can be any real number; the default value is 0.0. A value of 180
+ will rotate 180 degrees, clockwise. If you provide a negative number, the
+ item will be rotated counter-clockwise. Normally the rotation angle will be
+ in the range (-360, 360), but you can also provide numbers outside of this
+ range (e.g., a angle of 370 degrees gives the same result as 10 degrees).
-/*!
- \property QGraphicsRotation::angle
- The angle, in degrees, of the rotation.
+ \sa origin
*/
qreal QGraphicsRotation::angle() const
{
Q_D(const QGraphicsRotation);
return d->angle;
}
-
void QGraphicsRotation::setAngle(qreal angle)
{
Q_D(QGraphicsRotation);
@@ -361,33 +432,50 @@ void QGraphicsRotation::setAngle(qreal angle)
}
/*!
- \fn void QGraphicsRotation::angleChanged()
-
- This signal is emitted whenever the angle of the object
- changes.
-*/
-
-/*!
- \reimp
+ \reimp
*/
void QGraphicsRotation::applyTo(QTransform *t) const
{
Q_D(const QGraphicsRotation);
- if(d->angle) {
+ if (d->angle) {
t->translate(d->origin.x(), d->origin.y());
t->rotate(d->angle);
t->translate(-d->origin.x(), -d->origin.y());
}
}
+/*!
+ \fn QGraphicsRotation::originChanged()
+
+ This signal is emitted whenever the origin has changed.
+
+ \sa QGraphicsRotation::origin
+*/
/*!
- \class QGraphicsRotation3D
- \brief The QGraphicsRotation3D class provides a way to rotate a graphics item in 3 dimensions.
- \since 4.6
+ \fn void QGraphicsRotation::angleChanged()
- In addition to the origin and angle of a simple QGraphicsRotation, QGraphicsRotation3D contains
- also an axis that describes around which axis in space the rotation is supposed to happen.
+ This signal is emitted whenever the angle has changed.
+
+ \sa QGraphicsRotation::angle
+*/
+
+/*!
+ \class QGraphicsRotation3D
+ \brief The QGraphicsRotation3D class provides rotation in 3 dimensions.
+ \since 4.6
+
+ QGraphicsRotation3D extends QGraphicsRotation with the ability to rotate
+ around a given axis.
+
+ You can provide the desired axis by assigning a QVector3D to the axis
+ property. The angle property, which is provided by QGraphicsRotation, now
+ describes the number of degrees to rotate around this axis.
+
+ By default the axis is (0, 0, 1), giving QGraphicsRotation3D the same
+ default behavior as QGraphicsRotation (i.e., rotation around the Z axis).
+
+ \sa QGraphicsTransform, QGraphicsItem::setRotation(), QTransform::rotate()
*/
class QGraphicsRotation3DPrivate : public QGraphicsRotationPrivate
@@ -399,7 +487,7 @@ public:
};
/*!
- Constructs a new 3D rotation with \a parent.
+ Constructs a new QGraphicsRotation3D with the given \a parent.
*/
QGraphicsRotation3D::QGraphicsRotation3D(QObject *parent)
: QGraphicsRotation(*new QGraphicsRotation3DPrivate, parent)
@@ -407,7 +495,7 @@ QGraphicsRotation3D::QGraphicsRotation3D(QObject *parent)
}
/*!
- Destroys the object
+ Destroys the 3D graphics rotation.
*/
QGraphicsRotation3D::~QGraphicsRotation3D()
{
@@ -415,15 +503,22 @@ QGraphicsRotation3D::~QGraphicsRotation3D()
/*!
\property QGraphicsRotation3D::axis
+ \brief a rotation axis, specified by a vector in 3D space.
+
+ This can be any axis in 3D space. By default the axis is (0, 0, 1),
+ which is aligned with the Z axis and provides the same behavior
+ for the rotation angle as QGraphicsRotation. If you provide another
+ axis, QGraphicsRotation3D will provide a transformation that rotates
+ around this axis. For example, if you would like to rotate an item
+ around its X axis, you could pass (1, 0, 0) as the axis.
- A rotation axis is specified by a vector in 3D space.
+ \sa QTransform, QGraphicsRotation::angle
*/
QVector3D QGraphicsRotation3D::axis()
{
Q_D(QGraphicsRotation3D);
return d->axis;
}
-
void QGraphicsRotation3D::setAxis(const QVector3D &axis)
{
Q_D(QGraphicsRotation3D);
@@ -431,17 +526,10 @@ void QGraphicsRotation3D::setAxis(const QVector3D &axis)
update();
}
-/*!
- \fn void QGraphicsRotation3D::axisChanged()
-
- This signal is emitted whenever the axis of the object
- changes.
-*/
-
-const qreal inv_dist_to_plane = 1. / 1024.;
+static const qreal inv_dist_to_plane = 1. / 1024.;
/*!
- \reimp
+ \reimp
*/
void QGraphicsRotation3D::applyTo(QTransform *t) const
{
@@ -474,6 +562,12 @@ void QGraphicsRotation3D::applyTo(QTransform *t) const
t->translate(-d->origin.x(), -d->origin.y());
}
+/*!
+ \fn void QGraphicsRotation3D::axisChanged()
+
+ This signal is emitted whenever the axis of the object changes.
+*/
+
#include "moc_qgraphicstransform.cpp"
QT_END_NAMESPACE
diff --git a/src/gui/graphicsview/qgraphicstransform.h b/src/gui/graphicsview/qgraphicstransform.h
index b5d8d84..d7c07d0 100644
--- a/src/gui/graphicsview/qgraphicstransform.h
+++ b/src/gui/graphicsview/qgraphicstransform.h
@@ -70,6 +70,7 @@ protected Q_SLOTS:
protected:
QGraphicsTransform(QGraphicsTransformPrivate &p, QObject *parent);
+
private:
friend class QGraphicsItem;
friend class QGraphicsItemPrivate;
diff --git a/src/gui/image/image.pri b/src/gui/image/image.pri
index bf348af..b9c36dc 100644
--- a/src/gui/image/image.pri
+++ b/src/gui/image/image.pri
@@ -25,7 +25,9 @@ HEADERS += \
image/qpixmapcache_p.h \
image/qpixmapdata_p.h \
image/qpixmapdatafactory_p.h \
- image/qpixmapfilter_p.h
+ image/qpixmapfilter_p.h \
+ image/qimagepixmapcleanuphooks_p.h \
+
SOURCES += \
image/qbitmap.cpp \
@@ -47,6 +49,8 @@ SOURCES += \
image/qmovie.cpp \
image/qpixmap_raster.cpp \
image/qnativeimage.cpp \
+ image/qimagepixmapcleanuphooks.cpp \
+
win32 {
SOURCES += image/qpixmap_win.cpp
diff --git a/src/gui/image/qimage.cpp b/src/gui/image/qimage.cpp
index e8ca7a9..bb77fb5 100644
--- a/src/gui/image/qimage.cpp
+++ b/src/gui/image/qimage.cpp
@@ -49,6 +49,7 @@
#include "qimagewriter.h"
#include "qstringlist.h"
#include "qvariant.h"
+#include "qimagepixmapcleanuphooks_p.h"
#include <ctype.h>
#include <stdlib.h>
#include <limits.h>
@@ -106,14 +107,6 @@ static inline bool checkPixelSize(const QImage::Format format)
}
-// ### Qt 5: remove
-typedef void (*_qt_image_cleanup_hook)(int);
-Q_GUI_EXPORT _qt_image_cleanup_hook qt_image_cleanup_hook = 0;
-
-// ### Qt 5: rename
-typedef void (*_qt_image_cleanup_hook_64)(qint64);
-Q_GUI_EXPORT _qt_image_cleanup_hook_64 qt_image_cleanup_hook_64 = 0;
-
static QImage rotated90(const QImage &src);
static QImage rotated180(const QImage &src);
static QImage rotated270(const QImage &src);
@@ -257,8 +250,8 @@ QImageData * QImageData::create(const QSize &size, QImage::Format format, int nu
QImageData::~QImageData()
{
- if (is_cached && qt_image_cleanup_hook_64)
- qt_image_cleanup_hook_64((((qint64) ser_no) << 32) | ((qint64) detach_no));
+ if (is_cached)
+ QImagePixmapCleanupHooks::executeImageHooks((((qint64) ser_no) << 32) | ((qint64) detach_no));
delete paintEngine;
if (data && own_data)
free(data);
@@ -1342,8 +1335,8 @@ QImage::operator QVariant() const
void QImage::detach()
{
if (d) {
- if (d->is_cached && qt_image_cleanup_hook_64 && d->ref == 1)
- qt_image_cleanup_hook_64(cacheKey());
+ if (d->is_cached && d->ref == 1)
+ QImagePixmapCleanupHooks::executeImageHooks(cacheKey());
if (d->ref != 1 || d->ro_data)
*this = copy();
diff --git a/src/gui/image/qimagepixmapcleanuphooks.cpp b/src/gui/image/qimagepixmapcleanuphooks.cpp
new file mode 100644
index 0000000..7d1c5fb
--- /dev/null
+++ b/src/gui/image/qimagepixmapcleanuphooks.cpp
@@ -0,0 +1,110 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtGui module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the either Technology Preview License Agreement or the
+** Beta Release License Agreement.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain
+** additional rights. These rights are described in the Nokia Qt LGPL
+** Exception version 1.0, 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.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at http://www.qtsoftware.com/contact.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qimagepixmapcleanuphooks_p.h"
+#include "qpixmapdata_p.h"
+
+
+// Legacy, single instance hooks: ### Qt 5: remove
+typedef void (*_qt_pixmap_cleanup_hook)(int);
+typedef void (*_qt_pixmap_cleanup_hook_64)(qint64);
+typedef void (*_qt_image_cleanup_hook)(int);
+Q_GUI_EXPORT _qt_pixmap_cleanup_hook qt_pixmap_cleanup_hook = 0;
+Q_GUI_EXPORT _qt_pixmap_cleanup_hook_64 qt_pixmap_cleanup_hook_64 = 0;
+Q_GUI_EXPORT _qt_image_cleanup_hook qt_image_cleanup_hook = 0;
+Q_GUI_EXPORT _qt_image_cleanup_hook_64 qt_image_cleanup_hook_64 = 0;
+
+
+QImagePixmapCleanupHooks* qt_image_and_pixmap_cleanup_hooks = 0;
+
+
+QImagePixmapCleanupHooks::QImagePixmapCleanupHooks()
+{
+ qt_image_and_pixmap_cleanup_hooks = this;
+}
+
+QImagePixmapCleanupHooks *QImagePixmapCleanupHooks::instance()
+{
+ if (!qt_image_and_pixmap_cleanup_hooks)
+ qt_image_and_pixmap_cleanup_hooks = new QImagePixmapCleanupHooks;
+ return qt_image_and_pixmap_cleanup_hooks;
+}
+
+void QImagePixmapCleanupHooks::addPixmapHook(_qt_pixmap_cleanup_hook_pm hook)
+{
+ pixmapHooks.append(hook);
+}
+
+void QImagePixmapCleanupHooks::addImageHook(_qt_image_cleanup_hook_64 hook)
+{
+ imageHooks.append(hook);
+}
+
+void QImagePixmapCleanupHooks::removePixmapHook(_qt_pixmap_cleanup_hook_pm hook)
+{
+ pixmapHooks.removeAll(hook);
+}
+
+void QImagePixmapCleanupHooks::removeImageHook(_qt_image_cleanup_hook_64 hook)
+{
+ imageHooks.removeAll(hook);
+}
+
+
+void QImagePixmapCleanupHooks::executePixmapHooks(QPixmap* pm)
+{
+ for (int i = 0; i < qt_image_and_pixmap_cleanup_hooks->pixmapHooks.count(); ++i)
+ qt_image_and_pixmap_cleanup_hooks->pixmapHooks[i](pm);
+
+ if (qt_pixmap_cleanup_hook_64)
+ qt_pixmap_cleanup_hook_64(pm->cacheKey());
+}
+
+
+void QImagePixmapCleanupHooks::executeImageHooks(qint64 key)
+{
+ for (int i = 0; i < qt_image_and_pixmap_cleanup_hooks->imageHooks.count(); ++i)
+ qt_image_and_pixmap_cleanup_hooks->imageHooks[i](key);
+
+ if (qt_image_cleanup_hook_64)
+ qt_image_cleanup_hook_64(key);
+}
+
diff --git a/src/gui/painting/qregion_wince.cpp b/src/gui/image/qimagepixmapcleanuphooks_p.h
index 9c33123..e765e69 100644
--- a/src/gui/painting/qregion_wince.cpp
+++ b/src/gui/image/qimagepixmapcleanuphooks_p.h
@@ -39,81 +39,51 @@
**
****************************************************************************/
-#include "qatomic.h"
-#include "qbitmap.h"
-#include "qbuffer.h"
-#include "qimage.h"
-#include "qpolygon.h"
-#include "qregion.h"
-#include "qt_windows.h"
-#include "qpainterpath.h"
-#include "qguifunctions_wince.h"
+#ifndef QIMAGEPIXMAP_CLEANUPHOOKS_P_H
+#define QIMAGEPIXMAP_CLEANUPHOOKS_P_H
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists purely as an
+// implementation detail. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
+#include <QtGui/qpixmap.h>
QT_BEGIN_NAMESPACE
-QRegion::QRegionData QRegion::shared_empty = { Q_BASIC_ATOMIC_INITIALIZER(1), 0, 0 };
+typedef void (*_qt_image_cleanup_hook_64)(qint64);
+typedef void (*_qt_pixmap_cleanup_hook_pm)(QPixmap*);
-HRGN qt_tryCreateRegion(QRegion::RegionType type, int left, int top, int right, int bottom)
-{
- const int tries = 10;
- for (int i = 0; i < tries; ++i) {
- HRGN region;
- switch (type) {
- case QRegion::Rectangle:
- region = CreateRectRgn(left, top, right, bottom);
- break;
- case QRegion::Ellipse:
-#ifndef Q_OS_WINCE
- region = CreateEllipticRgn(left, top, right, bottom);
-#endif
- break;
- }
- if (region) {
- if (GetRegionData(region, 0, 0))
- return region;
- else
- DeleteObject(region);
- }
- }
- return 0;
-}
+class QImagePixmapCleanupHooks;
+extern QImagePixmapCleanupHooks* qt_image_and_pixmap_cleanup_hooks;
-void qt_win_dispose_rgn(HRGN r)
+class Q_GUI_EXPORT QImagePixmapCleanupHooks
{
- if (r)
- DeleteObject(r);
-}
+public:
+ QImagePixmapCleanupHooks();
-static void qt_add_rect(HRGN &winRegion, QRect r)
-{
- HRGN rgn = CreateRectRgn(r.left(), r.top(), r.x() + r.width(), r.y() + r.height());
- if (rgn) {
- HRGN dest = CreateRectRgn(0,0,0,0);
- int result = CombineRgn(dest, winRegion, rgn, RGN_OR);
- if (result) {
- DeleteObject(winRegion);
- winRegion = dest;
- }
- }
-}
+ static QImagePixmapCleanupHooks *instance();
-void QRegion::ensureHandle() const
-{
- if (d->rgn)
- DeleteObject(d->rgn);
- d->rgn = CreateRectRgn(0,0,0,0);
- if (d->qt_rgn) {
- if (d->qt_rgn->numRects == 1) {
- QRect r = d->qt_rgn->extents;
- qt_add_rect(d->rgn, r);
- return;
- }
- for (int i = 0;i < d->qt_rgn->numRects;i++) {
- QRect r = d->qt_rgn->rects.at(i);
- qt_add_rect(d->rgn, r);
- }
- }
-}
+ void addPixmapHook(_qt_pixmap_cleanup_hook_pm);
+ void addImageHook(_qt_image_cleanup_hook_64);
+
+ void removePixmapHook(_qt_pixmap_cleanup_hook_pm);
+ void removeImageHook(_qt_image_cleanup_hook_64);
+ static void executePixmapHooks(QPixmap*);
+ static void executeImageHooks(qint64 key);
+
+private:
+ QList<_qt_image_cleanup_hook_64> imageHooks;
+ QList<_qt_pixmap_cleanup_hook_pm> pixmapHooks;
+};
QT_END_NAMESPACE
+
+#endif // QIMAGEPIXMAP_CLEANUPHOOKS_P_H
diff --git a/src/gui/image/qpixmap.cpp b/src/gui/image/qpixmap.cpp
index 18829f4..82835d5 100644
--- a/src/gui/image/qpixmap.cpp
+++ b/src/gui/image/qpixmap.cpp
@@ -43,6 +43,7 @@
#include "qpixmap.h"
#include "qpixmapdata_p.h"
+#include "qimagepixmapcleanuphooks_p.h"
#include "qbitmap.h"
#include "qcolormap.h"
@@ -81,14 +82,6 @@
QT_BEGIN_NAMESPACE
// ### Qt 5: remove
-typedef void (*_qt_pixmap_cleanup_hook)(int);
-Q_GUI_EXPORT _qt_pixmap_cleanup_hook qt_pixmap_cleanup_hook = 0;
-
-// ### Qt 5: rename
-typedef void (*_qt_pixmap_cleanup_hook_64)(qint64);
-Q_GUI_EXPORT _qt_pixmap_cleanup_hook_64 qt_pixmap_cleanup_hook_64 = 0;
-
-// ### Qt 5: remove
Q_GUI_EXPORT qint64 qt_pixmap_id(const QPixmap &pixmap)
{
return pixmap.cacheKey();
@@ -656,7 +649,7 @@ void QPixmap::resize_helper(const QSize &s)
QX11PixmapData *x11Data = data->classId() == QPixmapData::X11Class ? static_cast<QX11PixmapData*>(data) : 0;
if (x11Data) {
pm.x11SetScreen(x11Data->xinfo.screen());
- uninit = x11Data->uninit;
+ uninit = x11Data->flags & QX11PixmapData::Uninitialized;
}
#elif defined(Q_WS_MAC)
QMacPixmapData *macData = data->classId() == QPixmapData::MacClass ? static_cast<QMacPixmapData*>(data) : 0;
@@ -1357,8 +1350,8 @@ bool QPixmap::isDetached() const
void QPixmap::deref()
{
if (data && !data->ref.deref()) { // Destroy image if last ref
- if (data->is_cached && qt_pixmap_cleanup_hook_64)
- qt_pixmap_cleanup_hook_64(cacheKey());
+ if (data->is_cached)
+ QImagePixmapCleanupHooks::executePixmapHooks(this);
delete data;
data = 0;
}
@@ -1897,9 +1890,6 @@ int QPixmap::defaultDepth()
#endif
}
-typedef void (*_qt_pixmap_cleanup_hook_64)(qint64);
-extern _qt_pixmap_cleanup_hook_64 qt_pixmap_cleanup_hook_64;
-
/*!
Detaches the pixmap from shared pixmap data.
@@ -1925,8 +1915,8 @@ void QPixmap::detach()
rasterData->image.detach();
}
- if (data->is_cached && qt_pixmap_cleanup_hook_64 && data->ref == 1)
- qt_pixmap_cleanup_hook_64(cacheKey());
+ if (data->is_cached && data->ref == 1)
+ QImagePixmapCleanupHooks::executePixmapHooks(this);
#if defined(Q_WS_MAC)
QMacPixmapData *macData = id == QPixmapData::MacClass ? static_cast<QMacPixmapData*>(data) : 0;
@@ -1946,7 +1936,7 @@ void QPixmap::detach()
#if defined(Q_WS_X11)
if (data->classId() == QPixmapData::X11Class) {
QX11PixmapData *d = static_cast<QX11PixmapData*>(data);
- d->uninit = false;
+ d->flags &= ~QX11PixmapData::Uninitialized;
// reset the cache data
if (d->hd2) {
diff --git a/src/gui/image/qpixmap_mac.cpp b/src/gui/image/qpixmap_mac.cpp
index 45392f1..5568898 100644
--- a/src/gui/image/qpixmap_mac.cpp
+++ b/src/gui/image/qpixmap_mac.cpp
@@ -1178,6 +1178,7 @@ QPixmap QPixmap::fromMacCGImageRef(CGImageRef image)
const size_t w = CGImageGetWidth(image),
h = CGImageGetHeight(image);
QPixmap ret(w, h);
+ ret.fill(Qt::transparent);
CGRect rect = CGRectMake(0, 0, w, h);
CGContextRef ctx = qt_mac_cg_context(&ret);
qt_mac_drawCGImage(ctx, &rect, image);
diff --git a/src/gui/image/qpixmap_x11.cpp b/src/gui/image/qpixmap_x11.cpp
index 86cf515..be3d070 100644
--- a/src/gui/image/qpixmap_x11.cpp
+++ b/src/gui/image/qpixmap_x11.cpp
@@ -313,7 +313,7 @@ int Q_GUI_EXPORT qt_x11_preferred_pixmap_depth = 0;
QX11PixmapData::QX11PixmapData(PixelType type)
: QPixmapData(type, X11Class), hd(0),
- uninit(true), read_only(false), x11_mask(0), picture(0), mask_picture(0), hd2(0),
+ flags(Uninitialized), x11_mask(0), picture(0), mask_picture(0), hd2(0), gl_surface(0),
share_mode(QPixmap::ImplicitlyShared), pengine(0)
{
}
@@ -1217,7 +1217,7 @@ void QX11PixmapData::release()
XFreePixmap(xinfo.display(), hd2);
hd2 = 0;
}
- if (!read_only)
+ if (!(flags & Readonly))
XFreePixmap(xinfo.display(), hd);
hd = 0;
}
@@ -1876,7 +1876,7 @@ QPixmap QX11PixmapData::transformed(const QTransform &transform,
} else { // color pixmap
QPixmap pm;
QX11PixmapData *x11Data = static_cast<QX11PixmapData*>(pm.data);
- x11Data->uninit = false;
+ x11Data->flags &= ~QX11PixmapData::Uninitialized;
x11Data->xinfo = xinfo;
x11Data->d = d;
x11Data->w = w;
@@ -2018,7 +2018,7 @@ QPixmap QPixmap::grabWindow(WId window, int x, int y, int w, int h)
QPixmap pm(data);
- data->uninit = false;
+ data->flags &= ~QX11PixmapData::Uninitialized;
pm.x11SetScreen(scr);
GC gc = XCreateGC(dpy, pm.handle(), 0, 0);
@@ -2060,7 +2060,7 @@ QPaintEngine* QX11PixmapData::paintEngine() const
{
QX11PixmapData *that = const_cast<QX11PixmapData*>(this);
- if (read_only && share_mode == QPixmap::ImplicitlyShared) {
+ if ((flags & Readonly) && share_mode == QPixmap::ImplicitlyShared) {
// if someone wants to draw onto us, copy the shared contents
// and turn it into a fully fledged QPixmap
::Pixmap hd_copy = XCreatePixmap(X11->display, RootWindow(X11->display, xinfo.screen()),
@@ -2082,7 +2082,7 @@ QPaintEngine* QX11PixmapData::paintEngine() const
XFreeGC(X11->display, gc);
}
that->hd = hd_copy;
- that->read_only = false;
+ that->flags &= ~QX11PixmapData::Readonly;
}
if (!that->pengine)
@@ -2133,7 +2133,7 @@ void QX11PixmapData::copy(const QPixmapData *data, const QRect &rect)
setSerialNumber(++qt_pixmap_serial);
- uninit = false;
+ flags &= ~Uninitialized;
xinfo = x11Data->xinfo;
d = x11Data->d;
w = rect.width();
@@ -2201,7 +2201,7 @@ void QX11PixmapData::convertToARGB32(bool preserveContents)
return;
// Q_ASSERT(count == 1);
- if (read_only && share_mode == QPixmap::ExplicitlyShared)
+ if ((flags & Readonly) && share_mode == QPixmap::ExplicitlyShared)
return;
Pixmap pm = XCreatePixmap(X11->display, RootWindow(X11->display, xinfo.screen()),
@@ -2211,10 +2211,10 @@ void QX11PixmapData::convertToARGB32(bool preserveContents)
if (picture) {
if (preserveContents)
XRenderComposite(X11->display, PictOpSrc, picture, 0, p, 0, 0, 0, 0, 0, 0, w, h);
- if (!read_only)
+ if (!(flags & Readonly))
XRenderFreePicture(X11->display, picture);
}
- if (hd && !read_only)
+ if (hd && !(flags & Readonly))
XFreePixmap(X11->display, hd);
if (x11_mask) {
XFreePixmap(X11->display, x11_mask);
@@ -2252,9 +2252,8 @@ QPixmap QPixmap::fromX11Pixmap(Qt::HANDLE pixmap, QPixmap::ShareMode mode)
QX11PixmapData *data = new QX11PixmapData(depth == 1 ? QPixmapData::BitmapType : QPixmapData::PixmapType);
data->setSerialNumber(++qt_pixmap_serial);
- data->read_only = true;
+ data->flags = QX11PixmapData::Readonly;
data->share_mode = mode;
- data->uninit = false;
data->w = width;
data->h = height;
data->is_null = (width <= 0 || height <= 0);
diff --git a/src/gui/image/qpixmap_x11_p.h b/src/gui/image/qpixmap_x11_p.h
index 3de9a0f..835fea4 100644
--- a/src/gui/image/qpixmap_x11_p.h
+++ b/src/gui/image/qpixmap_x11_p.h
@@ -99,6 +99,7 @@ private:
friend class QX11PaintEngine;
friend class QX11WindowSurface;
friend class QRasterWindowSurface;
+ friend class QGLContextPrivate; // Needs to access xinfo, gl_surface & flags
void release();
@@ -108,14 +109,21 @@ private:
Qt::HANDLE hd;
- uint uninit : 1;
- uint read_only : 1;
+ enum Flag {
+ NoFlags = 0x0,
+ Uninitialized = 0x1,
+ Readonly = 0x2,
+ InvertedWhenBoundToTexture = 0x4,
+ GlSurfaceCreatedWithAlpha = 0x8
+ };
+ uint flags;
QX11Info xinfo;
Qt::HANDLE x11_mask;
Qt::HANDLE picture;
Qt::HANDLE mask_picture;
Qt::HANDLE hd2; // sorted in the default display depth
+ Qt::HANDLE gl_surface;
#ifndef QT_NO_XRENDER
void convertToARGB32(bool preserveContents = true);
#endif
diff --git a/src/gui/image/qpixmapdata_p.h b/src/gui/image/qpixmapdata_p.h
index 29dafaf..32b419e 100644
--- a/src/gui/image/qpixmapdata_p.h
+++ b/src/gui/image/qpixmapdata_p.h
@@ -116,6 +116,7 @@ private:
friend class QPixmap;
friend class QGLContextPrivate;
friend class QX11PixmapData;
+ friend class QGLTextureCache; //Needs to check the reference count
QAtomicInt ref;
int detach_no;
diff --git a/src/gui/itemviews/qabstractitemview.cpp b/src/gui/itemviews/qabstractitemview.cpp
index 8b6b5cb..94569ec 100644
--- a/src/gui/itemviews/qabstractitemview.cpp
+++ b/src/gui/itemviews/qabstractitemview.cpp
@@ -960,6 +960,7 @@ void QAbstractItemView::reset()
d->currentIndexSet = false;
setState(NoState);
setRootIndex(QModelIndex());
+ d->selectionModel->reset();
}
/*!
diff --git a/src/gui/itemviews/qitemdelegate.cpp b/src/gui/itemviews/qitemdelegate.cpp
index 336ca79..bd6dc62 100644
--- a/src/gui/itemviews/qitemdelegate.cpp
+++ b/src/gui/itemviews/qitemdelegate.cpp
@@ -1226,21 +1226,19 @@ bool QItemDelegate::eventFilter(QObject *object, QEvent *event)
} else if (event->type() == QEvent::FocusOut || (event->type() == QEvent::Hide && editor->isWindow())) {
//the Hide event will take care of he editors that are in fact complete dialogs
if (!editor->isActiveWindow() || (QApplication::focusWidget() != editor)) {
- if (editor->isAncestorOf(QApplication::focusWidget()))
- return false; // don't worry about focus changes internally in the editor
-
+ QWidget *w = QApplication::focusWidget();
+ while (w) { // don't worry about focus changes internally in the editor
+ if (w == editor)
+ return false;
+ w = w->parentWidget();
+ }
#ifndef QT_NO_DRAGANDDROP
// The window may lose focus during an drag operation.
// i.e when dragging involves the taskbar on Windows.
if (QDragManager::self() && QDragManager::self()->object != 0)
return false;
#endif
- // Opening a modal dialog will start a new eventloop
- // that will process the deleteLater event.
- if (QApplication::activeModalWidget()
- && !QApplication::activeModalWidget()->isAncestorOf(editor)
- && qobject_cast<QDialog*>(QApplication::activeModalWidget()))
- return false;
+
emit commitData(editor);
emit closeEditor(editor, NoHint);
}
@@ -1298,8 +1296,14 @@ bool QItemDelegate::editorEvent(QEvent *event,
return false;
}
- Qt::CheckState state = (static_cast<Qt::CheckState>(value.toInt()) == Qt::Checked
+ Qt::CheckState state;
+ if ( flags & Qt::ItemIsTristate ) {
+ state = static_cast<Qt::CheckState>( (value.toInt() + 1) % 3 );
+ } else {
+ state = (static_cast<Qt::CheckState>(value.toInt()) == Qt::Checked
? Qt::Unchecked : Qt::Checked);
+ }
+
return model->setData(index, state, Qt::CheckStateRole);
}
diff --git a/src/gui/itemviews/qstyleditemdelegate.cpp b/src/gui/itemviews/qstyleditemdelegate.cpp
index bd8fdac..34667ee 100644
--- a/src/gui/itemviews/qstyleditemdelegate.cpp
+++ b/src/gui/itemviews/qstyleditemdelegate.cpp
@@ -674,22 +674,19 @@ bool QStyledItemDelegate::eventFilter(QObject *object, QEvent *event)
} else if (event->type() == QEvent::FocusOut || (event->type() == QEvent::Hide && editor->isWindow())) {
//the Hide event will take care of he editors that are in fact complete dialogs
if (!editor->isActiveWindow() || (QApplication::focusWidget() != editor)) {
- if (editor->isAncestorOf(QApplication::focusWidget()))
- return false; // don't worry about focus changes internally in the editor
-
+ QWidget *w = QApplication::focusWidget();
+ while (w) { // don't worry about focus changes internally in the editor
+ if (w == editor)
+ return false;
+ w = w->parentWidget();
+ }
#ifndef QT_NO_DRAGANDDROP
// The window may lose focus during an drag operation.
// i.e when dragging involves the taskbar on Windows.
if (QDragManager::self() && QDragManager::self()->object != 0)
return false;
#endif
- // Opening a modal dialog will start a new eventloop
- // that will process the deleteLater event.
- QWidget *activeModalWidget = QApplication::activeModalWidget();
- if (activeModalWidget
- && !activeModalWidget->isAncestorOf(editor)
- && qobject_cast<QDialog*>(activeModalWidget))
- return false;
+
emit commitData(editor);
emit closeEditor(editor, NoHint);
}
@@ -749,8 +746,13 @@ bool QStyledItemDelegate::editorEvent(QEvent *event,
return false;
}
- Qt::CheckState state = (static_cast<Qt::CheckState>(value.toInt()) == Qt::Checked
+ Qt::CheckState state;
+ if ( flags & Qt::ItemIsTristate ) {
+ state = static_cast<Qt::CheckState>( (value.toInt() + 1) % 3 );
+ } else {
+ state = (static_cast<Qt::CheckState>(value.toInt()) == Qt::Checked
? Qt::Unchecked : Qt::Checked);
+ }
return model->setData(index, state, Qt::CheckStateRole);
}
diff --git a/src/gui/kernel/qaction.h b/src/gui/kernel/qaction.h
index 133fab4..cb681c4 100644
--- a/src/gui/kernel/qaction.h
+++ b/src/gui/kernel/qaction.h
@@ -68,24 +68,24 @@ class Q_GUI_EXPORT QAction : public QObject
Q_ENUMS(MenuRole)
Q_ENUMS(Priority)
- Q_PROPERTY(bool checkable READ isCheckable WRITE setCheckable)
+ Q_PROPERTY(bool checkable READ isCheckable WRITE setCheckable NOTIFY changed)
Q_PROPERTY(bool checked READ isChecked WRITE setChecked DESIGNABLE isCheckable NOTIFY toggled)
- Q_PROPERTY(bool enabled READ isEnabled WRITE setEnabled)
- Q_PROPERTY(QIcon icon READ icon WRITE setIcon)
- Q_PROPERTY(QString text READ text WRITE setText)
- Q_PROPERTY(QString iconText READ iconText WRITE setIconText)
- Q_PROPERTY(QString toolTip READ toolTip WRITE setToolTip)
- Q_PROPERTY(QString statusTip READ statusTip WRITE setStatusTip)
- Q_PROPERTY(QString whatsThis READ whatsThis WRITE setWhatsThis)
- Q_PROPERTY(QFont font READ font WRITE setFont)
+ Q_PROPERTY(bool enabled READ isEnabled WRITE setEnabled NOTIFY changed)
+ Q_PROPERTY(QIcon icon READ icon WRITE setIcon NOTIFY changed)
+ Q_PROPERTY(QString text READ text WRITE setText NOTIFY changed)
+ Q_PROPERTY(QString iconText READ iconText WRITE setIconText NOTIFY changed)
+ Q_PROPERTY(QString toolTip READ toolTip WRITE setToolTip NOTIFY changed)
+ Q_PROPERTY(QString statusTip READ statusTip WRITE setStatusTip NOTIFY changed)
+ Q_PROPERTY(QString whatsThis READ whatsThis WRITE setWhatsThis NOTIFY changed)
+ Q_PROPERTY(QFont font READ font WRITE setFont NOTIFY changed)
#ifndef QT_NO_SHORTCUT
- Q_PROPERTY(QKeySequence shortcut READ shortcut WRITE setShortcut)
- Q_PROPERTY(Qt::ShortcutContext shortcutContext READ shortcutContext WRITE setShortcutContext)
- Q_PROPERTY(bool autoRepeat READ autoRepeat WRITE setAutoRepeat)
+ Q_PROPERTY(QKeySequence shortcut READ shortcut WRITE setShortcut NOTIFY changed)
+ Q_PROPERTY(Qt::ShortcutContext shortcutContext READ shortcutContext WRITE setShortcutContext NOTIFY changed)
+ Q_PROPERTY(bool autoRepeat READ autoRepeat WRITE setAutoRepeat NOTIFY changed)
#endif
- Q_PROPERTY(bool visible READ isVisible WRITE setVisible)
- Q_PROPERTY(MenuRole menuRole READ menuRole WRITE setMenuRole)
- Q_PROPERTY(bool iconVisibleInMenu READ isIconVisibleInMenu WRITE setIconVisibleInMenu)
+ Q_PROPERTY(bool visible READ isVisible WRITE setVisible NOTIFY changed)
+ Q_PROPERTY(MenuRole menuRole READ menuRole WRITE setMenuRole NOTIFY changed)
+ Q_PROPERTY(bool iconVisibleInMenu READ isIconVisibleInMenu WRITE setIconVisibleInMenu NOTIFY changed)
Q_PROPERTY(Priority priority READ priority WRITE setPriority)
public:
diff --git a/src/gui/kernel/qapplication.cpp b/src/gui/kernel/qapplication.cpp
index 5181689..c24ff49 100644
--- a/src/gui/kernel/qapplication.cpp
+++ b/src/gui/kernel/qapplication.cpp
@@ -179,11 +179,11 @@ QApplicationPrivate::~QApplicationPrivate()
QApplication contains the main event loop, where all events from the window
system and other sources are processed and dispatched. It also handles the
- application's initialization and finalization, and provides session
- management. In addition, it handles most system-wide and application-wide
- settings.
+ application's initialization, finalization, and provides session
+ management. In addition, QApplication handles most of the system-wide and
+ application-wide settings.
- For any GUI application using Qt, there is precisely one QApplication
+ For any GUI application using Qt, there is precisely \bold one QApplication
object, no matter whether the application has 0, 1, 2 or more windows at
any given time. For non-GUI Qt applications, use QCoreApplication instead,
as it does not depend on the \l QtGui library.
@@ -239,9 +239,9 @@ QApplicationPrivate::~QApplicationPrivate()
saveState() for details.
\endlist
- The QApplication object does so much initialization. Hence, it \e{must} be
+ Since the QApplication object does so much initialization, it \e{must} be
created before any other objects related to the user interface are created.
- Since QApplication also deals with common command line arguments, it is
+ QApplication also deals with common command line arguments. Hence, it is
usually a good idea to create it \e before any interpretation or
modification of \c argv is done in the application itself.
@@ -673,9 +673,9 @@ QApplication::QApplication(int &argc, char **argv, int _internal)
On X11, the window system is initialized if \a GUIenabled is true. If
\a GUIenabled is false, the application does not connect to the X server.
- On Windows and Macintosh, currently the window system is always
- initialized, regardless of the value of GUIenabled. This may change in
- future versions of Qt.
+ On Windows and Mac OS, currently the window system is always initialized,
+ regardless of the value of GUIenabled. This may change in future versions
+ of Qt.
The following example shows how to create an application that uses a
graphical interface when available.
@@ -1194,21 +1194,22 @@ bool QApplication::compressEvent(QEvent *event, QObject *receiver, QPostEventLis
\since 4.4
\brief defines a threshold for auto maximizing widgets
- The auto maximize threshold is only available as part of Qt for Windows CE.
+ \bold{The auto maximize threshold is only available as part of Qt for
+ Windows CE.}
This property defines a threshold for the size of a window as a percentage
of the screen size. If the minimum size hint of a window exceeds the
- threshold, calling show() will then cause the window to be maximized
+ threshold, calling show() will cause the window to be maximized
automatically.
- Setting the threshold to be 100 or greater means that it will cause it to
- always be maximized. Setting it to be 50 means that the widget is maximized
- if the vertical minimum size hint is at least 50% of the vertical screen
- size.
+ Setting the threshold to 100 or greater means that the widget will always
+ be maximized. Alternatively, setting the threshold to 50 means that the
+ widget will be maximized only if the vertical minimum size hint is at least
+ 50% of the vertical screen size.
- If -1 is specified then this will disable the feature.
+ Setting the threshold to -1 disables the feature.
- On Windows CE the default is -1 (i.e. it is disabled).
+ On Windows CE the default is -1 (i.e., it is disabled).
On Windows Mobile the default is 40.
*/
@@ -1217,9 +1218,9 @@ bool QApplication::compressEvent(QEvent *event, QObject *receiver, QPostEventLis
\since 4.5
\brief toggles automatic SIP (software input panel) visibility
- The auto SIP property is only available as part of Qt for Windows CE.
+ \bold{The auto SIP property is only available as part of Qt for Windows CE.}
- Set this property to true to automatically display the SIP when entering
+ Set this property to \c true to automatically display the SIP when entering
widgets that accept keyboard input. This property only affects widgets with
the WA_InputMethodEnabled attribute set.
*/
@@ -1517,7 +1518,7 @@ int QApplication::colorSpec()
strategy. Use this option if your application uses buttons, menus,
texts and pixmaps with few colors. With this option, the
application uses system global colors. This works fine for most
- applications under X11, but on Windows machines it may cause
+ applications under X11, but on the Windows platform, it may cause
dithering of non-standard colors.
\o QApplication::CustomColor. Use this option if your application
needs a small number of custom colors. On X11, this option is the
@@ -3513,12 +3514,12 @@ void QApplication::changeOverrideCursor(const QCursor &cursor)
We recommend that you connect clean-up code to the
\l{QCoreApplication::}{aboutToQuit()} signal, instead of putting it in your
- application's \c{main()} function because on some platforms the
- QApplication::exec() call may not return. For example, on Windows when the
- user logs off, the system terminates the process after Qt closes all
- top-level windows. Hence, there is no guarantee that the application will
- have time to exit its event loop and execute code at the end of the
- \c{main()} function after the QApplication::exec() call.
+ application's \c{main()} function. This is because, on some platforms the
+ QApplication::exec() call may not return. For example, on the Windows
+ platform, when the user logs off, the system terminates the process after Qt
+ closes all top-level windows. Hence, there is \e{no guarantee} that the
+ application will have time to exit its event loop and execute code at the
+ end of the \c{main()} function, after the QApplication::exec() call.
\sa quitOnLastWindowClosed, quit(), exit(), processEvents(),
QCoreApplication::exec()
@@ -4051,7 +4052,7 @@ bool QApplication::notify(QObject *receiver, QEvent *e)
touchEvent->setAccepted(eventAccepted);
break;
}
- case QEvent::WinGesture:
+ case QEvent::NativeGesture:
{
// only propagate the first gesture event (after the GID_BEGIN)
QWidget *w = static_cast<QWidget *>(receiver);
@@ -4762,7 +4763,7 @@ bool QApplication::keypadNavigationEnabled()
On Mac OS X, this works more at the application level and will cause the
application icon to bounce in the dock.
- On Windows this causes the window's taskbar entry to flash for a time. If
+ On Windows, this causes the window's taskbar entry to flash for a time. If
\a msec is zero, the flashing will stop and the taskbar entry will turn a
different color (currently orange).
@@ -4779,24 +4780,22 @@ bool QApplication::keypadNavigationEnabled()
caret display. Usually the text cursor is displayed for half the cursor
flash time, then hidden for the same amount of time, but this may vary.
- The default value on X11 is 1000 milliseconds. On Windows, the control
- panel value is used. Widgets should not cache this value since it may be
- changed at any time by the user changing the global desktop settings.
+ The default value on X11 is 1000 milliseconds. On Windows, the
+ \gui{Control Panel} value is used and setting this property sets the cursor
+ flash time for all applications.
- \note On Microsoft Windows, setting this property sets the cursor flash
- time for all applications.
+ We recommend that widgets do not cache this value as it may change at any
+ time if the user changes the global desktop settings.
*/
/*!
\property QApplication::doubleClickInterval
- \brief the time limit in milliseconds that distinguishes a double click from two
- consecutive mouse clicks
-
- The default value on X11 is 400 milliseconds. On Windows and Mac OS X, the
- operating system's value is used.
+ \brief the time limit in milliseconds that distinguishes a double click
+ from two consecutive mouse clicks
- On Microsoft Windows, calling this function sets the double click interval
- for all applications.
+ The default value on X11 is 400 milliseconds. On Windows and Mac OS, the
+ operating system's value is used. However, on Windows, calling this
+ function sets the double click interval for all applications.
*/
/*!
@@ -4805,7 +4804,7 @@ bool QApplication::keypadNavigationEnabled()
from two consecutive key presses
\since 4.2
- The default value on X11 is 400 milliseconds. On Windows and Mac OS X, the
+ The default value on X11 is 400 milliseconds. On Windows and Mac OS, the
operating system's value is used.
*/
@@ -4870,7 +4869,7 @@ bool QApplication::keypadNavigationEnabled()
You need not have a main widget; connecting lastWindowClosed() to quit()
is an alternative.
- For X11, this function also resizes and moves the main widget according
+ On X11, this function also resizes and moves the main widget according
to the \e -geometry command-line option, so you should set the default
geometry (using \l QWidget::setGeometry()) before calling setMainWidget().
@@ -4899,9 +4898,10 @@ bool QApplication::keypadNavigationEnabled()
Application cursors are stored on an internal stack. setOverrideCursor()
pushes the cursor onto the stack, and restoreOverrideCursor() pops the
active cursor off the stack. changeOverrideCursor() changes the curently
- active application override cursor. Every setOverrideCursor() must
- eventually be followed by a corresponding restoreOverrideCursor(),
- otherwise the stack will never be emptied.
+ active application override cursor.
+
+ Every setOverrideCursor() must eventually be followed by a corresponding
+ restoreOverrideCursor(), otherwise the stack will never be emptied.
Example:
\snippet doc/src/snippets/code/src_gui_kernel_qapplication_x11.cpp 0
@@ -5082,19 +5082,19 @@ bool QApplicationPrivate::shouldSetFocus(QWidget *w, Qt::FocusPolicy policy)
*/
/*! \fn QDecoration* QApplication::qwsSetDecoration(const QString &decoration)
- \overload
+ \overload
- Requests a QDecoration object for \a decoration from the QDecorationFactory.
+ Requests a QDecoration object for \a decoration from the
+ QDecorationFactory.
- The string must be one of the QDecorationFactory::keys(). Keys are
- case insensitive.
+ The string must be one of the QDecorationFactory::keys(). Keys are case
+ insensitive.
- A later call to the QApplication constructor will override the
- requested style when a "-style" option is passed in as a commandline
- parameter.
+ A later call to the QApplication constructor will override the requested
+ style when a "-style" option is passed in as a commandline parameter.
- Returns 0 if an unknown \a decoration is passed, otherwise the QStyle object
- returned is set as the application's GUI style.
+ Returns 0 if an unknown \a decoration is passed, otherwise the QStyle object
+ returned is set as the application's GUI style.
*/
/*!
diff --git a/src/gui/kernel/qapplication_mac.mm b/src/gui/kernel/qapplication_mac.mm
index beccfb0..ac132aa 100644
--- a/src/gui/kernel/qapplication_mac.mm
+++ b/src/gui/kernel/qapplication_mac.mm
@@ -1480,6 +1480,7 @@ QWidget *QApplicationPrivate::tryModalHelper_sys(QWidget *top)
return top;
}
+#ifndef QT_MAC_USE_COCOA
static bool qt_try_modal(QWidget *widget, EventRef event)
{
QWidget * top = 0;
@@ -1513,6 +1514,7 @@ static bool qt_try_modal(QWidget *widget, EventRef event)
#endif
return !block_event;
}
+#endif
OSStatus QApplicationPrivate::tabletProximityCallback(EventHandlerCallRef, EventRef carbonEvent,
void *)
@@ -2890,52 +2892,25 @@ bool QApplicationPrivate::canQuit()
#endif
}
-void onApplicationWindowChangedActivation( QWidget*widget, bool activated )
+void onApplicationWindowChangedActivation(QWidget *widget, bool activated)
{
#if QT_MAC_USE_COCOA
- QApplication *app = qApp;
+ if (!widget)
+ return;
- if ( activated )
- {
- if (QApplicationPrivate::app_style)
- {
+ if (activated) {
+ if (QApplicationPrivate::app_style) {
QEvent ev(QEvent::Style);
qt_sendSpontaneousEvent(QApplicationPrivate::app_style, &ev);
}
-
- if (widget && app_do_modal && !qt_try_modal(widget, NULL))
- return;
-
- if (widget && widget->window()->isVisible())
- {
- QWidget *tlw = widget->window();
-
- if (tlw->isWindow() && !(tlw->windowType() == Qt::Popup)
- && !qt_mac_is_macdrawer(tlw)
- && (!tlw->parentWidget() || tlw->isModal() || !(tlw->windowType() == Qt::Tool))) {
- bool just_send_event = false;
-#if 0
- WindowActivationScope scope;
- if ( GetWindowActivationScope((OSWindowRef)wid, &scope) == noErr &&
- scope == kWindowActivationScopeIndependent)
- {
- if ( GetFrontWindowOfClass(kAllWindowClasses, true) != wid )
- just_send_event = true;
- }
-#endif
- if (just_send_event) {
- QEvent e(QEvent::WindowActivate);
- qt_sendSpontaneousEvent(widget, &e);
- } else {
- app->setActiveWindow(tlw);
- }
- }
- }
+ qApp->setActiveWindow(widget);
} else { // deactivated
- if (widget && QApplicationPrivate::active_window == widget)
- app->setActiveWindow(0);
+ if (QApplicationPrivate::active_window == widget)
+ qApp->setActiveWindow(0);
}
+
QMenuBar::macUpdateMenuBar();
+
#else
Q_UNUSED(widget);
Q_UNUSED(activated);
diff --git a/src/gui/kernel/qapplication_win.cpp b/src/gui/kernel/qapplication_win.cpp
index d5c820c..2bded5c 100644
--- a/src/gui/kernel/qapplication_win.cpp
+++ b/src/gui/kernel/qapplication_win.cpp
@@ -3735,22 +3735,22 @@ bool QETWidget::translateGestureEvent(const MSG &msg)
alienWidget = 0;
QWidget *widget = alienWidget ? alienWidget : this;
- QWinGestureEvent event;
+ QNativeGestureEvent event;
event.sequenceId = gi.dwSequenceID;
event.position = QPoint(gi.ptsLocation.x, gi.ptsLocation.y);
if (bResult) {
switch (gi.dwID) {
case GID_BEGIN:
- // we are not interested in this type of event.
+ event.gestureType = QNativeGestureEvent::GestureBegin;
break;
case GID_END:
- event.gestureType = QWinGestureEvent::GestureEnd;
+ event.gestureType = QNativeGestureEvent::GestureEnd;
break;
case GID_ZOOM:
- event.gestureType = QWinGestureEvent::Pinch;
+ event.gestureType = QNativeGestureEvent::Pinch;
break;
case GID_PAN:
- event.gestureType = QWinGestureEvent::Pan;
+ event.gestureType = QNativeGestureEvent::Pan;
break;
case GID_ROTATE:
case GID_TWOFINGERTAP:
@@ -3758,7 +3758,7 @@ bool QETWidget::translateGestureEvent(const MSG &msg)
default:
break;
}
- if (event.gestureType != QWinGestureEvent::None)
+ if (event.gestureType != QNativeGestureEvent::None)
qt_sendSpontaneousEvent(widget, &event);
} else {
DWORD dwErr = GetLastError();
diff --git a/src/gui/kernel/qboxlayout.cpp b/src/gui/kernel/qboxlayout.cpp
index 770f5bb..23d20ff 100644
--- a/src/gui/kernel/qboxlayout.cpp
+++ b/src/gui/kernel/qboxlayout.cpp
@@ -527,7 +527,7 @@ void QBoxLayoutPrivate::calcHfw(int w)
You will almost always want to use QVBoxLayout and QHBoxLayout
rather than QBoxLayout because of their convenient constructors.
- \sa QGridLayout, QStackedLayout, {Layout Classes}
+ \sa QGridLayout, QStackedLayout, {Layout Management}
*/
/*!
@@ -1295,7 +1295,7 @@ QBoxLayout::Direction QBoxLayout::direction() const
\image qhboxlayout-with-5-children.png Horizontal box layout with five child widgets
- \sa QVBoxLayout, QGridLayout, QStackedLayout, {Layout Classes}, {Basic Layouts Example}
+ \sa QVBoxLayout, QGridLayout, QStackedLayout, {Layout Management}, {Basic Layouts Example}
*/
@@ -1413,7 +1413,7 @@ QHBoxLayout::~QHBoxLayout()
\image qvboxlayout-with-5-children.png Horizontal box layout with five child widgets
- \sa QHBoxLayout, QGridLayout, QStackedLayout, {Layout Classes}, {Basic Layouts Example}
+ \sa QHBoxLayout, QGridLayout, QStackedLayout, {Layout Management}, {Basic Layouts Example}
*/
/*!
diff --git a/src/gui/kernel/qcocoaview_mac.mm b/src/gui/kernel/qcocoaview_mac.mm
index 57c9117..1d352cb 100644
--- a/src/gui/kernel/qcocoaview_mac.mm
+++ b/src/gui/kernel/qcocoaview_mac.mm
@@ -327,7 +327,7 @@ extern "C" {
return NSDragOperationNone;
} else {
// save the mouse position, used by draggingExited handler.
- DnDParams *dndParams = [QCocoaView currentMouseEvent];
+ DnDParams *dndParams = [QT_MANGLE_NAMESPACE(QCocoaView) currentMouseEvent];
dndParams->activeDragEnterPos = windowPoint;
// send a drag move event immediately after a drag enter event (as per documentation).
QDragMoveEvent qDMEvent(posDrag, qtAllowed, mimeData, QApplication::mouseButtons(), modifiers);
@@ -406,7 +406,7 @@ extern "C" {
dragEnterSequence = -1;
if (qwidget->testAttribute(Qt::WA_TransparentForMouseEvents)) {
// try sending the leave event to the last view which accepted drag enter.
- DnDParams *dndParams = [QCocoaView currentMouseEvent];
+ DnDParams *dndParams = [QT_MANGLE_NAMESPACE(QCocoaView) currentMouseEvent];
NSView *candidateView = [[[self window] contentView] hitTest:dndParams->activeDragEnterPos];
if (candidateView && candidateView != self)
return [candidateView draggingExited:sender];
diff --git a/src/gui/kernel/qcursor.cpp b/src/gui/kernel/qcursor.cpp
index 9cca0d6..0b47b6f 100644
--- a/src/gui/kernel/qcursor.cpp
+++ b/src/gui/kernel/qcursor.cpp
@@ -127,11 +127,11 @@ QT_BEGIN_NAMESPACE
\o Qt::SizeAllCursor \o \c size_all
\row \o \inlineimage cursor-busy.png
\o Qt::BusyCursor \o \c left_ptr_watch
- \o \inlineimage cursor-hsplit.png
+ \o \inlineimage cursor-vsplit.png
\o Qt::SplitVCursor \o \c split_v
\row \o \inlineimage cursor-forbidden.png
\o Qt::ForbiddenCursor \o \c forbidden
- \o \inlineimage cursor-vsplit.png
+ \o \inlineimage cursor-hsplit.png
\o Qt::SplitHCursor \o \c split_h
\row \o \inlineimage cursor-hand.png
\o Qt::PointingHandCursor \o \c pointing_hand
diff --git a/src/gui/kernel/qevent.cpp b/src/gui/kernel/qevent.cpp
index bc3633c..0fc36e7 100644
--- a/src/gui/kernel/qevent.cpp
+++ b/src/gui/kernel/qevent.cpp
@@ -49,7 +49,6 @@
#include "qmime.h"
#include "qdnd_p.h"
#include "qevent_p.h"
-#include "qgesture.h"
QT_BEGIN_NAMESPACE
diff --git a/src/gui/kernel/qevent_p.h b/src/gui/kernel/qevent_p.h
index 67441ea..92c4fc1 100644
--- a/src/gui/kernel/qevent_p.h
+++ b/src/gui/kernel/qevent_p.h
@@ -119,20 +119,30 @@ public:
qreal pressure;
};
-class QWinGestureEvent : public QEvent
+class QNativeGestureEvent : public QEvent
{
public:
enum Type {
None,
+ GestureBegin,
GestureEnd,
Pan,
Pinch
};
- QWinGestureEvent() : QEvent(QEvent::WinGesture), gestureType(None), sequenceId(0) { }
+ QNativeGestureEvent()
+ : QEvent(QEvent::NativeGesture), gestureType(None)
+#ifdef Q_WS_WIN
+ , sequenceId(0)
+#endif
+ {
+ }
+
Type gestureType;
+#ifdef Q_WS_WIN
QPoint position;
ulong sequenceId;
+#endif
};
QT_END_NAMESPACE
diff --git a/src/gui/kernel/qformlayout.cpp b/src/gui/kernel/qformlayout.cpp
index 0b7656f..de33f93 100644
--- a/src/gui/kernel/qformlayout.cpp
+++ b/src/gui/kernel/qformlayout.cpp
@@ -689,16 +689,12 @@ void QFormLayoutPrivate::setupVerticalLayoutData(int width)
// are split.
maxLabelWidth = 0;
if (!wrapAllRows) {
- int maxFieldMinWidth = 0; //the maximum minimum size of the field
for (int i = 0; i < rr; ++i) {
const QFormLayoutItem *label = m_matrix(i, 0);
const QFormLayoutItem *field = m_matrix(i, 1);
- if (label && field && label->sideBySide)
+ if (label && (label->sizeHint.width() + (field ? field->minSize.width() : 0) <= width))
maxLabelWidth = qMax(maxLabelWidth, label->sizeHint.width());
- if (field)
- maxFieldMinWidth = qMax(maxFieldMinWidth, field->minSize.width() + field->sbsHSpace);
}
- maxLabelWidth = qMin(maxLabelWidth, width - maxFieldMinWidth);
} else {
maxLabelWidth = width;
}
diff --git a/src/gui/kernel/qgesture.cpp b/src/gui/kernel/qgesture.cpp
index d53b419..8075ad9 100644
--- a/src/gui/kernel/qgesture.cpp
+++ b/src/gui/kernel/qgesture.cpp
@@ -97,7 +97,7 @@ private:
This is a base class, to create a custom gesture type, you should subclass
it and implement its pure virtual functions.
- \sa QPanGesture, QTapAndHoldGesture
+ \sa QPanGesture
*/
/*! \fn bool QGesture::filterEvent(QEvent *event)
@@ -153,7 +153,7 @@ QGesture::QGesture(QObject *parent)
: QObject(*new QGesturePrivate, parent)
{
if (parent)
- installEventFilter(parent);
+ parent->installEventFilter(this);
}
/*! \internal
@@ -162,7 +162,7 @@ QGesture::QGesture(QGesturePrivate &dd, QObject *parent)
: QObject(dd, parent)
{
if (parent)
- installEventFilter(parent);
+ parent->installEventFilter(this);
}
/*!
@@ -205,51 +205,6 @@ void QGesture::setState(Qt::GestureState state)
}
/*!
- \property QGesture::startPos
-
- \brief The start position of the gesture (if relevant).
-*/
-QPoint QGesture::startPos() const
-{
- return d_func()->startPos;
-}
-
-void QGesture::setStartPos(const QPoint &point)
-{
- d_func()->startPos = point;
-}
-
-/*!
- \property QGesture::lastPos
-
- \brief The last recorded position of the gesture (if relevant).
-*/
-QPoint QGesture::lastPos() const
-{
- return d_func()->lastPos;
-}
-
-void QGesture::setLastPos(const QPoint &point)
-{
- d_func()->lastPos = point;
-}
-
-/*!
- \property QGesture::pos
-
- \brief The current position of the gesture (if relevant).
-*/
-QPoint QGesture::pos() const
-{
- return d_func()->pos;
-}
-
-void QGesture::setPos(const QPoint &point)
-{
- d_func()->pos = point;
-}
-
-/*!
Sets the \a graphicsItem the gesture is filtering events for.
The gesture will install an event filter to the \a graphicsItem and
diff --git a/src/gui/kernel/qgesture.h b/src/gui/kernel/qgesture.h
index 1cd9cae..0735160 100644
--- a/src/gui/kernel/qgesture.h
+++ b/src/gui/kernel/qgesture.h
@@ -64,10 +64,6 @@ class Q_GUI_EXPORT QGesture : public QObject
Q_PROPERTY(Qt::GestureState state READ state)
- Q_PROPERTY(QPoint startPos READ startPos WRITE setStartPos)
- Q_PROPERTY(QPoint lastPos READ lastPos WRITE setLastPos)
- Q_PROPERTY(QPoint pos READ pos WRITE setPos)
-
public:
explicit QGesture(QObject *parent = 0);
~QGesture();
@@ -80,19 +76,13 @@ public:
virtual void reset();
Qt::GestureState state() const;
- void setState(Qt::GestureState state);
-
- QPoint startPos() const;
- void setStartPos(const QPoint &point);
- QPoint lastPos() const;
- void setLastPos(const QPoint &point);
- QPoint pos() const;
- void setPos(const QPoint &point);
protected:
QGesture(QGesturePrivate &dd, QObject *parent);
bool eventFilter(QObject*, QEvent*);
+ void setState(Qt::GestureState state);
+
Q_SIGNALS:
void started();
void triggered();
diff --git a/src/gui/kernel/qgesture_p.h b/src/gui/kernel/qgesture_p.h
index 99f572f..56eaee7 100644
--- a/src/gui/kernel/qgesture_p.h
+++ b/src/gui/kernel/qgesture_p.h
@@ -73,22 +73,11 @@ public:
{
}
- void init(const QPoint &startPos, const QPoint &lastPos,
- const QPoint &pos)
- {
- this->startPos = startPos;
- this->lastPos = lastPos;
- this->pos = pos;
- }
QGraphicsItem *graphicsItem;
QGraphicsItem *eventFilterProxyGraphicsItem;
Qt::GestureState state;
-
- QPoint startPos;
- QPoint lastPos;
- QPoint pos;
};
QT_END_NAMESPACE
diff --git a/src/gui/kernel/qgridlayout.cpp b/src/gui/kernel/qgridlayout.cpp
index 7ac874e..558f570 100644
--- a/src/gui/kernel/qgridlayout.cpp
+++ b/src/gui/kernel/qgridlayout.cpp
@@ -1046,7 +1046,7 @@ QRect QGridLayoutPrivate::cellRect(int row, int col) const
the margin width for a top-level layout, or to the same as the
parent layout.
- \sa QBoxLayout, QStackedLayout, {Layout Classes}, {Basic Layouts Example}
+ \sa QBoxLayout, QStackedLayout, {Layout Management}, {Basic Layouts Example}
*/
diff --git a/src/gui/kernel/qlayout.cpp b/src/gui/kernel/qlayout.cpp
index e750088..941db8f 100644
--- a/src/gui/kernel/qlayout.cpp
+++ b/src/gui/kernel/qlayout.cpp
@@ -83,7 +83,7 @@ static int menuBarHeightForWidth(QWidget *menubar, int w)
For users of QLayout subclasses or of QMainWindow there is seldom
any need to use the basic functions provided by QLayout, such as
- setSizeConstraint() or setMenuBar(). See \l{Layout Classes}
+ setSizeConstraint() or setMenuBar(). See \l{Layout Management}
for more information.
To make your own layout manager, implement the functions
@@ -98,7 +98,7 @@ static int menuBarHeightForWidth(QWidget *menubar, int w)
Geometry management stops when the layout manager is deleted.
- \sa QLayoutItem, {Layout Classes}, {Basic Layouts Example},
+ \sa QLayoutItem, {Layout Management}, {Basic Layouts Example},
{Border Layout Example}, {Flow Layout Example}
*/
diff --git a/src/gui/kernel/qstandardgestures.cpp b/src/gui/kernel/qstandardgestures.cpp
index c8b11c5..4753416 100644
--- a/src/gui/kernel/qstandardgestures.cpp
+++ b/src/gui/kernel/qstandardgestures.cpp
@@ -45,9 +45,14 @@
#include <qabstractscrollarea.h>
#include <qscrollbar.h>
#include <private/qapplication_p.h>
+#include <private/qevent_p.h>
QT_BEGIN_NAMESPACE
+#ifdef Q_WS_WIN
+QApplicationPrivate* getQApplicationPrivateInternal();
+#endif
+
/*!
\class QPanGesture
\since 4.6
@@ -68,7 +73,6 @@ QPanGesture::QPanGesture(QWidget *parent)
{
#ifdef Q_WS_WIN
if (parent) {
- QApplicationPrivate* getQApplicationPrivateInternal();
QApplicationPrivate *qAppPriv = getQApplicationPrivateInternal();
qAppPriv->widgetGestures[parent].pan = this;
}
@@ -93,9 +97,81 @@ bool QPanGesture::event(QEvent *event)
break;
}
#endif
+
+#if defined(Q_OS_MAC) && !defined(QT_MAC_USE_COCOA)
+ Q_D(QPanGesture);
+ if (event->type() == QEvent::Timer) {
+ const QTimerEvent *te = static_cast<QTimerEvent *>(event);
+ if (te->timerId() == d->panFinishedTimer) {
+ killTimer(d->panFinishedTimer);
+ d->panFinishedTimer = 0;
+ d->lastOffset = QSize(0, 0);
+ setState(Qt::GestureFinished);
+ emit triggered();
+ setState(Qt::NoGesture);
+ }
+ }
+#endif
+
return QObject::event(event);
}
+bool QPanGesture::eventFilter(QObject *receiver, QEvent *event)
+{
+#ifdef Q_WS_WIN
+ if (receiver->isWidgetType() && event->type() == QEvent::NativeGesture) {
+ QNativeGestureEvent *ev = static_cast<QNativeGestureEvent*>(event);
+ QApplicationPrivate *qAppPriv = getQApplicationPrivateInternal();
+ QApplicationPrivate::WidgetStandardGesturesMap::iterator it;
+ it = qAppPriv->widgetGestures.find(static_cast<QWidget*>(receiver));
+ if (it == qAppPriv->widgetGestures.end())
+ return false;
+ QPanGesture *gesture = it.value().pan;
+ if (!gesture)
+ return false;
+ Qt::GestureState nextState = state();
+ switch(ev->gestureType) {
+ case QNativeGestureEvent::GestureBegin:
+ // next we might receive the first gesture update event, so we
+ // prepare for it.
+ setState(Qt::GestureStarted);
+ return false;
+ case QNativeGestureEvent::Pan:
+ nextState = Qt::GestureUpdated;
+ break;
+ case QNativeGestureEvent::GestureEnd:
+ if (state() != QNativeGestureEvent::Pan)
+ return false; // some other gesture has ended
+ setState(Qt::GestureFinished);
+ nextState = Qt::GestureFinished;
+ break;
+ default:
+ return false;
+ }
+ QPanGesturePrivate *d = gesture->d_func();
+ if (state() == Qt::GestureStarted) {
+ d->lastPosition = ev->position;
+ d->lastOffset = d->totalOffset = QSize();
+ } else {
+ d->lastOffset = QSize(ev->position.x() - d->lastPosition.x(),
+ ev->position.y() - d->lastPosition.y());
+ d->totalOffset += d->lastOffset;
+ }
+ d->lastPosition = ev->position;
+
+ if (state() == Qt::GestureStarted)
+ emit gesture->started();
+ emit gesture->triggered();
+ if (state() == Qt::GestureFinished)
+ emit gesture->finished();
+ event->accept();
+ gesture->setState(nextState);
+ return true;
+ }
+#endif
+ return QGesture::eventFilter(receiver, event);
+}
+
/*! \internal */
bool QPanGesture::filterEvent(QEvent *event)
{
@@ -104,28 +180,34 @@ bool QPanGesture::filterEvent(QEvent *event)
return false;
const QTouchEvent *ev = static_cast<const QTouchEvent*>(event);
if (event->type() == QEvent::TouchBegin) {
- d->touchPoints = ev->touchPoints();
- const QPoint p = ev->touchPoints().at(0).pos().toPoint();
- setStartPos(p);
- setLastPos(p);
- setPos(p);
- return false;
+ QTouchEvent::TouchPoint p = ev->touchPoints().at(0);
+ d->lastPosition = p.pos().toPoint();
+ d->lastOffset = d->totalOffset = QSize();
} else if (event->type() == QEvent::TouchEnd) {
if (state() != Qt::NoGesture) {
setState(Qt::GestureFinished);
- setLastPos(pos());
- setPos(ev->touchPoints().at(0).pos().toPoint());
+ if (!ev->touchPoints().isEmpty()) {
+ QTouchEvent::TouchPoint p = ev->touchPoints().at(0);
+ const QPoint pos = p.pos().toPoint();
+ const QPoint lastPos = p.lastPos().toPoint();
+ const QPoint startPos = p.startPos().toPoint();
+ d->lastOffset = QSize(pos.x() - lastPos.x(), pos.y() - lastPos.y());
+ d->totalOffset = QSize(pos.x() - startPos.x(), pos.y() - startPos.y());
+ }
emit triggered();
emit finished();
}
setState(Qt::NoGesture);
reset();
} else if (event->type() == QEvent::TouchUpdate) {
- d->touchPoints = ev->touchPoints();
- QPointF pt = d->touchPoints.at(0).pos() - d->touchPoints.at(0).startPos();
- setLastPos(pos());
- setPos(ev->touchPoints().at(0).pos().toPoint());
- if (pt.x() > 10 || pt.y() > 10 || pt.x() < -10 || pt.y() < -10) {
+ QTouchEvent::TouchPoint p = ev->touchPoints().at(0);
+ const QPoint pos = p.pos().toPoint();
+ const QPoint lastPos = p.lastPos().toPoint();
+ const QPoint startPos = p.startPos().toPoint();
+ d->lastOffset = QSize(pos.x() - lastPos.x(), pos.y() - lastPos.y());
+ d->totalOffset = QSize(pos.x() - startPos.x(), pos.y() - startPos.y());
+ if (d->totalOffset.width() > 10 || d->totalOffset.height() > 10 ||
+ d->totalOffset.width() < -10 || d->totalOffset.height() < -10) {
if (state() == Qt::NoGesture)
setState(Qt::GestureStarted);
else
@@ -133,6 +215,36 @@ bool QPanGesture::filterEvent(QEvent *event)
emit triggered();
}
}
+#ifdef Q_OS_MAC
+ else if (event->type() == QEvent::Wheel) {
+ // On Mac, there is really no native panning gesture. Instead, a two
+ // finger pan is delivered as mouse wheel events. Otoh, on Windows, you
+ // either get mouse wheel events or pan events. We have decided to make this
+ // the Qt behaviour as well, meaning that on Mac, wheel
+ // events will be masked away when listening for pan events.
+#ifndef QT_MAC_USE_COCOA
+ // In Carbon we receive neither touch-, nor pan gesture events.
+ // So we create pan gestures by converting wheel events. After all, this
+ // is how things are supposed to work on mac in the first place.
+ const QWheelEvent *wev = static_cast<const QWheelEvent*>(event);
+ int offset = wev->delta() / -120;
+ d->lastOffset = wev->orientation() == Qt::Horizontal ? QSize(offset, 0) : QSize(0, offset);
+
+ if (state() == Qt::NoGesture) {
+ setState(Qt::GestureStarted);
+ d->totalOffset = d->lastOffset;
+ } else {
+ setState(Qt::GestureUpdated);
+ d->totalOffset += d->lastOffset;
+ }
+
+ killTimer(d->panFinishedTimer);
+ d->panFinishedTimer = startTimer(200);
+ emit triggered();
+#endif
+ return true;
+ }
+#endif
return false;
}
@@ -140,7 +252,14 @@ bool QPanGesture::filterEvent(QEvent *event)
void QPanGesture::reset()
{
Q_D(QPanGesture);
- d->touchPoints.clear();
+ d->lastOffset = d->totalOffset = QSize();
+ d->lastPosition = QPoint();
+#if defined(Q_OS_MAC) && !defined(QT_MAC_USE_COCOA)
+ if (d->panFinishedTimer) {
+ killTimer(d->panFinishedTimer);
+ d->panFinishedTimer = 0;
+ }
+#endif
}
/*!
@@ -150,8 +269,8 @@ void QPanGesture::reset()
*/
QSize QPanGesture::totalOffset() const
{
- QPoint pt = pos() - startPos();
- return QSize(pt.x(), pt.y());
+ Q_D(const QPanGesture);
+ return d->totalOffset;
}
/*!
@@ -162,93 +281,11 @@ QSize QPanGesture::totalOffset() const
*/
QSize QPanGesture::lastOffset() const
{
- QPoint pt = pos() - lastPos();
- return QSize(pt.x(), pt.y());
-}
-
-/*!
- \class QTapAndHoldGesture
- \since 4.6
-
- \brief The QTapAndHoldGesture class represents a Tap-and-Hold gesture,
- providing additional information.
-*/
-
-const int QTapAndHoldGesturePrivate::iterationCount = 40;
-const int QTapAndHoldGesturePrivate::iterationTimeout = 50;
-
-/*!
- Creates a new Tap and Hold gesture handler object and marks it as a child
- of \a parent.
-
- On some platforms like Windows there is a system-wide tap and hold gesture
- that cannot be overriden, hence the gesture might never trigger and default
- context menu will be shown instead.
-*/
-QTapAndHoldGesture::QTapAndHoldGesture(QWidget *parent)
- : QGesture(*new QTapAndHoldGesturePrivate, parent)
-{
-}
-
-/*! \internal */
-bool QTapAndHoldGesture::filterEvent(QEvent *event)
-{
- Q_D(QTapAndHoldGesture);
- if (!event->spontaneous())
- return false;
- const QTouchEvent *ev = static_cast<const QTouchEvent*>(event);
- switch (event->type()) {
- case QEvent::TouchBegin: {
- if (d->timer.isActive())
- d->timer.stop();
- d->timer.start(QTapAndHoldGesturePrivate::iterationTimeout, this);
- const QPoint p = ev->touchPoints().at(0).pos().toPoint();
- setStartPos(p);
- setLastPos(p);
- setPos(p);
- break;
- }
- case QEvent::TouchUpdate:
- if (ev->touchPoints().size() != 1)
- reset();
- else if ((startPos() - ev->touchPoints().at(0).pos().toPoint()).manhattanLength() > 15)
- reset();
- break;
- case QEvent::TouchEnd:
- reset();
- break;
- default:
- break;
- }
- return false;
+ Q_D(const QPanGesture);
+ return d->lastOffset;
}
-/*! \internal */
-void QTapAndHoldGesture::timerEvent(QTimerEvent *event)
-{
- Q_D(QTapAndHoldGesture);
- if (event->timerId() != d->timer.timerId())
- return;
- if (d->iteration == QTapAndHoldGesturePrivate::iterationCount) {
- d->timer.stop();
- setState(Qt::GestureFinished);
- emit triggered();
- } else {
- setState(Qt::GestureStarted);
- emit triggered();
- }
- ++d->iteration;
-}
+QT_END_NAMESPACE
-/*! \internal */
-void QTapAndHoldGesture::reset()
-{
- Q_D(QTapAndHoldGesture);
- if (state() != Qt::NoGesture)
- emit cancelled();
- setState(Qt::NoGesture);
- d->timer.stop();
- d->iteration = 0;
-}
+#include "moc_qstandardgestures.cpp"
-QT_END_NAMESPACE
diff --git a/src/gui/kernel/qstandardgestures.h b/src/gui/kernel/qstandardgestures.h
index 2234702..c734fba 100644
--- a/src/gui/kernel/qstandardgestures.h
+++ b/src/gui/kernel/qstandardgestures.h
@@ -71,29 +71,13 @@ public:
QSize totalOffset() const;
QSize lastOffset() const;
-protected:
+private:
bool event(QEvent *event);
+ bool eventFilter(QObject *receiver, QEvent *event);
-private:
friend class QWidget;
};
-class QTapAndHoldGesturePrivate;
-class Q_GUI_EXPORT QTapAndHoldGesture : public QGesture
-{
- Q_OBJECT
- Q_DECLARE_PRIVATE(QTapAndHoldGesture)
-
-public:
- QTapAndHoldGesture(QWidget *parent);
-
- bool filterEvent(QEvent *event);
- void reset();
-
-protected:
- void timerEvent(QTimerEvent *event);
-};
-
QT_END_NAMESPACE
QT_END_HEADER
diff --git a/src/gui/kernel/qstandardgestures_p.h b/src/gui/kernel/qstandardgestures_p.h
index bb11c9f..0fe24ee 100644
--- a/src/gui/kernel/qstandardgestures_p.h
+++ b/src/gui/kernel/qstandardgestures_p.h
@@ -60,6 +60,8 @@
#include "qgesture.h"
#include "qgesture_p.h"
+#include "qstandardgestures.h"
+
QT_BEGIN_NAMESPACE
class QPanGesturePrivate : public QGesturePrivate
@@ -67,23 +69,20 @@ class QPanGesturePrivate : public QGesturePrivate
Q_DECLARE_PUBLIC(QPanGesture)
public:
- QPanGesturePrivate() { }
-
- QList<QTouchEvent::TouchPoint> touchPoints;
-};
+ QPanGesturePrivate()
+ {
+#if defined(Q_OS_MAC) && !defined(QT_MAC_USE_COCOA)
+ panFinishedTimer = 0;
+#endif
+ }
-class QTapAndHoldGesturePrivate : public QGesturePrivate
-{
- Q_DECLARE_PUBLIC(QTapAndHoldGesture)
-
-public:
- QTapAndHoldGesturePrivate()
- : iteration(0) { }
+ QSize totalOffset;
+ QSize lastOffset;
+ QPoint lastPosition;
- QBasicTimer timer;
- int iteration;
- static const int iterationCount;
- static const int iterationTimeout;
+#if defined(Q_OS_MAC) && !defined(QT_MAC_USE_COCOA)
+ int panFinishedTimer;
+#endif
};
QT_END_NAMESPACE
diff --git a/src/gui/kernel/qwidget.cpp b/src/gui/kernel/qwidget.cpp
index 7026525..a827967 100644
--- a/src/gui/kernel/qwidget.cpp
+++ b/src/gui/kernel/qwidget.cpp
@@ -505,7 +505,7 @@ void QWidget::setAutoFillBackground(bool enabled)
been outlined to indicate their full sizes.
If you want to use a QWidget to hold child widgets you will usually want to
- add a layout to the parent QWidget. See \l{Layout Classes} for more
+ add a layout to the parent QWidget. See \l{Layout Management} for more
information.
@@ -1375,6 +1375,11 @@ QWidget::~QWidget()
// set all QPointers for this object to zero
QObjectPrivate::clearGuards(this);
+ if (d->declarativeData) {
+ d->declarativeData->destroyed(this);
+ d->declarativeData = 0; // don't activate again in ~QObject
+ }
+
if (!d->children.isEmpty())
d->deleteChildren();
@@ -3491,11 +3496,16 @@ bool QWidgetPrivate::setMinimumSize_helper(int &minw, int &minh)
minh = qMax(minh, 0);
}
createExtra();
- if (extra->minw == minw && extra->minh == minh)
+ int mw = minw, mh = minh;
+ if (mw == QWIDGETSIZE_MAX)
+ mw = 0;
+ if (mh == QWIDGETSIZE_MAX)
+ mh = 0;
+ if (extra->minw == mw && extra->minh == mh)
return false;
- extra->minw = minw;
- extra->minh = minh;
- extra->explicitMinSize = (minw ? Qt::Horizontal : 0) | (minh ? Qt::Vertical : 0);
+ extra->minw = mw;
+ extra->minh = mh;
+ extra->explicitMinSize = (mw ? Qt::Horizontal : 0) | (mh ? Qt::Vertical : 0);
return true;
}
@@ -3555,7 +3565,8 @@ bool QWidgetPrivate::setMaximumSize_helper(int &maxw, int &maxh)
return false;
extra->maxw = maxw;
extra->maxh = maxh;
- extra->explicitMaxSize = (maxw != QWIDGETSIZE_MAX ? Qt::Horizontal : 0) | (maxh != QWIDGETSIZE_MAX ? Qt::Vertical : 0);
+ extra->explicitMaxSize = (maxw != QWIDGETSIZE_MAX ? Qt::Horizontal : 0) |
+ (maxh != QWIDGETSIZE_MAX ? Qt::Vertical : 0);
return true;
}
@@ -3634,6 +3645,8 @@ void QWidget::setBaseSize(int basew, int baseh)
This will override the default size constraints set by QLayout.
+ To remove constraints, set the size to QWIDGETSIZE_MAX.
+
Alternatively, if you want the widget to have a
fixed size based on its contents, you can call
QLayout::setSizeConstraint(QLayout::SetFixedSize);
@@ -3675,7 +3688,8 @@ void QWidget::setFixedSize(int w, int h)
else
d->updateGeometry_helper(true);
- resize(w, h);
+ if (w != QWIDGETSIZE_MAX || h != QWIDGETSIZE_MAX)
+ resize(w, h);
}
void QWidget::setMinimumWidth(int w)
@@ -7925,59 +7939,6 @@ bool QWidget::event(QEvent *event)
(void) QApplication::sendEvent(this, &mouseEvent);
break;
}
-#ifdef Q_WS_WIN
- case QEvent::WinGesture: {
- QWinGestureEvent *ev = static_cast<QWinGestureEvent*>(event);
- QApplicationPrivate *qAppPriv = qApp->d_func();
- QApplicationPrivate::WidgetStandardGesturesMap::iterator it;
- it = qAppPriv->widgetGestures.find(this);
- if (it != qAppPriv->widgetGestures.end()) {
- Qt::GestureState state = Qt::GestureUpdated;
- if (qAppPriv->lastGestureId == 0)
- state = Qt::GestureStarted;
- QWinGestureEvent::Type type = ev->gestureType;
- if (ev->gestureType == QWinGestureEvent::GestureEnd) {
- type = (QWinGestureEvent::Type)qAppPriv->lastGestureId;
- state = Qt::GestureFinished;
- }
-
- QGesture *gesture = 0;
- switch (type) {
- case QWinGestureEvent::Pan: {
- QPanGesture *pan = it.value().pan;
- gesture = pan;
- if (state == Qt::GestureStarted) {
- gesture->setStartPos(ev->position);
- gesture->setLastPos(ev->position);
- } else {
- gesture->setLastPos(gesture->pos());
- }
- gesture->setPos(ev->position);
- break;
- }
- case QWinGestureEvent::Pinch:
- break;
- default:
- break;
- }
- if (gesture) {
- gesture->setState(state);
- if (state == Qt::GestureStarted)
- emit gesture->started();
- emit gesture->triggered();
- if (state == Qt::GestureFinished)
- emit gesture->finished();
- event->accept();
- }
- if (ev->gestureType == QWinGestureEvent::GestureEnd) {
- qAppPriv->lastGestureId = 0;
- } else {
- qAppPriv->lastGestureId = type;
- }
- }
- break;
- }
-#endif
#ifndef QT_NO_PROPERTIES
case QEvent::DynamicPropertyChange: {
const QByteArray &propName = static_cast<QDynamicPropertyChangeEvent *>(event)->propertyName();
@@ -8854,7 +8815,7 @@ QRegion QWidget::mask() const
The layout manager sets the geometry of the widget's children
that have been added to the layout.
- \sa setLayout(), sizePolicy(), {Layout Classes}
+ \sa setLayout(), sizePolicy(), {Layout Management}
*/
QLayout *QWidget::layout() const
{
@@ -8884,7 +8845,7 @@ QLayout *QWidget::layout() const
The QWidget will take ownership of \a layout.
- \sa layout(), {Layout Classes}
+ \sa layout(), {Layout Management}
*/
void QWidget::setLayout(QLayout *l)
@@ -9850,6 +9811,10 @@ void QWidget::setAttribute(Qt::WidgetAttribute attribute, bool on)
data->window_modality = (w && w->testAttribute(Qt::WA_GroupLeader))
? Qt::WindowModal
: Qt::ApplicationModal;
+ // Some window managers does not allow us to enter modal after the
+ // window is showing. Therefore, to be consistent, we cannot call
+ // QApplicationPrivate::enterModal(this) here. The window must be
+ // hidden before changing modality.
}
if (testAttribute(Qt::WA_WState_Created)) {
// don't call setModal_sys() before create_sys()
diff --git a/src/gui/kernel/qwidget_mac.mm b/src/gui/kernel/qwidget_mac.mm
index 70eea3a..78df09d 100644
--- a/src/gui/kernel/qwidget_mac.mm
+++ b/src/gui/kernel/qwidget_mac.mm
@@ -3100,7 +3100,12 @@ void QWidgetPrivate::update_sys(const QRegion &rgn)
return;
dirtyOnWidget += rgn;
#ifndef QT_MAC_USE_COCOA
- HIViewSetNeedsDisplayInRegion(qt_mac_nativeview_for(q), QMacSmartQuickDrawRegion(rgn.toQDRgn()), true);
+ RgnHandle rgnHandle = rgn.toQDRgnForUpdate_sys();
+ if (rgnHandle)
+ HIViewSetNeedsDisplayInRegion(qt_mac_nativeview_for(q), QMacSmartQuickDrawRegion(rgnHandle), true);
+ else {
+ HIViewSetNeedsDisplay(qt_mac_nativeview_for(q), true); // do a complete repaint on overflow.
+ }
#else
// Cocoa doesn't do regions, it seems more efficient to just update the bounding rect instead of a potential number of message passes for each rect.
const QRect &boundingRect = rgn.boundingRect();
@@ -4584,6 +4589,7 @@ void QWidgetPrivate::setModal_sys()
OSWindowRef windowRef = qt_mac_window_for(q);
#ifdef QT_MAC_USE_COCOA
+ QMacCocoaAutoReleasePool pool;
bool alreadySheet = [windowRef styleMask] & NSDocModalWindowMask;
if (windowParent && q->windowModality() == Qt::WindowModal){
@@ -4660,31 +4666,40 @@ void QWidgetPrivate::setModal_sys()
|| (primaryWindow && primaryWindow->windowModality() == Qt::WindowModal)){
// Window should be window-modal (which implies a sheet).
if (old_wclass != kSheetWindowClass){
- // We cannot convert a created window to a sheet. So we recreate the window:
+ // We cannot convert a created window to a sheet.
+ // So we recreate the window:
recreateMacWindow();
return;
}
- } else if (!(q->data->window_flags & Qt::CustomizeWindowHint)) {
- if (old_wclass == kDocumentWindowClass || old_wclass == kFloatingWindowClass || old_wclass == kUtilityWindowClass){
- // Only change the class to kMovableModalWindowClass if the no explicit jewels
- // are set (kMovableModalWindowClass can't contain them), and the current window class
- // can be converted to modal (according to carbon doc). Mind the order of
- // HIWindowChangeClass and ChangeWindowAttributes.
- WindowGroupRef group = GetWindowGroup(windowRef);
- HIWindowChangeClass(windowRef, kMovableModalWindowClass);
- quint32 tmpWattr = kWindowCloseBoxAttribute | kWindowHorizontalZoomAttribute;
- ChangeWindowAttributes(windowRef, tmpWattr, kWindowNoAttributes);
- ChangeWindowAttributes(windowRef, kWindowNoAttributes, tmpWattr);
- // If the window belongs to a qt-created group, set that group once more:
- if (data.window_flags & Qt::WindowStaysOnTopHint
- || q->windowType() == Qt::Popup
- || q->windowType() == Qt::ToolTip)
- SetWindowGroup(windowRef, group);
+ } else {
+ // Window should be application-modal (which implies NOT using a sheet).
+ if (old_wclass == kSheetWindowClass){
+ // We cannot convert a sheet to a window.
+ // So we recreate the window:
+ recreateMacWindow();
+ return;
+ } else if (!(q->data->window_flags & Qt::CustomizeWindowHint)) {
+ if (old_wclass == kDocumentWindowClass || old_wclass == kFloatingWindowClass || old_wclass == kUtilityWindowClass){
+ // Only change the class to kMovableModalWindowClass if the no explicit jewels
+ // are set (kMovableModalWindowClass can't contain them), and the current window class
+ // can be converted to modal (according to carbon doc). Mind the order of
+ // HIWindowChangeClass and ChangeWindowAttributes.
+ WindowGroupRef group = GetWindowGroup(windowRef);
+ HIWindowChangeClass(windowRef, kMovableModalWindowClass);
+ quint32 tmpWattr = kWindowCloseBoxAttribute | kWindowHorizontalZoomAttribute;
+ ChangeWindowAttributes(windowRef, tmpWattr, kWindowNoAttributes);
+ ChangeWindowAttributes(windowRef, kWindowNoAttributes, tmpWattr);
+ // If the window belongs to a qt-created group, set that group once more:
+ if (data.window_flags & Qt::WindowStaysOnTopHint
+ || q->windowType() == Qt::Popup
+ || q->windowType() == Qt::ToolTip)
+ SetWindowGroup(windowRef, group);
+ }
+ // Popups are usually handled "special" and are never modal.
+ Qt::WindowType winType = q->windowType();
+ if (winType != Qt::Popup && winType != Qt::ToolTip)
+ SetWindowModality(windowRef, kWindowModalityAppModal, 0);
}
- // Popups are usually handled "special" and are never modal.
- Qt::WindowType winType = q->windowType();
- if (winType != Qt::Popup && winType != Qt::ToolTip)
- SetWindowModality(windowRef, kWindowModalityAppModal, 0);
}
} else if (windowRef) {
if (old_wclass == kSheetWindowClass){
diff --git a/src/gui/kernel/qwidget_win.cpp b/src/gui/kernel/qwidget_win.cpp
index 46fa3be..b11b661 100644
--- a/src/gui/kernel/qwidget_win.cpp
+++ b/src/gui/kernel/qwidget_win.cpp
@@ -467,6 +467,17 @@ void QWidgetPrivate::create_sys(WId window, bool initializeWindow, bool destroyO
}
}
+ if (topLevel) {
+ if (data.window_flags & Qt::CustomizeWindowHint
+ && data.window_flags & Qt::WindowTitleHint) {
+ HMENU systemMenu = GetSystemMenu((HWND)q->internalWinId(), FALSE);
+ if (data.window_flags & Qt::WindowCloseButtonHint)
+ EnableMenuItem(systemMenu, SC_CLOSE, MF_BYCOMMAND|MF_ENABLED);
+ else
+ EnableMenuItem(systemMenu, SC_CLOSE, MF_BYCOMMAND|MF_GRAYED);
+ }
+ }
+
q->setAttribute(Qt::WA_WState_Created); // accept move/resize events
hd = 0; // no display context
@@ -638,16 +649,6 @@ void QWidgetPrivate::setParent_sys(QWidget *parent, Qt::WindowFlags f)
|| (!q->isWindow() && q->parentWidget() && q->parentWidget()->testAttribute(Qt::WA_DropSiteRegistered)))
q->setAttribute(Qt::WA_DropSiteRegistered, true);
-
- if (data.window_flags & Qt::CustomizeWindowHint
- && data.window_flags & Qt::WindowTitleHint) {
- HMENU systemMenu = GetSystemMenu((HWND)q->internalWinId(), FALSE);
- if (data.window_flags & Qt::WindowCloseButtonHint)
- EnableMenuItem(systemMenu, SC_CLOSE, MF_BYCOMMAND|MF_ENABLED);
- else
- EnableMenuItem(systemMenu, SC_CLOSE, MF_BYCOMMAND|MF_GRAYED);
- }
-
#ifdef Q_WS_WINCE
// Show borderless toplevel windows in tasklist & NavBar
if (!parent) {
@@ -1431,10 +1432,7 @@ void QWidgetPrivate::setGeometry_sys(int x, int y, int w, int h, bool isMove)
qt_wince_maximize(q);
} else {
#endif
- if (!isTranslucentWindow)
- MoveWindow(q->internalWinId(), fs.x(), fs.y(), fs.width(), fs.height(), true);
- else if (isMove && !isResize)
- SetWindowPos(q->internalWinId(), 0, fs.x(), fs.y(), 0, 0, SWP_NOACTIVATE | SWP_NOSIZE | SWP_NOZORDER);
+ MoveWindow(q->internalWinId(), fs.x(), fs.y(), fs.width(), fs.height(), true);
}
if (!q->isVisible())
InvalidateRect(q->internalWinId(), 0, FALSE);
@@ -1524,6 +1522,11 @@ bool QWidgetPrivate::shouldShowMaximizeButton()
{
if (data.window_flags & Qt::MSWindowsFixedSizeDialogHint)
return false;
+ // if the user explicitely asked for the maximize button, we try to add
+ // it even if the window has fixed size.
+ if (data.window_flags & Qt::CustomizeWindowHint &&
+ data.window_flags & Qt::WindowMaximizeButtonHint)
+ return true;
if (extra) {
if ((extra->maxw && extra->maxw != QWIDGETSIZE_MAX && extra->maxw != QLAYOUTSIZE_MAX)
|| (extra->maxh && extra->maxh != QWIDGETSIZE_MAX && extra->maxh != QLAYOUTSIZE_MAX))
diff --git a/src/gui/painting/painting.pri b/src/gui/painting/painting.pri
index 34d1779..d226be2 100644
--- a/src/gui/painting/painting.pri
+++ b/src/gui/painting/painting.pri
@@ -100,8 +100,8 @@ win32 {
painting/qcolormap_win.cpp \
painting/qpaintdevice_win.cpp \
painting/qprintengine_win.cpp \
- painting/qprinterinfo_win.cpp \
- painting/qregion_win.cpp
+ painting/qprinterinfo_win.cpp
+
!win32-borland:!wince*:LIBS += -lmsimg32
}
@@ -126,10 +126,6 @@ embedded {
painting/qwindowsurface_raster.cpp \
}
-wince* {
- SOURCES -= painting/qregion_win.cpp
-}
-
unix:x11 {
HEADERS += \
painting/qpaintengine_x11_p.h
diff --git a/src/gui/painting/qblendfunctions.cpp b/src/gui/painting/qblendfunctions.cpp
index 831d389..fc2eb60 100644
--- a/src/gui/painting/qblendfunctions.cpp
+++ b/src/gui/painting/qblendfunctions.cpp
@@ -223,8 +223,8 @@ void qt_scale_image_16bit(uchar *destPixels, int dbpl,
int h = ty2 - ty1;
int w = tx2 - tx1;
- const int dstx = int((tx1 + 0.5 - qMin(targetRect.left(), targetRect.right())) * ix);
- const int dsty = int((ty1 + 0.5 - qMin(targetRect.top(), targetRect.bottom())) * iy);
+ const int dstx = qCeil((tx1 + 0.5 - qMin(targetRect.left(), targetRect.right())) * ix) - 1;
+ const int dsty = qCeil((ty1 + 0.5 - qMin(targetRect.top(), targetRect.bottom())) * iy) - 1;
quint32 basex = quint32((sx < 0 ? srcRect.right() : srcRect.left()) * 65536) + dstx;
quint32 srcy = quint32((sy < 0 ? srcRect.bottom() : srcRect.top()) * 65536) + dsty;
@@ -723,8 +723,8 @@ template <typename T> void qt_scale_image_32bit(uchar *destPixels, int dbpl,
int h = ty2 - ty1;
int w = tx2 - tx1;
- const int dstx = int((tx1 + 0.5 - qMin(targetRect.left(), targetRect.right())) * ix);
- const int dsty = int((ty1 + 0.5 - qMin(targetRect.top(), targetRect.bottom())) * iy);
+ const int dstx = qCeil((tx1 + 0.5 - qMin(targetRect.left(), targetRect.right())) * ix) - 1;
+ const int dsty = qCeil((ty1 + 0.5 - qMin(targetRect.top(), targetRect.bottom())) * iy) - 1;
quint32 basex = quint32((sx < 0 ? srcRect.right() : srcRect.left()) * 65536) + dstx;
quint32 srcy = quint32((sy < 0 ? srcRect.bottom() : srcRect.top()) * 65536) + dsty;
diff --git a/src/gui/painting/qdatabuffer_p.h b/src/gui/painting/qdatabuffer_p.h
index b568f43..275ec13 100644
--- a/src/gui/painting/qdatabuffer_p.h
+++ b/src/gui/painting/qdatabuffer_p.h
@@ -114,23 +114,6 @@ public:
qSwap(buffer, other.buffer);
}
- inline void insertBlank(int pos, int count) {
- Q_ASSERT(pos >= 0);
- Q_ASSERT(pos < siz);
- reserve(siz + count);
- for (int i = siz - pos - 1; i >= 0; --i)
- buffer[pos + count + i] = buffer[pos + i];
- siz += count;
- }
-
- inline void removeAndShift(int pos, int count) {
- Q_ASSERT(pos >= 0);
- Q_ASSERT(pos < siz);
- for (int i=pos; i<siz-count; ++i)
- buffer[i] = buffer[i+count];
- siz -= count;
- }
-
inline QDataBuffer &operator<<(const Type &t) { add(t); return *this; }
private:
diff --git a/src/gui/painting/qdrawhelper.cpp b/src/gui/painting/qdrawhelper.cpp
index 979390a..b6603e4 100644
--- a/src/gui/painting/qdrawhelper.cpp
+++ b/src/gui/painting/qdrawhelper.cpp
@@ -4794,30 +4794,60 @@ Q_STATIC_TEMPLATE_FUNCTION void blendTiled(int count, const QSpan *spans, void *
if (sy < 0)
sy += image_height;
- while (length) {
- int l = qMin(image_width - sx, length);
- if (buffer_size < l)
- l = buffer_size;
-
- DST *dest = ((DST*)data->rasterBuffer->scanLine(spans->y)) + x;
- const SRC *src = (SRC*)data->texture.scanLine(sy) + sx;
- if (modeSource && coverage == 255) {
+ if (modeSource && coverage == 255) {
+ // Copy the first texture block
+ length = image_width;
+ while (length) {
+ int l = qMin(image_width - sx, length);
+ if (buffer_size < l)
+ l = buffer_size;
+ DST *dest = ((DST*)data->rasterBuffer->scanLine(spans->y)) + x;
+ const SRC *src = (SRC*)data->texture.scanLine(sy) + sx;
qt_memconvert<DST, SRC>(dest, src, l);
- } else if (sizeof(DST) == 3 && sizeof(SRC) == 3 && l >= 4 &&
- (quintptr(dest) & 3) == (quintptr(src) & 3))
- {
- blendUntransformed_dest24(dest, src, coverage, l);
- } else if (sizeof(DST) == 2 && sizeof(SRC) == 2 && l >= 2 &&
- (quintptr(dest) & 3) == (quintptr(src) & 3))
- {
- blendUntransformed_dest16(dest, src, coverage, l);
- } else {
- blendUntransformed_unaligned(dest, src, coverage, l);
+ length -= l;
+ sx = 0;
}
- x += l;
- length -= l;
- sx = 0;
+ // Now use the rasterBuffer as the source of the texture,
+ // We can now progressively copy larger blocks
+ // - Less cpu time in code figuring out what to copy
+ // We are dealing with one block of data
+ // - More likely to fit in the cache
+ // - can use memcpy
+ int copy_image_width = image_width;
+ length = spans->len - image_width;
+ DST *src = ((DST*)data->rasterBuffer->scanLine(spans->y)) + x;
+ DST *dest = src + copy_image_width;
+ while (copy_image_width < length) {
+ qt_memconvert(dest, src, copy_image_width);
+ dest += copy_image_width;
+ length -= copy_image_width;
+ copy_image_width *= 2;
+ }
+ qt_memconvert(dest, src, length);
+ } else {
+ while (length) {
+ int l = qMin(image_width - sx, length);
+ if (buffer_size < l)
+ l = buffer_size;
+ DST *dest = ((DST*)data->rasterBuffer->scanLine(spans->y)) + x;
+ const SRC *src = (SRC*)data->texture.scanLine(sy) + sx;
+ if (sizeof(DST) == 3 && sizeof(SRC) == 3 && l >= 4 &&
+ (quintptr(dest) & 3) == (quintptr(src) & 3))
+ {
+ blendUntransformed_dest24(dest, src, coverage, l);
+ } else if (sizeof(DST) == 2 && sizeof(SRC) == 2 && l >= 2 &&
+ (quintptr(dest) & 3) == (quintptr(src) & 3))
+ {
+ blendUntransformed_dest16(dest, src, coverage, l);
+ } else {
+ blendUntransformed_unaligned(dest, src, coverage, l);
+ }
+
+ x += l;
+ length -= l;
+ sx = 0;
+ }
}
++spans;
}
diff --git a/src/gui/painting/qoutlinemapper.cpp b/src/gui/painting/qoutlinemapper.cpp
index 9c073f2..1287672 100644
--- a/src/gui/painting/qoutlinemapper.cpp
+++ b/src/gui/painting/qoutlinemapper.cpp
@@ -40,7 +40,6 @@
****************************************************************************/
#include "qoutlinemapper_p.h"
-#include "qbezier_p.h"
#include "qmath.h"
@@ -199,70 +198,30 @@ void QOutlineMapper::endOutline()
m_m22 * e.y() + m_m12 * e.x() + m_dy);
}
} else {
- // ## TODO: this case needs to be plain code polygonal paths
- QTransform matrix(m_m11, m_m12, m_m13, m_m21, m_m22, m_m23, m_dx, m_dy, m_m33);
-
- if (m_element_types.isEmpty()) {
- if (!m_elements.isEmpty())
- m_elements_dev << m_elements.at(0) * matrix;
- for (int i=1; i<m_elements.size(); ++i)
- m_elements_dev << m_elements.at(i) * matrix;
-
- } else {
- for (int i=0, t=0; i<m_elements.size(); ++i) {
- switch (m_element_types.at(t)) {
- case QPainterPath::MoveToElement:
- m_elements_dev << m_elements.at(i) * matrix;
- ++t;
- break;
- case QPainterPath::LineToElement:
- m_elements_dev << m_elements.at(i) * matrix;
- ++t;
- break;
- case QPainterPath::CurveToElement: {
- QPolygonF segment = QBezier::fromPoints(m_elements.at(i-1),
- m_elements.at(i),
- m_elements.at(i+1),
- m_elements.at(i+2)).toPolygon();
- if (segment.size() > 3)
- m_element_types.insertBlank(t, segment.size() - 3);
- else if (segment.size() < 3)
- m_element_types.removeAndShift(t, 3 - segment.size());
-
- for (QPolygonF::const_iterator it = segment.constBegin();
- it < segment.constEnd(); ++it, ++t) {
- m_elements_dev << *it * matrix;
- m_element_types.at(t) = QPainterPath::LineToElement;
- }
- i += 2;
- } break;
- default:
- Q_ASSERT(false);
- break;
- }
- }
- element_count = m_elements_dev.size();
- }
+ const QVectorPath vp((qreal *)m_elements.data(), m_elements.size(), m_element_types.data());
+ QPainterPath path = vp.convertToPainterPath();
+ path = QTransform(m_m11, m_m12, m_m13, m_m21, m_m22, m_m23, m_dx, m_dy, m_m33).map(path);
+ if (!(m_outline.flags & QT_FT_OUTLINE_EVEN_ODD_FILL))
+ path.setFillRule(Qt::WindingFill);
+ uint old_txop = m_txop;
+ m_txop = QTransform::TxNone;
+ if (path.isEmpty())
+ m_valid = false;
+ else
+ convertPath(path);
+ m_txop = old_txop;
+ return;
}
elements = m_elements_dev.data();
}
if (m_round_coords) {
// round coordinates to match outlines drawn with drawLine_midpoint_i
- for (int i = 0; i < element_count; ++i)
+ for (int i = 0; i < m_elements.size(); ++i)
elements[i] = QPointF(qFloor(elements[i].x() + aliasedCoordinateDelta),
qFloor(elements[i].y() + aliasedCoordinateDelta));
}
-#ifdef QT_DEBUG_CONVERT
- for (int i=0; i<element_count; ++i) {
- printf("%d: (%.2f, %.2f)\n",
- !m_element_types.isEmpty() ? m_element_types.at(i) : -1,
- elements[i].x(),
- elements[i].y());
- }
-#endif
-
controlPointRect = boundingRect(elements, element_count);
#ifdef QT_DEBUG_CONVERT
diff --git a/src/gui/painting/qpaintengine_raster.cpp b/src/gui/painting/qpaintengine_raster.cpp
index 69e490a..74456dd 100644
--- a/src/gui/painting/qpaintengine_raster.cpp
+++ b/src/gui/painting/qpaintengine_raster.cpp
@@ -1736,6 +1736,8 @@ void QRasterPaintEngine::stroke(const QVectorPath &path, const QPen &pen)
const QLineF *lines = reinterpret_cast<const QLineF *>(path.points());
for (int i = 0; i < lineCount; ++i) {
+ if (path.shape() == QVectorPath::LinesHint)
+ dashOffset = s->lastPen.dashOffset();
if (lines[i].p1() == lines[i].p2()) {
if (s->lastPen.capStyle() != Qt::FlatCap) {
QPointF p = lines[i].p1();
@@ -3454,8 +3456,8 @@ void QRasterPaintEngine::drawLines(const QLine *lines, int lineCount)
int m22 = int(s->matrix.m22());
int dx = qFloor(s->matrix.dx() + aliasedCoordinateDelta);
int dy = qFloor(s->matrix.dy() + aliasedCoordinateDelta);
- int dashOffset = int(s->lastPen.dashOffset());
for (int i=0; i<lineCount; ++i) {
+ int dashOffset = int(s->lastPen.dashOffset());
if (s->flags.int_xform) {
const QLine &l = lines[i];
int x1 = l.x1() * m11 + dx;
@@ -3554,8 +3556,8 @@ void QRasterPaintEngine::drawLines(const QLineF *lines, int lineCount)
? LineDrawNormal
: LineDrawIncludeLastPixel;
- int dashOffset = int(s->lastPen.dashOffset());
for (int i=0; i<lineCount; ++i) {
+ int dashOffset = int(s->lastPen.dashOffset());
QLineF line = (lines[i] * s->matrix).translated(aliasedCoordinateDelta, aliasedCoordinateDelta);
const QRectF brect(QPointF(line.x1(), line.y1()),
QPointF(line.x2(), line.y2()));
diff --git a/src/gui/painting/qpaintengineex.cpp b/src/gui/painting/qpaintengineex.cpp
index 8ec881e..ed9b858 100644
--- a/src/gui/painting/qpaintengineex.cpp
+++ b/src/gui/painting/qpaintengineex.cpp
@@ -421,7 +421,6 @@ void QPaintEngineEx::stroke(const QVectorPath &path, const QPen &pen)
const qreal *lastPoint = points + (pointCount<<1);
- d->activeStroker->begin(d->strokeHandler);
d->strokeHandler->types.reset();
d->strokeHandler->pts.reset();
@@ -430,13 +429,13 @@ void QPaintEngineEx::stroke(const QVectorPath &path, const QPen &pen)
if (d->stroker.capStyle() == Qt::RoundCap || d->stroker.joinStyle() == Qt::RoundJoin)
flags |= QVectorPath::CurvedShapeHint;
- // ### Perspective Xforms are currently not supported...
qreal txscale = 1;
if (!(pen.isCosmetic() || (qt_scaleForTransform(state()->matrix, &txscale) && txscale != 1))) {
// We include cosmetic pens in this case to avoid having to
// change the current transform. Normal transformed,
// non-cosmetic pens will be transformed as part of fill
// later, so they are also covered here..
+ d->activeStroker->begin(d->strokeHandler);
if (types) {
while (points < lastPoint) {
switch (*types) {
@@ -491,79 +490,64 @@ void QPaintEngineEx::stroke(const QVectorPath &path, const QPen &pen)
const qreal strokeWidth = d->stroker.strokeWidth();
d->stroker.setStrokeWidth(strokeWidth * txscale);
// For cosmetic pens we need a bit of trickery... We to process xform the input points
- if (types) {
- bool isProject = state()->matrix.type() >= QTransform::TxProject;
- while (points < lastPoint) {
- switch (*types) {
- case QPainterPath::MoveToElement: {
- QPointF pt = (*(QPointF *) points) * state()->matrix;
- d->activeStroker->moveTo(pt.x(), pt.y());
- points += 2;
- ++types;
- break;
- }
- case QPainterPath::LineToElement: {
- QPointF pt = (*(QPointF *) points) * state()->matrix;
- d->activeStroker->lineTo(pt.x(), pt.y());
- points += 2;
- ++types;
- break;
- }
- case QPainterPath::CurveToElement: {
- // Convert projective xformed curves to line
- // segments so they can be transformed more
- // accurately
- if (isProject) {
- // -1 access here is safe because there is
- // always an element prior to the cubicTo, we
- // just need the value..
- QPolygonF segment =
- QBezier::fromPoints(*(((QPointF *) points) - 1),
- *((QPointF *) points),
- *(((QPointF *) points) + 1),
- *(((QPointF *) points) + 2)).toPolygon();
-
- for (QPolygonF::const_iterator it = segment.constBegin();
- it < segment.constEnd(); ++it) {
- const QPointF pt = *it * state()->matrix;
- d->activeStroker->lineTo(pt.x(), pt.y());
- }
- } else {
+ if (state()->matrix.type() >= QTransform::TxProject) {
+ QPainterPath painterPath = state()->matrix.map(path.convertToPainterPath());
+ d->activeStroker->strokePath(painterPath, d->strokeHandler, QTransform());
+ } else {
+ d->activeStroker->begin(d->strokeHandler);
+ if (types) {
+ while (points < lastPoint) {
+ switch (*types) {
+ case QPainterPath::MoveToElement: {
+ QPointF pt = (*(QPointF *) points) * state()->matrix;
+ d->activeStroker->moveTo(pt.x(), pt.y());
+ points += 2;
+ ++types;
+ break;
+ }
+ case QPainterPath::LineToElement: {
+ QPointF pt = (*(QPointF *) points) * state()->matrix;
+ d->activeStroker->lineTo(pt.x(), pt.y());
+ points += 2;
+ ++types;
+ break;
+ }
+ case QPainterPath::CurveToElement: {
QPointF c1 = ((QPointF *) points)[0] * state()->matrix;
QPointF c2 = ((QPointF *) points)[1] * state()->matrix;
QPointF e = ((QPointF *) points)[2] * state()->matrix;
d->activeStroker->cubicTo(c1.x(), c1.y(), c2.x(), c2.y(), e.x(), e.y());
+ points += 6;
+ types += 3;
+ flags |= QVectorPath::CurvedShapeHint;
+ break;
+ }
+ default:
+ break;
}
- points += 6;
- types += 3;
- flags |= QVectorPath::CurvedShapeHint;
- break;
}
- default:
- break;
+ if (path.hasImplicitClose()) {
+ QPointF pt = * ((QPointF *) path.points()) * state()->matrix;
+ d->activeStroker->lineTo(pt.x(), pt.y());
}
- }
- if (path.hasImplicitClose()) {
- QPointF pt = * ((QPointF *) path.points()) * state()->matrix;
- d->activeStroker->lineTo(pt.x(), pt.y());
- }
- } else {
- QPointF p = ((QPointF *)points)[0] * state()->matrix;
- d->activeStroker->moveTo(p.x(), p.y());
- points += 2;
- ++types;
- while (points < lastPoint) {
+ } else {
QPointF p = ((QPointF *)points)[0] * state()->matrix;
- d->activeStroker->lineTo(p.x(), p.y());
+ d->activeStroker->moveTo(p.x(), p.y());
points += 2;
++types;
+ while (points < lastPoint) {
+ QPointF p = ((QPointF *)points)[0] * state()->matrix;
+ d->activeStroker->lineTo(p.x(), p.y());
+ points += 2;
+ ++types;
+ }
+ if (path.hasImplicitClose())
+ d->activeStroker->lineTo(p.x(), p.y());
}
- if (path.hasImplicitClose())
- d->activeStroker->lineTo(p.x(), p.y());
+ d->activeStroker->end();
}
- d->activeStroker->end();
d->stroker.setStrokeWidth(strokeWidth);
QVectorPath strokePath(d->strokeHandler->pts.data(),
d->strokeHandler->types.size(),
diff --git a/src/gui/painting/qpainter.cpp b/src/gui/painting/qpainter.cpp
index 9c7a7fa..8192fb7 100644
--- a/src/gui/painting/qpainter.cpp
+++ b/src/gui/painting/qpainter.cpp
@@ -1672,7 +1672,7 @@ bool QPainter::begin(QPaintDevice *pd)
if (!d->engine) {
qWarning("QPainter::begin: Paint device returned engine == 0, type: %d", pd->devType());
- return true;
+ return false;
}
// Slip a painter state into the engine before we do any other operations
diff --git a/src/gui/painting/qregion.cpp b/src/gui/painting/qregion.cpp
index 762e9e0..d59f3ff 100644
--- a/src/gui/painting/qregion.cpp
+++ b/src/gui/painting/qregion.cpp
@@ -49,7 +49,7 @@
#include <qdebug.h>
-#if defined(Q_OS_UNIX) || defined(Q_OS_WINCE)
+#if defined(Q_OS_UNIX) || defined(Q_WS_WIN)
#include "qimage.h"
#include "qbitmap.h"
#include <stdlib.h>
@@ -545,7 +545,7 @@ QRegion& QRegion::operator|=(const QRegion &r)
\sa intersected()
*/
-#if !defined (Q_OS_UNIX) && !defined (Q_OS_WINCE)
+#if !defined (Q_OS_UNIX) && !defined (Q_WS_WIN)
QRegion& QRegion::operator+=(const QRect &r)
{
return operator+=(QRegion(r));
@@ -561,16 +561,14 @@ QRegion& QRegion::operator+=(const QRect &r)
\sa intersected()
*/
-#if !defined(Q_WS_WIN) || defined(Q_OS_WINCE)
QRegion& QRegion::operator&=(const QRegion &r)
{ return *this = *this & r; }
-#endif
/*!
\overload
\since 4.4
*/
-#if defined (Q_OS_UNIX) || defined (Q_OS_WINCE)
+#if defined (Q_OS_UNIX) || defined (Q_WS_WIN)
QRegion& QRegion::operator&=(const QRect &r)
{
return *this = *this & r;
@@ -591,10 +589,8 @@ QRegion& QRegion::operator&=(const QRect &r)
\sa subtracted()
*/
-#if !defined(Q_WS_WIN) || defined(Q_OS_WINCE)
QRegion& QRegion::operator-=(const QRegion &r)
{ return *this = *this - r; }
-#endif
/*!
Applies the xored() function to this region and \a r and
@@ -731,7 +727,7 @@ bool QRegion::intersects(const QRect &rect) const
return false;
}
-#if !defined (Q_OS_UNIX) && !defined (Q_OS_WINCE)
+#if !defined (Q_OS_UNIX) && !defined (Q_WS_WIN)
/*!
\overload
\since 4.4
@@ -1086,7 +1082,7 @@ Q_AUTOTEST_EXPORT QPainterPath qt_regionToPath(const QRegion &region)
return result;
}
-#if defined(Q_OS_UNIX) || defined(Q_OS_WINCE)
+#if defined(Q_OS_UNIX) || defined(Q_WS_WIN)
//#define QT_REGION_DEBUG
/*
@@ -1627,9 +1623,9 @@ QT_END_INCLUDE_NAMESPACE
QT_BEGIN_INCLUDE_NAMESPACE
# include "qregion_mac.cpp"
QT_END_INCLUDE_NAMESPACE
-#elif defined(Q_OS_WINCE)
+#elif defined(Q_WS_WIN)
QT_BEGIN_INCLUDE_NAMESPACE
-# include "qregion_wince.cpp"
+# include "qregion_win.cpp"
QT_END_INCLUDE_NAMESPACE
#elif defined(Q_WS_QWS)
static QRegionPrivate qrp;
@@ -3829,7 +3825,7 @@ QRegion::QRegion(const QRect &r, RegionType t)
#if defined(Q_WS_X11)
d->rgn = 0;
d->xrectangles = 0;
-#elif defined(Q_OS_WINCE)
+#elif defined(Q_WS_WIN)
d->rgn = 0;
#endif
if (t == Rectangle) {
@@ -3851,7 +3847,7 @@ QRegion::QRegion(const QPolygon &a, Qt::FillRule fillRule)
#if defined(Q_WS_X11)
d->rgn = 0;
d->xrectangles = 0;
-#elif defined(Q_OS_WINCE)
+#elif defined(Q_WS_WIN)
d->rgn = 0;
#endif
d->qt_rgn = PolygonRegion(a.constData(), a.size(),
@@ -3881,7 +3877,7 @@ QRegion::QRegion(const QBitmap &bm)
#if defined(Q_WS_X11)
d->rgn = 0;
d->xrectangles = 0;
-#elif defined(Q_OS_WINCE)
+#elif defined(Q_WS_WIN)
d->rgn = 0;
#endif
d->qt_rgn = qt_bitmapToRegion(bm);
@@ -3896,7 +3892,7 @@ void QRegion::cleanUp(QRegion::QRegionData *x)
XDestroyRegion(x->rgn);
if (x->xrectangles)
free(x->xrectangles);
-#elif defined(Q_OS_WINCE)
+#elif defined(Q_WS_WIN)
if (x->rgn)
qt_win_dispose_rgn(x->rgn);
#endif
@@ -3932,7 +3928,7 @@ QRegion QRegion::copy() const
#if defined(Q_WS_X11)
x->rgn = 0;
x->xrectangles = 0;
-#elif defined(Q_OS_WINCE)
+#elif defined(Q_WS_WIN)
x->rgn = 0;
#endif
if (d->qt_rgn)
diff --git a/src/gui/painting/qregion.h b/src/gui/painting/qregion.h
index bfedcb1..84024ce 100644
--- a/src/gui/painting/qregion.h
+++ b/src/gui/painting/qregion.h
@@ -59,7 +59,7 @@ QT_MODULE(Gui)
template <class T> class QVector;
class QVariant;
-#if defined(Q_WS_QWS) || defined(Q_WS_X11) || defined(Q_WS_MAC) || defined(Q_OS_WINCE)
+#if defined(Q_WS_QWS) || defined(Q_WS_X11) || defined(Q_WS_MAC) || defined(Q_WS_WIN)
struct QRegionPrivate;
#endif
@@ -148,6 +148,7 @@ public:
#elif defined(Q_WS_MAC)
#if defined Q_WS_MAC32
RgnHandle toQDRgn() const;
+ RgnHandle toQDRgnForUpdate_sys() const;
static QRegion fromQDRgn(RgnHandle shape);
#endif
#ifdef QT_MAC_USE_COCOA
@@ -199,7 +200,7 @@ private:
#elif defined(Q_WS_MAC) && !defined(QT_MAC_USE_COCOA)
mutable RgnHandle unused; // Here for binary compatability reasons. ### Qt 5 remove.
#endif
-#if defined(Q_WS_QWS) || defined(Q_WS_X11) || defined(Q_WS_MAC) || defined(Q_OS_WINCE)
+#if defined(Q_WS_QWS) || defined(Q_WS_X11) || defined(Q_WS_MAC) || defined(Q_WS_WIN)
QRegionPrivate *qt_rgn;
#endif
};
diff --git a/src/gui/painting/qregion_mac.cpp b/src/gui/painting/qregion_mac.cpp
index b57f234..6fe7805 100644
--- a/src/gui/painting/qregion_mac.cpp
+++ b/src/gui/painting/qregion_mac.cpp
@@ -155,6 +155,43 @@ RgnHandle QRegion::toQDRgn() const
}
return rgnHandle;
}
+
+/*!
+ \internal
+ Create's a RegionHandle, it's the caller's responsibility to release.
+ Returns 0 if the QRegion overflows.
+*/
+RgnHandle QRegion::toQDRgnForUpdate_sys() const
+{
+ RgnHandle rgnHandle = qt_mac_get_rgn();
+ if(d->qt_rgn && d->qt_rgn->numRects) {
+ RgnHandle tmp_rgn = qt_mac_get_rgn();
+ int n = d->qt_rgn->numRects;
+ const QRect *qt_r = (n == 1) ? &d->qt_rgn->extents : d->qt_rgn->rects.constData();
+ while (n--) {
+
+ // detect overflow. Tested for use with HIViewSetNeedsDisplayInRegion
+ // in QWidgetPrivate::update_sys().
+ enum { HIViewSetNeedsDisplayInRegionOverflow = 10000 }; // empirically determined conservative value
+ if (qt_r->right() > HIViewSetNeedsDisplayInRegionOverflow || qt_r->bottom() > HIViewSetNeedsDisplayInRegionOverflow) {
+ qt_mac_dispose_rgn(tmp_rgn);
+ qt_mac_dispose_rgn(rgnHandle);
+ return 0;
+ }
+
+ SetRectRgn(tmp_rgn,
+ qMax(SHRT_MIN, qt_r->x()),
+ qMax(SHRT_MIN, qt_r->y()),
+ qMin(SHRT_MAX, qt_r->right() + 1),
+ qMin(SHRT_MAX, qt_r->bottom() + 1));
+ UnionRgn(rgnHandle, tmp_rgn, rgnHandle);
+ ++qt_r;
+ }
+ qt_mac_dispose_rgn(tmp_rgn);
+ }
+ return rgnHandle;
+}
+
#endif
#if (MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_5)
diff --git a/src/gui/painting/qregion_win.cpp b/src/gui/painting/qregion_win.cpp
index 249b1a6..8708461 100644
--- a/src/gui/painting/qregion_win.cpp
+++ b/src/gui/painting/qregion_win.cpp
@@ -39,22 +39,20 @@
**
****************************************************************************/
+#include "qatomic.h"
#include "qbitmap.h"
#include "qbuffer.h"
#include "qimage.h"
#include "qpolygon.h"
#include "qregion.h"
#include "qt_windows.h"
+#include "qpainterpath.h"
+#include "qguifunctions_wince.h"
QT_BEGIN_NAMESPACE
+QRegion::QRegionData QRegion::shared_empty = { Q_BASIC_ATOMIC_INITIALIZER(1), 0, 0 };
-/*
- In Windows versions before Windows Vista CreateRectRgn - when called in a multi-threaded
- environment - might return an invalid handle. This function works around this limitation
- by verifying the handle with a quick GetRegionData() call and re-creates the region
- if necessary.
-*/
HRGN qt_tryCreateRegion(QRegion::RegionType type, int left, int top, int right, int bottom)
{
const int tries = 10;
@@ -80,497 +78,73 @@ HRGN qt_tryCreateRegion(QRegion::RegionType type, int left, int top, int right,
return 0;
}
-#ifndef Q_OS_WINCE
-HRGN qt_tryCreatePolygonRegion(const QPolygon &a, Qt::FillRule fillRule)
-{
- const int tries = 10;
- for (int i = 0; i < tries; ++i) {
- HRGN region = CreatePolygonRgn(reinterpret_cast<const POINT*>(a.data()), a.size(),
- fillRule == Qt::OddEvenFill ? ALTERNATE : WINDING);
- if (region) {
- if (GetRegionData(region, 0, 0))
- return region;
- else
- DeleteObject(region);
- }
- }
- return 0;
-}
-#endif
-
-QRegion::QRegionData QRegion::shared_empty = { Q_BASIC_ATOMIC_INITIALIZER(1), 0 };
-
-QRegion::QRegion()
- : d(&shared_empty)
-{
- d->ref.ref();
-}
-
-#ifndef Q_OS_WINCE //implementation for WindowsCE in qregion_wce.cpp
-QRegion::QRegion(const QRect &r, RegionType t)
-{
- if (r.isEmpty()) {
- d = &shared_empty;
- d->ref.ref();
- } else {
- d = new QRegionData;
- d->ref = 1;
- if (t == Rectangle)
- d->rgn = qt_tryCreateRegion(t, r.left(), r.top(), r.x() + r.width(), r.y() + r.height());
- else if (t == Ellipse) {
- // need to add 1 to width/height for the ellipse to have correct boundingrect.
- d->rgn = qt_tryCreateRegion(t, r.x(), r.y(), r.x() + r.width() + 1, r.y() + r.height() + 1);
- }
- }
-}
-#endif
-
-#ifndef Q_OS_WINCE //implementation for WindowsCE in qregion_wce.cpp
-QRegion::QRegion(const QPolygon &a, Qt::FillRule fillRule)
-{
- if (a.size() < 3) {
- d = &shared_empty;
- d->ref.ref();
- } else {
- d = new QRegionData;
- d->ref = 1;
- d->rgn = qt_tryCreatePolygonRegion(a, fillRule);
- }
-}
-#endif
-
-QRegion::QRegion(const QRegion &r)
-{
- d = r.d;
- d->ref.ref();
-}
-
-HRGN qt_win_bitmapToRegion(const QBitmap& bitmap)
-{
- HRGN region=0;
- QImage image = bitmap.toImage();
- const int MAXRECT = 256;
- struct RData {
- RGNDATAHEADER header;
- RECT rect[MAXRECT];
- };
- RData data;
-
-#define FlushSpans \
- { \
- data.header.dwSize = sizeof(RGNDATAHEADER); \
- data.header.iType = RDH_RECTANGLES; \
- data.header.nCount = n; \
- data.header.nRgnSize = 0; \
- data.header.rcBound.bottom = y; \
- HRGN r = ExtCreateRegion(0, \
- sizeof(RGNDATAHEADER)+n*sizeof(RECT),(RGNDATA*)&data); \
- if (region) { \
- CombineRgn(region, region, r, RGN_OR); \
- DeleteObject(r); \
- } else { \
- region = r; \
- } \
- data.header.rcBound.top = y; \
- }
-
-#define AddSpan \
- { \
- data.rect[n].left=prev1; \
- data.rect[n].top=y; \
- data.rect[n].right=x-1+1; \
- data.rect[n].bottom=y+1; \
- n++; \
- if (n == MAXRECT) { \
- FlushSpans \
- n=0; \
- } \
- }
-
- data.header.rcBound.top = 0;
- data.header.rcBound.left = 0;
- data.header.rcBound.right = image.width()-1;
- int n = 0;
-
- int zero = 0x00;
-
- int x, y;
- for (y = 0; y < image.height(); ++y) {
- uchar *line = image.scanLine(y);
- int w = image.width();
- uchar all=zero;
- int prev1 = -1;
- for (x = 0; x < w;) {
- uchar byte = line[x/8];
- if (x > w - 8 || byte != all) {
- for (int b = 8; b > 0 && x < w; --b) {
- if (!(byte & 0x01) == !all) {
- // More of the same
- } else {
- // A change.
- if (all != zero) {
- AddSpan;
- all = zero;
- } else {
- prev1 = x;
- all = ~zero;
- }
- }
- byte >>= 1;
- ++x;
- }
- } else {
- x += 8;
- }
- }
- if (all != zero) {
- AddSpan;
- }
- }
- if (n) {
- FlushSpans;
- }
-
- if (!region) {
- // Surely there is some better way.
- region = qt_tryCreateRegion(QRegion::Rectangle, 0,0,1,1);
- CombineRgn(region, region, region, RGN_XOR);
- }
- return region;
-}
-
-#ifndef Q_OS_WINCE //implementation for WindowsCE in qregion_wce.cpp
-QRegion::QRegion(const QBitmap &bm)
-{
- if (bm.isNull()) {
- d = &shared_empty;
- d->ref.ref();
- } else {
- d = new QRegionData;
- d->ref = 1;
- d->rgn = qt_win_bitmapToRegion(bm);
- }
-}
-#endif
-
-void QRegion::cleanUp(QRegion::QRegionData *x)
-{
- if (x->rgn)
- DeleteObject(x->rgn);
- delete x;
-}
-
-QRegion::~QRegion()
-{
- if (!d->ref.deref())
- cleanUp(d);
-}
-
-QRegion &QRegion::operator=(const QRegion &r)
-{
- r.d->ref.ref();
- if (!d->ref.deref())
- cleanUp(d);
- d = r.d;
- return *this;
-}
-
-
-QRegion QRegion::copy() const
-{
- QRegion r;
- QRegionData *x = new QRegionData;
- x->ref = 1;
- if (d->rgn) {
- x->rgn = qt_tryCreateRegion(QRegion::Rectangle, 0, 0, 2, 2);
- CombineRgn(x->rgn, d->rgn, 0, RGN_COPY);
- } else {
- x->rgn = 0;
- }
- if (!r.d->ref.deref())
- cleanUp(r.d);
- r.d = x;
- return r;
-}
-
-bool QRegion::isEmpty() const
-{
- return (d == &shared_empty || boundingRect().isEmpty());
-}
-
-
-bool QRegion::contains(const QPoint &p) const
-{
- return d->rgn ? PtInRegion(d->rgn, p.x(), p.y()) : false;
-}
-
-bool QRegion::contains(const QRect &r) const
-{
- if (!d->rgn)
- return false;
- RECT rect;
- SetRect(&rect, r.left(), r.top(), r.right(), r.bottom());
- return RectInRegion(d->rgn, &rect);
-}
-
-
-void QRegion::translate(int dx, int dy)
-{
- if (!d->rgn || (dx == 0 && dy == 0))
- return;
- detach();
- OffsetRgn(d->rgn, dx, dy);
-}
-
-
-#define RGN_NOP -1
-
-// Duplicates of those in qregion.cpp
-#define QRGN_OR 6
-#define QRGN_AND 7
-#define QRGN_SUB 8
-#define QRGN_XOR 9
-
-/*
- Performs the actual OR, AND, SUB and XOR operation between regions.
- Sets the resulting region handle to 0 to indicate an empty region.
-*/
-
-QRegion QRegion::winCombine(const QRegion &r, int op) const
+QRegion qt_region_from_HRGN(HRGN rgn)
{
- int both=RGN_NOP,
- left=RGN_NOP,
- right=RGN_NOP;
- switch (op) {
- case QRGN_OR:
- both = RGN_OR;
- left = right = RGN_COPY;
- break;
- case QRGN_AND:
- both = RGN_AND;
- break;
- case QRGN_SUB:
- both = RGN_DIFF;
- left = RGN_COPY;
- break;
- case QRGN_XOR:
- both = RGN_XOR;
- left = right = RGN_COPY;
- break;
- default:
- qWarning("QRegion: Internal error in winCombine");
- }
-
- int allCombineRgnResults = NULLREGION;
- QRegion result;
- result.detach();
- result.d->rgn = qt_tryCreateRegion(QRegion::Rectangle, 0, 0, 0, 0);
- if (d->rgn && r.d->rgn)
- allCombineRgnResults = CombineRgn(result.d->rgn, d->rgn, r.d->rgn, both);
- else if (d->rgn && left != RGN_NOP)
- allCombineRgnResults = CombineRgn(result.d->rgn, d->rgn, d->rgn, left);
- else if (r.d->rgn && right != RGN_NOP)
- allCombineRgnResults = CombineRgn(result.d->rgn, r.d->rgn, r.d->rgn, right);
-
- if (allCombineRgnResults == NULLREGION || allCombineRgnResults == ERROR)
- result = QRegion();
-
- //##### do not delete this. A null pointer is different from an empty region in SelectClipRgn in qpainter_win! (M)
-// if (allCombineRgnResults == NULLREGION) {
-// if (result.data->rgn)
-// DeleteObject(result.data->rgn);
-// result.data->rgn = 0; // empty region
-// }
- return result;
-}
-
-QRegion QRegion::unite(const QRegion &r) const
-{
- if (!d->rgn)
- return r;
- if (!r.d->rgn)
- return *this;
- return winCombine(r, QRGN_OR);
-}
-
-QRegion QRegion::unite(const QRect &r) const
-{
- return unite(QRegion(r));
-}
-
-QRegion QRegion::intersect(const QRegion &r) const
-{
- if (!r.d->rgn || !d->rgn)
- return QRegion();
- return winCombine(r, QRGN_AND);
-}
-
-QRegion QRegion::subtract(const QRegion &r) const
-{
- if (!r.d->rgn || !d->rgn)
- return *this;
- return winCombine(r, QRGN_SUB);
-}
-
-QRegion QRegion::eor(const QRegion &r) const
-{
- if (!d->rgn)
- return r;
- if (!r.d->rgn)
- return *this;
- return winCombine(r, QRGN_XOR);
-}
-
-
-QRect QRegion::boundingRect() const
-{
- if (!d->rgn)
- return QRect();
- RECT r;
- if (GetRgnBox(d->rgn, &r) == NULLREGION)
- return QRect();
- else
- return QRect(r.left, r.top, r.right - r.left, r.bottom - r.top);
-}
-
-QVector<QRect> QRegion::rects() const
-{
- if (d->rgn == 0)
- return QVector<QRect>();
-
- int numBytes = GetRegionData(d->rgn, 0, 0);
+ int numBytes = GetRegionData(rgn, 0, 0);
if (numBytes == 0)
- return QVector<QRect>();
+ return QRegion();
char *buf = new char[numBytes];
if (buf == 0)
- return QVector<QRect>();
+ return QRegion();
RGNDATA *rd = reinterpret_cast<RGNDATA*>(buf);
- if (GetRegionData(d->rgn, numBytes, rd) == 0) {
+ if (GetRegionData(rgn, numBytes, rd) == 0) {
delete [] buf;
- return QVector<QRect>();
+ return QRegion();
}
- QVector<QRect> a(rd->rdh.nCount);
+ QRegion region;
RECT *r = reinterpret_cast<RECT*>(rd->Buffer);
- for (int i = 0; i < a.size(); ++i) {
- a[i].setCoords(r->left, r->top, r->right - 1, r->bottom - 1);
+ for (uint i = 0; i < rd->rdh.nCount; ++i) {
+ QRect rect;
+ rect.setCoords(r->left, r->top, r->right - 1, r->bottom - 1);
++r;
+ region |= rect;
}
delete [] buf;
- return a;
-}
-
-void QRegion::setRects(const QRect *rects, int num)
-{
- *this = QRegion();
- if (!rects || num == 0 || (num == 1 && rects->isEmpty()))
- return;
- for (int i = 0; i < num; ++i)
- *this |= rects[i];
-}
-
-int QRegion::numRects() const
-{
- if (d->rgn == 0)
- return 0;
-
- const int numBytes = GetRegionData(d->rgn, 0, 0);
- if (numBytes == 0)
- return 0;
-
- char *buf = new char[numBytes];
- if (buf == 0)
- return 0;
-
- RGNDATA *rd = reinterpret_cast<RGNDATA*>(buf);
- if (GetRegionData(d->rgn, numBytes, rd) == 0) {
- delete[] buf;
- return 0;
- }
-
- const int n = rd->rdh.nCount;
- delete[] buf;
- return n;
+ return region;
}
-bool QRegion::operator==(const QRegion &r) const
+void qt_win_dispose_rgn(HRGN r)
{
- if (d == r.d)
- return true;
- if ((d->rgn == 0) ^ (r.d->rgn == 0)) // one is empty, not both
- return false;
- return d->rgn == 0 ? true // both empty
- : EqualRgn(d->rgn, r.d->rgn); // both non-empty
+ if (r)
+ DeleteObject(r);
}
-QRegion& QRegion::operator+=(const QRegion &r)
+static void qt_add_rect(HRGN &winRegion, QRect r)
{
- if (!r.d->rgn)
- return *this;
-
- if (!d->rgn) {
- *this = r;
- return *this;
+ HRGN rgn = CreateRectRgn(r.left(), r.top(), r.x() + r.width(), r.y() + r.height());
+ if (rgn) {
+ HRGN dest = CreateRectRgn(0,0,0,0);
+ int result = CombineRgn(dest, winRegion, rgn, RGN_OR);
+ if (result) {
+ DeleteObject(winRegion);
+ winRegion = dest;
+ }
+ DeleteObject(rgn);
}
-
- detach();
-
- int result;
- result = CombineRgn(d->rgn, d->rgn, r.d->rgn, RGN_OR);
- if (result == NULLREGION || result == ERROR)
- *this = QRegion();
-
- return *this;
-}
-
-QRegion& QRegion::operator-=(const QRegion &r)
-{
- if (!r.d->rgn || !d->rgn)
- return *this;
-
- detach();
-
- int result;
- result = CombineRgn(d->rgn, d->rgn, r.d->rgn, RGN_DIFF);
- if (result == NULLREGION || result == ERROR)
- *this = QRegion();
-
- return *this;
}
-QRegion& QRegion::operator&=(const QRegion &r)
+void QRegion::ensureHandle() const
{
- if (!d->rgn)
- return *this;
-
- if (!r.d->rgn) {
- *this = QRegion();
- return *this;
+ if (d->rgn)
+ DeleteObject(d->rgn);
+ d->rgn = CreateRectRgn(0,0,0,0);
+ if (d->qt_rgn) {
+ if (d->qt_rgn->numRects == 1) {
+ QRect r = d->qt_rgn->extents;
+ qt_add_rect(d->rgn, r);
+ return;
+ }
+ for (int i = 0;i < d->qt_rgn->numRects;i++) {
+ QRect r = d->qt_rgn->rects.at(i);
+ qt_add_rect(d->rgn, r);
+ }
}
-
- detach();
-
- int result;
- result = CombineRgn(d->rgn, d->rgn, r.d->rgn, RGN_AND);
- if (result == NULLREGION || result == ERROR)
- *this = QRegion();
-
- return *this;
-}
-
-bool qt_region_strictContains(const QRegion &region, const QRect &rect)
-{
- Q_UNUSED(region);
- Q_UNUSED(rect);
- return false;
}
-void QRegion::ensureHandle() const
-{
-}
QT_END_NAMESPACE
diff --git a/src/gui/painting/qtransform.cpp b/src/gui/painting/qtransform.cpp
index a322fe4..a13b494 100644
--- a/src/gui/painting/qtransform.cpp
+++ b/src/gui/painting/qtransform.cpp
@@ -48,6 +48,8 @@
#include "qvariant.h"
#include <qmath.h>
+#include <private/qbezier_p.h>
+
QT_BEGIN_NAMESPACE
#define Q_NEAR_CLIP 0.000001
@@ -1492,27 +1494,12 @@ static inline bool lineTo_clipped(QPainterPath &path, const QTransform &transfor
static inline bool cubicTo_clipped(QPainterPath &path, const QTransform &transform, const QPointF &a, const QPointF &b, const QPointF &c, const QPointF &d, bool needsMoveTo)
{
- const QHomogeneousCoordinate ha = mapHomogeneous(transform, a);
- const QHomogeneousCoordinate hb = mapHomogeneous(transform, b);
- const QHomogeneousCoordinate hc = mapHomogeneous(transform, c);
- const QHomogeneousCoordinate hd = mapHomogeneous(transform, d);
-
- if (ha.w < Q_NEAR_CLIP && hb.w < Q_NEAR_CLIP && hc.w < Q_NEAR_CLIP && hd.w < Q_NEAR_CLIP)
- return false;
+ // Convert projective xformed curves to line
+ // segments so they can be transformed more accurately
+ QPolygonF segment = QBezier::fromPoints(a, b, c, d).toPolygon();
- if (ha.w >= Q_NEAR_CLIP && hb.w >= Q_NEAR_CLIP && hc.w >= Q_NEAR_CLIP && hd.w >= Q_NEAR_CLIP) {
- if (needsMoveTo)
- path.moveTo(ha.toPoint());
-
- path.cubicTo(hb.toPoint(), hc.toPoint(), hd.toPoint());
- return true;
- }
-
- if (lineTo_clipped(path, transform, a, b, needsMoveTo))
- needsMoveTo = false;
- if (lineTo_clipped(path, transform, b, c, needsMoveTo))
- needsMoveTo = false;
- if (lineTo_clipped(path, transform, c, d, needsMoveTo))
+ for (int i = 0; i < segment.size() - 1; ++i)
+ if (lineTo_clipped(path, transform, segment.at(i), segment.at(i+1), needsMoveTo))
needsMoveTo = false;
return !needsMoveTo;
@@ -1554,6 +1541,7 @@ static QPainterPath mapProjective(const QTransform &transform, const QPainterPat
if (path.elementCount() > 0 && lastMoveTo != last)
lineTo_clipped(result, transform, last, lastMoveTo, needsMoveTo, false);
+ result.setFillRule(path.fillRule());
return result;
}
@@ -1793,6 +1781,14 @@ void QTransform::setMatrix(qreal m11, qreal m12, qreal m13,
m_dirty = TxProject;
}
+static inline bool needsPerspectiveClipping(const QRectF &rect, const QTransform &transform)
+{
+ const qreal wx = qMin(transform.m13() * rect.left(), transform.m13() * rect.right());
+ const qreal wy = qMin(transform.m23() * rect.top(), transform.m23() * rect.bottom());
+
+ return wx + wy + transform.m33() < Q_NEAR_CLIP;
+}
+
QRect QTransform::mapRect(const QRect &rect) const
{
TransformationType t = inline_type();
@@ -1813,7 +1809,7 @@ QRect QTransform::mapRect(const QRect &rect) const
y -= h;
}
return QRect(x, y, w, h);
- } else {
+ } else if (t < TxProject || !needsPerspectiveClipping(rect, *this)) {
// see mapToPolygon for explanations of the algorithm.
qreal x = 0, y = 0;
MAP(rect.left(), rect.top(), x, y);
@@ -1837,6 +1833,10 @@ QRect QTransform::mapRect(const QRect &rect) const
xmax = qMax(xmax, x);
ymax = qMax(ymax, y);
return QRect(qRound(xmin), qRound(ymin), qRound(xmax)-qRound(xmin), qRound(ymax)-qRound(ymin));
+ } else {
+ QPainterPath path;
+ path.addRect(rect);
+ return map(path).boundingRect().toRect();
}
}
@@ -1879,7 +1879,7 @@ QRectF QTransform::mapRect(const QRectF &rect) const
y -= h;
}
return QRectF(x, y, w, h);
- } else {
+ } else if (t < TxProject || !needsPerspectiveClipping(rect, *this)) {
qreal x = 0, y = 0;
MAP(rect.x(), rect.y(), x, y);
qreal xmin = x;
@@ -1902,6 +1902,10 @@ QRectF QTransform::mapRect(const QRectF &rect) const
xmax = qMax(xmax, x);
ymax = qMax(ymax, y);
return QRectF(xmin, ymin, xmax-xmin, ymax - ymin);
+ } else {
+ QPainterPath path;
+ path.addRect(rect);
+ return map(path).boundingRect();
}
}
diff --git a/src/gui/painting/qwindowsurface_raster.cpp b/src/gui/painting/qwindowsurface_raster.cpp
index 22433dd..eddbfd2 100644
--- a/src/gui/painting/qwindowsurface_raster.cpp
+++ b/src/gui/painting/qwindowsurface_raster.cpp
@@ -118,7 +118,7 @@ QPaintDevice *QRasterWindowSurface::paintDevice()
void QRasterWindowSurface::beginPaint(const QRegion &rgn)
{
#if (defined(Q_WS_X11) && !defined(QT_NO_XRENDER)) || (defined(Q_WS_WIN) && !defined(Q_WS_WINCE))
- if (!qt_widget_private(window())->isOpaque) {
+ if (!qt_widget_private(window())->isOpaque && window()->testAttribute(Qt::WA_TranslucentBackground)) {
#if defined(Q_WS_WIN) && !defined(Q_WS_WINCE)
if (d_ptr->image->image.format() != QImage::Format_ARGB32_Premultiplied)
prepareBuffer(QImage::Format_ARGB32_Premultiplied, window());
@@ -149,7 +149,7 @@ void QRasterWindowSurface::flush(QWidget *widget, const QRegion &rgn, const QPoi
QRect br = rgn.boundingRect();
#ifndef Q_WS_WINCE
- if (!qt_widget_private(window())->isOpaque) {
+ if (!qt_widget_private(window())->isOpaque && window()->testAttribute(Qt::WA_TranslucentBackground)) {
QRect r = window()->frameGeometry();
QPoint frameOffset = qt_widget_private(window())->frameStrut().topLeft();
QRect dirtyRect = br.translated(offset + frameOffset);
diff --git a/src/gui/painting/qwindowsurface_x11.cpp b/src/gui/painting/qwindowsurface_x11.cpp
index d8b0d9e..95f6ce3 100644
--- a/src/gui/painting/qwindowsurface_x11.cpp
+++ b/src/gui/painting/qwindowsurface_x11.cpp
@@ -154,7 +154,7 @@ void QX11WindowSurface::setGeometry(const QRect &rect)
QX11PixmapData *oldData = static_cast<QX11PixmapData *>(d_ptr->device.pixmapData());
Q_ASSERT(oldData);
- if (!oldData->uninit && hasStaticContents()) {
+ if (!(oldData->flags & QX11PixmapData::Uninitialized) && hasStaticContents()) {
// Copy the content of the old pixmap into the new one.
QX11PixmapData *newData = new QX11PixmapData(QPixmapData::PixmapType);
newData->resize(size.width(), size.height());
@@ -175,7 +175,7 @@ void QX11WindowSurface::setGeometry(const QRect &rect)
dx, dy, qMin(boundingRect.width(), size.width()),
qMin(boundingRect.height(), size.height()), dx, dy);
XFreeGC(X11->display, tmpGc);
- newData->uninit = false;
+ newData->flags &= ~QX11PixmapData::Uninitialized;
d_ptr->device = QPixmap(newData);
} else {
diff --git a/src/gui/statemachine/qkeyeventtransition.cpp b/src/gui/statemachine/qkeyeventtransition.cpp
index 51b3ccc..21a0736 100644
--- a/src/gui/statemachine/qkeyeventtransition.cpp
+++ b/src/gui/statemachine/qkeyeventtransition.cpp
@@ -106,19 +106,6 @@ QKeyEventTransition::QKeyEventTransition(QObject *object, QEvent::Type type,
}
/*!
- Constructs a new key event transition for events of the given \a type for
- the given \a object, with the given \a key, \a targets and \a sourceState.
-*/
-QKeyEventTransition::QKeyEventTransition(QObject *object, QEvent::Type type,
- int key, const QList<QAbstractState*> &targets,
- QState *sourceState)
- : QEventTransition(*new QKeyEventTransitionPrivate, object, type, targets, sourceState)
-{
- Q_D(QKeyEventTransition);
- d->transition = new QBasicKeyEventTransition(type, key);
-}
-
-/*!
Destroys this key event transition.
*/
QKeyEventTransition::~QKeyEventTransition()
diff --git a/src/gui/statemachine/qkeyeventtransition.h b/src/gui/statemachine/qkeyeventtransition.h
index f5e8de3..45ae684 100644
--- a/src/gui/statemachine/qkeyeventtransition.h
+++ b/src/gui/statemachine/qkeyeventtransition.h
@@ -62,9 +62,6 @@ public:
QKeyEventTransition(QState *sourceState = 0);
QKeyEventTransition(QObject *object, QEvent::Type type, int key,
QState *sourceState = 0);
- QKeyEventTransition(QObject *object, QEvent::Type type, int key,
- const QList<QAbstractState*> &targets,
- QState *sourceState = 0);
~QKeyEventTransition();
int key() const;
diff --git a/src/gui/statemachine/qmouseeventtransition.cpp b/src/gui/statemachine/qmouseeventtransition.cpp
index 0cd096a..dbe50b3 100644
--- a/src/gui/statemachine/qmouseeventtransition.cpp
+++ b/src/gui/statemachine/qmouseeventtransition.cpp
@@ -112,21 +112,6 @@ QMouseEventTransition::QMouseEventTransition(QObject *object, QEvent::Type type,
}
/*!
- Constructs a new mouse event transition for events of the given \a type for
- the given \a object, with the given \a button, \a targets and \a
- sourceState.
-*/
-QMouseEventTransition::QMouseEventTransition(QObject *object, QEvent::Type type,
- Qt::MouseButton button,
- const QList<QAbstractState*> &targets,
- QState *sourceState)
- : QEventTransition(*new QMouseEventTransitionPrivate, object, type, targets, sourceState)
-{
- Q_D(QMouseEventTransition);
- d->transition = new QBasicMouseEventTransition(type, button);
-}
-
-/*!
Destroys this mouse event transition.
*/
QMouseEventTransition::~QMouseEventTransition()
diff --git a/src/gui/statemachine/qmouseeventtransition.h b/src/gui/statemachine/qmouseeventtransition.h
index 73ae6c9..a56a554 100644
--- a/src/gui/statemachine/qmouseeventtransition.h
+++ b/src/gui/statemachine/qmouseeventtransition.h
@@ -63,10 +63,6 @@ public:
QMouseEventTransition(QState *sourceState = 0);
QMouseEventTransition(QObject *object, QEvent::Type type,
Qt::MouseButton button, QState *sourceState = 0);
- QMouseEventTransition(QObject *object, QEvent::Type type,
- Qt::MouseButton button,
- const QList<QAbstractState*> &targets,
- QState *sourceState = 0);
~QMouseEventTransition();
Qt::MouseButton button() const;
diff --git a/src/gui/styles/gtksymbols.cpp b/src/gui/styles/gtksymbols.cpp
index c2c7876..f947ac1 100644
--- a/src/gui/styles/gtksymbols.cpp
+++ b/src/gui/styles/gtksymbols.cpp
@@ -752,7 +752,24 @@ static void setupGtkFileChooser(GtkWidget* gtkFileChooser, QWidget *parent,
QGtk::gtk_file_filter_set_name(gtkFilter, qPrintable(name.isEmpty() ? extensions.join(QLS(", ")) : name));
foreach (const QString &fileExtension, extensions) {
- QGtk::gtk_file_filter_add_pattern (gtkFilter, qPrintable(fileExtension));
+ // Note Gtk file dialogs are by default case sensitive
+ // and only supports basic glob syntax so we
+ // rewrite .xyz to .[xX][yY][zZ]
+ QString caseInsensitive;
+ for (int i = 0 ; i < fileExtension.length() ; ++i) {
+ QChar ch = fileExtension.at(i);
+ if (ch.isLetter()) {
+ caseInsensitive.append(
+ QLatin1Char('[') +
+ ch.toLower() +
+ ch.toUpper() +
+ QLatin1Char(']'));
+ } else {
+ caseInsensitive.append(ch);
+ }
+ }
+ QGtk::gtk_file_filter_add_pattern (gtkFilter, qPrintable(caseInsensitive));
+
}
if (filterMap)
filterMap->insert(gtkFilter, rawfilter);
diff --git a/src/gui/styles/qstylesheetstyle.cpp b/src/gui/styles/qstylesheetstyle.cpp
index 2efa4a7..5f6d4ab 100644
--- a/src/gui/styles/qstylesheetstyle.cpp
+++ b/src/gui/styles/qstylesheetstyle.cpp
@@ -2891,8 +2891,8 @@ void QStyleSheetStyle::drawComplexControl(ComplexControl cc, const QStyleOptionC
bool customUp = true, customDown = true;
QRenderRule upRule = renderRule(w, opt, PseudoElement_SpinBoxUpButton);
QRenderRule downRule = renderRule(w, opt, PseudoElement_SpinBoxDownButton);
- bool upRuleMatch = upRule.hasGeometry();
- bool downRuleMatch = downRule.hasGeometry();
+ bool upRuleMatch = upRule.hasGeometry() || upRule.hasPosition();
+ bool downRuleMatch = downRule.hasGeometry() || downRule.hasPosition();
if (rule.hasNativeBorder() && !upRuleMatch && !downRuleMatch) {
rule.drawBackgroundImage(p, spinOpt.rect);
customUp = (opt->subControls & QStyle::SC_SpinBoxUp)
@@ -5167,8 +5167,8 @@ QRect QStyleSheetStyle::subControlRect(ComplexControl cc, const QStyleOptionComp
QRenderRule upRule = renderRule(w, opt, PseudoElement_SpinBoxUpButton);
QRenderRule downRule = renderRule(w, opt, PseudoElement_SpinBoxDownButton);
bool ruleMatch = rule.hasBox() || !rule.hasNativeBorder();
- bool upRuleMatch = upRule.hasGeometry();
- bool downRuleMatch = downRule.hasGeometry();
+ bool upRuleMatch = upRule.hasGeometry() || upRule.hasPosition();
+ bool downRuleMatch = downRule.hasGeometry() || upRule.hasPosition();
if (ruleMatch || upRuleMatch || downRuleMatch) {
switch (sc) {
case SC_SpinBoxFrame:
diff --git a/src/gui/styles/qwindowsxpstyle.cpp b/src/gui/styles/qwindowsxpstyle.cpp
index 9560c4b..ad87354 100644
--- a/src/gui/styles/qwindowsxpstyle.cpp
+++ b/src/gui/styles/qwindowsxpstyle.cpp
@@ -134,6 +134,7 @@ static const int windowsRightBorder = 12; // right border on windows
// External function calls
extern Q_GUI_EXPORT HDC qt_win_display_dc();
+extern QRegion qt_region_from_HRGN(HRGN rgn);
@@ -445,6 +446,7 @@ bool QWindowsXPStylePrivate::isTransparent(XPThemeData &themeData)
themeData.stateId);
}
+
/*! \internal
Returns a QRegion of the region of the part
*/
@@ -456,12 +458,18 @@ QRegion QWindowsXPStylePrivate::region(XPThemeData &themeData)
themeData.stateId, &rect, &hRgn)))
return QRegion();
- QRegion rgn = QRegion(0,0,1,1);
- const bool success = CombineRgn(rgn.handle(), hRgn, 0, RGN_COPY) != ERROR;
- DeleteObject(hRgn);
+ HRGN dest = CreateRectRgn(0, 0, 0, 0);
+ const bool success = CombineRgn(dest, hRgn, 0, RGN_COPY) != ERROR;
+
+ QRegion region;
+
if (success)
- return rgn;
- return QRegion();
+ region = qt_region_from_HRGN(dest);
+
+ DeleteObject(hRgn);
+ DeleteObject(dest);
+
+ return region;
}
/*! \internal
diff --git a/src/gui/text/qfontengine_ft.cpp b/src/gui/text/qfontengine_ft.cpp
index a0b6f0c..d210cb4 100644
--- a/src/gui/text/qfontengine_ft.cpp
+++ b/src/gui/text/qfontengine_ft.cpp
@@ -1378,8 +1378,8 @@ bool QFontEngineFT::loadGlyphs(QGlyphSet *gs, glyph_t *glyphs, int num_glyphs, G
FT_Face face = 0;
for (int i = 0; i < num_glyphs; ++i) {
- if (!gs->glyph_data.contains(glyphs[i])
- || gs->glyph_data.value(glyphs[i])->format != format) {
+ Glyph *glyph = gs->glyph_data.value(glyphs[i]);
+ if (glyph == 0 || glyph->format != format) {
if (!face) {
face = lockFace();
FT_Matrix m = matrix;
diff --git a/src/gui/text/qfontengine_mac.mm b/src/gui/text/qfontengine_mac.mm
index 76132df..dbf3015 100644
--- a/src/gui/text/qfontengine_mac.mm
+++ b/src/gui/text/qfontengine_mac.mm
@@ -156,7 +156,7 @@ QCoreTextFontEngineMulti::QCoreTextFontEngineMulti(const ATSFontFamilyRef &, con
if (!kerning) {
float zero = 0.0;
QCFType<CFNumberRef> noKern = CFNumberCreate(kCFAllocatorDefault, kCFNumberFloatType, &zero);
- CFDictionaryAddValue(attributeDict, kCTKernAttributeName, &noKern);
+ CFDictionaryAddValue(attributeDict, kCTKernAttributeName, noKern);
}
QCoreTextFontEngine *fe = new QCoreTextFontEngine(ctfont, fontDef, this);
@@ -1588,6 +1588,7 @@ QFontEngine::FaceId QFontEngineMac::faceId() const
{
FaceId ret;
#if (MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_5)
+if (QSysInfo::MacintoshVersion >= QSysInfo::MV_10_5) {
// CTFontGetPlatformFont
FSRef ref;
if (ATSFontGetFileReference(FMGetATSFontRefFromFont(fontID), &ref) != noErr)
@@ -1595,7 +1596,9 @@ QFontEngine::FaceId QFontEngineMac::faceId() const
ret.filename = QByteArray(128, 0);
ret.index = fontID;
FSRefMakePath(&ref, (UInt8 *)ret.filename.data(), ret.filename.size());
-#else
+}else
+#endif
+{
FSSpec spec;
if (ATSFontGetFileSpecification(FMGetATSFontRefFromFont(fontID), &spec) != noErr)
return ret;
@@ -1605,7 +1608,7 @@ QFontEngine::FaceId QFontEngineMac::faceId() const
ret.filename = QByteArray(128, 0);
ret.index = fontID;
FSRefMakePath(&ref, (UInt8 *)ret.filename.data(), ret.filename.size());
-#endif
+}
return ret;
}
diff --git a/src/gui/text/qtextcontrol_p.h b/src/gui/text/qtextcontrol_p.h
index 872bcd5..eb0d749 100644
--- a/src/gui/text/qtextcontrol_p.h
+++ b/src/gui/text/qtextcontrol_p.h
@@ -83,7 +83,7 @@ class QAbstractScrollArea;
class QEvent;
class QTimerEvent;
-class Q_AUTOTEST_EXPORT QTextControl : public QObject
+class Q_GUI_EXPORT QTextControl : public QObject
{
Q_OBJECT
Q_DECLARE_PRIVATE(QTextControl)
diff --git a/src/gui/util/qcompleter.cpp b/src/gui/util/qcompleter.cpp
index bf1fa6a..f4dd87c 100644
--- a/src/gui/util/qcompleter.cpp
+++ b/src/gui/util/qcompleter.cpp
@@ -772,7 +772,7 @@ QMatchData QUnsortedModelEngine::filter(const QString& part, const QModelIndex&
///////////////////////////////////////////////////////////////////////////////
QCompleterPrivate::QCompleterPrivate()
: widget(0), proxy(0), popup(0), cs(Qt::CaseSensitive), role(Qt::EditRole), column(0),
- sorting(QCompleter::UnsortedModel), wrap(true), maxVisibleItems(7), eatFocusOut(true)
+ maxVisibleItems(7), sorting(QCompleter::UnsortedModel), wrap(true), eatFocusOut(true)
{
}
@@ -824,6 +824,9 @@ void QCompleterPrivate::_q_complete(QModelIndex index, bool highlighted)
Q_Q(QCompleter);
QString completion;
+ if (!(index.flags() & Qt::ItemIsEnabled))
+ return;
+
if (!index.isValid() || (!proxy->showAll && (index.row() >= proxy->engine->matchCount()))) {
completion = prefix;
} else {
@@ -1102,7 +1105,8 @@ void QCompleter::setPopup(QAbstractItemView *popup)
QObject::connect(popup, SIGNAL(clicked(QModelIndex)),
this, SLOT(_q_complete(QModelIndex)));
- QObject::connect(popup, SIGNAL(clicked(QModelIndex)), popup, SLOT(hide()));
+ QObject::connect(this, SIGNAL(activated(QModelIndex)),
+ popup, SLOT(hide()));
QObject::connect(popup->selectionModel(), SIGNAL(selectionChanged(QItemSelection,QItemSelection)),
this, SLOT(_q_completionSelected(QItemSelection)));
diff --git a/src/gui/widgets/qlinecontrol.cpp b/src/gui/widgets/qlinecontrol.cpp
index 106d8f2..f68d287 100644
--- a/src/gui/widgets/qlinecontrol.cpp
+++ b/src/gui/widgets/qlinecontrol.cpp
@@ -1,7 +1,7 @@
/****************************************************************************
**
** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
-** Contact: Qt Software Information (qt-info@nokia.com)
+** Contact: Nokia Corporation (qt-info@nokia.com)
**
** This file is part of the QtGui module of the Qt Toolkit.
**
@@ -34,7 +34,7 @@
** met: http://www.gnu.org/copyleft/gpl.html.
**
** If you are unsure which license is appropriate for your use, please
-** contact the sales department at qt-sales@nokia.com.
+** contact the sales department at http://www.qtsoftware.com/contact.
** $QT_END_LICENSE$
**
****************************************************************************/
diff --git a/src/gui/widgets/qlineedit_p.cpp b/src/gui/widgets/qlineedit_p.cpp
index 0e39304..f0ec8ad 100644
--- a/src/gui/widgets/qlineedit_p.cpp
+++ b/src/gui/widgets/qlineedit_p.cpp
@@ -1,7 +1,7 @@
/****************************************************************************
**
** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
-** Contact: Qt Software Information (qt-info@nokia.com)
+** Contact: Nokia Corporation (qt-info@nokia.com)
**
** This file is part of the QtGui module of the Qt Toolkit.
**
@@ -34,7 +34,7 @@
** met: http://www.gnu.org/copyleft/gpl.html.
**
** If you are unsure which license is appropriate for your use, please
-** contact the sales department at qt-sales@nokia.com.
+** contact the sales department at http://www.qtsoftware.com/contact.
** $QT_END_LICENSE$
**
****************************************************************************/
diff --git a/src/gui/widgets/qmainwindowlayout.cpp b/src/gui/widgets/qmainwindowlayout.cpp
index 3936a67..55afa70 100644
--- a/src/gui/widgets/qmainwindowlayout.cpp
+++ b/src/gui/widgets/qmainwindowlayout.cpp
@@ -1988,6 +1988,9 @@ void QMainWindowLayout::timerEvent(QTimerEvent *e)
if (movingSeparatorOrigin == movingSeparatorPos)
return;
+ //when moving the separator, we need to update the previous position
+ parentWidget()->update(layoutState.dockAreaLayout.separatorRegion());
+
layoutState = savedState;
layoutState.dockAreaLayout.separatorMove(movingSeparator, movingSeparatorOrigin,
movingSeparatorPos);
diff --git a/src/gui/widgets/qmenu.cpp b/src/gui/widgets/qmenu.cpp
index 8eec0fc..05426a0 100644
--- a/src/gui/widgets/qmenu.cpp
+++ b/src/gui/widgets/qmenu.cpp
@@ -225,9 +225,17 @@ void QMenuPrivate::updateActionRects() const
dh = popupGeometry(QApplication::desktop()->screenNumber(q)).height(),
y = 0;
QStyle *style = q->style();
- const int hmargin = style->pixelMetric(QStyle::PM_MenuHMargin, 0, q),
- vmargin = style->pixelMetric(QStyle::PM_MenuVMargin, 0, q),
- icone = style->pixelMetric(QStyle::PM_SmallIconSize, 0, q);
+ QStyleOption opt;
+ opt.init(q);
+ const int hmargin = style->pixelMetric(QStyle::PM_MenuHMargin, &opt, q),
+ vmargin = style->pixelMetric(QStyle::PM_MenuVMargin, &opt, q),
+ icone = style->pixelMetric(QStyle::PM_SmallIconSize, &opt, q);
+ const int fw = style->pixelMetric(QStyle::PM_MenuPanelWidth, &opt, q);
+ const int deskFw = style->pixelMetric(QStyle::PM_MenuDesktopFrameWidth, &opt, q);
+
+ const int sfcMargin = style->sizeFromContents(QStyle::CT_Menu, &opt, QApplication::globalStrut(), q).width() - QApplication::globalStrut().width();
+ const int min_column_width = q->minimumWidth() - (sfcMargin + leftmargin + rightmargin + 2 * (fw + hmargin));
+ const int tearoffHeight = tearoff ? style->pixelMetric(QStyle::PM_MenuTearoffHeight, &opt, q) : 0;
//for compatability now - will have to refactor this away..
tabWidth = 0;
@@ -300,10 +308,10 @@ void QMenuPrivate::updateActionRects() const
if (!sz.isEmpty()) {
- max_column_width = qMax(max_column_width, sz.width());
+ max_column_width = qMax(min_column_width, qMax(max_column_width, sz.width()));
//wrapping
if (!scroll &&
- y+sz.height()+vmargin > dh - (style->pixelMetric(QStyle::PM_MenuDesktopFrameWidth, 0, q) * 2)) {
+ y+sz.height()+vmargin > dh - (deskFw * 2)) {
ncols++;
y = vmargin;
}
@@ -316,10 +324,9 @@ void QMenuPrivate::updateActionRects() const
max_column_width += tabWidth; //finally add in the tab width
//calculate position
- const int fw = style->pixelMetric(QStyle::PM_MenuPanelWidth, 0, q);
const int base_y = vmargin + fw + topmargin +
(scroll ? scroll->scrollOffset : 0) +
- (tearoff ? style->pixelMetric(QStyle::PM_MenuTearoffHeight, 0, q) : 0);
+ tearoffHeight;
int x = hmargin + fw + leftmargin;
y = base_y;
@@ -328,7 +335,7 @@ void QMenuPrivate::updateActionRects() const
if (rect.isNull())
continue;
if (!scroll &&
- y+rect.height() > dh - (style->pixelMetric(QStyle::PM_MenuDesktopFrameWidth, 0, q) * 2)) {
+ y+rect.height() > dh - deskFw * 2) {
x += max_column_width + hmargin;
y = base_y;
}
@@ -1703,9 +1710,7 @@ QSize QMenu::sizeHint() const
QSize s;
QStyleOption opt(0);
- opt.rect = rect();
- opt.palette = palette();
- opt.state = QStyle::State_None;
+ opt.init(this);
for (int i = 0; i < d->actionRects.count(); ++i) {
const QRect &rect = d->actionRects.at(i);
if (rect.isNull())
@@ -2721,7 +2726,7 @@ void QMenu::mouseMoveEvent(QMouseEvent *e)
QAction *action = d->actionAt(e->pos());
if (!action) {
- if (d->hasHadMouse && !rect().contains(e->pos()))
+ if (d->hasHadMouse)
d->setCurrentAction(0);
return;
} else if(e->buttons()) {
diff --git a/src/gui/widgets/qmenubar.cpp b/src/gui/widgets/qmenubar.cpp
index a3964f7..4a900d6 100644
--- a/src/gui/widgets/qmenubar.cpp
+++ b/src/gui/widgets/qmenubar.cpp
@@ -716,7 +716,7 @@ void QMenuBar::initStyleOption(QStyleOptionMenuItem *option, const QAction *acti
application examples} also provide menus using these classes.
\sa QMenu, QShortcut, QAction,
- {http://developer.apple.com/documentation/UserExperience/Conceptual/OSXHIGuidelines/index.html}{Introduction to Apple Human Interface Guidelines},
+ {http://developer.apple.com/documentation/UserExperience/Conceptual/AppleHIGuidelines/XHIGIntro/XHIGIntro.html}{Introduction to Apple Human Interface Guidelines},
{fowler}{GUI Design Handbook: Menu Bar}, {Menus Example}
*/
diff --git a/src/gui/widgets/qtextedit.cpp b/src/gui/widgets/qtextedit.cpp
index e80df92..c095f5c 100644
--- a/src/gui/widgets/qtextedit.cpp
+++ b/src/gui/widgets/qtextedit.cpp
@@ -2625,12 +2625,12 @@ void QTextEditPrivate::_q_gestureTriggered()
return;
QScrollBar *hBar = q->horizontalScrollBar();
QScrollBar *vBar = q->verticalScrollBar();
- QPoint delta = g->pos() - (g->lastPos().isNull() ? g->pos() : g->lastPos());
+ QSize delta = g->lastOffset();
if (!delta.isNull()) {
if (QApplication::isRightToLeft())
- delta.rx() *= -1;
- int newX = hBar->value() - delta.x();
- int newY = vBar->value() - delta.y();
+ delta.rwidth() *= -1;
+ int newX = hBar->value() - delta.width();
+ int newY = vBar->value() - delta.height();
hbar->setValue(newX);
vbar->setValue(newY);
}
diff --git a/src/multimedia/audio/audio.pri b/src/multimedia/audio/audio.pri
new file mode 100644
index 0000000..3ddb23b
--- /dev/null
+++ b/src/multimedia/audio/audio.pri
@@ -0,0 +1,56 @@
+HEADERS += $$PWD/qaudio.h \
+ $$PWD/qaudioformat.h \
+ $$PWD/qaudioinput.h \
+ $$PWD/qaudiooutput.h \
+ $$PWD/qaudiodeviceinfo.h \
+ $$PWD/qaudioengineplugin.h \
+ $$PWD/qaudioengine.h \
+ $$PWD/qaudiodevicefactory_p.h \
+ $$PWD/qaudiodeviceid.h \
+ $$PWD/qaudiodeviceid_p.h
+
+
+SOURCES += $$PWD/qaudio.cpp \
+ $$PWD/qaudioformat.cpp \
+ $$PWD/qaudiodeviceinfo.cpp \
+ $$PWD/qaudiooutput.cpp \
+ $$PWD/qaudioinput.cpp \
+ $$PWD/qaudioengineplugin.cpp \
+ $$PWD/qaudioengine.cpp \
+ $$PWD/qaudiodevicefactory.cpp \
+ $$PWD/qaudiodeviceid.cpp
+
+mac {
+ HEADERS += $$PWD/qaudioinput_mac_p.h \
+ $$PWD/qaudiooutput_mac_p.h \
+ $$PWD/qaudiodeviceinfo_mac_p.h \
+ $$PWD/qaudio_mac_p.h
+
+ SOURCES += $$PWD/qaudiodeviceinfo_mac_p.cpp \
+ $$PWD/qaudiooutput_mac_p.cpp \
+ $$PWD/qaudioinput_mac_p.cpp \
+ $$PWD/qaudio_mac.cpp
+
+ LIBS += -framework CoreAudio -framework AudioUnit -framework AudioToolbox
+
+} else:win32 {
+
+ HEADERS += $$PWD/qaudioinput_win32_p.h $$PWD/qaudiooutput_win32_p.h $$PWD/qaudiodeviceinfo_win32_p.h
+ SOURCES += $$PWD/qaudiodeviceinfo_win32_p.cpp \
+ $$PWD/qaudiooutput_win32_p.cpp \
+ $$PWD/qaudioinput_win32_p.cpp
+ !wince*:LIBS += -lwinmm
+ wince*:LIBS += -lcoredll
+
+} else:unix {
+ unix:contains(QT_CONFIG, alsa) {
+ linux-*|freebsd-*|openbsd-*:{
+ DEFINES += HAS_ALSA
+ HEADERS += $$PWD/qaudiooutput_alsa_p.h $$PWD/qaudioinput_alsa_p.h $$PWD/qaudiodeviceinfo_alsa_p.h
+ SOURCES += $$PWD/qaudiodeviceinfo_alsa_p.cpp \
+ $$PWD/qaudiooutput_alsa_p.cpp \
+ $$PWD/qaudioinput_alsa_p.cpp
+ LIBS += -lasound
+ }
+ }
+}
diff --git a/src/multimedia/audio/qaudio.cpp b/src/multimedia/audio/qaudio.cpp
new file mode 100644
index 0000000..5ba6493
--- /dev/null
+++ b/src/multimedia/audio/qaudio.cpp
@@ -0,0 +1,102 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtMultimedia module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the either Technology Preview License Agreement or the
+** Beta Release License Agreement.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain
+** additional rights. These rights are described in the Nokia Qt LGPL
+** Exception version 1.0, 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.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at http://www.qtsoftware.com/contact.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+
+#include <QtMultimedia/qaudio.h>
+
+
+QT_BEGIN_NAMESPACE
+
+namespace QAudio
+{
+
+class RegisterMetaTypes
+{
+public:
+ RegisterMetaTypes()
+ {
+ qRegisterMetaType<QAudio::Error>();
+ qRegisterMetaType<QAudio::State>();
+ qRegisterMetaType<QAudio::Mode>();
+ }
+
+} _register;
+
+}
+
+/*!
+ \namespace QAudio
+ \brief The QAudio namespace contains enums used by the audio classes.
+ \since 4.6
+*/
+
+/*!
+ \enum QAudio::Error
+
+ \value NoError No errors have occurred
+ \value OpenError An error opening the audio device
+ \value IOError An error occurred during read/write of audio device
+ \value UnderrunError Audio data is not being fed to the audio device at a fast enough rate
+ \value FatalError A non-recoverable error has occurred, the audio device is not usable at this time.
+*/
+
+/*!
+ \enum QAudio::State
+
+ \value ActiveState Audio data is being processed, this state is set after start() is called
+ and while audio data is available to be processed.
+ \value SuspendState The audio device is in a suspended state, this state will only be entered
+ after suspend() is called.
+ \value StopState The audio device is closed, not processing any audio data
+ \value IdleState The QIODevice passed in has no data and audio system's buffer is empty, this state
+ is set after start() is called and while no audio data is available to be processed.
+*/
+
+/*!
+ \enum QAudio::Mode
+
+ \value AudioOutput audio output device
+ \value AudioInput audio input device
+*/
+
+
+QT_END_NAMESPACE
+
diff --git a/src/multimedia/audio/qaudio.h b/src/multimedia/audio/qaudio.h
new file mode 100644
index 0000000..b996cc6
--- /dev/null
+++ b/src/multimedia/audio/qaudio.h
@@ -0,0 +1,71 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtMultimedia module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the either Technology Preview License Agreement or the
+** Beta Release License Agreement.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain
+** additional rights. These rights are described in the Nokia Qt LGPL
+** Exception version 1.0, 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.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at http://www.qtsoftware.com/contact.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+
+#ifndef QAUDIO_H
+#define QAUDIO_H
+
+
+#include <QtCore/qglobal.h>
+#include <QtCore/qmetatype.h>
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+QT_MODULE(Multimedia)
+
+namespace QAudio
+{
+ enum Error { NoError, OpenError, IOError, UnderrunError, FatalError };
+ enum State { ActiveState, SuspendState, StopState, IdleState };
+ enum Mode { AudioInput, AudioOutput };
+}
+
+QT_END_NAMESPACE
+
+QT_END_HEADER
+
+Q_DECLARE_METATYPE(QAudio::Error);
+Q_DECLARE_METATYPE(QAudio::State);
+Q_DECLARE_METATYPE(QAudio::Mode);
+
+#endif // QAUDIO_H
diff --git a/src/multimedia/audio/qaudio_mac.cpp b/src/multimedia/audio/qaudio_mac.cpp
new file mode 100644
index 0000000..cfa7ca3
--- /dev/null
+++ b/src/multimedia/audio/qaudio_mac.cpp
@@ -0,0 +1,142 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtMultimedia module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the either Technology Preview License Agreement or the
+** Beta Release License Agreement.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain
+** additional rights. These rights are described in the Nokia Qt LGPL
+** Exception version 1.0, 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.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at http://www.qtsoftware.com/contact.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+
+#include "qaudio_mac_p.h"
+
+QT_BEGIN_NAMESPACE
+
+// Debugging
+QDebug operator<<(QDebug dbg, const QAudioFormat& audioFormat)
+{
+ dbg.nospace() << "QAudioFormat(" <<
+ audioFormat.frequency() << "," <<
+ audioFormat.channels() << "," <<
+ audioFormat.sampleSize()<< "," <<
+ audioFormat.codec() << "," <<
+ audioFormat.byteOrder() << "," <<
+ audioFormat.sampleType() << ")";
+
+ return dbg.space();
+}
+
+
+// Conversion
+QAudioFormat toQAudioFormat(AudioStreamBasicDescription const& sf)
+{
+ QAudioFormat audioFormat;
+
+ audioFormat.setFrequency(sf.mSampleRate);
+ audioFormat.setChannels(sf.mChannelsPerFrame);
+ audioFormat.setSampleSize(sf.mBitsPerChannel);
+ audioFormat.setCodec(QString::fromLatin1("audio/pcm"));
+ audioFormat.setByteOrder(sf.mFormatFlags & kLinearPCMFormatFlagIsBigEndian != 0 ? QAudioFormat::BigEndian : QAudioFormat::LittleEndian);
+ QAudioFormat::SampleType type = QAudioFormat::UnSignedInt;
+ if ((sf.mFormatFlags & kLinearPCMFormatFlagIsSignedInteger) != 0)
+ type = QAudioFormat::SignedInt;
+ else if ((sf.mFormatFlags & kLinearPCMFormatFlagIsFloat) != 0)
+ type = QAudioFormat::Float;
+ audioFormat.setSampleType(type);
+
+ return audioFormat;
+}
+
+AudioStreamBasicDescription toAudioStreamBasicDescription(QAudioFormat const& audioFormat)
+{
+ AudioStreamBasicDescription sf;
+
+ sf.mFormatFlags = kAudioFormatFlagIsPacked;
+ sf.mSampleRate = audioFormat.frequency();
+ sf.mFramesPerPacket = 1;
+ sf.mChannelsPerFrame = audioFormat.channels();
+ sf.mBitsPerChannel = audioFormat.sampleSize();
+ sf.mBytesPerFrame = sf.mChannelsPerFrame * (sf.mBitsPerChannel / 8);
+ sf.mBytesPerPacket = sf.mFramesPerPacket * sf.mBytesPerFrame;
+ sf.mFormatID = kAudioFormatLinearPCM;
+
+ switch (audioFormat.sampleType()) {
+ case QAudioFormat::SignedInt: sf.mFormatFlags |= kAudioFormatFlagIsSignedInteger; break;
+ case QAudioFormat::UnSignedInt: /* default */ break;
+ case QAudioFormat::Float: sf.mFormatFlags |= kAudioFormatFlagIsFloat; break;
+ case QAudioFormat::Unknown: default: break;
+ }
+
+ return sf;
+}
+
+// QAudioRingBuffer
+QAudioRingBuffer::QAudioRingBuffer(int bufferSize):
+ m_bufferSize(bufferSize)
+{
+ m_buffer = new char[m_bufferSize];
+ reset();
+}
+
+QAudioRingBuffer::~QAudioRingBuffer()
+{
+ delete m_buffer;
+}
+
+int QAudioRingBuffer::used() const
+{
+ return m_bufferUsed;
+}
+
+int QAudioRingBuffer::free() const
+{
+ return m_bufferSize - m_bufferUsed;
+}
+
+int QAudioRingBuffer::size() const
+{
+ return m_bufferSize;
+}
+
+void QAudioRingBuffer::reset()
+{
+ m_readPos = 0;
+ m_writePos = 0;
+ m_bufferUsed = 0;
+}
+
+QT_END_NAMESPACE
+
+
diff --git a/src/multimedia/audio/qaudio_mac_p.h b/src/multimedia/audio/qaudio_mac_p.h
new file mode 100644
index 0000000..8e2d522
--- /dev/null
+++ b/src/multimedia/audio/qaudio_mac_p.h
@@ -0,0 +1,144 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtMultimedia module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the either Technology Preview License Agreement or the
+** Beta Release License Agreement.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain
+** additional rights. These rights are described in the Nokia Qt LGPL
+** Exception version 1.0, 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.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at http://www.qtsoftware.com/contact.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists for the convenience
+// of other Qt classes. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
+
+#ifndef QAUDIO_MAC_P_H
+#define QAUDIO_MAC_P_H
+
+#include <CoreAudio/CoreAudio.h>
+
+#include <QtCore/qdebug.h>
+#include <QtCore/qatomic.h>
+
+#include <QtMultimedia/qaudioformat.h>
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+QT_MODULE(Multimedia)
+
+
+extern QDebug operator<<(QDebug dbg, const QAudioFormat& audioFormat);
+
+extern QAudioFormat toQAudioFormat(const AudioStreamBasicDescription& streamFormat);
+extern AudioStreamBasicDescription toAudioStreamBasicDescription(QAudioFormat const& audioFormat);
+
+class QAudioRingBuffer
+{
+public:
+ typedef QPair<char*, int> Region;
+
+ QAudioRingBuffer(int bufferSize);
+ ~QAudioRingBuffer();
+
+ Region acquireReadRegion(int size)
+ {
+ const int used = m_bufferUsed.fetchAndAddAcquire(0);
+
+ if (used > 0) {
+ const int readSize = qMin(size, qMin(m_bufferSize - m_readPos, used));
+
+ return readSize > 0 ? Region(m_buffer + m_readPos, readSize) : Region(0, 0);
+ }
+
+ return Region(0, 0);
+ }
+
+ void releaseReadRegion(Region const& region)
+ {
+ m_readPos = (m_readPos + region.second) % m_bufferSize;
+
+ m_bufferUsed.fetchAndAddRelease(-region.second);
+ }
+
+ Region acquireWriteRegion(int size)
+ {
+ const int free = m_bufferSize - m_bufferUsed.fetchAndAddAcquire(0);
+
+ if (free > 0) {
+ const int writeSize = qMin(size, qMin(m_bufferSize - m_writePos, free));
+
+ return writeSize > 0 ? Region(m_buffer + m_writePos, writeSize) : Region(0, 0);
+ }
+
+ return Region(0, 0);
+ }
+
+ void releaseWriteRegion(Region const& region)
+ {
+ m_writePos = (m_writePos + region.second) % m_bufferSize;
+
+ m_bufferUsed.fetchAndAddRelease(region.second);
+ }
+
+ int used() const;
+ int free() const;
+ int size() const;
+
+ void reset();
+
+private:
+ int m_bufferSize;
+ int m_readPos;
+ int m_writePos;
+ char* m_buffer;
+ QAtomicInt m_bufferUsed;
+};
+
+QT_END_NAMESPACE
+
+QT_END_HEADER
+
+#endif // QAUDIO_MAC_P_H
+
+
diff --git a/src/multimedia/audio/qaudiodevicefactory.cpp b/src/multimedia/audio/qaudiodevicefactory.cpp
new file mode 100644
index 0000000..35e9c91
--- /dev/null
+++ b/src/multimedia/audio/qaudiodevicefactory.cpp
@@ -0,0 +1,250 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtMultimedia module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the either Technology Preview License Agreement or the
+** Beta Release License Agreement.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain
+** additional rights. These rights are described in the Nokia Qt LGPL
+** Exception version 1.0, 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.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at http://www.qtsoftware.com/contact.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include <QtCore/qdebug.h>
+#include <QtMultimedia/qaudioengine.h>
+#include <QtMultimedia/qaudioengineplugin.h>
+#include <private/qfactoryloader_p.h>
+#include "qaudiodevicefactory_p.h"
+#include "qaudiodeviceid_p.h"
+
+#if defined(Q_OS_WIN)
+#include "qaudiodeviceinfo_win32_p.h"
+#include "qaudiooutput_win32_p.h"
+#include "qaudioinput_win32_p.h"
+#elif defined(Q_OS_MAC)
+#include "qaudiodeviceinfo_mac_p.h"
+#include "qaudiooutput_mac_p.h"
+#include "qaudioinput_mac_p.h"
+#elif defined(HAS_ALSA)
+#include "qaudiodeviceinfo_alsa_p.h"
+#include "qaudiooutput_alsa_p.h"
+#include "qaudioinput_alsa_p.h"
+#endif
+
+QT_BEGIN_NAMESPACE
+
+Q_GLOBAL_STATIC_WITH_ARGS(QFactoryLoader, loader,
+ (QAudioEngineFactoryInterface_iid, QLatin1String("/audio"), Qt::CaseInsensitive))
+
+
+class QNullDeviceInfo : public QAbstractAudioDeviceInfo
+{
+public:
+ QAudioFormat preferredFormat() const { qWarning()<<"using null deviceinfo, none available"; return QAudioFormat(); }
+ bool isFormatSupported(const QAudioFormat& ) const { return false; }
+ QAudioFormat nearestFormat(const QAudioFormat& ) const { return QAudioFormat(); }
+ QString deviceName() const { return QString(); }
+ QStringList codecList() { return QStringList(); }
+ QList<int> frequencyList() { return QList<int>(); }
+ QList<int> channelsList() { return QList<int>(); }
+ QList<int> sampleSizeList() { return QList<int>(); }
+ QList<QAudioFormat::Endian> byteOrderList() { return QList<QAudioFormat::Endian>(); }
+ QList<QAudioFormat::SampleType> sampleTypeList() { return QList<QAudioFormat::SampleType>(); }
+};
+
+class QNullInputDevice : public QAbstractAudioInput
+{
+public:
+ QIODevice* start(QIODevice* ) { qWarning()<<"using null input device, none available"; return 0; }
+ void stop() {}
+ void reset() {}
+ void suspend() {}
+ void resume() {}
+ int bytesReady() const { return 0; }
+ int periodSize() const { return 0; }
+ void setBufferSize(int ) {}
+ int bufferSize() const { return 0; }
+ void setNotifyInterval(int ) {}
+ int notifyInterval() const { return 0; }
+ qint64 totalTime() const { return 0; }
+ qint64 clock() const { return 0; }
+ QAudio::Error error() const { return QAudio::OpenError; }
+ QAudio::State state() const { return QAudio::StopState; }
+ QAudioFormat format() const { return QAudioFormat(); }
+};
+
+class QNullOutputDevice : public QAbstractAudioOutput
+{
+public:
+ QIODevice* start(QIODevice* ) { qWarning()<<"using null output device, none available"; return 0; }
+ void stop() {}
+ void reset() {}
+ void suspend() {}
+ void resume() {}
+ int bytesFree() const { return 0; }
+ int periodSize() const { return 0; }
+ void setBufferSize(int ) {}
+ int bufferSize() const { return 0; }
+ void setNotifyInterval(int ) {}
+ int notifyInterval() const { return 0; }
+ qint64 totalTime() const { return 0; }
+ qint64 clock() const { return 0; }
+ QAudio::Error error() const { return QAudio::OpenError; }
+ QAudio::State state() const { return QAudio::StopState; }
+ QAudioFormat format() const { return QAudioFormat(); }
+};
+
+QList<QAudioDeviceId> QAudioDeviceFactory::deviceList(QAudio::Mode mode)
+{
+ QList<QAudioDeviceId> devices;
+#if (defined(Q_OS_WIN) || defined(Q_OS_MAC) || defined(HAS_ALSA))
+ foreach (const QByteArray &handle, QAudioDeviceInfoPrivate::deviceList(mode))
+ devices += createDeviceId(QLatin1String("builtin"), mode, handle);
+#endif
+ QFactoryLoader* l = loader();
+
+ foreach (QString const& key, l->keys()) {
+ QAudioEngineFactoryInterface* plugin = qobject_cast<QAudioEngineFactoryInterface*>(l->instance(key));
+ if (plugin) {
+ foreach (QByteArray const& handle, plugin->deviceList(mode))
+ devices += createDeviceId(key, mode, handle);
+ }
+
+ delete plugin;
+ }
+
+ return devices;
+}
+
+QAudioDeviceId QAudioDeviceFactory::defaultInputDevice()
+{
+ QAudioEngineFactoryInterface* plugin = qobject_cast<QAudioEngineFactoryInterface*>(loader()->instance(QLatin1String("default")));
+
+ if (plugin) {
+ QList<QByteArray> list = plugin->deviceList(QAudio::AudioInput);
+ if (list.size() > 0)
+ return createDeviceId(QLatin1String("default"), QAudio::AudioInput, list.at(0));
+ }
+#if (defined(Q_OS_WIN) || defined(Q_OS_MAC) || defined(HAS_ALSA))
+ return createDeviceId(QLatin1String("builtin"), QAudio::AudioInput, QAudioDeviceInfoPrivate::defaultInputDevice());
+#endif
+ return QAudioDeviceId();
+}
+
+QAudioDeviceId QAudioDeviceFactory::defaultOutputDevice()
+{
+ QAudioEngineFactoryInterface* plugin = qobject_cast<QAudioEngineFactoryInterface*>(loader()->instance(QLatin1String("default")));
+
+ if (plugin) {
+ QList<QByteArray> list = plugin->deviceList(QAudio::AudioOutput);
+ if (list.size() > 0)
+ return createDeviceId(QLatin1String("default"), QAudio::AudioOutput, list.at(0));
+ }
+#if (defined(Q_OS_WIN) || defined(Q_OS_MAC) || defined(HAS_ALSA))
+ return createDeviceId(QLatin1String("builtin"), QAudio::AudioOutput, QAudioDeviceInfoPrivate::defaultOutputDevice());
+#endif
+ return QAudioDeviceId();
+}
+
+QAbstractAudioDeviceInfo* QAudioDeviceFactory::audioDeviceInfo(QAudioDeviceId const& id)
+{
+ if (id.isNull())
+ return new QNullDeviceInfo();
+#if (defined(Q_OS_WIN) || defined(Q_OS_MAC) || defined(HAS_ALSA))
+ if (id.d->key == QLatin1String("builtin"))
+ return new QAudioDeviceInfoPrivate(id.d->handle, QAudio::Mode(id.d->mode));
+#endif
+ QAudioEngineFactoryInterface* plugin = qobject_cast<QAudioEngineFactoryInterface*>(loader()->instance(id.d->key));
+
+ if (plugin)
+ return plugin->createDeviceInfo(id.d->handle, QAudio::Mode(id.d->mode));
+
+ return new QNullDeviceInfo();
+}
+
+QAbstractAudioInput* QAudioDeviceFactory::createDefaultInputDevice(QAudioFormat const &format)
+{
+ return createInputDevice(defaultInputDevice(), format);
+}
+
+QAbstractAudioOutput* QAudioDeviceFactory::createDefaultOutputDevice(QAudioFormat const &format)
+{
+ return createOutputDevice(defaultOutputDevice(), format);
+}
+
+QAbstractAudioInput* QAudioDeviceFactory::createInputDevice(QAudioDeviceId const& id, QAudioFormat const &format)
+{
+ if (id.isNull())
+ return new QNullInputDevice();
+#if (defined(Q_OS_WIN) || defined(Q_OS_MAC) || defined(HAS_ALSA))
+ if (id.d->key == QLatin1String("builtin")) {
+ if(!defaultInputDevice().isNull())
+ return new QAudioInputPrivate(id.d->handle, format);
+ else
+ return new QNullInputDevice();
+ }
+#endif
+ QAudioEngineFactoryInterface* plugin = qobject_cast<QAudioEngineFactoryInterface*>(loader()->instance((id.d->key)));
+
+ if (plugin)
+ return plugin->createInput(id.d->handle, format);
+
+ return new QNullInputDevice();
+}
+
+QAbstractAudioOutput* QAudioDeviceFactory::createOutputDevice(QAudioDeviceId const& id, QAudioFormat const &format)
+{
+ if (id.isNull())
+ return new QNullOutputDevice();
+#if (defined(Q_OS_WIN) || defined(Q_OS_MAC) || defined(HAS_ALSA))
+ if (id.d->key == QLatin1String("builtin")) {
+ if(!defaultOutputDevice().isNull())
+ return new QAudioOutputPrivate(id.d->handle, format);
+ else
+ return new QNullOutputDevice();
+ }
+#endif
+ QAudioEngineFactoryInterface* plugin = qobject_cast<QAudioEngineFactoryInterface*>(loader()->instance(id.d->key));
+
+ if (plugin)
+ return plugin->createOutput(id.d->handle, format);
+
+ return new QNullOutputDevice();
+}
+
+QAudioDeviceId QAudioDeviceFactory::createDeviceId(QString const& key, int mode, QByteArray const& handle)
+{
+ return QAudioDeviceId(new QAudioDeviceIdPrivate(key, mode, handle));
+}
+
+QT_END_NAMESPACE
+
diff --git a/src/multimedia/audio/qaudiodevicefactory_p.h b/src/multimedia/audio/qaudiodevicefactory_p.h
new file mode 100644
index 0000000..a8e2b28
--- /dev/null
+++ b/src/multimedia/audio/qaudiodevicefactory_p.h
@@ -0,0 +1,100 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtMultimedia module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the either Technology Preview License Agreement or the
+** Beta Release License Agreement.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain
+** additional rights. These rights are described in the Nokia Qt LGPL
+** Exception version 1.0, 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.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at http://www.qtsoftware.com/contact.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists for the convenience
+// of other Qt classes. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
+#ifndef QAUDIODEVICEFACTORY_P_H
+#define QAUDIODEVICEFACTORY_P_H
+
+#include <QtCore/qglobal.h>
+#include <QtCore/qbytearray.h>
+#include <QtCore/qlist.h>
+
+#include <QtMultimedia/qaudiodeviceid.h>
+#include <QtMultimedia/qaudiodeviceinfo.h>
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+QT_MODULE(Multimedia)
+
+class QAbstractAudioInput;
+class QAbstractAudioOutput;
+
+
+class QAudioDeviceFactory
+{
+public:
+ static QList<QAudioDeviceId> deviceList(QAudio::Mode mode);
+
+ static QAudioDeviceId defaultInputDevice();
+ static QAudioDeviceId defaultOutputDevice();
+
+ static QAbstractAudioDeviceInfo* audioDeviceInfo(QAudioDeviceId const &device);
+
+ static QAbstractAudioInput* createDefaultInputDevice(QAudioFormat const &format);
+ static QAbstractAudioOutput* createDefaultOutputDevice(QAudioFormat const &format);
+
+ static QAbstractAudioInput* createInputDevice(QAudioDeviceId const &device, QAudioFormat const &format);
+ static QAbstractAudioOutput* createOutputDevice(QAudioDeviceId const &device, QAudioFormat const &format);
+
+ static QAbstractAudioInput* createNullInput();
+ static QAbstractAudioOutput* createNullOutput();
+
+ static QAudioDeviceId createDeviceId(QString const& key, int mode, QByteArray const& handle);
+};
+
+QT_END_NAMESPACE
+
+QT_END_HEADER
+
+#endif // QAUDIODEVICEFACTORY_P_H
+
diff --git a/src/multimedia/audio/qaudiodeviceid.cpp b/src/multimedia/audio/qaudiodeviceid.cpp
new file mode 100644
index 0000000..21a9cd8
--- /dev/null
+++ b/src/multimedia/audio/qaudiodeviceid.cpp
@@ -0,0 +1,168 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtMultimedia module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the either Technology Preview License Agreement or the
+** Beta Release License Agreement.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain
+** additional rights. These rights are described in the Nokia Qt LGPL
+** Exception version 1.0, 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.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at http://www.qtsoftware.com/contact.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include <QtCore/qstring.h>
+#include <QtCore/qbytearray.h>
+#include <QtCore/qdatastream.h>
+
+#include <QtMultimedia/qaudiodeviceid.h>
+#include "qaudiodeviceid_p.h"
+
+
+QT_BEGIN_NAMESPACE
+
+/*!
+ \class QAudioDeviceId
+ \brief The QAudioDeviceId class provides means for identifying a unique input or output device on a system.
+
+ \inmodule QtMultimedia
+ \ingroup multimedia
+ \since 4.6
+
+ \sa QAudioDeviceInfo, QAudioOutput, QAudioInput
+*/
+
+/*!
+ Construct a new null QAudioDeviceId.
+*/
+
+QAudioDeviceId::QAudioDeviceId()
+{
+}
+
+/*!
+ Copy the QAudDeviceId referenced by \a other.
+*/
+
+QAudioDeviceId::QAudioDeviceId(const QAudioDeviceId &other):
+ d(other.d)
+{
+}
+
+/*!
+ Destroy the QAudioDeviceId.
+*/
+
+QAudioDeviceId::~QAudioDeviceId()
+{
+}
+
+/*!
+ Make a copy of the \a other QAudioDeviceId.
+*/
+
+QAudioDeviceId& QAudioDeviceId::operator=(const QAudioDeviceId &other)
+{
+ d = other.d;
+ return *this;
+}
+
+/*!
+ Compare with the \a other QAudioDeviceId, return true if they are the same;
+ otherwise false.
+*/
+
+bool QAudioDeviceId::operator==(const QAudioDeviceId &other) const
+{
+ return (d.constData() == 0 && other.d.constData() == 0) ||
+ (d.constData() != 0 && other.d.constData() != 0 &&
+ d->key == other.d->key && d->mode == other.d->mode && d->handle == other.d->handle);
+}
+
+/*!
+ Compare with the \a other QAudioDeviceId, return false if they are the same;
+ otherwise true.
+*/
+
+bool QAudioDeviceId::operator!=(const QAudioDeviceId &other) const
+{
+ return !(*this == other);
+}
+
+/*!
+ Returns true if this is not a valid QAudioDeviceId; otherwise false.
+*/
+
+bool QAudioDeviceId::isNull() const
+{
+ return d.constData() == 0;
+}
+
+/*!
+ \internal
+*/
+
+QAudioDeviceId::QAudioDeviceId(QAudioDeviceIdPrivate* data):
+ d(data)
+{
+}
+
+/*!
+ \internal
+*/
+
+QAudioDeviceIdPrivate::QAudioDeviceIdPrivate(QString const& k, int m, QByteArray const& h):
+ key(k), mode(m), handle(h)
+{
+}
+
+#ifndef QT_NO_DATASTREAM
+Q_MULTIMEDIA_EXPORT QDataStream &operator<<(QDataStream &s, const QAudioDeviceId &id)
+{
+ s << id.d->key << id.d->mode << id.d->handle;
+ return s;
+}
+
+Q_MULTIMEDIA_EXPORT QDataStream &operator>>(QDataStream &s, QAudioDeviceId &id)
+{
+ QString key;
+ int mode;
+ QByteArray handle;
+
+ s >> key >> mode >> handle;
+ id = QAudioDeviceId(new QAudioDeviceIdPrivate(key, mode, handle));
+
+ return s;
+}
+#endif
+
+
+QT_END_NAMESPACE
diff --git a/src/multimedia/audio/qaudiodeviceid.h b/src/multimedia/audio/qaudiodeviceid.h
new file mode 100644
index 0000000..f9188d3
--- /dev/null
+++ b/src/multimedia/audio/qaudiodeviceid.h
@@ -0,0 +1,94 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtMultimedia module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the either Technology Preview License Agreement or the
+** Beta Release License Agreement.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain
+** additional rights. These rights are described in the Nokia Qt LGPL
+** Exception version 1.0, 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.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at http://www.qtsoftware.com/contact.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QAUDIODEVICEID_H
+#define QAUDIODEVICEID_H
+
+#include <QtCore/qshareddata.h>
+#include <QtCore/qmetatype.h>
+
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+QT_MODULE(Multimedia)
+
+
+class QAudioDeviceFactory;
+class QAudioDeviceIdPrivate;
+
+class Q_MULTIMEDIA_EXPORT QAudioDeviceId
+{
+ friend class QAudioDeviceFactory;
+ friend Q_MULTIMEDIA_EXPORT QDataStream &operator<<(QDataStream&, const QAudioDeviceId&);
+ friend Q_MULTIMEDIA_EXPORT QDataStream &operator>>(QDataStream&, QAudioDeviceId&);
+
+public:
+ QAudioDeviceId();
+ QAudioDeviceId(const QAudioDeviceId &other);
+ ~QAudioDeviceId();
+
+ QAudioDeviceId& operator=(const QAudioDeviceId &other);
+ bool operator==(const QAudioDeviceId &id) const;
+ bool operator!=(const QAudioDeviceId &id) const;
+
+ bool isNull() const;
+
+private:
+ QAudioDeviceId(QAudioDeviceIdPrivate *data);
+
+ QSharedDataPointer<QAudioDeviceIdPrivate> d;
+};
+
+#ifndef QT_NO_DATASTREAM
+Q_MULTIMEDIA_EXPORT QDataStream &operator<<(QDataStream&, const QAudioDeviceId&);
+Q_MULTIMEDIA_EXPORT QDataStream &operator>>(QDataStream&, QAudioDeviceId&);
+#endif
+
+QT_END_NAMESPACE
+
+QT_END_HEADER
+
+Q_DECLARE_METATYPE(QAudioDeviceId);
+
+
+#endif // QAUDIODEVICEID_H
diff --git a/src/multimedia/audio/qaudiodeviceid_p.h b/src/multimedia/audio/qaudiodeviceid_p.h
new file mode 100644
index 0000000..3034574
--- /dev/null
+++ b/src/multimedia/audio/qaudiodeviceid_p.h
@@ -0,0 +1,82 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtMultimedia module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the either Technology Preview License Agreement or the
+** Beta Release License Agreement.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain
+** additional rights. These rights are described in the Nokia Qt LGPL
+** Exception version 1.0, 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.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at http://www.qtsoftware.com/contact.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists for the convenience
+// of other Qt classes. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
+#ifndef QAUDIODEVICEIDPRIVATE_H
+#define QAUDIODEVICEIDPRIVATE_H
+
+#include <QtCore/qstring.h>
+#include <QtCore/qbytearray.h>
+#include <QtCore/qshareddata.h>
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+QT_MODULE(Multimedia)
+
+
+class QAudioDeviceIdPrivate : public QSharedData
+{
+public:
+ QAudioDeviceIdPrivate(QString const& k, int m, QByteArray const& h);
+
+ QString key;
+ int mode;
+ QByteArray handle;
+};
+
+
+QT_END_NAMESPACE
+
+QT_END_HEADER
+
+#endif // QAUDIODEVICEIDPRIVATE_H
diff --git a/src/multimedia/audio/qaudiodeviceinfo.cpp b/src/multimedia/audio/qaudiodeviceinfo.cpp
new file mode 100644
index 0000000..c1895d7
--- /dev/null
+++ b/src/multimedia/audio/qaudiodeviceinfo.cpp
@@ -0,0 +1,270 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtMultimedia module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the either Technology Preview License Agreement or the
+** Beta Release License Agreement.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain
+** additional rights. These rights are described in the Nokia Qt LGPL
+** Exception version 1.0, 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.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at http://www.qtsoftware.com/contact.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qaudiodevicefactory_p.h"
+#include <QtMultimedia/qaudioengine.h>
+#include <QtMultimedia/qaudiodeviceinfo.h>
+
+
+QT_BEGIN_NAMESPACE
+
+/*!
+ \class QAudioDeviceInfo
+ \brief The QAudioDeviceInfo class provides an interface to query audio devices and their functionality.
+
+ \inmodule QtMultimedia
+ \ingroup multimedia
+ \since 4.6
+
+ QAudioDeviceInfo lets you query for audio devices--such as sound
+ cards and USB headsets--that are currently available on the system.
+ The audio devices available are dependent on the platform or audio plugins installed.
+
+ You can also query each device for the formats it supports. A
+ format in this context is a set consisting of a specific byte
+ order, channel, codec, frequency, sample rate, and sample type. A
+ format is represented by the QAudioFormat class.
+
+ The values supported by the the device for each of these
+ parameters can be fetched with
+ supportedByteOrders(), supportedChannels(), supportedCodecs(),
+ supportedFrequencies(), supportedSampleSizes(), and
+ supportedSampleTypes(). The combinations supported are dependent on the platform,
+ audio plugins installed and the audio device capabilities. If you need a specific format, you can check if
+ the device supports it with isFormatSupported(), or fetch a
+ supported format that is as close as possible to the format with
+ nearestFormat().
+
+ A QAudioDeviceInfo is constructed with a QAudioDeviceId, which is
+ an identifier for a physical device. It is used by Qt to construct
+ classes that communicate with the device--such as
+ QAudioDeviceInfo, QAudioInput, and QAudioOutput. The static
+ functions defaultInputDevice(), defaultOutputDevice(), and
+ deviceList() let you get a hold of the ids for all available
+ devices. You fetch ids based on whether you will use the device
+ for input or output; this is specified by the QAudio::Mode enum.
+ The QAudioDeviceId returned are only valid for the QAudio::Mode.
+
+ For instance:
+
+ \code
+ foreach(QAudioDeviceId audioId, QAudioDeviceInfo::deviceList(QAudio::AudioOutput)) {
+ QAudioDeviceInfo info(audioId);
+ qDebug() << "Device name: " << info.deviceName();
+ }
+ \endcode
+
+ In this code sample, we loop through all devices that are able to output
+ sound, i.e., play an audio stream in a supported format. For each device we
+ find, we simply print the deviceName().
+
+ \sa QAudioOutput, QAudioInput, QAudioDeviceId
+*/
+
+/*!
+ Construct a new audio device info and attach it to \a parent.
+ Using the audio device with the specified \a id.
+*/
+
+QAudioDeviceInfo::QAudioDeviceInfo(const QAudioDeviceId &id, QObject *parent):
+ QObject(parent)
+{
+ d = QAudioDeviceFactory::audioDeviceInfo(id);
+}
+
+/*!
+ Destroy this audio device info.
+*/
+
+QAudioDeviceInfo::~QAudioDeviceInfo()
+{
+ delete d;
+}
+
+/*!
+ Returns human readable name of audio device.
+
+ Device names vary depending on platform/audio plugin being used.
+
+ They are a unique string identifiers for the audio device.
+
+ eg. default, Intel, U0x46d0x9a4
+*/
+
+QString QAudioDeviceInfo::deviceName() const
+{
+ return d->deviceName();
+}
+
+/*!
+ Returns true if \a settings are supported by the audio device of this QAudioDeviceInfo.
+*/
+
+bool QAudioDeviceInfo::isFormatSupported(const QAudioFormat &settings) const
+{
+ return d->isFormatSupported(settings);
+}
+
+/*!
+ Returns QAudioFormat of default settings.
+
+ These settings are provided by the platform/audio plugin being used.
+
+ They also are dependent on the QAudio::Mode being used.
+
+ A typical audio system would provide something like:
+ \list
+ \o Input settings: 8000Hz mono 8 bit.
+ \o Output settings: 44100Hz stereo 16 bit little endian.
+ \endlist
+*/
+
+QAudioFormat QAudioDeviceInfo::preferredFormat() const
+{
+ return d->preferredFormat();
+}
+
+/*!
+ Returns closest QAudioFormat to \a settings that system audio supports.
+
+ These settings are provided by the platform/audio plugin being used.
+
+ They also are dependent on the QAudio::Mode being used.
+*/
+
+QAudioFormat QAudioDeviceInfo::nearestFormat(const QAudioFormat &settings) const
+{
+ return d->nearestFormat(settings);
+}
+
+/*!
+ Returns a list of supported codecs.
+
+ All platform and plugin implementations should provide support for:
+
+ "audio/pcm" - Linear PCM
+
+ For writing plugins to support additional codecs refer to:
+
+ http://www.iana.org/assignments/media-types/audio/
+*/
+
+QStringList QAudioDeviceInfo::supportedCodecs() const
+{
+ return d->codecList();
+}
+
+/*!
+ Returns a list of supported frequencies.
+*/
+
+QList<int> QAudioDeviceInfo::supportedFrequencies() const
+{
+ return d->frequencyList();
+}
+
+/*!
+ Returns a list of supported channels.
+*/
+
+QList<int> QAudioDeviceInfo::supportedChannels() const
+{
+ return d->channelsList();
+}
+
+/*!
+ Returns a list of supported sample sizes.
+*/
+
+QList<int> QAudioDeviceInfo::supportedSampleSizes() const
+{
+ return d->sampleSizeList();
+}
+
+/*!
+ Returns a list of supported byte orders.
+*/
+
+QList<QAudioFormat::Endian> QAudioDeviceInfo::supportedByteOrders() const
+{
+ return d->byteOrderList();
+}
+
+/*!
+ Returns a list of supported sample types.
+*/
+
+QList<QAudioFormat::SampleType> QAudioDeviceInfo::supportedSampleTypes() const
+{
+ return d->sampleTypeList();
+}
+
+/*!
+ Returns the name of the default input audio device.
+ All platform and audio plugin implementations provide a default audio device to use.
+*/
+
+QAudioDeviceId QAudioDeviceInfo::defaultInputDevice()
+{
+ return QAudioDeviceFactory::defaultInputDevice();
+}
+
+/*!
+ Returns the name of the default output audio device.
+ All platform and audio plugin implementations provide a default audio device to use.
+*/
+
+QAudioDeviceId QAudioDeviceInfo::defaultOutputDevice()
+{
+ return QAudioDeviceFactory::defaultOutputDevice();
+}
+
+/*!
+ Returns a list of audio devices that support \a mode.
+*/
+
+QList<QAudioDeviceId> QAudioDeviceInfo::deviceList(QAudio::Mode mode)
+{
+ return QAudioDeviceFactory::deviceList(mode);
+}
+
+QT_END_NAMESPACE
+
diff --git a/src/multimedia/audio/qaudiodeviceinfo.h b/src/multimedia/audio/qaudiodeviceinfo.h
new file mode 100644
index 0000000..444a00a
--- /dev/null
+++ b/src/multimedia/audio/qaudiodeviceinfo.h
@@ -0,0 +1,102 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtMultimedia module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the either Technology Preview License Agreement or the
+** Beta Release License Agreement.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain
+** additional rights. These rights are described in the Nokia Qt LGPL
+** Exception version 1.0, 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.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at http://www.qtsoftware.com/contact.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+
+#ifndef QAUDIODEVICEINFO_H
+#define QAUDIODEVICEINFO_H
+
+#include <QtCore/qobject.h>
+#include <QtCore/qglobal.h>
+#include <QtCore/qbytearray.h>
+#include <QtCore/qstring.h>
+#include <QtCore/qstringlist.h>
+#include <QtCore/qlist.h>
+
+#include <QtMultimedia/qaudio.h>
+#include <QtMultimedia/qaudioformat.h>
+#include <QtMultimedia/qaudiodeviceid.h>
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+QT_MODULE(Multimedia)
+
+
+class QAbstractAudioDeviceInfo;
+
+class Q_MULTIMEDIA_EXPORT QAudioDeviceInfo : public QObject
+{
+ Q_OBJECT
+
+public:
+ explicit QAudioDeviceInfo(const QAudioDeviceId &id, QObject *parent = 0);
+ ~QAudioDeviceInfo();
+
+ QString deviceName() const;
+
+ bool isFormatSupported(const QAudioFormat &format) const;
+ QAudioFormat preferredFormat() const;
+ QAudioFormat nearestFormat(const QAudioFormat &format) const;
+
+ QStringList supportedCodecs() const;
+ QList<int> supportedFrequencies() const;
+ QList<int> supportedChannels() const;
+ QList<int> supportedSampleSizes() const;
+ QList<QAudioFormat::Endian> supportedByteOrders() const;
+ QList<QAudioFormat::SampleType> supportedSampleTypes() const;
+
+ static QAudioDeviceId defaultInputDevice();
+ static QAudioDeviceId defaultOutputDevice();
+
+ static QList<QAudioDeviceId> deviceList(QAudio::Mode mode);
+
+private:
+ Q_DISABLE_COPY(QAudioDeviceInfo)
+
+ QAbstractAudioDeviceInfo* d;
+};
+
+QT_END_NAMESPACE
+
+QT_END_HEADER
+
+#endif // QAUDIODEVICEINFO_H
diff --git a/src/multimedia/audio/qaudiodeviceinfo_alsa_p.cpp b/src/multimedia/audio/qaudiodeviceinfo_alsa_p.cpp
new file mode 100644
index 0000000..fe45f82
--- /dev/null
+++ b/src/multimedia/audio/qaudiodeviceinfo_alsa_p.cpp
@@ -0,0 +1,394 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtMultimedia module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the either Technology Preview License Agreement or the
+** Beta Release License Agreement.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain
+** additional rights. These rights are described in the Nokia Qt LGPL
+** Exception version 1.0, 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.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at http://www.qtsoftware.com/contact.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists for the convenience
+// of other Qt classes. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
+#include "qaudiodeviceinfo_alsa_p.h"
+
+QAudioDeviceInfoPrivate::QAudioDeviceInfoPrivate(QByteArray dev, QAudio::Mode mode)
+{
+ handle = 0;
+
+ device = QLatin1String(dev);
+ this->mode = mode;
+}
+
+QAudioDeviceInfoPrivate::~QAudioDeviceInfoPrivate()
+{
+ close();
+}
+
+bool QAudioDeviceInfoPrivate::isFormatSupported(const QAudioFormat& format) const
+{
+ return testSettings(format);
+}
+
+QAudioFormat QAudioDeviceInfoPrivate::preferredFormat() const
+{
+ QAudioFormat nearest;
+ if(mode == QAudio::AudioOutput) {
+ nearest.setFrequency(44100);
+ nearest.setChannels(2);
+ nearest.setByteOrder(QAudioFormat::LittleEndian);
+ nearest.setSampleType(QAudioFormat::SignedInt);
+ nearest.setSampleSize(16);
+ nearest.setCodec(tr("audio/pcm"));
+ } else {
+ nearest.setFrequency(8000);
+ nearest.setChannels(1);
+ nearest.setSampleType(QAudioFormat::SignedInt);
+ nearest.setSampleSize(8);
+ nearest.setCodec(tr("audio/pcm"));
+ }
+ return nearest;
+}
+
+QAudioFormat QAudioDeviceInfoPrivate::nearestFormat(const QAudioFormat& format) const
+{
+ if(testSettings(format))
+ return format;
+ else
+ return preferredFormat();
+}
+
+QString QAudioDeviceInfoPrivate::deviceName() const
+{
+ return device;
+}
+
+QStringList QAudioDeviceInfoPrivate::codecList()
+{
+ updateLists();
+ return codecz;
+}
+
+QList<int> QAudioDeviceInfoPrivate::frequencyList()
+{
+ updateLists();
+ return freqz;
+}
+
+QList<int> QAudioDeviceInfoPrivate::channelsList()
+{
+ updateLists();
+ return channelz;
+}
+
+QList<int> QAudioDeviceInfoPrivate::sampleSizeList()
+{
+ updateLists();
+ return sizez;
+}
+
+QList<QAudioFormat::Endian> QAudioDeviceInfoPrivate::byteOrderList()
+{
+ updateLists();
+ return byteOrderz;
+}
+
+QList<QAudioFormat::SampleType> QAudioDeviceInfoPrivate::sampleTypeList()
+{
+ updateLists();
+ return typez;
+}
+
+bool QAudioDeviceInfoPrivate::open()
+{
+ int err = 0;
+ QString dev = device;
+ if(!dev.contains(tr("default"))) {
+ int idx = snd_card_get_index(dev.toLocal8Bit().constData());
+ dev = QString(tr("hw:%1,0")).arg(idx);
+ }
+ if(mode == QAudio::AudioOutput) {
+ err=snd_pcm_open( &handle,dev.toLocal8Bit().constData(),SND_PCM_STREAM_PLAYBACK,0);
+ } else {
+ err=snd_pcm_open( &handle,dev.toLocal8Bit().constData(),SND_PCM_STREAM_CAPTURE,0);
+ }
+ if(err < 0) {
+ handle = 0;
+ return false;
+ }
+ return true;
+}
+
+void QAudioDeviceInfoPrivate::close()
+{
+ if(handle)
+ snd_pcm_close(handle);
+ handle = 0;
+}
+
+bool QAudioDeviceInfoPrivate::testSettings(const QAudioFormat& format) const
+{
+ // Set nearest to closest settings that do work.
+ // See if what is in settings will work (return value).
+
+ int err = 0;
+ snd_pcm_t* handle;
+ snd_pcm_hw_params_t *params;
+ QString dev = device;
+
+ // open()
+ if(!dev.contains(tr("default"))) {
+ int idx = snd_card_get_index(dev.toLocal8Bit().constData());
+ dev = QString(tr("hw:%1,0")).arg(idx);
+ }
+ if(mode == QAudio::AudioOutput) {
+ err=snd_pcm_open( &handle,dev.toLocal8Bit().constData(),SND_PCM_STREAM_PLAYBACK,0);
+ } else {
+ err=snd_pcm_open( &handle,dev.toLocal8Bit().constData(),SND_PCM_STREAM_CAPTURE,0);
+ }
+ if(err < 0) {
+ handle = 0;
+ return false;
+ }
+
+ bool testChannel = false;
+ bool testCodec = false;
+ bool testFreq = false;
+ bool testType = false;
+ bool testSize = false;
+
+ int dir = 0;
+
+ snd_pcm_nonblock( handle, 0 );
+ snd_pcm_hw_params_alloca( &params );
+ snd_pcm_hw_params_any( handle, params );
+
+ // For now, just accept only audio/pcm codec
+ if(!format.codec().startsWith(tr("audio/pcm"))) {
+ err=-1;
+ } else
+ testCodec = true;
+
+ if(err>=0 && format.channels() != -1) {
+ err = snd_pcm_hw_params_test_channels(handle,params,format.channels());
+ if(err>=0)
+ err = snd_pcm_hw_params_set_channels(handle,params,format.channels());
+ if(err>=0)
+ testChannel = true;
+ }
+
+ if(err>=0 && format.frequency() != -1) {
+ err = snd_pcm_hw_params_test_rate(handle,params,format.frequency(),0);
+ if(err>=0)
+ err = snd_pcm_hw_params_set_rate(handle,params,format.frequency(),dir);
+ if(err>=0)
+ testFreq = true;
+ }
+
+ if((err>=0 && format.sampleSize() != -1) &&
+ (format.sampleType() != QAudioFormat::Unknown)) {
+ switch(format.sampleSize()) {
+ case 8:
+ if(format.sampleType() == QAudioFormat::SignedInt)
+ err = snd_pcm_hw_params_set_format(handle,params,SND_PCM_FORMAT_S8);
+ else if(format.sampleType() == QAudioFormat::UnSignedInt)
+ err = snd_pcm_hw_params_set_format(handle,params,SND_PCM_FORMAT_U8);
+ break;
+ case 16:
+ if(format.sampleType() == QAudioFormat::SignedInt) {
+ if(format.byteOrder() == QAudioFormat::LittleEndian)
+ err = snd_pcm_hw_params_set_format(handle,params,SND_PCM_FORMAT_S16_LE);
+ else if(format.byteOrder() == QAudioFormat::BigEndian)
+ err = snd_pcm_hw_params_set_format(handle,params,SND_PCM_FORMAT_S16_BE);
+ } else if(format.sampleType() == QAudioFormat::UnSignedInt) {
+ if(format.byteOrder() == QAudioFormat::LittleEndian)
+ err = snd_pcm_hw_params_set_format(handle,params,SND_PCM_FORMAT_U16_LE);
+ else if(format.byteOrder() == QAudioFormat::BigEndian)
+ err = snd_pcm_hw_params_set_format(handle,params,SND_PCM_FORMAT_U16_BE);
+ }
+ break;
+ case 32:
+ if(format.sampleType() == QAudioFormat::SignedInt) {
+ if(format.byteOrder() == QAudioFormat::LittleEndian)
+ err = snd_pcm_hw_params_set_format(handle,params,SND_PCM_FORMAT_S32_LE);
+ else if(format.byteOrder() == QAudioFormat::BigEndian)
+ err = snd_pcm_hw_params_set_format(handle,params,SND_PCM_FORMAT_S32_BE);
+ } else if(format.sampleType() == QAudioFormat::UnSignedInt) {
+ if(format.byteOrder() == QAudioFormat::LittleEndian)
+ err = snd_pcm_hw_params_set_format(handle,params,SND_PCM_FORMAT_U32_LE);
+ else if(format.byteOrder() == QAudioFormat::BigEndian)
+ err = snd_pcm_hw_params_set_format(handle,params,SND_PCM_FORMAT_U32_BE);
+ }
+ }
+ if(err>=0) {
+ testSize = true;
+ testType = true;
+ }
+ }
+ if(err>=0)
+ err = snd_pcm_hw_params(handle, params);
+
+ if(err == 0) {
+ // settings work
+ // close()
+ if(handle)
+ snd_pcm_close(handle);
+ return true;
+ }
+ if(handle)
+ snd_pcm_close(handle);
+
+ return false;
+}
+
+void QAudioDeviceInfoPrivate::updateLists()
+{
+ // redo all lists based on current settings
+ freqz.clear();
+ channelz.clear();
+ sizez.clear();
+ byteOrderz.clear();
+ typez.clear();
+ codecz.clear();
+
+ if(!handle)
+ open();
+
+ if(!handle)
+ return;
+
+ for(int i=0; i<(int)MAX_SAMPLE_RATES; i++) {
+ //if(snd_pcm_hw_params_test_rate(handle, params, SAMPLE_RATES[i], dir) == 0)
+ freqz.append(SAMPLE_RATES[i]);
+ }
+ channelz.append(1);
+ channelz.append(2);
+ sizez.append(8);
+ sizez.append(16);
+ sizez.append(32);
+ byteOrderz.append(QAudioFormat::LittleEndian);
+ byteOrderz.append(QAudioFormat::BigEndian);
+ typez.append(QAudioFormat::SignedInt);
+ typez.append(QAudioFormat::UnSignedInt);
+ typez.append(QAudioFormat::Float);
+ codecz.append(tr("audio/pcm"));
+ close();
+}
+
+QList<QByteArray> QAudioDeviceInfoPrivate::deviceList(QAudio::Mode mode)
+{
+ QAudio::Mode _m;
+ QList<QByteArray> devices;
+ QByteArray filter;
+ QString dir;
+
+ // Create a list of all current audio devices that support mode
+ void **hints, **n;
+ char *name, *descr, *io;
+
+ if(snd_device_name_hint(-1, "pcm", &hints) < 0) {
+ qWarning()<<"no alsa devices available";
+ return devices;
+ }
+ n = hints;
+
+ while (*n != NULL) {
+ _m = QAudio::AudioOutput;
+ name = snd_device_name_get_hint(*n, "NAME");
+ descr = snd_device_name_get_hint(*n, "DESC");
+ io = snd_device_name_get_hint(*n, "IOID");
+ dir = QString::fromUtf8(io);
+ if((name != NULL) && (descr != NULL) && ((io == NULL) || (dir.length() ==filter.length()))) {
+ if(dir.length() == 5)
+ _m = QAudio::AudioInput;
+ if(io == NULL)
+ _m = mode;
+
+ QString str = tr(name);
+
+ if(str.contains(tr("default"))) {
+ int pos = str.indexOf(tr("="),0);
+ devices.append(str.mid(pos+1).toLocal8Bit().constData());
+ }
+ }
+ if(name != NULL)
+ free(name);
+ if(descr != NULL)
+ free(descr);
+ if(io != NULL)
+ free(io);
+ n++;
+ }
+ snd_device_name_free_hint(hints);
+
+ if(devices.size() > 0) {
+ devices.append("default");
+ if(mode == QAudio::AudioInput) {
+ filter.append("Input");
+ } else {
+ filter.append("Output");
+ }
+ }
+
+ return devices;
+}
+
+QByteArray QAudioDeviceInfoPrivate::defaultInputDevice()
+{
+ QList<QByteArray> devices = deviceList(QAudio::AudioInput);
+ if(devices.size() == 0)
+ return QByteArray();
+
+ return QByteArray("default");
+}
+
+QByteArray QAudioDeviceInfoPrivate::defaultOutputDevice()
+{
+ QList<QByteArray> devices = deviceList(QAudio::AudioOutput);
+ if(devices.size() == 0)
+ return QByteArray();
+
+ return QByteArray("default");
+}
+
+
diff --git a/src/multimedia/audio/qaudiodeviceinfo_alsa_p.h b/src/multimedia/audio/qaudiodeviceinfo_alsa_p.h
new file mode 100644
index 0000000..3ac9239
--- /dev/null
+++ b/src/multimedia/audio/qaudiodeviceinfo_alsa_p.h
@@ -0,0 +1,113 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtMultimedia module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the either Technology Preview License Agreement or the
+** Beta Release License Agreement.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain
+** additional rights. These rights are described in the Nokia Qt LGPL
+** Exception version 1.0, 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.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at http://www.qtsoftware.com/contact.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists for the convenience
+// of other Qt classes. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
+
+#ifndef QAUDIODEVICEINFOALSA_H
+#define QAUDIODEVICEINFOALSA_H
+
+#include <alsa/asoundlib.h>
+
+#include <QtCore/qbytearray.h>
+#include <QtCore/qstringlist.h>
+#include <QtCore/qlist.h>
+#include <QtCore/qdebug.h>
+
+#include <QtMultimedia/qaudio.h>
+#include <QtMultimedia/qaudiodeviceinfo.h>
+#include <QtMultimedia/qaudioengine.h>
+
+const unsigned int MAX_SAMPLE_RATES = 5;
+const unsigned int SAMPLE_RATES[] =
+ { 8000, 11025, 22050, 44100, 48000 };
+
+class QAudioDeviceInfoPrivate : public QAbstractAudioDeviceInfo
+{
+ Q_OBJECT
+public:
+ QAudioDeviceInfoPrivate(QByteArray dev,QAudio::Mode mode);
+ ~QAudioDeviceInfoPrivate();
+
+ bool testSettings(const QAudioFormat& format) const;
+ void updateLists();
+ QAudioFormat preferredFormat() const;
+ bool isFormatSupported(const QAudioFormat& format) const;
+ QAudioFormat nearestFormat(const QAudioFormat& format) const;
+ QString deviceName() const;
+ QStringList codecList();
+ QList<int> frequencyList();
+ QList<int> channelsList();
+ QList<int> sampleSizeList();
+ QList<QAudioFormat::Endian> byteOrderList();
+ QList<QAudioFormat::SampleType> sampleTypeList();
+ static QByteArray defaultInputDevice();
+ static QByteArray defaultOutputDevice();
+ static QList<QByteArray> deviceList(QAudio::Mode);
+
+private:
+ bool open();
+ void close();
+
+ QString device;
+ QAudio::Mode mode;
+ QAudioFormat nearest;
+ QList<int> freqz;
+ QList<int> channelz;
+ QList<int> sizez;
+ QList<QAudioFormat::Endian> byteOrderz;
+ QStringList codecz;
+ QList<QAudioFormat::SampleType> typez;
+ snd_pcm_t* handle;
+ snd_pcm_hw_params_t *params;
+};
+
+#endif
+
diff --git a/src/multimedia/audio/qaudiodeviceinfo_mac_p.cpp b/src/multimedia/audio/qaudiodeviceinfo_mac_p.cpp
new file mode 100644
index 0000000..c94e0c4
--- /dev/null
+++ b/src/multimedia/audio/qaudiodeviceinfo_mac_p.cpp
@@ -0,0 +1,357 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtMultimedia module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the either Technology Preview License Agreement or the
+** Beta Release License Agreement.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain
+** additional rights. These rights are described in the Nokia Qt LGPL
+** Exception version 1.0, 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.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at http://www.qtsoftware.com/contact.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists for the convenience
+// of other Qt classes. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
+#include <QtCore/qstringlist.h>
+#include <QtCore/qlist.h>
+#include <QtCore/qbytearray.h>
+#include <QtCore/qdatastream.h>
+#include <QtCore/qdebug.h>
+#include <private/qcore_mac_p.h>
+
+#include <QtMultimedia/qaudiodeviceinfo.h>
+#include "qaudio_mac_p.h"
+#include "qaudiodeviceinfo_mac_p.h"
+
+
+
+QT_BEGIN_NAMESPACE
+
+
+QAudioDeviceInfoPrivate::QAudioDeviceInfoPrivate(QByteArray const& handle, QAudio::Mode)
+{
+ QDataStream ds(handle);
+ quint32 did, tm;
+
+ ds >> did >> tm >> name;
+ deviceId = AudioDeviceID(did);
+ mode = QAudio::Mode(tm);
+}
+
+bool QAudioDeviceInfoPrivate::isFormatSupported(const QAudioFormat& format) const
+{
+ return format.codec() == QString::fromLatin1("audio/pcm");
+}
+
+QAudioFormat QAudioDeviceInfoPrivate::preferredFormat() const
+{
+ QAudioFormat rc;
+
+ UInt32 propSize = 0;
+
+ if (AudioDeviceGetPropertyInfo(deviceId,
+ 0,
+ mode == QAudio::AudioInput,
+ kAudioDevicePropertyStreams,
+ &propSize,
+ 0) == noErr) {
+
+ const int sc = propSize / sizeof(AudioStreamID);
+
+ if (sc > 0) {
+ AudioStreamID* streams = new AudioStreamID[sc];
+
+ if (AudioDeviceGetProperty(deviceId,
+ 0,
+ mode == QAudio::AudioInput,
+ kAudioDevicePropertyStreams,
+ &propSize,
+ streams) == noErr) {
+
+ for (int i = 0; i < sc; ++i) {
+ if (AudioStreamGetPropertyInfo(streams[i],
+ 0,
+ kAudioStreamPropertyPhysicalFormat,
+ &propSize,
+ 0) == noErr) {
+
+ AudioStreamBasicDescription sf;
+
+ if (AudioStreamGetProperty(streams[i],
+ 0,
+ kAudioStreamPropertyPhysicalFormat,
+ &propSize,
+ &sf) == noErr) {
+ rc = toQAudioFormat(sf);
+ break;
+ }
+ }
+ }
+ }
+
+ delete streams;
+ }
+ }
+
+ return rc;
+}
+
+QAudioFormat QAudioDeviceInfoPrivate::nearestFormat(const QAudioFormat& format) const
+{
+ QAudioFormat rc(format);
+ QAudioFormat target = preferredFormat();
+
+ if (!format.codec().isEmpty() && format.codec() != QString::fromLatin1("audio/pcm"))
+ return QAudioFormat();
+
+ rc.setCodec(QString::fromLatin1("audio/pcm"));
+
+ if (rc.frequency() != target.frequency())
+ rc.setFrequency(target.frequency());
+ if (rc.channels() != target.channels())
+ rc.setChannels(target.channels());
+ if (rc.sampleSize() != target.sampleSize())
+ rc.setSampleSize(target.sampleSize());
+ if (rc.byteOrder() != target.byteOrder())
+ rc.setByteOrder(target.byteOrder());
+ if (rc.sampleType() != target.sampleType())
+ rc.setSampleType(target.sampleType());
+
+ return rc;
+}
+
+QString QAudioDeviceInfoPrivate::deviceName() const
+{
+ return name;
+}
+
+QStringList QAudioDeviceInfoPrivate::codecList()
+{
+ return QStringList() << QString::fromLatin1("audio/pcm");
+}
+
+QList<int> QAudioDeviceInfoPrivate::frequencyList()
+{
+ QSet<int> rc;
+
+ // Add some common frequencies
+ rc << 8000 << 11025 << 22050 << 44100;
+
+ //
+ UInt32 propSize = 0;
+
+ if (AudioDeviceGetPropertyInfo(deviceId,
+ 0,
+ mode == QAudio::AudioInput,
+ kAudioDevicePropertyAvailableNominalSampleRates,
+ &propSize,
+ 0) == noErr) {
+
+ const int pc = propSize / sizeof(AudioValueRange);
+
+ if (pc > 0) {
+ AudioValueRange* vr = new AudioValueRange[pc];
+
+ if (AudioDeviceGetProperty(deviceId,
+ 0,
+ mode == QAudio::AudioInput,
+ kAudioDevicePropertyAvailableNominalSampleRates,
+ &propSize,
+ vr) == noErr) {
+
+ for (int i = 0; i < pc; ++i)
+ rc << vr[i].mMaximum;
+ }
+
+ delete vr;
+ }
+ }
+
+ return rc.toList();
+}
+
+QList<int> QAudioDeviceInfoPrivate::channelsList()
+{
+ QList<int> rc;
+
+ // Can mix down to 1 channel
+ rc << 1;
+
+ UInt32 propSize = 0;
+ int channels = 0;
+
+ if (AudioDeviceGetPropertyInfo(deviceId,
+ 0,
+ mode == QAudio::AudioInput,
+ kAudioDevicePropertyStreamConfiguration,
+ &propSize,
+ 0) == noErr) {
+
+ AudioBufferList* audioBufferList = static_cast<AudioBufferList*>(qMalloc(propSize));
+
+ if (audioBufferList != 0) {
+ if (AudioDeviceGetProperty(deviceId,
+ 0,
+ mode == QAudio::AudioInput,
+ kAudioDevicePropertyStreamConfiguration,
+ &propSize,
+ audioBufferList) == noErr) {
+
+ for (int i = 0; i < int(audioBufferList->mNumberBuffers); ++i) {
+ channels += audioBufferList->mBuffers[i].mNumberChannels;
+ rc << channels;
+ }
+ }
+
+ qFree(audioBufferList);
+ }
+ }
+
+ return rc;
+}
+
+QList<int> QAudioDeviceInfoPrivate::sampleSizeList()
+{
+ return QList<int>() << 8 << 16 << 24 << 32 << 64;
+}
+
+QList<QAudioFormat::Endian> QAudioDeviceInfoPrivate::byteOrderList()
+{
+ return QList<QAudioFormat::Endian>() << QAudioFormat::LittleEndian << QAudioFormat::BigEndian;
+}
+
+QList<QAudioFormat::SampleType> QAudioDeviceInfoPrivate::sampleTypeList()
+{
+ return QList<QAudioFormat::SampleType>() << QAudioFormat::SignedInt << QAudioFormat::UnSignedInt << QAudioFormat::Float;
+}
+
+static QByteArray get_device_info(AudioDeviceID audioDevice, QAudio::Mode mode)
+{
+ UInt32 size;
+ QByteArray device;
+ QDataStream ds(&device, QIODevice::WriteOnly);
+ AudioStreamBasicDescription sf;
+ CFStringRef name;
+ Boolean isInput = mode == QAudio::AudioInput;
+
+ // Id
+ ds << quint32(audioDevice);
+
+ // Mode
+ size = sizeof(AudioStreamBasicDescription);
+ if (AudioDeviceGetProperty(audioDevice, 0, isInput, kAudioDevicePropertyStreamFormat,
+ &size, &sf) != noErr) {
+ return QByteArray();
+ }
+ ds << quint32(mode);
+
+ // Name
+ size = sizeof(CFStringRef);
+ if (AudioDeviceGetProperty(audioDevice, 0, isInput, kAudioObjectPropertyName,
+ &size, &name) != noErr) {
+ qWarning() << "QAudioDeviceInfo: Unable to find device name";
+ }
+ ds << QCFString::toQString(name);
+
+ CFRelease(name);
+
+ return device;
+}
+
+QByteArray QAudioDeviceInfoPrivate::defaultInputDevice()
+{
+ AudioDeviceID audioDevice;
+ UInt32 size = sizeof(audioDevice);
+
+ if (AudioHardwareGetProperty(kAudioHardwarePropertyDefaultInputDevice, &size,
+ &audioDevice) != noErr) {
+ qWarning() << "QAudioDeviceInfo: Unable to find default input device";
+ return QByteArray();
+ }
+
+ return get_device_info(audioDevice, QAudio::AudioInput);
+}
+
+QByteArray QAudioDeviceInfoPrivate::defaultOutputDevice()
+{
+ AudioDeviceID audioDevice;
+ UInt32 size = sizeof(audioDevice);
+
+ if (AudioHardwareGetProperty(kAudioHardwarePropertyDefaultOutputDevice, &size,
+ &audioDevice) != noErr) {
+ qWarning() << "QAudioDeviceInfo: Unable to find default output device";
+ return QByteArray();
+ }
+
+ return get_device_info(audioDevice, QAudio::AudioOutput);
+}
+
+QList<QByteArray> QAudioDeviceInfoPrivate::deviceList(QAudio::Mode mode)
+{
+ QList<QByteArray> devices;
+
+ UInt32 propSize = 0;
+
+ if (AudioHardwareGetPropertyInfo(kAudioHardwarePropertyDevices, &propSize, 0) == noErr) {
+
+ const int dc = propSize / sizeof(AudioDeviceID);
+
+ if (dc > 0) {
+ AudioDeviceID* audioDevices = new AudioDeviceID[dc];
+
+ if (AudioHardwareGetProperty(kAudioHardwarePropertyDevices, &propSize, audioDevices) == noErr) {
+ for (int i = 0; i < dc; ++i) {
+ QByteArray info = get_device_info(audioDevices[i], mode);
+ if (!info.isNull())
+ devices << info;
+ }
+ }
+
+ delete audioDevices;
+ }
+ }
+
+ return devices;
+}
+
+
+QT_END_NAMESPACE
+
diff --git a/src/multimedia/audio/qaudiodeviceinfo_mac_p.h b/src/multimedia/audio/qaudiodeviceinfo_mac_p.h
new file mode 100644
index 0000000..ee593de
--- /dev/null
+++ b/src/multimedia/audio/qaudiodeviceinfo_mac_p.h
@@ -0,0 +1,97 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtMultimedia module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the either Technology Preview License Agreement or the
+** Beta Release License Agreement.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain
+** additional rights. These rights are described in the Nokia Qt LGPL
+** Exception version 1.0, 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.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at http://www.qtsoftware.com/contact.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists for the convenience
+// of other Qt classes. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
+
+#ifndef QDEVICEINFO_MAC_P_H
+#define QDEVICEINFO_MAC_P_H
+
+#include <CoreAudio/CoreAudio.h>
+
+#include <QtMultimedia/qaudioengine.h>
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+class QAudioDeviceInfoPrivate : public QAbstractAudioDeviceInfo
+{
+public:
+ AudioDeviceID deviceId;
+ QString name;
+ QAudio::Mode mode;
+
+ QAudioDeviceInfoPrivate(QByteArray const& handle, QAudio::Mode mode);
+
+ bool isFormatSupported(const QAudioFormat& format) const;
+ QAudioFormat preferredFormat() const;
+ QAudioFormat nearestFormat(const QAudioFormat& format) const;
+
+ QString deviceName() const;
+
+ QStringList codecList();
+ QList<int> frequencyList();
+ QList<int> channelsList();
+ QList<int> sampleSizeList();
+ QList<QAudioFormat::Endian> byteOrderList();
+ QList<QAudioFormat::SampleType> sampleTypeList();
+
+ static QByteArray defaultInputDevice();
+ static QByteArray defaultOutputDevice();
+
+ static QList<QByteArray> deviceList(QAudio::Mode mode);
+};
+
+QT_END_NAMESPACE
+
+QT_END_HEADER
+
+#endif // QDEVICEINFO_MAC_P_H
diff --git a/src/multimedia/audio/qaudiodeviceinfo_win32_p.cpp b/src/multimedia/audio/qaudiodeviceinfo_win32_p.cpp
new file mode 100644
index 0000000..1a1995a
--- /dev/null
+++ b/src/multimedia/audio/qaudiodeviceinfo_win32_p.cpp
@@ -0,0 +1,378 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtMultimedia module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the either Technology Preview License Agreement or the
+** Beta Release License Agreement.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain
+** additional rights. These rights are described in the Nokia Qt LGPL
+** Exception version 1.0, 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.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at http://www.qtsoftware.com/contact.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists for the convenience
+// of other Qt classes. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
+
+#include <windows.h>
+#include <mmsystem.h>
+#include "qaudiodeviceinfo_win32_p.h"
+
+// For mingw toolchain mmsystem.h only defines half the defines, so add if needed.
+#ifndef WAVE_FORMAT_44M08
+#define WAVE_FORMAT_44M08 0x00000100
+#define WAVE_FORMAT_44S08 0x00000200
+#define WAVE_FORMAT_44M16 0x00000400
+#define WAVE_FORMAT_44S16 0x00000800
+#define WAVE_FORMAT_48M08 0x00001000
+#define WAVE_FORMAT_48S08 0x00002000
+#define WAVE_FORMAT_48M16 0x00004000
+#define WAVE_FORMAT_48S16 0x00008000
+#define WAVE_FORMAT_96M08 0x00010000
+#define WAVE_FORMAT_96S08 0x00020000
+#define WAVE_FORMAT_96M16 0x00040000
+#define WAVE_FORMAT_96S16 0x00080000
+#endif
+
+
+QAudioDeviceInfoPrivate::QAudioDeviceInfoPrivate(QByteArray dev, QAudio::Mode mode)
+{
+ device = QLatin1String(dev);
+ this->mode = mode;
+}
+
+QAudioDeviceInfoPrivate::~QAudioDeviceInfoPrivate()
+{
+ close();
+}
+
+bool QAudioDeviceInfoPrivate::isFormatSupported(const QAudioFormat& format) const
+{
+ return testSettings(format);
+}
+
+QAudioFormat QAudioDeviceInfoPrivate::preferredFormat() const
+{
+ QAudioFormat nearest;
+ if(mode == QAudio::AudioOutput) {
+ nearest.setFrequency(44100);
+ nearest.setChannels(2);
+ nearest.setByteOrder(QAudioFormat::LittleEndian);
+ nearest.setSampleType(QAudioFormat::SignedInt);
+ nearest.setSampleSize(16);
+ nearest.setCodec(tr("audio/pcm"));
+ } else {
+ nearest.setFrequency(11025);
+ nearest.setChannels(1);
+ nearest.setSampleType(QAudioFormat::SignedInt);
+ nearest.setSampleSize(8);
+ nearest.setCodec(tr("audio/pcm"));
+ }
+ return nearest;
+}
+
+QAudioFormat QAudioDeviceInfoPrivate::nearestFormat(const QAudioFormat& format) const
+{
+ if(testSettings(format))
+ return format;
+ else
+ return preferredFormat();
+}
+
+QString QAudioDeviceInfoPrivate::deviceName() const
+{
+ return device;
+}
+
+QStringList QAudioDeviceInfoPrivate::codecList()
+{
+ updateLists();
+ return codecz;
+}
+
+QList<int> QAudioDeviceInfoPrivate::frequencyList()
+{
+ updateLists();
+ return freqz;
+}
+
+QList<int> QAudioDeviceInfoPrivate::channelsList()
+{
+ updateLists();
+ return channelz;
+}
+
+QList<int> QAudioDeviceInfoPrivate::sampleSizeList()
+{
+ updateLists();
+ return sizez;
+}
+
+QList<QAudioFormat::Endian> QAudioDeviceInfoPrivate::byteOrderList()
+{
+ updateLists();
+ return byteOrderz;
+}
+
+QList<QAudioFormat::SampleType> QAudioDeviceInfoPrivate::sampleTypeList()
+{
+ updateLists();
+ return typez;
+}
+
+
+bool QAudioDeviceInfoPrivate::open()
+{
+ return true;
+}
+
+void QAudioDeviceInfoPrivate::close()
+{
+}
+
+bool QAudioDeviceInfoPrivate::testSettings(const QAudioFormat& format) const
+{
+ // Set nearest to closest settings that do work.
+ // See if what is in settings will work (return value).
+
+ bool testChannel = false;
+ bool testCodec = false;
+ bool testFreq = false;
+
+ int err = 0;
+
+ // For now, just accept only audio/pcm codec
+ if(!format.codec().startsWith(tr("audio/pcm"))) {
+ err=-1;
+ } else
+ testCodec = true;
+
+ if(err>=0 && format.channels() != -1) {
+ testChannel = true;
+ }
+
+ if(err>=0 && format.frequency() != -1) {
+ testFreq = true;
+ }
+
+ if(err == 0) {
+ // settings work
+ return true;
+ }
+ return false;
+}
+
+void QAudioDeviceInfoPrivate::updateLists()
+{
+ // redo all lists based on current settings
+ bool base = false;
+ bool match = false;
+ DWORD fmt = NULL;
+ QString tmp;
+
+ if(device.compare(tr("default")) == 0)
+ base = true;
+
+ if(mode == QAudio::AudioOutput) {
+ WAVEOUTCAPS woc;
+ unsigned long iNumDevs,i;
+ iNumDevs = waveOutGetNumDevs();
+ for(i=0;i<iNumDevs;i++) {
+ if(waveOutGetDevCaps(i, &woc, sizeof(WAVEOUTCAPS))
+ == MMSYSERR_NOERROR) {
+ tmp = QString::fromUtf16((const unsigned short*)woc.szPname);
+ if(tmp.compare(device) == 0) {
+ match = true;
+ fmt = woc.dwFormats;
+ break;
+ }
+ if(base) {
+ match = true;
+ fmt = woc.dwFormats;
+ break;
+ }
+ }
+ }
+ } else {
+ WAVEINCAPS woc;
+ unsigned long iNumDevs,i;
+ iNumDevs = waveInGetNumDevs();
+ for(i=0;i<iNumDevs;i++) {
+ if(waveInGetDevCaps(i, &woc, sizeof(WAVEINCAPS))
+ == MMSYSERR_NOERROR) {
+ tmp = QString::fromUtf16((const unsigned short*)woc.szPname);
+ if(tmp.compare(device) == 0) {
+ match = true;
+ fmt = woc.dwFormats;
+ break;
+ }
+ if(base) {
+ match = true;
+ fmt = woc.dwFormats;
+ break;
+ }
+ }
+ }
+ }
+ sizez.clear();
+ freqz.clear();
+ channelz.clear();
+ byteOrderz.clear();
+ typez.clear();
+ codecz.clear();
+
+ if(match) {
+ if((fmt && WAVE_FORMAT_1M08)
+ || (fmt && WAVE_FORMAT_1S08)
+ || (fmt && WAVE_FORMAT_2M08)
+ || (fmt && WAVE_FORMAT_2S08)
+ || (fmt && WAVE_FORMAT_4M08)
+ || (fmt && WAVE_FORMAT_4S08)
+#ifndef Q_OS_WINCE
+ || (fmt && WAVE_FORMAT_48M08)
+ || (fmt && WAVE_FORMAT_48S08)
+ || (fmt && WAVE_FORMAT_96M08)
+ || (fmt && WAVE_FORMAT_96S08)
+#endif
+ ) {
+ sizez.append(8);
+ }
+ if((fmt && WAVE_FORMAT_1M16)
+ || (fmt && WAVE_FORMAT_1S16)
+ || (fmt && WAVE_FORMAT_2M16)
+ || (fmt && WAVE_FORMAT_2S16)
+ || (fmt && WAVE_FORMAT_4M16)
+ || (fmt && WAVE_FORMAT_4S16)
+#ifndef Q_OS_WINCE
+ || (fmt && WAVE_FORMAT_48M16)
+ || (fmt && WAVE_FORMAT_48S16)
+ || (fmt && WAVE_FORMAT_96M16)
+ || (fmt && WAVE_FORMAT_96S16)
+#endif
+ ) {
+ sizez.append(16);
+ }
+ if((fmt && WAVE_FORMAT_1M08)
+ || (fmt && WAVE_FORMAT_1S08)
+ || (fmt && WAVE_FORMAT_1M16)
+ || (fmt && WAVE_FORMAT_1S16)) {
+ freqz.append(11025);
+ }
+ if((fmt && WAVE_FORMAT_2M08)
+ || (fmt && WAVE_FORMAT_2S08)
+ || (fmt && WAVE_FORMAT_2M16)
+ || (fmt && WAVE_FORMAT_2S16)) {
+ freqz.append(22050);
+ }
+ if((fmt && WAVE_FORMAT_4M08)
+ || (fmt && WAVE_FORMAT_4S08)
+ || (fmt && WAVE_FORMAT_4M16)
+ || (fmt && WAVE_FORMAT_4S16)) {
+ freqz.append(44100);
+ }
+#ifndef Q_OS_WINCE
+ if((fmt && WAVE_FORMAT_48M08)
+ || (fmt && WAVE_FORMAT_48S08)
+ || (fmt && WAVE_FORMAT_48M16)
+ || (fmt && WAVE_FORMAT_48S16)) {
+ freqz.append(48000);
+ }
+ if((fmt && WAVE_FORMAT_96M08)
+ || (fmt && WAVE_FORMAT_96S08)
+ || (fmt && WAVE_FORMAT_96M16)
+ || (fmt && WAVE_FORMAT_96S16)) {
+ freqz.append(96000);
+ }
+#endif
+ channelz.append(1);
+ channelz.append(2);
+
+ byteOrderz.append(QAudioFormat::LittleEndian);
+
+ typez.append(QAudioFormat::SignedInt);
+ typez.append(QAudioFormat::UnSignedInt);
+
+ codecz.append(tr("audio/pcm"));
+ }
+}
+
+QList<QByteArray> QAudioDeviceInfoPrivate::deviceList(QAudio::Mode mode)
+{
+ Q_UNUSED(mode)
+
+ QList<QByteArray> devices;
+
+ devices.append("default");
+
+ if(mode == QAudio::AudioOutput) {
+ WAVEOUTCAPS woc;
+ unsigned long iNumDevs,i;
+ iNumDevs = waveOutGetNumDevs();
+ for(i=0;i<iNumDevs;i++) {
+ if(waveOutGetDevCaps(i, &woc, sizeof(WAVEOUTCAPS))
+ == MMSYSERR_NOERROR) {
+ devices.append(QString::fromUtf16((const unsigned short*)woc.szPname).toLocal8Bit().constData());
+ }
+ }
+ } else {
+ WAVEINCAPS woc;
+ unsigned long iNumDevs,i;
+ iNumDevs = waveInGetNumDevs();
+ for(i=0;i<iNumDevs;i++) {
+ if(waveInGetDevCaps(i, &woc, sizeof(WAVEINCAPS))
+ == MMSYSERR_NOERROR) {
+ devices.append(QString::fromUtf16((const unsigned short*)woc.szPname).toLocal8Bit().constData());
+ }
+ }
+
+ }
+ return devices;
+}
+
+QByteArray QAudioDeviceInfoPrivate::defaultOutputDevice()
+{
+ return QByteArray("default");
+}
+
+QByteArray QAudioDeviceInfoPrivate::defaultInputDevice()
+{
+ return QByteArray("default");
+}
+
diff --git a/src/multimedia/audio/qaudiodeviceinfo_win32_p.h b/src/multimedia/audio/qaudiodeviceinfo_win32_p.h
new file mode 100644
index 0000000..140a741
--- /dev/null
+++ b/src/multimedia/audio/qaudiodeviceinfo_win32_p.h
@@ -0,0 +1,108 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtMultimedia module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the either Technology Preview License Agreement or the
+** Beta Release License Agreement.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain
+** additional rights. These rights are described in the Nokia Qt LGPL
+** Exception version 1.0, 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.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at http://www.qtsoftware.com/contact.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists for the convenience
+// of other Qt classes. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
+
+#ifndef QAUDIODEVICEINFOWIN_H
+#define QAUDIODEVICEINFOWIN_H
+
+#include <QtCore/qbytearray.h>
+#include <QtCore/qstringlist.h>
+#include <QtCore/qlist.h>
+#include <QtCore/qdebug.h>
+
+#include <QtMultimedia/qaudiodeviceinfo.h>
+#include <QtMultimedia/qaudioengine.h>
+
+
+const unsigned int MAX_SAMPLE_RATES = 5;
+const unsigned int SAMPLE_RATES[] = { 8000, 11025, 22050, 44100, 48000 };
+
+class QAudioDeviceInfoPrivate : public QAbstractAudioDeviceInfo
+{
+ Q_OBJECT
+
+public:
+ QAudioDeviceInfoPrivate(QByteArray dev,QAudio::Mode mode);
+ ~QAudioDeviceInfoPrivate();
+
+ bool open();
+ void close();
+
+ bool testSettings(const QAudioFormat& format) const;
+ void updateLists();
+ QAudioFormat preferredFormat() const;
+ bool isFormatSupported(const QAudioFormat& format) const;
+ QAudioFormat nearestFormat(const QAudioFormat& format) const;
+ QString deviceName() const;
+ QStringList codecList();
+ QList<int> frequencyList();
+ QList<int> channelsList();
+ QList<int> sampleSizeList();
+ QList<QAudioFormat::Endian> byteOrderList();
+ QList<QAudioFormat::SampleType> sampleTypeList();
+ static QByteArray defaultInputDevice();
+ static QByteArray defaultOutputDevice();
+ static QList<QByteArray> deviceList(QAudio::Mode);
+
+private:
+ QAudio::Mode mode;
+ QString device;
+ QAudioFormat nearest;
+ QList<int> freqz;
+ QList<int> channelz;
+ QList<int> sizez;
+ QList<QAudioFormat::Endian> byteOrderz;
+ QStringList codecz;
+ QList<QAudioFormat::SampleType> typez;
+};
+
+#endif
diff --git a/src/multimedia/audio/qaudioengine.cpp b/src/multimedia/audio/qaudioengine.cpp
new file mode 100644
index 0000000..930977e
--- /dev/null
+++ b/src/multimedia/audio/qaudioengine.cpp
@@ -0,0 +1,343 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtMultimedia module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the either Technology Preview License Agreement or the
+** Beta Release License Agreement.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain
+** additional rights. These rights are described in the Nokia Qt LGPL
+** Exception version 1.0, 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.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at http://www.qtsoftware.com/contact.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include <QtMultimedia/qaudioengine.h>
+
+QT_BEGIN_NAMESPACE
+
+/*!
+ \class QAbstractAudioDeviceInfo
+ \brief The QAbstractAudioDeviceInfo class provides access for QAudioDeviceInfo to access the audio
+ device provided by the plugin.
+ \internal
+
+ \ingroup multimedia
+
+ This class implements the audio functionality for
+ QAudioDeviceInfo, i.e., QAudioDeviceInfo keeps a
+ QAbstractAudioDeviceInfo and routes function calls to it. For a
+ description of the functionality that QAbstractAudioDeviceInfo
+ implements, you can read the class and functions documentation of
+ QAudioDeviceInfo.
+
+ \sa QAudioDeviceInfo
+*/
+
+/*!
+ \fn virtual QAudioFormat QAbstractAudioDeviceInfo::preferredFormat() const
+ Returns the nearest settings.
+*/
+
+/*!
+ \fn virtual bool QAbstractAudioDeviceInfo::isFormatSupported(const QAudioFormat& format) const
+ Returns true if \a format is available from audio device.
+*/
+
+/*!
+ \fn virtual QAudioFormat QAbstractAudioDeviceInfo::nearestFormat(const QAudioFormat& format) const
+ Returns the nearest settings \a format.
+*/
+
+/*!
+ \fn virtual QString QAbstractAudioDeviceInfo::deviceName() const
+ Returns the audio device name.
+*/
+
+/*!
+ \fn virtual QStringList QAbstractAudioDeviceInfo::codecList()
+ Returns the list of currently available codecs.
+*/
+
+/*!
+ \fn virtual QList<int> QAbstractAudioDeviceInfo::frequencyList()
+ Returns the list of currently available frequencies.
+*/
+
+/*!
+ \fn virtual QList<int> QAbstractAudioDeviceInfo::channelsList()
+ Returns the list of currently available channels.
+*/
+
+/*!
+ \fn virtual QList<int> QAbstractAudioDeviceInfo::sampleSizeList()
+ Returns the list of currently available sample sizes.
+*/
+
+/*!
+ \fn virtual QList<QAudioFormat::Endian> QAbstractAudioDeviceInfo::byteOrderList()
+ Returns the list of currently available byte orders.
+*/
+
+/*!
+ \fn virtual QList<QAudioFormat::SampleType> QAbstractAudioDeviceInfo::sampleTypeList()
+ Returns the list of currently available sample types.
+*/
+
+/*!
+ \class QAbstractAudioOutput
+ \brief The QAbstractAudioOutput class provides access for QAudioOutput to access the audio
+ device provided by the plugin.
+ \internal
+
+ \ingroup multimedia
+
+ QAbstractAudioOutput implements audio functionality for
+ QAudioOutput, i.e., QAudioOutput routes function calls to
+ QAbstractAudioOutput. For a description of the functionality that
+ is implemented, see the QAudioOutput class and function
+ descriptions.
+
+ \sa QAudioOutput
+*/
+
+/*!
+ \fn virtual QIODevice* QAbstractAudioOutput::start(QIODevice* device)
+ Uses the \a device as the QIODevice to transfer data. If \a device is null then the class
+ creates an internal QIODevice. Returns a pointer to the QIODevice being used to handle
+ the data transfer. This QIODevice can be used to write() audio data directly. Passing a
+ QIODevice allows the data to be transfered without any extra code.
+*/
+
+/*!
+ \fn virtual void QAbstractAudioOutput::stop()
+ Stops the audio output.
+*/
+
+/*!
+ \fn virtual void QAbstractAudioOutput::reset()
+ Drops all audio data in the buffers, resets buffers to zero.
+*/
+
+/*!
+ \fn virtual void QAbstractAudioOutput::suspend()
+ Stops processing audio data, preserving buffered audio data.
+*/
+
+/*!
+ \fn virtual void QAbstractAudioOutput::resume()
+ Resumes processing audio data after a suspend()
+*/
+
+/*!
+ \fn virtual int QAbstractAudioOutput::bytesFree() const
+ Returns the free space available in bytes in the audio buffer.
+*/
+
+/*!
+ \fn virtual int QAbstractAudioOutput::periodSize() const
+ Returns the period size in bytes.
+*/
+
+/*!
+ \fn virtual void QAbstractAudioOutput::setBufferSize(int value)
+ Sets the audio buffer size to \a value in bytes.
+*/
+
+/*!
+ \fn virtual int QAbstractAudioOutput::bufferSize() const
+ Returns the audio buffer size in bytes.
+*/
+
+/*!
+ \fn virtual void QAbstractAudioOutput::setNotifyInterval(int ms)
+ Sets the interval for notify() signal to be emitted. This is based on the \a ms
+ of audio data processed not on actual real-time. The resolution of the timer
+ is platform specific.
+*/
+
+/*!
+ \fn virtual int QAbstractAudioOutput::notifyInterval() const
+ Returns the notify interval in milliseconds.
+*/
+
+/*!
+ \fn virtual qint64 QAbstractAudioOutput::totalTime() const
+ Returns the amount of audio data processed since start() was called in milliseconds.
+*/
+
+/*!
+ \fn virtual qint64 QAbstractAudioOutput::clock() const
+ Returns the milliseconds since start() was called, including time in Idle and suspend states.
+*/
+
+/*!
+ \fn virtual QAudio::Error QAbstractAudioOutput::error() const
+ Returns the error state.
+*/
+
+/*!
+ \fn virtual QAudio::State QAbstractAudioOutput::state() const
+ Returns the state of audio processing.
+*/
+
+/*!
+ \fn virtual QAudioFormat QAbstractAudioOutput::format() const
+ Returns the QAudioFormat being used.
+*/
+
+/*!
+ \fn QAbstractAudioOutput::stateChanged(QAudio::State state)
+ This signal is emitted when the device \a state has changed.
+*/
+
+/*!
+ \fn QAbstractAudioOutput::notify()
+ This signal is emitted when x ms of audio data has been processed
+ the interval set by setNotifyInterval(x).
+*/
+
+
+/*!
+ \class QAbstractAudioInput
+ \brief The QAbstractAudioInput class provides access for QAudioInput to access the audio
+ device provided by the plugin.
+ \internal
+
+ \ingroup multimedia
+
+ QAudioDeviceInput keeps an instance of QAbstractAudioInput and
+ routes calls to functions of the same name to QAbstractAudioInput.
+ This means that it is QAbstractAudioInput that implements the
+ audio functionality. For a description of the functionality, see
+ the QAudioInput class description.
+
+ \sa QAudioInput
+*/
+
+/*!
+ \fn virtual QIODevice* QAbstractAudioInput::start(QIODevice* device)
+ Uses the \a device as the QIODevice to transfer data. If \a device is null
+ then the class creates an internal QIODevice. Returns a pointer to the
+ QIODevice being used to handle the data transfer. This QIODevice can be used to
+ read() audio data directly. Passing a QIODevice allows the data to be transfered
+ without any extra code.
+*/
+
+/*!
+ \fn virtual void QAbstractAudioInput::stop()
+ Stops the audio input.
+*/
+
+/*!
+ \fn virtual void QAbstractAudioInput::reset()
+ Drops all audio data in the buffers, resets buffers to zero.
+*/
+
+/*!
+ \fn virtual void QAbstractAudioInput::suspend()
+ Stops processing audio data, preserving buffered audio data.
+*/
+
+/*!
+ \fn virtual void QAbstractAudioInput::resume()
+ Resumes processing audio data after a suspend().
+*/
+
+/*!
+ \fn virtual int QAbstractAudioInput::bytesReady() const
+ Returns the amount of audio data available to read in bytes.
+*/
+
+/*!
+ \fn virtual int QAbstractAudioInput::periodSize() const
+ Returns the period size in bytes.
+*/
+
+/*!
+ \fn virtual void QAbstractAudioInput::setBufferSize(int value)
+ Sets the audio buffer size to \a value in milliseconds.
+*/
+
+/*!
+ \fn virtual int QAbstractAudioInput::bufferSize() const
+ Returns the audio buffer size in milliseconds.
+*/
+
+/*!
+ \fn virtual void QAbstractAudioInput::setNotifyInterval(int ms)
+ Sets the interval for notify() signal to be emitted. This is based
+ on the \a ms of audio data processed not on actual real-time.
+ The resolution of the timer is platform specific.
+*/
+
+/*!
+ \fn virtual int QAbstractAudioInput::notifyInterval() const
+ Returns the notify interval in milliseconds.
+*/
+
+/*!
+ \fn virtual qint64 QAbstractAudioInput::totalTime() const
+ Returns the amount of audio data processed since start() was called in milliseconds.
+*/
+
+/*!
+ \fn virtual qint64 QAbstractAudioInput::clock() const
+ Returns the milliseconds since start() was called, including time in Idle and suspend states.
+*/
+
+/*!
+ \fn virtual QAudio::Error QAbstractAudioInput::error() const
+ Returns the error state.
+*/
+
+/*!
+ \fn virtual QAudio::State QAbstractAudioInput::state() const
+ Returns the state of audio processing.
+*/
+
+/*!
+ \fn virtual QAudioFormat QAbstractAudioInput::format() const
+ Returns the QAudioFormat being used
+*/
+
+/*!
+ \fn QAbstractAudioInput::stateChanged(QAudio::State state)
+ This signal is emitted when the device \a state has changed.
+*/
+
+/*!
+ \fn QAbstractAudioInput::notify()
+ This signal is emitted when x ms of audio data has been processed
+ the interval set by setNotifyInterval(x).
+*/
+
+
+QT_END_NAMESPACE
diff --git a/src/multimedia/audio/qaudioengine.h b/src/multimedia/audio/qaudioengine.h
new file mode 100644
index 0000000..b0aa762
--- /dev/null
+++ b/src/multimedia/audio/qaudioengine.h
@@ -0,0 +1,131 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtMultimedia module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the either Technology Preview License Agreement or the
+** Beta Release License Agreement.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain
+** additional rights. These rights are described in the Nokia Qt LGPL
+** Exception version 1.0, 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.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at http://www.qtsoftware.com/contact.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QAUDIOENGINE_H
+#define QAUDIOENGINE_H
+
+#include <QtCore/qglobal.h>
+#include <QtMultimedia/qaudio.h>
+#include <QtMultimedia/qaudioformat.h>
+#include <QtMultimedia/qaudiodeviceinfo.h>
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+QT_MODULE(Multimedia)
+
+class Q_MULTIMEDIA_EXPORT QAbstractAudioDeviceInfo : public QObject
+{
+ Q_OBJECT
+
+public:
+ virtual QAudioFormat preferredFormat() const = 0;
+ virtual bool isFormatSupported(const QAudioFormat &format) const = 0;
+ virtual QAudioFormat nearestFormat(const QAudioFormat &format) const = 0;
+ virtual QString deviceName() const = 0;
+ virtual QStringList codecList() = 0;
+ virtual QList<int> frequencyList() = 0;
+ virtual QList<int> channelsList() = 0;
+ virtual QList<int> sampleSizeList() = 0;
+ virtual QList<QAudioFormat::Endian> byteOrderList() = 0;
+ virtual QList<QAudioFormat::SampleType> sampleTypeList() = 0;
+};
+
+class Q_MULTIMEDIA_EXPORT QAbstractAudioOutput : public QObject
+{
+ Q_OBJECT
+
+public:
+ virtual QIODevice* start(QIODevice* device) = 0;
+ virtual void stop() = 0;
+ virtual void reset() = 0;
+ virtual void suspend() = 0;
+ virtual void resume() = 0;
+ virtual int bytesFree() const = 0;
+ virtual int periodSize() const = 0;
+ virtual void setBufferSize(int value) = 0;
+ virtual int bufferSize() const = 0;
+ virtual void setNotifyInterval(int milliSeconds) = 0;
+ virtual int notifyInterval() const = 0;
+ virtual qint64 totalTime() const = 0;
+ virtual qint64 clock() const = 0;
+ virtual QAudio::Error error() const = 0;
+ virtual QAudio::State state() const = 0;
+ virtual QAudioFormat format() const = 0;
+
+Q_SIGNALS:
+ void stateChanged(QAudio::State);
+ void notify();
+};
+
+class Q_MULTIMEDIA_EXPORT QAbstractAudioInput : public QObject
+{
+ Q_OBJECT
+
+public:
+ virtual QIODevice* start(QIODevice* device) = 0;
+ virtual void stop() = 0;
+ virtual void reset() = 0;
+ virtual void suspend() = 0;
+ virtual void resume() = 0;
+ virtual int bytesReady() const = 0;
+ virtual int periodSize() const = 0;
+ virtual void setBufferSize(int value) = 0;
+ virtual int bufferSize() const = 0;
+ virtual void setNotifyInterval(int milliSeconds) = 0;
+ virtual int notifyInterval() const = 0;
+ virtual qint64 totalTime() const = 0;
+ virtual qint64 clock() const = 0;
+ virtual QAudio::Error error() const = 0;
+ virtual QAudio::State state() const = 0;
+ virtual QAudioFormat format() const = 0;
+
+Q_SIGNALS:
+ void stateChanged(QAudio::State);
+ void notify();
+};
+
+QT_END_NAMESPACE
+
+QT_END_HEADER
+
+#endif // QAUDIOENGINE_H
diff --git a/src/multimedia/audio/qaudioengineplugin.cpp b/src/multimedia/audio/qaudioengineplugin.cpp
new file mode 100644
index 0000000..6e39004
--- /dev/null
+++ b/src/multimedia/audio/qaudioengineplugin.cpp
@@ -0,0 +1,54 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtMultimedia module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the either Technology Preview License Agreement or the
+** Beta Release License Agreement.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain
+** additional rights. These rights are described in the Nokia Qt LGPL
+** Exception version 1.0, 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.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at http://www.qtsoftware.com/contact.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+
+#include <QtMultimedia/qaudioengineplugin.h>
+
+QT_BEGIN_NAMESPACE
+
+QAudioEnginePlugin::QAudioEnginePlugin(QObject* parent) :
+ QObject(parent)
+{}
+
+QAudioEnginePlugin::~QAudioEnginePlugin()
+{}
+
+QT_END_NAMESPACE
diff --git a/src/multimedia/audio/qaudioengineplugin.h b/src/multimedia/audio/qaudioengineplugin.h
new file mode 100644
index 0000000..8eab2d7
--- /dev/null
+++ b/src/multimedia/audio/qaudioengineplugin.h
@@ -0,0 +1,93 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtMultimedia module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the either Technology Preview License Agreement or the
+** Beta Release License Agreement.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain
+** additional rights. These rights are described in the Nokia Qt LGPL
+** Exception version 1.0, 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.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at http://www.qtsoftware.com/contact.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+
+#ifndef QAUDIOENGINEPLUGIN_H
+#define QAUDIOENGINEPLUGIN_H
+
+#include <QtCore/qstring.h>
+#include <QtCore/qplugin.h>
+#include <QtCore/qfactoryinterface.h>
+
+#include <QtMultimedia/qaudioformat.h>
+#include <QtMultimedia/qaudiodeviceinfo.h>
+#include <QtMultimedia/qaudioengine.h>
+
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+QT_MODULE(Multimedia)
+
+struct Q_MULTIMEDIA_EXPORT QAudioEngineFactoryInterface : public QFactoryInterface
+{
+ virtual QList<QByteArray> deviceList(QAudio::Mode) const = 0;
+ virtual QAbstractAudioInput* createInput(const QByteArray& device, const QAudioFormat& format = QAudioFormat()) = 0;
+ virtual QAbstractAudioOutput* createOutput(const QByteArray& device, const QAudioFormat& format = QAudioFormat()) = 0;
+ virtual QAbstractAudioDeviceInfo* createDeviceInfo(const QByteArray& device, QAudio::Mode mode) = 0;
+};
+
+#define QAudioEngineFactoryInterface_iid \
+ "com.nokia.qt.QAudioEngineFactoryInterface"
+Q_DECLARE_INTERFACE(QAudioEngineFactoryInterface, QAudioEngineFactoryInterface_iid)
+
+class Q_MULTIMEDIA_EXPORT QAudioEnginePlugin : public QObject, public QAudioEngineFactoryInterface
+{
+ Q_OBJECT
+ Q_INTERFACES(QAudioEngineFactoryInterface:QFactoryInterface)
+
+public:
+ QAudioEnginePlugin(QObject *parent = 0);
+ ~QAudioEnginePlugin();
+
+ virtual QStringList keys() const = 0;
+ virtual QList<QByteArray> deviceList(QAudio::Mode) const = 0;
+ virtual QAbstractAudioInput* createInput(const QByteArray& device, const QAudioFormat& format = QAudioFormat()) = 0;
+ virtual QAbstractAudioOutput* createOutput(const QByteArray& device, const QAudioFormat& format = QAudioFormat()) = 0;
+ virtual QAbstractAudioDeviceInfo* createDeviceInfo(const QByteArray& device, QAudio::Mode mode) = 0;
+};
+
+QT_END_NAMESPACE
+
+QT_END_HEADER
+
+#endif // QAUDIOENGINEPLUGIN_H
diff --git a/src/multimedia/audio/qaudioformat.cpp b/src/multimedia/audio/qaudioformat.cpp
new file mode 100644
index 0000000..6632c63
--- /dev/null
+++ b/src/multimedia/audio/qaudioformat.cpp
@@ -0,0 +1,335 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtMultimedia module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the either Technology Preview License Agreement or the
+** Beta Release License Agreement.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain
+** additional rights. These rights are described in the Nokia Qt LGPL
+** Exception version 1.0, 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.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at http://www.qtsoftware.com/contact.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include <QtMultimedia/qaudioformat.h>
+
+
+QT_BEGIN_NAMESPACE
+
+
+class QAudioFormatPrivate : public QSharedData
+{
+public:
+ QAudioFormatPrivate()
+ {
+ frequency = -1;
+ channels = -1;
+ sampleSize = -1;
+ byteOrder = QAudioFormat::Endian(QSysInfo::ByteOrder);
+ sampleType = QAudioFormat::Unknown;
+ }
+
+ QString codec;
+ QAudioFormat::Endian byteOrder;
+ QAudioFormat::SampleType sampleType;
+
+ int frequency;
+ int channels;
+ int sampleSize;
+};
+
+/*!
+ \class QAudioFormat
+ \brief The QAudioFormat class stores audio parameter information.
+
+ \inmodule QtMultimedia
+ \ingroup multimedia
+ \since 4.6
+
+ An audio format specifies how data in an audio stream is arranged,
+ i.e, how the stream is to be interpreted. The encoding itself is
+ specified by the codec() used for the stream.
+
+ In addition to the encoding, QAudioFormat contains other
+ parameters that further specify how the audio data is arranged.
+ These are the frequency, the number of channels, the sample size,
+ the sample type, and the byte order. The following table describes
+ these in more detail.
+
+ \table
+ \header
+ \o Parameter
+ \o Description
+ \row
+ \o Frequency
+ \o Samples per second of audio data in Hertz.
+ \row
+ \o Number of channels
+ \o The number of audio channels (typically one for mono
+ or two for stereo)
+ \row
+ \o Sample size
+ \o How much data is stored in each sample (typically 8
+ or 16)
+ \row
+ \o Sample type
+ \o Numerical representation of sample (typically signed integer,
+ unsigned integer or float)
+ \row
+ \o Byte order
+ \o Byte ordering of sample (typically little endian, big endian)
+ \endtable
+
+ You can obtain audio formats compatible with the audio device used
+ through functions in QAudioDeviceInfo. This class also lets you
+ query available parameter values for a device, so that you can set
+ the parameters yourself. See the QAudioDeviceInfo class
+ description for details.
+*/
+
+/*!
+ Construct a new audio format.
+
+ Values are initialized as follows:
+ \list
+ \o frequency() = -1
+ \o channels() = -1
+ \o sampleSize() = -1
+ \o byteOrder() = QAudioFormat::Endian(QSysInfo::ByteOrder)
+ \o sampleType() = QAudioFormat::Unknown
+ \c codec() = ""
+ \endlist
+*/
+
+QAudioFormat::QAudioFormat():
+ d(new QAudioFormatPrivate)
+{
+}
+
+/*!
+ Construct a new audio format using \a other.
+*/
+
+QAudioFormat::QAudioFormat(const QAudioFormat &other):
+ d(other.d)
+{
+}
+
+/*!
+ Destroy this audio format.
+*/
+
+QAudioFormat::~QAudioFormat()
+{
+}
+
+/*!
+ Assigns \a other to this QAudioFormat implementation.
+*/
+
+QAudioFormat& QAudioFormat::operator=(const QAudioFormat &other)
+{
+ d = other.d;
+ return *this;
+}
+
+/*!
+ Returns true if this QAudioFormat is equal to the \a other
+ QAudioFormat; otherwise returns false.
+
+ All elements of QAudioFormat are used for the comparison.
+*/
+
+bool QAudioFormat::operator==(const QAudioFormat &other) const
+{
+ return d->frequency == other.d->frequency &&
+ d->channels == other.d->channels &&
+ d->sampleSize == other.d->sampleSize &&
+ d->byteOrder == other.d->byteOrder &&
+ d->codec == other.d->codec &&
+ d->sampleType == other.d->sampleType;
+}
+
+/*!
+ Returns true if this QAudioFormat is not equal to the \a other
+ QAudioFormat; otherwise returns false.
+
+ All elements of QAudioFormat are used for the comparison.
+*/
+
+bool QAudioFormat::operator!=(const QAudioFormat& other) const
+{
+ return !(*this == other);
+}
+
+/*!
+ Returns true if any of the parameters are invalid.
+*/
+
+bool QAudioFormat::isNull() const
+{
+ return d->frequency == -1 && d->channels == -1 &&
+ d->sampleSize == -1 &&
+ d->byteOrder == QAudioFormat::Endian(QSysInfo::ByteOrder) &&
+ d->sampleType == QAudioFormat::Unknown &&
+ d->codec.isNull();
+}
+
+/*!
+ Sets the frequency to \a frequency.
+*/
+
+void QAudioFormat::setFrequency(int frequency)
+{
+ d->frequency = frequency;
+}
+
+/*!
+ Returns the current frequency value.
+*/
+
+int QAudioFormat::frequency() const
+{
+ return d->frequency;
+}
+
+/*!
+ Sets the channels to \a channels.
+*/
+
+void QAudioFormat::setChannels(int channels)
+{
+ d->channels = channels;
+}
+
+/*!
+ Returns the current channel value.
+*/
+
+int QAudioFormat::channels() const
+{
+ return d->channels;
+}
+
+/*!
+ Sets the sampleSize to \a sampleSize.
+*/
+
+void QAudioFormat::setSampleSize(int sampleSize)
+{
+ d->sampleSize = sampleSize;
+}
+
+/*!
+ Returns the current sampleSize value.
+*/
+
+int QAudioFormat::sampleSize() const
+{
+ return d->sampleSize;
+}
+
+/*!
+ Sets the codec to \a codec.
+
+ \sa QAudioDeviceInfo::supportedCodecs()
+*/
+
+void QAudioFormat::setCodec(QString codec)
+{
+ d->codec = codec;
+}
+
+/*!
+ Returns the current codec value.
+
+ \sa QAudioDeviceInfo::supportedCodecs()
+*/
+
+QString QAudioFormat::codec() const
+{
+ return d->codec;
+}
+
+/*!
+ Sets the byteOrder to \a byteOrder.
+*/
+
+void QAudioFormat::setByteOrder(QAudioFormat::Endian byteOrder)
+{
+ d->byteOrder = byteOrder;
+}
+
+/*!
+ Returns the current byteOrder value.
+*/
+
+QAudioFormat::Endian QAudioFormat::byteOrder() const
+{
+ return d->byteOrder;
+}
+
+/*!
+ Sets the sampleType to \a sampleType.
+*/
+
+void QAudioFormat::setSampleType(QAudioFormat::SampleType sampleType)
+{
+ d->sampleType = sampleType;
+}
+
+/*!
+ Returns the current SampleType value.
+*/
+
+QAudioFormat::SampleType QAudioFormat::sampleType() const
+{
+ return d->sampleType;
+}
+
+/*!
+ \enum QAudioFormat::SampleType
+
+ \value Unknown Not Set
+ \value SignedInt samples are signed integers
+ \value UnSignedInt samples are unsigned intergers
+ \value Float samples are floats
+*/
+
+/*!
+ \enum QAudioFormat::Endian
+
+ \value BigEndian samples are big endian byte order
+ \value LittleEndian samples are little endian byte order
+*/
+
+QT_END_NAMESPACE
+
diff --git a/src/multimedia/audio/qaudioformat.h b/src/multimedia/audio/qaudioformat.h
new file mode 100644
index 0000000..c740969
--- /dev/null
+++ b/src/multimedia/audio/qaudioformat.h
@@ -0,0 +1,103 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtMultimedia module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the either Technology Preview License Agreement or the
+** Beta Release License Agreement.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain
+** additional rights. These rights are described in the Nokia Qt LGPL
+** Exception version 1.0, 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.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at http://www.qtsoftware.com/contact.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+
+#ifndef QAUDIOFORMAT_H
+#define QAUDIOFORMAT_H
+
+#include <QtCore/qobject.h>
+#include <QtCore/qglobal.h>
+#include <QtCore/qshareddata.h>
+
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+QT_MODULE(Multimedia)
+
+
+class QAudioFormatPrivate;
+
+class Q_MULTIMEDIA_EXPORT QAudioFormat
+{
+public:
+ enum SampleType { Unknown, SignedInt, UnSignedInt, Float };
+ enum Endian { BigEndian = QSysInfo::BigEndian, LittleEndian = QSysInfo::LittleEndian };
+
+ QAudioFormat();
+ QAudioFormat(const QAudioFormat &other);
+ ~QAudioFormat();
+
+ QAudioFormat& operator=(const QAudioFormat &other);
+ bool operator==(const QAudioFormat &other) const;
+ bool operator!=(const QAudioFormat &other) const;
+
+ bool isNull() const;
+
+ void setFrequency(int frequency);
+ int frequency() const;
+
+ void setChannels(int channels);
+ int channels() const;
+
+ void setSampleSize(int sampleSize);
+ int sampleSize() const;
+
+ void setCodec(QString codec);
+ QString codec() const;
+
+ void setByteOrder(QAudioFormat::Endian byteOrder);
+ QAudioFormat::Endian byteOrder() const;
+
+ void setSampleType(QAudioFormat::SampleType sampleType);
+ QAudioFormat::SampleType sampleType() const;
+
+private:
+ QSharedDataPointer<QAudioFormatPrivate> d;
+};
+
+
+QT_END_NAMESPACE
+
+QT_END_HEADER
+
+#endif // QAUDIOFORMAT_H
diff --git a/src/multimedia/audio/qaudioinput.cpp b/src/multimedia/audio/qaudioinput.cpp
new file mode 100644
index 0000000..17cacc6
--- /dev/null
+++ b/src/multimedia/audio/qaudioinput.cpp
@@ -0,0 +1,400 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtMultimedia module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the either Technology Preview License Agreement or the
+** Beta Release License Agreement.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain
+** additional rights. These rights are described in the Nokia Qt LGPL
+** Exception version 1.0, 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.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at http://www.qtsoftware.com/contact.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+
+#include <QtMultimedia/qaudio.h>
+#include <QtMultimedia/qaudiodeviceinfo.h>
+#include <QtMultimedia/qaudioengine.h>
+#include <QtMultimedia/qaudioinput.h>
+
+#include "qaudiodevicefactory_p.h"
+
+
+QT_BEGIN_NAMESPACE
+
+/*!
+ \class QAudioInput
+ \brief The QAudioInput class provides an interface for receiving audio data from an audio input device.
+
+ \inmodule QtMultimedia
+ \ingroup multimedia
+ \since 4.6
+
+ You can construct an audio input with the system's
+ \l{QAudioDeviceInfo::defaultInputDevice()}{default audio input
+ device}. It is also possible to create QAudioInput with a
+ specific QAudioDeviceId. When you create the audio input, you
+ should also send in the QAudioFormat to be used for the recording
+ (see the QAudioFormat class description for details).
+
+ To record to a file:
+
+ QAudioInput lets you record audio with an audio input device. The
+ default constructor of this class will use the systems default
+ audio device, but you can also specify a QAudioDeviceId for a
+ specific device. You also need to pass in the QAudioFormat in
+ which you wish to record.
+
+ Starting up the QAudioInput is simply a matter of calling start()
+ with a QIODevice opened for writing. For instance, to record to a
+ file, you can:
+
+ \code
+ {
+ QFile outputFile;
+ outputFile.setFileName("/tmp/test.raw");
+ outputFile.open( QIODevice::WriteOnly | QIODevice::Truncate );
+
+ QAudioFormat format;
+ // set up the format you want, eg.
+ format.setFrequency(8000);
+ format.setChannels(1);
+ format.setSampleSize(8);
+ format.setCodec("audio/pcm");
+ format.setByteOrder(QAudioFormat::LittleEndian);
+ format.setSampleType(QAudioFormat::UnSignedInt);
+
+ QAudioInput *audio = new QAudioInput(format, this);
+ QTimer::singleShot(3000, this, SLOT(stopRecording()));
+ audio->start(outputFile);
+ // Records audio for 3000ms
+ }
+ \endcode
+
+ This will start recording if the format specified is supported by
+ the input device (you can check this with
+ QAudioDeviceInfo::isFormatSupported(). In case there are any
+ snags, use the error() function to check what went wrong. We stop
+ recording in the \c stopRecording() slot.
+
+ \code
+ void stopRecording()
+ {
+ audio->stop();
+ outputFile->close();
+ }
+ \endcode
+
+ At any point in time, QAudioInput will be in one of four states:
+ active, suspended, stopped, or idle. These states are specified by
+ the QAudio::State enum. You can request a state change directly through
+ suspend(), resume(), stop(), reset(), and start(). The current
+ state is reported by state(). QAudioOutput will also signal you
+ when the state changes (stateChanged()).
+
+ QAudioInput provides several ways of measuring the time that has
+ passed since the start() of the recording. The \c totalTime()
+ function returns the length of the stream in microseconds written,
+ i.e., it leaves out the times the audio input was suspended or idle.
+ The clock() function returns the time elapsed since start() was called regardless of
+ which states the QAudioInput has been in.
+
+ If an error should occur, you can fetch its reason with error().
+ The possible error reasons are described by the QAudio::Error enum.
+
+ \sa QAudioOutput, QAudioDeviceInfo
+*/
+
+/*!
+ Construct a new audio input and attach it to \a parent.
+ The default audio input device is used with the output
+ \a format parameters.
+*/
+
+QAudioInput::QAudioInput(const QAudioFormat &format, QObject *parent):
+ QObject(parent)
+{
+ d = QAudioDeviceFactory::createDefaultInputDevice(format);
+ connect(d, SIGNAL(notify()), SIGNAL(notify()));
+ connect(d, SIGNAL(stateChanged(QAudio::State)), SIGNAL(stateChanged(QAudio::State)));
+}
+
+/*!
+ Construct a new audio input and attach it to \a parent.
+ The \a id of the audio input device is used with the input
+ \a format parameters.
+*/
+
+QAudioInput::QAudioInput(const QAudioDeviceId &id, const QAudioFormat &format, QObject *parent):
+ QObject(parent)
+{
+ d = QAudioDeviceFactory::createInputDevice(id, format);
+ connect(d, SIGNAL(notify()), SIGNAL(notify()));
+ connect(d, SIGNAL(stateChanged(QAudio::State)), SIGNAL(stateChanged(QAudio::State)));
+}
+
+/*!
+ Destroy this audio input.
+*/
+
+QAudioInput::~QAudioInput()
+{
+ delete d;
+}
+
+/*!
+ Uses the \a device as the QIODevice to transfer data.
+ If \a device is null then the class creates an internal QIODevice.
+ Returns a pointer to the QIODevice being used to handle the data
+ transfer. This QIODevice can be used to read() audio data
+ directly.
+ Passing a QIODevice allows the data to be transfered without any extra code.
+ All that is required is to open the QIODevice.
+
+ /sa QIODevice
+*/
+
+QIODevice* QAudioInput::start(QIODevice* device)
+{
+ /*
+ PULL MODE (valid QIODevice)
+ -If currently not StopState, stop
+ -If previous start was push mode, delete internal QIODevice.
+ -open audio input.
+ If ok, NoError and ActiveState, else OpenError and StopState.
+ -emit stateChanged()
+ -return device
+
+ PUSH MODE (device = 0)
+ -If currently not StopState, stop
+ -If no internal QIODevice, create one.
+ -open audio input.
+ -If ok, NoError and IdleState, else OpenError and StopState
+ -emit stateChanged()
+ -return internal QIODevice
+ */
+ return d->start(device);
+}
+
+/*!
+ Returns the QAudioFormat being used.
+*/
+
+QAudioFormat QAudioInput::format() const
+{
+ return d->format();
+}
+
+/*!
+ Stops the audio input.
+*/
+
+void QAudioInput::stop()
+{
+ /*
+ -If StopState, return
+ -set to StopState
+ -detach from audio device
+ -emit stateChanged()
+ */
+ d->stop();
+}
+
+/*!
+ Drops all audio data in the buffers, resets buffers to zero.
+*/
+
+void QAudioInput::reset()
+{
+ /*
+ -drop all buffered audio, set buffers to zero.
+ -call stop()
+ */
+ d->reset();
+}
+
+/*!
+ Stops processing audio data, preserving buffered audio data.
+*/
+
+void QAudioInput::suspend()
+{
+ /*
+ -If not ActiveState|IdleState, return
+ -stop processing audio, saving all buffered audio data
+ -set NoError and SuspendState
+ -emit stateChanged()
+ */
+ d->suspend();
+}
+
+/*!
+ Resumes processing audio data after a suspend().
+*/
+
+void QAudioInput::resume()
+{
+ /*
+ -If SuspendState, return
+ -resume audio
+ -(PULL MODE): set ActiveState, NoError
+ -(PUSH MODE): set IdleState, NoError
+ -kick start audio if needed
+ -emit stateChanged()
+ */
+ d->resume();
+}
+
+/*!
+ Sets the audio buffer size to \a value milliseconds.
+
+ Note: This function can be called anytime before start(), calls to this
+ are ignored after start(). It should not be assumed that the buffer size
+ set is the actual buffer size used, calling bufferSize() anytime after start()
+ will return the actual buffer size being used.
+
+*/
+
+void QAudioInput::setBufferSize(int value)
+{
+ d->setBufferSize(value);
+}
+
+/*!
+ Returns the audio buffer size in milliseconds.
+
+ If called before start(), returns platform default value.
+ If called before start() but setBufferSize() was called prior, returns value set by setBufferSize().
+ If called after start(), returns the actual buffer size being used. This may not be what was set previously
+ by setBufferSize().
+
+*/
+
+int QAudioInput::bufferSize() const
+{
+ return d->bufferSize();
+}
+
+/*!
+ Returns the amount of audio data available to read in bytes.
+*/
+
+int QAudioInput::bytesReady() const
+{
+ /*
+ -If not ActiveState|IdleState, return 0
+ -return amount of audio data available to read
+ */
+ return d->bytesReady();
+}
+
+/*!
+ Returns the period size in bytes.
+
+ Note: This is the recommended read size in bytes.
+*/
+
+int QAudioInput::periodSize() const
+{
+ return d->periodSize();
+}
+
+/*!
+ Sets the interval for notify() signal to be emitted.
+ This is based on the \a ms of audio data processed
+ not on actual real-time. The resolution of the timer is platform specific.
+*/
+
+void QAudioInput::setNotifyInterval(int ms)
+{
+ d->setNotifyInterval(ms);
+}
+
+/*!
+ Returns the notify interval in milliseconds.
+*/
+
+int QAudioInput::notifyInterval() const
+{
+ return d->notifyInterval();
+}
+
+/*!
+ Returns the amount of audio data processed since start()
+ was called in microseconds.
+*/
+
+qint64 QAudioInput::totalTime() const
+{
+ return d->totalTime();
+}
+
+/*!
+ Returns the microseconds since start() was called, including time in Idle and
+ Suspend states.
+*/
+
+qint64 QAudioInput::clock() const
+{
+ return d->clock();
+}
+
+/*!
+ Returns the error state.
+*/
+
+QAudio::Error QAudioInput::error() const
+{
+ return d->error();
+}
+
+/*!
+ Returns the state of audio processing.
+*/
+
+QAudio::State QAudioInput::state() const
+{
+ return d->state();
+}
+
+/*!
+ \fn QAudioInput::stateChanged(QAudio::State state)
+ This signal is emitted when the device \a state has changed.
+*/
+
+/*!
+ \fn QAudioInput::notify()
+ This signal is emitted when x ms of audio data has been processed
+ the interval set by setNotifyInterval(x).
+*/
+
+QT_END_NAMESPACE
+
diff --git a/src/multimedia/audio/qaudioinput.h b/src/multimedia/audio/qaudioinput.h
new file mode 100644
index 0000000..b0f1aed
--- /dev/null
+++ b/src/multimedia/audio/qaudioinput.h
@@ -0,0 +1,108 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtMultimedia module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the either Technology Preview License Agreement or the
+** Beta Release License Agreement.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain
+** additional rights. These rights are described in the Nokia Qt LGPL
+** Exception version 1.0, 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.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at http://www.qtsoftware.com/contact.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+
+#ifndef QAUDIOINPUT_H
+#define QAUDIOINPUT_H
+
+#include <QtCore/qiodevice.h>
+#include <QtCore/qglobal.h>
+
+#include <QtMultimedia/qaudio.h>
+#include <QtMultimedia/qaudioformat.h>
+#include <QtMultimedia/qaudiodeviceid.h>
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+QT_MODULE(Multimedia)
+
+
+class QAbstractAudioInput;
+
+class Q_MULTIMEDIA_EXPORT QAudioInput : public QObject
+{
+ Q_OBJECT
+
+public:
+ explicit QAudioInput(const QAudioFormat &format = QAudioFormat(), QObject *parent = 0);
+ explicit QAudioInput(const QAudioDeviceId &id, const QAudioFormat &format = QAudioFormat(), QObject *parent = 0);
+ ~QAudioInput();
+
+ QAudioFormat format() const;
+
+ QIODevice* start(QIODevice *device = 0);
+ void stop();
+ void reset();
+ void suspend();
+ void resume();
+
+ void setBufferSize(int bytes);
+ int bufferSize() const;
+
+ int bytesReady() const;
+ int periodSize() const;
+
+ void setNotifyInterval(int milliSeconds);
+ int notifyInterval() const;
+
+ qint64 totalTime() const;
+ qint64 clock() const;
+
+ QAudio::Error error() const;
+ QAudio::State state() const;
+
+Q_SIGNALS:
+ void stateChanged(QAudio::State);
+ void notify();
+
+private:
+ Q_DISABLE_COPY(QAudioInput);
+
+ QAbstractAudioInput* d;
+};
+
+QT_END_NAMESPACE
+
+QT_END_HEADER
+
+#endif // QAUDIOINPUT_H
diff --git a/src/multimedia/audio/qaudioinput_alsa_p.cpp b/src/multimedia/audio/qaudioinput_alsa_p.cpp
new file mode 100644
index 0000000..6f00469
--- /dev/null
+++ b/src/multimedia/audio/qaudioinput_alsa_p.cpp
@@ -0,0 +1,688 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtMultimedia module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the either Technology Preview License Agreement or the
+** Beta Release License Agreement.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain
+** additional rights. These rights are described in the Nokia Qt LGPL
+** Exception version 1.0, 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.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at http://www.qtsoftware.com/contact.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists for the convenience
+// of other Qt classes. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
+#include <QtCore/qcoreapplication.h>
+#include "qaudioinput_alsa_p.h"
+
+//#define DEBUG_AUDIO 1
+
+QAudioInputPrivate::QAudioInputPrivate(const QByteArray &device, const QAudioFormat& audioFormat):
+ settings(audioFormat)
+{
+ bytesAvailable = 0;
+ handle = 0;
+ ahandler = 0;
+ access = SND_PCM_ACCESS_RW_INTERLEAVED;
+ pcmformat = SND_PCM_FORMAT_S16;
+ buffer_size = 0;
+ period_size = 0;
+ buffer_time = 100000;
+ period_time = 20000;
+ totalTimeValue = 0;
+ intervalTime = 1000;
+ audioBuffer = 0;
+ errorState = QAudio::NoError;
+ deviceState = QAudio::StopState;
+ audioSource = 0;
+ pullMode = true;
+ resuming = false;
+
+ QStringList list1 = QString(tr(device)).split(tr(":"));
+ m_device = QByteArray(list1.at(0).toLocal8Bit().constData());
+
+ timer = new QTimer(this);
+ connect(timer,SIGNAL(timeout()),SLOT(userFeed()));
+}
+
+QAudioInputPrivate::~QAudioInputPrivate()
+{
+ close();
+ disconnect(timer, SIGNAL(timeout()));
+ QCoreApplication::processEvents();
+ delete timer;
+}
+
+QAudio::Error QAudioInputPrivate::error() const
+{
+ return errorState;
+}
+
+QAudio::State QAudioInputPrivate::state() const
+{
+ return deviceState;
+}
+
+
+QAudioFormat QAudioInputPrivate::format() const
+{
+ return settings;
+}
+
+int QAudioInputPrivate::xrun_recovery(int err)
+{
+ int count = 0;
+ bool reset = false;
+
+ if(err == -EPIPE) {
+ errorState = QAudio::UnderrunError;
+ err = snd_pcm_prepare(handle);
+ if(err < 0)
+ reset = true;
+
+ } else if((err == -ESTRPIPE)||(err == -EIO)) {
+ errorState = QAudio::IOError;
+ while((err = snd_pcm_resume(handle)) == -EAGAIN){
+ usleep(100);
+ count++;
+ if(count > 5) {
+ reset = true;
+ break;
+ }
+ }
+ if(err < 0) {
+ err = snd_pcm_prepare(handle);
+ if(err < 0)
+ reset = true;
+ }
+ }
+ if(reset) {
+ close();
+ open();
+ snd_pcm_prepare(handle);
+ return 0;
+ }
+ return err;
+}
+
+int QAudioInputPrivate::setFormat()
+{
+ snd_pcm_format_t format = SND_PCM_FORMAT_S16;
+
+ if(settings.sampleSize() == 8) {
+ format = SND_PCM_FORMAT_U8;
+ } else if(settings.sampleSize() == 16) {
+ if(settings.sampleType() == QAudioFormat::SignedInt) {
+ if(settings.byteOrder() == QAudioFormat::LittleEndian)
+ format = SND_PCM_FORMAT_S16_LE;
+ else
+ format = SND_PCM_FORMAT_S16_BE;
+ } else if(settings.sampleType() == QAudioFormat::UnSignedInt) {
+ if(settings.byteOrder() == QAudioFormat::LittleEndian)
+ format = SND_PCM_FORMAT_U16_LE;
+ else
+ format = SND_PCM_FORMAT_U16_BE;
+ }
+ } else if(settings.sampleSize() == 24) {
+ if(settings.sampleType() == QAudioFormat::SignedInt) {
+ if(settings.byteOrder() == QAudioFormat::LittleEndian)
+ format = SND_PCM_FORMAT_S24_LE;
+ else
+ format = SND_PCM_FORMAT_S24_BE;
+ } else if(settings.sampleType() == QAudioFormat::UnSignedInt) {
+ if(settings.byteOrder() == QAudioFormat::LittleEndian)
+ format = SND_PCM_FORMAT_U24_LE;
+ else
+ format = SND_PCM_FORMAT_U24_BE;
+ }
+ } else if(settings.sampleSize() == 32) {
+ if(settings.sampleType() == QAudioFormat::SignedInt) {
+ if(settings.byteOrder() == QAudioFormat::LittleEndian)
+ format = SND_PCM_FORMAT_S32_LE;
+ else
+ format = SND_PCM_FORMAT_S32_BE;
+ } else if(settings.sampleType() == QAudioFormat::UnSignedInt) {
+ if(settings.byteOrder() == QAudioFormat::LittleEndian)
+ format = SND_PCM_FORMAT_U32_LE;
+ else
+ format = SND_PCM_FORMAT_U32_BE;
+ } else if(settings.sampleType() == QAudioFormat::Float) {
+ if(settings.byteOrder() == QAudioFormat::LittleEndian)
+ format = SND_PCM_FORMAT_FLOAT_LE;
+ else
+ format = SND_PCM_FORMAT_FLOAT_BE;
+ }
+ } else if(settings.sampleSize() == 64) {
+ if(settings.byteOrder() == QAudioFormat::LittleEndian)
+ format = SND_PCM_FORMAT_FLOAT64_LE;
+ else
+ format = SND_PCM_FORMAT_FLOAT64_BE;
+ }
+
+ return snd_pcm_hw_params_set_format( handle, hwparams, format);
+}
+
+QIODevice* QAudioInputPrivate::start(QIODevice* device)
+{
+ if(deviceState != QAudio::StopState)
+ close();
+
+ if(!pullMode && audioSource) {
+ delete audioSource;
+ }
+
+ if(device) {
+ //set to pull mode
+ pullMode = true;
+ audioSource = device;
+ } else {
+ //set to push mode
+ pullMode = false;
+ audioSource = new InputPrivate(this);
+ audioSource->open(QIODevice::ReadOnly | QIODevice::Unbuffered);
+ }
+
+ if( !open() )
+ return 0;
+
+ emit stateChanged(deviceState);
+
+ return audioSource;
+}
+
+void QAudioInputPrivate::stop()
+{
+ if(deviceState == QAudio::StopState)
+ return;
+
+ deviceState = QAudio::StopState;
+
+ close();
+ emit stateChanged(deviceState);
+}
+
+bool QAudioInputPrivate::open()
+{
+#ifdef DEBUG_AUDIO
+ QTime now(QTime::currentTime());
+ qDebug()<<now.second()<<"s "<<now.msec()<<"ms :open()";
+#endif
+ timeStamp.restart();
+
+ int dir;
+ int err=-1;
+ int count=0;
+ unsigned int freakuency=settings.frequency();
+
+ QString dev = QString(tr(m_device.constData()));
+ if(!dev.contains(tr("default"))) {
+ dev = QString(tr("default:CARD=%1")).arg(tr(m_device.constData()));
+ }
+
+ // Step 1: try and open the device
+ while((count < 5) && (err < 0)) {
+ err=snd_pcm_open(&handle,dev.toLocal8Bit().constData(),SND_PCM_STREAM_CAPTURE,0);
+ if(err < 0)
+ count++;
+ }
+ if (( err < 0)||(handle == 0)) {
+ errorState = QAudio::OpenError;
+ deviceState = QAudio::StopState;
+ emit stateChanged(deviceState);
+ return false;
+ }
+ snd_pcm_nonblock( handle, 0 );
+
+ // Step 2: Set the desired HW parameters.
+ snd_pcm_hw_params_alloca( &hwparams );
+
+ bool fatal = false;
+ QString errMessage;
+ unsigned int chunks = 8;
+
+ err = snd_pcm_hw_params_any( handle, hwparams );
+ if ( err < 0 ) {
+ fatal = true;
+ errMessage = QString(tr("QAudioInput: snd_pcm_hw_params_any: err = %1")).arg(err);
+ }
+ if ( !fatal ) {
+ err = snd_pcm_hw_params_set_rate_resample( handle, hwparams, 1 );
+ if ( err < 0 ) {
+ fatal = true;
+ errMessage = QString(tr("QAudioInput: snd_pcm_hw_params_set_rate_resample: err = %1")).arg(err);
+ }
+ }
+ if ( !fatal ) {
+ err = snd_pcm_hw_params_set_access( handle, hwparams, access );
+ if ( err < 0 ) {
+ fatal = true;
+ errMessage = QString(tr("QAudioInput: snd_pcm_hw_params_set_access: err = %1")).arg(err);
+ }
+ }
+ if ( !fatal ) {
+ err = setFormat();
+ if ( err < 0 ) {
+ fatal = true;
+ errMessage = QString(tr("QAudioInput: snd_pcm_hw_params_set_format: err = %1")).arg(err);
+ }
+ }
+ if ( !fatal ) {
+ err = snd_pcm_hw_params_set_channels( handle, hwparams, (unsigned int)settings.channels() );
+ if ( err < 0 ) {
+ fatal = true;
+ errMessage = QString(tr("QAudioInput: snd_pcm_hw_params_set_channels: err = %1")).arg(err);
+ }
+ }
+ if ( !fatal ) {
+ err = snd_pcm_hw_params_set_rate_near( handle, hwparams, &freakuency, 0 );
+ if ( err < 0 ) {
+ fatal = true;
+ errMessage = QString(tr("QAudioInput: snd_pcm_hw_params_set_rate_near: err = %1")).arg(err);
+ }
+ }
+ if ( !fatal ) {
+ err = snd_pcm_hw_params_set_buffer_time_near(handle, hwparams, &buffer_time, &dir);
+ if ( err < 0 ) {
+ fatal = true;
+ errMessage = QString(tr("QAudioInput: snd_pcm_hw_params_set_buffer_time_near: err = %1")).arg(err);
+ }
+ }
+ if ( !fatal ) {
+ err = snd_pcm_hw_params_set_period_time_near(handle, hwparams, &period_time, &dir);
+ if ( err < 0 ) {
+ fatal = true;
+ errMessage = QString(tr("QAudioInput: snd_pcm_hw_params_set_period_time_near: err = %1")).arg(err);
+ }
+ }
+ if ( !fatal ) {
+ err = snd_pcm_hw_params_set_periods_near(handle, hwparams, &chunks, &dir);
+ if ( err < 0 ) {
+ fatal = true;
+ errMessage = QString(tr("QAudioInput: snd_pcm_hw_params_set_periods_near: err = %1")).arg(err);
+ }
+ }
+ if ( !fatal ) {
+ err = snd_pcm_hw_params(handle, hwparams);
+ if ( err < 0 ) {
+ fatal = true;
+ errMessage = QString(tr("QAudioInput: snd_pcm_hw_params: err = %1")).arg(err);
+ }
+ }
+ if( err < 0) {
+ qWarning()<<errMessage;
+ errorState = QAudio::OpenError;
+ deviceState = QAudio::StopState;
+ emit stateChanged(deviceState);
+ return false;
+ }
+ snd_pcm_hw_params_get_buffer_size(hwparams,&buffer_frames);
+ buffer_size = snd_pcm_frames_to_bytes(handle,buffer_frames);
+ snd_pcm_hw_params_get_period_size(hwparams,&period_frames, &dir);
+ period_size = snd_pcm_frames_to_bytes(handle,period_frames);
+ snd_pcm_hw_params_get_buffer_time(hwparams,&buffer_time, &dir);
+ snd_pcm_hw_params_get_period_time(hwparams,&period_time, &dir);
+
+ // Step 3: Set the desired SW parameters.
+ snd_pcm_sw_params_t *swparams;
+ snd_pcm_sw_params_alloca(&swparams);
+ snd_pcm_sw_params_current(handle, swparams);
+ snd_pcm_sw_params_set_start_threshold(handle,swparams,period_frames);
+ snd_pcm_sw_params_set_stop_threshold(handle,swparams,buffer_frames);
+ snd_pcm_sw_params_set_avail_min(handle, swparams,period_frames);
+ snd_pcm_sw_params(handle, swparams);
+
+ // Step 4: Prepare audio
+ if(audioBuffer == 0)
+ audioBuffer = new char[buffer_size];
+ snd_pcm_prepare( handle );
+ snd_pcm_start(handle);
+
+ // Step 5: Setup timer
+ bytesAvailable = bytesReady();
+
+ if(pullMode)
+ connect(audioSource,SIGNAL(readyRead()),this,SLOT(userFeed()));
+
+ // Step 6: Start audio processing
+ chunks = buffer_size/period_size;
+ timer->start(period_time*chunks/2000);
+
+ errorState = QAudio::NoError;
+ deviceState = QAudio::ActiveState;
+
+ totalTimeValue = 0;
+
+ return true;
+}
+
+void QAudioInputPrivate::close()
+{
+ deviceState = QAudio::StopState;
+ timer->stop();
+
+ if ( handle ) {
+ snd_pcm_drop( handle );
+ snd_pcm_close( handle );
+ handle = 0;
+ delete [] audioBuffer;
+ audioBuffer=0;
+ }
+}
+
+int QAudioInputPrivate::bytesReady() const
+{
+ if(resuming)
+ return period_size;
+
+ if(deviceState != QAudio::ActiveState)
+ return 0;
+ int frames = snd_pcm_avail_update(handle);
+ if((int)frames > (int)buffer_frames)
+ frames = buffer_frames;
+
+ return snd_pcm_frames_to_bytes(handle, frames);
+}
+
+qint64 QAudioInputPrivate::read(char* data, qint64 len)
+{
+ Q_UNUSED(data)
+ Q_UNUSED(len)
+ // Read in some audio data and write it to QIODevice, pull mode
+ if ( !handle )
+ return 0;
+
+ bytesAvailable = bytesReady();
+
+ int count=0, err = 0;
+ while(count < 5) {
+ int chunks = bytesAvailable/period_size;
+ int frames = chunks*period_frames;
+ if(frames > (int)buffer_frames)
+ frames = buffer_frames;
+ int readFrames = snd_pcm_readi(handle, audioBuffer, frames);
+ if (readFrames >= 0) {
+ err = snd_pcm_frames_to_bytes(handle, readFrames);
+#ifdef DEBUG_AUDIO
+ qDebug()<<QString(tr("PULL: read in bytes = %1 (frames=%2)")).arg(err).arg(readFrames).toLatin1().constData();
+#endif
+ break;
+ } else if((readFrames == -EAGAIN) || (readFrames == -EINTR)) {
+ errorState = QAudio::IOError;
+ err = 0;
+ break;
+ } else {
+ if(readFrames == -EPIPE) {
+ errorState = QAudio::UnderrunError;
+ err = snd_pcm_prepare(handle);
+ } else if(readFrames == -ESTRPIPE) {
+ err = snd_pcm_prepare(handle);
+ }
+ if(err != 0) break;
+ }
+ count++;
+ }
+ if(err > 0) {
+ // got some send it onward
+#ifdef DEBUG_AUDIO
+ qDebug()<<"PULL: frames to write to QIODevice = "<<
+ snd_pcm_bytes_to_frames( handle, (int)err )<<" ("<<err<<") bytes";
+#endif
+ if(deviceState != QAudio::ActiveState)
+ return 0;
+
+ qint64 l = audioSource->write(audioBuffer,err);
+ if(l < 0) {
+ close();
+ errorState = QAudio::IOError;
+ deviceState = QAudio::StopState;
+ emit stateChanged(deviceState);
+ } else if(l == 0) {
+ errorState = QAudio::NoError;
+ deviceState = QAudio::IdleState;
+ } else {
+ totalTimeValue += snd_pcm_bytes_to_frames(handle, err)*1000000/settings.frequency();
+ resuming = false;
+ errorState = QAudio::NoError;
+ deviceState = QAudio::ActiveState;
+ }
+ return l;
+ }
+ return 0;
+}
+
+void QAudioInputPrivate::resume()
+{
+ if(deviceState == QAudio::SuspendState) {
+ int err = 0;
+
+ if(handle) {
+ err = snd_pcm_prepare( handle );
+ if(err < 0)
+ xrun_recovery(err);
+
+ err = snd_pcm_start(handle);
+ if(err < 0)
+ xrun_recovery(err);
+
+ bytesAvailable = buffer_size;
+ }
+ resuming = true;
+ deviceState = QAudio::ActiveState;
+ int chunks = buffer_size/period_size;
+ timer->start(buffer_time*chunks/2000);
+ emit stateChanged(deviceState);
+ }
+}
+
+void QAudioInputPrivate::setBufferSize(int value)
+{
+ buffer_size = value;
+}
+
+int QAudioInputPrivate::bufferSize() const
+{
+ return buffer_size;
+}
+
+int QAudioInputPrivate::periodSize() const
+{
+ return period_size;
+}
+
+void QAudioInputPrivate::setNotifyInterval(int ms)
+{
+ intervalTime = ms;
+}
+
+int QAudioInputPrivate::notifyInterval() const
+{
+ return intervalTime;
+}
+
+qint64 QAudioInputPrivate::totalTime() const
+{
+ return totalTimeValue;
+}
+
+void QAudioInputPrivate::suspend()
+{
+ if(deviceState == QAudio::ActiveState||resuming) {
+ timer->stop();
+ deviceState = QAudio::SuspendState;
+ emit stateChanged(deviceState);
+ }
+}
+
+void QAudioInputPrivate::userFeed()
+{
+ if(deviceState == QAudio::StopState || deviceState == QAudio::SuspendState)
+ return;
+#ifdef DEBUG_AUDIO
+ QTime now(QTime::currentTime());
+ qDebug()<<now.second()<<"s "<<now.msec()<<"ms :userFeed() IN";
+#endif
+ deviceReady();
+}
+
+bool QAudioInputPrivate::deviceReady()
+{
+ if(pullMode) {
+ // reads some audio data and writes it to QIODevice
+ read(0,0);
+ } else {
+ // emits readyRead() so user will call read() on QIODevice to get some audio data
+ InputPrivate* a = qobject_cast<InputPrivate*>(audioSource);
+ a->trigger();
+ }
+ bytesAvailable = bytesReady();
+
+ if(deviceState != QAudio::ActiveState)
+ return true;
+
+ if(timeStamp.elapsed() > intervalTime && intervalTime > 50) {
+ emit notify();
+ timeStamp.restart();
+ }
+ return true;
+}
+
+qint64 QAudioInputPrivate::clock() const
+{
+ if(!handle)
+ return 0;
+
+ if(deviceState != QAudio::ActiveState)
+ return 0;
+
+ snd_pcm_status_t* status;
+ snd_pcm_status_alloca(&status);
+
+ snd_timestamp_t t1,t2;
+ if( snd_pcm_status(handle, status) >= 0) {
+ snd_pcm_status_get_tstamp(status,&t1);
+ snd_pcm_status_get_trigger_tstamp(status,&t2);
+ t1.tv_sec-=t2.tv_sec;
+
+ signed long l = (signed long)t1.tv_usec - (signed long)t2.tv_usec;
+ if(l < 0) {
+ t1.tv_sec--;
+ l = -l;
+ l %= 1000000;
+ }
+ return ((t1.tv_sec * 1000)+l/1000);
+ } else
+ return 0;
+}
+
+void QAudioInputPrivate::reset()
+{
+ if(handle)
+ snd_pcm_reset(handle);
+}
+
+void QAudioInputPrivate::drain()
+{
+ if(handle)
+ snd_pcm_drain(handle);
+}
+
+InputPrivate::InputPrivate(QAudioInputPrivate* audio)
+{
+ audioDevice = qobject_cast<QAudioInputPrivate*>(audio);
+}
+
+InputPrivate::~InputPrivate()
+{
+}
+
+qint64 InputPrivate::readData( char* data, qint64 len)
+{
+ // push mode, user read() called
+ if((audioDevice->state() != QAudio::ActiveState) && !audioDevice->resuming)
+ return 0;
+
+ int readFrames;
+ int count=0, err = 0;
+
+ while(count < 5) {
+ int frames = snd_pcm_bytes_to_frames(audioDevice->handle, len);
+ readFrames = snd_pcm_readi(audioDevice->handle, data, frames);
+ if (readFrames >= 0) {
+ err = snd_pcm_frames_to_bytes(audioDevice->handle, readFrames);
+#ifdef DEBUG_AUDIO
+ qDebug()<<QString(tr("PUSH: read in bytes = %1 (frames=%2)")).arg(err).arg(readFrames).toLatin1().constData();
+#endif
+ break;
+ } else if((readFrames == -EAGAIN) || (readFrames == -EINTR)) {
+ audioDevice->errorState = QAudio::IOError;
+ err = 0;
+ break;
+ } else {
+ if(readFrames == -EPIPE) {
+ audioDevice->errorState = QAudio::UnderrunError;
+ err = snd_pcm_prepare(audioDevice->handle);
+ } else if(readFrames == -ESTRPIPE) {
+ err = snd_pcm_prepare(audioDevice->handle);
+ }
+ if(err != 0) break;
+ }
+ count++;
+ }
+ if(err > 0 && readFrames > 0) {
+ audioDevice->totalTimeValue += readFrames*1000/audioDevice->settings.frequency()*1000;
+ audioDevice->deviceState = QAudio::ActiveState;
+ return err;
+ }
+ return 0;
+}
+
+qint64 InputPrivate::writeData(const char* data, qint64 len)
+{
+ Q_UNUSED(data)
+ Q_UNUSED(len)
+ return 0;
+}
+
+void InputPrivate::trigger()
+{
+ emit readyRead();
+}
+
diff --git a/src/multimedia/audio/qaudioinput_alsa_p.h b/src/multimedia/audio/qaudioinput_alsa_p.h
new file mode 100644
index 0000000..21c8064
--- /dev/null
+++ b/src/multimedia/audio/qaudioinput_alsa_p.h
@@ -0,0 +1,151 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtMultimedia module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the either Technology Preview License Agreement or the
+** Beta Release License Agreement.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain
+** additional rights. These rights are described in the Nokia Qt LGPL
+** Exception version 1.0, 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.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at http://www.qtsoftware.com/contact.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists for the convenience
+// of other Qt classes. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
+
+#ifndef QAUDIOINPUTALSA_H
+#define QAUDIOINPUTALSA_H
+
+#include <alsa/asoundlib.h>
+
+#include <QtCore/qfile.h>
+#include <QtCore/qdebug.h>
+#include <QtCore/qtimer.h>
+#include <QtCore/qstring.h>
+#include <QtCore/qstringlist.h>
+#include <QtCore/qdatetime.h>
+
+#include <QtMultimedia/qaudio.h>
+#include <QtMultimedia/qaudiodeviceinfo.h>
+#include <QtMultimedia/qaudioengine.h>
+
+class InputPrivate;
+
+class QAudioInputPrivate : public QAbstractAudioInput
+{
+ Q_OBJECT
+public:
+ QAudioInputPrivate(const QByteArray &device, const QAudioFormat& audioFormat);
+ ~QAudioInputPrivate();
+
+ qint64 read(char* data, qint64 len);
+
+ QIODevice* start(QIODevice* device = 0);
+ void stop();
+ void reset();
+ void suspend();
+ void resume();
+ int bytesReady() const;
+ int periodSize() const;
+ void setBufferSize(int value);
+ int bufferSize() const;
+ void setNotifyInterval(int milliSeconds);
+ int notifyInterval() const;
+ qint64 totalTime() const;
+ qint64 clock() const;
+ QAudio::Error error() const;
+ QAudio::State state() const;
+ QAudioFormat format() const;
+ bool resuming;
+ snd_pcm_t* handle;
+ qint64 totalTimeValue;
+ QIODevice* audioSource;
+ QAudioFormat settings;
+ QAudio::Error errorState;
+ QAudio::State deviceState;
+
+private slots:
+ void userFeed();
+ bool deviceReady();
+
+private:
+ int xrun_recovery(int err);
+ int setFormat();
+ bool open();
+ void close();
+ void drain();
+
+ QTimer* timer;
+ QTime timeStamp;
+ int intervalTime;
+ char* audioBuffer;
+ int bytesAvailable;
+ QByteArray m_device;
+ bool pullMode;
+ int buffer_size;
+ int period_size;
+ unsigned int buffer_time;
+ unsigned int period_time;
+ snd_pcm_uframes_t buffer_frames;
+ snd_pcm_uframes_t period_frames;
+ snd_async_handler_t* ahandler;
+ snd_pcm_access_t access;
+ snd_pcm_format_t pcmformat;
+ snd_timestamp_t* timestamp;
+ snd_pcm_hw_params_t *hwparams;
+};
+
+class InputPrivate : public QIODevice
+{
+ Q_OBJECT
+public:
+ InputPrivate(QAudioInputPrivate* audio);
+ ~InputPrivate();
+
+ qint64 readData( char* data, qint64 len);
+ qint64 writeData(const char* data, qint64 len);
+
+ void trigger();
+private:
+ QAudioInputPrivate *audioDevice;
+};
+
+#endif
diff --git a/src/multimedia/audio/qaudioinput_mac_p.cpp b/src/multimedia/audio/qaudioinput_mac_p.cpp
new file mode 100644
index 0000000..5400c85
--- /dev/null
+++ b/src/multimedia/audio/qaudioinput_mac_p.cpp
@@ -0,0 +1,930 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtMultimedia module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the either Technology Preview License Agreement or the
+** Beta Release License Agreement.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain
+** additional rights. These rights are described in the Nokia Qt LGPL
+** Exception version 1.0, 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.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at http://www.qtsoftware.com/contact.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists for the convenience
+// of other Qt classes. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
+#include <QtCore/qendian.h>
+#include <QtCore/qtimer.h>
+#include <QtCore/qdebug.h>
+
+#include <QtMultimedia/qaudiodeviceinfo.h>
+#include <QtMultimedia/qaudioinput.h>
+
+#include "qaudio_mac_p.h"
+#include "qaudioinput_mac_p.h"
+
+
+QT_BEGIN_NAMESPACE
+
+
+namespace
+{
+
+static const int default_buffer_size = 4 * 1024;
+
+class QAudioBufferList
+{
+public:
+ QAudioBufferList(AudioStreamBasicDescription const& streamFormat):
+ owner(false),
+ sf(streamFormat)
+ {
+ const bool isInterleaved = (sf.mFormatFlags & kAudioFormatFlagIsNonInterleaved) == 0;
+ const int numberOfBuffers = isInterleaved ? 1 : sf.mChannelsPerFrame;
+
+ dataSize = 0;
+
+ bfs = reinterpret_cast<AudioBufferList*>(qMalloc(sizeof(AudioBufferList) +
+ (sizeof(AudioBuffer) * numberOfBuffers)));
+
+ bfs->mNumberBuffers = numberOfBuffers;
+ for (int i = 0; i < numberOfBuffers; ++i) {
+ bfs->mBuffers[i].mNumberChannels = isInterleaved ? numberOfBuffers : 1;
+ bfs->mBuffers[i].mDataByteSize = 0;
+ bfs->mBuffers[i].mData = 0;
+ }
+ }
+
+ QAudioBufferList(AudioStreamBasicDescription const& streamFormat, char* buffer, int bufferSize):
+ owner(false),
+ sf(streamFormat),
+ bfs(0)
+ {
+ dataSize = bufferSize;
+
+ bfs = reinterpret_cast<AudioBufferList*>(qMalloc(sizeof(AudioBufferList) + sizeof(AudioBuffer)));
+
+ bfs->mNumberBuffers = 1;
+ bfs->mBuffers[0].mNumberChannels = 1;
+ bfs->mBuffers[0].mDataByteSize = dataSize;
+ bfs->mBuffers[0].mData = buffer;
+ }
+
+ QAudioBufferList(AudioStreamBasicDescription const& streamFormat, int framesToBuffer):
+ owner(true),
+ sf(streamFormat),
+ bfs(0)
+ {
+ const bool isInterleaved = (sf.mFormatFlags & kAudioFormatFlagIsNonInterleaved) == 0;
+ const int numberOfBuffers = isInterleaved ? 1 : sf.mChannelsPerFrame;
+
+ dataSize = framesToBuffer * sf.mBytesPerFrame;
+
+ bfs = reinterpret_cast<AudioBufferList*>(qMalloc(sizeof(AudioBufferList) +
+ (sizeof(AudioBuffer) * numberOfBuffers)));
+ bfs->mNumberBuffers = numberOfBuffers;
+ for (int i = 0; i < numberOfBuffers; ++i) {
+ bfs->mBuffers[i].mNumberChannels = isInterleaved ? numberOfBuffers : 1;
+ bfs->mBuffers[i].mDataByteSize = dataSize;
+ bfs->mBuffers[i].mData = qMalloc(dataSize);
+ }
+ }
+
+ ~QAudioBufferList()
+ {
+ if (owner) {
+ for (UInt32 i = 0; i < bfs->mNumberBuffers; ++i)
+ qFree(bfs->mBuffers[i].mData);
+ }
+
+ qFree(bfs);
+ }
+
+ AudioBufferList* audioBufferList() const
+ {
+ return bfs;
+ }
+
+ char* data(int buffer = 0) const
+ {
+ return static_cast<char*>(bfs->mBuffers[buffer].mData);
+ }
+
+ qint64 bufferSize(int buffer = 0) const
+ {
+ return bfs->mBuffers[buffer].mDataByteSize;
+ }
+
+ int frameCount(int buffer = 0) const
+ {
+ return bfs->mBuffers[buffer].mDataByteSize / sf.mBytesPerFrame;
+ }
+
+ int packetCount(int buffer = 0) const
+ {
+ return bfs->mBuffers[buffer].mDataByteSize / sf.mBytesPerPacket;
+ }
+
+ int packetSize() const
+ {
+ return sf.mBytesPerPacket;
+ }
+
+ void reset()
+ {
+ for (UInt32 i = 0; i < bfs->mNumberBuffers; ++i)
+ bfs->mBuffers[i].mDataByteSize = dataSize;
+ }
+
+private:
+ bool owner;
+ int dataSize;
+ AudioStreamBasicDescription sf;
+ AudioBufferList* bfs;
+};
+
+class QAudioPacketFeeder
+{
+public:
+ QAudioPacketFeeder(QAudioBufferList* abl):
+ audioBufferList(abl)
+ {
+ totalPackets = audioBufferList->packetCount();
+ position = 0;
+ }
+
+ bool feed(AudioBufferList& dst, UInt32& packetCount)
+ {
+ if (position == totalPackets) {
+ dst.mBuffers[0].mDataByteSize = 0;
+ packetCount = 0;
+ return false;
+ }
+
+ if (totalPackets - position < packetCount)
+ packetCount = totalPackets - position;
+
+ dst.mBuffers[0].mDataByteSize = packetCount * audioBufferList->packetSize();
+ dst.mBuffers[0].mData = audioBufferList->data() + (position * audioBufferList->packetSize());
+
+ position += packetCount;
+
+ return true;
+ }
+
+private:
+ UInt32 totalPackets;
+ UInt32 position;
+ QAudioBufferList* audioBufferList;
+};
+
+class QAudioInputBuffer : public QObject
+{
+ Q_OBJECT
+
+public:
+ QAudioInputBuffer(int bufferSize,
+ int maxPeriodSize,
+ AudioStreamBasicDescription const& inputFormat,
+ AudioStreamBasicDescription const& outputFormat,
+ QObject* parent):
+ QObject(parent),
+ m_deviceError(false),
+ m_inputFormat(inputFormat),
+ m_outputFormat(outputFormat)
+ {
+ m_maxPeriodSize = maxPeriodSize;
+ m_periodTime = m_maxPeriodSize / m_outputFormat.mBytesPerFrame * 1000 / m_outputFormat.mSampleRate;
+ m_buffer = new QAudioRingBuffer(bufferSize + (bufferSize % maxPeriodSize == 0 ? 0 : maxPeriodSize - (bufferSize % maxPeriodSize)));
+ m_inputBufferList = new QAudioBufferList(m_inputFormat);
+
+ m_flushTimer = new QTimer(this);
+ connect(m_flushTimer, SIGNAL(timeout()), SLOT(flushBuffer()));
+
+ if (inputFormat.mSampleRate != outputFormat.mSampleRate) {
+ if (AudioConverterNew(&m_inputFormat, &m_outputFormat, &m_audioConverter) != noErr) {
+ qWarning() << "QAudioInput: Unable to create an Audio Converter";
+ m_audioConverter = 0;
+ }
+ }
+ }
+
+ ~QAudioInputBuffer()
+ {
+ delete m_buffer;
+ }
+
+ qint64 renderFromDevice(AudioUnit audioUnit,
+ AudioUnitRenderActionFlags* ioActionFlags,
+ const AudioTimeStamp* inTimeStamp,
+ UInt32 inBusNumber,
+ UInt32 inNumberFrames)
+ {
+ const bool wasEmpty = m_buffer->used() == 0;
+
+ OSStatus err;
+ qint64 framesRendered = 0;
+
+ m_inputBufferList->reset();
+ err = AudioUnitRender(audioUnit,
+ ioActionFlags,
+ inTimeStamp,
+ inBusNumber,
+ inNumberFrames,
+ m_inputBufferList->audioBufferList());
+
+ if (m_audioConverter != 0) {
+ QAudioPacketFeeder feeder(m_inputBufferList);
+
+ bool wecan = true;
+ int copied = 0;
+
+ const int available = m_buffer->free();
+
+ while (err == noErr && wecan) {
+ QAudioRingBuffer::Region region = m_buffer->acquireWriteRegion(available);
+
+ if (region.second > 0) {
+ AudioBufferList output;
+ output.mNumberBuffers = 1;
+ output.mBuffers[0].mNumberChannels = 1;
+ output.mBuffers[0].mDataByteSize = region.second;
+ output.mBuffers[0].mData = region.first;
+
+ UInt32 packetSize = region.second / m_outputFormat.mBytesPerPacket;
+ err = AudioConverterFillComplexBuffer(m_audioConverter,
+ converterCallback,
+ &feeder,
+ &packetSize,
+ &output,
+ 0);
+
+ region.second = output.mBuffers[0].mDataByteSize;
+ copied += region.second;
+
+ m_buffer->releaseWriteRegion(region);
+ }
+ else
+ wecan = false;
+ }
+
+ framesRendered += copied / m_outputFormat.mBytesPerFrame;
+ }
+ else {
+ const int available = m_inputBufferList->bufferSize();
+ bool wecan = true;
+ int copied = 0;
+
+ while (wecan && copied < available) {
+ QAudioRingBuffer::Region region = m_buffer->acquireWriteRegion(available - copied);
+
+ if (region.second > 0) {
+ memcpy(region.first, m_inputBufferList->data() + copied, region.second);
+ copied += region.second;
+ }
+ else
+ wecan = false;
+
+ m_buffer->releaseWriteRegion(region);
+ }
+
+ framesRendered = copied / m_outputFormat.mBytesPerFrame;
+ }
+
+ if (wasEmpty && framesRendered > 0)
+ emit readyRead();
+
+ return framesRendered;
+ }
+
+ qint64 readBytes(char* data, qint64 len)
+ {
+ bool wecan = true;
+ qint64 bytesCopied = 0;
+
+ len -= len % m_maxPeriodSize;
+ while (wecan && bytesCopied < len) {
+ QAudioRingBuffer::Region region = m_buffer->acquireReadRegion(len - bytesCopied);
+
+ if (region.second > 0) {
+ memcpy(data + bytesCopied, region.first, region.second);
+ bytesCopied += region.second;
+ }
+ else
+ wecan = false;
+
+ m_buffer->releaseReadRegion(region);
+ }
+
+ return bytesCopied;
+ }
+
+ void setFlushDevice(QIODevice* device)
+ {
+ if (m_device != device)
+ m_device = device;
+ }
+
+ void startFlushTimer()
+ {
+ if (m_device != 0) {
+ m_flushTimer->start((m_buffer->size() - (m_maxPeriodSize * 2)) / m_maxPeriodSize * m_periodTime);
+ }
+ }
+
+ void stopFlushTimer()
+ {
+ m_flushTimer->stop();
+ }
+
+ void flush(bool all = false)
+ {
+ const int used = m_buffer->used();
+ const int readSize = all ? used : used - (used % m_maxPeriodSize);
+
+ if (readSize > 0) {
+ bool wecan = true;
+ int flushed = 0;
+
+ while (!m_deviceError && wecan && flushed < readSize) {
+ QAudioRingBuffer::Region region = m_buffer->acquireReadRegion(readSize - flushed);
+
+ if (region.second > 0) {
+ int bytesWritten = m_device->write(region.first, region.second);
+ if (bytesWritten < 0) {
+ stopFlushTimer();
+ m_deviceError = true;
+ }
+ else {
+ region.second = bytesWritten;
+ flushed += bytesWritten;
+ wecan = bytesWritten != 0;
+ }
+ }
+ else
+ wecan = false;
+
+ m_buffer->releaseReadRegion(region);
+ }
+ }
+ }
+
+ void reset()
+ {
+ m_buffer->reset();
+ m_deviceError = false;
+ }
+
+ int available() const
+ {
+ return m_buffer->free();
+ }
+
+ int used() const
+ {
+ return m_buffer->used();
+ }
+
+signals:
+ void readyRead();
+
+private slots:
+ void flushBuffer()
+ {
+ flush();
+ }
+
+private:
+ bool m_deviceError;
+ int m_maxPeriodSize;
+ int m_periodTime;
+ QIODevice* m_device;
+ QTimer* m_flushTimer;
+ QAudioRingBuffer* m_buffer;
+ QAudioBufferList* m_inputBufferList;
+ AudioConverterRef m_audioConverter;
+ AudioStreamBasicDescription m_inputFormat;
+ AudioStreamBasicDescription m_outputFormat;
+
+ const static OSStatus as_empty = 'qtem';
+
+ // Converter callback
+ static OSStatus converterCallback(AudioConverterRef inAudioConverter,
+ UInt32* ioNumberDataPackets,
+ AudioBufferList* ioData,
+ AudioStreamPacketDescription** outDataPacketDescription,
+ void* inUserData)
+ {
+ Q_UNUSED(inAudioConverter);
+ Q_UNUSED(outDataPacketDescription);
+
+ QAudioPacketFeeder* feeder = static_cast<QAudioPacketFeeder*>(inUserData);
+
+ if (!feeder->feed(*ioData, *ioNumberDataPackets))
+ return as_empty;
+
+ return noErr;
+ }
+};
+
+
+class MacInputDevice : public QIODevice
+{
+ Q_OBJECT
+
+public:
+ MacInputDevice(QAudioInputBuffer* audioBuffer, QObject* parent):
+ QIODevice(parent),
+ m_audioBuffer(audioBuffer)
+ {
+ open(QIODevice::ReadOnly | QIODevice::Unbuffered);
+ connect(m_audioBuffer, SIGNAL(readyRead()), SIGNAL(readyRead()));
+ }
+
+ qint64 readData(char* data, qint64 len)
+ {
+ return m_audioBuffer->readBytes(data, len);
+ }
+
+ qint64 writeData(const char* data, qint64 len)
+ {
+ Q_UNUSED(data);
+ Q_UNUSED(len);
+
+ return 0;
+ }
+
+ bool isSequential() const
+ {
+ return true;
+ }
+
+private:
+ QAudioInputBuffer* m_audioBuffer;
+};
+
+}
+
+
+QAudioInputPrivate::QAudioInputPrivate(const QByteArray& device, QAudioFormat const& format):
+ audioFormat(format)
+{
+ QDataStream ds(device);
+ quint32 did, mode;
+
+ ds >> did >> mode;
+
+ if (QAudio::Mode(mode) == QAudio::AudioOutput)
+ errorCode = QAudio::OpenError;
+ else {
+ isOpen = false;
+ audioDeviceId = AudioDeviceID(did);
+ audioUnit = 0;
+ startTime = 0;
+ totalFrames = 0;
+ audioBuffer = 0;
+ internalBufferSize = default_buffer_size;
+ clockFrequency = AudioGetHostClockFrequency() / 1000;
+ errorCode = QAudio::NoError;
+ stateCode = QAudio::StopState;
+
+ intervalTimer = new QTimer(this);
+ intervalTimer->setInterval(1000);
+ connect(intervalTimer, SIGNAL(timeout()), SIGNAL(notify()));
+ }
+}
+
+QAudioInputPrivate::~QAudioInputPrivate()
+{
+ close();
+}
+
+bool QAudioInputPrivate::open()
+{
+ UInt32 size = 0;
+
+ if (isOpen)
+ return true;
+
+ ComponentDescription cd;
+ cd.componentType = kAudioUnitType_Output;
+ cd.componentSubType = kAudioUnitSubType_HALOutput;
+ cd.componentManufacturer = kAudioUnitManufacturer_Apple;
+ cd.componentFlags = 0;
+ cd.componentFlagsMask = 0;
+
+ // Open
+ Component cp = FindNextComponent(NULL, &cd);
+ if (cp == 0) {
+ qWarning() << "QAudioInput: Failed to find HAL Output component";
+ return false;
+ }
+
+ if (OpenAComponent(cp, &audioUnit) != noErr) {
+ qWarning() << "QAudioInput: Unable to Open Output Component";
+ return false;
+ }
+
+ // Set mode
+ // switch to input mode
+ UInt32 enable = 1;
+ if (AudioUnitSetProperty(audioUnit,
+ kAudioOutputUnitProperty_EnableIO,
+ kAudioUnitScope_Input,
+ 1,
+ &enable,
+ sizeof(enable)) != noErr) {
+ qWarning() << "QAudioInput: Unabled to switch to input mode (Enable Input)";
+ return false;
+ }
+
+ enable = 0;
+ if (AudioUnitSetProperty(audioUnit,
+ kAudioOutputUnitProperty_EnableIO,
+ kAudioUnitScope_Output,
+ 0,
+ &enable,
+ sizeof(enable)) != noErr) {
+ qWarning() << "QAudioInput: Unabled to switch to input mode (Disable output)";
+ return false;
+ }
+
+ // register callback
+ AURenderCallbackStruct cb;
+ cb.inputProc = inputCallback;
+ cb.inputProcRefCon = this;
+
+ if (AudioUnitSetProperty(audioUnit,
+ kAudioOutputUnitProperty_SetInputCallback,
+ kAudioUnitScope_Global,
+ 0,
+ &cb,
+ sizeof(cb)) != noErr) {
+ qWarning() << "QAudioInput: Failed to set AudioUnit callback";
+ return false;
+ }
+
+ // Set Audio Device
+ if (AudioUnitSetProperty(audioUnit,
+ kAudioOutputUnitProperty_CurrentDevice,
+ kAudioUnitScope_Global,
+ 0,
+ &audioDeviceId,
+ sizeof(audioDeviceId)) != noErr) {
+ qWarning() << "QAudioInput: Unable to use configured device";
+ return false;
+ }
+
+ // Set format
+ streamFormat = toAudioStreamBasicDescription(audioFormat);
+
+ size = sizeof(deviceFormat);
+ if (AudioUnitGetProperty(audioUnit,
+ kAudioUnitProperty_StreamFormat,
+ kAudioUnitScope_Input,
+ 1,
+ &deviceFormat,
+ &size) != noErr) {
+ qWarning() << "QAudioInput: Unable to retrieve device format";
+ return false;
+ }
+
+ // If the device frequency is different to the requested use a converter
+ if (deviceFormat.mSampleRate != streamFormat.mSampleRate) {
+ AudioUnitSetProperty(audioUnit,
+ kAudioUnitProperty_StreamFormat,
+ kAudioUnitScope_Output,
+ 1,
+ &deviceFormat,
+ sizeof(streamFormat));
+ }
+ else {
+ AudioUnitSetProperty(audioUnit,
+ kAudioUnitProperty_StreamFormat,
+ kAudioUnitScope_Output,
+ 1,
+ &streamFormat,
+ sizeof(streamFormat));
+ }
+
+ // Setup buffers
+ UInt32 numberOfFrames;
+ size = sizeof(UInt32);
+ if (AudioUnitGetProperty(audioUnit,
+ kAudioDevicePropertyBufferFrameSize,
+ kAudioUnitScope_Global,
+ 0,
+ &numberOfFrames,
+ &size) != noErr) {
+ qWarning() << "QAudioInput: Failed to get audio period size";
+ return false;
+ }
+
+ // Allocate buffer
+ periodSizeBytes = (numberOfFrames * streamFormat.mSampleRate / deviceFormat.mSampleRate) *
+ streamFormat.mBytesPerFrame;
+ if (internalBufferSize < periodSizeBytes * 2)
+ internalBufferSize = periodSizeBytes * 2;
+ else
+ internalBufferSize -= internalBufferSize % streamFormat.mBytesPerFrame;
+
+ audioBuffer = new QAudioInputBuffer(internalBufferSize,
+ periodSizeBytes,
+ deviceFormat,
+ streamFormat,
+ this);
+
+ audioIO = new MacInputDevice(audioBuffer, this);
+
+ // Init
+ if (AudioUnitInitialize(audioUnit) != noErr) {
+ qWarning() << "QAudioInput: Failed to initialize AudioUnit";
+ return false;
+ }
+
+ isOpen = true;
+
+ return isOpen;
+}
+
+void QAudioInputPrivate::close()
+{
+ if (audioUnit != 0) {
+ AudioOutputUnitStop(audioUnit);
+ AudioUnitUninitialize(audioUnit);
+ CloseComponent(audioUnit);
+ }
+
+ delete audioBuffer;
+}
+
+QAudioFormat QAudioInputPrivate::format() const
+{
+ return audioFormat;
+}
+
+QIODevice* QAudioInputPrivate::start(QIODevice* device)
+{
+ QIODevice* op = device;
+
+ if (!open()) {
+ stateCode = QAudio::StopState;
+ errorCode = QAudio::OpenError;
+ return audioIO;
+ }
+
+ reset();
+ audioBuffer->reset();
+ audioBuffer->setFlushDevice(op);
+
+ if (op == 0)
+ op = audioIO;
+
+ // Start
+ startTime = AudioGetCurrentHostTime();
+ totalFrames = 0;
+
+ audioThreadStart();
+
+ return op;
+}
+
+void QAudioInputPrivate::stop()
+{
+ QMutexLocker lock(&mutex);
+ if (stateCode != QAudio::StopState) {
+ audioThreadStop();
+ audioBuffer->flush(true);
+
+ errorCode = QAudio::NoError;
+ stateCode = QAudio::StopState;
+ QMetaObject::invokeMethod(this, "stateChanged", Qt::QueuedConnection, Q_ARG(QAudio::State, stateCode));
+ }
+}
+
+void QAudioInputPrivate::reset()
+{
+ QMutexLocker lock(&mutex);
+ if (stateCode != QAudio::StopState) {
+ audioThreadStop();
+
+ errorCode = QAudio::NoError;
+ stateCode = QAudio::StopState;
+ QMetaObject::invokeMethod(this, "stateChanged", Qt::QueuedConnection, Q_ARG(QAudio::State, stateCode));
+ }
+}
+
+void QAudioInputPrivate::suspend()
+{
+ QMutexLocker lock(&mutex);
+ if (stateCode == QAudio::ActiveState || stateCode == QAudio::IdleState) {
+ audioThreadStop();
+
+ errorCode = QAudio::NoError;
+ stateCode = QAudio::SuspendState;
+ QMetaObject::invokeMethod(this, "stateChanged", Qt::QueuedConnection, Q_ARG(QAudio::State, stateCode));
+ }
+}
+
+void QAudioInputPrivate::resume()
+{
+ QMutexLocker lock(&mutex);
+ if (stateCode == QAudio::SuspendState) {
+ audioThreadStart();
+
+ errorCode = QAudio::NoError;
+ stateCode = QAudio::ActiveState;
+ QMetaObject::invokeMethod(this, "stateChanged", Qt::QueuedConnection, Q_ARG(QAudio::State, stateCode));
+ }
+}
+
+int QAudioInputPrivate::bytesReady() const
+{
+ return audioBuffer->used();
+}
+
+int QAudioInputPrivate::periodSize() const
+{
+ return periodSizeBytes;
+}
+
+void QAudioInputPrivate::setBufferSize(int bs)
+{
+ internalBufferSize = bs;
+}
+
+int QAudioInputPrivate::bufferSize() const
+{
+ return internalBufferSize;
+}
+
+void QAudioInputPrivate::setNotifyInterval(int milliSeconds)
+{
+ intervalTimer->setInterval(milliSeconds);
+}
+
+int QAudioInputPrivate::notifyInterval() const
+{
+ return intervalTimer->interval();
+}
+
+qint64 QAudioInputPrivate::totalTime() const
+{
+ return totalFrames * 1000000 / audioFormat.frequency();
+}
+
+qint64 QAudioInputPrivate::clock() const
+{
+ return (AudioGetCurrentHostTime() - startTime) / (clockFrequency / 1000);
+}
+
+QAudio::Error QAudioInputPrivate::error() const
+{
+ return errorCode;
+}
+
+QAudio::State QAudioInputPrivate::state() const
+{
+ return stateCode;
+}
+
+void QAudioInputPrivate::audioThreadStop()
+{
+ stopTimers();
+ if (audioThreadState.testAndSetAcquire(Running, Stopped))
+ threadFinished.wait(&mutex);
+}
+
+void QAudioInputPrivate::audioThreadStart()
+{
+ startTimers();
+ audioThreadState = Running;
+ AudioOutputUnitStart(audioUnit);
+}
+
+void QAudioInputPrivate::audioDeviceStop()
+{
+ AudioOutputUnitStop(audioUnit);
+ audioThreadState = Stopped;
+ threadFinished.wakeOne();
+}
+
+void QAudioInputPrivate::audioDeviceFull()
+{
+ QMutexLocker lock(&mutex);
+ if (stateCode == QAudio::ActiveState) {
+ audioDeviceStop();
+
+ errorCode = QAudio::UnderrunError;
+ stateCode = QAudio::IdleState;
+ QMetaObject::invokeMethod(this, "deviceStopped", Qt::QueuedConnection);
+ }
+}
+
+void QAudioInputPrivate::audioDeviceError()
+{
+ QMutexLocker lock(&mutex);
+ if (stateCode == QAudio::ActiveState) {
+ audioDeviceStop();
+
+ errorCode = QAudio::IOError;
+ stateCode = QAudio::StopState;
+ QMetaObject::invokeMethod(this, "deviceStopped", Qt::QueuedConnection);
+ }
+}
+
+void QAudioInputPrivate::startTimers()
+{
+ audioBuffer->startFlushTimer();
+ intervalTimer->start();
+}
+
+void QAudioInputPrivate::stopTimers()
+{
+ audioBuffer->stopFlushTimer();
+ intervalTimer->stop();
+}
+
+void QAudioInputPrivate::deviceStopped()
+{
+ stopTimers();
+ emit stateChanged(stateCode);
+}
+
+// Input callback
+OSStatus QAudioInputPrivate::inputCallback(void* inRefCon,
+ AudioUnitRenderActionFlags* ioActionFlags,
+ const AudioTimeStamp* inTimeStamp,
+ UInt32 inBusNumber,
+ UInt32 inNumberFrames,
+ AudioBufferList* ioData)
+{
+ Q_UNUSED(ioData);
+
+ QAudioInputPrivate* d = static_cast<QAudioInputPrivate*>(inRefCon);
+
+ const int threadState = d->audioThreadState.fetchAndAddAcquire(0);
+ if (threadState == Stopped)
+ d->audioDeviceStop();
+ else {
+ qint64 framesWritten;
+
+ framesWritten = d->audioBuffer->renderFromDevice(d->audioUnit,
+ ioActionFlags,
+ inTimeStamp,
+ inBusNumber,
+ inNumberFrames);
+
+ if (framesWritten > 0)
+ d->totalFrames += framesWritten;
+ else if (framesWritten == 0)
+ d->audioDeviceFull();
+ else if (framesWritten < 0)
+ d->audioDeviceError();
+ }
+
+ return noErr;
+}
+
+
+QT_END_NAMESPACE
+
+#include "qaudioinput_mac_p.moc"
+
diff --git a/src/multimedia/audio/qaudioinput_mac_p.h b/src/multimedia/audio/qaudioinput_mac_p.h
new file mode 100644
index 0000000..98ef9ce
--- /dev/null
+++ b/src/multimedia/audio/qaudioinput_mac_p.h
@@ -0,0 +1,171 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtMultimedia module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the either Technology Preview License Agreement or the
+** Beta Release License Agreement.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain
+** additional rights. These rights are described in the Nokia Qt LGPL
+** Exception version 1.0, 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.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at http://www.qtsoftware.com/contact.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists for the convenience
+// of other Qt classes. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
+
+#ifndef QAUDIOINPUT_MAC_P_H
+#define QAUDIOINPUT_MAC_P_H
+
+#include <CoreServices/CoreServices.h>
+#include <CoreAudio/CoreAudio.h>
+#include <AudioUnit/AudioUnit.h>
+#include <AudioToolbox/AudioToolbox.h>
+
+#include <QtCore/qobject.h>
+#include <QtCore/qmutex.h>
+#include <QtCore/qwaitcondition.h>
+#include <QtCore/qatomic.h>
+
+#include <QtMultimedia/qaudio.h>
+#include <QtMultimedia/qaudioformat.h>
+#include <QtMultimedia/qaudioengine.h>
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+class QTimer;
+class QIODevice;
+
+namespace
+{
+class QAudioInputBuffer;
+}
+
+class QAudioInputPrivate : public QAbstractAudioInput
+{
+ Q_OBJECT
+
+public:
+ bool isOpen;
+ int periodSizeBytes;
+ int internalBufferSize;
+ qint64 totalFrames;
+ QAudioFormat audioFormat;
+ QIODevice* audioIO;
+ AudioUnit audioUnit;
+ AudioDeviceID audioDeviceId;
+ Float64 clockFrequency;
+ UInt64 startTime;
+ QAudio::Error errorCode;
+ QAudio::State stateCode;
+ QAudioInputBuffer* audioBuffer;
+ QMutex mutex;
+ QWaitCondition threadFinished;
+ QAtomicInt audioThreadState;
+ QTimer* intervalTimer;
+ AudioStreamBasicDescription streamFormat;
+ AudioStreamBasicDescription deviceFormat;
+
+ QAudioInputPrivate(const QByteArray& device, QAudioFormat const& format);
+ ~QAudioInputPrivate();
+
+ bool open();
+ void close();
+
+ QAudioFormat format() const;
+
+ QIODevice* start(QIODevice* device);
+ void stop();
+ void reset();
+ void suspend();
+ void resume();
+ void idle();
+
+ int bytesReady() const;
+ int periodSize() const;
+
+ void setBufferSize(int value);
+ int bufferSize() const;
+
+ void setNotifyInterval(int milliSeconds);
+ int notifyInterval() const;
+
+ qint64 totalTime() const;
+ qint64 clock() const;
+
+ QAudio::Error error() const;
+ QAudio::State state() const;
+
+ void audioThreadStart();
+ void audioThreadStop();
+
+ void audioDeviceStop();
+ void audioDeviceFull();
+ void audioDeviceError();
+
+ void startTimers();
+ void stopTimers();
+
+signals:
+ void stateChanged(QAudio::State);
+ void notify();
+
+private slots:
+ void deviceStopped();
+
+private:
+ enum { Running, Stopped };
+
+ // Input callback
+ static OSStatus inputCallback(void* inRefCon,
+ AudioUnitRenderActionFlags* ioActionFlags,
+ const AudioTimeStamp* inTimeStamp,
+ UInt32 inBusNumber,
+ UInt32 inNumberFrames,
+ AudioBufferList* ioData);
+};
+
+QT_END_NAMESPACE
+
+QT_END_HEADER
+
+#endif // QAUDIOINPUT_MAC_P_H
diff --git a/src/multimedia/audio/qaudioinput_win32_p.cpp b/src/multimedia/audio/qaudioinput_win32_p.cpp
new file mode 100644
index 0000000..e5b6e0d
--- /dev/null
+++ b/src/multimedia/audio/qaudioinput_win32_p.cpp
@@ -0,0 +1,540 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtMultimedia module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the either Technology Preview License Agreement or the
+** Beta Release License Agreement.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain
+** additional rights. These rights are described in the Nokia Qt LGPL
+** Exception version 1.0, 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.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at http://www.qtsoftware.com/contact.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists for the convenience
+// of other Qt classes. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
+
+#include "qaudioinput_win32_p.h"
+
+//#define DEBUG_AUDIO 1
+
+
+QAudioInputPrivate::QAudioInputPrivate(const QByteArray &device, const QAudioFormat& audioFormat):
+ settings(audioFormat)
+{
+ bytesAvailable = 0;
+ buffer_size = 0;
+ period_size = 0;
+ m_device = device;
+ totalTimeValue = 0;
+ intervalTime = 1000;
+ errorState = QAudio::NoError;
+ deviceState = QAudio::StopState;
+ audioSource = 0;
+ pullMode = true;
+ resuming = false;
+
+ connect(this,SIGNAL(processMore()),SLOT(deviceReady()));
+
+ InitializeCriticalSection(&waveInCriticalSection);
+}
+
+QAudioInputPrivate::~QAudioInputPrivate()
+{
+ close();
+ DeleteCriticalSection(&waveInCriticalSection);
+}
+
+void CALLBACK QAudioInputPrivate::waveInProc( HWAVEIN hWaveIn, UINT uMsg,
+ DWORD dwInstance, DWORD dwParam1, DWORD dwParam2 )
+{
+ Q_UNUSED(dwParam1)
+ Q_UNUSED(dwParam2)
+ Q_UNUSED(hWaveIn)
+
+ QAudioInputPrivate* qAudio;
+ qAudio = (QAudioInputPrivate*)(dwInstance);
+ if(!qAudio)
+ return;
+
+ switch(uMsg) {
+ case WIM_OPEN:
+ break;
+ case WIM_DATA:
+ EnterCriticalSection(&waveInCriticalSection);
+ if(qAudio->waveFreeBlockCount > 0)
+ qAudio->waveFreeBlockCount--;
+ LeaveCriticalSection(&waveInCriticalSection);
+ qAudio->feedback();
+ break;
+ case WIM_CLOSE:
+ break;
+ default:
+ return;
+ }
+}
+
+WAVEHDR* QAudioInputPrivate::allocateBlocks(int size, int count)
+{
+ int i;
+ unsigned char* buffer;
+ WAVEHDR* blocks;
+ DWORD totalBufferSize = (size + sizeof(WAVEHDR))*count;
+
+ if((buffer=(unsigned char*)HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,
+ totalBufferSize)) == 0) {
+ qWarning("QAudioInput: Memory allocation error");
+ return 0;
+ }
+ blocks = (WAVEHDR*)buffer;
+ buffer += sizeof(WAVEHDR)*count;
+ for(i = 0; i < count; i++) {
+ blocks[i].dwBufferLength = size;
+ blocks[i].lpData = (LPSTR)buffer;
+ blocks[i].dwBytesRecorded=0;
+ blocks[i].dwUser = 0L;
+ blocks[i].dwFlags = 0L;
+ blocks[i].dwLoops = 0L;
+ result = waveInPrepareHeader(hWaveIn,&blocks[i], sizeof(WAVEHDR));
+ if(result != MMSYSERR_NOERROR) {
+ qWarning("QAudioInput: Can't prepare block %d",i);
+ return 0;
+ }
+ buffer += size;
+ }
+ return blocks;
+}
+
+void QAudioInputPrivate::freeBlocks(WAVEHDR* blockArray)
+{
+ HeapFree(GetProcessHeap(), 0, blockArray);
+}
+
+QAudio::Error QAudioInputPrivate::error() const
+{
+ return errorState;
+}
+
+QAudio::State QAudioInputPrivate::state() const
+{
+ return deviceState;
+}
+
+QAudioFormat QAudioInputPrivate::format() const
+{
+ return settings;
+}
+
+QIODevice* QAudioInputPrivate::start(QIODevice* device)
+{
+ if(deviceState != QAudio::StopState)
+ close();
+
+ if(!pullMode && audioSource) {
+ delete audioSource;
+ }
+
+ if(device) {
+ //set to pull mode
+ pullMode = true;
+ audioSource = device;
+ } else {
+ //set to push mode
+ pullMode = false;
+ audioSource = new InputPrivate(this);
+ audioSource->open(QIODevice::ReadOnly | QIODevice::Unbuffered);
+ }
+
+ if( !open() )
+ return 0;
+
+ emit stateChanged(deviceState);
+
+ return audioSource;
+}
+
+void QAudioInputPrivate::stop()
+{
+ if(deviceState == QAudio::StopState)
+ return;
+
+ deviceState = QAudio::StopState;
+
+ close();
+ emit stateChanged(deviceState);
+}
+
+bool QAudioInputPrivate::open()
+{
+#ifdef DEBUG_AUDIO
+ QTime now(QTime::currentTime());
+ qDebug()<<now.second()<<"s "<<now.msec()<<"ms :open()";
+#endif
+ header = 0;
+ if(buffer_size == 0) {
+ // Default buffer size, 100ms, default period size is 20ms
+ buffer_size = settings.frequency()*settings.channels()*(settings.sampleSize()/8)*0.1;
+ period_size = buffer_size/5;
+ } else {
+ period_size = buffer_size/5;
+ }
+ timeStamp.restart();
+ wfx.nSamplesPerSec = settings.frequency();
+ wfx.wBitsPerSample = settings.sampleSize();
+ wfx.nChannels = settings.channels();
+ wfx.cbSize = 0;
+
+ wfx.wFormatTag = WAVE_FORMAT_PCM;
+ wfx.nBlockAlign = (wfx.wBitsPerSample >> 3) * wfx.nChannels;
+ wfx.nAvgBytesPerSec = wfx.nBlockAlign * wfx.nSamplesPerSec;
+
+ UINT_PTR devId = WAVE_MAPPER;
+
+ WAVEINCAPS wic;
+ unsigned long iNumDevs,ii;
+ iNumDevs = waveInGetNumDevs();
+ for(ii=0;ii<iNumDevs;ii++) {
+ if(waveInGetDevCaps(ii, &wic, sizeof(WAVEINCAPS))
+ == MMSYSERR_NOERROR) {
+ QString tmp;
+ tmp = QString::fromUtf16((const unsigned short*)wic.szPname);
+ if(tmp.compare(tr(m_device)) == 0) {
+ devId = ii;
+ break;
+ }
+ }
+ }
+
+ if(waveInOpen(&hWaveIn, devId, &wfx,
+ (DWORD_PTR)&waveInProc,
+ (DWORD_PTR) this,
+ CALLBACK_FUNCTION) != MMSYSERR_NOERROR) {
+ errorState = QAudio::OpenError;
+ deviceState = QAudio::StopState;
+ emit stateChanged(deviceState);
+ qWarning("QAudioInput: failed to open audio device");
+ return false;
+ }
+ waveBlocks = allocateBlocks(period_size, buffer_size/period_size);
+ waveFreeBlockCount = buffer_size/period_size;
+ waveCurrentBlock = 0;
+
+ for(int i=0; i<buffer_size/period_size; i++) {
+ result = waveInAddBuffer(hWaveIn, &waveBlocks[i], sizeof(WAVEHDR));
+ if(result != MMSYSERR_NOERROR) {
+ qWarning("QAudioInput: failed to setup block %d,err=%d",i,result);
+ errorState = QAudio::OpenError;
+ deviceState = QAudio::StopState;
+ emit stateChanged(deviceState);
+ return false;
+ }
+ }
+ result = waveInStart(hWaveIn);
+ if(result) {
+ qWarning("QAudioInput: failed to start audio input");
+ errorState = QAudio::OpenError;
+ deviceState = QAudio::StopState;
+ emit stateChanged(deviceState);
+ return false;
+ }
+ timeStampOpened.restart();
+ totalTimeValue = 0;
+ errorState = QAudio::NoError;
+ deviceState = QAudio::ActiveState;
+ return true;
+}
+
+void QAudioInputPrivate::close()
+{
+ deviceState = QAudio::StopState;
+ int delay = (buffer_size-bytesReady())*1000/(settings.frequency()
+ *settings.channels()*(settings.sampleSize()/8));
+ waveInReset(hWaveIn);
+ Sleep(delay+10);
+
+ for(int i=0; i<waveFreeBlockCount; i++) {
+ if(waveBlocks[i].dwFlags & WHDR_PREPARED)
+ waveInUnprepareHeader(hWaveIn,&waveBlocks[i],sizeof(WAVEHDR));
+ }
+ freeBlocks(waveBlocks);
+ waveInClose(hWaveIn);
+}
+
+int QAudioInputPrivate::bytesReady() const
+{
+ int buf = ((buffer_size/period_size)-waveFreeBlockCount)*period_size;
+ if(buf < 0)
+ buf = 0;
+ return buf;
+}
+
+qint64 QAudioInputPrivate::read(char* data, qint64 len)
+{
+ bool done = false;
+
+ char* p = data;
+ qint64 l = 0;
+ qint64 written = 0;
+ while(!done) {
+ // Read in some audio data
+ if(waveBlocks[header].dwBytesRecorded > 0) {
+ if(pullMode) {
+ l = audioSource->write(waveBlocks[header].lpData,
+ waveBlocks[header].dwBytesRecorded);
+#ifdef DEBUG_AUDIO
+ qDebug()<<"IN: "<<waveBlocks[header].dwBytesRecorded<<", OUT: "<<l;
+#endif
+ if(l < 0) {
+ // error
+ qWarning("QAudioInput: IOError");
+ errorState = QAudio::IOError;
+
+ } else if(l == 0) {
+ // cant write to IODevice
+ qWarning("QAudioInput: IOError, can't write to QIODevice");
+ errorState = QAudio::IOError;
+
+ } else {
+ totalTimeValue += waveBlocks[header].dwBytesRecorded
+ /((settings.channels()*settings.sampleSize()/8))
+ *10000/settings.frequency()*100;
+ errorState = QAudio::NoError;
+ deviceState = QAudio::ActiveState;
+ resuming = false;
+ }
+ } else {
+ // push mode
+ memcpy(p,waveBlocks[header].lpData,waveBlocks[header].dwBytesRecorded);
+ l = waveBlocks[header].dwBytesRecorded;
+#ifdef DEBUG_AUDIO
+ qDebug()<<"IN: "<<waveBlocks[header].dwBytesRecorded<<", OUT: "<<l;
+#endif
+ totalTimeValue += waveBlocks[header].dwBytesRecorded
+ /((settings.channels()*settings.sampleSize()/8))
+ *10000/settings.frequency()*100;
+ errorState = QAudio::NoError;
+ deviceState = QAudio::ActiveState;
+ resuming = false;
+ }
+ } else {
+ //no data, not ready yet, next time
+ return 0;
+ }
+ EnterCriticalSection(&waveInCriticalSection);
+ waveFreeBlockCount++;
+ LeaveCriticalSection(&waveInCriticalSection);
+ waveBlocks[header].dwBytesRecorded=0;
+ waveBlocks[header].dwFlags = 0L;
+ result = waveInPrepareHeader(hWaveIn,&waveBlocks[header], sizeof(WAVEHDR));
+ if(result != MMSYSERR_NOERROR) {
+ qWarning("QAudioInput: failed to prepare block %d,err=%d",header,result);
+ errorState = QAudio::OpenError;
+ deviceState = QAudio::StopState;
+ emit stateChanged(deviceState);
+ }
+ result = waveInAddBuffer(hWaveIn, &waveBlocks[header], sizeof(WAVEHDR));
+ if(result != MMSYSERR_NOERROR) {
+ qWarning("QAudioInput: failed to setup block %d,err=%d",header,result);
+ errorState = QAudio::OpenError;
+ deviceState = QAudio::StopState;
+ emit stateChanged(deviceState);
+ }
+ header++;
+ if(header >= buffer_size/period_size)
+ header = 0;
+ p+=l;
+
+ if(!pullMode) {
+ if(l+period_size > len && waveFreeBlockCount == buffer_size/period_size)
+ done = true;
+ } else {
+ if(waveFreeBlockCount == buffer_size/period_size)
+ done = true;
+ }
+ written+=l;
+ }
+#ifdef DEBUG_AUDIO
+ qDebug()<<"read in len="<<written;
+#endif
+ return written;
+}
+
+void QAudioInputPrivate::resume()
+{
+ if(deviceState == QAudio::SuspendState) {
+ deviceState = QAudio::ActiveState;
+ for(int i=0; i<buffer_size/period_size; i++) {
+ result = waveInAddBuffer(hWaveIn, &waveBlocks[i], sizeof(WAVEHDR));
+ if(result != MMSYSERR_NOERROR) {
+ qWarning("QAudioInput: failed to setup block %d,err=%d",i,result);
+ errorState = QAudio::OpenError;
+ deviceState = QAudio::StopState;
+ emit stateChanged(deviceState);
+ return;
+ }
+ }
+ waveFreeBlockCount = buffer_size/period_size;
+ waveCurrentBlock = 0;
+ header = 0;
+ resuming = true;
+ waveInStart(hWaveIn);
+ QTimer::singleShot(20,this,SLOT(feedback()));
+ emit stateChanged(deviceState);
+ }
+}
+
+void QAudioInputPrivate::setBufferSize(int value)
+{
+ buffer_size = value;
+}
+
+int QAudioInputPrivate::bufferSize() const
+{
+ return buffer_size;
+}
+
+int QAudioInputPrivate::periodSize() const
+{
+ return period_size;
+}
+
+void QAudioInputPrivate::setNotifyInterval(int ms)
+{
+ intervalTime = ms;
+}
+
+int QAudioInputPrivate::notifyInterval() const
+{
+ return intervalTime;
+}
+
+qint64 QAudioInputPrivate::totalTime() const
+{
+ return totalTimeValue;
+}
+
+void QAudioInputPrivate::suspend()
+{
+ if(deviceState == QAudio::ActiveState) {
+ waveInReset(hWaveIn);
+ deviceState = QAudio::SuspendState;
+ emit stateChanged(deviceState);
+ }
+}
+
+void QAudioInputPrivate::feedback()
+{
+#ifdef DEBUG_AUDIO
+ QTime now(QTime::currentTime());
+ qDebug()<<now.second()<<"s "<<now.msec()<<"ms :feedback() INPUT";
+#endif
+ bytesAvailable = bytesReady();
+
+ if(!(deviceState==QAudio::StopState||deviceState==QAudio::SuspendState))
+ emit processMore();
+}
+
+bool QAudioInputPrivate::deviceReady()
+{
+#ifdef DEBUG_AUDIO
+ QTime now(QTime::currentTime());
+ qDebug()<<now.second()<<"s "<<now.msec()<<"ms :deviceReady() INPUT";
+#endif
+ if(pullMode) {
+ // reads some audio data and writes it to QIODevice
+ read(0,0);
+ } else {
+ // emits readyRead() so user will call read() on QIODevice to get some audio data
+ InputPrivate* a = qobject_cast<InputPrivate*>(audioSource);
+ a->trigger();
+ }
+ if(deviceState != QAudio::ActiveState)
+ return true;
+
+ if(timeStamp.elapsed() > intervalTime && intervalTime > 50) {
+ emit notify();
+ timeStamp.restart();
+ }
+ return true;
+}
+
+qint64 QAudioInputPrivate::clock() const
+{
+ if(deviceState != QAudio::ActiveState)
+ return 0;
+
+ return timeStampOpened.elapsed();
+}
+
+void QAudioInputPrivate::reset()
+{
+ close();
+}
+
+InputPrivate::InputPrivate(QAudioInputPrivate* audio)
+{
+ audioDevice = qobject_cast<QAudioInputPrivate*>(audio);
+}
+
+InputPrivate::~InputPrivate() {}
+
+qint64 InputPrivate::readData( char* data, qint64 len)
+{
+ // push mode, user read() called
+ if(audioDevice->deviceState != QAudio::ActiveState)
+ return 0;
+ // Read in some audio data
+ return audioDevice->read(data,len);
+}
+
+qint64 InputPrivate::writeData(const char* data, qint64 len)
+{
+ Q_UNUSED(data)
+ Q_UNUSED(len)
+
+ emit readyRead();
+ return 0;
+}
+
+void InputPrivate::trigger()
+{
+ emit readyRead();
+}
+
diff --git a/src/multimedia/audio/qaudioinput_win32_p.h b/src/multimedia/audio/qaudioinput_win32_p.h
new file mode 100644
index 0000000..32464f0
--- /dev/null
+++ b/src/multimedia/audio/qaudioinput_win32_p.h
@@ -0,0 +1,154 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtMultimedia module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the either Technology Preview License Agreement or the
+** Beta Release License Agreement.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain
+** additional rights. These rights are described in the Nokia Qt LGPL
+** Exception version 1.0, 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.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at http://www.qtsoftware.com/contact.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists for the convenience
+// of other Qt classes. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
+#ifndef QAUDIOINPUTWIN_H
+#define QAUDIOINPUTWIN_H
+
+#include <windows.h>
+#include <mmsystem.h>
+
+#include <QtCore/qfile.h>
+#include <QtCore/qdebug.h>
+#include <QtCore/qtimer.h>
+#include <QtCore/qstring.h>
+#include <QtCore/qstringlist.h>
+#include <QtCore/qdatetime.h>
+
+#include <QtMultimedia/qaudio.h>
+#include <QtMultimedia/qaudiodeviceinfo.h>
+#include <QtMultimedia/qaudioengine.h>
+
+
+static CRITICAL_SECTION waveInCriticalSection;
+
+class QAudioInputPrivate : public QAbstractAudioInput
+{
+ Q_OBJECT
+public:
+ QAudioInputPrivate(const QByteArray &device, const QAudioFormat& audioFormat);
+ ~QAudioInputPrivate();
+
+ qint64 read(char* data, qint64 len);
+
+ QAudioFormat format() const;
+ QIODevice* start(QIODevice* device = 0);
+ void stop();
+ void reset();
+ void suspend();
+ void resume();
+ int bytesReady() const;
+ int periodSize() const;
+ void setBufferSize(int value);
+ int bufferSize() const;
+ void setNotifyInterval(int milliSeconds);
+ int notifyInterval() const;
+ qint64 totalTime() const;
+ qint64 clock() const;
+ QAudio::Error error() const;
+ QAudio::State state() const;
+
+ QIODevice* audioSource;
+ QAudioFormat settings;
+ QAudio::Error errorState;
+ QAudio::State deviceState;
+
+private:
+ qint32 buffer_size;
+ qint32 period_size;
+ qint32 header;
+ QByteArray m_device;
+ int bytesAvailable;
+ int intervalTime;
+ QTime timeStamp;
+ QTime timeStampOpened;
+ qint64 totalTimeValue;
+ bool pullMode;
+ bool resuming;
+ WAVEFORMATEX wfx;
+ HWAVEIN hWaveIn;
+ MMRESULT result;
+ WAVEHDR* waveBlocks;
+ volatile int waveFreeBlockCount;
+ int waveCurrentBlock;
+
+ static void CALLBACK waveInProc( HWAVEIN hWaveIn, UINT uMsg,
+ DWORD dwInstance, DWORD dwParam1, DWORD dwParam2 );
+
+ WAVEHDR* allocateBlocks(int size, int count);
+ void freeBlocks(WAVEHDR* blockArray);
+ bool open();
+ void close();
+
+private slots:
+ void feedback();
+ bool deviceReady();
+
+signals:
+ void processMore();
+};
+
+class InputPrivate : public QIODevice
+{
+ Q_OBJECT
+public:
+ InputPrivate(QAudioInputPrivate* audio);
+ ~InputPrivate();
+
+ qint64 readData( char* data, qint64 len);
+ qint64 writeData(const char* data, qint64 len);
+
+ void trigger();
+private:
+ QAudioInputPrivate *audioDevice;
+};
+
+#endif
diff --git a/src/multimedia/audio/qaudiooutput.cpp b/src/multimedia/audio/qaudiooutput.cpp
new file mode 100644
index 0000000..785da61
--- /dev/null
+++ b/src/multimedia/audio/qaudiooutput.cpp
@@ -0,0 +1,403 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtMultimedia module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the either Technology Preview License Agreement or the
+** Beta Release License Agreement.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain
+** additional rights. These rights are described in the Nokia Qt LGPL
+** Exception version 1.0, 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.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at http://www.qtsoftware.com/contact.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+
+#include <QtMultimedia/qaudio.h>
+#include <QtMultimedia/qaudiodeviceinfo.h>
+#include <QtMultimedia/qaudioengine.h>
+#include <QtMultimedia/qaudiooutput.h>
+
+#include "qaudiodevicefactory_p.h"
+
+
+QT_BEGIN_NAMESPACE
+
+/*!
+ \class QAudioOutput
+ \brief The QAudioOutput class provides an interface for sending audio data to an audio output device.
+
+ \inmodule QtMultimedia
+ \ingroup multimedia
+ \since 4.6
+
+ You can construct an audio output with the system's
+ \l{QAudioDeviceInfo::defaultOutputDevice()}{default audio output
+ device}. It is also possible to create QAudioOutput with a
+ specific QAudioDeviceId. When you create the audio output, you
+ should also send in the QAudioFormat to be used for the playback
+ (see the QAudioFormat class description for details).
+
+ To play a file:
+
+ Starting to play an audio stream is simply a matter of calling
+ start() with a QIODevice. QAudioOutput will then fetch the data it
+ needs from the io device. So playing back an audio file is as
+ simple as:
+
+ \code
+ QFile inputFile;
+ inputFile.setFileName("/tmp/test.raw");
+ inputFile.open(QIODevice::ReadOnly);
+
+ QAudioFormat format;
+ // Set up the format, eg.
+ format.setFrequency(8000);
+ format.setChannels(1);
+ format.setSampleSize(8);
+ format.setCodec("audio/pcm");
+ format.setByteOrder(QAudioFormat::LittleEndian);
+ format.setSampleType(QAudioFormat::UnSignedInt);
+
+ QAudioOutput *audio = new QAudioOutput(format, this);
+ connect(audio,SIGNAL(stateChanged(QAudio::State)),SLOT(finishedPlaying(QAudio::State)));
+ audio->start(inputFile);
+
+ \endcode
+
+ The file will start playing assuming that the audio system and
+ output device support it. If you run out of luck, check what's
+ up with the error() function.
+
+ After the file has finished playing, we need to stop the device:
+
+ \code
+ void finishedPlaying(QAudio::State state)
+ {
+ if(state == QAudio::IdleState) {
+ audio->stop();
+ inputFile.close();
+ }
+ }
+ \endcode
+
+ At any given time, the QAudioOutput will be in one of four states:
+ active, suspended, stopped, or idle. These states are described
+ by the QAudio::State enum.
+ State changes are reported through the stateChanged() signal. You
+ can use this signal to, for instance, update the GUI of the
+ application; the mundane example here being changing the state of
+ a \c { play/pause } button. You request a state change directly
+ with suspend(), stop(), reset(), resume(), and start().
+
+ While the stream is playing, you can set a notify interval in
+ milliseconds with setNotifyInterval(). This interval specifies the
+ time between two emissions of the notify() signal. This is
+ relative to the position in the stream, i.e., if the QAudioOutput
+ is in the SuspendedState or the IdleState, the notify() signal is
+ not emitted. A typical use-case would be to update a
+ \l{QSlider}{slider} that allows seeking in the stream.
+ If you want the time since playback started regardless of which
+ states the audio output has been in, clock() is the function for you.
+
+ If an error occurs, you can fetch the \l{QAudio::Error}{error
+ type} with the error() function. Please see the QAudio::Error enum
+ for a description of the possible errors that are reported.
+
+ If an error is encountered state changes to QAudio::StopState.
+
+ \sa QAudioInput, QAudioDeviceInfo
+*/
+
+/*!
+ Construct a new audio output and attach it to \a parent.
+ The default audio output device is used with the output
+ \a format parameters.
+*/
+
+QAudioOutput::QAudioOutput(const QAudioFormat &format, QObject *parent):
+ QObject(parent)
+{
+ d = QAudioDeviceFactory::createDefaultOutputDevice(format);
+ connect(d, SIGNAL(notify()), SIGNAL(notify()));
+ connect(d, SIGNAL(stateChanged(QAudio::State)), SIGNAL(stateChanged(QAudio::State)));
+}
+
+/*!
+ Construct a new audio output and attach it to \a parent.
+ The \a id of the audio output device is used with the output
+ \a format parameters.
+*/
+
+QAudioOutput::QAudioOutput(const QAudioDeviceId &id, const QAudioFormat &format, QObject *parent):
+ QObject(parent)
+{
+ d = QAudioDeviceFactory::createOutputDevice(id, format);
+ connect(d, SIGNAL(notify()), SIGNAL(notify()));
+ connect(d, SIGNAL(stateChanged(QAudio::State)), SIGNAL(stateChanged(QAudio::State)));
+}
+
+/*!
+ Destroys this audio output.
+*/
+
+QAudioOutput::~QAudioOutput()
+{
+ delete d;
+}
+
+/*!
+ Returns the QAudioFormat being used.
+
+*/
+
+QAudioFormat QAudioOutput::format() const
+{
+ return d->format();
+}
+
+/*!
+ Uses the \a device as the QIODevice to transfer data.
+ If \a device is null then the class creates an internal QIODevice.
+ Returns a pointer to the QIODevice being used to handle the data
+ transfer. This QIODevice can be used to write() audio data
+ directly.
+ Passing a QIODevice allows the data to be transfered without any extra code.
+ All that is required is to open the QIODevice.
+
+ /sa QIODevice
+*/
+
+QIODevice* QAudioOutput::start(QIODevice* device)
+{
+ /*
+ PULL MODE (valid QIODevice)
+ -If currently not StopState, stop.
+ -If previous start was push mode, delete internal QIODevice.
+ -open audio output.
+ -If ok, NoError and ActiveState, else OpenError and StopState
+ -emit stateChanged()
+ -return device
+
+ PUSH MODE (device = 0)
+ -If currently not StopState, stop.
+ -If no internal QIODevice, create one.
+ -open audio output.
+ -If ok, NoError and IdleState, else OpenError and StopState
+ -emit stateChanged()
+ -return internal QIODevice
+ */
+ return d->start(device);
+}
+
+/*!
+ Stops the audio output.
+*/
+
+void QAudioOutput::stop()
+{
+ /*
+ -If StopState, return
+ -set to StopState
+ -detach from audio device
+ -emit stateChanged()
+ */
+ d->stop();
+}
+
+/*!
+ Drops all audio data in the buffers, resets buffers to zero.
+*/
+
+void QAudioOutput::reset()
+{
+ /*
+ -drop all buffered audio, set buffers to zero.
+ -call stop()
+ */
+ d->reset();
+}
+
+/*!
+ Stops processing audio data, preserving buffered audio data.
+*/
+
+void QAudioOutput::suspend()
+{
+ /*
+ -If not ActiveState|IdleState, return
+ -stop processing audio, saving all buffered audio data
+ -set NoError and SuspendState
+ -emit stateChanged()
+ */
+ d->suspend();
+}
+
+/*!
+ Resumes processing audio data after a suspend().
+*/
+
+void QAudioOutput::resume()
+{
+ /*
+ -If SuspendState, return
+ -resume audio
+ -(PULL MODE): set ActiveState, NoError
+ -(PUSH MODE): set IdleState, NoError
+ -kick start audio if needed
+ -emit stateChanged()
+ */
+ d->resume();
+}
+
+/*!
+ Returns the free space available in bytes in the audio buffer.
+*/
+
+int QAudioOutput::bytesFree() const
+{
+ /*
+ -If not ActiveState|IdleState, return 0
+ -return space available in audio buffer in bytes
+ */
+ return d->bytesFree();
+}
+
+/*!
+ Returns the period size in bytes.
+
+ Note: This is the recommended write size in bytes.
+*/
+
+int QAudioOutput::periodSize() const
+{
+ return d->periodSize();
+}
+
+/*!
+ Sets the audio buffer size to \a value in bytes.
+
+ Note: This function can be called anytime before start(), calls to this
+ are ignored after start(). It should not be assumed that the buffer size
+ set is the actual buffer size used, calling bufferSize() anytime after start()
+ will return the actual buffer size being used.
+*/
+
+void QAudioOutput::setBufferSize(int value)
+{
+ d->setBufferSize(value);
+}
+
+/*!
+ Returns the audio buffer size in bytes.
+
+ If called before start(), returns platform default value.
+ If called before start() but setBufferSize() was called prior, returns value set by setBufferSize().
+ If called after start(), returns the actual buffer size being used. This may not be what was set previously
+ by setBufferSize().
+
+*/
+
+int QAudioOutput::bufferSize() const
+{
+ return d->bufferSize();
+}
+
+/*!
+ Sets the interval for notify() signal to be emitted.
+ This is based on the \a ms of audio data processed
+ not on actual real-time. The resolution of the timer is platform specific.
+*/
+
+void QAudioOutput::setNotifyInterval(int ms)
+{
+ d->setNotifyInterval(ms);
+}
+
+/*!
+ Returns the notify interval in milliseconds.
+*/
+
+int QAudioOutput::notifyInterval() const
+{
+ return d->notifyInterval();
+}
+
+/*!
+ Returns the amount of audio data processed since start()
+ was called in microseconds.
+*/
+
+qint64 QAudioOutput::totalTime() const
+{
+ return d->totalTime();
+}
+
+/*!
+ Returns the microseconds since start() was called, including time in Idle and
+ Suspend states.
+*/
+
+qint64 QAudioOutput::clock() const
+{
+ return d->clock();
+}
+
+/*!
+ Returns the error state.
+*/
+
+QAudio::Error QAudioOutput::error() const
+{
+ return d->error();
+}
+
+/*!
+ Returns the state of audio processing.
+*/
+
+QAudio::State QAudioOutput::state() const
+{
+ return d->state();
+}
+
+/*!
+ \fn QAudioOutput::stateChanged(QAudio::State state)
+ This signal is emitted when the device \a state has changed.
+ This is the current state of the audio output.
+*/
+
+/*!
+ \fn QAudioOutput::notify()
+ This signal is emitted when x ms of audio data has been processed
+ the interval set by setNotifyInterval(x).
+*/
+
+QT_END_NAMESPACE
diff --git a/src/multimedia/audio/qaudiooutput.h b/src/multimedia/audio/qaudiooutput.h
new file mode 100644
index 0000000..95e28ea
--- /dev/null
+++ b/src/multimedia/audio/qaudiooutput.h
@@ -0,0 +1,109 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtMultimedia module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the either Technology Preview License Agreement or the
+** Beta Release License Agreement.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain
+** additional rights. These rights are described in the Nokia Qt LGPL
+** Exception version 1.0, 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.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at http://www.qtsoftware.com/contact.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+
+#ifndef QAUDIOOUTPUT_H
+#define QAUDIOOUTPUT_H
+
+#include <QtCore/qiodevice.h>
+#include <QtCore/qglobal.h>
+
+#include <QtMultimedia/qaudio.h>
+#include <QtMultimedia/qaudioformat.h>
+#include <QtMultimedia/qaudiodeviceid.h>
+
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+QT_MODULE(Multimedia)
+
+
+class QAbstractAudioOutput;
+
+class Q_MULTIMEDIA_EXPORT QAudioOutput : public QObject
+{
+ Q_OBJECT
+
+public:
+ explicit QAudioOutput(const QAudioFormat &format = QAudioFormat(), QObject *parent = 0);
+ explicit QAudioOutput(const QAudioDeviceId &id, const QAudioFormat &format = QAudioFormat(), QObject *parent = 0);
+ ~QAudioOutput();
+
+ QAudioFormat format() const;
+
+ QIODevice* start(QIODevice *device = 0);
+ void stop();
+ void reset();
+ void suspend();
+ void resume();
+
+ void setBufferSize(int bytes);
+ int bufferSize() const;
+
+ int bytesFree() const;
+ int periodSize() const;
+
+ void setNotifyInterval(int milliSeconds);
+ int notifyInterval() const;
+
+ qint64 totalTime() const;
+ qint64 clock() const;
+
+ QAudio::Error error() const;
+ QAudio::State state() const;
+
+Q_SIGNALS:
+ void stateChanged(QAudio::State);
+ void notify();
+
+private:
+ Q_DISABLE_COPY(QAudioOutput)
+
+ QAbstractAudioOutput* d;
+};
+
+QT_END_NAMESPACE
+
+QT_END_HEADER
+
+#endif // QAUDIOOUTPUT_H
diff --git a/src/multimedia/audio/qaudiooutput_alsa_p.cpp b/src/multimedia/audio/qaudiooutput_alsa_p.cpp
new file mode 100644
index 0000000..d41c449
--- /dev/null
+++ b/src/multimedia/audio/qaudiooutput_alsa_p.cpp
@@ -0,0 +1,706 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtMultimedia module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the either Technology Preview License Agreement or the
+** Beta Release License Agreement.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain
+** additional rights. These rights are described in the Nokia Qt LGPL
+** Exception version 1.0, 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.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at http://www.qtsoftware.com/contact.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists for the convenience
+// of other Qt classes. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
+#include <QtCore/qcoreapplication.h>
+#include "qaudiooutput_alsa_p.h"
+
+//#define DEBUG_AUDIO 1
+
+QAudioOutputPrivate::QAudioOutputPrivate(const QByteArray &device, const QAudioFormat& audioFormat):
+ settings(audioFormat)
+{
+ bytesAvailable = 0;
+ handle = 0;
+ ahandler = 0;
+ access = SND_PCM_ACCESS_RW_INTERLEAVED;
+ pcmformat = SND_PCM_FORMAT_S16;
+ buffer_frames = 0;
+ period_frames = 0;
+ buffer_size = 0;
+ period_size = 0;
+ buffer_time = 100000;
+ period_time = 20000;
+ totalTimeValue = 0;
+ intervalTime = 1000;
+ audioBuffer = 0;
+ errorState = QAudio::NoError;
+ deviceState = QAudio::StopState;
+ audioSource = 0;
+ pullMode = true;
+ resuming = false;
+ opened = false;
+
+ QStringList list1 = QString(tr(device)).split(tr(":"));
+ m_device = QByteArray(list1.at(0).toLocal8Bit().constData());
+
+ timer = new QTimer(this);
+ connect(timer,SIGNAL(timeout()),SLOT(userFeed()));
+}
+
+QAudioOutputPrivate::~QAudioOutputPrivate()
+{
+ close();
+ disconnect(timer, SIGNAL(timeout()));
+ QCoreApplication::processEvents();
+ delete timer;
+}
+
+QAudio::Error QAudioOutputPrivate::error() const
+{
+ return errorState;
+}
+
+QAudio::State QAudioOutputPrivate::state() const
+{
+ return deviceState;
+}
+
+void QAudioOutputPrivate::async_callback(snd_async_handler_t *ahandler)
+{
+ QAudioOutputPrivate* audioOut;
+
+ audioOut = static_cast<QAudioOutputPrivate*>
+ (snd_async_handler_get_callback_private(ahandler));
+
+ if((audioOut->deviceState==QAudio::ActiveState)||(audioOut->resuming))
+ audioOut->feedback();
+}
+
+int QAudioOutputPrivate::xrun_recovery(int err)
+{
+ int count = 0;
+ bool reset = false;
+
+ if(err == -EPIPE) {
+ errorState = QAudio::UnderrunError;
+ err = snd_pcm_prepare(handle);
+ if(err < 0)
+ reset = true;
+
+ } else if((err == -ESTRPIPE)||(err == -EIO)) {
+ errorState = QAudio::IOError;
+ while((err = snd_pcm_resume(handle)) == -EAGAIN){
+ usleep(100);
+ count++;
+ if(count > 5) {
+ reset = true;
+ break;
+ }
+ }
+ if(err < 0) {
+ err = snd_pcm_prepare(handle);
+ if(err < 0)
+ reset = true;
+ }
+ }
+ if(reset) {
+ close();
+ open();
+ snd_pcm_prepare(handle);
+ return 0;
+ }
+ return err;
+}
+
+int QAudioOutputPrivate::setFormat()
+{
+ snd_pcm_format_t pcmformat = SND_PCM_FORMAT_S16;
+
+ if(settings.sampleSize() == 8) {
+ pcmformat = SND_PCM_FORMAT_U8;
+
+ } else if(settings.sampleSize() == 16) {
+ if(settings.sampleType() == QAudioFormat::SignedInt) {
+ if(settings.byteOrder() == QAudioFormat::LittleEndian)
+ pcmformat = SND_PCM_FORMAT_S16_LE;
+ else
+ pcmformat = SND_PCM_FORMAT_S16_BE;
+ } else if(settings.sampleType() == QAudioFormat::UnSignedInt) {
+ if(settings.byteOrder() == QAudioFormat::LittleEndian)
+ pcmformat = SND_PCM_FORMAT_U16_LE;
+ else
+ pcmformat = SND_PCM_FORMAT_U16_BE;
+ }
+ } else if(settings.sampleSize() == 24) {
+ if(settings.sampleType() == QAudioFormat::SignedInt) {
+ if(settings.byteOrder() == QAudioFormat::LittleEndian)
+ pcmformat = SND_PCM_FORMAT_S24_LE;
+ else
+ pcmformat = SND_PCM_FORMAT_S24_BE;
+ } else if(settings.sampleType() == QAudioFormat::UnSignedInt) {
+ if(settings.byteOrder() == QAudioFormat::LittleEndian)
+ pcmformat = SND_PCM_FORMAT_U24_LE;
+ else
+ pcmformat = SND_PCM_FORMAT_U24_BE;
+ }
+ } else if(settings.sampleSize() == 32) {
+ if(settings.sampleType() == QAudioFormat::SignedInt) {
+ if(settings.byteOrder() == QAudioFormat::LittleEndian)
+ pcmformat = SND_PCM_FORMAT_S32_LE;
+ else
+ pcmformat = SND_PCM_FORMAT_S32_BE;
+ } else if(settings.sampleType() == QAudioFormat::UnSignedInt) {
+ if(settings.byteOrder() == QAudioFormat::LittleEndian)
+ pcmformat = SND_PCM_FORMAT_U32_LE;
+ else
+ pcmformat = SND_PCM_FORMAT_U32_BE;
+ } else if(settings.sampleType() == QAudioFormat::Float) {
+ if(settings.byteOrder() == QAudioFormat::LittleEndian)
+ pcmformat = SND_PCM_FORMAT_FLOAT_LE;
+ else
+ pcmformat = SND_PCM_FORMAT_FLOAT_BE;
+ }
+ } else if(settings.sampleSize() == 64) {
+ if(settings.byteOrder() == QAudioFormat::LittleEndian)
+ pcmformat = SND_PCM_FORMAT_FLOAT64_LE;
+ else
+ pcmformat = SND_PCM_FORMAT_FLOAT64_BE;
+ }
+
+ return snd_pcm_hw_params_set_format( handle, hwparams, pcmformat);
+}
+
+QIODevice* QAudioOutputPrivate::start(QIODevice* device)
+{
+ if(deviceState != QAudio::StopState)
+ deviceState = QAudio::StopState;
+
+ errorState = QAudio::NoError;
+
+ // Handle change of mode
+ if(audioSource && pullMode && !device) {
+ // pull -> push
+ close();
+ audioSource = 0;
+ } else if(audioSource && !pullMode && device) {
+ // push -> pull
+ close();
+ delete audioSource;
+ audioSource = 0;
+ }
+
+ if(device) {
+ //set to pull mode
+ pullMode = true;
+ audioSource = device;
+ deviceState = QAudio::ActiveState;
+ } else {
+ //set to push mode
+ if(!audioSource) {
+ audioSource = new OutputPrivate(this);
+ audioSource->open(QIODevice::WriteOnly|QIODevice::Unbuffered);
+ }
+ pullMode = false;
+ deviceState = QAudio::IdleState;
+ }
+
+ open();
+
+ emit stateChanged(deviceState);
+
+ return audioSource;
+}
+
+void QAudioOutputPrivate::stop()
+{
+ if(deviceState == QAudio::StopState)
+ return;
+ deviceState = QAudio::StopState;
+ close();
+ emit stateChanged(deviceState);
+}
+
+bool QAudioOutputPrivate::open()
+{
+ if(opened)
+ return true;
+
+#ifdef DEBUG_AUDIO
+ QTime now(QTime::currentTime());
+ qDebug()<<now.second()<<"s "<<now.msec()<<"ms :open()";
+#endif
+ timeStamp.restart();
+
+ int dir;
+ int err=-1;
+ int count=0;
+ unsigned int freakuency=settings.frequency();
+
+ QString dev = tr(m_device.constData());
+ if(!dev.contains(tr("default"))) {
+ dev = QString(tr("default:CARD=%1")).arg(tr(m_device.constData()));
+ }
+ // Step 1: try and open the device
+ while((count < 5) && (err < 0)) {
+ err=snd_pcm_open(&handle,dev.toLocal8Bit().constData(),SND_PCM_STREAM_PLAYBACK,0);
+ if(err < 0)
+ count++;
+ }
+ if (( err < 0)||(handle == 0)) {
+ errorState = QAudio::OpenError;
+ deviceState = QAudio::StopState;
+ return false;
+ }
+ snd_pcm_nonblock( handle, 0 );
+
+ // Step 2: Set the desired HW parameters.
+ snd_pcm_hw_params_alloca( &hwparams );
+
+ bool fatal = false;
+ QString errMessage;
+ unsigned int chunks = 8;
+
+ err = snd_pcm_hw_params_any( handle, hwparams );
+ if ( err < 0 ) {
+ fatal = true;
+ errMessage = QString(tr("QAudioOutput: snd_pcm_hw_params_any: err = %1")).arg(err);
+ }
+ if ( !fatal ) {
+ err = snd_pcm_hw_params_set_rate_resample( handle, hwparams, 1 );
+ if ( err < 0 ) {
+ fatal = true;
+ errMessage = QString(tr("QAudioOutput: snd_pcm_hw_params_set_rate_resample: err = %1")).arg(err);
+ }
+ }
+ if ( !fatal ) {
+ err = snd_pcm_hw_params_set_access( handle, hwparams, access );
+ if ( err < 0 ) {
+ fatal = true;
+ errMessage = QString(tr("QAudioOutput: snd_pcm_hw_params_set_access: err = %1")).arg(err);
+ }
+ }
+ if ( !fatal ) {
+ err = setFormat();
+ if ( err < 0 ) {
+ fatal = true;
+ errMessage = QString(tr("QAudioOutput: snd_pcm_hw_params_set_format: err = %1")).arg(err);
+ }
+ }
+ if ( !fatal ) {
+ err = snd_pcm_hw_params_set_channels( handle, hwparams, (unsigned int)settings.channels() );
+ if ( err < 0 ) {
+ fatal = true;
+ errMessage = QString(tr("QAudioOutput: snd_pcm_hw_params_set_channels: err = %1")).arg(err);
+ }
+ }
+ if ( !fatal ) {
+ err = snd_pcm_hw_params_set_rate_near( handle, hwparams, &freakuency, 0 );
+ if ( err < 0 ) {
+ fatal = true;
+ errMessage = QString(tr("QAudioOutput: snd_pcm_hw_params_set_rate_near: err = %1")).arg(err);
+ }
+ }
+ if ( !fatal ) {
+ err = snd_pcm_hw_params_set_buffer_time_near(handle, hwparams, &buffer_time, &dir);
+ if ( err < 0 ) {
+ fatal = true;
+ errMessage = QString(tr("QAudioOutput: snd_pcm_hw_params_set_buffer_time_near: err = %1")).arg(err);
+ }
+ }
+ if ( !fatal ) {
+ err = snd_pcm_hw_params_set_period_time_near(handle, hwparams, &period_time, &dir);
+ if ( err < 0 ) {
+ fatal = true;
+ errMessage = QString(tr("QAudioOutput: snd_pcm_hw_params_set_period_time_near: err = %1")).arg(err);
+ }
+ }
+ if ( !fatal ) {
+ err = snd_pcm_hw_params_set_periods_near(handle, hwparams, &chunks, &dir);
+ if ( err < 0 ) {
+ fatal = true;
+ errMessage = QString(tr("QAudioOutput: snd_pcm_hw_params_set_periods_near: err = %1")).arg(err);
+ }
+ }
+ if ( !fatal ) {
+ err = snd_pcm_hw_params(handle, hwparams);
+ if ( err < 0 ) {
+ fatal = true;
+ errMessage = QString(tr("QAudioOutput: snd_pcm_hw_params: err = %1")).arg(err);
+ }
+ }
+ if( err < 0) {
+ qWarning()<<errMessage;
+ errorState = QAudio::OpenError;
+ deviceState = QAudio::StopState;
+ return false;
+ }
+ snd_pcm_hw_params_get_buffer_size(hwparams,&buffer_frames);
+ buffer_size = snd_pcm_frames_to_bytes(handle,buffer_frames);
+ snd_pcm_hw_params_get_period_size(hwparams,&period_frames, &dir);
+ period_size = snd_pcm_frames_to_bytes(handle,period_frames);
+ snd_pcm_hw_params_get_buffer_time(hwparams,&buffer_time, &dir);
+ snd_pcm_hw_params_get_period_time(hwparams,&period_time, &dir);
+
+ // Step 3: Set the desired SW parameters.
+ snd_pcm_sw_params_t *swparams;
+ snd_pcm_sw_params_alloca(&swparams);
+ snd_pcm_sw_params_current(handle, swparams);
+ snd_pcm_sw_params_set_start_threshold(handle,swparams,period_frames);
+ snd_pcm_sw_params_set_stop_threshold(handle,swparams,buffer_frames);
+ snd_pcm_sw_params_set_avail_min(handle, swparams,period_frames);
+ snd_pcm_sw_params(handle, swparams);
+
+ // Step 4: Prepare audio
+ if(audioBuffer == 0)
+ audioBuffer = new char[snd_pcm_frames_to_bytes(handle,buffer_frames)];
+ snd_pcm_prepare( handle );
+ snd_pcm_start(handle);
+
+ // Step 5: Setup callback and timer fallback
+ snd_async_add_pcm_handler(&ahandler, handle, async_callback, this);
+ bytesAvailable = bytesFree();
+
+ // Step 6: Start audio processing
+ timer->start(period_time/1000);
+
+ errorState = QAudio::NoError;
+ totalTimeValue = 0;
+ opened = true;
+
+ return true;
+}
+
+void QAudioOutputPrivate::close()
+{
+ deviceState = QAudio::StopState;
+ timer->stop();
+
+ if ( handle ) {
+ snd_pcm_drain( handle );
+ snd_pcm_close( handle );
+ handle = 0;
+ delete [] audioBuffer;
+ audioBuffer=0;
+ }
+ if(!pullMode && audioSource) {
+ delete audioSource;
+ audioSource = 0;
+ }
+ opened = false;
+}
+
+int QAudioOutputPrivate::bytesFree() const
+{
+ if(resuming)
+ return period_size;
+
+ if(deviceState != QAudio::ActiveState && deviceState != QAudio::IdleState)
+ return 0;
+ int frames = snd_pcm_avail_update(handle);
+ if((int)frames > (int)buffer_frames)
+ frames = buffer_frames;
+
+ return snd_pcm_frames_to_bytes(handle, frames);
+}
+
+qint64 QAudioOutputPrivate::write( const char *data, qint64 len )
+{
+ // Write out some audio data
+ if ( !handle )
+ return 0;
+#ifdef DEBUG_AUDIO
+ qDebug()<<"frames to write out = "<<
+ snd_pcm_bytes_to_frames( handle, (int)len )<<" ("<<len<<") bytes";
+#endif
+ int frames, err;
+ int space = bytesFree();
+ if(len < space) {
+ // Just write it
+ frames = snd_pcm_bytes_to_frames( handle, (int)len );
+ err = snd_pcm_writei( handle, data, frames );
+ } else {
+ // Only write space worth
+ frames = snd_pcm_bytes_to_frames( handle, (int)space );
+ err = snd_pcm_writei( handle, data, frames );
+ }
+ if(err > 0) {
+ totalTimeValue += err*1000000/settings.frequency();
+ resuming = false;
+ errorState = QAudio::NoError;
+ deviceState = QAudio::ActiveState;
+ return snd_pcm_frames_to_bytes( handle, err );
+ } else
+ err = xrun_recovery(err);
+
+ if(err < 0) {
+ close();
+ errorState = QAudio::FatalError;
+ deviceState = QAudio::StopState;
+ emit stateChanged(deviceState);
+ }
+ return 0;
+}
+
+int QAudioOutputPrivate::periodSize() const
+{
+ return period_size;
+}
+
+void QAudioOutputPrivate::setBufferSize(int value)
+{
+ if(deviceState == QAudio::StopState)
+ buffer_size = value;
+}
+
+int QAudioOutputPrivate::bufferSize() const
+{
+ return buffer_size;
+}
+
+void QAudioOutputPrivate::setNotifyInterval(int ms)
+{
+ intervalTime = ms;
+}
+
+int QAudioOutputPrivate::notifyInterval() const
+{
+ return intervalTime;
+}
+
+qint64 QAudioOutputPrivate::totalTime() const
+{
+ return totalTimeValue;
+}
+
+void QAudioOutputPrivate::resume()
+{
+ if(deviceState == QAudio::SuspendState) {
+ int err = 0;
+
+ if(handle) {
+ err = snd_pcm_prepare( handle );
+ if(err < 0)
+ xrun_recovery(err);
+
+ err = snd_pcm_start(handle);
+ if(err < 0)
+ xrun_recovery(err);
+
+ bytesAvailable = (int)snd_pcm_frames_to_bytes(handle, buffer_frames);
+ }
+ resuming = true;
+ if(pullMode)
+ deviceState = QAudio::ActiveState;
+ else
+ deviceState = QAudio::IdleState;
+
+ errorState = QAudio::NoError;
+ timer->start(period_time/1000);
+ emit stateChanged(deviceState);
+ }
+}
+
+QAudioFormat QAudioOutputPrivate::format() const
+{
+ return settings;
+}
+
+void QAudioOutputPrivate::suspend()
+{
+ if(deviceState == QAudio::ActiveState || deviceState == QAudio::IdleState || resuming) {
+ timer->stop();
+ deviceState = QAudio::SuspendState;
+ errorState = QAudio::NoError;
+ emit stateChanged(deviceState);
+ }
+}
+
+void QAudioOutputPrivate::userFeed()
+{
+ if(deviceState == QAudio::StopState || deviceState == QAudio::SuspendState)
+ return;
+#ifdef DEBUG_AUDIO
+ QTime now(QTime::currentTime());
+ qDebug()<<now.second()<<"s "<<now.msec()<<"ms :userFeed() OUT";
+#endif
+ if(deviceState == QAudio::IdleState)
+ bytesAvailable = bytesFree();
+
+ deviceReady();
+}
+
+void QAudioOutputPrivate::feedback()
+{
+ QMetaObject::invokeMethod(this, SLOT(updateAvailable()), Qt::QueuedConnection);
+}
+
+void QAudioOutputPrivate::updateAvailable()
+{
+#ifdef DEBUG_AUDIO
+ QTime now(QTime::currentTime());
+ qDebug()<<now.second()<<"s "<<now.msec()<<"ms :updateAvailable()";
+#endif
+ bytesAvailable = bytesFree();
+}
+
+bool QAudioOutputPrivate::deviceReady()
+{
+ if(pullMode) {
+ int l = 0;
+ int chunks = bytesAvailable/period_size;
+ if(chunks==0) {
+ bytesAvailable = bytesFree();
+ return false;
+ }
+#ifdef DEBUG_AUDIO
+ qDebug()<<"deviceReady() avail="<<bytesAvailable<<" bytes, period size="<<period_size<<" bytes";
+ qDebug()<<"deviceReady() no. of chunks that can fit ="<<chunks<<", chunks in bytes ="<<period_size*chunks;
+#endif
+ int input = period_frames*chunks;
+ if(input > (int)buffer_frames)
+ input = buffer_frames;
+ l = audioSource->read(audioBuffer,snd_pcm_frames_to_bytes(handle, input));
+ if(l > 0) {
+ // Got some data to output
+ if(deviceState != QAudio::ActiveState)
+ return true;
+ write(audioBuffer,l);
+ bytesAvailable = bytesFree();
+
+ } else if(l == 0) {
+ // Did not get any data to output
+ bytesAvailable = bytesFree();
+ if(bytesAvailable > snd_pcm_frames_to_bytes(handle, buffer_frames-period_frames)) {
+ // Underrun
+ errorState = QAudio::UnderrunError;
+ deviceState = QAudio::IdleState;
+ emit stateChanged(deviceState);
+ }
+
+ } else if(l < 0) {
+ close();
+ errorState = QAudio::IOError;
+ emit stateChanged(deviceState);
+ }
+ } else
+ bytesAvailable = bytesFree();
+
+ if(deviceState != QAudio::ActiveState)
+ return true;
+
+ if(timeStamp.elapsed() > intervalTime && intervalTime > 50) {
+ emit notify();
+ timeStamp.restart();
+ }
+ return true;
+}
+
+qint64 QAudioOutputPrivate::clock() const
+{
+ if(!handle)
+ return 0;
+
+ if(deviceState != QAudio::ActiveState)
+ return 0;
+
+ snd_pcm_status_t* status;
+ snd_pcm_status_alloca(&status);
+
+ snd_timestamp_t t1,t2;
+ if( snd_pcm_status(handle, status) >= 0) {
+ snd_pcm_status_get_tstamp(status,&t1);
+ snd_pcm_status_get_trigger_tstamp(status,&t2);
+ t1.tv_sec-=t2.tv_sec;
+
+ signed long l = (signed long)t1.tv_usec - (signed long)t2.tv_usec;
+ if(l < 0) {
+ t1.tv_sec--;
+ l = -l;
+ l %= 1000000;
+ }
+ return ((t1.tv_sec * 1000)+l/1000);
+ } else
+ return 0;
+ return 0;
+}
+
+void QAudioOutputPrivate::reset()
+{
+ if(handle)
+ snd_pcm_reset(handle);
+
+ stop();
+}
+
+OutputPrivate::OutputPrivate(QAudioOutputPrivate* audio)
+{
+ audioDevice = qobject_cast<QAudioOutputPrivate*>(audio);
+}
+
+OutputPrivate::~OutputPrivate() {}
+
+qint64 OutputPrivate::readData( char* data, qint64 len)
+{
+ Q_UNUSED(data)
+ Q_UNUSED(len)
+
+ return 0;
+}
+
+qint64 OutputPrivate::writeData(const char* data, qint64 len)
+{
+ int retry = 0;
+ qint64 written = 0;
+ if((audioDevice->deviceState == QAudio::ActiveState)
+ ||(audioDevice->deviceState == QAudio::IdleState)) {
+ while(written < len) {
+ int chunk = audioDevice->write(data+written,(len-written));
+ if(chunk <= 0)
+ retry++;
+ written+=chunk;
+ if(retry > 10)
+ return written;
+ }
+ }
+ return written;
+
+}
diff --git a/src/multimedia/audio/qaudiooutput_alsa_p.h b/src/multimedia/audio/qaudiooutput_alsa_p.h
new file mode 100644
index 0000000..f243bad
--- /dev/null
+++ b/src/multimedia/audio/qaudiooutput_alsa_p.h
@@ -0,0 +1,159 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtMultimedia module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the either Technology Preview License Agreement or the
+** Beta Release License Agreement.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain
+** additional rights. These rights are described in the Nokia Qt LGPL
+** Exception version 1.0, 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.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at http://www.qtsoftware.com/contact.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists for the convenience
+// of other Qt classes. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
+#ifndef QAUDIOOUTPUTALSA_H
+#define QAUDIOOUTPUTALSA_H
+
+#include <alsa/asoundlib.h>
+
+#include <QtCore/qfile.h>
+#include <QtCore/qdebug.h>
+#include <QtCore/qtimer.h>
+#include <QtCore/qstring.h>
+#include <QtCore/qstringlist.h>
+#include <QtCore/qdatetime.h>
+
+#include <QtMultimedia/qaudio.h>
+#include <QtMultimedia/qaudiodeviceinfo.h>
+#include <QtMultimedia/qaudioengine.h>
+
+class OutputPrivate;
+
+class QAudioOutputPrivate : public QAbstractAudioOutput
+{
+ friend class OutputPrivate;
+ Q_OBJECT
+public:
+ QAudioOutputPrivate(const QByteArray &device, const QAudioFormat& audioFormat);
+ ~QAudioOutputPrivate();
+
+ qint64 write( const char *data, qint64 len );
+
+ QIODevice* start(QIODevice* device = 0);
+ void stop();
+ void reset();
+ void suspend();
+ void resume();
+ int bytesFree() const;
+ int periodSize() const;
+ void setBufferSize(int value);
+ int bufferSize() const;
+ void setNotifyInterval(int milliSeconds);
+ int notifyInterval() const;
+ qint64 totalTime() const;
+ qint64 clock() const;
+ QAudio::Error error() const;
+ QAudio::State state() const;
+ QAudioFormat format() const;
+
+ QIODevice* audioSource;
+ QAudioFormat settings;
+ QAudio::Error errorState;
+ QAudio::State deviceState;
+
+private slots:
+ void userFeed();
+ void feedback();
+ void updateAvailable();
+ bool deviceReady();
+
+signals:
+ void processMore();
+
+private:
+ bool opened;
+ bool pullMode;
+ bool resuming;
+ int buffer_size;
+ int period_size;
+ int intervalTime;
+ qint64 totalTimeValue;
+ unsigned int buffer_time;
+ unsigned int period_time;
+ snd_pcm_uframes_t buffer_frames;
+ snd_pcm_uframes_t period_frames;
+ static void async_callback(snd_async_handler_t *ahandler);
+ int xrun_recovery(int err);
+
+ int setFormat();
+ bool open();
+ void close();
+
+ QTimer* timer;
+ QByteArray m_device;
+ int bytesAvailable;
+ QTime timeStamp;
+ char* audioBuffer;
+ snd_pcm_t* handle;
+ snd_async_handler_t* ahandler;
+ snd_pcm_access_t access;
+ snd_pcm_format_t pcmformat;
+ snd_timestamp_t* timestamp;
+ snd_pcm_hw_params_t *hwparams;
+};
+
+class OutputPrivate : public QIODevice
+{
+ friend class QAudioOutputPrivate;
+ Q_OBJECT
+public:
+ OutputPrivate(QAudioOutputPrivate* audio);
+ ~OutputPrivate();
+
+ qint64 readData( char* data, qint64 len);
+ qint64 writeData(const char* data, qint64 len);
+
+private:
+ QAudioOutputPrivate *audioDevice;
+};
+
+#endif
diff --git a/src/multimedia/audio/qaudiooutput_mac_p.cpp b/src/multimedia/audio/qaudiooutput_mac_p.cpp
new file mode 100644
index 0000000..0d6e615
--- /dev/null
+++ b/src/multimedia/audio/qaudiooutput_mac_p.cpp
@@ -0,0 +1,700 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtMultimedia module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the either Technology Preview License Agreement or the
+** Beta Release License Agreement.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain
+** additional rights. These rights are described in the Nokia Qt LGPL
+** Exception version 1.0, 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.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at http://www.qtsoftware.com/contact.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists for the convenience
+// of other Qt classes. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
+#include <CoreServices/CoreServices.h>
+#include <CoreAudio/CoreAudio.h>
+#include <AudioUnit/AudioUnit.h>
+#include <AudioToolbox/AudioToolbox.h>
+
+#include <QtCore/qendian.h>
+#include <QtCore/qbuffer.h>
+#include <QtCore/qtimer.h>
+#include <QtCore/qdebug.h>
+
+#include <QtMultimedia/qaudiodeviceinfo.h>
+#include <QtMultimedia/qaudiooutput.h>
+
+#include "qaudio_mac_p.h"
+#include "qaudiooutput_mac_p.h"
+
+
+QT_BEGIN_NAMESPACE
+
+
+namespace
+{
+
+static const int default_buffer_size = 8 * 1024;
+
+
+class QAudioOutputBuffer : public QObject
+{
+ Q_OBJECT
+
+public:
+ QAudioOutputBuffer(int bufferSize, int maxPeriodSize, QAudioFormat const& audioFormat):
+ m_deviceError(false),
+ m_maxPeriodSize(maxPeriodSize),
+ m_device(0)
+ {
+ m_buffer = new QAudioRingBuffer(bufferSize + (bufferSize % maxPeriodSize == 0 ? 0 : maxPeriodSize - (bufferSize % maxPeriodSize)));
+ m_bytesPerFrame = (audioFormat.sampleSize() / 8) * audioFormat.channels();
+ m_periodTime = m_maxPeriodSize / m_bytesPerFrame * 1000 / audioFormat.frequency();
+
+ m_fillTimer = new QTimer(this);
+ connect(m_fillTimer, SIGNAL(timeout()), SLOT(fillBuffer()));
+ }
+
+ ~QAudioOutputBuffer()
+ {
+ delete m_buffer;
+ }
+
+ qint64 readFrames(char* data, qint64 maxFrames)
+ {
+ bool wecan = true;
+ qint64 framesRead = 0;
+
+ while (wecan && framesRead < maxFrames) {
+ QAudioRingBuffer::Region region = m_buffer->acquireReadRegion((maxFrames - framesRead) * m_bytesPerFrame);
+
+ if (region.second > 0) {
+ region.second -= region.second % m_bytesPerFrame;
+ memcpy(data + (framesRead * m_bytesPerFrame), region.first, region.second);
+ framesRead += region.second / m_bytesPerFrame;
+ }
+ else
+ wecan = false;
+
+ m_buffer->releaseReadRegion(region);
+ }
+
+ if (framesRead == 0 && m_deviceError)
+ framesRead = -1;
+
+ return framesRead;
+ }
+
+ qint64 writeBytes(const char* data, qint64 maxSize)
+ {
+ bool wecan = true;
+ qint64 bytesWritten = 0;
+
+ maxSize -= maxSize % m_bytesPerFrame;
+ while (wecan && bytesWritten < maxSize) {
+ QAudioRingBuffer::Region region = m_buffer->acquireWriteRegion(maxSize - bytesWritten);
+
+ if (region.second > 0) {
+ memcpy(region.first, data + bytesWritten, region.second);
+ bytesWritten += region.second;
+ }
+ else
+ wecan = false;
+
+ m_buffer->releaseWriteRegion(region);
+ }
+
+ if (bytesWritten > 0)
+ emit readyRead();
+
+ return bytesWritten;
+ }
+
+ int available() const
+ {
+ return m_buffer->free();
+ }
+
+ void reset()
+ {
+ m_buffer->reset();
+ m_deviceError = false;
+ }
+
+ void setPrefetchDevice(QIODevice* device)
+ {
+ if (m_device != device) {
+ m_device = device;
+ if (m_device != 0)
+ fillBuffer();
+ }
+ }
+
+ void startFillTimer()
+ {
+ if (m_device != 0)
+ m_fillTimer->start(m_buffer->size() / 2 / m_maxPeriodSize * m_periodTime);
+ }
+
+ void stopFillTimer()
+ {
+ m_fillTimer->stop();
+ }
+
+signals:
+ void readyRead();
+
+private slots:
+ void fillBuffer()
+ {
+ const int free = m_buffer->free();
+ const int writeSize = free - (free % m_maxPeriodSize);
+
+ if (writeSize > 0) {
+ bool wecan = true;
+ int filled = 0;
+
+ while (!m_deviceError && wecan && filled < writeSize) {
+ QAudioRingBuffer::Region region = m_buffer->acquireWriteRegion(writeSize - filled);
+
+ if (region.second > 0) {
+ region.second = m_device->read(region.first, region.second);
+ if (region.second > 0)
+ filled += region.second;
+ else if (region.second == 0)
+ wecan = false;
+ else if (region.second < 0) {
+ m_fillTimer->stop();
+ region.second = 0;
+ m_deviceError = true;
+ }
+ }
+ else
+ wecan = false;
+
+ m_buffer->releaseWriteRegion(region);
+ }
+
+ if (filled > 0)
+ emit readyRead();
+ }
+ }
+
+private:
+ bool m_deviceError;
+ int m_maxPeriodSize;
+ int m_bytesPerFrame;
+ int m_periodTime;
+ QIODevice* m_device;
+ QTimer* m_fillTimer;
+ QAudioRingBuffer* m_buffer;
+};
+
+
+}
+
+class MacOutputDevice : public QIODevice
+{
+ Q_OBJECT
+
+public:
+ MacOutputDevice(QAudioOutputBuffer* audioBuffer, QObject* parent):
+ QIODevice(parent),
+ m_audioBuffer(audioBuffer)
+ {
+ open(QIODevice::WriteOnly | QIODevice::Unbuffered);
+ }
+
+ qint64 readData(char* data, qint64 len)
+ {
+ Q_UNUSED(data);
+ Q_UNUSED(len);
+
+ return 0;
+ }
+
+ qint64 writeData(const char* data, qint64 len)
+ {
+ return m_audioBuffer->writeBytes(data, len);
+ }
+
+ bool isSequential() const
+ {
+ return true;
+ }
+
+private:
+ QAudioOutputBuffer* m_audioBuffer;
+};
+
+
+QAudioOutputPrivate::QAudioOutputPrivate(const QByteArray& device, const QAudioFormat& format):
+ audioFormat(format)
+{
+ QDataStream ds(device);
+ quint32 did, mode;
+
+ ds >> did >> mode;
+
+ if (QAudio::Mode(mode) == QAudio::AudioInput)
+ errorCode = QAudio::OpenError;
+ else {
+ isOpen = false;
+ audioDeviceId = AudioDeviceID(did);
+ audioUnit = 0;
+ audioIO = 0;
+ startTime = 0;
+ totalFrames = 0;
+ audioBuffer = 0;
+ internalBufferSize = default_buffer_size;
+ clockFrequency = AudioGetHostClockFrequency() / 1000;
+ errorCode = QAudio::NoError;
+ stateCode = QAudio::StopState;
+ audioThreadState = Stopped;
+
+ intervalTimer = new QTimer(this);
+ intervalTimer->setInterval(1000);
+ connect(intervalTimer, SIGNAL(timeout()), SIGNAL(notify()));
+ }
+}
+
+QAudioOutputPrivate::~QAudioOutputPrivate()
+{
+ close();
+}
+
+bool QAudioOutputPrivate::open()
+{
+ if (errorCode != QAudio::NoError)
+ return false;
+
+ if (isOpen)
+ return true;
+
+ ComponentDescription cd;
+ cd.componentType = kAudioUnitType_Output;
+ cd.componentSubType = kAudioUnitSubType_HALOutput;
+ cd.componentManufacturer = kAudioUnitManufacturer_Apple;
+ cd.componentFlags = 0;
+ cd.componentFlagsMask = 0;
+
+ // Open
+ Component cp = FindNextComponent(NULL, &cd);
+ if (cp == 0) {
+ qWarning() << "QAudioOutput: Failed to find HAL Output component";
+ return false;
+ }
+
+ if (OpenAComponent(cp, &audioUnit) != noErr) {
+ qWarning() << "QAudioOutput: Unable to Open Output Component";
+ return false;
+ }
+
+ // register callback
+ AURenderCallbackStruct cb;
+ cb.inputProc = renderCallback;
+ cb.inputProcRefCon = this;
+
+ if (AudioUnitSetProperty(audioUnit,
+ kAudioUnitProperty_SetRenderCallback,
+ kAudioUnitScope_Global,
+ 0,
+ &cb,
+ sizeof(cb)) != noErr) {
+ qWarning() << "QAudioOutput: Failed to set AudioUnit callback";
+ return false;
+ }
+
+ // Set Audio Device
+ if (AudioUnitSetProperty(audioUnit,
+ kAudioOutputUnitProperty_CurrentDevice,
+ kAudioUnitScope_Global,
+ 0,
+ &audioDeviceId,
+ sizeof(audioDeviceId)) != noErr) {
+ qWarning() << "QAudioOutput: Unable to use configured device";
+ return false;
+ }
+
+ // Set stream format
+ streamFormat = toAudioStreamBasicDescription(audioFormat);
+
+ UInt32 size = sizeof(deviceFormat);
+ if (AudioUnitGetProperty(audioUnit,
+ kAudioUnitProperty_StreamFormat,
+ kAudioUnitScope_Input,
+ 0,
+ &deviceFormat,
+ &size) != noErr) {
+ qWarning() << "QAudioOutput: Unable to retrieve device format";
+ return false;
+ }
+
+ if (AudioUnitSetProperty(audioUnit,
+ kAudioUnitProperty_StreamFormat,
+ kAudioUnitScope_Input,
+ 0,
+ &streamFormat,
+ sizeof(streamFormat)) != noErr) {
+ qWarning() << "QAudioOutput: Unable to Set Stream information";
+ return false;
+ }
+
+ // Allocate buffer
+ UInt32 numberOfFrames = 0;
+ size = sizeof(UInt32);
+ if (AudioUnitGetProperty(audioUnit,
+ kAudioDevicePropertyBufferFrameSize,
+ kAudioUnitScope_Global,
+ 0,
+ &numberOfFrames,
+ &size) != noErr) {
+ qWarning() << "QAudioInput: Failed to get audio period size";
+ return false;
+ }
+
+ periodSizeBytes = (numberOfFrames * streamFormat.mSampleRate / deviceFormat.mSampleRate) *
+ streamFormat.mBytesPerFrame;
+ if (internalBufferSize < periodSizeBytes * 2)
+ internalBufferSize = periodSizeBytes * 2;
+ else
+ internalBufferSize -= internalBufferSize % streamFormat.mBytesPerFrame;
+
+ audioBuffer = new QAudioOutputBuffer(internalBufferSize, periodSizeBytes, audioFormat);
+ connect(audioBuffer, SIGNAL(readyRead()), SLOT(inputReady())); // Pull
+
+ audioIO = new MacOutputDevice(audioBuffer, this);
+
+ // Init
+ if (AudioUnitInitialize(audioUnit)) {
+ qWarning() << "QAudioOutput: Failed to initialize AudioUnit";
+ return false;
+ }
+
+ isOpen = true;
+
+ return true;
+}
+
+void QAudioOutputPrivate::close()
+{
+ if (audioUnit != 0) {
+ AudioOutputUnitStop(audioUnit);
+ AudioUnitUninitialize(audioUnit);
+ CloseComponent(audioUnit);
+ }
+
+ delete audioBuffer;
+}
+
+QAudioFormat QAudioOutputPrivate::format() const
+{
+ return audioFormat;
+}
+
+QIODevice* QAudioOutputPrivate::start(QIODevice* device)
+{
+ QIODevice* op = device;
+
+ if (!open()) {
+ stateCode = QAudio::StopState;
+ errorCode = QAudio::OpenError;
+ return audioIO;
+ }
+
+ reset();
+ audioBuffer->reset();
+ audioBuffer->setPrefetchDevice(op);
+
+ if (op == 0) {
+ op = audioIO;
+ stateCode = QAudio::IdleState;
+ }
+ else
+ stateCode = QAudio::ActiveState;
+
+ // Start
+ errorCode = QAudio::NoError;
+ totalFrames = 0;
+ startTime = AudioGetCurrentHostTime();
+
+ if (stateCode == QAudio::ActiveState)
+ audioThreadStart();
+
+ return op;
+}
+
+void QAudioOutputPrivate::stop()
+{
+ QMutexLocker lock(&mutex);
+ if (stateCode != QAudio::StopState) {
+ audioThreadDrain();
+
+ stateCode = QAudio::StopState;
+ errorCode = QAudio::NoError;
+ QMetaObject::invokeMethod(this, "stateChanged", Qt::QueuedConnection, Q_ARG(QAudio::State, stateCode));
+ }
+}
+
+void QAudioOutputPrivate::reset()
+{
+ QMutexLocker lock(&mutex);
+ if (stateCode != QAudio::StopState) {
+ audioThreadStop();
+
+ stateCode = QAudio::StopState;
+ errorCode = QAudio::NoError;
+ QMetaObject::invokeMethod(this, "stateChanged", Qt::QueuedConnection, Q_ARG(QAudio::State, stateCode));
+ }
+}
+
+void QAudioOutputPrivate::suspend()
+{
+ QMutexLocker lock(&mutex);
+ if (stateCode == QAudio::ActiveState || stateCode == QAudio::IdleState) {
+ audioThreadStop();
+
+ stateCode = QAudio::SuspendState;
+ errorCode = QAudio::NoError;
+ QMetaObject::invokeMethod(this, "stateChanged", Qt::QueuedConnection, Q_ARG(QAudio::State, stateCode));
+ }
+}
+
+void QAudioOutputPrivate::resume()
+{
+ QMutexLocker lock(&mutex);
+ if (stateCode == QAudio::SuspendState) {
+ audioThreadStart();
+
+ stateCode = QAudio::ActiveState;
+ errorCode = QAudio::NoError;
+ QMetaObject::invokeMethod(this, "stateChanged", Qt::QueuedConnection, Q_ARG(QAudio::State, stateCode));
+ }
+}
+
+int QAudioOutputPrivate::bytesFree() const
+{
+ return audioBuffer->available();
+}
+
+int QAudioOutputPrivate::periodSize() const
+{
+ return periodSizeBytes;
+}
+
+void QAudioOutputPrivate::setBufferSize(int bs)
+{
+ if (stateCode == QAudio::StopState)
+ internalBufferSize = bs;
+}
+
+int QAudioOutputPrivate::bufferSize() const
+{
+ return internalBufferSize;
+}
+
+void QAudioOutputPrivate::setNotifyInterval(int milliSeconds)
+{
+ intervalTimer->setInterval(milliSeconds);
+}
+
+int QAudioOutputPrivate::notifyInterval() const
+{
+ return intervalTimer->interval();
+}
+
+qint64 QAudioOutputPrivate::totalTime() const
+{
+ return totalFrames * 1000000 / audioFormat.frequency();
+}
+
+qint64 QAudioOutputPrivate::clock() const
+{
+ return (AudioGetCurrentHostTime() - startTime) / (clockFrequency / 1000);
+}
+
+QAudio::Error QAudioOutputPrivate::error() const
+{
+ return errorCode;
+}
+
+QAudio::State QAudioOutputPrivate::state() const
+{
+ return stateCode;
+}
+
+void QAudioOutputPrivate::audioThreadStart()
+{
+ startTimers();
+ audioThreadState = Running;
+ AudioOutputUnitStart(audioUnit);
+}
+
+void QAudioOutputPrivate::audioThreadStop()
+{
+ stopTimers();
+ if (audioThreadState.testAndSetAcquire(Running, Stopped))
+ threadFinished.wait(&mutex);
+}
+
+void QAudioOutputPrivate::audioThreadDrain()
+{
+ stopTimers();
+ if (audioThreadState.testAndSetAcquire(Running, Draining))
+ threadFinished.wait(&mutex);
+}
+
+void QAudioOutputPrivate::audioDeviceStop()
+{
+ AudioOutputUnitStop(audioUnit);
+ audioThreadState = Stopped;
+ threadFinished.wakeOne();
+}
+
+void QAudioOutputPrivate::audioDeviceIdle()
+{
+ QMutexLocker lock(&mutex);
+ if (stateCode == QAudio::ActiveState) {
+ audioDeviceStop();
+
+ errorCode = QAudio::UnderrunError;
+ stateCode = QAudio::IdleState;
+ QMetaObject::invokeMethod(this, "deviceStopped", Qt::QueuedConnection);
+ }
+}
+
+void QAudioOutputPrivate::audioDeviceError()
+{
+ QMutexLocker lock(&mutex);
+ if (stateCode == QAudio::ActiveState) {
+ audioDeviceStop();
+
+ errorCode = QAudio::IOError;
+ stateCode = QAudio::StopState;
+ QMetaObject::invokeMethod(this, "deviceStopped", Qt::QueuedConnection);
+ }
+}
+
+void QAudioOutputPrivate::startTimers()
+{
+ audioBuffer->startFillTimer();
+ intervalTimer->start();
+}
+
+void QAudioOutputPrivate::stopTimers()
+{
+ audioBuffer->stopFillTimer();
+ intervalTimer->stop();
+}
+
+
+void QAudioOutputPrivate::deviceStopped()
+{
+ intervalTimer->stop();
+ emit stateChanged(stateCode);
+}
+
+void QAudioOutputPrivate::inputReady()
+{
+ QMutexLocker lock(&mutex);
+ if (stateCode == QAudio::IdleState) {
+ audioThreadStart();
+
+ stateCode = QAudio::ActiveState;
+ errorCode = QAudio::NoError;
+
+ QMetaObject::invokeMethod(this, "stateChanged", Qt::QueuedConnection, Q_ARG(QAudio::State, stateCode));
+ }
+}
+
+
+OSStatus QAudioOutputPrivate::renderCallback(void* inRefCon,
+ AudioUnitRenderActionFlags* ioActionFlags,
+ const AudioTimeStamp* inTimeStamp,
+ UInt32 inBusNumber,
+ UInt32 inNumberFrames,
+ AudioBufferList* ioData)
+{
+ Q_UNUSED(ioActionFlags)
+ Q_UNUSED(inTimeStamp)
+ Q_UNUSED(inBusNumber)
+ Q_UNUSED(inNumberFrames)
+
+ QAudioOutputPrivate* d = static_cast<QAudioOutputPrivate*>(inRefCon);
+
+ const int threadState = d->audioThreadState.fetchAndAddAcquire(0);
+ if (threadState == Stopped) {
+ ioData->mBuffers[0].mDataByteSize = 0;
+ d->audioDeviceStop();
+ }
+ else {
+ const UInt32 bytesPerFrame = d->streamFormat.mBytesPerFrame;
+ qint64 framesRead;
+
+ framesRead = d->audioBuffer->readFrames((char*)ioData->mBuffers[0].mData,
+ ioData->mBuffers[0].mDataByteSize / bytesPerFrame);
+
+ if (framesRead > 0) {
+ ioData->mBuffers[0].mDataByteSize = framesRead * bytesPerFrame;
+ d->totalFrames += framesRead;
+ }
+ else {
+ ioData->mBuffers[0].mDataByteSize = 0;
+ if (framesRead == 0) {
+ if (threadState == Draining)
+ d->audioDeviceStop();
+ else
+ d->audioDeviceIdle();
+ }
+ else
+ d->audioDeviceError();
+ }
+ }
+
+ return noErr;
+}
+
+
+QT_END_NAMESPACE
+
+#include "qaudiooutput_mac_p.moc"
+
diff --git a/src/multimedia/audio/qaudiooutput_mac_p.h b/src/multimedia/audio/qaudiooutput_mac_p.h
new file mode 100644
index 0000000..c85cab4
--- /dev/null
+++ b/src/multimedia/audio/qaudiooutput_mac_p.h
@@ -0,0 +1,171 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtMultimedia module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the either Technology Preview License Agreement or the
+** Beta Release License Agreement.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain
+** additional rights. These rights are described in the Nokia Qt LGPL
+** Exception version 1.0, 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.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at http://www.qtsoftware.com/contact.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists for the convenience
+// of other Qt classes. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
+#ifndef QAUDIOOUTPUT_MAC_P_H
+#define QAUDIOOUTPUT_MAC_P_H
+
+#include <CoreServices/CoreServices.h>
+#include <CoreAudio/CoreAudio.h>
+#include <AudioUnit/AudioUnit.h>
+#include <AudioToolbox/AudioToolbox.h>
+
+#include <QtCore/qobject.h>
+#include <QtCore/qmutex.h>
+#include <QtCore/qwaitcondition.h>
+#include <QtCore/qtimer.h>
+#include <QtCore/qatomic.h>
+
+#include <QtMultimedia/qaudio.h>
+#include <QtMultimedia/qaudioformat.h>
+#include <QtMultimedia/qaudioengine.h>
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+class QIODevice;
+
+namespace
+{
+class QAudioOutputBuffer;
+}
+
+class QAudioOutputPrivate : public QAbstractAudioOutput
+{
+ Q_OBJECT
+
+public:
+ bool isOpen;
+ int internalBufferSize;
+ int periodSizeBytes;
+ qint64 totalFrames;
+ QAudioFormat audioFormat;
+ QIODevice* audioIO;
+ AudioDeviceID audioDeviceId;
+ AudioUnit audioUnit;
+ Float64 clockFrequency;
+ UInt64 startTime;
+ AudioStreamBasicDescription deviceFormat;
+ AudioStreamBasicDescription streamFormat;
+ QAudioOutputBuffer* audioBuffer;
+ QAtomicInt audioThreadState;
+ QWaitCondition threadFinished;
+ QMutex mutex;
+ QTimer* intervalTimer;
+
+ QAudio::Error errorCode;
+ QAudio::State stateCode;
+
+ QAudioOutputPrivate(const QByteArray& device, const QAudioFormat& format);
+ ~QAudioOutputPrivate();
+
+ bool open();
+ void close();
+
+ QAudioFormat format() const;
+
+ QIODevice* start(QIODevice* device);
+ void stop();
+ void reset();
+ void suspend();
+ void resume();
+
+ int bytesFree() const;
+ int periodSize() const;
+
+ void setBufferSize(int value);
+ int bufferSize() const;
+
+ void setNotifyInterval(int milliSeconds);
+ int notifyInterval() const;
+
+ qint64 totalTime() const;
+ qint64 clock() const;
+
+ QAudio::Error error() const;
+ QAudio::State state() const;
+
+ void audioThreadStart();
+ void audioThreadStop();
+ void audioThreadDrain();
+
+ void audioDeviceStop();
+ void audioDeviceIdle();
+ void audioDeviceError();
+
+ void startTimers();
+ void stopTimers();
+
+signals:
+ void stateChanged(QAudio::State);
+ void notify();
+
+private slots:
+ void deviceStopped();
+ void inputReady();
+
+private:
+ enum { Running, Draining, Stopped };
+
+ static OSStatus renderCallback(void* inRefCon,
+ AudioUnitRenderActionFlags* ioActionFlags,
+ const AudioTimeStamp* inTimeStamp,
+ UInt32 inBusNumber,
+ UInt32 inNumberFrames,
+ AudioBufferList* ioData);
+};
+
+QT_END_NAMESPACE
+
+QT_END_HEADER
+
+#endif
diff --git a/src/multimedia/audio/qaudiooutput_win32_p.cpp b/src/multimedia/audio/qaudiooutput_win32_p.cpp
new file mode 100644
index 0000000..f681936
--- /dev/null
+++ b/src/multimedia/audio/qaudiooutput_win32_p.cpp
@@ -0,0 +1,502 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtMultimedia module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the either Technology Preview License Agreement or the
+** Beta Release License Agreement.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain
+** additional rights. These rights are described in the Nokia Qt LGPL
+** Exception version 1.0, 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.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at http://www.qtsoftware.com/contact.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists for the convenience
+// of other Qt classes. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
+#include "qaudiooutput_win32_p.h"
+
+//#define DEBUG_AUDIO 1
+
+QAudioOutputPrivate::QAudioOutputPrivate(const QByteArray &device, const QAudioFormat& audioFormat):
+ settings(audioFormat)
+{
+ bytesAvailable = 0;
+ buffer_size = 0;
+ period_size = 0;
+ m_device = device;
+ totalTimeValue = 0;
+ intervalTime = 1000;
+ audioBuffer = 0;
+ errorState = QAudio::NoError;
+ deviceState = QAudio::StopState;
+ audioSource = 0;
+ pullMode = true;
+ InitializeCriticalSection(&waveOutCriticalSection);
+}
+
+QAudioOutputPrivate::~QAudioOutputPrivate()
+{
+ close();
+ DeleteCriticalSection(&waveOutCriticalSection);
+}
+
+void CALLBACK QAudioOutputPrivate::waveOutProc( HWAVEOUT hWaveOut, UINT uMsg,
+ DWORD dwInstance, DWORD dwParam1, DWORD dwParam2 )
+{
+ Q_UNUSED(dwParam1)
+ Q_UNUSED(dwParam2)
+ Q_UNUSED(hWaveOut)
+
+ QAudioOutputPrivate* qAudio;
+ qAudio = (QAudioOutputPrivate*)(dwInstance);
+ if(!qAudio)
+ return;
+
+ switch(uMsg) {
+ case WOM_OPEN:
+ qAudio->feedback();
+ break;
+ case WOM_CLOSE:
+ return;
+ case WOM_DONE:
+ EnterCriticalSection(&waveOutCriticalSection);
+ qAudio->waveFreeBlockCount++;
+ if(qAudio->waveFreeBlockCount >= qAudio->buffer_size/qAudio->period_size)
+ qAudio->waveFreeBlockCount = qAudio->buffer_size/qAudio->period_size;
+ LeaveCriticalSection(&waveOutCriticalSection);
+ qAudio->feedback();
+ break;
+ default:
+ return;
+ }
+}
+
+WAVEHDR* QAudioOutputPrivate::allocateBlocks(int size, int count)
+{
+ int i;
+ unsigned char* buffer;
+ WAVEHDR* blocks;
+ DWORD totalBufferSize = (size + sizeof(WAVEHDR))*count;
+
+ if((buffer=(unsigned char*)HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,
+ totalBufferSize)) == 0) {
+ qWarning("QAudioOutput: Memory allocation error");
+ return 0;
+ }
+ blocks = (WAVEHDR*)buffer;
+ buffer += sizeof(WAVEHDR)*count;
+ for(i = 0; i < count; i++) {
+ blocks[i].dwBufferLength = size;
+ blocks[i].lpData = (LPSTR)buffer;
+ buffer += size;
+ }
+ return blocks;
+}
+
+void QAudioOutputPrivate::freeBlocks(WAVEHDR* blockArray)
+{
+ HeapFree(GetProcessHeap(), 0, blockArray);
+}
+
+QAudioFormat QAudioOutputPrivate::format() const
+{
+ return settings;
+}
+
+QIODevice* QAudioOutputPrivate::start(QIODevice* device)
+{
+ if(deviceState != QAudio::StopState)
+ close();
+
+ if(!pullMode && audioSource) {
+ delete audioSource;
+ }
+
+ if(device) {
+ //set to pull mode
+ pullMode = true;
+ audioSource = device;
+ deviceState = QAudio::ActiveState;
+ } else {
+ //set to push mode
+ pullMode = false;
+ audioSource = new OutputPrivate(this);
+ audioSource->open(QIODevice::WriteOnly|QIODevice::Unbuffered);
+ deviceState = QAudio::IdleState;
+ }
+
+ if( !open() )
+ return 0;
+
+ emit stateChanged(deviceState);
+
+ return audioSource;
+}
+
+void QAudioOutputPrivate::stop()
+{
+ if(deviceState == QAudio::StopState)
+ return;
+ deviceState = QAudio::StopState;
+ close();
+ if(!pullMode && audioSource) {
+ delete audioSource;
+ audioSource = 0;
+ }
+ emit stateChanged(deviceState);
+}
+
+bool QAudioOutputPrivate::open()
+{
+#ifdef DEBUG_AUDIO
+ QTime now(QTime::currentTime());
+ qDebug()<<now.second()<<"s "<<now.msec()<<"ms :open()";
+#endif
+ if(buffer_size == 0) {
+ // Default buffer size, 200ms, default period size is 40ms
+ buffer_size = settings.frequency()*settings.channels()*(settings.sampleSize()/8)*0.2;
+ period_size = buffer_size/5;
+ } else {
+ period_size = buffer_size/5;
+ }
+ waveBlocks = allocateBlocks(period_size, buffer_size/period_size);
+ waveFreeBlockCount = buffer_size/period_size;
+ waveCurrentBlock = 0;
+
+ if(audioBuffer == 0)
+ audioBuffer = new char[buffer_size];
+
+ timeStamp.restart();
+
+ wfx.nSamplesPerSec = settings.frequency();
+ wfx.wBitsPerSample = settings.sampleSize();
+ wfx.nChannels = settings.channels();
+ wfx.cbSize = 0;
+
+ wfx.wFormatTag = WAVE_FORMAT_PCM;
+ wfx.nBlockAlign = (wfx.wBitsPerSample >> 3) * wfx.nChannels;
+ wfx.nAvgBytesPerSec = wfx.nBlockAlign * wfx.nSamplesPerSec;
+
+ UINT_PTR devId = WAVE_MAPPER;
+
+ WAVEOUTCAPS woc;
+ unsigned long iNumDevs,ii;
+ iNumDevs = waveOutGetNumDevs();
+ for(ii=0;ii<iNumDevs;ii++) {
+ if(waveOutGetDevCaps(ii, &woc, sizeof(WAVEOUTCAPS))
+ == MMSYSERR_NOERROR) {
+ QString tmp;
+ tmp = QString::fromUtf16((const unsigned short*)woc.szPname);
+ if(tmp.compare(tr(m_device)) == 0) {
+ devId = ii;
+ break;
+ }
+ }
+ }
+
+ if(waveOutOpen(&hWaveOut, devId, &wfx,
+ (DWORD_PTR)&waveOutProc,
+ (DWORD_PTR) this,
+ CALLBACK_FUNCTION) != MMSYSERR_NOERROR) {
+ errorState = QAudio::OpenError;
+ deviceState = QAudio::StopState;
+ emit stateChanged(deviceState);
+ qWarning("QAudioOutput: open error");
+ return false;
+ }
+
+ totalTimeValue = 0;
+ timeStampOpened.restart();
+
+ errorState = QAudio::NoError;
+ if(pullMode) {
+ deviceState = QAudio::ActiveState;
+ QTimer::singleShot(10, this, SLOT(feedback()));
+ } else
+ deviceState = QAudio::IdleState;
+
+ return true;
+}
+
+void QAudioOutputPrivate::close()
+{
+ if(deviceState == QAudio::StopState)
+ return;
+
+ deviceState = QAudio::StopState;
+ int delay = (buffer_size-bytesFree())*1000/(settings.frequency()
+ *settings.channels()*(settings.sampleSize()/8));
+ waveOutReset(hWaveOut);
+ Sleep(delay+10);
+
+ freeBlocks(waveBlocks);
+ waveOutClose(hWaveOut);
+ delete [] audioBuffer;
+ audioBuffer = 0;
+ buffer_size = 0;
+}
+
+int QAudioOutputPrivate::bytesFree() const
+{
+ int buf;
+ buf = waveFreeBlockCount*period_size;
+ return buf;
+}
+
+int QAudioOutputPrivate::periodSize() const
+{
+ return period_size;
+}
+
+void QAudioOutputPrivate::setBufferSize(int value)
+{
+ if(deviceState == QAudio::StopState)
+ buffer_size = value;
+}
+
+int QAudioOutputPrivate::bufferSize() const
+{
+ return buffer_size;
+}
+
+void QAudioOutputPrivate::setNotifyInterval(int ms)
+{
+ intervalTime = ms;
+}
+
+int QAudioOutputPrivate::notifyInterval() const
+{
+ return intervalTime;
+}
+
+qint64 QAudioOutputPrivate::totalTime() const
+{
+ return totalTimeValue;
+}
+
+qint64 QAudioOutputPrivate::write( const char *data, qint64 len )
+{
+ // Write out some audio data
+
+ char* p = (char*)data;
+ int l = (int)len;
+
+ WAVEHDR* current;
+ int remain;
+ current = &waveBlocks[waveCurrentBlock];
+ while(l > 0) {
+ if(waveFreeBlockCount==0)
+ break;
+
+ if(current->dwFlags & WHDR_PREPARED)
+ waveOutUnprepareHeader(hWaveOut, current, sizeof(WAVEHDR));
+
+ if(l < period_size)
+ remain = l;
+ else
+ remain = period_size;
+ memcpy(current->lpData, p, remain);
+
+ l -= remain;
+ p += remain;
+ current->dwBufferLength = remain;
+ waveOutPrepareHeader(hWaveOut, current, sizeof(WAVEHDR));
+ waveOutWrite(hWaveOut, current, sizeof(WAVEHDR));
+
+ EnterCriticalSection(&waveOutCriticalSection);
+ waveFreeBlockCount--;
+ LeaveCriticalSection(&waveOutCriticalSection);
+#ifdef DEBUG_AUDIO
+ qDebug("write out l=%d, waveFreeBlockCount=%d",
+ current->dwBufferLength,waveFreeBlockCount);
+#endif
+ totalTimeValue += current->dwBufferLength
+ /(settings.channels()*(settings.sampleSize()/8))
+ *1000000/settings.frequency();;
+ waveCurrentBlock++;
+ waveCurrentBlock %= buffer_size/period_size;
+ current = &waveBlocks[waveCurrentBlock];
+ current->dwUser = 0;
+ }
+ return (len-l);
+}
+
+void QAudioOutputPrivate::resume()
+{
+ if(deviceState == QAudio::SuspendState) {
+ deviceState = QAudio::ActiveState;
+ errorState = QAudio::NoError;
+ waveOutRestart(hWaveOut);
+ QTimer::singleShot(10, this, SLOT(feedback()));
+ emit stateChanged(deviceState);
+ }
+}
+
+void QAudioOutputPrivate::suspend()
+{
+ if(deviceState == QAudio::ActiveState) {
+ waveOutPause(hWaveOut);
+ deviceState = QAudio::SuspendState;
+ errorState = QAudio::NoError;
+ emit stateChanged(deviceState);
+ }
+}
+
+void QAudioOutputPrivate::feedback()
+{
+#ifdef DEBUG_AUDIO
+ QTime now(QTime::currentTime());
+ qDebug()<<now.second()<<"s "<<now.msec()<<"ms :feedback()";
+#endif
+ bytesAvailable = bytesFree();
+
+ if(!(deviceState==QAudio::StopState||deviceState==QAudio::SuspendState)) {
+ if(bytesAvailable >= period_size)
+ QMetaObject::invokeMethod(this, "deviceReady", Qt::QueuedConnection);
+ }
+}
+
+bool QAudioOutputPrivate::deviceReady()
+{
+ if(pullMode) {
+ int i = 0;
+ int chunks = bytesAvailable/period_size;
+#ifdef DEBUG_AUDIO
+ qDebug()<<"deviceReady() avail="<<bytesAvailable<<" bytes, period size="<<period_size<<" bytes";
+ qDebug()<<"deviceReady() no. of chunks that can fit ="<<chunks<<", chunks in bytes ="<<chunks*period_size;
+#endif
+ bool startup = false;
+ if(totalTimeValue == 0)
+ startup = true;
+
+ if(startup)
+ waveOutPause(hWaveOut);
+ int input = period_size*chunks;
+ int l = audioSource->read(audioBuffer,input);
+ if(l > 0) {
+ int out= write(audioBuffer,l);
+ if(out > 0)
+ deviceState = QAudio::ActiveState;
+ if(startup)
+ waveOutRestart(hWaveOut);
+ } else if(l == 0) {
+ bytesAvailable = bytesFree();
+ if(waveFreeBlockCount == buffer_size/period_size) {
+ errorState = QAudio::UnderrunError;
+ deviceState = QAudio::IdleState;
+ emit stateChanged(deviceState);
+ }
+
+ } else if(i < 0) {
+ bytesAvailable = bytesFree();
+ errorState = QAudio::IOError;
+ }
+ }
+ if(deviceState != QAudio::ActiveState)
+ return true;
+
+ if(timeStamp.elapsed() > intervalTime && intervalTime > 50) {
+ emit notify();
+ timeStamp.restart();
+ }
+
+ return true;
+}
+
+qint64 QAudioOutputPrivate::clock() const
+{
+ if(deviceState != QAudio::ActiveState)
+ return 0;
+
+ return timeStampOpened.elapsed();
+}
+
+QAudio::Error QAudioOutputPrivate::error() const
+{
+ return errorState;
+}
+
+QAudio::State QAudioOutputPrivate::state() const
+{
+ return deviceState;
+}
+
+void QAudioOutputPrivate::reset()
+{
+ close();
+}
+
+OutputPrivate::OutputPrivate(QAudioOutputPrivate* audio)
+{
+ audioDevice = qobject_cast<QAudioOutputPrivate*>(audio);
+}
+
+OutputPrivate::~OutputPrivate() {}
+
+qint64 OutputPrivate::readData( char* data, qint64 len)
+{
+ Q_UNUSED(data)
+ Q_UNUSED(len)
+
+ return 0;
+}
+
+qint64 OutputPrivate::writeData(const char* data, qint64 len)
+{
+ int retry = 0;
+ qint64 written = 0;
+
+ if((audioDevice->deviceState == QAudio::ActiveState)
+ ||(audioDevice->deviceState == QAudio::IdleState)) {
+ qint64 l = len;
+ while(written < l) {
+ int chunk = audioDevice->write(data+written,(l-written));
+ if(chunk <= 0)
+ retry++;
+ else
+ written+=chunk;
+
+ if(retry > 10)
+ return written;
+ }
+ audioDevice->deviceState = QAudio::ActiveState;
+ }
+ return written;
+}
diff --git a/src/multimedia/audio/qaudiooutput_win32_p.h b/src/multimedia/audio/qaudiooutput_win32_p.h
new file mode 100644
index 0000000..91f14f5
--- /dev/null
+++ b/src/multimedia/audio/qaudiooutput_win32_p.h
@@ -0,0 +1,154 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtMultimedia module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the either Technology Preview License Agreement or the
+** Beta Release License Agreement.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain
+** additional rights. These rights are described in the Nokia Qt LGPL
+** Exception version 1.0, 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.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at http://www.qtsoftware.com/contact.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists for the convenience
+// of other Qt classes. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
+#ifndef QAUDIOOUTPUTWIN_H
+#define QAUDIOOUTPUTWIN_H
+
+#include <windows.h>
+#include <mmsystem.h>
+
+#include <QtCore/qdebug.h>
+#include <QtCore/qtimer.h>
+#include <QtCore/qstring.h>
+#include <QtCore/qstringlist.h>
+#include <QtCore/qdatetime.h>
+
+#include <QtMultimedia/qaudio.h>
+#include <QtMultimedia/qaudiodeviceinfo.h>
+#include <QtMultimedia/qaudioengine.h>
+
+
+static CRITICAL_SECTION waveOutCriticalSection;
+
+class QAudioOutputPrivate : public QAbstractAudioOutput
+{
+ Q_OBJECT
+public:
+ QAudioOutputPrivate(const QByteArray &device, const QAudioFormat& audioFormat);
+ ~QAudioOutputPrivate();
+
+ qint64 write( const char *data, qint64 len );
+
+ QAudioFormat format() const;
+ QIODevice* start(QIODevice* device = 0);
+ void stop();
+ void reset();
+ void suspend();
+ void resume();
+ int bytesFree() const;
+ int periodSize() const;
+ void setBufferSize(int value);
+ int bufferSize() const;
+ void setNotifyInterval(int milliSeconds);
+ int notifyInterval() const;
+ qint64 totalTime() const;
+ qint64 clock() const;
+ QAudio::Error error() const;
+ QAudio::State state() const;
+
+ QIODevice* audioSource;
+ QAudioFormat settings;
+ QAudio::Error errorState;
+ QAudio::State deviceState;
+
+private slots:
+ void feedback();
+ bool deviceReady();
+
+signals:
+ void stateChanged(QAudio::State);
+ void notify();
+
+private:
+ QByteArray m_device;
+ bool resuming;
+ int bytesAvailable;
+ QTime timeStamp;
+ QTime timeStampOpened;
+ qint32 buffer_size;
+ qint32 period_size;
+ qint64 totalTimeValue;
+ bool pullMode;
+ int intervalTime;
+ static void CALLBACK waveOutProc( HWAVEOUT hWaveOut, UINT uMsg,
+ DWORD dwInstance, DWORD dwParam1, DWORD dwParam2 );
+
+ WAVEHDR* allocateBlocks(int size, int count);
+ void freeBlocks(WAVEHDR* blockArray);
+ bool open();
+ void close();
+
+ WAVEFORMATEX wfx;
+ HWAVEOUT hWaveOut;
+ MMRESULT result;
+ WAVEHDR header;
+ WAVEHDR* waveBlocks;
+ volatile int waveFreeBlockCount;
+ int waveCurrentBlock;
+ char* audioBuffer;
+};
+
+class OutputPrivate : public QIODevice
+{
+ Q_OBJECT
+public:
+ OutputPrivate(QAudioOutputPrivate* audio);
+ ~OutputPrivate();
+
+ qint64 readData( char* data, qint64 len);
+ qint64 writeData(const char* data, qint64 len);
+
+private:
+ QAudioOutputPrivate *audioDevice;
+};
+
+#endif
diff --git a/src/multimedia/multimedia.pro b/src/multimedia/multimedia.pro
new file mode 100644
index 0000000..7d38afa
--- /dev/null
+++ b/src/multimedia/multimedia.pro
@@ -0,0 +1,11 @@
+TARGET = QtMultimedia
+QPRO_PWD = $$PWD
+QT = core
+DEFINES += QT_BUILD_MULTIMEDIA_LIB
+
+win32-msvc*:QMAKE_LIBS += $$QMAKE_LIBS_CORE
+
+unix:QMAKE_PKGCONFIG_REQUIRES = QtCore
+
+include(../qbase.pri)
+include(audio/audio.pri)
diff --git a/src/network/access/qhttpnetworkconnection.cpp b/src/network/access/qhttpnetworkconnection.cpp
index 75ab837..4c52545 100644
--- a/src/network/access/qhttpnetworkconnection.cpp
+++ b/src/network/access/qhttpnetworkconnection.cpp
@@ -87,58 +87,11 @@ QHttpNetworkConnectionPrivate::~QHttpNetworkConnectionPrivate()
delete []channels;
}
-void QHttpNetworkConnectionPrivate::connectSignals(QAbstractSocket *socket)
-{
- Q_Q(QHttpNetworkConnection);
-
- QObject::connect(socket, SIGNAL(bytesWritten(qint64)),
- q, SLOT(_q_bytesWritten(qint64)),
- Qt::DirectConnection);
- QObject::connect(socket, SIGNAL(connected()),
- q, SLOT(_q_connected()),
- Qt::DirectConnection);
- QObject::connect(socket, SIGNAL(readyRead()),
- q, SLOT(_q_readyRead()),
- Qt::DirectConnection);
- QObject::connect(socket, SIGNAL(disconnected()),
- q, SLOT(_q_disconnected()),
- Qt::DirectConnection);
- QObject::connect(socket, SIGNAL(error(QAbstractSocket::SocketError)),
- q, SLOT(_q_error(QAbstractSocket::SocketError)),
- Qt::DirectConnection);
-#ifndef QT_NO_NETWORKPROXY
- QObject::connect(socket, SIGNAL(proxyAuthenticationRequired(const QNetworkProxy&, QAuthenticator*)),
- q, SLOT(_q_proxyAuthenticationRequired(const QNetworkProxy&, QAuthenticator*)),
- Qt::DirectConnection);
-#endif
-
-#ifndef QT_NO_OPENSSL
- QSslSocket *sslSocket = qobject_cast<QSslSocket*>(socket);
- if (sslSocket) {
- // won't be a sslSocket if encrypt is false
- QObject::connect(sslSocket, SIGNAL(encrypted()),
- q, SLOT(_q_encrypted()),
- Qt::DirectConnection);
- QObject::connect(sslSocket, SIGNAL(sslErrors(const QList<QSslError>&)),
- q, SLOT(_q_sslErrors(const QList<QSslError>&)),
- Qt::DirectConnection);
- }
-#endif
-}
-
void QHttpNetworkConnectionPrivate::init()
{
- for (int i = 0; i < channelCount; ++i) {
-#ifndef QT_NO_OPENSSL
- if (encrypt)
- channels[i].socket = new QSslSocket;
- else
- channels[i].socket = new QTcpSocket;
-#else
- channels[i].socket = new QTcpSocket;
-#endif
-
- connectSignals(channels[i].socket);
+ for (int i = 0; i < channelCount; i++) {
+ channels[i].setConnection(this->q_func());
+ channels[i].init();
}
}
@@ -176,35 +129,6 @@ bool QHttpNetworkConnectionPrivate::isSocketReading(QAbstractSocket *socket) con
return (i != -1 && (channels[i].state & QHttpNetworkConnectionChannel::ReadingState));
}
-void QHttpNetworkConnectionPrivate::appendUncompressedData(QHttpNetworkReply &reply, QByteArray &qba)
-{
- reply.d_func()->responseData.append(qba);
-
- // clear the original! helps with implicit sharing and
- // avoiding memcpy when the user is reading the data
- qba.clear();
-}
-
-void QHttpNetworkConnectionPrivate::appendUncompressedData(QHttpNetworkReply &reply, QByteDataBuffer &data)
-{
- reply.d_func()->responseData.append(data);
-
- // clear the original! helps with implicit sharing and
- // avoiding memcpy when the user is reading the data
- data.clear();
-}
-
-void QHttpNetworkConnectionPrivate::appendCompressedData(QHttpNetworkReply &reply, QByteDataBuffer &data)
-{
- // Work in progress: Later we will directly use a list of QByteArray or a QRingBuffer
- // instead of one QByteArray.
- for(int i = 0; i < data.bufferCount(); i++) {
- QByteArray &byteData = data[i];
- reply.d_func()->compressedData.append(byteData.constData(), byteData.size());
- }
- data.clear();
-}
-
qint64 QHttpNetworkConnectionPrivate::uncompressedBytesAvailable(const QHttpNetworkReply &reply) const
{
return reply.d_func()->responseData.byteAmount();
@@ -406,7 +330,7 @@ bool QHttpNetworkConnectionPrivate::sendRequest(QAbstractSocket *socket)
QNonContiguousByteDevice* uploadByteDevice = channels[i].request.uploadByteDevice();
if (uploadByteDevice) {
// connect the signals so this function gets called again
- QObject::connect(uploadByteDevice, SIGNAL(readyRead()), q, SLOT(_q_uploadDataReadyRead()));
+ QObject::connect(uploadByteDevice, SIGNAL(readyRead()), &channels[i], SLOT(_q_uploadDataReadyRead()));
channels[i].bytesTotal = channels[i].request.contentLength();
} else {
@@ -485,7 +409,7 @@ bool QHttpNetworkConnectionPrivate::sendRequest(QAbstractSocket *socket)
{
QNonContiguousByteDevice* uploadByteDevice = channels[i].request.uploadByteDevice();
if (uploadByteDevice) {
- QObject::disconnect(uploadByteDevice, SIGNAL(readyRead()), q, SLOT(_q_uploadDataReadyRead()));
+ QObject::disconnect(uploadByteDevice, SIGNAL(readyRead()), &channels[i], SLOT(_q_uploadDataReadyRead()));
}
// ensure we try to receive a reply in all cases, even if _q_readyRead_ hat not been called
// this is needed if the sends an reply before we have finished sending the request. In that
@@ -564,7 +488,7 @@ bool QHttpNetworkConnectionPrivate::expand(QAbstractSocket *socket, QHttpNetwork
if (ret >= retCheck) {
if (inflated.size()) {
reply->d_func()->totalProgress += inflated.size();
- appendUncompressedData(*reply, inflated);
+ reply->d_func()->appendUncompressedReplyData(inflated);
if (shouldEmitSignals(reply)) {
// important: At the point of this readyRead(), inflated must be cleared,
// else implicit sharing will trigger memcpy when the user is reading data!
@@ -685,9 +609,9 @@ void QHttpNetworkConnectionPrivate::receiveReply(QAbstractSocket *socket, QHttpN
bytes = reply->d_func()->readBody(socket, &byteDatas);
if (bytes) {
if (reply->d_func()->autoDecompress)
- appendCompressedData(*reply, byteDatas);
+ reply->d_func()->appendCompressedReplyData(byteDatas);
else
- appendUncompressedData(*reply, byteDatas);
+ reply->d_func()->appendUncompressedReplyData(byteDatas);
if (!reply->d_func()->autoDecompress) {
reply->d_func()->totalProgress += bytes;
@@ -1004,11 +928,7 @@ void QHttpNetworkConnectionPrivate::unqueueAndSendRequest(QAbstractSocket *socke
void QHttpNetworkConnectionPrivate::closeChannel(int channel)
{
- QAbstractSocket *socket = channels[channel].socket;
- socket->blockSignals(true);
- socket->close();
- socket->blockSignals(false);
- channels[channel].state = QHttpNetworkConnectionChannel::IdleState;
+ channels[channel].close();
}
void QHttpNetworkConnectionPrivate::resendCurrentRequest(QAbstractSocket *socket)
@@ -1102,53 +1022,6 @@ void QHttpNetworkConnectionPrivate::removeReply(QHttpNetworkReply *reply)
}
-//private slots
-void QHttpNetworkConnectionPrivate::_q_readyRead()
-{
- Q_Q(QHttpNetworkConnection);
- QAbstractSocket *socket = qobject_cast<QAbstractSocket*>(q->sender());
- if (!socket)
- return; // ### error
- if (isSocketWaiting(socket) || isSocketReading(socket)) {
- int i = indexOf(socket);
- channels[i].state = QHttpNetworkConnectionChannel::ReadingState;
- if (channels[i].reply)
- receiveReply(socket, channels[i].reply);
- }
- // ### error
-}
-
-void QHttpNetworkConnectionPrivate::_q_bytesWritten(qint64 bytes)
-{
- Q_UNUSED(bytes);
- Q_Q(QHttpNetworkConnection);
- QAbstractSocket *socket = qobject_cast<QAbstractSocket*>(q->sender());
- if (!socket)
- return; // ### error
- // bytes have been written to the socket. write even more of them :)
- if (isSocketWriting(socket))
- sendRequest(socket);
- // otherwise we do nothing
-}
-
-void QHttpNetworkConnectionPrivate::_q_disconnected()
-{
- Q_Q(QHttpNetworkConnection);
- QAbstractSocket *socket = qobject_cast<QAbstractSocket*>(q->sender());
- if (!socket)
- return; // ### error
- // read the available data before closing
- int i = indexOf(socket);
- if (isSocketWaiting(socket) || isSocketReading(socket)) {
- channels[i].state = QHttpNetworkConnectionChannel::ReadingState;
- if (channels[i].reply)
- receiveReply(socket, channels[i].reply);
- } else if (channels[i].state == QHttpNetworkConnectionChannel::IdleState && channels[i].resendCurrent) {
- // re-sending request because the socket was in ClosingState
- QMetaObject::invokeMethod(q, "_q_startNextRequest", Qt::QueuedConnection);
- }
- channels[i].state = QHttpNetworkConnectionChannel::IdleState;
-}
void QHttpNetworkConnectionPrivate::_q_startNextRequest()
{
@@ -1188,121 +1061,6 @@ void QHttpNetworkConnectionPrivate::_q_restartAuthPendingRequests()
}
}
-void QHttpNetworkConnectionPrivate::_q_connected()
-{
- Q_Q(QHttpNetworkConnection);
- QAbstractSocket *socket = qobject_cast<QAbstractSocket*>(q->sender());
- if (!socket)
- return; // ### error
-
- // improve performance since we get the request sent by the kernel ASAP
- socket->setSocketOption(QAbstractSocket::LowDelayOption, 1);
-
- int i = indexOf(socket);
- // ### FIXME: if the server closes the connection unexpectedly, we shouldn't send the same broken request again!
- //channels[i].reconnectAttempts = 2;
- if (!channels[i].pendingEncrypt) {
- channels[i].state = QHttpNetworkConnectionChannel::IdleState;
- if (channels[i].reply)
- sendRequest(socket);
- else
- closeChannel(i);
- }
-}
-
-
-void QHttpNetworkConnectionPrivate::_q_error(QAbstractSocket::SocketError socketError)
-{
- Q_Q(QHttpNetworkConnection);
- QAbstractSocket *socket = qobject_cast<QAbstractSocket*>(q->sender());
- if (!socket)
- return;
- bool send2Reply = false;
- int i = indexOf(socket);
- QNetworkReply::NetworkError errorCode = QNetworkReply::UnknownNetworkError;
-
- switch (socketError) {
- case QAbstractSocket::HostNotFoundError:
- errorCode = QNetworkReply::HostNotFoundError;
- break;
- case QAbstractSocket::ConnectionRefusedError:
- errorCode = QNetworkReply::ConnectionRefusedError;
- break;
- case QAbstractSocket::RemoteHostClosedError:
- // try to reconnect/resend before sending an error.
- // while "Reading" the _q_disconnected() will handle this.
- if (channels[i].state != QHttpNetworkConnectionChannel::IdleState && channels[i].state != QHttpNetworkConnectionChannel::ReadingState) {
- if (channels[i].reconnectAttempts-- > 0) {
- resendCurrentRequest(socket);
- return;
- } else {
- send2Reply = true;
- errorCode = QNetworkReply::RemoteHostClosedError;
- }
- } else {
- return;
- }
- break;
- case QAbstractSocket::SocketTimeoutError:
- // try to reconnect/resend before sending an error.
- if (channels[i].state == QHttpNetworkConnectionChannel::WritingState && (channels[i].reconnectAttempts-- > 0)) {
- resendCurrentRequest(socket);
- return;
- }
- send2Reply = true;
- errorCode = QNetworkReply::TimeoutError;
- break;
- case QAbstractSocket::ProxyAuthenticationRequiredError:
- errorCode = QNetworkReply::ProxyAuthenticationRequiredError;
- break;
- case QAbstractSocket::SslHandshakeFailedError:
- errorCode = QNetworkReply::SslHandshakeFailedError;
- break;
- default:
- // all other errors are treated as NetworkError
- errorCode = QNetworkReply::UnknownNetworkError;
- break;
- }
- QPointer<QObject> that = q;
- QString errorString = errorDetail(errorCode, socket);
- if (send2Reply) {
- if (channels[i].reply) {
- channels[i].reply->d_func()->errorString = errorString;
- // this error matters only to this reply
- emit channels[i].reply->finishedWithError(errorCode, errorString);
- }
- // send the next request
- QMetaObject::invokeMethod(that, "_q_startNextRequest", Qt::QueuedConnection);
- } else {
- // the failure affects all requests.
- emit q->error(errorCode, errorString);
- }
- if (that) //signals make enter the event loop
- closeChannel(i);
-}
-
-#ifndef QT_NO_NETWORKPROXY
-void QHttpNetworkConnectionPrivate::_q_proxyAuthenticationRequired(const QNetworkProxy &proxy, QAuthenticator* auth)
-{
- Q_Q(QHttpNetworkConnection);
- emit q->proxyAuthenticationRequired(proxy, auth, q);
-}
-#endif
-
-void QHttpNetworkConnectionPrivate::_q_uploadDataReadyRead()
-{
- Q_Q(QHttpNetworkConnection);
- // upload data emitted readyRead()
- // find out which channel it is for
- QObject *sender = q->sender();
-
- for (int i = 0; i < channelCount; ++i) {
- if (sender == channels[i].request.uploadByteDevice()) {
- sendRequest(channels[i].socket);
- break;
- }
- }
-}
QHttpNetworkConnection::QHttpNetworkConnection(const QString &hostName, quint16 port, bool encrypt, QObject *parent)
: QObject(*(new QHttpNetworkConnectionPrivate(hostName, port, encrypt)), parent)
@@ -1397,27 +1155,6 @@ QNetworkProxy QHttpNetworkConnection::transparentProxy() const
// SSL support below
#ifndef QT_NO_OPENSSL
-void QHttpNetworkConnectionPrivate::_q_encrypted()
-{
- Q_Q(QHttpNetworkConnection);
- QAbstractSocket *socket = qobject_cast<QAbstractSocket*>(q->sender());
- if (!socket)
- return; // ### error
- int i = indexOf(socket);
- channels[i].state = QHttpNetworkConnectionChannel::IdleState;
- sendRequest(socket);
-}
-
-void QHttpNetworkConnectionPrivate::_q_sslErrors(const QList<QSslError> &errors)
-{
- Q_Q(QHttpNetworkConnection);
- QAbstractSocket *socket = qobject_cast<QAbstractSocket*>(q->sender());
- if (!socket)
- return;
- //QNetworkReply::NetworkError errorCode = QNetworkReply::ProtocolFailure;
- emit q->sslErrors(errors);
-}
-
QSslConfiguration QHttpNetworkConnectionPrivate::sslConfiguration(const QHttpNetworkReply &reply) const
{
if (!encrypt)
diff --git a/src/network/access/qhttpnetworkconnection_p.h b/src/network/access/qhttpnetworkconnection_p.h
index db6a140..d6b0325 100644
--- a/src/network/access/qhttpnetworkconnection_p.h
+++ b/src/network/access/qhttpnetworkconnection_p.h
@@ -138,23 +138,10 @@ private:
Q_DECLARE_PRIVATE(QHttpNetworkConnection)
Q_DISABLE_COPY(QHttpNetworkConnection)
friend class QHttpNetworkReply;
+ friend class QHttpNetworkConnectionChannel;
- Q_PRIVATE_SLOT(d_func(), void _q_bytesWritten(qint64))
- Q_PRIVATE_SLOT(d_func(), void _q_readyRead())
- Q_PRIVATE_SLOT(d_func(), void _q_disconnected())
Q_PRIVATE_SLOT(d_func(), void _q_startNextRequest())
Q_PRIVATE_SLOT(d_func(), void _q_restartAuthPendingRequests())
- Q_PRIVATE_SLOT(d_func(), void _q_connected())
- Q_PRIVATE_SLOT(d_func(), void _q_error(QAbstractSocket::SocketError))
-#ifndef QT_NO_NETWORKPROXY
- Q_PRIVATE_SLOT(d_func(), void _q_proxyAuthenticationRequired(const QNetworkProxy&, QAuthenticator*))
-#endif
- Q_PRIVATE_SLOT(d_func(), void _q_uploadDataReadyRead())
-
-#ifndef QT_NO_OPENSSL
- Q_PRIVATE_SLOT(d_func(), void _q_encrypted())
- Q_PRIVATE_SLOT(d_func(), void _q_sslErrors(const QList<QSslError>&))
-#endif
};
@@ -169,7 +156,6 @@ public:
QHttpNetworkConnectionPrivate(const QString &hostName, quint16 port, bool encrypt);
~QHttpNetworkConnectionPrivate();
void init();
- void connectSignals(QAbstractSocket *socket);
enum { ChunkSize = 4096 };
@@ -189,18 +175,8 @@ public:
void copyCredentials(int fromChannel, QAuthenticator *auth, bool isProxy);
// private slots
- void _q_bytesWritten(qint64 bytes); // proceed sending
- void _q_readyRead(); // pending data to read
- void _q_disconnected(); // disconnected from host
void _q_startNextRequest(); // send the next request from the queue
void _q_restartAuthPendingRequests(); // send the currently blocked request
- void _q_connected(); // start sending request
- void _q_error(QAbstractSocket::SocketError); // error from socket
-#ifndef QT_NO_NETWORKPROXY
- void _q_proxyAuthenticationRequired(const QNetworkProxy &proxy, QAuthenticator *auth); // from transparent proxy
-#endif
-
- void _q_uploadDataReadyRead();
void createAuthorization(QAbstractSocket *socket, QHttpNetworkRequest &request);
bool ensureConnection(QAbstractSocket *socket);
@@ -221,10 +197,6 @@ public:
bool pendingAuthSignal; // there is an incomplete authentication signal
bool pendingProxyAuthSignal; // there is an incomplete proxy authentication signal
- void appendUncompressedData(QHttpNetworkReply &reply, QByteArray &qba);
- void appendUncompressedData(QHttpNetworkReply &reply, QByteDataBuffer &data);
- void appendCompressedData(QHttpNetworkReply &reply, QByteDataBuffer &data);
-
qint64 uncompressedBytesAvailable(const QHttpNetworkReply &reply) const;
qint64 uncompressedBytesAvailableNextBlock(const QHttpNetworkReply &reply) const;
qint64 compressedBytesAvailable(const QHttpNetworkReply &reply) const;
@@ -237,8 +209,6 @@ public:
inline bool expectContent(QHttpNetworkReply *reply);
#ifndef QT_NO_OPENSSL
- void _q_encrypted(); // start sending request (https)
- void _q_sslErrors(const QList<QSslError> &errors); // ssl errors from the socket
QSslConfiguration sslConfiguration(const QHttpNetworkReply &reply) const;
#endif
@@ -249,6 +219,8 @@ public:
//The request queues
QList<HttpMessagePair> highPriorityQueue;
QList<HttpMessagePair> lowPriorityQueue;
+
+ friend class QHttpNetworkConnectionChannel;
};
diff --git a/src/network/access/qhttpnetworkconnectionchannel.cpp b/src/network/access/qhttpnetworkconnectionchannel.cpp
index a04b530..6cd46fd 100644
--- a/src/network/access/qhttpnetworkconnectionchannel.cpp
+++ b/src/network/access/qhttpnetworkconnectionchannel.cpp
@@ -57,6 +57,220 @@ QT_BEGIN_NAMESPACE
// TODO: Put channel specific stuff here so it does not polute qhttpnetworkconnection.cpp
+void QHttpNetworkConnectionChannel::init()
+{
+#ifndef QT_NO_OPENSSL
+ if (connection->d_func()->encrypt)
+ socket = new QSslSocket;
+ else
+ socket = new QTcpSocket;
+#else
+ socket = new QTcpSocket;
+#endif
+
+ QObject::connect(socket, SIGNAL(bytesWritten(qint64)),
+ this, SLOT(_q_bytesWritten(qint64)),
+ Qt::DirectConnection);
+ QObject::connect(socket, SIGNAL(connected()),
+ this, SLOT(_q_connected()),
+ Qt::DirectConnection);
+ QObject::connect(socket, SIGNAL(readyRead()),
+ this, SLOT(_q_readyRead()),
+ Qt::DirectConnection);
+ QObject::connect(socket, SIGNAL(disconnected()),
+ this, SLOT(_q_disconnected()),
+ Qt::DirectConnection);
+ QObject::connect(socket, SIGNAL(error(QAbstractSocket::SocketError)),
+ this, SLOT(_q_error(QAbstractSocket::SocketError)),
+ Qt::DirectConnection);
+#ifndef QT_NO_NETWORKPROXY
+ QObject::connect(socket, SIGNAL(proxyAuthenticationRequired(const QNetworkProxy&, QAuthenticator*)),
+ this, SLOT(_q_proxyAuthenticationRequired(const QNetworkProxy&, QAuthenticator*)),
+ Qt::DirectConnection);
+#endif
+
+#ifndef QT_NO_OPENSSL
+ QSslSocket *sslSocket = qobject_cast<QSslSocket*>(socket);
+ if (sslSocket) {
+ // won't be a sslSocket if encrypt is false
+ QObject::connect(sslSocket, SIGNAL(encrypted()),
+ this, SLOT(_q_encrypted()),
+ Qt::DirectConnection);
+ QObject::connect(sslSocket, SIGNAL(sslErrors(const QList<QSslError>&)),
+ this, SLOT(_q_sslErrors(const QList<QSslError>&)),
+ Qt::DirectConnection);
+ }
+#endif
+}
+
+
+void QHttpNetworkConnectionChannel::close()
+{
+ socket->blockSignals(true);
+ socket->close();
+ socket->blockSignals(false);
+ state = QHttpNetworkConnectionChannel::IdleState;
+}
+
+
+//private slots
+void QHttpNetworkConnectionChannel::_q_readyRead()
+{
+ if (!socket)
+ return; // ### error
+ if (connection->d_func()->isSocketWaiting(socket) || connection->d_func()->isSocketReading(socket)) {
+ state = QHttpNetworkConnectionChannel::ReadingState;
+ if (reply)
+ connection->d_func()->receiveReply(socket, reply);
+ }
+ // ### error
+}
+
+void QHttpNetworkConnectionChannel::_q_bytesWritten(qint64 bytes)
+{
+ Q_UNUSED(bytes);
+ if (!socket)
+ return; // ### error
+ // bytes have been written to the socket. write even more of them :)
+ if (connection->d_func()->isSocketWriting(socket))
+ connection->d_func()->sendRequest(socket);
+ // otherwise we do nothing
+}
+
+void QHttpNetworkConnectionChannel::_q_disconnected()
+{
+ if (!socket)
+ return; // ### error
+ // read the available data before closing
+ if (connection->d_func()->isSocketWaiting(socket) || connection->d_func()->isSocketReading(socket)) {
+ state = QHttpNetworkConnectionChannel::ReadingState;
+ if (reply)
+ connection->d_func()->receiveReply(socket, reply);
+ } else if (state == QHttpNetworkConnectionChannel::IdleState && resendCurrent) {
+ // re-sending request because the socket was in ClosingState
+ QMetaObject::invokeMethod(connection, "_q_startNextRequest", Qt::QueuedConnection);
+ }
+ state = QHttpNetworkConnectionChannel::IdleState;
+}
+
+
+void QHttpNetworkConnectionChannel::_q_connected()
+{
+ if (!socket)
+ return; // ### error
+
+ // improve performance since we get the request sent by the kernel ASAP
+ socket->setSocketOption(QAbstractSocket::LowDelayOption, 1);
+
+ // ### FIXME: if the server closes the connection unexpectedly, we shouldn't send the same broken request again!
+ //channels[i].reconnectAttempts = 2;
+ if (!pendingEncrypt) {
+ state = QHttpNetworkConnectionChannel::IdleState;
+ if (reply)
+ connection->d_func()->sendRequest(socket);
+ else
+ close();
+ }
+}
+
+
+void QHttpNetworkConnectionChannel::_q_error(QAbstractSocket::SocketError socketError)
+{
+ if (!socket)
+ return;
+ bool send2Reply = false;
+ QNetworkReply::NetworkError errorCode = QNetworkReply::UnknownNetworkError;
+
+ switch (socketError) {
+ case QAbstractSocket::HostNotFoundError:
+ errorCode = QNetworkReply::HostNotFoundError;
+ break;
+ case QAbstractSocket::ConnectionRefusedError:
+ errorCode = QNetworkReply::ConnectionRefusedError;
+ break;
+ case QAbstractSocket::RemoteHostClosedError:
+ // try to reconnect/resend before sending an error.
+ // while "Reading" the _q_disconnected() will handle this.
+ if (state != QHttpNetworkConnectionChannel::IdleState && state != QHttpNetworkConnectionChannel::ReadingState) {
+ if (reconnectAttempts-- > 0) {
+ connection->d_func()->resendCurrentRequest(socket);
+ return;
+ } else {
+ send2Reply = true;
+ errorCode = QNetworkReply::RemoteHostClosedError;
+ }
+ } else {
+ return;
+ }
+ break;
+ case QAbstractSocket::SocketTimeoutError:
+ // try to reconnect/resend before sending an error.
+ if (state == QHttpNetworkConnectionChannel::WritingState && (reconnectAttempts-- > 0)) {
+ connection->d_func()->resendCurrentRequest(socket);
+ return;
+ }
+ send2Reply = true;
+ errorCode = QNetworkReply::TimeoutError;
+ break;
+ case QAbstractSocket::ProxyAuthenticationRequiredError:
+ errorCode = QNetworkReply::ProxyAuthenticationRequiredError;
+ break;
+ case QAbstractSocket::SslHandshakeFailedError:
+ errorCode = QNetworkReply::SslHandshakeFailedError;
+ break;
+ default:
+ // all other errors are treated as NetworkError
+ errorCode = QNetworkReply::UnknownNetworkError;
+ break;
+ }
+ QPointer<QObject> that = connection;
+ QString errorString = connection->d_func()->errorDetail(errorCode, socket);
+ if (send2Reply) {
+ if (reply) {
+ reply->d_func()->errorString = errorString;
+ // this error matters only to this reply
+ emit reply->finishedWithError(errorCode, errorString);
+ }
+ // send the next request
+ QMetaObject::invokeMethod(that, "_q_startNextRequest", Qt::QueuedConnection);
+ } else {
+ // the failure affects all requests.
+ emit connection->error(errorCode, errorString);
+ }
+ if (that) //signal emission triggered event loop
+ close();
+}
+
+#ifndef QT_NO_NETWORKPROXY
+void QHttpNetworkConnectionChannel::_q_proxyAuthenticationRequired(const QNetworkProxy &proxy, QAuthenticator* auth)
+{
+ emit connection->proxyAuthenticationRequired(proxy, auth, connection);
+}
+#endif
+
+void QHttpNetworkConnectionChannel::_q_uploadDataReadyRead()
+{
+ connection->d_func()->sendRequest(socket);
+}
+
+#ifndef QT_NO_OPENSSL
+void QHttpNetworkConnectionChannel::_q_encrypted()
+{
+ if (!socket)
+ return; // ### error
+ state = QHttpNetworkConnectionChannel::IdleState;
+ connection->d_func()->sendRequest(socket);
+}
+
+void QHttpNetworkConnectionChannel::_q_sslErrors(const QList<QSslError> &errors)
+{
+ if (!socket)
+ return;
+ //QNetworkReply::NetworkError errorCode = QNetworkReply::ProtocolFailure;
+ emit connection->sslErrors(errors);
+}
+#endif
+
QT_END_NAMESPACE
#include "moc_qhttpnetworkconnectionchannel_p.cpp"
diff --git a/src/network/access/qhttpnetworkconnectionchannel_p.h b/src/network/access/qhttpnetworkconnectionchannel_p.h
index cbabc67..013e7a5 100644
--- a/src/network/access/qhttpnetworkconnectionchannel_p.h
+++ b/src/network/access/qhttpnetworkconnectionchannel_p.h
@@ -80,6 +80,7 @@ QT_BEGIN_NAMESPACE
class QHttpNetworkRequest;
class QHttpNetworkReply;
class QByteArray;
+class QHttpNetworkConnection;
class QHttpNetworkConnectionChannel : public QObject {
Q_OBJECT
@@ -117,7 +118,31 @@ public:
#ifndef QT_NO_OPENSSL
, ignoreAllSslErrors(false)
#endif
+ , connection(0)
{}
+
+ void setConnection(QHttpNetworkConnection *c) {connection = c;}
+ QHttpNetworkConnection *connection;
+
+ void init();
+ void close();
+
+ protected slots:
+ void _q_bytesWritten(qint64 bytes); // proceed sending
+ void _q_readyRead(); // pending data to read
+ void _q_disconnected(); // disconnected from host
+ void _q_connected(); // start sending request
+ void _q_error(QAbstractSocket::SocketError); // error from socket
+#ifndef QT_NO_NETWORKPROXY
+ void _q_proxyAuthenticationRequired(const QNetworkProxy &proxy, QAuthenticator *auth); // from transparent proxy
+#endif
+
+ void _q_uploadDataReadyRead();
+
+#ifndef QT_NO_OPENSSL
+ void _q_encrypted(); // start sending request (https)
+ void _q_sslErrors(const QList<QSslError> &errors); // ssl errors from the socket
+#endif
};
diff --git a/src/network/access/qhttpnetworkreply.cpp b/src/network/access/qhttpnetworkreply.cpp
index a623999..f40f7bf 100644
--- a/src/network/access/qhttpnetworkreply.cpp
+++ b/src/network/access/qhttpnetworkreply.cpp
@@ -687,6 +687,36 @@ qint64 QHttpNetworkReplyPrivate::getChunkSize(QIODevice *in, qint64 *chunkSize)
return bytes;
}
+void QHttpNetworkReplyPrivate::appendUncompressedReplyData(QByteArray &qba)
+{
+ responseData.append(qba);
+
+ // clear the original! helps with implicit sharing and
+ // avoiding memcpy when the user is reading the data
+ qba.clear();
+}
+
+void QHttpNetworkReplyPrivate::appendUncompressedReplyData(QByteDataBuffer &data)
+{
+ responseData.append(data);
+
+ // clear the original! helps with implicit sharing and
+ // avoiding memcpy when the user is reading the data
+ data.clear();
+}
+
+void QHttpNetworkReplyPrivate::appendCompressedReplyData(QByteDataBuffer &data)
+{
+ // Work in progress: Later we will directly use a list of QByteArray or a QRingBuffer
+ // instead of one QByteArray.
+ for(int i = 0; i < data.bufferCount(); i++) {
+ QByteArray &byteData = data[i];
+ compressedData.append(byteData.constData(), byteData.size());
+ }
+ data.clear();
+}
+
+
// SSL support below
#ifndef QT_NO_OPENSSL
diff --git a/src/network/access/qhttpnetworkreply_p.h b/src/network/access/qhttpnetworkreply_p.h
index 575e824..fe49799 100644
--- a/src/network/access/qhttpnetworkreply_p.h
+++ b/src/network/access/qhttpnetworkreply_p.h
@@ -149,6 +149,7 @@ private:
Q_DECLARE_PRIVATE(QHttpNetworkReply)
friend class QHttpNetworkConnection;
friend class QHttpNetworkConnectionPrivate;
+ friend class QHttpNetworkConnectionChannel;
};
@@ -171,6 +172,10 @@ public:
qint64 readReplyBodyChunked(QIODevice *in, QByteDataBuffer *out);
qint64 getChunkSize(QIODevice *in, qint64 *chunkSize);
+ void appendUncompressedReplyData(QByteArray &qba);
+ void appendUncompressedReplyData(QByteDataBuffer &data);
+ void appendCompressedReplyData(QByteDataBuffer &data);
+
qint64 bytesAvailable() const;
bool isChunked();
bool connectionCloseEnabled();
diff --git a/src/network/access/qnetworkaccessmanager.cpp b/src/network/access/qnetworkaccessmanager.cpp
index 61e5601..e1d6634 100644
--- a/src/network/access/qnetworkaccessmanager.cpp
+++ b/src/network/access/qnetworkaccessmanager.cpp
@@ -121,7 +121,9 @@ static void ensureInitialized()
as well as meta-data (headers, etc.).
\note After the request has finished, it is the responsibility of the user
- to delete the QNetworkReply object at an appropriate time.
+ to delete the QNetworkReply object at an appropriate time. Do not directly
+ delete it inside the slot connected to finished(). You can use the
+ deleteLater() function.
A more involved example, assuming the manager is already existent,
can be:
@@ -202,6 +204,9 @@ static void ensureInitialized()
See QNetworkReply::finished() for information on the status that
the object will be in.
+ \note Do not delete the \a reply object in the slot connected to this
+ signal. Use deleteLater().
+
\sa QNetworkReply::finished(), QNetworkReply::error()
*/
diff --git a/src/network/access/qnetworkcookiejar.h b/src/network/access/qnetworkcookiejar.h
index b2cdf12..fae0857 100644
--- a/src/network/access/qnetworkcookiejar.h
+++ b/src/network/access/qnetworkcookiejar.h
@@ -43,6 +43,10 @@
#define QNETWORKCOOKIEJAR_H
#include <QtCore/QObject>
+#include <QtCore/QUrl>
+
+// ### Qt5 remove this include
+#include "qnetworkcookie.h"
QT_BEGIN_HEADER
@@ -50,8 +54,6 @@ QT_BEGIN_NAMESPACE
QT_MODULE(Network)
-class QNetworkCookie;
-
class QNetworkCookieJarPrivate;
class Q_NETWORK_EXPORT QNetworkCookieJar: public QObject
{
diff --git a/src/network/access/qnetworkreply.cpp b/src/network/access/qnetworkreply.cpp
index 3abf927..f6649b6 100644
--- a/src/network/access/qnetworkreply.cpp
+++ b/src/network/access/qnetworkreply.cpp
@@ -87,6 +87,9 @@ QNetworkReplyPrivate::QNetworkReplyPrivate()
indicates the progress of the upload for operations that have such
content.
+ \note Do not delete the object in the slot connected to the
+ error() or finished() signal. Use deleteLater().
+
\sa QNetworkRequest, QNetworkAccessManager
*/
@@ -232,6 +235,9 @@ QNetworkReplyPrivate::QNetworkReplyPrivate()
QNetworkAccessManager::finished() where that signal's reply
parameter is this object.
+ \note Do not delete the object in the slot connected to this
+ signal. Use deleteLater().
+
\sa QNetworkAccessManager::finished()
*/
@@ -246,6 +252,9 @@ QNetworkReplyPrivate::QNetworkReplyPrivate()
detected. Call errorString() to obtain a textual representation of
the error condition.
+ \note Do not delete the object in the slot connected to this
+ signal. Use deleteLater().
+
\sa error(), errorString()
*/
diff --git a/src/network/socket/qnet_unix_p.h b/src/network/socket/qnet_unix_p.h
index f38c2fc..040b3ec 100644
--- a/src/network/socket/qnet_unix_p.h
+++ b/src/network/socket/qnet_unix_p.h
@@ -85,7 +85,7 @@ static inline int qt_safe_socket(int domain, int type, int protocol, int flags =
Q_ASSERT((flags & ~O_NONBLOCK) == 0);
register int fd;
-#ifdef SOCK_CLOEXEC
+#if defined(SOCK_CLOEXEC) && defined(SOCK_NONBLOCK)
int newtype = type | SOCK_CLOEXEC;
if (flags & O_NONBLOCK)
newtype |= SOCK_NONBLOCK;
diff --git a/src/opengl/opengl.pro b/src/opengl/opengl.pro
index c92b8cf..868484e 100644
--- a/src/opengl/opengl.pro
+++ b/src/opengl/opengl.pro
@@ -20,6 +20,7 @@ HEADERS += qgl.h \
qgl_p.h \
qglcolormap.h \
qglpixelbuffer.h \
+ qglpixelbuffer_p.h \
qglframebufferobject.h \
qglextensions_p.h
diff --git a/src/opengl/qgl.cpp b/src/opengl/qgl.cpp
index edda6b6..0631df5 100644
--- a/src/opengl/qgl.cpp
+++ b/src/opengl/qgl.cpp
@@ -86,6 +86,7 @@
#include <private/qpixmapdata_gl_p.h>
#include <private/qglpixelbuffer_p.h>
#include <private/qwindowsurface_gl_p.h>
+#include <private/qimagepixmapcleanuphooks_p.h>
#include "qcolormap.h"
#include "qfile.h"
#include "qlibrary.h"
@@ -526,7 +527,7 @@ void QGLFormat::setAccum(bool enable)
\fn bool QGLFormat::stencil() const
Returns true if the stencil buffer is enabled; otherwise returns
- false. The stencil buffer is disabled by default.
+ false. The stencil buffer is enabled by default.
\sa setStencil(), setStencilBufferSize()
*/
@@ -535,7 +536,7 @@ void QGLFormat::setAccum(bool enable)
If \a enable is true enables the stencil buffer; otherwise
disables the stencil buffer.
- The stencil buffer is disabled by default.
+ The stencil buffer is enabled by default.
The stencil buffer masks certain parts of the drawing area so that
masked parts are not drawn on.
@@ -1407,15 +1408,17 @@ QGLTextureCache::QGLTextureCache()
{
Q_ASSERT(qt_gl_texture_cache == 0);
qt_gl_texture_cache = this;
- qt_pixmap_cleanup_hook_64 = cleanupHook;
- qt_image_cleanup_hook_64 = cleanupHook;
+
+ QImagePixmapCleanupHooks::instance()->addPixmapHook(pixmapCleanupHook);
+ QImagePixmapCleanupHooks::instance()->addImageHook(imageCleanupHook);
}
QGLTextureCache::~QGLTextureCache()
{
qt_gl_texture_cache = 0;
- qt_pixmap_cleanup_hook_64 = 0;
- qt_image_cleanup_hook_64 = 0;
+
+ QImagePixmapCleanupHooks::instance()->removePixmapHook(pixmapCleanupHook);
+ QImagePixmapCleanupHooks::instance()->removeImageHook(imageCleanupHook);
}
void QGLTextureCache::insert(QGLContext* ctx, qint64 key, QGLTexture* texture, int cost)
@@ -1471,7 +1474,7 @@ QGLTextureCache* QGLTextureCache::instance()
a hook that removes textures from the cache when a pixmap/image
is deref'ed
*/
-void QGLTextureCache::cleanupHook(qint64 cacheKey)
+void QGLTextureCache::imageCleanupHook(qint64 cacheKey)
{
// ### remove when the GL texture cache becomes thread-safe
if (qApp->thread() != QThread::currentThread())
@@ -1481,6 +1484,24 @@ void QGLTextureCache::cleanupHook(qint64 cacheKey)
instance()->remove(cacheKey);
}
+
+void QGLTextureCache::pixmapCleanupHook(QPixmap* pixmap)
+{
+ // ### remove when the GL texture cache becomes thread-safe
+ if (qApp->thread() == QThread::currentThread()) {
+ const qint64 cacheKey = pixmap->cacheKey();
+ QGLTexture *texture = instance()->getTexture(cacheKey);
+ if (texture && texture->clean)
+ instance()->remove(cacheKey);
+ }
+#if defined(Q_WS_X11)
+ QPixmapData *pd = pixmap->data_ptr();
+ // Only need to delete the gl surface if the pixmap is about to be deleted
+ if (pd->ref == 0)
+ QGLContextPrivate::destroyGlSurfaceForPixmap(pd);
+#endif
+}
+
void QGLTextureCache::deleteIfEmpty()
{
if (instance()->size() == 0)
@@ -2021,11 +2042,11 @@ QGLTexture *QGLContextPrivate::bindTexture(const QPixmap &pixmap, GLenum target,
#if defined(Q_WS_X11)
// Try to use texture_from_pixmap
if (pd->classId() == QPixmapData::X11Class) {
- QPixmap *thatPixmap = const_cast<QPixmap*>(&pixmap);
- texture = bindTextureFromNativePixmap(thatPixmap, key, canInvert);
+ texture = bindTextureFromNativePixmap(pd, key, canInvert);
if (texture) {
texture->clean = clean;
- boundPixmaps.insert(thatPixmap->data_ptr(), QPixmap(pixmap));
+ texture->boundPixmap = pd;
+ boundPixmaps.insert(pd, QPixmap(pixmap));
}
}
#endif
@@ -4583,7 +4604,7 @@ QGLFormat QGLDrawable::format() const
GLuint QGLDrawable::bindTexture(const QImage &image, GLenum target, GLint format)
{
- QGLTexture *texture;
+ QGLTexture *texture = 0;
if (widget)
texture = widget->d_func()->glcx->d_func()->bindTexture(image, target, format, true);
else if (buffer)
@@ -4599,7 +4620,7 @@ GLuint QGLDrawable::bindTexture(const QImage &image, GLenum target, GLint format
GLuint QGLDrawable::bindTexture(const QPixmap &pixmap, GLenum target, GLint format)
{
- QGLTexture *texture;
+ QGLTexture *texture = 0;
if (widget)
texture = widget->d_func()->glcx->d_func()->bindTexture(pixmap, target, format, true, true);
else if (buffer)
@@ -4697,6 +4718,7 @@ void QGLShareRegister::removeShare(const QGLContext *context) {
int count = it.value().removeAll(context);
Q_ASSERT(count == 1);
+ Q_UNUSED(count);
Q_ASSERT(it.value().size() != 0);
if (it.value().size() == 1)
diff --git a/src/opengl/qgl_p.h b/src/opengl/qgl_p.h
index 85dae0d..f21ab93 100644
--- a/src/opengl/qgl_p.h
+++ b/src/opengl/qgl_p.h
@@ -241,7 +241,9 @@ public:
quint32 gpm;
int screen;
QHash<QPixmapData*, QPixmap> boundPixmaps;
- QGLTexture *bindTextureFromNativePixmap(QPixmap *pm, const qint64 key, bool internal);
+ QGLTexture *bindTextureFromNativePixmap(QPixmapData*, const qint64 key, bool canInvert);
+ static void destroyGlSurfaceForPixmap(QPixmapData*);
+ static void unbindPixmapFromTexture(QPixmapData*);
#endif
#if defined(Q_WS_MAC)
bool update;
@@ -423,7 +425,8 @@ public:
// is a current context - the context the pixmap was bound to a texture in.
// Otherwise the release doesn't do anything and you get BadDrawable errors
// when you come to delete the context.
- deleteBoundPixmap();
+ if (boundPixmap)
+ QGLContextPrivate::unbindPixmapFromTexture(boundPixmap);
#endif
glDeleteTextures(1, &id);
if (switch_context && current)
@@ -437,9 +440,9 @@ public:
bool clean;
bool yInverted; // NOTE: Y-Inverted textures are for internal use only!
#if defined(Q_WS_X11)
- Qt::HANDLE boundPixmap;
- void deleteBoundPixmap(); // in qgl_x11.cpp/qgl_x11egl.cpp
+ QPixmapData* boundPixmap;
#endif
+
};
class QGLTextureCache {
@@ -458,7 +461,8 @@ public:
static QGLTextureCache *instance();
static void deleteIfEmpty();
- static void cleanupHook(qint64 cacheKey);
+ static void imageCleanupHook(qint64 cacheKey);
+ static void pixmapCleanupHook(QPixmap* pixmap);
private:
QCache<qint64, QGLTexture> m_cache;
diff --git a/src/opengl/qgl_x11.cpp b/src/opengl/qgl_x11.cpp
index cf70991..4509a64 100644
--- a/src/opengl/qgl_x11.cpp
+++ b/src/opengl/qgl_x11.cpp
@@ -58,11 +58,16 @@
#include <private/qglpixelbuffer_p.h>
#endif
+// We always define GLX_EXT_texture_from_pixmap ourselves because
+// we can't trust system headers to do it properly
+#define GLX_EXT_texture_from_pixmap 1
+
#define INT8 dummy_INT8
#define INT32 dummy_INT32
#include <GL/glx.h>
#undef INT8
#undef INT32
+
#include <X11/Xlib.h>
#include <X11/Xutil.h>
#include <X11/Xos.h>
@@ -90,7 +95,7 @@ extern const QX11Info *qt_x11Info(const QPaintDevice *pd);
#define GLX_SAMPLES_ARB 100001
#endif
-#ifndef GLX_EXT_texture_from_pixmap
+#ifndef GLX_TEXTURE_2D_BIT_EXT
#define GLX_TEXTURE_2D_BIT_EXT 0x00000002
#define GLX_TEXTURE_RECTANGLE_BIT_EXT 0x00000004
#define GLX_BIND_TO_TEXTURE_RGB_EXT 0x20D0
@@ -1548,38 +1553,26 @@ void QGLExtensions::init()
}
}
-#if !defined(glXBindTexImageEXT)
+// Solaris defines glXBindTexImageEXT as part of the GL library
+#if defined(GLX_VERSION_1_3) && !defined(Q_OS_HPUX)
typedef void (*qt_glXBindTexImageEXT)(Display*, GLXDrawable, int, const int*);
-static qt_glXBindTexImageEXT glXBindTexImageEXT = 0;
-#endif
-#if !defined(glXReleaseTexImageEXT)
typedef void (*qt_glXReleaseTexImageEXT)(Display*, GLXDrawable, int);
+static qt_glXBindTexImageEXT glXBindTexImageEXT = 0;
static qt_glXReleaseTexImageEXT glXReleaseTexImageEXT = 0;
-#endif
-static bool qt_resolved_texture_from_pixmap = false;
-QGLTexture *QGLContextPrivate::bindTextureFromNativePixmap(QPixmap *pm, const qint64 key, bool canInvert)
+bool qt_resolveTextureFromPixmap()
{
-#if !defined(Q_OS_LINUX)
- return 0;
-#else
- Q_Q(QGLContext);
-
- if (pm->data_ptr()->classId() != QPixmapData::X11Class)
- return 0;
- QX11PixmapData *pixmapData = static_cast<QX11PixmapData*>(pm->data_ptr());
- const QX11Info *x11Info = qt_x11Info(pm);
+ static bool resolvedTextureFromPixmap = false;
+ if (!resolvedTextureFromPixmap) {
+ resolvedTextureFromPixmap = true;
- // Check to see if we have NPOT texture support
- // TODO: Use GLX_TEXTURE_RECTANGLE_EXT texture target on systems without npot textures
- if ( !(QGLExtensions::glExtensions & QGLExtensions::NPOTTextures) &&
- !(QGLFormat::openGLVersionFlags() & QGLFormat::OpenGL_Version_2_0))
- return 0;
-
-
- if (!qt_resolved_texture_from_pixmap) {
- qt_resolved_texture_from_pixmap = true;
+ // Check to see if we have NPOT texture support
+ if ( !(QGLExtensions::glExtensions & QGLExtensions::NPOTTextures) &&
+ !(QGLFormat::openGLVersionFlags() & QGLFormat::OpenGL_Version_2_0))
+ {
+ return false; // Can't use TFP without NPOT
+ }
QString glxExt = QLatin1String(glXGetClientString(QX11Info::display(), GLX_EXTENSIONS));
if (glxExt.contains(QLatin1String("GLX_EXT_texture_from_pixmap"))) {
@@ -1601,81 +1594,139 @@ QGLTexture *QGLContextPrivate::bindTextureFromNativePixmap(QPixmap *pm, const qi
}
}
- if (!glXBindTexImageEXT)
- return 0;
+ return glXBindTexImageEXT && glXReleaseTexImageEXT;
+}
+#endif //defined(GLX_VERSION_1_3) && !defined(Q_OS_HPUX)
+
+QGLTexture *QGLContextPrivate::bindTextureFromNativePixmap(QPixmapData *pmd, const qint64 key, bool canInvert)
+{
#if !defined(GLX_VERSION_1_3) || defined(Q_OS_HPUX)
return 0;
#else
- GLXFBConfig *configList = 0;
- GLXFBConfig glxPixmapConfig;
- int configCount = 0;
- bool hasAlpha = pixmapData->hasAlphaChannel();
-
- int configAttribs[] = {
- hasAlpha ? GLX_BIND_TO_TEXTURE_RGBA_EXT : GLX_BIND_TO_TEXTURE_RGB_EXT, True,
- GLX_DRAWABLE_TYPE, GLX_PIXMAP_BIT,
- GLX_BIND_TO_TEXTURE_TARGETS_EXT, GLX_TEXTURE_2D_BIT_EXT,
- // QGLContext::bindTexture() can't return an inverted texture, but QPainter::drawPixmap() can:
- GLX_Y_INVERTED_EXT, canInvert ? GLX_DONT_CARE : False,
- XNone
-// GLX_BIND_TO_MIPMAP_TEXTURE_EXT, False,
-// GLX_BIND_TO_TEXTURE_TARGETS_EXT, GLX_TEXTURE_1D_BIT_EXT or GLX_TEXTURE_2D_BIT_EXT or GLX_TEXTURE_RECTANGLE_BIT_EXT
- };
- configList = glXChooseFBConfig(x11Info->display(), x11Info->screen(), configAttribs, &configCount);
- if (!configList)
- return 0;
- glxPixmapConfig = configList[0];
- XFree(configList);
-
- GLXPixmap glxPixmap;
- int pixmapAttribs[] = {
- GLX_TEXTURE_FORMAT_EXT, hasAlpha ? GLX_TEXTURE_FORMAT_RGBA_EXT : GLX_TEXTURE_FORMAT_RGB_EXT,
- GLX_TEXTURE_TARGET_EXT, GLX_TEXTURE_2D_EXT,
- GLX_MIPMAP_TEXTURE_EXT, False,
- XNone
-// GLX_TEXTURE_FORMAT_EXT, GLX_TEXTURE_FORMAT_RGBA_EXT or GLX_TEXTURE_FORMAT_RGB_EXT or GLX_TEXTURE_FORMAT_NONE_EXT,
-// GLX_TEXTURE_TARGET_EXT, GLX_TEXTURE_2D_EXT or GLX_TEXTURE_RECTANGLE_EXT,
-// GLX_MIPMAP_TEXTURE_EXT, True or False,
- };
+ Q_Q(QGLContext);
- // Wrap the X Pixmap into a GLXPixmap:
- glxPixmap = glXCreatePixmap(x11Info->display(), glxPixmapConfig, pixmapData->handle(), pixmapAttribs);
+ Q_ASSERT(pmd->classId() == QPixmapData::X11Class);
- if (!glxPixmap)
+ if (!qt_resolveTextureFromPixmap())
return 0;
- int yInverted;
- glXGetFBConfigAttrib(x11Info->display(), glxPixmapConfig, GLX_Y_INVERTED_EXT, &yInverted);
+ QX11PixmapData *pixmapData = static_cast<QX11PixmapData*>(pmd);
+ const QX11Info &x11Info = pixmapData->xinfo;
+
+ // Store the configs (Can be static because configs aren't dependent on current context)
+ static GLXFBConfig glxRGBPixmapConfig = 0;
+ static bool RGBConfigInverted = false;
+ static GLXFBConfig glxRGBAPixmapConfig = 0;
+ static bool RGBAConfigInverted = false;
+
+ bool hasAlpha = pixmapData->hasAlphaChannel();
+
+ // Check to see if we need a config
+ if ( (hasAlpha && !glxRGBAPixmapConfig) || (!hasAlpha && !glxRGBPixmapConfig) ) {
+ GLXFBConfig *configList = 0;
+ int configCount = 0;
+
+ int configAttribs[] = {
+ hasAlpha ? GLX_BIND_TO_TEXTURE_RGBA_EXT : GLX_BIND_TO_TEXTURE_RGB_EXT, True,
+ GLX_DRAWABLE_TYPE, GLX_PIXMAP_BIT,
+ GLX_BIND_TO_TEXTURE_TARGETS_EXT, GLX_TEXTURE_2D_BIT_EXT,
+ // QGLContext::bindTexture() can't return an inverted texture, but QPainter::drawPixmap() can:
+ GLX_Y_INVERTED_EXT, canInvert ? GLX_DONT_CARE : False,
+ XNone
+ };
+ configList = glXChooseFBConfig(x11Info.display(), x11Info.screen(), configAttribs, &configCount);
+ if (!configList)
+ return 0;
+
+ int yInv;
+ glXGetFBConfigAttrib(x11Info.display(), configList[0], GLX_Y_INVERTED_EXT, &yInv);
+
+ if (hasAlpha) {
+ glxRGBAPixmapConfig = configList[0];
+ RGBAConfigInverted = yInv;
+ }
+ else {
+ glxRGBPixmapConfig = configList[0];
+ RGBConfigInverted = yInv;
+ }
+
+ XFree(configList);
+ }
+
+ // Check to see if the surface is still valid
+ if (pixmapData->gl_surface &&
+ hasAlpha != (pixmapData->flags & QX11PixmapData::GlSurfaceCreatedWithAlpha))
+ {
+ // Surface is invalid!
+ destroyGlSurfaceForPixmap(pixmapData);
+ }
+
+ // Check to see if we need a surface
+ if (!pixmapData->gl_surface) {
+ GLXPixmap glxPixmap;
+ int pixmapAttribs[] = {
+ GLX_TEXTURE_FORMAT_EXT, hasAlpha ? GLX_TEXTURE_FORMAT_RGBA_EXT : GLX_TEXTURE_FORMAT_RGB_EXT,
+ GLX_TEXTURE_TARGET_EXT, GLX_TEXTURE_2D_EXT,
+ GLX_MIPMAP_TEXTURE_EXT, False, // Maybe needs to be don't care
+ XNone
+ };
+
+ // Wrap the X Pixmap into a GLXPixmap:
+ glxPixmap = glXCreatePixmap(x11Info.display(),
+ hasAlpha ? glxRGBAPixmapConfig : glxRGBPixmapConfig,
+ pixmapData->handle(), pixmapAttribs);
+
+ if (!glxPixmap)
+ return 0;
+
+ pixmapData->gl_surface = (Qt::HANDLE)glxPixmap;
+
+ // Make sure the cleanup hook gets called so we can delete the glx pixmap
+ pixmapData->is_cached = true;
+ }
GLuint textureId;
glGenTextures(1, &textureId);
glBindTexture(GL_TEXTURE_2D, textureId);
- glXBindTexImageEXT(x11Info->display(), glxPixmap, GLX_FRONT_LEFT_EXT, 0);
+ glXBindTexImageEXT(x11Info.display(), (GLXPixmap)pixmapData->gl_surface, GLX_FRONT_LEFT_EXT, 0);
glBindTexture(GL_TEXTURE_2D, textureId);
- QGLTexture *texture = new QGLTexture(q, textureId, GL_TEXTURE_2D, canInvert, yInverted);
- texture->boundPixmap = glxPixmap;
+ QGLTexture *texture = new QGLTexture(q, textureId, GL_TEXTURE_2D, canInvert, false);
+ texture->yInverted = (hasAlpha && RGBAConfigInverted) || (!hasAlpha && RGBConfigInverted);
+ if (texture->yInverted)
+ pixmapData->flags |= QX11PixmapData::InvertedWhenBoundToTexture;
// We assume the cost of bound pixmaps is zero
QGLTextureCache::instance()->insert(q, key, texture, 0);
return texture;
#endif //!defined(GLX_VERSION_1_3) || defined(Q_OS_HPUX)
-#endif //!defined(Q_OS_LINUX
}
-void QGLTexture::deleteBoundPixmap()
+
+void QGLContextPrivate::destroyGlSurfaceForPixmap(QPixmapData* pmd)
{
-#if defined(GLX_VERSION_1_3) && !defined(Q_OS_HPUX) && defined(Q_OS_LINUX)
- if (boundPixmap) {
- glXReleaseTexImageEXT(QX11Info::display(), boundPixmap, GLX_FRONT_LEFT_EXT);
- glXDestroyPixmap(QX11Info::display(), boundPixmap);
- boundPixmap = 0;
+#if defined(GLX_VERSION_1_3) && !defined(Q_OS_HPUX)
+ Q_ASSERT(pmd->classId() == QPixmapData::X11Class);
+ QX11PixmapData *pixmapData = static_cast<QX11PixmapData*>(pmd);
+ if (pixmapData->gl_surface) {
+ glXDestroyPixmap(QX11Info::display(), (GLXPixmap)pixmapData->gl_surface);
+ pixmapData->gl_surface = 0;
}
#endif
}
+void QGLContextPrivate::unbindPixmapFromTexture(QPixmapData* pmd)
+{
+#if defined(GLX_VERSION_1_3) && !defined(Q_OS_HPUX)
+ Q_ASSERT(pmd->classId() == QPixmapData::X11Class);
+ Q_ASSERT(QGLContext::currentContext());
+ QX11PixmapData *pixmapData = static_cast<QX11PixmapData*>(pmd);
+ if (pixmapData->gl_surface)
+ glXReleaseTexImageEXT(QX11Info::display(), (GLXPixmap)pixmapData->gl_surface, GLX_FRONT_LEFT_EXT);
+#endif
+}
QT_END_NAMESPACE
diff --git a/src/opengl/qgl_x11egl.cpp b/src/opengl/qgl_x11egl.cpp
index c6904fe..ed9930f 100644
--- a/src/opengl/qgl_x11egl.cpp
+++ b/src/opengl/qgl_x11egl.cpp
@@ -41,15 +41,16 @@
#include "qgl.h"
#include <private/qt_x11_p.h>
+#include <private/qpixmap_x11_p.h>
#include <private/qgl_p.h>
#include <private/qpaintengine_opengl_p.h>
#include "qgl_egl_p.h"
#include "qcolormap.h"
+#include <QDebug>
QT_BEGIN_NAMESPACE
-
bool QGLFormat::hasOpenGL()
{
return true;
@@ -298,6 +299,7 @@ void QGLWidget::setContext(QGLContext *context, const QGLContext* shareContext,
int matchingCount = 0;
chosenVisualInfo = XGetVisualInfo(x11Info().display(), VisualIDMask, &vi, &matchingCount);
if (chosenVisualInfo) {
+#if !defined(QT_NO_XRENDER)
if (useArgbVisual) {
// Check to make sure the visual provided by EGL is ARGB
XRenderPictFormat *format;
@@ -311,8 +313,9 @@ void QGLWidget::setContext(QGLContext *context, const QGLContext* shareContext,
nativeVisualId, (int)qeglCtx->config());
vi.visualid = 0;
}
- }
- else {
+ } else
+#endif
+ {
qDebug("Using opaque X Visual ID (%d) provided by EGL", (int)vi.visualid);
vi = *chosenVisualInfo;
}
@@ -486,15 +489,175 @@ void QGLWidgetPrivate::recreateEglSurface(bool force)
}
}
-QGLTexture *QGLContextPrivate::bindTextureFromNativePixmap(QPixmap *pm, const qint64 key, bool canInvert)
+
+QGLTexture *QGLContextPrivate::bindTextureFromNativePixmap(QPixmapData* pd, const qint64 key, bool canInvert)
{
- // TODO
- return 0;
+ Q_Q(QGLContext);
+
+ Q_ASSERT(pd->classId() == QPixmapData::X11Class);
+
+ static bool checkedForTFP = false;
+ static bool haveTFP = false;
+
+ if (!checkedForTFP) {
+ // Check for texture_from_pixmap egl extension
+ checkedForTFP = true;
+ if (eglContext->hasExtension("EGL_NOKIA_texture_from_pixmap") ||
+ eglContext->hasExtension("EGL_EXT_texture_from_pixmap"))
+ {
+ qDebug("Found texture_from_pixmap EGL extension!");
+ haveTFP = true;
+ }
+ }
+
+ if (!haveTFP)
+ return 0;
+
+ QX11PixmapData *pixmapData = static_cast<QX11PixmapData*>(pd);
+
+ bool hasAlpha = pixmapData->hasAlphaChannel();
+
+ // Check to see if the surface is still valid
+ if (pixmapData->gl_surface &&
+ hasAlpha != (pixmapData->flags & QX11PixmapData::GlSurfaceCreatedWithAlpha))
+ {
+ // Surface is invalid!
+ destroyGlSurfaceForPixmap(pixmapData);
+ }
+
+ EGLint pixmapAttribs[] = {
+ EGL_TEXTURE_TARGET, EGL_TEXTURE_2D,
+ EGL_TEXTURE_FORMAT, hasAlpha ? EGL_TEXTURE_RGBA : EGL_TEXTURE_RGB,
+ EGL_NONE
+ };
+ Q_ASSERT(sizeof(Qt::HANDLE) >= sizeof(EGLSurface)); // Just to make totally sure!
+ if (pixmapData->gl_surface == 0)
+ pixmapData->gl_surface = (Qt::HANDLE)EGL_NO_SURFACE;
+ EGLSurface pixmapSurface = (EGLSurface)pixmapData->gl_surface;
+ static EGLConfig pixmapRGBConfig = 0;
+ static EGLConfig pixmapRGBAConfig = 0;
+
+ // Check to see if we need to find a config
+ if ((hasAlpha && !pixmapRGBAConfig) || (!hasAlpha && !pixmapRGBConfig) ) {
+ const EGLint configAttribs[] = {
+ EGL_SURFACE_TYPE, EGL_PIXMAP_BIT,
+ EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT,
+ EGL_DEPTH_SIZE, 0,
+ hasAlpha ? EGL_BIND_TO_TEXTURE_RGBA : EGL_BIND_TO_TEXTURE_RGB, EGL_TRUE,
+ EGL_NONE
+ };
+
+ EGLint configCount = 0;
+ eglChooseConfig(eglContext->display(), configAttribs, 0, 256, &configCount);
+ if (configCount == 0) {
+ haveTFP = false;
+ qWarning("bindTextureFromNativePixmap() - Couldn't find a suitable config");
+ return 0;
+ }
+
+ EGLConfig *configList = new EGLConfig[configCount];
+ eglChooseConfig(eglContext->display(), configAttribs, configList, configCount, &configCount);
+ Q_ASSERT(configCount);
+
+ // Try to create a pixmap surface for each config until one works
+ for (int i = 0; i < configCount; ++i) {
+ pixmapSurface = eglCreatePixmapSurface(eglContext->display(), configList[i],
+ (EGLNativePixmapType) pixmapData->handle(),
+ pixmapAttribs);
+ if (pixmapSurface != EGL_NO_SURFACE) {
+ // Got one!
+ qDebug() << "Found an" << (hasAlpha ? "ARGB" : "RGB")
+ << "config (" << int(configList[i]) << ") to create a pixmap surface";
+ if (hasAlpha)
+ pixmapRGBAConfig = configList[i];
+ else
+ pixmapRGBConfig = configList[i];
+ pixmapData->gl_surface = (Qt::HANDLE)pixmapSurface;
+ break;
+ }
+ }
+ delete configList;
+
+ if ((hasAlpha && !pixmapRGBAConfig) || (!hasAlpha && !pixmapRGBConfig) ) {
+ qDebug("Couldn't create a pixmap surface with any of the provided configs");
+ haveTFP = false;
+ return 0;
+ }
+ }
+
+ if (pixmapSurface == EGL_NO_SURFACE) {
+ pixmapSurface = eglCreatePixmapSurface(eglContext->display(),
+ hasAlpha? pixmapRGBAConfig : pixmapRGBConfig,
+ (EGLNativePixmapType) pixmapData->handle(),
+ pixmapAttribs);
+ if (pixmapSurface == EGL_NO_SURFACE) {
+ qWarning("Failed to create a pixmap surface using config %d",
+ (int)(hasAlpha? pixmapRGBAConfig : pixmapRGBConfig));
+ haveTFP = false;
+ return 0;
+ }
+ pixmapData->gl_surface = (Qt::HANDLE)pixmapSurface;
+ }
+
+ // Make sure the cleanup hook gets called so we can delete the glx pixmap
+ pixmapData->is_cached = true;
+ Q_ASSERT(pixmapData->gl_surface);
+
+ GLuint textureId;
+ glGenTextures(1, &textureId);
+ glEnable(GL_TEXTURE_2D);
+ glBindTexture(GL_TEXTURE_2D, textureId);
+
+ // bind the egl pixmap surface to a texture
+ EGLBoolean success;
+ success = eglBindTexImage(eglContext->display(), pixmapSurface, EGL_BACK_BUFFER);
+ if (success == EGL_FALSE) {
+ qWarning() << "eglBindTexImage() failed:" << eglContext->errorString(eglGetError());
+ eglDestroySurface(eglContext->display(), pixmapSurface);
+ pixmapData->gl_surface = (Qt::HANDLE)EGL_NO_SURFACE;
+ haveTFP = false;
+ return 0;
+ }
+
+ QGLTexture *texture = new QGLTexture(q, textureId, GL_TEXTURE_2D, canInvert, true);
+ pixmapData->flags |= QX11PixmapData::InvertedWhenBoundToTexture;
+
+ // We assume the cost of bound pixmaps is zero
+ QGLTextureCache::instance()->insert(q, key, texture, 0);
+
+ glBindTexture(GL_TEXTURE_2D, textureId);
+ return texture;
+}
+
+void QGLContextPrivate::destroyGlSurfaceForPixmap(QPixmapData* pmd)
+{
+ Q_ASSERT(pmd->classId() == QPixmapData::X11Class);
+ QX11PixmapData *pixmapData = static_cast<QX11PixmapData*>(pmd);
+ if (pixmapData->gl_surface) {
+ EGLBoolean success;
+ success = eglDestroySurface(QEglContext::defaultDisplay(0), (EGLSurface)pixmapData->gl_surface);
+ if (success == EGL_FALSE) {
+ qWarning() << "destroyGlSurfaceForPixmap() - Error deleting surface: "
+ << QEglContext::errorString(eglGetError());
+ }
+ pixmapData->gl_surface = 0;
+ }
}
-void QGLTexture::deleteBoundPixmap()
+void QGLContextPrivate::unbindPixmapFromTexture(QPixmapData* pmd)
{
- //TODO
+ Q_ASSERT(pmd->classId() == QPixmapData::X11Class);
+ QX11PixmapData *pixmapData = static_cast<QX11PixmapData*>(pmd);
+ if (pixmapData->gl_surface) {
+ EGLBoolean success;
+ success = eglReleaseTexImage(QEglContext::defaultDisplay(0),
+ (EGLSurface)pixmapData->gl_surface,
+ EGL_BACK_BUFFER);
+ if (success == EGL_FALSE) {
+ qWarning() << "unbindPixmapFromTexture() - Unable to release bound texture: "
+ << QEglContext::errorString(eglGetError());
+ }
+ }
}
QT_END_NAMESPACE
diff --git a/src/opengl/qglcolormap.cpp b/src/opengl/qglcolormap.cpp
index 426e090..481089a 100644
--- a/src/opengl/qglcolormap.cpp
+++ b/src/opengl/qglcolormap.cpp
@@ -174,13 +174,14 @@ void QGLColormap::setEntry(int idx, QRgb color)
detach();
if (!d->cells)
d->cells = new QVector<QRgb>(256);
- d->cells->insert(idx, color);
+ d->cells->replace(idx, color);
}
/*!
Set an array of cells in this colormap. \a count is the number of
colors that should be set, \a colors is the array of colors, and
- \a base is the starting index.
+ \a base is the starting index. The first element in \a colors
+ is set at \a base in the colormap.
*/
void QGLColormap::setEntries(int count, const QRgb *colors, int base)
{
@@ -188,10 +189,10 @@ void QGLColormap::setEntries(int count, const QRgb *colors, int base)
if (!d->cells)
d->cells = new QVector<QRgb>(256);
- Q_ASSERT_X(!colors || base >= 0 || base + count < d->cells->size(), "QGLColormap::setEntries",
+ Q_ASSERT_X(colors && base >= 0 && (base + count) <= d->cells->size(), "QGLColormap::setEntries",
"preconditions not met");
- for (int i = base; i < base + count; ++i)
- setEntry(i, colors[i]);
+ for (int i = 0; i < count; ++i)
+ setEntry(base + i, colors[i]);
}
/*!
@@ -227,8 +228,17 @@ QColor QGLColormap::entryColor(int idx) const
}
/*!
- Returns true if the colormap is empty; otherwise returns false. A
- colormap with no color values set is considered to be empty.
+ Returns true if the colormap is empty or it is not in use
+ by a QGLWidget; otherwise returns false.
+
+ A colormap with no color values set is considered to be empty.
+ For historical reasons, a colormap that has color values set
+ but which is not in use by a QGLWidget is also considered empty.
+
+ Compare size() with zero to determine if the colormap is empty
+ regardless of whether it is in use by a QGLWidget or not.
+
+ \sa size()
*/
bool QGLColormap::isEmpty() const
{
diff --git a/src/plugins/audio/audio.pro b/src/plugins/audio/audio.pro
new file mode 100644
index 0000000..e93b369
--- /dev/null
+++ b/src/plugins/audio/audio.pro
@@ -0,0 +1,3 @@
+TEMPLATE = subdirs
+
+#SUBDIRS += ossaudio
diff --git a/src/plugins/gfxdrivers/directfb/qdirectfbkeyboard.cpp b/src/plugins/gfxdrivers/directfb/qdirectfbkeyboard.cpp
index b5376b1..13c4053 100644
--- a/src/plugins/gfxdrivers/directfb/qdirectfbkeyboard.cpp
+++ b/src/plugins/gfxdrivers/directfb/qdirectfbkeyboard.cpp
@@ -77,13 +77,15 @@ private:
QSocketNotifier *keyboardNotifier;
DFBEvent event;
int bytesRead;
-
+ int lastUnicode, lastKeycode;
+ Qt::KeyboardModifiers lastModifiers;
private Q_SLOTS:
void readKeyboardData();
};
QDirectFBKeyboardHandlerPrivate::QDirectFBKeyboardHandlerPrivate(QDirectFBKeyboardHandler *h)
- : handler(h), eventBuffer(0)
+ : handler(h), eventBuffer(0), keyboardNotifier(0), bytesRead(0),
+ lastUnicode(0), lastKeycode(0), lastModifiers(0)
{
Q_ASSERT(qt_screen);
@@ -114,8 +116,6 @@ QDirectFBKeyboardHandlerPrivate::QDirectFBKeyboardHandlerPrivate(QDirectFBKeyboa
::fcntl(fd, F_SETFL, flags | O_NONBLOCK);
memset(&event, 0, sizeof(event));
- bytesRead = 0;
-
keyboardNotifier = new QSocketNotifier(fd, QSocketNotifier::Read, this);
connect(keyboardNotifier, SIGNAL(activated(int)),
@@ -213,8 +213,27 @@ void QDirectFBKeyboardHandlerPrivate::readKeyboardData()
unicode = symbol;
if (unicode != -1 || keycode != 0) {
+ bool autoRepeat = false;
+ if (press) {
+ if (unicode == lastUnicode && keycode == lastKeycode && modifiers == lastModifiers) {
+ autoRepeat = true;
+ } else {
+ lastUnicode = unicode;
+ lastKeycode = keycode;
+ lastModifiers = modifiers;
+ }
+ } else {
+ lastUnicode = lastKeycode = -1;
+ lastModifiers = 0;
+ }
+ if (autoRepeat) {
+ handler->processKeyEvent(unicode, keycode,
+ modifiers, false, autoRepeat);
+
+ }
+
handler->processKeyEvent(unicode, keycode,
- modifiers, press, false);
+ modifiers, press, autoRepeat);
}
}
}
diff --git a/src/plugins/gfxdrivers/directfb/qdirectfbpaintdevice.cpp b/src/plugins/gfxdrivers/directfb/qdirectfbpaintdevice.cpp
index 86e92f7..2075799 100644
--- a/src/plugins/gfxdrivers/directfb/qdirectfbpaintdevice.cpp
+++ b/src/plugins/gfxdrivers/directfb/qdirectfbpaintdevice.cpp
@@ -43,10 +43,17 @@
#include "qdirectfbscreen.h"
#include "qdirectfbpaintdevice.h"
+#include "qdirectfbpaintengine.h"
+
+QDirectFBPaintDevice::QDirectFBPaintDevice(QDirectFBScreen *scr)
+ : QCustomRasterPaintDevice(0), dfbSurface(0), lockedImage(0), screen(scr),
+ lock(DFBSurfaceLockFlags(0)), mem(0), engine(0)
+{}
QDirectFBPaintDevice::~QDirectFBPaintDevice()
{
delete lockedImage;
+ delete engine;
}
@@ -164,4 +171,10 @@ int QDirectFBPaintDevice::metric(QPaintDevice::PaintDeviceMetric metric) const
}
}
+QPaintEngine *QDirectFBPaintDevice::paintEngine() const
+{
+ return engine;
+}
+
#endif
+
diff --git a/src/plugins/gfxdrivers/directfb/qdirectfbpaintdevice.h b/src/plugins/gfxdrivers/directfb/qdirectfbpaintdevice.h
index 248a15b..c4aeb70 100644
--- a/src/plugins/gfxdrivers/directfb/qdirectfbpaintdevice.h
+++ b/src/plugins/gfxdrivers/directfb/qdirectfbpaintdevice.h
@@ -51,7 +51,8 @@ QT_BEGIN_HEADER
QT_MODULE(Gui)
// Inherited by both window surface and pixmap
- class QDirectFBPaintDevice : public QCustomRasterPaintDevice
+class QDirectFBPaintEngine;
+class QDirectFBPaintDevice : public QCustomRasterPaintDevice
{
public:
~QDirectFBPaintDevice();
@@ -62,19 +63,16 @@ public:
void unlockDirectFB();
// Reimplemented from QCustomRasterPaintDevice:
- void* memory() const;
+ void *memory() const;
QImage::Format format() const;
int bytesPerLine() const;
QSize size() const;
int metric(QPaintDevice::PaintDeviceMetric metric) const;
DFBSurfaceLockFlags lockFlags() const { return lock; }
-protected:
- // Shouldn't create QDirectFBPaintDevice by itself but only sub-class it:
- QDirectFBPaintDevice(QDirectFBScreen *scr = QDirectFBScreen::instance())
- : QCustomRasterPaintDevice(0), dfbSurface(0), lockedImage(0), screen(scr),
- lock(DFBSurfaceLockFlags(0)), mem(0)
- {}
+ QPaintEngine *paintEngine() const;
+protected:
+ QDirectFBPaintDevice(QDirectFBScreen *scr);
inline int dotsPerMeterX() const
{
return (screen->deviceWidth() * 1000) / screen->physicalWidth();
@@ -83,16 +81,17 @@ protected:
{
return (screen->deviceHeight() * 1000) / screen->physicalHeight();
}
-
+protected:
IDirectFBSurface *dfbSurface;
QImage *lockedImage;
QDirectFBScreen *screen;
int bpl;
DFBSurfaceLockFlags lock;
uchar *mem;
+ QDirectFBPaintEngine *engine;
private:
- Q_DISABLE_COPY(QDirectFBPaintDevice)
- };
+ Q_DISABLE_COPY(QDirectFBPaintDevice);
+};
QT_END_HEADER
diff --git a/src/plugins/gfxdrivers/directfb/qdirectfbpaintengine.cpp b/src/plugins/gfxdrivers/directfb/qdirectfbpaintengine.cpp
index b264ac0..58c8a58 100644
--- a/src/plugins/gfxdrivers/directfb/qdirectfbpaintengine.cpp
+++ b/src/plugins/gfxdrivers/directfb/qdirectfbpaintengine.cpp
@@ -53,16 +53,32 @@
#include <qmath.h>
#include <private/qpixmapdata_p.h>
#include <private/qpixmap_raster_p.h>
+#include <private/qimagepixmapcleanuphooks_p.h>
class SurfaceCache;
class QDirectFBPaintEnginePrivate : public QRasterPaintEnginePrivate
{
public:
enum TransformationTypeFlags {
- NegativeScale = 0x100,
- RectsUnsupported = (QTransform::TxRotate|QTransform::TxShear|QTransform::TxProject),
- BlitUnsupported = (NegativeScale|RectsUnsupported)
+ Matrix_NegativeScale = 0x100,
+ Matrix_RectsUnsupported = (QTransform::TxRotate|QTransform::TxShear|QTransform::TxProject),
+ Matrix_BlitsUnsupported = (Matrix_NegativeScale|Matrix_RectsUnsupported)
};
+
+ enum CompositionModeStatus {
+ PorterDuff_None = 0x0,
+ PorterDuff_SupportedBlits = 0x1,
+ PorterDuff_SupportedPrimitives = 0x2
+ };
+
+ enum ClipType {
+ ClipUnset,
+ NoClip,
+ RectClip,
+ RegionClip,
+ ComplexClip
+ };
+
QDirectFBPaintEnginePrivate(QDirectFBPaintEngine *p);
~QDirectFBPaintEnginePrivate();
@@ -76,9 +92,6 @@ public:
inline void lock();
inline void unlock();
- inline bool dfbCanHandleClip(const QRect &rect) const;
- inline bool dfbCanHandleClip(const QRectF &rect) const;
- inline bool dfbCanHandleClip() const;
inline bool isSimpleBrush(const QBrush &brush) const;
void drawTiledPixmap(const QRectF &dest, const QPixmap &pixmap, const QPointF &pos);
@@ -100,19 +113,16 @@ private:
bool antialiased;
bool simplePen;
- uint transformationType; // this is QTransform::type() + NegativeScale if qMin(transform.m11(), transform.m22()) < 0
+ uint transformationType; // this is QTransform::type() + Matrix_NegativeScale if qMin(transform.m11(), transform.m22()) < 0
SurfaceCache *surfaceCache;
-
IDirectFB *fb;
-
quint8 opacity;
bool dirtyClip;
- bool dfbHandledClip;
- bool ignoreSystemClip;
+ ClipType clipType;
QDirectFBPaintDevice *dfbDevice;
- bool unsupportedCompositionMode;
+ uint compositionModeStatus;
QDirectFBPaintEngine *q;
QRect currentClip;
@@ -161,8 +171,12 @@ enum PaintOperation {
#ifdef QT_DIRECTFB_WARN_ON_RASTERFALLBACKS
template <typename device, typename T1, typename T2, typename T3>
-static void rasterFallbackWarn(const char *msg, const char *, const device *, uint, bool, bool, bool,
- const char *, const T1 &, const char *, const T2 &, const char *, const T3 &);
+static void rasterFallbackWarn(const char *msg, const char *func, const device *dev,
+ uint transformationType, bool simplePen,
+ uint clipType, uint compositionModeStatus,
+ const char *nameOne, const T1 &one,
+ const char *nameTwo, const T2 &two,
+ const char *nameThree, const T3 &three);
#endif
#if defined QT_DIRECTFB_WARN_ON_RASTERFALLBACKS && defined QT_DIRECTFB_DISABLE_RASTERFALLBACKS
@@ -172,8 +186,8 @@ static void rasterFallbackWarn(const char *msg, const char *, const device *, ui
__FUNCTION__, state()->painter->device(), \
d_func()->transformationType, \
d_func()->simplePen, \
- d_func()->dfbCanHandleClip(), \
- d_func()->unsupportedCompositionMode, \
+ d_func()->clipType, \
+ d_func()->compositionModeStatus, \
#one, one, #two, two, #three, three); \
if (op & (QT_DIRECTFB_DISABLE_RASTERFALLBACKS)) \
return;
@@ -188,14 +202,13 @@ static void rasterFallbackWarn(const char *msg, const char *, const device *, ui
__FUNCTION__, state()->painter->device(), \
d_func()->transformationType, \
d_func()->simplePen, \
- d_func()->dfbCanHandleClip(), \
- d_func()->unsupportedCompositionMode, \
+ d_func()->clipType, \
+ d_func()->compositionModeStatus, \
#one, one, #two, two, #three, three);
#else
#define RASTERFALLBACK(op, one, two, three)
#endif
-
template <class T>
static inline void drawLines(const T *lines, int n, const QTransform &transform, IDirectFBSurface *surface);
template <class T>
@@ -203,6 +216,36 @@ static inline void fillRects(const T *rects, int n, const QTransform &transform,
template <class T>
static inline void drawRects(const T *rects, int n, const QTransform &transform, IDirectFBSurface *surface);
+#define CLIPPED_PAINT(operation) { \
+ DFBRegion clipRegion; \
+ switch (d->clipType) { \
+ case QDirectFBPaintEnginePrivate::NoClip: \
+ case QDirectFBPaintEnginePrivate::RectClip: \
+ operation; \
+ break; \
+ case QDirectFBPaintEnginePrivate::RegionClip: { \
+ Q_ASSERT(d->clip()); \
+ const QVector<QRect> cr = d->clip()->clipRegion.rects(); \
+ const int size = cr.size(); \
+ for (int i=0; i<size; ++i) { \
+ d->currentClip = cr.at(i); \
+ clipRegion.x1 = d->currentClip.x(); \
+ clipRegion.y1 = d->currentClip.y(); \
+ clipRegion.x2 = d->currentClip.right(); \
+ clipRegion.y2 = d->currentClip.bottom(); \
+ d->surface->SetClip(d->surface, &clipRegion); \
+ operation; \
+ } \
+ d->dirtyClip = true; \
+ break; } \
+ case QDirectFBPaintEnginePrivate::ComplexClip: \
+ case QDirectFBPaintEnginePrivate::ClipUnset: \
+ qFatal("CLIPPED_PAINT internal error %d", d->clipType); \
+ break; \
+ } \
+ }
+
+
QDirectFBPaintEngine::QDirectFBPaintEngine(QPaintDevice *device)
: QRasterPaintEngine(*(new QDirectFBPaintEnginePrivate(this)), device)
{
@@ -233,7 +276,7 @@ bool QDirectFBPaintEngine::begin(QPaintDevice *device)
}
d->prepare(d->dfbDevice);
-
+ d->setCompositionMode(state()->composition_mode);
return QRasterPaintEngine::begin(device);
}
@@ -323,58 +366,60 @@ void QDirectFBPaintEngine::clip(const QRect &rect, Qt::ClipOperation op)
void QDirectFBPaintEngine::drawRects(const QRect *rects, int rectCount)
{
Q_D(QDirectFBPaintEngine);
- d->updateClip();
+ const QPen &pen = state()->pen;
const QBrush &brush = state()->brush;
- if (d->unsupportedCompositionMode
- || (d->transformationType & QDirectFBPaintEnginePrivate::RectsUnsupported)
+ if (brush == Qt::NoBrush && pen == Qt::NoPen)
+ return;
+
+ d->updateClip();
+ if (!(d->compositionModeStatus & QDirectFBPaintEnginePrivate::PorterDuff_SupportedPrimitives)
+ || (d->transformationType & QDirectFBPaintEnginePrivate::Matrix_RectsUnsupported)
|| !d->simplePen
- || !d->dfbCanHandleClip()
+ || d->clipType == QDirectFBPaintEnginePrivate::ComplexClip
|| !d->isSimpleBrush(brush)) {
RASTERFALLBACK(DRAW_RECTS, rectCount, VOID_ARG(), VOID_ARG());
d->lock();
QRasterPaintEngine::drawRects(rects, rectCount);
return;
}
-
d->unlock();
-
if (brush != Qt::NoBrush) {
d->setDFBColor(brush.color());
- ::fillRects<QRect>(rects, rectCount, state()->matrix, d->surface);
+ CLIPPED_PAINT(::fillRects<QRect>(rects, rectCount, state()->matrix, d->surface));
}
- const QPen &pen = state()->pen;
if (pen != Qt::NoPen) {
d->setDFBColor(pen.color());
- ::drawRects<QRect>(rects, rectCount, state()->matrix, d->surface);
+ CLIPPED_PAINT(::drawRects<QRect>(rects, rectCount, state()->matrix, d->surface));
}
}
void QDirectFBPaintEngine::drawRects(const QRectF *rects, int rectCount)
{
Q_D(QDirectFBPaintEngine);
- d->updateClip();
+ const QPen &pen = state()->pen;
const QBrush &brush = state()->brush;
- if (d->unsupportedCompositionMode
- || (d->transformationType & QDirectFBPaintEnginePrivate::RectsUnsupported)
+ if (brush == Qt::NoBrush && pen == Qt::NoPen)
+ return;
+
+ d->updateClip();
+ if (!(d->compositionModeStatus & QDirectFBPaintEnginePrivate::PorterDuff_SupportedPrimitives)
+ || (d->transformationType & QDirectFBPaintEnginePrivate::Matrix_RectsUnsupported)
|| !d->simplePen
- || !d->dfbCanHandleClip()
+ || d->clipType == QDirectFBPaintEnginePrivate::ComplexClip
|| !d->isSimpleBrush(brush)) {
RASTERFALLBACK(DRAW_RECTS, rectCount, VOID_ARG(), VOID_ARG());
d->lock();
QRasterPaintEngine::drawRects(rects, rectCount);
return;
}
-
d->unlock();
-
if (brush != Qt::NoBrush) {
d->setDFBColor(brush.color());
- ::fillRects<QRectF>(rects, rectCount, state()->matrix, d->surface);
+ CLIPPED_PAINT(::fillRects<QRectF>(rects, rectCount, state()->matrix, d->surface));
}
- const QPen &pen = state()->pen;
if (pen != Qt::NoPen) {
d->setDFBColor(pen.color());
- ::drawRects<QRectF>(rects, rectCount, state()->matrix, d->surface);
+ CLIPPED_PAINT(::drawRects<QRectF>(rects, rectCount, state()->matrix, d->surface));
}
}
@@ -382,7 +427,10 @@ void QDirectFBPaintEngine::drawLines(const QLine *lines, int lineCount)
{
Q_D(QDirectFBPaintEngine);
d->updateClip();
- if (d->unsupportedCompositionMode || !d->simplePen || !d->dfbCanHandleClip()) {
+
+ if (!(d->compositionModeStatus & QDirectFBPaintEnginePrivate::PorterDuff_SupportedPrimitives)
+ || !d->simplePen
+ || d->clipType == QDirectFBPaintEnginePrivate::ComplexClip) {
RASTERFALLBACK(DRAW_LINES, lineCount, VOID_ARG(), VOID_ARG());
d->lock();
QRasterPaintEngine::drawLines(lines, lineCount);
@@ -393,7 +441,7 @@ void QDirectFBPaintEngine::drawLines(const QLine *lines, int lineCount)
if (pen != Qt::NoPen) {
d->unlock();
d->setDFBColor(pen.color());
- ::drawLines<QLine>(lines, lineCount, state()->matrix, d->surface);
+ CLIPPED_PAINT(::drawLines<QLine>(lines, lineCount, state()->matrix, d->surface));
}
}
@@ -401,7 +449,10 @@ void QDirectFBPaintEngine::drawLines(const QLineF *lines, int lineCount)
{
Q_D(QDirectFBPaintEngine);
d->updateClip();
- if (d->unsupportedCompositionMode || !d->simplePen || !d->dfbCanHandleClip()) {
+
+ if (!(d->compositionModeStatus & QDirectFBPaintEnginePrivate::PorterDuff_SupportedPrimitives)
+ || !d->simplePen
+ || d->clipType == QDirectFBPaintEnginePrivate::ComplexClip) {
RASTERFALLBACK(DRAW_LINES, lineCount, VOID_ARG(), VOID_ARG());
d->lock();
QRasterPaintEngine::drawLines(lines, lineCount);
@@ -412,7 +463,7 @@ void QDirectFBPaintEngine::drawLines(const QLineF *lines, int lineCount)
if (pen != Qt::NoPen) {
d->unlock();
d->setDFBColor(pen.color());
- ::drawLines<QLineF>(lines, lineCount, state()->matrix, d->surface);
+ CLIPPED_PAINT(::drawLines<QLineF>(lines, lineCount, state()->matrix, d->surface));
}
}
@@ -442,9 +493,9 @@ void QDirectFBPaintEngine::drawImage(const QRectF &r, const QImage &image,
d->updateClip();
#if !defined QT_NO_DIRECTFB_PREALLOCATED || defined QT_DIRECTFB_IMAGECACHE
- if (d->unsupportedCompositionMode
- || (d->transformationType & QDirectFBPaintEnginePrivate::BlitUnsupported)
- || !d->dfbCanHandleClip(r)
+ if (!(d->compositionModeStatus & QDirectFBPaintEnginePrivate::PorterDuff_SupportedBlits)
+ || (d->transformationType & QDirectFBPaintEnginePrivate::Matrix_BlitsUnsupported)
+ || d->clipType == QDirectFBPaintEnginePrivate::ComplexClip
#ifndef QT_DIRECTFB_IMAGECACHE
|| QDirectFBScreen::getSurfacePixelFormat(image.format()) == DSPF_UNKNOWN
#elif defined QT_NO_DIRECTFB_PREALLOCATED
@@ -463,7 +514,7 @@ void QDirectFBPaintEngine::drawImage(const QRectF &r, const QImage &image,
bool release;
IDirectFBSurface *imgSurface = d->getSurface(image, &release);
d->prepareForBlit(QDirectFBScreen::hasAlpha(imgSurface));
- d->blit(r, imgSurface, sr);
+ CLIPPED_PAINT(d->blit(r, imgSurface, sr));
if (release) {
#if (Q_DIRECTFB_VERSION >= 0x010000)
d->surface->ReleaseSource(d->surface);
@@ -482,15 +533,15 @@ void QDirectFBPaintEngine::drawPixmap(const QRectF &r, const QPixmap &pixmap,
const QRectF &sr)
{
Q_D(QDirectFBPaintEngine);
- d->updateClip();
+ d->updateClip();
if (pixmap.pixmapData()->classId() != QPixmapData::DirectFBClass) {
RASTERFALLBACK(DRAW_PIXMAP, r, pixmap.size(), sr);
d->lock();
QRasterPaintEngine::drawPixmap(r, pixmap, sr);
- } else if (d->unsupportedCompositionMode
- || (d->transformationType & QDirectFBPaintEnginePrivate::BlitUnsupported)
- || !d->dfbCanHandleClip(r)) {
+ } else if (!(d->compositionModeStatus & QDirectFBPaintEnginePrivate::PorterDuff_SupportedBlits)
+ || (d->transformationType & QDirectFBPaintEnginePrivate::Matrix_BlitsUnsupported)
+ || d->clipType == QDirectFBPaintEnginePrivate::ComplexClip) {
RASTERFALLBACK(DRAW_PIXMAP, r, pixmap.size(), sr);
const QImage *img = static_cast<QDirectFBPixmapData*>(pixmap.pixmapData())->buffer(DSLF_READ);
d->lock();
@@ -503,7 +554,8 @@ void QDirectFBPaintEngine::drawPixmap(const QRectF &r, const QPixmap &pixmap,
QDirectFBPixmapData *dfbData = static_cast<QDirectFBPixmapData*>(data);
dfbData->unlockDirectFB();
IDirectFBSurface *s = dfbData->directFBSurface();
- d->blit(r, s, sr);
+
+ CLIPPED_PAINT(d->blit(r, s, sr));
}
}
@@ -522,9 +574,9 @@ void QDirectFBPaintEngine::drawTiledPixmap(const QRectF &r,
RASTERFALLBACK(DRAW_TILED_PIXMAP, r, pixmap.size(), offset);
d->lock();
QRasterPaintEngine::drawTiledPixmap(r, pixmap, offset);
- } else if (d->unsupportedCompositionMode
- || (d->transformationType & QDirectFBPaintEnginePrivate::BlitUnsupported)
- || !d->dfbCanHandleClip(r)) {
+ } else if (!(d->compositionModeStatus & QDirectFBPaintEnginePrivate::PorterDuff_SupportedBlits)
+ || (d->transformationType & QDirectFBPaintEnginePrivate::Matrix_BlitsUnsupported)
+ || d->clipType == QDirectFBPaintEnginePrivate::ComplexClip) {
RASTERFALLBACK(DRAW_TILED_PIXMAP, r, pixmap.size(), offset);
const QImage *img = static_cast<QDirectFBPixmapData*>(pixmap.pixmapData())->buffer(DSLF_READ);
d->lock();
@@ -623,30 +675,34 @@ void QDirectFBPaintEngine::fillRect(const QRectF &rect, const QBrush &brush)
if (brush.style() == Qt::NoBrush)
return;
d->updateClip();
- if (!d->unsupportedCompositionMode
- && !(d->transformationType & (QDirectFBPaintEnginePrivate::RectsUnsupported))
- && d->dfbCanHandleClip(rect)) {
+ if (d->clipType != QDirectFBPaintEnginePrivate::ComplexClip) {
switch (brush.style()) {
case Qt::SolidPattern: {
+ if (!(d->compositionModeStatus & QDirectFBPaintEnginePrivate::PorterDuff_SupportedPrimitives)
+ || (d->transformationType & QDirectFBPaintEnginePrivate::Matrix_RectsUnsupported)) {
+ break;
+ }
const QColor color = brush.color();
if (!color.isValid())
return;
d->unlock();
d->setDFBColor(color);
const QRect r = state()->matrix.mapRect(rect).toRect();
- d->surface->FillRectangle(d->surface, r.x(), r.y(),
- r.width(), r.height());
+ CLIPPED_PAINT(d->surface->FillRectangle(d->surface, r.x(), r.y(), r.width(), r.height()));
return; }
+
case Qt::TexturePattern: {
- if (d->transformationType & QDirectFBPaintEnginePrivate::NegativeScale)
+ if (!(d->compositionModeStatus & QDirectFBPaintEnginePrivate::PorterDuff_SupportedBlits)
+ || (d->transformationType & QDirectFBPaintEnginePrivate::Matrix_BlitsUnsupported)) {
break;
+ }
const QPixmap texture = brush.texture();
if (texture.pixmapData()->classId() != QPixmapData::DirectFBClass)
break;
d->unlock();
- d->drawTiledPixmap(rect, texture, rect.topLeft() - state()->brushOrigin);
+ CLIPPED_PAINT(d->drawTiledPixmap(rect, texture, rect.topLeft() - state()->brushOrigin));
return; }
default:
break;
@@ -663,9 +719,9 @@ void QDirectFBPaintEngine::fillRect(const QRectF &rect, const QColor &color)
return;
Q_D(QDirectFBPaintEngine);
d->updateClip();
- if (d->unsupportedCompositionMode
- || (d->transformationType & QDirectFBPaintEnginePrivate::RectsUnsupported)
- || !d->dfbCanHandleClip()) {
+ if (!(d->compositionModeStatus & QDirectFBPaintEnginePrivate::PorterDuff_SupportedPrimitives)
+ || (d->transformationType & QDirectFBPaintEnginePrivate::Matrix_RectsUnsupported)
+ || d->clipType == QDirectFBPaintEnginePrivate::ComplexClip) {
RASTERFALLBACK(FILL_RECT, rect, color, VOID_ARG());
d->lock();
QRasterPaintEngine::fillRect(rect, color);
@@ -699,9 +755,7 @@ void QDirectFBPaintEngine::initImageCache(int size)
{
Q_ASSERT(size >= 0);
imageCache.setMaxCost(size);
- typedef void (*_qt_image_cleanup_hook_64)(qint64);
- extern Q_GUI_EXPORT _qt_image_cleanup_hook_64 qt_image_cleanup_hook_64;
- qt_image_cleanup_hook_64 = ::cachedImageCleanupHook;
+ QImagePixmapCleanupHooks::instance()->addImageHook(cachedImageCleanupHook);
}
#endif // QT_DIRECTFB_IMAGECACHE
@@ -712,11 +766,10 @@ void QDirectFBPaintEngine::initImageCache(int size)
QDirectFBPaintEnginePrivate::QDirectFBPaintEnginePrivate(QDirectFBPaintEngine *p)
: surface(0), antialiased(false), simplePen(false),
transformationType(0), opacity(255), dirtyClip(true),
- dfbHandledClip(false), dfbDevice(0),
- unsupportedCompositionMode(false), q(p)
+ clipType(ClipUnset), dfbDevice(0),
+ compositionModeStatus(0), q(p)
{
fb = QDirectFBScreen::instance()->dfb();
- ignoreSystemClip = QDirectFBScreen::instance()->directFBFlags() & QDirectFBScreen::IgnoreSystemClip;
surfaceCache = new SurfaceCache;
}
@@ -725,23 +778,6 @@ QDirectFBPaintEnginePrivate::~QDirectFBPaintEnginePrivate()
delete surfaceCache;
}
-bool QDirectFBPaintEnginePrivate::dfbCanHandleClip(const QRect &) const
-{
- // TODO: Check to see if DirectFB can handle the clip for the given rect
- return dfbHandledClip;
-}
-
-bool QDirectFBPaintEnginePrivate::dfbCanHandleClip(const QRectF &) const
-{
- // TODO: Check to see if DirectFB can handle the clip for the given rect
- return dfbHandledClip;
-}
-
-bool QDirectFBPaintEnginePrivate::dfbCanHandleClip() const
-{
- return dfbHandledClip;
-}
-
bool QDirectFBPaintEnginePrivate::isSimpleBrush(const QBrush &brush) const
{
return (brush.style() == Qt::NoBrush) || (brush.style() == Qt::SolidPattern && !antialiased);
@@ -769,7 +805,7 @@ void QDirectFBPaintEnginePrivate::setTransform(const QTransform &transform)
{
transformationType = transform.type();
if (qMin(transform.m11(), transform.m22()) < 0) {
- transformationType |= QDirectFBPaintEnginePrivate::NegativeScale;
+ transformationType |= QDirectFBPaintEnginePrivate::Matrix_NegativeScale;
}
setPen(q->state()->pen);
}
@@ -791,7 +827,53 @@ void QDirectFBPaintEnginePrivate::setPen(const QPen &pen)
void QDirectFBPaintEnginePrivate::setCompositionMode(QPainter::CompositionMode mode)
{
- unsupportedCompositionMode = (mode != QPainter::CompositionMode_SourceOver);
+ if (!surface)
+ return;
+ compositionModeStatus = PorterDuff_SupportedBlits;
+ switch (mode) {
+ case QPainter::CompositionMode_Clear:
+ surface->SetPorterDuff(surface, DSPD_CLEAR);
+ break;
+ case QPainter::CompositionMode_Source:
+ surface->SetPorterDuff(surface, DSPD_SRC);
+ break;
+ case QPainter::CompositionMode_SourceOver:
+ compositionModeStatus |= PorterDuff_SupportedPrimitives;
+ surface->SetPorterDuff(surface, DSPD_SRC_OVER);
+ break;
+ case QPainter::CompositionMode_DestinationOver:
+ surface->SetPorterDuff(surface, DSPD_DST_OVER);
+ break;
+ case QPainter::CompositionMode_SourceIn:
+ surface->SetPorterDuff(surface, DSPD_SRC_IN);
+ break;
+ case QPainter::CompositionMode_DestinationIn:
+ surface->SetPorterDuff(surface, DSPD_DST_IN);
+ break;
+ case QPainter::CompositionMode_SourceOut:
+ surface->SetPorterDuff(surface, DSPD_SRC_OUT);
+ break;
+ case QPainter::CompositionMode_DestinationOut:
+ surface->SetPorterDuff(surface, DSPD_DST_OUT);
+ break;
+#if (Q_DIRECTFB_VERSION >= 0x010000)
+ case QPainter::CompositionMode_SourceAtop:
+ surface->SetPorterDuff(surface, DSPD_SRC_ATOP);
+ break;
+ case QPainter::CompositionMode_DestinationAtop:
+ surface->SetPorterDuff(surface, DSPD_DST_ATOP);
+ break;
+ case QPainter::CompositionMode_Plus:
+ surface->SetPorterDuff(surface, DSPD_ADD);
+ break;
+#endif
+ case QPainter::CompositionMode_Xor:
+ surface->SetPorterDuff(surface, DSPD_XOR);
+ break;
+ default:
+ compositionModeStatus = 0;
+ break;
+ }
}
void QDirectFBPaintEnginePrivate::setRenderHints(QPainter::RenderHints hints)
@@ -897,7 +979,7 @@ static inline qreal fixCoord(qreal rect_pos, qreal pixmapSize, qreal offset)
void QDirectFBPaintEnginePrivate::drawTiledPixmap(const QRectF &dest, const QPixmap &pixmap, const QPointF &off)
{
Q_ASSERT(!dirtyClip);
- Q_ASSERT(!(transformationType & BlitUnsupported));
+ Q_ASSERT(!(transformationType & Matrix_BlitsUnsupported));
const QTransform &transform = q->state()->matrix;
const QRect destinationRect = transform.mapRect(dest).toRect().normalized();
QRect newClip = destinationRect;
@@ -910,8 +992,8 @@ void QDirectFBPaintEnginePrivate::drawTiledPixmap(const QRectF &dest, const QPix
const DFBRegion clip = {
newClip.x(),
newClip.y(),
- newClip.x() + newClip.width() - 1,
- newClip.y() + newClip.height() - 1
+ newClip.right(),
+ newClip.bottom()
};
surface->SetClip(surface, &clip);
@@ -980,8 +1062,8 @@ void QDirectFBPaintEnginePrivate::drawTiledPixmap(const QRectF &dest, const QPix
const DFBRegion clip = {
currentClip.x(),
currentClip.y(),
- currentClip.x() + currentClip.width(),
- currentClip.y() + currentClip.height()
+ currentClip.right(),
+ currentClip.bottom()
};
surface->SetClip(surface, &clip);
}
@@ -996,22 +1078,22 @@ void QDirectFBPaintEnginePrivate::updateClip()
const QClipData *clipData = clip();
if (!clipData || !clipData->enabled) {
surface->SetClip(surface, NULL);
- dfbHandledClip = true;
+ clipType = NoClip;
} else if (clipData->hasRectClip) {
const DFBRegion r = {
clipData->clipRect.x(),
clipData->clipRect.y(),
- clipData->clipRect.x() + clipData->clipRect.width(),
- clipData->clipRect.y() + clipData->clipRect.height()
+ clipData->clipRect.right(),
+ clipData->clipRect.bottom()
};
surface->SetClip(surface, &r);
currentClip = clipData->clipRect.normalized();
// ### is this guaranteed to always be normalized?
- dfbHandledClip = true;
- } else if (clipData->hasRegionClip && ignoreSystemClip && clipData->clipRegion == systemClip) {
- dfbHandledClip = true;
+ clipType = RectClip;
+ } else if (clipData->hasRegionClip) {
+ clipType = RegionClip;
} else {
- dfbHandledClip = false;
+ clipType = ComplexClip;
}
dirtyClip = false;
@@ -1108,7 +1190,7 @@ template <> inline const bool* ptr<bool>(const bool &) { return 0; }
template <typename device, typename T1, typename T2, typename T3>
static void rasterFallbackWarn(const char *msg, const char *func, const device *dev,
uint transformationType, bool simplePen,
- bool dfbHandledClip, bool unsupportedCompositionMode,
+ uint clipType, uint compositionModeStatus,
const char *nameOne, const T1 &one,
const char *nameTwo, const T2 &two,
const char *nameThree, const T3 &three)
@@ -1124,8 +1206,8 @@ static void rasterFallbackWarn(const char *msg, const char *func, const device *
dbg << QString("transformationType 0x%1").arg(transformationType, 3, 16, QLatin1Char('0'))
<< "simplePen" << simplePen
- << "dfbHandledClip" << dfbHandledClip
- << "unsupportedCompositionMode" << unsupportedCompositionMode;
+ << "clipType" << clipType
+ << "compositionModeStatus" << compositionModeStatus;
const T1 *t1 = ptr(one);
const T2 *t2 = ptr(two);
@@ -1142,7 +1224,6 @@ static void rasterFallbackWarn(const char *msg, const char *func, const device *
}
qWarning("%s", qPrintable(out));
}
-#endif
-
+#endif // QT_DIRECTFB_WARN_ON_RASTERFALLBACKS
#endif // QT_NO_DIRECTFB
diff --git a/src/plugins/gfxdrivers/directfb/qdirectfbpixmap.cpp b/src/plugins/gfxdrivers/directfb/qdirectfbpixmap.cpp
index 52e85ba..bedd9e5 100644
--- a/src/plugins/gfxdrivers/directfb/qdirectfbpixmap.cpp
+++ b/src/plugins/gfxdrivers/directfb/qdirectfbpixmap.cpp
@@ -49,9 +49,9 @@
static int global_ser_no = 0;
-QDirectFBPixmapData::QDirectFBPixmapData(PixelType pixelType)
- : QPixmapData(pixelType, DirectFBClass),
- engine(0), format(QImage::Format_Invalid), alpha(false)
+QDirectFBPixmapData::QDirectFBPixmapData(QDirectFBScreen *screen, PixelType pixelType)
+ : QPixmapData(pixelType, DirectFBClass), QDirectFBPaintDevice(screen),
+ format(QImage::Format_Invalid), alpha(false)
{
setSerialNumber(0);
}
@@ -61,7 +61,6 @@ QDirectFBPixmapData::~QDirectFBPixmapData()
unlockDirectFB();
if (dfbSurface && QDirectFBScreen::instance())
screen->releaseDFBSurface(dfbSurface);
- delete engine;
}
void QDirectFBPixmapData::resize(int width, int height)
@@ -304,7 +303,7 @@ QPixmap QDirectFBPixmapData::transformed(const QTransform &transform,
Q_ASSERT(image);
const QImage transformed = image->transformed(transform, mode);
that->unlockDirectFB();
- QDirectFBPixmapData *data = new QDirectFBPixmapData(QPixmapData::PixmapType);
+ QDirectFBPixmapData *data = new QDirectFBPixmapData(screen, QPixmapData::PixmapType);
data->fromImage(transformed, Qt::AutoColor);
return QPixmap(data);
}
@@ -314,7 +313,7 @@ QPixmap QDirectFBPixmapData::transformed(const QTransform &transform,
if (size.isEmpty())
return QPixmap();
- QDirectFBPixmapData *data = new QDirectFBPixmapData(QPixmapData::PixmapType);
+ QDirectFBPixmapData *data = new QDirectFBPixmapData(screen, QPixmapData::PixmapType);
DFBSurfaceBlittingFlags flags = DSBLIT_NOFX;
data->alpha = alpha;
if (alpha) {
@@ -373,6 +372,8 @@ QImage QDirectFBPixmapData::toImage() const
return img->copy();
}
+/* This is QPixmapData::paintEngine(), not QPaintDevice::paintEngine() */
+
QPaintEngine *QDirectFBPixmapData::paintEngine() const
{
if (!engine) {
diff --git a/src/plugins/gfxdrivers/directfb/qdirectfbpixmap.h b/src/plugins/gfxdrivers/directfb/qdirectfbpixmap.h
index 0204061..df3c679 100644
--- a/src/plugins/gfxdrivers/directfb/qdirectfbpixmap.h
+++ b/src/plugins/gfxdrivers/directfb/qdirectfbpixmap.h
@@ -56,7 +56,7 @@ class QDirectFBPaintEngine;
class QDirectFBPixmapData : public QPixmapData, public QDirectFBPaintDevice
{
public:
- QDirectFBPixmapData(PixelType pixelType);
+ QDirectFBPixmapData(QDirectFBScreen *screen, PixelType pixelType);
~QDirectFBPixmapData();
// Re-implemented from QPixmapData:
@@ -79,7 +79,6 @@ public:
inline bool hasAlphaChannel() const { return alpha; }
private:
void invalidate();
- QDirectFBPaintEngine *engine;
QImage::Format format;
bool alpha;
};
diff --git a/src/plugins/gfxdrivers/directfb/qdirectfbscreen.cpp b/src/plugins/gfxdrivers/directfb/qdirectfbscreen.cpp
index 030e51f..4f8fa2f 100644
--- a/src/plugins/gfxdrivers/directfb/qdirectfbscreen.cpp
+++ b/src/plugins/gfxdrivers/directfb/qdirectfbscreen.cpp
@@ -57,7 +57,7 @@
class QDirectFBScreenPrivate : public QObject, public QWSGraphicsSystem
{
public:
- QDirectFBScreenPrivate(QDirectFBScreen*);
+ QDirectFBScreenPrivate(QDirectFBScreen *qptr);
~QDirectFBScreenPrivate();
void setFlipFlags(const QStringList &args);
@@ -82,10 +82,11 @@ public:
QDirectFBScreen::DirectFBFlags directFBFlags;
QImage::Format alphaPixmapFormat;
QColor backgroundColor;
+ QDirectFBScreen *q;
};
-QDirectFBScreenPrivate::QDirectFBScreenPrivate(QDirectFBScreen *screen)
- : QWSGraphicsSystem(screen), dfb(0), dfbSurface(0), flipFlags(DSFLIP_NONE)
+QDirectFBScreenPrivate::QDirectFBScreenPrivate(QDirectFBScreen *qptr)
+ : QWSGraphicsSystem(qptr), dfb(0), dfbSurface(0), flipFlags(DSFLIP_NONE)
#ifndef QT_NO_DIRECTFB_LAYER
, dfbLayer(0)
#endif
@@ -98,6 +99,7 @@ QDirectFBScreenPrivate::QDirectFBScreenPrivate(QDirectFBScreen *screen)
#endif
, directFBFlags(QDirectFBScreen::NoFlags)
, alphaPixmapFormat(QImage::Format_Invalid)
+ , q(qptr)
{
#ifndef QT_NO_QWS_SIGNALHANDLER
QWSSignalHandler::instance()->addObject(this);
@@ -742,7 +744,7 @@ QPixmapData *QDirectFBScreenPrivate::createPixmapData(QPixmapData::PixelType typ
if (type == QPixmapData::BitmapType)
return QWSGraphicsSystem::createPixmapData(type);
- return new QDirectFBPixmapData(type);
+ return new QDirectFBPixmapData(q, type);
}
#if (Q_DIRECTFB_VERSION >= 0x000923)
@@ -914,9 +916,6 @@ bool QDirectFBScreen::connect(const QString &displaySpec)
QDirectFBPaintEngine::initImageCache(imageCacheSize);
#endif
- if (displayArgs.contains(QLatin1String("ignoresystemclip"), Qt::CaseInsensitive))
- d_ptr->directFBFlags |= IgnoreSystemClip;
-
#ifndef QT_NO_DIRECTFB_WM
if (displayArgs.contains(QLatin1String("fullscreen")))
#endif
@@ -1328,15 +1327,15 @@ void QDirectFBScreen::flipSurface(IDirectFBSurface *surface, DFBSurfaceFlipFlags
for (int i=0; i<rects.size(); ++i) {
const QRect &r = rects.at(i);
const DFBRegion dfbReg = { r.x() + offset.x(), r.y() + offset.y(),
- r.x() + r.width() + offset.x(),
- r.y() + r.height() + offset.y() };
+ r.right() + offset.x(),
+ r.bottom() + offset.y() };
surface->Flip(surface, &dfbReg, i + 1 < rects.size() ? nonWaitFlags : flipFlags);
}
} else {
const QRect r = region.boundingRect();
const DFBRegion dfbReg = { r.x() + offset.x(), r.y() + offset.y(),
- r.x() + r.width() + offset.x(),
- r.y() + r.height() + offset.y() };
+ r.right() + offset.x(),
+ r.bottom() + offset.y() };
surface->Flip(surface, &dfbReg, flipFlags);
}
}
diff --git a/src/plugins/gfxdrivers/directfb/qdirectfbscreen.h b/src/plugins/gfxdrivers/directfb/qdirectfbscreen.h
index 63c608e..8884a06 100644
--- a/src/plugins/gfxdrivers/directfb/qdirectfbscreen.h
+++ b/src/plugins/gfxdrivers/directfb/qdirectfbscreen.h
@@ -79,8 +79,7 @@ public:
NoFlags = 0x00,
VideoOnly = 0x01,
SystemOnly = 0x02,
- IgnoreSystemClip = 0x04,
- BoundingRectFlip = 0x08
+ BoundingRectFlip = 0x04
};
Q_DECLARE_FLAGS(DirectFBFlags, DirectFBFlag);
diff --git a/src/plugins/gfxdrivers/directfb/qdirectfbwindowsurface.cpp b/src/plugins/gfxdrivers/directfb/qdirectfbwindowsurface.cpp
index a1009ac..34168bc 100644
--- a/src/plugins/gfxdrivers/directfb/qdirectfbwindowsurface.cpp
+++ b/src/plugins/gfxdrivers/directfb/qdirectfbwindowsurface.cpp
@@ -55,7 +55,7 @@ QDirectFBWindowSurface::QDirectFBWindowSurface(DFBSurfaceFlipFlags flip, QDirect
#ifndef QT_NO_DIRECTFB_WM
, dfbWindow(0)
#endif
- , engine(0)
+ , engineHeight(-1)
, flipFlags(flip)
, boundingRectFlip(scr->directFBFlags() & QDirectFBScreen::BoundingRectFlip)
{
@@ -76,7 +76,7 @@ QDirectFBWindowSurface::QDirectFBWindowSurface(DFBSurfaceFlipFlags flip, QDirect
#ifndef QT_NO_DIRECTFB_WM
, dfbWindow(0)
#endif
- , engine(0)
+ , engineHeight(-1)
, flipFlags(flip)
, boundingRectFlip(scr->directFBFlags() & QDirectFBScreen::BoundingRectFlip)
{
@@ -209,7 +209,6 @@ void QDirectFBWindowSurface::setGeometry(const QRect &rect)
if (!dfbWindow)
createWindow();
::setGeometry(dfbWindow, oldRect, rect);
- // ### do I need to release and get the surface again here?
#endif
break;
case Offscreen: {
@@ -227,7 +226,10 @@ void QDirectFBWindowSurface::setGeometry(const QRect &rect)
if (result != DFB_OK)
DirectFBErrorFatal("QDirectFBWindowSurface::setGeometry()", result);
}
-
+ if (engine) {
+ delete engine;
+ engine = 0;
+ }
QWSWindowSurface::setGeometry(rect);
}
@@ -293,16 +295,6 @@ bool QDirectFBWindowSurface::move(const QPoint &moveBy)
return true;
}
-QPaintEngine *QDirectFBWindowSurface::paintEngine() const
-{
- if (!engine) {
- QDirectFBWindowSurface *that = const_cast<QDirectFBWindowSurface*>(this);
- that->engine = new QDirectFBPaintEngine(that);
- return that->engine;
- }
- return engine;
-}
-
// hw: XXX: copied from QWidgetPrivate::isOpaque()
inline bool isWidgetOpaque(const QWidget *w)
{
@@ -427,6 +419,12 @@ void QDirectFBWindowSurface::flush(QWidget *, const QRegion &region,
void QDirectFBWindowSurface::beginPaint(const QRegion &)
{
+ const int h = height();
+ if (h > engineHeight) {
+ engineHeight = h;
+ delete engine;
+ engine = new QDirectFBPaintEngine(this);
+ }
}
void QDirectFBWindowSurface::endPaint(const QRegion &)
diff --git a/src/plugins/gfxdrivers/directfb/qdirectfbwindowsurface.h b/src/plugins/gfxdrivers/directfb/qdirectfbwindowsurface.h
index c46d93b..fefe9f3 100644
--- a/src/plugins/gfxdrivers/directfb/qdirectfbwindowsurface.h
+++ b/src/plugins/gfxdrivers/directfb/qdirectfbwindowsurface.h
@@ -61,8 +61,8 @@ QT_MODULE(Gui)
class QDirectFBWindowSurface : public QWSWindowSurface, public QDirectFBPaintDevice
{
public:
- QDirectFBWindowSurface(DFBSurfaceFlipFlags flipFlags, QDirectFBScreen* scr);
- QDirectFBWindowSurface(DFBSurfaceFlipFlags flipFlags, QDirectFBScreen* scr, QWidget *widget);
+ QDirectFBWindowSurface(DFBSurfaceFlipFlags flipFlags, QDirectFBScreen *scr);
+ QDirectFBWindowSurface(DFBSurfaceFlipFlags flipFlags, QDirectFBScreen *scr, QWidget *widget);
~QDirectFBWindowSurface();
bool isValid() const;
@@ -79,7 +79,6 @@ public:
QImage image() const { return QImage(); }
QPaintDevice *paintDevice() { return this; }
- QPaintEngine *paintEngine() const;
void flush(QWidget *widget, const QRegion &region, const QPoint &offset);
@@ -92,7 +91,7 @@ private:
void createWindow();
IDirectFBWindow *dfbWindow;
#endif
- QDirectFBPaintEngine *engine;
+ int engineHeight;
enum Mode {
Primary,
diff --git a/src/plugins/plugins.pro b/src/plugins/plugins.pro
index cf4edf1..45669e4 100644
--- a/src/plugins/plugins.pro
+++ b/src/plugins/plugins.pro
@@ -10,3 +10,4 @@ unix {
embedded:SUBDIRS *= gfxdrivers decorations mousedrivers kbddrivers
!win32:!embedded:!mac:SUBDIRS *= inputmethods
contains(QT_CONFIG, phonon): SUBDIRS *= phonon
+contains(QT_CONFIG, multimedia): SUBDIRS *= audio
diff --git a/src/sql/drivers/mysql/qsql_mysql.cpp b/src/sql/drivers/mysql/qsql_mysql.cpp
index bfd65fc..39ef1ef 100644
--- a/src/sql/drivers/mysql/qsql_mysql.cpp
+++ b/src/sql/drivers/mysql/qsql_mysql.cpp
@@ -85,11 +85,10 @@ public:
#else
tc(0),
#endif
- preparedQuerys(false), preparedQuerysEnabled(false) {}
+ preparedQuerysEnabled(false) {}
MYSQL *mysql;
QTextCodec *tc;
- bool preparedQuerys;
bool preparedQuerysEnabled;
};
@@ -172,6 +171,7 @@ public:
#if MYSQL_VERSION_ID >= 40108
, stmt(0), meta(0), inBinds(0), outBinds(0)
#endif
+ , preparedQuery(false)
{
connect(dp, SIGNAL(destroyed()), this, SLOT(driverDestroyed()));
}
@@ -209,6 +209,9 @@ public:
MYSQL_BIND *inBinds;
MYSQL_BIND *outBinds;
#endif
+
+ bool preparedQuery;
+
private Q_SLOTS:
void driverDestroyed() { driver = NULL; }
};
@@ -399,7 +402,7 @@ QMYSQLResult::~QMYSQLResult()
QVariant QMYSQLResult::handle() const
{
#if MYSQL_VERSION_ID >= 40108
- if(d->driver && d->driver->d->preparedQuerys)
+ if(d->preparedQuery)
return d->meta ? qVariantFromValue(d->meta) : qVariantFromValue(d->stmt);
else
#endif
@@ -454,9 +457,6 @@ void QMYSQLResult::cleanup()
d->row = NULL;
setAt(-1);
setActive(false);
-
- if(d->driver)
- d->driver->d->preparedQuerys = d->driver->d->preparedQuerysEnabled;
}
bool QMYSQLResult::fetch(int i)
@@ -474,7 +474,7 @@ bool QMYSQLResult::fetch(int i)
}
if (at() == i)
return true;
- if (d->driver->d->preparedQuerys) {
+ if (d->preparedQuery) {
#if MYSQL_VERSION_ID >= 40108
mysql_stmt_data_seek(d->stmt, i);
@@ -507,7 +507,7 @@ bool QMYSQLResult::fetchNext()
{
if(!d->driver)
return false;
- if (d->driver->d->preparedQuerys) {
+ if (d->preparedQuery) {
#if MYSQL_VERSION_ID >= 40108
if (mysql_stmt_fetch(d->stmt))
return false;
@@ -534,7 +534,7 @@ bool QMYSQLResult::fetchLast()
}
my_ulonglong numRows;
- if (d->driver->d->preparedQuerys) {
+ if (d->preparedQuery) {
#if MYSQL_VERSION_ID >= 40108
numRows = mysql_stmt_num_rows(d->stmt);
#else
@@ -574,7 +574,7 @@ QVariant QMYSQLResult::data(int field)
int fieldLength = 0;
const QMYSQLResultPrivate::QMyField &f = d->fields.at(field);
QString val;
- if (d->driver->d->preparedQuerys) {
+ if (d->preparedQuery) {
if (f.nullIndicator)
return QVariant(f.type);
@@ -634,7 +634,7 @@ QVariant QMYSQLResult::data(int field)
case QVariant::ByteArray: {
QByteArray ba;
- if (d->driver->d->preparedQuerys) {
+ if (d->preparedQuery) {
ba = QByteArray(f.outField, f.bufLength);
} else {
ba = QByteArray(d->row[field], fieldLength);
@@ -651,7 +651,7 @@ QVariant QMYSQLResult::data(int field)
bool QMYSQLResult::isNull(int field)
{
- if (d->driver->d->preparedQuerys)
+ if (d->preparedQuery)
return d->fields.at(field).nullIndicator;
else
return d->row[field] == NULL;
@@ -662,11 +662,9 @@ bool QMYSQLResult::reset (const QString& query)
if (!driver() || !driver()->isOpen() || driver()->isOpenError() || !d->driver)
return false;
- if(d->driver->d->preparedQuerysEnabled && prepare(query)) {
- d->driver->d->preparedQuerys = true;
- return exec();
- }
- d->driver->d->preparedQuerys = false;
+ d->preparedQuery = false;
+
+ cleanup();
const QByteArray encQuery(fromUnicode(d->driver->d->tc, query));
if (mysql_real_query(d->driver->d->mysql, encQuery.data(), encQuery.length())) {
@@ -699,7 +697,7 @@ bool QMYSQLResult::reset (const QString& query)
int QMYSQLResult::size()
{
if (d->driver && isSelect())
- if (d->driver->d->preparedQuerys)
+ if (d->preparedQuery)
#if MYSQL_VERSION_ID >= 40108
return mysql_stmt_num_rows(d->stmt);
#else
@@ -721,7 +719,7 @@ QVariant QMYSQLResult::lastInsertId() const
if (!isActive() || !d->driver)
return QVariant();
- if (d->driver->d->preparedQuerys) {
+ if (d->preparedQuery) {
#if MYSQL_VERSION_ID >= 40108
quint64 id = mysql_stmt_insert_id(d->stmt);
if (id)
@@ -743,7 +741,7 @@ QSqlRecord QMYSQLResult::record() const
return info;
#if MYSQL_VERSION_ID >= 40108
- res = d->driver->d->preparedQuerys ? d->meta : d->result;
+ res = d->preparedQuery ? d->meta : d->result;
#else
res = d->result;
#endif
@@ -856,7 +854,7 @@ bool QMYSQLResult::prepare(const QString& query)
return false;
#if MYSQL_VERSION_ID >= 40108
cleanup();
- if (!d->driver->d->preparedQuerys)
+ if (!d->driver->d->preparedQuerysEnabled)
return QSqlResult::prepare(query);
int r;
@@ -886,6 +884,7 @@ bool QMYSQLResult::prepare(const QString& query)
}
setSelect(d->bindInValues());
+ d->preparedQuery = true;
return true;
#else
return false;
@@ -896,7 +895,7 @@ bool QMYSQLResult::exec()
{
if (!d->driver)
return false;
- if (!d->driver->d->preparedQuerys)
+ if (!d->preparedQuery)
return QSqlResult::exec();
if (!d->stmt)
return false;
@@ -1338,9 +1337,6 @@ QSqlIndex QMYSQLDriver::primaryIndex(const QString& tablename) const
if (!isOpen())
return idx;
- prepQ = d->preparedQuerys;
- d->preparedQuerys = false;
-
QSqlQuery i(createResult());
QString stmt(QLatin1String("show index from %1;"));
QSqlRecord fil = record(tablename);
@@ -1353,7 +1349,6 @@ QSqlIndex QMYSQLDriver::primaryIndex(const QString& tablename) const
}
}
- d->preparedQuerys = prepQ;
return idx;
}
diff --git a/src/sql/drivers/psql/qsql_psql.cpp b/src/sql/drivers/psql/qsql_psql.cpp
index c61c526..4fd0c11 100644
--- a/src/sql/drivers/psql/qsql_psql.cpp
+++ b/src/sql/drivers/psql/qsql_psql.cpp
@@ -940,7 +940,7 @@ QSqlIndex QPSQLDriver::primaryIndex(const QString& tablename) const
case QPSQLDriver::Version6:
stmt = QLatin1String("select pg_att1.attname, int(pg_att1.atttypid), pg_cl.relname "
"from pg_attribute pg_att1, pg_attribute pg_att2, pg_class pg_cl, pg_index pg_ind "
- "where lower(pg_cl.relname) = '%1_pkey' "
+ "where pg_cl.relname = '%1_pkey' "
"and pg_cl.oid = pg_ind.indexrelid "
"and pg_att2.attrelid = pg_ind.indexrelid "
"and pg_att1.attrelid = pg_ind.indrelid "
@@ -951,7 +951,7 @@ QSqlIndex QPSQLDriver::primaryIndex(const QString& tablename) const
case QPSQLDriver::Version71:
stmt = QLatin1String("select pg_att1.attname, pg_att1.atttypid::int, pg_cl.relname "
"from pg_attribute pg_att1, pg_attribute pg_att2, pg_class pg_cl, pg_index pg_ind "
- "where lower(pg_cl.relname) = '%1_pkey' "
+ "where pg_cl.relname = '%1_pkey' "
"and pg_cl.oid = pg_ind.indexrelid "
"and pg_att2.attrelid = pg_ind.indexrelid "
"and pg_att1.attrelid = pg_ind.indrelid "
@@ -1016,7 +1016,7 @@ QSqlRecord QPSQLDriver::record(const QString& tablename) const
"pg_attribute.attnotnull, pg_attribute.attlen, pg_attribute.atttypmod, "
"int(pg_attribute.attrelid), pg_attribute.attnum "
"from pg_class, pg_attribute "
- "where lower(pg_class.relname) = '%1' "
+ "where pg_class.relname = '%1' "
"and pg_attribute.attnum > 0 "
"and pg_attribute.attrelid = pg_class.oid ");
break;
@@ -1025,7 +1025,7 @@ QSqlRecord QPSQLDriver::record(const QString& tablename) const
"pg_attribute.attnotnull, pg_attribute.attlen, pg_attribute.atttypmod, "
"pg_attribute.attrelid::int, pg_attribute.attnum "
"from pg_class, pg_attribute "
- "where lower(pg_class.relname) = '%1' "
+ "where pg_class.relname = '%1' "
"and pg_attribute.attnum > 0 "
"and pg_attribute.attrelid = pg_class.oid ");
break;
@@ -1036,7 +1036,7 @@ QSqlRecord QPSQLDriver::record(const QString& tablename) const
"from pg_class, pg_attribute "
"left join pg_attrdef on (pg_attrdef.adrelid = "
"pg_attribute.attrelid and pg_attrdef.adnum = pg_attribute.attnum) "
- "where lower(pg_class.relname) = '%1' "
+ "where pg_class.relname = '%1' "
"and pg_attribute.attnum > 0 "
"and pg_attribute.attrelid = pg_class.oid "
"order by pg_attribute.attnum ");
diff --git a/src/src.pro b/src/src.pro
index 34db728..54ed6da 100644
--- a/src/src.pro
+++ b/src/src.pro
@@ -22,6 +22,7 @@ contains(QT_CONFIG, opengl)|contains(QT_CONFIG, opengles1)|contains(QT_CONFIG, o
contains(QT_CONFIG, openvg): SRC_SUBDIRS += src_openvg
contains(QT_CONFIG, xmlpatterns): SRC_SUBDIRS += src_xmlpatterns
contains(QT_CONFIG, phonon): SRC_SUBDIRS += src_phonon
+contains(QT_CONFIG, multimedia): SRC_SUBDIRS += src_multimedia
contains(QT_CONFIG, svg): SRC_SUBDIRS += src_svg
contains(QT_CONFIG, webkit) {
#exists($$QT_SOURCE_TREE/src/3rdparty/webkit/JavaScriptCore/JavaScriptCore.pro): SRC_SUBDIRS += src_javascriptcore
@@ -68,6 +69,8 @@ src_qt3support.subdir = $$QT_SOURCE_TREE/src/qt3support
src_qt3support.target = sub-qt3support
src_phonon.subdir = $$QT_SOURCE_TREE/src/phonon
src_phonon.target = sub-phonon
+src_multimedia.subdir = $$QT_SOURCE_TREE/src/multimedia
+src_multimedia.target = sub-multimedia
src_tools_uic3.subdir = $$QT_SOURCE_TREE/src/tools/uic3
src_tools_uic3.target = sub-uic3
src_activeqt.subdir = $$QT_SOURCE_TREE/src/activeqt
@@ -104,6 +107,7 @@ src_webkit.target = sub-webkit
src_testlib.depends = src_corelib
src_qt3support.depends = src_gui src_xml src_network src_sql
src_phonon.depends = src_gui
+ src_multimedia.depends = src_gui
src_tools_uic3.depends = src_qt3support src_xml
src_tools_idc.depends = src_corelib
src_tools_activeqt.depends = src_tools_idc src_gui
diff --git a/src/svg/qsvggraphics.cpp b/src/svg/qsvggraphics.cpp
index e09f382..2be7559 100644
--- a/src/svg/qsvggraphics.cpp
+++ b/src/svg/qsvggraphics.cpp
@@ -266,21 +266,23 @@ void QSvgRect::draw(QPainter *p, QSvgExtraStates &states)
}
}
+QSvgTspan * const QSvgText::LINEBREAK = 0;
+
QSvgText::QSvgText(QSvgNode *parent, const QPointF &coord)
: QSvgNode(parent)
, m_coord(coord)
- , m_textAlignment(Qt::AlignLeft)
- , m_scale(1)
- , m_appendSpace(false)
, m_type(TEXT)
, m_size(0, 0)
+ , m_mode(Default)
{
- m_paragraphs.push_back(QString());
- m_formatRanges.push_back(QList<QTextLayout::FormatRange>());
}
QSvgText::~QSvgText()
{
+ for (int i = 0; i < m_tspans.size(); ++i) {
+ if (m_tspans[i] != LINEBREAK)
+ delete m_tspans[i];
+ }
}
void QSvgText::setTextArea(const QSizeF &size)
@@ -295,175 +297,173 @@ void QSvgText::draw(QPainter *p, QSvgExtraStates &states)
{
applyStyle(p, states);
- QSvgFontStyle *fontStyle = static_cast<QSvgFontStyle*>(
- styleProperty(QSvgStyleProperty::FONT));
- if (fontStyle && fontStyle->svgFont()) {
- // SVG fonts not fully supported...
- QString text = m_paragraphs.front();
- for (int i = 1; i < m_paragraphs.size(); ++i) {
- text.append(QLatin1Char('\n'));
- text.append(m_paragraphs[i]);
- }
- fontStyle->svgFont()->draw(p, m_coord, text, fontStyle->pointSize(), m_textAlignment);
- revertStyle(p, states);
- return;
- }
+ // Force the font to have a size of 100 pixels to avoid truncation problems
+ // when the font is very small.
+ qreal scale = 100.0 / p->font().pointSizeF();
+ Qt::Alignment alignment = states.textAnchor;
- // Scale the font to its correct size.
QTransform oldTransform = p->worldTransform();
- p->scale(1 / m_scale, 1 / m_scale);
+ p->scale(1 / scale, 1 / scale);
qreal y = 0;
bool initial = true;
- qreal px = m_coord.x() * m_scale;
- qreal py = m_coord.y() * m_scale;
- QSizeF scaledSize = m_size * m_scale;
+ qreal px = m_coord.x() * scale;
+ qreal py = m_coord.y() * scale;
+ QSizeF scaledSize = m_size * scale;
if (m_type == TEXTAREA) {
- if (m_textAlignment == Qt::AlignHCenter)
+ if (alignment == Qt::AlignHCenter)
px += scaledSize.width() / 2;
- else if (m_textAlignment == Qt::AlignRight)
+ else if (alignment == Qt::AlignRight)
px += scaledSize.width();
}
QRectF bounds;
if (m_size.height() != 0)
- bounds = QRectF(0, 0, 1, scaledSize.height());
-
- for (int i = 0; i < m_paragraphs.size(); ++i) {
- QTextLayout tl(m_paragraphs[i]);
- QTextOption op = tl.textOption();
- op.setWrapMode(QTextOption::WrapAtWordBoundaryOrAnywhere);
- tl.setTextOption(op);
- tl.setAdditionalFormats(m_formatRanges[i]);
- tl.beginLayout();
- forever {
- QTextLine line = tl.createLine();
- if (!line.isValid())
- break;
-
- if (m_size.width() != 0)
- line.setLineWidth(scaledSize.width());
- }
- tl.endLayout();
-
- bool endOfBoundsReached = false;
- for (int i = 0; i < tl.lineCount(); ++i) {
- QTextLine line = tl.lineAt(i);
-
- qreal x = 0;
- if (m_textAlignment == Qt::AlignHCenter)
- x -= line.naturalTextWidth() / 2;
- else if (m_textAlignment == Qt::AlignRight)
- x -= line.naturalTextWidth();
-
- if (initial && m_type == TEXT)
- y -= line.ascent();
- initial = false;
-
- line.setPosition(QPointF(x, y));
- if ((m_size.width() != 0 && line.naturalTextWidth() > scaledSize.width())
- || (m_size.height() != 0 && y + line.height() > scaledSize.height())) {
- bounds.setHeight(y);
- endOfBoundsReached = true;
- break;
+ bounds = QRectF(0, py, 1, scaledSize.height()); // x and width are not used.
+
+ bool appendSpace = false;
+ QVector<QString> paragraphs;
+ QStack<QTextCharFormat> formats;
+ QVector<QList<QTextLayout::FormatRange> > formatRanges;
+ paragraphs.push_back(QString());
+ formatRanges.push_back(QList<QTextLayout::FormatRange>());
+
+ for (int i = 0; i < m_tspans.size(); ++i) {
+ if (m_tspans[i] == LINEBREAK) {
+ if (m_type == TEXTAREA) {
+ if (paragraphs.back().isEmpty()) {
+ QFont font = p->font();
+ font.setPixelSize(font.pointSizeF() * scale);
+
+ QTextLayout::FormatRange range;
+ range.start = 0;
+ range.length = 1;
+ range.format.setFont(font);
+ formatRanges.back().append(range);
+
+ paragraphs.back().append(QLatin1Char(' '));;
+ }
+ appendSpace = false;
+ paragraphs.push_back(QString());
+ formatRanges.push_back(QList<QTextLayout::FormatRange>());
}
+ } else {
+ WhitespaceMode mode = m_tspans[i]->whitespaceMode();
+ m_tspans[i]->applyStyle(p, states);
- y += 1.1 * line.height();
- }
- tl.draw(p, QPointF(px, py), QVector<QTextLayout::FormatRange>(), bounds);
+ QFont font = p->font();
+ font.setPixelSize(font.pointSizeF() * scale);
- if (endOfBoundsReached)
- break;
- }
+ QString newText(m_tspans[i]->text());
+ newText.replace(QLatin1Char('\t'), QLatin1Char(' '));
+ newText.replace(QLatin1Char('\n'), QLatin1Char(' '));
- p->setWorldTransform(oldTransform, false);
- revertStyle(p, states);
-}
+ bool prependSpace = !appendSpace && !m_tspans[i]->isTspan() && (mode == Default) && !paragraphs.back().isEmpty() && newText.startsWith(QLatin1Char(' '));
+ if (appendSpace || prependSpace)
+ paragraphs.back().append(QLatin1Char(' '));
-void QSvgText::insertText(const QString &text, WhitespaceMode mode)
-{
- bool isTSpan = (m_formats.count() == 2);
- QString newText(text);
- newText.replace(QLatin1Char('\t'), QLatin1Char(' '));
- newText.replace(QLatin1Char('\n'), QLatin1Char(' '));
+ bool appendSpaceNext = (!m_tspans[i]->isTspan() && (mode == Default) && newText.endsWith(QLatin1Char(' ')));
- bool prependSpace = !m_appendSpace && !isTSpan && (mode == Default) && !m_paragraphs.back().isEmpty() && newText.startsWith(QLatin1Char(' '));
- if (m_appendSpace || prependSpace)
- m_paragraphs.back().append(QLatin1Char(' '));
+ if (mode == Default) {
+ newText = newText.simplified();
+ if (newText.isEmpty())
+ appendSpaceNext = false;
+ }
- bool appendSpaceNext = (!isTSpan && (mode == Default) && newText.endsWith(QLatin1Char(' ')));
+ QTextLayout::FormatRange range;
+ range.start = paragraphs.back().length();
+ range.length = newText.length();
+ range.format.setFont(font);
+ range.format.setTextOutline(p->pen());
+ range.format.setForeground(p->brush());
+
+ if (appendSpace) {
+ Q_ASSERT(!formatRanges.back().isEmpty());
+ ++formatRanges.back().back().length;
+ } else if (prependSpace) {
+ --range.start;
+ ++range.length;
+ }
+ formatRanges.back().append(range);
- if (mode == Default) {
- newText = newText.simplified();
- if (newText.isEmpty())
- appendSpaceNext = false;
- }
+ appendSpace = appendSpaceNext;
+ paragraphs.back() += newText;
- if (!m_formats.isEmpty()) {
- QTextLayout::FormatRange range;
- range.start = m_paragraphs.back().length();
- range.length = newText.length();
- range.format = m_formats.top();
- if (m_appendSpace) {
- Q_ASSERT(!m_formatRanges.back().isEmpty());
- ++m_formatRanges.back().back().length;
- } else if (prependSpace) {
- --range.start;
- ++range.length;
+ m_tspans[i]->revertStyle(p, states);
}
- m_formatRanges.back().append(range);
}
- m_appendSpace = appendSpaceNext;
- m_paragraphs.back() += newText;
-}
-
-void QSvgText::insertFormat(const QTextCharFormat &format)
-{
- QTextCharFormat mergedFormat = format;
- if (!m_formats.isEmpty()) {
- mergedFormat = m_formats.top();
- mergedFormat.merge(format);
- }
- m_formats.push(mergedFormat);
-}
+ if (states.svgFont) {
+ // SVG fonts not fully supported...
+ QString text = paragraphs.front();
+ for (int i = 1; i < paragraphs.size(); ++i) {
+ text.append(QLatin1Char('\n'));
+ text.append(paragraphs[i]);
+ }
+ states.svgFont->draw(p, m_coord, text, p->font().pointSizeF() * scale, states.textAnchor);
+ } else {
+ for (int i = 0; i < paragraphs.size(); ++i) {
+ QTextLayout tl(paragraphs[i]);
+ QTextOption op = tl.textOption();
+ op.setWrapMode(QTextOption::WrapAtWordBoundaryOrAnywhere);
+ tl.setTextOption(op);
+ tl.setAdditionalFormats(formatRanges[i]);
+ tl.beginLayout();
+
+ forever {
+ QTextLine line = tl.createLine();
+ if (!line.isValid())
+ break;
+ if (m_size.width() != 0)
+ line.setLineWidth(scaledSize.width());
+ }
+ tl.endLayout();
+
+ bool endOfBoundsReached = false;
+ for (int i = 0; i < tl.lineCount(); ++i) {
+ QTextLine line = tl.lineAt(i);
+
+ qreal x = 0;
+ if (alignment == Qt::AlignHCenter)
+ x -= 0.5 * line.naturalTextWidth();
+ else if (alignment == Qt::AlignRight)
+ x -= line.naturalTextWidth();
+
+ if (initial && m_type == TEXT)
+ y -= line.ascent();
+ initial = false;
+
+ line.setPosition(QPointF(x, y));
+
+ // Check if the current line fits into the bounding rectangle.
+ if ((m_size.width() != 0 && line.naturalTextWidth() > scaledSize.width())
+ || (m_size.height() != 0 && y + line.height() > scaledSize.height())) {
+ // I need to set the bounds height to 'y-epsilon' to avoid drawing the current
+ // line. Since the font is scaled to 100 units, 1 should be a safe epsilon.
+ bounds.setHeight(y - 1);
+ endOfBoundsReached = true;
+ break;
+ }
+
+ y += 1.1 * line.height();
+ }
+ tl.draw(p, QPointF(px, py), QVector<QTextLayout::FormatRange>(), bounds);
-void QSvgText::insertLineBreak()
-{
- if (m_type == TEXTAREA) {
- if (m_paragraphs.back().isEmpty())
- insertText(QLatin1String(" "), Preserve);
- m_appendSpace = false;
- m_paragraphs.push_back(QString());
- m_formatRanges.push_back(QList<QTextLayout::FormatRange>());
+ if (endOfBoundsReached)
+ break;
+ }
}
-}
-void QSvgText::popFormat()
-{
- if (m_formats.count() > 1)
- m_formats.pop();
-}
-
-qreal QSvgText::scale() const
-{
- return m_scale;
-}
-
-void QSvgText::setScale(qreal scale)
-{
- m_scale = scale;
-}
-
-const QTextCharFormat &QSvgText::topFormat() const
-{
- return m_formats.top();
+ p->setWorldTransform(oldTransform, false);
+ revertStyle(p, states);
}
-void QSvgText::setTextAlignment(const Qt::Alignment &alignment)
+void QSvgText::addText(const QString &text)
{
- m_textAlignment = alignment;
+ m_tspans.append(new QSvgTspan(this, false));
+ m_tspans.back()->setWhitespaceMode(m_mode);
+ m_tspans.back()->addText(text);
}
QSvgUse::QSvgUse(const QPointF &start, QSvgNode *parent, QSvgNode *node)
diff --git a/src/svg/qsvggraphics_p.h b/src/svg/qsvggraphics_p.h
index 4a19c7e..345b90b 100644
--- a/src/svg/qsvggraphics_p.h
+++ b/src/svg/qsvggraphics_p.h
@@ -187,6 +187,8 @@ private:
int m_rx, m_ry;
};
+class QSvgTspan;
+
class QSvgText : public QSvgNode
{
public:
@@ -202,26 +204,47 @@ public:
virtual void draw(QPainter *p, QSvgExtraStates &states);
virtual Type type() const;
- void insertText(const QString &text, WhitespaceMode mode);
- void insertFormat(const QTextCharFormat &format);
- void insertLineBreak();
- void popFormat();
- void setTextAlignment(const Qt::Alignment &alignment);
- const QTextCharFormat &topFormat() const;
- qreal scale() const;
- void setScale(qreal scale);
+
+ void addTspan(QSvgTspan *tspan) {m_tspans.append(tspan);}
+ void addText(const QString &text);
+ void addLineBreak() {m_tspans.append(LINEBREAK);}
+ void setWhitespaceMode(WhitespaceMode mode) {m_mode = mode;}
+
//virtual QRectF bounds() const;
private:
+ static QSvgTspan * const LINEBREAK;
+
QPointF m_coord;
- QVector<QString> m_paragraphs;
- QStack<QTextCharFormat> m_formats;
- Qt::Alignment m_textAlignment;
- QVector<QList<QTextLayout::FormatRange> > m_formatRanges;
- qreal m_scale;
- bool m_appendSpace;
+ // 'm_tspans' is also used to store characters outside tspans and line breaks.
+ // If a 'm_tspan' item is null, it indicates a line break.
+ QVector<QSvgTspan *> m_tspans;
+
Type m_type;
QSizeF m_size;
+ WhitespaceMode m_mode;
+};
+
+class QSvgTspan : public QSvgNode
+{
+public:
+ // tspans are also used to store normal text, so the 'isProperTspan' is used to separate text from tspan.
+ QSvgTspan(QSvgNode *parent, bool isProperTspan = true)
+ : QSvgNode(parent), m_mode(QSvgText::Default), m_isTspan(isProperTspan)
+ {
+ }
+ ~QSvgTspan() { };
+ virtual Type type() const {return TSPAN;}
+ virtual void draw(QPainter *, QSvgExtraStates &) {Q_ASSERT(!"Tspans should be drawn through QSvgText::draw().");}
+ void addText(const QString &text) {m_text += text;}
+ const QString &text() const {return m_text;}
+ bool isTspan() const {return m_isTspan;}
+ void setWhitespaceMode(QSvgText::WhitespaceMode mode) {m_mode = mode;}
+ QSvgText::WhitespaceMode whitespaceMode() const {return m_mode;}
+private:
+ QString m_text;
+ QSvgText::WhitespaceMode m_mode;
+ bool m_isTspan;
};
class QSvgUse : public QSvgNode
diff --git a/src/svg/qsvghandler.cpp b/src/svg/qsvghandler.cpp
index f10b26f..73c8b01 100644
--- a/src/svg/qsvghandler.cpp
+++ b/src/svg/qsvghandler.cpp
@@ -70,6 +70,8 @@
QT_BEGIN_NAMESPACE
+static const char *qt_inherit_text = "inherit";
+#define QT_INHERIT QLatin1String(qt_inherit_text)
double qstrtod(const char *s00, char const **se, bool *ok);
@@ -492,7 +494,7 @@ static bool resolveColor(const QString &colorStr, QColor &color, QSvgHandler *ha
int(compo[2]));
return true;
} else if (colorStr == QLatin1String("inherited") ||
- colorStr == QLatin1String("inherit")) {
+ colorStr == QT_INHERIT) {
return false;
} else if (colorStr == QLatin1String("currentColor")) {
color = handler->currentColor();
@@ -646,138 +648,48 @@ static void parseBrush(QSvgNode *node,
QString opacity = attributes.value(QLatin1String("fill-opacity")).toString();
QString myId = someId(attributes);
- QSvgFillStyle *prop = new QSvgFillStyle(0);
+ if (!value.isEmpty() || !fillRule.isEmpty() || !opacity.isEmpty()) {
+ QSvgFillStyle *prop = new QSvgFillStyle(0);
- //fill-rule attribute handling
- if (!fillRule.isEmpty() && fillRule != QLatin1String("inherit")) {
- if (fillRule == QLatin1String("evenodd"))
- prop->setFillRule(Qt::OddEvenFill);
- else if (fillRule == QLatin1String("nonzero"))
- prop->setFillRule(Qt::WindingFill);
- }
-
- //fill-opacity atttribute handling
- if (!opacity.isEmpty() && opacity != QLatin1String("inherit")) {
- prop->setFillOpacity(qMin(qreal(1.0), qMax(qreal(0.0), toDouble(opacity))));
- }
-
- //fill attribute handling
- if ((!value.isEmpty()) && (value != QLatin1String("inherit")) ) {
- if (value.startsWith(QLatin1String("url"))) {
- value = value.remove(0, 3);
- QSvgStyleProperty *style = styleFromUrl(node, value);
- if (style) {
- prop->setFillStyle(style);
- } else {
- QString id = idFromUrl(value);
- prop->setGradientId(id);
- prop->setGradientResolved(false);
- }
- } else if (value != QLatin1String("none")) {
- QColor color;
- if (resolveColor(value, color, handler))
- prop->setBrush(QBrush(color));
- } else {
- prop->setBrush(QBrush(Qt::NoBrush));
+ //fill-rule attribute handling
+ if (!fillRule.isEmpty() && fillRule != QT_INHERIT) {
+ if (fillRule == QLatin1String("evenodd"))
+ prop->setFillRule(Qt::OddEvenFill);
+ else if (fillRule == QLatin1String("nonzero"))
+ prop->setFillRule(Qt::WindingFill);
}
- }
- node->appendStyleProperty(prop,myId);
-}
-
-static void parseQPen(QPen &pen, QSvgNode *node,
- const QSvgAttributes &attributes,
- QSvgHandler *handler)
-{
- QString value = attributes.value(QLatin1String("stroke")).toString();
- QString dashArray = attributes.value(QLatin1String("stroke-dasharray")).toString();
- QString dashOffset = attributes.value(QLatin1String("stroke-dashoffset")).toString();
- QString linecap = attributes.value(QLatin1String("stroke-linecap")).toString();
- QString linejoin = attributes.value(QLatin1String("stroke-linejoin")).toString();
- QString miterlimit = attributes.value(QLatin1String("stroke-miterlimit")).toString();
- QString opacity = attributes.value(QLatin1String("stroke-opacity")).toString();
- QString width = attributes.value(QLatin1String("stroke-width")).toString();
- QString myId = someId(attributes);
+ //fill-opacity atttribute handling
+ if (!opacity.isEmpty() && opacity != QT_INHERIT) {
+ prop->setFillOpacity(qMin(qreal(1.0), qMax(qreal(0.0), toDouble(opacity))));
+ }
- if (!value.isEmpty() || !width.isEmpty()) {
- if (value != QLatin1String("none")) {
- if (!value.isEmpty()) {
- if (node && value.startsWith(QLatin1String("url"))) {
- value = value.remove(0, 3);
- QSvgStyleProperty *style = styleFromUrl(node, value);
- if (style) {
- if (style->type() == QSvgStyleProperty::GRADIENT) {
- QBrush b(*((QSvgGradientStyle*)style)->qgradient());
- pen.setBrush(b);
- } else if (style->type() == QSvgStyleProperty::SOLID_COLOR) {
- pen.setColor(
- ((QSvgSolidColorStyle*)style)->qcolor());
- }
- } else {
- qWarning()<<"QSvgHandler::parsePen could not resolve property" << idFromUrl(value);
- }
+ //fill attribute handling
+ if ((!value.isEmpty()) && (value != QT_INHERIT) ) {
+ if (value.startsWith(QLatin1String("url"))) {
+ value = value.remove(0, 3);
+ QSvgStyleProperty *style = styleFromUrl(node, value);
+ if (style) {
+ prop->setFillStyle(style);
} else {
- QColor color;
- if (constructColor(value, opacity, color, handler))
- pen.setColor(color);
+ QString id = idFromUrl(value);
+ prop->setGradientId(id);
+ prop->setGradientResolved(false);
}
- //since we could inherit stroke="none"
- //we need to reset the style of our stroke to something
- pen.setStyle(Qt::SolidLine);
- }
- if (!width.isEmpty()) {
- QSvgHandler::LengthType lt;
- qreal widthF = parseLength(width, lt, handler);
- //### fixme
- if (!widthF) {
- pen.setStyle(Qt::NoPen);
- return;
- }
- pen.setWidthF(widthF);
- }
- qreal penw = pen.widthF();
-
- if (!linejoin.isEmpty()) {
- if (linejoin == QLatin1String("miter"))
- pen.setJoinStyle(Qt::SvgMiterJoin);
- else if (linejoin == QLatin1String("round"))
- pen.setJoinStyle(Qt::RoundJoin);
- else if (linejoin == QLatin1String("bevel"))
- pen.setJoinStyle(Qt::BevelJoin);
- }
- if (!miterlimit.isEmpty())
- pen.setMiterLimit(toDouble(miterlimit));
-
- if (!linecap.isEmpty()) {
- if (linecap == QLatin1String("butt"))
- pen.setCapStyle(Qt::FlatCap);
- else if (linecap == QLatin1String("round"))
- pen.setCapStyle(Qt::RoundCap);
- else if (linecap == QLatin1String("square"))
- pen.setCapStyle(Qt::SquareCap);
- }
-
- if (!dashArray.isEmpty()) {
- const QChar *s = dashArray.constData();
- QVector<qreal> dashes = parseNumbersList(s);
- qreal *d = dashes.data();
- if (penw != 0)
- for (int i = 0; i < dashes.size(); ++i) {
- *d /= penw;
- ++d;
- }
- pen.setDashPattern(dashes);
- }
- if (!dashOffset.isEmpty()) {
- pen.setDashOffset(toDouble(dashOffset));
+ } else if (value != QLatin1String("none")) {
+ QColor color;
+ if (resolveColor(value, color, handler))
+ prop->setBrush(QBrush(color));
+ } else {
+ prop->setBrush(QBrush(Qt::NoBrush));
}
-
- } else {
- pen.setStyle(Qt::NoPen);
}
+ node->appendStyleProperty(prop, myId);
}
}
+
+
static QMatrix parseTransformationMatrix(const QString &value)
{
QMatrix matrix;
@@ -917,18 +829,15 @@ static void parsePen(QSvgNode *node,
QString miterlimit = attributes.value(QLatin1String("stroke-miterlimit")).toString();
QString opacity = attributes.value(QLatin1String("stroke-opacity")).toString();
QString width = attributes.value(QLatin1String("stroke-width")).toString();
+ QString vectorEffect = attributes.value(QLatin1String("vector-effect")).toString();
QString myId = someId(attributes);
//qDebug()<<"Node "<<node->type()<<", attrs are "<<value<<width;
- /* All the below checks needed because g (or any container element) can have only one of these attributes.
- * If it doesn't has any one of these, then processing below not needed */
-
if (!value.isEmpty() || !width.isEmpty() || !dashArray.isEmpty() || !linecap.isEmpty() ||
- !linejoin.isEmpty() || !miterlimit.isEmpty() || !opacity.isEmpty() || !dashOffset.isEmpty() ) {
- //if (value != QLatin1String("none")) {
- /* If stroke = "none" then also, we need to parse below, because elements like 'g' may
- have other defined stroke attributes, which will be inherited by its children */
+ !linejoin.isEmpty() || !miterlimit.isEmpty() || !opacity.isEmpty() ||
+ !dashOffset.isEmpty() || !vectorEffect.isEmpty()) {
+
QSvgStrokeStyle *inherited =
static_cast<QSvgStrokeStyle*>(node->parent()->styleProperty(
QSvgStyleProperty::STROKE));
@@ -942,14 +851,14 @@ static void parsePen(QSvgNode *node,
// stroke-opacity attribute handling
qreal strokeAlpha;
- if (!opacity.isEmpty() && opacity != QLatin1String("inherit")) {
+ if (!opacity.isEmpty() && opacity != QT_INHERIT) {
strokeAlpha = qMin(qreal(1.0), qMax(qreal(0.0), toDouble(opacity)));
} else {
strokeAlpha = pen.color().alphaF();
}
//stroke attribute handling
- if (!value.isEmpty() && value != QLatin1String("inherit")) {
+ if (!value.isEmpty() && value != QT_INHERIT) {
if (value.startsWith(QLatin1String("url"))) {
value = value.remove(0, 3);
QSvgStyleProperty *style = styleFromUrl(node, value);
@@ -961,8 +870,7 @@ static void parsePen(QSvgNode *node,
pen.setColor(
((QSvgSolidColorStyle*)style)->qcolor());
}
- pen.setStyle(Qt::SolidLine);
- stroke = true;
+ stroke = true;
} else {
qWarning() << "QSvgHandler::parsePen could not resolve property" << idFromUrl(value);
}
@@ -986,14 +894,11 @@ static void parsePen(QSvgNode *node,
}
//stroke-width handling
- if (!width.isEmpty() && width != QLatin1String("inherit")) {
+ if (!width.isEmpty() && width != QT_INHERIT) {
qreal widthF;
QSvgHandler::LengthType lt;
widthF = parseLength(width, lt, handler);
pen.setWidthF(widthF);
- } else if (inherited){
- qreal widthF = inherited->qpen().widthF();
- pen.setWidthF(widthF);
}
//stroke-linejoin attribute handling
@@ -1018,7 +923,7 @@ static void parsePen(QSvgNode *node,
//strok-dasharray attribute handling
qreal penw = pen.widthF();
- if (!dashArray.isEmpty() && dashArray != QLatin1String("inherit")) {
+ if (!dashArray.isEmpty() && dashArray != QT_INHERIT) {
const QChar *s = dashArray.constData();
QVector<qreal> dashes = parseNumbersList(s);
qreal *d = dashes.data();
@@ -1048,7 +953,7 @@ static void parsePen(QSvgNode *node,
//stroke-dashoffset attribute handling
- if (!dashOffset.isEmpty() && dashOffset != QLatin1String("inherit")) {
+ if (!dashOffset.isEmpty() && dashOffset != QT_INHERIT) {
qreal doffset = toDouble(dashOffset);
if (penw != 0)
doffset /= penw;
@@ -1064,7 +969,15 @@ static void parsePen(QSvgNode *node,
pen.setDashOffset(doffset);
}
- if (!miterlimit.isEmpty() && miterlimit != QLatin1String("inherit"))
+ //vector-effect attribute handling
+ if (!vectorEffect.isEmpty()) {
+ if (vectorEffect == QLatin1String("non-scaling-stroke"))
+ pen.setCosmetic(true);
+ else if (vectorEffect == QLatin1String("none"))
+ pen.setCosmetic(false);
+ }
+
+ if (!miterlimit.isEmpty() && miterlimit != QT_INHERIT)
pen.setMiterLimit(toDouble(miterlimit));
QSvgStrokeStyle *prop = new QSvgStrokeStyle(pen);
@@ -1073,182 +986,84 @@ static void parsePen(QSvgNode *node,
}
}
-
-static bool parseQBrush(const QSvgAttributes &attributes, QSvgNode *node,
- QBrush &brush, QSvgHandler *handler)
-{
- QString value = attributes.value(QLatin1String("fill")).toString();
- QString opacity = attributes.value(QLatin1String("fill-opacity")).toString();
-
- QColor color;
- if (!value.isEmpty() || !opacity.isEmpty()) {
- if (value.startsWith(QLatin1String("url"))) {
- value = value.remove(0, 3);
- QSvgStyleProperty *style = styleFromUrl(node, value);
- if (style) {
- switch (style->type()) {
- case QSvgStyleProperty::FILL:
- {
- brush = static_cast<QSvgFillStyle*>(style)->qbrush();
- break;
- }
- case QSvgStyleProperty::SOLID_COLOR:
- {
- brush = QBrush(static_cast<QSvgSolidColorStyle*>(style)->qcolor());
- break;
- }
- case QSvgStyleProperty::GRADIENT:
- {
- brush = QBrush(*static_cast<QSvgGradientStyle*>(style)->qgradient());
- break;
- }
- default:
- qWarning("Cannot use property \"%s\" as brush.", qPrintable(idFromUrl(value)));
- }
- } else {
- qWarning("Couldn't resolve property: %s", qPrintable(idFromUrl(value)));
- }
- } else if (value != QLatin1String("none")) {
- if (constructColor(value, opacity, color, handler)) {
- brush.setStyle(Qt::SolidPattern);
- brush.setColor(color);
- }
- } else {
- brush = QBrush(Qt::NoBrush);
- }
- return true;
- }
- return false;
-}
-
-static bool parseQFont(const QSvgAttributes &attributes,
- QFont &font, qreal &fontSize, QSvgHandler *handler)
+static void parseFont(QSvgNode *node,
+ const QSvgAttributes &attributes,
+ QSvgHandler *handler)
{
QString family = attributes.value(QLatin1String("font-family")).toString();
QString size = attributes.value(QLatin1String("font-size")).toString();
QString style = attributes.value(QLatin1String("font-style")).toString();
QString weight = attributes.value(QLatin1String("font-weight")).toString();
+ QString variant = attributes.value(QLatin1String("font-variant")).toString();
+ QString anchor = attributes.value(QLatin1String("text-anchor")).toString();
- if (!family.isEmpty() || !size.isEmpty() ||
- !style.isEmpty() || !weight.isEmpty()) {
+ if (family.isEmpty() && size.isEmpty() && style.isEmpty() && weight.isEmpty() && variant.isEmpty() && anchor.isEmpty())
+ return;
- if (!family.isEmpty()) {
- font.setFamily(family.trimmed());
- }
- if (!size.isEmpty()) {
- if (size == QLatin1String("inherit")) {
- //inherited already
- } else {
- QSvgHandler::LengthType dummy; // should always be pixel size
- fontSize = parseLength(size, dummy, handler);
- if (fontSize <= 0)
- fontSize = 1;
- }
- font.setPixelSize(qMax(1, int(fontSize)));
- }
- if (!style.isEmpty()) {
- if (style == QLatin1String("normal")) {
- font.setStyle(QFont::StyleNormal);
- } else if (style == QLatin1String("italic")) {
- font.setStyle(QFont::StyleItalic);
- } else if (style == QLatin1String("oblique")) {
- font.setStyle(QFont::StyleOblique);
- } else if (style == QLatin1String("inherit")) {
- //inherited already
- }
- }
- if (!weight.isEmpty()) {
- bool ok = false;
- int weightNum = weight.toInt(&ok);
- if (ok) {
- switch (weightNum) {
- case 100:
- case 200:
- font.setWeight(QFont::Light);
- break;
- case 300:
- case 400:
- font.setWeight(QFont::Normal);
- break;
- case 500:
- case 600:
- font.setWeight(QFont::DemiBold);
- break;
- case 700:
- case 800:
- font.setWeight(QFont::Bold);
- break;
- case 900:
- font.setWeight(QFont::Black);
- break;
- default:
- break;
- }
- } else {
- if (weight == QLatin1String("normal")) {
- font.setWeight(QFont::Normal);
- } else if (weight == QLatin1String("bold")) {
- font.setWeight(QFont::Bold);
- } else if (weight == QLatin1String("bolder")) {
- font.setWeight(QFont::DemiBold);
- } else if (weight == QLatin1String("lighter")) {
- font.setWeight(QFont::Light);
- }
- }
- }
- // QFontInfo fi(font);
- // font.setPointSize(fi.pointSize());
- return true;
+ QString id = someId(attributes);
+ QSvgTinyDocument *doc = node->document();
+ QSvgFontStyle *fontStyle = 0;
+ if (!family.isEmpty()) {
+ QSvgFont *svgFont = doc->svgFont(family);
+ if (svgFont)
+ fontStyle = new QSvgFontStyle(svgFont, doc);
}
+ if (!fontStyle)
+ fontStyle = new QSvgFontStyle;
- return false;
-}
+ if (!family.isEmpty() && family != QT_INHERIT)
+ fontStyle->setFamily(family.trimmed());
-static void parseFont(QSvgNode *node,
- const QSvgAttributes &attributes,
- QSvgHandler *handler)
-{
- QFont font;
- font.setPixelSize(12);
- qreal fontSize = font.pixelSize();
-
- QSvgFontStyle *inherited =
- static_cast<QSvgFontStyle*>(node->styleProperty(
- QSvgStyleProperty::FONT));
- if (!inherited)
- inherited =
- static_cast<QSvgFontStyle*>(node->parent()->styleProperty(
- QSvgStyleProperty::FONT));
- if (inherited) {
- font = inherited->qfont();
- fontSize = inherited->pointSize();
- }
- // group or any container element can have only text-anchor and should
- // be processed, because its children can inherit from it.
- // So checking for text-anchor before parseQfont()
- QString anchor = attributes.value(QLatin1String("text-anchor")).toString();
- if (parseQFont(attributes, font, fontSize, handler) || (!anchor.isEmpty())) {
- QString myId = someId(attributes);
- //QString anchor = attributes.value(QLatin1String("text-anchor")).toString();
- QSvgTinyDocument *doc = node->document();
- QSvgFontStyle *fontStyle = 0;
- QString family = (font.family().isEmpty())?myId:font.family();
- if (!family.isEmpty()) {
- QSvgFont *svgFont = doc->svgFont(family);
- if (svgFont) {
- fontStyle = new QSvgFontStyle(svgFont, doc);
- fontStyle->setPointSize(fontSize);
- }
+ if (!size.isEmpty() && size != QT_INHERIT) {
+ QSvgHandler::LengthType dummy; // should always be pixel size
+ fontStyle->setSize(parseLength(size, dummy, handler));
+ }
+
+ if (!style.isEmpty() && style != QT_INHERIT) {
+ if (style == QLatin1String("normal")) {
+ fontStyle->setStyle(QFont::StyleNormal);
+ } else if (style == QLatin1String("italic")) {
+ fontStyle->setStyle(QFont::StyleItalic);
+ } else if (style == QLatin1String("oblique")) {
+ fontStyle->setStyle(QFont::StyleOblique);
}
- if (!fontStyle) {
- fontStyle = new QSvgFontStyle(font, node->document());
- fontStyle->setPointSize(fontSize);
+ }
+
+ if (!weight.isEmpty() && weight != QT_INHERIT) {
+ bool ok = false;
+ int weightNum = weight.toInt(&ok);
+ if (ok) {
+ fontStyle->setWeight(weightNum);
+ } else {
+ if (weight == QLatin1String("normal")) {
+ fontStyle->setWeight(400);
+ } else if (weight == QLatin1String("bold")) {
+ fontStyle->setWeight(700);
+ } else if (weight == QLatin1String("bolder")) {
+ fontStyle->setWeight(QSvgFontStyle::BOLDER);
+ } else if (weight == QLatin1String("lighter")) {
+ fontStyle->setWeight(QSvgFontStyle::LIGHTER);
+ }
}
- if (!anchor.isEmpty())
- fontStyle->setTextAnchor(anchor);
+ }
- node->appendStyleProperty(fontStyle, myId);
+ if (!variant.isEmpty() && variant != QT_INHERIT) {
+ if (variant == QLatin1String("normal"))
+ fontStyle->setVariant(QFont::MixedCase);
+ else if (variant == QLatin1String("small-caps"))
+ fontStyle->setVariant(QFont::SmallCaps);
}
+
+ if (!anchor.isEmpty() && anchor != QT_INHERIT) {
+ if (anchor == QLatin1String("start"))
+ fontStyle->setTextAnchor(Qt::AlignLeft);
+ if (anchor == QLatin1String("middle"))
+ fontStyle->setTextAnchor(Qt::AlignHCenter);
+ else if (anchor == QLatin1String("end"))
+ fontStyle->setTextAnchor(Qt::AlignRight);
+ }
+
+ node->appendStyleProperty(fontStyle, id);
}
static void parseTransform(QSvgNode *node,
@@ -1275,7 +1090,7 @@ static void parseVisibility(QSvgNode *node,
QString value = attributes.value(QLatin1String("visibility")).toString();
QSvgNode *parent = node->parent();
- if (parent && (value.isEmpty() || value == QLatin1String("inherit")))
+ if (parent && (value.isEmpty() || value == QT_INHERIT))
node->setVisible(parent->isVisible());
else if (value == QLatin1String("hidden") || value == QLatin1String("collapse")) {
node->setVisible(false);
@@ -1886,105 +1701,6 @@ static void cssStyleLookup(QSvgNode *node,
parseStyle(node, attributes, handler);
}
-static bool parseDefaultTextStyle(QSvgNode *node,
- const QXmlStreamAttributes &attributes,
- bool initial,
- QSvgHandler *handler)
-{
- Q_ASSERT(node->type() == QSvgText::TEXT || node->type() == QSvgNode::TEXTAREA);
- QSvgText *textNode = static_cast<QSvgText*>(node);
-
- QSvgAttributes attrs(attributes, handler);
-
- QString fontFamily = attrs.value(QString(), QLatin1String("font-family")).toString();
-
- QString anchor = attrs.value(QString(), QLatin1String("text-anchor")).toString();
-
- QSvgFontStyle *fontStyle = static_cast<QSvgFontStyle*>(
- node->styleProperty(QSvgStyleProperty::FONT));
- if (fontStyle) {
- QSvgTinyDocument *doc = fontStyle->doc();
- if (doc && fontStyle->svgFont()) {
- cssStyleLookup(node, handler, handler->selector());
- parseStyle(node, attrs, handler);
- return true;
- }
- } else if (!fontFamily.isEmpty()) {
- QSvgTinyDocument *doc = node->document();
- QSvgFont *svgFont = doc->svgFont(fontFamily);
- if (svgFont) {
- cssStyleLookup(node, handler, handler->selector());
- parseStyle(node, attrs, handler);
- return true;
- }
- }
-
- QTextCharFormat format;
- QBrush brush(QColor(0, 0, 0));
- QFont font;
- font.setPixelSize(12);
- qreal fontSize = font.pixelSize();
-
- if (!initial) {
- font = textNode->topFormat().font();
- fontSize = font.pixelSize() / textNode->scale();
- brush = textNode->topFormat().foreground();
- } else {
- QSvgFontStyle *fontStyle = static_cast<QSvgFontStyle*>(
- node->styleProperty(QSvgStyleProperty::FONT));
- if (!fontStyle)
- fontStyle = static_cast<QSvgFontStyle*>(
- node->parent()->styleProperty(QSvgStyleProperty::FONT));
- if (fontStyle) {
- font = fontStyle->qfont();
- fontSize = fontStyle->pointSize();
- if (anchor.isEmpty() || anchor == QLatin1String("inherit"))
- anchor = fontStyle->textAnchor();
- }
-
- Qt::Alignment align = Qt::AlignLeft;
- if (anchor == QLatin1String("middle"))
- align = Qt::AlignHCenter;
- else if (anchor == QLatin1String("end"))
- align = Qt::AlignRight;
- textNode->setTextAlignment(align);
-
- QSvgFillStyle *fillStyle = static_cast<QSvgFillStyle*>(
- node->styleProperty(QSvgStyleProperty::FILL));
- if (fillStyle)
- brush = fillStyle->qbrush();
- }
-
- if (parseQFont(attrs, font, fontSize, handler) || initial) {
- if (initial)
- textNode->setScale(100 / fontSize);
- font.setPixelSize(qMax(1, int(fontSize * textNode->scale())));
- format.setFont(font);
- }
-
- if (parseQBrush(attrs, node, brush, handler) || initial) {
- if (brush.style() != Qt::NoBrush || initial)
- format.setForeground(brush);
- }
-
- QPen pen(Qt::NoPen);
-// QSvgStrokeStyle *inherited =
-// static_cast<QSvgStrokeStyle*>(node->parent()->styleProperty(
-// QSvgStyleProperty::STROKE));
-// if (inherited)
-// pen = inherited->qpen();
- parseQPen(pen, node, attrs, handler);
- if (pen.style() != Qt::NoPen) {
- format.setTextOutline(pen);
- }
-
- parseTransform(node, attrs, handler);
-
- textNode->insertFormat(format);
-
- return true;
-}
-
static inline QStringList stringToList(const QString &str)
{
QStringList lst = str.split(QLatin1Char(','), QString::SkipEmptyParts);
@@ -2143,7 +1859,7 @@ static inline QSvgNode::DisplayMode displayStringToEnum(const QString &str)
return QSvgNode::TableCaptionMode;
} else if (str == QLatin1String("none")) {
return QSvgNode::NoneMode;
- } else if (str == QLatin1String("inherit")) {
+ } else if (str == QT_INHERIT) {
return QSvgNode::InheritMode;
}
return QSvgNode::BlockMode;
@@ -3107,7 +2823,6 @@ static QSvgNode *createSvgNode(QSvgNode *parent,
node->setHeight(int(height), type == QSvgHandler::LT_PERCENT);
}
-
if (!viewBoxStr.isEmpty()) {
QStringList lst = viewBoxStr.split(QLatin1Char(' '), QString::SkipEmptyParts);
if (lst.count() != 4)
@@ -3157,7 +2872,7 @@ static bool parseTbreakNode(QSvgNode *parent,
{
if (parent->type() != QSvgNode::TEXTAREA)
return false;
- static_cast<QSvgText*>(parent)->insertLineBreak();
+ static_cast<QSvgText*>(parent)->addLineBreak();
return true;
}
@@ -3172,12 +2887,6 @@ static QSvgNode *createTextNode(QSvgNode *parent,
qreal nx = parseLength(x, type, handler);
qreal ny = parseLength(y, type, handler);
- //### not to pixels but to the default coordinate system
- // and text should be already in the correct coordinate
- // system here
- //nx = convertToPixels(nx, true, type);
- //ny = convertToPixels(ny, true, type);
-
QSvgNode *text = new QSvgText(parent, QPointF(nx, ny));
return text;
}
@@ -3196,6 +2905,13 @@ static QSvgNode *createTextAreaNode(QSvgNode *parent,
return node;
}
+static QSvgNode *createTspanNode(QSvgNode *parent,
+ const QXmlStreamAttributes &,
+ QSvgHandler *)
+{
+ return new QSvgTspan(parent);
+}
+
static bool parseTitleNode(QSvgNode *parent,
const QXmlStreamAttributes &attributes,
QSvgHandler *)
@@ -3204,15 +2920,6 @@ static bool parseTitleNode(QSvgNode *parent,
return true;
}
-static bool parseTspanNode(QSvgNode *parent,
- const QXmlStreamAttributes &attributes,
- QSvgHandler *handler)
-{
-
- cssStyleLookup(parent, handler, handler->selector());
- return parseDefaultTextStyle(parent, attributes, false, handler);
-}
-
static QSvgNode *createUseNode(QSvgNode *parent,
const QXmlStreamAttributes &attributes,
QSvgHandler *handler)
@@ -3326,6 +3033,7 @@ static FactoryMethod findGraphicsFactory(const QString &name)
case 't':
if (ref == QLatin1String("ext")) return createTextNode;
if (ref == QLatin1String("extArea")) return createTextAreaNode;
+ if (ref == QLatin1String("span")) return createTspanNode;
break;
case 'u':
if (ref == QLatin1String("se")) return createUseNode;
@@ -3382,7 +3090,6 @@ static ParseMethod findUtilFactory(const QString &name)
case 't':
if (ref == QLatin1String("break")) return parseTbreakNode;
if (ref == QLatin1String("itle")) return parseTitleNode;
- if (ref == QLatin1String("span")) return parseTspanNode;
break;
default:
break;
@@ -3591,16 +3298,33 @@ bool QSvgHandler::startElement(const QString &localName,
group->addChild(node, someId(attributes));
}
break;
+ case QSvgNode::TEXT:
+ case QSvgNode::TEXTAREA:
+ if (node->type() == QSvgNode::TSPAN) {
+ static_cast<QSvgText *>(m_nodes.top())->addTspan(static_cast<QSvgTspan *>(node));
+ } else {
+ qWarning("\'text\' or \'textArea\' element contains invalid element type.");
+ delete node;
+ node = 0;
+ }
+ break;
default:
- Q_ASSERT(!"not a grouping element is the parent");
+ qWarning("Could not add child element to parent element because the types are incorrect.");
+ delete node;
+ node = 0;
+ break;
}
- parseCoreNode(node, attributes);
- cssStyleLookup(node, this, m_selector);
- if (node->type() != QSvgNode::TEXT && node->type() != QSvgNode::TEXTAREA)
+ if (node) {
+ parseCoreNode(node, attributes);
+ cssStyleLookup(node, this, m_selector);
parseStyle(node, attributes, this);
- else
- parseDefaultTextStyle(node, attributes, true, this);
+ if (node->type() == QSvgNode::TEXT || node->type() == QSvgNode::TEXTAREA) {
+ static_cast<QSvgText *>(node)->setWhitespaceMode(m_whitespaceMode.top());
+ } else if (node->type() == QSvgNode::TSPAN) {
+ static_cast<QSvgTspan *>(node)->setWhitespaceMode(m_whitespaceMode.top());
+ }
+ }
}
} else if (ParseMethod method = findUtilFactory(localName)) {
Q_ASSERT(!m_nodes.isEmpty());
@@ -3657,13 +3381,8 @@ bool QSvgHandler::endElement(const QStringRef &localName)
return true;
}
- if (m_inStyle && localName == QLatin1String("style")) {
+ if (m_inStyle && localName == QLatin1String("style"))
m_inStyle = false;
- } else if (m_nodes.top()->type() == QSvgNode::TEXT || m_nodes.top()->type() == QSvgNode::TEXTAREA) {
- QSvgText *node = static_cast<QSvgText*>(m_nodes.top());
- if (localName == QLatin1String("tspan"))
- node->popFormat();
- }
if (node == Graphics) {
// Iterate through the m_renderers to resolve any unresolved gradients.
@@ -3711,8 +3430,9 @@ bool QSvgHandler::characters(const QStringRef &str)
return true;
if (m_nodes.top()->type() == QSvgNode::TEXT || m_nodes.top()->type() == QSvgNode::TEXTAREA) {
- QSvgText *node = static_cast<QSvgText*>(m_nodes.top());
- node->insertText(str.toString(), m_whitespaceMode.top());
+ static_cast<QSvgText*>(m_nodes.top())->addText(str.toString());
+ } else if (m_nodes.top()->type() == QSvgNode::TSPAN) {
+ static_cast<QSvgTspan*>(m_nodes.top())->addText(str.toString());
}
return true;
diff --git a/src/svg/qsvgnode_p.h b/src/svg/qsvgnode_p.h
index f203ea7..315f228 100644
--- a/src/svg/qsvgnode_p.h
+++ b/src/svg/qsvgnode_p.h
@@ -86,6 +86,7 @@ public:
RECT,
TEXT,
TEXTAREA,
+ TSPAN,
USE,
VIDEO
};
diff --git a/src/svg/qsvgstyle.cpp b/src/svg/qsvgstyle.cpp
index c3c0a68..6ed3dc2 100644
--- a/src/svg/qsvgstyle.cpp
+++ b/src/svg/qsvgstyle.cpp
@@ -59,6 +59,9 @@ QT_BEGIN_NAMESPACE
QSvgExtraStates::QSvgExtraStates()
: fillOpacity(1.0)
+ , svgFont(0)
+ , textAnchor(Qt::AlignLeft)
+ , fontWeight(400)
{
}
@@ -191,39 +194,94 @@ void QSvgViewportFillStyle::revert(QPainter *p, QSvgExtraStates &)
}
QSvgFontStyle::QSvgFontStyle(QSvgFont *font, QSvgTinyDocument *doc)
- : m_font(font), m_pointSize(24), m_doc(doc)
-{
-}
-
-QSvgFontStyle::QSvgFontStyle(const QFont &font, QSvgTinyDocument *doc)
- : m_font(0), m_pointSize(24), m_doc(doc), m_qfont(font)
-{
-}
-
-
-void QSvgFontStyle::setPointSize(qreal size)
-{
- m_pointSize = size;
-}
-
-qreal QSvgFontStyle::pointSize() const
-{
- return m_pointSize;
-}
-
-void QSvgFontStyle::apply(QPainter *p, const QRectF &, QSvgNode *, QSvgExtraStates &)
-{
- if (!m_font) {
- m_oldFont = p->font();
- p->setFont(m_qfont);
+ : m_svgFont(font)
+ , m_doc(doc)
+ , m_familySet(0)
+ , m_sizeSet(0)
+ , m_styleSet(0)
+ , m_variantSet(0)
+ , m_weightSet(0)
+ , m_textAnchorSet(0)
+{
+}
+
+QSvgFontStyle::QSvgFontStyle()
+ : m_svgFont(0)
+ , m_doc(0)
+ , m_familySet(0)
+ , m_sizeSet(0)
+ , m_styleSet(0)
+ , m_variantSet(0)
+ , m_weightSet(0)
+ , m_textAnchorSet(0)
+{
+}
+
+int QSvgFontStyle::SVGToQtWeight(int weight) {
+ switch (weight) {
+ case 100:
+ case 200:
+ return QFont::Light;
+ case 300:
+ case 400:
+ return QFont::Normal;
+ case 500:
+ case 600:
+ return QFont::DemiBold;
+ case 700:
+ case 800:
+ return QFont::Bold;
+ case 900:
+ return QFont::Black;
+ }
+ return QFont::Normal;
+}
+
+void QSvgFontStyle::apply(QPainter *p, const QRectF &, QSvgNode *, QSvgExtraStates &states)
+{
+ m_oldQFont = p->font();
+ m_oldSvgFont = states.svgFont;
+ m_oldTextAnchor = states.textAnchor;
+ m_oldWeight = states.fontWeight;
+
+ if (m_textAnchorSet)
+ states.textAnchor = m_textAnchor;
+
+ QFont font = m_oldQFont;
+ if (m_familySet) {
+ states.svgFont = m_svgFont;
+ font.setFamily(m_qfont.family());
+ }
+
+ if (m_sizeSet)
+ font.setPointSize(m_qfont.pointSizeF());
+
+ if (m_styleSet)
+ font.setStyle(m_qfont.style());
+
+ if (m_variantSet)
+ font.setCapitalization(m_qfont.capitalization());
+
+ if (m_weightSet) {
+ if (m_weight == BOLDER) {
+ states.fontWeight = qMin(states.fontWeight + 100, 900);
+ } else if (m_weight == LIGHTER) {
+ states.fontWeight = qMax(states.fontWeight - 100, 100);
+ } else {
+ states.fontWeight = m_weight;
+ }
+ font.setWeight(SVGToQtWeight(states.fontWeight));
}
+
+ p->setFont(font);
}
-void QSvgFontStyle::revert(QPainter *p, QSvgExtraStates &)
+void QSvgFontStyle::revert(QPainter *p, QSvgExtraStates &states)
{
- if (!m_font) {
- p->setFont(m_oldFont);
- }
+ p->setFont(m_oldQFont);
+ states.svgFont = m_oldSvgFont;
+ states.textAnchor = m_oldTextAnchor;
+ states.fontWeight = m_oldWeight;
}
QSvgStrokeStyle::QSvgStrokeStyle(const QPen &pen)
@@ -799,16 +857,6 @@ QSvgStyleProperty::Type QSvgAnimateColor::type() const
return ANIMATE_COLOR;
}
-QString QSvgFontStyle::textAnchor() const
-{
- return m_textAnchor;
-}
-
-void QSvgFontStyle::setTextAnchor(const QString &anchor)
-{
- m_textAnchor = anchor;
-}
-
QSvgOpacityStyle::QSvgOpacityStyle(qreal opacity)
: m_opacity(opacity)
{
diff --git a/src/svg/qsvgstyle_p.h b/src/svg/qsvgstyle_p.h
index 70ecf5b..bd28bb6 100644
--- a/src/svg/qsvgstyle_p.h
+++ b/src/svg/qsvgstyle_p.h
@@ -141,7 +141,11 @@ private:
struct QSvgExtraStates
{
QSvgExtraStates();
+
qreal fillOpacity;
+ QSvgFont *svgFont;
+ Qt::Alignment textAnchor;
+ int fontWeight;
};
class QSvgStyleProperty : public QSvgRefCounted
@@ -307,41 +311,85 @@ private:
class QSvgFontStyle : public QSvgStyleProperty
{
public:
+ static const int LIGHTER = -1;
+ static const int BOLDER = 1;
+
QSvgFontStyle(QSvgFont *font, QSvgTinyDocument *doc);
- QSvgFontStyle(const QFont &font, QSvgTinyDocument *doc);
+ QSvgFontStyle();
virtual void apply(QPainter *p, const QRectF &, QSvgNode *node, QSvgExtraStates &states);
virtual void revert(QPainter *p, QSvgExtraStates &states);
virtual Type type() const;
- void setPointSize(qreal size);
- qreal pointSize() const;
+ void setSize(qreal size)
+ {
+ // Store the _pixel_ size in the font. Since QFont::setPixelSize() only takes an int, call
+ // QFont::SetPointSize() instead. Set proper font size just before rendering.
+ m_qfont.setPointSize(size);
+ m_sizeSet = 1;
+ }
- //### hack to avoid having a separate style element for text-anchor
- QString textAnchor() const;
- void setTextAnchor(const QString &anchor);
+ void setTextAnchor(Qt::Alignment anchor)
+ {
+ m_textAnchor = anchor;
+ m_textAnchorSet = 1;
+ }
- QSvgFont * svgFont() const
+ void setFamily(const QString &family)
{
- return m_font;
+ m_qfont.setFamily(family);
+ m_familySet = 1;
+ }
+
+ void setStyle(QFont::Style fontStyle) {
+ m_qfont.setStyle(fontStyle);
+ m_styleSet = 1;
}
- QSvgTinyDocument *doc() const
+
+ void setVariant(QFont::Capitalization fontVariant)
{
- return m_doc;
+ m_qfont.setCapitalization(fontVariant);
+ m_variantSet = 1;
}
- const QFont & qfont() const
+ static int SVGToQtWeight(int weight);
+
+ void setWeight(int weight)
+ {
+ m_weight = weight;
+ m_weightSet = 1;
+ }
+
+ QSvgFont * svgFont() const
+ {
+ return m_svgFont;
+ }
+
+ const QFont &qfont() const
{
return m_qfont;
}
+
+ QSvgTinyDocument *doc() const {return m_doc;}
+
private:
- QSvgFont *m_font;
- qreal m_pointSize;
+ QSvgFont *m_svgFont;
QSvgTinyDocument *m_doc;
+ QFont m_qfont;
- QString m_textAnchor;
+ int m_weight;
+ Qt::Alignment m_textAnchor;
- QFont m_qfont;
- QFont m_oldFont;
+ QSvgFont *m_oldSvgFont;
+ QFont m_oldQFont;
+ Qt::Alignment m_oldTextAnchor;
+ int m_oldWeight;
+
+ unsigned m_familySet : 1;
+ unsigned m_sizeSet : 1;
+ unsigned m_styleSet : 1;
+ unsigned m_variantSet : 1;
+ unsigned m_weightSet : 1;
+ unsigned m_textAnchorSet : 1;
};
class QSvgStrokeStyle : public QSvgStyleProperty
diff --git a/src/testlib/qabstracttestlogger_p.h b/src/testlib/qabstracttestlogger_p.h
index a0e8a1e..588184e 100644
--- a/src/testlib/qabstracttestlogger_p.h
+++ b/src/testlib/qabstracttestlogger_p.h
@@ -99,6 +99,42 @@ public:
static bool isTtyOutput();
};
+struct QTestCharBuffer
+{
+ inline QTestCharBuffer()
+ : buf(0)
+ {}
+
+ inline ~QTestCharBuffer()
+ {
+ delete[] buf;
+ buf = 0;
+ }
+
+ inline operator void*()
+ {
+ return buf;
+ }
+
+ inline operator char*()
+ {
+ return buf;
+ }
+
+ inline operator char**()
+ {
+ return &buf;
+ }
+
+ inline const char* constData() const
+ {
+ return buf;
+ }
+
+private:
+ char* buf;
+};
+
QT_END_NAMESPACE
#endif
diff --git a/src/testlib/qplaintestlogger.cpp b/src/testlib/qplaintestlogger.cpp
index 071b55e..7bebaa1 100644
--- a/src/testlib/qplaintestlogger.cpp
+++ b/src/testlib/qplaintestlogger.cpp
@@ -168,7 +168,7 @@ namespace QTest {
QTEST_ASSERT(type);
QTEST_ASSERT(msg);
- char buf[1024];
+ QTestCharBuffer buf;
const char *fn = QTestResult::currentTestFunction() ? QTestResult::currentTestFunction()
: "UnknownTestFunc";
@@ -178,7 +178,7 @@ namespace QTest {
: "";
const char *filler = (tag[0] && gtag[0]) ? ":" : "";
if (file) {
- QTest::qt_snprintf(buf, sizeof(buf), "%s: %s::%s(%s%s%s)%s%s\n"
+ QTest::qt_asprintf(buf, "%s: %s::%s(%s%s%s)%s%s\n"
#ifdef Q_OS_WIN
"%s(%d) : failure location\n"
#else
@@ -187,10 +187,12 @@ namespace QTest {
, type, QTestResult::currentTestObjectName(), fn, gtag, filler, tag,
msg[0] ? " " : "", msg, file, line);
} else {
- QTest::qt_snprintf(buf, sizeof(buf), "%s: %s::%s(%s%s%s)%s%s\n",
+ QTest::qt_asprintf(buf, "%s: %s::%s(%s%s%s)%s%s\n",
type, QTestResult::currentTestObjectName(), fn, gtag, filler, tag,
msg[0] ? " " : "", msg);
}
+ // In colored mode, printf above stripped our nonprintable control characters.
+ // Put them back.
memcpy(buf, type, strlen(type));
outputMessage(buf);
}
diff --git a/src/testlib/qtest_global.h b/src/testlib/qtest_global.h
index b5b0fc0..c40f0ad 100644
--- a/src/testlib/qtest_global.h
+++ b/src/testlib/qtest_global.h
@@ -82,6 +82,7 @@ namespace QTest
enum TestFailMode { Abort = 1, Continue = 2 };
int Q_TESTLIB_EXPORT qt_snprintf(char *str, int size, const char *format, ...);
+ int qt_asprintf(char **str, const char *format, ...);
}
QT_END_NAMESPACE
diff --git a/src/testlib/qtestbasicstreamer.cpp b/src/testlib/qtestbasicstreamer.cpp
index 5fe9d4d..aac57ba 100644
--- a/src/testlib/qtestbasicstreamer.cpp
+++ b/src/testlib/qtestbasicstreamer.cpp
@@ -68,39 +68,39 @@ QTestBasicStreamer::QTestBasicStreamer()
QTestBasicStreamer::~QTestBasicStreamer()
{}
-void QTestBasicStreamer::formatStart(const QTestElement *element, char *formatted) const
+void QTestBasicStreamer::formatStart(const QTestElement *element, char **formatted) const
{
if(!element || !formatted )
return;
- QTest::qt_snprintf(formatted, 10, "");
+ QTest::qt_asprintf(formatted, "");
}
-void QTestBasicStreamer::formatEnd(const QTestElement *element, char *formatted) const
+void QTestBasicStreamer::formatEnd(const QTestElement *element, char **formatted) const
{
if(!element || !formatted )
return;
- QTest::qt_snprintf(formatted, 10, "");
+ QTest::qt_asprintf(formatted, "");
}
-void QTestBasicStreamer::formatBeforeAttributes(const QTestElement *element, char *formatted) const
+void QTestBasicStreamer::formatBeforeAttributes(const QTestElement *element, char **formatted) const
{
if(!element || !formatted )
return;
- QTest::qt_snprintf(formatted, 10, "");
+ QTest::qt_asprintf(formatted, "");
}
-void QTestBasicStreamer::formatAfterAttributes(const QTestElement *element, char *formatted) const
+void QTestBasicStreamer::formatAfterAttributes(const QTestElement *element, char **formatted) const
{
if(!element || !formatted )
return;
- QTest::qt_snprintf(formatted, 10, "");
+ QTest::qt_asprintf(formatted, "");
}
-void QTestBasicStreamer::formatAttributes(const QTestElement *, const QTestElementAttribute *attribute, char *formatted) const
+void QTestBasicStreamer::formatAttributes(const QTestElement *, const QTestElementAttribute *attribute, char **formatted) const
{
if(!attribute || !formatted )
return;
- QTest::qt_snprintf(formatted, 10, "");
+ QTest::qt_asprintf(formatted, "");
}
void QTestBasicStreamer::output(QTestElement *element) const
@@ -113,7 +113,7 @@ void QTestBasicStreamer::output(QTestElement *element) const
void QTestBasicStreamer::outputElements(QTestElement *element, bool) const
{
- char buf[1024];
+ QTestCharBuffer buf;
bool hasChildren;
/*
Elements are in reverse order of occurrence, so start from the end and work
@@ -148,7 +148,7 @@ void QTestBasicStreamer::outputElements(QTestElement *element, bool) const
void QTestBasicStreamer::outputElementAttributes(const QTestElement* element, QTestElementAttribute *attribute) const
{
- char buf[1024];
+ QTestCharBuffer buf;
while(attribute){
formatAttributes(element, attribute, buf);
outputString(buf);
diff --git a/src/testlib/qtestbasicstreamer.h b/src/testlib/qtestbasicstreamer.h
index 84d1bce..432dd22 100644
--- a/src/testlib/qtestbasicstreamer.h
+++ b/src/testlib/qtestbasicstreamer.h
@@ -71,11 +71,11 @@ class QTestBasicStreamer
const QTestLogger *logger() const;
protected:
- virtual void formatStart(const QTestElement *element = 0, char *formatted = 0) const;
- virtual void formatEnd(const QTestElement *element = 0, char *formatted = 0) const;
- virtual void formatBeforeAttributes(const QTestElement *element = 0, char *formatted = 0) const;
- virtual void formatAfterAttributes(const QTestElement *element = 0, char *formatted = 0) const;
- virtual void formatAttributes(const QTestElement *element = 0, const QTestElementAttribute *attribute = 0, char *formatted = 0) const;
+ virtual void formatStart(const QTestElement *element, char **formatted) const;
+ virtual void formatEnd(const QTestElement *element, char **formatted) const;
+ virtual void formatBeforeAttributes(const QTestElement *element, char **formatted) const;
+ virtual void formatAfterAttributes(const QTestElement *element, char **formatted) const;
+ virtual void formatAttributes(const QTestElement *element, const QTestElementAttribute *attribute, char **formatted) const;
virtual void outputElements(QTestElement *element, bool isChildElement = false) const;
virtual void outputElementAttributes(const QTestElement *element, QTestElementAttribute *attribute) const;
diff --git a/src/testlib/qtestcase.cpp b/src/testlib/qtestcase.cpp
index cb05400..ac4ca83 100644
--- a/src/testlib/qtestcase.cpp
+++ b/src/testlib/qtestcase.cpp
@@ -808,6 +808,53 @@ namespace QTest
static int eventDelay = -1;
static int keyVerbose = -1;
+void filter_unprintable(char *str)
+{
+ char *idx = str;
+ while (*idx) {
+ if (((*idx < 0x20 && *idx != '\n' && *idx != '\t') || *idx > 0x7e))
+ *idx = '?';
+ ++idx;
+ }
+}
+
+/*! \internal
+ */
+int qt_asprintf(char **str, const char *format, ...)
+{
+ static const int MAXSIZE = 1024*1024*2;
+
+ int size = 32;
+ delete[] *str;
+ *str = new char[size];
+
+ va_list ap;
+ int res = 0;
+
+ for (;;) {
+ va_start(ap, format);
+ res = qvsnprintf(*str, size, format, ap);
+ va_end(ap);
+ (*str)[size - 1] = '\0';
+ if (res >= 0 && res < size) {
+ // We succeeded
+ break;
+ }
+ // buffer wasn't big enough, try again.
+ // Note, we're assuming that a result of -1 is always due to running out of space.
+ size *= 2;
+ if (size > MAXSIZE) {
+ break;
+ }
+ delete[] *str;
+ *str = new char[size];
+ }
+
+ filter_unprintable(*str);
+
+ return res;
+}
+
/*! \internal
*/
int qt_snprintf(char *str, int size, const char *format, ...)
@@ -820,12 +867,8 @@ int qt_snprintf(char *str, int size, const char *format, ...)
va_end(ap);
str[size - 1] = '\0';
- char *idx = str;
- while (*idx) {
- if (((*idx < 0x20 && *idx != '\n' && *idx != '\t') || *idx > 0x7e))
- *idx = '?';
- ++idx;
- }
+ filter_unprintable(str);
+
return res;
}
diff --git a/src/testlib/qtestlightxmlstreamer.cpp b/src/testlib/qtestlightxmlstreamer.cpp
index 170938a..e176201 100644
--- a/src/testlib/qtestlightxmlstreamer.cpp
+++ b/src/testlib/qtestlightxmlstreamer.cpp
@@ -59,61 +59,55 @@ QTestLightXmlStreamer::QTestLightXmlStreamer()
QTestLightXmlStreamer::~QTestLightXmlStreamer()
{}
-void QTestLightXmlStreamer::formatStart(const QTestElement *element, char *formatted) const
+void QTestLightXmlStreamer::formatStart(const QTestElement *element, char **formatted) const
{
if(!element || !formatted)
return;
switch(element->elementType()){
case QTest::LET_TestCase: {
- char quotedTf[950];
- QXmlTestLogger::xmlQuote(quotedTf, element->attributeValue(QTest::AI_Name),
- sizeof(quotedTf));
+ QTestCharBuffer quotedTf;
+ QXmlTestLogger::xmlQuote(quotedTf, element->attributeValue(QTest::AI_Name));
- QTest::qt_snprintf(formatted, 1024, "<TestFunction name=\"%s\">\n", quotedTf);
+ QTest::qt_asprintf(formatted, "<TestFunction name=\"%s\">\n", quotedTf.constData());
break;
}
case QTest::LET_Failure: {
- char cdataDesc[900];
- QXmlTestLogger::xmlCdata(cdataDesc, element->attributeValue(QTest::AI_Description),
- sizeof(cdataDesc));
+ QTestCharBuffer cdataDesc;
+ QXmlTestLogger::xmlCdata(cdataDesc, element->attributeValue(QTest::AI_Description));
- QTest::qt_snprintf(formatted, 1024, " <Description><![CDATA[%s]]></Description>\n",
- cdataDesc);
+ QTest::qt_asprintf(formatted, " <Description><![CDATA[%s]]></Description>\n",
+ cdataDesc.constData());
break;
}
case QTest::LET_Error: {
// assuming type and attribute names don't need quoting
- char quotedFile[128];
- char cdataDesc[700];
- QXmlTestLogger::xmlQuote(quotedFile, element->attributeValue(QTest::AI_File),
- sizeof(quotedFile));
- QXmlTestLogger::xmlCdata(cdataDesc, element->attributeValue(QTest::AI_Description),
- sizeof(cdataDesc));
-
- QTest::qt_snprintf(formatted, 1024, "<Message type=\"%s\" %s=\"%s\" %s=\"%s\">\n <Description><![CDATA[%s]]></Description>\n</Message>\n",
+ QTestCharBuffer quotedFile;
+ QTestCharBuffer cdataDesc;
+ QXmlTestLogger::xmlQuote(quotedFile, element->attributeValue(QTest::AI_File));
+ QXmlTestLogger::xmlCdata(cdataDesc, element->attributeValue(QTest::AI_Description));
+
+ QTest::qt_asprintf(formatted, "<Message type=\"%s\" %s=\"%s\" %s=\"%s\">\n <Description><![CDATA[%s]]></Description>\n</Message>\n",
element->attributeValue(QTest::AI_Type),
element->attributeName(QTest::AI_File),
- quotedFile,
+ quotedFile.constData(),
element->attributeName(QTest::AI_Line),
element->attributeValue(QTest::AI_Line),
- cdataDesc);
+ cdataDesc.constData());
break;
}
case QTest::LET_Benchmark: {
// assuming value and iterations don't need quoting
- char quotedMetric[256];
- char quotedTag[256];
- QXmlTestLogger::xmlQuote(quotedMetric, element->attributeValue(QTest::AI_Metric),
- sizeof(quotedMetric));
- QXmlTestLogger::xmlQuote(quotedTag, element->attributeValue(QTest::AI_Tag),
- sizeof(quotedTag));
-
- QTest::qt_snprintf(formatted, 1024, "<BenchmarkResult %s=\"%s\" %s=\"%s\" %s=\"%s\" %s=\"%s\" />\n",
+ QTestCharBuffer quotedMetric;
+ QTestCharBuffer quotedTag;
+ QXmlTestLogger::xmlQuote(quotedMetric, element->attributeValue(QTest::AI_Metric));
+ QXmlTestLogger::xmlQuote(quotedTag, element->attributeValue(QTest::AI_Tag));
+
+ QTest::qt_asprintf(formatted, "<BenchmarkResult %s=\"%s\" %s=\"%s\" %s=\"%s\" %s=\"%s\" />\n",
element->attributeName(QTest::AI_Metric),
- quotedMetric,
+ quotedMetric.constData(),
element->attributeName(QTest::AI_Tag),
- quotedTag,
+ quotedTag.constData(),
element->attributeName(QTest::AI_Value),
element->attributeValue(QTest::AI_Value),
element->attributeName(QTest::AI_Iterations),
@@ -121,61 +115,60 @@ void QTestLightXmlStreamer::formatStart(const QTestElement *element, char *forma
break;
}
default:
- QTest::qt_snprintf(formatted, 10, "");
+ QTest::qt_asprintf(formatted, "");
}
}
-void QTestLightXmlStreamer::formatEnd(const QTestElement *element, char *formatted) const
+void QTestLightXmlStreamer::formatEnd(const QTestElement *element, char **formatted) const
{
if(!element || !formatted)
return;
if (element->elementType() == QTest::LET_TestCase) {
if( element->attribute(QTest::AI_Result) && element->childElements())
- QTest::qt_snprintf(formatted, 1024, "</Incident>\n</TestFunction>\n");
+ QTest::qt_asprintf(formatted, "</Incident>\n</TestFunction>\n");
else
- QTest::qt_snprintf(formatted, 1024, "</TestFunction>\n");
+ QTest::qt_asprintf(formatted, "</TestFunction>\n");
}
else
- QTest::qt_snprintf(formatted, 10, "");
+ QTest::qt_asprintf(formatted, "");
}
-void QTestLightXmlStreamer::formatBeforeAttributes(const QTestElement *element, char *formatted) const
+void QTestLightXmlStreamer::formatBeforeAttributes(const QTestElement *element, char **formatted) const
{
if(!element || !formatted)
return;
if (element->elementType() == QTest::LET_TestCase && element->attribute(QTest::AI_Result)){
- char buf[900];
- char quotedFile[700];
- QXmlTestLogger::xmlQuote(quotedFile, element->attributeValue(QTest::AI_File),
- sizeof(quotedFile));
+ QTestCharBuffer buf;
+ QTestCharBuffer quotedFile;
+ QXmlTestLogger::xmlQuote(quotedFile, element->attributeValue(QTest::AI_File));
- QTest::qt_snprintf(buf, sizeof(buf), "%s=\"%s\" %s=\"%s\"",
+ QTest::qt_asprintf(buf, "%s=\"%s\" %s=\"%s\"",
element->attributeName(QTest::AI_File),
- quotedFile,
+ quotedFile.constData(),
element->attributeName(QTest::AI_Line),
element->attributeValue(QTest::AI_Line));
if( !element->childElements() )
- QTest::qt_snprintf(formatted, 1024, "<Incident type=\"%s\" %s/>\n",
- element->attributeValue(QTest::AI_Result), buf);
+ QTest::qt_asprintf(formatted, "<Incident type=\"%s\" %s/>\n",
+ element->attributeValue(QTest::AI_Result), buf.constData());
else
- QTest::qt_snprintf(formatted, 1024, "<Incident type=\"%s\" %s>\n",
- element->attributeValue(QTest::AI_Result), buf);
+ QTest::qt_asprintf(formatted, "<Incident type=\"%s\" %s>\n",
+ element->attributeValue(QTest::AI_Result), buf.constData());
}else{
- QTest::qt_snprintf(formatted, 10, "");
+ QTest::qt_asprintf(formatted, "");
}
}
void QTestLightXmlStreamer::output(QTestElement *element) const
{
- char buf[1024];
- QTest::qt_snprintf(buf, sizeof(buf), "<Environment>\n <QtVersion>%s</QtVersion>\n <QTestVersion>%s</QTestVersion>\n",
+ QTestCharBuffer buf;
+ QTest::qt_asprintf(buf, "<Environment>\n <QtVersion>%s</QtVersion>\n <QTestVersion>%s</QTestVersion>\n",
qVersion(), QTEST_VERSION_STR );
outputString(buf);
- QTest::qt_snprintf(buf, sizeof(buf), "</Environment>\n");
+ QTest::qt_asprintf(buf, "</Environment>\n");
outputString(buf);
QTestBasicStreamer::output(element);
diff --git a/src/testlib/qtestlightxmlstreamer.h b/src/testlib/qtestlightxmlstreamer.h
index 5a16327..6dafdcc 100644
--- a/src/testlib/qtestlightxmlstreamer.h
+++ b/src/testlib/qtestlightxmlstreamer.h
@@ -59,9 +59,9 @@ class QTestLightXmlStreamer: public QTestBasicStreamer
QTestLightXmlStreamer();
~QTestLightXmlStreamer();
- void formatStart(const QTestElement *element = 0, char *formatted = 0) const;
- void formatEnd(const QTestElement *element = 0, char *formatted = 0) const;
- void formatBeforeAttributes(const QTestElement *element = 0, char *formatted = 0) const;
+ void formatStart(const QTestElement *element, char **formatted) const;
+ void formatEnd(const QTestElement *element, char **formatted) const;
+ void formatBeforeAttributes(const QTestElement *element, char **formatted) const;
void output(QTestElement *element) const;
};
diff --git a/src/testlib/qtestxmlstreamer.cpp b/src/testlib/qtestxmlstreamer.cpp
index 5172bcd..1b6e674 100644
--- a/src/testlib/qtestxmlstreamer.cpp
+++ b/src/testlib/qtestxmlstreamer.cpp
@@ -60,86 +60,78 @@ QTestXmlStreamer::QTestXmlStreamer()
QTestXmlStreamer::~QTestXmlStreamer()
{}
-void QTestXmlStreamer::formatStart(const QTestElement *element, char *formatted) const
+void QTestXmlStreamer::formatStart(const QTestElement *element, char **formatted) const
{
if(!element || !formatted)
return;
switch(element->elementType()){
case QTest::LET_TestCase: {
- char quotedTf[950];
- QXmlTestLogger::xmlQuote(quotedTf, element->attributeValue(QTest::AI_Name),
- sizeof(quotedTf));
+ QTestCharBuffer quotedTf;
+ QXmlTestLogger::xmlQuote(quotedTf, element->attributeValue(QTest::AI_Name));
- QTest::qt_snprintf(formatted, 1024, "<TestFunction name=\"%s\">\n", quotedTf);
+ QTest::qt_asprintf(formatted, "<TestFunction name=\"%s\">\n", quotedTf.constData());
break;
}
case QTest::LET_Failure: {
- char cdataDesc[800];
- QXmlTestLogger::xmlCdata(cdataDesc, element->attributeValue(QTest::AI_Description),
- sizeof(cdataDesc));
+ QTestCharBuffer cdataDesc;
+ QXmlTestLogger::xmlCdata(cdataDesc, element->attributeValue(QTest::AI_Description));
- char location[100];
- char quotedFile[70];
- QXmlTestLogger::xmlQuote(quotedFile, element->attributeValue(QTest::AI_File),
- sizeof(quotedFile));
+ QTestCharBuffer location;
+ QTestCharBuffer quotedFile;
+ QXmlTestLogger::xmlQuote(quotedFile, element->attributeValue(QTest::AI_File));
- QTest::qt_snprintf(location, sizeof(location), "%s=\"%s\" %s=\"%s\"",
+ QTest::qt_asprintf(location, "%s=\"%s\" %s=\"%s\"",
element->attributeName(QTest::AI_File),
- quotedFile,
+ quotedFile.constData(),
element->attributeName(QTest::AI_Line),
element->attributeValue(QTest::AI_Line));
if (element->attribute(QTest::AI_Tag)) {
- char cdataTag[100];
- QXmlTestLogger::xmlCdata(cdataTag, element->attributeValue(QTest::AI_Tag),
- sizeof(cdataTag));
- QTest::qt_snprintf(formatted, 1024, "<Incident type=\"%s\" %s>\n"
+ QTestCharBuffer cdataTag;
+ QXmlTestLogger::xmlCdata(cdataTag, element->attributeValue(QTest::AI_Tag));
+ QTest::qt_asprintf(formatted, "<Incident type=\"%s\" %s>\n"
" <DataTag><![CDATA[%s]]></DataTag>\n"
" <Description><![CDATA[%s]]></Description>\n"
"</Incident>\n", element->attributeValue(QTest::AI_Result),
- location, cdataTag, cdataDesc);
+ location.constData(), cdataTag.constData(), cdataDesc.constData());
}
else {
- QTest::qt_snprintf(formatted, 1024, "<Incident type=\"%s\" %s>\n"
+ QTest::qt_asprintf(formatted, "<Incident type=\"%s\" %s>\n"
" <Description><![CDATA[%s]]></Description>\n"
"</Incident>\n", element->attributeValue(QTest::AI_Result),
- location, cdataDesc);
+ location.constData(), cdataDesc.constData());
}
break;
}
case QTest::LET_Error: {
// assuming type and attribute names don't need quoting
- char quotedFile[128];
- char cdataDesc[700];
- QXmlTestLogger::xmlQuote(quotedFile, element->attributeValue(QTest::AI_File),
- sizeof(quotedFile));
- QXmlTestLogger::xmlCdata(cdataDesc, element->attributeValue(QTest::AI_Description),
- sizeof(cdataDesc));
-
- QTest::qt_snprintf(formatted, 1024, "<Message type=\"%s\" %s=\"%s\" %s=\"%s\">\n <Description><![CDATA[%s]]></Description>\n</Message>\n",
+ QTestCharBuffer quotedFile;
+ QTestCharBuffer cdataDesc;
+ QXmlTestLogger::xmlQuote(quotedFile, element->attributeValue(QTest::AI_File));
+ QXmlTestLogger::xmlCdata(cdataDesc, element->attributeValue(QTest::AI_Description));
+
+ QTest::qt_asprintf(formatted, "<Message type=\"%s\" %s=\"%s\" %s=\"%s\">\n <Description><![CDATA[%s]]></Description>\n</Message>\n",
element->attributeValue(QTest::AI_Type),
element->attributeName(QTest::AI_File),
- quotedFile,
+ quotedFile.constData(),
element->attributeName(QTest::AI_Line),
element->attributeValue(QTest::AI_Line),
- cdataDesc);
+ cdataDesc.constData());
break;
}
case QTest::LET_Benchmark: {
// assuming value and iterations don't need quoting
- char quotedMetric[256];
- char quotedTag[256];
- QXmlTestLogger::xmlQuote(quotedMetric, element->attributeValue(QTest::AI_Metric),
- sizeof(quotedMetric));
- QXmlTestLogger::xmlQuote(quotedTag, element->attributeValue(QTest::AI_Tag),
- sizeof(quotedTag));
-
- QTest::qt_snprintf(formatted, 1024, "<BenchmarkResult %s=\"%s\" %s=\"%s\" %s=\"%s\" %s=\"%s\" />\n",
+ QTestCharBuffer quotedMetric;
+ QTestCharBuffer quotedTag;
+ QXmlTestLogger::xmlQuote(quotedMetric, element->attributeValue(QTest::AI_Metric));
+ QXmlTestLogger::xmlQuote(quotedTag, element->attributeValue(QTest::AI_Tag));
+
+ QTest::qt_asprintf(formatted, "<BenchmarkResult %s=\"%s\" %s=\"%s\" %s=\"%s\" %s=\"%s\" />\n",
element->attributeName(QTest::AI_Metric),
- quotedMetric,
+ quotedMetric.constData(),
element->attributeName(QTest::AI_Tag),
- quotedTag,
+ quotedTag.constData(),
element->attributeName(QTest::AI_Value),
element->attributeValue(QTest::AI_Value),
element->attributeName(QTest::AI_Iterations),
@@ -147,71 +139,70 @@ void QTestXmlStreamer::formatStart(const QTestElement *element, char *formatted)
break;
}
default:
- QTest::qt_snprintf(formatted, 10, "");
+ QTest::qt_asprintf(formatted, "");
}
}
-void QTestXmlStreamer::formatEnd(const QTestElement *element, char *formatted) const
+void QTestXmlStreamer::formatEnd(const QTestElement *element, char **formatted) const
{
if(!element || !formatted)
return;
if (element->elementType() == QTest::LET_TestCase) {
- QTest::qt_snprintf(formatted, 1024, "</TestFunction>\n");
+ QTest::qt_asprintf(formatted, "</TestFunction>\n");
}
else
- QTest::qt_snprintf(formatted, 10, "");
+ QTest::qt_asprintf(formatted, "");
}
-void QTestXmlStreamer::formatBeforeAttributes(const QTestElement *element, char *formatted) const
+void QTestXmlStreamer::formatBeforeAttributes(const QTestElement *element, char **formatted) const
{
if(!element || !formatted)
return;
if (element->elementType() == QTest::LET_TestCase && element->attribute(QTest::AI_Result)){
- char buf[900];
- char quotedFile[700];
- QXmlTestLogger::xmlQuote(quotedFile, element->attributeValue(QTest::AI_File),
- sizeof(quotedFile));
+ QTestCharBuffer buf;
+ QTestCharBuffer quotedFile;
+ QXmlTestLogger::xmlQuote(quotedFile, element->attributeValue(QTest::AI_File));
- QTest::qt_snprintf(buf, sizeof(buf), "%s=\"%s\" %s=\"%s\"",
+ QTest::qt_asprintf(buf, "%s=\"%s\" %s=\"%s\"",
element->attributeName(QTest::AI_File),
- quotedFile,
+ quotedFile.constData(),
element->attributeName(QTest::AI_Line),
element->attributeValue(QTest::AI_Line));
if( !element->childElements() ) {
- QTest::qt_snprintf(formatted, 1024, "<Incident type=\"%s\" %s/>\n",
- element->attributeValue(QTest::AI_Result), buf);
+ QTest::qt_asprintf(formatted, "<Incident type=\"%s\" %s/>\n",
+ element->attributeValue(QTest::AI_Result), buf.constData());
}
else {
- QTest::qt_snprintf(formatted, 10, "");
+ QTest::qt_asprintf(formatted, "");
}
}else{
- QTest::qt_snprintf(formatted, 10, "");
+ QTest::qt_asprintf(formatted, "");
}
}
void QTestXmlStreamer::output(QTestElement *element) const
{
- char buf[1024];
- char quotedTc[800];
- QXmlTestLogger::xmlQuote(quotedTc, QTestResult::currentTestObjectName(), sizeof(quotedTc));
+ QTestCharBuffer buf;
+ QTestCharBuffer quotedTc;
+ QXmlTestLogger::xmlQuote(quotedTc, QTestResult::currentTestObjectName());
- QTest::qt_snprintf(buf, sizeof(buf), "<?xml version=\"1.0\" encoding=\"ISO-8859-1\"?>\n<TestCase name=\"%s\">\n",
- quotedTc);
+ QTest::qt_asprintf(buf, "<?xml version=\"1.0\" encoding=\"ISO-8859-1\"?>\n<TestCase name=\"%s\">\n",
+ quotedTc.constData());
outputString(buf);
- QTest::qt_snprintf(buf, sizeof(buf), "<Environment>\n <QtVersion>%s</QtVersion>\n <QTestVersion>%s</QTestVersion>\n",
+ QTest::qt_asprintf(buf, "<Environment>\n <QtVersion>%s</QtVersion>\n <QTestVersion>%s</QTestVersion>\n",
qVersion(), QTEST_VERSION_STR );
outputString(buf);
- QTest::qt_snprintf(buf, sizeof(buf), "</Environment>\n");
+ QTest::qt_asprintf(buf, "</Environment>\n");
outputString(buf);
QTestBasicStreamer::output(element);
- QTest::qt_snprintf(buf, sizeof(buf), "</TestCase>\n");
+ QTest::qt_asprintf(buf, "</TestCase>\n");
outputString(buf);
}
diff --git a/src/testlib/qtestxmlstreamer.h b/src/testlib/qtestxmlstreamer.h
index 3cb1c60..a601f60 100644
--- a/src/testlib/qtestxmlstreamer.h
+++ b/src/testlib/qtestxmlstreamer.h
@@ -59,9 +59,9 @@ class QTestXmlStreamer: public QTestBasicStreamer
QTestXmlStreamer();
~QTestXmlStreamer();
- void formatStart(const QTestElement *element = 0, char *formatted = 0) const;
- void formatEnd(const QTestElement *element = 0, char *formatted = 0) const;
- void formatBeforeAttributes(const QTestElement *element = 0, char *formatted = 0) const;
+ void formatStart(const QTestElement *element, char **formatted) const;
+ void formatEnd(const QTestElement *element, char **formatted) const;
+ void formatBeforeAttributes(const QTestElement *element, char **formatted) const;
void output(QTestElement *element) const;
};
diff --git a/src/testlib/qtestxunitstreamer.cpp b/src/testlib/qtestxunitstreamer.cpp
index 6690cec..d5d2631 100644
--- a/src/testlib/qtestxunitstreamer.cpp
+++ b/src/testlib/qtestxunitstreamer.cpp
@@ -73,7 +73,7 @@ void QTestXunitStreamer::indentForElement(const QTestElement* element, char* buf
}
}
-void QTestXunitStreamer::formatStart(const QTestElement *element, char *formatted) const
+void QTestXunitStreamer::formatStart(const QTestElement *element, char **formatted) const
{
if(!element || !formatted )
return;
@@ -84,34 +84,34 @@ void QTestXunitStreamer::formatStart(const QTestElement *element, char *formatte
// Errors are written as CDATA within system-err, comments elsewhere
if (element->elementType() == QTest::LET_Error) {
if (element->parentElement()->elementType() == QTest::LET_SystemError) {
- QTest::qt_snprintf(formatted, 1024, "<![CDATA[");
+ QTest::qt_asprintf(formatted, "<![CDATA[");
}
else {
- QTest::qt_snprintf(formatted, 1024, "%s<!--", indent);
+ QTest::qt_asprintf(formatted, "%s<!--", indent);
}
return;
}
- QTest::qt_snprintf(formatted, 1024, "%s<%s", indent, element->elementName());
+ QTest::qt_asprintf(formatted, "%s<%s", indent, element->elementName());
}
-void QTestXunitStreamer::formatEnd(const QTestElement *element, char *formatted) const
+void QTestXunitStreamer::formatEnd(const QTestElement *element, char **formatted) const
{
if(!element || !formatted )
return;
if(!element->childElements()){
- QTest::qt_snprintf(formatted, 10, "");
+ QTest::qt_asprintf(formatted, "");
return;
}
char indent[20];
indentForElement(element, indent, sizeof(indent));
- QTest::qt_snprintf(formatted, 1024, "%s</%s>\n", indent, element->elementName());
+ QTest::qt_asprintf(formatted, "%s</%s>\n", indent, element->elementName());
}
-void QTestXunitStreamer::formatAttributes(const QTestElement* element, const QTestElementAttribute *attribute, char *formatted) const
+void QTestXunitStreamer::formatAttributes(const QTestElement* element, const QTestElementAttribute *attribute, char **formatted) const
{
if(!attribute || !formatted )
return;
@@ -124,7 +124,7 @@ void QTestXunitStreamer::formatAttributes(const QTestElement* element, const QTe
if (attrindex != QTest::AI_Description) return;
- QXmlTestLogger::xmlCdata(formatted, attribute->value(), 1024);
+ QXmlTestLogger::xmlCdata(formatted, attribute->value());
return;
}
@@ -135,16 +135,16 @@ void QTestXunitStreamer::formatAttributes(const QTestElement* element, const QTe
key = attribute->name();
if (key) {
- char quotedValue[900];
- QXmlTestLogger::xmlQuote(quotedValue, attribute->value(), sizeof(quotedValue));
- QTest::qt_snprintf(formatted, 1024, " %s=\"%s\"", key, quotedValue);
+ QTestCharBuffer quotedValue;
+ QXmlTestLogger::xmlQuote(quotedValue, attribute->value());
+ QTest::qt_asprintf(formatted, " %s=\"%s\"", key, quotedValue.constData());
}
else {
- QTest::qt_snprintf(formatted, 10, "");
+ QTest::qt_asprintf(formatted, "");
}
}
-void QTestXunitStreamer::formatAfterAttributes(const QTestElement *element, char *formatted) const
+void QTestXunitStreamer::formatAfterAttributes(const QTestElement *element, char **formatted) const
{
if(!element || !formatted )
return;
@@ -152,31 +152,29 @@ void QTestXunitStreamer::formatAfterAttributes(const QTestElement *element, char
// Errors are written as CDATA within system-err, comments elsewhere
if (element->elementType() == QTest::LET_Error) {
if (element->parentElement()->elementType() == QTest::LET_SystemError) {
- QTest::qt_snprintf(formatted, 1024, "]]>\n");
+ QTest::qt_asprintf(formatted, "]]>\n");
}
else {
- QTest::qt_snprintf(formatted, 1024, " -->\n");
+ QTest::qt_asprintf(formatted, " -->\n");
}
return;
}
if(!element->childElements())
- QTest::qt_snprintf(formatted, 10, "/>\n");
+ QTest::qt_asprintf(formatted, "/>\n");
else
- QTest::qt_snprintf(formatted, 10, ">\n");
+ QTest::qt_asprintf(formatted, ">\n");
}
void QTestXunitStreamer::output(QTestElement *element) const
{
- char buf[1024];
- QTest::qt_snprintf(buf, sizeof(buf), "<?xml version=\"1.0\" encoding=\"UTF-8\" ?>\n");
- outputString(buf);
+ outputString("<?xml version=\"1.0\" encoding=\"UTF-8\" ?>\n");
QTestBasicStreamer::output(element);
}
void QTestXunitStreamer::outputElements(QTestElement *element, bool) const
{
- char buf[1024];
+ QTestCharBuffer buf;
bool hasChildren;
/*
Elements are in reverse order of occurrence, so start from the end and work
diff --git a/src/testlib/qtestxunitstreamer.h b/src/testlib/qtestxunitstreamer.h
index 9817fd3..044307f 100644
--- a/src/testlib/qtestxunitstreamer.h
+++ b/src/testlib/qtestxunitstreamer.h
@@ -58,10 +58,10 @@ class QTestXunitStreamer: public QTestBasicStreamer
QTestXunitStreamer();
~QTestXunitStreamer();
- void formatStart(const QTestElement *element = 0, char *formatted = 0) const;
- void formatEnd(const QTestElement *element = 0, char *formatted = 0) const;
- void formatAfterAttributes(const QTestElement *element = 0, char *formatted = 0) const;
- void formatAttributes(const QTestElement *element = 0, const QTestElementAttribute *attribute = 0, char *formatted = 0) const;
+ void formatStart(const QTestElement *element, char **formatted) const;
+ void formatEnd(const QTestElement *element, char **formatted) const;
+ void formatAfterAttributes(const QTestElement *element, char **formatted) const;
+ void formatAttributes(const QTestElement *element, const QTestElementAttribute *attribute, char **formatted) const;
void output(QTestElement *element) const;
void outputElements(QTestElement *element, bool isChildElement = false) const;
diff --git a/src/testlib/qxmltestlogger.cpp b/src/testlib/qxmltestlogger.cpp
index 85eb0dd..fca7bfc 100644
--- a/src/testlib/qxmltestlogger.cpp
+++ b/src/testlib/qxmltestlogger.cpp
@@ -104,18 +104,18 @@ QXmlTestLogger::~QXmlTestLogger()
void QXmlTestLogger::startLogging()
{
QAbstractTestLogger::startLogging();
- char buf[1024];
+ QTestCharBuffer buf;
if (xmlmode == QXmlTestLogger::Complete) {
- char quotedTc[900];
- xmlQuote(quotedTc, QTestResult::currentTestObjectName(), sizeof(quotedTc));
- QTest::qt_snprintf(buf, sizeof(buf),
+ QTestCharBuffer quotedTc;
+ xmlQuote(quotedTc, QTestResult::currentTestObjectName());
+ QTest::qt_asprintf(buf,
"<?xml version=\"1.0\" encoding=\"ISO-8859-1\"?>\n"
- "<TestCase name=\"%s\">\n", quotedTc);
+ "<TestCase name=\"%s\">\n", quotedTc.constData());
outputString(buf);
}
- QTest::qt_snprintf(buf, sizeof(buf),
+ QTest::qt_asprintf(buf,
"<Environment>\n"
" <QtVersion>%s</QtVersion>\n"
" <QTestVersion>"QTEST_VERSION_STR"</QTestVersion>\n"
@@ -134,10 +134,10 @@ void QXmlTestLogger::stopLogging()
void QXmlTestLogger::enterTestFunction(const char *function)
{
- char buf[1024];
- char quotedFunction[950];
- xmlQuote(quotedFunction, function, sizeof(quotedFunction));
- QTest::qt_snprintf(buf, sizeof(buf), "<TestFunction name=\"%s\">\n", quotedFunction);
+ QTestCharBuffer buf;
+ QTestCharBuffer quotedFunction;
+ xmlQuote(quotedFunction, function);
+ QTest::qt_asprintf(buf, "<TestFunction name=\"%s\">\n", quotedFunction.constData());
outputString(buf);
}
@@ -208,51 +208,49 @@ static const char *messageFormatString(bool noDescription, bool noTag)
void QXmlTestLogger::addIncident(IncidentTypes type, const char *description,
const char *file, int line)
{
- // buffer must be large enough to hold all quoted/cdata buffers plus the format string itself
- char buf[5000];
+ QTestCharBuffer buf;
const char *tag = QTestResult::currentDataTag();
const char *gtag = QTestResult::currentGlobalDataTag();
const char *filler = (tag && gtag) ? ":" : "";
const bool notag = QTest::isEmpty(tag) && QTest::isEmpty(gtag);
- char quotedFile[1024];
- char cdataGtag[1024];
- char cdataTag[1024];
- char cdataDescription[1024];
+ QTestCharBuffer quotedFile;
+ QTestCharBuffer cdataGtag;
+ QTestCharBuffer cdataTag;
+ QTestCharBuffer cdataDescription;
- xmlQuote(quotedFile, file, sizeof(quotedFile));
- xmlCdata(cdataGtag, gtag, sizeof(cdataGtag));
- xmlCdata(cdataTag, tag, sizeof(cdataTag));
- xmlCdata(cdataDescription, description, sizeof(cdataDescription));
+ xmlQuote(quotedFile, file);
+ xmlCdata(cdataGtag, gtag);
+ xmlCdata(cdataTag, tag);
+ xmlCdata(cdataDescription, description);
- QTest::qt_snprintf(buf, sizeof(buf),
+ QTest::qt_asprintf(buf,
QTest::incidentFormatString(QTest::isEmpty(description), notag),
QTest::xmlIncidentType2String(type),
- quotedFile, line,
- cdataGtag,
+ quotedFile.constData(), line,
+ cdataGtag.constData(),
filler,
- cdataTag,
- cdataDescription);
+ cdataTag.constData(),
+ cdataDescription.constData());
outputString(buf);
}
void QXmlTestLogger::addBenchmarkResult(const QBenchmarkResult &result)
{
- char buf[1536];
- char quotedMetric[64];
- char quotedTag[1024];
+ QTestCharBuffer buf;
+ QTestCharBuffer quotedMetric;
+ QTestCharBuffer quotedTag;
xmlQuote(quotedMetric,
- QBenchmarkGlobalData::current->measurer->metricText().toAscii().constData(),
- sizeof(quotedMetric));
- xmlQuote(quotedTag, result.context.tag.toAscii().constData(), sizeof(quotedTag));
+ QBenchmarkGlobalData::current->measurer->metricText().toAscii().constData());
+ xmlQuote(quotedTag, result.context.tag.toAscii().constData());
- QTest::qt_snprintf(
- buf, sizeof(buf),
+ QTest::qt_asprintf(
+ buf,
QTest::benchmarkResultFormatString(),
- quotedMetric,
- quotedTag,
+ quotedMetric.constData(),
+ quotedTag.constData(),
QByteArray::number(result.value).constData(), //no 64-bit qt_snprintf support
result.iterations);
outputString(buf);
@@ -261,30 +259,30 @@ void QXmlTestLogger::addBenchmarkResult(const QBenchmarkResult &result)
void QXmlTestLogger::addMessage(MessageTypes type, const char *message,
const char *file, int line)
{
- char buf[5000];
+ QTestCharBuffer buf;
const char *tag = QTestResult::currentDataTag();
const char *gtag = QTestResult::currentGlobalDataTag();
const char *filler = (tag && gtag) ? ":" : "";
const bool notag = QTest::isEmpty(tag) && QTest::isEmpty(gtag);
- char quotedFile[1024];
- char cdataGtag[1024];
- char cdataTag[1024];
- char cdataDescription[1024];
+ QTestCharBuffer quotedFile;
+ QTestCharBuffer cdataGtag;
+ QTestCharBuffer cdataTag;
+ QTestCharBuffer cdataDescription;
- xmlQuote(quotedFile, file, sizeof(quotedFile));
- xmlCdata(cdataGtag, gtag, sizeof(cdataGtag));
- xmlCdata(cdataTag, tag, sizeof(cdataTag));
- xmlCdata(cdataDescription, message, sizeof(cdataDescription));
+ xmlQuote(quotedFile, file);
+ xmlCdata(cdataGtag, gtag);
+ xmlCdata(cdataTag, tag);
+ xmlCdata(cdataDescription, message);
- QTest::qt_snprintf(buf, sizeof(buf),
+ QTest::qt_asprintf(buf,
QTest::messageFormatString(QTest::isEmpty(message), notag),
QTest::xmlMessageType2String(type),
- quotedFile, line,
- cdataGtag,
+ quotedFile.constData(), line,
+ cdataGtag.constData(),
filler,
- cdataTag,
- cdataDescription);
+ cdataTag.constData(),
+ cdataDescription.constData());
outputString(buf);
}
@@ -294,29 +292,30 @@ void QXmlTestLogger::addMessage(MessageTypes type, const char *message,
XML characters as necessary so that dest is suitable for use in an XML
quoted attribute string.
*/
-void QXmlTestLogger::xmlQuote(char* dest, char const* src, size_t n)
+int QXmlTestLogger::xmlQuote(char* dest, char const* src, size_t n)
{
- if (n == 0) return;
+ if (n == 0) return 0;
*dest = 0;
- if (!src) return;
+ if (!src) return 0;
+ char* begin = dest;
char* end = dest + n;
while (dest < end) {
switch (*src) {
#define MAP_ENTITY(chr, ent) \
- case chr: \
- if (dest + sizeof(ent) < end) { \
- strcpy(dest, ent); \
- dest += sizeof(ent) - 1; \
- } \
- else { \
- *dest = 0; \
- return; \
- } \
- ++src; \
+ case chr: \
+ if (dest + sizeof(ent) < end) { \
+ strcpy(dest, ent); \
+ dest += sizeof(ent) - 1; \
+ } \
+ else { \
+ *dest = 0; \
+ return (dest+sizeof(ent)-begin); \
+ } \
+ ++src; \
break;
MAP_ENTITY('>', "&gt;");
@@ -333,7 +332,7 @@ void QXmlTestLogger::xmlQuote(char* dest, char const* src, size_t n)
case 0:
*dest = 0;
- return;
+ return (dest-begin);
default:
*dest = *src;
@@ -345,29 +344,31 @@ void QXmlTestLogger::xmlQuote(char* dest, char const* src, size_t n)
// If we get here, dest was completely filled (dest == end)
*(dest-1) = 0;
+ return (dest-begin);
}
/*
Copy up to n characters from the src string into dest, escaping any
special strings such that dest is suitable for use in an XML CDATA section.
*/
-void QXmlTestLogger::xmlCdata(char* dest, char const* src, size_t n)
+int QXmlTestLogger::xmlCdata(char* dest, char const* src, size_t n)
{
- if (!n) return;
+ if (!n) return 0;
if (!src || n == 1) {
*dest = 0;
- return;
+ return 0;
}
- char const CDATA_END[] = "]]>";
- char const CDATA_END_ESCAPED[] = "]]]><![CDATA[]>";
+ static char const CDATA_END[] = "]]>";
+ static char const CDATA_END_ESCAPED[] = "]]]><![CDATA[]>";
+ char* begin = dest;
char* end = dest + n;
while (dest < end) {
if (!*src) {
*dest = 0;
- return;
+ return (dest-begin);
}
if (!strncmp(src, CDATA_END, sizeof(CDATA_END)-1)) {
@@ -378,7 +379,7 @@ void QXmlTestLogger::xmlCdata(char* dest, char const* src, size_t n)
}
else {
*dest = 0;
- return;
+ return (dest+sizeof(CDATA_END_ESCAPED)-begin);
}
continue;
}
@@ -390,6 +391,52 @@ void QXmlTestLogger::xmlCdata(char* dest, char const* src, size_t n)
// If we get here, dest was completely filled (dest == end)
*(dest-1) = 0;
+ return (dest-begin);
+}
+
+typedef int (*StringFormatFunction)(char*,char const*,size_t);
+
+/*
+ A wrapper for string functions written to work with a fixed size buffer so they can be called
+ with a dynamically allocated buffer.
+*/
+int allocateStringFn(char** str, char const* src, StringFormatFunction func)
+{
+ static const int MAXSIZE = 1024*1024*2;
+
+ int size = 32;
+ delete[] *str;
+ *str = new char[size];
+
+ int res = 0;
+
+ for (;;) {
+ res = func(*str, src, size);
+ (*str)[size - 1] = '\0';
+ if (res < size) {
+ // We succeeded or fatally failed
+ break;
+ }
+ // buffer wasn't big enough, try again
+ size *= 2;
+ if (size > MAXSIZE) {
+ break;
+ }
+ delete[] *str;
+ *str = new char[size];
+ }
+
+ return res;
+}
+
+int QXmlTestLogger::xmlQuote(char** str, char const* src)
+{
+ return allocateStringFn(str, src, QXmlTestLogger::xmlQuote);
+}
+
+int QXmlTestLogger::xmlCdata(char** str, char const* src)
+{
+ return allocateStringFn(str, src, QXmlTestLogger::xmlCdata);
}
QT_END_NAMESPACE
diff --git a/src/testlib/qxmltestlogger_p.h b/src/testlib/qxmltestlogger_p.h
index 526b471..a7cc00a 100644
--- a/src/testlib/qxmltestlogger_p.h
+++ b/src/testlib/qxmltestlogger_p.h
@@ -79,8 +79,10 @@ public:
void addMessage(MessageTypes type, const char *message,
const char *file = 0, int line = 0);
- static void xmlCdata(char* dest, char const* src, size_t n);
- static void xmlQuote(char* dest, char const* src, size_t n);
+ static int xmlCdata(char** dest, char const* src);
+ static int xmlQuote(char** dest, char const* src);
+ static int xmlCdata(char* dest, char const* src, size_t n);
+ static int xmlQuote(char* dest, char const* src, size_t n);
private:
XmlMode xmlmode;
diff --git a/src/tools/moc/generator.cpp b/src/tools/moc/generator.cpp
index b872dfd..e3ce2ec 100644
--- a/src/tools/moc/generator.cpp
+++ b/src/tools/moc/generator.cpp
@@ -56,6 +56,8 @@ enum PropertyFlags {
EnumOrFlag = 0x00000008,
StdCppSet = 0x00000100,
// Override = 0x00000200,
+ Constant = 0x00000400,
+ Final = 0x00000800,
Designable = 0x00001000,
ResolveDesignable = 0x00002000,
Scriptable = 0x00004000,
@@ -68,6 +70,7 @@ enum PropertyFlags {
ResolveUser = 0x00200000,
Notify = 0x00400000
};
+
enum MethodFlags {
AccessPrivate = 0x00,
AccessProtected = 0x01,
@@ -202,10 +205,10 @@ void Generator::generateCode()
QByteArray qualifiedClassNameIdentifier = cdef->qualified;
qualifiedClassNameIdentifier.replace(':', '_');
- int index = 12;
+ int index = 13;
fprintf(out, "static const uint qt_meta_data_%s[] = {\n", qualifiedClassNameIdentifier.constData());
fprintf(out, "\n // content:\n");
- fprintf(out, " %4d, // revision\n", 2);
+ fprintf(out, " %4d, // revision\n", 3);
fprintf(out, " %4d, // classname\n", strreg(cdef->qualified));
fprintf(out, " %4d, %4d, // classinfo\n", cdef->classInfoList.count(), cdef->classInfoList.count() ? index : 0);
index += cdef->classInfoList.count() * 2;
@@ -225,6 +228,9 @@ void Generator::generateCode()
fprintf(out, " %4d, %4d, // constructors\n", isConstructible ? cdef->constructorList.count() : 0,
isConstructible ? index : 0);
+ fprintf(out, " %4d, // flags\n", 0);
+
+
//
// Build classinfo array
//
@@ -379,7 +385,7 @@ void Generator::generateCode()
if (isQt || !cdef->hasQObject)
return;
- fprintf(out, "\nconst QMetaObject *%s::metaObject() const\n{\n return &staticMetaObject;\n}\n",
+ fprintf(out, "\nconst QMetaObject *%s::metaObject() const\n{\n return QObject::d_ptr->metaObject ? QObject::d_ptr->metaObject : &staticMetaObject;\n}\n",
cdef->qualified.constData());
//
// Generate smart cast function
@@ -597,6 +603,11 @@ void Generator::generateProperties()
if (p.notifyId != -1)
flags |= Notify;
+ if (p.constant)
+ flags |= Constant;
+ if (p.final)
+ flags |= Final;
+
fprintf(out, " %4d, %4d, ",
strreg(p.name),
strreg(p.type));
diff --git a/src/tools/moc/moc.cpp b/src/tools/moc/moc.cpp
index 797595f..74b1a67 100644
--- a/src/tools/moc/moc.cpp
+++ b/src/tools/moc/moc.cpp
@@ -429,7 +429,7 @@ bool Moc::parseMaybeFunction(const ClassDef *cdef, FunctionDef *def)
{
def->isVirtual = false;
//skip modifiers and attributes
- while (test(INLINE) || test(STATIC) ||
+ while (test(EXPLICIT) || test(INLINE) || test(STATIC) ||
(test(VIRTUAL) && (def->isVirtual = true)) //mark as virtual
|| testFunctionAttribute(def)) {}
bool tilde = test(TILDE);
@@ -908,6 +908,15 @@ void Moc::parseProperty(ClassDef *def)
propDef.name = lexem();
while (test(IDENTIFIER)) {
QByteArray l = lexem();
+
+ if (l[0] == 'C' && l == "CONSTANT") {
+ propDef.constant = true;
+ continue;
+ } else if(l[0] == 'F' && l == "FINAL") {
+ propDef.final = true;
+ continue;
+ }
+
QByteArray v, v2;
if (test(LPAREN)) {
v = lexemUntil(RPAREN);
@@ -963,6 +972,23 @@ void Moc::parseProperty(ClassDef *def)
msg += " has no READ accessor function. The property will be invalid.";
warning(msg.constData());
}
+ if (propDef.constant && !propDef.write.isNull()) {
+ QByteArray msg;
+ msg += "Property declaration ";
+ msg += propDef.name;
+ msg += " is both WRITEable and CONSTANT. CONSTANT will be ignored.";
+ propDef.constant = false;
+ warning(msg.constData());
+ }
+ if (propDef.constant && !propDef.notify.isNull()) {
+ QByteArray msg;
+ msg += "Property declaration ";
+ msg += propDef.name;
+ msg += " is both NOTIFYable and CONSTANT. CONSTANT will be ignored.";
+ propDef.constant = false;
+ warning(msg.constData());
+ }
+
if(!propDef.notify.isEmpty())
def->notifyableProperties++;
diff --git a/src/tools/moc/moc.h b/src/tools/moc/moc.h
index 9fa9ac2..767f84e 100644
--- a/src/tools/moc/moc.h
+++ b/src/tools/moc/moc.h
@@ -115,9 +115,11 @@ struct FunctionDef
struct PropertyDef
{
- PropertyDef():notifyId(-1), gspec(ValueSpec){}
+ PropertyDef():notifyId(-1), constant(false), final(false), gspec(ValueSpec){}
QByteArray name, type, read, write, reset, designable, scriptable, editable, stored, user, notify;
int notifyId;
+ bool constant;
+ bool final;
enum Specification { ValueSpec, ReferenceSpec, PointerSpec };
Specification gspec;
bool stdCppSet() const {
diff --git a/src/xmlpatterns/acceltree/qacceltreeresourceloader.cpp b/src/xmlpatterns/acceltree/qacceltreeresourceloader.cpp
index 1cd84db..8019551 100644
--- a/src/xmlpatterns/acceltree/qacceltreeresourceloader.cpp
+++ b/src/xmlpatterns/acceltree/qacceltreeresourceloader.cpp
@@ -125,7 +125,7 @@ QNetworkReply *AccelTreeResourceLoader::load(const QUrl &uri,
networkLoop.connect(reply, SIGNAL(error(QNetworkReply::NetworkError)), SLOT(error(QNetworkReply::NetworkError)));
networkLoop.connect(reply, SIGNAL(finished()), SLOT(finished()));
- if(networkLoop.exec())
+ if(networkLoop.exec(QEventLoop::ExcludeUserInputEvents))
{
const QString errorMessage(escape(reply->errorString()));