Skip to content

Instantly share code, notes, and snippets.

@xim
Last active November 4, 2015 18:08
Show Gist options
  • Save xim/151e50088d06ee21b643 to your computer and use it in GitHub Desktop.
Save xim/151e50088d06ee21b643 to your computer and use it in GitHub Desktop.
QTBUG-49238

This code reproduces QTBUG-49238.

#include "dialog.h"
#include <QCoreApplication>
#include <QHBoxLayout>
#include <QTextEdit>
static Dialog *dialog = nullptr;
Dialog::Dialog()
: QDialog()
{
dialog = this;
QLayout *layout = new QHBoxLayout(this);
label = new QTextEdit;
addText("Status updates for the application will be shown here. Close dialog to exit.");
layout->addWidget(label);
layout->setContentsMargins(10, 10, 10, 10);
}
void Dialog::addText(const QString &text) {
label->append(text);
}
void logToDialog(const QString &text) {
qDebug("%s", text.toLocal8Bit().constData());
dialog->addText(text);
}
#ifndef DIALOG_H
#define DIALOG_H
#include <QDialog>
class QTextEdit;
class Dialog : public QDialog
{
Q_OBJECT
public:
Dialog();
void addText(const QString &);
private:
QTextEdit *label;
};
void logToDialog(const QString &);
#endif // DIALOG_H
#include "dialog.h"
#include "sleeplistener.h"
#include <QApplication>
QDialog *testObject = nullptr;
static void printDestruction() {
logToDialog("Destroyed object.");
}
static void createNewObject() {
testObject = new QDialog;
logToDialog("Created object.");
QObject::connect(testObject, &QObject::destroyed, qApp, &printDestruction);
}
static void deleteObject() {
logToDialog("Queueing object delete.");
testObject->deleteLater();
}
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
Dialog w;
SleepListener listener;
createNewObject();
QObject::connect(&listener, &SleepListener::willSleep, qApp, &deleteObject);
QObject::connect(&listener, &SleepListener::didWake, qApp, &createNewObject);
QObject::connect(qApp, &QCoreApplication::aboutToQuit, qApp, &deleteObject);
w.show();
return a.exec();
}
#-------------------------------------------------
#
# Project created by QtCreator 2015-11-04T17:57:59
#
#-------------------------------------------------
QT += core gui widgets
TARGET = SleepDelete
TEMPLATE = app
CONFIG += c++11
SOURCES += \
dialog.cpp \
main.cpp
OBJECTIVE_SOURCES += \
sleeplistener.mm
HEADERS += \
dialog.h \
sleeplistener.h
QMAKE_LFLAGS += -framework IOKit -framework Cocoa
QMAKE_MAC_SDK = macosx10.11
#ifndef SLEEPLISTENER_H
#define SLEEPLISTENER_H
#include <QObject>
#include <IOKit/IOMessage.h>
#include <IOKit/pwr_mgt/IOPMLib.h>
class SleepListener : public QObject {
Q_OBJECT
public:
SleepListener();
~SleepListener();
SleepListener(const SleepListener &) = delete;
SleepListener &operator=(const SleepListener &) = delete;
signals:
void willSleep();
void didWake();
public:
io_connect_t root_port; // Root power domain IOService connection
IONotificationPortRef notifyPortRef; // Notification port allocated by IORegisterForSystemPower
io_object_t notifierObject; // Notifier object, used to deregister
};
#endif // SLEEPLISTENER_H
#include "dialog.h"
#include "sleeplistener.h"
#include <mach/mach_port.h>
#include <mach/mach_interface.h>
#include <mach/mach_init.h>
namespace {
void sleepCallback(void *refCon, io_service_t service, natural_t messageType, void *messageArgument) {
Q_UNUSED(service)
SleepListener *listener = reinterpret_cast<SleepListener *>(refCon);
switch (messageType) {
case kIOMessageCanSystemSleep:
logToDialog("System wants to enter idle sleep.");
IOAllowPowerChange(listener->root_port, (long) messageArgument);
break;
case kIOMessageSystemWillSleep:
logToDialog("System WILL sleep.");
emit listener->willSleep();
logToDialog("Allowing sleep.");
IOAllowPowerChange(listener->root_port, (long) messageArgument);
break;
case kIOMessageSystemWillPowerOn:
logToDialog("System is waking up from sleep.");
break;
case kIOMessageSystemHasPoweredOn:
logToDialog("System has powered on.");
emit listener->didWake();
logToDialog("System has woken up from sleep.");
break;
}
}
}
SleepListener::SleepListener()
{
// Register to receive system sleep notifications
root_port = IORegisterForSystemPower(this, &notifyPortRef,
sleepCallback, &notifierObject);
if (!root_port) {
logToDialog("Could not register for sleep notifications.");
return;
}
// Add the notification port to the application runloop
CFRunLoopAddSource(CFRunLoopGetCurrent(),
IONotificationPortGetRunLoopSource(notifyPortRef), kCFRunLoopCommonModes);
}
SleepListener::~SleepListener() {
// Remove the sleep notification port from the application runloop
CFRunLoopRemoveSource(CFRunLoopGetCurrent(),
IONotificationPortGetRunLoopSource(notifyPortRef),
kCFRunLoopCommonModes);
// Deregister for system sleep notifications
IODeregisterForSystemPower(&notifierObject);
// IORegisterForSystemPower implicitly opens the Root Power Domain IOService
// so we close it here
IOServiceClose(root_port);
// Destroy the notification port allocated by IORegisterForSystemPower
IONotificationPortDestroy(notifyPortRef);
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment