-
Bug
-
Resolution: Done
-
P2: Important
-
4.8.1
-
None
-
Qt 4.8.1. Windows.
It seems that Qt 5 have the same code in the relevant places.
And the bug is not platform specific.
The problem
-----------
The current ownership model selected for signal expressions attached to states
did not account for certain cases. A signal owns its current expression. A
state owns an expression that the signal had just before we entered this state.
But when we enter a state an expression been set for a signal is the initial
expression for this particular state, not an expression owned by this state.
This would cause all kind of errors in a particularly complex case. Here is an
explanation of what happens under the old ownership model.
QML:
import QtQuick 1.0
Rectangle {
id: myRect
width: 400
height: 400
states: [
State {
name: "state1"
PropertyChanges {
target: myRect
onHeightChanged: console.log("state1")
color: "green"
}
},
State {
name: "state2";
PropertyChanges {
target: myRect
onHeightChanged: console.log("state2")
color: "red"
}
}]
}
Let's give our expressions ids:
0x1 : console.log("state1")
0x2 : console.log("state2")
Initially:
Rectangle.onHeightChanged: <no expression>
Rectangle.state1
expression: 0x1
owns: <nothing>
Rectangle.state2
expression: 0x2
owns: <nothing>
Enter state1:
Rectangle.onHeightChanged: 0x1
Rectangle.state1
expression: 0x1
owns: <nothing>
Rectangle.state2
expression: 0x2
owns: <nothing>
Enter state2:
Rectangle.onHeightChanged: 0x2
Rectangle.state1
expression: 0x1
owns: <nothing>
Rectangle.state2
expression: 0x2
owns: 0x1
state2 now own expression that "conceptually" belongs to state1 and might
still be set by state1.
Enter state1:
Rectangle.onHeightChanged: 0x1
Rectangle.state1
expression: 0x1
owns: 0x2
Rectangle.state2
expression: 0x2
owns: 0x1
Now we have everything mixed up. States owns each other's expression and in
addition to that the rectangle's signal also owns one of the expression. If
we delete the rectangle the 0x1 expression would be deleted twice.
Note that in addition to the crazy mix ups unless we enter a state at least
once we would leak all the signal expressions for that state. I am not sure
how to check for leaks here.
Short term solution (Patch attached)
---------------------------------
Use reference counted pointers for the signal handler expressions. Considering
all the cases we want to preserve an expression:
- State is destroyed but the item is alive and is in this state
- State is destroyed but the item has a reverse action in its reverse
list uses this expression (not sure it is actually usable)
- The original item signal handler expression should be preserved
regardless of the state we are in and regardless of what do we do
with the states (add new, delete, change current state)
It seems like reference counting is the only manageable solution unless
the overall model is modified a little bit.
General solution (Not implemented)
----------------------------------
In the long run I would advise a more general refactoring with a strict
rules of ownership for the expressions, state groups and states. I
would say that the reverse list should be moved into the state group and
states should own their expressions. And we do not allow destruction of
the current state or any of the state's current state extends.
When a state is destroyed we would delete all the expressions that
belong to that state. The reverse list should contain only references
to the expressions that were the initial values of the item signal
handlers. Thus unless we are trying to remove current state (or a state
that the current state extends) we should be fine from the semantic
standpoint.