aboutsummaryrefslogtreecommitdiffstats
path: root/src
Commit message (Collapse)AuthorAgeFilesLines
...
* Fix mapping of JS objects/arrays to C++Simon Hausmann2014-09-1711-231/+227
| | | | | | | | | | | | | | | [ChangeLog][QtQml][Important Behavior Changes] When a JavaScript object/array is passed to C++ through a QVariant, the engine no longer immediately converts the object recursively into a QVariantMap or QVariantList but instead stores a QJSValue in the QVariant. This prevents a loss of data when the JS object contains non-primitive types such as function objects for example. Code that expects the variant type to be exactly QVariant::Map or QVariant::List may need to be adapted. Registered conversion functions however ensure that code that merely calls toMap() or toList() continues to work. Task-number: QTBUG-40431 Change-Id: I1dbc1d5f8e78ad28bb62db3681b9a0b34557e7f5 Reviewed-by: Lars Knoll <lars.knoll@digia.com>
* Cleaned up the documentation for QQmlEngine::ObjectOwnership.Kavindra Palaraja2014-09-161-34/+30
| | | | | | | The paragraphs needed a bit of polish. Change-Id: I5c6b41fad34f3f58a372aa1bf8be627769871cf8 Reviewed-by: Simon Hausmann <simon.hausmann@digia.com>
* Fixed documentation for QQmlEngine::ObjectOwnership.Kavindra Palaraja2014-09-161-1/+1
| | | | | | | | | The ObjectOwnership enum's documentation mentioned that QObjects returned from property access are indestructible, which they aren't. Task-number: QTBUG-35426 Change-Id: Ic936b33b736ff7a45482cf1b626977d34ac4ebb2 Reviewed-by: Simon Hausmann <simon.hausmann@digia.com>
* Fix crash when borders exceed item width/height in border imageEskil Abrahamsen Blomfeldt2014-09-162-87/+126
| | | | | | | | | | | | | | | | | While we protected against the the borders exceeding the size of the source image when deciding whether to create a given patch, we did not protect against the case where the target rectangle is smaller than the borders. To fix this, we simply move the calculation of the target rectangle up to before we create the nodes, and check for isEmpty() before creating the nodes. In addition, we did not properly handle changing the borders dynamically. The subtree has to be rebuilt if the borders change so that the source or target rectangles change. Change-Id: Ia6a0df616ebbd0a32924de0b63fd48043027930a Task-number: QTBUG-41338 Reviewed-by: Gunnar Sletta <gunnar@sletta.org>
* QQuickTextControl: update cursor rect when cursor changes positionRichard Moe Gustavsen2014-09-163-5/+5
| | | | | | | | | | | | | | If the text cursor changes position by indirect manipulation of the document that backs a QQuickTextControl, we need to inform that the cursor rect changed as well. This will fix a bug with QQuickTextEdit that caused the platform input method to be out of sync since the cursor rect signal was never emitted from the the text control. Task-number: QTBUG-41042 Change-Id: Idcf35a2d51c8dffcb80ba21f8e59a61e04e5a879 Reviewed-by: Andrew den Exter <andrew.den.exter@qinetic.com.au>
* Don't start QQmlThreads from their constructorUlf Hermann2014-09-163-6/+13
| | | | | | | | | | In the case of derived classes (like the only user of QQmlThread) we cannot guarantee that the class is completely constructed when the thread starts. This includes the vtable which is necessary to decide which virtual functions to call. Change-Id: Ieaea67a72cc3b4f845b8621b34ca2928185917fb Reviewed-by: Simon Hausmann <simon.hausmann@digia.com>
* Let QSGPlainTexture support shutting down without a GL context.Gunnar Sletta2014-09-121-1/+1
| | | | | | Change-Id: Iae934e4d9e91f4ea21dd5bf27c4fafc5d481fb0a Task-number: QTBUG-41278 Reviewed-by: Laszlo Agocs <laszlo.agocs@digia.com>
* Fix stack size check on systems with less than 256kb stackSimon Hausmann2014-09-121-1/+5
| | | | | | | | | | | | | We require at least 256 kbytes slack stack space, and if a system is configured with less (or equal), then the stack size checks fail early on and strange error message occur during engine startup and execution. This patch calls the stack check code early on and bails out with an error message that's more descriptive. Change-Id: I3263f2f93f62332d08003411e1bb5b3b1140d02b Task-number: QTBUG-41213 Reviewed-by: Lars Knoll <lars.knoll@digia.com>
* Link to Key Handling Priorities section more in Keys documentation.Mitch Curtis2014-09-121-0/+5
| | | | | | | | | For those clicking directly on specific property links who might not know that the info they need about event order already exists. Change-Id: I18a9124697f542f5b3a2955ee10dfee538a93385 Reviewed-by: J-P Nurmi <jpnurmi@digia.com> Reviewed-by: Topi Reiniö <topi.reinio@digia.com>
* prevent crash when set ShaderEffectSource::sourceItem nullTasuku Suzuki2014-09-121-16/+16
| | | | | | | | Regression introduced in 81ba77d736f07efac37d284cd741d71f9dad4149 Task-number: QTBUG-41241 Change-Id: I9a65af6915325e1cbf9205c7da94273d5b91b310 Reviewed-by: Gunnar Sletta <gunnar@sletta.org>
* Check for valid QSGRenderContext instead of QOpenGLContextAndy Nichols2014-09-111-1/+1
| | | | | | | | A QQuickWindow with a valid QSGRenderContext is what should be checked for in QQuickCanvasItem::itemChange. Change-Id: Ibb85c2bb79d85b2d91b5d68cfa8a4760106047ae Reviewed-by: Gunnar Sletta <gunnar@sletta.org>
* Fix String leak by calling the correct destructorOle André Vadla Ravnås2014-09-111-1/+1
| | | | | | Task-number: QTBUG-41167 Change-Id: I696fbb7400215c7f1fb8cb2a1dbbc0780440a8c3 Reviewed-by: Simon Hausmann <simon.hausmann@digia.com>
* Check for a current QOpenGLContext before useAndy Nichols2014-09-111-0/+3
| | | | | | | | | We can not assume that there will be a current OpenGL context to use in QQuickImageParticle so now there is a check before we make a call to the current context. Change-Id: I0c77895d0b0f1afdf4853c0486fba0ef9a7b883d Reviewed-by: Lars Knoll <lars.knoll@digia.com>
* Select specific features to be recorded when profiling QMLUlf Hermann2014-09-1124-128/+181
| | | | | | | | | | | | Some features, like the memory profiler, create huge amounts of data. Often enough, we're not actually interested in all the data available from the profiler and collecting it all can lead to excessive memory consumption. This change enables us to optionally turn various aspects of QML profiling off. Task-number: QTBUG-41118 Change-Id: I7bb223414e24eb903124ffa6e0896af6ce974e49 Reviewed-by: Gunnar Sletta <gunnar@sletta.org>
* Fix debug output from renderer.Gunnar Sletta2014-09-111-3/+6
| | | | | | | | It was wrong when we ran without depth buffer or when we used the separate ibo code path. Change-Id: Ie6e4bfc99ee2a4a593e45be7d9af9af17896bcba Reviewed-by: Laszlo Agocs <laszlo.agocs@digia.com>
* Snap native glyphs to pixel grid in vertex shader.Gunnar Sletta2014-09-115-28/+8
| | | | | | | | | | | The implementation relied on the full matrix, but did not set the RequiresFullMatrix flag. Setting the flag would have serious negative performance impact as it prevents batching, so we solve it in the vertex shader instead. Task-number: QTBUG-38702 Change-Id: I0c245ea9e18b0b29dd9e3073a2648a7f4e061685 Reviewed-by: Eskil Abrahamsen Blomfeldt <eskil.abrahamsen-blomfeldt@digia.com>
* Fix setUTCXxx methods in DateLars Knoll2014-09-111-18/+9
| | | | | | | | | The methods where converting doing a localtime->UTC conversion even though the input was already in UTC. Task-number: QTBUG-38448 Change-Id: I4409275fade0dd2a677af2293edc87445f853879 Reviewed-by: Simon Hausmann <simon.hausmann@digia.com>
* Fix roundtrip conversion between JS var and QVariantLars Knoll2014-09-112-3/+12
| | | | | | | | | | | | | | Always convert null to a QVariant(VoidStar) as documented in QJSValue. Make sure the reverse conversion will lead back to a null JS value. Adjusted two test cases that expected an invalid QVariant when setting the property to null, and added test cases for the correct conversion. Task-number: QTBUG-40880 Change-Id: I6eb01f0067f2c89779c53fd2cd0a1193047ed2cc Reviewed-by: Simon Hausmann <simon.hausmann@digia.com>
* Fix failing assertion when compiling self-referencing QML singletonSimon Hausmann2014-09-111-6/+7
| | | | | | | | | When a QML singleton file accesses itself, we would hit incomplete type data. Task-number: QTBUG-41220 Change-Id: Id0bd5fd71cf9be21f7e4ad8527fa8724a718d702 Reviewed-by: Michael Brasser <michael.brasser@live.com>
* Merge "Merge remote-tracking branch 'origin/5.3' into 5.4" into refs/staging/5.4Simon Hausmann2014-09-116-8/+80
|\
| * Merge remote-tracking branch 'origin/5.3' into 5.4Simon Hausmann2014-09-086-8/+80
| |\ | | | | | | | | | | | | | | | | | | | | | | | | Conflicts: .qmake.conf src/qml/jsruntime/qv4arraydata.cpp src/quick/scenegraph/util/qsgatlastexture.cpp Change-Id: Ic4c96066d5c37dcf0d5446baed590ea005d445ce
| | * QML: parse .js files as JavaScript, not QML.Erik Verbruggen2014-09-051-1/+1
| | | | | | | | | | | | | | | | | | | | | | | | | | | When importing a JS library into a QML file with the "import" keyword, that JS file was parsed in QML mode, disallowing QML keywords like "as". Task-number: QTBUG-40143 Change-Id: Ie98adceb27544732c2e96657d41170db36bff288 Reviewed-by: Simon Hausmann <simon.hausmann@digia.com>
| | * Fix crashes when calling Array.sort with imperfect sort functionsLars Knoll2014-09-011-1/+55
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | We can't use std::sort to implement Array.sort. The reason is that std::sort expects a conformant compare function, and can do weird things (esp. crash) when the sort function isn't conformant. Falling back to qSort is not possible, as the method has been deprecated. So add a copy of the qSort implementation here, and use that one instead. Fix the sortint test in tst_qqmlecmascript to have a consistent sort function for strings, as the result of calling sort is otherwise undefined according to the ecma standard. Task-number: QTBUG-39072 Change-Id: I0602b3aa1ffa4de5006da58396f166805cf4a5e2 Reviewed-by: Robin Burchell <robin.burchell@viroteck.net> Reviewed-by: Simon Hausmann <simon.hausmann@digia.com>
| | * Support padding in images stored in atlas textureEskil Abrahamsen Blomfeldt2014-08-301-1/+10
| | | | | | | | | | | | | | | | | | | | | | | | If the stride does not match the width of the image, we upload it line-by-line instead of as one big rect. Change-Id: I5e08afcf5c35dc810fed25e45255d55d932b2a4c Reviewed-by: Gunnar Sletta <gunnar@sletta.org>
| | * Fix crash with cleanup of animators.Gunnar Sletta2014-08-303-5/+14
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | We had several separate issues relating to how the jobs were cleaned up. The first was that upon getting setWindow(0), the animator did not reset m_controller to 0, leading to the starts() coming after that to post null jobs to the controller. This would later crash in beforeNodeSync as the starting job was null. The second issue was that during shutdown, QQuickAnimatorProxy would try to delete jobs on the controller which was already deleted. The controller is deleted on the GUI thread regardless of render loop, so this was solved with a QPointer. The third was that we were a bit too aggressive in trying to clean up jobs on the GUI thread, so we introduced a new bool which gets set to true in startJob() so that Proxy::deleteJob() knows who owns the job. Task-number: QTBUG-37833 Change-Id: I1b6221a2c1ce2bfd0758801b950cda00ff6899d0 Reviewed-by: Michael Brasser <michael.brasser@live.com>
* | | Improve KeyNavigation documentation.Mitch Curtis2014-09-111-2/+2
| | | | | | | | | | | | | | | Change-Id: I07e66deb4b21eca191c17532749eeccd33d83fb0 Reviewed-by: Mitch Curtis <mitch.curtis@digia.com>
* | | Improve Drag documentation.Mitch Curtis2014-09-111-6/+7
| | | | | | | | | | | | | | | Change-Id: Ifba60b729c8ad02009cd5c8caa5d58e20a76c73b Reviewed-by: J-P Nurmi <jpnurmi@digia.com>
* | | Fix broken QJSEngine snippet in documentation.Mitch Curtis2014-09-111-3/+3
| | | | | | | | | | | | | | | | | | | | | | | | toBoolean() isn't even a function in that class, and declaring the button on the stack causes crashes upon closing the application. Change-Id: I063cac2bb144cfb9786f20bbc122d5af92a4c2c0 Reviewed-by: Jędrzej Nowacki <jedrzej.nowacki@digia.com>
* | | Enhance QQuickWidget docs regarding transparencyLaszlo Agocs2014-09-101-4/+20
| | | | | | | | | | | | | | | | | | | | | Provide a section similar to the one in the QOpenGLWidget docs. Change-Id: Ibe161f5b6e1b6654e78b522f44ba21b89fc85abe Reviewed-by: Mitch Curtis <mitch.curtis@digia.com>
* | | V4 runtime: tune Runtime::add/sub/mul a bit.Erik Verbruggen2014-09-102-38/+33
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | Tell the compiler to schedule the int32 case first, tune the double conversion a bit (int64->double is quite expensive), and write the function in such a way that it matches typical overflow idiom which compilers recognize. Change-Id: Ieae9a60275716002fbdbc54e1d7291c8aad8c927 Reviewed-by: Lars Knoll <lars.knoll@digia.com>
* | | QQuickTextInput: calculate height of cursor rect using QTextLine::height()Richard Moe Gustavsen2014-09-101-4/+2
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | Calculating the height of the line using ascent + descent seems inaccurate, since the result will not match what ends up being drawn. QQuickTextEdit uses instead QTextLine::height() for the same function, and this works correct. Since there seems to be no reason to reinvent how to calculate the height when the line already has a function for that, and since the result also seems to be wrong, we change the implementation to use QTextLine::height(). Change-Id: I9c9cd4360b6d4cfd3582756c4efdff9c02065789 Reviewed-by: Eskil Abrahamsen Blomfeldt <eskil.abrahamsen-blomfeldt@digia.com>
* | | Don't post deleteLater on invalid canvas contextsUlf Hermann2014-09-101-1/+2
| | | | | | | | | | | | | | | | | | | | | | | | QCoreApplication complains about that. The context will only be valid once it has been requested in one way or another. Change-Id: Idb44f2541d71355443a5b491078a3040907b1614 Reviewed-by: Gunnar Sletta <gunnar@sletta.org>
* | | Fix pixel bleed in BorderImageEskil Abrahamsen Blomfeldt2014-09-106-72/+393
|/ / | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | Keeping all patches of the border image in the same texture with different sample points can cause parts of the border to bleed over to the center patch. To rectify this, we create a separate texture for each of the nine patches we need, and separate image nodes. To avoid applying antialiasing on the interior edges of the border image, we introduce new antialiasing flags which can be used to specify precisely which edges of the image should be antialiased. [ChangeLog][BorderImage] Fixed possible pixel bleed between border patches and center patch in BorderImage. Change-Id: Icc292b3969217320eecca99e79675316c42eab08 Task-number: QTBUG-35838 Reviewed-by: Gunnar Sletta <gunnar@sletta.org>
* | Doc: Fix link to Qt namespacev5.4.0-alpha1Topi Reinio2014-09-051-1/+1
| | | | | | | | | | | | | | | | | | Linking to 'Qt Namespace' will link to the Detailed Description section on the Qt namespace doc. Use the new linking format to link to the start of the page instead. Change-Id: Ib7e1b2b91fd9987262fc1a083ae94ef086260766 Reviewed-by: Martin Smith <martin.smith@digia.com>
* | QQuickTextInput: keep floating point precition when calculating offsetRichard Moe Gustavsen2014-09-041-2/+2
| | | | | | | | | | | | | | | | | | Without this patch, positionToRectangle will return a slightly different rectangle than what ends up being drawn. Change-Id: Ib1a3936f0fab393d6016d85d63547ec7f3036b7a Reviewed-by: Andrew den Exter <andrew.den.exter@qinetic.com.au> Reviewed-by: Eskil Abrahamsen Blomfeldt <eskil.abrahamsen-blomfeldt@digia.com>
* | MouseArea: Fix cancelling the double click when the windows loses focusOlivier Goffart2014-09-031-0/+1
| | | | | | | | | | | | | | | | | | | | Without this, the next click is not received after the windows loses focus while we double clicked but not released the mouse. This may happen if the onDoubleClicked opens a new window Change-Id: I86742de2bb1ea4c9657b9d5e90472d093293177d Reviewed-by: Alan Alpert <aalpert@blackberry.com>
* | Fix performance regression caused by SG signals in QQuickItem.Gunnar Sletta2014-09-0313-92/+30
| | | | | | | | | | | | | | | | | | | | | | | | | | For a testcase with thosands of items, I measured an increase in shutdown time from 800ms to 7500ms, all spent in disconnect(). This is not acceptible, so we're choosing a different approach. If items implement a invalidateSceneGraph slot, this function will be called during shutdown. It should be made a proper virtual in Qt 6. This approach costs very little. Change-Id: I5970143cc0a0744955687e17586f0bb00c9afb26 Reviewed-by: Lars Knoll <lars.knoll@digia.com>
* | Append scenegraph in MODULE_PLUGIN_TYPES of quick moduleAndy Nichols2014-09-021-1/+2
| | | | | | | | | | | | | | | | | | While scenegraph is already a plugin type, it was not defined as plugin_type by the module feature file so qmake fails to build when using load(qt_plugin). Change-Id: I7a6cf21358bbda9878ebe78b7c208c0ded2cf4a9 Reviewed-by: Lars Knoll <lars.knoll@digia.com>
* | Fix selection of text with negative right bearingEskil Abrahamsen Blomfeldt2014-09-022-63/+150
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | Selecting text with a negative right bearing (like italic text) would cause clipping to occur at the edges of the characters. The algorithm for drawing text and text selection tried to divide the text into two: 1. Selected text, and 2. Unselected text. However, the selected text might be drawn outside the selection rect when it has a negative right bearing. Similarly, unselected text before the selection might overlap with the selection rect when it has a negative right bearing, or unselected text after the selection might overlap if it has a negative left bearing. See added test textinput_italic_selected.qml for an example. To rectify this, we do drawing of selected text like this: 1. Draw all text with unselected color 2. Draw selection rects 3. Draw the following in the selection text color and clipped to the selection rect: A. The selected text B. The unselected text right before the selection C. The unselected text right after the selection To avoid drawing the same text twice for extra boldness, we check if 3B or 3C actually contain 3A, in which case we skip 3A. [ChangeLog][Text] Fixed clipping when selecting text with negative right bearing. Task-number: QTBUG-34233 Change-Id: I3506b3a72a2d963c5f24c5b819bbb92769b9aee1 Reviewed-by: Samuel Nevala <samuel.nevala@digia.com> Reviewed-by: Lars Knoll <lars.knoll@digia.com> Reviewed-by: Gunnar Sletta <gunnar@sletta.org>
* | Remove Q_ASSERT when getting the OpenGL Context ProfileAndy Nichols2014-09-011-2/+2
| | | | | | | | | | | | | | | | | | | | We do not actually use the OpenGL context in this method other than to query the profile type if one is available. In the case that there is no context the profile type does not matter and the default value of QSurfaceFormat::NoProfile is correct. Change-Id: Ice4440fe0e578d4cdcba347f5325768667722af8 Reviewed-by: Lars Knoll <lars.knoll@digia.com>
* | Remove use of anonymous struct in header fileKai Koehne2014-09-011-4/+2
| | | | | | | | | | | | | | | | | | | | | | | | | | Although all compilers seem to support this, anonymous structs have only been added formally to C++ 11. Also, this breaks with a change that adds a constructor to QElapsedTimer: error: member 'QElapsedTimer QQmlInstantiationInterrupt::<anonymous struct>::timer' with constructor not allowed in anonymous aggregate QElapsedTimer timer; ^ Change-Id: I5672060e3a623a5d9c4eb1d4e2981c67b96a1192 Reviewed-by: Simon Hausmann <simon.hausmann@digia.com>
* | Fix the dynamic build by not calling glGet directlyLaszlo Agocs2014-08-291-1/+1
| | | | | | | | | | | | Change-Id: I97ee290c31ca4fa0ffc2f822f14bc7d5e34dd222 Reviewed-by: Gunnar Sletta <gunnar@sletta.org> Reviewed-by: Friedemann Kleint <Friedemann.Kleint@digia.com>
* | QQuickWidget: Keep the offscreen quick window size in syncLaszlo Agocs2014-08-291-7/+9
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | The resizing logic has some faults: The size change is not always communicated to the offscreen QQuickWindow. When hiding and showing a QQuickWidget we may return early from the resize event handler, skipping the geometry change for the offscreen window. This is wrong. To make sure the sizes always match, set the geometry together with the FBO creation instead. This is much more robust and guarantees that the FBO size and the QQuickWindow size will not be out of sync. Task-number: QTBUG-40517 Change-Id: I61ef3ad2d23dff4280dbf03b57c03c1aeda8dc91 Reviewed-by: Paul Olav Tvete <paul.tvete@digia.com>
* | introduce *.ui.qml file types as new forms file typeTim Jenssen2014-08-291-0/+7
| | | | | | | | | | Change-Id: I1f07b6c1ab8afac7ee7ad05e988fe313ba904705 Reviewed-by: Thomas Hartmann <Thomas.Hartmann@digia.com>
* | Abort the application if the render thread fails to startGunnar Sletta2014-08-291-0/+2
| | | | | | | | | | | | | | | | This is a system-level failure, with which we can do very little, so we abort. Change-Id: I945da8bd28df35a6c8987160a2f0177d27d6c95d Reviewed-by: Robin Burchell <robin.burchell@viroteck.net>
* | Merge "Merge remote-tracking branch 'origin/5.3' into 5.4" into refs/staging/5.4Frederik Gladhorn2014-08-285-15/+12
|\ \
| * | Merge remote-tracking branch 'origin/5.3' into 5.4Frederik Gladhorn2014-08-285-15/+12
| |\| | | | | | | | | | Change-Id: I92b91cce499ed4bec64521a581276f397792e218
| | * Use QtQuick.Window 2.2v5.3.2Kai Koehne2014-08-275-15/+12
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | Use version 2.2 in the documentation and for the .qmltypes file. The revision for properties got dropped in commit 7ceca6ac0 , and is now dropped from the .qmltypes file, too. The removed signals are also dropped because of that (because they are implicitly declared by the property, anyway). Change-Id: Ia14dd403ce1f098cb378bd7940e8f80f32b770a0 Reviewed-by: Fawzi Mohamed <fawzi.mohamed@digia.com> Reviewed-by: Alan Alpert <aalpert@blackberry.com>
* | | Add new property "designersupported" to qmldirTim Jenssen2014-08-2811-1/+64
|/ / | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | This patch adds a property called "designersupported" to qmldir. This allows the Qt Quick Designer to only load plugins that have the line ""designersupported"" in their qmldir file. So the designer can load sub components without risking to load plugins that have never been tested in the designer and that might crash. The check for "designersupported"" is activated by using QQmlImports::setDesignerSupportRequired(). Change-Id: I4bf07cc163faa47996eacb1365a7961c51c51060 Reviewed-by: Thomas Hartmann <Thomas.Hartmann@digia.com> Reviewed-by: Tim Jenssen <tim.jenssen@digia.com>
* | TestCase.qml: add missing closing parenthesis to example.Mitch Curtis2014-08-271-1/+1
| | | | | | | | | | Change-Id: I93f1f8ec74808fc0a9f681cd88f7e5616089c80c Reviewed-by: Gunnar Sletta <gunnar@sletta.org>