| 213 | |
| 214 | |
| 215 | static EventData createEventData(QObject *receiver, QEvent *event) |
| 216 | { |
| 217 | EventData eventData; |
| 218 | eventData.time = QTime::currentTime(); |
| 219 | eventData.type = event->type(); |
| 220 | eventData.receiver = receiver; |
| 221 | eventData.attributes << QPair<const char *, QVariant> { "receiver", QVariant::fromValue(receiver) }; |
| 222 | eventData.eventPtr = event; |
| 223 | |
| 224 | // the receiver of a deferred delete event is almost always invalid when shown in the UI |
| 225 | // we therefore store the name of the receiver as a string to provide at least |
| 226 | // some useful information: |
| 227 | if (event->type() == QEvent::DeferredDelete) { |
| 228 | eventData.attributes << QPair<const char *, QVariant> { "[receiver type]", Util::displayString(receiver) }; |
| 229 | } |
| 230 | |
| 231 | // try to extract the method name, arguments and return value from a meta call event: |
| 232 | if (event->type() == QEvent::MetaCall) { |
| 233 | eventData.attributes << QPair<const char *, QVariant> { "[receiver type]", Util::displayString(receiver) }; |
| 234 | #if QT_VERSION >= QT_VERSION_CHECK(6, 11, 0) |
| 235 | auto *metaCallEvent = static_cast<MetaCallEventCopy *>(event); |
| 236 | const ushort methodIndex = metaCallEvent->signalId() >= 0 ? metaCallEvent->signalId() : metaCallEvent->d.method_offset_ + metaCallEvent->d.method_relative_; |
| 237 | #else |
| 238 | auto *metaCallEvent = static_cast<QMetaCallEvent *>(event); |
| 239 | int methodIndex = metaCallEvent->id(); |
| 240 | #endif |
| 241 | |
| 242 | if (methodIndex == ushort(-1)) { |
| 243 | eventData.attributes << QPair<const char *, QVariant> { "[method name]", "[unknown slot]" }; |
| 244 | } else if (receiver->metaObject()) { |
| 245 | const QMetaObject *meta = receiver->metaObject(); |
| 246 | QMetaMethod method = meta->method(methodIndex); |
| 247 | if (method.isValid()) { |
| 248 | eventData.attributes << QPair<const char *, QVariant> { "[method name]", method.name() }; |
| 249 | |
| 250 | #if QT_VERSION >= QT_VERSION_CHECK(6, 11, 0) |
| 251 | void **argv = metaCallEvent->d.args_; |
| 252 | int argc = std::min<int>(metaCallEvent->d.nargs_, method.parameterCount()); |
| 253 | #else |
| 254 | void **argv = metaCallEvent->args(); |
| 255 | int argc = method.parameterCount(); |
| 256 | #endif |
| 257 | if (argv) { // nullptr e.g. for QDBusCallDeliveryEvent |
| 258 | if (method.returnType() != QMetaType::Void) { |
| 259 | void *returnValueCopy = QMetaType(method.returnType()).create(argv[0]); |
| 260 | eventData.attributes << QPair<const char *, QVariant> { "[return value]", QVariant(QMetaType(method.returnType()), returnValueCopy) }; |
| 261 | } |
| 262 | QVariantMap vargs; |
| 263 | for (int i = 0; i < argc; ++i) { |
| 264 | int type = method.parameterType(i); |
| 265 | void *argumentDataCopy = QMetaType(type).create(argv[i + 1]); |
| 266 | vargs.insert(method.parameterNames().at(i), QVariant(QMetaType(type), argumentDataCopy)); |
| 267 | } |
| 268 | if (argc > 0) |
| 269 | eventData.attributes << QPair<const char *, QVariant> { "[arguments]", vargs }; |
| 270 | } |
| 271 | } else { |
| 272 | eventData.attributes << QPair<const char *, QVariant> { "[method name]", "[unknown slot]" }; |
no test coverage detected