#include "endsessionwait.h" #include "ui_endsessionwait.h" EndSessionWait::EndSessionWait(shutdownType type, QWidget *parent) : QDialog(parent), ui(new Ui::EndSessionWait) { ui->setupUi(this); switch (type) { case powerOff: ui->label->setText("Power Off"); ui->askWhatToDo->setVisible(false); break; case reboot: ui->label->setText("Reboot"); ui->askWhatToDo->setVisible(false); break; case logout: ui->label->setText("Log out"); ui->askWhatToDo->setVisible(false); break; case dummy: ui->label->setText("Dummy"); ui->askWhatToDo->setVisible(false); break; case ask: ui->poweringOff->setVisible(false); } this->type = type; } EndSessionWait::~EndSessionWait() { delete ui; } void EndSessionWait::close() { QPropertyAnimation* anim = new QPropertyAnimation(this, "windowOpacity"); anim->setDuration(250); anim->setStartValue(1.0); anim->setEndValue(0.0); connect(anim, &QPropertyAnimation::finished, [=]() { QDialog::close(); }); anim->start(QAbstractAnimation::DeleteWhenStopped); } void EndSessionWait::showFullScreen() { if (!alreadyShowing) { alreadyShowing = true; this->setWindowOpacity(0.0); QDialog::showFullScreen(); //ui->terminateAppFrame->resize(ui->terminateAppFrame->width(), 0); ui->terminateAppFrame->setGeometry(ui->terminateAppFrame->x(), ui->terminateAppFrame->y(), ui->terminateAppFrame->width(), 0); ui->terminateAppFrame->setVisible(false); ui->ExitFrameTop->resize(ui->ExitFrameTop->sizeHint()); ui->ExitFrameBottom->resize(ui->ExitFrameBottom->sizeHint()); QPropertyAnimation* anim = new QPropertyAnimation(this, "windowOpacity"); anim->setDuration(250); anim->setStartValue(0.0); anim->setEndValue(1.0); anim->start(QAbstractAnimation::DeleteWhenStopped); } if (this->type != dummy && this->type != ask) { QProcess p; p.start("wmctrl -lp"); p.waitForStarted(); while (p.state() != 0) { QApplication::processEvents(); } QList *wlist = new QList(); QString output(p.readAllStandardOutput()); for (QString window : output.split("\n")) { QStringList parts = window.split(" "); parts.removeAll(""); if (parts.length() >= 4) { if (parts[2].toInt() != QCoreApplication::applicationPid()) { WmWindow *w = new WmWindow(this); w->setPID(parts[2].toInt()); QString title; for (int i = 4; i != parts.length(); i++) { title = title.append(" " + parts[i]); } title = title.remove(0, 1); w->setTitle(title); wlist->append(w); } } } for (WmWindow* window : *wlist) { p.start("wmctrl -c " + window->title()); p.waitForStarted(); while (p.state() != 0) { QApplication::processEvents(); } } bool appsOpen = true; while (appsOpen) { appsOpen = false; p.start("wmctrl -lp"); p.waitForStarted(); while (p.state() != 0) { QApplication::processEvents(); } QString output(p.readAllStandardOutput()); for (QString window : output.split("\n")) { QStringList parts = window.split(" "); parts.removeAll(""); if (parts.length() >= 4) { if (parts[2].toInt() != QCoreApplication::applicationPid()) { appsOpen = true; } } } QApplication::processEvents(); } performEndSession(); } } void EndSessionWait::on_pushButton_clicked() { QProcess p; p.start("wmctrl -lp"); p.waitForStarted(); while (p.state() != 0) { QApplication::processEvents(); } QList *wlist = new QList(); QString output(p.readAllStandardOutput()); for (QString window : output.split("\n")) { QStringList parts = window.split(" "); parts.removeAll(""); if (parts.length() >= 4) { if (parts[2].toInt() != QCoreApplication::applicationPid()) { WmWindow *w = new WmWindow(this); w->setPID(parts[2].toInt()); QString title; for (int i = 4; i != parts.length(); i++) { title = title.append(" " + parts[i]); } title = title.remove(0, 1); w->setTitle(title); wlist->append(w); } } } performEndSession(); } void EndSessionWait::performEndSession() { QFile(QDir::home().absolutePath() + "/.theshell.lck").remove(); QSettings settings; QString logoutSoundPath = settings.value("sounds/logout", "").toString(); if (logoutSoundPath == "") { logoutSoundPath = "/usr/share/sounds/contemporary/logout.ogg"; settings.setValue("sounds/logout", logoutSoundPath); } QMediaPlayer* sound = new QMediaPlayer(); connect(sound, SIGNAL(error(QMediaPlayer::Error)), this, SLOT(EndSessionNow())); connect(sound, &QMediaPlayer::stateChanged, [=]() { if (sound->state() == QMediaPlayer::StoppedState) { EndSessionNow(); } }); sound->setMedia(QUrl::fromLocalFile(logoutSoundPath)); sound->play(); QGraphicsOpacityEffect *fadeEffect = new QGraphicsOpacityEffect(this); ui->poweringOff->setGraphicsEffect(fadeEffect); QPropertyAnimation *a = new QPropertyAnimation(fadeEffect, "opacity"); a->setDuration(500); a->setStartValue(1); a->setEndValue(0); a->start(); connect(a, &QPropertyAnimation::finished, [=]() { ui->poweringOff->setVisible(false); }); } void EndSessionWait::EndSessionNow() { QDBusMessage message; QList arguments; arguments.append(true); switch (type) { case powerOff: message = QDBusMessage::createMethodCall("org.freedesktop.login1", "/org/freedesktop/login1", "org.freedesktop.login1.Manager", "PowerOff"); message.setArguments(arguments); QDBusConnection::systemBus().send(message); break; case reboot: message = QDBusMessage::createMethodCall("org.freedesktop.login1", "/org/freedesktop/login1", "org.freedesktop.login1.Manager", "Reboot"); message.setArguments(arguments); QDBusConnection::systemBus().send(message); break; case logout: QApplication::exit(0); } } void EndSessionWait::on_pushButton_2_clicked() { this->close(); } void EndSessionWait::on_CancelAsk_clicked() { this->close(); } void EndSessionWait::on_PowerOff_clicked() { ui->askWhatToDo->setVisible(false); ui->poweringOff->setVisible(true); this->type = powerOff; ui->label->setText("Power Off"); this->showFullScreen(); } void EndSessionWait::on_Reboot_clicked() { ui->askWhatToDo->setVisible(false); ui->poweringOff->setVisible(true); this->type = reboot; ui->label->setText("Reboot"); this->showFullScreen(); } void EndSessionWait::on_LogOut_clicked() { ui->askWhatToDo->setVisible(false); ui->poweringOff->setVisible(true); this->type = logout; ui->label->setText("Log Out"); this->showFullScreen(); } void EndSessionWait::on_Suspend_clicked() { QList arguments; arguments.append(true); QDBusMessage message = QDBusMessage::createMethodCall("org.freedesktop.login1", "/org/freedesktop/login1", "org.freedesktop.login1.Manager", "Suspend"); message.setArguments(arguments); QDBusConnection::systemBus().send(message); this->close(); } void EndSessionWait::on_Hibernate_clicked() { QList arguments; arguments.append(true); QDBusMessage message = QDBusMessage::createMethodCall("org.freedesktop.login1", "/org/freedesktop/login1", "org.freedesktop.login1.Manager", "Hibernate"); message.setArguments(arguments); QDBusConnection::systemBus().send(message); this->close(); } void EndSessionWait::on_terminateApp_clicked() { int width = ui->ExitFrameTop->width(); QParallelAnimationGroup* group = new QParallelAnimationGroup(); QVariantAnimation* topAnim = new QVariantAnimation(); topAnim->setStartValue(ui->ExitFrameTop->height()); topAnim->setEndValue(0); topAnim->setEasingCurve(QEasingCurve::OutCubic); topAnim->setDuration(250); connect(topAnim, &QVariantAnimation::valueChanged, [=](QVariant value) { ui->ExitFrameTop->resize(width, value.toInt()); }); QVariantAnimation* bottomAnim = new QVariantAnimation(); bottomAnim->setStartValue(ui->ExitFrameBottom->height()); bottomAnim->setEndValue(0); bottomAnim->setEasingCurve(QEasingCurve::OutCubic); bottomAnim->setDuration(250); connect(bottomAnim, &QVariantAnimation::valueChanged, [=](QVariant value) { ui->ExitFrameBottom->resize(width, value.toInt()); }); QVariantAnimation* midAnim = new QVariantAnimation(); midAnim->setStartValue(ui->terminateAppFrame->height()); midAnim->setEndValue(ui->terminateAppFrame->sizeHint().height()); midAnim->setEasingCurve(QEasingCurve::OutCubic); midAnim->setDuration(500); connect(midAnim, &QVariantAnimation::valueChanged, [=](QVariant value) { ui->terminateAppFrame->resize(width, value.toInt()); }); group->addAnimation(midAnim); group->addAnimation(topAnim); group->addAnimation(bottomAnim); group->start(); connect(group, &QParallelAnimationGroup::finished, [=]() { ui->terminateAppFrame->resize(width, ui->terminateAppFrame->sizeHint().height()); ui->ExitFrameTop->resize(width, 0); ui->ExitFrameBottom->resize(width, 0); }); ui->terminateAppFrame->setVisible(true); this->reloadAppList(); } void EndSessionWait::reloadAppList() { QList *wlist = new QList(); Display* d = QX11Info::display(); QList TopWindows; Atom WindowListType; int format; unsigned long items, bytes; unsigned char *data; XGetWindowProperty(d, RootWindow(d, 0), XInternAtom(d, "_NET_CLIENT_LIST", true), 0L, (~0L), False, AnyPropertyType, &WindowListType, &format, &items, &bytes, &data); quint64 *windows = (quint64*) data; for (unsigned long i = 0; i < items; i++) { TopWindows.append((Window) windows[i]); } XFree(data); //XQueryTree(QX11Info::display(), RootWindow(d, 0), new Window(), new Window(), &ChildList, &NumOfChildren); for (Window win : TopWindows) { XWindowAttributes attributes; int retval = XGetWindowAttributes(d, win, &attributes); unsigned long items, bytes; unsigned char *netWmName; XTextProperty wmName; int format; Atom ReturnType; retval = XGetWindowProperty(d, win, XInternAtom(d, "_NET_WM_VISIBLE_NAME", False), 0, 1024, False, XInternAtom(d, "UTF8_STRING", False), &ReturnType, &format, &items, &bytes, &netWmName); if (retval != 0 || netWmName == 0x0) { retval = XGetWindowProperty(d, win, XInternAtom(d, "_NET_WM_NAME", False), 0, 1024, False, AnyPropertyType, &ReturnType, &format, &items, &bytes, &netWmName); if (retval != 0) { retval = XGetWMName(d, win, &wmName); if (retval == 1) { retval = 0; } else { retval = 1; } } } if (retval == 0) { WmWindow *w = new WmWindow(); w->setWID(win); QString title; if (netWmName) { title = QString::fromLocal8Bit((char *) netWmName); XFree(netWmName); } else if (wmName.value) { title = QString::fromLatin1((char *) wmName.value); //XFree(wmName); } unsigned long *pidPointer; unsigned long pitems, pbytes; int pformat; Atom pReturnType; int retval = XGetWindowProperty(d, win, XInternAtom(d, "_NET_WM_PID", False), 0, 1024, False, XA_CARDINAL, &pReturnType, &pformat, &pitems, &pbytes, (unsigned char**) &pidPointer); if (retval == 0) { if (pidPointer != 0) { unsigned long pid = *pidPointer; w->setPID(pid); } } XFree(pidPointer); /*unsigned long icItems, icBytes; unsigned char *icon; int icFormat; Atom icReturnType; retval = XGetWindowProperty(d, win, XInternAtom(d, "_NET_WM_ICON", False), 0, 1048576, False, XA_CARDINAL, &icReturnType, &icFormat, &icItems, &icBytes, &icon); w->setIcon(QIcon(QPixmap::fromImage(QImage::fromData(icon, icBytes)))); XFree(icon);*/ w->setTitle(title); if (w->PID() != QCoreApplication::applicationPid()) { wlist->append(w); } else { delete w; } } } ui->listWidget->clear(); for (WmWindow *wi : *wlist) { QListWidgetItem* item = new QListWidgetItem(); item->setText(wi->title() + " (PID " + QString::number(wi->PID()) + ")"); item->setData(Qt::UserRole, QVariant::fromValue(wi->PID())); ui->listWidget->addItem(item); } } void EndSessionWait::on_exitTerminate_clicked() { int width = ui->terminateAppFrame->width(); QParallelAnimationGroup* group = new QParallelAnimationGroup(); QVariantAnimation* topAnim = new QVariantAnimation(); topAnim->setStartValue(ui->ExitFrameTop->height()); topAnim->setEndValue(ui->ExitFrameTop->sizeHint().height()); topAnim->setEasingCurve(QEasingCurve::OutCubic); topAnim->setDuration(500); topAnim->setKeyValueAt(0.5, 0); connect(topAnim, &QVariantAnimation::valueChanged, [=](QVariant value) { ui->ExitFrameTop->resize(width, value.toInt()); }); QVariantAnimation* bottomAnim = new QVariantAnimation(); bottomAnim->setStartValue(ui->ExitFrameBottom->height()); bottomAnim->setEndValue(ui->ExitFrameBottom->sizeHint().height()); bottomAnim->setEasingCurve(QEasingCurve::OutCubic); bottomAnim->setDuration(500); bottomAnim->setKeyValueAt(0.5, 0); connect(bottomAnim, &QVariantAnimation::valueChanged, [=](QVariant value) { ui->ExitFrameBottom->resize(width, value.toInt()); }); QVariantAnimation* midAnim = new QVariantAnimation(); midAnim->setStartValue(ui->terminateAppFrame->height()); midAnim->setEndValue(0); midAnim->setEasingCurve(QEasingCurve::OutCubic); midAnim->setDuration(500); connect(midAnim, &QVariantAnimation::valueChanged, [=](QVariant value) { ui->terminateAppFrame->resize(width, value.toInt()); }); group->addAnimation(midAnim); group->addAnimation(topAnim); group->addAnimation(bottomAnim); group->start(); connect(group, &QParallelAnimationGroup::finished, [=]() { ui->terminateAppFrame->resize(ui->ExitFrameTop->width(), 0); ui->ExitFrameTop->resize(ui->ExitFrameTop->width(), ui->ExitFrameTop->sizeHint().height()); ui->ExitFrameBottom->resize(ui->ExitFrameBottom->width(), ui->ExitFrameTop->sizeHint().height()); ui->terminateAppFrame->setVisible(false); }); } void EndSessionWait::on_pushButton_5_clicked() { //Send SIGTERM to app kill(ui->listWidget->selectedItems().first()->data(Qt::UserRole).value(), SIGTERM); QThread::sleep(1); reloadAppList(); } void EndSessionWait::on_pushButton_4_clicked() { //Send SIGKILL to app kill(ui->listWidget->selectedItems().first()->data(Qt::UserRole).value(), SIGKILL); QThread::sleep(1); reloadAppList(); } void EndSessionWait::on_listWidget_currentRowChanged(int currentRow) { if (currentRow == -1) { ui->pushButton_5->setEnabled(false); ui->pushButton_4->setEnabled(false); } else { ui->pushButton_5->setEnabled(true); ui->pushButton_4->setEnabled(true); } }